From 8348b8b3b29733fe88c6114fc0c5a47c7df18ac9 Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Mon, 7 Apr 2025 14:52:22 -0700 Subject: [PATCH 001/876] Added board definitions --- .../board.c | 9 ++++ .../mpconfigboard.h | 27 ++++++++++ .../mpconfigboard.mk | 31 +++++++++++ .../pins.c | 53 +++++++++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/board.c create mode 100644 ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h create mode 100644 ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk create mode 100644 ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/board.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/board.c new file mode 100644 index 00000000000..b44a1ae51e0 --- /dev/null +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h new file mode 100644 index 00000000000..0188cd9b519 --- /dev/null +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h @@ -0,0 +1,27 @@ + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Microchip Curiosity CircuitPython Nano" +#define MICROPY_HW_MCU_NAME "same51j20" +#define CIRCUITPY_MCU_FAMILY samd51 + +#define MICROPY_HW_LED_STATUS (&pin_PB22) +#define MICROPY_HW_NEOPIXEL (&pin_PB22) + +#define EXTERNAL_FLASH_QSPI_DUAL + +#define BOARD_HAS_CRYSTAL 1 + +// USB is always used internally so skip the pin objects for it. +#define IGNORE_PIN_PA24 1 +#define IGNORE_PIN_PA25 1 + +#define DEFAULT_I2C_BUS_SCL (&pin_PB31) +#define DEFAULT_I2C_BUS_SDA (&pin_PB30) + +#define DEFAULT_SPI_BUS_SCK (&pin_PBA17) +#define DEFAULT_SPI_BUS_MOSI (&pin_PA16) +#define DEFAULT_SPI_BUS_MISO (&pin_PA18) + +#define DEFAULT_UART_BUS_RX (&pin_PA23) +#define DEFAULT_UART_BUS_TX (&pin_PA22) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk new file mode 100644 index 00000000000..fcda6bf4b77 --- /dev/null +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk @@ -0,0 +1,31 @@ +USB_VID = 0x04D8 +USB_PID = 0xE52B +USB_PRODUCT = "Microchip Curiosity CircuitPython Nano" +USB_MANUFACTURER = "Microchip Technology Inc" + +CHIP_VARIANT = SAME51J20A +CHIP_FAMILY = same51 + +QSPI_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICES = "GD25Q16C,W25Q16JVxQ,SST26VF032B" +LONGINT_IMPL = MPZ + +CIRCUITPY__EVE = 1 +CIRCUITPY_BITMAPFILTER = 0 +CIRCUITPY_CANIO = 1 +CIRCUITPY_FLOPPYIO = 0 +CIRCUITPY_SYNTHIO = 0 +CIRCUITPY_GIFIO = 0 +CIRCUITPY_JPEGIO = 0 + +CIRCUITPY_LTO_PARTITION = one + +# We don't have room for the fonts for terminalio for certain languages, +# so turn off terminalio, and if it's off and displayio is on, +# force a clean build. +# Note that we cannot test $(CIRCUITPY_DISPLAYIO) directly with an +# ifeq, because it's not set yet. +ifneq (,$(filter $(TRANSLATION),ja ko ru)) +CIRCUITPY_TERMINALIO = 0 +RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO) +endif diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c new file mode 100644 index 00000000000..c6a9dd9c416 --- /dev/null +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c @@ -0,0 +1,53 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA21) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA27) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PB14) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PB15) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PB16) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB22) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIX), MP_ROM_PTR(&pin_PB22) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, + { MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_PTR(&pin_PA03) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PB04) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB05) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB06) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PB07) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pin_PA02) }, + { MP_ROM_QSTR(MP_QSTR_CAP1), MP_ROM_PTR(&pin_PB09) }, + { MP_ROM_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, + { MP_ROM_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, + { MP_ROM_QSTR(MP_QSTR_CAN_STDBY), MP_ROM_PTR(&pin_PB17) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB30) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB31) }, + { MP_ROM_QSTR(MP_QSTR_BLE_TX), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_BLE_RX), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_BLE_CLR), MP_ROM_PTR(&pin_PA14) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_PA18) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_0), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_1), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_2), MP_ROM_PTR(&pin_PB02) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_3), MP_ROM_PTR(&pin_PB03) }, + { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, + { MP_ROM_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_PA23) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 0f9462f35cbbad14d602a9fcae7ead20e8db51c2 Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Wed, 9 Apr 2025 11:11:34 -0700 Subject: [PATCH 002/876] Updated mpconfig.mk to use SST26VF016B. --- .../microchip_curiosity_circuitpython_nano/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk index fcda6bf4b77..666cec8ede1 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk @@ -7,7 +7,7 @@ CHIP_VARIANT = SAME51J20A CHIP_FAMILY = same51 QSPI_FLASH_FILESYSTEM = 1 -EXTERNAL_FLASH_DEVICES = "GD25Q16C,W25Q16JVxQ,SST26VF032B" +EXTERNAL_FLASH_DEVICES = "SST26VF016B" LONGINT_IMPL = MPZ CIRCUITPY__EVE = 1 From b2a11f0d851512508de9adf0c9e2f281c8404525 Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Thu, 10 Apr 2025 14:34:14 -0700 Subject: [PATCH 003/876] Updated pins.c to contain objects for I2C, SPI, UART, CAN --- .../pins.c | 96 +++++++++++-------- 1 file changed, 56 insertions(+), 40 deletions(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c index c6a9dd9c416..aae64a8a2f8 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c @@ -9,45 +9,61 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA15) }, - { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA20) }, - { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA21) }, - { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA27) }, - { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PB14) }, - { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PB15) }, - { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PB16) }, - { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, - { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB22) }, - { MP_ROM_QSTR(MP_QSTR_NEOPIX), MP_ROM_PTR(&pin_PB22) }, - { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, - { MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_PTR(&pin_PA03) }, - { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PB04) }, - { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB05) }, - { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB06) }, - { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PB07) }, - { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PB08) }, - { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB09) }, - { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pin_PA02) }, - { MP_ROM_QSTR(MP_QSTR_CAP1), MP_ROM_PTR(&pin_PB09) }, - { MP_ROM_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, - { MP_ROM_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, - { MP_ROM_QSTR(MP_QSTR_CAN_STDBY), MP_ROM_PTR(&pin_PB17) }, - { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_PA07) }, - { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, - { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, - { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB30) }, - { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB31) }, - { MP_ROM_QSTR(MP_QSTR_BLE_TX), MP_ROM_PTR(&pin_PA12) }, - { MP_ROM_QSTR(MP_QSTR_BLE_RX), MP_ROM_PTR(&pin_PA13) }, - { MP_ROM_QSTR(MP_QSTR_BLE_CLR), MP_ROM_PTR(&pin_PA14) }, - { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_PA16) }, - { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_PA18) }, - { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_PA17) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_0), MP_ROM_PTR(&pin_PB00) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_1), MP_ROM_PTR(&pin_PB01) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_2), MP_ROM_PTR(&pin_PB02) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_3), MP_ROM_PTR(&pin_PB03) }, - { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, - { MP_ROM_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_PA23) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA21) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA27) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PB14) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PB15) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PB16) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB22) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIX), MP_ROM_PTR(&pin_PB22) }, + + { MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_PTR(&pin_PA03) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PB04) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB05) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB06) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PB07) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB09) }, + + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pin_PA02) }, + + { MP_ROM_QSTR(MP_QSTR_CAP1), MP_ROM_PTR(&pin_PB09) }, + + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB30) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB31) }, + + { MP_ROM_QSTR(MP_QSTR_BLE_TX), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_BLE_RX), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_BLE_CLR), MP_ROM_PTR(&pin_PA14) }, + + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_PA18) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_PA17) }, + + { MP_ROM_QSTR(MP_QSTR_SPARE_0), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_1), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_2), MP_ROM_PTR(&pin_PB02) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_3), MP_ROM_PTR(&pin_PB03) }, + + { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, + { MP_ROM_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_PA23) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 15b1d5f276fd30f8bcd5b3725dc53799c36e8caf Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Wed, 23 Apr 2025 11:38:00 -0700 Subject: [PATCH 004/876] Changes to mpconfigboard.h and pins.c --- mpconfigboard.h | 37 ++++++++++++++++++++++++++ pins.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 mpconfigboard.h create mode 100644 pins.c diff --git a/mpconfigboard.h b/mpconfigboard.h new file mode 100644 index 00000000000..673a5845851 --- /dev/null +++ b/mpconfigboard.h @@ -0,0 +1,37 @@ + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Microchip Curiosity CircuitPython Nano" +#define MICROPY_HW_MCU_NAME "same51j20" +#define CIRCUITPY_MCU_FAMILY samd51 + +#define MICROPY_HW_LED_STATUS (&pin_PB23) +#define MICROPY_HW_NEOPIXEL (&pin_PB22) + +#define EXTERNAL_FLASH_QSPI_DUAL + +#define BOARD_HAS_CRYSTAL 1 + +// USB is always used internally so skip the pin objects for it. +#define IGNORE_PIN_PA24 1 +#define IGNORE_PIN_PA25 1 + +#define DEFAULT_I2C_BUS_SCL (&pin_PB31) +#define DEFAULT_I2C_BUS_SDA (&pin_PB30) + +#define LCD_SPI_BUS_SCK (&pin_PA05) +#define LCD_SPI_BUS_MOSI (&pin_PA04) +#define LCD_SPI_BUS_CS (&pin_PA07) +#define LCD_BACKLIGHT (&pin_PA06) + +#define SDCARD_SPI_BUS_SCK (&pin_PA17) +#define SDCARD_SPI_BUS_MOSI (&pin_PA16) +#define SDCARD_SPI_BUS_MISO (&pin_PA18) +#define SDCARD_SPI_BUS_CS (&pin_PA19) + +#define DEFAULT_CAN_BUS_TX (&pin_PB12) +#define DEFAULT_CAN_BUS_RX (&pin_PB13) +#define DEFAULT_CAN_BUS_STDBY (&pin_PB17) + +#define DEFAULT_UART_BUS_RX (&pin_PA23) +#define DEFAULT_UART_BUS_TX (&pin_PA22) diff --git a/pins.c b/pins.c new file mode 100644 index 00000000000..73cd7c64f18 --- /dev/null +++ b/pins.c @@ -0,0 +1,71 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA15) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA20) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA21) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA27) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PB14) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PB15) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PB16) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB22) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB23) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIX), MP_ROM_PTR(&pin_PB22) }, + + { MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_PTR(&pin_PA03) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PB04) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB05) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB06) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PB07) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PB08) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB09) }, + + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pin_PA02) }, + + { MP_ROM_QSTR(MP_QSTR_CAP1), MP_ROM_PTR(&pin_PB09) }, + + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_PA07) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB30) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB31) }, + + { MP_ROM_QSTR(MP_QSTR_BLE_TX), MP_ROM_PTR(&pin_PA12) }, + { MP_ROM_QSTR(MP_QSTR_BLE_RX), MP_ROM_PTR(&pin_PA13) }, + { MP_ROM_QSTR(MP_QSTR_BLE_CLR), MP_ROM_PTR(&pin_PA14) }, + + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_PA16) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_PA18) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_PA17) }, + + { MP_ROM_QSTR(MP_QSTR_SPARE_0), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_1), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_2), MP_ROM_PTR(&pin_PB02) }, + { MP_ROM_QSTR(MP_QSTR_SPARE_3), MP_ROM_PTR(&pin_PB03) }, + + { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, + { MP_ROM_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_PA23) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 4b72af42624dc50b56ecd836015483940ef3f9b1 Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Wed, 23 Apr 2025 12:17:43 -0700 Subject: [PATCH 005/876] Delete pins.c --- pins.c | 71 ---------------------------------------------------------- 1 file changed, 71 deletions(-) delete mode 100644 pins.c diff --git a/pins.c b/pins.c deleted file mode 100644 index 73cd7c64f18..00000000000 --- a/pins.c +++ /dev/null @@ -1,71 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2017 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/board/__init__.h" - -static const mp_rom_map_elem_t board_module_globals_table[] = { - CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - - { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_PA15) }, - { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_PA20) }, - { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_PA21) }, - { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_PA27) }, - { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PB14) }, - { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PB15) }, - { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PB16) }, - { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, - { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB22) }, - { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, - - { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB23) }, - - { MP_ROM_QSTR(MP_QSTR_NEOPIX), MP_ROM_PTR(&pin_PB22) }, - - { MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_PTR(&pin_PA03) }, - - { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_PB04) }, - { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_PB05) }, - { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_PB06) }, - { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_PB07) }, - { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_PB08) }, - { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_PB09) }, - - { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&pin_PA02) }, - - { MP_ROM_QSTR(MP_QSTR_CAP1), MP_ROM_PTR(&pin_PB09) }, - - { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_PA07) }, - { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, - { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, - - { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB30) }, - { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB31) }, - - { MP_ROM_QSTR(MP_QSTR_BLE_TX), MP_ROM_PTR(&pin_PA12) }, - { MP_ROM_QSTR(MP_QSTR_BLE_RX), MP_ROM_PTR(&pin_PA13) }, - { MP_ROM_QSTR(MP_QSTR_BLE_CLR), MP_ROM_PTR(&pin_PA14) }, - - { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_PA16) }, - { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_PA18) }, - { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_PA17) }, - - { MP_ROM_QSTR(MP_QSTR_SPARE_0), MP_ROM_PTR(&pin_PB00) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_1), MP_ROM_PTR(&pin_PB01) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_2), MP_ROM_PTR(&pin_PB02) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_3), MP_ROM_PTR(&pin_PB03) }, - - { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, - { MP_ROM_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_PA23) }, - - { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, - - { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, - { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, -}; -MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From c4285e8472f44b7f1bff796b65efd9200a2522db Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Wed, 23 Apr 2025 12:17:59 -0700 Subject: [PATCH 006/876] Delete mpconfigboard.h --- mpconfigboard.h | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 mpconfigboard.h diff --git a/mpconfigboard.h b/mpconfigboard.h deleted file mode 100644 index 673a5845851..00000000000 --- a/mpconfigboard.h +++ /dev/null @@ -1,37 +0,0 @@ - -#pragma once - -#define MICROPY_HW_BOARD_NAME "Microchip Curiosity CircuitPython Nano" -#define MICROPY_HW_MCU_NAME "same51j20" -#define CIRCUITPY_MCU_FAMILY samd51 - -#define MICROPY_HW_LED_STATUS (&pin_PB23) -#define MICROPY_HW_NEOPIXEL (&pin_PB22) - -#define EXTERNAL_FLASH_QSPI_DUAL - -#define BOARD_HAS_CRYSTAL 1 - -// USB is always used internally so skip the pin objects for it. -#define IGNORE_PIN_PA24 1 -#define IGNORE_PIN_PA25 1 - -#define DEFAULT_I2C_BUS_SCL (&pin_PB31) -#define DEFAULT_I2C_BUS_SDA (&pin_PB30) - -#define LCD_SPI_BUS_SCK (&pin_PA05) -#define LCD_SPI_BUS_MOSI (&pin_PA04) -#define LCD_SPI_BUS_CS (&pin_PA07) -#define LCD_BACKLIGHT (&pin_PA06) - -#define SDCARD_SPI_BUS_SCK (&pin_PA17) -#define SDCARD_SPI_BUS_MOSI (&pin_PA16) -#define SDCARD_SPI_BUS_MISO (&pin_PA18) -#define SDCARD_SPI_BUS_CS (&pin_PA19) - -#define DEFAULT_CAN_BUS_TX (&pin_PB12) -#define DEFAULT_CAN_BUS_RX (&pin_PB13) -#define DEFAULT_CAN_BUS_STDBY (&pin_PB17) - -#define DEFAULT_UART_BUS_RX (&pin_PA23) -#define DEFAULT_UART_BUS_TX (&pin_PA22) From 6742579e46d8ef7061baf31a41536f6df5a57a3e Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Wed, 23 Apr 2025 12:19:21 -0700 Subject: [PATCH 007/876] Updated mpconfig.h and pins.c --- .../mpconfigboard.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h index 0188cd9b519..673a5845851 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h @@ -5,7 +5,7 @@ #define MICROPY_HW_MCU_NAME "same51j20" #define CIRCUITPY_MCU_FAMILY samd51 -#define MICROPY_HW_LED_STATUS (&pin_PB22) +#define MICROPY_HW_LED_STATUS (&pin_PB23) #define MICROPY_HW_NEOPIXEL (&pin_PB22) #define EXTERNAL_FLASH_QSPI_DUAL @@ -19,9 +19,19 @@ #define DEFAULT_I2C_BUS_SCL (&pin_PB31) #define DEFAULT_I2C_BUS_SDA (&pin_PB30) -#define DEFAULT_SPI_BUS_SCK (&pin_PBA17) -#define DEFAULT_SPI_BUS_MOSI (&pin_PA16) -#define DEFAULT_SPI_BUS_MISO (&pin_PA18) +#define LCD_SPI_BUS_SCK (&pin_PA05) +#define LCD_SPI_BUS_MOSI (&pin_PA04) +#define LCD_SPI_BUS_CS (&pin_PA07) +#define LCD_BACKLIGHT (&pin_PA06) + +#define SDCARD_SPI_BUS_SCK (&pin_PA17) +#define SDCARD_SPI_BUS_MOSI (&pin_PA16) +#define SDCARD_SPI_BUS_MISO (&pin_PA18) +#define SDCARD_SPI_BUS_CS (&pin_PA19) + +#define DEFAULT_CAN_BUS_TX (&pin_PB12) +#define DEFAULT_CAN_BUS_RX (&pin_PB13) +#define DEFAULT_CAN_BUS_STDBY (&pin_PB17) #define DEFAULT_UART_BUS_RX (&pin_PA23) #define DEFAULT_UART_BUS_TX (&pin_PA22) From 0a5ce8d453d480d7fcfcc9800616a1bb38df9785 Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Wed, 23 Apr 2025 12:22:27 -0700 Subject: [PATCH 008/876] Switched to SST26VF064B flash --- .../microchip_curiosity_circuitpython_nano/mpconfigboard.mk | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk index 666cec8ede1..c6fbb75fe80 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk @@ -6,9 +6,11 @@ USB_MANUFACTURER = "Microchip Technology Inc" CHIP_VARIANT = SAME51J20A CHIP_FAMILY = same51 -QSPI_FLASH_FILESYSTEM = 1 -EXTERNAL_FLASH_DEVICES = "SST26VF016B" +# QSPI_FLASH_FILESYSTEM = 1 +INTERNAL_FLASH_FILESYSTEM = 1 +EXTERNAL_FLASH_DEVICES = "SST26VF064B" LONGINT_IMPL = MPZ +CIRCUITPY_ULAB = 0 CIRCUITPY__EVE = 1 CIRCUITPY_BITMAPFILTER = 0 From 92aa962bdf53cdfe1737c8730ce3283d99074f7a Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Wed, 23 Apr 2025 13:19:36 -0700 Subject: [PATCH 009/876] Added support for flash chips Microchip Quad SPI flash: SST26VF016B, SST26VF016B,SST26VF016B, SST26VF064B --- .../microchip_curiosity_circuitpython_nano/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk index c6fbb75fe80..1a39d6ac11a 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk @@ -8,7 +8,7 @@ CHIP_FAMILY = same51 # QSPI_FLASH_FILESYSTEM = 1 INTERNAL_FLASH_FILESYSTEM = 1 -EXTERNAL_FLASH_DEVICES = "SST26VF064B" +EXTERNAL_FLASH_DEVICES = "SST26VF016B,SST26VF032B,SST26VF064B" LONGINT_IMPL = MPZ CIRCUITPY_ULAB = 0 From 6558a85eb9fe8b64f9c7d5e53db9dad06ed312a9 Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Wed, 23 Apr 2025 16:08:13 -0700 Subject: [PATCH 010/876] Removed dual QSPI for flash chips --- .../microchip_curiosity_circuitpython_nano/mpconfigboard.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h index 673a5845851..71cd8829f66 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h @@ -8,8 +8,6 @@ #define MICROPY_HW_LED_STATUS (&pin_PB23) #define MICROPY_HW_NEOPIXEL (&pin_PB22) -#define EXTERNAL_FLASH_QSPI_DUAL - #define BOARD_HAS_CRYSTAL 1 // USB is always used internally so skip the pin objects for it. From a9c9aa5c360870e9e4a6373196dd82b3c0a5f295 Mon Sep 17 00:00:00 2001 From: ross-satchell <59891338+ross-satchell@users.noreply.github.com> Date: Mon, 28 Apr 2025 15:38:56 -0700 Subject: [PATCH 011/876] Updated pins.c to add SD card CS pin and obj for lcd sd --- .../boards/microchip_curiosity_circuitpython_nano/pins.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c index aae64a8a2f8..ef8a44f0874 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c @@ -19,6 +19,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB22) }, { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB23) }, { MP_ROM_QSTR(MP_QSTR_NEOPIX), MP_ROM_PTR(&pin_PB22) }, @@ -49,6 +51,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_PA16) }, { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_PA18) }, { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_PA17) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_PA19) }, { MP_ROM_QSTR(MP_QSTR_SPARE_0), MP_ROM_PTR(&pin_PB00) }, { MP_ROM_QSTR(MP_QSTR_SPARE_1), MP_ROM_PTR(&pin_PB01) }, @@ -62,8 +65,14 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, + { MP_ROM_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, + { MP_ROM_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, + { MP_ROM_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_SDSPI), MP_ROM_PTR(&board_sdspi_obj) }, + { MP_ROM_QSTR(MP_QSTR_LCDSPI), MP_ROM_PTR(&board_lcdspi_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From b0861ec4427135dba8131a7cd5f30f437722fbcb Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 28 Apr 2025 19:22:32 -0500 Subject: [PATCH 012/876] Initial board declarations for Thumby --- .../boards/tinycircuits_thumby/board.c | 105 ++++++++++++++++++ .../tinycircuits_thumby/mpconfigboard.h | 20 ++++ .../tinycircuits_thumby/mpconfigboard.mk | 18 +++ .../pico-sdk-configboard.h | 12 ++ .../boards/tinycircuits_thumby/pins.c | 48 ++++++++ 5 files changed, 203 insertions(+) create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby/board.c create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby/pins.c diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/board.c b/ports/raspberrypi/boards/tinycircuits_thumby/board.c new file mode 100644 index 00000000000..16292dc9e38 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/board.c @@ -0,0 +1,105 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + + +uint8_t display_init_sequence[] = { + /* + 0, 0xae, // display off + 0xd5, 0, 0x80, // set display clock div + 0, 0xd3, 0, 0x00, // set display offset + 0, 0x40, // set start line + 0, 0xa4, // display all on, resume + 0, 0xa6, // normal display + 0, 0x8d, 0, 0x14, // charge pump + 0, 0x20, 0, 0x00, // memory mode + 0, 0xa0, // segremap + 0, 0xc0, // com scan increment + 0, 0x81, 0, 0xff, // set contrast + 0, 0xd9, 0, 0xf1, // set precharge + 0, 0xd8, 0, 0x20, // set v com detect + 0, 0xa8, 0, 40-1, // set multiplex + 0, 0xda, 0, 0x12, // set com pins + 0, 0xad, 0, 0x30, + 0, 0xaf, // on + */ + + 0xae, 0, // sleep + 0xd5, 1, 0x80, // fOsc divide by 2 + 0xd3, 1, 0x00, // set display offset + 0x40, 1, 0x00, // set start line + 0xa4, 0, // display all on, resume + 0xa6, 0, // normal display + 0x8d, 1, 0x14, // charge pump + 0x20, 1, 0x00, // memory mode + 0xa0, 0, // segremap + 0xc0, 0, // com scan increment + 0x81, 1, 0xff, // set contrast + 0xd9, 1, 0xf1, // set precharge + 0xd8, 1, 0x20, // set v com detect + 0xa8, 1, 40-1, // set multiplex + 0xda, 1, 0x12, // set com pins + 0xad, 1, 0x30, + 0xaf, 0, // on +}; + +void board_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + CIRCUITPY_BOARD_OLED_DC, // Command or data + CIRCUITPY_BOARD_OLED_CS, // Chip select + CIRCUITPY_BOARD_OLED_RESET, // Reset + 10000000, // Baudrate + 0, // Polarity + 0); // Phase + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 72, // Width (after rotation) + 40, // Height (after rotation) + 28, // column start + 0, // row start + 0, // rotation + 1, // Color depth + true, // grayscale + false, // pixels in byte share row. only used for depth < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + 0, // Set column command + 0, // Set row command + 0, // Write memory command + display_init_sequence, + sizeof(display_init_sequence), + NULL, // backlight pin + 0x81, + 1.0f, // brightness + true, // single_byte_bounds + true, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + true, // SH1107_addressing + 50000); // backlight pwm frequency +} + +void reset_board(void) { +} diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h new file mode 100644 index 00000000000..06e46139fbc --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "TinyCircuits Thumby" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) + +#define CIRCUITPY_BOARD_OLED_DC (&pin_GPIO17) +#define CIRCUITPY_BOARD_OLED_CS (&pin_GPIO16) +#define CIRCUITPY_BOARD_OLED_RESET (&pin_GPIO20) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL }} diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk new file mode 100644 index 00000000000..44dc0d67100 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk @@ -0,0 +1,18 @@ +USB_VID = 0x1D6B +USB_PID = 0x0003 +USB_PRODUCT = "Thumby" +USB_MANUFACTURER = "TinyCircuits" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" + +CIRCUITPY_STAGE = 1 +CIRCUITPY_AUDIOIO = 1 +CIRCUITPY_AUDIOPWMIO = 1 +CIRCUITPY_KEYPAD = 1 + +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/pico-sdk-configboard.h b/ports/raspberrypi/boards/tinycircuits_thumby/pico-sdk-configboard.h new file mode 100644 index 00000000000..ce5a7645b4e --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/pico-sdk-configboard.h @@ -0,0 +1,12 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. + +// Allow extra time for xosc to start. +#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/pins.c b/ports/raspberrypi/boards/tinycircuits_thumby/pins.c new file mode 100644 index 00000000000..ec04983719e --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby/pins.c @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Link Cable (ASR00074) + { MP_ROM_QSTR(MP_QSTR_EXT_TX), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_EXT), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_EXT_PU), MP_ROM_PTR(&pin_GPIO1) }, + + // 0.42 inch OLED AST1042 + { MP_ROM_QSTR(MP_QSTR_OLED_CS), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_OLED_DC), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_OLED_RESET), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, + + // Buttons + { MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_UP), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_DOWN), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_1), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_2), MP_ROM_PTR(&pin_GPIO27) }, + + // Mono PWM Speaker + { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_GPIO28) }, + + // Hardware revision ID pins + { MP_OBJ_NEW_QSTR(MP_QSTR_ID3), MP_ROM_PTR(&pin_GPIO12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ID2), MP_ROM_PTR(&pin_GPIO13) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ID1), MP_ROM_PTR(&pin_GPIO14) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ID0), MP_ROM_PTR(&pin_GPIO15) }, + + // Power pins + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO26) } +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 992d50a455689aa949f4b5fcc38e29d56c6030de Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 28 Apr 2025 20:53:08 -0400 Subject: [PATCH 013/876] Fix up available SPI buses; swap I2C pins --- .../mpconfigboard.h | 22 +++++++------- .../pins.c | 30 ++++++++++++------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h index 71cd8829f66..31559f318ad 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h @@ -14,18 +14,16 @@ #define IGNORE_PIN_PA24 1 #define IGNORE_PIN_PA25 1 -#define DEFAULT_I2C_BUS_SCL (&pin_PB31) -#define DEFAULT_I2C_BUS_SDA (&pin_PB30) - -#define LCD_SPI_BUS_SCK (&pin_PA05) -#define LCD_SPI_BUS_MOSI (&pin_PA04) -#define LCD_SPI_BUS_CS (&pin_PA07) -#define LCD_BACKLIGHT (&pin_PA06) - -#define SDCARD_SPI_BUS_SCK (&pin_PA17) -#define SDCARD_SPI_BUS_MOSI (&pin_PA16) -#define SDCARD_SPI_BUS_MISO (&pin_PA18) -#define SDCARD_SPI_BUS_CS (&pin_PA19) +#define DEFAULT_I2C_BUS_SCL (&pin_PB30) +#define DEFAULT_I2C_BUS_SDA (&pin_PB31) + +#define CIRCUITPY_BOARD_SPI (3) +// These correspond to the CIRCUITPY_BOARD_BUS_SINGLETON definitions in pins.c +#define CIRCUITPY_BOARD_SPI_PIN { \ + {.clock = &pin_PB03, .mosi = &pin_PB02, .miso = &pin_PB00}, /*board.SPI()*/ \ + {.clock = &pin_PA05, .mosi = &pin_PA04, .miso = NULL}, /*board.LCD_SPI()*/ \ + {.clock = &pin_PA17, .mosi = &pin_PA16, .miso = &pin_PA18}, /*board.SD_SPI()*/ \ +} #define DEFAULT_CAN_BUS_TX (&pin_PB12) #define DEFAULT_CAN_BUS_RX (&pin_PB13) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c index ef8a44f0874..93e96cb2b11 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c @@ -6,6 +6,12 @@ #include "shared-bindings/board/__init__.h" +// The singleton for board.SPI() is already defined. +// board.LCD_SPI() +CIRCUITPY_BOARD_BUS_SINGLETON(lcd_spi, spi, 1) +// board.SD_SPI() +CIRCUITPY_BOARD_BUS_SINGLETON(sd_spi, spi, 2) + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -19,7 +25,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB22) }, { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, - + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB23) }, { MP_ROM_QSTR(MP_QSTR_NEOPIX), MP_ROM_PTR(&pin_PB22) }, @@ -41,8 +47,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, - { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB30) }, - { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB31) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB30) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB31) }, { MP_ROM_QSTR(MP_QSTR_BLE_TX), MP_ROM_PTR(&pin_PA12) }, { MP_ROM_QSTR(MP_QSTR_BLE_RX), MP_ROM_PTR(&pin_PA13) }, @@ -53,9 +59,16 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_PA17) }, { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_PA19) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PB00) }, { MP_ROM_QSTR(MP_QSTR_SPARE_0), MP_ROM_PTR(&pin_PB00) }, + + { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_PB01) }, { MP_ROM_QSTR(MP_QSTR_SPARE_1), MP_ROM_PTR(&pin_PB01) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB02) }, { MP_ROM_QSTR(MP_QSTR_SPARE_2), MP_ROM_PTR(&pin_PB02) }, + + { MP_ROM_QSTR(MP_QSTR_SCK ), MP_ROM_PTR(&pin_PB03) }, { MP_ROM_QSTR(MP_QSTR_SPARE_3), MP_ROM_PTR(&pin_PB03) }, { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, @@ -65,14 +78,11 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, - { MP_ROM_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, - { MP_ROM_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, - { MP_ROM_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, - { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, - { MP_ROM_QSTR(MP_QSTR_SDSPI), MP_ROM_PTR(&board_sdspi_obj) }, - { MP_ROM_QSTR(MP_QSTR_LCDSPI), MP_ROM_PTR(&board_lcdspi_obj) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SPI), MP_ROM_PTR(&board_lcd_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_SD_SPI), MP_ROM_PTR(&board_sd_spi_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From a4af1be162842300e627b7f078ea88a195b86c96 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 28 Apr 2025 20:55:33 -0400 Subject: [PATCH 014/876] fix pre-commit formatting complaint --- .../boards/microchip_curiosity_circuitpython_nano/pins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c index 93e96cb2b11..b4184e3cecd 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c @@ -68,7 +68,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB02) }, { MP_ROM_QSTR(MP_QSTR_SPARE_2), MP_ROM_PTR(&pin_PB02) }, - { MP_ROM_QSTR(MP_QSTR_SCK ), MP_ROM_PTR(&pin_PB03) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB03) }, { MP_ROM_QSTR(MP_QSTR_SPARE_3), MP_ROM_PTR(&pin_PB03) }, { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, From 602a9f61d2a584aa1af53c86e3dac4070217ef46 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 29 Apr 2025 09:26:10 -0500 Subject: [PATCH 015/876] Fix SSD1306 display --- .../boards/tinycircuits_thumby/board.c | 62 ++++++------------- .../tinycircuits_thumby/mpconfigboard.h | 17 ++--- .../boards/tinycircuits_thumby/pins.c | 10 +-- 3 files changed, 34 insertions(+), 55 deletions(-) diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/board.c b/ports/raspberrypi/boards/tinycircuits_thumby/board.c index 16292dc9e38..15a7eeb93a4 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby/board.c +++ b/ports/raspberrypi/boards/tinycircuits_thumby/board.c @@ -16,43 +16,19 @@ uint8_t display_init_sequence[] = { - /* - 0, 0xae, // display off - 0xd5, 0, 0x80, // set display clock div - 0, 0xd3, 0, 0x00, // set display offset - 0, 0x40, // set start line - 0, 0xa4, // display all on, resume - 0, 0xa6, // normal display - 0, 0x8d, 0, 0x14, // charge pump - 0, 0x20, 0, 0x00, // memory mode - 0, 0xa0, // segremap - 0, 0xc0, // com scan increment - 0, 0x81, 0, 0xff, // set contrast - 0, 0xd9, 0, 0xf1, // set precharge - 0, 0xd8, 0, 0x20, // set v com detect - 0, 0xa8, 0, 40-1, // set multiplex - 0, 0xda, 0, 0x12, // set com pins - 0, 0xad, 0, 0x30, - 0, 0xaf, // on - */ - - 0xae, 0, // sleep - 0xd5, 1, 0x80, // fOsc divide by 2 - 0xd3, 1, 0x00, // set display offset - 0x40, 1, 0x00, // set start line - 0xa4, 0, // display all on, resume - 0xa6, 0, // normal display - 0x8d, 1, 0x14, // charge pump - 0x20, 1, 0x00, // memory mode - 0xa0, 0, // segremap - 0xc0, 0, // com scan increment - 0x81, 1, 0xff, // set contrast - 0xd9, 1, 0xf1, // set precharge - 0xd8, 1, 0x20, // set v com detect - 0xa8, 1, 40-1, // set multiplex - 0xda, 1, 0x12, // set com pins - 0xad, 1, 0x30, - 0xaf, 0, // on + 0xAE, 0, // DISPLAY_OFF + 0x20, 1, 0x00, // Set memory addressing to horizontal mode. + 0x81, 1, 0xcf, // set contrast control + 0xA1, 0, // Column 127 is segment 0 + 0xA6, 0, // Normal display + 0xc8, 0, // Normal display + 0xA8, 1, 0x3f, // Mux ratio is 1/64 + 0xd5, 1, 0x80, // Set divide ratio + 0xd9, 1, 0xf1, // Set pre-charge period + 0xda, 1, 0x12, // Set com configuration + 0xdb, 1, 0x40, // Set vcom configuration + 0x8d, 1, 0x14, // Enable charge pump + 0xAF, 0, // DISPLAY_ON }; void board_init(void) { @@ -76,7 +52,7 @@ void board_init(void) { 72, // Width (after rotation) 40, // Height (after rotation) 28, // column start - 0, // row start + 28, // row start 0, // rotation 1, // Color depth true, // grayscale @@ -84,9 +60,9 @@ void board_init(void) { 1, // bytes per cell. Only valid for depths < 8 false, // reverse_pixels_in_byte. Only valid for depths < 8 true, // reverse_pixels_in_word - 0, // Set column command - 0, // Set row command - 0, // Write memory command + 0x21, // Set column command + 0x22, // Set row command + 44, // Write memory command display_init_sequence, sizeof(display_init_sequence), NULL, // backlight pin @@ -97,8 +73,8 @@ void board_init(void) { true, // auto_refresh 60, // native_frames_per_second true, // backlight_on_high - true, // SH1107_addressing - 50000); // backlight pwm frequency + false, // SH1107_addressing + 0); // backlight pwm frequency } void reset_board(void) { diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h index 06e46139fbc..6423f545fd4 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h +++ b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h @@ -6,15 +6,18 @@ #pragma once -#define MICROPY_HW_BOARD_NAME "TinyCircuits Thumby" -#define MICROPY_HW_MCU_NAME "rp2040" +#define MICROPY_HW_BOARD_NAME "TinyCircuits Thumby" +#define MICROPY_HW_MCU_NAME "rp2040" -#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) -#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) -#define CIRCUITPY_BOARD_OLED_DC (&pin_GPIO17) -#define CIRCUITPY_BOARD_OLED_CS (&pin_GPIO16) -#define CIRCUITPY_BOARD_OLED_RESET (&pin_GPIO20) +#define CIRCUITPY_BOARD_OLED_DC (&pin_GPIO17) +#define CIRCUITPY_BOARD_OLED_CS (&pin_GPIO16) +#define CIRCUITPY_BOARD_OLED_RESET (&pin_GPIO20) #define CIRCUITPY_BOARD_SPI (1) #define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL }} + +// For entering safe mode +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO6) diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/pins.c b/ports/raspberrypi/boards/tinycircuits_thumby/pins.c index ec04983719e..4f3d81e7627 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby/pins.c +++ b/ports/raspberrypi/boards/tinycircuits_thumby/pins.c @@ -16,11 +16,11 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_EXT_PU), MP_ROM_PTR(&pin_GPIO1) }, // 0.42 inch OLED AST1042 - { MP_ROM_QSTR(MP_QSTR_OLED_CS), MP_ROM_PTR(&pin_GPIO16) }, - { MP_ROM_QSTR(MP_QSTR_OLED_DC), MP_ROM_PTR(&pin_GPIO17) }, - { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO18) }, - { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) }, - { MP_ROM_QSTR(MP_QSTR_OLED_RESET), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_OLED_CS), MP_ROM_PTR(CIRCUITPY_BOARD_OLED_CS) }, + { MP_ROM_QSTR(MP_QSTR_OLED_DC), MP_ROM_PTR(CIRCUITPY_BOARD_OLED_DC) }, + { MP_ROM_QSTR(MP_QSTR_OLED_RESET), MP_ROM_PTR(CIRCUITPY_BOARD_OLED_RESET) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(DEFAULT_SPI_BUS_SCK) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(DEFAULT_SPI_BUS_MOSI) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, From 67804080a46c45846c76f5ba2409ebac30bde8ba Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 1 May 2025 09:37:18 -0500 Subject: [PATCH 016/876] Added Thumby Color --- .../tinycircuits_thumby/mpconfigboard.h | 2 +- .../boards/tinycircuits_thumby/pins.c | 2 +- .../boards/tinycircuits_thumby_color/board.c | 108 ++++++++++++++++++ .../tinycircuits_thumby_color/mpconfigboard.h | 27 +++++ .../mpconfigboard.mk | 15 +++ .../pico-sdk-configboard.h | 9 ++ .../boards/tinycircuits_thumby_color/pins.c | 58 ++++++++++ 7 files changed, 219 insertions(+), 2 deletions(-) create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby_color/board.c create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby_color/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/tinycircuits_thumby_color/pins.c diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h index 6423f545fd4..91430966d23 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h +++ b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h @@ -17,7 +17,7 @@ #define CIRCUITPY_BOARD_OLED_RESET (&pin_GPIO20) #define CIRCUITPY_BOARD_SPI (1) -#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL }} +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} // For entering safe mode #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO6) diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/pins.c b/ports/raspberrypi/boards/tinycircuits_thumby/pins.c index 4f3d81e7627..0a087bb8db8 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby/pins.c +++ b/ports/raspberrypi/boards/tinycircuits_thumby/pins.c @@ -14,7 +14,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_EXT_TX), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_EXT), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_EXT_PU), MP_ROM_PTR(&pin_GPIO1) }, - + // 0.42 inch OLED AST1042 { MP_ROM_QSTR(MP_QSTR_OLED_CS), MP_ROM_PTR(CIRCUITPY_BOARD_OLED_CS) }, { MP_ROM_QSTR(MP_QSTR_OLED_DC), MP_ROM_PTR(CIRCUITPY_BOARD_OLED_DC) }, diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c b/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c new file mode 100644 index 00000000000..abd80dafc62 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c @@ -0,0 +1,108 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + + +#define DELAY 0x80 + +// display init sequence according to TinyCircuits-Tiny-Game-Engine +uint8_t display_init_sequence[] = { + 0xFE, 0, // inter register enable 1 + 0xEF, 0, // inter register enable 2 + 0xB0, 1, 0xC0, + 0xB1, 1, 0x80, + 0xB2, 1, 0x2F, + 0xB3, 1, 0x03, + 0xB7, 1, 0x01, + 0xB6, 1, 0x19, + 0xAC, 1, 0xC8, // Complement Principle of RGB 5, 6, 5 + 0xAB, 1, 0x0f, // ? + 0x3A, 1, 0x05, // COLMOD: Pixel Format Set + 0xB4, 1, 0x04, // ? + 0xA8, 1, 0x07, // Frame Rate Set + 0xB8, 1, 0x08, // ? + 0xE7, 1, 0x5A, // VREG_CTL + 0xE8, 1, 0x23, // VGH_SET + 0xE9, 1, 0x47, // VGL_SET + 0xEA, 1, 0x99, // VGH_VGL_CLK + 0xC6, 1, 0x30, // ? + 0xC7, 1, 0x1F, // ? + 0xF0, 14, 0x05, 0x1D, 0x51, 0x2F, 0x85, 0x2A, 0x11, 0x62, 0x00, 0x07, 0x07, 0x0F, 0x08, 0x1F, // SET_GAMMA1 + 0xF1, 14, 0x2E, 0x41, 0x62, 0x56, 0xA5, 0x3A, 0x3f, 0x60, 0x0F, 0x07, 0x0A, 0x18, 0x18, 0x1D, // SET_GAMMA2 + 0x11, 0 | DELAY, 120, + 0x29, 0 | DELAY, 10, // display on +}; + +void board_init(void) { + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct( + spi, + DEFAULT_SPI_BUS_SCK, // CLK + DEFAULT_SPI_BUS_MOSI, // MOSI + NULL, // MISO not connected + false // Not half-duplex + ); + + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + CIRCUITPY_BOARD_LCD_DC, // DC + CIRCUITPY_BOARD_LCD_CS, // CS + CIRCUITPY_BOARD_LCD_RESET, // RST + 80000000, // baudrate + 0, // polarity + 0 // phase + ); + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 128, // width (after rotation) + 128, // height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + CIRCUITPY_BOARD_LCD_BACKLIGHT, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} + +void reset_board(void) { +} diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h new file mode 100644 index 00000000000..ce5d015db58 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h @@ -0,0 +1,27 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "TinyCircuits Thumby Color" +#define MICROPY_HW_MCU_NAME "rp2350" + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO9) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO8) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = DEFAULT_I2C_BUS_SCL, .sda = DEFAULT_I2C_BUS_SDA}} + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) + +#define CIRCUITPY_BOARD_LCD_DC (&pin_GPIO16) +#define CIRCUITPY_BOARD_LCD_CS (&pin_GPIO17) +#define CIRCUITPY_BOARD_LCD_RESET (&pin_GPIO11) +#define CIRCUITPY_BOARD_LCD_BACKLIGHT (&pin_GPIO20) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk new file mode 100644 index 00000000000..ed1255e2b96 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk @@ -0,0 +1,15 @@ +USB_VID = 0x1D6B +USB_PID = 0x0003 +USB_PRODUCT = "Thumby Color" +USB_MANUFACTURER = "TinyCircuits" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +CIRCUITPY_STAGE = 1 +CIRCUITPY_AUDIOIO = 1 +CIRCUITPY_AUDIOPWMIO = 1 +CIRCUITPY_KEYPAD = 1 diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/pico-sdk-configboard.h b/ports/raspberrypi/boards/tinycircuits_thumby_color/pico-sdk-configboard.h new file mode 100644 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/pins.c b/ports/raspberrypi/boards/tinycircuits_thumby_color/pins.c new file mode 100644 index 00000000000..d0e63512d7a --- /dev/null +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/pins.c @@ -0,0 +1,58 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Buttons + { MP_ROM_QSTR(MP_QSTR_BUTTON_UP), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_DOWN), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_A), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_B), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_BUMPER_LEFT), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_BUMPER_RIGHT), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_MENU), MP_ROM_PTR(&pin_GPIO26) }, + + // LED + { MP_ROM_QSTR(MP_QSTR_LED_R), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_LED_G), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_LED_B), MP_ROM_PTR(&pin_GPIO12) }, + + // Rumble + { MP_ROM_QSTR(MP_QSTR_RUMBLE), MP_ROM_PTR(&pin_GPIO5) }, + + // Mono PWM Speaker + { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_SPEAKER_ENABLE), MP_ROM_PTR(&pin_GPIO20) }, + + // 0.85 inch TFT GC9107 + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(CIRCUITPY_BOARD_LCD_CS) }, + { MP_ROM_QSTR(MP_QSTR_LCD_DC), MP_ROM_PTR(CIRCUITPY_BOARD_LCD_DC) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RESET), MP_ROM_PTR(CIRCUITPY_BOARD_LCD_RESET) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BACKLIGHT), MP_ROM_PTR(CIRCUITPY_BOARD_LCD_BACKLIGHT) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(DEFAULT_SPI_BUS_SCK) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(DEFAULT_SPI_BUS_MOSI) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, + { MP_ROM_QSTR(MP_QSTR_LCD_SPI), MP_ROM_PTR(&board_spi_obj) }, + + // RTC I2C + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(DEFAULT_I2C_BUS_SDA) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(DEFAULT_I2C_BUS_SCL) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + // Power pins + { MP_ROM_QSTR(MP_QSTR_CHARGE_STAT), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 987cade17341faa8e2f4d5afd8173088d01dc852 Mon Sep 17 00:00:00 2001 From: hannah Date: Tue, 17 Jun 2025 08:26:50 +0000 Subject: [PATCH 017/876] Add WIZnet W55RP20-EVB-Pico --- .../boards/wiznet_w55rp20_evb_pico/board.c | 9 +++ .../wiznet_w55rp20_evb_pico/mpconfigboard.h | 30 ++++++++ .../wiznet_w55rp20_evb_pico/mpconfigboard.mk | 13 ++++ .../pico-sdk-configboard.h | 9 +++ .../boards/wiznet_w55rp20_evb_pico/pins.c | 73 +++++++++++++++++++ 5 files changed, 134 insertions(+) create mode 100755 ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/board.c create mode 100755 ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.h create mode 100755 ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk create mode 100755 ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pico-sdk-configboard.h create mode 100755 ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/board.c b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/board.c new file mode 100755 index 00000000000..e6a868ab212 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.h b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.h new file mode 100755 index 00000000000..b5ccfb5ffd9 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.h @@ -0,0 +1,30 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "W55RP20-EVB-Pico" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO19) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO21) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO23) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO22) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO1) +#define DEFAULT_UART_BUS_TX (&pin_GPIO0) + +// Wiznet HW config. +#define MICROPY_HW_WIZNET_PIO_SPI_ID (0) +#define MICROPY_HW_WIZNET_PIO_SPI_BAUDRATE (20 * 1000 * 1000) +#define MICROPY_HW_WIZNET_PIO_SPI_SCK (21) +#define MICROPY_HW_WIZNET_PIO_SPI_MOSI (23) +#define MICROPY_HW_WIZNET_PIO_SPI_MISO (22) +#define MICROPY_HW_WIZNET_PIO_PIN_CS (20) +#define MICROPY_HW_WIZNET_PIO_PIN_RST (25) +// Connecting the INTN pin enables RECV interrupt handling of incoming data. +#define MICROPY_HW_WIZNET_PIN_INTN (24) diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk new file mode 100755 index 00000000000..12d673ce7b0 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk @@ -0,0 +1,13 @@ +USB_VID = 0x2E8A +USB_PID = 0x0005 +USB_PRODUCT = "WIZNET W55RP20 EVB PICO" +USB_MANUFACTURER = "WIZNET" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" + +CIRCUITPY__EVE = 1 +CIRCUITPY_SSL = 1 +CIRCUITPY_USB_HOST = 0 \ No newline at end of file diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pico-sdk-configboard.h b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pico-sdk-configboard.h new file mode 100755 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c new file mode 100755 index 00000000000..c0db99042c0 --- /dev/null +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c @@ -0,0 +1,73 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_CS), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_SCK), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_MISO), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_MOSI), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_INT), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_RST), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_W5K_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From d78a9c7ba0b481c5d10ff6ce70874876560900a3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 17 Jun 2025 17:24:03 -0400 Subject: [PATCH 018/876] curiosity: switch back to external flash filesystem --- .../microchip_curiosity_circuitpython_nano/mpconfigboard.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk index 1a39d6ac11a..408c4eca9fd 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk @@ -6,8 +6,7 @@ USB_MANUFACTURER = "Microchip Technology Inc" CHIP_VARIANT = SAME51J20A CHIP_FAMILY = same51 -# QSPI_FLASH_FILESYSTEM = 1 -INTERNAL_FLASH_FILESYSTEM = 1 +QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "SST26VF016B,SST26VF032B,SST26VF064B" LONGINT_IMPL = MPZ CIRCUITPY_ULAB = 0 From 56ffd4eca71b829ea20cff76e857c164bc15008f Mon Sep 17 00:00:00 2001 From: hannah Date: Fri, 20 Jun 2025 08:51:52 +0000 Subject: [PATCH 019/876] Add functions and define for wiznet_pio_spi support. --- ports/raspberrypi/Makefile | 29 ++ .../wiznet_w55rp20_evb_pico/mpconfigboard.mk | 5 +- .../common-hal/busio/WIZNET_PIO_SPI.c | 123 +++++ .../common-hal/busio/WIZNET_PIO_SPI.h | 25 + .../wiznet_pio_spi/wizchip_pio_spi.c | 389 ++++++++++++++ .../wiznet_pio_spi/wizchip_pio_spi.h | 43 ++ .../wiznet_pio_spi/wizchip_pio_spi.pio | 24 + py/circuitpy_defns.mk | 3 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/busio/WIZNET_PIO_SPI.c | 486 ++++++++++++++++++ shared-bindings/busio/WIZNET_PIO_SPI.h | 40 ++ shared-bindings/busio/__init__.c | 7 + 12 files changed, 1175 insertions(+), 2 deletions(-) mode change 100644 => 100755 ports/raspberrypi/Makefile create mode 100755 ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c create mode 100755 ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h create mode 100755 ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c create mode 100755 ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.h create mode 100755 ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio mode change 100644 => 100755 py/circuitpy_defns.mk mode change 100644 => 100755 py/circuitpy_mpconfig.mk create mode 100755 shared-bindings/busio/WIZNET_PIO_SPI.c create mode 100755 shared-bindings/busio/WIZNET_PIO_SPI.h mode change 100644 => 100755 shared-bindings/busio/__init__.c diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile old mode 100644 new mode 100755 index 6565af79bf3..e1f17adb402 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -83,6 +83,33 @@ SRC_CYW43 := SRC_LWIP := endif +ifeq ($(CIRCUITPY_WIZNET_PIO_SPI), 1) +INC_WIZNET_PIO_SPI := \ + -isystem wiznet_pio_spi \ + +SRC_WIZNET_PIO_SPI := \ + wiznet_pio_spi/wizchip_pio_spi.c \ + +WIZNET_PIOASM = $(BUILD)/pioasm/pioasm/pioasm +.PHONY: pioasmBuild +pioasmBuild: $(WIZNET_PIOASM) + +$(WIZNET_PIOASM): + $(Q)cmake -S pioasm -B $(BUILD)/pioasm + $(MAKE) -C $(BUILD)/pioasm pioasmBuild + +$(BUILD)/wizchip_pio_spi.pio.h: wiznet_pio_spi/wizchip_pio_spi.pio $(WIZNET_PIOASM) + $(Q)$(WIZNET_PIOASM) -o c-sdk $< $@ +$(BUILD)/wiznet_pio_spi/wizchip_pio_spi.o: $(BUILD)/wizchip_pio_spi.pio.h + +$(BUILD)/genhdr/qstr.i.last: $(BUILD)/wizchip_pio_spi.pio.h + +else +INC_WIZNET_PIO_SPI := +SRC_WIZNET_PIO_SPI := + +endif + CHIP_VARIANT_LOWER = $(shell echo $(CHIP_VARIANT) | tr '[:upper:]' '[:lower:]') INC += \ @@ -155,6 +182,7 @@ INC += \ -isystem sdk/src/rp2_common/pico_time_adapter/include/ \ -isystem sdk/src/rp2_common/pico_unique_id/include/ \ $(INC_CYW43) \ + $(INC_WIZNET_PIO_SPI) \ -Isdk_config \ -I../../lib/tinyusb/src \ -I../../supervisor/shared/usb \ @@ -541,6 +569,7 @@ SRC_C += \ mphalport.c \ $(SRC_CYW43) \ $(SRC_LWIP) \ + $(SRC_WIZNET_PIO_SPI) \ ifeq ($(CIRCUITPY_USB_HOST), 1) diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk index 12d673ce7b0..6045e5c8986 100755 --- a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk @@ -1,13 +1,14 @@ USB_VID = 0x2E8A USB_PID = 0x0005 -USB_PRODUCT = "WIZNET W55RP20 EVB PICO" -USB_MANUFACTURER = "WIZNET" +USB_PRODUCT = "W55RP20-EVB-Pico" +USB_MANUFACTURER = "WIZnet" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" +CIRCUITPY_WIZNET_PIO_SPI = 1 CIRCUITPY__EVE = 1 CIRCUITPY_SSL = 1 CIRCUITPY_USB_HOST = 0 \ No newline at end of file diff --git a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c b/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c new file mode 100755 index 00000000000..a90646e47aa --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c @@ -0,0 +1,123 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/busio/WIZNET_PIO_SPI.h" + +#include "shared/runtime/interrupt_char.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "supervisor/board.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "hardware/dma.h" +#include "hardware/gpio.h" +#include "hardware/pio.h" +#include "hardware/clocks.h" + +#include "wiznet_pio_spi/wizchip_pio_spi.h" + +#define NO_INSTANCE 0xff + +#ifndef PIO_SPI_PREFERRED_PIO +#define PIO_SPI_PREFERRED_PIO 1 +#endif + +// All wiznet spi operations must start with writing a 3 byte header + +wiznet_pio_spi_config_t wiznet_pio_spi_config; +wiznet_pio_spi_handle_t wiznet_pio_spi_handle = NULL; + +void common_hal_wiznet_pio_spi_construct(wiznet_pio_spi_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso, bool half_duplex) { + + if (half_duplex) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); + } + + wiznet_pio_spi_config.data_in_pin = miso->number; + wiznet_pio_spi_config.data_out_pin = mosi->number; + wiznet_pio_spi_config.clock_pin = clock->number; + + if (wiznet_pio_spi_handle != NULL) { + wiznet_pio_spi_close(wiznet_pio_spi_handle); + } + + wiznet_pio_spi_handle = wiznet_pio_spi_open(&wiznet_pio_spi_config); + (*wiznet_pio_spi_handle)->set_active(wiznet_pio_spi_handle); + +} + +bool common_hal_wiznet_pio_spi_deinited(wiznet_pio_spi_obj_t *self) { + return wiznet_pio_spi_config.clock_pin == 0; +} + +void common_hal_wiznet_pio_spi_deinit(wiznet_pio_spi_obj_t *self) { + if (common_hal_wiznet_pio_spi_deinited(self)) { + return; + } + + common_hal_reset_pin(self->clock); + common_hal_reset_pin(self->MOSI); + common_hal_reset_pin(self->MISO); + + wiznet_pio_spi_config.clock_pin = 0; +} + +bool common_hal_wiznet_pio_spi_configure(wiznet_pio_spi_obj_t *self, + uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { + + uint32_t clock = clock_get_hz(clk_sys); + uint32_t clock_div = clock / baudrate; + + if (clock_div > clock / 4) { + clock_div = clock / 4; + } + + wiznet_pio_spi_config.clock_div_major = clock_div; + wiznet_pio_spi_config.clock_div_minor = 0; + + return true; +} + +bool common_hal_wiznet_pio_spi_try_lock(wiznet_pio_spi_obj_t *self) { + if (common_hal_wiznet_pio_spi_deinited(self)) { + return false; + } + + bool grabbed_lock = false; + if (!self->has_lock) { + grabbed_lock = true; + self->has_lock = true; + } + return grabbed_lock; +} + +bool common_hal_wiznet_pio_spi_has_lock(wiznet_pio_spi_obj_t *self) { + return self->has_lock; +} + +void common_hal_wiznet_pio_spi_unlock(wiznet_pio_spi_obj_t *self) { + self->has_lock = false; +} + +bool common_hal_wiznet_pio_spi_write(wiznet_pio_spi_obj_t *self, + const uint8_t *data, size_t len) { + wiznet_pio_spi_write_buffer(data, len); + return true; +} + +bool common_hal_wiznet_pio_spi_read(wiznet_pio_spi_obj_t *self, + uint8_t *data, size_t len, uint8_t write_value) { + wiznet_pio_spi_read_buffer(data, len); + return true; +} + +bool common_hal_wiznet_pio_spi_transfer(wiznet_pio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { + return wiznet_pio_spi_transfer(data_out, len, data_in, len); +} \ No newline at end of file diff --git a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h b/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h new file mode 100755 index 00000000000..29d077b4341 --- /dev/null +++ b/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h @@ -0,0 +1,25 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" + +#include "py/obj.h" + +#include "hardware/spi.h" + +#define SPI_HEADER_LEN 3 + +typedef struct { + mp_obj_base_t base; + bool has_lock; + const mcu_pin_obj_t *clock; + const mcu_pin_obj_t *MOSI; + const mcu_pin_obj_t *MISO; +} wiznet_pio_spi_obj_t; + +void reset_spi(void); \ No newline at end of file diff --git a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c new file mode 100755 index 00000000000..564dd9191b0 --- /dev/null +++ b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include "pico/stdlib.h" +#include "pico/error.h" + +#include "hardware/dma.h" +#include "hardware/clocks.h" + +#include "wizchip_pio_spi.h" +#include "wizchip_pio_spi.pio.h" + +#ifndef PIO_SPI_PREFERRED_PIO +#define PIO_SPI_PREFERRED_PIO 1 +#endif + +#define PADS_DRIVE_STRENGTH PADS_BANK0_GPIO0_DRIVE_VALUE_12MA +#define IRQ_SAMPLE_DELAY_NS 100 + +#define WIZNET_PIO_SPI_PROGRAM_NAME wiznet_pio_spi_write_read +#define WIZNET_PIO_SPI_PROGRAM_FUNC __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _program) +#define WIZNET_PIO_SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _program_get_default_config) +#define WIZNET_PIO_SPI_OFFSET_WRITE_BITS __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_write_bits) +#define WIZNET_PIO_SPI_OFFSET_WRITE_END __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_write_end) +#define WIZNET_PIO_SPI_OFFSET_READ_END __CONCAT(WIZNET_PIO_SPI_PROGRAM_NAME, _offset_read_end) + +// All wiznet spi operations must start with writing a 3 byte header +#define WIZNET_PIO_SPI_HEADER_LEN 3 + +#ifndef WIZNET_PICO_PIO_SPI_INSTANCE_COUNT +#define WIZNET_PICO_PIO_SPI_INSTANCE_COUNT 1 +#endif + +typedef struct wiznet_pio_spi_state { + wiznet_pio_spi_funcs_t *funcs; + const wiznet_pio_spi_config_t *spi_config; + pio_hw_t *pio; + uint8_t pio_func_sel; + int8_t pio_offset; + int8_t pio_sm; + int8_t dma_out; + int8_t dma_in; + uint8_t spi_header[WIZNET_PIO_SPI_HEADER_LEN]; + uint8_t spi_header_count; +} wiznet_pio_spi_state_t; +static wiznet_pio_spi_state_t wiznet_pio_spi_state[WIZNET_PICO_PIO_SPI_INSTANCE_COUNT]; +static wiznet_pio_spi_state_t *active_state; + +static wiznet_pio_spi_funcs_t *get_wiznet_pio_spi_impl(void); + +// Initialise our gpios +static void wiznet_pio_spi_gpio_setup(wiznet_pio_spi_state_t *state) { + + // Setup MOSI, MISO and IRQ + gpio_init(state->spi_config->data_out_pin); + gpio_set_dir(state->spi_config->data_out_pin, GPIO_OUT); + gpio_put(state->spi_config->data_out_pin, false); + + gpio_init(state->spi_config->data_in_pin); + gpio_set_dir(state->spi_config->data_in_pin, GPIO_IN); + + // Setup CS + gpio_init(state->spi_config->cs_pin); + gpio_set_dir(state->spi_config->cs_pin, GPIO_OUT); + gpio_put(state->spi_config->cs_pin, true); + + // Setup IRQ + gpio_init(state->spi_config->irq_pin); + gpio_set_dir(state->spi_config->irq_pin, GPIO_IN); + gpio_set_pulls(state->spi_config->irq_pin, false, false); +} + +wiznet_pio_spi_handle_t wiznet_pio_spi_open(const wiznet_pio_spi_config_t *wiznet_pio_spi_config) { + wiznet_pio_spi_state_t *state; + for (size_t i = 0; i < count_of(wiznet_pio_spi_state); i++) { + if (!wiznet_pio_spi_state[i].funcs) { + state = &wiznet_pio_spi_state[i]; + break; + } + } + assert(state); + // if (!state) return NULL; + state->spi_config = wiznet_pio_spi_config; + state->funcs = get_wiznet_pio_spi_impl(); + + wiznet_pio_spi_gpio_setup(state); + + pio_hw_t *pios[2] = {pio0, pio1}; + uint pio_index = PIO_SPI_PREFERRED_PIO; + + if (!pio_can_add_program(pios[pio_index], &WIZNET_PIO_SPI_PROGRAM_FUNC)) { + pio_index ^= 1; + if (!pio_can_add_program(pios[pio_index], &WIZNET_PIO_SPI_PROGRAM_FUNC)) { + return NULL; + } + } + + state->pio = pios[pio_index]; + state->dma_in = -1; + state->dma_out = -1; + + static_assert(GPIO_FUNC_PIO1 == GPIO_FUNC_PIO0 + 1, ""); + state->pio_func_sel = GPIO_FUNC_PIO0 + pio_index; + state->pio_sm = (int8_t)pio_claim_unused_sm(state->pio, false); + if (state->pio_sm < 0) { + wiznet_pio_spi_close(&state->funcs); + return NULL; + } + + state->pio_offset = pio_add_program(state->pio, &WIZNET_PIO_SPI_PROGRAM_FUNC); + + pio_sm_config sm_config = WIZNET_PIO_SPI_PROGRAM_GET_DEFAULT_CONFIG_FUNC(state->pio_offset); + + sm_config_set_clkdiv_int_frac(&sm_config, state->spi_config->clock_div_major, state->spi_config->clock_div_minor); + hw_write_masked(&pads_bank0_hw->io[state->spi_config->clock_pin], + (uint)PADS_DRIVE_STRENGTH << PADS_BANK0_GPIO0_DRIVE_LSB, + PADS_BANK0_GPIO0_DRIVE_BITS + ); + hw_write_masked(&pads_bank0_hw->io[state->spi_config->clock_pin], + (uint)1 << PADS_BANK0_GPIO0_SLEWFAST_LSB, + PADS_BANK0_GPIO0_SLEWFAST_BITS + ); + + sm_config_set_out_pins(&sm_config, state->spi_config->data_out_pin, 1); + sm_config_set_in_pins(&sm_config, state->spi_config->data_in_pin); + sm_config_set_set_pins(&sm_config, state->spi_config->data_out_pin, 1); + sm_config_set_sideset(&sm_config, 1, false, false); + sm_config_set_sideset_pins(&sm_config, state->spi_config->clock_pin); + + sm_config_set_in_shift(&sm_config, false, true, 8); + sm_config_set_out_shift(&sm_config, false, true, 8); + hw_set_bits(&state->pio->input_sync_bypass, 1u << state->spi_config->data_in_pin); + pio_sm_set_config(state->pio, state->pio_sm, &sm_config); + pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->clock_pin, 1, true); + gpio_set_function(state->spi_config->data_out_pin, state->pio_func_sel); + gpio_set_function(state->spi_config->clock_pin, state->pio_func_sel); + + // Set data pin to pull down and schmitt + gpio_set_pulls(state->spi_config->data_in_pin, false, true); + gpio_set_input_hysteresis_enabled(state->spi_config->data_in_pin, true); + + pio_sm_exec(state->pio, state->pio_sm, pio_encode_set(pio_pins, 1)); + state->dma_out = (int8_t)dma_claim_unused_channel(false); // todo: Should be able to use one dma channel? + state->dma_in = (int8_t)dma_claim_unused_channel(false); + if (state->dma_out < 0 || state->dma_in < 0) { + wiznet_pio_spi_close(&state->funcs); + return NULL; + } + return &state->funcs; +} + +void wiznet_pio_spi_close(wiznet_pio_spi_handle_t handle) { + wiznet_pio_spi_state_t *state = (wiznet_pio_spi_state_t *)handle; + if (state) { + if (state->pio_sm >= 0) { + if (state->pio_offset != -1) { + pio_remove_program(state->pio, &WIZNET_PIO_SPI_PROGRAM_FUNC, state->pio_offset); + } + + pio_sm_unclaim(state->pio, state->pio_sm); + } + if (state->dma_out >= 0) { + dma_channel_unclaim(state->dma_out); + state->dma_out = -1; + } + if (state->dma_in >= 0) { + dma_channel_unclaim(state->dma_in); + state->dma_in = -1; + } + state->funcs = NULL; + } +} + +static void cs_set(wiznet_pio_spi_state_t *state, bool value) { + gpio_put(state->spi_config->cs_pin, value); +} + +static __noinline void ns_delay(uint32_t ns) { + // cycles = ns * clk_sys_hz / 1,000,000,000 + uint32_t cycles = ns * (clock_get_hz(clk_sys) >> 16u) / (1000000000u >> 16u); + busy_wait_at_least_cycles(cycles); +} + +static void wiznet_pio_spi_frame_start(void) { + assert(active_state); + + gpio_set_function(active_state->spi_config->data_out_pin, active_state->pio_func_sel); + gpio_set_function(active_state->spi_config->clock_pin, active_state->pio_func_sel); + gpio_pull_down(active_state->spi_config->clock_pin); + + // Pull CS low + cs_set(active_state, false); +} + +static void wiznet_pio_spi_frame_end(void) { + assert(active_state); + + // from this point a positive edge will cause an IRQ to be pending + cs_set(active_state, true); + + // we need to wait a bit in case the irq line is incorrectly high + #ifdef IRQ_SAMPLE_DELAY_NS + ns_delay(IRQ_SAMPLE_DELAY_NS); + #endif +} + +// send tx then receive rx +// rx can be null if you just want to send, but tx and tx_length must be valid +bool wiznet_pio_spi_transfer(const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length) { + const wiznet_pio_spi_state_t *state = active_state; + if (!state || (tx == NULL)) { + return false; + } + + if (rx != NULL && tx != NULL) { + assert(tx && tx_length && rx_length); + + pio_sm_set_enabled(state->pio, state->pio_sm, false); // disable sm + pio_sm_set_wrap(state->pio, state->pio_sm, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS, state->pio_offset + WIZNET_PIO_SPI_OFFSET_READ_END - 1); + pio_sm_clear_fifos(state->pio, state->pio_sm); // clear fifos from previous run + pio_sm_set_pindirs_with_mask(state->pio, state->pio_sm, 1u << state->spi_config->data_out_pin, 1u << state->spi_config->data_out_pin); + pio_sm_restart(state->pio, state->pio_sm); + pio_sm_clkdiv_restart(state->pio, state->pio_sm); + pio_sm_put(state->pio, state->pio_sm, tx_length * 8 - 1); // set x + pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_x, 32)); + pio_sm_put(state->pio, state->pio_sm, rx_length - 1); // set y + pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_y, 32)); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_jmp(state->pio_offset)); // setup pc + + dma_channel_abort(state->dma_out); + dma_channel_abort(state->dma_in); + + dma_channel_config out_config = dma_channel_get_default_config(state->dma_out); + channel_config_set_dreq(&out_config, pio_get_dreq(state->pio, state->pio_sm, true)); + channel_config_set_transfer_data_size(&out_config, DMA_SIZE_8); + dma_channel_configure(state->dma_out, &out_config, &state->pio->txf[state->pio_sm], tx, tx_length, true); + + dma_channel_config in_config = dma_channel_get_default_config(state->dma_in); + channel_config_set_dreq(&in_config, pio_get_dreq(state->pio, state->pio_sm, false)); + channel_config_set_write_increment(&in_config, true); + channel_config_set_read_increment(&in_config, false); + channel_config_set_transfer_data_size(&in_config, DMA_SIZE_8); + dma_channel_configure(state->dma_in, &in_config, rx, &state->pio->rxf[state->pio_sm], rx_length, true); + + pio_sm_set_enabled(state->pio, state->pio_sm, true); + __compiler_memory_barrier(); + + dma_channel_wait_for_finish_blocking(state->dma_out); + dma_channel_wait_for_finish_blocking(state->dma_in); + + __compiler_memory_barrier(); + } else if (tx != NULL) { + assert(tx_length); + + pio_sm_set_enabled(state->pio, state->pio_sm, false); + pio_sm_set_wrap(state->pio, state->pio_sm, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS, state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_END - 1); + pio_sm_clear_fifos(state->pio, state->pio_sm); + pio_sm_restart(state->pio, state->pio_sm); + pio_sm_clkdiv_restart(state->pio, state->pio_sm); + pio_sm_put(state->pio, state->pio_sm, tx_length * 8 - 1); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_x, 32)); + pio_sm_put(state->pio, state->pio_sm, tx_length - 1); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_out(pio_y, 32)); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_set(pio_pins, 0)); + pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->data_out_pin, 1, true); + pio_sm_exec(state->pio, state->pio_sm, pio_encode_jmp(state->pio_offset + WIZNET_PIO_SPI_OFFSET_WRITE_BITS)); + + dma_channel_abort(state->dma_out); + + dma_channel_config out_config = dma_channel_get_default_config(state->dma_out); + channel_config_set_dreq(&out_config, pio_get_dreq(state->pio, state->pio_sm, true)); + + channel_config_set_transfer_data_size(&out_config, DMA_SIZE_8); + dma_channel_configure(state->dma_out, &out_config, &state->pio->txf[state->pio_sm], tx, tx_length, true); + + const uint32_t fDebugTxStall = 1u << (PIO_FDEBUG_TXSTALL_LSB + state->pio_sm); + state->pio->fdebug = fDebugTxStall; + pio_sm_set_enabled(state->pio, state->pio_sm, true); + while (!(state->pio->fdebug & fDebugTxStall)) { + // printf("WIZNET_PIO_SPI: waiting for tx stall\n"); + tight_loop_contents(); // todo timeout + } + uint32_t timeout = 1000000; + if (timeout == 0) { + printf("ERROR: PIO TXSTALL timeout!\n"); + return false; + } + __compiler_memory_barrier(); + pio_sm_set_enabled(state->pio, state->pio_sm, false); + pio_sm_set_consecutive_pindirs(state->pio, state->pio_sm, state->spi_config->data_in_pin, 1, false); + } else if (rx != NULL) { + panic_unsupported(); // shouldn't be used + } + pio_sm_exec(state->pio, state->pio_sm, pio_encode_mov(pio_pins, pio_null)); // for next time we turn output on + + return true; +} + +// To read a byte we must first have been asked to write a 3 byte spi header +static uint8_t wiznet_pio_spi_read_byte(void) { + assert(active_state); + assert(active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN); + uint8_t ret; + if (!wiznet_pio_spi_transfer(active_state->spi_header, active_state->spi_header_count, &ret, 1)) { + panic("spi failed read"); + } + active_state->spi_header_count = 0; + return ret; +} + +// This is not used when the burst functions are provided +static void wiznet_pio_spi_write_byte(uint8_t wb) { + panic_unsupported(); // shouldn't be used +} + +// To read a buffer we must first have been asked to write a 3 byte spi header +void wiznet_pio_spi_read_buffer(uint8_t *pBuf, uint16_t len) { + assert(active_state); + assert(active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN); + if (!wiznet_pio_spi_transfer(active_state->spi_header, active_state->spi_header_count, pBuf, len)) { + panic("spi failed reading buffer"); + } + active_state->spi_header_count = 0; +} + +// If we have been asked to write a spi header already, then write it and the rest of the buffer +// or else if we've been given enough data for just the spi header, save it until the next call +// or we're writing a byte in which case we're given a buffer including the spi header +void wiznet_pio_spi_write_buffer(const uint8_t *pBuf, uint16_t len) { + assert(active_state); + + if (len < WIZNET_PIO_SPI_HEADER_LEN && active_state->spi_header_count != WIZNET_PIO_SPI_HEADER_LEN) { + memcpy(&active_state->spi_header[active_state->spi_header_count], pBuf, len); // expect another call + active_state->spi_header_count++; + } else if (len == WIZNET_PIO_SPI_HEADER_LEN && active_state->spi_header_count == 0) { + memcpy(active_state->spi_header, pBuf, WIZNET_PIO_SPI_HEADER_LEN); // expect another call + active_state->spi_header_count = WIZNET_PIO_SPI_HEADER_LEN; + } else { + if (active_state->spi_header_count == WIZNET_PIO_SPI_HEADER_LEN) { + if (!wiznet_pio_spi_transfer(active_state->spi_header, WIZNET_PIO_SPI_HEADER_LEN, NULL, 0)) { + panic("spi failed writing header"); + } + active_state->spi_header_count = 0; + } + assert(active_state->spi_header_count == 0); + if (!wiznet_pio_spi_transfer(pBuf, len, NULL, 0)) { + panic("spi failed writing buffer"); + } + } +} + +static void wiznet_pio_spi_set_active(wiznet_pio_spi_handle_t handle) { + active_state = (wiznet_pio_spi_state_t *)handle; +} + +static void wiznet_pio_spi_set_inactive(void) { + active_state = NULL; +} + +static void wiznet_pio_spi_reset(wiznet_pio_spi_handle_t handle) { + wiznet_pio_spi_state_t *state = (wiznet_pio_spi_state_t *)handle; + gpio_set_dir(state->spi_config->reset_pin, GPIO_OUT); + gpio_put(state->spi_config->reset_pin, 0); + sleep_ms(100); + gpio_put(state->spi_config->reset_pin, 1); + sleep_ms(100); +} + +static wiznet_pio_spi_funcs_t *get_wiznet_pio_spi_impl(void) { + static wiznet_pio_spi_funcs_t funcs = { + .close = wiznet_pio_spi_close, + .set_active = wiznet_pio_spi_set_active, + .set_inactive = wiznet_pio_spi_set_inactive, + .frame_start = wiznet_pio_spi_frame_start, + .frame_end = wiznet_pio_spi_frame_end, + .read_byte = wiznet_pio_spi_read_byte, + .write_byte = wiznet_pio_spi_write_byte, + .read_buffer = wiznet_pio_spi_read_buffer, + .write_buffer = wiznet_pio_spi_write_buffer, + .reset = wiznet_pio_spi_reset, + }; + return &funcs; +} diff --git a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.h b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.h new file mode 100755 index 00000000000..841eb48c480 --- /dev/null +++ b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Raspberry Pi (Trading) Ltd. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _WIZNET_PIO_SPI_H_ +#define _WIZNET_PIO_SPI_H_ + +typedef struct wiznet_pio_spi_config { + uint8_t data_in_pin; + uint8_t data_out_pin; + uint8_t cs_pin; + uint8_t clock_pin; + uint8_t irq_pin; + uint8_t reset_pin; + uint16_t clock_div_major; + uint8_t clock_div_minor; + uint8_t spi_hw_instance; +} wiznet_pio_spi_config_t; + +typedef struct wiznet_pio_spi_funcs **wiznet_pio_spi_handle_t; + +typedef struct wiznet_pio_spi_funcs { + void (*close)(wiznet_pio_spi_handle_t funcs); + void (*set_active)(wiznet_pio_spi_handle_t funcs); + void (*set_inactive)(void); + void (*frame_start)(void); + void (*frame_end)(void); + uint8_t (*read_byte)(void); + void (*write_byte)(uint8_t tx_data); + void (*read_buffer)(uint8_t *pBuf, uint16_t len); + void (*write_buffer)(const uint8_t *pBuf, uint16_t len); + void (*reset)(wiznet_pio_spi_handle_t funcs); +} wiznet_pio_spi_funcs_t; + +wiznet_pio_spi_handle_t wiznet_pio_spi_open(const wiznet_pio_spi_config_t *pio_spi_config); +void wiznet_pio_spi_close(wiznet_pio_spi_handle_t handle); +bool wiznet_pio_spi_transfer(const uint8_t *tx, size_t tx_length, uint8_t *rx, size_t rx_length); +void wiznet_pio_spi_read_buffer(uint8_t *pBuf, uint16_t len); +void wiznet_pio_spi_write_buffer(const uint8_t *pBuf, uint16_t len); + +#endif diff --git a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio new file mode 100755 index 00000000000..092a2b589a7 --- /dev/null +++ b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio @@ -0,0 +1,24 @@ +; +; Copyright (c) 2023 Raspberry Pi (Trading) Ltd. +; +; SPDX-License-Identifier: BSD-3-Clause +; + +.program wiznet_pio_spi_write_read +.side_set 1 + +public write_bits: + out pins, 1 side 0 + jmp x-- write_bits side 1 + set pins 0 side 0 +public write_end: +read_byte_delay: + set pindirs 0 side 0 +read_byte: + set x 6 side 1 +read_bits: + in pins, 1 side 0 + jmp x-- read_bits side 1 + in pins, 1 side 0 + jmp y-- read_byte side 0 +public read_end: \ No newline at end of file diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk old mode 100644 new mode 100755 index d6569bc39bd..de9703811c7 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -459,6 +459,9 @@ endif ifeq ($(CIRCUITPY_WIFI),1) SRC_PATTERNS += wifi/% endif +ifeq ($(CIRCUITPY_WIZNET_PIO_SPI),1) +SRC_PATTERNS += busio/WIZNET_PIO_SPI.c busio/WIZNET_PIO_SPI.h +endif ifeq ($(CIRCUITPY_ZLIB),1) SRC_PATTERNS += zlib/% endif diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk old mode 100644 new mode 100755 index 2009c4e177d..9fa788d6fb3 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -206,6 +206,9 @@ CFLAGS += -DCIRCUITPY_BUSIO_SPI=$(CIRCUITPY_BUSIO_SPI) CIRCUITPY_BUSIO_UART ?= $(CIRCUITPY_BUSIO) CFLAGS += -DCIRCUITPY_BUSIO_UART=$(CIRCUITPY_BUSIO_UART) +CIRCUITPY_WIZNET_PIO_SPI ?= 0 +CFLAGS += -DCIRCUITPY_WIZNET_PIO_SPI=$(CIRCUITPY_WIZNET_PIO_SPI) + CIRCUITPY_CAMERA ?= 0 CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA) diff --git a/shared-bindings/busio/WIZNET_PIO_SPI.c b/shared-bindings/busio/WIZNET_PIO_SPI.c new file mode 100755 index 00000000000..81a74f933d0 --- /dev/null +++ b/shared-bindings/busio/WIZNET_PIO_SPI.c @@ -0,0 +1,486 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft +// +// SPDX-License-Identifier: MIT + +// This file contains all of the Python API definitions for the +// busio.SPI class. + +#include + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/WIZNET_PIO_SPI.h" +#include "shared-bindings/util.h" + +#include "shared/runtime/buffer_helper.h" +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/mperrno.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include + + +//| class SPI: +//| """A 3-4 wire serial protocol +//| +//| SPI is a serial protocol that has exclusive pins for data in and out of the +//| main device. It is typically faster than :py:class:`~bitbangio.I2C` because a +//| separate pin is used to select a device rather than a transmitted +//| address. This class only manages three of the four SPI lines: `!clock`, +//| `!MOSI`, `!MISO`. It is up to the client to manage the appropriate +//| select line, often abbreviated `!CS` or `!SS`. (This is common because +//| multiple secondaries can share the `!clock`, `!MOSI` and `!MISO` lines +//| and therefore the hardware.) +//| +//| .. raw:: html +//| +//|

+//|

+//| Available on these boards +//|
    +//| {% for board in support_matrix_reverse["busio.SPI"] %} +//|
  • {{ board }} +//| {% endfor %} +//|
+//|
+//|

+//| +//| .. seealso:: This class acts as an SPI main (controller). +//| To act as an SPI secondary (target), use `spitarget.SPITarget`. +//| """ +//| +//| def __init__( +//| self, +//| clock: microcontroller.Pin, +//| MOSI: Optional[microcontroller.Pin] = None, +//| MISO: Optional[microcontroller.Pin] = None, +//| half_duplex: bool = False, +//| ) -> None: +//| """Construct an SPI object on the given pins. +//| +//| .. note:: The SPI peripherals allocated in order of desirability, if possible, +//| such as highest speed and not shared use first. For instance, on the nRF52840, +//| there is a single 32MHz SPI peripheral, and multiple 8MHz peripherals, +//| some of which may also be used for I2C. The 32MHz SPI peripheral is returned +//| first, then the exclusive 8MHz SPI peripheral, and finally the shared 8MHz +//| peripherals. +//| +//| .. seealso:: Using this class directly requires careful lock management. +//| Instead, use :class:`~adafruit_bus_device.SPIDevice` to +//| manage locks. +//| +//| .. seealso:: Using this class to directly read registers requires manual +//| bit unpacking. Instead, use an existing driver or make one with +//| :ref:`Register ` data descriptors. +//| +//| :param ~microcontroller.Pin clock: the pin to use for the clock. +//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin. +//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin. +//| :param bool half_duplex: True when MOSI is used for bidirectional data. False when SPI is full-duplex or simplex. +//| +//| **Limitations:** ``half_duplex`` is available only on STM; other chips do not have the hardware support. +//| """ +//| ... +//| + +// TODO(tannewt): Support LSB SPI. +static mp_obj_t wiznet_pio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + #if CIRCUITPY_WIZNET_PIO_SPI + wiznet_pio_spi_obj_t *self = mp_obj_malloc(wiznet_pio_spi_obj_t, &busio_wiznet_pio_spi_type); + enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_half_duplex, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj, MP_QSTR_mosi); + const mcu_pin_obj_t *miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj, MP_QSTR_miso); + + if (!miso && !mosi) { + mp_raise_ValueError(MP_ERROR_TEXT("Must provide MISO or MOSI pin")); + } + + common_hal_wiznet_pio_spi_construct(self, clock, mosi, miso, args[ARG_half_duplex].u_bool); + return MP_OBJ_FROM_PTR(self); + #else + mp_raise_NotImplementedError(NULL); + #endif // CIRCUITPY_WIZNET_PIO_SPI +} + +#if CIRCUITPY_WIZNET_PIO_SPI +//| def deinit(self) -> None: +//| """Turn off the SPI bus.""" +//| ... +//| +static mp_obj_t wiznet_pio_spi_obj_deinit(mp_obj_t self_in) { + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_wiznet_pio_spi_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_deinit_obj, wiznet_pio_spi_obj_deinit); + +//| def __enter__(self) -> SPI: +//| """No-op used by Context Managers. +//| Provided by context manager helper.""" +//| ... +//| + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +static void check_lock(wiznet_pio_spi_obj_t *self) { + asm (""); + if (!common_hal_wiznet_pio_spi_has_lock(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); + } +} + +static void check_for_deinit(wiznet_pio_spi_obj_t *self) { + if (common_hal_wiznet_pio_spi_deinited(self)) { + raise_deinited_error(); + } +} + +//| def configure( +//| self, *, baudrate: int = 100000, polarity: int = 0, phase: int = 0, bits: int = 8 +//| ) -> None: +//| """Configures the SPI bus. The SPI object must be locked. +//| +//| :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be higher or lower +//| due to the granularity of available clock settings. +//| Check the `frequency` attribute for the actual clock rate. +//| :param int polarity: the base state of the clock line (0 or 1) +//| :param int phase: the edge of the clock that data is captured. First (0) +//| or second (1). Rising or falling depends on clock polarity. +//| :param int bits: the number of bits per word +//| +//| .. note:: On the SAMD21, it is possible to set the baudrate to 24 MHz, but that +//| speed is not guaranteed to work. 12 MHz is the next available lower speed, and is +//| within spec for the SAMD21. +//| +//| .. note:: On the nRF52840, these baudrates are available: 125kHz, 250kHz, 1MHz, 2MHz, 4MHz, +//| and 8MHz. +//| If you pick a a baudrate other than one of these, the nearest lower +//| baudrate will be chosen, with a minimum of 125kHz. +//| Two SPI objects may be created, except on the Circuit Playground Bluefruit, +//| which allows only one (to allow for an additional I2C object).""" +//| ... +//| + +static mp_obj_t wiznet_pio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_baudrate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100000} }, + { MP_QSTR_polarity, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_phase, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_bits, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 8} }, + }; + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t polarity = (uint8_t)mp_arg_validate_int_range(args[ARG_polarity].u_int, 0, 1, MP_QSTR_polarity); + uint8_t phase = (uint8_t)mp_arg_validate_int_range(args[ARG_phase].u_int, 0, 1, MP_QSTR_phase); + uint8_t bits = (uint8_t)mp_arg_validate_int_range(args[ARG_bits].u_int, 8, 9, MP_QSTR_bits); + + if (!common_hal_wiznet_pio_spi_configure(self, args[ARG_baudrate].u_int, + polarity, phase, bits)) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_configure_obj, 1, wiznet_pio_spi_configure); + +//| def try_lock(self) -> bool: +//| """Attempts to grab the SPI lock. Returns True on success. +//| +//| :return: True when lock has been grabbed +//| :rtype: bool""" +//| ... +//| + +static mp_obj_t wiznet_pio_spi_obj_try_lock(mp_obj_t self_in) { + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_wiznet_pio_spi_try_lock(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_try_lock_obj, wiznet_pio_spi_obj_try_lock); + +//| def unlock(self) -> None: +//| """Releases the SPI lock.""" +//| ... +//| + +static mp_obj_t wiznet_pio_spi_obj_unlock(mp_obj_t self_in) { + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_wiznet_pio_spi_unlock(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_unlock_obj, wiznet_pio_spi_obj_unlock); + +//| import sys +//| +//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None: +//| """Write the data contained in ``buffer``. The SPI object must be locked. +//| If the buffer is empty, nothing happens. +//| +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]`` were passed, but without copying the data. +//| The number of bytes written will be the length of ``buffer[start:end]``. +//| +//| :param ReadableBuffer buffer: write out bytes from this buffer +//| :param int start: beginning of buffer slice +//| :param int end: end of buffer slice; if not specified, use ``len(buffer)`` +//| """ +//| ... +//| + +static mp_obj_t wiznet_pio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + // Compute bounds in terms of elements, not bytes. + int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); + int32_t start = args[ARG_start].u_int; + size_t length = bufinfo.len / stride_in_bytes; + normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + + // Treat start and length in terms of bytes from now on. + start *= stride_in_bytes; + length *= stride_in_bytes; + + if (length == 0) { + return mp_const_none; + } + + bool ok = common_hal_wiznet_pio_spi_write(self, ((uint8_t *)bufinfo.buf) + start, length); + + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_write_obj, 1, wiznet_pio_spi_write); + + +//| import sys +//| +//| def readinto( +//| self, +//| buffer: WriteableBuffer, +//| *, +//| start: int = 0, +//| end: int = sys.maxsize, +//| write_value: int = 0, +//| ) -> None: +//| """Read into ``buffer`` while writing ``write_value`` for each byte read. +//| The SPI object must be locked. +//| If the number of bytes to read is 0, nothing happens. +//| +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]`` were passed. +//| The number of bytes read will be the length of ``buffer[start:end]``. +//| +//| :param WriteableBuffer buffer: read bytes into this buffer +//| :param int start: beginning of buffer slice +//| :param int end: end of buffer slice; if not specified, it will be the equivalent value +//| of ``len(buffer)`` and for any value provided it will take the value of +//| ``min(end, len(buffer))`` +//| :param int write_value: value to write while reading +//| """ +//| ... +//| + +static mp_obj_t wiznet_pio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_write_value, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + // Compute bounds in terms of elements, not bytes. + int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); + int32_t start = args[ARG_start].u_int; + size_t length = bufinfo.len / stride_in_bytes; + normalize_buffer_bounds(&start, args[ARG_end].u_int, &length); + + // Treat start and length in terms of bytes from now on. + start *= stride_in_bytes; + length *= stride_in_bytes; + + if (length == 0) { + return mp_const_none; + } + + bool ok = common_hal_wiznet_pio_spi_read(self, ((uint8_t *)bufinfo.buf) + start, length, args[ARG_write_value].u_int); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_readinto_obj, 1, wiznet_pio_spi_readinto); + +//| import sys +//| +//| def write_readinto( +//| self, +//| out_buffer: ReadableBuffer, +//| in_buffer: WriteableBuffer, +//| *, +//| out_start: int = 0, +//| out_end: int = sys.maxsize, +//| in_start: int = 0, +//| in_end: int = sys.maxsize, +//| ) -> None: +//| """Write out the data in ``out_buffer`` while simultaneously reading data into ``in_buffer``. +//| The SPI object must be locked. +//| +//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced +//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data. +//| The number of bytes written will be the length of ``out_buffer[out_start:out_end]``. +//| +//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced +//| as if ``in_buffer[in_start:in_end]`` were passed, +//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``. +//| +//| The lengths of the slices defined by ``out_buffer[out_start:out_end]`` +//| and ``in_buffer[in_start:in_end]`` must be equal. +//| If buffer slice lengths are both 0, nothing happens. +//| +//| :param ReadableBuffer out_buffer: write out bytes from this buffer +//| :param WriteableBuffer in_buffer: read bytes into this buffer +//| :param int out_start: beginning of ``out_buffer`` slice +//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)`` +//| :param int in_start: beginning of ``in_buffer`` slice +//| :param int in_end: end of ``in_buffer slice``; if not specified, use ``len(in_buffer)`` +//| """ +//| ... +//| + +static mp_obj_t wiznet_pio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + check_lock(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t buf_out_info; + mp_get_buffer_raise(args[ARG_out_buffer].u_obj, &buf_out_info, MP_BUFFER_READ); + int out_stride_in_bytes = mp_binary_get_size('@', buf_out_info.typecode, NULL); + int32_t out_start = args[ARG_out_start].u_int; + size_t out_length = buf_out_info.len / out_stride_in_bytes; + normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length); + + mp_buffer_info_t buf_in_info; + mp_get_buffer_raise(args[ARG_in_buffer].u_obj, &buf_in_info, MP_BUFFER_WRITE); + int in_stride_in_bytes = mp_binary_get_size('@', buf_in_info.typecode, NULL); + int32_t in_start = args[ARG_in_start].u_int; + size_t in_length = buf_in_info.len / in_stride_in_bytes; + normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length); + + // Treat start and length in terms of bytes from now on. + out_start *= out_stride_in_bytes; + out_length *= out_stride_in_bytes; + in_start *= in_stride_in_bytes; + in_length *= in_stride_in_bytes; + + if (out_length != in_length) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer slices must be of equal length")); + } + + if (out_length == 0) { + return mp_const_none; + } + + bool ok = common_hal_wiznet_pio_spi_transfer(self, + ((uint8_t *)buf_out_info.buf) + out_start, + ((uint8_t *)buf_in_info.buf) + in_start, + out_length); + if (!ok) { + mp_raise_OSError(MP_EIO); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_write_readinto_obj, 1, wiznet_pio_spi_write_readinto); + +//| frequency: int +//| """The actual SPI bus frequency. This may not match the frequency requested +//| due to internal limitations.""" +//| +//| + +#endif // CIRCUITPY_WIZNET_PIO_SPI + +static const mp_rom_map_elem_t wiznet_pio_spi_locals_dict_table[] = { + #if CIRCUITPY_WIZNET_PIO_SPI + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&wiznet_pio_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + + { MP_ROM_QSTR(MP_QSTR_configure), MP_ROM_PTR(&wiznet_pio_spi_configure_obj) }, + { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&wiznet_pio_spi_try_lock_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&wiznet_pio_spi_unlock_obj) }, + + { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&wiznet_pio_spi_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&wiznet_pio_spi_write_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&wiznet_pio_spi_write_readinto_obj) }, + + #endif // CIRCUITPY_WIZNET_PIO_SPI +}; +static MP_DEFINE_CONST_DICT(wiznet_pio_spi_locals_dict, wiznet_pio_spi_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + busio_wiznet_pio_spi_type, + MP_QSTR_WIZNET_PIO_SPI, + MP_TYPE_FLAG_NONE, + make_new, wiznet_pio_spi_make_new, + locals_dict, &wiznet_pio_spi_locals_dict +); + +wiznet_pio_spi_obj_t *validate_obj_is_wiznet_pio_spi_bus(mp_obj_t obj, qstr arg_name) { + return mp_arg_validate_type(obj, &busio_wiznet_pio_spi_type, arg_name); +} diff --git a/shared-bindings/busio/WIZNET_PIO_SPI.h b/shared-bindings/busio/WIZNET_PIO_SPI.h new file mode 100755 index 00000000000..2196d1e4814 --- /dev/null +++ b/shared-bindings/busio/WIZNET_PIO_SPI.h @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/busio/WIZNET_PIO_SPI.h" + +// Type object used in Python. Should be shared between ports. +extern const mp_obj_type_t busio_wiznet_pio_spi_type; + +// Construct an underlying SPI object. +extern void common_hal_wiznet_pio_spi_construct(wiznet_pio_spi_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso, bool half_duplex); + +extern void common_hal_wiznet_pio_spi_deinit(wiznet_pio_spi_obj_t *self); +extern bool common_hal_wiznet_pio_spi_deinited(wiznet_pio_spi_obj_t *self); + +extern bool common_hal_wiznet_pio_spi_configure(wiznet_pio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits); + +extern bool common_hal_wiznet_pio_spi_try_lock(wiznet_pio_spi_obj_t *self); +extern bool common_hal_wiznet_pio_spi_has_lock(wiznet_pio_spi_obj_t *self); +extern void common_hal_wiznet_pio_spi_unlock(wiznet_pio_spi_obj_t *self); + +// Writes out the given data. +extern bool common_hal_wiznet_pio_spi_write(wiznet_pio_spi_obj_t *self, const uint8_t *data, size_t len); + +// Reads in len bytes while outputting the byte write_value. +extern bool common_hal_wiznet_pio_spi_read(wiznet_pio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value); + +// Reads and write len bytes simultaneously. +extern bool common_hal_wiznet_pio_spi_transfer(wiznet_pio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len); + +extern wiznet_pio_spi_obj_t *validate_obj_is_wiznet_pio_spi_bus(mp_obj_t obj_in, qstr arg_name); diff --git a/shared-bindings/busio/__init__.c b/shared-bindings/busio/__init__.c old mode 100644 new mode 100755 index 028d73d9c36..b4e3dff7447 --- a/shared-bindings/busio/__init__.c +++ b/shared-bindings/busio/__init__.c @@ -15,6 +15,10 @@ #include "shared-bindings/busio/SPI.h" #include "shared-bindings/busio/UART.h" +#if CIRCUITPY_WIZNET_PIO_SPI +#include "shared-bindings/busio/WIZNET_PIO_SPI.h" +#endif + #include "py/runtime.h" //| """Hardware accelerated external bus access @@ -69,6 +73,9 @@ static const mp_rom_map_elem_t busio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&busio_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&busio_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&busio_uart_type) }, +#if CIRCUITPY_WIZNET_PIO_SPI + { MP_ROM_QSTR(MP_QSTR_WIZNET_PIO_SPI), MP_ROM_PTR(&busio_wiznet_pio_spi_type) }, +#endif }; static MP_DEFINE_CONST_DICT(busio_module_globals, busio_module_globals_table); From a5864a1b73678fc18b070176ef2266353cc8a01c Mon Sep 17 00:00:00 2001 From: hannah Date: Tue, 24 Jun 2025 07:07:48 +0000 Subject: [PATCH 020/876] Fix undefined reference to 'busio_wiznet_pio_spi_type' and clean up code --- .../wiznet_w55rp20_evb_pico/mpconfigboard.mk | 2 +- .../common-hal/busio/WIZNET_PIO_SPI.c | 4 +- .../common-hal/busio/WIZNET_PIO_SPI.h | 2 +- .../wiznet_pio_spi/wizchip_pio_spi.c | 2 +- .../wiznet_pio_spi/wizchip_pio_spi.pio | 2 +- py/circuitpy_defns.mk | 6 +- shared-bindings/busio/WIZNET_PIO_SPI.c | 225 ++---------------- shared-bindings/busio/__init__.c | 4 +- 8 files changed, 32 insertions(+), 215 deletions(-) diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk index 6045e5c8986..a6371ece1cf 100755 --- a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk @@ -11,4 +11,4 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_WIZNET_PIO_SPI = 1 CIRCUITPY__EVE = 1 CIRCUITPY_SSL = 1 -CIRCUITPY_USB_HOST = 0 \ No newline at end of file +CIRCUITPY_USB_HOST = 0 diff --git a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c b/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c index a90646e47aa..41f08c4480c 100755 --- a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c +++ b/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c @@ -89,7 +89,7 @@ bool common_hal_wiznet_pio_spi_try_lock(wiznet_pio_spi_obj_t *self) { if (common_hal_wiznet_pio_spi_deinited(self)) { return false; } - + bool grabbed_lock = false; if (!self->has_lock) { grabbed_lock = true; @@ -120,4 +120,4 @@ bool common_hal_wiznet_pio_spi_read(wiznet_pio_spi_obj_t *self, bool common_hal_wiznet_pio_spi_transfer(wiznet_pio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { return wiznet_pio_spi_transfer(data_out, len, data_in, len); -} \ No newline at end of file +} diff --git a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h b/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h index 29d077b4341..6fcfb452cce 100755 --- a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h +++ b/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h @@ -22,4 +22,4 @@ typedef struct { const mcu_pin_obj_t *MISO; } wiznet_pio_spi_obj_t; -void reset_spi(void); \ No newline at end of file +void reset_spi(void); diff --git a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c index 564dd9191b0..ca68a0cc372 100755 --- a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c +++ b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c @@ -351,7 +351,7 @@ void wiznet_pio_spi_write_buffer(const uint8_t *pBuf, uint16_t len) { assert(active_state->spi_header_count == 0); if (!wiznet_pio_spi_transfer(pBuf, len, NULL, 0)) { panic("spi failed writing buffer"); - } + } } } diff --git a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio index 092a2b589a7..97a1c5b73d4 100755 --- a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio +++ b/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio @@ -21,4 +21,4 @@ read_bits: jmp x-- read_bits side 1 in pins, 1 side 0 jmp y-- read_byte side 0 -public read_end: \ No newline at end of file +public read_end: diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index de9703811c7..571e4554192 100755 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -460,7 +460,7 @@ ifeq ($(CIRCUITPY_WIFI),1) SRC_PATTERNS += wifi/% endif ifeq ($(CIRCUITPY_WIZNET_PIO_SPI),1) -SRC_PATTERNS += busio/WIZNET_PIO_SPI.c busio/WIZNET_PIO_SPI.h +SRC_PATTERNS += busio/WIZNET_PIO_SPI.c endif ifeq ($(CIRCUITPY_ZLIB),1) SRC_PATTERNS += zlib/% @@ -849,6 +849,10 @@ SRC_SHARED_MODULE_ALL += \ ssl/SSLSocket.c endif +ifeq ($(CIRCUITPY_WIZNET_PIO_SPI),1) +SRC_COMMON_HAL_ALL += busio/WIZNET_PIO_SPI.c +endif + ifeq ($(CIRCUITPY_KEYPAD_DEMUX),1) SRC_SHARED_MODULE_ALL += \ keypad_demux/__init__.c \ diff --git a/shared-bindings/busio/WIZNET_PIO_SPI.c b/shared-bindings/busio/WIZNET_PIO_SPI.c index 81a74f933d0..68dc53f5d6d 100755 --- a/shared-bindings/busio/WIZNET_PIO_SPI.c +++ b/shared-bindings/busio/WIZNET_PIO_SPI.c @@ -4,8 +4,9 @@ // // SPDX-License-Identifier: MIT +//TODO: busio.WIZNET_PIO_SPI class. // This file contains all of the Python API definitions for the -// busio.SPI class. +// busio.WIZNET_PIO_SPI class. #include @@ -20,73 +21,10 @@ #include "py/objproperty.h" #include "py/runtime.h" -#include - - -//| class SPI: -//| """A 3-4 wire serial protocol -//| -//| SPI is a serial protocol that has exclusive pins for data in and out of the -//| main device. It is typically faster than :py:class:`~bitbangio.I2C` because a -//| separate pin is used to select a device rather than a transmitted -//| address. This class only manages three of the four SPI lines: `!clock`, -//| `!MOSI`, `!MISO`. It is up to the client to manage the appropriate -//| select line, often abbreviated `!CS` or `!SS`. (This is common because -//| multiple secondaries can share the `!clock`, `!MOSI` and `!MISO` lines -//| and therefore the hardware.) -//| -//| .. raw:: html -//| -//|

-//|

-//| Available on these boards -//|
    -//| {% for board in support_matrix_reverse["busio.SPI"] %} -//|
  • {{ board }} -//| {% endfor %} -//|
-//|
-//|

-//| -//| .. seealso:: This class acts as an SPI main (controller). -//| To act as an SPI secondary (target), use `spitarget.SPITarget`. -//| """ -//| -//| def __init__( -//| self, -//| clock: microcontroller.Pin, -//| MOSI: Optional[microcontroller.Pin] = None, -//| MISO: Optional[microcontroller.Pin] = None, -//| half_duplex: bool = False, -//| ) -> None: -//| """Construct an SPI object on the given pins. -//| -//| .. note:: The SPI peripherals allocated in order of desirability, if possible, -//| such as highest speed and not shared use first. For instance, on the nRF52840, -//| there is a single 32MHz SPI peripheral, and multiple 8MHz peripherals, -//| some of which may also be used for I2C. The 32MHz SPI peripheral is returned -//| first, then the exclusive 8MHz SPI peripheral, and finally the shared 8MHz -//| peripherals. -//| -//| .. seealso:: Using this class directly requires careful lock management. -//| Instead, use :class:`~adafruit_bus_device.SPIDevice` to -//| manage locks. -//| -//| .. seealso:: Using this class to directly read registers requires manual -//| bit unpacking. Instead, use an existing driver or make one with -//| :ref:`Register ` data descriptors. -//| -//| :param ~microcontroller.Pin clock: the pin to use for the clock. -//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin. -//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin. -//| :param bool half_duplex: True when MOSI is used for bidirectional data. False when SPI is full-duplex or simplex. -//| -//| **Limitations:** ``half_duplex`` is available only on STM; other chips do not have the hardware support. -//| """ -//| ... -//| - -// TODO(tannewt): Support LSB SPI. + +//TODO: class WIZNET_PIO_SPI + + static mp_obj_t wiznet_pio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_WIZNET_PIO_SPI wiznet_pio_spi_obj_t *self = mp_obj_malloc(wiznet_pio_spi_obj_t, &busio_wiznet_pio_spi_type); @@ -116,10 +54,9 @@ static mp_obj_t wiznet_pio_spi_make_new(const mp_obj_type_t *type, size_t n_args } #if CIRCUITPY_WIZNET_PIO_SPI -//| def deinit(self) -> None: -//| """Turn off the SPI bus.""" -//| ... -//| + +// TODO: def deinit + static mp_obj_t wiznet_pio_spi_obj_deinit(mp_obj_t self_in) { wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_wiznet_pio_spi_deinit(self); @@ -127,18 +64,9 @@ static mp_obj_t wiznet_pio_spi_obj_deinit(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_deinit_obj, wiznet_pio_spi_obj_deinit); -//| def __enter__(self) -> SPI: -//| """No-op used by Context Managers. -//| Provided by context manager helper.""" -//| ... -//| +// TODO: def __enter__ -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -// Provided by context manager helper. +// TODO: def __exit__ static void check_lock(wiznet_pio_spi_obj_t *self) { asm (""); @@ -153,31 +81,7 @@ static void check_for_deinit(wiznet_pio_spi_obj_t *self) { } } -//| def configure( -//| self, *, baudrate: int = 100000, polarity: int = 0, phase: int = 0, bits: int = 8 -//| ) -> None: -//| """Configures the SPI bus. The SPI object must be locked. -//| -//| :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be higher or lower -//| due to the granularity of available clock settings. -//| Check the `frequency` attribute for the actual clock rate. -//| :param int polarity: the base state of the clock line (0 or 1) -//| :param int phase: the edge of the clock that data is captured. First (0) -//| or second (1). Rising or falling depends on clock polarity. -//| :param int bits: the number of bits per word -//| -//| .. note:: On the SAMD21, it is possible to set the baudrate to 24 MHz, but that -//| speed is not guaranteed to work. 12 MHz is the next available lower speed, and is -//| within spec for the SAMD21. -//| -//| .. note:: On the nRF52840, these baudrates are available: 125kHz, 250kHz, 1MHz, 2MHz, 4MHz, -//| and 8MHz. -//| If you pick a a baudrate other than one of these, the nearest lower -//| baudrate will be chosen, with a minimum of 125kHz. -//| Two SPI objects may be created, except on the Circuit Playground Bluefruit, -//| which allows only one (to allow for an additional I2C object).""" -//| ... -//| +// TODO: def configure static mp_obj_t wiznet_pio_spi_configure(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_baudrate, ARG_polarity, ARG_phase, ARG_bits }; @@ -205,13 +109,7 @@ static mp_obj_t wiznet_pio_spi_configure(size_t n_args, const mp_obj_t *pos_args } MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_configure_obj, 1, wiznet_pio_spi_configure); -//| def try_lock(self) -> bool: -//| """Attempts to grab the SPI lock. Returns True on success. -//| -//| :return: True when lock has been grabbed -//| :rtype: bool""" -//| ... -//| +// TODO: def try_lock static mp_obj_t wiznet_pio_spi_obj_try_lock(mp_obj_t self_in) { wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -219,10 +117,7 @@ static mp_obj_t wiznet_pio_spi_obj_try_lock(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_try_lock_obj, wiznet_pio_spi_obj_try_lock); -//| def unlock(self) -> None: -//| """Releases the SPI lock.""" -//| ... -//| +// TODO: def unlock static mp_obj_t wiznet_pio_spi_obj_unlock(mp_obj_t self_in) { wiznet_pio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in); @@ -232,22 +127,7 @@ static mp_obj_t wiznet_pio_spi_obj_unlock(mp_obj_t self_in) { } MP_DEFINE_CONST_FUN_OBJ_1(wiznet_pio_spi_unlock_obj, wiznet_pio_spi_obj_unlock); -//| import sys -//| -//| def write(self, buffer: ReadableBuffer, *, start: int = 0, end: int = sys.maxsize) -> None: -//| """Write the data contained in ``buffer``. The SPI object must be locked. -//| If the buffer is empty, nothing happens. -//| -//| If ``start`` or ``end`` is provided, then the buffer will be sliced -//| as if ``buffer[start:end]`` were passed, but without copying the data. -//| The number of bytes written will be the length of ``buffer[start:end]``. -//| -//| :param ReadableBuffer buffer: write out bytes from this buffer -//| :param int start: beginning of buffer slice -//| :param int end: end of buffer slice; if not specified, use ``len(buffer)`` -//| """ -//| ... -//| +// TODO: def write static mp_obj_t wiznet_pio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end }; @@ -280,7 +160,7 @@ static mp_obj_t wiznet_pio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp } bool ok = common_hal_wiznet_pio_spi_write(self, ((uint8_t *)bufinfo.buf) + start, length); - + if (!ok) { mp_raise_OSError(MP_EIO); } @@ -288,34 +168,7 @@ static mp_obj_t wiznet_pio_spi_write(size_t n_args, const mp_obj_t *pos_args, mp } MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_write_obj, 1, wiznet_pio_spi_write); - -//| import sys -//| -//| def readinto( -//| self, -//| buffer: WriteableBuffer, -//| *, -//| start: int = 0, -//| end: int = sys.maxsize, -//| write_value: int = 0, -//| ) -> None: -//| """Read into ``buffer`` while writing ``write_value`` for each byte read. -//| The SPI object must be locked. -//| If the number of bytes to read is 0, nothing happens. -//| -//| If ``start`` or ``end`` is provided, then the buffer will be sliced -//| as if ``buffer[start:end]`` were passed. -//| The number of bytes read will be the length of ``buffer[start:end]``. -//| -//| :param WriteableBuffer buffer: read bytes into this buffer -//| :param int start: beginning of buffer slice -//| :param int end: end of buffer slice; if not specified, it will be the equivalent value -//| of ``len(buffer)`` and for any value provided it will take the value of -//| ``min(end, len(buffer))`` -//| :param int write_value: value to write while reading -//| """ -//| ... -//| +// TODO: def readinto static mp_obj_t wiznet_pio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_buffer, ARG_start, ARG_end, ARG_write_value }; @@ -355,42 +208,8 @@ static mp_obj_t wiznet_pio_spi_readinto(size_t n_args, const mp_obj_t *pos_args, } MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_readinto_obj, 1, wiznet_pio_spi_readinto); -//| import sys -//| -//| def write_readinto( -//| self, -//| out_buffer: ReadableBuffer, -//| in_buffer: WriteableBuffer, -//| *, -//| out_start: int = 0, -//| out_end: int = sys.maxsize, -//| in_start: int = 0, -//| in_end: int = sys.maxsize, -//| ) -> None: -//| """Write out the data in ``out_buffer`` while simultaneously reading data into ``in_buffer``. -//| The SPI object must be locked. -//| -//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced -//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data. -//| The number of bytes written will be the length of ``out_buffer[out_start:out_end]``. -//| -//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced -//| as if ``in_buffer[in_start:in_end]`` were passed, -//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``. -//| -//| The lengths of the slices defined by ``out_buffer[out_start:out_end]`` -//| and ``in_buffer[in_start:in_end]`` must be equal. -//| If buffer slice lengths are both 0, nothing happens. -//| -//| :param ReadableBuffer out_buffer: write out bytes from this buffer -//| :param WriteableBuffer in_buffer: read bytes into this buffer -//| :param int out_start: beginning of ``out_buffer`` slice -//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)`` -//| :param int in_start: beginning of ``in_buffer`` slice -//| :param int in_end: end of ``in_buffer slice``; if not specified, use ``len(in_buffer)`` -//| """ -//| ... -//| + +// TODO: def write_readinto static mp_obj_t wiznet_pio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; @@ -447,12 +266,6 @@ static mp_obj_t wiznet_pio_spi_write_readinto(size_t n_args, const mp_obj_t *pos } MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_write_readinto_obj, 1, wiznet_pio_spi_write_readinto); -//| frequency: int -//| """The actual SPI bus frequency. This may not match the frequency requested -//| due to internal limitations.""" -//| -//| - #endif // CIRCUITPY_WIZNET_PIO_SPI static const mp_rom_map_elem_t wiznet_pio_spi_locals_dict_table[] = { diff --git a/shared-bindings/busio/__init__.c b/shared-bindings/busio/__init__.c index b4e3dff7447..46386faef0a 100755 --- a/shared-bindings/busio/__init__.c +++ b/shared-bindings/busio/__init__.c @@ -73,9 +73,9 @@ static const mp_rom_map_elem_t busio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&busio_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&busio_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&busio_uart_type) }, -#if CIRCUITPY_WIZNET_PIO_SPI + #if CIRCUITPY_WIZNET_PIO_SPI { MP_ROM_QSTR(MP_QSTR_WIZNET_PIO_SPI), MP_ROM_PTR(&busio_wiznet_pio_spi_type) }, -#endif + #endif }; static MP_DEFINE_CONST_DICT(busio_module_globals, busio_module_globals_table); From 05fae5d00f9c3fb949007d20d4ca3a88cc006530 Mon Sep 17 00:00:00 2001 From: Amaar Ebrahim Date: Fri, 11 Jul 2025 18:30:45 -0500 Subject: [PATCH 021/876] raspberrypi/I2CTarget: Fixed bug where I2C starts were seen as restarts. The Rasperry Pi Pico, based on the RP2040, has a register that maintains the status of I2C interrupt flags called IC_INTR_STAT. The bits of this register are set by hardware and cleared by software. Before this commit, the I2CTarget library did not clear the restart bit (R_RESTART_DET) in this register after an I2C transaction ended, causing the is_restart field of the i2ctarget_i2c_target_request_obj_t struct to always be true after the first I2C transaction. This commit causes the restart and stop bits to get cleared when the I2C transaction ends. Signed-off-by: Amaar Ebrahim --- .../raspberrypi/common-hal/i2ctarget/I2CTarget.c | 15 +++++++++++++++ .../raspberrypi/common-hal/i2ctarget/I2CTarget.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c index d1c92eea998..655dfd867ca 100644 --- a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +++ b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c @@ -85,6 +85,8 @@ void common_hal_i2ctarget_i2c_target_deinit(i2ctarget_i2c_target_obj_t *self) { } int common_hal_i2ctarget_i2c_target_is_addressed(i2ctarget_i2c_target_obj_t *self, uint8_t *address, bool *is_read, bool *is_restart) { + common_hal_i2ctarget_i2c_target_is_stop(self); + if (!((self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) || (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_RD_REQ_BITS))) { return 0; } @@ -123,6 +125,19 @@ int common_hal_i2ctarget_i2c_target_write_byte(i2ctarget_i2c_target_obj_t *self, } } +int common_hal_i2ctarget_i2c_target_is_stop(i2ctarget_i2c_target_obj_t *self) { + // Interrupt bits must be cleared by software. Clear the STOP and + // RESTART interrupt bits after an I2C transaction finishes. + if (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { + self->peripheral->hw->clr_stop_det; + self->peripheral->hw->clr_restart_det; + return 1; + } else { + return 0; + } + +} + void common_hal_i2ctarget_i2c_target_ack(i2ctarget_i2c_target_obj_t *self, bool ack) { return; } diff --git a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.h b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.h index 5d4e0690cbf..67b09c18c2f 100644 --- a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.h +++ b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.h @@ -21,3 +21,5 @@ typedef struct { uint8_t scl_pin; uint8_t sda_pin; } i2ctarget_i2c_target_obj_t; + +int common_hal_i2ctarget_i2c_target_is_stop(i2ctarget_i2c_target_obj_t *self); From 7aa13ed1b71f6ae861ee0d087199e820192d16fb Mon Sep 17 00:00:00 2001 From: hannah Date: Mon, 14 Jul 2025 04:59:15 +0000 Subject: [PATCH 022/876] Restructure: Move Wiznet PIO SPI code to new wiznet module --- data/nvm.toml | 2 +- ports/raspberrypi/Makefile | 27 +++++++++-------- .../raspberrypi/bindings/wiznet/PIO_SPI.c | 22 +++++++------- .../raspberrypi/bindings/wiznet/PIO_SPI.h | 4 +-- ports/raspberrypi/bindings/wiznet/__init__.c | 29 +++++++++++++++++++ ports/raspberrypi/bindings/wiznet/__init__.h | 7 +++++ .../wiznet_w55rp20_evb_pico/mpconfigboard.mk | 4 +-- .../WIZNET_PIO_SPI.c => wiznet/PIO_SPI.c} | 4 +-- .../WIZNET_PIO_SPI.h => wiznet/PIO_SPI.h} | 0 .../raspberrypi/common-hal/wiznet/__init__.c | 7 +++++ .../wiznet}/wizchip_pio_spi.c | 2 +- .../wiznet}/wizchip_pio_spi.h | 0 .../wiznet}/wizchip_pio_spi.pio | 0 py/circuitpy_defns.mk | 8 ++--- py/circuitpy_mpconfig.mk | 6 ++-- shared-bindings/busio/__init__.c | 7 ----- 16 files changed, 82 insertions(+), 47 deletions(-) rename shared-bindings/busio/WIZNET_PIO_SPI.c => ports/raspberrypi/bindings/wiznet/PIO_SPI.c (96%) rename shared-bindings/busio/WIZNET_PIO_SPI.h => ports/raspberrypi/bindings/wiznet/PIO_SPI.h (94%) create mode 100755 ports/raspberrypi/bindings/wiznet/__init__.c create mode 100755 ports/raspberrypi/bindings/wiznet/__init__.h rename ports/raspberrypi/common-hal/{busio/WIZNET_PIO_SPI.c => wiznet/PIO_SPI.c} (97%) rename ports/raspberrypi/common-hal/{busio/WIZNET_PIO_SPI.h => wiznet/PIO_SPI.h} (100%) create mode 100755 ports/raspberrypi/common-hal/wiznet/__init__.c rename ports/raspberrypi/{wiznet_pio_spi => common-hal/wiznet}/wizchip_pio_spi.c (99%) rename ports/raspberrypi/{wiznet_pio_spi => common-hal/wiznet}/wizchip_pio_spi.h (100%) rename ports/raspberrypi/{wiznet_pio_spi => common-hal/wiznet}/wizchip_pio_spi.pio (100%) diff --git a/data/nvm.toml b/data/nvm.toml index 8bca037b052..3f3921f351a 160000 --- a/data/nvm.toml +++ b/data/nvm.toml @@ -1 +1 @@ -Subproject commit 8bca037b052a4a4dc46a56a25a1b802652ee3f47 +Subproject commit 3f3921f351ab206e729ad965c857b80a7ece8198 diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index e1f17adb402..91de903e22e 100755 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -83,13 +83,13 @@ SRC_CYW43 := SRC_LWIP := endif -ifeq ($(CIRCUITPY_WIZNET_PIO_SPI), 1) -INC_WIZNET_PIO_SPI := \ - -isystem wiznet_pio_spi \ - -SRC_WIZNET_PIO_SPI := \ - wiznet_pio_spi/wizchip_pio_spi.c \ +ifeq ($(CIRCUITPY_WIZNET), 1) +INC_WIZNET := \ + -isystem common-hal/wiznet \ +SRC_WIZNET := \ + common-hal/wiznet/wizchip_pio_spi.c \ + WIZNET_PIOASM = $(BUILD)/pioasm/pioasm/pioasm .PHONY: pioasmBuild pioasmBuild: $(WIZNET_PIOASM) @@ -98,15 +98,15 @@ $(WIZNET_PIOASM): $(Q)cmake -S pioasm -B $(BUILD)/pioasm $(MAKE) -C $(BUILD)/pioasm pioasmBuild -$(BUILD)/wizchip_pio_spi.pio.h: wiznet_pio_spi/wizchip_pio_spi.pio $(WIZNET_PIOASM) +$(BUILD)/wizchip_pio_spi.pio.h: common-hal/wiznet/wizchip_pio_spi.pio $(WIZNET_PIOASM) $(Q)$(WIZNET_PIOASM) -o c-sdk $< $@ -$(BUILD)/wiznet_pio_spi/wizchip_pio_spi.o: $(BUILD)/wizchip_pio_spi.pio.h +$(BUILD)/common-hal/wiznet/wizchip_pio_spi.o: $(BUILD)/wizchip_pio_spi.pio.h $(BUILD)/genhdr/qstr.i.last: $(BUILD)/wizchip_pio_spi.pio.h else -INC_WIZNET_PIO_SPI := -SRC_WIZNET_PIO_SPI := +INC_WIZNET := +SRC_WIZNET := endif @@ -182,7 +182,6 @@ INC += \ -isystem sdk/src/rp2_common/pico_time_adapter/include/ \ -isystem sdk/src/rp2_common/pico_unique_id/include/ \ $(INC_CYW43) \ - $(INC_WIZNET_PIO_SPI) \ -Isdk_config \ -I../../lib/tinyusb/src \ -I../../supervisor/shared/usb \ @@ -560,6 +559,10 @@ SRC_C += \ bindings/rp2pio/__init__.c \ common-hal/rp2pio/StateMachine.c \ common-hal/rp2pio/__init__.c \ + bindings/wiznet/PIO_SPI.c \ + bindings/wiznet/__init__.c \ + common-hal/wiznet/PIO_SPI.c \ + common-hal/wiznet/__init__.c \ audio_dma.c \ background.c \ peripherals/pins.c \ @@ -569,7 +572,7 @@ SRC_C += \ mphalport.c \ $(SRC_CYW43) \ $(SRC_LWIP) \ - $(SRC_WIZNET_PIO_SPI) \ + $(SRC_WIZNET) \ ifeq ($(CIRCUITPY_USB_HOST), 1) diff --git a/shared-bindings/busio/WIZNET_PIO_SPI.c b/ports/raspberrypi/bindings/wiznet/PIO_SPI.c similarity index 96% rename from shared-bindings/busio/WIZNET_PIO_SPI.c rename to ports/raspberrypi/bindings/wiznet/PIO_SPI.c index 68dc53f5d6d..f628ca868b8 100755 --- a/shared-bindings/busio/WIZNET_PIO_SPI.c +++ b/ports/raspberrypi/bindings/wiznet/PIO_SPI.c @@ -11,7 +11,7 @@ #include #include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/busio/WIZNET_PIO_SPI.h" +#include "bindings/wiznet/PIO_SPI.h" #include "shared-bindings/util.h" #include "shared/runtime/buffer_helper.h" @@ -26,8 +26,8 @@ static mp_obj_t wiznet_pio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - #if CIRCUITPY_WIZNET_PIO_SPI - wiznet_pio_spi_obj_t *self = mp_obj_malloc(wiznet_pio_spi_obj_t, &busio_wiznet_pio_spi_type); + #if CIRCUITPY_WIZNET + wiznet_pio_spi_obj_t *self = mp_obj_malloc(wiznet_pio_spi_obj_t, &wiznet_pio_spi_type); enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -50,10 +50,10 @@ static mp_obj_t wiznet_pio_spi_make_new(const mp_obj_type_t *type, size_t n_args return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError(NULL); - #endif // CIRCUITPY_WIZNET_PIO_SPI + #endif // CIRCUITPY_WIZNET } -#if CIRCUITPY_WIZNET_PIO_SPI +#if CIRCUITPY_WIZNET // TODO: def deinit @@ -266,10 +266,10 @@ static mp_obj_t wiznet_pio_spi_write_readinto(size_t n_args, const mp_obj_t *pos } MP_DEFINE_CONST_FUN_OBJ_KW(wiznet_pio_spi_write_readinto_obj, 1, wiznet_pio_spi_write_readinto); -#endif // CIRCUITPY_WIZNET_PIO_SPI +#endif // CIRCUITPY_WIZNET static const mp_rom_map_elem_t wiznet_pio_spi_locals_dict_table[] = { - #if CIRCUITPY_WIZNET_PIO_SPI + #if CIRCUITPY_WIZNET { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&wiznet_pio_spi_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, @@ -282,18 +282,18 @@ static const mp_rom_map_elem_t wiznet_pio_spi_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&wiznet_pio_spi_write_obj) }, { MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&wiznet_pio_spi_write_readinto_obj) }, - #endif // CIRCUITPY_WIZNET_PIO_SPI + #endif // CIRCUITPY_WIZNET }; static MP_DEFINE_CONST_DICT(wiznet_pio_spi_locals_dict, wiznet_pio_spi_locals_dict_table); MP_DEFINE_CONST_OBJ_TYPE( - busio_wiznet_pio_spi_type, - MP_QSTR_WIZNET_PIO_SPI, + wiznet_pio_spi_type, + MP_QSTR_PIO_SPI, MP_TYPE_FLAG_NONE, make_new, wiznet_pio_spi_make_new, locals_dict, &wiznet_pio_spi_locals_dict ); wiznet_pio_spi_obj_t *validate_obj_is_wiznet_pio_spi_bus(mp_obj_t obj, qstr arg_name) { - return mp_arg_validate_type(obj, &busio_wiznet_pio_spi_type, arg_name); + return mp_arg_validate_type(obj, &wiznet_pio_spi_type, arg_name); } diff --git a/shared-bindings/busio/WIZNET_PIO_SPI.h b/ports/raspberrypi/bindings/wiznet/PIO_SPI.h similarity index 94% rename from shared-bindings/busio/WIZNET_PIO_SPI.h rename to ports/raspberrypi/bindings/wiznet/PIO_SPI.h index 2196d1e4814..0289ac0767a 100755 --- a/shared-bindings/busio/WIZNET_PIO_SPI.h +++ b/ports/raspberrypi/bindings/wiznet/PIO_SPI.h @@ -9,10 +9,10 @@ #include "py/obj.h" #include "common-hal/microcontroller/Pin.h" -#include "common-hal/busio/WIZNET_PIO_SPI.h" +#include "common-hal/wiznet/PIO_SPI.h" // Type object used in Python. Should be shared between ports. -extern const mp_obj_type_t busio_wiznet_pio_spi_type; +extern const mp_obj_type_t wiznet_pio_spi_type; // Construct an underlying SPI object. extern void common_hal_wiznet_pio_spi_construct(wiznet_pio_spi_obj_t *self, diff --git a/ports/raspberrypi/bindings/wiznet/__init__.c b/ports/raspberrypi/bindings/wiznet/__init__.c new file mode 100755 index 00000000000..6ed3c2886cc --- /dev/null +++ b/ports/raspberrypi/bindings/wiznet/__init__.c @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "bindings/wiznet/PIO_SPI.h" + +#include "py/runtime.h" + +static const mp_rom_map_elem_t wiznet_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_wiznet) }, + { MP_ROM_QSTR(MP_QSTR_PIO_SPI), MP_ROM_PTR(&wiznet_pio_spi_type) }, +}; + +static MP_DEFINE_CONST_DICT(wiznet_module_globals, wiznet_module_globals_table); + +const mp_obj_module_t wiznet_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&wiznet_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_wiznet, wiznet_module); diff --git a/ports/raspberrypi/bindings/wiznet/__init__.h b/ports/raspberrypi/bindings/wiznet/__init__.h new file mode 100755 index 00000000000..370e233985f --- /dev/null +++ b/ports/raspberrypi/bindings/wiznet/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk index a6371ece1cf..5030ee88f52 100755 --- a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk @@ -6,9 +6,9 @@ USB_MANUFACTURER = "WIZnet" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" +EXTERNAL_FLASH_DEVICES = "PY25Q16HB" -CIRCUITPY_WIZNET_PIO_SPI = 1 +CIRCUITPY_WIZNET = 1 CIRCUITPY__EVE = 1 CIRCUITPY_SSL = 1 CIRCUITPY_USB_HOST = 0 diff --git a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c b/ports/raspberrypi/common-hal/wiznet/PIO_SPI.c similarity index 97% rename from ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c rename to ports/raspberrypi/common-hal/wiznet/PIO_SPI.c index 41f08c4480c..30fe8c5d25c 100755 --- a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.c +++ b/ports/raspberrypi/common-hal/wiznet/PIO_SPI.c @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT -#include "shared-bindings/busio/WIZNET_PIO_SPI.h" +#include "bindings/wiznet/PIO_SPI.h" #include "shared/runtime/interrupt_char.h" #include "py/mperrno.h" @@ -19,7 +19,7 @@ #include "hardware/pio.h" #include "hardware/clocks.h" -#include "wiznet_pio_spi/wizchip_pio_spi.h" +#include "wizchip_pio_spi.h" #define NO_INSTANCE 0xff diff --git a/ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h b/ports/raspberrypi/common-hal/wiznet/PIO_SPI.h similarity index 100% rename from ports/raspberrypi/common-hal/busio/WIZNET_PIO_SPI.h rename to ports/raspberrypi/common-hal/wiznet/PIO_SPI.h diff --git a/ports/raspberrypi/common-hal/wiznet/__init__.c b/ports/raspberrypi/common-hal/wiznet/__init__.c new file mode 100755 index 00000000000..b3d5d23882d --- /dev/null +++ b/ports/raspberrypi/common-hal/wiznet/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// No wiznet module functions. diff --git a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.c similarity index 99% rename from ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c rename to ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.c index ca68a0cc372..eb041527209 100755 --- a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.c +++ b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.c @@ -61,7 +61,7 @@ static void wiznet_pio_spi_gpio_setup(wiznet_pio_spi_state_t *state) { gpio_init(state->spi_config->data_out_pin); gpio_set_dir(state->spi_config->data_out_pin, GPIO_OUT); gpio_put(state->spi_config->data_out_pin, false); - + gpio_init(state->spi_config->data_in_pin); gpio_set_dir(state->spi_config->data_in_pin, GPIO_IN); diff --git a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.h b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.h similarity index 100% rename from ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.h rename to ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.h diff --git a/ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio b/ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.pio similarity index 100% rename from ports/raspberrypi/wiznet_pio_spi/wizchip_pio_spi.pio rename to ports/raspberrypi/common-hal/wiznet/wizchip_pio_spi.pio diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 571e4554192..0a34e3596d3 100755 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -459,8 +459,8 @@ endif ifeq ($(CIRCUITPY_WIFI),1) SRC_PATTERNS += wifi/% endif -ifeq ($(CIRCUITPY_WIZNET_PIO_SPI),1) -SRC_PATTERNS += busio/WIZNET_PIO_SPI.c +ifeq ($(CIRCUITPY_WIZNET),1) +SRC_PATTERNS += wiznet/% endif ifeq ($(CIRCUITPY_ZLIB),1) SRC_PATTERNS += zlib/% @@ -849,10 +849,6 @@ SRC_SHARED_MODULE_ALL += \ ssl/SSLSocket.c endif -ifeq ($(CIRCUITPY_WIZNET_PIO_SPI),1) -SRC_COMMON_HAL_ALL += busio/WIZNET_PIO_SPI.c -endif - ifeq ($(CIRCUITPY_KEYPAD_DEMUX),1) SRC_SHARED_MODULE_ALL += \ keypad_demux/__init__.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 9fa788d6fb3..eee6c93444f 100755 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -206,9 +206,6 @@ CFLAGS += -DCIRCUITPY_BUSIO_SPI=$(CIRCUITPY_BUSIO_SPI) CIRCUITPY_BUSIO_UART ?= $(CIRCUITPY_BUSIO) CFLAGS += -DCIRCUITPY_BUSIO_UART=$(CIRCUITPY_BUSIO_UART) -CIRCUITPY_WIZNET_PIO_SPI ?= 0 -CFLAGS += -DCIRCUITPY_WIZNET_PIO_SPI=$(CIRCUITPY_WIZNET_PIO_SPI) - CIRCUITPY_CAMERA ?= 0 CFLAGS += -DCIRCUITPY_CAMERA=$(CIRCUITPY_CAMERA) @@ -707,6 +704,9 @@ CFLAGS += -DCIRCUITPY_WATCHDOG=$(CIRCUITPY_WATCHDOG) CIRCUITPY_WIFI ?= 0 CFLAGS += -DCIRCUITPY_WIFI=$(CIRCUITPY_WIFI) +CIRCUITPY_WIZNET ?= 0 +CFLAGS += -DCIRCUITPY_WIZNET=$(CIRCUITPY_WIZNET) + CIRCUITPY_WEB_WORKFLOW ?= $(CIRCUITPY_WIFI) CFLAGS += -DCIRCUITPY_WEB_WORKFLOW=$(CIRCUITPY_WEB_WORKFLOW) diff --git a/shared-bindings/busio/__init__.c b/shared-bindings/busio/__init__.c index 46386faef0a..028d73d9c36 100755 --- a/shared-bindings/busio/__init__.c +++ b/shared-bindings/busio/__init__.c @@ -15,10 +15,6 @@ #include "shared-bindings/busio/SPI.h" #include "shared-bindings/busio/UART.h" -#if CIRCUITPY_WIZNET_PIO_SPI -#include "shared-bindings/busio/WIZNET_PIO_SPI.h" -#endif - #include "py/runtime.h" //| """Hardware accelerated external bus access @@ -73,9 +69,6 @@ static const mp_rom_map_elem_t busio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&busio_i2c_type) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&busio_spi_type) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&busio_uart_type) }, - #if CIRCUITPY_WIZNET_PIO_SPI - { MP_ROM_QSTR(MP_QSTR_WIZNET_PIO_SPI), MP_ROM_PTR(&busio_wiznet_pio_spi_type) }, - #endif }; static MP_DEFINE_CONST_DICT(busio_module_globals, busio_module_globals_table); From a3868636e8831796cd6185121d6cf2a964a06028 Mon Sep 17 00:00:00 2001 From: hannah Date: Tue, 15 Jul 2025 04:12:31 +0000 Subject: [PATCH 023/876] fix: lower compiler optimization to -O2 for wiznet_w55rp20_evb_pico --- ports/raspberrypi/Makefile | 2 +- ports/raspberrypi/bindings/wiznet/PIO_SPI.c | 8 ++++---- .../boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 91de903e22e..6281e7863f1 100755 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -89,7 +89,7 @@ INC_WIZNET := \ SRC_WIZNET := \ common-hal/wiznet/wizchip_pio_spi.c \ - + WIZNET_PIOASM = $(BUILD)/pioasm/pioasm/pioasm .PHONY: pioasmBuild pioasmBuild: $(WIZNET_PIOASM) diff --git a/ports/raspberrypi/bindings/wiznet/PIO_SPI.c b/ports/raspberrypi/bindings/wiznet/PIO_SPI.c index f628ca868b8..1f860fc9979 100755 --- a/ports/raspberrypi/bindings/wiznet/PIO_SPI.c +++ b/ports/raspberrypi/bindings/wiznet/PIO_SPI.c @@ -4,9 +4,9 @@ // // SPDX-License-Identifier: MIT -//TODO: busio.WIZNET_PIO_SPI class. +// TODO: wiznet.PIO_SPI class. // This file contains all of the Python API definitions for the -// busio.WIZNET_PIO_SPI class. +// wiznet.PIO_SPI class. #include @@ -22,7 +22,7 @@ #include "py/runtime.h" -//TODO: class WIZNET_PIO_SPI +// TODO: class WIZNET_PIO_SPI static mp_obj_t wiznet_pio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -292,7 +292,7 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_TYPE_FLAG_NONE, make_new, wiznet_pio_spi_make_new, locals_dict, &wiznet_pio_spi_locals_dict -); + ); wiznet_pio_spi_obj_t *validate_obj_is_wiznet_pio_spi_bus(mp_obj_t obj, qstr arg_name) { return mp_arg_validate_type(obj, &wiznet_pio_spi_type, arg_name); diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk index 5030ee88f52..d43195c0f2a 100755 --- a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/mpconfigboard.mk @@ -12,3 +12,5 @@ CIRCUITPY_WIZNET = 1 CIRCUITPY__EVE = 1 CIRCUITPY_SSL = 1 CIRCUITPY_USB_HOST = 0 + +OPTIMIZATION_FLAGS = -O2 From 16d3353987dc2c49863d873074394f12d8a0444f Mon Sep 17 00:00:00 2001 From: hannah Date: Tue, 15 Jul 2025 05:06:39 +0000 Subject: [PATCH 024/876] Modified pin definitions for wiznet_w55rp20_evb_pico and fix pre-commit error --- ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c | 9 ++++----- shared-bindings/busio/__init__.c | 0 2 files changed, 4 insertions(+), 5 deletions(-) mode change 100755 => 100644 shared-bindings/busio/__init__.c diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c index c0db99042c0..399cc2d9b7b 100755 --- a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c @@ -26,6 +26,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO19) }, { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, @@ -47,21 +50,17 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_W5K_RST), MP_ROM_PTR(&pin_GPIO25) }, { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, - { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO26) }, { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, - { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, - { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO27) }, { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, - { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, - { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, diff --git a/shared-bindings/busio/__init__.c b/shared-bindings/busio/__init__.c old mode 100755 new mode 100644 From 8a0e31620db12fb02302643191e6b6fa2ea0fea1 Mon Sep 17 00:00:00 2001 From: hannah Date: Tue, 15 Jul 2025 05:21:44 +0000 Subject: [PATCH 025/876] Modified pin definitions --- ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c index 399cc2d9b7b..37ecfd3dfb1 100755 --- a/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c +++ b/ports/raspberrypi/boards/wiznet_w55rp20_evb_pico/pins.c @@ -60,7 +60,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, - { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, From 06f7192cba388a3da683387a959c8bc1a73f2e82 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 9 Sep 2025 21:24:03 -0400 Subject: [PATCH 026/876] Rev 3 board changes; lots of flash so turn on most features --- .../mpconfigboard.h | 4 ++-- .../mpconfigboard.mk | 19 ------------------- .../pins.c | 16 ++++++++-------- 3 files changed, 10 insertions(+), 29 deletions(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h index 31559f318ad..6e67197e757 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h @@ -5,8 +5,8 @@ #define MICROPY_HW_MCU_NAME "same51j20" #define CIRCUITPY_MCU_FAMILY samd51 -#define MICROPY_HW_LED_STATUS (&pin_PB23) -#define MICROPY_HW_NEOPIXEL (&pin_PB22) +#define MICROPY_HW_LED_STATUS (&pin_PB23) +#define MICROPY_HW_NEOPIXEL (&pin_PB22) #define BOARD_HAS_CRYSTAL 1 diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk index 408c4eca9fd..34c9d7bcaab 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk @@ -9,24 +9,5 @@ CHIP_FAMILY = same51 QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "SST26VF016B,SST26VF032B,SST26VF064B" LONGINT_IMPL = MPZ -CIRCUITPY_ULAB = 0 CIRCUITPY__EVE = 1 -CIRCUITPY_BITMAPFILTER = 0 -CIRCUITPY_CANIO = 1 -CIRCUITPY_FLOPPYIO = 0 -CIRCUITPY_SYNTHIO = 0 -CIRCUITPY_GIFIO = 0 -CIRCUITPY_JPEGIO = 0 - -CIRCUITPY_LTO_PARTITION = one - -# We don't have room for the fonts for terminalio for certain languages, -# so turn off terminalio, and if it's off and displayio is on, -# force a clean build. -# Note that we cannot test $(CIRCUITPY_DISPLAYIO) directly with an -# ifeq, because it's not set yet. -ifneq (,$(filter $(TRANSLATION),ja ko ru)) -CIRCUITPY_TERMINALIO = 0 -RELEASE_NEEDS_CLEAN_BUILD = $(CIRCUITPY_DISPLAYIO) -endif diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c index b4184e3cecd..f3069930c6b 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c @@ -22,13 +22,11 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_PB14) }, { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_PB15) }, { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_PB16) }, - { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, - { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB22) }, - { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_PB23) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_PB23) }, - { MP_ROM_QSTR(MP_QSTR_NEOPIX), MP_ROM_PTR(&pin_PB22) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_PB22) }, { MP_ROM_QSTR(MP_QSTR_VREF), MP_ROM_PTR(&pin_PA03) }, @@ -60,23 +58,25 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_PA19) }, { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PB00) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_0), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB00) }, { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_PB01) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_1), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PB01) }, { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB02) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_2), MP_ROM_PTR(&pin_PB02) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PB02) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_PB03) }, - { MP_ROM_QSTR(MP_QSTR_SPARE_3), MP_ROM_PTR(&pin_PB03) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_PB03) }, { MP_ROM_QSTR(MP_QSTR_DEBUG_TX), MP_ROM_PTR(&pin_PA22) }, { MP_ROM_QSTR(MP_QSTR_DEBUG_RX), MP_ROM_PTR(&pin_PA23) }, { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, From dd0e10d6f45398683627f268eb6ad060044887d6 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 21 Sep 2025 11:49:58 -0400 Subject: [PATCH 027/876] turn on canio --- .../microchip_curiosity_circuitpython_nano/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk index 34c9d7bcaab..4bb7b685509 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk @@ -11,3 +11,4 @@ EXTERNAL_FLASH_DEVICES = "SST26VF016B,SST26VF032B,SST26VF064B" LONGINT_IMPL = MPZ CIRCUITPY__EVE = 1 +CIRCUITPY_CANIO = 1 From 9c9252c7100771d7b03eac4eb95ef89e5fbd9095 Mon Sep 17 00:00:00 2001 From: Manjunath CV Date: Sun, 28 Sep 2025 12:56:26 +0530 Subject: [PATCH 028/876] Added Board WeAct Studio RP2350B Core --- locale/circuitpython.pot | 4 -- .../boards/weact_studio_rp2350b_core/board.c | 9 +++ .../weact_studio_rp2350b_core/mpconfigboard.h | 10 +++ .../mpconfigboard.mk | 12 ++++ .../pico-sdk-configboard.h | 7 ++ .../boards/weact_studio_rp2350b_core/pins.c | 67 +++++++++++++++++++ 6 files changed, 105 insertions(+), 4 deletions(-) create mode 100644 ports/raspberrypi/boards/weact_studio_rp2350b_core/board.c create mode 100644 ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/weact_studio_rp2350b_core/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1e167c30353..e1c235252fb 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -159,10 +159,6 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "" - #: py/argcheck.c msgid "%q must be %d" msgstr "" diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/board.c b/ports/raspberrypi/boards/weact_studio_rp2350b_core/board.c new file mode 100644 index 00000000000..e6a868ab212 --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h new file mode 100644 index 00000000000..80d557cdc25 --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "WeAct Studio RP2350B Core" +#define MICROPY_HW_MCU_NAME "rp2350b" + +//#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO47) diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk new file mode 100644 index 00000000000..ceef6b4846d --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk @@ -0,0 +1,12 @@ +USB_VID = 0x2E8A +USB_PID = 0x000F +USB_PRODUCT = "RP2350B Core" +USB_MANUFACTURER = "WeAct Studio" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = B +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +CIRCUITPY__EVE = 1 diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/pico-sdk-configboard.h b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pico-sdk-configboard.h new file mode 100644 index 00000000000..66b57dfd13d --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pico-sdk-configboard.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c new file mode 100644 index 00000000000..989855a3843 --- /dev/null +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c @@ -0,0 +1,67 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, + + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_GP30), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_GP31), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_GP32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_GP33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_GP34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_GP35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_GP36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_GP37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_GP38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_GP39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_GP40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_GP41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_GP42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_GP43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_GP44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_GP45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_GP46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_GP47), MP_ROM_PTR(&pin_GPIO47) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From c3b6fb34f74833baf97c020de2095f4d8ac823f1 Mon Sep 17 00:00:00 2001 From: Manjunath CV Date: Sun, 28 Sep 2025 13:57:42 +0530 Subject: [PATCH 029/876] Added Board WeAct Studio RP2350B Core --- .../boards/weact_studio_rp2350b_core/mpconfigboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h index 80d557cdc25..95a81334c73 100644 --- a/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.h @@ -7,4 +7,4 @@ #define MICROPY_HW_BOARD_NAME "WeAct Studio RP2350B Core" #define MICROPY_HW_MCU_NAME "rp2350b" -//#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO47) +#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO0) From 3d22d521fe8d5a6c62adb1857b838166d1cf747f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 29 Sep 2025 20:15:51 -0400 Subject: [PATCH 030/876] Prevent both host and CircuitPython rw access to mounted filesystems --- py/circuitpy_mpconfig.h | 3 +++ shared-bindings/storage/__init__.c | 10 +++++++++- shared-module/storage/__init__.c | 5 +++++ supervisor/shared/filesystem.c | 8 ++++---- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 27d4e97ad4d..2754d57b01c 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -345,6 +345,9 @@ typedef long mp_off_t; #endif +// For easy debugging printf's. +#define PLAT_PRINTF(...) mp_printf(&mp_plat_print, __VA_ARGS__) + #if MICROPY_PY_ASYNC_AWAIT && !CIRCUITPY_TRACEBACK #error CIRCUITPY_ASYNCIO requires CIRCUITPY_TRACEBACK #endif diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index ee0fb4ab53c..93c360d564e 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -54,15 +54,23 @@ static mp_obj_t storage_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t // get the mount point const char *mnt_str = mp_obj_str_get_str(args[ARG_mount_path].u_obj); + + mp_obj_t vfs_obj = args[ARG_filesystem].u_obj; + + // Currently, the only supported filesystem is VfsFat. + mp_arg_validate_type(vfs_obj, &mp_fat_vfs_type, MP_QSTR_filesystem); + + // Add this back if/when we start supporting other filesystems. + #if 0 // Make sure we're given an object we can mount. // TODO(tannewt): Make sure we have all the methods we need to operating it // as a file system. - mp_obj_t vfs_obj = args[ARG_filesystem].u_obj; mp_obj_t dest[2]; mp_load_method_maybe(vfs_obj, MP_QSTR_mount, dest); if (dest[0] == MP_OBJ_NULL) { mp_raise_ValueError(MP_ERROR_TEXT("filesystem must provide mount method")); } + #endif common_hal_storage_mount(vfs_obj, mnt_str, args[ARG_readonly].u_bool); diff --git a/shared-module/storage/__init__.c b/shared-module/storage/__init__.c index 9a2c8271222..dedcee1ff23 100644 --- a/shared-module/storage/__init__.c +++ b/shared-module/storage/__init__.c @@ -126,6 +126,11 @@ void common_hal_storage_mount(mp_obj_t vfs_obj, const char *mount_path, bool rea // call the underlying object to do any mounting operation mp_vfs_proxy_call(vfs, MP_QSTR_mount, 2, (mp_obj_t *)&args); + fs_user_mount_t *vfs_fat = MP_OBJ_TO_PTR(vfs_obj); + // Filesystem is read-only to USB if writable by CircuitPython, and vice versa. + filesystem_set_writable_by_usb(vfs_fat, readonly); + filesystem_set_concurrent_write_protection(vfs_fat, true); + // Insert the vfs into the mount table by pushing it onto the front of the // mount table. mp_vfs_mount_t **vfsp = &MP_STATE_VM(vfs_mount_table); diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index df70d963de6..24c7f9bffc5 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -247,13 +247,13 @@ void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable) { } bool filesystem_is_writable_by_python(fs_user_mount_t *vfs) { - return (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0 || - (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) == 0; + return ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0) || + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) == 0); } bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs) { - return (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0 || - (vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) != 0; + return ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0) || + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) != 0); } void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection) { From 81e77aa71e1dfdd4989f832346874e89d3dd564a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 30 Sep 2025 10:57:27 -0400 Subject: [PATCH 031/876] main.c: unmount user-mounted vfs regardless of order --- main.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/main.c b/main.c index 78148f2cb01..d7f3c7aaf1b 100644 --- a/main.c +++ b/main.c @@ -211,14 +211,22 @@ static void start_mp(safe_mode_t safe_mode) { static void stop_mp(void) { #if MICROPY_VFS - mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); // Unmount all heap allocated vfs mounts. - while (gc_ptr_on_heap(vfs)) { + mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); + do { + if (gc_ptr_on_heap(vfs)) { + // mp_vfs_umount will splice out an unmounted vfs from the vfs_mount_table linked list. + mp_vfs_umount(vfs->obj); + // Start over at the beginning of the list since the first entry may have been removed. + vfs = MP_STATE_VM(vfs_mount_table); + continue; + } vfs = vfs->next; - } - MP_STATE_VM(vfs_mount_table) = vfs; + } while (vfs != NULL); + // The last vfs is CIRCUITPY and the root directory. + vfs = MP_STATE_VM(vfs_mount_table); while (vfs->next != NULL) { vfs = vfs->next; } From 216b3100652f93466730b49c5993293e0dc23459 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 30 Sep 2025 12:09:13 -0400 Subject: [PATCH 032/876] shrink some atmel-samd boards --- .../atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk | 3 ++- ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk | 1 + ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk | 1 + ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk b/ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk index 7c301e3ea96..121becc472d 100755 --- a/ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk +++ b/ports/atmel-samd/boards/circuitbrains_basic_m0/mpconfigboard.mk @@ -11,4 +11,5 @@ EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" LONGINT_IMPL = MPZ CIRCUITPY_CODEOP = 0 -CIRCUITPY_JPEGIO = 0 +CIRCUITPY_ERRNO = 0 +CIRCUITPY_RAINBOWIO = 0 diff --git a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk index 783e2cb5657..1152fb4acc4 100644 --- a/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_express/mpconfigboard.mk @@ -11,4 +11,5 @@ EXTERNAL_FLASH_DEVICES = "S25FL216K, GD25Q16C, W25Q16JVxQ" LONGINT_IMPL = MPZ CIRCUITPY_CODEOP = 0 +CIRCUITPY_ERRNO = 0 CIRCUITPY_RAINBOWIO = 0 diff --git a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk index bd068adc943..dd58e8d1ce5 100644 --- a/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m0_supersized/mpconfigboard.mk @@ -11,4 +11,5 @@ EXTERNAL_FLASH_DEVICES = "S25FL064L" LONGINT_IMPL = MPZ CIRCUITPY_CODEOP = 0 +CIRCUITPY_ERRNO = 0 CIRCUITPY_RAINBOWIO = 0 diff --git a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk index a7c18acba3c..ee414b6e214 100644 --- a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk @@ -17,6 +17,7 @@ CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_GIFIO = 0 CIRCUITPY_I2CTARGET = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_PS2IO = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_LTO_PARTITION = one From 179a52ec5321a3ad9a45f102f88b771852a96025 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 30 Sep 2025 13:40:56 -0400 Subject: [PATCH 033/876] remove unused code --- shared-bindings/storage/__init__.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index 93c360d564e..14ec16f3096 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -60,18 +60,6 @@ static mp_obj_t storage_mount(size_t n_args, const mp_obj_t *pos_args, mp_map_t // Currently, the only supported filesystem is VfsFat. mp_arg_validate_type(vfs_obj, &mp_fat_vfs_type, MP_QSTR_filesystem); - // Add this back if/when we start supporting other filesystems. - #if 0 - // Make sure we're given an object we can mount. - // TODO(tannewt): Make sure we have all the methods we need to operating it - // as a file system. - mp_obj_t dest[2]; - mp_load_method_maybe(vfs_obj, MP_QSTR_mount, dest); - if (dest[0] == MP_OBJ_NULL) { - mp_raise_ValueError(MP_ERROR_TEXT("filesystem must provide mount method")); - } - #endif - common_hal_storage_mount(vfs_obj, mnt_str, args[ARG_readonly].u_bool); return mp_const_none; From 0b89ac1e245bbf5070b8cb752ebc18a6516c2adf Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 30 Sep 2025 16:32:41 -0400 Subject: [PATCH 034/876] update frozen libraries --- frozen/Adafruit_CircuitPython_PortalBase | 2 +- frozen/Adafruit_CircuitPython_Wiznet5k | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_PortalBase b/frozen/Adafruit_CircuitPython_PortalBase index c87f120723e..d26e2324de4 160000 --- a/frozen/Adafruit_CircuitPython_PortalBase +++ b/frozen/Adafruit_CircuitPython_PortalBase @@ -1 +1 @@ -Subproject commit c87f120723e9fa742e3da25eaf33f3be1ae33715 +Subproject commit d26e2324de496761e0aa72abc30ba07cdce8814b diff --git a/frozen/Adafruit_CircuitPython_Wiznet5k b/frozen/Adafruit_CircuitPython_Wiznet5k index 6b3484d1ee2..736241c7a22 160000 --- a/frozen/Adafruit_CircuitPython_Wiznet5k +++ b/frozen/Adafruit_CircuitPython_Wiznet5k @@ -1 +1 @@ -Subproject commit 6b3484d1ee243a7e8bc0513ab84956e1b6e2a520 +Subproject commit 736241c7a22f86dcf8ff73a77c4536cedfdc4cdd From 3de2c639fd9070bf49f09f4f8af0da6148af7817 Mon Sep 17 00:00:00 2001 From: Juergen Pabel Date: Thu, 2 Oct 2025 18:15:47 +0200 Subject: [PATCH 035/876] Added new board: M5Stack DinMeter (esp32s3) --- .../espressif/boards/m5stack_dinmeter/board.c | 107 ++++++++++++++++++ .../boards/m5stack_dinmeter/mpconfigboard.h | 22 ++++ .../boards/m5stack_dinmeter/mpconfigboard.mk | 15 +++ .../espressif/boards/m5stack_dinmeter/pins.c | 61 ++++++++++ .../boards/m5stack_dinmeter/sdkconfig | 14 +++ 5 files changed, 219 insertions(+) create mode 100644 ports/espressif/boards/m5stack_dinmeter/board.c create mode 100644 ports/espressif/boards/m5stack_dinmeter/mpconfigboard.h create mode 100644 ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk create mode 100644 ports/espressif/boards/m5stack_dinmeter/pins.c create mode 100644 ports/espressif/boards/m5stack_dinmeter/sdkconfig diff --git a/ports/espressif/boards/m5stack_dinmeter/board.c b/ports/espressif/boards/m5stack_dinmeter/board.c new file mode 100644 index 00000000000..cd49318fd1c --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/board.c @@ -0,0 +1,107 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "mpconfigboard.h" +#include "supervisor/board.h" +#include "supervisor/shared/serial.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" +#include "py/runtime.h" +#include "py/ringbuf.h" +#include "shared/runtime/interrupt_char.h" + + +uint8_t display_init_sequence[] = { + 0x01, 0x80, 0x96, // SWRESET and Delay 150ms + 0x11, 0x80, 0xff, // SLPOUT and Delay + 0xb1, 0x03, 0x01, 0x2C, 0x2D, // _FRMCTR1 + 0xb2, 0x03, 0x01, 0x2C, 0x2D, // _FRMCTR2 + 0xb3, 0x06, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D, // _FRMCTR3 + 0xb4, 0x01, 0x07, // _INVCTR line inversion + 0xc0, 0x03, 0xa2, 0x02, 0x84, // _PWCTR1 GVDD = 4.7V, 1.0uA + 0xc1, 0x01, 0xc5, // _PWCTR2 VGH=14.7V, VGL=-7.35V + 0xc2, 0x02, 0x0a, 0x00, // _PWCTR3 Opamp current small, Boost frequency + 0xc3, 0x02, 0x8a, 0x2a, + 0xc4, 0x02, 0x8a, 0xee, + 0xc5, 0x01, 0x0e, // _VMCTR1 VCOMH = 4V, VOML = -1.1V + 0x36, 0x01, 0xc8, // MADCTL Rotate display + 0x21, 0x00, // _INVON + 0x3a, 0x01, 0x05, // COLMOD - 16bit color + 0xe0, 0x10, 0x02, 0x1c, 0x07, 0x12, 0x37, 0x32, 0x29, 0x2d, 0x29, 0x25, 0x2B, 0x39, 0x00, 0x01, 0x03, 0x10, // _GMCTRP1 Gamma + 0xe1, 0x10, 0x03, 0x1d, 0x07, 0x06, 0x2E, 0x2C, 0x29, 0x2D, 0x2E, 0x2E, 0x37, 0x3F, 0x00, 0x00, 0x02, 0x10, // _GMCTRN1 + 0x13, 0x80, 0x0a, // _NORON + 0x29, 0x80, 0x64 // _DISPON +}; + + +// Overrides the weakly linked function from supervisor/shared/board.c +void board_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + // see here for inspiration: https://github.com/m5stack/M5GFX/blob/33d7d3135e816a86a008fae8ab3757938cee95d2/src/M5GFX.cpp#L1350 + common_hal_fourwire_fourwire_construct( + bus, + spi, + &pin_GPIO4, // DC + &pin_GPIO7, // CS + &pin_GPIO8, // RST + 40000000, // baudrate + 0, // polarity + 0 // phase + ); + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 240, // width (after rotation) + 135, // height (after rotation) + 40, // column start + 52, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO9, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 80, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} + + +bool espressif_board_reset_pin_number(gpio_num_t pin_number) { + // Hold pin must be set high to avoid a power off when battery powered + if (pin_number == 46) { + // Turn on hold output + config_pin_as_output_with_level(pin_number, true); + return true; + } + return false; +} + +// TODO: Should we turn off the display when asleep, in board_deinit() ? diff --git a/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.h b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.h new file mode 100644 index 00000000000..2d69e61ea95 --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 CDarius +// SPDX-FileCopyrightText: Copyright (c) 2025 juergenpabel +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "M5Stack DinMeter" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define CIRCUITPY_BOARD_I2C (2) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO12, .sda = &pin_GPIO11}, \ + {.scl = &pin_GPIO15, .sda = &pin_GPIO13}} + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO6, .mosi = &pin_GPIO5}} + +#define CIRCUITPY_I2C_ALLOW_INTERNAL_PULL_UP (1) diff --git a/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk new file mode 100644 index 00000000000..7b7e941b6bc --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk @@ -0,0 +1,15 @@ +USB_VID = 0x303A +USB_PID = 0x81DD + +USB_PRODUCT = "M5stack - DinMeter" +USB_MANUFACTURER = "M5Stack" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +# Very few pins. +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 diff --git a/ports/espressif/boards/m5stack_dinmeter/pins.c b/ports/espressif/boards/m5stack_dinmeter/pins.c new file mode 100644 index 00000000000..f75e05e848b --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/pins.c @@ -0,0 +1,61 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Juergen Pabel +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +#include "shared-module/displayio/__init__.h" + +CIRCUITPY_BOARD_BUS_SINGLETON(porta_i2c, i2c, 1) + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Port A + { MP_ROM_QSTR(MP_QSTR_PORTA_SCL), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_SDA), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + // Port B + { MP_ROM_QSTR(MP_QSTR_PORTB_IN), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_PORTB_OUT), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + + // Encoder + { MP_ROM_QSTR(MP_QSTR_ENC_A), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_ENC_B), MP_ROM_PTR(&pin_GPIO40) }, + + // Button + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + + // Misc + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_SPEAKER), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_KNOB_BUTTON), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_POWER_HOLD), MP_ROM_PTR(&pin_GPIO46) }, + + // Display + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_I2C), MP_ROM_PTR(&board_porta_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/m5stack_dinmeter/sdkconfig b/ports/espressif/boards/m5stack_dinmeter/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/m5stack_dinmeter/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From 7806098d3866ce805b63c358ab64c837e008669d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Pabel?= Date: Thu, 2 Oct 2025 20:48:31 +0200 Subject: [PATCH 036/876] Update ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk Co-authored-by: Scott Shawcroft --- ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk index 7b7e941b6bc..02570b54230 100644 --- a/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk @@ -1,7 +1,7 @@ USB_VID = 0x303A USB_PID = 0x81DD -USB_PRODUCT = "M5stack - DinMeter" +USB_PRODUCT = "DinMeter" USB_MANUFACTURER = "M5Stack" IDF_TARGET = esp32s3 From 5b4b9e8db19c097e8422c15b04705050fab98798 Mon Sep 17 00:00:00 2001 From: Juergen Pabel Date: Thu, 2 Oct 2025 20:57:03 +0200 Subject: [PATCH 037/876] Updated USB-PID as per https://github.com/espressif/usb-pids/pull/261 --- ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk index 02570b54230..81a23af1fe4 100644 --- a/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_dinmeter/mpconfigboard.mk @@ -1,5 +1,5 @@ USB_VID = 0x303A -USB_PID = 0x81DD +USB_PID = 0x830B USB_PRODUCT = "DinMeter" USB_MANUFACTURER = "M5Stack" From 1ad0d5fcb113b9c44ed0328e9f28de4596bd789f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 3 Oct 2025 14:02:14 -0400 Subject: [PATCH 038/876] drop Nano from Microchip Curiosity CircuitPython Nano --- .../board.c | 0 .../mpconfigboard.h | 2 +- .../mpconfigboard.mk | 2 +- .../pins.c | 0 4 files changed, 2 insertions(+), 2 deletions(-) rename ports/atmel-samd/boards/{microchip_curiosity_circuitpython_nano => microchip_curiosity_circuitpython}/board.c (100%) rename ports/atmel-samd/boards/{microchip_curiosity_circuitpython_nano => microchip_curiosity_circuitpython}/mpconfigboard.h (99%) rename ports/atmel-samd/boards/{microchip_curiosity_circuitpython_nano => microchip_curiosity_circuitpython}/mpconfigboard.mk (83%) rename ports/atmel-samd/boards/{microchip_curiosity_circuitpython_nano => microchip_curiosity_circuitpython}/pins.c (100%) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/board.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/board.c similarity index 100% rename from ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/board.c rename to ports/atmel-samd/boards/microchip_curiosity_circuitpython/board.c diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.h similarity index 99% rename from ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h rename to ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.h index 6e67197e757..4416d8517d2 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.h +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.h @@ -1,7 +1,7 @@ #pragma once -#define MICROPY_HW_BOARD_NAME "Microchip Curiosity CircuitPython Nano" +#define MICROPY_HW_BOARD_NAME "Microchip Curiosity CircuitPython" #define MICROPY_HW_MCU_NAME "same51j20" #define CIRCUITPY_MCU_FAMILY samd51 diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.mk similarity index 83% rename from ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk rename to ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.mk index 4bb7b685509..985eb4c6a44 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/mpconfigboard.mk +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/mpconfigboard.mk @@ -1,6 +1,6 @@ USB_VID = 0x04D8 USB_PID = 0xE52B -USB_PRODUCT = "Microchip Curiosity CircuitPython Nano" +USB_PRODUCT = "Microchip Curiosity CircuitPython" USB_MANUFACTURER = "Microchip Technology Inc" CHIP_VARIANT = SAME51J20A diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c similarity index 100% rename from ports/atmel-samd/boards/microchip_curiosity_circuitpython_nano/pins.c rename to ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c From ea15d7461402e5a5346b28e73458c115fe72b419 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 5 Oct 2025 15:45:42 -0400 Subject: [PATCH 039/876] Allow subclassing deque --- py/objdeque.c | 36 ++++++++++++++++-------- tests/circuitpython/deque_subclass.py | 40 +++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 11 deletions(-) create mode 100644 tests/circuitpython/deque_subclass.py diff --git a/py/objdeque.c b/py/objdeque.c index 264c795801b..4e1ee82e9d4 100644 --- a/py/objdeque.c +++ b/py/objdeque.c @@ -46,6 +46,11 @@ static mp_obj_t mp_obj_deque_extend(mp_obj_t self_in, mp_obj_t arg_in); static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque, mp_obj_iter_buf_t *iter_buf); #endif +// CIRCUITPY-CHANGE +static mp_obj_deque_t *native_deque(mp_obj_t self_in) { + return MP_OBJ_TO_PTR(mp_obj_cast_to_native_base(self_in, MP_OBJ_FROM_PTR(&mp_type_deque))); +} + static mp_obj_t deque_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, 2, 3, false); @@ -79,7 +84,8 @@ static size_t deque_len(mp_obj_deque_t *self) { } static mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->i_get != self->i_put); @@ -98,7 +104,8 @@ static mp_obj_t deque_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } static mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); size_t new_i_put = self->i_put + 1; if (new_i_put == self->alloc) { @@ -123,7 +130,8 @@ static mp_obj_t mp_obj_deque_append(mp_obj_t self_in, mp_obj_t arg) { static MP_DEFINE_CONST_FUN_OBJ_2(deque_append_obj, mp_obj_deque_append); static mp_obj_t mp_obj_deque_appendleft(mp_obj_t self_in, mp_obj_t arg) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); size_t new_i_get = self->i_get - 1; if (self->i_get == 0) { @@ -162,7 +170,8 @@ static mp_obj_t mp_obj_deque_extend(mp_obj_t self_in, mp_obj_t arg_in) { static MP_DEFINE_CONST_FUN_OBJ_2(deque_extend_obj, mp_obj_deque_extend); static mp_obj_t deque_popleft(mp_obj_t self_in) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); if (self->i_get == self->i_put) { mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty")); @@ -180,7 +189,8 @@ static mp_obj_t deque_popleft(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(deque_popleft_obj, deque_popleft); static mp_obj_t deque_pop(mp_obj_t self_in) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); if (self->i_get == self->i_put) { mp_raise_msg(&mp_type_IndexError, MP_ERROR_TEXT("empty")); @@ -205,7 +215,8 @@ static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { // delete not supported, fall back to mp_obj_subscr() error message return MP_OBJ_NULL; } - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); size_t offset = mp_get_index(self->base.type, deque_len(self), index, false); size_t index_val = self->i_get + offset; @@ -226,7 +237,8 @@ static mp_obj_t deque_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { #if 0 static mp_obj_t deque_clear(mp_obj_t self_in) { - mp_obj_deque_t *self = MP_OBJ_TO_PTR(self_in); + // CIRCUITPY-CHANGE + mp_obj_deque_t *self = native_deque(self_in); self->i_get = self->i_put = 0; mp_seq_clear(self->items, 0, self->alloc, sizeof(*self->items)); return mp_const_none; @@ -286,7 +298,8 @@ typedef struct _mp_obj_deque_it_t { static mp_obj_t deque_it_iternext(mp_obj_t self_in) { mp_obj_deque_it_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_deque_t *deque = MP_OBJ_TO_PTR(self->deque); + // CIRCUITPY-CHANGE + mp_obj_deque_t *deque = native_deque(self->deque); if (self->cur != deque->i_put) { mp_obj_t o_out = deque->items[self->cur]; if (++self->cur == deque->alloc) { @@ -298,9 +311,10 @@ static mp_obj_t deque_it_iternext(mp_obj_t self_in) { } } -static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque, mp_obj_iter_buf_t *iter_buf) { - mp_obj_deque_t *deque_ = MP_OBJ_TO_PTR(deque); - size_t i_get = deque_->i_get; +static mp_obj_t mp_obj_new_deque_it(mp_obj_t deque_in, mp_obj_iter_buf_t *iter_buf) { + // CIRCUITPY-CHANGE + mp_obj_deque_t *deque = native_deque(deque_in); + size_t i_get = deque->i_get; assert(sizeof(mp_obj_deque_it_t) <= sizeof(mp_obj_iter_buf_t)); mp_obj_deque_it_t *o = (mp_obj_deque_it_t *)iter_buf; o->base.type = &mp_type_polymorph_iter; diff --git a/tests/circuitpython/deque_subclass.py b/tests/circuitpython/deque_subclass.py new file mode 100644 index 00000000000..5708407a9b6 --- /dev/null +++ b/tests/circuitpython/deque_subclass.py @@ -0,0 +1,40 @@ +try: + from collections import deque +except ImportError: + print("SKIP") + raise SystemExit + + +class DequeSubclass(deque): + def __init__(self, values, maxlen): + super().__init__(values, maxlen) + + def pop(self): + print("pop") + return super().pop() + + def popleft(self): + print("popleft") + return super().popleft() + + def append(self, value): + print("append") + return super().append(value) + + def appendleft(self, value): + print("appendleft") + return super().appendleft(value) + + def extend(self, value): + print("extend") + return super().extend(value) + + +d = DequeSubclass([1, 2, 3], 10) +print(d.append(4)) +print(d.appendleft(0)) +print(d.pop()) +print(d.popleft()) +d.extend([6, 7]) +# calling list() tests iteration. +print(list(d)) From 36d53efa7c6f9a3f0172620df309904a01a8e854 Mon Sep 17 00:00:00 2001 From: Chris Wilson <14631+cdwilson@users.noreply.github.com> Date: Mon, 6 Oct 2025 11:41:37 -0700 Subject: [PATCH 040/876] stm/boards: Fix USB PID for SparkFun STM32 MicroMod. When I originally created the PR to add support for the SparkFun STM32 MicroMod, SparkFun provided me with the following PID/VID: PID: 0x0027 VID: 0X1B4F I missed a follow-up post from SparkFun about 5 months later which provided a corrected PID for this device: PID: 0x0029 See https://community.sparkfun.com/t/circuitpython-support-for-micromod-stm32-need-usb-pid/42486/5 --- ports/stm/boards/sparkfun_stm32f405_micromod/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/stm/boards/sparkfun_stm32f405_micromod/mpconfigboard.mk b/ports/stm/boards/sparkfun_stm32f405_micromod/mpconfigboard.mk index d1df685c676..31c2b7e2874 100644 --- a/ports/stm/boards/sparkfun_stm32f405_micromod/mpconfigboard.mk +++ b/ports/stm/boards/sparkfun_stm32f405_micromod/mpconfigboard.mk @@ -1,5 +1,5 @@ USB_VID = 0X1B4F -USB_PID = 0x0027 +USB_PID = 0x0029 USB_PRODUCT = "SparkFun STM32 MicroMod Processor" USB_MANUFACTURER = "SparkFun Electronics" From 3d40ba3531701407daa13f9a979ddbdd44806bcd Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 14 Aug 2025 11:40:43 -0700 Subject: [PATCH 041/876] Update to ESP IDF 5.5.1 --- .gitmodules | 2 +- lib/protomatter | 2 +- lib/tinyusb | 2 +- ports/espressif/Makefile | 31 +++++++++++++------ .../espressif/common-hal/alarm/pin/PinAlarm.c | 2 ++ .../espressif/common-hal/analogio/AnalogIn.c | 6 ---- ports/espressif/common-hal/espnow/ESPNow.c | 2 +- .../paralleldisplaybus/ParallelBus.c | 2 +- .../paralleldisplaybus/ParallelBus.h | 2 +- ports/espressif/esp-idf | 2 +- .../esp-idf-config/partitions-8MB-no-uf2.csv | 3 +- .../esp-idf-config/sdkconfig.defaults | 6 ++++ ports/espressif/mpconfigport.mk | 2 ++ ports/espressif/peripherals/pins.h | 2 +- py/circuitpy_mpconfig.mk | 4 +++ supervisor/supervisor.mk | 5 ++- 16 files changed, 48 insertions(+), 27 deletions(-) diff --git a/.gitmodules b/.gitmodules index b89769942af..7eaa0b04142 100644 --- a/.gitmodules +++ b/.gitmodules @@ -143,7 +143,7 @@ [submodule "ports/espressif/esp-idf"] path = ports/espressif/esp-idf url = https://github.com/adafruit/esp-idf.git - branch = circuitpython-v5.4.1 + branch = circuitpython-v5.5.1 [submodule "ports/espressif/esp-protocols"] path = ports/espressif/esp-protocols url = https://github.com/adafruit/esp-protocols.git diff --git a/lib/protomatter b/lib/protomatter index 0bd9873153a..f83bac7e421 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit 0bd9873153ab0a91d6737c392622159a4515a2e5 +Subproject commit f83bac7e421077812523fddb83d3e25f29753315 diff --git a/lib/tinyusb b/lib/tinyusb index 5fb3c09963b..8304587d777 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 5fb3c09963bca362e535788e289d4b3518da5973 +Subproject commit 8304587d7774526a03c6881d11e6d6208fe759be diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index a063101991f..157b59d9aaa 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -64,6 +64,7 @@ INC += \ -isystem esp-idf/components/esp_driver_i2s/include \ -isystem esp-idf/components/esp_driver_$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_driver_ledc/include \ + -isystem esp-idf/components/esp_driver_parlio/include \ -isystem esp-idf/components/esp_driver_pcnt/include \ -isystem esp-idf/components/esp_driver_rmt/include \ -isystem esp-idf/components/esp_driver_sdio/include \ @@ -149,6 +150,8 @@ CFLAGS += -DSTACK_CANARY_VALUE=0xa5a5a5a5 REGISTRATION_FUNCTIONS = \ -u ld_include_highint_hdl \ -u __cxx_fatal_exception \ + -u __cxx_init_dummy \ + -u __cxa_guard_dummy \ -u esp_app_desc \ -u esp_timer_init_include_func \ -u uart_vfs_include_dev_init \ @@ -156,13 +159,17 @@ REGISTRATION_FUNCTIONS = \ -u __ubsan_include \ -u esp_system_include_startup_funcs \ -u esp_efuse_startup_include_func \ - -u newlib_include_heap_impl \ - -u newlib_include_syscalls_impl \ - -u newlib_include_pthread_impl \ - -u newlib_include_assert_impl \ - -u newlib_include_init_funcs \ + -u esp_libc_include_heap_impl \ + -u esp_libc_include_reent_syscalls_impl \ + -u esp_libc_include_syscalls_impl \ + -u esp_libc_include_pthread_impl \ + -u esp_libc_include_assert_impl \ + -u esp_libc_include_getentropy_impl \ + -u esp_libc_include_init_funcs \ + -u esp_libc_init_funcs \ -u include_esp_phy_override \ - -u vfs_include_syscalls_impl + -u vfs_include_syscalls_impl \ + -u esp_vfs_include_nullfs_register #Debugging/Optimization @@ -222,7 +229,6 @@ else ifeq ($(IDF_TARGET_ARCH),riscv) -Trom.api.ld endif -$(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align LDFLAGS += $(CFLAGS) -Wl,-nostdlib -Wl,-Map=$@.map -Wl,-cref -Wl,--undefined=uxTopUsedPriority @@ -244,7 +250,9 @@ LDFLAGS += \ ifeq ($(IDF_TARGET),esp32) LDFLAGS += \ -Tesp32.rom.newlib-data.ld \ - -Tesp32.rom.newlib-funcs.ld \ + -Tesp32.rom.syscalls.ld \ + -Tesp32.rom.libc-funcs.ld \ + -Tesp32.rom.newlib-reent-funcs.ld \ -Tesp32.rom.spiflash_legacy.ld CHIP_COMPONENTS = \ @@ -280,7 +288,9 @@ LDFLAGS += \ -Tesp32c6.rom.phy.ld \ -Tesp32c6.rom.pp.ld \ -Tesp32c6.rom.net80211.ld \ + -Tesp32c6.rom.libc.ld \ -Tesp32c6.rom.newlib.ld \ + -Tesp32c6.rom.spiflash.ld \ -Tesp32c6.rom.coexist.ld \ -Tesp32c6.rom.heap.ld \ -Tesp32c6.rom.systimer.ld \ @@ -312,8 +322,9 @@ CHIP_COMPONENTS = \ else ifeq ($(IDF_TARGET),esp32s2) LDFLAGS += \ + -Tesp32s2.rom.libc-funcs.ld \ -Tesp32s2.rom.newlib-data.ld \ - -Tesp32s2.rom.newlib-funcs.ld \ + -Tesp32s2.rom.newlib-reent-funcs.ld \ -Tesp32s2.rom.spiflash_legacy.ld CHIP_COMPONENTS = \ @@ -782,7 +793,7 @@ endif IDF_CMAKE_TARGETS = \ bootloader/bootloader.bin \ - esp-idf/esp_system/__ldgen_output_sections.ld \ + __ldgen_output_sections.ld \ $(foreach component, $(ESP_IDF_COMPONENTS_LINK), esp-idf/$(component)/lib$(component).a) PARTITION_TABLE_OFFSET = 0x8000 diff --git a/ports/espressif/common-hal/alarm/pin/PinAlarm.c b/ports/espressif/common-hal/alarm/pin/PinAlarm.c index 8e3e46785f2..cecb91fe46d 100644 --- a/ports/espressif/common-hal/alarm/pin/PinAlarm.c +++ b/ports/espressif/common-hal/alarm/pin/PinAlarm.c @@ -14,10 +14,12 @@ #include "esp_sleep.h" #include "hal/gpio_ll.h" +#include "driver/gpio.h" #include "esp_debug_helpers.h" #ifdef SOC_PM_SUPPORT_EXT0_WAKEUP #include "soc/rtc_cntl_reg.h" +#include "soc/rtc_io_reg.h" #endif #include "driver/rtc_io.h" diff --git a/ports/espressif/common-hal/analogio/AnalogIn.c b/ports/espressif/common-hal/analogio/AnalogIn.c index 16340e91ac9..b4039b3d32d 100644 --- a/ports/espressif/common-hal/analogio/AnalogIn.c +++ b/ports/espressif/common-hal/analogio/AnalogIn.c @@ -86,10 +86,8 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { adc_cali_scheme_ver_t supported_schemes; adc_cali_check_scheme(&supported_schemes); - #ifndef CONFIG_IDF_TARGET_ESP32P4 adc_cali_scheme_ver_t calibration_scheme = 0; adc_cali_handle_t calibration; - #endif #if defined(ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED adc_cali_curve_fitting_config_t config = { .unit_id = self->pin->adc_index, @@ -137,11 +135,7 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { // This corrects non-linear regions of the ADC range with a LUT, so it's a better reading than raw int voltage; - #ifdef CONFIG_IDF_TARGET_ESP32P4 - voltage = 0; - #else adc_cali_raw_to_voltage(calibration, adc_reading, &voltage); - #endif #if defined(ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED) && ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED if (calibration_scheme == ADC_CALI_SCHEME_VER_CURVE_FITTING) { diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index 79bded96fb4..ae11db25032 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -56,7 +56,7 @@ typedef struct { // Callback triggered when a sent packet is acknowledged by the peer (or not). // Just count the number of responses and number of failures. // These are used in the send() logic. -static void send_cb(const uint8_t *mac, esp_now_send_status_t status) { +static void send_cb(const esp_now_send_info_t *tx_info, esp_now_send_status_t status) { espnow_obj_t *self = MP_STATE_PORT(espnow_singleton); if (status == ESP_NOW_SEND_SUCCESS) { self->send_success++; diff --git a/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c b/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c index 7721b5e197f..52c4b67bf4e 100644 --- a/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +++ b/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c @@ -18,7 +18,7 @@ #include "common-hal/microcontroller/Pin.h" #include "py/runtime.h" -#include "driver/gpio.h" +#include /* * Current pin limitations for ESP32-S2 ParallelBus: diff --git a/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.h b/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.h index 4724ba7231a..114a1e527a6 100644 --- a/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.h +++ b/ports/espressif/common-hal/paralleldisplaybus/ParallelBus.h @@ -8,7 +8,7 @@ #include "common-hal/digitalio/DigitalInOut.h" -#include "esp-idf/components/esp_lcd/include/esp_lcd_panel_io.h" +#include typedef struct { mp_obj_base_t base; diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index f50ec8ecdb3..f4fddd2d05b 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit f50ec8ecdb31f681e6a778f145de95f849c1089d +Subproject commit f4fddd2d05b44d1d606b546b596d17de0a73e9eb diff --git a/ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv b/ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv index 6d78fe8af59..44121812ea2 100644 --- a/ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv +++ b/ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv @@ -3,6 +3,5 @@ # partition_table, data, table, 0x8000, 4K nvs, data, nvs, 0x9000, 20K otadata, data, ota, 0xe000, 8K -ota_0, app, ota_0, 0x10000, 2048K -ota_1, app, ota_1, 0x210000, 2048K +ota_0, app, ota_0, 0x10000, 4096K user_fs, data, fat, 0x410000, 4032K diff --git a/ports/espressif/esp-idf-config/sdkconfig.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults index dd766675136..3c174057ceb 100644 --- a/ports/espressif/esp-idf-config/sdkconfig.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig.defaults @@ -20,6 +20,12 @@ CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y CONFIG_GPTIMER_ISR_IRAM_SAFE=y # end of GPTimer Configuration +# +# Touch Configuration +# +CONFIG_TOUCH_SUPPRESS_DEPRECATE_WARN=y +# end of Touch Configuration + # end of Driver Configurations # diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 42bf3418f96..b632c5dfd6f 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -54,6 +54,8 @@ CIRCUITPY_HASHLIB_MBEDTLS_ONLY = 0 CIRCUITPY_PORT_SERIAL = 1 +CIRCUITPY_LIB_TLSF = 0 + # These modules are implemented in ports//common-hal: CIRCUITPY__EVE ?= 1 CIRCUITPY_ALARM ?= 1 diff --git a/ports/espressif/peripherals/pins.h b/ports/espressif/peripherals/pins.h index f89855e308f..f185cee92c4 100644 --- a/ports/espressif/peripherals/pins.h +++ b/ports/espressif/peripherals/pins.h @@ -14,7 +14,7 @@ #include "components/hal/include/hal/gpio_types.h" #include "components/hal/include/hal/adc_types.h" -#include "components/hal/include/hal/touch_sensor_types.h" +#include "components/hal/include/hal/touch_sensor_legacy_types.h" typedef struct { mp_obj_base_t base; diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 8c838a41218..76ee8a1d72b 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -62,6 +62,10 @@ CFLAGS += -DCIRCUITPY_FULL_BUILD=$(CIRCUITPY_FULL_BUILD) # increased build time CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 9 +# By default, use our copy of TLSF. Some vendor SDKs may provide their own +# implementation of TLSF, which can be used instead by setting CIRCUITPY_LIB_TLSF=0. +CIRCUITPY_LIB_TLSF ?= 1 + # Reduce the size of in-flash properties. Requires support in the .ld linker # file, so not enabled by default. CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 0 diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 0ecc6ea3acf..21bda334131 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -1,6 +1,5 @@ SRC_SUPERVISOR = \ main.c \ - lib/tlsf/tlsf.c \ supervisor/port.c \ supervisor/shared/background_callback.c \ supervisor/shared/board.c \ @@ -20,6 +19,10 @@ SRC_SUPERVISOR = \ supervisor/shared/translate/translate.c \ supervisor/shared/workflow.c \ +ifeq ($(CIRCUITPY_LIB_TLSF),1) +SRC_SUPERVISOR += lib/tlsf/tlsf.c +endif + # For tlsf CFLAGS += -D_DEBUG=0 From c25ce600013058817b08f7838eab61e0ab0be490 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 11 Sep 2025 16:47:23 -0700 Subject: [PATCH 042/876] Stop using our own memcpy. Enhance decode backtrace script. --- ports/espressif/Makefile | 1 - .../esp-idf-config/sdkconfig-debug.defaults | 26 ++++++++++++ .../esp-idf-config/sdkconfig.defaults | 7 ++++ ports/espressif/tools/decode_backtrace.py | 41 ++++++++++++++----- py/circuitpy_defns.mk | 1 - 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 157b59d9aaa..5e4256749ee 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -290,7 +290,6 @@ LDFLAGS += \ -Tesp32c6.rom.net80211.ld \ -Tesp32c6.rom.libc.ld \ -Tesp32c6.rom.newlib.ld \ - -Tesp32c6.rom.spiflash.ld \ -Tesp32c6.rom.coexist.ld \ -Tesp32c6.rom.heap.ld \ -Tesp32c6.rom.systimer.ld \ diff --git a/ports/espressif/esp-idf-config/sdkconfig-debug.defaults b/ports/espressif/esp-idf-config/sdkconfig-debug.defaults index a9c8e34e547..368ba81bb4a 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-debug.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-debug.defaults @@ -7,6 +7,21 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y # end of Compiler options +# Bootloader config +# +# +# Log +# +# +# Format +# +CONFIG_BOOTLOADER_LOG_COLORS=y +# end of Format + +# end of Log + +# end of Bootloader config + # # Component config # @@ -19,6 +34,17 @@ CONFIG_ESP_CONSOLE_SECONDARY_NONE=y # CONFIG_ESP_CONSOLE_SECONDARY_USB_SERIAL_JTAG is not set # end of ESP System Settings +# +# Log +# +# +# Format +# +CONFIG_LOG_COLORS=y +# end of Format + +# end of Log + # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults index 3c174057ceb..5c4d6a31a62 100644 --- a/ports/espressif/esp-idf-config/sdkconfig.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig.defaults @@ -65,6 +65,13 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=16384 CONFIG_FREERTOS_HZ=1000 # end of Kernel +# +# LibC +# +# end of LWIP +CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS=y +# end of LibC + # # LWIP # diff --git a/ports/espressif/tools/decode_backtrace.py b/ports/espressif/tools/decode_backtrace.py index 024e636207e..1733c69b5bb 100644 --- a/ports/espressif/tools/decode_backtrace.py +++ b/ports/espressif/tools/decode_backtrace.py @@ -12,20 +12,39 @@ board = sys.argv[1] print(board) +elfs = [ + f"build-{board}/firmware.elf", + "/home/tannewt/Downloads/esp-rom-elfs-20241011/esp32c6_rev0_rom.elf", +] + while True: + print('"Backtrace:" or "Stack memory:". CTRL-D to finish multiline paste') addresses = input("? ") if addresses.startswith("Backtrace:"): addresses = addresses[len("Backtrace:") :] + addresses = addresses.strip().split() + addresses = [address.split(":")[0] for address in addresses] if addresses.startswith("Stack memory:"): - addresses = addresses[len("Stack memory:") :] - addresses = addresses.strip().split() - addresses = [address.split(":")[0] for address in addresses] + addresses = [] + extra_lines = sys.stdin.readlines() + for line in extra_lines: + if not line.strip(): + continue + addresses.extend(line.split(":")[1].strip().split()) for address in addresses: - result = subprocess.run( - ["xtensa-esp32s2-elf-addr2line", "-aipfe", "build-{}/firmware.elf".format(board)] - + [address], - capture_output=True, - ) - stdout = result.stdout.decode("utf-8") - if "?? ??" not in stdout: - print(stdout.strip()) + if address == "0xa5a5a5a5": + # Skip stack fill value. + continue + for elf in elfs: + result = subprocess.run( + ["riscv32-esp-elf-addr2line", "-aipfe", elf, address], + capture_output=True, + ) + stdout = result.stdout.decode("utf-8") + if not stdout: + continue + if "?? ??" not in stdout: + print(stdout.strip()) + break + + print("loop") diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index d6569bc39bd..f3d25f6270c 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -992,7 +992,6 @@ endif # Sources used in all ports except unix. SRC_CIRCUITPY_COMMON = \ - shared/libc/string0.c \ shared/readline/readline.c \ lib/oofatfs/ff.c \ lib/oofatfs/ffunicode.c \ From f98014475dd2e91b29bc817f0d8c6afd4d43f114 Mon Sep 17 00:00:00 2001 From: Derek Daniels Date: Mon, 15 Sep 2025 14:38:14 -0400 Subject: [PATCH 043/876] [ports/espressif] esp-idf v5.5 changes --- ports/espressif/Makefile | 8 +++- .../espressif/common-hal/alarm/pin/PinAlarm.c | 40 +++++++++---------- .../common-hal/digitalio/DigitalInOut.c | 24 ++++++----- .../common-hal/microcontroller/Pin.c | 5 +-- ports/espressif/common-hal/wifi/__init__.c | 7 +++- 5 files changed, 47 insertions(+), 37 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 5e4256749ee..a080939e220 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -672,7 +672,7 @@ ifneq ($(IDF_TARGET),esp32p4) BINARY_BLOBS = esp-idf/components/esp_phy/lib/$(IDF_TARGET)/libphy.a endif ifneq ($(CIRCUITPY_WIFI),0) - BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, $(BINARY_WIFI_BLOBS)) + BINARY_BLOBS += $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, $(BINARY_WIFI_BLOBS)) ifneq ($(IDF_TARGET),esp32c2) BINARY_BLOBS += $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, libmesh.a libwapi.a) endif @@ -683,6 +683,12 @@ BINARY_BLOBS += esp-idf/components/esp_phy/lib/$(IDF_TARGET)/librtc.a endif ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console +NEEDS_COEX = $(CIRCUITPY_BLEIO_NATIVE) + $(CIRCUITPY_WIFI) +ifneq ($(NEEDS_COEX),0) + # esp_system_include_startup_funcs requires coexist as well BT regardless of wifi + BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a + ESP_IDF_COMPONENTS_LINK += esp_coex +endif ifneq ($(CIRCUITPY_WIFI),0) ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy endif diff --git a/ports/espressif/common-hal/alarm/pin/PinAlarm.c b/ports/espressif/common-hal/alarm/pin/PinAlarm.c index cecb91fe46d..2b09c630925 100644 --- a/ports/espressif/common-hal/alarm/pin/PinAlarm.c +++ b/ports/espressif/common-hal/alarm/pin/PinAlarm.c @@ -360,38 +360,36 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob if (gpio_isr_register(gpio_interrupt, NULL, 0, &gpio_interrupt_handle) != ESP_OK) { mp_raise_ValueError(MP_ERROR_TEXT("Can only alarm on RTC IO from deep sleep.")); } - for (size_t i = 0; i < 64; i++) { - uint64_t mask = 1ull << i; + for (gpio_num_t pin = 0; pin < SOC_GPIO_PIN_COUNT; pin++) { + uint64_t mask = 1ULL << pin; bool high = (high_alarms & mask) != 0; bool low = (low_alarms & mask) != 0; bool pull = (pull_pins & mask) != 0; if (!(high || low)) { continue; } - if (rtc_gpio_is_valid_gpio(i)) { + if (rtc_gpio_is_valid_gpio(pin)) { #ifdef SOC_PM_SUPPORT_RTC_PERIPH_PD - rtc_gpio_deinit(i); + rtc_gpio_deinit(pin); #endif } - gpio_int_type_t interrupt_mode = GPIO_INTR_DISABLE; - gpio_pull_mode_t pull_mode = GPIO_FLOATING; - if (high) { - interrupt_mode = GPIO_INTR_HIGH_LEVEL; - pull_mode = GPIO_PULLDOWN_ONLY; - } - if (low) { - interrupt_mode = GPIO_INTR_LOW_LEVEL; - pull_mode = GPIO_PULLUP_ONLY; - } - gpio_set_direction(i, GPIO_MODE_DEF_INPUT); - PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[i], PIN_FUNC_GPIO); + gpio_set_direction(pin, GPIO_MODE_INPUT); if (pull) { - gpio_set_pull_mode(i, pull_mode); + if (high) { + ESP_ERROR_CHECK(gpio_set_pull_mode(pin, GPIO_PULLDOWN_ONLY)); + } else { + ESP_ERROR_CHECK(gpio_set_pull_mode(pin, GPIO_PULLUP_ONLY)); + } + } else { + ESP_ERROR_CHECK(gpio_set_pull_mode(pin, GPIO_FLOATING)); } - never_reset_pin_number(i); - // Sets interrupt type and wakeup bits. - gpio_wakeup_enable(i, interrupt_mode); - gpio_intr_enable(i); + gpio_int_type_t intr = GPIO_INTR_DISABLE; + if (high) intr = GPIO_INTR_HIGH_LEVEL; + if (low) intr = GPIO_INTR_LOW_LEVEL; + never_reset_pin_number(pin); + gpio_wakeup_enable(pin, intr); + gpio_set_intr_type(pin, intr); + gpio_intr_enable(pin); } // Wait for any pulls to settle. mp_hal_delay_ms(50); diff --git a/ports/espressif/common-hal/digitalio/DigitalInOut.c b/ports/espressif/common-hal/digitalio/DigitalInOut.c index ed537419405..e4272ba1ff5 100644 --- a/ports/espressif/common-hal/digitalio/DigitalInOut.c +++ b/ports/espressif/common-hal/digitalio/DigitalInOut.c @@ -11,8 +11,11 @@ #include "hal/gpio_hal.h" static bool _pin_is_input(uint8_t pin_number) { - const uint32_t iomux = READ_PERI_REG(GPIO_PIN_MUX_REG[pin_number]); - return (iomux & FUN_IE) != 0; + gpio_io_config_t config; + if (gpio_get_io_config((gpio_num_t)pin_number, &config) != ESP_OK) { + return false; + } + return config.ie; } void digitalio_digitalinout_preserve_for_deep_sleep(size_t n_dios, digitalio_digitalinout_obj_t *preserve_dios[]) { @@ -113,10 +116,12 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_drive_mode( digitalio_drive_mode_t common_hal_digitalio_digitalinout_get_drive_mode( digitalio_digitalinout_obj_t *self) { - if (GPIO_HAL_GET_HW(GPIO_PORT_0)->pin[self->pin->number].pad_driver == 1) { + gpio_io_config_t config; + if (gpio_get_io_config((gpio_num_t)self->pin->number, &config) != ESP_OK) { + // Should it fail closed or open? return DRIVE_MODE_OPEN_DRAIN; } - return DRIVE_MODE_PUSH_PULL; + return config.od ? DRIVE_MODE_OPEN_DRAIN : DRIVE_MODE_PUSH_PULL; } digitalinout_result_t common_hal_digitalio_digitalinout_set_pull( @@ -134,11 +139,10 @@ digitalinout_result_t common_hal_digitalio_digitalinout_set_pull( digitalio_pull_t common_hal_digitalio_digitalinout_get_pull( digitalio_digitalinout_obj_t *self) { - gpio_num_t gpio_num = self->pin->number; - if (REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PU)) { - return PULL_UP; - } else if (REG_GET_BIT(GPIO_PIN_MUX_REG[gpio_num], FUN_PD)) { - return PULL_DOWN; + gpio_io_config_t config; + if (gpio_get_io_config((gpio_num_t)self->pin->number, &config) != ESP_OK) { + // Should it fail closed or open? + return PULL_NONE; } - return PULL_NONE; + return config.pd ? PULL_DOWN : PULL_UP; } diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index 70912afb545..e14a3366691 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -370,9 +370,8 @@ void reset_all_pins(void) { gpio_deep_sleep_hold_dis(); #endif - for (uint8_t i = 0; i < GPIO_PIN_COUNT; i++) { - uint32_t iomux_address = GPIO_PIN_MUX_REG[i]; - if (iomux_address == 0 || + for (gpio_num_t i = 0; i < SOC_GPIO_PIN_COUNT; i++) { + if (!GPIO_IS_VALID_GPIO(i) || _never_reset(i) || _skip_reset_once(i) || _preserved_pin(i)) { diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index 1a4c014bfbc..0eacd2bab3e 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -146,8 +146,8 @@ void common_hal_wifi_init(bool user_initiated) { common_hal_wifi_radio_obj.base.type = &wifi_radio_type; if (!wifi_ever_inited) { - ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); + ESP_ERROR_CHECK(esp_netif_init()); wifi_ever_inited = true; } @@ -175,6 +175,7 @@ void common_hal_wifi_init(bool user_initiated) { &self->handler_instance_got_ip)); wifi_init_config_t config = WIFI_INIT_CONFIG_DEFAULT(); + esp_err_t result = esp_wifi_init(&config); #ifdef CONFIG_ESP32_WIFI_NVS_ENABLED // Generally we don't use this because we store ssid and passwords ourselves in the filesystem. esp_err_t err = nvs_flash_init(); @@ -185,8 +186,10 @@ void common_hal_wifi_init(bool user_initiated) { err = nvs_flash_init(); } ESP_ERROR_CHECK(err); + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_FLASH)); + #else + ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM)); #endif - esp_err_t result = esp_wifi_init(&config); if (result == ESP_ERR_NO_MEM) { if (gc_alloc_possible()) { mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Failed to allocate Wifi memory")); From bc44db821442fcb5f5fcf5b8f1cef59d8f0e349b Mon Sep 17 00:00:00 2001 From: Derek Daniels Date: Mon, 15 Sep 2025 14:41:06 -0400 Subject: [PATCH 044/876] [ports/espressif] support for esp32c61 --- ports/espressif/Makefile | 28 +++++++- .../espressif_esp32c61_devkitc_1_n8r2/board.c | 9 +++ .../mpconfigboard.h | 15 ++++ .../mpconfigboard.mk | 13 ++++ .../espressif_esp32c61_devkitc_1_n8r2/pins.c | 48 +++++++++++++ .../sdkconfig | 14 ++++ .../common-hal/analogbufio/BufferedIn.c | 2 +- .../espressif/common-hal/analogio/AnalogIn.c | 2 + .../common-hal/microcontroller/Pin.c | 23 ++++++ .../common-hal/microcontroller/Processor.c | 6 +- .../common-hal/microcontroller/__init__.c | 5 +- .../sdkconfig-esp32c61.defaults | 54 ++++++++++++++ ports/espressif/mpconfigport.h | 2 +- ports/espressif/mpconfigport.mk | 42 +++++++++++ ports/espressif/peripherals/esp32c61/pins.c | 38 ++++++++++ ports/espressif/peripherals/esp32c61/pins.h | 72 +++++++++++++++++++ ports/espressif/peripherals/pins.h | 2 + ports/espressif/supervisor/port.c | 7 +- ports/espressif/tools/build_memory_info.py | 6 ++ 19 files changed, 381 insertions(+), 7 deletions(-) create mode 100644 ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/board.c create mode 100644 ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.h create mode 100644 ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.mk create mode 100644 ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/pins.c create mode 100644 ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/sdkconfig create mode 100644 ports/espressif/esp-idf-config/sdkconfig-esp32c61.defaults create mode 100644 ports/espressif/peripherals/esp32c61/pins.c create mode 100644 ports/espressif/peripherals/esp32c61/pins.h diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index a080939e220..930cdd96182 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -8,6 +8,8 @@ include ../../py/circuitpy_mkenv.mk ifeq ($(IDF_TARGET),esp32s3) BT_IDF_TARGET = esp32c3 +else ifeq ($(IDF_TARGET),esp32c61) +BT_IDF_TARGET = esp32c6 else BT_IDF_TARGET = $(IDF_TARGET) endif @@ -296,6 +298,23 @@ LDFLAGS += \ -Tesp32c6.rom.wdt.ld +CHIP_COMPONENTS = \ + esp_driver_tsens + +else ifeq ($(IDF_TARGET),esp32c61) +LDFLAGS += \ + -Tesp32c61.rom.phy.ld \ + -Tesp32c61.rom.pp.ld \ + -Tesp32c61.rom.net80211.ld \ + -Tesp32c61.rom.libc.ld \ + -Tesp32c61.rom.newlib.ld \ + -Tesp32c61.rom.version.ld \ + -Tesp32c61.rom.coexist.ld \ + -Tesp32c61.rom.heap.ld \ + -Tesp32c61.rom.systimer.ld \ + -Tesp32c61.rom.wdt.ld + + CHIP_COMPONENTS = \ esp_driver_tsens @@ -360,6 +379,8 @@ else ifeq ($(IDF_TARGET),esp32c3) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C3 else ifeq ($(IDF_TARGET),esp32c6) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C6 +else ifeq ($(IDF_TARGET),esp32c61) +CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32C61 else ifeq ($(IDF_TARGET),esp32p4) CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_ESP32P4 else ifeq ($(IDF_TARGET),esp32h2) @@ -698,6 +719,7 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32c2 := libble BLE_IMPL_esp32c3 := esp32c3 BLE_IMPL_esp32c6 := libble + BLE_IMPL_esp32c61 := libble BLE_IMPL_esp32h2 := libble BLE_IMPL = $(BLE_IMPL_$(IDF_TARGET)) @@ -716,8 +738,8 @@ ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) ifeq ($(BLE_IMPL),libble) BINARY_BLOBS += esp-idf/components/esp_phy/lib/$(IDF_TARGET)/libbtbb.a - ifeq ($(IDF_TARGET),esp32c6) - BINARY_BLOBS += esp-idf/components/bt/controller/lib_$(IDF_TARGET)/$(IDF_TARGET)-bt-lib/$(IDF_TARGET)/libble_app.a + ifeq ($(BT_IDF_TARGET),esp32c6) + BINARY_BLOBS += esp-idf/components/bt/controller/lib_$(BT_IDF_TARGET)/$(BT_IDF_TARGET)-bt-lib/$(IDF_TARGET)/libble_app.a else BINARY_BLOBS += esp-idf/components/bt/controller/lib_$(IDF_TARGET)/$(IDF_TARGET)-bt-lib/libble_app.a endif @@ -785,6 +807,8 @@ else ifeq ($(IDF_TARGET),esp32c3) BOOTLOADER_OFFSET = 0x0 else ifeq ($(IDF_TARGET),esp32c6) BOOTLOADER_OFFSET = 0x0 +else ifeq ($(IDF_TARGET),esp32c61) +BOOTLOADER_OFFSET = 0x0 else ifeq ($(IDF_TARGET),esp32p4) BOOTLOADER_OFFSET = 0x2000 else ifeq ($(IDF_TARGET),esp32s3) diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/board.c b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.h b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.h new file mode 100644 index 00000000000..d901bfb37ba --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "ESP32-C61-DevKitC-1-N8R2" +#define MICROPY_HW_MCU_NAME "ESP32C61" + +#define DEFAULT_UART_BUS_RX (&pin_GPIO10) +#define DEFAULT_UART_BUS_TX (&pin_GPIO11) diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.mk new file mode 100644 index 00000000000..1092a874a68 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/mpconfigboard.mk @@ -0,0 +1,13 @@ +CIRCUITPY_CREATOR_ID = 0x000C303A +CIRCUITPY_CREATION_ID = 0x00C61001 + +IDF_TARGET = esp32c61 +IDF_TARGET_ARCH = riscv + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 2MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/pins.c b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/pins.c new file mode 100644 index 00000000000..901e5216657 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/pins.c @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_IO28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_IO29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/sdkconfig b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32c61_devkitc_1_n8r2/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/common-hal/analogbufio/BufferedIn.c b/ports/espressif/common-hal/analogbufio/BufferedIn.c index aac7ad28daf..20c5c060574 100644 --- a/ports/espressif/common-hal/analogbufio/BufferedIn.c +++ b/ports/espressif/common-hal/analogbufio/BufferedIn.c @@ -33,7 +33,7 @@ #elif defined(CONFIG_IDF_TARGET_ESP32S2) #define ADC_RESULT_BYTE 2 #define ADC_CONV_LIMIT_EN 0 -#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) +#elif defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32C61) #define ADC_RESULT_BYTE 4 #define ADC_CONV_LIMIT_EN 0 #elif defined(CONFIG_IDF_TARGET_ESP32S3) diff --git a/ports/espressif/common-hal/analogio/AnalogIn.c b/ports/espressif/common-hal/analogio/AnalogIn.c index b4039b3d32d..34cd5b846cf 100644 --- a/ports/espressif/common-hal/analogio/AnalogIn.c +++ b/ports/espressif/common-hal/analogio/AnalogIn.c @@ -32,6 +32,8 @@ #define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32C6) #define DATA_WIDTH ADC_BITWIDTH_12 +#elif defined(CONFIG_IDF_TARGET_ESP32C61) +#define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32P4) #define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32S2) diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index e14a3366691..922cde763e3 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -146,6 +146,29 @@ static const uint64_t pin_mask_reset_forbidden = #endif #endif // ESP32C6 + #if defined(CONFIG_IDF_TARGET_ESP32C61) + // Never ever reset pins used to communicate with SPI flash. + GPIO_SEL_15 | // SPICS0 (flash CS#) + GPIO_SEL_16 | // SPIQ (MISO/SIO1) + GPIO_SEL_17 | // SPIWP (WP#/SIO2) + GPIO_SEL_19 | // SPIHD (HOLD#/SIO3) + GPIO_SEL_20 | // SPICLK (CLK) + GPIO_SEL_21 | // SPID (MOSI/SIO0) + #if CIRCUITPY_ESP_USB_SERIAL_JTAG + // Never ever reset serial/JTAG communication pins. + GPIO_SEL_12 | // USB D- + GPIO_SEL_13 | // USB D+ + #endif + #if defined(CONFIG_SPIRAM) + GPIO_SEL_14 | // SPICS1 (PSRAM CS#); keep if PSRAM in use + #endif + #if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT && CONFIG_ESP_CONSOLE_UART_NUM == 0 + // Never reset debug UART/console pins. + GPIO_SEL_10 | + GPIO_SEL_11 | + #endif + #endif // ESP32C6 + #if defined(CONFIG_IDF_TARGET_ESP32H2) // Never ever reset pins used to communicate with the in-package SPI flash. GPIO_SEL_15 | diff --git a/ports/espressif/common-hal/microcontroller/Processor.c b/ports/espressif/common-hal/microcontroller/Processor.c index 8a6a14c0236..0056465f1c5 100644 --- a/ports/espressif/common-hal/microcontroller/Processor.c +++ b/ports/espressif/common-hal/microcontroller/Processor.c @@ -59,7 +59,7 @@ uint32_t common_hal_mcu_processor_get_frequency(void) { // If the requested frequency is not supported by the hardware, return the next lower supported frequency static uint32_t get_valid_cpu_frequency(uint32_t requested_freq_mhz) { - #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) + #if defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) uint32_t valid_cpu_frequencies[] = {20, 40, 80, 160}; #elif defined(CONFIG_IDF_TARGET_ESP32C2) uint32_t valid_cpu_frequencies[] = {20, 40, 80, 120}; @@ -126,6 +126,8 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SYS_0_REG); #elif defined(CONFIG_IDF_TARGET_ESP32C2) uint32_t mac_address_part = REG_READ(EFUSE_RD_BLK2_DATA0_REG); + #elif defined(CONFIG_IDF_TARGET_ESP32C61) + uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SYS0_REG); #else uint32_t mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_0_REG); #endif @@ -145,6 +147,8 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { mac_address_part = REG_READ(EFUSE_RD_MAC_SYS_1_REG); #elif defined(CONFIG_IDF_TARGET_ESP32C2) mac_address_part = REG_READ(EFUSE_RD_BLK2_DATA1_REG); + #elif defined(CONFIG_IDF_TARGET_ESP32C61) + mac_address_part = REG_READ(EFUSE_RD_MAC_SYS1_REG); #else mac_address_part = REG_READ(EFUSE_RD_MAC_SPI_SYS_1_REG); #endif diff --git a/ports/espressif/common-hal/microcontroller/__init__.c b/ports/espressif/common-hal/microcontroller/__init__.c index 918366b8933..d23afce4d99 100644 --- a/ports/espressif/common-hal/microcontroller/__init__.c +++ b/ports/espressif/common-hal/microcontroller/__init__.c @@ -36,6 +36,9 @@ #elif defined(CONFIG_IDF_TARGET_ESP32C6) #include "soc/lp_aon_reg.h" #include "esp32c6/rom/rtc.h" +#elif defined(CONFIG_IDF_TARGET_ESP32C61) +#include "soc/lp_aon_reg.h" +#include "esp32c61/rom/rtc.h" #elif defined(CONFIG_IDF_TARGET_ESP32P4) #include "esp32p4/rom/rtc.h" #elif defined(CONFIG_IDF_TARGET_ESP32S2) @@ -83,7 +86,7 @@ void common_hal_mcu_enable_interrupts(void) { void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { switch (runmode) { case RUNMODE_UF2: - #if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) + #if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32C61) mp_arg_error_invalid(MP_QSTR_run_mode); #else // 0x11F2 is APP_REQUEST_UF2_RESET_HINT & is defined by TinyUF2 diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c61.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c61.defaults new file mode 100644 index 00000000000..85dde905f3c --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c61.defaults @@ -0,0 +1,54 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# Bluetooth +# +CONFIG_BT_ENABLED=y +CONFIG_BT_NIMBLE_ENABLED=y +# +# NimBLE Options +# +CONFIG_BT_NIMBLE_LOG_LEVEL_NONE=y +CONFIG_BT_NIMBLE_NVS_PERSIST=y +# +# Memory Settings +# +CONFIG_BT_NIMBLE_TRANSPORT_ACL_FROM_LL_COUNT=20 +CONFIG_BT_NIMBLE_TRANSPORT_EVT_SIZE=70 +# end of Memory Settings + +CONFIG_BT_NIMBLE_EXT_ADV=y +# end of NimBLE Options + +# end of Bluetooth + +# +# Driver Configurations +# +# +# PCNT Configuration +# +CONFIG_PCNT_CTRL_FUNC_IN_IRAM=y +# end of PCNT Configuration + +# end of Driver Configurations + +# +# PHY +# +CONFIG_ESP_PHY_ENABLE_USB=y +# end of PHY + +# +# Wi-Fi +# +CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 +# end of Wi-Fi + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 712eb67f1f4..031676cf4d8 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -27,7 +27,7 @@ // Nearly all boards have this because it is used to enter the ROM bootloader. #ifndef CIRCUITPY_BOOT_BUTTON - #if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) + #if defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6) || defined(CONFIG_IDF_TARGET_ESP32H2) || defined(CONFIG_IDF_TARGET_ESP32C61) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) #elif !defined(CONFIG_IDF_TARGET_ESP32) #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index b632c5dfd6f..572e0579ef0 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -17,6 +17,9 @@ CROSS_COMPILE = riscv32-esp-elf- else ifeq ($(IDF_TARGET),esp32c6) IDF_TARGET_ARCH = riscv CROSS_COMPILE = riscv32-esp-elf- +else ifeq ($(IDF_TARGET),esp32c61) +IDF_TARGET_ARCH = riscv +CROSS_COMPILE = riscv32-esp-elf- else ifeq ($(IDF_TARGET),esp32h2) IDF_TARGET_ARCH = riscv CROSS_COMPILE = riscv32-esp-elf- @@ -201,6 +204,45 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0 CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 +#### esp32c6 ########################################################## +else ifeq ($(IDF_TARGET),esp32c61) +# Modules +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_ESPULP = 0 +CIRCUITPY_MEMORYMAP = 0 +CIRCUITPY_RGBMATRIX = 0 + +# No DAC +CIRCUITPY_AUDIOIO = 0 + +# No space for this +CIRCUITPY_AUDIOBUSIO = 0 + +# No I80 support from the IDF +CIRCUITPY_PARALLELDISPLAYBUS = 0 + +# No SDMMC +CIRCUITPY_SDIOIO = 0 + +CIRCUITPY_TOUCHIO ?= 1 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 +# Features +CIRCUITPY_USB_DEVICE = 0 +CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 + +# No TWAI on chip +CIRCUITPY_CANIO = 0 + +# No RMT on chip +CIRCUITPY_NEOPIXEL_WRITE = 0 +CIRCUITPY_PULSEIO = 0 +CIRCUITPY_RGBMATRIX = 0 + +# No PCNT on chip +CIRCUITPY_COUNTIO = 0 +CIRCUITPY_ROTARYIO = 0 +CIRCUITPY_FREQUENCYIO = 0 + #### esp32h2 ########################################################## else ifeq ($(IDF_TARGET),esp32h2) # Modules diff --git a/ports/espressif/peripherals/esp32c61/pins.c b/ports/espressif/peripherals/esp32c61/pins.c new file mode 100644 index 00000000000..a32e1e8da98 --- /dev/null +++ b/ports/espressif/peripherals/esp32c61/pins.c @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// +// SPDX-License-Identifier: MIT + +#include "peripherals/pins.h" + +const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_1, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_2, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_3, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO15 = PIN(15, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO16 = PIN(16, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO17 = PIN(17, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO18 = PIN(18, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO19 = PIN(19, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO20 = PIN(20, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO21 = PIN(21, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO22 = PIN(22, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO23 = PIN(23, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO24 = PIN(24, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO25 = PIN(25, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO26 = PIN(26, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO27 = PIN(27, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO28 = PIN(28, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); +const mcu_pin_obj_t pin_GPIO29 = PIN(29, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32c61/pins.h b/ports/espressif/peripherals/esp32c61/pins.h new file mode 100644 index 00000000000..908c9fe29f0 --- /dev/null +++ b/ports/espressif/peripherals/esp32c61/pins.h @@ -0,0 +1,72 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2023 Scott Shawcroft for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// DO NOT include this file directly. +// Use shared-bindings/microcontroller/Pin.h instead. +// This ensures that all necessary includes are already included. + +#pragma once + +#define GPIO0_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO0; +#define GPIO1_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO1; +#define GPIO2_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO2; +#define GPIO3_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO3; +#define GPIO4_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO4; +#define GPIO5_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO5; +#define GPIO6_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO6; +#define GPIO7_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO7; +#define GPIO8_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO8; +#define GPIO9_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO9; +#define GPIO10_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO10; +#define GPIO11_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO11; +#define GPIO12_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO12; +#define GPIO13_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO13; +#define GPIO14_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO14; +#define GPIO15_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO15; +#define GPIO16_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO16; +#define GPIO17_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO17; +#define GPIO18_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO18; +#define GPIO19_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO19; +#define GPIO20_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO20; +#define GPIO21_EXISTS 0 +extern const mcu_pin_obj_t pin_GPIO21; +#define GPIO22_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO22; +#define GPIO23_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO23; +#define GPIO24_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO24; +#define GPIO25_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO25; +#define GPIO26_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO26; +#define GPIO27_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO27; +#define GPIO28_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO28; +#define GPIO29_EXISTS 1 +extern const mcu_pin_obj_t pin_GPIO29; diff --git a/ports/espressif/peripherals/pins.h b/ports/espressif/peripherals/pins.h index f185cee92c4..bbe42be1bca 100644 --- a/ports/espressif/peripherals/pins.h +++ b/ports/espressif/peripherals/pins.h @@ -52,6 +52,8 @@ extern const mp_obj_type_t mcu_pin_type; #include "esp32c3/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32C6) #include "esp32c6/pins.h" +#elif defined(CONFIG_IDF_TARGET_ESP32C61) +#include "esp32c61/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32P4) #include "esp32p4/pins.h" #elif defined(CONFIG_IDF_TARGET_ESP32H2) diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 48ae29ab4f9..72c92c98bae 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -216,6 +216,11 @@ static void _never_reset_spi_ram_flash(void) { never_reset_pin_number(bootloader_flash_get_wp_pin()); } #endif // CONFIG_IDF_TARGET_ESP32 + #if defined(CONFIG_IDF_TARGET_ESP32C61) + #if defined(CONFIG_SPIRAM) + common_hal_never_reset_pin(&pin_GPIO14); + #endif + #endif } safe_mode_t port_init(void) { @@ -271,7 +276,7 @@ safe_mode_t port_init(void) { common_hal_never_reset_pin(&pin_GPIO40); common_hal_never_reset_pin(&pin_GPIO41); common_hal_never_reset_pin(&pin_GPIO42); - #elif defined(CONFIG_IDF_TARGET_ESP32P4) + #elif defined(CONFIG_IDF_TARGET_ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32C61) common_hal_never_reset_pin(&pin_GPIO3); common_hal_never_reset_pin(&pin_GPIO4); common_hal_never_reset_pin(&pin_GPIO5); diff --git a/ports/espressif/tools/build_memory_info.py b/ports/espressif/tools/build_memory_info.py index 9a3c5550138..cd9cc914271 100644 --- a/ports/espressif/tools/build_memory_info.py +++ b/ports/espressif/tools/build_memory_info.py @@ -61,6 +61,12 @@ ("LP SRAM", (0x5000_0000,), 16 * 1024), ("HP SRAM", (0x4080_0000,), 512 * 1024), ], + "esp32c61": [ + # Name, Start, Length + ("LP SRAM", (0x5000_0000,), 16 * 1024), + ("HP SRAM", (0x4080_0000,), 320 * 1024), + ("PSRAM", (0x4200_0000,), 2 * 1024 * 1024), + ], "esp32h2": [ # Name, Start, Length ("LP SRAM", (0x5000_0000,), 4 * 1024), From cdd423b01a5d7b02fd5eea19bf871fb38c28195e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 17 Sep 2025 12:02:23 -0700 Subject: [PATCH 045/876] Make string0 use configurable --- ports/espressif/mpconfigport.mk | 2 ++ py/circuitpy_defns.mk | 4 ++++ py/circuitpy_mpconfig.mk | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 572e0579ef0..f133e86c6e0 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -59,6 +59,8 @@ CIRCUITPY_PORT_SERIAL = 1 CIRCUITPY_LIB_TLSF = 0 +CIRCUITPY_LIBC_STRING0 = 0 + # These modules are implemented in ports//common-hal: CIRCUITPY__EVE ?= 1 CIRCUITPY_ALARM ?= 1 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index f3d25f6270c..f4ac2350ffb 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -1003,6 +1003,10 @@ SRC_CIRCUITPY_COMMON = \ shared/runtime/stdout_helpers.c \ shared/runtime/sys_stdio_mphal.c +ifeq ($(CIRCUITPY_LIBC_STRING0),1) +SRC_CIRCUITPY_COMMON += shared/libc/string0.c +endif + ifeq ($(CIRCUITPY_QRIO),1) SRC_CIRCUITPY_COMMON += lib/quirc/lib/decode.c lib/quirc/lib/identify.c lib/quirc/lib/quirc.c lib/quirc/lib/version_db.c $(BUILD)/lib/quirc/lib/%.o: CFLAGS += -Wno-type-limits -Wno-shadow -Wno-sign-compare -include shared-module/qrio/quirc_alloc.h diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 76ee8a1d72b..09ef4361427 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -66,6 +66,11 @@ CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 9 # implementation of TLSF, which can be used instead by setting CIRCUITPY_LIB_TLSF=0. CIRCUITPY_LIB_TLSF ?= 1 +# By default, use our copy of string0 (memcpy and friends) because it is optimized. Some vendor SDKs +# or ROMs may provide their own implementation of string0, which can be used instead by setting +# CIRCUITPY_LIBC_STRING0=0. +CIRCUITPY_LIBC_STRING0 ?= 1 + # Reduce the size of in-flash properties. Requires support in the .ld linker # file, so not enabled by default. CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 0 From 6ebd5bbfa31965b14a78d95b14ede21c362d31be Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 23 Sep 2025 11:16:15 -0700 Subject: [PATCH 046/876] Fix PID check and C3 build --- ports/espressif/Makefile | 1 + tools/ci_check_duplicate_usb_vid_pid.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 930cdd96182..0f3ff1ca708 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -277,6 +277,7 @@ CHIP_COMPONENTS = \ else ifeq ($(IDF_TARGET),esp32c3) LDFLAGS += \ -Tesp32c3.rom.newlib.ld \ + -Tesp32c3.rom.libc.ld \ -Tesp32c3.rom.version.ld \ -Tesp32c3.rom.eco3_bt_funcs.ld \ -Tesp32c3.rom.eco3.ld \ diff --git a/tools/ci_check_duplicate_usb_vid_pid.py b/tools/ci_check_duplicate_usb_vid_pid.py index 5361914af19..38cce0f28be 100644 --- a/tools/ci_check_duplicate_usb_vid_pid.py +++ b/tools/ci_check_duplicate_usb_vid_pid.py @@ -104,7 +104,7 @@ def check_vid_pid(files, clusterlist): """ usb_pattern = re.compile( - r"^CIRCUITPY_USB_DEVICE\s*=\s*0$|^IDF_TARGET = (esp32|esp32c2|esp32c3|esp32c6|esp32h2|esp32p4)$|^MCU_SERIES = MG24$", + r"^CIRCUITPY_USB_DEVICE\s*=\s*0$|^IDF_TARGET = (esp32|esp32c2|esp32c3|esp32c5|esp32c6|esp32c61|esp32h2|esp32p4)$|^MCU_SERIES = MG24$", flags=re.M, ) From 680fb207d141afe784ca0976ee27dcaa51e3b566 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 23 Sep 2025 15:31:15 -0700 Subject: [PATCH 047/876] Limit cryptography version to IDF limit --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 261a5cc2c7f..fb931079c52 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -25,7 +25,7 @@ intelhex # for building & testing natmods pyelftools -cryptography +cryptography<45 # for web workflow minify minify_html From 8190b409d20cfa8a10b06299d9b45908aa173d51 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 23 Sep 2025 16:15:32 -0700 Subject: [PATCH 048/876] Make room of IDF in S2 RTC slow memory --- ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults index 5c748bd0e6f..101f90f9fa4 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults @@ -55,7 +55,7 @@ CONFIG_ULP_COPROC_ENABLED=y CONFIG_ULP_COPROC_TYPE_FSM=y CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only works due to a modification of adafruit/esp-idf # (see adafruit/esp-idf/pull/16) until espressif/esp-idf/issues/12999 is fixed. -CONFIG_ULP_COPROC_RESERVE_MEM=8176 +CONFIG_ULP_COPROC_RESERVE_MEM=8144 # end of Ultra Low Power (ULP) Co-processor # From 2fd8589e2876adffa69f647ace904f3818e4e39e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 24 Sep 2025 12:04:59 -0700 Subject: [PATCH 049/876] Fix C2, H2 and S3 builds --- ports/espressif/Makefile | 8 ++++++-- ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 0f3ff1ca708..b759fe3c005 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -205,7 +205,6 @@ CFLAGS += $(INC) -Werror -Wall -std=gnu11 -Wl,--gc-sections $(BASE_CFLAGS) $(C_D # Most current ESPs have nano versions of newlib in ROM so we use them. ifneq ($(IDF_TARGET),esp32c6) CFLAGS += --specs=nano.specs - LDFLAGS += -T$(IDF_TARGET).rom.newlib-nano.ld else LDFLAGS += -T$(IDF_TARGET).rom.newlib-normal.ld endif @@ -264,7 +263,9 @@ else ifeq ($(IDF_TARGET),esp32c2) LDFLAGS += \ -Tesp32c2.rom.ble.ld \ -Tesp32c2.rom.heap.ld \ + -Tesp32c2.rom.libc.ld \ -Tesp32c2.rom.newlib.ld \ + -Tesp32c2.rom.newlib-nano.ld \ -Tesp32c2.rom.version.ld \ -Tesp32c2.rom.systimer.ld \ -Tesp32c2.rom.wdt.ld @@ -321,6 +322,7 @@ CHIP_COMPONENTS = \ else ifeq ($(IDF_TARGET),esp32p4) LDFLAGS += \ + -Tesp32p4.rom.libc.ld \ -Tesp32p4.rom.newlib.ld \ -Tesp32p4.rom.systimer.ld \ -Tesp32p4.rom.wdt.ld @@ -332,6 +334,7 @@ CHIP_COMPONENTS = \ else ifeq ($(IDF_TARGET),esp32h2) LDFLAGS += \ -Tesp32h2.rom.heap.ld \ + -Tesp32h2.rom.libc.ld \ -Tesp32h2.rom.newlib.ld \ -Tesp32h2.rom.systimer.ld \ -Tesp32h2.rom.wdt.ld @@ -352,6 +355,7 @@ CHIP_COMPONENTS = \ else ifeq ($(IDF_TARGET),esp32s3) LDFLAGS += \ + -Tesp32s3.rom.libc.ld \ -Tesp32s3.rom.newlib.ld \ -Tesp32s3.rom.version.ld \ -Tesp32s3.rom.systimer.ld \ @@ -712,7 +716,7 @@ ifneq ($(NEEDS_COEX),0) ESP_IDF_COMPONENTS_LINK += esp_coex endif ifneq ($(CIRCUITPY_WIFI),0) - ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy + ESP_IDF_COMPONENTS_LINK += esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy endif ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32 := esp32 diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults index fe3c3e0a2da..2553c648018 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults @@ -95,7 +95,7 @@ CONFIG_ULP_COPROC_ENABLED=y CONFIG_ULP_COPROC_TYPE_FSM=y CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only works due to a modification of adafruit/esp-idf # (see adafruit/esp-idf/pull/16) until espressif/esp-idf/issues/12999 is fixed. -CONFIG_ULP_COPROC_RESERVE_MEM=8176 +CONFIG_ULP_COPROC_RESERVE_MEM=8144 # end of Ultra Low Power (ULP) Co-processor # end of Component config From 4ea6bb7b3b929d8fb69391072fbe6f958cd8abca Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 24 Sep 2025 16:21:56 -0700 Subject: [PATCH 050/876] Tweak coex inclusion --- ports/espressif/Makefile | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index b759fe3c005..ed744da878a 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -709,14 +709,13 @@ BINARY_BLOBS += esp-idf/components/esp_phy/lib/$(IDF_TARGET)/librtc.a endif ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console -NEEDS_COEX = $(CIRCUITPY_BLEIO_NATIVE) + $(CIRCUITPY_WIFI) -ifneq ($(NEEDS_COEX),0) - # esp_system_include_startup_funcs requires coexist as well BT regardless of wifi - BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a - ESP_IDF_COMPONENTS_LINK += esp_coex -endif ifneq ($(CIRCUITPY_WIFI),0) ESP_IDF_COMPONENTS_LINK += esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy + ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) + # esp_system_include_startup_funcs requires coexist as well BT regardless of wifi + BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a + ESP_IDF_COMPONENTS_LINK += esp_coex + endif endif ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32 := esp32 From 40620146f4d8a8dd7eb82e5b82ea1b8ed46f798b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 25 Sep 2025 16:37:39 -0700 Subject: [PATCH 051/876] Tweak coex inclusion (again). The wrapper is always needed with wifi. --- ports/espressif/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index ed744da878a..4fbcd62bdc3 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -710,11 +710,9 @@ endif ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console ifneq ($(CIRCUITPY_WIFI),0) - ESP_IDF_COMPONENTS_LINK += esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy + ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) - # esp_system_include_startup_funcs requires coexist as well BT regardless of wifi BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a - ESP_IDF_COMPONENTS_LINK += esp_coex endif endif ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) From fec20467062c723e31d90bf308b4b0778a26fc0c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 26 Sep 2025 10:32:32 -0700 Subject: [PATCH 052/876] Formatting --- ports/espressif/common-hal/alarm/pin/PinAlarm.c | 8 ++++++-- ports/espressif/tools/build_memory_info.py | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ports/espressif/common-hal/alarm/pin/PinAlarm.c b/ports/espressif/common-hal/alarm/pin/PinAlarm.c index 2b09c630925..97ad3b2a942 100644 --- a/ports/espressif/common-hal/alarm/pin/PinAlarm.c +++ b/ports/espressif/common-hal/alarm/pin/PinAlarm.c @@ -384,8 +384,12 @@ void alarm_pin_pinalarm_set_alarms(bool deep_sleep, size_t n_alarms, const mp_ob ESP_ERROR_CHECK(gpio_set_pull_mode(pin, GPIO_FLOATING)); } gpio_int_type_t intr = GPIO_INTR_DISABLE; - if (high) intr = GPIO_INTR_HIGH_LEVEL; - if (low) intr = GPIO_INTR_LOW_LEVEL; + if (high) { + intr = GPIO_INTR_HIGH_LEVEL; + } + if (low) { + intr = GPIO_INTR_LOW_LEVEL; + } never_reset_pin_number(pin); gpio_wakeup_enable(pin, intr); gpio_set_intr_type(pin, intr); diff --git a/ports/espressif/tools/build_memory_info.py b/ports/espressif/tools/build_memory_info.py index cd9cc914271..0cf609c4d63 100644 --- a/ports/espressif/tools/build_memory_info.py +++ b/ports/espressif/tools/build_memory_info.py @@ -65,7 +65,7 @@ # Name, Start, Length ("LP SRAM", (0x5000_0000,), 16 * 1024), ("HP SRAM", (0x4080_0000,), 320 * 1024), - ("PSRAM", (0x4200_0000,), 2 * 1024 * 1024), + ("PSRAM", (0x4200_0000,), 2 * 1024 * 1024), ], "esp32h2": [ # Name, Start, Length From c493f1b48054c74f99811c71686ecca0481db18e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 26 Sep 2025 11:01:15 -0700 Subject: [PATCH 053/876] Always link coex with wifi. Shrink 2M C3 --- ports/espressif/Makefile | 4 +--- ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 4fbcd62bdc3..b6ddc27e408 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -699,6 +699,7 @@ ifneq ($(IDF_TARGET),esp32p4) endif ifneq ($(CIRCUITPY_WIFI),0) BINARY_BLOBS += $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, $(BINARY_WIFI_BLOBS)) + BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a ifneq ($(IDF_TARGET),esp32c2) BINARY_BLOBS += $(addprefix esp-idf/components/esp_wifi/lib/$(IDF_TARGET)/, libmesh.a libwapi.a) endif @@ -711,9 +712,6 @@ endif ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console ifneq ($(CIRCUITPY_WIFI),0) ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy - ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) - BINARY_BLOBS += esp-idf/components/esp_coex/lib/$(IDF_TARGET)/libcoexist.a - endif endif ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) BLE_IMPL_esp32 := esp32 diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig index e9628662160..15b64d0ce2e 100644 --- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig +++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig @@ -9,6 +9,11 @@ # # end of LWIP +# +# Wireless Coexistence +# +# CONFIG_ESP_COEX_SW_COEXIST_ENABLE is not set +# end of Wireless Coexistence # end of Component config # end of Espressif IoT Development Framework Configuration From b0f3a238f820a15e8541aced8c27edcae294395c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 26 Sep 2025 15:52:06 -0700 Subject: [PATCH 054/876] Disable memory speed optimization on 2m board. Also disable dynamic log level on opt builds --- .../boards/ai_thinker_esp32-c3s-2m/sdkconfig | 7 +++++++ .../esp-idf-config/sdkconfig-opt.defaults | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig index 15b64d0ce2e..5fd531f274a 100644 --- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig +++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig @@ -14,6 +14,13 @@ # # CONFIG_ESP_COEX_SW_COEXIST_ENABLE is not set # end of Wireless Coexistence + +# +# LibC +# +# CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS is not set +# end of LibC + # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-opt.defaults b/ports/espressif/esp-idf-config/sdkconfig-opt.defaults index 16f5b990386..0da23e81227 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-opt.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-opt.defaults @@ -38,6 +38,24 @@ CONFIG_ESP_CONSOLE_SECONDARY_NONE=y CONFIG_LOG_DEFAULT_LEVEL_NONE=y # end of Log output +# +# Log +# +# +# Log Level +# +# +# Level Settings +# +# CONFIG_LOG_DYNAMIC_LEVEL_CONTROL is not set +CONFIG_LOG_TAG_LEVEL_IMPL_NONE=y +# CONFIG_LOG_TAG_LEVEL_IMPL_CACHE_AND_LINKED_LIST is not set +# end of Level Settings + +# end of Log Level + +# end of Log + # end of Component config # end of Espressif IoT Development Framework Configuration From 9dbe0d1aa886114eb334b5ecbd3b93f091782bf6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 6 Oct 2025 11:49:39 -0700 Subject: [PATCH 055/876] Don't duplicate USB callbacks. --- lib/tinyusb | 2 +- ports/espressif/supervisor/usb.c | 25 ----------------------- ports/espressif/tools/decode_backtrace.py | 2 +- supervisor/shared/usb/usb_device.c | 10 +++++++++ 4 files changed, 12 insertions(+), 27 deletions(-) diff --git a/lib/tinyusb b/lib/tinyusb index 8304587d777..c1bf19ed6cf 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 8304587d7774526a03c6881d11e6d6208fe759be +Subproject commit c1bf19ed6cf1eaa791f221c1bc5ce4b3d069f76d diff --git a/ports/espressif/supervisor/usb.c b/ports/espressif/supervisor/usb.c index 612abaa808a..274542ef22a 100644 --- a/ports/espressif/supervisor/usb.c +++ b/ports/espressif/supervisor/usb.c @@ -54,31 +54,6 @@ static void usb_device_task(void *param) { vTaskDelay(1); } } - -/** - * Callback invoked when received an "wanted" char. - * @param itf Interface index (for multiple cdc interfaces) - * @param wanted_char The wanted char (set previously) - */ -void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { - (void)itf; // not used - // CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB. - // So, we must notify the other task when a CTRL-C is received. - port_wake_main_task(); - // Workaround for using shared/runtime/interrupt_char.c - // Compare mp_interrupt_char with wanted_char and ignore if not matched - if (mp_interrupt_char == wanted_char) { - tud_cdc_read_flush(); // flush read fifo - mp_sched_keyboard_interrupt(); - } -} - -void tud_cdc_rx_cb(uint8_t itf) { - (void)itf; - // Workaround for "press any key to enter REPL" response being delayed on espressif. - // Wake main task when any key is pressed. - port_wake_main_task(); -} #endif // CIRCUITPY_USB_DEVICE void init_usb_hardware(void) { diff --git a/ports/espressif/tools/decode_backtrace.py b/ports/espressif/tools/decode_backtrace.py index 1733c69b5bb..d597741a596 100644 --- a/ports/espressif/tools/decode_backtrace.py +++ b/ports/espressif/tools/decode_backtrace.py @@ -24,7 +24,7 @@ addresses = addresses[len("Backtrace:") :] addresses = addresses.strip().split() addresses = [address.split(":")[0] for address in addresses] - if addresses.startswith("Stack memory:"): + elif addresses.startswith("Stack memory:"): addresses = [] extra_lines = sys.stdin.readlines() for line in extra_lines: diff --git a/supervisor/shared/usb/usb_device.c b/supervisor/shared/usb/usb_device.c index ec08b8bf4d7..16ae137edde 100644 --- a/supervisor/shared/usb/usb_device.c +++ b/supervisor/shared/usb/usb_device.c @@ -166,6 +166,9 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ * @param wanted_char The wanted char (set previously) */ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { + // CircuitPython's VM is run in a separate FreeRTOS task from TinyUSB on ESP. + // So, we must notify the other task when a CTRL-C is received. + port_wake_main_task(); // Workaround for using shared/runtime/interrupt_char.c // Compare mp_interrupt_char with wanted_char and ignore if not matched if (mp_interrupt_char == wanted_char) { @@ -177,7 +180,14 @@ void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) { void tud_cdc_send_break_cb(uint8_t itf, uint16_t duration_ms) { if (usb_cdc_console_enabled() && mp_interrupt_char != -1 && itf == 0 && duration_ms > 0) { mp_sched_keyboard_interrupt(); + port_wake_main_task(); } } +void tud_cdc_rx_cb(uint8_t itf) { + (void)itf; + // Workaround for "press any key to enter REPL" response being delayed on espressif. + // Wake main task when any key is pressed. + port_wake_main_task(); +} #endif From 802380d381f44583355e6fbc292a2a30e0140a7b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 6 Oct 2025 19:01:50 -0400 Subject: [PATCH 056/876] py/misc.h: prevent clang warning --- py/misc.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/py/misc.h b/py/misc.h index eb7fc54be6f..555e58dd14f 100644 --- a/py/misc.h +++ b/py/misc.h @@ -54,7 +54,14 @@ typedef unsigned int uint; #define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x) // Static assertion macro +#if __cplusplus +#define MP_STATIC_ASSERT(cond) static_assert((cond), #cond) +#elif __GNUC__ >= 5 || __STDC_VERSION__ >= 201112L +#define MP_STATIC_ASSERT(cond) _Static_assert((cond), #cond) +#else #define MP_STATIC_ASSERT(cond) ((void)sizeof(char[1 - 2 * !(cond)])) +#endif + // In C++ things like comparing extern const pointers are not constant-expressions so cannot be used // in MP_STATIC_ASSERT. Note that not all possible compiler versions will reject this. Some gcc versions // do, others only with -Werror=vla, msvc always does. @@ -63,7 +70,10 @@ typedef unsigned int uint; #if defined(_MSC_VER) || defined(__cplusplus) #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)1) #else -#define MP_STATIC_ASSERT_NONCONSTEXPR(cond) MP_STATIC_ASSERT(cond) +#if __clang__ +#pragma GCC diagnostic ignored "-Wgnu-folding-constant" +#endif +#define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)sizeof(char[1 - 2 * !(cond)])) #endif // Round-up integer division From 2e1c6169c1e44d8859f2f0d3b9adb62aa3a84134 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 6 Oct 2025 20:40:21 -0400 Subject: [PATCH 057/876] py/misc.h: test for __cplusplus and __clang__ more carefully --- py/misc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/py/misc.h b/py/misc.h index 555e58dd14f..22f32147124 100644 --- a/py/misc.h +++ b/py/misc.h @@ -54,7 +54,7 @@ typedef unsigned int uint; #define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x) // Static assertion macro -#if __cplusplus +#if defined(__cplusplus) #define MP_STATIC_ASSERT(cond) static_assert((cond), #cond) #elif __GNUC__ >= 5 || __STDC_VERSION__ >= 201112L #define MP_STATIC_ASSERT(cond) _Static_assert((cond), #cond) @@ -70,7 +70,7 @@ typedef unsigned int uint; #if defined(_MSC_VER) || defined(__cplusplus) #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)1) #else -#if __clang__ +#if defined(__clang__) #pragma GCC diagnostic ignored "-Wgnu-folding-constant" #endif #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)sizeof(char[1 - 2 * !(cond)])) From d5d6a8ef97fed4850a76c5bc0247a212c7304400 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 7 Oct 2025 11:04:57 -0400 Subject: [PATCH 058/876] use MP_STATIC_ASSERT_NONCONSTEXPR in ports/analog --- ports/analog/common-hal/digitalio/DigitalInOut.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/analog/common-hal/digitalio/DigitalInOut.c b/ports/analog/common-hal/digitalio/DigitalInOut.c index 7d4048d77e7..93e2242fbb6 100644 --- a/ports/analog/common-hal/digitalio/DigitalInOut.c +++ b/ports/analog/common-hal/digitalio/DigitalInOut.c @@ -107,7 +107,7 @@ digitalio_direction_t common_hal_digitalio_digitalinout_get_direction( if (self->pin->port < 4) { // Check that I/O mode is enabled and we don't have in AND out on at the same time - MP_STATIC_ASSERT(!((port->en0 & mask) && (port->inen & mask) && (port->outen & mask))); + MP_STATIC_ASSERT_NONCONSTEXPR(!((port->en0 & mask) && (port->inen & mask) && (port->outen & mask))); if ((port->en0 & mask) && (port->outen & mask)) { return DIRECTION_OUTPUT; From e2cbc2db3d4a3be0e9600e935339081be212f9f0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 7 Oct 2025 16:45:51 -0400 Subject: [PATCH 059/876] Fix filesystem writability from USB --- extmod/vfs.h | 2 ++ extmod/vfs_fat.c | 11 ++++------- extmod/vfs_fat_diskio.c | 6 +++++- main.c | 18 +++++++++++------- supervisor/filesystem.h | 1 + supervisor/shared/filesystem.c | 14 ++++++++++++-- supervisor/shared/usb/usb_msc_flash.c | 2 +- 7 files changed, 36 insertions(+), 18 deletions(-) diff --git a/extmod/vfs.h b/extmod/vfs.h index 67d5d9239a3..699232e56cd 100644 --- a/extmod/vfs.h +++ b/extmod/vfs.h @@ -52,6 +52,8 @@ #define MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED (0x0020) // Bit set when something has claimed the right to mutate the blockdev. #define MP_BLOCKDEV_FLAG_LOCKED (0x0040) +// Ignore write protections. Used to override other flags temporarily. +#define MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION (0x0080) // constants for block protocol ioctl #define MP_BLOCKDEV_IOCTL_INIT (1) diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 5011a820af8..6267452cd32 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -427,13 +427,10 @@ static MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_statvfs_obj, fat_vfs_statvfs); static mp_obj_t vfs_fat_mount(mp_obj_t self_in, mp_obj_t readonly, mp_obj_t mkfs) { fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); - // Read-only device indicated by writeblocks[0] == MP_OBJ_NULL. - // User can specify read-only device by: - // 1. readonly=True keyword argument - // 2. nonexistent writeblocks method (then writeblocks[0] == MP_OBJ_NULL already) - if (mp_obj_is_true(readonly)) { - self->blockdev.writeblocks[0] = MP_OBJ_NULL; - } + // CIRCUITPY-CHANGE: Use MP_BLOCKDEV_FLAG_USB_WRITABLE instead of writeblocks[0] =/!= MP_OBJ_NULL + // to specify read-write. + // If readonly to Python, it's writable by USB and vice versa. + filesystem_set_writable_by_usb(self, mp_obj_is_true(readonly)); // check if we need to make the filesystem FRESULT res = (self->blockdev.flags & MP_BLOCKDEV_FLAG_NO_FILESYSTEM) ? FR_NO_FILESYSTEM : FR_OK; diff --git a/extmod/vfs_fat_diskio.c b/extmod/vfs_fat_diskio.c index 6f500104d1e..591da07eb56 100644 --- a/extmod/vfs_fat_diskio.c +++ b/extmod/vfs_fat_diskio.c @@ -43,6 +43,9 @@ #include "lib/oofatfs/diskio.h" #include "extmod/vfs_fat.h" +// CIRCUITPY-CHANGE +#include "supervisor/filesystem.h" + typedef void *bdev_t; static fs_user_mount_t *disk_get_device(void *bdev) { return (fs_user_mount_t *)bdev; @@ -153,7 +156,8 @@ DRESULT disk_ioctl( if (ret != mp_const_none && MP_OBJ_SMALL_INT_VALUE(ret) != 0) { // error initialising stat = STA_NOINIT; - } else if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL) { + // CIRCUITPY-CHANGE: writability from Python check + } else if (!filesystem_is_writable_by_python(vfs)) { stat = STA_PROTECT; } else { stat = 0; diff --git a/main.c b/main.c index d7f3c7aaf1b..91687ff2f8b 100644 --- a/main.c +++ b/main.c @@ -863,6 +863,14 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { boot_output = &boot_text; #endif + // Get the base filesystem. + fs_user_mount_t *vfs = filesystem_circuitpy(); + FATFS *fs = &vfs->fatfs; + + // Allow boot.py access to CIRCUITPY, and allow writes to boot_out.txt. + // We can't use the regular flags for this, because they might get modified inside boot.py. + filesystem_set_ignore_write_protection(vfs, true); + // Write version info mp_printf(&mp_plat_print, "%s\nBoard ID:%s\n", MICROPY_FULL_VERSION_INFO, CIRCUITPY_BOARD_ID); #if CIRCUITPY_MICROCONTROLLER && COMMON_HAL_MCU_PROCESSOR_UID_LENGTH > 0 @@ -881,10 +889,6 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { #ifdef CIRCUITPY_BOOT_OUTPUT_FILE - // Get the base filesystem. - fs_user_mount_t *vfs = filesystem_circuitpy(); - FATFS *fs = &vfs->fatfs; - boot_output = NULL; #if CIRCUITPY_STATUS_BAR supervisor_status_bar_resume(); @@ -906,9 +910,6 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { // in case power is momentary or will fail shortly due to, say a low, battery. mp_hal_delay_ms(1000); - // USB isn't up, so we can write the file. - // operating at the oofatfs (f_open) layer means the usb concurrent write permission - // is not even checked! f_open(fs, &boot_output_file, CIRCUITPY_BOOT_OUTPUT_FILE, FA_WRITE | FA_CREATE_ALWAYS); UINT chars_written; f_write(&boot_output_file, boot_text.buf, boot_text.len, &chars_written); @@ -916,6 +917,9 @@ static void __attribute__ ((noinline)) run_boot_py(safe_mode_t safe_mode) { filesystem_flush(); } #endif + + // Back to regular filesystem protections. + filesystem_set_ignore_write_protection(vfs, false); } cleanup_after_vm(_exec_result.exception); diff --git a/supervisor/filesystem.h b/supervisor/filesystem.h index a0445b0510d..30cd83d4438 100644 --- a/supervisor/filesystem.h +++ b/supervisor/filesystem.h @@ -21,6 +21,7 @@ void filesystem_set_internal_writable_by_usb(bool usb_writable); void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection); void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable); void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concurrent_write_protection); +void filesystem_set_ignore_write_protection(fs_user_mount_t *vfs, bool ignore_write_protection); // Whether user code can modify the filesystem. It doesn't depend on the state // of USB. Don't use this for a workflow. In workflows, grab the shared file diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 24c7f9bffc5..025c9ddbd6d 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -248,12 +248,14 @@ void filesystem_set_writable_by_usb(fs_user_mount_t *vfs, bool usb_writable) { bool filesystem_is_writable_by_python(fs_user_mount_t *vfs) { return ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0) || - ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) == 0); + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) == 0) || + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION) != 0); } bool filesystem_is_writable_by_usb(fs_user_mount_t *vfs) { return ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_CONCURRENT_WRITE_PROTECTED) == 0) || - ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) != 0); + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_USB_WRITABLE) != 0) || + ((vfs->blockdev.flags & MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION) != 0); } void filesystem_set_internal_concurrent_write_protection(bool concurrent_write_protection) { @@ -268,6 +270,14 @@ void filesystem_set_concurrent_write_protection(fs_user_mount_t *vfs, bool concu } } +void filesystem_set_ignore_write_protection(fs_user_mount_t *vfs, bool ignore_write_protection) { + if (ignore_write_protection) { + vfs->blockdev.flags |= MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION; + } else { + vfs->blockdev.flags &= ~MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION; + } +} + bool filesystem_present(void) { return _circuitpy_vfs.len > 0; } diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index e4e4801de9c..febede876bb 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -249,7 +249,7 @@ bool tud_msc_is_writable_cb(uint8_t lun) { if (vfs == NULL) { return false; } - if (vfs->blockdev.writeblocks[0] == MP_OBJ_NULL || !filesystem_is_writable_by_usb(vfs)) { + if (!filesystem_is_writable_by_usb(vfs)) { return false; } // Lock the blockdev once we say we're writable. From a6a6ebe5892343e59056b0178c3369cb1ac4505d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 7 Oct 2025 17:03:16 -0700 Subject: [PATCH 060/876] Fix C6 by disabling hardware SHA --- ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults index 85dde905f3c..63f42cac952 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c6.defaults @@ -49,6 +49,12 @@ CONFIG_ESP_PHY_ENABLE_USB=y CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 # end of Wi-Fi +# +# mbedTLS +# +# CONFIG_MBEDTLS_HARDWARE_SHA is not set +# end of mbedTLS + # end of Component config # end of Espressif IoT Development Framework Configuration From a55305eae9aebfecff91410951eecafbe1f505f9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 9 Oct 2025 12:32:08 -0400 Subject: [PATCH 061/876] new location of importlib Traversable --- tools/board_stubs/circuitpython_setboard/__init__.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/board_stubs/circuitpython_setboard/__init__.py b/tools/board_stubs/circuitpython_setboard/__init__.py index 3a73beb3119..69a405405b8 100644 --- a/tools/board_stubs/circuitpython_setboard/__init__.py +++ b/tools/board_stubs/circuitpython_setboard/__init__.py @@ -12,7 +12,12 @@ import shutil from collections import defaultdict from importlib import resources -from importlib.abc import Traversable + +try: + from importlib.resources.abc import Traversable +except ModuleNotFoundError: + # 3.10 and earlier. + from importlib.abc import Traversable def get_definitions_or_exit(board: str) -> Traversable: From 6a1a59b84d8d3d8d2a766d898e88d0d87c11cf18 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Oct 2025 11:48:13 -0500 Subject: [PATCH 062/876] docs: add TilePaletteMapper to pixel_shader allowed types. --- shared-bindings/displayio/TileGrid.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index eddf3f66c4e..560fb66a675 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -49,7 +49,7 @@ void displayio_tilegrid_validate_pixel_shader(mp_obj_t pixel_shader) { //| self, //| bitmap: Union[Bitmap, OnDiskBitmap], //| *, -//| pixel_shader: Union[ColorConverter, Palette], +//| pixel_shader: Union[ColorConverter, Palette, tilepalettemapper.TilePaletteMapper], //| width: int = 1, //| height: int = 1, //| tile_width: Optional[int] = None, @@ -68,7 +68,7 @@ void displayio_tilegrid_validate_pixel_shader(mp_obj_t pixel_shader) { //| tile_width and tile_height match the height of the bitmap by default. //| //| :param Bitmap,OnDiskBitmap bitmap: The bitmap storing one or more tiles. -//| :param ColorConverter,Palette pixel_shader: The pixel shader that produces colors from values +//| :param ColorConverter,Palette,tilepalettemapper.TilePaletteMapper pixel_shader: The pixel shader that produces colors from values //| :param int width: Width of the grid in tiles. //| :param int height: Height of the grid in tiles. //| :param int tile_width: Width of a single tile in pixels. Defaults to the full Bitmap and must evenly divide into the Bitmap's dimensions. @@ -330,7 +330,7 @@ static mp_obj_t displayio_tilegrid_obj_contains(mp_obj_t self_in, mp_obj_t touch } MP_DEFINE_CONST_FUN_OBJ_2(displayio_tilegrid_contains_obj, displayio_tilegrid_obj_contains); -//| pixel_shader: Union[ColorConverter, Palette] +//| pixel_shader: Union[ColorConverter, Palette, tilepalettemapper.TilePaletteMapper] //| """The pixel shader of the tilegrid.""" static mp_obj_t displayio_tilegrid_obj_get_pixel_shader(mp_obj_t self_in) { displayio_tilegrid_t *self = native_tilegrid(self_in); From 611b887a8113c71a504a1893ac8b07f64f55c058 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 15 Oct 2025 11:09:57 -0400 Subject: [PATCH 063/876] Fix SPI DMA on SAMD --- ports/atmel-samd/audio_dma.c | 18 ++++++------- .../atmel-samd/common-hal/audiobusio/PDMIn.c | 2 +- ports/atmel-samd/common-hal/busio/SPI.c | 27 ++++++++++--------- .../imagecapture/ParallelImageCapture.c | 3 ++- .../common-hal/spitarget/SPITarget.c | 10 +++---- .../common-hal/spitarget/SPITarget.h | 2 +- ports/atmel-samd/peripherals | 2 +- 7 files changed, 34 insertions(+), 30 deletions(-) diff --git a/ports/atmel-samd/audio_dma.c b/ports/atmel-samd/audio_dma.c index e25b74d9a28..e3980401506 100644 --- a/ports/atmel-samd/audio_dma.c +++ b/ports/atmel-samd/audio_dma.c @@ -39,14 +39,14 @@ uint8_t find_sync_event_channel_raise(void) { } void audio_dma_disable_channel(uint8_t channel) { - if (channel >= AUDIO_DMA_CHANNEL_COUNT) { + if (channel == NO_DMA_CHANNEL) { return; } dma_disable_channel(channel); } void audio_dma_enable_channel(uint8_t channel) { - if (channel >= AUDIO_DMA_CHANNEL_COUNT) { + if (channel == NO_DMA_CHANNEL) { return; } dma_enable_channel(channel); @@ -171,8 +171,8 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma, bool output_signed, uint32_t output_register_address, uint8_t dma_trigger_source) { - uint8_t dma_channel = dma_allocate_channel(true); - if (dma_channel >= AUDIO_DMA_CHANNEL_COUNT) { + uint8_t dma_channel = dma_allocate_audio_channel(); + if (dma_channel == NO_DMA_CHANNEL) { return AUDIO_DMA_DMA_BUSY; } @@ -298,14 +298,14 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma, void audio_dma_stop(audio_dma_t *dma) { uint8_t channel = dma->dma_channel; - if (channel < AUDIO_DMA_CHANNEL_COUNT) { + if (channel != NO_DMA_CHANNEL) { audio_dma_disable_channel(channel); disable_event_channel(dma->event_channel); MP_STATE_PORT(playing_audio)[channel] = NULL; audio_dma_state[channel] = NULL; dma_free_channel(dma->dma_channel); } - dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT; + dma->dma_channel = NO_DMA_CHANNEL; dma->playing_in_progress = false; } @@ -318,7 +318,7 @@ void audio_dma_resume(audio_dma_t *dma) { } bool audio_dma_get_paused(audio_dma_t *dma) { - if (dma->dma_channel >= AUDIO_DMA_CHANNEL_COUNT) { + if (dma->dma_channel == NO_DMA_CHANNEL) { return false; } uint32_t status = dma_transfer_status(dma->dma_channel); @@ -327,7 +327,7 @@ bool audio_dma_get_paused(audio_dma_t *dma) { } void audio_dma_init(audio_dma_t *dma) { - dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT; + dma->dma_channel = NO_DMA_CHANNEL; } void audio_dma_reset(void) { @@ -341,7 +341,7 @@ void audio_dma_reset(void) { } bool audio_dma_get_playing(audio_dma_t *dma) { - if (dma->dma_channel >= AUDIO_DMA_CHANNEL_COUNT) { + if (dma->dma_channel == NO_DMA_CHANNEL) { return false; } return dma->playing_in_progress; diff --git a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c index a1a67d04082..f409563f5ed 100644 --- a/ports/atmel-samd/common-hal/audiobusio/PDMIn.c +++ b/ports/atmel-samd/common-hal/audiobusio/PDMIn.c @@ -364,7 +364,7 @@ static uint16_t filter_sample(uint32_t pdm_samples[4]) { // output_buffer_length is the number of slots, not the number of bytes. uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self, uint16_t *output_buffer, uint32_t output_buffer_length) { - uint8_t dma_channel = dma_allocate_channel(true); + uint8_t dma_channel = dma_allocate_audio_channel(); pdmin_event_channel = find_sync_event_channel_raise(); pdmin_dma_block_done = false; diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index 5d7633be7f8..5dd7bedebc3 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -21,7 +21,17 @@ #include "samd/dma.h" #include "samd/sercom.h" -void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux); + +static void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux, const enum gpio_direction direction) { + gpio_set_pin_direction(pin->number, direction); + gpio_set_pin_pull_mode(pin->number, GPIO_PULL_OFF); + gpio_set_pin_function(pin->number, pinmux); + if (direction == GPIO_DIRECTION_OUT) { + // Use strong drive strength for SPI outputs. + hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin->number), GPIO_PIN(pin->number)); + } + claim_pin(pin); +} void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, @@ -128,6 +138,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Pads must be set after spi_m_sync_init(), which uses default values from // the prototypical SERCOM. + // Set to SPI host mode and choose pads. hri_sercomspi_write_CTRLA_MODE_bf(sercom, 3); hri_sercomspi_write_CTRLA_DOPO_bf(sercom, dopo); hri_sercomspi_write_CTRLA_DIPO_bf(sercom, miso_pad); @@ -141,20 +152,20 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_OSError(MP_EIO); } - setup_pin(clock, clock_pinmux); + setup_pin(clock, clock_pinmux, GPIO_DIRECTION_OUT); self->clock_pin = clock->number; if (mosi_none) { self->MOSI_pin = NO_PIN; } else { - setup_pin(mosi, mosi_pinmux); + setup_pin(mosi, mosi_pinmux, GPIO_DIRECTION_OUT); self->MOSI_pin = mosi->number; } if (miso_none) { self->MISO_pin = NO_PIN; } else { - setup_pin(miso, miso_pinmux); + setup_pin(miso, miso_pinmux, GPIO_DIRECTION_IN); self->MISO_pin = miso->number; } @@ -317,11 +328,3 @@ uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { void *hw = self->spi_desc.dev.prvt; return hri_sercomspi_get_CTRLA_CPOL_bit(hw); } - -void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux) { - gpio_set_pin_direction(pin->number, GPIO_DIRECTION_OUT); - gpio_set_pin_pull_mode(pin->number, GPIO_PULL_OFF); - gpio_set_pin_function(pin->number, pinmux); - claim_pin(pin); - hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin->number), GPIO_PIN(pin->number)); -} diff --git a/ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c b/ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c index a6d8fef0f39..56eb82678ec 100644 --- a/ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +++ b/ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c @@ -135,7 +135,8 @@ void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecaptur mp_buffer_info_t bufinfo; mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_RW); - uint8_t dma_channel = dma_allocate_channel(true); + // Allocate a permanent channel (not really audio). + uint8_t dma_channel = dma_allocate_audio_channel(); uint32_t *dest = bufinfo.buf; size_t count = bufinfo.len / 4; // PCC receives 4 bytes (2 pixels) at a time diff --git a/ports/atmel-samd/common-hal/spitarget/SPITarget.c b/ports/atmel-samd/common-hal/spitarget/SPITarget.c index b9062911cc3..e5011b141fc 100644 --- a/ports/atmel-samd/common-hal/spitarget/SPITarget.c +++ b/ports/atmel-samd/common-hal/spitarget/SPITarget.c @@ -192,7 +192,7 @@ void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t * self->miso_packet = miso_packet; Sercom *sercom = self->spi_desc.dev.prvt; - self->running_dma = shared_dma_transfer_start(sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0); + shared_dma_transfer_start(&self->running_dma, sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0); // There is an issue where if an unexpected SPI transfer is received before the user calls "end" for the in-progress, expected // transfer, the SERCOM has an error and gets confused. This can be detected from INTFLAG.ERROR. I think the code in @@ -200,7 +200,7 @@ void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t * // s->SPI.DATA.reg) is supposed to fix this, but experimentation seems to show that it does not in fact fix anything. Anyways, if // the ERROR bit is set, let's just reset the peripheral and then setup the transfer again -- that seems to work. if (hri_sercomspi_get_INTFLAG_ERROR_bit(sercom)) { - shared_dma_transfer_close(self->running_dma); + shared_dma_transfer_close(&self->running_dma); // disable the sercom spi_m_sync_disable(&self->spi_desc); @@ -223,19 +223,19 @@ void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t * spi_m_sync_enable(&self->spi_desc); hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK); - self->running_dma = shared_dma_transfer_start(sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0); + shared_dma_transfer_start(&self->running_dma, sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0); } } bool common_hal_spitarget_spi_target_transfer_is_finished(spitarget_spi_target_obj_t *self) { - return self->running_dma.failure == 1 || shared_dma_transfer_finished(self->running_dma); + return self->running_dma.failure == 1 || shared_dma_transfer_finished(&self->running_dma); } int common_hal_spitarget_spi_target_transfer_close(spitarget_spi_target_obj_t *self) { if (self->running_dma.failure == 1) { return 0; } - int res = shared_dma_transfer_close(self->running_dma); + int res = shared_dma_transfer_close(&self->running_dma); self->running_dma.failure = 1; self->mosi_packet = NULL; diff --git a/ports/atmel-samd/common-hal/spitarget/SPITarget.h b/ports/atmel-samd/common-hal/spitarget/SPITarget.h index 50f2bcb3309..9fff23c1743 100644 --- a/ports/atmel-samd/common-hal/spitarget/SPITarget.h +++ b/ports/atmel-samd/common-hal/spitarget/SPITarget.h @@ -18,7 +18,7 @@ typedef struct { uint8_t *mosi_packet; const uint8_t *miso_packet; - dma_descr_t running_dma; + dma_transfer_t running_dma; } spitarget_spi_target_obj_t; #endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_TARGET_H diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index d3210221bbd..a1f1504d414 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit d3210221bbd018ae9d0183ea4640c42cf4bce672 +Subproject commit a1f1504d414387fc3ff48dc2ba98fd7af4461a63 From c8377c75533cb25f18b74f605e24adeaca3059fa Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 16 Oct 2025 13:50:05 -0400 Subject: [PATCH 064/876] incorporate https://github.com/adafruit/samd-peripherals/pull/47 --- ports/atmel-samd/peripherals | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index a1f1504d414..863e615ff98 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit a1f1504d414387fc3ff48dc2ba98fd7af4461a63 +Subproject commit 863e615ff98c3a8aa904e87a157553559c933b81 From a2d9e9e68b482d04c045cb53455e565a8b4292e7 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 16 Oct 2025 14:38:43 -0400 Subject: [PATCH 065/876] Restore atmel-samd SD card USB presentation --- ports/atmel-samd/mpconfigport.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index e953ea0fc50..087e0bc7d68 100644 --- a/ports/atmel-samd/mpconfigport.h +++ b/ports/atmel-samd/mpconfigport.h @@ -11,9 +11,6 @@ // Definitions that control circuitpy_mpconfig.h: -// On SAMD, presenting the SD card as a second LUN causes USB disconnect. This needs to be fixed eventually. -#define CIRCUITPY_SDCARD_USB (0) - //////////////////////////////////////////////////////////////////////////////////////////////////// #ifdef SAMD21 From 5df18c37b93fa7853494a8cfc1483488ca04eefd Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 16 Oct 2025 12:01:06 -0700 Subject: [PATCH 066/876] Clean up two leftovers from debugging --- ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv | 3 ++- ports/espressif/tools/decode_backtrace.py | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv b/ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv index 44121812ea2..6d78fe8af59 100644 --- a/ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv +++ b/ports/espressif/esp-idf-config/partitions-8MB-no-uf2.csv @@ -3,5 +3,6 @@ # partition_table, data, table, 0x8000, 4K nvs, data, nvs, 0x9000, 20K otadata, data, ota, 0xe000, 8K -ota_0, app, ota_0, 0x10000, 4096K +ota_0, app, ota_0, 0x10000, 2048K +ota_1, app, ota_1, 0x210000, 2048K user_fs, data, fat, 0x410000, 4032K diff --git a/ports/espressif/tools/decode_backtrace.py b/ports/espressif/tools/decode_backtrace.py index d597741a596..16cef9e0822 100644 --- a/ports/espressif/tools/decode_backtrace.py +++ b/ports/espressif/tools/decode_backtrace.py @@ -14,7 +14,9 @@ elfs = [ f"build-{board}/firmware.elf", - "/home/tannewt/Downloads/esp-rom-elfs-20241011/esp32c6_rev0_rom.elf", + # Add additional ELF files here such as the ROM ELF files from: + # https://github.com/espressif/esp-rom-elfs/releases + # "/home/tannewt/Downloads/esp-rom-elfs-20241011/esp32c6_rev0_rom.elf", ] while True: From 1786e9abc96ae007aa4d31a25c6238d790168f4a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 17 Oct 2025 13:37:16 -0400 Subject: [PATCH 067/876] restrict Python cryptography version --- requirements-dev.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 261a5cc2c7f..0e8426d5174 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -25,7 +25,8 @@ intelhex # for building & testing natmods pyelftools -cryptography +# newer versions break ESP-IDF now +cryptography<45 # for web workflow minify minify_html From f8cb53c367cf4b3bfe348112848d5ec358a033cf Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 17 Oct 2025 11:27:06 -0700 Subject: [PATCH 068/876] Fix overriding delay without an OS --- shared-module/max3421e/Max3421E.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/max3421e/Max3421E.c b/shared-module/max3421e/Max3421E.c index 4946e4e7d8d..3448cdd4c75 100644 --- a/shared-module/max3421e/Max3421E.c +++ b/shared-module/max3421e/Max3421E.c @@ -83,7 +83,7 @@ void common_hal_max3421e_max3421e_deinit(max3421e_max3421e_obj_t *self) { // anyway. Don't run background tasks because this function is used by // tuh_task() which is run as a background task. #if CFG_TUSB_OS == OPT_OS_NONE -void osal_task_delay(uint32_t msec) { +void tusb_time_delay_ms_api(uint32_t msec) { uint32_t end_time = common_hal_time_monotonic_ms() + msec; while (common_hal_time_monotonic_ms() < end_time) { if (tuh_callback.prev != NULL) { From 33b8aca6b2025cf507a3f8408311dac072b959b2 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Wed, 22 Oct 2025 16:35:39 -0400 Subject: [PATCH 069/876] make jpegio unsupported format error more helpful --- locale/circuitpython.pot | 16 ++++------------ shared-module/jpegio/JpegDecoder.c | 2 +- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1e167c30353..86587e0a4e8 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -159,10 +159,6 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "" - #: py/argcheck.c msgid "%q must be %d" msgstr "" @@ -1644,10 +1640,6 @@ msgstr "" msgid "Not playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -2371,6 +2363,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" @@ -3174,10 +3170,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" diff --git a/shared-module/jpegio/JpegDecoder.c b/shared-module/jpegio/JpegDecoder.c index 484ba8e7ccd..89cb624a8d0 100644 --- a/shared-module/jpegio/JpegDecoder.c +++ b/shared-module/jpegio/JpegDecoder.c @@ -46,7 +46,7 @@ static void check_jresult(JRESULT j) { msg = MP_ERROR_TEXT("Right format but not supported"); break; case JDR_FMT3: - msg = MP_ERROR_TEXT("Not supported JPEG standard"); + msg = MP_ERROR_TEXT("Unsupported JPEG (may be progressive)"); break; } mp_raise_RuntimeError(msg); From 61e80a61b055124678d3e1de214d29951b9270bc Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 22 Oct 2025 19:46:00 -0400 Subject: [PATCH 070/876] pin changes --- .../atmel-samd/boards/microchip_curiosity_circuitpython/pins.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c index f3069930c6b..fd8213a573a 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c @@ -44,6 +44,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_PA07) }, { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, + { MP_ROM_QSTR(MP_QSTR_LCD_LEDA), MP_ROM_PTR(&pin_PA06) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB30) }, { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB31) }, @@ -59,9 +60,11 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_PB00) }, { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_PB00) }, + { MP_ROM_QSTR(MP_QSTR_IMU_INT), MP_ROM_PTR(&pin_PB00) }, { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_PB01) }, { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_PB01) }, + { MP_ROM_QSTR(MP_QSTR_IMU_ADDR), MP_ROM_PTR(&pin_PB01) }, { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_PB02) }, { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_PB02) }, From b076e08283ac8b72d833b1dae8527dc186ddfd53 Mon Sep 17 00:00:00 2001 From: natheihei Date: Fri, 24 Oct 2025 21:47:10 -0700 Subject: [PATCH 071/876] board: add board waveshare_esp32_s3_touch_lcd_1_47 --- .../waveshare_esp32_s3_touch_lcd_1_47/board.c | 145 ++++++++++++++++++ .../mpconfigboard.h | 22 +++ .../mpconfigboard.mk | 14 ++ .../waveshare_esp32_s3_touch_lcd_1_47/pins.c | 58 +++++++ .../sdkconfig | 14 ++ 5 files changed, 253 insertions(+) create mode 100644 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c create mode 100644 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h create mode 100644 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.mk create mode 100644 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/pins.c create mode 100644 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/sdkconfig diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c new file mode 100644 index 00000000000..4c037ce8df0 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c @@ -0,0 +1,145 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 natheihei +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + +#define DELAY 0x80 + +// Driver is JD9853 +// 172 X 320 Pixels RGB 18-bit +// Init sequence converted from Arduino example + +uint8_t display_init_sequence[] = { + // Command: 0x11 (SLPOUT: Sleep Out) + // Description: Exits sleep mode. A 120ms delay is added for the power supply and clock circuits to stabilize. + 0x11, 0 | DELAY, 120, + + 0xDF, 2, 0x98, 0x53, + 0xB2, 1, 0x23, + + 0xB7, 4, 0x00, 0x47, 0x00, 0x6F, + 0xBB, 6, 0x1C, 0x1A, 0x55, 0x73, 0x63, 0xF0, + 0xC0, 2, 0x44, 0xA4, + 0xC1, 1, 0x16, + 0xC3, 8, 0x7D, 0x07, 0x14, 0x06, 0xCF, 0x71, 0x72, 0x77, + 0xC4, 12, 0x00, 0x00, 0xA0, 0x79, 0x0B, 0x0A, 0x16, 0x79, 0x0B, 0x0A, 0x16, 0x82, + + 0xC8, 32, 0x3F, 0x32, 0x29, 0x29, 0x27, 0x2B, 0x27, 0x28, 0x28, 0x26, 0x25, 0x17, 0x12, 0x0D, 0x04, 0x00, + 0x3F, 0x32, 0x29, 0x29, 0x27, 0x2B, 0x27, 0x28, 0x28, 0x26, 0x25, 0x17, 0x12, 0x0D, 0x04, 0x00, + + 0xD0, 5, 0x04, 0x06, 0x6B, 0x0F, 0x00, + 0xD7, 2, 0x00, 0x30, + 0xE6, 1, 0x14, + 0xDE, 1, 0x01, + + 0xB7, 5, 0x03, 0x13, 0xEF, 0x35, 0x35, + 0xC1, 3, 0x14, 0x15, 0xC0, + 0xC2, 2, 0x06, 0x3A, + 0xC4, 2, 0x72, 0x12, + 0xBE, 1, 0x00, + 0xDE, 1, 0x02, + + 0xE5, 3, 0x00, 0x02, 0x00, + 0xE5, 3, 0x01, 0x02, 0x00, + + 0xDE, 1, 0x00, + + // Command: 0x35 (TEON: Tearing Effect Line ON) + // Description: Turns on the Tearing Effect output signal. + 0x35, 1, 0x00, + + // Command: 0x3A (COLMOD: Pixel Format Set) + // Description: Sets the pixel format for the MCU interface. + 0x3A, 1, 0x05, + + // Command: 0x2A (CASET: Column Address Set) + // Description: Defines the accessible column range in frame memory. + 0x2A, 4, 0x00, 0x22, 0x00, 0xCD, + + // Command: 0x2B (PASET: Page Address Set) + // Description: Defines the accessible page (row) range. + 0x2B, 4, 0x00, 0x00, 0x01, 0x3F, + + 0xDE, 1, 0x02, + 0xE5, 3, 0x00, 0x02, 0x00, + 0xDE, 1, 0x00, + + // Command: 0x36 (MADCTL: Memory Access Control) + // Description: Sets the read/write scanning direction of the frame memory. + 0x36, 1, 0x00, + + // Command: 0x21 (INVON: Display Inversion ON) + // 0x21, 0 | DELAY, 10, + + // Command: 0x29 (DISPON: Display ON) + // Description: Turns the display on by enabling output from the frame memory. + 0x29, 0, +}; + +static void display_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + &pin_GPIO45, // DC + &pin_GPIO21, // CS + &pin_GPIO40, // RST + 80000000, // baudrate + 0, // polarity + 0 // phase + ); + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 172, // width (after rotation) + 320, // height (after rotation) + 34, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO46, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} + +void board_init(void) { + // Display + display_init(); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h new file mode 100644 index 00000000000..0dc2ad4a661 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 natheihei +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3 Touch LCD 1.47" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define CIRCUITPY_BOARD_UART (1) +#define CIRCUITPY_BOARD_UART_PIN {{.rx = &pin_GPIO44, .tx = &pin_GPIO43}} + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO41, .sda = &pin_GPIO42}} /* for Touchscreen */ + +#define CIRCUITPY_BOARD_SPI (2) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO38, .mosi = &pin_GPIO39}, /* for LCD display */ \ + {.clock = &pin_GPIO16, .mosi = &pin_GPIO15, .miso = &pin_GPIO17} /* for SD Card */} diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.mk new file mode 100644 index 00000000000..b337b211495 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x8325 +USB_PRODUCT = "ESP32-S3-Touch-LCD-1.47" +USB_MANUFACTURER = "Waveshare Electronics" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/pins.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/pins.c new file mode 100644 index 00000000000..32c7d0dd21d --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/pins.c @@ -0,0 +1,58 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 natheihei +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +CIRCUITPY_BOARD_BUS_SINGLETON(touch_i2c, i2c, 0) +CIRCUITPY_BOARD_BUS_SINGLETON(sd_spi, spi, 1) + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // UART + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + + // GPIO + { MP_ROM_QSTR(MP_QSTR_GPIO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GPIO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GPIO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GPIO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GPIO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GPIO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GPIO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GPIO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GPIO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GPIO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GPIO11), MP_ROM_PTR(&pin_GPIO11) }, + + // I2C (occupied by Touch I2C) + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + // SD Card + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SD_D0), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SD_D1), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SD_D2), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_SD_D3), MP_ROM_PTR(&pin_GPIO14) }, + // CLK, CMD, D0 is also included in the SPI object as its MISO pin, MOSI pin, and SCK pin respectively + { MP_ROM_QSTR(MP_QSTR_SD_SPI), MP_ROM_PTR(&board_sd_spi_obj) }, + + // AXS5106L Touch + { MP_ROM_QSTR(MP_QSTR_TOUCH_I2C), MP_ROM_PTR(&board_touch_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_RST), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_IRQ), MP_ROM_PTR(&pin_GPIO48) }, + + // JD9853 LCD Display + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, + +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From cb458bf1b469870d9882650679806b0461905431 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Sun, 26 Oct 2025 23:14:34 -0400 Subject: [PATCH 072/876] Add Waveshare ESP32S3 Touch LCD 2.8inch display board --- .../waveshare_esp32_s3_touch_lcd_2_8/board.c | 77 +++++++++++++ .../mpconfigboard.h | 19 +++ .../mpconfigboard.mk | 14 +++ .../waveshare_esp32_s3_touch_lcd_2_8/pins.c | 109 ++++++++++++++++++ .../sdkconfig | 0 5 files changed, 219 insertions(+) create mode 100755 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c create mode 100755 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h create mode 100755 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk create mode 100755 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c create mode 100755 ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/sdkconfig diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c new file mode 100755 index 00000000000..deb764b80a5 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c @@ -0,0 +1,77 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + +#define DELAY 0x80 + +// display init sequence according to LilyGO example app +uint8_t display_init_sequence[] = { + 0x01, DELAY, 0x96, // _SWRESET and Delay 150ms + 0x11, DELAY, 0xFF, // _SLPOUT and Delay 500ms + 0x3A, DELAY | 1, 0x55, 0x0A, // _COLMOD and Delay 10ms + 0x21, DELAY, 0x0A, // _INVON Hack and Delay 10ms + 0x13, DELAY, 0x0A, // _NORON and Delay 10ms + 0x36, 0x01, 0x60, // _MADCTL + 0x29, DELAY, 0xFF, // _DISPON and Delay 500ms +}; + +void board_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + &pin_GPIO41, // DC + &pin_GPIO42, // CS + &pin_GPIO39, // RST + 40000000, // baudrate + 0, // polarity + 0 // phase + ); + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 320, // width (after rotation) + 240, // height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO5, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h new file mode 100755 index 00000000000..3e0db8bf494 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Neradoc +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3 Touch LCD 2.8" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO3, .sda = &pin_GPIO1}} + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO40, .mosi = &pin_GPIO45, .miso = &pin_GPIO46}} + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk new file mode 100755 index 00000000000..dc845ad1399 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x825F +USB_MANUFACTURER = "Waveshare Electronics" +USB_PRODUCT = "ESP32-S3 Touch LCD 2.8" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m \ No newline at end of file diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c new file mode 100755 index 00000000000..00ff3557088 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c @@ -0,0 +1,109 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // LCD (SPI0) + { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_LCD_MISO), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_LCD_DC), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RST), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_GPIO5) }, // PWM-capable + + // microSD (SPI1) + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO21) }, + + // Touch panel (I2C0) + { MP_ROM_QSTR(MP_QSTR_TP_SCL), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_TP_SDA), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_TP_RST), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_TP_INT), MP_ROM_PTR(&pin_GPIO4) }, + + // IMU (I2C1) + { MP_ROM_QSTR(MP_QSTR_IMU_SCL), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IMU_SDA), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IMU_INT2), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IMU_INT1), MP_ROM_PTR(&pin_GPIO13) }, + + // I2S Audio + { MP_ROM_QSTR(MP_QSTR_I2S_BCK), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DIN), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCK), MP_ROM_PTR(&pin_GPIO38) }, + + // Battery management + { MP_ROM_QSTR(MP_QSTR_BAT_CONTROL), MP_ROM_PTR(&pin_GPIO7) }, // control pin + { MP_ROM_QSTR(MP_QSTR_BAT_PWR), MP_ROM_PTR(&pin_GPIO6) }, // Board name + { MP_ROM_QSTR(MP_QSTR_KEY_BAT), MP_ROM_PTR(&pin_GPIO6) }, // Schematics name + { MP_ROM_QSTR(MP_QSTR_BAT_ADC), MP_ROM_PTR(&pin_GPIO8) }, // VBAT sense (ADC) + + // UART header + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, // User accessible + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, // User accessible + + // I2C header + { MP_ROM_QSTR(MP_QSTR_I2C_SCL), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2C_SDA), MP_ROM_PTR(&pin_GPIO11) }, + + // Boot/User button + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON0), MP_ROM_PTR(&pin_GPIO0) }, // Optional Alias + + // Primary bus pins + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO40) }, // Primary SPI (LCD) + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO3) }, // Primary I2C (TP) + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO1) }, + + // Objects + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, + + // Fallback mapping for all GPIO pins + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, // User accessible + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, // User accessible + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, // User accessible + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, // User accessible + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, // User accessible + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, // User accessible + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/sdkconfig new file mode 100755 index 00000000000..e69de29bb2d From b406116b87442c66c30b4c708e404841742b555d Mon Sep 17 00:00:00 2001 From: Ross Satchell Date: Mon, 27 Oct 2025 11:32:32 -0700 Subject: [PATCH 073/876] Update pins.c Changed LED_LEDA to LCD_BL Changed CAN _STANDBY to CAN_STDBY --- .../boards/microchip_curiosity_circuitpython/pins.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c index fd8213a573a..49c7f7565e2 100644 --- a/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c +++ b/ports/atmel-samd/boards/microchip_curiosity_circuitpython/pins.c @@ -44,7 +44,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_PA07) }, { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_PA04) }, { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_PA05) }, - { MP_ROM_QSTR(MP_QSTR_LCD_LEDA), MP_ROM_PTR(&pin_PA06) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_PA06) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_PB30) }, { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_PB31) }, @@ -78,7 +78,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_RX), MP_ROM_PTR(&pin_PB13) }, { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_TX), MP_ROM_PTR(&pin_PB12) }, - { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STANDBY), MP_ROM_PTR(&pin_PB17) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_CAN_STDBY), MP_ROM_PTR(&pin_PB17) }, { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_PB17) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, From 064574d21bec47cf8d5c278f6b18965fee0f556a Mon Sep 17 00:00:00 2001 From: Gustavo Date: Mon, 27 Oct 2025 15:23:31 -0400 Subject: [PATCH 074/876] Fix trailing-whitespace and end-of-files --- .../boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk | 2 +- ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk index dc845ad1399..421a5897600 100755 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.mk @@ -11,4 +11,4 @@ CIRCUITPY_ESP_FLASH_SIZE = 16MB CIRCUITPY_ESP_PSRAM_SIZE = 8MB CIRCUITPY_ESP_PSRAM_MODE = opi -CIRCUITPY_ESP_PSRAM_FREQ = 80m \ No newline at end of file +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c index 00ff3557088..24891099ab1 100755 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c @@ -90,7 +90,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, // User accessible - { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, // User accessible { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, From 5028d2ce369afb9a083086be6086df3dbb657d87 Mon Sep 17 00:00:00 2001 From: Gustavo Date: Tue, 28 Oct 2025 18:33:56 -0400 Subject: [PATCH 075/876] Remove fallback pin aliases; keep only user-accessible pins --- .../waveshare_esp32_s3_touch_lcd_2_8/pins.c | 47 +++++-------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c index 24891099ab1..0bfb3e940b4 100755 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/pins.c @@ -49,8 +49,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BAT_ADC), MP_ROM_PTR(&pin_GPIO8) }, // VBAT sense (ADC) // UART header - { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, // User accessible - { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, // User accessible + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, // I2C header { MP_ROM_QSTR(MP_QSTR_I2C_SCL), MP_ROM_PTR(&pin_GPIO10) }, @@ -58,7 +58,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { // Boot/User button { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO0) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON0), MP_ROM_PTR(&pin_GPIO0) }, // Optional Alias + { MP_ROM_QSTR(MP_QSTR_BUTTON0), MP_ROM_PTR(&pin_GPIO0) }, // Primary bus pins { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO40) }, // Primary SPI (LCD) @@ -73,37 +73,14 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, - // Fallback mapping for all GPIO pins - { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, - { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, - { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, - { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, - { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, - { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, - { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, - { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, // User accessible - { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, // User accessible - { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, - { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, // User accessible - { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, - { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, - { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, // User accessible - { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, - { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, - { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, - { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, - { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, - { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, // User accessible - { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, // User accessible - { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, - { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, - { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, - { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + // User accessible + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 5a4662c1e58164d9929351037acf566b998c2f55 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 30 Oct 2025 16:00:42 -0500 Subject: [PATCH 076/876] Add terminalio.Terminal example usage to docstring. Move init function docstring so it appears above the rest of the docs next to the function signature. --- shared-bindings/terminalio/Terminal.c | 53 +++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 3 deletions(-) diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c index f8394dcc17d..199128e56e9 100644 --- a/shared-bindings/terminalio/Terminal.c +++ b/shared-bindings/terminalio/Terminal.c @@ -21,7 +21,10 @@ #endif //| class Terminal: -//| """Display a character stream with a TileGrid +//| """Terminal manages tile indices and cursor position based on VT100 commands. The ``font`` should be +//| a `fontio.BuiltinFont` and the ``scroll_area`` TileGrid's bitmap should match the font's bitmap. +//| +//| Display a character stream with a TileGrid //| //| ASCII control: //| @@ -75,6 +78,52 @@ //| +--------+------------+------------+ //| | White | 37 | 47 | //| +--------+------------+------------+ +//| +//| Example Usage: +//| +//| .. code-block:: python +//| +//| import time +//| import displayio +//| import supervisor +//| from displayio import Group, TileGrid +//| from terminalio import FONT, Terminal +//| +//| main_group = Group() +//| display = supervisor.runtime.display +//| font_bb = FONT.get_bounding_box() +//| screen_size = (display.width // font_bb[0], display.height // font_bb[1]) +//| char_size = FONT.get_bounding_box() +//| +//| palette = displayio.Palette(2) +//| palette[0] = 0x000000 +//| palette[1] = 0xffffff +//| +//| tilegrid = TileGrid( +//| bitmap=FONT.bitmap, width=screen_size[0], height=screen_size[1], +//| tile_width=char_size[0], tile_height=char_size[1], pixel_shader=palette) +//| +//| terminal = Terminal(tilegrid, FONT) +//| +//| main_group.append(tilegrid) +//| display.root_group = main_group +//| +//| message = "Hello World\\n" +//| terminal.write(message) +//| +//| print(terminal.cursor_x, terminal.cursor_y) +//| move_cursor = chr(27) + "[10;10H" +//| terminal.write(f"Moving the cursor\\n{move_cursor} To here") +//| +//| cursor_home = chr(27) + f"[{screen_size[1]};0H" +//| terminal.write(cursor_home) +//| i = 1 +//| while True: +//| terminal.write(f"Writing again {i}\\n") +//| i = i + 1 +//| time.sleep(1) +//| +//| //| """ //| //| def __init__( @@ -84,8 +133,6 @@ //| *, //| status_bar: Optional[displayio.TileGrid] = None, //| ) -> None: -//| """Terminal manages tile indices and cursor position based on VT100 commands. The font should be -//| a `fontio.BuiltinFont` and the TileGrid's bitmap should match the font's bitmap.""" //| ... //| From 6b458a907eef7f78e7a75ac342e43171f8b4e7b6 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 30 Oct 2025 18:23:59 -0400 Subject: [PATCH 077/876] finalisers for SPI; clean up sdcardio; reset all pins after finalisers; avoid USB SD races --- main.c | 15 ++++++ ports/analog/common-hal/busio/SPI.c | 10 +++- ports/analog/supervisor/port.c | 1 - ports/atmel-samd/common-hal/busio/SPI.c | 10 +++- ports/atmel-samd/supervisor/port.c | 2 - ports/broadcom/common-hal/busio/SPI.c | 36 +++++-------- ports/broadcom/common-hal/busio/SPI.h | 2 - ports/broadcom/supervisor/port.c | 3 -- ports/cxd56/common-hal/busio/SPI.c | 6 ++- ports/cxd56/supervisor/port.c | 2 - ports/espressif/common-hal/busio/I2C.c | 5 ++ ports/espressif/common-hal/busio/SPI.c | 43 ++++++++------- ports/espressif/common-hal/busio/SPI.h | 2 - ports/espressif/supervisor/port.c | 5 +- ports/litex/common-hal/microcontroller/Pin.c | 4 ++ ports/litex/supervisor/port.c | 1 - ports/mimxrt10xx/common-hal/busio/SPI.c | 26 ++++----- ports/mimxrt10xx/common-hal/busio/SPI.h | 2 - ports/mimxrt10xx/supervisor/port.c | 6 --- ports/nordic/common-hal/busio/SPI.c | 18 +++---- ports/nordic/common-hal/busio/SPI.h | 2 - ports/nordic/supervisor/port.c | 3 -- ports/raspberrypi/common-hal/busio/SPI.c | 21 ++++---- ports/raspberrypi/common-hal/busio/SPI.h | 2 - ports/raspberrypi/supervisor/port.c | 3 -- ports/renode/common-hal/busio/SPI.c | 3 ++ ports/silabs/common-hal/busio/SPI.c | 19 ++++--- ports/silabs/supervisor/port.c | 3 -- ports/stm/common-hal/busio/SPI.c | 19 +++---- ports/stm/supervisor/port.c | 3 -- py/mpstate.h | 3 ++ shared-bindings/busio/SPI.c | 3 +- shared-bindings/busio/SPI.h | 4 ++ shared-bindings/sdcardio/SDCard.c | 22 ++++++-- shared-bindings/sdcardio/SDCard.h | 2 + shared-module/displayio/__init__.c | 4 ++ shared-module/sdcardio/SDCard.c | 56 +++++++++++++------- shared-module/sdcardio/SDCard.h | 5 +- shared-module/sdcardio/__init__.c | 18 +++---- supervisor/shared/usb/usb_msc_flash.c | 20 ++++--- 40 files changed, 228 insertions(+), 186 deletions(-) diff --git a/main.c b/main.c index 91687ff2f8b..f4f67b04347 100644 --- a/main.c +++ b/main.c @@ -43,6 +43,7 @@ #include "supervisor/shared/external_flash/external_flash.h" #include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/supervisor/__init__.h" #include "shared-bindings/supervisor/Runtime.h" @@ -124,6 +125,7 @@ static void reset_devices(void) { static uint8_t *_heap; static uint8_t *_pystack; +static volatile bool _vm_is_running = false; static const char line_clear[] = "\x1b[2K\x1b[0G"; @@ -207,9 +209,12 @@ static void start_mp(safe_mode_t safe_mode) { // Always return to root common_hal_os_chdir("/"); + + _vm_is_running = true; } static void stop_mp(void) { + _vm_is_running = false; #if MICROPY_VFS // Unmount all heap allocated vfs mounts. @@ -409,8 +414,13 @@ static void cleanup_after_vm(mp_obj_t exception) { // Free the heap last because other modules may reference heap memory and need to shut down. filesystem_flush(); + + // Runs finalisers while shutting down the heap. stop_mp(); + // Don't reset pins until finalisers have run. + reset_all_pins(); + // Let the workflows know we've reset in case they want to restart. supervisor_workflow_reset(); } @@ -513,6 +523,7 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s // Finished executing python code. Cleanup includes filesystem flush and a board reset. + _vm_is_running = false; cleanup_after_vm(_exec_result.exception); _exec_result.exception = NULL; @@ -1201,6 +1212,10 @@ void NORETURN nlr_jump_fail(void *val) { } } +bool vm_is_running(void) { + return _vm_is_running; +} + #ifndef NDEBUG static void NORETURN __fatal_error(const char *msg) { #if CIRCUITPY_DEBUG == 0 diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index b4a519c37a7..a9bf4aad8df 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -61,6 +61,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Check for NULL Pointer assert(self); + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + // Assign SPI ID based on pins int spi_id = pinsToSpi(mosi, miso, sck); if (spi_id == -1) { @@ -127,6 +130,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { @@ -138,8 +145,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { self->mosi = NULL; self->miso = NULL; - self->sck = NULL; self->nss = NULL; + + common_hal_busio_spi_mark_deinit(self); } // Configures the SPI bus. The SPI object must be locked. diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index 40e8e1d6050..86d96bc251b 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -166,7 +166,6 @@ void reset_cpu(void) { // Reset MCU state void reset_port(void) { - reset_all_pins(); } // Reset to the bootloader diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index 5dd7bedebc3..fe53580afdf 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -53,7 +53,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } // Ensure the object starts in its deinit state. - self->clock_pin = NO_PIN; + common_hal_busio_spi_mark_deinit(self); // Special case for SAMR21 boards. (feather_radiofruit_zigbee) #if defined(PIN_PC19F_SERCOM4_PAD0) @@ -184,18 +184,24 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock_pin == NO_PIN; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock_pin = NO_PIN; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } allow_reset_sercom(self->spi_desc.dev.prvt); + // Mark as deinit early in case we are used in an interrupt. + common_hal_busio_spi_mark_deinit(self); + spi_m_sync_disable(&self->spi_desc); spi_m_sync_deinit(&self->spi_desc); reset_pin_number(self->clock_pin); reset_pin_number(self->MOSI_pin); reset_pin_number(self->MISO_pin); - self->clock_pin = NO_PIN; } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 03c2c2543a7..9654a791dbb 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -411,8 +411,6 @@ void reset_port(void) { reset_ticks(); } - reset_all_pins(); - // Output clocks for debugging. // not supported by SAMD51G; uncomment for SAMD51J or update for 51G // #ifdef SAM_D5X_E5X diff --git a/ports/broadcom/common-hal/busio/SPI.c b/ports/broadcom/common-hal/busio/SPI.c index 2396a9b921e..01d61ba9d1d 100644 --- a/ports/broadcom/common-hal/busio/SPI.c +++ b/ports/broadcom/common-hal/busio/SPI.c @@ -33,28 +33,6 @@ static SPI1_Type *aux_spi[NUM_SPI] = {NULL, SPI1, SPI2}; static bool never_reset_spi[NUM_SPI]; static bool spi_in_use[NUM_SPI]; -void reset_spi(void) { - for (size_t i = 0; i < NUM_SPI; i++) { - if (never_reset_spi[i]) { - continue; - } - - if (i == 1 || i == 2) { - if (i == 1) { - AUX->ENABLES_b.SPI_1 = false; - } else { - AUX->ENABLES_b.SPI_2 = false; - } - aux_spi[i]->CNTL0 = 0; - } else { - // Set CS back to default. All 0 except read enable. - spi[i]->CS = SPI0_CS_REN_Msk; - } - - spi_in_use[i] = false; - } -} - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { @@ -67,6 +45,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError(MP_ERROR_TEXT("Half duplex SPI is not implemented")); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + // BCM_VERSION != 2711 have 3 SPI but as listed in peripherals/gen/pins.c two are on // index 0, once one index 0 SPI is found the other will throw an invalid_pins error. for (size_t i = 0; i < NUM_SPI; i++) { @@ -129,6 +110,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -138,7 +123,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { common_hal_reset_pin(self->clock); common_hal_reset_pin(self->MOSI); common_hal_reset_pin(self->MISO); - self->clock = NULL; + spi_in_use[self->index] = false; if (self->index == 1 || @@ -149,7 +134,12 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } else if (self->index == 2) { AUX->ENABLES_b.SPI_2 = false; } + } else { + // Set CS back to default. All 0 except read enable. + spi[self->index]->CS = SPI0_CS_REN_Msk; } + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/broadcom/common-hal/busio/SPI.h b/ports/broadcom/common-hal/busio/SPI.h index aec91263677..3d52b6b0a44 100644 --- a/ports/broadcom/common-hal/busio/SPI.h +++ b/ports/broadcom/common-hal/busio/SPI.h @@ -23,5 +23,3 @@ typedef struct { uint8_t bits; uint8_t index; } busio_spi_obj_t; - -void reset_spi(void); diff --git a/ports/broadcom/supervisor/port.c b/ports/broadcom/supervisor/port.c index 83dd50f1b8b..a0f0be30dd7 100644 --- a/ports/broadcom/supervisor/port.c +++ b/ports/broadcom/supervisor/port.c @@ -67,7 +67,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO reset_i2c(); - reset_spi(); reset_uart(); #endif @@ -85,8 +84,6 @@ void reset_port(void) { #if CIRCUITPY_AUDIOCORE audio_dma_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/cxd56/common-hal/busio/SPI.c b/ports/cxd56/common-hal/busio/SPI.c index 8eedb624201..6c49e0f2750 100644 --- a/ports/cxd56/common-hal/busio/SPI.c +++ b/ports/cxd56/common-hal/busio/SPI.c @@ -54,7 +54,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { return; } - self->spi_dev = NULL; + common_hal_busio_spi_mark_deinit(self); reset_pin_number(self->clock_pin->number); reset_pin_number(self->mosi_pin->number); @@ -65,6 +65,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->spi_dev == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->spi_dev = NULL; +} + bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { uint8_t mode; diff --git a/ports/cxd56/supervisor/port.c b/ports/cxd56/supervisor/port.c index 75abcbf6d93..3dc54df96fb 100644 --- a/ports/cxd56/supervisor/port.c +++ b/ports/cxd56/supervisor/port.c @@ -66,8 +66,6 @@ void reset_port(void) { #if CIRCUITPY_RTC rtc_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 98c453ba3c0..9ef3877ea92 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -128,6 +128,11 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { i2c_del_master_bus(self->handle); self->handle = NULL; + // Release the mutex before we delete it. Otherwise FreeRTOS gets unhappy. + xSemaphoreGive(self->xSemaphore); + vSemaphoreDelete(self->xSemaphore); + self->xSemaphore = NULL; + common_hal_reset_pin(self->sda_pin); common_hal_reset_pin(self->scl_pin); common_hal_busio_i2c_mark_deinit(self); diff --git a/ports/espressif/common-hal/busio/SPI.c b/ports/espressif/common-hal/busio/SPI.c index 6439ca41129..3db4c770190 100644 --- a/ports/espressif/common-hal/busio/SPI.c +++ b/ports/espressif/common-hal/busio/SPI.c @@ -18,24 +18,11 @@ static bool spi_never_reset[SOC_SPI_PERIPH_NUM]; static spi_device_handle_t spi_handle[SOC_SPI_PERIPH_NUM]; -static StaticSemaphore_t spi_mutex[SOC_SPI_PERIPH_NUM]; static bool spi_bus_is_free(spi_host_device_t host_id) { return spi_bus_get_attr(host_id) == NULL; } -void spi_reset(void) { - for (spi_host_device_t host_id = SPI2_HOST; host_id < SOC_SPI_PERIPH_NUM; host_id++) { - if (spi_never_reset[host_id]) { - continue; - } - if (!spi_bus_is_free(host_id)) { - spi_bus_remove_device(spi_handle[host_id]); - spi_bus_free(host_id); - } - } -} - static void set_spi_config(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { // 128 is a 50% duty cycle. @@ -61,6 +48,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + const spi_bus_config_t bus_config = { .mosi_io_num = mosi != NULL ? mosi->number : -1, .miso_io_num = miso != NULL ? miso->number : -1, @@ -83,6 +73,11 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("All SPI peripherals are in use")); } + self->mutex = xSemaphoreCreateMutex(); + if (self->mutex == NULL) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to create lock")); + } + esp_err_t result = spi_bus_initialize(self->host_id, &bus_config, SPI_DMA_CH_AUTO); if (result == ESP_ERR_NO_MEM) { mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("ESP-IDF memory allocation failed")); @@ -90,6 +85,12 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, raise_ValueError_invalid_pins(); } + self->mutex = xSemaphoreCreateMutex(); + if (self->mutex == NULL) { + spi_bus_free(self->host_id); + mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to create lock")); + } + set_spi_config(self, 250000, 0, 0, 8); self->MOSI = mosi; @@ -103,8 +104,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, claim_pin(miso); } claim_pin(clock); - - self->mutex = xSemaphoreCreateMutexStatic(&spi_mutex[self->host_id]); } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { @@ -122,6 +121,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -132,9 +135,9 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { RUN_BACKGROUND_TASKS; } - // Mark us as deinit early in case we are used in an interrupt. + // Mark as deinit early in case we are used in an interrupt. common_hal_reset_pin(self->clock); - self->clock = NULL; + common_hal_busio_spi_mark_deinit(self); spi_never_reset[self->host_id] = false; spi_bus_remove_device(spi_handle[self->host_id]); @@ -170,11 +173,13 @@ bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { } bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { - return self->mutex != NULL && xSemaphoreGetMutexHolder(self->mutex) == xTaskGetCurrentTaskHandle(); + return (self->mutex != NULL) && (xSemaphoreGetMutexHolder(self->mutex) == xTaskGetCurrentTaskHandle()); } void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { - xSemaphoreGive(self->mutex); + if (self->mutex != NULL) { + xSemaphoreGive(self->mutex); + } } bool common_hal_busio_spi_write(busio_spi_obj_t *self, diff --git a/ports/espressif/common-hal/busio/SPI.h b/ports/espressif/common-hal/busio/SPI.h index 820f29333c7..ac2f404042b 100644 --- a/ports/espressif/common-hal/busio/SPI.h +++ b/ports/espressif/common-hal/busio/SPI.h @@ -25,5 +25,3 @@ typedef struct { SemaphoreHandle_t mutex; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 72c92c98bae..b67fae426b7 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -356,14 +356,11 @@ void reset_port(void) { ssl_reset(); #endif - reset_all_pins(); - #if CIRCUITPY_ANALOGIO analogout_reset(); #endif #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif @@ -417,7 +414,7 @@ void reset_to_bootloader(void) { } void reset_cpu(void) { - #if CIRCUITPY_DEBUG + #if CIRCUITPY_DEBUG || 1 esp_backtrace_print(100); #endif esp_restart(); diff --git a/ports/litex/common-hal/microcontroller/Pin.c b/ports/litex/common-hal/microcontroller/Pin.c index dea848f1ec3..bb3636c5b3f 100644 --- a/ports/litex/common-hal/microcontroller/Pin.c +++ b/ports/litex/common-hal/microcontroller/Pin.c @@ -11,6 +11,10 @@ static uint8_t claimed_pins[1]; +void reset_all_pins(void) { + // TODO +} + // Mark pin as free and return it to a quiescent state. void reset_pin_number(uint8_t pin_port, uint8_t pin_number) { if (pin_port == 0x0F) { diff --git a/ports/litex/supervisor/port.c b/ports/litex/supervisor/port.c index 98fce16152e..7f9aab7f7ff 100644 --- a/ports/litex/supervisor/port.c +++ b/ports/litex/supervisor/port.c @@ -59,7 +59,6 @@ extern uint32_t _heap_start; extern uint32_t _estack; void reset_port(void) { - // reset_all_pins(); // i2c_reset(); // spi_reset(); // uart_reset(); diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.c b/ports/mimxrt10xx/common-hal/busio/SPI.c index 732b23d8c9b..9b988e0d15e 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.c +++ b/ports/mimxrt10xx/common-hal/busio/SPI.c @@ -53,22 +53,6 @@ static void config_periph_pin(const mcu_periph_obj_t *periph) { | IOMUXC_SW_PAD_CTL_PAD_SRE(0)); } -void spi_reset(void) { - for (uint i = 0; i < MP_ARRAY_SIZE(mcu_spi_banks); i++) { - if (!never_reset_spi[i]) { - reserved_spi[i] = false; - #if IMXRT11XX - // Skip resetting SPIs that aren't clocked. Doing so generates a bus fault. - if ((CCM->LPCG[s_lpspiClocks[i + 1]].STATUS0 & CCM_LPCG_STATUS0_ON_MASK) == ((uint32_t)kCLOCK_Off & CCM_LPCG_STATUS0_ON_MASK)) { - continue; - } - #endif - - LPSPI_Deinit(mcu_spi_banks[i]); - } - } -} - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { @@ -82,6 +66,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + for (uint i = 0; i < sck_count; i++) { if (mcu_spi_sck_list[i].pin != clock) { continue; @@ -214,6 +201,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -226,9 +217,10 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { common_hal_reset_pin(self->mosi->pin); common_hal_reset_pin(self->miso->pin); - self->clock = NULL; self->mosi = NULL; self->miso = NULL; + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.h b/ports/mimxrt10xx/common-hal/busio/SPI.h index 67801078261..d86489428ec 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.h +++ b/ports/mimxrt10xx/common-hal/busio/SPI.h @@ -21,5 +21,3 @@ typedef struct { const mcu_periph_obj_t *mosi; const mcu_periph_obj_t *miso; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/mimxrt10xx/supervisor/port.c b/ports/mimxrt10xx/supervisor/port.c index d7f7f280d19..62d2569cfde 100644 --- a/ports/mimxrt10xx/supervisor/port.c +++ b/ports/mimxrt10xx/supervisor/port.c @@ -425,10 +425,6 @@ safe_mode_t port_init(void) { } void reset_port(void) { - #if CIRCUITPY_BUSIO - spi_reset(); - #endif - #if CIRCUITPY_AUDIOIO audio_dma_reset(); #endif @@ -450,8 +446,6 @@ void reset_port(void) { #endif // reset_event_system(); - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/nordic/common-hal/busio/SPI.c b/ports/nordic/common-hal/busio/SPI.c index 8af4c5f4e83..b4fc887aa34 100644 --- a/ports/nordic/common-hal/busio/SPI.c +++ b/ports/nordic/common-hal/busio/SPI.c @@ -65,15 +65,6 @@ static bool never_reset[MP_ARRAY_SIZE(spim_peripherals)]; // https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52840_Rev2%2FERR%2FnRF52840%2FRev2%2Flatest%2Fanomaly_840_198.html static uint8_t *spim3_transmit_buffer = (uint8_t *)SPIM3_BUFFER_RAM_START_ADDR; -void spi_reset(void) { - for (size_t i = 0; i < MP_ARRAY_SIZE(spim_peripherals); i++) { - if (never_reset[i]) { - continue; - } - nrfx_spim_uninit(&spim_peripherals[i].spim); - } -} - void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { for (size_t i = 0; i < MP_ARRAY_SIZE(spim_peripherals); i++) { if (self->spim_peripheral == &spim_peripherals[i]) { @@ -125,6 +116,9 @@ static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate) void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if (half_duplex) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } @@ -178,6 +172,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock_pin_number == NO_PIN; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock_pin_number = NO_PIN; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -188,6 +186,8 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { reset_pin_number(self->clock_pin_number); reset_pin_number(self->MOSI_pin_number); reset_pin_number(self->MISO_pin_number); + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { diff --git a/ports/nordic/common-hal/busio/SPI.h b/ports/nordic/common-hal/busio/SPI.h index 7bfddd9625d..3260c5c27de 100644 --- a/ports/nordic/common-hal/busio/SPI.h +++ b/ports/nordic/common-hal/busio/SPI.h @@ -23,5 +23,3 @@ typedef struct { uint8_t MOSI_pin_number; uint8_t MISO_pin_number; } busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/nordic/supervisor/port.c b/ports/nordic/supervisor/port.c index ed371c6ad85..1eabfcbe216 100644 --- a/ports/nordic/supervisor/port.c +++ b/ports/nordic/supervisor/port.c @@ -189,7 +189,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif @@ -216,8 +215,6 @@ void reset_port(void) { nrfx_gpiote_uninit(); } nrfx_gpiote_init(NRFX_GPIOTE_CONFIG_IRQ_PRIORITY); - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/raspberrypi/common-hal/busio/SPI.c b/ports/raspberrypi/common-hal/busio/SPI.c index 4735d1284f9..21af168df3b 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.c +++ b/ports/raspberrypi/common-hal/busio/SPI.c @@ -20,23 +20,15 @@ #define NO_INSTANCE 0xff static bool never_reset_spi[2]; -static spi_inst_t *spi[2] = {spi0, spi1}; - -void reset_spi(void) { - for (size_t i = 0; i < 2; i++) { - if (never_reset_spi[i]) { - continue; - } - - spi_deinit(spi[i]); - } -} void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { size_t instance_index = NO_INSTANCE; + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if (half_duplex) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex); } @@ -107,6 +99,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->clock == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->clock = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; @@ -117,7 +113,8 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { common_hal_reset_pin(self->clock); common_hal_reset_pin(self->MOSI); common_hal_reset_pin(self->MISO); - self->clock = NULL; + + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/raspberrypi/common-hal/busio/SPI.h b/ports/raspberrypi/common-hal/busio/SPI.h index 8510eb7693a..3d43c1eff00 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.h +++ b/ports/raspberrypi/common-hal/busio/SPI.h @@ -25,5 +25,3 @@ typedef struct { uint8_t phase; uint8_t bits; } busio_spi_obj_t; - -void reset_spi(void); diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 66e63248c48..5cfbdfa66a3 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -422,7 +422,6 @@ safe_mode_t port_init(void) { void reset_port(void) { #if CIRCUITPY_BUSIO - reset_spi(); reset_uart(); #endif @@ -453,8 +452,6 @@ void reset_port(void) { #if CIRCUITPY_WIFI wifi_reset(); #endif - - reset_all_pins(); } void reset_to_bootloader(void) { diff --git a/ports/renode/common-hal/busio/SPI.c b/ports/renode/common-hal/busio/SPI.c index 6f5f6050607..1f66fc5ec4a 100644 --- a/ports/renode/common-hal/busio/SPI.c +++ b/ports/renode/common-hal/busio/SPI.c @@ -21,6 +21,9 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return true; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; diff --git a/ports/silabs/common-hal/busio/SPI.c b/ports/silabs/common-hal/busio/SPI.c index 74cfc69bfb2..fcff2031fa2 100644 --- a/ports/silabs/common-hal/busio/SPI.c +++ b/ports/silabs/common-hal/busio/SPI.c @@ -39,15 +39,6 @@ static SPIDRV_Init_t spidrv_eusart_init = SPIDRV_MASTER_EUSART1; static bool in_used = false; static bool never_reset = false; -// Reset SPI when reload -void spi_reset(void) { - if (!never_reset && in_used) { - SPIDRV_DeInit(&spidrv_eusart_handle); - in_used = false; - } - return; -} - // Construct SPI protocol, this function init SPI peripheral void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *sck, @@ -61,6 +52,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, MP_ERROR_TEXT("Half duplex SPI is not implemented")); } + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + if ((sck != NULL) && (mosi != NULL) && (miso != NULL)) { if (sck->function_list[FN_EUSART1_SCLK] == 1 && miso->function_list[FN_EUSART1_RX] == 1 @@ -119,6 +113,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + // Deinit SPI obj void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { @@ -132,13 +130,14 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } in_used = false; - self->sck = NULL; self->mosi = NULL; self->miso = NULL; self->handle = NULL; common_hal_reset_pin(self->mosi); common_hal_reset_pin(self->miso); common_hal_reset_pin(self->sck); + + common_hal_busio_spi_mark_deinit(self); } // Configures the SPI bus. The SPI object must be locked. diff --git a/ports/silabs/supervisor/port.c b/ports/silabs/supervisor/port.c index 2409e907dea..85a6e0f92a5 100644 --- a/ports/silabs/supervisor/port.c +++ b/ports/silabs/supervisor/port.c @@ -156,10 +156,7 @@ safe_mode_t port_init(void) { } void reset_port(void) { - reset_all_pins(); - #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif diff --git a/ports/stm/common-hal/busio/SPI.c b/ports/stm/common-hal/busio/SPI.c index 98696271ca9..347e94bef9f 100644 --- a/ports/stm/common-hal/busio/SPI.c +++ b/ports/stm/common-hal/busio/SPI.c @@ -76,18 +76,6 @@ static uint32_t stm32_baud_to_spi_div(uint32_t baudrate, uint16_t *prescaler, ui return SPI_BAUDRATEPRESCALER_256; } -void spi_reset(void) { - uint16_t never_reset_mask = 0x00; - for (int i = 0; i < MAX_SPI; i++) { - if (!never_reset_spi[i]) { - reserved_spi[i] = false; - } else { - never_reset_mask |= 1 << i; - } - } - spi_clock_disable(ALL_CLOCKS & ~(never_reset_mask)); -} - static const mcu_periph_obj_t *find_pin_function(const mcu_periph_obj_t *table, size_t sz, const mcu_pin_obj_t *pin, int periph_index) { for (size_t i = 0; i < sz; i++, table++) { if (periph_index == table->periph_index && pin == table->pin) { @@ -152,6 +140,9 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, int periph_index = check_pins(self, sck, mosi, miso); SPI_TypeDef *SPIx = mcu_spi_banks[periph_index - 1]; + // Ensure the object starts in its deinit state. + common_hal_busio_spi_mark_deinit(self); + // Start GPIO for each pin GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = pin_mask(sck->number); @@ -238,6 +229,10 @@ bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { return self->sck == NULL; } +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + self->sck = NULL; +} + void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index c5a1685a7fd..3820a046fc4 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -302,14 +302,11 @@ void SysTick_Handler(void) { } void reset_port(void) { - reset_all_pins(); - #if CIRCUITPY_RTC rtc_reset(); #endif #if CIRCUITPY_BUSIO - spi_reset(); uart_reset(); #endif #if CIRCUITPY_SDIOIO diff --git a/py/mpstate.h b/py/mpstate.h index 4c48e9edaf4..e5e5f8d9fa3 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -369,4 +369,7 @@ extern mp_state_thread_t *mp_thread_get_state(void); #define mp_thread_is_main_thread() (true) #endif +// CIRCUITPY-CHANGE: defined in main.c +bool vm_is_running(void); + #endif // MICROPY_INCLUDED_PY_MPSTATE_H diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 0c8ae1bfdd7..1513a7cf094 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -88,7 +88,7 @@ // TODO(tannewt): Support LSB SPI. static mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_BUSIO_SPI - busio_spi_obj_t *self = mp_obj_malloc(busio_spi_obj_t, &busio_spi_type); + busio_spi_obj_t *self = mp_obj_malloc_with_finaliser(busio_spi_obj_t, &busio_spi_type); enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -466,6 +466,7 @@ MP_PROPERTY_GETTER(busio_spi_frequency_obj, static const mp_rom_map_elem_t busio_spi_locals_dict_table[] = { #if CIRCUITPY_BUSIO_SPI { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&busio_spi_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&busio_spi_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index 69e582411a1..34f34c927f6 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -22,6 +22,10 @@ extern void common_hal_busio_spi_construct(busio_spi_obj_t *self, extern void common_hal_busio_spi_deinit(busio_spi_obj_t *self); extern bool common_hal_busio_spi_deinited(busio_spi_obj_t *self); +// Mark as deinit without deiniting. This is used by displayio after copying the +// object elsewhere and prevents the heap from deiniting the object. +extern void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self); + extern bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits); extern bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self); diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index e6d8453eae1..26892a79462 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -9,7 +9,8 @@ #include "py/objarray.h" #include "shared-bindings/sdcardio/SDCard.h" -#include "shared-module/sdcardio/SDCard.h" +#include "shared-bindings/util.h" + #include "common-hal/busio/SPI.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/microcontroller/Pin.h" @@ -58,6 +59,12 @@ //| os.listdir('/sd')""" //| +static void check_for_deinit(sdcardio_sdcard_obj_t *self) { + if (common_hal_sdcardio_sdcard_deinited(self)) { + raise_deinited_error(); + } +} + static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_spi, ARG_cs, ARG_baudrate, NUM_ARGS }; static const mp_arg_t allowed_args[] = { @@ -72,7 +79,7 @@ static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj, MP_QSTR_spi); const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); - sdcardio_sdcard_obj_t *self = mp_obj_malloc(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type); + sdcardio_sdcard_obj_t *self = mp_obj_malloc_with_finaliser(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type); common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int); @@ -89,6 +96,7 @@ static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg //| static mp_obj_t sdcardio_sdcard_count(mp_obj_t self_in) { sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); return mp_obj_new_int_from_ull(common_hal_sdcardio_sdcard_get_blockcount(self)); } MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_count_obj, sdcardio_sdcard_count); @@ -116,10 +124,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_deinit_obj, sdcardio_sdcard_deinit); //| static mp_obj_t _sdcardio_sdcard_readblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); + uint32_t start_block = mp_obj_get_int(start_block_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_WRITE); - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; int result = common_hal_sdcardio_sdcard_readblocks(self, start_block, &bufinfo); if (result < 0) { mp_raise_OSError(-result); @@ -137,6 +147,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_readblocks_obj, _sdcardio_sdcard_readb //| static mp_obj_t sdcardio_sdcard_sync(mp_obj_t self_in) { sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); int result = common_hal_sdcardio_sdcard_sync(self); if (result < 0) { mp_raise_OSError(-result); @@ -158,10 +169,12 @@ MP_DEFINE_CONST_FUN_OBJ_1(sdcardio_sdcard_sync_obj, sdcardio_sdcard_sync); //| static mp_obj_t _sdcardio_sdcard_writeblocks(mp_obj_t self_in, mp_obj_t start_block_in, mp_obj_t buf_in) { + sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; + check_for_deinit(self); + uint32_t start_block = mp_obj_get_int(start_block_in); mp_buffer_info_t bufinfo; mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); - sdcardio_sdcard_obj_t *self = (sdcardio_sdcard_obj_t *)self_in; int result = common_hal_sdcardio_sdcard_writeblocks(self, start_block, &bufinfo); if (result < 0) { mp_raise_OSError(-result); @@ -173,6 +186,7 @@ MP_DEFINE_CONST_FUN_OBJ_3(sdcardio_sdcard_writeblocks_obj, _sdcardio_sdcard_writ static const mp_rom_map_elem_t sdcardio_sdcard_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&sdcardio_sdcard_count_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&sdcardio_sdcard_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_readblocks), MP_ROM_PTR(&sdcardio_sdcard_readblocks_obj) }, { MP_ROM_QSTR(MP_QSTR_sync), MP_ROM_PTR(&sdcardio_sdcard_sync_obj) }, { MP_ROM_QSTR(MP_QSTR_writeblocks), MP_ROM_PTR(&sdcardio_sdcard_writeblocks_obj) }, diff --git a/shared-bindings/sdcardio/SDCard.h b/shared-bindings/sdcardio/SDCard.h index ac27b47aa4d..95998f5af5e 100644 --- a/shared-bindings/sdcardio/SDCard.h +++ b/shared-bindings/sdcardio/SDCard.h @@ -13,7 +13,9 @@ extern const mp_obj_type_t sdcardio_SDCard_type; void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *cs, int baudrate); void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self); +bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); +void common_hal_sdcardio_sdcard_mark_deinit(sdcardio_sdcard_obj_t *self); int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index f3444241b3c..3ffd4d002f5 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -13,6 +13,7 @@ #include "py/runtime.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/SPI.h" #include "shared-bindings/displayio/Bitmap.h" #include "shared-bindings/displayio/Group.h" #include "shared-bindings/displayio/Palette.h" @@ -221,6 +222,7 @@ void reset_displays(void) { #endif memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t)); fourwire->bus = &fourwire->inline_bus; + // Check for other display buses that use the same spi bus and swap them too. for (uint8_t j = i + 1; j < CIRCUITPY_DISPLAY_LIMIT; j++) { if (display_buses[j].fourwire_bus.base.type == &fourwire_fourwire_type && @@ -228,6 +230,8 @@ void reset_displays(void) { display_buses[j].fourwire_bus.bus = &fourwire->inline_bus; } } + // Mark the old SPI object so it is considered deinit. + common_hal_busio_spi_mark_deinit(original_spi); } #endif #if CIRCUITPY_I2CDISPLAYBUS diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index bd3ea62d141..878fed7a13c 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -32,18 +32,41 @@ #define TOKEN_STOP_TRAN (0xFD) #define TOKEN_DATA (0xFE) +bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self) { + // Also check SPI bus was deinited out from under us. + if (!self->bus || common_hal_busio_spi_deinited(self->bus)) { + return true; + } + return false; +} + +void common_hal_sdcardio_sdcard_mark_deinit(sdcardio_sdcard_obj_t *self) { + self->bus = NULL; +} + static void common_hal_sdcardio_check_for_deinit(sdcardio_sdcard_obj_t *self) { - if (!self->bus) { + if (common_hal_sdcardio_sdcard_deinited(self)) { raise_deinited_error(); } } static bool lock_and_configure_bus(sdcardio_sdcard_obj_t *self) { + if (common_hal_sdcardio_sdcard_deinited(self)) { + return false; + } common_hal_sdcardio_check_for_deinit(self); if (!common_hal_busio_spi_try_lock(self->bus)) { return false; } + + // Make sure we can still use the SPI bus after grabbing the lock. + // The VM might be in the process of shutting down, and there could be a race. + if (!vm_is_running() && !self->persistent_mount) { + common_hal_busio_spi_unlock(self->bus); + return false; + } + common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); common_hal_digitalio_digitalinout_set_value(&self->cs, false); return true; @@ -97,7 +120,7 @@ static int wait_for_ready(sdcardio_sdcard_obj_t *self) { } // Note: this is never called while "in cmd25" (in fact, it's only used by `exit_cmd25`) -static bool cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { +static int cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { uint8_t cmdbuf[2] = {cmd, 0xff}; assert(!self->in_cmd25); @@ -111,7 +134,7 @@ static bool cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { return 0; } } - return -EIO; + return -MP_EIO; } @@ -160,7 +183,7 @@ static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf } if (!response_received) { - return -EIO; + return -MP_EIO; } if (response_buf) { @@ -294,13 +317,16 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { return NULL; } -mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate) { +mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate, bool persistent_mount) { self->bus = bus; + self->persistent_mount = persistent_mount; common_hal_digitalio_digitalinout_construct(&self->cs, cs); common_hal_digitalio_digitalinout_switch_to_output(&self->cs, true, DRIVE_MODE_PUSH_PULL); self->cdv = 512; self->sectors = 0; + + // During initialization, talk to the SPI card between 100 khZ and 400 kHz. After that, can use full speed. self->baudrate = 250000; lock_bus_or_throw(self); @@ -318,18 +344,19 @@ mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate) { - mp_rom_error_text_t result = sdcardio_sdcard_construct(self, bus, cs, baudrate); + // User mounted, so persistent_mount=false. + mp_rom_error_text_t result = sdcardio_sdcard_construct(self, bus, cs, baudrate, false); if (result != NULL) { mp_raise_OSError_msg(result); } } void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self) { - if (!self->bus) { + if (common_hal_sdcardio_sdcard_deinited(self)) { return; } common_hal_sdcardio_sdcard_sync(self); - self->bus = 0; + common_hal_sdcardio_sdcard_mark_deinit(self); common_hal_digitalio_digitalinout_deinit(&self->cs); } @@ -428,7 +455,7 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]); if ((cmd[0] & 0b00010001) == 0b00000001) { if ((cmd[0] & 0x1f) != 0x5) { - return -EIO; + return -MP_EIO; } else { break; } @@ -489,14 +516,10 @@ int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) { } int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { - // deinit check is in lock_and_configure_bus() if (buf->len % 512 != 0) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512); } - lock_and_configure_bus(self); - int r = sdcardio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), buf->buf, start_block, buf->len / 512); - extraclock_and_unlock_bus(self); - return r; + return sdcardio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), buf->buf, start_block, buf->len / 512); } bool sdcardio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *out_value) { @@ -504,11 +527,8 @@ bool sdcardio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *o *out_value = 0; switch (cmd) { case MP_BLOCKDEV_IOCTL_DEINIT: - common_hal_sdcardio_sdcard_sync(self); - break; // TODO properly case MP_BLOCKDEV_IOCTL_SYNC: - common_hal_sdcardio_sdcard_sync(self); - break; + return common_hal_sdcardio_sdcard_sync(self) == 0; case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: *out_value = common_hal_sdcardio_sdcard_get_blockcount(self); break; diff --git a/shared-module/sdcardio/SDCard.h b/shared-module/sdcardio/SDCard.h index f9cd64b8125..35a9ed1bf3c 100644 --- a/shared-module/sdcardio/SDCard.h +++ b/shared-module/sdcardio/SDCard.h @@ -23,6 +23,9 @@ typedef struct { uint32_t sectors; uint32_t next_block; bool in_cmd25; + // Automounted SD cards are usually persistent across VM's. Note this as needed to allow access + // when the VM is not running. + bool persistent_mount; } sdcardio_sdcard_obj_t; -mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate); +mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate, bool persistent_mount); diff --git a/shared-module/sdcardio/__init__.c b/shared-module/sdcardio/__init__.c index 29c890c6870..4a7a4d500cc 100644 --- a/shared-module/sdcardio/__init__.c +++ b/shared-module/sdcardio/__init__.c @@ -22,7 +22,7 @@ static mp_vfs_mount_t _sdcard_vfs; fs_user_mount_t _sdcard_usermount; static bool _init_error = false; -static bool _mounted = false; +static bool _automounted = false; #ifdef DEFAULT_SD_MOSI static busio_spi_obj_t busio_spi_obj; @@ -45,7 +45,7 @@ void automount_sd_card(void) { if (common_hal_digitalio_digitalinout_get_value(&sd_card_detect_pin) != DEFAULT_SD_CARD_INSERTED) { // No card. _init_error = false; - if (_mounted) { + if (_automounted) { // Unmount the card. mp_vfs_mount_t *cur = MP_STATE_VM(vfs_mount_table); if (cur == &_sdcard_vfs) { @@ -63,11 +63,11 @@ void automount_sd_card(void) { #ifdef DEFAULT_SD_MOSI common_hal_busio_spi_deinit(&busio_spi_obj); #endif - _mounted = false; + _automounted = false; } return; - } else if (_init_error || _mounted) { - // We've already tried and failed to init the card. Don't try again. + } else if (_init_error || _automounted) { + // We've already tried and failed to init the card, or it's still mounted. Don't try again. return; } @@ -81,10 +81,10 @@ void automount_sd_card(void) { common_hal_busio_spi_never_reset(spi_obj); #endif sdcard.base.type = &sdcardio_SDCard_type; - mp_rom_error_text_t error = sdcardio_sdcard_construct(&sdcard, spi_obj, DEFAULT_SD_CS, 25000000); + mp_rom_error_text_t error = sdcardio_sdcard_construct(&sdcard, spi_obj, DEFAULT_SD_CS, 25000000, true); if (error != NULL) { // Failed to communicate with the card. - _mounted = false; + _automounted = false; _init_error = true; #ifdef DEFAULT_SD_MOSI common_hal_busio_spi_deinit(spi_obj); @@ -104,7 +104,7 @@ void automount_sd_card(void) { // mount the block device so the VFS methods can be used FRESULT res = f_mount(&vfs->fatfs); if (res != FR_OK) { - _mounted = false; + _automounted = false; _init_error = true; common_hal_sdcardio_sdcard_deinit(&sdcard); #ifdef DEFAULT_SD_MOSI @@ -122,6 +122,6 @@ void automount_sd_card(void) { sdcard_vfs->obj = MP_OBJ_FROM_PTR(&_sdcard_usermount); sdcard_vfs->next = MP_STATE_VM(vfs_mount_table); MP_STATE_VM(vfs_mount_table) = sdcard_vfs; - _mounted = true; + _automounted = true; #endif // DEFAULT_SD_CARD_DETECT } diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index febede876bb..adc18249761 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -5,7 +5,6 @@ // SPDX-License-Identifier: MIT #include "tusb.h" -// // #include "supervisor/flash.h" // For updating fatfs's cache #include "extmod/vfs.h" @@ -14,6 +13,7 @@ #include "lib/oofatfs/ff.h" #include "py/gc.h" #include "py/mpstate.h" +#include "py/runtime.h" #include "shared-module/storage/__init__.h" #include "supervisor/filesystem.h" @@ -28,7 +28,7 @@ #define SAVES_COUNT 0 #endif -#if CIRCUITPY_SDCARDIO +#if CIRCUITPY_SDCARD_USB #include "shared-module/sdcardio/__init__.h" #define SDCARD_COUNT 1 @@ -137,7 +137,8 @@ static fs_user_mount_t *get_vfs(int lun) { if (lun == SAVES_LUN) { const char *path_under_mount; fs_user_mount_t *saves = filesystem_for_path("/saves", &path_under_mount); - if (saves != root && (saves->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0 && !gc_ptr_on_heap(saves)) { + if (saves != root && + (saves->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0 && !gc_ptr_on_heap(saves)) { return saves; } } @@ -146,8 +147,15 @@ static fs_user_mount_t *get_vfs(int lun) { if (lun == SDCARD_LUN) { const char *path_under_mount; fs_user_mount_t *sdcard = filesystem_for_path("/sd", &path_under_mount); - // If "/sd" is on the root filesystem, nothing has been mounted there. - if (sdcard != root && (sdcard->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0) { + // If sdcard ("/sd") is on the root filesystem, nothing has been mounted there, so don't + // return it as a separate filesystem. + // If the SD card was automounted at startup, then it persists across VMs and its fs_user_mount_t is + // not on the heap. + // If the SD card filesystem was mounted by the user using heap objects, + // it should not be used when the VM has stopped running. + if ((sdcard != root) && + ((sdcard->blockdev.flags & MP_BLOCKDEV_FLAG_NATIVE) != 0) && + (vm_is_running() || !gc_ptr_on_heap(sdcard))) { return sdcard; } else { // Clear any ejected state so that a re-insert causes it to reappear. @@ -359,7 +367,7 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { return false; } - #if CIRCUITPY_SDCARD_USB + #ifdef SDCARD_LUN if (lun == SDCARD_LUN) { automount_sd_card(); } From 2800777933166cf35ead80ec11743deb6ca79dfa Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 31 Oct 2025 14:50:34 -0400 Subject: [PATCH 078/876] remove local tracking of never_reset in all common-hal/busio/SPI.c --- ports/analog/common-hal/busio/SPI.c | 3 --- ports/broadcom/common-hal/busio/SPI.c | 4 ---- ports/espressif/common-hal/busio/SPI.c | 3 --- ports/espressif/supervisor/port.c | 2 +- ports/mimxrt10xx/common-hal/busio/SPI.c | 3 --- ports/nordic/common-hal/busio/SPI.c | 4 ---- ports/raspberrypi/common-hal/busio/SPI.c | 5 ----- ports/silabs/common-hal/busio/SPI.c | 2 -- ports/stm/common-hal/busio/SPI.c | 3 --- 9 files changed, 1 insertion(+), 28 deletions(-) diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index a9bf4aad8df..de3856b23b3 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -42,7 +42,6 @@ typedef enum { SPI_FREE = 0, SPI_BUSY, - SPI_NEVER_RESET, } spi_status_t; // Set each bit to indicate an active SPI @@ -121,8 +120,6 @@ void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { common_hal_never_reset_pin(self->miso); common_hal_never_reset_pin(self->sck); common_hal_never_reset_pin(self->nss); - - spi_status[self->spi_id] = SPI_NEVER_RESET; } // Check SPI status, deinited or not diff --git a/ports/broadcom/common-hal/busio/SPI.c b/ports/broadcom/common-hal/busio/SPI.c index 01d61ba9d1d..9e4834e86f3 100644 --- a/ports/broadcom/common-hal/busio/SPI.c +++ b/ports/broadcom/common-hal/busio/SPI.c @@ -30,7 +30,6 @@ static SPI0_Type *spi[NUM_SPI] = {SPI0, NULL, NULL}; static SPI1_Type *aux_spi[NUM_SPI] = {NULL, SPI1, SPI2}; #endif -static bool never_reset_spi[NUM_SPI]; static bool spi_in_use[NUM_SPI]; void common_hal_busio_spi_construct(busio_spi_obj_t *self, @@ -99,8 +98,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->index] = true; - common_hal_never_reset_pin(self->clock); common_hal_never_reset_pin(self->MOSI); common_hal_never_reset_pin(self->MISO); @@ -118,7 +115,6 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } - never_reset_spi[self->index] = false; common_hal_reset_pin(self->clock); common_hal_reset_pin(self->MOSI); diff --git a/ports/espressif/common-hal/busio/SPI.c b/ports/espressif/common-hal/busio/SPI.c index 3db4c770190..4c07917b20b 100644 --- a/ports/espressif/common-hal/busio/SPI.c +++ b/ports/espressif/common-hal/busio/SPI.c @@ -16,7 +16,6 @@ #define SPI_MAX_DMA_BITS (SPI_MAX_DMA_LEN * 8) #define MAX_SPI_TRANSACTIONS 10 -static bool spi_never_reset[SOC_SPI_PERIPH_NUM]; static spi_device_handle_t spi_handle[SOC_SPI_PERIPH_NUM]; static bool spi_bus_is_free(spi_host_device_t host_id) { @@ -107,7 +106,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - spi_never_reset[self->host_id] = true; common_hal_never_reset_pin(self->clock); if (self->MOSI != NULL) { common_hal_never_reset_pin(self->MOSI); @@ -139,7 +137,6 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { common_hal_reset_pin(self->clock); common_hal_busio_spi_mark_deinit(self); - spi_never_reset[self->host_id] = false; spi_bus_remove_device(spi_handle[self->host_id]); spi_bus_free(self->host_id); diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index b67fae426b7..c629eb52932 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -414,7 +414,7 @@ void reset_to_bootloader(void) { } void reset_cpu(void) { - #if CIRCUITPY_DEBUG || 1 + #if CIRCUITPY_DEBUG esp_backtrace_print(100); #endif esp_restart(); diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.c b/ports/mimxrt10xx/common-hal/busio/SPI.c index 9b988e0d15e..90695be4b4e 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.c +++ b/ports/mimxrt10xx/common-hal/busio/SPI.c @@ -26,7 +26,6 @@ // arrays use 0 based numbering: SPI1 is stored at index 0 static bool reserved_spi[MP_ARRAY_SIZE(mcu_spi_banks)]; -static bool never_reset_spi[MP_ARRAY_SIZE(mcu_spi_banks)]; #if IMXRT11XX static const clock_ip_name_t s_lpspiClocks[] = LPSPI_CLOCKS; @@ -187,7 +186,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->clock->bank_idx - 1] = true; common_hal_never_reset_pin(self->clock->pin); if (self->mosi != NULL) { common_hal_never_reset_pin(self->mosi->pin); @@ -211,7 +209,6 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } LPSPI_Deinit(self->spi); reserved_spi[self->clock->bank_idx - 1] = false; - never_reset_spi[self->clock->bank_idx - 1] = false; common_hal_reset_pin(self->clock->pin); common_hal_reset_pin(self->mosi->pin); diff --git a/ports/nordic/common-hal/busio/SPI.c b/ports/nordic/common-hal/busio/SPI.c index b4fc887aa34..de54dd08a27 100644 --- a/ports/nordic/common-hal/busio/SPI.c +++ b/ports/nordic/common-hal/busio/SPI.c @@ -59,8 +59,6 @@ static const spim_peripheral_t spim_peripherals[] = { #endif }; -static bool never_reset[MP_ARRAY_SIZE(spim_peripherals)]; - // Separate RAM area for SPIM3 transmit buffer to avoid SPIM3 hardware errata. // https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52840_Rev2%2FERR%2FnRF52840%2FRev2%2Flatest%2Fanomaly_840_198.html static uint8_t *spim3_transmit_buffer = (uint8_t *)SPIM3_BUFFER_RAM_START_ADDR; @@ -68,8 +66,6 @@ static uint8_t *spim3_transmit_buffer = (uint8_t *)SPIM3_BUFFER_RAM_START_ADDR; void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { for (size_t i = 0; i < MP_ARRAY_SIZE(spim_peripherals); i++) { if (self->spim_peripheral == &spim_peripherals[i]) { - never_reset[i] = true; - never_reset_pin_number(self->clock_pin_number); never_reset_pin_number(self->MOSI_pin_number); never_reset_pin_number(self->MISO_pin_number); diff --git a/ports/raspberrypi/common-hal/busio/SPI.c b/ports/raspberrypi/common-hal/busio/SPI.c index 21af168df3b..aeb06d919ae 100644 --- a/ports/raspberrypi/common-hal/busio/SPI.c +++ b/ports/raspberrypi/common-hal/busio/SPI.c @@ -19,8 +19,6 @@ #define NO_INSTANCE 0xff -static bool never_reset_spi[2]; - void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { @@ -88,8 +86,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[spi_get_index(self->peripheral)] = true; - common_hal_never_reset_pin(self->clock); common_hal_never_reset_pin(self->MOSI); common_hal_never_reset_pin(self->MISO); @@ -107,7 +103,6 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return; } - never_reset_spi[spi_get_index(self->peripheral)] = false; spi_deinit(self->peripheral); common_hal_reset_pin(self->clock); diff --git a/ports/silabs/common-hal/busio/SPI.c b/ports/silabs/common-hal/busio/SPI.c index fcff2031fa2..fb3b7c4fd20 100644 --- a/ports/silabs/common-hal/busio/SPI.c +++ b/ports/silabs/common-hal/busio/SPI.c @@ -37,7 +37,6 @@ static SPIDRV_HandleData_t spidrv_eusart_handle; static SPIDRV_Init_t spidrv_eusart_init = SPIDRV_MASTER_EUSART1; static bool in_used = false; -static bool never_reset = false; // Construct SPI protocol, this function init SPI peripheral void common_hal_busio_spi_construct(busio_spi_obj_t *self, @@ -102,7 +101,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Never reset SPI when reload void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset = true; common_hal_never_reset_pin(self->mosi); common_hal_never_reset_pin(self->miso); common_hal_never_reset_pin(self->sck); diff --git a/ports/stm/common-hal/busio/SPI.c b/ports/stm/common-hal/busio/SPI.c index 347e94bef9f..1b86a9f55d5 100644 --- a/ports/stm/common-hal/busio/SPI.c +++ b/ports/stm/common-hal/busio/SPI.c @@ -19,7 +19,6 @@ #define MAX_SPI 6 static bool reserved_spi[MAX_SPI]; -static bool never_reset_spi[MAX_SPI]; #define ALL_CLOCKS 0xFF static void spi_clock_enable(uint8_t mask); @@ -215,7 +214,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { - never_reset_spi[self->sck->periph_index - 1] = true; never_reset_pin_number(self->sck->pin->port, self->sck->pin->number); if (self->mosi != NULL) { never_reset_pin_number(self->mosi->pin->port, self->mosi->pin->number); @@ -239,7 +237,6 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } spi_clock_disable(1 << (self->sck->periph_index - 1)); reserved_spi[self->sck->periph_index - 1] = false; - never_reset_spi[self->sck->periph_index - 1] = false; reset_pin_number(self->sck->pin->port, self->sck->pin->number); if (self->mosi != NULL) { From 85e145f203d1d2f1cef2169b1af7103430d156a8 Mon Sep 17 00:00:00 2001 From: chinh4thepro Date: Sun, 2 Nov 2025 00:46:55 -0400 Subject: [PATCH 079/876] ports/espressif: add pins for seeed xiao esp32s3 plus board ports/espressif/boards: add pins for seeed xiao esp32s3 plus --- .../seeed_xiao_esp32_s3_sense/mpconfigboard.h | 10 +++++----- .../boards/seeed_xiao_esp32_s3_sense/pins.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/mpconfigboard.h b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/mpconfigboard.h index c05b6a93a10..d7f24b255d6 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/mpconfigboard.h +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/mpconfigboard.h @@ -12,9 +12,9 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) -#define DEFAULT_SPI_BUS_SCK (&pin_GPIO7) -#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO9) -#define DEFAULT_SPI_BUS_MISO (&pin_GPIO8) +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO7) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO9) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO8) -#define DEFAULT_I2C_BUS_SCL (&pin_GPIO6) -#define DEFAULT_I2C_BUS_SDA (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO6) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO5) diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c index aa3a6f7b7f5..8269f1d7a95 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c @@ -48,15 +48,30 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO11) }, { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_TX_1), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_RX_1), MP_ROM_PTR(&pin_GPIO41) }, { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_MOSI_1), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_MISO_1), MP_ROM_PTR(&pin_GPIO12) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SCK_1), MP_ROM_PTR(&pin_GPIO13) }, { MP_ROM_QSTR(MP_QSTR_SDCS), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_CAM_DATA), MP_ROM_PTR(&camera_data_tuple) }, { MP_ROM_QSTR(MP_QSTR_CAM_D0), MP_ROM_PTR(&pin_GPIO15) }, { MP_ROM_QSTR(MP_QSTR_CAM_D1), MP_ROM_PTR(&pin_GPIO17) }, @@ -74,6 +89,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_CAM_SDA), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_MIC_DATA), MP_ROM_PTR(&pin_GPIO41) }, { MP_ROM_QSTR(MP_QSTR_MIC_CLK), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SD), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WS), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, From 4c4a1888b09e02ca08f0d4b76f9b2aac3db3a627 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 17 Oct 2025 12:36:18 -0700 Subject: [PATCH 080/876] Add mipidsi module for MIPI DSI displays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds support for MIPI DSI (Display Serial Interface) displays via a new mipidsi module. This enables high-speed serial communication with DSI displays using differential signaling. The module provides: - Bus class: Manages DSI bus with 1-4 data lanes - Display class: Handles display configuration and framebuffer Module is: - Disabled by default globally - Enabled only for ESP32-P4 (has hardware MIPI-DSI support) 🤖 Initial code generated with [Claude Code](https://claude.com/claude-code) and then hand improved. Co-Authored-By: Claude --- locale/circuitpython.pot | 17 +- ports/espressif/Makefile | 17 +- .../mpconfigboard.h | 7 +- .../espressif_esp32p4_function_ev/pins.c | 93 +++--- ports/espressif/boards/m5stack_tab5/board.c | 9 + .../boards/m5stack_tab5/mpconfigboard.h | 28 ++ .../boards/m5stack_tab5/mpconfigboard.mk | 14 + ports/espressif/boards/m5stack_tab5/pins.c | 128 ++++++++ ports/espressif/boards/m5stack_tab5/sdkconfig | 0 .../common-hal/microcontroller/Pin.c | 15 +- ports/espressif/common-hal/mipidsi/Bus.c | 52 ++++ ports/espressif/common-hal/mipidsi/Bus.h | 17 ++ ports/espressif/common-hal/mipidsi/Display.c | 254 +++++++++++++++ ports/espressif/common-hal/mipidsi/Display.h | 37 +++ ports/espressif/common-hal/mipidsi/__init__.c | 7 + ports/espressif/common-hal/mipidsi/__init__.h | 7 + ports/espressif/mpconfigport.mk | 3 + ports/espressif/supervisor/port.c | 2 +- py/circuitpy_defns.mk | 6 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/mipidsi/Bus.c | 96 ++++++ shared-bindings/mipidsi/Bus.h | 15 + shared-bindings/mipidsi/Display.c | 289 ++++++++++++++++++ shared-bindings/mipidsi/Display.h | 44 +++ shared-bindings/mipidsi/__init__.c | 30 ++ shared-bindings/mipidsi/__init__.h | 7 + shared-module/displayio/__init__.h | 6 + 27 files changed, 1153 insertions(+), 50 deletions(-) create mode 100644 ports/espressif/boards/m5stack_tab5/board.c create mode 100644 ports/espressif/boards/m5stack_tab5/mpconfigboard.h create mode 100644 ports/espressif/boards/m5stack_tab5/mpconfigboard.mk create mode 100644 ports/espressif/boards/m5stack_tab5/pins.c create mode 100644 ports/espressif/boards/m5stack_tab5/sdkconfig create mode 100644 ports/espressif/common-hal/mipidsi/Bus.c create mode 100644 ports/espressif/common-hal/mipidsi/Bus.h create mode 100644 ports/espressif/common-hal/mipidsi/Display.c create mode 100644 ports/espressif/common-hal/mipidsi/Display.h create mode 100644 ports/espressif/common-hal/mipidsi/__init__.c create mode 100644 ports/espressif/common-hal/mipidsi/__init__.h create mode 100644 shared-bindings/mipidsi/Bus.c create mode 100644 shared-bindings/mipidsi/Bus.h create mode 100644 shared-bindings/mipidsi/Display.c create mode 100644 shared-bindings/mipidsi/Display.h create mode 100644 shared-bindings/mipidsi/__init__.c create mode 100644 shared-bindings/mipidsi/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1e167c30353..35fc94513a5 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -159,10 +159,6 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "" - #: py/argcheck.c msgid "%q must be %d" msgstr "" @@ -838,6 +834,10 @@ msgstr "" msgid "Clock unit in use" msgstr "" +#: ports/espressif/common-hal/mipidsi/Display.c +msgid "Color depth must be 16 or 24" +msgstr "" + #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -932,6 +932,7 @@ msgstr "" #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -1276,7 +1277,8 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c #: shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c @@ -2266,6 +2268,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -3174,10 +3177,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index b6ddc27e408..8302726aad7 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -76,6 +76,7 @@ INC += \ -isystem esp-idf/components/esp_driver_uart/include \ -isystem esp-idf/components/esp_event/include \ -isystem esp-idf/components/esp_hw_support/dma/include \ + -isystem esp-idf/components/esp_hw_support/ldo/include \ -isystem esp-idf/components/esp_hw_support/include \ -isystem esp-idf/components/esp_hw_support/include/soc \ -isystem esp-idf/components/esp_hw_support/port/$(IDF_TARGET)/private_include \ @@ -171,7 +172,8 @@ REGISTRATION_FUNCTIONS = \ -u esp_libc_init_funcs \ -u include_esp_phy_override \ -u vfs_include_syscalls_impl \ - -u esp_vfs_include_nullfs_register + -u esp_vfs_include_nullfs_register \ + -u usb_serial_jtag_vfs_include_dev_init #Debugging/Optimization @@ -329,7 +331,8 @@ LDFLAGS += \ CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_driver_usb_serial_jtag else ifeq ($(IDF_TARGET),esp32h2) LDFLAGS += \ @@ -467,6 +470,13 @@ CFLAGS += \ -isystem esp-idf/components/esp_lcd/rgb/include endif +ifneq ($(CIRCUITPY_MIPIDSI),0) +CFLAGS += \ + -isystem esp-idf/components/esp_lcd/include \ + -isystem esp-idf/components/esp_lcd/interface \ + -isystem esp-idf/components/esp_lcd/dsi/include +endif + ifneq ($(CIRCUITPY_ESPCAMERA),0) SRC_CAMERA := \ $(wildcard common-hal/espcamera/*.c) \ @@ -757,6 +767,9 @@ endif ifneq ($(CIRCUITPY_DOTCLOCKFRAMEBUFFER),0) ESP_IDF_COMPONENTS_LINK += esp_lcd endif +ifneq ($(CIRCUITPY_MIPIDSI),0) + ESP_IDF_COMPONENTS_LINK += esp_lcd +endif ifneq ($(CIRCUITPY_PARALLELDISPLAYBUS),0) ESP_IDF_COMPONENTS_LINK += esp_lcd endif diff --git a/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h b/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h index 646fb62e562..1bbf3a250fc 100644 --- a/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h +++ b/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -16,5 +16,10 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO38) #define DEFAULT_UART_BUS_TX (&pin_GPIO37) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO8) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO7) + // Use the second USB device (numbered 0 and 1) #define CIRCUITPY_USB_DEVICE_INSTANCE 1 + +#define CIRCUITPY_USB_HOST_INSTANCE 0 diff --git a/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c b/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c index 3bb64f434d0..7a3026f914d 100644 --- a/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c +++ b/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -9,47 +9,72 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, - { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, - { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, - { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, - { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + // Header Block J1 + { MP_ROM_QSTR(MP_QSTR_I2C_SDA), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_I2C_SCL), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, - { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, - { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, - { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, - { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, - { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, - { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, - { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, - { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, - { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, - { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, - { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO37) }, { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO38) }, { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, - { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, - { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, - { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, - { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, - { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, - { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, - { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_C6_WAKEUP), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_IO32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_C6_EN), MP_ROM_PTR(&pin_GPIO54) }, + { MP_ROM_QSTR(MP_QSTR_IO54), MP_ROM_PTR(&pin_GPIO54) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + + { MP_ROM_QSTR(MP_QSTR_PA_CTRL), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_IO53), MP_ROM_PTR(&pin_GPIO53) }, { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, - { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, - { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + + // I2S + { MP_ROM_QSTR(MP_QSTR_I2S_DSDIN), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2S_ASDOUT), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCLK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_ROM_PTR(&pin_GPIO13) }, + + // Ethernet + { MP_ROM_QSTR(MP_QSTR_RMII_RXDV), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_RMII_RXD0), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_RMII_RXD1), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_MDC), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXD0), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXD1), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXEN), MP_ROM_PTR(&pin_GPIO49) }, + { MP_ROM_QSTR(MP_QSTR_RMII_CLK), MP_ROM_PTR(&pin_GPIO50) }, + { MP_ROM_QSTR(MP_QSTR_PHY_RSTN), MP_ROM_PTR(&pin_GPIO51) }, + { MP_ROM_QSTR(MP_QSTR_MDIO), MP_ROM_PTR(&pin_GPIO52) }, - { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, - { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + // SD Card + { MP_ROM_QSTR(MP_QSTR_SD_DATA0), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA1), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA2), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA3), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_SD_PWRN), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/m5stack_tab5/board.c b/ports/espressif/boards/m5stack_tab5/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/m5stack_tab5/mpconfigboard.h b/ports/espressif/boards/m5stack_tab5/mpconfigboard.h new file mode 100644 index 00000000000..f85f1fe24b8 --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/mpconfigboard.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "M5Stack Tab5" +#define MICROPY_HW_MCU_NAME "ESP32P4" + +// I2C bus for touch, IMU, RTC, power monitor, and GPIO expanders +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO32, .sda = &pin_GPIO31}} + +// UART +#define DEFAULT_UART_BUS_RX (&pin_GPIO38) +#define DEFAULT_UART_BUS_TX (&pin_GPIO37) + +// SPI on M5-Bus +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO5) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO19) + +// Use the second USB device (numbered 0 and 1) +#define CIRCUITPY_USB_DEVICE_INSTANCE 1 diff --git a/ports/espressif/boards/m5stack_tab5/mpconfigboard.mk b/ports/espressif/boards/m5stack_tab5/mpconfigboard.mk new file mode 100644 index 00000000000..4871a259e7a --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x832B +USB_PRODUCT = "M5Stack Tab5" +USB_MANUFACTURER = "M5Stack" + +IDF_TARGET = esp32p4 + +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 32MB +CIRCUITPY_ESP_PSRAM_MODE = hpi +CIRCUITPY_ESP_PSRAM_FREQ = 200m diff --git a/ports/espressif/boards/m5stack_tab5/pins.c b/ports/espressif/boards/m5stack_tab5/pins.c new file mode 100644 index 00000000000..67012cc670d --- /dev/null +++ b/ports/espressif/boards/m5stack_tab5/pins.c @@ -0,0 +1,128 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // M5-Bus and general GPIO + { MP_ROM_QSTR(MP_QSTR_G2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_G3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_G4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_G6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_G7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_G16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_G17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_G35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_G45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_G47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_G48), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_G51), MP_ROM_PTR(&pin_GPIO51) }, + { MP_ROM_QSTR(MP_QSTR_G52), MP_ROM_PTR(&pin_GPIO52) }, + + // SPI (on M5-Bus) + { MP_ROM_QSTR(MP_QSTR_G5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_G18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_G19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO19) }, + + // UART (on M5-Bus) + { MP_ROM_QSTR(MP_QSTR_G37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TXD0), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_G38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_RXD0), MP_ROM_PTR(&pin_GPIO38) }, + + // I2C (Touch, IMU, RTC, Power Monitor, GPIO Expanders) + { MP_ROM_QSTR(MP_QSTR_G31), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_G32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO32) }, + + // Touch Panel + { MP_ROM_QSTR(MP_QSTR_G23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_TP_INT), MP_ROM_PTR(&pin_GPIO23) }, + + // LCD + { MP_ROM_QSTR(MP_QSTR_G22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_GPIO22) }, + + // Audio ES8388/ES7210 + { MP_ROM_QSTR(MP_QSTR_G26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DSDIN), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_G27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCLK), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_G28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_I2S_ASDOUT), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_G29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCK), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_G30), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_ROM_PTR(&pin_GPIO30) }, + + // Camera + { MP_ROM_QSTR(MP_QSTR_G36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_CAM_MCLK), MP_ROM_PTR(&pin_GPIO36) }, + + // microSD Card (SDIO mode) + { MP_ROM_QSTR(MP_QSTR_G39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT0), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_G40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT1), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_G41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT2), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_G42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_DAT3), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_G43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_G44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO44) }, + + // RS485 + { MP_ROM_QSTR(MP_QSTR_G20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_RS485_TX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_G21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_RS485_RX), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_G34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_RS485_DIR), MP_ROM_PTR(&pin_GPIO34) }, + + // HY2.0-4P PORT.A + { MP_ROM_QSTR(MP_QSTR_G53), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_Y), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_G54), MP_ROM_PTR(&pin_GPIO54) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_W), MP_ROM_PTR(&pin_GPIO54) }, + + // ESP32-C6 SDIO interface + { MP_ROM_QSTR(MP_QSTR_G8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_D3), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_G9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_D2), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_G10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_D1), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_G11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_D0), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_G12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_CK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_G13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_C6_SDIO2_CMD), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_G14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_C6_IO2), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_G15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_C6_RESET), MP_ROM_PTR(&pin_GPIO15) }, + + // I2C and SPI objects + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/m5stack_tab5/sdkconfig b/ports/espressif/boards/m5stack_tab5/sdkconfig new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index 922cde763e3..3ccd8dcbb69 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -77,6 +77,15 @@ static uint64_t _in_use_pin_mask; #define GPIO_SEL_47 ((uint64_t)PIN_BIT(47)) /*!< Pin 47 selected */ #define GPIO_SEL_48 ((uint64_t)PIN_BIT(48)) /*!< Pin 48 selected */ #endif +#if SOC_GPIO_PIN_COUNT > 49 +#define GPIO_SEL_49 ((uint64_t)PIN_BIT(49)) /*!< Pin 49 selected */ +#define GPIO_SEL_50 ((uint64_t)PIN_BIT(50)) /*!< Pin 50 selected */ +#define GPIO_SEL_51 ((uint64_t)PIN_BIT(51)) /*!< Pin 51 selected */ +#define GPIO_SEL_52 ((uint64_t)PIN_BIT(52)) /*!< Pin 52 selected */ +#define GPIO_SEL_53 ((uint64_t)PIN_BIT(53)) /*!< Pin 53 selected */ +#define GPIO_SEL_54 ((uint64_t)PIN_BIT(54)) /*!< Pin 54 selected */ +#define GPIO_SEL_55 ((uint64_t)PIN_BIT(55)) /*!< Pin 55 selected */ +#endif // Bit mask of all pins that should never EVER be reset. // Typically these are SPI flash and PSRAM control pins, and communication pins. @@ -202,10 +211,10 @@ static const uint64_t pin_mask_reset_forbidden = GPIO_SEL_32 | GPIO_SEL_33 | GPIO_SEL_34 | - #if CIRCUITPY_ESP_USB_SERIAL_JTAG + #if CIRCUITPY_ESP_USB_SERIAL_JTAG || (defined(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) && CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) // Never ever reset serial/JTAG communication pins. - GPIO_SEL_50 | // USB D- - GPIO_SEL_51 | // USB D+ + GPIO_SEL_24 | // USB D- + GPIO_SEL_25 | // USB D+ #endif #if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT && CONFIG_ESP_CONSOLE_UART_NUM == 0 // Never reset debug UART/console pins. diff --git a/ports/espressif/common-hal/mipidsi/Bus.c b/ports/espressif/common-hal/mipidsi/Bus.c new file mode 100644 index 00000000000..7f9dc01b773 --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/Bus.c @@ -0,0 +1,52 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/mipidsi/Bus.h" +#include "bindings/espidf/__init__.h" +#include "py/runtime.h" +#include + +void common_hal_mipidsi_bus_construct(mipidsi_bus_obj_t *self, mp_uint_t frequency, uint8_t num_lanes) { + self->frequency = frequency; + self->num_data_lanes = num_lanes; + self->bus_handle = NULL; + + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; + esp_ldo_channel_config_t ldo_mipi_phy_config = { + .chan_id = 3, + .voltage_mv = 2500, + }; + ESP_ERROR_CHECK(esp_ldo_acquire_channel(&ldo_mipi_phy_config, &ldo_mipi_phy)); + + // Create the DSI bus + esp_lcd_dsi_bus_config_t bus_config = { + .bus_id = 0, + .num_data_lanes = num_lanes, + .phy_clk_src = MIPI_DSI_PHY_CLK_SRC_DEFAULT, + .lane_bit_rate_mbps = frequency / 1000000, // Convert Hz to MHz + }; + + CHECK_ESP_RESULT(esp_lcd_new_dsi_bus(&bus_config, &self->bus_handle)); +} + +void common_hal_mipidsi_bus_deinit(mipidsi_bus_obj_t *self) { + if (common_hal_mipidsi_bus_deinited(self)) { + return; + } + + // Delete the DSI bus + if (self->bus_handle != NULL) { + esp_lcd_del_dsi_bus(self->bus_handle); + self->bus_handle = NULL; + } + + self->frequency = 0; + self->num_data_lanes = 0; +} + +bool common_hal_mipidsi_bus_deinited(mipidsi_bus_obj_t *self) { + return self->bus_handle == NULL; +} diff --git a/ports/espressif/common-hal/mipidsi/Bus.h b/ports/espressif/common-hal/mipidsi/Bus.h new file mode 100644 index 00000000000..0ffd333e52d --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/Bus.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include + +typedef struct { + mp_obj_base_t base; + mp_uint_t frequency; + esp_lcd_dsi_bus_handle_t bus_handle; + uint8_t num_data_lanes; +} mipidsi_bus_obj_t; diff --git a/ports/espressif/common-hal/mipidsi/Display.c b/ports/espressif/common-hal/mipidsi/Display.c new file mode 100644 index 00000000000..eff06f02bf7 --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/Display.c @@ -0,0 +1,254 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/mipidsi/Display.h" +#include "shared-bindings/mipidsi/Bus.h" +#include "shared-bindings/pwmio/PWMOut.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/time/__init__.h" +#include "bindings/espidf/__init__.h" +#include +#include +#include "py/runtime.h" + +// Cache write-back function (should be from rom/cache.h but it's not always available) +extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size); + +void common_hal_mipidsi_display_construct(mipidsi_display_obj_t *self, + mipidsi_bus_obj_t *bus, + const uint8_t *init_sequence, + size_t init_sequence_len, + mp_uint_t virtual_channel, + mp_uint_t width, + mp_uint_t height, + mp_int_t rotation, + mp_uint_t color_depth, + const mcu_pin_obj_t *backlight_pin, + mp_float_t brightness, + mp_uint_t native_frames_per_second, + bool backlight_on_high, + mp_uint_t hsync_pulse_width, + mp_uint_t hsync_back_porch, + mp_uint_t hsync_front_porch, + mp_uint_t vsync_pulse_width, + mp_uint_t vsync_back_porch, + mp_uint_t vsync_front_porch, + mp_uint_t pixel_clock_frequency) { + self->bus = bus; + self->virtual_channel = virtual_channel; + self->width = width; + self->height = height; + self->rotation = rotation; + self->color_depth = color_depth; + self->native_frames_per_second = native_frames_per_second; + self->backlight_on_high = backlight_on_high; + self->framebuffer = NULL; + self->dbi_io_handle = NULL; + self->dpi_panel_handle = NULL; + + // Create the DBI interface for sending commands + esp_lcd_dbi_io_config_t dbi_config = { + .virtual_channel = virtual_channel, + .lcd_cmd_bits = 8, + .lcd_param_bits = 8, + }; + + CHECK_ESP_RESULT(esp_lcd_new_panel_io_dbi(bus->bus_handle, &dbi_config, &self->dbi_io_handle)); + + // Determine the pixel format based on color depth + lcd_color_format_t color_format; + if (color_depth == 16) { + color_format = LCD_COLOR_FMT_RGB565; + } else if (color_depth == 24) { + color_format = LCD_COLOR_FMT_RGB888; + } else { + common_hal_mipidsi_display_deinit(self); + mp_raise_ValueError(MP_ERROR_TEXT("Color depth must be 16 or 24")); + } + + // Create the DPI panel for sending pixel data + esp_lcd_dpi_panel_config_t dpi_config = { + .virtual_channel = virtual_channel, + .dpi_clk_src = MIPI_DSI_DPI_CLK_SRC_DEFAULT, + .dpi_clock_freq_mhz = pixel_clock_frequency / 1000000, + .in_color_format = color_format, + .num_fbs = 1, + .video_timing = { + .h_size = width, + .v_size = height, + .hsync_pulse_width = hsync_pulse_width, + .hsync_back_porch = hsync_back_porch, + .hsync_front_porch = hsync_front_porch, + .vsync_pulse_width = vsync_pulse_width, + .vsync_back_porch = vsync_back_porch, + .vsync_front_porch = vsync_front_porch, + }, + .flags = { + .use_dma2d = false, + .disable_lp = false, + }, + }; + + esp_err_t ret = esp_lcd_new_panel_dpi(bus->bus_handle, &dpi_config, &self->dpi_panel_handle); + if (ret != ESP_OK) { + common_hal_mipidsi_display_deinit(self); + CHECK_ESP_RESULT(ret); + } + + // Get the framebuffer allocated by the driver + void *fb = NULL; + ret = esp_lcd_dpi_panel_get_frame_buffer(self->dpi_panel_handle, 1, &fb); + if (ret != ESP_OK || fb == NULL) { + common_hal_mipidsi_display_deinit(self); + CHECK_ESP_RESULT(ret); + } + + self->framebuffer = (uint8_t *)fb; + self->framebuffer_size = width * height * (color_depth / 8); + + // Send initialization sequence (format matches busdisplay) + #define DELAY 0x80 + uint32_t i = 0; + while (i < init_sequence_len) { + const uint8_t *cmd = init_sequence + i; + uint8_t data_size = *(cmd + 1); + bool delay = (data_size & DELAY) != 0; + data_size &= ~DELAY; + const uint8_t *data = cmd + 2; + esp_lcd_panel_io_tx_param(self->dbi_io_handle, cmd[0], data, data_size); + + uint16_t delay_length_ms = 0; + if (delay) { + data_size++; + delay_length_ms = *(cmd + 1 + data_size); + if (delay_length_ms == 255) { + delay_length_ms = 500; + } + } + common_hal_time_delay_ms(delay_length_ms); + i += 2 + data_size; + } + + // Initialize the panel after sending init commands + ret = esp_lcd_panel_init(self->dpi_panel_handle); + if (ret != ESP_OK) { + common_hal_mipidsi_display_deinit(self); + CHECK_ESP_RESULT(ret); + } + + // Setup backlight PWM if pin is provided + self->backlight_inout.base.type = &mp_type_NoneType; + if (backlight_pin != NULL && common_hal_mcu_pin_is_free(backlight_pin)) { + #if (CIRCUITPY_PWMIO) + pwmout_result_t result = common_hal_pwmio_pwmout_construct(&self->backlight_pwm, backlight_pin, 0, 50000, false); + if (result != PWMOUT_OK) { + self->backlight_inout.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->backlight_inout, backlight_pin); + common_hal_never_reset_pin(backlight_pin); + } else { + self->backlight_pwm.base.type = &pwmio_pwmout_type; + common_hal_pwmio_pwmout_never_reset(&self->backlight_pwm); + } + #else + self->backlight_inout.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&self->backlight_inout, backlight_pin); + common_hal_never_reset_pin(backlight_pin); + #endif + + // Set initial brightness + #if (CIRCUITPY_PWMIO) + if (self->backlight_pwm.base.type == &pwmio_pwmout_type) { + common_hal_pwmio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t)(brightness * 0xFFFF)); + } else + #endif + if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + bool on = brightness > 0; + if (!backlight_on_high) { + on = !on; + } + common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, on); + } + } +} + +void common_hal_mipidsi_display_deinit(mipidsi_display_obj_t *self) { + if (common_hal_mipidsi_display_deinited(self)) { + return; + } + + // Cleanup backlight + #if (CIRCUITPY_PWMIO) + if (self->backlight_pwm.base.type == &pwmio_pwmout_type) { + common_hal_pwmio_pwmout_deinit(&self->backlight_pwm); + } else + #endif + if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_deinit(&self->backlight_inout); + } + + // Delete the DPI panel + if (self->dpi_panel_handle != NULL) { + esp_lcd_panel_del(self->dpi_panel_handle); + self->dpi_panel_handle = NULL; + } + + // Delete the DBI interface + if (self->dbi_io_handle != NULL) { + esp_lcd_panel_io_del(self->dbi_io_handle); + self->dbi_io_handle = NULL; + } + + self->bus = NULL; + self->framebuffer = NULL; +} + +bool common_hal_mipidsi_display_deinited(mipidsi_display_obj_t *self) { + return self->dpi_panel_handle == NULL; +} + +void common_hal_mipidsi_display_refresh(mipidsi_display_obj_t *self) { + // Write back the cache to ensure framebuffer changes are visible + Cache_WriteBack_Addr((uint32_t)(self->framebuffer), self->framebuffer_size); + + // The DPI panel will automatically refresh from the framebuffer + // No explicit refresh call is needed as the DSI hardware continuously + // sends data from the framebuffer to the display +} + +int common_hal_mipidsi_display_get_width(mipidsi_display_obj_t *self) { + return self->width; +} + +int common_hal_mipidsi_display_get_height(mipidsi_display_obj_t *self) { + return self->height; +} + +int common_hal_mipidsi_display_get_row_stride(mipidsi_display_obj_t *self) { + return self->width * (self->color_depth / 8); +} + +int common_hal_mipidsi_display_get_color_depth(mipidsi_display_obj_t *self) { + return self->color_depth; +} + +int common_hal_mipidsi_display_get_native_frames_per_second(mipidsi_display_obj_t *self) { + return self->native_frames_per_second; +} + +bool common_hal_mipidsi_display_get_grayscale(mipidsi_display_obj_t *self) { + return false; +} + +mp_int_t common_hal_mipidsi_display_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + mipidsi_display_obj_t *self = (mipidsi_display_obj_t *)self_in; + + bufinfo->buf = self->framebuffer; + bufinfo->len = self->framebuffer_size; + bufinfo->typecode = 'B'; + + return 0; +} diff --git a/ports/espressif/common-hal/mipidsi/Display.h b/ports/espressif/common-hal/mipidsi/Display.h new file mode 100644 index 00000000000..61e6cb73f6d --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/Display.h @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/mipidsi/Bus.h" +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/digitalio/DigitalInOut.h" +#include "common-hal/pwmio/PWMOut.h" +#include +#include + +typedef struct { + mp_obj_base_t base; + mipidsi_bus_obj_t *bus; + mp_uint_t virtual_channel; + mp_uint_t width; + mp_uint_t height; + mp_int_t rotation; + mp_uint_t color_depth; + mp_uint_t native_frames_per_second; + uint8_t *framebuffer; + esp_lcd_panel_io_handle_t dbi_io_handle; + esp_lcd_panel_handle_t dpi_panel_handle; + size_t framebuffer_size; + union { + digitalio_digitalinout_obj_t backlight_inout; + #if CIRCUITPY_PWMIO + pwmio_pwmout_obj_t backlight_pwm; + #endif + }; + bool backlight_on_high; +} mipidsi_display_obj_t; diff --git a/ports/espressif/common-hal/mipidsi/__init__.c b/ports/espressif/common-hal/mipidsi/__init__.c new file mode 100644 index 00000000000..173f2146e87 --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/mipidsi/__init__.h" diff --git a/ports/espressif/common-hal/mipidsi/__init__.h b/ports/espressif/common-hal/mipidsi/__init__.h new file mode 100644 index 00000000000..972a7c082fd --- /dev/null +++ b/ports/espressif/common-hal/mipidsi/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index f133e86c6e0..c3585c7e399 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -312,6 +312,9 @@ CIRCUITPY_PARALLELDISPLAYBUS = 0 # Library doesn't support P4 yet it seems CIRCUITPY_ESPCAMERA = 0 +# P4 has MIPI-DSI +CIRCUITPY_MIPIDSI = 1 + #### esp32s2 ########################################################## else ifeq ($(IDF_TARGET),esp32s2) # Modules diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index c629eb52932..192a9171716 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -244,7 +244,7 @@ safe_mode_t port_init(void) { #endif // Send the ROM output out of the UART. This includes early logs. - #if DEBUG + #if DEBUG && (defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT) esp_rom_install_uart_printf(); #endif diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index f4ac2350ffb..56c836cb3a4 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -294,6 +294,9 @@ endif ifeq ($(CIRCUITPY_MICROCONTROLLER),1) SRC_PATTERNS += microcontroller/% endif +ifeq ($(CIRCUITPY_MIPIDSI),1) +SRC_PATTERNS += mipidsi/% +endif ifeq ($(CIRCUITPY_MSGPACK),1) SRC_PATTERNS += msgpack/% endif @@ -531,6 +534,9 @@ SRC_COMMON_HAL_ALL = \ mdns/__init__.c \ mdns/Server.c \ mdns/RemoteService.c \ + mipidsi/Bus.c \ + mipidsi/Display.c \ + mipidsi/__init__.c \ neopixel_write/__init__.c \ nvm/ByteArray.c \ nvm/__init__.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 09ef4361427..9bbe5691dfb 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -405,6 +405,9 @@ CFLAGS += -DCIRCUITPY_MEMORYMONITOR=$(CIRCUITPY_MEMORYMONITOR) CIRCUITPY_MICROCONTROLLER ?= 1 CFLAGS += -DCIRCUITPY_MICROCONTROLLER=$(CIRCUITPY_MICROCONTROLLER) +CIRCUITPY_MIPIDSI ?= 0 +CFLAGS += -DCIRCUITPY_MIPIDSI=$(CIRCUITPY_MIPIDSI) + CIRCUITPY_MSGPACK ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_MSGPACK=$(CIRCUITPY_MSGPACK) diff --git a/shared-bindings/mipidsi/Bus.c b/shared-bindings/mipidsi/Bus.c new file mode 100644 index 00000000000..2f2ce046fe0 --- /dev/null +++ b/shared-bindings/mipidsi/Bus.c @@ -0,0 +1,96 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-bindings/mipidsi/Bus.h" +#include "shared-bindings/util.h" +#include "shared/runtime/context_manager_helpers.h" + +//| class Bus: +//| def __init__( +//| self, +//| *, +//| frequency: int = 500_000_000, +//| num_lanes: int = 2, +//| ) -> None: +//| """Create a MIPI DSI Bus object. +//| +//| This creates a DSI bus interface. The specific pins used are determined by the board. +//| DSI supports 1-4 data lanes. +//| +//| :param int frequency: the high speed clock frequency in Hz (default 500 MHz) +//| :param int num_lanes: the number of data lanes to use (default 2, range 1-4) +//| """ +//| + +static mp_obj_t mipidsi_bus_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_frequency, ARG_num_lanes }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 500000000} }, + { MP_QSTR_num_lanes, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 2} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mipidsi_bus_obj_t *self = mp_obj_malloc(mipidsi_bus_obj_t, &mipidsi_bus_type); + + mp_uint_t frequency = (mp_uint_t)mp_arg_validate_int_min(args[ARG_frequency].u_int, 1, MP_QSTR_frequency); + uint8_t num_lanes = (uint8_t)mp_arg_validate_int_range(args[ARG_num_lanes].u_int, 1, 4, MP_QSTR_num_lanes); + + common_hal_mipidsi_bus_construct(self, frequency, num_lanes); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Free the resources (pins, timers, etc.) associated with this +//| `mipidsi.Bus` instance. After deinitialization, no further operations +//| may be performed.""" +//| ... +//| +static mp_obj_t mipidsi_bus_deinit(mp_obj_t self_in) { + mipidsi_bus_obj_t *self = (mipidsi_bus_obj_t *)self_in; + common_hal_mipidsi_bus_deinit(self); + return mp_const_none; +} + +static MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_bus_deinit_obj, mipidsi_bus_deinit); + +//| def __enter__(self) -> Bus: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +static mp_obj_t mipidsi_bus_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_mipidsi_bus_deinit(args[0]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mipidsi_bus___exit___obj, 4, 4, mipidsi_bus_obj___exit__); + +static const mp_rom_map_elem_t mipidsi_bus_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mipidsi_bus_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mipidsi_bus___exit___obj) }, +}; +static MP_DEFINE_CONST_DICT(mipidsi_bus_locals_dict, mipidsi_bus_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mipidsi_bus_type, + MP_QSTR_Bus, + MP_TYPE_FLAG_NONE, + make_new, mipidsi_bus_make_new, + locals_dict, &mipidsi_bus_locals_dict + ); diff --git a/shared-bindings/mipidsi/Bus.h b/shared-bindings/mipidsi/Bus.h new file mode 100644 index 00000000000..f2fd13f7fc1 --- /dev/null +++ b/shared-bindings/mipidsi/Bus.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/mipidsi/Bus.h" + +extern const mp_obj_type_t mipidsi_bus_type; + +void common_hal_mipidsi_bus_construct(mipidsi_bus_obj_t *self, mp_uint_t frequency, uint8_t num_lanes); +void common_hal_mipidsi_bus_deinit(mipidsi_bus_obj_t *self); +bool common_hal_mipidsi_bus_deinited(mipidsi_bus_obj_t *self); diff --git a/shared-bindings/mipidsi/Display.c b/shared-bindings/mipidsi/Display.c new file mode 100644 index 00000000000..a553c7ca8fd --- /dev/null +++ b/shared-bindings/mipidsi/Display.c @@ -0,0 +1,289 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "py/objtype.h" + +#include "shared-bindings/mipidsi/Display.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/framebufferio/FramebufferDisplay.h" + +//| class Display: +//| def __init__( +//| self, +//| bus: Bus, +//| init_sequence: ReadableBuffer, +//| *, +//| width: int, +//| height: int, +//| hsync_pulse_width: int, +//| hsync_back_porch: int, +//| hsync_front_porch: int, +//| vsync_pulse_width: int, +//| vsync_back_porch: int, +//| vsync_front_porch: int, +//| pixel_clock_frequency: int, +//| virtual_channel: int = 0, +//| rotation: int = 0, +//| color_depth: int = 16, +//| backlight_pin: Optional[microcontroller.Pin] = None, +//| brightness: float = 1.0, +//| native_frames_per_second: int = 60, +//| backlight_on_high: bool = True, +//| ) -> None: +//| """Create a MIPI DSI Display object connected to the given bus. +//| +//| This allocates a framebuffer and configures the DSI display to use the +//| specified virtual channel for communication. +//| +//| The framebuffer pixel format varies depending on color_depth: +//| +//| * 16 - Each two bytes is a pixel in RGB565 format. +//| * 24 - Each three bytes is a pixel in RGB888 format. +//| +//| A Display is often used in conjunction with a +//| `framebufferio.FramebufferDisplay`. +//| +//| :param Bus bus: the DSI bus to use +//| :param ~circuitpython_typing.ReadableBuffer init_sequence: Byte-packed initialization sequence for the display +//| :param int width: the width of the framebuffer in pixels +//| :param int height: the height of the framebuffer in pixels +//| :param int hsync_pulse_width: horizontal sync pulse width in pixel clocks +//| :param int hsync_back_porch: horizontal back porch in pixel clocks +//| :param int hsync_front_porch: horizontal front porch in pixel clocks +//| :param int vsync_pulse_width: vertical sync pulse width in lines +//| :param int vsync_back_porch: vertical back porch in lines +//| :param int vsync_front_porch: vertical front porch in lines +//| :param int pixel_clock_frequency: pixel clock frequency in Hz +//| :param int virtual_channel: the DSI virtual channel (0-3) +//| :param int rotation: the rotation of the display in degrees clockwise (0, 90, 180, 270) +//| :param int color_depth: the color depth of the framebuffer in bits (16 or 24) +//| :param microcontroller.Pin backlight_pin: Pin connected to the display's backlight +//| :param float brightness: Initial display brightness (0.0 to 1.0) +//| :param int native_frames_per_second: Number of display refreshes per second +//| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on +//| """ +//| + +static mp_obj_t mipidsi_display_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_bus, ARG_init_sequence, ARG_width, ARG_height, ARG_hsync_pulse_width, ARG_hsync_back_porch, + ARG_hsync_front_porch, ARG_vsync_pulse_width, ARG_vsync_back_porch, ARG_vsync_front_porch, + ARG_pixel_clock_frequency, ARG_virtual_channel, ARG_rotation, + ARG_color_depth, ARG_backlight_pin, ARG_brightness, ARG_native_frames_per_second, + ARG_backlight_on_high }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bus, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_init_sequence, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_hsync_pulse_width, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_hsync_back_porch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_hsync_front_porch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_vsync_pulse_width, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_vsync_back_porch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_vsync_front_porch, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_pixel_clock_frequency, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_virtual_channel, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_rotation, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_color_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, + { MP_QSTR_native_frames_per_second, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 60} }, + { MP_QSTR_backlight_on_high, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mipidsi_display_obj_t *self = &allocate_display_bus_or_raise()->mipidsi; + self->base.type = &mipidsi_display_type; + + mipidsi_bus_obj_t *bus = mp_arg_validate_type(args[ARG_bus].u_obj, &mipidsi_bus_type, MP_QSTR_bus); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_init_sequence].u_obj, &bufinfo, MP_BUFFER_READ); + + const mcu_pin_obj_t *backlight_pin = + validate_obj_is_free_pin_or_none(args[ARG_backlight_pin].u_obj, MP_QSTR_backlight_pin); + + mp_float_t brightness = mp_obj_get_float(args[ARG_brightness].u_obj); + + mp_int_t rotation = args[ARG_rotation].u_int; + if (rotation % 90 != 0) { + mp_raise_ValueError(MP_ERROR_TEXT("Display rotation must be in 90 degree increments")); + } + + mp_uint_t virtual_channel = (mp_uint_t)mp_arg_validate_int_range(args[ARG_virtual_channel].u_int, 0, 3, MP_QSTR_virtual_channel); + mp_uint_t width = (mp_uint_t)mp_arg_validate_int_min(args[ARG_width].u_int, 0, MP_QSTR_width); + mp_uint_t height = (mp_uint_t)mp_arg_validate_int_min(args[ARG_height].u_int, 0, MP_QSTR_height); + mp_uint_t color_depth = args[ARG_color_depth].u_int; + + if (color_depth != 8 && color_depth != 16 && color_depth != 24) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_color_depth); + } + + common_hal_mipidsi_display_construct(self, bus, bufinfo.buf, bufinfo.len, virtual_channel, width, height, + rotation, color_depth, MP_OBJ_TO_PTR(backlight_pin), brightness, + args[ARG_native_frames_per_second].u_int, + args[ARG_backlight_on_high].u_bool, + args[ARG_hsync_pulse_width].u_int, + args[ARG_hsync_back_porch].u_int, + args[ARG_hsync_front_porch].u_int, + args[ARG_vsync_pulse_width].u_int, + args[ARG_vsync_back_porch].u_int, + args[ARG_vsync_front_porch].u_int, + args[ARG_pixel_clock_frequency].u_int); + + return MP_OBJ_FROM_PTR(self); +} + +// Helper to ensure we have the native super class instead of a subclass. +static mipidsi_display_obj_t *native_display(mp_obj_t display_obj) { + mp_obj_t native_display = mp_obj_cast_to_native_base(display_obj, &mipidsi_display_type); + mp_obj_assert_native_inited(native_display); + return MP_OBJ_TO_PTR(native_display); +} + +//| def deinit(self) -> None: +//| """Free the resources (pins, timers, etc.) associated with this +//| `mipidsi.Display` instance. After deinitialization, no further operations +//| may be performed.""" +//| ... +//| +static mp_obj_t mipidsi_display_deinit(mp_obj_t self_in) { + mipidsi_display_obj_t *self = native_display(self_in); + common_hal_mipidsi_display_deinit(self); + return mp_const_none; +} + +static MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_display_deinit_obj, mipidsi_display_deinit); + +static void check_for_deinit(mipidsi_display_obj_t *self) { + if (common_hal_mipidsi_display_deinited(self)) { + raise_deinited_error(); + } +} + +//| width: int +//| """The width of the framebuffer, in pixels.""" +static mp_obj_t mipidsi_display_get_width(mp_obj_t self_in) { + mipidsi_display_obj_t *self = native_display(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_mipidsi_display_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_display_get_width_obj, mipidsi_display_get_width); +MP_PROPERTY_GETTER(mipidsi_display_width_obj, + (mp_obj_t)&mipidsi_display_get_width_obj); + +//| height: int +//| """The height of the framebuffer, in pixels.""" +//| +//| +static mp_obj_t mipidsi_display_get_height(mp_obj_t self_in) { + mipidsi_display_obj_t *self = native_display(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_mipidsi_display_get_height(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_display_get_height_obj, mipidsi_display_get_height); + +MP_PROPERTY_GETTER(mipidsi_display_height_obj, + (mp_obj_t)&mipidsi_display_get_height_obj); + +//| color_depth: int +//| """The color depth of the framebuffer.""" +static mp_obj_t mipidsi_display_get_color_depth(mp_obj_t self_in) { + mipidsi_display_obj_t *self = native_display(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_mipidsi_display_get_color_depth(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_display_get_color_depth_obj, mipidsi_display_get_color_depth); +MP_PROPERTY_GETTER(mipidsi_display_color_depth_obj, + (mp_obj_t)&mipidsi_display_get_color_depth_obj); + + +static const mp_rom_map_elem_t mipidsi_display_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mipidsi_display_deinit_obj) }, + + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&mipidsi_display_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&mipidsi_display_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_color_depth), MP_ROM_PTR(&mipidsi_display_color_depth_obj) }, +}; +static MP_DEFINE_CONST_DICT(mipidsi_display_locals_dict, mipidsi_display_locals_dict_table); + +static void mipidsi_display_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufinfo) { + common_hal_mipidsi_display_get_buffer(self_in, bufinfo, 0); +} + +// These versions exist so that the prototype matches the protocol, +// avoiding a type cast that can hide errors +static void mipidsi_display_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) { + (void)dirty_row_bitmap; + common_hal_mipidsi_display_refresh(self_in); +} + +static void mipidsi_display_deinit_proto(mp_obj_t self_in) { + common_hal_mipidsi_display_deinit(self_in); +} + +static int mipidsi_display_get_width_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_width(self_in); +} + +static int mipidsi_display_get_height_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_height(self_in); +} + +static int mipidsi_display_get_color_depth_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_color_depth(self_in); +} + +static bool mipidsi_display_get_grayscale_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_grayscale(self_in); +} + +static int mipidsi_display_get_bytes_per_cell_proto(mp_obj_t self_in) { + return 1; +} + +static int mipidsi_display_get_native_frames_per_second_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_native_frames_per_second(self_in); +} + +static bool mipidsi_display_get_pixels_in_byte_share_row_proto(mp_obj_t self_in) { + return true; +} + +static int mipidsi_display_get_row_stride_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_row_stride(self_in); +} + +static const framebuffer_p_t mipidsi_display_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer) + .get_bufinfo = mipidsi_display_get_bufinfo, + .get_width = mipidsi_display_get_width_proto, + .get_height = mipidsi_display_get_height_proto, + .get_color_depth = mipidsi_display_get_color_depth_proto, + .get_grayscale = mipidsi_display_get_grayscale_proto, + .get_row_stride = mipidsi_display_get_row_stride_proto, + .get_bytes_per_cell = mipidsi_display_get_bytes_per_cell_proto, + .get_native_frames_per_second = mipidsi_display_get_native_frames_per_second_proto, + .get_pixels_in_byte_share_row = mipidsi_display_get_pixels_in_byte_share_row_proto, + .swapbuffers = mipidsi_display_swapbuffers, + .deinit = mipidsi_display_deinit_proto, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + mipidsi_display_type, + MP_QSTR_Display, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + locals_dict, &mipidsi_display_locals_dict, + make_new, mipidsi_display_make_new, + buffer, common_hal_mipidsi_display_get_buffer, + protocol, &mipidsi_display_proto + ); diff --git a/shared-bindings/mipidsi/Display.h b/shared-bindings/mipidsi/Display.h new file mode 100644 index 00000000000..1cec788f16c --- /dev/null +++ b/shared-bindings/mipidsi/Display.h @@ -0,0 +1,44 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/mipidsi/Display.h" +#include "shared-bindings/mipidsi/Bus.h" +#include "common-hal/microcontroller/Pin.h" + +extern const mp_obj_type_t mipidsi_display_type; + +void common_hal_mipidsi_display_construct(mipidsi_display_obj_t *self, + mipidsi_bus_obj_t *bus, + const uint8_t *init_sequence, + size_t init_sequence_len, + mp_uint_t virtual_channel, + mp_uint_t width, + mp_uint_t height, + mp_int_t rotation, + mp_uint_t color_depth, + const mcu_pin_obj_t *backlight_pin, + mp_float_t brightness, + mp_uint_t native_frames_per_second, + bool backlight_on_high, + mp_uint_t hsync_pulse_width, + mp_uint_t hsync_back_porch, + mp_uint_t hsync_front_porch, + mp_uint_t vsync_pulse_width, + mp_uint_t vsync_back_porch, + mp_uint_t vsync_front_porch, + mp_uint_t pixel_clock_frequency); +void common_hal_mipidsi_display_deinit(mipidsi_display_obj_t *self); +bool common_hal_mipidsi_display_deinited(mipidsi_display_obj_t *self); +void common_hal_mipidsi_display_refresh(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_width(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_height(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_row_stride(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_color_depth(mipidsi_display_obj_t *self); +int common_hal_mipidsi_display_get_native_frames_per_second(mipidsi_display_obj_t *self); +bool common_hal_mipidsi_display_get_grayscale(mipidsi_display_obj_t *self); +mp_int_t common_hal_mipidsi_display_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags); diff --git a/shared-bindings/mipidsi/__init__.c b/shared-bindings/mipidsi/__init__.c new file mode 100644 index 00000000000..0b6b8565929 --- /dev/null +++ b/shared-bindings/mipidsi/__init__.c @@ -0,0 +1,30 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/mipidsi/Bus.h" +#include "shared-bindings/mipidsi/Display.h" + +//| """Low-level routines for interacting with MIPI DSI""" + +static const mp_rom_map_elem_t mipidsi_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mipidsi) }, + { MP_ROM_QSTR(MP_QSTR_Bus), MP_ROM_PTR(&mipidsi_bus_type) }, + { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&mipidsi_display_type) }, +}; + +static MP_DEFINE_CONST_DICT(mipidsi_module_globals, mipidsi_module_globals_table); + +const mp_obj_module_t mipidsi_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mipidsi_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_mipidsi, mipidsi_module); diff --git a/shared-bindings/mipidsi/__init__.h b/shared-bindings/mipidsi/__init__.h new file mode 100644 index 00000000000..972a7c082fd --- /dev/null +++ b/shared-bindings/mipidsi/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index 29b8c64c972..f2f4691b313 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -38,6 +38,9 @@ #if CIRCUITPY_DOTCLOCKFRAMEBUFFER #include "common-hal/dotclockframebuffer/DotClockFramebuffer.h" #endif +#if CIRCUITPY_MIPIDSI +#include "shared-bindings/mipidsi/Display.h" +#endif // Port unique frame buffers. #if CIRCUITPY_VIDEOCORE #include "bindings/videocore/Framebuffer.h" @@ -81,6 +84,9 @@ typedef struct { #if CIRCUITPY_AURORA_EPAPER aurora_epaper_framebuffer_obj_t aurora_epaper; #endif + #if CIRCUITPY_MIPIDSI + mipidsi_display_obj_t mipidsi; + #endif }; } primary_display_bus_t; From eb84f5a6b3984cedcd68a525ab07b0f8e55ab764 Mon Sep 17 00:00:00 2001 From: chinh4thepro Date: Mon, 3 Nov 2025 19:29:47 -0500 Subject: [PATCH 081/876] ports/espressif: add MT* pin aliases to seeed xiao esp32s3 sense board --- ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c index 8269f1d7a95..222b17aa337 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c @@ -68,6 +68,10 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_MOSI_1), MP_ROM_PTR(&pin_GPIO11) }, { MP_ROM_QSTR(MP_QSTR_MISO_1), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO42) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_SCK_1), MP_ROM_PTR(&pin_GPIO13) }, { MP_ROM_QSTR(MP_QSTR_SDCS), MP_ROM_PTR(&pin_GPIO21) }, @@ -89,9 +93,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_CAM_SDA), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_MIC_DATA), MP_ROM_PTR(&pin_GPIO41) }, { MP_ROM_QSTR(MP_QSTR_MIC_CLK), MP_ROM_PTR(&pin_GPIO42) }, - { MP_ROM_QSTR(MP_QSTR_I2S_SD), MP_ROM_PTR(&pin_GPIO38) }, - { MP_ROM_QSTR(MP_QSTR_I2S_SCK), MP_ROM_PTR(&pin_GPIO39) }, - { MP_ROM_QSTR(MP_QSTR_I2S_WS), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, From 672f6855410e1eea71e7bedc97eafc6eff496d27 Mon Sep 17 00:00:00 2001 From: chinh4thepro Date: Mon, 3 Nov 2025 19:30:48 -0500 Subject: [PATCH 082/876] ports/espressif: add back the I2S pin aliases --- ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c index 222b17aa337..aa0d72b4d86 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c @@ -93,6 +93,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_CAM_SDA), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_MIC_DATA), MP_ROM_PTR(&pin_GPIO41) }, { MP_ROM_QSTR(MP_QSTR_MIC_CLK), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SD), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WS), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, From 785d5991bdfd955edf2c1f50e147c393e3d6d8ed Mon Sep 17 00:00:00 2001 From: chinh4thepro Date: Mon, 3 Nov 2025 22:34:54 -0500 Subject: [PATCH 083/876] seeed_xiao_esp32_s3_sense: stylize pins.c --- .../boards/seeed_xiao_esp32_s3_sense/pins.c | 90 +++++++++++-------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c index aa0d72b4d86..fcf48c83659 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c @@ -31,71 +31,91 @@ static const mp_rom_obj_tuple_t camera_data_tuple = { static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) }, - { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO2) }, - { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO5) }, - { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SD), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_CAM_VSYNC), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_CAM_SCL), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WS), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_CAM_SDA), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_MIC_DATA), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_RX_1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_MIC_CLK), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_TX_1), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_CAM_XCLK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_SCK_1), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_CAM_PCLK), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_MISO_1), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D5), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO11) }, - { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO5) }, - { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO6) }, - { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, - { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, - { MP_ROM_QSTR(MP_QSTR_TX_1), MP_ROM_PTR(&pin_GPIO42) }, - { MP_ROM_QSTR(MP_QSTR_RX_1), MP_ROM_PTR(&pin_GPIO41) }, - { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_MOSI_1), MP_ROM_PTR(&pin_GPIO11) }, - { MP_ROM_QSTR(MP_QSTR_MISO_1), MP_ROM_PTR(&pin_GPIO12) }, - { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO39) }, - { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO40) }, - { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO41) }, - { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO42) }, - { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO7) }, - { MP_ROM_QSTR(MP_QSTR_SCK_1), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_CAM_D6), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_SDCS), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_ADC), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_CAM_DATA), MP_ROM_PTR(&camera_data_tuple) }, { MP_ROM_QSTR(MP_QSTR_CAM_D0), MP_ROM_PTR(&pin_GPIO15) }, { MP_ROM_QSTR(MP_QSTR_CAM_D1), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_CAM_D2), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_CAM_D3), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_CAM_D4), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_CAM_D5), MP_ROM_PTR(&pin_GPIO12) }, - { MP_ROM_QSTR(MP_QSTR_CAM_D6), MP_ROM_PTR(&pin_GPIO11) }, { MP_ROM_QSTR(MP_QSTR_CAM_D7), MP_ROM_PTR(&pin_GPIO48) }, - { MP_ROM_QSTR(MP_QSTR_CAM_XCLK), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_CAM_HREF), MP_ROM_PTR(&pin_GPIO47) }, - { MP_ROM_QSTR(MP_QSTR_CAM_PCLK), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_CAM_VSYNC), MP_ROM_PTR(&pin_GPIO38) }, - { MP_ROM_QSTR(MP_QSTR_CAM_SCL), MP_ROM_PTR(&pin_GPIO39) }, - { MP_ROM_QSTR(MP_QSTR_CAM_SDA), MP_ROM_PTR(&pin_GPIO40) }, - { MP_ROM_QSTR(MP_QSTR_MIC_DATA), MP_ROM_PTR(&pin_GPIO41) }, - { MP_ROM_QSTR(MP_QSTR_MIC_CLK), MP_ROM_PTR(&pin_GPIO42) }, - { MP_ROM_QSTR(MP_QSTR_I2S_SD), MP_ROM_PTR(&pin_GPIO38) }, - { MP_ROM_QSTR(MP_QSTR_I2S_SCK), MP_ROM_PTR(&pin_GPIO39) }, - { MP_ROM_QSTR(MP_QSTR_I2S_WS), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, From 4c037682432b536c250213b380180a97afc2d122 Mon Sep 17 00:00:00 2001 From: chinh4thepro Date: Mon, 3 Nov 2025 22:39:08 -0500 Subject: [PATCH 084/876] seeed_xiao_esp32_s3_sense: add back pin alias --- ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c index fcf48c83659..fbb6014685c 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/pins.c @@ -49,6 +49,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO43) }, { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, From f469e93d53b6b6bc5c16a3b0291d996c0be4a4dc Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 3 Nov 2025 11:27:07 -0800 Subject: [PATCH 085/876] Fix Zephyr build --- ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml | 1 + 7 files changed, 7 insertions(+) diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 222a325e346..35966d6f9e2 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -66,6 +66,7 @@ mdns = false memorymap = false memorymonitor = false microcontroller = true +mipidsi = false msgpack = false neopixel_write = false nvm = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 41631c3d6c0..e3b6cc2248f 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -66,6 +66,7 @@ mdns = false memorymap = false memorymonitor = false microcontroller = true +mipidsi = false msgpack = false neopixel_write = false nvm = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index ea009aa36e1..328105d7150 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -66,6 +66,7 @@ mdns = false memorymap = false memorymonitor = false microcontroller = true +mipidsi = false msgpack = false neopixel_write = false nvm = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index a96d1bad1d2..2bc6e3e03a2 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -66,6 +66,7 @@ mdns = false memorymap = false memorymonitor = false microcontroller = true +mipidsi = false msgpack = false neopixel_write = false nvm = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index e4946decb19..2a2e16fd16a 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -66,6 +66,7 @@ mdns = false memorymap = false memorymonitor = false microcontroller = true +mipidsi = false msgpack = false neopixel_write = false nvm = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 7519d881768..5042eb972b1 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -66,6 +66,7 @@ mdns = false memorymap = false memorymonitor = false microcontroller = true +mipidsi = false msgpack = false neopixel_write = false nvm = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index e029020982d..cfe48a90cee 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -66,6 +66,7 @@ mdns = false memorymap = false memorymonitor = false microcontroller = true +mipidsi = false msgpack = false neopixel_write = false nvm = false From 7b452dc29a37b0976e0e6e8bb4ef38716d1b666e Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 4 Nov 2025 17:23:52 +0100 Subject: [PATCH 086/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 4 ++-- locale/ru.po | 4 ++-- locale/tr.po | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index fa1cb2d40b7..e59cc974e0e 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -4876,8 +4876,8 @@ msgstr "" #~ msgstr "IV musí být dlouhé %d bajtů" #~ msgid "" -#~ "Incompatible .mpy file. Please update all .mpy files. See http://adafru." -#~ "it/mpy-update for more info." +#~ "Incompatible .mpy file. Please update all .mpy files. See http://" +#~ "adafru.it/mpy-update for more info." #~ msgstr "" #~ "Nekompatibilní soubor .mpy. Aktualizujte prosím všechny soubory .mpy. " #~ "Další informace naleznete na adrese http://adafru.it/mpy-update." diff --git a/locale/ru.po b/locale/ru.po index af7c8bca194..83bfaf324d7 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -5149,8 +5149,8 @@ msgstr "zi должен иметь форму (n_section, 2)" #~ msgstr "IV должен быть длиной %d байт" #~ msgid "" -#~ "Incompatible .mpy file. Please update all .mpy files. See http://adafru." -#~ "it/mpy-update for more info." +#~ "Incompatible .mpy file. Please update all .mpy files. See http://" +#~ "adafru.it/mpy-update for more info." #~ msgstr "" #~ "Несовместимый файл .mpy. Пожалуйста, обновите все файлы .mpy. См. http://" #~ "adafru.it/mpy-update для получения дополнительной информации." diff --git a/locale/tr.po b/locale/tr.po index 758137eae21..4e03f59cbaf 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -4818,8 +4818,8 @@ msgstr "" #~ msgstr "IV %d bayt uzunluğunda olmalı" #~ msgid "" -#~ "Incompatible .mpy file. Please update all .mpy files. See http://adafru." -#~ "it/mpy-update for more info." +#~ "Incompatible .mpy file. Please update all .mpy files. See http://" +#~ "adafru.it/mpy-update for more info." #~ msgstr "" #~ "Uyumsuz .mpy dosyası. Lütfen tüm .mpy dosyalarını güncelleyin. Daha fazla " #~ "bilgi için http://adafru.it/mpy-update ." From d2dcfecb89420de5ad1495b7d5fa6d7bb5417f23 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 4 Nov 2025 14:01:24 -0500 Subject: [PATCH 087/876] espressif_esp32p4_function_ev/pins.c: add whitespace to clearly show pin aliases --- .../boards/espressif_esp32p4_function_ev/pins.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c b/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c index 7a3026f914d..165ce711b73 100644 --- a/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c +++ b/ports/espressif/boards/espressif_esp32p4_function_ev/pins.c @@ -12,18 +12,25 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { // Header Block J1 { MP_ROM_QSTR(MP_QSTR_I2C_SDA), MP_ROM_PTR(&pin_GPIO7) }, { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_I2C_SCL), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO37) }, { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO38) }, { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_C6_WAKEUP), MP_ROM_PTR(&pin_GPIO6) }, { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, @@ -36,12 +43,15 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_C6_EN), MP_ROM_PTR(&pin_GPIO54) }, { MP_ROM_QSTR(MP_QSTR_IO54), MP_ROM_PTR(&pin_GPIO54) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, { MP_ROM_QSTR(MP_QSTR_PA_CTRL), MP_ROM_PTR(&pin_GPIO53) }, { MP_ROM_QSTR(MP_QSTR_IO53), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, From 292d209fae5750df85537f2f4c33936b2ea8c5a2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 4 Nov 2025 16:29:30 -0800 Subject: [PATCH 088/876] Better reasoned allocations --- ports/espressif/common-hal/mipidsi/Bus.c | 17 +++++++++++ ports/espressif/common-hal/mipidsi/Bus.h | 4 +++ ports/espressif/common-hal/mipidsi/Display.c | 4 ++- shared-bindings/mipidsi/Bus.c | 30 ++++++-------------- shared-bindings/mipidsi/Display.c | 2 +- shared-module/displayio/__init__.c | 17 ++++++++++- 6 files changed, 50 insertions(+), 24 deletions(-) diff --git a/ports/espressif/common-hal/mipidsi/Bus.c b/ports/espressif/common-hal/mipidsi/Bus.c index 7f9dc01b773..dbb559ea30f 100644 --- a/ports/espressif/common-hal/mipidsi/Bus.c +++ b/ports/espressif/common-hal/mipidsi/Bus.c @@ -14,6 +14,10 @@ void common_hal_mipidsi_bus_construct(mipidsi_bus_obj_t *self, mp_uint_t frequen self->num_data_lanes = num_lanes; self->bus_handle = NULL; + if (self->use_count > 0) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_mipidsi); + } + esp_ldo_channel_handle_t ldo_mipi_phy = NULL; esp_ldo_channel_config_t ldo_mipi_phy_config = { .chan_id = 3, @@ -33,6 +37,9 @@ void common_hal_mipidsi_bus_construct(mipidsi_bus_obj_t *self, mp_uint_t frequen } void common_hal_mipidsi_bus_deinit(mipidsi_bus_obj_t *self) { + if (self->use_count > 0) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_Bus); + } if (common_hal_mipidsi_bus_deinited(self)) { return; } @@ -50,3 +57,13 @@ void common_hal_mipidsi_bus_deinit(mipidsi_bus_obj_t *self) { bool common_hal_mipidsi_bus_deinited(mipidsi_bus_obj_t *self) { return self->bus_handle == NULL; } + +void mipidsi_bus_increment_use_count(mipidsi_bus_obj_t *self) { + self->use_count++; +} +void mipidsi_bus_decrement_use_count(mipidsi_bus_obj_t *self) { + self->use_count--; + if (self->use_count == 0) { + common_hal_mipidsi_bus_deinit(self); + } +} diff --git a/ports/espressif/common-hal/mipidsi/Bus.h b/ports/espressif/common-hal/mipidsi/Bus.h index 0ffd333e52d..b6257fd7223 100644 --- a/ports/espressif/common-hal/mipidsi/Bus.h +++ b/ports/espressif/common-hal/mipidsi/Bus.h @@ -14,4 +14,8 @@ typedef struct { mp_uint_t frequency; esp_lcd_dsi_bus_handle_t bus_handle; uint8_t num_data_lanes; + uint8_t use_count; // Up to 4 displays } mipidsi_bus_obj_t; + +void mipidsi_bus_increment_use_count(mipidsi_bus_obj_t *self); +void mipidsi_bus_decrement_use_count(mipidsi_bus_obj_t *self); diff --git a/ports/espressif/common-hal/mipidsi/Display.c b/ports/espressif/common-hal/mipidsi/Display.c index eff06f02bf7..dac16162e91 100644 --- a/ports/espressif/common-hal/mipidsi/Display.c +++ b/ports/espressif/common-hal/mipidsi/Display.c @@ -67,7 +67,7 @@ void common_hal_mipidsi_display_construct(mipidsi_display_obj_t *self, color_format = LCD_COLOR_FMT_RGB888; } else { common_hal_mipidsi_display_deinit(self); - mp_raise_ValueError(MP_ERROR_TEXT("Color depth must be 16 or 24")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_color_depth); } // Create the DPI panel for sending pixel data @@ -173,6 +173,7 @@ void common_hal_mipidsi_display_construct(mipidsi_display_obj_t *self, common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, on); } } + mipidsi_bus_increment_use_count(self->bus); } void common_hal_mipidsi_display_deinit(mipidsi_display_obj_t *self) { @@ -202,6 +203,7 @@ void common_hal_mipidsi_display_deinit(mipidsi_display_obj_t *self) { self->dbi_io_handle = NULL; } + mipidsi_bus_decrement_use_count(self->bus); self->bus = NULL; self->framebuffer = NULL; } diff --git a/shared-bindings/mipidsi/Bus.c b/shared-bindings/mipidsi/Bus.c index 2f2ce046fe0..bac3cd3c75e 100644 --- a/shared-bindings/mipidsi/Bus.c +++ b/shared-bindings/mipidsi/Bus.c @@ -28,6 +28,13 @@ //| :param int num_lanes: the number of data lanes to use (default 2, range 1-4) //| """ //| +// +// +// All MCUs we support only have one DSI bus but it can be shared between multiple displays. One +// display may live longer than the VM, so we need to allocate the bus outside the VM. To simplify +// memory tracking, we use a global object for the bus. +// +static mipidsi_bus_obj_t _mipidsi_bus_obj; static mp_obj_t mipidsi_bus_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_frequency, ARG_num_lanes }; @@ -38,7 +45,8 @@ static mp_obj_t mipidsi_bus_make_new(const mp_obj_type_t *type, size_t n_args, s mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mipidsi_bus_obj_t *self = mp_obj_malloc(mipidsi_bus_obj_t, &mipidsi_bus_type); + _mipidsi_bus_obj.base.type = &mipidsi_bus_type; + mipidsi_bus_obj_t *self = &_mipidsi_bus_obj; mp_uint_t frequency = (mp_uint_t)mp_arg_validate_int_min(args[ARG_frequency].u_int, 1, MP_QSTR_frequency); uint8_t num_lanes = (uint8_t)mp_arg_validate_int_range(args[ARG_num_lanes].u_int, 1, 4, MP_QSTR_num_lanes); @@ -62,28 +70,8 @@ static mp_obj_t mipidsi_bus_deinit(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(mipidsi_bus_deinit_obj, mipidsi_bus_deinit); -//| def __enter__(self) -> Bus: -//| """No-op used by Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -static mp_obj_t mipidsi_bus_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_mipidsi_bus_deinit(args[0]); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mipidsi_bus___exit___obj, 4, 4, mipidsi_bus_obj___exit__); - static const mp_rom_map_elem_t mipidsi_bus_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mipidsi_bus_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&mipidsi_bus___exit___obj) }, }; static MP_DEFINE_CONST_DICT(mipidsi_bus_locals_dict, mipidsi_bus_locals_dict_table); diff --git a/shared-bindings/mipidsi/Display.c b/shared-bindings/mipidsi/Display.c index a553c7ca8fd..ad4522d653c 100644 --- a/shared-bindings/mipidsi/Display.c +++ b/shared-bindings/mipidsi/Display.c @@ -124,7 +124,7 @@ static mp_obj_t mipidsi_display_make_new(const mp_obj_type_t *type, size_t n_arg mp_uint_t height = (mp_uint_t)mp_arg_validate_int_min(args[ARG_height].u_int, 0, MP_QSTR_height); mp_uint_t color_depth = args[ARG_color_depth].u_int; - if (color_depth != 8 && color_depth != 16 && color_depth != 24) { + if (color_depth != 16 && color_depth != 24) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_color_depth); } diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 3ffd4d002f5..747fdbec5a7 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -41,6 +41,10 @@ #include "shared-module/aurora_epaper/aurora_framebuffer.h" #endif +#if CIRCUITPY_MIPIDSI +#include "shared-bindings/mipidsi/Display.h" +#endif + #ifdef BOARD_USE_INTERNAL_SPI #include "supervisor/spi_flash_api.h" #endif @@ -64,7 +68,7 @@ displayio_buffer_transform_t null_transform = { .transpose_xy = false }; -#if CIRCUITPY_RGBMATRIX || CIRCUITPY_IS31FL3741 || CIRCUITPY_VIDEOCORE || CIRCUITPY_PICODVI +#if CIRCUITPY_RGBMATRIX || CIRCUITPY_IS31FL3741 || CIRCUITPY_VIDEOCORE || CIRCUITPY_PICODVI || CIRCUITPY_MIPIDSI static bool any_display_uses_this_framebuffer(mp_obj_base_t *obj) { for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { if (displays[i].display_base.type == &framebufferio_framebufferdisplay_type) { @@ -180,6 +184,10 @@ static void common_hal_displayio_release_displays_impl(bool keep_primary) { } else if (bus_type == &picodvi_framebuffer_type) { common_hal_picodvi_framebuffer_deinit(&display_buses[i].picodvi); #endif + #if CIRCUITPY_MIPIDSI + } else if (bus_type == &mipidsi_display_type) { + common_hal_mipidsi_display_deinit(&display_buses[i].mipidsi); + #endif } display_buses[i].bus_base.type = &mp_type_NoneType; } @@ -333,6 +341,13 @@ void reset_displays(void) { // Set to None, gets deinit'd up by display_base display_buses[i].bus_base.type = &mp_type_NoneType; #endif + #if CIRCUITPY_MIPIDSI + } else if (display_bus_type == &mipidsi_display_type) { + mipidsi_display_obj_t *display = &display_buses[i].mipidsi; + if (!any_display_uses_this_framebuffer(&display->base)) { + common_hal_mipidsi_display_deinit(display); + } + #endif } else { // Not an active display bus. continue; From 000fa5ab5f3a3cdf077399af8a2c8ac9830aaefc Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 4 Nov 2025 16:36:14 -0800 Subject: [PATCH 089/876] Use latest macos in CI --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f837d793bd..ddd4a2eb936 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -107,7 +107,7 @@ jobs: cp-version: ${{ needs.scheduler.outputs.cp-version }} mpy-cross-mac: - runs-on: macos-13 + runs-on: macos-latest needs: scheduler if: needs.scheduler.outputs.ports != '{}' env: From 91e36f1b38f33719062168e3a7707edfff630948 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 5 Nov 2025 12:10:55 -0500 Subject: [PATCH 090/876] stop building intel and universal macos mpy-cross --- .github/workflows/build.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ddd4a2eb936..fbd3af440c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -131,33 +131,18 @@ jobs: gcc --version python3 --version msgfmt --version - - name: Build mpy-cross - run: make -C mpy-cross -j4 - - uses: actions/upload-artifact@v4 - with: - name: mpy-cross-macos-x64 - path: mpy-cross/build/mpy-cross - name: Build mpy-cross (arm64) run: make -C mpy-cross -j4 -f Makefile.m1 V=2 - uses: actions/upload-artifact@v4 with: name: mpy-cross-macos-arm64 path: mpy-cross/build-arm64/mpy-cross-arm64 - - name: Make universal binary - run: lipo -create -output mpy-cross-macos-universal mpy-cross/build/mpy-cross mpy-cross/build-arm64/mpy-cross-arm64 - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: mpy-cross-macos-universal - path: mpy-cross-macos-universal - name: Upload to S3 if: >- (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository_owner == 'adafruit') || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested')) run: | - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross-macos-universal s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-universal --no-progress --region us-east-1 [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/build-arm64/mpy-cross-arm64 s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-arm64 --no-progress --region us-east-1 - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/build/mpy-cross s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-x64 --no-progress --region us-east-1 env: AWS_PAGER: '' AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} From 7c9f9f6d3b40ad2b7efcade4f3c7fc4635112eea Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 5 Nov 2025 18:18:29 +0100 Subject: [PATCH 091/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 17 ++++++++--------- locale/el.po | 20 +++++++++++--------- locale/hi.po | 17 ++++++++--------- locale/ko.po | 22 ++++++++++++---------- locale/ru.po | 23 ++++++++++++++--------- locale/tr.po | 17 ++++++++--------- 6 files changed, 61 insertions(+), 55 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index e59cc974e0e..44adf488336 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -170,10 +170,6 @@ msgstr "Délka %q musí být <= %d" msgid "%q length must be >= %d" msgstr "Délka %q musí být >= %d" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "" - #: py/argcheck.c msgid "%q must be %d" msgstr "%q musí být %d" @@ -854,6 +850,10 @@ msgstr "Jádro kódu CircuitPython tvrdě havarovalo. Jejda!\n" msgid "Clock unit in use" msgstr "Jednotka hodin je používána" +#: ports/espressif/common-hal/mipidsi/Display.c +msgid "Color depth must be 16 or 24" +msgstr "" + #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -950,6 +950,7 @@ msgstr "Displej musí mít 16bitový barevný prostor." #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c msgid "Display rotation must be in 90 degree increments" msgstr "Otočení displeje musí být po 90 stupních" @@ -1296,7 +1297,8 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c #: shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c @@ -2290,6 +2292,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "Není možné vytvořit zámek" @@ -3203,10 +3206,6 @@ msgstr "" msgid "file write is not available" msgstr "zápis do souboru není dostupný" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "První argument musí být zavolatelný" diff --git a/locale/el.po b/locale/el.po index 91624ceb086..01f199d5c6a 100644 --- a/locale/el.po +++ b/locale/el.po @@ -174,10 +174,6 @@ msgstr "%q μήκος πρέπει να είναι <= %d" msgid "%q length must be >= %d" msgstr "%q μήκος πρέπει να είναι >= %d" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "%q μετακινήθηκε από το %q στο %q" - #: py/argcheck.c msgid "%q must be %d" msgstr "%q πρέπει να είναι %d" @@ -859,6 +855,10 @@ msgstr "Ο πυρήνας της CircuitPython κατέρευσε. Οουπς!\n msgid "Clock unit in use" msgstr "Μονάδα ρολογιού ήδη σε χρήση" +#: ports/espressif/common-hal/mipidsi/Display.c +msgid "Color depth must be 16 or 24" +msgstr "" + #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -957,6 +957,7 @@ msgstr "Η οθόνη πρέπει να έχει 16 bit χρωματική ευ #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c msgid "Display rotation must be in 90 degree increments" msgstr "Η περιστροφή της οθόνη πρέπει να γίνεται σε βήματα 90 μοιρών" @@ -1302,7 +1303,8 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c #: shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c @@ -2294,6 +2296,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -3202,10 +3205,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" @@ -4583,6 +4582,9 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ msgid "%q moved from %q to %q" +#~ msgstr "%q μετακινήθηκε από το %q στο %q" + #, c-format #~ msgid "%%c requires int or char" #~ msgstr "%%c απαιτεί ακέραιο ή χαρακτήρα" diff --git a/locale/hi.po b/locale/hi.po index 1ab48338eba..ea538c2f6f3 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -161,10 +161,6 @@ msgstr "" msgid "%q length must be >= %d" msgstr "" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "" - #: py/argcheck.c msgid "%q must be %d" msgstr "" @@ -840,6 +836,10 @@ msgstr "" msgid "Clock unit in use" msgstr "" +#: ports/espressif/common-hal/mipidsi/Display.c +msgid "Color depth must be 16 or 24" +msgstr "" + #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -934,6 +934,7 @@ msgstr "" #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c msgid "Display rotation must be in 90 degree increments" msgstr "" @@ -1278,7 +1279,8 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c #: shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c @@ -2268,6 +2270,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -3176,10 +3179,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 35bfed4de08..96d8003ff93 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -172,11 +172,6 @@ msgstr "%q 길이는 <= %d>여야 합니다" msgid "%q length must be >= %d" msgstr "%q 길이는 >= %d이어야 합니다" -#: py/runtime.c -#, fuzzy -msgid "%q moved from %q to %q" -msgstr "%q가 %q에서 %q로 이동했습니다" - #: py/argcheck.c msgid "%q must be %d" msgstr "%q는 %d이어야 합니다" @@ -885,6 +880,10 @@ msgstr "CircuitPython 핵심 코드가 심하게 충돌했습니다. 앗!\n" msgid "Clock unit in use" msgstr "시계 장치가 사용 중입니다" +#: ports/espressif/common-hal/mipidsi/Display.c +msgid "Color depth must be 16 or 24" +msgstr "" + #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -980,6 +979,7 @@ msgstr "디스플레이는 16 비트 색 공간을 가져야 합니다." #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c msgid "Display rotation must be in 90 degree increments" msgstr "디스플레이 회전은 90도씩 증가해야 합니다" @@ -1330,7 +1330,8 @@ msgstr "출력 함수로 인해 종료되었다" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c #: shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c @@ -2344,6 +2345,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -3252,10 +3254,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" @@ -4633,6 +4631,10 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, fuzzy +#~ msgid "%q moved from %q to %q" +#~ msgstr "%q가 %q에서 %q로 이동했습니다" + #, c-format #~ msgid "%%c requires int or char" #~ msgstr "%%c 전수(int)또는 캐릭터(char)필요합니다" diff --git a/locale/ru.po b/locale/ru.po index 83bfaf324d7..3b957b347c1 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -174,10 +174,6 @@ msgstr "Длинна %q должна быть <= %d" msgid "%q length must be >= %d" msgstr "Длинна %q должна быть >= %d" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "%q переместился из %q в %q" - #: py/argcheck.c msgid "%q must be %d" msgstr "%q должно быть %d" @@ -862,6 +858,10 @@ msgstr "Основной код CircuitPython сильно разбился. У msgid "Clock unit in use" msgstr "Источник тактирования уже используется" +#: ports/espressif/common-hal/mipidsi/Display.c +msgid "Color depth must be 16 or 24" +msgstr "" + #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -960,6 +960,7 @@ msgstr "Дисплей должен иметь 16 битное цветовое #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c msgid "Display rotation must be in 90 degree increments" msgstr "Поворот дисплея должен осуществляться с шагом 90 градусов" @@ -1317,7 +1318,8 @@ msgstr "Прерывается функцией выхода" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c #: shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c @@ -2324,6 +2326,7 @@ msgid "Unable to allocate to the heap." msgstr "Невозможно выделить место в куче." #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "Не удается создать блокировку" @@ -3257,10 +3260,6 @@ msgstr "Файл должен быть файлом, открытым в бай msgid "file write is not available" msgstr "Запись файлов недоступна" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "Файловая система должна предусматривать метод монтирования" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "Первый аргумент должен быть вызываемым" @@ -4650,6 +4649,12 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#~ msgid "%q moved from %q to %q" +#~ msgstr "%q переместился из %q в %q" + +#~ msgid "filesystem must provide mount method" +#~ msgstr "Файловая система должна предусматривать метод монтирования" + #~ msgid "start/end indices" #~ msgstr "Начальные/конечные индексы" diff --git a/locale/tr.po b/locale/tr.po index 4e03f59cbaf..54155a60543 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -172,10 +172,6 @@ msgstr "%q boyutu <= %d olmalıdır" msgid "%q length must be >= %d" msgstr "%q boyutu >= %d olmalıdır" -#: py/runtime.c -msgid "%q moved from %q to %q" -msgstr "" - #: py/argcheck.c msgid "%q must be %d" msgstr "%q, %d olmalıdır" @@ -854,6 +850,10 @@ msgstr "CircuitPython kor kodu patladı. Haydaaa!\n" msgid "Clock unit in use" msgstr "Saat ünitesi kullanımda" +#: ports/espressif/common-hal/mipidsi/Display.c +msgid "Color depth must be 16 or 24" +msgstr "" + #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -948,6 +948,7 @@ msgstr "Ekran 16 bitlik bir renk uzayına sahip olmalıdır." #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c msgid "Display rotation must be in 90 degree increments" msgstr "Ekran dönüşü 90 derecelik artışlarla olmalıdır" @@ -1296,7 +1297,8 @@ msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c shared-bindings/pwmio/PWMOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c #: shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c @@ -2290,6 +2292,7 @@ msgid "Unable to allocate to the heap." msgstr "" #: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c msgid "Unable to create lock" msgstr "" @@ -3198,10 +3201,6 @@ msgstr "" msgid "file write is not available" msgstr "" -#: shared-bindings/storage/__init__.c -msgid "filesystem must provide mount method" -msgstr "" - #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" msgstr "" From 91d4181a38c8dccff7fba060d512ed850d55010e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 5 Nov 2025 12:58:05 -0500 Subject: [PATCH 092/876] update frozen libraries --- frozen/Adafruit_CircuitPython_AHTx0 | 2 +- frozen/Adafruit_CircuitPython_APDS9960 | 2 +- frozen/Adafruit_CircuitPython_BLE | 2 +- frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center | 2 +- frozen/Adafruit_CircuitPython_Bitmap_Font | 2 +- frozen/Adafruit_CircuitPython_BusDevice | 2 +- frozen/Adafruit_CircuitPython_CircuitPlayground | 2 +- frozen/Adafruit_CircuitPython_ConnectionManager | 2 +- frozen/Adafruit_CircuitPython_Crickit | 2 +- frozen/Adafruit_CircuitPython_DRV2605 | 2 +- frozen/Adafruit_CircuitPython_DS3231 | 2 +- frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 | 2 +- frozen/Adafruit_CircuitPython_Display_Text | 2 +- frozen/Adafruit_CircuitPython_DotStar | 2 +- frozen/Adafruit_CircuitPython_ESP32SPI | 2 +- frozen/Adafruit_CircuitPython_FakeRequests | 2 +- frozen/Adafruit_CircuitPython_FocalTouch | 2 +- frozen/Adafruit_CircuitPython_HID | 2 +- frozen/Adafruit_CircuitPython_HTTPServer | 2 +- frozen/Adafruit_CircuitPython_IRRemote | 2 +- frozen/Adafruit_CircuitPython_IS31FL3731 | 2 +- frozen/Adafruit_CircuitPython_ImageLoad | 2 +- frozen/Adafruit_CircuitPython_LC709203F | 2 +- frozen/Adafruit_CircuitPython_LED_Animation | 2 +- frozen/Adafruit_CircuitPython_LIS3DH | 2 +- frozen/Adafruit_CircuitPython_LSM6DS | 2 +- frozen/Adafruit_CircuitPython_MIDI | 2 +- frozen/Adafruit_CircuitPython_MPU6050 | 2 +- frozen/Adafruit_CircuitPython_Motor | 2 +- frozen/Adafruit_CircuitPython_NeoPixel | 2 +- frozen/Adafruit_CircuitPython_PCF8563 | 2 +- frozen/Adafruit_CircuitPython_Pixel_Framebuf | 2 +- frozen/Adafruit_CircuitPython_PortalBase | 2 +- frozen/Adafruit_CircuitPython_ProgressBar | 2 +- frozen/Adafruit_CircuitPython_RFM69 | 2 +- frozen/Adafruit_CircuitPython_RFM9x | 2 +- frozen/Adafruit_CircuitPython_Register | 2 +- frozen/Adafruit_CircuitPython_Requests | 2 +- frozen/Adafruit_CircuitPython_SD | 2 +- frozen/Adafruit_CircuitPython_SHT4x | 2 +- frozen/Adafruit_CircuitPython_SSD1306 | 2 +- frozen/Adafruit_CircuitPython_SSD1680 | 2 +- frozen/Adafruit_CircuitPython_ST7789 | 2 +- frozen/Adafruit_CircuitPython_SimpleIO | 2 +- frozen/Adafruit_CircuitPython_SimpleMath | 2 +- frozen/Adafruit_CircuitPython_Thermistor | 2 +- frozen/Adafruit_CircuitPython_Ticks | 2 +- frozen/Adafruit_CircuitPython_UC8151D | 2 +- frozen/Adafruit_CircuitPython_Wave | 2 +- frozen/Adafruit_CircuitPython_Wiznet5k | 2 +- frozen/Adafruit_CircuitPython_asyncio | 2 +- frozen/Adafruit_CircuitPython_framebuf | 2 +- frozen/Adafruit_CircuitPython_seesaw | 2 +- 53 files changed, 53 insertions(+), 53 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_AHTx0 b/frozen/Adafruit_CircuitPython_AHTx0 index ff95dd5f3d0..8c61ed111fc 160000 --- a/frozen/Adafruit_CircuitPython_AHTx0 +++ b/frozen/Adafruit_CircuitPython_AHTx0 @@ -1 +1 @@ -Subproject commit ff95dd5f3d0186c5cdc8bd8cb34ac22ac2e2225d +Subproject commit 8c61ed111fc83e4e1703cf5e014e645f4dbbef32 diff --git a/frozen/Adafruit_CircuitPython_APDS9960 b/frozen/Adafruit_CircuitPython_APDS9960 index 00127a75d22..f05a7239131 160000 --- a/frozen/Adafruit_CircuitPython_APDS9960 +++ b/frozen/Adafruit_CircuitPython_APDS9960 @@ -1 +1 @@ -Subproject commit 00127a75d22f035096ea9317ad57c74c6a9b4232 +Subproject commit f05a7239131dc05df949e49c1bb5732529a864bf diff --git a/frozen/Adafruit_CircuitPython_BLE b/frozen/Adafruit_CircuitPython_BLE index 1acb303cc7f..6744b6869e4 160000 --- a/frozen/Adafruit_CircuitPython_BLE +++ b/frozen/Adafruit_CircuitPython_BLE @@ -1 +1 @@ -Subproject commit 1acb303cc7f63a752c9fb87655d2ec478e564be2 +Subproject commit 6744b6869e4c3112610132bcac23535ae5ef3983 diff --git a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center index 476082b43c9..e162713efa5 160000 --- a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center +++ b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center @@ -1 +1 @@ -Subproject commit 476082b43c9e5971da20a320a05546a8285d4891 +Subproject commit e162713efa578b9967f7ec921b129362036571b3 diff --git a/frozen/Adafruit_CircuitPython_Bitmap_Font b/frozen/Adafruit_CircuitPython_Bitmap_Font index 5ca3f55f2e3..13c6a39a58e 160000 --- a/frozen/Adafruit_CircuitPython_Bitmap_Font +++ b/frozen/Adafruit_CircuitPython_Bitmap_Font @@ -1 +1 @@ -Subproject commit 5ca3f55f2e39302c787ca93f95276e8269024038 +Subproject commit 13c6a39a58e28030f3651a90e116c1ab30f2035b diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice index afe91665e43..baa6bcafa22 160000 --- a/frozen/Adafruit_CircuitPython_BusDevice +++ b/frozen/Adafruit_CircuitPython_BusDevice @@ -1 +1 @@ -Subproject commit afe91665e438947bd3d88ba4a0f937ec58ff1035 +Subproject commit baa6bcafa22512ac56f343c7d124f3b029861c33 diff --git a/frozen/Adafruit_CircuitPython_CircuitPlayground b/frozen/Adafruit_CircuitPython_CircuitPlayground index d093fed4059..65be0763bed 160000 --- a/frozen/Adafruit_CircuitPython_CircuitPlayground +++ b/frozen/Adafruit_CircuitPython_CircuitPlayground @@ -1 +1 @@ -Subproject commit d093fed40590af312e44b1efa8d88ecaef9aaed4 +Subproject commit 65be0763beda780d3a1a8c4c49b033628bc54d28 diff --git a/frozen/Adafruit_CircuitPython_ConnectionManager b/frozen/Adafruit_CircuitPython_ConnectionManager index 95f39faaa64..2c85f3b98d0 160000 --- a/frozen/Adafruit_CircuitPython_ConnectionManager +++ b/frozen/Adafruit_CircuitPython_ConnectionManager @@ -1 +1 @@ -Subproject commit 95f39faaa647b4215f615603368a453742423a09 +Subproject commit 2c85f3b98d08102d2494195074ad836fc3020610 diff --git a/frozen/Adafruit_CircuitPython_Crickit b/frozen/Adafruit_CircuitPython_Crickit index efeb183228f..722f7937bfb 160000 --- a/frozen/Adafruit_CircuitPython_Crickit +++ b/frozen/Adafruit_CircuitPython_Crickit @@ -1 +1 @@ -Subproject commit efeb183228ff9640aec5938f9c2305766579dc25 +Subproject commit 722f7937bfb0c02340dcf737ebf37cc4ecf86b83 diff --git a/frozen/Adafruit_CircuitPython_DRV2605 b/frozen/Adafruit_CircuitPython_DRV2605 index f120d562221..616d61c7495 160000 --- a/frozen/Adafruit_CircuitPython_DRV2605 +++ b/frozen/Adafruit_CircuitPython_DRV2605 @@ -1 +1 @@ -Subproject commit f120d56222166af85b33e8e9c70eff6aec2e4828 +Subproject commit 616d61c7495e5dadc6b77ea9fce07a3861580534 diff --git a/frozen/Adafruit_CircuitPython_DS3231 b/frozen/Adafruit_CircuitPython_DS3231 index a5d94eee49d..62cc4dc49b5 160000 --- a/frozen/Adafruit_CircuitPython_DS3231 +++ b/frozen/Adafruit_CircuitPython_DS3231 @@ -1 +1 @@ -Subproject commit a5d94eee49d324bad474847749c3d481a1f7c908 +Subproject commit 62cc4dc49b587fad935368ed60b9ba1433250fdc diff --git a/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 b/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 index 4b382e8986d..89463c9bd81 160000 --- a/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 +++ b/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 @@ -1 +1 @@ -Subproject commit 4b382e8986db36eaef558fec67be543205f268b2 +Subproject commit 89463c9bd81aaf43a14fd4f3c7bdbb75d4e48b40 diff --git a/frozen/Adafruit_CircuitPython_Display_Text b/frozen/Adafruit_CircuitPython_Display_Text index 7d1f187aac8..727a1022e14 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit 7d1f187aac8e899e791324cc78633bf4f32c984b +Subproject commit 727a1022e140b971a2f4bde5e6571dd327f6785d diff --git a/frozen/Adafruit_CircuitPython_DotStar b/frozen/Adafruit_CircuitPython_DotStar index 4b0ba649e5a..8d19e1b23cb 160000 --- a/frozen/Adafruit_CircuitPython_DotStar +++ b/frozen/Adafruit_CircuitPython_DotStar @@ -1 +1 @@ -Subproject commit 4b0ba649e5abdebead5b9a47a6c695d67c2c25fa +Subproject commit 8d19e1b23cbe6c1d17a29f321d06b16d21909b92 diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index 063b90c8706..3fcea236876 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit 063b90c8706ddef97cc4abf9cb78e0cc09ff3c6c +Subproject commit 3fcea236876b05d09ebf95f43cec6016667ccf84 diff --git a/frozen/Adafruit_CircuitPython_FakeRequests b/frozen/Adafruit_CircuitPython_FakeRequests index 020121e90c6..ff942eaae83 160000 --- a/frozen/Adafruit_CircuitPython_FakeRequests +++ b/frozen/Adafruit_CircuitPython_FakeRequests @@ -1 +1 @@ -Subproject commit 020121e90c6306147f91b8079b75f3d14ff86138 +Subproject commit ff942eaae835144f7269d8206adf506c99f699f4 diff --git a/frozen/Adafruit_CircuitPython_FocalTouch b/frozen/Adafruit_CircuitPython_FocalTouch index 2fb86313db3..f20c13bdffa 160000 --- a/frozen/Adafruit_CircuitPython_FocalTouch +++ b/frozen/Adafruit_CircuitPython_FocalTouch @@ -1 +1 @@ -Subproject commit 2fb86313db3408e57b1fbfbc56359ccb4f16f38b +Subproject commit f20c13bdffa9b586c648f331851f427368a995ae diff --git a/frozen/Adafruit_CircuitPython_HID b/frozen/Adafruit_CircuitPython_HID index d06b8b812ca..788e46ca2cb 160000 --- a/frozen/Adafruit_CircuitPython_HID +++ b/frozen/Adafruit_CircuitPython_HID @@ -1 +1 @@ -Subproject commit d06b8b812caef3ae2eebb662f4e57ca306ce3219 +Subproject commit 788e46ca2cb2febddac83e0c660972598d6a8a27 diff --git a/frozen/Adafruit_CircuitPython_HTTPServer b/frozen/Adafruit_CircuitPython_HTTPServer index c43147a016f..e234a494050 160000 --- a/frozen/Adafruit_CircuitPython_HTTPServer +++ b/frozen/Adafruit_CircuitPython_HTTPServer @@ -1 +1 @@ -Subproject commit c43147a016ffd13c57a0923730bc6a83afefb4ad +Subproject commit e234a4940504b4fb21c7338d774ec273260ef672 diff --git a/frozen/Adafruit_CircuitPython_IRRemote b/frozen/Adafruit_CircuitPython_IRRemote index b92d6930421..98bd8fad8cd 160000 --- a/frozen/Adafruit_CircuitPython_IRRemote +++ b/frozen/Adafruit_CircuitPython_IRRemote @@ -1 +1 @@ -Subproject commit b92d69304212ee57a5f008317fcc4ebaf75ddebb +Subproject commit 98bd8fad8cd65f481b8808e5de8cdbf62d0dd300 diff --git a/frozen/Adafruit_CircuitPython_IS31FL3731 b/frozen/Adafruit_CircuitPython_IS31FL3731 index a0d701892d8..1babff02ea8 160000 --- a/frozen/Adafruit_CircuitPython_IS31FL3731 +++ b/frozen/Adafruit_CircuitPython_IS31FL3731 @@ -1 +1 @@ -Subproject commit a0d701892d8bef096d80f1117bee718cecb380ff +Subproject commit 1babff02ea87f5c4863aed20be0da553d76e9600 diff --git a/frozen/Adafruit_CircuitPython_ImageLoad b/frozen/Adafruit_CircuitPython_ImageLoad index 135b0e4478b..67532099f7a 160000 --- a/frozen/Adafruit_CircuitPython_ImageLoad +++ b/frozen/Adafruit_CircuitPython_ImageLoad @@ -1 +1 @@ -Subproject commit 135b0e4478b34e1271e6bd87fa6d8efa0bef64b5 +Subproject commit 67532099f7a574f08955b31efb7c1ca5cc3f143c diff --git a/frozen/Adafruit_CircuitPython_LC709203F b/frozen/Adafruit_CircuitPython_LC709203F index b007bcae07b..7fe15ca666b 160000 --- a/frozen/Adafruit_CircuitPython_LC709203F +++ b/frozen/Adafruit_CircuitPython_LC709203F @@ -1 +1 @@ -Subproject commit b007bcae07b346fd28aaee770dcabc9dde698c67 +Subproject commit 7fe15ca666bd3730a17e13bb29ff884092345b5f diff --git a/frozen/Adafruit_CircuitPython_LED_Animation b/frozen/Adafruit_CircuitPython_LED_Animation index 8af05705962..515553f0b6c 160000 --- a/frozen/Adafruit_CircuitPython_LED_Animation +++ b/frozen/Adafruit_CircuitPython_LED_Animation @@ -1 +1 @@ -Subproject commit 8af05705962e8bb7d2f8003e6a70916a9a51b863 +Subproject commit 515553f0b6cb1290b92965f8e4e8beab9e83bcf1 diff --git a/frozen/Adafruit_CircuitPython_LIS3DH b/frozen/Adafruit_CircuitPython_LIS3DH index 640b18ec1bf..a3c33eff7c0 160000 --- a/frozen/Adafruit_CircuitPython_LIS3DH +++ b/frozen/Adafruit_CircuitPython_LIS3DH @@ -1 +1 @@ -Subproject commit 640b18ec1bfd71e0a70f7ff3b8784043cd2d2671 +Subproject commit a3c33eff7c03e7c1f1e896a08f4878f5db6a6cbf diff --git a/frozen/Adafruit_CircuitPython_LSM6DS b/frozen/Adafruit_CircuitPython_LSM6DS index 2f50836f4bf..e7da74fd8d7 160000 --- a/frozen/Adafruit_CircuitPython_LSM6DS +++ b/frozen/Adafruit_CircuitPython_LSM6DS @@ -1 +1 @@ -Subproject commit 2f50836f4bf0d9e48e4b8e046ba4d4167ad6dbdc +Subproject commit e7da74fd8d7fddd9515e975be5479596283a719c diff --git a/frozen/Adafruit_CircuitPython_MIDI b/frozen/Adafruit_CircuitPython_MIDI index c4e693c2d49..2bc55548577 160000 --- a/frozen/Adafruit_CircuitPython_MIDI +++ b/frozen/Adafruit_CircuitPython_MIDI @@ -1 +1 @@ -Subproject commit c4e693c2d4904d885cf842efc25687ccaccbabfa +Subproject commit 2bc555485772743b70f620fe939048020924a605 diff --git a/frozen/Adafruit_CircuitPython_MPU6050 b/frozen/Adafruit_CircuitPython_MPU6050 index 05a0c3b7227..bb5100733f3 160000 --- a/frozen/Adafruit_CircuitPython_MPU6050 +++ b/frozen/Adafruit_CircuitPython_MPU6050 @@ -1 +1 @@ -Subproject commit 05a0c3b72279db9fa2431308a77e6ab7ba040c8a +Subproject commit bb5100733f339dcad24df7d32eeeb492023b5059 diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index 89facc69a40..610c42f1187 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit 89facc69a405ae83702ce566414adc39d46068f1 +Subproject commit 610c42f1187045fb962807ac8d895e66e2612298 diff --git a/frozen/Adafruit_CircuitPython_NeoPixel b/frozen/Adafruit_CircuitPython_NeoPixel index 0ba2f2122a5..1a9523574b6 160000 --- a/frozen/Adafruit_CircuitPython_NeoPixel +++ b/frozen/Adafruit_CircuitPython_NeoPixel @@ -1 +1 @@ -Subproject commit 0ba2f2122a54a71b1bc3576f87b1ba7dfc9db11e +Subproject commit 1a9523574b68cc205c151aaf080909348df7417c diff --git a/frozen/Adafruit_CircuitPython_PCF8563 b/frozen/Adafruit_CircuitPython_PCF8563 index 74bb72d1c60..3f40c877acb 160000 --- a/frozen/Adafruit_CircuitPython_PCF8563 +++ b/frozen/Adafruit_CircuitPython_PCF8563 @@ -1 +1 @@ -Subproject commit 74bb72d1c607e44cf0d5349c466acd34863c11b4 +Subproject commit 3f40c877acbbda0ef82336c18f3620ce1b9013f5 diff --git a/frozen/Adafruit_CircuitPython_Pixel_Framebuf b/frozen/Adafruit_CircuitPython_Pixel_Framebuf index 1db789cf994..d355df47c0d 160000 --- a/frozen/Adafruit_CircuitPython_Pixel_Framebuf +++ b/frozen/Adafruit_CircuitPython_Pixel_Framebuf @@ -1 +1 @@ -Subproject commit 1db789cf99429e27d740279000788edc794d9d0d +Subproject commit d355df47c0d5c1f80da01c86d585223988f30a33 diff --git a/frozen/Adafruit_CircuitPython_PortalBase b/frozen/Adafruit_CircuitPython_PortalBase index d26e2324de4..25fc43dd67a 160000 --- a/frozen/Adafruit_CircuitPython_PortalBase +++ b/frozen/Adafruit_CircuitPython_PortalBase @@ -1 +1 @@ -Subproject commit d26e2324de496761e0aa72abc30ba07cdce8814b +Subproject commit 25fc43dd67ae95a8e62173e90c3069502194873a diff --git a/frozen/Adafruit_CircuitPython_ProgressBar b/frozen/Adafruit_CircuitPython_ProgressBar index 6ba9d9d991a..9fa23112cea 160000 --- a/frozen/Adafruit_CircuitPython_ProgressBar +++ b/frozen/Adafruit_CircuitPython_ProgressBar @@ -1 +1 @@ -Subproject commit 6ba9d9d991ada6c0cea6a32bd64595cfd37e06b2 +Subproject commit 9fa23112cea1a8db2b9b87cf2156cc4b039440a7 diff --git a/frozen/Adafruit_CircuitPython_RFM69 b/frozen/Adafruit_CircuitPython_RFM69 index 07be137bf5b..62cb5cf6fbe 160000 --- a/frozen/Adafruit_CircuitPython_RFM69 +++ b/frozen/Adafruit_CircuitPython_RFM69 @@ -1 +1 @@ -Subproject commit 07be137bf5bda7a0469225c9cbb09b9a0aa08791 +Subproject commit 62cb5cf6fbeb9943bf7b2db4fc614f9b40830bf3 diff --git a/frozen/Adafruit_CircuitPython_RFM9x b/frozen/Adafruit_CircuitPython_RFM9x index 609aafb018b..5b8a9ae0ace 160000 --- a/frozen/Adafruit_CircuitPython_RFM9x +++ b/frozen/Adafruit_CircuitPython_RFM9x @@ -1 +1 @@ -Subproject commit 609aafb018b1cf5b7f60f2a7c961b827dce7468e +Subproject commit 5b8a9ae0ace6bd5f3a0860c95c3c389a09e4b59b diff --git a/frozen/Adafruit_CircuitPython_Register b/frozen/Adafruit_CircuitPython_Register index 96d0a4774f5..98faa16a0dd 160000 --- a/frozen/Adafruit_CircuitPython_Register +++ b/frozen/Adafruit_CircuitPython_Register @@ -1 +1 @@ -Subproject commit 96d0a4774f5525b926c131618e436b8e5c218a2f +Subproject commit 98faa16a0dd6c63a2726b291a53fde760a0fcabb diff --git a/frozen/Adafruit_CircuitPython_Requests b/frozen/Adafruit_CircuitPython_Requests index 5e646b244cf..1479169b59d 160000 --- a/frozen/Adafruit_CircuitPython_Requests +++ b/frozen/Adafruit_CircuitPython_Requests @@ -1 +1 @@ -Subproject commit 5e646b244cf36f879f15aaf77a270e4c7e6e8336 +Subproject commit 1479169b59d069b15384da64645f1e2d711a4679 diff --git a/frozen/Adafruit_CircuitPython_SD b/frozen/Adafruit_CircuitPython_SD index ee4d73293c8..dfbb9fd6ae2 160000 --- a/frozen/Adafruit_CircuitPython_SD +++ b/frozen/Adafruit_CircuitPython_SD @@ -1 +1 @@ -Subproject commit ee4d73293c8d059cd0c8bcf46758e62f5393cbee +Subproject commit dfbb9fd6ae297d6246554ea44e6c318970de98af diff --git a/frozen/Adafruit_CircuitPython_SHT4x b/frozen/Adafruit_CircuitPython_SHT4x index 26a0a407d43..9da248ca944 160000 --- a/frozen/Adafruit_CircuitPython_SHT4x +++ b/frozen/Adafruit_CircuitPython_SHT4x @@ -1 +1 @@ -Subproject commit 26a0a407d43bd6208deffdf577e214d899855c0e +Subproject commit 9da248ca944264cbc4278c1732f901f3e1229231 diff --git a/frozen/Adafruit_CircuitPython_SSD1306 b/frozen/Adafruit_CircuitPython_SSD1306 index d75b4d593cd..2d7fd1fd8f7 160000 --- a/frozen/Adafruit_CircuitPython_SSD1306 +++ b/frozen/Adafruit_CircuitPython_SSD1306 @@ -1 +1 @@ -Subproject commit d75b4d593cd184cbea5e237f5212cd9122d46263 +Subproject commit 2d7fd1fd8f7bb1b83d60926a28ab01ffaf67fa3b diff --git a/frozen/Adafruit_CircuitPython_SSD1680 b/frozen/Adafruit_CircuitPython_SSD1680 index d6aa01c4f8f..c22e6d097b4 160000 --- a/frozen/Adafruit_CircuitPython_SSD1680 +++ b/frozen/Adafruit_CircuitPython_SSD1680 @@ -1 +1 @@ -Subproject commit d6aa01c4f8fa1004430bfcdd4db2219183425693 +Subproject commit c22e6d097b44c6e9612ff6b866ebec569796e6f5 diff --git a/frozen/Adafruit_CircuitPython_ST7789 b/frozen/Adafruit_CircuitPython_ST7789 index 0f7269267c0..1060cf1753d 160000 --- a/frozen/Adafruit_CircuitPython_ST7789 +++ b/frozen/Adafruit_CircuitPython_ST7789 @@ -1 +1 @@ -Subproject commit 0f7269267c0d17ada34926333bbda4021e5d7cb3 +Subproject commit 1060cf1753df0024a95070132045357ddd9ce559 diff --git a/frozen/Adafruit_CircuitPython_SimpleIO b/frozen/Adafruit_CircuitPython_SimpleIO index d5278d246bc..054d2643744 160000 --- a/frozen/Adafruit_CircuitPython_SimpleIO +++ b/frozen/Adafruit_CircuitPython_SimpleIO @@ -1 +1 @@ -Subproject commit d5278d246bcf658ef5d44e7658c956fac29bd9e1 +Subproject commit 054d2643744fe78fed3c4c8b371ced26c8ab2ebe diff --git a/frozen/Adafruit_CircuitPython_SimpleMath b/frozen/Adafruit_CircuitPython_SimpleMath index 33f82828598..da27f052357 160000 --- a/frozen/Adafruit_CircuitPython_SimpleMath +++ b/frozen/Adafruit_CircuitPython_SimpleMath @@ -1 +1 @@ -Subproject commit 33f82828598a3a10c73dfa50601fef4beac40be8 +Subproject commit da27f05235713bc8e79cf3a005d11bab920e13bb diff --git a/frozen/Adafruit_CircuitPython_Thermistor b/frozen/Adafruit_CircuitPython_Thermistor index 2b45967cc52..f109e9d847b 160000 --- a/frozen/Adafruit_CircuitPython_Thermistor +++ b/frozen/Adafruit_CircuitPython_Thermistor @@ -1 +1 @@ -Subproject commit 2b45967cc5283e71b7826f6a158d8c8556dde287 +Subproject commit f109e9d847b7f8ba8545a2b6be8d0c3dd6a8a280 diff --git a/frozen/Adafruit_CircuitPython_Ticks b/frozen/Adafruit_CircuitPython_Ticks index 6e159f899b0..83695404ab7 160000 --- a/frozen/Adafruit_CircuitPython_Ticks +++ b/frozen/Adafruit_CircuitPython_Ticks @@ -1 +1 @@ -Subproject commit 6e159f899b017e920a6058a6b16735af8a6e852e +Subproject commit 83695404ab734eb60d32c9e96784b9bd90c58a1a diff --git a/frozen/Adafruit_CircuitPython_UC8151D b/frozen/Adafruit_CircuitPython_UC8151D index 4ebf9c28543..b9bd61a0bbe 160000 --- a/frozen/Adafruit_CircuitPython_UC8151D +++ b/frozen/Adafruit_CircuitPython_UC8151D @@ -1 +1 @@ -Subproject commit 4ebf9c2854376a06766a6ae4732a4537a766fb75 +Subproject commit b9bd61a0bbef1f4705abb831739d4888f1dcec95 diff --git a/frozen/Adafruit_CircuitPython_Wave b/frozen/Adafruit_CircuitPython_Wave index 6fba948b024..d302cd78d29 160000 --- a/frozen/Adafruit_CircuitPython_Wave +++ b/frozen/Adafruit_CircuitPython_Wave @@ -1 +1 @@ -Subproject commit 6fba948b024ec210b3cf1f1b068b3eebc82fe8d4 +Subproject commit d302cd78d29ef821faa1c18482a0b20fdca1d4ee diff --git a/frozen/Adafruit_CircuitPython_Wiznet5k b/frozen/Adafruit_CircuitPython_Wiznet5k index 736241c7a22..ea7b97c5b1f 160000 --- a/frozen/Adafruit_CircuitPython_Wiznet5k +++ b/frozen/Adafruit_CircuitPython_Wiznet5k @@ -1 +1 @@ -Subproject commit 736241c7a22f86dcf8ff73a77c4536cedfdc4cdd +Subproject commit ea7b97c5b1faa2db4b54d7f6d9a61b545b49f383 diff --git a/frozen/Adafruit_CircuitPython_asyncio b/frozen/Adafruit_CircuitPython_asyncio index 24818f817f5..e69ac03dccf 160000 --- a/frozen/Adafruit_CircuitPython_asyncio +++ b/frozen/Adafruit_CircuitPython_asyncio @@ -1 +1 @@ -Subproject commit 24818f817f5118f59aa696a04776049c179c0f4f +Subproject commit e69ac03dccfd87ccaf3655dc751331ff922f525f diff --git a/frozen/Adafruit_CircuitPython_framebuf b/frozen/Adafruit_CircuitPython_framebuf index 0fedf2f308e..8a94ddb7257 160000 --- a/frozen/Adafruit_CircuitPython_framebuf +++ b/frozen/Adafruit_CircuitPython_framebuf @@ -1 +1 @@ -Subproject commit 0fedf2f308ed6b3e8261661e4810e613f33d7171 +Subproject commit 8a94ddb7257bebfb856fe476d9b851dfa63ce443 diff --git a/frozen/Adafruit_CircuitPython_seesaw b/frozen/Adafruit_CircuitPython_seesaw index 94c541f4531..d01642926b8 160000 --- a/frozen/Adafruit_CircuitPython_seesaw +++ b/frozen/Adafruit_CircuitPython_seesaw @@ -1 +1 @@ -Subproject commit 94c541f45313dc7eb98a4cd1a6c3af39f001cc49 +Subproject commit d01642926b80a46762f1dd76dcdd5aefb0d95bc8 From 3f0b1b8c9d9fc41b29ef5fd36cb8283b75c48198 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 14 Nov 2025 12:20:00 -0800 Subject: [PATCH 093/876] Fix mipidsi cache flush The old way didn't flush all caches and left artifacts. Fixes #10708 --- ports/espressif/common-hal/mipidsi/Display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/espressif/common-hal/mipidsi/Display.c b/ports/espressif/common-hal/mipidsi/Display.c index dac16162e91..cc45db72375 100644 --- a/ports/espressif/common-hal/mipidsi/Display.c +++ b/ports/espressif/common-hal/mipidsi/Display.c @@ -213,8 +213,9 @@ bool common_hal_mipidsi_display_deinited(mipidsi_display_obj_t *self) { } void common_hal_mipidsi_display_refresh(mipidsi_display_obj_t *self) { - // Write back the cache to ensure framebuffer changes are visible - Cache_WriteBack_Addr((uint32_t)(self->framebuffer), self->framebuffer_size); + // Drawing the framebuffer we got from the IDF will flush the cache(s) so + // DMA can see our changes. It won't cause an extra copy. + esp_lcd_panel_draw_bitmap(self->dpi_panel_handle, 0, 0, self->width, self->height, self->framebuffer); // The DPI panel will automatically refresh from the framebuffer // No explicit refresh call is needed as the DSI hardware continuously From 82ff9f1c1e252917dafc0cb5a613fb489efcdd2b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 19 Nov 2025 15:23:54 -0800 Subject: [PATCH 094/876] Enable OV3660 camera support on XIAO S3 Fixes #10718 --- ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig index 919f4d9f345..2d98e822542 100644 --- a/ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_sense/sdkconfig @@ -5,15 +5,13 @@ # Component config # # -# LWIP # -# end of LWIP # Camera configuration # -CONFIG_OV2640_SUPPORT=y # CONFIG_OV7725_SUPPORT is not set -# CONFIG_OV3660_SUPPORT is not set +CONFIG_OV2640_SUPPORT=y # end of Camera configuration + # end of Component config # end of Espressif IoT Development Framework Configuration From b35fbdc624c19ae8b4b034d59e5b175b705b4594 Mon Sep 17 00:00:00 2001 From: Hans Maerki Date: Thu, 20 Nov 2025 21:24:47 +0000 Subject: [PATCH 095/876] Allow microcontroller.nvm to be bigger than 8k Signed-off-by: Hans Maerki --- shared-bindings/nvm/ByteArray.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/nvm/ByteArray.c b/shared-bindings/nvm/ByteArray.c index be01c1f7064..b2783006267 100644 --- a/shared-bindings/nvm/ByteArray.c +++ b/shared-bindings/nvm/ByteArray.c @@ -35,7 +35,7 @@ //| static mp_obj_t nvm_bytearray_unary_op(mp_unary_op_t op, mp_obj_t self_in) { nvm_bytearray_obj_t *self = MP_OBJ_TO_PTR(self_in); - uint16_t len = common_hal_nvm_bytearray_get_length(self); + uint32_t len = common_hal_nvm_bytearray_get_length(self); switch (op) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len != 0); From 70a3af8cf86b31cd6a20e318cd7af222b558944c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 17 Nov 2025 12:10:37 -0800 Subject: [PATCH 096/876] Update to Zephyr v4.3.0 --- .../actions/deps/ports/zephyr-cp/action.yml | 6 + ports/zephyr-cp/README.md | 4 +- .../boards/nrf7002dk_nrf5340_cpuapp.conf | 2 +- .../zephyr-cp/cptools/build_circuitpython.py | 21 +- ports/zephyr-cp/cptools/compat2driver.py | 742 ++++++++++++++++-- ports/zephyr-cp/cptools/cpbuild.py | 89 ++- ports/zephyr-cp/cptools/gen_compat2driver.py | 2 +- ports/zephyr-cp/cptools/zephyr2cp.py | 93 ++- ports/zephyr-cp/prj.conf | 2 +- ports/zephyr-cp/zephyr-config/west.yml | 2 +- 10 files changed, 838 insertions(+), 125 deletions(-) diff --git a/.github/actions/deps/ports/zephyr-cp/action.yml b/.github/actions/deps/ports/zephyr-cp/action.yml index cfa1177598e..75ff232562c 100644 --- a/.github/actions/deps/ports/zephyr-cp/action.yml +++ b/.github/actions/deps/ports/zephyr-cp/action.yml @@ -3,6 +3,12 @@ name: Fetch Zephyr port deps runs: using: composite steps: + - name: Get libusb + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y libusb-1.0-0-dev libudev-dev + shell: bash - name: Setup Zephyr project uses: zephyrproject-rtos/action-zephyr-setup@v1 with: diff --git a/ports/zephyr-cp/README.md b/ports/zephyr-cp/README.md index 4d08936cad6..1fba1d7d3f7 100644 --- a/ports/zephyr-cp/README.md +++ b/ports/zephyr-cp/README.md @@ -15,11 +15,11 @@ pip install west west init -l zephyr-config west update west zephyr-export -pip install -r lib/zephyr/scripts/requirements.txt +pip install -r zephyr/scripts/requirements.txt west sdk install ``` -Now to build from the top level: +Now to build from `ports/zephyr-cp`: ```sh make BOARD=nordic_nrf7002dk diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index 6f01624bb3a..c61851fad2d 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -1,7 +1,7 @@ CONFIG_NETWORKING=y CONFIG_WIFI=y -CONFIG_MBEDTLS_TLS_VERSION_1_2=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y CONFIG_MBEDTLS_USE_PSA_CRYPTO=n CONFIG_BT=y diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 61e103e9fe1..fd1ca7dc43f 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -1,16 +1,16 @@ import asyncio -import colorlog -import sys import logging import os import pathlib -import tomllib -import tomlkit -import yaml import pickle +import sys -import cpbuild import board_tools +import colorlog +import cpbuild +import tomlkit +import tomllib +import yaml logger = logging.getLogger(__name__) @@ -219,13 +219,13 @@ async def build_circuitpython(): circuitpython_flags.append(f"-DCIRCUITPY_ENABLE_MPY_NATIVE={1 if enable_mpy_native else 0}") circuitpython_flags.append(f"-DCIRCUITPY_FULL_BUILD={1 if full_build else 0}") circuitpython_flags.append(f"-DCIRCUITPY_USB_HOST={1 if usb_host else 0}") - circuitpython_flags.append(f'-DCIRCUITPY_BOARD_ID=\\"{board}\\"') + circuitpython_flags.append(f"-DCIRCUITPY_BOARD_ID='\"{board}\"'") circuitpython_flags.append(f"-DCIRCUITPY_TUSB_MEM_ALIGN={tusb_mem_align}") circuitpython_flags.append(f"-DCIRCUITPY_TRANSLATE_OBJECT={1 if lto else 0}") circuitpython_flags.append("-DINTERNAL_FLASH_FILESYSTEM") circuitpython_flags.append("-DLONGINT_IMPL_MPZ") circuitpython_flags.append("-DCIRCUITPY_SSL_MBEDTLS") - circuitpython_flags.append('-DFFCONF_H=\\"lib/oofatfs/ffconf.h\\"') + circuitpython_flags.append("-DFFCONF_H='\"lib/oofatfs/ffconf.h\"'") circuitpython_flags.extend(("-I", srcdir)) circuitpython_flags.extend(("-I", srcdir / "lib/tinyusb/src")) circuitpython_flags.extend(("-I", srcdir / "supervisor/shared/usb")) @@ -448,10 +448,7 @@ async def build_circuitpython(): if "ssl" in enabled_modules: # TODO: Figure out how to get these paths from zephyr - circuitpython_flags.append('-DMBEDTLS_CONFIG_FILE=\\"config-tls-generic.h\\"') - circuitpython_flags.extend( - ("-isystem", portdir / "modules" / "crypto" / "tinycrypt" / "lib" / "include") - ) + circuitpython_flags.append("-DMBEDTLS_CONFIG_FILE='\"config-mbedtls.h\"'") circuitpython_flags.extend( ("-isystem", portdir / "modules" / "crypto" / "mbedtls" / "include") ) diff --git a/ports/zephyr-cp/cptools/compat2driver.py b/ports/zephyr-cp/cptools/compat2driver.py index 2b818c4c237..dff09787b28 100644 --- a/ports/zephyr-cp/cptools/compat2driver.py +++ b/ports/zephyr-cp/cptools/compat2driver.py @@ -1,18 +1,29 @@ # This file was generated by gen_compat2driver.py COMPAT_TO_DRIVER = { # adc + "adi_ad4050_adc": "adc", + "adi_ad4052_adc": "adc", "adi_ad4114_adc": "adc", + "adi_ad4130_adc": "adc", + "adi_ad4170_adc": "adc", + "adi_ad4190_adc": "adc", + "adi_ad4195_adc": "adc", "adi_ad559x_adc": "adc", + "adi_ad7124_adc": "adc", "adi_max32_adc": "adc", "ambiq_adc": "adc", "atmel_sam0_adc": "adc", "atmel_sam_adc": "adc", "atmel_sam_afec": "adc", + "ene_kb106x_adc": "adc", "ene_kb1200_adc": "adc", "espressif_esp32_adc": "adc", "gd_gd32_adc": "adc", + "infineon_autanalog_sar_adc": "adc", "infineon_cat1_adc": "adc", + "infineon_hppass_sar_adc": "adc", "infineon_xmc4xxx_adc": "adc", + "ite_it51xxx_adc": "adc", "ite_it8xxx2_adc": "adc", "lltc_ltc2451": "adc", "maxim_max11102": "adc", @@ -26,6 +37,7 @@ "maxim_max11117": "adc", "maxim_max11253": "adc", "maxim_max11254": "adc", + "microchip_mcp356xr": "adc", "microchip_xec_adc": "adc", "nordic_nrf_adc": "adc", "nordic_nrf_saadc": "adc", @@ -37,13 +49,19 @@ "nxp_lpc_lpadc": "adc", "nxp_mcux_12b1msps_sar": "adc", "nxp_s32_adc_sar": "adc", + "nxp_sar_adc": "adc", "nxp_vf610_adc": "adc", "raspberrypi_pico_adc": "adc", + "realtek_rts5912_adc": "adc", "renesas_ra_adc": "adc", + "renesas_rx_adc": "adc", + "renesas_rz_adc": "adc", + "renesas_rz_adc_c": "adc", "renesas_smartbond_adc": "adc", "renesas_smartbond_sdadc": "adc", "silabs_gecko_adc": "adc", - "silabs_gecko_iadc": "adc", + "silabs_iadc": "adc", + "silabs_siwx91x_adc": "adc", "st_stm32_adc": "adc", "st_stm32wb0_adc": "adc", "telink_b91_adc": "adc", @@ -55,10 +73,15 @@ "ti_ads1114": "adc", "ti_ads1115": "adc", "ti_ads1119": "adc", + "ti_ads114s06": "adc", "ti_ads114s08": "adc", + "ti_ads124s06": "adc", + "ti_ads124s08": "adc", "ti_ads131m02": "adc", "ti_ads7052": "adc", + "ti_am335x_adc": "adc", "ti_cc13xx_cc26xx_adc": "adc", + "ti_cc23x0_adc": "adc", "ti_cc32xx_adc": "adc", "ti_lmp90077": "adc", "ti_lmp90078": "adc", @@ -72,26 +95,42 @@ "ti_tla2022": "adc", "ti_tla2024": "adc", "vnd_adc": "adc", + "wch_adc": "adc", "zephyr_adc_emul": "adc", # # audio + "ambiq_pdm": "audio", + "cirrus_cs43l22": "audio", + "dlg_da7212": "audio", + "maxim_max98091": "audio", "nxp_dmic": "audio", + "nxp_micfil": "audio", "st_mpxxdtyy": "audio", + "ti_pcm1681": "audio", "ti_tas6422dac": "audio", + "ti_tlv320aic3110": "audio", "ti_tlv320dac": "audio", "wolfson_wm8904": "audio", + "wolfson_wm8962": "audio", + # + # audio/mic_privacy/intel + "intel_adsp_mic_privacy": "audio/mic_privacy/intel", # # auxdisplay + "gpio_7_segment": "auxdisplay", "hit_hd44780": "auxdisplay", "jhd_jhd1313": "auxdisplay", "noritake_itron": "auxdisplay", "ptc_pt6314": "auxdisplay", "sparkfun_serlcd": "auxdisplay", + "titanmec_tm1637": "auxdisplay", # # bbram "ite_it8xxx2_bbram": "bbram", "microchip_xec_bbram": "bbram", + "motorola_mc146818_bbram": "bbram", "nuvoton_npcx_bbram": "bbram", + "realtek_rts5912_bbram": "bbram", "st_stm32_bbram": "bbram", "zephyr_bbram_emul": "bbram", # @@ -106,6 +145,7 @@ "renesas_bt_hci_da1453x": "bluetooth/hci", "renesas_bt_hci_da1469x": "bluetooth/hci", "silabs_bt_hci_efr32": "bluetooth/hci", + "silabs_siwx91x_bt_hci": "bluetooth/hci", "st_hci_spi_v1": "bluetooth/hci", "st_hci_spi_v2": "bluetooth/hci", "st_hci_stm32wb0": "bluetooth/hci", @@ -117,7 +157,11 @@ "zephyr_bt_hci_uart": "bluetooth/hci", "zephyr_bt_hci_userchan": "bluetooth/hci", # + # cache + "bflb_l1c": "cache", + # # can + "adi_max32_can": "can", "atmel_sam0_can": "can", "atmel_sam_can": "can", "espressif_esp32_twai": "can", @@ -132,6 +176,7 @@ "nxp_s32_canxl": "can", "renesas_ra_canfd": "can", "renesas_rcar_can": "can", + "renesas_rz_canfd": "can", "st_stm32_bxcan": "can", "st_stm32_fdcan": "can", "st_stm32h7_fdcan": "can", @@ -145,9 +190,13 @@ # # charger "maxim_max20335_charger": "charger", + "nxp_pca9422_charger": "charger", + "nxp_pf1550_charger": "charger", "sbs_sbs_charger": "charger", "ti_bq24190": "charger", "ti_bq25180": "charger", + "ti_bq25713": "charger", + "x_powers_axp2101_charger": "charger", # # clock_control "adi_max32_gcr": "clock_control", @@ -156,10 +205,20 @@ "arm_scmi_clock": "clock_control", "aspeed_ast10x0_clock": "clock_control", "atmel_sam_pmc": "clock_control", - "espressif_esp32_rtc": "clock_control", + "bflb_bl60x_clock_controller": "clock_control", + "bflb_bl61x_clock_controller": "clock_control", + "bflb_bl70x_clock_controller": "clock_control", + "espressif_esp32_clock": "clock_control", "fixed_clock": "clock_control", "gd_gd32_cctl": "clock_control", + "infineon_fixed_clock": "clock_control", + "infineon_fixed_factor_clock": "clock_control", + "infineon_peri_div": "clock_control", "intel_agilex5_clock": "clock_control", + "ite_it51xxx_ecpm": "clock_control", + "microchip_sam_d5x_e5x_clock": "clock_control", + "microchip_sam_pmc": "clock_control", + "microchip_sama7g5_sckc": "clock_control", "microchip_xec_pcr": "clock_control", "nordic_nrf54h_hfxo": "clock_control", "nordic_nrf_auxpll": "clock_control", @@ -167,7 +226,9 @@ "nordic_nrf_fll16m": "clock_control", "nordic_nrf_hsfll_global": "clock_control", "nordic_nrf_hsfll_local": "clock_control", + "nordic_nrf_iron_hsfll_local": "clock_control", "nordic_nrf_lfclk": "clock_control", + "nordic_nrfs_audiopll": "clock_control", "nuvoton_npcm_pcc": "clock_control", "nuvoton_npcx_pcc": "clock_control", "nuvoton_numaker_scc": "clock_control", @@ -179,6 +240,7 @@ "nxp_kinetis_sim": "clock_control", "nxp_lpc11u6x_syscon": "clock_control", "nxp_lpc_syscon": "clock_control", + "nxp_mc_cgm": "clock_control", "nxp_s32_clock": "clock_control", "nxp_scg_k4": "clock_control", "openisa_rv32m1_pcc": "clock_control", @@ -187,10 +249,20 @@ "realtek_rts5912_sccon": "clock_control", "renesas_r8a7795_cpg_mssr": "clock_control", "renesas_r8a779f0_cpg_mssr": "clock_control", + "renesas_ra_cgc_subclk": "clock_control", + "renesas_rx_cgc_pclk": "clock_control", + "renesas_rx_cgc_pll": "clock_control", + "renesas_rx_cgc_root_clock": "clock_control", + "renesas_rz_cgc": "clock_control", + "renesas_rz_cpg": "clock_control", + "renesas_rza2m_cpg": "clock_control", + "sifli_sf32lb_hxt48": "clock_control", + "sifli_sf32lb_rcc_clk": "clock_control", "silabs_series_clock": "clock_control", "silabs_si32_ahb": "clock_control", "silabs_si32_apb": "clock_control", "silabs_si32_pll": "clock_control", + "silabs_siwx91x_clock": "clock_control", "smartbond_clock": "clock_control", "st_stm32_clock_mco": "clock_control", "st_stm32_clock_mux": "clock_control", @@ -198,8 +270,15 @@ "wch_rcc": "clock_control", # # comparator + "ite_it51xxx_vcmp": "comparator", "nordic_nrf_comp": "comparator", "nordic_nrf_lpcomp": "comparator", + "nxp_cmp": "comparator", + "renesas_ra_acmphs": "comparator", + "renesas_ra_lvd": "comparator", + "renesas_rx_lvd": "comparator", + "silabs_acmp": "comparator", + "st_stm32_comp": "comparator", "zephyr_fake_comp": "comparator", # # coredump @@ -208,21 +287,27 @@ # counter "adi_max32_counter": "counter", "adi_max32_rtc_counter": "counter", + "adi_max32_wut": "counter", "ambiq_counter": "counter", "andestech_atcpit100": "counter", "arm_cmsdk_dtimer": "counter", "arm_cmsdk_timer": "counter", "atmel_sam0_tc32": "counter", "atmel_sam_tc": "counter", + "espressif_esp32_counter": "counter", "espressif_esp32_rtc_timer": "counter", - "espressif_esp32_timer": "counter", "gd_gd32_timer": "counter", "infineon_cat1_counter": "counter", + "infineon_tcpwm_counter": "counter", + "ite_it51xxx_counter": "counter", + "ite_it8xxx2_counter": "counter", "maxim_ds3231": "counter", "microchip_mcp7940n": "counter", "microchip_xec_timer": "counter", + "neorv32_gptmr": "counter", "nordic_nrf_rtc": "counter", "nordic_nrf_timer": "counter", + "nxp_ftm": "counter", "nxp_imx_epit": "counter", "nxp_imx_gpt": "counter", "nxp_imx_qtmr": "counter", @@ -231,37 +316,58 @@ "nxp_lpc_ctimer": "counter", "nxp_lpc_rtc": "counter", "nxp_lpc_rtc_highres": "counter", + "nxp_lpit": "counter", "nxp_mrt": "counter", "nxp_pit": "counter", "nxp_rtc": "counter", "nxp_s32_sys_timer": "counter", + "nxp_stm": "counter", "nxp_tpm_timer": "counter", "raspberrypi_pico_timer": "counter", + "realtek_rts5912_slwtimer": "counter", + "realtek_rts5912_timer": "counter", "renesas_ra_agt_counter": "counter", + "renesas_rz_cmtw_counter": "counter", + "renesas_rz_gtm_counter": "counter", "renesas_smartbond_timer": "counter", "silabs_gecko_rtcc": "counter", - "silabs_gecko_stimer": "counter", "snps_dw_timers": "counter", "st_stm32_counter": "counter", + "ti_cc23x0_lgpt": "counter", + "ti_cc23x0_rtc": "counter", + "ti_mspm0_timer_counter": "counter", "xlnx_xps_timer_1_00_a": "counter", "zephyr_native_posix_counter": "counter", + "zephyr_native_sim_counter": "counter", + # + # crc + "renesas_ra_crc": "crc", # # crypto "atmel_ataes132a": "crypto", + "espressif_esp32_aes": "crypto", + "espressif_esp32_sha": "crypto", "intel_adsp_sha": "crypto", + "ite_it51xxx_sha": "crypto", "ite_it8xxx2_sha": "crypto", "ite_it8xxx2_sha_v2": "crypto", "microchip_xec_symcr": "crypto", "nordic_nrf_ecb": "crypto", "nuvoton_npcx_sha": "crypto", "nxp_mcux_dcp": "crypto", + "realtek_rts5912_sha": "crypto", "renesas_smartbond_crypto": "crypto", "silabs_si32_aes": "crypto", "st_stm32_aes": "crypto", "st_stm32_cryp": "crypto", + "st_stm32_hash": "crypto", + "ti_cc23x0_aes": "crypto", # # dac "adi_ad559x_dac": "dac", + "adi_ad5601": "dac", + "adi_ad5611": "dac", + "adi_ad5621": "dac", "adi_ad5628": "dac", "adi_ad5648": "dac", "adi_ad5668": "dac", @@ -279,15 +385,20 @@ "adi_max22017_dac": "dac", "atmel_sam0_dac": "dac", "atmel_sam_dac": "dac", + "atmel_samd5x_dac": "dac", "espressif_esp32_dac": "dac", "gd_gd32_dac": "dac", "microchip_mcp4725": "dac", "microchip_mcp4728": "dac", + "nxp_dac12": "dac", "nxp_gau_dac": "dac", "nxp_kinetis_dac": "dac", "nxp_kinetis_dac32": "dac", "nxp_lpdac": "dac", + "renesas_ra_dac": "dac", + "silabs_vdac": "dac", "st_stm32_dac": "dac", + "ti_dac161s997": "dac", "ti_dacx0501": "dac", "vnd_dac": "dac", # @@ -303,9 +414,16 @@ # dai/intel/ssp "intel_ssp_dai": "dai/intel/ssp", # + # dai/nxp/micfil + "nxp_dai_micfil": "dai/nxp/micfil", + # # dai/nxp/sai "nxp_dai_sai": "dai/nxp/sai", # + # debug + "nordic_coresight_nrf": "debug", + "silabs_pti": "debug", + # # disk "st_stm32_sdmmc": "disk", "zephyr_flash_disk": "disk", @@ -317,36 +435,45 @@ "nvme_controller": "disk/nvme", # # display + "chipone_co5300": "display", "frida_nt35510": "display", "galaxycore_gc9x01x": "display", + "himax_hx8379c": "display", "himax_hx8394": "display", "ilitek_ili9806e_dsi": "display", "intel_multiboot_framebuffer": "display", "istech_ist3931": "display", + "jdi_lpm013m126": "display", "led_strip_matrix": "display", "maxim_max7219": "display", "nxp_dcnano_lcdif": "display", "nxp_imx_elcdif": "display", + "nxp_imx_lcdifv3": "display", "orisetech_otm8009a": "display", "raydium_rm67162": "display", "raydium_rm68200": "display", "renesas_ra_glcdc": "display", "renesas_smartbond_display": "display", "sharp_ls0xx": "display", + "sitronix_st75256": "display", + "sitronix_st7701": "display", "sitronix_st7735r": "display", "sitronix_st7789v": "display", "sitronix_st7796s": "display", "solomon_ssd1322": "display", "st_stm32_ltdc": "display", + "waveshare_7inch_dsi_lcd_c": "display", "zephyr_dummy_dc": "display", + "zephyr_hub12": "display", "zephyr_sdl_dc": "display", # # dma "adi_max32_dma": "dma", "altr_msgdma": "dma", - "andestech_atcdmac300": "dma", + "andestech_atcdmacx00": "dma", "atmel_sam0_dmac": "dma", "atmel_sam_xdmac": "dma", + "bflb_dma": "dma", "brcm_iproc_pax_dma_v1": "dma", "brcm_iproc_pax_dma_v2": "dma", "espressif_esp32_gdma": "dma", @@ -362,6 +489,7 @@ "intel_lpss": "dma", "intel_sedi_dma": "dma", "microchip_xec_dmac": "dma", + "nuvoton_npcx_gdma": "dma", "nxp_lpc_dma": "dma", "nxp_mcux_edma": "dma", "nxp_pxp": "dma", @@ -369,9 +497,15 @@ "nxp_smartdma": "dma", "nxp_sof_host_dma": "dma", "raspberrypi_pico_dma": "dma", + "renesas_ra_dma": "dma", + "renesas_rz_dmac": "dma", + "renesas_rz_dmac_b": "dma", "renesas_smartbond_dma": "dma", + "sifli_sf32lb_dmac": "dma", + "silabs_gpdma": "dma", "silabs_ldma": "dma", "silabs_si32_dma": "dma", + "silabs_siwx91x_dma": "dma", "snps_designware_dma": "dma", "snps_designware_dma_axi": "dma", "st_stm32_bdma": "dma", @@ -380,6 +514,8 @@ "st_stm32_dma_v2bis": "dma", "st_stm32_dmamux": "dma", "st_stm32u5_dma": "dma", + "ti_cc23x0_dma": "dma", + "wch_wch_dma": "dma", "xlnx_axi_dma_1_00_a": "dma", "xlnx_eth_dma": "dma", "zephyr_dma_emul": "dma", @@ -389,40 +525,50 @@ # # edac "intel_ibecc": "edac", + "xlnx_zynqmp_ddrc_2_40a": "edac", # # eeprom "atmel_at24": "eeprom", "fujitsu_mb85rcxx": "eeprom", "fujitsu_mb85rsxx": "eeprom", + "infineon_fm25xxx": "eeprom", "microchip_xec_eeprom": "eeprom", "nxp_lpc11u6x_eeprom": "eeprom", "st_stm32_eeprom": "eeprom", - "ti_tmp116_eeprom": "eeprom", + "ti_tmp11x_eeprom": "eeprom", "zephyr_emu_eeprom": "eeprom", "zephyr_fake_eeprom": "eeprom", "zephyr_sim_eeprom": "eeprom", # # entropy "adi_max32_trng": "entropy", + "adi_maxq10xx_trng": "entropy", + "ambiq_puf_trng": "entropy", "atmel_sam_trng": "entropy", + "brcm_iproc_rng200": "entropy", "espressif_esp32_trng": "entropy", "litex_prbs": "entropy", "neorv32_trng": "entropy", + "nordic_nrf_cracen_ctrdrbg": "entropy", "nordic_nrf_rng": "entropy", "nuvoton_npcx_drbg": "entropy", + "nxp_ele_trng": "entropy", "nxp_imx_caam": "entropy", "nxp_kinetis_rnga": "entropy", "nxp_kinetis_trng": "entropy", "nxp_lpc_rng": "entropy", "openisa_rv32m1_trng": "entropy", "renesas_smartbond_trng": "entropy", + "sensry_sy1xx_trng": "entropy", "silabs_gecko_semailbox": "entropy", "silabs_gecko_trng": "entropy", - "st_stm32_rng": "entropy", + "silabs_siwx91x_rng": "entropy", "telink_b91_trng": "entropy", "ti_cc13xx_cc26xx_trng": "entropy", + "virtio_device4": "entropy", "zephyr_bt_hci_entropy": "entropy", "zephyr_native_posix_rng": "entropy", + "zephyr_native_sim_rng": "entropy", "zephyr_psa_crypto_rng": "entropy", # # espi @@ -435,6 +581,7 @@ "nuvoton_npcx_espi": "espi", "nuvoton_npcx_espi_taf": "espi", "nuvoton_npcx_host_sub": "espi", + "realtek_rts5912_espi": "espi", "zephyr_espi_emul_controller": "espi", # # ethernet @@ -448,26 +595,36 @@ "litex_liteeth": "ethernet", "microchip_enc28j60": "ethernet", "microchip_enc424j600": "ethernet", - "microchip_ksz8794": "ethernet", - "microchip_ksz8863": "ethernet", "microchip_lan865x": "ethernet", "microchip_lan9250": "ethernet", "nuvoton_numaker_ethernet": "ethernet", - "nxp_imx_netc_psi": "ethernet", + "nxp_enet": "ethernet", + "nxp_enet1g": "ethernet", + "nxp_enet_mac": "ethernet", "nxp_s32_gmac": "ethernet", "nxp_s32_netc_psi": "ethernet", "nxp_s32_netc_vsi": "ethernet", "renesas_ra_ethernet": "ethernet", + "sensry_sy1xx_mac": "ethernet", "siemens_ivshmem_eth": "ethernet", "silabs_gecko_ethernet": "ethernet", "smsc_lan91c111": "ethernet", + "smsc_lan91c111_mdio": "ethernet", "smsc_lan9220": "ethernet", "snps_designware_ethernet": "ethernet", "snps_ethernet_cyclonev": "ethernet", "st_stm32_ethernet": "ethernet", "ti_stellaris_ethernet": "ethernet", + "virtio_net": "ethernet", "vnd_ethernet": "ethernet", "wiznet_w5500": "ethernet", + "xlnx_axi_ethernet_1_00_a": "ethernet", + # + # ethernet/dsa + "microchip_ksz8463": "ethernet/dsa", + "microchip_ksz8794": "ethernet/dsa", + "microchip_ksz8863": "ethernet/dsa", + "nxp_netc_switch": "ethernet/dsa", # # ethernet/dwc_xgmac "snps_dwcxgmac": "ethernet/dwc_xgmac", @@ -476,11 +633,13 @@ "nxp_enet_qos": "ethernet/eth_nxp_enet_qos", "nxp_enet_qos_mac": "ethernet/eth_nxp_enet_qos", # - # ethernet/nxp_enet - "nxp_enet": "ethernet/nxp_enet", - "nxp_enet1g": "ethernet/nxp_enet", - "nxp_enet_mac": "ethernet/nxp_enet", - "nxp_kinetis_ethernet": "ethernet/nxp_enet", + # ethernet/intel + "intel_eth_plat": "ethernet/intel", + "intel_igc_mac": "ethernet/intel", + # + # ethernet/nxp_imx_netc + "nxp_imx_netc_blk_ctrl": "ethernet/nxp_imx_netc", + "nxp_imx_netc_psi": "ethernet/nxp_imx_netc", # # ethernet/phy "adi_adin1100_phy": "ethernet/phy", @@ -488,21 +647,29 @@ "davicom_dm8806_phy": "ethernet/phy", "ethernet_phy": "ethernet/phy", "microchip_ksz8081": "ethernet/phy", + "microchip_ksz9131": "ethernet/phy", "microchip_t1s_phy": "ethernet/phy", "microchip_vsc8541": "ethernet/phy", "nxp_tja1103": "ethernet/phy", + "nxp_tja11xx": "ethernet/phy", "qca_ar8031": "ethernet/phy", "realtek_rtl8211f": "ethernet/phy", "ti_dp83825": "ethernet/phy", + "ti_dp83867": "ethernet/phy", # # firmware/scmi "arm_scmi_shmem": "firmware/scmi", # + # firmware/tisci + "ti_k2g_sci": "firmware/tisci", + # # flash "adi_max32_flash_controller": "flash", - "altr_nios2_qspi_nor": "flash", + "adi_max32_spixf_nor": "flash", "ambiq_flash_controller": "flash", "andestech_qspi_nor": "flash", + "andestech_qspi_nor_xip": "flash", + "atmel_at25xv021a": "flash", "atmel_at45": "flash", "atmel_sam0_nvmctrl": "flash", "atmel_sam_flash_controller": "flash", @@ -513,14 +680,19 @@ "infineon_cat1_flash_controller": "flash", "infineon_cat1_qspi_flash": "flash", "infineon_xmc4xxx_flash_controller": "flash", + "ite_it51xxx_manual_flash_1k": "flash", "ite_it8xxx2_flash_controller": "flash", + "jedec_mspi_nor": "flash", "jedec_spi_nor": "flash", + "microchip_nvmctrl_g1_flash": "flash", "mspi_atxp032": "flash", + "mspi_is25xx0xx": "flash", "nordic_mram": "flash", "nordic_nrf51_flash_controller": "flash", "nordic_nrf52_flash_controller": "flash", "nordic_nrf53_flash_controller": "flash", "nordic_nrf91_flash_controller": "flash", + "nordic_nrf_mramc": "flash", "nordic_qspi_nor": "flash", "nordic_rram_controller": "flash", "nuvoton_npcx_fiu_nor": "flash", @@ -538,15 +710,25 @@ "nxp_kinetis_ftfe": "flash", "nxp_kinetis_ftfl": "flash", "nxp_msf1": "flash", + "nxp_s32_qspi_hyperflash": "flash", "nxp_s32_qspi_nor": "flash", + "nxp_xspi_nor": "flash", "openisa_rv32m1_ftfe": "flash", "raspberrypi_pico_flash_controller": "flash", + "realtek_rts5912_flash_controller": "flash", "renesas_ra_flash_hp_controller": "flash", + "renesas_ra_mram_controller": "flash", "renesas_ra_ospi_b_nor": "flash", "renesas_ra_qspi_nor": "flash", + "renesas_rx_flash": "flash", + "renesas_rz_qspi_spibsc": "flash", + "renesas_rz_qspi_xspi": "flash", "renesas_smartbond_flash_controller": "flash", + "sifli_sf32lb_mpi_qspi_nor": "flash", "silabs_gecko_flash_controller": "flash", + "silabs_series2_flash_controller": "flash", "silabs_si32_flash_controller": "flash", + "silabs_siwx91x_flash_controller": "flash", "st_stm32_flash_controller": "flash", "st_stm32_ospi_nor": "flash", "st_stm32_qspi_nor": "flash", @@ -556,6 +738,7 @@ "st_stm32wba_flash_controller": "flash", "telink_b91_flash_controller": "flash", "ti_cc13xx_cc26xx_flash_controller": "flash", + "ti_cc23x0_flash_controller": "flash", "zephyr_mspi_emul_flash": "flash", "zephyr_sim_flash": "flash", # @@ -568,12 +751,24 @@ "renesas_slg47115": "fpga", "xlnx_fpga": "fpga", # + # fuel_gauge/axp2101 + "x_powers_axp2101_fuel_gauge": "fuel_gauge/axp2101", + # # fuel_gauge/bq27z746 "ti_bq27z746": "fuel_gauge/bq27z746", # + # fuel_gauge/bq40z50 + "ti_bq40z50": "fuel_gauge/bq40z50", + # # fuel_gauge/composite "zephyr_fuel_gauge_composite": "fuel_gauge/composite", # + # fuel_gauge/lc709203f + "onnn_lc709203f": "fuel_gauge/lc709203f", + # + # fuel_gauge/ltc2959 + "adi_ltc2959": "fuel_gauge/ltc2959", + # # fuel_gauge/max17048 "maxim_max17048": "fuel_gauge/max17048", # @@ -581,12 +776,16 @@ "sbs_sbs_gauge": "fuel_gauge/sbs_gauge", "sbs_sbs_gauge_new_api": "fuel_gauge/sbs_gauge", # + # fuel_gauge/sy24561 + "silergy_sy24561": "fuel_gauge/sy24561", + # # gnss "gnss_nmea_generic": "gnss", "luatos_air530z": "gnss", "quectel_lc26g": "gnss", "quectel_lc76g": "gnss", "quectel_lc86g": "gnss", + "u_blox_f9p": "gnss", "u_blox_m8": "gnss", "zephyr_gnss_emul": "gnss", # @@ -594,26 +793,35 @@ "adi_ad559x_gpio": "gpio", "adi_adp5585_gpio": "gpio", "adi_max14906_gpio": "gpio", + "adi_max14915_gpio": "gpio", "adi_max14916_gpio": "gpio", + "adi_max14917_gpio": "gpio", "adi_max22017_gpio": "gpio", "adi_max22190_gpio": "gpio", + "adi_max22199_gpio": "gpio", "adi_max32_gpio": "gpio", + "aesc_gpio": "gpio", "altr_pio_1_0": "gpio", "ambiq_gpio_bank": "gpio", "andestech_atcgpio100": "gpio", "arm_cmsdk_gpio": "gpio", + "arm_mmio32_gpio": "gpio", "atmel_sam0_gpio": "gpio", "atmel_sam4l_gpio": "gpio", "atmel_sam_gpio": "gpio", "awinic_aw9523b_gpio": "gpio", + "bflb_bl60x_70x_gpio": "gpio", + "bflb_bl61x_gpio": "gpio", "brcm_bcm2711_gpio": "gpio", "brcm_brcmstb_gpio": "gpio", "brcm_iproc_gpio": "gpio", "cypress_cy8c95xx_gpio_port": "gpio", "cypress_psoc6_gpio": "gpio", "efinix_sapphire_gpio": "gpio", + "ene_kb106x_gpio": "gpio", "ene_kb1200_gpio": "gpio", "espressif_esp32_gpio": "gpio", + "espressif_esp32_lpgpio": "gpio", "fcs_fxl6408": "gpio", "gaisler_grgpio": "gpio", "gd_gd32_gpio": "gpio", @@ -622,6 +830,7 @@ "infineon_xmc4xxx_gpio": "gpio", "intel_gpio": "gpio", "intel_sedi_gpio": "gpio", + "ite_it51xxx_gpio": "gpio", "ite_it8801_gpio": "gpio", "ite_it8xxx2_gpio": "gpio", "ite_it8xxx2_gpio_v2": "gpio", @@ -638,10 +847,13 @@ "microchip_mcp23s18": "gpio", "microchip_mec5_gpio": "gpio", "microchip_mpfs_gpio": "gpio", + "microchip_port_g1_gpio": "gpio", + "microchip_sam_pio4": "gpio", "microchip_xec_gpio": "gpio", "microchip_xec_gpio_v2": "gpio", "neorv32_gpio": "gpio", "nordic_npm1300_gpio": "gpio", + "nordic_npm1304_gpio": "gpio", "nordic_npm2100_gpio": "gpio", "nordic_npm6001_gpio": "gpio", "nordic_nrf_gpio": "gpio", @@ -656,27 +868,35 @@ "nxp_kinetis_gpio": "gpio", "nxp_lpc11u6x_gpio": "gpio", "nxp_lpc_gpio_port": "gpio", + "nxp_pca6408": "gpio", + "nxp_pca6416": "gpio", "nxp_pca9538": "gpio", "nxp_pca9539": "gpio", "nxp_pca9554": "gpio", "nxp_pca9555": "gpio", "nxp_pca95xx": "gpio", + "nxp_pcal6408": "gpio", "nxp_pcal6408a": "gpio", + "nxp_pcal6416": "gpio", "nxp_pcal6416a": "gpio", "nxp_pcal6524": "gpio", "nxp_pcal6534": "gpio", + "nxp_pcal9538": "gpio", + "nxp_pcal9539": "gpio", + "nxp_pcal9722": "gpio", "nxp_pcf857x": "gpio", - "nxp_s32_gpio": "gpio", "nxp_sc18im704_gpio": "gpio", + "nxp_siul2_gpio": "gpio", "openisa_rv32m1_gpio": "gpio", "quicklogic_eos_s3_gpio": "gpio", - "raspberrypi_pico_gpio": "gpio", + "raspberrypi_pico_gpio_port": "gpio", "raspberrypi_rp1_gpio": "gpio", "realtek_rts5912_gpio": "gpio", - "renesas_ra_gpio": "gpio", "renesas_ra_gpio_ioport": "gpio", "renesas_rcar_gpio": "gpio", + "renesas_rx_gpio": "gpio", "renesas_rz_gpio": "gpio", + "renesas_rza2m_gpio": "gpio", "renesas_rzt2m_gpio": "gpio", "renesas_smartbond_gpio": "gpio", "richtek_rt1718s": "gpio", @@ -685,18 +905,25 @@ "semtech_sx1509b": "gpio", "sensry_sy1xx_gpio": "gpio", "sifive_gpio0": "gpio", + "sifli_sf32lb_gpio": "gpio", "silabs_gecko_gpio_port": "gpio", + "silabs_gpio": "gpio", "silabs_si32_gpio": "gpio", + "silabs_siwx91x_gpio": "gpio", + "silabs_siwx91x_gpio_uulp": "gpio", "snps_creg_gpio": "gpio", "snps_designware_gpio": "gpio", + "st_mfxstm32l152": "gpio", "st_stm32_gpio": "gpio", "st_stmpe1600": "gpio", "telink_b91_gpio": "gpio", - "ti_ads114s0x_gpio": "gpio", + "ti_ads1x4s0x_gpio": "gpio", "ti_cc13xx_cc26xx_gpio": "gpio", + "ti_cc23x0_gpio": "gpio", "ti_cc32xx_gpio": "gpio", "ti_davinci_gpio": "gpio", "ti_lmp90xxx_gpio": "gpio", + "ti_mspm0_gpio": "gpio", "ti_sn74hc595": "gpio", "ti_stellaris_gpio": "gpio", "ti_tca6424a": "gpio", @@ -715,6 +942,7 @@ # # hdlc_rcp_if "nxp_hdlc_rcp_if": "hdlc_rcp_if", + "spi_hdlc_rcp_if": "hdlc_rcp_if", "uart_hdlc_rcp_if": "hdlc_rcp_if", # # hwinfo @@ -741,6 +969,7 @@ "atmel_sam_i2c_twihs": "i2c", "atmel_sam_i2c_twim": "i2c", "brcm_iproc_i2c": "i2c", + "cdns_i2c": "i2c", "ene_kb1200_i2c": "i2c", "espressif_esp32_i2c": "i2c", "fsl_imx21_i2c": "i2c", @@ -748,11 +977,14 @@ "gpio_i2c": "i2c", "gpio_i2c_switch": "i2c", "infineon_cat1_i2c": "i2c", + "infineon_cat1_i2c_pdl": "i2c", "infineon_xmc4xxx_i2c": "i2c", "intel_sedi_i2c": "i2c", "ite_enhance_i2c": "i2c", + "ite_it51xxx_i2c": "i2c", "ite_it8xxx2_i2c": "i2c", "litex_i2c": "i2c", + "litex_litei2c": "i2c", "microchip_mpfs_i2c": "i2c", "microchip_xec_i2c": "i2c", "microchip_xec_i2c_v2": "i2c", @@ -760,27 +992,38 @@ "nuvoton_npcx_i2c_ctrl": "i2c", "nuvoton_npcx_i2c_port": "i2c", "nuvoton_numaker_i2c": "i2c", + "nxp_ii2c": "i2c", "nxp_kinetis_i2c": "i2c", "nxp_lpc11u6x_i2c": "i2c", "nxp_lpc_i2c": "i2c", "nxp_lpi2c": "i2c", "nxp_sc18im704_i2c": "i2c", "openisa_rv32m1_lpi2c": "i2c", + "realtek_rts5912_i2c": "i2c", + "renesas_ra_i2c_sci": "i2c", + "renesas_ra_i2c_sci_b": "i2c", "renesas_ra_iic": "i2c", "renesas_rcar_i2c": "i2c", + "renesas_rx_i2c": "i2c", + "renesas_rz_iic": "i2c", + "renesas_rz_riic": "i2c", "renesas_smartbond_i2c": "i2c", + "sensry_sy1xx_i2c": "i2c", "sifive_i2c0": "i2c", "silabs_gecko_i2c": "i2c", + "silabs_i2c": "i2c", "st_stm32_i2c_v1": "i2c", "st_stm32_i2c_v2": "i2c", "telink_b91_i2c": "i2c", "ti_cc13xx_cc26xx_i2c": "i2c", + "ti_cc23x0_i2c": "i2c", "ti_cc32xx_i2c": "i2c", "ti_omap_i2c": "i2c", "ti_tca9544a": "i2c", "ti_tca9546a": "i2c", "ti_tca9548a": "i2c", "vnd_i2c": "i2c", + "wch_i2c": "i2c", "xlnx_xps_iic_2_00_a": "i2c", "xlnx_xps_iic_2_1": "i2c", "zephyr_i2c_emul_controller": "i2c", @@ -789,26 +1032,38 @@ "zephyr_i2c_target_eeprom": "i2c/target", # # i2s + "ambiq_i2s": "i2s", "atmel_sam_ssc": "i2s", "espressif_esp32_i2s": "i2s", "nxp_lpc_i2s": "i2s", "nxp_mcux_i2s": "i2s", + "renesas_ra_i2s_ssie": "i2s", + "silabs_siwx91x_i2s": "i2s", "st_stm32_i2s": "i2s", + "st_stm32_sai": "i2s", "vnd_i2s": "i2s", # # i3c + "adi_max32_i3c": "i3c", "cdns_i3c": "i3c", + "ite_it51xxx_i3cm": "i3c", + "ite_it51xxx_i3cs": "i3c", "nuvoton_npcx_i3c": "i3c", "nxp_mcux_i3c": "i3c", + "renesas_ra_i3c": "i3c", + "snps_designware_i3c": "i3c", "st_stm32_i3c": "i3c", "vnd_i3c": "i3c", # # ieee802154 "atmel_rf2xx": "ieee802154", "decawave_dw1000": "ieee802154", + "espressif_esp32_ieee802154": "ieee802154", "nordic_nrf_ieee802154": "ieee802154", "nxp_kw41z_ieee802154": "ieee802154", "nxp_mcr20a": "ieee802154", + "nxp_mcxw_ieee802154": "ieee802154", + "st_stm32wba_ieee802154": "ieee802154", "telink_b91_zb": "ieee802154", "ti_cc1200": "ieee802154", "ti_cc13xx_cc26xx_ieee802154": "ieee802154", @@ -819,8 +1074,11 @@ # input "adc_keys": "input", "analog_axis": "input", + "arduino_modulino_buttons": "input", + "chipsemi_chsc5x": "input", "chipsemi_chsc6x": "input", "cirque_pinnacle": "input", + "cypress_cy8cmbr3xxx": "input", "espressif_esp32_touch": "input", "focaltech_ft5336": "input", "futaba_sbus": "input", @@ -830,17 +1088,27 @@ "gpio_qdec": "input", "hynitron_cst816s": "input", "ilitek_ili2132a": "input", + "ite_it51xxx_kbd": "input", "ite_it8801_kbd": "input", "ite_it8xxx2_kbd": "input", "microchip_cap12xx": "input", "microchip_xec_kbd": "input", "nintendo_nunchuk": "input", "nuvoton_npcx_kbd": "input", + "nxp_mcux_kpp": "input", "pixart_pat912x": "input", "pixart_paw32xx": "input", "pixart_pmw3610": "input", + "realtek_rts5912_kbd": "input", + "renesas_ra_ctsu": "input", + "renesas_ra_ctsu_button": "input", + "renesas_ra_ctsu_slider": "input", + "renesas_ra_ctsu_wheel": "input", + "renesas_rx_ctsu": "input", "sitronix_cf1133": "input", + "st_stm32_tsc": "input", "st_stmpe811": "input", + "vishay_vs1838b": "input", "xptek_xpt2046": "input", "zephyr_input_sdl_touch": "input", "zephyr_native_linux_evdev": "input", @@ -853,12 +1121,14 @@ "atmel_sam0_eic": "interrupt_controller", "gaisler_irqmp": "interrupt_controller", "gd_gd32_exti": "interrupt_controller", + "hazard3_hazard3_intc": "interrupt_controller", "infineon_xmc4xxx_intc": "interrupt_controller", "intel_ace_intc": "interrupt_controller", "intel_cavs_intc": "interrupt_controller", "intel_ioapic": "interrupt_controller", "intel_loapic": "interrupt_controller", "intel_vt_d": "interrupt_controller", + "ite_it51xxx_wuc": "interrupt_controller", "ite_it8xxx2_wuc": "interrupt_controller", "litex_vexriscv_intc0": "interrupt_controller", "mediatek_adsp_intc": "interrupt_controller", @@ -867,10 +1137,12 @@ "nuvoton_npcx_miwu": "interrupt_controller", "nxp_irqsteer_intc": "interrupt_controller", "nxp_pint": "interrupt_controller", - "nxp_s32_siul2_eirq": "interrupt_controller", "nxp_s32_wkpu": "interrupt_controller", + "nxp_siul2_eirq": "interrupt_controller", "openisa_rv32m1_intmux": "interrupt_controller", - "renesas_ra_interrupt_controller_unit": "interrupt_controller", + "renesas_rx_icu": "interrupt_controller", + "renesas_rz_ext_irq": "interrupt_controller", + "riscv_clic": "interrupt_controller", "shared_irq": "interrupt_controller", "sifive_plic_1_0_0": "interrupt_controller", "snps_arcv2_intc": "interrupt_controller", @@ -878,6 +1150,7 @@ "st_stm32wb0_gpio_intc": "interrupt_controller", "swerv_pic": "interrupt_controller", "ti_vim": "interrupt_controller", + "wch_exti": "interrupt_controller", "wch_pfic": "interrupt_controller", # # ipm @@ -893,17 +1166,19 @@ "xlnx_zynqmp_ipi_mailbox": "ipm", "zephyr_mbox_ipm": "ipm", # - # kscan - "zephyr_kscan_input": "kscan", - # # led + "arduino_modulino_buttons_leds": "led", + "dac_leds": "led", "gpio_leds": "led", "holtek_ht16k33": "led", "issi_is31fl3194": "led", "issi_is31fl3216a": "led", "issi_is31fl3733": "led", + "leds_group_multicolor": "led", "microchip_xec_bbled": "led", "nordic_npm1300_led": "led", + "nordic_npm1304_led": "led", + "nxp_pca9533": "led", "nxp_pca9633": "led", "onnn_ncp5623": "led", "pwm_leds": "led", @@ -920,6 +1195,7 @@ # # led_strip "apa_apa102": "led_strip", + "arduino_modulino_pixels": "led_strip", "greeled_lpd8803": "led_strip", "greeled_lpd8806": "led_strip", "ti_tlc5971": "led_strip", @@ -928,14 +1204,18 @@ "worldsemi_ws2812_i2s": "led_strip", "worldsemi_ws2812_rpi_pico_pio": "led_strip", "worldsemi_ws2812_spi": "led_strip", + "worldsemi_ws2812_uart": "led_strip", # # lora "reyax_rylrxxx": "lora", - "semtech_sx1272": "lora", - "semtech_sx1276": "lora", + # + # lora/loramac_node + "semtech_sx1272": "lora/loramac_node", + "semtech_sx1276": "lora/loramac_node", # # mbox "andestech_mbox_plic_sw": "mbox", + "arm_mhuv3": "mbox", "espressif_mbox_esp32": "mbox", "linaro_ivshmem_mbox": "mbox", "nordic_mbox_nrf_ipc": "mbox", @@ -948,13 +1228,18 @@ "nxp_mbox_imx_mu": "mbox", "nxp_mbox_mailbox": "mbox", "nxp_s32_mru": "mbox", + "renesas_ra_ipc_mbox": "mbox", + "renesas_rz_mhu_mbox": "mbox", "st_mbox_stm32_hsem": "mbox", + "ti_omap_mailbox": "mbox", + "ti_secure_proxy": "mbox", # # mdio "adi_adin2111_mdio": "mdio", "atmel_sam_mdio": "mdio", "espressif_esp32_mdio": "mdio", "infineon_xmc4xxx_mdio": "mdio", + "intel_igc_mdio": "mdio", "litex_liteeth_mdio": "mdio", "microchip_lan865x_mdio": "mdio", "nxp_enet_mdio": "mdio", @@ -963,30 +1248,40 @@ "nxp_s32_gmac_mdio": "mdio", "nxp_s32_netc_emdio": "mdio", "renesas_ra_mdio": "mdio", - "smsc_lan91c111_mdio": "mdio", + "sensry_sy1xx_mdio": "mdio", "snps_dwcxgmac_mdio": "mdio", "st_stm32_mdio": "mdio", + "xlnx_axi_ethernet_1_00_a_mdio": "mdio", "zephyr_mdio_gpio": "mdio", # # memc + "adi_max32_hpb": "memc", "atmel_sam_smc": "memc", + "bflb_bl61x_psram": "memc", "mspi_aps6404l": "memc", + "mspi_aps_z8": "memc", "nxp_imx_flexspi": "memc", "nxp_imx_flexspi_s27ks0641": "memc", "nxp_imx_flexspi_w956a8mbya": "memc", "nxp_s32_qspi": "memc", + "nxp_xspi": "memc", + "nxp_xspi_psram": "memc", "renesas_ra_sdram": "memc", "renesas_smartbond_nor_psram": "memc", "sifive_fu740_c000_ddr": "memc", + "silabs_siwx91x_qspi_memory": "memc", "st_stm32_fmc": "memc", "st_stm32_fmc_nor_psram": "memc", "st_stm32_fmc_sdram": "memc", + "st_stm32_ospi_psram": "memc", + "st_stm32_xspi_psram": "memc", "st_stm32h7_fmc": "memc", # # mfd "adi_ad559x": "mfd", "adi_adp5585": "mfd", "adi_max22017": "mfd", + "adi_maxq10xx": "mfd", "awinic_aw9523b": "mfd", "infineon_tle9104": "mfd", "ite_it8801_altctrl": "mfd", @@ -994,16 +1289,21 @@ "maxim_ds3231_mfd": "mfd", "maxim_max20335": "mfd", "maxim_max31790": "mfd", + "microchip_sam_flexcom": "mfd", + "motorola_mc146818_mfd": "mfd", "nordic_npm1300": "mfd", + "nordic_npm1304": "mfd", "nordic_npm2100": "mfd", "nordic_npm6001": "mfd", "nuvoton_nct38xx": "mfd", "nxp_lp_flexcomm": "mfd", + "nxp_pca9422": "mfd", + "nxp_pf1550": "mfd", "rohm_bd8lb600fs": "mfd", - "x_powers_axp192": "mfd", # # mipi_dbi "nxp_lcdic": "mipi_dbi", + "nxp_mipi_dbi_dcnano_lcdif": "mipi_dbi", "nxp_mipi_dbi_flexio_lcdif": "mipi_dbi", "renesas_smartbond_mipi_dbi": "mipi_dbi", "st_stm32_fmc_mipi_dbi": "mipi_dbi", @@ -1013,6 +1313,7 @@ # mipi_dsi "nxp_imx_mipi_dsi": "mipi_dsi", "nxp_mipi_dsi_2l": "mipi_dsi", + "nxp_mipi_dsi_dwc": "mipi_dsi", "renesas_ra_mipi_dsi": "mipi_dsi", "st_stm32_mipi_dsi": "mipi_dsi", "vnd_mipi_dsi": "mipi_dsi", @@ -1022,6 +1323,8 @@ # # misc/ethos_u "arm_ethos_u": "misc/ethos_u", + "nuvoton_numaker_npu": "misc/ethos_u", + "renesas_ra_npu": "misc/ethos_u", # # misc/ft8xx "ftdi_ft800": "misc/ft8xx", @@ -1029,12 +1332,22 @@ # misc/grove_lcd_rgb "seeed_grove_lcd_rgb": "misc/grove_lcd_rgb", # + # misc/interconn/renesas_elc + "renesas_ra_elc": "misc/interconn/renesas_elc", + # # misc/mcux_flexio "nxp_flexio": "misc/mcux_flexio", # # misc/nordic_vpr_launcher "nordic_nrf_vpr_coprocessor": "misc/nordic_vpr_launcher", # + # misc/nxp_imx93_mediamix + "nxp_imx93_mediamix": "misc/nxp_imx93_mediamix", + # + # misc/nxp_rtxxx_dsp_ctrl + "nxp_rt600_dsp_ctrl": "misc/nxp_rtxxx_dsp_ctrl", + "nxp_rt700_dsp_ctrl_hifi4": "misc/nxp_rtxxx_dsp_ctrl", + # # misc/nxp_s32_emios "nxp_s32_emios": "misc/nxp_s32_emios", # @@ -1044,6 +1357,15 @@ # misc/renesas_ra_external_interrupt "renesas_ra_external_interrupt": "misc/renesas_ra_external_interrupt", # + # misc/renesas_rx_dtc + "renesas_rx_dtc": "misc/renesas_rx_dtc", + # + # misc/renesas_rx_external_interrupt + "renesas_rx_external_interrupt": "misc/renesas_rx_external_interrupt", + # + # misc/stm32n6_axisram + "st_stm32n6_ramcfg": "misc/stm32n6_axisram", + # # misc/timeaware_gpio "intel_timeaware_gpio": "misc/timeaware_gpio", # @@ -1053,11 +1375,12 @@ # modem "nordic_nrf91_slm": "modem", "quectel_bg95": "modem", + "quectel_bg96": "modem", "quectel_bg9x": "modem", "quectel_eg25_g": "modem", - "simcom_sim7080": "modem", + "quectel_eg800q": "modem", + "simcom_a76xx": "modem", "sqn_gm02s": "modem", - "swir_hl7800": "modem", "telit_me310g1": "modem", "telit_me910g1": "modem", "u_blox_lara_r6": "modem", @@ -1065,10 +1388,24 @@ "u_blox_sara_r5": "modem", "wnc_m14a2a": "modem", # + # modem/hl78xx + "swir_hl7800": "modem/hl78xx", + "swir_hl7800_offload": "modem/hl78xx", + "swir_hl7812": "modem/hl78xx", + "swir_hl7812_offload": "modem/hl78xx", + # + # modem/simcom/sim7080 + "simcom_sim7080": "modem/simcom/sim7080", + # # mspi "ambiq_mspi_controller": "mspi", + "snps_designware_ssi": "mspi", "zephyr_mspi_emul_controller": "mspi", # + # opamp + "nxp_opamp": "opamp", + "nxp_opamp_fast": "opamp", + # # pcie/controller "brcm_brcmstb_pcie": "pcie/controller", # @@ -1086,6 +1423,7 @@ "nuvoton_npcx_peci": "peci", # # pinctrl + "ene_kb106x_pinctrl": "pinctrl", "ene_kb1200_pinctrl": "pinctrl", "infineon_xmc4xxx_pinctrl": "pinctrl", "ite_it8xxx2_pinctrl_func": "pinctrl", @@ -1099,12 +1437,19 @@ "realtek_rts5912_pinctrl": "pinctrl", "sensry_sy1xx_pinctrl": "pinctrl", "sifive_pinctrl": "pinctrl", + "sifli_sf32lb52x_pinmux": "pinctrl", "silabs_dbus_pinctrl": "pinctrl", + "silabs_siwx91x_pinctrl": "pinctrl", "snps_emsdp_pinctrl": "pinctrl", "telink_b91_pinctrl": "pinctrl", "ti_cc13xx_cc26xx_pinctrl": "pinctrl", + "ti_cc23x0_pinctrl": "pinctrl", "ti_cc32xx_pinctrl": "pinctrl", "ti_k3_pinctrl": "pinctrl", + "ti_mspm0_pinctrl": "pinctrl", + "wch_00x_afio": "pinctrl", + "wch_20x_30x_afio": "pinctrl", + "wch_afio": "pinctrl", "xlnx_pinctrl_zynq": "pinctrl", "xlnx_pinctrl_zynqmp": "pinctrl", # @@ -1112,6 +1457,7 @@ "renesas_rcar_pfc": "pinctrl/renesas/rcar", # # pinctrl/renesas/rz + "renesas_rza2m_pinctrl": "pinctrl/renesas/rz", "renesas_rzt2m_pinctrl": "pinctrl/renesas/rz", # # pm_cpu_ops @@ -1120,38 +1466,53 @@ # # power_domain "intel_adsp_power_domain": "power_domain", + "nordic_nrfs_gdpwr": "power_domain", + "nordic_nrfs_swext": "power_domain", "nxp_scu_pd": "power_domain", "power_domain_gpio": "power_domain", "power_domain_gpio_monitor": "power_domain", + "power_domain_soc_state_change": "power_domain", + "silabs_siwx91x_power_domain": "power_domain", + "ti_sci_pm_domain": "power_domain", # # ps2 "microchip_xec_ps2": "ps2", "nuvoton_npcx_ps2_channel": "ps2", "nuvoton_npcx_ps2_ctrl": "ps2", # + # psi5 + "nxp_s32_psi5": "psi5", + # # ptp_clock "nxp_enet_ptp_clock": "ptp_clock", + "nxp_netc_ptp_clock": "ptp_clock", # # pwm "adi_max32_pwm": "pwm", + "ambiq_ctimer_pwm": "pwm", + "ambiq_timer_pwm": "pwm", "atmel_sam0_tc_pwm": "pwm", "atmel_sam0_tcc_pwm": "pwm", "atmel_sam_pwm": "pwm", + "ene_kb106x_pwm": "pwm", "ene_kb1200_pwm": "pwm", "espressif_esp32_ledc": "pwm", "espressif_esp32_mcpwm": "pwm", "fsl_imx27_pwm": "pwm", "gd_gd32_pwm": "pwm", - "infineon_cat1_pwm": "pwm", + "infineon_tcpwm_pwm": "pwm", "infineon_xmc4xxx_ccu4_pwm": "pwm", "infineon_xmc4xxx_ccu8_pwm": "pwm", "intel_blinky_pwm": "pwm", + "ite_it51xxx_pwm": "pwm", "ite_it8801_pwm": "pwm", "ite_it8xxx2_pwm": "pwm", "litex_pwm": "pwm", "maxim_max31790_pwm": "pwm", + "microchip_tcc_g1_pwm": "pwm", "microchip_xec_pwm": "pwm", "microchip_xec_pwmbbled": "pwm", + "neorv32_pwm": "pwm", "nordic_nrf_sw_pwm": "pwm", "nuvoton_npcx_pwm": "pwm", "nuvoton_numaker_pwm": "pwm", @@ -1167,14 +1528,24 @@ "nxp_sctimer_pwm": "pwm", "openisa_rv32m1_tpm": "pwm", "raspberrypi_pico_pwm": "pwm", + "realtek_rts5912_pwm": "pwm", "renesas_pwm_rcar": "pwm", "renesas_ra_pwm": "pwm", + "renesas_rx_mtu_pwm": "pwm", + "renesas_rz_gpt_pwm": "pwm", + "renesas_rz_mtu_pwm": "pwm", "sifive_pwm0": "pwm", "silabs_gecko_pwm": "pwm", + "silabs_letimer_pwm": "pwm", + "silabs_siwx91x_pwm": "pwm", + "silabs_timer_pwm": "pwm", "st_stm32_pwm": "pwm", "telink_b91_pwm": "pwm", "ti_cc13xx_cc26xx_timer_pwm": "pwm", + "ti_cc23x0_lgpt_pwm": "pwm", + "ti_mspm0_timer_pwm": "pwm", "vnd_pwm": "pwm", + "wch_gptm_pwm": "pwm", "xlnx_xps_timer_1_00_a_pwm": "pwm", "zephyr_fake_pwm": "pwm", # @@ -1185,30 +1556,39 @@ "mps_mpm54304": "regulator", "nordic_npm1100": "regulator", "nordic_npm1300_regulator": "regulator", + "nordic_npm1304_regulator": "regulator", "nordic_npm2100_regulator": "regulator", "nordic_npm6001_regulator": "regulator", "nxp_pca9420": "regulator", + "nxp_pca9422_regulator": "regulator", + "nxp_pf1550_regulator": "regulator", "nxp_vref": "regulator", + "nxp_vrefv1": "regulator", "raspberrypi_core_supply_regulator": "regulator", "regulator_fixed": "regulator", "regulator_gpio": "regulator", "renesas_smartbond_regulator": "regulator", - "x_powers_axp192_regulator": "regulator", "zephyr_fake_regulator": "regulator", # # reset "aspeed_ast10x0_reset": "reset", "gd_gd32_rctl": "reset", "intel_socfpga_reset": "reset", + "microchip_mpfs_reset": "reset", + "microchip_rstc_g1_reset": "reset", "nuvoton_npcx_rst": "reset", "nuvoton_numaker_rst": "reset", "nxp_lpc_syscon_reset": "reset", + "nxp_mrcc_reset": "reset", "nxp_rstctl": "reset", "raspberrypi_pico_reset": "reset", + "reset_mmio": "reset", + "sifli_sf32lb_rcc_rctl": "reset", "st_stm32_rcc_rctl": "reset", # # retained_mem "nordic_nrf_gpregret": "retained_mem", + "silabs_buram": "retained_mem", "zephyr_retained_ram": "retained_mem", "zephyr_retained_reg": "retained_mem", # @@ -1216,39 +1596,58 @@ "ambiq_am1805": "rtc", "ambiq_rtc": "rtc", "atmel_sam_rtc": "rtc", + "epson_rx8130ce_rtc": "rtc", "infineon_cat1_rtc": "rtc", "infineon_xmc4xxx_rtc": "rtc", "maxim_ds1307": "rtc", + "maxim_ds1337": "rtc", "maxim_ds3231_rtc": "rtc", "microcrystal_rv3028": "rtc", + "microcrystal_rv3032": "rtc", "microcrystal_rv8803": "rtc", "microcrystal_rv_8263_c8": "rtc", "motorola_mc146818": "rtc", "nuvoton_numaker_rtc": "rtc", "nxp_irtc": "rtc", + "nxp_pcf2123": "rtc", + "nxp_pcf85063a": "rtc", "nxp_pcf8523": "rtc", "nxp_pcf8563": "rtc", "raspberrypi_pico_rtc": "rtc", + "realtek_rts5912_rtc": "rtc", + "renesas_ra_rtc": "rtc", "renesas_smartbond_rtc": "rtc", + "silabs_siwx91x_rtc": "rtc", "st_stm32_rtc": "rtc", + "ti_bq32002": "rtc", + "ti_mspm0_rtc": "rtc", "zephyr_fake_rtc": "rtc", + "zephyr_rtc_counter": "rtc", "zephyr_rtc_emul": "rtc", # # sdhc + "adi_max32_sdhc": "sdhc", + "ambiq_sdio": "sdhc", "atmel_sam_hsmci": "sdhc", "cdns_sdhc": "sdhc", "espressif_esp32_sdhc_slot": "sdhc", "infineon_cat1_sdhc_sdio": "sdhc", "intel_emmc_host": "sdhc", + "microchip_sama7g5_sdmmc": "sdhc", "nxp_imx_usdhc": "sdhc", "nxp_lpc_sdif": "sdhc", "renesas_ra_sdhc": "sdhc", "renesas_rcar_mmc": "sdhc", + "st_stm32_sdio": "sdhc", + "xlnx_versal_8_9a": "sdhc", "zephyr_sdhc_spi_slot": "sdhc", # # sensor/a01nyub "dfrobot_a01nyub": "sensor/a01nyub", # + # sensor/adi/ad2s1210 + "adi_ad2s1210": "sensor/adi/ad2s1210", + # # sensor/adi/adltc2990 "adi_adltc2990": "sensor/adi/adltc2990", # @@ -1271,6 +1670,12 @@ # sensor/adi/adxl372 "adi_adxl372": "sensor/adi/adxl372", # + # sensor/adi/max32664c + "maxim_max32664c": "sensor/adi/max32664c", + # + # sensor/als31300 + "allegro_als31300": "sensor/als31300", + # # sensor/amd_sb_tsi "amd_sb_tsi": "sensor/amd_sb_tsi", # @@ -1362,6 +1767,9 @@ "bosch_bmp388": "sensor/bosch/bmp388", "bosch_bmp390": "sensor/bosch/bmp388", # + # sensor/broadcom/afbr_s50 + "brcm_afbr_s50": "sensor/broadcom/afbr_s50", + # # sensor/current_amp "current_sense_amplifier": "sensor/current_amp", # @@ -1377,6 +1785,9 @@ # sensor/espressif/pcnt_esp32 "espressif_esp32_pcnt": "sensor/espressif/pcnt_esp32", # + # sensor/everlight/als_pt19 + "everlight_als_pt19": "sensor/everlight/als_pt19", + # # sensor/explorir_m "gss_explorir_m": "sensor/explorir_m", # @@ -1414,6 +1825,9 @@ # sensor/infineon/xmc4xxx_temp "infineon_xmc4xxx_temp": "sensor/infineon/xmc4xxx_temp", # + # sensor/ite/ite_tach_it51xxx + "ite_it51xxx_tach": "sensor/ite/ite_tach_it51xxx", + # # sensor/ite/ite_tach_it8xxx2 "ite_it8xxx2_tach": "sensor/ite/ite_tach_it8xxx2", # @@ -1423,6 +1837,12 @@ # sensor/jedec/jc42 "jedec_jc_42_4_temp": "sensor/jedec/jc42", # + # sensor/liteon/ltr329 + "liteon_ltr329": "sensor/liteon/ltr329", + # + # sensor/liteon/ltrf216a + "liteon_ltrf216a": "sensor/liteon/ltrf216a", + # # sensor/lm35 "lm35": "sensor/lm35", # @@ -1432,9 +1852,6 @@ # sensor/lm77 "lm77": "sensor/lm77", # - # sensor/ltrf216a - "ltr_f216a": "sensor/ltrf216a", - # # sensor/maxim/ds18b20 "maxim_ds18b20": "sensor/maxim/ds18b20", "maxim_ds18s20": "sensor/maxim/ds18b20", @@ -1467,11 +1884,15 @@ # sensor/maxim/max6675 "maxim_max6675": "sensor/maxim/max6675", # + # sensor/mb7040 + "maxbotix_mb7040": "sensor/mb7040", + # # sensor/meas/ms5607 "meas_ms5607": "sensor/meas/ms5607", # # sensor/meas/ms5837 - "meas_ms5837": "sensor/meas/ms5837", + "meas_ms5837_02ba": "sensor/meas/ms5837", + "meas_ms5837_30ba": "sensor/meas/ms5837", # # sensor/melexis/mlx90394 "melexis_mlx90394": "sensor/melexis/mlx90394", @@ -1491,14 +1912,18 @@ # sensor/microchip/mcp970x "microchip_mcp970x": "sensor/microchip/mcp970x", # + # sensor/microchip/mtch9010 + "microchip_mtch9010": "sensor/microchip/mtch9010", + # # sensor/microchip/tcn75a "microchip_tcn75a": "sensor/microchip/tcn75a", # # sensor/nct75 "onnn_nct75": "sensor/nct75", # - # sensor/nordic/npm1300_charger - "nordic_npm1300_charger": "sensor/nordic/npm1300_charger", + # sensor/nordic/npm13xx_charger + "nordic_npm1300_charger": "sensor/nordic/npm13xx_charger", + "nordic_npm1304_charger": "sensor/nordic/npm13xx_charger", # # sensor/nordic/npm2100_vbat "nordic_npm2100_vbat": "sensor/nordic/npm2100_vbat", @@ -1541,9 +1966,18 @@ # sensor/nxp/nxp_kinetis_temp "nxp_kinetis_temperature": "sensor/nxp/nxp_kinetis_temp", # + # sensor/nxp/nxp_lpadc_temp40 + "nxp_lpadc_temp40": "sensor/nxp/nxp_lpadc_temp40", + # + # sensor/nxp/nxp_pmc_tmpsns + "nxp_pmc_tmpsns": "sensor/nxp/nxp_pmc_tmpsns", + # # sensor/nxp/nxp_tempmon "nxp_tempmon": "sensor/nxp/nxp_tempmon", # + # sensor/nxp/nxp_tmpsns + "nxp_tmpsns": "sensor/nxp/nxp_tmpsns", + # # sensor/nxp/p3t1755 "nxp_p3t1755": "sensor/nxp/p3t1755", # @@ -1553,12 +1987,40 @@ # sensor/nxp/qdec_nxp_s32 "nxp_qdec_s32": "sensor/nxp/qdec_nxp_s32", # + # sensor/nxp/qdec_tpm + "nxp_tpm_qdec": "sensor/nxp/qdec_tpm", + # + # sensor/omron/2smpb_02e + "omron_2smpb_02e": "sensor/omron/2smpb_02e", + # + # sensor/omron/d6f + "omron_d6f_p0001": "sensor/omron/d6f", + "omron_d6f_p0010": "sensor/omron/d6f", + # + # sensor/pixart/paa3905 + "pixart_paa3905": "sensor/pixart/paa3905", + # + # sensor/pixart/paj7620 + "pixart_paj7620": "sensor/pixart/paj7620", + # + # sensor/pixart/pat9136 + "pixart_pat9136": "sensor/pixart/pat9136", + # # sensor/pms7003 "plantower_pms7003": "sensor/pms7003", # + # sensor/pni/rm3100 + "pni_rm3100": "sensor/pni/rm3100", + # + # sensor/pzem004t + "peacefair_pzem004t": "sensor/pzem004t", + # # sensor/qdec_sam "atmel_sam_tc_qdec": "sensor/qdec_sam", # + # sensor/realtek/rts5912 + "realtek_rts5912_tach": "sensor/realtek/rts5912", + # # sensor/renesas/hs300x "renesas_hs300x": "sensor/renesas/hs300x", # @@ -1571,9 +2033,15 @@ # sensor/rohm/bd8lb600fs "rohm_bd8lb600fs_diagnostics": "sensor/rohm/bd8lb600fs", # + # sensor/rohm/bh1730 + "rohm_bh1730": "sensor/rohm/bh1730", + # # sensor/rohm/bh1750 "rohm_bh1750": "sensor/rohm/bh1750", # + # sensor/rohm/bh1790 + "rohm_bh1790": "sensor/rohm/bh1790", + # # sensor/rpi_pico_temp "raspberrypi_pico_temp": "sensor/rpi_pico_temp", # @@ -1643,6 +2111,9 @@ # sensor/st/iis3dhhc "st_iis3dhhc": "sensor/st/iis3dhhc", # + # sensor/st/iis3dwb + "st_iis3dwb": "sensor/st/iis3dwb", + # # sensor/st/ism330dhcx "st_ism330dhcx": "sensor/st/ism330dhcx", # @@ -1702,7 +2173,8 @@ "st_lsm6dso16is": "sensor/st/lsm6dso16is", # # sensor/st/lsm6dsv16x - "st_lsm6dsv16x": "sensor/st/lsm6dsv16x", + "DT_DRV_COMPAT_LSM6DSV16X": "sensor/st/lsm6dsv16x", + "DT_DRV_COMPAT_LSM6DSV32X": "sensor/st/lsm6dsv16x", # # sensor/st/lsm9ds0_gyro "st_lsm9ds0_gyro": "sensor/st/lsm9ds0_gyro", @@ -1713,6 +2185,9 @@ # sensor/st/lsm9ds1 "st_lsm9ds1": "sensor/st/lsm9ds1", # + # sensor/st/lsm9ds1_mag + "st_lsm9ds1_mag": "sensor/st/lsm9ds1_mag", + # # sensor/st/qdec_stm32 "st_stm32_qdec": "sensor/st/qdec_stm32", # @@ -1745,18 +2220,32 @@ # sensor/sx9500 "semtech_sx9500": "sensor/sx9500", # + # sensor/tach_gpio + "zephyr_tach_gpio": "sensor/tach_gpio", + # + # sensor/tdk/icm40627 + "invensense_icm40627": "sensor/tdk/icm40627", + # # sensor/tdk/icm42605 "invensense_icm42605": "sensor/tdk/icm42605", # - # sensor/tdk/icm42670 - "invensense_icm42670p": "sensor/tdk/icm42670", - "invensense_icm42670s": "sensor/tdk/icm42670", + # sensor/tdk/icm4268x + "invensense_icm42688": "sensor/tdk/icm4268x", + "invensense_icm4268x": "sensor/tdk/icm4268x", # - # sensor/tdk/icm42688 - "invensense_icm42688": "sensor/tdk/icm42688", + # sensor/tdk/icm42x70 + "invensense_icm42370p": "sensor/tdk/icm42x70", + "invensense_icm42670p": "sensor/tdk/icm42x70", + "invensense_icm42670s": "sensor/tdk/icm42x70", # - # sensor/tdk/icp10125 - "invensense_icp10125": "sensor/tdk/icp10125", + # sensor/tdk/icm45686 + "invensense_icm45686": "sensor/tdk/icm45686", + # + # sensor/tdk/icp101xx + "invensense_icp101xx": "sensor/tdk/icp101xx", + # + # sensor/tdk/icp201xx + "invensense_icp201xx": "sensor/tdk/icp201xx", # # sensor/tdk/mpu6050 "invensense_mpu6050": "sensor/tdk/mpu6050", @@ -1776,17 +2265,19 @@ # sensor/ti/ina219 "ti_ina219": "sensor/ti/ina219", # - # sensor/ti/ina226 - "ti_ina226": "sensor/ti/ina226", - # - # sensor/ti/ina23x - "ti_ina230": "sensor/ti/ina23x", - "ti_ina236": "sensor/ti/ina23x", - "ti_ina237": "sensor/ti/ina23x", + # sensor/ti/ina2xx + "ti_ina226": "sensor/ti/ina2xx", + "ti_ina228": "sensor/ti/ina2xx", + "ti_ina230": "sensor/ti/ina2xx", + "ti_ina236": "sensor/ti/ina2xx", + "ti_ina237": "sensor/ti/ina2xx", # # sensor/ti/ina3221 "ti_ina3221": "sensor/ti/ina3221", # + # sensor/ti/ina7xx + "ti_ina7xx": "sensor/ti/ina7xx", + # # sensor/ti/lm95234 "national_lm95234": "sensor/ti/lm95234", # @@ -1796,6 +2287,9 @@ # sensor/ti/ti_hdc "ti_hdc": "sensor/ti/ti_hdc", # + # sensor/ti/ti_hdc302x + "ti_hdc302x": "sensor/ti/ti_hdc302x", + # # sensor/ti/tmag5170 "ti_tmag5170": "sensor/ti/tmag5170", # @@ -1815,8 +2309,11 @@ # sensor/ti/tmp114 "ti_tmp114": "sensor/ti/tmp114", # - # sensor/ti/tmp116 - "ti_tmp116": "sensor/ti/tmp116", + # sensor/ti/tmp11x + "ti_tmp11x": "sensor/ti/tmp11x", + # + # sensor/ti/tmp435 + "ti_tmp435": "sensor/ti/tmp435", # # sensor/tsic_xx6 "ist_tsic_xx6": "sensor/tsic_xx6", @@ -1830,6 +2327,12 @@ # sensor/vishay/vcnl4040 "vishay_vcnl4040": "sensor/vishay/vcnl4040", # + # sensor/vishay/veml6031 + "vishay_veml6031": "sensor/vishay/veml6031", + # + # sensor/vishay/veml6046 + "vishay_veml6046": "sensor/vishay/veml6046", + # # sensor/vishay/veml7700 "vishay_veml7700": "sensor/vishay/veml7700", # @@ -1839,37 +2342,66 @@ # sensor/wsen/wsen_hids_2525020210002 "we_wsen_hids_2525020210002": "sensor/wsen/wsen_hids_2525020210002", # + # sensor/wsen/wsen_isds_2536030320001 + "we_wsen_isds_2536030320001": "sensor/wsen/wsen_isds_2536030320001", + # + # sensor/wsen/wsen_itds_2533020201601 + "we_wsen_itds_2533020201601": "sensor/wsen/wsen_itds_2533020201601", + # + # sensor/wsen/wsen_pads_2511020213301 + "we_wsen_pads_2511020213301": "sensor/wsen/wsen_pads_2511020213301", + # + # sensor/wsen/wsen_pdms_25131308XXX05 + "we_wsen_pdms_25131308xxx05": "sensor/wsen/wsen_pdms_25131308XXX05", + # # sensor/wsen/wsen_pdus_25131308XXXXX "we_wsen_pdus_25131308xxxxx": "sensor/wsen/wsen_pdus_25131308XXXXX", # + # sensor/wsen/wsen_tids_2521020222501 + "we_wsen_tids_2521020222501": "sensor/wsen/wsen_tids_2521020222501", + # + # sensor/xbr818 + "phosense_xbr818": "sensor/xbr818", + # + # sent + "nxp_s32_sent": "sent", + # # serial "SBSA_COMPAT": "serial", "adi_max32_uart": "serial", + "aesc_uart": "serial", "altr_jtag_uart": "serial", "altr_uart": "serial", + "ambiq_uart": "serial", "arm_cmsdk_uart": "serial", "arm_pl011": "serial", "atmel_sam0_uart": "serial", "atmel_sam_uart": "serial", "atmel_sam_usart": "serial", + "bflb_uart": "serial", "brcm_bcm2711_aux_uart": "serial", "cdns_uart": "serial", "cypress_psoc6_uart": "serial", "efinix_sapphire_uart0": "serial", + "ene_kb106x_uart": "serial", "ene_kb1200_uart": "serial", + "espressif_esp32_lpuart": "serial", "espressif_esp32_uart": "serial", "espressif_esp32_usb_serial": "serial", "gaisler_apbuart": "serial", "gd_gd32_usart": "serial", "infineon_cat1_uart": "serial", + "infineon_cat1_uart_pdl": "serial", "infineon_xmc4xxx_uart": "serial", "intel_lw_uart": "serial", "intel_sedi_uart": "serial", + "ite_it51xxx_uart": "serial", "ite_it8xxx2_uart": "serial", "litex_uart": "serial", "lowrisc_opentitan_uart": "serial", "microchip_coreuart": "serial", "microchip_mec5_uart": "serial", + "microchip_sercom_g1_uart": "serial", "microchip_xec_uart": "serial", "neorv32_uart": "serial", "nordic_nrf_uart": "serial", @@ -1891,35 +2423,47 @@ "realtek_rts5912_uart": "serial", "renesas_ra8_uart_sci_b": "serial", "renesas_ra_sci_uart": "serial", - "renesas_ra_uart_sci": "serial", "renesas_rcar_hscif": "serial", "renesas_rcar_scif": "serial", + "renesas_rx_uart_sci": "serial", + "renesas_rx_uart_sci_qemu": "serial", + "renesas_rz_sci_b_uart": "serial", + "renesas_rz_sci_uart": "serial", "renesas_rz_scif_uart": "serial", + "renesas_rza2m_scif_uart": "serial", "renesas_rzt2m_uart": "serial", "renesas_smartbond_uart": "serial", "segger_rtt_uart": "serial", "sensry_sy1xx_uart": "serial", "sifive_uart0": "serial", + "sifli_sf32lb_usart": "serial", "silabs_eusart_uart": "serial", "silabs_gecko_leuart": "serial", "silabs_gecko_uart": "serial", "silabs_gecko_usart": "serial", "silabs_si32_usart": "serial", + "silabs_usart_uart": "serial", "snps_hostlink_uart": "serial", "st_stm32_uart": "serial", "telink_b91_uart": "serial", "ti_cc13xx_cc26xx_uart": "serial", + "ti_cc23x0_uart": "serial", "ti_cc32xx_uart": "serial", "ti_msp432p4xx_uart": "serial", + "ti_mspm0_uart": "serial", "ti_stellaris_uart": "serial", + "virtio_console": "serial", "vnd_serial": "serial", "wch_usart": "serial", "xen_hvc_consoleio": "serial", "xlnx_xps_uartlite_1_00_a": "serial", "xlnx_xuartps": "serial", "zephyr_native_posix_uart": "serial", + "zephyr_native_pty_uart": "serial", "zephyr_native_tty_uart": "serial", "zephyr_nus_uart": "serial", + "zephyr_uart_bitbang": "serial", + "zephyr_uart_bridge": "serial", "zephyr_uart_emul": "serial", # # sip_svc @@ -1938,18 +2482,23 @@ "arm_pl022": "spi", "atmel_sam0_spi": "spi", "atmel_sam_spi": "spi", + "cdns_spi": "spi", "cypress_psoc6_spi": "spi", + "egis_et171_spi": "spi", "espressif_esp32_spi": "spi", "gaisler_spimctrl": "spi", "gd_gd32_spi": "spi", "infineon_cat1_spi": "spi", + "infineon_cat1_spi_pdl": "spi", "infineon_xmc4xxx_spi": "spi", "intel_penwell_spi": "spi", "intel_sedi_spi": "spi", + "ite_it51xxx_spi": "spi", "ite_it8xxx2_spi": "spi", "litex_spi": "spi", "litex_spi_litespi": "spi", "lowrisc_opentitan_spi": "spi", + "microchip_mec5_qspi": "spi", "microchip_mpfs_qspi": "spi", "microchip_mpfs_spi": "spi", "microchip_xec_qmspi": "spi", @@ -1961,20 +2510,28 @@ "nxp_imx_ecspi": "spi", "nxp_lpc_spi": "spi", "nxp_s32_spi": "spi", + "nxp_sc18is606_spi": "spi", "opencores_spi_simple": "spi", "openisa_rv32m1_lpspi": "spi", "raspberrypi_pico_spi_pio": "spi", "renesas_ra8_spi_b": "spi", "renesas_ra_spi": "spi", + "renesas_rx_rspi": "spi", + "renesas_rz_rspi": "spi", + "renesas_rz_spi": "spi", "renesas_smartbond_spi": "spi", "sifive_spi0": "spi", "silabs_eusart_spi": "spi", + "silabs_gspi": "spi", "silabs_usart_spi": "spi", "snps_designware_spi": "spi", "st_stm32_spi": "spi", "telink_b91_spi": "spi", "ti_cc13xx_cc26xx_spi": "spi", + "ti_cc23x0_spi": "spi", + "ti_omap_mcspi": "spi", "vnd_spi": "spi", + "wch_spi": "spi", "xlnx_xps_spi_2_00_a": "spi", "zephyr_spi_bitbang": "spi", "zephyr_spi_emul_controller": "spi", @@ -1984,16 +2541,20 @@ # # stepper "zephyr_fake_stepper": "stepper", - "zephyr_gpio_stepper": "stepper", + "zephyr_h_bridge_stepper": "stepper", # # stepper/adi_tmc "adi_tmc2209": "stepper/adi_tmc", - "adi_tmc5041": "stepper/adi_tmc", + "adi_tmc50xx": "stepper/adi_tmc", + # + # stepper/allegro + "allegro_a4979": "stepper/allegro", # # stepper/ti - "ti_drv8424": "stepper/ti", + "ti_drv84xx": "stepper/ti", # # syscon + "bflb_efuse": "syscon", "syscon": "syscon", # # tee/optee @@ -2001,35 +2562,35 @@ # # timer "ambiq_stimer": "timer", - "andestech_machine_timer": "timer", "atmel_sam0_rtc": "timer", "gaisler_gptimer": "timer", + "infineon_cat1_lp_timer": "timer", "intel_adsp_timer": "timer", "intel_hpet": "timer", + "ite_it51xxx_timer": "timer", "ite_it8xxx2_timer": "timer", "litex_timer0": "timer", - "lowrisc_machine_timer": "timer", - "microchip_mec5_ktimer": "timer", + "microchip_sam_pit64b": "timer", "microchip_xec_rtos_timer": "timer", - "neorv32_machine_timer": "timer", - "niosv_machine_timer": "timer", - "nuclei_systimer": "timer", "nuvoton_npcx_itim_timer": "timer", "nxp_gpt_hw_timer": "timer", - "nxp_kinetis_lptmr": "timer", "nxp_lptmr": "timer", "nxp_os_timer": "timer", "openisa_rv32m1_lptmr": "timer", "realtek_rts5912_rtmr": "timer", + "renesas_ra_ulpt_timer": "timer", "renesas_rcar_cmt": "timer", - "scr_machine_timer": "timer", - "sifive_clint0": "timer", + "renesas_rx_timer_cmt": "timer", + "renesas_rz_gtm_os_timer": "timer", + "renesas_rza2m_ostm": "timer", + "riscv_machine_timer": "timer", "silabs_gecko_burtc": "timer", "st_stm32_lptim": "timer", "sy1xx_sys_timer": "timer", - "telink_machine_timer": "timer", "ti_am654_timer": "timer", "ti_cc13xx_cc26xx_rtc_timer": "timer", + "ti_cc23x0_rtc_timer": "timer", + "ti_cc23x0_systim_timer": "timer", "wch_systick": "timer", "xlnx_ttcps": "timer", # @@ -2037,12 +2598,13 @@ "diodes_pi3usb9201": "usb/bc12", # # usb/device - "atmel_sam0_usb": "usb/device", "atmel_sam_usbc": "usb/device", "atmel_sam_usbhs": "usb/device", # # usb/udc + "adi_max32_usbhs": "usb/udc", "ambiq_usb": "usb/udc", + "atmel_sam0_usb": "usb/udc", "ite_it82xx2_usb": "usb/udc", "nordic_nrf_usbd": "usb/udc", "nuvoton_numaker_usbd": "usb/udc", @@ -2061,6 +2623,10 @@ # # usb/uhc "maxim_max3421e_spi": "usb/uhc", + "nxp_uhc_ehci": "usb/uhc", + "nxp_uhc_ip3516hs": "usb/uhc", + "nxp_uhc_khci": "usb/uhc", + "nxp_uhc_ohci": "usb/uhc", "zephyr_uhc_virtual": "usb/uhc", # # usb_c/ppc @@ -2069,6 +2635,7 @@ # # usb_c/tcpc "nuvoton_numaker_tcpc": "usb_c/tcpc", + "onnn_fusb307_tcpc": "usb_c/tcpc", "parade_ps8xxx": "usb_c/tcpc", "richtek_rt1715": "usb_c/tcpc", "st_stm32_ucpd": "usb_c/tcpc", @@ -2082,6 +2649,7 @@ "aptina_mt9m114": "video", "espressif_esp32_lcd_cam": "video", "galaxycore_gc2145": "video", + "himax_hm01b0": "video", "nxp_imx_csi": "video", "nxp_mipi_csi2rx": "video", "nxp_video_smartdma": "video", @@ -2089,10 +2657,21 @@ "ovti_ov5640": "video", "ovti_ov7670": "video", "ovti_ov7725": "video", + "ovti_ov9655": "video", + "renesas_ra_ceu": "video", + "sony_imx335": "video", + "st_mipid02": "video", "st_stm32_dcmi": "video", - "zephyr_sw_generator": "video", + "st_stm32_dcmipp": "video", + "st_stm32_jpeg": "video", + "st_stm32_venc": "video", "zephyr_video_emul_imager": "video", "zephyr_video_emul_rx": "video", + "zephyr_video_sw_generator": "video", + # + # virtio + "virtio_mmio": "virtio", + "virtio_pci": "virtio", # # virtualization "qemu_ivshmem": "virtualization", @@ -2113,7 +2692,9 @@ "andestech_atcwdt200": "watchdog", "arm_cmsdk_watchdog": "watchdog", "atmel_sam0_watchdog": "watchdog", + "atmel_sam4l_watchdog": "watchdog", "atmel_sam_watchdog": "watchdog", + "ene_kb106x_watchdog": "watchdog", "ene_kb1200_watchdog": "watchdog", "espressif_esp32_watchdog": "watchdog", "espressif_esp32_xt_wdt": "watchdog", @@ -2123,31 +2704,45 @@ "infineon_xmc4xxx_watchdog": "watchdog", "intel_adsp_watchdog": "watchdog", "intel_tco_wdt": "watchdog", + "ite_it51xxx_watchdog": "watchdog", "ite_it8xxx2_watchdog": "watchdog", "litex_watchdog": "watchdog", "lowrisc_opentitan_aontimer": "watchdog", "microchip_xec_watchdog": "watchdog", "nordic_npm1300_wdt": "watchdog", + "nordic_npm1304_wdt": "watchdog", "nordic_npm2100_wdt": "watchdog", "nordic_npm6001_wdt": "watchdog", "nuvoton_npcx_watchdog": "watchdog", "nuvoton_numaker_wwdt": "watchdog", + "nxp_cop": "watchdog", + "nxp_ewm": "watchdog", "nxp_fs26_wdog": "watchdog", "nxp_imx_wdog": "watchdog", "nxp_kinetis_wdog": "watchdog", "nxp_lpc_wwdt": "watchdog", + "nxp_rtwdog": "watchdog", "nxp_s32_swt": "watchdog", "nxp_wdog32": "watchdog", "raspberrypi_pico_watchdog": "watchdog", + "realtek_rts5912_watchdog": "watchdog", + "renesas_rx_iwdt": "watchdog", + "renesas_rz_wdt": "watchdog", "renesas_smartbond_watchdog": "watchdog", "sifive_wdt": "watchdog", + "sifli_sf32lb_wdt": "watchdog", "silabs_gecko_wdog": "watchdog", + "silabs_siwx91x_wdt": "watchdog", "snps_designware_watchdog": "watchdog", "st_stm32_watchdog": "watchdog", "st_stm32_window_watchdog": "watchdog", "ti_cc13xx_cc26xx_watchdog": "watchdog", + "ti_cc23x0_wdt": "watchdog", "ti_cc32xx_watchdog": "watchdog", + "ti_j7_rti_wdt": "watchdog", "ti_tps382x": "watchdog", + "wch_iwdg": "watchdog", + "xlnx_versal_wwdt": "watchdog", "xlnx_xps_timebase_wdt_1_00_a": "watchdog", # # wifi/esp32/src @@ -2166,6 +2761,9 @@ # wifi/nxp "nxp_wifi": "wifi/nxp", # + # wifi/siwx91x + "silabs_siwx91x_wifi": "wifi/siwx91x", + # # wifi/winc1500 "atmel_winc1500": "wifi/winc1500", } diff --git a/ports/zephyr-cp/cptools/cpbuild.py b/ports/zephyr-cp/cptools/cpbuild.py index ef836b3df8a..edaf020c264 100644 --- a/ports/zephyr-cp/cptools/cpbuild.py +++ b/ports/zephyr-cp/cptools/cpbuild.py @@ -1,15 +1,14 @@ import asyncio -import inspect +import atexit +import hashlib +import json import logging import os import pathlib -import shlex -import time -import hashlib -import atexit -import json import re -import sys +import tempfile +import time +from typing import Optional logger = logging.getLogger(__name__) @@ -111,7 +110,14 @@ def _create_semaphore(): max_track = 0 -async def run_command(command, working_directory, description=None, check_hash=[], extradeps=[]): +async def run_command( + command, + working_directory, + description=None, + check_hash=[], + extradeps=[], + responsefile: Optional[pathlib.Path] = None, +): """ Runs a command asynchronously. The command should ideally be a list of strings and pathlib.Path objects. If all of the paths haven't been modified since the last @@ -124,26 +130,39 @@ async def run_command(command, working_directory, description=None, check_hash=[ Paths in check_hash are hashed before and after the command. If the hash is the same, then the old mtimes are reset. This is helpful if a command may produce - the same result and you don't want the rest of the build impacted. + the same result and you don't want the rest of the build impacted + + responsefile is used to store the command line arguments if they are too long for the OS. + The arguments will be replaced with @ and tried again. + If None, commands that are too long will fail. """ paths = [] + responsefile_contents = None if isinstance(command, list): for i, part in enumerate(command): if isinstance(part, pathlib.Path): paths.append(part) part = part.relative_to(working_directory, walk_up=True) - # if isinstance(part, list): command[i] = str(part) - command = " ".join(command) + command_string = " ".join(command) + + # When on windows, use a responsefile if the command string is >= 8192 + if responsefile is not None and os.name == "nt" and len(command_string) >= 8192: + # Escape backslashes + responsefile_contents = "\n".join(part.replace("\\", "\\\\") for part in command[1:]) + responsefile.write_text(responsefile_contents) + command_string = f"{command[0]} -v @{responsefile}" + else: + command_string = command - command_hash = hashlib.sha3_256(command.encode("utf-8")) + command_hash = hashlib.sha3_256(command_string.encode("utf-8")) command_hash.update(str(working_directory).encode("utf-8")) command_hash = command_hash.hexdigest() # If a command is run multiple times, then wait for the first one to continue. Don't run it again. if command_hash in ALREADY_RUN: - logger.debug(f"Already running {command_hash} {command}") + logger.debug(f"Already running {command_hash} {command_string}") await ALREADY_RUN[command_hash].wait() return ALREADY_RUN[command_hash] = asyncio.Event() @@ -169,7 +188,7 @@ async def run_command(command, working_directory, description=None, check_hash=[ run_reason = f"{p.relative_to(working_directory, walk_up=True)} is newer" break if nothing_newer: - logger.debug(f"Nothing newer {command[-32:]}") + logger.debug(f"Nothing newer {command_string[-32:]}") ALREADY_RUN[command_hash].set() return else: @@ -196,7 +215,7 @@ async def run_command(command, working_directory, description=None, check_hash=[ track = tracks.pop() start_time = time.perf_counter_ns() // 1000 process = await asyncio.create_subprocess_shell( - command, + command_string, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, cwd=working_directory, @@ -242,22 +261,25 @@ async def run_command(command, working_directory, description=None, check_hash=[ raise cancellation if description: logger.info(f"{description} ({run_reason})") - logger.debug(command) + logger.debug(command_string) else: - logger.info(f"{command} ({run_reason})") + logger.info(f"{command_string} ({run_reason})") if old_newest_file == newest_file: logger.error("No files were modified by the command.") raise RuntimeError() else: if command_hash in LAST_BUILD_TIMES: del LAST_BUILD_TIMES[command_hash] + logger.error(command_string) + if responsefile_contents: + logger.error(f"Response file contents:\n{responsefile_contents}") + logger.error(f"Return code: {process.returncode}") if stdout: logger.info(stdout.decode("utf-8").strip()) if stderr: logger.warning(stderr.decode("utf-8").strip()) if not stdout and not stderr: logger.warning("No output") - logger.error(command) if cancellation: raise cancellation raise RuntimeError() @@ -335,8 +357,8 @@ async def preprocess( ): output_file.parent.mkdir(parents=True, exist_ok=True) depfile = output_file.parent / (output_file.name + ".d") - if depfile.exists(): - pass + responsefile = output_file.parent / (output_file.name + ".rsp") + await run_command( [ self.c_compiler, @@ -354,6 +376,7 @@ async def preprocess( description=f"Preprocess {source_file.relative_to(self.srcdir)} -> {output_file.relative_to(self.builddir)}", working_directory=self.srcdir, check_hash=[output_file], + responsefile=responsefile, ) async def compile( @@ -365,6 +388,7 @@ async def compile( output_file = self.builddir / output_file output_file.parent.mkdir(parents=True, exist_ok=True) depfile = output_file.with_suffix(".d") + responsefile = output_file.with_suffix(".rsp") extradeps = [] if depfile.exists(): depfile_contents = depfile.read_text().split() @@ -375,25 +399,30 @@ async def compile( extradeps.append(pathlib.Path(dep)) else: extradeps.append(self.srcdir / dep) + await run_command( - [self.c_compiler, self.cflags, "-MMD", "-c", source_file, *flags, "-o", output_file], + [ + self.c_compiler, + self.cflags, + "-MMD", + "-c", + source_file, + *flags, + "-o", + output_file, + ], description=f"Compile {source_file.relative_to(self.srcdir)} -> {output_file.relative_to(self.builddir)}", working_directory=self.srcdir, extradeps=extradeps, + responsefile=responsefile, ) async def archive(self, objects: list[pathlib.Path], output_file: pathlib.Path): output_file.parent.mkdir(parents=True, exist_ok=True) - # Do one file at a time so that we don't have a long command line. run_command - # should skip unchanged files ok. - input_files = output_file.with_suffix(output_file.suffix + ".input_files") - input_file_content = "\n".join(str(p) for p in objects) - # Windows paths have \ as separator but ar wants them as / (like UNIX) - input_file_content = input_file_content.replace("\\", "/") - input_files.write_text(input_file_content) + responsefile = output_file.with_suffix(".rsp") await run_command( - [self.ar, "rvs", output_file, f"@{input_files}"], + [self.ar, "rvs", output_file, *objects], description=f"Create archive {output_file.relative_to(self.srcdir)}", working_directory=self.srcdir, - extradeps=objects, + responsefile=responsefile, ) diff --git a/ports/zephyr-cp/cptools/gen_compat2driver.py b/ports/zephyr-cp/cptools/gen_compat2driver.py index 0cb6a16f9da..1e529072dab 100644 --- a/ports/zephyr-cp/cptools/gen_compat2driver.py +++ b/ports/zephyr-cp/cptools/gen_compat2driver.py @@ -2,7 +2,7 @@ mapping = {} -drivers = pathlib.Path("lib/zephyr/drivers") +drivers = pathlib.Path("zephyr/drivers") for p in drivers.glob("**/*.c"): for line in p.open(): if line.startswith("#define DT_DRV_COMPAT"): diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index cd0e3a6f2aa..071334161b9 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -1,14 +1,16 @@ import logging import pathlib -import cpbuild -from devicetree import dtlib +import cpbuild import yaml - from compat2driver import COMPAT_TO_DRIVER +from devicetree import dtlib logger = logging.getLogger(__name__) +# GPIO flags defined here: include/zephyr/dt-bindings/gpio/gpio.h +GPIO_ACTIVE_LOW = 1 << 0 + MANUAL_COMPAT_TO_DRIVER = { "renesas_ra_nv_flash": "flash", } @@ -82,6 +84,26 @@ "D12", "D13", ], + "arducam,dvp-20pin-connector": [ + "SCL", + "SDA", + "VS", + "HS", + "PCLK", + "XCLK", + "D7", + "D6", + "D5", + "D4", + "D3", + "D2", + "D1", + "D0", + "PEN", + "PDN", + "GPIO0", + "GPIO1", + ], "renesas,ra-gpio-mipi-header": [ "IIC_SDA", "DISP_BLEN", @@ -89,6 +111,60 @@ "DISP_INT", "DISP_RST", ], + "renesas,ra-parallel-graphics-header": [ + "DISP_BLEN", + "IIC_SDA", + "DISP_INT", + "IIC_SCL", + "DISP_RST", + "LCDC_TCON0", + "LCDC_CLK", + "LCDC_TCON2", + "LCDC_TCON1", + "LCDC_EXTCLK", + "LCDC_TCON3", + "LCDC_DATA01", + "LCDC_DATA00", + "LCDC_DATA03", + "LCDC_DATA02", + "LCDC_DATA05", + "LCDC_DATA04", + "LCDC_DATA07", + "LCDC_DATA16", + "LCDC_DATA09", + "LCDC_DATA08", + "LCDC_DATA11", + "LCDC_DATA10", + "LCDC_DATA13", + "LCDC_DATA12", + "LCDC_DATA15", + "LCDC_DATA14", + "LCDC_DATA17", + "LCDC_DATA16", + "LCDC_DATA19", + "LCDC_DATA18", + "LCDC_DATA21", + "LCDC_DATA20", + "LCDC_DATA23", + "LCDC_DATA22", + ], + "st,stm32-dcmi-camera-fpu-330zh": [ + "SCL", + "SDA", + "RESET", + "PEN", + "VS", + "HS", + "PCLK", + "D7", + "D6", + "D5", + "D4", + "D3", + "D2", + "D1", + "D0", + ], } @@ -139,6 +215,7 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 flashes = [] rams = [] status_led = None + status_led_inverted = False path2chosen = {} chosen2path = {} usb_num_endpoint_pairs = 0 @@ -247,6 +324,7 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 props = led.props ioport = props["gpios"]._markers[1][2] num = int.from_bytes(props["gpios"].value[4:8], "big") + flags = int.from_bytes(props["gpios"].value[8:12], "big") if "label" in props: if (ioport, num) not in board_names: board_names[(ioport, num)] = [] @@ -257,6 +335,7 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 if "led0" in node2alias[led]: board_names[(ioport, num)].append("LED") status_led = (ioport, num) + status_led_inverted = flags & GPIO_ACTIVE_LOW board_names[(ioport, num)].extend(node2alias[led]) if "gpio-keys" in compatible: @@ -316,8 +395,12 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 header = board_dir / "mpconfigboard.h" if status_led: status_led = f"#define MICROPY_HW_LED_STATUS (&pin_{status_led})\n" + status_led_inverted = ( + f"#define MICROPY_HW_LED_STATUS_INVERTED ({'1' if status_led_inverted else '0'})\n" + ) else: status_led = "" + status_led_inverted = "" ram_list = [] ram_externs = [] max_size = 0 @@ -339,6 +422,7 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 #define MICROPY_HW_MCU_NAME "{soc_name}" #define CIRCUITPY_RAM_DEVICE_COUNT {len(rams)} {status_led} +{status_led_inverted} """ if not header.exists() or header.read_text() != new_header_content: header.write_text(new_header_content) @@ -384,8 +468,7 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); """ - if not board_c.exists() or new_board_c_content != board_c.read_text(): - board_c.write_text(new_board_c_content) + board_c.write_text(new_board_c_content) board_info["source_files"] = [board_c] board_info["cflags"] = ("-I", board_dir) board_info["flash_count"] = len(flashes) diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index f769d7dc6b8..bd693bb897e 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -14,7 +14,7 @@ CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 CONFIG_THREAD_STACK_INFO=y CONFIG_STACK_SENTINEL=y CONFIG_DEBUG_THREAD_INFO=y -CONFIG_DEBUG_INFO=y +# CONFIG_DEBUG_INFO=y CONFIG_USB_DEVICE_STACK=n diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 01712e864e0..3eb38f7bea6 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -2,6 +2,6 @@ manifest: projects: - name: zephyr url: https://github.com/adafruit/zephyr - revision: circuitpython + revision: circuitpython-v4.3.0 clone-depth: 100 import: true From c5a28aa41e637c6bb32eed99693e5d9a1606e809 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 24 Nov 2025 23:29:18 -0500 Subject: [PATCH 097/876] hack_club_sprig: add board.SPI() for display and SD card use --- .../boards/hack_club_sprig/board.c | 19 ++++++++++--------- .../boards/hack_club_sprig/mpconfigboard.h | 8 ++++++++ .../raspberrypi/boards/hack_club_sprig/pins.c | 16 ++++++++++------ 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/ports/raspberrypi/boards/hack_club_sprig/board.c b/ports/raspberrypi/boards/hack_club_sprig/board.c index 89b1b3b75b7..40711c55445 100644 --- a/ports/raspberrypi/boards/hack_club_sprig/board.c +++ b/ports/raspberrypi/boards/hack_club_sprig/board.c @@ -10,7 +10,7 @@ #include "shared-bindings/fourwire/FourWire.h" #include "shared-module/displayio/__init__.h" #include "shared-module/displayio/mipi_constants.h" -#include "supervisor/shared/board.h" +#include "shared-bindings/board/__init__.h" // display init sequence from CircuitPython library https://github.com/adafruit/Adafruit_CircuitPython_ST7735R/blob/dfae353330cf051d1f31db9e4b681c8d70900cc5/adafruit_st7735r.py @@ -57,17 +57,14 @@ uint8_t display_init_sequence[] = { void board_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; - busio_spi_obj_t *spi = &bus->inline_bus; - common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, &pin_GPIO16, false); - common_hal_busio_spi_never_reset(spi); - bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO22, // DC - &pin_GPIO20, // CS - &pin_GPIO26, // RST + CIRCUITPY_BOARD_TFT_DC, + CIRCUITPY_BOARD_TFT_CS, + CIRCUITPY_BOARD_TFT_RESET, 30000000, 0, 0); @@ -92,7 +89,7 @@ void board_init(void) { MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command display_init_sequence, sizeof(display_init_sequence), - &pin_GPIO17, // backlight pin + CIRCUITPY_BOARD_TFT_BACKLIGHT, NO_BRIGHTNESS_COMMAND, 1.0f, // brightness false, // single_byte_bounds @@ -104,4 +101,8 @@ void board_init(void) { 50000); // backlight pwm frequency } +void board_deinit(void) { + common_hal_displayio_release_displays(); +} + // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/hack_club_sprig/mpconfigboard.h b/ports/raspberrypi/boards/hack_club_sprig/mpconfigboard.h index 041aca6d45e..bfc0469a711 100644 --- a/ports/raspberrypi/boards/hack_club_sprig/mpconfigboard.h +++ b/ports/raspberrypi/boards/hack_club_sprig/mpconfigboard.h @@ -10,3 +10,11 @@ #define MICROPY_HW_MCU_NAME "rp2040" #define MICROPY_HW_LED_STATUS (&pin_GPIO4) + +#define CIRCUITPY_BOARD_TFT_DC (&pin_GPIO22) +#define CIRCUITPY_BOARD_TFT_CS (&pin_GPIO20) +#define CIRCUITPY_BOARD_TFT_RESET (&pin_GPIO26) +#define CIRCUITPY_BOARD_TFT_BACKLIGHT (&pin_GPIO17) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO18, .mosi = &pin_GPIO19, .miso = &pin_GPIO16 }} diff --git a/ports/raspberrypi/boards/hack_club_sprig/pins.c b/ports/raspberrypi/boards/hack_club_sprig/pins.c index e5ce1478398..7802ef5466d 100644 --- a/ports/raspberrypi/boards/hack_club_sprig/pins.c +++ b/ports/raspberrypi/boards/hack_club_sprig/pins.c @@ -60,7 +60,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, - // Start Sprig-specific definitions { MP_ROM_QSTR(MP_QSTR_BLUE_LED), MP_ROM_PTR(&pin_GPIO4) }, @@ -79,18 +78,23 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BUTTON_K), MP_ROM_PTR(&pin_GPIO14) }, { MP_ROM_QSTR(MP_QSTR_BUTTON_L), MP_ROM_PTR(&pin_GPIO15) }, - { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO16) }, - { MP_ROM_QSTR(MP_QSTR_TFT_LITE), MP_ROM_PTR(&pin_GPIO17) }, { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) }, - { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_CARD_CS), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO22) }, - { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_DC) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_CS) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_RESET) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_BACKLIGHT) }, + { MP_ROM_QSTR(MP_QSTR_TFT_LITE), MP_ROM_PTR(CIRCUITPY_BOARD_TFT_BACKLIGHT) }, + { MP_ROM_QSTR(MP_QSTR_WHITE_LED), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 26bd5af3dd1fda13507750a104a3ae3e17972548 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 2 Dec 2025 09:43:08 -0600 Subject: [PATCH 098/876] bitmaptools.replace_color() function --- shared-bindings/bitmaptools/__init__.c | 41 ++++++++++++++++++++++++++ shared-bindings/bitmaptools/__init__.h | 3 ++ shared-module/bitmaptools/__init__.c | 15 ++++++++++ 3 files changed, 59 insertions(+) diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index 709e4582113..ba7bf7e3fa1 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -418,6 +418,46 @@ static mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, } MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_alphablend_obj, 0, bitmaptools_alphablend); +//| def replace_color( +//| dest_bitmap: displayio.Bitmap, old_color: int, new_color: int +//| ) -> None: +//| """Replace any pixels of old_color with new_color in the dest_bitmap +//| +//| :param bitmap dest_bitmap: Destination bitmap that will be written into +//| :param int old_color: Bitmap palette index that will overwritten +//| :param int new_color: Bitmap palette index that will get put in the bitmap""" +//| ... +//| +//| +static mp_obj_t bitmaptools_obj_replace_color(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum {ARG_dest_bitmap, ARG_old_color, ARG_new_color}; + + static const mp_arg_t allowed_args[] = { + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_old_color, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_new_color, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + + uint32_t old_color, new_color, color_depth; + old_color = args[ARG_old_color].u_int; + new_color = args[ARG_new_color].u_int; + + color_depth = (1 << destination->bits_per_value); + if (color_depth <= old_color || color_depth <= new_color) { + mp_raise_ValueError(MP_ERROR_TEXT("out of range of target")); + } + + common_hal_bitmaptools_replace_color(destination, old_color, new_color); + + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_replace_color_obj, 0, bitmaptools_obj_replace_color); + //| def fill_region( //| dest_bitmap: displayio.Bitmap, x1: int, y1: int, x2: int, y2: int, value: int //| ) -> None: @@ -1103,6 +1143,7 @@ static const mp_rom_map_elem_t bitmaptools_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_rotozoom), MP_ROM_PTR(&bitmaptools_rotozoom_obj) }, { MP_ROM_QSTR(MP_QSTR_arrayblit), MP_ROM_PTR(&bitmaptools_arrayblit_obj) }, { MP_ROM_QSTR(MP_QSTR_alphablend), MP_ROM_PTR(&bitmaptools_alphablend_obj) }, + { MP_ROM_QSTR(MP_QSTR_replace_color), MP_ROM_PTR(&bitmaptools_replace_color_obj) }, { MP_ROM_QSTR(MP_QSTR_fill_region), MP_ROM_PTR(&bitmaptools_fill_region_obj) }, { MP_ROM_QSTR(MP_QSTR_boundary_fill), MP_ROM_PTR(&bitmaptools_boundary_fill_obj) }, { MP_ROM_QSTR(MP_QSTR_draw_line), MP_ROM_PTR(&bitmaptools_draw_line_obj) }, diff --git a/shared-bindings/bitmaptools/__init__.h b/shared-bindings/bitmaptools/__init__.h index 21116b8bd42..f193ef6d952 100644 --- a/shared-bindings/bitmaptools/__init__.h +++ b/shared-bindings/bitmaptools/__init__.h @@ -42,6 +42,9 @@ void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination, int16_t x2, int16_t y2, uint32_t value); +void common_hal_bitmaptools_replace_color(displayio_bitmap_t *destination, + uint32_t old_color, uint32_t new_color); + void common_hal_bitmaptools_boundary_fill(displayio_bitmap_t *destination, int16_t x, int16_t y, uint32_t fill_color_value, uint32_t replaced_color_value); diff --git a/shared-module/bitmaptools/__init__.c b/shared-module/bitmaptools/__init__.c index 8a41e387e51..a4cc18529cc 100644 --- a/shared-module/bitmaptools/__init__.c +++ b/shared-module/bitmaptools/__init__.c @@ -204,6 +204,21 @@ void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16 } } +void common_hal_bitmaptools_replace_color(displayio_bitmap_t *destination, + uint32_t old_color, + uint32_t new_color){ + + int16_t x, y; + for (x = 0; x < destination->width; x++) { + for (y = 0; y < destination->height; y++) { + uint32_t pixel_val = common_hal_displayio_bitmap_get_pixel(destination, x, y); + if (pixel_val == old_color) { + displayio_bitmap_write_pixel(destination, x, y, new_color); + } + } + } +} + void common_hal_bitmaptools_fill_region(displayio_bitmap_t *destination, int16_t x1, int16_t y1, int16_t x2, int16_t y2, From 579afb27da70ed7b74d0ef5ee01d46c6ec7b0e4b Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 2 Dec 2025 09:50:50 -0600 Subject: [PATCH 099/876] fix code format --- shared-module/bitmaptools/__init__.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/shared-module/bitmaptools/__init__.c b/shared-module/bitmaptools/__init__.c index a4cc18529cc..2f2b7aaf475 100644 --- a/shared-module/bitmaptools/__init__.c +++ b/shared-module/bitmaptools/__init__.c @@ -206,16 +206,16 @@ void common_hal_bitmaptools_rotozoom(displayio_bitmap_t *self, int16_t ox, int16 void common_hal_bitmaptools_replace_color(displayio_bitmap_t *destination, uint32_t old_color, - uint32_t new_color){ + uint32_t new_color) { int16_t x, y; for (x = 0; x < destination->width; x++) { - for (y = 0; y < destination->height; y++) { - uint32_t pixel_val = common_hal_displayio_bitmap_get_pixel(destination, x, y); - if (pixel_val == old_color) { - displayio_bitmap_write_pixel(destination, x, y, new_color); + for (y = 0; y < destination->height; y++) { + uint32_t pixel_val = common_hal_displayio_bitmap_get_pixel(destination, x, y); + if (pixel_val == old_color) { + displayio_bitmap_write_pixel(destination, x, y, new_color); + } } - } } } From f6b91b72814a3c00bd599baaf5de50c2d72925ea Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 2 Dec 2025 12:07:01 -0600 Subject: [PATCH 100/876] simpler arg name, validate bitmap type, reuse error message, remove unneeded required arg default values. --- shared-bindings/bitmaptools/__init__.c | 76 +++++++++++++------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index ba7bf7e3fa1..f3aad1b67b0 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -185,8 +185,8 @@ static mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args ARG_angle, ARG_scale, ARG_skip_index}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, {MP_QSTR_ox, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to destination->width / 2 {MP_QSTR_oy, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, // None convert to destination->height / 2 @@ -421,26 +421,26 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_alphablend_obj, 0, bitmaptools_alphablend //| def replace_color( //| dest_bitmap: displayio.Bitmap, old_color: int, new_color: int //| ) -> None: -//| """Replace any pixels of old_color with new_color in the dest_bitmap +//| """Replace any pixels of ``old_color`` with ``new_color`` in the ``bitmap`` //| -//| :param bitmap dest_bitmap: Destination bitmap that will be written into +//| :param displayio.Bitmap bitmap: Bitmap that will be changed //| :param int old_color: Bitmap palette index that will overwritten //| :param int new_color: Bitmap palette index that will get put in the bitmap""" //| ... //| //| static mp_obj_t bitmaptools_obj_replace_color(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum {ARG_dest_bitmap, ARG_old_color, ARG_new_color}; + enum {ARG_bitmap, ARG_old_color, ARG_new_color}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_old_color, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_new_color, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_old_color, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_new_color, MP_ARG_REQUIRED | MP_ARG_INT}, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_bitmap)); uint32_t old_color, new_color, color_depth; old_color = args[ARG_old_color].u_int; @@ -448,7 +448,7 @@ static mp_obj_t bitmaptools_obj_replace_color(size_t n_args, const mp_obj_t *pos color_depth = (1 << destination->bits_per_value); if (color_depth <= old_color || color_depth <= new_color) { - mp_raise_ValueError(MP_ERROR_TEXT("out of range of target")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_color); } common_hal_bitmaptools_replace_color(destination, old_color, new_color); @@ -478,9 +478,9 @@ static mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_a enum {ARG_dest_bitmap, ARGS_X1_Y1_X2_Y2, ARG_value}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, ALLOWED_ARGS_X1_Y1_X2_Y2(MP_ARG_REQUIRED, MP_ARG_REQUIRED), - {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT}, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -527,10 +527,10 @@ static mp_obj_t bitmaptools_obj_boundary_fill(size_t n_args, const mp_obj_t *pos enum {ARG_dest_bitmap, ARG_x, ARG_y, ARG_fill_color_value, ARG_replaced_color_value}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_fill_color_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_fill_color_value, MP_ARG_REQUIRED | MP_ARG_INT}, {MP_QSTR_replaced_color_value, MP_ARG_INT, {.u_int = INT_MAX} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -588,12 +588,12 @@ static mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_arg enum {ARG_dest_bitmap, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_value}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_x2, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_y2, MP_ARG_REQUIRED | MP_ARG_INT}, + {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT}, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -675,10 +675,10 @@ static mp_obj_t bitmaptools_obj_draw_polygon(size_t n_args, const mp_obj_t *pos_ enum {ARG_dest_bitmap, ARG_xs, ARG_ys, ARG_value, ARG_close}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_xs, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_ys, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, - {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_xs, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_ys, MP_ARG_REQUIRED | MP_ARG_OBJ}, + {MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT}, {MP_QSTR_close, MP_ARG_BOOL, {.u_bool = true}}, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -757,8 +757,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_polygon_obj, 0, bitmaptools_obj_draw static mp_obj_t bitmaptools_arrayblit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_bitmap, ARG_data, ARGS_X1_Y1_X2_Y2, ARG_skip_index }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, ALLOWED_ARGS_X1_Y1_X2_Y2(0, 0), { MP_QSTR_skip_index, MP_ARG_OBJ, {.u_obj = mp_const_none } }, }; @@ -822,9 +822,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_arrayblit_obj, 0, bitmaptools_arrayblit); static mp_obj_t bitmaptools_readinto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_bitmap, ARG_file, ARG_bits_per_pixel, ARG_element_size, ARG_reverse_pixels_in_element, ARG_swap_bytes_in_element, ARG_reverse_rows }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_bits_per_pixel, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_file, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_bits_per_pixel, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_element_size, MP_ARG_INT, { .u_int = 1 } }, { MP_QSTR_reverse_pixels_in_element, MP_ARG_BOOL, { .u_bool = false } }, { MP_QSTR_swap_bytes_in_element, MP_ARG_BOOL, { .u_bool = false } }, @@ -913,9 +913,9 @@ MAKE_ENUM_TYPE(bitmaptools, DitherAlgorithm, bitmaptools_dither_algorithm); static mp_obj_t bitmaptools_dither(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_dest_bitmap, ARG_source_bitmap, ARG_source_colorspace, ARG_algorithm }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_source_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_source_colorspace, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_algorithm, MP_ARG_OBJ, { .u_obj = MP_ROM_PTR((void *)&dither_algorithm_Atkinson_obj) } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -1078,10 +1078,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(bitmaptools_draw_circle_obj, 0, bitmaptools_obj_draw_ static mp_obj_t bitmaptools_obj_blit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum {ARG_destination, ARG_source, ARG_x, ARG_y, ARG_x1, ARG_y1, ARG_x2, ARG_y2, ARG_skip_source_index, ARG_skip_dest_index}; static const mp_arg_t allowed_args[] = { - {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, - {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} }, - {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT, {.u_obj = MP_OBJ_NULL} }, + {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + {MP_QSTR_source_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, ALLOWED_ARGS_X1_Y1_X2_Y2(0, 0), {MP_QSTR_skip_source_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, {MP_QSTR_skip_dest_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, From 7b429baa0dd36e3e552e805481820f42b6219f6c Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 2 Dec 2025 14:53:44 -0600 Subject: [PATCH 101/876] -Wno-missing-field-initializers on unix port make --- ports/unix/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index bb1f6a4740a..6aee1a939b3 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -46,7 +46,7 @@ INC += -I$(BUILD) # compiler settings CWARN = -Wall -Werror -CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion +CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -Wno-missing-field-initializers CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) # Force the use of 64-bits for file sizes in C library functions on 32-bit platforms. From 88619f47353ce3b7c2618ddb209d81a7bad9a3a7 Mon Sep 17 00:00:00 2001 From: noqman Date: Wed, 3 Dec 2025 16:59:42 +0800 Subject: [PATCH 102/876] Initial commit --- .../boards/cytron_edu_pico_v2_2w/board.c | 9 ++ .../cytron_edu_pico_v2_2w/mpconfigboard.h | 21 +++++ .../cytron_edu_pico_v2_2w/mpconfigboard.mk | 53 ++++++++++++ .../pico-sdk-configboard.h | 9 ++ .../boards/cytron_edu_pico_v2_2w/pins.c | 86 +++++++++++++++++++ 5 files changed, 178 insertions(+) create mode 100644 ports/raspberrypi/boards/cytron_edu_pico_v2_2w/board.c create mode 100644 ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pins.c diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/board.c b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/board.c new file mode 100644 index 00000000000..e6a868ab212 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.h b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.h new file mode 100644 index 00000000000..8eab7e5a525 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Cytron EDU PICO 2" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1) +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE (1) + +#define MICROPY_HW_LED_STATUS (&pin_CYW0) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO5, .sda = &pin_GPIO4}} + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO18, .mosi = &pin_GPIO19, .miso = &pin_GPIO16}} diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk new file mode 100644 index 00000000000..72d20ea7e05 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk @@ -0,0 +1,53 @@ +USB_VID = 0x2E8A +USB_PID = 0x107E +USB_PRODUCT = "Cytron EDU PICO 2 for Pico 2W" +USB_MANUFACTURER = "Cytron" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" + +CIRCUITPY__EVE = 1 + +CIRCUITPY_CYW43 = 1 +CIRCUITPY_SSL = 1 +CIRCUITPY_HASHLIB = 1 +CIRCUITPY_WEB_WORKFLOW = 1 +CIRCUITPY_MDNS = 1 +CIRCUITPY_SOCKETPOOL = 1 +CIRCUITPY_WIFI = 1 + +CFLAGS += \ + -DCYW43_PIN_WL_DYNAMIC=0 \ + -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ + -DCYW43_DEFAULT_PIN_WL_REG_ON=23 \ + -DCYW43_DEFAULT_PIN_WL_CLOCK=29 \ + -DCYW43_DEFAULT_PIN_WL_DATA_IN=24 \ + -DCYW43_DEFAULT_PIN_WL_DATA_OUT=24 \ + -DCYW43_DEFAULT_PIN_WL_CS=25 \ + -DCYW43_WL_GPIO_COUNT=3 \ + -DCYW43_WL_GPIO_LED_PIN=0 + -DCYW43_PIO_CLOCK_DIV_INT=3 + +# Must be accompanied by a linker script change +CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' + +# The default is -O3. Change to -O2 because the build was overflowing. +OPTIMIZATION_FLAGS = -O2 + +# Include these Python libraries in firmware. +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Text +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Motor +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SimpleIO +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ImageLoad +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_AHTx0 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HTTPServer diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pico-sdk-configboard.h b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pico-sdk-configboard.h new file mode 100644 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pins.c b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pins.c new file mode 100644 index 00000000000..83b93e72685 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pins.c @@ -0,0 +1,86 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + + // Motor Controls + { MP_ROM_QSTR(MP_QSTR_M1A), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_M1B), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_M2A), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_M2B), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_LOG_SWITCH), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + + // SPI Pins for SD Card + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_USB_RELAY), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_CYW1) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_CYW0) }, + + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_CYW2) }, + + { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_USB_HOST_DATA_PLUS), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_USB_HOST_DATA_MINUS), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_USB_HOST_POWER), MP_ROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SD_SPI), MP_ROM_PTR(&board_spi_obj) }, + + + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From da50dfa686401f3b0c13bb879844ca3d36c21705 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 2 Dec 2025 09:52:57 -0800 Subject: [PATCH 103/876] Add I2C support to the Zephyr builds You cannot instantiate `zephyr_i2c.I2C()` because they are fixed by the board's device tree. All busses with status = "okay" are added to board with all of their labels as names. So, I2C() may be the same as I2C1() and ARDUINO_I2C(). Part of #9903. --- locale/circuitpython.pot | 14 +- ports/zephyr-cp/bindings/zephyr_i2c/I2C.c | 378 ++++++++++++++++++ ports/zephyr-cp/bindings/zephyr_i2c/I2C.h | 32 ++ .../zephyr-cp/bindings/zephyr_i2c/__init__.c | 27 ++ ports/zephyr-cp/boards/board_aliases.cmake | 2 + .../nordic/nrf5340dk/autogen_board_info.toml | 3 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 116 ++++++ .../nordic/nrf54h20dk/circuitpython.toml | 1 + .../nordic/nrf54l15dk/autogen_board_info.toml | 3 +- .../nordic/nrf7002dk/autogen_board_info.toml | 3 +- .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 1 + .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 45 +++ .../zephyr-cp/boards/nucleo_n657x0_q.overlay | 0 .../renesas/ek_ra6m5/autogen_board_info.toml | 3 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 3 +- .../nucleo_n657x0_q/autogen_board_info.toml | 116 ++++++ .../st/nucleo_n657x0_q/circuitpython.toml | 1 + .../nucleo_u575zi_q/autogen_board_info.toml | 3 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 3 +- ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c | 142 ++++--- ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h | 12 +- .../zephyr-cp/common-hal/zephyr_serial/UART.c | 6 + .../zephyr-cp/common-hal/zephyr_serial/UART.h | 2 + .../zephyr-cp/cptools/build_circuitpython.py | 12 +- ports/zephyr-cp/cptools/zephyr2cp.py | 123 +++++- ports/zephyr-cp/prj.conf | 2 + ports/zephyr-cp/supervisor/flash.c | 4 + 27 files changed, 975 insertions(+), 82 deletions(-) create mode 100644 ports/zephyr-cp/bindings/zephyr_i2c/I2C.c create mode 100644 ports/zephyr-cp/bindings/zephyr_i2c/I2C.h create mode 100644 ports/zephyr-cp/bindings/zephyr_i2c/__init__.c create mode 100644 ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf create mode 100644 ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay create mode 100644 ports/zephyr-cp/boards/nucleo_n657x0_q.overlay create mode 100644 ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 35fc94513a5..81074f3f804 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -111,6 +111,7 @@ msgid "%q in %q must be of type %q, not %q" msgstr "" #: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -244,7 +245,8 @@ msgstr "" #: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "" @@ -834,10 +836,6 @@ msgstr "" msgid "Clock unit in use" msgstr "" -#: ports/espressif/common-hal/mipidsi/Display.c -msgid "Color depth must be 16 or 24" -msgstr "" - #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -1119,8 +1117,9 @@ msgid "" "Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "" @@ -1271,6 +1270,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c #: ports/raspberrypi/bindings/picodvi/Framebuffer.c diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c new file mode 100644 index 00000000000..08ce9e966a6 --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c @@ -0,0 +1,378 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/zephyr_i2c/I2C.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared/runtime/buffer_helper.h" +#include "py/binary.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include +#include + +//| class I2C: +//| """Two wire serial protocol +//| +//| I2C is a two-wire protocol for communicating between devices. At the +//| physical level it consists of 2 wires: SCL and SDA, the clock and data +//| lines respectively. +//| +//| .. class:: I2C() +//| +//| Cannot be instantiated directly. Instead singletons are created using the +//| `board` aliases that match the device tree labels. `board` may list multiple +//| aliases for a single device. For example, `board.I2C1` and `board.ARDUINO_I2C` +//| may both refer to the same device. +//| """ +//| + +static zephyr_i2c_i2c_obj_t *native_i2c(mp_obj_t self_in) { + mp_check_self(mp_obj_is_type(self_in, &zephyr_i2c_i2c_type)); + return MP_OBJ_TO_PTR(self_in); +} + +static void check_for_deinit(zephyr_i2c_i2c_obj_t *self) { + if (common_hal_zephyr_i2c_i2c_deinited(self)) { + raise_deinited_error(); + } +} + +static void check_lock(zephyr_i2c_i2c_obj_t *self) { + if (!common_hal_zephyr_i2c_i2c_has_lock(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); + } +} + +//| def deinit(self) -> None: +//| """Releases control of the underlying hardware so other classes can use it.""" +//| ... +static mp_obj_t zephyr_i2c_i2c_obj_deinit(mp_obj_t self_in) { + zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); + common_hal_zephyr_i2c_i2c_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c_deinit_obj, zephyr_i2c_i2c_obj_deinit); + +//| def __enter__(self) -> I2C: +//| """No-op used in Context Managers.""" +//| ... +static mp_obj_t zephyr_i2c_i2c_obj___enter__(mp_obj_t self_in) { + zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); + check_for_deinit(self); + return self_in; +} +static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c___enter___obj, zephyr_i2c_i2c_obj___enter__); + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware on context exit.""" +//| ... +static mp_obj_t zephyr_i2c_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_zephyr_i2c_i2c_deinit(args[0]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(zephyr_i2c_i2c___exit___obj, 4, 4, zephyr_i2c_i2c_obj___exit__); + +//| def probe(self, address: int) -> bool: +//| """Check if a device responds at the address. +//| +//| :param int address: The 7-bit device address +//| :return: True if the device responds, False otherwise +//| :rtype: bool +//| """ +//| ... +static mp_obj_t zephyr_i2c_i2c_probe(mp_obj_t self_in, mp_obj_t addr_obj) { + zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); + check_for_deinit(self); + check_lock(self); + + mp_int_t addr = mp_obj_get_int(addr_obj); + return mp_obj_new_bool(common_hal_zephyr_i2c_i2c_probe(self, addr)); +} +static MP_DEFINE_CONST_FUN_OBJ_2(zephyr_i2c_i2c_probe_obj, zephyr_i2c_i2c_probe); + +//| def scan(self) -> List[int]: +//| """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a +//| list of those that respond. +//| +//| :return: List of device addresses +//| :rtype: list +//| """ +//| ... +static mp_obj_t zephyr_i2c_i2c_scan(mp_obj_t self_in) { + zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); + check_for_deinit(self); + check_lock(self); + + mp_obj_t list = mp_obj_new_list(0, NULL); + // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved + for (uint8_t addr = 0x08; addr <= 0x77; addr++) { + if (common_hal_zephyr_i2c_i2c_probe(self, addr)) { + mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); + } + } + return list; +} +static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c_scan_obj, zephyr_i2c_i2c_scan); + +//| def try_lock(self) -> bool: +//| """Attempts to grab the I2C lock. Returns True on success. +//| +//| :return: True when lock has been grabbed +//| :rtype: bool +//| """ +//| ... +static mp_obj_t zephyr_i2c_i2c_obj_try_lock(mp_obj_t self_in) { + zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_zephyr_i2c_i2c_try_lock(self)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c_try_lock_obj, zephyr_i2c_i2c_obj_try_lock); + +//| def unlock(self) -> None: +//| """Releases the I2C lock.""" +//| ... +static mp_obj_t zephyr_i2c_i2c_obj_unlock(mp_obj_t self_in) { + zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); + check_for_deinit(self); + common_hal_zephyr_i2c_i2c_unlock(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c_unlock_obj, zephyr_i2c_i2c_obj_unlock); + +//| import sys +//| +//| def readfrom_into( +//| self, address: int, buffer: WriteableBuffer, *, start: int = 0, end: int = sys.maxsize +//| ) -> None: +//| """Read into ``buffer`` from the device selected by ``address``. +//| At least one byte must be read. +//| +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]`` were passed, but without copying the data. +//| The number of bytes read will be the length of ``buffer[start:end]``. +//| +//| :param int address: 7-bit device address +//| :param ~circuitpython_typing.WriteableBuffer buffer: buffer to write into +//| :param int start: beginning of buffer slice +//| :param int end: end of buffer slice; if not specified, use ``len(buffer)`` +//| """ +//| ... +static mp_obj_t zephyr_i2c_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address, ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + zephyr_i2c_i2c_obj_t *self = native_i2c(pos_args[0]); + check_for_deinit(self); + check_lock(self); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + + // Compute bounds in terms of elements, not bytes. + int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); + size_t length = bufinfo.len / stride_in_bytes; + int32_t start = args[ARG_start].u_int; + const int32_t end = args[ARG_end].u_int; + normalize_buffer_bounds(&start, end, &length); + mp_arg_validate_length_min(length, 1, MP_QSTR_buffer); + + // Treat start and length in terms of bytes from now on. + start *= stride_in_bytes; + length *= stride_in_bytes; + + uint8_t status = common_hal_zephyr_i2c_i2c_read(self, args[ARG_address].u_int, + ((uint8_t *)bufinfo.buf) + start, length); + + if (status != 0) { + mp_raise_OSError(status); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_i2c_i2c_readfrom_into_obj, 3, zephyr_i2c_i2c_readfrom_into); + +//| import sys +//| +//| def writeto( +//| self, address: int, buffer: ReadableBuffer, *, start: int = 0, end: int = sys.maxsize +//| ) -> None: +//| """Write the bytes from ``buffer`` to the device selected by ``address`` and +//| then transmit a stop bit. +//| +//| If ``start`` or ``end`` is provided, then the buffer will be sliced +//| as if ``buffer[start:end]`` were passed, but without copying the data. +//| The number of bytes written will be the length of ``buffer[start:end]``. +//| +//| Writing a buffer or slice of length zero is permitted, as it can be used +//| to poll for the existence of a device. +//| +//| :param int address: 7-bit device address +//| :param ~circuitpython_typing.ReadableBuffer buffer: buffer containing the bytes to write +//| :param int start: beginning of buffer slice +//| :param int end: end of buffer slice; if not specified, use ``len(buffer)`` +//| """ +//| ... +static mp_obj_t zephyr_i2c_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address, ARG_buffer, ARG_start, ARG_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + zephyr_i2c_i2c_obj_t *self = native_i2c(pos_args[0]); + check_for_deinit(self); + check_lock(self); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // get the buffer to write the data from + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); + int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); + + // Compute bounds in terms of elements, not bytes. + size_t length = bufinfo.len / stride_in_bytes; + int32_t start = args[ARG_start].u_int; + const int32_t end = args[ARG_end].u_int; + normalize_buffer_bounds(&start, end, &length); + + // Treat start and length in terms of bytes from now on. + start *= stride_in_bytes; + length *= stride_in_bytes; + + uint8_t status = common_hal_zephyr_i2c_i2c_write(self, args[ARG_address].u_int, + ((uint8_t *)bufinfo.buf) + start, length); + + if (status != 0) { + mp_raise_OSError(status); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_i2c_i2c_writeto_obj, 3, zephyr_i2c_i2c_writeto); + +//| import sys +//| +//| def writeto_then_readfrom( +//| self, +//| address: int, +//| out_buffer: ReadableBuffer, +//| in_buffer: WriteableBuffer, +//| *, +//| out_start: int = 0, +//| out_end: int = None, +//| in_start: int = 0, +//| in_end: int = None +//| ) -> None: +//| """Write the bytes from ``out_buffer`` to the device selected by ``address``, generate +//| no stop bit, generate a repeated start and read into ``in_buffer``. ``out_buffer`` and +//| ``in_buffer`` can be the same buffer because they are used sequentially. +//| +//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced +//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data. +//| The number of bytes written will be the length of ``out_buffer[start:end]``. +//| +//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced +//| as if ``in_buffer[in_start:in_end]`` were passed, +//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``. +//| +//| :param int address: 7-bit device address +//| :param ~circuitpython_typing.ReadableBuffer out_buffer: buffer containing the bytes to write +//| :param ~circuitpython_typing.WriteableBuffer in_buffer: buffer to write into +//| :param int out_start: beginning of ``out_buffer`` slice +//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)`` +//| :param int in_start: beginning of ``in_buffer`` slice +//| :param int in_end: end of ``in_buffer`` slice; if not specified, use ``len(in_buffer)`` +//| """ +//| ... +static mp_obj_t zephyr_i2c_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_address, ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, + }; + zephyr_i2c_i2c_obj_t *self = native_i2c(pos_args[0]); + check_for_deinit(self); + check_lock(self); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_buffer_info_t out_bufinfo; + mp_get_buffer_raise(args[ARG_out_buffer].u_obj, &out_bufinfo, MP_BUFFER_READ); + int out_stride_in_bytes = mp_binary_get_size('@', out_bufinfo.typecode, NULL); + size_t out_length = out_bufinfo.len / out_stride_in_bytes; + int32_t out_start = args[ARG_out_start].u_int; + const int32_t out_end = args[ARG_out_end].u_int; + normalize_buffer_bounds(&out_start, out_end, &out_length); + + mp_buffer_info_t in_bufinfo; + mp_get_buffer_raise(args[ARG_in_buffer].u_obj, &in_bufinfo, MP_BUFFER_WRITE); + int in_stride_in_bytes = mp_binary_get_size('@', in_bufinfo.typecode, NULL); + size_t in_length = in_bufinfo.len / in_stride_in_bytes; + int32_t in_start = args[ARG_in_start].u_int; + const int32_t in_end = args[ARG_in_end].u_int; + normalize_buffer_bounds(&in_start, in_end, &in_length); + mp_arg_validate_length_min(in_length, 1, MP_QSTR_out_buffer); + + // Treat start and length in terms of bytes from now on. + out_start *= out_stride_in_bytes; + out_length *= out_stride_in_bytes; + in_start *= in_stride_in_bytes; + in_length *= in_stride_in_bytes; + + uint8_t status = common_hal_zephyr_i2c_i2c_write_read(self, args[ARG_address].u_int, + ((uint8_t *)out_bufinfo.buf) + out_start, out_length, + ((uint8_t *)in_bufinfo.buf) + in_start, in_length); + + if (status != 0) { + mp_raise_OSError(status); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_i2c_i2c_writeto_then_readfrom_obj, 4, zephyr_i2c_i2c_writeto_then_readfrom); + +static const mp_rom_map_elem_t zephyr_i2c_i2c_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&zephyr_i2c_i2c_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&zephyr_i2c_i2c_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&zephyr_i2c_i2c___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&zephyr_i2c_i2c___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_probe), MP_ROM_PTR(&zephyr_i2c_i2c_probe_obj) }, + { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&zephyr_i2c_i2c_scan_obj) }, + + { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&zephyr_i2c_i2c_try_lock_obj) }, + { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&zephyr_i2c_i2c_unlock_obj) }, + + { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&zephyr_i2c_i2c_readfrom_into_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&zephyr_i2c_i2c_writeto_obj) }, + { MP_ROM_QSTR(MP_QSTR_writeto_then_readfrom), MP_ROM_PTR(&zephyr_i2c_i2c_writeto_then_readfrom_obj) }, +}; +static MP_DEFINE_CONST_DICT(zephyr_i2c_i2c_locals_dict, zephyr_i2c_i2c_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + zephyr_i2c_i2c_type, + MP_QSTR_I2C, + MP_TYPE_FLAG_NONE, + locals_dict, &zephyr_i2c_i2c_locals_dict + ); diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.h b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.h new file mode 100644 index 00000000000..7f7eecbea6c --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.h @@ -0,0 +1,32 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "common-hal/zephyr_i2c/I2C.h" + +extern const mp_obj_type_t zephyr_i2c_i2c_type; + +// Check if the I2C object has been deinitialized +bool common_hal_zephyr_i2c_i2c_deinited(zephyr_i2c_i2c_obj_t *self); + +// Deinitialize the I2C bus +void common_hal_zephyr_i2c_i2c_deinit(zephyr_i2c_i2c_obj_t *self); + +// Locking functions +bool common_hal_zephyr_i2c_i2c_try_lock(zephyr_i2c_i2c_obj_t *self); +bool common_hal_zephyr_i2c_i2c_has_lock(zephyr_i2c_i2c_obj_t *self); +void common_hal_zephyr_i2c_i2c_unlock(zephyr_i2c_i2c_obj_t *self); + +// Device communication functions +bool common_hal_zephyr_i2c_i2c_probe(zephyr_i2c_i2c_obj_t *self, uint8_t addr); +uint8_t common_hal_zephyr_i2c_i2c_write(zephyr_i2c_i2c_obj_t *self, uint16_t address, + const uint8_t *data, size_t len); +uint8_t common_hal_zephyr_i2c_i2c_read(zephyr_i2c_i2c_obj_t *self, uint16_t address, + uint8_t *data, size_t len); +uint8_t common_hal_zephyr_i2c_i2c_write_read(zephyr_i2c_i2c_obj_t *self, uint16_t address, + uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len); diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/__init__.c b/ports/zephyr-cp/bindings/zephyr_i2c/__init__.c new file mode 100644 index 00000000000..3274dfdb740 --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_i2c/__init__.c @@ -0,0 +1,27 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" +#include "bindings/zephyr_i2c/I2C.h" + +//| """Zephyr I2C driver for fixed I2C busses. +//| +//| This module provides access to I2C busses using Zephyr device labels.""" + +static const mp_rom_map_elem_t zephyr_i2c_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr_i2c) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&zephyr_i2c_i2c_type) }, +}; + +static MP_DEFINE_CONST_DICT(zephyr_i2c_module_globals, zephyr_i2c_module_globals_table); + +const mp_obj_module_t zephyr_i2c_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&zephyr_i2c_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_zephyr_i2c, zephyr_i2c_module); diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index b8df9fb87f5..bb400f188db 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -2,7 +2,9 @@ set(pca10056_BOARD_ALIAS nrf52840dk/nrf52840) set(renesas_ek_ra6m5_BOARD_ALIAS ek_ra6m5) set(renesas_ek_ra8d1_BOARD_ALIAS ek_ra8d1) set(nordic_nrf54l15dk_BOARD_ALIAS nrf54l15dk/nrf54l15/cpuapp) +set(nordic_nrf54h20dk_BOARD_ALIAS nrf54h20dk/nrf54h20/cpuapp) set(nordic_nrf5340dk_BOARD_ALIAS nrf5340dk/nrf5340/cpuapp) set(nordic_nrf7002dk_BOARD_ALIAS nrf7002dk/nrf5340/cpuapp) set(st_stm32h7b3i_dk_BOARD_ALIAS stm32h7b3i_dk) set(st_nucleo_u575zi_q_BOARD_ALIAS nucleo_u575zi_q/stm32u575xx) +set(st_nucleo_n657x0_q_BOARD_ALIAS nucleo_n657x0_q/stm32n657xx) diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 35966d6f9e2..c59e03c323e 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -110,6 +110,7 @@ vectorio = false warnings = false watchdog = false wifi = false +zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true +zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml new file mode 100644 index 00000000000..d4017cae4da --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -0,0 +1,116 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Nordic Semiconductor nRF54H20 DK" + +[modules] +__future__ = false +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = false +bitmaptools = false +bitops = false +board = false +busdisplay = false +busio = false +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = false +dotclockframebuffer = false +dualbank = false +epaperdisplay = false +floppyio = false +fontio = false +fourwire = false +framebufferio = false +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = false +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = false +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = false +sdioio = false +sharpdisplay = false +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = false +synthio = false +terminalio = false +tilepalettemapper = false +time = true +touchio = false +traceback = false +uheap = false +usb = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = false +warnings = false +watchdog = false +wifi = false +zephyr_i2c = true # Zephyr board has zephyr_i2c +zephyr_kernel = false +zephyr_serial = true # Zephyr board has zephyr_serial +zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml new file mode 100644 index 00000000000..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index e3b6cc2248f..dbffa5944d9 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -110,6 +110,7 @@ vectorio = false warnings = false watchdog = false wifi = false +zephyr_i2c = false zephyr_kernel = false -zephyr_serial = true +zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 328105d7150..7a3ea9267c9 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -110,6 +110,7 @@ vectorio = false warnings = false watchdog = false wifi = true # Zephyr board has wifi +zephyr_i2c = false zephyr_kernel = false -zephyr_serial = true +zephyr_serial = false zlib = false diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf new file mode 100644 index 00000000000..f7443ecfa33 --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -0,0 +1 @@ +CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE=4096 diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay new file mode 100644 index 00000000000..0d90c87931b --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -0,0 +1,45 @@ +&gpio6 { + status = "okay"; + zephyr,pm-device-runtime-auto; +}; + +&exmif { + status = "okay"; + zephyr,pm-device-runtime-auto; +}; + +&mx25uw63 { + status = "okay"; +}; + +/* + * SDA = P2.11 + * SCL = P2.10 + */ + +&pinctrl { + i2c130_default: i2c130_default { + group1 { + psels = , + ; + }; + }; + + i2c130_sleep: i2c130_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&i2c130 { + clock-frequency = ; + pinctrl-0 = <&i2c130_default>; + pinctrl-1 = <&i2c130_sleep>; + pinctrl-names = "default", "sleep"; + zephyr,concat-buf-size = <256>; + memory-regions = <&cpuapp_dma_region>; + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/nucleo_n657x0_q.overlay b/ports/zephyr-cp/boards/nucleo_n657x0_q.overlay new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 2bc6e3e03a2..8c522296da6 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -110,6 +110,7 @@ vectorio = false warnings = false watchdog = false wifi = false +zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true +zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 2a2e16fd16a..5c79b0e962e 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -110,6 +110,7 @@ vectorio = false warnings = false watchdog = false wifi = false +zephyr_i2c = false zephyr_kernel = false -zephyr_serial = true +zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml new file mode 100644 index 00000000000..7a5beb79e44 --- /dev/null +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -0,0 +1,116 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "STMicroelectronics Nucleo N657X0-Q" + +[modules] +__future__ = false +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = false +bitmaptools = false +bitops = false +board = false +busdisplay = false +busio = false +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = false +dotclockframebuffer = false +dualbank = false +epaperdisplay = false +floppyio = false +fontio = false +fourwire = false +framebufferio = false +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = false +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = false +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = false +sdioio = false +sharpdisplay = false +socketpool = false +spitarget = false +ssl = false +storage = false +struct = true +supervisor = false +synthio = false +terminalio = false +tilepalettemapper = false +time = true +touchio = false +traceback = false +uheap = false +usb = false +usb_cdc = false # No TinyUSB settings for stm32n657xx +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = false +warnings = false +watchdog = false +wifi = false +zephyr_i2c = true # Zephyr board has zephyr_i2c +zephyr_kernel = false +zephyr_serial = true # Zephyr board has zephyr_serial +zlib = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml new file mode 100644 index 00000000000..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 5042eb972b1..a3183f180ae 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -110,6 +110,7 @@ vectorio = false warnings = false watchdog = false wifi = false +zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true +zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index cfe48a90cee..bf6a2828743 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -110,6 +110,7 @@ vectorio = false warnings = false watchdog = false wifi = false +zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true +zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c b/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c index d5bb0d44669..12ce95c282d 100644 --- a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c +++ b/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c @@ -1,92 +1,134 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries -// SPDX-FileCopyrightText: Copyright (c) 2018 Artur Pacholec -// SPDX-FileCopyrightText: Copyright (c) 2017 hathach -// SPDX-FileCopyrightText: Copyright (c) 2016 Sandeep Mistry All right reserved. +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT -#include "shared-bindings/busio/I2C.h" -#include "shared-bindings/microcontroller/__init__.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "supervisor/shared/tick.h" +#include "bindings/zephyr_i2c/I2C.h" #include "py/mperrno.h" #include "py/runtime.h" +#include +#include +#include -void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { - // never_reset_pin_number(self->scl_pin_number); - // never_reset_pin_number(self->sda_pin_number); +mp_obj_t zephyr_i2c_i2c_zephyr_init(zephyr_i2c_i2c_obj_t *self, const struct device *i2c_device) { + self->base.type = &zephyr_i2c_i2c_type; + self->i2c_device = i2c_device; + k_mutex_init(&self->mutex); + return MP_OBJ_FROM_PTR(self); } -void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint32_t frequency, uint32_t timeout) { - -} - -bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { - // return self->sda_pin_number == NO_PIN; - return true; +bool common_hal_zephyr_i2c_i2c_deinited(zephyr_i2c_i2c_obj_t *self) { + // Always leave it active + return false; } -void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { - if (common_hal_busio_i2c_deinited(self)) { +void common_hal_zephyr_i2c_i2c_deinit(zephyr_i2c_i2c_obj_t *self) { + if (common_hal_zephyr_i2c_i2c_deinited(self)) { return; } - - // nrfx_twim_uninit(&self->twim_peripheral->twim); - - // reset_pin_number(self->sda_pin_number); - // reset_pin_number(self->scl_pin_number); - - // self->twim_peripheral->in_use = false; - // common_hal_busio_i2c_mark_deinit(self); -} - -void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { - // self->sda_pin_number = NO_PIN; + // Always leave it active } -// nrfx_twim_tx doesn't support 0-length data so we fall back to the hal API -bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { - bool found = true; +bool common_hal_zephyr_i2c_i2c_probe(zephyr_i2c_i2c_obj_t *self, uint8_t addr) { + if (common_hal_zephyr_i2c_i2c_deinited(self)) { + return false; + } - return found; + // Try a zero-length write to probe for device + uint8_t dummy; + int ret = i2c_write(self->i2c_device, &dummy, 0, addr); + return ret == 0; } -bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { - if (common_hal_busio_i2c_deinited(self)) { +bool common_hal_zephyr_i2c_i2c_try_lock(zephyr_i2c_i2c_obj_t *self) { + if (common_hal_zephyr_i2c_i2c_deinited(self)) { return false; } - bool grabbed_lock = false; - return grabbed_lock; + + self->has_lock = k_mutex_lock(&self->mutex, K_NO_WAIT) == 0; + return self->has_lock; } -bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { +bool common_hal_zephyr_i2c_i2c_has_lock(zephyr_i2c_i2c_obj_t *self) { return self->has_lock; } -void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { - self->has_lock = false; +void common_hal_zephyr_i2c_i2c_unlock(zephyr_i2c_i2c_obj_t *self) { + k_mutex_unlock(&self->mutex); } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { +uint8_t common_hal_zephyr_i2c_i2c_write(zephyr_i2c_i2c_obj_t *self, uint16_t addr, + const uint8_t *data, size_t len) { + + if (common_hal_zephyr_i2c_i2c_deinited(self)) { + return MP_EIO; + } + + int ret = i2c_write(self->i2c_device, data, len, addr); + if (ret != 0) { + // Map Zephyr error codes to errno + if (ret == -ENOTSUP) { + return MP_EOPNOTSUPP; + } else if (ret == -EIO || ret == -ENXIO) { + return MP_EIO; + } else if (ret == -EBUSY) { + return MP_EBUSY; + } + return MP_EIO; + } + return 0; } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { +uint8_t common_hal_zephyr_i2c_i2c_read(zephyr_i2c_i2c_obj_t *self, uint16_t addr, + uint8_t *data, size_t len) { + + if (common_hal_zephyr_i2c_i2c_deinited(self)) { + return MP_EIO; + } + if (len == 0) { return 0; } + int ret = i2c_read(self->i2c_device, data, len, addr); + if (ret != 0) { + // Map Zephyr error codes to errno + if (ret == -ENOTSUP) { + return MP_EOPNOTSUPP; + } else if (ret == -EIO || ret == -ENXIO) { + return MP_EIO; + } else if (ret == -EBUSY) { + return MP_EBUSY; + } + return MP_EIO; + } + + return 0; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +uint8_t common_hal_zephyr_i2c_i2c_write_read(zephyr_i2c_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); - if (result != 0) { - return result; + + if (common_hal_zephyr_i2c_i2c_deinited(self)) { + return MP_EIO; } - return common_hal_busio_i2c_read(self, addr, in_data, in_len); + // Use i2c_write_read for combined transaction with repeated start + int ret = i2c_write_read(self->i2c_device, addr, out_data, out_len, in_data, in_len); + if (ret != 0) { + // Map Zephyr error codes to errno + if (ret == -ENOTSUP) { + return MP_EOPNOTSUPP; + } else if (ret == -EIO || ret == -ENXIO) { + return MP_EIO; + } else if (ret == -EBUSY) { + return MP_EBUSY; + } + return MP_EIO; + } + + return 0; } diff --git a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h b/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h index 22e9251b3f1..0265511e208 100644 --- a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h +++ b/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h @@ -1,17 +1,19 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT #pragma once #include "py/obj.h" +#include typedef struct { mp_obj_base_t base; - // twim_peripheral_t *twim_peripheral; + const struct device *i2c_device; + struct k_mutex mutex; bool has_lock; - uint8_t scl_pin_number; - uint8_t sda_pin_number; -} busio_i2c_obj_t; +} zephyr_i2c_i2c_obj_t; + +mp_obj_t zephyr_i2c_i2c_zephyr_init(zephyr_i2c_i2c_obj_t *self, const struct device *i2c_device); diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/UART.c b/ports/zephyr-cp/common-hal/zephyr_serial/UART.c index fcc05c22f1a..55e9c424ffe 100644 --- a/ports/zephyr-cp/common-hal/zephyr_serial/UART.c +++ b/ports/zephyr-cp/common-hal/zephyr_serial/UART.c @@ -74,6 +74,12 @@ void zephyr_serial_uart_construct(zephyr_serial_uart_obj_t *self, const struct d uart_irq_rx_enable(uart_device); } +mp_obj_t zephyr_serial_uart_zephyr_init(zephyr_serial_uart_obj_t *self, const struct device *uart_device) { + self->base.type = &zephyr_serial_uart_type; + zephyr_serial_uart_construct(self, uart_device, 128, NULL); + return MP_OBJ_FROM_PTR(self); +} + bool zephyr_serial_uart_deinited(zephyr_serial_uart_obj_t *self) { return !device_is_ready(self->uart_device); } diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/UART.h b/ports/zephyr-cp/common-hal/zephyr_serial/UART.h index 4e220ee6307..eb3cdd746c7 100644 --- a/ports/zephyr-cp/common-hal/zephyr_serial/UART.h +++ b/ports/zephyr-cp/common-hal/zephyr_serial/UART.h @@ -20,3 +20,5 @@ typedef struct { bool rx_paused; // set by irq if no space in rbuf } zephyr_serial_uart_obj_t; + +mp_obj_t zephyr_serial_uart_zephyr_init(zephyr_serial_uart_obj_t *self, const struct device *uart_device); diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index fd1ca7dc43f..abb1969470a 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -51,7 +51,6 @@ "json", "random", "digitalio", - "zephyr_serial", ] MPCONFIG_FLAGS = ["ulab", "nvm", "displayio", "warnings", "alarm", "array", "json"] @@ -254,7 +253,9 @@ async def build_circuitpython(): ) ) - board_autogen_task = tg.create_task(zephyr_dts_to_cp_board(builddir, zephyrbuilddir)) + board_autogen_task = tg.create_task( + zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir) + ) board_info = board_autogen_task.result() mpconfigboard_fn = board_tools.find_mpconfigboard(portdir, board) mpconfigboard = { @@ -290,6 +291,12 @@ async def build_circuitpython(): module_reasons["socketpool"] = "Zephyr networking enabled" module_reasons["ssl"] = "Zephyr networking enabled" + for port_module in (portdir / "bindings").iterdir(): + if not board_info.get(port_module.name, False): + continue + enabled_modules.add(port_module.name) + module_reasons[port_module.name] = f"Zephyr board has {port_module.name}" + circuitpython_flags.extend(board_info["cflags"]) supervisor_source = [ "main.c", @@ -301,6 +308,7 @@ async def build_circuitpython(): portdir / "common-hal/microcontroller/Processor.c", portdir / "common-hal/os/__init__.c", "shared/readline/readline.c", + "shared/runtime/buffer_helper.c", "shared/runtime/context_manager_helpers.c", "shared/runtime/pyexec.c", "shared/runtime/interrupt_char.c", diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 071334161b9..9d238a03bd8 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -7,12 +7,18 @@ from devicetree import dtlib logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) # GPIO flags defined here: include/zephyr/dt-bindings/gpio/gpio.h GPIO_ACTIVE_LOW = 1 << 0 +MINIMUM_RAM_SIZE = 1024 + MANUAL_COMPAT_TO_DRIVER = { "renesas_ra_nv_flash": "flash", + "nordic_nrf_uarte": "serial", + "nordic_nrf_uart": "serial", + "nordic_nrf_twim": "i2c", } # These are controllers, not the flash devices themselves. @@ -22,6 +28,8 @@ "nordic,nrf-spim", ) +DRIVER_CLASSES = {"serial": "UART", "i2c": "I2C", "spi": "SPI"} + CONNECTORS = { "mikro-bus": [ "AN", @@ -104,6 +112,22 @@ "GPIO0", "GPIO1", ], + "raspberrypi,csi-connector": [ + "CSI_D0_N", + "CSI_D0_P", + "CSI_D1_N", + "CSI_D1_P", + "CSI_CK_N", + "CSI_CK_P", + "CSI_D2_N", + "CSI_D2_P", + "CSI_D3_N", + "CSI_D3_P", + "IO0", + "IO1", + "I2C_SCL", + "I2C_SDA", + ], "renesas,ra-gpio-mipi-header": [ "IIC_SDA", "DISP_BLEN", @@ -167,9 +191,11 @@ ], } +EXCEPTIONAL_DRIVERS = ["entropy", "gpio", "led"] + @cpbuild.run_in_thread -def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 +def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 board_dir = builddir / "board" # Auto generate board files from device tree. @@ -218,6 +244,9 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 status_led_inverted = False path2chosen = {} chosen2path = {} + + # Store active Zephyr device labels per-driver so that we can make them available via board. + active_zephyr_devices = {} usb_num_endpoint_pairs = 0 for k in edt_pickle.root.nodes["chosen"].props: value = edt_pickle.root.nodes["chosen"].props[k] @@ -238,16 +267,20 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 compatible = [] if "compatible" in node.props: compatible = node.props["compatible"].to_strings() - logger.debug(node.name, status) + logger.debug(f"{node.name}: {status}") + logger.debug(f"compatible: {compatible}") chosen = None if node in path2chosen: chosen = path2chosen[node] - logger.debug(" chosen:", chosen) + logger.debug(f" chosen: {chosen}") + if not compatible and chosen == "zephyr,sram": + # The designated sram region may not have any compatible properties, + # so we assume it is compatible with mmio + compatible.append("mmio") for c in compatible: underscored = c.replace(",", "_").replace("-", "_") driver = COMPAT_TO_DRIVER.get(underscored, None) if "mmio" in c: - logger.debug(" ", c, node.labels, node.props) address, size = node.props["reg"].to_nums() end = address + size if chosen == "zephyr,sram": @@ -270,20 +303,21 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 info = (node.labels[0], start, end, size, node.path) if chosen == "zephyr,sram": rams.insert(0, info) - else: + elif status == "okay" and size > MINIMUM_RAM_SIZE: + logger.debug(f"Adding RAM info: {info}") rams.append(info) if not driver: driver = MANUAL_COMPAT_TO_DRIVER.get(underscored, None) - logger.debug(" ", underscored, driver) - if not driver: + logger.debug(f" {c} -> {underscored} -> {driver}") + if not driver or status != "okay": continue - if driver == "flash" and status == "okay": + if driver == "flash": if not chosen and compatible[0] not in BLOCKED_FLASH_COMPAT: # Skip chosen nodes because they are used by Zephyr. flashes.append(f"DEVICE_DT_GET(DT_NODELABEL({node.labels[0]}))") else: logger.debug(" skipping due to blocked compat") - if driver == "usb/udc" and status == "okay": + elif driver == "usb/udc": board_info["usb_device"] = True props = node.props if "num-bidir-endpoints" not in props: @@ -297,8 +331,18 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 single_direction_endpoints.append(props[eps].to_num() if eps in props else 0) # Count separate in/out pairs as bidirectional. usb_num_endpoint_pairs += min(single_direction_endpoints) - if driver.startswith("wifi") and status == "okay": + elif driver.startswith("wifi"): board_info["wifi"] = True + elif driver in EXCEPTIONAL_DRIVERS: + pass + elif (portdir / f"bindings/zephyr_{driver}").exists(): + board_info[f"zephyr_{driver}"] = True + logger.info(f"Supported driver: {driver}") + if driver not in active_zephyr_devices: + active_zephyr_devices[driver] = [] + active_zephyr_devices[driver].append(node.labels) + else: + logger.warning(f"Unsupported driver: {driver}") if gpio: if "ngpios" in node.props: @@ -391,6 +435,58 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 board_pin_mapping = "\n ".join(board_pin_mapping) mcu_pin_mapping = "\n ".join(mcu_pin_mapping) + zephyr_binding_headers = [] + zephyr_binding_objects = [] + zephyr_binding_labels = [] + for driver, instances in active_zephyr_devices.items(): + driverclass = DRIVER_CLASSES[driver] + zephyr_binding_headers.append(f'#include "bindings/zephyr_{driver}/{driverclass}.h"') + + # Designate a main bus such as board.I2C. + if len(instances) == 1: + instances[0].append(driverclass) + else: + # Check to see if a main bus has already been designated + found_main = False + for labels in instances: + for label in labels: + if label == driverclass: + found_main = True + if not found_main: + for priority_label in ("zephyr_i2c", "arduino_i2c"): + for labels in instances: + if priority_label in labels: + labels.append(driverclass) + found_main = True + break + if found_main: + break + for labels in instances: + instance_name = f"{driver}_{labels[0]}" + c_function_name = f"_{instance_name}" + singleton_ptr = f"{c_function_name}_singleton" + function_object = f"{c_function_name}_obj" + binding_prefix = f"zephyr_{driver}_{driverclass.lower()}" + zephyr_binding_objects.append( + f"""static {binding_prefix}_obj_t {instance_name}_obj; +static mp_obj_t {singleton_ptr} = mp_const_none; +static mp_obj_t {c_function_name}(void) {{ + if ({singleton_ptr} != mp_const_none) {{ + return {singleton_ptr}; + }} + {singleton_ptr} = {binding_prefix}_zephyr_init(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]}))); + return {singleton_ptr}; +}} +static MP_DEFINE_CONST_FUN_OBJ_0({function_object}, {c_function_name});""" + ) + for label in labels: + zephyr_binding_labels.append( + f"{{ MP_ROM_QSTR(MP_QSTR_{label.upper()}), MP_ROM_PTR(&{function_object}) }}," + ) + zephyr_binding_headers = "\n".join(zephyr_binding_headers) + zephyr_binding_objects = "\n".join(zephyr_binding_objects) + zephyr_binding_labels = "\n".join(zephyr_binding_labels) + board_dir.mkdir(exist_ok=True, parents=True) header = board_dir / "mpconfigboard.h" if status_led: @@ -442,6 +538,8 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 #include "py/obj.h" #include "py/mphal.h" +{zephyr_binding_headers} + const struct device* const flashes[] = {{ {", ".join(flashes)} }}; const int circuitpy_flash_device_count = {len(flashes)}; @@ -453,6 +551,8 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 {pin_defs} +{zephyr_binding_objects} + static const mp_rom_map_elem_t mcu_pin_globals_table[] = {{ {mcu_pin_mapping} }}; @@ -463,7 +563,8 @@ def zephyr_dts_to_cp_board(builddir, zephyrbuilddir): # noqa: C901 {board_pin_mapping} -// {{ MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }}, +{zephyr_binding_labels} + }}; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index bd693bb897e..8651b2715cc 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -26,3 +26,5 @@ CONFIG_ASSERT=y CONFIG_LOG_BLOCK_IN_THREAD=y CONFIG_EVENTS=y + +CONFIG_I2C=y diff --git a/ports/zephyr-cp/supervisor/flash.c b/ports/zephyr-cp/supervisor/flash.c index 6b893f89abe..8daef5fcdaa 100644 --- a/ports/zephyr-cp/supervisor/flash.c +++ b/ports/zephyr-cp/supervisor/flash.c @@ -111,6 +111,10 @@ void supervisor_flash_init(void) { const struct device *d = flashes[i]; printk("flash %p %s\n", d, d->name); + if (!device_is_ready(d)) { + printk(" not ready\n"); + continue; + } if (covered_by_areas[i]) { printk(" covered by flash area\n"); continue; From 46408592cd6432b122bf66cfd099201b0fe4ca34 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 3 Dec 2025 16:07:38 -0800 Subject: [PATCH 104/876] Allow swapping LSFS USB on ESP32-P4 to USB OTG This allows full USB device on the M5Stack Tab5. Improves #10666 --- lib/tinyusb | 2 +- .../analog/boards/apard32690/mpconfigboard.mk | 1 - .../boards/max32690evkit/mpconfigboard.mk | 1 - ports/analog/mpconfigport.h | 2 + ports/broadcom/mpconfigport.h | 2 + ports/broadcom/mpconfigport.mk | 1 - ports/cxd56/mpconfigport.h | 2 + ports/cxd56/mpconfigport.mk | 2 - .../boards/m5stack_tab5/mpconfigboard.h | 3 +- .../common-hal/microcontroller/Pin.c | 15 +++++ ports/espressif/mpconfigport.h | 12 ++++ ports/espressif/mpconfigport.mk | 1 - ports/espressif/supervisor/usb.c | 59 ++++++++++++++++++- ports/mimxrt10xx/mpconfigport.h | 2 + ports/mimxrt10xx/mpconfigport.mk | 2 - py/circuitpy_mpconfig.h | 8 +++ shared-module/usb_cdc/__init__.c | 6 +- shared-module/usb_midi/__init__.c | 4 +- supervisor/shared/usb/tusb_config.h | 32 +++++----- supervisor/shared/usb/usb_msc_flash.c | 4 +- supervisor/supervisor.mk | 3 - 21 files changed, 123 insertions(+), 41 deletions(-) diff --git a/lib/tinyusb b/lib/tinyusb index c1bf19ed6cf..3af1bec1a91 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit c1bf19ed6cf1eaa791f221c1bc5ce4b3d069f76d +Subproject commit 3af1bec1a9161ee8dec29487831f7ac7ade9e189 diff --git a/ports/analog/boards/apard32690/mpconfigboard.mk b/ports/analog/boards/apard32690/mpconfigboard.mk index 7cc54ccfc6d..0e62f25f3f8 100644 --- a/ports/analog/boards/apard32690/mpconfigboard.mk +++ b/ports/analog/boards/apard32690/mpconfigboard.mk @@ -19,7 +19,6 @@ USB_VID=0x0456 USB_PID=0x003C USB_MANUFACTURER="Analog Devices, Inc." USB_PRODUCT="MAX32690 APARD" -USB_HIGHSPEED=1 # NOTE: MAX32 devices do not support IN/OUT pairs on the same EP USB_NUM_ENDPOINT_PAIRS=12 diff --git a/ports/analog/boards/max32690evkit/mpconfigboard.mk b/ports/analog/boards/max32690evkit/mpconfigboard.mk index 61413216d81..a97bc9ddacd 100644 --- a/ports/analog/boards/max32690evkit/mpconfigboard.mk +++ b/ports/analog/boards/max32690evkit/mpconfigboard.mk @@ -19,7 +19,6 @@ USB_VID=0x0456 USB_PID=0x003D USB_MANUFACTURER="Analog Devices, Inc." USB_PRODUCT="MAX32690 EvKit" -USB_HIGHSPEED=1 # NOTE: MAX32 devices do not support IN/OUT pairs on the same EP USB_NUM_ENDPOINT_PAIRS=12 diff --git a/ports/analog/mpconfigport.h b/ports/analog/mpconfigport.h index c4b3ee031ca..3296661fca7 100644 --- a/ports/analog/mpconfigport.h +++ b/ports/analog/mpconfigport.h @@ -12,6 +12,8 @@ // 24KiB stack #define CIRCUITPY_DEFAULT_STACK_SIZE 0x6000 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + // Also includes mpconfigboard.h #include "py/circuitpy_mpconfig.h" diff --git a/ports/broadcom/mpconfigport.h b/ports/broadcom/mpconfigport.h index 8b749ca0310..73fae8295de 100644 --- a/ports/broadcom/mpconfigport.h +++ b/ports/broadcom/mpconfigport.h @@ -26,6 +26,8 @@ #define MICROPY_FATFS_EXFAT (1) #define MICROPY_FATFS_MKFS_FAT32 (1) +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + //////////////////////////////////////////////////////////////////////////////////////////////////// // This also includes mpconfigboard.h. diff --git a/ports/broadcom/mpconfigport.mk b/ports/broadcom/mpconfigport.mk index d906b5d2aa4..844794b107a 100644 --- a/ports/broadcom/mpconfigport.mk +++ b/ports/broadcom/mpconfigport.mk @@ -22,7 +22,6 @@ CIRCUITPY_VIDEOCORE = 1 INTERNAL_FLASH_FILESYSTEM = 1 USB_NUM_ENDPOINT_PAIRS = 8 -USB_HIGHSPEED = 1 CIRCUITPY_BUILD_EXTENSIONS ?= disk.img.zip,kernel8.img diff --git a/ports/cxd56/mpconfigport.h b/ports/cxd56/mpconfigport.h index f0a57248beb..ec606a76547 100644 --- a/ports/cxd56/mpconfigport.h +++ b/ports/cxd56/mpconfigport.h @@ -23,6 +23,8 @@ #define USB_MSC_EP_NUM_OUT (5) #define USB_MSC_EP_NUM_IN (4) +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + #include "py/circuitpy_mpconfig.h" #define MICROPY_BYTES_PER_GC_BLOCK (32) diff --git a/ports/cxd56/mpconfigport.mk b/ports/cxd56/mpconfigport.mk index cb54233a07e..ebfaa91f251 100644 --- a/ports/cxd56/mpconfigport.mk +++ b/ports/cxd56/mpconfigport.mk @@ -1,5 +1,3 @@ -USB_HIGHSPEED = 1 - # Number of USB endpoint pairs. USB_NUM_ENDPOINT_PAIRS = 6 diff --git a/ports/espressif/boards/m5stack_tab5/mpconfigboard.h b/ports/espressif/boards/m5stack_tab5/mpconfigboard.h index f85f1fe24b8..6c748e93ecd 100644 --- a/ports/espressif/boards/m5stack_tab5/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_tab5/mpconfigboard.h @@ -25,4 +25,5 @@ #define DEFAULT_SPI_BUS_MISO (&pin_GPIO19) // Use the second USB device (numbered 0 and 1) -#define CIRCUITPY_USB_DEVICE_INSTANCE 1 +#define CIRCUITPY_USB_DEVICE_INSTANCE 0 +#define CIRCUITPY_ESP32P4_SWAP_LSFS (1) diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index 3ccd8dcbb69..dc4e4bb032e 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -211,11 +211,26 @@ static const uint64_t pin_mask_reset_forbidden = GPIO_SEL_32 | GPIO_SEL_33 | GPIO_SEL_34 | + // USB is on the FS OTG + #if CIRCUITPY_USB_DEVICE_INSTANCE == 0 + #if CIRCUITPY_ESP32P4_SWAP_LSFS == 1 + // We leave 24 and 25 alone in addition to 26 and 27 when swapped. It doesn't work otherwise. (Not sure why.) + GPIO_SEL_24 | // USB D- + GPIO_SEL_25 | // USB D+ + #endif + GPIO_SEL_26 | // USB D- + GPIO_SEL_27 | // USB D+ + #endif #if CIRCUITPY_ESP_USB_SERIAL_JTAG || (defined(CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) && CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG) // Never ever reset serial/JTAG communication pins. + #if CIRCUITPY_ESP32P4_SWAP_LSFS == 1 + GPIO_SEL_26 | // USB D- + GPIO_SEL_27 | // USB D+ + #else GPIO_SEL_24 | // USB D- GPIO_SEL_25 | // USB D+ #endif + #endif #if defined(CONFIG_ESP_CONSOLE_UART_DEFAULT) && CONFIG_ESP_CONSOLE_UART_DEFAULT && CONFIG_ESP_CONSOLE_UART_NUM == 0 // Never reset debug UART/console pins. GPIO_SEL_37 | diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 031676cf4d8..6b85100608c 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -68,3 +68,15 @@ extern portMUX_TYPE background_task_mutex; #ifndef CIRCUITPY_WIFI_DEFAULT_TX_POWER #define CIRCUITPY_WIFI_DEFAULT_TX_POWER (20) #endif + +#ifndef CIRCUITPY_USB_DEVICE_HIGH_SPEED +#if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 1 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) +#else +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (0) +#endif +#endif + +#ifndef CIRCUITPY_ESP32P4_SWAP_LSFS +#define CIRCUITPY_ESP32P4_SWAP_LSFS (0) +#endif diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index c3585c7e399..a967b8a4f15 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -290,7 +290,6 @@ CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # Second stage bootloader doesn't work when the factory partition is empty due to # UF2 missing. UF2_BOOTLOADER = 0 -USB_HIGHSPEED = 1 CIRCUITPY_USB_HID = 0 CIRCUITPY_USB_MIDI = 0 CIRCUITPY_TUSB_MEM_ALIGN = 64 diff --git a/ports/espressif/supervisor/usb.c b/ports/espressif/supervisor/usb.c index 274542ef22a..327fada778f 100644 --- a/ports/espressif/supervisor/usb.c +++ b/ports/espressif/supervisor/usb.c @@ -2,6 +2,7 @@ // // SPDX-FileCopyrightText: Copyright (c) 2018 hathach for Adafruit Industries // SPDX-FileCopyrightText: Copyright (c) 2019 Lucian Copeland for Adafruit Industries +// SPDX-FileContributor: 2025 Nicolai Electronics // // SPDX-License-Identifier: MIT @@ -12,6 +13,7 @@ #include "shared/readline/readline.h" #include "hal/gpio_ll.h" +#include "hal/usb_serial_jtag_ll.h" #include "esp_err.h" #include "esp_private/usb_phy.h" @@ -37,7 +39,7 @@ StackType_t usb_device_stack[USBD_STACK_SIZE]; StaticTask_t usb_device_taskdef; -static usb_phy_handle_t phy_hdl; +static usb_phy_handle_t device_phy_hdl; // USB Device Driver task // This top level thread process all usb events and invoke callbacks @@ -62,13 +64,64 @@ void init_usb_hardware(void) { usb_phy_config_t phy_conf = { .controller = USB_PHY_CTRL_OTG, .target = USB_PHY_TARGET_INT, + .otg_mode = USB_OTG_MODE_DEVICE, + #if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 0 + .otg_speed = USB_PHY_SPEED_FULL, + #else + // https://github.com/hathach/tinyusb/issues/2943#issuecomment-2601888322 + // Set speed to undefined (auto-detect) to avoid timing/race issue with S3 with host such as macOS + .otg_speed = USB_PHY_SPEED_UNDEFINED, + #endif + }; + usb_new_phy(&phy_conf, &device_phy_hdl); + + #if CIRCUITPY_ESP32P4_SWAP_LSFS == 1 + #ifndef CONFIG_IDF_TARGET_ESP32P4 + #error "LSFS swap is only supported on ESP32P4" + #endif + // Switch the USB PHY + const usb_serial_jtag_pull_override_vals_t override_disable_usb = { + .dm_pd = true, .dm_pu = false, .dp_pd = true, .dp_pu = false}; + const usb_serial_jtag_pull_override_vals_t override_enable_usb = { + .dm_pd = false, .dm_pu = false, .dp_pd = false, .dp_pu = true}; + + // Drop off the bus by removing the pull-up on USB DP + usb_serial_jtag_ll_phy_enable_pull_override(&override_disable_usb); + // Select USB mode by swapping and un-swapping the two PHYs + vTaskDelay(pdMS_TO_TICKS(500)); // Wait for disconnect before switching to device + usb_serial_jtag_ll_phy_select(1); + + // Put the device back onto the bus by re-enabling the pull-up on USB DP + usb_serial_jtag_ll_phy_enable_pull_override(&override_enable_usb); + usb_serial_jtag_ll_phy_disable_pull_override(); + #endif + + // Pin the USB task to the same core as CircuitPython. This way we leave + // the other core for networking. + (void)xTaskCreateStaticPinnedToCore(usb_device_task, + "usbd", + USBD_STACK_SIZE, + NULL, + 5, + usb_device_stack, + &usb_device_taskdef, + xPortGetCoreID()); + #endif + // Configure USB PHY + usb_phy_config_t phy_conf = { + .controller = USB_PHY_CTRL_OTG, + .target = USB_PHY_TARGET_INT, .otg_mode = USB_OTG_MODE_DEVICE, + #if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 0 + .otg_speed = USB_PHY_SPEED_FULL, + #else // https://github.com/hathach/tinyusb/issues/2943#issuecomment-2601888322 // Set speed to undefined (auto-detect) to avoid timing/race issue with S3 with host such as macOS - .otg_speed = USB_PHY_SPEED_UNDEFINED, + .otg_speed = USB_PHY_SPEED_UNDEFINED, + #endif }; - usb_new_phy(&phy_conf, &phy_hdl); + usb_new_phy(&phy_conf, &device_phy_hdl); // Pin the USB task to the same core as CircuitPython. This way we leave // the other core for networking. diff --git a/ports/mimxrt10xx/mpconfigport.h b/ports/mimxrt10xx/mpconfigport.h index 4d5e4e59700..df634dc7328 100644 --- a/ports/mimxrt10xx/mpconfigport.h +++ b/ports/mimxrt10xx/mpconfigport.h @@ -25,6 +25,8 @@ extern uint8_t _ld_default_stack_size; // are aligned to cache lines. #define MICROPY_BYTES_PER_GC_BLOCK (32) +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + #include "py/circuitpy_mpconfig.h" // TODO: diff --git a/ports/mimxrt10xx/mpconfigport.mk b/ports/mimxrt10xx/mpconfigport.mk index 20d802eb354..b3f078c7ecf 100644 --- a/ports/mimxrt10xx/mpconfigport.mk +++ b/ports/mimxrt10xx/mpconfigport.mk @@ -2,8 +2,6 @@ LD_FILE = $(FLASH).ld $(CHIP_FAMILY).ld imxrt10xx.ld INTERNAL_LIBM = 1 -USB_HIGHSPEED = 1 - # Number of USB endpoint pairs. USB_NUM_ENDPOINT_PAIRS = 8 # Align buffers on the cache boundary so we don't inadvertently load them early. diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 2754d57b01c..4acbf96db03 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -539,10 +539,18 @@ void background_callback_run_all(void); #define CIRCUITPY_USB_DEVICE_INSTANCE 0 #endif +#ifndef CIRCUITPY_USB_DEVICE_HIGH_SPEED +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED 0 +#endif + #ifndef CIRCUITPY_USB_HOST_INSTANCE #define CIRCUITPY_USB_HOST_INSTANCE -1 #endif +#ifndef CIRCUITPY_USB_HOST_HIGH_SPEED +#define CIRCUITPY_USB_HOST_HIGH_SPEED 0 +#endif + // If the port requires certain USB endpoint numbers, define these in mpconfigport.h. #ifndef USB_CDC_EP_NUM_NOTIFICATION diff --git a/shared-module/usb_cdc/__init__.c b/shared-module/usb_cdc/__init__.c index 9a9f158f28c..644c4ccae79 100644 --- a/shared-module/usb_cdc/__init__.c +++ b/shared-module/usb_cdc/__init__.c @@ -105,7 +105,7 @@ static const uint8_t usb_cdc_descriptor_template[] = { 0xFF, // 54 bEndpointAddress (OUT/H2D) [SET AT RUNTIME] #define CDC_DATA_OUT_ENDPOINT_INDEX 54 0x02, // 55 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 56,57 wMaxPacketSize 512 #else 0x40, 0x00, // 56,57 wMaxPacketSize 64 @@ -118,7 +118,7 @@ static const uint8_t usb_cdc_descriptor_template[] = { 0xFF, // 61 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number] #define CDC_DATA_IN_ENDPOINT_INDEX 61 0x02, // 62 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 63,64 wMaxPacketSize 512 #else 0x40, 0x00, // 63,64 wMaxPacketSize 64 @@ -326,7 +326,7 @@ static const uint8_t usb_vendor_descriptor_template[] = { 0xFF, // 11 bEndpointAddress (IN/D2H) [SET AT RUNTIME: number] #define VENDOR_OUT_ENDPOINT_INDEX 11 0x02, // 12 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 13,14 wMaxPacketSize 512 #else 0x40, 0x00, // 13,14 wMaxPacketSize 64 diff --git a/shared-module/usb_midi/__init__.c b/shared-module/usb_midi/__init__.c index 3808801ff7e..1722911536f 100644 --- a/shared-module/usb_midi/__init__.c +++ b/shared-module/usb_midi/__init__.c @@ -106,7 +106,7 @@ static const uint8_t usb_midi_descriptor_template[] = { 0xFF, // 66 bEndpointAddress (OUT/H2D) [SET AT RUNTIME] #define MIDI_STREAMING_OUT_ENDPOINT_INDEX (66) 0x02, // 67 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 68,69 wMaxPacketSize (512) #else 0x40, 0x00, // 68,69 wMaxPacketSize (64) @@ -126,7 +126,7 @@ static const uint8_t usb_midi_descriptor_template[] = { 0xFF, // 78 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number] #define MIDI_STREAMING_IN_ENDPOINT_INDEX (78) 0x02, // 79 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 80, 81 wMaxPacketSize (512) #else 0x40, 0x00, // 80, 81 wMaxPacketSize (64) diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index ac2fd9f4f25..f2d800b9912 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -79,18 +79,16 @@ extern "C" { #if CIRCUITPY_USB_DEVICE -#if CIRCUITPY_USB_DEVICE_INSTANCE == 0 -#if USB_HIGHSPEED -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) +#if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 +#define _DEVICE_SPEED OPT_MODE_HIGH_SPEED #else -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE) +#define _DEVICE_SPEED 0 #endif + +#if CIRCUITPY_USB_DEVICE_INSTANCE == 0 +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | _DEVICE_SPEED) #elif CIRCUITPY_USB_DEVICE_INSTANCE == 1 -#if USB_HIGHSPEED -#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | OPT_MODE_HIGH_SPEED) -#else -#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE) -#endif +#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_DEVICE | _DEVICE_SPEED) #endif // Use DMA with the USB peripheral. @@ -157,18 +155,16 @@ extern "C" { #define CFG_TUH_RPI_PIO_USB 1 #endif -#if CIRCUITPY_USB_HOST_INSTANCE == 0 -#if USB_HIGHSPEED -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) +#if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 +#define _HOST_SPEED OPT_MODE_HIGH_SPEED #else -#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST) +#define _HOST_SPEED 0 #endif + +#if CIRCUITPY_USB_HOST_INSTANCE == 0 +#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_HOST | _HOST_SPEED) #elif CIRCUITPY_USB_HOST_INSTANCE == 1 -#if USB_HIGHSPEED -#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | OPT_MODE_HIGH_SPEED) -#else -#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST) -#endif +#define CFG_TUSB_RHPORT1_MODE (OPT_MODE_HOST | _HOST_SPEED) #endif // Size of buffer to hold descriptors and other data used for enumeration diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index adc18249761..5ea457ef328 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -72,7 +72,7 @@ static const uint8_t usb_msc_descriptor_template[] = { 0xFF, // 11 bEndpointAddress (IN/D2H) [SET AT RUNTIME: 0x80 | number] #define MSC_IN_ENDPOINT_INDEX (11) 0x02, // 12 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 13,14 wMaxPacketSize 512 #else 0x40, 0x00, // 13,14 wMaxPacketSize 64 @@ -85,7 +85,7 @@ static const uint8_t usb_msc_descriptor_template[] = { 0xFF, // 18 bEndpointAddress (OUT/H2D) [SET AT RUNTIME] #define MSC_OUT_ENDPOINT_INDEX (18) 0x02, // 19 bmAttributes (Bulk) - #if USB_HIGHSPEED + #if CIRCUITPY_USB_DEVICE_HIGH_SPEED == 1 0x00, 0x02, // 20,21 wMaxPacketSize 512 #else 0x40, 0x00, // 20,21 wMaxPacketSize 64 diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 21bda334131..4848915630c 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -259,9 +259,6 @@ ifeq ($(CIRCUITPY_USB_CDC),1) CFLAGS += -DCFG_TUD_CDC=2 endif -USB_HIGHSPEED ?= 0 -CFLAGS += -DUSB_HIGHSPEED=$(USB_HIGHSPEED) - $(BUILD)/supervisor/shared/translate/translate.o: $(HEADER_BUILD)/qstrdefs.generated.h $(HEADER_BUILD)/compressed_translations.generated.h CIRCUITPY_DISPLAY_FONT ?= "../../tools/fonts/ter-u12n.bdf" From 1ddc9d011b98256fa20c3a7a2c758d78a105c214 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 3 Dec 2025 16:21:56 -0800 Subject: [PATCH 105/876] Fix board autogen --- .../zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 7a3ea9267c9..2d723cbced6 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -110,7 +110,7 @@ vectorio = false warnings = false watchdog = false wifi = true # Zephyr board has wifi -zephyr_i2c = false +zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = false +zephyr_serial = true # Zephyr board has zephyr_serial zlib = false From 145d06f9aa951cad09e46e63dc76ff03701c5da9 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 3 Dec 2025 16:22:06 -0800 Subject: [PATCH 106/876] Fix doc build --- ports/zephyr-cp/bindings/zephyr_i2c/I2C.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c index 08ce9e966a6..f2fe029ee01 100644 --- a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c +++ b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c @@ -25,8 +25,8 @@ //| .. class:: I2C() //| //| Cannot be instantiated directly. Instead singletons are created using the -//| `board` aliases that match the device tree labels. `board` may list multiple -//| aliases for a single device. For example, `board.I2C1` and `board.ARDUINO_I2C` +//| ``board`` aliases that match the device tree labels. ``board`` may list multiple +//| aliases for a single device. For example, ``board.I2C1`` and ``board.ARDUINO_I2C`` //| may both refer to the same device. //| """ //| From 7e7abc0f1649b98ddb6a3ccabdf2ddb3c285b081 Mon Sep 17 00:00:00 2001 From: Jerzeek Date: Thu, 4 Dec 2025 11:01:39 +0100 Subject: [PATCH 107/876] add studiolab_picoexpander# Please enter the commit message for your changes. Lines starting --- .../boards/studiolab_picoexpander/board.c | 9 ++ .../boards/studiolab_picoexpander/link.ld | 1 + .../studiolab_picoexpander/mpconfigboard.h | 20 ++++ .../studiolab_picoexpander/mpconfigboard.mk | 35 +++++++ .../pico-sdk-configboard.h | 9 ++ .../boards/studiolab_picoexpander/pins.c | 94 +++++++++++++++++++ 6 files changed, 168 insertions(+) create mode 100644 ports/raspberrypi/boards/studiolab_picoexpander/board.c create mode 100644 ports/raspberrypi/boards/studiolab_picoexpander/link.ld create mode 100644 ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/studiolab_picoexpander/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/studiolab_picoexpander/pins.c diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/board.c b/ports/raspberrypi/boards/studiolab_picoexpander/board.c new file mode 100644 index 00000000000..299f32da04f --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/link.ld b/ports/raspberrypi/boards/studiolab_picoexpander/link.ld new file mode 100644 index 00000000000..e814bead4c5 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/link.ld @@ -0,0 +1 @@ +firmware_size = 1532k; diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h new file mode 100644 index 00000000000..5e2dd69f290 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Pico Expander" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1) +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE (1) + +#define MICROPY_HW_LED_STATUS (&pin_CYW0) +#define MICROPY_HW_NEOPIXEL (&pin_GPIO2) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO5, .sda = &pin_GPIO4}} + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO18, .mosi = &pin_GPIO19, .miso = &pin_GPIO16}} diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk new file mode 100644 index 00000000000..e1407c16854 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk @@ -0,0 +1,35 @@ +USB_VID = 0x239A +USB_PID = 0x8162 +USB_PRODUCT = "Pico 2 W" +USB_MANUFACTURER = "Raspberry Pi" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" + +CIRCUITPY__EVE = 1 + +CIRCUITPY_CYW43 = 1 +CIRCUITPY_SSL = 1 +CIRCUITPY_HASHLIB = 1 +CIRCUITPY_WEB_WORKFLOW = 1 +CIRCUITPY_MDNS = 1 +CIRCUITPY_SOCKETPOOL = 1 +CIRCUITPY_WIFI = 1 + +CFLAGS += \ + -DCYW43_PIN_WL_DYNAMIC=0 \ + -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ + -DCYW43_DEFAULT_PIN_WL_REG_ON=23 \ + -DCYW43_DEFAULT_PIN_WL_CLOCK=29 \ + -DCYW43_DEFAULT_PIN_WL_DATA_IN=24 \ + -DCYW43_DEFAULT_PIN_WL_DATA_OUT=24 \ + -DCYW43_DEFAULT_PIN_WL_CS=25 \ + -DCYW43_WL_GPIO_COUNT=3 \ + -DCYW43_WL_GPIO_LED_PIN=0 \ + -DCYW43_PIO_CLOCK_DIV_INT=3 + +# Must be accompanied by a linker script change +CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/pico-sdk-configboard.h b/ports/raspberrypi/boards/studiolab_picoexpander/pico-sdk-configboard.h new file mode 100644 index 00000000000..945802d1ab1 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/pins.c b/ports/raspberrypi/boards/studiolab_picoexpander/pins.c new file mode 100644 index 00000000000..f2c89251149 --- /dev/null +++ b/ports/raspberrypi/boards/studiolab_picoexpander/pins.c @@ -0,0 +1,94 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Jeff Epler for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_BTN), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO15) }, + + + { MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_CYW1) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_CYW0) }, + + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_CYW2) }, + + { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + + { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 84373ebf8f801ea1a8b5c9c0a8ca253bb0dcb768 Mon Sep 17 00:00:00 2001 From: Jerzeek Date: Thu, 4 Dec 2025 12:06:42 +0100 Subject: [PATCH 108/876] Correct PID and VID --- .../boards/studiolab_picoexpander/mpconfigboard.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk index e1407c16854..9db15479076 100644 --- a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk @@ -1,5 +1,5 @@ -USB_VID = 0x239A -USB_PID = 0x8162 +USB_VID = 0x1209 +USB_PID = 0xC1C1 USB_PRODUCT = "Pico 2 W" USB_MANUFACTURER = "Raspberry Pi" From 0348f977db195cbaee49d3acd7e54c9d7e6ed7db Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 4 Dec 2025 10:09:26 -0800 Subject: [PATCH 109/876] Fix ESP builds --- ports/espressif/supervisor/usb.c | 41 ++++++++------------------------ 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/ports/espressif/supervisor/usb.c b/ports/espressif/supervisor/usb.c index 327fada778f..56042fce1b7 100644 --- a/ports/espressif/supervisor/usb.c +++ b/ports/espressif/supervisor/usb.c @@ -13,7 +13,6 @@ #include "shared/readline/readline.h" #include "hal/gpio_ll.h" -#include "hal/usb_serial_jtag_ll.h" #include "esp_err.h" #include "esp_private/usb_phy.h" @@ -29,6 +28,10 @@ #include "tusb.h" +#ifdef CONFIG_IDF_TARGET_ESP32P4 +#include "hal/usb_serial_jtag_ll.h" +#endif + #if CIRCUITPY_USB_DEVICE #ifdef CFG_TUSB_DEBUG #define USBD_STACK_SIZE (3 * configMINIMAL_STACK_SIZE) @@ -66,11 +69,11 @@ void init_usb_hardware(void) { .target = USB_PHY_TARGET_INT, .otg_mode = USB_OTG_MODE_DEVICE, #if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 0 - .otg_speed = USB_PHY_SPEED_FULL, + .otg_speed = USB_PHY_SPEED_FULL, #else // https://github.com/hathach/tinyusb/issues/2943#issuecomment-2601888322 // Set speed to undefined (auto-detect) to avoid timing/race issue with S3 with host such as macOS - .otg_speed = USB_PHY_SPEED_UNDEFINED, + .otg_speed = USB_PHY_SPEED_UNDEFINED, #endif }; usb_new_phy(&phy_conf, &device_phy_hdl); @@ -81,9 +84,11 @@ void init_usb_hardware(void) { #endif // Switch the USB PHY const usb_serial_jtag_pull_override_vals_t override_disable_usb = { - .dm_pd = true, .dm_pu = false, .dp_pd = true, .dp_pu = false}; + .dm_pd = true, .dm_pu = false, .dp_pd = true, .dp_pu = false + }; const usb_serial_jtag_pull_override_vals_t override_enable_usb = { - .dm_pd = false, .dm_pu = false, .dp_pd = false, .dp_pu = true}; + .dm_pd = false, .dm_pu = false, .dp_pd = false, .dp_pu = true + }; // Drop off the bus by removing the pull-up on USB DP usb_serial_jtag_ll_phy_enable_pull_override(&override_disable_usb); @@ -97,32 +102,6 @@ void init_usb_hardware(void) { usb_serial_jtag_ll_phy_disable_pull_override(); #endif - // Pin the USB task to the same core as CircuitPython. This way we leave - // the other core for networking. - (void)xTaskCreateStaticPinnedToCore(usb_device_task, - "usbd", - USBD_STACK_SIZE, - NULL, - 5, - usb_device_stack, - &usb_device_taskdef, - xPortGetCoreID()); - #endif - // Configure USB PHY - usb_phy_config_t phy_conf = { - .controller = USB_PHY_CTRL_OTG, - .target = USB_PHY_TARGET_INT, - .otg_mode = USB_OTG_MODE_DEVICE, - #if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 0 - .otg_speed = USB_PHY_SPEED_FULL, - #else - // https://github.com/hathach/tinyusb/issues/2943#issuecomment-2601888322 - // Set speed to undefined (auto-detect) to avoid timing/race issue with S3 with host such as macOS - .otg_speed = USB_PHY_SPEED_UNDEFINED, - #endif - }; - usb_new_phy(&phy_conf, &device_phy_hdl); - // Pin the USB task to the same core as CircuitPython. This way we leave // the other core for networking. (void)xTaskCreateStaticPinnedToCore(usb_device_task, From e5fb28d53ebb49f83459cfb616b8ac31bab430af Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 4 Dec 2025 11:16:38 -0800 Subject: [PATCH 110/876] Revert TinyUSB update. It is too big now --- lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tinyusb b/lib/tinyusb index 3af1bec1a91..c1bf19ed6cf 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit 3af1bec1a9161ee8dec29487831f7ac7ade9e189 +Subproject commit c1bf19ed6cf1eaa791f221c1bc5ce4b3d069f76d From 3453683042d9ac4f0f4f476534a5f4f14ba5bd63 Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Fri, 5 Dec 2025 19:39:52 +0000 Subject: [PATCH 111/876] implement hashlib.new('sha256') support --- py/circuitpy_mpconfig.mk | 3 +++ shared-module/hashlib/Hash.c | 20 ++++++++++++++++++++ shared-module/hashlib/Hash.h | 6 ++++++ shared-module/hashlib/__init__.c | 8 ++++++++ shared-module/hashlib/__init__.h | 7 +++++++ 5 files changed, 44 insertions(+) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 9bbe5691dfb..dbd9de2b3f8 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -343,6 +343,9 @@ CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS=$(CIRCUITPY_HASHLIB_MBEDTLS) CIRCUITPY_HASHLIB_MBEDTLS_ONLY ?= $(call enable-if-all,$(CIRCUITPY_HASHLIB_MBEDTLS) $(call enable-if-not,$(CIRCUITPY_SSL))) CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS_ONLY=$(CIRCUITPY_HASHLIB_MBEDTLS_ONLY) +CIRCUITPY_HASHLIB_SHA256 ?= 0 +CFLAGS += -DCIRCUITPY_HASHLIB_SHA256=$(CIRCUITPY_HASHLIB_SHA256) + CIRCUITPY_I2CTARGET ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_I2CTARGET=$(CIRCUITPY_I2CTARGET) diff --git a/shared-module/hashlib/Hash.c b/shared-module/hashlib/Hash.c index a454966d993..a4e21c7a06f 100644 --- a/shared-module/hashlib/Hash.c +++ b/shared-module/hashlib/Hash.c @@ -14,6 +14,12 @@ void common_hal_hashlib_hash_update(hashlib_hash_obj_t *self, const uint8_t *dat mbedtls_sha1_update_ret(&self->sha1, data, datalen); return; } + #if CIRCUITPY_HASHLIB_SHA256 + else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + mbedtls_sha256_update_ret(&self->sha256, data, datalen); + return; + } + #endif } void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, size_t datalen) { @@ -28,11 +34,25 @@ void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, siz mbedtls_sha1_finish_ret(&self->sha1, data); mbedtls_sha1_clone(&self->sha1, ©); } + #if CIRCUITPY_HASHLIB_SHA256 + else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + mbedtls_sha256_context copy; + mbedtls_sha256_clone(©, &self->sha256); + mbedtls_sha256_finish_ret(&self->sha256, data); + mbedtls_sha256_clone(&self->sha256, ©); + } + #endif } size_t common_hal_hashlib_hash_get_digest_size(hashlib_hash_obj_t *self) { if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { return 20; } + #if CIRCUITPY_HASHLIB_SHA256 + else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + return 32; + } + #endif + return 0; } diff --git a/shared-module/hashlib/Hash.h b/shared-module/hashlib/Hash.h index ccc82037cb7..0c33b4876c1 100644 --- a/shared-module/hashlib/Hash.h +++ b/shared-module/hashlib/Hash.h @@ -7,11 +7,17 @@ #pragma once #include "mbedtls/sha1.h" +#if CIRCUITPY_HASHLIB_SHA256 +#include "mbedtls/sha256.h" +#endif typedef struct { mp_obj_base_t base; union { mbedtls_sha1_context sha1; + #if CIRCUITPY_HASHLIB_SHA256 + mbedtls_sha256_context sha256; + #endif }; // Of MBEDTLS_SSL_HASH_* uint8_t hash_type; diff --git a/shared-module/hashlib/__init__.c b/shared-module/hashlib/__init__.c index be3a9f18959..ebf9d1700ea 100644 --- a/shared-module/hashlib/__init__.c +++ b/shared-module/hashlib/__init__.c @@ -17,5 +17,13 @@ bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { mbedtls_sha1_starts_ret(&self->sha1); return true; } + #if CIRCUITPY_HASHLIB_SHA256 + else if (strcmp(algorithm, "sha256") == 0) { + self->hash_type = MBEDTLS_SSL_HASH_SHA256; + mbedtls_sha256_init(&self->sha256); + mbedtls_sha256_starts_ret(&self->sha256, 0); + return true; + } + #endif return false; } diff --git a/shared-module/hashlib/__init__.h b/shared-module/hashlib/__init__.h index f72882a1c03..50125595ab5 100644 --- a/shared-module/hashlib/__init__.h +++ b/shared-module/hashlib/__init__.h @@ -13,4 +13,11 @@ #define mbedtls_sha1_starts_ret mbedtls_sha1_starts #define mbedtls_sha1_update_ret mbedtls_sha1_update #define mbedtls_sha1_finish_ret mbedtls_sha1_finish + +#if CIRCUITPY_HASHLIB_SHA256 +#define mbedtls_sha256_starts_ret mbedtls_sha256_starts +#define mbedtls_sha256_update_ret mbedtls_sha256_update +#define mbedtls_sha256_finish_ret mbedtls_sha256_finish +#endif + #endif From f80d99297009428ed6c65a67be6b234bfaa71f7b Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Fri, 5 Dec 2025 19:40:49 +0000 Subject: [PATCH 112/876] enable hashlib sha1 & sha256 for CLUE board --- ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk b/ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk index e1a25137a19..c835621547a 100644 --- a/ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk +++ b/ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk @@ -7,3 +7,6 @@ MCU_CHIP = nrf52840 QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "GD25Q16C, W25Q16JVxQ" + +CIRCUITPY_HASHLIB = 1 +CIRCUITPY_HASHLIB_SHA256 = 1 From db86a75be37468ad962c0418ab2a5227df549a44 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 5 Dec 2025 15:05:58 -0800 Subject: [PATCH 113/876] Add mutable brightness --- .../common-hal/microcontroller/Pin.c | 9 ++--- ports/espressif/common-hal/mipidsi/Display.c | 34 +++++++++++++++++++ ports/espressif/common-hal/mipidsi/Display.h | 1 + shared-bindings/mipidsi/Display.c | 11 ++++++ shared-bindings/mipidsi/Display.h | 2 ++ 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index dc4e4bb032e..f995e65545d 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -204,13 +204,8 @@ static const uint64_t pin_mask_reset_forbidden = #endif // ESP32H2 #if defined(CONFIG_IDF_TARGET_ESP32P4) - // Never ever reset pins used to communicate with the SPI flash. - GPIO_SEL_28 | - GPIO_SEL_29 | - GPIO_SEL_30 | - GPIO_SEL_32 | - GPIO_SEL_33 | - GPIO_SEL_34 | + // SPI flash is on dedicated pins. + // USB is on the FS OTG #if CIRCUITPY_USB_DEVICE_INSTANCE == 0 #if CIRCUITPY_ESP32P4_SWAP_LSFS == 1 diff --git a/ports/espressif/common-hal/mipidsi/Display.c b/ports/espressif/common-hal/mipidsi/Display.c index cc45db72375..46ef46ed601 100644 --- a/ports/espressif/common-hal/mipidsi/Display.c +++ b/ports/espressif/common-hal/mipidsi/Display.c @@ -222,6 +222,40 @@ void common_hal_mipidsi_display_refresh(mipidsi_display_obj_t *self) { // sends data from the framebuffer to the display } +mp_float_t common_hal_mipidsi_display_get_brightness(mipidsi_display_obj_t *self) { + return self->current_brightness; +} + +bool common_hal_mipidsi_display_set_brightness(mipidsi_display_obj_t *self, mp_float_t brightness) { + if (!self->backlight_on_high) { + brightness = 1.0 - brightness; + } + bool ok = false; + + // Avoid PWM types and functions when the module isn't enabled + #if (CIRCUITPY_PWMIO) + bool ispwm = (self->backlight_pwm.base.type == &pwmio_pwmout_type) ? true : false; + #else + bool ispwm = false; + #endif + + if (ispwm) { + #if (CIRCUITPY_PWMIO) + common_hal_pwmio_pwmout_set_duty_cycle(&self->backlight_pwm, (uint16_t)(0xffff * brightness)); + ok = true; + #else + ok = false; + #endif + } else if (self->backlight_inout.base.type == &digitalio_digitalinout_type) { + common_hal_digitalio_digitalinout_set_value(&self->backlight_inout, brightness > 0.99); + ok = true; + } + if (ok) { + self->current_brightness = brightness; + } + return ok; +} + int common_hal_mipidsi_display_get_width(mipidsi_display_obj_t *self) { return self->width; } diff --git a/ports/espressif/common-hal/mipidsi/Display.h b/ports/espressif/common-hal/mipidsi/Display.h index 61e6cb73f6d..cbc87e268dc 100644 --- a/ports/espressif/common-hal/mipidsi/Display.h +++ b/ports/espressif/common-hal/mipidsi/Display.h @@ -34,4 +34,5 @@ typedef struct { #endif }; bool backlight_on_high; + mp_float_t current_brightness; } mipidsi_display_obj_t; diff --git a/shared-bindings/mipidsi/Display.c b/shared-bindings/mipidsi/Display.c index ad4522d653c..149d31e52a9 100644 --- a/shared-bindings/mipidsi/Display.c +++ b/shared-bindings/mipidsi/Display.c @@ -220,6 +220,15 @@ static void mipidsi_display_get_bufinfo(mp_obj_t self_in, mp_buffer_info_t *bufi common_hal_mipidsi_display_get_buffer(self_in, bufinfo, 0); } +static float mipidsi_display_get_brightness_proto(mp_obj_t self_in) { + return common_hal_mipidsi_display_get_brightness(self_in); +} + +static bool mipidsi_display_set_brightness_proto(mp_obj_t self_in, mp_float_t value) { + common_hal_mipidsi_display_set_brightness(self_in, value); + return true; +} + // These versions exist so that the prototype matches the protocol, // avoiding a type cast that can hide errors static void mipidsi_display_swapbuffers(mp_obj_t self_in, uint8_t *dirty_row_bitmap) { @@ -266,6 +275,8 @@ static int mipidsi_display_get_row_stride_proto(mp_obj_t self_in) { static const framebuffer_p_t mipidsi_display_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_framebuffer) .get_bufinfo = mipidsi_display_get_bufinfo, + .set_brightness = mipidsi_display_set_brightness_proto, + .get_brightness = mipidsi_display_get_brightness_proto, .get_width = mipidsi_display_get_width_proto, .get_height = mipidsi_display_get_height_proto, .get_color_depth = mipidsi_display_get_color_depth_proto, diff --git a/shared-bindings/mipidsi/Display.h b/shared-bindings/mipidsi/Display.h index 1cec788f16c..09cf130bf4a 100644 --- a/shared-bindings/mipidsi/Display.h +++ b/shared-bindings/mipidsi/Display.h @@ -35,6 +35,8 @@ void common_hal_mipidsi_display_construct(mipidsi_display_obj_t *self, void common_hal_mipidsi_display_deinit(mipidsi_display_obj_t *self); bool common_hal_mipidsi_display_deinited(mipidsi_display_obj_t *self); void common_hal_mipidsi_display_refresh(mipidsi_display_obj_t *self); +mp_float_t common_hal_mipidsi_display_get_brightness(mipidsi_display_obj_t *self); +bool common_hal_mipidsi_display_set_brightness(mipidsi_display_obj_t *self, mp_float_t brightness); int common_hal_mipidsi_display_get_width(mipidsi_display_obj_t *self); int common_hal_mipidsi_display_get_height(mipidsi_display_obj_t *self); int common_hal_mipidsi_display_get_row_stride(mipidsi_display_obj_t *self); From 9e204f114b4d786b3eda53840f057018bff10a2d Mon Sep 17 00:00:00 2001 From: noqman Date: Mon, 8 Dec 2025 16:17:35 +0800 Subject: [PATCH 114/876] Remove adafruit_bus_device --- ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk index 72d20ea7e05..95686552e69 100644 --- a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk @@ -38,7 +38,6 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' OPTIMIZATION_FLAGS = -O2 # Include these Python libraries in firmware. -FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_BusDevice FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Text FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel From 2d6d5f6aad79c9a5463dc45d1bd3e61ac07e2237 Mon Sep 17 00:00:00 2001 From: noqman Date: Mon, 8 Dec 2025 16:20:17 +0800 Subject: [PATCH 115/876] Remove adafruit_sdcard and enable sdcardio --- .../raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk index 95686552e69..af59c1ab25b 100644 --- a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk @@ -11,6 +11,8 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY__EVE = 1 +CIRCUITPY_SDCARDIO = 1 + CIRCUITPY_CYW43 = 1 CIRCUITPY_SSL = 1 CIRCUITPY_HASHLIB = 1 @@ -48,5 +50,4 @@ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ImageLoad FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_AHTx0 -FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HTTPServer From c69dc8f0f34c3e2362e25358e10b65a7cf687782 Mon Sep 17 00:00:00 2001 From: noqman Date: Mon, 8 Dec 2025 16:21:51 +0800 Subject: [PATCH 116/876] Add adafruit_OPT4048 --- ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk index af59c1ab25b..2bea1359b4a 100644 --- a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk @@ -48,6 +48,7 @@ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SimpleIO FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_OPT4048 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ImageLoad FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_AHTx0 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HTTPServer From b04f7e53da206e3b638fb17473d8545d180f5b35 Mon Sep 17 00:00:00 2001 From: noqman Date: Mon, 8 Dec 2025 16:35:22 +0800 Subject: [PATCH 117/876] Add the OPT4048 submodule --- .gitmodules | 3 +++ frozen/Adafruit_CircuitPython_OPT4048 | 1 + 2 files changed, 4 insertions(+) create mode 160000 frozen/Adafruit_CircuitPython_OPT4048 diff --git a/.gitmodules b/.gitmodules index 7eaa0b04142..4cef2eeb9d5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -415,3 +415,6 @@ [submodule "ports/espressif/microros-lib"] path = ports/espressif/microros-lib url = https://github.com/hierophect/microros-lib.git +[submodule "frozen/Adafruit_CircuitPython_OPT4048"] + path = frozen/Adafruit_CircuitPython_OPT4048 + url = https://github.com/adafruit/Adafruit_CircuitPython_OPT4048.git diff --git a/frozen/Adafruit_CircuitPython_OPT4048 b/frozen/Adafruit_CircuitPython_OPT4048 new file mode 160000 index 00000000000..b6a02e289e9 --- /dev/null +++ b/frozen/Adafruit_CircuitPython_OPT4048 @@ -0,0 +1 @@ +Subproject commit b6a02e289e922b328fd395908b6b89f12ee137ea From 3630042e27350327761961d027a18f4384b88ff0 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 8 Dec 2025 10:08:26 -0800 Subject: [PATCH 118/876] Add parens Co-authored-by: Dan Halbert --- ports/zephyr-cp/bindings/zephyr_i2c/I2C.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c index f2fe029ee01..456f3703ff5 100644 --- a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c +++ b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c @@ -26,7 +26,7 @@ //| //| Cannot be instantiated directly. Instead singletons are created using the //| ``board`` aliases that match the device tree labels. ``board`` may list multiple -//| aliases for a single device. For example, ``board.I2C1`` and ``board.ARDUINO_I2C`` +//| aliases for a single device. For example, ``board.I2C1()`` and ``board.ARDUINO_I2C()`` //| may both refer to the same device. //| """ //| From 30c8dd626f543c2927a08f8c5797aa0e0cf79ba7 Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Mon, 8 Dec 2025 18:37:33 +0000 Subject: [PATCH 119/876] default to enabling SHA256 when hashlib is enabled --- py/circuitpy_mpconfig.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index dbd9de2b3f8..61344a86f9e 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -343,7 +343,7 @@ CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS=$(CIRCUITPY_HASHLIB_MBEDTLS) CIRCUITPY_HASHLIB_MBEDTLS_ONLY ?= $(call enable-if-all,$(CIRCUITPY_HASHLIB_MBEDTLS) $(call enable-if-not,$(CIRCUITPY_SSL))) CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS_ONLY=$(CIRCUITPY_HASHLIB_MBEDTLS_ONLY) -CIRCUITPY_HASHLIB_SHA256 ?= 0 +CIRCUITPY_HASHLIB_SHA256 ?= $(CIRCUITPY_HASHLIB) CFLAGS += -DCIRCUITPY_HASHLIB_SHA256=$(CIRCUITPY_HASHLIB_SHA256) CIRCUITPY_I2CTARGET ?= $(CIRCUITPY_FULL_BUILD) From 9996cbf740e0a86bd14456d0baba6eb8c2f6dd40 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Mon, 8 Dec 2025 21:05:28 +0100 Subject: [PATCH 120/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 14 +++++++------- locale/el.po | 14 +++++++------- locale/hi.po | 14 +++++++------- locale/ko.po | 14 +++++++------- locale/ru.po | 14 +++++++------- locale/tr.po | 14 +++++++------- 6 files changed, 42 insertions(+), 42 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 44adf488336..35196a280e3 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -122,6 +122,7 @@ msgid "%q in %q must be of type %q, not %q" msgstr "%q v %q musí být typu %q, ne %q" #: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -255,7 +256,8 @@ msgstr "%q je mimo hranice" #: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "%q je mimo rozsah" @@ -850,10 +852,6 @@ msgstr "Jádro kódu CircuitPython tvrdě havarovalo. Jejda!\n" msgid "Clock unit in use" msgstr "Jednotka hodin je používána" -#: ports/espressif/common-hal/mipidsi/Display.c -msgid "Color depth must be 16 or 24" -msgstr "" - #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -1139,8 +1137,9 @@ msgstr "" "Frekvence musí být 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 nebo 1008 " "Mhz" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "Funkce vyžaduje zámek" @@ -1291,6 +1290,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c #: ports/raspberrypi/bindings/picodvi/Framebuffer.c diff --git a/locale/el.po b/locale/el.po index 01f199d5c6a..bde4522cc60 100644 --- a/locale/el.po +++ b/locale/el.po @@ -126,6 +126,7 @@ msgid "%q in %q must be of type %q, not %q" msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %q" #: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -259,7 +260,8 @@ msgstr "%q εκτός ορίων" #: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "%q εκτός εμβέλειας" @@ -855,10 +857,6 @@ msgstr "Ο πυρήνας της CircuitPython κατέρευσε. Οουπς!\n msgid "Clock unit in use" msgstr "Μονάδα ρολογιού ήδη σε χρήση" -#: ports/espressif/common-hal/mipidsi/Display.c -msgid "Color depth must be 16 or 24" -msgstr "" - #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -1145,8 +1143,9 @@ msgid "" "Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "" @@ -1297,6 +1296,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c #: ports/raspberrypi/bindings/picodvi/Framebuffer.c diff --git a/locale/hi.po b/locale/hi.po index ea538c2f6f3..43737b6cdd8 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -113,6 +113,7 @@ msgid "%q in %q must be of type %q, not %q" msgstr "" #: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -246,7 +247,8 @@ msgstr "" #: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "" @@ -836,10 +838,6 @@ msgstr "" msgid "Clock unit in use" msgstr "" -#: ports/espressif/common-hal/mipidsi/Display.c -msgid "Color depth must be 16 or 24" -msgstr "" - #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -1121,8 +1119,9 @@ msgid "" "Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "" @@ -1273,6 +1272,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c #: ports/raspberrypi/bindings/picodvi/Framebuffer.c diff --git a/locale/ko.po b/locale/ko.po index 96d8003ff93..f77519cf701 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -124,6 +124,7 @@ msgid "%q in %q must be of type %q, not %q" msgstr "%q의 %q는 %q가 아니라 %q 유형이어야 합니다" #: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -263,7 +264,8 @@ msgstr "%q가 경계를 벗어남" #: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c #, fuzzy msgid "%q out of range" msgstr "%q가 범위를 벗어남" @@ -880,10 +882,6 @@ msgstr "CircuitPython 핵심 코드가 심하게 충돌했습니다. 앗!\n" msgid "Clock unit in use" msgstr "시계 장치가 사용 중입니다" -#: ports/espressif/common-hal/mipidsi/Display.c -msgid "Color depth must be 16 or 24" -msgstr "" - #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -1172,8 +1170,9 @@ msgstr "" "주파수는 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 또는 1008 Mhz 여야 " "합니다" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "이 함수에는 잠금이 필요합니다" @@ -1324,6 +1323,7 @@ msgstr "출력 함수로 인해 종료되었다" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c #: ports/raspberrypi/bindings/picodvi/Framebuffer.c diff --git a/locale/ru.po b/locale/ru.po index 3b957b347c1..bbd39319823 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -126,6 +126,7 @@ msgid "%q in %q must be of type %q, not %q" msgstr "%q в %q должно быть типа %q, а не %q" #: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -259,7 +260,8 @@ msgstr "%q за пределом" #: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "%q вне диапазона" @@ -858,10 +860,6 @@ msgstr "Основной код CircuitPython сильно разбился. У msgid "Clock unit in use" msgstr "Источник тактирования уже используется" -#: ports/espressif/common-hal/mipidsi/Display.c -msgid "Color depth must be 16 or 24" -msgstr "" - #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -1156,8 +1154,9 @@ msgstr "" "Частота должна быть 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 или 1008 " "МГц" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "Функция требует блокировки" @@ -1312,6 +1311,7 @@ msgstr "Прерывается функцией выхода" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c #: ports/raspberrypi/bindings/picodvi/Framebuffer.c diff --git a/locale/tr.po b/locale/tr.po index 54155a60543..966a9123083 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -124,6 +124,7 @@ msgid "%q in %q must be of type %q, not %q" msgstr "" #: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -257,7 +258,8 @@ msgstr "%q sınırların dışında" #: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/canio/Match.c shared-bindings/time/__init__.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c msgid "%q out of range" msgstr "%q aralık dışında" @@ -850,10 +852,6 @@ msgstr "CircuitPython kor kodu patladı. Haydaaa!\n" msgid "Clock unit in use" msgstr "Saat ünitesi kullanımda" -#: ports/espressif/common-hal/mipidsi/Display.c -msgid "Color depth must be 16 or 24" -msgstr "" - #: shared-bindings/_bleio/Connection.c msgid "" "Connection has been disconnected and can no longer be used. Create a new " @@ -1139,8 +1137,9 @@ msgstr "" "Frekans 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 ya da 1008 Mhz " "olmalıdır" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "Fonksiyon kilit gerektirir" @@ -1291,6 +1290,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c #: ports/raspberrypi/bindings/picodvi/Framebuffer.c From f9d5778aa706e9094161d603b828443be627057c Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:36:18 +0000 Subject: [PATCH 121/876] turn on hashlib for all nrf52840 boards This turns on hashlib at the port level, but only for nrf52840 boards. There's a comment in mpconfigport.mk suggesting that space is already tight on nrf52833 boards. --- ports/nordic/mpconfigport.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index 502e71ae4ae..48536ec2acd 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -63,6 +63,8 @@ CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_RGBMATRIX ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 +CIRCUITPY_HASHLIB ?= 1 + CIRCUITPY_COUNTIO ?= 1 CIRCUITPY_WATCHDOG ?= 1 From fabe72b40e623f5504342e712d16aa9b131a4937 Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Mon, 8 Dec 2025 20:38:31 +0000 Subject: [PATCH 122/876] remove redundant hashlib enable for CLUE This is enabled at the port level now. --- ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk | 3 --- 1 file changed, 3 deletions(-) diff --git a/ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk b/ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk index c835621547a..e1a25137a19 100644 --- a/ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk +++ b/ports/nordic/boards/clue_nrf52840_express/mpconfigboard.mk @@ -7,6 +7,3 @@ MCU_CHIP = nrf52840 QSPI_FLASH_FILESYSTEM = 1 EXTERNAL_FLASH_DEVICES = "GD25Q16C, W25Q16JVxQ" - -CIRCUITPY_HASHLIB = 1 -CIRCUITPY_HASHLIB_SHA256 = 1 From c1bd53d40ae5aa5f655522d58fafa8c8dce45343 Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Mon, 8 Dec 2025 21:54:30 +0000 Subject: [PATCH 123/876] remove CIRCUITPY_HASHLIB_SHA256 ifdef guards --- py/circuitpy_mpconfig.mk | 3 --- shared-module/hashlib/Hash.c | 16 +++------------- shared-module/hashlib/Hash.h | 4 ---- shared-module/hashlib/__init__.c | 5 +---- shared-module/hashlib/__init__.h | 2 -- 5 files changed, 4 insertions(+), 26 deletions(-) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 61344a86f9e..9bbe5691dfb 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -343,9 +343,6 @@ CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS=$(CIRCUITPY_HASHLIB_MBEDTLS) CIRCUITPY_HASHLIB_MBEDTLS_ONLY ?= $(call enable-if-all,$(CIRCUITPY_HASHLIB_MBEDTLS) $(call enable-if-not,$(CIRCUITPY_SSL))) CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS_ONLY=$(CIRCUITPY_HASHLIB_MBEDTLS_ONLY) -CIRCUITPY_HASHLIB_SHA256 ?= $(CIRCUITPY_HASHLIB) -CFLAGS += -DCIRCUITPY_HASHLIB_SHA256=$(CIRCUITPY_HASHLIB_SHA256) - CIRCUITPY_I2CTARGET ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_I2CTARGET=$(CIRCUITPY_I2CTARGET) diff --git a/shared-module/hashlib/Hash.c b/shared-module/hashlib/Hash.c index a4e21c7a06f..b7e966e951b 100644 --- a/shared-module/hashlib/Hash.c +++ b/shared-module/hashlib/Hash.c @@ -13,13 +13,10 @@ void common_hal_hashlib_hash_update(hashlib_hash_obj_t *self, const uint8_t *dat if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { mbedtls_sha1_update_ret(&self->sha1, data, datalen); return; - } - #if CIRCUITPY_HASHLIB_SHA256 - else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { mbedtls_sha256_update_ret(&self->sha256, data, datalen); return; } - #endif } void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, size_t datalen) { @@ -33,26 +30,19 @@ void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, siz mbedtls_sha1_clone(©, &self->sha1); mbedtls_sha1_finish_ret(&self->sha1, data); mbedtls_sha1_clone(&self->sha1, ©); - } - #if CIRCUITPY_HASHLIB_SHA256 - else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { mbedtls_sha256_context copy; mbedtls_sha256_clone(©, &self->sha256); mbedtls_sha256_finish_ret(&self->sha256, data); mbedtls_sha256_clone(&self->sha256, ©); } - #endif } size_t common_hal_hashlib_hash_get_digest_size(hashlib_hash_obj_t *self) { if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { return 20; - } - #if CIRCUITPY_HASHLIB_SHA256 - else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { + } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { return 32; } - #endif - return 0; } diff --git a/shared-module/hashlib/Hash.h b/shared-module/hashlib/Hash.h index 0c33b4876c1..f3c2979e59c 100644 --- a/shared-module/hashlib/Hash.h +++ b/shared-module/hashlib/Hash.h @@ -7,17 +7,13 @@ #pragma once #include "mbedtls/sha1.h" -#if CIRCUITPY_HASHLIB_SHA256 #include "mbedtls/sha256.h" -#endif typedef struct { mp_obj_base_t base; union { mbedtls_sha1_context sha1; - #if CIRCUITPY_HASHLIB_SHA256 mbedtls_sha256_context sha256; - #endif }; // Of MBEDTLS_SSL_HASH_* uint8_t hash_type; diff --git a/shared-module/hashlib/__init__.c b/shared-module/hashlib/__init__.c index ebf9d1700ea..f9bc787d49f 100644 --- a/shared-module/hashlib/__init__.c +++ b/shared-module/hashlib/__init__.c @@ -16,14 +16,11 @@ bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { mbedtls_sha1_init(&self->sha1); mbedtls_sha1_starts_ret(&self->sha1); return true; - } - #if CIRCUITPY_HASHLIB_SHA256 - else if (strcmp(algorithm, "sha256") == 0) { + } else if (strcmp(algorithm, "sha256") == 0) { self->hash_type = MBEDTLS_SSL_HASH_SHA256; mbedtls_sha256_init(&self->sha256); mbedtls_sha256_starts_ret(&self->sha256, 0); return true; } - #endif return false; } diff --git a/shared-module/hashlib/__init__.h b/shared-module/hashlib/__init__.h index 50125595ab5..847bd8a8347 100644 --- a/shared-module/hashlib/__init__.h +++ b/shared-module/hashlib/__init__.h @@ -14,10 +14,8 @@ #define mbedtls_sha1_update_ret mbedtls_sha1_update #define mbedtls_sha1_finish_ret mbedtls_sha1_finish -#if CIRCUITPY_HASHLIB_SHA256 #define mbedtls_sha256_starts_ret mbedtls_sha256_starts #define mbedtls_sha256_update_ret mbedtls_sha256_update #define mbedtls_sha256_finish_ret mbedtls_sha256_finish -#endif #endif From c6ae68ad41891df42a4156611a59dbd33f1fa612 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 8 Dec 2025 14:34:29 -0800 Subject: [PATCH 124/876] Init older M5Stack Tab5 display Fixes #10666 --- ports/espressif/boards/m5stack_tab5/board.c | 370 ++++++++++++++++++++ 1 file changed, 370 insertions(+) diff --git a/ports/espressif/boards/m5stack_tab5/board.c b/ports/espressif/boards/m5stack_tab5/board.c index a3a9eec0471..7c7c768d5c1 100644 --- a/ports/espressif/boards/m5stack_tab5/board.c +++ b/ports/espressif/boards/m5stack_tab5/board.c @@ -5,5 +5,375 @@ // SPDX-License-Identifier: MIT #include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/mipidsi/Bus.h" +#include "shared-bindings/mipidsi/Display.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/framebufferio/__init__.h" +#include "shared-module/framebufferio/FramebufferDisplay.h" +#include "ports/espressif/common-hal/microcontroller/Pin.h" + +// Statically allocate the MIPI DSI bus (only one DSI bus on ESP32-P4) +static mipidsi_bus_obj_t board_mipidsi_bus; + +// ILI9881C initialization sequence +static const uint8_t ili9881c_init_sequence[] = { + 0xff, 0x03, 0x98, 0x81, 0x00, + 0x01, 0x80, 0x78, // software reset + // CMD_Page 1 + 0xff, 0x03, 0x98, 0x81, 0x01, + 0xb7, 0x01, 0x03, // set 2 lane + // CMD Page 0 + 0xff, 0x03, 0x98, 0x81, 0x00, + 0x11, 0x80, 0x0a, // out of sleep + 0x36, 0x01, 0x00, // madctl + 0x3a, 0x01, 0x55, // colmod + // CMD_Page 3 + 0xff, 0x03, 0x98, 0x81, 0x03, + 0x01, 0x01, 0x00, + 0x02, 0x01, 0x00, + 0x03, 0x01, 0x73, + 0x04, 0x01, 0x00, + 0x05, 0x01, 0x00, + 0x06, 0x01, 0x08, + 0x07, 0x01, 0x00, + 0x08, 0x01, 0x00, + 0x09, 0x01, 0x1b, + 0x0a, 0x01, 0x01, + 0x0b, 0x01, 0x01, + 0x0c, 0x01, 0x0d, + 0x0d, 0x01, 0x01, + 0x0e, 0x01, 0x01, + 0x0f, 0x01, 0x26, + 0x10, 0x01, 0x26, + 0x11, 0x01, 0x00, + 0x12, 0x01, 0x00, + 0x13, 0x01, 0x02, + 0x14, 0x01, 0x00, + 0x15, 0x01, 0x00, + 0x16, 0x01, 0x00, + 0x17, 0x01, 0x00, + 0x18, 0x01, 0x00, + 0x19, 0x01, 0x00, + 0x1a, 0x01, 0x00, + 0x1b, 0x01, 0x00, + 0x1c, 0x01, 0x00, + 0x1d, 0x01, 0x00, + 0x1e, 0x01, 0x40, + 0x1f, 0x01, 0x00, + 0x20, 0x01, 0x06, + 0x21, 0x01, 0x01, + 0x22, 0x01, 0x00, + 0x23, 0x01, 0x00, + 0x24, 0x01, 0x00, + 0x25, 0x01, 0x00, + 0x26, 0x01, 0x00, + 0x27, 0x01, 0x00, + 0x28, 0x01, 0x33, + 0x29, 0x01, 0x03, + 0x2a, 0x01, 0x00, + 0x2b, 0x01, 0x00, + 0x2c, 0x01, 0x00, + 0x2d, 0x01, 0x00, + 0x2e, 0x01, 0x00, + 0x2f, 0x01, 0x00, + 0x30, 0x01, 0x00, + 0x31, 0x01, 0x00, + 0x32, 0x01, 0x00, + 0x33, 0x01, 0x00, + 0x34, 0x01, 0x00, + 0x35, 0x01, 0x00, + 0x36, 0x01, 0x00, + 0x37, 0x01, 0x00, + 0x38, 0x01, 0x00, + 0x39, 0x01, 0x00, + 0x3a, 0x01, 0x00, + 0x3b, 0x01, 0x00, + 0x3c, 0x01, 0x00, + 0x3d, 0x01, 0x00, + 0x3e, 0x01, 0x00, + 0x3f, 0x01, 0x00, + 0x40, 0x01, 0x00, + 0x41, 0x01, 0x00, + 0x42, 0x01, 0x00, + 0x43, 0x01, 0x00, + 0x44, 0x01, 0x00, + 0x50, 0x01, 0x01, + 0x51, 0x01, 0x23, + 0x52, 0x01, 0x45, + 0x53, 0x01, 0x67, + 0x54, 0x01, 0x89, + 0x55, 0x01, 0xab, + 0x56, 0x01, 0x01, + 0x57, 0x01, 0x23, + 0x58, 0x01, 0x45, + 0x59, 0x01, 0x67, + 0x5a, 0x01, 0x89, + 0x5b, 0x01, 0xab, + 0x5c, 0x01, 0xcd, + 0x5d, 0x01, 0xef, + 0x5e, 0x01, 0x11, + 0x5f, 0x01, 0x02, + 0x60, 0x01, 0x00, + 0x61, 0x01, 0x07, + 0x62, 0x01, 0x06, + 0x63, 0x01, 0x0e, + 0x64, 0x01, 0x0f, + 0x65, 0x01, 0x0c, + 0x66, 0x01, 0x0d, + 0x67, 0x01, 0x02, + 0x68, 0x01, 0x02, + 0x69, 0x01, 0x02, + 0x6a, 0x01, 0x02, + 0x6b, 0x01, 0x02, + 0x6c, 0x01, 0x02, + 0x6d, 0x01, 0x02, + 0x6e, 0x01, 0x02, + 0x6f, 0x01, 0x02, + 0x70, 0x01, 0x02, + 0x71, 0x01, 0x02, + 0x72, 0x01, 0x02, + 0x73, 0x01, 0x05, + 0x74, 0x01, 0x01, + 0x75, 0x01, 0x02, + 0x76, 0x01, 0x00, + 0x77, 0x01, 0x07, + 0x78, 0x01, 0x06, + 0x79, 0x01, 0x0e, + 0x7a, 0x01, 0x0f, + 0x7b, 0x01, 0x0c, + 0x7c, 0x01, 0x0d, + 0x7d, 0x01, 0x02, + 0x7e, 0x01, 0x02, + 0x7f, 0x01, 0x02, + 0x80, 0x01, 0x02, + 0x81, 0x01, 0x02, + 0x82, 0x01, 0x02, + 0x83, 0x01, 0x02, + 0x84, 0x01, 0x02, + 0x85, 0x01, 0x02, + 0x86, 0x01, 0x02, + 0x87, 0x01, 0x02, + 0x88, 0x01, 0x02, + 0x89, 0x01, 0x05, + 0x8a, 0x01, 0x01, + // CMD_Page 4 + 0xff, 0x03, 0x98, 0x81, 0x04, + 0x38, 0x01, 0x01, + 0x39, 0x01, 0x00, + 0x6c, 0x01, 0x15, + 0x6e, 0x01, 0x1a, + 0x6f, 0x01, 0x25, + 0x3a, 0x01, 0xa4, + 0x8d, 0x01, 0x20, + 0x87, 0x01, 0xba, + 0x3b, 0x01, 0x98, + // CMD_Page 1 + 0xff, 0x03, 0x98, 0x81, 0x01, + 0x22, 0x01, 0x0a, + 0x31, 0x01, 0x00, + 0x50, 0x01, 0x6b, + 0x51, 0x01, 0x66, + 0x53, 0x01, 0x73, + 0x55, 0x01, 0x8b, + 0x60, 0x01, 0x1b, + 0x61, 0x01, 0x01, + 0x62, 0x01, 0x0c, + 0x63, 0x01, 0x00, + // Gamma P + 0xa0, 0x01, 0x00, + 0xa1, 0x01, 0x15, + 0xa2, 0x01, 0x1f, + 0xa3, 0x01, 0x13, + 0xa4, 0x01, 0x11, + 0xa5, 0x01, 0x21, + 0xa6, 0x01, 0x17, + 0xa7, 0x01, 0x1b, + 0xa8, 0x01, 0x6b, + 0xa9, 0x01, 0x1e, + 0xaa, 0x01, 0x2b, + 0xab, 0x01, 0x5d, + 0xac, 0x01, 0x19, + 0xad, 0x01, 0x14, + 0xae, 0x01, 0x4b, + 0xaf, 0x01, 0x1d, + 0xb0, 0x01, 0x27, + 0xb1, 0x01, 0x49, + 0xb2, 0x01, 0x5d, + 0xb3, 0x01, 0x39, + // Gamma N + 0xc0, 0x01, 0x00, + 0xc1, 0x01, 0x01, + 0xc2, 0x01, 0x0c, + 0xc3, 0x01, 0x11, + 0xc4, 0x01, 0x15, + 0xc5, 0x01, 0x28, + 0xc6, 0x01, 0x1b, + 0xc7, 0x01, 0x1c, + 0xc8, 0x01, 0x62, + 0xc9, 0x01, 0x1c, + 0xca, 0x01, 0x29, + 0xcb, 0x01, 0x60, + 0xcc, 0x01, 0x16, + 0xcd, 0x01, 0x17, + 0xce, 0x01, 0x4a, + 0xcf, 0x01, 0x23, + 0xd0, 0x01, 0x24, + 0xd1, 0x01, 0x4f, + 0xd2, 0x01, 0x5f, + 0xd3, 0x01, 0x39, + // CMD_Page 0 + 0xff, 0x03, 0x98, 0x81, 0x00, + 0x35, 0x00, + 0xfe, 0x00, + 0x29, 0x00, +}; + +// I2C addresses +#define GOODIX_TOUCH_ADDRESS 0x14 +#define ST7123_ADDRESS 0x55 +#define I2C_DEV_ADDR_PI4IOE1 0x43 + +// PI4IOE GPIO expander registers +#define PI4IO_REG_CHIP_RESET 0x01 +#define PI4IO_REG_IO_DIR 0x03 +#define PI4IO_REG_OUT_SET 0x05 +#define PI4IO_REG_OUT_H_IM 0x07 +#define PI4IO_REG_PULL_SEL 0x0D +#define PI4IO_REG_PULL_EN 0x0B + +void board_init(void) { + // Initialize I2C for GPIO expander and display detection + busio_i2c_obj_t *i2c = common_hal_board_create_i2c(0); + + // Initialize PI4IOE GPIO expander to control LCD reset + uint8_t write_buf[2]; + + common_hal_busio_i2c_try_lock(i2c); + + // Chip reset + write_buf[0] = PI4IO_REG_CHIP_RESET; + write_buf[1] = 0xFF; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Set IO direction (bit 7 as output for LCD reset) + write_buf[0] = PI4IO_REG_IO_DIR; + write_buf[1] = 0b01111111; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Set output high-impedance mode + write_buf[0] = PI4IO_REG_OUT_H_IM; + write_buf[1] = 0b00000000; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Set pull select + write_buf[0] = PI4IO_REG_PULL_SEL; + write_buf[1] = 0b01111111; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Enable pull resistors + write_buf[0] = PI4IO_REG_PULL_EN; + write_buf[1] = 0b01111111; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Set output state (including LCD reset) + write_buf[0] = PI4IO_REG_OUT_SET; + write_buf[1] = 0b01110110; + common_hal_busio_i2c_write(i2c, I2C_DEV_ADDR_PI4IOE1, write_buf, 2); + + // Small delay for reset to take effect + mp_hal_delay_ms(100); + + // Probe I2C bus to detect which display is present + bool has_goodix = common_hal_busio_i2c_probe(i2c, GOODIX_TOUCH_ADDRESS); + bool has_st7123 = common_hal_busio_i2c_probe(i2c, ST7123_ADDRESS); + + common_hal_busio_i2c_unlock(i2c); + + // Configure display parameters based on detected hardware + uint32_t bus_frequency; + uint32_t pixel_clock_frequency; + const uint8_t *init_sequence; + size_t init_sequence_len; + uint32_t hsync_pulse_width, hsync_back_porch, hsync_front_porch; + uint32_t vsync_pulse_width, vsync_back_porch, vsync_front_porch; + + if (has_goodix) { + // ILI9881C display with Goodix touch + bus_frequency = 730000000; + pixel_clock_frequency = 60000000; + init_sequence = ili9881c_init_sequence; + init_sequence_len = sizeof(ili9881c_init_sequence); + hsync_pulse_width = 40; + hsync_back_porch = 140; + hsync_front_porch = 40; + vsync_pulse_width = 4; + vsync_back_porch = 20; + vsync_front_porch = 20; + } else if (has_st7123) { + // ST7123 display + bus_frequency = 965000000; + pixel_clock_frequency = 70000000; + init_sequence = NULL; // ST7123 doesn't use init sequence + init_sequence_len = 0; + hsync_pulse_width = 2; + hsync_back_porch = 40; + hsync_front_porch = 40; + vsync_pulse_width = 2; + vsync_back_porch = 8; + vsync_front_porch = 220; + + // Not tested now + return; + } else { + return; + } + + // Initialize the statically allocated MIPI DSI bus + board_mipidsi_bus.base.type = &mipidsi_bus_type; + common_hal_mipidsi_bus_construct(&board_mipidsi_bus, bus_frequency, 2); // 2 lanes + + // Allocate display bus for the display object + primary_display_bus_t *display_bus_obj = allocate_display_bus_or_raise(); + mipidsi_display_obj_t *display = &display_bus_obj->mipidsi; + display->base.type = &mipidsi_display_type; + + common_hal_mipidsi_display_construct( + display, + &board_mipidsi_bus, // Use statically allocated bus + init_sequence, + init_sequence_len, + 0, // virtual_channel + 720, // width + 1280, // height + 0, // rotation + 16, // color_depth + &pin_GPIO22, // backlight_pin (LCD_BL) + 0.1f, // brightness + 60, // native_frames_per_second + true, // backlight_on_high + hsync_pulse_width, + hsync_back_porch, + hsync_front_porch, + vsync_pulse_width, + vsync_back_porch, + vsync_front_porch, + pixel_clock_frequency + ); + + // Create framebuffer display + framebufferio_framebufferdisplay_obj_t *fb_display = &allocate_display()->framebuffer_display; + fb_display->base.type = &framebufferio_framebufferdisplay_type; + + common_hal_framebufferio_framebufferdisplay_construct( + fb_display, + MP_OBJ_FROM_PTR(display), + 0, // rotation + true // auto_refresh + ); +} // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. From 39332eb957b274d66fae4575eaeea1ee446070a9 Mon Sep 17 00:00:00 2001 From: sam blenny <68084116+samblenny@users.noreply.github.com> Date: Mon, 8 Dec 2025 22:43:10 +0000 Subject: [PATCH 125/876] fix hashlib.new() documentation comment --- shared-bindings/hashlib/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/hashlib/__init__.c b/shared-bindings/hashlib/__init__.c index bfe19dee107..2a6517791be 100644 --- a/shared-bindings/hashlib/__init__.c +++ b/shared-bindings/hashlib/__init__.c @@ -20,7 +20,7 @@ //| //| def new(name: str, data: bytes = b"") -> hashlib.Hash: //| """Returns a Hash object setup for the named algorithm. Raises ValueError when the named -//| algorithm is unsupported. +//| algorithm is unsupported. Supported algorithms for ``name`` are ``'sha1`` and ``'sha256'``. //| //| :return: a hash object for the given algorithm //| :rtype: hashlib.Hash""" From 9133ea2273fd034117d90d8944c0460c9b993937 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 8 Dec 2025 16:15:17 -0800 Subject: [PATCH 126/876] Add board.DISPLAY() --- ports/espressif/boards/m5stack_tab5/pins.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/espressif/boards/m5stack_tab5/pins.c b/ports/espressif/boards/m5stack_tab5/pins.c index 67012cc670d..c64d8803c02 100644 --- a/ports/espressif/boards/m5stack_tab5/pins.c +++ b/ports/espressif/boards/m5stack_tab5/pins.c @@ -6,6 +6,8 @@ #include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -124,5 +126,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 7cfb1cb60faa0481bd77f20112c9f0f01c88bfa4 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 8 Dec 2025 16:19:15 -0800 Subject: [PATCH 127/876] Fix USB on P4 EV mpconfigport.h can't set a default to override circuitpy_mpconfig.h So, when using the high speed device we need to set two defines. Also, fix warning from IDF about selecting UTMI with high speed. --- .../boards/espressif_esp32p4_function_ev/mpconfigboard.h | 1 + ports/espressif/mpconfigport.h | 8 -------- ports/espressif/supervisor/usb.c | 4 ++++ 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h b/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h index 1bbf3a250fc..89a103e6196 100644 --- a/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h +++ b/ports/espressif/boards/espressif_esp32p4_function_ev/mpconfigboard.h @@ -21,5 +21,6 @@ // Use the second USB device (numbered 0 and 1) #define CIRCUITPY_USB_DEVICE_INSTANCE 1 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) #define CIRCUITPY_USB_HOST_INSTANCE 0 diff --git a/ports/espressif/mpconfigport.h b/ports/espressif/mpconfigport.h index 6b85100608c..7f1a581571e 100644 --- a/ports/espressif/mpconfigport.h +++ b/ports/espressif/mpconfigport.h @@ -69,14 +69,6 @@ extern portMUX_TYPE background_task_mutex; #define CIRCUITPY_WIFI_DEFAULT_TX_POWER (20) #endif -#ifndef CIRCUITPY_USB_DEVICE_HIGH_SPEED -#if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 1 -#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) -#else -#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (0) -#endif -#endif - #ifndef CIRCUITPY_ESP32P4_SWAP_LSFS #define CIRCUITPY_ESP32P4_SWAP_LSFS (0) #endif diff --git a/ports/espressif/supervisor/usb.c b/ports/espressif/supervisor/usb.c index 56042fce1b7..62feea6981e 100644 --- a/ports/espressif/supervisor/usb.c +++ b/ports/espressif/supervisor/usb.c @@ -66,7 +66,11 @@ void init_usb_hardware(void) { // Configure USB PHY usb_phy_config_t phy_conf = { .controller = USB_PHY_CTRL_OTG, + #if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 1 + .target = USB_PHY_TARGET_UTMI, + #else .target = USB_PHY_TARGET_INT, + #endif .otg_mode = USB_OTG_MODE_DEVICE, #if defined(CONFIG_IDF_TARGET_ESP32P4) && CIRCUITPY_USB_DEVICE_INSTANCE == 0 .otg_speed = USB_PHY_SPEED_FULL, From 75bf3bd1506f5f2362de27b5300e614f73ad1e84 Mon Sep 17 00:00:00 2001 From: Jerzeek Date: Tue, 9 Dec 2025 10:15:49 +0100 Subject: [PATCH 128/876] correct pin order --- .../studiolab_picoexpander/mpconfigboard.h | 2 +- .../studiolab_picoexpander/mpconfigboard.mk | 2 +- .../boards/studiolab_picoexpander/pins.c | 97 +++++++++++-------- 3 files changed, 60 insertions(+), 41 deletions(-) diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h index 5e2dd69f290..98e011cee99 100644 --- a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT -#define MICROPY_HW_BOARD_NAME "Pico Expander" +#define MICROPY_HW_BOARD_NAME "StudioLabPico Expander" #define MICROPY_HW_MCU_NAME "rp2350a" #define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1) diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk index 9db15479076..eabc2c41e07 100644 --- a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk @@ -1,6 +1,6 @@ USB_VID = 0x1209 USB_PID = 0xC1C1 -USB_PRODUCT = "Pico 2 W" +USB_PRODUCT = "StudioLab Pico Expander" USB_MANUFACTURER = "Raspberry Pi" CHIP_VARIANT = RP2350 diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/pins.c b/ports/raspberrypi/boards/studiolab_picoexpander/pins.c index f2c89251149..6faafbfd177 100644 --- a/ports/raspberrypi/boards/studiolab_picoexpander/pins.c +++ b/ports/raspberrypi/boards/studiolab_picoexpander/pins.c @@ -9,84 +9,103 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, - { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, - { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, - { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, - { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, - { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, - { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, - { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, - { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, - { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, - { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, - { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, - { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, - { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, - { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, - { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, - { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, - { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, - { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, - { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_BTN), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO15) }, { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, - { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, - { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) }, - { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, - { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) }, - { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, - { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, - { MP_ROM_QSTR(MP_QSTR_BTN), MP_ROM_PTR(&pin_GPIO15) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, - { MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_CYW1) }, + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, - { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_CYW0) }, + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, - { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_CYW2) }, + { MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_A26), MP_ROM_PTR(&pin_GPIO26) }, { MP_ROM_QSTR(MP_QSTR_GP26_A0), MP_ROM_PTR(&pin_GPIO26) }, { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, - { MP_ROM_QSTR(MP_QSTR_A26), MP_ROM_PTR(&pin_GPIO26) }, { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, - + { MP_ROM_QSTR(MP_QSTR_A27), MP_ROM_PTR(&pin_GPIO27) }, { MP_ROM_QSTR(MP_QSTR_GP27_A1), MP_ROM_PTR(&pin_GPIO27) }, { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, - { MP_ROM_QSTR(MP_QSTR_A27), MP_ROM_PTR(&pin_GPIO27) }, { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A28), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_GP28_A2), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, - { MP_ROM_QSTR(MP_QSTR_A28), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_SMPS_MODE), MP_ROM_PTR(&pin_CYW1) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_CYW0) }, + + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_CYW2) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, From cb8ad1fc90813354d7fc1d2dfac192216790feb7 Mon Sep 17 00:00:00 2001 From: Jerzeek Date: Tue, 9 Dec 2025 10:47:45 +0100 Subject: [PATCH 129/876] Correct board name --- ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h index 98e011cee99..ea475f68222 100644 --- a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.h @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT -#define MICROPY_HW_BOARD_NAME "StudioLabPico Expander" +#define MICROPY_HW_BOARD_NAME "Studiolab Pico Expander" #define MICROPY_HW_MCU_NAME "rp2350a" #define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1) From c8274f99a616788f77d0a3696fa4c8196230d8a1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 9 Dec 2025 09:32:54 -0600 Subject: [PATCH 130/876] update frozen libs --- frozen/Adafruit_CircuitPython_BLE | 2 +- frozen/Adafruit_CircuitPython_Display_Text | 2 +- frozen/Adafruit_CircuitPython_ESP32SPI | 2 +- frozen/Adafruit_CircuitPython_LSM6DS | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_BLE b/frozen/Adafruit_CircuitPython_BLE index 6744b6869e4..0058a10ba53 160000 --- a/frozen/Adafruit_CircuitPython_BLE +++ b/frozen/Adafruit_CircuitPython_BLE @@ -1 +1 @@ -Subproject commit 6744b6869e4c3112610132bcac23535ae5ef3983 +Subproject commit 0058a10ba53e2d7bd6bcc84c7bf10dd30ee998dd diff --git a/frozen/Adafruit_CircuitPython_Display_Text b/frozen/Adafruit_CircuitPython_Display_Text index 727a1022e14..0c4ea1b8c10 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit 727a1022e140b971a2f4bde5e6571dd327f6785d +Subproject commit 0c4ea1b8c102cdd98c91914dd09f067ea6f7b1e1 diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index 3fcea236876..0b24c52f472 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit 3fcea236876b05d09ebf95f43cec6016667ccf84 +Subproject commit 0b24c52f472f870fcd417301521a6f7895416a4e diff --git a/frozen/Adafruit_CircuitPython_LSM6DS b/frozen/Adafruit_CircuitPython_LSM6DS index e7da74fd8d7..2bf5c7fcadb 160000 --- a/frozen/Adafruit_CircuitPython_LSM6DS +++ b/frozen/Adafruit_CircuitPython_LSM6DS @@ -1 +1 @@ -Subproject commit e7da74fd8d7fddd9515e975be5479596283a719c +Subproject commit 2bf5c7fcadbb0034c0d193c5c45409f435e7329c From d38759b297e9405a5017bd9674a25a8985bf88b2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 9 Dec 2025 09:49:53 -0800 Subject: [PATCH 131/876] Fix zephyr_i2c stub --- ports/zephyr-cp/bindings/zephyr_i2c/I2C.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c index 456f3703ff5..5d9f305a479 100644 --- a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c +++ b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c @@ -275,9 +275,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_i2c_i2c_writeto_obj, 3, zephyr_i2c_i2c_writeto //| in_buffer: WriteableBuffer, //| *, //| out_start: int = 0, -//| out_end: int = None, +//| out_end: int = sys.maxsize, //| in_start: int = 0, -//| in_end: int = None +//| in_end: int = sys.maxsize //| ) -> None: //| """Write the bytes from ``out_buffer`` to the device selected by ``address``, generate //| no stop bit, generate a repeated start and read into ``in_buffer``. ``out_buffer`` and From cf9f4a5c114b45f37384a90d7328736d898d0d33 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 9 Dec 2025 13:29:59 -0800 Subject: [PATCH 132/876] Add SPI and merge zephyr_(serial|i2c) into busio Also: * Add enabling modules based on other available modules. (Such as displayio when busio is available.) * Implement ticks for display refreshes. * Be more rigorous finding flash and RAM regions. Add tests. --- .github/workflows/run-tests.yml | 84 ++- locale/circuitpython.pot | 14 +- ports/zephyr-cp/Makefile | 13 +- ports/zephyr-cp/bindings/zephyr_i2c/I2C.c | 378 ------------ ports/zephyr-cp/bindings/zephyr_i2c/I2C.h | 32 - .../zephyr-cp/bindings/zephyr_i2c/__init__.c | 27 - ports/zephyr-cp/bindings/zephyr_serial/UART.c | 291 --------- ports/zephyr-cp/bindings/zephyr_serial/UART.h | 41 -- .../bindings/zephyr_serial/__init__.c | 32 - .../bindings/zephyr_serial/__init__.h | 7 - .../nordic/nrf5340dk/autogen_board_info.toml | 42 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 42 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 42 +- .../nordic/nrf7002dk/autogen_board_info.toml | 42 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 42 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 42 +- .../nucleo_n657x0_q/autogen_board_info.toml | 42 +- .../nucleo_u575zi_q/autogen_board_info.toml | 42 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 42 +- .../common-hal/{zephyr_i2c => busio}/I2C.c | 58 +- .../common-hal/{zephyr_i2c => busio}/I2C.h | 5 +- ports/zephyr-cp/common-hal/busio/SPI.c | 281 +++++++++ ports/zephyr-cp/common-hal/busio/SPI.h | 24 + ports/zephyr-cp/common-hal/busio/UART.c | 149 +++++ .../{zephyr_serial => busio}/UART.h | 8 +- .../{zephyr_spi => busio}/__init__.c | 4 +- .../common-hal/zephyr_i2c/__init__.c | 7 - .../zephyr-cp/common-hal/zephyr_serial/UART.c | 136 ----- .../common-hal/zephyr_serial/__init__.c | 7 - ports/zephyr-cp/common-hal/zephyr_spi/SPI.c | 74 --- ports/zephyr-cp/common-hal/zephyr_spi/SPI.h | 20 - ports/zephyr-cp/cptools/build_all_boards.py | 165 ++++++ .../zephyr-cp/cptools/build_circuitpython.py | 151 ++++- ports/zephyr-cp/cptools/tests/README.md | 28 + .../zephyr-cp/cptools/tests/test_zephyr2cp.py | 550 ++++++++++++++++++ ports/zephyr-cp/cptools/zephyr2cp.py | 245 ++++++-- ports/zephyr-cp/prj.conf | 2 + ports/zephyr-cp/supervisor/port.c | 11 +- ports/zephyr-cp/supervisor/serial.c | 16 +- requirements-dev.txt | 1 + shared-bindings/board/__init__.h | 3 - shared-bindings/busio/I2C.c | 2 +- shared-bindings/busio/SPI.c | 2 +- shared-module/board/__init__.c | 27 - shared-module/displayio/Shape.c | 126 ---- shared-module/displayio/Shape.h | 28 - shared-module/displayio/__init__.c | 45 +- .../sharpdisplay/SharpMemoryFramebuffer.c | 6 +- supervisor/shared/display.c | 2 +- tools/gen_display_resources.py | 4 +- 50 files changed, 1852 insertions(+), 1632 deletions(-) delete mode 100644 ports/zephyr-cp/bindings/zephyr_i2c/I2C.c delete mode 100644 ports/zephyr-cp/bindings/zephyr_i2c/I2C.h delete mode 100644 ports/zephyr-cp/bindings/zephyr_i2c/__init__.c delete mode 100644 ports/zephyr-cp/bindings/zephyr_serial/UART.c delete mode 100644 ports/zephyr-cp/bindings/zephyr_serial/UART.h delete mode 100644 ports/zephyr-cp/bindings/zephyr_serial/__init__.c delete mode 100644 ports/zephyr-cp/bindings/zephyr_serial/__init__.h rename ports/zephyr-cp/common-hal/{zephyr_i2c => busio}/I2C.c (56%) rename ports/zephyr-cp/common-hal/{zephyr_i2c => busio}/I2C.h (67%) create mode 100644 ports/zephyr-cp/common-hal/busio/SPI.c create mode 100644 ports/zephyr-cp/common-hal/busio/SPI.h create mode 100644 ports/zephyr-cp/common-hal/busio/UART.c rename ports/zephyr-cp/common-hal/{zephyr_serial => busio}/UART.h (54%) rename ports/zephyr-cp/common-hal/{zephyr_spi => busio}/__init__.c (55%) delete mode 100644 ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c delete mode 100644 ports/zephyr-cp/common-hal/zephyr_serial/UART.c delete mode 100644 ports/zephyr-cp/common-hal/zephyr_serial/__init__.c delete mode 100644 ports/zephyr-cp/common-hal/zephyr_spi/SPI.c delete mode 100644 ports/zephyr-cp/common-hal/zephyr_spi/SPI.h create mode 100755 ports/zephyr-cp/cptools/build_all_boards.py create mode 100644 ports/zephyr-cp/cptools/tests/README.md create mode 100644 ports/zephyr-cp/cptools/tests/test_zephyr2cp.py delete mode 100644 shared-module/displayio/Shape.c delete mode 100644 shared-module/displayio/Shape.h diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 80bfc72bd98..06fe3bf6aea 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -23,36 +23,36 @@ jobs: TEST_native: --emit native TEST_native_mpy: --via-mpy --emit native -d basics float micropython steps: - - name: Set up repository - uses: actions/checkout@v4 - with: - submodules: false - show-progress: false - fetch-depth: 1 - - name: Set up python - uses: actions/setup-python@v5 - with: - python-version: 3.12 - - name: Set up submodules - uses: ./.github/actions/deps/submodules - with: - target: tests - - name: Set up external - if: matrix.test == 'all' - uses: ./.github/actions/deps/external - - name: Set up mpy-cross - uses: ./.github/actions/mpy_cross - with: - cp-version: ${{ inputs.cp-version }} - - name: Build unix port - run: make -C ports/unix VARIANT=coverage -j4 - - name: Run tests - run: ./run-tests.py -j4 ${{ env[format('TEST_{0}', matrix.test)] }} - working-directory: tests - - name: Print failure info - run: ./run-tests.py -j4 --print-failures - if: failure() - working-directory: tests + - name: Set up repository + uses: actions/checkout@v4 + with: + submodules: false + show-progress: false + fetch-depth: 1 + - name: Set up python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + - name: Set up submodules + uses: ./.github/actions/deps/submodules + with: + target: tests + - name: Set up external + if: matrix.test == 'all' + uses: ./.github/actions/deps/external + - name: Set up mpy-cross + uses: ./.github/actions/mpy_cross + with: + cp-version: ${{ inputs.cp-version }} + - name: Build unix port + run: make -C ports/unix VARIANT=coverage -j4 + - name: Run tests + run: ./run-tests.py -j4 ${{ env[format('TEST_{0}', matrix.test)] }} + working-directory: tests + - name: Print failure info + run: ./run-tests.py -j4 --print-failures + if: failure() + working-directory: tests # Not working after MicroPython v1.23 merge. # - name: Build native modules # if: matrix.test == 'all' @@ -66,3 +66,27 @@ jobs: # if: matrix.test == 'all' # run: ./run-natmodtests.py extmod/{heapq*,random*,re*}.py # working-directory: tests + + zephyr: + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + env: + CP_VERSION: ${{ inputs.cp-version }} + steps: + - name: Set up repository + uses: actions/checkout@v4 + with: + submodules: false + show-progress: false + fetch-depth: 1 + - name: Set up python + uses: actions/setup-python@v5 + with: + python-version: 3.13 + - name: Set up Zephyr + uses: ./.github/actions/deps/ports/zephyr-cp + - name: Set up external + uses: ./.github/actions/deps/external + - name: Run Zephyr build tests + run: make -C ports/zephyr-cp test diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 81074f3f804..bcc7d1dd1ca 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1117,9 +1117,8 @@ msgid "" "Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c -#: shared-bindings/busio/SPI.c +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "" @@ -1462,8 +1461,7 @@ msgstr "" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -2396,6 +2394,12 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index 217e094e3dc..037c14afad4 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,7 +8,7 @@ BUILD ?= build-$(BOARD) TRANSLATION ?= en_US -.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash debug clean menuconfig +.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash debug clean menuconfig all clean-all test $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) @@ -31,3 +31,14 @@ menuconfig: clean: rm -rf $(BUILD) + +# Build all boards. The + prefix allows jobserver file descriptors to be passed through. +# This enables parallel builds across all boards when invoked with `make -jN all`. +all: + +python cptools/build_all_boards.py --continue-on-error + +clean-all: + rm -rf build build-* + +test: + pytest cptools/tests diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c deleted file mode 100644 index 5d9f305a479..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.c +++ /dev/null @@ -1,378 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "bindings/zephyr_i2c/I2C.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/util.h" -#include "shared/runtime/buffer_helper.h" -#include "py/binary.h" -#include "py/mperrno.h" -#include "py/runtime.h" - -#include -#include - -//| class I2C: -//| """Two wire serial protocol -//| -//| I2C is a two-wire protocol for communicating between devices. At the -//| physical level it consists of 2 wires: SCL and SDA, the clock and data -//| lines respectively. -//| -//| .. class:: I2C() -//| -//| Cannot be instantiated directly. Instead singletons are created using the -//| ``board`` aliases that match the device tree labels. ``board`` may list multiple -//| aliases for a single device. For example, ``board.I2C1()`` and ``board.ARDUINO_I2C()`` -//| may both refer to the same device. -//| """ -//| - -static zephyr_i2c_i2c_obj_t *native_i2c(mp_obj_t self_in) { - mp_check_self(mp_obj_is_type(self_in, &zephyr_i2c_i2c_type)); - return MP_OBJ_TO_PTR(self_in); -} - -static void check_for_deinit(zephyr_i2c_i2c_obj_t *self) { - if (common_hal_zephyr_i2c_i2c_deinited(self)) { - raise_deinited_error(); - } -} - -static void check_lock(zephyr_i2c_i2c_obj_t *self) { - if (!common_hal_zephyr_i2c_i2c_has_lock(self)) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); - } -} - -//| def deinit(self) -> None: -//| """Releases control of the underlying hardware so other classes can use it.""" -//| ... -static mp_obj_t zephyr_i2c_i2c_obj_deinit(mp_obj_t self_in) { - zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); - common_hal_zephyr_i2c_i2c_deinit(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c_deinit_obj, zephyr_i2c_i2c_obj_deinit); - -//| def __enter__(self) -> I2C: -//| """No-op used in Context Managers.""" -//| ... -static mp_obj_t zephyr_i2c_i2c_obj___enter__(mp_obj_t self_in) { - zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); - check_for_deinit(self); - return self_in; -} -static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c___enter___obj, zephyr_i2c_i2c_obj___enter__); - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware on context exit.""" -//| ... -static mp_obj_t zephyr_i2c_i2c_obj___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_zephyr_i2c_i2c_deinit(args[0]); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(zephyr_i2c_i2c___exit___obj, 4, 4, zephyr_i2c_i2c_obj___exit__); - -//| def probe(self, address: int) -> bool: -//| """Check if a device responds at the address. -//| -//| :param int address: The 7-bit device address -//| :return: True if the device responds, False otherwise -//| :rtype: bool -//| """ -//| ... -static mp_obj_t zephyr_i2c_i2c_probe(mp_obj_t self_in, mp_obj_t addr_obj) { - zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); - check_for_deinit(self); - check_lock(self); - - mp_int_t addr = mp_obj_get_int(addr_obj); - return mp_obj_new_bool(common_hal_zephyr_i2c_i2c_probe(self, addr)); -} -static MP_DEFINE_CONST_FUN_OBJ_2(zephyr_i2c_i2c_probe_obj, zephyr_i2c_i2c_probe); - -//| def scan(self) -> List[int]: -//| """Scan all I2C addresses between 0x08 and 0x77 inclusive and return a -//| list of those that respond. -//| -//| :return: List of device addresses -//| :rtype: list -//| """ -//| ... -static mp_obj_t zephyr_i2c_i2c_scan(mp_obj_t self_in) { - zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); - check_for_deinit(self); - check_lock(self); - - mp_obj_t list = mp_obj_new_list(0, NULL); - // 7-bit addresses 0b0000xxx and 0b1111xxx are reserved - for (uint8_t addr = 0x08; addr <= 0x77; addr++) { - if (common_hal_zephyr_i2c_i2c_probe(self, addr)) { - mp_obj_list_append(list, MP_OBJ_NEW_SMALL_INT(addr)); - } - } - return list; -} -static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c_scan_obj, zephyr_i2c_i2c_scan); - -//| def try_lock(self) -> bool: -//| """Attempts to grab the I2C lock. Returns True on success. -//| -//| :return: True when lock has been grabbed -//| :rtype: bool -//| """ -//| ... -static mp_obj_t zephyr_i2c_i2c_obj_try_lock(mp_obj_t self_in) { - zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_zephyr_i2c_i2c_try_lock(self)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c_try_lock_obj, zephyr_i2c_i2c_obj_try_lock); - -//| def unlock(self) -> None: -//| """Releases the I2C lock.""" -//| ... -static mp_obj_t zephyr_i2c_i2c_obj_unlock(mp_obj_t self_in) { - zephyr_i2c_i2c_obj_t *self = native_i2c(self_in); - check_for_deinit(self); - common_hal_zephyr_i2c_i2c_unlock(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(zephyr_i2c_i2c_unlock_obj, zephyr_i2c_i2c_obj_unlock); - -//| import sys -//| -//| def readfrom_into( -//| self, address: int, buffer: WriteableBuffer, *, start: int = 0, end: int = sys.maxsize -//| ) -> None: -//| """Read into ``buffer`` from the device selected by ``address``. -//| At least one byte must be read. -//| -//| If ``start`` or ``end`` is provided, then the buffer will be sliced -//| as if ``buffer[start:end]`` were passed, but without copying the data. -//| The number of bytes read will be the length of ``buffer[start:end]``. -//| -//| :param int address: 7-bit device address -//| :param ~circuitpython_typing.WriteableBuffer buffer: buffer to write into -//| :param int start: beginning of buffer slice -//| :param int end: end of buffer slice; if not specified, use ``len(buffer)`` -//| """ -//| ... -static mp_obj_t zephyr_i2c_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_address, ARG_buffer, ARG_start, ARG_end }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, - }; - zephyr_i2c_i2c_obj_t *self = native_i2c(pos_args[0]); - check_for_deinit(self); - check_lock(self); - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); - - // Compute bounds in terms of elements, not bytes. - int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); - size_t length = bufinfo.len / stride_in_bytes; - int32_t start = args[ARG_start].u_int; - const int32_t end = args[ARG_end].u_int; - normalize_buffer_bounds(&start, end, &length); - mp_arg_validate_length_min(length, 1, MP_QSTR_buffer); - - // Treat start and length in terms of bytes from now on. - start *= stride_in_bytes; - length *= stride_in_bytes; - - uint8_t status = common_hal_zephyr_i2c_i2c_read(self, args[ARG_address].u_int, - ((uint8_t *)bufinfo.buf) + start, length); - - if (status != 0) { - mp_raise_OSError(status); - } - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_i2c_i2c_readfrom_into_obj, 3, zephyr_i2c_i2c_readfrom_into); - -//| import sys -//| -//| def writeto( -//| self, address: int, buffer: ReadableBuffer, *, start: int = 0, end: int = sys.maxsize -//| ) -> None: -//| """Write the bytes from ``buffer`` to the device selected by ``address`` and -//| then transmit a stop bit. -//| -//| If ``start`` or ``end`` is provided, then the buffer will be sliced -//| as if ``buffer[start:end]`` were passed, but without copying the data. -//| The number of bytes written will be the length of ``buffer[start:end]``. -//| -//| Writing a buffer or slice of length zero is permitted, as it can be used -//| to poll for the existence of a device. -//| -//| :param int address: 7-bit device address -//| :param ~circuitpython_typing.ReadableBuffer buffer: buffer containing the bytes to write -//| :param int start: beginning of buffer slice -//| :param int end: end of buffer slice; if not specified, use ``len(buffer)`` -//| """ -//| ... -static mp_obj_t zephyr_i2c_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_address, ARG_buffer, ARG_start, ARG_end }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, - }; - zephyr_i2c_i2c_obj_t *self = native_i2c(pos_args[0]); - check_for_deinit(self); - check_lock(self); - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - // get the buffer to write the data from - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); - int stride_in_bytes = mp_binary_get_size('@', bufinfo.typecode, NULL); - - // Compute bounds in terms of elements, not bytes. - size_t length = bufinfo.len / stride_in_bytes; - int32_t start = args[ARG_start].u_int; - const int32_t end = args[ARG_end].u_int; - normalize_buffer_bounds(&start, end, &length); - - // Treat start and length in terms of bytes from now on. - start *= stride_in_bytes; - length *= stride_in_bytes; - - uint8_t status = common_hal_zephyr_i2c_i2c_write(self, args[ARG_address].u_int, - ((uint8_t *)bufinfo.buf) + start, length); - - if (status != 0) { - mp_raise_OSError(status); - } - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_i2c_i2c_writeto_obj, 3, zephyr_i2c_i2c_writeto); - -//| import sys -//| -//| def writeto_then_readfrom( -//| self, -//| address: int, -//| out_buffer: ReadableBuffer, -//| in_buffer: WriteableBuffer, -//| *, -//| out_start: int = 0, -//| out_end: int = sys.maxsize, -//| in_start: int = 0, -//| in_end: int = sys.maxsize -//| ) -> None: -//| """Write the bytes from ``out_buffer`` to the device selected by ``address``, generate -//| no stop bit, generate a repeated start and read into ``in_buffer``. ``out_buffer`` and -//| ``in_buffer`` can be the same buffer because they are used sequentially. -//| -//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced -//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data. -//| The number of bytes written will be the length of ``out_buffer[start:end]``. -//| -//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced -//| as if ``in_buffer[in_start:in_end]`` were passed, -//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``. -//| -//| :param int address: 7-bit device address -//| :param ~circuitpython_typing.ReadableBuffer out_buffer: buffer containing the bytes to write -//| :param ~circuitpython_typing.WriteableBuffer in_buffer: buffer to write into -//| :param int out_start: beginning of ``out_buffer`` slice -//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)`` -//| :param int in_start: beginning of ``in_buffer`` slice -//| :param int in_end: end of ``in_buffer`` slice; if not specified, use ``len(in_buffer)`` -//| """ -//| ... -static mp_obj_t zephyr_i2c_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_address, ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, - { MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} }, - }; - zephyr_i2c_i2c_obj_t *self = native_i2c(pos_args[0]); - check_for_deinit(self); - check_lock(self); - - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_buffer_info_t out_bufinfo; - mp_get_buffer_raise(args[ARG_out_buffer].u_obj, &out_bufinfo, MP_BUFFER_READ); - int out_stride_in_bytes = mp_binary_get_size('@', out_bufinfo.typecode, NULL); - size_t out_length = out_bufinfo.len / out_stride_in_bytes; - int32_t out_start = args[ARG_out_start].u_int; - const int32_t out_end = args[ARG_out_end].u_int; - normalize_buffer_bounds(&out_start, out_end, &out_length); - - mp_buffer_info_t in_bufinfo; - mp_get_buffer_raise(args[ARG_in_buffer].u_obj, &in_bufinfo, MP_BUFFER_WRITE); - int in_stride_in_bytes = mp_binary_get_size('@', in_bufinfo.typecode, NULL); - size_t in_length = in_bufinfo.len / in_stride_in_bytes; - int32_t in_start = args[ARG_in_start].u_int; - const int32_t in_end = args[ARG_in_end].u_int; - normalize_buffer_bounds(&in_start, in_end, &in_length); - mp_arg_validate_length_min(in_length, 1, MP_QSTR_out_buffer); - - // Treat start and length in terms of bytes from now on. - out_start *= out_stride_in_bytes; - out_length *= out_stride_in_bytes; - in_start *= in_stride_in_bytes; - in_length *= in_stride_in_bytes; - - uint8_t status = common_hal_zephyr_i2c_i2c_write_read(self, args[ARG_address].u_int, - ((uint8_t *)out_bufinfo.buf) + out_start, out_length, - ((uint8_t *)in_bufinfo.buf) + in_start, in_length); - - if (status != 0) { - mp_raise_OSError(status); - } - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_i2c_i2c_writeto_then_readfrom_obj, 4, zephyr_i2c_i2c_writeto_then_readfrom); - -static const mp_rom_map_elem_t zephyr_i2c_i2c_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&zephyr_i2c_i2c_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&zephyr_i2c_i2c_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&zephyr_i2c_i2c___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&zephyr_i2c_i2c___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_probe), MP_ROM_PTR(&zephyr_i2c_i2c_probe_obj) }, - { MP_ROM_QSTR(MP_QSTR_scan), MP_ROM_PTR(&zephyr_i2c_i2c_scan_obj) }, - - { MP_ROM_QSTR(MP_QSTR_try_lock), MP_ROM_PTR(&zephyr_i2c_i2c_try_lock_obj) }, - { MP_ROM_QSTR(MP_QSTR_unlock), MP_ROM_PTR(&zephyr_i2c_i2c_unlock_obj) }, - - { MP_ROM_QSTR(MP_QSTR_readfrom_into), MP_ROM_PTR(&zephyr_i2c_i2c_readfrom_into_obj) }, - { MP_ROM_QSTR(MP_QSTR_writeto), MP_ROM_PTR(&zephyr_i2c_i2c_writeto_obj) }, - { MP_ROM_QSTR(MP_QSTR_writeto_then_readfrom), MP_ROM_PTR(&zephyr_i2c_i2c_writeto_then_readfrom_obj) }, -}; -static MP_DEFINE_CONST_DICT(zephyr_i2c_i2c_locals_dict, zephyr_i2c_i2c_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - zephyr_i2c_i2c_type, - MP_QSTR_I2C, - MP_TYPE_FLAG_NONE, - locals_dict, &zephyr_i2c_i2c_locals_dict - ); diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.h b/ports/zephyr-cp/bindings/zephyr_i2c/I2C.h deleted file mode 100644 index 7f7eecbea6c..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_i2c/I2C.h +++ /dev/null @@ -1,32 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/obj.h" -#include "common-hal/zephyr_i2c/I2C.h" - -extern const mp_obj_type_t zephyr_i2c_i2c_type; - -// Check if the I2C object has been deinitialized -bool common_hal_zephyr_i2c_i2c_deinited(zephyr_i2c_i2c_obj_t *self); - -// Deinitialize the I2C bus -void common_hal_zephyr_i2c_i2c_deinit(zephyr_i2c_i2c_obj_t *self); - -// Locking functions -bool common_hal_zephyr_i2c_i2c_try_lock(zephyr_i2c_i2c_obj_t *self); -bool common_hal_zephyr_i2c_i2c_has_lock(zephyr_i2c_i2c_obj_t *self); -void common_hal_zephyr_i2c_i2c_unlock(zephyr_i2c_i2c_obj_t *self); - -// Device communication functions -bool common_hal_zephyr_i2c_i2c_probe(zephyr_i2c_i2c_obj_t *self, uint8_t addr); -uint8_t common_hal_zephyr_i2c_i2c_write(zephyr_i2c_i2c_obj_t *self, uint16_t address, - const uint8_t *data, size_t len); -uint8_t common_hal_zephyr_i2c_i2c_read(zephyr_i2c_i2c_obj_t *self, uint16_t address, - uint8_t *data, size_t len); -uint8_t common_hal_zephyr_i2c_i2c_write_read(zephyr_i2c_i2c_obj_t *self, uint16_t address, - uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len); diff --git a/ports/zephyr-cp/bindings/zephyr_i2c/__init__.c b/ports/zephyr-cp/bindings/zephyr_i2c/__init__.c deleted file mode 100644 index 3274dfdb740..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_i2c/__init__.c +++ /dev/null @@ -1,27 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "py/obj.h" -#include "py/runtime.h" -#include "bindings/zephyr_i2c/I2C.h" - -//| """Zephyr I2C driver for fixed I2C busses. -//| -//| This module provides access to I2C busses using Zephyr device labels.""" - -static const mp_rom_map_elem_t zephyr_i2c_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr_i2c) }, - { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&zephyr_i2c_i2c_type) }, -}; - -static MP_DEFINE_CONST_DICT(zephyr_i2c_module_globals, zephyr_i2c_module_globals_table); - -const mp_obj_module_t zephyr_i2c_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&zephyr_i2c_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_zephyr_i2c, zephyr_i2c_module); diff --git a/ports/zephyr-cp/bindings/zephyr_serial/UART.c b/ports/zephyr-cp/bindings/zephyr_serial/UART.c deleted file mode 100644 index dbb643645f5..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_serial/UART.c +++ /dev/null @@ -1,291 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include - -#include "bindings/zephyr_serial/UART.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/util.h" - -#include "shared/runtime/context_manager_helpers.h" -#include "shared/runtime/interrupt_char.h" - -#include "py/stream.h" -#include "py/objproperty.h" -#include "py/objtype.h" -#include "py/runtime.h" -#include "py/stream.h" - -#define STREAM_DEBUG(...) (void)0 -// #define STREAM_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__) - -//| class UART: -//| """A bidirectional serial protocol. Already initialized for Zephyr defined -//| busses in :py:mod:`board`. -//| -//| .. raw:: html -//| -//|

-//|

-//| Available on these boards -//|
    -//| {% for board in support_matrix_reverse["zephyr_serial.UART"] %} -//|
  • {{ board }} -//| {% endfor %} -//|
-//|
-//|

-//| -//| """ -//| - -static void validate_timeout(mp_float_t timeout) { - mp_arg_validate_int_range((int)timeout, 0, 100, MP_QSTR_timeout); -} - -// Helper to ensure we have the native super class instead of a subclass. -static zephyr_serial_uart_obj_t *native_uart(mp_obj_t uart_obj) { - mp_obj_t native_uart = mp_obj_cast_to_native_base(uart_obj, MP_OBJ_FROM_PTR(&zephyr_serial_uart_type)); - if (native_uart == MP_OBJ_NULL) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("Must be a %q subclass."), MP_QSTR_UART); - } - mp_obj_assert_native_inited(native_uart); - return MP_OBJ_TO_PTR(native_uart); -} - - -//| def deinit(self) -> None: -//| """Deinitialises the UART and releases any hardware resources for reuse.""" -//| ... -//| -static mp_obj_t _zephyr_serial_uart_obj_deinit(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - zephyr_serial_uart_deinit(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_deinit_obj, _zephyr_serial_uart_obj_deinit); - -static void check_for_deinit(zephyr_serial_uart_obj_t *self) { - if (zephyr_serial_uart_deinited(self)) { - raise_deinited_error(); - } -} - -//| def __enter__(self) -> UART: -//| """No-op used by Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -// Provided by context manager helper. - -// These are standard stream methods. Code is in py/stream.c. -// -//| def read(self, nbytes: Optional[int] = None) -> Optional[bytes]: -//| """Read bytes. If ``nbytes`` is specified then read at most that many -//| bytes. Otherwise, read everything that arrives until the connection -//| times out. Providing the number of bytes expected is highly recommended -//| because it will be faster. If no bytes are read, return ``None``. -//| -//| .. note:: When no bytes are read due to a timeout, this function returns ``None``. -//| This matches the behavior of `io.RawIOBase.read` in Python 3, but -//| differs from pyserial which returns ``b''`` in that situation. -//| -//| :return: Data read -//| :rtype: bytes or None""" -//| ... -//| - -//| def readinto(self, buf: WriteableBuffer) -> Optional[int]: -//| """Read bytes into the ``buf``. Read at most ``len(buf)`` bytes. -//| -//| :return: number of bytes read and stored into ``buf`` -//| :rtype: int or None (on a non-blocking error) -//| -//| *New in CircuitPython 4.0:* No length parameter is permitted.""" -//| ... -//| - -//| def readline(self) -> bytes: -//| """Read a line, ending in a newline character, or -//| return ``None`` if a timeout occurs sooner, or -//| return everything readable if no newline is found and -//| ``timeout=0`` -//| -//| :return: the line read -//| :rtype: bytes or None""" -//| ... -//| - -//| def write(self, buf: ReadableBuffer) -> Optional[int]: -//| """Write the buffer of bytes to the bus. -//| -//| *New in CircuitPython 4.0:* ``buf`` must be bytes, not a string. -//| -//| :return: the number of bytes written -//| :rtype: int or None""" -//| ... -//| - -// These three methods are used by the shared stream methods. -static mp_uint_t _zephyr_serial_uart_read(mp_obj_t self_in, void *buf_in, mp_uint_t size, int *errcode) { - STREAM_DEBUG("_zephyr_serial_uart_read stream %d\n", size); - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - byte *buf = buf_in; - - // make sure we want at least 1 char - if (size == 0) { - return 0; - } - - return zephyr_serial_uart_read(self, buf, size, errcode); -} - -static mp_uint_t _zephyr_serial_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t size, int *errcode) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - const byte *buf = buf_in; - - return zephyr_serial_uart_write(self, buf, size, errcode); -} - -static mp_uint_t _zephyr_serial_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - mp_uint_t ret; - if (request == MP_STREAM_POLL) { - mp_uint_t flags = arg; - ret = 0; - if ((flags & MP_STREAM_POLL_RD) && zephyr_serial_uart_rx_characters_available(self) > 0) { - ret |= MP_STREAM_POLL_RD; - } - if ((flags & MP_STREAM_POLL_WR) && zephyr_serial_uart_ready_to_tx(self)) { - ret |= MP_STREAM_POLL_WR; - } - } else { - *errcode = MP_EINVAL; - ret = MP_STREAM_ERROR; - } - return ret; -} - -//| baudrate: int -//| """The current baudrate.""" -static mp_obj_t _zephyr_serial_uart_obj_get_baudrate(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(zephyr_serial_uart_get_baudrate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_get_baudrate_obj, _zephyr_serial_uart_obj_get_baudrate); - -static mp_obj_t _zephyr_serial_uart_obj_set_baudrate(mp_obj_t self_in, mp_obj_t baudrate) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - zephyr_serial_uart_set_baudrate(self, mp_obj_get_int(baudrate)); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(_zephyr_serial_uart_set_baudrate_obj, _zephyr_serial_uart_obj_set_baudrate); - - -MP_PROPERTY_GETSET(_zephyr_serial_uart_baudrate_obj, - (mp_obj_t)&_zephyr_serial_uart_get_baudrate_obj, - (mp_obj_t)&_zephyr_serial_uart_set_baudrate_obj); - -//| in_waiting: int -//| """The number of bytes in the input buffer, available to be read""" -static mp_obj_t _zephyr_serial_uart_obj_get_in_waiting(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(zephyr_serial_uart_rx_characters_available(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_get_in_waiting_obj, _zephyr_serial_uart_obj_get_in_waiting); - -MP_PROPERTY_GETTER(_zephyr_serial_uart_in_waiting_obj, - (mp_obj_t)&_zephyr_serial_uart_get_in_waiting_obj); - -//| timeout: float -//| """The current timeout, in seconds (float).""" -//| -static mp_obj_t _zephyr_serial_uart_obj_get_timeout(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - return mp_obj_new_float(zephyr_serial_uart_get_timeout(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_get_timeout_obj, _zephyr_serial_uart_obj_get_timeout); - -static mp_obj_t _zephyr_serial_uart_obj_set_timeout(mp_obj_t self_in, mp_obj_t timeout) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - mp_float_t timeout_float = mp_obj_get_float(timeout); - validate_timeout(timeout_float); - zephyr_serial_uart_set_timeout(self, timeout_float); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_2(_zephyr_serial_uart_set_timeout_obj, _zephyr_serial_uart_obj_set_timeout); - - -MP_PROPERTY_GETSET(_zephyr_serial_uart_timeout_obj, - (mp_obj_t)&_zephyr_serial_uart_get_timeout_obj, - (mp_obj_t)&_zephyr_serial_uart_set_timeout_obj); - -//| def reset_input_buffer(self) -> None: -//| """Discard any unread characters in the input buffer.""" -//| ... -//| -//| -static mp_obj_t _zephyr_serial_uart_obj_reset_input_buffer(mp_obj_t self_in) { - zephyr_serial_uart_obj_t *self = native_uart(self_in); - check_for_deinit(self); - zephyr_serial_uart_clear_rx_buffer(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(_zephyr_serial_uart_reset_input_buffer_obj, _zephyr_serial_uart_obj_reset_input_buffer); - -static const mp_rom_map_elem_t _zephyr_serial_uart_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&_zephyr_serial_uart_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&_zephyr_serial_uart_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - - // Standard stream methods. - { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) }, - { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj)}, - { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, - { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, - - { MP_ROM_QSTR(MP_QSTR_reset_input_buffer), MP_ROM_PTR(&_zephyr_serial_uart_reset_input_buffer_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&_zephyr_serial_uart_baudrate_obj) }, - { MP_ROM_QSTR(MP_QSTR_in_waiting), MP_ROM_PTR(&_zephyr_serial_uart_in_waiting_obj) }, - { MP_ROM_QSTR(MP_QSTR_timeout), MP_ROM_PTR(&_zephyr_serial_uart_timeout_obj) }, - -}; -static MP_DEFINE_CONST_DICT(_zephyr_serial_uart_locals_dict, _zephyr_serial_uart_locals_dict_table); - -static const mp_stream_p_t uart_stream_p = { - .read = _zephyr_serial_uart_read, - .write = _zephyr_serial_uart_write, - .ioctl = _zephyr_serial_uart_ioctl, - .is_text = false, - // Disallow optional length argument for .readinto() - .pyserial_readinto_compatibility = true, -}; - -MP_DEFINE_CONST_OBJ_TYPE( - zephyr_serial_uart_type, - MP_QSTR_UART, - MP_TYPE_FLAG_ITER_IS_ITERNEXT | MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - locals_dict, &_zephyr_serial_uart_locals_dict, - iter, mp_stream_unbuffered_iter, - protocol, &uart_stream_p - ); diff --git a/ports/zephyr-cp/bindings/zephyr_serial/UART.h b/ports/zephyr-cp/bindings/zephyr_serial/UART.h deleted file mode 100644 index 704b9a2d605..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_serial/UART.h +++ /dev/null @@ -1,41 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/zephyr_serial/UART.h" -#include "py/ringbuf.h" - -#include - -extern const mp_obj_type_t zephyr_serial_uart_type; - -// Construct an underlying UART object. -extern void zephyr_serial_uart_construct(zephyr_serial_uart_obj_t *self, - const struct device *const uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer); - -extern void zephyr_serial_uart_deinit(zephyr_serial_uart_obj_t *self); -extern bool zephyr_serial_uart_deinited(zephyr_serial_uart_obj_t *self); - -// Read characters. len is in characters NOT bytes! -extern size_t zephyr_serial_uart_read(zephyr_serial_uart_obj_t *self, - uint8_t *data, size_t len, int *errcode); - -// Write characters. len is in characters NOT bytes! -extern size_t zephyr_serial_uart_write(zephyr_serial_uart_obj_t *self, - const uint8_t *data, size_t len, int *errcode); - -extern uint32_t zephyr_serial_uart_get_baudrate(zephyr_serial_uart_obj_t *self); -extern void zephyr_serial_uart_set_baudrate(zephyr_serial_uart_obj_t *self, uint32_t baudrate); -extern mp_float_t zephyr_serial_uart_get_timeout(zephyr_serial_uart_obj_t *self); -extern void zephyr_serial_uart_set_timeout(zephyr_serial_uart_obj_t *self, mp_float_t timeout); - -extern uint32_t zephyr_serial_uart_rx_characters_available(zephyr_serial_uart_obj_t *self); -extern void zephyr_serial_uart_clear_rx_buffer(zephyr_serial_uart_obj_t *self); -extern bool zephyr_serial_uart_ready_to_tx(zephyr_serial_uart_obj_t *self); - -extern void zephyr_serial_uart_never_reset(zephyr_serial_uart_obj_t *self); diff --git a/ports/zephyr-cp/bindings/zephyr_serial/__init__.c b/ports/zephyr-cp/bindings/zephyr_serial/__init__.c deleted file mode 100644 index f4a3c7b92e3..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_serial/__init__.c +++ /dev/null @@ -1,32 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include - -#include "py/obj.h" -#include "py/runtime.h" - -#include "shared-bindings/microcontroller/Pin.h" -#include "bindings/zephyr_serial/__init__.h" -#include "bindings/zephyr_serial/UART.h" - -#include "py/runtime.h" - -//| """Zephyr UART driver for fixed busses.""" - -static const mp_rom_map_elem_t zephyr_serial_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr_serial) }, - { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&zephyr_serial_uart_type) }, -}; - -static MP_DEFINE_CONST_DICT(zephyr_serial_module_globals, zephyr_serial_module_globals_table); - -const mp_obj_module_t zephyr_serial_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&zephyr_serial_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_zephyr_serial, zephyr_serial_module); diff --git a/ports/zephyr-cp/bindings/zephyr_serial/__init__.h b/ports/zephyr-cp/bindings/zephyr_serial/__init__.h deleted file mode 100644 index 370e233985f..00000000000 --- a/ports/zephyr-cp/bindings/zephyr_serial/__init__.h +++ /dev/null @@ -1,7 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft -// -// SPDX-License-Identifier: MIT - -#pragma once diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index c59e03c323e..5c1e64aedc7 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = true @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false -zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index d4017cae4da..dfb363f2ed8 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = false @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false -zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index dbffa5944d9..227e4a2f6c1 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = false @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false -zephyr_i2c = false zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 2d723cbced6..104a2111525 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = true # Zephyr networking enabled spitarget = false ssl = true # Zephyr networking enabled storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = true @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = true # Zephyr board has wifi -zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 8c522296da6..c2d9048604f 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = false # No TinyUSB settings for r7fa6m5bh3cfc @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false -zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 5c79b0e962e..4b004746f90 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = false # No TinyUSB settings for r7fa8d1bhecbd @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false -zephyr_i2c = false zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 7a5beb79e44..4b9fbf5c110 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = false struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = false # No TinyUSB settings for stm32n657xx @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false -zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index a3183f180ae..01e3314fa5a 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = false struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = true @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false -zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index bf6a2828743..9ec442d4cfa 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -26,31 +26,31 @@ audiomp3 = false audiopwmio = false aurora_epaper = false bitbangio = false -bitmapfilter = false -bitmaptools = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio bitops = false board = false -busdisplay = false -busio = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio camera = false canio = false codeop = false countio = false digitalio = true -displayio = false +displayio = true # Zephyr board has busio dotclockframebuffer = false dualbank = false -epaperdisplay = false +epaperdisplay = true # Zephyr board has busio floppyio = false -fontio = false -fourwire = false -framebufferio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio frequencyio = false getpass = false gifio = false gnss = false hashlib = false -i2cdisplaybus = false +i2cdisplaybus = true # Zephyr board has busio i2ctarget = false imagecapture = false ipaddress = false @@ -59,7 +59,7 @@ jpegio = false keypad = false keypad_demux = false locale = false -lvfontio = false +lvfontio = true # Zephyr board has busio math = false max3421e = false mdns = false @@ -77,27 +77,27 @@ ps2io = false pulseio = false pwmio = false qrio = false -rainbowio = false +rainbowio = true random = true rclcpy = false rgbmatrix = false rotaryio = false rtc = false -sdcardio = false +sdcardio = true # Zephyr board has busio sdioio = false -sharpdisplay = false +sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false storage = true # Zephyr board has flash struct = true -supervisor = false +supervisor = true synthio = false -terminalio = false -tilepalettemapper = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio time = true touchio = false -traceback = false +traceback = true uheap = false usb = false usb_cdc = false @@ -106,11 +106,9 @@ usb_host = false usb_midi = false usb_video = false ustack = false -vectorio = false -warnings = false +vectorio = true # Zephyr board has busio +warnings = true watchdog = false wifi = false -zephyr_i2c = true # Zephyr board has zephyr_i2c zephyr_kernel = false -zephyr_serial = true # Zephyr board has zephyr_serial zlib = false diff --git a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c b/ports/zephyr-cp/common-hal/busio/I2C.c similarity index 56% rename from ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c rename to ports/zephyr-cp/common-hal/busio/I2C.c index 12ce95c282d..49def727a53 100644 --- a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.c +++ b/ports/zephyr-cp/common-hal/busio/I2C.c @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT -#include "bindings/zephyr_i2c/I2C.h" +#include "shared-bindings/busio/I2C.h" #include "py/mperrno.h" #include "py/runtime.h" @@ -12,27 +12,40 @@ #include #include -mp_obj_t zephyr_i2c_i2c_zephyr_init(zephyr_i2c_i2c_obj_t *self, const struct device *i2c_device) { - self->base.type = &zephyr_i2c_i2c_type; +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_i2c_construct_from_device(busio_i2c_obj_t *self, const struct device *i2c_device) { + self->base.type = &busio_i2c_type; self->i2c_device = i2c_device; k_mutex_init(&self->mutex); + self->has_lock = false; return MP_OBJ_FROM_PTR(self); } -bool common_hal_zephyr_i2c_i2c_deinited(zephyr_i2c_i2c_obj_t *self) { - // Always leave it active +// Standard busio construct - not used in Zephyr port (devices come from device tree) +void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, + const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, + uint32_t frequency, uint32_t timeout_ms) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_I2C); +} + +bool common_hal_busio_i2c_deinited(busio_i2c_obj_t *self) { + // Always leave it active (managed by Zephyr) return false; } -void common_hal_zephyr_i2c_i2c_deinit(zephyr_i2c_i2c_obj_t *self) { - if (common_hal_zephyr_i2c_i2c_deinited(self)) { +void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { return; } - // Always leave it active + // Always leave it active (managed by Zephyr) +} + +void common_hal_busio_i2c_mark_deinit(busio_i2c_obj_t *self) { + // Not needed for Zephyr port } -bool common_hal_zephyr_i2c_i2c_probe(zephyr_i2c_i2c_obj_t *self, uint8_t addr) { - if (common_hal_zephyr_i2c_i2c_deinited(self)) { +bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { + if (common_hal_busio_i2c_deinited(self)) { return false; } @@ -42,8 +55,8 @@ bool common_hal_zephyr_i2c_i2c_probe(zephyr_i2c_i2c_obj_t *self, uint8_t addr) { return ret == 0; } -bool common_hal_zephyr_i2c_i2c_try_lock(zephyr_i2c_i2c_obj_t *self) { - if (common_hal_zephyr_i2c_i2c_deinited(self)) { +bool common_hal_busio_i2c_try_lock(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { return false; } @@ -51,18 +64,19 @@ bool common_hal_zephyr_i2c_i2c_try_lock(zephyr_i2c_i2c_obj_t *self) { return self->has_lock; } -bool common_hal_zephyr_i2c_i2c_has_lock(zephyr_i2c_i2c_obj_t *self) { +bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { return self->has_lock; } -void common_hal_zephyr_i2c_i2c_unlock(zephyr_i2c_i2c_obj_t *self) { +void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + self->has_lock = false; k_mutex_unlock(&self->mutex); } -uint8_t common_hal_zephyr_i2c_i2c_write(zephyr_i2c_i2c_obj_t *self, uint16_t addr, +uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { - if (common_hal_zephyr_i2c_i2c_deinited(self)) { + if (common_hal_busio_i2c_deinited(self)) { return MP_EIO; } @@ -82,10 +96,10 @@ uint8_t common_hal_zephyr_i2c_i2c_write(zephyr_i2c_i2c_obj_t *self, uint16_t add return 0; } -uint8_t common_hal_zephyr_i2c_i2c_read(zephyr_i2c_i2c_obj_t *self, uint16_t addr, +uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - if (common_hal_zephyr_i2c_i2c_deinited(self)) { + if (common_hal_busio_i2c_deinited(self)) { return MP_EIO; } @@ -109,10 +123,10 @@ uint8_t common_hal_zephyr_i2c_i2c_read(zephyr_i2c_i2c_obj_t *self, uint16_t addr return 0; } -uint8_t common_hal_zephyr_i2c_i2c_write_read(zephyr_i2c_i2c_obj_t *self, uint16_t addr, +uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - if (common_hal_zephyr_i2c_i2c_deinited(self)) { + if (common_hal_busio_i2c_deinited(self)) { return MP_EIO; } @@ -132,3 +146,7 @@ uint8_t common_hal_zephyr_i2c_i2c_write_read(zephyr_i2c_i2c_obj_t *self, uint16_ return 0; } + +void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { + // Not needed for Zephyr port (devices are managed by Zephyr) +} diff --git a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h b/ports/zephyr-cp/common-hal/busio/I2C.h similarity index 67% rename from ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h rename to ports/zephyr-cp/common-hal/busio/I2C.h index 0265511e208..4fa877739b7 100644 --- a/ports/zephyr-cp/common-hal/zephyr_i2c/I2C.h +++ b/ports/zephyr-cp/common-hal/busio/I2C.h @@ -14,6 +14,7 @@ typedef struct { const struct device *i2c_device; struct k_mutex mutex; bool has_lock; -} zephyr_i2c_i2c_obj_t; +} busio_i2c_obj_t; -mp_obj_t zephyr_i2c_i2c_zephyr_init(zephyr_i2c_i2c_obj_t *self, const struct device *i2c_device); +// Helper function to construct from Zephyr device tree device +mp_obj_t common_hal_busio_i2c_construct_from_device(busio_i2c_obj_t *self, const struct device *i2c_device); diff --git a/ports/zephyr-cp/common-hal/busio/SPI.c b/ports/zephyr-cp/common-hal/busio/SPI.c new file mode 100644 index 00000000000..2864c90b490 --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/SPI.c @@ -0,0 +1,281 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/busio/SPI.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/gc.h" +#include "shared/runtime/interrupt_char.h" +#include "supervisor/port.h" + +#include +#include +#include + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_spi_construct_from_device(busio_spi_obj_t *self, const struct device *spi_device) { + self->base.type = &busio_spi_type; + self->spi_device = spi_device; + k_mutex_init(&self->mutex); + self->has_lock = false; + self->active_config = 0; + + k_poll_signal_init(&self->signal); + + // Default configuration for both config slots + self->config[0].frequency = 100000; + self->config[0].operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_LINES_SINGLE; + self->config[1].frequency = 100000; + self->config[1].operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(8) | SPI_LINES_SINGLE; + + return MP_OBJ_FROM_PTR(self); +} + +// Standard busio construct - not used in Zephyr port (devices come from device tree) +void common_hal_busio_spi_construct(busio_spi_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *miso, bool half_duplex) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_SPI); +} + +bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { + // Always leave it active + return false; +} + +void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return; + } + // Always leave it active +} + +void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { + // Not needed for Zephyr port +} + +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + self->has_lock = k_mutex_lock(&self->mutex, K_NO_WAIT) == 0; + return self->has_lock; +} + +bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { + return self->has_lock; +} + +void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { + self->has_lock = false; + k_mutex_unlock(&self->mutex); +} + +bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + // Set operation mode based on polarity and phase + uint16_t operation = SPI_OP_MODE_MASTER | SPI_WORD_SET(bits) | SPI_LINES_SINGLE; + + if (polarity) { + operation |= SPI_MODE_CPOL; + } + if (phase) { + operation |= SPI_MODE_CPHA; + } + + // Check if settings have changed. We must switch to the other config slot if they have because + // Zephyr drivers are allowed to use the pointer value to know if it has changed. + struct spi_config *current_config = &self->config[self->active_config]; + if (current_config->frequency != baudrate || current_config->operation != operation) { + // Settings changed, switch to the other config slot + self->active_config = 1 - self->active_config; + + // Update the new active configuration + self->config[self->active_config].frequency = baudrate; + self->config[self->active_config].operation = operation; + } + + return true; +} + +bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + if (len == 0) { + return true; + } + + const struct spi_buf tx_buf = { + .buf = (void *)data, + .len = len + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + // Initialize the signal for async operation + k_poll_signal_reset(&self->signal); + + int ret = spi_transceive_signal(self->spi_device, &self->config[self->active_config], &tx, NULL, &self->signal); + if (ret != 0) { + return false; + } + + // Wait for the transfer to complete while running background tasks + int signaled = 0; + int result = 0; + while (!signaled && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + k_poll_signal_check(&self->signal, &signaled, &result); + } + + return signaled && result == 0; +} + +bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + if (len == 0) { + return true; + } + + // For read, we need to write dummy bytes + // We'll allocate a temporary buffer if write_value is not 0 + uint8_t *tx_data = NULL; + bool need_free = false; + bool used_port_malloc = false; + + if (write_value != 0) { + // Use port_malloc if GC isn't active, otherwise use m_malloc + if (gc_alloc_possible()) { + tx_data = m_malloc(len); + } else { + tx_data = port_malloc(len, false); + used_port_malloc = true; + } + if (tx_data == NULL) { + return false; + } + memset(tx_data, write_value, len); + need_free = true; + } + + const struct spi_buf tx_buf = { + .buf = tx_data, + .len = tx_data ? len : 0 + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = tx_data ? 1 : 0 + }; + + const struct spi_buf rx_buf = { + .buf = data, + .len = len + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1 + }; + + // Initialize the signal for async operation + k_poll_signal_reset(&self->signal); + + int ret = spi_transceive_signal(self->spi_device, &self->config[self->active_config], &tx, &rx, &self->signal); + + if (need_free) { + if (used_port_malloc) { + port_free(tx_data); + } else { + m_free(tx_data); + } + } + + if (ret != 0) { + return false; + } + + // Wait for the transfer to complete while running background tasks + int signaled = 0; + int result = 0; + while (!signaled && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + k_poll_signal_check(&self->signal, &signaled, &result); + } + + return signaled && result == 0; +} + +bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { + if (common_hal_busio_spi_deinited(self)) { + return false; + } + + if (len == 0) { + return true; + } + + const struct spi_buf tx_buf = { + .buf = (void *)data_out, + .len = len + }; + const struct spi_buf_set tx = { + .buffers = &tx_buf, + .count = 1 + }; + + const struct spi_buf rx_buf = { + .buf = data_in, + .len = len + }; + const struct spi_buf_set rx = { + .buffers = &rx_buf, + .count = 1 + }; + + // Initialize the signal for async operation + k_poll_signal_reset(&self->signal); + + int ret = spi_transceive_signal(self->spi_device, &self->config[self->active_config], &tx, &rx, &self->signal); + if (ret != 0) { + return false; + } + + // Wait for the transfer to complete while running background tasks + int signaled = 0; + int result = 0; + while (!signaled && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + k_poll_signal_check(&self->signal, &signaled, &result); + } + + return signaled && result == 0; +} + +uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) { + return self->config[self->active_config].frequency; +} + +uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self) { + return (self->config[self->active_config].operation & SPI_MODE_CPHA) ? 1 : 0; +} + +uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { + return (self->config[self->active_config].operation & SPI_MODE_CPOL) ? 1 : 0; +} + +void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { + // Not needed for Zephyr port (devices are managed by Zephyr) +} diff --git a/ports/zephyr-cp/common-hal/busio/SPI.h b/ports/zephyr-cp/common-hal/busio/SPI.h new file mode 100644 index 00000000000..87411c9825c --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/SPI.h @@ -0,0 +1,24 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include +#include + +typedef struct { + mp_obj_base_t base; + const struct device *spi_device; + struct k_mutex mutex; + bool has_lock; + struct spi_config config[2]; // Two configs for pointer comparison by driver + uint8_t active_config; // Index of currently active config (0 or 1) + struct k_poll_signal signal; +} busio_spi_obj_t; + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_spi_construct_from_device(busio_spi_obj_t *self, const struct device *spi_device); diff --git a/ports/zephyr-cp/common-hal/busio/UART.c b/ports/zephyr-cp/common-hal/busio/UART.c new file mode 100644 index 00000000000..cecce48d45b --- /dev/null +++ b/ports/zephyr-cp/common-hal/busio/UART.c @@ -0,0 +1,149 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/busio/UART.h" + +#include "shared/runtime/interrupt_char.h" +#include "py/mpconfig.h" +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include +#include + +#include +#include +LOG_MODULE_REGISTER(busio_uart); + +/* + * Read characters from UART until line end is detected. Afterwards push the + * data to the message queue. + */ +static void serial_cb(const struct device *dev, void *user_data) { + busio_uart_obj_t *self = (busio_uart_obj_t *)user_data; + + uint8_t c; + + if (!uart_irq_update(dev)) { + return; + } + + if (!uart_irq_rx_ready(dev)) { + return; + } + + /* read until FIFO empty */ + while (uart_fifo_read(dev, &c, 1) == 1) { + if (mp_interrupt_char == c) { + common_hal_busio_uart_clear_rx_buffer(self); + mp_sched_keyboard_interrupt(); + } else if (!self->rx_paused) { + if (k_msgq_put(&self->msgq, &c, K_NO_WAIT) != 0) { + self->rx_paused = true; + } + } + } +} + +void common_hal_busio_uart_never_reset(busio_uart_obj_t *self) { + // Not needed for Zephyr port (devices are managed by Zephyr) +} + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_uart_construct_from_device(busio_uart_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer) { + self->base.type = &busio_uart_type; + self->uart_device = uart_device; + int ret = uart_irq_callback_user_data_set(uart_device, serial_cb, self); + + if (ret < 0) { + LOG_ERR("Failed to set UART IRQ callback: %d", ret); + } + + k_msgq_init(&self->msgq, receiver_buffer, 1, receiver_buffer_size); + + self->timeout = K_USEC(100); + self->rx_paused = false; + uart_irq_rx_enable(uart_device); + + return MP_OBJ_FROM_PTR(self); +} + +// Standard busio construct - not used in Zephyr port (devices come from device tree) +void common_hal_busio_uart_construct(busio_uart_obj_t *self, + const mcu_pin_obj_t *tx, const mcu_pin_obj_t *rx, + const mcu_pin_obj_t *rts, const mcu_pin_obj_t *cts, + const mcu_pin_obj_t *rs485_dir, bool rs485_invert, + uint32_t baudrate, uint8_t bits, busio_uart_parity_t parity, uint8_t stop, + mp_float_t timeout, uint16_t receiver_buffer_size, byte *receiver_buffer, + bool sigint_enabled) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_UART); +} + +bool common_hal_busio_uart_deinited(busio_uart_obj_t *self) { + return !device_is_ready(self->uart_device); +} + +void common_hal_busio_uart_deinit(busio_uart_obj_t *self) { + // Leave it active (managed by Zephyr) +} + +// Read characters. +size_t common_hal_busio_uart_read(busio_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { + size_t count = 0; + while (count < len && k_msgq_get(&self->msgq, data + count, self->timeout) == 0) { + count++; + } + if (count > 0) { + self->rx_paused = false; + } + + return count; +} + +// Write characters. +size_t common_hal_busio_uart_write(busio_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { + for (int i = 0; i < len; i++) { + uart_poll_out(self->uart_device, data[i]); + } + + return len; +} + +uint32_t common_hal_busio_uart_get_baudrate(busio_uart_obj_t *self) { + struct uart_config config; + uart_config_get(self->uart_device, &config); + return config.baudrate; +} + +void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrate) { + struct uart_config config; + uart_config_get(self->uart_device, &config); + config.baudrate = baudrate; + uart_config_set(self->uart_device, &config); +} + +mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { + return (mp_float_t)self->timeout.ticks / 1000000.0; +} + +void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeout) { + self->timeout = K_USEC((uint64_t)(timeout * 1000000)); +} + +uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { + return k_msgq_num_used_get(&self->msgq); +} + +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self) { + k_msgq_purge(&self->msgq); +} + +bool common_hal_busio_uart_ready_to_tx(busio_uart_obj_t *self) { + return true; +} diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/UART.h b/ports/zephyr-cp/common-hal/busio/UART.h similarity index 54% rename from ports/zephyr-cp/common-hal/zephyr_serial/UART.h rename to ports/zephyr-cp/common-hal/busio/UART.h index eb3cdd746c7..27cd76c537b 100644 --- a/ports/zephyr-cp/common-hal/zephyr_serial/UART.h +++ b/ports/zephyr-cp/common-hal/busio/UART.h @@ -19,6 +19,10 @@ typedef struct { k_timeout_t timeout; bool rx_paused; // set by irq if no space in rbuf -} zephyr_serial_uart_obj_t; +} busio_uart_obj_t; -mp_obj_t zephyr_serial_uart_zephyr_init(zephyr_serial_uart_obj_t *self, const struct device *uart_device); +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_busio_uart_construct_from_device(busio_uart_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer); + +// Internal helper for clearing buffer +void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self); diff --git a/ports/zephyr-cp/common-hal/zephyr_spi/__init__.c b/ports/zephyr-cp/common-hal/busio/__init__.c similarity index 55% rename from ports/zephyr-cp/common-hal/zephyr_spi/__init__.c rename to ports/zephyr-cp/common-hal/busio/__init__.c index d3a4d472733..135a53f4907 100644 --- a/ports/zephyr-cp/common-hal/zephyr_spi/__init__.c +++ b/ports/zephyr-cp/common-hal/busio/__init__.c @@ -1,7 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// SPDX-FileCopyrightText: Copyright (c) 2025 Adafruit Industries LLC // // SPDX-License-Identifier: MIT -// No zephyr_spi module functions. +// No busio module functions. diff --git a/ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c b/ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c deleted file mode 100644 index db93a442f04..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_i2c/__init__.c +++ /dev/null @@ -1,7 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC -// -// SPDX-License-Identifier: MIT - -// No zephyr_i2c module functions. diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/UART.c b/ports/zephyr-cp/common-hal/zephyr_serial/UART.c deleted file mode 100644 index 55e9c424ffe..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_serial/UART.c +++ /dev/null @@ -1,136 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/microcontroller/__init__.h" -#include "bindings/zephyr_serial/UART.h" - -#include "shared/runtime/interrupt_char.h" -#include "py/mpconfig.h" -#include "py/gc.h" -#include "py/mperrno.h" -#include "py/runtime.h" -#include "py/stream.h" - -#include -#include - -#include - -/* - * Read characters from UART until line end is detected. Afterwards push the - * data to the message queue. - */ -static void serial_cb(const struct device *dev, void *user_data) { - zephyr_serial_uart_obj_t *self = (zephyr_serial_uart_obj_t *)user_data; - - uint8_t c; - - if (!uart_irq_update(dev)) { - return; - } - - if (!uart_irq_rx_ready(dev)) { - return; - } - - /* read until FIFO empty */ - while (uart_fifo_read(dev, &c, 1) == 1) { - if (mp_interrupt_char == c) { - zephyr_serial_uart_clear_rx_buffer(self); - mp_sched_keyboard_interrupt(); - } else if (!self->rx_paused) { - if (k_msgq_put(&self->msgq, &c, K_NO_WAIT) != 0) { - self->rx_paused = true; - } - } - } -} - -void zephyr_serial_uart_never_reset(zephyr_serial_uart_obj_t *self) { -} - - -void zephyr_serial_uart_construct(zephyr_serial_uart_obj_t *self, const struct device *const uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer) { - self->uart_device = uart_device; - int ret = uart_irq_callback_user_data_set(uart_device, serial_cb, self); - - - k_msgq_init(&self->msgq, receiver_buffer, 1, receiver_buffer_size); - - if (ret < 0) { - if (ret == -ENOTSUP) { - printk("Interrupt-driven UART API support not enabled\n"); - } else if (ret == -ENOSYS) { - printk("UART device does not support interrupt-driven API\n"); - } else { - printk("Error setting UART callback: %d\n", ret); - } - return; - } - self->timeout = K_USEC(100); - uart_irq_rx_enable(uart_device); -} - -mp_obj_t zephyr_serial_uart_zephyr_init(zephyr_serial_uart_obj_t *self, const struct device *uart_device) { - self->base.type = &zephyr_serial_uart_type; - zephyr_serial_uart_construct(self, uart_device, 128, NULL); - return MP_OBJ_FROM_PTR(self); -} - -bool zephyr_serial_uart_deinited(zephyr_serial_uart_obj_t *self) { - return !device_is_ready(self->uart_device); -} - -void zephyr_serial_uart_deinit(zephyr_serial_uart_obj_t *self) { -} - -// Read characters. -size_t zephyr_serial_uart_read(zephyr_serial_uart_obj_t *self, uint8_t *data, size_t len, int *errcode) { - size_t count = 0; - while (count < len && k_msgq_get(&self->msgq, data + count, self->timeout) == 0) { - count++; - } - if (count > 0) { - self->rx_paused = false; - } - - return count; -} - -// Write characters. -size_t zephyr_serial_uart_write(zephyr_serial_uart_obj_t *self, const uint8_t *data, size_t len, int *errcode) { - for (int i = 0; i < len; i++) { - uart_poll_out(self->uart_device, data[i]); - } - - return len; -} - -uint32_t zephyr_serial_uart_get_baudrate(zephyr_serial_uart_obj_t *self) { - return 0; -} - -void zephyr_serial_uart_set_baudrate(zephyr_serial_uart_obj_t *self, uint32_t baudrate) { -} - -mp_float_t zephyr_serial_uart_get_timeout(zephyr_serial_uart_obj_t *self) { - return 0; -} - -void zephyr_serial_uart_set_timeout(zephyr_serial_uart_obj_t *self, mp_float_t timeout) { -} - -uint32_t zephyr_serial_uart_rx_characters_available(zephyr_serial_uart_obj_t *self) { - return k_msgq_num_used_get(&self->msgq); -} - -void zephyr_serial_uart_clear_rx_buffer(zephyr_serial_uart_obj_t *self) { - k_msgq_purge(&self->msgq); -} - -bool zephyr_serial_uart_ready_to_tx(zephyr_serial_uart_obj_t *self) { - return true; -} diff --git a/ports/zephyr-cp/common-hal/zephyr_serial/__init__.c b/ports/zephyr-cp/common-hal/zephyr_serial/__init__.c deleted file mode 100644 index 2784446ba15..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_serial/__init__.c +++ /dev/null @@ -1,7 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC -// -// SPDX-License-Identifier: MIT - -// No zephyr_serial module functions. diff --git a/ports/zephyr-cp/common-hal/zephyr_spi/SPI.c b/ports/zephyr-cp/common-hal/zephyr_spi/SPI.c deleted file mode 100644 index 5601492fd69..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_spi/SPI.c +++ /dev/null @@ -1,74 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries -// SPDX-FileCopyrightText: Copyright (c) 2018 Artur Pacholec -// -// SPDX-License-Identifier: MIT - -#include - -#include "shared-bindings/busio/SPI.h" -#include "py/mperrno.h" -#include "py/runtime.h" - -void spi_reset(void) { -} - -void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { -} - -void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { - -} - -bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { -} - -void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { - if (common_hal_busio_spi_deinited(self)) { - return; - } -} - -bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { - return true; -} - -bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { - if (common_hal_busio_spi_deinited(self)) { - return false; - } - bool grabbed_lock = false; - return grabbed_lock; -} - -bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { - return self->has_lock; -} - -void common_hal_busio_spi_unlock(busio_spi_obj_t *self) { - self->has_lock = false; -} - -bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) { - return true; -} - -bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) { - return true; -} - -bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) { - return true; -} - -uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) { -} - -uint8_t common_hal_busio_spi_get_phase(busio_spi_obj_t *self) { - return 0; -} - -uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) { - return 0; -} diff --git a/ports/zephyr-cp/common-hal/zephyr_spi/SPI.h b/ports/zephyr-cp/common-hal/zephyr_spi/SPI.h deleted file mode 100644 index 5a1c91c8f0f..00000000000 --- a/ports/zephyr-cp/common-hal/zephyr_spi/SPI.h +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Scott Shawcroft -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - // const spim_peripheral_t *spim_peripheral; - bool has_lock; - uint8_t clock_pin_number; - uint8_t MOSI_pin_number; - uint8_t MISO_pin_number; -} busio_spi_obj_t; - -void spi_reset(void); diff --git a/ports/zephyr-cp/cptools/build_all_boards.py b/ports/zephyr-cp/cptools/build_all_boards.py new file mode 100755 index 00000000000..8ad6bd05ea9 --- /dev/null +++ b/ports/zephyr-cp/cptools/build_all_boards.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +""" +Build all CircuitPython boards for the Zephyr port. + +This script discovers all boards by finding circuitpython.toml files +and builds each one sequentially, passing through the jobserver for +parallelism within each build. +""" + +import argparse +import pathlib +import subprocess +import sys +import time + + +def discover_boards(port_dir): + """ + Discover all boards by finding circuitpython.toml files. + + Returns a list of (vendor, board) tuples. + """ + boards = [] + boards_dir = port_dir / "boards" + + # Find all circuitpython.toml files + for toml_file in boards_dir.glob("*/*/circuitpython.toml"): + # Extract vendor and board from path: boards/vendor/board/circuitpython.toml + parts = toml_file.relative_to(boards_dir).parts + if len(parts) == 3: + vendor = parts[0] + board = parts[1] + boards.append((vendor, board)) + + return sorted(boards) + + +def build_board(port_dir, vendor, board, extra_args=None): + """ + Build a single board using make. + + Args: + port_dir: Path to the zephyr-cp port directory + vendor: Board vendor name + board: Board name + extra_args: Additional arguments to pass to make + + Returns: + (success: bool, elapsed_time: float) + """ + board_id = f"{vendor}_{board}" + start_time = time.time() + + cmd = ["make", f"BOARD={board_id}"] + + # Add extra arguments (like -j) + if extra_args: + cmd.extend(extra_args) + + try: + subprocess.run( + cmd, + cwd=port_dir, + check=True, + # Inherit stdin to pass through jobserver file descriptors + stdin=sys.stdin, + # Show output in real-time + stdout=None, + stderr=None, + capture_output=True, + ) + elapsed = time.time() - start_time + return True, elapsed + except subprocess.CalledProcessError: + elapsed = time.time() - start_time + return False, elapsed + except KeyboardInterrupt: + raise + + +def main(): + parser = argparse.ArgumentParser( + description="Build all CircuitPython boards for the Zephyr port", + formatter_class=argparse.RawDescriptionHelpFormatter, + epilog=""" +Examples: + # Build all boards sequentially with 32 parallel jobs per board + %(prog)s -j32 + + # Build all boards using make's jobserver (recommended) + make -j32 all +""", + ) + parser.add_argument( + "-j", + "--jobs", + type=str, + default=None, + help="Number of parallel jobs for each board build (passed to make)", + ) + parser.add_argument( + "--continue-on-error", + action="store_true", + help="Continue building remaining boards even if one fails", + ) + + args = parser.parse_args() + + # Get the port directory + port_dir = pathlib.Path(__file__).parent.resolve().parent + + # Discover all boards + boards = discover_boards(port_dir) + + if not boards: + print("ERROR: No boards found!") + return 1 + + # Prepare extra make arguments + extra_args = [] + if args.jobs: + extra_args.append(f"-j{args.jobs}") + + # Build all boards + start_time = time.time() + results = [] + + try: + for index, (vendor, board) in enumerate(boards): + board_id = f"{vendor}_{board}" + print(f"{index + 1}/{len(boards)} {board_id}: ", end="", flush=True) + + success, elapsed = build_board(port_dir, vendor, board, extra_args) + if success: + print(f"✅ SUCCESS ({elapsed:.1f}s)") + else: + print(f"❌ FAILURE ({elapsed:.1f}s)") + results.append((vendor, board, success, elapsed)) + + if not success and not args.continue_on_error: + print("\nStopping due to build failure.") + break + except KeyboardInterrupt: + print("\n\nBuild interrupted by user.") + return 130 # Standard exit code for SIGINT + + # Print summary + total_time = time.time() - start_time + print(f"\n{'=' * 80}") + print("Build Summary") + print(f"{'=' * 80}") + + successful = [r for r in results if r[2]] + failed = [r for r in results if not r[2]] + + print(f"\nTotal boards: {len(results)}/{len(boards)}") + print(f"Successful: {len(successful)}") + print(f"Failed: {len(failed)}") + print(f"Total time: {total_time:.1f}s") + + return 0 if len(failed) == 0 else 1 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index abb1969470a..87ff00a4503 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -51,8 +51,34 @@ "json", "random", "digitalio", + "rainbowio", + "traceback", + "warnings", + "supervisor", ] -MPCONFIG_FLAGS = ["ulab", "nvm", "displayio", "warnings", "alarm", "array", "json"] +# Flags that don't match with with a *bindings module. +MPCONFIG_FLAGS = ["array", "json"] + +# List of other modules (the value) that can be enabled when another one (the key) is. +REVERSE_DEPENDENCIES = { + "busio": ["fourwire", "i2cdisplaybus", "sdcardio", "sharpdisplay"], + "fourwire": ["displayio", "busdisplay", "epaperdisplay"], + "i2cdisplaybus": ["displayio", "busdisplay", "epaperdisplay"], + "displayio": [ + "vectorio", + "bitmapfilter", + "bitmaptools", + "terminalio", + "lvfontio", + "tilepalettemapper", + "fontio", + ], + "sharpdisplay": ["framebufferio"], + "framebufferio": ["displayio"], +} + +# Other flags to set when a module is enabled +EXTRA_FLAGS = {"busio": ["BUSIO_SPI", "BUSIO_I2C"]} async def preprocess_and_split_defs(compiler, source_file, build_path, flags): @@ -83,10 +109,17 @@ async def preprocess_and_split_defs(compiler, source_file, build_path, flags): async def collect_defs(mode, build_path): output_file = build_path / f"{mode}defs.collected" splitdir = build_path / "genhdr" / mode + to_collect = list(splitdir.glob(f"**/*.{mode}")) + batch_size = 50 await cpbuild.run_command( - ["cat", "-s", *splitdir.glob(f"**/*.{mode}"), ">", output_file], + ["cat", "-s", *to_collect[:batch_size], ">", output_file], splitdir, ) + for i in range(0, len(to_collect), batch_size): + await cpbuild.run_command( + ["cat", "-s", *to_collect[i : i + batch_size], ">>", output_file], + splitdir, + ) return output_file @@ -161,6 +194,79 @@ async def generate_root_pointer_header(build_path): ) +async def generate_display_resources(output_path, translation, font, extra_characters): + await cpbuild.run_command( + [ + "python", + srcdir / "tools" / "gen_display_resources.py", + "--font", + srcdir / font, + "--sample_file", + srcdir / "locale" / f"{translation}.po", + "--extra_characters", + repr(extra_characters), + "--output_c_file", + output_path, + ], + srcdir, + check_hash=[output_path], + ) + + +def determine_enabled_modules(board_info, portdir, srcdir): + """Determine which CircuitPython modules should be enabled based on board capabilities. + + Args: + board_info: Dictionary containing board hardware capabilities + portdir: Path to the port directory (ports/zephyr-cp) + srcdir: Path to the CircuitPython source root + + Returns: + tuple: (enabled_modules set, module_reasons dict) + """ + enabled_modules = set(DEFAULT_MODULES) + module_reasons = {} + + if board_info["wifi"]: + enabled_modules.add("wifi") + module_reasons["wifi"] = "Zephyr board has wifi" + + if board_info["flash_count"] > 0: + enabled_modules.add("storage") + module_reasons["storage"] = "Zephyr board has flash" + + if "wifi" in enabled_modules: + enabled_modules.add("socketpool") + enabled_modules.add("ssl") + module_reasons["socketpool"] = "Zephyr networking enabled" + module_reasons["ssl"] = "Zephyr networking enabled" + + for port_module in (portdir / "bindings").iterdir(): + if not board_info.get(port_module.name, False): + continue + enabled_modules.add(port_module.name) + module_reasons[port_module.name] = f"Zephyr board has {port_module.name}" + + for shared_module in (srcdir / "shared-bindings").iterdir(): + if not board_info.get(shared_module.name, False) or not shared_module.glob("*.c"): + continue + enabled_modules.add(shared_module.name) + module_reasons[shared_module.name] = f"Zephyr board has {shared_module.name}" + + more_modules = [] + more_modules.extend(REVERSE_DEPENDENCIES.get(shared_module.name, [])) + while more_modules: + reverse_dependency = more_modules.pop(0) + if reverse_dependency in enabled_modules: + continue + logger.debug(f"Enabling {reverse_dependency} because {shared_module.name} is enabled") + enabled_modules.add(reverse_dependency) + more_modules.extend(REVERSE_DEPENDENCIES.get(reverse_dependency, [])) + module_reasons[reverse_dependency] = f"Zephyr board has {shared_module.name}" + + return enabled_modules, module_reasons + + TINYUSB_SETTINGS = { "": { "CFG_TUSB_MCU": "OPT_MCU_MIMXRT10XX", @@ -275,27 +381,7 @@ async def build_circuitpython(): autogen_board_info_fn = mpconfigboard_fn.parent / "autogen_board_info.toml" - enabled_modules = set(DEFAULT_MODULES) - module_reasons = {} - if board_info["wifi"]: - enabled_modules.add("wifi") - module_reasons["wifi"] = "Zephyr board has wifi" - - if board_info["flash_count"] > 0: - enabled_modules.add("storage") - module_reasons["storage"] = "Zephyr board has flash" - - if "wifi" in enabled_modules: - enabled_modules.add("socketpool") - enabled_modules.add("ssl") - module_reasons["socketpool"] = "Zephyr networking enabled" - module_reasons["ssl"] = "Zephyr networking enabled" - - for port_module in (portdir / "bindings").iterdir(): - if not board_info.get(port_module.name, False): - continue - enabled_modules.add(port_module.name) - module_reasons[port_module.name] = f"Zephyr board has {port_module.name}" + enabled_modules, module_reasons = determine_enabled_modules(board_info, portdir, srcdir) circuitpython_flags.extend(board_info["cflags"]) supervisor_source = [ @@ -484,7 +570,8 @@ async def build_circuitpython(): list(top.glob("shared-bindings/*")) + list(portdir.glob("bindings/*")), key=lambda x: x.name, ): - if not module.is_dir(): + # Skip files and directories without C source files (like artifacts from a docs build) + if not module.is_dir() or len(list(module.glob("*.c"))) == 0: continue enabled = module.name in enabled_modules # print(f"Module {module.name} enabled: {enabled}") @@ -494,6 +581,11 @@ async def build_circuitpython(): autogen_modules.add(module.name, v) circuitpython_flags.append(f"-DCIRCUITPY_{module.name.upper()}={1 if enabled else 0}") + if enabled: + if module.name in EXTRA_FLAGS: + for flag in EXTRA_FLAGS[module.name]: + circuitpython_flags.append(f"-DCIRCUITPY_{flag}=1") + if enabled: hal_source.extend(portdir.glob(f"bindings/{module.name}/*.c")) hal_source.extend(top.glob(f"ports/zephyr-cp/common-hal/{module.name}/*.c")) @@ -563,6 +655,17 @@ async def build_circuitpython(): tg.create_task(generate_module_header(board_build)) tg.create_task(generate_root_pointer_header(board_build)) + if "terminalio" in enabled_modules: + output_path = board_build / f"autogen_display_resources-{translation}.c" + font_path = srcdir / mpconfigboard.get( + "CIRCUITPY_DISPLAY_FONT", "tools/fonts/ter-u12n.bdf" + ) + extra_characters = mpconfigboard.get("CIRCUITPY_FONT_EXTRA_CHARACTERS", "") + tg.create_task( + generate_display_resources(output_path, translation, font_path, extra_characters) + ) + source_files.append(output_path) + # This file is generated by the QSTR/translation process. source_files.append(builddir / f"translations-{translation}.c") # These files don't include unique QSTRs. They just need to be compiled. diff --git a/ports/zephyr-cp/cptools/tests/README.md b/ports/zephyr-cp/cptools/tests/README.md new file mode 100644 index 00000000000..6bc8aa43ce6 --- /dev/null +++ b/ports/zephyr-cp/cptools/tests/README.md @@ -0,0 +1,28 @@ +# Zephyr2CP Tests + +This directory contains unit tests for the `zephyr2cp.py` module using real device tree parsing and pytest. + +## Running Tests + +To run all tests: +```bash +cd /home/tannewt/repos/circuitpython/ports/zephyr-cp +make test +``` + +For verbose output: +```bash +pytest test_zephyr2cp.py -v +``` + +To run specific test classes: +```bash +pytest test_zephyr2cp.py::TestFindFlashDevices -v +pytest test_zephyr2cp.py::TestFindRAMRegions -v +pytest test_zephyr2cp.py::TestIntegration -v +``` + +To run a specific test: +```bash +pytest test_zephyr2cp.py::TestFindFlashDevices::test_valid_flash_device -v +``` diff --git a/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py b/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py new file mode 100644 index 00000000000..95a07930e98 --- /dev/null +++ b/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py @@ -0,0 +1,550 @@ +import sys +import pathlib +import tempfile + +# Add devicetree library to path +portdir = pathlib.Path(__file__).parent.parent.parent +sys.path.append(str(portdir / "zephyr/scripts/dts/python-devicetree/src/")) + +from devicetree import dtlib + +# Add parent directory to path to import zephyr2cp +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent)) + +# Mock cpbuild before importing +sys.modules["cpbuild"] = type(sys)("cpbuild") +sys.modules["cpbuild"].run_in_thread = lambda x: x + +from zephyr2cp import find_flash_devices, find_ram_regions, BLOCKED_FLASH_COMPAT, MINIMUM_RAM_SIZE + + +def parse_dts_string(dts_content): + """ + Parse a device tree string and return the dtlib.DT object. + + Args: + dts_content: String containing device tree source + + Returns: + dtlib.DT object with parsed device tree + """ + with tempfile.NamedTemporaryFile(mode="w", suffix=".dts", delete=False) as f: + f.write(dts_content) + f.flush() + temp_path = f.name + + try: + dt = dtlib.DT(temp_path) + return dt + finally: + pathlib.Path(temp_path).unlink() + + +class TestFindFlashDevices: + """Test suite for find_flash_devices function.""" + + def test_no_compatible_returns_empty(self): + """Test that device tree with no flash devices returns empty list.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + memory@0 { + reg = <0x0 0x100000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert result == [] + + def test_chosen_flash_excluded(self): + """Test that chosen flash nodes are excluded.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 0x100000>; + }; + + chosen { + zephyr,flash = &flash0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert result == [], "Chosen flash should be excluded" + + def test_blocked_compat_excluded(self): + """Test that blocked compatible strings are excluded.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + qspi0: qspi@40000 { + compatible = "renesas,ra-qspi"; + reg = <0x40000 0x1000>; + }; + + spi0: spi@50000 { + compatible = "nordic,nrf-spim"; + reg = <0x50000 0x1000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert result == [], "Blocked flash controllers should be excluded" + + def test_valid_flash_device(self): + """Test that valid flash device is detected.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0 0x100000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert len(result) == 1 + assert result[0] == "flash0" + + def test_valid_flash_device_multiple_drivers(self): + """Test that valid flash device is detected.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "other,driver", "jedec,spi-nor"; + reg = <0x0 0x100000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert len(result) == 1 + assert result[0] == "flash0" + + def test_external_flash_not_chosen(self): + """Test external flash is included when internal is chosen.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + internal_flash: flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 0x100000>; + }; + + external_flash: flash@1000000 { + compatible = "jedec,spi-nor"; + reg = <0x1000000 0x800000>; + }; + + chosen { + zephyr,flash = &internal_flash; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + + # Should only include external flash, not chosen internal flash + assert len(result) == 1 + assert "external_flash" in result[0] + assert "internal_flash" not in result[0] + + def test_disabled_flash_excluded(self): + """Test that disabled flash devices are excluded.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0 0x100000>; + status = "disabled"; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_flash_devices(dt) + assert result == [], "Disabled flash should be excluded" + + +class TestFindRAMRegions: + """Test suite for find_ram_regions function.""" + + def test_no_ram_returns_empty(self): + """Test that device tree with no RAM returns empty list.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 0x100000>; + }; + + chosen { + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + assert result == [] + + def test_chosen_sram_basic(self): + """Test chosen sram region is detected correctly.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + + assert len(result) == 1 + label, start, end, size, path = result[0] + + assert label == "sram0" + assert start == "z_mapped_end" + assert ( + end + == "(uint32_t*) (DT_REG_ADDR(DT_NODELABEL(sram0)) + DT_REG_SIZE(DT_NODELABEL(sram0)))" + ) + assert size == 0x40000 + + def test_memory_region_with_custom_name(self): + """Test memory region with zephyr,memory-region property.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + + reserved_mem: memory@30000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x30000000 0x10000>; + zephyr,memory-region = "CUSTOM_REGION"; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + + # Should have both regions, chosen first + assert len(result) == 2 + + # First should be chosen SRAM + assert result[0][0] == "sram0" + + # Second should be custom region + label, start, end, size, path = result[1] + assert label == "reserved_mem" + assert start == "__CUSTOM_REGION_end" + + def test_disabled_ram_excluded(self): + """Test that disabled RAM regions are excluded.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + + sram1: memory@30000000 { + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x30000000 0x10000>; + status = "disabled"; + zephyr,memory-region = "CUSTOM_REGION"; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + + # Should only have chosen SRAM, not disabled one + assert len(result) == 1 + assert result[0][0] == "sram0" + + +class TestIntegration: + """Integration tests with realistic device tree configurations.""" + + def test_typical_nrf_board_configuration(self): + """Test typical Nordic nRF board with internal and external flash.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + soc { + #address-cells = <1>; + #size-cells = <1>; + + flash0: flash@0 { + compatible = "soc-nv-flash"; + reg = <0x0 0x100000>; + }; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + }; + + external_flash: spi_flash@0 { + compatible = "jedec,spi-nor"; + reg = <0x0 0x800000>; + }; + + chosen { + zephyr,flash = &flash0; + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + + # Test flash detection + flashes = find_flash_devices(dt) + assert len(flashes) == 1, "Should find external flash only" + assert "external_flash" in flashes[0] + + # Test RAM detection + rams = find_ram_regions(dt) + assert len(rams) == 1, "Should find chosen SRAM only" + assert rams[0][0] == "sram0" + + def test_board_with_nrf5340_regions(self): + """Test that RAM subregions are included with the right addresses.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + chosen { + zephyr,sram = &sram0_image; + }; + /* node '/soc/peripheral@50000000/qspi@2b000' defined in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:475 */ + qspi: qspi@2b000 { + compatible = "nordic,nrf-qspi"; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:476 */ + #address-cells = < 0x1 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:477 */ + #size-cells = < 0x0 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:478 */ + reg = < 0x2b000 0x1000 >, + < 0x10000000 0x10000000 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:479 */ + reg-names = "qspi", + "qspi_mm"; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:480 */ + interrupts = < 0x2b 0x1 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_peripherals.dtsi:481 */ + status = "okay"; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:118 */ + + /* node '/soc/peripheral@50000000/qspi@2b000/mx25r6435f@0' defined in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:123 */ + mx25r64: mx25r6435f@0 { + compatible = "nordic,qspi-nor"; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:124 */ + reg = < 0x0 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:125 */ + writeoc = "pp4io"; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:127 */ + readoc = "read4io"; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:129 */ + sck-frequency = < 0x7a1200 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:130 */ + jedec-id = [ C2 28 17 ]; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:131 */ + sfdp-bfp = [ E5 20 F1 FF FF FF FF 03 44 EB 08 6B 08 3B 04 BB EE FF FF FF FF FF 00 FF FF FF 00 + FF 0C 20 0F 52 10 D8 00 FF 23 72 F5 00 82 ED 04 CC 44 83 68 44 30 B0 30 B0 F7 C4 + D5 5C 00 BE 29 FF F0 D0 FF FF ]; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:132 */ + size = < 0x4000000 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:136 */ + has-dpd; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:137 */ + t-enter-dpd = < 0x2710 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:138 */ + t-exit-dpd = < 0x88b8 >; /* in zephyr/boards/nordic/nrf5340dk/nrf5340_cpuapp_common.dtsi:139 */ + }; + }; + + /* node '/soc/memory@20000000' defined in zephyr/dts/arm/nordic/nrf5340_cpuapp.dtsi:55 */ + sram0: memory@20000000 { + compatible = "mmio-sram"; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp.dtsi:56 */ + #address-cells = < 0x1 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp.dtsi:57 */ + #size-cells = < 0x1 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp.dtsi:58 */ + reg = < 0x20000000 0x80000 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi:15 */ + ranges = < 0x0 0x20000000 0x80000 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_qkaa.dtsi:16 */ + + /* node '/soc/memory@20000000/sram@0' defined in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:16 */ + sram0_image: sram@0 { + reg = < 0x0 0x70000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:18 */ + ranges = < 0x0 0x0 0x70000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:19 */ + #address-cells = < 0x1 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:20 */ + #size-cells = < 0x1 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:21 */ + + /* node '/soc/memory@20000000/sram@0/sram0_image@0' defined in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:23 */ + sram0_s: sram0_image@0 { + reg = < 0x0 0x40000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:25 */ + }; + }; + + /* node '/soc/memory@20000000/sram@40000' defined in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:33 */ + sram0_ns: sram@40000 { + reg = < 0x40000 0x40000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:35 */ + ranges = < 0x0 0x40000 0x40000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:36 */ + #address-cells = < 0x1 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:37 */ + #size-cells = < 0x1 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:38 */ + + /* node '/soc/memory@20000000/sram@40000/sram0_ns@0' defined in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:40 */ + sram0_ns_app: sram0_ns@0 { + reg = < 0x0 0x30000 >; /* in zephyr/dts/vendor/nordic/nrf5340_sram_partition.dtsi:42 */ + }; + }; + + /* node '/soc/memory@20000000/sram@70000' defined in zephyr/dts/vendor/nordic/nrf5340_shared_sram_partition.dtsi:27 */ + sram0_shared: sram@70000 { + reg = < 0x70000 0x10000 >; /* in zephyr/dts/vendor/nordic/nrf5340_shared_sram_partition.dtsi:29 */ + phandle = < 0x11 >; /* in zephyr/dts/arm/nordic/nrf5340_cpuapp_ipc.dtsi:9 */ + }; + }; +}; +""" + dt = parse_dts_string(dts) + flashes = find_flash_devices(dt) + rams = find_ram_regions(dt) + + # Should only get chosen SRAM + assert len(rams) == 1 + assert rams[0][0] == "sram0_image" + + assert len(flashes) == 1 + assert flashes[0] == "mx25r64" + + def test_board_with_chosen_memory_region(self): + """Test that RAM subregions are included with the right addresses.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + chosen { + zephyr,sram = &axisram2; /* in zephyr/boards/st/nucleo_n657x0_q/nucleo_n657x0_q_common.dtsi:18 */ + }; + + + /* node '/memory@34000000' defined in zephyr/dts/arm/st/n6/stm32n6.dtsi:42 */ + axisram1: memory@34000000 { + compatible = "zephyr,memory-region", + "mmio-sram"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:43 */ + zephyr,memory-region = "AXISRAM1"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:44 */ + reg = < 0x34000000 0x200000 >; /* in zephyr/dts/arm/st/n6/stm32n657X0.dtsi:12 */ + }; + + /* node '/memory@34180400' defined in zephyr/dts/arm/st/n6/stm32n6.dtsi:47 */ + axisram2: memory@34180400 { + compatible = "zephyr,memory-region", + "mmio-sram"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:48 */ + zephyr,memory-region = "AXISRAM2"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:49 */ + reg = < 0x34180400 0x7fc00 >; /* in zephyr/dts/arm/st/n6/stm32n657X0.dtsi:17 */ + }; + + /* node '/soc/ramcfg@42023100' defined in zephyr/dts/arm/st/n6/stm32n6.dtsi:251 */ + ramcfg_sram3_axi: ramcfg@42023100 { + compatible = "st,stm32n6-ramcfg"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:252 */ + #address-cells = < 0x1 >; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:253 */ + #size-cells = < 0x1 >; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:254 */ + reg = < 0x42023100 0x80 >; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:255 */ + + /* node '/soc/ramcfg@42023100/memory@34200000' defined in zephyr/dts/arm/st/n6/stm32n6.dtsi:259 */ + axisram3: memory@34200000 { + compatible = "zephyr,memory-region", + "mmio-sram"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:260 */ + zephyr,memory-region = "AXISRAM3"; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:261 */ + zephyr,memory-attr = < 0x100000 >; /* in zephyr/dts/arm/st/n6/stm32n6.dtsi:262 */ + reg = < 0x34200000 0x70000 >; /* in zephyr/dts/arm/st/n6/stm32n657X0.dtsi:23 */ + status = "disabled"; /* in zephyr/dts/arm/st/n6/stm32n657X0.dtsi:24 */ + }; + }; +}; +""" + dt = parse_dts_string(dts) + rams = find_ram_regions(dt) + + print(rams) + + # Should only get chosen SRAM + assert len(rams) == 2 + assert rams[0][0] == "axisram2" + assert rams[1][0] == "axisram1" diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 9d238a03bd8..8cfbc0118a7 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -19,6 +19,7 @@ "nordic_nrf_uarte": "serial", "nordic_nrf_uart": "serial", "nordic_nrf_twim": "i2c", + "nordic_nrf_spim": "spi", } # These are controllers, not the flash devices themselves. @@ -28,7 +29,7 @@ "nordic,nrf-spim", ) -DRIVER_CLASSES = {"serial": "UART", "i2c": "I2C", "spi": "SPI"} +BUSIO_CLASSES = {"serial": "UART", "i2c": "I2C", "spi": "SPI"} CONNECTORS = { "mikro-bus": [ @@ -194,6 +195,151 @@ EXCEPTIONAL_DRIVERS = ["entropy", "gpio", "led"] +def find_flash_devices(device_tree): + """ + Find all flash devices from a device tree. + + Args: + device_tree: Parsed device tree (dtlib.DT object) + + Returns: + List of device tree flash device reference strings + """ + # Build path2chosen mapping + path2chosen = {} + for k in device_tree.root.nodes["chosen"].props: + value = device_tree.root.nodes["chosen"].props[k] + path2chosen[value.to_path()] = k + + flashes = [] + logger.debug("Flash devices:") + + # Traverse all nodes in the device tree + remaining_nodes = set([device_tree.root]) + while remaining_nodes: + node = remaining_nodes.pop() + remaining_nodes.update(node.nodes.values()) + + # Get compatible strings + compatible = [] + if "compatible" in node.props: + compatible = node.props["compatible"].to_strings() + + # Get status + status = node.props.get("status", None) + if status is None: + status = "okay" + else: + status = status.to_string() + + # Check if this is a flash device + if not compatible or status != "okay": + continue + + # Check for flash driver via compat2driver + drivers = [] + for c in compatible: + underscored = c.replace(",", "_").replace("-", "_") + driver = COMPAT_TO_DRIVER.get(underscored, None) + if not driver: + driver = MANUAL_COMPAT_TO_DRIVER.get(underscored, None) + if driver: + drivers.append(driver) + logger.debug(f" {node.labels[0] if node.labels else node.name} drivers: {drivers}") + + if "flash" not in drivers: + continue + + # Skip chosen nodes because they are used by Zephyr + if node in path2chosen: + logger.debug( + f" skipping flash {node.labels[0] if node.labels else node.name} (chosen)" + ) + continue + + # Skip blocked flash compatibles (controllers, not actual flash devices) + if compatible[0] in BLOCKED_FLASH_COMPAT: + logger.debug( + f" skipping flash {node.labels[0] if node.labels else node.name} (blocked compat)" + ) + continue + + if node.labels: + flashes.append(node.labels[0]) + + logger.debug("Flash devices:") + for flash in flashes: + logger.debug(f" {flash}") + + return flashes + + +def _label_to_end(label): + return f"(uint32_t*) (DT_REG_ADDR(DT_NODELABEL({label})) + DT_REG_SIZE(DT_NODELABEL({label})))" + + +def find_ram_regions(device_tree): + """ + Find all RAM regions from a device tree. Includes the zephyr,sram node and + any zephyr,memory-region nodes. + + Returns: + List of RAM region info tuples: (label, start, end, size, path) + """ + rams = [] + chosen = None + # Get the chosen SRAM node directly + if "zephyr,sram" in device_tree.root.nodes["chosen"].props: + chosen = device_tree.root.nodes["chosen"].props["zephyr,sram"].to_path() + label = chosen.labels[0] + size = chosen.props["reg"].to_nums()[1] + logger.debug(f"Found chosen SRAM node: {label} with size {size}") + rams.append((label, "z_mapped_end", _label_to_end(label), size, chosen.path)) + + # Traverse all nodes in the device tree to find memory-region nodes + remaining_nodes = set([device_tree.root]) + while remaining_nodes: + node = remaining_nodes.pop() + + # Check status first so we don't add child nodes that aren't active. + status = node.props.get("status", None) + if status is None: + status = "okay" + else: + status = status.to_string() + + if status != "okay": + continue + + if node == chosen: + continue + + remaining_nodes.update(node.nodes.values()) + + if "compatible" not in node.props or not node.labels: + continue + + compatible = node.props["compatible"].to_strings() + + if "zephyr,memory-region" not in compatible or "zephyr,memory-region" not in node.props: + continue + + size = node.props["reg"].to_nums()[1] + + start = "__" + node.props["zephyr,memory-region"].to_string() + "_end" + end = _label_to_end(node.labels[0]) + + # Filter by minimum size + if size >= MINIMUM_RAM_SIZE: + logger.debug( + f"Adding extra RAM info: ({node.labels[0]}, {start}, {end}, {size}, {node.path})" + ) + info = (node.labels[0], start, end, size, node.path) + rams.append(info) + + return rams + + @cpbuild.run_in_thread def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 board_dir = builddir / "board" @@ -228,31 +374,33 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 # board_name = board_id_yaml["name"] dts = zephyrbuilddir / "zephyr.dts" - edt_pickle = dtlib.DT(dts) + device_tree = dtlib.DT(dts) node2alias = {} - for alias in edt_pickle.alias2node: - node = edt_pickle.alias2node[alias] + for alias in device_tree.alias2node: + node = device_tree.alias2node[alias] if node not in node2alias: node2alias[node] = [] node2alias[node].append(alias) ioports = {} all_ioports = [] board_names = {} - flashes = [] - rams = [] status_led = None status_led_inverted = False path2chosen = {} chosen2path = {} + # Find flash and RAM regions using extracted functions + flashes = find_flash_devices(device_tree) + rams = find_ram_regions(device_tree) # Returns filtered and sorted list + # Store active Zephyr device labels per-driver so that we can make them available via board. active_zephyr_devices = {} usb_num_endpoint_pairs = 0 - for k in edt_pickle.root.nodes["chosen"].props: - value = edt_pickle.root.nodes["chosen"].props[k] + for k in device_tree.root.nodes["chosen"].props: + value = device_tree.root.nodes["chosen"].props[k] path2chosen[value.to_path()] = k chosen2path[k] = value.to_path() - remaining_nodes = set([edt_pickle.root]) + remaining_nodes = set([device_tree.root]) while remaining_nodes: node = remaining_nodes.pop() remaining_nodes.update(node.nodes.values()) @@ -273,50 +421,16 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 if node in path2chosen: chosen = path2chosen[node] logger.debug(f" chosen: {chosen}") - if not compatible and chosen == "zephyr,sram": - # The designated sram region may not have any compatible properties, - # so we assume it is compatible with mmio - compatible.append("mmio") for c in compatible: underscored = c.replace(",", "_").replace("-", "_") driver = COMPAT_TO_DRIVER.get(underscored, None) - if "mmio" in c: - address, size = node.props["reg"].to_nums() - end = address + size - if chosen == "zephyr,sram": - start = "z_mapped_end" - elif "zephyr,memory-region" in node.props: - start = "__" + node.props["zephyr,memory-region"].to_string() + "_end" - else: - # Check to see if the chosen sram is a subset of this region. If it is, - # then do as above for a smaller region and assume the rest is reserved. - chosen_sram = chosen2path["zephyr,sram"] - chosen_address, chosen_size = chosen_sram.props["reg"].to_nums() - chosen_end = chosen_address + chosen_size - if address <= chosen_address <= end and address <= chosen_end <= end: - start = "z_mapped_end" - address = chosen_address - size = chosen_size - end = chosen_end - else: - start = address - info = (node.labels[0], start, end, size, node.path) - if chosen == "zephyr,sram": - rams.insert(0, info) - elif status == "okay" and size > MINIMUM_RAM_SIZE: - logger.debug(f"Adding RAM info: {info}") - rams.append(info) if not driver: driver = MANUAL_COMPAT_TO_DRIVER.get(underscored, None) logger.debug(f" {c} -> {underscored} -> {driver}") if not driver or status != "okay": continue if driver == "flash": - if not chosen and compatible[0] not in BLOCKED_FLASH_COMPAT: - # Skip chosen nodes because they are used by Zephyr. - flashes.append(f"DEVICE_DT_GET(DT_NODELABEL({node.labels[0]}))") - else: - logger.debug(" skipping due to blocked compat") + pass # Handled by find_flash_devices() elif driver == "usb/udc": board_info["usb_device"] = True props = node.props @@ -335,9 +449,10 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 board_info["wifi"] = True elif driver in EXCEPTIONAL_DRIVERS: pass - elif (portdir / f"bindings/zephyr_{driver}").exists(): - board_info[f"zephyr_{driver}"] = True - logger.info(f"Supported driver: {driver}") + elif driver in BUSIO_CLASSES: + # busio driver (i2c, spi, uart) + board_info["busio"] = True + logger.info(f"Supported busio driver: {driver}") if driver not in active_zephyr_devices: active_zephyr_devices[driver] = [] active_zephyr_devices[driver].append(node.labels) @@ -439,8 +554,8 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 zephyr_binding_objects = [] zephyr_binding_labels = [] for driver, instances in active_zephyr_devices.items(): - driverclass = DRIVER_CLASSES[driver] - zephyr_binding_headers.append(f'#include "bindings/zephyr_{driver}/{driverclass}.h"') + driverclass = BUSIO_CLASSES[driver] + zephyr_binding_headers.append(f'#include "shared-bindings/busio/{driverclass}.h"') # Designate a main bus such as board.I2C. if len(instances) == 1: @@ -453,7 +568,7 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 if label == driverclass: found_main = True if not found_main: - for priority_label in ("zephyr_i2c", "arduino_i2c"): + for priority_label in (f"zephyr_{driver}", f"arduino_{driver}"): for labels in instances: if priority_label in labels: labels.append(driverclass) @@ -466,18 +581,28 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 c_function_name = f"_{instance_name}" singleton_ptr = f"{c_function_name}_singleton" function_object = f"{c_function_name}_obj" - binding_prefix = f"zephyr_{driver}_{driverclass.lower()}" + busio_type = f"busio_{driverclass.lower()}" + + # UART needs a receiver buffer + if driver == "serial": + buffer_decl = f"static byte {instance_name}_buffer[128];" + construct_call = f"common_hal_busio_uart_construct_from_device(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]})), 128, {instance_name}_buffer)" + else: + buffer_decl = "" + construct_call = f"common_hal_busio_{driverclass.lower()}_construct_from_device(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]})))" + zephyr_binding_objects.append( - f"""static {binding_prefix}_obj_t {instance_name}_obj; + f"""{buffer_decl} +static {busio_type}_obj_t {instance_name}_obj; static mp_obj_t {singleton_ptr} = mp_const_none; static mp_obj_t {c_function_name}(void) {{ if ({singleton_ptr} != mp_const_none) {{ return {singleton_ptr}; }} - {singleton_ptr} = {binding_prefix}_zephyr_init(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]}))); + {singleton_ptr} = {construct_call}; return {singleton_ptr}; }} -static MP_DEFINE_CONST_FUN_OBJ_0({function_object}, {c_function_name});""" +static MP_DEFINE_CONST_FUN_OBJ_0({function_object}, {c_function_name});""".lstrip() ) for label in labels: zephyr_binding_labels.append( @@ -503,15 +628,15 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 for ram in rams: device, start, end, size, path = ram max_size = max(max_size, size) - if isinstance(start, str): - ram_externs.append(f"extern uint32_t {start};") - start = "&" + start - else: - start = f"(uint32_t*) 0x{start:08x}" - ram_list.append(f" {start}, (uint32_t*) 0x{end:08x}, // {path}") + # We always start at the end of a Zephyr linker section so we need the externs and &. + ram_externs.append(f"extern uint32_t {start};") + start = "&" + start + ram_list.append(f" {start}, {end}, // {path}") ram_list = "\n".join(ram_list) ram_externs = "\n".join(ram_externs) + flashes = [f"DEVICE_DT_GET(DT_NODELABEL({flash}))" for flash in flashes] + new_header_content = f"""#pragma once #define MICROPY_HW_BOARD_NAME "{board_name}" diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 8651b2715cc..3d2f1fe69aa 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -28,3 +28,5 @@ CONFIG_LOG_BLOCK_IN_THREAD=y CONFIG_EVENTS=y CONFIG_I2C=y +CONFIG_SPI=y +CONFIG_SPI_ASYNC=y diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 860584c2b19..c58de56d707 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -26,7 +26,14 @@ static pool_t pools[CIRCUITPY_RAM_DEVICE_COUNT]; static K_EVENT_DEFINE(main_needed); +static struct k_timer tick_timer; + +static void _tick_function(struct k_timer *timer_id) { + supervisor_tick(); +} + safe_mode_t port_init(void) { + k_timer_init(&tick_timer, _tick_function, NULL); return SAFE_MODE_NONE; } @@ -94,12 +101,12 @@ uint64_t port_get_raw_ticks(uint8_t *subticks) { // Enable 1/1024 second tick. void port_enable_tick(void) { - + k_timer_start(&tick_timer, K_USEC(1000000 / 1024), K_USEC(1000000 / 1024)); } // Disable 1/1024 second tick. void port_disable_tick(void) { - + k_timer_stop(&tick_timer); } static k_timeout_t next_timeout; diff --git a/ports/zephyr-cp/supervisor/serial.c b/ports/zephyr-cp/supervisor/serial.c index 97e2bee9ce5..a62e00a7742 100644 --- a/ports/zephyr-cp/supervisor/serial.c +++ b/ports/zephyr-cp/supervisor/serial.c @@ -6,15 +6,17 @@ #include "supervisor/shared/serial.h" -#include "bindings/zephyr_serial/UART.h" +#if CIRCUITPY_USB_DEVICE == 0 +#include "shared-bindings/busio/UART.h" -static zephyr_serial_uart_obj_t zephyr_console; +static busio_uart_obj_t zephyr_console; static uint8_t buffer[64]; +#endif void port_serial_early_init(void) { #if CIRCUITPY_USB_DEVICE == 0 - zephyr_console.base.type = &zephyr_serial_uart_type; - zephyr_serial_uart_construct(&zephyr_console, DEVICE_DT_GET(DT_CHOSEN(zephyr_console)), sizeof(buffer), buffer); + zephyr_console.base.type = &busio_uart_type; + common_hal_busio_uart_construct_from_device(&zephyr_console, DEVICE_DT_GET(DT_CHOSEN(zephyr_console)), sizeof(buffer), buffer); #endif } @@ -32,7 +34,7 @@ bool port_serial_connected(void) { char port_serial_read(void) { #if CIRCUITPY_USB_DEVICE == 0 char buf[1]; - size_t count = zephyr_serial_uart_read(&zephyr_console, buf, 1, NULL); + size_t count = common_hal_busio_uart_read(&zephyr_console, buf, 1, NULL); if (count == 0) { return -1; } @@ -44,7 +46,7 @@ char port_serial_read(void) { uint32_t port_serial_bytes_available(void) { #if CIRCUITPY_USB_DEVICE == 0 - return zephyr_serial_uart_rx_characters_available(&zephyr_console); + return common_hal_busio_uart_rx_characters_available(&zephyr_console); #else return 0; #endif @@ -52,6 +54,6 @@ uint32_t port_serial_bytes_available(void) { void port_serial_write_substring(const char *text, uint32_t length) { #if CIRCUITPY_USB_DEVICE == 0 - zephyr_serial_uart_write(&zephyr_console, text, length, NULL); + common_hal_busio_uart_write(&zephyr_console, text, length, NULL); #endif } diff --git a/requirements-dev.txt b/requirements-dev.txt index 0e8426d5174..cdfb62da1fa 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -41,3 +41,4 @@ setuptools # For zephyr port tomlkit +pytest diff --git a/shared-bindings/board/__init__.h b/shared-bindings/board/__init__.h index 7c9a59d2dbd..fbc39317a30 100644 --- a/shared-bindings/board/__init__.h +++ b/shared-bindings/board/__init__.h @@ -14,19 +14,16 @@ extern const mp_obj_dict_t board_module_globals; static const MP_DEFINE_STR_OBJ(board_module_id_obj, CIRCUITPY_BOARD_ID); -bool common_hal_board_is_i2c(mp_obj_t obj); mp_obj_t common_hal_board_get_i2c(const mp_int_t instance); mp_obj_t common_hal_board_create_i2c(const mp_int_t instance); mp_obj_t board_i2c(size_t n_args, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ_0(board_i2c_obj); -bool common_hal_board_is_spi(mp_obj_t obj); mp_obj_t common_hal_board_get_spi(const mp_int_t instance); mp_obj_t common_hal_board_create_spi(const mp_int_t instance); mp_obj_t board_spi(size_t n_args, const mp_obj_t *args); MP_DECLARE_CONST_FUN_OBJ_0(board_spi_obj); -bool common_hal_board_is_uart(mp_obj_t obj); mp_obj_t common_hal_board_get_uart(const mp_int_t instance); mp_obj_t common_hal_board_create_uart(const mp_int_t instance); mp_obj_t board_uart(size_t n_args, const mp_obj_t *args); diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 8aa35ec6e07..165b6a5ba93 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -106,7 +106,7 @@ static void check_for_deinit(busio_i2c_obj_t *self) { // Provided by context manager helper. static void check_lock(busio_i2c_obj_t *self) { - asm (""); + __asm__ (""); if (!common_hal_busio_i2c_has_lock(self)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); } diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 1513a7cf094..24c02a16e63 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -140,7 +140,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_deinit_obj, busio_spi_obj_deinit); // Provided by context manager helper. static void check_lock(busio_spi_obj_t *self) { - asm (""); + __asm__ (""); if (!common_hal_busio_spi_has_lock(self)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Function requires lock")); } diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index 96735c8dbaa..a9c0e9a6c80 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -43,15 +43,6 @@ static const board_i2c_pin_t i2c_pin[CIRCUITPY_BOARD_I2C] = CIRCUITPY_BOARD_I2C_ static busio_i2c_obj_t i2c_obj[CIRCUITPY_BOARD_I2C]; static bool i2c_obj_created[CIRCUITPY_BOARD_I2C]; -bool common_hal_board_is_i2c(mp_obj_t obj) { - for (uint8_t instance = 0; instance < CIRCUITPY_BOARD_I2C; instance++) { - if (obj == &i2c_obj[instance]) { - return true; - } - } - return false; -} - mp_obj_t common_hal_board_get_i2c(const mp_int_t instance) { return i2c_obj_created[instance] ? &i2c_obj[instance] : NULL; } @@ -89,15 +80,6 @@ static const board_spi_pin_t spi_pin[CIRCUITPY_BOARD_SPI] = CIRCUITPY_BOARD_SPI_ static busio_spi_obj_t spi_obj[CIRCUITPY_BOARD_SPI]; static bool spi_obj_created[CIRCUITPY_BOARD_SPI]; -bool common_hal_board_is_spi(mp_obj_t obj) { - for (uint8_t instance = 0; instance < CIRCUITPY_BOARD_SPI; instance++) { - if (obj == &spi_obj[instance]) { - return true; - } - } - return false; -} - mp_obj_t common_hal_board_get_spi(const mp_int_t instance) { return spi_obj_created[instance] ? &spi_obj[instance] : NULL; } @@ -136,15 +118,6 @@ static const board_uart_pin_t uart_pin[CIRCUITPY_BOARD_UART] = CIRCUITPY_BOARD_U static busio_uart_obj_t uart_obj[CIRCUITPY_BOARD_UART]; static bool uart_obj_created[CIRCUITPY_BOARD_UART]; -bool common_hal_board_is_uart(mp_obj_t obj) { - for (uint8_t instance = 0; instance < CIRCUITPY_BOARD_UART; instance++) { - if (obj == &uart_obj[instance]) { - return true; - } - } - return false; -} - mp_obj_t common_hal_board_get_uart(const mp_int_t instance) { return uart_obj_created[instance] ? &uart_obj[instance] : NULL; } diff --git a/shared-module/displayio/Shape.c b/shared-module/displayio/Shape.c deleted file mode 100644 index 143d37c6c9b..00000000000 --- a/shared-module/displayio/Shape.c +++ /dev/null @@ -1,126 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "shared-bindings/displayio/Shape.h" - -#include - -#include "py/runtime.h" -#include "py/misc.h" - -void common_hal_displayio_shape_construct(displayio_shape_t *self, uint32_t width, - uint32_t height, bool mirror_x, bool mirror_y) { - self->mirror_x = mirror_x; - self->mirror_y = mirror_y; - self->width = width; - if (self->mirror_x) { - width /= 2; - width += self->width % 2; - } - self->half_width = width; - - self->height = height; - if (self->mirror_y) { - height /= 2; - height += self->height % 2; - } - self->half_height = height; - - self->data = m_malloc_without_collect(height * sizeof(uint32_t)); - - for (uint16_t i = 0; i < height; i++) { - self->data[2 * i] = 0; - self->data[2 * i + 1] = width; - } - - self->dirty_area.x1 = 0; - self->dirty_area.x2 = width; - self->dirty_area.y1 = 0; - self->dirty_area.y2 = height; -} - -void common_hal_displayio_shape_set_boundary(displayio_shape_t *self, uint16_t y, uint16_t start_x, uint16_t end_x) { - uint16_t max_y = self->height - 1; - if (self->mirror_y) { - max_y = self->half_height - 1; - } - mp_arg_validate_int_range(y, 0, max_y, MP_QSTR_y); - uint16_t max_x = self->width - 1; - if (self->mirror_x) { - max_x = self->half_width - 1; - } - mp_arg_validate_int_range(start_x, 0, max_x, MP_QSTR_start_x); - mp_arg_validate_int_range(end_x, 0, max_x, MP_QSTR_end_x); - - uint16_t lower_x, upper_x, lower_y, upper_y; - - // find x-boundaries for updating based on current data and start_x, end_x, and mirror_x - lower_x = MIN(start_x, self->data[2 * y]); - - if (self->mirror_x) { - upper_x = self->width - lower_x + 1; // dirty rectangles are treated with max value exclusive - } else { - upper_x = MAX(end_x, self->data[2 * y + 1]) + 1; // dirty rectangles are treated with max value exclusive - } - - // find y-boundaries based on y and mirror_y - lower_y = y; - - if (self->mirror_y) { - upper_y = self->height - lower_y + 1; // dirty rectangles are treated with max value exclusive - } else { - upper_y = y + 1; // dirty rectangles are treated with max value exclusive - } - - self->data[2 * y] = start_x; // update the data array with the new boundaries - self->data[2 * y + 1] = end_x; - - if (self->dirty_area.x1 == self->dirty_area.x2) { // Dirty region is empty - self->dirty_area.x1 = lower_x; - self->dirty_area.x2 = upper_x; - self->dirty_area.y1 = lower_y; - self->dirty_area.y2 = upper_y; - - } else { // Dirty region is not empty - self->dirty_area.x1 = MIN(lower_x, self->dirty_area.x1); - self->dirty_area.x2 = MAX(upper_x, self->dirty_area.x2); - - self->dirty_area.y1 = MIN(lower_y, self->dirty_area.y1); - self->dirty_area.y2 = MAX(upper_y, self->dirty_area.y2); - } -} - -uint32_t common_hal_displayio_shape_get_pixel(void *obj, int16_t x, int16_t y) { - displayio_shape_t *self = obj; - if (x >= self->width || x < 0 || y >= self->height || y < 0) { - return 0; - } - if (self->mirror_x && x >= self->half_width) { - x = self->width - x - 1; - } - if (self->mirror_y && y >= self->half_height) { - y = self->height - y - 1; - } - uint16_t start_x = self->data[2 * y]; - uint16_t end_x = self->data[2 * y + 1]; - if (x < start_x || x > end_x) { - return 0; - } - return 1; -} - -displayio_area_t *displayio_shape_get_refresh_areas(displayio_shape_t *self, displayio_area_t *tail) { - if (self->dirty_area.x1 == self->dirty_area.x2) { - return tail; - } - self->dirty_area.next = tail; - return &self->dirty_area; -} - -void displayio_shape_finish_refresh(displayio_shape_t *self) { - self->dirty_area.x1 = 0; - self->dirty_area.x2 = 0; -} diff --git a/shared-module/displayio/Shape.h b/shared-module/displayio/Shape.h deleted file mode 100644 index 20ee182023f..00000000000 --- a/shared-module/displayio/Shape.h +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include -#include - -#include "py/obj.h" -#include "shared-module/displayio/area.h" - -typedef struct { - mp_obj_base_t base; - uint16_t width; - uint16_t height; - uint16_t half_width; - uint16_t half_height; - uint16_t *data; - bool mirror_x; - bool mirror_y; - displayio_area_t dirty_area; -} displayio_shape_t; - -void displayio_shape_finish_refresh(displayio_shape_t *self); -displayio_area_t *displayio_shape_get_refresh_areas(displayio_shape_t *self, displayio_area_t *tail); diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index 747fdbec5a7..e325a7857f4 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -10,6 +10,7 @@ #include "shared-bindings/displayio/__init__.h" #include "shared/runtime/interrupt_char.h" +#include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/busio/I2C.h" @@ -215,19 +216,9 @@ void reset_displays(void) { if (((size_t)fourwire->bus) < ((size_t)&display_buses) || ((size_t)fourwire->bus) > ((size_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT * sizeof(primary_display_bus_t))) { busio_spi_obj_t *original_spi = fourwire->bus; - #if CIRCUITPY_BOARD_SPI - // We don't need to move original_spi if it is a board.SPI object because it is - // statically allocated already. (Doing so would also make it impossible to reference in - // a subsequent VM run.) - if (common_hal_board_is_spi(original_spi)) { + if (!gc_ptr_on_heap(original_spi)) { continue; } - #endif - #ifdef BOARD_USE_INTERNAL_SPI - if (original_spi == (mp_obj_t)(&supervisor_flash_spi_bus)) { - continue; - } - #endif memcpy(&fourwire->inline_bus, original_spi, sizeof(busio_spi_obj_t)); fourwire->bus = &fourwire->inline_bus; @@ -249,14 +240,9 @@ void reset_displays(void) { if (((size_t)i2c->bus) < ((size_t)&display_buses) || ((size_t)i2c->bus) > ((size_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT * sizeof(primary_display_bus_t))) { busio_i2c_obj_t *original_i2c = i2c->bus; - #if CIRCUITPY_BOARD_I2C - // We don't need to move original_i2c if it is a board.I2C object because it is - // statically allocated already. (Doing so would also make it impossible to reference in - // a subsequent VM run.) - if (common_hal_board_is_i2c(original_i2c)) { + if (!gc_ptr_on_heap(original_i2c)) { continue; } - #endif memcpy(&i2c->inline_bus, original_i2c, sizeof(busio_i2c_obj_t)); i2c->bus = &i2c->inline_bus; // Check for other displays that use the same i2c bus and swap them too. @@ -285,22 +271,17 @@ void reset_displays(void) { if (((uint32_t)is31fb->is31fl3741->i2c) < ((uint32_t)&display_buses) || ((uint32_t)is31fb->is31fl3741->i2c) > ((uint32_t)&display_buses + CIRCUITPY_DISPLAY_LIMIT)) { - #if CIRCUITPY_BOARD_I2C - // We don't need to move original_i2c if it is the board.I2C object because it is - // statically allocated already. (Doing so would also make it impossible to reference in - // a subsequent VM run.) - if (common_hal_board_is_i2c(is31fb->is31fl3741->i2c)) { - continue; - } - #endif - is31fl3741_IS31FL3741_obj_t *original_is31 = is31fb->is31fl3741; - memcpy(&is31fb->inline_is31fl3741, original_is31, sizeof(is31fl3741_IS31FL3741_obj_t)); - is31fb->is31fl3741 = &is31fb->inline_is31fl3741; + if (gc_ptr_on_heap(original_is31)) { + memcpy(&is31fb->inline_is31fl3741, original_is31, sizeof(is31fl3741_IS31FL3741_obj_t)); + is31fb->is31fl3741 = &is31fb->inline_is31fl3741; + } busio_i2c_obj_t *original_i2c = is31fb->is31fl3741->i2c; - memcpy(&is31fb->is31fl3741->inline_i2c, original_i2c, sizeof(busio_i2c_obj_t)); - is31fb->is31fl3741->i2c = &is31fb->is31fl3741->inline_i2c; + if (gc_ptr_on_heap(original_i2c)) { + memcpy(&is31fb->is31fl3741->inline_i2c, original_i2c, sizeof(busio_i2c_obj_t)); + is31fb->is31fl3741->i2c = &is31fb->is31fl3741->inline_i2c; + } } if (!any_display_uses_this_framebuffer(&is31fb->base)) { @@ -332,12 +313,10 @@ void reset_displays(void) { #endif #if CIRCUITPY_AURORA_EPAPER } else if (display_bus_type == &aurora_framebuffer_type) { - #if CIRCUITPY_BOARD_SPI aurora_epaper_framebuffer_obj_t *aurora = &display_buses[i].aurora_epaper; - if (common_hal_board_is_spi(aurora->bus)) { + if (gc_ptr_on_heap(aurora->bus)) { common_hal_aurora_epaper_framebuffer_set_free_bus(false); } - #endif // Set to None, gets deinit'd up by display_base display_buses[i].bus_base.type = &mp_type_NoneType; #endif diff --git a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c index 3c6eaf065df..8b9629b002f 100644 --- a/shared-module/sharpdisplay/SharpMemoryFramebuffer.c +++ b/shared-module/sharpdisplay/SharpMemoryFramebuffer.c @@ -54,11 +54,7 @@ static bool common_hal_sharpdisplay_framebuffer_get_pixels_in_byte_share_row(sha } void common_hal_sharpdisplay_framebuffer_reset(sharpdisplay_framebuffer_obj_t *self) { - if (self->bus != &self->inline_bus - #if CIRCUITPY_BOARD_SPI - && !common_hal_board_is_spi(self->bus) - #endif - ) { + if (self->bus != &self->inline_bus && gc_ptr_on_heap(self->bus)) { memcpy(&self->inline_bus, self->bus, sizeof(busio_spi_obj_t)); self->bus = &self->inline_bus; } diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 8d53b0e62be..99c1497f023 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -125,7 +125,7 @@ static uint8_t *tilegrid_tiles = NULL; static size_t tilegrid_tiles_size = 0; #endif -#if CIRCUITPY_LVFONTIO +#if CIRCUITPY_LVFONTIO && CIRCUITPY_TERMINALIO static lvfontio_ondiskfont_t *lvfont = NULL; #endif diff --git a/tools/gen_display_resources.py b/tools/gen_display_resources.py index 7b6de6d95d4..9ed829f7d37 100644 --- a/tools/gen_display_resources.py +++ b/tools/gen_display_resources.py @@ -8,8 +8,8 @@ import struct import sys -sys.path.insert(0, "bitmap_font") -sys.path.insert(0, "../../tools/bitmap_font") +sys.path.insert(0, "tools/bitmap_font") # For running from root +sys.path.insert(0, "../../tools/bitmap_font") # For running from a port directory from adafruit_bitmap_font import bitmap_font From 9e7edf2d1a76586f85d4ae5b5097bce9d7232516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Alse=CC=81n?= Date: Mon, 15 Dec 2025 20:01:49 +0100 Subject: [PATCH 133/876] Fixed compilation error when disabling CIRCUITPY_SERIAL_BLE || CIRCUITPY_BLE_FILE_SERVICE + variable name mismatch --- ports/espressif/common-hal/_bleio/PacketBuffer.c | 6 ++++++ shared-bindings/_bleio/PacketBuffer.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ports/espressif/common-hal/_bleio/PacketBuffer.c b/ports/espressif/common-hal/_bleio/PacketBuffer.c index db035157ceb..00aaae44e38 100644 --- a/ports/espressif/common-hal/_bleio/PacketBuffer.c +++ b/ports/espressif/common-hal/_bleio/PacketBuffer.c @@ -159,7 +159,13 @@ static int packet_buffer_on_ble_client_evt(struct ble_gap_event *event, void *pa return false; } +#if CIRCUITPY_SERIAL_BLE || CIRCUITPY_BLE_FILE_SERVICE +// Exposed via shared-bindings header when enabled void _common_hal_bleio_packet_buffer_construct( +#else +// Internal static helper when disabled (avoids "missing prototype" error) +static void _common_hal_bleio_packet_buffer_construct( +#endif bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, uint32_t *incoming_buffer, size_t incoming_buffer_size, uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, diff --git a/shared-bindings/_bleio/PacketBuffer.h b/shared-bindings/_bleio/PacketBuffer.h index 1a872512da2..e58a2c39371 100644 --- a/shared-bindings/_bleio/PacketBuffer.h +++ b/shared-bindings/_bleio/PacketBuffer.h @@ -25,7 +25,7 @@ void common_hal_bleio_packet_buffer_construct( void _common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, uint32_t *incoming_buffer, size_t incoming_buffer_size, - uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t outgoing_buffer_size, + uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, ble_event_handler_t *static_handler_entry); #endif mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, const uint8_t *data, size_t len, uint8_t *header, size_t header_len); From 5457fc8b22e1beeca2f7829c2e1702390394ae5e Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 17 Dec 2025 19:34:11 +0100 Subject: [PATCH 134/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 14 +++++++++----- locale/el.po | 14 +++++++++----- locale/hi.po | 14 +++++++++----- locale/ko.po | 14 +++++++++----- locale/ru.po | 14 +++++++++----- locale/tr.po | 14 +++++++++----- 6 files changed, 54 insertions(+), 30 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 35196a280e3..b1e50a11e12 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1137,9 +1137,8 @@ msgstr "" "Frekvence musí být 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 nebo 1008 " "Mhz" -#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c -#: shared-bindings/busio/SPI.c +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "Funkce vyžaduje zámek" @@ -1482,8 +1481,7 @@ msgstr "Chybí jmp_pin. %q[%u] skáče na pin" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "Musí být podtřída %q." @@ -2420,6 +2418,12 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c diff --git a/locale/el.po b/locale/el.po index bde4522cc60..10d7d4d1f51 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1143,9 +1143,8 @@ msgid "" "Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c -#: shared-bindings/busio/SPI.c +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "" @@ -1488,8 +1487,7 @@ msgstr "" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -2424,6 +2422,12 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c diff --git a/locale/hi.po b/locale/hi.po index 43737b6cdd8..ebbedfe7639 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1119,9 +1119,8 @@ msgid "" "Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c -#: shared-bindings/busio/SPI.c +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "" @@ -1464,8 +1463,7 @@ msgstr "" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -2398,6 +2396,12 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c diff --git a/locale/ko.po b/locale/ko.po index f77519cf701..182f4d08d6b 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1170,9 +1170,8 @@ msgstr "" "주파수는 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 또는 1008 Mhz 여야 " "합니다" -#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c -#: shared-bindings/busio/SPI.c +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "이 함수에는 잠금이 필요합니다" @@ -1518,8 +1517,7 @@ msgstr "jmp_pin이 누락되었습니다. %q[%u] 핀으로 점프합니다" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "%q의 하위클래스여야 합니다." @@ -2473,6 +2471,12 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c diff --git a/locale/ru.po b/locale/ru.po index bbd39319823..653eed6c0bf 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1154,9 +1154,8 @@ msgstr "" "Частота должна быть 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 или 1008 " "МГц" -#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c -#: shared-bindings/busio/SPI.c +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "Функция требует блокировки" @@ -1503,8 +1502,7 @@ msgstr "Не хватает jmp_pin.%q [%u] прыгает на пин" msgid "Mount point directory missing" msgstr "Отсутствует каталог точки монтирования" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "Должен быть субклассом %q." @@ -2457,6 +2455,12 @@ msgstr "Неподдерживаемый тип сокета" msgid "Update failed" msgstr "Обновление не удалось" +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c diff --git a/locale/tr.po b/locale/tr.po index 966a9123083..511e9cb7f46 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1137,9 +1137,8 @@ msgstr "" "Frekans 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 ya da 1008 Mhz " "olmalıdır" -#: ports/zephyr-cp/bindings/zephyr_i2c/I2C.c shared-bindings/bitbangio/I2C.c -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c -#: shared-bindings/busio/SPI.c +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c msgid "Function requires lock" msgstr "Fonksiyon kilit gerektirir" @@ -1483,8 +1482,7 @@ msgstr "" msgid "Mount point directory missing" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c -#: shared-bindings/displayio/Group.c +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c msgid "Must be a %q subclass." msgstr "" @@ -2420,6 +2418,12 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c From 3653803de0c600c7564d746192f2d5704e12670a Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 16 Dec 2025 13:31:02 -0800 Subject: [PATCH 135/876] Switch to Zephyr USB + QoL changes * Enable full builds * Two additional NXP boards --- main.c | 30 +- ports/zephyr-cp/app.overlay | 10 + ports/zephyr-cp/boards/board_aliases.cmake | 2 + ports/zephyr-cp/boards/ek_ra8d1.overlay | 2 + .../boards/frdm_mcxn947_mcxn947_cpu0.overlay | 5 + .../mimxrt1170_evk_mimxrt1176_cm7.overlay | 11 + .../nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 2 + .../boards/nrf54l15dk_nrf54l15_cpuapp.overlay | 1 + .../zephyr-cp/boards/nucleo_n657x0_q.overlay | 0 .../nxp/frdm_mcxn947/autogen_board_info.toml | 114 +++++ .../nxp/frdm_mcxn947/circuitpython.toml | 1 + .../mimxrt1170_evk/autogen_board_info.toml | 114 +++++ .../nxp/mimxrt1170_evk/circuitpython.toml | 1 + .../renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../renesas/ek_ra6m5/circuitpython.toml | 2 + .../renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../nucleo_n657x0_q/autogen_board_info.toml | 2 +- ports/zephyr-cp/common-hal/busio/UART.c | 11 +- ports/zephyr-cp/common-hal/busio/UART.h | 1 + ports/zephyr-cp/common-hal/usb_cdc/Serial.c | 68 +++ ports/zephyr-cp/common-hal/usb_cdc/Serial.h | 14 + ports/zephyr-cp/common-hal/usb_cdc/__init__.c | 40 ++ ports/zephyr-cp/common-hal/usb_cdc/__init__.h | 16 + .../zephyr-cp/cptools/build_circuitpython.py | 188 +------ ports/zephyr-cp/cptools/zephyr2cp.py | 33 +- ports/zephyr-cp/prj.conf | 11 +- ports/zephyr-cp/supervisor/port.c | 8 + ports/zephyr-cp/supervisor/serial.c | 54 +- ports/zephyr-cp/supervisor/usb.c | 474 ++++++++++++------ ports/zephyr-cp/supervisor/zephyr-cp.h | 9 + py/circuitpy_mpconfig.h | 2 +- shared-bindings/sdcardio/SDCard.c | 4 +- shared-bindings/supervisor/Runtime.c | 10 +- shared-bindings/usb_cdc/Serial.c | 4 +- shared-bindings/usb_cdc/Serial.h | 4 + shared-bindings/usb_cdc/__init__.h | 4 + supervisor/shared/serial.c | 18 +- supervisor/shared/usb.c | 65 +++ supervisor/shared/usb/usb.c | 38 +- supervisor/shared/workflow.c | 2 +- supervisor/usb.h | 1 + 42 files changed, 975 insertions(+), 407 deletions(-) create mode 100644 ports/zephyr-cp/app.overlay create mode 100644 ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay create mode 100644 ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay create mode 100644 ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay delete mode 100644 ports/zephyr-cp/boards/nucleo_n657x0_q.overlay create mode 100644 ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/nxp/frdm_mcxn947/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/nxp/mimxrt1170_evk/circuitpython.toml create mode 100644 ports/zephyr-cp/common-hal/usb_cdc/Serial.c create mode 100644 ports/zephyr-cp/common-hal/usb_cdc/Serial.h create mode 100644 ports/zephyr-cp/common-hal/usb_cdc/__init__.c create mode 100644 ports/zephyr-cp/common-hal/usb_cdc/__init__.h create mode 100644 ports/zephyr-cp/supervisor/zephyr-cp.h create mode 100644 supervisor/shared/usb.c diff --git a/main.c b/main.c index f4f67b04347..d636c851b70 100644 --- a/main.c +++ b/main.c @@ -219,21 +219,23 @@ static void stop_mp(void) { // Unmount all heap allocated vfs mounts. mp_vfs_mount_t *vfs = MP_STATE_VM(vfs_mount_table); - do { - if (gc_ptr_on_heap(vfs)) { - // mp_vfs_umount will splice out an unmounted vfs from the vfs_mount_table linked list. - mp_vfs_umount(vfs->obj); - // Start over at the beginning of the list since the first entry may have been removed. - vfs = MP_STATE_VM(vfs_mount_table); - continue; - } - vfs = vfs->next; - } while (vfs != NULL); + if (vfs != NULL) { + do { + if (gc_ptr_on_heap(vfs)) { + // mp_vfs_umount will splice out an unmounted vfs from the vfs_mount_table linked list. + mp_vfs_umount(vfs->obj); + // Start over at the beginning of the list since the first entry may have been removed. + vfs = MP_STATE_VM(vfs_mount_table); + continue; + } + vfs = vfs->next; + } while (vfs != NULL); - // The last vfs is CIRCUITPY and the root directory. - vfs = MP_STATE_VM(vfs_mount_table); - while (vfs->next != NULL) { - vfs = vfs->next; + // The last vfs is CIRCUITPY and the root directory. + vfs = MP_STATE_VM(vfs_mount_table); + while (vfs->next != NULL) { + vfs = vfs->next; + } } MP_STATE_VM(vfs_cur) = vfs; #endif diff --git a/ports/zephyr-cp/app.overlay b/ports/zephyr-cp/app.overlay new file mode 100644 index 00000000000..0f34d64a80f --- /dev/null +++ b/ports/zephyr-cp/app.overlay @@ -0,0 +1,10 @@ +&zephyr_udc0 { + cdc_acm_console: cdc_acm_console { + compatible = "zephyr,cdc-acm-uart"; + label = "CircuitPython Console"; + }; + cdc_acm_data: cdc_acm_data { + compatible = "zephyr,cdc-acm-uart"; + label = "CircuitPython Data"; + }; +}; diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index bb400f188db..7fc973efc78 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -5,6 +5,8 @@ set(nordic_nrf54l15dk_BOARD_ALIAS nrf54l15dk/nrf54l15/cpuapp) set(nordic_nrf54h20dk_BOARD_ALIAS nrf54h20dk/nrf54h20/cpuapp) set(nordic_nrf5340dk_BOARD_ALIAS nrf5340dk/nrf5340/cpuapp) set(nordic_nrf7002dk_BOARD_ALIAS nrf7002dk/nrf5340/cpuapp) +set(nxp_frdm_mcxn947_BOARD_ALIAS frdm_mcxn947/mcxn947/cpu0) +set(nxp_mimxrt1170_evk_BOARD_ALIAS mimxrt1170_evk@A/mimxrt1176/cm7) set(st_stm32h7b3i_dk_BOARD_ALIAS stm32h7b3i_dk) set(st_nucleo_u575zi_q_BOARD_ALIAS nucleo_u575zi_q/stm32u575xx) set(st_nucleo_n657x0_q_BOARD_ALIAS nucleo_n657x0_q/stm32n657xx) diff --git a/ports/zephyr-cp/boards/ek_ra8d1.overlay b/ports/zephyr-cp/boards/ek_ra8d1.overlay index 29735d02b8f..c13dfc457f5 100644 --- a/ports/zephyr-cp/boards/ek_ra8d1.overlay +++ b/ports/zephyr-cp/boards/ek_ra8d1.overlay @@ -1,3 +1,5 @@ &s28hl512t { /delete-node/ partitions; }; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay new file mode 100644 index 00000000000..83242201c5b --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay @@ -0,0 +1,5 @@ +&w25q64jvssiq { + /delete-node/ partitions; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay new file mode 100644 index 00000000000..d6f6d4f0c15 --- /dev/null +++ b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -0,0 +1,11 @@ +&is25wp128 { + partitions{ + /delete-node/ storage_partition; + circuitpy_partition: partition@E20000 { + label = "circuitpy"; + reg = <0x00E20000 (DT_SIZE_M(2) - DT_SIZE_K(128))>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index dfb363f2ed8..2cd411fbc06 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -100,7 +100,7 @@ touchio = false traceback = true uheap = false usb = false -usb_cdc = false +usb_cdc = true usb_hid = false usb_host = false usb_midi = false diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index 0d90c87931b..a70eede551e 100644 --- a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -43,3 +43,5 @@ memory-regions = <&cpuapp_dma_region>; status = "okay"; }; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..39db1e981af --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -0,0 +1 @@ +// No app.overlay because it doesn't have USB. diff --git a/ports/zephyr-cp/boards/nucleo_n657x0_q.overlay b/ports/zephyr-cp/boards/nucleo_n657x0_q.overlay deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml new file mode 100644 index 00000000000..f22d066fe64 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -0,0 +1,114 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "NXP Semiconductors FRDM-MCXN947" + +[modules] +__future__ = false +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = true # Zephyr board has busio +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/circuitpython.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/circuitpython.toml new file mode 100644 index 00000000000..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml new file mode 100644 index 00000000000..1768f331180 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -0,0 +1,114 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "NXP Semiconductors MIMXRT1170-EVK/EVKB" + +[modules] +__future__ = false +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = true # Zephyr board has busio +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/circuitpython.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/circuitpython.toml new file mode 100644 index 00000000000..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index c2d9048604f..0a4bf3ce19f 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -100,7 +100,7 @@ touchio = false traceback = true uheap = false usb = false -usb_cdc = false # No TinyUSB settings for r7fa6m5bh3cfc +usb_cdc = true usb_hid = false usb_host = false usb_midi = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/circuitpython.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/circuitpython.toml index 3272dd4c5f3..13ff40aa042 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/circuitpython.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/circuitpython.toml @@ -1 +1,3 @@ +# TX is on pin P411. RX is on pin P410. + CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 4b004746f90..518af74c405 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -100,7 +100,7 @@ touchio = false traceback = true uheap = false usb = false -usb_cdc = false # No TinyUSB settings for r7fa8d1bhecbd +usb_cdc = true usb_hid = false usb_host = false usb_midi = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 4b9fbf5c110..9806cd8a811 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -100,7 +100,7 @@ touchio = false traceback = true uheap = false usb = false -usb_cdc = false # No TinyUSB settings for stm32n657xx +usb_cdc = true usb_hid = false usb_host = false usb_midi = false diff --git a/ports/zephyr-cp/common-hal/busio/UART.c b/ports/zephyr-cp/common-hal/busio/UART.c index cecce48d45b..b5aaadb3bb5 100644 --- a/ports/zephyr-cp/common-hal/busio/UART.c +++ b/ports/zephyr-cp/common-hal/busio/UART.c @@ -67,7 +67,8 @@ mp_obj_t common_hal_busio_uart_construct_from_device(busio_uart_obj_t *self, con k_msgq_init(&self->msgq, receiver_buffer, 1, receiver_buffer_size); - self->timeout = K_USEC(100); + self->timeout = K_FOREVER; + self->write_timeout = K_FOREVER; self->rx_paused = false; uart_irq_rx_enable(uart_device); @@ -136,6 +137,14 @@ void common_hal_busio_uart_set_timeout(busio_uart_obj_t *self, mp_float_t timeou self->timeout = 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; +} + +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)); +} + uint32_t common_hal_busio_uart_rx_characters_available(busio_uart_obj_t *self) { return k_msgq_num_used_get(&self->msgq); } diff --git a/ports/zephyr-cp/common-hal/busio/UART.h b/ports/zephyr-cp/common-hal/busio/UART.h index 27cd76c537b..25e767c5b28 100644 --- a/ports/zephyr-cp/common-hal/busio/UART.h +++ b/ports/zephyr-cp/common-hal/busio/UART.h @@ -17,6 +17,7 @@ typedef struct { struct k_msgq msgq; k_timeout_t timeout; + k_timeout_t write_timeout; bool rx_paused; // set by irq if no space in rbuf } busio_uart_obj_t; diff --git a/ports/zephyr-cp/common-hal/usb_cdc/Serial.c b/ports/zephyr-cp/common-hal/usb_cdc/Serial.c new file mode 100644 index 00000000000..272a78b3141 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_cdc/Serial.c @@ -0,0 +1,68 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared/runtime/interrupt_char.h" +#include "shared-bindings/usb_cdc/Serial.h" +#include "shared-bindings/busio/UART.h" +#include "supervisor/shared/tick.h" + +mp_obj_t common_hal_usb_cdc_serial_construct_from_device(usb_cdc_serial_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer) { + common_hal_busio_uart_construct_from_device(self, uart_device, receiver_buffer_size, receiver_buffer); + self->base.type = &usb_cdc_serial_type; + return MP_OBJ_FROM_PTR(self); +} + +size_t common_hal_usb_cdc_serial_read(usb_cdc_serial_obj_t *self, uint8_t *data, size_t len, int *errcode) { + return common_hal_busio_uart_read(self, data, len, errcode); +} + +size_t common_hal_usb_cdc_serial_write(usb_cdc_serial_obj_t *self, const uint8_t *data, size_t len, int *errcode) { + return common_hal_busio_uart_write(self, data, len, errcode); +} + +uint32_t common_hal_usb_cdc_serial_get_in_waiting(usb_cdc_serial_obj_t *self) { + return common_hal_busio_uart_rx_characters_available(self); +} + +uint32_t common_hal_usb_cdc_serial_get_out_waiting(usb_cdc_serial_obj_t *self) { + // Return number of FIFO bytes currently occupied. + // return CFG_TUD_CDC_TX_BUFSIZE - tud_cdc_n_write_available(self->idx); + return 0; +} + +void common_hal_usb_cdc_serial_reset_input_buffer(usb_cdc_serial_obj_t *self) { + common_hal_busio_uart_clear_rx_buffer(self); +} + +uint32_t common_hal_usb_cdc_serial_reset_output_buffer(usb_cdc_serial_obj_t *self) { + // return tud_cdc_n_write_clear(self->idx); + return 0; +} + +uint32_t common_hal_usb_cdc_serial_flush(usb_cdc_serial_obj_t *self) { + // return tud_cdc_n_write_flush(self->idx); + return 0; +} + +bool common_hal_usb_cdc_serial_get_connected(usb_cdc_serial_obj_t *self) { + return !common_hal_busio_uart_deinited(self); +} + +mp_float_t common_hal_usb_cdc_serial_get_timeout(usb_cdc_serial_obj_t *self) { + return common_hal_busio_uart_get_timeout(self); +} + +void common_hal_usb_cdc_serial_set_timeout(usb_cdc_serial_obj_t *self, mp_float_t timeout) { + common_hal_busio_uart_set_timeout(self, timeout); +} + +mp_float_t common_hal_usb_cdc_serial_get_write_timeout(usb_cdc_serial_obj_t *self) { + return common_hal_busio_uart_get_write_timeout(self); +} + +void common_hal_usb_cdc_serial_set_write_timeout(usb_cdc_serial_obj_t *self, mp_float_t write_timeout) { + common_hal_busio_uart_set_write_timeout(self, write_timeout); +} diff --git a/ports/zephyr-cp/common-hal/usb_cdc/Serial.h b/ports/zephyr-cp/common-hal/usb_cdc/Serial.h new file mode 100644 index 00000000000..9a110545a37 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_cdc/Serial.h @@ -0,0 +1,14 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-bindings/busio/UART.h" + +typedef busio_uart_obj_t usb_cdc_serial_obj_t; + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_usb_cdc_serial_construct_from_device(usb_cdc_serial_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer); diff --git a/ports/zephyr-cp/common-hal/usb_cdc/__init__.c b/ports/zephyr-cp/common-hal/usb_cdc/__init__.c new file mode 100644 index 00000000000..7bcae396733 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_cdc/__init__.c @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/gc.h" +#include "py/obj.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "py/objtuple.h" +#include "shared-bindings/usb_cdc/__init__.h" +#include "shared-bindings/usb_cdc/Serial.h" +#include "supervisor/usb.h" + +static bool usb_cdc_console_is_enabled; +static bool usb_cdc_data_is_enabled; + +void usb_cdc_set_defaults(void) { + common_hal_usb_cdc_enable(true, + false); +} + +bool usb_cdc_console_enabled(void) { + return usb_cdc_console_is_enabled; +} + +bool usb_cdc_data_enabled(void) { + return usb_cdc_data_is_enabled; +} + +bool common_hal_usb_cdc_disable(void) { + return common_hal_usb_cdc_enable(false, false); +} + +bool common_hal_usb_cdc_enable(bool console, bool data) { + usb_cdc_console_is_enabled = console; + usb_cdc_data_is_enabled = data; + return true; +} diff --git a/ports/zephyr-cp/common-hal/usb_cdc/__init__.h b/ports/zephyr-cp/common-hal/usb_cdc/__init__.h new file mode 100644 index 00000000000..daf06d580ad --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_cdc/__init__.h @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/mpconfig.h" +#include "py/objtuple.h" +#include "supervisor/usb.h" + +bool usb_cdc_console_enabled(void); +bool usb_cdc_data_enabled(void); + +void usb_cdc_set_defaults(void); diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 87ff00a4503..a5e4d72b902 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -55,9 +55,11 @@ "traceback", "warnings", "supervisor", + "errno", + "io", ] -# Flags that don't match with with a *bindings module. -MPCONFIG_FLAGS = ["array", "json"] +# Flags that don't match with with a *bindings module. Some used by adafruit_requests +MPCONFIG_FLAGS = ["array", "errno", "io", "json"] # List of other modules (the value) that can be enabled when another one (the key) is. REVERSE_DEPENDENCIES = { @@ -80,6 +82,8 @@ # Other flags to set when a module is enabled EXTRA_FLAGS = {"busio": ["BUSIO_SPI", "BUSIO_I2C"]} +SHARED_MODULE_AND_COMMON_HAL = ["os"] + async def preprocess_and_split_defs(compiler, source_file, build_path, flags): build_file = source_file.with_suffix(".pp") @@ -267,51 +271,12 @@ def determine_enabled_modules(board_info, portdir, srcdir): return enabled_modules, module_reasons -TINYUSB_SETTINGS = { - "": { - "CFG_TUSB_MCU": "OPT_MCU_MIMXRT10XX", - "CFG_TUD_CDC_RX_BUFSIZE": 640, - "CFG_TUD_CDC_TX_BUFSIZE": 512, - }, - "stm32u575xx": {"CFG_TUSB_MCU": "OPT_MCU_STM32U5"}, - "nrf52840": {"CFG_TUSB_MCU": "OPT_MCU_NRF5X"}, - "nrf5340": {"CFG_TUSB_MCU": "OPT_MCU_NRF5X"}, - # "r7fa8d1bhecbd": {"CFG_TUSB_MCU": "OPT_MCU_RAXXX", "USB_HIGHSPEED": "1", "USBHS_USB_INT_RESUME_IRQn": "54", "USBFS_INT_IRQn": "54", "CIRCUITPY_USB_DEVICE_INSTANCE": "1"}, - # ifeq ($(CHIP_FAMILY),$(filter $(CHIP_FAMILY),MIMXRT1011 MIMXRT1015)) - # CFLAGS += -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_MIDI_TX_BUFSIZE=64 -DCFG_TUD_MSC_BUFSIZE=512 - # else - # CFLAGS += -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_MIDI_TX_BUFSIZE=512 -DCFG_TUD_MSC_BUFSIZE=1024 - # endif -} - -TINYUSB_SOURCE = { - "stm32u575xx": [ - "src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c", - "src/portable/synopsys/dwc2/dcd_dwc2.c", - "src/portable/synopsys/dwc2/hcd_dwc2.c", - "src/portable/synopsys/dwc2/dwc2_common.c", - ], - "nrf52840": [ - "src/portable/nordic/nrf5x/dcd_nrf5x.c", - ], - "nrf5340": [ - "src/portable/nordic/nrf5x/dcd_nrf5x.c", - ], - # "r7fa8d1bhecbd": [ - # "src/portable/renesas/rusb2/dcd_rusb2.c", - # "src/portable/renesas/rusb2/hcd_rusb2.c", - # "src/portable/renesas/rusb2/rusb2_common.c", - # ], -} - - async def build_circuitpython(): circuitpython_flags = ["-DCIRCUITPY"] port_flags = [] enable_mpy_native = False - full_build = False + full_build = True usb_host = False - tusb_mem_align = 4 board = cmake_args["BOARD_ALIAS"] if not board: board = cmake_args["BOARD"] @@ -325,20 +290,14 @@ async def build_circuitpython(): circuitpython_flags.append(f"-DCIRCUITPY_FULL_BUILD={1 if full_build else 0}") circuitpython_flags.append(f"-DCIRCUITPY_USB_HOST={1 if usb_host else 0}") circuitpython_flags.append(f"-DCIRCUITPY_BOARD_ID='\"{board}\"'") - circuitpython_flags.append(f"-DCIRCUITPY_TUSB_MEM_ALIGN={tusb_mem_align}") circuitpython_flags.append(f"-DCIRCUITPY_TRANSLATE_OBJECT={1 if lto else 0}") circuitpython_flags.append("-DINTERNAL_FLASH_FILESYSTEM") circuitpython_flags.append("-DLONGINT_IMPL_MPZ") circuitpython_flags.append("-DCIRCUITPY_SSL_MBEDTLS") circuitpython_flags.append("-DFFCONF_H='\"lib/oofatfs/ffconf.h\"'") circuitpython_flags.extend(("-I", srcdir)) - circuitpython_flags.extend(("-I", srcdir / "lib/tinyusb/src")) - circuitpython_flags.extend(("-I", srcdir / "supervisor/shared/usb")) circuitpython_flags.extend(("-I", builddir)) circuitpython_flags.extend(("-I", portdir)) - # circuitpython_flags.extend(("-I", srcdir / "ports" / port / "peripherals")) - - # circuitpython_flags.extend(("-I", build_path / board_id)) genhdr = builddir / "genhdr" genhdr.mkdir(exist_ok=True, parents=True) @@ -364,10 +323,7 @@ async def build_circuitpython(): ) board_info = board_autogen_task.result() mpconfigboard_fn = board_tools.find_mpconfigboard(portdir, board) - mpconfigboard = { - "USB_VID": 0x1209, - "USB_PID": 0x000C, - } + mpconfigboard = {"USB_VID": 0x1209, "USB_PID": 0x000C, "USB_INTERFACE_NAME": "CircuitPython"} if mpconfigboard_fn is None: mpconfigboard_fn = ( portdir / "boards" / board_info["vendor_id"] / board / "circuitpython.toml" @@ -377,7 +333,7 @@ async def build_circuitpython(): ) elif mpconfigboard_fn.exists(): with mpconfigboard_fn.open("rb") as f: - mpconfigboard = tomllib.load(f) + mpconfigboard.update(tomllib.load(f)) autogen_board_info_fn = mpconfigboard_fn.parent / "autogen_board_info.toml" @@ -386,6 +342,7 @@ async def build_circuitpython(): circuitpython_flags.extend(board_info["cflags"]) supervisor_source = [ "main.c", + "extmod/modjson.c", "extmod/vfs_fat.c", "lib/tlsf/tlsf.c", portdir / "background.c", @@ -417,20 +374,18 @@ async def build_circuitpython(): # if web_workflow: # supervisor_source.extend(top.glob("supervisor/shared/web_workflow/*.c")) - usb_num_endpoint_pairs = board_info.get("usb_num_endpoint_pairs", 0) - soc = board_info["soc"] - usb_ok = usb_num_endpoint_pairs > 0 and soc in TINYUSB_SETTINGS - circuitpython_flags.append(f"-DCIRCUITPY_TINYUSB={1 if usb_ok else 0}") + usb_ok = board_info.get("usb_device", False) circuitpython_flags.append(f"-DCIRCUITPY_USB_DEVICE={1 if usb_ok else 0}") - tinyusb_files = [] if usb_ok: enabled_modules.add("usb_cdc") - for setting in TINYUSB_SETTINGS[soc]: - circuitpython_flags.append(f"-D{setting}={TINYUSB_SETTINGS[soc][setting]}") - tinyusb_files.extend((top / "lib" / "tinyusb" / path for path in TINYUSB_SOURCE[soc])) + for macro in ("USB_PID", "USB_VID"): + print(f"Setting {macro} to {mpconfigboard.get(macro)}") circuitpython_flags.append(f"-D{macro}=0x{mpconfigboard.get(macro):04x}") + circuitpython_flags.append( + f"-DUSB_INTERFACE_NAME='\"{mpconfigboard['USB_INTERFACE_NAME']}\"'" + ) for macro, limit, value in ( ("USB_PRODUCT", 16, board_info["name"]), ("USB_MANUFACTURER", 8, board_info["vendor"]), @@ -438,107 +393,15 @@ async def build_circuitpython(): circuitpython_flags.append(f"-D{macro}='\"{value}\"'") circuitpython_flags.append(f"-D{macro}_{limit}='\"{value[:limit]}\"'") - usb_interface_name = "CircuitPython" - - circuitpython_flags.append("-DCFG_TUSB_OS=OPT_OS_ZEPHYR") - circuitpython_flags.append(f"-DUSB_INTERFACE_NAME='\"{usb_interface_name}\"'") - circuitpython_flags.append(f"-DUSB_NUM_ENDPOINT_PAIRS={usb_num_endpoint_pairs}") - for direction in ("IN", "OUT"): - circuitpython_flags.append(f"-DUSB_NUM_{direction}_ENDPOINTS={usb_num_endpoint_pairs}") - # USB is special because it doesn't have a matching module. - msc_enabled = board_info["flash_count"] > 0 - if msc_enabled: - circuitpython_flags.append("-DCFG_TUD_MSC_BUFSIZE=1024") - circuitpython_flags.append("-DCIRCUITPY_USB_MSC_ENABLED_DEFAULT=1") - tinyusb_files.append(top / "lib/tinyusb/src/class/msc/msc_device.c") - supervisor_source.append(top / "supervisor/shared/usb/usb_msc_flash.c") - circuitpython_flags.append(f"-DCIRCUITPY_USB_MSC={1 if msc_enabled else 0}") - if "usb_cdc" in enabled_modules: - tinyusb_files.extend(top.glob("lib/tinyusb/*.c")) - tinyusb_files.append(top / "lib/tinyusb/src/class/cdc/cdc_device.c") - circuitpython_flags.append("-DCFG_TUD_CDC_RX_BUFSIZE=640") - circuitpython_flags.append("-DCFG_TUD_CDC_TX_BUFSIZE=512") - circuitpython_flags.append("-DCFG_TUD_CDC=2") - circuitpython_flags.append("-DCIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT=1") - circuitpython_flags.append("-DCIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT=0") - - if "usb_hid_enabled_default" not in mpconfigboard: - mpconfigboard["usb_hid_enabled_default"] = usb_num_endpoint_pairs >= 5 - if "usb_midi_enabled_default" not in mpconfigboard: - mpconfigboard["usb_midi_enabled_default"] = usb_num_endpoint_pairs >= 8 - - tinyusb_files.extend( - (top / "lib/tinyusb/src/common/tusb_fifo.c", top / "lib/tinyusb/src/tusb.c") - ) - supervisor_source.extend( - (portdir / "supervisor/usb.c", top / "supervisor/shared/usb/usb.c") - ) + circuitpython_flags.append("-DCIRCUITPY_USB_CDC_CONSOLE_ENABLED_DEFAULT=1") + circuitpython_flags.append("-DCIRCUITPY_USB_CDC_DATA_ENABLED_DEFAULT=0") - tinyusb_files.extend( - ( - top / "lib/tinyusb/src/device/usbd.c", - top / "lib/tinyusb/src/device/usbd_control.c", - ) - ) supervisor_source.extend( - (top / "supervisor/shared/usb/usb_desc.c", top / "supervisor/shared/usb/usb_device.c") + (portdir / "supervisor/usb.c", srcdir / "supervisor/shared/usb.c") ) - elif usb_num_endpoint_pairs > 0: - module_reasons["usb_cdc"] = f"No TinyUSB settings for {soc}" - - circuitpython_flags.append(f"-DCIRCUITPY_PORT_SERIAL={0 if usb_ok else 1}") - # ifeq ($(CIRCUITPY_USB_HID), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/class/hid/hid_device.c \ - # shared-bindings/usb_hid/__init__.c \ - # shared-bindings/usb_hid/Device.c \ - # shared-module/usb_hid/__init__.c \ - # shared-module/usb_hid/Device.c \ - - # endif - - # ifeq ($(CIRCUITPY_USB_MIDI), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/class/midi/midi_device.c \ - # shared-bindings/usb_midi/__init__.c \ - # shared-bindings/usb_midi/PortIn.c \ - # shared-bindings/usb_midi/PortOut.c \ - # shared-module/usb_midi/__init__.c \ - # shared-module/usb_midi/PortIn.c \ - # shared-module/usb_midi/PortOut.c \ - - # endif - - # ifeq ($(CIRCUITPY_USB_VIDEO), 1) - # SRC_SUPERVISOR += \ - # shared-bindings/usb_video/__init__.c \ - # shared-module/usb_video/__init__.c \ - # shared-bindings/usb_video/USBFramebuffer.c \ - # shared-module/usb_video/USBFramebuffer.c \ - # lib/tinyusb/src/class/video/video_device.c \ - - # CFLAGS += -DCFG_TUD_VIDEO=1 -DCFG_TUD_VIDEO_STREAMING=1 -DCFG_TUD_VIDEO_STREAMING_EP_BUFSIZE=256 -DCFG_TUD_VIDEO_STREAMING_BULK=1 - # endif - - # ifeq ($(CIRCUITPY_USB_VENDOR), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/class/vendor/vendor_device.c \ - - # endif - - # ifeq ($(CIRCUITPY_TINYUSB_HOST), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/host/hub.c \ - # lib/tinyusb/src/host/usbh.c \ - - # endif - - # ifeq ($(CIRCUITPY_USB_KEYBOARD_WORKFLOW), 1) - # SRC_SUPERVISOR += \ - # lib/tinyusb/src/class/hid/hid_host.c \ - # supervisor/shared/usb/host_keyboard.c \ - - # endif + + # Always use port serial. It'll switch between USB and UART automatically. + circuitpython_flags.append("-DCIRCUITPY_PORT_SERIAL=1") if "ssl" in enabled_modules: # TODO: Figure out how to get these paths from zephyr @@ -588,9 +451,12 @@ async def build_circuitpython(): if enabled: hal_source.extend(portdir.glob(f"bindings/{module.name}/*.c")) + len_before = len(hal_source) hal_source.extend(top.glob(f"ports/zephyr-cp/common-hal/{module.name}/*.c")) + # Only include shared-module/*.c if no common-hal/*.c files were found + if len(hal_source) == len_before or module.name in SHARED_MODULE_AND_COMMON_HAL: + hal_source.extend(top.glob(f"shared-module/{module.name}/*.c")) hal_source.extend(top.glob(f"shared-bindings/{module.name}/*.c")) - hal_source.extend(top.glob(f"shared-module/{module.name}/*.c")) if os.environ.get("CI", "false") == "true": # Fail the build if it isn't up to date. @@ -687,8 +553,6 @@ async def build_circuitpython(): source_files.extend(assembly_files) - source_files.extend(tinyusb_files) - objects = [] async with asyncio.TaskGroup() as tg: for source_file in source_files: diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 8cfbc0118a7..77404ec2bec 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -113,6 +113,35 @@ "GPIO0", "GPIO1", ], + "nxp,cam-44pins-connector": ["CAM_RESETB", "CAM_PWDN"], + "nxp,lcd-8080": [ + "TOUCH_SCL", + "TOUCH_SDA", + "TOUCH_INT", + "BACKLIGHT", + "RESET", + "LCD_DC", + "LCD_CS", + "LCD_WR", + "LCD_RD", + "LCD_TE", + "LCD_D0", + "LCD_D1", + "LCD_D2", + "LCD_D3", + "LCD_D4", + "LCD_D5", + "LCD_D6", + "LCD_D7", + "LCD_D8", + "LCD_D9", + "LCD_D10", + "LCD_D11", + "LCD_D12", + "LCD_D13", + "LCD_D14", + "LCD_D15", + ], "raspberrypi,csi-connector": [ "CSI_D0_N", "CSI_D0_P", @@ -431,7 +460,7 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 continue if driver == "flash": pass # Handled by find_flash_devices() - elif driver == "usb/udc": + elif driver == "usb/udc" or "zephyr_udc0" in node.labels: board_info["usb_device"] = True props = node.props if "num-bidir-endpoints" not in props: @@ -467,7 +496,7 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 all_ioports.append(node.labels[0]) if status == "okay": ioports[node.labels[0]] = set(range(0, ngpios)) - if gpio_map: + if gpio_map and compatible[0] != "gpio-nexus": i = 0 for offset, t, label in gpio_map._markers: if not label: diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 3d2f1fe69aa..485559fe480 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -16,7 +16,13 @@ CONFIG_STACK_SENTINEL=y CONFIG_DEBUG_THREAD_INFO=y # CONFIG_DEBUG_INFO=y -CONFIG_USB_DEVICE_STACK=n +CONFIG_USB_DEVICE_STACK_NEXT=y +CONFIG_USBD_CDC_ACM_CLASS=y +CONFIG_USBD_MAX_SPEED=1 +CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n + +CONFIG_USBD_MSC_CLASS=y +CONFIG_USBD_MSC_LUNS_PER_INSTANCE=1 CONFIG_HWINFO=y CONFIG_REBOOT=y @@ -27,6 +33,9 @@ CONFIG_LOG_BLOCK_IN_THREAD=y CONFIG_EVENTS=y +CONFIG_SERIAL=y +CONFIG_UART_LINE_CTRL=y + CONFIG_I2C=y CONFIG_SPI=y CONFIG_SPI_ASYNC=y diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index c58de56d707..799e44800cf 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -178,3 +178,11 @@ size_t port_heap_get_largest_free_size(void) { // IDF does this. Not sure why. return tlsf_fit_size(heap, max_size); } + +void assert_post_action(const char *file, unsigned int line) { + printk("Assertion failed at %s:%u\n", file, line); + __asm__ ("bkpt"); + while (1) { + ; + } +} diff --git a/ports/zephyr-cp/supervisor/serial.c b/ports/zephyr-cp/supervisor/serial.c index a62e00a7742..3ae3e73fa10 100644 --- a/ports/zephyr-cp/supervisor/serial.c +++ b/ports/zephyr-cp/supervisor/serial.c @@ -6,54 +6,80 @@ #include "supervisor/shared/serial.h" -#if CIRCUITPY_USB_DEVICE == 0 -#include "shared-bindings/busio/UART.h" +#include "supervisor/zephyr-cp.h" -static busio_uart_obj_t zephyr_console; +#if CIRCUITPY_USB_DEVICE == 1 +#include "shared-bindings/usb_cdc/Serial.h" +usb_cdc_serial_obj_t *usb_console; +#else +#include "shared-bindings/busio/UART.h" +static busio_uart_obj_t uart_console; static uint8_t buffer[64]; #endif void port_serial_early_init(void) { #if CIRCUITPY_USB_DEVICE == 0 - zephyr_console.base.type = &busio_uart_type; - common_hal_busio_uart_construct_from_device(&zephyr_console, DEVICE_DT_GET(DT_CHOSEN(zephyr_console)), sizeof(buffer), buffer); + uart_console.base.type = &busio_uart_type; + common_hal_busio_uart_construct_from_device(&uart_console, DEVICE_DT_GET(DT_CHOSEN(zephyr_console)), sizeof(buffer), buffer); #endif } void port_serial_init(void) { + #if CIRCUITPY_USB_DEVICE == 1 + usb_console = usb_cdc_serial_get_console(); + #endif } bool port_serial_connected(void) { #if CIRCUITPY_USB_DEVICE == 1 - return false; + if (usb_console == NULL) { + return false; + } + return common_hal_usb_cdc_serial_get_connected(usb_console); #else return true; #endif } char port_serial_read(void) { - #if CIRCUITPY_USB_DEVICE == 0 + #if CIRCUITPY_USB_DEVICE == 1 + if (usb_console == NULL) { + return -1; + } char buf[1]; - size_t count = common_hal_busio_uart_read(&zephyr_console, buf, 1, NULL); + size_t count = common_hal_usb_cdc_serial_read(usb_console, buf, 1, NULL); if (count == 0) { return -1; } return buf[0]; #else - return -1; + char buf[1]; + size_t count = common_hal_busio_uart_read(&uart_console, buf, 1, NULL); + if (count == 0) { + return -1; + } + return buf[0]; #endif } uint32_t port_serial_bytes_available(void) { - #if CIRCUITPY_USB_DEVICE == 0 - return common_hal_busio_uart_rx_characters_available(&zephyr_console); + #if CIRCUITPY_USB_DEVICE == 1 + if (usb_console == NULL) { + return 0; + } + return common_hal_usb_cdc_serial_get_in_waiting(usb_console); #else - return 0; + return common_hal_busio_uart_rx_characters_available(&uart_console); #endif } void port_serial_write_substring(const char *text, uint32_t length) { - #if CIRCUITPY_USB_DEVICE == 0 - common_hal_busio_uart_write(&zephyr_console, text, length, NULL); + #if CIRCUITPY_USB_DEVICE == 1 + if (usb_console == NULL) { + return; + } + common_hal_usb_cdc_serial_write(usb_console, text, length, NULL); + #else + common_hal_busio_uart_write(&uart_console, text, length, NULL); #endif } diff --git a/ports/zephyr-cp/supervisor/usb.c b/ports/zephyr-cp/supervisor/usb.c index 18eb2847ad9..844d4fae759 100644 --- a/ports/zephyr-cp/supervisor/usb.c +++ b/ports/zephyr-cp/supervisor/usb.c @@ -1,202 +1,364 @@ #include "supervisor/usb.h" -#include "tusb_option.h" +#include "shared-bindings/usb_cdc/__init__.h" +#include "shared-bindings/usb_cdc/Serial.h" -#if CFG_TUSB_MCU == OPT_MCU_STM32U5 -#include -#endif +#include "supervisor/zephyr-cp.h" -#if CFG_TUSB_MCU == OPT_MCU_NRF5X -#include -#include -#endif +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" +#include "lib/oofatfs/diskio.h" +#include "lib/oofatfs/ff.h" #include +#include #include -#include #include +#include +#include -#if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otghs) -#define UDC_IRQ_NAME otghs -#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_otgfs) -#define UDC_IRQ_NAME otgfs -#elif DT_HAS_COMPAT_STATUS_OKAY(st_stm32_usb) -#define UDC_IRQ_NAME usb -#elif DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_usb) -#define UDC_IRQ_NAME usbhs_ir -#endif +#include "shared-module/storage/__init__.h" +#include "supervisor/filesystem.h" +#include "supervisor/shared/reload.h" -#if DT_HAS_COMPAT_STATUS_OKAY(renesas_ra_usb) -#define USB_NAME usbhs -#else -#define USB_NAME zephyr_udc0 -#endif +#include +LOG_MODULE_REGISTER(usb, LOG_LEVEL_INF); + +#define USB_DEVICE DT_NODELABEL(zephyr_udc0) + +USBD_DEVICE_DEFINE(main_usbd, + DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), + USB_VID, USB_PID); + +USBD_DESC_LANG_DEFINE(main_lang); +USBD_DESC_MANUFACTURER_DEFINE(main_mfr, USB_MANUFACTURER); +USBD_DESC_PRODUCT_DEFINE(main_product, USB_PRODUCT); + +USBD_DESC_CONFIG_DEFINE(fs_cfg_desc, "FS Configuration"); +USBD_DESC_CONFIG_DEFINE(hs_cfg_desc, "HS Configuration"); -#define USB_DEVICE DT_NODELABEL(USB_NAME) +/* doc configuration instantiation start */ +static const uint8_t attributes = 0; -#ifdef UDC_IRQ_NAME -#define UDC_IRQ DT_IRQ_BY_NAME(USB_DEVICE, UDC_IRQ_NAME, irq) -#define UDC_IRQ_PRI DT_IRQ_BY_NAME(USB_DEVICE, UDC_IRQ_NAME, priority) -#else -#define UDC_IRQ DT_IRQ(USB_DEVICE, irq) -#define UDC_IRQ_PRI DT_IRQ(USB_DEVICE, priority) +USBD_CONFIGURATION_DEFINE(main_fs_config, + attributes, + 100, &fs_cfg_desc); + +USBD_CONFIGURATION_DEFINE(main_hs_config, + attributes, + 100, &hs_cfg_desc); + +static usb_cdc_serial_obj_t usb_cdc_console_obj; +static usb_cdc_serial_obj_t usb_cdc_data_obj; + +#ifndef USBD_DEFINE_MSC_LUN +#error "MSC not enabled" #endif -PINCTRL_DT_DEFINE(USB_DEVICE); -static const struct pinctrl_dev_config *usb_pcfg = - PINCTRL_DT_DEV_CONFIG_GET(USB_DEVICE); +#define LUN_COUNT 1 +#define MSC_FLASH_BLOCK_SIZE 512 + +// The ellipsis range in the designated initializer of `ejected` is not standard C, +// but it works in both gcc and clang. +static bool locked[LUN_COUNT] = { [0 ... (LUN_COUNT - 1)] = false}; + +// Set to true if a write was in a file data or metadata area, +// as opposed to in the filesystem metadata area (e.g., dirty bit). +// Used to determine if an auto-reload is warranted. +static bool content_write[LUN_COUNT] = { [0 ... (LUN_COUNT - 1)] = false}; + +int _zephyr_disk_init(struct disk_info *disk); +int _zephyr_disk_status(struct disk_info *disk); +int _zephyr_disk_read(struct disk_info *disk, uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector); +int _zephyr_disk_write(struct disk_info *disk, const uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector); +int _zephyr_disk_ioctl(struct disk_info *disk, uint8_t cmd, void *buff); + +static const struct disk_operations disk_ops = { + .init = _zephyr_disk_init, + .status = _zephyr_disk_status, + .read = _zephyr_disk_read, + .write = _zephyr_disk_write, + .ioctl = _zephyr_disk_ioctl, +}; -#if CFG_TUSB_MCU == OPT_MCU_NRF5X -// Value is chosen to be as same as NRFX_POWER_USB_EVT_* in nrfx_power.h -enum { - USB_EVT_DETECTED = 0, - USB_EVT_REMOVED = 1, - USB_EVT_READY = 2 +static struct disk_info circuitpy_disk = { + .name = "CIRCUITPY", + .ops = &disk_ops, + .dev = NULL }; -#ifdef NRF5340_XXAA - #define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC - #define VBUSDETECT_Msk USBREG_USBREGSTATUS_VBUSDETECT_Msk - #define OUTPUTRDY_Msk USBREG_USBREGSTATUS_OUTPUTRDY_Msk - #define GPIOTE_IRQn GPIOTE1_IRQn -#else - #define LFCLK_SRC_RC CLOCK_LFCLKSRC_SRC_RC - #define VBUSDETECT_Msk POWER_USBREGSTATUS_VBUSDETECT_Msk - #define OUTPUTRDY_Msk POWER_USBREGSTATUS_OUTPUTRDY_Msk -#endif +USBD_DEFINE_MSC_LUN(circuitpy_lun, "CIRCUITPY", "Zephyr", "FlashDisk", "0.00"); -// tinyusb function that handles power event (detected, ready, removed) -// We must call it within SD's SOC event handler, or set it as power event handler if SD is not enabled. -extern void tusb_hal_nrf_power_event(uint32_t event); -// nrf power callback, could be unused if SD is enabled or usb is disabled (board_test example) -TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) { - tusb_hal_nrf_power_event((uint32_t)event); +int _zephyr_disk_init(struct disk_info *disk) { + printk("Initializing disk\n"); + return 0; } -#endif -void init_usb_hardware(void) { - #if CFG_TUSB_MCU == OPT_MCU_RAXXX - #if !USBHS_PHY_CLOCK_SOURCE_IS_XTAL - if (data->udc_cfg.usb_speed == USBD_SPEED_HS) { - LOG_ERR("High-speed operation is not supported in case PHY clock source is not " - "XTAL"); - return; +int _zephyr_disk_status(struct disk_info *disk) { + fs_user_mount_t *root = filesystem_circuitpy(); + int lun = 0; + if (root == NULL) { + printk("Status: No media\n"); + return DISK_STATUS_NOMEDIA; } - #endif + if (!filesystem_is_writable_by_usb(root)) { + printk("Status: Read-only\n"); + return DISK_STATUS_WR_PROTECT; + } + // Lock the blockdev once we say we're writable. + if (!locked[lun] && !blockdev_lock(root)) { + printk("Status: Locked\n"); + return DISK_STATUS_WR_PROTECT; + } + locked[lun] = true; + return DISK_STATUS_OK; +} + +int _zephyr_disk_read(struct disk_info *disk, uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector) { + fs_user_mount_t *root = filesystem_circuitpy(); + + uint32_t disk_block_count; + disk_ioctl(root, GET_SECTOR_COUNT, &disk_block_count); + + if (start_sector + num_sector > disk_block_count) { + return -EIO; + } + disk_read(root, data_buf, start_sector, num_sector); + return 0; +} - R_ICU->IELSR[UDC_IRQ] = ELC_EVENT_USBHS_USB_INT_RESUME; +int _zephyr_disk_write(struct disk_info *disk, const uint8_t *data_buf, uint32_t start_sector, uint32_t num_sector) { + fs_user_mount_t *root = filesystem_circuitpy(); + int lun = 0; + autoreload_suspend(AUTORELOAD_SUSPEND_USB); + disk_write(root, data_buf, start_sector, num_sector); + // Since by getting here we assume the mount is read-only to + // CircuitPython let's update the cached FatFs sector if it's the one + // we just wrote. + if + #if FF_MAX_SS != FF_MIN_SS + (root->fatfs.ssize == MSC_FLASH_BLOCK_SIZE) + #else + // The compiler can optimize this away. + (FF_MAX_SS == FILESYSTEM_BLOCK_SIZE) #endif + { + if (start_sector == root->fatfs.winsect && start_sector > 0) { + memcpy(root->fatfs.win, + data_buf + MSC_FLASH_BLOCK_SIZE * (root->fatfs.winsect - start_sector), + MSC_FLASH_BLOCK_SIZE); + } + } + + // A write to an lba below fatbase is in the filesystem metadata (BPB) area or the "Reserved Region", + // and is probably setting or clearing the dirty bit. This should not trigger auto-reload. + // All other writes will trigger auto-reload. + if (start_sector >= root->fatfs.fatbase) { + content_write[lun] = true; + } + return 0; +} + +int _zephyr_disk_ioctl(struct disk_info *disk, uint8_t cmd, void *buff) { + + fs_user_mount_t *root = filesystem_circuitpy(); + int lun = 0; + switch (cmd) { + case DISK_IOCTL_GET_SECTOR_COUNT: + disk_ioctl(root, GET_SECTOR_COUNT, buff); + return 0; + case DISK_IOCTL_GET_SECTOR_SIZE: + disk_ioctl(root, GET_SECTOR_SIZE, buff); + return 0; + case DISK_IOCTL_CTRL_SYNC: + disk_ioctl(root, CTRL_SYNC, buff); + autoreload_resume(AUTORELOAD_SUSPEND_USB); + + // This write is complete; initiate an autoreload if this was a file data or metadata write, + // not just a dirty-bit write. + if (content_write[lun] && lun == 0) { + autoreload_trigger(); + content_write[lun] = false; + } + return 0; + default: + printk("Unsupported disk ioctl %02x\n", cmd); + return -ENOTSUP; + } + return 0; +} +static void _msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg) { + LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type)); +} + +void usb_init(void) { + printk("Initializing USB\n"); + int err; - IRQ_CONNECT(UDC_IRQ, UDC_IRQ_PRI, usb_irq_handler, 0, 0); + printk("Adding language descriptor\n"); + err = usbd_add_descriptor(&main_usbd, &main_lang); + if (err) { + LOG_ERR("Failed to initialize language descriptor (%d)", err); + return; + } - /* Configure USB GPIOs */ - int err = pinctrl_apply_state(usb_pcfg, PINCTRL_STATE_DEFAULT); - if (err < 0) { - printk("USB pinctrl setup failed (%d)\n", err); - } else { - printk("USB pins setup\n"); + err = usbd_add_descriptor(&main_usbd, &main_mfr); + if (err) { + LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); + return; } -// #ifdef USB_DRD_FS -// // STM32U535/STM32U545 + err = usbd_add_descriptor(&main_usbd, &main_product); + if (err) { + LOG_ERR("Failed to initialize product descriptor (%d)", err); + return; + } -// /* Enable USB power on Pwrctrl CR2 register */ -// HAL_PWREx_EnableVddUSB(); + bool console = usb_cdc_console_enabled(); + if (console) { + uint8_t *receiver_buffer = port_malloc(128, true); + if (receiver_buffer != NULL) { + common_hal_usb_cdc_serial_construct_from_device(&usb_cdc_console_obj, DEVICE_DT_GET(DT_NODELABEL(cdc_acm_console)), 128, receiver_buffer); + } else { + console = false; + } + } + usb_cdc_set_console(console ? MP_OBJ_FROM_PTR(&usb_cdc_console_obj) : mp_const_none); + + bool data = usb_cdc_data_enabled(); + if (data) { + uint8_t *receiver_buffer = port_malloc(128, true); + if (receiver_buffer != NULL) { + common_hal_usb_cdc_serial_construct_from_device(&usb_cdc_data_obj, DEVICE_DT_GET(DT_NODELABEL(cdc_acm_data)), 128, receiver_buffer); + } else { + data = false; + } + } + usb_cdc_set_data(data ? MP_OBJ_FROM_PTR(&usb_cdc_data_obj) : mp_const_none); -// /* USB clock enable */ -// __HAL_RCC_USB_FS_CLK_ENABLE(); + err = disk_access_register(&circuitpy_disk); + if (err) { + printk("Failed to register disk access %d\n", err); + return; + } -// #endif + if (USBD_SUPPORTS_HIGH_SPEED && + usbd_caps_speed(&main_usbd) == USBD_SPEED_HS) { + printk("Adding High-Speed configuration\n"); + err = usbd_add_configuration(&main_usbd, USBD_SPEED_HS, + &main_hs_config); + if (err) { + LOG_ERR("Failed to add High-Speed configuration"); + return; + } + + printk("Registering High-Speed cdc_acm class\n"); + if (usb_cdc_console_enabled()) { + err = usbd_register_class(&main_usbd, "cdc_acm_0", USBD_SPEED_HS, 1); + if (err) { + printk("Failed to add register classes %d\n", err); + return; + } + } + + if (usb_cdc_data_enabled()) { + err = usbd_register_class(&main_usbd, "cdc_acm_1", USBD_SPEED_HS, 1); + if (err) { + printk("Failed to add register classes %d\n", err); + return; + } + } + + err = usbd_register_class(&main_usbd, "msc_0", USBD_SPEED_HS, 1); + if (err) { + printk("Failed to add register MSC class %d\n", err); + return; + } else { + printk("Registered MSC class for high speed\n"); + } + + usbd_device_set_code_triple(&main_usbd, USBD_SPEED_HS, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + } - #if CFG_TUSB_MCU == OPT_MCU_STM32U5 && defined(USB_OTG_FS) - /* Enable USB power on Pwrctrl CR2 register */ - // HAL_PWREx_EnableVddUSB(); - LL_PWR_EnableVddUSB(); + /* doc configuration register start */ + printk("Adding Full-Speed configuration\n"); + err = usbd_add_configuration(&main_usbd, USBD_SPEED_FS, + &main_fs_config); + if (err) { + LOG_ERR("Failed to add Full-Speed configuration"); + return; + } + /* doc configuration register end */ - /* USB clock enable */ - __HAL_RCC_USB_OTG_FS_CLK_ENABLE(); + /* doc functions register start */ - #endif + if (usb_cdc_console_enabled()) { + printk("Registering Full-Speed cdc_acm class\n"); + err = usbd_register_class(&main_usbd, "cdc_acm_0", USBD_SPEED_FS, 1); + if (err) { + printk("Failed to add register classes\n"); + return; + } + } -// #ifdef USB_OTG_HS -// // STM59x/Ax/Fx/Gx only have 1 USB HS port + if (usb_cdc_data_enabled()) { + printk("Registering Full-Speed cdc_acm class\n"); + err = usbd_register_class(&main_usbd, "cdc_acm_1", USBD_SPEED_FS, 1); + if (err) { + printk("Failed to add register classes\n"); + return; + } + } -// #if CFG_TUSB_OS == OPT_OS_FREERTOS -// // If freeRTOS is used, IRQ priority is limit by max syscall ( smaller is higher ) -// NVIC_SetPriority(OTG_HS_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY); -// #endif + err = usbd_register_class(&main_usbd, "msc_0", USBD_SPEED_FS, 1); + if (err) { + printk("Failed to add register MSC class %d\n", err); + return; + } + /* doc functions register end */ -// /* USB clock enable */ -// __HAL_RCC_USB_OTG_HS_CLK_ENABLE(); -// __HAL_RCC_USBPHYC_CLK_ENABLE(); + usbd_device_set_code_triple(&main_usbd, USBD_SPEED_FS, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + printk("Setting self powered\n"); + usbd_self_powered(&main_usbd, attributes & USB_SCD_SELF_POWERED); -// /* Enable USB power on Pwrctrl CR2 register */ -// HAL_PWREx_EnableVddUSB(); -// HAL_PWREx_EnableUSBHSTranceiverSupply(); + printk("Registering callback\n"); + err = usbd_msg_register_cb(&main_usbd, _msg_cb); + if (err) { + LOG_ERR("Failed to register message callback"); + return; + } -// /*Configuring the SYSCFG registers OTG_HS PHY*/ -// HAL_SYSCFG_EnableOTGPHY(SYSCFG_OTG_HS_PHY_ENABLE); + printk("usbd_init\n"); + err = usbd_init(&main_usbd); + if (err) { + LOG_ERR("Failed to initialize device support"); + return; + } -// // Disable VBUS sense (B device) -// USB_OTG_HS->GCCFG &= ~USB_OTG_GCCFG_VBDEN; + printk("USB initialized\n"); -// // B-peripheral session valid override enable -// USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBVALEXTOEN; -// USB_OTG_HS->GCCFG |= USB_OTG_GCCFG_VBVALOVAL; -// #endif // USB_OTG_FS + err = usbd_enable(&main_usbd); + if (err) { + LOG_ERR("Failed to enable device support"); + return; + } + printk("usbd enabled\n"); +} +bool usb_connected(void) { + return false; +} - #if CFG_TUSB_MCU == OPT_MCU_NRF5X - #ifdef CONFIG_HAS_HW_NRF_USBREG - /* Use CLOCK/POWER priority for compatibility with other series where - * USB events are handled by CLOCK interrupt handler. - */ - IRQ_CONNECT(USBREGULATOR_IRQn, - DT_IRQ(DT_INST(0, nordic_nrf_clock), priority), - nrfx_isr, nrfx_usbreg_irq_handler, 0); - irq_enable(USBREGULATOR_IRQn); - #endif - // USB power may already be ready at this time -> no event generated - // We need to invoke the handler based on the status initially - uint32_t usb_reg; - { - // Power module init - static const nrfx_power_config_t pwr_cfg = { - .dcdcen = (DT_PROP(DT_INST(0, nordic_nrf5x_regulator), regulator_initial_mode) - == NRF5X_REG_MODE_DCDC), - #if NRFX_POWER_SUPPORTS_DCDCEN_VDDH - .dcdcenhv = COND_CODE_1(CONFIG_SOC_SERIES_NRF52X, - (DT_NODE_HAS_STATUS_OKAY(DT_INST(0, nordic_nrf52x_regulator_hv))), - (DT_NODE_HAS_STATUS_OKAY(DT_INST(0, nordic_nrf53x_regulator_hv)))), - #endif - }; - nrfx_power_init(&pwr_cfg); - - // Register tusb function as USB power handler - // cause cast-function-type warning - const nrfx_power_usbevt_config_t config = {.handler = power_event_handler}; - nrfx_power_usbevt_init(&config); - nrfx_power_usbevt_enable(); - - // USB power may already be ready at this time -> no event generated - // We need to invoke the handler based on the status initially - #ifdef NRF5340_XXAA - usb_reg = NRF_USBREGULATOR->USBREGSTATUS; - #else - usb_reg = NRF_POWER->USBREGSTATUS; - #endif - } - - if (usb_reg & VBUSDETECT_Msk) { - tusb_hal_nrf_power_event(USB_EVT_DETECTED); - } - if (usb_reg & OUTPUTRDY_Msk) { - tusb_hal_nrf_power_event(USB_EVT_READY); - } - - printk("usb started hopefully\n"); - #endif +void usb_disconnect(void) { +} +usb_cdc_serial_obj_t *usb_cdc_serial_get_console(void) { + if (usb_cdc_console_enabled()) { + return &usb_cdc_console_obj; + } + return NULL; } diff --git a/ports/zephyr-cp/supervisor/zephyr-cp.h b/ports/zephyr-cp/supervisor/zephyr-cp.h new file mode 100644 index 00000000000..ecf7d42e3b4 --- /dev/null +++ b/ports/zephyr-cp/supervisor/zephyr-cp.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/usb_cdc/Serial.h" + +usb_cdc_serial_obj_t *usb_cdc_serial_get_console(void); diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 4acbf96db03..386d1ee3d1e 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -650,7 +650,7 @@ void background_callback_run_all(void); // Align the internal sector buffer. Useful when it is passed into TinyUSB for // loads. #ifndef MICROPY_FATFS_WINDOW_ALIGNMENT -#define MICROPY_FATFS_WINDOW_ALIGNMENT CIRCUITPY_TUSB_MEM_ALIGN +#define MICROPY_FATFS_WINDOW_ALIGNMENT 64 // Espressif is strictest #endif #define FF_FS_CASE_INSENSITIVE_COMPARISON_ASCII_ONLY (1) diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index 26892a79462..65c5f80b52b 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -53,10 +53,12 @@ //| import sdcardio //| import storage //| +//| # Make sure to make an "sd" folder on CIRCUITPY +//| //| sd = sdcardio.SDCard(board.SPI(), board.SD_CS) //| vfs = storage.VfsFat(sd) //| storage.mount(vfs, '/sd') -//| os.listdir('/sd')""" +//| print(os.listdir('/sd'))""" //| static void check_for_deinit(sdcardio_sdcard_obj_t *self) { diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index 7b497639939..20cfd2e8200 100644 --- a/shared-bindings/supervisor/Runtime.c +++ b/shared-bindings/supervisor/Runtime.c @@ -20,12 +20,12 @@ #include "supervisor/shared/status_leds.h" #include "supervisor/shared/bluetooth/bluetooth.h" -#if CIRCUITPY_DISPLAYIO -#include "shared-bindings/displayio/__init__.h" +#if CIRCUITPY_USB_DEVICE +#include "supervisor/usb.h" #endif -#if CIRCUITPY_TINYUSB -#include "tusb.h" +#if CIRCUITPY_DISPLAYIO +#include "shared-bindings/displayio/__init__.h" #endif static supervisor_run_reason_t _run_reason; @@ -52,7 +52,7 @@ static supervisor_run_reason_t _run_reason; //| """Returns the USB enumeration status (read-only).""" static mp_obj_t supervisor_runtime_get_usb_connected(mp_obj_t self) { #if CIRCUITPY_USB_DEVICE - return mp_obj_new_bool(tud_ready()); + return mp_obj_new_bool(usb_connected()); #else return mp_const_false; #endif diff --git a/shared-bindings/usb_cdc/Serial.c b/shared-bindings/usb_cdc/Serial.c index 4d6851351af..eb526615927 100644 --- a/shared-bindings/usb_cdc/Serial.c +++ b/shared-bindings/usb_cdc/Serial.c @@ -194,7 +194,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_reset_output_buffer_obj, usb_cdc_serial static mp_obj_t usb_cdc_serial_get_timeout(mp_obj_t self_in) { usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_float_t timeout = common_hal_usb_cdc_serial_get_timeout(self); - return (timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->timeout); + return (timeout < 0.0f) ? mp_const_none : mp_obj_new_float(timeout); } MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_timeout_obj, usb_cdc_serial_get_timeout); @@ -219,7 +219,7 @@ MP_PROPERTY_GETSET(usb_cdc_serial_timeout_obj, static mp_obj_t usb_cdc_serial_get_write_timeout(mp_obj_t self_in) { usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_float_t write_timeout = common_hal_usb_cdc_serial_get_write_timeout(self); - return (write_timeout < 0.0f) ? mp_const_none : mp_obj_new_float(self->write_timeout); + return (write_timeout < 0.0f) ? mp_const_none : mp_obj_new_float(write_timeout); } MP_DEFINE_CONST_FUN_OBJ_1(usb_cdc_serial_get_write_timeout_obj, usb_cdc_serial_get_write_timeout); diff --git a/shared-bindings/usb_cdc/Serial.h b/shared-bindings/usb_cdc/Serial.h index 30249cef389..091f7514a4f 100644 --- a/shared-bindings/usb_cdc/Serial.h +++ b/shared-bindings/usb_cdc/Serial.h @@ -6,7 +6,11 @@ #pragma once +#if defined(__ZEPHYR__) && __ZEPHYR__ == 1 +#include "common-hal/usb_cdc/Serial.h" +#else #include "shared-module/usb_cdc/Serial.h" +#endif extern const mp_obj_type_t usb_cdc_serial_type; diff --git a/shared-bindings/usb_cdc/__init__.h b/shared-bindings/usb_cdc/__init__.h index 34099f7e8fd..154f259f410 100644 --- a/shared-bindings/usb_cdc/__init__.h +++ b/shared-bindings/usb_cdc/__init__.h @@ -6,7 +6,11 @@ #pragma once +#if defined(__ZEPHYR__) && __ZEPHYR__ == 1 +#include "common-hal/usb_cdc/__init__.h" +#else #include "shared-module/usb_cdc/__init__.h" +#endif // Set the module dict entries. void usb_cdc_set_console(mp_obj_t serial_obj); diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c index 94b429b6ab6..5728a95e08f 100644 --- a/supervisor/shared/serial.c +++ b/supervisor/shared/serial.c @@ -219,7 +219,7 @@ void serial_init(void) { } bool serial_connected(void) { - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR if (tud_vendor_connected()) { return true; } @@ -235,11 +235,11 @@ bool serial_connected(void) { } #endif - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC if (usb_cdc_console_enabled() && tud_cdc_connected()) { return true; } - #elif CIRCUITPY_USB_DEVICE + #elif CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE if (tud_cdc_connected()) { return true; } @@ -273,7 +273,7 @@ bool serial_connected(void) { } char serial_read(void) { - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR if (tud_vendor_connected() && tud_vendor_available() > 0) { char tiny_buffer; tud_vendor_read(&tiny_buffer, 1); @@ -327,7 +327,7 @@ char serial_read(void) { return -1; } #endif - #if CIRCUITPY_USB_DEVICE + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE return (char)tud_cdc_read_char(); #endif @@ -338,7 +338,7 @@ uint32_t serial_bytes_available(void) { // There may be multiple serial input channels, so sum the count from all. uint32_t count = 0; - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR if (tud_vendor_connected()) { count += tud_vendor_available(); } @@ -360,7 +360,7 @@ uint32_t serial_bytes_available(void) { count += usb_keyboard_chars_available(); #endif - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC if (usb_cdc_console_enabled()) { count += tud_cdc_available(); } @@ -399,7 +399,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) { return length_sent; } - #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VENDOR if (tud_vendor_connected()) { length_sent = tud_vendor_write(text, length); } @@ -423,7 +423,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) { } #endif - #if CIRCUITPY_USB_DEVICE + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE // Delay the very first write if (tud_cdc_connected() && !_first_write_done) { mp_hal_delay_ms(50); diff --git a/supervisor/shared/usb.c b/supervisor/shared/usb.c new file mode 100644 index 00000000000..ff0dd1f8467 --- /dev/null +++ b/supervisor/shared/usb.c @@ -0,0 +1,65 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/usb.h" + +#if CIRCUITPY_STORAGE +#include "shared-module/storage/__init__.h" +#endif + +#if CIRCUITPY_USB_DEVICE +#include "shared-bindings/supervisor/__init__.h" + +#if CIRCUITPY_USB_CDC +#include "shared-module/usb_cdc/__init__.h" +#endif + +#if CIRCUITPY_USB_HID +#include "shared-module/usb_hid/__init__.h" +#endif + +#if CIRCUITPY_USB_MIDI +#include "shared-module/usb_midi/__init__.h" +#endif + +#if CIRCUITPY_USB_VIDEO +#include "shared-module/usb_video/__init__.h" +#endif +#endif + +// Set up USB defaults before any USB changes are made in boot.py +void usb_set_defaults(void) { + #if CIRCUITPY_USB_DEVICE + #if CIRCUITPY_STORAGE && CIRCUITPY_USB_MSC + storage_usb_set_defaults(); + #endif + + #if CIRCUITPY_USB_CDC + usb_cdc_set_defaults(); + #endif + + #if CIRCUITPY_USB_HID + usb_hid_set_defaults(); + #endif + + #if CIRCUITPY_USB_MIDI + usb_midi_set_defaults(); + #endif + #endif +}; + +// Call this when ready to run code.py or a REPL, and a VM has been started. +void usb_setup_with_vm(void) { + #if CIRCUITPY_USB_DEVICE + #if CIRCUITPY_USB_HID + usb_hid_setup_devices(); + #endif + + #if CIRCUITPY_USB_MIDI + usb_midi_setup_ports(); + #endif + #endif +} diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index e67c15d022c..86a0cf8237e 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -87,6 +87,10 @@ bool usb_enabled(void) { return tusb_inited(); } +bool usb_connected(void) { + return tud_ready(); +} + MP_WEAK void post_usb_init(void) { } @@ -144,40 +148,6 @@ void usb_init(void) { #endif } -// Set up USB defaults before any USB changes are made in boot.py -void usb_set_defaults(void) { - #if CIRCUITPY_USB_DEVICE - #if CIRCUITPY_STORAGE && CIRCUITPY_USB_MSC - storage_usb_set_defaults(); - #endif - - #if CIRCUITPY_USB_CDC - usb_cdc_set_defaults(); - #endif - - #if CIRCUITPY_USB_HID - usb_hid_set_defaults(); - #endif - - #if CIRCUITPY_USB_MIDI - usb_midi_set_defaults(); - #endif - #endif -}; - -// Call this when ready to run code.py or a REPL, and a VM has been started. -void usb_setup_with_vm(void) { - #if CIRCUITPY_USB_DEVICE - #if CIRCUITPY_USB_HID - usb_hid_setup_devices(); - #endif - - #if CIRCUITPY_USB_MIDI - usb_midi_setup_ports(); - #endif - #endif -} - void usb_background(void) { if (usb_enabled()) { #if CFG_TUSB_OS == OPT_OS_NONE || CFG_TUSB_OS == OPT_OS_PICO diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index df2055580fc..c1999b4a7b6 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -89,7 +89,7 @@ bool supervisor_workflow_active(void) { void supervisor_workflow_start(void) { // Start USB after giving boot.py a chance to tweak behavior. - #if CIRCUITPY_TINYUSB + #if CIRCUITPY_USB_DEVICE // Setup USB connection after heap is available. // It needs the heap to build descriptors. usb_init(); diff --git a/supervisor/usb.h b/supervisor/usb.h index 10f033a3616..d6e4236c9b4 100644 --- a/supervisor/usb.h +++ b/supervisor/usb.h @@ -48,6 +48,7 @@ typedef struct { bool usb_enabled(void); void usb_add_interface_string(uint8_t interface_string_index, const char str[]); bool usb_build_descriptors(const usb_identification_t *identification); +bool usb_connected(void); void usb_disconnect(void); void usb_init(void); void usb_set_defaults(void); From eb0be7e240320210b3f41d7150f80a2c48042098 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 18 Dec 2025 10:07:01 -0800 Subject: [PATCH 136/876] Add new usb.c to old builds --- supervisor/supervisor.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 4848915630c..9ebdd52068e 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -116,6 +116,7 @@ ifeq ($(CIRCUITPY_TINYUSB),1) lib/tinyusb/src/common/tusb_fifo.c \ lib/tinyusb/src/tusb.c \ supervisor/usb.c \ + supervisor/shared/usb.c \ supervisor/shared/usb/usb.c \ ifeq ($(CIRCUITPY_USB_DEVICE),1) From 248dd38ef36b588752e5ac0b9484e3112bf5cf79 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 18 Dec 2025 11:13:33 -0800 Subject: [PATCH 137/876] Fix host-only tinyusb builds --- supervisor/shared/usb/usb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index 86a0cf8237e..fbe8be97882 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -88,7 +88,11 @@ bool usb_enabled(void) { } bool usb_connected(void) { + #if CIRCUITPY_TINYUSB && CIRCUITPY_USB_DEVICE return tud_ready(); + #else + return false; + #endif } MP_WEAK void post_usb_init(void) { From 51057e75d8f418e4696eeffd08fecdc48090341b Mon Sep 17 00:00:00 2001 From: noqman Date: Mon, 22 Dec 2025 04:32:10 +0800 Subject: [PATCH 138/876] Add frozen PAJ7620 submodule and adjust firmware flash allocation --- .gitmodules | 3 +++ frozen/CircuitPython_edupico2_paj7620 | 1 + .../boards/cytron_edu_pico_v2_2w/link.ld | 1 + .../cytron_edu_pico_v2_2w/mpconfigboard.mk | 17 +++++++++++------ 4 files changed, 16 insertions(+), 6 deletions(-) create mode 160000 frozen/CircuitPython_edupico2_paj7620 create mode 100644 ports/raspberrypi/boards/cytron_edu_pico_v2_2w/link.ld diff --git a/.gitmodules b/.gitmodules index 4cef2eeb9d5..a7b67b8d860 100644 --- a/.gitmodules +++ b/.gitmodules @@ -418,3 +418,6 @@ [submodule "frozen/Adafruit_CircuitPython_OPT4048"] path = frozen/Adafruit_CircuitPython_OPT4048 url = https://github.com/adafruit/Adafruit_CircuitPython_OPT4048.git +[submodule "frozen/CircuitPython_edupico2_paj7620"] + path = frozen/CircuitPython_edupico2_paj7620 + url = https://github.com/CytronTechnologies/CircuitPython_edupico2_paj7620.git diff --git a/frozen/CircuitPython_edupico2_paj7620 b/frozen/CircuitPython_edupico2_paj7620 new file mode 160000 index 00000000000..16a4d784724 --- /dev/null +++ b/frozen/CircuitPython_edupico2_paj7620 @@ -0,0 +1 @@ +Subproject commit 16a4d784724992862cffd594aeed8c627ecc18b3 diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/link.ld b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/link.ld new file mode 100644 index 00000000000..e814bead4c5 --- /dev/null +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/link.ld @@ -0,0 +1 @@ +firmware_size = 1532k; diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk index 2bea1359b4a..1fa8666cfad 100644 --- a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk @@ -9,10 +9,10 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" -CIRCUITPY__EVE = 1 - CIRCUITPY_SDCARDIO = 1 +CIRCUITPY__EVE = 1 + CIRCUITPY_CYW43 = 1 CIRCUITPY_SSL = 1 CIRCUITPY_HASHLIB = 1 @@ -21,6 +21,11 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 +CIRCUITPY_MAX3421E = 0 +CIRCUITPY_ULAB = 0 +CIRCUITPY_ZLIB = 0 +CIRCUITPY_SSL_MBEDTLS = 0 + CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ @@ -33,9 +38,6 @@ CFLAGS += \ -DCYW43_WL_GPIO_LED_PIN=0 -DCYW43_PIO_CLOCK_DIV_INT=3 -# Must be accompanied by a linker script change -CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' - # The default is -O3. Change to -O2 because the build was overflowing. OPTIMIZATION_FLAGS = -O2 @@ -46,9 +48,12 @@ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Motor FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SimpleIO FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_OPT4048 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 -FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_OPT4048 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ImageLoad FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_AHTx0 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HTTPServer +FROZEN_MPY_DIRS += $(TOP)/frozen/CircuitPython_edupico2_paj7620 + +CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' From 195938db6b57051b51381c85b5e7a22023bd8bd5 Mon Sep 17 00:00:00 2001 From: Noqman Muzafar Date: Mon, 22 Dec 2025 14:55:48 +0800 Subject: [PATCH 139/876] Re-enable CIRCUITPY_SSL_MBEDTLS and change the optimization flag to -Os --- .../boards/cytron_edu_pico_v2_2w/mpconfigboard.mk | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk index 1fa8666cfad..6bcb010159e 100644 --- a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk @@ -24,7 +24,6 @@ CIRCUITPY_WIFI = 1 CIRCUITPY_MAX3421E = 0 CIRCUITPY_ULAB = 0 CIRCUITPY_ZLIB = 0 -CIRCUITPY_SSL_MBEDTLS = 0 CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ @@ -38,8 +37,8 @@ CFLAGS += \ -DCYW43_WL_GPIO_LED_PIN=0 -DCYW43_PIO_CLOCK_DIV_INT=3 -# The default is -O3. Change to -O2 because the build was overflowing. -OPTIMIZATION_FLAGS = -O2 +# The default is -O3. +OPTIMIZATION_FLAGS = -Os # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Text From 83a933d1b2209968adc6d01e7d00dbac3de3e2d0 Mon Sep 17 00:00:00 2001 From: Noqman Muzafar Date: Tue, 23 Dec 2025 16:33:55 +0800 Subject: [PATCH 140/876] Disable sdcardio and add Adafruit_SD frozen --- .../boards/cytron_edu_pico_v2_2w/mpconfigboard.mk | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk index 6bcb010159e..4e40cb792c7 100644 --- a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk @@ -9,8 +9,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" -CIRCUITPY_SDCARDIO = 1 - CIRCUITPY__EVE = 1 CIRCUITPY_CYW43 = 1 @@ -21,10 +19,6 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 -CIRCUITPY_MAX3421E = 0 -CIRCUITPY_ULAB = 0 -CIRCUITPY_ZLIB = 0 - CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ @@ -52,6 +46,7 @@ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ImageLoad FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_AHTx0 +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HTTPServer FROZEN_MPY_DIRS += $(TOP)/frozen/CircuitPython_edupico2_paj7620 From 9160a494cf68db413e738e816d5d32de7b44fb53 Mon Sep 17 00:00:00 2001 From: Noqman Muzafar Date: Tue, 23 Dec 2025 22:31:06 +0800 Subject: [PATCH 141/876] Enable sdcardio and unfreeze Adafruit_SD --- .../raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk index 4e40cb792c7..ac0bb6d6f27 100644 --- a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk @@ -9,6 +9,8 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" +CIRCUITPY_SDCARDIO = 1 + CIRCUITPY__EVE = 1 CIRCUITPY_CYW43 = 1 @@ -43,7 +45,6 @@ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SimpleIO FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_OPT4048 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SSD1306 -FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ImageLoad FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_AHTx0 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD From ddeef5bab871f4461073c9882b17fd06e2e5eb87 Mon Sep 17 00:00:00 2001 From: Manjunath CV Date: Thu, 25 Dec 2025 00:43:37 +0530 Subject: [PATCH 142/876] Updated USB_VID and USB_PID from https://pid.codes/1209/DEC1/ --- .../boards/weact_studio_rp2350b_core/mpconfigboard.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk index ceef6b4846d..d86f28280f3 100644 --- a/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/mpconfigboard.mk @@ -1,5 +1,5 @@ -USB_VID = 0x2E8A -USB_PID = 0x000F +USB_VID = 0x1209 +USB_PID = 0xDEC1 USB_PRODUCT = "RP2350B Core" USB_MANUFACTURER = "WeAct Studio" From 1e9c67312c544444cfe5fdec4750c65e2d68f92b Mon Sep 17 00:00:00 2001 From: David Dyck Date: Wed, 24 Dec 2025 13:28:35 -0800 Subject: [PATCH 143/876] Update monotonic function docstring for clarity Clarify the return value of the monotonic function to specify it returns fractional seconds. looking at cpython's time.monotonic() documentation, one sees in the first line "Return the value (in fractional seconds) of a monotonic clock" - I would have expected a similar introduction when reading that for circuitpython at https://docs.circuitpython.org/en/latest/shared-bindings/time/ I see there is a fall back that says "For more information, refer to the original CPython documentation" but would it have hurt to have mention that the units of the float returned by time.monotomic was in seconds? ( there are 7 mentions of millisecond(s), --- shared-bindings/time/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 8a591da3688..86f73d95ca6 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -22,7 +22,7 @@ //| //| //| def monotonic() -> float: -//| """Returns an always increasing value of time with an unknown reference +//| """Returns an always increasing value of time (in fractional **seconds**) with an unknown reference //| point. Only use it to compare against other values from `time.monotonic()` //| during the same code run. //| From 75b3c3974315c063ab9bd1fcc57fe13c2599efaa Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 24 Dec 2025 16:34:10 -0500 Subject: [PATCH 144/876] Fix comment formatting in monotonic function --- shared-bindings/time/__init__.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index 86f73d95ca6..e19d97251bc 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -22,12 +22,12 @@ //| //| //| def monotonic() -> float: -//| """Returns an always increasing value of time (in fractional **seconds**) with an unknown reference +//| """Returns an always increasing value of time, in fractional seconds, with an unknown reference //| point. Only use it to compare against other values from `time.monotonic()` //| during the same code run. //| //| On most boards, `time.monotonic()` converts a 64-bit millisecond tick counter -//| to a float. Floats on most boards are encoded in 30 bits internally, with +//| to seconds, as a float. Floats on most boards are encoded in 30 bits internally, with //| effectively 22 bits of precision. The float returned by `time.monotonic()` will //| accurately represent time to millisecond precision only up to 2**22 milliseconds //| (about 1.165 hours). From 7a3c9aeccfee6de3c46349c742ad2e342007058b Mon Sep 17 00:00:00 2001 From: Manjunath CV Date: Thu, 25 Dec 2025 17:30:10 +0530 Subject: [PATCH 145/876] Updated pin names --- .../boards/weact_studio_rp2350b_core/pins.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c index 989855a3843..39febd2a9f3 100644 --- a/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c @@ -55,13 +55,29 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP37), MP_ROM_PTR(&pin_GPIO37) }, { MP_ROM_QSTR(MP_QSTR_GP38), MP_ROM_PTR(&pin_GPIO38) }, { MP_ROM_QSTR(MP_QSTR_GP39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_GP40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_GP41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_GP42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_GP43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_GP44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_GP45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_GP46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_GP47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO47) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From c7e605fc40bd300fb20a6461089439bbbe99612e Mon Sep 17 00:00:00 2001 From: Manjunath CV Date: Thu, 25 Dec 2025 17:34:20 +0530 Subject: [PATCH 146/876] Updated pin names --- .../boards/weact_studio_rp2350b_core/pins.c | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c index 39febd2a9f3..d6a82becfdd 100644 --- a/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c +++ b/ports/raspberrypi/boards/weact_studio_rp2350b_core/pins.c @@ -34,12 +34,12 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, - { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO23) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, - { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO25) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO25) }, { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, @@ -57,27 +57,35 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP39), MP_ROM_PTR(&pin_GPIO39) }, { MP_ROM_QSTR(MP_QSTR_GP40), MP_ROM_PTR(&pin_GPIO40) }, - { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO40) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO40) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP40_A0), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_GP41), MP_ROM_PTR(&pin_GPIO41) }, - { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP41_A1), MP_ROM_PTR(&pin_GPIO41) }, { MP_ROM_QSTR(MP_QSTR_GP42), MP_ROM_PTR(&pin_GPIO42) }, - { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO42) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO42) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP42_A2), MP_ROM_PTR(&pin_GPIO42) }, { MP_ROM_QSTR(MP_QSTR_GP43), MP_ROM_PTR(&pin_GPIO43) }, - { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO43) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO43) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP43_A3), MP_ROM_PTR(&pin_GPIO43) }, { MP_ROM_QSTR(MP_QSTR_GP44), MP_ROM_PTR(&pin_GPIO44) }, - { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO44) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO44) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP44_A4), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_GP45), MP_ROM_PTR(&pin_GPIO45) }, - { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO45) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO45) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP45_A5), MP_ROM_PTR(&pin_GPIO45) }, { MP_ROM_QSTR(MP_QSTR_GP46), MP_ROM_PTR(&pin_GPIO46) }, - { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO46) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO46) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP46_A6), MP_ROM_PTR(&pin_GPIO46) }, { MP_ROM_QSTR(MP_QSTR_GP47), MP_ROM_PTR(&pin_GPIO47) }, - { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO47) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO47) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_GP47_A7), MP_ROM_PTR(&pin_GPIO47) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From ca2afccb1ca74a188964d4cc0b77c1c4e903e89a Mon Sep 17 00:00:00 2001 From: Noqman Muzafar Date: Mon, 29 Dec 2025 15:58:53 +0800 Subject: [PATCH 147/876] Rename board folder/id from cytron_edu_pico_v2_2w to cytron_edu_v2_pico_2w --- .../{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/board.c | 0 .../{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/link.ld | 0 .../mpconfigboard.h | 0 .../mpconfigboard.mk | 0 .../pico-sdk-configboard.h | 0 .../{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/pins.c | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename ports/raspberrypi/boards/{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/board.c (100%) rename ports/raspberrypi/boards/{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/link.ld (100%) rename ports/raspberrypi/boards/{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/mpconfigboard.h (100%) rename ports/raspberrypi/boards/{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/mpconfigboard.mk (100%) rename ports/raspberrypi/boards/{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/pico-sdk-configboard.h (100%) rename ports/raspberrypi/boards/{cytron_edu_pico_v2_2w => cytron_edu_v2_pico_2w}/pins.c (100%) diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/board.c b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/board.c similarity index 100% rename from ports/raspberrypi/boards/cytron_edu_pico_v2_2w/board.c rename to ports/raspberrypi/boards/cytron_edu_v2_pico_2w/board.c diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/link.ld b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/link.ld similarity index 100% rename from ports/raspberrypi/boards/cytron_edu_pico_v2_2w/link.ld rename to ports/raspberrypi/boards/cytron_edu_v2_pico_2w/link.ld diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.h b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.h similarity index 100% rename from ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.h rename to ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.h diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk similarity index 100% rename from ports/raspberrypi/boards/cytron_edu_pico_v2_2w/mpconfigboard.mk rename to ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pico-sdk-configboard.h b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pico-sdk-configboard.h similarity index 100% rename from ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pico-sdk-configboard.h rename to ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pico-sdk-configboard.h diff --git a/ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pins.c b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pins.c similarity index 100% rename from ports/raspberrypi/boards/cytron_edu_pico_v2_2w/pins.c rename to ports/raspberrypi/boards/cytron_edu_v2_pico_2w/pins.c From 5a4446ea09ad3f883d9db136b5d92f15476c7e3c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 4 Jan 2026 22:24:50 -0500 Subject: [PATCH 148/876] espressif_bindings/Camera.c: fix type of framebuffer_count --- ports/espressif/bindings/espcamera/Camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/bindings/espcamera/Camera.c b/ports/espressif/bindings/espcamera/Camera.c index ed6b542a02f..712ff8827d7 100644 --- a/ports/espressif/bindings/espcamera/Camera.c +++ b/ports/espressif/bindings/espcamera/Camera.c @@ -261,7 +261,7 @@ static mp_obj_t espcamera_camera_reconfigure(mp_uint_t n_args, const mp_obj_t *p args[ARG_grab_mode].u_obj != MP_ROM_NONE ? validate_grab_mode(args[ARG_grab_mode].u_obj, MP_QSTR_grab_mode) : common_hal_espcamera_camera_get_grab_mode(self); - bool framebuffer_count = + mp_int_t framebuffer_count = args[ARG_framebuffer_count].u_obj != MP_ROM_NONE ? mp_obj_get_int(args[ARG_framebuffer_count].u_obj) : common_hal_espcamera_camera_get_framebuffer_count(self); From c5e4979655ed6a90e8510723d18949a01979a84d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 5 Nov 2025 12:10:55 -0500 Subject: [PATCH 149/876] stop building intel and universal macos mpy-cross --- .github/workflows/build.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0f837d793bd..697a1106054 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -131,33 +131,18 @@ jobs: gcc --version python3 --version msgfmt --version - - name: Build mpy-cross - run: make -C mpy-cross -j4 - - uses: actions/upload-artifact@v4 - with: - name: mpy-cross-macos-x64 - path: mpy-cross/build/mpy-cross - name: Build mpy-cross (arm64) run: make -C mpy-cross -j4 -f Makefile.m1 V=2 - uses: actions/upload-artifact@v4 with: name: mpy-cross-macos-arm64 path: mpy-cross/build-arm64/mpy-cross-arm64 - - name: Make universal binary - run: lipo -create -output mpy-cross-macos-universal mpy-cross/build/mpy-cross mpy-cross/build-arm64/mpy-cross-arm64 - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: mpy-cross-macos-universal - path: mpy-cross-macos-universal - name: Upload to S3 if: >- (github.event_name == 'push' && github.ref == 'refs/heads/main' && github.repository_owner == 'adafruit') || (github.event_name == 'release' && (github.event.action == 'published' || github.event.action == 'rerequested')) run: | - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross-macos-universal s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-universal --no-progress --region us-east-1 [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/build-arm64/mpy-cross-arm64 s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-arm64 --no-progress --region us-east-1 - [ -z "$AWS_ACCESS_KEY_ID" ] || aws s3 cp mpy-cross/build/mpy-cross s3://adafruit-circuit-python/bin/mpy-cross/macos/mpy-cross-macos-"${CP_VERSION}"-x64 --no-progress --region us-east-1 env: AWS_PAGER: '' AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} From 0caa9edc6d1b594ddf819166dacc3ccad6d21918 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 4 Nov 2025 16:36:14 -0800 Subject: [PATCH 150/876] Use latest macos in CI --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 697a1106054..fbd3af440c6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -107,7 +107,7 @@ jobs: cp-version: ${{ needs.scheduler.outputs.cp-version }} mpy-cross-mac: - runs-on: macos-13 + runs-on: macos-latest needs: scheduler if: needs.scheduler.outputs.ports != '{}' env: From 85a8f1ec464c84084af0fdff3998c52039e6de75 Mon Sep 17 00:00:00 2001 From: Joe Freeman Date: Tue, 6 Jan 2026 07:11:52 -0500 Subject: [PATCH 151/876] Add APA102 and DEFAULT_I2C_BUS definitions to the lilygo_tdongle_s3 --- ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h b/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h index fe5525ef056..0edea0bf63b 100644 --- a/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h +++ b/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h @@ -11,5 +11,8 @@ #define MICROPY_HW_BOARD_NAME "LILYGO T-Dongle S3" #define MICROPY_HW_MCU_NAME "ESP32S3" -#define DEFAULT_UART_BUS_RX (&pin_GPIO44) -#define DEFAULT_UART_BUS_TX (&pin_GPIO43) +#define MICROPY_HW_APA102_MOSI (&pin_GPIO40) +#define MICROPY_HW_APA102_SCK (&pin_GPIO39) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO44) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO43) From 7b77c43e0eddd834ad75961461eb2c0826d9cf0e Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 7 Jan 2026 09:00:42 -0600 Subject: [PATCH 152/876] update frozen libs --- frozen/Adafruit_CircuitPython_Display_Text | 2 +- frozen/Adafruit_CircuitPython_LIS3DH | 2 +- frozen/Adafruit_CircuitPython_LSM6DS | 2 +- frozen/Adafruit_CircuitPython_PortalBase | 2 +- frozen/Adafruit_CircuitPython_RFM69 | 2 +- frozen/Adafruit_CircuitPython_RFM9x | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_Display_Text b/frozen/Adafruit_CircuitPython_Display_Text index 0c4ea1b8c10..372cbe27459 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit 0c4ea1b8c102cdd98c91914dd09f067ea6f7b1e1 +Subproject commit 372cbe27459c02db838fb65489cf8b4b5dba12f3 diff --git a/frozen/Adafruit_CircuitPython_LIS3DH b/frozen/Adafruit_CircuitPython_LIS3DH index a3c33eff7c0..83333f8f6a5 160000 --- a/frozen/Adafruit_CircuitPython_LIS3DH +++ b/frozen/Adafruit_CircuitPython_LIS3DH @@ -1 +1 @@ -Subproject commit a3c33eff7c03e7c1f1e896a08f4878f5db6a6cbf +Subproject commit 83333f8f6a5501f9cbee215ebc791cd2fb67bd7d diff --git a/frozen/Adafruit_CircuitPython_LSM6DS b/frozen/Adafruit_CircuitPython_LSM6DS index 2bf5c7fcadb..36247d1d9d7 160000 --- a/frozen/Adafruit_CircuitPython_LSM6DS +++ b/frozen/Adafruit_CircuitPython_LSM6DS @@ -1 +1 @@ -Subproject commit 2bf5c7fcadbb0034c0d193c5c45409f435e7329c +Subproject commit 36247d1d9d769a23f40ca2c4371a5cd64e2a7204 diff --git a/frozen/Adafruit_CircuitPython_PortalBase b/frozen/Adafruit_CircuitPython_PortalBase index 25fc43dd67a..059c805bd1f 160000 --- a/frozen/Adafruit_CircuitPython_PortalBase +++ b/frozen/Adafruit_CircuitPython_PortalBase @@ -1 +1 @@ -Subproject commit 25fc43dd67ae95a8e62173e90c3069502194873a +Subproject commit 059c805bd1f9157495d17739c8082f9a2042bdbf diff --git a/frozen/Adafruit_CircuitPython_RFM69 b/frozen/Adafruit_CircuitPython_RFM69 index 62cb5cf6fbe..763992bb084 160000 --- a/frozen/Adafruit_CircuitPython_RFM69 +++ b/frozen/Adafruit_CircuitPython_RFM69 @@ -1 +1 @@ -Subproject commit 62cb5cf6fbeb9943bf7b2db4fc614f9b40830bf3 +Subproject commit 763992bb084343ee1a7cfce72585e028ced0d890 diff --git a/frozen/Adafruit_CircuitPython_RFM9x b/frozen/Adafruit_CircuitPython_RFM9x index 5b8a9ae0ace..ad05a38fc96 160000 --- a/frozen/Adafruit_CircuitPython_RFM9x +++ b/frozen/Adafruit_CircuitPython_RFM9x @@ -1 +1 @@ -Subproject commit 5b8a9ae0ace6bd5f3a0860c95c3c389a09e4b59b +Subproject commit ad05a38fc96edcae5d0ac9d107c268dd76e4a186 From 4fe2f03a865cbf5cd020596f4117f793ded9e329 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 12 Jan 2026 16:48:25 -0800 Subject: [PATCH 153/876] Add support for Yoto Mini and Yoto Player V3 There were a bunch of changes to enable the boards: * Add web workflow for sdioio cards. Adds the "native" access. * Introduce `i2cioexpander` for native I2C expander support. * Introduce DigitalInOut protocol so that IOPins can be used where DigitalInOut would be traditionally. * Add mp_errno_t for clarifying what APIs return errno. * DigitalInOut protocol uses it to pass through I2C issues. * Switch `bitbangio` and `fourwire` to DigitalInOutProtocol. * Support the Mini's GC9306 display with CS and DC over IOPin. * DigitalInOutProtocol can fall back to Python-level access if not natively supported. * Make board.I2C() speed configurable to speed up IOExpander access. * Update codespell to work with Python 3.14. * Make static web workflow responses cachable by the browser for 1 day. --- .pre-commit-config.yaml | 2 +- extmod/vfs_blockdev.c | 11 +- locale/circuitpython.pot | 36 +- ports/analog/common-hal/busio/I2C.c | 12 +- ports/atmel-samd/common-hal/busio/I2C.c | 18 +- ports/atmel-samd/common-hal/sdioio/SDCard.c | 69 +++- ports/broadcom/common-hal/busio/I2C.c | 16 +- ports/broadcom/common-hal/sdioio/SDCard.c | 76 +++- ports/cxd56/common-hal/busio/I2C.c | 10 +- ports/cxd56/common-hal/sdioio/SDCard.c | 60 ++- ports/espressif/boards/yoto_mini_2024/board.c | 203 +++++++++ ports/espressif/boards/yoto_mini_2024/board.h | 3 + .../boards/yoto_mini_2024/mpconfigboard.h | 26 ++ .../boards/yoto_mini_2024/mpconfigboard.mk | 14 + ports/espressif/boards/yoto_mini_2024/pins.c | 79 ++++ .../espressif/boards/yoto_mini_2024/sdkconfig | 0 ports/espressif/boards/yoto_player_v3/board.c | 148 +++++++ ports/espressif/boards/yoto_player_v3/board.h | 3 + .../boards/yoto_player_v3/mpconfigboard.h | 26 ++ .../boards/yoto_player_v3/mpconfigboard.mk | 14 + ports/espressif/boards/yoto_player_v3/pins.c | 104 +++++ .../espressif/boards/yoto_player_v3/sdkconfig | 0 ports/espressif/common-hal/busio/I2C.c | 14 +- ports/espressif/common-hal/sdioio/SDCard.c | 66 ++- ports/espressif/mpconfigport.mk | 3 - ports/mimxrt10xx/common-hal/busio/I2C.c | 14 +- ports/nordic/common-hal/busio/I2C.c | 22 +- ports/raspberrypi/common-hal/busio/I2C.c | 24 +- ports/raspberrypi/mpconfigport.mk | 1 + ports/renode/common-hal/busio/I2C.c | 10 +- ports/silabs/common-hal/busio/I2C.c | 12 +- ports/stm/common-hal/busio/I2C.c | 14 +- ports/stm/common-hal/sdioio/SDCard.c | 63 ++- ports/zephyr-cp/common-hal/busio/I2C.c | 36 +- py/circuitpy_defns.mk | 7 + py/circuitpy_mpconfig.h | 3 + py/circuitpy_mpconfig.mk | 3 + py/mperrno.h | 2 + shared-bindings/bitbangio/I2C.c | 13 +- shared-bindings/bitbangio/I2C.h | 4 +- shared-bindings/bitbangio/SPI.c | 18 +- shared-bindings/bitbangio/SPI.h | 3 +- shared-bindings/board/__init__.h | 6 +- shared-bindings/busio/I2C.c | 12 +- shared-bindings/busio/I2C.h | 11 +- shared-bindings/digitalio/DigitalInOut.c | 77 +++- shared-bindings/digitalio/DigitalInOut.h | 3 + .../digitalio/DigitalInOutProtocol.c | 386 ++++++++++++++++++ .../digitalio/DigitalInOutProtocol.h | 67 +++ shared-bindings/fourwire/FourWire.c | 12 +- shared-bindings/fourwire/FourWire.h | 4 +- shared-bindings/i2cioexpander/IOExpander.c | 247 +++++++++++ shared-bindings/i2cioexpander/IOExpander.h | 34 ++ shared-bindings/i2cioexpander/IOPin.c | 331 +++++++++++++++ shared-bindings/i2cioexpander/IOPin.h | 46 +++ shared-bindings/i2cioexpander/__init__.c | 49 +++ shared-bindings/i2cioexpander/__init__.h | 9 + shared-bindings/sdcardio/SDCard.h | 7 +- shared-bindings/sdioio/SDCard.h | 12 +- shared-bindings/socketpool/Socket.h | 1 + shared-module/bitbangio/I2C.c | 145 ++++--- shared-module/bitbangio/I2C.h | 6 +- shared-module/bitbangio/SPI.c | 161 +++++--- shared-module/bitbangio/SPI.h | 9 +- shared-module/board/__init__.c | 4 + shared-module/busdisplay/BusDisplay.c | 2 +- shared-module/fourwire/FourWire.c | 90 ++-- shared-module/fourwire/FourWire.h | 11 +- shared-module/i2cioexpander/IOExpander.c | 196 +++++++++ shared-module/i2cioexpander/IOExpander.h | 41 ++ shared-module/i2cioexpander/IOPin.c | 147 +++++++ shared-module/i2cioexpander/IOPin.h | 26 ++ shared-module/i2cioexpander/__init__.c | 7 + supervisor/port.h | 5 + supervisor/shared/port.c | 17 + supervisor/shared/status_leds.c | 6 +- supervisor/shared/web_workflow/web_workflow.c | 4 + 77 files changed, 3083 insertions(+), 370 deletions(-) create mode 100644 ports/espressif/boards/yoto_mini_2024/board.c create mode 100644 ports/espressif/boards/yoto_mini_2024/board.h create mode 100644 ports/espressif/boards/yoto_mini_2024/mpconfigboard.h create mode 100644 ports/espressif/boards/yoto_mini_2024/mpconfigboard.mk create mode 100644 ports/espressif/boards/yoto_mini_2024/pins.c create mode 100644 ports/espressif/boards/yoto_mini_2024/sdkconfig create mode 100644 ports/espressif/boards/yoto_player_v3/board.c create mode 100644 ports/espressif/boards/yoto_player_v3/board.h create mode 100644 ports/espressif/boards/yoto_player_v3/mpconfigboard.h create mode 100644 ports/espressif/boards/yoto_player_v3/mpconfigboard.mk create mode 100644 ports/espressif/boards/yoto_player_v3/pins.c create mode 100644 ports/espressif/boards/yoto_player_v3/sdkconfig create mode 100644 shared-bindings/digitalio/DigitalInOutProtocol.c create mode 100644 shared-bindings/digitalio/DigitalInOutProtocol.h create mode 100644 shared-bindings/i2cioexpander/IOExpander.c create mode 100644 shared-bindings/i2cioexpander/IOExpander.h create mode 100644 shared-bindings/i2cioexpander/IOPin.c create mode 100644 shared-bindings/i2cioexpander/IOPin.h create mode 100644 shared-bindings/i2cioexpander/__init__.c create mode 100644 shared-bindings/i2cioexpander/__init__.h create mode 100644 shared-module/i2cioexpander/IOExpander.c create mode 100644 shared-module/i2cioexpander/IOExpander.h create mode 100644 shared-module/i2cioexpander/IOPin.c create mode 100644 shared-module/i2cioexpander/IOPin.h create mode 100644 shared-module/i2cioexpander/__init__.c diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f7e7956498d..4db04e1d0ed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,7 +28,7 @@ repos: lib/mbedtls_errors/generate_errors.diff ) - repo: https://github.com/codespell-project/codespell - rev: v2.2.4 + rev: v2.4.1 hooks: - id: codespell args: [-w] diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c index f1187b9bbf2..0cd3cc6f0c6 100644 --- a/extmod/vfs_blockdev.c +++ b/extmod/vfs_blockdev.c @@ -63,7 +63,16 @@ void mp_vfs_blockdev_init(mp_vfs_blockdev_t *self, mp_obj_t bdev) { #endif #if CIRCUITPY_SDIOIO if (mp_obj_get_type(bdev) == &sdioio_SDCard_type) { - // TODO: Enable native blockdev for SDIO too. + self->flags |= MP_BLOCKDEV_FLAG_NATIVE | MP_BLOCKDEV_FLAG_HAVE_IOCTL; + self->readblocks[0] = mp_const_none; + self->readblocks[1] = bdev; + self->readblocks[2] = (mp_obj_t)sdioio_sdcard_readblocks; // native version + self->writeblocks[0] = mp_const_none; + self->writeblocks[1] = bdev; + self->writeblocks[2] = (mp_obj_t)sdioio_sdcard_writeblocks; // native version + self->u.ioctl[0] = mp_const_none; + self->u.ioctl[1] = bdev; + self->u.ioctl[2] = (mp_obj_t)sdioio_sdcard_ioctl; // native version } #endif if (self->u.ioctl[0] != MP_OBJ_NULL) { diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index bcc7d1dd1ca..9cf51a0c025 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -119,7 +119,8 @@ msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/usb_host/Port.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "" @@ -132,7 +133,7 @@ msgid "%q indices must be integers, not %s" msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q init failed" msgstr "" @@ -235,6 +236,14 @@ msgstr "" msgid "%q must be power of 2" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "" @@ -766,6 +775,10 @@ msgstr "" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -800,6 +813,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "" @@ -939,6 +953,7 @@ msgid "Done" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "" @@ -1277,8 +1292,8 @@ msgstr "" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" @@ -1880,6 +1895,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -2539,6 +2555,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -3814,6 +3834,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3827,6 +3851,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index 336c04fe039..b74c921bae3 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -187,7 +187,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { int ret; @@ -202,14 +202,14 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, }; ret = MXC_I2C_MasterTransaction(&wr_req); if (ret) { - return MP_EIO; + return -MP_EIO; } return 0; } // Read into buffer from the device selected by address -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { @@ -226,14 +226,14 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, ret = MXC_I2C_MasterTransaction(&rd_req); if (ret) { // Return I/O error - return MP_EIO; + return -MP_EIO; } return 0; } // Write the bytes from out_data to the device selected by address -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { @@ -249,7 +249,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, }; ret = MXC_I2C_MasterTransaction(&wr_rd_req); if (ret) { - return MP_EIO; + return -MP_EIO; } return 0; diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index da108709fea..700c3e4aba2 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -176,7 +176,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { uint16_t attempts = ATTEMPTS; @@ -197,17 +197,17 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, if (status == I2C_OK) { return 0; } else if (status == I2C_ERR_BAD_ADDRESS) { - return MP_ENODEV; + return -MP_ENODEV; } - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { uint16_t attempts = ATTEMPTS; @@ -228,14 +228,14 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, if (status == ERR_NONE) { return 0; } else if (status == I2C_ERR_BAD_ADDRESS) { - return MP_ENODEV; + return -MP_ENODEV; } - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/atmel-samd/common-hal/sdioio/SDCard.c b/ports/atmel-samd/common-hal/sdioio/SDCard.c index 8ff1a391bb2..af3610c89e9 100644 --- a/ports/atmel-samd/common-hal/sdioio/SDCard.c +++ b/ports/atmel-samd/common-hal/sdioio/SDCard.c @@ -9,6 +9,7 @@ #include "py/runtime.h" #include "common-hal/microcontroller/Pin.h" +#include "extmod/vfs.h" #include "shared-bindings/sdioio/SDCard.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" @@ -170,43 +171,85 @@ static void debug_print_state(sdioio_sdcard_obj_t *self, const char *what, sd_mm #endif } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { - check_for_deinit(self); - check_whole_block(bufinfo); +mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); self->state_programming = true; - sd_mmc_err_t r = sd_mmc_init_write_blocks(0, start_block, bufinfo->len / 512); + sd_mmc_err_t r = sd_mmc_init_write_blocks(0, start_block, num_blocks); if (r != SD_MMC_OK) { debug_print_state(self, "sd_mmc_init_write_blocks", r); - return -EIO; + return -MP_EIO; } - r = sd_mmc_start_write_blocks(bufinfo->buf, bufinfo->len / 512); + r = sd_mmc_start_write_blocks(buf, num_blocks); if (r != SD_MMC_OK) { debug_print_state(self, "sd_mmc_start_write_blocks", r); - return -EIO; + return -MP_EIO; } - // debug_print_state(self, "after writeblocks OK"); return 0; } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { check_for_deinit(self); check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); - sd_mmc_err_t r = sd_mmc_init_read_blocks(0, start_block, bufinfo->len / 512); + sd_mmc_err_t r = sd_mmc_init_read_blocks(0, start_block, num_blocks); if (r != SD_MMC_OK) { debug_print_state(self, "sd_mmc_init_read_blocks", r); - return -EIO; + return -MP_EIO; } - r = sd_mmc_start_read_blocks(bufinfo->buf, bufinfo->len / 512); + r = sd_mmc_start_read_blocks(buf, num_blocks); if (r != SD_MMC_OK) { debug_print_state(self, "sd_mmc_start_read_blocks", r); - return -EIO; + return -MP_EIO; } sd_mmc_wait_end_of_write_blocks(0); return 0; } +mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } +} + bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { check_for_deinit(self); return true; diff --git a/ports/broadcom/common-hal/busio/I2C.c b/ports/broadcom/common-hal/busio/I2C.c index 6a77cec08af..cdc986f05ae 100644 --- a/ports/broadcom/common-hal/busio/I2C.c +++ b/ports/broadcom/common-hal/busio/I2C.c @@ -137,7 +137,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { // Discussion of I2C implementation is here: https://github.com/raspberrypi/linux/issues/254 -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { COMPLETE_MEMORY_READS; self->peripheral->S_b.DONE = true; @@ -182,7 +182,7 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, while (self->peripheral->S_b.ERR == 1) { RUN_BACKGROUND_TASKS; } - return MP_ENODEV; + return -MP_ENODEV; } if (loop_len < len) { @@ -192,19 +192,19 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, return 0; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { COMPLETE_MEMORY_READS; self->peripheral->A_b.ADDR = addr; if (self->finish_write) { self->finish_write = false; if (self->peripheral->S_b.ERR == 1) { - return MP_ENODEV; + return -MP_ENODEV; } self->peripheral->FIFO_b.DATA = self->last_write_data; } else { @@ -236,15 +236,15 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, while (self->peripheral->S_b.ERR == 1) { RUN_BACKGROUND_TASKS; } - return MP_ENODEV; + return -MP_ENODEV; } return 0; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/broadcom/common-hal/sdioio/SDCard.c b/ports/broadcom/common-hal/sdioio/SDCard.c index f87d40cd8dc..5dc405bdc18 100644 --- a/ports/broadcom/common-hal/sdioio/SDCard.c +++ b/ports/broadcom/common-hal/sdioio/SDCard.c @@ -11,6 +11,7 @@ #include "py/runtime.h" #include "common-hal/microcontroller/Pin.h" +#include "extmod/vfs.h" #include "shared-bindings/sdioio/SDCard.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" @@ -304,44 +305,95 @@ static void check_whole_block(mp_buffer_info_t *bufinfo) { } } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +// Native function for VFS blockdev layer +mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!self->init) { - return -EIO; + return -MP_EIO; } - check_whole_block(bufinfo); self->state_programming = true; COMPLETE_MEMORY_READS; - sdmmc_err_t error = sdmmc_write_sectors(&self->card_info, bufinfo->buf, - start_block, bufinfo->len / 512); + sdmmc_err_t error = sdmmc_write_sectors(&self->card_info, buf, + start_block, num_blocks); COMPLETE_MEMORY_READS; if (error != SDMMC_OK) { mp_printf(&mp_plat_print, "write sectors result %d\n", error); - return -EIO; + return -MP_EIO; } return 0; } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (!self->init) { - return -EIO; + return -MP_EIO; } check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!self->init) { + return -MP_EIO; + } COMPLETE_MEMORY_READS; - sdmmc_err_t error = sdmmc_read_sectors(&self->card_info, bufinfo->buf, - start_block, bufinfo->len / 512); + sdmmc_err_t error = sdmmc_read_sectors(&self->card_info, buf, + start_block, num_blocks); COMPLETE_MEMORY_READS; if (error != SDMMC_OK) { - mp_printf(&mp_plat_print, "read sectors result %d when reading block %d for %d\n", error, start_block, bufinfo->len / 512); - return -EIO; + mp_printf(&mp_plat_print, "read sectors result %d when reading block %d for %d\n", error, start_block, num_blocks); + return -MP_EIO; } return 0; } +mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + if (!self->init) { + return -MP_EIO; + } + check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } +} + bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { if (!self->init) { return false; diff --git a/ports/cxd56/common-hal/busio/I2C.c b/ports/cxd56/common-hal/busio/I2C.c index fb33c242a03..c8b32b6a023 100644 --- a/ports/cxd56/common-hal/busio/I2C.c +++ b/ports/cxd56/common-hal/busio/I2C.c @@ -91,7 +91,7 @@ bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { return I2C_TRANSFER(self->i2c_dev, &msg, 1) < 0 ? false : true; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len, bool stop) { +static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len, bool stop) { struct i2c_msg_s msg; msg.frequency = self->frequency; @@ -102,12 +102,12 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addre return -I2C_TRANSFER(self->i2c_dev, &msg, 1); } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len) { +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len) { struct i2c_msg_s msg; msg.frequency = self->frequency; @@ -118,9 +118,9 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8 return -I2C_TRANSFER(self->i2c_dev, &msg, 1); } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/cxd56/common-hal/sdioio/SDCard.c b/ports/cxd56/common-hal/sdioio/SDCard.c index aa1d1371770..95dde482dde 100644 --- a/ports/cxd56/common-hal/sdioio/SDCard.c +++ b/ports/cxd56/common-hal/sdioio/SDCard.c @@ -8,6 +8,7 @@ #include #include +#include "extmod/vfs.h" #include "py/mperrno.h" #include "py/runtime.h" @@ -95,22 +96,73 @@ static void check_whole_block(mp_buffer_info_t *bufinfo) { } } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +// Native function for VFS blockdev layer +mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + int result = self->inode->u.i_bops->read(self->inode, buf, start_block, num_blocks); + if (result < 0) { + return -MP_EIO; + } + return 0; +} + +mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (common_hal_sdioio_sdcard_deinited(self)) { raise_deinited_error(); } check_whole_block(bufinfo); - return self->inode->u.i_bops->read(self->inode, bufinfo->buf, start_block, bufinfo->len / 512); + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +// Native function for VFS blockdev layer +mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + int result = self->inode->u.i_bops->write(self->inode, buf, start_block, num_blocks); + if (result < 0) { + return -MP_EIO; + } + return 0; +} + +mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (common_hal_sdioio_sdcard_deinited(self)) { raise_deinited_error(); } check_whole_block(bufinfo); - return self->inode->u.i_bops->write(self->inode, bufinfo->buf, start_block, bufinfo->len / 512); + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } } void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) { diff --git a/ports/espressif/boards/yoto_mini_2024/board.c b/ports/espressif/boards/yoto_mini_2024/board.c new file mode 100644 index 00000000000..fb6a96a957d --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/board.c @@ -0,0 +1,203 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "board.h" + +#include "supervisor/board.h" + +#include "extmod/vfs_fat.h" + +#include "py/mpstate.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/i2cioexpander/IOExpander.h" +#include "shared-bindings/i2cioexpander/IOPin.h" +#include "shared-bindings/sdioio/SDCard.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" + +#include "supervisor/filesystem.h" + +static sdioio_sdcard_obj_t sdmmc; +static mp_vfs_mount_t _sdcard_vfs; +static fs_user_mount_t _sdcard_usermount; +static i2cioexpander_ioexpander_obj_t ioexpander; + +#define DELAY 0x80 + +// This is a GC9306. +uint8_t display_init_sequence[] = { + 0xfe, 0, + 0xef, 0, + + // // sw reset + // 0x01, 0 | DELAY, 150, + // normal display mode on + // 0x13, 0, + // display and color format settings + 0x36, 1, 0x48, // Memory access control. mini does 0x48, not 0, 2, 3, 4 or 6 + 0x3A, 1 | DELAY, 0x55, 10, // COLMOD. mini does 0x06 + 0xa4, 2, 0x44, 0x44, // power control 7 + 0xa5, 2, 0x42, 0x42, + 0xaa, 2, 0x88, 0x88, + 0xae, 1, 0x2b, + 0xe8, 2, 0x22, 0x0b, // frame rate + 0xe3, 2, 0x01, 0x10, + 0xff, 1, 0x61, + 0xac, 1, 0x00, + 0xad, 1, 0x33, + 0xaf, 1, 0x77, + 0xa6, 2, 0x1c, 0x1c, // power control 2 + 0xa7, 2, 0x1c, 0x1c, // power control 3 + 0xa8, 2, 0x10, 0x10, // power control 4 + 0xa9, 2, 0x0d, 0x0d, // power control 5 + 0xf0, 6, 0x02, 0x01, 0x00, 0x00, 0x00, 0x05, // Gamma settings + 0xf1, 6, 0x01, 0x02, 0x00, 0x06, 0x10, 0x0e, + 0xf2, 6, 0x03, 0x11, 0x28, 0x02, 0x00, 0x48, + 0xf3, 6, 0x0c, 0x11, 0x30, 0x00, 0x00, 0x46, + 0xf4, 6, 0x05, 0x1f, 0x1f, 0x36, 0x30, 0x0f, + 0xf5, 6, 0x04, 0x1d, 0x1a, 0x38, 0x3f, 0x0f, // Last gamma setting + 0x35, 1, 0x00, + 0x44, 2, 0x00, 0x0a, // set tear scan line + 0x21, 0, // display inversion on + // sleep out + 0x11, 0 | DELAY, 255, + + // display on + 0x29, 0 | DELAY, 255, +}; + +void board_init(void) { + // Wait for everything to start + mp_hal_delay_ms(300); + + // Initialize the board's peripherals here. + busio_i2c_obj_t *i2c = MP_OBJ_TO_PTR(common_hal_board_create_i2c(0)); + + // Initialize the IOExpander + ioexpander.base.type = &i2cioexpander_ioexpander_type; + common_hal_i2cioexpander_ioexpander_construct( + &ioexpander, + MP_OBJ_FROM_PTR(i2c), + 0x20, // I2C address + 16, // Number of pins + 2, // Output register + 0, // Input register + 6); // Direction register + + board_set(MP_QSTR_IOEXPANDER, MP_OBJ_FROM_PTR(&ioexpander)); + board_set(MP_QSTR_PLUG_STATUS, ioexpander.pins->items[8 + 5]); + board_set(MP_QSTR_CHARGE_STATUS, ioexpander.pins->items[8 + 7]); + board_set(MP_QSTR_POWER_BUTTON, ioexpander.pins->items[8 + 3]); + board_set(MP_QSTR_ENC1_BUTTON, ioexpander.pins->items[5]); + board_set(MP_QSTR_ENC2_BUTTON, ioexpander.pins->items[4]); + board_set(MP_QSTR_HEADPHONE_DETECT, ioexpander.pins->items[8 + 1]); + board_set(MP_QSTR_PACTRL, ioexpander.pins->items[6]); + board_set(MP_QSTR_DISPLAY_CS, ioexpander.pins->items[0]); + board_set(MP_QSTR_DISPLAY_DC, ioexpander.pins->items[1]); + board_set(MP_QSTR_DISPLAY_RESET, ioexpander.pins->items[2]); + + board_set(MP_QSTR_LEVEL_CONVERTER, ioexpander.pins->items[3]); + board_set(MP_QSTR_LEVEL_POWER_ENABLE, ioexpander.pins->items[8 + 4]); + board_set(MP_QSTR_LEVEL_VINHOLD, ioexpander.pins->items[8 + 6]); + + board_set(MP_QSTR_TILT, ioexpander.pins->items[8 + 2]); + + // Only on some variants + board_set(MP_QSTR_RTC_INT, ioexpander.pins->items[7]); + + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[2]), true, DRIVE_MODE_PUSH_PULL); + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[3]), true, DRIVE_MODE_PUSH_PULL); + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[6]), true, DRIVE_MODE_PUSH_PULL); + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[14]), true, DRIVE_MODE_PUSH_PULL); + + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + ioexpander.pins->items[1], // DC + ioexpander.pins->items[0], // CS + ioexpander.pins->items[2], // RST + 25000000, // baudrate + 0, // polarity + 0 // phase + ); + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 240, // width (after rotation) + 240, // height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO26, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); + + digitalinout_result_t sd_enable_res = common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander.pins->items[12]), false, DRIVE_MODE_PUSH_PULL); + if (sd_enable_res != DIGITALINOUT_OK) { + mp_printf(&mp_plat_print, "Failed to initialize IOExpander. Skipping SD card\n"); + return; + } + + sdmmc.base.type = &sdioio_SDCard_type; + const mcu_pin_obj_t *data_pins[4] = {MP_ROM_PTR(&pin_GPIO2), MP_ROM_PTR(&pin_GPIO4), MP_ROM_PTR(&pin_GPIO12), MP_ROM_PTR(&pin_GPIO13)}; + common_hal_sdioio_sdcard_construct(&sdmmc, MP_ROM_PTR(&pin_GPIO14), MP_ROM_PTR(&pin_GPIO15), 4, data_pins, 25 * 1000000); + + fs_user_mount_t *vfs = &_sdcard_usermount; + vfs->base.type = &mp_fat_vfs_type; + vfs->fatfs.drv = vfs; + + // Initialise underlying block device + vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to MP_BLOCKDEV_IOCTL_BLOCK_SIZE + mp_vfs_blockdev_init(&vfs->blockdev, &sdmmc); + + // mount the block device so the VFS methods can be used + FRESULT res = f_mount(&vfs->fatfs); + if (res != FR_OK) { + common_hal_sdioio_sdcard_deinit(&sdmmc); + return; + } + common_hal_sdioio_sdcard_never_reset(&sdmmc); + + filesystem_set_concurrent_write_protection(vfs, true); + filesystem_set_writable_by_usb(vfs, false); + + mp_vfs_mount_t *sdcard_vfs = &_sdcard_vfs; + sdcard_vfs->str = "/sd"; + sdcard_vfs->len = 3; + sdcard_vfs->obj = MP_OBJ_FROM_PTR(&_sdcard_usermount); + sdcard_vfs->next = MP_STATE_VM(vfs_mount_table); + MP_STATE_VM(vfs_mount_table) = sdcard_vfs; +} diff --git a/ports/espressif/boards/yoto_mini_2024/board.h b/ports/espressif/boards/yoto_mini_2024/board.h new file mode 100644 index 00000000000..1e40b62b047 --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/board.h @@ -0,0 +1,3 @@ +#include "py/obj.h" + +extern void board_set(qstr key, mp_obj_t value); diff --git a/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h new file mode 100644 index 00000000000..b5ab8a7e6c2 --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Yoto Mini 2024" +#define MICROPY_HW_MCU_NAME "ESP32" + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO25, .sda = &pin_GPIO21}} +#define CIRCUITPY_BOARD_I2C_SPEED (400000) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO23, .mosi = &pin_GPIO22, .miso = NULL}} + +#define CIRCUITPY_BOARD_UART (1) +#define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO17, .rx = &pin_GPIO16}} + +// UART pins attached to the USB-serial converter chip +#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) +#define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) diff --git a/ports/espressif/boards/yoto_mini_2024/mpconfigboard.mk b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.mk new file mode 100644 index 00000000000..356e7015a04 --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.mk @@ -0,0 +1,14 @@ +CIRCUITPY_CREATOR_ID = 0x40100000 +CIRCUITPY_CREATION_ID = 0x00320002 + +IDF_TARGET = esp32 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 40m + +CIRCUITPY_I2CIOEXPANDER = 1 diff --git a/ports/espressif/boards/yoto_mini_2024/pins.c b/ports/espressif/boards/yoto_mini_2024/pins.c new file mode 100644 index 00000000000..d4ff3b4863f --- /dev/null +++ b/ports/espressif/boards/yoto_mini_2024/pins.c @@ -0,0 +1,79 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT +// + +#include "board.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static mp_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_MUTABLE_BOARD_DICT_STANDARD_ITEMS + + // External pins are in silkscreen order, from top to bottom, left side, then right side + { MP_ROM_QSTR(MP_QSTR_ENC1A), MP_OBJ_FROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_ENC1B), MP_OBJ_FROM_PTR(&pin_GPIO35) }, + + { MP_ROM_QSTR(MP_QSTR_ENC2A), MP_OBJ_FROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_ENC2B), MP_OBJ_FROM_PTR(&pin_GPIO27) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_OBJ_FROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_OBJ_FROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY_SCK), MP_OBJ_FROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_MOSI), MP_OBJ_FROM_PTR(&pin_GPIO22) }, + + { MP_ROM_QSTR(MP_QSTR_NFC_IN), MP_OBJ_FROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_OBJ_FROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_NFC_OUT), MP_OBJ_FROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_OBJ_FROM_PTR(&pin_GPIO33) }, + + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_OBJ_FROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_OBJ_FROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BCLK), MP_OBJ_FROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_OBJ_FROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCLK), MP_OBJ_FROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DOUT), MP_OBJ_FROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER_INT), MP_OBJ_FROM_PTR(&pin_GPIO34) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_OBJ_FROM_PTR(&displays[0].display)}, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_OBJ_FROM_PTR(&board_i2c_obj) }, + + // Filled in by board_init() + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_PLUG_STATUS), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_CHARGE_STATUS), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_POWER_BUTTON), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_ENC1_BUTTON), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_ENC2_BUTTON), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_HEADPHONE_DETECT), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_PACTRL), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_DC), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_RESET), mp_const_none }, + + { MP_ROM_QSTR(MP_QSTR_LEVEL_CONVERTER), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_LEVEL_POWER_ENABLE), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_LEVEL_VINHOLD), mp_const_none }, + + { MP_ROM_QSTR(MP_QSTR_TILT), mp_const_none }, + + // Only on some variants + { MP_ROM_QSTR(MP_QSTR_RTC_INT), mp_const_none }, + +}; +MP_DEFINE_MUTABLE_DICT(board_module_globals, board_module_globals_table); + +void board_set(qstr q, mp_obj_t value) { + mp_obj_t key = MP_OBJ_NEW_QSTR(q); + for (size_t i = 0; i < MP_ARRAY_SIZE(board_module_globals_table); i++) { + if (board_module_globals_table[i].key == key) { + board_module_globals_table[i].value = value; + return; + } + } +} diff --git a/ports/espressif/boards/yoto_mini_2024/sdkconfig b/ports/espressif/boards/yoto_mini_2024/sdkconfig new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ports/espressif/boards/yoto_player_v3/board.c b/ports/espressif/boards/yoto_player_v3/board.c new file mode 100644 index 00000000000..fd6ee40b9f3 --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/board.c @@ -0,0 +1,148 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "board.h" + +#include "supervisor/board.h" + +#include "extmod/vfs_fat.h" + +#include "py/mpstate.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/i2cioexpander/IOExpander.h" +#include "shared-bindings/i2cioexpander/IOPin.h" +#include "shared-bindings/sdioio/SDCard.h" + +#include "supervisor/filesystem.h" + +static sdioio_sdcard_obj_t sdmmc; +static mp_vfs_mount_t _sdcard_vfs; +static fs_user_mount_t _sdcard_usermount; +static i2cioexpander_ioexpander_obj_t ioexpander0; // First chip (p0/p1) +static i2cioexpander_ioexpander_obj_t ioexpander1; // Second chip (p2/p3) + +void board_init(void) { + // Wait for everything to start + mp_hal_delay_ms(300); + + // Initialize the board's peripherals here. + busio_i2c_obj_t *i2c = MP_OBJ_TO_PTR(common_hal_board_create_i2c(0)); + + // Initialize the IOExpanders + // V3/V3-E uses two PI4IOE5V6416 chips (16 pins each) + // First chip (0x20): p0 (pins 0-7), p1 (pins 8-15) + ioexpander0.base.type = &i2cioexpander_ioexpander_type; + common_hal_i2cioexpander_ioexpander_construct( + &ioexpander0, + MP_OBJ_FROM_PTR(i2c), + 0x20, // I2C address for first chip + 16, // Number of pins + 2, // Output register + 0, // Input register + 6); // Direction register + + // Second chip (0x21): p2 (pins 0-7), p3 (pins 8-15) + ioexpander1.base.type = &i2cioexpander_ioexpander_type; + common_hal_i2cioexpander_ioexpander_construct( + &ioexpander1, + MP_OBJ_FROM_PTR(i2c), + 0x21, // I2C address for second chip + 16, // Number of pins + 2, // Output register + 0, // Input register + 6); // Direction register + + board_set(MP_QSTR_IOEXPANDER0, MP_OBJ_FROM_PTR(&ioexpander0)); + board_set(MP_QSTR_IOEXPANDER1, MP_OBJ_FROM_PTR(&ioexpander1)); + + // Battery and charging (from first chip - p0/p1) + board_set(MP_QSTR_BATTERY_ALERT, ioexpander0.pins->items[6]); // IOX.0.6 + board_set(MP_QSTR_QI_STATUS, ioexpander0.pins->items[7]); // IOX.0.7 + board_set(MP_QSTR_QI_I2C_INT, ioexpander0.pins->items[0]); // IOX.0.0 + board_set(MP_QSTR_USB_STATUS, ioexpander0.pins->items[8 + 0]); // IOX.1.0 + board_set(MP_QSTR_CHARGE_STATUS, ioexpander0.pins->items[8 + 4]); // IOX.1.4 + + // Buttons (from first chip - p0/p1) + board_set(MP_QSTR_POWER_BUTTON, ioexpander0.pins->items[8 + 3]); // IOX.1.3 + board_set(MP_QSTR_ENC1_BUTTON, ioexpander0.pins->items[5]); // IOX.0.5 + board_set(MP_QSTR_ENC2_BUTTON, ioexpander0.pins->items[4]); // IOX.0.4 + + // Audio (from first chip - p0/p1 and second chip - p2/p3) + board_set(MP_QSTR_HEADPHONE_DETECT, ioexpander0.pins->items[8 + 1]); // IOX.1.1 + board_set(MP_QSTR_PACTRL, ioexpander1.pins->items[4]); // IOX.2.4 + + // Display - V3/V3-E uses ht16d35x with 4 CS lines (from second chip - p2) + board_set(MP_QSTR_DISPLAY_CS0, ioexpander1.pins->items[0]); // IOX.2.0 + board_set(MP_QSTR_DISPLAY_CS1, ioexpander1.pins->items[1]); // IOX.2.1 + board_set(MP_QSTR_DISPLAY_CS2, ioexpander1.pins->items[2]); // IOX.2.2 + board_set(MP_QSTR_DISPLAY_CS3, ioexpander1.pins->items[3]); // IOX.2.3 + + // Power control (from second chip - p2/p3) + board_set(MP_QSTR_LEVEL_CONVERTER, ioexpander1.pins->items[8 + 0]); // IOX.3.0 + board_set(MP_QSTR_LEVEL_POWER_ENABLE, ioexpander1.pins->items[5]); // IOX.2.5 + board_set(MP_QSTR_LEVEL_VINHOLD, ioexpander1.pins->items[8 + 1]); // IOX.3.1 + board_set(MP_QSTR_LEVEL_VOUTEN, ioexpander1.pins->items[8 + 3]); // IOX.3.3 + + // Sensors (from first chip - p0/p1) + board_set(MP_QSTR_TILT, ioexpander0.pins->items[8 + 2]); // IOX.1.2 + board_set(MP_QSTR_RTC_INT, ioexpander0.pins->items[1]); // IOX.0.1 + + // Qi charging control (V3-E, from second chip - p2/p3) + board_set(MP_QSTR_QI_CHARGE_ENABLE, ioexpander1.pins->items[6]); // IOX.2.6 + board_set(MP_QSTR_USB_CHARGE_ENABLE, ioexpander1.pins->items[7]); // IOX.2.7 + board_set(MP_QSTR_QI_ENABLE_5W, ioexpander1.pins->items[8 + 5]); // IOX.3.5 + + // Output pin 3 high. Not clear why. + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander0.pins->items[3]), true, DRIVE_MODE_PUSH_PULL); + + // Initialize output pins + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[0]), true, DRIVE_MODE_PUSH_PULL); // DISPLAY_CS0 (IOX.2.0) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[1]), true, DRIVE_MODE_PUSH_PULL); // DISPLAY_CS1 (IOX.2.1) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[2]), true, DRIVE_MODE_PUSH_PULL); // DISPLAY_CS2 (IOX.2.2) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[3]), true, DRIVE_MODE_PUSH_PULL); // DISPLAY_CS3 (IOX.2.3) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[4]), true, DRIVE_MODE_PUSH_PULL); // PACTRL (IOX.2.4) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[5]), false, DRIVE_MODE_PUSH_PULL); // LEVEL_POWER_ENABLE (IOX.2.5) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[6]), true, DRIVE_MODE_PUSH_PULL); // QI_CHARGE_ENABLE + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[7]), false, DRIVE_MODE_PUSH_PULL); // USB_CHARGE_ENABLE + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[8 + 0]), true, DRIVE_MODE_PUSH_PULL); // LEVEL_CONVERTER (IOX.3.0) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[8 + 1]), true, DRIVE_MODE_PUSH_PULL); // VINHOLD (IOX.3.1) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[8 + 3]), true, DRIVE_MODE_PUSH_PULL); // VOUTEN (IOX.3.3) + common_hal_i2cioexpander_iopin_switch_to_output(MP_OBJ_TO_PTR(ioexpander1.pins->items[8 + 5]), false, DRIVE_MODE_PUSH_PULL); // QI_ENABLE_5W (IOX.3.5) + + // Initialize SD card + // V3/V3-E uses single-line SD (sd1 mode), not 4-line (sd4 mode) like Mini + sdmmc.base.type = &sdioio_SDCard_type; + const mcu_pin_obj_t *data_pins[1] = {MP_ROM_PTR(&pin_GPIO2)}; + common_hal_sdioio_sdcard_construct(&sdmmc, MP_ROM_PTR(&pin_GPIO14), MP_ROM_PTR(&pin_GPIO15), 1, data_pins, 25 * 1000000); + + fs_user_mount_t *vfs = &_sdcard_usermount; + vfs->base.type = &mp_fat_vfs_type; + vfs->fatfs.drv = vfs; + + // Initialise underlying block device + vfs->blockdev.block_size = FF_MIN_SS; // default, will be populated by call to MP_BLOCKDEV_IOCTL_BLOCK_SIZE + mp_vfs_blockdev_init(&vfs->blockdev, &sdmmc); + + // mount the block device so the VFS methods can be used + FRESULT res = f_mount(&vfs->fatfs); + if (res != FR_OK) { + common_hal_sdioio_sdcard_deinit(&sdmmc); + return; + } + common_hal_sdioio_sdcard_never_reset(&sdmmc); + + filesystem_set_concurrent_write_protection(vfs, true); + filesystem_set_writable_by_usb(vfs, false); + + mp_vfs_mount_t *sdcard_vfs = &_sdcard_vfs; + sdcard_vfs->str = "/sd"; + sdcard_vfs->len = 3; + sdcard_vfs->obj = MP_OBJ_FROM_PTR(&_sdcard_usermount); + sdcard_vfs->next = MP_STATE_VM(vfs_mount_table); + MP_STATE_VM(vfs_mount_table) = sdcard_vfs; +} diff --git a/ports/espressif/boards/yoto_player_v3/board.h b/ports/espressif/boards/yoto_player_v3/board.h new file mode 100644 index 00000000000..1e40b62b047 --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/board.h @@ -0,0 +1,3 @@ +#include "py/obj.h" + +extern void board_set(qstr key, mp_obj_t value); diff --git a/ports/espressif/boards/yoto_player_v3/mpconfigboard.h b/ports/espressif/boards/yoto_player_v3/mpconfigboard.h new file mode 100644 index 00000000000..ba53649275c --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/mpconfigboard.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Yoto Player V3" +#define MICROPY_HW_MCU_NAME "ESP32" + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO25, .sda = &pin_GPIO21}} +#define CIRCUITPY_BOARD_I2C_SPEED (400000) + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO23, .mosi = &pin_GPIO22, .miso = &pin_GPIO26}} + +#define CIRCUITPY_BOARD_UART (1) +#define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO17, .rx = &pin_GPIO16}} + +// UART pins attached to the USB-serial converter chip +#define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) +#define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) diff --git a/ports/espressif/boards/yoto_player_v3/mpconfigboard.mk b/ports/espressif/boards/yoto_player_v3/mpconfigboard.mk new file mode 100644 index 00000000000..a1b940316c4 --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/mpconfigboard.mk @@ -0,0 +1,14 @@ +CIRCUITPY_CREATOR_ID = 0x40100000 +CIRCUITPY_CREATION_ID = 0x00320001 + +IDF_TARGET = esp32 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 40m + +CIRCUITPY_I2CIOEXPANDER = 1 diff --git a/ports/espressif/boards/yoto_player_v3/pins.c b/ports/espressif/boards/yoto_player_v3/pins.c new file mode 100644 index 00000000000..0862a020fdf --- /dev/null +++ b/ports/espressif/boards/yoto_player_v3/pins.c @@ -0,0 +1,104 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT +// + +#include "board.h" + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static mp_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_MUTABLE_BOARD_DICT_STANDARD_ITEMS + + // External pins are in silkscreen order, from top to bottom, left side, then right side + // Encoder 1: V3-E uses GPIO26/13, V3 uses GPIO35/13 + { MP_ROM_QSTR(MP_QSTR_ENC1A), MP_OBJ_FROM_PTR(&pin_GPIO26) }, // V3-E: GPIO26, V3: GPIO35 + { MP_ROM_QSTR(MP_QSTR_ENC1A_V3), MP_OBJ_FROM_PTR(&pin_GPIO35) }, // V3-E: GPIO26, V3: GPIO35 + { MP_ROM_QSTR(MP_QSTR_ENC1B), MP_OBJ_FROM_PTR(&pin_GPIO13) }, + + // Encoder 2: Both V3 and V3-E use GPIO27/4 + { MP_ROM_QSTR(MP_QSTR_ENC2A), MP_OBJ_FROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_ENC2B), MP_OBJ_FROM_PTR(&pin_GPIO4) }, + + // Light sensor (V3/V3-E) + { MP_ROM_QSTR(MP_QSTR_LIGHT_SENSOR), MP_OBJ_FROM_PTR(&pin_GPIO36) }, + + // Temperature sensors (V3/V3-E) + { MP_ROM_QSTR(MP_QSTR_TEMP_SENSOR), MP_OBJ_FROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_QI_RX_TEMP_SENSOR), MP_OBJ_FROM_PTR(&pin_GPIO35) }, // V3-E only + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_OBJ_FROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_OBJ_FROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY_SCK), MP_OBJ_FROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_OBJ_FROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_MOSI), MP_OBJ_FROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_OBJ_FROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_MISO), MP_OBJ_FROM_PTR(&pin_GPIO26) }, // V3/V3-E have MISO + { MP_ROM_QSTR(MP_QSTR_MISO), MP_OBJ_FROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_NFC_IN), MP_OBJ_FROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_OBJ_FROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_NFC_OUT), MP_OBJ_FROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_OBJ_FROM_PTR(&pin_GPIO33) }, + + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_OBJ_FROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_OBJ_FROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BCLK), MP_OBJ_FROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_OBJ_FROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCLK), MP_OBJ_FROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DOUT), MP_OBJ_FROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER_INT), MP_OBJ_FROM_PTR(&pin_GPIO34) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_OBJ_FROM_PTR(&board_i2c_obj) }, + + // Filled in by board_init() + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER0), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_IOEXPANDER1), mp_const_none }, + { MP_ROM_QSTR(MP_QSTR_BATTERY_ALERT), mp_const_none }, // IOX.0.6 + { MP_ROM_QSTR(MP_QSTR_QI_STATUS), mp_const_none }, // IOX.0.7 + { MP_ROM_QSTR(MP_QSTR_USB_STATUS), mp_const_none }, // IOX.1.0 + { MP_ROM_QSTR(MP_QSTR_CHARGE_STATUS), mp_const_none }, // IOX.1.4 + { MP_ROM_QSTR(MP_QSTR_POWER_BUTTON), mp_const_none }, // IOX.1.3 + { MP_ROM_QSTR(MP_QSTR_ENC1_BUTTON), mp_const_none }, // IOX.0.5 + { MP_ROM_QSTR(MP_QSTR_ENC2_BUTTON), mp_const_none }, // IOX.0.4 + { MP_ROM_QSTR(MP_QSTR_HEADPHONE_DETECT), mp_const_none }, // IOX.1.1 + { MP_ROM_QSTR(MP_QSTR_PACTRL), mp_const_none }, // IOX.2.4 + // V3/V3-E use ht16d35x display with 4 CS lines + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS0), mp_const_none }, // IOX.2.0 + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS1), mp_const_none }, // IOX.2.1 + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS2), mp_const_none }, // IOX.2.2 + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS3), mp_const_none }, // IOX.2.3 + + { MP_ROM_QSTR(MP_QSTR_LEVEL_CONVERTER), mp_const_none }, // IOX.3.0 + { MP_ROM_QSTR(MP_QSTR_LEVEL_POWER_ENABLE), mp_const_none }, // IOX.2.5 + { MP_ROM_QSTR(MP_QSTR_LEVEL_VINHOLD), mp_const_none }, // IOX.3.1 + { MP_ROM_QSTR(MP_QSTR_LEVEL_VOUTEN), mp_const_none }, // IOX.3.3 + + { MP_ROM_QSTR(MP_QSTR_TILT), mp_const_none }, // IOX.1.2 + { MP_ROM_QSTR(MP_QSTR_RTC_INT), mp_const_none }, // IOX.0.1 + + // Qi charging pins (V3-E) + { MP_ROM_QSTR(MP_QSTR_QI_CHARGE_ENABLE), mp_const_none }, // IOX.2.6 + { MP_ROM_QSTR(MP_QSTR_QI_ENABLE_5W), mp_const_none }, // IOX.3.5 + { MP_ROM_QSTR(MP_QSTR_QI_I2C_INT), mp_const_none }, // IOX.0.0 + + // USB-C charging pins (V3/V3-E) + { MP_ROM_QSTR(MP_QSTR_USB_CHARGE_ENABLE), mp_const_none }, // IOX.2.7 + +}; +MP_DEFINE_MUTABLE_DICT(board_module_globals, board_module_globals_table); + +void board_set(qstr q, mp_obj_t value) { + mp_obj_t key = MP_OBJ_NEW_QSTR(q); + for (size_t i = 0; i < MP_ARRAY_SIZE(board_module_globals_table); i++) { + if (board_module_globals_table[i].key == key) { + board_module_globals_table[i].value = value; + return; + } + } +} diff --git a/ports/espressif/boards/yoto_player_v3/sdkconfig b/ports/espressif/boards/yoto_player_v3/sdkconfig new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 9ef3877ea92..723fa7d7400 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -169,16 +169,16 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t convert_esp_err(esp_err_t result) { +static mp_errno_t convert_esp_err(esp_err_t result) { switch (result) { case ESP_OK: return 0; case ESP_FAIL: - return MP_ENODEV; + return -MP_ENODEV; case ESP_ERR_TIMEOUT: - return MP_ETIMEDOUT; + return -MP_ETIMEDOUT; default: - return MP_EIO; + return -MP_EIO; } } @@ -189,7 +189,7 @@ static size_t _transaction_duration_ms(size_t frequency, size_t len) { return (len + 1) / bytes_per_ms + 1000; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = addr, @@ -202,7 +202,7 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const u return convert_esp_err(result); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = addr, @@ -215,7 +215,7 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t return convert_esp_err(result); } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, diff --git a/ports/espressif/common-hal/sdioio/SDCard.c b/ports/espressif/common-hal/sdioio/SDCard.c index 87ba32f8020..f7745618162 100644 --- a/ports/espressif/common-hal/sdioio/SDCard.c +++ b/ports/espressif/common-hal/sdioio/SDCard.c @@ -10,6 +10,7 @@ #include "driver/sdmmc_host.h" #include "ports/espressif/esp-idf/components/sdmmc/include/sdmmc_cmd.h" +#include "extmod/vfs.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/util.h" #include "shared-bindings/sdioio/SDCard.h" @@ -168,32 +169,73 @@ static void check_whole_block(mp_buffer_info_t *bufinfo, int sector_size) { } } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { - common_hal_sdioio_sdcard_check_for_deinit(self); - check_whole_block(bufinfo, self->card.csd.sector_size); - esp_err_t err; - ESP_LOGI(TAG, "in common_hal_sdioio_sdcard_writeblocks"); - // err = sdmmc_io_write_blocks(&self->card, 1, start_block, bufinfo->buf, bufinfo->len); - err = sdmmc_write_sectors(&self->card, bufinfo->buf, start_block, bufinfo->len / self->card.csd.sector_size); +mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + ESP_LOGI(TAG, "in sdioio_sdcard_writeblocks"); + esp_err_t err = sdmmc_write_sectors(&self->card, buf, start_block, num_blocks); if (err != ESP_OK) { ESP_LOGW(TAG, "Failed to write blocks with err 0x%X", err); + return -MP_EIO; } return 0; } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { common_hal_sdioio_sdcard_check_for_deinit(self); check_whole_block(bufinfo, self->card.csd.sector_size); - esp_err_t err; - ESP_LOGI(TAG, "in common_hal_sdioio_sdcard_readblocks"); - // err = sdmmc_io_read_blocks(&self->card, 1, start_block, bufinfo->buf, bufinfo->len); - err = sdmmc_read_sectors(&self->card, bufinfo->buf, start_block, bufinfo->len / self->card.csd.sector_size); + + uint32_t num_blocks = bufinfo->len / self->card.csd.sector_size; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + ESP_LOGI(TAG, "in sdioio_sdcard_readblocks"); + esp_err_t err = sdmmc_read_sectors(&self->card, buf, start_block, num_blocks); if (err != ESP_OK) { ESP_LOGW(TAG, "Failed to read blocks with err 0x%X", err); + return -MP_EIO; } return 0; } +mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + common_hal_sdioio_sdcard_check_for_deinit(self); + check_whole_block(bufinfo, self->card.csd.sector_size); + + uint32_t num_blocks = bufinfo->len / self->card.csd.sector_size; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } +} + bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { return true; } diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index a967b8a4f15..67f8ca2987b 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -103,9 +103,6 @@ ifeq ($(IDF_TARGET),esp32) CIRCUITPY_ALARM_TOUCH = 1 CIRCUITPY_RGBMATRIX = 0 -# SDMMC not supported yet -CIRCUITPY_SDIOIO = 0 - # Has no USB CIRCUITPY_USB_DEVICE = 0 diff --git a/ports/mimxrt10xx/common-hal/busio/I2C.c b/ports/mimxrt10xx/common-hal/busio/I2C.c index 132b3083212..38777f2c903 100644 --- a/ports/mimxrt10xx/common-hal/busio/I2C.c +++ b/ports/mimxrt10xx/common-hal/busio/I2C.c @@ -201,7 +201,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { lpi2c_master_transfer_t xfer = { 0 }; @@ -215,15 +215,15 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, return 0; } - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { lpi2c_master_transfer_t xfer = { 0 }; @@ -237,12 +237,12 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, return 0; } - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/nordic/common-hal/busio/I2C.c b/ports/nordic/common-hal/busio/I2C.c index 3558fad165b..904d35cae3d 100644 --- a/ports/nordic/common-hal/busio/I2C.c +++ b/ports/nordic/common-hal/busio/I2C.c @@ -47,18 +47,18 @@ void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { never_reset_pin_number(self->sda_pin_number); } -static uint8_t twi_error_to_mp(const nrfx_err_t err) { +static mp_errno_t twi_error_to_mp(const nrfx_err_t err) { switch (err) { case NRFX_ERROR_DRV_TWI_ERR_ANACK: - return MP_ENODEV; + return -MP_ENODEV; case NRFX_ERROR_BUSY: - return MP_EBUSY; + return -MP_EBUSY; case NRFX_ERROR_INVALID_ADDR: case NRFX_ERROR_DRV_TWI_ERR_DNACK: case NRFX_ERROR_DRV_TWI_ERR_OVERRUN: - return MP_EIO; + return -MP_EIO; case NRFX_ERROR_TIMEOUT: - return MP_ETIMEDOUT; + return -MP_ETIMEDOUT; default: break; } @@ -258,9 +258,9 @@ static nrfx_err_t _twim_xfer_with_timeout(busio_i2c_obj_t *self, nrfx_twim_xfer_ } } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool stopBit) { +static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool stopBit) { if (len == 0) { - return common_hal_busio_i2c_probe(self, addr) ? 0 : MP_ENODEV; + return common_hal_busio_i2c_probe(self, addr) ? 0 : -MP_ENODEV; } nrfx_err_t err = NRFX_SUCCESS; @@ -286,11 +286,11 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, return twi_error_to_mp(err); } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { if (len == 0) { return 0; } @@ -317,9 +317,9 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t return twi_error_to_mp(err); } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/raspberrypi/common-hal/busio/I2C.c b/ports/raspberrypi/common-hal/busio/I2C.c index 0f7e023f0e9..41df0eac724 100644 --- a/ports/raspberrypi/common-hal/busio/I2C.c +++ b/ports/raspberrypi/common-hal/busio/I2C.c @@ -86,7 +86,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, // // Do not use the default supplied clock stretching timeout here. // It is too short for some devices. Use the busio timeout instead. - shared_module_bitbangio_i2c_construct(&self->bitbangio_i2c, scl, sda, + shared_module_bitbangio_i2c_construct(&self->bitbangio_i2c, MP_OBJ_FROM_PTR(scl), MP_OBJ_FROM_PTR(sda), frequency, BUS_TIMEOUT_US); self->baudrate = i2c_init(self->peripheral, frequency); @@ -144,7 +144,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { if (len == 0) { // The RP2040 I2C peripheral will not perform 0 byte writes. @@ -174,20 +174,20 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, } switch (result) { case PICO_ERROR_GENERIC: - return MP_ENODEV; + return -MP_ENODEV; case PICO_ERROR_TIMEOUT: - return MP_ETIMEDOUT; + return -MP_ETIMEDOUT; default: - return MP_EIO; + return -MP_EIO; } } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { size_t result = i2c_read_timeout_us(self->peripheral, addr, data, len, false, BUS_TIMEOUT_US); if (result == len) { @@ -195,17 +195,17 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, } switch (result) { case PICO_ERROR_GENERIC: - return MP_ENODEV; + return -MP_ENODEV; case PICO_ERROR_TIMEOUT: - return MP_ETIMEDOUT; + return -MP_ETIMEDOUT; default: - return MP_EIO; + return -MP_EIO; } } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index bbce13d1381..8401c5d7545 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -30,6 +30,7 @@ CIRCUITPY_FREQUENCYIO = 0 # Use PWM internally CIRCUITPY_I2CTARGET = 1 +CIRCUITPY_I2CIOEXPANDER = 1 CIRCUITPY_NVM = 1 # Use PIO internally CIRCUITPY_PULSEIO ?= 1 diff --git a/ports/renode/common-hal/busio/I2C.c b/ports/renode/common-hal/busio/I2C.c index c94f63cb880..0b01b6e7936 100644 --- a/ports/renode/common-hal/busio/I2C.c +++ b/ports/renode/common-hal/busio/I2C.c @@ -44,19 +44,19 @@ bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return 0; } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { - return MP_EIO; + return -MP_EIO; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - return MP_EIO; + return -MP_EIO; } void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { diff --git a/ports/silabs/common-hal/busio/I2C.c b/ports/silabs/common-hal/busio/I2C.c index ae18f561c50..85f3e63a6db 100644 --- a/ports/silabs/common-hal/busio/I2C.c +++ b/ports/silabs/common-hal/busio/I2C.c @@ -145,7 +145,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { I2C_TransferSeq_TypeDef seq; @@ -159,13 +159,13 @@ uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, ret = I2CSPM_Transfer(self->i2cspm, &seq); if (ret != i2cTransferDone) { - return MP_EIO; + return -MP_EIO; } return 0; } // Read into buffer from the device selected by address -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { @@ -180,13 +180,13 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, ret = I2CSPM_Transfer(self->i2cspm, &seq); if (ret != i2cTransferDone) { - return MP_EIO; + return -MP_EIO; } return 0; } // Write the bytes from out_data to the device selected by address, -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { @@ -204,7 +204,7 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, ret = I2CSPM_Transfer(self->i2cspm, &seq); if (ret != i2cTransferDone) { - return MP_EIO; + return -MP_EIO; } return 0; } diff --git a/ports/stm/common-hal/busio/I2C.c b/ports/stm/common-hal/busio/I2C.c index e6957989cc7..5277bffe1fc 100644 --- a/ports/stm/common-hal/busio/I2C.c +++ b/ports/stm/common-hal/busio/I2C.c @@ -212,7 +212,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { HAL_StatusTypeDef result; if (!transmit_stop_bit) { @@ -234,19 +234,19 @@ static uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, result = HAL_I2C_Master_Transmit(&(self->handle), (uint16_t)(addr << 1), (uint8_t *)data, (uint16_t)len, 500); } - return result == HAL_OK ? 0 : MP_EIO; + return result == HAL_OK ? 0 : -MP_EIO; } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { if (!self->frame_in_prog) { return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr << 1), data, (uint16_t)len, 500) - == HAL_OK ? 0 : MP_EIO; + == HAL_OK ? 0 : -MP_EIO; } else { HAL_StatusTypeDef result = HAL_I2C_Master_Seq_Receive_IT(&(self->handle), (uint16_t)(addr << 1), (uint8_t *)data, @@ -259,9 +259,9 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, } } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - uint8_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/stm/common-hal/sdioio/SDCard.c b/ports/stm/common-hal/sdioio/SDCard.c index 92e552c2e89..d8cfdb11318 100644 --- a/ports/stm/common-hal/sdioio/SDCard.c +++ b/ports/stm/common-hal/sdioio/SDCard.c @@ -6,6 +6,8 @@ #include #include "shared-bindings/sdioio/SDCard.h" + +#include "extmod/vfs.h" #include "py/mperrno.h" #include "py/runtime.h" @@ -239,9 +241,10 @@ static void check_for_deinit(sdioio_sdcard_obj_t *self) { } } -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { - check_for_deinit(self); - check_whole_block(bufinfo); +// Native function for VFS blockdev layer +mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); self->state_programming = true; common_hal_mcu_disable_interrupts(); @@ -251,17 +254,27 @@ int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t sta #else uint32_t time_out = 1000; #endif - HAL_StatusTypeDef r = HAL_SD_WriteBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, time_out); + HAL_StatusTypeDef r = HAL_SD_WriteBlocks(&self->handle, buf, start_block, num_blocks, time_out); common_hal_mcu_enable_interrupts(); if (r != HAL_OK) { - return -EIO; + return -MP_EIO; } return 0; } -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { check_for_deinit(self); check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); common_hal_mcu_disable_interrupts(); #ifdef STM32H750xx @@ -270,14 +283,48 @@ int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t star #else uint32_t time_out = 1000; #endif - HAL_StatusTypeDef r = HAL_SD_ReadBlocks(&self->handle, bufinfo->buf, start_block, bufinfo->len / 512, time_out); + HAL_StatusTypeDef r = HAL_SD_ReadBlocks(&self->handle, buf, start_block, num_blocks, time_out); common_hal_mcu_enable_interrupts(); if (r != HAL_OK) { - return -EIO; + return -MP_EIO; } return 0; } +mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors + return true; + + default: + return false; // Unsupported command + } +} + bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { check_for_deinit(self); return true; diff --git a/ports/zephyr-cp/common-hal/busio/I2C.c b/ports/zephyr-cp/common-hal/busio/I2C.c index 49def727a53..d26fc2828cd 100644 --- a/ports/zephyr-cp/common-hal/busio/I2C.c +++ b/ports/zephyr-cp/common-hal/busio/I2C.c @@ -73,34 +73,34 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { k_mutex_unlock(&self->mutex); } -uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { if (common_hal_busio_i2c_deinited(self)) { - return MP_EIO; + return -MP_EIO; } int ret = i2c_write(self->i2c_device, data, len, addr); if (ret != 0) { // Map Zephyr error codes to errno if (ret == -ENOTSUP) { - return MP_EOPNOTSUPP; + return -MP_EOPNOTSUPP; } else if (ret == -EIO || ret == -ENXIO) { - return MP_EIO; + return -MP_EIO; } else if (ret == -EBUSY) { - return MP_EBUSY; + return -MP_EBUSY; } - return MP_EIO; + return -MP_EIO; } return 0; } -uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { if (common_hal_busio_i2c_deinited(self)) { - return MP_EIO; + return -MP_EIO; } if (len == 0) { @@ -111,23 +111,23 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, if (ret != 0) { // Map Zephyr error codes to errno if (ret == -ENOTSUP) { - return MP_EOPNOTSUPP; + return -MP_EOPNOTSUPP; } else if (ret == -EIO || ret == -ENXIO) { - return MP_EIO; + return -MP_EIO; } else if (ret == -EBUSY) { - return MP_EBUSY; + return -MP_EBUSY; } - return MP_EIO; + return -MP_EIO; } return 0; } -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { if (common_hal_busio_i2c_deinited(self)) { - return MP_EIO; + return -MP_EIO; } // Use i2c_write_read for combined transaction with repeated start @@ -135,13 +135,13 @@ uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, if (ret != 0) { // Map Zephyr error codes to errno if (ret == -ENOTSUP) { - return MP_EOPNOTSUPP; + return -MP_EOPNOTSUPP; } else if (ret == -EIO || ret == -ENXIO) { - return MP_EIO; + return -MP_EIO; } else if (ret == -EBUSY) { - return MP_EBUSY; + return -MP_EBUSY; } - return MP_EIO; + return -MP_EIO; } return 0; diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 56c836cb3a4..5760dbd9eb1 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -255,6 +255,9 @@ endif ifeq ($(CIRCUITPY_I2CTARGET),1) SRC_PATTERNS += i2ctarget/% endif +ifeq ($(CIRCUITPY_I2CIOEXPANDER),1) +SRC_PATTERNS += i2cioexpander/% +endif ifeq ($(CIRCUITPY_IMAGECAPTURE),1) SRC_PATTERNS += imagecapture/% endif @@ -612,6 +615,7 @@ $(filter $(SRC_PATTERNS), \ canio/Match.c \ codeop/__init__.c \ countio/Edge.c \ + digitalio/DigitalInOutProtocol.c \ digitalio/Direction.c \ digitalio/DriveMode.c \ digitalio/Pull.c \ @@ -725,6 +729,9 @@ SRC_SHARED_MODULE_ALL = \ dotclockframebuffer/__init__.c \ epaperdisplay/__init__.c \ epaperdisplay/EPaperDisplay.c \ + i2cioexpander/IOExpander.c \ + i2cioexpander/IOPin.c \ + i2cioexpander/__init__.c \ floppyio/__init__.c \ fontio/BuiltinFont.c \ fontio/__init__.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 386d1ee3d1e..fb4f261ab6f 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -321,6 +321,9 @@ typedef long mp_off_t; #if defined(DEFAULT_I2C_BUS_SCL) && defined(DEFAULT_I2C_BUS_SDA) #define CIRCUITPY_BOARD_I2C (1) #define CIRCUITPY_BOARD_I2C_PIN {{.scl = DEFAULT_I2C_BUS_SCL, .sda = DEFAULT_I2C_BUS_SDA}} +#ifndef CIRCUITPY_BOARD_I2C_SPEED +#define CIRCUITPY_BOARD_I2C_SPEED (100000) +#endif #else #define CIRCUITPY_BOARD_I2C (0) #endif diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 9bbe5691dfb..e3a3e8fe800 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -346,6 +346,9 @@ CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS_ONLY=$(CIRCUITPY_HASHLIB_MBEDTLS_ONLY) CIRCUITPY_I2CTARGET ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_I2CTARGET=$(CIRCUITPY_I2CTARGET) +CIRCUITPY_I2CIOEXPANDER ?= 0 +CFLAGS += -DCIRCUITPY_I2CIOEXPANDER=$(CIRCUITPY_I2CIOEXPANDER) + CIRCUITPY_IMAGECAPTURE ?= 0 CFLAGS += -DCIRCUITPY_IMAGECAPTURE=$(CIRCUITPY_IMAGECAPTURE) diff --git a/py/mperrno.h b/py/mperrno.h index 9e4ecd9419c..f1fee77b22e 100644 --- a/py/mperrno.h +++ b/py/mperrno.h @@ -143,6 +143,8 @@ #endif +typedef int mp_errno_t; + #if MICROPY_PY_ERRNO #include "py/obj.h" diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index d1a200d39b5..ddd8824eb58 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -22,8 +22,8 @@ //| //| def __init__( //| self, -//| scl: microcontroller.Pin, -//| sda: microcontroller.Pin, +//| scl: Union[microcontroller.Pin, digitalio.DigitalInOutProtocol], +//| sda: Union[microcontroller.Pin, digitalio.DigitalInOutProtocol], //| *, //| frequency: int = 400000, //| timeout: int = 255, @@ -40,8 +40,8 @@ //| bit unpacking. Instead, use an existing driver or make one with //| :ref:`Register ` data descriptors. //| -//| :param ~microcontroller.Pin scl: The clock pin -//| :param ~microcontroller.Pin sda: The data pin +//| :param ~microcontroller.Pin scl: The clock pin or DigitalInOut object +//| :param ~microcontroller.Pin sda: The data pin or DigitalInOut object //| :param int frequency: The clock frequency of the bus //| :param int timeout: The maximum clock stretching timeout in microseconds""" //| ... @@ -57,11 +57,8 @@ static mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const mcu_pin_obj_t *scl = validate_obj_is_free_pin(args[ARG_scl].u_obj, MP_QSTR_scl); - const mcu_pin_obj_t *sda = validate_obj_is_free_pin(args[ARG_sda].u_obj, MP_QSTR_sda); - bitbangio_i2c_obj_t *self = mp_obj_malloc_with_finaliser(bitbangio_i2c_obj_t, &bitbangio_i2c_type); - shared_module_bitbangio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); + shared_module_bitbangio_i2c_construct(self, args[ARG_scl].u_obj, args[ARG_sda].u_obj, args[ARG_frequency].u_int, args[ARG_timeout].u_int); return (mp_obj_t)self; } diff --git a/shared-bindings/bitbangio/I2C.h b/shared-bindings/bitbangio/I2C.h index 022be3692a6..cc9cd21b601 100644 --- a/shared-bindings/bitbangio/I2C.h +++ b/shared-bindings/bitbangio/I2C.h @@ -16,8 +16,8 @@ extern const mp_obj_type_t bitbangio_i2c_type; // Initializes the hardware peripheral. extern void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, - const mcu_pin_obj_t *scl, - const mcu_pin_obj_t *sda, + mp_obj_t scl, + mp_obj_t sda, uint32_t frequency, uint32_t us_timeout); diff --git a/shared-bindings/bitbangio/SPI.c b/shared-bindings/bitbangio/SPI.c index 8938ae4898d..f2e635b47bb 100644 --- a/shared-bindings/bitbangio/SPI.c +++ b/shared-bindings/bitbangio/SPI.c @@ -33,9 +33,9 @@ //| //| def __init__( //| self, -//| clock: microcontroller.Pin, -//| MOSI: Optional[microcontroller.Pin] = None, -//| MISO: Optional[microcontroller.Pin] = None, +//| clock: Union[microcontroller.Pin, digitalio.DigitalInOutProtocol], +//| MOSI: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, +//| MISO: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, //| ) -> None: //| """Construct an SPI object on the given pins. //| @@ -48,9 +48,9 @@ //| :ref:`Register ` data descriptors. //| //| -//| :param ~microcontroller.Pin clock: the pin to use for the clock. -//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin. -//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin.""" +//| :param ~microcontroller.Pin clock: the pin to use for the clock or DigitalInOut object +//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin or DigitalInOut object +//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin or DigitalInOut object""" //| ... //| @@ -65,12 +65,8 @@ static mp_obj_t bitbangio_spi_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); - const mcu_pin_obj_t *mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj, MP_QSTR_mosi); - const mcu_pin_obj_t *miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj, MP_QSTR_miso); - bitbangio_spi_obj_t *self = mp_obj_malloc(bitbangio_spi_obj_t, &bitbangio_spi_type); - shared_module_bitbangio_spi_construct(self, clock, mosi, miso); + shared_module_bitbangio_spi_construct(self, args[ARG_clock].u_obj, args[ARG_MOSI].u_obj, args[ARG_MISO].u_obj); return (mp_obj_t)self; } diff --git a/shared-bindings/bitbangio/SPI.h b/shared-bindings/bitbangio/SPI.h index dbe821683b0..19ec05152ad 100644 --- a/shared-bindings/bitbangio/SPI.h +++ b/shared-bindings/bitbangio/SPI.h @@ -16,8 +16,7 @@ extern const mp_obj_type_t bitbangio_spi_type; // Construct an underlying SPI object. extern void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self, - const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *miso); + mp_obj_t clock, mp_obj_t mosi, mp_obj_t miso); extern void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self); extern bool shared_module_bitbangio_spi_deinited(bitbangio_spi_obj_t *self); diff --git a/shared-bindings/board/__init__.h b/shared-bindings/board/__init__.h index fbc39317a30..4466f3924bf 100644 --- a/shared-bindings/board/__init__.h +++ b/shared-bindings/board/__init__.h @@ -11,7 +11,7 @@ #include "shared-bindings/microcontroller/Pin.h" // for the pin definitions -extern const mp_obj_dict_t board_module_globals; +extern mp_obj_dict_t board_module_globals; static const MP_DEFINE_STR_OBJ(board_module_id_obj, CIRCUITPY_BOARD_ID); mp_obj_t common_hal_board_get_i2c(const mp_int_t instance); @@ -38,3 +38,7 @@ MP_DECLARE_CONST_FUN_OBJ_0(board_uart_obj); #define CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS \ { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_board) }, \ { MP_ROM_QSTR(MP_QSTR_board_id), MP_ROM_PTR(&board_module_id_obj) }, + +#define CIRCUITPYTHON_MUTABLE_BOARD_DICT_STANDARD_ITEMS \ + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_board) }, \ + { MP_ROM_QSTR(MP_QSTR_board_id), MP_OBJ_FROM_PTR(&board_module_id_obj) }, diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 165b6a5ba93..34c02349deb 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -228,10 +228,10 @@ static mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, start *= stride_in_bytes; length *= stride_in_bytes; - uint8_t status = + mp_errno_t status = common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t *)bufinfo.buf) + start, length); if (status != 0) { - mp_raise_OSError(status); + mp_raise_OSError(-status); } return mp_const_none; @@ -290,11 +290,11 @@ static mp_obj_t busio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_ma length *= stride_in_bytes; // do the transfer - uint8_t status = + mp_errno_t status = common_hal_busio_i2c_write(self, args[ARG_address].u_int, ((uint8_t *)bufinfo.buf) + start, length); if (status != 0) { - mp_raise_OSError(status); + mp_raise_OSError(-status); } return mp_const_none; @@ -377,10 +377,10 @@ static mp_obj_t busio_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *p in_start *= in_stride_in_bytes; in_length *= in_stride_in_bytes; - uint8_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int, + mp_errno_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int, ((uint8_t *)out_bufinfo.buf) + out_start, out_length, ((uint8_t *)in_bufinfo.buf) + in_start, in_length); if (status != 0) { - mp_raise_OSError(status); + mp_raise_OSError(-status); } return mp_const_none; diff --git a/shared-bindings/busio/I2C.h b/shared-bindings/busio/I2C.h index 55f2d0f0108..e7293ce8617 100644 --- a/shared-bindings/busio/I2C.h +++ b/shared-bindings/busio/I2C.h @@ -7,6 +7,7 @@ #pragma once #include "py/obj.h" +#include "py/mperrno.h" #include "common-hal/microcontroller/Pin.h" #include "common-hal/busio/I2C.h" @@ -35,17 +36,17 @@ extern void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self); // Probe the bus to see if a device acknowledges the given address. extern bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr); -// Write to the device and return 0 on success or an appropriate error code from mperrno.h -extern uint8_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, +// Write to the device and return 0 on success or a negative error code from mperrno.h +extern mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len); // Reads memory of the i2c device picking up where it left off and return 0 on -// success or an appropriate error code from mperrno.h -extern uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, +// success or a negative error code from mperrno.h +extern mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len); // Do a write and then a read in the same I2C transaction. -uint8_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t address, +mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len); // This is used by the supervisor to claim I2C devices indefinitely. diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index a29fdcc371c..7d847165049 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -17,6 +17,7 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" #include "shared-bindings/digitalio/Direction.h" #include "shared-bindings/digitalio/DriveMode.h" #include "shared-bindings/digitalio/Pull.h" @@ -341,12 +342,86 @@ static const mp_rom_map_elem_t digitalio_digitalinout_locals_dict_table[] = { static MP_DEFINE_CONST_DICT(digitalio_digitalinout_locals_dict, digitalio_digitalinout_locals_dict_table); +// Protocol implementation - thin wrappers to match protocol signature +static void digitalinout_proto_deinit(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_digitalio_digitalinout_deinit(self); +} + +static bool digitalinout_proto_deinited(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_deinited(self); +} + +static digitalinout_result_t digitalinout_proto_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_switch_to_input(self, pull); +} + +static digitalinout_result_t digitalinout_proto_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_switch_to_output(self, value, drive_mode); +} + +static digitalio_direction_t digitalinout_proto_get_direction(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_get_direction(self); +} + +static mp_errno_t digitalinout_proto_set_value(mp_obj_t self_in, bool value) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_digitalio_digitalinout_set_value(self, value); + return 0; +} + +static mp_errno_t digitalinout_proto_get_value(mp_obj_t self_in, bool *value) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + *value = common_hal_digitalio_digitalinout_get_value(self); + return 0; +} + +static digitalinout_result_t digitalinout_proto_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_set_drive_mode(self, drive_mode); +} + +static digitalio_drive_mode_t digitalinout_proto_get_drive_mode(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_get_drive_mode(self); +} + +static digitalinout_result_t digitalinout_proto_set_pull(mp_obj_t self_in, digitalio_pull_t pull) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_set_pull(self, pull); +} + +static digitalio_pull_t digitalinout_proto_get_pull(mp_obj_t self_in) { + digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_digitalio_digitalinout_get_pull(self); +} + +static const digitalinout_p_t digitalinout_digitalinout_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_digitalinout) + .deinit = digitalinout_proto_deinit, + .deinited = digitalinout_proto_deinited, + .switch_to_input = digitalinout_proto_switch_to_input, + .switch_to_output = digitalinout_proto_switch_to_output, + .get_direction = digitalinout_proto_get_direction, + .get_value = digitalinout_proto_get_value, + .set_value = digitalinout_proto_set_value, + .get_drive_mode = digitalinout_proto_get_drive_mode, + .set_drive_mode = digitalinout_proto_set_drive_mode, + .get_pull = digitalinout_proto_get_pull, + .set_pull = digitalinout_proto_set_pull, +}; + MP_DEFINE_CONST_OBJ_TYPE( digitalio_digitalinout_type, MP_QSTR_DigitalInOut, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, make_new, digitalio_digitalinout_make_new, - locals_dict, &digitalio_digitalinout_locals_dict + locals_dict, &digitalio_digitalinout_locals_dict, + protocol, &digitalinout_digitalinout_proto ); // Helper for validating digitalio.DigitalInOut arguments diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h index f030e27a60b..7465af3e288 100644 --- a/shared-bindings/digitalio/DigitalInOut.h +++ b/shared-bindings/digitalio/DigitalInOut.h @@ -28,6 +28,9 @@ typedef enum { #endif } digitalinout_result_t; +// Include protocol after types are defined +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" + typedef enum { DIGITALINOUT_REG_READ, DIGITALINOUT_REG_WRITE, diff --git a/shared-bindings/digitalio/DigitalInOutProtocol.c b/shared-bindings/digitalio/DigitalInOutProtocol.c new file mode 100644 index 00000000000..e0671a1b881 --- /dev/null +++ b/shared-bindings/digitalio/DigitalInOutProtocol.c @@ -0,0 +1,386 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" + +#include "py/obj.h" +#include "py/objtype.h" +#include "py/proto.h" +#include "py/runtime.h" +#include "py/nlr.h" +#include "py/gc.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/digitalio/Direction.h" +#include "shared-bindings/digitalio/DriveMode.h" +#include "shared-bindings/digitalio/Pull.h" +#include "shared-bindings/util.h" +#include "supervisor/port_heap.h" + +//| from typing import Protocol, Optional +//| +//| class DigitalInOutProtocol(Protocol): +//| """Protocol for digital input/output pin control. +//| +//| Any object that implements this protocol can be used as a digital pin, +//| providing compatibility with code expecting a `digitalio.DigitalInOut`. +//| """ +//| +//| def deinit(self) -> None: +//| """Deinitialize the pin and release hardware resources.""" +//| ... +//| +//| def deinited(self) -> bool: +//| """Check whether the pin has been deinitialized. +//| +//| :return: True if deinitialized, False otherwise +//| """ +//| ... +//| +//| def switch_to_input(self, pull: Optional[digitalio.Pull] = None) -> None: +//| """Configure the pin as a digital input. +//| +//| :param pull: Pull resistor configuration (UP, DOWN, or None) +//| """ +//| ... +//| +//| def switch_to_output( +//| self, +//| value: bool = False, +//| drive_mode: digitalio.DriveMode = digitalio.DriveMode.PUSH_PULL +//| ) -> None: +//| """Configure the pin as a digital output. +//| +//| :param value: Initial output value (default False) +//| :param drive_mode: Output drive mode (PUSH_PULL or OPEN_DRAIN) +//| """ +//| ... +//| +//| @property +//| def direction(self) -> digitalio.Direction: +//| """The pin direction (INPUT or OUTPUT).""" +//| ... +//| +//| @direction.setter +//| def direction(self, value: digitalio.Direction) -> None: +//| ... +//| +//| @property +//| def value(self) -> bool: +//| """The digital logic level of the pin.""" +//| ... +//| +//| @value.setter +//| def value(self, val: bool) -> None: +//| ... +//| +//| @property +//| def pull(self) -> Optional[digitalio.Pull]: +//| """The pull resistor configuration for inputs (UP, DOWN, or None).""" +//| ... +//| +//| @pull.setter +//| def pull(self, pul: Optional[digitalio.Pull]) -> None: +//| ... +//| +//| @property +//| def drive_mode(self) -> digitalio.DriveMode: +//| """The drive mode for outputs (PUSH_PULL or OPEN_DRAIN).""" +//| ... +//| +//| @drive_mode.setter +//| def drive_mode(self, mode: digitalio.DriveMode) -> None: +//| ... +//| +// C Implementation Notes: +// ----------------------- +// For C implementations, define a digitalinout_p_t protocol structure and assign it +// to your type's protocol field in MP_DEFINE_CONST_OBJ_TYPE. +// +// Example: +// static const digitalinout_p_t my_type_proto = { +// MP_PROTO_IMPLEMENT(MP_QSTR_protocol_digitalinout) +// .construct = my_construct_func, +// .deinit = my_deinit_func, +// .deinited = my_deinited_func, +// .switch_to_input = my_switch_to_input_func, +// .switch_to_output = my_switch_to_output_func, +// .get_direction = my_get_direction_func, +// .get_value = my_get_value_func, +// .set_value = my_set_value_func, +// .get_drive_mode = my_get_drive_mode_func, +// .set_drive_mode = my_set_drive_mode_func, +// .get_pull = my_get_pull_func, +// .set_pull = my_set_pull_func, +// }; +// +// MP_DEFINE_CONST_OBJ_TYPE( +// my_type, +// MP_QSTR_MyType, +// MP_TYPE_FLAG_NONE, +// make_new, my_make_new, +// protocol, &my_type_proto +// ); +// +// See shared-bindings/digitalio/DigitalInOut.c for a complete example. +// + + +static void check_object_has_method(mp_obj_t obj, qstr method_name) { + mp_obj_t dest[2]; + mp_load_method_protected(obj, method_name, dest, true); + if (dest[0] == MP_OBJ_NULL) { + mp_raise_TypeError_varg(MP_ERROR_TEXT("%q object missing '%q' method"), MP_OBJ_TO_PTR(obj), method_name); + } +} + +static void check_object_has_attr(mp_obj_t obj, qstr attr_name) { + mp_obj_t dest[2]; + mp_load_method_protected(obj, attr_name, dest, true); + if (dest[0] == MP_OBJ_NULL) { + mp_raise_TypeError_varg(MP_ERROR_TEXT("%q object missing '%q' attribute"), MP_OBJ_TO_PTR(obj), attr_name); + } +} + +mp_obj_t digitalinout_protocol_from_pin( + mp_obj_t pin_or_dio, + qstr arg_name, + bool allow_none, + bool use_port_allocation, + bool *out_owns_pin) { + + *out_owns_pin = false; + + // Handle None case + if (allow_none && pin_or_dio == mp_const_none) { + return mp_const_none; + } + + // Check if it's a Pin + if (mp_obj_is_type(pin_or_dio, &mcu_pin_type)) { + // Validate the pin is free + const mcu_pin_obj_t *pin; + if (allow_none) { + pin = validate_obj_is_free_pin_or_none(pin_or_dio, arg_name); + if (pin == NULL) { + return mp_const_none; + } + } else { + pin = validate_obj_is_free_pin(pin_or_dio, arg_name); + } + + // Allocate and construct a DigitalInOut object + // Use port_malloc if GC is not available or if forced + digitalio_digitalinout_obj_t *dio; + if (use_port_allocation) { + dio = port_malloc(sizeof(digitalio_digitalinout_obj_t), false); + } else { + dio = m_malloc(sizeof(digitalio_digitalinout_obj_t)); + } + dio->base.type = &digitalio_digitalinout_type; + mp_obj_t dio_obj = MP_OBJ_FROM_PTR(dio); + *out_owns_pin = true; + + digitalinout_result_t result = common_hal_digitalio_digitalinout_construct(dio_obj, pin); + if (result != DIGITALINOUT_OK) { + // Free the allocation on error + if (use_port_allocation) { + port_free(dio); + } + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q init failed"), arg_name); + } + return dio_obj; + } + + // Check if it natively implements the DigitalInOutProtocol + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, pin_or_dio); + if (proto != NULL) { + // Native protocol support - use it directly + return pin_or_dio; + } + + // Verify the object has the required methods/attributes + check_object_has_method(pin_or_dio, MP_QSTR_deinit); + check_object_has_method(pin_or_dio, MP_QSTR_switch_to_input); + check_object_has_method(pin_or_dio, MP_QSTR_switch_to_output); + check_object_has_attr(pin_or_dio, MP_QSTR_deinited); + check_object_has_attr(pin_or_dio, MP_QSTR_direction); + check_object_has_attr(pin_or_dio, MP_QSTR_value); + check_object_has_attr(pin_or_dio, MP_QSTR_drive_mode); + check_object_has_attr(pin_or_dio, MP_QSTR_pull); + + // Object has all required attributes - use it as DigitalInOutProtocol + return pin_or_dio; +} + +void digitalinout_protocol_deinit(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->deinit) { + proto->deinit(self); + return; + } + + // Fallback to Python method call + mp_obj_t dest[2]; + mp_load_method_maybe(self, MP_QSTR_deinit, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_call_method_n_kw(0, 0, dest); + return; + } +} + +bool digitalinout_protocol_deinited(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->deinited) { + return proto->deinited(self); + } + + // Try as attribute + mp_obj_t attr = mp_load_attr(self, MP_QSTR_deinited); + return mp_obj_is_true(attr); +} + +digitalinout_result_t digitalinout_protocol_switch_to_input(mp_obj_t self, digitalio_pull_t pull) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->switch_to_input) { + return proto->switch_to_input(self, pull); + } + + // Fallback to Python method call + mp_obj_t dest[3]; + mp_load_method_maybe(self, MP_QSTR_switch_to_input, dest); + if (dest[0] != MP_OBJ_NULL) { + mp_obj_t pull_obj = mp_const_none; + if (pull == PULL_UP) { + pull_obj = MP_OBJ_FROM_PTR(&digitalio_pull_up_obj); + } else if (pull == PULL_DOWN) { + pull_obj = MP_OBJ_FROM_PTR(&digitalio_pull_down_obj); + } + dest[2] = pull_obj; + mp_call_method_n_kw(1, 0, dest); + return DIGITALINOUT_OK; + } + + return DIGITALINOUT_PIN_BUSY; +} + +digitalinout_result_t digitalinout_protocol_switch_to_output(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->switch_to_output) { + return proto->switch_to_output(self, value, drive_mode); + } + + // Fallback to Python method call + mp_obj_t dest[4]; + mp_load_method_maybe(self, MP_QSTR_switch_to_output, dest); + if (dest[0] != MP_OBJ_NULL) { + dest[2] = mp_obj_new_bool(value); + dest[3] = (drive_mode == DRIVE_MODE_PUSH_PULL) ? + MP_OBJ_FROM_PTR(&digitalio_drive_mode_push_pull_obj) : + MP_OBJ_FROM_PTR(&digitalio_drive_mode_open_drain_obj); + mp_call_method_n_kw(2, 0, dest); + return DIGITALINOUT_OK; + } + + mp_raise_TypeError(MP_ERROR_TEXT("object does not support DigitalInOut protocol")); +} + +digitalio_direction_t digitalinout_protocol_get_direction(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->get_direction) { + return proto->get_direction(self); + } + + // Fallback to Python attribute access + mp_obj_t direction = mp_load_attr(self, MP_QSTR_direction); + if (direction == MP_ROM_PTR(&digitalio_direction_input_obj)) { + return DIRECTION_INPUT; + } + return DIRECTION_OUTPUT; +} + +mp_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->set_value) { + return proto->set_value(self, value); + } + + // Fallback to Python attribute assignment + mp_store_attr(self, MP_QSTR_value, mp_obj_new_bool(value)); + return 0; +} + +mp_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->get_value) { + return proto->get_value(self, value); + } + + // Fallback to Python attribute access + *value = mp_obj_is_true(mp_load_attr(self, MP_QSTR_value)); + return 0; +} + +digitalinout_result_t digitalinout_protocol_set_drive_mode(mp_obj_t self, digitalio_drive_mode_t drive_mode) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->set_drive_mode) { + return proto->set_drive_mode(self, drive_mode); + } + + // Fallback to Python attribute assignment + mp_obj_t drive_mode_obj = (drive_mode == DRIVE_MODE_PUSH_PULL) ? + MP_OBJ_FROM_PTR(&digitalio_drive_mode_push_pull_obj) : + MP_OBJ_FROM_PTR(&digitalio_drive_mode_open_drain_obj); + mp_store_attr(self, MP_QSTR_drive_mode, drive_mode_obj); + return DIGITALINOUT_OK; +} + +digitalio_drive_mode_t digitalinout_protocol_get_drive_mode(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->get_drive_mode) { + return proto->get_drive_mode(self); + } + + // Fallback to Python attribute access + mp_obj_t drive_mode = mp_load_attr(self, MP_QSTR_drive_mode); + if (drive_mode == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { + return DRIVE_MODE_OPEN_DRAIN; + } + return DRIVE_MODE_PUSH_PULL; +} + +digitalinout_result_t digitalinout_protocol_set_pull(mp_obj_t self, digitalio_pull_t pull) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->set_pull) { + return proto->set_pull(self, pull); + } + + // Fallback to Python attribute assignment + mp_obj_t pull_obj = mp_const_none; + if (pull == PULL_UP) { + pull_obj = MP_OBJ_FROM_PTR(&digitalio_pull_up_obj); + } else if (pull == PULL_DOWN) { + pull_obj = MP_OBJ_FROM_PTR(&digitalio_pull_down_obj); + } + mp_store_attr(self, MP_QSTR_pull, pull_obj); + return DIGITALINOUT_OK; +} + +digitalio_pull_t digitalinout_protocol_get_pull(mp_obj_t self) { + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + if (proto && proto->get_pull) { + return proto->get_pull(self); + } + + // Fallback to Python attribute access + mp_obj_t pull = mp_load_attr(self, MP_QSTR_pull); + if (pull == MP_OBJ_FROM_PTR(&digitalio_pull_up_obj)) { + return PULL_UP; + } else if (pull == MP_OBJ_FROM_PTR(&digitalio_pull_down_obj)) { + return PULL_DOWN; + } + return PULL_NONE; +} diff --git a/shared-bindings/digitalio/DigitalInOutProtocol.h b/shared-bindings/digitalio/DigitalInOutProtocol.h new file mode 100644 index 00000000000..5ec8bcb1855 --- /dev/null +++ b/shared-bindings/digitalio/DigitalInOutProtocol.h @@ -0,0 +1,67 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" +#include "py/proto.h" +#include "py/mperrno.h" +#include "shared-bindings/digitalio/Direction.h" +#include "shared-bindings/digitalio/DriveMode.h" +#include "shared-bindings/digitalio/Pull.h" + +// Protocol structure for DigitalInOut implementations +// Note: mcu_pin_obj_t and digitalinout_result_t are defined by files that include this header +typedef struct _digitalinout_p_t { + MP_PROTOCOL_HEAD // MP_QSTR_protocol_digitalinout + void (*deinit)(mp_obj_t self); + bool (*deinited)(mp_obj_t self); + digitalinout_result_t (*switch_to_input)(mp_obj_t self, digitalio_pull_t pull); + digitalinout_result_t (*switch_to_output)(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode); + digitalio_direction_t (*get_direction)(mp_obj_t self); + mp_errno_t (*set_value)(mp_obj_t self, bool value); // Return 0 if ok + mp_errno_t (*get_value)(mp_obj_t self, bool *value); // Return 0 if ok + digitalinout_result_t (*set_drive_mode)(mp_obj_t self, digitalio_drive_mode_t drive_mode); + digitalio_drive_mode_t (*get_drive_mode)(mp_obj_t self); + digitalinout_result_t (*set_pull)(mp_obj_t self, digitalio_pull_t pull); + digitalio_pull_t (*get_pull)(mp_obj_t self); +} digitalinout_p_t; + +// Protocol helper functions +// These functions work with any object that implements the DigitalInOut protocol, +// either through native C protocol or Python attributes/methods. + +// Converts a Pin or DigitalInOutProtocol to a DigitalInOutProtocol object. +// If pin_or_dio is a Pin, allocates and initializes a DigitalInOut object. +// If pin_or_dio is already a DigitalInOutProtocol, returns it directly. +// If allow_none is true and pin_or_dio is None, returns None. +// If force_port_allocation is true, uses port_malloc instead of GC allocation. +// Sets *out_owns_pin to true if a new DigitalInOut was allocated (caller must deinit and free). +// Returns the DigitalInOutProtocol object to use. +// Raises an exception on error. +// Note: To free allocated objects, deinit first, then use gc_ptr_on_heap() to determine +// if port_free() should be called (if not on heap) or let GC handle it (if on heap). +mp_obj_t digitalinout_protocol_from_pin( + mp_obj_t pin_or_dio, + qstr arg_name, + bool allow_none, + bool force_port_allocation, + bool *out_owns_pin); + +void digitalinout_protocol_deinit(mp_obj_t self); +bool digitalinout_protocol_deinited(mp_obj_t self); +digitalinout_result_t digitalinout_protocol_switch_to_input(mp_obj_t self, digitalio_pull_t pull); +digitalinout_result_t digitalinout_protocol_switch_to_output(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode); +digitalio_direction_t digitalinout_protocol_get_direction(mp_obj_t self); +mp_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value); +mp_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value); +digitalinout_result_t digitalinout_protocol_set_drive_mode(mp_obj_t self, digitalio_drive_mode_t drive_mode); +digitalio_drive_mode_t digitalinout_protocol_get_drive_mode(mp_obj_t self); +digitalinout_result_t digitalinout_protocol_set_pull(mp_obj_t self, digitalio_pull_t pull); +digitalio_pull_t digitalinout_protocol_get_pull(mp_obj_t self); diff --git a/shared-bindings/fourwire/FourWire.c b/shared-bindings/fourwire/FourWire.c index 083cf21a003..608645aaebf 100644 --- a/shared-bindings/fourwire/FourWire.c +++ b/shared-bindings/fourwire/FourWire.c @@ -30,9 +30,9 @@ //| self, //| spi_bus: busio.SPI, //| *, -//| command: Optional[microcontroller.Pin], -//| chip_select: Optional[microcontroller.Pin], -//| reset: Optional[microcontroller.Pin] = None, +//| command: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, +//| chip_select: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, +//| reset: Optional[Union[microcontroller.Pin, digitalio.DigitalInOutProtocol]] = None, //| baudrate: int = 24000000, //| polarity: int = 0, //| phase: int = 0, @@ -73,10 +73,6 @@ static mp_obj_t fourwire_fourwire_make_new(const mp_obj_type_t *type, size_t n_a mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const mcu_pin_obj_t *command = validate_obj_is_free_pin_or_none(args[ARG_command].u_obj, MP_QSTR_command); - const mcu_pin_obj_t *chip_select = validate_obj_is_free_pin_or_none(args[ARG_chip_select].u_obj, MP_QSTR_chip_select); - const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj, MP_QSTR_reset); - mp_obj_t spi = mp_arg_validate_type(args[ARG_spi_bus].u_obj, &busio_spi_type, MP_QSTR_spi_bus); fourwire_fourwire_obj_t *self = &allocate_display_bus_or_raise()->fourwire_bus; @@ -86,7 +82,7 @@ static mp_obj_t fourwire_fourwire_make_new(const mp_obj_type_t *type, size_t n_a uint8_t phase = (uint8_t)mp_arg_validate_int_range(args[ARG_phase].u_int, 0, 1, MP_QSTR_phase); common_hal_fourwire_fourwire_construct(self, - MP_OBJ_TO_PTR(spi), command, chip_select, reset, args[ARG_baudrate].u_int, polarity, phase); + MP_OBJ_TO_PTR(spi), args[ARG_command].u_obj, args[ARG_chip_select].u_obj, args[ARG_reset].u_obj, args[ARG_baudrate].u_int, polarity, phase); return self; } diff --git a/shared-bindings/fourwire/FourWire.h b/shared-bindings/fourwire/FourWire.h index 515a466b4b9..3e77c25434d 100644 --- a/shared-bindings/fourwire/FourWire.h +++ b/shared-bindings/fourwire/FourWire.h @@ -16,8 +16,8 @@ extern const mp_obj_type_t fourwire_fourwire_type; void common_hal_fourwire_fourwire_construct(fourwire_fourwire_obj_t *self, - busio_spi_obj_t *spi, const mcu_pin_obj_t *command, - const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *reset, uint32_t baudrate, + busio_spi_obj_t *spi, mp_obj_t command, + mp_obj_t chip_select, mp_obj_t reset, uint32_t baudrate, uint8_t polarity, uint8_t phase); void common_hal_fourwire_fourwire_deinit(fourwire_fourwire_obj_t *self); diff --git a/shared-bindings/i2cioexpander/IOExpander.c b/shared-bindings/i2cioexpander/IOExpander.c new file mode 100644 index 00000000000..09c404d289c --- /dev/null +++ b/shared-bindings/i2cioexpander/IOExpander.c @@ -0,0 +1,247 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-bindings/i2cioexpander/IOExpander.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/util.h" +#include "shared/runtime/context_manager_helpers.h" + +//| class IOExpander: +//| """Control a generic I2C-based GPIO expander +//| +//| IOExpander provides a simple interface to I2C-based GPIO expanders that +//| use basic register reads and writes for control. The expander provides +//| individual pins through the `pins` attribute that implement the +//| DigitalInOutProtocol. +//| """ +//| +//| def __init__( +//| self, +//| i2c: busio.I2C, +//| address: int, +//| num_pins: int, +//| set_value_reg: Optional[int] = None, +//| get_value_reg: Optional[int] = None, +//| set_direction_reg: Optional[int] = None, +//| ) -> None: +//| """Initialize an I2C GPIO expander +//| +//| :param busio.I2C i2c: The I2C bus the expander is connected to +//| :param int address: The I2C device address +//| :param int num_pins: The number of GPIO pins (8 or 16) +//| :param int set_value_reg: Register address to write pin values (optional) +//| :param int get_value_reg: Register address to read pin values (optional) +//| :param int set_direction_reg: Register address to set pin directions (optional) +//| """ +//| ... + +static mp_obj_t i2cioexpander_ioexpander_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_i2c, ARG_address, ARG_num_pins, ARG_set_value_reg, ARG_get_value_reg, ARG_set_direction_reg }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_address, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_num_pins, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_set_value_reg, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_get_value_reg, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_set_direction_reg, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Validate I2C object + mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c); + + // Validate address + int address = args[ARG_address].u_int; + if (address < 0 || address > 0x7F) { + mp_raise_ValueError(MP_ERROR_TEXT("address out of range")); + } + + // Validate num_pins + int num_pins = args[ARG_num_pins].u_int; + if (num_pins != 8 && num_pins != 16) { + mp_raise_ValueError(MP_ERROR_TEXT("num_pins must be 8 or 16")); + } + + i2cioexpander_ioexpander_obj_t *self = mp_obj_malloc(i2cioexpander_ioexpander_obj_t, &i2cioexpander_ioexpander_type); + + // Convert and validate register parameters + uint16_t set_value_reg = NO_REGISTER; + if (args[ARG_set_value_reg].u_obj != mp_const_none) { + mp_int_t reg = mp_obj_get_int(args[ARG_set_value_reg].u_obj); + mp_arg_validate_int_range(reg, 0, 255, MP_QSTR_set_value_reg); + set_value_reg = reg; + } + + uint16_t get_value_reg = NO_REGISTER; + if (args[ARG_get_value_reg].u_obj != mp_const_none) { + mp_int_t reg = mp_obj_get_int(args[ARG_get_value_reg].u_obj); + mp_arg_validate_int_range(reg, 0, 255, MP_QSTR_get_value_reg); + get_value_reg = reg; + } + + uint16_t set_direction_reg = NO_REGISTER; + if (args[ARG_set_direction_reg].u_obj != mp_const_none) { + mp_int_t reg = mp_obj_get_int(args[ARG_set_direction_reg].u_obj); + mp_arg_validate_int_range(reg, 0, 255, MP_QSTR_set_direction_reg); + set_direction_reg = reg; + } + + common_hal_i2cioexpander_ioexpander_construct( + self, + i2c, + address, + num_pins, + set_value_reg, + get_value_reg, + set_direction_reg); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialize the expander. No further operations are possible.""" +//| ... +static mp_obj_t i2cioexpander_ioexpander_deinit(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_i2cioexpander_ioexpander_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_deinit_obj, i2cioexpander_ioexpander_deinit); + +//| def __enter__(self) -> IOExpander: +//| """No-op used by Context Managers.""" +//| ... +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +static mp_obj_t i2cioexpander_ioexpander___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_i2cioexpander_ioexpander_deinit(MP_OBJ_TO_PTR(args[0])); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(i2cioexpander_ioexpander___exit___obj, 4, 4, i2cioexpander_ioexpander___exit__); + +//| @property +//| def input_value(self) -> int: +//| """Read the live value of all pins at once. Returns an integer where each +//| bit represents a pin's current state.""" +//| ... +static mp_obj_t i2cioexpander_ioexpander_obj_get_input_value(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t value; + if (!common_hal_i2cioexpander_ioexpander_get_input_value(self, &value)) { + mp_raise_OSError(MP_EIO); + } + return MP_OBJ_NEW_SMALL_INT(value); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_input_value_obj, i2cioexpander_ioexpander_obj_get_input_value); + +MP_PROPERTY_GETTER(i2cioexpander_ioexpander_input_value_obj, + (mp_obj_t)&i2cioexpander_ioexpander_get_input_value_obj); + +//| @property +//| def output_value(self) -> int: +//| """Get or set the cached output value. Reading returns the last value written, +//| not the live pin state. Writing updates the output pins.""" +//| ... +//| @output_value.setter +//| def output_value(self, val: int) -> None: ... +static mp_obj_t i2cioexpander_ioexpander_obj_get_output_value(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t value; + common_hal_i2cioexpander_ioexpander_get_output_value(self, &value); + return mp_obj_new_int(value); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_output_value_obj, i2cioexpander_ioexpander_obj_get_output_value); + +static mp_obj_t i2cioexpander_ioexpander_obj_set_output_value(mp_obj_t self_in, mp_obj_t value) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_errno_t result = common_hal_i2cioexpander_ioexpander_set_output_value(self, mp_obj_get_int(value)); + if (result != 0) { + mp_raise_OSError(result); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_ioexpander_set_output_value_obj, i2cioexpander_ioexpander_obj_set_output_value); + +MP_PROPERTY_GETSET(i2cioexpander_ioexpander_output_value_obj, + (mp_obj_t)&i2cioexpander_ioexpander_get_output_value_obj, + (mp_obj_t)&i2cioexpander_ioexpander_set_output_value_obj); + +//| @property +//| def output_mask(self) -> int: +//| """Get or set which pins are configured as outputs. Each bit in the mask +//| represents a pin: 1 for output, 0 for input.""" +//| ... +//| @output_mask.setter +//| def output_mask(self, val: int) -> None: ... +static mp_obj_t i2cioexpander_ioexpander_obj_get_output_mask(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t output_mask; + common_hal_i2cioexpander_ioexpander_get_output_mask(self, &output_mask); + return mp_obj_new_int(output_mask); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_output_mask_obj, i2cioexpander_ioexpander_obj_get_output_mask); + +static mp_obj_t i2cioexpander_ioexpander_obj_set_output_mask(mp_obj_t self_in, mp_obj_t value) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_errno_t result = common_hal_i2cioexpander_ioexpander_set_output_mask(self, mp_obj_get_int(value)); + if (result != 0) { + mp_raise_OSError(result); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_ioexpander_set_output_mask_obj, i2cioexpander_ioexpander_obj_set_output_mask); + +MP_PROPERTY_GETSET(i2cioexpander_ioexpander_output_mask_obj, + (mp_obj_t)&i2cioexpander_ioexpander_get_output_mask_obj, + (mp_obj_t)&i2cioexpander_ioexpander_set_output_mask_obj); + +//| @property +//| def pins(self) -> Tuple[DigitalInOutProtocol, ...]: +//| """A tuple of pin objects that implement the DigitalInOutProtocol. +//| Each pin can be used like a digitalio.DigitalInOut object.""" +//| ... +static mp_obj_t i2cioexpander_ioexpander_obj_get_pins(mp_obj_t self_in) { + i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_ioexpander_get_pins(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_pins_obj, i2cioexpander_ioexpander_obj_get_pins); + +MP_PROPERTY_GETTER(i2cioexpander_ioexpander_pins_obj, + (mp_obj_t)&i2cioexpander_ioexpander_get_pins_obj); + +static const mp_rom_map_elem_t i2cioexpander_ioexpander_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2cioexpander_ioexpander_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&i2cioexpander_ioexpander___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_input_value), MP_ROM_PTR(&i2cioexpander_ioexpander_input_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_output_value), MP_ROM_PTR(&i2cioexpander_ioexpander_output_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_output_mask), MP_ROM_PTR(&i2cioexpander_ioexpander_output_mask_obj) }, + { MP_ROM_QSTR(MP_QSTR_pins), MP_ROM_PTR(&i2cioexpander_ioexpander_pins_obj) }, +}; +static MP_DEFINE_CONST_DICT(i2cioexpander_ioexpander_locals_dict, i2cioexpander_ioexpander_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + i2cioexpander_ioexpander_type, + MP_QSTR_IOExpander, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, i2cioexpander_ioexpander_make_new, + locals_dict, &i2cioexpander_ioexpander_locals_dict + ); diff --git a/shared-bindings/i2cioexpander/IOExpander.h b/shared-bindings/i2cioexpander/IOExpander.h new file mode 100644 index 00000000000..64e49b60364 --- /dev/null +++ b/shared-bindings/i2cioexpander/IOExpander.h @@ -0,0 +1,34 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-module/i2cioexpander/IOExpander.h" + +extern const mp_obj_type_t i2cioexpander_ioexpander_type; + +void common_hal_i2cioexpander_ioexpander_construct( + i2cioexpander_ioexpander_obj_t *self, + mp_obj_t i2c, + uint8_t address, + uint8_t num_pins, + uint16_t set_value_reg, + uint16_t get_value_reg, + uint16_t set_direction_reg); + +void common_hal_i2cioexpander_ioexpander_deinit(i2cioexpander_ioexpander_obj_t *self); +bool common_hal_i2cioexpander_ioexpander_deinited(i2cioexpander_ioexpander_obj_t *self); + +mp_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioexpander_obj_t *self, size_t *value); +// No error return because this returns a cached value. +void common_hal_i2cioexpander_ioexpander_get_output_value(i2cioexpander_ioexpander_obj_t *self, size_t *value); +mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_ioexpander_obj_t *self, size_t value); + +void common_hal_i2cioexpander_ioexpander_get_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t *mask); +mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t mask); + +mp_obj_t common_hal_i2cioexpander_ioexpander_get_pins(i2cioexpander_ioexpander_obj_t *self); diff --git a/shared-bindings/i2cioexpander/IOPin.c b/shared-bindings/i2cioexpander/IOPin.c new file mode 100644 index 00000000000..3e43e18831f --- /dev/null +++ b/shared-bindings/i2cioexpander/IOPin.c @@ -0,0 +1,331 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/i2cioexpander/IOPin.h" +#include "shared-module/i2cioexpander/IOPin.h" + +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" +#include "shared-bindings/digitalio/Direction.h" +#include "shared-bindings/digitalio/DriveMode.h" +#include "shared-bindings/digitalio/Pull.h" +#include "shared-bindings/util.h" + +static void check_result(digitalinout_result_t result) { + switch (result) { + case DIGITALINOUT_OK: + return; + case DIGITALINOUT_PIN_BUSY: + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_Pin); + #if CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY + case DIGITALINOUT_INPUT_ONLY: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_direction); + #endif + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL + case DIGITALINOUT_INVALID_PULL: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_pull); + #endif + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE + case DIGITALINOUT_INVALID_DRIVE_MODE: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_drive_mode); + #endif + } +} + +static inline void check_for_deinit(i2cioexpander_iopin_obj_t *self) { + if (common_hal_i2cioexpander_iopin_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Turn off the pin and release it for other use.""" +//| ... +static mp_obj_t i2cioexpander_iopin_deinit(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_i2cioexpander_iopin_deinit(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_deinit_obj, i2cioexpander_iopin_deinit); + +//| def switch_to_output( +//| self, value: bool = False, drive_mode: digitalio.DriveMode = digitalio.DriveMode.PUSH_PULL +//| ) -> None: +//| """Set the drive mode and value and then switch to writing out digital values. +//| +//| :param bool value: default value to set upon switching +//| :param digitalio.DriveMode drive_mode: drive mode for the output""" +//| ... +static mp_obj_t i2cioexpander_iopin_switch_to_output(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_value, ARG_drive_mode }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_value, MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_drive_mode, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&digitalio_drive_mode_push_pull_obj)} }, + }; + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + digitalio_drive_mode_t drive_mode = DRIVE_MODE_PUSH_PULL; + if (args[ARG_drive_mode].u_rom_obj == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { + drive_mode = DRIVE_MODE_OPEN_DRAIN; + } + check_result(common_hal_i2cioexpander_iopin_switch_to_output(self, args[ARG_value].u_bool, drive_mode)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(i2cioexpander_iopin_switch_to_output_obj, 1, i2cioexpander_iopin_switch_to_output); + +//| def switch_to_input(self, pull: Optional[digitalio.Pull] = None) -> None: +//| """Set the pull and then switch to read in digital values. +//| +//| :param digitalio.Pull pull: pull configuration for the input""" +//| ... +static mp_obj_t i2cioexpander_iopin_switch_to_input(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_pull }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_pull, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + }; + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + check_result(common_hal_i2cioexpander_iopin_switch_to_input(self, validate_pull(args[ARG_pull].u_rom_obj, MP_QSTR_pull))); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(i2cioexpander_iopin_switch_to_input_obj, 1, i2cioexpander_iopin_switch_to_input); + +//| direction: digitalio.Direction +//| """The direction of the pin.""" +static mp_obj_t i2cioexpander_iopin_obj_get_direction(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + digitalio_direction_t direction = common_hal_i2cioexpander_iopin_get_direction(self); + if (direction == DIRECTION_INPUT) { + return MP_OBJ_FROM_PTR(&digitalio_direction_input_obj); + } + return MP_OBJ_FROM_PTR(&digitalio_direction_output_obj); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_get_direction_obj, i2cioexpander_iopin_obj_get_direction); + +static mp_obj_t i2cioexpander_iopin_obj_set_direction(mp_obj_t self_in, mp_obj_t value) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (value == MP_ROM_PTR(&digitalio_direction_input_obj)) { + check_result(common_hal_i2cioexpander_iopin_switch_to_input(self, PULL_NONE)); + } else if (value == MP_ROM_PTR(&digitalio_direction_output_obj)) { + check_result(common_hal_i2cioexpander_iopin_switch_to_output(self, false, DRIVE_MODE_PUSH_PULL)); + } else { + mp_arg_error_invalid(MP_QSTR_direction); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_iopin_set_direction_obj, i2cioexpander_iopin_obj_set_direction); + +MP_PROPERTY_GETSET(i2cioexpander_iopin_direction_obj, + (mp_obj_t)&i2cioexpander_iopin_get_direction_obj, + (mp_obj_t)&i2cioexpander_iopin_set_direction_obj); + +//| value: bool +//| """The digital logic level of the pin.""" +static mp_obj_t i2cioexpander_iopin_obj_get_value(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + bool value; + mp_errno_t res = common_hal_i2cioexpander_iopin_get_value(self, &value); + if (res != 0) { + mp_raise_OSError(-res); + } + return mp_obj_new_bool(value); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_get_value_obj, i2cioexpander_iopin_obj_get_value); + +static mp_obj_t i2cioexpander_iopin_obj_set_value(mp_obj_t self_in, mp_obj_t value) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_INPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Cannot set value when direction is input.")); + return mp_const_none; + } + mp_errno_t res = common_hal_i2cioexpander_iopin_set_value(self, mp_obj_is_true(value)); + if (res != 0) { + mp_raise_OSError(-res); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_iopin_set_value_obj, i2cioexpander_iopin_obj_set_value); + +MP_PROPERTY_GETSET(i2cioexpander_iopin_value_obj, + (mp_obj_t)&i2cioexpander_iopin_get_value_obj, + (mp_obj_t)&i2cioexpander_iopin_set_value_obj); + +//| drive_mode: digitalio.DriveMode +//| """The pin drive mode.""" +static mp_obj_t i2cioexpander_iopin_obj_get_drive_mode(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_INPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Drive mode not used when direction is input.")); + return mp_const_none; + } + digitalio_drive_mode_t drive_mode = common_hal_i2cioexpander_iopin_get_drive_mode(self); + if (drive_mode == DRIVE_MODE_PUSH_PULL) { + return MP_OBJ_FROM_PTR(&digitalio_drive_mode_push_pull_obj); + } + return MP_OBJ_FROM_PTR(&digitalio_drive_mode_open_drain_obj); +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_get_drive_mode_obj, i2cioexpander_iopin_obj_get_drive_mode); + +static mp_obj_t i2cioexpander_iopin_obj_set_drive_mode(mp_obj_t self_in, mp_obj_t drive_mode) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_INPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Drive mode not used when direction is input.")); + return mp_const_none; + } + digitalio_drive_mode_t c_drive_mode = DRIVE_MODE_PUSH_PULL; + if (drive_mode == MP_ROM_PTR(&digitalio_drive_mode_open_drain_obj)) { + c_drive_mode = DRIVE_MODE_OPEN_DRAIN; + } + check_result(common_hal_i2cioexpander_iopin_set_drive_mode(self, c_drive_mode)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_iopin_set_drive_mode_obj, i2cioexpander_iopin_obj_set_drive_mode); + +MP_PROPERTY_GETSET(i2cioexpander_iopin_drive_mode_obj, + (mp_obj_t)&i2cioexpander_iopin_get_drive_mode_obj, + (mp_obj_t)&i2cioexpander_iopin_set_drive_mode_obj); + +//| pull: Optional[digitalio.Pull] +//| """The pin pull direction.""" +static mp_obj_t i2cioexpander_iopin_obj_get_pull(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_OUTPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Pull not used when direction is output.")); + return mp_const_none; + } + digitalio_pull_t pull = common_hal_i2cioexpander_iopin_get_pull(self); + if (pull == PULL_UP) { + return MP_OBJ_FROM_PTR(&digitalio_pull_up_obj); + } else if (pull == PULL_DOWN) { + return MP_OBJ_FROM_PTR(&digitalio_pull_down_obj); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_get_pull_obj, i2cioexpander_iopin_obj_get_pull); + +static mp_obj_t i2cioexpander_iopin_obj_set_pull(mp_obj_t self_in, mp_obj_t pull_obj) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_i2cioexpander_iopin_get_direction(self) == DIRECTION_OUTPUT) { + mp_raise_AttributeError(MP_ERROR_TEXT("Pull not used when direction is output.")); + return mp_const_none; + } + check_result(common_hal_i2cioexpander_iopin_set_pull(self, validate_pull(pull_obj, MP_QSTR_pull))); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(i2cioexpander_iopin_set_pull_obj, i2cioexpander_iopin_obj_set_pull); + +MP_PROPERTY_GETSET(i2cioexpander_iopin_pull_obj, + (mp_obj_t)&i2cioexpander_iopin_get_pull_obj, + (mp_obj_t)&i2cioexpander_iopin_set_pull_obj); + +// Protocol implementation for DigitalInOutProtocol +static void iopin_protocol_deinit(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_i2cioexpander_iopin_deinit(self); +} + +static bool iopin_protocol_deinited(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_deinited(self); +} + +static digitalinout_result_t iopin_protocol_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_switch_to_input(self, pull); +} + +static digitalinout_result_t iopin_protocol_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_switch_to_output(self, value, drive_mode); +} + +static digitalio_direction_t iopin_protocol_get_direction(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_get_direction(self); +} + +static mp_errno_t iopin_protocol_get_value(mp_obj_t self_in, bool *value) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_get_value(self, value); +} + +static mp_errno_t iopin_protocol_set_value(mp_obj_t self_in, bool value) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_set_value(self, value); +} + +static digitalio_drive_mode_t iopin_protocol_get_drive_mode(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_get_drive_mode(self); +} + +static digitalinout_result_t iopin_protocol_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_set_drive_mode(self, drive_mode); +} + +static digitalio_pull_t iopin_protocol_get_pull(mp_obj_t self_in) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_get_pull(self); +} + +static digitalinout_result_t iopin_protocol_set_pull(mp_obj_t self_in, digitalio_pull_t pull) { + i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_i2cioexpander_iopin_set_pull(self, pull); +} + +static const digitalinout_p_t iopin_digitalinout_p = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_digitalinout) + .deinit = iopin_protocol_deinit, + .deinited = iopin_protocol_deinited, + .switch_to_input = iopin_protocol_switch_to_input, + .switch_to_output = iopin_protocol_switch_to_output, + .get_direction = iopin_protocol_get_direction, + .get_value = iopin_protocol_get_value, + .set_value = iopin_protocol_set_value, + .get_drive_mode = iopin_protocol_get_drive_mode, + .set_drive_mode = iopin_protocol_set_drive_mode, + .get_pull = iopin_protocol_get_pull, + .set_pull = iopin_protocol_set_pull, +}; + +static const mp_rom_map_elem_t i2cioexpander_iopin_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2cioexpander_iopin_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_switch_to_input), MP_ROM_PTR(&i2cioexpander_iopin_switch_to_input_obj) }, + { MP_ROM_QSTR(MP_QSTR_switch_to_output), MP_ROM_PTR(&i2cioexpander_iopin_switch_to_output_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_direction), MP_ROM_PTR(&i2cioexpander_iopin_direction_obj) }, + { MP_ROM_QSTR(MP_QSTR_value), MP_ROM_PTR(&i2cioexpander_iopin_value_obj) }, + { MP_ROM_QSTR(MP_QSTR_drive_mode), MP_ROM_PTR(&i2cioexpander_iopin_drive_mode_obj) }, + { MP_ROM_QSTR(MP_QSTR_pull), MP_ROM_PTR(&i2cioexpander_iopin_pull_obj) }, +}; +static MP_DEFINE_CONST_DICT(i2cioexpander_iopin_locals_dict, i2cioexpander_iopin_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + i2cioexpander_iopin_type, + MP_QSTR_IOPin, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + protocol, &iopin_digitalinout_p, + locals_dict, &i2cioexpander_iopin_locals_dict + ); diff --git a/shared-bindings/i2cioexpander/IOPin.h b/shared-bindings/i2cioexpander/IOPin.h new file mode 100644 index 00000000000..6a7d96130fa --- /dev/null +++ b/shared-bindings/i2cioexpander/IOPin.h @@ -0,0 +1,46 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-module/i2cioexpander/IOPin.h" + +extern const mp_obj_type_t i2cioexpander_iopin_type; + +mp_errno_t i2cioexpander_iopin_construct( + i2cioexpander_iopin_obj_t *self, + i2cioexpander_ioexpander_obj_t *expander, + uint8_t pin_number); + +void common_hal_i2cioexpander_iopin_deinit(i2cioexpander_iopin_obj_t *self); +bool common_hal_i2cioexpander_iopin_deinited(i2cioexpander_iopin_obj_t *self); + +digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_input( + i2cioexpander_iopin_obj_t *self, + digitalio_pull_t pull); + +digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_output( + i2cioexpander_iopin_obj_t *self, + bool value, + digitalio_drive_mode_t drive_mode); + +digitalio_direction_t common_hal_i2cioexpander_iopin_get_direction(i2cioexpander_iopin_obj_t *self); + +mp_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *self, bool value); +mp_errno_t common_hal_i2cioexpander_iopin_get_value(i2cioexpander_iopin_obj_t *self, bool *value); + +digitalinout_result_t common_hal_i2cioexpander_iopin_set_drive_mode( + i2cioexpander_iopin_obj_t *self, + digitalio_drive_mode_t drive_mode); + +digitalio_drive_mode_t common_hal_i2cioexpander_iopin_get_drive_mode(i2cioexpander_iopin_obj_t *self); + +digitalinout_result_t common_hal_i2cioexpander_iopin_set_pull( + i2cioexpander_iopin_obj_t *self, + digitalio_pull_t pull); + +digitalio_pull_t common_hal_i2cioexpander_iopin_get_pull(i2cioexpander_iopin_obj_t *self); diff --git a/shared-bindings/i2cioexpander/__init__.c b/shared-bindings/i2cioexpander/__init__.c new file mode 100644 index 00000000000..106c45c3768 --- /dev/null +++ b/shared-bindings/i2cioexpander/__init__.c @@ -0,0 +1,49 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/i2cioexpander/__init__.h" +#include "shared-bindings/i2cioexpander/IOExpander.h" + +//| """Support for I2C-based GPIO expanders +//| +//| The `i2cioexpander` module contains classes to support I2C-based GPIO expanders +//| that can be controlled via simple register reads and writes. +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed if the program continues after use. To do so, either +//| call :py:meth:`!deinit` or use a context manager. See +//| :ref:`lifetime-and-contextmanagers` for more info. +//| +//| Example:: +//| +//| import board +//| import busio +//| import i2cioexpander +//| +//| i2c = busio.I2C(board.SCL, board.SDA) +//| expander = i2cioexpander.IOExpander(i2c, 0x20, 8, 0x01, 0x00, 0x03) +//| pin0 = expander.pins[0] +//| pin0.switch_to_output(value=True) +//| """ + +static const mp_rom_map_elem_t i2cioexpander_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_i2cioexpander) }, + { MP_ROM_QSTR(MP_QSTR_IOExpander), MP_ROM_PTR(&i2cioexpander_ioexpander_type) }, +}; + +static MP_DEFINE_CONST_DICT(i2cioexpander_module_globals, i2cioexpander_module_globals_table); + +const mp_obj_module_t i2cioexpander_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&i2cioexpander_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_i2cioexpander, i2cioexpander_module); diff --git a/shared-bindings/i2cioexpander/__init__.h b/shared-bindings/i2cioexpander/__init__.h new file mode 100644 index 00000000000..e0d06686868 --- /dev/null +++ b/shared-bindings/i2cioexpander/__init__.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Nothing now. diff --git a/shared-bindings/sdcardio/SDCard.h b/shared-bindings/sdcardio/SDCard.h index 95998f5af5e..ae364357707 100644 --- a/shared-bindings/sdcardio/SDCard.h +++ b/shared-bindings/sdcardio/SDCard.h @@ -7,6 +7,7 @@ #pragma once +#include "py/mperrno.h" #include "shared-module/sdcardio/SDCard.h" extern const mp_obj_type_t sdcardio_SDCard_type; @@ -17,9 +18,9 @@ bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_mark_deinit(sdcardio_sdcard_obj_t *self); int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); -int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); -int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self); -int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); +mp_errno_t common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); +mp_errno_t common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self); +mp_errno_t common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); // Used by native vfs blockdev. mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); diff --git a/shared-bindings/sdioio/SDCard.h b/shared-bindings/sdioio/SDCard.h index dfeaf8fca89..446ff3dfd76 100644 --- a/shared-bindings/sdioio/SDCard.h +++ b/shared-bindings/sdioio/SDCard.h @@ -7,6 +7,7 @@ #pragma once #include "py/obj.h" +#include "py/mperrno.h" #include "common-hal/microcontroller/Pin.h" #include "common-hal/sdioio/SDCard.h" @@ -35,9 +36,14 @@ uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t *self); // Return number of device blocks uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t *self); -// Read or write blocks -int common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); -int common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); +// Read or write blocks - returns 0 on success or negative error code from mperrno.h +mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); +mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); + +// Used by native vfs blockdev. +mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); +mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *out_value); // This is used by the supervisor to claim SDIO devices indefinitely. extern void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self); diff --git a/shared-bindings/socketpool/Socket.h b/shared-bindings/socketpool/Socket.h index a883ebd5054..295f86e7371 100644 --- a/shared-bindings/socketpool/Socket.h +++ b/shared-bindings/socketpool/Socket.h @@ -6,6 +6,7 @@ #pragma once +#include "py/mperrno.h" #include "common-hal/socketpool/Socket.h" extern const mp_obj_type_t socketpool_socket_type; diff --git a/shared-module/bitbangio/I2C.c b/shared-module/bitbangio/I2C.c index 0089bdc1e1e..8e27298af7c 100644 --- a/shared-module/bitbangio/I2C.c +++ b/shared-module/bitbangio/I2C.c @@ -8,10 +8,15 @@ #include "py/mperrno.h" #include "py/obj.h" #include "py/runtime.h" +#include "py/gc.h" #include "common-hal/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" static void delay(bitbangio_i2c_obj_t *self) { // We need to use an accurate delay to get acceptable I2C @@ -19,61 +24,81 @@ static void delay(bitbangio_i2c_obj_t *self) { common_hal_mcu_delay_us(self->us_delay); } -static void scl_low(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_set_value(&self->scl, false); +static bool scl_low(bitbangio_i2c_obj_t *self) { + return digitalinout_protocol_set_value(self->scl, false) == 0; } -static void scl_release(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_set_value(&self->scl, true); +static bool scl_release(bitbangio_i2c_obj_t *self) { + if (digitalinout_protocol_set_value(self->scl, true) != 0) { + return false; + } uint32_t count = self->us_timeout; delay(self); // For clock stretching, wait for the SCL pin to be released, with timeout. - common_hal_digitalio_digitalinout_switch_to_input(&self->scl, PULL_UP); - for (; !common_hal_digitalio_digitalinout_get_value(&self->scl) && count; --count) { + digitalinout_protocol_switch_to_input(self->scl, PULL_UP); + bool value; + for (; count; --count) { + if (digitalinout_protocol_get_value(self->scl, &value) != 0) { + return false; + } + if (value) { + break; + } common_hal_mcu_delay_us(1); } - common_hal_digitalio_digitalinout_switch_to_output(&self->scl, true, DRIVE_MODE_OPEN_DRAIN); + digitalinout_protocol_switch_to_output(self->scl, true, DRIVE_MODE_OPEN_DRAIN); // raise exception on timeout if (count == 0) { mp_raise_msg_varg(&mp_type_TimeoutError, MP_ERROR_TEXT("%q too long"), MP_QSTR_timeout); } + return true; } -static void sda_low(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_set_value(&self->sda, false); +static bool sda_low(bitbangio_i2c_obj_t *self) { + return digitalinout_protocol_set_value(self->sda, false) == 0; } -static void sda_release(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_set_value(&self->sda, true); +static bool sda_release(bitbangio_i2c_obj_t *self) { + return digitalinout_protocol_set_value(self->sda, true) == 0; } -static bool sda_read(bitbangio_i2c_obj_t *self) { - common_hal_digitalio_digitalinout_switch_to_input(&self->sda, PULL_UP); - bool value = common_hal_digitalio_digitalinout_get_value(&self->sda); - common_hal_digitalio_digitalinout_switch_to_output(&self->sda, true, DRIVE_MODE_OPEN_DRAIN); - return value; +static bool sda_read(bitbangio_i2c_obj_t *self, bool *value) { + digitalinout_protocol_switch_to_input(self->sda, PULL_UP); + if (digitalinout_protocol_get_value(self->sda, value) != 0) { + return false; + } + digitalinout_protocol_switch_to_output(self->sda, true, DRIVE_MODE_OPEN_DRAIN); + return true; } -static void start(bitbangio_i2c_obj_t *self) { - sda_release(self); +static bool start(bitbangio_i2c_obj_t *self) { + if (!sda_release(self)) { + return false; + } delay(self); scl_release(self); sda_low(self); delay(self); + return true; } -static void stop(bitbangio_i2c_obj_t *self) { +static bool stop(bitbangio_i2c_obj_t *self) { delay(self); - sda_low(self); + if (!sda_low(self)) { + return false; + } delay(self); scl_release(self); sda_release(self); delay(self); + return true; } static int write_byte(bitbangio_i2c_obj_t *self, uint8_t val) { delay(self); - scl_low(self); + if (!scl_low(self)) { + return -1; + } for (int i = 7; i >= 0; i--) { if ((val >> i) & 1) { @@ -90,7 +115,10 @@ static int write_byte(bitbangio_i2c_obj_t *self, uint8_t val) { delay(self); scl_release(self); - int ret = sda_read(self); + bool ret; + if (!sda_read(self, &ret)) { + return -1; + } delay(self); scl_low(self); @@ -99,13 +127,17 @@ static int write_byte(bitbangio_i2c_obj_t *self, uint8_t val) { static bool read_byte(bitbangio_i2c_obj_t *self, uint8_t *val, bool ack) { delay(self); - scl_low(self); + if (!scl_low(self)) { + return false; + } delay(self); uint8_t data = 0; for (int i = 7; i >= 0; i--) { scl_release(self); - data = (data << 1) | sda_read(self); + bool bit; + sda_read(self, &bit); + data = (data << 1) | bit; scl_low(self); delay(self); } @@ -124,8 +156,8 @@ static bool read_byte(bitbangio_i2c_obj_t *self, uint8_t *val, bool ack) { } void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, - const mcu_pin_obj_t *scl, - const mcu_pin_obj_t *sda, + mp_obj_t scl, + mp_obj_t sda, uint32_t frequency, uint32_t us_timeout) { @@ -134,32 +166,39 @@ void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, if (self->us_delay == 0) { self->us_delay = 1; } - digitalinout_result_t result = common_hal_digitalio_digitalinout_construct(&self->scl, scl); - if (result != DIGITALINOUT_OK) { - return; - } - result = common_hal_digitalio_digitalinout_construct(&self->sda, sda); - if (result != DIGITALINOUT_OK) { - common_hal_digitalio_digitalinout_deinit(&self->scl); - return; - } - common_hal_digitalio_digitalinout_switch_to_output(&self->scl, true, DRIVE_MODE_OPEN_DRAIN); - common_hal_digitalio_digitalinout_switch_to_output(&self->sda, true, DRIVE_MODE_OPEN_DRAIN); - stop(self); + // Convert scl from Pin to DigitalInOutProtocol + self->scl = digitalinout_protocol_from_pin(scl, MP_QSTR_scl, false, false, &self->own_scl); + + // Convert sda from Pin to DigitalInOutProtocol + self->sda = digitalinout_protocol_from_pin(sda, MP_QSTR_sda, false, false, &self->own_sda); + + digitalinout_protocol_switch_to_output(self->scl, true, DRIVE_MODE_OPEN_DRAIN); + digitalinout_protocol_switch_to_output(self->sda, true, DRIVE_MODE_OPEN_DRAIN); + + if (!stop(self)) { + mp_raise_OSError(MP_EIO); + } } bool shared_module_bitbangio_i2c_deinited(bitbangio_i2c_obj_t *self) { // If one is deinited, both will be. - return common_hal_digitalio_digitalinout_deinited(&self->scl); + return digitalinout_protocol_deinited(self->scl); } void shared_module_bitbangio_i2c_deinit(bitbangio_i2c_obj_t *self) { if (shared_module_bitbangio_i2c_deinited(self)) { return; } - common_hal_digitalio_digitalinout_deinit(&self->scl); - common_hal_digitalio_digitalinout_deinit(&self->sda); + // Only deinit and free the pins if we own them + if (self->own_scl) { + digitalinout_protocol_deinit(self->scl); + circuitpy_free_obj(self->scl); + } + if (self->own_sda) { + digitalinout_protocol_deinit(self->sda); + circuitpy_free_obj(self->sda); + } } bool shared_module_bitbangio_i2c_try_lock(bitbangio_i2c_obj_t *self) { @@ -182,18 +221,28 @@ void shared_module_bitbangio_i2c_unlock(bitbangio_i2c_obj_t *self) { } bool shared_module_bitbangio_i2c_probe(bitbangio_i2c_obj_t *self, uint8_t addr) { - start(self); - bool ok = write_byte(self, addr << 1); + if (!start(self)) { + mp_raise_OSError(MP_EIO); + } + int result = write_byte(self, addr << 1); stop(self); - return ok; + if (result < 0) { + mp_raise_OSError(MP_EIO); + } + return result; } uint8_t shared_module_bitbangio_i2c_write(bitbangio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { // start the I2C transaction - start(self); + if (!start(self)) { + return MP_EIO; + } uint8_t status = 0; - if (!write_byte(self, addr << 1)) { + int result = write_byte(self, addr << 1); + if (result < 0) { + status = MP_EIO; + } else if (!result) { status = MP_ENODEV; } @@ -215,7 +264,9 @@ uint8_t shared_module_bitbangio_i2c_write(bitbangio_i2c_obj_t *self, uint16_t ad uint8_t shared_module_bitbangio_i2c_read(bitbangio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { // start the I2C transaction - start(self); + if (!start(self)) { + return MP_EIO; + } uint8_t status = 0; if (!write_byte(self, (addr << 1) | 1)) { status = MP_ENODEV; diff --git a/shared-module/bitbangio/I2C.h b/shared-module/bitbangio/I2C.h index 3908a3dd374..0cec9186e9b 100644 --- a/shared-module/bitbangio/I2C.h +++ b/shared-module/bitbangio/I2C.h @@ -12,9 +12,11 @@ typedef struct { mp_obj_base_t base; - digitalio_digitalinout_obj_t scl; - digitalio_digitalinout_obj_t sda; + mp_obj_t scl; + mp_obj_t sda; uint32_t us_delay; uint32_t us_timeout; volatile bool locked; + bool own_scl; + bool own_sda; } bitbangio_i2c_obj_t; diff --git a/shared-module/bitbangio/SPI.c b/shared-module/bitbangio/SPI.c index 56e978985ed..b891d22c9aa 100644 --- a/shared-module/bitbangio/SPI.c +++ b/shared-module/bitbangio/SPI.c @@ -7,64 +7,63 @@ #include "py/mpconfig.h" #include "py/obj.h" #include "py/runtime.h" +#include "py/gc.h" #include "common-hal/microcontroller/Pin.h" #include "shared-bindings/bitbangio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" #include "shared-bindings/microcontroller/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "supervisor/port.h" #define MAX_BAUDRATE (common_hal_mcu_get_clock_frequency() / 48) void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self, - const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *miso) { - digitalinout_result_t result = common_hal_digitalio_digitalinout_construct(&self->clock, clock); - if (result != DIGITALINOUT_OK) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_clock); - } - common_hal_digitalio_digitalinout_switch_to_output(&self->clock, self->polarity == 1, DRIVE_MODE_PUSH_PULL); + mp_obj_t clock, mp_obj_t mosi, mp_obj_t miso) { - if (mosi != NULL) { - result = common_hal_digitalio_digitalinout_construct(&self->mosi, mosi); - if (result != DIGITALINOUT_OK) { - common_hal_digitalio_digitalinout_deinit(&self->clock); - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_mosi); - } - self->has_mosi = true; - common_hal_digitalio_digitalinout_switch_to_output(&self->mosi, false, DRIVE_MODE_PUSH_PULL); - } + // Convert clock from Pin to DigitalInOutProtocol + self->clock = digitalinout_protocol_from_pin(clock, MP_QSTR_clock, false, false, &self->own_clock); + digitalinout_protocol_switch_to_output(self->clock, self->polarity == 1, DRIVE_MODE_PUSH_PULL); - if (miso != NULL) { - // Starts out as input by default, no need to change. - result = common_hal_digitalio_digitalinout_construct(&self->miso, miso); - if (result != DIGITALINOUT_OK) { - common_hal_digitalio_digitalinout_deinit(&self->clock); - if (mosi != NULL) { - common_hal_digitalio_digitalinout_deinit(&self->mosi); - } - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_miso); - } - self->has_miso = true; + // Convert mosi from Pin to DigitalInOutProtocol (optional) + self->mosi = digitalinout_protocol_from_pin(mosi, MP_QSTR_mosi, true, false, &self->own_mosi); + self->has_mosi = (self->mosi != mp_const_none); + if (self->has_mosi) { + digitalinout_protocol_switch_to_output(self->mosi, false, DRIVE_MODE_PUSH_PULL); } + + // Convert miso from Pin to DigitalInOutProtocol (optional) + self->miso = digitalinout_protocol_from_pin(miso, MP_QSTR_miso, true, false, &self->own_miso); + self->has_miso = (self->miso != mp_const_none); + // MISO starts out as input by default, no need to change + self->delay_half = 5; self->polarity = 0; self->phase = 0; } bool shared_module_bitbangio_spi_deinited(bitbangio_spi_obj_t *self) { - return common_hal_digitalio_digitalinout_deinited(&self->clock); + return digitalinout_protocol_deinited(self->clock); } void shared_module_bitbangio_spi_deinit(bitbangio_spi_obj_t *self) { if (shared_module_bitbangio_spi_deinited(self)) { return; } - common_hal_digitalio_digitalinout_deinit(&self->clock); - if (self->has_mosi) { - common_hal_digitalio_digitalinout_deinit(&self->mosi); + // Only deinit and free the pins if we own them + if (self->own_clock) { + digitalinout_protocol_deinit(self->clock); + circuitpy_free_obj(self->clock); + } + if (self->has_mosi && self->own_mosi) { + digitalinout_protocol_deinit(self->mosi); + circuitpy_free_obj(self->mosi); } - if (self->has_miso) { - common_hal_digitalio_digitalinout_deinit(&self->miso); + if (self->has_miso && self->own_miso) { + digitalinout_protocol_deinit(self->miso); + circuitpy_free_obj(self->miso); } } @@ -80,7 +79,7 @@ void shared_module_bitbangio_spi_configure(bitbangio_spi_obj_t *self, // If the polarity has changed, make sure we re-initialize the idle state // of the clock as well. self->polarity = polarity; - common_hal_digitalio_digitalinout_switch_to_output(&self->clock, polarity == 1, DRIVE_MODE_PUSH_PULL); + digitalinout_protocol_switch_to_output(self->clock, polarity == 1, DRIVE_MODE_PUSH_PULL); } self->phase = phase; } @@ -121,9 +120,15 @@ bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t for (size_t i = 0; i < len; ++i) { uint8_t data_out = data[i]; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + if (i == 0 && j == 0) { + if (digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1) != 0) { + return false; + } + } else { + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); + } + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); } if (dest != NULL) { dest[i] = data_in; @@ -136,16 +141,22 @@ bool shared_module_bitbangio_spi_write(bitbangio_spi_obj_t *self, const uint8_t for (size_t i = 0; i < len; ++i) { uint8_t data_out = data[i]; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); + if (i == 0 && j == 0) { + if (!digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1)) { + return false; + } + } else { + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); + } if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); common_hal_mcu_delay_us(delay_half); } } @@ -176,14 +187,18 @@ bool shared_module_bitbangio_spi_read(bitbangio_spi_obj_t *self, uint8_t *data, if (delay_half <= MICROPY_PY_MACHINE_SPI_MIN_DELAY) { // Clock out zeroes while we read. if (self->has_mosi) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, false); + if (digitalinout_protocol_set_value(self->mosi, false) != 0) { + return false; + } } for (size_t i = 0; i < len; ++i) { uint8_t data_in = 0; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); - data_in = (data_in << 1) | common_hal_digitalio_digitalinout_get_value(&self->miso); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); + bool bit; + digitalinout_protocol_get_value(self->miso, &bit); + data_in = (data_in << 1) | bit; + digitalinout_protocol_set_value(self->clock, self->polarity); } data[i] = data_in; } @@ -191,28 +206,32 @@ bool shared_module_bitbangio_spi_read(bitbangio_spi_obj_t *self, uint8_t *data, } #endif if (self->has_mosi) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, false); + if (!digitalinout_protocol_set_value(self->mosi, false)) { + return false; + } } for (size_t i = 0; i < len; ++i) { uint8_t data_out = write_data; uint8_t data_in = 0; for (int j = 0; j < 8; ++j, data_out <<= 1) { if (self->has_mosi) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); } if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); common_hal_mcu_delay_us(delay_half); } - data_in = (data_in << 1) | common_hal_digitalio_digitalinout_get_value(&self->miso); + bool bit; + digitalinout_protocol_get_value(self->miso, &bit); + data_in = (data_in << 1) | bit; if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); common_hal_mcu_delay_us(delay_half); } } @@ -248,10 +267,18 @@ bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self, const uint8 uint8_t data_out = dout[i]; uint8_t data_in = 0; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); - data_in = (data_in << 1) | common_hal_digitalio_digitalinout_get_value(&self->miso); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + if (i == 0 && j == 0) { + if (digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1) != 0) { + return false; + } + } else { + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); + } + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); + bool bit; + digitalinout_protocol_get_value(self->miso, &bit); + data_in = (data_in << 1) | bit; + digitalinout_protocol_set_value(self->clock, self->polarity); } din[i] = data_in; @@ -267,20 +294,28 @@ bool shared_module_bitbangio_spi_transfer(bitbangio_spi_obj_t *self, const uint8 uint8_t data_out = dout[i]; uint8_t data_in = 0; for (int j = 0; j < 8; ++j, data_out <<= 1) { - common_hal_digitalio_digitalinout_set_value(&self->mosi, (data_out >> 7) & 1); + if (i == 0 && j == 0) { + if (!digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1)) { + return false; + } + } else { + digitalinout_protocol_set_value(self->mosi, (data_out >> 7) & 1); + } if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, 1 - self->polarity); + digitalinout_protocol_set_value(self->clock, 1 - self->polarity); common_hal_mcu_delay_us(delay_half); } - data_in = (data_in << 1) | common_hal_digitalio_digitalinout_get_value(&self->miso); + bool bit; + digitalinout_protocol_get_value(self->miso, &bit); + data_in = (data_in << 1) | bit; if (self->phase == 0) { common_hal_mcu_delay_us(delay_half); - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); } else { - common_hal_digitalio_digitalinout_set_value(&self->clock, self->polarity); + digitalinout_protocol_set_value(self->clock, self->polarity); common_hal_mcu_delay_us(delay_half); } } diff --git a/shared-module/bitbangio/SPI.h b/shared-module/bitbangio/SPI.h index c19170af7c4..5f3c109b7f6 100644 --- a/shared-module/bitbangio/SPI.h +++ b/shared-module/bitbangio/SPI.h @@ -12,13 +12,16 @@ typedef struct { mp_obj_base_t base; - digitalio_digitalinout_obj_t clock; - digitalio_digitalinout_obj_t mosi; - digitalio_digitalinout_obj_t miso; + mp_obj_t clock; + mp_obj_t mosi; + mp_obj_t miso; uint32_t delay_half; bool has_miso : 1; bool has_mosi : 1; uint8_t polarity : 1; uint8_t phase : 1; volatile bool locked : 1; + bool own_clock; + bool own_mosi; + bool own_miso; } bitbangio_spi_obj_t; diff --git a/shared-module/board/__init__.c b/shared-module/board/__init__.c index a9c0e9a6c80..6bfc0bbf0f1 100644 --- a/shared-module/board/__init__.c +++ b/shared-module/board/__init__.c @@ -156,6 +156,10 @@ void reset_board_buses(void) { } } #endif + #if CIRCUITPY_I2CIOEXPANDER + // Assume the native I2C bus is used for IO Expander pins. + display_using_i2c = true; + #endif if (i2c_obj_created[instance]) { // make sure I2C lock is not held over a soft reset common_hal_busio_i2c_unlock(&i2c_obj[instance]); diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index ac57f3bf3e0..a4652324c1e 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -80,7 +80,7 @@ void common_hal_busdisplay_busdisplay_construct(busdisplay_busdisplay_obj_t *sel memcpy(full_command + 1, data, data_size); self->bus.send(self->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, full_command, data_size + 1); } else { - self->bus.send(self->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, cmd, 1); + self->bus.send(self->bus.bus, DISPLAY_COMMAND, data_size > 0 ? CHIP_SELECT_TOGGLE_EVERY_BYTE : CHIP_SELECT_UNTOUCHED, cmd, 1); self->bus.send(self->bus.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, data_size); } displayio_display_bus_end_transaction(&self->bus); diff --git a/shared-module/fourwire/FourWire.c b/shared-module/fourwire/FourWire.c index 0a168fa1563..0266401f9ce 100644 --- a/shared-module/fourwire/FourWire.c +++ b/shared-module/fourwire/FourWire.c @@ -11,13 +11,15 @@ #include "py/gc.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/digitalio/DigitalInOutProtocol.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" +#include "supervisor/port.h" void common_hal_fourwire_fourwire_construct(fourwire_fourwire_obj_t *self, - busio_spi_obj_t *spi, const mcu_pin_obj_t *command, - const mcu_pin_obj_t *chip_select, const mcu_pin_obj_t *reset, uint32_t baudrate, + busio_spi_obj_t *spi, mp_obj_t command, + mp_obj_t chip_select, mp_obj_t reset, uint32_t baudrate, uint8_t polarity, uint8_t phase) { self->bus = spi; @@ -27,31 +29,24 @@ void common_hal_fourwire_fourwire_construct(fourwire_fourwire_obj_t *self, self->polarity = polarity; self->phase = phase; - - self->command.base.type = &mp_type_NoneType; - if (command != NULL) { - self->command.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->command, command); - common_hal_digitalio_digitalinout_switch_to_output(&self->command, true, DRIVE_MODE_PUSH_PULL); + self->command = digitalinout_protocol_from_pin(command, MP_QSTR_command, true, false, &self->own_command); + if (self->command != mp_const_none) { + digitalinout_protocol_switch_to_output(self->command, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(command); } - self->reset.base.type = &mp_type_NoneType; - if (reset != NULL) { - self->reset.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->reset, reset); - common_hal_digitalio_digitalinout_switch_to_output(&self->reset, true, DRIVE_MODE_PUSH_PULL); + + self->reset = digitalinout_protocol_from_pin(reset, MP_QSTR_reset, true, false, &self->own_reset); + if (self->reset != mp_const_none) { + digitalinout_protocol_switch_to_output(self->reset, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(reset); common_hal_fourwire_fourwire_reset(self); } - self->chip_select.base.type = &mp_type_NoneType; - if (chip_select != NULL) { - self->chip_select.base.type = &digitalio_digitalinout_type; - common_hal_digitalio_digitalinout_construct(&self->chip_select, chip_select); - common_hal_digitalio_digitalinout_switch_to_output(&self->chip_select, true, DRIVE_MODE_PUSH_PULL); + self->chip_select = digitalinout_protocol_from_pin(chip_select, MP_QSTR_chip_select, true, false, &self->own_chip_select); + if (self->chip_select != mp_const_none) { + digitalinout_protocol_switch_to_output(self->chip_select, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(chip_select); } - } void common_hal_fourwire_fourwire_deinit(fourwire_fourwire_obj_t *self) { @@ -59,19 +54,33 @@ void common_hal_fourwire_fourwire_deinit(fourwire_fourwire_obj_t *self) { common_hal_busio_spi_deinit(self->bus); } - common_hal_reset_pin(self->command.pin); - common_hal_reset_pin(self->chip_select.pin); - common_hal_reset_pin(self->reset.pin); + // Only deinit and free the pins if we own them + if (self->command != mp_const_none && self->own_command) { + digitalinout_protocol_deinit(self->command); + circuitpy_free_obj(self->command); + } + if (self->chip_select != mp_const_none && self->own_chip_select) { + digitalinout_protocol_deinit(self->chip_select); + circuitpy_free_obj(self->chip_select); + } + if (self->reset != mp_const_none && self->own_reset) { + digitalinout_protocol_deinit(self->reset); + circuitpy_free_obj(self->reset); + } } bool common_hal_fourwire_fourwire_reset(mp_obj_t obj) { fourwire_fourwire_obj_t *self = MP_OBJ_TO_PTR(obj); - if (self->reset.base.type == &mp_type_NoneType) { + if (self->reset == mp_const_none) { + return false; + } + if (digitalinout_protocol_set_value(self->reset, false) != 0) { return false; } - common_hal_digitalio_digitalinout_set_value(&self->reset, false); common_hal_mcu_delay_us(1000); - common_hal_digitalio_digitalinout_set_value(&self->reset, true); + if (digitalinout_protocol_set_value(self->reset, true) != 0) { + return false; + } common_hal_mcu_delay_us(1000); return true; } @@ -92,16 +101,23 @@ bool common_hal_fourwire_fourwire_begin_transaction(mp_obj_t obj) { } common_hal_busio_spi_configure(self->bus, self->frequency, self->polarity, self->phase, 8); - if (self->chip_select.base.type != &mp_type_NoneType) { - common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + if (self->chip_select != mp_const_none) { + // IO Expander CS can fail due to an I2C lock. + if (digitalinout_protocol_set_value(self->chip_select, false) != 0) { + common_hal_busio_spi_unlock(self->bus); + return false; + } } return true; } void common_hal_fourwire_fourwire_send(mp_obj_t obj, display_byte_type_t data_type, display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length) { + if (data_length == 0) { + return; + } fourwire_fourwire_obj_t *self = MP_OBJ_TO_PTR(obj); - if (self->command.base.type == &mp_type_NoneType) { + if (self->command == mp_const_none) { // When the data/command pin is not specified, we simulate a 9-bit SPI mode, by // adding a data/command bit to every byte, and then splitting the resulting data back // into 8-bit chunks for transmission. If the length of the data being transmitted @@ -133,24 +149,24 @@ void common_hal_fourwire_fourwire_send(mp_obj_t obj, display_byte_type_t data_ty if (bits > 0) { buffer = buffer << (8 - bits); common_hal_busio_spi_write(self->bus, &buffer, 1); - if (self->chip_select.base.type != &mp_type_NoneType) { + if (self->chip_select != mp_const_none) { // toggle CS to discard superfluous bits - common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + digitalinout_protocol_set_value(self->chip_select, true); common_hal_mcu_delay_us(1); - common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + digitalinout_protocol_set_value(self->chip_select, false); } } } else { - common_hal_digitalio_digitalinout_set_value(&self->command, data_type == DISPLAY_DATA); + digitalinout_protocol_set_value(self->command, data_type == DISPLAY_DATA); if (chip_select == CHIP_SELECT_TOGGLE_EVERY_BYTE) { // Toggle chip select after each command byte in case the display driver // IC latches commands based on it. for (size_t i = 0; i < data_length; i++) { common_hal_busio_spi_write(self->bus, &data[i], 1); - if (self->chip_select.base.type != &mp_type_NoneType) { - common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + if (self->chip_select != mp_const_none) { + digitalinout_protocol_set_value(self->chip_select, true); common_hal_mcu_delay_us(1); - common_hal_digitalio_digitalinout_set_value(&self->chip_select, false); + digitalinout_protocol_set_value(self->chip_select, false); } } } else { @@ -161,8 +177,8 @@ void common_hal_fourwire_fourwire_send(mp_obj_t obj, display_byte_type_t data_ty void common_hal_fourwire_fourwire_end_transaction(mp_obj_t obj) { fourwire_fourwire_obj_t *self = MP_OBJ_TO_PTR(obj); - if (self->chip_select.base.type != &mp_type_NoneType) { - common_hal_digitalio_digitalinout_set_value(&self->chip_select, true); + if (self->chip_select != mp_const_none) { + digitalinout_protocol_set_value(self->chip_select, true); } common_hal_busio_spi_unlock(self->bus); } diff --git a/shared-module/fourwire/FourWire.h b/shared-module/fourwire/FourWire.h index 629a426b3b0..c239a3dfde3 100644 --- a/shared-module/fourwire/FourWire.h +++ b/shared-module/fourwire/FourWire.h @@ -6,6 +6,8 @@ #pragma once +#include + #include "common-hal/busio/SPI.h" #include "common-hal/digitalio/DigitalInOut.h" #include "shared-module/displayio/Group.h" @@ -14,10 +16,13 @@ typedef struct { mp_obj_base_t base; busio_spi_obj_t *bus; busio_spi_obj_t inline_bus; - digitalio_digitalinout_obj_t command; - digitalio_digitalinout_obj_t chip_select; - digitalio_digitalinout_obj_t reset; + mp_obj_t command; + mp_obj_t chip_select; + mp_obj_t reset; uint32_t frequency; uint8_t polarity; uint8_t phase; + bool own_command; + bool own_chip_select; + bool own_reset; } fourwire_fourwire_obj_t; diff --git a/shared-module/i2cioexpander/IOExpander.c b/shared-module/i2cioexpander/IOExpander.c new file mode 100644 index 00000000000..5146abc66e6 --- /dev/null +++ b/shared-module/i2cioexpander/IOExpander.c @@ -0,0 +1,196 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/i2cioexpander/IOExpander.h" +#include "shared-bindings/i2cioexpander/IOPin.h" + +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/busio/I2C.h" +#include "supervisor/port.h" + +void common_hal_i2cioexpander_ioexpander_construct( + i2cioexpander_ioexpander_obj_t *self, + mp_obj_t i2c, + uint8_t address, + uint8_t num_pins, + uint16_t set_value_reg, + uint16_t get_value_reg, + uint16_t set_direction_reg) { + + // Store the I2C bus + self->i2c = (busio_i2c_obj_t *)i2c; + self->address = address; + self->num_pins = num_pins; + self->output_value = 0; + self->output_mask = 0; + + // Parse optional register addresses + self->has_set_value = (set_value_reg != NO_REGISTER); + if (self->has_set_value) { + self->set_value_reg = set_value_reg; + } + + self->has_get_value = (get_value_reg != NO_REGISTER); + if (self->has_get_value) { + self->get_value_reg = get_value_reg; + } + + self->has_set_direction = (set_direction_reg != NO_REGISTER); + if (self->has_set_direction) { + self->set_direction_reg = set_direction_reg; + } + + bool allocate_in_port_heap = !gc_alloc_possible() || !gc_ptr_on_heap(self); + + // Allocate tuple with space for pin objects in items[] + size_t tuple_size = offsetof(mp_obj_tuple_t, items) + sizeof(mp_obj_t) * num_pins; + mp_obj_tuple_t *pins_tuple = allocate_in_port_heap ? port_malloc(tuple_size, false) : m_malloc(tuple_size); + pins_tuple->base.type = &mp_type_tuple; + pins_tuple->len = num_pins; + + // Create IOPin objects for each pin + size_t pin_size = sizeof(i2cioexpander_iopin_obj_t); + for (uint8_t i = 0; i < num_pins; i++) { + i2cioexpander_iopin_obj_t *pin = allocate_in_port_heap ? port_malloc(pin_size, false) : m_malloc(pin_size); + pin->base.type = &i2cioexpander_iopin_type; + i2cioexpander_iopin_construct(pin, self, i); + pins_tuple->items[i] = MP_OBJ_FROM_PTR(pin); + } + + self->pins = pins_tuple; +} + +void common_hal_i2cioexpander_ioexpander_deinit(i2cioexpander_ioexpander_obj_t *self) { + if (gc_alloc_possible() && !gc_ptr_on_heap(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot deinitialize board IOExpander")); + } + for (uint8_t i = 0; i < self->num_pins; i++) { + circuitpy_free_obj(self->pins->items[i]); + } + circuitpy_free_obj(self->pins); + self->i2c = NULL; +} + +bool common_hal_i2cioexpander_ioexpander_deinited(i2cioexpander_ioexpander_obj_t *self) { + return self->i2c == NULL; +} + +mp_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioexpander_obj_t *self, size_t *value) { + uint8_t buffer[2]; + uint8_t num_bytes = (self->num_pins > 8) ? 2 : 1; + + while (!common_hal_busio_i2c_try_lock(self->i2c)) { + RUN_BACKGROUND_TASKS; + } + + mp_errno_t result; + if (self->has_get_value) { + // Send register address then read + result = common_hal_busio_i2c_write_read( + self->i2c, self->address, &self->get_value_reg, 1, buffer, num_bytes); + } else { + // Read directly without register address + result = common_hal_busio_i2c_read(self->i2c, self->address, buffer, num_bytes); + } + common_hal_busio_i2c_unlock(self->i2c); + + if (result != 0) { + return result; + } + + if (num_bytes == 2) { + *value = buffer[0] | (buffer[1] << 8); + } else { + *value = buffer[0]; + } + return 0; +} + +void common_hal_i2cioexpander_ioexpander_get_output_value(i2cioexpander_ioexpander_obj_t *self, size_t *value) { + *value = self->output_value; +} + +mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_ioexpander_obj_t *self, size_t value) { + uint8_t buffer[5]; + uint8_t num_bytes = 0; + + // Add register address if provided + if (self->has_set_value) { + buffer[num_bytes++] = self->set_value_reg; + } + + size_t current_value = self->output_value; + if (current_value == value) { + return 0; + } + size_t diff = current_value ^ value; + + // Add value byte(s) but only if a high bit is changed + buffer[num_bytes++] = value & 0xFF; + if (self->num_pins > 8 && (diff >> 8) != 0) { + buffer[num_bytes++] = (value >> 8) & 0xFF; + } + if (self->num_pins > 16 && (diff >> 16) != 0) { + buffer[num_bytes++] = (value >> 16) & 0xFF; + } + if (self->num_pins > 24 && (diff >> 24) != 0) { + buffer[num_bytes++] = (value >> 24) & 0xFF; + } + + if (!common_hal_busio_i2c_try_lock(self->i2c)) { + return -MP_EBUSY; + } + + mp_errno_t result = common_hal_busio_i2c_write(self->i2c, self->address, buffer, num_bytes); + common_hal_busio_i2c_unlock(self->i2c); + if (result == 0) { + self->output_value = value; + } + return result; +} + +void common_hal_i2cioexpander_ioexpander_get_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t *mask) { + *mask = self->output_mask; +} + +mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t mask) { + self->output_mask = mask; + + // Only write to device if direction register is provided + if (!self->has_set_direction) { + return 0; + } + + uint8_t buffer[3]; + uint8_t num_bytes = 0; + + // Add register address + buffer[num_bytes++] = self->set_direction_reg; + + // Invert the mask so 0 indicates output. We taken 1 for output to match output enable. + size_t inverted_mask = ~mask; + + // Add mask byte(s) + buffer[num_bytes++] = inverted_mask & 0xFF; + if (self->num_pins > 8) { + buffer[num_bytes++] = (inverted_mask >> 8) & 0xFF; + } + + if (!common_hal_busio_i2c_try_lock(self->i2c)) { + return -MP_EBUSY; + } + + mp_errno_t result = common_hal_busio_i2c_write(self->i2c, self->address, buffer, num_bytes); + common_hal_busio_i2c_unlock(self->i2c); + return result; +} + +mp_obj_t common_hal_i2cioexpander_ioexpander_get_pins(i2cioexpander_ioexpander_obj_t *self) { + return MP_OBJ_FROM_PTR(self->pins); +} diff --git a/shared-module/i2cioexpander/IOExpander.h b/shared-module/i2cioexpander/IOExpander.h new file mode 100644 index 00000000000..e225bfc75c7 --- /dev/null +++ b/shared-module/i2cioexpander/IOExpander.h @@ -0,0 +1,41 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" +#include "py/objtuple.h" +#include "shared-bindings/busio/I2C.h" + +#define NO_REGISTER (0x100) + +typedef struct { + mp_obj_base_t base; + busio_i2c_obj_t *i2c; + uint8_t address; + uint8_t num_pins; + uint8_t set_value_reg; + uint8_t get_value_reg; + uint8_t set_direction_reg; + size_t output_value; + size_t output_mask; + bool has_set_value; + bool has_get_value; + bool has_set_direction; + mp_obj_tuple_t *pins; +} i2cioexpander_ioexpander_obj_t; + +void common_hal_i2cioexpander_ioexpander_construct( + i2cioexpander_ioexpander_obj_t *self, + mp_obj_t i2c, + uint8_t address, + uint8_t num_pins, + uint16_t set_value_reg, + uint16_t get_value_reg, + uint16_t set_direction_reg); diff --git a/shared-module/i2cioexpander/IOPin.c b/shared-module/i2cioexpander/IOPin.c new file mode 100644 index 00000000000..bf78fe6fbd4 --- /dev/null +++ b/shared-module/i2cioexpander/IOPin.c @@ -0,0 +1,147 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/i2cioexpander/IOPin.h" +#include "shared-bindings/i2cioexpander/IOExpander.h" + +#include "py/runtime.h" + +mp_errno_t i2cioexpander_iopin_construct( + i2cioexpander_iopin_obj_t *self, + i2cioexpander_ioexpander_obj_t *expander, + uint8_t pin_number) { + + if (pin_number >= expander->num_pins) { + return MP_EINVAL; // Reusing this for "invalid pin" + } + + self->expander = expander; + self->pin_number = pin_number; + self->direction = DIRECTION_INPUT; + + return 0; +} + +void common_hal_i2cioexpander_iopin_deinit(i2cioexpander_iopin_obj_t *self) { + self->expander = NULL; +} + +bool common_hal_i2cioexpander_iopin_deinited(i2cioexpander_iopin_obj_t *self) { + return self->expander == NULL; +} + +digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_input( + i2cioexpander_iopin_obj_t *self, + digitalio_pull_t pull) { + + if (pull != PULL_NONE) { + // IO expanders typically don't support pull resistors + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL + return DIGITALINOUT_INVALID_PULL; + #endif + } + + self->direction = DIRECTION_INPUT; + + // Clear the output mask bit for this pin + size_t new_mask = self->expander->output_mask & ~(1 << self->pin_number); + common_hal_i2cioexpander_ioexpander_set_output_mask(self->expander, new_mask); + + return DIGITALINOUT_OK; +} + +digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_output( + i2cioexpander_iopin_obj_t *self, + bool value, + digitalio_drive_mode_t drive_mode) { + + if (drive_mode != DRIVE_MODE_PUSH_PULL) { + // IO expanders typically only support push-pull + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE + return DIGITALINOUT_INVALID_DRIVE_MODE; + #endif + } + + self->direction = DIRECTION_OUTPUT; + + // Set the value first + size_t new_value = self->expander->output_value; + if (value) { + new_value |= (1 << self->pin_number); + } else { + new_value &= ~(1 << self->pin_number); + } + common_hal_i2cioexpander_ioexpander_set_output_value(self->expander, new_value); + + // Set the output mask bit for this pin + size_t new_mask = self->expander->output_mask | (1 << self->pin_number); + common_hal_i2cioexpander_ioexpander_set_output_mask(self->expander, new_mask); + + return DIGITALINOUT_OK; +} + +digitalio_direction_t common_hal_i2cioexpander_iopin_get_direction(i2cioexpander_iopin_obj_t *self) { + return self->direction; +} + +mp_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *self, bool value) { + size_t current_value; + common_hal_i2cioexpander_ioexpander_get_output_value(self->expander, ¤t_value); + size_t new_value; + if (value) { + new_value = current_value | (1 << self->pin_number); + } else { + new_value = current_value & ~(1 << self->pin_number); + } + if (new_value != current_value) { + return common_hal_i2cioexpander_ioexpander_set_output_value(self->expander, new_value); + } + return 0; +} + +mp_errno_t common_hal_i2cioexpander_iopin_get_value(i2cioexpander_iopin_obj_t *self, bool *value) { + size_t full_value; + mp_errno_t result = common_hal_i2cioexpander_ioexpander_get_input_value(self->expander, &full_value); + if (result != 0) { + return result; + } + *value = (full_value & (1 << self->pin_number)) != 0; + return 0; +} + +digitalinout_result_t common_hal_i2cioexpander_iopin_set_drive_mode( + i2cioexpander_iopin_obj_t *self, + digitalio_drive_mode_t drive_mode) { + + if (drive_mode != DRIVE_MODE_PUSH_PULL) { + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE + return DIGITALINOUT_INVALID_DRIVE_MODE; + #endif + } + + return DIGITALINOUT_OK; +} + +digitalio_drive_mode_t common_hal_i2cioexpander_iopin_get_drive_mode(i2cioexpander_iopin_obj_t *self) { + return DRIVE_MODE_PUSH_PULL; +} + +digitalinout_result_t common_hal_i2cioexpander_iopin_set_pull( + i2cioexpander_iopin_obj_t *self, + digitalio_pull_t pull) { + + if (pull != PULL_NONE) { + #if CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL + return DIGITALINOUT_INVALID_PULL; + #endif + } + + return DIGITALINOUT_OK; +} + +digitalio_pull_t common_hal_i2cioexpander_iopin_get_pull(i2cioexpander_iopin_obj_t *self) { + return PULL_NONE; +} diff --git a/shared-module/i2cioexpander/IOPin.h b/shared-module/i2cioexpander/IOPin.h new file mode 100644 index 00000000000..0c4da8a0213 --- /dev/null +++ b/shared-module/i2cioexpander/IOPin.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" +#include "shared-bindings/digitalio/Direction.h" +#include "shared-bindings/digitalio/DriveMode.h" +#include "shared-bindings/digitalio/Pull.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-module/i2cioexpander/IOExpander.h" + +typedef struct { + mp_obj_base_t base; + i2cioexpander_ioexpander_obj_t *expander; + uint8_t pin_number; + digitalio_direction_t direction; +} i2cioexpander_iopin_obj_t; + +extern const mp_obj_type_t i2cioexpander_iopin_type; diff --git a/shared-module/i2cioexpander/__init__.c b/shared-module/i2cioexpander/__init__.c new file mode 100644 index 00000000000..43e652db897 --- /dev/null +++ b/shared-module/i2cioexpander/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Nothing now. diff --git a/supervisor/port.h b/supervisor/port.h index 0bf8fd8d013..192307a5f57 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -115,3 +115,8 @@ bool port_boot_button_pressed(void); void *mp_obj_port_malloc_helper(size_t num_bytes, const mp_obj_type_t *type); mp_obj_t mp_obj_new_port_tuple(size_t n, const mp_obj_t *items); + +// Safely free an object that may have been allocated from either the GC heap or port heap. +// If the pointer is on the GC heap, it will be freed by the GC automatically. +// If the pointer is not on the GC heap, it will be freed with port_free. +void circuitpy_free_obj(mp_obj_t obj); diff --git a/supervisor/shared/port.c b/supervisor/shared/port.c index aabf003fb30..f908e3f0bd8 100644 --- a/supervisor/shared/port.c +++ b/supervisor/shared/port.c @@ -9,6 +9,7 @@ #include #include "py/runtime.h" +#include "py/gc.h" #include "lib/tlsf/tlsf.h" @@ -56,6 +57,22 @@ MP_WEAK void port_free(void *ptr) { tlsf_free(heap, ptr); } +// Safely free an object that may have been allocated from either the GC heap or port heap. +// If the pointer is on the GC heap, it will be freed by the GC automatically, so we do nothing. +// If the pointer is not on the GC heap (i.e., allocated with port_malloc), we free it with port_free. +// This is safe to call during shutdown when GC may not be available. +void circuitpy_free_obj(mp_obj_t obj) { + if (obj == mp_const_none) { + return; + } + void *ptr = MP_OBJ_TO_PTR(obj); + if (gc_alloc_possible() && gc_ptr_on_heap(ptr)) { + gc_free(ptr); + } else { + port_free(ptr); + } +} + MP_WEAK void *port_realloc(void *ptr, size_t size, bool dma_capable) { return tlsf_realloc(heap, ptr, size); } diff --git a/supervisor/shared/status_leds.c b/supervisor/shared/status_leds.c index ffe8b46b20b..ca29fd79212 100644 --- a/supervisor/shared/status_leds.c +++ b/supervisor/shared/status_leds.c @@ -133,9 +133,9 @@ void status_led_init(void) { memset(status_apa102_color + 4, 0xff, APA102_BUFFER_LENGTH - 4); #if CIRCUITPY_BITBANG_APA102 shared_module_bitbangio_spi_construct(&status_apa102, - MICROPY_HW_APA102_SCK, - MICROPY_HW_APA102_MOSI, - NULL); + MP_OBJ_FROM_PTR(MICROPY_HW_APA102_SCK), + MP_OBJ_FROM_PTR(MICROPY_HW_APA102_MOSI), + mp_const_none); #else if (!common_hal_busio_spi_deinited(&status_apa102)) { common_hal_busio_spi_deinit(&status_apa102); diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index eea11bd5fb4..553fe8694c6 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -1085,6 +1085,10 @@ static void _reply_static(socketpool_socket_obj_t *socket, _request *request, co "Content-Encoding: gzip\r\n", "Content-Length: ", encoded_len, "\r\n", "Content-Type: ", content_type, "\r\n", + #if CIRCUITPY_DEBUG == 0 + "Cache-Control: max-age=31536000\r\n", // Cache for a year. + "Vary: Accept\r\n", + #endif "\r\n", NULL); web_workflow_send_raw(socket, true, response, response_len); } From 21c96452b3012db15de858289eceeb853e960af2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 23 Jan 2026 16:55:44 -0800 Subject: [PATCH 154/876] Fix codespell --- .../asf4_conf/samd21/hpl_sercom_config.h | 2 +- .../asf4_conf/samd51/hpl_sercom_config.h | 2 +- .../asf4_conf/same51/hpl_sercom_config.h | 2 +- .../asf4_conf/same54/hpl_sercom_config.h | 2 +- ports/atmel-samd/sd_mmc/sd_mmc.c | 14 +++++++------- ports/atmel-samd/sd_mmc/sd_mmc.h | 2 +- .../espressif/boards/sunton_esp32_2432S024C/pins.c | 2 +- .../espressif/boards/sunton_esp32_2432S028/pins.c | 2 +- ports/espressif/common-hal/_bleio/Adapter.c | 2 +- ports/espressif/common-hal/pulseio/PulseOut.c | 2 +- ports/raspberrypi/common-hal/socketpool/Socket.c | 2 +- ports/silabs/common-hal/_bleio/Characteristic.c | 4 ++-- ports/silabs/common-hal/_bleio/Service.c | 8 ++++---- ports/stm/boards/espruino_pico/README.md | 2 +- ports/stm/boards/espruino_wifi/README.MD | 2 +- ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c | 2 +- py/mpz.c | 12 ++++++------ shared-bindings/aurora_epaper/aurora_framebuffer.c | 2 +- shared-bindings/canio/__init__.c | 2 +- shared-bindings/ssl/SSLSocket.c | 2 +- tools/safe_mode_finder.py | 4 ++-- 21 files changed, 37 insertions(+), 37 deletions(-) diff --git a/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h index 5979d1ee997..157db0d3f7f 100644 --- a/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h +++ b/ports/atmel-samd/asf4_conf/samd21/hpl_sercom_config.h @@ -431,7 +431,7 @@ // <0x2=>8x arithmetic // <0x3=>8x fractional // <0x3=>3x -// How many over-sampling bits used when samling data state +// How many over-sampling bits used when sampling data state // usart_arch_sampr #ifndef CONF_SERCOM_2_USART_SAMPR #define CONF_SERCOM_2_USART_SAMPR 0x0 diff --git a/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h index e05560e6358..6dd21277b78 100644 --- a/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h +++ b/ports/atmel-samd/asf4_conf/samd51/hpl_sercom_config.h @@ -431,7 +431,7 @@ // <0x2=>8x arithmetic // <0x3=>8x fractional // <0x3=>3x -// How many over-sampling bits used when samling data state +// How many over-sampling bits used when sampling data state // usart_arch_sampr #ifndef CONF_SERCOM_2_USART_SAMPR #define CONF_SERCOM_2_USART_SAMPR 0x0 diff --git a/ports/atmel-samd/asf4_conf/same51/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/same51/hpl_sercom_config.h index e05560e6358..6dd21277b78 100644 --- a/ports/atmel-samd/asf4_conf/same51/hpl_sercom_config.h +++ b/ports/atmel-samd/asf4_conf/same51/hpl_sercom_config.h @@ -431,7 +431,7 @@ // <0x2=>8x arithmetic // <0x3=>8x fractional // <0x3=>3x -// How many over-sampling bits used when samling data state +// How many over-sampling bits used when sampling data state // usart_arch_sampr #ifndef CONF_SERCOM_2_USART_SAMPR #define CONF_SERCOM_2_USART_SAMPR 0x0 diff --git a/ports/atmel-samd/asf4_conf/same54/hpl_sercom_config.h b/ports/atmel-samd/asf4_conf/same54/hpl_sercom_config.h index e05560e6358..6dd21277b78 100644 --- a/ports/atmel-samd/asf4_conf/same54/hpl_sercom_config.h +++ b/ports/atmel-samd/asf4_conf/same54/hpl_sercom_config.h @@ -431,7 +431,7 @@ // <0x2=>8x arithmetic // <0x3=>8x fractional // <0x3=>3x -// How many over-sampling bits used when samling data state +// How many over-sampling bits used when sampling data state // usart_arch_sampr #ifndef CONF_SERCOM_2_USART_SAMPR #define CONF_SERCOM_2_USART_SAMPR 0x0 diff --git a/ports/atmel-samd/sd_mmc/sd_mmc.c b/ports/atmel-samd/sd_mmc/sd_mmc.c index 60b4d9f8985..6724e88f42a 100644 --- a/ports/atmel-samd/sd_mmc/sd_mmc.c +++ b/ports/atmel-samd/sd_mmc/sd_mmc.c @@ -160,9 +160,9 @@ static struct sd_mmc_card sd_mmc_cards[CONF_SD_MMC_MEM_CNT]; /** HAL driver instance */ static void *sd_mmc_hal; -/** Index of current slot configurated */ +/** Index of current slot configured */ static uint8_t sd_mmc_slot_sel; -/** Pointer on current slot configurated */ +/** Pointer on current slot configured */ static struct sd_mmc_card *sd_mmc_card; /** Number of block to read or write on the current transfer */ static uint16_t sd_mmc_nb_block_to_tranfer = 0; @@ -238,7 +238,7 @@ static bool mmc_mci_op_cond(void) { uint32_t retry, resp; /* - * Timeout 1s = 400KHz / ((6+6)*8) cylces = 4200 retry + * Timeout 1s = 400KHz / ((6+6)*8) cycles = 4200 retry * 6 = cmd byte size * 6 = response byte size */ @@ -277,7 +277,7 @@ static bool sd_mci_op_cond(uint8_t v2) { uint32_t arg, retry, resp; /* - * Timeout 1s = 400KHz / ((6+6+6+6)*8) cylces = 2100 retry + * Timeout 1s = 400KHz / ((6+6+6+6)*8) cycles = 2100 retry * 6 = cmd byte size * 6 = response byte size * 6 = cmd byte size @@ -339,7 +339,7 @@ static bool sdio_op_cond(void) { /* * Wait card ready - * Timeout 1s = 400KHz / ((6+4)*8) cylces = 5000 retry + * Timeout 1s = 400KHz / ((6+4)*8) cycles = 5000 retry * 6 = cmd byte size * 4(SPI) 6(MCI) = response byte size */ @@ -1292,13 +1292,13 @@ static bool sd_mmc_mci_install_mmc(void) { void sd_mmc_init(void *hal, sd_mmc_detect_t *card_detects, sd_mmc_detect_t *wp_detects) { /* GPIO will be used to detect card and write protect. - * The related clocks and pinmux must be configurated in good + * The related clocks and pinmux must be configured in good * condition. */ for (uint8_t slot = 0; slot < CONF_SD_MMC_MEM_CNT; slot++) { sd_mmc_cards[slot].state = SD_MMC_CARD_STATE_NO_CARD; } - sd_mmc_slot_sel = 0xFF; /* No slot configurated */ + sd_mmc_slot_sel = 0xFF; /* No slot configured */ sd_mmc_hal = hal; _cd = card_detects; _wp = wp_detects; diff --git a/ports/atmel-samd/sd_mmc/sd_mmc.h b/ports/atmel-samd/sd_mmc/sd_mmc.h index cdc98e7108e..7b70a631164 100644 --- a/ports/atmel-samd/sd_mmc/sd_mmc.h +++ b/ports/atmel-samd/sd_mmc/sd_mmc.h @@ -113,7 +113,7 @@ typedef struct sd_mmc_detect { uint16_t val; /**< Detection value */ } sd_mmc_detect_t; -/** This SD MMC stack uses the maximum block size autorized (512 bytes) */ +/** This SD MMC stack uses the maximum block size authorized (512 bytes) */ #define SD_MMC_BLOCK_SIZE 512 /** diff --git a/ports/espressif/boards/sunton_esp32_2432S024C/pins.c b/ports/espressif/boards/sunton_esp32_2432S024C/pins.c index a69f3150e92..6544017cd99 100644 --- a/ports/espressif/boards/sunton_esp32_2432S024C/pins.c +++ b/ports/espressif/boards/sunton_esp32_2432S024C/pins.c @@ -46,7 +46,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO5) }, - // ILI9341 dsplay (spi) + // ILI9341 display (spi) { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_GPIO13) }, { MP_ROM_QSTR(MP_QSTR_LCD_MISO), MP_ROM_PTR(&pin_GPIO12) }, { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_GPIO14) }, diff --git a/ports/espressif/boards/sunton_esp32_2432S028/pins.c b/ports/espressif/boards/sunton_esp32_2432S028/pins.c index b852ab11e04..7791c1685eb 100644 --- a/ports/espressif/boards/sunton_esp32_2432S028/pins.c +++ b/ports/espressif/boards/sunton_esp32_2432S028/pins.c @@ -45,7 +45,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_SCK), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO5) }, - // ILI9341 dsplay (spi) + // ILI9341 display (spi) { MP_ROM_QSTR(MP_QSTR_LCD_MOSI), MP_ROM_PTR(&pin_GPIO13) }, { MP_ROM_QSTR(MP_QSTR_LCD_MISO), MP_ROM_PTR(&pin_GPIO12) }, { MP_ROM_QSTR(MP_QSTR_LCD_SCK), MP_ROM_PTR(&pin_GPIO14) }, diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index f604e02c200..352d01372a9 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -384,7 +384,7 @@ static int _connect_event(struct ble_gap_event *event, void *self_in) { // connection and need a new tuple. self->connection_objs = NULL; } else { - // The loop waiting for the connection to be comnpleted will stop when _connection_status changes. + // The loop waiting for the connection to be completed will stop when _connection_status changes. _connection_status = -event->connect.status; } break; diff --git a/ports/espressif/common-hal/pulseio/PulseOut.c b/ports/espressif/common-hal/pulseio/PulseOut.c index 68cb64b5e60..8995043b825 100644 --- a/ports/espressif/common-hal/pulseio/PulseOut.c +++ b/ports/espressif/common-hal/pulseio/PulseOut.c @@ -69,7 +69,7 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t *self, uint16_t *pu // Circuitpython allows 16 bit pulse values, while ESP32 only allows 15 bits // Thus, we use entire items for one pulse, rather than switching inside each item for (size_t i = 0; i < length; i++) { - // Setting the RMT duration to 0 has undefined behavior, so avoid that pre-emptively. + // Setting the RMT duration to 0 has undefined behavior, so avoid that preemptively. if (pulses[i] == 0) { continue; } diff --git a/ports/raspberrypi/common-hal/socketpool/Socket.c b/ports/raspberrypi/common-hal/socketpool/Socket.c index aeab1498510..0543fd53dc3 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.c +++ b/ports/raspberrypi/common-hal/socketpool/Socket.c @@ -251,7 +251,7 @@ static void _lwip_tcp_err_unaccepted(void *arg, err_t err) { // because it's only ever used by lwIP if tcp_connect is called on the TCP PCB. socketpool_socket_obj_t *socket = (socketpool_socket_obj_t *)pcb->connected; - // Array is not volatile because thiss callback is executed within the lwIP context + // Array is not volatile because this callback is executed within the lwIP context uint8_t alloc = socket->incoming.connection.alloc; struct tcp_pcb **tcp_array = (struct tcp_pcb **)lwip_socket_incoming_array(socket); diff --git a/ports/silabs/common-hal/_bleio/Characteristic.c b/ports/silabs/common-hal/_bleio/Characteristic.c index 37fb792cd4d..a707b0ef1ac 100644 --- a/ports/silabs/common-hal/_bleio/Characteristic.c +++ b/ports/silabs/common-hal/_bleio/Characteristic.c @@ -249,7 +249,7 @@ size_t common_hal_bleio_characteristic_get_value( return 0; } -// Get max length of charateristic +// Get max length of characteristic size_t common_hal_bleio_characteristic_get_max_length( bleio_characteristic_obj_t *self) { return self->max_length; @@ -373,7 +373,7 @@ void common_hal_bleio_characteristic_add_descriptor( // This indicates the new added descriptor shall be started. sc = sl_bt_gattdb_start_characteristic(gattdb_session, self->handle); if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Start charateristic fail.")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Start characteristic fail.")); return; } diff --git a/ports/silabs/common-hal/_bleio/Service.c b/ports/silabs/common-hal/_bleio/Service.c index abc8ffe74ed..50f0c4593a6 100644 --- a/ports/silabs/common-hal/_bleio/Service.c +++ b/ports/silabs/common-hal/_bleio/Service.c @@ -128,7 +128,7 @@ bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { return self->uuid; } -// Get tuple charateristic of service +// Get tuple characteristic of service mp_obj_tuple_t *common_hal_bleio_service_get_characteristics( bleio_service_obj_t *self) { return mp_obj_new_tuple(self->characteristic_list->len, @@ -210,19 +210,19 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, } if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Add charateristic fail.")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Add characteristic fail.")); } sc = sl_bt_gattdb_start_characteristic(gattdb_session, characteristic->handle); if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Start charateristic fail.")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Start characteristic fail.")); return; } sc = sl_bt_gattdb_commit(gattdb_session); if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Commit charateristic fail.")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Commit characteristic fail.")); return; } mp_obj_list_append(self->characteristic_list, diff --git a/ports/stm/boards/espruino_pico/README.md b/ports/stm/boards/espruino_pico/README.md index 86df1ad32a3..d930e9aeca3 100644 --- a/ports/stm/boards/espruino_pico/README.md +++ b/ports/stm/boards/espruino_pico/README.md @@ -12,4 +12,4 @@ The Espruino Pico is normally updated via a bootloader activated by the Espruino - Restart the board. -To reinstall Espruino, follow the same steps with the latest Espruino Pico binary from espruino.com/binaries. This will reinstall the usual Espruino bootloader. You must un-short the BOOT0/BTN jumper to re-use the original Espruino Bootloader again. If you used a Pencil mark then you may need to use cleaning fluid and a small brush to totally clear out the graphite. +To reinstall Espruino, follow the same steps with the latest Espruino Pico binary from espruino.com/binaries. This will reinstall the usual Espruino bootloader. You must un-short the BOOT0/BTN jumper to reuse the original Espruino Bootloader again. If you used a Pencil mark then you may need to use cleaning fluid and a small brush to totally clear out the graphite. diff --git a/ports/stm/boards/espruino_wifi/README.MD b/ports/stm/boards/espruino_wifi/README.MD index cc78811f1c7..cebe99bf6d1 100644 --- a/ports/stm/boards/espruino_wifi/README.MD +++ b/ports/stm/boards/espruino_wifi/README.MD @@ -12,4 +12,4 @@ The Espruino Wifi is normally updated via a bootloader activated by the Espruino - Restart the board. -To reinstall Espruino, follow the same steps with the latest Espruino Wifi binary from espruino.com/binaries. This will reinstall the usual Espruino bootloader. You must un-short the BOOT0/BTN jumper to re-use the original Espruino Bootloader again. If you used a Pencil mark then you may need to use cleaning fluid and a small brush to totally clear out the graphite. +To reinstall Espruino, follow the same steps with the latest Espruino Wifi binary from espruino.com/binaries. This will reinstall the usual Espruino bootloader. You must un-short the BOOT0/BTN jumper to reuse the original Espruino Bootloader again. If you used a Pencil mark then you may need to use cleaning fluid and a small brush to totally clear out the graphite. diff --git a/ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c b/ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c index 18fe8b760a2..a4adc58e42a 100644 --- a/ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c +++ b/ports/stm/peripherals/stm32l4/stm32l4r5xx/gpio.c @@ -17,7 +17,7 @@ void stm32_peripherals_gpio_init(void) { __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); - // These ports are not used on the Swan R5 but may need to be enabeld on other boards + // These ports are not used on the Swan R5 but may need to be enabled on other boards // __HAL_RCC_GPIOH_CLK_ENABLE(); // __HAL_RCC_GPIOI_CLK_ENABLE(); diff --git a/py/mpz.c b/py/mpz.c index 7d8bc03ca86..046d4fcdd5a 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -782,15 +782,15 @@ void mpz_set_from_float(mpz_t *z, mp_float_t src) { // 2 <= value const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE; const unsigned int rem = adj_exp % DIG_SIZE; - int dig_ind, shft; + int dig_ind, shift; mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS); if (adj_exp < MP_FLOAT_FRAC_BITS) { - shft = 0; + shift = 0; dig_ind = 0; frc >>= MP_FLOAT_FRAC_BITS - adj_exp; } else { - shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE; + shift = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE; dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE; } mpz_need_dig(z, dig_cnt); @@ -798,9 +798,9 @@ void mpz_set_from_float(mpz_t *z, mp_float_t src) { if (dig_ind != 0) { memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t)); } - if (shft != 0) { - z->dig[dig_ind++] = (frc << shft) & DIG_MASK; - frc >>= DIG_SIZE - shft; + if (shift != 0) { + z->dig[dig_ind++] = (frc << shift) & DIG_MASK; + frc >>= DIG_SIZE - shift; } #if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1) while (dig_ind != dig_cnt) { diff --git a/shared-bindings/aurora_epaper/aurora_framebuffer.c b/shared-bindings/aurora_epaper/aurora_framebuffer.c index f1bb1693284..49e0b34a856 100644 --- a/shared-bindings/aurora_epaper/aurora_framebuffer.c +++ b/shared-bindings/aurora_epaper/aurora_framebuffer.c @@ -64,7 +64,7 @@ //| ) -> None: //| """Create a framebuffer for the Aurora CoG display. //| -//| .. note:: Displays of size 1.9" and 2.6" are not tested, and may exibit unexpected behavior. +//| .. note:: Displays of size 1.9" and 2.6" are not tested, and may exhibit unexpected behavior. //| //| :param busio.SPI spi_bus: The SPI bus that the display is connected to //| :param microcontroller.Pin chip_select: The pin connected to the displays chip select input diff --git a/shared-bindings/canio/__init__.c b/shared-bindings/canio/__init__.c index c65b119ff24..2300a6652dd 100644 --- a/shared-bindings/canio/__init__.c +++ b/shared-bindings/canio/__init__.c @@ -36,7 +36,7 @@ //| //| Other implementations of the CAN device may exist (for instance, attached //| via an SPI bus). If so their constructor arguments may differ, but -//| otherwise we encourage implementors to follow the API that the core uses. +//| otherwise we encourage implementers to follow the API that the core uses. //| //| For more information on working with this module, refer to //| `this Learn Guide on using it `_. diff --git a/shared-bindings/ssl/SSLSocket.c b/shared-bindings/ssl/SSLSocket.c index 92440f9ea30..4418a8e48d9 100644 --- a/shared-bindings/ssl/SSLSocket.c +++ b/shared-bindings/ssl/SSLSocket.c @@ -106,7 +106,7 @@ static MP_DEFINE_CONST_FUN_OBJ_2(ssl_sslsocket_connect_obj, ssl_sslsocket_connec //| def listen(self, backlog: int) -> None: //| """Set socket to listen for incoming connections //| -//| :param ~int backlog: length of backlog queue for waiting connetions""" +//| :param ~int backlog: length of backlog queue for waiting connections""" //| ... //| static mp_obj_t ssl_sslsocket_listen(mp_obj_t self_in, mp_obj_t backlog_in) { diff --git a/tools/safe_mode_finder.py b/tools/safe_mode_finder.py index fece8531278..af3ff0d3c6d 100644 --- a/tools/safe_mode_finder.py +++ b/tools/safe_mode_finder.py @@ -86,8 +86,8 @@ print(e.has_dwarf_info()) d = e.get_dwarf_info() # print(dir(d)) - aranges = d.get_aranges() - cu_offset = aranges.cu_offset_at_addr(pc) + arranges = d.get_aranges() + cu_offset = arranges.cu_offset_at_addr(pc) if not cu_offset: cu_offset = 0 main_cu = d.get_CU_at(cu_offset) From 6ead6b432291730535e37aa9d8af308dfc9eefa2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 23 Jan 2026 17:07:11 -0800 Subject: [PATCH 155/876] Fix stubs and tweak IOPin deinit --- shared-bindings/i2cioexpander/IOPin.c | 17 ++++++----------- shared-module/i2cioexpander/IOPin.c | 5 +++-- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/shared-bindings/i2cioexpander/IOPin.c b/shared-bindings/i2cioexpander/IOPin.c index 3e43e18831f..4a8ca46372b 100644 --- a/shared-bindings/i2cioexpander/IOPin.c +++ b/shared-bindings/i2cioexpander/IOPin.c @@ -42,16 +42,12 @@ static inline void check_for_deinit(i2cioexpander_iopin_obj_t *self) { raise_deinited_error(); } } - -//| def deinit(self) -> None: -//| """Turn off the pin and release it for other use.""" -//| ... -static mp_obj_t i2cioexpander_iopin_deinit(mp_obj_t self_in) { - i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_i2cioexpander_iopin_deinit(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_iopin_deinit_obj, i2cioexpander_iopin_deinit); +//| class IOPin: +//| """Control a single pin on an `IOExpander` in the same way as `DigitalInOut`. +//| +//| Not constructed directly. Get from `IOExpander.pins` instead. +//| """ +//| //| def switch_to_output( //| self, value: bool = False, drive_mode: digitalio.DriveMode = digitalio.DriveMode.PUSH_PULL @@ -310,7 +306,6 @@ static const digitalinout_p_t iopin_digitalinout_p = { static const mp_rom_map_elem_t i2cioexpander_iopin_locals_dict_table[] = { // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&i2cioexpander_iopin_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_switch_to_input), MP_ROM_PTR(&i2cioexpander_iopin_switch_to_input_obj) }, { MP_ROM_QSTR(MP_QSTR_switch_to_output), MP_ROM_PTR(&i2cioexpander_iopin_switch_to_output_obj) }, diff --git a/shared-module/i2cioexpander/IOPin.c b/shared-module/i2cioexpander/IOPin.c index bf78fe6fbd4..9502d2814f3 100644 --- a/shared-module/i2cioexpander/IOPin.c +++ b/shared-module/i2cioexpander/IOPin.c @@ -26,11 +26,12 @@ mp_errno_t i2cioexpander_iopin_construct( } void common_hal_i2cioexpander_iopin_deinit(i2cioexpander_iopin_obj_t *self) { - self->expander = NULL; + // Switch to input on deinit. + common_hal_i2cioexpander_iopin_switch_to_input(self, PULL_NONE); } bool common_hal_i2cioexpander_iopin_deinited(i2cioexpander_iopin_obj_t *self) { - return self->expander == NULL; + return self->expander == NULL || common_hal_i2cioexpander_ioexpander_deinited(self->expander); } digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_input( From 482620433c5428dfafee1b0d80a8f32c2a7674b5 Mon Sep 17 00:00:00 2001 From: Tim Walter Date: Sun, 25 Jan 2026 23:32:04 -0500 Subject: [PATCH 156/876] Add missing quote in hashlib.new docstring --- shared-bindings/hashlib/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/hashlib/__init__.c b/shared-bindings/hashlib/__init__.c index 2a6517791be..354529cfa77 100644 --- a/shared-bindings/hashlib/__init__.c +++ b/shared-bindings/hashlib/__init__.c @@ -20,7 +20,7 @@ //| //| def new(name: str, data: bytes = b"") -> hashlib.Hash: //| """Returns a Hash object setup for the named algorithm. Raises ValueError when the named -//| algorithm is unsupported. Supported algorithms for ``name`` are ``'sha1`` and ``'sha256'``. +//| algorithm is unsupported. Supported algorithms for ``name`` are ``'sha1'`` and ``'sha256'``. //| //| :return: a hash object for the given algorithm //| :rtype: hashlib.Hash""" From bcf7549544c0aeafbe64fd3bc1d5eec3c12008b5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 26 Jan 2026 09:38:13 -0800 Subject: [PATCH 157/876] Make board optionally mutable --- ports/espressif/boards/yoto_mini_2024/mpconfigboard.h | 2 ++ ports/espressif/boards/yoto_player_v3/mpconfigboard.h | 2 ++ py/circuitpy_mpconfig.h | 4 ++++ shared-bindings/board/__init__.h | 4 ++++ 4 files changed, 12 insertions(+) diff --git a/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h index b5ab8a7e6c2..4fcc2afaae8 100644 --- a/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h +++ b/ports/espressif/boards/yoto_mini_2024/mpconfigboard.h @@ -11,6 +11,8 @@ #define MICROPY_HW_BOARD_NAME "Yoto Mini 2024" #define MICROPY_HW_MCU_NAME "ESP32" +#define CIRCUITPY_MUTABLE_BOARD (1) + #define CIRCUITPY_BOARD_I2C (1) #define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO25, .sda = &pin_GPIO21}} #define CIRCUITPY_BOARD_I2C_SPEED (400000) diff --git a/ports/espressif/boards/yoto_player_v3/mpconfigboard.h b/ports/espressif/boards/yoto_player_v3/mpconfigboard.h index ba53649275c..1660c4881f9 100644 --- a/ports/espressif/boards/yoto_player_v3/mpconfigboard.h +++ b/ports/espressif/boards/yoto_player_v3/mpconfigboard.h @@ -11,6 +11,8 @@ #define MICROPY_HW_BOARD_NAME "Yoto Player V3" #define MICROPY_HW_MCU_NAME "ESP32" +#define CIRCUITPY_MUTABLE_BOARD (1) + #define CIRCUITPY_BOARD_I2C (1) #define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO25, .sda = &pin_GPIO21}} #define CIRCUITPY_BOARD_I2C_SPEED (400000) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index fb4f261ab6f..6266f75ceae 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -317,6 +317,10 @@ typedef long mp_off_t; // Default board buses. +#ifndef CIRCUITPY_MUTABLE_BOARD +#define CIRCUITPY_MUTABLE_BOARD (0) +#endif + #ifndef CIRCUITPY_BOARD_I2C #if defined(DEFAULT_I2C_BUS_SCL) && defined(DEFAULT_I2C_BUS_SDA) #define CIRCUITPY_BOARD_I2C (1) diff --git a/shared-bindings/board/__init__.h b/shared-bindings/board/__init__.h index 4466f3924bf..43343099730 100644 --- a/shared-bindings/board/__init__.h +++ b/shared-bindings/board/__init__.h @@ -11,7 +11,11 @@ #include "shared-bindings/microcontroller/Pin.h" // for the pin definitions +#if CIRCUITPY_MUTABLE_BOARD extern mp_obj_dict_t board_module_globals; +#else +extern const mp_obj_dict_t board_module_globals; +#endif static const MP_DEFINE_STR_OBJ(board_module_id_obj, CIRCUITPY_BOARD_ID); mp_obj_t common_hal_board_get_i2c(const mp_int_t instance); From de4311396203ef1e0bb11d9ea3ecefef0c54903d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 26 Jan 2026 11:19:03 -0800 Subject: [PATCH 158/876] Fix other FourWire calls --- ports/atmel-samd/boards/hallowing_m0_express/board.c | 6 +++--- ports/atmel-samd/boards/hallowing_m4_express/board.c | 6 +++--- ports/atmel-samd/boards/monster_m4sk/board.c | 6 +++--- ports/atmel-samd/boards/openbook_m4/board.c | 6 +++--- ports/atmel-samd/boards/pewpew_lcd/board.c | 6 +++--- ports/atmel-samd/boards/pewpew_m4/board.c | 6 +++--- ports/atmel-samd/boards/pybadge/board.c | 6 +++--- ports/atmel-samd/boards/pygamer/board.c | 6 +++--- ports/atmel-samd/boards/seeeduino_wio_terminal/board.c | 6 +++--- ports/atmel-samd/boards/ugame10/board.c | 6 +++--- ports/espressif/boards/adafruit_esp32s3_camera/board.c | 6 +++--- .../boards/adafruit_feather_esp32s2_reverse_tft/board.c | 6 +++--- .../espressif/boards/adafruit_feather_esp32s2_tft/board.c | 6 +++--- .../boards/adafruit_feather_esp32s3_reverse_tft/board.c | 6 +++--- .../espressif/boards/adafruit_feather_esp32s3_tft/board.c | 6 +++--- ports/espressif/boards/adafruit_funhouse/board.c | 6 +++--- .../boards/adafruit_magtag_2.9_grayscale/board.c | 6 +++--- ports/espressif/boards/elecrow_crowpanel_3.5/board.c | 4 ++-- .../espressif/boards/elecrow_crowpanel_4_2_epaper/board.c | 6 +++--- ports/espressif/boards/espressif_esp32s3_box/board.c | 6 +++--- ports/espressif/boards/espressif_esp32s3_box_lite/board.c | 6 +++--- ports/espressif/boards/espressif_esp32s3_eye/board.c | 4 ++-- .../espressif/boards/espressif_esp32s3_usb_otg_n8/board.c | 6 +++--- ports/espressif/boards/hardkernel_odroid_go/board.c | 4 ++-- ports/espressif/boards/heltec_vision_master_e290/board.c | 6 +++--- ports/espressif/boards/heltec_wireless_paper/board.c | 6 +++--- ports/espressif/boards/hexky_s2/board.c | 6 +++--- ports/espressif/boards/hiibot_iots2/board.c | 4 ++-- ports/espressif/boards/lilygo_tdeck/board.c | 4 ++-- ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c | 6 +++--- ports/espressif/boards/lilygo_tdongle_s3/board.c | 6 +++--- ports/espressif/boards/lilygo_tembed_esp32s3/board.c | 6 +++--- ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c | 6 +++--- ports/espressif/boards/lilygo_tqt_pro_psram/board.c | 6 +++--- ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c | 6 +++--- .../boards/lilygo_ttgo_tdisplay_esp32_16m/board.c | 6 +++--- .../boards/lilygo_ttgo_tdisplay_esp32_4m/board.c | 6 +++--- ports/espressif/boards/lilygo_twatch_2020_v3/board.c | 4 ++-- ports/espressif/boards/lilygo_twatch_s3/board.c | 4 ++-- ports/espressif/boards/lolin_s3_mini_pro/board.c | 6 +++--- ports/espressif/boards/m5stack_atoms3/board.c | 6 +++--- ports/espressif/boards/m5stack_cardputer/board.c | 6 +++--- ports/espressif/boards/m5stack_cardputer_ros/board.c | 6 +++--- ports/espressif/boards/m5stack_core2/board.c | 6 +++--- ports/espressif/boards/m5stack_core_basic/board.c | 6 +++--- ports/espressif/boards/m5stack_core_fire/board.c | 6 +++--- ports/espressif/boards/m5stack_cores3/board.c | 6 +++--- ports/espressif/boards/m5stack_dial/board.c | 6 +++--- ports/espressif/boards/m5stack_dinmeter/board.c | 6 +++--- ports/espressif/boards/m5stack_stick_c/board.c | 6 +++--- ports/espressif/boards/m5stack_stick_c_plus/board.c | 6 +++--- ports/espressif/boards/m5stack_stick_c_plus2/board.c | 6 +++--- ports/espressif/boards/morpheans_morphesp-240/board.c | 6 +++--- ports/espressif/boards/oxocard_artwork/board.c | 6 +++--- ports/espressif/boards/oxocard_connect/board.c | 6 +++--- ports/espressif/boards/oxocard_galaxy/board.c | 6 +++--- ports/espressif/boards/oxocard_science/board.c | 6 +++--- ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c | 6 +++--- ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c | 6 +++--- ports/espressif/boards/sqfmi_watchy/board.c | 6 +++--- ports/espressif/boards/sunton_esp32_2424S012/board.c | 6 +++--- ports/espressif/boards/sunton_esp32_2432S024C/board.c | 6 +++--- ports/espressif/boards/sunton_esp32_2432S028/board.c | 6 +++--- ports/espressif/boards/sunton_esp32_2432S032C/board.c | 6 +++--- ports/espressif/boards/vidi_x/board.c | 6 +++--- .../espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c | 6 +++--- .../espressif/boards/waveshare_esp32_s2_pico_lcd/board.c | 6 +++--- ports/espressif/boards/waveshare_esp32_s3_geek/board.c | 6 +++--- .../espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c | 6 +++--- .../espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c | 6 +++--- .../boards/waveshare_esp32_s3_touch_lcd_1_47/board.c | 6 +++--- .../boards/waveshare_esp32_s3_touch_lcd_2/board.c | 6 +++--- .../boards/waveshare_esp32_s3_touch_lcd_2_8/board.c | 6 +++--- ports/nordic/boards/clue_nrf52840_express/board.c | 6 +++--- ports/nordic/boards/hiibot_bluefi/board.c | 6 +++--- ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c | 6 +++--- ports/nordic/boards/ohs2020_badge/board.c | 6 +++--- ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c | 6 +++--- ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c | 8 ++++---- .../boards/bradanlanestudio_explorer_rp2040/board.c | 6 +++--- ports/raspberrypi/boards/hack_club_sprig/board.c | 6 +++--- ports/raspberrypi/boards/heiafr_picomo_v2/board.c | 6 +++--- ports/raspberrypi/boards/heiafr_picomo_v3/board.c | 6 +++--- ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c | 6 +++--- ports/raspberrypi/boards/pajenicko_picopad/board.c | 6 +++--- ports/raspberrypi/boards/pimoroni_badger2040/board.c | 6 +++--- ports/raspberrypi/boards/pimoroni_badger2040w/board.c | 6 +++--- ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c | 6 +++--- ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c | 6 +++--- ports/raspberrypi/boards/pimoroni_picosystem/board.c | 6 +++--- ports/raspberrypi/boards/ugame22/board.c | 6 +++--- ports/raspberrypi/boards/waveshare_rp2040_geek/board.c | 6 +++--- .../raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c | 6 +++--- ports/raspberrypi/boards/waveshare_rp2350_geek/board.c | 6 +++--- .../raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c | 6 +++--- ports/stm/boards/meowbit_v121/board.c | 6 +++--- 96 files changed, 282 insertions(+), 282 deletions(-) diff --git a/ports/atmel-samd/boards/hallowing_m0_express/board.c b/ports/atmel-samd/boards/hallowing_m0_express/board.c index 637129a0e9d..fd5ad548512 100644 --- a/ports/atmel-samd/boards/hallowing_m0_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m0_express/board.c @@ -54,9 +54,9 @@ void board_init(void) { common_hal_busio_spi_never_reset(spi); common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA28, // Command or data - &pin_PA01, // Chip select - &pin_PA27, // Reset + MP_OBJ_FROM_PTR(&pin_PA28), // Command or data + MP_OBJ_FROM_PTR(&pin_PA01), // Chip select + MP_OBJ_FROM_PTR(&pin_PA27), // Reset 12000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/hallowing_m4_express/board.c b/ports/atmel-samd/boards/hallowing_m4_express/board.c index bfef5fbcd75..c7217b70b0a 100644 --- a/ports/atmel-samd/boards/hallowing_m4_express/board.c +++ b/ports/atmel-samd/boards/hallowing_m4_express/board.c @@ -35,9 +35,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PB31, // TFT_DC Command or data - &pin_PA27, // TFT_CS Chip select - &pin_PB30, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PB31), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PA27), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PB30), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/monster_m4sk/board.c b/ports/atmel-samd/boards/monster_m4sk/board.c index 1d4fd69b7f7..1c143ad9270 100644 --- a/ports/atmel-samd/boards/monster_m4sk/board.c +++ b/ports/atmel-samd/boards/monster_m4sk/board.c @@ -35,9 +35,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA07, // TFT_DC Command or data - &pin_PA06, // TFT_CS Chip select - &pin_PA04, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PA07), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PA06), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA04), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/openbook_m4/board.c b/ports/atmel-samd/boards/openbook_m4/board.c index fb75cac3a4e..ebabfb84e9b 100644 --- a/ports/atmel-samd/boards/openbook_m4/board.c +++ b/ports/atmel-samd/boards/openbook_m4/board.c @@ -44,9 +44,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PB05, // EPD_DC Command or data - &pin_PB07, // EPD_CS Chip select - &pin_PA00, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_PB05), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_PB07), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA00), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/pewpew_lcd/board.c b/ports/atmel-samd/boards/pewpew_lcd/board.c index 6a10132e11d..d60efd39bf7 100644 --- a/ports/atmel-samd/boards/pewpew_lcd/board.c +++ b/ports/atmel-samd/boards/pewpew_lcd/board.c @@ -54,9 +54,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA19, // TFT_DC Command or data - &pin_PA17, // TFT_CS Chip select - &pin_PA18, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PA19), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PA17), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA18), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/pewpew_m4/board.c b/ports/atmel-samd/boards/pewpew_m4/board.c index 2007d755c69..ac67b82a3dc 100644 --- a/ports/atmel-samd/boards/pewpew_m4/board.c +++ b/ports/atmel-samd/boards/pewpew_m4/board.c @@ -83,9 +83,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA16, // TFT_DC Command or data - &pin_PA11, // TFT_CS Chip select - &pin_PA17, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PA16), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PA11), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA17), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/pybadge/board.c b/ports/atmel-samd/boards/pybadge/board.c index 545918374e2..e938e96e19e 100644 --- a/ports/atmel-samd/boards/pybadge/board.c +++ b/ports/atmel-samd/boards/pybadge/board.c @@ -56,9 +56,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PB05, // TFT_DC Command or data - &pin_PB07, // TFT_CS Chip select - &pin_PA00, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PB05), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PB07), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA00), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/pygamer/board.c b/ports/atmel-samd/boards/pygamer/board.c index 53275ac686a..fcf6aff0e65 100644 --- a/ports/atmel-samd/boards/pygamer/board.c +++ b/ports/atmel-samd/boards/pygamer/board.c @@ -57,9 +57,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PB05, // TFT_DC Command or data - &pin_PB12, // TFT_CS Chip select - &pin_PA00, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PB05), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PB12), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PA00), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c index d3d1ae3a956..1ee80c98786 100644 --- a/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c +++ b/ports/atmel-samd/boards/seeeduino_wio_terminal/board.c @@ -52,9 +52,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PC06, // TFT_DC Command or data - &pin_PB21, // TFT_CS Chip select - &pin_PC07, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_PC06), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_PB21), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_PC07), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/atmel-samd/boards/ugame10/board.c b/ports/atmel-samd/boards/ugame10/board.c index bbf3839c516..78d03a3fd9a 100644 --- a/ports/atmel-samd/boards/ugame10/board.c +++ b/ports/atmel-samd/boards/ugame10/board.c @@ -53,9 +53,9 @@ void board_init(void) { busio_spi_obj_t *spi = common_hal_board_create_spi(0); common_hal_fourwire_fourwire_construct(bus, spi, - &pin_PA09, // Command or data - &pin_PA08, // Chip select - NULL, // Reset + MP_OBJ_FROM_PTR(&pin_PA09), // Command or data + MP_OBJ_FROM_PTR(&pin_PA08), // Chip select + MP_OBJ_NULL, // Reset 24000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/adafruit_esp32s3_camera/board.c b/ports/espressif/boards/adafruit_esp32s3_camera/board.c index e0c357f04c8..d8b0832d3d0 100644 --- a/ports/espressif/boards/adafruit_esp32s3_camera/board.c +++ b/ports/espressif/boards/adafruit_esp32s3_camera/board.c @@ -37,9 +37,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO40, // TFT_DC Command or data - &pin_GPIO39, // TFT_CS Chip select - &pin_GPIO38, // TFT_RESET Reset + MP_OBJ_FROM_PTR(&pin_GPIO40), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO39), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO38), // TFT_RESET Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/board.c b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/board.c index e554be121db..1fe3fd62800 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32s2_reverse_tft/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO40, // DC - &pin_GPIO42, // CS - &pin_GPIO41, // RST + MP_OBJ_FROM_PTR(&pin_GPIO40), // DC + MP_OBJ_FROM_PTR(&pin_GPIO42), // CS + MP_OBJ_FROM_PTR(&pin_GPIO41), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/adafruit_feather_esp32s2_tft/board.c b/ports/espressif/boards/adafruit_feather_esp32s2_tft/board.c index 1ebb357aed5..22af4caa652 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s2_tft/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32s2_tft/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO39, // DC - &pin_GPIO7, // CS - &pin_GPIO40, // RST + MP_OBJ_FROM_PTR(&pin_GPIO39), // DC + MP_OBJ_FROM_PTR(&pin_GPIO7), // CS + MP_OBJ_FROM_PTR(&pin_GPIO40), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/board.c b/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/board.c index e554be121db..1fe3fd62800 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32s3_reverse_tft/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO40, // DC - &pin_GPIO42, // CS - &pin_GPIO41, // RST + MP_OBJ_FROM_PTR(&pin_GPIO40), // DC + MP_OBJ_FROM_PTR(&pin_GPIO42), // CS + MP_OBJ_FROM_PTR(&pin_GPIO41), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/adafruit_feather_esp32s3_tft/board.c b/ports/espressif/boards/adafruit_feather_esp32s3_tft/board.c index e3569d864e7..587c742a64f 100644 --- a/ports/espressif/boards/adafruit_feather_esp32s3_tft/board.c +++ b/ports/espressif/boards/adafruit_feather_esp32s3_tft/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO39, // DC - &pin_GPIO7, // CS - &pin_GPIO40, // RST + MP_OBJ_FROM_PTR(&pin_GPIO39), // DC + MP_OBJ_FROM_PTR(&pin_GPIO7), // CS + MP_OBJ_FROM_PTR(&pin_GPIO40), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/adafruit_funhouse/board.c b/ports/espressif/boards/adafruit_funhouse/board.c index 061a6abf0d8..83499f5a492 100644 --- a/ports/espressif/boards/adafruit_funhouse/board.c +++ b/ports/espressif/boards/adafruit_funhouse/board.c @@ -37,9 +37,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO39, // TFT_DC Command or data - &pin_GPIO40, // TFT_CS Chip select - &pin_GPIO41, // TFT_RESET Reset + MP_OBJ_FROM_PTR(&pin_GPIO39), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO40), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO41), // TFT_RESET Reset 5000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index d37233b7f24..dc117deee63 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -206,9 +206,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO7, // EPD_DC Command or data - &pin_GPIO8, // EPD_CS Chip select - &pin_GPIO6, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO7), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO8), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO6), // EPD_RST Reset 4000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/elecrow_crowpanel_3.5/board.c b/ports/espressif/boards/elecrow_crowpanel_3.5/board.c index 3adfb512e3f..0748e03fce8 100755 --- a/ports/espressif/boards/elecrow_crowpanel_3.5/board.c +++ b/ports/espressif/boards/elecrow_crowpanel_3.5/board.c @@ -54,8 +54,8 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO2, // TFT_DC Command or data - &pin_GPIO15, // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select NULL, // TFT_RST Reset 20000000, // Baudrate 0, // Polarity diff --git a/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c b/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c index 04f5f92f85b..c292ea113aa 100644 --- a/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c +++ b/ports/espressif/boards/elecrow_crowpanel_4_2_epaper/board.c @@ -56,9 +56,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO46, // EPD_DC Command or data - &pin_GPIO45, // EPD_CS Chip select - &pin_GPIO47, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO46), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO45), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO47), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/espressif_esp32s3_box/board.c b/ports/espressif/boards/espressif_esp32s3_box/board.c index 54edb47bac3..a27411fd79c 100644 --- a/ports/espressif/boards/espressif_esp32s3_box/board.c +++ b/ports/espressif/boards/espressif_esp32s3_box/board.c @@ -31,9 +31,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO48, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO48), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/espressif_esp32s3_box_lite/board.c b/ports/espressif/boards/espressif_esp32s3_box_lite/board.c index e675c0f915b..48a49e03bc3 100644 --- a/ports/espressif/boards/espressif_esp32s3_box_lite/board.c +++ b/ports/espressif/boards/espressif_esp32s3_box_lite/board.c @@ -32,9 +32,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO48, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO48), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/espressif_esp32s3_eye/board.c b/ports/espressif/boards/espressif_esp32s3_eye/board.c index c48c9428cf4..09a05cc72c4 100644 --- a/ports/espressif/boards/espressif_esp32s3_eye/board.c +++ b/ports/espressif/boards/espressif_esp32s3_eye/board.c @@ -56,8 +56,8 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO43, // DC - &pin_GPIO44, // CS + MP_OBJ_FROM_PTR(&pin_GPIO43), // DC + MP_OBJ_FROM_PTR(&pin_GPIO44), // CS NULL, // no reset pin 40000000, // baudrate 0, // polarity diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c index 94d08bb56c8..3b5aa06b676 100644 --- a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c +++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c @@ -59,9 +59,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO8, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO8), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/hardkernel_odroid_go/board.c b/ports/espressif/boards/hardkernel_odroid_go/board.c index 647fcd740eb..5a8b6ccaefe 100644 --- a/ports/espressif/boards/hardkernel_odroid_go/board.c +++ b/ports/espressif/boards/hardkernel_odroid_go/board.c @@ -51,8 +51,8 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO21, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO21), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select NULL, // TFT_RST Reset 40000000, // Baudrate 0, // Polarity diff --git a/ports/espressif/boards/heltec_vision_master_e290/board.c b/ports/espressif/boards/heltec_vision_master_e290/board.c index 9749f5c7048..5a102c7119b 100644 --- a/ports/espressif/boards/heltec_vision_master_e290/board.c +++ b/ports/espressif/boards/heltec_vision_master_e290/board.c @@ -54,9 +54,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // EPD_DC Command or data - &pin_GPIO3, // EPD_CS Chip select - &pin_GPIO5, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO3), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO5), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/heltec_wireless_paper/board.c b/ports/espressif/boards/heltec_wireless_paper/board.c index c796a9be884..38f6472e085 100644 --- a/ports/espressif/boards/heltec_wireless_paper/board.c +++ b/ports/espressif/boards/heltec_wireless_paper/board.c @@ -94,9 +94,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO5, // EPD_DC Command or data - &pin_GPIO4, // EPD_CS Chip select - &pin_GPIO6, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO5), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO4), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO6), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/hexky_s2/board.c b/ports/espressif/boards/hexky_s2/board.c index c1e1801fed6..41f97796be4 100644 --- a/ports/espressif/boards/hexky_s2/board.c +++ b/ports/espressif/boards/hexky_s2/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO34, // DC - &pin_GPIO33, // CS - &pin_GPIO41, // RST + MP_OBJ_FROM_PTR(&pin_GPIO34), // DC + MP_OBJ_FROM_PTR(&pin_GPIO33), // CS + MP_OBJ_FROM_PTR(&pin_GPIO41), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/hiibot_iots2/board.c b/ports/espressif/boards/hiibot_iots2/board.c index e9941cbc368..e4bff05822c 100644 --- a/ports/espressif/boards/hiibot_iots2/board.c +++ b/ports/espressif/boards/hiibot_iots2/board.c @@ -62,8 +62,8 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO35, // DC - &pin_GPIO36, // CS + MP_OBJ_FROM_PTR(&pin_GPIO35), // DC + MP_OBJ_FROM_PTR(&pin_GPIO36), // CS NULL, // NO RST ? 40000000, // baudrate 0, // polarity diff --git a/ports/espressif/boards/lilygo_tdeck/board.c b/ports/espressif/boards/lilygo_tdeck/board.c index 91a2f6d2ad7..a1008f2173f 100644 --- a/ports/espressif/boards/lilygo_tdeck/board.c +++ b/ports/espressif/boards/lilygo_tdeck/board.c @@ -32,8 +32,8 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO11, // TFT_DC Command or data - &pin_GPIO12, // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO11), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO12), // TFT_CS Chip select NULL, // TFT_RST Reset 60000000, // Baudrate 0, // Polarity diff --git a/ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c b/ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c index ede20df200f..0782e2161ca 100644 --- a/ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c +++ b/ports/espressif/boards/lilygo_tdisplay_s3_pro/board.c @@ -34,9 +34,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO9, // TFT_DC Command or data - &pin_GPIO39, // TFT_CS Chip select - &pin_GPIO47, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO39), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO47), // TFT_RST Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/lilygo_tdongle_s3/board.c b/ports/espressif/boards/lilygo_tdongle_s3/board.c index 8907dc7fe98..ede75a5842e 100644 --- a/ports/espressif/boards/lilygo_tdongle_s3/board.c +++ b/ports/espressif/boards/lilygo_tdongle_s3/board.c @@ -60,9 +60,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO2, // DC - &pin_GPIO4, // CS - &pin_GPIO1, // RST + MP_OBJ_FROM_PTR(&pin_GPIO2), // DC + MP_OBJ_FROM_PTR(&pin_GPIO4), // CS + MP_OBJ_FROM_PTR(&pin_GPIO1), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_tembed_esp32s3/board.c b/ports/espressif/boards/lilygo_tembed_esp32s3/board.c index 698e6980ece..46e2ecf863c 100644 --- a/ports/espressif/boards/lilygo_tembed_esp32s3/board.c +++ b/ports/espressif/boards/lilygo_tembed_esp32s3/board.c @@ -32,9 +32,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO13, // TFT_DC Command or data - &pin_GPIO10, // TFT_CS Chip select - &pin_GPIO9, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO13), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO10), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c b/ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c index c7e711aee66..fe72222a22c 100644 --- a/ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c +++ b/ports/espressif/boards/lilygo_tqt_pro_nopsram/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO6, // DC - &pin_GPIO5, // CS - &pin_GPIO1, // RST + MP_OBJ_FROM_PTR(&pin_GPIO6), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO1), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_tqt_pro_psram/board.c b/ports/espressif/boards/lilygo_tqt_pro_psram/board.c index c7e711aee66..fe72222a22c 100644 --- a/ports/espressif/boards/lilygo_tqt_pro_psram/board.c +++ b/ports/espressif/boards/lilygo_tqt_pro_psram/board.c @@ -57,9 +57,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO6, // DC - &pin_GPIO5, // CS - &pin_GPIO1, // RST + MP_OBJ_FROM_PTR(&pin_GPIO6), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO1), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c b/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c index 2b77e24b91e..6fcfb5c19a4 100644 --- a/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c +++ b/ports/espressif/boards/lilygo_ttgo_t8_s2_st7789/board.c @@ -62,9 +62,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO37, // DC - &pin_GPIO34, // CS - &pin_GPIO38, // RST + MP_OBJ_FROM_PTR(&pin_GPIO37), // DC + MP_OBJ_FROM_PTR(&pin_GPIO34), // CS + MP_OBJ_FROM_PTR(&pin_GPIO38), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_16m/board.c b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_16m/board.c index 97574398ca2..8ed5462a2d3 100644 --- a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_16m/board.c +++ b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_16m/board.c @@ -42,9 +42,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO16, // DC - &pin_GPIO5, // CS - &pin_GPIO23, // RST + MP_OBJ_FROM_PTR(&pin_GPIO16), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO23), // RST 24000000, // baudrate (default from the driver) // 40000000, 0, // polarity diff --git a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/board.c b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/board.c index 2d3cb64d455..a90cc5eb66a 100644 --- a/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/board.c +++ b/ports/espressif/boards/lilygo_ttgo_tdisplay_esp32_4m/board.c @@ -41,9 +41,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO16, // DC - &pin_GPIO5, // CS - &pin_GPIO23, // RST + MP_OBJ_FROM_PTR(&pin_GPIO16), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO23), // RST 24000000, // baudrate (default from the driver) // 40000000, 0, // polarity diff --git a/ports/espressif/boards/lilygo_twatch_2020_v3/board.c b/ports/espressif/boards/lilygo_twatch_2020_v3/board.c index 266515c2338..e88a82ea24f 100644 --- a/ports/espressif/boards/lilygo_twatch_2020_v3/board.c +++ b/ports/espressif/boards/lilygo_twatch_2020_v3/board.c @@ -46,8 +46,8 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO5, // CS + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS NULL, // RST 24000000, // baudrate 0, // polarity diff --git a/ports/espressif/boards/lilygo_twatch_s3/board.c b/ports/espressif/boards/lilygo_twatch_s3/board.c index 51f5933d177..801914a4991 100644 --- a/ports/espressif/boards/lilygo_twatch_s3/board.c +++ b/ports/espressif/boards/lilygo_twatch_s3/board.c @@ -108,8 +108,8 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO38, // DC - &pin_GPIO12, // CS + MP_OBJ_FROM_PTR(&pin_GPIO38), // DC + MP_OBJ_FROM_PTR(&pin_GPIO12), // CS NULL, // RST 40000000, // baudrate 0, // polarity diff --git a/ports/espressif/boards/lolin_s3_mini_pro/board.c b/ports/espressif/boards/lolin_s3_mini_pro/board.c index cd5a083dbdb..39e645bc7b5 100644 --- a/ports/espressif/boards/lolin_s3_mini_pro/board.c +++ b/ports/espressif/boards/lolin_s3_mini_pro/board.c @@ -39,9 +39,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO36, // DC - &pin_GPIO35, // CS - &pin_GPIO34, // RST + MP_OBJ_FROM_PTR(&pin_GPIO36), // DC + MP_OBJ_FROM_PTR(&pin_GPIO35), // CS + MP_OBJ_FROM_PTR(&pin_GPIO34), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_atoms3/board.c b/ports/espressif/boards/m5stack_atoms3/board.c index df620976b61..3dbd8a1a2b8 100644 --- a/ports/espressif/boards/m5stack_atoms3/board.c +++ b/ports/espressif/boards/m5stack_atoms3/board.c @@ -39,9 +39,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO33, // DC - &pin_GPIO15, // CS - &pin_GPIO34, // RST + MP_OBJ_FROM_PTR(&pin_GPIO33), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO34), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cardputer/board.c b/ports/espressif/boards/m5stack_cardputer/board.c index 6fdc2f8ea5c..00630cd36d2 100644 --- a/ports/espressif/boards/m5stack_cardputer/board.c +++ b/ports/espressif/boards/m5stack_cardputer/board.c @@ -50,9 +50,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO34, // DC - &pin_GPIO37, // CS - &pin_GPIO33, // RST + MP_OBJ_FROM_PTR(&pin_GPIO34), // DC + MP_OBJ_FROM_PTR(&pin_GPIO37), // CS + MP_OBJ_FROM_PTR(&pin_GPIO33), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cardputer_ros/board.c b/ports/espressif/boards/m5stack_cardputer_ros/board.c index 6fdc2f8ea5c..00630cd36d2 100644 --- a/ports/espressif/boards/m5stack_cardputer_ros/board.c +++ b/ports/espressif/boards/m5stack_cardputer_ros/board.c @@ -50,9 +50,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO34, // DC - &pin_GPIO37, // CS - &pin_GPIO33, // RST + MP_OBJ_FROM_PTR(&pin_GPIO34), // DC + MP_OBJ_FROM_PTR(&pin_GPIO37), // CS + MP_OBJ_FROM_PTR(&pin_GPIO33), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_core2/board.c b/ports/espressif/boards/m5stack_core2/board.c index 9d5c2bd650a..2d63436235a 100644 --- a/ports/espressif/boards/m5stack_core2/board.c +++ b/ports/espressif/boards/m5stack_core2/board.c @@ -318,9 +318,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO15, // DC - &pin_GPIO5, // CS - NULL, // RST + MP_OBJ_FROM_PTR(&pin_GPIO15), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_NULL, // RST 32000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_core_basic/board.c b/ports/espressif/boards/m5stack_core_basic/board.c index 4ae128817a1..5a18d33e527 100644 --- a/ports/espressif/boards/m5stack_core_basic/board.c +++ b/ports/espressif/boards/m5stack_core_basic/board.c @@ -42,9 +42,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO14, // CS - &pin_GPIO33, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO14), // CS + MP_OBJ_FROM_PTR(&pin_GPIO33), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_core_fire/board.c b/ports/espressif/boards/m5stack_core_fire/board.c index 4ae128817a1..5a18d33e527 100644 --- a/ports/espressif/boards/m5stack_core_fire/board.c +++ b/ports/espressif/boards/m5stack_core_fire/board.c @@ -42,9 +42,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO14, // CS - &pin_GPIO33, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO14), // CS + MP_OBJ_FROM_PTR(&pin_GPIO33), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cores3/board.c b/ports/espressif/boards/m5stack_cores3/board.c index f49d6349997..c14be4ae0d1 100644 --- a/ports/espressif/boards/m5stack_cores3/board.c +++ b/ports/espressif/boards/m5stack_cores3/board.c @@ -45,9 +45,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO35, // DC - &pin_GPIO3, // CS - NULL, // RST + MP_OBJ_FROM_PTR(&pin_GPIO35), // DC + MP_OBJ_FROM_PTR(&pin_GPIO3), // CS + MP_OBJ_NULL, // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_dial/board.c b/ports/espressif/boards/m5stack_dial/board.c index 4e7cf4b0240..6214255612b 100644 --- a/ports/espressif/boards/m5stack_dial/board.c +++ b/ports/espressif/boards/m5stack_dial/board.c @@ -49,9 +49,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO4, // DC - &pin_GPIO7, // CS - &pin_GPIO8, // RST + MP_OBJ_FROM_PTR(&pin_GPIO4), // DC + MP_OBJ_FROM_PTR(&pin_GPIO7), // CS + MP_OBJ_FROM_PTR(&pin_GPIO8), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_dinmeter/board.c b/ports/espressif/boards/m5stack_dinmeter/board.c index cd49318fd1c..37fafa994dc 100644 --- a/ports/espressif/boards/m5stack_dinmeter/board.c +++ b/ports/espressif/boards/m5stack_dinmeter/board.c @@ -51,9 +51,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO4, // DC - &pin_GPIO7, // CS - &pin_GPIO8, // RST + MP_OBJ_FROM_PTR(&pin_GPIO4), // DC + MP_OBJ_FROM_PTR(&pin_GPIO7), // CS + MP_OBJ_FROM_PTR(&pin_GPIO8), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_stick_c/board.c b/ports/espressif/boards/m5stack_stick_c/board.c index 641d2d1db7e..491ddead860 100644 --- a/ports/espressif/boards/m5stack_stick_c/board.c +++ b/ports/espressif/boards/m5stack_stick_c/board.c @@ -154,9 +154,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO23, // DC - &pin_GPIO5, // CS - &pin_GPIO18, // RST + MP_OBJ_FROM_PTR(&pin_GPIO23), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO18), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_stick_c_plus/board.c b/ports/espressif/boards/m5stack_stick_c_plus/board.c index eec6a208260..8902521db8e 100644 --- a/ports/espressif/boards/m5stack_stick_c_plus/board.c +++ b/ports/espressif/boards/m5stack_stick_c_plus/board.c @@ -154,9 +154,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO23, // DC - &pin_GPIO5, // CS - &pin_GPIO18, // RST + MP_OBJ_FROM_PTR(&pin_GPIO23), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO18), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_stick_c_plus2/board.c b/ports/espressif/boards/m5stack_stick_c_plus2/board.c index a50e38df09e..d84faa1888d 100644 --- a/ports/espressif/boards/m5stack_stick_c_plus2/board.c +++ b/ports/espressif/boards/m5stack_stick_c_plus2/board.c @@ -50,9 +50,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO14, // DC - &pin_GPIO5, // CS - &pin_GPIO12, // RST + MP_OBJ_FROM_PTR(&pin_GPIO14), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/morpheans_morphesp-240/board.c b/ports/espressif/boards/morpheans_morphesp-240/board.c index 5b1c3f82bbb..44266cce6ed 100644 --- a/ports/espressif/boards/morpheans_morphesp-240/board.c +++ b/ports/espressif/boards/morpheans_morphesp-240/board.c @@ -138,9 +138,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO14, // DC - &pin_GPIO10, // CS - &pin_GPIO9, // RST + MP_OBJ_FROM_PTR(&pin_GPIO14), // DC + MP_OBJ_FROM_PTR(&pin_GPIO10), // CS + MP_OBJ_FROM_PTR(&pin_GPIO9), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/oxocard_artwork/board.c b/ports/espressif/boards/oxocard_artwork/board.c index a27cdb7003b..5fe8e814558 100644 --- a/ports/espressif/boards/oxocard_artwork/board.c +++ b/ports/espressif/boards/oxocard_artwork/board.c @@ -43,9 +43,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO15, // CS - &pin_GPIO4, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO4), // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/oxocard_connect/board.c b/ports/espressif/boards/oxocard_connect/board.c index 89be45c8226..2c013811474 100644 --- a/ports/espressif/boards/oxocard_connect/board.c +++ b/ports/espressif/boards/oxocard_connect/board.c @@ -44,9 +44,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO15, // CS - &pin_GPIO4, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO4), // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/oxocard_galaxy/board.c b/ports/espressif/boards/oxocard_galaxy/board.c index a27cdb7003b..5fe8e814558 100644 --- a/ports/espressif/boards/oxocard_galaxy/board.c +++ b/ports/espressif/boards/oxocard_galaxy/board.c @@ -43,9 +43,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO15, // CS - &pin_GPIO4, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO4), // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/oxocard_science/board.c b/ports/espressif/boards/oxocard_science/board.c index a27cdb7003b..5fe8e814558 100644 --- a/ports/espressif/boards/oxocard_science/board.c +++ b/ports/espressif/boards/oxocard_science/board.c @@ -43,9 +43,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO27, // DC - &pin_GPIO15, // CS - &pin_GPIO4, // RST + MP_OBJ_FROM_PTR(&pin_GPIO27), // DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // CS + MP_OBJ_FROM_PTR(&pin_GPIO4), // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c b/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c index 89bcbf6b8dd..f4288ae45ac 100644 --- a/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c +++ b/ports/espressif/boards/spotpear_esp32c3_lcd_1_44/board.c @@ -42,9 +42,9 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO0, // DC - &pin_GPIO2, // CS - &pin_GPIO5, // RST + MP_OBJ_FROM_PTR(&pin_GPIO0), // DC + MP_OBJ_FROM_PTR(&pin_GPIO2), // CS + MP_OBJ_FROM_PTR(&pin_GPIO5), // RST 10000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c b/ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c index 6299402e8e0..30879e71404 100644 --- a/ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c +++ b/ports/espressif/boards/spotpear_esp32c3_lcd_1_69/board.c @@ -39,9 +39,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO2, // DC - &pin_GPIO3, // CS - &pin_GPIO10, // RST + MP_OBJ_FROM_PTR(&pin_GPIO2), // DC + MP_OBJ_FROM_PTR(&pin_GPIO3), // CS + MP_OBJ_FROM_PTR(&pin_GPIO10), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/sqfmi_watchy/board.c b/ports/espressif/boards/sqfmi_watchy/board.c index 297190b53e2..9cea4e98095 100644 --- a/ports/espressif/boards/sqfmi_watchy/board.c +++ b/ports/espressif/boards/sqfmi_watchy/board.c @@ -150,9 +150,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO10, // EPD_DC Command or data - &pin_GPIO5, // EPD_CS Chip select - &pin_GPIO9, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO10), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO9), // EPD_RST Reset 2000000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/espressif/boards/sunton_esp32_2424S012/board.c b/ports/espressif/boards/sunton_esp32_2424S012/board.c index c313ded8637..731694a4e1b 100644 --- a/ports/espressif/boards/sunton_esp32_2424S012/board.c +++ b/ports/espressif/boards/sunton_esp32_2424S012/board.c @@ -105,9 +105,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO2, // DC - &pin_GPIO10, // CS - NULL, // RST + MP_OBJ_FROM_PTR(&pin_GPIO2), // DC + MP_OBJ_FROM_PTR(&pin_GPIO10), // CS + MP_OBJ_NULL, // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/sunton_esp32_2432S024C/board.c b/ports/espressif/boards/sunton_esp32_2432S024C/board.c index 8b4201d88e8..a43b5ad65a0 100644 --- a/ports/espressif/boards/sunton_esp32_2432S024C/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S024C/board.c @@ -50,9 +50,9 @@ static void display_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO2, // TFT_DC Command or data - &pin_GPIO15, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select + MP_OBJ_NULL, // TFT_RST Reset 6000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/sunton_esp32_2432S028/board.c b/ports/espressif/boards/sunton_esp32_2432S028/board.c index b249c45dd8f..7380e252410 100644 --- a/ports/espressif/boards/sunton_esp32_2432S028/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S028/board.c @@ -50,9 +50,9 @@ static void display_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO2, // TFT_DC Command or data - &pin_GPIO15, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select + MP_OBJ_NULL, // TFT_RST Reset 6000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/sunton_esp32_2432S032C/board.c b/ports/espressif/boards/sunton_esp32_2432S032C/board.c index b2160e0aa4f..48e206040d8 100644 --- a/ports/espressif/boards/sunton_esp32_2432S032C/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S032C/board.c @@ -43,9 +43,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO2, // TFT_DC - &pin_GPIO15, // TFT_CS - NULL, // TFT_RST + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC + MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS + MP_OBJ_NULL, // TFT_RST 26600000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/espressif/boards/vidi_x/board.c b/ports/espressif/boards/vidi_x/board.c index e53dfd82ad9..7ba7094b917 100644 --- a/ports/espressif/boards/vidi_x/board.c +++ b/ports/espressif/boards/vidi_x/board.c @@ -51,9 +51,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO21, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO21), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_NULL, // TFT_RST Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c index 7dd0e0c0fa2..e56c096e403 100644 --- a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c +++ b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/board.c @@ -48,9 +48,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO15, // DC - &pin_GPIO14, // CS - &pin_GPIO21, // RST + MP_OBJ_FROM_PTR(&pin_GPIO15), // DC + MP_OBJ_FROM_PTR(&pin_GPIO14), // CS + MP_OBJ_FROM_PTR(&pin_GPIO21), // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/board.c b/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/board.c index cb6fb310338..0bf710ec34c 100644 --- a/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/board.c +++ b/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/board.c @@ -61,9 +61,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO18, // DC - &pin_GPIO9, // CS - &pin_GPIO21, // RST + MP_OBJ_FROM_PTR(&pin_GPIO18), // DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // CS + MP_OBJ_FROM_PTR(&pin_GPIO21), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_s3_geek/board.c b/ports/espressif/boards/waveshare_esp32_s3_geek/board.c index 414188fb46a..0ce44753264 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_geek/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_geek/board.c @@ -38,9 +38,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // TFT_DC - &pin_GPIO10, // TFT_CS - &pin_GPIO9, // TFT_RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // TFT_DC + MP_OBJ_FROM_PTR(&pin_GPIO10), // TFT_CS + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_RST 50000000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c index 36990c85566..ee47ccb0bc9 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/board.c @@ -105,9 +105,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // DC - &pin_GPIO9, // CS - &pin_GPIO12, // RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c index f3dd38522f7..4ecf87948ad 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/board.c @@ -48,9 +48,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO41, // DC - &pin_GPIO42, // CS - &pin_GPIO39, // RST + MP_OBJ_FROM_PTR(&pin_GPIO41), // DC + MP_OBJ_FROM_PTR(&pin_GPIO42), // CS + MP_OBJ_FROM_PTR(&pin_GPIO39), // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c index 4c037ce8df0..1bdd74e77ee 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/board.c @@ -94,9 +94,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO45, // DC - &pin_GPIO21, // CS - &pin_GPIO40, // RST + MP_OBJ_FROM_PTR(&pin_GPIO45), // DC + MP_OBJ_FROM_PTR(&pin_GPIO21), // CS + MP_OBJ_FROM_PTR(&pin_GPIO40), // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/board.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/board.c index e7a6b86440e..71e2d745623 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/board.c @@ -34,9 +34,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO42, // DC - &pin_GPIO45, // CS - &pin_GPIO0, // RST + MP_OBJ_FROM_PTR(&pin_GPIO42), // DC + MP_OBJ_FROM_PTR(&pin_GPIO45), // CS + MP_OBJ_FROM_PTR(&pin_GPIO0), // RST // 24000000, 40000000, // baudrate 0, // polarity diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c index deb764b80a5..49177f48fe7 100755 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/board.c @@ -34,9 +34,9 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO41, // DC - &pin_GPIO42, // CS - &pin_GPIO39, // RST + MP_OBJ_FROM_PTR(&pin_GPIO41), // DC + MP_OBJ_FROM_PTR(&pin_GPIO42), // CS + MP_OBJ_FROM_PTR(&pin_GPIO39), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/nordic/boards/clue_nrf52840_express/board.c b/ports/nordic/boards/clue_nrf52840_express/board.c index e2cd8a324ba..0b331b63a96 100644 --- a/ports/nordic/boards/clue_nrf52840_express/board.c +++ b/ports/nordic/boards/clue_nrf52840_express/board.c @@ -34,9 +34,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_P0_13, // TFT_DC Command or data - &pin_P0_12, // TFT_CS Chip select - &pin_P1_03, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_P0_13), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_P0_12), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_P1_03), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/nordic/boards/hiibot_bluefi/board.c b/ports/nordic/boards/hiibot_bluefi/board.c index 73430d675eb..7a681140ddb 100644 --- a/ports/nordic/boards/hiibot_bluefi/board.c +++ b/ports/nordic/boards/hiibot_bluefi/board.c @@ -34,9 +34,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_P0_27, // TFT_DC Command or data - &pin_P0_05, // TFT_CS Chip select - NULL, // no TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_P0_27), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_P0_05), // TFT_CS Chip select + MP_OBJ_NULL, // no TFT_RST Reset // &pin_P1_14, // TFT_RST Reset 60000000, // Baudrate 0, // Polarity diff --git a/ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c b/ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c index 64199b98009..4f9c051478a 100644 --- a/ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c +++ b/ports/nordic/boards/makerdiary_nrf52840_m2_devkit/board.c @@ -35,9 +35,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_P0_08, // TFT_DC Command or data - &pin_P0_06, // TFT_CS Chip select - &pin_P1_09, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_P0_08), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_P0_06), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_P1_09), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/nordic/boards/ohs2020_badge/board.c b/ports/nordic/boards/ohs2020_badge/board.c index ea716006cb4..d16d99473f0 100644 --- a/ports/nordic/boards/ohs2020_badge/board.c +++ b/ports/nordic/boards/ohs2020_badge/board.c @@ -34,9 +34,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_P0_08, // TFT_DC Command or data - &pin_P0_14, // TFT_CS Chip select - &pin_P0_13, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_P0_08), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_P0_14), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_P0_13), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c b/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c index 5056a4d9c7a..882bc9a1a9e 100644 --- a/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c +++ b/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c @@ -34,9 +34,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - CIRCUITPY_BOARD_TFT_DC, - CIRCUITPY_BOARD_TFT_CS, - NULL, // TFT_RESET Reset + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_DC), + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_CS), + MP_OBJ_NULL, // TFT_RESET Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c b/ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c index 673d9303d6b..ec37b398e22 100644 --- a/ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c +++ b/ports/raspberrypi/boards/adafruit_macropad_rp2040/board.c @@ -29,7 +29,7 @@ uint8_t display_init_sequence[] = { 0xda, 1, 0x12, // com pins 0x81, 1, 0xff, // contrast 255 0xd9, 1, 0x1f, // pre/dis-charge 2DCLKs/2CLKs - 0xdb, 1, 0x20, // VCOM deslect 0.770 + 0xdb, 1, 0x20, // VCOM select 0.770 0x20, 1, 0x20, 0x33, 0, // VPP 9V 0xa6, 0, // not inverted @@ -46,9 +46,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO24, // Command or data - &pin_GPIO22, // Chip select - &pin_GPIO23, // Reset + MP_OBJ_FROM_PTR(&pin_GPIO24), // Command or data + MP_OBJ_FROM_PTR(&pin_GPIO22), // Chip select + MP_OBJ_FROM_PTR(&pin_GPIO23), // Reset 10000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c index 35e128627bc..f091c4b05a8 100644 --- a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c +++ b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/board.c @@ -212,9 +212,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO11, // DEFAULT_SPI_BUS_DC, // EPD_DC Command or data - &pin_GPIO13, // DEFAULT_SPI_BUS_CS, // EPD_CS Chip select - &pin_GPIO10, // DEFAULT_SPI_BUS_RESET, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO11), // DEFAULT_SPI_BUS_DC, // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO13), // DEFAULT_SPI_BUS_CS, // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO10), // DEFAULT_SPI_BUS_RESET, // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/hack_club_sprig/board.c b/ports/raspberrypi/boards/hack_club_sprig/board.c index 40711c55445..94c5a7c5be9 100644 --- a/ports/raspberrypi/boards/hack_club_sprig/board.c +++ b/ports/raspberrypi/boards/hack_club_sprig/board.c @@ -62,9 +62,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - CIRCUITPY_BOARD_TFT_DC, - CIRCUITPY_BOARD_TFT_CS, - CIRCUITPY_BOARD_TFT_RESET, + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_DC), + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_CS), + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_RESET), 30000000, 0, 0); diff --git a/ports/raspberrypi/boards/heiafr_picomo_v2/board.c b/ports/raspberrypi/boards/heiafr_picomo_v2/board.c index 8c60341489f..3824c5959f5 100644 --- a/ports/raspberrypi/boards/heiafr_picomo_v2/board.c +++ b/ports/raspberrypi/boards/heiafr_picomo_v2/board.c @@ -51,9 +51,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO16, // TFT_DC Command or data - &pin_GPIO17, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO16), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // TFT_CS Chip select + MP_OBJ_NULL, // TFT_RST Reset 62500000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/heiafr_picomo_v3/board.c b/ports/raspberrypi/boards/heiafr_picomo_v3/board.c index 8c60341489f..3824c5959f5 100644 --- a/ports/raspberrypi/boards/heiafr_picomo_v3/board.c +++ b/ports/raspberrypi/boards/heiafr_picomo_v3/board.c @@ -51,9 +51,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO16, // TFT_DC Command or data - &pin_GPIO17, // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO16), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // TFT_CS Chip select + MP_OBJ_NULL, // TFT_RST Reset 62500000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c b/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c index 78cc912130e..67e63daed1d 100644 --- a/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c +++ b/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c @@ -63,9 +63,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO1, // DC - &pin_GPIO5, // CS - NULL, // RST (Reset pin tie to 0, do not set here) + MP_OBJ_FROM_PTR(&pin_GPIO1), // DC + MP_OBJ_FROM_PTR(&pin_GPIO5), // CS + MP_OBJ_NULL, // RST (Reset pin tie to 0, do not set here) 40000000, // baudrate 1, // polarity 0 // phase diff --git a/ports/raspberrypi/boards/pajenicko_picopad/board.c b/ports/raspberrypi/boards/pajenicko_picopad/board.c index 0ca13b3ec2e..d8f93922623 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/board.c +++ b/ports/raspberrypi/boards/pajenicko_picopad/board.c @@ -51,9 +51,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO17, // TFT_DC Command or data - &pin_GPIO21, // TFT_CS Chip select - &pin_GPIO20, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO17), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO21), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO20), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_badger2040/board.c b/ports/raspberrypi/boards/pimoroni_badger2040/board.c index 07cc512b9a5..80eddb49e13 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2040/board.c +++ b/ports/raspberrypi/boards/pimoroni_badger2040/board.c @@ -263,9 +263,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO20, // EPD_DC Command or data - &pin_GPIO17, // EPD_CS Chip select - &pin_GPIO21, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO20), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO21), // EPD_RST Reset 1200000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_badger2040w/board.c b/ports/raspberrypi/boards/pimoroni_badger2040w/board.c index b992bcd6a1e..ef5da7ceabc 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2040w/board.c +++ b/ports/raspberrypi/boards/pimoroni_badger2040w/board.c @@ -263,9 +263,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO20, // EPD_DC Command or data - &pin_GPIO17, // EPD_CS Chip select - &pin_GPIO21, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO20), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO21), // EPD_RST Reset 1200000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c index 4bf7518c6a8..58c54334d59 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/board.c @@ -58,9 +58,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO28, // EPD_DC Command or data - &pin_GPIO17, // EPD_CS Chip select - &pin_GPIO27, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO28), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO27), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c index 763a91a2555..fc6ca67f3ae 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_7_3/board.c @@ -117,9 +117,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO28, // EPD_DC Command or data - &pin_GPIO17, // EPD_CS Chip select - &pin_GPIO27, // EPD_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO28), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO27), // EPD_RST Reset 1000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/pimoroni_picosystem/board.c b/ports/raspberrypi/boards/pimoroni_picosystem/board.c index 40756b56426..e5956e43ed1 100644 --- a/ports/raspberrypi/boards/pimoroni_picosystem/board.c +++ b/ports/raspberrypi/boards/pimoroni_picosystem/board.c @@ -51,9 +51,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO9, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO4, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/ugame22/board.c b/ports/raspberrypi/boards/ugame22/board.c index 6b8152b14ee..ed17a13ebc1 100644 --- a/ports/raspberrypi/boards/ugame22/board.c +++ b/ports/raspberrypi/boards/ugame22/board.c @@ -52,9 +52,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - &pin_GPIO4, // TFT_DC Command or data - &pin_GPIO5, // TFT_CS Chip select - &pin_GPIO1, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO4), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO1), // TFT_RST Reset 80000000L, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/waveshare_rp2040_geek/board.c b/ports/raspberrypi/boards/waveshare_rp2040_geek/board.c index 71269f0d185..431840fb0c5 100644 --- a/ports/raspberrypi/boards/waveshare_rp2040_geek/board.c +++ b/ports/raspberrypi/boards/waveshare_rp2040_geek/board.c @@ -37,9 +37,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // TFT_DC - &pin_GPIO9, // TFT_CS - &pin_GPIO12, // TFT_RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // TFT_DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // TFT_RST 50000000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c b/ports/raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c index f17ca53d724..44d279da43f 100644 --- a/ports/raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c +++ b/ports/raspberrypi/boards/waveshare_rp2040_lcd_0_96/board.c @@ -60,9 +60,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // DC - &pin_GPIO9, // CS - &pin_GPIO12, // RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/raspberrypi/boards/waveshare_rp2350_geek/board.c b/ports/raspberrypi/boards/waveshare_rp2350_geek/board.c index 71269f0d185..431840fb0c5 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_geek/board.c +++ b/ports/raspberrypi/boards/waveshare_rp2350_geek/board.c @@ -37,9 +37,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // TFT_DC - &pin_GPIO9, // TFT_CS - &pin_GPIO12, // TFT_RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // TFT_DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // TFT_RST 50000000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c b/ports/raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c index f17ca53d724..44d279da43f 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c +++ b/ports/raspberrypi/boards/waveshare_rp2350_lcd_0_96/board.c @@ -60,9 +60,9 @@ static void display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO8, // DC - &pin_GPIO9, // CS - &pin_GPIO12, // RST + MP_OBJ_FROM_PTR(&pin_GPIO8), // DC + MP_OBJ_FROM_PTR(&pin_GPIO9), // CS + MP_OBJ_FROM_PTR(&pin_GPIO12), // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/stm/boards/meowbit_v121/board.c b/ports/stm/boards/meowbit_v121/board.c index 181f433a372..c3c745f64a1 100644 --- a/ports/stm/boards/meowbit_v121/board.c +++ b/ports/stm/boards/meowbit_v121/board.c @@ -55,9 +55,9 @@ void board_init(void) { busio_spi_obj_t *internal_spi = &supervisor_flash_spi_bus; common_hal_fourwire_fourwire_construct(bus, internal_spi, - &pin_PA08, // Command or data - &pin_PB12, // Chip select - &pin_PB10, // Reset + MP_OBJ_FROM_PTR(&pin_PA08), // Command or data + MP_OBJ_FROM_PTR(&pin_PB12), // Chip select + MP_OBJ_FROM_PTR(&pin_PB10), // Reset 24000000, // Baudrate 0, // Polarity 0); // Phase From e1fe8a0827dccf17e7d736a88f98b1007754a6e4 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 27 Jan 2026 09:58:18 -0800 Subject: [PATCH 159/876] Fix Zephyr builds --- ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml | 1 + .../zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml | 1 + 11 files changed, 11 insertions(+) diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 5c1e64aedc7..334cf4001eb 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 2cd411fbc06..40edb7b7058 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 227e4a2f6c1..509f14cd20d 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 104a2111525..3b0ecedcc63 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index f22d066fe64..7e03594f1d1 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 1768f331180..4398a38ab87 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 0a4bf3ce19f..d60e8eb4b26 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 518af74c405..8743994bbc7 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 9806cd8a811..9b10fbe3c2d 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 01e3314fa5a..ef54f4bb0f7 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 9ec442d4cfa..30ac22d00cc 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false From 8c22e671a257f38d67235929b0c93a46d7b1b47d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 27 Jan 2026 11:01:25 -0800 Subject: [PATCH 160/876] Save space by disabling DigitalInOut protocol support where needed --- locale/circuitpython.pot | 2 +- ports/atmel-samd/mpconfigport.mk | 2 + .../stm/boards/meowbit_v121/mpconfigboard.mk | 2 + py/circuitpy_mpconfig.mk | 6 +++ shared-bindings/digitalio/DigitalInOut.c | 53 ++++++++++--------- shared-bindings/digitalio/DigitalInOut.h | 13 +++++ .../digitalio/DigitalInOutProtocol.c | 37 ++++++++----- .../digitalio/DigitalInOutProtocol.h | 18 ++++++- shared-bindings/i2cioexpander/IOPin.c | 2 +- 9 files changed, 95 insertions(+), 40 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 9cf51a0c025..670ef5dcf0e 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -313,7 +313,7 @@ msgstr "" msgid "'%q' argument required" msgstr "" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "" diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index 861ef374646..c095220d0a3 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -14,6 +14,8 @@ CIRCUITPY_LTO = 1 CIRCUITPY_KEYPAD_DEMUX ?= 0 CIRCUITPY_LVFONTIO ?= 0 +CIRCUITPY_DIGITALINOUT_PROTOCOL = 0 + ###################################################################### # Put samd21-only choices here. diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.mk b/ports/stm/boards/meowbit_v121/mpconfigboard.mk index 3a128fb8343..74759abed54 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.mk +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.mk @@ -37,4 +37,6 @@ CIRCUITPY_ZLIB = 0 CIRCUITPY_STAGE = 1 +CIRCUITPY_DIGITALINOUT_PROTOCOL = 0 + FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/meowbit diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index e3a3e8fe800..8e0992f0418 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -241,6 +241,12 @@ CFLAGS += -DCIRCUITPY_CYW43=$(CIRCUITPY_CYW43) CIRCUITPY_DIGITALIO ?= 1 CFLAGS += -DCIRCUITPY_DIGITALIO=$(CIRCUITPY_DIGITALIO) +# Enable the DigitalInOut protocol on the native DigitalInOut type. +# This allows other C code to use DigitalInOut objects polymorphically. +# Disable on small builds to save space. +CIRCUITPY_DIGITALINOUT_PROTOCOL ?= $(CIRCUITPY_FULL_BUILD) +CFLAGS += -DCIRCUITPY_DIGITALINOUT_PROTOCOL=$(CIRCUITPY_DIGITALINOUT_PROTOCOL) + CIRCUITPY_COPROC ?= 0 CFLAGS += -DCIRCUITPY_COPROC=$(CIRCUITPY_COPROC) diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index 7d847165049..50cbc3bc36d 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -343,85 +343,90 @@ static const mp_rom_map_elem_t digitalio_digitalinout_locals_dict_table[] = { static MP_DEFINE_CONST_DICT(digitalio_digitalinout_locals_dict, digitalio_digitalinout_locals_dict_table); // Protocol implementation - thin wrappers to match protocol signature -static void digitalinout_proto_deinit(mp_obj_t self_in) { +void digitalinout_deinit(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_digitalio_digitalinout_deinit(self); } -static bool digitalinout_proto_deinited(mp_obj_t self_in) { +bool digitalinout_deinited(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_digitalio_digitalinout_deinited(self); } -static digitalinout_result_t digitalinout_proto_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull) { +digitalinout_result_t digitalinout_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_digitalio_digitalinout_switch_to_input(self, pull); } -static digitalinout_result_t digitalinout_proto_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode) { +digitalinout_result_t digitalinout_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_digitalio_digitalinout_switch_to_output(self, value, drive_mode); } -static digitalio_direction_t digitalinout_proto_get_direction(mp_obj_t self_in) { +digitalio_direction_t digitalinout_get_direction(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_digitalio_digitalinout_get_direction(self); } -static mp_errno_t digitalinout_proto_set_value(mp_obj_t self_in, bool value) { +mp_errno_t digitalinout_set_value(mp_obj_t self_in, bool value) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_digitalio_digitalinout_set_value(self, value); return 0; } -static mp_errno_t digitalinout_proto_get_value(mp_obj_t self_in, bool *value) { +mp_errno_t digitalinout_get_value(mp_obj_t self_in, bool *value) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); *value = common_hal_digitalio_digitalinout_get_value(self); return 0; } -static digitalinout_result_t digitalinout_proto_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode) { +digitalinout_result_t digitalinout_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_digitalio_digitalinout_set_drive_mode(self, drive_mode); } -static digitalio_drive_mode_t digitalinout_proto_get_drive_mode(mp_obj_t self_in) { +digitalio_drive_mode_t digitalinout_get_drive_mode(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_digitalio_digitalinout_get_drive_mode(self); } -static digitalinout_result_t digitalinout_proto_set_pull(mp_obj_t self_in, digitalio_pull_t pull) { +digitalinout_result_t digitalinout_set_pull(mp_obj_t self_in, digitalio_pull_t pull) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_digitalio_digitalinout_set_pull(self, pull); } -static digitalio_pull_t digitalinout_proto_get_pull(mp_obj_t self_in) { +digitalio_pull_t digitalinout_get_pull(mp_obj_t self_in) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_digitalio_digitalinout_get_pull(self); } +#if CIRCUITPY_DIGITALINOUT_PROTOCOL static const digitalinout_p_t digitalinout_digitalinout_proto = { - MP_PROTO_IMPLEMENT(MP_QSTR_protocol_digitalinout) - .deinit = digitalinout_proto_deinit, - .deinited = digitalinout_proto_deinited, - .switch_to_input = digitalinout_proto_switch_to_input, - .switch_to_output = digitalinout_proto_switch_to_output, - .get_direction = digitalinout_proto_get_direction, - .get_value = digitalinout_proto_get_value, - .set_value = digitalinout_proto_set_value, - .get_drive_mode = digitalinout_proto_get_drive_mode, - .set_drive_mode = digitalinout_proto_set_drive_mode, - .get_pull = digitalinout_proto_get_pull, - .set_pull = digitalinout_proto_set_pull, + MP_PROTO_IMPLEMENT(MP_QSTR_DigitalInOut) + .deinit = digitalinout_deinit, + .deinited = digitalinout_deinited, + .switch_to_input = digitalinout_switch_to_input, + .switch_to_output = digitalinout_switch_to_output, + .get_direction = digitalinout_get_direction, + .get_value = digitalinout_get_value, + .set_value = digitalinout_set_value, + .get_drive_mode = digitalinout_get_drive_mode, + .set_drive_mode = digitalinout_set_drive_mode, + .get_pull = digitalinout_get_pull, + .set_pull = digitalinout_set_pull, }; +#endif MP_DEFINE_CONST_OBJ_TYPE( digitalio_digitalinout_type, MP_QSTR_DigitalInOut, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, make_new, digitalio_digitalinout_make_new, - locals_dict, &digitalio_digitalinout_locals_dict, + locals_dict, &digitalio_digitalinout_locals_dict + #if CIRCUITPY_DIGITALINOUT_PROTOCOL + , protocol, &digitalinout_digitalinout_proto + #endif ); // Helper for validating digitalio.DigitalInOut arguments diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h index 7465af3e288..ad38cbec6a4 100644 --- a/shared-bindings/digitalio/DigitalInOut.h +++ b/shared-bindings/digitalio/DigitalInOut.h @@ -57,3 +57,16 @@ digitalio_digitalinout_obj_t *assert_digitalinout(mp_obj_t obj); volatile uint32_t *common_hal_digitalio_digitalinout_get_reg(digitalio_digitalinout_obj_t *self, digitalinout_reg_op_t op, uint32_t *mask); bool common_hal_digitalio_has_reg_op(digitalinout_reg_op_t op); + +// Protocol wrapper functions - always available for direct calls +void digitalinout_deinit(mp_obj_t self_in); +bool digitalinout_deinited(mp_obj_t self_in); +digitalinout_result_t digitalinout_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull); +digitalinout_result_t digitalinout_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode); +digitalio_direction_t digitalinout_get_direction(mp_obj_t self_in); +mp_errno_t digitalinout_set_value(mp_obj_t self_in, bool value); +mp_errno_t digitalinout_get_value(mp_obj_t self_in, bool *value); +digitalinout_result_t digitalinout_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode); +digitalio_drive_mode_t digitalinout_get_drive_mode(mp_obj_t self_in); +digitalinout_result_t digitalinout_set_pull(mp_obj_t self_in, digitalio_pull_t pull); +digitalio_pull_t digitalinout_get_pull(mp_obj_t self_in); diff --git a/shared-bindings/digitalio/DigitalInOutProtocol.c b/shared-bindings/digitalio/DigitalInOutProtocol.c index e0671a1b881..df64fd729c2 100644 --- a/shared-bindings/digitalio/DigitalInOutProtocol.c +++ b/shared-bindings/digitalio/DigitalInOutProtocol.c @@ -102,7 +102,7 @@ // // Example: // static const digitalinout_p_t my_type_proto = { -// MP_PROTO_IMPLEMENT(MP_QSTR_protocol_digitalinout) +// MP_PROTO_IMPLEMENT(MP_QSTR_DigitalInOut) // .construct = my_construct_func, // .deinit = my_deinit_func, // .deinited = my_deinited_func, @@ -128,7 +128,7 @@ // See shared-bindings/digitalio/DigitalInOut.c for a complete example. // - +#if CIRCUITPY_DIGITALINOUT_PROTOCOL static void check_object_has_method(mp_obj_t obj, qstr method_name) { mp_obj_t dest[2]; mp_load_method_protected(obj, method_name, dest, true); @@ -144,6 +144,7 @@ static void check_object_has_attr(mp_obj_t obj, qstr attr_name) { mp_raise_TypeError_varg(MP_ERROR_TEXT("%q object missing '%q' attribute"), MP_OBJ_TO_PTR(obj), attr_name); } } +#endif mp_obj_t digitalinout_protocol_from_pin( mp_obj_t pin_or_dio, @@ -195,8 +196,9 @@ mp_obj_t digitalinout_protocol_from_pin( return dio_obj; } + #if CIRCUITPY_DIGITALINOUT_PROTOCOL // Check if it natively implements the DigitalInOutProtocol - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, pin_or_dio); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, pin_or_dio); if (proto != NULL) { // Native protocol support - use it directly return pin_or_dio; @@ -214,8 +216,15 @@ mp_obj_t digitalinout_protocol_from_pin( // Object has all required attributes - use it as DigitalInOutProtocol return pin_or_dio; + #else + mp_raise_TypeError_varg(MP_ERROR_TEXT("'%q' object does not support '%q'"), + mp_obj_get_type_qstr(pin_or_dio), MP_QSTR_DigitalInOut); + #endif } +// These functions are only used when CIRCUITPY_DIGITALINOUT_PROTOCOL is enabled. +// Otherwise, the digitalinout_* functions are called directly. +#if CIRCUITPY_DIGITALINOUT_PROTOCOL void digitalinout_protocol_deinit(mp_obj_t self) { const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); if (proto && proto->deinit) { @@ -233,7 +242,7 @@ void digitalinout_protocol_deinit(mp_obj_t self) { } bool digitalinout_protocol_deinited(mp_obj_t self) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->deinited) { return proto->deinited(self); } @@ -244,7 +253,7 @@ bool digitalinout_protocol_deinited(mp_obj_t self) { } digitalinout_result_t digitalinout_protocol_switch_to_input(mp_obj_t self, digitalio_pull_t pull) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->switch_to_input) { return proto->switch_to_input(self, pull); } @@ -268,7 +277,7 @@ digitalinout_result_t digitalinout_protocol_switch_to_input(mp_obj_t self, digit } digitalinout_result_t digitalinout_protocol_switch_to_output(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->switch_to_output) { return proto->switch_to_output(self, value, drive_mode); } @@ -289,7 +298,7 @@ digitalinout_result_t digitalinout_protocol_switch_to_output(mp_obj_t self, bool } digitalio_direction_t digitalinout_protocol_get_direction(mp_obj_t self) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->get_direction) { return proto->get_direction(self); } @@ -303,7 +312,7 @@ digitalio_direction_t digitalinout_protocol_get_direction(mp_obj_t self) { } mp_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->set_value) { return proto->set_value(self, value); } @@ -314,7 +323,7 @@ mp_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value) { } mp_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->get_value) { return proto->get_value(self, value); } @@ -325,7 +334,7 @@ mp_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value) { } digitalinout_result_t digitalinout_protocol_set_drive_mode(mp_obj_t self, digitalio_drive_mode_t drive_mode) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->set_drive_mode) { return proto->set_drive_mode(self, drive_mode); } @@ -339,7 +348,7 @@ digitalinout_result_t digitalinout_protocol_set_drive_mode(mp_obj_t self, digita } digitalio_drive_mode_t digitalinout_protocol_get_drive_mode(mp_obj_t self) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->get_drive_mode) { return proto->get_drive_mode(self); } @@ -353,7 +362,7 @@ digitalio_drive_mode_t digitalinout_protocol_get_drive_mode(mp_obj_t self) { } digitalinout_result_t digitalinout_protocol_set_pull(mp_obj_t self, digitalio_pull_t pull) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->set_pull) { return proto->set_pull(self, pull); } @@ -370,7 +379,7 @@ digitalinout_result_t digitalinout_protocol_set_pull(mp_obj_t self, digitalio_pu } digitalio_pull_t digitalinout_protocol_get_pull(mp_obj_t self) { - const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_protocol_digitalinout, self); + const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->get_pull) { return proto->get_pull(self); } @@ -384,3 +393,5 @@ digitalio_pull_t digitalinout_protocol_get_pull(mp_obj_t self) { } return PULL_NONE; } + +#endif // CIRCUITPY_DIGITALINOUT_PROTOCOL diff --git a/shared-bindings/digitalio/DigitalInOutProtocol.h b/shared-bindings/digitalio/DigitalInOutProtocol.h index 5ec8bcb1855..798cb6a9de1 100644 --- a/shared-bindings/digitalio/DigitalInOutProtocol.h +++ b/shared-bindings/digitalio/DigitalInOutProtocol.h @@ -19,7 +19,7 @@ // Protocol structure for DigitalInOut implementations // Note: mcu_pin_obj_t and digitalinout_result_t are defined by files that include this header typedef struct _digitalinout_p_t { - MP_PROTOCOL_HEAD // MP_QSTR_protocol_digitalinout + MP_PROTOCOL_HEAD // MP_QSTR_DigitalInOut void (*deinit)(mp_obj_t self); bool (*deinited)(mp_obj_t self); digitalinout_result_t (*switch_to_input)(mp_obj_t self, digitalio_pull_t pull); @@ -54,6 +54,8 @@ mp_obj_t digitalinout_protocol_from_pin( bool force_port_allocation, bool *out_owns_pin); +#if CIRCUITPY_DIGITALINOUT_PROTOCOL +// Protocol helper functions that do protocol lookup or Python fallback void digitalinout_protocol_deinit(mp_obj_t self); bool digitalinout_protocol_deinited(mp_obj_t self); digitalinout_result_t digitalinout_protocol_switch_to_input(mp_obj_t self, digitalio_pull_t pull); @@ -65,3 +67,17 @@ digitalinout_result_t digitalinout_protocol_set_drive_mode(mp_obj_t self, digita digitalio_drive_mode_t digitalinout_protocol_get_drive_mode(mp_obj_t self); digitalinout_result_t digitalinout_protocol_set_pull(mp_obj_t self, digitalio_pull_t pull); digitalio_pull_t digitalinout_protocol_get_pull(mp_obj_t self); +#else +// When protocol is disabled, map directly to native DigitalInOut functions +#define digitalinout_protocol_deinit digitalinout_deinit +#define digitalinout_protocol_deinited digitalinout_deinited +#define digitalinout_protocol_switch_to_input digitalinout_switch_to_input +#define digitalinout_protocol_switch_to_output digitalinout_switch_to_output +#define digitalinout_protocol_get_direction digitalinout_get_direction +#define digitalinout_protocol_set_value digitalinout_set_value +#define digitalinout_protocol_get_value digitalinout_get_value +#define digitalinout_protocol_set_drive_mode digitalinout_set_drive_mode +#define digitalinout_protocol_get_drive_mode digitalinout_get_drive_mode +#define digitalinout_protocol_set_pull digitalinout_set_pull +#define digitalinout_protocol_get_pull digitalinout_get_pull +#endif diff --git a/shared-bindings/i2cioexpander/IOPin.c b/shared-bindings/i2cioexpander/IOPin.c index 4a8ca46372b..e2957f9a220 100644 --- a/shared-bindings/i2cioexpander/IOPin.c +++ b/shared-bindings/i2cioexpander/IOPin.c @@ -290,7 +290,7 @@ static digitalinout_result_t iopin_protocol_set_pull(mp_obj_t self_in, digitalio } static const digitalinout_p_t iopin_digitalinout_p = { - MP_PROTO_IMPLEMENT(MP_QSTR_protocol_digitalinout) + MP_PROTO_IMPLEMENT(MP_QSTR_DigitalInOut) .deinit = iopin_protocol_deinit, .deinited = iopin_protocol_deinited, .switch_to_input = iopin_protocol_switch_to_input, From b79de65ad61d3d997969cef736bc75c2415fce80 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 27 Jan 2026 16:30:36 -0500 Subject: [PATCH 161/876] Initial defn for Freensy 2350 --- .../boards/adafruit_freensy_rp2350/board.c | 16 ++++++ .../adafruit_freensy_rp2350/mpconfigboard.h | 20 +++++++ .../adafruit_freensy_rp2350/mpconfigboard.mk | 10 ++++ .../pico-sdk-configboard.h | 10 ++++ .../boards/adafruit_freensy_rp2350/pins.c | 54 +++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 ports/raspberrypi/boards/adafruit_freensy_rp2350/board.c create mode 100644 ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/adafruit_freensy_rp2350/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/adafruit_freensy_rp2350/pins.c diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/board.c b/ports/raspberrypi/boards/adafruit_freensy_rp2350/board.c new file mode 100644 index 00000000000..fddd2572c1f --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_freensy_rp2350/board.c @@ -0,0 +1,16 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "supervisor/board.h" + +#include "common-hal/picodvi/__init__.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. + +void board_init(void) { + picodvi_autoconstruct(); +} diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.h new file mode 100644 index 00000000000..9bde1fdbdd7 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Adafruit Freensy RP2350" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO17) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO19) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO18) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO10) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO11) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO12) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO1) +#define DEFAULT_UART_BUS_TX (&pin_GPIO0) diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.mk new file mode 100644 index 00000000000..6070a1fbe8f --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.mk @@ -0,0 +1,10 @@ +USB_VID = 0x239A +USB_PID = 0x8170 +USB_PRODUCT = "Freensy RP2350" +USB_MANUFACTURER = "Adafruit" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ" diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/adafruit_freensy_rp2350/pico-sdk-configboard.h new file mode 100644 index 00000000000..2d9283a9192 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_freensy_rp2350/pico-sdk-configboard.h @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. + +// Allow extra time for xosc to start. +#define PICO_XOSC_STARTUP_DELAY_MULTIPLIER 64 diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/pins.c b/ports/raspberrypi/boards/adafruit_freensy_rp2350/pins.c new file mode 100644 index 00000000000..0d769fd4d56 --- /dev/null +++ b/ports/raspberrypi/boards/adafruit_freensy_rp2350/pins.c @@ -0,0 +1,54 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_D22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_CS), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 928e6bc4aa3fc499b029c99b4d7ed33bf4bfdf0e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 27 Jan 2026 14:43:07 -0800 Subject: [PATCH 162/876] Add copespell ignores and fix stubs --- ports/atmel-samd/Makefile | 2 +- ports/cxd56/mkspk/clefia.c | 10 +++++----- ports/espressif/tools/update_sdkconfig.py | 2 +- py/makeqstrdata.py | 2 +- shared-bindings/i2cioexpander/IOExpander.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 9582eff212d..f8f420fda80 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -169,7 +169,7 @@ LIBS += -lm endif ifeq ($(CHIP_FAMILY), samd21) -LDFLAGS += -mthumb -mcpu=cortex-m0plus -Lasf/thirdparty/CMSIS/Lib/GCC/ +LDFLAGS += -mthumb -mcpu=cortex-m0plus -Lasf/thirdparty/CMSIS/Lib/GCC/ # codespell:ignore thirdparty BOOTLOADER_SIZE := 0x2000 else ifeq ($(CHIP_FAMILY), samd51) LDFLAGS += -mthumb -mcpu=cortex-m4 diff --git a/ports/cxd56/mkspk/clefia.c b/ports/cxd56/mkspk/clefia.c index e946ee5348a..d36f638fa0b 100644 --- a/ports/cxd56/mkspk/clefia.c +++ b/ports/cxd56/mkspk/clefia.c @@ -466,16 +466,16 @@ int clefiakeyset(unsigned char *rk, const unsigned char *skey) { void clefiaencrypt(unsigned char *ct, const unsigned char *pt, const unsigned char *rk, const int r) { - unsigned char rin[16]; + unsigned char r_in[16]; unsigned char rout[16]; - bytecpy(rin, pt, 16); + bytecpy(r_in, pt, 16); - bytexor(rin + 4, rin + 4, rk + 0, 4); /* initial key whitening */ - bytexor(rin + 12, rin + 12, rk + 4, 4); + bytexor(r_in + 4, r_in + 4, rk + 0, 4); /* initial key whitening */ + bytexor(r_in + 12, r_in + 12, rk + 4, 4); rk += 8; - clefiagfn4(rout, rin, rk, r); /* GFN_{4,r} */ + clefiagfn4(rout, r_in, rk, r); /* GFN_{4,r} */ bytecpy(ct, rout, 16); bytexor(ct + 4, ct + 4, rk + r * 8 + 0, 4); /* final key whitening */ diff --git a/ports/espressif/tools/update_sdkconfig.py b/ports/espressif/tools/update_sdkconfig.py index 8837d84321b..209b976b881 100644 --- a/ports/espressif/tools/update_sdkconfig.py +++ b/ports/espressif/tools/update_sdkconfig.py @@ -321,7 +321,7 @@ def update(debug, board, update_all): # noqa: C901: too complex if print_debug: print(" " * len(current_group), i, config_string.strip()) - # Some files are `rsource`d into another kconfig with $IDF_TARGET as + # Some files are `rsource`d into another kconfig with $IDF_TARGET as # codespell:ignore rsource # part of the path. kconfiglib doesn't show this as a reference so # we have to look ourselves. target_reference = target in item.name_and_loc diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 45cc896f925..998328bf1d2 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -51,7 +51,7 @@ 954: "kappa", 8656: "lArr", 955: "lambda", 9001: "lang", 171: "laquo", 8592: "larr", 8968: "lceil", 8220: "ldquo", 8804: "le", 8970: "lfloor", 8727: "lowast", 9674: "loz", 8206: "lrm", 8249: "lsaquo", 8216: "lsquo", 60: "lt", 175: "macr", 8212: "mdash", 181: "micro", 183: "middot", 8722: "minus", - 956: "mu", 8711: "nabla", 160: "nbsp", 8211: "ndash", 8800: "ne", 8715: "ni", 172: "not", 8713: "notin", + 956: "mu", 8711: "nabla", 160: "nbsp", 8211: "ndash", 8800: "ne", 8715: "ni", 172: "not", 8713: "notin", # codespell:ignore notin 8836: "nsub", 241: "ntilde", 957: "nu", 243: "oacute", 244: "ocirc", 339: "oelig", 242: "ograve", 8254: "oline", 969: "omega", 959: "omicron", 8853: "oplus", 8744: "or", 170: "ordf", 186: "ordm", 248: "oslash", 245: "otilde", 8855: "otimes", 246: "ouml", 182: "para", 8706: "part", 8240: "permil", diff --git a/shared-bindings/i2cioexpander/IOExpander.c b/shared-bindings/i2cioexpander/IOExpander.c index 09c404d289c..f2257b4b632 100644 --- a/shared-bindings/i2cioexpander/IOExpander.c +++ b/shared-bindings/i2cioexpander/IOExpander.c @@ -211,8 +211,8 @@ MP_PROPERTY_GETSET(i2cioexpander_ioexpander_output_mask_obj, (mp_obj_t)&i2cioexpander_ioexpander_set_output_mask_obj); //| @property -//| def pins(self) -> Tuple[DigitalInOutProtocol, ...]: -//| """A tuple of pin objects that implement the DigitalInOutProtocol. +//| def pins(self) -> Tuple[IOPin, ...]: +//| """A tuple of `IOPin` objects that implement the DigitalInOutProtocol. //| Each pin can be used like a digitalio.DigitalInOut object.""" //| ... static mp_obj_t i2cioexpander_ioexpander_obj_get_pins(mp_obj_t self_in) { From dd82fe0d1d95992058b5b8fffc0faa3b5f23221e Mon Sep 17 00:00:00 2001 From: George Hartzell Date: Wed, 28 Jan 2026 10:34:05 -0700 Subject: [PATCH 163/876] Update __init__.c Add a bit more info to the docs for the rainboxio.colorwheel function, making it more useful to someone just getting started. --- shared-bindings/rainbowio/__init__.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shared-bindings/rainbowio/__init__.c b/shared-bindings/rainbowio/__init__.c index a085669d7ff..e02df713eeb 100644 --- a/shared-bindings/rainbowio/__init__.c +++ b/shared-bindings/rainbowio/__init__.c @@ -16,7 +16,8 @@ //| //| def colorwheel(n: float) -> int: //| """C implementation of the common colorwheel() function found in many examples. -//| Returns the colorwheel RGB value as an integer value for n (usable in neopixel and dotstar). +//| Takes a hue, a value between 0-255, and returns an RGB tuple encoded as an +//| integer value (usable in neopixel and dotstar). //| """ //| ... //| From 342a3649f69c03d7117b85376bc4fffadb12da5e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 28 Jan 2026 14:20:23 -0500 Subject: [PATCH 164/876] name change to Tinychad --- .../board.c | 0 .../mpconfigboard.h | 2 +- .../mpconfigboard.mk | 2 +- .../pico-sdk-configboard.h | 0 .../pins.c | 0 5 files changed, 2 insertions(+), 2 deletions(-) rename ports/raspberrypi/boards/{adafruit_freensy_rp2350 => adafruit_tinychad_rp2350}/board.c (100%) rename ports/raspberrypi/boards/{adafruit_freensy_rp2350 => adafruit_tinychad_rp2350}/mpconfigboard.h (90%) rename ports/raspberrypi/boards/{adafruit_freensy_rp2350 => adafruit_tinychad_rp2350}/mpconfigboard.mk (84%) rename ports/raspberrypi/boards/{adafruit_freensy_rp2350 => adafruit_tinychad_rp2350}/pico-sdk-configboard.h (100%) rename ports/raspberrypi/boards/{adafruit_freensy_rp2350 => adafruit_tinychad_rp2350}/pins.c (100%) diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/board.c b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c similarity index 100% rename from ports/raspberrypi/boards/adafruit_freensy_rp2350/board.c rename to ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.h similarity index 90% rename from ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.h rename to ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.h index 9bde1fdbdd7..958ab01a0b6 100644 --- a/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.h @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT -#define MICROPY_HW_BOARD_NAME "Adafruit Freensy RP2350" +#define MICROPY_HW_BOARD_NAME "Adafruit Tinychad RP2350" #define MICROPY_HW_MCU_NAME "rp2350a" #define MICROPY_HW_NEOPIXEL (&pin_GPIO17) diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk similarity index 84% rename from ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.mk rename to ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk index 6070a1fbe8f..8d2a9c2f527 100644 --- a/ports/raspberrypi/boards/adafruit_freensy_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk @@ -1,6 +1,6 @@ USB_VID = 0x239A USB_PID = 0x8170 -USB_PRODUCT = "Freensy RP2350" +USB_PRODUCT = "Tinychad RP2350" USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2350 diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/pico-sdk-configboard.h similarity index 100% rename from ports/raspberrypi/boards/adafruit_freensy_rp2350/pico-sdk-configboard.h rename to ports/raspberrypi/boards/adafruit_tinychad_rp2350/pico-sdk-configboard.h diff --git a/ports/raspberrypi/boards/adafruit_freensy_rp2350/pins.c b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/pins.c similarity index 100% rename from ports/raspberrypi/boards/adafruit_freensy_rp2350/pins.c rename to ports/raspberrypi/boards/adafruit_tinychad_rp2350/pins.c From 44f38161919e0d838d43ccf9b71b79a4fca466c3 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 26 Jan 2026 17:07:33 -0800 Subject: [PATCH 165/876] Fixes for native sim --- .pre-commit-config.yaml | 2 +- main.c | 9 +- ports/zephyr-cp/Makefile | 8 +- ports/zephyr-cp/boards/board_aliases.cmake | 1 + .../native/native_sim/autogen_board_info.toml | 114 ++++++++++++++++++ .../native/native_sim/circuitpython.toml | 1 + ports/zephyr-cp/boards/native_sim.conf | 6 + ports/zephyr-cp/boards/native_sim.overlay | 39 ++++++ ports/zephyr-cp/common-hal/busio/UART.c | 2 +- .../common-hal/microcontroller/Processor.c | 4 + .../common-hal/zephyr_kernel/__init__.c | 1 + .../zephyr-cp/cptools/build_circuitpython.py | 7 +- ports/zephyr-cp/cptools/zephyr2cp.py | 47 +++++--- ports/zephyr-cp/supervisor/flash.c | 2 +- ports/zephyr-cp/supervisor/port.c | 12 +- shared/runtime/gchelper_generic.c | 8 +- supervisor/shared/background_callback.c | 2 + supervisor/shared/safe_mode.c | 12 ++ 18 files changed, 243 insertions(+), 34 deletions(-) create mode 100644 ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/native/native_sim/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/native_sim.conf create mode 100644 ports/zephyr-cp/boards/native_sim.overlay diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f7e7956498d..4db04e1d0ed 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -28,7 +28,7 @@ repos: lib/mbedtls_errors/generate_errors.diff ) - repo: https://github.com/codespell-project/codespell - rev: v2.2.4 + rev: v2.4.1 hooks: - id: codespell args: [-w] diff --git a/main.c b/main.c index d636c851b70..d187c56cee4 100644 --- a/main.c +++ b/main.c @@ -21,6 +21,7 @@ #include "py/stackctrl.h" #include "shared/readline/readline.h" +#include "shared/runtime/gchelper.h" #include "shared/runtime/pyexec.h" #include "background.h" @@ -1161,13 +1162,7 @@ int __attribute__((used)) main(void) { void gc_collect(void) { gc_collect_start(); - // Load register values onto the stack. They get collected below with the rest of the stack. - size_t regs[SAVED_REGISTER_COUNT]; - mp_uint_t sp = cpu_get_regs_and_sp(regs); - - // This naively collects all object references from an approximate stack - // range. - gc_collect_root((void **)sp, ((mp_uint_t)port_stack_get_top() - sp) / sizeof(mp_uint_t)); + gc_helper_collect_regs_and_stack(); // This collects root pointers from the VFS mount table. Some of them may // have lost their references in the VM even though they are mounted. diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index 037c14afad4..d31068e4c92 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,7 +8,7 @@ BUILD ?= build-$(BOARD) TRANSLATION ?= en_US -.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash debug clean menuconfig all clean-all test +.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash debug run clean menuconfig all clean-all test $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) @@ -20,12 +20,18 @@ $(BUILD)/firmware.elf: $(BUILD)/zephyr-cp/zephyr/zephyr.elf $(BUILD)/firmware.hex: $(BUILD)/zephyr-cp/zephyr/zephyr.elf cp $(BUILD)/zephyr-cp/zephyr/zephyr.hex $@ +$(BUILD)/firmware.exe: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + cp $(BUILD)/zephyr-cp/zephyr/zephyr.exe $@ + flash: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west flash -d $(BUILD) debug: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west debug -d $(BUILD) +run: $(BUILD)/firmware.exe + $^ + menuconfig: west build --sysbuild -d $(BUILD) -t menuconfig diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index 7fc973efc78..954bce0b298 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -1,6 +1,7 @@ set(pca10056_BOARD_ALIAS nrf52840dk/nrf52840) set(renesas_ek_ra6m5_BOARD_ALIAS ek_ra6m5) set(renesas_ek_ra8d1_BOARD_ALIAS ek_ra8d1) +set(native_native_sim_BOARD_ALIAS native_sim) set(nordic_nrf54l15dk_BOARD_ALIAS nrf54l15dk/nrf54l15/cpuapp) set(nordic_nrf54h20dk_BOARD_ALIAS nrf54h20dk/nrf54h20/cpuapp) set(nordic_nrf5340dk_BOARD_ALIAS nrf5340dk/nrf5340/cpuapp) diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml new file mode 100644 index 00000000000..8a4eb3e6fb5 --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -0,0 +1,114 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "POSIX/Native Boards Native simulator - native_sim" + +[modules] +__future__ = false +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = true # Zephyr board has busio +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml new file mode 100644 index 00000000000..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native_sim.conf new file mode 100644 index 00000000000..baf808b5142 --- /dev/null +++ b/ports/zephyr-cp/boards/native_sim.conf @@ -0,0 +1,6 @@ +CONFIG_EMUL=y +CONFIG_GPIO=y +CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=n + +# So we can test safe mode +CONFIG_NATIVE_SIM_REBOOT=y diff --git a/ports/zephyr-cp/boards/native_sim.overlay b/ports/zephyr-cp/boards/native_sim.overlay new file mode 100644 index 00000000000..6a13f58379a --- /dev/null +++ b/ports/zephyr-cp/boards/native_sim.overlay @@ -0,0 +1,39 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Device tree overlay for CircuitPython on native_sim. + * Adds simulated SRAM region required by CircuitPython build system. + */ + +#include + +/ { + sram0: memory@20000000 { + device_type = "memory"; + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_M(1)>; + zephyr,memory-region = "SRAM"; + }; + + chosen { + zephyr,sram = &sram0; + /delete-property/ zephyr,flash; + /delete-property/ zephyr,code-partition; + }; +}; + +&flash0 { + /delete-node/ partitions; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_K(2048)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/common-hal/busio/UART.c b/ports/zephyr-cp/common-hal/busio/UART.c index b5aaadb3bb5..9940853da50 100644 --- a/ports/zephyr-cp/common-hal/busio/UART.c +++ b/ports/zephyr-cp/common-hal/busio/UART.c @@ -126,7 +126,7 @@ void common_hal_busio_uart_set_baudrate(busio_uart_obj_t *self, uint32_t baudrat struct uart_config config; uart_config_get(self->uart_device, &config); config.baudrate = baudrate; - uart_config_set(self->uart_device, &config); + uart_configure(self->uart_device, &config); } mp_float_t common_hal_busio_uart_get_timeout(busio_uart_obj_t *self) { diff --git a/ports/zephyr-cp/common-hal/microcontroller/Processor.c b/ports/zephyr-cp/common-hal/microcontroller/Processor.c index ddc8b97056d..9f512a686ec 100644 --- a/ports/zephyr-cp/common-hal/microcontroller/Processor.c +++ b/ports/zephyr-cp/common-hal/microcontroller/Processor.c @@ -21,7 +21,11 @@ float common_hal_mcu_processor_get_temperature(void) { extern uint32_t SystemCoreClock; uint32_t common_hal_mcu_processor_get_frequency(void) { + #ifdef __ARM__ return SystemCoreClock; + #else + return CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; + #endif } float common_hal_mcu_processor_get_voltage(void) { diff --git a/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c b/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c index 042f06b0ed2..d5e6fd08006 100644 --- a/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c +++ b/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c @@ -6,6 +6,7 @@ #include "bindings/zephyr_kernel/__init__.h" #include "py/runtime.h" +#include #include diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index a5e4d72b902..83f80945f3e 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -277,9 +277,10 @@ async def build_circuitpython(): enable_mpy_native = False full_build = True usb_host = False + zephyr_board = cmake_args["BOARD"] board = cmake_args["BOARD_ALIAS"] if not board: - board = cmake_args["BOARD"] + board = zephyr_board translation = cmake_args["TRANSLATION"] if not translation: translation = "en_US" @@ -319,7 +320,7 @@ async def build_circuitpython(): ) board_autogen_task = tg.create_task( - zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir) + zephyr_dts_to_cp_board(zephyr_board, portdir, builddir, zephyrbuilddir) ) board_info = board_autogen_task.result() mpconfigboard_fn = board_tools.find_mpconfigboard(portdir, board) @@ -353,6 +354,8 @@ async def build_circuitpython(): "shared/readline/readline.c", "shared/runtime/buffer_helper.c", "shared/runtime/context_manager_helpers.c", + "shared/runtime/gchelper_generic.c", + "shared/runtime/gchelper_native.c", "shared/runtime/pyexec.c", "shared/runtime/interrupt_char.c", "shared/runtime/stdout_helpers.c", diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 77404ec2bec..0f09c21e83f 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -16,6 +16,7 @@ MANUAL_COMPAT_TO_DRIVER = { "renesas_ra_nv_flash": "flash", + "soc_nv_flash": "flash", "nordic_nrf_uarte": "serial", "nordic_nrf_uart": "serial", "nordic_nrf_twim": "i2c", @@ -370,7 +371,7 @@ def find_ram_regions(device_tree): @cpbuild.run_in_thread -def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 +def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa: C901 board_dir = builddir / "board" # Auto generate board files from device tree. @@ -384,7 +385,14 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 zephyr_board_dir = pathlib.Path(runners["config"]["board_dir"]) board_yaml = zephyr_board_dir / "board.yml" board_yaml = yaml.safe_load(board_yaml.read_text()) - board_info["vendor_id"] = board_yaml["board"]["vendor"] + if "board" not in board_yaml and "boards" in board_yaml: + for board in board_yaml["boards"]: + if board["name"] == board_id: + board_yaml = board + break + else: + board_yaml = board_yaml["board"] + board_info["vendor_id"] = board_yaml["vendor"] vendor_index = zephyr_board_dir.parent / "index.rst" if vendor_index.exists(): vendor_index = vendor_index.read_text() @@ -393,9 +401,9 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 else: vendor_name = board_info["vendor_id"] board_info["vendor"] = vendor_name - soc_name = board_yaml["board"]["socs"][0]["name"] + soc_name = board_yaml["socs"][0]["name"] board_info["soc"] = soc_name - board_name = board_yaml["board"]["full_name"] + board_name = board_yaml["full_name"] board_info["name"] = board_name # board_id_yaml = zephyr_board_dir / (zephyr_board_dir.name + ".yaml") # board_id_yaml = yaml.safe_load(board_id_yaml.read_text()) @@ -540,15 +548,18 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 board_names[(ioport, num)].append("BUTTON") board_names[(ioport, num)].extend(node2alias[key]) - a, b = all_ioports[:2] - i = 0 - while a[i] == b[i]: - i += 1 - shared_prefix = a[:i] - for ioport in ioports: - if not ioport.startswith(shared_prefix): - shared_prefix = "" - break + if len(all_ioports) > 1: + a, b = all_ioports[:2] + i = 0 + while a[i] == b[i]: + i += 1 + shared_prefix = a[:i] + for ioport in ioports: + if not ioport.startswith(shared_prefix): + shared_prefix = "" + break + else: + shared_prefix = all_ioports[0] pin_defs = [] pin_declarations = ["#pragma once"] @@ -658,8 +669,14 @@ def zephyr_dts_to_cp_board(portdir, builddir, zephyrbuilddir): # noqa: C901 device, start, end, size, path = ram max_size = max(max_size, size) # We always start at the end of a Zephyr linker section so we need the externs and &. - ram_externs.append(f"extern uint32_t {start};") - start = "&" + start + if board_id in ["native_sim"]: + ram_externs.append("// This is a native board so we provide all of RAM for our heaps.") + ram_externs.append(f"static uint32_t _{device}[{size // 4}]; // {path}") + start = f"(const uint32_t *) (_{device})" + end = f"(const uint32_t *)(_{device} + {size // 4})" + else: + ram_externs.append(f"extern uint32_t {start};") + start = "&" + start ram_list.append(f" {start}, {end}, // {path}") ram_list = "\n".join(ram_list) ram_externs = "\n".join(ram_externs) diff --git a/ports/zephyr-cp/supervisor/flash.c b/ports/zephyr-cp/supervisor/flash.c index 8daef5fcdaa..38f35a5235a 100644 --- a/ports/zephyr-cp/supervisor/flash.c +++ b/ports/zephyr-cp/supervisor/flash.c @@ -21,7 +21,7 @@ #include #define CIRCUITPY_PARTITION circuitpy_partition -static struct flash_area *filesystem_area = NULL; +static const struct flash_area *filesystem_area = NULL; #if !FIXED_PARTITION_EXISTS(CIRCUITPY_PARTITION) static struct flash_area _dynamic_area; diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 799e44800cf..7be2beb1d20 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -7,6 +7,7 @@ #include "supervisor/port.h" #include "mpconfigboard.h" +#include "supervisor/shared/tick.h" #include #include @@ -66,6 +67,10 @@ void port_wake_main_task_from_isr(void) { void port_yield(void) { k_yield(); + // Make sure time advances in the simulator. + #if defined(CONFIG_ARCH_POSIX) + k_busy_wait(100); + #endif } void port_boot_info(void) { @@ -73,14 +78,14 @@ void port_boot_info(void) { // Get stack limit address uint32_t *port_stack_get_limit(void) { - return k_current_get()->stack_info.start; + return (uint32_t *)k_current_get()->stack_info.start; } // Get stack top address uint32_t *port_stack_get_top(void) { _thread_stack_info_t stack_info = k_current_get()->stack_info; - return stack_info.start + stack_info.size - stack_info.delta; + return (uint32_t *)(stack_info.start + stack_info.size - stack_info.delta); } // Save and retrieve a word from memory that is preserved over reset. Used for safe mode. @@ -181,7 +186,10 @@ size_t port_heap_get_largest_free_size(void) { void assert_post_action(const char *file, unsigned int line) { printk("Assertion failed at %s:%u\n", file, line); + // Check that this is arm + #if defined(__arm__) __asm__ ("bkpt"); + #endif while (1) { ; } diff --git a/shared/runtime/gchelper_generic.c b/shared/runtime/gchelper_generic.c index 45b2e4f7d84..40c5865ed1c 100644 --- a/shared/runtime/gchelper_generic.c +++ b/shared/runtime/gchelper_generic.c @@ -74,10 +74,10 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { #elif defined(__i386__) static void gc_helper_get_regs(gc_helper_regs_t arr) { - register long ebx asm ("ebx"); - register long esi asm ("esi"); - register long edi asm ("edi"); - register long ebp asm ("ebp"); + register long ebx __asm__ ("ebx"); + register long esi __asm__ ("esi"); + register long edi __asm__ ("edi"); + register long ebp __asm__ ("ebp"); #ifdef __clang__ // TODO: // This is dirty workaround for Clang. It tries to get around diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c index ffeb78bbb83..02aa9ae84d5 100644 --- a/supervisor/shared/background_callback.c +++ b/supervisor/shared/background_callback.c @@ -61,6 +61,7 @@ static int background_prevention_count; void PLACE_IN_ITCM(background_callback_run_all)(void) { port_background_task(); if (!background_callback_pending()) { + port_yield(); return; } CALLBACK_CRITICAL_BEGIN; @@ -87,6 +88,7 @@ void PLACE_IN_ITCM(background_callback_run_all)(void) { } --background_prevention_count; CALLBACK_CRITICAL_END; + port_yield(); } void background_callback_prevent(void) { diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 5f24618f7f3..a3e4de235c7 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -18,6 +18,8 @@ #include "supervisor/shared/translate/translate.h" #include "supervisor/shared/tick.h" +#include + #define SAFE_MODE_DATA_GUARD 0xad0000af #define SAFE_MODE_DATA_GUARD_MASK 0xff0000ff @@ -78,6 +80,7 @@ safe_mode_t wait_for_safe_mode_reset(void) { boot_in_safe_mode = true; break; } + port_yield(); diff = supervisor_ticks_ms64() - start_ticks; } #if CIRCUITPY_STATUS_LED @@ -99,10 +102,19 @@ void PLACE_IN_ITCM(safe_mode_on_next_reset)(safe_mode_t reason) { // Don't inline this so it's easy to break on it from GDB. void __attribute__((noinline, )) PLACE_IN_ITCM(reset_into_safe_mode)(safe_mode_t reason) { if (_safe_mode > SAFE_MODE_BROWNOUT && reason > SAFE_MODE_BROWNOUT) { + #if __ZEPHYR__ + printk("Already in safe mode\n"); + printk("Reason: %d\n", reason); + printk("Current safe mode: %d\n", _safe_mode); + while (true) { + k_cpu_idle(); + } + #else while (true) { // This very bad because it means running in safe mode didn't save us. Only ignore brownout // because it may be due to a switch bouncing. } + #endif } safe_mode_on_next_reset(reason); From 885428e43274856a27d265f4ca3acd5a04a1d916 Mon Sep 17 00:00:00 2001 From: Sean Carolan Date: Fri, 30 Jan 2026 15:04:38 -0500 Subject: [PATCH 166/876] Add M5Stack CoreS3 SE board definition The CoreS3 SE is a variant of the CoreS3 with the camera, IMU, magnetometer, proximity sensor, and audio codec removed, paired with the M5GO Battery Bottom3 which adds 10 NeoPixels (GPIO5) and an IR transmitter (GPIO7). Based on the CoreS3 board definition with the following changes: - Board name set to "M5Stack CoreS3 SE" - NEOPIXEL pin defined (GPIO5) for M5GO Bottom3 LEDs - Camera pin definitions and data tuple removed from pins.c - NEOPIXEL and IR named pin aliases added to pins.c - ESPCAMERA support disabled in mpconfigboard.mk - Camera-related AXP2101 power rails (ALDO2/ALDO3) disabled in board.c - Camera config removed from sdkconfig - SD card CS (GPIO4) driven high before display init to mitigate shared SPI bus contention (see #10536) Note: SD card does not work on any Core S3 variant in CircuitPython due to GPIO35 being shared between SPI MISO and display DC pin (upstream issues #10536, #6290). Tested on hardware: display, I2C (AXP2101, AW9523B, FT6336, BM8563), NeoPixels, IR pin, I2S speaker pins, Port B/C GPIOs all verified. Co-Authored-By: Claude Opus 4.5 --- .../boards/m5stack_cores3_se/board.c | 224 ++++++++++++++++++ .../boards/m5stack_cores3_se/mpconfigboard.h | 25 ++ .../boards/m5stack_cores3_se/mpconfigboard.mk | 27 +++ .../espressif/boards/m5stack_cores3_se/pins.c | 87 +++++++ .../boards/m5stack_cores3_se/sdkconfig | 14 ++ 5 files changed, 377 insertions(+) create mode 100644 ports/espressif/boards/m5stack_cores3_se/board.c create mode 100644 ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h create mode 100644 ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk create mode 100644 ports/espressif/boards/m5stack_cores3_se/pins.c create mode 100644 ports/espressif/boards/m5stack_cores3_se/sdkconfig diff --git a/ports/espressif/boards/m5stack_cores3_se/board.c b/ports/espressif/boards/m5stack_cores3_se/board.c new file mode 100644 index 00000000000..cf06bd8488d --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/board.c @@ -0,0 +1,224 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/busio/I2C.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" +#include "common-hal/microcontroller/Pin.h" + + +#define DELAY 0x80 +#define AXP2101_I2C_ADDRESS 0x34 +#define AW9523B_I2C_ADDRESS 0x58 + +uint8_t display_init_sequence[] = { + 0x01, DELAY, 0x80, // Software reset then delay 0x80 (128ms) + 0xC8, 0x03, 0xFF, 0x93, 0x42, // Turn on the external command + 0xC0, 0x02, 0x12, 0x12, // Power Control 1 + 0xC1, 0x01, 0x03, // Power Control 2 + 0xC5, 0x01, 0xF2, // VCOM Control 1 + 0xB0, 0x01, 0xE0, // RGB Interface SYNC Mode + 0xF6, 0x03, 0x01, 0x00, 0x00, // Interface control + 0XE0, 0x0F, 0x00, 0x0C, 0x11, 0x04, 0x11, 0x08, 0x37, 0x89, 0x4C, 0x06, 0x0C, 0x0A, 0x2E, 0x34, 0x0F, // Positive Gamma Correction + 0xE1, 0x0F, 0x00, 0x0B, 0x11, 0x05, 0x13, 0x09, 0x33, 0x67, 0x48, 0x07, 0x0E, 0x0B, 0x2E, 0x33, 0x0F, // Negative Gamma Correction + 0xB6, 0x04, 0x08, 0x82, 0x1D, 0x04, // Display Function Control + 0x3A, 0x01, 0x55, // COLMOD: Pixel Format Set 16 bit + 0x21, 0x00, // Display inversion ON + 0x36, 0x01, 0x08, // Memory Access Control: RGB order + 0x11, DELAY, 0x78, // Exit Sleep then delay 0x78 (120ms) + 0x29, DELAY, 0x78, // Display on then delay 0x78 (120ms) +}; + +static bool display_init(void) { + busio_spi_obj_t *spi = common_hal_board_create_spi(0); + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + bus->base.type = &fourwire_fourwire_type; + + common_hal_fourwire_fourwire_construct( + bus, + spi, + &pin_GPIO35, // DC + &pin_GPIO3, // CS + NULL, // RST + 40000000, // baudrate + 0, // polarity + 0 // phase + ); + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 320, // width (after rotation) + 240, // height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // color depth + false, // grayscale + false, // pixels in a byte share a row. Only valid for depths < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + NULL, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 61, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); + + return true; +} + +static bool axp2101_init(busio_i2c_obj_t *i2c) { + int rc; + uint8_t write_buf[2]; + + // 0x90 = 0b1011_0011 // LDOS ON/OFF control 0 + // Compared to CoreS3: ALDO2 (bit 2) and ALDO3 (bit 3) disabled (no ES7210/camera) + write_buf[0] = 0x90; + write_buf[1] = 0b10110011; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x92, 0x0D // ALDO1 set to 1.8v for AW88298 + write_buf[0] = 0x92; + write_buf[1] = 0x0D; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x95, 0x1C // ALDO4 set to 3.3v for TF card slot + write_buf[0] = 0x95; + write_buf[1] = 0x1C; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x99, 0x18 // DLDO1 set to 2.9v for TFT backlight + write_buf[0] = 0x99; + write_buf[1] = 0x18; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x27, 0x00 // PowerKey Hold=1sec / PowerOff=4sec + write_buf[0] = 0x27; + write_buf[1] = 0x00; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x69, 0x11 // CHGLED setting + write_buf[0] = 0x69; + write_buf[1] = 0x11; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x10, 0x30 // PMU common config + write_buf[0] = 0x10; + write_buf[1] = 0x30; + rc = common_hal_busio_i2c_write(i2c, AXP2101_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + return true; +} + +static bool aw9523b_init(busio_i2c_obj_t *i2c) { + int rc; + uint8_t write_buf[2]; + + // 0x02 = 0b0000_0111 // AW_RST, BUD_OUT_EN, TOUCH_RST + write_buf[0] = 0x02; + write_buf[1] = 0b00000111; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x03 = 0b1000_0011 // BOOST_EN, CAM_RST, LCD_RST + write_buf[0] = 0x03; + write_buf[1] = 0b10000011; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x04 = 0b0001_1000 // Set TF_SW, ES_INT as input + write_buf[0] = 0x04; + write_buf[1] = 0b00011000; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x05 = 0b0000_1100 // Set AW_INT, TOUCH_INT as input + write_buf[0] = 0x05; + write_buf[1] = 0b00001100; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + // 0x11 = 0b0001_0000 // Set P0 outputs in push pull mode + write_buf[0] = 0x11; + write_buf[1] = 0b00010000; + rc = common_hal_busio_i2c_write(i2c, AW9523B_I2C_ADDRESS, write_buf, sizeof(write_buf)); + if (rc != 0) { + return false; + } + + return true; +} + +void board_init(void) { + // Deselect SD card on shared SPI bus before display init (see #10536) + config_pin_as_output_with_level(GPIO_NUM_4, true); + + busio_i2c_obj_t *internal_i2c = common_hal_board_create_i2c(0); + + if (!axp2101_init(internal_i2c)) { + mp_printf(&mp_plat_print, "could not initialize AXP2101"); + return; + } + + if (!aw9523b_init(internal_i2c)) { + mp_printf(&mp_plat_print, "could not initialize AW9523B"); + return; + } + + if (!display_init()) { + mp_printf(&mp_plat_print, "could not initialize the display"); + return; + } +} diff --git a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h new file mode 100644 index 00000000000..070ccf9195e --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h @@ -0,0 +1,25 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "M5Stack CoreS3 SE" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO5) + +#define CIRCUITPY_BOARD_I2C (2) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO11, .sda = &pin_GPIO12}, \ + {.scl = &pin_GPIO1, .sda = &pin_GPIO2}} + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO37) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO35) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO18) +#define DEFAULT_UART_BUS_TX (&pin_GPIO17) diff --git a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk new file mode 100644 index 00000000000..6b43abb6839 --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk @@ -0,0 +1,27 @@ +USB_VID = 0x303A +USB_PID = 0x811B + +USB_PRODUCT = "M5Stack CoreS3 SE" +USB_MANUFACTURER = "M5Stack" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +CIRCUITPY_PARALLELDISPLAYBUS = 0 + +OPTIMIZATION_FLAGS = -Os + +# Include these Python libraries in firmware. +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_ConnectionManager +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Shapes +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Text +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_FakeRequests +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Requests diff --git a/ports/espressif/boards/m5stack_cores3_se/pins.c b/ports/espressif/boards/m5stack_cores3_se/pins.c new file mode 100644 index 00000000000..f0e20926bfa --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/pins.c @@ -0,0 +1,87 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +CIRCUITPY_BOARD_BUS_SINGLETON(porta_i2c, i2c, 1) + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // M5 Bus (except I2S) + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_PORTC_RX), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_A18), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_PORTA_SDA), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_PORTB_IN), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_PORTB_OUT), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_D43), MP_ROM_PTR(&pin_GPIO43) }, + + { MP_ROM_QSTR(MP_QSTR_PORTC_TX), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_A17), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_PORTA_SCL), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_IR), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO7) }, + + // I2S + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DATA_OUT), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DATA_IN), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MASTER_CLOCK), MP_ROM_PTR(&pin_GPIO0) }, + + // Display + { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO35) }, + + // Misc + { MP_ROM_QSTR(MP_QSTR_I2C_INTERRUPT), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SDCARD_CS), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_PORTA_I2C), MP_ROM_PTR(&board_porta_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/m5stack_cores3_se/sdkconfig b/ports/espressif/boards/m5stack_cores3_se/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/m5stack_cores3_se/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From 069ad6aecffe6ae48b9bdc34ace41791d50a39d7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 27 Jan 2026 16:19:40 -0800 Subject: [PATCH 167/876] Add basic native sim tests --- .github/workflows/run-tests.yml | 2 +- ports/zephyr-cp/CMakeLists.txt | 5 + ports/zephyr-cp/Makefile | 3 +- ports/zephyr-cp/boards/native_sim.conf | 14 + ports/zephyr-cp/boards/native_sim.overlay | 12 + ports/zephyr-cp/docs/perfetto-tracing.md | 150 +++++ ports/zephyr-cp/native_sim_i2c_emul_control.c | 169 +++++ ports/zephyr-cp/tests/TEST_IDEAS.md | 623 ++++++++++++++++++ ports/zephyr-cp/tests/conftest.py | 312 +++++++++ .../docs/i2c_emulator_cmdline_control.md | 306 +++++++++ ports/zephyr-cp/tests/test_basics.py | 199 ++++++ ports/zephyr-cp/tests/test_i2c.py | 98 +++ 12 files changed, 1891 insertions(+), 2 deletions(-) create mode 100644 ports/zephyr-cp/docs/perfetto-tracing.md create mode 100644 ports/zephyr-cp/native_sim_i2c_emul_control.c create mode 100644 ports/zephyr-cp/tests/TEST_IDEAS.md create mode 100644 ports/zephyr-cp/tests/conftest.py create mode 100644 ports/zephyr-cp/tests/docs/i2c_emulator_cmdline_control.md create mode 100644 ports/zephyr-cp/tests/test_basics.py create mode 100644 ports/zephyr-cp/tests/test_i2c.py diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 06fe3bf6aea..ed0dd65a4f1 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -88,5 +88,5 @@ jobs: uses: ./.github/actions/deps/ports/zephyr-cp - name: Set up external uses: ./.github/actions/deps/external - - name: Run Zephyr build tests + - name: Run Zephyr tests run: make -C ports/zephyr-cp test diff --git a/ports/zephyr-cp/CMakeLists.txt b/ports/zephyr-cp/CMakeLists.txt index e35b4b7c764..0ba4a3c48b3 100644 --- a/ports/zephyr-cp/CMakeLists.txt +++ b/ports/zephyr-cp/CMakeLists.txt @@ -5,6 +5,11 @@ project(circuitpython) target_sources(app PRIVATE zephyr_main.c) +# Add I2C emulator control for native_sim testing +if(CONFIG_BOARD_NATIVE_SIM) + target_sources(app PRIVATE native_sim_i2c_emul_control.c) +endif() + # From: https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/application_development/external_lib/CMakeLists.txt # The external static library that we are linking with does not know # how to build for this platform so we export all the flags used in diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index d31068e4c92..15ae523fb72 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -46,5 +46,6 @@ all: clean-all: rm -rf build build-* -test: +test: build-native_native_sim/zephyr-cp/zephyr/zephyr.exe pytest cptools/tests + pytest tests/ -v diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native_sim.conf index baf808b5142..cc295949d03 100644 --- a/ports/zephyr-cp/boards/native_sim.conf +++ b/ports/zephyr-cp/boards/native_sim.conf @@ -4,3 +4,17 @@ CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=n # So we can test safe mode CONFIG_NATIVE_SIM_REBOOT=y + +CONFIG_TRACING=y +CONFIG_TRACING_PERFETTO=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_GPIO=y + +# I2C emulation for testing +CONFIG_I2C_EMUL=y + +# EEPROM emulation for testing +CONFIG_EEPROM=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT2X_EMUL=y diff --git a/ports/zephyr-cp/boards/native_sim.overlay b/ports/zephyr-cp/boards/native_sim.overlay index 6a13f58379a..2a07108627f 100644 --- a/ports/zephyr-cp/boards/native_sim.overlay +++ b/ports/zephyr-cp/boards/native_sim.overlay @@ -36,4 +36,16 @@ }; }; +/* Add emulated I2C devices for testing */ +&i2c0 { + at24_eeprom: eeprom@50 { + compatible = "atmel,at24"; + reg = <0x50>; + size = <256>; + pagesize = <8>; + address-width = <8>; + timeout = <5>; + }; +}; + #include "../app.overlay" diff --git a/ports/zephyr-cp/docs/perfetto-tracing.md b/ports/zephyr-cp/docs/perfetto-tracing.md new file mode 100644 index 00000000000..ff35d361f70 --- /dev/null +++ b/ports/zephyr-cp/docs/perfetto-tracing.md @@ -0,0 +1,150 @@ +# Perfetto Tracing + +The Zephyr port supports Perfetto tracing for performance analysis. This document +describes how to capture, validate, and view traces. + +## Capturing Traces + +Traces are written to `circuitpython.perfetto-trace` in the port directory when +running with tracing enabled (e.g., on native_sim). + +## Validating Traces + +### Using trace_processor + +The Perfetto trace_processor tool can validate and query trace files: + +```bash +~/repos/perfetto/tools/trace_processor circuitpython.perfetto-trace +``` + +This will download the trace_processor binary if needed and open an interactive +SQL shell. If the trace loads successfully, you can query it: + +```sql +SELECT COUNT(*) FROM slice; +``` + +### Using the Perfetto UI + +Open https://ui.perfetto.dev and drag your trace file onto the page. + +## Debugging Invalid Traces + +### Common Error: Packets Skipped Due to Invalid Incremental State + +If trace_processor reports packets being skipped with messages like: + +``` +packet_skipped_seq_needs_incremental_state_invalid +``` + +This means packets have `SEQ_NEEDS_INCREMENTAL_STATE` (value 2) set but no +prior packet set `SEQ_INCREMENTAL_STATE_CLEARED` (value 1) to initialize the +incremental state. + +**Root Cause**: The process descriptor packet (which sets `SEQ_INCREMENTAL_STATE_CLEARED`) +must be emitted before any other trace packets. + +**Diagnosis**: Use protoc to inspect the raw trace: + +```bash +protoc --decode_raw < circuitpython.perfetto-trace | head -100 +``` + +Look for field 13 (sequence_flags) in the first few packets: + +- `13: 1` = SEQ_INCREMENTAL_STATE_CLEARED (good - should be first) +- `13: 2` = SEQ_NEEDS_INCREMENTAL_STATE (requires prior cleared packet) + +A valid trace should have the process descriptor with `13: 1` as one of the +first packets. + +**Fix**: Ensure `perfetto_start()` is called before any trace events are emitted. +The descriptor emit functions in `perfetto_encoder.c` should check: + +```c +if (!started) { + perfetto_start(); +} +``` + +### Analyzing Raw Trace Structure + +To understand the trace structure: + +```bash +# Count total packets +protoc --decode_raw < circuitpython.perfetto-trace | grep -c "^1 {" + +# Find all sequence_flags values +protoc --decode_raw < circuitpython.perfetto-trace | grep "13:" | sort | uniq -c + +# Look for track descriptors (field 60) +protoc --decode_raw < circuitpython.perfetto-trace | grep -A20 "60 {" + +# Look for process descriptors (field 3 inside track_descriptor) +protoc --decode_raw < circuitpython.perfetto-trace | grep -B5 "3 {" +``` + +### Key Protobuf Field Numbers + +TracePacket fields: + +| Field | Description | +|-------|-------------| +| 8 | timestamp | +| 10 | trusted_packet_sequence_id | +| 11 | track_event | +| 12 | interned_data | +| 13 | sequence_flags | +| 60 | track_descriptor | + +TrackDescriptor fields (inside field 60): + +| Field | Description | +|-------|-------------| +| 1 | uuid | +| 2 | name | +| 3 | process (ProcessDescriptor) | +| 4 | thread (ThreadDescriptor) | +| 5 | parent_uuid | + +## Build Verification + +After modifying tracing code, verify the build is updated: + +```bash +# Check source vs object file timestamps +ls -la zephyr/subsys/tracing/perfetto/perfetto_encoder.c +ls -la zephyr/build/zephyr/subsys/tracing/perfetto/CMakeFiles/subsys__tracing__perfetto.dir/perfetto_encoder.c.obj +``` + +The object file timestamp must be newer than the source file timestamp. If not, +rebuild the project before capturing a new trace. + +## Architecture + +The tracing implementation consists of: + +- `perfetto_encoder.c`: Encodes trace packets using nanopb +- `perfetto_top.c`: Implements Zephyr tracing hooks (sys_trace_*) +- `perfetto_encoder.h`: Public API and UUID definitions + +Key UUIDs: + +| Constant | Value | Description | +|----------|-------|-------------| +| PROCESS_UUID | 1 | Root process track | +| ISR_TRACK_UUID | 2 | Interrupt service routine track | +| TRACE_TRACK_UUID | 3 | Top-level trace track | + +### Initialization Flow + +1. `SYS_INIT` calls `perfetto_init()` at POST_KERNEL priority 0 +2. `perfetto_init()` calls `perfetto_encoder_init()` +3. `perfetto_initialized` is set to true +4. Thread hooks start firing +5. First emit function calls `perfetto_start()` +6. `perfetto_start()` emits process descriptor with `SEQ_INCREMENTAL_STATE_CLEARED` +7. Subsequent packets use `SEQ_NEEDS_INCREMENTAL_STATE` diff --git a/ports/zephyr-cp/native_sim_i2c_emul_control.c b/ports/zephyr-cp/native_sim_i2c_emul_control.c new file mode 100644 index 00000000000..de467122a7b --- /dev/null +++ b/ports/zephyr-cp/native_sim_i2c_emul_control.c @@ -0,0 +1,169 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Command-line control for enabling/disabling emulated I2C devices + * on native_sim. This allows testing device hot-plug and error scenarios. + */ + +#include +#include +#include +#include +#include +#include + +#include "nsi_cmdline.h" +#include "posix_native_task.h" + +LOG_MODULE_REGISTER(i2c_emul_control, LOG_LEVEL_INF); + +#define MAX_DISABLED_DEVICES 16 + +struct disabled_device { + const char *name; + const struct emul *emul; + struct i2c_emul_api mock_api; + bool disabled; +}; + +static struct disabled_device disabled_devices[MAX_DISABLED_DEVICES]; +static int num_disabled_devices = 0; + +static char *disabled_device_args[MAX_DISABLED_DEVICES]; +static int num_disabled_device_args = 0; + +/* + * Mock transfer function that returns -EIO (NACK) when device is disabled, + * or -ENOSYS to fall back to the real emulator. + */ +static int disabled_device_transfer(const struct emul *target, + struct i2c_msg *msgs, + int num_msgs, + int addr) { + ARG_UNUSED(msgs); + ARG_UNUSED(num_msgs); + ARG_UNUSED(addr); + + for (int i = 0; i < num_disabled_devices; i++) { + if (disabled_devices[i].emul == target) { + if (disabled_devices[i].disabled) { + LOG_DBG("Device %s is disabled, returning -EIO", + disabled_devices[i].name); + return -EIO; + } + break; + } + } + /* Fall back to normal emulator behavior */ + return -ENOSYS; +} + +int i2c_emul_control_disable_device(const char *name) { + const struct emul *emul = emul_get_binding(name); + if (!emul) { + LOG_ERR("Emulator '%s' not found", name); + return -ENODEV; + } + + if (emul->bus_type != EMUL_BUS_TYPE_I2C) { + LOG_ERR("Emulator '%s' is not an I2C device", name); + return -EINVAL; + } + + /* Find existing entry or create new one */ + int idx = -1; + for (int i = 0; i < num_disabled_devices; i++) { + if (disabled_devices[i].emul == emul) { + idx = i; + break; + } + } + + if (idx < 0) { + if (num_disabled_devices >= MAX_DISABLED_DEVICES) { + LOG_ERR("Too many disabled devices"); + return -ENOMEM; + } + idx = num_disabled_devices++; + disabled_devices[idx].name = name; + disabled_devices[idx].emul = emul; + disabled_devices[idx].mock_api.transfer = disabled_device_transfer; + + /* Install our mock_api to intercept transfers */ + emul->bus.i2c->mock_api = &disabled_devices[idx].mock_api; + } + + disabled_devices[idx].disabled = true; + LOG_INF("Disabled I2C emulator: %s", name); + return 0; +} + +int i2c_emul_control_enable_device(const char *name) { + for (int i = 0; i < num_disabled_devices; i++) { + if (strcmp(disabled_devices[i].name, name) == 0) { + disabled_devices[i].disabled = false; + LOG_INF("Enabled I2C emulator: %s", name); + return 0; + } + } + LOG_ERR("Device '%s' not in disabled list", name); + return -ENODEV; +} + +bool i2c_emul_control_is_disabled(const char *name) { + for (int i = 0; i < num_disabled_devices; i++) { + if (strcmp(disabled_devices[i].name, name) == 0) { + return disabled_devices[i].disabled; + } + } + return false; +} + +/* Command-line option handler */ +static void cmd_disable_i2c_device(char *argv, int offset) { + /* The value is at argv + offset (after the '=' in --disable-i2c=value) */ + char *value = argv + offset; + if (num_disabled_device_args < MAX_DISABLED_DEVICES) { + disabled_device_args[num_disabled_device_args++] = value; + } else { + printk("i2c_emul_control: Too many --disable-i2c arguments, ignoring: %s\n", value); + } +} + +static struct args_struct_t i2c_emul_args[] = { + { + .option = "disable-i2c", + .name = "device", + .type = 's', + .call_when_found = cmd_disable_i2c_device, + .descript = "Disable an emulated I2C device by name (can be repeated). " + "Example: --disable-i2c=bmi160" + }, + ARG_TABLE_ENDMARKER +}; + +static void register_cmdline_opts(void) { + nsi_add_command_line_opts(i2c_emul_args); +} + +/* Register command-line options early in boot */ +NATIVE_TASK(register_cmdline_opts, PRE_BOOT_1, 0); + +static int apply_disabled_devices(void) { + LOG_DBG("Applying %d disabled device(s)", num_disabled_device_args); + for (int i = 0; i < num_disabled_device_args; i++) { + int rc = i2c_emul_control_disable_device(disabled_device_args[i]); + if (rc != 0) { + LOG_WRN("Failed to disable I2C device '%s': %d", + disabled_device_args[i], rc); + } + } + return 0; +} + +/* + * Apply after emulators are initialized. + * I2C emulators are registered at POST_KERNEL level, so we need to run + * at APPLICATION level to ensure they exist. + */ +SYS_INIT(apply_disabled_devices, APPLICATION, 99); diff --git a/ports/zephyr-cp/tests/TEST_IDEAS.md b/ports/zephyr-cp/tests/TEST_IDEAS.md new file mode 100644 index 00000000000..6ef71d7a5a0 --- /dev/null +++ b/ports/zephyr-cp/tests/TEST_IDEAS.md @@ -0,0 +1,623 @@ +# CircuitPython Simulator Test Ideas + +Test ideas for the native_sim simulator, organized by module/category. + +## Core Python / Interpreter + +### 1. Multiple file priority +Test that boot.py runs before code.py, and main.py is used as fallback when code.py doesn't exist. + +```python +# boot.py +print("boot.py ran") + +# code.py +print("code.py ran") +``` + +Expected output order: "boot.py ran" then "code.py ran" + +### 2. Exception handling +Verify tracebacks print correctly with file/line info, and exception types propagate properly. + +```python +def inner(): + raise ValueError("test error") + +def outer(): + inner() + +outer() +``` + +### 3. Memory / gc module +Test `gc.collect()`, `gc.mem_free()`, `gc.mem_alloc()`, and behavior under memory pressure. + +```python +import gc +gc.collect() +free_before = gc.mem_free() +data = [0] * 1000 +free_after = gc.mem_free() +assert free_after < free_before +del data +gc.collect() +free_final = gc.mem_free() +print("done") +``` + +### 4. Import system +Test importing frozen modules vs filesystem modules, verify import errors are clear. + +```python +import sys +import board +import digitalio +print(f"modules loaded: {len(sys.modules)}") +print("done") +``` + +--- + +## digitalio + +### 5. Input mode +Test reading GPIO input state. May require trace file injection or loopback configuration. + +```python +import board +import digitalio + +pin = digitalio.DigitalInOut(board.D0) +pin.direction = digitalio.Direction.INPUT +value = pin.value +print(f"input value: {value}") +print("done") +``` + +### 6. Pull resistors +Verify pull-up/pull-down configuration affects input readings. + +```python +import board +import digitalio + +pin = digitalio.DigitalInOut(board.D0) +pin.direction = digitalio.Direction.INPUT +pin.pull = digitalio.Pull.UP +value_up = pin.value +pin.pull = digitalio.Pull.DOWN +value_down = pin.value +print(f"pull-up: {value_up}, pull-down: {value_down}") +print("done") +``` + +### 7. Direction switching +Switch same pin between input/output modes multiple times. + +```python +import board +import digitalio + +pin = digitalio.DigitalInOut(board.D0) +pin.direction = digitalio.Direction.OUTPUT +pin.value = True +pin.direction = digitalio.Direction.INPUT +_ = pin.value +pin.direction = digitalio.Direction.OUTPUT +pin.value = False +print("done") +``` + +--- + +## time module + +### 8. time.sleep() precision +Verify sleep timing via Perfetto trace timestamps. Use GPIO transitions as timing markers. + +```python +import time +import board +import digitalio + +led = digitalio.DigitalInOut(board.LED) +led.direction = digitalio.Direction.OUTPUT + +led.value = True +time.sleep(0.05) # 50ms +led.value = False +time.sleep(0.1) # 100ms +led.value = True +time.sleep(0.05) # 50ms +led.value = False +print("done") +``` + +Verify trace shows: 50ms high, 100ms low, 50ms high pattern. + +### 9. time.monotonic() +Test monotonic clock increments correctly and never goes backward. + +```python +import time + +samples = [] +for _ in range(10): + samples.append(time.monotonic()) + time.sleep(0.01) + +# Verify monotonic increase +for i in range(1, len(samples)): + assert samples[i] > samples[i-1], "monotonic went backward!" + +elapsed = samples[-1] - samples[0] +assert 0.08 < elapsed < 0.15, f"unexpected elapsed: {elapsed}" +print("done") +``` + +### 10. time.localtime / struct_time +Test time structure operations if available. + +```python +import time + +t = time.localtime() +print(f"year: {t.tm_year}") +print(f"month: {t.tm_mon}") +print(f"day: {t.tm_mday}") +print("done") +``` + +--- + +## microcontroller + +### 11. microcontroller.cpu properties +Test frequency, temperature, UID properties. + +```python +import microcontroller + +print(f"frequency: {microcontroller.cpu.frequency}") +print(f"uid: {microcontroller.cpu.uid.hex()}") +print("done") +``` + +### 12. Safe mode +Trigger and verify safe mode entry (requires CONFIG_NATIVE_SIM_REBOOT=y). + +```python +import microcontroller +# This would trigger safe mode - test carefully +# microcontroller.on_next_reset(microcontroller.RunMode.SAFE_MODE) +# microcontroller.reset() +print("done") +``` + +### 13. Reset reason +Test microcontroller.reset_reason after various reset types. + +```python +import microcontroller + +reason = microcontroller.reset_reason +print(f"reset reason: {reason}") +print("done") +``` + +--- + +## os module + +### 14. os.uname() +Verify returns correct system info for native_sim. + +```python +import os + +info = os.uname() +print(f"sysname: {info.sysname}") +print(f"machine: {info.machine}") +print(f"release: {info.release}") +print("done") +``` + +### 15. Filesystem operations +Test os.listdir(), os.stat(), os.remove(). + +```python +import os + +# List root +files = os.listdir("/") +print(f"root files: {files}") + +# Stat a file +if "code.py" in files: + stat = os.stat("/code.py") + print(f"code.py size: {stat[6]}") + +print("done") +``` + +### 16. os.getenv() +Test environment variable reading. + +```python +import os + +# May return None if not set +path = os.getenv("PATH") +print(f"PATH exists: {path is not None}") +print("done") +``` + +--- + +## board module + +### 17. board.board_id +Verify board ID matches expected value. + +```python +import board + +print(f"board_id: {board.board_id}") +assert board.board_id == "native_native_sim" +print("done") +``` + +### 18. Pin availability +Test that board.LED and other defined pins exist. + +```python +import board + +assert hasattr(board, "LED"), "board.LED missing" +print(f"LED pin: {board.LED}") +print("done") +``` + +--- + +## Filesystem + +### 19. File read/write +Create, read, and modify files on CIRCUITPY. + +```python +# Write a test file +with open("/test.txt", "w") as f: + f.write("hello world") + +# Read it back +with open("/test.txt", "r") as f: + content = f.read() + +assert content == "hello world" +print("done") +``` + +### 20. Directory operations +Test mkdir, rmdir, nested paths. + +```python +import os + +# Create directory +os.mkdir("/testdir") +assert "testdir" in os.listdir("/") + +# Create file in directory +with open("/testdir/file.txt", "w") as f: + f.write("nested") + +# Clean up +os.remove("/testdir/file.txt") +os.rmdir("/testdir") +assert "testdir" not in os.listdir("/") +print("done") +``` + +### 21. Large file handling +Test with larger files approaching flash limits. + +```python +import gc + +# Write 10KB file +data = "x" * 10240 +with open("/large.txt", "w") as f: + f.write(data) + +# Verify size +import os +stat = os.stat("/large.txt") +assert stat[6] == 10240 + +# Clean up +os.remove("/large.txt") +gc.collect() +print("done") +``` + +--- + +## Error Conditions + +### 22. Syntax error in code.py +Verify graceful error message when code.py has syntax error. + +```python +# code.py with intentional syntax error: +def broken( + print("missing close paren" +``` + +Expected: Clear syntax error message with line number. + +### 23. Runtime error +Verify traceback format shows file, line, and function. + +```python +def cause_error(): + x = 1 / 0 + +cause_error() +``` + +Expected: Traceback showing ZeroDivisionError with line info. + +### 24. Keyboard interrupt +Test Ctrl+C handling via PTY if applicable. + +```python +import time + +print("starting long loop") +for i in range(100): + print(f"iteration {i}") + time.sleep(0.1) +print("done") +``` + +Send Ctrl+C during execution, verify clean KeyboardInterrupt. + +--- + +## busio (if emulation available) + +### 25. busio.UART +Basic UART operations if configured. + +```python +import board +import busio + +# Check if UART pins exist +if hasattr(board, "TX") and hasattr(board, "RX"): + uart = busio.UART(board.TX, board.RX, baudrate=115200) + uart.write(b"test") + uart.deinit() +print("done") +``` + +### 26. busio.I2C scan +Scan for emulated I2C devices. + +```python +import board +import busio + +if hasattr(board, "SCL") and hasattr(board, "SDA"): + i2c = busio.I2C(board.SCL, board.SDA) + while not i2c.try_lock(): + pass + devices = i2c.scan() + print(f"I2C devices: {[hex(d) for d in devices]}") + i2c.unlock() + i2c.deinit() +print("done") +``` + +### 27. busio.SPI +Basic SPI transfer to emulated device. + +```python +import board +import busio + +if hasattr(board, "SCK") and hasattr(board, "MOSI"): + spi = busio.SPI(board.SCK, MOSI=board.MOSI, MISO=getattr(board, "MISO", None)) + while not spi.try_lock(): + pass + spi.configure(baudrate=1000000) + result = bytearray(4) + spi.write_readinto(b"\x00\x00\x00\x00", result) + spi.unlock() + spi.deinit() +print("done") +``` + +--- + +## Serial/PTY Input + +These tests require extending conftest.py to support writing to the PTY, not just reading. + +### 28. Basic serial input +Test reading single characters from serial via PTY write. + +```python +import sys + +print("ready") +char = sys.stdin.read(1) +print(f"received: {repr(char)}") +print("done") +``` + +**Test harness**: After seeing "ready", write "A" to PTY, verify output shows "received: 'A'". + +### 29. input() function +Test the built-in input() function with PTY input. + +```python +print("ready") +name = input("Enter name: ") +print(f"hello {name}") +print("done") +``` + +**Test harness**: After seeing "Enter name:", write "World\n" to PTY, verify "hello World". + +### 30. Serial line buffering +Test reading a complete line with newline termination. + +```python +import sys + +print("ready") +line = sys.stdin.readline() +print(f"got: {repr(line)}") +print("done") +``` + +**Test harness**: Write "test line\n" to PTY, verify complete line received. + +### 31. usb_cdc.console data read +Test reading from usb_cdc.console.data if available. + +```python +import usb_cdc + +print("ready") +if usb_cdc.console: + while not usb_cdc.console.in_waiting: + pass + data = usb_cdc.console.read(usb_cdc.console.in_waiting) + print(f"console got: {data}") +print("done") +``` + +**Test harness**: Write bytes to PTY, verify they're received via usb_cdc.console. + +### 32. REPL interaction +Test entering REPL mode and executing commands interactively. + +```python +# No code.py - boots to REPL +``` + +**Test harness**: +1. Boot with empty/no code.py to get REPL prompt +2. Write "1 + 1\r\n" to PTY +3. Verify output contains "2" +4. Write "print('hello')\r\n" +5. Verify output contains "hello" + +### 33. Ctrl+C interrupt via PTY +Test sending Ctrl+C (0x03) to interrupt running code. + +```python +import time + +print("starting") +for i in range(100): + print(f"loop {i}") + time.sleep(0.1) +print("completed") # Should not reach this +``` + +**Test harness**: +1. Wait for "loop 5" in output +2. Write b"\x03" (Ctrl+C) to PTY +3. Verify KeyboardInterrupt raised +4. Verify "completed" NOT in output + +### 34. Ctrl+D soft reload via PTY +Test sending Ctrl+D (0x04) to trigger soft reload. + +```python +print("first run") +import time +time.sleep(10) # Long sleep to allow interrupt +print("done") +``` + +**Test harness**: +1. Wait for "first run" +2. Write b"\x04" (Ctrl+D) to PTY +3. Verify code restarts (see "first run" again or reload message) + +### 35. Serial input timeout +Test behavior when waiting for input with timeout. + +```python +import sys +import select + +print("ready") +# Poll for input with timeout +readable, _, _ = select.select([sys.stdin], [], [], 0.5) +if readable: + data = sys.stdin.read(1) + print(f"got: {repr(data)}") +else: + print("timeout") +print("done") +``` + +**Test harness**: Don't send anything, verify "timeout" appears. + +--- + +## Fixture Changes for PTY Input + +The `run_circuitpython` fixture in conftest.py needs to be extended: + +```python +@dataclass +class SimulatorResult: + output: str + trace_file: Path + pty_write_fd: int # New: file descriptor for writing to PTY + +def _run(code: str | None, timeout: float = 5.0, ...) -> SimulatorResult: + # Open PTY for both read AND write + pty_fd = os.open(pty_path, os.O_RDWR | os.O_NONBLOCK) + # ... +``` + +Or provide a callback/queue mechanism: + +```python +def _run(code, timeout=5.0, input_sequence=None): + """ + input_sequence: list of (trigger_text, bytes_to_send) tuples + When trigger_text is seen in output, send bytes_to_send to PTY + """ +``` + +--- + +## Implementation Priority + +Suggested order for implementation: + +### Phase 1: Basic module tests (no fixture changes) +1. **#17 board.board_id** - Quick sanity check +2. **#14 os.uname()** - Tests another module, simple +3. **#9 time.monotonic()** - Core timing functionality +4. **#8 time.sleep() precision** - Builds on GPIO trace infrastructure +5. **#1 Multiple file priority** - Tests interpreter boot sequence +6. **#19 File read/write** - Tests filesystem layer +7. **#3 Memory / gc** - Tests memory management +8. **#2 Exception handling** - Tests error reporting + +### Phase 2: PTY input tests (requires fixture extension) +9. **#28 Basic serial input** - Foundation for all input tests +10. **#33 Ctrl+C interrupt** - Important for interactive use +11. **#29 input() function** - Common user pattern +12. **#32 REPL interaction** - Tests interactive mode diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py new file mode 100644 index 00000000000..f26c7f0f45f --- /dev/null +++ b/ports/zephyr-cp/tests/conftest.py @@ -0,0 +1,312 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Pytest fixtures for CircuitPython native_sim testing.""" + +import logging +import os +import re +import select +import subprocess +import time +from dataclasses import dataclass +from pathlib import Path + +import pytest +from perfetto.trace_processor import TraceProcessor + +logger = logging.getLogger(__name__) + +ZEPHYR_CP = Path(__file__).parent.parent +BUILD_DIR = ZEPHYR_CP / "build-native_native_sim" +BINARY = BUILD_DIR / "zephyr-cp/zephyr/zephyr.exe" + + +@dataclass +class InputTrigger: + """A trigger for sending input to the simulator. + + Attributes: + trigger: Text to match in output to trigger input, or None for immediate send. + data: Bytes to send when triggered. + sent: Whether this trigger has been sent (set internally). + """ + + trigger: str | None + data: bytes + sent: bool = False + + +@dataclass +class SimulatorResult: + """Result from running CircuitPython on the simulator.""" + + output: str + trace_file: Path + + +def parse_gpio_trace(trace_file: Path, pin_name: str = "gpio_emul.00") -> list[tuple[int, int]]: + """Parse GPIO trace from Perfetto trace file. + + Args: + trace_file: Path to the Perfetto trace file. + pin_name: Name of the GPIO pin track (e.g., "gpio_emul.00"). + + Returns: + List of (timestamp_ns, value) tuples for the specified GPIO pin. + """ + tp = TraceProcessor(file_path=str(trace_file)) + result = tp.query( + f''' + SELECT c.ts, c.value + FROM counter c + JOIN track t ON c.track_id = t.id + WHERE t.name = "{pin_name}" + ORDER BY c.ts + ''' + ) + return [(row.ts, int(row.value)) for row in result] + + +def _iter_uart_tx_slices(trace_file: Path) -> list[tuple[int, int, str, str]]: + """Return UART TX slices as (timestamp_ns, duration_ns, text, device_name).""" + tp = TraceProcessor(file_path=str(trace_file)) + result = tp.query( + """ + SELECT s.ts, s.dur, s.name, dev.name AS device_name + FROM slice s + JOIN track tx ON s.track_id = tx.id + JOIN track dev ON tx.parent_id = dev.id + JOIN track uart ON dev.parent_id = uart.id + WHERE tx.name = "TX" AND uart.name = "UART" + ORDER BY s.ts + """ + ) + return [ + (int(row.ts), int(row.dur or 0), row.name or "", row.device_name or "UART") + for row in result + ] + + +def log_uart_trace_output(trace_file: Path) -> None: + """Log UART TX output from Perfetto trace with timestamps for line starts.""" + if not logger.isEnabledFor(logging.INFO): + return + slices = _iter_uart_tx_slices(trace_file) + if not slices: + return + + buffers: dict[str, list[str]] = {} + line_start_ts: dict[str, int | None] = {} + + for ts, dur, text, device in slices: + if device not in buffers: + buffers[device] = [] + line_start_ts[device] = None + + if not text: + continue + + char_step = dur / max(len(text), 1) if dur > 0 else 0.0 + for idx, ch in enumerate(text): + if line_start_ts[device] is None: + line_start_ts[device] = int(ts + idx * char_step) + buffers[device].append(ch) + if ch == "\n": + line_text = "".join(buffers[device]).rstrip("\n") + logger.info( + "UART trace %s @%d ns: %s", + device, + line_start_ts[device], + repr(line_text), + ) + buffers[device] = [] + line_start_ts[device] = None + + for device, buf in buffers.items(): + if buf: + logger.info( + "UART trace %s @%d ns (partial): %s", + device, + line_start_ts[device] or 0, + repr("".join(buf)), + ) + + +@pytest.fixture +def native_sim_binary(): + """Return path to native_sim binary, skip if not built.""" + if not BINARY.exists(): + pytest.skip(f"native_sim not built: {BINARY}") + return BINARY + + +@pytest.fixture +def create_flash_image(tmp_path): + """Factory fixture to create FAT flash images.""" + + def _create(files: dict[str, str]) -> Path: + flash = tmp_path / "flash.bin" + + # Create 2MB empty file + flash.write_bytes(b"\x00" * (2 * 1024 * 1024)) + + # Format as FAT (mformat) + subprocess.run(["mformat", "-i", str(flash), "::"], check=True) + + # Copy files (mcopy) + for name, content in files.items(): + src = tmp_path / name + src.write_text(content) + subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) + + return flash + + return _create + + +@pytest.fixture +def run_circuitpython(native_sim_binary, create_flash_image, tmp_path): + """Run CircuitPython with given code string and return output from PTY. + + Args: + code: Python code to write to code.py, or None for no code.py. + timeout: Timeout in seconds for the simulation. + erase_flash: If True, erase flash before running. + input_sequence: List of InputTrigger objects. When trigger text is seen + in output, the corresponding data is written to the PTY. If trigger + is None, the data is sent immediately when PTY is opened. + """ + + def _run( + code: str | None, + timeout: float = 5.0, + erase_flash: bool = False, + input_sequence: list[InputTrigger] | None = None, + disabled_i2c_devices: list[str] | None = None, + ) -> SimulatorResult: + files = {"code.py": code} if code is not None else {} + flash = create_flash_image(files) + triggers = list(input_sequence) if input_sequence else [] + trace_file = tmp_path / "trace.perfetto" + + cmd = [ + str(native_sim_binary), + f"--flash={flash}", + "--flash_rm", + "-no-rt", + "-wait_uart", + f"-stop_at={timeout}", + f"--trace-file={trace_file}", + ] + if erase_flash: + cmd.append("--flash_erase") + if disabled_i2c_devices: + for device in disabled_i2c_devices: + cmd.append(f"--disable-i2c={device}") + logger.info("Running: %s", " ".join(cmd)) + + # Start the process + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + + pty_path = None + pty_fd = None + output = [] + stdout_lines = [] + + try: + # Read stdout to find the PTY path + start_time = time.time() + while time.time() - start_time < timeout + 5: + if proc.poll() is not None: + # Process exited + break + + # Check if stdout has data + ready, _, _ = select.select([proc.stdout], [], [], 0.1) + if ready: + line = proc.stdout.readline() + if not line: + break + + stdout_lines.append(line.rstrip()) + + # Look for PTY path + match = re.search(r"uart connected to pseudotty: (/dev/pts/\d+)", line) + if match: + pty_path = match.group(1) + # Open the PTY for reading and writing + pty_fd = os.open(pty_path, os.O_RDWR | os.O_NONBLOCK) + + # Send any immediate triggers (trigger=None) + for t in triggers: + if t.trigger is None and not t.sent: + os.write(pty_fd, t.data) + logger.info("PTY input (immediate): %r", t.data) + t.sent = True + break + + if pty_fd is None: + raise RuntimeError("Failed to find PTY path in output") + + def check_triggers(accumulated_output: str) -> None: + """Check accumulated output against triggers and send input.""" + for t in triggers: + if t.trigger is not None and not t.sent: + if t.trigger in accumulated_output: + os.write(pty_fd, t.data) + logger.info("PTY input (trigger %r): %r", t.trigger, t.data) + t.sent = True + + # Read from PTY until process exits or timeout + while time.time() - start_time < timeout + 1: + if proc.poll() is not None: + # Process exited, do one final read + try: + ready, _, _ = select.select([pty_fd], [], [], 0.1) + if ready: + data = os.read(pty_fd, 4096) + if data: + output.append(data.decode("utf-8", errors="replace")) + except (OSError, BlockingIOError): + pass + break + + # Check if PTY has data + try: + ready, _, _ = select.select([pty_fd], [], [], 0.1) + if ready: + data = os.read(pty_fd, 4096) + if data: + output.append(data.decode("utf-8", errors="replace")) + check_triggers("".join(output)) + except (OSError, BlockingIOError): + pass + + # Read any remaining stdout + remaining_stdout = proc.stdout.read() + if remaining_stdout: + stdout_lines.extend(remaining_stdout.rstrip().split("\n")) + + # Log stdout + for line in stdout_lines: + logger.info("stdout: %s", line) + + pty_output = "".join(output) + for line in pty_output.split("\n"): + logger.info("PTY output: %s", repr(line.strip())) + log_uart_trace_output(trace_file) + return SimulatorResult(output=pty_output, trace_file=trace_file) + + finally: + if pty_fd is not None: + os.close(pty_fd) + proc.terminate() + proc.wait(timeout=1) + + return _run diff --git a/ports/zephyr-cp/tests/docs/i2c_emulator_cmdline_control.md b/ports/zephyr-cp/tests/docs/i2c_emulator_cmdline_control.md new file mode 100644 index 00000000000..8ee2925915c --- /dev/null +++ b/ports/zephyr-cp/tests/docs/i2c_emulator_cmdline_control.md @@ -0,0 +1,306 @@ +# Command-Line Control of Emulated I2C Devices in native_sim + +This document describes an approach for enabling/disabling emulated I2C devices +at runtime via command-line options in Zephyr's native_sim environment. + +## Background + +Zephyr's I2C emulation framework (`zephyr,i2c-emul-controller`) provides: + +1. **Bus emulation** - Fake I2C controller that routes transfers to emulated devices +2. **Device emulators** - Software implementations of I2C peripherals (sensors, etc.) +3. **Backend APIs** - Test interfaces for manipulating emulator state + +However, there's no built-in mechanism to enable/disable emulated devices from the +command line. This capability would be useful for: + +- Testing device hot-plug scenarios +- Simulating hardware failures +- Testing error handling paths in CircuitPython + +## Relevant Zephyr APIs + +### I2C Emulator Structure + +From `include/zephyr/drivers/i2c_emul.h`: + +```c +struct i2c_emul { + sys_snode_t node; + const struct emul *target; + const struct i2c_emul_api *api; + struct i2c_emul_api *mock_api; // If non-NULL, takes precedence + uint16_t addr; +}; + +struct i2c_emul_api { + i2c_emul_transfer_t transfer; +}; +``` + +Key insight: The `mock_api` field allows overriding the normal transfer function. +If `mock_api->transfer()` returns `-ENOSYS`, it falls back to the real API. + +### Command-Line Registration + +From `boards/native/native_sim/cmdline.h`: + +```c +void native_add_command_line_opts(struct args_struct_t *args); +``` + +### Emulator Lookup + +From `include/zephyr/drivers/emul.h`: + +```c +const struct emul *emul_get_binding(const char *name); +``` + +## Implementation Approach + +### 1. Create a Disabled Device Registry + +Track which devices are "disabled" (should NACK all transactions): + +```c +// i2c_emul_cmdline.c + +#include +#include +#include +#include "nsi_cmdline.h" + +#define MAX_DISABLED_DEVICES 16 + +static struct { + const char *name; + const struct emul *emul; + struct i2c_emul_api mock_api; + struct i2c_emul_api *original_mock_api; + bool disabled; +} disabled_devices[MAX_DISABLED_DEVICES]; + +static int num_disabled_devices = 0; +``` + +### 2. Mock Transfer Function + +Return `-EIO` (simulates NACK) when device is disabled: + +```c +static int disabled_device_transfer(const struct emul *target, + struct i2c_msg *msgs, + int num_msgs, + int addr) +{ + // Find this device in our registry + for (int i = 0; i < num_disabled_devices; i++) { + if (disabled_devices[i].emul == target) { + if (disabled_devices[i].disabled) { + // Device is disabled - simulate NACK + return -EIO; + } + break; + } + } + // Fall back to normal emulator behavior + return -ENOSYS; +} +``` + +### 3. Enable/Disable Functions + +```c +int i2c_emul_cmdline_disable_device(const char *name) +{ + const struct emul *emul = emul_get_binding(name); + if (!emul || emul->bus_type != EMUL_BUS_TYPE_I2C) { + return -ENODEV; + } + + // Find or create registry entry + int idx = -1; + for (int i = 0; i < num_disabled_devices; i++) { + if (disabled_devices[i].emul == emul) { + idx = i; + break; + } + } + + if (idx < 0) { + if (num_disabled_devices >= MAX_DISABLED_DEVICES) { + return -ENOMEM; + } + idx = num_disabled_devices++; + disabled_devices[idx].name = name; + disabled_devices[idx].emul = emul; + disabled_devices[idx].mock_api.transfer = disabled_device_transfer; + + // Save and replace mock_api + disabled_devices[idx].original_mock_api = emul->bus.i2c->mock_api; + emul->bus.i2c->mock_api = &disabled_devices[idx].mock_api; + } + + disabled_devices[idx].disabled = true; + return 0; +} + +int i2c_emul_cmdline_enable_device(const char *name) +{ + for (int i = 0; i < num_disabled_devices; i++) { + if (strcmp(disabled_devices[i].name, name) == 0) { + disabled_devices[i].disabled = false; + return 0; + } + } + return -ENODEV; +} +``` + +### 4. Command-Line Option Registration + +```c +static char *disabled_device_args[MAX_DISABLED_DEVICES]; +static int num_disabled_device_args = 0; + +static void cmd_disable_i2c_device(char *argv, int offset) +{ + ARG_UNUSED(offset); + if (num_disabled_device_args < MAX_DISABLED_DEVICES) { + disabled_device_args[num_disabled_device_args++] = argv; + } +} + +static struct args_struct_t i2c_emul_args[] = { + { + .option = "disable-i2c", + .name = "device_name", + .type = 's', + .call_when_found = cmd_disable_i2c_device, + .descript = "Disable an emulated I2C device (can be repeated)" + }, + ARG_TABLE_ENDMARKER +}; + +static void register_cmdline_opts(void) +{ + native_add_command_line_opts(i2c_emul_args); +} + +// Hook into native_sim initialization +NATIVE_TASK(register_cmdline_opts, PRE_BOOT_1, 0); + +static void apply_disabled_devices(void) +{ + for (int i = 0; i < num_disabled_device_args; i++) { + int rc = i2c_emul_cmdline_disable_device(disabled_device_args[i]); + if (rc != 0) { + printk("Warning: Failed to disable I2C device '%s': %d\n", + disabled_device_args[i], rc); + } + } +} + +// Apply after emulators are initialized +NATIVE_TASK(apply_disabled_devices, PRE_BOOT_3, 0); +``` + +### 5. Usage + +After building with this code: + +```bash +# Disable a sensor at startup +./build/zephyr/zephyr.exe --disable-i2c=bmi160@68 + +# Disable multiple devices +./build/zephyr/zephyr.exe --disable-i2c=bmi160@68 --disable-i2c=sht4x@44 +``` + +## Runtime Control Extension + +For runtime enable/disable (not just at startup), you could: + +### Option A: Use a Named Pipe / FIFO + +```c +// Create a FIFO that accepts commands +// "disable bmi160@68" or "enable bmi160@68" +static void *cmdline_control_thread(void *arg) +{ + int fd = open("/tmp/i2c_emul_control", O_RDONLY); + char buf[256]; + while (read(fd, buf, sizeof(buf)) > 0) { + if (strncmp(buf, "disable ", 8) == 0) { + i2c_emul_cmdline_disable_device(buf + 8); + } else if (strncmp(buf, "enable ", 7) == 0) { + i2c_emul_cmdline_enable_device(buf + 7); + } + } + return NULL; +} +``` + +### Option B: Signal Handler + +Use `SIGUSR1`/`SIGUSR2` with a config file that specifies which device to toggle. + +### Option C: Shared Memory + +Map a shared memory region that external tools can write to for device state. + +## Integration with CircuitPython Tests + +For pytest-based tests, you could: + +```python +import subprocess +import os + +class NativeSimProcess: + def __init__(self, exe_path): + self.exe_path = exe_path + self.control_fifo = "/tmp/i2c_emul_control" + + def start(self, disabled_devices=None): + args = [self.exe_path] + if disabled_devices: + for dev in disabled_devices: + args.extend(["--disable-i2c", dev]) + self.proc = subprocess.Popen(args, ...) + + def disable_device(self, name): + """Runtime disable via FIFO""" + with open(self.control_fifo, 'w') as f: + f.write(f"disable {name}\n") + + def enable_device(self, name): + """Runtime enable via FIFO""" + with open(self.control_fifo, 'w') as f: + f.write(f"enable {name}\n") +``` + +## Alternative: Device Tree Approach + +For compile-time configuration, use device tree overlays: + +```dts +// boards/native_sim_no_bmi160.overlay +&bmi160 { + status = "disabled"; +}; +``` + +Build separate variants: +```bash +west build -b native_sim -- -DDTC_OVERLAY_FILE=boards/native_sim_no_bmi160.overlay +``` + +## References + +- Zephyr I2C Emulation: `zephyr/drivers/i2c/i2c_emul.c` +- Emulator Framework: `zephyr/doc/hardware/emulator/bus_emulators.rst` +- Native Sim Docs: `zephyr/boards/native/native_sim/doc/index.rst` +- Command-line handling: `zephyr/boards/native/native_sim/cmdline.c` +- Example mock API usage: `zephyr/tests/drivers/sensor/bmi160/src/i2c.c` diff --git a/ports/zephyr-cp/tests/test_basics.py b/ports/zephyr-cp/tests/test_basics.py new file mode 100644 index 00000000000..9abb7f451b7 --- /dev/null +++ b/ports/zephyr-cp/tests/test_basics.py @@ -0,0 +1,199 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test LED blink functionality on native_sim.""" + +from conftest import InputTrigger, parse_gpio_trace + + +def test_blank_flash_hello_world(run_circuitpython): + """Test that an erased flash shows code.py output header.""" + result = run_circuitpython(None, timeout=4, erase_flash=True) + + assert "Board ID:native_native_sim" in result.output + assert "UID:" in result.output + assert "code.py output:" in result.output + assert "Hello World" in result.output + assert "done" in result.output + + +BLINK_CODE = """\ +import time +import board +import digitalio + +led = digitalio.DigitalInOut(board.LED) +led.direction = digitalio.Direction.OUTPUT + +for i in range(3): + print(f"LED on {i}") + led.value = True + time.sleep(0.1) + print(f"LED off {i}") + led.value = False + time.sleep(0.1) + +print("done") +""" + + +def test_blink_output(run_circuitpython): + """Test blink program produces expected output and GPIO traces.""" + result = run_circuitpython(BLINK_CODE, timeout=5) + + # Check serial output + assert "LED on 0" in result.output + assert "LED off 0" in result.output + assert "LED on 2" in result.output + assert "LED off 2" in result.output + assert "done" in result.output + + # Check GPIO traces - LED is on gpio_emul.00 + gpio_trace = parse_gpio_trace(result.trace_file, "gpio_emul.00") + + # Deduplicate by timestamp (keep last value at each timestamp) + by_timestamp = {} + for ts, val in gpio_trace: + by_timestamp[ts] = val + sorted_trace = sorted(by_timestamp.items()) + + # Find transition points (where value changes), skipping initialization at ts=0 + transitions = [] + for i in range(1, len(sorted_trace)): + prev_ts, prev_val = sorted_trace[i - 1] + curr_ts, curr_val = sorted_trace[i] + if prev_val != curr_val and curr_ts > 0: + transitions.append((curr_ts, curr_val)) + + # We expect at least 6 transitions (3 on + 3 off) from the blink loop + assert len(transitions) >= 6, f"Expected at least 6 transitions, got {len(transitions)}" + + # Verify timing between consecutive transitions + # Each sleep is 0.1s = 100ms = 100,000,000 ns + expected_interval_ns = 100_000_000 + tolerance_ns = 20_000_000 # 20ms tolerance + + # Find a sequence of 6 consecutive transitions with ~100ms intervals (the blink loop) + # This filters out initialization and cleanup noise + blink_transitions = [] + for i in range(len(transitions) - 1): + interval = transitions[i + 1][0] - transitions[i][0] + if abs(interval - expected_interval_ns) < tolerance_ns: + if not blink_transitions: + blink_transitions.append(transitions[i]) + blink_transitions.append(transitions[i + 1]) + elif blink_transitions: + # Found end of blink sequence + break + + assert len(blink_transitions) >= 6, ( + f"Expected at least 6 blink transitions with ~100ms intervals, got {len(blink_transitions)}" + ) + + # Verify timing between blink transitions + for i in range(1, min(6, len(blink_transitions))): + prev_ts = blink_transitions[i - 1][0] + curr_ts = blink_transitions[i][0] + interval = curr_ts - prev_ts + assert abs(interval - expected_interval_ns) < tolerance_ns, ( + f"Transition interval {interval / 1_000_000:.1f}ms deviates from " + f"expected {expected_interval_ns / 1_000_000:.1f}ms by more than " + f"{tolerance_ns / 1_000_000:.1f}ms tolerance" + ) + + +# --- PTY Input Tests --- + + +INPUT_CODE = """\ +import sys + +print("ready") +char = sys.stdin.read(1) +print(f"received: {repr(char)}") +print("done") +""" + + +def test_basic_serial_input(run_circuitpython): + """Test reading single character from serial via PTY write.""" + result = run_circuitpython( + INPUT_CODE, + timeout=5.0, + input_sequence=[InputTrigger(trigger="ready", data=b"A")], + ) + + assert "ready" in result.output + assert "received: 'A'" in result.output + assert "done" in result.output + + +INPUT_FUNC_CODE = """\ +print("ready") +name = input("Enter name: ") +print(f"hello {name}") +print("done") +""" + + +def test_input_function(run_circuitpython): + """Test the built-in input() function with PTY input.""" + result = run_circuitpython( + INPUT_FUNC_CODE, + timeout=5.0, + input_sequence=[InputTrigger(trigger="Enter name:", data=b"World\r")], + ) + + assert "ready" in result.output + assert "Enter name:" in result.output + assert "hello World" in result.output + assert "done" in result.output + + +INTERRUPT_CODE = """\ +import time + +print("starting") +for i in range(100): + print(f"loop {i}") + time.sleep(0.1) +print("completed") +""" + + +def test_ctrl_c_interrupt(run_circuitpython): + """Test sending Ctrl+C (0x03) to interrupt running code.""" + result = run_circuitpython( + INTERRUPT_CODE, + timeout=15.0, + input_sequence=[InputTrigger(trigger="loop 5", data=b"\x03")], + ) + + assert "starting" in result.output + assert "loop 5" in result.output + assert "KeyboardInterrupt" in result.output + assert "completed" not in result.output + + +RELOAD_CODE = """\ +print("first run") +import time +time.sleep(1) +print("done") +""" + + +def test_ctrl_d_soft_reload(run_circuitpython): + """Test sending Ctrl+D (0x04) to trigger soft reload.""" + result = run_circuitpython( + RELOAD_CODE, + timeout=10.0, + input_sequence=[InputTrigger(trigger="first run", data=b"\x04")], + ) + + # Should see "first run" appear multiple times due to reload + # or see a soft reboot message + assert "first run" in result.output + # The soft reload should restart the code before "done" is printed + assert "done" in result.output + assert result.output.count("first run") > 1 diff --git a/ports/zephyr-cp/tests/test_i2c.py b/ports/zephyr-cp/tests/test_i2c.py new file mode 100644 index 00000000000..594dfcc8f4d --- /dev/null +++ b/ports/zephyr-cp/tests/test_i2c.py @@ -0,0 +1,98 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test I2C functionality on native_sim.""" + +I2C_SCAN_CODE = """\ +import board + +i2c = board.I2C() +while not i2c.try_lock(): + pass +devices = i2c.scan() +print(f"I2C devices: {[hex(d) for d in devices]}") +i2c.unlock() +i2c.deinit() +print("done") +""" + + +def test_i2c_scan(run_circuitpython): + """Test I2C bus scanning finds emulated devices. + + The AT24 EEPROM emulator responds to zero-length probe writes, + so it should appear in scan results at address 0x50. + """ + result = run_circuitpython(I2C_SCAN_CODE, timeout=5.0) + + assert "I2C devices:" in result.output + # AT24 EEPROM should be at address 0x50 + assert "0x50" in result.output + assert "done" in result.output + + +AT24_READ_CODE = """\ +import board + +i2c = board.I2C() +while not i2c.try_lock(): + pass + +# AT24 EEPROM at address 0x50 +AT24_ADDR = 0x50 + +# Read first byte from address 0 +result = bytearray(1) +try: + i2c.writeto_then_readfrom(AT24_ADDR, bytes([0x00]), result) + value = result[0] + print(f"AT24 byte 0: 0x{value:02X}") + # Fresh EEPROM should be 0xFF + if value == 0xFF: + print("eeprom_valid") + else: + print(f"unexpected value: expected 0xFF, got 0x{value:02X}") +except OSError as e: + print(f"I2C error: {e}") + +i2c.unlock() +i2c.deinit() +print("done") +""" + + +def test_i2c_at24_read(run_circuitpython): + """Test reading from AT24 EEPROM emulator.""" + result = run_circuitpython(AT24_READ_CODE, timeout=5.0) + + assert "AT24 byte 0: 0xFF" in result.output + assert "eeprom_valid" in result.output + assert "done" in result.output + + +def test_i2c_device_disabled(run_circuitpython): + """Test that disabled I2C device doesn't appear in scan.""" + result = run_circuitpython( + I2C_SCAN_CODE, + timeout=5.0, + disabled_i2c_devices=["eeprom@50"], + ) + + assert "I2C devices:" in result.output + # AT24 at 0x50 should NOT appear when disabled + assert "0x50" not in result.output + assert "done" in result.output + + +def test_i2c_device_disabled_communication_fails(run_circuitpython): + """Test that communication with disabled I2C device fails.""" + result = run_circuitpython( + AT24_READ_CODE, + timeout=5.0, + disabled_i2c_devices=["eeprom@50"], + ) + + # Should get an I2C error when trying to communicate + assert "I2C error" in result.output + assert "eeprom_valid" not in result.output + assert "done" in result.output From e9b74b1471972cdcbdd1780ffc8765edc7003b89 Mon Sep 17 00:00:00 2001 From: Alec Delaney Date: Sun, 1 Feb 2026 12:36:34 -0500 Subject: [PATCH 168/876] Update audiobusio.PDMIn.record() --- shared-bindings/audiobusio/PDMIn.c | 34 +++++++++++++++--------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index 2a3fd3540c3..2890afda0fd 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -155,11 +155,11 @@ static void check_for_deinit(audiobusio_pdmin_obj_t *self) { // Provided by context manager helper. -//| def record(self, destination: WriteableBuffer, destination_length: int) -> None: +//| def record(self, destination: WriteableBuffer, destination_length: int) -> int: //| """Records destination_length bytes of samples to destination. This is //| blocking. //| -//| An IOError may be raised when the destination is too slow to record the +//| An OSError may be raised when the destination is too slow to record the //| audio at the given rate. For internal flash, writing all 1s to the file //| before recording is recommended to speed up writes. //| @@ -176,22 +176,22 @@ static mp_obj_t audiobusio_pdmin_obj_record(mp_obj_t self_obj, mp_obj_t destinat mp_buffer_info_t bufinfo; if (mp_obj_is_type(destination, &mp_type_fileio)) { mp_raise_NotImplementedError(MP_ERROR_TEXT("Cannot record to a file")); - } else if (mp_get_buffer(destination, &bufinfo, MP_BUFFER_WRITE)) { - if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { - mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); - } - uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self); - if (bufinfo.typecode != 'H' && bit_depth == 16) { - mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'H' for bit_depth = 16")); - } else if (bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE && bit_depth == 8) { - mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8")); - } - // length is the buffer length in slots, not bytes. - uint32_t length_written = - common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length); - return MP_OBJ_NEW_SMALL_INT(length_written); } - return mp_const_none; + + mp_get_buffer_raise(destination, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { + mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); + } + uint8_t bit_depth = common_hal_audiobusio_pdmin_get_bit_depth(self); + if (bufinfo.typecode != 'H' && bit_depth == 16) { + mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'H' for bit_depth = 16")); + } else if (bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE && bit_depth == 8) { + mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8")); + } + // length is the buffer length in slots, not bytes. + uint32_t length_written = + common_hal_audiobusio_pdmin_record_to_buffer(self, bufinfo.buf, length); + return MP_OBJ_NEW_SMALL_INT(length_written); } MP_DEFINE_CONST_FUN_OBJ_3(audiobusio_pdmin_record_obj, audiobusio_pdmin_obj_record); From 9b25e5f1c7fcc9b654b93673942f84f50dfaf014 Mon Sep 17 00:00:00 2001 From: tyeth Date: Tue, 20 Jan 2026 19:56:05 +0000 Subject: [PATCH 169/876] add(board): add Pimoroni Explorer RP2350 (PIM720) --- .../boards/pimoroni_explorer2350/board.c | 145 ++++++++++++++++++ .../pimoroni_explorer2350/mpconfigboard.h | 18 +++ .../pimoroni_explorer2350/mpconfigboard.mk | 10 ++ .../pico-sdk-configboard.h | 7 + .../boards/pimoroni_explorer2350/pins.c | 124 +++++++++++++++ 5 files changed, 304 insertions(+) create mode 100644 ports/raspberrypi/boards/pimoroni_explorer2350/board.c create mode 100644 ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/pimoroni_explorer2350/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/pimoroni_explorer2350/pins.c diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/board.c b/ports/raspberrypi/boards/pimoroni_explorer2350/board.c new file mode 100644 index 00000000000..d0c6d9a57ce --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/board.c @@ -0,0 +1,145 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/paralleldisplaybus/ParallelBus.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "hardware/gpio.h" + +// Display pins from Pimoroni Explorer parallel bus: {cs=27, dc=28, wr=30, rd=31, d0=32, bl=26} +#define LCD_BACKLIGHT_PIN 26 +#define LCD_CS_PIN 27 +#define LCD_DC_PIN 28 +#define LCD_WR_PIN 30 +#define LCD_RD_PIN 31 +#define LCD_D0_PIN 32 // Data pins are GPIO32-39 (8 consecutive pins) + +#define DELAY 0x80 + +// ST7789V display init sequence for 320x240 parallel bus +// Based on Pimoroni's pimoroni-pico ST7789 driver configuration +uint8_t display_init_sequence[] = { + // Software reset + 0x01, 0 | DELAY, 150, + // Sleep out + 0x11, 0 | DELAY, 255, + // Tearing effect line on (frame sync) + 0x35, 1, 0x00, + // COLMOD: 16-bit color (5-6-5 RGB) + 0x3A, 1, 0x55, + // Porch control (PORCTRL) + 0xB2, 5, 0x0C, 0x0C, 0x00, 0x33, 0x33, + // Gate control (GCTRL) - VGH=13.26V, VGL=-10.43V + 0xB7, 1, 0x35, + // VCOM setting (VCOMS) + 0xBB, 1, 0x1F, + // LCM control (LCMCTRL) + 0xC0, 1, 0x2C, + // VDV and VRH command enable (VDVVRHEN) + 0xC2, 1, 0x01, + // VRH set (VRHS) + 0xC3, 1, 0x12, + // VDV set (VDVS) + 0xC4, 1, 0x20, + // Frame rate control (FRCTRL2) + 0xC6, 1, 0x0F, + // Power control 1 (PWCTRL1) + 0xD0, 2, 0xA4, 0xA1, + // RAM control (RAMCTRL) - for proper endianness + 0xB0, 2, 0x00, 0xC0, + // Positive gamma correction + 0xE0, 14, 0xD0, 0x08, 0x11, 0x08, 0x0C, 0x15, 0x39, 0x33, 0x50, 0x36, 0x13, 0x14, 0x29, 0x2D, + // Negative gamma correction + 0xE1, 14, 0xD0, 0x08, 0x10, 0x08, 0x06, 0x06, 0x39, 0x44, 0x51, 0x0B, 0x16, 0x14, 0x2F, 0x31, + // Inversion on + 0x21, 0, + // Normal display mode on + 0x13, 0 | DELAY, 10, + // MADCTL: MX=0, MY=1, MV=1, ML=1 (COL_ORDER | SWAP_XY | SCAN_ORDER) = 0x70 + // This configures the 320x240 display in landscape orientation + 0x36, 1, 0x70, + // Display on + 0x29, 0 | DELAY, 100, +}; + +static void display_init(void) { + paralleldisplaybus_parallelbus_obj_t *bus = &allocate_display_bus()->parallel_bus; + bus->base.type = ¶lleldisplaybus_parallelbus_type; + + common_hal_paralleldisplaybus_parallelbus_construct(bus, + &pin_GPIO32, // Data0 (D0) - data pins are sequential GPIO32-39 + &pin_GPIO28, // Command/Data (DC) + &pin_GPIO27, // Chip select (CS) + &pin_GPIO30, // Write (WR) + &pin_GPIO31, // Read (RD) + NULL, // Reset (directly connected to board reset) + 15000000); // Frequency - ST7789 min clock cycle ~66ns = ~15MHz + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct(display, + bus, + 320, // Width + 240, // Height + 0, // column start + 0, // row start + 0, // rotation + 16, // Color depth + false, // grayscale + false, // pixels_in_byte_share_row + 1, // bytes per cell + false, // reverse_pixels_in_byte + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set row command + MIPI_COMMAND_WRITE_MEMORY_START, // write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO26, // Backlight pin (BL) + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000 // backlight pwm frequency + ); +} + +void board_init(void) { + // Ensure backlight is on before display init + board_reset_pin_number(LCD_BACKLIGHT_PIN); + display_init(); +} + +// Prevent the backlight pin from being reset, keeping display visible across soft resets +bool board_reset_pin_number(uint8_t pin_number) { + if (pin_number == LCD_BACKLIGHT_PIN) { + // Keep backlight on - set high output without glitching + gpio_put(pin_number, 1); + gpio_set_dir(pin_number, GPIO_OUT); + gpio_set_function(pin_number, GPIO_FUNC_SIO); + return true; + } + return false; +} + +void reset_board(void) { + // Keep backlight on during reset + board_reset_pin_number(LCD_BACKLIGHT_PIN); +} + +void board_deinit(void) { + // Backlight will be handled by board_reset_pin_number +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.h new file mode 100644 index 00000000000..dd269aa6b84 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Pimoroni Explorer" +#define MICROPY_HW_MCU_NAME "rp2350b" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO25) + +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO21, .sda = &pin_GPIO20}} + +#define DEFAULT_UART_BUS_RX (&pin_GPIO1) +#define DEFAULT_UART_BUS_TX (&pin_GPIO0) diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk new file mode 100644 index 00000000000..4e4882910c8 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk @@ -0,0 +1,10 @@ +USB_VID = 0x2E8A +USB_PID = 0x10C0 +USB_PRODUCT = "Explorer" +USB_MANUFACTURER = "Pimoroni" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = B +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/pimoroni_explorer2350/pico-sdk-configboard.h new file mode 100644 index 00000000000..66b57dfd13d --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/pico-sdk-configboard.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/pins.c b/ports/raspberrypi/boards/pimoroni_explorer2350/pins.c new file mode 100644 index 00000000000..8154a43de00 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/pins.c @@ -0,0 +1,124 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // User GPIOs (accent connector) + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + + // Servo pins + { MP_ROM_QSTR(MP_QSTR_SERVO1), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_SERVO2), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_SERVO3), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SERVO4), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + + // Audio + { MP_ROM_QSTR(MP_QSTR_AUDIO), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_AMP_EN), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + + // Buttons + { MP_ROM_QSTR(MP_QSTR_SW_C), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SW_B), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SW_A), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_SW_X), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_SW_Y), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SW_Z), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + + // I2C + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + + // User button + { MP_ROM_QSTR(MP_QSTR_SW_USER), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + + // LED? + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + + // Display parallel bus pins (ST7789V 320x240) + // Pins from Pimoroni: {cs=27, dc=28, wr=30, rd=31, d0=32, bl=26} + { MP_ROM_QSTR(MP_QSTR_LCD_BL), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_LCD_DC), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_LCD_WR), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_GP30), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RD), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_GP31), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D0), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_GP32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D1), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_GP33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D2), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_GP34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D3), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_GP35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D4), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_GP36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D5), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_GP37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D6), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_GP38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D7), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_GP39), MP_ROM_PTR(&pin_GPIO39) }, + + // ADC pins (RP2350B extended GPIOs) + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_ADC0), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_GP40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_ADC1), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_GP41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_ADC2), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_GP42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_ADC3), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_GP43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_ADC4), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_GP44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_ADC5), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_GP45), MP_ROM_PTR(&pin_GPIO45) }, + + // I2C object + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + // Display object + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 23be085b5e79a0904789b41b3aa71f46f214359d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 2 Feb 2026 12:05:42 -0800 Subject: [PATCH 170/876] Build native sim in CI explicitly --- .github/workflows/run-tests.yml | 2 ++ requirements-dev.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index ed0dd65a4f1..4fded6bbbdf 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -88,5 +88,7 @@ jobs: uses: ./.github/actions/deps/ports/zephyr-cp - name: Set up external uses: ./.github/actions/deps/external + - name: Build native sim target + run: make -C ports/zephyr-cp -j2 BOARD=native_native_sim - name: Run Zephyr tests run: make -C ports/zephyr-cp test diff --git a/requirements-dev.txt b/requirements-dev.txt index cdfb62da1fa..566618d2c47 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -42,3 +42,4 @@ setuptools # For zephyr port tomlkit pytest +perfetto From 4d2f974712cb595c9c5c825a8f5cb1c418db79c1 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 2 Feb 2026 12:09:04 -0800 Subject: [PATCH 171/876] Dunder asm for Zephyr toolchain --- shared/runtime/gchelper_generic.c | 98 +++++++++++++++---------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/shared/runtime/gchelper_generic.c b/shared/runtime/gchelper_generic.c index 40c5865ed1c..464aeaa9981 100644 --- a/shared/runtime/gchelper_generic.c +++ b/shared/runtime/gchelper_generic.c @@ -43,12 +43,12 @@ #if defined(__x86_64__) static void gc_helper_get_regs(gc_helper_regs_t arr) { - register long rbx asm ("rbx"); - register long rbp asm ("rbp"); - register long r12 asm ("r12"); - register long r13 asm ("r13"); - register long r14 asm ("r14"); - register long r15 asm ("r15"); + register long rbx __asm__ ("rbx"); + register long rbp __asm__ ("rbp"); + register long r12 __asm__ ("r12"); + register long r13 __asm__ ("r13"); + register long r14 __asm__ ("r14"); + register long r15 __asm__ ("r15"); #ifdef __clang__ // TODO: // This is dirty workaround for Clang. It tries to get around @@ -56,12 +56,12 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { // Application of this patch here is random, and done only to unbreak // MacOS build. Better, cross-arch ways to deal with Clang issues should // be found. - asm ("" : "=r" (rbx)); - asm ("" : "=r" (rbp)); - asm ("" : "=r" (r12)); - asm ("" : "=r" (r13)); - asm ("" : "=r" (r14)); - asm ("" : "=r" (r15)); + __asm__ ("" : "=r" (rbx)); + __asm__ ("" : "=r" (rbp)); + __asm__ ("" : "=r" (r12)); + __asm__ ("" : "=r" (r13)); + __asm__ ("" : "=r" (r14)); + __asm__ ("" : "=r" (r15)); #endif arr[0] = rbx; arr[1] = rbp; @@ -85,10 +85,10 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { // Application of this patch here is random, and done only to unbreak // MacOS build. Better, cross-arch ways to deal with Clang issues should // be found. - asm ("" : "=r" (ebx)); - asm ("" : "=r" (esi)); - asm ("" : "=r" (edi)); - asm ("" : "=r" (ebp)); + __asm__ ("" : "=r" (ebx)); + __asm__ ("" : "=r" (esi)); + __asm__ ("" : "=r" (edi)); + __asm__ ("" : "=r" (ebp)); #endif arr[0] = ebx; arr[1] = esi; @@ -105,16 +105,16 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wuninitialized" #endif - register long r4 asm ("r4"); - register long r5 asm ("r5"); - register long r6 asm ("r6"); - register long r7 asm ("r7"); - register long r8 asm ("r8"); - register long r9 asm ("r9"); - register long r10 asm ("r10"); - register long r11 asm ("r11"); - register long r12 asm ("r12"); - register long r13 asm ("r13"); + register long r4 __asm__ ("r4"); + register long r5 __asm__ ("r5"); + register long r6 __asm__ ("r6"); + register long r7 __asm__ ("r7"); + register long r8 __asm__ ("r8"); + register long r9 __asm__ ("r9"); + register long r10 __asm__ ("r10"); + register long r11 __asm__ ("r11"); + register long r12 __asm__ ("r12"); + register long r13 __asm__ ("r13"); arr[0] = r4; arr[1] = r5; arr[2] = r6; @@ -133,17 +133,17 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { #elif defined(__aarch64__) static void gc_helper_get_regs(gc_helper_regs_t arr) { - const register long x19 asm ("x19"); - const register long x20 asm ("x20"); - const register long x21 asm ("x21"); - const register long x22 asm ("x22"); - const register long x23 asm ("x23"); - const register long x24 asm ("x24"); - const register long x25 asm ("x25"); - const register long x26 asm ("x26"); - const register long x27 asm ("x27"); - const register long x28 asm ("x28"); - const register long x29 asm ("x29"); + const register long x19 __asm__ ("x19"); + const register long x20 __asm__ ("x20"); + const register long x21 __asm__ ("x21"); + const register long x22 __asm__ ("x22"); + const register long x23 __asm__ ("x23"); + const register long x24 __asm__ ("x24"); + const register long x25 __asm__ ("x25"); + const register long x26 __asm__ ("x26"); + const register long x27 __asm__ ("x27"); + const register long x28 __asm__ ("x28"); + const register long x29 __asm__ ("x29"); arr[0] = x19; arr[1] = x20; arr[2] = x21; @@ -163,18 +163,18 @@ static void gc_helper_get_regs(gc_helper_regs_t arr) { // for RV32I targets or gchelper_rv64i.s for RV64I targets. static void gc_helper_get_regs(gc_helper_regs_t arr) { - register uintptr_t s0 asm ("x8"); - register uintptr_t s1 asm ("x9"); - register uintptr_t s2 asm ("x18"); - register uintptr_t s3 asm ("x19"); - register uintptr_t s4 asm ("x20"); - register uintptr_t s5 asm ("x21"); - register uintptr_t s6 asm ("x22"); - register uintptr_t s7 asm ("x23"); - register uintptr_t s8 asm ("x24"); - register uintptr_t s9 asm ("x25"); - register uintptr_t s10 asm ("x26"); - register uintptr_t s11 asm ("x27"); + register uintptr_t s0 __asm__ ("x8"); + register uintptr_t s1 __asm__ ("x9"); + register uintptr_t s2 __asm__ ("x18"); + register uintptr_t s3 __asm__ ("x19"); + register uintptr_t s4 __asm__ ("x20"); + register uintptr_t s5 __asm__ ("x21"); + register uintptr_t s6 __asm__ ("x22"); + register uintptr_t s7 __asm__ ("x23"); + register uintptr_t s8 __asm__ ("x24"); + register uintptr_t s9 __asm__ ("x25"); + register uintptr_t s10 __asm__ ("x26"); + register uintptr_t s11 __asm__ ("x27"); arr[0] = s0; arr[1] = s1; arr[2] = s2; From 03ec5c8f6af546dca7e3bae4c95aab06b56d3658 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 2 Feb 2026 14:41:24 -0800 Subject: [PATCH 172/876] Changes based on Dan's feedback --- ports/analog/common-hal/busio/I2C.c | 6 ++--- ports/atmel-samd/common-hal/busio/I2C.c | 10 +++---- ports/atmel-samd/common-hal/sdioio/SDCard.c | 8 +++--- ports/broadcom/common-hal/busio/I2C.c | 10 +++---- ports/broadcom/common-hal/sdioio/SDCard.c | 8 +++--- ports/cxd56/common-hal/busio/I2C.c | 10 +++---- ports/cxd56/common-hal/sdioio/SDCard.c | 8 +++--- ports/espressif/common-hal/busio/I2C.c | 8 +++--- ports/espressif/common-hal/sdioio/SDCard.c | 8 +++--- ports/mimxrt10xx/common-hal/busio/I2C.c | 10 +++---- ports/nordic/common-hal/busio/I2C.c | 12 ++++----- ports/raspberrypi/common-hal/busio/I2C.c | 10 +++---- ports/renode/common-hal/busio/I2C.c | 6 ++--- ports/silabs/common-hal/busio/I2C.c | 6 ++--- ports/stm/common-hal/busio/I2C.c | 10 +++---- ports/stm/common-hal/sdioio/SDCard.c | 8 +++--- ports/zephyr-cp/common-hal/busio/I2C.c | 6 ++--- py/mperrno.h | 3 ++- py/mpz.c | 12 ++++----- pyproject.toml | 26 ++++++++++++++++++- shared-bindings/busio/I2C.c | 6 ++--- shared-bindings/busio/I2C.h | 6 ++--- shared-bindings/digitalio/DigitalInOut.c | 4 +-- shared-bindings/digitalio/DigitalInOut.h | 4 +-- .../digitalio/DigitalInOutProtocol.c | 4 +-- .../digitalio/DigitalInOutProtocol.h | 8 +++--- shared-bindings/i2cioexpander/IOExpander.c | 4 +-- shared-bindings/i2cioexpander/IOExpander.h | 6 ++--- shared-bindings/i2cioexpander/IOPin.c | 8 +++--- shared-bindings/i2cioexpander/IOPin.h | 6 ++--- shared-bindings/sdcardio/SDCard.h | 6 ++--- shared-bindings/sdioio/SDCard.h | 8 +++--- shared-module/i2cioexpander/IOExpander.c | 12 ++++----- shared-module/i2cioexpander/IOPin.c | 8 +++--- tools/safe_mode_finder.py | 4 +-- 35 files changed, 152 insertions(+), 127 deletions(-) diff --git a/ports/analog/common-hal/busio/I2C.c b/ports/analog/common-hal/busio/I2C.c index b74c921bae3..7ebe721b3f4 100644 --- a/ports/analog/common-hal/busio/I2C.c +++ b/ports/analog/common-hal/busio/I2C.c @@ -187,7 +187,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { int ret; @@ -209,7 +209,7 @@ mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, } // Read into buffer from the device selected by address -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { @@ -233,7 +233,7 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, } // Write the bytes from out_data to the device selected by address -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { diff --git a/ports/atmel-samd/common-hal/busio/I2C.c b/ports/atmel-samd/common-hal/busio/I2C.c index 700c3e4aba2..d9da050dabe 100644 --- a/ports/atmel-samd/common-hal/busio/I2C.c +++ b/ports/atmel-samd/common-hal/busio/I2C.c @@ -176,7 +176,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { uint16_t attempts = ATTEMPTS; @@ -202,12 +202,12 @@ static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t ad return -MP_EIO; } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { uint16_t attempts = ATTEMPTS; @@ -233,9 +233,9 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, return -MP_EIO; } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/atmel-samd/common-hal/sdioio/SDCard.c b/ports/atmel-samd/common-hal/sdioio/SDCard.c index af3610c89e9..e38a664ed48 100644 --- a/ports/atmel-samd/common-hal/sdioio/SDCard.c +++ b/ports/atmel-samd/common-hal/sdioio/SDCard.c @@ -171,7 +171,7 @@ static void debug_print_state(sdioio_sdcard_obj_t *self, const char *what, sd_mm #endif } -mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); @@ -189,7 +189,7 @@ mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { check_for_deinit(self); check_whole_block(bufinfo); @@ -198,7 +198,7 @@ mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint3 start_block, num_blocks); } -mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); @@ -216,7 +216,7 @@ mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { check_for_deinit(self); check_whole_block(bufinfo); diff --git a/ports/broadcom/common-hal/busio/I2C.c b/ports/broadcom/common-hal/busio/I2C.c index cdc986f05ae..7c1eafe281d 100644 --- a/ports/broadcom/common-hal/busio/I2C.c +++ b/ports/broadcom/common-hal/busio/I2C.c @@ -137,7 +137,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { // Discussion of I2C implementation is here: https://github.com/raspberrypi/linux/issues/254 -static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { COMPLETE_MEMORY_READS; self->peripheral->S_b.DONE = true; @@ -192,12 +192,12 @@ static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t ad return 0; } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { COMPLETE_MEMORY_READS; self->peripheral->A_b.ADDR = addr; @@ -242,9 +242,9 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, return 0; } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/broadcom/common-hal/sdioio/SDCard.c b/ports/broadcom/common-hal/sdioio/SDCard.c index 5dc405bdc18..2c9e6a2bb58 100644 --- a/ports/broadcom/common-hal/sdioio/SDCard.c +++ b/ports/broadcom/common-hal/sdioio/SDCard.c @@ -306,7 +306,7 @@ static void check_whole_block(mp_buffer_info_t *bufinfo) { } // Native function for VFS blockdev layer -mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!self->init) { @@ -327,7 +327,7 @@ mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (!self->init) { return -MP_EIO; } @@ -339,7 +339,7 @@ mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint3 } // Native function for VFS blockdev layer -mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!self->init) { @@ -358,7 +358,7 @@ mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (!self->init) { return -MP_EIO; } diff --git a/ports/cxd56/common-hal/busio/I2C.c b/ports/cxd56/common-hal/busio/I2C.c index c8b32b6a023..8e846b2402d 100644 --- a/ports/cxd56/common-hal/busio/I2C.c +++ b/ports/cxd56/common-hal/busio/I2C.c @@ -91,7 +91,7 @@ bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr) { return I2C_TRANSFER(self->i2c_dev, &msg, 1) < 0 ? false : true; } -static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len, bool stop) { +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len, bool stop) { struct i2c_msg_s msg; msg.frequency = self->frequency; @@ -102,12 +102,12 @@ static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t ad return -I2C_TRANSFER(self->i2c_dev, &msg, 1); } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len) { struct i2c_msg_s msg; msg.frequency = self->frequency; @@ -118,9 +118,9 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, ui return -I2C_TRANSFER(self->i2c_dev, &msg, 1); } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/cxd56/common-hal/sdioio/SDCard.c b/ports/cxd56/common-hal/sdioio/SDCard.c index 95dde482dde..227011a8871 100644 --- a/ports/cxd56/common-hal/sdioio/SDCard.c +++ b/ports/cxd56/common-hal/sdioio/SDCard.c @@ -97,7 +97,7 @@ static void check_whole_block(mp_buffer_info_t *bufinfo) { } // Native function for VFS blockdev layer -mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); int result = self->inode->u.i_bops->read(self->inode, buf, start_block, num_blocks); @@ -107,7 +107,7 @@ mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (common_hal_sdioio_sdcard_deinited(self)) { raise_deinited_error(); } @@ -119,7 +119,7 @@ mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32 } // Native function for VFS blockdev layer -mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); int result = self->inode->u.i_bops->write(self->inode, buf, start_block, num_blocks); @@ -129,7 +129,7 @@ mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { if (common_hal_sdioio_sdcard_deinited(self)) { raise_deinited_error(); } diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 723fa7d7400..8ff608717c7 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -169,7 +169,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static mp_errno_t convert_esp_err(esp_err_t result) { +static mp_negative_errno_t convert_esp_err(esp_err_t result) { switch (result) { case ESP_OK: return 0; @@ -189,7 +189,7 @@ static size_t _transaction_duration_ms(size_t frequency, size_t len) { return (len + 1) / bytes_per_ms + 1000; } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = addr, @@ -202,7 +202,7 @@ mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, cons return convert_esp_err(result); } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = addr, @@ -215,7 +215,7 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8 return convert_esp_err(result); } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { i2c_device_config_t dev_config = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, diff --git a/ports/espressif/common-hal/sdioio/SDCard.c b/ports/espressif/common-hal/sdioio/SDCard.c index f7745618162..102f4a4048e 100644 --- a/ports/espressif/common-hal/sdioio/SDCard.c +++ b/ports/espressif/common-hal/sdioio/SDCard.c @@ -169,7 +169,7 @@ static void check_whole_block(mp_buffer_info_t *bufinfo, int sector_size) { } } -mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); ESP_LOGI(TAG, "in sdioio_sdcard_writeblocks"); @@ -181,7 +181,7 @@ mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { common_hal_sdioio_sdcard_check_for_deinit(self); check_whole_block(bufinfo, self->card.csd.sector_size); @@ -190,7 +190,7 @@ mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint3 start_block, num_blocks); } -mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); ESP_LOGI(TAG, "in sdioio_sdcard_readblocks"); @@ -202,7 +202,7 @@ mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { common_hal_sdioio_sdcard_check_for_deinit(self); check_whole_block(bufinfo, self->card.csd.sector_size); diff --git a/ports/mimxrt10xx/common-hal/busio/I2C.c b/ports/mimxrt10xx/common-hal/busio/I2C.c index 38777f2c903..93c0ab30123 100644 --- a/ports/mimxrt10xx/common-hal/busio/I2C.c +++ b/ports/mimxrt10xx/common-hal/busio/I2C.c @@ -201,7 +201,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { lpi2c_master_transfer_t xfer = { 0 }; @@ -218,12 +218,12 @@ static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t ad return -MP_EIO; } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { lpi2c_master_transfer_t xfer = { 0 }; @@ -240,9 +240,9 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, return -MP_EIO; } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/nordic/common-hal/busio/I2C.c b/ports/nordic/common-hal/busio/I2C.c index 904d35cae3d..999737f632b 100644 --- a/ports/nordic/common-hal/busio/I2C.c +++ b/ports/nordic/common-hal/busio/I2C.c @@ -47,7 +47,7 @@ void common_hal_busio_i2c_never_reset(busio_i2c_obj_t *self) { never_reset_pin_number(self->sda_pin_number); } -static mp_errno_t twi_error_to_mp(const nrfx_err_t err) { +static mp_negative_errno_t twi_error_to_mp(const nrfx_err_t err) { switch (err) { case NRFX_ERROR_DRV_TWI_ERR_ANACK: return -MP_ENODEV; @@ -258,7 +258,7 @@ static nrfx_err_t _twim_xfer_with_timeout(busio_i2c_obj_t *self, nrfx_twim_xfer_ } } -static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool stopBit) { +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool stopBit) { if (len == 0) { return common_hal_busio_i2c_probe(self, addr) ? 0 : -MP_ENODEV; } @@ -286,11 +286,11 @@ static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t ad return twi_error_to_mp(err); } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { if (len == 0) { return 0; } @@ -317,9 +317,9 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8 return twi_error_to_mp(err); } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/raspberrypi/common-hal/busio/I2C.c b/ports/raspberrypi/common-hal/busio/I2C.c index 41df0eac724..1441a2a7a06 100644 --- a/ports/raspberrypi/common-hal/busio/I2C.c +++ b/ports/raspberrypi/common-hal/busio/I2C.c @@ -144,7 +144,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { if (len == 0) { // The RP2040 I2C peripheral will not perform 0 byte writes. @@ -182,12 +182,12 @@ static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t ad } } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { size_t result = i2c_read_timeout_us(self->peripheral, addr, data, len, false, BUS_TIMEOUT_US); if (result == len) { @@ -203,9 +203,9 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, } } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/renode/common-hal/busio/I2C.c b/ports/renode/common-hal/busio/I2C.c index 0b01b6e7936..41649f180b3 100644 --- a/ports/renode/common-hal/busio/I2C.c +++ b/ports/renode/common-hal/busio/I2C.c @@ -44,17 +44,17 @@ bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return 0; } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { return -MP_EIO; } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { return -MP_EIO; } diff --git a/ports/silabs/common-hal/busio/I2C.c b/ports/silabs/common-hal/busio/I2C.c index 85f3e63a6db..6c2b04d821d 100644 --- a/ports/silabs/common-hal/busio/I2C.c +++ b/ports/silabs/common-hal/busio/I2C.c @@ -145,7 +145,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { } // Write data to the device selected by address -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { I2C_TransferSeq_TypeDef seq; @@ -165,7 +165,7 @@ mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, } // Read into buffer from the device selected by address -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { @@ -186,7 +186,7 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, } // Write the bytes from out_data to the device selected by address, -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { diff --git a/ports/stm/common-hal/busio/I2C.c b/ports/stm/common-hal/busio/I2C.c index 5277bffe1fc..7f7eb990e4d 100644 --- a/ports/stm/common-hal/busio/I2C.c +++ b/ports/stm/common-hal/busio/I2C.c @@ -212,7 +212,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { self->has_lock = false; } -static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +static mp_negative_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len, bool transmit_stop_bit) { HAL_StatusTypeDef result; if (!transmit_stop_bit) { @@ -237,12 +237,12 @@ static mp_errno_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t ad return result == HAL_OK ? 0 : -MP_EIO; } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { return _common_hal_busio_i2c_write(self, addr, data, len, true); } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { if (!self->frame_in_prog) { return HAL_I2C_Master_Receive(&(self->handle), (uint16_t)(addr << 1), data, (uint16_t)len, 500) @@ -259,9 +259,9 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, } } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { - mp_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); + mp_negative_errno_t result = _common_hal_busio_i2c_write(self, addr, out_data, out_len, false); if (result != 0) { return result; } diff --git a/ports/stm/common-hal/sdioio/SDCard.c b/ports/stm/common-hal/sdioio/SDCard.c index d8cfdb11318..2d24f24d825 100644 --- a/ports/stm/common-hal/sdioio/SDCard.c +++ b/ports/stm/common-hal/sdioio/SDCard.c @@ -242,7 +242,7 @@ static void check_for_deinit(sdioio_sdcard_obj_t *self) { } // Native function for VFS blockdev layer -mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); @@ -262,7 +262,7 @@ mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { check_for_deinit(self); check_whole_block(bufinfo); @@ -272,7 +272,7 @@ mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint3 } // Native function for VFS blockdev layer -mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t num_blocks) { sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); wait_write_complete(self); @@ -291,7 +291,7 @@ mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, return 0; } -mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { check_for_deinit(self); check_whole_block(bufinfo); diff --git a/ports/zephyr-cp/common-hal/busio/I2C.c b/ports/zephyr-cp/common-hal/busio/I2C.c index d26fc2828cd..84e95721b27 100644 --- a/ports/zephyr-cp/common-hal/busio/I2C.c +++ b/ports/zephyr-cp/common-hal/busio/I2C.c @@ -73,7 +73,7 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { k_mutex_unlock(&self->mutex); } -mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, const uint8_t *data, size_t len) { if (common_hal_busio_i2c_deinited(self)) { @@ -96,7 +96,7 @@ mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr, return 0; } -mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *data, size_t len) { if (common_hal_busio_i2c_deinited(self)) { @@ -123,7 +123,7 @@ mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, return 0; } -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len) { if (common_hal_busio_i2c_deinited(self)) { diff --git a/py/mperrno.h b/py/mperrno.h index f1fee77b22e..6c675125f4e 100644 --- a/py/mperrno.h +++ b/py/mperrno.h @@ -143,7 +143,8 @@ #endif -typedef int mp_errno_t; +// Type for return values where 0 indicates success and negative values are negated MP_E* error codes. +typedef int mp_negative_errno_t; #if MICROPY_PY_ERRNO diff --git a/py/mpz.c b/py/mpz.c index 046d4fcdd5a..7d8bc03ca86 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -782,15 +782,15 @@ void mpz_set_from_float(mpz_t *z, mp_float_t src) { // 2 <= value const int dig_cnt = (adj_exp + 1 + (DIG_SIZE - 1)) / DIG_SIZE; const unsigned int rem = adj_exp % DIG_SIZE; - int dig_ind, shift; + int dig_ind, shft; mp_float_uint_t frc = u.p.frc | ((mp_float_uint_t)1 << MP_FLOAT_FRAC_BITS); if (adj_exp < MP_FLOAT_FRAC_BITS) { - shift = 0; + shft = 0; dig_ind = 0; frc >>= MP_FLOAT_FRAC_BITS - adj_exp; } else { - shift = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE; + shft = (rem - MP_FLOAT_FRAC_BITS) % DIG_SIZE; dig_ind = (adj_exp - MP_FLOAT_FRAC_BITS) / DIG_SIZE; } mpz_need_dig(z, dig_cnt); @@ -798,9 +798,9 @@ void mpz_set_from_float(mpz_t *z, mp_float_t src) { if (dig_ind != 0) { memset(z->dig, 0, dig_ind * sizeof(mpz_dig_t)); } - if (shift != 0) { - z->dig[dig_ind++] = (frc << shift) & DIG_MASK; - frc >>= DIG_SIZE - shift; + if (shft != 0) { + z->dig[dig_ind++] = (frc << shft) & DIG_MASK; + frc >>= DIG_SIZE - shft; } #if DIG_SIZE < (MP_FLOAT_FRAC_BITS + 1) while (dig_ind != dig_cnt) { diff --git a/pyproject.toml b/pyproject.toml index 0db7eb70a78..7003a6af9ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ [tool.setuptools_scm] # can be empty if no extra settings are needed, presence enables setuptools-scm -# Ruff settings copied from MicroPython +# Codespell settings copied from MicroPython [tool.ruff] target-version = "py37" @@ -59,3 +59,27 @@ lint.per-file-ignores."ports/**/boards/**/manifest_*.py" = [ "F821" ] # Exclude all tests from linting (does not apply to formatting). lint.per-file-ignores."tests/**/*.py" = [ "ALL" ] lint.mccabe.max-complexity = 40 + +[tool.codespell] +count = "" +ignore-regex = '\b[A-Z]{3}\b' +ignore-words-list = "ans,asend,aranges,deques,dout,emac,extint,hsi,iput,mis,notin,numer,ser,shft,synopsys,technic,ure,curren" +quiet-level = 3 +skip = """ +*/build*,\ +./.git,\ +./drivers/cc3100,\ +./lib,\ +./ports/cc3200/FreeRTOS,\ +./ports/cc3200/bootmgr/sl,\ +./ports/cc3200/hal,\ +./ports/cc3200/simplelink,\ +./ports/cc3200/telnet,\ +./ports/esp32/managed_components,\ +./ports/nrf/drivers/bluetooth/s1*,\ +./ports/stm32/usbhost,\ +./tests,\ +ACKNOWLEDGEMENTS,\ +""" + +# Ruff settings copied from MicroPython diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index 34c02349deb..a2724e60c34 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -228,7 +228,7 @@ static mp_obj_t busio_i2c_readfrom_into(size_t n_args, const mp_obj_t *pos_args, start *= stride_in_bytes; length *= stride_in_bytes; - mp_errno_t status = + mp_negative_errno_t status = common_hal_busio_i2c_read(self, args[ARG_address].u_int, ((uint8_t *)bufinfo.buf) + start, length); if (status != 0) { mp_raise_OSError(-status); @@ -290,7 +290,7 @@ static mp_obj_t busio_i2c_writeto(size_t n_args, const mp_obj_t *pos_args, mp_ma length *= stride_in_bytes; // do the transfer - mp_errno_t status = + mp_negative_errno_t status = common_hal_busio_i2c_write(self, args[ARG_address].u_int, ((uint8_t *)bufinfo.buf) + start, length); if (status != 0) { @@ -377,7 +377,7 @@ static mp_obj_t busio_i2c_writeto_then_readfrom(size_t n_args, const mp_obj_t *p in_start *= in_stride_in_bytes; in_length *= in_stride_in_bytes; - mp_errno_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int, + mp_negative_errno_t status = common_hal_busio_i2c_write_read(self, args[ARG_address].u_int, ((uint8_t *)out_bufinfo.buf) + out_start, out_length, ((uint8_t *)in_bufinfo.buf) + in_start, in_length); if (status != 0) { mp_raise_OSError(-status); diff --git a/shared-bindings/busio/I2C.h b/shared-bindings/busio/I2C.h index e7293ce8617..2978a907544 100644 --- a/shared-bindings/busio/I2C.h +++ b/shared-bindings/busio/I2C.h @@ -37,16 +37,16 @@ extern void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self); extern bool common_hal_busio_i2c_probe(busio_i2c_obj_t *self, uint8_t addr); // Write to the device and return 0 on success or a negative error code from mperrno.h -extern mp_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, +extern mp_negative_errno_t common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t address, const uint8_t *data, size_t len); // Reads memory of the i2c device picking up where it left off and return 0 on // success or a negative error code from mperrno.h -extern mp_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, +extern mp_negative_errno_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *data, size_t len); // Do a write and then a read in the same I2C transaction. -mp_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t address, +mp_negative_errno_t common_hal_busio_i2c_write_read(busio_i2c_obj_t *self, uint16_t address, uint8_t *out_data, size_t out_len, uint8_t *in_data, size_t in_len); // This is used by the supervisor to claim I2C devices indefinitely. diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index 50cbc3bc36d..c868ca7d443 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -368,13 +368,13 @@ digitalio_direction_t digitalinout_get_direction(mp_obj_t self_in) { return common_hal_digitalio_digitalinout_get_direction(self); } -mp_errno_t digitalinout_set_value(mp_obj_t self_in, bool value) { +mp_negative_errno_t digitalinout_set_value(mp_obj_t self_in, bool value) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_digitalio_digitalinout_set_value(self, value); return 0; } -mp_errno_t digitalinout_get_value(mp_obj_t self_in, bool *value) { +mp_negative_errno_t digitalinout_get_value(mp_obj_t self_in, bool *value) { digitalio_digitalinout_obj_t *self = MP_OBJ_TO_PTR(self_in); *value = common_hal_digitalio_digitalinout_get_value(self); return 0; diff --git a/shared-bindings/digitalio/DigitalInOut.h b/shared-bindings/digitalio/DigitalInOut.h index ad38cbec6a4..8d3fe8c00a2 100644 --- a/shared-bindings/digitalio/DigitalInOut.h +++ b/shared-bindings/digitalio/DigitalInOut.h @@ -64,8 +64,8 @@ bool digitalinout_deinited(mp_obj_t self_in); digitalinout_result_t digitalinout_switch_to_input(mp_obj_t self_in, digitalio_pull_t pull); digitalinout_result_t digitalinout_switch_to_output(mp_obj_t self_in, bool value, digitalio_drive_mode_t drive_mode); digitalio_direction_t digitalinout_get_direction(mp_obj_t self_in); -mp_errno_t digitalinout_set_value(mp_obj_t self_in, bool value); -mp_errno_t digitalinout_get_value(mp_obj_t self_in, bool *value); +mp_negative_errno_t digitalinout_set_value(mp_obj_t self_in, bool value); +mp_negative_errno_t digitalinout_get_value(mp_obj_t self_in, bool *value); digitalinout_result_t digitalinout_set_drive_mode(mp_obj_t self_in, digitalio_drive_mode_t drive_mode); digitalio_drive_mode_t digitalinout_get_drive_mode(mp_obj_t self_in); digitalinout_result_t digitalinout_set_pull(mp_obj_t self_in, digitalio_pull_t pull); diff --git a/shared-bindings/digitalio/DigitalInOutProtocol.c b/shared-bindings/digitalio/DigitalInOutProtocol.c index df64fd729c2..48b428ad463 100644 --- a/shared-bindings/digitalio/DigitalInOutProtocol.c +++ b/shared-bindings/digitalio/DigitalInOutProtocol.c @@ -311,7 +311,7 @@ digitalio_direction_t digitalinout_protocol_get_direction(mp_obj_t self) { return DIRECTION_OUTPUT; } -mp_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value) { +mp_negative_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value) { const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->set_value) { return proto->set_value(self, value); @@ -322,7 +322,7 @@ mp_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value) { return 0; } -mp_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value) { +mp_negative_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value) { const digitalinout_p_t *proto = mp_proto_get(MP_QSTR_DigitalInOut, self); if (proto && proto->get_value) { return proto->get_value(self, value); diff --git a/shared-bindings/digitalio/DigitalInOutProtocol.h b/shared-bindings/digitalio/DigitalInOutProtocol.h index 798cb6a9de1..6cb92a3735f 100644 --- a/shared-bindings/digitalio/DigitalInOutProtocol.h +++ b/shared-bindings/digitalio/DigitalInOutProtocol.h @@ -25,8 +25,8 @@ typedef struct _digitalinout_p_t { digitalinout_result_t (*switch_to_input)(mp_obj_t self, digitalio_pull_t pull); digitalinout_result_t (*switch_to_output)(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode); digitalio_direction_t (*get_direction)(mp_obj_t self); - mp_errno_t (*set_value)(mp_obj_t self, bool value); // Return 0 if ok - mp_errno_t (*get_value)(mp_obj_t self, bool *value); // Return 0 if ok + mp_negative_errno_t (*set_value)(mp_obj_t self, bool value); // Return 0 if ok + mp_negative_errno_t (*get_value)(mp_obj_t self, bool *value); // Return 0 if ok digitalinout_result_t (*set_drive_mode)(mp_obj_t self, digitalio_drive_mode_t drive_mode); digitalio_drive_mode_t (*get_drive_mode)(mp_obj_t self); digitalinout_result_t (*set_pull)(mp_obj_t self, digitalio_pull_t pull); @@ -61,8 +61,8 @@ bool digitalinout_protocol_deinited(mp_obj_t self); digitalinout_result_t digitalinout_protocol_switch_to_input(mp_obj_t self, digitalio_pull_t pull); digitalinout_result_t digitalinout_protocol_switch_to_output(mp_obj_t self, bool value, digitalio_drive_mode_t drive_mode); digitalio_direction_t digitalinout_protocol_get_direction(mp_obj_t self); -mp_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value); -mp_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value); +mp_negative_errno_t digitalinout_protocol_set_value(mp_obj_t self, bool value); +mp_negative_errno_t digitalinout_protocol_get_value(mp_obj_t self, bool *value); digitalinout_result_t digitalinout_protocol_set_drive_mode(mp_obj_t self, digitalio_drive_mode_t drive_mode); digitalio_drive_mode_t digitalinout_protocol_get_drive_mode(mp_obj_t self); digitalinout_result_t digitalinout_protocol_set_pull(mp_obj_t self, digitalio_pull_t pull); diff --git a/shared-bindings/i2cioexpander/IOExpander.c b/shared-bindings/i2cioexpander/IOExpander.c index f2257b4b632..c828c6dc5c7 100644 --- a/shared-bindings/i2cioexpander/IOExpander.c +++ b/shared-bindings/i2cioexpander/IOExpander.c @@ -169,7 +169,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_output_value_obj, i2cioex static mp_obj_t i2cioexpander_ioexpander_obj_set_output_value(mp_obj_t self_in, mp_obj_t value) { i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_errno_t result = common_hal_i2cioexpander_ioexpander_set_output_value(self, mp_obj_get_int(value)); + mp_negative_errno_t result = common_hal_i2cioexpander_ioexpander_set_output_value(self, mp_obj_get_int(value)); if (result != 0) { mp_raise_OSError(result); } @@ -198,7 +198,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(i2cioexpander_ioexpander_get_output_mask_obj, i2cioexp static mp_obj_t i2cioexpander_ioexpander_obj_set_output_mask(mp_obj_t self_in, mp_obj_t value) { i2cioexpander_ioexpander_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_errno_t result = common_hal_i2cioexpander_ioexpander_set_output_mask(self, mp_obj_get_int(value)); + mp_negative_errno_t result = common_hal_i2cioexpander_ioexpander_set_output_mask(self, mp_obj_get_int(value)); if (result != 0) { mp_raise_OSError(result); } diff --git a/shared-bindings/i2cioexpander/IOExpander.h b/shared-bindings/i2cioexpander/IOExpander.h index 64e49b60364..5c93c6250cc 100644 --- a/shared-bindings/i2cioexpander/IOExpander.h +++ b/shared-bindings/i2cioexpander/IOExpander.h @@ -23,12 +23,12 @@ void common_hal_i2cioexpander_ioexpander_construct( void common_hal_i2cioexpander_ioexpander_deinit(i2cioexpander_ioexpander_obj_t *self); bool common_hal_i2cioexpander_ioexpander_deinited(i2cioexpander_ioexpander_obj_t *self); -mp_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioexpander_obj_t *self, size_t *value); +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioexpander_obj_t *self, size_t *value); // No error return because this returns a cached value. void common_hal_i2cioexpander_ioexpander_get_output_value(i2cioexpander_ioexpander_obj_t *self, size_t *value); -mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_ioexpander_obj_t *self, size_t value); +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_ioexpander_obj_t *self, size_t value); void common_hal_i2cioexpander_ioexpander_get_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t *mask); -mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t mask); +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t mask); mp_obj_t common_hal_i2cioexpander_ioexpander_get_pins(i2cioexpander_ioexpander_obj_t *self); diff --git a/shared-bindings/i2cioexpander/IOPin.c b/shared-bindings/i2cioexpander/IOPin.c index e2957f9a220..bba229bd31e 100644 --- a/shared-bindings/i2cioexpander/IOPin.c +++ b/shared-bindings/i2cioexpander/IOPin.c @@ -134,7 +134,7 @@ static mp_obj_t i2cioexpander_iopin_obj_get_value(mp_obj_t self_in) { i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); bool value; - mp_errno_t res = common_hal_i2cioexpander_iopin_get_value(self, &value); + mp_negative_errno_t res = common_hal_i2cioexpander_iopin_get_value(self, &value); if (res != 0) { mp_raise_OSError(-res); } @@ -149,7 +149,7 @@ static mp_obj_t i2cioexpander_iopin_obj_set_value(mp_obj_t self_in, mp_obj_t val mp_raise_AttributeError(MP_ERROR_TEXT("Cannot set value when direction is input.")); return mp_const_none; } - mp_errno_t res = common_hal_i2cioexpander_iopin_set_value(self, mp_obj_is_true(value)); + mp_negative_errno_t res = common_hal_i2cioexpander_iopin_set_value(self, mp_obj_is_true(value)); if (res != 0) { mp_raise_OSError(-res); } @@ -259,12 +259,12 @@ static digitalio_direction_t iopin_protocol_get_direction(mp_obj_t self_in) { return common_hal_i2cioexpander_iopin_get_direction(self); } -static mp_errno_t iopin_protocol_get_value(mp_obj_t self_in, bool *value) { +static mp_negative_errno_t iopin_protocol_get_value(mp_obj_t self_in, bool *value) { i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_i2cioexpander_iopin_get_value(self, value); } -static mp_errno_t iopin_protocol_set_value(mp_obj_t self_in, bool value) { +static mp_negative_errno_t iopin_protocol_set_value(mp_obj_t self_in, bool value) { i2cioexpander_iopin_obj_t *self = MP_OBJ_TO_PTR(self_in); return common_hal_i2cioexpander_iopin_set_value(self, value); } diff --git a/shared-bindings/i2cioexpander/IOPin.h b/shared-bindings/i2cioexpander/IOPin.h index 6a7d96130fa..c8155c71aa1 100644 --- a/shared-bindings/i2cioexpander/IOPin.h +++ b/shared-bindings/i2cioexpander/IOPin.h @@ -11,7 +11,7 @@ extern const mp_obj_type_t i2cioexpander_iopin_type; -mp_errno_t i2cioexpander_iopin_construct( +mp_negative_errno_t i2cioexpander_iopin_construct( i2cioexpander_iopin_obj_t *self, i2cioexpander_ioexpander_obj_t *expander, uint8_t pin_number); @@ -30,8 +30,8 @@ digitalinout_result_t common_hal_i2cioexpander_iopin_switch_to_output( digitalio_direction_t common_hal_i2cioexpander_iopin_get_direction(i2cioexpander_iopin_obj_t *self); -mp_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *self, bool value); -mp_errno_t common_hal_i2cioexpander_iopin_get_value(i2cioexpander_iopin_obj_t *self, bool *value); +mp_negative_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *self, bool value); +mp_negative_errno_t common_hal_i2cioexpander_iopin_get_value(i2cioexpander_iopin_obj_t *self, bool *value); digitalinout_result_t common_hal_i2cioexpander_iopin_set_drive_mode( i2cioexpander_iopin_obj_t *self, diff --git a/shared-bindings/sdcardio/SDCard.h b/shared-bindings/sdcardio/SDCard.h index ae364357707..d0cb8206c34 100644 --- a/shared-bindings/sdcardio/SDCard.h +++ b/shared-bindings/sdcardio/SDCard.h @@ -18,9 +18,9 @@ bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_mark_deinit(sdcardio_sdcard_obj_t *self); int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self); -mp_errno_t common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); -mp_errno_t common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self); -mp_errno_t common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); +mp_negative_errno_t common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); +mp_negative_errno_t common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self); +mp_negative_errno_t common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf); // Used by native vfs blockdev. mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); diff --git a/shared-bindings/sdioio/SDCard.h b/shared-bindings/sdioio/SDCard.h index 446ff3dfd76..042521aea50 100644 --- a/shared-bindings/sdioio/SDCard.h +++ b/shared-bindings/sdioio/SDCard.h @@ -37,12 +37,12 @@ uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t *self); uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t *self); // Read or write blocks - returns 0 on success or negative error code from mperrno.h -mp_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); -mp_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo); // Used by native vfs blockdev. -mp_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); -mp_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t buflen); bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, mp_int_t *out_value); // This is used by the supervisor to claim SDIO devices indefinitely. diff --git a/shared-module/i2cioexpander/IOExpander.c b/shared-module/i2cioexpander/IOExpander.c index 5146abc66e6..f4aac5c0532 100644 --- a/shared-module/i2cioexpander/IOExpander.c +++ b/shared-module/i2cioexpander/IOExpander.c @@ -81,7 +81,7 @@ bool common_hal_i2cioexpander_ioexpander_deinited(i2cioexpander_ioexpander_obj_t return self->i2c == NULL; } -mp_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioexpander_obj_t *self, size_t *value) { +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioexpander_obj_t *self, size_t *value) { uint8_t buffer[2]; uint8_t num_bytes = (self->num_pins > 8) ? 2 : 1; @@ -89,7 +89,7 @@ mp_errno_t common_hal_i2cioexpander_ioexpander_get_input_value(i2cioexpander_ioe RUN_BACKGROUND_TASKS; } - mp_errno_t result; + mp_negative_errno_t result; if (self->has_get_value) { // Send register address then read result = common_hal_busio_i2c_write_read( @@ -116,7 +116,7 @@ void common_hal_i2cioexpander_ioexpander_get_output_value(i2cioexpander_ioexpand *value = self->output_value; } -mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_ioexpander_obj_t *self, size_t value) { +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_ioexpander_obj_t *self, size_t value) { uint8_t buffer[5]; uint8_t num_bytes = 0; @@ -147,7 +147,7 @@ mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_value(i2cioexpander_io return -MP_EBUSY; } - mp_errno_t result = common_hal_busio_i2c_write(self->i2c, self->address, buffer, num_bytes); + mp_negative_errno_t result = common_hal_busio_i2c_write(self->i2c, self->address, buffer, num_bytes); common_hal_busio_i2c_unlock(self->i2c); if (result == 0) { self->output_value = value; @@ -159,7 +159,7 @@ void common_hal_i2cioexpander_ioexpander_get_output_mask(i2cioexpander_ioexpande *mask = self->output_mask; } -mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t mask) { +mp_negative_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioexpander_obj_t *self, size_t mask) { self->output_mask = mask; // Only write to device if direction register is provided @@ -186,7 +186,7 @@ mp_errno_t common_hal_i2cioexpander_ioexpander_set_output_mask(i2cioexpander_ioe return -MP_EBUSY; } - mp_errno_t result = common_hal_busio_i2c_write(self->i2c, self->address, buffer, num_bytes); + mp_negative_errno_t result = common_hal_busio_i2c_write(self->i2c, self->address, buffer, num_bytes); common_hal_busio_i2c_unlock(self->i2c); return result; } diff --git a/shared-module/i2cioexpander/IOPin.c b/shared-module/i2cioexpander/IOPin.c index 9502d2814f3..04642623b3d 100644 --- a/shared-module/i2cioexpander/IOPin.c +++ b/shared-module/i2cioexpander/IOPin.c @@ -9,7 +9,7 @@ #include "py/runtime.h" -mp_errno_t i2cioexpander_iopin_construct( +mp_negative_errno_t i2cioexpander_iopin_construct( i2cioexpander_iopin_obj_t *self, i2cioexpander_ioexpander_obj_t *expander, uint8_t pin_number) { @@ -88,7 +88,7 @@ digitalio_direction_t common_hal_i2cioexpander_iopin_get_direction(i2cioexpander return self->direction; } -mp_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *self, bool value) { +mp_negative_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *self, bool value) { size_t current_value; common_hal_i2cioexpander_ioexpander_get_output_value(self->expander, ¤t_value); size_t new_value; @@ -103,9 +103,9 @@ mp_errno_t common_hal_i2cioexpander_iopin_set_value(i2cioexpander_iopin_obj_t *s return 0; } -mp_errno_t common_hal_i2cioexpander_iopin_get_value(i2cioexpander_iopin_obj_t *self, bool *value) { +mp_negative_errno_t common_hal_i2cioexpander_iopin_get_value(i2cioexpander_iopin_obj_t *self, bool *value) { size_t full_value; - mp_errno_t result = common_hal_i2cioexpander_ioexpander_get_input_value(self->expander, &full_value); + mp_negative_errno_t result = common_hal_i2cioexpander_ioexpander_get_input_value(self->expander, &full_value); if (result != 0) { return result; } diff --git a/tools/safe_mode_finder.py b/tools/safe_mode_finder.py index af3ff0d3c6d..fece8531278 100644 --- a/tools/safe_mode_finder.py +++ b/tools/safe_mode_finder.py @@ -86,8 +86,8 @@ print(e.has_dwarf_info()) d = e.get_dwarf_info() # print(dir(d)) - arranges = d.get_aranges() - cu_offset = arranges.cu_offset_at_addr(pc) + aranges = d.get_aranges() + cu_offset = aranges.cu_offset_at_addr(pc) if not cu_offset: cu_offset = 0 main_cu = d.get_CU_at(cu_offset) From 4fdf0d10d83c672b2f493b7ef7c78c408a3fa596 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 2 Feb 2026 16:53:47 -0800 Subject: [PATCH 173/876] Fix digitalio allocation location --- shared-module/bitbangio/I2C.c | 7 +++++-- shared-module/bitbangio/SPI.c | 9 ++++++--- shared-module/fourwire/FourWire.c | 9 ++++++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/shared-module/bitbangio/I2C.c b/shared-module/bitbangio/I2C.c index 8e27298af7c..d88455729e2 100644 --- a/shared-module/bitbangio/I2C.c +++ b/shared-module/bitbangio/I2C.c @@ -167,11 +167,14 @@ void shared_module_bitbangio_i2c_construct(bitbangio_i2c_obj_t *self, self->us_delay = 1; } + // Allocate the pins in the same place as self. + bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); + // Convert scl from Pin to DigitalInOutProtocol - self->scl = digitalinout_protocol_from_pin(scl, MP_QSTR_scl, false, false, &self->own_scl); + self->scl = digitalinout_protocol_from_pin(scl, MP_QSTR_scl, false, use_port_allocation, &self->own_scl); // Convert sda from Pin to DigitalInOutProtocol - self->sda = digitalinout_protocol_from_pin(sda, MP_QSTR_sda, false, false, &self->own_sda); + self->sda = digitalinout_protocol_from_pin(sda, MP_QSTR_sda, false, use_port_allocation, &self->own_sda); digitalinout_protocol_switch_to_output(self->scl, true, DRIVE_MODE_OPEN_DRAIN); digitalinout_protocol_switch_to_output(self->sda, true, DRIVE_MODE_OPEN_DRAIN); diff --git a/shared-module/bitbangio/SPI.c b/shared-module/bitbangio/SPI.c index b891d22c9aa..9b89d1d4a1b 100644 --- a/shared-module/bitbangio/SPI.c +++ b/shared-module/bitbangio/SPI.c @@ -23,19 +23,22 @@ void shared_module_bitbangio_spi_construct(bitbangio_spi_obj_t *self, mp_obj_t clock, mp_obj_t mosi, mp_obj_t miso) { + // Allocate the pins in the same place as self. + bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); + // Convert clock from Pin to DigitalInOutProtocol - self->clock = digitalinout_protocol_from_pin(clock, MP_QSTR_clock, false, false, &self->own_clock); + self->clock = digitalinout_protocol_from_pin(clock, MP_QSTR_clock, false, use_port_allocation, &self->own_clock); digitalinout_protocol_switch_to_output(self->clock, self->polarity == 1, DRIVE_MODE_PUSH_PULL); // Convert mosi from Pin to DigitalInOutProtocol (optional) - self->mosi = digitalinout_protocol_from_pin(mosi, MP_QSTR_mosi, true, false, &self->own_mosi); + self->mosi = digitalinout_protocol_from_pin(mosi, MP_QSTR_mosi, true, use_port_allocation, &self->own_mosi); self->has_mosi = (self->mosi != mp_const_none); if (self->has_mosi) { digitalinout_protocol_switch_to_output(self->mosi, false, DRIVE_MODE_PUSH_PULL); } // Convert miso from Pin to DigitalInOutProtocol (optional) - self->miso = digitalinout_protocol_from_pin(miso, MP_QSTR_miso, true, false, &self->own_miso); + self->miso = digitalinout_protocol_from_pin(miso, MP_QSTR_miso, true, use_port_allocation, &self->own_miso); self->has_miso = (self->miso != mp_const_none); // MISO starts out as input by default, no need to change diff --git a/shared-module/fourwire/FourWire.c b/shared-module/fourwire/FourWire.c index 0266401f9ce..d87cb0cec0f 100644 --- a/shared-module/fourwire/FourWire.c +++ b/shared-module/fourwire/FourWire.c @@ -29,20 +29,23 @@ void common_hal_fourwire_fourwire_construct(fourwire_fourwire_obj_t *self, self->polarity = polarity; self->phase = phase; - self->command = digitalinout_protocol_from_pin(command, MP_QSTR_command, true, false, &self->own_command); + // Allocate the pins in the same place as self. + bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); + + self->command = digitalinout_protocol_from_pin(command, MP_QSTR_command, true, use_port_allocation, &self->own_command); if (self->command != mp_const_none) { digitalinout_protocol_switch_to_output(self->command, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(command); } - self->reset = digitalinout_protocol_from_pin(reset, MP_QSTR_reset, true, false, &self->own_reset); + self->reset = digitalinout_protocol_from_pin(reset, MP_QSTR_reset, true, use_port_allocation, &self->own_reset); if (self->reset != mp_const_none) { digitalinout_protocol_switch_to_output(self->reset, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(reset); common_hal_fourwire_fourwire_reset(self); } - self->chip_select = digitalinout_protocol_from_pin(chip_select, MP_QSTR_chip_select, true, false, &self->own_chip_select); + self->chip_select = digitalinout_protocol_from_pin(chip_select, MP_QSTR_chip_select, true, use_port_allocation, &self->own_chip_select); if (self->chip_select != mp_const_none) { digitalinout_protocol_switch_to_output(self->chip_select, true, DRIVE_MODE_PUSH_PULL); common_hal_never_reset_pin(chip_select); From e95921bc3a5ed3f314dab5bfcbd75108ade26efa Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 2 Feb 2026 17:01:36 -0800 Subject: [PATCH 174/876] Fix samd pin tracking --- ports/atmel-samd/supervisor/port.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 9654a791dbb..31bc5faf827 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -341,6 +341,9 @@ safe_mode_t port_init(void) { // Reset everything into a known state before board_init. reset_port(); + // Reset the pins too. + reset_all_pins(); + #ifdef SAMD21 if (PM->RCAUSE.bit.BOD33 == 1 || PM->RCAUSE.bit.BOD12 == 1) { return SAFE_MODE_BROWNOUT; From b439846408b15f7acdb174015bdff235f581d3dd Mon Sep 17 00:00:00 2001 From: Sean Carolan Date: Tue, 3 Feb 2026 09:53:34 -0500 Subject: [PATCH 175/876] Use assigned Espressif USB PID 0x8348 PID allocated via https://github.com/espressif/usb-pids/pull/292 Co-Authored-By: Claude Opus 4.5 --- ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk index 6b43abb6839..2413c43cebe 100644 --- a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.mk @@ -1,5 +1,5 @@ USB_VID = 0x303A -USB_PID = 0x811B +USB_PID = 0x8348 USB_PRODUCT = "M5Stack CoreS3 SE" USB_MANUFACTURER = "M5Stack" From 74e380bed0b44bb5081500c4ff9e130a313cc251 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 08:54:28 -0800 Subject: [PATCH 176/876] Fix last overflowing board --- ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk b/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk index 0e3b1b90489..fc59a101e45 100644 --- a/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk +++ b/ports/nordic/boards/electronut_labs_blip/mpconfigboard.mk @@ -11,3 +11,4 @@ INTERNAL_FLASH_FILESYSTEM = 1 CIRCUITPY_AUDIOIO = 0 CIRCUITPY_DISPLAYIO = 1 CIRCUITPY_STAGE = 1 +CIRCUITPY_DIGITALINOUT_PROTOCOL = 0 From 1dc9c83b54a5ad61ca7cfaccb49efa9b2d2fd7d6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 09:34:07 -0800 Subject: [PATCH 177/876] Fetch submodules --- .github/workflows/run-tests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 4fded6bbbdf..01172041b62 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -86,6 +86,11 @@ jobs: python-version: 3.13 - name: Set up Zephyr uses: ./.github/actions/deps/ports/zephyr-cp + - name: Set up submodules + id: set-up-submodules + uses: ./.github/actions/deps/submodules + with: + target: zephyr-cp - name: Set up external uses: ./.github/actions/deps/external - name: Build native sim target From df8b3e530197bf3c7857506a04253ecfcd3be3f2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 09:36:24 -0800 Subject: [PATCH 178/876] Guard zephyr include. Add fetch-port-submodules make target --- ports/zephyr-cp/Makefile | 5 ++++- supervisor/shared/safe_mode.c | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index 15ae523fb72..622fe4901a9 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,7 +8,7 @@ BUILD ?= build-$(BOARD) TRANSLATION ?= en_US -.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash debug run clean menuconfig all clean-all test +.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash debug run clean menuconfig all clean-all test fetch-port-submodules $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) @@ -38,6 +38,9 @@ menuconfig: clean: rm -rf $(BUILD) +fetch-port-submodules: + python ../../tools/ci_fetch_deps.py zephyr-cp + # Build all boards. The + prefix allows jobserver file descriptors to be passed through. # This enables parallel builds across all boards when invoked with `make -jN all`. all: diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index a3e4de235c7..36a0e99180b 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -18,7 +18,9 @@ #include "supervisor/shared/translate/translate.h" #include "supervisor/shared/tick.h" +#if __ZEPHYR__ #include +#endif #define SAFE_MODE_DATA_GUARD 0xad0000af #define SAFE_MODE_DATA_GUARD_MASK 0xff0000ff From 1ed4442e0533329f7d45310c7ccec9ba3d57fe28 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 11:00:25 -0800 Subject: [PATCH 179/876] Fix thunk issue --- ports/zephyr-cp/mpconfigport.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/zephyr-cp/mpconfigport.h b/ports/zephyr-cp/mpconfigport.h index 5b5b077a371..491b5293e2e 100644 --- a/ports/zephyr-cp/mpconfigport.h +++ b/ports/zephyr-cp/mpconfigport.h @@ -17,6 +17,9 @@ #define CIRCUITPY_DEBUG_TINYUSB 0 +// Disable native _Float16 handling for host builds. +#define MICROPY_FLOAT_USE_NATIVE_FLT16 (0) + //////////////////////////////////////////////////////////////////////////////////////////////////// // This also includes mpconfigboard.h. From ac063d15fc1ae440fccd5834ec5918122ed2d0c0 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 11:44:48 -0800 Subject: [PATCH 180/876] Zephyr ifdef --- supervisor/shared/safe_mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 36a0e99180b..96505565460 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -18,7 +18,7 @@ #include "supervisor/shared/translate/translate.h" #include "supervisor/shared/tick.h" -#if __ZEPHYR__ +#ifdef __ZEPHYR__ #include #endif @@ -104,7 +104,7 @@ void PLACE_IN_ITCM(safe_mode_on_next_reset)(safe_mode_t reason) { // Don't inline this so it's easy to break on it from GDB. void __attribute__((noinline, )) PLACE_IN_ITCM(reset_into_safe_mode)(safe_mode_t reason) { if (_safe_mode > SAFE_MODE_BROWNOUT && reason > SAFE_MODE_BROWNOUT) { - #if __ZEPHYR__ + #ifdef __ZEPHYR__ printk("Already in safe mode\n"); printk("Reason: %d\n", reason); printk("Current safe mode: %d\n", _safe_mode); From f7c66cc518a61c6bb23dc2c0a1891c3203198aa8 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 11:46:45 -0800 Subject: [PATCH 181/876] install mtools --- .github/actions/deps/ports/zephyr-cp/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/deps/ports/zephyr-cp/action.yml b/.github/actions/deps/ports/zephyr-cp/action.yml index 75ff232562c..5f52cc7f0c2 100644 --- a/.github/actions/deps/ports/zephyr-cp/action.yml +++ b/.github/actions/deps/ports/zephyr-cp/action.yml @@ -3,11 +3,11 @@ name: Fetch Zephyr port deps runs: using: composite steps: - - name: Get libusb + - name: Get libusb and mtools if: runner.os == 'Linux' run: | sudo apt-get update - sudo apt-get install -y libusb-1.0-0-dev libudev-dev + sudo apt-get install -y libusb-1.0-0-dev libudev-dev mtools shell: bash - name: Setup Zephyr project uses: zephyrproject-rtos/action-zephyr-setup@v1 From 6ab3b0be848ef9ebe67a35399d64c7abf57f472c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 14:58:31 -0800 Subject: [PATCH 182/876] Move other ports to gchelper --- ports/analog/Makefile | 3 +++ ports/atmel-samd/Makefile | 8 ++++++++ ports/broadcom/Makefile | 2 ++ ports/cxd56/Makefile | 4 ++++ ports/espressif/Makefile | 7 +++++++ ports/litex/Makefile | 5 +++++ ports/mimxrt10xx/Makefile | 6 +++++- ports/nordic/Makefile | 4 ++++ ports/raspberrypi/Makefile | 5 +++++ ports/renode/Makefile | 3 +++ ports/silabs/Makefile | 4 +++- ports/stm/Makefile | 3 +++ py/circuitpy_mpconfig.h | 4 ++++ 13 files changed, 56 insertions(+), 2 deletions(-) diff --git a/ports/analog/Makefile b/ports/analog/Makefile index 0ae276985f7..4dd174d2f6c 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -156,6 +156,9 @@ endif SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S += $(STARTUPFILE) +SRC_S += shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c # Needed to compile some MAX32 headers CFLAGS += -D$(MCU_VARIANT_UPPER) \ diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index 9582eff212d..ec414f3d633 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -284,6 +284,7 @@ SRC_C += \ lib/tinyusb/src/portable/microchip/samd/dcd_samd.c \ mphalport.c \ reset.c \ + shared/runtime/gchelper_native.c \ timer_handler.c \ $(SRC_PERIPHERALS) \ @@ -308,6 +309,12 @@ ifeq ($(CIRCUITPY_AUDIOBUSIO),1) SRC_C += peripherals/samd/i2s.c peripherals/samd/$(PERIPHERALS_CHIP_FAMILY)/i2s.c endif +ifeq ($(CHIP_FAMILY), samd21) +SRC_S += shared/runtime/gchelper_thumb1.s +else +SRC_S += shared/runtime/gchelper_thumb2.s +endif + SRC_S_UPPER = supervisor/shared/cpu_regs.S OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) @@ -317,6 +324,7 @@ ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/broadcom/Makefile b/ports/broadcom/Makefile index f60ebbf045e..dda93c6fd7c 100644 --- a/ports/broadcom/Makefile +++ b/ports/broadcom/Makefile @@ -59,6 +59,8 @@ SRC_C += bindings/videocore/__init__.c \ SRC_S = peripherals/broadcom/boot$(SUFFIX).s +SRC_C += shared/runtime/gchelper_generic.c + OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) diff --git a/ports/cxd56/Makefile b/ports/cxd56/Makefile index fdf3646c80d..6305a5b1d4b 100644 --- a/ports/cxd56/Makefile +++ b/ports/cxd56/Makefile @@ -111,6 +111,9 @@ LDFLAGS = \ CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_CXD56 -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_MIDI_TX_BUFSIZE=512 -DCFG_TUD_CDC_TX_BUFSIZE=1024 -DCFG_TUD_MSC_BUFSIZE=512 $(CFLAGS_MOD) SRC_S_UPPER = supervisor/shared/cpu_regs.S +SRC_S = shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c SRC_C += \ background.c \ @@ -120,6 +123,7 @@ SRC_C += \ lib/tinyusb/src/portable/sony/cxd56/dcd_cxd56.c \ OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 8302726aad7..f83c2446df1 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -216,9 +216,12 @@ ifeq ($(IDF_TARGET_ARCH),xtensa) # `#include "xtensa/xtensa_api.h"`. CFLAGS += -mlongcalls -isystem esp-idf/components/xtensa/deprecated_include/ -Wno-error=cpp + CFLAGS += -DMICROPY_GCREGS_SETJMP=1 # Wrap longjmp with a patched version that protects register window update with a critical section LDFLAGS += -Wl,--wrap=longjmp + + SRC_C += shared/runtime/gchelper_generic.c else ifeq ($(IDF_TARGET_ARCH),riscv) ifeq ($(IDF_TARGET),esp32p4) @@ -230,6 +233,9 @@ else ifeq ($(IDF_TARGET_ARCH),riscv) LDFLAGS += \ -Lesp-idf/components/riscv/ld \ -Trom.api.ld + + SRC_C += shared/runtime/gchelper_native.c + SRC_S = shared/runtime/gchelper_rv32i.s endif @@ -594,6 +600,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os diff --git a/ports/litex/Makefile b/ports/litex/Makefile index 98abe985699..9ef34cd8ff8 100644 --- a/ports/litex/Makefile +++ b/ports/litex/Makefile @@ -81,6 +81,10 @@ SRC_S_UPPER = \ crt0-vexriscv.S \ supervisor/shared/cpu_regs.S +SRC_S = shared/runtime/gchelper_rv32i.s + +SRC_C += shared/runtime/gchelper_native.c + $(BUILD)/lib/tlsf/tlsf.o: CFLAGS += -Wno-cast-align ifneq ($(FROZEN_MPY_DIR),) @@ -94,6 +98,7 @@ ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile index e6928eead61..9cb1df80145 100644 --- a/ports/mimxrt10xx/Makefile +++ b/ports/mimxrt10xx/Makefile @@ -165,6 +165,10 @@ SRC_S_UPPER = \ sdk/devices/$(CHIP_FAMILY)/gcc/startup_$(CHIP_CORE).S \ supervisor/shared/cpu_regs.S +SRC_S = shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c + OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_SDK:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) @@ -172,7 +176,7 @@ ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S:.S=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index aa614e097ba..cd1360b9fd4 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -147,6 +147,9 @@ $(patsubst %.c,$(BUILD)/%.o,$(SRC_DCD)): CFLAGS += -Wno-missing-prototypes endif # CIRCUITPY_USB_DEVICE SRC_S_UPPER = supervisor/shared/cpu_regs.S +SRC_S = shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o)) @@ -155,6 +158,7 @@ ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) +OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index b75d5423251..097a4e7728f 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -422,6 +422,8 @@ SRC_S_UPPER_CHIP_VARIANT := \ sdk/src/rp2_common/pico_float/float_aeabi_rp2040.S \ sdk/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S \ +SRC_S = shared/runtime/gchelper_thumb1.s + PICO_LDFLAGS += \ $(PICO_WRAP_FLOAT_AEABI_FLAGS) \ $(PICO_WRAP_FLOAT_SCI_FLAGS) \ @@ -461,6 +463,8 @@ SRC_S_UPPER_CHIP_VARIANT := \ sdk/src/rp2_common/pico_float/float_sci_m33_vfp.S \ sdk/src/rp2_common/pico_float/float_common_m33.S \ +SRC_S = shared/runtime/gchelper_thumb2.s + PICO_LDFLAGS += $(PICO_WRAP_FLOAT_SCI_FLAGS) $(PICO_WRAP_DOUBLE_FLAGS) ifeq ($(CHIP_PACKAGE),A) @@ -473,6 +477,7 @@ endif endif +SRC_C += shared/runtime/gchelper_native.c SRC_SDK := \ src/common/hardware_claim/claim.c \ diff --git a/ports/renode/Makefile b/ports/renode/Makefile index 92541c03e77..40013ac4f66 100644 --- a/ports/renode/Makefile +++ b/ports/renode/Makefile @@ -46,6 +46,9 @@ SRC_C += \ mphalport.c \ SRC_S_UPPER = supervisor/shared/cpu_regs.S +SRC_S = shared/runtime/gchelper_thumb1.s + +SRC_C += shared/runtime/gchelper_native.c OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) diff --git a/ports/silabs/Makefile b/ports/silabs/Makefile index 58929dd498f..97b0e4c597f 100644 --- a/ports/silabs/Makefile +++ b/ports/silabs/Makefile @@ -90,7 +90,9 @@ ifneq (,$(wildcard boards/$(BOARD)/sensor.c)) SRC_C += boards/$(BOARD)/sensor.c endif -SRC_S = boards/mp_efr32xg24_gchelper.s +SRC_S = shared/runtime/gchelper_thumb2.s + +SRC_C += shared/runtime/gchelper_native.c OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) diff --git a/ports/stm/Makefile b/ports/stm/Makefile index 9db283767e0..f85991cfedb 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -214,8 +214,11 @@ endif SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S = \ + shared/runtime/gchelper_thumb2.s \ st_driver/cmsis_device_$(MCU_SERIES_LOWER)/Source/Templates/gcc/startup_$(MCU_VARIANT_LOWER).s +SRC_C += shared/runtime/gchelper_native.c + ifneq ($(FROZEN_MPY_DIR),) FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 386d1ee3d1e..7715e77eab5 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -46,6 +46,10 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_VFS_LFS1 (0) #define MICROPY_VFS_LFS2 (0) +#ifndef MICROPY_GCREGS_SETJMP +#define MICROPY_GCREGS_SETJMP (0) +#endif + // Sorted alphabetically for easy finding. // // default is 128; consider raising to reduce fragmentation. From 38c118b071d966069c061201ddde1ed79b84e48d Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 4 Feb 2026 01:08:24 +0100 Subject: [PATCH 183/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 38 +++++++++++++++++++++++++++++++++----- locale/el.po | 38 +++++++++++++++++++++++++++++++++----- locale/hi.po | 38 +++++++++++++++++++++++++++++++++----- locale/ko.po | 38 +++++++++++++++++++++++++++++++++----- locale/ru.po | 38 +++++++++++++++++++++++++++++++++----- locale/tr.po | 38 +++++++++++++++++++++++++++++++++----- 6 files changed, 198 insertions(+), 30 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index b1e50a11e12..b7964d4ff13 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -130,7 +130,8 @@ msgstr "%q v %q musí být typu %q, ne %q" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/usb_host/Port.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q se právě používá" @@ -143,7 +144,7 @@ msgid "%q indices must be integers, not %s" msgstr "Indexy %q musí být celá čísla, nikoli %s" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q init failed" msgstr "Inicializace %q selhala" @@ -246,6 +247,14 @@ msgstr "%q musí být typu %q, ne %q" msgid "%q must be power of 2" msgstr "%q musí být mocnina 2" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "%q je mimo hranice" @@ -315,7 +324,7 @@ msgstr "%s chyba 0x%x" msgid "'%q' argument required" msgstr "Je vyžadován argument '%q'" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "Objekt '%q' nepodporuje '%q'" @@ -782,6 +791,10 @@ msgstr "Nelze změnit USB zařízení" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "Není možné vytvořit nový adaptér; použití _bleio.adapter;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -816,6 +829,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "Nelze nastavit hodnotu, když směr je vstup." @@ -957,6 +971,7 @@ msgid "Done" msgstr "Hotovo" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "" @@ -1297,8 +1312,8 @@ msgstr "" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" @@ -1903,6 +1918,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -2568,6 +2584,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -3843,6 +3863,10 @@ msgstr "není implementováno pro komplexní dtype" msgid "not supported for input types" msgstr "není podporováno pro vstupní typy" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3856,6 +3880,10 @@ msgstr "objekt " msgid "object '%s' isn't a tuple or list" msgstr "objekt '%s' není tuple or nebo list" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" diff --git a/locale/el.po b/locale/el.po index 10d7d4d1f51..b40162b35b7 100644 --- a/locale/el.po +++ b/locale/el.po @@ -134,7 +134,8 @@ msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %q" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/usb_host/Port.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q είναι σε χρήση" @@ -147,7 +148,7 @@ msgid "%q indices must be integers, not %s" msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι %s" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q init failed" msgstr "%q εκκίνηση απέτυχε" @@ -250,6 +251,14 @@ msgstr "%q πρέπει να είναι τύπου %q, όχι %q" msgid "%q must be power of 2" msgstr "%q πρέπει να είναι δύναμη του 2" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "%q εκτός ορίων" @@ -319,7 +328,7 @@ msgstr "%s σφάλμα 0x%x" msgid "'%q' argument required" msgstr "'%q' όρισμα απαιτείται" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "'%q' αντικείμενο δεν υποστηρίζει '%q'" @@ -785,6 +794,10 @@ msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" "Δεν μπορεί να δημιουργηθεί νέο Adapter; χρησιμοποιείστε _bleio.adapter;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -821,6 +834,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "Δεν μπορεί να οριστεί τιμή οταν η κατεύθυνση είναι input." @@ -964,6 +978,7 @@ msgid "Done" msgstr "Ολοκληρώθηκε" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "Ο τρόπος οδήγησης δεν χρησιμοποιείται όταν η κατεύθυνση είναι είσοδος." @@ -1303,8 +1318,8 @@ msgstr "" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" @@ -1908,6 +1923,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -2567,6 +2583,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -3842,6 +3862,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3855,6 +3879,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index ebbedfe7639..08b91c9bad6 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -121,7 +121,8 @@ msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/usb_host/Port.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "" @@ -134,7 +135,7 @@ msgid "%q indices must be integers, not %s" msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q init failed" msgstr "" @@ -237,6 +238,14 @@ msgstr "" msgid "%q must be power of 2" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "" @@ -306,7 +315,7 @@ msgstr "" msgid "'%q' argument required" msgstr "" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "" @@ -768,6 +777,10 @@ msgstr "" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -802,6 +815,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "" @@ -941,6 +955,7 @@ msgid "Done" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "" @@ -1279,8 +1294,8 @@ msgstr "" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" @@ -1882,6 +1897,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -2541,6 +2557,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -3816,6 +3836,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3829,6 +3853,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 182f4d08d6b..7963a7a9822 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -132,7 +132,8 @@ msgstr "%q의 %q는 %q가 아니라 %q 유형이어야 합니다" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/usb_host/Port.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q 사용 중입니다" @@ -145,7 +146,7 @@ msgid "%q indices must be integers, not %s" msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q init failed" msgstr "%q 초기화 실패" @@ -253,6 +254,14 @@ msgstr "%q는 %q가 아니라 %q 유형이어야 합니다" msgid "%q must be power of 2" msgstr "%q는 2의 거듭제곱이어야 합니다" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c #, fuzzy msgid "%q out of bounds" @@ -328,7 +337,7 @@ msgstr "%s 오류 0x%x" msgid "'%q' argument required" msgstr "'%q' 인수가 필요합니다" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "'%q' 개체가 '%q'를 지원하지 않습니다" @@ -810,6 +819,10 @@ msgstr "현재 USB 디바이스를 변경할 수 없습니다" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "_bleio.adapter를 사용해서; 새로운 Adapter를 만들 수 없습니다;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -844,6 +857,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "방향이 입력되면 값을 설정할 수 없습니다." @@ -986,6 +1000,7 @@ msgid "Done" msgstr "완료" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "방향을 입력할 때 드라이브 모드는 사용되지 않습니다." @@ -1330,8 +1345,8 @@ msgstr "출력 함수로 인해 종료되었다" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" @@ -1955,6 +1970,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c #, fuzzy msgid "Pull not used when direction is output." msgstr "방향이 출력 될 때 풀은 사용되지 않습니다" @@ -2616,6 +2632,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -3891,6 +3911,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3904,6 +3928,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 653eed6c0bf..45ecfb19f0f 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -134,7 +134,8 @@ msgstr "%q в %q должно быть типа %q, а не %q" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/usb_host/Port.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q используется" @@ -147,7 +148,7 @@ msgid "%q indices must be integers, not %s" msgstr "Индексы %q должны быть целыми числами, а не %s" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q init failed" msgstr "Инициализация %q не удалась" @@ -250,6 +251,14 @@ msgstr "%q должно быть типа %q, а не %q" msgid "%q must be power of 2" msgstr "%q должен быть во 2-й степени" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "%q за пределом" @@ -319,7 +328,7 @@ msgstr "%s ошибка 0x%x" msgid "'%q' argument required" msgstr "Требуется аргумент '%q'" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "Объект '%q' не поддерживает '%q'" @@ -787,6 +796,10 @@ msgstr "Невозможно изменить USB устройство сейч msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "Невозможно создать новый Adapter; используйте _bleio.adapter;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -823,6 +836,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "Невозможно установить значение при вводе направления." @@ -967,6 +981,7 @@ msgid "Done" msgstr "Выполнено" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "Режим движения не используется при вводе направления." @@ -1318,8 +1333,8 @@ msgstr "Прерывается функцией выхода" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" @@ -1933,6 +1948,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "Тяга не используется, когда выводится направление." @@ -2607,6 +2623,10 @@ msgstr "__new__ arg должен быть пользовательского т msgid "a bytes-like object is required" msgstr "Требуется байтоподобный объект" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "адреса пусты" @@ -3905,6 +3925,10 @@ msgstr "не реализовано для сложного типа d" msgid "not supported for input types" msgstr "Не поддерживается для типов ввода" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "Количество баллов должно быть не менее 2" @@ -3918,6 +3942,10 @@ msgstr "объект " msgid "object '%s' isn't a tuple or list" msgstr "Объект \"%s\" не является кортежом или списком" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "Объект не поддерживает назначение элементов" diff --git a/locale/tr.po b/locale/tr.po index 511e9cb7f46..7951c91c4bf 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -132,7 +132,8 @@ msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/usb_host/Port.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/microcontroller/Pin.c shared-module/max3421e/Max3421E.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c msgid "%q in use" msgstr "%q kullanımda" @@ -145,7 +146,7 @@ msgid "%q indices must be integers, not %s" msgstr "%q indeksleri integer olmalı, %s değil" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q init failed" msgstr "%q init başarısız oldu" @@ -248,6 +249,14 @@ msgstr "" msgid "%q must be power of 2" msgstr "%q, 2'nin kuvveti olmalıdır" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" msgstr "%q sınırların dışında" @@ -317,7 +326,7 @@ msgstr "%s hatası 0x%x" msgid "'%q' argument required" msgstr "'%q' argümanı gerekli" -#: py/proto.c +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c msgid "'%q' object does not support '%q'" msgstr "'%q' nesnesi '%q' öğesini desteklemiyor" @@ -781,6 +790,10 @@ msgstr "USB aygıtları şu an değiştirilemez" msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "yeni Adaptör oluşturulamadı; _bleio.adapter kullanın;" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c #: shared-bindings/pulseio/PulseIn.c @@ -816,6 +829,7 @@ msgid "Cannot remount path when visible via USB." msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Cannot set value when direction is input." msgstr "Yön, giriş olduğunda değer ayarlanamıyor." @@ -955,6 +969,7 @@ msgid "Done" msgstr "Tamamlandı" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Drive mode not used when direction is input." msgstr "Yön, giriş olduğunda sürüş modu kullanılmaz." @@ -1297,8 +1312,8 @@ msgstr "" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c #: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/mipidsi/Display.c shared-bindings/pwmio/PWMOut.c -#: shared-bindings/supervisor/__init__.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" @@ -1904,6 +1919,7 @@ msgid "Publishers can only be created from a parent node" msgstr "" #: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c msgid "Pull not used when direction is output." msgstr "" @@ -2563,6 +2579,10 @@ msgstr "" msgid "a bytes-like object is required" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + #: shared-bindings/i2ctarget/I2CTarget.c msgid "addresses is empty" msgstr "" @@ -3838,6 +3858,10 @@ msgstr "" msgid "not supported for input types" msgstr "" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" msgstr "" @@ -3851,6 +3875,10 @@ msgstr "" msgid "object '%s' isn't a tuple or list" msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + #: py/obj.c msgid "object doesn't support item assignment" msgstr "" From 57ce5dac643181e638f016c54d2238bc37b80b25 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 16:17:55 -0800 Subject: [PATCH 184/876] Fix AFLAGS issues --- ports/raspberrypi/Makefile | 12 +++++------- ports/silabs/Makefile | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 097a4e7728f..1784d325d89 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -396,6 +396,8 @@ OTHER_PICO_FLAGS := \ -Wl,--wrap=__aeabi_uidivmod \ -Wl,--wrap=__aeabi_uldivmod +SRC_S = shared/runtime/gchelper_thumb1.s + ifeq ($(CHIP_VARIANT),RP2040) CFLAGS += \ -march=armv6-m \ @@ -422,8 +424,6 @@ SRC_S_UPPER_CHIP_VARIANT := \ sdk/src/rp2_common/pico_float/float_aeabi_rp2040.S \ sdk/src/rp2_common/pico_mem_ops/mem_ops_aeabi.S \ -SRC_S = shared/runtime/gchelper_thumb1.s - PICO_LDFLAGS += \ $(PICO_WRAP_FLOAT_AEABI_FLAGS) \ $(PICO_WRAP_FLOAT_SCI_FLAGS) \ @@ -436,12 +436,12 @@ UF2_ID = 0xE48BFF56 DOUBLE_EABI = rp2040 endif ifeq ($(CHIP_VARIANT),RP2350) -CFLAGS += \ - -march=armv8-m.main+fp+dsp \ +AFLAGS = -march=armv8-m.main+fp+dsp \ -mthumb \ - -mabi=aapcs-linux \ -mcpu=cortex-m33 \ -mfloat-abi=softfp +CFLAGS += $(AFLAGS) \ + -mabi=aapcs-linux # ARM Secure family id UF2_ID = 0xe48bff59 @@ -463,8 +463,6 @@ SRC_S_UPPER_CHIP_VARIANT := \ sdk/src/rp2_common/pico_float/float_sci_m33_vfp.S \ sdk/src/rp2_common/pico_float/float_common_m33.S \ -SRC_S = shared/runtime/gchelper_thumb2.s - PICO_LDFLAGS += $(PICO_WRAP_FLOAT_SCI_FLAGS) $(PICO_WRAP_DOUBLE_FLAGS) ifeq ($(CHIP_PACKAGE),A) diff --git a/ports/silabs/Makefile b/ports/silabs/Makefile index 97b0e4c597f..34b6346d0d4 100644 --- a/ports/silabs/Makefile +++ b/ports/silabs/Makefile @@ -90,7 +90,8 @@ ifneq (,$(wildcard boards/$(BOARD)/sensor.c)) SRC_C += boards/$(BOARD)/sensor.c endif -SRC_S = shared/runtime/gchelper_thumb2.s +AFLAGS = -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard +SRC_S = shared/runtime/gchelper_thumb1.s SRC_C += shared/runtime/gchelper_native.c From 86bb6dbd101267dadcd10c92f0387046bc6d74b6 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 4 Feb 2026 09:38:11 -0600 Subject: [PATCH 185/876] raspberrypi: PDMIn: Fix sample rate calculation. The sample rate needs to be mutiplied by oversampling, not by 32. --- ports/raspberrypi/common-hal/audiobusio/PDMIn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c index 327bec8de72..afe35cc1901 100644 --- a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c +++ b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -43,7 +43,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, // Use the state machine to manage pins. common_hal_rp2pio_statemachine_construct(&self->state_machine, pdmin, MP_ARRAY_SIZE(pdmin), - sample_rate * 32 * 2, // Frequency based on sample rate + sample_rate * OVERSAMPLING * 2, // Frequency based on sample rate NULL, 0, NULL, 0, // may_exec NULL, 1, PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // out pin From c95cbea009cd8a53e66e01a748297c196637bf13 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 4 Feb 2026 09:38:53 -0600 Subject: [PATCH 186/876] raspberrypi: PDMIn: Fix sample rate check. The "actual frequency" is the PIO frequency, which is twice the audio clock. --- ports/raspberrypi/common-hal/audiobusio/PDMIn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c index afe35cc1901..52fe03b7002 100644 --- a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c +++ b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -64,7 +64,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, PIO_FIFO_TYPE_DEFAULT, PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); - if (actual_frequency < MIN_MIC_CLOCK) { + if (actual_frequency < 2 * MIN_MIC_CLOCK) { // 2 PIO samples per audio clock mp_raise_ValueError(MP_ERROR_TEXT("sampling rate out of range")); } From 5cda32b6dc7938a1322d907c69db191fc6bfb265 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 4 Feb 2026 09:39:27 -0600 Subject: [PATCH 187/876] raspberrypi: PDMIn: Free resources when failing to construct. This ensures that after using an invalid sample rate, the pin objects and pio object are deinitialized. --- ports/raspberrypi/common-hal/audiobusio/PDMIn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c index 52fe03b7002..b436469d090 100644 --- a/ports/raspberrypi/common-hal/audiobusio/PDMIn.c +++ b/ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -65,6 +65,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); if (actual_frequency < 2 * MIN_MIC_CLOCK) { // 2 PIO samples per audio clock + common_hal_audiobusio_pdmin_deinit(self); mp_raise_ValueError(MP_ERROR_TEXT("sampling rate out of range")); } From 5c70dc03879db8d54fafde168eac3af0f7ec7a3f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 4 Feb 2026 10:30:28 -0600 Subject: [PATCH 188/876] audio: Remove unused function prototypes. --- shared-bindings/audiodelays/Chorus.h | 4 ---- shared-bindings/audiofreeverb/Freeverb.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/shared-bindings/audiodelays/Chorus.h b/shared-bindings/audiodelays/Chorus.h index 10c6448df89..63e9ba9c28d 100644 --- a/shared-bindings/audiodelays/Chorus.h +++ b/shared-bindings/audiodelays/Chorus.h @@ -18,10 +18,6 @@ void common_hal_audiodelays_chorus_construct(audiodelays_chorus_obj_t *self, uin void common_hal_audiodelays_chorus_deinit(audiodelays_chorus_obj_t *self); bool common_hal_audiodelays_chorus_deinited(audiodelays_chorus_obj_t *self); -uint32_t common_hal_audiodelays_chorus_get_sample_rate(audiodelays_chorus_obj_t *self); -uint8_t common_hal_audiodelays_chorus_get_channel_count(audiodelays_chorus_obj_t *self); -uint8_t common_hal_audiodelays_chorus_get_bits_per_sample(audiodelays_chorus_obj_t *self); - mp_obj_t common_hal_audiodelays_chorus_get_delay_ms(audiodelays_chorus_obj_t *self); void common_hal_audiodelays_chorus_set_delay_ms(audiodelays_chorus_obj_t *self, mp_obj_t delay_ms); diff --git a/shared-bindings/audiofreeverb/Freeverb.h b/shared-bindings/audiofreeverb/Freeverb.h index 913953ebecf..bde6cfffda7 100644 --- a/shared-bindings/audiofreeverb/Freeverb.h +++ b/shared-bindings/audiofreeverb/Freeverb.h @@ -18,10 +18,6 @@ void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *s void common_hal_audiofreeverb_freeverb_deinit(audiofreeverb_freeverb_obj_t *self); bool common_hal_audiofreeverb_freeverb_deinited(audiofreeverb_freeverb_obj_t *self); -uint32_t common_hal_audiofreeverb_freeverb_get_sample_rate(audiofreeverb_freeverb_obj_t *self); -uint8_t common_hal_audiofreeverb_freeverb_get_channel_count(audiofreeverb_freeverb_obj_t *self); -uint8_t common_hal_audiofreeverb_freeverb_get_bits_per_sample(audiofreeverb_freeverb_obj_t *self); - mp_obj_t common_hal_audiofreeverb_freeverb_get_roomsize(audiofreeverb_freeverb_obj_t *self); void common_hal_audiofreeverb_freeverb_set_roomsize(audiofreeverb_freeverb_obj_t *self, mp_obj_t feedback); From ed54e9d1a08bec463e487e2471eb2a258a0b5f64 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Wed, 4 Feb 2026 10:30:54 -0600 Subject: [PATCH 189/876] audio: Call audiosample_mark_deinit. Also remove the deinited check when it's safe to do all deinit actions again. --- shared-module/audiodelays/Chorus.c | 5 ++--- shared-module/audiofreeverb/Freeverb.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/shared-module/audiodelays/Chorus.c b/shared-module/audiodelays/Chorus.c index 9262c6b4de1..3c35b902189 100644 --- a/shared-module/audiodelays/Chorus.c +++ b/shared-module/audiodelays/Chorus.c @@ -4,6 +4,7 @@ // // SPDX-License-Identifier: MIT #include "shared-bindings/audiodelays/Chorus.h" +#include "shared-bindings/audiocore/__init__.h" #include #include @@ -104,9 +105,7 @@ bool common_hal_audiodelays_chorus_deinited(audiodelays_chorus_obj_t *self) { } void common_hal_audiodelays_chorus_deinit(audiodelays_chorus_obj_t *self) { - if (common_hal_audiodelays_chorus_deinited(self)) { - return; - } + audiosample_mark_deinit(&self->base); self->chorus_buffer = NULL; self->buffer[0] = NULL; self->buffer[1] = NULL; diff --git a/shared-module/audiofreeverb/Freeverb.c b/shared-module/audiofreeverb/Freeverb.c index 28779bdcc84..b57e82cdca2 100644 --- a/shared-module/audiofreeverb/Freeverb.c +++ b/shared-module/audiofreeverb/Freeverb.c @@ -8,6 +8,7 @@ // Fixed point ideas from - Paul Stoffregen in the Teensy audio library https://github.com/PaulStoffregen/Audio/blob/master/effect_freeverb.cpp // #include "shared-bindings/audiofreeverb/Freeverb.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-module/synthio/__init__.h" #include @@ -124,9 +125,7 @@ bool common_hal_audiofreeverb_freeverb_deinited(audiofreeverb_freeverb_obj_t *se } void common_hal_audiofreeverb_freeverb_deinit(audiofreeverb_freeverb_obj_t *self) { - if (common_hal_audiofreeverb_freeverb_deinited(self)) { - return; - } + audiosample_mark_deinit(&self->base); self->buffer[0] = NULL; self->buffer[1] = NULL; } From c5066abd787d7b4ad971f105fb16d6eca601181e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 4 Feb 2026 09:21:37 -0800 Subject: [PATCH 190/876] Update autogen file after merge --- ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 8a4eb3e6fb5..2cf9d7127d5 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false From f545763d79cb37950a0e39fb3b6f35fc9eae5818 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 4 Feb 2026 10:58:38 -0800 Subject: [PATCH 191/876] Remove cpu_regs. We're using the MP stuff now --- main.c | 1 - ports/analog/Makefile | 2 - ports/atmel-samd/Makefile | 3 - ports/cxd56/Makefile | 2 - ports/espressif/Makefile | 3 - ports/litex/Makefile | 3 +- ports/mimxrt10xx/Makefile | 3 +- ports/nordic/Makefile | 2 - ports/raspberrypi/Makefile | 1 - ports/renode/Makefile | 2 - ports/stm/Makefile | 4 +- .../zephyr-cp/cptools/build_circuitpython.py | 2 - supervisor/shared/cpu_regs.S | 102 ------------------ supervisor/shared/cpu_regs.h | 38 ------- 14 files changed, 3 insertions(+), 165 deletions(-) delete mode 100644 supervisor/shared/cpu_regs.S delete mode 100644 supervisor/shared/cpu_regs.h diff --git a/main.c b/main.c index d187c56cee4..7b936488fb7 100644 --- a/main.c +++ b/main.c @@ -31,7 +31,6 @@ #include "supervisor/cpu.h" #include "supervisor/filesystem.h" #include "supervisor/port.h" -#include "supervisor/shared/cpu_regs.h" #include "supervisor/shared/reload.h" #include "supervisor/shared/safe_mode.h" #include "supervisor/shared/serial.h" diff --git a/ports/analog/Makefile b/ports/analog/Makefile index 4dd174d2f6c..6b86bd70396 100644 --- a/ports/analog/Makefile +++ b/ports/analog/Makefile @@ -154,7 +154,6 @@ LINKERFILE = linking/$(MCU_VARIANT_LOWER)_cktpy.ld LDFLAGS += -nostartfiles -specs=nano.specs endif -SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S += $(STARTUPFILE) SRC_S += shared/runtime/gchelper_thumb2.s @@ -255,7 +254,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) # List of sources for qstr extraction diff --git a/ports/atmel-samd/Makefile b/ports/atmel-samd/Makefile index ac1d50123b9..0aaf6e3d849 100644 --- a/ports/atmel-samd/Makefile +++ b/ports/atmel-samd/Makefile @@ -315,8 +315,6 @@ else SRC_S += shared/runtime/gchelper_thumb2.s endif -SRC_S_UPPER = supervisor/shared/cpu_regs.S - OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_ASF:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) @@ -325,7 +323,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) QSTR_GLOBAL_REQUIREMENTS += $(HEADER_BUILD)/sdiodata.h diff --git a/ports/cxd56/Makefile b/ports/cxd56/Makefile index 6305a5b1d4b..c4526f31252 100644 --- a/ports/cxd56/Makefile +++ b/ports/cxd56/Makefile @@ -110,7 +110,6 @@ LDFLAGS = \ CFLAGS += -DCFG_TUSB_MCU=OPT_MCU_CXD56 -DCFG_TUD_MIDI_RX_BUFSIZE=512 -DCFG_TUD_CDC_RX_BUFSIZE=1024 -DCFG_TUD_MIDI_TX_BUFSIZE=512 -DCFG_TUD_CDC_TX_BUFSIZE=1024 -DCFG_TUD_MSC_BUFSIZE=512 $(CFLAGS_MOD) -SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S = shared/runtime/gchelper_thumb2.s SRC_C += shared/runtime/gchelper_native.c @@ -124,7 +123,6 @@ SRC_C += \ OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index f83c2446df1..ebc4fa3a4e1 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -591,8 +591,6 @@ FROZEN_MPY_PY_FILES := $(shell find -L $(FROZEN_MPY_DIR) -type f -name '*.py') FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy)) endif -SRC_S_UPPER = supervisor/shared/cpu_regs.S - OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) ifeq ($(INTERNAL_LIBM),1) @@ -601,7 +599,6 @@ endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os $(filter $(PY_BUILD)/../extmod/vfs_fat_%.o, $(PY_O)): COPT += -Os diff --git a/ports/litex/Makefile b/ports/litex/Makefile index 9ef34cd8ff8..940d751e3d9 100644 --- a/ports/litex/Makefile +++ b/ports/litex/Makefile @@ -78,8 +78,7 @@ SRC_C += lib/tinyusb/src/portable/valentyusb/eptri/dcd_eptri.c endif SRC_S_UPPER = \ - crt0-vexriscv.S \ - supervisor/shared/cpu_regs.S + crt0-vexriscv.S SRC_S = shared/runtime/gchelper_rv32i.s diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile index 9cb1df80145..74667fd3d64 100644 --- a/ports/mimxrt10xx/Makefile +++ b/ports/mimxrt10xx/Makefile @@ -162,8 +162,7 @@ SRC_C += \ endif SRC_S_UPPER = \ - sdk/devices/$(CHIP_FAMILY)/gcc/startup_$(CHIP_CORE).S \ - supervisor/shared/cpu_regs.S + sdk/devices/$(CHIP_FAMILY)/gcc/startup_$(CHIP_CORE).S SRC_S = shared/runtime/gchelper_thumb2.s diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index cd1360b9fd4..0d8d8878f4c 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -146,7 +146,6 @@ SRC_C += $(SRC_DCD) $(patsubst %.c,$(BUILD)/%.o,$(SRC_DCD)): CFLAGS += -Wno-missing-prototypes endif # CIRCUITPY_USB_DEVICE -SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S = shared/runtime/gchelper_thumb2.s SRC_C += shared/runtime/gchelper_native.c @@ -159,7 +158,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) # nrfx uses undefined preprocessor variables quite casually, so we can't do diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 1784d325d89..cef2806c874 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -675,7 +675,6 @@ SRC_S_UPPER = sdk/src/rp2_common/hardware_irq/irq_handler_chain.S \ sdk/src/rp2_common/pico_double/double_aeabi_$(DOUBLE_EABI).S \ sdk/src/rp2_common/pico_int64_ops/pico_int64_ops_aeabi.S \ sdk/src/rp2_common/pico_crt0/crt0.S \ - supervisor/shared/cpu_regs.S \ $(SRC_S_UPPER_CHIP_VARIANT) ifeq ($(CIRCUITPY_PICODVI),1) diff --git a/ports/renode/Makefile b/ports/renode/Makefile index 40013ac4f66..c4ce66194e9 100644 --- a/ports/renode/Makefile +++ b/ports/renode/Makefile @@ -45,7 +45,6 @@ SRC_C += \ background.c \ mphalport.c \ -SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S = shared/runtime/gchelper_thumb1.s SRC_C += shared/runtime/gchelper_native.c @@ -57,7 +56,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) $(BUILD)/%.o: $(BUILD)/%.S diff --git a/ports/stm/Makefile b/ports/stm/Makefile index f85991cfedb..c0e64e2339d 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -212,9 +212,8 @@ ifneq ($(CIRCUITPY_USB),0) endif endif -SRC_S_UPPER = supervisor/shared/cpu_regs.S SRC_S = \ - shared/runtime/gchelper_thumb2.s \ + shared/runtime/gchelper_thumb1.s \ st_driver/cmsis_device_$(MCU_SERIES_LOWER)/Source/Templates/gcc/startup_$(MCU_VARIANT_LOWER).s SRC_C += shared/runtime/gchelper_native.c @@ -232,7 +231,6 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_LIBM:.c=.o)) endif OBJ += $(addprefix $(BUILD)/, $(SRC_CIRCUITPY_COMMON:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o)) -OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) $(BUILD)/$(FATFS_DIR)/ff.o: COPT += -Os diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 83f80945f3e..5d3c7d7515d 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -552,8 +552,6 @@ async def build_circuitpython(): source_files.append(portdir / "common-hal/zephyr_kernel/__init__.c") # source_files.append(srcdir / "ports" / port / "peripherals" / "nrf" / "nrf52840" / "pins.c") - assembly_files.append(srcdir / "supervisor/shared/cpu_regs.S") - source_files.extend(assembly_files) objects = [] diff --git a/supervisor/shared/cpu_regs.S b/supervisor/shared/cpu_regs.S deleted file mode 100644 index 90e5367ed58..00000000000 --- a/supervisor/shared/cpu_regs.S +++ /dev/null @@ -1,102 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include "supervisor/shared/cpu_regs.h" - -#ifdef __arm__ -.syntax unified -.thumb -.text -.align 2 - -@ uint cpu_get_regs_and_sp(r0=uint regs[SAVED_REGISTER_COUNT]) -.global cpu_get_regs_and_sp -.thumb -.thumb_func -.type cpu_get_regs_and_sp, %function -cpu_get_regs_and_sp: -#if __ARM_ARCH_ISA_THUMB == 2 -@ store registers into given array -#ifdef __arm__ -stmia r0!, {r4-r11} -#endif -#if defined(__aarch64__) && __aarch64__ == 1 -#error "aarch64 not supported" -stmia r0!, {x19-x28} -#endif -#ifdef __ARM_FP -#ifdef __arm__ -vstmia r0!, {s16-s31} -#endif -#if defined(__aarch64__) && __aarch64__ == 1 -vst1.64 {d8-d15}, [r0], #16 -#endif -#endif -#endif -// Thumb 1 can only store directly from R0-R7. This is M0 and M23 mostly. -#if __ARM_ARCH_ISA_THUMB == 1 -str r4, [r0, #0] -str r5, [r0, #4] -str r6, [r0, #8] -str r7, [r0, #12] -push {r1} -mov r1, r8 -str r1, [r0, #16] -mov r1, r9 -str r1, [r0, #20] -mov r1, r10 -str r1, [r0, #24] -mov r1, r11 -str r1, [r0, #28] -mov r1, r12 -str r1, [r0, #32] -mov r1, r13 -str r1, [r0, #36] -pop {r1} -#endif - -@ return the sp -mov r0, sp -bx lr -#endif - -#ifdef __riscv -#if __riscv_xlen == 32 -.global cpu_get_regs_and_sp -.type cpu_get_regs_and_sp, %function -cpu_get_regs_and_sp: -sw s0, 0(a0) -sw s1, 4(a0) -sw s2, 8(a0) -sw s3, 12(a0) -sw s4, 16(a0) -sw s5, 20(a0) -sw s6, 24(a0) -sw s7, 28(a0) -sw s8, 32(a0) -sw s9, 36(a0) -sw s10, 40(a0) -sw s11, 44(a0) -#ifdef __riscv_vector -sw fs0, 48(a0) -sw fs1, 52(a0) -sw fs2, 56(a0) -sw fs3, 60(a0) -sw fs4, 64(a0) -sw fs5, 68(a0) -sw fs6, 72(a0) -sw fs7, 76(a0) -sw fs8, 80(a0) -sw fs9, 84(a0) -sw fs10, 88(a0) -sw fs11, 92(a0) -#endif -move a0, sp -ret -#else -#error "Unsupported RISC-V bit length" -#endif -#endif diff --git a/supervisor/shared/cpu_regs.h b/supervisor/shared/cpu_regs.h deleted file mode 100644 index 8243c2388cd..00000000000 --- a/supervisor/shared/cpu_regs.h +++ /dev/null @@ -1,38 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#ifdef __arm__ -#define INTEGER_REGS 10 -#ifdef __ARM_FP -#define FLOATING_POINT_REGS 16 -#endif -#endif - -#ifdef __aarch64__ -#define INTEGER_REGS 10 -#ifdef __ARM_FP -#define FLOATING_POINT_REGS 8 -#endif -#endif - -#ifdef __riscv -#define INTEGER_REGS 12 -#ifdef __riscv_vector -#define FLOATING_POINT_REGS 12 -#endif -#endif - -#ifndef INTEGER_REGS -#define INTEGER_REGS 0 -#endif - -#ifndef FLOATING_POINT_REGS -#define FLOATING_POINT_REGS 0 -#endif - -#define SAVED_REGISTER_COUNT (INTEGER_REGS + FLOATING_POINT_REGS) From f8c06e39ed97a32b67e0816f53d62762d3b096f2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 4 Feb 2026 10:58:53 -0800 Subject: [PATCH 192/876] Fix board builds --- ports/espressif/boards/m5stack_cores3_se/board.c | 4 ++-- ports/stm/boards/meowbit_v121/mpconfigboard.mk | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/m5stack_cores3_se/board.c b/ports/espressif/boards/m5stack_cores3_se/board.c index cf06bd8488d..bf5ccd17f36 100644 --- a/ports/espressif/boards/m5stack_cores3_se/board.c +++ b/ports/espressif/boards/m5stack_cores3_se/board.c @@ -46,8 +46,8 @@ static bool display_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - &pin_GPIO35, // DC - &pin_GPIO3, // CS + MP_OBJ_FROM_PTR(&pin_GPIO35), // DC + MP_OBJ_FROM_PTR(&pin_GPIO3), // CS NULL, // RST 40000000, // baudrate 0, // polarity diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.mk b/ports/stm/boards/meowbit_v121/mpconfigboard.mk index 74759abed54..419f073b5ea 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.mk +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.mk @@ -23,6 +23,7 @@ LD_FILE = boards/STM32F401xe_boot.ld # LD_FILE = boards/STM32F401xe_fs.ld CIRCUITPY_AESIO = 0 +CIRCUITPY_CODEOP = 0 CIRCUITPY_BITMAPFILTER = 0 CIRCUITPY_BITMAPTOOLS = 0 CIRCUITPY_BLEIO_HCI = 0 @@ -30,6 +31,7 @@ CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_I2CDISPLAYBUS = 0 CIRCUITPY_KEYPAD_DEMUX = 0 +CIRCUITPY_PIXELMAP = 0 CIRCUITPY_SHARPDISPLAY = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 CIRCUITPY_ULAB = 0 From b975d1da814ef32d8ee9b89ef7015e82e403042b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 5 Feb 2026 21:44:55 -0500 Subject: [PATCH 193/876] py/nlrthumb.c: restore r1,r2,r3 clobbers to nlr_push() --- ports/atmel-samd/peripherals | 2 +- py/nlrthumb.c | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index 863e615ff98..da0a1d7dccb 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit 863e615ff98c3a8aa904e87a157553559c933b81 +Subproject commit da0a1d7dccb34b7fa07738e7a8ce25118c88d1a3 diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 0aa1f053a23..265052568ff 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -36,8 +36,7 @@ // For reference, arm/thumb callee save regs are: // r4-r11, r13=sp -// CIRCUITPY-CHANGE: added returns_twice -__attribute__((naked, returns_twice)) unsigned int nlr_push(nlr_buf_t *nlr) { +__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { // If you get a linker error here, indicating that a relocation doesn't // fit, try the following (in that order): @@ -92,6 +91,10 @@ __attribute__((naked, returns_twice)) unsigned int nlr_push(nlr_buf_t *nlr) { "b nlr_push_tail \n" // do the rest in C #endif #endif + // CIRCUITPY-CHANGE: add input and clobbers to prevent smashing registers. + : // output operands + : "r" (nlr) // input operands + : "r1", "r2", "r3" // clobbers ); #if !defined(__clang__) && defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) @@ -141,7 +144,8 @@ NORETURN void nlr_jump(void *val) { "bx lr \n" // return : // output operands : "r" (top) // input operands - : "memory" // clobbered registers + // CIRCUITPY-CHANGE: better comment + : "memory" // clobbers ); MP_UNREACHABLE From 8df888eb29adbc49ea0b37b4206603829d3446b6 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 7 Feb 2026 18:28:59 -0500 Subject: [PATCH 194/876] prevent recursive display refresh --- shared-module/busdisplay/BusDisplay.c | 5 ++++- shared-module/epaperdisplay/EPaperDisplay.c | 6 +++++- shared-module/framebufferio/FramebufferDisplay.c | 5 ++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index a4652324c1e..46f3aaeaa0a 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -309,11 +309,14 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } static void _refresh_display(busdisplay_busdisplay_obj_t *self) { + if (!displayio_display_core_start_refresh(&self->core)) { + // Refresh for this display already in progress. + return; + } if (!displayio_display_bus_is_free(&self->bus)) { // A refresh on this bus is already in progress. Try next display. return; } - displayio_display_core_start_refresh(&self->core); const displayio_area_t *current_area = _get_refresh_areas(self); while (current_area != NULL) { _refresh_area(self, current_area); diff --git a/shared-module/epaperdisplay/EPaperDisplay.c b/shared-module/epaperdisplay/EPaperDisplay.c index 556db6ae220..5d92862fced 100644 --- a/shared-module/epaperdisplay/EPaperDisplay.c +++ b/shared-module/epaperdisplay/EPaperDisplay.c @@ -187,6 +187,11 @@ void epaperdisplay_epaperdisplay_change_refresh_mode_parameters(epaperdisplay_ep } static void epaperdisplay_epaperdisplay_start_refresh(epaperdisplay_epaperdisplay_obj_t *self) { + if (!displayio_display_core_start_refresh(&self->core)) { + // Refresh on this display already in progress. + return; + } + if (!displayio_display_bus_is_free(&self->bus)) { // Can't acquire display bus; skip updating this display. Try next display. return; @@ -201,7 +206,6 @@ static void epaperdisplay_epaperdisplay_start_refresh(epaperdisplay_epaperdispla if (mp_hal_is_interrupted()) { return; } - displayio_display_core_start_refresh(&self->core); } uint32_t common_hal_epaperdisplay_epaperdisplay_get_time_to_refresh(epaperdisplay_epaperdisplay_obj_t *self) { diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 4ba2b132581..8116f4b0347 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -217,7 +217,10 @@ static void _refresh_display(framebufferio_framebufferdisplay_obj_t *self) { if (!self->bufinfo.buf) { return; } - displayio_display_core_start_refresh(&self->core); + if (!displayio_display_core_start_refresh(&self->core)) { + // Refresh on this display already in progress. + return; + } const displayio_area_t *current_area = _get_refresh_areas(self); if (current_area) { bool transposed = (self->core.rotation == 90 || self->core.rotation == 270); From 65151c2ca182cc8c5a102df3619def5ee35cc5c3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 8 Feb 2026 15:21:50 -0500 Subject: [PATCH 195/876] Apply suggestions from code review --- ports/espressif/common-hal/_bleio/PacketBuffer.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/PacketBuffer.c b/ports/espressif/common-hal/_bleio/PacketBuffer.c index 00aaae44e38..db035157ceb 100644 --- a/ports/espressif/common-hal/_bleio/PacketBuffer.c +++ b/ports/espressif/common-hal/_bleio/PacketBuffer.c @@ -159,13 +159,7 @@ static int packet_buffer_on_ble_client_evt(struct ble_gap_event *event, void *pa return false; } -#if CIRCUITPY_SERIAL_BLE || CIRCUITPY_BLE_FILE_SERVICE -// Exposed via shared-bindings header when enabled void _common_hal_bleio_packet_buffer_construct( -#else -// Internal static helper when disabled (avoids "missing prototype" error) -static void _common_hal_bleio_packet_buffer_construct( -#endif bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, uint32_t *incoming_buffer, size_t incoming_buffer_size, uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, From ad580f4d9a30963f5747f41873740737fcc7ec93 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Mon, 9 Feb 2026 13:22:13 +0100 Subject: [PATCH 196/876] Bump circuitpython-stage to 1.4.0 This fixes the FourWire and BusDisplay imports for pybadge and pygamer. --- frozen/circuitpython-stage | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frozen/circuitpython-stage b/frozen/circuitpython-stage index ccac175f5e9..7b71363acb6 160000 --- a/frozen/circuitpython-stage +++ b/frozen/circuitpython-stage @@ -1 +1 @@ -Subproject commit ccac175f5e9c8392d436058d4364a8ca5e58abc7 +Subproject commit 7b71363acb67cb1b254b12607f35280cfb4ad6c1 From bcb9cd1f78be1508ef46967dba55cbfe3d6e29fd Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 9 Feb 2026 15:09:06 -0500 Subject: [PATCH 197/876] don't start refresh until we know bus is available --- shared-module/busdisplay/BusDisplay.c | 9 +++++---- shared-module/epaperdisplay/EPaperDisplay.c | 9 ++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 46f3aaeaa0a..6ef1c4c7f66 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -309,14 +309,15 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } static void _refresh_display(busdisplay_busdisplay_obj_t *self) { - if (!displayio_display_core_start_refresh(&self->core)) { - // Refresh for this display already in progress. - return; - } if (!displayio_display_bus_is_free(&self->bus)) { // A refresh on this bus is already in progress. Try next display. return; } + if (!displayio_display_core_start_refresh(&self->core)) { + // Refresh for this display already in progress. + return; + } + const displayio_area_t *current_area = _get_refresh_areas(self); while (current_area != NULL) { _refresh_area(self, current_area); diff --git a/shared-module/epaperdisplay/EPaperDisplay.c b/shared-module/epaperdisplay/EPaperDisplay.c index 5d92862fced..655ae103071 100644 --- a/shared-module/epaperdisplay/EPaperDisplay.c +++ b/shared-module/epaperdisplay/EPaperDisplay.c @@ -187,15 +187,14 @@ void epaperdisplay_epaperdisplay_change_refresh_mode_parameters(epaperdisplay_ep } static void epaperdisplay_epaperdisplay_start_refresh(epaperdisplay_epaperdisplay_obj_t *self) { - if (!displayio_display_core_start_refresh(&self->core)) { - // Refresh on this display already in progress. - return; - } - if (!displayio_display_bus_is_free(&self->bus)) { // Can't acquire display bus; skip updating this display. Try next display. return; } + if (!displayio_display_core_start_refresh(&self->core)) { + // Refresh on this display already in progress. + return; + } // run start sequence self->bus.bus_reset(self->bus.bus); From 4599aba309edc95ee7a618163e0a71cb3364e5f1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 9 Feb 2026 16:52:12 -0500 Subject: [PATCH 198/876] update frozen libraries --- frozen/Adafruit_CircuitPython_Bitmap_Font | 2 +- frozen/Adafruit_CircuitPython_BusDevice | 2 +- frozen/Adafruit_CircuitPython_NeoPixel | 2 +- frozen/Adafruit_CircuitPython_PortalBase | 2 +- frozen/Adafruit_CircuitPython_Wiznet5k | 2 +- frozen/Adafruit_CircuitPython_seesaw | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_Bitmap_Font b/frozen/Adafruit_CircuitPython_Bitmap_Font index 13c6a39a58e..cb6a08e2ca5 160000 --- a/frozen/Adafruit_CircuitPython_Bitmap_Font +++ b/frozen/Adafruit_CircuitPython_Bitmap_Font @@ -1 +1 @@ -Subproject commit 13c6a39a58e28030f3651a90e116c1ab30f2035b +Subproject commit cb6a08e2ca57df75b512b844cce78558088979fe diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice index baa6bcafa22..69ebda79d40 160000 --- a/frozen/Adafruit_CircuitPython_BusDevice +++ b/frozen/Adafruit_CircuitPython_BusDevice @@ -1 +1 @@ -Subproject commit baa6bcafa22512ac56f343c7d124f3b029861c33 +Subproject commit 69ebda79d40d0e74c01e4f1aa293f219b8c7e086 diff --git a/frozen/Adafruit_CircuitPython_NeoPixel b/frozen/Adafruit_CircuitPython_NeoPixel index 1a9523574b6..5b8fe0e7064 160000 --- a/frozen/Adafruit_CircuitPython_NeoPixel +++ b/frozen/Adafruit_CircuitPython_NeoPixel @@ -1 +1 @@ -Subproject commit 1a9523574b68cc205c151aaf080909348df7417c +Subproject commit 5b8fe0e70646d55bfa75a14cbc5136b9328be850 diff --git a/frozen/Adafruit_CircuitPython_PortalBase b/frozen/Adafruit_CircuitPython_PortalBase index 059c805bd1f..067b1b80dfd 160000 --- a/frozen/Adafruit_CircuitPython_PortalBase +++ b/frozen/Adafruit_CircuitPython_PortalBase @@ -1 +1 @@ -Subproject commit 059c805bd1f9157495d17739c8082f9a2042bdbf +Subproject commit 067b1b80dfd42fe1b62416eef2790b7d99d46206 diff --git a/frozen/Adafruit_CircuitPython_Wiznet5k b/frozen/Adafruit_CircuitPython_Wiznet5k index ea7b97c5b1f..fa2e95d61fb 160000 --- a/frozen/Adafruit_CircuitPython_Wiznet5k +++ b/frozen/Adafruit_CircuitPython_Wiznet5k @@ -1 +1 @@ -Subproject commit ea7b97c5b1faa2db4b54d7f6d9a61b545b49f383 +Subproject commit fa2e95d61fb5a90b8bd59234b56d1acbfe9fd995 diff --git a/frozen/Adafruit_CircuitPython_seesaw b/frozen/Adafruit_CircuitPython_seesaw index d01642926b8..50628104824 160000 --- a/frozen/Adafruit_CircuitPython_seesaw +++ b/frozen/Adafruit_CircuitPython_seesaw @@ -1 +1 @@ -Subproject commit d01642926b80a46762f1dd76dcdd5aefb0d95bc8 +Subproject commit 50628104824849fbdac093c8f18367623edff1c4 From ecdb5db1c968e72af50fab3636c1b8318310f388 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 10 Feb 2026 12:12:29 -0500 Subject: [PATCH 199/876] remove guard meant to be removed in #10755 --- shared-bindings/_bleio/PacketBuffer.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-bindings/_bleio/PacketBuffer.h b/shared-bindings/_bleio/PacketBuffer.h index 1a872512da2..dd0c1ae9e25 100644 --- a/shared-bindings/_bleio/PacketBuffer.h +++ b/shared-bindings/_bleio/PacketBuffer.h @@ -21,13 +21,11 @@ void common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, size_t buffer_size, size_t max_packet_size); // Allocation free version for BLE workflow use. -#if CIRCUITPY_SERIAL_BLE || CIRCUITPY_BLE_FILE_SERVICE void _common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, uint32_t *incoming_buffer, size_t incoming_buffer_size, - uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t outgoing_buffer_size, + uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, ble_event_handler_t *static_handler_entry); -#endif mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, const uint8_t *data, size_t len, uint8_t *header, size_t header_len); mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len); mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self); From f65029ed185a9037b46207abbd9a4a3c92852421 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 10 Feb 2026 19:09:20 +0100 Subject: [PATCH 200/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 8 ++++---- locale/el.po | 8 ++++---- locale/hi.po | 8 ++++---- locale/ko.po | 13 ++++++++----- locale/ru.po | 11 +++++++---- locale/tr.po | 8 ++++---- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index b7964d4ff13..ec160f6bdd3 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1679,10 +1679,6 @@ msgstr "Nepřipojený" msgid "Not playing" msgstr "Nehraje" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -2412,6 +2408,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "Nepodporovaný barevný prostor" diff --git a/locale/el.po b/locale/el.po index b40162b35b7..7b1a182690e 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1685,10 +1685,6 @@ msgstr "" msgid "Not playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -2416,6 +2412,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index 08b91c9bad6..c11116b34f6 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1661,10 +1661,6 @@ msgstr "" msgid "Not playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -2390,6 +2386,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 7963a7a9822..99c62684dc6 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1719,11 +1719,6 @@ msgstr "연결되지 않았습니다" msgid "Not playing" msgstr "재생되지 않았습니다" -#: shared-module/jpegio/JpegDecoder.c -#, fuzzy -msgid "Not supported JPEG standard" -msgstr "지원되지 않는 JPEG 표준" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -2465,6 +2460,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" @@ -4663,6 +4662,10 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, fuzzy +#~ msgid "Not supported JPEG standard" +#~ msgstr "지원되지 않는 JPEG 표준" + #, fuzzy #~ msgid "%q moved from %q to %q" #~ msgstr "%q가 %q에서 %q로 이동했습니다" diff --git a/locale/ru.po b/locale/ru.po index 45ecfb19f0f..cf83523e82c 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1702,10 +1702,6 @@ msgstr "Не подключено" msgid "Not playing" msgstr "Не воспроизводится (Not playing)" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "Не поддерживается Стандарт JPEG" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -2449,6 +2445,10 @@ msgstr "" "Неуказанная проблема. Возможно, запрос на сопряжение на другом устройстве " "был отклонен или проигнорирован." +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "Неподдерживаемое цветовое пространство" @@ -4681,6 +4681,9 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#~ msgid "Not supported JPEG standard" +#~ msgstr "Не поддерживается Стандарт JPEG" + #~ msgid "%q moved from %q to %q" #~ msgstr "%q переместился из %q в %q" diff --git a/locale/tr.po b/locale/tr.po index 7951c91c4bf..f8db30f3893 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1680,10 +1680,6 @@ msgstr "" msgid "Not playing" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Not supported JPEG standard" -msgstr "" - #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format @@ -2412,6 +2408,10 @@ msgid "" "declined or ignored." msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" msgstr "" From 5a1b57cf62d59b3bbbe657f810d5042f3d1459ca Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 10 Feb 2026 13:45:09 -0500 Subject: [PATCH 201/876] fix silab compile issues --- ports/silabs/common-hal/_bleio/PacketBuffer.c | 2 +- ports/silabs/common-hal/microcontroller/__init__.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/silabs/common-hal/_bleio/PacketBuffer.c b/ports/silabs/common-hal/_bleio/PacketBuffer.c index dec833fe62f..881cf1622eb 100644 --- a/ports/silabs/common-hal/_bleio/PacketBuffer.c +++ b/ports/silabs/common-hal/_bleio/PacketBuffer.c @@ -145,7 +145,7 @@ void _common_hal_bleio_packet_buffer_construct( uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, - ble_event_handler_t static_handler_entry) { + ble_event_handler_t *static_handler_entry) { bleio_characteristic_properties_t temp_prop; self->characteristic = characteristic; diff --git a/ports/silabs/common-hal/microcontroller/__init__.c b/ports/silabs/common-hal/microcontroller/__init__.c index b1472fcf437..7244af6619d 100644 --- a/ports/silabs/common-hal/microcontroller/__init__.c +++ b/ports/silabs/common-hal/microcontroller/__init__.c @@ -60,6 +60,9 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { } } +// CHIP_Reset does not return, but is not declared as such in the SDK. +void __attribute__ ((noreturn)) CHIP_Reset(void); + void common_hal_mcu_reset(void) { filesystem_flush(); // TODO: implement as part of flash improvements CHIP_Reset(); From 0b3b90ae16603c22b18e7d88fbe37fd8d2a687a8 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 10 Feb 2026 18:48:26 -0500 Subject: [PATCH 202/876] ble_hci PacketBuffer.h: need a def for ble_event_handler_t --- devices/ble_hci/common-hal/_bleio/PacketBuffer.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.h b/devices/ble_hci/common-hal/_bleio/PacketBuffer.h index 563f365d21b..4e001339fe3 100644 --- a/devices/ble_hci/common-hal/_bleio/PacketBuffer.h +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.h @@ -28,4 +28,7 @@ typedef struct { bool packet_queued; } bleio_packet_buffer_obj_t; +// Unused, but needed for _common_hal_bleio_packet_buffer_construct() +typedef void *ble_event_handler_t; + void bleio_packet_buffer_update(bleio_packet_buffer_obj_t *self, mp_buffer_info_t *bufinfo); From 13de16c14ae0511bdad2617030184171930543dc Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 12 Feb 2026 11:53:40 -0600 Subject: [PATCH 203/876] Update USB vid/pid codes --- ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk | 4 ++-- .../boards/tinycircuits_thumby_color/mpconfigboard.mk | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk index 44dc0d67100..d8140e6cb0a 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk +++ b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.mk @@ -1,5 +1,5 @@ -USB_VID = 0x1D6B -USB_PID = 0x0003 +USB_VID = 0x1209 +USB_PID = 0x3500 USB_PRODUCT = "Thumby" USB_MANUFACTURER = "TinyCircuits" diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk index ed1255e2b96..828d4a638d5 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk @@ -1,5 +1,5 @@ -USB_VID = 0x1D6B -USB_PID = 0x0003 +USB_VID = 0x1209 +USB_PID = 0x3501 USB_PRODUCT = "Thumby Color" USB_MANUFACTURER = "TinyCircuits" From a2ab5536c857ea401058c609bf0f4d2f24f4fc86 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Thu, 12 Feb 2026 19:37:37 +0100 Subject: [PATCH 204/876] Add board definition for uGame S3 uGame S3 is a handheld game console with an ESP32-S3 chip. More information at https://deshipu.art/projects/project-178061/ --- .../espressif/boards/deshipu_ugame_s3/board.c | 123 ++++++++++++++++++ .../boards/deshipu_ugame_s3/mpconfigboard.h | 28 ++++ .../boards/deshipu_ugame_s3/mpconfigboard.mk | 27 ++++ .../espressif/boards/deshipu_ugame_s3/pins.c | 43 ++++++ .../boards/deshipu_ugame_s3/sdkconfig | 22 ++++ 5 files changed, 243 insertions(+) create mode 100644 ports/espressif/boards/deshipu_ugame_s3/board.c create mode 100644 ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h create mode 100644 ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk create mode 100644 ports/espressif/boards/deshipu_ugame_s3/pins.c create mode 100644 ports/espressif/boards/deshipu_ugame_s3/sdkconfig diff --git a/ports/espressif/boards/deshipu_ugame_s3/board.c b/ports/espressif/boards/deshipu_ugame_s3/board.c new file mode 100644 index 00000000000..677cab7f076 --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/board.c @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "supervisor/board.h" +#include "mpconfigboard.h" + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + +#include "esp_log.h" +#include "esp_err.h" + +fourwire_fourwire_obj_t board_display_obj; + +#define DELAY 0x80 + +uint8_t display_init_sequence[] = { + 0x01, 0 | DELAY, 0x80, // Software reset then delay 0x80 (128ms) + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + 0xc0, 1, 0x23, // Power control VRH[5:0] + 0xc1, 1, 0x10, // Power control SAP[2:0];BT[3:0] + 0xc5, 2, 0x3e, 0x28, // VCM control + 0xc7, 1, 0x86, // VCM control2 + 0x37, 1, 0x00, // Vertical scroll zero + 0x3a, 1, 0x55, // COLMOD: Pixel Format Set + 0xb1, 2, 0x00, 0x18, // Frame Rate Control (In Normal Mode/Full Colors) + 0xb6, 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + 0x26, 1, 0x01, // Gamma curve selected + 0xe0, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma + 0xe1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma + 0x11, 0 | DELAY, 0x78, // Exit Sleep then delay 0x78 (120ms) + 0x29, 0 | DELAY, 0x78, // Display on then delay 0x78 (120ms) + 0x36, 1, 0x38, +}; + + +void board_init(void) { + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO12, &pin_GPIO11, NULL, false); + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO10), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO13), // TFT_RESET Reset + 80000000L, // Baudrate + 0, // Polarity + 0); // Phase + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 320, // Width (after rotation) + 240, // Height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // Color depth + false, // Grayscale + false, // Pixels in a byte share a row. Only used for depth < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command + MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO21, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 20, // native_frames_per_second + true, // backlight_on_high + false, // not SH1107 + 50000); // backlight pwm frequency +} + +void board_deinit(void) { +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h new file mode 100644 index 00000000000..da7c3b4e8a4 --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h @@ -0,0 +1,28 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#define MICROPY_HW_BOARD_NAME "uGame S3" +#define MICROPY_HW_MCU_NAME "ESP32S3" diff --git a/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk new file mode 100644 index 00000000000..36a0ce040c5 --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk @@ -0,0 +1,27 @@ +USB_VID = 0x1209 +USB_PID = 0xD187 +USB_PRODUCT = "uGameS3" +USB_MANUFACTURER = "deshipu" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +CIRCUITPY_STAGE = 1 +CIRCUITPY_KEYPAD = 1 + +CIRCUITPY_CANIO = 0 +CIRCUITPY_DUALBANK = 0 +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_FRAMEBUFFERIO = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_RGBMATRIX = 0 +CIRCUITPY_ROTARYIO = 0 + +FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/ugame_s3 diff --git a/ports/espressif/boards/deshipu_ugame_s3/pins.c b/ports/espressif/boards/deshipu_ugame_s3/pins.c new file mode 100644 index 00000000000..54bd5dcdb4f --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/pins.c @@ -0,0 +1,43 @@ +#include "py/objtuple.h" +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_P1), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_P2), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_P3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_P4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_P5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_P6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_P7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_UP), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_DOWN), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_O), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_Z), MP_ROM_PTR(&pin_GPIO47) }, + + { MP_ROM_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_GPIO8) }, + + + { MP_ROM_QSTR(MP_QSTR_AUDIO_BCLK), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_LRCLK), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_DATA), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_GAIN), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/deshipu_ugame_s3/sdkconfig b/ports/espressif/boards/deshipu_ugame_s3/sdkconfig new file mode 100644 index 00000000000..1bddb7a89fb --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/sdkconfig @@ -0,0 +1,22 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="espressif-esp32s3" +# end of LWIP + +# +# Camera configuration +# +# CONFIG_OV7725_SUPPORT is not set +# CONFIG_OV3660_SUPPORT is not set +# end of Camera configuration + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From 8142afc6a2004c75478b0f6a100664633710878a Mon Sep 17 00:00:00 2001 From: Arif Budiman Date: Thu, 12 Feb 2026 15:15:35 +0100 Subject: [PATCH 205/876] Translated using Weblate (Indonesian) Currently translated at 100.0% (1012 of 1012 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/id/ --- locale/ID.po | 1113 +++++++++++++++++++++++++------------------------- 1 file changed, 563 insertions(+), 550 deletions(-) diff --git a/locale/ID.po b/locale/ID.po index ee7b8dfc4a3..ca862a97147 100644 --- a/locale/ID.po +++ b/locale/ID.po @@ -6,15 +6,15 @@ msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-06-30 16:01+0000\n" -"Last-Translator: MAE \n" +"PO-Revision-Date: 2026-02-13 15:09+0000\n" +"Last-Translator: Arif Budiman \n" "Language-Team: LANGUAGE \n" "Language: ID\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 5.13-dev\n" +"X-Generator: Weblate 5.16-dev\n" #: main.c msgid "" @@ -116,7 +116,7 @@ msgstr "%q gagal: %d" #: shared-module/audiodelays/MultiTapDelay.c msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +msgstr "%q dalam %q harus bertipe %q atau %q, bukan %q" #: py/argcheck.c shared-module/audiofilters/Filter.c msgid "%q in %q must be of type %q, not %q" @@ -289,7 +289,7 @@ msgstr "%q, %q, dan %q semuanya harus memiliki panjang yang sama" #: py/objint.c shared-bindings/_bleio/Connection.c #: shared-bindings/storage/__init__.c msgid "%q=%q" -msgstr "" +msgstr "%q=%q" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "%q[%u] shifts in more bits than pin count" @@ -566,7 +566,7 @@ msgstr "Sudah disebarkan." #: ports/atmel-samd/common-hal/canio/Listener.c msgid "Already have all-matches listener" -msgstr "" +msgstr "Sudah memiliki listener semua-kecocokan" #: ports/espressif/common-hal/_bleio/__init__.c msgid "Already in progress" @@ -610,7 +610,7 @@ msgstr "Nilai array harus berupa byte tunggal." #: ports/atmel-samd/common-hal/spitarget/SPITarget.c msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" +msgstr "Transfer SPI async sedang berlangsung pada bus ini, terus menunggu." #: shared-module/memorymonitor/AllocationAlarm.c #, c-format @@ -624,7 +624,7 @@ msgstr "Konversi audio belum diimplementasikan" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c msgid "Audio source error" -msgstr "" +msgstr "Kesalahan sumber audio" #: shared-bindings/wifi/Radio.c msgid "AuthMode.OPEN is not used with password" @@ -767,7 +767,7 @@ msgstr "" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Can't construct AudioOut because continuous channel already open" -msgstr "" +msgstr "Tidak dapat membuat AudioOut karena kanal berkelanjutan sudah terbuka" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c @@ -817,7 +817,7 @@ msgstr "Tidak dapat merekam ke file" #: shared-module/storage/__init__.c msgid "Cannot remount path when visible via USB." -msgstr "" +msgstr "Tidak dapat me-remount jalur ketika terlihat melalui USB." #: shared-bindings/digitalio/DigitalInOut.c msgid "Cannot set value when direction is input." @@ -834,7 +834,7 @@ msgstr "Tidak dapat membuat subkelas dari irisan" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" +msgstr "Tidak dapat menggunakan GPIO0..15 bersamaan dengan GPIO32..47" #: ports/nordic/common-hal/alarm/pin/PinAlarm.c msgid "Cannot wake on pin edge, only level" @@ -873,7 +873,7 @@ msgstr "Tipe array koordinat memiliki ukuran yang berbeda" #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" -msgstr "" +msgstr "Tidak dapat mempublikasikan ke topik ROS" #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" @@ -890,7 +890,7 @@ msgstr "Tidak dapat mengalokasikan dekoder" #: ports/espressif/common-hal/rclcpy/__init__.c #, c-format msgid "Critical ROS failure during soft reboot, reset required: %d" -msgstr "" +msgstr "Kegagalan ROS kritis selama soft reboot, reset diperlukan: %d" #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Channel Init Error" @@ -1009,28 +1009,30 @@ msgstr "Gagal memperoleh mutex, err 0x%04x" #: ports/raspberrypi/common-hal/mdns/Server.c msgid "Failed to add service TXT record" -msgstr "" +msgstr "Gagal menambahkan record TXT layanan" #: shared-bindings/mdns/Server.c msgid "" "Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" +"Gagal menambahkan record TXT layanan; ditemukan non-string atau bytes dalam " +"txt_records" #: shared-module/rgbmatrix/RGBMatrix.c msgid "Failed to allocate %q buffer" -msgstr "" +msgstr "Gagal mengalokasikan buffer %q" #: ports/espressif/common-hal/wifi/__init__.c msgid "Failed to allocate Wifi memory" -msgstr "" +msgstr "Gagal mengalokasikan memori Wifi" #: ports/espressif/common-hal/wifi/ScannedNetworks.c msgid "Failed to allocate wifi scan memory" -msgstr "" +msgstr "Gagal mengalokasikan memori pemindaian wifi" #: ports/stm/common-hal/audiopwmio/PWMAudioOut.c msgid "Failed to buffer the sample" -msgstr "" +msgstr "Gagal membuffer sampel" #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c @@ -1043,23 +1045,23 @@ msgstr "Gagal terhubung: habis waktu" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: invalid arg" -msgstr "" +msgstr "Gagal membuat kanal berkelanjutan: argumen tidak valid" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: invalid state" -msgstr "" +msgstr "Gagal membuat kanal berkelanjutan: status tidak valid" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: no mem" -msgstr "" +msgstr "Gagal membuat kanal berkelanjutan: tidak ada memori" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to create continuous channels: not found" -msgstr "" +msgstr "Gagal membuat kanal berkelanjutan: tidak ditemukan" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to enable continuous" -msgstr "" +msgstr "Gagal mengaktifkan berkelanjutan" #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" @@ -1067,7 +1069,7 @@ msgstr "Gagal mengurai file MP3" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to register continuous events callback" -msgstr "" +msgstr "Gagal mendaftarkan callback event berkelanjutan" #: ports/nordic/sd_mutex.c #, c-format @@ -1076,11 +1078,11 @@ msgstr "Gagal melepaskan mutex, err 0x%04x" #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" -msgstr "" +msgstr "Gagal menetapkan hostname" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to start async audio" -msgstr "" +msgstr "Gagal memulai audio async" #: supervisor/shared/safe_mode.c msgid "Failed to write internal flash." @@ -1093,43 +1095,44 @@ msgstr "File sudah ada" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c #: shared-module/os/getenv.c msgid "File not found" -msgstr "" +msgstr "File tidak ditemukan" #: ports/atmel-samd/common-hal/canio/Listener.c #: ports/espressif/common-hal/canio/Listener.c #: ports/mimxrt10xx/common-hal/canio/Listener.c #: ports/stm/common-hal/canio/Listener.c msgid "Filters too complex" -msgstr "" +msgstr "Filter terlalu kompleks" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is duplicate" -msgstr "" +msgstr "Firmware adalah duplikat" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is invalid" -msgstr "" +msgstr "Firmware tidak valid" #: ports/espressif/common-hal/dualbank/__init__.c msgid "Firmware is too big" -msgstr "" +msgstr "Firmware terlalu besar" #: shared-bindings/bitmaptools/__init__.c msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "" +msgstr "Untuk colorspace L8, bitmap input harus memiliki 8 bit per piksel" #: shared-bindings/bitmaptools/__init__.c msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "" +msgstr "Untuk colorspace RGB, bitmap input harus memiliki 16 bit per piksel" #: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c msgid "Format not supported" -msgstr "" +msgstr "Format tidak didukung" #: ports/mimxrt10xx/common-hal/microcontroller/Processor.c msgid "" "Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" +"Frekuensi harus 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 atau 1008 Mhz" #: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c #: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c @@ -1138,11 +1141,11 @@ msgstr "Fungsinya membutuhkan kunci" #: ports/cxd56/common-hal/gnss/GNSS.c msgid "GNSS init" -msgstr "" +msgstr "Inisialisasi GNSS" #: ports/espressif/common-hal/espidf/__init__.c msgid "Generic Failure" -msgstr "" +msgstr "Kegagalan Umum" #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c @@ -1152,7 +1155,7 @@ msgstr "Grup sudah digunakan" #: supervisor/shared/safe_mode.c msgid "Hard fault: memory access or instruction error." -msgstr "" +msgstr "Hard fault: kesalahan akses memori atau instruksi." #: ports/mimxrt10xx/common-hal/busio/SPI.c #: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c @@ -1163,7 +1166,7 @@ msgstr "Perangkat keras sedang digunakan, coba pin alternatif" #: supervisor/shared/safe_mode.c msgid "Heap allocation when VM not running." -msgstr "" +msgstr "Alokasi heap ketika VM tidak berjalan." #: extmod/vfs_posix_file.c py/objstringio.c msgid "I/O operation on closed file" @@ -1171,16 +1174,16 @@ msgstr "operasi I/O pada file tertutup" #: ports/stm/common-hal/busio/I2C.c msgid "I2C init error" -msgstr "" +msgstr "Kesalahan inisialisasi I2C" #: ports/raspberrypi/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c msgid "I2C peripheral in use" -msgstr "" +msgstr "Periferal I2C sedang digunakan" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "In-buffer elements must be <= 4 bytes long" -msgstr "" +msgstr "Elemen in-buffer harus <= 4 byte panjangnya" #: shared-bindings/_pew/PewPew.c msgid "Incorrect buffer size" @@ -1188,24 +1191,25 @@ msgstr "Ukuran penyangga salah" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Init program size invalid" -msgstr "" +msgstr "Ukuran program inisialisasi tidak valid" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "" +msgstr "Arah pin set awal berkonflik dengan arah pin out awal" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Initial set pin state conflicts with initial out pin state" -msgstr "" +msgstr "Status pin set awal berkonflik dengan status pin out awal" #: shared-bindings/bitops/__init__.c #, c-format msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" +"Panjang buffer input (%d) harus merupakan kelipatan dari jumlah strand (%d)" #: ports/atmel-samd/common-hal/pulseio/PulseIn.c msgid "Input taking too long" -msgstr "" +msgstr "Input memakan waktu terlalu lama" #: py/moderrno.c msgid "Input/output error" @@ -1223,20 +1227,20 @@ msgstr "Enkripsi tidak cukup" #: shared-module/jpegio/JpegDecoder.c msgid "Insufficient memory pool for the image" -msgstr "" +msgstr "Pool memori tidak mencukupi untuk gambar" #: shared-module/jpegio/JpegDecoder.c msgid "Insufficient stream input buffer" -msgstr "" +msgstr "Buffer input stream tidak mencukupi" #: ports/espressif/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Interface must be started" -msgstr "" +msgstr "Interface harus dimulai" #: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c msgid "Internal audio buffer too small" -msgstr "" +msgstr "Buffer audio internal terlalu kecil" #: ports/stm/common-hal/busio/UART.c msgid "Internal define error" @@ -1244,7 +1248,7 @@ msgstr "Kesalahan definisi internal" #: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c msgid "Internal error" -msgstr "" +msgstr "Kesalahan internal" #: shared-module/rgbmatrix/RGBMatrix.c #, c-format @@ -1262,19 +1266,19 @@ msgstr "Kesalahan internal #%d" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-bindings/pwmio/PWMOut.c msgid "Internal resource(s) in use" -msgstr "" +msgstr "Sumber daya internal sedang digunakan" #: supervisor/shared/safe_mode.c msgid "Internal watchdog timer expired." -msgstr "" +msgstr "Timer watchdog internal kedaluwarsa." #: supervisor/shared/safe_mode.c msgid "Interrupt error." -msgstr "" +msgstr "Kesalahan interrupt." #: shared-module/jpegio/JpegDecoder.c msgid "Interrupted by output function" -msgstr "" +msgstr "Diinterupsi oleh fungsi output" #: ports/espressif/common-hal/_bleio/Service.c #: ports/espressif/common-hal/espulp/ULP.c @@ -1290,12 +1294,12 @@ msgstr "" #: shared-module/aurora_epaper/aurora_framebuffer.c #: shared-module/lvfontio/OnDiskFont.c msgid "Invalid %q" -msgstr "" +msgstr "%q tidak valid" #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" -msgstr "" +msgstr "%q dan %q tidak valid" #: ports/atmel-samd/common-hal/microcontroller/Pin.c #: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c @@ -1311,19 +1315,19 @@ msgstr "Nilai Unit ADC tidak valid" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid BLE parameter" -msgstr "" +msgstr "Parameter BLE tidak valid" #: shared-bindings/wifi/Radio.c msgid "Invalid BSSID" -msgstr "" +msgstr "BSSID tidak valid" #: shared-bindings/wifi/Radio.c msgid "Invalid MAC address" -msgstr "" +msgstr "Alamat MAC tidak valid" #: ports/espressif/common-hal/rclcpy/__init__.c msgid "Invalid ROS domain ID" -msgstr "" +msgstr "ID domain ROS tidak valid" #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" @@ -1336,16 +1340,16 @@ msgstr "Bit per nilai tidak valid" #: shared-module/os/getenv.c #, c-format msgid "Invalid byte %.*s" -msgstr "" +msgstr "Byte tidak valid %.*s" #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" -msgstr "" +msgstr "data_pins[%d] tidak valid" #: shared-module/msgpack/__init__.c msgid "Invalid format" -msgstr "" +msgstr "Format tidak valid" #: shared-module/audiocore/WaveFile.c msgid "Invalid format chunk size" @@ -1353,29 +1357,29 @@ msgstr "Ukuran potongan format tidak valid" #: shared-bindings/wifi/Radio.c msgid "Invalid hex password" -msgstr "" +msgstr "Password hex tidak valid" #: ports/espressif/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Invalid multicast MAC address" -msgstr "" +msgstr "Alamat MAC multicast tidak valid" #: ports/espressif/common-hal/espidf/__init__.c msgid "Invalid size" -msgstr "" +msgstr "Ukuran tidak valid" #: shared-module/ssl/SSLSocket.c msgid "Invalid socket for TLS" -msgstr "" +msgstr "Socket tidak valid untuk TLS" #: ports/espressif/common-hal/espidf/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c msgid "Invalid state" -msgstr "" +msgstr "Status tidak valid" #: shared-module/os/getenv.c msgid "Invalid unicode escape" -msgstr "" +msgstr "Escape unicode tidak valid" #: shared-bindings/aesio/aes.c msgid "Key must be 16, 24, or 32 bytes long" @@ -1383,11 +1387,11 @@ msgstr "Panjang kunci harus 16, 24, atau 32 byte" #: shared-module/os/getenv.c msgid "Key not found" -msgstr "" +msgstr "Kunci tidak ditemukan" #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" -msgstr "" +msgstr "Pemetaan LED harus sesuai dengan ukuran display" #: py/compile.c msgid "LHS of keyword arg must be an id" @@ -1395,74 +1399,75 @@ msgstr "LHS dari keyword arg harus menjadi sebuah id" #: shared-module/displayio/Group.c msgid "Layer already in a group" -msgstr "" +msgstr "Layer sudah ada dalam grup" #: shared-module/displayio/Group.c msgid "Layer must be a Group or TileGrid subclass" -msgstr "" +msgstr "Layer harus merupakan subclass Group atau TileGrid" #: shared-bindings/audiocore/RawSample.c msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" +"Panjang %q harus merupakan kelipatan genap dari channel_count * type_size" #: ports/espressif/common-hal/espidf/__init__.c msgid "MAC address was invalid" -msgstr "" +msgstr "Alamat MAC tidak valid" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/espressif/common-hal/_bleio/Descriptor.c msgid "MITM security not supported" -msgstr "" +msgstr "Keamanan MITM tidak didukung" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "MMC/SDIO Clock Error %x" -msgstr "" +msgstr "Kesalahan Clock MMC/SDIO %x" #: shared-bindings/is31fl3741/IS31FL3741.c msgid "Mapping must be a tuple" -msgstr "" +msgstr "Mapping harus berupa tuple" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched data size" -msgstr "" +msgstr "Ukuran data tidak cocok" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Mismatched swap flag" -msgstr "" +msgstr "Flag swap tidak cocok" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "" +msgstr "first_in_pin tidak ada. %q[%u] membaca pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "" +msgstr "first_in_pin tidak ada. %q[%u] melakukan shift in dari pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "" +msgstr "first_in_pin tidak ada. %q[%u] menunggu berdasarkan pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "" +msgstr "first_out_pin tidak ada. %q[%u] melakukan shift out ke pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "" +msgstr "first_out_pin tidak ada. %q[%u] menulis pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "" +msgstr "first_set_pin tidak ada. %q[%u] menetapkan pin" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "" +msgstr "jmp_pin tidak ada. %q[%u] melompat pada pin" #: shared-module/storage/__init__.c msgid "Mount point directory missing" -msgstr "" +msgstr "Direktori titik mount tidak ada" #: ports/zephyr-cp/bindings/zephyr_serial/UART.c shared-bindings/busio/UART.c #: shared-bindings/displayio/Group.c @@ -1471,7 +1476,7 @@ msgstr "Harus berupa subclass %q." #: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c msgid "Must provide 5/6/5 RGB pins" -msgstr "" +msgstr "Harus menyediakan pin RGB 5/6/5" #: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" @@ -1484,23 +1489,23 @@ msgstr "Harus menggunakan kelipatan 6 pin rgb, bukan %d" #: supervisor/shared/safe_mode.c msgid "NLR jump failed. Likely memory corruption." -msgstr "" +msgstr "Lompatan NLR gagal. Kemungkinan korupsi memori." #: ports/espressif/common-hal/nvm/ByteArray.c msgid "NVS Error" -msgstr "" +msgstr "Kesalahan NVS" #: shared-bindings/socketpool/SocketPool.c msgid "Name or service not known" -msgstr "" +msgstr "Nama atau layanan tidak diketahui" #: shared-bindings/displayio/TileGrid.c msgid "New bitmap must be same size as old bitmap" -msgstr "" +msgstr "Bitmap baru harus berukuran sama dengan bitmap lama" #: ports/espressif/common-hal/_bleio/__init__.c msgid "Nimble out of memory" -msgstr "" +msgstr "Nimble kehabisan memori" #: ports/atmel-samd/common-hal/busio/UART.c #: ports/espressif/common-hal/busio/SPI.c @@ -1535,26 +1540,26 @@ msgstr "tidak ada channel DMA ditemukan" #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c msgid "No DMA pacing timer found" -msgstr "" +msgstr "Tidak ditemukan timer pacing DMA" #: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c #, c-format msgid "No I2C device at address: 0x%x" -msgstr "" +msgstr "Tidak ada perangkat I2C pada alamat: 0x%x" #: supervisor/shared/web_workflow/web_workflow.c msgid "No IP" -msgstr "" +msgstr "Tidak ada IP" #: ports/atmel-samd/common-hal/microcontroller/__init__.c #: ports/cxd56/common-hal/microcontroller/__init__.c #: ports/mimxrt10xx/common-hal/microcontroller/__init__.c msgid "No bootloader present" -msgstr "" +msgstr "Tidak ada bootloader" #: shared-module/usb/core/Device.c msgid "No configuration set" -msgstr "" +msgstr "Tidak ada konfigurasi yang ditetapkan" #: shared-bindings/_bleio/PacketBuffer.c msgid "No connection: length cannot be determined" @@ -1576,11 +1581,11 @@ msgstr "Tidak ada perangkat keras acak yang tersedia" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "No in in program" -msgstr "" +msgstr "Tidak ada in dalam program" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "No in or out in program" -msgstr "" +msgstr "Tidak ada in atau out dalam program" #: py/objint.c shared-bindings/time/__init__.c msgid "No long integer support" @@ -1588,18 +1593,18 @@ msgstr "Tidak ada dukungan bilangan bulat yang panjang" #: shared-bindings/wifi/Radio.c msgid "No network with that ssid" -msgstr "" +msgstr "Tidak ada jaringan dengan ssid tersebut" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "No out in program" -msgstr "" +msgstr "Tidak ada out dalam program" #: ports/atmel-samd/common-hal/busio/I2C.c #: ports/espressif/common-hal/busio/I2C.c #: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c #: ports/raspberrypi/common-hal/busio/I2C.c msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "" +msgstr "Tidak ditemukan pull up pada SDA atau SCL; periksa pengkabelan Anda" #: shared-module/touchio/TouchIn.c msgid "No pulldown on pin; 1Mohm recommended" @@ -1607,7 +1612,7 @@ msgstr "Tidak ada pull-down pada pin; 1Mohm direkomendasikan" #: shared-module/touchio/TouchIn.c msgid "No pullup on pin; 1Mohm recommended" -msgstr "" +msgstr "Tidak ada pullup pada pin; 1Mohm direkomendasikan" #: py/moderrno.c msgid "No space left on device" @@ -1615,7 +1620,7 @@ msgstr "Tidak ada ruang yang tersisa di perangkat" #: py/moderrno.c msgid "No such device" -msgstr "" +msgstr "Perangkat tidak ada" #: py/moderrno.c msgid "No such file/directory" @@ -1627,15 +1632,15 @@ msgstr "Penghitung waktu tidak tersedia" #: shared-module/usb/core/Device.c msgid "No usb host port initialized" -msgstr "" +msgstr "Tidak ada port host usb yang diinisialisasi" #: ports/nordic/common-hal/_bleio/__init__.c msgid "Nordic system firmware out of memory" -msgstr "" +msgstr "Firmware sistem Nordic kehabisan memori" #: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c msgid "Not a valid IP string" -msgstr "" +msgstr "Bukan string IP yang valid" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c @@ -1656,7 +1661,7 @@ msgstr "" #: ports/espressif/common-hal/sdioio/SDCard.c #, c-format msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" +msgstr "Jumlah data_pins harus %d atau %d, bukan %d" #: shared-bindings/util.c msgid "" @@ -1670,17 +1675,17 @@ msgstr "Parity ganjil tidak didukung" #: supervisor/shared/bluetooth/bluetooth.c msgid "Off" -msgstr "" +msgstr "Mati" #: supervisor/shared/bluetooth/bluetooth.c msgid "Ok" -msgstr "" +msgstr "Ok" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c #, c-format msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "" +msgstr "Hanya mono 8 atau 16 bit dengan oversampling %dx yang didukung." #: ports/espressif/common-hal/wifi/__init__.c #: ports/raspberrypi/common-hal/wifi/__init__.c @@ -1701,51 +1706,51 @@ msgstr "" #: shared-bindings/_bleio/Adapter.c msgid "Only connectable advertisements can be directed" -msgstr "" +msgstr "Hanya advertisement yang dapat terhubung yang dapat diarahkan" #: ports/stm/common-hal/alarm/pin/PinAlarm.c msgid "Only edge detection is available on this hardware" -msgstr "" +msgstr "Hanya deteksi tepi yang tersedia pada perangkat keras ini" #: shared-bindings/ipaddress/__init__.c msgid "Only int or string supported for ip" -msgstr "" +msgstr "Hanya int atau string yang didukung untuk ip" #: ports/espressif/common-hal/alarm/touch/TouchAlarm.c msgid "Only one %q can be set in deep sleep." -msgstr "" +msgstr "Hanya satu %q yang dapat ditetapkan dalam deep sleep." #: ports/espressif/common-hal/espulp/ULPAlarm.c msgid "Only one %q can be set." -msgstr "" +msgstr "Hanya satu %q yang dapat ditetapkan." #: ports/espressif/common-hal/i2ctarget/I2CTarget.c #: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c msgid "Only one address is allowed" -msgstr "" +msgstr "Hanya satu alamat yang diperbolehkan" #: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c #: ports/nordic/common-hal/alarm/time/TimeAlarm.c #: ports/stm/common-hal/alarm/time/TimeAlarm.c msgid "Only one alarm.time alarm can be set" -msgstr "" +msgstr "Hanya satu alarm alarm.time yang dapat ditetapkan" #: ports/espressif/common-hal/alarm/time/TimeAlarm.c #: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c msgid "Only one alarm.time alarm can be set." -msgstr "" +msgstr "Hanya satu alarm alarm.time yang dapat ditetapkan." #: shared-module/displayio/ColorConverter.c msgid "Only one color can be transparent at a time" -msgstr "" +msgstr "Hanya satu warna yang dapat transparan pada satu waktu" #: py/moderrno.c msgid "Operation not permitted" -msgstr "" +msgstr "Operasi tidak diizinkan" #: ports/espressif/common-hal/espidf/__init__.c msgid "Operation or feature not supported" -msgstr "" +msgstr "Operasi atau fitur tidak didukung" #: ports/espressif/common-hal/espidf/__init__.c msgid "Operation timed out" @@ -1753,7 +1758,7 @@ msgstr "Waktu habis" #: ports/raspberrypi/common-hal/mdns/Server.c msgid "Out of MDNS service slots" -msgstr "" +msgstr "Kehabisan slot layanan MDNS" #: ports/espressif/common-hal/espidf/__init__.c msgid "Out of memory" @@ -1767,27 +1772,27 @@ msgstr "Kehabisan socket" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "" +msgstr "Elemen out-buffer harus <= 4 byte panjangnya" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "PWM restart" -msgstr "" +msgstr "Restart PWM" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "PWM slice already in use" -msgstr "" +msgstr "Slice PWM sudah digunakan" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "PWM slice channel A already in use" -msgstr "" +msgstr "Channel A slice PWM sudah digunakan" #: shared-bindings/spitarget/SPITarget.c msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" +msgstr "Buffer paket untuk transfer SPI harus memiliki panjang yang sama." #: shared-module/jpegio/JpegDecoder.c msgid "Parameter error" -msgstr "" +msgstr "Kesalahan parameter" #: ports/espressif/common-hal/audiobusio/__init__.c msgid "Peripheral in use" @@ -1799,7 +1804,7 @@ msgstr "Izin ditolak" #: ports/stm/common-hal/alarm/pin/PinAlarm.c msgid "Pin cannot wake from Deep Sleep" -msgstr "" +msgstr "Pin tidak dapat membangunkan dari Deep Sleep" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Pin count too large" @@ -1843,7 +1848,7 @@ msgstr "Pin harus berbagi potongan PWM" #: shared-module/usb/core/Device.c msgid "Pipe error" -msgstr "" +msgstr "Kesalahan pipe" #: py/builtinhelp.c msgid "Plus any modules on the filesystem\n" @@ -1869,7 +1874,7 @@ msgstr "" #: main.c msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "" +msgstr "Berpura-pura deep sleep sampai alarm, CTRL-C atau penulisan file.\n" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" @@ -1889,7 +1894,7 @@ msgstr "Program terlalu lama" #: shared-bindings/rclcpy/Publisher.c msgid "Publishers can only be created from a parent node" -msgstr "" +msgstr "Publisher hanya dapat dibuat dari node induk" #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." @@ -1913,23 +1918,23 @@ msgstr "Kesalahan Init RNG" #: ports/espressif/common-hal/rclcpy/__init__.c msgid "ROS failed to initialize. Is agent connected?" -msgstr "" +msgstr "ROS gagal diinisialisasi. Apakah agen terhubung?" #: ports/espressif/common-hal/rclcpy/__init__.c msgid "ROS internal setup failure" -msgstr "" +msgstr "Kegagalan pengaturan internal ROS" #: ports/espressif/common-hal/rclcpy/__init__.c msgid "ROS memory allocator failure" -msgstr "" +msgstr "Kegagalan alokator memori ROS" #: ports/espressif/common-hal/rclcpy/Node.c msgid "ROS node failed to initialize" -msgstr "" +msgstr "Node ROS gagal diinisialisasi" #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "ROS topic failed to initialize" -msgstr "" +msgstr "Topik ROS gagal diinisialisasi" #: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c #: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c @@ -2003,18 +2008,18 @@ msgstr "Kartu SD Format CSD tidak didukung" #: ports/cxd56/common-hal/sdioio/SDCard.c msgid "SDCard init" -msgstr "" +msgstr "Inisialisasi SDCard" #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO GetCardInfo Error %d" -msgstr "" +msgstr "Kesalahan GetCardInfo SDIO %d" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO Init Error %x" -msgstr "" +msgstr "Kesalahan Init SDIO %x" #: ports/espressif/common-hal/busio/SPI.c msgid "SPI configuration failed" @@ -2022,7 +2027,7 @@ msgstr "Konfigurasi SPI gagal" #: ports/stm/common-hal/busio/SPI.c msgid "SPI init error" -msgstr "" +msgstr "Kesalahan inisialisasi SPI" #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" @@ -2030,7 +2035,7 @@ msgstr "Periferal SPI sedang digunakan" #: ports/stm/common-hal/busio/SPI.c msgid "SPI re-init" -msgstr "" +msgstr "Inisialisasi ulang SPI" #: shared-bindings/is31fl3741/FrameBuffer.c msgid "Scale dimensions must divide by 3" @@ -2146,7 +2151,7 @@ msgstr "Lebar ubin harus persis membagi lebar bitmap" #: shared-module/tilepalettemapper/TilePaletteMapper.c msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +msgstr "TilePaletteMapper hanya dapat diikat ke TileGrid sekali" #: shared-bindings/alarm/time/TimeAlarm.c msgid "Time is in the past." @@ -2197,12 +2202,12 @@ msgstr "Traceback (bagian terakhir dari panggilan terkini):\n" #: ports/stm/common-hal/busio/UART.c msgid "UART de-init" -msgstr "" +msgstr "De-inisialisasi UART" #: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c #: ports/stm/common-hal/busio/UART.c msgid "UART init" -msgstr "" +msgstr "Inisialisasi UART" #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" @@ -2210,11 +2215,11 @@ msgstr "Periferal UART sedang digunakan" #: ports/stm/common-hal/busio/UART.c msgid "UART re-init" -msgstr "" +msgstr "Inisialisasi ulang UART" #: ports/stm/common-hal/busio/UART.c msgid "UART write" -msgstr "" +msgstr "Penulisan UART" #: main.c msgid "UID:" @@ -2222,7 +2227,7 @@ msgstr "UID:" #: shared-module/usb_hid/Device.c msgid "USB busy" -msgstr "" +msgstr "USB sibuk" #: supervisor/shared/safe_mode.c msgid "USB devices need more endpoints than are available." @@ -2234,7 +2239,7 @@ msgstr "Perangkat USB menggunakan terlalu banyak nama antarmuka." #: shared-module/usb_hid/Device.c msgid "USB error" -msgstr "" +msgstr "Kesalahan USB" #: shared-bindings/_bleio/UUID.c msgid "UUID integer value must be 0-0xffff" @@ -2283,7 +2288,7 @@ msgstr "Tidak dapat membaca data palet warna" #: ports/mimxrt10xx/common-hal/canio/CAN.c msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" +msgstr "Tidak dapat mengirim Pesan CAN: semua buffer pesan Tx sibuk" #: ports/espressif/common-hal/mdns/Server.c #: ports/raspberrypi/common-hal/mdns/Server.c @@ -2373,7 +2378,7 @@ msgstr "" #: shared-bindings/bitmaptools/__init__.c msgid "Unsupported colorspace" -msgstr "" +msgstr "Colorspace tidak didukung" #: shared-module/displayio/bus_core.c msgid "Unsupported display bus type" @@ -2439,17 +2444,17 @@ msgstr "" #: supervisor/shared/web_workflow/web_workflow.c msgid "Wi-Fi: " -msgstr "" +msgstr "Wi-Fi: " #: ports/espressif/common-hal/wifi/Radio.c #: ports/raspberrypi/common-hal/wifi/Radio.c #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "WiFi is not enabled" -msgstr "" +msgstr "WiFi tidak diaktifkan" #: main.c msgid "Woken up by alarm.\n" -msgstr "" +msgstr "Dibangunkan oleh alarm.\n" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c @@ -2528,7 +2533,7 @@ msgstr "__init __() harus mengembalikan None" #: py/objtype.c #, c-format msgid "__init__() should return None, not '%s'" -msgstr "" +msgstr "__init__() harus mengembalikan None, bukan '%s'" #: py/objobject.c msgid "__new__ arg must be a user-type" @@ -2544,7 +2549,7 @@ msgstr "alamatnya kosong" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "already playing" -msgstr "" +msgstr "sudah diputar" #: py/compile.c msgid "annotation must be an identifier" @@ -2568,15 +2573,15 @@ msgstr "Argumen argsort harus berupa ndarray" #: extmod/ulab/code/numpy/numerical.c msgid "argsort is not implemented for flattened arrays" -msgstr "" +msgstr "argsort tidak diimplementasikan untuk array yang diratakan" #: extmod/ulab/code/numpy/random/random.c msgid "argument must be None, an integer or a tuple of integers" -msgstr "" +msgstr "argumen harus None, integer atau tuple integer" #: py/compile.c msgid "argument name reused" -msgstr "" +msgstr "nama argumen digunakan kembali" #: py/argcheck.c shared-bindings/_stage/__init__.c #: shared-bindings/digitalio/DigitalInOut.c @@ -2589,15 +2594,15 @@ msgstr "argumen harus berupa ndarrays" #: extmod/ulab/code/ndarray.c msgid "array and index length must be equal" -msgstr "" +msgstr "panjang array dan indeks harus sama" #: extmod/ulab/code/numpy/io/io.c msgid "array has too many dimensions" -msgstr "" +msgstr "array memiliki terlalu banyak dimensi" #: extmod/ulab/code/ndarray.c msgid "array is too big" -msgstr "" +msgstr "array terlalu besar" #: py/objarray.c shared-bindings/alarm/SleepMemory.c #: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c @@ -2606,15 +2611,15 @@ msgstr "diperlukan array/byte di sisi kanan" #: py/asmxtensa.c msgid "asm overflow" -msgstr "" +msgstr "asm overflow" #: py/compile.c msgid "async for/with outside async function" -msgstr "" +msgstr "async for/with di luar fungsi async" #: extmod/ulab/code/numpy/numerical.c msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "" +msgstr "percobaan untuk mendapatkan (arg)min/(arg)max dari urutan kosong" #: extmod/ulab/code/numpy/numerical.c msgid "attempt to get argmin/argmax of an empty sequence" @@ -2622,27 +2627,27 @@ msgstr "berusaha mendapatkan argmin/argmax dari urutan kosong" #: py/objstr.c msgid "attributes not supported" -msgstr "" +msgstr "atribut tidak didukung" #: ports/espressif/common-hal/audioio/AudioOut.c msgid "audio format not supported" -msgstr "" +msgstr "format audio tidak didukung" #: extmod/ulab/code/ulab_tools.c msgid "axis is out of bounds" -msgstr "" +msgstr "axis berada di luar batas" #: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c msgid "axis must be None, or an integer" -msgstr "" +msgstr "axis harus None, atau integer" #: extmod/ulab/code/numpy/numerical.c msgid "axis too long" -msgstr "" +msgstr "axis terlalu panjang" #: shared-bindings/bitmaptools/__init__.c msgid "background value out of range of target" -msgstr "" +msgstr "nilai latar belakang di luar jangkauan target" #: py/builtinevex.c msgid "bad compile mode" @@ -2654,7 +2659,7 @@ msgstr "specifier salah konversi" #: py/objstr.c msgid "bad format string" -msgstr "" +msgstr "string format salah" #: py/binary.c py/objarray.c msgid "bad typecode" @@ -2662,27 +2667,27 @@ msgstr "typecode buruk" #: py/emitnative.c msgid "binary op %q not implemented" -msgstr "" +msgstr "operasi biner %q tidak diimplementasikan" #: ports/espressif/common-hal/audiobusio/PDMIn.c msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" +msgstr "bit_depth harus 8, 16, 24, atau 32." #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" -msgstr "" +msgstr "ukuran dan kedalaman bitmap harus cocok" #: shared-bindings/bitmaptools/__init__.c msgid "bitmap sizes must match" -msgstr "" +msgstr "ukuran bitmap harus cocok" #: extmod/modrandom.c msgid "bits must be 32 or less" -msgstr "" +msgstr "bit harus 32 atau kurang" #: shared-bindings/audiofreeverb/Freeverb.c msgid "bits_per_sample must be 16" -msgstr "" +msgstr "bits_per_sample harus 16" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c #: shared-bindings/audiodelays/MultiTapDelay.c @@ -2691,19 +2696,19 @@ msgstr "" #: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c #: shared-bindings/audiomixer/Mixer.c msgid "bits_per_sample must be 8 or 16" -msgstr "" +msgstr "bits_per_sample harus 8 atau 16" #: py/emitinlinethumb.c msgid "branch not in range" -msgstr "" +msgstr "branch tidak dalam jangkauan" #: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c msgid "buffer is smaller than requested size" -msgstr "" +msgstr "buffer lebih kecil dari ukuran yang diminta" #: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c msgid "buffer size must be a multiple of element size" -msgstr "" +msgstr "ukuran buffer harus kelipatan dari ukuran elemen" #: shared-module/struct/__init__.c msgid "buffer size must match format" @@ -2711,27 +2716,27 @@ msgstr "ukuran buffer harus sesuai dengan format" #: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c msgid "buffer slices must be of equal length" -msgstr "" +msgstr "potongan buffer harus memiliki panjang yang sama" #: py/modstruct.c shared-module/struct/__init__.c msgid "buffer too small" -msgstr "" +msgstr "buffer terlalu kecil" #: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c msgid "buffer too small for requested bytes" -msgstr "" +msgstr "buffer terlalu kecil untuk byte yang diminta" #: py/emitbc.c msgid "bytecode overflow" -msgstr "" +msgstr "bytecode overflow" #: py/objarray.c msgid "bytes length not a multiple of item size" -msgstr "" +msgstr "panjang bytes bukan kelipatan dari ukuran item" #: py/objstr.c msgid "bytes value out of range" -msgstr "" +msgstr "nilai bytes di luar jangkauan" #: ports/atmel-samd/bindings/samd/Clock.c msgid "calibration is out of range" @@ -2744,7 +2749,7 @@ msgstr "kalibrasi adalah read only" #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" -msgstr "" +msgstr "hanya dapat memiliki satu induk" #: py/emitinlinethumb.c msgid "can only have up to 4 parameters to Thumb assembly" @@ -2752,15 +2757,15 @@ msgstr "hanya mampu memiliki hingga 4 parameter untuk Thumb assembly" #: py/emitinlinextensa.c msgid "can only have up to 4 parameters to Xtensa assembly" -msgstr "" +msgstr "hanya dapat memiliki hingga 4 parameter untuk assembly Xtensa" #: extmod/ulab/code/ndarray.c msgid "can only specify one unknown dimension" -msgstr "" +msgstr "hanya dapat menentukan satu dimensi yang tidak diketahui" #: py/objtype.c msgid "can't add special method to already-subclassed class" -msgstr "" +msgstr "tidak dapat menambahkan metode khusus ke kelas yang sudah di-subclass" #: py/compile.c msgid "can't assign to expression" @@ -2768,50 +2773,50 @@ msgstr "tidak dapat menetapkan ke ekspresi" #: extmod/modasyncio.c msgid "can't cancel self" -msgstr "" +msgstr "tidak dapat membatalkan diri sendiri" #: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c msgid "can't convert %q to %q" -msgstr "" +msgstr "tidak dapat mengonversi %q ke %q" #: py/obj.c #, c-format msgid "can't convert %s to complex" -msgstr "" +msgstr "tidak dapat mengonversi %s ke complex" #: py/obj.c #, c-format msgid "can't convert %s to float" -msgstr "" +msgstr "tidak dapat mengonversi %s ke float" #: py/objint.c py/runtime.c #, c-format msgid "can't convert %s to int" -msgstr "" +msgstr "tidak dapat mengonversi %s ke int" #: py/objstr.c msgid "can't convert '%q' object to %q implicitly" -msgstr "" +msgstr "tidak dapat mengonversi objek '%q' ke %q secara implisit" #: extmod/ulab/code/numpy/vector.c msgid "can't convert complex to float" -msgstr "" +msgstr "tidak dapat mengonversi complex ke float" #: py/obj.c msgid "can't convert to complex" -msgstr "" +msgstr "tidak dapat mengonversi ke complex" #: py/obj.c msgid "can't convert to float" -msgstr "" +msgstr "tidak dapat mengonversi ke float" #: py/runtime.c msgid "can't convert to int" -msgstr "" +msgstr "tidak dapat mengonversi ke int" #: py/objstr.c msgid "can't convert to str implicitly" -msgstr "" +msgstr "tidak dapat mengonversi ke str secara implisit" #: py/compile.c msgid "can't declare nonlocal in outer code" @@ -2823,93 +2828,95 @@ msgstr "tidak bisa menghapus ekspresi" #: py/emitnative.c msgid "can't do binary op between '%q' and '%q'" -msgstr "" +msgstr "tidak dapat melakukan operasi biner antara '%q' dan '%q'" #: py/emitnative.c msgid "can't do unary op of '%q'" -msgstr "" +msgstr "tidak dapat melakukan operasi unary dari '%q'" #: py/emitnative.c msgid "can't implicitly convert '%q' to 'bool'" -msgstr "" +msgstr "tidak dapat mengonversi '%q' ke 'bool' secara implisit" #: py/runtime.c msgid "can't import name %q" -msgstr "" +msgstr "tidak dapat mengimpor nama %q" #: py/emitnative.c msgid "can't load from '%q'" -msgstr "" +msgstr "tidak dapat memuat dari '%q'" #: py/emitnative.c msgid "can't load with '%q' index" -msgstr "" +msgstr "tidak dapat memuat dengan indeks '%q'" #: py/builtinimport.c msgid "can't perform relative import" -msgstr "" +msgstr "tidak dapat melakukan impor relatif" #: py/objgenerator.c msgid "can't send non-None value to a just-started generator" -msgstr "" +msgstr "tidak dapat mengirim nilai non-None ke generator yang baru dimulai" #: shared-module/sdcardio/SDCard.c msgid "can't set 512 block size" -msgstr "" +msgstr "tidak dapat mengatur ukuran blok 512" #: py/objexcept.c py/objnamedtuple.c msgid "can't set attribute" -msgstr "" +msgstr "tidak dapat mengatur atribut" #: py/runtime.c msgid "can't set attribute '%q'" -msgstr "" +msgstr "tidak dapat mengatur atribut '%q'" #: py/emitnative.c msgid "can't store '%q'" -msgstr "" +msgstr "tidak dapat menyimpan '%q'" #: py/emitnative.c msgid "can't store to '%q'" -msgstr "" +msgstr "tidak dapat menyimpan ke '%q'" #: py/emitnative.c msgid "can't store with '%q' index" -msgstr "" +msgstr "tidak dapat menyimpan dengan indeks '%q'" #: py/objstr.c msgid "" "can't switch from automatic field numbering to manual field specification" msgstr "" +"tidak dapat beralih dari penomoran field otomatis ke spesifikasi field manual" #: py/objstr.c msgid "" "can't switch from manual field specification to automatic field numbering" msgstr "" +"tidak dapat beralih dari spesifikasi field manual ke penomoran field otomatis" #: py/objcomplex.c msgid "can't truncate-divide a complex number" -msgstr "" +msgstr "tidak dapat truncate-divide bilangan complex" #: extmod/modasyncio.c msgid "can't wait" -msgstr "" +msgstr "tidak dapat menunggu" #: extmod/ulab/code/ndarray.c msgid "cannot assign new shape" -msgstr "" +msgstr "tidak dapat menetapkan bentuk baru" #: extmod/ulab/code/ndarray_operators.c msgid "cannot cast output with casting rule" -msgstr "" +msgstr "tidak dapat melakukan cast output dengan aturan casting" #: extmod/ulab/code/ndarray.c msgid "cannot convert complex to dtype" -msgstr "" +msgstr "tidak dapat mengonversi complex ke dtype" #: extmod/ulab/code/ndarray.c msgid "cannot convert complex type" -msgstr "" +msgstr "tidak dapat mengonversi tipe complex" #: py/objtype.c msgid "cannot create '%q' instances" @@ -2917,71 +2924,71 @@ msgstr "" #: py/objtype.c msgid "cannot create instance" -msgstr "" +msgstr "tidak dapat membuat instance" #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" -msgstr "" +msgstr "tidak dapat menghapus elemen array" #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" -msgstr "" +msgstr "tidak dapat membentuk ulang array" #: py/emitnative.c msgid "casting" -msgstr "" +msgstr "casting" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "channel re-init" -msgstr "" +msgstr "inisialisasi ulang channel" #: shared-bindings/_stage/Text.c msgid "chars buffer too small" -msgstr "" +msgstr "buffer chars terlalu kecil" #: py/modbuiltins.c msgid "chr() arg not in range(0x110000)" -msgstr "" +msgstr "argumen chr() tidak dalam rentang(0x110000)" #: py/modbuiltins.c msgid "chr() arg not in range(256)" -msgstr "" +msgstr "argumen chr() tidak dalam rentang(256)" #: shared-bindings/bitmaptools/__init__.c msgid "clip point must be (x,y) tuple" -msgstr "" +msgstr "clip point harus berupa tuple (x,y)" #: shared-bindings/msgpack/ExtType.c msgid "code outside range 0~127" -msgstr "" +msgstr "kode di luar rentang 0~127" #: shared-bindings/displayio/Palette.c msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" -msgstr "" +msgstr "buffer warna harus 3 byte (RGB) atau 4 byte (RGB + pad byte)" #: shared-bindings/displayio/Palette.c msgid "color buffer must be a buffer, tuple, list, or int" -msgstr "" +msgstr "buffer warna harus berupa buffer, tuple, list, atau int" #: shared-bindings/displayio/Palette.c msgid "color buffer must be a bytearray or array of type 'b' or 'B'" -msgstr "" +msgstr "buffer warna harus berupa bytearray atau array bertipe 'b' atau 'B'" #: shared-bindings/displayio/Palette.c msgid "color must be between 0x000000 and 0xffffff" -msgstr "" +msgstr "warna harus antara 0x000000 dan 0xffffff" #: py/emitnative.c msgid "comparison of int and uint" -msgstr "" +msgstr "perbandingan int dan uint" #: py/objcomplex.c msgid "complex divide by zero" -msgstr "" +msgstr "pembagian complex dengan nol" #: py/objfloat.c py/parsenum.c msgid "complex values not supported" -msgstr "" +msgstr "nilai complex tidak didukung" #: extmod/modzlib.c msgid "compression header" @@ -2989,56 +2996,56 @@ msgstr "kompresi header" #: py/emitnative.c msgid "conversion to object" -msgstr "" +msgstr "konversi ke objek" #: extmod/ulab/code/numpy/filter.c msgid "convolve arguments must be linear arrays" -msgstr "" +msgstr "argumen convolve harus berupa array linear" #: extmod/ulab/code/numpy/filter.c msgid "convolve arguments must be ndarrays" -msgstr "" +msgstr "argumen convolve harus berupa ndarray" #: extmod/ulab/code/numpy/filter.c msgid "convolve arguments must not be empty" -msgstr "" +msgstr "argumen convolve tidak boleh kosong" #: extmod/ulab/code/numpy/io/io.c msgid "corrupted file" -msgstr "" +msgstr "file rusak" #: extmod/ulab/code/numpy/poly.c msgid "could not invert Vandermonde matrix" -msgstr "" +msgstr "tidak dapat membalik matriks Vandermonde" #: shared-module/sdcardio/SDCard.c msgid "couldn't determine SD card version" -msgstr "" +msgstr "tidak dapat menentukan versi kartu SD" #: extmod/ulab/code/numpy/numerical.c msgid "cross is defined for 1D arrays of length 3" -msgstr "" +msgstr "cross didefinisikan untuk array 1D dengan panjang 3" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "data must be iterable" -msgstr "" +msgstr "data harus dapat diiterasi" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "data must be of equal length" -msgstr "" +msgstr "data harus memiliki panjang yang sama" #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "data pin #%d in use" -msgstr "" +msgstr "pin data #%d sedang digunakan" #: extmod/ulab/code/ndarray.c msgid "data type not understood" -msgstr "" +msgstr "tipe data tidak dipahami" #: py/parsenum.c msgid "decimal numbers not supported" -msgstr "" +msgstr "angka desimal tidak didukung" #: py/compile.c msgid "default 'except' must be last" @@ -3046,60 +3053,62 @@ msgstr "'except' standar harus terakhir" #: shared-bindings/msgpack/__init__.c msgid "default is not a function" -msgstr "" +msgstr "default bukan fungsi" #: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" +"buffer tujuan harus berupa bytearray atau array bertipe 'B' untuk bit_depth " +"= 8" #: shared-bindings/audiobusio/PDMIn.c msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" +msgstr "buffer tujuan harus berupa array bertipe 'H' untuk bit_depth = 16" #: py/objdict.c msgid "dict update sequence has wrong length" -msgstr "" +msgstr "urutan pembaruan dict memiliki panjang yang salah" #: extmod/ulab/code/numpy/numerical.c msgid "diff argument must be an ndarray" -msgstr "" +msgstr "argumen diff harus berupa ndarray" #: extmod/ulab/code/numpy/numerical.c msgid "differentiation order out of range" -msgstr "" +msgstr "urutan diferensiasi di luar jangkauan" #: extmod/ulab/code/numpy/transform.c msgid "dimensions do not match" -msgstr "" +msgstr "dimensi tidak cocok" #: py/emitnative.c msgid "div/mod not implemented for uint" -msgstr "" +msgstr "div/mod tidak diimplementasikan untuk uint" #: extmod/ulab/code/numpy/create.c msgid "divide by zero" -msgstr "" +msgstr "pembagian dengan nol" #: py/runtime.c msgid "division by zero" -msgstr "" +msgstr "pembagian dengan nol" #: extmod/ulab/code/numpy/vector.c msgid "dtype must be float, or complex" -msgstr "" +msgstr "dtype harus float, atau complex" #: extmod/ulab/code/ndarray_operators.c msgid "dtype of int32 is not supported" -msgstr "" +msgstr "dtype int32 tidak didukung" #: py/objdeque.c msgid "empty" -msgstr "" +msgstr "kosong" #: extmod/ulab/code/numpy/io/io.c msgid "empty file" -msgstr "" +msgstr "file kosong" #: extmod/modasyncio.c extmod/modheapq.c msgid "empty heap" @@ -3107,19 +3116,19 @@ msgstr "heap kosong" #: py/objstr.c msgid "empty separator" -msgstr "" +msgstr "pemisah kosong" #: shared-bindings/random/__init__.c msgid "empty sequence" -msgstr "" +msgstr "urutan kosong" #: py/objstr.c msgid "end of format while looking for conversion specifier" -msgstr "" +msgstr "akhir format saat mencari spesifier konversi" #: shared-bindings/alarm/time/TimeAlarm.c msgid "epoch_time not supported on this board" -msgstr "" +msgstr "epoch_time tidak didukung pada board ini" #: ports/nordic/common-hal/busio/UART.c #, c-format @@ -3128,19 +3137,19 @@ msgstr "error = 0x%08lX" #: py/runtime.c msgid "exceptions must derive from BaseException" -msgstr "" +msgstr "exception harus diturunkan dari BaseException" #: py/objstr.c msgid "expected ':' after format specifier" -msgstr "" +msgstr "mengharapkan ':' setelah spesifier format" #: py/obj.c msgid "expected tuple/list" -msgstr "" +msgstr "mengharapkan tuple/list" #: py/modthread.c msgid "expecting a dict for keyword args" -msgstr "" +msgstr "mengharapkan dict untuk argumen keyword" #: py/compile.c msgid "expecting an assembler instruction" @@ -3156,7 +3165,7 @@ msgstr "key:value diharapkan untuk dict" #: shared-bindings/msgpack/__init__.c msgid "ext_hook is not a function" -msgstr "" +msgstr "ext_hook bukan fungsi" #: py/argcheck.c msgid "extra keyword arguments given" @@ -3170,11 +3179,11 @@ msgstr "argumen posisi ekstra telah diberikan" #: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c #: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c msgid "file must be a file opened in byte mode" -msgstr "" +msgstr "file harus berupa file yang dibuka dalam mode byte" #: shared-bindings/traceback/__init__.c msgid "file write is not available" -msgstr "" +msgstr "penulisan file tidak tersedia" #: shared-bindings/storage/__init__.c msgid "filesystem must provide mount method" @@ -3182,63 +3191,63 @@ msgstr "" #: extmod/ulab/code/numpy/vector.c msgid "first argument must be a callable" -msgstr "" +msgstr "argumen pertama harus dapat dipanggil" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "first argument must be a function" -msgstr "" +msgstr "argumen pertama harus berupa fungsi" #: extmod/ulab/code/numpy/create.c msgid "first argument must be a tuple of ndarrays" -msgstr "" +msgstr "argumen pertama harus berupa tuple ndarray" #: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c msgid "first argument must be an ndarray" -msgstr "" +msgstr "argumen pertama harus berupa ndarray" #: py/objtype.c msgid "first argument to super() must be type" -msgstr "" +msgstr "argumen pertama untuk super() harus bertipe type" #: extmod/ulab/code/scipy/linalg/linalg.c msgid "first two arguments must be ndarrays" -msgstr "" +msgstr "dua argumen pertama harus berupa ndarray" #: extmod/ulab/code/ndarray.c msgid "flattening order must be either 'C', or 'F'" -msgstr "" +msgstr "urutan perataan harus 'C', atau 'F'" #: extmod/ulab/code/numpy/numerical.c msgid "flip argument must be an ndarray" -msgstr "" +msgstr "argumen flip harus berupa ndarray" #: py/objint.c msgid "float too big" -msgstr "" +msgstr "float terlalu besar" #: py/nativeglue.c msgid "float unsupported" -msgstr "" +msgstr "float tidak didukung" #: shared-bindings/_stage/Text.c msgid "font must be 2048 bytes long" -msgstr "" +msgstr "font harus sepanjang 2048 byte" #: extmod/moddeflate.c msgid "format" -msgstr "" +msgstr "format" #: py/objstr.c msgid "format needs a dict" -msgstr "" +msgstr "format memerlukan dict" #: py/objdeque.c msgid "full" -msgstr "" +msgstr "penuh" #: py/argcheck.c msgid "function doesn't take keyword arguments" -msgstr "" +msgstr "fungsi tidak menerima argumen keyword" #: py/argcheck.c #, c-format @@ -3251,15 +3260,15 @@ msgstr "fungsi mendapatkan nilai ganda untuk argumen '%q'" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "function has the same sign at the ends of interval" -msgstr "" +msgstr "fungsi memiliki tanda yang sama pada ujung interval" #: extmod/ulab/code/ndarray.c msgid "function is defined for ndarrays only" -msgstr "" +msgstr "fungsi didefinisikan hanya untuk ndarray" #: extmod/ulab/code/numpy/carray/carray.c msgid "function is implemented for ndarrays only" -msgstr "" +msgstr "fungsi diimplementasikan hanya untuk ndarray" #: py/argcheck.c #, c-format @@ -3287,23 +3296,23 @@ msgstr "fungsi mengambil posisi argumen %d tapi %d yang diberikan" #: py/objgenerator.c msgid "generator already executing" -msgstr "" +msgstr "generator sudah berjalan" #: py/objgenerator.c msgid "generator ignored GeneratorExit" -msgstr "" +msgstr "generator mengabaikan GeneratorExit" #: py/objgenerator.c py/runtime.c msgid "generator raised StopIteration" -msgstr "" +msgstr "generator memunculkan StopIteration" #: shared-bindings/_stage/Layer.c msgid "graphic must be 2048 bytes long" -msgstr "" +msgstr "grafik harus sepanjang 2048 byte" #: extmod/modhashlib.c msgid "hash is final" -msgstr "" +msgstr "hash bersifat final" #: extmod/modheapq.c msgid "heap must be a list" @@ -3319,23 +3328,23 @@ msgstr "identifier didefinisi ulang sebagai nonlocal" #: py/compile.c msgid "import * not at module level" -msgstr "" +msgstr "import * tidak pada tingkat modul" #: py/persistentcode.c msgid "incompatible .mpy arch" -msgstr "" +msgstr "arsitektur .mpy tidak kompatibel" #: py/persistentcode.c msgid "incompatible .mpy file" -msgstr "" +msgstr "file .mpy tidak kompatibel" #: py/objstr.c msgid "incomplete format" -msgstr "" +msgstr "format tidak lengkap" #: py/objstr.c msgid "incomplete format key" -msgstr "" +msgstr "kunci format tidak lengkap" #: extmod/modbinascii.c msgid "incorrect padding" @@ -3343,11 +3352,11 @@ msgstr "lapisan (padding) tidak benar" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c msgid "index is out of bounds" -msgstr "" +msgstr "indeks berada di luar batas" #: shared-bindings/_pixelmap/PixelMap.c msgid "index must be tuple or int" -msgstr "" +msgstr "indeks harus berupa tuple atau int" #: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c #: ports/espressif/common-hal/pulseio/PulseIn.c @@ -3357,19 +3366,19 @@ msgstr "index keluar dari jangkauan" #: py/obj.c msgid "indices must be integers" -msgstr "" +msgstr "indeks harus berupa integer" #: extmod/ulab/code/ndarray.c msgid "indices must be integers, slices, or Boolean lists" -msgstr "" +msgstr "indeks harus berupa integer, slice, atau list Boolean" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "initial values must be iterable" -msgstr "" +msgstr "nilai awal harus dapat diiterasi" #: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c msgid "initial_value length is wrong" -msgstr "" +msgstr "panjang initial_value salah" #: py/compile.c msgid "inline assembler must be a function" @@ -3377,98 +3386,98 @@ msgstr "inline assembler harus sebuah fungsi" #: extmod/ulab/code/numpy/vector.c msgid "input and output dimensions differ" -msgstr "" +msgstr "dimensi input dan output berbeda" #: extmod/ulab/code/numpy/vector.c msgid "input and output shapes differ" -msgstr "" +msgstr "bentuk input dan output berbeda" #: extmod/ulab/code/numpy/create.c msgid "input argument must be an integer, a tuple, or a list" -msgstr "" +msgstr "argumen input harus berupa integer, tuple, atau list" #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "input array length must be power of 2" -msgstr "" +msgstr "panjang array input harus pangkat 2" #: extmod/ulab/code/numpy/create.c msgid "input arrays are not compatible" -msgstr "" +msgstr "array input tidak kompatibel" #: extmod/ulab/code/numpy/poly.c msgid "input data must be an iterable" -msgstr "" +msgstr "data input harus dapat diiterasi" #: extmod/ulab/code/numpy/vector.c msgid "input dtype must be float or complex" -msgstr "" +msgstr "dtype input harus float atau complex" #: extmod/ulab/code/numpy/poly.c msgid "input is not iterable" -msgstr "" +msgstr "input tidak dapat diiterasi" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "input matrix is asymmetric" -msgstr "" +msgstr "matriks input asimetris" #: extmod/ulab/code/numpy/linalg/linalg.c #: extmod/ulab/code/scipy/linalg/linalg.c msgid "input matrix is singular" -msgstr "" +msgstr "matriks input singular" #: extmod/ulab/code/numpy/create.c msgid "input must be 1- or 2-d" -msgstr "" +msgstr "input harus 1- atau 2-d" #: extmod/ulab/code/numpy/carray/carray.c msgid "input must be a 1D ndarray" -msgstr "" +msgstr "input harus berupa ndarray 1D" #: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c msgid "input must be a dense ndarray" -msgstr "" +msgstr "input harus berupa ndarray padat" #: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c msgid "input must be an ndarray" -msgstr "" +msgstr "input harus berupa ndarray" #: extmod/ulab/code/numpy/carray/carray.c msgid "input must be an ndarray, or a scalar" -msgstr "" +msgstr "input harus berupa ndarray, atau skalar" #: extmod/ulab/code/scipy/signal/signal.c msgid "input must be one-dimensional" -msgstr "" +msgstr "input harus satu dimensi" #: extmod/ulab/code/ulab_tools.c msgid "input must be square matrix" -msgstr "" +msgstr "input harus berupa matriks persegi" #: extmod/ulab/code/numpy/numerical.c msgid "input must be tuple, list, range, or ndarray" -msgstr "" +msgstr "input harus berupa tuple, list, range, atau ndarray" #: extmod/ulab/code/numpy/poly.c msgid "input vectors must be of equal length" -msgstr "" +msgstr "vektor input harus memiliki panjang yang sama" #: extmod/ulab/code/numpy/approx.c msgid "interp is defined for 1D iterables of equal length" -msgstr "" +msgstr "interp didefinisikan untuk iterable 1D dengan panjang yang sama" #: shared-bindings/_bleio/Adapter.c #, c-format msgid "interval must be in range %s-%s" -msgstr "" +msgstr "interval harus dalam rentang %s-%s" #: py/compile.c msgid "invalid arch" -msgstr "" +msgstr "arsitektur tidak valid" #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" -msgstr "" +msgstr "bits_per_pixel %d tidak valid, harus 1, 2, 4, 8, 16, 24, atau 32" #: shared-module/ssl/SSLSocket.c msgid "invalid cert" @@ -3477,24 +3486,24 @@ msgstr "cert tidak valid" #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" -msgstr "" +msgstr "element size %d tidak valid untuk bits_per_pixel %d\n" #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element_size %d, must be, 1, 2, or 4" -msgstr "" +msgstr "element_size %d tidak valid, harus 1, 2, atau 4" #: shared-bindings/traceback/__init__.c msgid "invalid exception" -msgstr "" +msgstr "exception tidak valid" #: py/objstr.c msgid "invalid format specifier" -msgstr "" +msgstr "spesifier format tidak valid" #: shared-bindings/wifi/Radio.c msgid "invalid hostname" -msgstr "" +msgstr "hostname tidak valid" #: shared-module/ssl/SSLSocket.c msgid "invalid key" @@ -3506,11 +3515,11 @@ msgstr "micropython decorator tidak valid" #: ports/espressif/common-hal/espcamera/Camera.c msgid "invalid setting" -msgstr "" +msgstr "pengaturan tidak valid" #: shared-bindings/random/__init__.c msgid "invalid step" -msgstr "" +msgstr "step tidak valid" #: py/compile.c py/parse.c msgid "invalid syntax" @@ -3518,40 +3527,42 @@ msgstr "syntax tidak valid" #: py/parsenum.c msgid "invalid syntax for integer" -msgstr "" +msgstr "sintaks tidak valid untuk integer" #: py/parsenum.c #, c-format msgid "invalid syntax for integer with base %d" -msgstr "" +msgstr "sintaks tidak valid untuk integer dengan basis %d" #: py/parsenum.c msgid "invalid syntax for number" -msgstr "" +msgstr "sintaks tidak valid untuk angka" #: py/objtype.c msgid "issubclass() arg 1 must be a class" -msgstr "" +msgstr "argumen 1 issubclass() harus berupa class" #: py/objtype.c msgid "issubclass() arg 2 must be a class or a tuple of classes" -msgstr "" +msgstr "argumen 2 issubclass() harus berupa class atau tuple class" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "iterations did not converge" -msgstr "" +msgstr "iterasi tidak konvergen" #: py/objstr.c msgid "join expects a list of str/bytes objects consistent with self object" -msgstr "" +msgstr "join mengharapkan list objek str/bytes yang konsisten dengan objek self" #: py/argcheck.c msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" +"argumen keyword tidak diimplementasikan - gunakan argumen normal sebagai " +"gantinya" #: py/emitinlinethumb.c py/emitinlinextensa.c msgid "label '%q' not defined" -msgstr "" +msgstr "label '%q' tidak didefinisikan" #: py/compile.c msgid "label redefined" @@ -3559,101 +3570,101 @@ msgstr "label didefinis ulang" #: py/objarray.c msgid "lhs and rhs should be compatible" -msgstr "" +msgstr "lhs dan rhs harus kompatibel" #: py/emitnative.c msgid "local '%q' has type '%q' but source is '%q'" -msgstr "" +msgstr "lokal '%q' memiliki tipe '%q' tetapi sumber adalah '%q'" #: py/emitnative.c msgid "local '%q' used before type known" -msgstr "" +msgstr "lokal '%q' digunakan sebelum tipe diketahui" #: py/vm.c msgid "local variable referenced before assignment" -msgstr "" +msgstr "variabel lokal direferensikan sebelum penetapan" #: ports/espressif/common-hal/canio/CAN.c msgid "loopback + silent mode not supported by peripheral" -msgstr "" +msgstr "mode loopback + silent tidak didukung oleh periferal" #: ports/espressif/common-hal/mdns/Server.c #: ports/raspberrypi/common-hal/mdns/Server.c msgid "mDNS already initialized" -msgstr "" +msgstr "mDNS sudah diinisialisasi" #: ports/espressif/common-hal/mdns/Server.c #: ports/raspberrypi/common-hal/mdns/Server.c msgid "mDNS only works with built-in WiFi" -msgstr "" +msgstr "mDNS hanya bekerja dengan WiFi bawaan" #: py/parse.c msgid "malformed f-string" -msgstr "" +msgstr "f-string salah bentuk" #: shared-bindings/_stage/Layer.c msgid "map buffer too small" -msgstr "" +msgstr "buffer peta terlalu kecil" #: py/modmath.c shared-bindings/math/__init__.c msgid "math domain error" -msgstr "" +msgstr "kesalahan domain matematika" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "matrix is not positive definite" -msgstr "" +msgstr "matriks tidak definit positif" #: ports/espressif/common-hal/_bleio/Descriptor.c #: ports/nordic/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Descriptor.c #, c-format msgid "max_length must be 0-%d when fixed_length is %s" -msgstr "" +msgstr "max_length harus 0-%d ketika fixed_length adalah %s" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c msgid "maximum number of dimensions is " -msgstr "" +msgstr "jumlah maksimum dimensi adalah " #: py/runtime.c msgid "maximum recursion depth exceeded" -msgstr "" +msgstr "kedalaman rekursi maksimum terlampaui" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "maxiter must be > 0" -msgstr "" +msgstr "maxiter harus > 0" #: extmod/ulab/code/scipy/optimize/optimize.c msgid "maxiter should be > 0" -msgstr "" +msgstr "maxiter harus > 0" #: extmod/ulab/code/numpy/numerical.c msgid "median argument must be an ndarray" -msgstr "" +msgstr "argumen median harus berupa ndarray" #: py/runtime.c #, c-format msgid "memory allocation failed, allocating %u bytes" -msgstr "" +msgstr "alokasi memori gagal, mengalokasikan %u byte" #: py/runtime.c msgid "memory allocation failed, heap is locked" -msgstr "" +msgstr "alokasi memori gagal, heap terkunci" #: py/objarray.c msgid "memoryview offset too large" -msgstr "" +msgstr "offset memoryview terlalu besar" #: py/objarray.c msgid "memoryview: length is not a multiple of itemsize" -msgstr "" +msgstr "memoryview: panjang bukan kelipatan dari itemsize" #: extmod/modtime.c msgid "mktime needs a tuple of length 8 or 9" -msgstr "" +msgstr "mktime memerlukan tuple dengan panjang 8 atau 9" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "mode must be complete, or reduced" -msgstr "" +msgstr "mode harus complete, atau reduced" #: py/builtinimport.c msgid "module not found" @@ -3661,11 +3672,11 @@ msgstr "modul tidak ditemukan" #: ports/espressif/common-hal/wifi/Monitor.c msgid "monitor init failed" -msgstr "" +msgstr "inisialisasi monitor gagal" #: extmod/ulab/code/numpy/poly.c msgid "more degrees of freedom than data points" -msgstr "" +msgstr "lebih banyak derajat kebebasan daripada titik data" #: py/compile.c msgid "multiple *x in assignment" @@ -3673,76 +3684,76 @@ msgstr "perkalian *x dalam assignment" #: py/objtype.c msgid "multiple bases have instance lay-out conflict" -msgstr "" +msgstr "beberapa basis memiliki konflik tata letak instance" #: py/objtype.c msgid "multiple inheritance not supported" -msgstr "" +msgstr "pewarisan berganda tidak didukung" #: py/emitnative.c msgid "must raise an object" -msgstr "" +msgstr "harus memunculkan objek" #: py/modbuiltins.c msgid "must use keyword argument for key function" -msgstr "" +msgstr "harus menggunakan argumen keyword untuk fungsi kunci" #: py/runtime.c msgid "name '%q' isn't defined" -msgstr "" +msgstr "nama '%q' tidak didefinisikan" #: py/runtime.c msgid "name not defined" -msgstr "" +msgstr "nama tidak didefinisikan" #: py/qstr.c msgid "name too long" -msgstr "" +msgstr "nama terlalu panjang" #: py/persistentcode.c msgid "native code in .mpy unsupported" -msgstr "" +msgstr "kode native dalam .mpy tidak didukung" #: py/asmthumb.c msgid "native method too big" -msgstr "" +msgstr "metode native terlalu besar" #: py/emitnative.c msgid "native yield" -msgstr "" +msgstr "yield native" #: extmod/ulab/code/ndarray.c msgid "ndarray length overflows" -msgstr "" +msgstr "panjang ndarray meluap" #: py/runtime.c #, c-format msgid "need more than %d values to unpack" -msgstr "" +msgstr "memerlukan lebih dari %d nilai untuk membongkar" #: py/modmath.c msgid "negative factorial" -msgstr "" +msgstr "faktorial negatif" #: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative power with no float support" -msgstr "" +msgstr "pangkat negatif tanpa dukungan float" #: py/objint_mpz.c py/runtime.c msgid "negative shift count" -msgstr "" +msgstr "jumlah shift negatif" #: shared-bindings/_pixelmap/PixelMap.c msgid "nested index must be int" -msgstr "" +msgstr "indeks bersarang harus int" #: shared-module/sdcardio/SDCard.c msgid "no SD card" -msgstr "" +msgstr "tidak ada kartu SD" #: py/vm.c msgid "no active exception to reraise" -msgstr "" +msgstr "tidak ada exception aktif untuk dimunculkan kembali" #: py/compile.c msgid "no binding for nonlocal found" @@ -3750,11 +3761,11 @@ msgstr "tidak ada ikatan/bind pada temuan nonlocal" #: shared-module/msgpack/__init__.c msgid "no default packer" -msgstr "" +msgstr "tidak ada packer default" #: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c msgid "no default seed" -msgstr "" +msgstr "tidak ada seed default" #: py/builtinimport.c msgid "no module named '%q'" @@ -3762,16 +3773,16 @@ msgstr "tidak ada modul yang bernama '%q'" #: shared-module/sdcardio/SDCard.c msgid "no response from SD card" -msgstr "" +msgstr "tidak ada respons dari kartu SD" #: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c msgid "no such attribute" -msgstr "" +msgstr "atribut tidak ada" #: ports/espressif/common-hal/_bleio/Connection.c #: ports/nordic/common-hal/_bleio/Connection.c msgid "non-UUID found in service_uuids_whitelist" -msgstr "" +msgstr "non-UUID ditemukan dalam service_uuids_whitelist" #: py/compile.c msgid "non-default argument follows default argument" @@ -3783,19 +3794,19 @@ msgstr "digit non-hex ditemukan" #: ports/nordic/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" -msgstr "" +msgstr "timeout non-nol harus > 0.01" #: shared-bindings/_bleio/Adapter.c msgid "non-zero timeout must be >= interval" -msgstr "" +msgstr "timeout non-nol harus >= interval" #: shared-bindings/_bleio/UUID.c msgid "not a 128-bit UUID" -msgstr "" +msgstr "bukan UUID 128-bit" #: py/parse.c msgid "not a constant" -msgstr "" +msgstr "bukan konstanta" #: py/objstr.c msgid "not all arguments converted during string formatting" @@ -3807,65 +3818,65 @@ msgstr "" #: extmod/ulab/code/numpy/carray/carray_tools.c msgid "not implemented for complex dtype" -msgstr "" +msgstr "tidak diimplementasikan untuk dtype complex" #: extmod/ulab/code/numpy/bitwise.c msgid "not supported for input types" -msgstr "" +msgstr "tidak didukung untuk tipe input" #: extmod/ulab/code/numpy/create.c msgid "number of points must be at least 2" -msgstr "" +msgstr "jumlah titik harus setidaknya 2" #: py/builtinhelp.c msgid "object " -msgstr "" +msgstr "objek " #: py/obj.c #, c-format msgid "object '%s' isn't a tuple or list" -msgstr "" +msgstr "objek '%s' bukan tuple atau list" #: py/obj.c msgid "object doesn't support item assignment" -msgstr "" +msgstr "objek tidak mendukung penetapan item" #: py/obj.c msgid "object doesn't support item deletion" -msgstr "" +msgstr "objek tidak mendukung penghapusan item" #: py/obj.c msgid "object has no len" -msgstr "" +msgstr "objek tidak memiliki len" #: py/obj.c msgid "object isn't subscriptable" -msgstr "" +msgstr "objek tidak dapat disubskripsikan" #: py/runtime.c msgid "object not an iterator" -msgstr "" +msgstr "objek bukan iterator" #: py/objtype.c py/runtime.c msgid "object not callable" -msgstr "" +msgstr "objek tidak dapat dipanggil" #: py/sequence.c shared-bindings/displayio/Group.c msgid "object not in sequence" -msgstr "" +msgstr "objek tidak dalam urutan" #: py/runtime.c msgid "object not iterable" -msgstr "" +msgstr "objek tidak dapat diiterasi" #: py/obj.c #, c-format msgid "object of type '%s' has no len()" -msgstr "" +msgstr "objek bertipe '%s' tidak memiliki len()" #: py/obj.c msgid "object with buffer protocol required" -msgstr "" +msgstr "objek dengan protokol buffer diperlukan" #: py/objstr.c msgid "odd-length string" @@ -3873,146 +3884,146 @@ msgstr "panjang data string memiliki keganjilan (odd-length)" #: supervisor/shared/web_workflow/web_workflow.c msgid "off" -msgstr "" +msgstr "mati" #: extmod/ulab/code/utils/utils.c msgid "offset is too large" -msgstr "" +msgstr "offset terlalu besar" #: shared-bindings/dualbank/__init__.c msgid "offset must be >= 0" -msgstr "" +msgstr "offset harus >= 0" #: extmod/ulab/code/numpy/create.c msgid "offset must be non-negative and no greater than buffer length" -msgstr "" +msgstr "offset harus non-negatif dan tidak lebih besar dari panjang buffer" #: ports/nordic/common-hal/audiobusio/PDMIn.c #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only bit_depth=16 is supported" -msgstr "" +msgstr "hanya bit_depth=16 yang didukung" #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only mono is supported" -msgstr "" +msgstr "hanya mono yang didukung" #: extmod/ulab/code/numpy/create.c msgid "only ndarrays can be concatenated" -msgstr "" +msgstr "hanya ndarray yang dapat digabungkan" #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only oversample=64 is supported" -msgstr "" +msgstr "hanya oversample=64 yang didukung" #: ports/nordic/common-hal/audiobusio/PDMIn.c #: ports/stm/common-hal/audiobusio/PDMIn.c msgid "only sample_rate=16000 is supported" -msgstr "" +msgstr "hanya sample_rate=16000 yang didukung" #: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c #: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c #: shared-bindings/nvm/ByteArray.c msgid "only slices with step=1 (aka None) are supported" -msgstr "" +msgstr "hanya slice dengan step=1 (alias None) yang didukung" #: py/vm.c msgid "opcode" -msgstr "" +msgstr "opcode" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c #: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c msgid "operands could not be broadcast together" -msgstr "" +msgstr "operan tidak dapat di-broadcast bersama" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "operation is defined for 2D arrays only" -msgstr "" +msgstr "operasi didefinisikan hanya untuk array 2D" #: extmod/ulab/code/numpy/linalg/linalg.c msgid "operation is defined for ndarrays only" -msgstr "" +msgstr "operasi didefinisikan hanya untuk ndarray" #: extmod/ulab/code/ndarray.c msgid "operation is implemented for 1D Boolean arrays only" -msgstr "" +msgstr "operasi diimplementasikan hanya untuk array Boolean 1D" #: extmod/ulab/code/numpy/numerical.c msgid "operation is not implemented on ndarrays" -msgstr "" +msgstr "operasi tidak diimplementasikan pada ndarray" #: extmod/ulab/code/ndarray.c msgid "operation is not supported for given type" -msgstr "" +msgstr "operasi tidak didukung untuk tipe yang diberikan" #: extmod/ulab/code/ndarray_operators.c msgid "operation not supported for the input types" -msgstr "" +msgstr "operasi tidak didukung untuk tipe input" #: py/modbuiltins.c msgid "ord expects a character" -msgstr "" +msgstr "ord mengharapkan karakter" #: py/modbuiltins.c #, c-format msgid "ord() expected a character, but string of length %d found" -msgstr "" +msgstr "ord() mengharapkan karakter, tetapi string dengan panjang %d ditemukan" #: extmod/ulab/code/utils/utils.c msgid "out array is too small" -msgstr "" +msgstr "array out terlalu kecil" #: extmod/ulab/code/numpy/random/random.c msgid "out has wrong type" -msgstr "" +msgstr "out memiliki tipe yang salah" #: extmod/ulab/code/numpy/vector.c msgid "out keyword is not supported for complex dtype" -msgstr "" +msgstr "keyword out tidak didukung untuk dtype complex" #: extmod/ulab/code/numpy/vector.c msgid "out keyword is not supported for function" -msgstr "" +msgstr "keyword out tidak didukung untuk fungsi" #: extmod/ulab/code/utils/utils.c msgid "out must be a float dense array" -msgstr "" +msgstr "out harus berupa array padat float" #: extmod/ulab/code/numpy/vector.c msgid "out must be an ndarray" -msgstr "" +msgstr "out harus berupa ndarray" #: extmod/ulab/code/numpy/vector.c msgid "out must be of float dtype" -msgstr "" +msgstr "out harus bertipe dtype float" #: shared-bindings/bitmaptools/__init__.c msgid "out of range of target" -msgstr "" +msgstr "di luar jangkauan target" #: extmod/ulab/code/numpy/random/random.c msgid "output array has wrong type" -msgstr "" +msgstr "array output memiliki tipe yang salah" #: extmod/ulab/code/numpy/random/random.c msgid "output array must be contiguous" -msgstr "" +msgstr "array output harus berdekatan" #: py/objint_mpz.c msgid "overflow converting long int to machine word" -msgstr "" +msgstr "overflow saat mengonversi long int ke machine word" #: py/modstruct.c #, c-format msgid "pack expected %d items for packing (got %d)" -msgstr "" +msgstr "pack mengharapkan %d item untuk packing (mendapat %d)" #: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c msgid "palette must be 32 bytes long" -msgstr "" +msgstr "palet harus sepanjang 32 byte" #: py/emitinlinextensa.c msgid "parameters must be registers in sequence a2 to a5" -msgstr "" +msgstr "parameter harus berupa register dalam urutan a2 hingga a5" #: py/emitinlinethumb.c msgid "parameters must be registers in sequence r0 to r3" @@ -4020,7 +4031,7 @@ msgstr "parameter harus menjadi register dalam urutan r0 sampai r3" #: extmod/vfs_posix_file.c msgid "poll on file not available on win32" -msgstr "" +msgstr "poll pada file tidak tersedia di win32" #: ports/espressif/common-hal/pulseio/PulseIn.c msgid "pop from an empty PulseIn" @@ -4033,31 +4044,31 @@ msgstr "Muncul dari PulseIn yang kosong" #: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c #: shared-bindings/ps2io/Ps2.c msgid "pop from empty %q" -msgstr "" +msgstr "pop dari %q kosong" #: shared-bindings/socketpool/Socket.c msgid "port must be >= 0" -msgstr "" +msgstr "port harus >= 0" #: py/compile.c msgid "positional arg after **" -msgstr "" +msgstr "argumen posisional setelah **" #: py/compile.c msgid "positional arg after keyword arg" -msgstr "" +msgstr "argumen posisional setelah argumen keyword" #: py/objint_mpz.c msgid "pow() 3rd argument cannot be 0" -msgstr "" +msgstr "argumen ketiga pow() tidak boleh 0" #: py/objint_mpz.c msgid "pow() with 3 arguments requires integers" -msgstr "" +msgstr "pow() dengan 3 argumen memerlukan integer" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "pull masks conflict with direction masks" -msgstr "" +msgstr "mask pull berkonflik dengan mask arah" #: py/parse.c msgid "raw f-strings are not supported" @@ -4065,7 +4076,7 @@ msgstr "" #: extmod/ulab/code/numpy/fft/fft_tools.c msgid "real and imaginary parts must be of equal length" -msgstr "" +msgstr "bagian real dan imajiner harus memiliki panjang yang sama" #: py/builtinimport.c msgid "relative import" @@ -4074,11 +4085,11 @@ msgstr "impor relatif" #: py/obj.c #, c-format msgid "requested length %d but object has length %d" -msgstr "" +msgstr "panjang yang diminta %d tetapi objek memiliki panjang %d" #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" -msgstr "" +msgstr "hasil tidak dapat di-cast ke tipe yang ditentukan" #: py/compile.c msgid "return annotation must be an identifier" @@ -4086,29 +4097,29 @@ msgstr "anotasi return harus sebuah identifier" #: py/emitnative.c msgid "return expected '%q' but got '%q'" -msgstr "" +msgstr "return mengharapkan '%q' tetapi mendapat '%q'" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format msgid "rgb_pins[%d] duplicates another pin assignment" -msgstr "" +msgstr "rgb_pins[%d] menduplikasi penetapan pin lain" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format msgid "rgb_pins[%d] is not on the same port as clock" -msgstr "" +msgstr "rgb_pins[%d] tidak pada port yang sama dengan clock" #: extmod/ulab/code/numpy/numerical.c msgid "roll argument must be an ndarray" -msgstr "" +msgstr "argumen roll harus berupa ndarray" #: py/objstr.c msgid "rsplit(None,n)" -msgstr "" +msgstr "rsplit(None,n)" #: shared-bindings/audiofreeverb/Freeverb.c msgid "samples_signed must be true" -msgstr "" +msgstr "samples_signed harus true" #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c @@ -4117,7 +4128,7 @@ msgstr "nilai sampling keluar dari jangkauan" #: py/modmicropython.c msgid "schedule queue full" -msgstr "" +msgstr "antrian jadwal penuh" #: py/builtinimport.c msgid "script compilation not supported" @@ -4125,43 +4136,43 @@ msgstr "kompilasi script tidak didukung" #: py/nativeglue.c msgid "set unsupported" -msgstr "" +msgstr "set tidak didukung" #: extmod/ulab/code/numpy/random/random.c msgid "shape must be None, and integer or a tuple of integers" -msgstr "" +msgstr "shape harus None, dan integer atau tuple integer" #: extmod/ulab/code/ndarray.c msgid "shape must be integer or tuple of integers" -msgstr "" +msgstr "shape harus integer atau tuple integer" #: shared-module/msgpack/__init__.c msgid "short read" -msgstr "" +msgstr "pembacaan pendek" #: py/objstr.c msgid "sign not allowed in string format specifier" -msgstr "" +msgstr "tanda tidak diperbolehkan dalam spesifier format string" #: py/objstr.c msgid "sign not allowed with integer format specifier 'c'" -msgstr "" +msgstr "tanda tidak diperbolehkan dengan spesifier format integer 'c'" #: extmod/ulab/code/ulab_tools.c msgid "size is defined for ndarrays only" -msgstr "" +msgstr "size didefinisikan hanya untuk ndarray" #: extmod/ulab/code/numpy/random/random.c msgid "size must match out.shape when used together" -msgstr "" +msgstr "size harus cocok dengan out.shape ketika digunakan bersama" #: py/nativeglue.c msgid "slice unsupported" -msgstr "" +msgstr "slice tidak didukung" #: py/objint.c py/sequence.c msgid "small int overflow" -msgstr "" +msgstr "overflow int kecil" #: main.c msgid "soft reboot\n" @@ -4169,39 +4180,39 @@ msgstr "memulai ulang software(soft reboot)\n" #: extmod/ulab/code/numpy/numerical.c msgid "sort argument must be an ndarray" -msgstr "" +msgstr "argumen sort harus berupa ndarray" #: extmod/ulab/code/scipy/signal/signal.c msgid "sos array must be of shape (n_section, 6)" -msgstr "" +msgstr "array sos harus berbentuk (n_section, 6)" #: extmod/ulab/code/scipy/signal/signal.c msgid "sos[:, 3] should be all ones" -msgstr "" +msgstr "sos[:, 3] harus semuanya satu" #: extmod/ulab/code/scipy/signal/signal.c msgid "sosfilt requires iterable arguments" -msgstr "" +msgstr "sosfilt memerlukan argumen yang dapat diiterasi" #: shared-bindings/bitmaptools/__init__.c msgid "source palette too large" -msgstr "" +msgstr "palet sumber terlalu besar" #: shared-bindings/bitmaptools/__init__.c msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" +msgstr "source_bitmap harus memiliki value_count 2 atau 65536" #: shared-bindings/bitmaptools/__init__.c msgid "source_bitmap must have value_count of 65536" -msgstr "" +msgstr "source_bitmap harus memiliki value_count 65536" #: shared-bindings/bitmaptools/__init__.c msgid "source_bitmap must have value_count of 8" -msgstr "" +msgstr "source_bitmap harus memiliki value_count 8" #: extmod/modre.c msgid "splitting with sub-captures" -msgstr "" +msgstr "pemisahan dengan sub-capture" #: py/objstr.c msgid "start/end indices" @@ -4209,28 +4220,28 @@ msgstr "" #: shared-bindings/random/__init__.c msgid "stop not reachable from start" -msgstr "" +msgstr "stop tidak dapat dijangkau dari start" #: py/stream.c shared-bindings/getpass/__init__.c msgid "stream operation not supported" -msgstr "" +msgstr "operasi stream tidak didukung" #: py/objarray.c py/objstr.c msgid "string argument without an encoding" -msgstr "" +msgstr "argumen string tanpa encoding" #: py/objstrunicode.c msgid "string index out of range" -msgstr "" +msgstr "indeks string di luar jangkauan" #: py/objstrunicode.c #, c-format msgid "string indices must be integers, not %s" -msgstr "" +msgstr "indeks string harus integer, bukan %s" #: py/objarray.c py/objstr.c msgid "substring not found" -msgstr "" +msgstr "substring tidak ditemukan" #: py/compile.c msgid "super() can't find self" @@ -4242,87 +4253,87 @@ msgstr "sintaksis error pada JSON" #: extmod/modtime.c msgid "ticks interval overflow" -msgstr "" +msgstr "overflow interval tick" #: ports/nordic/common-hal/watchdog/WatchDogTimer.c msgid "timeout duration exceeded the maximum supported value" -msgstr "" +msgstr "durasi timeout melebihi nilai maksimum yang didukung" #: ports/nordic/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" -msgstr "" +msgstr "timeout harus < 655.35 detik" #: ports/raspberrypi/common-hal/floppyio/__init__.c msgid "timeout waiting for flux" -msgstr "" +msgstr "timeout menunggu flux" #: ports/raspberrypi/common-hal/floppyio/__init__.c #: shared-module/floppyio/__init__.c msgid "timeout waiting for index pulse" -msgstr "" +msgstr "timeout menunggu pulsa indeks" #: shared-module/sdcardio/SDCard.c msgid "timeout waiting for v1 card" -msgstr "" +msgstr "timeout menunggu kartu v1" #: shared-module/sdcardio/SDCard.c msgid "timeout waiting for v2 card" -msgstr "" +msgstr "timeout menunggu kartu v2" #: ports/stm/common-hal/pwmio/PWMOut.c msgid "timer re-init" -msgstr "" +msgstr "inisialisasi ulang timer" #: shared-bindings/time/__init__.c msgid "timestamp out of range for platform time_t" -msgstr "" +msgstr "timestamp di luar jangkauan untuk time_t platform" #: extmod/ulab/code/ndarray.c msgid "tobytes can be invoked for dense arrays only" -msgstr "" +msgstr "tobytes hanya dapat dipanggil untuk array padat" #: py/compile.c msgid "too many args" -msgstr "" +msgstr "terlalu banyak argumen" #: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c msgid "too many dimensions" -msgstr "" +msgstr "terlalu banyak dimensi" #: extmod/ulab/code/ndarray.c msgid "too many indices" -msgstr "" +msgstr "terlalu banyak indeks" #: py/asmthumb.c msgid "too many locals for native method" -msgstr "" +msgstr "terlalu banyak lokal untuk metode native" #: py/runtime.c #, c-format msgid "too many values to unpack (expected %d)" -msgstr "" +msgstr "terlalu banyak nilai untuk dibongkar (diharapkan %d)" #: extmod/ulab/code/numpy/approx.c msgid "trapz is defined for 1D arrays of equal length" -msgstr "" +msgstr "trapz didefinisikan untuk array 1D dengan panjang yang sama" #: extmod/ulab/code/numpy/approx.c msgid "trapz is defined for 1D iterables" -msgstr "" +msgstr "trapz didefinisikan untuk iterable 1D" #: py/obj.c msgid "tuple/list has wrong length" -msgstr "" +msgstr "tuple/list memiliki panjang yang salah" #: ports/espressif/common-hal/canio/CAN.c #, c-format msgid "twai_driver_install returned esp-idf error #%d" -msgstr "" +msgstr "twai_driver_install mengembalikan kesalahan esp-idf #%d" #: ports/espressif/common-hal/canio/CAN.c #, c-format msgid "twai_start returned esp-idf error #%d" -msgstr "" +msgstr "twai_start mengembalikan kesalahan esp-idf #%d" #: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c msgid "tx and rx cannot both be None" @@ -4330,27 +4341,27 @@ msgstr "tx dan rx keduanya tidak boleh kosong" #: py/objtype.c msgid "type '%q' isn't an acceptable base type" -msgstr "" +msgstr "tipe '%q' bukan tipe basis yang dapat diterima" #: py/objtype.c msgid "type isn't an acceptable base type" -msgstr "" +msgstr "tipe bukan tipe basis yang dapat diterima" #: py/runtime.c msgid "type object '%q' has no attribute '%q'" -msgstr "" +msgstr "objek tipe '%q' tidak memiliki atribut '%q'" #: py/objtype.c msgid "type takes 1 or 3 arguments" -msgstr "" +msgstr "type memerlukan 1 atau 3 argumen" #: py/objint_longlong.c msgid "ulonglong too large" -msgstr "" +msgstr "ulonglong terlalu besar" #: py/parse.c msgid "unexpected indent" -msgstr "" +msgstr "indentasi tak terduga" #: py/bc.c msgid "unexpected keyword argument" @@ -4363,20 +4374,20 @@ msgstr "keyword argumen '%q' tidak diharapkan" #: py/lexer.c msgid "unicode name escapes" -msgstr "" +msgstr "escape nama unicode" #: py/parse.c msgid "unindent doesn't match any outer indent level" -msgstr "" +msgstr "unindent tidak cocok dengan tingkat indentasi luar mana pun" #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" -msgstr "" +msgstr "spesifier konversi tidak dikenal %c" #: py/objstr.c msgid "unknown format code '%c' for object of type '%q'" -msgstr "" +msgstr "kode format tidak dikenal '%c' untuk objek bertipe '%q'" #: py/compile.c msgid "unknown type" @@ -4384,100 +4395,102 @@ msgstr "tipe tidak diketahui" #: py/compile.c msgid "unknown type '%q'" -msgstr "" +msgstr "tipe tidak dikenal '%q'" #: py/objstr.c #, c-format msgid "unmatched '%c' in format" -msgstr "" +msgstr "'%c' tidak cocok dalam format" #: py/objtype.c py/runtime.c msgid "unreadable attribute" -msgstr "" +msgstr "atribut tidak dapat dibaca" #: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c #: shared-bindings/tilepalettemapper/TilePaletteMapper.c #: shared-bindings/vectorio/VectorShape.c msgid "unsupported %q type" -msgstr "" +msgstr "tipe %q tidak didukung" #: py/emitinlinethumb.c #, c-format msgid "unsupported Thumb instruction '%s' with %d arguments" -msgstr "" +msgstr "instruksi Thumb tidak didukung '%s' dengan %d argumen" #: py/emitinlinextensa.c #, c-format msgid "unsupported Xtensa instruction '%s' with %d arguments" -msgstr "" +msgstr "instruksi Xtensa tidak didukung '%s' dengan %d argumen" #: shared-module/bitmapfilter/__init__.c msgid "unsupported bitmap depth" -msgstr "" +msgstr "kedalaman bitmap tidak didukung" #: shared-module/gifio/GifWriter.c msgid "unsupported colorspace for GifWriter" -msgstr "" +msgstr "colorspace tidak didukung untuk GifWriter" #: shared-bindings/bitmaptools/__init__.c msgid "unsupported colorspace for dither" -msgstr "" +msgstr "colorspace tidak didukung untuk dither" #: py/objstr.c #, c-format msgid "unsupported format character '%c' (0x%x) at index %d" -msgstr "" +msgstr "karakter format tidak didukung '%c' (0x%x) pada indeks %d" #: py/runtime.c msgid "unsupported type for %q: '%s'" -msgstr "" +msgstr "tipe tidak didukung untuk %q: '%s'" #: py/runtime.c msgid "unsupported type for operator" -msgstr "" +msgstr "tipe tidak didukung untuk operator" #: py/runtime.c msgid "unsupported types for %q: '%q', '%q'" -msgstr "" +msgstr "tipe tidak didukung untuk %q: '%q', '%q'" #: extmod/ulab/code/numpy/io/io.c msgid "usecols is too high" -msgstr "" +msgstr "usecols terlalu tinggi" #: extmod/ulab/code/numpy/io/io.c msgid "usecols keyword must be specified" -msgstr "" +msgstr "keyword usecols harus ditentukan" #: py/objint.c #, c-format msgid "value must fit in %d byte(s)" -msgstr "" +msgstr "nilai harus muat dalam %d byte" #: shared-bindings/bitmaptools/__init__.c msgid "value out of range of target" -msgstr "" +msgstr "nilai di luar jangkauan target" #: extmod/moddeflate.c msgid "wbits" -msgstr "" +msgstr "wbit" #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " "or 25)" msgstr "" +"weights harus berupa urutan dengan jumlah persegi ganjil elemen (biasanya 9 " +"atau 25)" #: shared-bindings/bitmapfilter/__init__.c msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "" +msgstr "weights harus berupa objek bertipe %q, %q, %q, atau %q, bukan %q " #: shared-bindings/is31fl3741/FrameBuffer.c msgid "width must be greater than zero" -msgstr "" +msgstr "lebar harus lebih besar dari nol" #: ports/raspberrypi/common-hal/wifi/Monitor.c msgid "wifi.Monitor not available" -msgstr "" +msgstr "wifi.Monitor tidak tersedia" #: shared-bindings/_bleio/Adapter.c msgid "window must be <= interval" @@ -4493,11 +4506,11 @@ msgstr "sumbu yang ditentukan salah" #: extmod/ulab/code/numpy/io/io.c msgid "wrong dtype" -msgstr "" +msgstr "dtype salah" #: extmod/ulab/code/numpy/transform.c msgid "wrong index type" -msgstr "" +msgstr "tipe indeks salah" #: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c #: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c @@ -4507,11 +4520,11 @@ msgstr "tipe input salah" #: extmod/ulab/code/numpy/transform.c msgid "wrong length of condition array" -msgstr "" +msgstr "panjang array kondisi salah" #: extmod/ulab/code/numpy/transform.c msgid "wrong length of index array" -msgstr "" +msgstr "panjang array indeks salah" #: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c msgid "wrong number of arguments" From e26fb4cb9dd83df22a91cb844a637b204987718a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 13 Feb 2026 15:58:36 -0500 Subject: [PATCH 206/876] shrink pygamer board --- ports/atmel-samd/boards/pygamer/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/boards/pygamer/mpconfigboard.mk b/ports/atmel-samd/boards/pygamer/mpconfigboard.mk index 19fa4f19b9d..0c6f16f8b63 100644 --- a/ports/atmel-samd/boards/pygamer/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pygamer/mpconfigboard.mk @@ -12,6 +12,7 @@ LONGINT_IMPL = MPZ CIRCUITPY_AESIO = 0 CIRCUITPY_FLOPPYIO = 0 +CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_GIFIO = 0 CIRCUITPY_I2CDISPLAYBUS = 0 From 4b2111e10b0f7c04bb98de16bfa96cac082c14c7 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 14 Feb 2026 20:10:00 -0500 Subject: [PATCH 207/876] os.getenv() now always returns str; add supervisor.get_setting() to fetch typed objects --- devices/ble_hci/common-hal/_bleio/Adapter.c | 4 +- docs/environment.rst | 4 +- docs/shared_bindings_matrix.py | 3 +- locale/circuitpython.pot | 18 +- main.c | 10 +- ports/atmel-samd/mpconfigport.mk | 2 +- ports/espressif/boards/makerfabs_tft7/board.c | 11 +- .../boards/sunton_esp32_2432S024C/board.c | 11 +- .../boards/sunton_esp32_2432S028/board.c | 11 +- .../boards/sunton_esp32_8048S050/board.c | 7 +- ports/espressif/common-hal/_bleio/Adapter.c | 10 +- ports/nordic/common-hal/_bleio/Adapter.c | 11 +- .../raspberrypi/common-hal/picodvi/__init__.c | 12 +- ports/unix/Makefile | 2 + ports/unix/main.c | 31 -- ports/unix/modos.c | 32 +- .../unix/variants/coverage/mpconfigvariant.mk | 3 +- py/circuitpy_defns.mk | 1 - py/circuitpy_mpconfig.mk | 6 +- shared-bindings/os/__init__.c | 17 +- shared-bindings/supervisor/__init__.c | 67 +++ shared-module/os/__init__.c | 17 + shared-module/os/__init__.h | 21 - shared-module/os/getenv.c | 417 ---------------- supervisor/shared/bluetooth/bluetooth.c | 10 +- supervisor/shared/display.c | 14 +- supervisor/shared/filesystem.c | 2 +- supervisor/shared/settings.c | 463 ++++++++++++++++++ supervisor/shared/settings.h | 53 ++ supervisor/shared/web_workflow/web_workflow.c | 26 +- supervisor/supervisor.mk | 4 + tests/circuitpython/getenv.py | 7 +- tests/circuitpython/getenv.py.exp | 26 +- 33 files changed, 723 insertions(+), 610 deletions(-) delete mode 100644 shared-module/os/getenv.c create mode 100644 supervisor/shared/settings.c create mode 100644 supervisor/shared/settings.h diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index fac7eb9f5fd..03ec7a5588f 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -29,7 +29,7 @@ #include "shared-bindings/_bleio/ScanEntry.h" #include "shared-bindings/time/__init__.h" -#if CIRCUITPY_OS_GETENV +#if CIRCUITPY_SETTINGS_TOML #include "shared-bindings/os/__init__.h" #endif @@ -261,7 +261,7 @@ static void _adapter_set_name(bleio_adapter_obj_t *self, mp_obj_str_t *name_obj) static void bleio_adapter_hci_init(bleio_adapter_obj_t *self) { mp_int_t name_len = 0; - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML mp_obj_t name = common_hal_os_getenv("CIRCUITPY_BLE_NAME", mp_const_none); if (name != mp_const_none) { mp_arg_validate_type_string(name, MP_QSTR_CIRCUITPY_BLE_NAME); diff --git a/docs/environment.rst b/docs/environment.rst index b97820b3caf..36404eb81f9 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -187,7 +187,7 @@ Allows the entry of a display scaling factor used during the terminalio console The entered scaling factor only affects the terminalio console and has no impact on the UART, Web Workflow, BLE Workflow, etc consoles. -This feature is not enabled on boards that the CIRCUITPY_OS_GETENV (os CIRCUIPTY_FULL_BUILD) +This feature is not enabled on boards that the CIRCUITPY_SETTINGS_TOML (or CIRCUITPY_FULL_BUILD) flag has been set to 0. Currently this is primarily boards with limited flash including some of the Atmel_samd boards based on the SAMD21/M0 microprocessor. @@ -197,7 +197,7 @@ Specifies a custom font file path to use for the terminalio console instead of t ``/fonts/terminal.lvfontbin``. This allows users to create and use custom fonts for the CircuitPython console. -This feature requires both CIRCUITPY_OS_GETENV and CIRCUITPY_LVFONTIO to be enabled. +This feature requires both CIRCUITPY_SETTINGS_TOML and CIRCUITPY_LVFONTIO to be enabled. Example: diff --git a/docs/shared_bindings_matrix.py b/docs/shared_bindings_matrix.py index b4fe4ff7e24..8fbee4beea5 100644 --- a/docs/shared_bindings_matrix.py +++ b/docs/shared_bindings_matrix.py @@ -84,8 +84,9 @@ "keypad.Keys": "CIRCUITPY_KEYPAD_KEYS", "keypad.ShiftRegisterKeys": "CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS", "keypad_demux.DemuxKeyMatrix": "CIRCUITPY_KEYPAD_DEMUX", - "os.getenv": "CIRCUITPY_OS_GETENV", + "os.getenv": "CIRCUITPY_SETTINGS_TOML", "select": "MICROPY_PY_SELECT_SELECT", + "supervisor.get_setting": "CIRCUITPY_SETTINGS_TOML", "sys": "CIRCUITPY_SYS", "terminalio": "CIRCUITPY_DISPLAYIO", "usb": "CIRCUITPY_PYUSB", diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index c135442f600..0a776db93db 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -583,7 +583,7 @@ msgstr "" msgid "Already scanning for wifi networks" msgstr "" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "" @@ -1092,7 +1092,6 @@ msgid "File exists" msgstr "" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "" @@ -1243,7 +1242,7 @@ msgstr "" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1340,17 +1339,12 @@ msgstr "" msgid "Invalid bits per value" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "" @@ -1381,7 +1375,7 @@ msgstr "" msgid "Invalid state" msgstr "" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "" @@ -1389,10 +1383,6 @@ msgstr "" msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "" diff --git a/main.c b/main.c index 7b936488fb7..46b54f522b5 100644 --- a/main.c +++ b/main.c @@ -113,8 +113,8 @@ uint8_t value_out = 0; #endif -#if MICROPY_ENABLE_PYSTACK && CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif static void reset_devices(void) { @@ -132,17 +132,17 @@ static const char line_clear[] = "\x1b[2K\x1b[0G"; #if MICROPY_ENABLE_PYSTACK || MICROPY_ENABLE_GC static uint8_t *_allocate_memory(safe_mode_t safe_mode, const char *env_key, size_t default_size, size_t *final_size) { *final_size = default_size; - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML if (safe_mode == SAFE_MODE_NONE) { mp_int_t size; - if (common_hal_os_getenv_int(env_key, &size) == GETENV_OK && size > 0) { + if (settings_get_int(env_key, &size) == SETTINGS_OK && size > 0) { *final_size = size; } } #endif uint8_t *ptr = port_malloc(*final_size, false); - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML if (ptr == NULL) { // Fallback to the build size. ptr = port_malloc(default_size, false); diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index c095220d0a3..b0947ea6f25 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -48,10 +48,10 @@ CIRCUITPY_I2CTARGET ?= 0 CIRCUITPY_JSON ?= 0 CIRCUITPY_KEYPAD ?= 0 CIRCUITPY_MSGPACK ?= 0 -CIRCUITPY_OS_GETENV ?= 0 CIRCUITPY_PIXELMAP ?= 0 CIRCUITPY_RE ?= 0 CIRCUITPY_SDCARDIO ?= 0 +CIRCUITPY_SETTINGS_TOML ?= 0 CIRCUITPY_SPITARGET ?= 0 CIRCUITPY_SYNTHIO ?= 0 CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1 diff --git a/ports/espressif/boards/makerfabs_tft7/board.c b/ports/espressif/boards/makerfabs_tft7/board.c index dd0ffa26528..a994cfef381 100644 --- a/ports/espressif/boards/makerfabs_tft7/board.c +++ b/ports/espressif/boards/makerfabs_tft7/board.c @@ -6,13 +6,14 @@ #include "supervisor/board.h" #include "mpconfigboard.h" + #include "shared-bindings/board/__init__.h" #include "shared-bindings/dotclockframebuffer/DotClockFramebuffer.h" #include "shared-bindings/dotclockframebuffer/__init__.h" #include "shared-bindings/framebufferio/FramebufferDisplay.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" -#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" static const mcu_pin_obj_t *blue_pins[] = { &pin_GPIO8, @@ -40,14 +41,14 @@ static const mcu_pin_obj_t *red_pins[] = { static void display_init(void) { mp_int_t height = 0, width = 0, frequency = 0; - os_getenv_err_t result; + settings_err_t result; - result = common_hal_os_getenv_int("CIRCUITPY_DISPLAY_WIDTH", &width); - if (result == GETENV_OK && width == 800) { + result = settings_get_int("CIRCUITPY_DISPLAY_WIDTH", &width); + if (result == SETTINGS_OK && width == 800) { width = 800; height = 480; frequency = 6500000; - } else if (result == GETENV_OK && width == 1024) { + } else if (result == SETTINGS_OK && width == 1024) { width = 1024; height = 600; frequency = 10000000; diff --git a/ports/espressif/boards/sunton_esp32_2432S024C/board.c b/ports/espressif/boards/sunton_esp32_2432S024C/board.c index a43b5ad65a0..de7504a8715 100644 --- a/ports/espressif/boards/sunton_esp32_2432S024C/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S024C/board.c @@ -6,13 +6,14 @@ #include "supervisor/board.h" #include "mpconfigboard.h" + +#include "common-hal/microcontroller/Pin.h" +#include "driver/gpio.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" #include "shared-module/displayio/mipi_constants.h" -#include "driver/gpio.h" -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" uint8_t display_init_sequence[] = { 0x01, 0x80, 0x80, // # Software reset then delay 0x80 (128ms) @@ -59,8 +60,8 @@ static void display_init(void) { busdisplay_busdisplay_obj_t *display = &allocate_display()->display; display->base.type = &busdisplay_busdisplay_type; - os_getenv_err_t result = common_hal_os_getenv_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); - if (result != GETENV_OK) { + settings_err_t result = settings_get_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); + if (result != SETTINGS_OK) { rotation = 0; } diff --git a/ports/espressif/boards/sunton_esp32_2432S028/board.c b/ports/espressif/boards/sunton_esp32_2432S028/board.c index 7380e252410..214e3b13e15 100644 --- a/ports/espressif/boards/sunton_esp32_2432S028/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S028/board.c @@ -6,13 +6,14 @@ #include "supervisor/board.h" #include "mpconfigboard.h" + +#include "common-hal/microcontroller/Pin.h" +#include "driver/gpio.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" #include "shared-module/displayio/mipi_constants.h" -#include "driver/gpio.h" -#include "common-hal/microcontroller/Pin.h" -#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" uint8_t display_init_sequence[] = { 0x01, 0x80, 0x80, // # Software reset then delay 0x80 (128ms) @@ -59,8 +60,8 @@ static void display_init(void) { busdisplay_busdisplay_obj_t *display = &allocate_display()->display; display->base.type = &busdisplay_busdisplay_type; - os_getenv_err_t result = common_hal_os_getenv_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); - if (result != GETENV_OK) { + settings_err_t result = settings_get_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); + if (result != SETTINGS_OK) { rotation = 0; } diff --git a/ports/espressif/boards/sunton_esp32_8048S050/board.c b/ports/espressif/boards/sunton_esp32_8048S050/board.c index e01f857bfd9..a6f573a86e7 100644 --- a/ports/espressif/boards/sunton_esp32_8048S050/board.c +++ b/ports/espressif/boards/sunton_esp32_8048S050/board.c @@ -6,13 +6,14 @@ #include "supervisor/board.h" #include "mpconfigboard.h" + #include "shared-bindings/board/__init__.h" #include "shared-bindings/dotclockframebuffer/DotClockFramebuffer.h" #include "shared-bindings/dotclockframebuffer/__init__.h" #include "shared-bindings/framebufferio/FramebufferDisplay.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" -#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" static const mcu_pin_obj_t *blue_pins[] = { &pin_GPIO8, @@ -47,8 +48,8 @@ static void display_init(void) { dotclockframebuffer_framebuffer_obj_t *framebuffer = &allocate_display_bus_or_raise()->dotclock; framebuffer->base.type = &dotclockframebuffer_framebuffer_type; - os_getenv_err_t result = common_hal_os_getenv_int("CIRCUITPY_DISPLAY_FREQUENCY", &frequency); - if (result != GETENV_OK) { + settings_err_t result = settings_get_int("CIRCUITPY_DISPLAY_FREQUENCY", &frequency); + if (result != SETTINGS_OK) { frequency = 12500000; } diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index 352d01372a9..327515da4de 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -44,8 +44,8 @@ #include "esp_nimble_hci.h" #include "nvs_flash.h" -#if CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif // Status variables used while busy-waiting for events. @@ -105,10 +105,10 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable ble_svc_gatt_init(); ble_svc_ans_init(); - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML char ble_name[1 + MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH]; - os_getenv_err_t result = common_hal_os_getenv_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); - if (result == GETENV_OK) { + settings_err_t result = settings_get_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); + if (result == SETTINGS_OK) { ble_svc_gap_device_name_set(ble_name); } else #endif diff --git a/ports/nordic/common-hal/_bleio/Adapter.c b/ports/nordic/common-hal/_bleio/Adapter.c index 9cf40ae91b3..2ca9df89710 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.c +++ b/ports/nordic/common-hal/_bleio/Adapter.c @@ -32,9 +32,8 @@ #include "supervisor/usb.h" #endif -#if CIRCUITPY_OS_GETENV -#include "shared-bindings/os/__init__.h" -#include "shared-module/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif #define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) @@ -324,11 +323,11 @@ static void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { default_ble_name[len - 1] = nibble_to_hex_lower[addr.addr[0] & 0xf]; default_ble_name[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML char ble_name[32]; - os_getenv_err_t result = common_hal_os_getenv_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); - if (result == GETENV_OK) { + settings_err_t result = settings_get_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); + if (result == SETTINGS_OK) { common_hal_bleio_adapter_set_name(self, ble_name); return; } diff --git a/ports/raspberrypi/common-hal/picodvi/__init__.c b/ports/raspberrypi/common-hal/picodvi/__init__.c index e8f344852de..c2d4b297b39 100644 --- a/ports/raspberrypi/common-hal/picodvi/__init__.c +++ b/ports/raspberrypi/common-hal/picodvi/__init__.c @@ -10,8 +10,8 @@ #include "shared-bindings/busio/I2C.h" #include "shared-bindings/board/__init__.h" #include "shared-module/displayio/__init__.h" -#include "shared-module/os/__init__.h" #include "supervisor/shared/safe_mode.h" +#include "supervisor/shared/settings.h" #include "py/gc.h" #include "py/runtime.h" #include "supervisor/port_heap.h" @@ -22,7 +22,7 @@ static bool picodvi_autoconstruct_enabled(mp_int_t *default_width, mp_int_t *def buf[0] = 0; // (any failure leaves the content of buf untouched: an empty nul-terminated string - (void)common_hal_os_getenv_str("CIRCUITPY_PICODVI_ENABLE", buf, sizeof(buf)); + (void)settings_get_str("CIRCUITPY_PICODVI_ENABLE", buf, sizeof(buf)); if (!strcasecmp(buf, "never")) { return false; @@ -106,10 +106,10 @@ void picodvi_autoconstruct(void) { mp_int_t color_depth = 8; mp_int_t rotation = 0; - (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_WIDTH", &width); - (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_HEIGHT", &height); - (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_COLOR_DEPTH", &color_depth); - (void)common_hal_os_getenv_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); + (void)settings_get_int("CIRCUITPY_DISPLAY_WIDTH", &width); + (void)settings_get_int("CIRCUITPY_DISPLAY_HEIGHT", &height); + (void)settings_get_int("CIRCUITPY_DISPLAY_COLOR_DEPTH", &color_depth); + (void)settings_get_int("CIRCUITPY_DISPLAY_ROTATION", &rotation); if (height == 0) { switch (width) { diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 6aee1a939b3..6461c310eeb 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -208,6 +208,8 @@ SRC_C += \ input.c \ alloc.c \ fatfs_port.c \ + shared-module/os/__init__.c \ + supervisor/shared/settings.c \ supervisor/stub/filesystem.c \ supervisor/stub/safe_mode.c \ supervisor/stub/stack.c \ diff --git a/ports/unix/main.c b/ports/unix/main.c index ce8b8913637..259b183eb76 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -55,35 +55,6 @@ #include "genhdr/mpversion.h" #include "input.h" -// CIRCUITPY-CHANGE -#if defined(MICROPY_UNIX_COVERAGE) -#include "py/objstr.h" -typedef int os_getenv_err_t; -mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_); -os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len); -os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value); - -static mp_obj_t mod_os_getenv_int(mp_obj_t var_in) { - mp_int_t value; - os_getenv_err_t result = common_hal_os_getenv_int(mp_obj_str_get_str(var_in), &value); - if (result == 0) { - return mp_obj_new_int(value); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_int_obj, mod_os_getenv_int); - -static mp_obj_t mod_os_getenv_str(mp_obj_t var_in) { - char buf[4096]; - os_getenv_err_t result = common_hal_os_getenv_str(mp_obj_str_get_str(var_in), buf, sizeof(buf)); - if (result == 0) { - return mp_obj_new_str_copy(&mp_type_str, (byte *)buf, strlen(buf)); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mod_os_getenv_str_obj, mod_os_getenv_str); -#endif - // Command line options, with their defaults static bool compile_only = false; static uint emit_opt = MP_EMIT_OPT_NONE; @@ -645,8 +616,6 @@ MP_NOINLINE int main_(int argc, char **argv) { // CIRCUITPY-CHANGE: test native base classes work as needed by CircuitPython libraries. extern const mp_obj_type_t native_base_class_type; mp_store_global(MP_QSTR_NativeBaseClass, MP_OBJ_FROM_PTR(&native_base_class_type)); - mp_store_global(MP_QSTR_getenv_int, MP_OBJ_FROM_PTR(&mod_os_getenv_int_obj)); - mp_store_global(MP_QSTR_getenv_str, MP_OBJ_FROM_PTR(&mod_os_getenv_str_obj)); } #endif diff --git a/ports/unix/modos.c b/ports/unix/modos.c index 896bf351b83..af8a1cc4da8 100644 --- a/ports/unix/modos.c +++ b/ports/unix/modos.c @@ -32,13 +32,12 @@ #include "py/runtime.h" #include "py/mphal.h" -// CIRCUITPY-CHANGE: enhanced getenv +// CIRCUITPY-CHANGE: use shared-module os getenv #if defined(MICROPY_UNIX_COVERAGE) #include "py/objstr.h" -typedef int os_getenv_err_t; +#include "shared-module/os/__init__.h" +#include "supervisor/shared/settings.h" mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_); -os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len); -os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value); #endif static mp_obj_t mp_os_getenv(size_t n_args, const mp_obj_t *args) { @@ -58,30 +57,7 @@ static mp_obj_t mp_os_getenv(size_t n_args, const mp_obj_t *args) { } return mp_obj_new_str_from_cstr(s); } -MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_os_getenv_obj, 1, 2, mp_os_getenv); - -// CIRCUITPY-CHANGE: getenv differences -#if defined(MICROPY_UNIX_COVERAGE) -static mp_obj_t mp_os_getenv_int(mp_obj_t var_in) { - mp_int_t value; - os_getenv_err_t result = common_hal_os_getenv_int(mp_obj_str_get_str(var_in), &value); - if (result == 0) { - return mp_obj_new_int(value); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mp_os_getenv_int_obj, mp_os_getenv_int); - -static mp_obj_t mp_os_getenv_str(mp_obj_t var_in) { - char buf[4096]; - os_getenv_err_t result = common_hal_os_getenv_str(mp_obj_str_get_str(var_in), buf, sizeof(buf)); - if (result == 0) { - return mp_obj_new_str_copy(&mp_type_str, (byte *)buf, strlen(buf)); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mp_os_getenv_str_obj, mp_os_getenv_str); -#endif +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_os_getenv_obj, 1, 2, mp_os_getenv); static mp_obj_t mp_os_putenv(mp_obj_t key_in, mp_obj_t value_in) { const char *key = mp_obj_str_get_str(key_in); diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index 6ec0e85377c..292e4de8169 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -106,7 +106,6 @@ SRC_BITMAP := \ shared-module/floppyio/__init__.c \ shared-module/jpegio/__init__.c \ shared-module/jpegio/JpegDecoder.c \ - shared-module/os/getenv.c \ shared-module/rainbowio/__init__.c \ shared-module/struct/__init__.c \ shared-module/synthio/__init__.c \ @@ -164,8 +163,8 @@ CFLAGS += \ -DCIRCUITPY_GIFIO=1 \ -DCIRCUITPY_JPEGIO=1 \ -DCIRCUITPY_LOCALE=1 \ - -DCIRCUITPY_OS_GETENV=1 \ -DCIRCUITPY_RAINBOWIO=1 \ + -DCIRCUITPY_SETTINGS_TOML=1 \ -DCIRCUITPY_STRUCT=1 \ -DCIRCUITPY_SYNTHIO=1 \ -DCIRCUITPY_SYNTHIO_MAX_CHANNELS=14 \ diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 5760dbd9eb1..d8c95d18a79 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -959,7 +959,6 @@ SRC_SHARED_MODULE_INTERNAL = \ $(filter $(SRC_PATTERNS), \ displayio/bus_core.c \ displayio/display_core.c \ - os/getenv.c \ usb/utf16le.c \ ) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 8e0992f0418..56fc6957421 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -295,9 +295,6 @@ CFLAGS += -DCIRCUITPY_DUALBANK=$(CIRCUITPY_DUALBANK) CIRCUITPY_ENABLE_MPY_NATIVE ?= 0 CFLAGS += -DCIRCUITPY_ENABLE_MPY_NATIVE=$(CIRCUITPY_ENABLE_MPY_NATIVE) -CIRCUITPY_OS_GETENV ?= $(CIRCUITPY_FULL_BUILD) -CFLAGS += -DCIRCUITPY_OS_GETENV=$(CIRCUITPY_OS_GETENV) - CIRCUITPY_ERRNO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_ERRNO=$(CIRCUITPY_ERRNO) @@ -535,6 +532,9 @@ CFLAGS += -DCIRCUITPY_SERIAL_BLE=$(CIRCUITPY_SERIAL_BLE) CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY?= 0 CFLAGS += -DCIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY=$(CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY) +CIRCUITPY_SETTINGS_TOML ?= $(CIRCUITPY_FULL_BUILD) +CFLAGS += -DCIRCUITPY_SETTINGS_TOML=$(CIRCUITPY_SETTINGS_TOML) + CIRCUITPY_SHARPDISPLAY ?= $(CIRCUITPY_FRAMEBUFFERIO) CFLAGS += -DCIRCUITPY_SHARPDISPLAY=$(CIRCUITPY_SHARPDISPLAY) diff --git a/shared-bindings/os/__init__.c b/shared-bindings/os/__init__.c index 5e28c02452d..65bc90fbf86 100644 --- a/shared-bindings/os/__init__.c +++ b/shared-bindings/os/__init__.c @@ -94,11 +94,20 @@ static mp_obj_t os_getcwd(void) { MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd); //| def getenv(key: str, default: Optional[str] = None) -> Optional[str]: -//| """Get the environment variable value for the given key or return ``default``. +//| """Get the environment variable value for the given ``key`` from the +//| ``/settings.toml`` file. +//| If ``key`` is not present or the value is ill-formed, return the ``default`` value. +//| The value is returned as a string even if it can be parsed as an integer or boolean. +//| No errors are raised if the value is not a valid TOML value; instead the original +//| string is returned, or ``default`` if no value can be retrieved at all. //| -//| This may load values from disk so cache the result instead of calling this often. +//| If you want to retrieve the value as a ``str``, ``bool``, or ``int``, use `supervisor.get_setting()`. //| -//| On boards that do not support ``settings.toml`` reading in the core, this function will raise NotImplementedError. +//| The ``settings.toml`` file is re-scanned on every call, +//| so cache the result instead of calling `getenv()` frequently. +//| +//| On boards that do not support ``settings.toml`` reading in the core, +//| this function will raise NotImplementedError. //| //| .. raw:: html //| @@ -118,7 +127,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(os_getcwd_obj, os_getcwd); //| //| static mp_obj_t os_getenv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML enum { ARG_key, ARG_default }; static const mp_arg_t allowed_args[] = { { MP_QSTR_key, MP_ARG_REQUIRED | MP_ARG_OBJ }, diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c index f2fc14c3c9a..a0a01f124f7 100644 --- a/shared-bindings/supervisor/__init__.c +++ b/shared-bindings/supervisor/__init__.c @@ -21,6 +21,10 @@ #include "supervisor/usb.h" #endif +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/supervisor/__init__.h" #include "shared-bindings/time/__init__.h" @@ -360,6 +364,68 @@ static mp_obj_t supervisor_set_usb_identification(size_t n_args, const mp_obj_t } MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_usb_identification_obj, 0, supervisor_set_usb_identification); +//| def get_setting(key: str, default: object=None) -> int | str | bool: +//| """ +//| Get and parse the value for the given ``key`` from the ``/settings.toml`` file. +//| If ``key`` is not found or ``settings.toml`` is not present, return the ``default`` value. +//| +//| :param str key: The setting key to retrieve +//| :return: The setting value as an ``int``, ``str``, or ``bool`` depending on the value in the file +//| +//| :raises ValueError: If the value cannot be parsed as a valid TOML value. +//| +//| The value must be parseable as one of these types: +//| +//| - ``str``: Double-quoted string. +//| The string may include Unicode characters, and ``\\u`` Unicode escapes. Backslash-escaped characters +//| ``\\b``, ``\\r``, ``\\n``, ``\\t``, ``\\v``, ``\\v`` are also allowed. +//| - ``int``: signed or unsigned integer +//| - lower-case boolean words ``true`` and ``false``. +//| The values are returned as Python ``True`` or ``False`` values. +//| +//| Example:: +//| +//| # settings.toml: +//| WIDTH = 42 +//| color = "red" +//| DEBUG = true +//| +//| import supervisor +//| print(supervisor.get_setting("WIDTH")) # prints 42 +//| print(supervisor.get_setting("color")) # prints 'red' +//| print(supervisor.get_setting("DEBUG")) # prints True +//| """ +//| ... +//| +static mp_obj_t supervisor_get_setting(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + #if CIRCUITPY_SETTINGS_TOML + enum { ARG_key, ARG_default }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_key, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_default, MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, (mp_arg_val_t *)&args); + + const char *key = mp_obj_str_get_str(args[ARG_key].u_obj); + mp_obj_t value; + settings_err_t result = settings_get_obj(key, &value); + + switch (result) { + case SETTINGS_OK: + return value; + case SETTINGS_ERR_NOT_FOUND: + case SETTINGS_ERR_OPEN: + return args[ARG_default].u_obj; + default: + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), MP_QSTR_value); + } + #else + mp_raise_NotImplementedError(NULL); + #endif +} +MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_get_setting_obj, 1, supervisor_get_setting); + static const mp_rom_map_elem_t supervisor_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_supervisor) }, { MP_ROM_QSTR(MP_QSTR_runtime), MP_ROM_PTR(&common_hal_supervisor_runtime_obj) }, @@ -373,6 +439,7 @@ static const mp_rom_map_elem_t supervisor_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_set_next_code_file), MP_ROM_PTR(&supervisor_set_next_code_file_obj) }, { MP_ROM_QSTR(MP_QSTR_ticks_ms), MP_ROM_PTR(&supervisor_ticks_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_get_previous_traceback), MP_ROM_PTR(&supervisor_get_previous_traceback_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_setting), MP_ROM_PTR(&supervisor_get_setting_obj) }, { MP_ROM_QSTR(MP_QSTR_reset_terminal), MP_ROM_PTR(&supervisor_reset_terminal_obj) }, { MP_ROM_QSTR(MP_QSTR_set_usb_identification), MP_ROM_PTR(&supervisor_set_usb_identification_obj) }, { MP_ROM_QSTR(MP_QSTR_status_bar), MP_ROM_PTR(&shared_module_supervisor_status_bar_obj) }, diff --git a/shared-module/os/__init__.c b/shared-module/os/__init__.c index 3594c9bb028..3a9c0e31f8e 100644 --- a/shared-module/os/__init__.c +++ b/shared-module/os/__init__.c @@ -17,6 +17,10 @@ #include "py/runtime.h" #include "shared-bindings/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + // This provides all VFS related OS functions so that ports can share the code // as needed. @@ -281,4 +285,17 @@ void common_hal_os_utime(const char *path, mp_obj_t times) { mp_vfs_proxy_call(vfs, MP_QSTR_utime, 2, args); } +#if CIRCUITPY_SETTINGS_TOML +mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_) { + vstr_t vstr; + vstr_init(&vstr, 64); + + settings_err_t result = settings_get_raw_vstr(key, &vstr); + if (result == SETTINGS_OK) { + return mp_obj_new_str_from_vstr(&vstr); + } + return default_; +} +#endif + MP_REGISTER_ROOT_POINTER(const char *cwd_path); diff --git a/shared-module/os/__init__.h b/shared-module/os/__init__.h index d44bae1ffc5..830f7629509 100644 --- a/shared-module/os/__init__.h +++ b/shared-module/os/__init__.h @@ -6,26 +6,5 @@ #pragma once -typedef enum { - GETENV_OK = 0, - GETENV_ERR_OPEN, - GETENV_ERR_UNICODE, - GETENV_ERR_LENGTH, - GETENV_ERR_NOT_FOUND, - GETENV_ERR_UNEXPECTED = 0xff00, // logical or'd with the byte value -} os_getenv_err_t; - -// Allocation free version that returns the full length of the value. -// If it fits, the return value is 0-terminated. The passed in buffer -// may be modified even if an error is returned. Allocation free. -// An error that is not 'open' or 'not found' is printed on the repl. -os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len); - -// Returns GETENV_OK and sets value to the read value. Returns -// GETENV_ERR_... if the value was not numeric. allocation-free. -// If any error code is returned, value is guaranteed not modified -// An error that is not 'open' or 'not found' is printed on the repl. -os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value); - // Not made available to the VM but used by other modules to normalize paths. const char *common_hal_os_path_abspath(const char *path); diff --git a/shared-module/os/getenv.c b/shared-module/os/getenv.c deleted file mode 100644 index c7bfadf3418..00000000000 --- a/shared-module/os/getenv.c +++ /dev/null @@ -1,417 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2022 Scott Shawcroft for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -// These functions are separate from __init__.c so that os.getenv() can be -// tested in the unix "coverage" build, without bringing in "our" os module - -#include -#include -#include - -#include "shared-bindings/os/__init__.h" -#include "shared-module/os/__init__.h" - -#include "py/gc.h" -#include "py/misc.h" -#include "py/mpstate.h" -#include "py/mpprint.h" -#include "py/objstr.h" -#include "py/parsenum.h" -#include "py/runtime.h" -#include "supervisor/filesystem.h" - -#define GETENV_PATH "/settings.toml" - -#include "extmod/vfs.h" -#include "extmod/vfs_fat.h" - -#if CIRCUITPY_OS_GETENV -typedef FIL file_arg; -static bool open_file(const char *name, file_arg *active_file) { - #if defined(UNIX) - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_obj_t file_obj = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), mp_obj_new_str(name, strlen(name)), MP_ROM_QSTR(MP_QSTR_rb)); - mp_arg_validate_type(file_obj, &mp_type_vfs_fat_fileio, MP_QSTR_file); - pyb_file_obj_t *file = MP_OBJ_TO_PTR(file_obj); - *active_file = file->fp; - nlr_pop(); - return true; - } else { - return false; - } - #else - fs_user_mount_t *fs_mount = filesystem_circuitpy(); - if (fs_mount == NULL) { - return false; - } - FATFS *fatfs = &fs_mount->fatfs; - FRESULT result = f_open(fatfs, active_file, name, FA_READ); - return result == FR_OK; - #endif -} -static void close_file(file_arg *active_file) { - // nothing -} -static bool is_eof(file_arg *active_file) { - return f_eof(active_file) || f_error(active_file); -} - -// Return 0 if there is no next character (EOF). -static uint8_t get_next_byte(FIL *active_file) { - uint8_t character = 0; - UINT quantity_read; - // If there's an error or quantity_read is 0, character will remain 0. - f_read(active_file, &character, 1, &quantity_read); - return character; -} -static void seek_eof(file_arg *active_file) { - f_lseek(active_file, f_size(active_file)); -} - -// For a fixed buffer, record the required size rather than throwing -static void vstr_add_byte_nonstd(vstr_t *vstr, byte b) { - if (!vstr->fixed_buf || vstr->alloc > vstr->len) { - vstr_add_byte(vstr, b); - } else { - vstr->len++; - } -} - -// For a fixed buffer, record the required size rather than throwing -static void vstr_add_char_nonstd(vstr_t *vstr, unichar c) { - size_t ulen = - (c < 0x80) ? 1 : - (c < 0x800) ? 2 : - (c < 0x10000) ? 3 : 4; - if (!vstr->fixed_buf || vstr->alloc > vstr->len + ulen) { - vstr_add_char(vstr, c); - } else { - vstr->len += ulen; - } -} - -static void next_line(file_arg *active_file) { - uint8_t character; - do { - character = get_next_byte(active_file); - } while (character != 0 && character != '\n'); -} - -// Discard whitespace, except for newlines, returning the next character after the whitespace. -// Return 0 if there is no next character (EOF). -static uint8_t consume_whitespace(file_arg *active_file) { - uint8_t character; - do { - character = get_next_byte(active_file); - } while (character != '\n' && character != 0 && unichar_isspace(character)); - return character; -} - -// Starting at the start of a new line, determines if the key matches the given -// key. -// -// If result is true, the key matches and file pointer is pointing just after the "=". -// If the result is false, the key does NOT match and the file pointer is -// pointing at the start of the next line, if any -static bool key_matches(file_arg *active_file, const char *key) { - uint8_t character; - character = consume_whitespace(active_file); - if (character == '[' || character == 0) { - seek_eof(active_file); - return false; - } - while (*key) { - if (character != *key++) { - // A character didn't match the key, so it's not a match - // If the non-matching char was not the end of the line, - // then consume the rest of the line - if (character != '\n') { - next_line(active_file); - } - return false; - } - character = get_next_byte(active_file); - } - // the next character could be whitespace; consume if necessary - if (unichar_isspace(character)) { - character = consume_whitespace(active_file); - } - // If we're not looking at the "=" then the key didn't match - if (character != '=') { - // A character didn't match the key, so it's not a match - // If the non-matching char was not the end of the line, - // then consume the rest of the line - if (character != '\n') { - next_line(active_file); - } - return false; - } - return true; -} - -static os_getenv_err_t read_unicode_escape(file_arg *active_file, int sz, vstr_t *buf) { - char hex_buf[sz + 1]; - for (int i = 0; i < sz; i++) { - hex_buf[i] = get_next_byte(active_file); - } - hex_buf[sz] = 0; - char *end; - unsigned long c = strtoul(hex_buf, &end, 16); - if (end != &hex_buf[sz]) { - return GETENV_ERR_UNEXPECTED | *end; - } - if (c >= 0x110000) { - return GETENV_ERR_UNICODE; - } - vstr_add_char_nonstd(buf, c); - return GETENV_OK; -} - -// Read a quoted string -static os_getenv_err_t read_string_value(file_arg *active_file, vstr_t *buf) { - while (true) { - int character = get_next_byte(active_file); - switch (character) { - case 0: - case '\n': - return GETENV_ERR_UNEXPECTED | character; - - case '"': - character = consume_whitespace(active_file); - switch (character) { - case '#': - next_line(active_file); - MP_FALLTHROUGH; - case 0: - case '\n': - return GETENV_OK; - default: - return GETENV_ERR_UNEXPECTED | character; - } - - case '\\': - character = get_next_byte(active_file); - switch (character) { - case 0: - case '\n': - return GETENV_ERR_UNEXPECTED | character; - case 'b': - character = '\b'; - break; - case 'r': - character = '\r'; - break; - case 'n': - character = '\n'; - break; - case 't': - character = '\t'; - break; - case 'v': - character = '\v'; - break; - case 'f': - character = '\f'; - break; - case 'U': - case 'u': { - int sz = (character == 'u') ? 4 : 8; - os_getenv_err_t res; - res = read_unicode_escape(active_file, sz, buf); - if (res != GETENV_OK) { - return res; - } - continue; - } - // default falls through, other escaped characters - // represent themselves - } - MP_FALLTHROUGH; - default: - vstr_add_byte_nonstd(buf, character); - } - } -} - -// Read a numeric value (non-quoted value) as a string -static os_getenv_err_t read_bare_value(file_arg *active_file, vstr_t *buf, int first_character) { - int character = first_character; - while (true) { - switch (character) { - case 0: - case '\n': - return GETENV_OK; - case '#': - next_line(active_file); - return GETENV_OK; - default: - vstr_add_byte_nonstd(buf, character); - } - character = get_next_byte(active_file); - } -} - -static mp_int_t read_value(file_arg *active_file, vstr_t *buf, bool *quoted) { - uint8_t character; - character = consume_whitespace(active_file); - *quoted = (character == '"'); - - if (*quoted) { - return read_string_value(active_file, buf); - } else { - return read_bare_value(active_file, buf, character); - } -} - -static os_getenv_err_t os_getenv_vstr(const char *path, const char *key, vstr_t *buf, bool *quoted) { - file_arg active_file; - if (!open_file(path, &active_file)) { - return GETENV_ERR_OPEN; - } - - os_getenv_err_t result = GETENV_ERR_NOT_FOUND; - while (!is_eof(&active_file)) { - if (key_matches(&active_file, key)) { - result = read_value(&active_file, buf, quoted); - break; - } - } - close_file(&active_file); - return result; -} - -static os_getenv_err_t os_getenv_buf_terminated(const char *key, char *value, size_t value_len, bool *quoted) { - vstr_t buf; - vstr_init_fixed_buf(&buf, value_len, value); - os_getenv_err_t result = os_getenv_vstr(GETENV_PATH, key, &buf, quoted); - - if (result == GETENV_OK) { - vstr_add_byte_nonstd(&buf, 0); - memcpy(value, buf.buf, MIN(buf.len, value_len)); - if (buf.len > value_len) { // this length includes trailing NUL - result = GETENV_ERR_LENGTH; - } - } - return result; -} - -static void print_dont_raise(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) { - va_list argptr; - va_start(argptr, fmt); - mp_vcprintf(&mp_plat_print, fmt, argptr); - mp_printf(&mp_plat_print, "\n"); - va_end(argptr); -} - -static void handle_getenv_error(os_getenv_err_t error, void (*handle)(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...)) { - if (error == GETENV_OK) { - return; - } - if (error & GETENV_ERR_UNEXPECTED) { - byte character = (error & 0xff); - char buf[8]; - vstr_t vstr; - vstr_init_fixed_buf(&vstr, sizeof(buf), buf); - mp_print_t print = { .data = &vstr, .print_strn = (mp_print_strn_t)vstr_add_strn }; - - if (character) { - mp_str_print_quoted(&print, &character, 1, true); - } else { - mp_str_print_quoted(&print, (byte *)"EOF", 3, true); - } - handle(&mp_type_ValueError, MP_ERROR_TEXT("Invalid byte %.*s"), vstr.len, vstr.buf); - } else { - switch (error) { - case GETENV_ERR_OPEN: - handle(&mp_type_ValueError, MP_ERROR_TEXT("%S"), MP_ERROR_TEXT("File not found")); - break; - case GETENV_ERR_UNICODE: - handle(&mp_type_ValueError, MP_ERROR_TEXT("%S"), MP_ERROR_TEXT("Invalid unicode escape")); - break; - case GETENV_ERR_NOT_FOUND: - handle(&mp_type_ValueError, MP_ERROR_TEXT("%S"), MP_ERROR_TEXT("Key not found")); - break; - default: - handle(&mp_type_RuntimeError, MP_ERROR_TEXT("%S"), MP_ERROR_TEXT("Internal error")); - break; - } - } -} - -static void common_hal_os_getenv_showerr(const char *key, os_getenv_err_t result) { - if (result != GETENV_OK && result != GETENV_ERR_OPEN && result != GETENV_ERR_NOT_FOUND) { - mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("An error occurred while retrieving '%s':\n"), key); - handle_getenv_error(result, print_dont_raise); - } -} - -static -os_getenv_err_t common_hal_os_getenv_str_inner(const char *key, char *value, size_t value_len) { - bool quoted; - os_getenv_err_t result = os_getenv_buf_terminated(key, value, value_len, "ed); - if (result == GETENV_OK && !quoted) { - result = GETENV_ERR_UNEXPECTED | value[0]; - } - return result; -} - -os_getenv_err_t common_hal_os_getenv_str(const char *key, char *value, size_t value_len) { - os_getenv_err_t result = common_hal_os_getenv_str_inner(key, value, value_len); - common_hal_os_getenv_showerr(key, result); - return result; -} - -mp_obj_t common_hal_os_getenv_path(const char *path, const char *key, mp_obj_t default_) { - vstr_t buf; - bool quoted; - - vstr_init(&buf, 64); - os_getenv_err_t result = os_getenv_vstr(path, key, &buf, "ed); - if (result == GETENV_ERR_NOT_FOUND || result == GETENV_ERR_OPEN) { - return default_; - } - handle_getenv_error(result, mp_raise_msg_varg); - - if (quoted) { - return mp_obj_new_str_from_vstr(&buf); - } else { - return mp_parse_num_integer(buf.buf, buf.len, 0, NULL); - } -} - -mp_obj_t common_hal_os_getenv(const char *key, mp_obj_t default_) { - return common_hal_os_getenv_path(GETENV_PATH, key, default_); -} - -static os_getenv_err_t common_hal_os_getenv_int_inner(const char *key, mp_int_t *value) { - char buf[16]; - bool quoted; - os_getenv_err_t result = os_getenv_buf_terminated(key, buf, sizeof(buf), "ed); - if (result != GETENV_OK) { - return result; - } - if (quoted) { - return GETENV_ERR_UNEXPECTED | '"'; - } - char *end; - long num = strtol(buf, &end, 0); - while (unichar_isspace(*end)) { - end++; - } - if (end == buf || *end) { // If the whole buffer was not consumed it's an error - return GETENV_ERR_UNEXPECTED | *end; - } - *value = (mp_int_t)num; - return GETENV_OK; -} - -os_getenv_err_t common_hal_os_getenv_int(const char *key, mp_int_t *value) { - os_getenv_err_t result = common_hal_os_getenv_int_inner(key, value); - common_hal_os_getenv_showerr(key, result); - return result; -} -#endif diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 055a5cdf1fd..cccb371fc4d 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -36,8 +36,8 @@ #include "supervisor/shared/status_bar.h" #endif -#if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif @@ -216,11 +216,11 @@ void supervisor_bluetooth_init(void) { // Checking here allows us to have the status LED solidly on even if no button was // pressed. bool wifi_workflow_active = false; - #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_OS_GETENV + #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML char _api_password[64]; const size_t api_password_len = sizeof(_api_password) - 1; - os_getenv_err_t result = common_hal_os_getenv_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); - wifi_workflow_active = result == GETENV_OK; + settings_err_t result = settings_get_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); + wifi_workflow_active = result == SETTINGS_OK; #endif if (!bonded && !wifi_workflow_active) { boot_in_discovery_mode = true; diff --git a/supervisor/shared/display.c b/supervisor/shared/display.c index 99c1497f023..1352c76b006 100644 --- a/supervisor/shared/display.c +++ b/supervisor/shared/display.c @@ -38,9 +38,11 @@ #if CIRCUITPY_TERMINALIO #include "supervisor/port.h" -#if CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" + +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif + #if CIRCUITPY_LVFONTIO #include "shared-bindings/lvfontio/OnDiskFont.h" #include "supervisor/filesystem.h" @@ -66,10 +68,10 @@ static bool check_for_custom_font(const char **font_path_out) { const char *default_font_path = "/fonts/terminal.lvfontbin"; const char *font_path = default_font_path; - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML // Buffer for storing custom font path static char custom_font_path[128]; - if (common_hal_os_getenv_str("CIRCUITPY_TERMINAL_FONT", custom_font_path, sizeof(custom_font_path)) == GETENV_OK) { + if (settings_get_str("CIRCUITPY_TERMINAL_FONT", custom_font_path, sizeof(custom_font_path)) == SETTINGS_OK) { // Use custom font path from environment variable font_path = custom_font_path; } @@ -179,8 +181,8 @@ void supervisor_start_terminal(uint16_t width_px, uint16_t height_px) { if (width_in_tiles <= 120) { scale = 1; } - #if CIRCUITPY_OS_GETENV - (void)common_hal_os_getenv_int("CIRCUITPY_TERMINAL_SCALE", &scale); + #if CIRCUITPY_SETTINGS_TOML + (void)settings_get_int("CIRCUITPY_TERMINAL_SCALE", &scale); #endif width_in_tiles = MAX(1, width_px / (glyph_width * scale)); diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 025c9ddbd6d..eb4b6548d11 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -172,7 +172,7 @@ bool filesystem_init(bool create_allowed, bool force_create) { #endif #endif - #if CIRCUITPY_OS_GETENV + #if CIRCUITPY_SETTINGS_TOML make_empty_file(&circuitpy->fatfs, "/settings.toml"); #endif // make a sample code.py file diff --git a/supervisor/shared/settings.c b/supervisor/shared/settings.c new file mode 100644 index 00000000000..d1b05a5da9d --- /dev/null +++ b/supervisor/shared/settings.c @@ -0,0 +1,463 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Scott Shawcroft for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include +#include + +#include "py/gc.h" +#include "py/misc.h" +#include "py/mpstate.h" +#include "py/mpprint.h" +#include "py/objstr.h" +#include "py/parsenum.h" +#include "py/runtime.h" +#include "supervisor/filesystem.h" +#include "supervisor/shared/settings.h" + +#define SETTINGS_PATH "/settings.toml" + +#include "extmod/vfs.h" +#include "extmod/vfs_fat.h" + +#if CIRCUITPY_SETTINGS_TOML +typedef FIL file_arg; +static bool open_file(const char *name, file_arg *file_handle) { + #if defined(UNIX) + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t file_obj = mp_call_function_2( + MP_OBJ_FROM_PTR(&mp_builtin_open_obj), mp_obj_new_str(name, strlen(name)), MP_ROM_QSTR(MP_QSTR_rb)); + mp_arg_validate_type(file_obj, &mp_type_vfs_fat_fileio, MP_QSTR_file); + pyb_file_obj_t *file = MP_OBJ_TO_PTR(file_obj); + *file_handle = file->fp; + nlr_pop(); + return true; + } else { + return false; + } + #else + fs_user_mount_t *fs_mount = filesystem_circuitpy(); + if (fs_mount == NULL) { + return false; + } + FATFS *fatfs = &fs_mount->fatfs; + FRESULT result = f_open(fatfs, file_handle, name, FA_READ); + return result == FR_OK; + #endif +} + +static void close_file(file_arg *file_handle) { + f_close(file_handle); +} + +static bool is_eof(file_arg *file_handle) { + return f_eof(file_handle) || f_error(file_handle); +} + +// Return 0 if there is no next character (EOF). +static uint8_t get_next_byte(FIL *file_handle) { + uint8_t character = 0; + UINT quantity_read; + // If there's an error or quantity_read is 0, character will remain 0. + f_read(file_handle, &character, 1, &quantity_read); + return character; +} + +static void seek_eof(file_arg *file_handle) { + f_lseek(file_handle, f_size(file_handle)); +} + +// For a fixed buffer, record the required size rather than throwing +static void vstr_add_byte_nonstd(vstr_t *vstr, byte b) { + if (!vstr->fixed_buf || vstr->alloc > vstr->len) { + vstr_add_byte(vstr, b); + } else { + vstr->len++; + } +} + +// For a fixed buffer, record the required size rather than throwing +static void vstr_add_char_nonstd(vstr_t *vstr, unichar c) { + size_t ulen = + (c < 0x80) ? 1 : + (c < 0x800) ? 2 : + (c < 0x10000) ? 3 : 4; + if (!vstr->fixed_buf || vstr->alloc > vstr->len + ulen) { + vstr_add_char(vstr, c); + } else { + vstr->len += ulen; + } +} + +static void next_line(file_arg *file_handle) { + uint8_t character; + do { + character = get_next_byte(file_handle); + } while (character != 0 && character != '\n'); +} + +// Discard whitespace, except for newlines, returning the next character after the whitespace. +// Return 0 if there is no next character (EOF). +static uint8_t consume_whitespace(file_arg *file_handle) { + uint8_t character; + do { + character = get_next_byte(file_handle); + } while (character != '\n' && character != 0 && unichar_isspace(character)); + return character; +} + +// Starting at the start of a new line, determines if the key matches the given key. +// +// If result is true, the key matches and file pointer is pointing just after the "=". +// If the result is false, the key does NOT match and the file pointer is +// pointing at the start of the next line, if any +static bool key_matches(file_arg *file_handle, const char *key) { + uint8_t character; + character = consume_whitespace(file_handle); + // [section] isn't implemented, so skip to end of file. + if (character == '[' || character == 0) { + seek_eof(file_handle); + return false; + } + while (*key) { + if (character != *key++) { + // A character didn't match the key, so it's not a match + // If the non-matching char was not the end of the line, + // then consume the rest of the line + if (character != '\n') { + next_line(file_handle); + } + return false; + } + character = get_next_byte(file_handle); + } + // the next character could be whitespace; consume if necessary + if (unichar_isspace(character)) { + character = consume_whitespace(file_handle); + } + // If we're not looking at the "=" then the key didn't match + if (character != '=') { + // A character didn't match the key, so it's not a match + // If the non-matching char was not the end of the line, + // then consume the rest of the line + if (character != '\n') { + next_line(file_handle); + } + return false; + } + return true; +} + +static settings_err_t read_unicode_escape(file_arg *file_handle, int sz, vstr_t *vstr) { + char hex_buf[sz + 1]; + for (int i = 0; i < sz; i++) { + hex_buf[i] = get_next_byte(file_handle); + } + hex_buf[sz] = 0; + char *end; + unsigned long c = strtoul(hex_buf, &end, 16); + if (end != &hex_buf[sz]) { + return SETTINGS_ERR_BAD_VALUE; + } + if (c >= 0x110000) { + return SETTINGS_ERR_UNICODE; + } + vstr_add_char_nonstd(vstr, c); + return SETTINGS_OK; +} + +// Read a quoted string +static settings_err_t read_string_value(file_arg *file_handle, vstr_t *vstr) { + while (true) { + int character = get_next_byte(file_handle); + switch (character) { + case 0: + case '\n': + return SETTINGS_ERR_BAD_VALUE; + + case '"': + character = consume_whitespace(file_handle); + switch (character) { + case '#': + next_line(file_handle); + MP_FALLTHROUGH; + case 0: + case '\n': + return SETTINGS_OK; + default: + return SETTINGS_ERR_BAD_VALUE; + } + + case '\\': + character = get_next_byte(file_handle); + switch (character) { + case 0: + case '\n': + return SETTINGS_ERR_BAD_VALUE; + case 'b': + character = '\b'; + break; + case 'r': + character = '\r'; + break; + case 'n': + character = '\n'; + break; + case 't': + character = '\t'; + break; + case 'v': + character = '\v'; + break; + case 'f': + character = '\f'; + break; + case 'U': + case 'u': { + int sz = (character == 'u') ? 4 : 8; + settings_err_t res; + res = read_unicode_escape(file_handle, sz, vstr); + if (res != SETTINGS_OK) { + return res; + } + continue; + } + // default falls through, other escaped characters + // represent themselves + } + MP_FALLTHROUGH; + default: + vstr_add_byte_nonstd(vstr, character); + } + } +} + +// Read a bare value (non-quoted value) as a string +// Trims leading and trailing spaces/tabs, stops at # comment or newline +static settings_err_t read_bare_value(file_arg *file_handle, vstr_t *vstr, int first_character) { + int character = first_character; + size_t trailing_space_count = 0; + + while (true) { + switch (character) { + case 0: + case '\n': + // Remove trailing spaces/tabs and \r + vstr->len -= trailing_space_count; + return SETTINGS_OK; + case '#': + // Remove trailing spaces/tabs and \r before comment + vstr->len -= trailing_space_count; + next_line(file_handle); + return SETTINGS_OK; + case ' ': + case '\t': + case '\r': + // Track potential trailing whitespace + vstr_add_byte_nonstd(vstr, character); + trailing_space_count++; + break; + default: + // Non-whitespace character resets trailing space count + vstr_add_byte_nonstd(vstr, character); + trailing_space_count = 0; + } + character = get_next_byte(file_handle); + } +} + +static mp_int_t read_value(file_arg *file_handle, vstr_t *vstr, bool *quoted) { + uint8_t character; + character = consume_whitespace(file_handle); + *quoted = (character == '"'); + + if (*quoted) { + return read_string_value(file_handle, vstr); + } else if (character == '\n' || character == 0) { + // Empty value is an error + return SETTINGS_ERR_BAD_VALUE; + } else { + return read_bare_value(file_handle, vstr, character); + } +} + +static settings_err_t settings_get_vstr(const char *key, vstr_t *vstr, bool *quoted) { + file_arg file_handle; + if (!open_file(SETTINGS_PATH, &file_handle)) { + return SETTINGS_ERR_OPEN; + } + + settings_err_t result = SETTINGS_ERR_NOT_FOUND; + while (!is_eof(&file_handle)) { + if (key_matches(&file_handle, key)) { + result = read_value(&file_handle, vstr, quoted); + break; + } + } + close_file(&file_handle); + return result; +} + +static settings_err_t settings_get_buf_terminated(const char *key, char *value, size_t value_len, bool *quoted) { + vstr_t vstr; + vstr_init_fixed_buf(&vstr, value_len, value); + settings_err_t result = settings_get_vstr(key, &vstr, quoted); + + if (result == SETTINGS_OK) { + vstr_add_byte_nonstd(&vstr, 0); + memcpy(value, vstr.buf, MIN(vstr.len, value_len)); + if (vstr.len > value_len) { // this length includes trailing NUL + result = SETTINGS_ERR_LENGTH; + } + } + return result; +} + +static void print_error(const char *key, settings_err_t result) { + switch (result) { + case SETTINGS_OK: + case SETTINGS_ERR_OPEN: + case SETTINGS_ERR_NOT_FOUND: + // These errors need not be printed. + // The code asking for the value is not necessarily expecting to find one. + return; + default: + mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("An error occurred while retrieving '%s':\n"), key); + break; + } + + switch (result) { + case SETTINGS_ERR_UNICODE: + mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("Invalid unicode escape")); + break; + case SETTINGS_ERR_BAD_VALUE: + mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("Invalid format")); + break; + default: + mp_cprintf(&mp_plat_print, MP_ERROR_TEXT("Internal error")); + break; + } + mp_printf(&mp_plat_print, "\n"); +} + + +static settings_err_t get_str(const char *key, char *value, size_t value_len) { + bool quoted; + settings_err_t result = settings_get_buf_terminated(key, value, value_len, "ed); + if (result == SETTINGS_OK && !quoted) { + result = SETTINGS_ERR_BAD_VALUE; + } + return result; +} + +settings_err_t settings_get_str(const char *key, char *value, size_t value_len) { + settings_err_t result = get_str(key, value, value_len); + print_error(key, result); + return result; +} + +static settings_err_t get_int(const char *key, mp_int_t *value) { + char buf[16]; + bool quoted; + settings_err_t result = settings_get_buf_terminated(key, buf, sizeof(buf), "ed); + if (result != SETTINGS_OK) { + return result; + } + if (quoted) { + return SETTINGS_ERR_BAD_VALUE; + } + char *end; + long num = strtol(buf, &end, 0); + while (unichar_isspace(*end)) { + end++; + } + if (end == buf || *end) { // If the whole buffer was not consumed it's an error + return SETTINGS_ERR_BAD_VALUE; + } + *value = (mp_int_t)num; + return SETTINGS_OK; +} + +settings_err_t settings_get_int(const char *key, mp_int_t *value) { + settings_err_t result = get_int(key, value); + print_error(key, result); + return result; +} + +static settings_err_t get_bool(const char *key, bool *value) { + char buf[16]; + bool quoted; + settings_err_t result = settings_get_buf_terminated(key, buf, sizeof(buf), "ed); + if (result != SETTINGS_OK) { + return result; + } + if (quoted) { + return SETTINGS_ERR_BAD_VALUE; + } + + // Check for "true" or "false" (case-sensitive) + if (strcmp(buf, "true") == 0) { + *value = true; + return SETTINGS_OK; + } else if (strcmp(buf, "false") == 0) { + *value = false; + return SETTINGS_OK; + } + + // Not a valid boolean value + return SETTINGS_ERR_BAD_VALUE; +} + +settings_err_t settings_get_bool(const char *key, bool *value) { + settings_err_t result = get_bool(key, value); + print_error(key, result); + return result; +} + +// Get the raw value as a vstr, whether quoted or bare. Value may be an invalid TOML value. +settings_err_t settings_get_raw_vstr(const char *key, vstr_t *vstr) { + bool quoted; + return settings_get_vstr(key, vstr, "ed); +} + +settings_err_t settings_get_obj(const char *key, mp_obj_t *value) { + vstr_t vstr; + vstr_init(&vstr, 32); + bool quoted; + + settings_err_t result = settings_get_vstr(key, &vstr, "ed); + if (result != SETTINGS_OK) { + return result; + } + + if (quoted) { + // Successfully parsed a quoted string + *value = mp_obj_new_str_from_vstr(&vstr); + return SETTINGS_OK; + } + + // Not a quoted string, try boolean + bool bool_val; + result = get_bool(key, &bool_val); + if (result == SETTINGS_OK) { + *value = mp_obj_new_bool(bool_val); + return SETTINGS_OK; + } + + // Not a boolean, try integer + mp_int_t int_val; + result = get_int(key, &int_val); + if (result == SETTINGS_OK) { + *value = mp_obj_new_int(int_val); + return SETTINGS_OK; + } + + return SETTINGS_ERR_BAD_VALUE; +} + +#endif diff --git a/supervisor/shared/settings.h b/supervisor/shared/settings.h new file mode 100644 index 00000000000..eafa9962e95 --- /dev/null +++ b/supervisor/shared/settings.h @@ -0,0 +1,53 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2022 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +typedef enum { + SETTINGS_OK = 0, + SETTINGS_ERR_OPEN, + SETTINGS_ERR_UNICODE, + SETTINGS_ERR_LENGTH, + SETTINGS_ERR_NOT_FOUND, + SETTINGS_ERR_BAD_VALUE, +} settings_err_t; + +// Read a string value from the settings file. +// If it fits, the return value is 0-terminated. The passed-in buffer +// may be modified even if an error is returned. Allocation free. +// An error that is not 'open' or 'not found' is printed on the repl. +// Returns an error if the value is not a quoted string. +settings_err_t settings_get_str(const char *key, char *value, size_t value_len); + +// Read an integer value from the settings file. +// Returns SETTINGS_OK and sets value to the read value. Returns +// SETTINGS_ERR_... if the value was not numeric. allocation-free. +// If any error code is returned, value is guaranteed not modified +// An error that is not 'open' or 'not found' is printed on the repl. +settings_err_t settings_get_int(const char *key, mp_int_t *value); + +// Read a boolean value from the settings file. +// Returns SETTINGS_OK and sets value to the read value. Returns +// SETTINGS_ERR_... if the value was not a boolean (true or false). allocation-free. +// If any error code is returned, value is guaranteed not modified +// An error that is not 'open' or 'not found' is printed on the repl. +settings_err_t settings_get_bool(const char *key, bool *value); + +// Read a value from the settings file and return as parsed Python object. +// Returns SETTINGS_OK and sets value to a parsed Python object from the RHS value: +// - Quoted strings return as str +// - Bare "true" or "false" return as bool +// - Valid integers return as int +// Returns SETTINGS_ERR_... if the value is not parseable as one of these types. +// An error that is not 'open' or 'not found' is printed on the repl. +settings_err_t settings_get_obj(const char *key, mp_obj_t *value); + +// Read the raw value as a string, whether quoted or bare. +// This is used by os.getenv() to always return strings. +// Does not print errors. +settings_err_t settings_get_raw_vstr(const char *key, vstr_t *vstr); diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index 553fe8694c6..74e4fed5759 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -46,8 +46,8 @@ #include "shared-bindings/wifi/__init__.h" #endif -#if CIRCUITPY_OS_GETENV -#include "shared-module/os/__init__.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" #endif enum request_state { @@ -237,21 +237,21 @@ void supervisor_web_workflow_status(void) { #endif bool supervisor_start_web_workflow(void) { - #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_OS_GETENV + #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML char ssid[33]; char password[64]; - os_getenv_err_t result = common_hal_os_getenv_str("CIRCUITPY_WIFI_SSID", ssid, sizeof(ssid)); - if (result != GETENV_OK || strlen(ssid) < 1) { + settings_err_t result = settings_get_str("CIRCUITPY_WIFI_SSID", ssid, sizeof(ssid)); + if (result != SETTINGS_OK || strlen(ssid) < 1) { return false; } - result = common_hal_os_getenv_str("CIRCUITPY_WIFI_PASSWORD", password, sizeof(password)); - if (result == GETENV_ERR_NOT_FOUND) { + result = settings_get_str("CIRCUITPY_WIFI_PASSWORD", password, sizeof(password)); + if (result == SETTINGS_ERR_NOT_FOUND) { // if password is unspecified, assume an open network password[0] = '\0'; - } else if (result != GETENV_OK) { + } else if (result != SETTINGS_OK) { return false; } @@ -289,17 +289,17 @@ bool supervisor_start_web_workflow(void) { bool initialized = pool.base.type == &socketpool_socketpool_type; if (!initialized) { - result = common_hal_os_getenv_str("CIRCUITPY_WEB_INSTANCE_NAME", web_instance_name, sizeof(web_instance_name)); - if (result != GETENV_OK || web_instance_name[0] == '\0') { + result = settings_get_str("CIRCUITPY_WEB_INSTANCE_NAME", web_instance_name, sizeof(web_instance_name)); + if (result != SETTINGS_OK || web_instance_name[0] == '\0') { strcpy(web_instance_name, MICROPY_HW_BOARD_NAME); } // (leaves new_port unchanged on any failure) - (void)common_hal_os_getenv_int("CIRCUITPY_WEB_API_PORT", &web_api_port); + (void)settings_get_int("CIRCUITPY_WEB_API_PORT", &web_api_port); const size_t api_password_len = sizeof(_api_password) - 1; - result = common_hal_os_getenv_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); - if (result == GETENV_OK) { + result = settings_get_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); + if (result == SETTINGS_OK) { _api_password[0] = ':'; _base64_in_place(_api_password, strlen(_api_password), sizeof(_api_password) - 1); } else { // Skip starting web-workflow when no password is passed. diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 9ebdd52068e..bce47353f57 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -19,6 +19,10 @@ SRC_SUPERVISOR = \ supervisor/shared/translate/translate.c \ supervisor/shared/workflow.c \ +ifeq ($(CIRCUITPY_SETTINGS_TOML),1) +SRC_SUPERVISOR += supervisor/shared/settings.c +endif + ifeq ($(CIRCUITPY_LIB_TLSF),1) SRC_SUPERVISOR += lib/tlsf/tlsf.c endif diff --git a/tests/circuitpython/getenv.py b/tests/circuitpython/getenv.py index 37819dd6f5f..3647b562eed 100644 --- a/tests/circuitpython/getenv.py +++ b/tests/circuitpython/getenv.py @@ -58,7 +58,7 @@ def ioctl(self, op, arg): b'key = """\n', b"key =\n", b'key="', - b"key = strings must be quoted\n", + b"key = this is an unquoted string\n", ] @@ -75,6 +75,7 @@ def run_test(key, content): run_test("key", b"") +# key12 does not exist for i in range(13): run_test(f"key{i}", content_good) @@ -82,11 +83,9 @@ def run_test(key, content): for i in range(13): run_test(f"key{i}", content_good) -run_test(f"K", b"K = 7\r\n") -print(getenv_int("K")) - # Test value without trailing newline run_test(f"noeol", b"noeol=3") +# These return None now for content in content_bad: run_test("key", content) diff --git a/tests/circuitpython/getenv.py.exp b/tests/circuitpython/getenv.py.exp index 67707eb67fd..89d654403dc 100644 --- a/tests/circuitpython/getenv.py.exp +++ b/tests/circuitpython/getenv.py.exp @@ -1,6 +1,6 @@ key None key0 'hello world' -key1 7 +key1 '7' key2 '\n' key3 'Áx' key4 'Áx' @@ -9,11 +9,11 @@ key6 '\t\r\x08' key7 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' key8 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' key9 'hello comment' -key10 127 -key11 0 +key10 '0x7f' +key11 '0' key12 None key0 'hello world' -key1 7 +key1 '7' key2 '\n' key3 'Áx' key4 'Áx' @@ -22,14 +22,12 @@ key6 '\t\r\x08' key7 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' key8 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' key9 'hello comment' -key10 127 -key11 0 +key10 '0x7f' +key11 '0' key12 None -K 7 -7 -noeol 3 -key Invalid byte '\n' -key Invalid byte '"' -key invalid syntax for integer with base 10: '' -key Invalid byte 'EOF' -key invalid syntax for integer with base 10: 'strings must be quoted' +noeol '3' +key None +key None +key None +key None +key 'this is an unquoted string' From 7bb0c022560d9c6a3535b5d5d6a28ecb533d87cd Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 16 Feb 2026 14:46:58 -0500 Subject: [PATCH 208/876] add port_yield from #10795 only on zephyr to fix #10822 --- supervisor/shared/background_callback.c | 6 ++++++ supervisor/shared/safe_mode.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c index 02aa9ae84d5..79b18f7a137 100644 --- a/supervisor/shared/background_callback.c +++ b/supervisor/shared/background_callback.c @@ -61,7 +61,10 @@ static int background_prevention_count; void PLACE_IN_ITCM(background_callback_run_all)(void) { port_background_task(); if (!background_callback_pending()) { + // TEMPORARY to fix #10822 + #ifdef __ZEPHYR__ port_yield(); + #endif return; } CALLBACK_CRITICAL_BEGIN; @@ -88,7 +91,10 @@ void PLACE_IN_ITCM(background_callback_run_all)(void) { } --background_prevention_count; CALLBACK_CRITICAL_END; + // TEMPORARY to fix #10822 + #ifdef __ZEPHYR__ port_yield(); + #endif } void background_callback_prevent(void) { diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 96505565460..bfe27ac7c65 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -82,7 +82,10 @@ safe_mode_t wait_for_safe_mode_reset(void) { boot_in_safe_mode = true; break; } + // TEMPORARY to fix #10822 + #ifdef __ZEPHYR__ port_yield(); + #endif diff = supervisor_ticks_ms64() - start_ticks; } #if CIRCUITPY_STATUS_LED From f4cc5f5a7aff7a5fa4dd6a66e36bfd85162dcad7 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 16 Feb 2026 16:07:03 -0500 Subject: [PATCH 209/876] shrink pygamer --- ports/atmel-samd/boards/pygamer/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/boards/pygamer/mpconfigboard.mk b/ports/atmel-samd/boards/pygamer/mpconfigboard.mk index 19fa4f19b9d..0c6f16f8b63 100644 --- a/ports/atmel-samd/boards/pygamer/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pygamer/mpconfigboard.mk @@ -12,6 +12,7 @@ LONGINT_IMPL = MPZ CIRCUITPY_AESIO = 0 CIRCUITPY_FLOPPYIO = 0 +CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_GIFIO = 0 CIRCUITPY_I2CDISPLAYBUS = 0 From 4ec807fc3ddffeb869e070ed26e517cc8dc1be9a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 16 Feb 2026 19:21:53 -0500 Subject: [PATCH 210/876] update to arm gcc 15.2Rel1 --- .github/actions/deps/external/action.yml | 2 +- .github/actions/deps/ports/broadcom/action.yml | 4 ++-- .github/workflows/build.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/deps/external/action.yml b/.github/actions/deps/external/action.yml index 10aace1134e..564c851cfc9 100644 --- a/.github/actions/deps/external/action.yml +++ b/.github/actions/deps/external/action.yml @@ -27,7 +27,7 @@ runs: uses: carlosperate/arm-none-eabi-gcc-action@v1 with: # When changing this update what Windows grabs too! - release: '14.2.Rel1' + release: '15.2.Rel1' # espressif - name: Get espressif toolchain diff --git a/.github/actions/deps/ports/broadcom/action.yml b/.github/actions/deps/ports/broadcom/action.yml index 9ad0e361bda..fc375aa10f7 100644 --- a/.github/actions/deps/ports/broadcom/action.yml +++ b/.github/actions/deps/ports/broadcom/action.yml @@ -5,8 +5,8 @@ runs: steps: - name: Get broadcom toolchain run: | - wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/arm-gnu-toolchain-14.2.rel1-x86_64-aarch64-none-elf.tar.xz - sudo tar -C /usr --strip-components=1 -xaf arm-gnu-toolchain-14.2.rel1-x86_64-aarch64-none-elf.tar.xz + wget --no-verbose https://adafruit-circuit-python.s3.amazonaws.com/arm-gnu-toolchain-15.2.rel1-x86_64-aarch64-none-elf.tar.xz + sudo tar -C /usr --strip-components=1 -xaf arm-gnu-toolchain-15.2.rel1-x86_64-aarch64-none-elf.tar.xz sudo apt-get update sudo apt-get install -y mtools shell: bash diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fbd3af440c6..5b755eb398e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -246,7 +246,7 @@ jobs: python3 -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))" - name: Install dependencies run: | - wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-mingw-w64-i686-arm-none-eabi.zip + wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi.zip unzip -q -d /tmp/arm-gnu-toolchain gcc-arm.zip tar -C /tmp/arm-gnu-toolchain -cf - . | tar -C /usr/local -xf - # We could use a venv instead, but that requires entering the venv on each run step From 40abcd180028a20df940939a4347a8cc765015e9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 17 Feb 2026 08:31:18 -0500 Subject: [PATCH 211/876] update .devcontainer to gcc 15.2 --- .devcontainer/cortex-m-toolchain.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/cortex-m-toolchain.sh b/.devcontainer/cortex-m-toolchain.sh index 10896abd08c..56be006544f 100755 --- a/.devcontainer/cortex-m-toolchain.sh +++ b/.devcontainer/cortex-m-toolchain.sh @@ -14,10 +14,10 @@ echo -e "[cortex-m-toolchain.sh] downloading and installing gcc-arm-non-eabi too cd /workspaces wget -qO gcc-arm-none-eabi.tar.xz \ - https://developer.arm.com/-/media/Files/downloads/gnu/14.2.rel1/binrel/arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi.tar.xz + https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi.tar.xz tar -xJf gcc-arm-none-eabi.tar.xz -ln -s arm-gnu-toolchain-14.2.rel1-x86_64-arm-none-eabi gcc-arm-none-eabi +ln -s arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi gcc-arm-none-eabi rm -f gcc-arm-none-eabi.tar.xz echo -e "[cortex-m-toolchain.sh] update PATH in environment" From 3840b81946072d3d06f6689a2aba95d041df2a71 Mon Sep 17 00:00:00 2001 From: mimi89999 Date: Tue, 17 Feb 2026 17:22:31 +0100 Subject: [PATCH 212/876] Use TRNG as additional entropy source on RP2350 --- ports/raspberrypi/common-hal/os/__init__.c | 153 +++++++++++++++++++-- 1 file changed, 139 insertions(+), 14 deletions(-) diff --git a/ports/raspberrypi/common-hal/os/__init__.c b/ports/raspberrypi/common-hal/os/__init__.c index 616bb8d8c79..d2a8da4caef 100644 --- a/ports/raspberrypi/common-hal/os/__init__.c +++ b/ports/raspberrypi/common-hal/os/__init__.c @@ -18,35 +18,159 @@ #include +#ifdef HAS_RP2350_TRNG +#include "hardware/structs/trng.h" +#include "hardware/sync.h" +#endif + // NIST Special Publication 800-90B (draft) recommends several extractors, // including the SHA hash family and states that if the amount of entropy input // is twice the number of bits output from them, that output can be considered -// essentially fully random. If every RANDOM_SAFETY_MARGIN bits from -// `rosc_hw->randombit` have at least 1 bit of entropy, then this criterion is met. +// essentially fully random. +// +// This works by seeding `random_state` with entropy from hardware sources +// (SHA-256 as the conditioning function), then using that state as a counter +// input (SHA-256 as a CSPRNG), re-seeding at least every 256 blocks (8kB). // -// This works by seeding the `random_state` with plenty of random bits (SHA256 -// as entropy harvesting function), then using that state it as a counter input -// (SHA256 as a CSPRNG), re-seeding at least every 256 blocks (8kB). +// On RP2350, entropy comes from both the dedicated TRNG peripheral and the +// ROSC. On RP2040, the ROSC is the only available source. // // In practice, `PractRand` doesn't detect any gross problems with the output // random numbers on samples of 1 to 8 megabytes, no matter the setting of -// RANDOM_SAFETY_MARGIN. (it does detect "unusual" results from time to time, +// ROSC_SAFETY_MARGIN. (it does detect "unusual" results from time to time, // as it will with any RNG) -#define RANDOM_SAFETY_MARGIN (4) + +// Number of ROSC collection rounds on RP2040. Each round feeds +// SHA256_BLOCK_SIZE bytes into the hash; we do 2*N rounds so the +// raw-to-output ratio satisfies 800-90B's 2:1 minimum. +#define ROSC_SAFETY_MARGIN (4) static BYTE random_state[SHA256_BLOCK_SIZE]; + +// Collect `count` bytes from the ROSC, one bit per read. +static void rosc_random_bytes(BYTE *buf, size_t count) { + for (size_t i = 0; i < count; i++) { + buf[i] = rosc_hw->randombit & 1; + for (int k = 0; k < 8; k++) { + buf[i] = (buf[i] << 1) ^ (rosc_hw->randombit & 1); + } + } +} + +#ifdef HAS_RP2350_TRNG + +// TRNG_DEBUG_CONTROL bypass bits: +// +// bit 1 VNC_BYPASS Von Neumann corrector +// bit 2 TRNG_CRNGT_BYPASS Continuous Random Number Generator Test +// bit 3 AUTO_CORRELATE_BYPASS Autocorrelation test +// +// We bypass Von Neumann and autocorrelation but keep CRNGT. +// +// Von Neumann (bypassed): ~4x throughput cost for bias removal. +// Redundant here because SHA-256 conditioning already handles +// biased input -- that's what the 2:1 oversampling ratio is for. +// +// Autocorrelation (bypassed): has a non-trivial false-positive rate +// at high sampling speeds and halts the TRNG until SW reset on +// failure. SHA-256 is not bothered by correlated input. ARM's own +// TZ-TRNG 90B reference configuration also bypasses it (0x0A). +// +// CRNGT (kept): compares consecutive 192-bit EHR outputs. Flags if +// identical -- false-positive rate 2^-192, throughput cost zero. +// This is our early warning for a stuck oscillator or a successful +// injection lock to a fixed state. +#define TRNG_BYPASS_BITS \ + (TRNG_TRNG_DEBUG_CONTROL_VNC_BYPASS_BITS | \ + TRNG_TRNG_DEBUG_CONTROL_AUTO_CORRELATE_BYPASS_BITS) + +// Collect 192 raw bits (6 x 32-bit words) from the TRNG. +// Returns false on CRNGT failure (consecutive identical EHR outputs). +// +// Holds PICO_SPINLOCK_ID_RAND (the SDK's lock for this peripheral) +// with interrupts disabled for the duration of the collection, which +// takes ~192 ROSC cycles (~24us at 8MHz). +static bool trng_collect_192(uint32_t out[6]) { + spin_lock_t *lock = spin_lock_instance(PICO_SPINLOCK_ID_RAND); + uint32_t save = spin_lock_blocking(lock); + + trng_hw->trng_debug_control = TRNG_BYPASS_BITS; + // One rng_clk cycle between samples. The SDK uses 0 here, but it + // also sets debug_control = -1u (full bypass). The behavior of + // sample_cnt1 = 0 with health tests still active is undocumented, + // so we use 1 to be safe. + trng_hw->sample_cnt1 = 1; + trng_hw->rnd_source_enable = 1; + trng_hw->rng_icr = 0xFFFFFFFF; + + while (trng_hw->trng_busy) { + } + + if (trng_hw->rng_isr & TRNG_RNG_ISR_CRNGT_ERR_BITS) { + // Drain ehr_data so the hardware starts a fresh collection. + // (Reading the last word clears the valid flag.) + for (int i = 0; i < 6; i++) { + (void)trng_hw->ehr_data[i]; + } + trng_hw->rng_icr = TRNG_RNG_ISR_CRNGT_ERR_BITS; + spin_unlock(lock, save); + return false; + } + + for (int i = 0; i < 6; i++) { + out[i] = trng_hw->ehr_data[i]; + } + + // Switch the inverter chain length for the next collection, using + // bits from the sample we just read. Only bits [1:0] matter -- they + // select one of four chain lengths, changing the ROSC frequency. + // This is borrowed from pico_rand's injection-locking countermeasure. + // (The SDK uses its PRNG state here instead of raw output; either + // works since the real defense is SHA-256 conditioning, not this.) + trng_hw->trng_config = out[0]; + + spin_unlock(lock, save); + return true; +} + +#endif // HAS_RP2350_TRNG + static void seed_random_bits(BYTE out[SHA256_BLOCK_SIZE]) { CRYAL_SHA256_CTX context; sha256_init(&context); - for (int i = 0; i < 2 * RANDOM_SAFETY_MARGIN; i++) { - for (int j = 0; j < SHA256_BLOCK_SIZE; j++) { - out[j] = rosc_hw->randombit & 1; - for (int k = 0; k < 8; k++) { - out[j] = (out[j] << 1) ^ (rosc_hw->randombit & 1); + + #ifdef HAS_RP2350_TRNG + // 384 bits from TRNG + 384 bits from ROSC = 768 bits into the hash, + // giving a 3:1 ratio over the 256-bit output (800-90B wants >= 2:1). + // Two independent sources so a failure in one doesn't zero the input. + + // TRNG: 2 x 192 bits. + for (int i = 0; i < 2; i++) { + uint32_t trng_buf[6] = {0}; + for (int attempt = 0; attempt < 3; attempt++) { + if (trng_collect_192(trng_buf)) { + break; } + // CRNGT failure. If all 3 retries fail, trng_buf stays zeroed + // and we rely entirely on the ROSC contribution below. } + sha256_update(&context, (const BYTE *)trng_buf, sizeof(trng_buf)); + } + + // ROSC: 2 x 24 bytes = 384 bits. + for (int i = 0; i < 2; i++) { + BYTE rosc_buf[24]; + rosc_random_bytes(rosc_buf, sizeof(rosc_buf)); + sha256_update(&context, rosc_buf, sizeof(rosc_buf)); + } + #else + // RP2040: ROSC is the only entropy source. + for (int i = 0; i < 2 * ROSC_SAFETY_MARGIN; i++) { + rosc_random_bytes(out, SHA256_BLOCK_SIZE); sha256_update(&context, out, SHA256_BLOCK_SIZE); } + #endif + sha256_final(&context, out); } @@ -61,10 +185,11 @@ static void get_random_bits(BYTE out[SHA256_BLOCK_SIZE]) { } bool common_hal_os_urandom(uint8_t *buffer, mp_uint_t length) { -#define ROSC_POWER_SAVE (1) // assume ROSC is not necessarily active all the time + #define ROSC_POWER_SAVE (1) // assume ROSC is not necessarily active all the time #if ROSC_POWER_SAVE uint32_t old_rosc_ctrl = rosc_hw->ctrl; - rosc_hw->ctrl = (old_rosc_ctrl & ~ROSC_CTRL_ENABLE_BITS) | (ROSC_CTRL_ENABLE_VALUE_ENABLE << 12); + rosc_hw->ctrl = (old_rosc_ctrl & ~ROSC_CTRL_ENABLE_BITS) + | (ROSC_CTRL_ENABLE_VALUE_ENABLE << ROSC_CTRL_ENABLE_LSB); #endif while (length) { size_t n = MIN(length, SHA256_BLOCK_SIZE); From d85a4fc9975817c7e382a3dd9bb62e161bb55753 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 17 Feb 2026 11:25:07 -0500 Subject: [PATCH 213/876] remove unneeded -fno-inline-functions and -ggdb3; fix cxd56 noreturn warning --- ports/cxd56/Makefile | 2 +- ports/cxd56/common-hal/microcontroller/__init__.c | 2 ++ ports/litex/Makefile | 2 +- ports/nordic/Makefile | 4 ++-- ports/silabs/Makefile | 2 +- ports/stm/Makefile | 3 +-- 6 files changed, 8 insertions(+), 7 deletions(-) diff --git a/ports/cxd56/Makefile b/ports/cxd56/Makefile index c4526f31252..88c39210220 100644 --- a/ports/cxd56/Makefile +++ b/ports/cxd56/Makefile @@ -74,7 +74,7 @@ CFLAGS += \ -fdata-sections \ -Wall \ -OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions +OPTIMIZATION_FLAGS ?= -O2 # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk CFLAGS += $(OPTIMIZATION_FLAGS) diff --git a/ports/cxd56/common-hal/microcontroller/__init__.c b/ports/cxd56/common-hal/microcontroller/__init__.c index fa872f2807b..f7ac0c174ae 100644 --- a/ports/cxd56/common-hal/microcontroller/__init__.c +++ b/ports/cxd56/common-hal/microcontroller/__init__.c @@ -61,6 +61,8 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { void common_hal_mcu_reset(void) { filesystem_flush(); boardctl(BOARDIOC_RESET, 0); + // boardctl is noreturn in this case. + __builtin_unreachable(); } static const mp_rom_map_elem_t mcu_pin_globals_table[] = { diff --git a/ports/litex/Makefile b/ports/litex/Makefile index 940d751e3d9..cc813a49f8e 100644 --- a/ports/litex/Makefile +++ b/ports/litex/Makefile @@ -32,7 +32,7 @@ ifeq ($(DEBUG), 1) OPTIMIZATION_FLAGS ?= -Og else CFLAGS += -DNDEBUG -ggdb3 - OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions + OPTIMIZATION_FLAGS ?= -O2 endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index 0d8d8878f4c..1e283fc699c 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -36,8 +36,8 @@ ifeq ($(DEBUG), 1) CFLAGS += -ggdb3 OPTIMIZATION_FLAGS = -Og else - OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions - CFLAGS += -DNDEBUG -ggdb3 + OPTIMIZATION_FLAGS ?= -O2 + CFLAGS += -DNDEBUG endif ifeq ($(NRF_DEBUG_PRINT), 1) diff --git a/ports/silabs/Makefile b/ports/silabs/Makefile index 34b6346d0d4..810ab53f1f3 100644 --- a/ports/silabs/Makefile +++ b/ports/silabs/Makefile @@ -71,7 +71,7 @@ ifeq ($(DEBUG), 1) CFLAGS += -fno-inline -fno-ipa-sra -Og else CFLAGS += -DNDEBUG - OPTIMIZATION_FLAGS ?= -Os -fno-inline-functions + OPTIMIZATION_FLAGS ?= -Os CFLAGS += -g endif diff --git a/ports/stm/Makefile b/ports/stm/Makefile index c0e64e2339d..2ed3bddb5b7 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -38,8 +38,7 @@ ifeq ($(DEBUG), 1) CFLAGS += -fno-inline -fno-ipa-sra else CFLAGS += -DNDEBUG - OPTIMIZATION_FLAGS ?= -O2 -fno-inline-functions - CFLAGS += -ggdb3 + OPTIMIZATION_FLAGS ?= -O2 endif # to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk From 2dee1904c7efd927139effede8da8634fbb7146e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 17 Feb 2026 13:09:45 -0500 Subject: [PATCH 214/876] -Os for some stm boards --- .../boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk | 1 + ports/stm/mpconfigport.mk | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk b/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk index 64be6f4f142..c46a270df65 100644 --- a/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk +++ b/ports/stm/boards/stm32f411ce_blackpill_with_flash/mpconfigboard.mk @@ -9,6 +9,7 @@ EXTERNAL_FLASH_DEVICES = GD25Q16C,W25Q16JVxQ,W25Q64FV,W25Q32JVxQ,W25Q64JVxQ LONGINT_IMPL = MPZ INTERNAL_FLASH_FILESYSTEM = 0 +OPTIMIZATION_FLAGS = -Os MCU_SERIES = F4 MCU_VARIANT = STM32F411xE diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk index 83759fc5d24..96724a52960 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -10,6 +10,10 @@ ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32F405xx STM32F407xx)) USB_NUM_ENDPOINT_PAIRS = 4 endif +ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) + OPTIMIZATION_FLAGS ?= -Os +endif + ifeq ($(MCU_VARIANT),STM32F407xx) UF2_FAMILY_ID ?= 0x6d0922fa endif From fce9ce6c2829226df67b329bedc59307570345cb Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 17 Feb 2026 23:31:29 +0100 Subject: [PATCH 215/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 25 +++++++++++-------------- locale/el.po | 18 ++++-------------- locale/hi.po | 18 ++++-------------- locale/ko.po | 25 +++++++++++-------------- locale/ru.po | 25 +++++++++++-------------- locale/tr.po | 18 ++++-------------- 6 files changed, 45 insertions(+), 84 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index ec160f6bdd3..24dc4292753 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -594,7 +594,7 @@ msgstr "Již běží" msgid "Already scanning for wifi networks" msgstr "Již skenuje wifi sítě" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "Došlo k chybě při načítání '%s'\n" @@ -1110,7 +1110,6 @@ msgid "File exists" msgstr "soubor existuje" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "Soubor nenalezen" @@ -1263,7 +1262,7 @@ msgstr "Interní audio buffer je příliš malý" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c msgid "Internal error" msgstr "Interní chyba" @@ -1360,17 +1359,12 @@ msgstr "Neplatný argument" msgid "Invalid bits per value" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "Špatný byte %.*s" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "Chybný data_pin[%d]" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "Špatný formát" @@ -1401,7 +1395,7 @@ msgstr "Chybný soket pro TLS" msgid "Invalid state" msgstr "Chybný stav" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "Neplatná unicode escape sekvence" @@ -1409,10 +1403,6 @@ msgstr "Neplatná unicode escape sekvence" msgid "Key must be 16, 24, or 32 bytes long" msgstr "Klíč musí být dlouhý 16, 24 nebo 32 bajtů" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "Klíč nenalezen" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "Mapování LED musí korespondovat s velikostí displeje" @@ -4615,6 +4605,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "Invalid byte %.*s" +#~ msgstr "Špatný byte %.*s" + +#~ msgid "Key not found" +#~ msgstr "Klíč nenalezen" + #, c-format #~ msgid "%%c requires int or char" #~ msgstr "%%c vyžaduje int nebo char" diff --git a/locale/el.po b/locale/el.po index 7b1a182690e..016fb3a381e 100644 --- a/locale/el.po +++ b/locale/el.po @@ -598,7 +598,7 @@ msgstr "Τρέχει ήδη" msgid "Already scanning for wifi networks" msgstr "Ήδη γίνεται σάρωση για δίκτυα wifi" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "Παρουσιάστηκε σφάλμα κατά την ανάκτηση '%s':\n" @@ -1118,7 +1118,6 @@ msgid "File exists" msgstr "" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "" @@ -1269,7 +1268,7 @@ msgstr "" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1366,17 +1365,12 @@ msgstr "" msgid "Invalid bits per value" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "" @@ -1407,7 +1401,7 @@ msgstr "" msgid "Invalid state" msgstr "" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "" @@ -1415,10 +1409,6 @@ msgstr "" msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index c11116b34f6..be00c7cf1c9 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -585,7 +585,7 @@ msgstr "" msgid "Already scanning for wifi networks" msgstr "" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "" @@ -1094,7 +1094,6 @@ msgid "File exists" msgstr "" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "" @@ -1245,7 +1244,7 @@ msgstr "" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1342,17 +1341,12 @@ msgstr "" msgid "Invalid bits per value" msgstr "" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "" @@ -1383,7 +1377,7 @@ msgstr "" msgid "Invalid state" msgstr "" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "" @@ -1391,10 +1385,6 @@ msgstr "" msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 99c62684dc6..8e96781ed27 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -622,7 +622,7 @@ msgstr "이미 실행 중입니다" msgid "Already scanning for wifi networks" msgstr "이미 wifi 네트워크를 찾고 있습니다" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "%s'을(를) 검색하는 동안 오류가 발생했습니다:\n" @@ -1143,7 +1143,6 @@ msgid "File exists" msgstr "파일이 있습니다" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "파일을 찾을 수 없습니다" @@ -1296,7 +1295,7 @@ msgstr "내부 오디오 버퍼가 너무 작습니다" msgid "Internal define error" msgstr "내부 정의 오류" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c msgid "Internal error" msgstr "내부 오류" @@ -1393,17 +1392,12 @@ msgstr "잘못된 인수" msgid "Invalid bits per value" msgstr "값 당 잘못된 비트" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "잘못된 바이트 %.*s" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "잘못된 data_pins[%d]" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "잘못된 형식" @@ -1434,7 +1428,7 @@ msgstr "TLS에 대한 잘못된 소켓" msgid "Invalid state" msgstr "잘못된 상태" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "잘못된 유니코드 이스케이프" @@ -1442,10 +1436,6 @@ msgstr "잘못된 유니코드 이스케이프" msgid "Key must be 16, 24, or 32 bytes long" msgstr "키는 16, 24, 또는 32 바이트 길이여야 합니다" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "키를 찾을 수 없습니다" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "LED 매핑은 디스플레이 크기와 일치해야 합니다" @@ -4662,6 +4652,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "Invalid byte %.*s" +#~ msgstr "잘못된 바이트 %.*s" + +#~ msgid "Key not found" +#~ msgstr "키를 찾을 수 없습니다" + #, fuzzy #~ msgid "Not supported JPEG standard" #~ msgstr "지원되지 않는 JPEG 표준" diff --git a/locale/ru.po b/locale/ru.po index cf83523e82c..cff7a97b396 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -598,7 +598,7 @@ msgstr "Уже запущен" msgid "Already scanning for wifi networks" msgstr "Поиск сетей wifi уже происходит" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "Произошла ошибка при получении '%s':\n" @@ -1123,7 +1123,6 @@ msgid "File exists" msgstr "Файл существует" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "Файл не найден" @@ -1284,7 +1283,7 @@ msgstr "Внутренний звуковой буфер слишком мал" msgid "Internal define error" msgstr "Внутренняя ошибка определения" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c msgid "Internal error" msgstr "Внутренняя ошибка" @@ -1381,17 +1380,12 @@ msgstr "Недопустимый аргумент" msgid "Invalid bits per value" msgstr "Недопустимое бит-на-значение" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "Неверный байт %.*s" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "Неверный data_pins[%d]" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "Недопустимый формат" @@ -1422,7 +1416,7 @@ msgstr "Неверный сокет для TLS" msgid "Invalid state" msgstr "Неверное состояние" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "Недопустимое экранирование Юникода" @@ -1430,10 +1424,6 @@ msgstr "Недопустимое экранирование Юникода" msgid "Key must be 16, 24, or 32 bytes long" msgstr "Ключ должен быть длинной 16, 24 или 32 байта" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "Ключ не найден" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "Светодиодные сопоставления должны соответствовать размеру дисплея" @@ -4681,6 +4671,13 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#, c-format +#~ msgid "Invalid byte %.*s" +#~ msgstr "Неверный байт %.*s" + +#~ msgid "Key not found" +#~ msgstr "Ключ не найден" + #~ msgid "Not supported JPEG standard" #~ msgstr "Не поддерживается Стандарт JPEG" diff --git a/locale/tr.po b/locale/tr.po index f8db30f3893..0449d8d1261 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -596,7 +596,7 @@ msgstr "Halihazırda çalışıyor" msgid "Already scanning for wifi networks" msgstr "Halihazırda wifi ağları için tarama yapılıyor" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" msgstr "" @@ -1108,7 +1108,6 @@ msgid "File exists" msgstr "Dosya var" #: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -#: shared-module/os/getenv.c msgid "File not found" msgstr "" @@ -1263,7 +1262,7 @@ msgstr "Dahili ses arabelleği çok küçük" msgid "Internal define error" msgstr "Dahili tanımlama hatası" -#: shared-bindings/pwmio/PWMOut.c shared-module/os/getenv.c +#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c msgid "Internal error" msgstr "Dahili hata" @@ -1361,17 +1360,12 @@ msgstr "Geçersiz argüman" msgid "Invalid bits per value" msgstr "Geçersiz bit başına değer" -#: shared-module/os/getenv.c -#, c-format -msgid "Invalid byte %.*s" -msgstr "" - #: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format msgid "Invalid data_pins[%d]" msgstr "Geçersiz veri_pini [%d]" -#: shared-module/msgpack/__init__.c +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c msgid "Invalid format" msgstr "" @@ -1402,7 +1396,7 @@ msgstr "TLS için geçersiz soket" msgid "Invalid state" msgstr "Geçersiz durum" -#: shared-module/os/getenv.c +#: supervisor/shared/settings.c msgid "Invalid unicode escape" msgstr "" @@ -1410,10 +1404,6 @@ msgstr "" msgid "Key must be 16, 24, or 32 bytes long" msgstr "Anahtar 16, 24 veya 32 bayt uzunluğunda olmalıdır" -#: shared-module/os/getenv.c -msgid "Key not found" -msgstr "" - #: shared-module/is31fl3741/FrameBuffer.c msgid "LED mappings must match display size" msgstr "LED eşlemeleri ekran boyutuyla eşleşmelidir" From 757e3a3ff75e56d228bd724696e034271d615578 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 23 Jan 2026 09:34:51 -0800 Subject: [PATCH 216/876] Add basic _bleio implementation for zephyr-cp port Adds basic scanning and advertising support. Uses BabbleSim to test on a host computer. --- .github/workflows/run-tests.yml | 5 + .gitignore | 3 + AGENTS.md | 3 + locale/circuitpython.pot | 6 + ports/zephyr-cp/AGENTS.md | 5 + ports/zephyr-cp/Kconfig.sysbuild | 1 + ports/zephyr-cp/Makefile | 6 +- ports/zephyr-cp/boards/board_aliases.cmake | 4 + ports/zephyr-cp/boards/da14695_dk_usb.conf | 20 + ports/zephyr-cp/boards/da14695_dk_usb.overlay | 10 + ports/zephyr-cp/boards/frdm_rw612.conf | 46 ++ ports/zephyr-cp/boards/frdm_rw612.overlay | 11 + .../native/native_sim/autogen_board_info.toml | 2 +- .../nrf5340bsim/autogen_board_info.toml | 115 +++++ .../native/nrf5340bsim/circuitpython.toml | 1 + .../nordic/nrf5340dk/autogen_board_info.toml | 4 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 2 +- .../nordic/nrf7002dk/autogen_board_info.toml | 4 +- .../boards/nrf5340bsim_nrf5340_cpuapp.conf | 26 ++ .../boards/nrf5340bsim_nrf5340_cpuapp.overlay | 28 ++ .../boards/nrf5340dk_nrf5340_cpuapp.conf | 14 + .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 7 + .../boards/nrf7002dk_nrf5340_cpuapp.conf | 4 + .../nxp/frdm_mcxn947/autogen_board_info.toml | 2 +- .../nxp/frdm_rw612/autogen_board_info.toml | 114 +++++ .../boards/nxp/frdm_rw612/circuitpython.toml | 5 + .../mimxrt1170_evk/autogen_board_info.toml | 2 +- .../da14695_dk_usb/autogen_board_info.toml | 114 +++++ .../renesas/da14695_dk_usb/circuitpython.toml | 1 + .../renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../boards/renesas_da14695_dk_usb.conf | 20 + .../nucleo_n657x0_q/autogen_board_info.toml | 2 +- .../nucleo_u575zi_q/autogen_board_info.toml | 2 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 2 +- .../stm32wba65i_dk1/autogen_board_info.toml | 115 +++++ .../st/stm32wba65i_dk1/circuitpython.toml | 1 + ports/zephyr-cp/boards/stm32wba65i_dk1.conf | 24 + .../zephyr-cp/boards/stm32wba65i_dk1.overlay | 63 +++ ports/zephyr-cp/common-hal/_bleio/Adapter.c | 412 ++++++++++++++++++ ports/zephyr-cp/common-hal/_bleio/Adapter.h | 29 ++ ports/zephyr-cp/common-hal/_bleio/Attribute.c | 7 + ports/zephyr-cp/common-hal/_bleio/Attribute.h | 9 + .../common-hal/_bleio/Characteristic.c | 66 +++ .../common-hal/_bleio/Characteristic.h | 39 ++ .../common-hal/_bleio/CharacteristicBuffer.c | 72 +++ .../common-hal/_bleio/CharacteristicBuffer.h | 18 + .../zephyr-cp/common-hal/_bleio/Connection.c | 56 +++ .../zephyr-cp/common-hal/_bleio/Connection.h | 48 ++ .../zephyr-cp/common-hal/_bleio/Descriptor.c | 29 ++ .../zephyr-cp/common-hal/_bleio/Descriptor.h | 23 + .../common-hal/_bleio/PacketBuffer.c | 65 +++ .../common-hal/_bleio/PacketBuffer.h | 20 + ports/zephyr-cp/common-hal/_bleio/Service.c | 45 ++ ports/zephyr-cp/common-hal/_bleio/Service.h | 22 + ports/zephyr-cp/common-hal/_bleio/UUID.c | 51 +++ ports/zephyr-cp/common-hal/_bleio/UUID.h | 15 + ports/zephyr-cp/common-hal/_bleio/__init__.c | 74 ++++ ports/zephyr-cp/common-hal/_bleio/__init__.h | 9 + ports/zephyr-cp/common-hal/wifi/__init__.c | 21 +- .../common-hal/zephyr_kernel/__init__.c | 10 + .../zephyr-cp/cptools/build_circuitpython.py | 18 +- .../zephyr-cp/cptools/tests/test_zephyr2cp.py | 39 ++ ports/zephyr-cp/cptools/zephyr2cp.py | 59 ++- ports/zephyr-cp/prj.conf | 17 +- ports/zephyr-cp/supervisor/port.c | 77 +++- ports/zephyr-cp/supervisor/usb.c | 28 +- ports/zephyr-cp/sysbuild.cmake | 2 + ports/zephyr-cp/tests/__init__.py | 136 ++++++ ports/zephyr-cp/tests/bsim/__init__.py | 3 + ports/zephyr-cp/tests/bsim/conftest.py | 222 ++++++++++ .../zephyr-cp/tests/bsim/test_bsim_basics.py | 34 ++ .../tests/bsim/test_bsim_ble_advertising.py | 111 +++++ .../tests/bsim/test_bsim_ble_name.py | 31 ++ .../tests/bsim/test_bsim_ble_scan.py | 151 +++++++ ports/zephyr-cp/tests/conftest.py | 315 +++++-------- ports/zephyr-cp/tests/docs/babblesim.md | 69 +++ ports/zephyr-cp/tests/test_basics.py | 130 +++--- ports/zephyr-cp/tests/test_i2c.py | 60 +-- shared-bindings/_bleio/PacketBuffer.h | 1 + 81 files changed, 3111 insertions(+), 332 deletions(-) create mode 100644 AGENTS.md create mode 100644 ports/zephyr-cp/AGENTS.md create mode 100644 ports/zephyr-cp/boards/da14695_dk_usb.conf create mode 100644 ports/zephyr-cp/boards/da14695_dk_usb.overlay create mode 100644 ports/zephyr-cp/boards/frdm_rw612.conf create mode 100644 ports/zephyr-cp/boards/frdm_rw612.overlay create mode 100644 ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf create mode 100644 ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay create mode 100644 ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/nxp/frdm_rw612/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf create mode 100644 ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/stm32wba65i_dk1.conf create mode 100644 ports/zephyr-cp/boards/stm32wba65i_dk1.overlay create mode 100644 ports/zephyr-cp/common-hal/_bleio/Adapter.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/Adapter.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/Attribute.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/Attribute.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/Characteristic.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/Characteristic.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/Connection.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/Connection.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/Descriptor.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/Descriptor.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/Service.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/Service.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/UUID.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/UUID.h create mode 100644 ports/zephyr-cp/common-hal/_bleio/__init__.c create mode 100644 ports/zephyr-cp/common-hal/_bleio/__init__.h create mode 100644 ports/zephyr-cp/tests/__init__.py create mode 100644 ports/zephyr-cp/tests/bsim/__init__.py create mode 100644 ports/zephyr-cp/tests/bsim/conftest.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_basics.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py create mode 100644 ports/zephyr-cp/tests/docs/babblesim.md diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 01172041b62..925ee469854 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -95,5 +95,10 @@ jobs: uses: ./.github/actions/deps/external - name: Build native sim target run: make -C ports/zephyr-cp -j2 BOARD=native_native_sim + - name: Build bsim + run: make -j 2 everything + working-directory: ports/zephyr-cp/tools/bsim + - name: Build native_nrf5340bsim + run: make -C ports/zephyr-cp -j2 BOARD=native_nrf5340bsim - name: Run Zephyr tests run: make -C ports/zephyr-cp test diff --git a/.gitignore b/.gitignore index f996911d8d7..fdc71c92e32 100644 --- a/.gitignore +++ b/.gitignore @@ -107,3 +107,6 @@ TAGS # windsurf rules .windsurfrules + +# git-review-web outputs +.review diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..145e31c1271 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,3 @@ +- Capture CircuitPython output by finding the matching device in `/dev/serial/by-id` +- You can mount the CIRCUITPY drive by doing `udisksctl mount -b /dev/disk/by-label/CIRCUITPY` and access it via `/run/media//CIRCUITPY`. +- `circup` is a command line tool to install libraries and examples to CIRCUITPY. diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index c135442f600..37c2ca250c9 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1332,6 +1332,10 @@ msgstr "" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -3811,6 +3815,7 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4294,6 +4299,7 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" diff --git a/ports/zephyr-cp/AGENTS.md b/ports/zephyr-cp/AGENTS.md new file mode 100644 index 00000000000..a2413e64e42 --- /dev/null +++ b/ports/zephyr-cp/AGENTS.md @@ -0,0 +1,5 @@ +- Build a board by doing `make BOARD=_`. +- The corresponding configuration files are in `boards//` +- The files (not folders) in `boards/` directory are used by Zephyr. +- To flash it on a board do `make BOARD=_ flash`. +- Zephyr board docs are at `zephyr/boards//`. diff --git a/ports/zephyr-cp/Kconfig.sysbuild b/ports/zephyr-cp/Kconfig.sysbuild index cd74ff13592..11b49446f42 100644 --- a/ports/zephyr-cp/Kconfig.sysbuild +++ b/ports/zephyr-cp/Kconfig.sysbuild @@ -8,6 +8,7 @@ config NET_CORE_BOARD default "nrf5340dk/nrf5340/cpunet" if $(BOARD) = "nrf5340dk" default "nrf7002dk/nrf5340/cpunet" if $(BOARD) = "nrf7002dk" default "nrf5340_audio_dk/nrf5340/cpunet" if $(BOARD) = "nrf5340_audio_dk" + default "nrf5340bsim/nrf5340/cpunet" if $(BOARD) = "nrf5340bsim" config NET_CORE_IMAGE_HCI_IPC bool "HCI IPC image on network core" diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index 622fe4901a9..c4feead23b9 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,7 +8,8 @@ BUILD ?= build-$(BOARD) TRANSLATION ?= en_US -.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash debug run clean menuconfig all clean-all test fetch-port-submodules + +.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug run clean menuconfig all clean-all test fetch-port-submodules $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) @@ -26,6 +27,9 @@ $(BUILD)/firmware.exe: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west flash -d $(BUILD) +recover: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + west flash --recover -d $(BUILD) + debug: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west debug -d $(BUILD) diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index 954bce0b298..ddf1627a924 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -1,13 +1,17 @@ set(pca10056_BOARD_ALIAS nrf52840dk/nrf52840) set(renesas_ek_ra6m5_BOARD_ALIAS ek_ra6m5) set(renesas_ek_ra8d1_BOARD_ALIAS ek_ra8d1) +set(renesas_da14695_dk_usb_BOARD_ALIAS da14695_dk_usb) set(native_native_sim_BOARD_ALIAS native_sim) +set(native_nrf5340bsim_BOARD_ALIAS nrf5340bsim/nrf5340/cpuapp) set(nordic_nrf54l15dk_BOARD_ALIAS nrf54l15dk/nrf54l15/cpuapp) set(nordic_nrf54h20dk_BOARD_ALIAS nrf54h20dk/nrf54h20/cpuapp) set(nordic_nrf5340dk_BOARD_ALIAS nrf5340dk/nrf5340/cpuapp) set(nordic_nrf7002dk_BOARD_ALIAS nrf7002dk/nrf5340/cpuapp) set(nxp_frdm_mcxn947_BOARD_ALIAS frdm_mcxn947/mcxn947/cpu0) +set(nxp_frdm_rw612_BOARD_ALIAS frdm_rw612) set(nxp_mimxrt1170_evk_BOARD_ALIAS mimxrt1170_evk@A/mimxrt1176/cm7) set(st_stm32h7b3i_dk_BOARD_ALIAS stm32h7b3i_dk) +set(st_stm32wba65i_dk1_BOARD_ALIAS stm32wba65i_dk1) set(st_nucleo_u575zi_q_BOARD_ALIAS nucleo_u575zi_q/stm32u575xx) set(st_nucleo_n657x0_q_BOARD_ALIAS nucleo_n657x0_q/stm32n657xx) diff --git a/ports/zephyr-cp/boards/da14695_dk_usb.conf b/ports/zephyr-cp/boards/da14695_dk_usb.conf new file mode 100644 index 00000000000..145a9393407 --- /dev/null +++ b/ports/zephyr-cp/boards/da14695_dk_usb.conf @@ -0,0 +1,20 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/da14695_dk_usb.overlay b/ports/zephyr-cp/boards/da14695_dk_usb.overlay new file mode 100644 index 00000000000..fbc1817c759 --- /dev/null +++ b/ports/zephyr-cp/boards/da14695_dk_usb.overlay @@ -0,0 +1,10 @@ +&flash0 { + partitions{ + circuitpy_partition: partition@118000 { + label = "circuitpy"; + reg = <0x118000 (DT_SIZE_M(4) - DT_SIZE_K(1120))>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf new file mode 100644 index 00000000000..7f063218153 --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -0,0 +1,46 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_POSIX_NAMES=y + +CONFIG_WIFI=y +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +CONFIG_NET_HOSTNAME_ENABLE=y +CONFIG_NET_HOSTNAME_DYNAMIC=y +CONFIG_NET_HOSTNAME="circuitpython" + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +CONFIG_MBEDTLS_RSA_C=y +CONFIG_MBEDTLS_PKCS1_V15=y +CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=y +CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CTR_DRBG_ENABLED=y +CONFIG_MBEDTLS_USE_PSA_CRYPTO=n + +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=8 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 + +CONFIG_UDC_WORKQUEUE_STACK_SIZE=1024 diff --git a/ports/zephyr-cp/boards/frdm_rw612.overlay b/ports/zephyr-cp/boards/frdm_rw612.overlay new file mode 100644 index 00000000000..1c38f42c4ab --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_rw612.overlay @@ -0,0 +1,11 @@ +&w25q512jvfiq { + partitions { + /delete-node/ storage_partition; + circuitpy_partition: partition@620000 { + label = "circuitpy"; + reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 2cf9d7127d5..73897f71620 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "POSIX/Native Boards Native simulator - native_sim" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml new file mode 100644 index 00000000000..9ddbb2153fb --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -0,0 +1,115 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "POSIX/Native Boards nRF5340 simulated boards (BabbleSim)" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml new file mode 100644 index 00000000000..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 334cf4001eb..52beeda076f 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -2,8 +2,8 @@ name = "Nordic Semiconductor nRF5340 DK" [modules] -__future__ = false -_bleio = false +__future__ = true +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 40edb7b7058..2759dfb89c1 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "Nordic Semiconductor nRF54H20 DK" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 509f14cd20d..6df832f607b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "Nordic Semiconductor nRF54L15 DK" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 3b0ecedcc63..d713552d87b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -2,8 +2,8 @@ name = "Nordic Semiconductor nRF7002 DK" [modules] -__future__ = false -_bleio = false +__future__ = true +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf new file mode 100644 index 00000000000..f9507bd0319 --- /dev/null +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -0,0 +1,26 @@ +# Configuration for nrf5340bsim simulated board +# Mirror settings from native_sim.conf for compatibility + +CONFIG_GPIO=y + +# Enable Bluetooth stack - bsim is for BT simulation +CONFIG_BT=y +CONFIG_BT_HCI=y +CONFIG_BT_HCI_IPC=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_BROADCASTER=y + +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 + +# So we can test safe mode +CONFIG_NATIVE_SIM_REBOOT=y + +# Ensure the network core image starts when using native simulator +CONFIG_NATIVE_SIMULATOR_AUTOSTART_MCU=y + +CONFIG_TRACING=y +CONFIG_TRACING_PERFETTO=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_GPIO=y diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000..eeb043c6f3c --- /dev/null +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/ { + chosen { + zephyr,sram = &sram0; + }; +}; + +&sram0 { + compatible = "zephyr,memory-region", "mmio-sram"; + zephyr,memory-region = "SRAM"; +}; + +&flash0 { + /delete-node/ partitions; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_K(1024)>; + }; + }; +}; + +/* Note: bsim doesn't have USB, so we don't include app.overlay */ diff --git a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf index fa0532e8150..145a9393407 100644 --- a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf @@ -4,3 +4,17 @@ CONFIG_BT_CENTRAL=y CONFIG_BT_BROADCASTER=y CONFIG_BT_OBSERVER=y CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf index f7443ecfa33..a55b90c50e7 100644 --- a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -1 +1,8 @@ CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE=4096 + +# Reduce flash usage for this board. +CONFIG_LOG=y +CONFIG_LOG_MAX_LEVEL=2 +CONFIG_ASSERT=n +CONFIG_FRAME_POINTER=n +CONFIG_HW_STACK_PROTECTION=n diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index c61851fad2d..9829d4a1581 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -4,6 +4,10 @@ CONFIG_WIFI=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y CONFIG_MBEDTLS_USE_PSA_CRYPTO=n +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 + CONFIG_BT=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_CENTRAL=y diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 7e03594f1d1..233796fc6f4 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "NXP Semiconductors FRDM-MCXN947" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml new file mode 100644 index 00000000000..c9bd2729b9e --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -0,0 +1,114 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "NXP Semiconductors FRDM_RW612" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = true # Zephyr board has busio +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = true # Zephyr networking enabled +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = true # Zephyr board has wifi +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/circuitpython.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/circuitpython.toml new file mode 100644 index 00000000000..9bceea470ca --- /dev/null +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/circuitpython.toml @@ -0,0 +1,5 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +BLOBS=["hal_nxp"] + +[blob_fetch_args] +hal_nxp = ["--allow-regex", "^rw61x/"] diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 4398a38ab87..4926b5c9a6c 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "NXP Semiconductors MIMXRT1170-EVK/EVKB" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml new file mode 100644 index 00000000000..e5adbfd582d --- /dev/null +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -0,0 +1,114 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Renesas Electronics Corporation DA14695 Development Kit USB" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = true # Zephyr board has busio +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml new file mode 100644 index 00000000000..3272dd4c5f3 --- /dev/null +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf"] diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index d60e8eb4b26..2ea2cea90b7 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "Renesas Electronics Corporation RA6M5 Evaluation Kit" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 8743994bbc7..3be48a8b72c 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "Renesas Electronics Corporation RA8D1 Evaluation Kit" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf b/ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf new file mode 100644 index 00000000000..145a9393407 --- /dev/null +++ b/ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf @@ -0,0 +1,20 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 9b10fbe3c2d..4b9c1053f22 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "STMicroelectronics Nucleo N657X0-Q" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index ef54f4bb0f7..ec78a62f066 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "STMicroelectronics Nucleo U575ZI Q" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 30ac22d00cc..24e44662e40 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -2,7 +2,7 @@ name = "STMicroelectronics STM32H7B3I Discovery kit" [modules] -__future__ = false +__future__ = true _bleio = false _eve = false _pew = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml new file mode 100644 index 00000000000..e26084cc43e --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -0,0 +1,115 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "STMicroelectronics STM32WBA65I Discovery kit" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = false +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml new file mode 100644 index 00000000000..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.conf b/ports/zephyr-cp/boards/stm32wba65i_dk1.conf new file mode 100644 index 00000000000..55d951959e6 --- /dev/null +++ b/ports/zephyr-cp/boards/stm32wba65i_dk1.conf @@ -0,0 +1,24 @@ +# USB OTG on STM32WBA requires VOS Range 1. Keep HCLK > 16 MHz. +CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=32000000 + +# Bluetooth doesn't start up for some reason. +# CONFIG_BT=y +# CONFIG_BT_PERIPHERAL=y +# CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y +CONFIG_BT_STM32WBA_USE_TEMP_BASED_CALIB=n + +CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_DYNAMIC=y +CONFIG_BT_DEVICE_NAME_MAX=28 +CONFIG_BT_L2CAP_TX_MTU=253 + +# BT Buffers +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay new file mode 100644 index 00000000000..1b6e55ba462 --- /dev/null +++ b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay @@ -0,0 +1,63 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 DT_SIZE_K(64)>; + }; + + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 DT_SIZE_K(928)>; + }; + + storage_partition: partition@f80000 { + label = "storage"; + reg = <0x001e0000 DT_SIZE_K(64)>; + }; + + circuitpy_partition: partition@108000 { + label = "circuitpy"; + reg = <0x00108000 DT_SIZE_K(992)>; + }; + }; +}; + +&rng { + status = "okay"; +}; + +/* + * USB on STM32WBA requires VOS Range 1. Zephyr selects VOS from HCLK, and + * 16 MHz keeps it in Range 2, which trips an assertion in udc_stm32. + * Run SYSCLK from full 32 MHz HSE so VOS is set to Range 1. + */ +&clk_hse { + /delete-property/ hse-div2; +}; + +&rcc { + clock-frequency = ; + ahb5-prescaler = <1>; +}; + +zephyr_udc0: &usbotg_hs { + clocks = <&rcc STM32_CLOCK(AHB2, 14)>, + <&rcc STM32_SRC_HSE OTGHS_SEL(0)>; + pinctrl-0 = <&usb_otg_hs_dm_pd7 &usb_otg_hs_dp_pd6>; + pinctrl-names = "default"; + status = "okay"; +}; + +&otghs_phy { + /* OTG HS clock source is 32 MHz HSE */ + clock-reference = "SYSCFG_OTG_HS_PHY_CLK_32MHz"; + status = "okay"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c new file mode 100644 index 00000000000..7257f54c35f --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -0,0 +1,412 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include +#include + +#include +#include +#include +#include + +#include "py/runtime.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "shared-bindings/_bleio/Address.h" +#include "shared-module/_bleio/Address.h" +#include "shared-module/_bleio/ScanResults.h" +#include "supervisor/shared/tick.h" + +bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; + +static bool scan_callbacks_registered = false; +static bleio_scanresults_obj_t *active_scan_results = NULL; +static struct bt_le_scan_cb scan_callbacks; +static bool ble_advertising = false; +static bool ble_adapter_enabled = true; + +#define BLEIO_ADV_MAX_FIELDS 16 +#define BLEIO_ADV_MAX_DATA_LEN 31 +static struct bt_data adv_data[BLEIO_ADV_MAX_FIELDS]; +static struct bt_data scan_resp_data[BLEIO_ADV_MAX_FIELDS]; +static uint8_t adv_data_storage[BLEIO_ADV_MAX_DATA_LEN]; +static uint8_t scan_resp_storage[BLEIO_ADV_MAX_DATA_LEN]; + +static uint8_t bleio_address_type_from_zephyr(const bt_addr_le_t *addr) { + if (addr == NULL) { + return BLEIO_ADDRESS_TYPE_PUBLIC; + } + + switch (addr->type) { + case BT_ADDR_LE_PUBLIC: + case BT_ADDR_LE_PUBLIC_ID: + return BLEIO_ADDRESS_TYPE_PUBLIC; + case BT_ADDR_LE_RANDOM: + case BT_ADDR_LE_RANDOM_ID: + case BT_ADDR_LE_UNRESOLVED: + if (BT_ADDR_IS_RPA(&addr->a)) { + return BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE; + } + if (BT_ADDR_IS_NRPA(&addr->a)) { + return BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE; + } + return BLEIO_ADDRESS_TYPE_RANDOM_STATIC; + default: + return BLEIO_ADDRESS_TYPE_PUBLIC; + } +} + +static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) { + if (active_scan_results == NULL || info == NULL || buf == NULL) { + return; + } + + const bool connectable = (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0; + const bool scan_response = (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0; + const bt_addr_le_t *addr = info->addr; + + uint8_t addr_bytes[NUM_BLEIO_ADDRESS_BYTES] = {0}; + if (addr != NULL) { + memcpy(addr_bytes, addr->a.val, sizeof(addr_bytes)); + } + + shared_module_bleio_scanresults_append(active_scan_results, + supervisor_ticks_ms64(), + connectable, + scan_response, + info->rssi, + addr_bytes, + bleio_address_type_from_zephyr(addr), + buf->data, + buf->len); +} + +static void scan_timeout_cb(void) { + if (active_scan_results == NULL) { + return; + } + shared_module_bleio_scanresults_set_done(active_scan_results, true); + active_scan_results = NULL; +} + +// We need to disassemble the full advertisement packet because the Zephyr takes +// in each ADT in an array. +static size_t bleio_parse_adv_data(const uint8_t *raw, size_t raw_len, struct bt_data *out, + size_t out_len, uint8_t *storage, size_t storage_len) { + size_t count = 0; + size_t offset = 0; + size_t storage_offset = 0; + + while (offset < raw_len) { + uint8_t field_len = raw[offset]; + if (field_len == 0) { + offset++; + continue; + } + uint8_t data_len = field_len - 1; + if (offset + field_len + 1 > raw_len || + count >= out_len || + field_len < 1 || + storage_offset + data_len > storage_len) { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid advertising data")); + } + uint8_t type = raw[offset + 1]; + memcpy(storage + storage_offset, raw + offset + 2, data_len); + out[count].type = type; + out[count].data_len = data_len; + out[count].data = storage + storage_offset; + storage_offset += data_len; + count++; + offset += field_len + 1; + } + + return count; +} + +void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { + if (enabled) { + if (!bt_is_ready()) { + int err = bt_enable(NULL); + raise_zephyr_error(err); + if (err != 0) { + return; + } + } + ble_adapter_enabled = true; + return; + } + + // On Zephyr bsim + HCI IPC, disabling and immediately re-enabling BLE can + // race endpoint rebinding during soft reload. Keep the controller running, + // but present adapter.enabled=False to CircuitPython code. + common_hal_bleio_adapter_stop_scan(self); + common_hal_bleio_adapter_stop_advertising(self); + ble_adapter_enabled = false; +} + +bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { + return ble_adapter_enabled; +} + +mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { + mp_raise_NotImplementedError(NULL); +} + +bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { + mp_raise_NotImplementedError(NULL); +} + +mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) { + (void)self; + const char *name = bt_get_name(); + return mp_obj_new_str(name, strlen(name)); +} + +void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char *name) { + (void)self; + size_t len = strlen(name); + int err = 0; + if (len > CONFIG_BT_DEVICE_NAME_MAX) { + char truncated[CONFIG_BT_DEVICE_NAME_MAX + 1]; + memcpy(truncated, name, CONFIG_BT_DEVICE_NAME_MAX); + truncated[CONFIG_BT_DEVICE_NAME_MAX] = '\0'; + err = bt_set_name(truncated); + } else { + err = bt_set_name(name); + } + if (err != 0) { + raise_zephyr_error(err); + } +} + +void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, + bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, + mp_buffer_info_t *advertising_data_bufinfo, + mp_buffer_info_t *scan_response_data_bufinfo, + mp_int_t tx_power, const bleio_address_obj_t *directed_to) { + (void)tx_power; + (void)directed_to; + (void)interval; + + if (advertising_data_bufinfo->len > BLEIO_ADV_MAX_DATA_LEN || + scan_response_data_bufinfo->len > BLEIO_ADV_MAX_DATA_LEN) { + mp_raise_NotImplementedError(NULL); + } + + if (timeout != 0) { + mp_raise_NotImplementedError(NULL); + } + + if (ble_advertising) { + raise_zephyr_error(-EALREADY); + } + + bt_addr_le_t id_addrs[CONFIG_BT_ID_MAX]; + size_t id_count = CONFIG_BT_ID_MAX; + bt_id_get(id_addrs, &id_count); + if (id_count == 0 || bt_addr_le_eq(&id_addrs[BT_ID_DEFAULT], BT_ADDR_LE_ANY)) { + int id = bt_id_create(NULL, NULL); + if (id < 0) { + printk("Failed to create identity address: %d\n", id); + raise_zephyr_error(id); + } + } + + size_t adv_count = bleio_parse_adv_data(advertising_data_bufinfo->buf, + advertising_data_bufinfo->len, + adv_data, + BLEIO_ADV_MAX_FIELDS, + adv_data_storage, + sizeof(adv_data_storage)); + + size_t scan_resp_count = 0; + if (scan_response_data_bufinfo->len > 0) { + scan_resp_count = bleio_parse_adv_data(scan_response_data_bufinfo->buf, + scan_response_data_bufinfo->len, + scan_resp_data, + BLEIO_ADV_MAX_FIELDS, + scan_resp_storage, + sizeof(scan_resp_storage)); + } + + if (anonymous) { + mp_raise_NotImplementedError(NULL); + } + + struct bt_le_adv_param adv_params; + if (connectable) { + adv_params = (struct bt_le_adv_param)BT_LE_ADV_PARAM_INIT( + BT_LE_ADV_OPT_CONN, + BT_GAP_ADV_FAST_INT_MIN_1, + BT_GAP_ADV_FAST_INT_MAX_1, + NULL); + } else if (scan_resp_count > 0) { + adv_params = (struct bt_le_adv_param)BT_LE_ADV_PARAM_INIT( + BT_LE_ADV_OPT_SCANNABLE, + BT_GAP_ADV_FAST_INT_MIN_2, + BT_GAP_ADV_FAST_INT_MAX_2, + NULL); + } else { + adv_params = (struct bt_le_adv_param)BT_LE_ADV_PARAM_INIT( + 0, + BT_GAP_ADV_FAST_INT_MIN_2, + BT_GAP_ADV_FAST_INT_MAX_2, + NULL); + } + + raise_zephyr_error(bt_le_adv_start(&adv_params, + adv_data, + adv_count, + scan_resp_count > 0 ? scan_resp_data : NULL, + scan_resp_count)); + + ble_advertising = true; +} + +void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { + (void)self; + if (!ble_advertising) { + return; + } + bt_le_adv_stop(); + ble_advertising = false; +} + +bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { + (void)self; + return ble_advertising; +} + +mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t *prefixes, size_t prefix_length, bool extended, mp_int_t buffer_size, mp_float_t timeout, mp_float_t interval, mp_float_t window, mp_int_t minimum_rssi, bool active) { + (void)extended; + + if (self->scan_results != NULL) { + if (!shared_module_bleio_scanresults_get_done(self->scan_results)) { + common_hal_bleio_adapter_stop_scan(self); + } else { + self->scan_results = NULL; + } + } + + int err = 0; + + self->scan_results = shared_module_bleio_new_scanresults(buffer_size, prefixes, prefix_length, minimum_rssi); + active_scan_results = self->scan_results; + + if (!scan_callbacks_registered) { + scan_callbacks.recv = scan_recv_cb; + scan_callbacks.timeout = scan_timeout_cb; + err = bt_le_scan_cb_register(&scan_callbacks); + if (err != 0) { + self->scan_results = NULL; + active_scan_results = NULL; + raise_zephyr_error(err); + } + scan_callbacks_registered = true; + } + + uint16_t interval_units = (uint16_t)((interval / 0.000625f) + 0.5f); + uint16_t window_units = (uint16_t)((window / 0.000625f) + 0.5f); + uint32_t timeout_units = 0; + + if (timeout > 0.0f) { + timeout_units = (uint32_t)(timeout * 100.0f + 0.5f); + if (timeout_units > UINT16_MAX) { + mp_raise_ValueError(MP_ERROR_TEXT("timeout must be < 655.35 secs")); + } + if (timeout_units == 0) { + mp_raise_ValueError(MP_ERROR_TEXT("non-zero timeout must be > 0.01")); + } + } + + struct bt_le_scan_param scan_params = { + .type = active ? BT_LE_SCAN_TYPE_ACTIVE : BT_LE_SCAN_TYPE_PASSIVE, + .options = BT_LE_SCAN_OPT_FILTER_DUPLICATE, + .interval = interval_units, + .window = window_units, + .timeout = (uint16_t)timeout_units, + .interval_coded = 0, + .window_coded = 0, + }; + + err = bt_le_scan_start(&scan_params, NULL); + if (err != 0) { + self->scan_results = NULL; + active_scan_results = NULL; + raise_zephyr_error(err); + } + + return MP_OBJ_FROM_PTR(self->scan_results); +} + +void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { + if (self->scan_results == NULL) { + return; + } + bt_le_scan_stop(); + shared_module_bleio_scanresults_set_done(self->scan_results, true); + active_scan_results = NULL; + self->scan_results = NULL; +} + +bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { + return false; +} + +mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self) { + return false; +} + +void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) { + // Nothing to do for now. +} + +void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { + if (adapter == NULL) { + return; + } + adapter->scan_results = NULL; + adapter->connection_objs = NULL; + active_scan_results = NULL; + ble_advertising = false; + ble_adapter_enabled = bt_is_ready(); +} + +bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void) { + return &common_hal_bleio_adapter_obj; +} + +uint16_t bleio_adapter_get_name(char *buf, uint16_t len) { + const char *name = bt_get_name(); + uint16_t full_len = strlen(name); + if (len > 0) { + uint16_t copy_len = len < full_len ? len : full_len; + memcpy(buf, name, copy_len); + } + return full_len; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.h b/ports/zephyr-cp/common-hal/_bleio/Adapter.h new file mode 100644 index 00000000000..7cb3dc402c6 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "py/objtuple.h" + +#include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/ScanResults.h" + +#define BLEIO_TOTAL_CONNECTION_COUNT 5 +#define BLEIO_HANDLE_INVALID 0xffff + +extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; + +typedef struct { + mp_obj_base_t base; + bleio_scanresults_obj_t *scan_results; + mp_obj_t name; + mp_obj_tuple_t *connection_objs; + bool user_advertising; +} bleio_adapter_obj_t; + +void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); +void bleio_adapter_reset(bleio_adapter_obj_t *adapter); diff --git a/ports/zephyr-cp/common-hal/_bleio/Attribute.c b/ports/zephyr-cp/common-hal/_bleio/Attribute.c new file mode 100644 index 00000000000..cf8a818e6a7 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Attribute.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Attribute is defined in shared-module, no port-specific implementation needed diff --git a/ports/zephyr-cp/common-hal/_bleio/Attribute.h b/ports/zephyr-cp/common-hal/_bleio/Attribute.h new file mode 100644 index 00000000000..417ac3c4549 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Attribute.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/_bleio/Attribute.h" diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.c b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c new file mode 100644 index 00000000000..6e71f848627 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c @@ -0,0 +1,66 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" + +bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self) { + return self->props; +} + +mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) { + return mp_obj_new_tuple(self->descriptor_list->len, self->descriptor_list->items); +} + +bleio_service_obj_t *common_hal_bleio_characteristic_get_service(bleio_characteristic_obj_t *self) { + return self->service; +} + +bleio_uuid_obj_t *common_hal_bleio_characteristic_get_uuid(bleio_characteristic_obj_t *self) { + return self->uuid; +} + +size_t common_hal_bleio_characteristic_get_max_length(bleio_characteristic_obj_t *self) { + return self->max_length; +} + +size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t *buf, size_t len) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo, const char *user_description) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) { + return self->service == NULL; +} + +void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) { + // Nothing to do +} + +void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { + mp_raise_NotImplementedError(NULL); +} + +void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer) { + self->observer = observer; +} + +void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self) { + self->observer = mp_const_none; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.h b/ports/zephyr-cp/common-hal/_bleio/Characteristic.h new file mode 100644 index 00000000000..b9021c13295 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.h @@ -0,0 +1,39 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "py/objlist.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "shared-module/_bleio/Characteristic.h" +#include "common-hal/_bleio/Descriptor.h" +#include "common-hal/_bleio/Service.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct _bleio_characteristic_obj { + mp_obj_base_t base; + bleio_service_obj_t *service; + bleio_uuid_obj_t *uuid; + mp_obj_t observer; + uint8_t *current_value; + uint16_t current_value_len; + uint16_t current_value_alloc; + uint16_t max_length; + uint16_t def_handle; + uint16_t handle; + bleio_characteristic_properties_t props; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; + mp_obj_list_t *descriptor_list; + uint16_t user_desc_handle; + uint16_t cccd_handle; + uint16_t sccd_handle; + bool fixed_length; +} bleio_characteristic_obj_t; + +void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer); +void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self); diff --git a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c new file mode 100644 index 00000000000..e6ae3bf9b72 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c @@ -0,0 +1,72 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "shared-bindings/_bleio/CharacteristicBuffer.h" + +void _common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, + bleio_characteristic_obj_t *characteristic, + mp_float_t timeout, + uint8_t *buffer, size_t buffer_size, + void *static_handler_entry, + bool watch_for_interrupt_char) { + (void)self; + (void)characteristic; + (void)timeout; + (void)buffer; + (void)buffer_size; + (void)static_handler_entry; + (void)watch_for_interrupt_char; + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, + bleio_characteristic_obj_t *characteristic, + mp_float_t timeout, + size_t buffer_size) { + (void)self; + (void)characteristic; + (void)timeout; + (void)buffer_size; + mp_raise_NotImplementedError(NULL); +} + +uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) { + (void)self; + (void)data; + (void)len; + if (errcode != NULL) { + *errcode = MP_EAGAIN; + } + mp_raise_NotImplementedError(NULL); +} + +uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { + return self->deinited; +} + +void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) { + if (self == NULL) { + return; + } + self->deinited = true; +} + +bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) { + (void)self; + return false; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h new file mode 100644 index 00000000000..53b10413775 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" +#include "shared-bindings/_bleio/Characteristic.h" + +typedef struct { + mp_obj_base_t base; + bleio_characteristic_obj_t *characteristic; + bool deinited; +} bleio_characteristic_buffer_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.c b/ports/zephyr-cp/common-hal/_bleio/Connection.c new file mode 100644 index 00000000000..b0cac644367 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -0,0 +1,56 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-bindings/_bleio/Connection.h" + +void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) { + return false; +} + +mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_internal_t *self) { + return 20; +} + +bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { + return false; +} + +mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist) { + mp_raise_NotImplementedError(NULL); +} + +mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_connection_set_connection_interval(bleio_connection_internal_t *self, mp_float_t new_interval) { + mp_raise_NotImplementedError(NULL); +} + +void bleio_connection_clear(bleio_connection_internal_t *self) { + // Nothing to do +} + +uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self) { + return self->connection->conn_handle; +} + +mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection) { + mp_raise_NotImplementedError(NULL); +} + +bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle) { + return NULL; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.h b/ports/zephyr-cp/common-hal/_bleio/Connection.h new file mode 100644 index 00000000000..b3faef63f8c --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.h @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" +#include "py/objlist.h" + +#include "common-hal/_bleio/__init__.h" +#include "shared-module/_bleio/Address.h" +#include "common-hal/_bleio/Service.h" + +typedef enum { + PAIR_NOT_PAIRED, + PAIR_WAITING, + PAIR_PAIRED, +} pair_status_t; + +typedef struct { + uint16_t conn_handle; + bool is_central; + mp_obj_list_t *remote_service_list; + uint16_t ediv; + volatile pair_status_t pair_status; + uint8_t sec_status; + mp_obj_t connection_obj; + volatile bool conn_params_updating; + uint16_t mtu; + volatile bool do_bond_cccds; + volatile bool do_bond_keys; + uint64_t do_bond_cccds_request_time; +} bleio_connection_internal_t; + +typedef struct { + mp_obj_base_t base; + bleio_connection_internal_t *connection; + uint8_t disconnect_reason; +} bleio_connection_obj_t; + +void bleio_connection_clear(bleio_connection_internal_t *self); +uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); +mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); +bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/zephyr-cp/common-hal/_bleio/Descriptor.c b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c new file mode 100644 index 00000000000..847546b1ced --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Characteristic.h" + +void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) { + mp_raise_NotImplementedError(NULL); +} + +bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { + return self->uuid; +} + +bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self) { + mp_raise_NotImplementedError(NULL); +} + +size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t *buf, size_t len) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) { + mp_raise_NotImplementedError(NULL); +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Descriptor.h b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h new file mode 100644 index 00000000000..8abf1dcfaad --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h @@ -0,0 +1,23 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/_bleio/Attribute.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct _bleio_descriptor_obj { + mp_obj_base_t base; + bleio_uuid_obj_t *uuid; + uint16_t handle; + bleio_attribute_security_mode_t read_perm; + bleio_attribute_security_mode_t write_perm; + uint16_t max_length; + bool fixed_length; + uint8_t *value; + uint16_t value_length; +} bleio_descriptor_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c new file mode 100644 index 00000000000..6cba2135156 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c @@ -0,0 +1,65 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-bindings/_bleio/PacketBuffer.h" + +void common_hal_bleio_packet_buffer_construct( + bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, + size_t buffer_size, size_t max_packet_size) { + (void)self; + (void)characteristic; + (void)buffer_size; + (void)max_packet_size; + mp_raise_NotImplementedError(NULL); +} + +mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, const uint8_t *data, size_t len, uint8_t *header, size_t header_len) { + (void)self; + (void)data; + (void)len; + (void)header; + (void)header_len; + mp_raise_NotImplementedError(NULL); +} + +mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len) { + (void)self; + (void)data; + (void)len; + mp_raise_NotImplementedError(NULL); +} + +mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_packet_buffer_flush(bleio_packet_buffer_obj_t *self) { + (void)self; + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { + return self->deinited; +} + +void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { + if (self == NULL) { + return; + } + self->deinited = true; +} + +bool common_hal_bleio_packet_buffer_connected(bleio_packet_buffer_obj_t *self) { + (void)self; + return false; +} diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h new file mode 100644 index 00000000000..c96dd9f2eb6 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" + +typedef struct _bleio_characteristic_obj bleio_characteristic_obj_t; + +typedef void *ble_event_handler_t; + +typedef struct { + mp_obj_base_t base; + bool deinited; +} bleio_packet_buffer_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.c b/ports/zephyr-cp/common-hal/_bleio/Service.c new file mode 100644 index 00000000000..da2bf48e16f --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Service.c @@ -0,0 +1,45 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/Characteristic.h" + +uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary, mp_obj_list_t *characteristic_list) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_service_deinit(bleio_service_obj_t *self) { + // Nothing to do +} + +void common_hal_bleio_service_from_remote_service(bleio_service_obj_t *self, bleio_connection_obj_t *connection, bleio_uuid_obj_t *uuid, bool is_secondary) { + mp_raise_NotImplementedError(NULL); +} + +bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { + return self->uuid; +} + +mp_obj_tuple_t *common_hal_bleio_service_get_characteristics(bleio_service_obj_t *self) { + return mp_obj_new_tuple(self->characteristic_list->len, self->characteristic_list->items); +} + +bool common_hal_bleio_service_get_is_remote(bleio_service_obj_t *self) { + return self->is_remote; +} + +bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { + return self->is_secondary; +} + +void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *initial_value_bufinfo, const char *user_description) { + mp_raise_NotImplementedError(NULL); +} diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.h b/ports/zephyr-cp/common-hal/_bleio/Service.h new file mode 100644 index 00000000000..03ab8b5d7fd --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/Service.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "py/objlist.h" +#include "common-hal/_bleio/UUID.h" + +typedef struct bleio_service_obj { + mp_obj_base_t base; + bleio_uuid_obj_t *uuid; + mp_obj_t connection; + mp_obj_list_t *characteristic_list; + uint16_t start_handle; + uint16_t end_handle; + bool is_remote; + bool is_secondary; +} bleio_service_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/UUID.c b/ports/zephyr-cp/common-hal/_bleio/UUID.c new file mode 100644 index 00000000000..3bfbffb5a2b --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.c @@ -0,0 +1,51 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/runtime.h" +#include "shared-bindings/_bleio/UUID.h" + +void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]) { + if (uuid16 != 0) { + // 16-bit UUID + self->size = 16; + // Convert 16-bit UUID to 128-bit + // Bluetooth Base UUID: 00000000-0000-1000-8000-00805F9B34FB + const uint8_t base_uuid[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + memcpy(self->uuid128, base_uuid, 16); + self->uuid128[12] = (uuid16 & 0xff); + self->uuid128[13] = (uuid16 >> 8) & 0xff; + } else { + // 128-bit UUID + self->size = 128; + memcpy(self->uuid128, uuid128, 16); + } +} + +uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { + if (self->size == 16) { + return (self->uuid128[13] << 8) | self->uuid128[12]; + } + return 0; +} + +void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]) { + memcpy(uuid128, self->uuid128, 16); +} + +uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self) { + return self->size; +} + +void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t *buf) { + if (self->size == 16) { + buf[0] = self->uuid128[12]; + buf[1] = self->uuid128[13]; + } else { + memcpy(buf, self->uuid128, 16); + } +} diff --git a/ports/zephyr-cp/common-hal/_bleio/UUID.h b/ports/zephyr-cp/common-hal/_bleio/UUID.h new file mode 100644 index 00000000000..d58016cffef --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t uuid128[16]; + uint8_t size; +} bleio_uuid_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.c b/ports/zephyr-cp/common-hal/_bleio/__init__.c new file mode 100644 index 00000000000..5b8f8ece898 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.c @@ -0,0 +1,74 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Adapter.h" +#include "supervisor/shared/bluetooth/bluetooth.h" + +// The singleton _bleio.Adapter object +bleio_adapter_obj_t common_hal_bleio_adapter_obj; + +void common_hal_bleio_init(void) { + common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; +} + +void bleio_user_reset(void) { + common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); + common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); + bleio_adapter_reset(&common_hal_bleio_adapter_obj); + + if (supervisor_bluetooth_workflow_is_enabled()) { + supervisor_bluetooth_background(); + } +} + +void bleio_reset(void) { + common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; + + common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); + common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); + + // Keep Zephyr BLE transport up, but present a disabled adapter state. + common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); + bleio_adapter_reset(&common_hal_bleio_adapter_obj); + + if (supervisor_bluetooth_workflow_is_enabled()) { + supervisor_start_bluetooth(); + } +} + +void common_hal_bleio_gc_collect(void) { + // Nothing to do for stubs +} + +void common_hal_bleio_check_connected(uint16_t conn_handle) { + mp_raise_NotImplementedError(NULL); +} + +uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { + mp_raise_NotImplementedError(NULL); +} + +size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { + mp_raise_NotImplementedError(NULL); +} + +size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { + mp_raise_NotImplementedError(NULL); +} + +void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { + mp_raise_NotImplementedError(NULL); +} diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.h b/ports/zephyr-cp/common-hal/_bleio/__init__.h new file mode 100644 index 00000000000..9c30c7c8063 --- /dev/null +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Placeholder for Zephyr-specific BLE defines diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 57f073a9cbb..f043734ebfb 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -29,6 +29,8 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include #include +#include + #define MAC_ADDRESS_LENGTH 6 static void schedule_background_on_cp_core(void *arg) { @@ -44,18 +46,23 @@ static void schedule_background_on_cp_core(void *arg) { static struct net_mgmt_event_callback wifi_cb; static struct net_mgmt_event_callback ipv4_cb; -static void _event_handler(struct net_mgmt_event_callback *cb, uint32_t mgmt_event, struct net_if *iface) { +static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; - printk("_event_handler cb %p event %08x if %p\n", cb, mgmt_event, iface); + printk("_event_handler cb %p event 0x%" PRIx64 " if %p\n", cb, mgmt_event, iface); switch (mgmt_event) { - case NET_EVENT_WIFI_SCAN_RESULT: + case NET_EVENT_WIFI_SCAN_RESULT: { printk("NET_EVENT_WIFI_SCAN_RESULT\n"); - struct wifi_scan_result *result = (struct wifi_scan_result *)cb->info; - if (self->current_scan != NULL) { + #if defined(CONFIG_NET_MGMT_EVENT_INFO) + const struct wifi_scan_result *result = cb->info; + if (result != NULL && self->current_scan != NULL) { wifi_scannednetworks_scan_result(self->current_scan, result); } + #else + printk("Scan result info unavailable (CONFIG_NET_MGMT_EVENT_INFO disabled)\n"); + #endif break; + } case NET_EVENT_WIFI_SCAN_DONE: printk("NET_EVENT_WIFI_SCAN_DONE\n"); if (self->current_scan != NULL) { @@ -281,6 +288,7 @@ void common_hal_wifi_init(bool user_initiated) { net_mgmt_add_event_callback(&wifi_cb); net_mgmt_add_event_callback(&ipv4_cb); + #if defined(CONFIG_NET_HOSTNAME) // Set the default hostname capped at NET_HOSTNAME_MAX_LEN characters. We trim off // the start of the board name (likely manufacturer) because the end is // often more unique to the board. @@ -301,6 +309,9 @@ void common_hal_wifi_init(bool user_initiated) { if (net_hostname_set(cpy_default_hostname, strlen(cpy_default_hostname)) != 0) { printk("setting hostname failed\n"); } + #else + printk("Hostname support disabled in Zephyr config\n"); + #endif // set station mode to avoid the default SoftAP common_hal_wifi_radio_start_station(self); // start wifi diff --git a/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c b/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c index d5e6fd08006..b7a5bf9dbf1 100644 --- a/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c +++ b/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c @@ -12,6 +12,9 @@ void raise_zephyr_error(int err) { + if (err == 0) { + return; + } switch (-err) { case EALREADY: printk("EALREADY\n"); @@ -40,7 +43,14 @@ void raise_zephyr_error(int err) { case ENOTSUP: printk("ENOTSUP\n"); break; + case EADDRINUSE: + printk("EADDRINUSE\n"); + break; + case EINVAL: + printk("EINVAL\n"); + break; default: printk("Zephyr error %d\n", err); } + mp_raise_OSError(-err); } diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 5d3c7d7515d..3a007661c77 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -43,6 +43,7 @@ ALWAYS_ON_MODULES = ["sys", "collections"] DEFAULT_MODULES = [ + "__future__", "time", "os", "microcontroller", @@ -82,7 +83,13 @@ # Other flags to set when a module is enabled EXTRA_FLAGS = {"busio": ["BUSIO_SPI", "BUSIO_I2C"]} -SHARED_MODULE_AND_COMMON_HAL = ["os"] +SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os"] + +# Mapping from module directory name to the flag name used in CIRCUITPY_ +MODULE_FLAG_NAMES = { + "__future__": "FUTURE", + "_bleio": "BLEIO", +} async def preprocess_and_split_defs(compiler, source_file, build_path, flags): @@ -338,6 +345,11 @@ async def build_circuitpython(): autogen_board_info_fn = mpconfigboard_fn.parent / "autogen_board_info.toml" + creator_id = mpconfigboard.get("CIRCUITPY_CREATOR_ID", mpconfigboard.get("USB_VID", 0x1209)) + creation_id = mpconfigboard.get("CIRCUITPY_CREATION_ID", mpconfigboard.get("USB_PID", 0x000C)) + circuitpython_flags.append(f"-DCIRCUITPY_CREATOR_ID=0x{creator_id:08x}") + circuitpython_flags.append(f"-DCIRCUITPY_CREATION_ID=0x{creation_id:08x}") + enabled_modules, module_reasons = determine_enabled_modules(board_info, portdir, srcdir) circuitpython_flags.extend(board_info["cflags"]) @@ -373,6 +385,7 @@ async def build_circuitpython(): supervisor_source = [pathlib.Path(p) for p in supervisor_source] supervisor_source.extend(board_info["source_files"]) supervisor_source.extend(top.glob("supervisor/shared/*.c")) + supervisor_source.append(top / "supervisor/shared/bluetooth/bluetooth.c") supervisor_source.append(top / "supervisor/shared/translate/translate.c") # if web_workflow: # supervisor_source.extend(top.glob("supervisor/shared/web_workflow/*.c")) @@ -445,7 +458,8 @@ async def build_circuitpython(): if module.name in module_reasons: v.comment(module_reasons[module.name]) autogen_modules.add(module.name, v) - circuitpython_flags.append(f"-DCIRCUITPY_{module.name.upper()}={1 if enabled else 0}") + flag_name = MODULE_FLAG_NAMES.get(module.name, module.name.upper()) + circuitpython_flags.append(f"-DCIRCUITPY_{flag_name}={1 if enabled else 0}") if enabled: if module.name in EXTRA_FLAGS: diff --git a/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py b/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py index 95a07930e98..b147ae0605e 100644 --- a/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py +++ b/ports/zephyr-cp/cptools/tests/test_zephyr2cp.py @@ -313,6 +313,45 @@ def test_memory_region_with_custom_name(self): assert label == "reserved_mem" assert start == "__CUSTOM_REGION_end" + def test_memory_region_requires_sram_or_device_type(self): + """Test memory regions require mmio-sram compatibility or device_type=memory.""" + dts = """ +/dts-v1/; + +/ { + #address-cells = <1>; + #size-cells = <1>; + + sram0: memory@20000000 { + compatible = "mmio-sram"; + reg = <0x20000000 0x40000>; + }; + + reserved_mem: memory@30000000 { + compatible = "zephyr,memory-region"; + reg = <0x30000000 0x10000>; + zephyr,memory-region = "CUSTOM_REGION"; + }; + + external_mem: memory@40000000 { + compatible = "zephyr,memory-region"; + device_type = "memory"; + reg = <0x40000000 0x20000>; + zephyr,memory-region = "EXT_REGION"; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; +""" + dt = parse_dts_string(dts) + result = find_ram_regions(dt) + + assert len(result) == 2 + assert result[0][0] == "sram0" + assert result[1][0] == "external_mem" + def test_disabled_ram_excluded(self): """Test that disabled RAM regions are excluded.""" dts = """ diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 0f09c21e83f..d275a7ce960 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -143,6 +143,16 @@ "LCD_D14", "LCD_D15", ], + "nxp,lcd-pmod": [ + "LCD_WR", + "TOUCH_SCL", + "LCD_DC", + "TOUCH_SDA", + "LCD_MOSI", + "TOUCH_RESET", + "LCD_CS", + "TOUCH_INT", + ], "raspberrypi,csi-connector": [ "CSI_D0_N", "CSI_D0_P", @@ -354,6 +364,12 @@ def find_ram_regions(device_tree): if "zephyr,memory-region" not in compatible or "zephyr,memory-region" not in node.props: continue + is_mmio_sram = "mmio-sram" in compatible + device_type = node.props.get("device_type") + has_memory_device_type = device_type and device_type.to_string() == "memory" + if not (is_mmio_sram or has_memory_device_type): + continue + size = node.props["reg"].to_nums()[1] start = "__" + node.props["zephyr,memory-region"].to_string() + "_end" @@ -378,8 +394,26 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa board_info = { "wifi": False, "usb_device": False, + "_bleio": False, } + config_bt_enabled = False + config_bt_found = False + config_present = True + config = zephyrbuilddir / ".config" + if not config.exists(): + config_present = False + else: + for line in config.read_text().splitlines(): + if line.startswith("CONFIG_BT="): + config_bt_enabled = line.strip().endswith("=y") + config_bt_found = True + break + if line.startswith("# CONFIG_BT is not set"): + config_bt_enabled = False + config_bt_found = True + break + runners = zephyrbuilddir / "runners.yaml" runners = yaml.safe_load(runners.read_text()) zephyr_board_dir = pathlib.Path(runners["config"]["board_dir"]) @@ -433,6 +467,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa # Store active Zephyr device labels per-driver so that we can make them available via board. active_zephyr_devices = {} usb_num_endpoint_pairs = 0 + ble_hardware_present = False for k in device_tree.root.nodes["chosen"].props: value = device_tree.root.nodes["chosen"].props[k] path2chosen[value.to_path()] = k @@ -484,6 +519,8 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa usb_num_endpoint_pairs += min(single_direction_endpoints) elif driver.startswith("wifi"): board_info["wifi"] = True + elif driver == "bluetooth/hci": + ble_hardware_present = True elif driver in EXCEPTIONAL_DRIVERS: pass elif driver in BUSIO_CLASSES: @@ -580,7 +617,13 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa board_pin_names = board_names.get((ioport, num), []) for board_pin_name in board_pin_names: - board_pin_name = board_pin_name.upper().replace(" ", "_").replace("-", "_") + board_pin_name = ( + board_pin_name.upper() + .replace(" ", "_") + .replace("-", "_") + .replace("(", "") + .replace(")", "") + ) board_pin_mapping.append( f"{{ MP_ROM_QSTR(MP_QSTR_{board_pin_name}), MP_ROM_PTR(&pin_{pin_object_name}) }}," ) @@ -669,7 +712,8 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa device, start, end, size, path = ram max_size = max(max_size, size) # We always start at the end of a Zephyr linker section so we need the externs and &. - if board_id in ["native_sim"]: + # Native/simulated boards don't have real memory-mapped RAM, so we allocate static arrays. + if board_id in ["native_sim"] or "bsim" in board_id: ram_externs.append("// This is a native board so we provide all of RAM for our heaps.") ram_externs.append(f"static uint32_t _{device}[{size // 4}]; // {path}") start = f"(const uint32_t *) (_{device})" @@ -741,6 +785,17 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); """ board_c.write_text(new_board_c_content) + if ble_hardware_present: + if not config_present: + raise RuntimeError( + "Missing Zephyr .config; CONFIG_BT must be set explicitly when BLE hardware is present." + ) + if not config_bt_found: + raise RuntimeError( + "CONFIG_BT is missing from Zephyr .config; set it explicitly when BLE hardware is present." + ) + + board_info["_bleio"] = ble_hardware_present and config_bt_enabled board_info["source_files"] = [board_c] board_info["cflags"] = ("-I", board_dir) board_info["flash_count"] = len(flashes) diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 485559fe480..121de2c4ae5 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -14,11 +14,13 @@ CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 CONFIG_THREAD_STACK_INFO=y CONFIG_STACK_SENTINEL=y CONFIG_DEBUG_THREAD_INFO=y -# CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_INFO=y +CONFIG_EXCEPTION_STACK_TRACE=y CONFIG_USB_DEVICE_STACK_NEXT=y CONFIG_USBD_CDC_ACM_CLASS=y CONFIG_USBD_MAX_SPEED=1 +CONFIG_USBD_MSC_STACK_SIZE=1536 CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n CONFIG_USBD_MSC_CLASS=y @@ -39,3 +41,16 @@ CONFIG_UART_LINE_CTRL=y CONFIG_I2C=y CONFIG_SPI=y CONFIG_SPI_ASYNC=y + +CONFIG_LOG=y +CONFIG_LOG_MAX_LEVEL=2 +CONFIG_HW_STACK_PROTECTION=y +CONFIG_FRAME_POINTER=y + +CONFIG_BT_BUF_ACL_TX_COUNT=7 +CONFIG_BT_HCI_ERR_TO_STR=y + +CONFIG_NET_HOSTNAME_ENABLE=y +CONFIG_NET_HOSTNAME_DYNAMIC=y +CONFIG_NET_HOSTNAME="circuitpython" +CONFIG_NET_MGMT_EVENT_INFO=y diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 7be2beb1d20..595bc6a3491 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -9,6 +9,10 @@ #include "mpconfigboard.h" #include "supervisor/shared/tick.h" +#if CIRCUITPY_BLEIO +#include "shared-bindings/_bleio/__init__.h" +#endif + #include #include #include @@ -24,6 +28,10 @@ extern const uint32_t *const ram_bounds[]; extern const size_t circuitpy_max_ram_size; static pool_t pools[CIRCUITPY_RAM_DEVICE_COUNT]; +static uint8_t valid_pool_count = 0; +static bool zephyr_malloc_active = false; +static void *zephyr_malloc_top = NULL; +static void *zephyr_malloc_bottom = NULL; static K_EVENT_DEFINE(main_needed); @@ -50,7 +58,9 @@ void reset_cpu(void) { } void reset_port(void) { - + #if CIRCUITPY_BLEIO + bleio_reset(); + #endif } void reset_to_bootloader(void) { @@ -135,19 +145,40 @@ void port_idle_until_interrupt(void) { // Zephyr doesn't maintain one multi-heap. So, make our own using TLSF. void port_heap_init(void) { + #ifdef CONFIG_COMMON_LIBC_MALLOC + // Do a test malloc to determine if Zephyr has an outer heap. + uint32_t *test_malloc = malloc(32); + free(test_malloc); // Free right away so we don't forget. We don't actually write it anyway. + zephyr_malloc_active = test_malloc != NULL; + #endif + for (size_t i = 0; i < CIRCUITPY_RAM_DEVICE_COUNT; i++) { uint32_t *heap_bottom = ram_bounds[2 * i]; uint32_t *heap_top = ram_bounds[2 * i + 1]; size_t size = (heap_top - heap_bottom) * sizeof(uint32_t); + if (size < 1024) { + printk("Skipping region because the linker filled it up.\n"); + continue; + } + #ifdef CONFIG_COMMON_LIBC_MALLOC + if (heap_bottom <= test_malloc && test_malloc < heap_top) { + zephyr_malloc_top = heap_top; + zephyr_malloc_bottom = heap_bottom; + printk("Skipping region because Zephyr malloc is within bounds\n"); + pools[i] = NULL; + continue; + } + #endif printk("Init heap at %p - %p with size %d\n", heap_bottom, heap_top, size); // If this crashes, then make sure you've enabled all of the Kconfig needed for the drivers. - if (i == 0) { + if (valid_pool_count == 0) { heap = tlsf_create_with_pool(heap_bottom, size, circuitpy_max_ram_size); pools[i] = tlsf_get_pool(heap); } else { pools[i] = tlsf_add_pool(heap, heap_bottom + 1, size - sizeof(uint32_t)); } + valid_pool_count++; } #if !DT_HAS_CHOSEN(zephyr_sram) #error "No SRAM!" @@ -155,16 +186,36 @@ void port_heap_init(void) { } void *port_malloc(size_t size, bool dma_capable) { - void *block = tlsf_malloc(heap, size); + void *block = NULL; + if (valid_pool_count > 0) { + block = tlsf_malloc(heap, size); + } + #ifdef CONFIG_COMMON_LIBC_MALLOC + if (block == NULL) { + block = malloc(size); + } + #endif return block; } void port_free(void *ptr) { - tlsf_free(heap, ptr); + if (valid_pool_count > 0 && !(ptr >= zephyr_malloc_bottom && ptr < zephyr_malloc_top)) { + tlsf_free(heap, ptr); + return; + } + #ifdef CONFIG_COMMON_LIBC_MALLOC + free(ptr); + #endif } void *port_realloc(void *ptr, size_t size, bool dma_capable) { - return tlsf_realloc(heap, ptr, size); + if (valid_pool_count > 0 && !(ptr >= zephyr_malloc_bottom && ptr < zephyr_malloc_top)) { + return tlsf_realloc(heap, ptr, size); + } + #ifdef CONFIG_COMMON_LIBC_MALLOC + return realloc(ptr, size); + #endif + return NULL; } static bool max_size_walker(void *ptr, size_t size, int used, void *user) { @@ -177,15 +228,21 @@ static bool max_size_walker(void *ptr, size_t size, int used, void *user) { size_t port_heap_get_largest_free_size(void) { size_t max_size = 0; - for (size_t i = 0; i < CIRCUITPY_RAM_DEVICE_COUNT; i++) { - tlsf_walk_pool(pools[i], max_size_walker, &max_size); + if (valid_pool_count > 0) { + for (size_t i = 0; i < CIRCUITPY_RAM_DEVICE_COUNT; i++) { + if (pools[i] == NULL) { + continue; + } + tlsf_walk_pool(pools[i], max_size_walker, &max_size); + } + // IDF does this. Not sure why. + return tlsf_fit_size(heap, max_size); } - // IDF does this. Not sure why. - return tlsf_fit_size(heap, max_size); + return 64 * 1024; } void assert_post_action(const char *file, unsigned int line) { - printk("Assertion failed at %s:%u\n", file, line); + // printk("Assertion failed at %s:%u\n", file, line); // Check that this is arm #if defined(__arm__) __asm__ ("bkpt"); diff --git a/ports/zephyr-cp/supervisor/usb.c b/ports/zephyr-cp/supervisor/usb.c index 844d4fae759..a42a5192f4f 100644 --- a/ports/zephyr-cp/supervisor/usb.c +++ b/ports/zephyr-cp/supervisor/usb.c @@ -22,7 +22,7 @@ #include "supervisor/shared/reload.h" #include -LOG_MODULE_REGISTER(usb, LOG_LEVEL_INF); +LOG_MODULE_REGISTER(cpusb, CONFIG_LOG_DEFAULT_LEVEL); #define USB_DEVICE DT_NODELABEL(zephyr_udc0) @@ -191,6 +191,20 @@ int _zephyr_disk_ioctl(struct disk_info *disk, uint8_t cmd, void *buff) { static void _msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg) { LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type)); + + if (usbd_can_detect_vbus(ctx)) { + if (msg->type == USBD_MSG_VBUS_READY) { + if (usbd_enable(ctx)) { + LOG_ERR("Failed to enable device support"); + } + } + + if (msg->type == USBD_MSG_VBUS_REMOVED) { + if (usbd_disable(ctx)) { + LOG_ERR("Failed to disable device support"); + } + } + } } void usb_init(void) { @@ -341,12 +355,14 @@ void usb_init(void) { printk("USB initialized\n"); - err = usbd_enable(&main_usbd); - if (err) { - LOG_ERR("Failed to enable device support"); - return; + if (!usbd_can_detect_vbus(&main_usbd)) { + err = usbd_enable(&main_usbd); + if (err) { + LOG_ERR("Failed to enable device support"); + return; + } + printk("usbd enabled\n"); } - printk("usbd enabled\n"); } bool usb_connected(void) { diff --git a/ports/zephyr-cp/sysbuild.cmake b/ports/zephyr-cp/sysbuild.cmake index f0968e05b5c..3c3acf0a803 100644 --- a/ports/zephyr-cp/sysbuild.cmake +++ b/ports/zephyr-cp/sysbuild.cmake @@ -18,4 +18,6 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) CACHE INTERNAL "" ) + native_simulator_set_child_images(${DEFAULT_IMAGE} ${NET_APP}) + native_simulator_set_final_executable(${DEFAULT_IMAGE}) endif() diff --git a/ports/zephyr-cp/tests/__init__.py b/ports/zephyr-cp/tests/__init__.py new file mode 100644 index 00000000000..a560b2c40c1 --- /dev/null +++ b/ports/zephyr-cp/tests/__init__.py @@ -0,0 +1,136 @@ +import serial +import subprocess +import threading + + +class StdSerial: + def __init__(self, stdin, stdout): + self.stdin = stdin + self.stdout = stdout + + def read(self, amount=None): + data = self.stdout.read(amount) + if data == b"": + raise EOFError("stdout closed") + return data + + def write(self, buf): + if self.stdin is None: + return + self.stdin.write(buf) + self.stdin.flush() + + def close(self): + if self.stdin is not None: + self.stdin.close() + self.stdout.close() + + +class SerialSaver: + """Capture serial output in a background thread so output isn't missed.""" + + def __init__(self, serial_obj, name="serial"): + self.all_output = "" + self.all_input = "" + self.serial = serial_obj + self.name = name + + self._stop = threading.Event() + self._lock = threading.Lock() + self._cv = threading.Condition(self._lock) + self._reader = threading.Thread(target=self._reader_loop, daemon=True) + self._reader.start() + + def _reader_loop(self): + while not self._stop.is_set(): + try: + read = self.serial.read(1) + except Exception: + # Serial port closed or device disconnected. + break + + if read == b"": + # Timeout with no data — keep waiting. Only a real + # exception or an explicit stop should end the loop. + continue + + text = read.decode("utf-8", errors="replace") + with self._cv: + self.all_output += text + self._cv.notify_all() + + def wait_for(self, text, timeout=10): + with self._cv: + while text not in self.all_output and self._reader.is_alive(): + if not self._cv.wait(timeout=timeout): + break + if text not in self.all_output: + tail = self.all_output[-400:] + raise TimeoutError( + f"Timed out waiting for {text!r} on {self.name}. Output tail:\n{tail}" + ) + + def read(self, amount=None): + # Kept for compatibility with existing callers. + return + + def close(self): + if not self.serial: + return + + self._stop.set() + try: + self.serial.close() + except Exception: + pass + self._reader.join(timeout=1.0) + self.serial = None + + def write(self, text): + self.all_input += text + self.serial.write(text.encode("utf-8")) + + +class NativeSimProcess: + def __init__(self, cmd, timeout=5, trace_file=None, env=None): + if trace_file: + cmd.append(f"--trace-file={trace_file}") + + self._timeout = timeout + self.trace_file = trace_file + print("Running", " ".join(cmd)) + self._proc = subprocess.Popen( + cmd, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=None, + env=env, + ) + if self._proc.stdout is None: + raise RuntimeError("Failed to capture simulator stdout") + + # Discard the test warning + uart_pty_line = self._proc.stdout.readline().decode("utf-8") + if "connected to pseudotty:" not in uart_pty_line: + raise RuntimeError("Failed to connect to UART") + pty_path = uart_pty_line.strip().rsplit(":", maxsplit=1)[1].strip() + self.serial = SerialSaver( + serial.Serial(pty_path, baudrate=115200, timeout=0.05, write_timeout=0), + name="uart0", + ) + self.debug_serial = SerialSaver( + StdSerial(self._proc.stdin, self._proc.stdout), name="debug" + ) + + def shutdown(self): + if self._proc.poll() is None: + self._proc.terminate() + self._proc.wait(timeout=self._timeout) + + self.serial.close() + self.debug_serial.close() + + def wait_until_done(self): + self._proc.wait(timeout=self._timeout) + self.serial.close() + self.debug_serial.close() diff --git a/ports/zephyr-cp/tests/bsim/__init__.py b/ports/zephyr-cp/tests/bsim/__init__.py new file mode 100644 index 00000000000..75136bccf43 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/__init__.py @@ -0,0 +1,3 @@ +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") diff --git a/ports/zephyr-cp/tests/bsim/conftest.py b/ports/zephyr-cp/tests/bsim/conftest.py new file mode 100644 index 00000000000..505ff77bf7e --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/conftest.py @@ -0,0 +1,222 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Pytest fixtures for CircuitPython bsim testing.""" + +import logging +import os +import shutil +import subprocess +from pathlib import Path + +import pytest + +from .. import SerialSaver, StdSerial + +logger = logging.getLogger(__name__) + +ZEPHYR_CP = Path(__file__).resolve().parents[2] +BSIM_BUILD_DIR = ZEPHYR_CP / "build-native_nrf5340bsim" +BSIM_SYSBUILD_BINARY = BSIM_BUILD_DIR / "zephyr/zephyr.exe" +BSIM_BINARY = BSIM_BUILD_DIR / "zephyr-cp/zephyr/zephyr.exe" +BSIM_ROOT = ZEPHYR_CP / "tools/bsim" +BSIM_PHY_BINARY = BSIM_ROOT / "bin/bs_2G4_phy_v1" + + +@pytest.fixture +def native_sim_env() -> dict[str, str]: + env = os.environ.copy() + env["BSIM_OUT_PATH"] = str(BSIM_ROOT) + env["BSIM_COMPONENTS_PATH"] = str(BSIM_ROOT / "components") + lib_path = str(BSIM_ROOT / "lib") + existing = env.get("LD_LIBRARY_PATH", "") + env["LD_LIBRARY_PATH"] = f"{lib_path}:{existing}" if existing else lib_path + return env + + +@pytest.fixture +def bsim_binary(): + """Return path to nrf5340bsim binary, skip if not built.""" + if BSIM_SYSBUILD_BINARY.exists(): + return BSIM_SYSBUILD_BINARY + if not BSIM_BINARY.exists(): + pytest.skip(f"nrf5340bsim not built: {BSIM_BINARY}") + return BSIM_BINARY + + +@pytest.fixture +def bsim_phy_binary(): + """Return path to BabbleSim PHY binary, skip if not present.""" + if not BSIM_PHY_BINARY.exists(): + pytest.skip(f"bs_2G4_phy_v1 not found: {BSIM_PHY_BINARY}") + return BSIM_PHY_BINARY + + +class BsimPhyInstance: + def __init__(self, proc: subprocess.Popen, serial: SerialSaver, timeout: float): + self.proc = proc + self.serial = serial + self.timeout = timeout + + def finish_sim(self) -> None: + self.serial.wait_for("Cleaning up", timeout=self.timeout + 5) + + def shutdown(self) -> None: + if self.proc.poll() is None: + self.proc.terminate() + self.proc.wait(timeout=2) + self.serial.close() + + +class ZephyrSampleProcess: + def __init__(self, proc: subprocess.Popen, timeout: float): + self._proc = proc + self._timeout = timeout + if proc.stdout is None: + raise RuntimeError("Failed to capture Zephyr sample stdout") + self.serial = SerialSaver(StdSerial(None, proc.stdout), name="zephyr sample") + + def shutdown(self) -> None: + if self._proc.poll() is None: + self._proc.terminate() + self._proc.wait(timeout=self._timeout) + self.serial.close() + + +@pytest.fixture +def bsim_phy(request, bsim_phy_binary, native_sim_env, sim_id): + duration_marker = request.node.get_closest_marker("duration") + sim_length = float(duration_marker.args[0]) if duration_marker else 20.0 + + devices = 1 + if "circuitpython2" in request.fixturenames or "zephyr_sample" in request.fixturenames: + devices = 2 + + sample_marker = request.node.get_closest_marker("zephyr_sample") + if sample_marker is not None: + sample_device_id = int(sample_marker.kwargs.get("device_id", 1)) + devices = max(devices, sample_device_id + 1) + + bsim_marker = request.node.get_closest_marker("bsim") + if bsim_marker is not None: + devices = int(bsim_marker.kwargs.get("devices", devices)) + sim_length = float(bsim_marker.kwargs.get("sim_length", sim_length)) + + sim_length_us = int(sim_length * 1e6) + cmd = [ + "stdbuf", + "-oL", + str(bsim_phy_binary), + "-v=9", # Cleaning up level is on 9. Connecting is 7. + f"-s={sim_id}", + f"-D={devices}", + f"-sim_length={sim_length_us}", + ] + print("Running:", " ".join(cmd)) + proc = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env=native_sim_env, + cwd=BSIM_ROOT / "bin", + ) + if proc.stdout is None: + raise RuntimeError("Failed to capture bsim phy stdout") + + # stdbuf -oL forces line-buffered stdout so SerialSaver can + # stream-read PHY output in real time. Wrapping in StdSerial + # ensures the reader thread exits on EOF when the PHY process + # terminates, rather than spinning on empty timeout reads. + phy_output = SerialSaver(StdSerial(None, proc.stdout), name="bsim phy") + try: + phy_output.wait_for("Connecting", timeout=2) + except TimeoutError: + if proc.poll() is not None: + print(phy_output.all_output) + raise RuntimeError("bsim PHY exited immediately") + # Assume bsim is running + + phy = BsimPhyInstance(proc, phy_output, timeout=sim_length) + yield phy + phy.shutdown() + + print("bsim phy output:") + print(phy_output.all_output) + + +def _build_zephyr_sample(build_dir: Path, source_dir: Path, board: str) -> Path: + if shutil.which("west") is None: + raise RuntimeError("west not found") + + cmd = [ + "west", + "build", + "-b", + board, + "-d", + str(build_dir), + "-p=auto", + str(source_dir), + ] + logger.info("Building Zephyr sample: %s", " ".join(cmd)) + subprocess.run(cmd, check=True, cwd=ZEPHYR_CP) + + return build_dir / "zephyr/zephyr.exe" + + +@pytest.fixture +def zephyr_sample(request, bsim_phy, native_sim_env, sim_id): + marker = request.node.get_closest_marker("zephyr_sample") + if marker is None or len(marker.args) != 1: + raise RuntimeError( + "zephyr_sample fixture requires @pytest.mark.zephyr_sample('')" + ) + + sample = marker.args[0] + board = marker.kwargs.get("board", "nrf52_bsim") + device_id = int(marker.kwargs.get("device_id", 1)) + timeout = float(marker.kwargs.get("timeout", 10.0)) + + sample_rel = str(sample).removeprefix("zephyr/samples/") + source_dir = ZEPHYR_CP / "zephyr/samples" / sample_rel + if not source_dir.exists(): + pytest.skip(f"Zephyr sample not found: {source_dir}") + + build_name = f"build-bsim-sample-{sample_rel.replace('/', '_')}-{board}" + build_dir = ZEPHYR_CP / build_name + binary = build_dir / "zephyr/zephyr.exe" + + if not binary.exists(): + try: + binary = _build_zephyr_sample(build_dir, source_dir, board) + except (subprocess.CalledProcessError, RuntimeError) as exc: + pytest.skip(f"Failed to build Zephyr sample {sample_rel}: {exc}") + + if not binary.exists(): + pytest.skip(f"Zephyr sample binary not found: {binary}") + + cmd = [str(binary), f"-s={sim_id}", f"-d={device_id}"] + logger.info("Running: %s", " ".join(cmd)) + proc = subprocess.Popen( + cmd, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env=native_sim_env, + ) + sample_proc = ZephyrSampleProcess(proc, timeout=timeout) + yield sample_proc + sample_proc.shutdown() + + print("Zephyr sample output:") + print(sample_proc.serial.all_output) + + +@pytest.fixture +def circuitpython1(circuitpython): + return circuitpython[0] + + +@pytest.fixture +def circuitpython2(circuitpython): + return circuitpython[1] diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py new file mode 100644 index 00000000000..7f1ad036f6f --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py @@ -0,0 +1,34 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Basic BabbleSim connectivity tests for nrf5340bsim.""" + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +BSIM_CODE = """\ +print("bsim ready") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) +def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2): + """Run two bsim instances on the same sim id and verify UART output.""" + print("in the test") + + # Wait for both devices to produce their expected output before + # tearing down the simulation. + circuitpython1.serial.wait_for("bsim ready") + circuitpython2.serial.wait_for("bsim ready") + + bsim_phy.finish_sim() + + output0 = circuitpython1.serial.all_output + output1 = circuitpython2.serial.all_output + + assert "Board ID:native_nrf5340bsim" in output0 + assert "Board ID:native_nrf5340bsim" in output1 + assert "bsim ready" in output0 + assert "bsim ready" in output1 diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py new file mode 100644 index 00000000000..4822d42b9bb --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -0,0 +1,111 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE advertising tests for nrf5340bsim.""" + +import logging +import time + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +logger = logging.getLogger(__name__) + +BSIM_ADV_CODE = """\ +import _bleio +import time + +name = b"CPADV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +adapter = _bleio.adapter +print("adv start") +adapter.start_advertising(advertisement, connectable=False) +print("adv started") +time.sleep(4) +adapter.stop_advertising() +print("adv stop") +""" + +BSIM_ADV_INTERRUPT_RELOAD_CODE = """\ +import _bleio +import time + +name = b"CPADV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +adapter = _bleio.adapter +print("adv run start") +adapter.start_advertising(advertisement, connectable=False) +print("adv running") +while True: + time.sleep(0.2) +""" + + +@pytest.mark.zephyr_sample("bluetooth/observer") +@pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_CODE}) +def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): + """Advertise from CircuitPython and verify Zephyr observer sees traffic.""" + observer = zephyr_sample + + start_time = time.time() + while time.time() - start_time < 12.0: + observer_output = observer.serial.all_output + adv_ready = "adv started" in circuitpython.serial.all_output + if ( + "Device found:" in observer_output + and "AD data len 10" in observer_output + and adv_ready + ): + break + time.sleep(0.05) + + observer_output = observer.serial.all_output + assert "adv start" in circuitpython.serial.all_output + assert "adv started" in circuitpython.serial.all_output + assert "Device found:" in observer_output + assert "AD data len 10" in observer_output + + +@pytest.mark.zephyr_sample("bluetooth/observer", timeout=20.0) +@pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_INTERRUPT_RELOAD_CODE}) +def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): + """Ensure advertising resumes after Ctrl-C and a reload.""" + observer = zephyr_sample + + start_time = time.time() + sent_ctrl_c = False + sent_reload = False + observer_count_before = 0 + + while time.time() - start_time < 22.0: + cp_output = circuitpython.serial.all_output + observer_output = observer.serial.all_output + device_found_count = observer_output.count("Device found:") + + if not sent_ctrl_c and "adv running" in cp_output and device_found_count > 0: + circuitpython.serial.write("\x03") + sent_ctrl_c = True + observer_count_before = device_found_count + + if sent_ctrl_c and not sent_reload and "KeyboardInterrupt" in cp_output: + circuitpython.serial.write("\x04") + sent_reload = True + + if sent_reload and cp_output.count("adv running") >= 2: + break + + time.sleep(0.05) + + cp_output = circuitpython.serial.all_output + observer_output = observer.serial.all_output + logger.info(observer_output) + logger.info(cp_output) + + assert "adv run start" in cp_output + assert "KeyboardInterrupt" in cp_output + assert cp_output.count("adv running") >= 2 + assert observer_output.count("Device found:") >= observer_count_before + assert "Already advertising" not in cp_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py new file mode 100644 index 00000000000..a7f76ca72b7 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py @@ -0,0 +1,31 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE name tests for nrf5340bsim.""" + +import time + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +BSIM_NAME_CODE = """\ +import _bleio + +adapter = _bleio.adapter +adapter.enabled = True +adapter.name = "CPNAME" +print("name", adapter.name) +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_NAME_CODE}) +def test_bsim_set_name(bsim_phy, circuitpython): + """Set the BLE name and read it back on bsim.""" + start_time = time.time() + while time.time() - start_time < 3.0: + if "name CPNAME" in circuitpython.serial.all_output: + break + time.sleep(0.05) + + assert "name CPNAME" in circuitpython.serial.all_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py new file mode 100644 index 00000000000..88366698016 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -0,0 +1,151 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE scanning tests for nrf5340bsim.""" + +import time + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +BSIM_SCAN_CODE = """\ +import _bleio + +adapter = _bleio.adapter +print("scan start") +scan = adapter.start_scan(timeout=4.0, active=True) +found = False +for entry in scan: + if b"zephyrproject" in entry.advertisement_bytes: + print("found beacon") + found = True + break +adapter.stop_scan() +print("scan done", found) +""" + +BSIM_SCAN_RELOAD_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("scan run start") +for _ in range(10): + try: + scan = adapter.start_scan(timeout=4.0, active=True) + break + except OSError: + time.sleep(0.1) +else: + raise RuntimeError("scan start failed") +found = False +for entry in scan: + if b"zephyrproject" in entry.advertisement_bytes: + print("found beacon run") + found = True + break +adapter.stop_scan() +print("scan run done", found) +""" + +BSIM_SCAN_RELOAD_NO_STOP_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("scan run start") +for _ in range(10): + try: + scan = adapter.start_scan(timeout=4.0, active=True) + break + except OSError: + time.sleep(0.1) +else: + raise RuntimeError("scan start failed") +found = False +for entry in scan: + if b"zephyrproject" in entry.advertisement_bytes: + print("found beacon run") + found = True + break +print("scan run done", found) +""" + + +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_CODE}) +def test_bsim_scan_zephyr_beacon(bsim_phy, circuitpython, zephyr_sample): + """Scan for Zephyr beacon sample advertisement using bsim.""" + _ = zephyr_sample + + start_time = time.time() + while time.time() - start_time < 6.0: + if "found beacon" in circuitpython.serial.all_output: + break + time.sleep(0.05) + + assert "scan start" in circuitpython.serial.all_output + assert "found beacon" in circuitpython.serial.all_output + + +@pytest.mark.zephyr_sample("bluetooth/beacon", timeout=12.0) +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_CODE}) +def test_bsim_scan_zephyr_beacon_reload(bsim_phy, circuitpython, zephyr_sample): + """Scan for Zephyr beacon, soft reload, and scan again.""" + _ = zephyr_sample + + start_time = time.time() + sent_reload = False + while time.time() - start_time < 12.0: + output = circuitpython.serial.all_output + + if ( + not sent_reload + and "scan run done" in output + and "Press any key to enter the REPL" in output + ): + time.sleep(0.2) + circuitpython.serial.write("\x04") + sent_reload = True + + if sent_reload and output.count("scan run done") >= 2: + break + time.sleep(0.05) + + output = circuitpython.serial.all_output + assert "scan run start" in output + assert output.count("found beacon run") >= 2 + assert output.count("scan run done") >= 2 + + +@pytest.mark.zephyr_sample("bluetooth/beacon", timeout=12.0) +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_NO_STOP_CODE}) +def test_bsim_scan_zephyr_beacon_reload_no_stop(bsim_phy, circuitpython, zephyr_sample): + """Scan for Zephyr beacon without explicit stop, soft reload, and scan again.""" + _ = zephyr_sample + + start_time = time.time() + sent_reload = False + while time.time() - start_time < 12.0: + output = circuitpython.serial.all_output + + if ( + not sent_reload + and "scan run done" in output + and "Press any key to enter the REPL" in output + ): + time.sleep(0.2) + circuitpython.serial.write("\x04") + sent_reload = True + + if sent_reload and output.count("scan run done") >= 2: + break + time.sleep(0.05) + + output = circuitpython.serial.all_output + assert "scan run start" in output + assert output.count("found beacon run") >= 2 + assert output.count("scan run done") >= 2 diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index f26c7f0f45f..f6545a46b55 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -4,7 +4,6 @@ """Pytest fixtures for CircuitPython native_sim testing.""" import logging -import os import re import select import subprocess @@ -13,59 +12,37 @@ from pathlib import Path import pytest +import serial +from . import NativeSimProcess + from perfetto.trace_processor import TraceProcessor logger = logging.getLogger(__name__) -ZEPHYR_CP = Path(__file__).parent.parent -BUILD_DIR = ZEPHYR_CP / "build-native_native_sim" -BINARY = BUILD_DIR / "zephyr-cp/zephyr/zephyr.exe" - - -@dataclass -class InputTrigger: - """A trigger for sending input to the simulator. - - Attributes: - trigger: Text to match in output to trigger input, or None for immediate send. - data: Bytes to send when triggered. - sent: Whether this trigger has been sent (set internally). - """ - trigger: str | None - data: bytes - sent: bool = False - - -@dataclass -class SimulatorResult: - """Result from running CircuitPython on the simulator.""" - - output: str - trace_file: Path - - -def parse_gpio_trace(trace_file: Path, pin_name: str = "gpio_emul.00") -> list[tuple[int, int]]: - """Parse GPIO trace from Perfetto trace file. +def pytest_configure(config): + config.addinivalue_line( + "markers", "circuitpy_drive(files): run CircuitPython with files in the flash image" + ) + config.addinivalue_line( + "markers", "disable_i2c_devices(*names): disable native_sim I2C emulator devices" + ) + config.addinivalue_line( + "markers", "circuitpython_board(board_id): which board id to use in the test" + ) + config.addinivalue_line( + "markers", + "zephyr_sample(sample, board='nrf52_bsim', device_id=1): build and run a Zephyr sample for bsim tests", + ) + config.addinivalue_line( + "markers", + "bsim(devices=1, sim_length=20.0): configure bsim PHY device count and simulation length", + ) - Args: - trace_file: Path to the Perfetto trace file. - pin_name: Name of the GPIO pin track (e.g., "gpio_emul.00"). - Returns: - List of (timestamp_ns, value) tuples for the specified GPIO pin. - """ - tp = TraceProcessor(file_path=str(trace_file)) - result = tp.query( - f''' - SELECT c.ts, c.value - FROM counter c - JOIN track t ON c.track_id = t.id - WHERE t.name = "{pin_name}" - ORDER BY c.ts - ''' - ) - return [(row.ts, int(row.value)) for row in result] +ZEPHYR_CP = Path(__file__).parent.parent +BUILD_DIR = ZEPHYR_CP / "build-native_native_sim" +BINARY = BUILD_DIR / "zephyr-cp/zephyr/zephyr.exe" def _iter_uart_tx_slices(trace_file: Path) -> list[tuple[int, int, str, str]]: @@ -134,179 +111,99 @@ def log_uart_trace_output(trace_file: Path) -> None: @pytest.fixture -def native_sim_binary(): - """Return path to native_sim binary, skip if not built.""" - if not BINARY.exists(): - pytest.skip(f"native_sim not built: {BINARY}") - return BINARY +def board(request): + board = request.node.get_closest_marker("circuitpython_board") + print("board", board) + if board is not None: + board = board.args[0] + else: + board = "native_native_sim" + return board @pytest.fixture -def create_flash_image(tmp_path): - """Factory fixture to create FAT flash images.""" - - def _create(files: dict[str, str]) -> Path: - flash = tmp_path / "flash.bin" +def native_sim_binary(request, board): + """Return path to native_sim binary, skip if not built.""" + ZEPHYR_CP = Path(__file__).parent.parent + build_dir = ZEPHYR_CP / f"build-{board}" + binary = build_dir / "zephyr-cp/zephyr/zephyr.exe" - # Create 2MB empty file - flash.write_bytes(b"\x00" * (2 * 1024 * 1024)) + if not binary.exists(): + pytest.skip(f"binary not built: {binary}") + return binary - # Format as FAT (mformat) - subprocess.run(["mformat", "-i", str(flash), "::"], check=True) - # Copy files (mcopy) - for name, content in files.items(): - src = tmp_path / name - src.write_text(content) - subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) +@pytest.fixture +def native_sim_env() -> dict[str, str]: + return {} - return flash - return _create +@pytest.fixture +def sim_id(request) -> str: + return request.node.nodeid.replace("/", "_") @pytest.fixture -def run_circuitpython(native_sim_binary, create_flash_image, tmp_path): - """Run CircuitPython with given code string and return output from PTY. - - Args: - code: Python code to write to code.py, or None for no code.py. - timeout: Timeout in seconds for the simulation. - erase_flash: If True, erase flash before running. - input_sequence: List of InputTrigger objects. When trigger text is seen - in output, the corresponding data is written to the PTY. If trigger - is None, the data is sent immediately when PTY is opened. - """ - - def _run( - code: str | None, - timeout: float = 5.0, - erase_flash: bool = False, - input_sequence: list[InputTrigger] | None = None, - disabled_i2c_devices: list[str] | None = None, - ) -> SimulatorResult: - files = {"code.py": code} if code is not None else {} - flash = create_flash_image(files) - triggers = list(input_sequence) if input_sequence else [] - trace_file = tmp_path / "trace.perfetto" - - cmd = [ - str(native_sim_binary), - f"--flash={flash}", - "--flash_rm", - "-no-rt", - "-wait_uart", - f"-stop_at={timeout}", - f"--trace-file={trace_file}", - ] - if erase_flash: - cmd.append("--flash_erase") - if disabled_i2c_devices: - for device in disabled_i2c_devices: +def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp_path): + """Run CircuitPython with given code string and return PTY output.""" + + instance_count = 1 + if "circuitpython1" in request.fixturenames and "circuitpython2" in request.fixturenames: + instance_count = 2 + + drives = list(request.node.iter_markers_with_node("circuitpy_drive")) + if len(drives) != instance_count: + raise RuntimeError(f"not enough drives for {instance_count} instances") + + procs = [] + for i in range(instance_count): + flash = tmp_path / f"flash-{i}.bin" + flash.write_bytes(b"\xff" * (2 * 1024 * 1024)) + files = None + if len(drives[i][1].args) == 1: + files = drives[i][1].args[0] + if files is not None: + subprocess.run(["mformat", "-i", str(flash), "::"], check=True) + tmp_drive = tmp_path / f"drive{i}" + tmp_drive.mkdir(exist_ok=True) + + for name, content in files.items(): + src = tmp_drive / name + src.write_text(content) + subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) + + trace_file = tmp_path / f"trace-{i}.perfetto" + + marker = request.node.get_closest_marker("duration") + if marker is None: + timeout = 10 + else: + timeout = marker.args[0] + if "bsim" in board: + cmd = [str(native_sim_binary), f"--flash_app={flash}"] + cmd.extend((f"-s={sim_id}", f"-d={i}", "-uart0_pty", "-uart_pty_wait")) + else: + cmd = [str(native_sim_binary), f"--flash={flash}"] + cmd.extend(("-no-rt", "-wait_uart", f"-stop_at={timeout}")) + + marker = request.node.get_closest_marker("disable_i2c_devices") + if marker and len(marker.args) > 0: + for device in marker.args: cmd.append(f"--disable-i2c={device}") logger.info("Running: %s", " ".join(cmd)) - # Start the process - proc = subprocess.Popen( - cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, - ) - - pty_path = None - pty_fd = None - output = [] - stdout_lines = [] - - try: - # Read stdout to find the PTY path - start_time = time.time() - while time.time() - start_time < timeout + 5: - if proc.poll() is not None: - # Process exited - break - - # Check if stdout has data - ready, _, _ = select.select([proc.stdout], [], [], 0.1) - if ready: - line = proc.stdout.readline() - if not line: - break - - stdout_lines.append(line.rstrip()) - - # Look for PTY path - match = re.search(r"uart connected to pseudotty: (/dev/pts/\d+)", line) - if match: - pty_path = match.group(1) - # Open the PTY for reading and writing - pty_fd = os.open(pty_path, os.O_RDWR | os.O_NONBLOCK) - - # Send any immediate triggers (trigger=None) - for t in triggers: - if t.trigger is None and not t.sent: - os.write(pty_fd, t.data) - logger.info("PTY input (immediate): %r", t.data) - t.sent = True - break - - if pty_fd is None: - raise RuntimeError("Failed to find PTY path in output") - - def check_triggers(accumulated_output: str) -> None: - """Check accumulated output against triggers and send input.""" - for t in triggers: - if t.trigger is not None and not t.sent: - if t.trigger in accumulated_output: - os.write(pty_fd, t.data) - logger.info("PTY input (trigger %r): %r", t.trigger, t.data) - t.sent = True - - # Read from PTY until process exits or timeout - while time.time() - start_time < timeout + 1: - if proc.poll() is not None: - # Process exited, do one final read - try: - ready, _, _ = select.select([pty_fd], [], [], 0.1) - if ready: - data = os.read(pty_fd, 4096) - if data: - output.append(data.decode("utf-8", errors="replace")) - except (OSError, BlockingIOError): - pass - break - - # Check if PTY has data - try: - ready, _, _ = select.select([pty_fd], [], [], 0.1) - if ready: - data = os.read(pty_fd, 4096) - if data: - output.append(data.decode("utf-8", errors="replace")) - check_triggers("".join(output)) - except (OSError, BlockingIOError): - pass - - # Read any remaining stdout - remaining_stdout = proc.stdout.read() - if remaining_stdout: - stdout_lines.extend(remaining_stdout.rstrip().split("\n")) - - # Log stdout - for line in stdout_lines: - logger.info("stdout: %s", line) - - pty_output = "".join(output) - for line in pty_output.split("\n"): - logger.info("PTY output: %s", repr(line.strip())) - log_uart_trace_output(trace_file) - return SimulatorResult(output=pty_output, trace_file=trace_file) - - finally: - if pty_fd is not None: - os.close(pty_fd) - proc.terminate() - proc.wait(timeout=1) - - return _run + procs.append(NativeSimProcess(cmd, timeout, trace_file, native_sim_env)) + if instance_count == 1: + yield procs[0] + else: + yield procs + for i, proc in enumerate(procs): + if instance_count > 1: + print(f"---------- Instance {i} -----------") + proc.shutdown() + + print("All serial output:") + print(proc.serial.all_output) + print() + print("All debug serial output:") + print(proc.debug_serial.all_output) diff --git a/ports/zephyr-cp/tests/docs/babblesim.md b/ports/zephyr-cp/tests/docs/babblesim.md new file mode 100644 index 00000000000..39d60fa306c --- /dev/null +++ b/ports/zephyr-cp/tests/docs/babblesim.md @@ -0,0 +1,69 @@ +# BabbleSim testing + +This document describes how to build and run CircuitPython tests against the +BabbleSim (bsim) nRF5340 board. + +## Board target + +We use the Zephyr BabbleSim board for the nRF5340 application core: + +- Zephyr board: `nrf5340bsim/nrf5340/cpuapp` +- CircuitPython board alias: `native_nrf5340bsim` + +The tests expect two bsim instances to run in the same simulation, which allows +future BLE/802.15.4 multi-node tests. + +## Prerequisites + +BabbleSim needs to be available to Zephyr. Either: + +- Use the repo-provided `tools/bsim` checkout (if present) +- Or set environment variables: + +``` +export BSIM_COMPONENTS_PATH=/path/to/bsim/components +export BSIM_OUT_PATH=/path/to/bsim +``` + +## Build + +``` +CCACHE_TEMPDIR=/tmp/ccache-tmp make -j32 BOARD=native_nrf5340bsim +``` + +If you do not use ccache, you can omit `CCACHE_TEMPDIR`. + +## Run the bsim test + +``` +pytest tests/test_bsim_basics.py -v +``` + +## BLE scan + advertising tests + +The BLE tests run multiple bsim instances and build Zephyr samples on-demand: + +- `tests/test_bsim_ble_scan.py` scans for the Zephyr beacon sample +- `tests/test_bsim_ble_advertising.py` advertises from CircuitPython while the + Zephyr observer sample scans + +The fixtures build the Zephyr samples if missing: + +- Beacon: `zephyr/samples/bluetooth/beacon` (board `nrf52_bsim`) +- Observer: `zephyr/samples/bluetooth/observer` (board `nrf52_bsim`) + +Run the tests with: + +``` +pytest tests/test_bsim_ble_scan.py -v +pytest tests/test_bsim_ble_advertising.py -v +``` + +## Notes + +- The bsim test spawns two instances that share a sim id. It only checks UART + output for now, but is the base for BLE/Thread multi-node tests. +- The BLE tests rely on the sysbuild HCI IPC net-core image for the nRF5340 + simulator (enabled via `sysbuild.conf`). +- The board uses a custom devicetree overlay to provide the SRAM region and + CircuitPython flash partition expected by the port. diff --git a/ports/zephyr-cp/tests/test_basics.py b/ports/zephyr-cp/tests/test_basics.py index 9abb7f451b7..96f41d39795 100644 --- a/ports/zephyr-cp/tests/test_basics.py +++ b/ports/zephyr-cp/tests/test_basics.py @@ -3,18 +3,23 @@ """Test LED blink functionality on native_sim.""" -from conftest import InputTrigger, parse_gpio_trace +import pytest +from pathlib import Path +from perfetto.trace_processor import TraceProcessor -def test_blank_flash_hello_world(run_circuitpython): + +@pytest.mark.circuitpy_drive(None) +def test_blank_flash_hello_world(circuitpython): """Test that an erased flash shows code.py output header.""" - result = run_circuitpython(None, timeout=4, erase_flash=True) + circuitpython.wait_until_done() - assert "Board ID:native_native_sim" in result.output - assert "UID:" in result.output - assert "code.py output:" in result.output - assert "Hello World" in result.output - assert "done" in result.output + output = circuitpython.serial.all_output + assert "Board ID:native_native_sim" in output + assert "UID:" in output + assert "code.py output:" in output + assert "Hello World" in output + assert "done" in output BLINK_CODE = """\ @@ -37,19 +42,36 @@ def test_blank_flash_hello_world(run_circuitpython): """ -def test_blink_output(run_circuitpython): +def parse_gpio_trace(trace_file: Path, pin_name: str = "gpio_emul.00") -> list[tuple[int, int]]: + """Parse GPIO trace from Perfetto trace file.""" + tp = TraceProcessor(file_path=str(trace_file)) + result = tp.query( + f''' + SELECT c.ts, c.value + FROM counter c + JOIN track t ON c.track_id = t.id + WHERE t.name = "{pin_name}" + ORDER BY c.ts + ''' + ) + return [(row.ts, int(row.value)) for row in result] + + +@pytest.mark.circuitpy_drive({"code.py": BLINK_CODE}) +def test_blink_output(circuitpython): """Test blink program produces expected output and GPIO traces.""" - result = run_circuitpython(BLINK_CODE, timeout=5) + circuitpython.wait_until_done() # Check serial output - assert "LED on 0" in result.output - assert "LED off 0" in result.output - assert "LED on 2" in result.output - assert "LED off 2" in result.output - assert "done" in result.output + output = circuitpython.serial.all_output + assert "LED on 0" in output + assert "LED off 0" in output + assert "LED on 2" in output + assert "LED off 2" in output + assert "done" in output # Check GPIO traces - LED is on gpio_emul.00 - gpio_trace = parse_gpio_trace(result.trace_file, "gpio_emul.00") + gpio_trace = parse_gpio_trace(circuitpython.trace_file, "gpio_emul.00") # Deduplicate by timestamp (keep last value at each timestamp) by_timestamp = {} @@ -115,17 +137,17 @@ def test_blink_output(run_circuitpython): """ -def test_basic_serial_input(run_circuitpython): +@pytest.mark.circuitpy_drive({"code.py": INPUT_CODE}) +def test_basic_serial_input(circuitpython): """Test reading single character from serial via PTY write.""" - result = run_circuitpython( - INPUT_CODE, - timeout=5.0, - input_sequence=[InputTrigger(trigger="ready", data=b"A")], - ) + circuitpython.serial.wait_for("ready") + circuitpython.serial.write("A") + circuitpython.wait_until_done() - assert "ready" in result.output - assert "received: 'A'" in result.output - assert "done" in result.output + output = circuitpython.serial.all_output + assert "ready" in output + assert "received: 'A'" in output + assert "done" in output INPUT_FUNC_CODE = """\ @@ -136,18 +158,18 @@ def test_basic_serial_input(run_circuitpython): """ -def test_input_function(run_circuitpython): +@pytest.mark.circuitpy_drive({"code.py": INPUT_FUNC_CODE}) +def test_input_function(circuitpython): """Test the built-in input() function with PTY input.""" - result = run_circuitpython( - INPUT_FUNC_CODE, - timeout=5.0, - input_sequence=[InputTrigger(trigger="Enter name:", data=b"World\r")], - ) + circuitpython.serial.wait_for("Enter name:") + circuitpython.serial.write("World\r") + circuitpython.wait_until_done() - assert "ready" in result.output - assert "Enter name:" in result.output - assert "hello World" in result.output - assert "done" in result.output + output = circuitpython.serial.all_output + assert "ready" in output + assert "Enter name:" in output + assert "hello World" in output + assert "done" in output INTERRUPT_CODE = """\ @@ -161,18 +183,18 @@ def test_input_function(run_circuitpython): """ -def test_ctrl_c_interrupt(run_circuitpython): +@pytest.mark.circuitpy_drive({"code.py": INTERRUPT_CODE}) +def test_ctrl_c_interrupt(circuitpython): """Test sending Ctrl+C (0x03) to interrupt running code.""" - result = run_circuitpython( - INTERRUPT_CODE, - timeout=15.0, - input_sequence=[InputTrigger(trigger="loop 5", data=b"\x03")], - ) + circuitpython.serial.wait_for("loop 5") + circuitpython.serial.write("\x03") + circuitpython.wait_until_done() - assert "starting" in result.output - assert "loop 5" in result.output - assert "KeyboardInterrupt" in result.output - assert "completed" not in result.output + output = circuitpython.serial.all_output + assert "starting" in output + assert "loop 5" in output + assert "KeyboardInterrupt" in output + assert "completed" not in output RELOAD_CODE = """\ @@ -183,17 +205,17 @@ def test_ctrl_c_interrupt(run_circuitpython): """ -def test_ctrl_d_soft_reload(run_circuitpython): +@pytest.mark.circuitpy_drive({"code.py": RELOAD_CODE}) +def test_ctrl_d_soft_reload(circuitpython): """Test sending Ctrl+D (0x04) to trigger soft reload.""" - result = run_circuitpython( - RELOAD_CODE, - timeout=10.0, - input_sequence=[InputTrigger(trigger="first run", data=b"\x04")], - ) + circuitpython.serial.wait_for("first run") + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() # Should see "first run" appear multiple times due to reload # or see a soft reboot message - assert "first run" in result.output + output = circuitpython.serial.all_output + assert "first run" in output # The soft reload should restart the code before "done" is printed - assert "done" in result.output - assert result.output.count("first run") > 1 + assert "done" in output + assert output.count("first run") > 1 diff --git a/ports/zephyr-cp/tests/test_i2c.py b/ports/zephyr-cp/tests/test_i2c.py index 594dfcc8f4d..ec5229faa2f 100644 --- a/ports/zephyr-cp/tests/test_i2c.py +++ b/ports/zephyr-cp/tests/test_i2c.py @@ -3,6 +3,8 @@ """Test I2C functionality on native_sim.""" +import pytest + I2C_SCAN_CODE = """\ import board @@ -17,18 +19,20 @@ """ -def test_i2c_scan(run_circuitpython): +@pytest.mark.circuitpy_drive({"code.py": I2C_SCAN_CODE}) +def test_i2c_scan(circuitpython): """Test I2C bus scanning finds emulated devices. The AT24 EEPROM emulator responds to zero-length probe writes, so it should appear in scan results at address 0x50. """ - result = run_circuitpython(I2C_SCAN_CODE, timeout=5.0) + circuitpython.wait_until_done() - assert "I2C devices:" in result.output + output = circuitpython.serial.all_output + assert "I2C devices:" in output # AT24 EEPROM should be at address 0x50 - assert "0x50" in result.output - assert "done" in result.output + assert "0x50" in output + assert "done" in output AT24_READ_CODE = """\ @@ -61,38 +65,38 @@ def test_i2c_scan(run_circuitpython): """ -def test_i2c_at24_read(run_circuitpython): +@pytest.mark.circuitpy_drive({"code.py": AT24_READ_CODE}) +def test_i2c_at24_read(circuitpython): """Test reading from AT24 EEPROM emulator.""" - result = run_circuitpython(AT24_READ_CODE, timeout=5.0) + circuitpython.wait_until_done() - assert "AT24 byte 0: 0xFF" in result.output - assert "eeprom_valid" in result.output - assert "done" in result.output + output = circuitpython.serial.all_output + assert "AT24 byte 0: 0xFF" in output + assert "eeprom_valid" in output + assert "done" in output -def test_i2c_device_disabled(run_circuitpython): +@pytest.mark.circuitpy_drive({"code.py": I2C_SCAN_CODE}) +@pytest.mark.disable_i2c_devices("eeprom@50") +def test_i2c_device_disabled(circuitpython): """Test that disabled I2C device doesn't appear in scan.""" - result = run_circuitpython( - I2C_SCAN_CODE, - timeout=5.0, - disabled_i2c_devices=["eeprom@50"], - ) + circuitpython.wait_until_done() - assert "I2C devices:" in result.output + output = circuitpython.serial.all_output + assert "I2C devices:" in output # AT24 at 0x50 should NOT appear when disabled - assert "0x50" not in result.output - assert "done" in result.output + assert "0x50" not in output + assert "done" in output -def test_i2c_device_disabled_communication_fails(run_circuitpython): +@pytest.mark.circuitpy_drive({"code.py": AT24_READ_CODE}) +@pytest.mark.disable_i2c_devices("eeprom@50") +def test_i2c_device_disabled_communication_fails(circuitpython): """Test that communication with disabled I2C device fails.""" - result = run_circuitpython( - AT24_READ_CODE, - timeout=5.0, - disabled_i2c_devices=["eeprom@50"], - ) + circuitpython.wait_until_done() + output = circuitpython.serial.all_output # Should get an I2C error when trying to communicate - assert "I2C error" in result.output - assert "eeprom_valid" not in result.output - assert "done" in result.output + assert "I2C error" in output + assert "eeprom_valid" not in output + assert "done" in output diff --git a/shared-bindings/_bleio/PacketBuffer.h b/shared-bindings/_bleio/PacketBuffer.h index dd0c1ae9e25..24fb24bce78 100644 --- a/shared-bindings/_bleio/PacketBuffer.h +++ b/shared-bindings/_bleio/PacketBuffer.h @@ -6,6 +6,7 @@ #pragma once +#include "shared-bindings/_bleio/Characteristic.h" #include "common-hal/_bleio/PacketBuffer.h" extern const mp_obj_type_t bleio_packet_buffer_type; From aff436cee40790ca6e532af9dfbc3ea48a83a5f6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 18 Feb 2026 11:05:19 -0800 Subject: [PATCH 217/876] Exclude AGENTS.md from docs build --- conf.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/conf.py b/conf.py index 34436c09020..e2a8cbbd82f 100644 --- a/conf.py +++ b/conf.py @@ -192,7 +192,12 @@ def autoapi_prepare_jinja_env(jinja_env): # Port READMEs in various formats "ports/*/README*", ] -exclude_patterns = ["docs/autoapi/templates/**", "docs/README.md"] +exclude_patterns = [ + "docs/autoapi/templates/**", + "docs/README.md", + "AGENTS.md", + "**/AGENTS.md", +] # The reST default role (used for this markup: `text`) to use for all # documents. From 84e8f359cf78e0dca8a01bbb3d3731cf5054a675 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 18 Feb 2026 12:19:24 -0800 Subject: [PATCH 218/876] Install babblesim --- ports/zephyr-cp/zephyr-config/west.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 3eb38f7bea6..98caa4a0b2b 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -1,4 +1,6 @@ manifest: + group-filter: + - +babblesim projects: - name: zephyr url: https://github.com/adafruit/zephyr From 0a244eeb2ffc4cd957c3a535b9eb3baa9bd3d762 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 18 Feb 2026 15:58:34 -0800 Subject: [PATCH 219/876] Remove extra yields for Zephyr Instead, delay in a couple spots within Zephyr. --- ports/zephyr-cp/background.c | 9 ++++----- ports/zephyr-cp/mphalport.h | 7 ++++++- ports/zephyr-cp/supervisor/port.c | 8 ++++---- supervisor/shared/background_callback.c | 8 -------- supervisor/shared/safe_mode.c | 4 ---- 5 files changed, 14 insertions(+), 22 deletions(-) diff --git a/ports/zephyr-cp/background.c b/ports/zephyr-cp/background.c index 9afade89136..1abc034e878 100644 --- a/ports/zephyr-cp/background.c +++ b/ports/zephyr-cp/background.c @@ -36,10 +36,9 @@ void port_background_tick(void) { #endif } -// Allow boards to override this. -MP_WEAK void board_background_task(void) { -} - void port_background_task(void) { - board_background_task(); + // Make sure time advances in the simulator. + #if defined(CONFIG_ARCH_POSIX) + k_busy_wait(100); + #endif } diff --git a/ports/zephyr-cp/mphalport.h b/ports/zephyr-cp/mphalport.h index b3adf5830d0..ee696a4f043 100644 --- a/ports/zephyr-cp/mphalport.h +++ b/ports/zephyr-cp/mphalport.h @@ -13,7 +13,12 @@ #include "py/mpconfig.h" #include "supervisor/shared/tick.h" +#include + #define mp_hal_ticks_ms() ((mp_uint_t)supervisor_ticks_ms32()) -#define mp_hal_delay_us(us) NRFX_DELAY_US((uint32_t)(us)) + +static inline void mp_hal_delay_us(mp_uint_t us) { + k_busy_wait((uint32_t)us); +} bool mp_hal_stdin_any(void); diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 7be2beb1d20..786e6c2f2f5 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -67,10 +67,6 @@ void port_wake_main_task_from_isr(void) { void port_yield(void) { k_yield(); - // Make sure time advances in the simulator. - #if defined(CONFIG_ARCH_POSIX) - k_busy_wait(100); - #endif } void port_boot_info(void) { @@ -97,6 +93,10 @@ uint32_t port_get_saved_word(void) { } uint64_t port_get_raw_ticks(uint8_t *subticks) { + // Make sure time advances in the simulator. + #if defined(CONFIG_ARCH_POSIX) + k_busy_wait(100); + #endif int64_t uptime = k_uptime_ticks() * 32768 / CONFIG_SYS_CLOCK_TICKS_PER_SEC; if (subticks != NULL) { *subticks = uptime % 32; diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c index 79b18f7a137..ffeb78bbb83 100644 --- a/supervisor/shared/background_callback.c +++ b/supervisor/shared/background_callback.c @@ -61,10 +61,6 @@ static int background_prevention_count; void PLACE_IN_ITCM(background_callback_run_all)(void) { port_background_task(); if (!background_callback_pending()) { - // TEMPORARY to fix #10822 - #ifdef __ZEPHYR__ - port_yield(); - #endif return; } CALLBACK_CRITICAL_BEGIN; @@ -91,10 +87,6 @@ void PLACE_IN_ITCM(background_callback_run_all)(void) { } --background_prevention_count; CALLBACK_CRITICAL_END; - // TEMPORARY to fix #10822 - #ifdef __ZEPHYR__ - port_yield(); - #endif } void background_callback_prevent(void) { diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index bfe27ac7c65..3860de6621f 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -82,10 +82,6 @@ safe_mode_t wait_for_safe_mode_reset(void) { boot_in_safe_mode = true; break; } - // TEMPORARY to fix #10822 - #ifdef __ZEPHYR__ - port_yield(); - #endif diff = supervisor_ticks_ms64() - start_ticks; } #if CIRCUITPY_STATUS_LED From e6d863a60a17729c2c5002f27f1425848d0320ba Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 18 Feb 2026 16:07:27 -0800 Subject: [PATCH 220/876] Handle bsim and blobs --- .../boards/renesas/da14695_dk_usb/circuitpython.toml | 1 + ports/zephyr-cp/cptools/pre_zephyr_build_prep.py | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml index 3272dd4c5f3..f7fad6bc444 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/circuitpython.toml @@ -1 +1,2 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +BLOBS=["hal_renesas"] diff --git a/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py b/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py index 0ed280cbc67..acc3ae78619 100644 --- a/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py +++ b/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py @@ -19,5 +19,14 @@ mpconfigboard = tomllib.load(f) blobs = mpconfigboard.get("BLOBS", []) +blob_fetch_args = mpconfigboard.get("blob_fetch_args", {}) for blob in blobs: - subprocess.run(["west", "blobs", "fetch", blob], check=True) + args = blob_fetch_args.get(blob, []) + subprocess.run(["west", "blobs", "fetch", blob, *args], check=True) + +if board.endswith("bsim"): + subprocess.run( + ["make", "everything", "-j", "8"], + cwd=portdir / "tools" / "bsim", + check=True, + ) From 35a7e433ac5a2e01bc15ddebfc2bcf05f2ed3ba0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 18 Feb 2026 19:34:10 -0500 Subject: [PATCH 221/876] MagTag: autodetect display type --- .../adafruit_magtag_2.9_grayscale/board.c | 84 ++++++++++++------- 1 file changed, 55 insertions(+), 29 deletions(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index dc117deee63..1437f75165d 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -135,10 +135,23 @@ const uint8_t ssd1680_display_refresh_sequence[] = { 0x20, 0x00, 0x00 }; -static bool detect_ssd1680(void) { - // Bitbang 4-wire SPI with a bidirectional data line to read register 0x71. - // On the IL0373 it will return 0x13 or similar. On the SSD1680 it is - // unsupported and will be 0xff. + +typedef enum { + DISPLAY_IL0373, + DISPLAY_SSD1680_COLSTART_0, + DISPLAY_SSD1680_COLSTART_8, +} display_type_t; + +static display_type_t detect_display_type(void) { + // Bitbang 4-wire SPI with a bidirectional data line to read the first word of register 0x2e, + // which is the 10-byte USER ID. + // On the IL0373 it will return 0xff because it's not a valid register. + // With SSD1680, we have seen two types: + // 1. The first batch of displays, labeled "FPC-A005 20.06.15 TRX", which needs colstart=0. + // These have 10 byes of zeros in the User ID + // 2. Second batch, labeled "FPC-7619rev.b", which needs colstart=8. + // The USER ID for these boards is [0x44, 0x0, 0x4, 0x0, 0x25, 0x0, 0x1, 0x78, 0x2b, 0xe] + // So let's distinguish just by the first byte. digitalio_digitalinout_obj_t data; digitalio_digitalinout_obj_t clock; digitalio_digitalinout_obj_t chip_select; @@ -163,7 +176,7 @@ static bool detect_ssd1680(void) { common_hal_digitalio_digitalinout_switch_to_output(&reset, true, DRIVE_MODE_PUSH_PULL); common_hal_digitalio_digitalinout_switch_to_output(&clock, false, DRIVE_MODE_PUSH_PULL); - uint8_t status_read = 0x71; + uint8_t status_read = 0x2e; // SSD1680 User ID register. Not a valid register on IL0373. for (int i = 0; i < 8; i++) { common_hal_digitalio_digitalinout_set_value(&data, (status_read & (1 << (7 - i))) != 0); common_hal_digitalio_digitalinout_set_value(&clock, true); @@ -192,11 +205,20 @@ static bool detect_ssd1680(void) { common_hal_digitalio_digitalinout_deinit(&chip_select); common_hal_digitalio_digitalinout_deinit(&data_command); common_hal_digitalio_digitalinout_deinit(&reset); - return status == 0xff; + + switch (status) { + case 0xff: + return DISPLAY_IL0373; + default: // who knows? Just guess. + case 0x00: + return DISPLAY_SSD1680_COLSTART_0; + case 0x44: + return DISPLAY_SSD1680_COLSTART_8; + } } void board_init(void) { - bool is_ssd1680 = detect_ssd1680(); + display_type_t display_type = detect_display_type(); fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; busio_spi_obj_t *spi = &bus->inline_bus; @@ -216,8 +238,33 @@ void board_init(void) { epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; display->base.type = &epaperdisplay_epaperdisplay_type; - if (is_ssd1680) { + if (display_type == DISPLAY_IL0373) { + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = il0373_display_start_sequence; + args.start_sequence_len = sizeof(il0373_display_start_sequence); + args.stop_sequence = il0373_display_stop_sequence; + args.stop_sequence_len = sizeof(il0373_display_stop_sequence); + args.width = 296; + args.height = 128; + args.ram_width = 160; + args.ram_height = 296; + args.rotation = 270; + args.write_black_ram_command = 0x10; + args.write_color_ram_command = 0x13; + args.refresh_sequence = il0373_display_refresh_sequence; + args.refresh_sequence_len = sizeof(il0373_display_refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO5; + args.seconds_per_frame = 5.0; + args.grayscale = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); + } else { epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + // Default colstart is 0. + if (display_type == DISPLAY_SSD1680_COLSTART_8) { + args.colstart = 8; + } args.bus = bus; args.start_sequence = ssd1680_display_start_sequence; args.start_sequence_len = sizeof(ssd1680_display_start_sequence); @@ -244,27 +291,6 @@ void board_init(void) { args.two_byte_sequence_length = true; args.address_little_endian = true; common_hal_epaperdisplay_epaperdisplay_construct(display, &args); - } else { - epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; - args.bus = bus; - args.start_sequence = il0373_display_start_sequence; - args.start_sequence_len = sizeof(il0373_display_start_sequence); - args.stop_sequence = il0373_display_stop_sequence; - args.stop_sequence_len = sizeof(il0373_display_stop_sequence); - args.width = 296; - args.height = 128; - args.ram_width = 160; - args.ram_height = 296; - args.rotation = 270; - args.write_black_ram_command = 0x10; - args.write_color_ram_command = 0x13; - args.refresh_sequence = il0373_display_refresh_sequence; - args.refresh_sequence_len = sizeof(il0373_display_refresh_sequence); - args.refresh_time = 1.0; - args.busy_pin = &pin_GPIO5; - args.seconds_per_frame = 5.0; - args.grayscale = true; - common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } } From b59a3e59706abd0f4a6247381d1bcf7389b665cc Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Sat, 14 Feb 2026 09:54:54 +0100 Subject: [PATCH 222/876] support user-configuration files --- .gitignore | 3 +++ py/circuitpy_mkenv.mk | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/.gitignore b/.gitignore index f996911d8d7..80b045f5ec5 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,9 @@ __pycache__/ ###################### GNUmakefile user.props +mpconfiguser1.mk +mpconfiguser2.mk +user_defns.mk # Sphinx output ############### diff --git a/py/circuitpy_mkenv.mk b/py/circuitpy_mkenv.mk index 7bdf943a14d..49ce0978b20 100644 --- a/py/circuitpy_mkenv.mk +++ b/py/circuitpy_mkenv.mk @@ -43,6 +43,10 @@ ifneq ($(VALID_BOARD),) include boards/$(BOARD)/mpconfigboard.mk endif +# user-specific settings that mpconfigport does not override +# (i.e. mpconfigport.mk uses "foo ?= bar") +-include mpconfiguser1.mk + # Port-specific include mpconfigport.mk @@ -52,6 +56,10 @@ ifneq ($(VALID_BOARD),) include $(TOP)/py/circuitpy_mpconfig.mk endif +# user-specific overrides of hard-coded settings +# (i.e. xxx.mk uses "foo = bar") +-include mpconfiguser2.mk + # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h @@ -62,3 +70,6 @@ include $(TOP)/supervisor/supervisor.mk # Include make rules and variables common across CircuitPython builds. include $(TOP)/py/circuitpy_defns.mk + +# user specific +-include user_defns.mk From 387a45c99aa2b9a786e04a6a6fe1aa1729b0c961 Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Mon, 16 Feb 2026 08:12:02 +0100 Subject: [PATCH 223/876] changed filenames as requested --- .gitignore | 6 +++--- py/circuitpy_mkenv.mk | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 80b045f5ec5..3e9ee009cb3 100644 --- a/.gitignore +++ b/.gitignore @@ -55,9 +55,9 @@ __pycache__/ ###################### GNUmakefile user.props -mpconfiguser1.mk -mpconfiguser2.mk -user_defns.mk +user_pre_mpconfigport.mk +user_post_mpconfigport.mk +user_post_circuitpy_defns.mk # Sphinx output ############### diff --git a/py/circuitpy_mkenv.mk b/py/circuitpy_mkenv.mk index 49ce0978b20..6416d6bd19c 100644 --- a/py/circuitpy_mkenv.mk +++ b/py/circuitpy_mkenv.mk @@ -45,7 +45,7 @@ endif # user-specific settings that mpconfigport does not override # (i.e. mpconfigport.mk uses "foo ?= bar") --include mpconfiguser1.mk +-include user_pre_mpconfigport.mk # Port-specific include mpconfigport.mk @@ -58,7 +58,7 @@ endif # user-specific overrides of hard-coded settings # (i.e. xxx.mk uses "foo = bar") --include mpconfiguser2.mk +-include user_post_mpconfigport.mk # qstr definitions (must come before including py.mk) QSTR_DEFS = qstrdefsport.h @@ -72,4 +72,4 @@ include $(TOP)/supervisor/supervisor.mk include $(TOP)/py/circuitpy_defns.mk # user specific --include user_defns.mk +-include user_post_circuitpy_defns.mk From e46458705e1c1cf4e8a054aa9f5e3c7c35b618a3 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Thu, 19 Feb 2026 10:43:37 +0100 Subject: [PATCH 224/876] Lower SPI speed on uGame S3 to avoid display glitches --- ports/espressif/boards/deshipu_ugame_s3/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/deshipu_ugame_s3/board.c b/ports/espressif/boards/deshipu_ugame_s3/board.c index 677cab7f076..dc09786e74c 100644 --- a/ports/espressif/boards/deshipu_ugame_s3/board.c +++ b/ports/espressif/boards/deshipu_ugame_s3/board.c @@ -80,7 +80,7 @@ void board_init(void) { MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_GPIO10), // TFT_CS Chip select MP_OBJ_FROM_PTR(&pin_GPIO13), // TFT_RESET Reset - 80000000L, // Baudrate + 48000000L, // Baudrate 0, // Polarity 0); // Phase From 3dfba6b8b7d4d7e21165dd77bb8285a7bc6894e0 Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Thu, 19 Feb 2026 15:21:48 +0100 Subject: [PATCH 225/876] added documentation for user config files --- BUILDING.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/BUILDING.md b/BUILDING.md index 34cd544d736..6778965bed0 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -64,6 +64,52 @@ If you aren't sure what boards exist, have a peek in the boards subdirectory of If you have a fast computer with many cores, consider adding `-j` to your build flags, such as `-j17` on a 6-core 12-thread machine. +## Configuration + +Ports and boards are preconfigured, thus make knows how to build a specific +board. Power users can change the configuration of a specific board or port, +either by passing compile-time options to make, or by creating appropriate +make include files. + +The configuration system is hierarchical. A higher level will typically only +set an option that a lower level hasn't configured: + +* board configuration: `mpconfigport.mk` +* pre-port user configuration: `user_pre_mpconfigport.mk` +* port configuration: `mpconfigport.mk` +* post-port user configuration: `user_post_mpconfigport.mk` +* global configuration: `py/circuitpython_mpconfig.mk` + +The board configuration is within the board-directory, e.g. +`ports/raspberrypi/boards/raspberry_pi_pico/`, the port configuration is +in the port-directory, e.g. `ports/raspberrypi/`. + +Editing these configuration files is the way to go if you want to change +the default behavior and ultimately create a pull-request. Otherwise, +changes should go into one of the user configuration files. + +User specific configurations are optional and should be maintained out of +tree. Passing `-I directory` tells make where to search for the additional +configuration files. E.g. to speed up boots by removing the wait-time for +the save-mode button press, you would: + +* create a directory: `mkdir -p ~/my_cp_config` +* create the config file: `echo 'CIRCUITPY_SKIP_SAFE_MODE_WAIT=0' > ~/my_cp_config/user_pre_mpconfigport.mk` +* run make with: `make -I ~/my_cp_config BOARD=raspberry_pi_pico` + +Besides the `user*mpconfigport.mk` files, there is another optional file +named `user_post_circuitpy_defns.mk`. This file is included at the end +and can be used to tweak compiler-definitions that are not covered by +one of the compile time options `CIRCUITPY_*`. + +Example: to create a build for the Pico2-W with an integrated saves-partition, +you would create a `user_post_circuitpy_defns.mk` with the following content: + + $(info ===> processing user_post_circuitpy_defns.mk) + ifeq (${BOARD},raspberry_pi_pico2_w) + CFLAGS += -DCIRCUITPY_SAVES_PARTITION_SIZE=1048576 + endif + ## Testing If you are working on changes to the core language, you might find it useful to run the test suite. From 3abe916d5fa93a092864a86837170b406517d58b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 19 Feb 2026 09:24:58 -0800 Subject: [PATCH 226/876] Fix the builds --- ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf | 4 ++++ .../boards/nxp/frdm_rw612/autogen_board_info.toml | 1 + .../boards/renesas/da14695_dk_usb/autogen_board_info.toml | 1 + ports/zephyr-cp/cptools/zephyr2cp.py | 7 +++++-- 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index 9829d4a1581..afb546a980d 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -14,3 +14,7 @@ CONFIG_BT_CENTRAL=y CONFIG_BT_BROADCASTER=y CONFIG_BT_OBSERVER=y CONFIG_BT_EXT_ADV=y + +CONFIG_LOG=n +CONFIG_ASSERT=n +CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index c9bd2729b9e..f7ad0289cc7 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index e5adbfd582d..77d93aa10f0 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -51,6 +51,7 @@ gifio = false gnss = false hashlib = false i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false i2ctarget = false imagecapture = false ipaddress = false diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index d275a7ce960..86b0b0fe403 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -588,15 +588,18 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa if len(all_ioports) > 1: a, b = all_ioports[:2] i = 0 - while a[i] == b[i]: + max_i = min(len(a), len(b)) + while i < max_i and a[i] == b[i]: i += 1 shared_prefix = a[:i] for ioport in ioports: if not ioport.startswith(shared_prefix): shared_prefix = "" break - else: + elif all_ioports: shared_prefix = all_ioports[0] + else: + shared_prefix = "" pin_defs = [] pin_declarations = ["#pragma once"] From 839236ea263fb49b0fab2bbdd4c71d68743662f6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 19 Feb 2026 13:36:58 -0800 Subject: [PATCH 227/876] Address PR review feedback from dhalbert Done mostly automatically: https://pi.dev/session/#f06760de11a3f7b5f80620088e37bd6b --- ports/zephyr-cp/common-hal/_bleio/Adapter.c | 4 ++-- ports/zephyr-cp/common-hal/_bleio/Adapter.h | 1 + ports/zephyr-cp/common-hal/_bleio/Attribute.c | 1 + ports/zephyr-cp/common-hal/_bleio/Attribute.h | 1 + ports/zephyr-cp/common-hal/_bleio/Characteristic.c | 1 + ports/zephyr-cp/common-hal/_bleio/Characteristic.h | 1 + .../zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c | 1 + .../zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h | 1 + ports/zephyr-cp/common-hal/_bleio/Connection.c | 1 + ports/zephyr-cp/common-hal/_bleio/Connection.h | 1 + ports/zephyr-cp/common-hal/_bleio/Descriptor.c | 1 + ports/zephyr-cp/common-hal/_bleio/Descriptor.h | 1 + ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c | 1 + ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h | 1 + ports/zephyr-cp/common-hal/_bleio/Service.c | 1 + ports/zephyr-cp/common-hal/_bleio/Service.h | 1 + ports/zephyr-cp/common-hal/_bleio/UUID.c | 1 + ports/zephyr-cp/common-hal/_bleio/UUID.h | 1 + ports/zephyr-cp/common-hal/_bleio/__init__.c | 1 + ports/zephyr-cp/common-hal/_bleio/__init__.h | 1 + ports/zephyr-cp/common-hal/wifi/__init__.c | 9 ++------- ports/zephyr-cp/supervisor/port.c | 10 +++++++++- ports/zephyr-cp/tests/docs/babblesim.md | 2 +- 23 files changed, 33 insertions(+), 11 deletions(-) diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index 7257f54c35f..d72a7bed865 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -132,9 +133,8 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable if (enabled) { if (!bt_is_ready()) { int err = bt_enable(NULL); - raise_zephyr_error(err); if (err != 0) { - return; + raise_zephyr_error(err); } } ble_adapter_enabled = true; diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.h b/ports/zephyr-cp/common-hal/_bleio/Adapter.h index 7cb3dc402c6..dda9075776e 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.h +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Attribute.c b/ports/zephyr-cp/common-hal/_bleio/Attribute.c index cf8a818e6a7..6312f3d46b8 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Attribute.c +++ b/ports/zephyr-cp/common-hal/_bleio/Attribute.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Attribute.h b/ports/zephyr-cp/common-hal/_bleio/Attribute.h index 417ac3c4549..24b0f78a106 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Attribute.h +++ b/ports/zephyr-cp/common-hal/_bleio/Attribute.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.c b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c index 6e71f848627..386be6004d2 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Characteristic.c +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.h b/ports/zephyr-cp/common-hal/_bleio/Characteristic.h index b9021c13295..b710a9f2662 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Characteristic.h +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c index e6ae3bf9b72..17e000e905e 100644 --- a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h index 53b10413775..91ea262945a 100644 --- a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.c b/ports/zephyr-cp/common-hal/_bleio/Connection.c index b0cac644367..2e93b6ab127 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.c +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.h b/ports/zephyr-cp/common-hal/_bleio/Connection.h index b3faef63f8c..f8f9581ad00 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.h +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Descriptor.c b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c index 847546b1ced..a3e65a5e006 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Descriptor.c +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Descriptor.h b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h index 8abf1dcfaad..1d29cb27a50 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Descriptor.h +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c index 6cba2135156..82fe8a3d176 100644 --- a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h index c96dd9f2eb6..c8cd763fd61 100644 --- a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.c b/ports/zephyr-cp/common-hal/_bleio/Service.c index da2bf48e16f..cefc85b6df6 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Service.c +++ b/ports/zephyr-cp/common-hal/_bleio/Service.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.h b/ports/zephyr-cp/common-hal/_bleio/Service.h index 03ab8b5d7fd..86727d3b0f7 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Service.h +++ b/ports/zephyr-cp/common-hal/_bleio/Service.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/UUID.c b/ports/zephyr-cp/common-hal/_bleio/UUID.c index 3bfbffb5a2b..916eedb2c47 100644 --- a/ports/zephyr-cp/common-hal/_bleio/UUID.c +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/UUID.h b/ports/zephyr-cp/common-hal/_bleio/UUID.h index d58016cffef..386f5a7b8b9 100644 --- a/ports/zephyr-cp/common-hal/_bleio/UUID.h +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2019 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.c b/ports/zephyr-cp/common-hal/_bleio/__init__.c index 5b8f8ece898..fca1eae9827 100644 --- a/ports/zephyr-cp/common-hal/_bleio/__init__.c +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.c @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.h b/ports/zephyr-cp/common-hal/_bleio/__init__.h index 9c30c7c8063..1502767c615 100644 --- a/ports/zephyr-cp/common-hal/_bleio/__init__.h +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.h @@ -1,6 +1,7 @@ // This file is part of the CircuitPython project: https://circuitpython.org // // SPDX-FileCopyrightText: Copyright (c) 2018 Dan Halbert for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index f043734ebfb..da26d560724 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -48,18 +48,15 @@ static struct net_mgmt_event_callback ipv4_cb; static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; - printk("_event_handler cb %p event 0x%" PRIx64 " if %p\n", cb, mgmt_event, iface); + (void)iface; switch (mgmt_event) { case NET_EVENT_WIFI_SCAN_RESULT: { - printk("NET_EVENT_WIFI_SCAN_RESULT\n"); #if defined(CONFIG_NET_MGMT_EVENT_INFO) const struct wifi_scan_result *result = cb->info; if (result != NULL && self->current_scan != NULL) { wifi_scannednetworks_scan_result(self->current_scan, result); } - #else - printk("Scan result info unavailable (CONFIG_NET_MGMT_EVENT_INFO disabled)\n"); #endif break; } @@ -306,9 +303,7 @@ void common_hal_wifi_init(bool user_initiated) { } snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac->addr[0], mac->addr[1], mac->addr[2], mac->addr[3], mac->addr[4], mac->addr[5]); - if (net_hostname_set(cpy_default_hostname, strlen(cpy_default_hostname)) != 0) { - printk("setting hostname failed\n"); - } + CHECK_ZEPHYR_RESULT(net_hostname_set(cpy_default_hostname, strlen(cpy_default_hostname))); #else printk("Hostname support disabled in Zephyr config\n"); #endif diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 595bc6a3491..5a7a982392a 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -145,8 +145,10 @@ void port_idle_until_interrupt(void) { // Zephyr doesn't maintain one multi-heap. So, make our own using TLSF. void port_heap_init(void) { + // Do a test malloc to determine if Zephyr has an outer heap that may + // overlap with a memory region we've identified in ram_bounds. We'll + // corrupt each other if we both use it. #ifdef CONFIG_COMMON_LIBC_MALLOC - // Do a test malloc to determine if Zephyr has an outer heap. uint32_t *test_malloc = malloc(32); free(test_malloc); // Free right away so we don't forget. We don't actually write it anyway. zephyr_malloc_active = test_malloc != NULL; @@ -156,11 +158,17 @@ void port_heap_init(void) { uint32_t *heap_bottom = ram_bounds[2 * i]; uint32_t *heap_top = ram_bounds[2 * i + 1]; size_t size = (heap_top - heap_bottom) * sizeof(uint32_t); + // The linker script may fill up a region we thought we could use at + // build time. (The ram_bounds values are sometimes determined by the + // linker.) So, we need to guard against regions that aren't actually + // free. if (size < 1024) { printk("Skipping region because the linker filled it up.\n"); continue; } #ifdef CONFIG_COMMON_LIBC_MALLOC + // Skip a ram region if our test malloc is within it. We'll use Zephyr's + // malloc to share that space with Zephyr. if (heap_bottom <= test_malloc && test_malloc < heap_top) { zephyr_malloc_top = heap_top; zephyr_malloc_bottom = heap_bottom; diff --git a/ports/zephyr-cp/tests/docs/babblesim.md b/ports/zephyr-cp/tests/docs/babblesim.md index 39d60fa306c..abf68b2b1de 100644 --- a/ports/zephyr-cp/tests/docs/babblesim.md +++ b/ports/zephyr-cp/tests/docs/babblesim.md @@ -28,7 +28,7 @@ export BSIM_OUT_PATH=/path/to/bsim ## Build ``` -CCACHE_TEMPDIR=/tmp/ccache-tmp make -j32 BOARD=native_nrf5340bsim +CCACHE_TEMPDIR=/tmp/ccache-tmp make -j BOARD=native_nrf5340bsim ``` If you do not use ccache, you can omit `CCACHE_TEMPDIR`. From f7ee5cf90a1f8fb9398a9f4e847cdedd63bea5c2 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 19 Feb 2026 14:30:21 -0800 Subject: [PATCH 228/876] Use a git sha for revision --- ports/zephyr-cp/zephyr-config/west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 98caa4a0b2b..159467ae7e6 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -4,6 +4,6 @@ manifest: projects: - name: zephyr url: https://github.com/adafruit/zephyr - revision: circuitpython-v4.3.0 + revision: 3c5a3a72daa3ca6462cd8bc9c8c7c6a41fbf3b2e clone-depth: 100 import: true From 2b0e36802752f4ba3b53d563feae8ef2ee0581e1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 20 Feb 2026 09:54:15 -0500 Subject: [PATCH 229/876] espressif: check for deinit in common_hal_busio_i2c_unlock() I2C bus is unlocked in reset_board_buses(), but it might have been deinited already. --- ports/espressif/common-hal/busio/I2C.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 8ff608717c7..890f9339c22 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -132,6 +132,7 @@ void common_hal_busio_i2c_deinit(busio_i2c_obj_t *self) { xSemaphoreGive(self->xSemaphore); vSemaphoreDelete(self->xSemaphore); self->xSemaphore = NULL; + self->has_lock = false; common_hal_reset_pin(self->sda_pin); common_hal_reset_pin(self->scl_pin); @@ -165,6 +166,9 @@ bool common_hal_busio_i2c_has_lock(busio_i2c_obj_t *self) { } void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) { + if (common_hal_busio_i2c_deinited(self)) { + return; + } xSemaphoreGive(self->xSemaphore); self->has_lock = false; } From 473ec3862b3db8dc4ef4b1c4370306259a956377 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 20 Feb 2026 10:23:13 -0800 Subject: [PATCH 230/876] ports/espressif: update esp-idf to 5.5.3 Signed-off-by: Scott Shawcroft --- ports/espressif/esp-idf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index f4fddd2d05b..1d2c73f641a 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit f4fddd2d05b44d1d606b546b596d17de0a73e9eb +Subproject commit 1d2c73f641af70c24274e2d3e74641592bee97e5 From 0a18d1d364ebe7f2904b51fcc0401367ff96efd9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 20 Feb 2026 13:44:06 -0500 Subject: [PATCH 231/876] pin click<8.2.0 to avoid esp-idf build problem --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 566618d2c47..6505a982906 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ jinja2 typer sh -click +click<8.2.0 cpp-coveralls requests From 8147243cc748330b5c158a3301011ba94672ce2b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 20 Feb 2026 11:49:23 -0800 Subject: [PATCH 232/876] ci: apply ESP-IDF constraints to requirements-dev install Signed-off-by: Scott Shawcroft --- .github/actions/deps/external/action.yml | 12 +++++- requirements-dev.txt | 3 +- tools/ci_set_idf_constraint.py | 47 ++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 tools/ci_set_idf_constraint.py diff --git a/.github/actions/deps/external/action.yml b/.github/actions/deps/external/action.yml index 564c851cfc9..81e73f871ef 100644 --- a/.github/actions/deps/external/action.yml +++ b/.github/actions/deps/external/action.yml @@ -56,6 +56,16 @@ runs: uses: ./.github/actions/deps/python with: action: ${{ inputs.action }} + - name: Set ESP-IDF constraints path + if: inputs.port == 'espressif' + run: python3 -u tools/ci_set_idf_constraint.py + shell: bash + - name: Install python dependencies - run: pip install -r requirements-dev.txt + run: | + if [ -n "${IDF_CONSTRAINT_FILE:-}" ] && [ -f "$IDF_CONSTRAINT_FILE" ]; then + pip install -c "$IDF_CONSTRAINT_FILE" -r requirements-dev.txt + else + pip install -r requirements-dev.txt + fi shell: bash diff --git a/requirements-dev.txt b/requirements-dev.txt index 566618d2c47..3c7e18b7bf0 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -25,8 +25,7 @@ intelhex # for building & testing natmods pyelftools -# newer versions break ESP-IDF now -cryptography<45 +cryptography # for web workflow minify minify_html diff --git a/tools/ci_set_idf_constraint.py b/tools/ci_set_idf_constraint.py new file mode 100644 index 00000000000..49c187f4587 --- /dev/null +++ b/tools/ci_set_idf_constraint.py @@ -0,0 +1,47 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries LLC +# +# SPDX-License-Identifier: MIT + +"""Set IDF_CONSTRAINT_FILE for CI. + +CI installs requirements-dev.txt for all ports, but on Espressif builds we must +also apply the matching ESP-IDF constraints file so pip does not upgrade shared +packages (for example click) beyond what ESP-IDF allows. This script derives the +active ESP-IDF major.minor version from version.cmake and exports the exact +constraints file path into GITHUB_ENV for later install steps. +""" + +import os +import pathlib +import re + +TOP = pathlib.Path(__file__).resolve().parent.parent + + +def main() -> None: + version_cmake = TOP / "ports" / "espressif" / "esp-idf" / "tools" / "cmake" / "version.cmake" + data = version_cmake.read_text(encoding="utf-8") + + major = re.search(r"IDF_VERSION_MAJOR\s+(\d+)", data) + minor = re.search(r"IDF_VERSION_MINOR\s+(\d+)", data) + if major is None or minor is None: + raise RuntimeError(f"Unable to parse IDF version from {version_cmake}") + + idf_tools_path = os.environ.get("IDF_TOOLS_PATH") + if not idf_tools_path: + raise RuntimeError("IDF_TOOLS_PATH is not set") + + constraint = ( + pathlib.Path(idf_tools_path) / f"espidf.constraints.v{major.group(1)}.{minor.group(1)}.txt" + ) + + github_env = os.environ.get("GITHUB_ENV") + if github_env: + with open(github_env, "a", encoding="utf-8") as f: + f.write(f"IDF_CONSTRAINT_FILE={constraint}\n") + + print(f"Set IDF_CONSTRAINT_FILE={constraint}") + + +if __name__ == "__main__": + main() From d2d6094cd852ac28ee3e13654cc8bffdb1962b64 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 22 Feb 2026 14:23:32 -0500 Subject: [PATCH 233/876] call reset_all_pins() in main() after port_init() Before #10699, `reset_all_pins()` was called in `reset_port()`. That changed to reset all pins in main after the finalizers ran. However, this mean that pins were not all reset on power-up or hard reset. This caused #1841, because the power control pin for Feather S3 TFT was not powering the display as required before the display was reset. Add a call to `reset_all_pins()` early in `main()` to serve the same purpose. --- main.c | 4 ++++ ports/atmel-samd/supervisor/port.c | 4 +--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/main.c b/main.c index 7b936488fb7..846e5ece096 100644 --- a/main.c +++ b/main.c @@ -1020,8 +1020,12 @@ int __attribute__((used)) main(void) { // initialise the cpu and peripherals set_safe_mode(port_init()); + // All ports need pins reset, after never-reset pins are marked in port_init(); + reset_all_pins(); + port_heap_init(); + // Turn on RX and TX LEDs if we have them. init_rxtx_leds(); diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 31bc5faf827..fe7b4a3676c 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -339,11 +339,9 @@ safe_mode_t port_init(void) { init_shared_dma(); // Reset everything into a known state before board_init. + // Pins are reset in main() after this routine returns. reset_port(); - // Reset the pins too. - reset_all_pins(); - #ifdef SAMD21 if (PM->RCAUSE.bit.BOD33 == 1 || PM->RCAUSE.bit.BOD12 == 1) { return SAFE_MODE_BROWNOUT; From 1e707b78021367ef359c6845e5905c3c56990a16 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 23 Feb 2026 10:45:58 -0800 Subject: [PATCH 234/876] Fix P4 and remove canio from c3s-2m --- ports/espressif/Makefile | 3 +++ .../espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk | 1 + 2 files changed, 4 insertions(+) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index ebc4fa3a4e1..9e331740dd6 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -123,6 +123,9 @@ INC += \ -isystem esp-idf/components/soc/include \ -isystem esp-idf/components/soc/$(IDF_TARGET)/include \ -isystem esp-idf/components/soc/$(IDF_TARGET)/register \ + -isystem esp-idf/components/soc/$(IDF_TARGET)/register/hw_ver3 \ + -isystem esp-idf/components/soc/$(IDF_TARGET)/register/hw_ver2 \ + -isystem esp-idf/components/soc/$(IDF_TARGET)/register/hw_ver1 \ -isystem esp-idf/components/spi_flash/include \ -isystem esp-idf/components/usb/include \ -isystem esp-idf/components/ulp/ulp_fsm/include \ diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk index 9ca2eee1577..da3e6a14496 100644 --- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk +++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk @@ -10,5 +10,6 @@ CIRCUITPY_ESP_FLASH_SIZE = 2MB CIRCUITPY_DUALBANK = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_CANIO = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 From fde84b9449171404537ed240b95b75952abea52d Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 23 Feb 2026 17:10:18 -0600 Subject: [PATCH 235/876] Fix pin assignments on Thumby Color --- .../boards/tinycircuits_thumby_color/mpconfigboard.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h index ce5d015db58..fc76138bb8a 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.h @@ -20,8 +20,8 @@ #define CIRCUITPY_BOARD_LCD_DC (&pin_GPIO16) #define CIRCUITPY_BOARD_LCD_CS (&pin_GPIO17) -#define CIRCUITPY_BOARD_LCD_RESET (&pin_GPIO11) -#define CIRCUITPY_BOARD_LCD_BACKLIGHT (&pin_GPIO20) +#define CIRCUITPY_BOARD_LCD_RESET (&pin_GPIO4) +#define CIRCUITPY_BOARD_LCD_BACKLIGHT (&pin_GPIO7) #define CIRCUITPY_BOARD_SPI (1) #define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} From b705adedf1778a7d4ac3b9e306696104b4106350 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 23 Feb 2026 12:44:53 -0800 Subject: [PATCH 236/876] Exit the sim after the desired number of code.py runs Make UART PTY reliable by waiting for all bytes to be read from the subsidiary PTY. --- ports/zephyr-cp/supervisor/port.c | 45 ++++++++++ ports/zephyr-cp/tests/__init__.py | 23 ++++- ports/zephyr-cp/tests/bsim/conftest.py | 18 ++-- .../zephyr-cp/tests/bsim/test_bsim_basics.py | 11 +-- .../tests/bsim/test_bsim_ble_advertising.py | 59 +++++------- .../tests/bsim/test_bsim_ble_name.py | 8 +- .../tests/bsim/test_bsim_ble_scan.py | 90 ++++++------------- ports/zephyr-cp/tests/conftest.py | 29 +++++- ports/zephyr-cp/tests/test_basics.py | 1 + ports/zephyr-cp/zephyr-config/west.yml | 4 + 10 files changed, 154 insertions(+), 134 deletions(-) diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index a473e1664d8..08a84043e8e 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -17,6 +17,15 @@ #include #include +#if defined(CONFIG_ARCH_POSIX) +#include +#include + +#include "cmdline.h" +#include "posix_board_if.h" +#include "posix_native_task.h" +#endif + #include "lib/tlsf/tlsf.h" #include @@ -37,6 +46,32 @@ static K_EVENT_DEFINE(main_needed); static struct k_timer tick_timer; +#if defined(CONFIG_ARCH_POSIX) +// Number of VM runs before exiting. +// <= 0 means run forever. +// INT32_MAX means option was not provided. +static int32_t native_sim_vm_runs = INT32_MAX; +static uint32_t native_sim_reset_port_count = 0; + +static struct args_struct_t native_sim_reset_port_args[] = { + { + .option = "vm-runs", + .name = "count", + .type = 'i', + .dest = &native_sim_vm_runs, + .descript = "Exit native_sim after this many VM runs. " + "Example: --vm-runs=2" + }, + ARG_TABLE_ENDMARKER +}; + +static void native_sim_register_cmdline_opts(void) { + native_add_command_line_opts(native_sim_reset_port_args); +} + +NATIVE_TASK(native_sim_register_cmdline_opts, PRE_BOOT_1, 0); +#endif + static void _tick_function(struct k_timer *timer_id) { supervisor_tick(); } @@ -61,6 +96,16 @@ void reset_port(void) { #if CIRCUITPY_BLEIO bleio_reset(); #endif + + #if defined(CONFIG_ARCH_POSIX) + native_sim_reset_port_count++; + if (native_sim_vm_runs != INT32_MAX && + native_sim_vm_runs > 0 && + native_sim_reset_port_count >= (uint32_t)(native_sim_vm_runs + 1)) { + printk("posix: exiting after %d VM runs\n", native_sim_vm_runs); + posix_exit(0); + } + #endif } void reset_to_bootloader(void) { diff --git a/ports/zephyr-cp/tests/__init__.py b/ports/zephyr-cp/tests/__init__.py index a560b2c40c1..18e596e8e70 100644 --- a/ports/zephyr-cp/tests/__init__.py +++ b/ports/zephyr-cp/tests/__init__.py @@ -1,6 +1,7 @@ import serial import subprocess import threading +import time class StdSerial: @@ -25,6 +26,12 @@ def close(self): self.stdin.close() self.stdout.close() + @property + def in_waiting(self): + if self.stdout is None: + return 0 + return len(self.stdout.peek()) + class SerialSaver: """Capture serial output in a background thread so output isn't missed.""" @@ -58,6 +65,13 @@ def _reader_loop(self): with self._cv: self.all_output += text self._cv.notify_all() + in_waiting = 0 + try: + in_waiting = self.serial.in_waiting + except OSError: + pass + if in_waiting > 0: + self.all_output += self.serial.read().decode("utf-8", errors="replace") def wait_for(self, text, timeout=10): with self._cv: @@ -79,11 +93,11 @@ def close(self): return self._stop.set() + self._reader.join(timeout=1.0) try: self.serial.close() except Exception: pass - self._reader.join(timeout=1.0) self.serial = None def write(self, text): @@ -131,6 +145,7 @@ def shutdown(self): self.debug_serial.close() def wait_until_done(self): - self._proc.wait(timeout=self._timeout) - self.serial.close() - self.debug_serial.close() + start_time = time.monotonic() + while self._proc.poll() is None and time.monotonic() - start_time < self._timeout: + time.sleep(0.01) + self.shutdown() diff --git a/ports/zephyr-cp/tests/bsim/conftest.py b/ports/zephyr-cp/tests/bsim/conftest.py index 505ff77bf7e..b7a66346ce2 100644 --- a/ports/zephyr-cp/tests/bsim/conftest.py +++ b/ports/zephyr-cp/tests/bsim/conftest.py @@ -86,7 +86,7 @@ def shutdown(self) -> None: @pytest.fixture def bsim_phy(request, bsim_phy_binary, native_sim_env, sim_id): duration_marker = request.node.get_closest_marker("duration") - sim_length = float(duration_marker.args[0]) if duration_marker else 20.0 + duration = float(duration_marker.args[0]) if duration_marker else 20.0 devices = 1 if "circuitpython2" in request.fixturenames or "zephyr_sample" in request.fixturenames: @@ -97,12 +97,7 @@ def bsim_phy(request, bsim_phy_binary, native_sim_env, sim_id): sample_device_id = int(sample_marker.kwargs.get("device_id", 1)) devices = max(devices, sample_device_id + 1) - bsim_marker = request.node.get_closest_marker("bsim") - if bsim_marker is not None: - devices = int(bsim_marker.kwargs.get("devices", devices)) - sim_length = float(bsim_marker.kwargs.get("sim_length", sim_length)) - - sim_length_us = int(sim_length * 1e6) + sim_length_us = int(duration * 1e6) cmd = [ "stdbuf", "-oL", @@ -136,7 +131,7 @@ def bsim_phy(request, bsim_phy_binary, native_sim_env, sim_id): raise RuntimeError("bsim PHY exited immediately") # Assume bsim is running - phy = BsimPhyInstance(proc, phy_output, timeout=sim_length) + phy = BsimPhyInstance(proc, phy_output, timeout=duration) yield phy phy.shutdown() @@ -195,7 +190,12 @@ def zephyr_sample(request, bsim_phy, native_sim_env, sim_id): if not binary.exists(): pytest.skip(f"Zephyr sample binary not found: {binary}") - cmd = [str(binary), f"-s={sim_id}", f"-d={device_id}"] + cmd = [ + str(binary), + f"-s={sim_id}", + f"-d={device_id}", + "-disconnect_on_exit=1", + ] logger.info("Running: %s", " ".join(cmd)) proc = subprocess.Popen( cmd, diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py index 7f1ad036f6f..477292ddd54 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py @@ -14,16 +14,13 @@ @pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) +@pytest.mark.duration(3) def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2): """Run two bsim instances on the same sim id and verify UART output.""" - print("in the test") - # Wait for both devices to produce their expected output before - # tearing down the simulation. - circuitpython1.serial.wait_for("bsim ready") - circuitpython2.serial.wait_for("bsim ready") - - bsim_phy.finish_sim() + # Wait for both devices to complete before checking output. + circuitpython1.wait_until_done() + circuitpython2.wait_until_done() output0 = circuitpython1.serial.all_output output1 = circuitpython2.serial.all_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py index 4822d42b9bb..35d85b416d6 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -4,7 +4,6 @@ """BLE advertising tests for nrf5340bsim.""" import logging -import time import pytest @@ -39,8 +38,9 @@ print("adv run start") adapter.start_advertising(advertisement, connectable=False) print("adv running") -while True: - time.sleep(0.2) +time.sleep(10) +adapter.stop_advertising() +print("adv run done") """ @@ -50,54 +50,34 @@ def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): """Advertise from CircuitPython and verify Zephyr observer sees traffic.""" observer = zephyr_sample - start_time = time.time() - while time.time() - start_time < 12.0: - observer_output = observer.serial.all_output - adv_ready = "adv started" in circuitpython.serial.all_output - if ( - "Device found:" in observer_output - and "AD data len 10" in observer_output - and adv_ready - ): - break - time.sleep(0.05) + circuitpython.wait_until_done() + cp_output = circuitpython.serial.all_output observer_output = observer.serial.all_output - assert "adv start" in circuitpython.serial.all_output - assert "adv started" in circuitpython.serial.all_output + assert "adv start" in cp_output + assert "adv started" in cp_output + assert "adv stop" in cp_output assert "Device found:" in observer_output assert "AD data len 10" in observer_output -@pytest.mark.zephyr_sample("bluetooth/observer", timeout=20.0) +@pytest.mark.zephyr_sample("bluetooth/observer") +@pytest.mark.code_py_runs(2) +@pytest.mark.duration(25) @pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_INTERRUPT_RELOAD_CODE}) def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): """Ensure advertising resumes after Ctrl-C and a reload.""" observer = zephyr_sample - start_time = time.time() - sent_ctrl_c = False - sent_reload = False - observer_count_before = 0 - - while time.time() - start_time < 22.0: - cp_output = circuitpython.serial.all_output - observer_output = observer.serial.all_output - device_found_count = observer_output.count("Device found:") - - if not sent_ctrl_c and "adv running" in cp_output and device_found_count > 0: - circuitpython.serial.write("\x03") - sent_ctrl_c = True - observer_count_before = device_found_count - - if sent_ctrl_c and not sent_reload and "KeyboardInterrupt" in cp_output: - circuitpython.serial.write("\x04") - sent_reload = True + circuitpython.serial.wait_for("adv running") + observer.serial.wait_for("Device found:") + observer_count_before = observer.serial.all_output.count("Device found:") - if sent_reload and cp_output.count("adv running") >= 2: - break + circuitpython.serial.write("\x03") + circuitpython.serial.wait_for("KeyboardInterrupt") - time.sleep(0.05) + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() cp_output = circuitpython.serial.all_output observer_output = observer.serial.all_output @@ -107,5 +87,6 @@ def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): assert "adv run start" in cp_output assert "KeyboardInterrupt" in cp_output assert cp_output.count("adv running") >= 2 - assert observer_output.count("Device found:") >= observer_count_before + assert cp_output.count("adv run done") >= 1 + assert observer_output.count("Device found:") >= observer_count_before + 1 assert "Already advertising" not in cp_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py index a7f76ca72b7..69435d38256 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py @@ -3,8 +3,6 @@ """BLE name tests for nrf5340bsim.""" -import time - import pytest pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") @@ -22,10 +20,6 @@ @pytest.mark.circuitpy_drive({"code.py": BSIM_NAME_CODE}) def test_bsim_set_name(bsim_phy, circuitpython): """Set the BLE name and read it back on bsim.""" - start_time = time.time() - while time.time() - start_time < 3.0: - if "name CPNAME" in circuitpython.serial.all_output: - break - time.sleep(0.05) + circuitpython.wait_until_done() assert "name CPNAME" in circuitpython.serial.all_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py index 88366698016..95888ecccb3 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -3,8 +3,6 @@ """BLE scanning tests for nrf5340bsim.""" -import time - import pytest pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") @@ -32,16 +30,8 @@ adapter = _bleio.adapter print("scan run start") -for _ in range(10): - try: - scan = adapter.start_scan(timeout=4.0, active=True) - break - except OSError: - time.sleep(0.1) -else: - raise RuntimeError("scan start failed") found = False -for entry in scan: +for entry in adapter.start_scan(active=True): if b"zephyrproject" in entry.advertisement_bytes: print("found beacon run") found = True @@ -57,16 +47,8 @@ adapter = _bleio.adapter print("scan run start") -for _ in range(10): - try: - scan = adapter.start_scan(timeout=4.0, active=True) - break - except OSError: - time.sleep(0.1) -else: - raise RuntimeError("scan start failed") found = False -for entry in scan: +for entry in adapter.start_scan(active=True): if b"zephyrproject" in entry.advertisement_bytes: print("found beacon run") found = True @@ -81,71 +63,49 @@ def test_bsim_scan_zephyr_beacon(bsim_phy, circuitpython, zephyr_sample): """Scan for Zephyr beacon sample advertisement using bsim.""" _ = zephyr_sample - start_time = time.time() - while time.time() - start_time < 6.0: - if "found beacon" in circuitpython.serial.all_output: - break - time.sleep(0.05) + circuitpython.wait_until_done() - assert "scan start" in circuitpython.serial.all_output - assert "found beacon" in circuitpython.serial.all_output + output = circuitpython.serial.all_output + assert "scan start" in output + assert "found beacon" in output + assert "scan done True" in output -@pytest.mark.zephyr_sample("bluetooth/beacon", timeout=12.0) +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.code_py_runs(2) +@pytest.mark.duration(4) @pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_CODE}) def test_bsim_scan_zephyr_beacon_reload(bsim_phy, circuitpython, zephyr_sample): """Scan for Zephyr beacon, soft reload, and scan again.""" _ = zephyr_sample - start_time = time.time() - sent_reload = False - while time.time() - start_time < 12.0: - output = circuitpython.serial.all_output - - if ( - not sent_reload - and "scan run done" in output - and "Press any key to enter the REPL" in output - ): - time.sleep(0.2) - circuitpython.serial.write("\x04") - sent_reload = True + circuitpython.serial.wait_for("scan run done") + circuitpython.serial.wait_for("Press any key to enter the REPL") + circuitpython.serial.write("\x04") - if sent_reload and output.count("scan run done") >= 2: - break - time.sleep(0.05) + circuitpython.wait_until_done() output = circuitpython.serial.all_output - assert "scan run start" in output + assert output.count("scan run start") >= 2 assert output.count("found beacon run") >= 2 - assert output.count("scan run done") >= 2 + assert output.count("scan run done True") >= 2 -@pytest.mark.zephyr_sample("bluetooth/beacon", timeout=12.0) +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.code_py_runs(2) +@pytest.mark.duration(4) @pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_NO_STOP_CODE}) def test_bsim_scan_zephyr_beacon_reload_no_stop(bsim_phy, circuitpython, zephyr_sample): """Scan for Zephyr beacon without explicit stop, soft reload, and scan again.""" _ = zephyr_sample - start_time = time.time() - sent_reload = False - while time.time() - start_time < 12.0: - output = circuitpython.serial.all_output - - if ( - not sent_reload - and "scan run done" in output - and "Press any key to enter the REPL" in output - ): - time.sleep(0.2) - circuitpython.serial.write("\x04") - sent_reload = True + circuitpython.serial.wait_for("scan run done") + circuitpython.serial.wait_for("Press any key to enter the REPL") + circuitpython.serial.write("\x04") - if sent_reload and output.count("scan run done") >= 2: - break - time.sleep(0.05) + circuitpython.wait_until_done() output = circuitpython.serial.all_output - assert "scan run start" in output + assert output.count("scan run start") >= 2 assert output.count("found beacon run") >= 2 - assert output.count("scan run done") >= 2 + assert output.count("scan run done True") >= 2 diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index f6545a46b55..0bc296cf43f 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -36,7 +36,11 @@ def pytest_configure(config): ) config.addinivalue_line( "markers", - "bsim(devices=1, sim_length=20.0): configure bsim PHY device count and simulation length", + "duration(seconds): native_sim timeout and bsim PHY simulation duration", + ) + config.addinivalue_line( + "markers", + "code_py_runs(count): stop native_sim after count code.py runs (default: 1)", ) @@ -179,12 +183,31 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp timeout = 10 else: timeout = marker.args[0] + + runs_marker = request.node.get_closest_marker("code_py_runs") + if runs_marker is None: + code_py_runs = 1 + else: + code_py_runs = int(runs_marker.args[0]) + if "bsim" in board: cmd = [str(native_sim_binary), f"--flash_app={flash}"] - cmd.extend((f"-s={sim_id}", f"-d={i}", "-uart0_pty", "-uart_pty_wait")) + if instance_count > 1: + cmd.append("-disconnect_on_exit=1") + cmd.extend( + ( + f"-s={sim_id}", + f"-d={i}", + "-uart0_pty", + "-uart0_pty_wait_for_readers", + "-uart_pty_wait", + f"--vm-runs={code_py_runs + 1}", + ) + ) else: cmd = [str(native_sim_binary), f"--flash={flash}"] - cmd.extend(("-no-rt", "-wait_uart", f"-stop_at={timeout}")) + # native_sim vm-runs includes the boot VM setup run. + cmd.extend(("-no-rt", "-wait_uart", f"--vm-runs={code_py_runs + 1}")) marker = request.node.get_closest_marker("disable_i2c_devices") if marker and len(marker.args) > 0: diff --git a/ports/zephyr-cp/tests/test_basics.py b/ports/zephyr-cp/tests/test_basics.py index 96f41d39795..8ed9cc08a59 100644 --- a/ports/zephyr-cp/tests/test_basics.py +++ b/ports/zephyr-cp/tests/test_basics.py @@ -206,6 +206,7 @@ def test_ctrl_c_interrupt(circuitpython): @pytest.mark.circuitpy_drive({"code.py": RELOAD_CODE}) +@pytest.mark.code_py_runs(2) def test_ctrl_d_soft_reload(circuitpython): """Test sending Ctrl+D (0x04) to trigger soft reload.""" circuitpython.serial.wait_for("first run") diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 159467ae7e6..a8b05fabd05 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -2,6 +2,10 @@ manifest: group-filter: - +babblesim projects: + - name: nrf_hw_models + url: https://github.com/tannewt/ext_nRF_hw_models + revision: 24de78c485dce1a6048f8ae1c69a8d70c93b8cdd + path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr revision: 3c5a3a72daa3ca6462cd8bc9c8c7c6a41fbf3b2e From 1303767f6d673259880a6dc357b052478b7969b0 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 23 Feb 2026 16:43:30 -0800 Subject: [PATCH 237/876] Extend timeout --- ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py index 95888ecccb3..3a022944e00 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -93,7 +93,7 @@ def test_bsim_scan_zephyr_beacon_reload(bsim_phy, circuitpython, zephyr_sample): @pytest.mark.zephyr_sample("bluetooth/beacon") @pytest.mark.code_py_runs(2) -@pytest.mark.duration(4) +@pytest.mark.duration(8) @pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_NO_STOP_CODE}) def test_bsim_scan_zephyr_beacon_reload_no_stop(bsim_phy, circuitpython, zephyr_sample): """Scan for Zephyr beacon without explicit stop, soft reload, and scan again.""" From 2428afaf8ce05154f6f946a6125a4ecb30a4ae52 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 24 Feb 2026 18:17:47 +0100 Subject: [PATCH 238/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 6 ++++++ locale/el.po | 6 ++++++ locale/hi.po | 6 ++++++ locale/ko.po | 6 ++++++ locale/ru.po | 6 ++++++ locale/tr.po | 6 ++++++ 6 files changed, 36 insertions(+) diff --git a/locale/cs.po b/locale/cs.po index 24dc4292753..319fe64bc75 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1351,6 +1351,10 @@ msgstr "Chybná MAC adresa" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Neplatný argument" @@ -3830,6 +3834,7 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "nenulový timeout musí být > 0.01" @@ -4313,6 +4318,7 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "timeout překročil maximální podporovanou hodnotu" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "timeout musí být < 655.35 s" diff --git a/locale/el.po b/locale/el.po index 016fb3a381e..da44530ba7e 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1357,6 +1357,10 @@ msgstr "" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -3829,6 +3833,7 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4312,6 +4317,7 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index be00c7cf1c9..f0a35d43e79 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1333,6 +1333,10 @@ msgstr "" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "" @@ -3803,6 +3807,7 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4286,6 +4291,7 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 8e96781ed27..31ec5a50294 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1384,6 +1384,10 @@ msgstr "잘못된 MAC 주소" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "잘못된 인수" @@ -3877,6 +3881,7 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4360,6 +4365,7 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index cff7a97b396..3efafa9e464 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1372,6 +1372,10 @@ msgstr "Неверный MAC-адрес" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Недопустимый аргумент" @@ -3892,6 +3896,7 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "Ненулевое время ожидания должно быть > 0,01" @@ -4376,6 +4381,7 @@ msgstr "" "Продолжительность таймаута превысила максимальное поддерживаемое значение" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "таймаут должен быть < 655.35 сек" diff --git a/locale/tr.po b/locale/tr.po index 0449d8d1261..737eaff9b55 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1351,6 +1351,10 @@ msgstr "Geçersiz MAC adresi" msgid "Invalid ROS domain ID" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + #: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c msgid "Invalid argument" msgstr "Geçersiz argüman" @@ -3825,6 +3829,7 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4308,6 +4313,7 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" From 83510b114cd3d5d7d1a53781fb6170f4194a356a Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 2 Feb 2026 12:02:10 -0800 Subject: [PATCH 239/876] Add input testing based on perfetto traces Tests digital input and new rotaryio. --- ports/zephyr-cp/AGENTS.md | 1 + ports/zephyr-cp/CMakeLists.txt | 4 + ports/zephyr-cp/Makefile | 4 + .../autogen_board_info.toml | 115 +++++ .../circuitpython.toml | 3 + .../boards/adafruit_feather_nrf52840_uf2.conf | 9 + .../adafruit_feather_nrf52840_uf2.overlay | 24 + ports/zephyr-cp/boards/board_aliases.cmake | 1 + .../native/native_sim/autogen_board_info.toml | 2 +- .../nrf5340bsim/autogen_board_info.toml | 2 +- .../nordic/nrf5340dk/autogen_board_info.toml | 2 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 2 +- .../nordic/nrf7002dk/autogen_board_info.toml | 2 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 2 +- .../nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../mimxrt1170_evk/autogen_board_info.toml | 2 +- .../da14695_dk_usb/autogen_board_info.toml | 2 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../nucleo_n657x0_q/autogen_board_info.toml | 2 +- .../nucleo_u575zi_q/autogen_board_info.toml | 2 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 2 +- .../stm32wba65i_dk1/autogen_board_info.toml | 2 +- .../common-hal/rotaryio/IncrementalEncoder.c | 129 +++++ .../common-hal/rotaryio/IncrementalEncoder.h | 31 ++ .../zephyr-cp/common-hal/rotaryio/__init__.c | 7 + ports/zephyr-cp/cptools/build_all_boards.py | 446 ++++++++++++++++-- .../zephyr-cp/cptools/build_circuitpython.py | 8 +- ports/zephyr-cp/cptools/zephyr2cp.py | 3 + ports/zephyr-cp/tests/conftest.py | 22 +- ports/zephyr-cp/tests/docs/babblesim.md | 12 + ports/zephyr-cp/tests/perfetto_input_trace.py | 128 +++++ ports/zephyr-cp/tests/test_basics.py | 107 +---- ports/zephyr-cp/tests/test_digitalio.py | 171 +++++++ ports/zephyr-cp/tests/test_rotaryio.py | 132 ++++++ ports/zephyr-cp/zephyr-config/west.yml | 2 +- 37 files changed, 1215 insertions(+), 176 deletions(-) create mode 100644 ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf create mode 100644 ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay create mode 100644 ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.c create mode 100644 ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.h create mode 100644 ports/zephyr-cp/common-hal/rotaryio/__init__.c create mode 100644 ports/zephyr-cp/tests/perfetto_input_trace.py create mode 100644 ports/zephyr-cp/tests/test_digitalio.py create mode 100644 ports/zephyr-cp/tests/test_rotaryio.py diff --git a/ports/zephyr-cp/AGENTS.md b/ports/zephyr-cp/AGENTS.md index a2413e64e42..47813886804 100644 --- a/ports/zephyr-cp/AGENTS.md +++ b/ports/zephyr-cp/AGENTS.md @@ -3,3 +3,4 @@ - The files (not folders) in `boards/` directory are used by Zephyr. - To flash it on a board do `make BOARD=_ flash`. - Zephyr board docs are at `zephyr/boards//`. +- Run zephyr-cp tests with `make test`. diff --git a/ports/zephyr-cp/CMakeLists.txt b/ports/zephyr-cp/CMakeLists.txt index 0ba4a3c48b3..9d115f1e176 100644 --- a/ports/zephyr-cp/CMakeLists.txt +++ b/ports/zephyr-cp/CMakeLists.txt @@ -10,6 +10,10 @@ if(CONFIG_BOARD_NATIVE_SIM) target_sources(app PRIVATE native_sim_i2c_emul_control.c) endif() +if(CONFIG_TRACING_PERFETTO) + zephyr_include_directories(${ZEPHYR_BINARY_DIR}/subsys/tracing/perfetto/proto) +endif() + # From: https://github.com/zephyrproject-rtos/zephyr/blob/main/samples/application_development/external_lib/CMakeLists.txt # The external static library that we are linking with does not know # how to build for this platform so we export all the flags used in diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index c4feead23b9..24c6bf08da6 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,6 +8,7 @@ BUILD ?= build-$(BOARD) TRANSLATION ?= en_US +.DEFAULT_GOAL := $(BUILD)/zephyr-cp/zephyr/zephyr.elf .PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug run clean menuconfig all clean-all test fetch-port-submodules @@ -24,6 +25,9 @@ $(BUILD)/firmware.hex: $(BUILD)/zephyr-cp/zephyr/zephyr.elf $(BUILD)/firmware.exe: $(BUILD)/zephyr-cp/zephyr/zephyr.elf cp $(BUILD)/zephyr-cp/zephyr/zephyr.exe $@ +$(BUILD)/firmware.uf2: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + cp $(BUILD)/zephyr-cp/zephyr/zephyr.uf2 $@ + flash: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west flash -d $(BUILD) diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..db83e1b7448 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -0,0 +1,115 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Adafruit Industries LLC Feather nRF52840 (Express, Sense)" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml new file mode 100644 index 00000000000..e1a16cb74aa --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml @@ -0,0 +1,3 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +USB_VID=0x239A +USB_PID=0x802A diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf new file mode 100644 index 00000000000..c30c8c19fcd --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf @@ -0,0 +1,9 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n +CONFIG_BOARD_REQUIRES_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay new file mode 100644 index 00000000000..a61cbf2047d --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay @@ -0,0 +1,24 @@ +/ { + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + }; +}; + +&zephyr_udc0 { + /delete-node/ board_cdc_acm_uart; +}; + + +&gd25q16 { + /delete-node/ partitions; +}; + +&uart0 { + status = "okay"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index ddf1627a924..ee46145a112 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -1,4 +1,5 @@ set(pca10056_BOARD_ALIAS nrf52840dk/nrf52840) +set(adafruit_feather_nrf52840_zephyr_BOARD_ALIAS adafruit_feather_nrf52840/nrf52840/uf2) set(renesas_ek_ra6m5_BOARD_ALIAS ek_ra6m5) set(renesas_ek_ra8d1_BOARD_ALIAS ek_ra8d1) set(renesas_da14695_dk_usb_BOARD_ALIAS da14695_dk_usb) diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 73897f71620..447a6ab2d5b 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 9ddbb2153fb..1e69862044a 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 52beeda076f..c2d1b48f942 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 2759dfb89c1..0068cb9601d 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 6df832f607b..df63cff8f7c 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index d713552d87b..6a60bfd84f1 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 233796fc6f4..c8890700681 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index f7ad0289cc7..7413c21be9a 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 4926b5c9a6c..f5262b28236 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index 77d93aa10f0..8f054774d55 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 2ea2cea90b7..e9fbec0cdce 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 3be48a8b72c..dd3d0869625 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 4b9c1053f22..e044cef97ca 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index ec78a62f066..53deb5b22e9 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 24e44662e40..da3aa7e30b7 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index e26084cc43e..c943b80affe 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -82,7 +82,7 @@ rainbowio = true random = true rclcpy = false rgbmatrix = false -rotaryio = false +rotaryio = true # Zephyr board has rotaryio rtc = false sdcardio = true # Zephyr board has busio sdioio = false diff --git a/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.c b/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.c new file mode 100644 index 00000000000..d36b571535a --- /dev/null +++ b/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.c @@ -0,0 +1,129 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include "common-hal/rotaryio/IncrementalEncoder.h" +#include "shared-bindings/rotaryio/IncrementalEncoder.h" +#include "shared-module/rotaryio/IncrementalEncoder.h" + +#include "bindings/zephyr_kernel/__init__.h" +#include "py/runtime.h" + +#include +#include +#include +#include + +static void incrementalencoder_gpio_callback(const struct device *port, + struct gpio_callback *cb, gpio_port_pins_t pins) { + (void)port; + (void)pins; + rotaryio_incrementalencoder_gpio_callback_t *callback = + CONTAINER_OF(cb, rotaryio_incrementalencoder_gpio_callback_t, callback); + rotaryio_incrementalencoder_obj_t *self = callback->encoder; + if (self == NULL || self->pin_a == NULL) { + return; + } + + int a = gpio_pin_get(self->pin_a->port, self->pin_a->number); + int b = gpio_pin_get(self->pin_b->port, self->pin_b->number); + if (a < 0 || b < 0) { + return; + } + uint8_t new_state = ((uint8_t)a << 1) | (uint8_t)b; + shared_module_softencoder_state_update(self, new_state); +} + +void common_hal_rotaryio_incrementalencoder_construct(rotaryio_incrementalencoder_obj_t *self, + const mcu_pin_obj_t *pin_a, const mcu_pin_obj_t *pin_b) { + // Ensure object starts in its deinit state. + common_hal_rotaryio_incrementalencoder_mark_deinit(self); + + self->pin_a = pin_a; + self->pin_b = pin_b; + self->divisor = 4; + + if (!device_is_ready(pin_a->port) || !device_is_ready(pin_b->port)) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(-ENODEV); + } + + int result = gpio_pin_configure(pin_a->port, pin_a->number, GPIO_INPUT | GPIO_PULL_UP); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + result = gpio_pin_configure(pin_b->port, pin_b->number, GPIO_INPUT | GPIO_PULL_UP); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + self->callback_a.encoder = self; + gpio_init_callback(&self->callback_a.callback, incrementalencoder_gpio_callback, + BIT(pin_a->number)); + result = gpio_add_callback(pin_a->port, &self->callback_a.callback); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + self->callback_b.encoder = self; + gpio_init_callback(&self->callback_b.callback, incrementalencoder_gpio_callback, + BIT(pin_b->number)); + result = gpio_add_callback(pin_b->port, &self->callback_b.callback); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + result = gpio_pin_interrupt_configure(pin_a->port, pin_a->number, GPIO_INT_EDGE_BOTH); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + result = gpio_pin_interrupt_configure(pin_b->port, pin_b->number, GPIO_INT_EDGE_BOTH); + if (result != 0) { + common_hal_rotaryio_incrementalencoder_deinit(self); + raise_zephyr_error(result); + } + + int a = gpio_pin_get(pin_a->port, pin_a->number); + int b = gpio_pin_get(pin_b->port, pin_b->number); + uint8_t quiescent_state = ((uint8_t)(a > 0) << 1) | (uint8_t)(b > 0); + shared_module_softencoder_state_init(self, quiescent_state); + + claim_pin(pin_a); + claim_pin(pin_b); +} + +bool common_hal_rotaryio_incrementalencoder_deinited(rotaryio_incrementalencoder_obj_t *self) { + return self->pin_a == NULL; +} + +void common_hal_rotaryio_incrementalencoder_deinit(rotaryio_incrementalencoder_obj_t *self) { + if (common_hal_rotaryio_incrementalencoder_deinited(self)) { + return; + } + + // Best-effort cleanup. During failed construct(), some of these may not be + // initialized yet. Ignore cleanup errors. + gpio_pin_interrupt_configure(self->pin_a->port, self->pin_a->number, GPIO_INT_DISABLE); + gpio_pin_interrupt_configure(self->pin_b->port, self->pin_b->number, GPIO_INT_DISABLE); + gpio_remove_callback(self->pin_a->port, &self->callback_a.callback); + gpio_remove_callback(self->pin_b->port, &self->callback_b.callback); + + reset_pin(self->pin_a); + reset_pin(self->pin_b); + + common_hal_rotaryio_incrementalencoder_mark_deinit(self); +} + +void common_hal_rotaryio_incrementalencoder_mark_deinit(rotaryio_incrementalencoder_obj_t *self) { + self->pin_a = NULL; + self->pin_b = NULL; +} diff --git a/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.h b/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.h new file mode 100644 index 00000000000..a0d2bb392e2 --- /dev/null +++ b/ports/zephyr-cp/common-hal/rotaryio/IncrementalEncoder.h @@ -0,0 +1,31 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "common-hal/microcontroller/Pin.h" +#include "py/obj.h" + +typedef struct rotaryio_incrementalencoder_obj rotaryio_incrementalencoder_obj_t; + +typedef struct { + struct gpio_callback callback; + rotaryio_incrementalencoder_obj_t *encoder; +} rotaryio_incrementalencoder_gpio_callback_t; + +struct rotaryio_incrementalencoder_obj { + mp_obj_base_t base; + const mcu_pin_obj_t *pin_a; + const mcu_pin_obj_t *pin_b; + rotaryio_incrementalencoder_gpio_callback_t callback_a; + rotaryio_incrementalencoder_gpio_callback_t callback_b; + uint8_t state; // + int8_t sub_count; // count intermediate transitions between detents + int8_t divisor; // Number of quadrature edges required per count + mp_int_t position; +}; diff --git a/ports/zephyr-cp/common-hal/rotaryio/__init__.c b/ports/zephyr-cp/common-hal/rotaryio/__init__.c new file mode 100644 index 00000000000..67cae26a8b7 --- /dev/null +++ b/ports/zephyr-cp/common-hal/rotaryio/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// No rotaryio module functions. diff --git a/ports/zephyr-cp/cptools/build_all_boards.py b/ports/zephyr-cp/cptools/build_all_boards.py index 8ad6bd05ea9..da9f45ead1e 100755 --- a/ports/zephyr-cp/cptools/build_all_boards.py +++ b/ports/zephyr-cp/cptools/build_all_boards.py @@ -3,17 +3,113 @@ Build all CircuitPython boards for the Zephyr port. This script discovers all boards by finding circuitpython.toml files -and builds each one sequentially, passing through the jobserver for -parallelism within each build. +and builds them in parallel while sharing a single jobserver across +all builds. + +This is agent generated and works. Don't bother reading too closely because it +is just a tool for us. """ import argparse +import concurrent.futures +import os import pathlib +import shlex import subprocess import sys import time +class Jobserver: + def __init__(self, read_fd, write_fd, jobs=None, owns_fds=False): + self.read_fd = read_fd + self.write_fd = write_fd + self.jobs = jobs + self.owns_fds = owns_fds + + def acquire(self): + while True: + try: + os.read(self.read_fd, 1) + return + except InterruptedError: + continue + + def release(self): + while True: + try: + os.write(self.write_fd, b"+") + return + except InterruptedError: + continue + + def pass_fds(self): + return (self.read_fd, self.write_fd) + + def close(self): + if self.owns_fds: + os.close(self.read_fd) + os.close(self.write_fd) + + +def _parse_makeflags_jobserver(makeflags): + jobserver_auth = None + jobs = None + + for token in shlex.split(makeflags): + if token == "-j" or token == "--jobs": + continue + if token.startswith("-j") and token != "-j": + try: + jobs = int(token[2:]) + except ValueError: + pass + elif token.startswith("--jobs="): + try: + jobs = int(token.split("=", 1)[1]) + except ValueError: + pass + elif token.startswith("--jobserver-auth=") or token.startswith("--jobserver-fds="): + jobserver_auth = token.split("=", 1)[1] + + if not jobserver_auth: + return None, jobs, False + + if jobserver_auth.startswith("fifo:"): + fifo_path = jobserver_auth[len("fifo:") :] + read_fd = os.open(fifo_path, os.O_RDONLY) + write_fd = os.open(fifo_path, os.O_WRONLY) + os.set_inheritable(read_fd, True) + os.set_inheritable(write_fd, True) + return (read_fd, write_fd), jobs, True + + if "," in jobserver_auth: + read_fd, write_fd = jobserver_auth.split(",", 1) + return (int(read_fd), int(write_fd)), jobs, False + + return None, jobs, False + + +def _create_jobserver(jobs): + read_fd, write_fd = os.pipe() + os.set_inheritable(read_fd, True) + os.set_inheritable(write_fd, True) + for _ in range(jobs): + os.write(write_fd, b"+") + return Jobserver(read_fd, write_fd, jobs=jobs, owns_fds=True) + + +def _jobserver_from_env(): + makeflags = os.environ.get("MAKEFLAGS", "") + fds, jobs, owns_fds = _parse_makeflags_jobserver(makeflags) + if not fds: + return None, jobs + read_fd, write_fd = fds + os.set_inheritable(read_fd, True) + os.set_inheritable(write_fd, True) + return Jobserver(read_fd, write_fd, jobs=jobs, owns_fds=owns_fds), jobs + + def discover_boards(port_dir): """ Discover all boards by finding circuitpython.toml files. @@ -35,7 +131,15 @@ def discover_boards(port_dir): return sorted(boards) -def build_board(port_dir, vendor, board, extra_args=None): +def build_board( + port_dir, + vendor, + board, + extra_args=None, + jobserver=None, + env=None, + log_dir=None, +): """ Build a single board using make. @@ -44,12 +148,16 @@ def build_board(port_dir, vendor, board, extra_args=None): vendor: Board vendor name board: Board name extra_args: Additional arguments to pass to make + jobserver: Jobserver instance to limit parallel builds + env: Environment variables for the subprocess + log_dir: Directory to write build logs Returns: - (success: bool, elapsed_time: float) + (success: bool, elapsed_time: float, output: str, log_path: pathlib.Path) """ board_id = f"{vendor}_{board}" start_time = time.time() + log_path = None cmd = ["make", f"BOARD={board_id}"] @@ -57,25 +165,240 @@ def build_board(port_dir, vendor, board, extra_args=None): if extra_args: cmd.extend(extra_args) + if jobserver: + jobserver.acquire() + try: - subprocess.run( + result = subprocess.run( cmd, cwd=port_dir, - check=True, - # Inherit stdin to pass through jobserver file descriptors + # Inherit stdin alongside jobserver file descriptors stdin=sys.stdin, - # Show output in real-time - stdout=None, - stderr=None, - capture_output=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True, + env=env, + pass_fds=jobserver.pass_fds() if jobserver else (), ) elapsed = time.time() - start_time - return True, elapsed - except subprocess.CalledProcessError: - elapsed = time.time() - start_time - return False, elapsed + output = result.stdout or "" + if log_dir: + log_path = log_dir / f"{board_id}.log" + log_path.write_text(output) + return result.returncode == 0, elapsed, output, log_path except KeyboardInterrupt: raise + finally: + if jobserver: + jobserver.release() + + +def _format_status(status): + state = status["state"] + elapsed = status.get("elapsed") + if state == "queued": + return "QUEUED" + if state == "running": + return f"RUNNING {elapsed:.1f}s" + if state == "success": + return f"SUCCESS {elapsed:.1f}s" + if state == "failed": + return f"FAILED {elapsed:.1f}s" + if state == "skipped": + return "SKIPPED" + return state.upper() + + +def _build_status_table(boards, statuses, start_time, stop_submitting): + from rich.table import Table + from rich.text import Text + + elapsed = time.time() - start_time + title = f"Building {len(boards)} boards | Elapsed: {elapsed:.1f}s" + if stop_submitting: + title += " | STOPPING AFTER FAILURE" + + table = Table(title=title) + table.add_column("#", justify="right") + table.add_column("Board", no_wrap=True) + table.add_column("Status", no_wrap=True) + + for i, (vendor, board) in enumerate(boards): + board_id = f"{vendor}_{board}" + status_text = _format_status(statuses[i]) + state = statuses[i]["state"] + style = None + if state == "success": + style = "green" + elif state == "failed": + style = "red" + table.add_row( + f"{i + 1}/{len(boards)}", + board_id, + Text(status_text, style=style) if style else status_text, + ) + + return table + + +def _run_builds_tui( + port_dir, + boards, + extra_args, + jobserver, + env, + log_dir, + max_workers, + continue_on_error, +): + from rich.live import Live + + statuses = [ + {"state": "queued", "elapsed": 0.0, "start": None, "log_path": None} for _ in boards + ] + results = [] + futures = {} + next_index = 0 + stop_submitting = False + start_time = time.time() + + with Live( + _build_status_table(boards, statuses, start_time, stop_submitting), + refresh_per_second=4, + transient=False, + ) as live: + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + while next_index < len(boards) and len(futures) < max_workers: + vendor, board = boards[next_index] + statuses[next_index]["state"] = "running" + statuses[next_index]["start"] = time.time() + future = executor.submit( + build_board, + port_dir, + vendor, + board, + extra_args, + jobserver, + env, + log_dir, + ) + futures[future] = next_index + next_index += 1 + + while futures: + for status in statuses: + if status["state"] == "running": + status["elapsed"] = time.time() - status["start"] + + live.update(_build_status_table(boards, statuses, start_time, stop_submitting)) + + done, _ = concurrent.futures.wait( + futures, + timeout=0.1, + return_when=concurrent.futures.FIRST_COMPLETED, + ) + for future in done: + index = futures.pop(future) + vendor, board = boards[index] + success, elapsed, _output, log_path = future.result() + statuses[index]["elapsed"] = elapsed + statuses[index]["log_path"] = log_path + statuses[index]["state"] = "success" if success else "failed" + results.append((vendor, board, success, elapsed)) + + if not success and not continue_on_error: + stop_submitting = True + + if not stop_submitting and next_index < len(boards): + vendor, board = boards[next_index] + statuses[next_index]["state"] = "running" + statuses[next_index]["start"] = time.time() + future = executor.submit( + build_board, + port_dir, + vendor, + board, + extra_args, + jobserver, + env, + log_dir, + ) + futures[future] = next_index + next_index += 1 + + if stop_submitting: + for index in range(next_index, len(boards)): + if statuses[index]["state"] == "queued": + statuses[index]["state"] = "skipped" + + live.update(_build_status_table(boards, statuses, start_time, stop_submitting)) + + return results, stop_submitting + + +def _run_builds_plain( + port_dir, + boards, + extra_args, + jobserver, + env, + log_dir, + max_workers, + continue_on_error, +): + results = [] + futures = {} + next_index = 0 + stop_submitting = False + + with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor: + while next_index < len(boards) and len(futures) < max_workers: + vendor, board = boards[next_index] + future = executor.submit( + build_board, + port_dir, + vendor, + board, + extra_args, + jobserver, + env, + log_dir, + ) + futures[future] = (vendor, board) + next_index += 1 + + while futures: + done, _ = concurrent.futures.wait( + futures, + return_when=concurrent.futures.FIRST_COMPLETED, + ) + for future in done: + vendor, board = futures.pop(future) + success, elapsed, _output, _log_path = future.result() + board_id = f"{vendor}_{board}" + status = "SUCCESS" if success else "FAILURE" + print(f"{board_id}: {status} ({elapsed:.1f}s)") + results.append((vendor, board, success, elapsed)) + + if not success and not continue_on_error: + stop_submitting = True + + if not stop_submitting and next_index < len(boards): + vendor, board = boards[next_index] + future = executor.submit( + build_board, + port_dir, + vendor, + board, + extra_args, + jobserver, + env, + log_dir, + ) + futures[future] = (vendor, board) + next_index += 1 + + return results, stop_submitting def main(): @@ -84,7 +407,7 @@ def main(): formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" Examples: - # Build all boards sequentially with 32 parallel jobs per board + # Build all boards in parallel with 32 jobserver slots %(prog)s -j32 # Build all boards using make's jobserver (recommended) @@ -94,9 +417,9 @@ def main(): parser.add_argument( "-j", "--jobs", - type=str, + type=int, default=None, - help="Number of parallel jobs for each board build (passed to make)", + help="Number of shared jobserver slots across all board builds", ) parser.add_argument( "--continue-on-error", @@ -106,6 +429,10 @@ def main(): args = parser.parse_args() + if args.jobs is not None and args.jobs < 1: + print("ERROR: --jobs must be at least 1") + return 2 + # Get the port directory port_dir = pathlib.Path(__file__).parent.resolve().parent @@ -116,48 +443,67 @@ def main(): print("ERROR: No boards found!") return 1 - # Prepare extra make arguments + # Prepare jobserver and extra make arguments + jobserver, detected_jobs = _jobserver_from_env() + env = os.environ.copy() + extra_args = [] - if args.jobs: - extra_args.append(f"-j{args.jobs}") + jobserver_jobs = detected_jobs + + if not jobserver: + jobserver_jobs = args.jobs if args.jobs else (os.cpu_count() or 1) + jobserver = _create_jobserver(jobserver_jobs) + env["MAKEFLAGS"] = ( + f"-j{jobserver_jobs} --jobserver-auth={jobserver.read_fd},{jobserver.write_fd}" + ) + + max_workers = jobserver_jobs + if max_workers is None: + max_workers = min(len(boards), os.cpu_count() or 1) + max_workers = max(1, min(len(boards), max_workers)) # Build all boards - start_time = time.time() - results = [] + log_dir = port_dir / "build-logs" + log_dir.mkdir(parents=True, exist_ok=True) try: - for index, (vendor, board) in enumerate(boards): - board_id = f"{vendor}_{board}" - print(f"{index + 1}/{len(boards)} {board_id}: ", end="", flush=True) - - success, elapsed = build_board(port_dir, vendor, board, extra_args) - if success: - print(f"✅ SUCCESS ({elapsed:.1f}s)") - else: - print(f"❌ FAILURE ({elapsed:.1f}s)") - results.append((vendor, board, success, elapsed)) - - if not success and not args.continue_on_error: - print("\nStopping due to build failure.") - break + use_tui = sys.stdout.isatty() + if use_tui: + try: + import rich # noqa: F401 + except ImportError: + use_tui = False + + if use_tui: + results, stop_submitting = _run_builds_tui( + port_dir, + boards, + extra_args, + jobserver, + env, + log_dir, + max_workers, + args.continue_on_error, + ) + else: + results, stop_submitting = _run_builds_plain( + port_dir, + boards, + extra_args, + jobserver, + env, + log_dir, + max_workers, + args.continue_on_error, + ) except KeyboardInterrupt: print("\n\nBuild interrupted by user.") return 130 # Standard exit code for SIGINT + finally: + if jobserver: + jobserver.close() - # Print summary - total_time = time.time() - start_time - print(f"\n{'=' * 80}") - print("Build Summary") - print(f"{'=' * 80}") - - successful = [r for r in results if r[2]] failed = [r for r in results if not r[2]] - - print(f"\nTotal boards: {len(results)}/{len(boards)}") - print(f"Successful: {len(successful)}") - print(f"Failed: {len(failed)}") - print(f"Total time: {total_time:.1f}s") - return 0 if len(failed) == 0 else 1 diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 3a007661c77..dcd49640a8d 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -52,6 +52,7 @@ "json", "random", "digitalio", + "rotaryio", "rainbowio", "traceback", "warnings", @@ -81,9 +82,12 @@ } # Other flags to set when a module is enabled -EXTRA_FLAGS = {"busio": ["BUSIO_SPI", "BUSIO_I2C"]} +EXTRA_FLAGS = { + "busio": ["BUSIO_SPI", "BUSIO_I2C"], + "rotaryio": ["ROTARYIO_SOFTENCODER"], +} -SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os"] +SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os", "rotaryio"] # Mapping from module directory name to the flag name used in CIRCUITPY_ MODULE_FLAG_NAMES = { diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 86b0b0fe403..f24bdfddadc 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -20,7 +20,9 @@ "nordic_nrf_uarte": "serial", "nordic_nrf_uart": "serial", "nordic_nrf_twim": "i2c", + "nordic_nrf_twi": "i2c", "nordic_nrf_spim": "spi", + "nordic_nrf_spi": "spi", } # These are controllers, not the flash devices themselves. @@ -802,5 +804,6 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa board_info["source_files"] = [board_c] board_info["cflags"] = ("-I", board_dir) board_info["flash_count"] = len(flashes) + board_info["rotaryio"] = bool(ioports) board_info["usb_num_endpoint_pairs"] = usb_num_endpoint_pairs return board_info diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index 0bc296cf43f..cb7c61ed68a 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -14,6 +14,7 @@ import pytest import serial from . import NativeSimProcess +from .perfetto_input_trace import write_input_trace from perfetto.trace_processor import TraceProcessor @@ -42,6 +43,10 @@ def pytest_configure(config): "markers", "code_py_runs(count): stop native_sim after count code.py runs (default: 1)", ) + config.addinivalue_line( + "markers", + "input_trace(trace): inject input signal trace data into native_sim", + ) ZEPHYR_CP = Path(__file__).parent.parent @@ -117,7 +122,6 @@ def log_uart_trace_output(trace_file: Path) -> None: @pytest.fixture def board(request): board = request.node.get_closest_marker("circuitpython_board") - print("board", board) if board is not None: board = board.args[0] else: @@ -159,6 +163,14 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp if len(drives) != instance_count: raise RuntimeError(f"not enough drives for {instance_count} instances") + input_trace_markers = list(request.node.iter_markers_with_node("input_trace")) + if len(input_trace_markers) > 1: + raise RuntimeError("expected at most one input_trace marker") + + input_trace = None + if input_trace_markers and len(input_trace_markers[0][1].args) == 1: + input_trace = input_trace_markers[0][1].args[0] + procs = [] for i in range(instance_count): flash = tmp_path / f"flash-{i}.bin" @@ -178,6 +190,11 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp trace_file = tmp_path / f"trace-{i}.perfetto" + input_trace_file = None + if input_trace is not None: + input_trace_file = tmp_path / f"input-{i}.perfetto" + write_input_trace(input_trace_file, input_trace) + marker = request.node.get_closest_marker("duration") if marker is None: timeout = 10 @@ -209,6 +226,9 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp # native_sim vm-runs includes the boot VM setup run. cmd.extend(("-no-rt", "-wait_uart", f"--vm-runs={code_py_runs + 1}")) + if input_trace_file is not None: + cmd.append(f"--input-trace={input_trace_file}") + marker = request.node.get_closest_marker("disable_i2c_devices") if marker and len(marker.args) > 0: for device in marker.args: diff --git a/ports/zephyr-cp/tests/docs/babblesim.md b/ports/zephyr-cp/tests/docs/babblesim.md index abf68b2b1de..75d45079b2e 100644 --- a/ports/zephyr-cp/tests/docs/babblesim.md +++ b/ports/zephyr-cp/tests/docs/babblesim.md @@ -59,6 +59,18 @@ pytest tests/test_bsim_ble_scan.py -v pytest tests/test_bsim_ble_advertising.py -v ``` +## Pytest markers + +For bsim-specific test tuning: + +- `@pytest.mark.duration(seconds)` controls simulation runtime/timeout. + +Example: + +```py +pytestmark = pytest.mark.duration(30.0) +``` + ## Notes - The bsim test spawns two instances that share a sim id. It only checks UART diff --git a/ports/zephyr-cp/tests/perfetto_input_trace.py b/ports/zephyr-cp/tests/perfetto_input_trace.py new file mode 100644 index 00000000000..d0cde49be08 --- /dev/null +++ b/ports/zephyr-cp/tests/perfetto_input_trace.py @@ -0,0 +1,128 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries LLC +# SPDX-License-Identifier: MIT + +"""Utilities for creating Perfetto input trace files for native_sim tests. + +This module can be used directly from Python or from the command line: + + python -m tests.perfetto_input_trace input_trace.json output.perfetto + +Input JSON format: + +{ + "gpio_emul.01": [[8000000000, 0], [9000000000, 1], [10000000000, 0]], + "gpio_emul.02": [[8000000000, 0], [9200000000, 1]] +} +""" + +from __future__ import annotations + +import argparse +import json +from pathlib import Path +from typing import Mapping, Sequence + +InputTraceData = Mapping[str, Sequence[tuple[int, int]]] + + +def _load_perfetto_pb2(): + from perfetto.protos.perfetto.trace import perfetto_trace_pb2 as perfetto_pb2 + + return perfetto_pb2 + + +def build_input_trace(trace_data: InputTraceData, *, sequence_id: int = 1): + """Build a Perfetto Trace protobuf for input replay counter tracks.""" + perfetto_pb2 = _load_perfetto_pb2() + trace = perfetto_pb2.Trace() + + seq_incremental_state_cleared = 1 + seq_needs_incremental_state = 2 + + for idx, (track_name, events) in enumerate(trace_data.items()): + track_uuid = 1001 + idx + + desc_packet = trace.packet.add() + desc_packet.timestamp = 0 + desc_packet.trusted_packet_sequence_id = sequence_id + if idx == 0: + desc_packet.sequence_flags = seq_incremental_state_cleared + desc_packet.track_descriptor.uuid = track_uuid + desc_packet.track_descriptor.name = track_name + desc_packet.track_descriptor.counter.unit = perfetto_pb2.CounterDescriptor.Unit.UNIT_COUNT + + for ts, value in events: + event_packet = trace.packet.add() + event_packet.timestamp = ts + event_packet.trusted_packet_sequence_id = sequence_id + event_packet.sequence_flags = seq_needs_incremental_state + event_packet.track_event.type = perfetto_pb2.TrackEvent.Type.TYPE_COUNTER + event_packet.track_event.track_uuid = track_uuid + event_packet.track_event.counter_value = value + + return trace + + +def write_input_trace( + trace_file: Path, trace_data: InputTraceData, *, sequence_id: int = 1 +) -> None: + """Write input replay data to a Perfetto trace file.""" + trace = build_input_trace(trace_data, sequence_id=sequence_id) + trace_file.parent.mkdir(parents=True, exist_ok=True) + trace_file.write_bytes(trace.SerializeToString()) + + +def _parse_trace_json(data: object) -> dict[str, list[tuple[int, int]]]: + if not isinstance(data, dict): + raise ValueError("top-level JSON value must be an object") + + parsed: dict[str, list[tuple[int, int]]] = {} + for track_name, events in data.items(): + if not isinstance(track_name, str): + raise ValueError("track names must be strings") + if not isinstance(events, list): + raise ValueError( + f"track {track_name!r} must map to a list of [timestamp, value] events" + ) + + parsed_events: list[tuple[int, int]] = [] + for event in events: + if not isinstance(event, (list, tuple)) or len(event) != 2: + raise ValueError(f"track {track_name!r} events must be [timestamp, value] pairs") + timestamp_ns, value = event + parsed_events.append((int(timestamp_ns), int(value))) + + parsed[track_name] = parsed_events + + return parsed + + +def _build_arg_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser( + description="Generate a Perfetto input trace file used by native_sim --input-trace" + ) + parser.add_argument("input_json", type=Path, help="Path to input trace JSON") + parser.add_argument("output_trace", type=Path, help="Output .perfetto file path") + parser.add_argument( + "--sequence-id", + type=int, + default=1, + help="trusted_packet_sequence_id to use (default: 1)", + ) + return parser + + +def main(argv: Sequence[str] | None = None) -> int: + parser = _build_arg_parser() + args = parser.parse_args(argv) + + trace_json = json.loads(args.input_json.read_text()) + trace_data = _parse_trace_json(trace_json) + write_input_trace(args.output_trace, trace_data, sequence_id=args.sequence_id) + + print(f"Wrote {args.output_trace} ({len(trace_data)} tracks)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/ports/zephyr-cp/tests/test_basics.py b/ports/zephyr-cp/tests/test_basics.py index 8ed9cc08a59..84b31849a8e 100644 --- a/ports/zephyr-cp/tests/test_basics.py +++ b/ports/zephyr-cp/tests/test_basics.py @@ -1,13 +1,10 @@ # SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""Test LED blink functionality on native_sim.""" +"""Test basic native_sim functionality.""" import pytest -from pathlib import Path -from perfetto.trace_processor import TraceProcessor - @pytest.mark.circuitpy_drive(None) def test_blank_flash_hello_world(circuitpython): @@ -22,108 +19,6 @@ def test_blank_flash_hello_world(circuitpython): assert "done" in output -BLINK_CODE = """\ -import time -import board -import digitalio - -led = digitalio.DigitalInOut(board.LED) -led.direction = digitalio.Direction.OUTPUT - -for i in range(3): - print(f"LED on {i}") - led.value = True - time.sleep(0.1) - print(f"LED off {i}") - led.value = False - time.sleep(0.1) - -print("done") -""" - - -def parse_gpio_trace(trace_file: Path, pin_name: str = "gpio_emul.00") -> list[tuple[int, int]]: - """Parse GPIO trace from Perfetto trace file.""" - tp = TraceProcessor(file_path=str(trace_file)) - result = tp.query( - f''' - SELECT c.ts, c.value - FROM counter c - JOIN track t ON c.track_id = t.id - WHERE t.name = "{pin_name}" - ORDER BY c.ts - ''' - ) - return [(row.ts, int(row.value)) for row in result] - - -@pytest.mark.circuitpy_drive({"code.py": BLINK_CODE}) -def test_blink_output(circuitpython): - """Test blink program produces expected output and GPIO traces.""" - circuitpython.wait_until_done() - - # Check serial output - output = circuitpython.serial.all_output - assert "LED on 0" in output - assert "LED off 0" in output - assert "LED on 2" in output - assert "LED off 2" in output - assert "done" in output - - # Check GPIO traces - LED is on gpio_emul.00 - gpio_trace = parse_gpio_trace(circuitpython.trace_file, "gpio_emul.00") - - # Deduplicate by timestamp (keep last value at each timestamp) - by_timestamp = {} - for ts, val in gpio_trace: - by_timestamp[ts] = val - sorted_trace = sorted(by_timestamp.items()) - - # Find transition points (where value changes), skipping initialization at ts=0 - transitions = [] - for i in range(1, len(sorted_trace)): - prev_ts, prev_val = sorted_trace[i - 1] - curr_ts, curr_val = sorted_trace[i] - if prev_val != curr_val and curr_ts > 0: - transitions.append((curr_ts, curr_val)) - - # We expect at least 6 transitions (3 on + 3 off) from the blink loop - assert len(transitions) >= 6, f"Expected at least 6 transitions, got {len(transitions)}" - - # Verify timing between consecutive transitions - # Each sleep is 0.1s = 100ms = 100,000,000 ns - expected_interval_ns = 100_000_000 - tolerance_ns = 20_000_000 # 20ms tolerance - - # Find a sequence of 6 consecutive transitions with ~100ms intervals (the blink loop) - # This filters out initialization and cleanup noise - blink_transitions = [] - for i in range(len(transitions) - 1): - interval = transitions[i + 1][0] - transitions[i][0] - if abs(interval - expected_interval_ns) < tolerance_ns: - if not blink_transitions: - blink_transitions.append(transitions[i]) - blink_transitions.append(transitions[i + 1]) - elif blink_transitions: - # Found end of blink sequence - break - - assert len(blink_transitions) >= 6, ( - f"Expected at least 6 blink transitions with ~100ms intervals, got {len(blink_transitions)}" - ) - - # Verify timing between blink transitions - for i in range(1, min(6, len(blink_transitions))): - prev_ts = blink_transitions[i - 1][0] - curr_ts = blink_transitions[i][0] - interval = curr_ts - prev_ts - assert abs(interval - expected_interval_ns) < tolerance_ns, ( - f"Transition interval {interval / 1_000_000:.1f}ms deviates from " - f"expected {expected_interval_ns / 1_000_000:.1f}ms by more than " - f"{tolerance_ns / 1_000_000:.1f}ms tolerance" - ) - - # --- PTY Input Tests --- diff --git a/ports/zephyr-cp/tests/test_digitalio.py b/ports/zephyr-cp/tests/test_digitalio.py new file mode 100644 index 00000000000..22c64f7b83f --- /dev/null +++ b/ports/zephyr-cp/tests/test_digitalio.py @@ -0,0 +1,171 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries LLC +# SPDX-License-Identifier: MIT + +"""Test digitalio functionality on native_sim.""" + +import re +from pathlib import Path + +import pytest +from perfetto.trace_processor import TraceProcessor + + +DIGITALIO_INPUT_TRACE_READ_CODE = """\ +import time +import digitalio +import microcontroller + +pin = digitalio.DigitalInOut(microcontroller.pin.P_01) +pin.direction = digitalio.Direction.INPUT + +start = time.monotonic() +last = pin.value +print(f"t_abs={time.monotonic():.3f} initial={last}") + +# Poll long enough to observe a high pulse injected through input trace. +while time.monotonic() - start < 8.0: + value = pin.value + if value != last: + print(f"t_abs={time.monotonic():.3f} edge={value}") + last = value + time.sleep(0.05) + +print(f"t_abs={time.monotonic():.3f} done") +""" + + +DIGITALIO_INPUT_TRACE = { + "gpio_emul.01": [ + (8_000_000_000, 0), + (9_000_000_000, 1), + (10_000_000_000, 0), + ], +} + + +@pytest.mark.duration(14.0) +@pytest.mark.circuitpy_drive({"code.py": DIGITALIO_INPUT_TRACE_READ_CODE}) +@pytest.mark.input_trace(DIGITALIO_INPUT_TRACE) +def test_digitalio_reads_input_trace(circuitpython): + """Test DigitalInOut input reads values injected via input trace.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + + initial_match = re.search(r"t_abs=([0-9]+\.[0-9]+) initial=False", output) + edge_match = re.search(r"t_abs=([0-9]+\.[0-9]+) edge=True", output) + done_match = re.search(r"t_abs=([0-9]+\.[0-9]+) done", output) + + assert initial_match is not None + assert edge_match is not None + assert done_match is not None + + initial_abs = float(initial_match.group(1)) + edge_abs = float(edge_match.group(1)) + done_abs = float(done_match.group(1)) + + # Input trace edge is at 9.0s for gpio_emul.01. + assert 8.5 <= edge_abs <= 9.5 + assert initial_abs <= edge_abs <= done_abs + + +BLINK_CODE = """\ +import time +import board +import digitalio + +led = digitalio.DigitalInOut(board.LED) +led.direction = digitalio.Direction.OUTPUT + +for i in range(3): + print(f"LED on {i}") + led.value = True + time.sleep(0.1) + print(f"LED off {i}") + led.value = False + time.sleep(0.1) + +print("done") +""" + + +def parse_gpio_trace(trace_file: Path, pin_name: str = "gpio_emul.00") -> list[tuple[int, int]]: + """Parse GPIO trace from Perfetto trace file.""" + tp = TraceProcessor(file_path=str(trace_file)) + result = tp.query( + f''' + SELECT c.ts, c.value + FROM counter c + JOIN track t ON c.track_id = t.id + WHERE t.name = "{pin_name}" + ORDER BY c.ts + ''' + ) + return [(row.ts, int(row.value)) for row in result] + + +@pytest.mark.circuitpy_drive({"code.py": BLINK_CODE}) +def test_digitalio_blink_output(circuitpython): + """Test blink program produces expected output and GPIO traces.""" + circuitpython.wait_until_done() + + # Check serial output + output = circuitpython.serial.all_output + assert "LED on 0" in output + assert "LED off 0" in output + assert "LED on 2" in output + assert "LED off 2" in output + assert "done" in output + + # Check GPIO traces - LED is on gpio_emul.00 + gpio_trace = parse_gpio_trace(circuitpython.trace_file, "gpio_emul.00") + + # Deduplicate by timestamp (keep last value at each timestamp) + by_timestamp = {} + for ts, val in gpio_trace: + by_timestamp[ts] = val + sorted_trace = sorted(by_timestamp.items()) + + # Find transition points (where value changes), skipping initialization at ts=0 + transitions = [] + for i in range(1, len(sorted_trace)): + prev_ts, prev_val = sorted_trace[i - 1] + curr_ts, curr_val = sorted_trace[i] + if prev_val != curr_val and curr_ts > 0: + transitions.append((curr_ts, curr_val)) + + # We expect at least 6 transitions (3 on + 3 off) from the blink loop + assert len(transitions) >= 6, f"Expected at least 6 transitions, got {len(transitions)}" + + # Verify timing between consecutive transitions + # Each sleep is 0.1s = 100ms = 100,000,000 ns + expected_interval_ns = 100_000_000 + tolerance_ns = 20_000_000 # 20ms tolerance + + # Find a sequence of 6 consecutive transitions with ~100ms intervals (the blink loop) + # This filters out initialization and cleanup noise + blink_transitions = [] + for i in range(len(transitions) - 1): + interval = transitions[i + 1][0] - transitions[i][0] + if abs(interval - expected_interval_ns) < tolerance_ns: + if not blink_transitions: + blink_transitions.append(transitions[i]) + blink_transitions.append(transitions[i + 1]) + elif blink_transitions: + # Found end of blink sequence + break + + assert len(blink_transitions) >= 6, ( + f"Expected at least 6 blink transitions with ~100ms intervals, got {len(blink_transitions)}" + ) + + # Verify timing between blink transitions + for i in range(1, min(6, len(blink_transitions))): + prev_ts = blink_transitions[i - 1][0] + curr_ts = blink_transitions[i][0] + interval = curr_ts - prev_ts + assert abs(interval - expected_interval_ns) < tolerance_ns, ( + f"Transition interval {interval / 1_000_000:.1f}ms deviates from " + f"expected {expected_interval_ns / 1_000_000:.1f}ms by more than " + f"{tolerance_ns / 1_000_000:.1f}ms tolerance" + ) diff --git a/ports/zephyr-cp/tests/test_rotaryio.py b/ports/zephyr-cp/tests/test_rotaryio.py new file mode 100644 index 00000000000..e9a5c1913cb --- /dev/null +++ b/ports/zephyr-cp/tests/test_rotaryio.py @@ -0,0 +1,132 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries LLC +# SPDX-License-Identifier: MIT + +"""Test rotaryio functionality on native_sim.""" + +import pytest + + +ROTARY_CODE_5S = """\ +import time +import microcontroller +import rotaryio + +encoder = rotaryio.IncrementalEncoder(microcontroller.pin.P_01, microcontroller.pin.P_02) + +time.sleep(5.0) # Sleep long enough for trace events to complete +print(f"position={encoder.position}") +print("done") +""" + + +ROTARY_CODE_7S = """\ +import time +import microcontroller +import rotaryio + +encoder = rotaryio.IncrementalEncoder(microcontroller.pin.P_01, microcontroller.pin.P_02) + +time.sleep(7.0) # Sleep long enough for trace events to complete +print(f"position={encoder.position}") +print("done") +""" + + +CLOCKWISE_TRACE = { + "gpio_emul.01": [ + (4_000_000_000, 0), # 4.0s: initial state (low) + (4_100_000_000, 1), # 4.1s: A goes high (A leads) + (4_300_000_000, 0), # 4.3s: A goes low + ], + "gpio_emul.02": [ + (4_000_000_000, 0), # 4.0s: initial state (low) + (4_200_000_000, 1), # 4.2s: B goes high (B follows) + (4_400_000_000, 0), # 4.4s: B goes low + ], +} + +COUNTERCLOCKWISE_TRACE = { + "gpio_emul.01": [ + (4_000_000_000, 0), # 4.0s: initial state (low) + (4_200_000_000, 1), # 4.2s: A goes high (A follows) + (4_400_000_000, 0), # 4.4s: A goes low + ], + "gpio_emul.02": [ + (4_000_000_000, 0), # 4.0s: initial state (low) + (4_100_000_000, 1), # 4.1s: B goes high (B leads) + (4_300_000_000, 0), # 4.3s: B goes low + ], +} + +BOTH_DIRECTIONS_TRACE = { + "gpio_emul.01": [ + (4_000_000_000, 0), # Initial state + # First clockwise detent + (4_100_000_000, 1), # A rises (leads) + (4_300_000_000, 0), # A falls + # Second clockwise detent + (4_500_000_000, 1), # A rises (leads) + (4_700_000_000, 0), # A falls + # First counter-clockwise detent + (5_000_000_000, 1), # A rises (follows) + (5_200_000_000, 0), # A falls + # Second counter-clockwise detent + (5_400_000_000, 1), # A rises (follows) + (5_600_000_000, 0), # A falls + # Third counter-clockwise detent + (5_800_000_000, 1), # A rises (follows) + (6_000_000_000, 0), # A falls + ], + "gpio_emul.02": [ + (4_000_000_000, 0), # Initial state + # First clockwise detent + (4_200_000_000, 1), # B rises (follows) + (4_400_000_000, 0), # B falls + # Second clockwise detent + (4_600_000_000, 1), # B rises (follows) + (4_800_000_000, 0), # B falls + # First counter-clockwise detent + (4_900_000_000, 1), # B rises (leads) + (5_100_000_000, 0), # B falls + # Second counter-clockwise detent + (5_300_000_000, 1), # B rises (leads) + (5_500_000_000, 0), # B falls + # Third counter-clockwise detent + (5_700_000_000, 1), # B rises (leads) + (5_900_000_000, 0), # B falls + ], +} + + +@pytest.mark.circuitpy_drive({"code.py": ROTARY_CODE_5S}) +@pytest.mark.input_trace(CLOCKWISE_TRACE) +def test_rotaryio_incrementalencoder_clockwise(circuitpython): + """Test clockwise rotation increments position.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "position=1" in output + assert "done" in output + + +@pytest.mark.circuitpy_drive({"code.py": ROTARY_CODE_5S}) +@pytest.mark.input_trace(COUNTERCLOCKWISE_TRACE) +def test_rotaryio_incrementalencoder_counterclockwise(circuitpython): + """Test counter-clockwise rotation decrements position.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "position=-1" in output + assert "done" in output + + +@pytest.mark.duration(12.0) +@pytest.mark.circuitpy_drive({"code.py": ROTARY_CODE_7S}) +@pytest.mark.input_trace(BOTH_DIRECTIONS_TRACE) +def test_rotaryio_incrementalencoder_both_directions(circuitpython): + """Test rotation in both directions: 2 clockwise, then 3 counter-clockwise.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "position=-1" in output + assert "done" in output diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index a8b05fabd05..736cea31de1 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -8,6 +8,6 @@ manifest: path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: 3c5a3a72daa3ca6462cd8bc9c8c7c6a41fbf3b2e + revision: 8801b409ec554cfd217c159c00f91280ea1331db clone-depth: 100 import: true From 4f015eee197074feb983473765c23b81520c3412 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 24 Feb 2026 23:15:45 -0500 Subject: [PATCH 240/876] wip --- .../adafruit_metro_esp32s3/mpconfigboard.mk | 2 + shared-module/sdcardio/SDCard.c | 136 +++++++++++------- 2 files changed, 85 insertions(+), 53 deletions(-) diff --git a/ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk b/ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk index 2fd5a40f259..57ccf4a4074 100644 --- a/ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk @@ -12,3 +12,5 @@ CIRCUITPY_ESP_FLASH_SIZE = 16MB CIRCUITPY_ESP_PSRAM_MODE = opi CIRCUITPY_ESP_PSRAM_FREQ = 80m CIRCUITPY_ESP_PSRAM_SIZE = 8MB + +CIRCUITPY_ULAB = 0 diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index 878fed7a13c..f9b937686b7 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -7,7 +7,7 @@ // This implementation largely follows the structure of adafruit_sdcard.py #include "extmod/vfs.h" - +#include "esp_log.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/sdcardio/SDCard.h" @@ -23,7 +23,12 @@ #define DEBUG_PRINT(...) ((void)0) #endif -#define CMD_TIMEOUT (200) +// https://www.taterli.com/wp-content/uploads/2017/05/Physical-Layer-Simplified-SpecificationV6.0.pdf +// specifies timeouts for read (100 ms), write (250 ms), erase (depends on size), and other operations. +// But the document also suggests allowing 500 ms even if a shorter timeout is specified. +// So let's allow a nice long time, but don't wait in a tight loop: allow background tasks to run. +#define CMD_TIMEOUT_MS (500) +#define TIMEOUT_MS (500) #define R1_IDLE_STATE (1 << 0) #define R1_ILLEGAL_COMMAND (1 << 2) @@ -106,21 +111,38 @@ static uint8_t CRC7(const uint8_t *data, uint8_t n) { return (crc << 1) | 1; } -#define READY_TIMEOUT_NS (300 * 1000 * 1000) // 300ms -static int wait_for_ready(sdcardio_sdcard_obj_t *self) { - uint64_t deadline = common_hal_time_monotonic_ns() + READY_TIMEOUT_NS; - while (common_hal_time_monotonic_ns() < deadline) { +// Assumes that the spi lock has been acquired. +// +// Mask the incoming value with mask. Use 0xff to not mask. +// if not_match is true, wait for something NOT matching the value. +// Return the response as an int32_t (which is always >= 0), or -1 if timed out. +static int32_t wait_for_masked_response(sdcardio_sdcard_obj_t *self, uint8_t mask, uint8_t response, bool not_match, uint32_t timeout_ms) { + uint64_t deadline = supervisor_ticks_ms64() + timeout_ms; + while (supervisor_ticks_ms64() < deadline) { uint8_t b; common_hal_busio_spi_read(self->bus, &b, 1, 0xff); - if (b == 0xff) { - return 0; + if (((b & mask) == response) ^ not_match) { + return b; } + RUN_BACKGROUND_TASKS; } - return -ETIMEDOUT; + return -1; +} + +// Wait for the given response byte. +static bool wait_for_response(sdcardio_sdcard_obj_t *self, uint8_t response) { + return wait_for_masked_response(self, 0xff, response, false, TIMEOUT_MS) != -1; +} + +#define READY_TIMEOUT_MS (300) + +// Wait for 0xff, with a shorter timeout. +static bool wait_for_ready(sdcardio_sdcard_obj_t *self) { + return wait_for_masked_response(self, 0xff, 0xff, false, READY_TIMEOUT_MS) != -1; } // Note: this is never called while "in cmd25" (in fact, it's only used by `exit_cmd25`) -static int cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { +static mp_negative_errno_t cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { uint8_t cmdbuf[2] = {cmd, 0xff}; assert(!self->in_cmd25); @@ -128,17 +150,14 @@ static int cmd_nodata(sdcardio_sdcard_obj_t *self, int cmd, int response) { common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); // Wait for the response (response[7] == response) - for (int i = 0; i < CMD_TIMEOUT; i++) { - common_hal_busio_spi_read(self->bus, cmdbuf, 1, 0xff); - if (cmdbuf[0] == response) { - return 0; - } + if (wait_for_response(self, response)) { + return 0; } return -MP_EIO; } -static int exit_cmd25(sdcardio_sdcard_obj_t *self) { +static mp_negative_errno_t exit_cmd25(sdcardio_sdcard_obj_t *self) { if (self->in_cmd25) { DEBUG_PRINT("exit cmd25\n"); self->in_cmd25 = false; @@ -149,7 +168,7 @@ static int exit_cmd25(sdcardio_sdcard_obj_t *self) { // In Python API, defaults are response=None, data_block=True, wait=True static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf, size_t response_len, bool data_block, bool wait) { - int r = exit_cmd25(self); + mp_negative_errno_t r = exit_cmd25(self); if (r < 0) { return r; } @@ -164,25 +183,17 @@ static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf cmdbuf[5] = CRC7(cmdbuf, 5); if (wait) { - r = wait_for_ready(self); - if (r < 0) { - return r; + if (!wait_for_ready(self)) { + return -MP_ETIMEDOUT; } } common_hal_busio_spi_write(self->bus, cmdbuf, sizeof(cmdbuf)); // Wait for the response (response[7] == 0) - bool response_received = false; - for (int i = 0; i < CMD_TIMEOUT; i++) { - common_hal_busio_spi_read(self->bus, cmdbuf, 1, 0xff); - if ((cmdbuf[0] & 0x80) == 0) { - response_received = true; - break; - } - } - - if (!response_received) { + // Now wait for cmd response, which is the high bit being 0. + int32_t response = wait_for_masked_response(self, 0x80, 0, false, CMD_TIMEOUT_MS); + if (response == -1) { return -MP_EIO; } @@ -190,22 +201,25 @@ static int cmd(sdcardio_sdcard_obj_t *self, int cmd, int arg, void *response_buf if (data_block) { cmdbuf[1] = 0xff; - do { - // Wait for the start block byte - common_hal_busio_spi_read(self->bus, cmdbuf + 1, 1, 0xff); - } while (cmdbuf[1] != 0xfe); + if (!wait_for_response(self, 0xfe)) { + return -MP_EIO; + } } - common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff); + if (!common_hal_busio_spi_read(self->bus, response_buf, response_len, 0xff)) { + return -MP_EIO; + } if (data_block) { // Read and discard the CRC-CCITT checksum - common_hal_busio_spi_read(self->bus, cmdbuf + 1, 2, 0xff); + if (!common_hal_busio_spi_read(self->bus, cmdbuf + 1, 2, 0xff)) { + return -MP_EIO; + } } } - return cmdbuf[0]; + return response; } static int block_cmd(sdcardio_sdcard_obj_t *self, int cmd_, int block, void *response_buf, size_t response_len, bool data_block, bool wait) { @@ -213,16 +227,19 @@ static int block_cmd(sdcardio_sdcard_obj_t *self, int cmd_, int block, void *res } static mp_rom_error_text_t init_card_v1(sdcardio_sdcard_obj_t *self) { - for (int i = 0; i < CMD_TIMEOUT; i++) { + uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS; + while (supervisor_ticks_ms64() < deadline) { if (cmd(self, 41, 0, NULL, 0, true, true) == 0) { return NULL; } + RUN_BACKGROUND_TASKS; } return MP_ERROR_TEXT("timeout waiting for v1 card"); } static mp_rom_error_text_t init_card_v2(sdcardio_sdcard_obj_t *self) { - for (int i = 0; i < CMD_TIMEOUT; i++) { + uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS; + while (supervisor_ticks_ms64() < deadline) { uint8_t ocr[4]; common_hal_time_delay_ms(50); cmd(self, 58, 0, ocr, sizeof(ocr), false, true); @@ -234,6 +251,7 @@ static mp_rom_error_text_t init_card_v2(sdcardio_sdcard_obj_t *self) { } return NULL; } + RUN_BACKGROUND_TASKS; } return MP_ERROR_TEXT("timeout waiting for v2 card"); } @@ -250,6 +268,7 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { { bool reached_idle_state = false; for (int i = 0; i < 5; i++) { + ESP_LOGW("init_card", "loop: %d", i); // do not call cmd with wait=true, because that will return // prematurely if the idle state is not reached. we can't depend on // this when the card is not yet in SPI mode @@ -366,23 +385,25 @@ int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self) { } static int readinto(sdcardio_sdcard_obj_t *self, void *buf, size_t size) { - uint8_t aux[2] = {0, 0}; - while (aux[0] != 0xfe) { - common_hal_busio_spi_read(self->bus, aux, 1, 0xff); + + if (!wait_for_response(self, 0xfe)) { + return -MP_EIO; } common_hal_busio_spi_read(self->bus, buf, size, 0xff); // Read checksum and throw it away - common_hal_busio_spi_read(self->bus, aux, sizeof(aux), 0xff); + uint8_t checksum[2]; + common_hal_busio_spi_read(self->bus, checksum, sizeof(checksum), 0xff); return 0; } +// The mp_uint_t is misleading; negative errors can be returned. mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t start_block, uint32_t nblocks) { // deinit check is in lock_and_configure_bus() sdcardio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!lock_and_configure_bus(self)) { - return MP_EAGAIN; + return -MP_EAGAIN; } int r = 0; size_t buflen = 512 * nblocks; @@ -415,6 +436,7 @@ mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t st } } extraclock_and_unlock_bus(self); + // No caller actually uses this value. return r; } @@ -427,7 +449,9 @@ int common_hal_sdcardio_sdcard_readblocks(sdcardio_sdcard_obj_t *self, uint32_t } static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t size) { - wait_for_ready(self); + if (!wait_for_ready(self)) { + return -MP_ETIMEDOUT; + } uint8_t cmd[2]; cmd[0] = token; @@ -450,7 +474,8 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t // with STATUS 010 indicating "data accepted", and other status bit // combinations indicating failure. // In practice, I was seeing cmd[0] as 0xe5, indicating success - for (int i = 0; i < CMD_TIMEOUT; i++) { + uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS; + while (supervisor_ticks_ms64() < deadline) { common_hal_busio_spi_read(self->bus, cmd, 1, 0xff); DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]); if ((cmd[0] & 0b00010001) == 0b00000001) { @@ -460,12 +485,15 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t break; } } + RUN_BACKGROUND_TASKS; } // Wait for the write to finish - do { - common_hal_busio_spi_read(self->bus, cmd, 1, 0xff); - } while (cmd[0] == 0); + + // Wait for a non-zero value. + if (wait_for_masked_response(self, 0xff /*mask*/, 0, true /*not_match*/, TIMEOUT_MS) == -1) { + return -MP_EIO; + } // Success return 0; @@ -475,7 +503,7 @@ mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t s // deinit check is in lock_and_configure_bus() sdcardio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!lock_and_configure_bus(self)) { - return MP_EAGAIN; + return -MP_EAGAIN; } if (!self->in_cmd25 || start_block != self->next_block) { @@ -507,15 +535,17 @@ mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t s return 0; } -int common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) { +mp_negative_errno_t common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) { // deinit check is in lock_and_configure_bus() - lock_and_configure_bus(self); + if (!lock_and_configure_bus(self)) { + return -MP_EAGAIN; + } int r = exit_cmd25(self); extraclock_and_unlock_bus(self); return r; } -int common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { +mp_negative_errno_t common_hal_sdcardio_sdcard_writeblocks(sdcardio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *buf) { if (buf->len % 512 != 0) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512); } From 73aa39f23c87a9061422b02bf7177d0829df67d9 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 11 Feb 2026 10:18:28 -0800 Subject: [PATCH 241/876] Add networking support to the Zephyr native_sim It uses the host's sockets directly to test our zsock integration. This doesn't test network management. It does also test the web workflow. --- .gitignore | 4 + locale/circuitpython.pot | 5 +- ports/zephyr-cp/Makefile | 13 +- ports/zephyr-cp/README.md | 14 + .../bindings/hostnetwork/HostNetwork.c | 37 ++ .../bindings/hostnetwork/HostNetwork.h | 19 + .../zephyr-cp/bindings/hostnetwork/__init__.c | 26 + .../zephyr-cp/bindings/hostnetwork/__init__.h | 11 + ports/zephyr-cp/boards/frdm_rw612.conf | 1 + .../native/native_sim/autogen_board_info.toml | 5 +- .../nrf5340bsim/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/native_sim.conf | 16 + .../nordic/nrf5340dk/autogen_board_info.toml | 1 + .../nordic/nrf54h20dk/autogen_board_info.toml | 1 + .../nordic/nrf54l15dk/autogen_board_info.toml | 1 + .../nordic/nrf7002dk/autogen_board_info.toml | 3 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 1 + .../nxp/frdm_rw612/autogen_board_info.toml | 3 +- .../mimxrt1170_evk/autogen_board_info.toml | 1 + .../da14695_dk_usb/autogen_board_info.toml | 1 + .../renesas/ek_ra6m5/autogen_board_info.toml | 1 + .../renesas/ek_ra8d1/autogen_board_info.toml | 1 + .../nucleo_n657x0_q/autogen_board_info.toml | 1 + .../nucleo_u575zi_q/autogen_board_info.toml | 1 + .../st/stm32h7b3i_dk/autogen_board_info.toml | 1 + .../stm32wba65i_dk1/autogen_board_info.toml | 1 + .../common-hal/hostnetwork/HostNetwork.c | 15 + .../common-hal/hostnetwork/HostNetwork.h | 11 + .../zephyr-cp/common-hal/socketpool/Socket.c | 518 +++++++++--------- .../common-hal/socketpool/SocketPool.c | 178 +++--- .../common-hal/socketpool/SocketPool.h | 3 + .../zephyr-cp/cptools/build_circuitpython.py | 57 +- ports/zephyr-cp/cptools/zephyr2cp.py | 16 + ports/zephyr-cp/prj.conf | 16 +- ports/zephyr-cp/tests/conftest.py | 9 +- ports/zephyr-cp/tests/docs/web_workflow.md | 37 ++ ports/zephyr-cp/tests/test_web_workflow.py | 142 +++++ py/circuitpy_mpconfig.mk | 3 + shared-bindings/socketpool/SocketPool.c | 7 +- supervisor/shared/web_workflow/web_workflow.c | 137 +++-- supervisor/shared/web_workflow/web_workflow.h | 5 + supervisor/shared/workflow.c | 12 +- 42 files changed, 911 insertions(+), 425 deletions(-) create mode 100644 ports/zephyr-cp/bindings/hostnetwork/HostNetwork.c create mode 100644 ports/zephyr-cp/bindings/hostnetwork/HostNetwork.h create mode 100644 ports/zephyr-cp/bindings/hostnetwork/__init__.c create mode 100644 ports/zephyr-cp/bindings/hostnetwork/__init__.h create mode 100644 ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.c create mode 100644 ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.h create mode 100644 ports/zephyr-cp/tests/docs/web_workflow.md create mode 100644 ports/zephyr-cp/tests/test_web_workflow.py diff --git a/.gitignore b/.gitignore index 5b3b1db2d33..ca6872387dd 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,7 @@ TAGS # git-review-web outputs .review + +# Zephyr trace files +**/channel0_0 +**/*.perfetto-trace diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 48e0ab6fbfd..e2eebdea0fe 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -2067,10 +2067,13 @@ msgstr "" #: ports/espressif/common-hal/socketpool/SocketPool.c #: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c msgid "SocketPool can only be used with wifi.radio" msgstr "" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + #: shared-bindings/aesio/aes.c msgid "Source and destination buffers must be the same length" msgstr "" diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index c4feead23b9..5e320a32881 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,8 +8,7 @@ BUILD ?= build-$(BOARD) TRANSLATION ?= en_US - -.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug run clean menuconfig all clean-all test fetch-port-submodules +.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug run run-sim clean menuconfig all clean-all test fetch-port-submodules $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) @@ -36,6 +35,16 @@ debug: $(BUILD)/zephyr-cp/zephyr/zephyr.elf run: $(BUILD)/firmware.exe $^ +run-sim: + $(MAKE) BOARD=native_native_sim BUILD=build-native_native_sim build-native_native_sim/firmware.exe + truncate -s 2M build-native_native_sim/flash.bin + mformat -i build-native_native_sim/flash.bin :: + @if [ -d CIRCUITPY ] && [ -n "$$(find CIRCUITPY -mindepth 1 -print -quit)" ]; then \ + echo "Populating build-native_native_sim/flash.bin from ./CIRCUITPY"; \ + mcopy -s -i build-native_native_sim/flash.bin CIRCUITPY/* ::; \ + fi + build-native_native_sim/firmware.exe --flash=build-native_native_sim/flash.bin --flash_rm -wait_uart -rt + menuconfig: west build --sysbuild -d $(BUILD) -t menuconfig diff --git a/ports/zephyr-cp/README.md b/ports/zephyr-cp/README.md index 1fba1d7d3f7..f4391fc4cb6 100644 --- a/ports/zephyr-cp/README.md +++ b/ports/zephyr-cp/README.md @@ -28,6 +28,20 @@ make BOARD=nordic_nrf7002dk This uses Zephyr's cmake to generate Makefiles that then delegate to `tools/cpbuild/build_circuitpython.py` to build the CircuitPython bits in parallel. +## Running the native simulator + +From `ports/zephyr-cp`, run: + +```sh +make run-sim +``` + +`run-sim` starts the native simulator in realtime. +It prints the PTY path to connect to the simulator REPL. +If a local `./CIRCUITPY/` folder exists, its files are used as the simulator's CIRCUITPY drive. + +Edit files in `./CIRCUITPY` (for example `code.py`) and rerun `make run-sim` to test changes. + ## Testing other boards [Any Zephyr board](https://docs.zephyrproject.org/latest/boards/index.html#) can diff --git a/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.c b/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.c new file mode 100644 index 00000000000..fc0fb9ecc4f --- /dev/null +++ b/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.c @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/hostnetwork/HostNetwork.h" + +#include "py/runtime.h" + +//| class HostNetwork: +//| """Native networking for the host simulator.""" +//| +//| def __init__(self) -> None: +//| """Create a HostNetwork instance.""" +//| ... +//| +static mp_obj_t hostnetwork_hostnetwork_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, 0, false); + + hostnetwork_hostnetwork_obj_t *self = mp_obj_malloc(hostnetwork_hostnetwork_obj_t, &hostnetwork_hostnetwork_type); + common_hal_hostnetwork_hostnetwork_construct(self); + return MP_OBJ_FROM_PTR(self); +} + +static const mp_rom_map_elem_t hostnetwork_hostnetwork_locals_dict_table[] = { +}; +static MP_DEFINE_CONST_DICT(hostnetwork_hostnetwork_locals_dict, hostnetwork_hostnetwork_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + hostnetwork_hostnetwork_type, + MP_QSTR_HostNetwork, + MP_TYPE_FLAG_NONE, + make_new, hostnetwork_hostnetwork_make_new, + locals_dict, &hostnetwork_hostnetwork_locals_dict + ); diff --git a/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.h b/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.h new file mode 100644 index 00000000000..009d8c06087 --- /dev/null +++ b/ports/zephyr-cp/bindings/hostnetwork/HostNetwork.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +} hostnetwork_hostnetwork_obj_t; + +extern const mp_obj_type_t hostnetwork_hostnetwork_type; + +void common_hal_hostnetwork_hostnetwork_construct(hostnetwork_hostnetwork_obj_t *self); diff --git a/ports/zephyr-cp/bindings/hostnetwork/__init__.c b/ports/zephyr-cp/bindings/hostnetwork/__init__.c new file mode 100644 index 00000000000..92302b67d0e --- /dev/null +++ b/ports/zephyr-cp/bindings/hostnetwork/__init__.c @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" + +#include "bindings/hostnetwork/__init__.h" +#include "bindings/hostnetwork/HostNetwork.h" + +//| """Host networking support for the native simulator.""" +//| + +static const mp_rom_map_elem_t hostnetwork_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_hostnetwork) }, + { MP_ROM_QSTR(MP_QSTR_HostNetwork), MP_ROM_PTR(&hostnetwork_hostnetwork_type) }, +}; +static MP_DEFINE_CONST_DICT(hostnetwork_module_globals, hostnetwork_module_globals_table); + +const mp_obj_module_t hostnetwork_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&hostnetwork_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_hostnetwork, hostnetwork_module); diff --git a/ports/zephyr-cp/bindings/hostnetwork/__init__.h b/ports/zephyr-cp/bindings/hostnetwork/__init__.h new file mode 100644 index 00000000000..a6731546bde --- /dev/null +++ b/ports/zephyr-cp/bindings/hostnetwork/__init__.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "bindings/hostnetwork/HostNetwork.h" + +extern hostnetwork_hostnetwork_obj_t common_hal_hostnetwork_obj; diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf index 7f063218153..7d56dfed29c 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.conf +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -20,6 +20,7 @@ CONFIG_MBEDTLS_PKCS1_V15=y CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=y CONFIG_MBEDTLS_ENTROPY_C=y CONFIG_MBEDTLS_CTR_DRBG_ENABLED=y +CONFIG_MBEDTLS_SHA1=y CONFIG_MBEDTLS_USE_PSA_CRYPTO=n CONFIG_BT=y diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 73897f71620..3738e6494ec 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -49,7 +49,8 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true # Zephyr networking enabled +hostnetwork = true # Zephyr board has hostnetwork i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false @@ -87,7 +88,7 @@ rtc = false sdcardio = true # Zephyr board has busio sdioio = false sharpdisplay = true # Zephyr board has busio -socketpool = false +socketpool = true # Zephyr networking enabled spitarget = false ssl = false storage = true # Zephyr board has flash diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 9ddbb2153fb..aa2deb2b41c 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native_sim.conf index cc295949d03..ddbfef11266 100644 --- a/ports/zephyr-cp/boards/native_sim.conf +++ b/ports/zephyr-cp/boards/native_sim.conf @@ -18,3 +18,19 @@ CONFIG_I2C_EMUL=y CONFIG_EEPROM=y CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT2X_EMUL=y + +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_TCP=y +CONFIG_NET_SOCKETS=y +CONFIG_ETH_NATIVE_TAP=n +CONFIG_NET_DRIVERS=y +CONFIG_NET_SOCKETS_OFFLOAD=y +CONFIG_NET_NATIVE_OFFLOADED_SOCKETS=y +CONFIG_HEAP_MEM_POOL_SIZE=1024 + +CONFIG_NET_LOG=y + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_SHA1=y +CONFIG_MBEDTLS_SHA256=y diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 52beeda076f..8490d71d8f6 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 2759dfb89c1..333733d6b30 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 6df832f607b..10d03bf8578 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index d713552d87b..7d2bceb9691 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -49,7 +49,8 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true # Zephyr networking enabled +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 233796fc6f4..37091a344cc 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index f7ad0289cc7..3030dff3a6e 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -49,7 +49,8 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true # Zephyr networking enabled +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 4926b5c9a6c..9a5c4c54144 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index 77d93aa10f0..883bf6be466 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 2ea2cea90b7..b2097d011fc 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 3be48a8b72c..1686169fffb 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 4b9c1053f22..2e20a0db1b8 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index ec78a62f066..a542e756c62 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 24e44662e40..0088d60f018 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index e26084cc43e..f030ee7319e 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false diff --git a/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.c b/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.c new file mode 100644 index 00000000000..494b21cb02d --- /dev/null +++ b/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.c @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/hostnetwork/HostNetwork.h" + +hostnetwork_hostnetwork_obj_t common_hal_hostnetwork_obj = { + .base = { &hostnetwork_hostnetwork_type }, +}; + +void common_hal_hostnetwork_hostnetwork_construct(hostnetwork_hostnetwork_obj_t *self) { + (void)self; +} diff --git a/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.h b/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.h new file mode 100644 index 00000000000..a6731546bde --- /dev/null +++ b/ports/zephyr-cp/common-hal/hostnetwork/HostNetwork.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "bindings/hostnetwork/HostNetwork.h" + +extern hostnetwork_hostnetwork_obj_t common_hal_hostnetwork_obj; diff --git a/ports/zephyr-cp/common-hal/socketpool/Socket.c b/ports/zephyr-cp/common-hal/socketpool/Socket.c index 857526a12de..ca8ba419839 100644 --- a/ports/zephyr-cp/common-hal/socketpool/Socket.c +++ b/ports/zephyr-cp/common-hal/socketpool/Socket.c @@ -20,165 +20,104 @@ #include "supervisor/shared/tick.h" #include "supervisor/workflow.h" -#include - -// void socketpool_resolve_host_or_throw(int family, int type, const char *hostname, struct sockaddr_storage *addr, int port) { -// // struct addrinfo *result_i; -// // const struct addrinfo hints = { -// // .ai_family = family, -// // .ai_socktype = type, -// // }; -// // int error = socketpool_getaddrinfo_common(hostname, port, &hints, &result_i); -// if (true) { -// common_hal_socketpool_socketpool_raise_gaierror_noname(); -// } -// // memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage)); -// // lwip_freeaddrinfo(result_i); -// } - -// static void resolve_host_or_throw(socketpool_socket_obj_t *self, const char *hostname, struct sockaddr_storage *addr, int port) { -// socketpool_resolve_host_or_throw(self->family, self->type, hostname, addr, port); -// } - -// StackType_t socket_select_stack[2 * configMINIMAL_STACK_SIZE]; - -// /* Socket state table: -// * 0 := Closed (unused) -// * 1 := Open -// * 2 := Closing (remove from rfds) -// * Index into socket_fd_state is calculated from actual lwip fd. idx := fd - LWIP_SOCKET_OFFSET -// */ -// #define FDSTATE_CLOSED 0 -// #define FDSTATE_OPEN 1 -// #define FDSTATE_CLOSING 2 -// static uint8_t socket_fd_state[CONFIG_LWIP_MAX_SOCKETS]; +#include +#include +#include +#include +#include -// How long to wait between checks for a socket to connect. -#define SOCKET_CONNECT_POLL_INTERVAL_MS 100 +#include +#include -// static socketpool_socket_obj_t *user_socket[CONFIG_LWIP_MAX_SOCKETS]; -// StaticTask_t socket_select_task_buffer; -// TaskHandle_t socket_select_task_handle; -// static int socket_change_fd = -1; - -// static void socket_select_task(void *arg) { -// uint64_t signal; -// fd_set readfds; -// fd_set excptfds; - -// while (true) { -// FD_ZERO(&readfds); -// FD_ZERO(&excptfds); -// FD_SET(socket_change_fd, &readfds); -// int max_fd = socket_change_fd; -// for (size_t i = 0; i < MP_ARRAY_SIZE(socket_fd_state); i++) { -// if ((socket_fd_state[i] == FDSTATE_OPEN) && (user_socket[i] == NULL)) { -// int sockfd = i + LWIP_SOCKET_OFFSET; -// max_fd = MAX(max_fd, sockfd); -// FD_SET(sockfd, &readfds); -// FD_SET(sockfd, &excptfds); -// } -// } - -// int num_triggered = select(max_fd + 1, &readfds, NULL, &excptfds, NULL); -// // Hard error (or someone closed a socket on another thread) -// if (num_triggered == -1) { -// assert(errno == EBADF); -// continue; -// } - -// assert(num_triggered > 0); - -// // Notice event trigger -// if (FD_ISSET(socket_change_fd, &readfds)) { -// read(socket_change_fd, &signal, sizeof(signal)); -// num_triggered--; -// } - -// // Handle active FDs, close the dead ones -// for (size_t i = 0; i < MP_ARRAY_SIZE(socket_fd_state); i++) { -// int sockfd = i + LWIP_SOCKET_OFFSET; -// if (socket_fd_state[i] != FDSTATE_CLOSED) { -// if (FD_ISSET(sockfd, &readfds) || FD_ISSET(sockfd, &excptfds)) { -// if (socket_fd_state[i] == FDSTATE_CLOSING) { -// socket_fd_state[i] = FDSTATE_CLOSED; -// num_triggered--; -// } -// } -// } -// } - -// if (num_triggered > 0) { -// // Wake up CircuitPython by queuing request -// supervisor_workflow_request_background(); -// ulTaskNotifyTake(pdTRUE, portMAX_DELAY); -// } -// } - -// close(socket_change_fd); -// socket_change_fd = -1; -// vTaskDelete(NULL); -// } +#define SOCKETPOOL_IP_STR_LEN 48 -void socket_user_reset(void) { - // if (socket_change_fd < 0) { - // esp_vfs_eventfd_config_t config = ESP_VFS_EVENTD_CONFIG_DEFAULT(); - // ESP_ERROR_CHECK(esp_vfs_eventfd_register(&config)); - - // // Clear initial socket states - // for (size_t i = 0; i < MP_ARRAY_SIZE(socket_fd_state); i++) { - // socket_fd_state[i] = FDSTATE_CLOSED; - // user_socket[i] = NULL; - // } - // socket_change_fd = eventfd(0, 0); - // // Run this at the same priority as CP so that the web workflow background task can be - // // queued while CP is running. Both tasks can still sleep and, therefore, sleep overall. - // socket_select_task_handle = xTaskCreateStaticPinnedToCore(socket_select_task, - // "socket_select", - // 2 * configMINIMAL_STACK_SIZE, - // NULL, - // uxTaskPriorityGet(NULL), - // socket_select_stack, - // &socket_select_task_buffer, - // xPortGetCoreID()); - // } else { - // // Not init - close open user sockets - // for (size_t i = 0; i < MP_ARRAY_SIZE(socket_fd_state); i++) { - // if ((socket_fd_state[i] == FDSTATE_OPEN) && user_socket[i]) { - // common_hal_socketpool_socket_close(user_socket[i]); - // } - // } - // } +static mp_obj_t _format_address(const struct sockaddr *addr, int family) { + char ip_str[SOCKETPOOL_IP_STR_LEN]; + const struct sockaddr_in *a = (void *)addr; + + switch (family) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + case AF_INET6: + zsock_inet_ntop(family, &((const struct sockaddr_in6 *)a)->sin6_addr, ip_str, sizeof(ip_str)); + break; + #endif + default: + case AF_INET: + zsock_inet_ntop(family, &((const struct sockaddr_in *)a)->sin_addr, ip_str, sizeof(ip_str)); + break; + } + return mp_obj_new_str(ip_str, strlen(ip_str)); } -// Unblock select task (ok if not blocked yet) -void socketpool_socket_poll_resume(void) { - // if (socket_select_task_handle) { - // xTaskNotifyGive(socket_select_task_handle); - // } +static mp_obj_t _sockaddr_to_tuple(const struct sockaddr_storage *sockaddr) { + mp_obj_t args[4] = { + _format_address((const struct sockaddr *)sockaddr, sockaddr->ss_family), + }; + int n = 2; + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (sockaddr->ss_family == AF_INET6) { + const struct sockaddr_in6 *addr6 = (const void *)sockaddr; + args[1] = MP_OBJ_NEW_SMALL_INT(ntohs(addr6->sin6_port)); + args[2] = MP_OBJ_NEW_SMALL_INT(addr6->sin6_flowinfo); + args[3] = MP_OBJ_NEW_SMALL_INT(addr6->sin6_scope_id); + n = 4; + } else + #endif + { + const struct sockaddr_in *addr = (const void *)sockaddr; + args[1] = MP_OBJ_NEW_SMALL_INT(ntohs(addr->sin_port)); + } + return mp_obj_new_tuple(n, args); +} + +static void socketpool_resolve_host_or_throw(int family, int type, const char *hostname, struct sockaddr_storage *addr, int port) { + const struct zsock_addrinfo hints = { + .ai_family = family, + .ai_socktype = type, + }; + struct zsock_addrinfo *result_i = NULL; + char service_buf[6]; + + snprintf(service_buf, sizeof(service_buf), "%d", port); + + int error = zsock_getaddrinfo(hostname, service_buf, &hints, &result_i); + if (error != 0 || result_i == NULL) { + common_hal_socketpool_socketpool_raise_gaierror_noname(); + } + + memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage)); + zsock_freeaddrinfo(result_i); } -// The writes below send an event to the socket select task so that it redoes the -// select with the new open socket set. +static void resolve_host_or_throw(socketpool_socket_obj_t *self, const char *hostname, struct sockaddr_storage *addr, int port) { + socketpool_resolve_host_or_throw(self->family, self->type, hostname, addr, port); +} -// static bool register_open_socket(int fd) { -// if (fd < FD_SETSIZE) { -// socket_fd_state[fd - LWIP_SOCKET_OFFSET] = FDSTATE_OPEN; -// user_socket[fd - LWIP_SOCKET_OFFSET] = NULL; +// How long to wait between checks for a socket to connect. +#define SOCKET_CONNECT_POLL_INTERVAL_MS 100 -// uint64_t signal = 1; -// write(socket_change_fd, &signal, sizeof(signal)); -// socketpool_socket_poll_resume(); -// return true; -// } -// return false; -// } +void socket_user_reset(void) { + // User sockets are heap objects with __del__ bound to close(). + // During VM shutdown/reset, gc_sweep_all() runs finalizers, so sockets + // are closed there rather than being tracked and closed explicitly here. +} + +static struct k_work_delayable socketpool_poll_work; +static bool socketpool_poll_work_initialized; -// static void mark_user_socket(int fd, socketpool_socket_obj_t *obj) { -// socket_fd_state[fd - LWIP_SOCKET_OFFSET] = FDSTATE_OPEN; -// user_socket[fd - LWIP_SOCKET_OFFSET] = obj; -// // No need to wakeup select task -// } +static void socketpool_poll_work_handler(struct k_work *work) { + (void)work; + supervisor_workflow_request_background(); +} + +// Unblock select task (ok if not blocked yet) +void socketpool_socket_poll_resume(void) { + if (!socketpool_poll_work_initialized) { + k_work_init_delayable(&socketpool_poll_work, socketpool_poll_work_handler); + socketpool_poll_work_initialized = true; + } + k_work_schedule(&socketpool_poll_work, K_MSEC(10)); +} static bool _socketpool_socket(socketpool_socketpool_obj_t *self, socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type, @@ -212,16 +151,23 @@ static bool _socketpool_socket(socketpool_socketpool_obj_t *self, sock->pool = self; sock->timeout_ms = (uint)-1; - // Create LWIP socket - // int socknum = -1; - // socknum = lwip_socket(sock->family, sock->type, sock->ipproto); - // if (socknum < 0) { - // return false; - // } + int socknum = zsock_socket(sock->family, sock->type, sock->ipproto); + if (socknum < 0) { + return false; + } - // sock->num = socknum; - // // Sockets should be nonblocking in most cases - // lwip_fcntl(socknum, F_SETFL, O_NONBLOCK); + sock->num = socknum; + + // Enable address reuse by default to avoid bind failures on recently-used ports. + int reuseaddr = 1; + if (zsock_setsockopt(socknum, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)) < 0) { + // Ignore if SO_REUSEADDR is unsupported. + } + + // Sockets should be nonblocking in most cases. + if (zsock_fcntl(socknum, F_SETFL, O_NONBLOCK) < 0) { + // Ignore if non-blocking is unsupported. + } return true; } @@ -235,11 +181,6 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self, return false; } - // This shouldn't happen since we have room for the same number of sockets as LWIP. - // if (!register_open_socket(sock->num)) { - // lwip_close(sock->num); - // return false; - // } return true; } @@ -260,13 +201,12 @@ socketpool_socket_obj_t *common_hal_socketpool_socket(socketpool_socketpool_obj_ if (!_socketpool_socket(self, family, type, proto, sock)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Out of sockets")); } - // mark_user_socket(sock->num, sock); return sock; } int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, socketpool_socket_obj_t *accepted) { struct sockaddr_storage peer_addr; - // socklen_t socklen = sizeof(peer_addr); + socklen_t socklen = sizeof(peer_addr); int newsoc = -1; bool timed_out = false; uint64_t start_ticks = supervisor_ticks_ms64(); @@ -277,11 +217,23 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; } RUN_BACKGROUND_TASKS; - // newsoc = lwip_accept(self->num, (struct sockaddr *)&peer_addr, &socklen); + #if CIRCUITPY_HOSTNETWORK + if (self->timeout_ms == 0) { + struct zsock_timeval tv = { + .tv_sec = 0, + .tv_usec = 1000, + }; + zsock_setsockopt(self->num, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); + } + #endif + newsoc = zsock_accept(self->num, (struct sockaddr *)&peer_addr, &socklen); // In non-blocking mode, fail instead of timing out if (newsoc == -1 && (self->timeout_ms == 0 || mp_hal_is_interrupted())) { return -MP_EAGAIN; } + if (newsoc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { + return -errno; + } } if (timed_out) { @@ -293,18 +245,14 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, } // We got a socket. New client socket will not be non-blocking by default, so make it non-blocking. - // lwip_fcntl(newsoc, F_SETFL, O_NONBLOCK); + if (zsock_fcntl(newsoc, F_SETFL, O_NONBLOCK) < 0) { + // Ignore if non-blocking is unsupported. + } if (accepted != NULL) { // Error if called with open socket object. assert(common_hal_socketpool_socket_get_closed(accepted)); - // Register if system socket - // if (!register_open_socket(newsoc)) { - // lwip_close(newsoc); - // return -MP_EBADF; - // } - // Replace the old accepted socket with the new one. accepted->num = newsoc; accepted->pool = self->pool; @@ -313,7 +261,7 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, } if (peer_out) { - *peer_out = sockaddr_to_tuple(&peer_addr); + *peer_out = _sockaddr_to_tuple(&peer_addr); } return newsoc; @@ -327,7 +275,6 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o if (newsoc > 0) { // Create the socket - // mark_user_socket(newsoc, sock); sock->base.type = &socketpool_socket_type; sock->num = newsoc; sock->pool = self->pool; @@ -343,40 +290,42 @@ socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_o size_t common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port) { - // struct sockaddr_storage bind_addr; + struct sockaddr_storage bind_addr; const char *broadcast = ""; + uint32_t local_port = port; - // bind_addr.ss_family = self->family; + memset(&bind_addr, 0, sizeof(bind_addr)); + bind_addr.ss_family = self->family; #if CIRCUITPY_SOCKETPOOL_IPV6 if (self->family == AF_INET6) { struct sockaddr_in6 *addr6 = (void *)&bind_addr; - addr6->sin6_port = htons(port); + addr6->sin6_port = htons(local_port); // no ipv6 broadcast if (hostlen == 0) { memset(&addr6->sin6_addr, 0, sizeof(addr6->sin6_addr)); } else { - socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, port); + socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, local_port); } } else #endif { - // struct sockaddr_in *addr4 = (void *)&bind_addr; - // addr4->sin_port = htons(port); + struct sockaddr_in *addr4 = (void *)&bind_addr; + addr4->sin_port = htons(local_port); if (hostlen == 0) { - // addr4->sin_addr.s_addr = IPADDR_ANY; + addr4->sin_addr.s_addr = htonl(INADDR_ANY); } else if (hostlen == strlen(broadcast) && memcmp(host, broadcast, strlen(broadcast)) == 0) { - // addr4->sin_addr.s_addr = IPADDR_BROADCAST; + addr4->sin_addr.s_addr = htonl(INADDR_BROADCAST); } else { - // socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, port); + socketpool_resolve_host_or_throw(self->family, self->type, host, &bind_addr, local_port); } } - // int result = lwip_bind(self->num, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); - // if (result == 0) { - // return 0; - // } + int result = zsock_bind(self->num, (struct sockaddr *)&bind_addr, sizeof(bind_addr)); + if (result == 0) { + return 0; + } return errno; } @@ -390,20 +339,11 @@ void socketpool_socket_close(socketpool_socket_obj_t *self) { } #endif self->connected = false; - // int fd = self->num; - // Ignore bogus/closed sockets - // if (fd >= LWIP_SOCKET_OFFSET) { - // if (user_socket[fd - LWIP_SOCKET_OFFSET] == NULL) { - // socket_fd_state[fd - LWIP_SOCKET_OFFSET] = FDSTATE_CLOSING; - // lwip_shutdown(fd, SHUT_RDWR); - // lwip_close(fd); - // } else { - // lwip_shutdown(fd, SHUT_RDWR); - // lwip_close(fd); - // socket_fd_state[fd - LWIP_SOCKET_OFFSET] = FDSTATE_CLOSED; - // user_socket[fd - LWIP_SOCKET_OFFSET] = NULL; - // } - // } + int fd = self->num; + if (fd >= 0) { + zsock_shutdown(fd, ZSOCK_SHUT_RDWR); + zsock_close(fd); + } self->num = -1; } @@ -413,16 +353,11 @@ void common_hal_socketpool_socket_close(socketpool_socket_obj_t *self) { void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port) { - // struct sockaddr_storage addr; - // resolve_host_or_throw(self, host, &addr, port); - - // Replace above with function call ----- - - // Emulate SO_CONTIMEO, which is not implemented by lwip. - // All our sockets are non-blocking, so we check the timeout ourselves. + (void)hostlen; + struct sockaddr_storage addr; + resolve_host_or_throw(self, host, &addr, port); - int result = -1; - // result = lwip_connect(self->num, (struct sockaddr *)&addr, addr.s2_len); + int result = zsock_connect(self->num, (struct sockaddr *)&addr, sizeof(addr)); if (result == 0) { // Connected immediately. @@ -436,12 +371,7 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, return; } - // struct timeval timeout = { - // .tv_sec = 0, - // .tv_usec = SOCKET_CONNECT_POLL_INTERVAL_MS * 1000, - // }; - - // Keep checking, using select(), until timeout expires, at short intervals. + // Keep checking, using poll(), until timeout expires, at short intervals. // This allows ctrl-C interrupts to be detected and background tasks to run. mp_uint_t timeout_left = self->timeout_ms; @@ -452,14 +382,22 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, return; } - // fd_set fds; - // FD_ZERO(&fds); - // FD_SET(self->num, &fds); + struct zsock_pollfd fd = { + .fd = self->num, + .events = ZSOCK_POLLOUT, + }; + int poll_timeout = SOCKET_CONNECT_POLL_INTERVAL_MS; + if (self->timeout_ms == (uint)-1) { + poll_timeout = -1; + } else if (timeout_left < SOCKET_CONNECT_POLL_INTERVAL_MS) { + poll_timeout = timeout_left; + } - // result = select(self->num + 1, NULL, &fds, NULL, &timeout); + result = zsock_poll(&fd, 1, poll_timeout); if (result == 0) { - // No change to fd's after waiting for timeout, so try again if some time is still left. - // Don't wrap below 0, because we're using a uint. + if (self->timeout_ms == (uint)-1) { + continue; + } if (timeout_left < SOCKET_CONNECT_POLL_INTERVAL_MS) { timeout_left = 0; } else { @@ -469,16 +407,14 @@ void common_hal_socketpool_socket_connect(socketpool_socket_obj_t *self, } if (result < 0) { - // Some error happened when doing select(); error is in errno. mp_raise_OSError(errno); } - // select() indicated the socket is writable. Check if any connection error occurred. int error_code = 0; - // socklen_t socklen = sizeof(error_code); - // result = getsockopt(self->num, SOL_SOCKET, SO_ERROR, &error_code, &socklen); + socklen_t socklen = sizeof(error_code); + result = zsock_getsockopt(self->num, SOL_SOCKET, SO_ERROR, &error_code, &socklen); if (result < 0 || error_code != 0) { - mp_raise_OSError(errno); + mp_raise_OSError(error_code != 0 ? error_code : errno); } self->connected = true; return; @@ -498,17 +434,15 @@ bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t *self) { } bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int backlog) { - // return lwip_listen(self->num, backlog) == 0; - return false; + return zsock_listen(self->num, backlog) == 0; } mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *self, uint8_t *buf, uint32_t len, mp_obj_t *source_out) { - // struct sockaddr_storage source_addr; - // socklen_t socklen = sizeof(source_addr); + struct sockaddr_storage source_addr; + socklen_t socklen = sizeof(source_addr); - // LWIP Socket uint64_t start_ticks = supervisor_ticks_ms64(); int received = -1; bool timed_out = false; @@ -519,11 +453,18 @@ mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *se timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; } RUN_BACKGROUND_TASKS; - // received = lwip_recvfrom(self->num, buf, len, 0, (struct sockaddr *)&source_addr, &socklen); + received = zsock_recvfrom(self->num, buf, len, ZSOCK_MSG_DONTWAIT, (struct sockaddr *)&source_addr, &socklen); - // In non-blocking mode, fail instead of looping - if (received == -1 && self->timeout_ms == 0) { - mp_raise_OSError(MP_EAGAIN); + if (received < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + mp_raise_OSError(errno); + } + + if (received == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + // In non-blocking mode, fail instead of looping + if (self->timeout_ms == 0) { + mp_raise_OSError(MP_EAGAIN); + } + continue; } } @@ -537,7 +478,7 @@ mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *se } if (source_out) { - // *source_out = sockaddr_to_tuple(&source_addr); + *source_out = _sockaddr_to_tuple(&source_addr); } return received; @@ -549,7 +490,6 @@ int socketpool_socket_recv_into(socketpool_socket_obj_t *self, bool timed_out = false; if (self->num != -1) { - // LWIP Socket uint64_t start_ticks = supervisor_ticks_ms64(); received = -1; while (received == -1 && @@ -558,7 +498,16 @@ int socketpool_socket_recv_into(socketpool_socket_obj_t *self, timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; } RUN_BACKGROUND_TASKS; - // received = lwip_recv(self->num, (void *)buf, len, 0); + received = zsock_recv(self->num, (void *)buf, len, ZSOCK_MSG_DONTWAIT); + if (received < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + return -errno; + } + if (received < 1 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + if (self->timeout_ms == 0) { + return -MP_EAGAIN; + } + continue; + } // In non-blocking mode, fail instead of looping if (received < 1 && self->timeout_ms == 0) { if ((received == 0) || (errno == ENOTCONN)) { @@ -597,9 +546,7 @@ mp_uint_t common_hal_socketpool_socket_recv_into(socketpool_socket_obj_t *self, int socketpool_socket_send(socketpool_socket_obj_t *self, const uint8_t *buf, uint32_t len) { int sent = -1; if (self->num != -1) { - // LWIP Socket - // TODO: deal with potential failure/add timeout? - // sent = lwip_send(self->num, buf, len, 0); + sent = zsock_send(self->num, buf, len, 0); } else { sent = -MP_EBADF; } @@ -626,15 +573,15 @@ mp_uint_t common_hal_socketpool_socket_send(socketpool_socket_obj_t *self, const mp_uint_t common_hal_socketpool_socket_sendto(socketpool_socket_obj_t *self, const char *host, size_t hostlen, uint32_t port, const uint8_t *buf, uint32_t len) { - // struct sockaddr_storage addr; - // resolve_host_or_throw(self, host, &addr, port); + (void)hostlen; + struct sockaddr_storage addr; + resolve_host_or_throw(self, host, &addr, port); - // int bytes_sent = lwip_sendto(self->num, buf, len, 0, (struct sockaddr *)&addr, addr.s2_len); - // if (bytes_sent < 0) { - // mp_raise_BrokenPipeError(); - // return 0; - // } - int bytes_sent = 0; + int bytes_sent = zsock_sendto(self->num, buf, len, 0, (struct sockaddr *)&addr, sizeof(addr)); + if (bytes_sent < 0) { + mp_raise_BrokenPipeError(); + return 0; + } return bytes_sent; } @@ -648,7 +595,44 @@ mp_int_t common_hal_socketpool_socket_get_type(socketpool_socket_obj_t *self) { int common_hal_socketpool_socket_setsockopt(socketpool_socket_obj_t *self, int level, int optname, const void *value, size_t optlen) { - int err = 0; // lwip_setsockopt(self->num, level, optname, value, optlen); + int zephyr_level = level; + int zephyr_optname = optname; + + switch (level) { + case SOCKETPOOL_SOL_SOCKET: + zephyr_level = SOL_SOCKET; + break; + case SOCKETPOOL_IPPROTO_IP: + zephyr_level = IPPROTO_IP; + break; + case SOCKETPOOL_IPPROTO_TCP: + zephyr_level = IPPROTO_TCP; + break; + case SOCKETPOOL_IPPROTO_UDP: + zephyr_level = IPPROTO_UDP; + break; + #if CIRCUITPY_SOCKETPOOL_IPV6 + case SOCKETPOOL_IPPROTO_IPV6: + zephyr_level = IPPROTO_IPV6; + break; + #endif + } + + if (zephyr_level == SOL_SOCKET) { + switch (optname) { + case SOCKETPOOL_SO_REUSEADDR: + zephyr_optname = SO_REUSEADDR; + break; + } + } else if (zephyr_level == IPPROTO_TCP) { + switch (optname) { + case SOCKETPOOL_TCP_NODELAY: + zephyr_optname = TCP_NODELAY; + break; + } + } + + int err = zsock_setsockopt(self->num, zephyr_level, zephyr_optname, value, optlen); if (err != 0) { return -errno; } @@ -656,29 +640,23 @@ int common_hal_socketpool_socket_setsockopt(socketpool_socket_obj_t *self, int l } bool common_hal_socketpool_readable(socketpool_socket_obj_t *self) { - // struct timeval immediate = {0, 0}; + struct zsock_pollfd fd = { + .fd = self->num, + .events = ZSOCK_POLLIN, + }; - // fd_set fds; - // FD_ZERO(&fds); - // FD_SET(self->num, &fds); - // int num_triggered = select(self->num + 1, &fds, NULL, &fds, &immediate); - - // including returning true in the error case - // return num_triggered != 0; - return false; + int num_triggered = zsock_poll(&fd, 1, 0); + return num_triggered > 0; } bool common_hal_socketpool_writable(socketpool_socket_obj_t *self) { - // struct timeval immediate = {0, 0}; - - // fd_set fds; - // FD_ZERO(&fds); - // FD_SET(self->num, &fds); - // int num_triggered = select(self->num + 1, NULL, &fds, &fds, &immediate); + struct zsock_pollfd fd = { + .fd = self->num, + .events = ZSOCK_POLLOUT, + }; - // including returning true in the error case - // return num_triggered != 0; - return false; + int num_triggered = zsock_poll(&fd, 1, 0); + return num_triggered > 0; } void socketpool_socket_move(socketpool_socket_obj_t *self, socketpool_socket_obj_t *sock) { diff --git a/ports/zephyr-cp/common-hal/socketpool/SocketPool.c b/ports/zephyr-cp/common-hal/socketpool/SocketPool.c index 4531c5bf1b7..c9a3f008321 100644 --- a/ports/zephyr-cp/common-hal/socketpool/SocketPool.c +++ b/ports/zephyr-cp/common-hal/socketpool/SocketPool.c @@ -8,114 +8,116 @@ #include "common-hal/socketpool/Socket.h" #include "py/runtime.h" +#if CIRCUITPY_HOSTNETWORK +#include "bindings/hostnetwork/__init__.h" +#endif +#if CIRCUITPY_WIFI #include "shared-bindings/wifi/__init__.h" +#endif #include "common-hal/socketpool/__init__.h" +#include +#include + +#include + void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *self, mp_obj_t radio) { - if (radio != MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj)) { - mp_raise_ValueError(MP_ERROR_TEXT("SocketPool can only be used with wifi.radio")); + bool is_wifi = false; + #if CIRCUITPY_WIFI + is_wifi = radio == MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj); + #endif + bool is_hostnetwork = false; + #if CIRCUITPY_HOSTNETWORK + is_hostnetwork = mp_obj_is_type(radio, &hostnetwork_hostnetwork_type); + #endif + if (!(is_wifi || is_hostnetwork)) { + mp_raise_ValueError(MP_ERROR_TEXT("SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork")); } } // common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking. -// int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) { -// // As of 2022, the version of lwip in esp-idf does not handle the -// // trailing-dot syntax of domain names, so emulate it. -// // Remove this once https://github.com/espressif/esp-idf/issues/10013 has -// // been implemented -// if (host) { -// size_t strlen_host = strlen(host); -// if (strlen_host && host[strlen_host - 1] == '.') { -// mp_obj_t nodot = mp_obj_new_str(host, strlen_host - 1); -// host = mp_obj_str_get_str(nodot); -// } -// } - -// // char service_buf[6]; -// // snprintf(service_buf, sizeof(service_buf), "%d", service); - -// // return lwip_getaddrinfo(host, service_buf, hints, res); -// return 0; -// } - -// static mp_obj_t format_address(const struct sockaddr *addr, int family) { -// char ip_str[IPADDR_STRLEN_MAX]; // big enough for any supported address type -// const struct sockaddr_in *a = (void *)addr; - -// switch (family) { -// #if CIRCUITPY_SOCKETPOOL_IPV6 -// case AF_INET6: -// inet_ntop(family, &((const struct sockaddr_in6 *)a)->sin6_addr, ip_str, sizeof(ip_str)); -// break; -// #endif -// default: -// case AF_INET: -// inet_ntop(family, &((const struct sockaddr_in *)a)->sin_addr, ip_str, sizeof(ip_str)); -// break; -// } -// return mp_obj_new_str(ip_str, strlen(ip_str)); -// } - -// static mp_obj_t convert_sockaddr(const struct addrinfo *ai, int port) { -// #if CIRCUITPY_SOCKETPOOL_IPV6 -// mp_int_t n_tuple = ai->ai_family == AF_INET6 ? 4 : 2; -// #else -// mp_int_t n_tuple = 2; -// #endif -// mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_tuple, NULL)); -// result->items[0] = format_address(ai->ai_addr, ai->ai_family); -// result->items[1] = MP_OBJ_NEW_SMALL_INT(port); -// #if CIRCUITPY_SOCKETPOOL_IPV6 -// if (ai->ai_family == AF_INET6) { -// const struct sockaddr_in6 *ai6 = (void *)ai->ai_addr; -// result->items[2] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_flowinfo); -// result->items[3] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_scope_id); -// } -// #endif -// return result; -// } - -// static mp_obj_t convert_addrinfo(const struct addrinfo *ai, int port) { -// MP_STATIC_ASSERT(AF_INET == SOCKETPOOL_AF_INET); -// #if CIRCUITPY_SOCKETPOOL_IPV6 -// MP_STATIC_ASSERT(AF_INET6 == SOCKETPOOL_AF_INET6); -// #endif -// // MP_STATIC_ASSERT(AF_UNSPEC == SOCKETPOOL_AF_UNSPEC); -// mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); -// result->items[0] = MP_OBJ_NEW_SMALL_INT(ai->ai_family); -// result->items[1] = MP_OBJ_NEW_SMALL_INT(ai->ai_socktype); -// result->items[2] = MP_OBJ_NEW_SMALL_INT(ai->ai_protocol); -// result->items[3] = ai->ai_canonname ? mp_obj_new_str(ai->ai_canonname, strlen(ai->ai_canonname)) : MP_OBJ_NEW_QSTR(MP_QSTR_); -// result->items[4] = convert_sockaddr(ai, port); -// return result; -// } +static int socketpool_getaddrinfo_common(const char *host, int service, const struct zsock_addrinfo *hints, struct zsock_addrinfo **res) { + char service_buf[6]; + snprintf(service_buf, sizeof(service_buf), "%d", service); + + return zsock_getaddrinfo(host, service_buf, hints, res); +} + +#define SOCKETPOOL_IP_STR_LEN 48 + +static mp_obj_t format_address(const struct sockaddr *addr, int family) { + char ip_str[SOCKETPOOL_IP_STR_LEN]; + const struct sockaddr_in *a = (void *)addr; + + switch (family) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + case AF_INET6: + zsock_inet_ntop(family, &((const struct sockaddr_in6 *)a)->sin6_addr, ip_str, sizeof(ip_str)); + break; + #endif + default: + case AF_INET: + zsock_inet_ntop(family, &((const struct sockaddr_in *)a)->sin_addr, ip_str, sizeof(ip_str)); + break; + } + return mp_obj_new_str(ip_str, strlen(ip_str)); +} + +static mp_obj_t convert_sockaddr(const struct zsock_addrinfo *ai, int port) { + #if CIRCUITPY_SOCKETPOOL_IPV6 + mp_int_t n_tuple = ai->ai_family == AF_INET6 ? 4 : 2; + #else + mp_int_t n_tuple = 2; + #endif + mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(n_tuple, NULL)); + result->items[0] = format_address(ai->ai_addr, ai->ai_family); + result->items[1] = MP_OBJ_NEW_SMALL_INT(port); + #if CIRCUITPY_SOCKETPOOL_IPV6 + if (ai->ai_family == AF_INET6) { + const struct sockaddr_in6 *ai6 = (void *)ai->ai_addr; + result->items[2] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_flowinfo); + result->items[3] = MP_OBJ_NEW_SMALL_INT(ai6->sin6_scope_id); + } + #endif + return result; +} + +static mp_obj_t convert_addrinfo(const struct zsock_addrinfo *ai, int port) { + mp_obj_tuple_t *result = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL)); + result->items[0] = MP_OBJ_NEW_SMALL_INT(ai->ai_family); + result->items[1] = MP_OBJ_NEW_SMALL_INT(ai->ai_socktype); + result->items[2] = MP_OBJ_NEW_SMALL_INT(ai->ai_protocol); + result->items[3] = ai->ai_canonname ? mp_obj_new_str(ai->ai_canonname, strlen(ai->ai_canonname)) : MP_OBJ_NEW_QSTR(MP_QSTR_); + result->items[4] = convert_sockaddr(ai, port); + return result; +} mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags) { - // const struct addrinfo hints = { - // .ai_flags = flags, - // .ai_family = family, - // .ai_protocol = proto, - // .ai_socktype = type, - // }; - - // struct addrinfo *res = NULL; - // int err = socketpool_getaddrinfo_common(host, port, &hints, &res); - if (true) { + const struct zsock_addrinfo hints = { + .ai_flags = flags, + .ai_family = family, + .ai_protocol = proto, + .ai_socktype = type, + }; + + struct zsock_addrinfo *res = NULL; + int err = socketpool_getaddrinfo_common(host, port, &hints, &res); + if (err != 0 || res == NULL) { common_hal_socketpool_socketpool_raise_gaierror_noname(); } nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { mp_obj_t result = mp_obj_new_list(0, NULL); - // for (struct addrinfo *ai = res; ai; ai = ai->ai_next) { - // mp_obj_list_append(result, convert_addrinfo(ai, port)); - // } + for (struct zsock_addrinfo *ai = res; ai; ai = ai->ai_next) { + mp_obj_list_append(result, convert_addrinfo(ai, port)); + } nlr_pop(); - // lwip_freeaddrinfo(res); + zsock_freeaddrinfo(res); return result; } else { - // lwip_freeaddrinfo(res); + zsock_freeaddrinfo(res); nlr_raise(MP_OBJ_FROM_PTR(nlr.ret_val)); } } diff --git a/ports/zephyr-cp/common-hal/socketpool/SocketPool.h b/ports/zephyr-cp/common-hal/socketpool/SocketPool.h index 64f91e01e1c..7891a8b8e48 100644 --- a/ports/zephyr-cp/common-hal/socketpool/SocketPool.h +++ b/ports/zephyr-cp/common-hal/socketpool/SocketPool.h @@ -6,6 +6,9 @@ #pragma once +#include +#include + #include "py/obj.h" typedef struct { diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 3a007661c77..51521e913ab 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -224,6 +224,20 @@ async def generate_display_resources(output_path, translation, font, extra_chara ) +async def generate_web_workflow_static(output_path, static_files): + await cpbuild.run_command( + [ + "python", + srcdir / "tools" / "gen_web_workflow_static.py", + "--output_c_file", + output_path, + *static_files, + ], + srcdir, + check_hash=[output_path], + ) + + def determine_enabled_modules(board_info, portdir, srcdir): """Determine which CircuitPython modules should be enabled based on board capabilities. @@ -246,10 +260,16 @@ def determine_enabled_modules(board_info, portdir, srcdir): enabled_modules.add("storage") module_reasons["storage"] = "Zephyr board has flash" - if "wifi" in enabled_modules: + network_enabled = board_info.get("wifi", False) or board_info.get("hostnetwork", False) + + if network_enabled: enabled_modules.add("socketpool") - enabled_modules.add("ssl") module_reasons["socketpool"] = "Zephyr networking enabled" + enabled_modules.add("hashlib") + module_reasons["hashlib"] = "Zephyr networking enabled" + + if board_info.get("wifi", False) or board_info.get("ethernet", False): + enabled_modules.add("ssl") module_reasons["ssl"] = "Zephyr networking enabled" for port_module in (portdir / "bindings").iterdir(): @@ -296,6 +316,9 @@ async def build_circuitpython(): lto = cmake_args.get("LTO", "n") == "y" circuitpython_flags.append(f"-DCIRCUITPY_ENABLE_MPY_NATIVE={1 if enable_mpy_native else 0}") circuitpython_flags.append(f"-DCIRCUITPY_FULL_BUILD={1 if full_build else 0}") + circuitpython_flags.append(f"-DCIRCUITPY_SETTINGS_TOML={1 if full_build else 0}") + circuitpython_flags.append(f"-DCIRCUITPY_OS_GETENV={1 if full_build else 0}") + circuitpython_flags.append("-DCIRCUITPY_STATUS_BAR=1") circuitpython_flags.append(f"-DCIRCUITPY_USB_HOST={1 if usb_host else 0}") circuitpython_flags.append(f"-DCIRCUITPY_BOARD_ID='\"{board}\"'") circuitpython_flags.append(f"-DCIRCUITPY_TRANSLATE_OBJECT={1 if lto else 0}") @@ -352,7 +375,10 @@ async def build_circuitpython(): enabled_modules, module_reasons = determine_enabled_modules(board_info, portdir, srcdir) + web_workflow_enabled = board_info.get("wifi", False) or board_info.get("hostnetwork", False) + circuitpython_flags.extend(board_info["cflags"]) + circuitpython_flags.append(f"-DCIRCUITPY_WEB_WORKFLOW={1 if web_workflow_enabled else 0}") supervisor_source = [ "main.c", "extmod/modjson.c", @@ -387,8 +413,8 @@ async def build_circuitpython(): supervisor_source.extend(top.glob("supervisor/shared/*.c")) supervisor_source.append(top / "supervisor/shared/bluetooth/bluetooth.c") supervisor_source.append(top / "supervisor/shared/translate/translate.c") - # if web_workflow: - # supervisor_source.extend(top.glob("supervisor/shared/web_workflow/*.c")) + if web_workflow_enabled: + supervisor_source.extend(top.glob("supervisor/shared/web_workflow/*.c")) usb_ok = board_info.get("usb_device", False) circuitpython_flags.append(f"-DCIRCUITPY_USB_DEVICE={1 if usb_ok else 0}") @@ -416,10 +442,22 @@ async def build_circuitpython(): (portdir / "supervisor/usb.c", srcdir / "supervisor/shared/usb.c") ) + creator_id = mpconfigboard.get("CIRCUITPY_CREATOR_ID", mpconfigboard.get("USB_VID")) + creation_id = mpconfigboard.get("CIRCUITPY_CREATION_ID", mpconfigboard.get("USB_PID")) + if creator_id is not None: + circuitpython_flags.append(f"-DCIRCUITPY_CREATOR_ID=0x{creator_id:08x}") + if creation_id is not None: + circuitpython_flags.append(f"-DCIRCUITPY_CREATION_ID=0x{creation_id:08x}") + # Always use port serial. It'll switch between USB and UART automatically. circuitpython_flags.append("-DCIRCUITPY_PORT_SERIAL=1") - if "ssl" in enabled_modules: + if "hashlib" in enabled_modules: + circuitpython_flags.append("-DCIRCUITPY_HASHLIB_MBEDTLS=1") + if "ssl" not in enabled_modules: + circuitpython_flags.append("-DCIRCUITPY_HASHLIB_MBEDTLS_ONLY=1") + + if "ssl" in enabled_modules or "hashlib" in enabled_modules: # TODO: Figure out how to get these paths from zephyr circuitpython_flags.append("-DMBEDTLS_CONFIG_FILE='\"config-mbedtls.h\"'") circuitpython_flags.extend( @@ -432,7 +470,8 @@ async def build_circuitpython(): ("-isystem", portdir / "modules" / "crypto" / "mbedtls" / "include") ) circuitpython_flags.extend(("-isystem", zephyrdir / "modules" / "mbedtls" / "configs")) - supervisor_source.append(top / "lib" / "mbedtls_config" / "crt_bundle.c") + if "ssl" in enabled_modules: + supervisor_source.append(top / "lib" / "mbedtls_config" / "crt_bundle.c") # Make sure all modules have a setting by filling in defaults. hal_source = [] @@ -549,6 +588,12 @@ async def build_circuitpython(): ) source_files.append(output_path) + if web_workflow_enabled: + output_path = board_build / "autogen_web_workflow_static.c" + static_files = sorted((srcdir / "supervisor/shared/web_workflow/static").glob("*")) + tg.create_task(generate_web_workflow_static(output_path, static_files)) + source_files.append(output_path) + # This file is generated by the QSTR/translation process. source_files.append(builddir / f"translations-{translation}.c") # These files don't include unique QSTRs. They just need to be compiled. diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 86b0b0fe403..a891069b315 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -395,6 +395,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa "wifi": False, "usb_device": False, "_bleio": False, + "hostnetwork": board_id in ["native_sim"], } config_bt_enabled = False @@ -746,11 +747,25 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa pins.write_text(pin_declarations) board_c = board_dir / "board.c" + hostnetwork_include = "" + hostnetwork_entry = "" + if board_info.get("hostnetwork", False): + hostnetwork_include = ( + '#if CIRCUITPY_HOSTNETWORK\n#include "bindings/hostnetwork/__init__.h"\n#endif\n' + ) + hostnetwork_entry = ( + "#if CIRCUITPY_HOSTNETWORK\n" + " { MP_ROM_QSTR(MP_QSTR_NETWORK), MP_ROM_PTR(&common_hal_hostnetwork_obj) },\n" + "#endif\n" + ) + new_board_c_content = f""" // This file is autogenerated by build_circuitpython.py #include "shared-bindings/board/__init__.h" +{hostnetwork_include} + #include #include "py/obj.h" @@ -779,6 +794,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa static const mp_rom_map_elem_t board_module_globals_table[] = {{ CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS +{hostnetwork_entry} {board_pin_mapping} {zephyr_binding_labels} diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 121de2c4ae5..d0f4d911c12 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -1,4 +1,4 @@ -CONFIG_SYS_HEAP_RUNTIME_STATS=y +CONFIG_SYS_HEAP_RUNTIME_STATS=n CONFIG_FLASH=y CONFIG_FLASH_MAP=y CONFIG_STD_C23=y @@ -12,10 +12,10 @@ CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 CONFIG_THREAD_STACK_INFO=y -CONFIG_STACK_SENTINEL=y -CONFIG_DEBUG_THREAD_INFO=y -CONFIG_DEBUG_INFO=y -CONFIG_EXCEPTION_STACK_TRACE=y +CONFIG_STACK_SENTINEL=n +CONFIG_DEBUG_THREAD_INFO=n +CONFIG_DEBUG_INFO=n +CONFIG_EXCEPTION_STACK_TRACE=n CONFIG_USB_DEVICE_STACK_NEXT=y CONFIG_USBD_CDC_ACM_CLASS=y @@ -30,8 +30,8 @@ CONFIG_HWINFO=y CONFIG_REBOOT=y CONFIG_ENTROPY_GENERATOR=y -CONFIG_ASSERT=y -CONFIG_LOG_BLOCK_IN_THREAD=y +CONFIG_ASSERT=n +CONFIG_LOG_BLOCK_IN_THREAD=n CONFIG_EVENTS=y @@ -45,7 +45,7 @@ CONFIG_SPI_ASYNC=y CONFIG_LOG=y CONFIG_LOG_MAX_LEVEL=2 CONFIG_HW_STACK_PROTECTION=y -CONFIG_FRAME_POINTER=y +CONFIG_FRAME_POINTER=n CONFIG_BT_BUF_ACL_TX_COUNT=7 CONFIG_BT_HCI_ERR_TO_STR=y diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index 0bc296cf43f..7c7eb6ae349 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -42,6 +42,10 @@ def pytest_configure(config): "markers", "code_py_runs(count): stop native_sim after count code.py runs (default: 1)", ) + config.addinivalue_line( + "markers", + "native_sim_rt: run native_sim in realtime mode (-rt instead of -no-rt)", + ) ZEPHYR_CP = Path(__file__).parent.parent @@ -190,6 +194,8 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp else: code_py_runs = int(runs_marker.args[0]) + use_realtime = request.node.get_closest_marker("native_sim_rt") is not None + if "bsim" in board: cmd = [str(native_sim_binary), f"--flash_app={flash}"] if instance_count > 1: @@ -207,7 +213,8 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp else: cmd = [str(native_sim_binary), f"--flash={flash}"] # native_sim vm-runs includes the boot VM setup run. - cmd.extend(("-no-rt", "-wait_uart", f"--vm-runs={code_py_runs + 1}")) + realtime_flag = "-rt" if use_realtime else "-no-rt" + cmd.extend((realtime_flag, "-wait_uart", f"--vm-runs={code_py_runs + 1}")) marker = request.node.get_closest_marker("disable_i2c_devices") if marker and len(marker.args) > 0: diff --git a/ports/zephyr-cp/tests/docs/web_workflow.md b/ports/zephyr-cp/tests/docs/web_workflow.md new file mode 100644 index 00000000000..eb6742b8a3e --- /dev/null +++ b/ports/zephyr-cp/tests/docs/web_workflow.md @@ -0,0 +1,37 @@ +# Web Workflow native_sim Tests + +These tests validate CircuitPython's web workflow support in the Zephyr native_sim port, including filesystem write behavior with and without USB-style write protection. + +## Coverage + +- `test_web_workflow_hostnetwork`: Verifies the web workflow HTTP server responds and enforces authentication (`/edit/` returns `401 Unauthorized`). +- `test_web_workflow_write_code_py_conflict`: Exercises a write attempt while the filesystem is protected (no `boot.py` remount). The DELETE request should return `409 Conflict`. +- `test_web_workflow_write_code_py_remount`: Uses a `boot.py` remount to allow CircuitPython to write. A PUT request updates `code.py`, and a subsequent GET verifies the contents. + +## Filesystem Setup + +The tests create a flash image with: + +- `settings.toml` containing `CIRCUITPY_WEB_API_PASSWORD="testpass"` so the web workflow starts using the on-device settings file. +- `boot.py` (for the remount test only) with: + ```python + import storage + storage.remount("/", readonly=False) + ``` + This disables concurrent write protection so the web workflow can write to CIRCUITPY. + +## Running the Tests + +Build native_sim (if needed): + +```bash +make BOARD=native_native_sim +``` + +Run the tests: + +```bash +pytest -q ports/zephyr-cp/tests/test_web_workflow.py::test_web_workflow_hostnetwork -vv +pytest -q ports/zephyr-cp/tests/test_web_workflow.py::test_web_workflow_write_code_py_conflict -vv +pytest -q ports/zephyr-cp/tests/test_web_workflow.py::test_web_workflow_write_code_py_remount -vv +``` diff --git a/ports/zephyr-cp/tests/test_web_workflow.py b/ports/zephyr-cp/tests/test_web_workflow.py new file mode 100644 index 00000000000..d3a00782a33 --- /dev/null +++ b/ports/zephyr-cp/tests/test_web_workflow.py @@ -0,0 +1,142 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Tests for web workflow on native_sim.""" + +from __future__ import annotations + +import json +import re + +import pytest +import requests + + +pytestmark = pytest.mark.native_sim_rt + +WEB_WORKFLOW_PORT = 8090 +WEB_WORKFLOW_PASSWORD = "testpass" + +WEB_WORKFLOW_CODE = """\ +import time + +# Keep the VM alive while the web workflow starts. +time.sleep(3) +""" + +WEB_WORKFLOW_UPDATED_CODE = """\ +print("updated") +""" + +WEB_WORKFLOW_SETTINGS = f"""\ +CIRCUITPY_WEB_API_PASSWORD="{WEB_WORKFLOW_PASSWORD}" +CIRCUITPY_WEB_API_PORT={WEB_WORKFLOW_PORT} +""" + +WEB_WORKFLOW_SETTINGS_PORT_80 = f"""\ +CIRCUITPY_WEB_API_PASSWORD="{WEB_WORKFLOW_PASSWORD}" +CIRCUITPY_WEB_API_PORT=80 +""" + +WEB_WORKFLOW_BOOT = """\ +import storage + +storage.remount("/", readonly=False) +""" + + +@pytest.mark.circuitpy_drive( + { + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS, + } +) +def test_web_workflow_hostnetwork(circuitpython): + """Ensure web workflow responds over hostnetwork.""" + circuitpython.serial.wait_for(f"127.0.0.1:{WEB_WORKFLOW_PORT}") + response = requests.get(f"http://127.0.0.1:{WEB_WORKFLOW_PORT}/edit/", timeout=1.0) + + assert response.status_code == 401 + + +@pytest.mark.circuitpy_drive( + { + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS, + } +) +def test_web_workflow_version_json_hostnetwork_ip_and_port(circuitpython): + """Ensure /cp/version.json reports hostnetwork endpoint with configured port.""" + circuitpython.serial.wait_for(f"127.0.0.1:{WEB_WORKFLOW_PORT}") + response = requests.get( + f"http://127.0.0.1:{WEB_WORKFLOW_PORT}/cp/version.json", + auth=("", WEB_WORKFLOW_PASSWORD), + timeout=1.0, + ) + + assert response.status_code == 200 + + payload = json.loads(response.text) + assert payload["ip"] == "127.0.0.1" + assert payload["port"] == WEB_WORKFLOW_PORT + + +@pytest.mark.circuitpy_drive( + { + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS, + } +) +def test_web_workflow_status_line_hostnetwork_non_default_port(circuitpython): + """Status line should include hostnetwork IP and non-default port.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + + # Remove ANSI control sequences before matching. + output = re.sub(r"\x1b\[[0-9;]*[A-Za-z]", "", output) + assert "127.0.0.1:8090" in output + + +@pytest.mark.circuitpy_drive( + { + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS_PORT_80, + } +) +def test_web_workflow_status_line_hostnetwork_default_port(circuitpython): + """Status line should show IP without :80 for default HTTP port.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + + output = re.sub(r"\x1b\[[0-9;]*[A-Za-z]", "", output) + assert "127.0.0.1" in output + assert "127.0.0.1:80" not in output + + +@pytest.mark.circuitpy_drive( + { + "boot.py": WEB_WORKFLOW_BOOT, + "code.py": WEB_WORKFLOW_CODE, + "settings.toml": WEB_WORKFLOW_SETTINGS, + } +) +def test_web_workflow_write_code_py_remount(circuitpython): + """Ensure web workflow can update code.py after remounting.""" + circuitpython.serial.wait_for(f"127.0.0.1:{WEB_WORKFLOW_PORT}") + body = WEB_WORKFLOW_UPDATED_CODE.encode("utf-8") + + response = requests.put( + f"http://127.0.0.1:{WEB_WORKFLOW_PORT}/fs/code.py", + auth=("", WEB_WORKFLOW_PASSWORD), + data=body, + timeout=1.0, + ) + assert response.status_code in (201, 204) + + response = requests.get( + f"http://127.0.0.1:{WEB_WORKFLOW_PORT}/fs/code.py", + auth=("", WEB_WORKFLOW_PASSWORD), + timeout=1.0, + ) + assert response.status_code == 200 + assert WEB_WORKFLOW_UPDATED_CODE in response.text diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 56fc6957421..a1297a47544 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -346,6 +346,9 @@ CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS=$(CIRCUITPY_HASHLIB_MBEDTLS) CIRCUITPY_HASHLIB_MBEDTLS_ONLY ?= $(call enable-if-all,$(CIRCUITPY_HASHLIB_MBEDTLS) $(call enable-if-not,$(CIRCUITPY_SSL))) CFLAGS += -DCIRCUITPY_HASHLIB_MBEDTLS_ONLY=$(CIRCUITPY_HASHLIB_MBEDTLS_ONLY) +# Always zero because it is for Zephyr only +CFLAGS += -DCIRCUITPY_HOSTNETWORK=0 + CIRCUITPY_I2CTARGET ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_I2CTARGET=$(CIRCUITPY_I2CTARGET) diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c index e139e3a077a..06b63b80ea7 100644 --- a/shared-bindings/socketpool/SocketPool.c +++ b/shared-bindings/socketpool/SocketPool.c @@ -24,12 +24,11 @@ //| a pool of sockets provided by the underlying OS. //| """ //| -//| def __init__(self, radio: wifi.Radio) -> None: +//| def __init__(self, radio: Union[wifi.Radio, hostnetwork.HostNetwork]) -> None: //| """Create a new SocketPool object for the provided radio //| -//| :param wifi.Radio radio: The (connected) network hardware to associate -//| with this SocketPool; currently, this will always be the object -//| returned by :py:attr:`wifi.radio` +//| :param radio: The (connected) network interface to associate with this +//| SocketPool, such as :py:attr:`wifi.radio` or :py:attr:`board.NETWORK`. //| """ //| ... //| diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index 74e4fed5759..55b7de8df63 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -8,6 +8,8 @@ #define _GNU_SOURCE #include +#include +#include #include #include "extmod/vfs.h" @@ -42,6 +44,10 @@ #include "shared-bindings/socketpool/Socket.h" #include "shared-bindings/socketpool/SocketPool.h" +#if CIRCUITPY_HOSTNETWORK +#include "bindings/hostnetwork/__init__.h" +#endif + #if CIRCUITPY_WIFI #include "shared-bindings/wifi/__init__.h" #endif @@ -84,12 +90,18 @@ typedef struct { char websocket_key[24 + 1]; } _request; +#if CIRCUITPY_WIFI static wifi_radio_error_t _wifi_status = WIFI_RADIO_ERROR_NONE; +#endif -#if CIRCUITPY_STATUS_BAR +#if CIRCUITPY_STATUS_BAR && (CIRCUITPY_WIFI || CIRCUITPY_HOSTNETWORK) // Store various last states to compute if status bar needs an update. static bool _last_enabled = false; static uint32_t _last_ip = 0; +static mp_int_t _last_web_api_port = 80; +#endif + +#if CIRCUITPY_STATUS_BAR && CIRCUITPY_WIFI static wifi_radio_error_t _last_wifi_status = WIFI_RADIO_ERROR_NONE; #endif @@ -171,11 +183,7 @@ static bool _base64_in_place(char *buf, size_t in_len, size_t out_len) { return true; } -static void _update_encoded_ip(void) { - uint32_t ipv4_address = 0; - if (common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { - ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj); - } +static void _update_encoded_ip(uint32_t ipv4_address) { if (_encoded_ip != ipv4_address) { uint8_t *octets = (uint8_t *)&ipv4_address; snprintf(_our_ip_encoded, sizeof(_our_ip_encoded), "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); @@ -183,66 +191,118 @@ static void _update_encoded_ip(void) { } } +static bool _get_web_workflow_ip(uint32_t *ipv4_address) { + *ipv4_address = 0; + #if CIRCUITPY_WIFI + if (!common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj)) { + return false; + } + *ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj); + return true; + #elif CIRCUITPY_HOSTNETWORK + // hostnetwork uses the host network namespace and is reachable via localhost. + *ipv4_address = 0x0100007f; // 127.0.0.1 + return true; + #else + return false; + #endif +} + +#if CIRCUITPY_STATUS_BAR +static void _print_web_workflow_endpoint(void) { + mp_printf(&mp_plat_print, "%s", _our_ip_encoded); + if (web_api_port != 80) { + mp_printf(&mp_plat_print, ":%d", web_api_port); + } +} +#endif + mdns_server_obj_t *supervisor_web_workflow_mdns(mp_obj_t network_interface) { - #if CIRCUITPY_MDNS + #if CIRCUITPY_MDNS && CIRCUITPY_WIFI if (network_interface == &common_hal_wifi_radio_obj && mdns.base.type == &mdns_server_type) { return &mdns; } #endif + (void)network_interface; return NULL; } #if CIRCUITPY_STATUS_BAR bool supervisor_web_workflow_status_dirty(void) { - return common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj) != _last_enabled || - _encoded_ip != _last_ip || - _last_wifi_status != _wifi_status; + #if CIRCUITPY_WIFI || CIRCUITPY_HOSTNETWORK + uint32_t ipv4_address = 0; + bool enabled = _get_web_workflow_ip(&ipv4_address); + if (enabled != _last_enabled || ipv4_address != _last_ip || web_api_port != _last_web_api_port) { + return true; + } + #if CIRCUITPY_WIFI + if (_last_wifi_status != _wifi_status) { + return true; + } + #endif + return false; + #else + return false; + #endif } #endif #if CIRCUITPY_STATUS_BAR void supervisor_web_workflow_status(void) { - _last_enabled = common_hal_wifi_radio_get_enabled(&common_hal_wifi_radio_obj); + #if CIRCUITPY_WIFI || CIRCUITPY_HOSTNETWORK + uint32_t ipv4_address = 0; + _last_enabled = _get_web_workflow_ip(&ipv4_address); + _last_web_api_port = web_api_port; + if (_last_enabled) { - uint32_t ipv4_address = wifi_radio_get_ipv4_address(&common_hal_wifi_radio_obj); + _update_encoded_ip(ipv4_address); + _last_ip = _encoded_ip; + if (ipv4_address != 0) { - _update_encoded_ip(); - _last_ip = _encoded_ip; - mp_printf(&mp_plat_print, "%s", _our_ip_encoded); - if (web_api_port != 80) { - mp_printf(&mp_plat_print, ":%d", web_api_port); - } + _print_web_workflow_endpoint(); // TODO: Use these unicode to show signal strength: ▂▄▆█ return; } - serial_write_compressed(MP_ERROR_TEXT("Wi-Fi: ")); - _last_wifi_status = _wifi_status; - if (_wifi_status == WIFI_RADIO_ERROR_AUTH_EXPIRE || - _wifi_status == WIFI_RADIO_ERROR_AUTH_FAIL) { - serial_write_compressed(MP_ERROR_TEXT("Authentication failure")); - } else if (_wifi_status != WIFI_RADIO_ERROR_NONE) { - mp_printf(&mp_plat_print, "%d", _wifi_status); - } else if (ipv4_address == 0) { - _last_ip = 0; - serial_write_compressed(MP_ERROR_TEXT("No IP")); - } else { - } - } else { - // Keep Wi-Fi print separate so its data can be matched with the one above. - serial_write_compressed(MP_ERROR_TEXT("Wi-Fi: ")); + } + + #if CIRCUITPY_WIFI + serial_write_compressed(MP_ERROR_TEXT("Wi-Fi: ")); + _last_wifi_status = _wifi_status; + if (!_last_enabled) { serial_write_compressed(MP_ERROR_TEXT("off")); + } else if (_wifi_status == WIFI_RADIO_ERROR_AUTH_EXPIRE || + _wifi_status == WIFI_RADIO_ERROR_AUTH_FAIL) { + serial_write_compressed(MP_ERROR_TEXT("Authentication failure")); + } else if (_wifi_status != WIFI_RADIO_ERROR_NONE) { + mp_printf(&mp_plat_print, "%d", _wifi_status); + } else { + _last_ip = 0; + serial_write_compressed(MP_ERROR_TEXT("No IP")); } + #endif + #else + return; + #endif } #endif bool supervisor_start_web_workflow(void) { - #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML + #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_SETTINGS_TOML && (CIRCUITPY_WIFI || CIRCUITPY_HOSTNETWORK) + + #if CIRCUITPY_WIFI + mp_obj_t socketpool_radio = MP_OBJ_FROM_PTR(&common_hal_wifi_radio_obj); + #else + mp_obj_t socketpool_radio = MP_OBJ_FROM_PTR(&common_hal_hostnetwork_obj); + #endif + settings_err_t result; + + #if CIRCUITPY_WIFI char ssid[33]; char password[64]; - settings_err_t result = settings_get_str("CIRCUITPY_WIFI_SSID", ssid, sizeof(ssid)); + result = settings_get_str("CIRCUITPY_WIFI_SSID", ssid, sizeof(ssid)); if (result != SETTINGS_OK || strlen(ssid) < 1) { return false; } @@ -275,6 +335,7 @@ bool supervisor_start_web_workflow(void) { common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, false); return false; } + #endif // Skip starting the workflow if we're not starting from power on or reset. const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); @@ -307,7 +368,7 @@ bool supervisor_start_web_workflow(void) { } pool.base.type = &socketpool_socketpool_type; - common_hal_socketpool_socketpool_construct(&pool, &common_hal_wifi_radio_obj); + common_hal_socketpool_socketpool_construct(&pool, socketpool_radio); socketpool_socket_reset(&listening); socketpool_socket_reset(&active); @@ -847,7 +908,9 @@ static void _reply_with_version_json(socketpool_socket_obj_t *socket, _request * instance_name = common_hal_mdns_server_get_instance_name(&mdns); } #endif - _update_encoded_ip(); + uint32_t ipv4_address = 0; + (void)_get_web_workflow_ip(&ipv4_address); + _update_encoded_ip(ipv4_address); // Note: this leverages the fact that C concats consecutive string literals together. mp_printf(&_socket_print, "{\"web_api_version\": 4, " diff --git a/supervisor/shared/web_workflow/web_workflow.h b/supervisor/shared/web_workflow/web_workflow.h index 439964dd333..9ec15a14ddc 100644 --- a/supervisor/shared/web_workflow/web_workflow.h +++ b/supervisor/shared/web_workflow/web_workflow.h @@ -8,7 +8,12 @@ #include +#if CIRCUITPY_MDNS #include "shared-bindings/mdns/Server.h" +#else +typedef struct mdns_server_obj mdns_server_obj_t; +#endif + #include "shared-bindings/socketpool/Socket.h" // This background function should be called repeatedly. It cannot be done based diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index c1999b4a7b6..7370e34e860 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -43,10 +43,12 @@ void supervisor_workflow_reset(void) { #if CIRCUITPY_WEB_WORKFLOW bool result = supervisor_start_web_workflow(); - if (workflow_background_cb.fun) { - if (result) { - supervisor_workflow_request_background(); + if (result) { + if (!workflow_background_cb.fun) { + memset(&workflow_background_cb, 0, sizeof(workflow_background_cb)); + workflow_background_cb.fun = supervisor_web_workflow_background; } + supervisor_workflow_request_background(); } #endif } @@ -105,9 +107,11 @@ void supervisor_workflow_start(void) { #if CIRCUITPY_WEB_WORKFLOW if (supervisor_start_web_workflow()) { - // Enable background callbacks if web_workflow startup successful + // Enable background callbacks if web_workflow startup successful. memset(&workflow_background_cb, 0, sizeof(workflow_background_cb)); workflow_background_cb.fun = supervisor_web_workflow_background; + // Kick the first background run now that the callback is installed. + supervisor_workflow_request_background(); } #endif From d6afaf7bc2284fa67abee1bfb9160fa4048653d4 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 25 Feb 2026 11:57:39 -0800 Subject: [PATCH 242/876] Fix tinycircuits boards after base branch didn't catch the issues --- ports/raspberrypi/boards/tinycircuits_thumby/board.c | 6 +++--- .../boards/tinycircuits_thumby/mpconfigboard.h | 3 --- .../boards/tinycircuits_thumby_color/board.c | 12 ++++++------ ports/raspberrypi/mpconfigport.h | 4 +--- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/board.c b/ports/raspberrypi/boards/tinycircuits_thumby/board.c index 15a7eeb93a4..3a306b35f0d 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby/board.c +++ b/ports/raspberrypi/boards/tinycircuits_thumby/board.c @@ -37,9 +37,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - CIRCUITPY_BOARD_OLED_DC, // Command or data - CIRCUITPY_BOARD_OLED_CS, // Chip select - CIRCUITPY_BOARD_OLED_RESET, // Reset + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_OLED_DC), // Command or data + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_OLED_CS), // Chip select + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_OLED_RESET), // Reset 10000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h index 91430966d23..cec0fc10f55 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h +++ b/ports/raspberrypi/boards/tinycircuits_thumby/mpconfigboard.h @@ -18,6 +18,3 @@ #define CIRCUITPY_BOARD_SPI (1) #define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} - -// For entering safe mode -#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO6) diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c b/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c index abd80dafc62..17c512cb2a6 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/board.c @@ -62,12 +62,12 @@ void board_init(void) { common_hal_fourwire_fourwire_construct( bus, spi, - CIRCUITPY_BOARD_LCD_DC, // DC - CIRCUITPY_BOARD_LCD_CS, // CS - CIRCUITPY_BOARD_LCD_RESET, // RST - 80000000, // baudrate - 0, // polarity - 0 // phase + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_LCD_DC), // DC + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_LCD_CS), // CS + MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_LCD_RESET), // RST + 80000000, // baudrate + 0, // polarity + 0 // phase ); busdisplay_busdisplay_obj_t *display = &allocate_display()->display; diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index 3eb576de39e..c4253937c98 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -36,10 +36,8 @@ #define CIRCUITPY_PROCESSOR_COUNT (2) -// For many RP2 boards BOOTSEL is not connected to a GPIO pin. -#ifndef CIRCUITPY_BOOT_BUTTON +// For RP2 boards we use a custom way to read BOOTSEL #define CIRCUITPY_BOOT_BUTTON_NO_GPIO (1) -#endif #if CIRCUITPY_USB_HOST #define CIRCUITPY_USB_HOST_INSTANCE 1 From 20d9e1812ce050a8ae1e3331f3e6cd833a14cd89 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 25 Feb 2026 13:06:22 -0800 Subject: [PATCH 243/876] Remove outdated OS_GETENV flag Co-authored-by: Dan Halbert --- ports/zephyr-cp/cptools/build_circuitpython.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 51521e913ab..4bae0cc73bf 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -317,7 +317,6 @@ async def build_circuitpython(): circuitpython_flags.append(f"-DCIRCUITPY_ENABLE_MPY_NATIVE={1 if enable_mpy_native else 0}") circuitpython_flags.append(f"-DCIRCUITPY_FULL_BUILD={1 if full_build else 0}") circuitpython_flags.append(f"-DCIRCUITPY_SETTINGS_TOML={1 if full_build else 0}") - circuitpython_flags.append(f"-DCIRCUITPY_OS_GETENV={1 if full_build else 0}") circuitpython_flags.append("-DCIRCUITPY_STATUS_BAR=1") circuitpython_flags.append(f"-DCIRCUITPY_USB_HOST={1 if usb_host else 0}") circuitpython_flags.append(f"-DCIRCUITPY_BOARD_ID='\"{board}\"'") From a9ad7a1c90358de5ff6d02d143969c59f128d950 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 25 Feb 2026 23:09:35 +0100 Subject: [PATCH 244/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 5 ++++- locale/el.po | 5 ++++- locale/hi.po | 5 ++++- locale/ko.po | 5 ++++- locale/ru.po | 5 ++++- locale/tr.po | 5 ++++- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 319fe64bc75..92979bdd31b 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -2090,10 +2090,13 @@ msgstr "" #: ports/espressif/common-hal/socketpool/SocketPool.c #: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c msgid "SocketPool can only be used with wifi.radio" msgstr "SocketPool je možné použít pouze s wifi.radio" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + #: shared-bindings/aesio/aes.c msgid "Source and destination buffers must be the same length" msgstr "Zdrojové a cílové buffery musí být stejné délky" diff --git a/locale/el.po b/locale/el.po index da44530ba7e..9ad4e3ccfc3 100644 --- a/locale/el.po +++ b/locale/el.po @@ -2095,10 +2095,13 @@ msgstr "" #: ports/espressif/common-hal/socketpool/SocketPool.c #: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c msgid "SocketPool can only be used with wifi.radio" msgstr "" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + #: shared-bindings/aesio/aes.c msgid "Source and destination buffers must be the same length" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index f0a35d43e79..046cea6b3d4 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -2069,10 +2069,13 @@ msgstr "" #: ports/espressif/common-hal/socketpool/SocketPool.c #: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c msgid "SocketPool can only be used with wifi.radio" msgstr "" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + #: shared-bindings/aesio/aes.c msgid "Source and destination buffers must be the same length" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 31ec5a50294..311803d7630 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -2142,10 +2142,13 @@ msgstr "" #: ports/espressif/common-hal/socketpool/SocketPool.c #: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c msgid "SocketPool can only be used with wifi.radio" msgstr "" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + #: shared-bindings/aesio/aes.c msgid "Source and destination buffers must be the same length" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 3efafa9e464..1eac7b309a6 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -2120,10 +2120,13 @@ msgstr "Фрагменты не поддерживаются" #: ports/espressif/common-hal/socketpool/SocketPool.c #: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c msgid "SocketPool can only be used with wifi.radio" msgstr "SocketPool можно использовать только с wifi.radio" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + #: shared-bindings/aesio/aes.c msgid "Source and destination buffers must be the same length" msgstr "Исходный и конечный буферы должны иметь одинаковую длину" diff --git a/locale/tr.po b/locale/tr.po index 737eaff9b55..4e75d975f55 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -2091,10 +2091,13 @@ msgstr "" #: ports/espressif/common-hal/socketpool/SocketPool.c #: ports/raspberrypi/common-hal/socketpool/SocketPool.c -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c msgid "SocketPool can only be used with wifi.radio" msgstr "" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + #: shared-bindings/aesio/aes.c msgid "Source and destination buffers must be the same length" msgstr "" From d92dc147c3474589f7613bc312ee304f6b77174a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 25 Feb 2026 17:52:09 -0600 Subject: [PATCH 245/876] update frozen libs --- frozen/Adafruit_CircuitPython_Bitmap_Font | 2 +- frozen/Adafruit_CircuitPython_Display_Text | 2 +- frozen/Adafruit_CircuitPython_HTTPServer | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_Bitmap_Font b/frozen/Adafruit_CircuitPython_Bitmap_Font index cb6a08e2ca5..47999fac242 160000 --- a/frozen/Adafruit_CircuitPython_Bitmap_Font +++ b/frozen/Adafruit_CircuitPython_Bitmap_Font @@ -1 +1 @@ -Subproject commit cb6a08e2ca57df75b512b844cce78558088979fe +Subproject commit 47999fac242f673812315f42d1886ea54a2c5177 diff --git a/frozen/Adafruit_CircuitPython_Display_Text b/frozen/Adafruit_CircuitPython_Display_Text index 372cbe27459..3b606a735a0 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit 372cbe27459c02db838fb65489cf8b4b5dba12f3 +Subproject commit 3b606a735a01f0cb577447fba59e0190ba79b10e diff --git a/frozen/Adafruit_CircuitPython_HTTPServer b/frozen/Adafruit_CircuitPython_HTTPServer index e234a494050..1419fc5c071 160000 --- a/frozen/Adafruit_CircuitPython_HTTPServer +++ b/frozen/Adafruit_CircuitPython_HTTPServer @@ -1 +1 @@ -Subproject commit e234a4940504b4fb21c7338d774ec273260ef672 +Subproject commit 1419fc5c071b7c631d9285c4efef4c4df23a079c From 5a49c524f8e10d9520bbfef0b527c19968d33b08 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 26 Feb 2026 10:50:03 -0800 Subject: [PATCH 246/876] Update autogen --- .../adafruit/feather_nrf52840_zephyr/autogen_board_info.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index db83e1b7448..43b018c327a 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -50,6 +50,7 @@ getpass = false gifio = false gnss = false hashlib = false +hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false From 1f8408ec90cd88593fc0e017a48594fdf2c4bb87 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 26 Feb 2026 12:19:33 -0800 Subject: [PATCH 247/876] Fix S3 startup due to ble_gap_adv_active crash ble_gap_adv_active() crashes now when BLE hasn't been init. This is likely due to internal memory allocations in esp-nimble. So, check enabled before calling into it. Fixes #10849 --- ports/espressif/common-hal/_bleio/Adapter.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index 327515da4de..aca3f8c2042 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -733,7 +733,7 @@ void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { } bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { - return ble_gap_adv_active(); + return common_hal_bleio_adapter_get_enabled(self) && ble_gap_adv_active(); } bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { From a358cd58bce7afcfb3ff4ea2f5dd264aeb75518d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 26 Feb 2026 12:23:08 -0800 Subject: [PATCH 248/876] Tweak flaky test Now the bsim PHY will stay active until the test harness terminates it. This requires the CircuitPython device process to exit correctly first but is backed up by wall clock timeouts in the harness. (Sim timeouts were in simulated time.) --- ports/zephyr-cp/tests/bsim/conftest.py | 5 +++-- ports/zephyr-cp/zephyr-config/west.yml | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/zephyr-cp/tests/bsim/conftest.py b/ports/zephyr-cp/tests/bsim/conftest.py index b7a66346ce2..67b76469fa0 100644 --- a/ports/zephyr-cp/tests/bsim/conftest.py +++ b/ports/zephyr-cp/tests/bsim/conftest.py @@ -97,7 +97,9 @@ def bsim_phy(request, bsim_phy_binary, native_sim_env, sim_id): sample_device_id = int(sample_marker.kwargs.get("device_id", 1)) devices = max(devices, sample_device_id + 1) - sim_length_us = int(duration * 1e6) + # Do not pass -sim_length: if the PHY exits on simulated time, device 0 can + # still be flushing UART output and test output can get truncated. Instead, + # let pytest own process lifetime and terminate the PHY at fixture teardown. cmd = [ "stdbuf", "-oL", @@ -105,7 +107,6 @@ def bsim_phy(request, bsim_phy_binary, native_sim_env, sim_id): "-v=9", # Cleaning up level is on 9. Connecting is 7. f"-s={sim_id}", f"-D={devices}", - f"-sim_length={sim_length_us}", ] print("Running:", " ".join(cmd)) proc = subprocess.Popen( diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index a8b05fabd05..04983fb602b 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -4,7 +4,7 @@ manifest: projects: - name: nrf_hw_models url: https://github.com/tannewt/ext_nRF_hw_models - revision: 24de78c485dce1a6048f8ae1c69a8d70c93b8cdd + revision: bb351cef9e5ab4d175fe3cb7c4d6761d837bac20 path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr From 2c95679ccf1ea9ce4791a61ad4db632c1f4a2309 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 27 Feb 2026 13:38:47 -0800 Subject: [PATCH 249/876] Start tracking zephyr/main main is still quite stable but has the latest hardware support and bug fixes. --- ports/zephyr-cp/boards/board_aliases.cmake | 64 +++++++++++++------ .../boards/nrf5340bsim_nrf5340_cpuapp.conf | 4 -- ports/zephyr-cp/prj.conf | 10 --- ports/zephyr-cp/socs/nrf5340_cpuapp.conf | 3 +- ports/zephyr-cp/zephyr-config/west.yml | 4 +- 5 files changed, 49 insertions(+), 36 deletions(-) diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index ee46145a112..dce5b100aa6 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -1,18 +1,46 @@ -set(pca10056_BOARD_ALIAS nrf52840dk/nrf52840) -set(adafruit_feather_nrf52840_zephyr_BOARD_ALIAS adafruit_feather_nrf52840/nrf52840/uf2) -set(renesas_ek_ra6m5_BOARD_ALIAS ek_ra6m5) -set(renesas_ek_ra8d1_BOARD_ALIAS ek_ra8d1) -set(renesas_da14695_dk_usb_BOARD_ALIAS da14695_dk_usb) -set(native_native_sim_BOARD_ALIAS native_sim) -set(native_nrf5340bsim_BOARD_ALIAS nrf5340bsim/nrf5340/cpuapp) -set(nordic_nrf54l15dk_BOARD_ALIAS nrf54l15dk/nrf54l15/cpuapp) -set(nordic_nrf54h20dk_BOARD_ALIAS nrf54h20dk/nrf54h20/cpuapp) -set(nordic_nrf5340dk_BOARD_ALIAS nrf5340dk/nrf5340/cpuapp) -set(nordic_nrf7002dk_BOARD_ALIAS nrf7002dk/nrf5340/cpuapp) -set(nxp_frdm_mcxn947_BOARD_ALIAS frdm_mcxn947/mcxn947/cpu0) -set(nxp_frdm_rw612_BOARD_ALIAS frdm_rw612) -set(nxp_mimxrt1170_evk_BOARD_ALIAS mimxrt1170_evk@A/mimxrt1176/cm7) -set(st_stm32h7b3i_dk_BOARD_ALIAS stm32h7b3i_dk) -set(st_stm32wba65i_dk1_BOARD_ALIAS stm32wba65i_dk1) -set(st_nucleo_u575zi_q_BOARD_ALIAS nucleo_u575zi_q/stm32u575xx) -set(st_nucleo_n657x0_q_BOARD_ALIAS nucleo_n657x0_q/stm32n657xx) +# Workaround for Zephyr alias handling with BOARD_QUALIFIERS in newer Zephyr. +# +# Instead of using _BOARD_ALIAS variables, translate BOARD directly so +# we don't end up with a spurious trailing '/' in BOARD_QUALIFIERS. +macro(cp_board_alias alias target) + if(BOARD STREQUAL "${alias}") + if(NOT "${target}" MATCHES "^([^@/]+)(@[^@/]+)?(/([^@]+))?$") + message(FATAL_ERROR "Invalid alias target '${target}'") + endif() + + set(BOARD_ALIAS "${alias}" CACHE STRING "Board alias, provided by user") + set(BOARD "${CMAKE_MATCH_1}") + + if(CMAKE_MATCH_2) + string(REPLACE "@" "" _rev "${CMAKE_MATCH_2}") + set(BOARD_REVISION "${_rev}") + else() + unset(BOARD_REVISION) + endif() + + if(CMAKE_MATCH_4) + set(BOARD_QUALIFIERS "${CMAKE_MATCH_4}") + else() + unset(BOARD_QUALIFIERS) + endif() + endif() +endmacro() + +cp_board_alias(pca10056 nrf52840dk/nrf52840) +cp_board_alias(adafruit_feather_nrf52840_zephyr adafruit_feather_nrf52840/nrf52840/uf2) +cp_board_alias(renesas_ek_ra6m5 ek_ra6m5) +cp_board_alias(renesas_ek_ra8d1 ek_ra8d1) +cp_board_alias(renesas_da14695_dk_usb da14695_dk_usb) +cp_board_alias(native_native_sim native_sim/native) +cp_board_alias(native_nrf5340bsim nrf5340bsim/nrf5340/cpuapp) +cp_board_alias(nordic_nrf54l15dk nrf54l15dk/nrf54l15/cpuapp) +cp_board_alias(nordic_nrf54h20dk nrf54h20dk/nrf54h20/cpuapp) +cp_board_alias(nordic_nrf5340dk nrf5340dk/nrf5340/cpuapp) +cp_board_alias(nordic_nrf7002dk nrf7002dk/nrf5340/cpuapp) +cp_board_alias(nxp_frdm_mcxn947 frdm_mcxn947/mcxn947/cpu0) +cp_board_alias(nxp_frdm_rw612 frdm_rw612) +cp_board_alias(nxp_mimxrt1170_evk mimxrt1170_evk@A/mimxrt1176/cm7) +cp_board_alias(st_stm32h7b3i_dk stm32h7b3i_dk) +cp_board_alias(st_stm32wba65i_dk1 stm32wba65i_dk1) +cp_board_alias(st_nucleo_u575zi_q nucleo_u575zi_q/stm32u575xx) +cp_board_alias(st_nucleo_n657x0_q nucleo_n657x0_q/stm32n657xx) diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf index f9507bd0319..02e4e0d0d56 100644 --- a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -6,16 +6,12 @@ CONFIG_GPIO=y # Enable Bluetooth stack - bsim is for BT simulation CONFIG_BT=y CONFIG_BT_HCI=y -CONFIG_BT_HCI_IPC=y CONFIG_BT_OBSERVER=y CONFIG_BT_BROADCASTER=y CONFIG_BT_DEVICE_NAME_DYNAMIC=y CONFIG_BT_DEVICE_NAME_MAX=28 -# So we can test safe mode -CONFIG_NATIVE_SIM_REBOOT=y - # Ensure the network core image starts when using native simulator CONFIG_NATIVE_SIMULATOR_AUTOSTART_MCU=y diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index d0f4d911c12..9b4dcccb53e 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -1,25 +1,20 @@ CONFIG_SYS_HEAP_RUNTIME_STATS=n CONFIG_FLASH=y CONFIG_FLASH_MAP=y -CONFIG_STD_C23=y CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_FLASH_MAP_LABELS=y CONFIG_MAIN_STACK_SIZE=24288 -CONFIG_SPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 -CONFIG_NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE=4096 CONFIG_THREAD_STACK_INFO=y CONFIG_STACK_SENTINEL=n CONFIG_DEBUG_THREAD_INFO=n -CONFIG_DEBUG_INFO=n CONFIG_EXCEPTION_STACK_TRACE=n CONFIG_USB_DEVICE_STACK_NEXT=y CONFIG_USBD_CDC_ACM_CLASS=y -CONFIG_USBD_MAX_SPEED=1 CONFIG_USBD_MSC_STACK_SIZE=1536 CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n @@ -44,13 +39,8 @@ CONFIG_SPI_ASYNC=y CONFIG_LOG=y CONFIG_LOG_MAX_LEVEL=2 -CONFIG_HW_STACK_PROTECTION=y CONFIG_FRAME_POINTER=n -CONFIG_BT_BUF_ACL_TX_COUNT=7 -CONFIG_BT_HCI_ERR_TO_STR=y - CONFIG_NET_HOSTNAME_ENABLE=y CONFIG_NET_HOSTNAME_DYNAMIC=y CONFIG_NET_HOSTNAME="circuitpython" -CONFIG_NET_MGMT_EVENT_INFO=y diff --git a/ports/zephyr-cp/socs/nrf5340_cpuapp.conf b/ports/zephyr-cp/socs/nrf5340_cpuapp.conf index bf70997d83f..734d26db8e9 100644 --- a/ports/zephyr-cp/socs/nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/socs/nrf5340_cpuapp.conf @@ -1,4 +1,3 @@ -CONFIG_NRFX_UARTE0=y -CONFIG_NRFX_UARTE1=y +CONFIG_NRFX_UARTE=y CONFIG_NRFX_POWER=y diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 3cee04f982b..bb5c9b4942b 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -4,10 +4,10 @@ manifest: projects: - name: nrf_hw_models url: https://github.com/tannewt/ext_nRF_hw_models - revision: bb351cef9e5ab4d175fe3cb7c4d6761d837bac20 + revision: c2927847bdf2ee0af9c5459f4155c67f39f6837a path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: 8801b409ec554cfd217c159c00f91280ea1331db + revision: 5351284ac926b1352ab98f5ae692a21f38068beb clone-depth: 100 import: true From 89c818679fd521a1130e989ac5cf160403e33e5a Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Tue, 24 Feb 2026 00:04:27 +0100 Subject: [PATCH 250/876] QSPI bus driver and RM690B0 display driver for Waveshare ESP32-S3 AMOLED 2.41 --- locale/circuitpython.pot | 56 ++ ports/espressif/Makefile | 3 + .../waveshare_esp32_s3_amoled_241/board.c | 8 + .../mpconfigboard.h | 41 ++ .../mpconfigboard.mk | 39 ++ .../waveshare_esp32_s3_amoled_241/pins.c | 100 +++ .../waveshare_esp32_s3_amoled_241/sdkconfig | 33 + ports/espressif/common-hal/qspibus/QSPIBus.c | 580 ++++++++++++++++++ ports/espressif/common-hal/qspibus/QSPIBus.h | 51 ++ ports/espressif/common-hal/qspibus/__init__.c | 3 + ports/espressif/common-hal/qspibus/__init__.h | 3 + py/circuitpy_defns.mk | 5 + py/circuitpy_mpconfig.h | 7 + py/circuitpy_mpconfig.mk | 4 + shared-bindings/qspibus/QSPIBus.c | 222 +++++++ shared-bindings/qspibus/QSPIBus.h | 57 ++ shared-bindings/qspibus/__init__.c | 50 ++ shared-bindings/qspibus/__init__.h | 8 + shared-module/busdisplay/BusDisplay.c | 47 ++ shared-module/displayio/__init__.c | 4 + shared-module/displayio/__init__.h | 6 + shared-module/displayio/bus_core.c | 13 + 22 files changed, 1340 insertions(+) create mode 100644 ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c create mode 100644 ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h create mode 100644 ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk create mode 100644 ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c create mode 100644 ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig create mode 100644 ports/espressif/common-hal/qspibus/QSPIBus.c create mode 100644 ports/espressif/common-hal/qspibus/QSPIBus.h create mode 100644 ports/espressif/common-hal/qspibus/__init__.c create mode 100644 ports/espressif/common-hal/qspibus/__init__.h create mode 100644 shared-bindings/qspibus/QSPIBus.c create mode 100644 shared-bindings/qspibus/QSPIBus.h create mode 100644 shared-bindings/qspibus/__init__.c create mode 100644 shared-bindings/qspibus/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index e2eebdea0fe..1f3d4c0974a 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -646,6 +646,10 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Begin transaction first" +msgstr "" + #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -712,6 +716,10 @@ msgstr "" msgid "Buffer too small" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Bus in display transaction" +msgstr "" + #: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c @@ -906,6 +914,10 @@ msgstr "" msgid "Data 0 pin must be byte aligned" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Data buffer is null" +msgstr "" + #: shared-module/jpegio/JpegDecoder.c msgid "Data format error (may be broken data)" msgstr "" @@ -1017,6 +1029,10 @@ msgstr "" msgid "Failed to allocate %q buffer" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Failed to allocate DMA buffers" +msgstr "" + #: ports/espressif/common-hal/wifi/__init__.c msgid "Failed to allocate Wifi memory" msgstr "" @@ -1054,6 +1070,10 @@ msgstr "" msgid "Failed to create continuous channels: not found" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Failed to create semaphore" +msgstr "" + #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to enable continuous" msgstr "" @@ -1599,6 +1619,10 @@ msgstr "" msgid "No out in program" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "No pending command" +msgstr "" + #: ports/atmel-samd/common-hal/busio/I2C.c #: ports/espressif/common-hal/busio/I2C.c #: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c @@ -1783,6 +1807,11 @@ msgstr "" msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#, c-format +msgid "Panel IO init failed: %d" +msgstr "" + #: shared-module/jpegio/JpegDecoder.c msgid "Parameter error" msgstr "" @@ -1889,6 +1918,28 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "QSPI DMA buffers unavailable" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "QSPI color timeout" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "QSPI command timeout" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#, c-format +msgid "QSPI send color failed: %d" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#, c-format +msgid "QSPI send failed: %d" +msgstr "" + #: ports/raspberrypi/common-hal/countio/Counter.c msgid "RISE_AND_FALL not available on this chip" msgstr "" @@ -2010,6 +2061,11 @@ msgstr "" msgid "SDIO Init Error %x" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#, c-format +msgid "SPI bus init failed: %d" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c msgid "SPI configuration failed" msgstr "" diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 9e331740dd6..2545b33d22a 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -780,6 +780,9 @@ endif ifneq ($(CIRCUITPY_PARALLELDISPLAYBUS),0) ESP_IDF_COMPONENTS_LINK += esp_lcd endif +ifneq ($(CIRCUITPY_QSPIBUS),0) + ESP_IDF_COMPONENTS_LINK += esp_lcd +endif ifneq ($(CIRCUITPY_USB_DEVICE),0) ESP_IDF_COMPONENTS_LINK += usb endif diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c new file mode 100644 index 00000000000..10ef3d7274c --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +void board_init(void) { +} diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h new file mode 100644 index 00000000000..b4d4df961bf --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3-Touch-AMOLED-2.41" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +// USB identifiers +#define USB_VID 0x303A +#define USB_PID 0x82CE +#define USB_MANUFACTURER "Waveshare" +#define USB_PRODUCT "ESP32-S3-Touch-AMOLED-2.41" + +// I2C bus - Disabled on boot to avoid conflicts. User must manually initialize I2C. +#define CIRCUITPY_BOARD_I2C (0) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO48, .sda = &pin_GPIO47}} + +// QSPI display refresh buffer: 2048 uint32_t words = 8KB on stack. +// ESP32-S3 main task stack is 24KB; verified safe with this board. +#define CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE (2048) + +// AMOLED Display (displayio + qspibus path) +#define CIRCUITPY_BOARD_DISPLAY (0) +#define CIRCUITPY_LCD_CS (&pin_GPIO9) +#define CIRCUITPY_LCD_CLK (&pin_GPIO10) +#define CIRCUITPY_LCD_D0 (&pin_GPIO11) +#define CIRCUITPY_LCD_D1 (&pin_GPIO12) +#define CIRCUITPY_LCD_D2 (&pin_GPIO13) +#define CIRCUITPY_LCD_D3 (&pin_GPIO14) +#define CIRCUITPY_LCD_RESET (&pin_GPIO21) +#define CIRCUITPY_LCD_POWER (&pin_GPIO16) +#define CIRCUITPY_LCD_POWER_ON_LEVEL (1) // GPIO level: 1=high, 0=low + +// No default SPI bus — SD card uses SDIO, display uses QSPI. +#define CIRCUITPY_BOARD_SPI (0) + +// Default UART bus +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk new file mode 100644 index 00000000000..0546d906933 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk @@ -0,0 +1,39 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +# +# SPDX-License-Identifier: MIT + +CIRCUITPY_CREATOR_ID = 0x57415645 # 'WAVE' (Waveshare) +CIRCUITPY_CREATION_ID = 0x41323431 # 'A241' (AMOLED 2.41) + +# USB identifiers - from Arduino pins_arduino.h +USB_VID = 0x303A +USB_PID = 0x82CE +USB_MANUFACTURER = "Waveshare" +USB_PRODUCT = "ESP32-S3-Touch-AMOLED-2.41" + +IDF_TARGET = esp32s3 + +# Flash configuration - 16MB QSPI Flash +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +# PSRAM configuration - 8MB Octal PSRAM +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +OPTIMIZATION_FLAGS = -Os + +# QSPI bus for RM690B0 AMOLED display +CIRCUITPY_QSPIBUS = 1 +CIRCUITPY_PARALLELDISPLAYBUS = 0 + +# No camera on this board +CIRCUITPY_ESPCAMERA = 0 + +# Capacitive touch not available; board uses I2C touch controller +CIRCUITPY_TOUCHIO = 0 + +# SD card via SDMMC interface +CIRCUITPY_SDIOIO = 1 diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c new file mode 100644 index 00000000000..437488e3f2b --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c @@ -0,0 +1,100 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/mphal.h" +#include "shared-bindings/board/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // ================================================================= + // ONBOARD PERIPHERALS - Functional Names + // ================================================================= + + // Boot/Control/Battery/Display Power + // NOTE: GPIO16 is shared between battery control circuitry and LCD power + // (see CIRCUITPY_QSPIBUS_PANEL_POWER_PIN in mpconfigboard.h). + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_KEY_BAT), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_BAT_CONTROL), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_LCD_POWER), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_BAT_ADC), MP_ROM_PTR(&pin_GPIO17) }, + + // I2C Bus (shared by Touch, RTC, IMU, IO Expander) + // NOTE: board.I2C auto-initialization is disabled (CIRCUITPY_BOARD_I2C=0) + // to avoid boot conflicts. Users must manually create I2C bus: + // i2c = busio.I2C(board.SCL, board.SDA) + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + // Touch Panel (FT6336U on I2C) + { MP_ROM_QSTR(MP_QSTR_TP_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_TP_SCL), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_TP_RESET), MP_ROM_PTR(&pin_GPIO3) }, + + // RTC (PCF85063 on I2C) + { MP_ROM_QSTR(MP_QSTR_RTC_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_RTC_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + // IMU (QMI8658 on I2C) + { MP_ROM_QSTR(MP_QSTR_IMU_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IMU_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + // I/O Expander (TCA9554 on I2C) + { MP_ROM_QSTR(MP_QSTR_EXIO_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_EXIO_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + // USB + { MP_ROM_QSTR(MP_QSTR_USB_D_N), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_USB_D_P), MP_ROM_PTR(&pin_GPIO20) }, + + // UART + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + // QSPI Display (RM690B0) - canonical generic LCD aliases. + { MP_ROM_QSTR(MP_QSTR_LCD_CS), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_LCD_CLK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D0), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D1), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D2), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_LCD_D3), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_LCD_RESET), MP_ROM_PTR(&pin_GPIO21) }, + + // Display Aliases + { MP_ROM_QSTR(MP_QSTR_DISPLAY_CS), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_SCK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_D0), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_D1), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_D2), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_D3), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_DISPLAY_RST), MP_ROM_PTR(&pin_GPIO21) }, + + // SD Card (SDIO / SDMMC) + { MP_ROM_QSTR(MP_QSTR_SDIO_CLK), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_CMD), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_D0), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_D3), MP_ROM_PTR(&pin_GPIO2) }, + + // ================================================================= + // GENERAL PURPOSE I/O (IOxx - Espressif Convention) + // ================================================================= + // Only pins NOT dedicated to onboard peripherals are exposed here. + // Use functional names above for dedicated pins (e.g., SDA, SD_CS). + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, // BOOT button (available when not holding BOOT) + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, // TP_RESET (available if touch not used) + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, // Available + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, // Available +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig new file mode 100644 index 00000000000..3ef898aed3e --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig @@ -0,0 +1,33 @@ +# +# Configuration file for the Waveshare ESP32-S3 Touch AMOLED 2.41 +# + +# PSRAM Configuration +CONFIG_SPIRAM=y +CONFIG_SPIRAM_BOOT_INIT=y +CONFIG_SPIRAM_USE_MALLOC=y +CONFIG_SPIRAM_MODE_OCT=y +CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y +CONFIG_SPIRAM_RODATA=y +CONFIG_SPIRAM_SPEED_80M=y +CONFIG_SPIRAM_MEMTEST=y +CONFIG_SPIRAM_CLK_IO=39 +CONFIG_SPIRAM_CS_IO=38 + +# Performance and Cache +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y +CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y + +# Default flash settings for this board +CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y +CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-16MB.csv" +CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-16MB.csv" + +# Networking +CONFIG_LWIP_LOCAL_HOSTNAME="waveshare-esp32-s3-amoled" + +# Disable USB-Serial/JTAG console - CircuitPython uses TinyUSB (USB OTG) for REPL +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=n + +# Enable .app_desc structure +CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c new file mode 100644 index 00000000000..7182869b6b6 --- /dev/null +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -0,0 +1,580 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/qspibus/QSPIBus.h" + +#include "common-hal/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" + +#include "py/gc.h" +#include "py/runtime.h" + +#include "driver/gpio.h" +#include "esp_heap_caps.h" +#include "soc/soc_caps.h" +#include + +#define QSPI_OPCODE_WRITE_CMD (0x02U) +#define QSPI_OPCODE_WRITE_COLOR (0x32U) +#define LCD_CMD_RAMWR (0x2CU) +#define LCD_CMD_RAMWRC (0x3CU) +#define LCD_CMD_DISPOFF (0x28U) +#define LCD_CMD_SLPIN (0x10U) +#define QSPI_DMA_BUFFER_COUNT (2U) +#define QSPI_DMA_BUFFER_SIZE (16U * 1024U) +#define QSPI_COLOR_TIMEOUT_MS (1000U) +#if defined(CIRCUITPY_LCD_POWER) +#define CIRCUITPY_QSPIBUS_PANEL_POWER_PIN CIRCUITPY_LCD_POWER +#endif + +#ifndef CIRCUITPY_LCD_POWER_ON_LEVEL +#define CIRCUITPY_LCD_POWER_ON_LEVEL (1) +#endif + +static void qspibus_release_dma_buffers(qspibus_qspibus_obj_t *self) { + for (size_t i = 0; i < QSPI_DMA_BUFFER_COUNT; i++) { + if (self->dma_buffer[i] != NULL) { + heap_caps_free(self->dma_buffer[i]); + self->dma_buffer[i] = NULL; + } + } + self->dma_buffer_size = 0; + self->active_buffer = 0; + self->inflight_transfers = 0; + self->transfer_in_progress = false; +} + +static bool qspibus_allocate_dma_buffers(qspibus_qspibus_obj_t *self) { + const size_t candidates[] = { + QSPI_DMA_BUFFER_SIZE, + QSPI_DMA_BUFFER_SIZE / 2, + QSPI_DMA_BUFFER_SIZE / 4, + }; + + for (size_t c = 0; c < MP_ARRAY_SIZE(candidates); c++) { + size_t size = candidates[c]; + bool ok = true; + for (size_t i = 0; i < QSPI_DMA_BUFFER_COUNT; i++) { + self->dma_buffer[i] = heap_caps_malloc(size, MALLOC_CAP_DMA | MALLOC_CAP_8BIT); + if (self->dma_buffer[i] == NULL) { + ok = false; + break; + } + } + if (ok) { + self->dma_buffer_size = size; + self->active_buffer = 0; + self->inflight_transfers = 0; + self->transfer_in_progress = false; + return true; + } + qspibus_release_dma_buffers(self); + } + return false; +} + +// Reset transfer bookkeeping after timeout/error. Drains any stale semaphore +// tokens that late ISR completions may have posted after the timeout expired. +static void qspibus_reset_transfer_state(qspibus_qspibus_obj_t *self) { + self->inflight_transfers = 0; + self->transfer_in_progress = false; + if (self->transfer_done_sem != NULL) { + while (xSemaphoreTake(self->transfer_done_sem, 0) == pdTRUE) { + } + } +} + +static bool qspibus_wait_one_transfer_done(qspibus_qspibus_obj_t *self, TickType_t timeout) { + if (self->inflight_transfers == 0) { + self->transfer_in_progress = false; + return true; + } + + if (xSemaphoreTake(self->transfer_done_sem, timeout) != pdTRUE) { + return false; + } + self->inflight_transfers--; + self->transfer_in_progress = (self->inflight_transfers > 0); + return true; +} + +static bool qspibus_wait_all_transfers_done(qspibus_qspibus_obj_t *self, TickType_t timeout) { + while (self->inflight_transfers > 0) { + if (!qspibus_wait_one_transfer_done(self, timeout)) { + return false; + } + } + return true; +} + +static void qspibus_send_command_bytes( + qspibus_qspibus_obj_t *self, + uint8_t command, + const uint8_t *data, + size_t len) { + + if (!self->bus_initialized) { + raise_deinited_error(); + } + if (self->inflight_transfers >= QSPI_DMA_BUFFER_COUNT) { + if (!qspibus_wait_one_transfer_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg(MP_ERROR_TEXT("QSPI command timeout")); + } + } + + uint32_t packed_cmd = ((uint32_t)QSPI_OPCODE_WRITE_CMD << 24) | ((uint32_t)command << 8); + esp_err_t err = esp_lcd_panel_io_tx_param(self->io_handle, packed_cmd, data, len); + if (err != ESP_OK) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("QSPI send failed: %d"), err); + } +} + +static void qspibus_send_color_bytes( + qspibus_qspibus_obj_t *self, + uint8_t command, + const uint8_t *data, + size_t len) { + + if (!self->bus_initialized) { + raise_deinited_error(); + } + + if (len == 0) { + qspibus_send_command_bytes(self, command, NULL, 0); + return; + } + if (data == NULL || self->dma_buffer_size == 0) { + mp_raise_OSError_msg(MP_ERROR_TEXT("QSPI DMA buffers unavailable")); + } + + // RAMWR must transition to RAMWRC for continued payload chunks. + uint8_t chunk_command = command; + const uint8_t *cursor = data; + size_t remaining = len; + + while (remaining > 0) { + if (self->inflight_transfers >= QSPI_DMA_BUFFER_COUNT) { + if (!qspibus_wait_one_transfer_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg(MP_ERROR_TEXT("QSPI color timeout")); + } + } + + size_t chunk = remaining; + if (chunk > self->dma_buffer_size) { + chunk = self->dma_buffer_size; + } + + uint8_t *buffer = self->dma_buffer[self->active_buffer]; + memcpy(buffer, cursor, chunk); + + uint32_t packed_cmd = ((uint32_t)QSPI_OPCODE_WRITE_COLOR << 24) | ((uint32_t)chunk_command << 8); + esp_err_t err = esp_lcd_panel_io_tx_color(self->io_handle, packed_cmd, buffer, chunk); + if (err != ESP_OK) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("QSPI send color failed: %d"), err); + } + + self->inflight_transfers++; + self->transfer_in_progress = true; + self->active_buffer = (self->active_buffer + 1) % QSPI_DMA_BUFFER_COUNT; + + if (chunk_command == LCD_CMD_RAMWR) { + chunk_command = LCD_CMD_RAMWRC; + } + + cursor += chunk; + remaining -= chunk; + } + + // Keep Python/API semantics predictable: color transfer call returns only + // after queued DMA chunks have completed. + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg(MP_ERROR_TEXT("QSPI color timeout")); + } +} + +static bool qspibus_is_color_payload_command(uint8_t command) { + return command == LCD_CMD_RAMWR || command == LCD_CMD_RAMWRC; +} + +static void qspibus_panel_sleep_best_effort(qspibus_qspibus_obj_t *self) { + if (!self->bus_initialized || self->io_handle == NULL) { + return; + } + + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + } + + // If a command is buffered, flush it first so the panel state machine + // doesn't get a truncated transaction before sleep. + if (self->has_pending_command) { + uint32_t pending = ((uint32_t)QSPI_OPCODE_WRITE_CMD << 24) | ((uint32_t)self->pending_command << 8); + (void)esp_lcd_panel_io_tx_param(self->io_handle, pending, NULL, 0); + self->has_pending_command = false; + } + + uint32_t disp_off = ((uint32_t)QSPI_OPCODE_WRITE_CMD << 24) | ((uint32_t)LCD_CMD_DISPOFF << 8); + (void)esp_lcd_panel_io_tx_param(self->io_handle, disp_off, NULL, 0); + vTaskDelay(pdMS_TO_TICKS(20)); + + uint32_t sleep_in = ((uint32_t)QSPI_OPCODE_WRITE_CMD << 24) | ((uint32_t)LCD_CMD_SLPIN << 8); + (void)esp_lcd_panel_io_tx_param(self->io_handle, sleep_in, NULL, 0); + vTaskDelay(pdMS_TO_TICKS(120)); +} + +static bool IRAM_ATTR qspibus_on_color_trans_done( + esp_lcd_panel_io_handle_t io_handle, + esp_lcd_panel_io_event_data_t *event_data, + void *user_ctx) { + (void)io_handle; + (void)event_data; + + qspibus_qspibus_obj_t *self = (qspibus_qspibus_obj_t *)user_ctx; + if (self->transfer_done_sem == NULL) { + return false; + } + BaseType_t x_higher_priority_task_woken = pdFALSE; + + xSemaphoreGiveFromISR(self->transfer_done_sem, &x_higher_priority_task_woken); + return x_higher_priority_task_woken == pdTRUE; +} + +void common_hal_qspibus_qspibus_construct( + qspibus_qspibus_obj_t *self, + const mcu_pin_obj_t *clock, + const mcu_pin_obj_t *data0, + const mcu_pin_obj_t *data1, + const mcu_pin_obj_t *data2, + const mcu_pin_obj_t *data3, + const mcu_pin_obj_t *cs, + const mcu_pin_obj_t *dcx, + const mcu_pin_obj_t *reset, + uint32_t frequency) { + + self->io_handle = NULL; + self->host_id = SPI2_HOST; + self->clock_pin = clock->number; + self->data0_pin = data0->number; + self->data1_pin = data1->number; + self->data2_pin = data2->number; + self->data3_pin = data3->number; + self->cs_pin = cs->number; + self->dcx_pin = (dcx != NULL) ? dcx->number : -1; + self->reset_pin = (reset != NULL) ? reset->number : -1; + self->power_pin = -1; + self->frequency = frequency; + self->bus_initialized = false; + self->in_transaction = false; + self->has_pending_command = false; + self->pending_command = 0; + self->transfer_in_progress = false; + self->active_buffer = 0; + self->inflight_transfers = 0; + self->dma_buffer_size = 0; + self->dma_buffer[0] = NULL; + self->dma_buffer[1] = NULL; + self->transfer_done_sem = NULL; + + self->transfer_done_sem = xSemaphoreCreateCounting(QSPI_DMA_BUFFER_COUNT, 0); + if (self->transfer_done_sem == NULL) { + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Failed to create semaphore")); + } + + if (!qspibus_allocate_dma_buffers(self)) { + vSemaphoreDelete(self->transfer_done_sem); + self->transfer_done_sem = NULL; + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Failed to allocate DMA buffers")); + } + + const spi_bus_config_t bus_config = { + .sclk_io_num = self->clock_pin, + .mosi_io_num = self->data0_pin, + .miso_io_num = self->data1_pin, + .quadwp_io_num = self->data2_pin, + .quadhd_io_num = self->data3_pin, + .max_transfer_sz = self->dma_buffer_size, + .flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_GPIO_PINS, + }; + + esp_err_t err = spi_bus_initialize(self->host_id, &bus_config, SPI_DMA_CH_AUTO); + if (err != ESP_OK) { + qspibus_release_dma_buffers(self); + vSemaphoreDelete(self->transfer_done_sem); + self->transfer_done_sem = NULL; + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SPI bus init failed: %d"), err); + } + + const esp_lcd_panel_io_spi_config_t io_config = { + .cs_gpio_num = self->cs_pin, + .dc_gpio_num = -1, + .spi_mode = 0, + .pclk_hz = self->frequency, + .trans_queue_depth = QSPI_DMA_BUFFER_COUNT, + .on_color_trans_done = qspibus_on_color_trans_done, + .user_ctx = self, + .lcd_cmd_bits = 32, + .lcd_param_bits = 8, + .flags = { + .quad_mode = 1, + }, + }; + + err = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)self->host_id, &io_config, &self->io_handle); + if (err != ESP_OK) { + spi_bus_free(self->host_id); + qspibus_release_dma_buffers(self); + vSemaphoreDelete(self->transfer_done_sem); + self->transfer_done_sem = NULL; + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("Panel IO init failed: %d"), err); + } + + claim_pin(clock); + claim_pin(data0); + claim_pin(data1); + claim_pin(data2); + claim_pin(data3); + claim_pin(cs); + if (dcx != NULL) { + claim_pin(dcx); + gpio_set_direction((gpio_num_t)self->dcx_pin, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)self->dcx_pin, 1); + } + + #ifdef CIRCUITPY_QSPIBUS_PANEL_POWER_PIN + const mcu_pin_obj_t *power = CIRCUITPY_QSPIBUS_PANEL_POWER_PIN; + if (power != NULL) { + self->power_pin = power->number; + claim_pin(power); + gpio_set_direction((gpio_num_t)self->power_pin, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)self->power_pin, CIRCUITPY_LCD_POWER_ON_LEVEL ? 1 : 0); + // Panel power rail needs extra settle time before reset/init commands. + vTaskDelay(pdMS_TO_TICKS(200)); + } + #endif + + if (reset != NULL) { + claim_pin(reset); + + gpio_set_direction((gpio_num_t)self->reset_pin, GPIO_MODE_OUTPUT); + gpio_set_level((gpio_num_t)self->reset_pin, 0); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level((gpio_num_t)self->reset_pin, 1); + vTaskDelay(pdMS_TO_TICKS(120)); + } + + self->bus_initialized = true; +} + +void common_hal_qspibus_qspibus_deinit(qspibus_qspibus_obj_t *self) { + if (!self->bus_initialized) { + qspibus_release_dma_buffers(self); + return; + } + + qspibus_panel_sleep_best_effort(self); + self->in_transaction = false; + + if (self->io_handle != NULL) { + esp_lcd_panel_io_del(self->io_handle); + self->io_handle = NULL; + } + + spi_bus_free(self->host_id); + + if (self->transfer_done_sem != NULL) { + // Set NULL before delete so late ISR callbacks (if any) see NULL and skip. + SemaphoreHandle_t sem = self->transfer_done_sem; + self->transfer_done_sem = NULL; + vSemaphoreDelete(sem); + } + + qspibus_release_dma_buffers(self); + + reset_pin_number(self->clock_pin); + reset_pin_number(self->data0_pin); + reset_pin_number(self->data1_pin); + reset_pin_number(self->data2_pin); + reset_pin_number(self->data3_pin); + reset_pin_number(self->cs_pin); + if (self->dcx_pin >= 0) { + reset_pin_number(self->dcx_pin); + } + if (self->power_pin >= 0) { + reset_pin_number(self->power_pin); + } + if (self->reset_pin >= 0) { + reset_pin_number(self->reset_pin); + } + + self->bus_initialized = false; + self->in_transaction = false; + self->has_pending_command = false; + self->pending_command = 0; + self->transfer_in_progress = false; + self->inflight_transfers = 0; +} + +bool common_hal_qspibus_qspibus_deinited(qspibus_qspibus_obj_t *self) { + return !self->bus_initialized; +} + +void common_hal_qspibus_qspibus_send_command( + qspibus_qspibus_obj_t *self, + uint8_t command, + const uint8_t *data, + size_t len) { + qspibus_send_command_bytes(self, command, data, len); +} + + +void common_hal_qspibus_qspibus_write_command( + qspibus_qspibus_obj_t *self, + uint8_t command) { + if (!self->bus_initialized) { + raise_deinited_error(); + } + if (self->in_transaction) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Bus in display transaction")); + } + + // If caller stages command-only operations repeatedly, flush the previous + // pending command as no-data before replacing it. + if (self->has_pending_command) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + } + + self->pending_command = command; + self->has_pending_command = true; +} + +void common_hal_qspibus_qspibus_write_data( + qspibus_qspibus_obj_t *self, + const uint8_t *data, + size_t len) { + if (!self->bus_initialized) { + raise_deinited_error(); + } + if (self->in_transaction) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Bus in display transaction")); + } + if (len == 0) { + if (self->has_pending_command) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + self->has_pending_command = false; + } + return; + } + if (data == NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("Data buffer is null")); + } + if (!self->has_pending_command) { + mp_raise_ValueError(MP_ERROR_TEXT("No pending command")); + } + + if (qspibus_is_color_payload_command(self->pending_command)) { + qspibus_send_color_bytes(self, self->pending_command, data, len); + } else { + qspibus_send_command_bytes(self, self->pending_command, data, len); + } + self->has_pending_command = false; +} + +bool common_hal_qspibus_qspibus_reset(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + if (!self->bus_initialized || self->reset_pin < 0) { + return false; + } + + gpio_set_level((gpio_num_t)self->reset_pin, 0); + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level((gpio_num_t)self->reset_pin, 1); + vTaskDelay(pdMS_TO_TICKS(120)); + return true; +} + +bool common_hal_qspibus_qspibus_bus_free(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + return self->bus_initialized && !self->in_transaction && !self->transfer_in_progress && !self->has_pending_command; +} + +bool common_hal_qspibus_qspibus_begin_transaction(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + if (!self->bus_initialized || self->in_transaction) { + return false; + } + self->in_transaction = true; + self->has_pending_command = false; + self->pending_command = 0; + return true; +} + +void common_hal_qspibus_qspibus_send( + mp_obj_t obj, + display_byte_type_t data_type, + display_chip_select_behavior_t chip_select, + const uint8_t *data, + uint32_t data_length) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + (void)chip_select; + if (!self->bus_initialized) { + raise_deinited_error(); + } + if (!self->in_transaction) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Begin transaction first")); + } + + if (data_type == DISPLAY_COMMAND) { + for (uint32_t i = 0; i < data_length; i++) { + if (self->has_pending_command) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + } + self->pending_command = data[i]; + self->has_pending_command = true; + } + return; + } + + if (!self->has_pending_command) { + if (data_length == 0) { + // Zero-length data write after a no-data command is benign. + return; + } + mp_raise_ValueError(MP_ERROR_TEXT("No pending command")); + } + + if (data_length == 0) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + self->has_pending_command = false; + return; + } + + if (qspibus_is_color_payload_command(self->pending_command)) { + qspibus_send_color_bytes(self, self->pending_command, data, data_length); + } else { + qspibus_send_command_bytes(self, self->pending_command, data, data_length); + } + self->has_pending_command = false; +} + +void common_hal_qspibus_qspibus_end_transaction(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + if (!self->bus_initialized) { + return; + } + if (self->has_pending_command) { + qspibus_send_command_bytes(self, self->pending_command, NULL, 0); + self->has_pending_command = false; + } + self->in_transaction = false; +} + +void common_hal_qspibus_qspibus_collect_ptrs(mp_obj_t obj) { + (void)obj; +} diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.h b/ports/espressif/common-hal/qspibus/QSPIBus.h new file mode 100644 index 00000000000..ba525a0e6ed --- /dev/null +++ b/ports/espressif/common-hal/qspibus/QSPIBus.h @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include + +#include "py/obj.h" + +#include "esp-idf/components/esp_lcd/include/esp_lcd_panel_io.h" +#include "driver/spi_master.h" +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +typedef struct { + mp_obj_base_t base; + + // ESP LCD panel IO handle used for QSPI transactions. + esp_lcd_panel_io_handle_t io_handle; + + // SPI host (SPI2_HOST on ESP32-S3). + spi_host_device_t host_id; + + // Claimed GPIO numbers. + int8_t clock_pin; + int8_t data0_pin; + int8_t data1_pin; + int8_t data2_pin; + int8_t data3_pin; + int8_t cs_pin; + int8_t dcx_pin; // -1 when optional DCX line is not provided. + int8_t reset_pin; // -1 when reset line is not provided. + int8_t power_pin; // -1 when board has no explicit display power pin. + + uint32_t frequency; + bool bus_initialized; + bool in_transaction; + bool has_pending_command; + uint8_t pending_command; + bool transfer_in_progress; + uint8_t active_buffer; + uint8_t inflight_transfers; + size_t dma_buffer_size; + uint8_t *dma_buffer[2]; + + // Signaled from ISR when panel IO transfer completes. + SemaphoreHandle_t transfer_done_sem; +} qspibus_qspibus_obj_t; diff --git a/ports/espressif/common-hal/qspibus/__init__.c b/ports/espressif/common-hal/qspibus/__init__.c new file mode 100644 index 00000000000..4ac7203fd28 --- /dev/null +++ b/ports/espressif/common-hal/qspibus/__init__.c @@ -0,0 +1,3 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT diff --git a/ports/espressif/common-hal/qspibus/__init__.h b/ports/espressif/common-hal/qspibus/__init__.h new file mode 100644 index 00000000000..4ac7203fd28 --- /dev/null +++ b/ports/espressif/common-hal/qspibus/__init__.h @@ -0,0 +1,3 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index d8c95d18a79..ae7ec7da7b7 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -228,6 +228,9 @@ endif ifeq ($(CIRCUITPY_FOURWIRE),1) SRC_PATTERNS += fourwire/% endif +ifeq ($(CIRCUITPY_QSPIBUS),1) +SRC_PATTERNS += qspibus/% +endif ifeq ($(CIRCUITPY_FRAMEBUFFERIO),1) SRC_PATTERNS += framebufferio/% endif @@ -552,6 +555,8 @@ SRC_COMMON_HAL_ALL = \ pulseio/__init__.c \ pwmio/PWMOut.c \ pwmio/__init__.c \ + qspibus/QSPIBus.c \ + qspibus/__init__.c \ rclcpy/__init__.c \ rclcpy/Node.c \ rclcpy/Publisher.c \ diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index f6310dfaf68..1db12ac8ae9 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -399,6 +399,13 @@ typedef long mp_off_t; #define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (128) #endif +// QSPI display buffer size in uint32_t words for _refresh_area() VLA. +// Allocated on stack; boards should verify sufficient stack headroom. +// Default 512 words = 2KB. Override per-board for larger buffers. +#ifndef CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE +#define CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE (512) +#endif + #else #define CIRCUITPY_DISPLAY_LIMIT (0) #define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (0) diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index a1297a47544..ea8412fa3e6 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -262,6 +262,10 @@ CFLAGS += -DCIRCUITPY_BUSDISPLAY=$(CIRCUITPY_BUSDISPLAY) CIRCUITPY_FOURWIRE ?= $(CIRCUITPY_DISPLAYIO) CFLAGS += -DCIRCUITPY_FOURWIRE=$(CIRCUITPY_FOURWIRE) +# QSPI bus protocol for quad-SPI displays (like RM690B0) +CIRCUITPY_QSPIBUS ?= 0 +CFLAGS += -DCIRCUITPY_QSPIBUS=$(CIRCUITPY_QSPIBUS) + CIRCUITPY_EPAPERDISPLAY ?= $(CIRCUITPY_DISPLAYIO) CFLAGS += -DCIRCUITPY_EPAPERDISPLAY=$(CIRCUITPY_EPAPERDISPLAY) diff --git a/shared-bindings/qspibus/QSPIBus.c b/shared-bindings/qspibus/QSPIBus.c new file mode 100644 index 00000000000..18419bf6c55 --- /dev/null +++ b/shared-bindings/qspibus/QSPIBus.c @@ -0,0 +1,222 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared-bindings/qspibus/QSPIBus.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "shared-module/displayio/__init__.h" + +#include "py/binary.h" +#include "py/obj.h" +#include "py/runtime.h" + +static void check_for_deinit(qspibus_qspibus_obj_t *self) { + if (common_hal_qspibus_qspibus_deinited(self)) { + raise_deinited_error(); + } +} + +//| class QSPIBus: +//| """QSPI bus for quad-SPI displays.""" +//| +//| def __init__( +//| self, +//| *, +//| clock: microcontroller.Pin, +//| data0: microcontroller.Pin, +//| data1: microcontroller.Pin, +//| data2: microcontroller.Pin, +//| data3: microcontroller.Pin, +//| cs: microcontroller.Pin, +//| dcx: Optional[microcontroller.Pin] = None, +//| reset: Optional[microcontroller.Pin] = None, +//| frequency: int = 80_000_000, +//| ) -> None: +//| """Create a QSPIBus object for quad-SPI display communication. +//| +//| :param ~microcontroller.Pin clock: QSPI clock pin +//| :param ~microcontroller.Pin data0: QSPI data line 0 +//| :param ~microcontroller.Pin data1: QSPI data line 1 +//| :param ~microcontroller.Pin data2: QSPI data line 2 +//| :param ~microcontroller.Pin data3: QSPI data line 3 +//| :param ~microcontroller.Pin cs: Chip select pin +//| :param ~microcontroller.Pin dcx: Optional data/command select pin. +//| Reserved for future hardware paths. Current ESP32-S3 implementation +//| uses encoded QSPI command words and does not require explicit DCX. +//| :param ~microcontroller.Pin reset: Optional reset pin +//| :param int frequency: Bus frequency in Hz (1-80MHz) +//| """ +//| ... +//| +static mp_obj_t qspibus_qspibus_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + + enum { ARG_clock, ARG_data0, ARG_data1, ARG_data2, ARG_data3, ARG_cs, ARG_dcx, ARG_reset, ARG_frequency }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_data0, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_data1, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_data2, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_data3, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_cs, MP_ARG_KW_ONLY | MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_dcx, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_reset, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_frequency, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 80000000} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *data0 = validate_obj_is_free_pin(args[ARG_data0].u_obj, MP_QSTR_data0); + const mcu_pin_obj_t *data1 = validate_obj_is_free_pin(args[ARG_data1].u_obj, MP_QSTR_data1); + const mcu_pin_obj_t *data2 = validate_obj_is_free_pin(args[ARG_data2].u_obj, MP_QSTR_data2); + const mcu_pin_obj_t *data3 = validate_obj_is_free_pin(args[ARG_data3].u_obj, MP_QSTR_data3); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + const mcu_pin_obj_t *dcx = validate_obj_is_free_pin_or_none(args[ARG_dcx].u_obj, MP_QSTR_dcx); + const mcu_pin_obj_t *reset = validate_obj_is_free_pin_or_none(args[ARG_reset].u_obj, MP_QSTR_reset); + + uint32_t frequency = (uint32_t)mp_arg_validate_int_range(args[ARG_frequency].u_int, 1, 80000000, MP_QSTR_frequency); + + qspibus_qspibus_obj_t *self = &allocate_display_bus_or_raise()->qspi_bus; + self->base.type = &qspibus_qspibus_type; + common_hal_qspibus_qspibus_construct(self, clock, data0, data1, data2, data3, cs, dcx, reset, frequency); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Release QSPI bus resources and claimed pins.""" +//| ... +//| +static mp_obj_t qspibus_qspibus_deinit(mp_obj_t self_in) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_qspibus_qspibus_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(qspibus_qspibus_deinit_obj, qspibus_qspibus_deinit); + +//| def send(self, command: int, data: ReadableBuffer = b"") -> None: +//| """Send command with optional payload bytes. +//| +//| This mirrors FourWire-style convenience API: +//| - command byte is sent first +//| - optional payload bytes follow +//| """ +//| ... +//| +static mp_obj_t qspibus_qspibus_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_command, ARG_data }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_command, MP_ARG_INT | MP_ARG_REQUIRED }, + { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + + uint8_t command = (uint8_t)mp_arg_validate_int_range(args[ARG_command].u_int, 0, 255, MP_QSTR_command); + + const uint8_t *data = NULL; + size_t len = 0; + mp_buffer_info_t data_bufinfo; + if (args[ARG_data].u_obj != mp_const_none) { + mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ); + data = (const uint8_t *)data_bufinfo.buf; + len = data_bufinfo.len; + } + + // Wait for display bus to be available, then acquire transaction. + // Mirrors FourWire.send() pattern: begin_transaction → send → end_transaction. + while (!common_hal_qspibus_qspibus_begin_transaction(MP_OBJ_FROM_PTR(self))) { + RUN_BACKGROUND_TASKS; + } + common_hal_qspibus_qspibus_send(MP_OBJ_FROM_PTR(self), DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, &command, 1); + common_hal_qspibus_qspibus_send(MP_OBJ_FROM_PTR(self), DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, len); + common_hal_qspibus_qspibus_end_transaction(MP_OBJ_FROM_PTR(self)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(qspibus_qspibus_send_obj, 1, qspibus_qspibus_send); + +//| def write_command(self, command: int) -> None: +//| """Stage a command byte for subsequent :py:meth:`write_data`. +//| +//| If a previously staged command had no data, it is sent as +//| a command-only transaction before staging the new one. +//| """ +//| ... +//| +static mp_obj_t qspibus_qspibus_write_command(mp_obj_t self_in, mp_obj_t command_obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + uint8_t command = (uint8_t)mp_arg_validate_int_range(mp_obj_get_int(command_obj), 0, 255, MP_QSTR_command); + common_hal_qspibus_qspibus_write_command(self, command); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(qspibus_qspibus_write_command_obj, qspibus_qspibus_write_command); + +//| def write_data(self, data: ReadableBuffer) -> None: +//| """Send payload bytes for the most recently staged command.""" +//| ... +//| +static mp_obj_t qspibus_qspibus_write_data(mp_obj_t self_in, mp_obj_t data_obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_obj, &bufinfo, MP_BUFFER_READ); + common_hal_qspibus_qspibus_write_data(self, (const uint8_t *)bufinfo.buf, bufinfo.len); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(qspibus_qspibus_write_data_obj, qspibus_qspibus_write_data); + +//| def __enter__(self) -> QSPIBus: +//| """No-op context manager entry.""" +//| ... +//| +static mp_obj_t qspibus_qspibus___enter__(mp_obj_t self_in) { + return self_in; +} +static MP_DEFINE_CONST_FUN_OBJ_1(qspibus_qspibus___enter___obj, qspibus_qspibus___enter__); + +//| def __exit__( +//| self, +//| exc_type: type[BaseException] | None, +//| exc_value: BaseException | None, +//| traceback: TracebackType | None, +//| ) -> None: +//| """Deinitialize on context manager exit.""" +//| ... +//| +static mp_obj_t qspibus_qspibus___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_qspibus_qspibus_deinit(MP_OBJ_TO_PTR(args[0])); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qspibus_qspibus___exit___obj, 4, 4, qspibus_qspibus___exit__); + +static const mp_rom_map_elem_t qspibus_qspibus_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&qspibus_qspibus_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&qspibus_qspibus_send_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_command), MP_ROM_PTR(&qspibus_qspibus_write_command_obj) }, + { MP_ROM_QSTR(MP_QSTR_write_data), MP_ROM_PTR(&qspibus_qspibus_write_data_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&qspibus_qspibus___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&qspibus_qspibus___exit___obj) }, +}; +static MP_DEFINE_CONST_DICT(qspibus_qspibus_locals_dict, qspibus_qspibus_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + qspibus_qspibus_type, + MP_QSTR_QSPIBus, + MP_TYPE_FLAG_NONE, + make_new, qspibus_qspibus_make_new, + locals_dict, &qspibus_qspibus_locals_dict + ); diff --git a/shared-bindings/qspibus/QSPIBus.h b/shared-bindings/qspibus/QSPIBus.h new file mode 100644 index 00000000000..1055ee7c6a5 --- /dev/null +++ b/shared-bindings/qspibus/QSPIBus.h @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" + +#include "shared-bindings/displayio/__init__.h" + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/qspibus/QSPIBus.h" + +extern const mp_obj_type_t qspibus_qspibus_type; + +void common_hal_qspibus_qspibus_construct( + qspibus_qspibus_obj_t *self, + const mcu_pin_obj_t *clock, + const mcu_pin_obj_t *data0, + const mcu_pin_obj_t *data1, + const mcu_pin_obj_t *data2, + const mcu_pin_obj_t *data3, + const mcu_pin_obj_t *cs, + const mcu_pin_obj_t *dcx, + const mcu_pin_obj_t *reset, + uint32_t frequency); + +void common_hal_qspibus_qspibus_deinit(qspibus_qspibus_obj_t *self); +bool common_hal_qspibus_qspibus_deinited(qspibus_qspibus_obj_t *self); + +void common_hal_qspibus_qspibus_send_command( + qspibus_qspibus_obj_t *self, + uint8_t command, + const uint8_t *data, + size_t len); +void common_hal_qspibus_qspibus_write_command( + qspibus_qspibus_obj_t *self, + uint8_t command); +void common_hal_qspibus_qspibus_write_data( + qspibus_qspibus_obj_t *self, + const uint8_t *data, + size_t len); + +bool common_hal_qspibus_qspibus_reset(mp_obj_t obj); +bool common_hal_qspibus_qspibus_bus_free(mp_obj_t obj); +bool common_hal_qspibus_qspibus_begin_transaction(mp_obj_t obj); +void common_hal_qspibus_qspibus_send( + mp_obj_t obj, + display_byte_type_t data_type, + display_chip_select_behavior_t chip_select, + const uint8_t *data, + uint32_t data_length); +void common_hal_qspibus_qspibus_end_transaction(mp_obj_t obj); +void common_hal_qspibus_qspibus_collect_ptrs(mp_obj_t obj); diff --git a/shared-bindings/qspibus/__init__.c b/shared-bindings/qspibus/__init__.c new file mode 100644 index 00000000000..51a5267e30a --- /dev/null +++ b/shared-bindings/qspibus/__init__.c @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/qspibus/__init__.h" +#include "shared-bindings/qspibus/QSPIBus.h" + +//| """QSPI bus protocol for quad-SPI displays +//| +//| The `qspibus` module provides a low-level QSPI bus interface for displays +//| that use four data lines. It is analogous to `fourwire` for standard SPI. +//| +//| Use :class:`qspibus.QSPIBus` to create a bus instance. +//| +//| Example usage:: +//| +//| import board +//| import qspibus +//| import displayio +//| +//| displayio.release_displays() +//| +//| bus = qspibus.QSPIBus( +//| clock=board.LCD_CLK, +//| data0=board.LCD_D0, +//| data1=board.LCD_D1, +//| data2=board.LCD_D2, +//| data3=board.LCD_D3, +//| cs=board.LCD_CS, +//| reset=board.LCD_RESET, +//| frequency=80_000_000, +//| ) +//| """ + +static const mp_rom_map_elem_t qspibus_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_qspibus) }, + { MP_ROM_QSTR(MP_QSTR_QSPIBus), MP_ROM_PTR(&qspibus_qspibus_type) }, +}; + +static MP_DEFINE_CONST_DICT(qspibus_module_globals, qspibus_module_globals_table); + +const mp_obj_module_t qspibus_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&qspibus_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_qspibus, qspibus_module); diff --git a/shared-bindings/qspibus/__init__.h b/shared-bindings/qspibus/__init__.h new file mode 100644 index 00000000000..3604bf04c0e --- /dev/null +++ b/shared-bindings/qspibus/__init__.h @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/qspibus/QSPIBus.h" diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 6ef1c4c7f66..3a8d2721af7 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -16,6 +16,9 @@ #if CIRCUITPY_PARALLELDISPLAYBUS #include "shared-bindings/paralleldisplaybus/ParallelBus.h" #endif +#if CIRCUITPY_QSPIBUS +#include "shared-bindings/qspibus/QSPIBus.h" +#endif #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" #include "shared-module/displayio/__init__.h" @@ -254,6 +257,50 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } } + #if CIRCUITPY_QSPIBUS + // QSPI panels benefit from larger sub-rectangle buffers because each chunk + // has non-trivial command/window overhead. Keep this path qspibus-specific + // to avoid increasing stack usage on other display buses. + if (mp_obj_is_type(self->bus.bus, &qspibus_qspibus_type) && + self->core.colorspace.depth == 16 && + !self->bus.data_as_commands && + !self->bus.SH1107_addressing && + buffer_size < CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE) { + buffer_size = CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE; + rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + } + + if (mp_obj_is_type(self->bus.bus, &qspibus_qspibus_type) && + self->core.colorspace.depth == 16 && + !self->bus.data_as_commands && + displayio_area_height(&clipped) > 1 && + rows_per_buffer < 2 && + (2 * displayio_area_width(&clipped) + pixels_per_word - 1) / pixels_per_word <= CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE) { + rows_per_buffer = 2; + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + } + #endif + // Allocated and shared as a uint32_t array so the compiler knows the // alignment everywhere. uint32_t buffer[buffer_size]; diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index e325a7857f4..ce90bf8f1c3 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -189,6 +189,10 @@ static void common_hal_displayio_release_displays_impl(bool keep_primary) { } else if (bus_type == &mipidsi_display_type) { common_hal_mipidsi_display_deinit(&display_buses[i].mipidsi); #endif + #if CIRCUITPY_QSPIBUS + } else if (bus_type == &qspibus_qspibus_type) { + common_hal_qspibus_qspibus_deinit(&display_buses[i].qspi_bus); + #endif } display_buses[i].bus_base.type = &mp_type_NoneType; } diff --git a/shared-module/displayio/__init__.h b/shared-module/displayio/__init__.h index f2f4691b313..0c6a881ef62 100644 --- a/shared-module/displayio/__init__.h +++ b/shared-module/displayio/__init__.h @@ -41,6 +41,9 @@ #if CIRCUITPY_MIPIDSI #include "shared-bindings/mipidsi/Display.h" #endif +#if CIRCUITPY_QSPIBUS +#include "shared-bindings/qspibus/QSPIBus.h" +#endif // Port unique frame buffers. #if CIRCUITPY_VIDEOCORE #include "bindings/videocore/Framebuffer.h" @@ -87,6 +90,9 @@ typedef struct { #if CIRCUITPY_MIPIDSI mipidsi_display_obj_t mipidsi; #endif + #if CIRCUITPY_QSPIBUS + qspibus_qspibus_obj_t qspi_bus; + #endif }; } primary_display_bus_t; diff --git a/shared-module/displayio/bus_core.c b/shared-module/displayio/bus_core.c index e01b9d9eef6..3a181181051 100644 --- a/shared-module/displayio/bus_core.c +++ b/shared-module/displayio/bus_core.c @@ -17,6 +17,9 @@ #if CIRCUITPY_PARALLELDISPLAYBUS #include "shared-bindings/paralleldisplaybus/ParallelBus.h" #endif +#if CIRCUITPY_QSPIBUS +#include "shared-bindings/qspibus/QSPIBus.h" +#endif #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" #include "shared-module/displayio/__init__.h" @@ -79,6 +82,16 @@ void displayio_display_bus_construct(displayio_display_bus_t *self, self->collect_ptrs = common_hal_i2cdisplaybus_i2cdisplaybus_collect_ptrs; } else #endif + #if CIRCUITPY_QSPIBUS + if (mp_obj_is_type(bus, &qspibus_qspibus_type)) { + self->bus_reset = common_hal_qspibus_qspibus_reset; + self->bus_free = common_hal_qspibus_qspibus_bus_free; + self->begin_transaction = common_hal_qspibus_qspibus_begin_transaction; + self->send = common_hal_qspibus_qspibus_send; + self->end_transaction = common_hal_qspibus_qspibus_end_transaction; + self->collect_ptrs = common_hal_qspibus_qspibus_collect_ptrs; + } else + #endif { mp_raise_ValueError(MP_ERROR_TEXT("Unsupported display bus type")); } From f74912453db3f74f90178bcb5cf26f58faecc92e Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Tue, 24 Feb 2026 23:51:19 +0100 Subject: [PATCH 251/876] qspibus: address code review feedback - Reuse existing CircuitPython error messages to reduce translation burden: "QSPI command/color timeout" -> "Operation timed out", "QSPI send[color] failed: %d" / "SPI bus init failed: %d" / "Panel IO init failed: %d" -> "%q failure: %d", "Failed to allocate DMA buffers" / "QSPI DMA buffers unavailable" -> "Could not allocate DMA capable buffer", "Data buffer is null" -> "Buffer too small". Net removal of 8 unique translatable strings with 0 new ones. - Regenerate locale/circuitpython.pot to remove stale entries. - Add _Static_assert in BusDisplay.c to guard the QSPI stack-allocated refresh buffer size (max 2048 uint32_t words = 8KB). - Add comment clarifying that inflight_transfers bookkeeping is task-context only (ISR only signals semaphore), so no atomics needed. - Fix SPDX file header format across all new qspibus files to match the CircuitPython project convention. --- locale/circuitpython.pot | 41 ++----------------- .../waveshare_esp32_s3_amoled_241/board.c | 2 +- .../mpconfigboard.h | 2 +- .../waveshare_esp32_s3_amoled_241/pins.c | 2 +- ports/espressif/common-hal/qspibus/QSPIBus.c | 25 ++++++----- ports/espressif/common-hal/qspibus/QSPIBus.h | 2 +- ports/espressif/common-hal/qspibus/__init__.c | 2 +- ports/espressif/common-hal/qspibus/__init__.h | 2 +- shared-bindings/qspibus/QSPIBus.c | 2 +- shared-bindings/qspibus/QSPIBus.h | 2 +- shared-bindings/qspibus/__init__.c | 2 +- shared-bindings/qspibus/__init__.h | 2 +- shared-module/busdisplay/BusDisplay.c | 4 ++ 13 files changed, 32 insertions(+), 58 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 1f3d4c0974a..7c66d1de8ce 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -99,6 +99,7 @@ msgid "%q contains duplicate pins" msgstr "" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "" @@ -710,6 +711,7 @@ msgid "Buffer too short by %d bytes" msgstr "" #: ports/cxd56/common-hal/camera/Camera.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/struct/__init__.c shared-module/struct/__init__.c @@ -872,7 +874,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1029,10 +1031,6 @@ msgstr "" msgid "Failed to allocate %q buffer" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Failed to allocate DMA buffers" -msgstr "" - #: ports/espressif/common-hal/wifi/__init__.c msgid "Failed to allocate Wifi memory" msgstr "" @@ -1770,6 +1768,7 @@ msgid "Operation or feature not supported" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "" @@ -1807,11 +1806,6 @@ msgstr "" msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#, c-format -msgid "Panel IO init failed: %d" -msgstr "" - #: shared-module/jpegio/JpegDecoder.c msgid "Parameter error" msgstr "" @@ -1918,28 +1912,6 @@ msgstr "" msgid "Pull not used when direction is output." msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "QSPI DMA buffers unavailable" -msgstr "" - -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "QSPI color timeout" -msgstr "" - -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "QSPI command timeout" -msgstr "" - -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#, c-format -msgid "QSPI send color failed: %d" -msgstr "" - -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#, c-format -msgid "QSPI send failed: %d" -msgstr "" - #: ports/raspberrypi/common-hal/countio/Counter.c msgid "RISE_AND_FALL not available on this chip" msgstr "" @@ -2061,11 +2033,6 @@ msgstr "" msgid "SDIO Init Error %x" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#, c-format -msgid "SPI bus init failed: %d" -msgstr "" - #: ports/espressif/common-hal/busio/SPI.c msgid "SPI configuration failed" msgstr "" diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c index 10ef3d7274c..3941e89a5e4 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #include "supervisor/board.h" diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h index b4d4df961bf..d31dd2e0e84 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #pragma once diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c index 437488e3f2b..ed033419233 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #include "py/obj.h" diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index 7182869b6b6..5041c826aff 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #include "shared-bindings/qspibus/QSPIBus.h" @@ -121,7 +121,7 @@ static void qspibus_send_command_bytes( if (self->inflight_transfers >= QSPI_DMA_BUFFER_COUNT) { if (!qspibus_wait_one_transfer_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { qspibus_reset_transfer_state(self); - mp_raise_OSError_msg(MP_ERROR_TEXT("QSPI command timeout")); + mp_raise_OSError_msg(MP_ERROR_TEXT("Operation timed out")); } } @@ -129,7 +129,7 @@ static void qspibus_send_command_bytes( esp_err_t err = esp_lcd_panel_io_tx_param(self->io_handle, packed_cmd, data, len); if (err != ESP_OK) { qspibus_reset_transfer_state(self); - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("QSPI send failed: %d"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_QSPI, (int)err); } } @@ -148,7 +148,7 @@ static void qspibus_send_color_bytes( return; } if (data == NULL || self->dma_buffer_size == 0) { - mp_raise_OSError_msg(MP_ERROR_TEXT("QSPI DMA buffers unavailable")); + mp_raise_OSError_msg(MP_ERROR_TEXT("Could not allocate DMA capable buffer")); } // RAMWR must transition to RAMWRC for continued payload chunks. @@ -157,10 +157,13 @@ static void qspibus_send_color_bytes( size_t remaining = len; while (remaining > 0) { + // inflight_transfers is only modified in task context (never from ISR), + // so no atomic/critical section is needed. The ISR only signals the + // counting semaphore; all counter bookkeeping happens task-side. if (self->inflight_transfers >= QSPI_DMA_BUFFER_COUNT) { if (!qspibus_wait_one_transfer_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { qspibus_reset_transfer_state(self); - mp_raise_OSError_msg(MP_ERROR_TEXT("QSPI color timeout")); + mp_raise_OSError_msg(MP_ERROR_TEXT("Operation timed out")); } } @@ -176,7 +179,7 @@ static void qspibus_send_color_bytes( esp_err_t err = esp_lcd_panel_io_tx_color(self->io_handle, packed_cmd, buffer, chunk); if (err != ESP_OK) { qspibus_reset_transfer_state(self); - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("QSPI send color failed: %d"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_QSPI, (int)err); } self->inflight_transfers++; @@ -195,7 +198,7 @@ static void qspibus_send_color_bytes( // after queued DMA chunks have completed. if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { qspibus_reset_transfer_state(self); - mp_raise_OSError_msg(MP_ERROR_TEXT("QSPI color timeout")); + mp_raise_OSError_msg(MP_ERROR_TEXT("Operation timed out")); } } @@ -290,7 +293,7 @@ void common_hal_qspibus_qspibus_construct( if (!qspibus_allocate_dma_buffers(self)) { vSemaphoreDelete(self->transfer_done_sem); self->transfer_done_sem = NULL; - mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Failed to allocate DMA buffers")); + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); } const spi_bus_config_t bus_config = { @@ -308,7 +311,7 @@ void common_hal_qspibus_qspibus_construct( qspibus_release_dma_buffers(self); vSemaphoreDelete(self->transfer_done_sem); self->transfer_done_sem = NULL; - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SPI bus init failed: %d"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_SPI, (int)err); } const esp_lcd_panel_io_spi_config_t io_config = { @@ -332,7 +335,7 @@ void common_hal_qspibus_qspibus_construct( qspibus_release_dma_buffers(self); vSemaphoreDelete(self->transfer_done_sem); self->transfer_done_sem = NULL; - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("Panel IO init failed: %d"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_QSPI, (int)err); } claim_pin(clock); @@ -472,7 +475,7 @@ void common_hal_qspibus_qspibus_write_data( return; } if (data == NULL) { - mp_raise_ValueError(MP_ERROR_TEXT("Data buffer is null")); + mp_raise_ValueError(MP_ERROR_TEXT("Buffer too small")); } if (!self->has_pending_command) { mp_raise_ValueError(MP_ERROR_TEXT("No pending command")); diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.h b/ports/espressif/common-hal/qspibus/QSPIBus.h index ba525a0e6ed..caed3661cfd 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.h +++ b/ports/espressif/common-hal/qspibus/QSPIBus.h @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #pragma once diff --git a/ports/espressif/common-hal/qspibus/__init__.c b/ports/espressif/common-hal/qspibus/__init__.c index 4ac7203fd28..2f763b218cb 100644 --- a/ports/espressif/common-hal/qspibus/__init__.c +++ b/ports/espressif/common-hal/qspibus/__init__.c @@ -1,3 +1,3 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT diff --git a/ports/espressif/common-hal/qspibus/__init__.h b/ports/espressif/common-hal/qspibus/__init__.h index 4ac7203fd28..2f763b218cb 100644 --- a/ports/espressif/common-hal/qspibus/__init__.h +++ b/ports/espressif/common-hal/qspibus/__init__.h @@ -1,3 +1,3 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT diff --git a/shared-bindings/qspibus/QSPIBus.c b/shared-bindings/qspibus/QSPIBus.c index 18419bf6c55..60f83682ba0 100644 --- a/shared-bindings/qspibus/QSPIBus.c +++ b/shared-bindings/qspibus/QSPIBus.c @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #include diff --git a/shared-bindings/qspibus/QSPIBus.h b/shared-bindings/qspibus/QSPIBus.h index 1055ee7c6a5..8b8e7f76b3f 100644 --- a/shared-bindings/qspibus/QSPIBus.h +++ b/shared-bindings/qspibus/QSPIBus.h @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #pragma once diff --git a/shared-bindings/qspibus/__init__.c b/shared-bindings/qspibus/__init__.c index 51a5267e30a..0281c41c804 100644 --- a/shared-bindings/qspibus/__init__.c +++ b/shared-bindings/qspibus/__init__.c @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #include "py/obj.h" diff --git a/shared-bindings/qspibus/__init__.h b/shared-bindings/qspibus/__init__.h index 3604bf04c0e..9b4ca243327 100644 --- a/shared-bindings/qspibus/__init__.h +++ b/shared-bindings/qspibus/__init__.h @@ -1,5 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org // SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -// // SPDX-License-Identifier: MIT #pragma once diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 3a8d2721af7..4c1fcb2c458 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -261,6 +261,10 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are // QSPI panels benefit from larger sub-rectangle buffers because each chunk // has non-trivial command/window overhead. Keep this path qspibus-specific // to avoid increasing stack usage on other display buses. + // Guard: buffer is a VLA on stack; 2048 uint32_t words = 8KB is the safe + // upper bound for ESP32-S3's 24KB main task stack. + _Static_assert(CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE <= 2048, + "CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE exceeds safe stack limit (8KB)"); if (mp_obj_is_type(self->bus.bus, &qspibus_qspibus_type) && self->core.colorspace.depth == 16 && !self->bus.data_as_commands && From 21bf0f7ed54bc200037fe4877a5bfa088022405b Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 25 Feb 2026 00:02:34 +0100 Subject: [PATCH 252/876] Update: Fixes in locale/circuitpython.pot --- locale/circuitpython.pot | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 7c66d1de8ce..5d9a525c479 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -874,7 +874,8 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +#: shared-module/usb/core/Device.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Could not allocate DMA capable buffer" msgstr "" From 48aaf516739171dbde8fe41be19261b2c984e58e Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 25 Feb 2026 00:31:53 +0100 Subject: [PATCH 253/876] qspibus: align Python API with FourWire/ParallelBus conventions - Add reset() method binding (common_hal implementation already existed) with "No %q pin" error matching FourWire/ParallelBus pattern. - Remove deinit(), __enter__(), __exit__() from Python API; display bus lifecycle is managed through displayio.release_displays(). - Remove two unreachable data == NULL guards: Python binding validates buffers via mp_get_buffer_raise(), and displayio always passes valid pointers. --- ports/espressif/common-hal/qspibus/QSPIBus.c | 5 +-- shared-bindings/qspibus/QSPIBus.c | 45 ++++++-------------- 2 files changed, 13 insertions(+), 37 deletions(-) diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index 5041c826aff..f6dc10f0b39 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -147,7 +147,7 @@ static void qspibus_send_color_bytes( qspibus_send_command_bytes(self, command, NULL, 0); return; } - if (data == NULL || self->dma_buffer_size == 0) { + if (self->dma_buffer_size == 0) { mp_raise_OSError_msg(MP_ERROR_TEXT("Could not allocate DMA capable buffer")); } @@ -474,9 +474,6 @@ void common_hal_qspibus_qspibus_write_data( } return; } - if (data == NULL) { - mp_raise_ValueError(MP_ERROR_TEXT("Buffer too small")); - } if (!self->has_pending_command) { mp_raise_ValueError(MP_ERROR_TEXT("No pending command")); } diff --git a/shared-bindings/qspibus/QSPIBus.c b/shared-bindings/qspibus/QSPIBus.c index 60f83682ba0..398be4d38c4 100644 --- a/shared-bindings/qspibus/QSPIBus.c +++ b/shared-bindings/qspibus/QSPIBus.c @@ -89,16 +89,22 @@ static mp_obj_t qspibus_qspibus_make_new(const mp_obj_type_t *type, size_t n_arg return MP_OBJ_FROM_PTR(self); } -//| def deinit(self) -> None: -//| """Release QSPI bus resources and claimed pins.""" +//| def reset(self) -> None: +//| """Perform a hardware reset using the reset pin. +//| +//| :raises RuntimeError: if no reset pin was provided at construction. +//| """ //| ... //| -static mp_obj_t qspibus_qspibus_deinit(mp_obj_t self_in) { +static mp_obj_t qspibus_qspibus_obj_reset(mp_obj_t self_in) { qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_qspibus_qspibus_deinit(self); + check_for_deinit(self); + if (!common_hal_qspibus_qspibus_reset(MP_OBJ_FROM_PTR(self))) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("No %q pin"), MP_QSTR_reset); + } return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(qspibus_qspibus_deinit_obj, qspibus_qspibus_deinit); +static MP_DEFINE_CONST_FUN_OBJ_1(qspibus_qspibus_reset_obj, qspibus_qspibus_obj_reset); //| def send(self, command: int, data: ReadableBuffer = b"") -> None: //| """Send command with optional payload bytes. @@ -178,38 +184,11 @@ static mp_obj_t qspibus_qspibus_write_data(mp_obj_t self_in, mp_obj_t data_obj) } MP_DEFINE_CONST_FUN_OBJ_2(qspibus_qspibus_write_data_obj, qspibus_qspibus_write_data); -//| def __enter__(self) -> QSPIBus: -//| """No-op context manager entry.""" -//| ... -//| -static mp_obj_t qspibus_qspibus___enter__(mp_obj_t self_in) { - return self_in; -} -static MP_DEFINE_CONST_FUN_OBJ_1(qspibus_qspibus___enter___obj, qspibus_qspibus___enter__); - -//| def __exit__( -//| self, -//| exc_type: type[BaseException] | None, -//| exc_value: BaseException | None, -//| traceback: TracebackType | None, -//| ) -> None: -//| """Deinitialize on context manager exit.""" -//| ... -//| -static mp_obj_t qspibus_qspibus___exit__(size_t n_args, const mp_obj_t *args) { - (void)n_args; - common_hal_qspibus_qspibus_deinit(MP_OBJ_TO_PTR(args[0])); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(qspibus_qspibus___exit___obj, 4, 4, qspibus_qspibus___exit__); - static const mp_rom_map_elem_t qspibus_qspibus_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&qspibus_qspibus_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_reset), MP_ROM_PTR(&qspibus_qspibus_reset_obj) }, { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&qspibus_qspibus_send_obj) }, { MP_ROM_QSTR(MP_QSTR_write_command), MP_ROM_PTR(&qspibus_qspibus_write_command_obj) }, { MP_ROM_QSTR(MP_QSTR_write_data), MP_ROM_PTR(&qspibus_qspibus_write_data_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&qspibus_qspibus___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&qspibus_qspibus___exit___obj) }, }; static MP_DEFINE_CONST_DICT(qspibus_qspibus_locals_dict, qspibus_qspibus_locals_dict_table); From 1518226147da04f0bf4c51cbbc6b6c68d3478b8e Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 25 Feb 2026 00:53:19 +0100 Subject: [PATCH 254/876] qspibus: fix begin_transaction() consistency and regenerate .pot - Align begin_transaction() with bus_free() by delegating to it, so transfer_in_progress and has_pending_command are checked before entering a transaction. This prevents silently discarding a staged write_command() or starting a transaction during active DMA. - Regenerate locale/circuitpython.pot to remove stale "Data buffer is null" entry left over from the previous round of error message reuse. --- locale/circuitpython.pot | 10 ++-------- ports/espressif/common-hal/qspibus/QSPIBus.c | 4 +--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 5d9a525c479..2779501a19b 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -711,7 +711,6 @@ msgid "Buffer too short by %d bytes" msgstr "" #: ports/cxd56/common-hal/camera/Camera.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/struct/__init__.c shared-module/struct/__init__.c @@ -874,8 +873,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -917,10 +915,6 @@ msgstr "" msgid "Data 0 pin must be byte aligned" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Data buffer is null" -msgstr "" - #: shared-module/jpegio/JpegDecoder.c msgid "Data format error (may be broken data)" msgstr "" @@ -1536,7 +1530,7 @@ msgstr "" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "" diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index f6dc10f0b39..348ac317da4 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -506,12 +506,10 @@ bool common_hal_qspibus_qspibus_bus_free(mp_obj_t obj) { bool common_hal_qspibus_qspibus_begin_transaction(mp_obj_t obj) { qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); - if (!self->bus_initialized || self->in_transaction) { + if (!common_hal_qspibus_qspibus_bus_free(obj)) { return false; } self->in_transaction = true; - self->has_pending_command = false; - self->pending_command = 0; return true; } From 25709c1003728ee04f52e9926404e72ef1de49df Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 25 Feb 2026 00:59:29 +0100 Subject: [PATCH 255/876] qspibus: locale fixes and API cleanups for rm690b0 QSPI display driver (#1) * Initial plan * Fix stale and missing locale entries for qspibus Co-authored-by: ppsx <7107135+ppsx@users.noreply.github.com> * qspibus: three low-cost cleanups consistent with CircuitPython conventions Co-authored-by: ppsx <7107135+ppsx@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ppsx <7107135+ppsx@users.noreply.github.com> Co-authored-by: ppsx --- locale/circuitpython.pot | 8 +++----- ports/espressif/common-hal/qspibus/QSPIBus.c | 11 +---------- shared-bindings/qspibus/QSPIBus.c | 4 ++-- shared-bindings/qspibus/QSPIBus.h | 5 ----- 4 files changed, 6 insertions(+), 22 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 2779501a19b..b01cd445003 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -976,6 +976,7 @@ msgstr "" #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "ESP-IDF memory allocation failed" msgstr "" @@ -1063,10 +1064,6 @@ msgstr "" msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Failed to create semaphore" -msgstr "" - #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Failed to enable continuous" msgstr "" @@ -1530,7 +1527,8 @@ msgstr "" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c +#: shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "" diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index 348ac317da4..bda037c886e 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -287,7 +287,7 @@ void common_hal_qspibus_qspibus_construct( self->transfer_done_sem = xSemaphoreCreateCounting(QSPI_DMA_BUFFER_COUNT, 0); if (self->transfer_done_sem == NULL) { - mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Failed to create semaphore")); + mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("ESP-IDF memory allocation failed")); } if (!qspibus_allocate_dma_buffers(self)) { @@ -428,15 +428,6 @@ bool common_hal_qspibus_qspibus_deinited(qspibus_qspibus_obj_t *self) { return !self->bus_initialized; } -void common_hal_qspibus_qspibus_send_command( - qspibus_qspibus_obj_t *self, - uint8_t command, - const uint8_t *data, - size_t len) { - qspibus_send_command_bytes(self, command, data, len); -} - - void common_hal_qspibus_qspibus_write_command( qspibus_qspibus_obj_t *self, uint8_t command) { diff --git a/shared-bindings/qspibus/QSPIBus.c b/shared-bindings/qspibus/QSPIBus.c index 398be4d38c4..cc4fdc91c06 100644 --- a/shared-bindings/qspibus/QSPIBus.c +++ b/shared-bindings/qspibus/QSPIBus.c @@ -106,7 +106,7 @@ static mp_obj_t qspibus_qspibus_obj_reset(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(qspibus_qspibus_reset_obj, qspibus_qspibus_obj_reset); -//| def send(self, command: int, data: ReadableBuffer = b"") -> None: +//| def send(self, command: int, data: Optional[ReadableBuffer] = None) -> None: //| """Send command with optional payload bytes. //| //| This mirrors FourWire-style convenience API: @@ -119,7 +119,7 @@ static mp_obj_t qspibus_qspibus_send(size_t n_args, const mp_obj_t *pos_args, mp enum { ARG_command, ARG_data }; static const mp_arg_t allowed_args[] = { { MP_QSTR_command, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_empty_bytes} }, + { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; diff --git a/shared-bindings/qspibus/QSPIBus.h b/shared-bindings/qspibus/QSPIBus.h index 8b8e7f76b3f..a5d8f824ad2 100644 --- a/shared-bindings/qspibus/QSPIBus.h +++ b/shared-bindings/qspibus/QSPIBus.h @@ -31,11 +31,6 @@ void common_hal_qspibus_qspibus_construct( void common_hal_qspibus_qspibus_deinit(qspibus_qspibus_obj_t *self); bool common_hal_qspibus_qspibus_deinited(qspibus_qspibus_obj_t *self); -void common_hal_qspibus_qspibus_send_command( - qspibus_qspibus_obj_t *self, - uint8_t command, - const uint8_t *data, - size_t len); void common_hal_qspibus_qspibus_write_command( qspibus_qspibus_obj_t *self, uint8_t command); From 6c2a5ce6e596c3aab2d36243dbca838473f656dd Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 25 Feb 2026 14:29:17 +0100 Subject: [PATCH 256/876] The last license header and the temple of doom (pot file) --- locale/circuitpython.pot | 3 ++- .../boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index b01cd445003..e19fcc266eb 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -873,7 +873,8 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +#: shared-module/usb/core/Device.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Could not allocate DMA capable buffer" msgstr "" diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk index 0546d906933..127eec2e8b6 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk @@ -1,5 +1,5 @@ +# This file is part of the CircuitPython project: https://circuitpython.org # SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha -# # SPDX-License-Identifier: MIT CIRCUITPY_CREATOR_ID = 0x57415645 # 'WAVE' (Waveshare) From cb468b8510cfea852cbad65cfa8d2736031af646 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 25 Feb 2026 20:56:54 +0100 Subject: [PATCH 257/876] ~20% improvements in data transfer when drawing --- ports/espressif/common-hal/qspibus/QSPIBus.c | 33 +++-- shared-module/busdisplay/BusDisplay.c | 120 +++++++++++++------ shared-module/displayio/TileGrid.c | 69 +++++++++++ shared-module/displayio/bus_core.h | 6 + 4 files changed, 183 insertions(+), 45 deletions(-) diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index bda037c886e..0e74fcf1fdf 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -194,12 +194,11 @@ static void qspibus_send_color_bytes( remaining -= chunk; } - // Keep Python/API semantics predictable: color transfer call returns only - // after queued DMA chunks have completed. - if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { - qspibus_reset_transfer_state(self); - mp_raise_OSError_msg(MP_ERROR_TEXT("Operation timed out")); - } + // Let DMA complete asynchronously. The next begin_transaction() will + // wait for all in-flight transfers, allowing fill_area() computation + // to overlap with DMA. The explicit wait is only needed for the + // Python write_data() API path where callers expect the transfer to + // be finished on return. } static bool qspibus_is_color_payload_command(uint8_t command) { @@ -465,12 +464,19 @@ void common_hal_qspibus_qspibus_write_data( } return; } - if (!self->has_pending_command) { + if (!self->has_pending_command) { mp_raise_ValueError(MP_ERROR_TEXT("No pending command")); } if (qspibus_is_color_payload_command(self->pending_command)) { qspibus_send_color_bytes(self, self->pending_command, data, len); + // Python API: wait for DMA to finish so callers see the transfer as + // complete on return. The internal displayio path skips this wait + // to allow fill_area/DMA overlap. + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + mp_raise_OSError_msg(MP_ERROR_TEXT("Operation timed out")); + } } else { qspibus_send_command_bytes(self, self->pending_command, data, len); } @@ -497,9 +503,20 @@ bool common_hal_qspibus_qspibus_bus_free(mp_obj_t obj) { bool common_hal_qspibus_qspibus_begin_transaction(mp_obj_t obj) { qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); - if (!common_hal_qspibus_qspibus_bus_free(obj)) { + if (!self->bus_initialized || self->in_transaction || self->has_pending_command) { return false; } + // Wait for any in-flight DMA to complete before starting a new + // transaction. This replaces the old non-blocking bus_free() check + // and enables fill_area()/DMA overlap: the CPU fills the next + // subrectangle while the previous DMA runs, and this wait only + // blocks when we actually need the bus for the next send. + if (self->transfer_in_progress) { + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + return false; + } + } self->in_transaction = true; return true; } diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 4c1fcb2c458..1994a25214c 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -217,7 +217,7 @@ static void _send_pixels(busdisplay_busdisplay_obj_t *self, uint8_t *pixels, uin } static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_area_t *area) { - uint16_t buffer_size = 128; // In uint32_ts + uint32_t buffer_size = 128; // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. @@ -226,7 +226,7 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } uint16_t rows_per_buffer = displayio_area_height(&clipped); uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; - uint16_t pixels_per_buffer = displayio_area_size(&clipped); + uint32_t pixels_per_buffer = displayio_area_size(&clipped); uint16_t subrectangles = 1; // for SH1107 and other boundary constrained controllers @@ -265,7 +265,8 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are // upper bound for ESP32-S3's 24KB main task stack. _Static_assert(CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE <= 2048, "CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE exceeds safe stack limit (8KB)"); - if (mp_obj_is_type(self->bus.bus, &qspibus_qspibus_type) && + bool is_qspi_bus = mp_obj_is_type(self->bus.bus, &qspibus_qspibus_type); + if (is_qspi_bus && self->core.colorspace.depth == 16 && !self->bus.data_as_commands && !self->bus.SH1107_addressing && @@ -275,6 +276,10 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are if (rows_per_buffer == 0) { rows_per_buffer = 1; } + // Clamp to actual display height. + if (rows_per_buffer > displayio_area_height(&clipped)) { + rows_per_buffer = displayio_area_height(&clipped); + } subrectangles = displayio_area_height(&clipped) / rows_per_buffer; if (displayio_area_height(&clipped) % rows_per_buffer != 0) { subrectangles++; @@ -284,32 +289,31 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are if (pixels_per_buffer % pixels_per_word) { buffer_size += 1; } - } - if (mp_obj_is_type(self->bus.bus, &qspibus_qspibus_type) && - self->core.colorspace.depth == 16 && - !self->bus.data_as_commands && - displayio_area_height(&clipped) > 1 && - rows_per_buffer < 2 && - (2 * displayio_area_width(&clipped) + pixels_per_word - 1) / pixels_per_word <= CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE) { - rows_per_buffer = 2; - subrectangles = displayio_area_height(&clipped) / rows_per_buffer; - if (displayio_area_height(&clipped) % rows_per_buffer != 0) { - subrectangles++; - } - pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); - buffer_size = pixels_per_buffer / pixels_per_word; - if (pixels_per_buffer % pixels_per_word) { - buffer_size += 1; + // Ensure at least 2 rows per buffer when possible. + if (rows_per_buffer < 2 && + displayio_area_height(&clipped) > 1 && + (uint32_t)((2 * displayio_area_width(&clipped) + pixels_per_word - 1) / pixels_per_word) <= (uint32_t)CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE) { + rows_per_buffer = 2; + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } } } #endif // Allocated and shared as a uint32_t array so the compiler knows the // alignment everywhere. - uint32_t buffer[buffer_size]; uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t buffer[buffer_size]; uint32_t mask[mask_length]; + uint16_t remaining_rows = displayio_area_height(&clipped); for (uint16_t j = 0; j < subrectangles; j++) { @@ -324,28 +328,55 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } remaining_rows -= rows_per_buffer; - displayio_display_bus_set_region_to_update(&self->bus, &self->core, &subrectangle); + #if CIRCUITPY_QSPIBUS + if (is_qspi_bus) { + // QSPI path: fill_area first (overlaps with previous DMA), + // then single-transaction set_region + RAMWR + pixels. + // depth is always 16 here (guarded by is_qspi_bus check above). + uint32_t subrectangle_size_bytes = (uint32_t)displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); - uint16_t subrectangle_size_bytes; - if (self->core.colorspace.depth >= 8) { - subrectangle_size_bytes = displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); - } else { - subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); - } + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); + + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - memset(mask, 0, mask_length * sizeof(mask[0])); - memset(buffer, 0, buffer_size * sizeof(buffer[0])); + // begin_transaction waits for any prior async DMA to finish, + // so fill_area above overlaps with previous DMA. + if (!displayio_display_bus_begin_transaction(&self->bus)) { + // Transaction failed (bus deinitialized, timeout, etc.). + // Bail out to prevent calling send() outside a transaction. + return false; + } + displayio_display_bus_send_region_commands(&self->bus, &self->core, &subrectangle); + _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); + displayio_display_bus_end_transaction(&self->bus); + } else + #endif + { + // Non-QSPI path: original ordering preserved exactly. + displayio_display_bus_set_region_to_update(&self->bus, &self->core, &subrectangle); + + uint16_t subrectangle_size_bytes; + if (self->core.colorspace.depth >= 8) { + subrectangle_size_bytes = displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); + } else { + subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); + } - displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); - // Can't acquire display bus; skip the rest of the data. - if (!displayio_display_bus_is_free(&self->bus)) { - return false; - } + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - displayio_display_bus_begin_transaction(&self->bus); - _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); - displayio_display_bus_end_transaction(&self->bus); + // Can't acquire display bus; skip the rest of the data. + if (!displayio_display_bus_is_free(&self->bus)) { + return false; + } + + displayio_display_bus_begin_transaction(&self->bus); + _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); + displayio_display_bus_end_transaction(&self->bus); + } // Run background tasks so they can run during an explicit refresh. // Auto-refresh won't run background tasks here because it is a background task itself. @@ -356,6 +387,21 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are usb_background(); #endif } + + #if CIRCUITPY_QSPIBUS + if (is_qspi_bus) { + // Drain the last async DMA transfer before returning. + // Within the loop, begin_transaction() waits for the PREVIOUS + // subrectangle's DMA, enabling fill_area/DMA overlap. But the + // LAST subrectangle's DMA is still in-flight when the loop ends. + // Without this drain, bus_free() returns false on the next + // refresh() call, causing it to be silently skipped. + if (displayio_display_bus_begin_transaction(&self->bus)) { + displayio_display_bus_end_transaction(&self->bus); + } + } + #endif + return true; } diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index b5c691ccbd6..96f8b682fdd 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -512,6 +512,75 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, y_shift = temp_shift; } + // Fast path for the common case: single-tile, 16bpp bitmap with Palette, + // no transforms, full coverage. Inlines bitmap access and palette cache + // lookup to eliminate per-pixel function-call overhead (~4-5x speedup). + if (full_coverage && + colorspace->depth == 16 && + self->width_in_tiles == 1 && + self->height_in_tiles == 1 && + self->absolute_transform->scale == 1 && + self->absolute_transform->dx == 1 && + self->absolute_transform->dy == 1 && + !self->absolute_transform->transpose_xy && + !self->flip_x && !self->flip_y && + !self->transpose_xy && + x_stride == 1 && y_stride == displayio_area_width(area) && + x_shift == 0 && y_shift == 0 && + mp_obj_is_type(self->bitmap, &displayio_bitmap_type) && + mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) { + + displayio_bitmap_t *bmp = MP_OBJ_TO_PTR(self->bitmap); + displayio_palette_t *pal = MP_OBJ_TO_PTR(self->pixel_shader); + + if (bmp->bits_per_value == 16 && !pal->dither) { + uint16_t *out = (uint16_t *)buffer; + bool all_opaque = true; + + // Process all pixels with inlined bitmap access and palette cache. + uint32_t idx = 0; + for (int16_t y = start_y; y < end_y; ++y) { + // Direct row pointer into bitmap data (16bpp → uint16_t). + // stride is in uint32_t units, so multiply by 2 for uint16_t indexing. + const uint16_t *bmp_row = ((const uint16_t *)bmp->data) + y * (bmp->stride * 2); + + for (int16_t x = start_x; x < end_x; ++x) { + uint16_t px_index = bmp_row[x]; + + // Inline palette cache check (avoids function call overhead). + if (px_index < pal->color_count) { + _displayio_color_t *color = &pal->colors[px_index]; + if (color->transparent) { + all_opaque = false; + idx++; + continue; + } + if (color->cached_colorspace == colorspace && + color->cached_colorspace_grayscale_bit == colorspace->grayscale_bit && + color->cached_colorspace_grayscale == colorspace->grayscale) { + out[idx] = (uint16_t)color->cached_color; + } else { + // Cache miss — do full conversion, then cache. + displayio_input_pixel_t in_px = {.pixel = px_index}; + displayio_output_pixel_t out_px = {.opaque = true}; + displayio_palette_get_color(pal, colorspace, &in_px, &out_px); + out[idx] = (uint16_t)out_px.pixel; + } + } else { + // Out of palette range — transparent. + all_opaque = false; + idx++; + continue; + } + mask[idx >> 5] |= 1u << (idx & 31); + idx++; + } + } + + return all_opaque; + } + } + displayio_input_pixel_t input_pixel; displayio_output_pixel_t output_pixel; diff --git a/shared-module/displayio/bus_core.h b/shared-module/displayio/bus_core.h index 838454c92e6..bd7e51aeb45 100644 --- a/shared-module/displayio/bus_core.h +++ b/shared-module/displayio/bus_core.h @@ -49,6 +49,12 @@ void displayio_display_bus_end_transaction(displayio_display_bus_t *self); void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area); +#if CIRCUITPY_QSPIBUS +// Send column/row window commands within an already-open transaction. +// Caller must have called displayio_display_bus_begin_transaction() first. +void displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area); +#endif + void release_display_bus(displayio_display_bus_t *self); void displayio_display_bus_collect_ptrs(displayio_display_bus_t *self); From ad93dd94f2d4d02047da9949ae95d5b7e2b27df4 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 25 Feb 2026 21:12:15 +0100 Subject: [PATCH 258/876] Proper VID/PID --- .../boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk index 127eec2e8b6..17d53001001 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk @@ -5,9 +5,8 @@ CIRCUITPY_CREATOR_ID = 0x57415645 # 'WAVE' (Waveshare) CIRCUITPY_CREATION_ID = 0x41323431 # 'A241' (AMOLED 2.41) -# USB identifiers - from Arduino pins_arduino.h USB_VID = 0x303A -USB_PID = 0x82CE +USB_PID = 0x8278 USB_MANUFACTURER = "Waveshare" USB_PRODUCT = "ESP32-S3-Touch-AMOLED-2.41" From 1ff419ade6755a9bb12ea9e77645205c6a1763b1 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 25 Feb 2026 21:28:11 +0100 Subject: [PATCH 259/876] displayio: make region command sends reusable for QSPI transactions Refactor display bus region-update command emission into a shared helper with optional transaction management. Keep the existing public path unchanged, and add a QSPIBus-only entrypoint that can send region commands without nesting begin/end transaction calls. Also remove the TileGrid 16bpp+Palette fast path so fill_area uses the generic path, and fix indentation in QSPIBus write_data. --- ports/espressif/common-hal/qspibus/QSPIBus.c | 2 +- shared-module/displayio/TileGrid.c | 69 -------------------- shared-module/displayio/bus_core.c | 44 ++++++++++--- 3 files changed, 36 insertions(+), 79 deletions(-) diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index 0e74fcf1fdf..91f16d233de 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -464,7 +464,7 @@ void common_hal_qspibus_qspibus_write_data( } return; } - if (!self->has_pending_command) { + if (!self->has_pending_command) { mp_raise_ValueError(MP_ERROR_TEXT("No pending command")); } diff --git a/shared-module/displayio/TileGrid.c b/shared-module/displayio/TileGrid.c index 96f8b682fdd..b5c691ccbd6 100644 --- a/shared-module/displayio/TileGrid.c +++ b/shared-module/displayio/TileGrid.c @@ -512,75 +512,6 @@ bool displayio_tilegrid_fill_area(displayio_tilegrid_t *self, y_shift = temp_shift; } - // Fast path for the common case: single-tile, 16bpp bitmap with Palette, - // no transforms, full coverage. Inlines bitmap access and palette cache - // lookup to eliminate per-pixel function-call overhead (~4-5x speedup). - if (full_coverage && - colorspace->depth == 16 && - self->width_in_tiles == 1 && - self->height_in_tiles == 1 && - self->absolute_transform->scale == 1 && - self->absolute_transform->dx == 1 && - self->absolute_transform->dy == 1 && - !self->absolute_transform->transpose_xy && - !self->flip_x && !self->flip_y && - !self->transpose_xy && - x_stride == 1 && y_stride == displayio_area_width(area) && - x_shift == 0 && y_shift == 0 && - mp_obj_is_type(self->bitmap, &displayio_bitmap_type) && - mp_obj_is_type(self->pixel_shader, &displayio_palette_type)) { - - displayio_bitmap_t *bmp = MP_OBJ_TO_PTR(self->bitmap); - displayio_palette_t *pal = MP_OBJ_TO_PTR(self->pixel_shader); - - if (bmp->bits_per_value == 16 && !pal->dither) { - uint16_t *out = (uint16_t *)buffer; - bool all_opaque = true; - - // Process all pixels with inlined bitmap access and palette cache. - uint32_t idx = 0; - for (int16_t y = start_y; y < end_y; ++y) { - // Direct row pointer into bitmap data (16bpp → uint16_t). - // stride is in uint32_t units, so multiply by 2 for uint16_t indexing. - const uint16_t *bmp_row = ((const uint16_t *)bmp->data) + y * (bmp->stride * 2); - - for (int16_t x = start_x; x < end_x; ++x) { - uint16_t px_index = bmp_row[x]; - - // Inline palette cache check (avoids function call overhead). - if (px_index < pal->color_count) { - _displayio_color_t *color = &pal->colors[px_index]; - if (color->transparent) { - all_opaque = false; - idx++; - continue; - } - if (color->cached_colorspace == colorspace && - color->cached_colorspace_grayscale_bit == colorspace->grayscale_bit && - color->cached_colorspace_grayscale == colorspace->grayscale) { - out[idx] = (uint16_t)color->cached_color; - } else { - // Cache miss — do full conversion, then cache. - displayio_input_pixel_t in_px = {.pixel = px_index}; - displayio_output_pixel_t out_px = {.opaque = true}; - displayio_palette_get_color(pal, colorspace, &in_px, &out_px); - out[idx] = (uint16_t)out_px.pixel; - } - } else { - // Out of palette range — transparent. - all_opaque = false; - idx++; - continue; - } - mask[idx >> 5] |= 1u << (idx & 31); - idx++; - } - } - - return all_opaque; - } - } - displayio_input_pixel_t input_pixel; displayio_output_pixel_t output_pixel; diff --git a/shared-module/displayio/bus_core.c b/shared-module/displayio/bus_core.c index 3a181181051..5afa42f26fd 100644 --- a/shared-module/displayio/bus_core.c +++ b/shared-module/displayio/bus_core.c @@ -114,7 +114,7 @@ void displayio_display_bus_end_transaction(displayio_display_bus_t *self) { self->end_transaction(self->bus); } -void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { +static void _displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area, bool manage_transactions) { uint16_t x1 = area->x1 + self->colstart; uint16_t x2 = area->x2 + self->colstart; uint16_t y1 = area->y1 + self->rowstart; @@ -141,7 +141,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d } // Set column. - displayio_display_bus_begin_transaction(self); + if (manage_transactions) { + displayio_display_bus_begin_transaction(self); + } uint8_t data[5]; data[0] = self->column_command; uint8_t data_length = 1; @@ -176,20 +178,28 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d } self->send(self->bus, data_type, chip_select, data, data_length); - displayio_display_bus_end_transaction(self); + if (manage_transactions) { + displayio_display_bus_end_transaction(self); + } if (self->set_current_column_command != NO_COMMAND) { uint8_t command = self->set_current_column_command; - displayio_display_bus_begin_transaction(self); + if (manage_transactions) { + displayio_display_bus_begin_transaction(self); + } self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); // Only send the first half of data because it is the first coordinate. self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); - displayio_display_bus_end_transaction(self); + if (manage_transactions) { + displayio_display_bus_end_transaction(self); + } } // Set row. - displayio_display_bus_begin_transaction(self); + if (manage_transactions) { + displayio_display_bus_begin_transaction(self); + } data[0] = self->row_command; data_length = 1; if (!self->data_as_commands) { @@ -220,18 +230,34 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d } self->send(self->bus, data_type, chip_select, data, data_length); - displayio_display_bus_end_transaction(self); + if (manage_transactions) { + displayio_display_bus_end_transaction(self); + } if (self->set_current_row_command != NO_COMMAND) { uint8_t command = self->set_current_row_command; - displayio_display_bus_begin_transaction(self); + if (manage_transactions) { + displayio_display_bus_begin_transaction(self); + } self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); // Only send the first half of data because it is the first coordinate. self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); - displayio_display_bus_end_transaction(self); + if (manage_transactions) { + displayio_display_bus_end_transaction(self); + } } } +void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { + _displayio_display_bus_send_region_commands(self, display, area, true); +} + +#if CIRCUITPY_QSPIBUS +void displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { + _displayio_display_bus_send_region_commands(self, display, area, false); +} +#endif + void displayio_display_bus_collect_ptrs(displayio_display_bus_t *self) { self->collect_ptrs(self->bus); } From dee2d9fe87d2388acf8819873a0f64cf899ca11b Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 25 Feb 2026 21:34:31 +0100 Subject: [PATCH 260/876] Proper VID/PID --- .../boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h index d31dd2e0e84..5c1aec08d96 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -9,7 +9,7 @@ // USB identifiers #define USB_VID 0x303A -#define USB_PID 0x82CE +#define USB_PID 0x8278 #define USB_MANUFACTURER "Waveshare" #define USB_PRODUCT "ESP32-S3-Touch-AMOLED-2.41" From 3c8e7f85e87388018b30748b1d3ab6413d28f357 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 15:55:25 +0100 Subject: [PATCH 261/876] Workaround for an issue with esp-idf 5.5.3 --- .../boards/waveshare_esp32_s3_amoled_241/sdkconfig | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig index 3ef898aed3e..4b70697b575 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig @@ -29,5 +29,18 @@ CONFIG_LWIP_LOCAL_HOSTNAME="waveshare-esp32-s3-amoled" # Disable USB-Serial/JTAG console - CircuitPython uses TinyUSB (USB OTG) for REPL CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=n +# === TEMPORARY DEBUG: route console to UART0 (TX=GPIO43, RX=GPIO44) === +# CONFIG_ESP_CONSOLE_UART_DEFAULT=y +# CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y +# CONFIG_LOG_DEFAULT_LEVEL_INFO=y +# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y +# === END TEMPORARY DEBUG === + +# Workaround: NimBLE BLE_STATIC_TO_DYNAMIC=y (default in IDF 5.5.3) causes +# ble_gap_vars to be a dynamically allocated pointer (NULL before ble_gap_init). +# CircuitPython calls ble_gap_adv_active() before NimBLE init → NULL deref → bootloop. +# Reverting to static allocation avoids the crash. +CONFIG_BT_NIMBLE_STATIC_TO_DYNAMIC=n + # Enable .app_desc structure CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 From 347296c86608baf78402d556696b261631603d1e Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 17:44:41 +0100 Subject: [PATCH 262/876] Fixing Copilot findings --- py/circuitpy_mpconfig.h | 7 +++++++ shared-module/busdisplay/BusDisplay.c | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 1db12ac8ae9..c7509753ec6 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -406,6 +406,13 @@ typedef long mp_off_t; #define CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE (512) #endif +// Port-level upper bound for the QSPI display buffer (uint32_t words). +// The _Static_assert in BusDisplay.c enforces this at compile time. +// Ports with larger stacks can raise this in mpconfigport.h. +#ifndef CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE_MAX +#define CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE_MAX (2048) +#endif + #else #define CIRCUITPY_DISPLAY_LIMIT (0) #define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (0) diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 1994a25214c..f22cd78a16e 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -261,10 +261,10 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are // QSPI panels benefit from larger sub-rectangle buffers because each chunk // has non-trivial command/window overhead. Keep this path qspibus-specific // to avoid increasing stack usage on other display buses. - // Guard: buffer is a VLA on stack; 2048 uint32_t words = 8KB is the safe - // upper bound for ESP32-S3's 24KB main task stack. - _Static_assert(CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE <= 2048, - "CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE exceeds safe stack limit (8KB)"); + // Guard: buffer is a VLA on stack. The port-specific max keeps shared + // code free of single-port assumptions (default 2048 words = 8KB). + _Static_assert(CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE <= CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE_MAX, + "CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE exceeds CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE_MAX"); bool is_qspi_bus = mp_obj_is_type(self->bus.bus, &qspibus_qspibus_type); if (is_qspi_bus && self->core.colorspace.depth == 16 && From b2149f2c1fd34b59c9b9af0eb5d9281c9ef24bb0 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 18:01:59 +0100 Subject: [PATCH 263/876] Fixing Copilot findings (2) --- ports/espressif/common-hal/qspibus/QSPIBus.c | 3 +++ shared-module/busdisplay/BusDisplay.c | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index 91f16d233de..2a262f520d8 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -352,6 +352,9 @@ void common_hal_qspibus_qspibus_construct( #ifdef CIRCUITPY_QSPIBUS_PANEL_POWER_PIN const mcu_pin_obj_t *power = CIRCUITPY_QSPIBUS_PANEL_POWER_PIN; if (power != NULL) { + if (!common_hal_mcu_pin_is_free(power)) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_power); + } self->power_pin = power->number; claim_pin(power); gpio_set_direction((gpio_num_t)self->power_pin, GPIO_MODE_OUTPUT); diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index f22cd78a16e..4610721a061 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -329,10 +329,12 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are remaining_rows -= rows_per_buffer; #if CIRCUITPY_QSPIBUS - if (is_qspi_bus) { + if (is_qspi_bus && + self->core.colorspace.depth >= 8 && + !self->bus.data_as_commands && + !self->bus.SH1107_addressing) { // QSPI path: fill_area first (overlaps with previous DMA), // then single-transaction set_region + RAMWR + pixels. - // depth is always 16 here (guarded by is_qspi_bus check above). uint32_t subrectangle_size_bytes = (uint32_t)displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); memset(mask, 0, mask_length * sizeof(mask[0])); From 170451819696319cb01363b8a1992b4d461af3ab Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 18:40:08 +0100 Subject: [PATCH 264/876] Fixing Copilot findings (3) --- ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig | 2 +- ports/espressif/common-hal/qspibus/QSPIBus.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig index 4b70697b575..01a370d1dbd 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig @@ -10,7 +10,7 @@ CONFIG_SPIRAM_MODE_OCT=y CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y CONFIG_SPIRAM_RODATA=y CONFIG_SPIRAM_SPEED_80M=y -CONFIG_SPIRAM_MEMTEST=y +CONFIG_SPIRAM_MEMTEST=n CONFIG_SPIRAM_CLK_IO=39 CONFIG_SPIRAM_CS_IO=38 diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index 2a262f520d8..46b6f339962 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -353,7 +353,7 @@ void common_hal_qspibus_qspibus_construct( const mcu_pin_obj_t *power = CIRCUITPY_QSPIBUS_PANEL_POWER_PIN; if (power != NULL) { if (!common_hal_mcu_pin_is_free(power)) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_power); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_LCD_POWER); } self->power_pin = power->number; claim_pin(power); From 2bd02fada26a32f5c888c6168883b21c7f059911 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 19:22:13 +0100 Subject: [PATCH 265/876] Made board.DISPLAY available --- .../waveshare_esp32_s3_amoled_241/board.c | 87 +++++++++++++++++++ .../mpconfigboard.h | 4 +- .../waveshare_esp32_s3_amoled_241/pins.c | 4 + 3 files changed, 93 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c index 3941e89a5e4..36d25e6fa33 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c @@ -3,6 +3,93 @@ // SPDX-License-Identifier: MIT #include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "shared-bindings/qspibus/QSPIBus.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" + +// RM690B0 AMOLED initialization sequence. +// Format: command byte, length | 0x80 (if delay), data bytes..., [delay ms] +// Based on vendor recommendations, tested with Waveshare 2.41" AMOLED panel. +static const uint8_t display_init_sequence[] = { + // Page select and configuration + 0xFE, 0x01, 0x20, // Enter user command mode + 0x26, 0x01, 0x0A, // Bias setting + 0x24, 0x01, 0x80, // Source output control + 0xFE, 0x01, 0x13, // Page 13 + 0xEB, 0x01, 0x0E, // Vendor command + 0xFE, 0x01, 0x00, // Return to page 0 + // Display configuration + 0x3A, 0x01, 0x55, // COLMOD: 16-bit RGB565 + 0xC2, 0x81, 0x00, 0x0A, // Vendor command + 10ms delay + 0x35, 0x00, // Tearing effect line on (no data) + 0x51, 0x81, 0x00, 0x0A, // Brightness control + 10ms delay + // Power on + 0x11, 0x80, 0x50, // Sleep out + 80ms delay + // Display window (MV=1: CASET→rows, RASET→cols) + 0x2A, 0x04, 0x00, 0x10, 0x01, 0xD1, // CASET: 16..465 (450px + 16 offset) + 0x2B, 0x04, 0x00, 0x00, 0x02, 0x57, // RASET: 0..599 (600px) + // Enable display + 0x29, 0x80, 0x0A, // Display on + 10ms delay + // Memory access: MV=1, ML=1 for landscape + 0x36, 0x81, 0x30, 0x0A, // MADCTL + 10ms delay + // Brightness + 0x51, 0x01, 0xFF, // Set brightness to maximum +}; void board_init(void) { + // 1. Allocate and construct QSPI bus + qspibus_qspibus_obj_t *bus = &allocate_display_bus_or_raise()->qspi_bus; + bus->base.type = &qspibus_qspibus_type; + + common_hal_qspibus_qspibus_construct(bus, + CIRCUITPY_LCD_CLK, // clock + CIRCUITPY_LCD_D0, // data0 + CIRCUITPY_LCD_D1, // data1 + CIRCUITPY_LCD_D2, // data2 + CIRCUITPY_LCD_D3, // data3 + CIRCUITPY_LCD_CS, // cs + NULL, // dcx (not used, QSPI uses encoded commands) + CIRCUITPY_LCD_RESET, // reset + 40000000); // 40 MHz + + // 2. Allocate and construct BusDisplay with RM690B0 init sequence. + // Physical panel: 450 cols × 600 rows. + // MADCTL MV=1 swaps row/col → logical 600×450 landscape. + busdisplay_busdisplay_obj_t *display = &allocate_display_or_raise()->display; + display->base.type = &busdisplay_busdisplay_type; + + common_hal_busdisplay_busdisplay_construct(display, + bus, + 600, // width (logical, after MV=1 swap) + 450, // height (logical, after MV=1 swap) + 0, // colstart + 16, // rowstart (physical row offset) + 0, // rotation + 16, // color_depth (RGB565) + false, // grayscale + false, // pixels_in_byte_share_row + 1, // bytes_per_cell + false, // reverse_pixels_in_byte + false, // reverse_bytes_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // set_column_command + MIPI_COMMAND_SET_PAGE_ADDRESS, // set_row_command + MIPI_COMMAND_WRITE_MEMORY_START, // write_ram_command + (uint8_t *)display_init_sequence, + sizeof(display_init_sequence), + NULL, // backlight_pin (AMOLED — no backlight GPIO) + 0x51, // brightness_command + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 60, // native_frames_per_second + true, // backlight_on_high + false, // SH1107_addressing + 50000); // backlight_pwm_frequency } + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h index 5c1aec08d96..fcd3c0e5b03 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -21,8 +21,8 @@ // ESP32-S3 main task stack is 24KB; verified safe with this board. #define CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE (2048) -// AMOLED Display (displayio + qspibus path) -#define CIRCUITPY_BOARD_DISPLAY (0) +// AMOLED Display (displayio + qspibus path) - initialized in board_init() +#define CIRCUITPY_BOARD_DISPLAY (1) #define CIRCUITPY_LCD_CS (&pin_GPIO9) #define CIRCUITPY_LCD_CLK (&pin_GPIO10) #define CIRCUITPY_LCD_D0 (&pin_GPIO11) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c index ed033419233..937847b6838 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c @@ -6,6 +6,7 @@ #include "py/mphal.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -96,5 +97,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, // Available { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, // Available { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, // Available + + // Board display (initialized in board_init) + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From d20581be6d9fa04d1e7b472172e186a321818a49 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 19:41:40 +0100 Subject: [PATCH 266/876] Removed temp debug settings --- .../boards/waveshare_esp32_s3_amoled_241/sdkconfig | 7 ------- 1 file changed, 7 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig index 01a370d1dbd..b6c009f3116 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig @@ -29,13 +29,6 @@ CONFIG_LWIP_LOCAL_HOSTNAME="waveshare-esp32-s3-amoled" # Disable USB-Serial/JTAG console - CircuitPython uses TinyUSB (USB OTG) for REPL CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=n -# === TEMPORARY DEBUG: route console to UART0 (TX=GPIO43, RX=GPIO44) === -# CONFIG_ESP_CONSOLE_UART_DEFAULT=y -# CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y -# CONFIG_LOG_DEFAULT_LEVEL_INFO=y -# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y -# === END TEMPORARY DEBUG === - # Workaround: NimBLE BLE_STATIC_TO_DYNAMIC=y (default in IDF 5.5.3) causes # ble_gap_vars to be a dynamically allocated pointer (NULL before ble_gap_init). # CircuitPython calls ble_gap_adv_active() before NimBLE init → NULL deref → bootloop. From 4e4461e46a2a5f0f46d262fea1617a73a43af766 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 20:00:41 +0100 Subject: [PATCH 267/876] Fixing Copilot findings (4) --- ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c index 36d25e6fa33..29dbb64050a 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c @@ -14,7 +14,8 @@ // RM690B0 AMOLED initialization sequence. // Format: command byte, length | 0x80 (if delay), data bytes..., [delay ms] // Based on vendor recommendations, tested with Waveshare 2.41" AMOLED panel. -static const uint8_t display_init_sequence[] = { +// Non-const to match upstream common_hal_busdisplay_busdisplay_construct signature. +static uint8_t display_init_sequence[] = { // Page select and configuration 0xFE, 0x01, 0x20, // Enter user command mode 0x26, 0x01, 0x0A, // Bias setting @@ -78,7 +79,7 @@ void board_init(void) { MIPI_COMMAND_SET_COLUMN_ADDRESS, // set_column_command MIPI_COMMAND_SET_PAGE_ADDRESS, // set_row_command MIPI_COMMAND_WRITE_MEMORY_START, // write_ram_command - (uint8_t *)display_init_sequence, + display_init_sequence, sizeof(display_init_sequence), NULL, // backlight_pin (AMOLED — no backlight GPIO) 0x51, // brightness_command From bdea5218d2731c1812091324d2adc5e3fd4c3b6c Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 20:15:41 +0100 Subject: [PATCH 268/876] Fixing Copilot findings (5) --- ports/espressif/common-hal/qspibus/QSPIBus.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index 46b6f339962..33c5f128206 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -156,6 +156,15 @@ static void qspibus_send_color_bytes( const uint8_t *cursor = data; size_t remaining = len; + // Drain stale semaphore tokens that late ISR completions may have + // posted after a previous qspibus_reset_transfer_state(). Without + // this, a stale token could satisfy a future wait, causing the next + // transfer to skip its real DMA-done wait. + if (self->inflight_transfers == 0 && self->transfer_done_sem != NULL) { + while (xSemaphoreTake(self->transfer_done_sem, 0) == pdTRUE) { + } + } + while (remaining > 0) { // inflight_transfers is only modified in task context (never from ISR), // so no atomic/critical section is needed. The ISR only signals the From 79eb389f0777da893bd4b5e4a1045497dcec8995 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 20:33:04 +0100 Subject: [PATCH 269/876] Fixing Copilot findings (6) --- shared-bindings/qspibus/QSPIBus.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shared-bindings/qspibus/QSPIBus.c b/shared-bindings/qspibus/QSPIBus.c index cc4fdc91c06..1452d2ddd86 100644 --- a/shared-bindings/qspibus/QSPIBus.c +++ b/shared-bindings/qspibus/QSPIBus.c @@ -139,8 +139,14 @@ static mp_obj_t qspibus_qspibus_send(size_t n_args, const mp_obj_t *pos_args, mp len = data_bufinfo.len; } + // Flush any pending command from a prior write_command() call. + // begin_transaction() returns false while has_pending_command is set, + // so entering the wait loop without flushing would spin forever. + if (self->has_pending_command) { + common_hal_qspibus_qspibus_write_data(self, NULL, 0); + } + // Wait for display bus to be available, then acquire transaction. - // Mirrors FourWire.send() pattern: begin_transaction → send → end_transaction. while (!common_hal_qspibus_qspibus_begin_transaction(MP_OBJ_FROM_PTR(self))) { RUN_BACKGROUND_TASKS; } From 11299b3afe2b06fb7dd4e4d77a1acadeffdc71da Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Thu, 26 Feb 2026 21:04:56 +0100 Subject: [PATCH 270/876] Fixing Copilot findings (7) --- shared-bindings/qspibus/QSPIBus.c | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/shared-bindings/qspibus/QSPIBus.c b/shared-bindings/qspibus/QSPIBus.c index 1452d2ddd86..24c3089213f 100644 --- a/shared-bindings/qspibus/QSPIBus.c +++ b/shared-bindings/qspibus/QSPIBus.c @@ -106,20 +106,18 @@ static mp_obj_t qspibus_qspibus_obj_reset(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(qspibus_qspibus_reset_obj, qspibus_qspibus_obj_reset); -//| def send(self, command: int, data: Optional[ReadableBuffer] = None) -> None: -//| """Send command with optional payload bytes. -//| -//| This mirrors FourWire-style convenience API: -//| - command byte is sent first -//| - optional payload bytes follow -//| """ +//| def send( +//| self, command: int, data: ReadableBuffer, *, toggle_every_byte: bool = False +//| ) -> None: +//| """Sends the given command value followed by the full set of data. Display state, such as +//| vertical scroll, set via ``send`` may or may not be reset once the code is done.""" //| ... //| static mp_obj_t qspibus_qspibus_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_command, ARG_data }; static const mp_arg_t allowed_args[] = { { MP_QSTR_command, MP_ARG_INT | MP_ARG_REQUIRED }, - { MP_QSTR_data, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; @@ -130,14 +128,8 @@ static mp_obj_t qspibus_qspibus_send(size_t n_args, const mp_obj_t *pos_args, mp uint8_t command = (uint8_t)mp_arg_validate_int_range(args[ARG_command].u_int, 0, 255, MP_QSTR_command); - const uint8_t *data = NULL; - size_t len = 0; - mp_buffer_info_t data_bufinfo; - if (args[ARG_data].u_obj != mp_const_none) { - mp_get_buffer_raise(args[ARG_data].u_obj, &data_bufinfo, MP_BUFFER_READ); - data = (const uint8_t *)data_bufinfo.buf; - len = data_bufinfo.len; - } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_data].u_obj, &bufinfo, MP_BUFFER_READ); // Flush any pending command from a prior write_command() call. // begin_transaction() returns false while has_pending_command is set, @@ -151,7 +143,7 @@ static mp_obj_t qspibus_qspibus_send(size_t n_args, const mp_obj_t *pos_args, mp RUN_BACKGROUND_TASKS; } common_hal_qspibus_qspibus_send(MP_OBJ_FROM_PTR(self), DISPLAY_COMMAND, CHIP_SELECT_UNTOUCHED, &command, 1); - common_hal_qspibus_qspibus_send(MP_OBJ_FROM_PTR(self), DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, len); + common_hal_qspibus_qspibus_send(MP_OBJ_FROM_PTR(self), DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ((uint8_t *)bufinfo.buf), bufinfo.len); common_hal_qspibus_qspibus_end_transaction(MP_OBJ_FROM_PTR(self)); return mp_const_none; } From 551bc83e642e24ce6280298b51b26d8bd762fe0d Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Fri, 27 Feb 2026 12:16:21 +0100 Subject: [PATCH 271/876] Added common touch pins definitions --- .../boards/waveshare_esp32_s3_amoled_241/pins.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c index 937847b6838..8804cace06d 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/pins.c @@ -32,9 +32,14 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO48) }, // Touch Panel (FT6336U on I2C) - { MP_ROM_QSTR(MP_QSTR_TP_SDA), MP_ROM_PTR(&pin_GPIO47) }, - { MP_ROM_QSTR(MP_QSTR_TP_SCL), MP_ROM_PTR(&pin_GPIO48) }, - { MP_ROM_QSTR(MP_QSTR_TP_RESET), MP_ROM_PTR(&pin_GPIO3) }, + // NOTE: TP_INT is routed through the TCA9554 IO expander (EXIO2), + // not a direct ESP32-S3 GPIO — no TOUCH_INT alias is possible here. + { MP_ROM_QSTR(MP_QSTR_TP_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_TP_SCL), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_TP_RESET), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_SCL), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_TOUCH_RST), MP_ROM_PTR(&pin_GPIO3) }, // RTC (PCF85063 on I2C) { MP_ROM_QSTR(MP_QSTR_RTC_SDA), MP_ROM_PTR(&pin_GPIO47) }, From a01d36036fe242e33c8aeaacfad7873e4f9759a7 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 1 Mar 2026 14:05:48 -0500 Subject: [PATCH 272/876] Espressif SPI: remove duplicate mutex create --- ports/espressif/common-hal/busio/SPI.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/ports/espressif/common-hal/busio/SPI.c b/ports/espressif/common-hal/busio/SPI.c index 4c07917b20b..fc12d40fccb 100644 --- a/ports/espressif/common-hal/busio/SPI.c +++ b/ports/espressif/common-hal/busio/SPI.c @@ -72,11 +72,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("All SPI peripherals are in use")); } - self->mutex = xSemaphoreCreateMutex(); - if (self->mutex == NULL) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to create lock")); - } - esp_err_t result = spi_bus_initialize(self->host_id, &bus_config, SPI_DMA_CH_AUTO); if (result == ESP_ERR_NO_MEM) { mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("ESP-IDF memory allocation failed")); @@ -166,7 +161,7 @@ bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) { return false; } - return xSemaphoreTake(self->mutex, 1) == pdTRUE; + return xSemaphoreTake(self->mutex, 0) == pdTRUE; } bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { From 77fcc6fa96aae33d3da2c5639054514bd83b6ea4 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 1 Mar 2026 14:06:50 -0500 Subject: [PATCH 273/876] use CONFIG_ESP_CONSOLE_UART_{TX,RX}_GPIO instead of deprecated CONFIG_CONSOLE_UART_*_GPIO --- ports/espressif/supervisor/port.c | 8 ++++---- py/mpconfig.h | 6 ++++++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 192a9171716..46914330798 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -251,12 +251,12 @@ safe_mode_t port_init(void) { #define pin_GPIOn(n) pin_GPIO##n #define pin_GPIOn_EXPAND(x) pin_GPIOn(x) - #ifdef CONFIG_CONSOLE_UART_TX_GPIO - common_hal_never_reset_pin(&pin_GPIOn_EXPAND(CONFIG_CONSOLE_UART_TX_GPIO)); + #ifdef CONFIG_ESP_CONSOLE_UART_TX_GPIO + common_hal_never_reset_pin(&pin_GPIOn_EXPAND(CONFIG_ESP_CONSOLE_UART_TX_GPIO)); #endif - #ifdef CONFIG_CONSOLE_UART_RX_GPIO - common_hal_never_reset_pin(&pin_GPIOn_EXPAND(CONFIG_CONSOLE_UART_RX_GPIO)); + #ifdef CONFIG_ESP_CONSOLE_UART_RX_GPIO + common_hal_never_reset_pin(&pin_GPIOn_EXPAND(CONFIG_ESP_CONSOLE_UART_RX_GPIO)); #endif #ifndef ENABLE_JTAG diff --git a/py/mpconfig.h b/py/mpconfig.h index a4895820061..5ff568e64b0 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -2205,6 +2205,12 @@ typedef double mp_float_t; #define MP_INLINE inline MP_NO_INSTRUMENT #endif +// CIRCUITPY-CHANGE +// Modifier for functions whose return value should not be ignored +#ifndef MP_WARN_UNUSED_RESULT +#define MP_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#endif + // Modifier for functions which should be never inlined #ifndef MP_NOINLINE #define MP_NOINLINE __attribute__((noinline)) From bcc33faf67737e461720b2eb6125a7d702820397 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 1 Mar 2026 14:11:44 -0500 Subject: [PATCH 274/876] displayio: check whether we locked the bus or not --- shared-module/busdisplay/BusDisplay.c | 9 +++++--- shared-module/displayio/bus_core.c | 23 ++++++++++++++++----- shared-module/epaperdisplay/EPaperDisplay.c | 14 ++++++++++--- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 6ef1c4c7f66..d320d4f13ea 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -6,6 +6,7 @@ #include "shared-bindings/busdisplay/BusDisplay.h" +#include "py/mphal.h" #include "py/runtime.h" #if CIRCUITPY_FOURWIRE #include "shared-bindings/fourwire/FourWire.h" @@ -16,6 +17,7 @@ #if CIRCUITPY_PARALLELDISPLAYBUS #include "shared-bindings/paralleldisplaybus/ParallelBus.h" #endif +#include "shared/runtime/interrupt_char.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" #include "shared-module/displayio/__init__.h" @@ -73,6 +75,9 @@ void common_hal_busdisplay_busdisplay_construct(busdisplay_busdisplay_obj_t *sel uint8_t *data = cmd + 2; while (!displayio_display_bus_begin_transaction(&self->bus)) { RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_display); + } } if (self->bus.data_as_commands) { uint8_t full_command[data_size + 1]; @@ -288,11 +293,9 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); // Can't acquire display bus; skip the rest of the data. - if (!displayio_display_bus_is_free(&self->bus)) { + if (!displayio_display_bus_begin_transaction(&self->bus)) { return false; } - - displayio_display_bus_begin_transaction(&self->bus); _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); displayio_display_bus_end_transaction(&self->bus); diff --git a/shared-module/displayio/bus_core.c b/shared-module/displayio/bus_core.c index e01b9d9eef6..4f0d7c4d9d2 100644 --- a/shared-module/displayio/bus_core.c +++ b/shared-module/displayio/bus_core.c @@ -85,11 +85,16 @@ void displayio_display_bus_construct(displayio_display_bus_t *self, self->bus = bus; } +// This is just a hint, and is not a reliable result, since the bus could be grabbed in between this called +// and the attempt to use the bus. Use displayio_display_bus_begin_transaction(), which is atomic. bool displayio_display_bus_is_free(displayio_display_bus_t *self) { return !self->bus || self->bus_free(self->bus); } -bool displayio_display_bus_begin_transaction(displayio_display_bus_t *self) { +MP_WARN_UNUSED_RESULT bool displayio_display_bus_begin_transaction(displayio_display_bus_t *self) { + if (!self->bus) { + return false; + } mp_obj_base_t *bus_base = MP_OBJ_TO_PTR(self->bus); if (bus_base->type == &mp_type_NoneType) { return false; @@ -128,7 +133,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d } // Set column. - displayio_display_bus_begin_transaction(self); + if (!displayio_display_bus_begin_transaction(self)) { + return; + } uint8_t data[5]; data[0] = self->column_command; uint8_t data_length = 1; @@ -167,7 +174,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d if (self->set_current_column_command != NO_COMMAND) { uint8_t command = self->set_current_column_command; - displayio_display_bus_begin_transaction(self); + if (!displayio_display_bus_begin_transaction(self)) { + return; + } self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); // Only send the first half of data because it is the first coordinate. self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); @@ -176,7 +185,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d // Set row. - displayio_display_bus_begin_transaction(self); + if (!displayio_display_bus_begin_transaction(self)) { + return; + } data[0] = self->row_command; data_length = 1; if (!self->data_as_commands) { @@ -211,7 +222,9 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d if (self->set_current_row_command != NO_COMMAND) { uint8_t command = self->set_current_row_command; - displayio_display_bus_begin_transaction(self); + if (!displayio_display_bus_begin_transaction(self)) { + return; + } self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); // Only send the first half of data because it is the first coordinate. self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); diff --git a/shared-module/epaperdisplay/EPaperDisplay.c b/shared-module/epaperdisplay/EPaperDisplay.c index 655ae103071..d34be9d5c7c 100644 --- a/shared-module/epaperdisplay/EPaperDisplay.c +++ b/shared-module/epaperdisplay/EPaperDisplay.c @@ -153,7 +153,10 @@ static void send_command_sequence(epaperdisplay_epaperdisplay_obj_t *self, data_size = ((data_size & ~DELAY) << 8) + *(cmd + 2); data = cmd + 3; } - displayio_display_bus_begin_transaction(&self->bus); + while (!displayio_display_bus_begin_transaction(&self->bus) && + !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + } self->bus.send(self->bus.bus, DISPLAY_COMMAND, self->chip_select, cmd, 1); self->bus.send(self->bus.bus, DISPLAY_DATA, self->chip_select, data, data_size); displayio_display_bus_end_transaction(&self->bus); @@ -311,7 +314,10 @@ static bool epaperdisplay_epaperdisplay_refresh_area(epaperdisplay_epaperdisplay if (pass == 1) { write_command = self->write_color_ram_command; } - displayio_display_bus_begin_transaction(&self->bus); + if (!displayio_display_bus_begin_transaction(&self->bus)) { + // Display bus not available now. + return false; + } self->bus.send(self->bus.bus, DISPLAY_COMMAND, self->chip_select, &write_command, 1); displayio_display_bus_end_transaction(&self->bus); @@ -388,7 +394,9 @@ static bool _clean_area(epaperdisplay_epaperdisplay_obj_t *self) { memset(buffer, 0x77, width / 2); uint8_t write_command = self->write_black_ram_command; - displayio_display_bus_begin_transaction(&self->bus); + if (displayio_display_bus_begin_transaction(&self->bus)) { + return false; + } self->bus.send(self->bus.bus, DISPLAY_COMMAND, self->chip_select, &write_command, 1); displayio_display_bus_end_transaction(&self->bus); From 882701bca07c97735df6ccc00f2df20da21180c5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 2 Mar 2026 12:07:04 -0800 Subject: [PATCH 275/876] Fix build --- .../boards/adafruit_feather_nrf52840_uf2.conf | 1 - ports/zephyr-cp/boards/frdm_rw612.conf | 5 +-- ports/zephyr-cp/boards/frdm_rw612.overlay | 2 +- .../mimxrt1170_evk_mimxrt1176_cm7.overlay | 12 +++--- .../zephyr-cp/boards/stm32wba65i_dk1.overlay | 6 +-- ports/zephyr-cp/cptools/zephyr2cp.py | 43 ++++++++++++++----- ports/zephyr-cp/socs/stm32h7b3xx.conf | 3 -- ports/zephyr-cp/socs/stm32u575xx.conf | 2 - 8 files changed, 44 insertions(+), 30 deletions(-) diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf index c30c8c19fcd..4849c8ce2b4 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf @@ -6,4 +6,3 @@ CONFIG_BT_OBSERVER=y CONFIG_BT_EXT_ADV=y CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n -CONFIG_BOARD_REQUIRES_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf index 7d56dfed29c..4fc5c8c5bf0 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.conf +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -2,7 +2,6 @@ CONFIG_NETWORKING=y CONFIG_NET_IPV4=y CONFIG_NET_DHCPV4=y CONFIG_NET_SOCKETS=y -CONFIG_NET_SOCKETS_POSIX_NAMES=y CONFIG_WIFI=y CONFIG_NET_L2_WIFI_MGMT=y @@ -17,9 +16,9 @@ CONFIG_MBEDTLS=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y CONFIG_MBEDTLS_RSA_C=y CONFIG_MBEDTLS_PKCS1_V15=y -CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_ENABLED=y +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=y CONFIG_MBEDTLS_ENTROPY_C=y -CONFIG_MBEDTLS_CTR_DRBG_ENABLED=y +CONFIG_MBEDTLS_CTR_DRBG_C=y CONFIG_MBEDTLS_SHA1=y CONFIG_MBEDTLS_USE_PSA_CRYPTO=n diff --git a/ports/zephyr-cp/boards/frdm_rw612.overlay b/ports/zephyr-cp/boards/frdm_rw612.overlay index 1c38f42c4ab..c6a021d9999 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.overlay +++ b/ports/zephyr-cp/boards/frdm_rw612.overlay @@ -1,6 +1,6 @@ &w25q512jvfiq { partitions { - /delete-node/ storage_partition; + /delete-node/ partition@620000; circuitpy_partition: partition@620000 { label = "circuitpy"; reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay index d6f6d4f0c15..89a78998cea 100644 --- a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay +++ b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -1,10 +1,10 @@ &is25wp128 { - partitions{ - /delete-node/ storage_partition; - circuitpy_partition: partition@E20000 { - label = "circuitpy"; - reg = <0x00E20000 (DT_SIZE_M(2) - DT_SIZE_K(128))>; - }; + partitions { + /delete-node/ partition@e20000; + circuitpy_partition: partition@e20000 { + label = "circuitpy"; + reg = <0x00e20000 (DT_SIZE_M(2) - DT_SIZE_K(128))>; + }; }; }; diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay index 1b6e55ba462..3b72ffc9984 100644 --- a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay +++ b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay @@ -47,15 +47,13 @@ }; zephyr_udc0: &usbotg_hs { - clocks = <&rcc STM32_CLOCK(AHB2, 14)>, - <&rcc STM32_SRC_HSE OTGHS_SEL(0)>; - pinctrl-0 = <&usb_otg_hs_dm_pd7 &usb_otg_hs_dp_pd6>; - pinctrl-names = "default"; status = "okay"; }; &otghs_phy { /* OTG HS clock source is 32 MHz HSE */ + clocks = <&rcc STM32_CLOCK(AHB2, 15)>, + <&rcc STM32_SRC_HSE OTGHS_SEL(0)>; clock-reference = "SYSCFG_OTG_HS_PHY_CLK_32MHz"; status = "okay"; }; diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 7c78113b95b..f7d79517195 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -96,6 +96,19 @@ "D12", "D13", ], + "nordic,expansion-board-header": [ + "P1_04", + "P1_05", + "P1_06", + "P1_07", + "P1_08", + "P1_09", + "P1_10", + "P1_11", + "P1_12", + "P1_13", + "P1_14", + ], "arducam,dvp-20pin-connector": [ "SCL", "SDA", @@ -544,16 +557,26 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa all_ioports.append(node.labels[0]) if status == "okay": ioports[node.labels[0]] = set(range(0, ngpios)) - if gpio_map and compatible[0] != "gpio-nexus": - i = 0 - for offset, t, label in gpio_map._markers: - if not label: - continue - num = int.from_bytes(gpio_map.value[offset + 4 : offset + 8], "big") - if (label, num) not in board_names: - board_names[(label, num)] = [] - board_names[(label, num)].append(CONNECTORS[compatible[0]][i]) - i += 1 + if gpio_map and compatible and compatible[0] != "gpio-nexus": + connector_pins = CONNECTORS.get(compatible[0], None) + if connector_pins is None: + logger.warning(f"Unsupported connector mapping compatible: {compatible[0]}") + else: + i = 0 + for offset, t, label in gpio_map._markers: + if not label: + continue + if i >= len(connector_pins): + logger.warning( + f"Connector mapping for {compatible[0]} has more pins than names; " + f"stopping at {len(connector_pins)}" + ) + break + num = int.from_bytes(gpio_map.value[offset + 4 : offset + 8], "big") + if (label, num) not in board_names: + board_names[(label, num)] = [] + board_names[(label, num)].append(connector_pins[i]) + i += 1 if "gpio-leds" in compatible: for led in node.nodes: led = node.nodes[led] diff --git a/ports/zephyr-cp/socs/stm32h7b3xx.conf b/ports/zephyr-cp/socs/stm32h7b3xx.conf index 3c7daeb753d..14a93b52ce8 100644 --- a/ports/zephyr-cp/socs/stm32h7b3xx.conf +++ b/ports/zephyr-cp/socs/stm32h7b3xx.conf @@ -1,4 +1 @@ -CONFIG_USE_STM32_LL_USB=y -CONFIG_USE_STM32_HAL_PCD=y - CONFIG_MEMC=y diff --git a/ports/zephyr-cp/socs/stm32u575xx.conf b/ports/zephyr-cp/socs/stm32u575xx.conf index 78cefbfef40..e69de29bb2d 100644 --- a/ports/zephyr-cp/socs/stm32u575xx.conf +++ b/ports/zephyr-cp/socs/stm32u575xx.conf @@ -1,2 +0,0 @@ -CONFIG_USE_STM32_LL_USB=y -CONFIG_USE_STM32_HAL_PCD=y From 00ce600ebe54e455548ad4413de70f6dfb3c4b92 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 2 Mar 2026 13:17:19 -0800 Subject: [PATCH 276/876] Update autogen. Board names changed --- ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index c24d0a85273..91a2776ae74 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -1,5 +1,5 @@ # This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. -name = "NXP Semiconductors FRDM_RW612" +name = "NXP Semiconductors FRDM-RW612" [modules] __future__ = true diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index b2f384e21c1..6f648df82fb 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -1,5 +1,5 @@ # This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. -name = "NXP Semiconductors MIMXRT1170-EVK/EVKB" +name = "NXP Semiconductors MIMXRT1170-EVK" [modules] __future__ = true From ac11cb27c47d819c1a0d9738111ded0bb88d4aef Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 24 Feb 2026 11:49:27 -0800 Subject: [PATCH 277/876] Implement Zephyr bleio connect and disconnect Rework the conn_handle related functions because they are port-internal API. Signed-off-by: Scott Shawcroft --- .../ble_hci/common-hal/_bleio/Connection.h | 1 + locale/circuitpython.pot | 27 +- .../espressif/common-hal/_bleio/Connection.h | 1 + ports/nordic/common-hal/_bleio/Attribute.h | 9 + ports/nordic/common-hal/_bleio/Connection.h | 1 + ports/silabs/common-hal/_bleio/Connection.h | 1 + .../boards/nrf5340bsim_nrf5340_cpuapp.conf | 11 + ports/zephyr-cp/common-hal/_bleio/Adapter.c | 252 ++++++++++++++++-- ports/zephyr-cp/common-hal/_bleio/Adapter.h | 3 +- .../zephyr-cp/common-hal/_bleio/Connection.c | 68 ++++- .../zephyr-cp/common-hal/_bleio/Connection.h | 26 +- ports/zephyr-cp/common-hal/_bleio/__init__.c | 56 ++-- .../zephyr-cp/cptools/build_circuitpython.py | 3 +- ports/zephyr-cp/supervisor/port.c | 8 - .../tests/bsim/test_bsim_ble_connect.py | 119 +++++++++ shared-bindings/_bleio/Adapter.c | 17 +- shared-bindings/_bleio/Address.c | 13 +- shared-bindings/_bleio/Characteristic.c | 6 +- shared-bindings/_bleio/Descriptor.c | 6 +- shared-bindings/_bleio/PacketBuffer.c | 5 +- shared-bindings/_bleio/UUID.c | 20 +- shared-bindings/_bleio/__init__.h | 8 - 22 files changed, 496 insertions(+), 165 deletions(-) create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h index 04edb104ddc..fa9f4c7103e 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.h +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -61,6 +61,7 @@ typedef struct { uint8_t disconnect_reason; } bleio_connection_obj_t; +void common_hal_bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index e2eebdea0fe..2b67216cf50 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -476,7 +476,7 @@ msgstr "" msgid "AP could not be started" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "" @@ -673,11 +673,6 @@ msgstr "" msgid "Brightness not adjustable" msgstr "" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "" @@ -720,10 +715,6 @@ msgstr "" msgid "Bus pin %d is already in use" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "" - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "" @@ -1029,12 +1020,18 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "" @@ -2247,10 +2244,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" @@ -3393,10 +3386,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3808,7 +3797,6 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4292,7 +4280,6 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" diff --git a/ports/espressif/common-hal/_bleio/Connection.h b/ports/espressif/common-hal/_bleio/Connection.h index 326eca02ecd..bb48782e84f 100644 --- a/ports/espressif/common-hal/_bleio/Connection.h +++ b/ports/espressif/common-hal/_bleio/Connection.h @@ -64,6 +64,7 @@ void bleio_connection_clear(bleio_connection_internal_t *self); int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in); +void common_hal_bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/nordic/common-hal/_bleio/Attribute.h b/ports/nordic/common-hal/_bleio/Attribute.h index 5fa6b4d6377..c9438571a86 100644 --- a/ports/nordic/common-hal/_bleio/Attribute.h +++ b/ports/nordic/common-hal/_bleio/Attribute.h @@ -6,6 +6,15 @@ #pragma once +#include + +#include "py/obj.h" + #include "shared-module/_bleio/Attribute.h" extern void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode); + +size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); +void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); +size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); +void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); diff --git a/ports/nordic/common-hal/_bleio/Connection.h b/ports/nordic/common-hal/_bleio/Connection.h index 110677dc78b..87e0e9856a4 100644 --- a/ports/nordic/common-hal/_bleio/Connection.h +++ b/ports/nordic/common-hal/_bleio/Connection.h @@ -65,6 +65,7 @@ typedef struct { void bleio_connection_clear(bleio_connection_internal_t *self); bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in); +void common_hal_bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/silabs/common-hal/_bleio/Connection.h b/ports/silabs/common-hal/_bleio/Connection.h index 56872024c93..23976d3c849 100644 --- a/ports/silabs/common-hal/_bleio/Connection.h +++ b/ports/silabs/common-hal/_bleio/Connection.h @@ -85,6 +85,7 @@ typedef struct void bleio_connection_clear(bleio_connection_internal_t *self); +void common_hal_bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal( diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf index 02e4e0d0d56..d996ec05ac9 100644 --- a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -6,9 +6,20 @@ CONFIG_GPIO=y # Enable Bluetooth stack - bsim is for BT simulation CONFIG_BT=y CONFIG_BT_HCI=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y CONFIG_BT_OBSERVER=y CONFIG_BT_BROADCASTER=y +CONFIG_BT_L2CAP_TX_MTU=253 +CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_BUF_EVT_RX_COUNT=16 +CONFIG_BT_BUF_EVT_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_COUNT=3 +CONFIG_BT_BUF_ACL_TX_SIZE=251 +CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 +CONFIG_BT_BUF_ACL_RX_SIZE=255 + CONFIG_BT_DEVICE_NAME_DYNAMIC=y CONFIG_BT_DEVICE_NAME_MAX=28 diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index d72a7bed865..7f034cfc24d 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -11,9 +11,10 @@ #include #include +#include #include -#include +#include "py/gc.h" #include "py/runtime.h" #include "bindings/zephyr_kernel/__init__.h" #include "shared-bindings/_bleio/__init__.h" @@ -62,6 +63,104 @@ static uint8_t bleio_address_type_from_zephyr(const bt_addr_le_t *addr) { } } +static uint8_t bleio_address_type_to_zephyr(uint8_t type) { + switch (type) { + case BLEIO_ADDRESS_TYPE_PUBLIC: + return BT_ADDR_LE_PUBLIC; + case BLEIO_ADDRESS_TYPE_RANDOM_STATIC: + case BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_RESOLVABLE: + case BLEIO_ADDRESS_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE: + return BT_ADDR_LE_RANDOM; + default: + return BT_ADDR_LE_PUBLIC; + } +} + +static bleio_connection_internal_t *bleio_connection_find_by_conn(const struct bt_conn *conn) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + if (connection->conn == conn) { + return connection; + } + } + + return NULL; +} + +static bleio_connection_internal_t *bleio_connection_track(struct bt_conn *conn) { + bleio_connection_internal_t *connection = bleio_connection_find_by_conn(conn); + if (connection == NULL) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *candidate = &bleio_connections[i]; + if (candidate->conn == NULL) { + connection = candidate; + break; + } + } + } + + if (connection == NULL) { + return NULL; + } + + if (connection->conn == NULL) { + connection->conn = bt_conn_ref(conn); + } + + return connection; +} + +static void bleio_connection_clear(bleio_connection_internal_t *self) { + if (self == NULL) { + return; + } + + if (self->conn != NULL) { + bt_conn_unref(self->conn); + self->conn = NULL; + } + + self->connection_obj = mp_const_none; +} + +static void bleio_connection_release(bleio_connection_internal_t *connection, uint8_t reason) { + if (connection == NULL) { + return; + } + + if (connection->connection_obj != mp_const_none) { + bleio_connection_obj_t *connection_obj = MP_OBJ_TO_PTR(connection->connection_obj); + connection_obj->connection = NULL; + connection_obj->disconnect_reason = reason; + } + + bleio_connection_clear(connection); + common_hal_bleio_adapter_obj.connection_objs = NULL; +} + +static void bleio_connected_cb(struct bt_conn *conn, uint8_t err) { + if (err != 0) { + return; + } + + if (bleio_connection_track(conn) == NULL) { + bt_conn_disconnect(conn, BT_HCI_ERR_CONN_LIMIT_EXCEEDED); + return; + } + + common_hal_bleio_adapter_obj.connection_objs = NULL; +} + +static void bleio_disconnected_cb(struct bt_conn *conn, uint8_t reason) { + printk("disconnected %p\n", conn); + bleio_connection_release(bleio_connection_find_by_conn(conn), reason); +} + +BT_CONN_CB_DEFINE(bleio_connection_callbacks) = { + .connected = bleio_connected_cb, + .disconnected = bleio_disconnected_cb, +}; + static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) { if (active_scan_results == NULL || info == NULL || buf == NULL) { return; @@ -129,8 +228,27 @@ static size_t bleio_parse_adv_data(const uint8_t *raw, size_t raw_len, struct bt return count; } +static uint16_t bleio_validate_and_convert_timeout(mp_float_t timeout) { + mp_arg_validate_float_range(timeout, 0, UINT16_MAX, MP_QSTR_timeout); + + if (timeout <= 0.0f) { + return 0; + } + + const mp_int_t timeout_units = + mp_arg_validate_int_range((mp_int_t)(timeout * 100.0f + 0.5f), 1, UINT16_MAX, MP_QSTR_timeout); + + return (uint16_t)timeout_units; +} + void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { + if (enabled == ble_adapter_enabled) { + return; + } if (enabled) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_clear(&bleio_connections[i]); + } if (!bt_is_ready()) { int err = bt_enable(NULL); if (err != 0) { @@ -320,17 +438,7 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t uint16_t interval_units = (uint16_t)((interval / 0.000625f) + 0.5f); uint16_t window_units = (uint16_t)((window / 0.000625f) + 0.5f); - uint32_t timeout_units = 0; - - if (timeout > 0.0f) { - timeout_units = (uint32_t)(timeout * 100.0f + 0.5f); - if (timeout_units > UINT16_MAX) { - mp_raise_ValueError(MP_ERROR_TEXT("timeout must be < 655.35 secs")); - } - if (timeout_units == 0) { - mp_raise_ValueError(MP_ERROR_TEXT("non-zero timeout must be > 0.01")); - } - } + uint16_t timeout_units = bleio_validate_and_convert_timeout(timeout); struct bt_le_scan_param scan_params = { .type = active ? BT_LE_SCAN_TYPE_ACTIVE : BT_LE_SCAN_TYPE_PASSIVE, @@ -363,15 +471,110 @@ void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { } bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { + if (!ble_adapter_enabled) { + return false; + } + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn != NULL) { + return true; + } + } + return false; } mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) { - mp_raise_NotImplementedError(NULL); + if (!ble_adapter_enabled) { + self->connection_objs = NULL; + return mp_const_empty_tuple; + } + + if (self->connection_objs != NULL) { + return self->connection_objs; + } + + size_t total_connected = 0; + mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT]; + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + if (connection->conn == NULL) { + continue; + } + + if (connection->connection_obj == mp_const_none) { + connection->connection_obj = bleio_connection_new_from_internal(connection); + } + + items[total_connected] = connection->connection_obj; + total_connected++; + } + + self->connection_objs = mp_obj_new_tuple(total_connected, items); + return self->connection_objs; } mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { - mp_raise_NotImplementedError(NULL); + common_hal_bleio_adapter_stop_scan(self); + + const uint16_t timeout_units = bleio_validate_and_convert_timeout(timeout); + + mp_buffer_info_t address_bufinfo; + mp_get_buffer_raise(address->bytes, &address_bufinfo, MP_BUFFER_READ); + + bt_addr_le_t peer = { + .type = bleio_address_type_to_zephyr(address->type), + }; + memcpy(peer.a.val, address_bufinfo.buf, NUM_BLEIO_ADDRESS_BYTES); + + struct bt_conn_le_create_param create_params = BT_CONN_LE_CREATE_PARAM_INIT( + BT_CONN_LE_OPT_NONE, + BT_GAP_SCAN_FAST_INTERVAL, + BT_GAP_SCAN_FAST_INTERVAL); + create_params.timeout = timeout_units; + + struct bt_conn *conn = NULL; + int err = bt_conn_le_create(&peer, &create_params, BT_LE_CONN_PARAM_DEFAULT, &conn); + if (err != 0) { + raise_zephyr_error(err); + } + + while (true) { + struct bt_conn_info info; + err = bt_conn_get_info(conn, &info); + if (err == 0) { + if (info.state == BT_CONN_STATE_CONNECTED) { + break; + } + + if (info.state == BT_CONN_STATE_DISCONNECTED) { + bt_conn_unref(conn); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Failed to connect")); + } + } else if (err != -ENOTCONN) { + bt_conn_unref(conn); + raise_zephyr_error(err); + } + + RUN_BACKGROUND_TASKS; + } + + bleio_connection_internal_t *connection = bleio_connection_find_by_conn(conn); + if (connection == NULL) { + connection = bleio_connection_track(conn); + } + + if (connection == NULL) { + bt_conn_unref(conn); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Failed to connect: internal error")); + } + + // bt_conn_le_create() gave us a ref in `conn`; `connection` keeps its own + // ref via bleio_connection_track(). Drop the create ref now. + bt_conn_unref(conn); + + self->connection_objs = NULL; + return bleio_connection_new_from_internal(connection); } void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) { @@ -383,13 +586,32 @@ bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self) { } void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) { - // Nothing to do for now. + gc_collect_root((void **)adapter, sizeof(bleio_adapter_obj_t) / sizeof(size_t)); + gc_collect_root((void **)bleio_connections, sizeof(bleio_connections) / sizeof(size_t)); } void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { if (adapter == NULL) { return; } + + common_hal_bleio_adapter_stop_scan(adapter); + common_hal_bleio_adapter_stop_advertising(adapter); + + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + if (connection->conn != NULL) { + bt_conn_disconnect(connection->conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } + if (connection->connection_obj != MP_OBJ_NULL && + connection->connection_obj != mp_const_none) { + bleio_connection_obj_t *connection_obj = MP_OBJ_TO_PTR(connection->connection_obj); + connection_obj->connection = NULL; + connection_obj->disconnect_reason = BT_HCI_ERR_REMOTE_USER_TERM_CONN; + } + bleio_connection_clear(connection); + } + adapter->scan_results = NULL; adapter->connection_objs = NULL; active_scan_results = NULL; diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.h b/ports/zephyr-cp/common-hal/_bleio/Adapter.h index dda9075776e..c15c698e2a5 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.h +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.h @@ -13,8 +13,7 @@ #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" -#define BLEIO_TOTAL_CONNECTION_COUNT 5 -#define BLEIO_HANDLE_INVALID 0xffff +#define BLEIO_TOTAL_CONNECTION_COUNT CONFIG_BT_MAX_CONN extern bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.c b/ports/zephyr-cp/common-hal/_bleio/Connection.c index 2e93b6ab127..938359c79ca 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.c +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -5,7 +5,14 @@ // // SPDX-License-Identifier: MIT +#include + +#include +#include + #include "py/runtime.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Connection.h" void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) { @@ -13,15 +20,47 @@ void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bo } void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { - mp_raise_NotImplementedError(NULL); + if (self == NULL || self->conn == NULL) { + return; + } + + int err = bt_conn_disconnect(self->conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + if (err != 0 && err != -ENOTCONN) { + raise_zephyr_error(err); + } + + // The connection may now be disconnecting; force connections tuple rebuild. + common_hal_bleio_adapter_obj.connection_objs = NULL; } bool common_hal_bleio_connection_get_connected(bleio_connection_obj_t *self) { - return false; + if (self == NULL || self->connection == NULL) { + return false; + } + + bleio_connection_internal_t *connection = self->connection; + if (connection->conn == NULL) { + return false; + } + + struct bt_conn_info info; + if (bt_conn_get_info(connection->conn, &info) != 0) { + return false; + } + + return info.state == BT_CONN_STATE_CONNECTED || info.state == BT_CONN_STATE_DISCONNECTING; } mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_internal_t *self) { - return 20; + if (self == NULL || self->conn == NULL) { + return 20; + } + + uint16_t mtu = bt_gatt_get_mtu(self->conn); + if (mtu < 3) { + return 20; + } + return mtu - 3; } bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { @@ -40,18 +79,19 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern mp_raise_NotImplementedError(NULL); } -void bleio_connection_clear(bleio_connection_internal_t *self) { - // Nothing to do -} +mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection) { + if (connection == NULL) { + return mp_const_none; + } -uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self) { - return self->connection->conn_handle; -} + if (connection->connection_obj != mp_const_none) { + return connection->connection_obj; + } -mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection) { - mp_raise_NotImplementedError(NULL); -} + bleio_connection_obj_t *connection_obj = mp_obj_malloc(bleio_connection_obj_t, &bleio_connection_type); + connection_obj->connection = connection; + connection_obj->disconnect_reason = 0; + connection->connection_obj = MP_OBJ_FROM_PTR(connection_obj); -bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle) { - return NULL; + return connection->connection_obj; } diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.h b/ports/zephyr-cp/common-hal/_bleio/Connection.h index f8f9581ad00..dc14125db5f 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.h +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.h @@ -10,31 +10,12 @@ #include #include "py/obj.h" -#include "py/objlist.h" -#include "common-hal/_bleio/__init__.h" -#include "shared-module/_bleio/Address.h" -#include "common-hal/_bleio/Service.h" - -typedef enum { - PAIR_NOT_PAIRED, - PAIR_WAITING, - PAIR_PAIRED, -} pair_status_t; +struct bt_conn; typedef struct { - uint16_t conn_handle; - bool is_central; - mp_obj_list_t *remote_service_list; - uint16_t ediv; - volatile pair_status_t pair_status; - uint8_t sec_status; + struct bt_conn *conn; mp_obj_t connection_obj; - volatile bool conn_params_updating; - uint16_t mtu; - volatile bool do_bond_cccds; - volatile bool do_bond_keys; - uint64_t do_bond_cccds_request_time; } bleio_connection_internal_t; typedef struct { @@ -43,7 +24,4 @@ typedef struct { uint8_t disconnect_reason; } bleio_connection_obj_t; -void bleio_connection_clear(bleio_connection_internal_t *self); -uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); -bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.c b/ports/zephyr-cp/common-hal/_bleio/__init__.c index fca1eae9827..719564c1cd4 100644 --- a/ports/zephyr-cp/common-hal/_bleio/__init__.c +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.c @@ -8,6 +8,7 @@ #include "py/runtime.h" #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Adapter.h" +#include "common-hal/_bleio/Adapter.h" #include "supervisor/shared/bluetooth/bluetooth.h" // The singleton _bleio.Adapter object @@ -15,61 +16,36 @@ bleio_adapter_obj_t common_hal_bleio_adapter_obj; void common_hal_bleio_init(void) { common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; + bleio_adapter_reset(&common_hal_bleio_adapter_obj); } void bleio_user_reset(void) { - common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); - common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); - bleio_adapter_reset(&common_hal_bleio_adapter_obj); - - if (supervisor_bluetooth_workflow_is_enabled()) { - supervisor_bluetooth_background(); + if (common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + // Stop any user scanning or advertising. + common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); + common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); } + + // Maybe start advertising the BLE workflow. + supervisor_bluetooth_background(); } void bleio_reset(void) { common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + return; + } - common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); - common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); - - // Keep Zephyr BLE transport up, but present a disabled adapter state. - common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); + supervisor_stop_bluetooth(); bleio_adapter_reset(&common_hal_bleio_adapter_obj); - - if (supervisor_bluetooth_workflow_is_enabled()) { - supervisor_start_bluetooth(); - } + common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); + supervisor_start_bluetooth(); } void common_hal_bleio_gc_collect(void) { - // Nothing to do for stubs -} - -void common_hal_bleio_check_connected(uint16_t conn_handle) { - mp_raise_NotImplementedError(NULL); -} - -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device) { - mp_raise_NotImplementedError(NULL); + bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); } void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { mp_raise_NotImplementedError(NULL); } - -size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { - mp_raise_NotImplementedError(NULL); -} - -void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { - mp_raise_NotImplementedError(NULL); -} - -size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { - mp_raise_NotImplementedError(NULL); -} - -void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { - mp_raise_NotImplementedError(NULL); -} diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index e00cf6cac8d..3da878e0f5b 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -414,7 +414,8 @@ async def build_circuitpython(): supervisor_source = [pathlib.Path(p) for p in supervisor_source] supervisor_source.extend(board_info["source_files"]) supervisor_source.extend(top.glob("supervisor/shared/*.c")) - supervisor_source.append(top / "supervisor/shared/bluetooth/bluetooth.c") + if "_bleio" in enabled_modules: + supervisor_source.append(top / "supervisor/shared/bluetooth/bluetooth.c") supervisor_source.append(top / "supervisor/shared/translate/translate.c") if web_workflow_enabled: supervisor_source.extend(top.glob("supervisor/shared/web_workflow/*.c")) diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 08a84043e8e..0d8a2f48c13 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -9,10 +9,6 @@ #include "mpconfigboard.h" #include "supervisor/shared/tick.h" -#if CIRCUITPY_BLEIO -#include "shared-bindings/_bleio/__init__.h" -#endif - #include #include #include @@ -93,10 +89,6 @@ void reset_cpu(void) { } void reset_port(void) { - #if CIRCUITPY_BLEIO - bleio_reset(); - #endif - #if defined(CONFIG_ARCH_POSIX) native_sim_reset_port_count++; if (native_sim_vm_runs != INT32_MAX && diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py new file mode 100644 index 00000000000..21cfeaf79da --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py @@ -0,0 +1,119 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE central connection tests for nrf5340bsim.""" + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +BSIM_CONNECT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("connect start") +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable: + target = entry.address + print("found target") + break +adapter.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No connectable target found") + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected, adapter.connected, len(adapter.connections)) +connection.disconnect() + +for _ in range(40): + if not connection.connected and not adapter.connected: + break + time.sleep(0.1) + +print("disconnected", connection.connected, adapter.connected, len(adapter.connections)) +""" + +BSIM_RECONNECT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("run start") +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable: + target = entry.address + print("run found target") + break +adapter.stop_scan() +print("run have target", target is not None) + +if target is None: + raise RuntimeError("No connectable target found") + +connection = adapter.connect(target, timeout=5.0) +print("run connected", connection.connected, adapter.connected, len(adapter.connections)) +connection.disconnect() + +for _ in range(50): + if not connection.connected and not adapter.connected and len(adapter.connections) == 0: + break + time.sleep(0.1) + +print("run disconnected", connection.connected, adapter.connected, len(adapter.connections)) +""" + + +@pytest.mark.zephyr_sample("bluetooth/peripheral") +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CONNECT_CODE}) +def test_bsim_connect_zephyr_peripheral(bsim_phy, circuitpython, zephyr_sample): + """Connect to the Zephyr peripheral sample and disconnect cleanly.""" + peripheral = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + peripheral_output = peripheral.serial.all_output + + assert "connect start" in cp_output + assert "found target" in cp_output + assert "have target True" in cp_output + assert "connected True True 1" in cp_output + assert "disconnected False False 0" in cp_output + + assert "Advertising successfully started" in peripheral_output + assert "Connected" in peripheral_output + + +@pytest.mark.zephyr_sample("bluetooth/peripheral_sc_only") +@pytest.mark.code_py_runs(2) +@pytest.mark.duration(26) +@pytest.mark.circuitpy_drive({"code.py": BSIM_RECONNECT_CODE}) +def test_bsim_reconnect_zephyr_peripheral(bsim_phy, circuitpython, zephyr_sample): + """Connect/disconnect, soft reload, then connect/disconnect again.""" + peripheral = zephyr_sample + + circuitpython.serial.wait_for("run disconnected") + circuitpython.serial.wait_for("Press any key to enter the REPL") + circuitpython.serial.write("\x04") + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + peripheral_output = peripheral.serial.all_output + + assert cp_output.count("run start") >= 2 + assert cp_output.count("run found target") >= 2 + assert cp_output.count("run have target True") >= 2 + assert cp_output.count("run connected True True 1") >= 2 + assert cp_output.count("run disconnected False False 0") >= 2 + + assert "Advertising successfully started" in peripheral_output + assert peripheral_output.count("Connected") >= 2 diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index 839b8b19add..a1f81a063fd 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -215,7 +215,7 @@ static mp_obj_t bleio_adapter_start_advertising(mp_uint_t n_args, const mp_obj_t args[ARG_interval].u_obj = mp_obj_new_float(ADV_INTERVAL_DEFAULT); } - const mp_float_t interval = mp_obj_get_float(args[ARG_interval].u_obj); + const mp_float_t interval = mp_arg_validate_type_float(args[ARG_interval].u_obj, MP_QSTR_interval); if (interval < ADV_INTERVAL_MIN || interval > ADV_INTERVAL_MAX) { mp_raise_ValueError_varg(MP_ERROR_TEXT("interval must be in range %s-%s"), ADV_INTERVAL_MIN_STRING, ADV_INTERVAL_MAX_STRING); @@ -223,7 +223,7 @@ static mp_obj_t bleio_adapter_start_advertising(mp_uint_t n_args, const mp_obj_t bool connectable = args[ARG_connectable].u_bool; bool anonymous = args[ARG_anonymous].u_bool; - uint32_t timeout = args[ARG_timeout].u_int; + const uint32_t timeout = (uint32_t)mp_arg_validate_int_min(args[ARG_timeout].u_int, 0, MP_QSTR_timeout); if (data_bufinfo.len > 31 && connectable && scan_response_bufinfo.len > 0) { mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Cannot have scan responses for extended, connectable advertisements.")); } @@ -306,7 +306,7 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args mp_float_t timeout = 0.0f; if (args[ARG_timeout].u_obj != mp_const_none) { - timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + timeout = mp_arg_validate_obj_float_non_negative(args[ARG_timeout].u_obj, 0.0f, MP_QSTR_timeout); } if (args[ARG_interval].u_obj == MP_OBJ_NULL) { @@ -317,7 +317,7 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args args[ARG_window].u_obj = mp_obj_new_float(WINDOW_DEFAULT); } - const mp_float_t interval = mp_obj_get_float(args[ARG_interval].u_obj); + const mp_float_t interval = mp_arg_validate_type_float(args[ARG_interval].u_obj, MP_QSTR_interval); if (interval < INTERVAL_MIN || interval > INTERVAL_MAX) { mp_raise_ValueError_varg(MP_ERROR_TEXT("interval must be in range %s-%s"), INTERVAL_MIN_STRING, INTERVAL_MAX_STRING); } @@ -329,7 +329,7 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args } #pragma GCC diagnostic pop - const mp_float_t window = mp_obj_get_float(args[ARG_window].u_obj); + const mp_float_t window = mp_arg_validate_type_float(args[ARG_window].u_obj, MP_QSTR_window); if (window > interval) { mp_raise_ValueError(MP_ERROR_TEXT("window must be <= interval")); } @@ -344,7 +344,9 @@ static mp_obj_t bleio_adapter_start_scan(size_t n_args, const mp_obj_t *pos_args } } - return common_hal_bleio_adapter_start_scan(self, prefix_bufinfo.buf, prefix_bufinfo.len, args[ARG_extended].u_bool, args[ARG_buffer_size].u_int, timeout, interval, window, args[ARG_minimum_rssi].u_int, args[ARG_active].u_bool); + const mp_int_t buffer_size = mp_arg_validate_int_min(args[ARG_buffer_size].u_int, 1, MP_QSTR_buffer_size); + + return common_hal_bleio_adapter_start_scan(self, prefix_bufinfo.buf, prefix_bufinfo.len, args[ARG_extended].u_bool, buffer_size, timeout, interval, window, args[ARG_minimum_rssi].u_int, args[ARG_active].u_bool); } static MP_DEFINE_CONST_FUN_OBJ_KW(bleio_adapter_start_scan_obj, 1, bleio_adapter_start_scan); @@ -416,7 +418,8 @@ static mp_obj_t bleio_adapter_connect(mp_uint_t n_args, const mp_obj_t *pos_args mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); bleio_address_obj_t *address = mp_arg_validate_type(args[ARG_address].u_obj, &bleio_address_type, MP_QSTR_address); - mp_float_t timeout = mp_obj_get_float(args[ARG_timeout].u_obj); + const mp_float_t timeout = + mp_arg_validate_obj_float_non_negative(args[ARG_timeout].u_obj, 0.0f, MP_QSTR_timeout); return common_hal_bleio_adapter_connect(self, address, timeout); } diff --git a/shared-bindings/_bleio/Address.c b/shared-bindings/_bleio/Address.c index 58f8a8adc1e..e39fa4fe40b 100644 --- a/shared-bindings/_bleio/Address.c +++ b/shared-bindings/_bleio/Address.c @@ -42,14 +42,13 @@ static mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t address = args[ARG_address].u_obj; mp_buffer_info_t buf_info; mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); - if (buf_info.len != NUM_BLEIO_ADDRESS_BYTES) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("Address must be %d bytes long"), NUM_BLEIO_ADDRESS_BYTES); - } + mp_arg_validate_length(buf_info.len, NUM_BLEIO_ADDRESS_BYTES, MP_QSTR_address); - const mp_int_t address_type = args[ARG_address_type].u_int; - if (address_type < BLEIO_ADDRESS_TYPE_MIN || address_type > BLEIO_ADDRESS_TYPE_MAX) { - mp_arg_error_invalid(MP_QSTR_address_type); - } + const mp_int_t address_type = + mp_arg_validate_int_range(args[ARG_address_type].u_int, + BLEIO_ADDRESS_TYPE_MIN, + BLEIO_ADDRESS_TYPE_MAX, + MP_QSTR_address_type); common_hal_bleio_address_construct(self, buf_info.buf, address_type); diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c index 8d6ac43e487..b017295b45f 100644 --- a/shared-bindings/_bleio/Characteristic.c +++ b/shared-bindings/_bleio/Characteristic.c @@ -116,9 +116,9 @@ static mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_ } mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); - if (initial_value_bufinfo.len > max_length || - (fixed_length && initial_value_bufinfo.len != max_length)) { - mp_raise_ValueError(MP_ERROR_TEXT("initial_value length is wrong")); + mp_arg_validate_length_max(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); + if (fixed_length) { + mp_arg_validate_length(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); } const char *user_description = NULL; diff --git a/shared-bindings/_bleio/Descriptor.c b/shared-bindings/_bleio/Descriptor.c index 57cc605029f..8e721ff292d 100644 --- a/shared-bindings/_bleio/Descriptor.c +++ b/shared-bindings/_bleio/Descriptor.c @@ -99,9 +99,9 @@ static mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_o } } mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); - if (initial_value_bufinfo.len > max_length || - (fixed_length && initial_value_bufinfo.len != max_length)) { - mp_raise_ValueError(MP_ERROR_TEXT("initial_value length is wrong")); + mp_arg_validate_length_max(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); + if (fixed_length) { + mp_arg_validate_length(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); } bleio_descriptor_obj_t *descriptor = mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type); diff --git a/shared-bindings/_bleio/PacketBuffer.c b/shared-bindings/_bleio/PacketBuffer.c index 47d71ebd55a..aa1e6e8645a 100644 --- a/shared-bindings/_bleio/PacketBuffer.c +++ b/shared-bindings/_bleio/PacketBuffer.c @@ -57,7 +57,10 @@ static mp_obj_t bleio_packet_buffer_make_new(const mp_obj_type_t *type, size_t n size_t max_packet_size = common_hal_bleio_characteristic_get_max_length(characteristic); if (args[ARG_max_packet_size].u_obj != mp_const_none) { - max_packet_size = mp_obj_get_int(args[ARG_max_packet_size].u_obj); + const mp_int_t max_packet_size_int = + mp_arg_validate_type_int(args[ARG_max_packet_size].u_obj, MP_QSTR_max_packet_size); + max_packet_size = + (size_t)mp_arg_validate_int_min(max_packet_size_int, 1, MP_QSTR_max_packet_size); } bleio_packet_buffer_obj_t *self = mp_obj_malloc(bleio_packet_buffer_obj_t, &bleio_packet_buffer_type); diff --git a/shared-bindings/_bleio/UUID.c b/shared-bindings/_bleio/UUID.c index 2d28d5a9b61..165c2982f08 100644 --- a/shared-bindings/_bleio/UUID.c +++ b/shared-bindings/_bleio/UUID.c @@ -40,10 +40,8 @@ static mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, si uint8_t uuid128[16]; if (mp_obj_is_int(value)) { - mp_int_t uuid16 = mp_obj_get_int(value); - if (uuid16 < 0 || uuid16 > 0xffff) { - mp_raise_ValueError(MP_ERROR_TEXT("UUID integer value must be 0-0xffff")); - } + const mp_int_t uuid16 = + mp_arg_validate_int_range(mp_obj_get_int(value), 0, 0xffff, MP_QSTR_value); // NULL means no 128-bit value. common_hal_bleio_uuid_construct(self, uuid16, NULL); @@ -82,9 +80,7 @@ static mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, si mp_raise_ValueError(MP_ERROR_TEXT("UUID value is not str, int or byte buffer")); } - if (bufinfo.len != 16) { - mp_raise_ValueError(MP_ERROR_TEXT("Byte buffer must be 16 bytes.")); - } + mp_arg_validate_length(bufinfo.len, 16, MP_QSTR_value); memcpy(uuid128, bufinfo.buf, 16); } @@ -171,12 +167,12 @@ static mp_obj_t bleio_uuid_pack_into(mp_uint_t n_args, const mp_obj_t *pos_args, mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); - size_t offset = args[ARG_offset].u_int; - if (offset + common_hal_bleio_uuid_get_size(self) / 8 > bufinfo.len) { - mp_raise_ValueError(MP_ERROR_TEXT("Buffer + offset too small %d %d %d")); - } + const mp_int_t offset = + mp_arg_validate_int_range(args[ARG_offset].u_int, 0, (mp_int_t)bufinfo.len, MP_QSTR_offset); + const size_t packed_len = common_hal_bleio_uuid_get_size(self) / 8; + mp_arg_validate_length_min(bufinfo.len - (size_t)offset, packed_len, MP_QSTR_buffer); - common_hal_bleio_uuid_pack_into(self, bufinfo.buf + offset); + common_hal_bleio_uuid_pack_into(self, (uint8_t *)bufinfo.buf + (size_t)offset); return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_KW(bleio_uuid_pack_into_obj, 1, bleio_uuid_pack_into); diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index faf11ea1d06..f7428d2fb21 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -50,14 +50,6 @@ NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg); NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t msg, ...); bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void); -void common_hal_bleio_check_connected(uint16_t conn_handle); - -uint16_t common_hal_bleio_device_get_conn_handle(mp_obj_t device); void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); -size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); -void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); -size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); -void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); - void common_hal_bleio_gc_collect(void); From c0177c82086487725186c85e0bb6b82ffc0f121c Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Tue, 3 Mar 2026 11:23:49 +0100 Subject: [PATCH 278/876] Added qspibus = false for all Zephyr boards --- .../adafruit/feather_nrf52840_zephyr/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml | 1 + .../zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml | 1 + .../zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml | 1 + .../boards/renesas/da14695_dk_usb/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml | 1 + 17 files changed, 17 insertions(+) diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 43b018c327a..9712f467858 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 6261be1ec75..80b1b4ebf7d 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index a512a480889..1bc1b96e6cf 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 80cf2e119ed..7869cca4faf 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index b3f72751cbb..c2233ddf8b5 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index f4d2dd478c5..a1e8de8822b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 2557bc74df4..b50b1966ed0 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index b7cd8eb6110..21d55194a1c 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index c24d0a85273..d5464e6e20b 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index b2f384e21c1..de72979513c 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index aa947de5213..d6efa285fe2 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index f7495b52723..7600b8bbd15 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index b65c12b0aa9..8e49b95d334 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 92122525a29..b28a9481c72 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index e73b1c062a5..6b0ef8d8480 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 949cb89f082..b6f03f3d627 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 50c17ef6dba..8d1fd925348 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -79,6 +79,7 @@ ps2io = false pulseio = false pwmio = false qrio = false +qspibus = false rainbowio = true random = true rclcpy = false From 1c481e8a15fde9efd98d485fbd460e97442861ed Mon Sep 17 00:00:00 2001 From: Liz Date: Tue, 3 Mar 2026 12:22:19 -0500 Subject: [PATCH 279/876] add xteink x4 with ssd1677 eink --- ports/espressif/boards/xteink_x4/board.c | 134 ++++++++++++++++++ .../boards/xteink_x4/mpconfigboard.h | 18 +++ .../boards/xteink_x4/mpconfigboard.mk | 29 ++++ ports/espressif/boards/xteink_x4/pins.c | 52 +++++++ ports/espressif/boards/xteink_x4/sdkconfig | 14 ++ 5 files changed, 247 insertions(+) create mode 100644 ports/espressif/boards/xteink_x4/board.c create mode 100644 ports/espressif/boards/xteink_x4/mpconfigboard.h create mode 100644 ports/espressif/boards/xteink_x4/mpconfigboard.mk create mode 100644 ports/espressif/boards/xteink_x4/pins.c create mode 100644 ports/espressif/boards/xteink_x4/sdkconfig diff --git a/ports/espressif/boards/xteink_x4/board.c b/ports/espressif/boards/xteink_x4/board.c new file mode 100644 index 00000000000..bf6fbddebc9 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/board.c @@ -0,0 +1,134 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// SPDX-FileCopyrightText: Copyright (c) 2021 skieast/Bruce Segal +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/board.h" + +#define DELAY 0x80 + +// SSD1677 controller driving a GDEQ0426T82 4.26" 800x480 grayscale E-Ink display. + +const uint8_t ssd1677_display_start_sequence[] = { + // Software Reset + 0x12, DELAY, 0x00, 0x14, // SWRESET + wait 20ms + + // Temperature Sensor Control (use internal sensor) + 0x18, 0x00, 0x01, 0x80, + + // Booster Soft Start + 0x0C, 0x00, 0x05, 0xAE, 0xC7, 0xC3, 0xC0, 0x40, + + // Driver Output Control: 479 gates (HEIGHT-1 = 0x01DF) + 0x01, 0x00, 0x03, 0xDF, 0x01, 0x02, + + // Data Entry Mode: X increment, Y increment + 0x11, 0x00, 0x01, 0x02, + + // Border Waveform Control + 0x3C, 0x00, 0x01, 0x01, + + // Set RAM X Address Start/End: 0 to 799 + + // X start = 0 (LE: 0x00, 0x00), X end = 799 (LE: 0x1F, 0x03) + 0x44, 0x00, 0x04, 0x00, 0x00, 0x1F, 0x03, + + // Set RAM Y Address Start/End: 0 to 479 + 0x45, 0x00, 0x04, 0x00, 0x00, 0xDF, 0x01, + + // Set RAM X Counter to 0 + 0x4E, 0x00, 0x02, 0x00, 0x00, + + // Set RAM Y Counter to 0 + 0x4F, 0x00, 0x02, 0x00, 0x00, + + // Auto Write BW RAM (clear to white) + 0x46, DELAY, 0x01, 0xF7, 0xFF, // + wait 255ms + + // Display Update Control 1: bypass RED buffer for mono mode + 0x21, 0x00, 0x02, 0x40, 0x00, + + // Display Update Control 2: full refresh sequence with OTP LUT + 0x22, 0x00, 0x01, 0xF7, +}; + +const uint8_t ssd1677_display_stop_sequence[] = { + // Power off sequence + 0x22, 0x00, 0x01, 0x83, // Display update control: power off + 0x20, 0x00, 0x00, // Master activation + // Deep sleep + 0x10, 0x00, 0x01, 0x01, // Enter deep sleep mode +}; + +const uint8_t ssd1677_display_refresh_sequence[] = { + 0x20, 0x00, 0x00 +}; + +void board_init(void) { + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO8, &pin_GPIO10, NULL, false); + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO4), + MP_OBJ_FROM_PTR(&pin_GPIO21), + MP_OBJ_FROM_PTR(&pin_GPIO5), + 40000000, + 0, + 0); + + epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; + display->base.type = &epaperdisplay_epaperdisplay_type; + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = ssd1677_display_start_sequence; + args.start_sequence_len = sizeof(ssd1677_display_start_sequence); + args.stop_sequence = ssd1677_display_stop_sequence; + args.stop_sequence_len = sizeof(ssd1677_display_stop_sequence); + args.width = 800; + args.height = 480; + args.ram_width = 800; + args.ram_height = 480; + args.rotation = 0; + args.write_black_ram_command = 0x24; + args.black_bits_inverted = true; + args.refresh_sequence = ssd1677_display_refresh_sequence; + args.refresh_sequence_len = sizeof(ssd1677_display_refresh_sequence); + args.refresh_time = 1.6; // ~1600ms full refresh + args.busy_pin = &pin_GPIO6; + args.busy_state = true; // BUSY is active HIGH on SSD1677 + args.seconds_per_frame = 5.0; + args.grayscale = false; + args.two_byte_sequence_length = true; + args.address_little_endian = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); +} + +bool espressif_board_reset_pin_number(gpio_num_t pin_number) { + return false; +} + +void board_deinit(void) { + epaperdisplay_epaperdisplay_obj_t *display = &displays[0].epaper_display; + if (display->base.type == &epaperdisplay_epaperdisplay_type) { + while (common_hal_epaperdisplay_epaperdisplay_get_busy(display)) { + RUN_BACKGROUND_TASKS; + } + } + common_hal_displayio_release_displays(); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/xteink_x4/mpconfigboard.h b/ports/espressif/boards/xteink_x4/mpconfigboard.h new file mode 100644 index 00000000000..5d4bb372228 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/mpconfigboard.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// SPDX-FileCopyrightText: Copyright (c) 2021 skieast/Bruce Segal +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Board setup +#define MICROPY_HW_BOARD_NAME "Xteink X4" +#define MICROPY_HW_MCU_NAME "ESP32-C3" + +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO8, .mosi = &pin_GPIO10, .miso = &pin_GPIO7}} + +// For entering safe mode +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO3) diff --git a/ports/espressif/boards/xteink_x4/mpconfigboard.mk b/ports/espressif/boards/xteink_x4/mpconfigboard.mk new file mode 100644 index 00000000000..bed8b2c3fa9 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/mpconfigboard.mk @@ -0,0 +1,29 @@ +CIRCUITPY_CREATOR_ID = 0x0000303A +CIRCUITPY_CREATION_ID = 0x00001001 + +IDF_TARGET = esp32c3 + +CIRCUITPY_ESP_FLASH_MODE = dio +CIRCUITPY_ESP_FLASH_FREQ = 40m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 + +CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_RGBMATRIX = 0 +CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOCORE = 0 +CIRCUITPY_AUDIOMIXER = 0 +CIRCUITPY_AUDIOMP3 = 0 +CIRCUITPY_CAMERA = 0 +CIRCUITPY_CANIO = 0 +CIRCUITPY_DOTCLOCKFRAMEBUFFER = 0 +CIRCUITPY_KEYPAD = 0 +CIRCUITPY_ROTARYIO = 0 +CIRCUITPY_USB_HID = 0 +CIRCUITPY_USB_MIDI = 0 +CIRCUITPY_ULAB = 0 +CIRCUITPY_PULSEIO = 0 +CIRCUITPY_PWMIO = 0 +CIRCUITPY_RAINBOWIO = 0 +CIRCUITPY_SYNTHIO = 0 diff --git a/ports/espressif/boards/xteink_x4/pins.c b/ports/espressif/boards/xteink_x4/pins.c new file mode 100644 index 00000000000..6b8232d4cb3 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/pins.c @@ -0,0 +1,52 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 microDev +// SPDX-FileCopyrightText: Copyright (c) 2021 skieast/Bruce Segal +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +#include "shared-module/displayio/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_ADC_1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_ADC_2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_EPD_MOSI), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_EPD_SCK), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_EPD_BUSY), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_EPD_RESET), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_EPD_DC), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_EPD_CS), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)}, + +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/xteink_x4/sdkconfig b/ports/espressif/boards/xteink_x4/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/xteink_x4/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From 17805a82babca42bca8adeaf12ba5cb219e7d52d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Mar 2026 11:12:41 -0800 Subject: [PATCH 280/876] Rerun the flaky zephyr test --- ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py | 1 + requirements-dev.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py index 3a022944e00..ffc4cb6eabe 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -91,6 +91,7 @@ def test_bsim_scan_zephyr_beacon_reload(bsim_phy, circuitpython, zephyr_sample): assert output.count("scan run done True") >= 2 +@pytest.mark.flaky(reruns=3) @pytest.mark.zephyr_sample("bluetooth/beacon") @pytest.mark.code_py_runs(2) @pytest.mark.duration(8) diff --git a/requirements-dev.txt b/requirements-dev.txt index 46d5bd516c7..6a33c49daec 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -41,4 +41,5 @@ setuptools # For zephyr port tomlkit pytest +pytest-rerunfailures perfetto From 4378f51524c8b6beb5e30bf738b627522d276351 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Tue, 3 Mar 2026 22:52:42 +0100 Subject: [PATCH 281/876] Fixes after the review --- locale/circuitpython.pot | 13 +- .../waveshare_esp32_s3_amoled_241/board.c | 10 ++ .../mpconfigboard.h | 11 +- .../mpconfigboard.mk | 3 - .../waveshare_esp32_s3_amoled_241/sdkconfig | 36 ------ ports/espressif/common-hal/qspibus/QSPIBus.c | 49 +++----- ports/espressif/common-hal/qspibus/QSPIBus.h | 1 - py/circuitpy_mpconfig.h | 18 +-- shared-bindings/displayio/__init__.h | 1 + shared-bindings/qspibus/QSPIBus.h | 1 + shared-module/busdisplay/BusDisplay.c | 115 +++--------------- shared-module/displayio/bus_core.c | 11 +- shared-module/displayio/bus_core.h | 7 +- .../framebufferio/FramebufferDisplay.c | 2 +- 14 files changed, 67 insertions(+), 211 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index e19fcc266eb..ead836333ee 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -647,10 +647,6 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Begin transaction first" -msgstr "" - #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -717,10 +713,6 @@ msgstr "" msgid "Buffer too small" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Bus in display transaction" -msgstr "" - #: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c @@ -1253,6 +1245,7 @@ msgstr "" msgid "Internal define error" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1611,10 +1604,6 @@ msgstr "" msgid "No out in program" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "No pending command" -msgstr "" - #: ports/atmel-samd/common-hal/busio/I2C.c #: ports/espressif/common-hal/busio/I2C.c #: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c index 29dbb64050a..7b57f48bcdb 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/board.c @@ -5,6 +5,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" #include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/qspibus/QSPIBus.h" #include "shared-bindings/busdisplay/BusDisplay.h" @@ -42,6 +43,15 @@ static uint8_t display_init_sequence[] = { }; void board_init(void) { + // 0. Enable display power before any bus/display init. + digitalio_digitalinout_obj_t power_pin; + power_pin.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct(&power_pin, CIRCUITPY_LCD_POWER); + common_hal_digitalio_digitalinout_set_value(&power_pin, true); + common_hal_digitalio_digitalinout_never_reset(&power_pin); + // Allow power rail to settle before reset/init. + mp_hal_delay_ms(200); + // 1. Allocate and construct QSPI bus qspibus_qspibus_obj_t *bus = &allocate_display_bus_or_raise()->qspi_bus; bus->base.type = &qspibus_qspibus_type; diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h index fcd3c0e5b03..242cca6b30d 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -7,19 +7,13 @@ #define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3-Touch-AMOLED-2.41" #define MICROPY_HW_MCU_NAME "ESP32S3" -// USB identifiers -#define USB_VID 0x303A -#define USB_PID 0x8278 -#define USB_MANUFACTURER "Waveshare" -#define USB_PRODUCT "ESP32-S3-Touch-AMOLED-2.41" - // I2C bus - Disabled on boot to avoid conflicts. User must manually initialize I2C. #define CIRCUITPY_BOARD_I2C (0) #define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO48, .sda = &pin_GPIO47}} -// QSPI display refresh buffer: 2048 uint32_t words = 8KB on stack. +// Display refresh buffer: 2048 uint32_t words = 8KB on stack. // ESP32-S3 main task stack is 24KB; verified safe with this board. -#define CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE (2048) +#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (2048) // AMOLED Display (displayio + qspibus path) - initialized in board_init() #define CIRCUITPY_BOARD_DISPLAY (1) @@ -31,7 +25,6 @@ #define CIRCUITPY_LCD_D3 (&pin_GPIO14) #define CIRCUITPY_LCD_RESET (&pin_GPIO21) #define CIRCUITPY_LCD_POWER (&pin_GPIO16) -#define CIRCUITPY_LCD_POWER_ON_LEVEL (1) // GPIO level: 1=high, 0=low // No default SPI bus — SD card uses SDIO, display uses QSPI. #define CIRCUITPY_BOARD_SPI (0) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk index 17d53001001..f901246804c 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.mk @@ -2,9 +2,6 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 Przemyslaw Patrick Socha # SPDX-License-Identifier: MIT -CIRCUITPY_CREATOR_ID = 0x57415645 # 'WAVE' (Waveshare) -CIRCUITPY_CREATION_ID = 0x41323431 # 'A241' (AMOLED 2.41) - USB_VID = 0x303A USB_PID = 0x8278 USB_MANUFACTURER = "Waveshare" diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig index b6c009f3116..fa60cc4c237 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/sdkconfig @@ -1,39 +1,3 @@ # # Configuration file for the Waveshare ESP32-S3 Touch AMOLED 2.41 # - -# PSRAM Configuration -CONFIG_SPIRAM=y -CONFIG_SPIRAM_BOOT_INIT=y -CONFIG_SPIRAM_USE_MALLOC=y -CONFIG_SPIRAM_MODE_OCT=y -CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y -CONFIG_SPIRAM_RODATA=y -CONFIG_SPIRAM_SPEED_80M=y -CONFIG_SPIRAM_MEMTEST=n -CONFIG_SPIRAM_CLK_IO=39 -CONFIG_SPIRAM_CS_IO=38 - -# Performance and Cache -CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y -CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y - -# Default flash settings for this board -CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y -CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-16MB.csv" -CONFIG_PARTITION_TABLE_FILENAME="esp-idf-config/partitions-16MB.csv" - -# Networking -CONFIG_LWIP_LOCAL_HOSTNAME="waveshare-esp32-s3-amoled" - -# Disable USB-Serial/JTAG console - CircuitPython uses TinyUSB (USB OTG) for REPL -CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=n - -# Workaround: NimBLE BLE_STATIC_TO_DYNAMIC=y (default in IDF 5.5.3) causes -# ble_gap_vars to be a dynamically allocated pointer (NULL before ble_gap_init). -# CircuitPython calls ble_gap_adv_active() before NimBLE init → NULL deref → bootloop. -# Reverting to static allocation avoids the crash. -CONFIG_BT_NIMBLE_STATIC_TO_DYNAMIC=n - -# Enable .app_desc structure -CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index 33c5f128206..b4fabe91478 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -25,14 +25,6 @@ #define QSPI_DMA_BUFFER_COUNT (2U) #define QSPI_DMA_BUFFER_SIZE (16U * 1024U) #define QSPI_COLOR_TIMEOUT_MS (1000U) -#if defined(CIRCUITPY_LCD_POWER) -#define CIRCUITPY_QSPIBUS_PANEL_POWER_PIN CIRCUITPY_LCD_POWER -#endif - -#ifndef CIRCUITPY_LCD_POWER_ON_LEVEL -#define CIRCUITPY_LCD_POWER_ON_LEVEL (1) -#endif - static void qspibus_release_dma_buffers(qspibus_qspibus_obj_t *self) { for (size_t i = 0; i < QSPI_DMA_BUFFER_COUNT; i++) { if (self->dma_buffer[i] != NULL) { @@ -279,7 +271,6 @@ void common_hal_qspibus_qspibus_construct( self->cs_pin = cs->number; self->dcx_pin = (dcx != NULL) ? dcx->number : -1; self->reset_pin = (reset != NULL) ? reset->number : -1; - self->power_pin = -1; self->frequency = frequency; self->bus_initialized = false; self->in_transaction = false; @@ -319,7 +310,7 @@ void common_hal_qspibus_qspibus_construct( qspibus_release_dma_buffers(self); vSemaphoreDelete(self->transfer_done_sem); self->transfer_done_sem = NULL; - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_SPI, (int)err); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_SPI); } const esp_lcd_panel_io_spi_config_t io_config = { @@ -358,21 +349,6 @@ void common_hal_qspibus_qspibus_construct( gpio_set_level((gpio_num_t)self->dcx_pin, 1); } - #ifdef CIRCUITPY_QSPIBUS_PANEL_POWER_PIN - const mcu_pin_obj_t *power = CIRCUITPY_QSPIBUS_PANEL_POWER_PIN; - if (power != NULL) { - if (!common_hal_mcu_pin_is_free(power)) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_LCD_POWER); - } - self->power_pin = power->number; - claim_pin(power); - gpio_set_direction((gpio_num_t)self->power_pin, GPIO_MODE_OUTPUT); - gpio_set_level((gpio_num_t)self->power_pin, CIRCUITPY_LCD_POWER_ON_LEVEL ? 1 : 0); - // Panel power rail needs extra settle time before reset/init commands. - vTaskDelay(pdMS_TO_TICKS(200)); - } - #endif - if (reset != NULL) { claim_pin(reset); @@ -420,9 +396,6 @@ void common_hal_qspibus_qspibus_deinit(qspibus_qspibus_obj_t *self) { if (self->dcx_pin >= 0) { reset_pin_number(self->dcx_pin); } - if (self->power_pin >= 0) { - reset_pin_number(self->power_pin); - } if (self->reset_pin >= 0) { reset_pin_number(self->reset_pin); } @@ -446,7 +419,7 @@ void common_hal_qspibus_qspibus_write_command( raise_deinited_error(); } if (self->in_transaction) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Bus in display transaction")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); } // If caller stages command-only operations repeatedly, flush the previous @@ -467,7 +440,7 @@ void common_hal_qspibus_qspibus_write_data( raise_deinited_error(); } if (self->in_transaction) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Bus in display transaction")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); } if (len == 0) { if (self->has_pending_command) { @@ -477,7 +450,7 @@ void common_hal_qspibus_qspibus_write_data( return; } if (!self->has_pending_command) { - mp_raise_ValueError(MP_ERROR_TEXT("No pending command")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); } if (qspibus_is_color_payload_command(self->pending_command)) { @@ -545,7 +518,7 @@ void common_hal_qspibus_qspibus_send( raise_deinited_error(); } if (!self->in_transaction) { - mp_raise_RuntimeError(MP_ERROR_TEXT("Begin transaction first")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); } if (data_type == DISPLAY_COMMAND) { @@ -564,7 +537,7 @@ void common_hal_qspibus_qspibus_send( // Zero-length data write after a no-data command is benign. return; } - mp_raise_ValueError(MP_ERROR_TEXT("No pending command")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Internal error")); } if (data_length == 0) { @@ -593,6 +566,16 @@ void common_hal_qspibus_qspibus_end_transaction(mp_obj_t obj) { self->in_transaction = false; } +void common_hal_qspibus_qspibus_flush(mp_obj_t obj) { + qspibus_qspibus_obj_t *self = MP_OBJ_TO_PTR(obj); + if (!self->bus_initialized) { + return; + } + if (!qspibus_wait_all_transfers_done(self, pdMS_TO_TICKS(QSPI_COLOR_TIMEOUT_MS))) { + qspibus_reset_transfer_state(self); + } +} + void common_hal_qspibus_qspibus_collect_ptrs(mp_obj_t obj) { (void)obj; } diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.h b/ports/espressif/common-hal/qspibus/QSPIBus.h index caed3661cfd..eaaa971a79c 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.h +++ b/ports/espressif/common-hal/qspibus/QSPIBus.h @@ -33,7 +33,6 @@ typedef struct { int8_t cs_pin; int8_t dcx_pin; // -1 when optional DCX line is not provided. int8_t reset_pin; // -1 when reset line is not provided. - int8_t power_pin; // -1 when board has no explicit display power pin. uint32_t frequency; bool bus_initialized; diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index c7509753ec6..7bad99769df 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -394,25 +394,13 @@ typedef long mp_off_t; #define CIRCUITPY_DISPLAY_LIMIT (1) #endif -// Framebuffer area size in bytes. Rounded down to power of four for alignment. +// Display area buffer size in uint32_t words for _refresh_area() VLA. +// Allocated on stack; boards with larger displays can override per-board. +// Default 128 words = 512 bytes. #ifndef CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE #define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (128) #endif -// QSPI display buffer size in uint32_t words for _refresh_area() VLA. -// Allocated on stack; boards should verify sufficient stack headroom. -// Default 512 words = 2KB. Override per-board for larger buffers. -#ifndef CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE -#define CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE (512) -#endif - -// Port-level upper bound for the QSPI display buffer (uint32_t words). -// The _Static_assert in BusDisplay.c enforces this at compile time. -// Ports with larger stacks can raise this in mpconfigport.h. -#ifndef CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE_MAX -#define CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE_MAX (2048) -#endif - #else #define CIRCUITPY_DISPLAY_LIMIT (0) #define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (0) diff --git a/shared-bindings/displayio/__init__.h b/shared-bindings/displayio/__init__.h index 88e9650cf44..583f6b217fa 100644 --- a/shared-bindings/displayio/__init__.h +++ b/shared-bindings/displayio/__init__.h @@ -49,4 +49,5 @@ typedef bool (*display_bus_begin_transaction)(mp_obj_t bus); typedef void (*display_bus_send)(mp_obj_t bus, display_byte_type_t byte_type, display_chip_select_behavior_t chip_select, const uint8_t *data, uint32_t data_length); typedef void (*display_bus_end_transaction)(mp_obj_t bus); +typedef void (*display_bus_flush)(mp_obj_t bus); typedef void (*display_bus_collect_ptrs)(mp_obj_t bus); diff --git a/shared-bindings/qspibus/QSPIBus.h b/shared-bindings/qspibus/QSPIBus.h index a5d8f824ad2..140b639279d 100644 --- a/shared-bindings/qspibus/QSPIBus.h +++ b/shared-bindings/qspibus/QSPIBus.h @@ -49,4 +49,5 @@ void common_hal_qspibus_qspibus_send( const uint8_t *data, uint32_t data_length); void common_hal_qspibus_qspibus_end_transaction(mp_obj_t obj); +void common_hal_qspibus_qspibus_flush(mp_obj_t obj); void common_hal_qspibus_qspibus_collect_ptrs(mp_obj_t obj); diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 4610721a061..e83250740ba 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -16,9 +16,6 @@ #if CIRCUITPY_PARALLELDISPLAYBUS #include "shared-bindings/paralleldisplaybus/ParallelBus.h" #endif -#if CIRCUITPY_QSPIBUS -#include "shared-bindings/qspibus/QSPIBus.h" -#endif #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/time/__init__.h" #include "shared-module/displayio/__init__.h" @@ -217,7 +214,7 @@ static void _send_pixels(busdisplay_busdisplay_obj_t *self, uint8_t *pixels, uin } static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_area_t *area) { - uint32_t buffer_size = 128; // In uint32_ts + uint32_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE; // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. @@ -257,57 +254,6 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } } - #if CIRCUITPY_QSPIBUS - // QSPI panels benefit from larger sub-rectangle buffers because each chunk - // has non-trivial command/window overhead. Keep this path qspibus-specific - // to avoid increasing stack usage on other display buses. - // Guard: buffer is a VLA on stack. The port-specific max keeps shared - // code free of single-port assumptions (default 2048 words = 8KB). - _Static_assert(CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE <= CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE_MAX, - "CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE exceeds CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE_MAX"); - bool is_qspi_bus = mp_obj_is_type(self->bus.bus, &qspibus_qspibus_type); - if (is_qspi_bus && - self->core.colorspace.depth == 16 && - !self->bus.data_as_commands && - !self->bus.SH1107_addressing && - buffer_size < CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE) { - buffer_size = CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE; - rows_per_buffer = buffer_size * pixels_per_word / displayio_area_width(&clipped); - if (rows_per_buffer == 0) { - rows_per_buffer = 1; - } - // Clamp to actual display height. - if (rows_per_buffer > displayio_area_height(&clipped)) { - rows_per_buffer = displayio_area_height(&clipped); - } - subrectangles = displayio_area_height(&clipped) / rows_per_buffer; - if (displayio_area_height(&clipped) % rows_per_buffer != 0) { - subrectangles++; - } - pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); - buffer_size = pixels_per_buffer / pixels_per_word; - if (pixels_per_buffer % pixels_per_word) { - buffer_size += 1; - } - - // Ensure at least 2 rows per buffer when possible. - if (rows_per_buffer < 2 && - displayio_area_height(&clipped) > 1 && - (uint32_t)((2 * displayio_area_width(&clipped) + pixels_per_word - 1) / pixels_per_word) <= (uint32_t)CIRCUITPY_QSPI_DISPLAY_AREA_BUFFER_SIZE) { - rows_per_buffer = 2; - subrectangles = displayio_area_height(&clipped) / rows_per_buffer; - if (displayio_area_height(&clipped) % rows_per_buffer != 0) { - subrectangles++; - } - pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); - buffer_size = pixels_per_buffer / pixels_per_word; - if (pixels_per_buffer % pixels_per_word) { - buffer_size += 1; - } - } - } - #endif - // Allocated and shared as a uint32_t array so the compiler knows the // alignment everywhere. uint32_t mask_length = (pixels_per_buffer / 32) + 1; @@ -316,6 +262,8 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are uint16_t remaining_rows = displayio_area_height(&clipped); + bool async_bus = (self->bus.flush != NULL); + for (uint16_t j = 0; j < subrectangles; j++) { displayio_area_t subrectangle = { .x1 = clipped.x1, @@ -328,49 +276,33 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } remaining_rows -= rows_per_buffer; - #if CIRCUITPY_QSPIBUS - if (is_qspi_bus && - self->core.colorspace.depth >= 8 && - !self->bus.data_as_commands && - !self->bus.SH1107_addressing) { - // QSPI path: fill_area first (overlaps with previous DMA), - // then single-transaction set_region + RAMWR + pixels. - uint32_t subrectangle_size_bytes = (uint32_t)displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); + uint16_t subrectangle_size_bytes; + if (self->core.colorspace.depth >= 8) { + subrectangle_size_bytes = displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); + } else { + subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); + } - memset(mask, 0, mask_length * sizeof(mask[0])); - memset(buffer, 0, buffer_size * sizeof(buffer[0])); + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); + if (async_bus) { + // Async path: fill_area overlaps with previous DMA transfer. + // begin_transaction() waits for prior DMA to finish. displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - // begin_transaction waits for any prior async DMA to finish, - // so fill_area above overlaps with previous DMA. if (!displayio_display_bus_begin_transaction(&self->bus)) { - // Transaction failed (bus deinitialized, timeout, etc.). - // Bail out to prevent calling send() outside a transaction. return false; } displayio_display_bus_send_region_commands(&self->bus, &self->core, &subrectangle); _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); displayio_display_bus_end_transaction(&self->bus); - } else - #endif - { - // Non-QSPI path: original ordering preserved exactly. + } else { + // Sync path: set region first, then fill and send. displayio_display_bus_set_region_to_update(&self->bus, &self->core, &subrectangle); - uint16_t subrectangle_size_bytes; - if (self->core.colorspace.depth >= 8) { - subrectangle_size_bytes = displayio_area_size(&subrectangle) * (self->core.colorspace.depth / 8); - } else { - subrectangle_size_bytes = displayio_area_size(&subrectangle) / (8 / self->core.colorspace.depth); - } - - memset(mask, 0, mask_length * sizeof(mask[0])); - memset(buffer, 0, buffer_size * sizeof(buffer[0])); - displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - // Can't acquire display bus; skip the rest of the data. if (!displayio_display_bus_is_free(&self->bus)) { return false; } @@ -390,19 +322,8 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are #endif } - #if CIRCUITPY_QSPIBUS - if (is_qspi_bus) { - // Drain the last async DMA transfer before returning. - // Within the loop, begin_transaction() waits for the PREVIOUS - // subrectangle's DMA, enabling fill_area/DMA overlap. But the - // LAST subrectangle's DMA is still in-flight when the loop ends. - // Without this drain, bus_free() returns false on the next - // refresh() call, causing it to be silently skipped. - if (displayio_display_bus_begin_transaction(&self->bus)) { - displayio_display_bus_end_transaction(&self->bus); - } - } - #endif + // Drain any remaining asynchronous transfers. + displayio_display_bus_flush(&self->bus); return true; } diff --git a/shared-module/displayio/bus_core.c b/shared-module/displayio/bus_core.c index 5afa42f26fd..7362120e659 100644 --- a/shared-module/displayio/bus_core.c +++ b/shared-module/displayio/bus_core.c @@ -52,6 +52,8 @@ void displayio_display_bus_construct(displayio_display_bus_t *self, self->SH1107_addressing = SH1107_addressing; self->address_little_endian = address_little_endian; + self->flush = NULL; + #if CIRCUITPY_PARALLELDISPLAYBUS if (mp_obj_is_type(bus, ¶lleldisplaybus_parallelbus_type)) { self->bus_reset = common_hal_paralleldisplaybus_parallelbus_reset; @@ -89,6 +91,7 @@ void displayio_display_bus_construct(displayio_display_bus_t *self, self->begin_transaction = common_hal_qspibus_qspibus_begin_transaction; self->send = common_hal_qspibus_qspibus_send; self->end_transaction = common_hal_qspibus_qspibus_end_transaction; + self->flush = common_hal_qspibus_qspibus_flush; self->collect_ptrs = common_hal_qspibus_qspibus_collect_ptrs; } else #endif @@ -252,11 +255,15 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d _displayio_display_bus_send_region_commands(self, display, area, true); } -#if CIRCUITPY_QSPIBUS void displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { _displayio_display_bus_send_region_commands(self, display, area, false); } -#endif + +void displayio_display_bus_flush(displayio_display_bus_t *self) { + if (self->flush != NULL) { + self->flush(self->bus); + } +} void displayio_display_bus_collect_ptrs(displayio_display_bus_t *self) { self->collect_ptrs(self->bus); diff --git a/shared-module/displayio/bus_core.h b/shared-module/displayio/bus_core.h index bd7e51aeb45..163ccd2f148 100644 --- a/shared-module/displayio/bus_core.h +++ b/shared-module/displayio/bus_core.h @@ -21,6 +21,7 @@ typedef struct { display_bus_begin_transaction begin_transaction; display_bus_send send; display_bus_end_transaction end_transaction; + display_bus_flush flush; display_bus_collect_ptrs collect_ptrs; uint16_t ram_width; uint16_t ram_height; @@ -49,11 +50,13 @@ void displayio_display_bus_end_transaction(displayio_display_bus_t *self); void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area); -#if CIRCUITPY_QSPIBUS // Send column/row window commands within an already-open transaction. // Caller must have called displayio_display_bus_begin_transaction() first. void displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area); -#endif + +// Drain any pending asynchronous transfers on the bus. +// No-op for synchronous buses (FourWire, I2C, ParallelBus). +void displayio_display_bus_flush(displayio_display_bus_t *self); void release_display_bus(displayio_display_bus_t *self); diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 8116f4b0347..b120afad4c5 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -117,7 +117,7 @@ static const displayio_area_t *_get_refresh_areas(framebufferio_framebufferdispl #define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r / 8] |= (1 << (r & 7))) static bool _refresh_area(framebufferio_framebufferdisplay_obj_t *self, const displayio_area_t *area, uint8_t *dirty_row_bitmask) { - uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); // In uint32_ts + uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE; // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. From d2e9a584fc818af44b5004dc373f6b9533502a4e Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Tue, 3 Mar 2026 23:07:13 +0100 Subject: [PATCH 282/876] Fixes after the review --- ports/espressif/common-hal/qspibus/QSPIBus.c | 40 ++++++++------------ 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/ports/espressif/common-hal/qspibus/QSPIBus.c b/ports/espressif/common-hal/qspibus/QSPIBus.c index b4fabe91478..6fb872248e2 100644 --- a/ports/espressif/common-hal/qspibus/QSPIBus.c +++ b/ports/espressif/common-hal/qspibus/QSPIBus.c @@ -139,9 +139,6 @@ static void qspibus_send_color_bytes( qspibus_send_command_bytes(self, command, NULL, 0); return; } - if (self->dma_buffer_size == 0) { - mp_raise_OSError_msg(MP_ERROR_TEXT("Could not allocate DMA capable buffer")); - } // RAMWR must transition to RAMWRC for continued payload chunks. uint8_t chunk_command = command; @@ -290,8 +287,7 @@ void common_hal_qspibus_qspibus_construct( } if (!qspibus_allocate_dma_buffers(self)) { - vSemaphoreDelete(self->transfer_done_sem); - self->transfer_done_sem = NULL; + common_hal_qspibus_qspibus_deinit(self); mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("Could not allocate DMA capable buffer")); } @@ -307,12 +303,13 @@ void common_hal_qspibus_qspibus_construct( esp_err_t err = spi_bus_initialize(self->host_id, &bus_config, SPI_DMA_CH_AUTO); if (err != ESP_OK) { - qspibus_release_dma_buffers(self); - vSemaphoreDelete(self->transfer_done_sem); - self->transfer_done_sem = NULL; + common_hal_qspibus_qspibus_deinit(self); mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_SPI); } + // Mark bus as initialized so deinit knows to call spi_bus_free(). + self->bus_initialized = true; + const esp_lcd_panel_io_spi_config_t io_config = { .cs_gpio_num = self->cs_pin, .dc_gpio_num = -1, @@ -330,10 +327,7 @@ void common_hal_qspibus_qspibus_construct( err = esp_lcd_new_panel_io_spi((esp_lcd_spi_bus_handle_t)self->host_id, &io_config, &self->io_handle); if (err != ESP_OK) { - spi_bus_free(self->host_id); - qspibus_release_dma_buffers(self); - vSemaphoreDelete(self->transfer_done_sem); - self->transfer_done_sem = NULL; + common_hal_qspibus_qspibus_deinit(self); mp_raise_OSError_msg_varg(MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_QSPI, (int)err); } @@ -358,26 +352,22 @@ void common_hal_qspibus_qspibus_construct( gpio_set_level((gpio_num_t)self->reset_pin, 1); vTaskDelay(pdMS_TO_TICKS(120)); } - - self->bus_initialized = true; } void common_hal_qspibus_qspibus_deinit(qspibus_qspibus_obj_t *self) { - if (!self->bus_initialized) { - qspibus_release_dma_buffers(self); - return; - } + if (self->bus_initialized) { + qspibus_panel_sleep_best_effort(self); + self->in_transaction = false; - qspibus_panel_sleep_best_effort(self); - self->in_transaction = false; + if (self->io_handle != NULL) { + esp_lcd_panel_io_del(self->io_handle); + self->io_handle = NULL; + } - if (self->io_handle != NULL) { - esp_lcd_panel_io_del(self->io_handle); - self->io_handle = NULL; + spi_bus_free(self->host_id); + self->bus_initialized = false; } - spi_bus_free(self->host_id); - if (self->transfer_done_sem != NULL) { // Set NULL before delete so late ISR callbacks (if any) see NULL and skip. SemaphoreHandle_t sem = self->transfer_done_sem; From 44072a57c6f235f5f6e615988558fa66e86883af Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Mar 2026 14:26:34 -0800 Subject: [PATCH 283/876] Add peripheral support and tests --- ports/zephyr-cp/common-hal/_bleio/Adapter.c | 6 + .../tests/bsim/test_bsim_ble_peripheral.py | 143 ++++++++++++++++++ 2 files changed, 149 insertions(+) create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index 7f034cfc24d..5ba562146c8 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -148,6 +148,12 @@ static void bleio_connected_cb(struct bt_conn *conn, uint8_t err) { return; } + // When connectable advertising results in a connection, the controller + // auto-stops advertising. Clear our flag to match (we cannot call + // stop_advertising() here because this callback runs in Zephyr's BT + // thread context). + ble_advertising = false; + common_hal_bleio_adapter_obj.connection_objs = NULL; } diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py new file mode 100644 index 00000000000..f1db308bbfc --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py @@ -0,0 +1,143 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE peripheral connection tests for nrf5340bsim.""" + +import pytest + +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +BSIM_PERIPHERAL_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"CPPERIPH" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("peripheral start") +adapter.start_advertising(advertisement, connectable=True) +print("advertising", adapter.advertising) + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) + +print("connected", adapter.connected, "advertising", adapter.advertising) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) + +print("disconnected", adapter.connected, len(adapter.connections)) +""" + +BSIM_PERIPHERAL_CP_CENTRAL_PERIPHERAL_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"CPPERIPH" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("peripheral start") +adapter.start_advertising(advertisement, connectable=True) +print("advertising", adapter.advertising) + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) + +print("connected", adapter.connected, "advertising", adapter.advertising) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) + +print("disconnected", adapter.connected, len(adapter.connections)) +""" + +BSIM_PERIPHERAL_CP_CENTRAL_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("central start") +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPERIPH" in entry.advertisement_bytes: + target = entry.address + print("found peripheral") + break +adapter.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No connectable peripheral found") + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected, adapter.connected, len(adapter.connections)) +connection.disconnect() + +for _ in range(40): + if not connection.connected and not adapter.connected: + break + time.sleep(0.1) + +print("disconnected", connection.connected, adapter.connected, len(adapter.connections)) +""" + + +@pytest.mark.zephyr_sample("bluetooth/central") +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) +def test_bsim_peripheral_zephyr_central(bsim_phy, circuitpython, zephyr_sample): + """Advertise as connectable from CP; Zephyr central connects and disconnects.""" + central = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + central_output = central.serial.all_output + + assert "peripheral start" in cp_output + assert "advertising True" in cp_output + assert "connected True advertising False" in cp_output + assert "disconnected False 0" in cp_output + + assert "Scanning successfully started" in central_output + assert "Connected:" in central_output + assert "Disconnected:" in central_output + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CP_CENTRAL_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CP_CENTRAL_PERIPHERAL_CODE}) +def test_bsim_peripheral_cp_central(bsim_phy, circuitpython1, circuitpython2): + """Two CP instances: device 0 peripheral, device 1 central.""" + peripheral = circuitpython1 + central = circuitpython2 + + central.wait_until_done() + peripheral.wait_until_done() + + periph_output = peripheral.serial.all_output + central_output = central.serial.all_output + + assert "peripheral start" in periph_output + assert "advertising True" in periph_output + assert "connected True advertising False" in periph_output + assert "disconnected False 0" in periph_output + + assert "central start" in central_output + assert "found peripheral" in central_output + assert "have target True" in central_output + assert "connected True True 1" in central_output + assert "disconnected False False 0" in central_output From 907360e99cca00a3e36190f462fa8fb4bc5cbef0 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 3 Mar 2026 18:52:52 -0600 Subject: [PATCH 284/876] fix default_advance_width calculation, fix f_read(_,NULL) call, fix second slot of full width glyph overriding --- shared-module/lvfontio/OnDiskFont.c | 87 ++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 25 deletions(-) diff --git a/shared-module/lvfontio/OnDiskFont.c b/shared-module/lvfontio/OnDiskFont.c index 368bd381475..ade23280ed6 100644 --- a/shared-module/lvfontio/OnDiskFont.c +++ b/shared-module/lvfontio/OnDiskFont.c @@ -48,6 +48,7 @@ static inline void free_memory(lvfontio_ondiskfont_t *self, void *ptr) { // Forward declarations for helper functions static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint); +static bool slot_has_active_full_width_partner(lvfontio_ondiskfont_t *self, uint16_t slot); static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint); static FRESULT read_bits(FIL *file, size_t num_bits, uint8_t *byte_val, uint8_t *remaining_bits, uint32_t *result); static FRESULT read_glyph_dimensions(FIL *file, lvfontio_ondiskfont_t *self, uint32_t *advance_width, int32_t *bbox_x, int32_t *bbox_y, uint32_t *bbox_w, uint32_t *bbox_h, uint8_t *byte_val, uint8_t *remaining_bits); @@ -224,18 +225,24 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max // Throw away the bitmap bits. read_bits(file, self->header.bits_per_pixel * bbox_w * bbox_h, &byte_val, &remaining_bits, NULL); - if (advances[0] == glyph_advance) { - advance_count[0]++; - } else if (advances[1] == glyph_advance) { - advance_count[1]++; - } else if (advance_count[0] == 0) { - advances[0] = glyph_advance; - advance_count[0] = 1; - } else if (advance_count[1] == 0) { - advances[1] = glyph_advance; - advance_count[1] = 1; - } else { - break; + + // Ignore zero-advance glyphs when inferring the terminal cell width. + // Some fonts include placeholders/control glyphs with zero advance, + // which would otherwise skew default_advance_width too small. + if (glyph_advance > 0) { + if (advances[0] == glyph_advance) { + advance_count[0]++; + } else if (advances[1] == glyph_advance) { + advance_count[1]++; + } else if (advance_count[0] == 0) { + advances[0] = glyph_advance; + advance_count[0] = 1; + } else if (advance_count[1] == 0) { + advances[1] = glyph_advance; + advance_count[1] = 1; + } else { + break; + } } cid++; } @@ -257,6 +264,12 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max *max_slots = advance_count[0] + advance_count[1]; } + if (self->header.default_advance_width == 0) { + self->header.default_advance_width = 1; + } + if (*max_slots == 0) { + *max_slots = 1; + } found_glyf = true; } @@ -344,8 +357,9 @@ static int32_t get_char_id(lvfontio_ondiskfont_t *self, uint32_t codepoint) { for (size_t j = 0; j < self->cmap_ranges[i].entries_count; j++) { // Read code point at the index uint16_t candidate_codepoint_delta; - res = f_read(&self->file, &candidate_codepoint_delta, 2, NULL); - if (res != FR_OK) { + UINT bytes_read; + res = f_read(&self->file, &candidate_codepoint_delta, 2, &bytes_read); + if (res != FR_OK || bytes_read < 2) { return -1; } @@ -574,18 +588,18 @@ int16_t common_hal_lvfontio_ondiskfont_cache_glyph(lvfontio_ondiskfont_t *self, // Check if already cached int16_t existing_slot = find_codepoint_slot(self, codepoint); if (existing_slot >= 0) { - // Glyph is already cached, increment reference count + // Glyph is already cached, increment reference count(s). self->reference_counts[existing_slot]++; - // Check if this is a full-width character by looking for a second slot - // with the same codepoint right after this one + bool cached_is_full_width = existing_slot + 1 < self->max_glyphs && + self->codepoints[existing_slot + 1] == codepoint; + + if (cached_is_full_width) { + self->reference_counts[existing_slot + 1]++; + } + if (is_full_width != NULL) { - if (existing_slot + 1 < self->max_glyphs && - self->codepoints[existing_slot + 1] == codepoint) { - *is_full_width = true; - } else { - *is_full_width = false; - } + *is_full_width = cached_is_full_width; } return existing_slot; @@ -722,12 +736,34 @@ static int16_t find_codepoint_slot(lvfontio_ondiskfont_t *self, uint32_t codepoi for (uint16_t i = 0; i < self->max_glyphs; i++) { int16_t slot = (i + offset) % self->max_glyphs; if (self->codepoints[slot] == codepoint) { + // If this is the second slot of a full-width glyph pair, return the + // first slot so callers always get a canonical index. + if (slot > 0 && self->codepoints[slot - 1] == codepoint) { + return slot - 1; + } return slot; } } return -1; } +static bool slot_has_active_full_width_partner(lvfontio_ondiskfont_t *self, uint16_t slot) { + uint32_t codepoint = self->codepoints[slot]; + if (codepoint == LVFONTIO_INVALID_CODEPOINT) { + return false; + } + + // Don't evict one half of a full-width pair while the other half is still in use. + if (slot > 0 && self->codepoints[slot - 1] == codepoint && self->reference_counts[slot - 1] > 0) { + return true; + } + if (slot + 1 < self->max_glyphs && self->codepoints[slot + 1] == codepoint && self->reference_counts[slot + 1] > 0) { + return true; + } + + return false; +} + static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint) { size_t offset = codepoint % self->max_glyphs; @@ -739,10 +775,11 @@ static uint16_t find_free_slot(lvfontio_ondiskfont_t *self, uint32_t codepoint) } } - // If none found, look for slots with zero reference count, starting at the offset + // If none found, look for slots with zero reference count, starting at the offset. + // Avoid reusing one half of an active full-width glyph pair. for (uint16_t i = 0; i < self->max_glyphs; i++) { int16_t slot = (i + offset) % self->max_glyphs; - if (self->reference_counts[slot] == 0) { + if (self->reference_counts[slot] == 0 && !slot_has_active_full_width_partner(self, slot)) { return slot; } } From a2532bd5370b9c08da0f1a77bd0aebb934f67aaf Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 3 Mar 2026 19:10:39 -0600 Subject: [PATCH 285/876] return comment --- shared-module/lvfontio/OnDiskFont.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared-module/lvfontio/OnDiskFont.c b/shared-module/lvfontio/OnDiskFont.c index ade23280ed6..f6458346e93 100644 --- a/shared-module/lvfontio/OnDiskFont.c +++ b/shared-module/lvfontio/OnDiskFont.c @@ -591,6 +591,8 @@ int16_t common_hal_lvfontio_ondiskfont_cache_glyph(lvfontio_ondiskfont_t *self, // Glyph is already cached, increment reference count(s). self->reference_counts[existing_slot]++; + // Check if this is a full-width character by looking for a second slot + // with the same codepoint right after this one bool cached_is_full_width = existing_slot + 1 < self->max_glyphs && self->codepoints[existing_slot + 1] == codepoint; From 69dedabf140b10d573a1066398d8902e4d15a55f Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Wed, 4 Mar 2026 19:42:56 +0100 Subject: [PATCH 286/876] Review fixes --- .../mpconfigboard.h | 4 +-- py/circuitpy_mpconfig.h | 6 ++-- shared-module/busdisplay/BusDisplay.c | 32 ++++--------------- shared-module/displayio/bus_core.c | 4 --- shared-module/displayio/bus_core.h | 4 --- .../framebufferio/FramebufferDisplay.c | 2 +- 6 files changed, 13 insertions(+), 39 deletions(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h index 242cca6b30d..9ac461ee61d 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -11,9 +11,9 @@ #define CIRCUITPY_BOARD_I2C (0) #define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO48, .sda = &pin_GPIO47}} -// Display refresh buffer: 2048 uint32_t words = 8KB on stack. +// Display refresh buffer: 8192 bytes = 2048 uint32_t words on stack. // ESP32-S3 main task stack is 24KB; verified safe with this board. -#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (2048) +#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (8192) // AMOLED Display (displayio + qspibus path) - initialized in board_init() #define CIRCUITPY_BOARD_DISPLAY (1) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 7bad99769df..3918296636a 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -394,11 +394,11 @@ typedef long mp_off_t; #define CIRCUITPY_DISPLAY_LIMIT (1) #endif -// Display area buffer size in uint32_t words for _refresh_area() VLA. +// Display area buffer size in bytes for _refresh_area() VLA. // Allocated on stack; boards with larger displays can override per-board. -// Default 128 words = 512 bytes. +// Default 512 bytes = 128 uint32_t words. #ifndef CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE -#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (128) +#define CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE (512) #endif #else diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index e83250740ba..3626d2d2c3e 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -214,7 +214,7 @@ static void _send_pixels(busdisplay_busdisplay_obj_t *self, uint8_t *pixels, uin } static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_area_t *area) { - uint32_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE; // In uint32_ts + uint32_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. @@ -262,8 +262,6 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are uint16_t remaining_rows = displayio_area_height(&clipped); - bool async_bus = (self->bus.flush != NULL); - for (uint16_t j = 0; j < subrectangles; j++) { displayio_area_t subrectangle = { .x1 = clipped.x1, @@ -286,31 +284,15 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are memset(mask, 0, mask_length * sizeof(mask[0])); memset(buffer, 0, buffer_size * sizeof(buffer[0])); - if (async_bus) { - // Async path: fill_area overlaps with previous DMA transfer. - // begin_transaction() waits for prior DMA to finish. - displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - - if (!displayio_display_bus_begin_transaction(&self->bus)) { - return false; - } - displayio_display_bus_send_region_commands(&self->bus, &self->core, &subrectangle); - _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); - displayio_display_bus_end_transaction(&self->bus); - } else { - // Sync path: set region first, then fill and send. - displayio_display_bus_set_region_to_update(&self->bus, &self->core, &subrectangle); - - displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); - if (!displayio_display_bus_is_free(&self->bus)) { - return false; - } + displayio_display_bus_set_region_to_update(&self->bus, &self->core, &subrectangle); - displayio_display_bus_begin_transaction(&self->bus); - _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); - displayio_display_bus_end_transaction(&self->bus); + if (!displayio_display_bus_begin_transaction(&self->bus)) { + return false; } + _send_pixels(self, (uint8_t *)buffer, subrectangle_size_bytes); + displayio_display_bus_end_transaction(&self->bus); // Run background tasks so they can run during an explicit refresh. // Auto-refresh won't run background tasks here because it is a background task itself. diff --git a/shared-module/displayio/bus_core.c b/shared-module/displayio/bus_core.c index 7362120e659..df6c5d36f4b 100644 --- a/shared-module/displayio/bus_core.c +++ b/shared-module/displayio/bus_core.c @@ -255,10 +255,6 @@ void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, d _displayio_display_bus_send_region_commands(self, display, area, true); } -void displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { - _displayio_display_bus_send_region_commands(self, display, area, false); -} - void displayio_display_bus_flush(displayio_display_bus_t *self) { if (self->flush != NULL) { self->flush(self->bus); diff --git a/shared-module/displayio/bus_core.h b/shared-module/displayio/bus_core.h index 163ccd2f148..75d03d7f284 100644 --- a/shared-module/displayio/bus_core.h +++ b/shared-module/displayio/bus_core.h @@ -50,10 +50,6 @@ void displayio_display_bus_end_transaction(displayio_display_bus_t *self); void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area); -// Send column/row window commands within an already-open transaction. -// Caller must have called displayio_display_bus_begin_transaction() first. -void displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area); - // Drain any pending asynchronous transfers on the bus. // No-op for synchronous buses (FourWire, I2C, ParallelBus). void displayio_display_bus_flush(displayio_display_bus_t *self); diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index b120afad4c5..8116f4b0347 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -117,7 +117,7 @@ static const displayio_area_t *_get_refresh_areas(framebufferio_framebufferdispl #define MARK_ROW_DIRTY(r) (dirty_row_bitmask[r / 8] |= (1 << (r & 7))) static bool _refresh_area(framebufferio_framebufferdisplay_obj_t *self, const displayio_area_t *area, uint8_t *dirty_row_bitmask) { - uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE; // In uint32_ts + uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. From 7150f82c9d862db0b89f044f0192d629142bb840 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 4 Mar 2026 11:00:16 -0800 Subject: [PATCH 287/876] Address feedback --- .../ble_hci/common-hal/_bleio/Characteristic.c | 2 +- devices/ble_hci/common-hal/_bleio/Connection.h | 2 +- devices/ble_hci/common-hal/_bleio/__init__.c | 2 +- .../espressif/common-hal/_bleio/Characteristic.c | 2 +- ports/espressif/common-hal/_bleio/Connection.h | 2 +- ports/espressif/common-hal/_bleio/__init__.c | 2 +- ports/nordic/common-hal/_bleio/Attribute.h | 8 ++++---- ports/nordic/common-hal/_bleio/Characteristic.c | 10 +++++----- ports/nordic/common-hal/_bleio/Connection.h | 2 +- ports/nordic/common-hal/_bleio/Descriptor.c | 8 ++++---- ports/nordic/common-hal/_bleio/__init__.c | 16 ++++++++-------- ports/silabs/common-hal/_bleio/Characteristic.c | 2 +- ports/silabs/common-hal/_bleio/Connection.h | 2 +- ports/silabs/common-hal/_bleio/__init__.c | 2 +- shared-bindings/_bleio/Characteristic.c | 3 ++- shared-bindings/_bleio/Descriptor.c | 3 ++- 16 files changed, 35 insertions(+), 33 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Characteristic.c b/devices/ble_hci/common-hal/_bleio/Characteristic.c index a33b8ff4784..49b66d38e72 100644 --- a/devices/ble_hci/common-hal/_bleio/Characteristic.c +++ b/devices/ble_hci/common-hal/_bleio/Characteristic.c @@ -180,7 +180,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, } const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); - common_hal_bleio_check_connected(conn_handle); + bleio_check_connected(conn_handle); uint16_t cccd_value = (notify ? CCCD_NOTIFY : 0) | diff --git a/devices/ble_hci/common-hal/_bleio/Connection.h b/devices/ble_hci/common-hal/_bleio/Connection.h index fa9f4c7103e..02a000501bf 100644 --- a/devices/ble_hci/common-hal/_bleio/Connection.h +++ b/devices/ble_hci/common-hal/_bleio/Connection.h @@ -61,7 +61,7 @@ typedef struct { uint8_t disconnect_reason; } bleio_connection_obj_t; -void common_hal_bleio_check_connected(uint16_t conn_handle); +void bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index 6376f6f10c8..f9fdbc50f64 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -84,7 +84,7 @@ bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void) { return &common_hal_bleio_adapter_obj; } -void common_hal_bleio_check_connected(uint16_t conn_handle) { +void bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLE_CONN_HANDLE_INVALID) { mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); } diff --git a/ports/espressif/common-hal/_bleio/Characteristic.c b/ports/espressif/common-hal/_bleio/Characteristic.c index 805c6d160f3..736c61c650e 100644 --- a/ports/espressif/common-hal/_bleio/Characteristic.c +++ b/ports/espressif/common-hal/_bleio/Characteristic.c @@ -320,7 +320,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, } const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); - common_hal_bleio_check_connected(conn_handle); + bleio_check_connected(conn_handle); uint16_t cccd_value = (notify ? 1 << 0 : 0) | diff --git a/ports/espressif/common-hal/_bleio/Connection.h b/ports/espressif/common-hal/_bleio/Connection.h index bb48782e84f..5f33eb43b5d 100644 --- a/ports/espressif/common-hal/_bleio/Connection.h +++ b/ports/espressif/common-hal/_bleio/Connection.h @@ -64,7 +64,7 @@ void bleio_connection_clear(bleio_connection_internal_t *self); int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in); -void common_hal_bleio_check_connected(uint16_t conn_handle); +void bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index 119fe55921e..4fdd0a48a20 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -155,7 +155,7 @@ void check_notify(BaseType_t result) { mp_raise_msg(&mp_type_TimeoutError, NULL); } -void common_hal_bleio_check_connected(uint16_t conn_handle) { +void bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLEIO_HANDLE_INVALID) { mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); } diff --git a/ports/nordic/common-hal/_bleio/Attribute.h b/ports/nordic/common-hal/_bleio/Attribute.h index c9438571a86..9a58e16bb86 100644 --- a/ports/nordic/common-hal/_bleio/Attribute.h +++ b/ports/nordic/common-hal/_bleio/Attribute.h @@ -14,7 +14,7 @@ extern void bleio_attribute_gatts_set_security_mode(ble_gap_conn_sec_mode_t *perm, bleio_attribute_security_mode_t security_mode); -size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); -void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); -size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); -void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); +size_t bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); +void bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo); +size_t bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len); +void bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response); diff --git a/ports/nordic/common-hal/_bleio/Characteristic.c b/ports/nordic/common-hal/_bleio/Characteristic.c index 51335be9e59..2e6042e48e7 100644 --- a/ports/nordic/common-hal/_bleio/Characteristic.c +++ b/ports/nordic/common-hal/_bleio/Characteristic.c @@ -138,10 +138,10 @@ size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *sel if (self->handle != BLE_GATT_HANDLE_INVALID) { uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); if (common_hal_bleio_service_get_is_remote(self->service)) { - return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); + return bleio_gattc_read(self->handle, conn_handle, buf, len); } else { // conn_handle is ignored for non-system attributes. - return common_hal_bleio_gatts_read(self->handle, conn_handle, buf, len); + return bleio_gatts_read(self->handle, conn_handle, buf, len); } } @@ -159,7 +159,7 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, if (common_hal_bleio_service_get_is_remote(self->service)) { uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); // Last argument is true if write-no-reponse desired. - common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, + bleio_gattc_write(self->handle, conn_handle, bufinfo, (self->props & CHAR_PROP_WRITE_NO_RESPONSE)); } else { // Validate data length for local characteristics only. @@ -172,7 +172,7 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, // Always write the value locally even if no connections are active. // conn_handle is ignored for non-system attributes, so we use BLE_CONN_HANDLE_INVALID. - common_hal_bleio_gatts_write(self->handle, BLE_CONN_HANDLE_INVALID, bufinfo); + bleio_gatts_write(self->handle, BLE_CONN_HANDLE_INVALID, bufinfo); // Check to see if we need to notify or indicate any active connections. for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; @@ -255,7 +255,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, } const uint16_t conn_handle = bleio_connection_get_conn_handle(self->service->connection); - common_hal_bleio_check_connected(conn_handle); + bleio_check_connected(conn_handle); uint16_t cccd_value = (notify ? BLE_GATT_HVX_NOTIFICATION : 0) | diff --git a/ports/nordic/common-hal/_bleio/Connection.h b/ports/nordic/common-hal/_bleio/Connection.h index 87e0e9856a4..ea1edf17603 100644 --- a/ports/nordic/common-hal/_bleio/Connection.h +++ b/ports/nordic/common-hal/_bleio/Connection.h @@ -65,7 +65,7 @@ typedef struct { void bleio_connection_clear(bleio_connection_internal_t *self); bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in); -void common_hal_bleio_check_connected(uint16_t conn_handle); +void bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); bleio_connection_internal_t *bleio_conn_handle_to_connection(uint16_t conn_handle); diff --git a/ports/nordic/common-hal/_bleio/Descriptor.c b/ports/nordic/common-hal/_bleio/Descriptor.c index 959c8e5c9c0..0d27ca5dc2e 100644 --- a/ports/nordic/common-hal/_bleio/Descriptor.c +++ b/ports/nordic/common-hal/_bleio/Descriptor.c @@ -43,9 +43,9 @@ size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8 if (self->handle != BLE_GATT_HANDLE_INVALID) { uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { - return common_hal_bleio_gattc_read(self->handle, conn_handle, buf, len); + return bleio_gattc_read(self->handle, conn_handle, buf, len); } else { - return common_hal_bleio_gatts_read(self->handle, conn_handle, buf, len); + return bleio_gatts_read(self->handle, conn_handle, buf, len); } } @@ -58,7 +58,7 @@ void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buff uint16_t conn_handle = bleio_connection_get_conn_handle(self->characteristic->service->connection); if (common_hal_bleio_service_get_is_remote(self->characteristic->service)) { // false means WRITE_REQ, not write-no-response - common_hal_bleio_gattc_write(self->handle, conn_handle, bufinfo, false); + bleio_gattc_write(self->handle, conn_handle, bufinfo, false); } else { // Validate data length for local descriptors only. if (self->fixed_length && bufinfo->len != self->max_length) { @@ -68,7 +68,7 @@ void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buff mp_raise_ValueError(MP_ERROR_TEXT("Value length > max_length")); } - common_hal_bleio_gatts_write(self->handle, conn_handle, bufinfo); + bleio_gatts_write(self->handle, conn_handle, bufinfo); } } diff --git a/ports/nordic/common-hal/_bleio/__init__.c b/ports/nordic/common-hal/_bleio/__init__.c index 454937dcd35..9dc58d7687c 100644 --- a/ports/nordic/common-hal/_bleio/__init__.c +++ b/ports/nordic/common-hal/_bleio/__init__.c @@ -112,14 +112,14 @@ void bleio_reset(void) { // It currently only has properties and no state. Inited by bleio_reset bleio_adapter_obj_t common_hal_bleio_adapter_obj; -void common_hal_bleio_check_connected(uint16_t conn_handle) { +void bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLE_CONN_HANDLE_INVALID) { mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); } } // GATTS read of a Characteristic or Descriptor. -size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { +size_t bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { // conn_handle is ignored unless this is a system attribute. // If we're not connected, that's OK, because we can still read and write the local value. @@ -133,7 +133,7 @@ size_t common_hal_bleio_gatts_read(uint16_t handle, uint16_t conn_handle, uint8_ return gatts_value.len; } -void common_hal_bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { +void bleio_gatts_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo) { // conn_handle is ignored unless this is a system attribute. // If we're not connected, that's OK, because we can still read and write the local value. @@ -188,8 +188,8 @@ static bool _on_gattc_read_rsp_evt(ble_evt_t *ble_evt, void *param) { return true; } -size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { - common_hal_bleio_check_connected(conn_handle); +size_t bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_t *buf, size_t len) { + bleio_check_connected(conn_handle); read_info_t read_info; read_info.buf = buf; @@ -213,15 +213,15 @@ size_t common_hal_bleio_gattc_read(uint16_t handle, uint16_t conn_handle, uint8_ RUN_BACKGROUND_TASKS; } // Test if we were disconnected while reading - common_hal_bleio_check_connected(read_info.conn_handle); + bleio_check_connected(read_info.conn_handle); ble_drv_remove_event_handler(_on_gattc_read_rsp_evt, &read_info); check_gatt_status(read_info.status); return read_info.final_len; } -void common_hal_bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { - common_hal_bleio_check_connected(conn_handle); +void bleio_gattc_write(uint16_t handle, uint16_t conn_handle, mp_buffer_info_t *bufinfo, bool write_no_response) { + bleio_check_connected(conn_handle); ble_gattc_write_params_t write_params = { .write_op = write_no_response ? BLE_GATT_OP_WRITE_CMD: BLE_GATT_OP_WRITE_REQ, diff --git a/ports/silabs/common-hal/_bleio/Characteristic.c b/ports/silabs/common-hal/_bleio/Characteristic.c index a707b0ef1ac..9ccc6ad9c36 100644 --- a/ports/silabs/common-hal/_bleio/Characteristic.c +++ b/ports/silabs/common-hal/_bleio/Characteristic.c @@ -395,7 +395,7 @@ void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, const uint16_t conn_handle = bleio_connection_get_conn_handle( self->service->connection); - common_hal_bleio_check_connected(conn_handle); + bleio_check_connected(conn_handle); notify = 1; indicate = 0; if (notify) { diff --git a/ports/silabs/common-hal/_bleio/Connection.h b/ports/silabs/common-hal/_bleio/Connection.h index 23976d3c849..148caecba11 100644 --- a/ports/silabs/common-hal/_bleio/Connection.h +++ b/ports/silabs/common-hal/_bleio/Connection.h @@ -85,7 +85,7 @@ typedef struct void bleio_connection_clear(bleio_connection_internal_t *self); -void common_hal_bleio_check_connected(uint16_t conn_handle); +void bleio_check_connected(uint16_t conn_handle); uint16_t bleio_connection_get_conn_handle(bleio_connection_obj_t *self); mp_obj_t bleio_connection_new_from_internal( diff --git a/ports/silabs/common-hal/_bleio/__init__.c b/ports/silabs/common-hal/_bleio/__init__.c index c6ae8a0b606..4c5ce1f045d 100644 --- a/ports/silabs/common-hal/_bleio/__init__.c +++ b/ports/silabs/common-hal/_bleio/__init__.c @@ -102,7 +102,7 @@ void check_ble_error(int error_code) { } } -void common_hal_bleio_check_connected(uint16_t conn_handle) { +void bleio_check_connected(uint16_t conn_handle) { if (conn_handle == BLEIO_HANDLE_INVALID) { mp_raise_ConnectionError(MP_ERROR_TEXT("Not connected")); } diff --git a/shared-bindings/_bleio/Characteristic.c b/shared-bindings/_bleio/Characteristic.c index b017295b45f..0ed4c2b7eaa 100644 --- a/shared-bindings/_bleio/Characteristic.c +++ b/shared-bindings/_bleio/Characteristic.c @@ -116,9 +116,10 @@ static mp_obj_t bleio_characteristic_add_to_service(size_t n_args, const mp_obj_ } mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); - mp_arg_validate_length_max(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); if (fixed_length) { mp_arg_validate_length(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); + } else { + mp_arg_validate_length_max(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); } const char *user_description = NULL; diff --git a/shared-bindings/_bleio/Descriptor.c b/shared-bindings/_bleio/Descriptor.c index 8e721ff292d..9e29f57d8dd 100644 --- a/shared-bindings/_bleio/Descriptor.c +++ b/shared-bindings/_bleio/Descriptor.c @@ -99,9 +99,10 @@ static mp_obj_t bleio_descriptor_add_to_characteristic(size_t n_args, const mp_o } } mp_get_buffer_raise(initial_value, &initial_value_bufinfo, MP_BUFFER_READ); - mp_arg_validate_length_max(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); if (fixed_length) { mp_arg_validate_length(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); + } else { + mp_arg_validate_length_max(initial_value_bufinfo.len, max_length, MP_QSTR_initial_value); } bleio_descriptor_obj_t *descriptor = mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type); From f4f77e4e2832f29cd1ddaba0826a403789da05e6 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 4 Mar 2026 16:06:51 -0600 Subject: [PATCH 288/876] fix wrapping issue on glyph slots, refactor glyph_advance check. --- shared-module/lvfontio/OnDiskFont.c | 48 +++++++++++++++-------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/shared-module/lvfontio/OnDiskFont.c b/shared-module/lvfontio/OnDiskFont.c index f6458346e93..efffed63074 100644 --- a/shared-module/lvfontio/OnDiskFont.c +++ b/shared-module/lvfontio/OnDiskFont.c @@ -226,23 +226,22 @@ static bool load_font_header(lvfontio_ondiskfont_t *self, FIL *file, size_t *max // Throw away the bitmap bits. read_bits(file, self->header.bits_per_pixel * bbox_w * bbox_h, &byte_val, &remaining_bits, NULL); - // Ignore zero-advance glyphs when inferring the terminal cell width. - // Some fonts include placeholders/control glyphs with zero advance, - // which would otherwise skew default_advance_width too small. - if (glyph_advance > 0) { - if (advances[0] == glyph_advance) { - advance_count[0]++; - } else if (advances[1] == glyph_advance) { - advance_count[1]++; - } else if (advance_count[0] == 0) { - advances[0] = glyph_advance; - advance_count[0] = 1; - } else if (advance_count[1] == 0) { - advances[1] = glyph_advance; - advance_count[1] = 1; - } else { - break; - } + if (glyph_advance == 0) { + // Ignore zero-advance glyphs when inferring the terminal cell width. + // Some fonts include placeholders/control glyphs with zero advance, + // which would otherwise skew default_advance_width too small. + } else if (advances[0] == glyph_advance) { + advance_count[0]++; + } else if (advances[1] == glyph_advance) { + advance_count[1]++; + } else if (advance_count[0] == 0) { + advances[0] = glyph_advance; + advance_count[0] = 1; + } else if (advance_count[1] == 0) { + advances[1] = glyph_advance; + advance_count[1] = 1; + } else { + break; } cid++; } @@ -592,12 +591,12 @@ int16_t common_hal_lvfontio_ondiskfont_cache_glyph(lvfontio_ondiskfont_t *self, self->reference_counts[existing_slot]++; // Check if this is a full-width character by looking for a second slot - // with the same codepoint right after this one - bool cached_is_full_width = existing_slot + 1 < self->max_glyphs && - self->codepoints[existing_slot + 1] == codepoint; + // with the same codepoint right after this one, wrapping at the end. + uint16_t next_slot = (existing_slot + 1) % self->max_glyphs; + bool cached_is_full_width = self->codepoints[next_slot] == codepoint; if (cached_is_full_width) { - self->reference_counts[existing_slot + 1]++; + self->reference_counts[next_slot]++; } if (is_full_width != NULL) { @@ -756,10 +755,13 @@ static bool slot_has_active_full_width_partner(lvfontio_ondiskfont_t *self, uint } // Don't evict one half of a full-width pair while the other half is still in use. - if (slot > 0 && self->codepoints[slot - 1] == codepoint && self->reference_counts[slot - 1] > 0) { + uint16_t prev_slot = (slot + self->max_glyphs - 1) % self->max_glyphs; + uint16_t next_slot = (slot + 1) % self->max_glyphs; + + if (self->codepoints[prev_slot] == codepoint && self->reference_counts[prev_slot] > 0) { return true; } - if (slot + 1 < self->max_glyphs && self->codepoints[slot + 1] == codepoint && self->reference_counts[slot + 1] > 0) { + if (self->codepoints[next_slot] == codepoint && self->reference_counts[next_slot] > 0) { return true; } From 860ab98e85195112c288ce2d7dfbdc4de36c704e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 3 Feb 2026 13:11:37 -0800 Subject: [PATCH 289/876] Add heap stat tracking to native_sim This adds two tracks "Outer Heap Used" and "VM Heap Used" to the output perfetto trace. --- ports/zephyr-cp/supervisor/port.c | 95 ++++++++++++++++++++++++-- ports/zephyr-cp/zephyr-config/west.yml | 2 +- py/gc.c | 48 +++++++++++++ 3 files changed, 138 insertions(+), 7 deletions(-) diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 08a84043e8e..8b73169d8a0 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -16,6 +16,7 @@ #include #include #include +#include #if defined(CONFIG_ARCH_POSIX) #include @@ -29,7 +30,16 @@ #include "lib/tlsf/tlsf.h" #include +#if defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) +#include "perfetto_encoder.h" +#include +#define CIRCUITPY_PERFETTO_TRACK_GROUP_UUID 0x3000ULL +#define CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID 0x3001ULL +#define CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID 0x3002ULL +#endif + static tlsf_t heap; +static size_t tlsf_heap_used = 0; // Auto generated in pins.c extern const struct device *const rams[]; @@ -72,12 +82,60 @@ static void native_sim_register_cmdline_opts(void) { NATIVE_TASK(native_sim_register_cmdline_opts, PRE_BOOT_1, 0); #endif +#if defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) +static bool perfetto_circuitpython_tracks_emitted; + +static void perfetto_emit_outer_heap_stats(void) { + if (!perfetto_start()) { + return; + } + size_t total = tlsf_heap_used; + #if defined(CONFIG_COMMON_LIBC_MALLOC) && defined(CONFIG_SYS_HEAP_RUNTIME_STATS) + extern int malloc_runtime_stats_get(struct sys_memory_stats *stats); + struct sys_memory_stats stats; + if (malloc_runtime_stats_get(&stats) == 0) { + total += stats.allocated_bytes; + } + #endif + perfetto_emit_counter(CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID, (int64_t)total); + Z_SPIN_DELAY(1); +} + +static void perfetto_emit_circuitpython_tracks(void) { + if (perfetto_circuitpython_tracks_emitted) { + return; + } + if (!perfetto_start()) { + return; + } + perfetto_emit_track_descriptor(CIRCUITPY_PERFETTO_TRACK_GROUP_UUID, + perfetto_get_process_uuid(), + "CircuitPython"); + perfetto_emit_counter_track_descriptor(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID, + CIRCUITPY_PERFETTO_TRACK_GROUP_UUID, + "VM Heap Used", + PERFETTO_COUNTER_UNIT_BYTES); + perfetto_emit_counter_track_descriptor(CIRCUITPY_PERFETTO_OUTER_HEAP_USED_UUID, + CIRCUITPY_PERFETTO_TRACK_GROUP_UUID, + "Outer Heap Used", + PERFETTO_COUNTER_UNIT_BYTES); + perfetto_circuitpython_tracks_emitted = true; +} +#else +static inline void perfetto_emit_outer_heap_stats(void) { +} + +static inline void perfetto_emit_circuitpython_tracks(void) { +} +#endif + static void _tick_function(struct k_timer *timer_id) { supervisor_tick(); } safe_mode_t port_init(void) { k_timer_init(&tick_timer, _tick_function, NULL); + perfetto_emit_circuitpython_tracks(); return SAFE_MODE_NONE; } @@ -233,6 +291,7 @@ void port_heap_init(void) { } valid_pool_count++; } + perfetto_emit_outer_heap_stats(); #if !DT_HAS_CHOSEN(zephyr_sram) #error "No SRAM!" #endif @@ -243,30 +302,54 @@ void *port_malloc(size_t size, bool dma_capable) { if (valid_pool_count > 0) { block = tlsf_malloc(heap, size); } + if (block != NULL) { + tlsf_heap_used += tlsf_block_size(block); + } #ifdef CONFIG_COMMON_LIBC_MALLOC if (block == NULL) { block = malloc(size); } #endif + if (block != NULL) { + perfetto_emit_outer_heap_stats(); + } return block; } void port_free(void *ptr) { + if (ptr == NULL) { + return; + } if (valid_pool_count > 0 && !(ptr >= zephyr_malloc_bottom && ptr < zephyr_malloc_top)) { + tlsf_heap_used -= tlsf_block_size(ptr); tlsf_free(heap, ptr); - return; + } else { + #ifdef CONFIG_COMMON_LIBC_MALLOC + free(ptr); + #endif } - #ifdef CONFIG_COMMON_LIBC_MALLOC - free(ptr); - #endif + perfetto_emit_outer_heap_stats(); } void *port_realloc(void *ptr, size_t size, bool dma_capable) { + if (ptr == NULL) { + return port_malloc(size, dma_capable); + } if (valid_pool_count > 0 && !(ptr >= zephyr_malloc_bottom && ptr < zephyr_malloc_top)) { - return tlsf_realloc(heap, ptr, size); + size_t old_size = tlsf_block_size(ptr); + void *new_block = tlsf_realloc(heap, ptr, size); + if (new_block != NULL) { + tlsf_heap_used = tlsf_heap_used - old_size + tlsf_block_size(new_block); + perfetto_emit_outer_heap_stats(); + } + return new_block; } #ifdef CONFIG_COMMON_LIBC_MALLOC - return realloc(ptr, size); + void *new_block = realloc(ptr, size); + if (new_block != NULL) { + perfetto_emit_outer_heap_stats(); + } + return new_block; #endif return NULL; } diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index bb5c9b4942b..17a68bf8be7 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -8,6 +8,6 @@ manifest: path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: 5351284ac926b1352ab98f5ae692a21f38068beb + revision: 589b2139926017d4d98724bac653ceb30802be9f clone-depth: 100 import: true diff --git a/py/gc.c b/py/gc.c index c6da81d495c..fc7de6c4d3b 100644 --- a/py/gc.c +++ b/py/gc.c @@ -32,6 +32,12 @@ #include "py/gc.h" #include "py/runtime.h" +#if defined(__ZEPHYR__) +#include +#include +#include +#endif + #if MICROPY_DEBUG_VALGRIND #include #endif @@ -45,6 +51,12 @@ #include "shared-module/memorymonitor/__init__.h" #endif +#if defined(__ZEPHYR__) && defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) +#include "perfetto_encoder.h" +#define CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID 0x3001ULL +#define CIRCUITPY_PERFETTO_VM_HEAP_MAX_FREE_UUID 0x3002ULL +#endif + #if MICROPY_ENABLE_GC #if MICROPY_DEBUG_VERBOSE // print debugging info @@ -158,6 +170,32 @@ void __attribute__ ((noinline)) gc_log_change(uint32_t start_block, uint32_t len #pragma GCC pop_options #endif +#if defined(__ZEPHYR__) && defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) +static void gc_perfetto_emit_heap_stats(void) { + if (!perfetto_start()) { + return; + } + gc_info_t info; + gc_info(&info); + perfetto_emit_counter(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID, (int64_t)info.used); + Z_SPIN_DELAY(1); +} + +static void gc_perfetto_emit_heap_stopped(void) { + if (!perfetto_start()) { + return; + } + perfetto_emit_counter(CIRCUITPY_PERFETTO_VM_HEAP_USED_UUID, 0); + Z_SPIN_DELAY(1); +} +#else +static inline void gc_perfetto_emit_heap_stats(void) { +} + +static inline void gc_perfetto_emit_heap_stopped(void) { +} +#endif + // Static functions for individual steps of the GC mark/sweep sequence static void gc_collect_start_common(void); static void *gc_get_ptr(void **ptrs, int i); @@ -284,6 +322,7 @@ void gc_init(void *start, void *end) { #endif GC_MUTEX_INIT(); + gc_perfetto_emit_heap_stats(); } #if MICROPY_GC_SPLIT_HEAP @@ -425,6 +464,7 @@ void gc_deinit(void) { // Run any finalisers before we stop using the heap. This will also free // any additional heap areas (but not the first.) gc_sweep_all(); + gc_perfetto_emit_heap_stopped(); memset(&MP_STATE_MEM(area), 0, sizeof(MP_STATE_MEM(area))); } @@ -654,6 +694,7 @@ void gc_collect_end(void) { } MP_STATE_THREAD(gc_lock_depth) &= ~GC_COLLECT_FLAG; GC_EXIT(); + gc_perfetto_emit_heap_stats(); } static void gc_deal_with_stack_overflow(void) { @@ -1069,6 +1110,8 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) { memorymonitor_track_allocation(end_block - start_block + 1); #endif + gc_perfetto_emit_heap_stats(); + return ret_ptr; } @@ -1150,6 +1193,7 @@ void gc_free(void *ptr) { } while (ATB_GET_KIND(area, block) == AT_TAIL); GC_EXIT(); + gc_perfetto_emit_heap_stats(); #if EXTENSIVE_HEAP_PROFILING gc_dump_alloc_table(&mp_plat_print); @@ -1290,6 +1334,8 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { memorymonitor_track_allocation(new_blocks); #endif + gc_perfetto_emit_heap_stats(); + return ptr_in; } @@ -1327,6 +1373,8 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) { memorymonitor_track_allocation(new_blocks); #endif + gc_perfetto_emit_heap_stats(); + return ptr_in; } From fdab0971ed4712bb5fe14f2a7acd9297c8d724e6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 4 Mar 2026 16:31:14 -0800 Subject: [PATCH 290/876] Tweak peripheral tests --- .../boards/nrf5340bsim_nrf5340_cpuapp.conf | 2 + ports/zephyr-cp/common-hal/_bleio/Adapter.c | 47 ++++++++++- ports/zephyr-cp/tests/bsim/conftest.py | 8 +- .../tests/bsim/test_bsim_ble_advertising.py | 82 +++++++++++++++++++ .../tests/bsim/test_bsim_ble_peripheral.py | 61 +++++--------- 5 files changed, 152 insertions(+), 48 deletions(-) diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf index d996ec05ac9..57628a61e20 100644 --- a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -12,7 +12,9 @@ CONFIG_BT_OBSERVER=y CONFIG_BT_BROADCASTER=y CONFIG_BT_L2CAP_TX_MTU=253 +CONFIG_BT_BUF_CMD_TX_COUNT=2 CONFIG_BT_BUF_CMD_TX_SIZE=255 +CONFIG_BT_HCI_VS=y CONFIG_BT_BUF_EVT_RX_COUNT=16 CONFIG_BT_BUF_EVT_RX_SIZE=255 CONFIG_BT_BUF_ACL_TX_COUNT=3 diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index 5ba562146c8..d1410f02e1b 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "py/gc.h" #include "py/runtime.h" @@ -278,11 +279,48 @@ bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { } mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { - mp_raise_NotImplementedError(NULL); + struct bt_hci_cp_vs_read_tx_power_level *cp; + struct bt_hci_rp_vs_read_tx_power_level *rp; + struct net_buf *buf, *rsp = NULL; + + buf = bt_hci_cmd_alloc(K_MSEC(1000)); + if (!buf) { + mp_raise_msg(&mp_type_MemoryError, NULL); + } + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle_type = BT_HCI_VS_LL_HANDLE_TYPE_ADV; + cp->handle = 0; + + int err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_READ_TX_POWER_LEVEL, buf, &rsp); + if (err) { + raise_zephyr_error(err); + } + + rp = (void *)rsp->data; + int8_t power = rp->tx_power_level; + net_buf_unref(rsp); + return power; } void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { - mp_raise_NotImplementedError(NULL); + struct bt_hci_cp_vs_write_tx_power_level *cp; + struct net_buf *buf, *rsp = NULL; + + buf = bt_hci_cmd_alloc(K_MSEC(3000)); + if (!buf) { + mp_raise_msg(&mp_type_MemoryError, NULL); + } + cp = net_buf_add(buf, sizeof(*cp)); + cp->handle_type = BT_HCI_VS_LL_HANDLE_TYPE_ADV; + cp->handle = 0; + cp->tx_power_level = (int8_t)tx_power; + + int err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL, buf, &rsp); + if (err) { + raise_zephyr_error(err); + } + + net_buf_unref(rsp); } bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { @@ -321,7 +359,6 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, mp_buffer_info_t *advertising_data_bufinfo, mp_buffer_info_t *scan_response_data_bufinfo, mp_int_t tx_power, const bleio_address_obj_t *directed_to) { - (void)tx_power; (void)directed_to; (void)interval; @@ -391,6 +428,8 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, NULL); } + common_hal_bleio_adapter_set_tx_power(self, tx_power); + raise_zephyr_error(bt_le_adv_start(&adv_params, adv_data, adv_count, @@ -555,7 +594,7 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre if (info.state == BT_CONN_STATE_DISCONNECTED) { bt_conn_unref(conn); - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Failed to connect")); + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Failed to connect: timeout")); } } else if (err != -ENOTCONN) { bt_conn_unref(conn); diff --git a/ports/zephyr-cp/tests/bsim/conftest.py b/ports/zephyr-cp/tests/bsim/conftest.py index 67b76469fa0..493f4c92b3b 100644 --- a/ports/zephyr-cp/tests/bsim/conftest.py +++ b/ports/zephyr-cp/tests/bsim/conftest.py @@ -107,6 +107,8 @@ def bsim_phy(request, bsim_phy_binary, native_sim_env, sim_id): "-v=9", # Cleaning up level is on 9. Connecting is 7. f"-s={sim_id}", f"-D={devices}", + "-argschannel", + "-at=40", # 40 dB attenuation (default 60) so RSSI ~ -40 dBm ] print("Running:", " ".join(cmd)) proc = subprocess.Popen( @@ -213,11 +215,13 @@ def zephyr_sample(request, bsim_phy, native_sim_env, sim_id): print(sample_proc.serial.all_output) +# pytest markers are defined inside out meaning the bottom one is first in the +# list and the top is last. So use negative indices to reverse them. @pytest.fixture def circuitpython1(circuitpython): - return circuitpython[0] + return circuitpython[-1] @pytest.fixture def circuitpython2(circuitpython): - return circuitpython[1] + return circuitpython[-2] diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py index 35d85b416d6..33680fe2506 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -4,6 +4,7 @@ """BLE advertising tests for nrf5340bsim.""" import logging +import re import pytest @@ -44,6 +45,39 @@ """ +BSIM_TX_POWER_DEFAULT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"CPTXPWR" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("advertising default") +adapter.start_advertising(advertisement) +time.sleep(4) +adapter.stop_advertising() +print("done") +""" + +BSIM_TX_POWER_LOW_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"CPTXPWR" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("advertising low") +adapter.start_advertising(advertisement, tx_power=-20) +time.sleep(4) +adapter.stop_advertising() +print("done") +""" + + @pytest.mark.zephyr_sample("bluetooth/observer") @pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_CODE}) def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): @@ -90,3 +124,51 @@ def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): assert cp_output.count("adv run done") >= 1 assert observer_output.count("Device found:") >= observer_count_before + 1 assert "Already advertising" not in cp_output + + +@pytest.mark.zephyr_sample("bluetooth/observer") +@pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_DEFAULT_CODE}) +def test_bsim_tx_power_default_rssi(bsim_phy, circuitpython, zephyr_sample): + """Verify default TX power produces expected RSSI.""" + observer = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + obs_output = observer.serial.all_output + + assert "advertising default" in cp_output + assert "done" in cp_output + + # Observer: "Device found: (RSSI ), type , AD data len " + # Advertisement is 12 bytes: flags (3) + name (9). + # With 40 dB channel attenuation and 0 dBm TX → RSSI ~ -39 + rssi_pattern = re.compile(r"RSSI (-?\d+)\), type \d+, AD data len 12") + all_rssi = [int(m.group(1)) for m in rssi_pattern.finditer(obs_output)] + logger.info("RSSI values: %s", all_rssi) + + assert len(all_rssi) > 0, "Observer saw no advertisements" + assert all_rssi[0] == -39, f"Expected RSSI -39 (0 dBm TX), got {all_rssi[0]}" + + +@pytest.mark.zephyr_sample("bluetooth/observer") +@pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_LOW_CODE}) +def test_bsim_tx_power_low_rssi(bsim_phy, circuitpython, zephyr_sample): + """Verify low TX power reduces RSSI.""" + observer = zephyr_sample + + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + obs_output = observer.serial.all_output + + assert "advertising low" in cp_output + assert "done" in cp_output + + # With 40 dB channel attenuation and -20 dBm TX → RSSI ~ -59 + rssi_pattern = re.compile(r"RSSI (-?\d+)\), type \d+, AD data len 12") + all_rssi = [int(m.group(1)) for m in rssi_pattern.finditer(obs_output)] + logger.info("RSSI values: %s", all_rssi) + + assert len(all_rssi) > 0, "Observer saw no advertisements" + assert all_rssi[0] < -39, f"Expected lower RSSI with -20 dBm TX, got {all_rssi[0]}" diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py index f1db308bbfc..7a4bbfaecd9 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py @@ -10,6 +10,7 @@ BSIM_PERIPHERAL_CODE = """\ import _bleio import time +import sys adapter = _bleio.adapter @@ -20,50 +21,27 @@ adapter.start_advertising(advertisement, connectable=True) print("advertising", adapter.advertising) -for _ in range(80): - if adapter.connected: - break - time.sleep(0.1) - -print("connected", adapter.connected, "advertising", adapter.advertising) - -for _ in range(80): - if not adapter.connected: - break - time.sleep(0.1) - -print("disconnected", adapter.connected, len(adapter.connections)) -""" +was_connected = False +timeout = time.monotonic() + 8.0 +while not was_connected and time.monotonic() < timeout: + time.sleep(0.01) + was_connected = adapter.connected -BSIM_PERIPHERAL_CP_CENTRAL_PERIPHERAL_CODE = """\ -import _bleio -import time +if not was_connected: + print("connect timed out") + sys.exit(-1) -adapter = _bleio.adapter +print("connected", was_connected, "advertising", adapter.advertising) -name = b"CPPERIPH" -advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name - -print("peripheral start") -adapter.start_advertising(advertisement, connectable=True) -print("advertising", adapter.advertising) - -for _ in range(80): - if adapter.connected: - break - time.sleep(0.1) - -print("connected", adapter.connected, "advertising", adapter.advertising) - -for _ in range(80): - if not adapter.connected: - break - time.sleep(0.1) +if was_connected: + timeout = time.monotonic() + 8.0 + while adapter.connected and time.monotonic() < timeout: + time.sleep(0.1) print("disconnected", adapter.connected, len(adapter.connections)) """ -BSIM_PERIPHERAL_CP_CENTRAL_CODE = """\ +BSIM_CENTRAL_CODE = """\ import _bleio import time @@ -86,9 +64,8 @@ print("connected", connection.connected, adapter.connected, len(adapter.connections)) connection.disconnect() -for _ in range(40): - if not connection.connected and not adapter.connected: - break +timeout = time.monotonic() + 4.0 +while (connection.connected or adapter.connected) and time.monotonic() < timeout: time.sleep(0.1) print("disconnected", connection.connected, adapter.connected, len(adapter.connections)) @@ -118,8 +95,8 @@ def test_bsim_peripheral_zephyr_central(bsim_phy, circuitpython, zephyr_sample): @pytest.mark.duration(14) -@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CP_CENTRAL_CODE}) -@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CP_CENTRAL_PERIPHERAL_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_CODE}) def test_bsim_peripheral_cp_central(bsim_phy, circuitpython1, circuitpython2): """Two CP instances: device 0 peripheral, device 1 central.""" peripheral = circuitpython1 From 2555baec7581415c95d7b93b7d2ddc9f224e5f16 Mon Sep 17 00:00:00 2001 From: Liz Date: Wed, 4 Mar 2026 20:22:50 -0500 Subject: [PATCH 291/876] working display! --- ports/espressif/boards/xteink_x4/board.c | 42 +++++++++++------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/ports/espressif/boards/xteink_x4/board.c b/ports/espressif/boards/xteink_x4/board.c index bf6fbddebc9..b5b193c65fe 100644 --- a/ports/espressif/boards/xteink_x4/board.c +++ b/ports/espressif/boards/xteink_x4/board.c @@ -16,11 +16,11 @@ #define DELAY 0x80 -// SSD1677 controller driving a GDEQ0426T82 4.26" 800x480 grayscale E-Ink display. +// SSD1677 controller driving a GDEQ0426T82 4.26" 800x480 E-Ink display. const uint8_t ssd1677_display_start_sequence[] = { // Software Reset - 0x12, DELAY, 0x00, 0x14, // SWRESET + wait 20ms + 0x12, DELAY, 0x00, 0x14, // Temperature Sensor Control (use internal sensor) 0x18, 0x00, 0x01, 0x80, @@ -28,49 +28,45 @@ const uint8_t ssd1677_display_start_sequence[] = { // Booster Soft Start 0x0C, 0x00, 0x05, 0xAE, 0xC7, 0xC3, 0xC0, 0x40, - // Driver Output Control: 479 gates (HEIGHT-1 = 0x01DF) + // Driver Output Control: 480 gates, GD=0, SM=1, TB=0 = 0x02 0x01, 0x00, 0x03, 0xDF, 0x01, 0x02, - // Data Entry Mode: X increment, Y increment - 0x11, 0x00, 0x01, 0x02, + // Data Entry Mode: X increment, Y decrement = 0x01 + 0x11, 0x00, 0x01, 0x01, // Border Waveform Control 0x3C, 0x00, 0x01, 0x01, // Set RAM X Address Start/End: 0 to 799 - - // X start = 0 (LE: 0x00, 0x00), X end = 799 (LE: 0x1F, 0x03) 0x44, 0x00, 0x04, 0x00, 0x00, 0x1F, 0x03, - // Set RAM Y Address Start/End: 0 to 479 - 0x45, 0x00, 0x04, 0x00, 0x00, 0xDF, 0x01, + // Set RAM Y Address Start/End: 479 down to 0 + 0x45, 0x00, 0x04, 0xDF, 0x01, 0x00, 0x00, // Set RAM X Counter to 0 0x4E, 0x00, 0x02, 0x00, 0x00, - // Set RAM Y Counter to 0 - 0x4F, 0x00, 0x02, 0x00, 0x00, + // Set RAM Y Counter to 479 + 0x4F, 0x00, 0x02, 0xDF, 0x01, // Auto Write BW RAM (clear to white) - 0x46, DELAY, 0x01, 0xF7, 0xFF, // + wait 255ms + 0x46, DELAY, 0x01, 0xF7, 0xFF, - // Display Update Control 1: bypass RED buffer for mono mode + // Display Update Control 1: bypass RED 0x21, 0x00, 0x02, 0x40, 0x00, - // Display Update Control 2: full refresh sequence with OTP LUT + // Display Update Control 2: full refresh with OTP LUT 0x22, 0x00, 0x01, 0xF7, }; const uint8_t ssd1677_display_stop_sequence[] = { - // Power off sequence - 0x22, 0x00, 0x01, 0x83, // Display update control: power off - 0x20, 0x00, 0x00, // Master activation - // Deep sleep - 0x10, 0x00, 0x01, 0x01, // Enter deep sleep mode + 0x22, 0x00, 0x01, 0x83, + 0x20, 0x00, 0x00, + 0x10, 0x00, 0x01, 0x01, }; const uint8_t ssd1677_display_refresh_sequence[] = { - 0x20, 0x00, 0x00 + 0x20, 0x00, 0x00, }; void board_init(void) { @@ -104,12 +100,12 @@ void board_init(void) { args.ram_height = 480; args.rotation = 0; args.write_black_ram_command = 0x24; - args.black_bits_inverted = true; + args.black_bits_inverted = false; args.refresh_sequence = ssd1677_display_refresh_sequence; args.refresh_sequence_len = sizeof(ssd1677_display_refresh_sequence); - args.refresh_time = 1.6; // ~1600ms full refresh + args.refresh_time = 1.6; args.busy_pin = &pin_GPIO6; - args.busy_state = true; // BUSY is active HIGH on SSD1677 + args.busy_state = true; args.seconds_per_frame = 5.0; args.grayscale = false; args.two_byte_sequence_length = true; From 4813ed60e6677b8f0bdd2bb6dfdd5bd2988c6512 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 5 Mar 2026 15:05:49 +0100 Subject: [PATCH 292/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 40 ++++++++++++++++++++-------------------- locale/el.po | 34 ++++++++++++++-------------------- locale/hi.po | 27 +++++++-------------------- locale/ko.po | 34 ++++++++++++++-------------------- locale/ru.po | 40 ++++++++++++++++++++-------------------- locale/tr.po | 34 ++++++++++++++-------------------- 6 files changed, 89 insertions(+), 120 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 92979bdd31b..1b653528f19 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -487,7 +487,7 @@ msgstr "pow() nepodporuje 3 argumenty" msgid "AP could not be started" msgstr "AP nemohl být spuštěn" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "Adresa musí být %d bajtů dlouhá" @@ -686,11 +686,6 @@ msgstr "RX a TX jsou vyžadovány pro kontrolu toku" msgid "Brightness not adjustable" msgstr "Jas není nastavitelný" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Vyrovnávací paměť + offset je příliš malý %d %d %d" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "Prvky bufferu musí být 4 bajty dlouhé nebo méně" @@ -733,10 +728,6 @@ msgstr "Buffer příliš malý" msgid "Bus pin %d is already in use" msgstr "Sběrnicový pin %d je již používán" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Buffer musí být dlouhý 16 bajtů." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "Bloky CBC musí být násobky 16 bajtů" @@ -1047,12 +1038,18 @@ msgstr "Nepodařilo se alokovat paměť pro wifi scan" msgid "Failed to buffer the sample" msgstr "Nepodařilo se nabufferovat sample" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" msgstr "Připojení se nezdařilo: interní chyba" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "Nepodařilo se připojit: časový limit" @@ -2271,10 +2268,6 @@ msgstr "USB zařízení používají příliš mnoho názvů rozhraní." msgid "USB error" msgstr "Chyba USB" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "UUID integer musí být 0-0xffff" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "UUID řetězec neodpovídá 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" @@ -3422,10 +3415,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "výchozí hodnoty musí být iterovatelné" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "délka initial_value je chybná" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3837,7 +3826,6 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "nenulový timeout musí být > 0.01" @@ -4321,7 +4309,6 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "timeout překročil maximální podporovanou hodnotu" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "timeout musí být < 655.35 s" @@ -4614,6 +4601,19 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Vyrovnávací paměť + offset je příliš malý %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Buffer musí být dlouhý 16 bajtů." + +#~ msgid "UUID integer value must be 0-0xffff" +#~ msgstr "UUID integer musí být 0-0xffff" + +#~ msgid "initial_value length is wrong" +#~ msgstr "délka initial_value je chybná" + #, c-format #~ msgid "Invalid byte %.*s" #~ msgstr "Špatný byte %.*s" diff --git a/locale/el.po b/locale/el.po index 9ad4e3ccfc3..74e0da7b28b 100644 --- a/locale/el.po +++ b/locale/el.po @@ -491,7 +491,7 @@ msgstr "pow() με 3 παραμέτρους δεν υποστηρίζεται" msgid "AP could not be started" msgstr "AP δεν μπόρεσε να εκκινηθεί" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "Η διεύθυνση πρέπει να είναι %d bytes μεγάλη" @@ -690,11 +690,6 @@ msgstr "Και RX και TX απαιτούνται για έλεγχο flow" msgid "Brightness not adjustable" msgstr "H φωτεινότητα δεν μπορεί να προσαρμοστεί" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Buffer + offset είναι πολύ μικρά %d %d %d" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "Στοιχεία του buffer πρέπει να είναι το πολύ 4 bytes" @@ -737,10 +732,6 @@ msgstr "Buffer πολύ μικρός" msgid "Bus pin %d is already in use" msgstr "Bus pin %d είναι ήδη σε χρήση" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Byte buffer πρέπει να είναι 16 bytes." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "CBC blocks πρέπει να είναι πολλαπλάσια του 16 bytes" @@ -1055,12 +1046,18 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "" @@ -2275,10 +2272,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" @@ -3421,10 +3414,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3836,7 +3825,6 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4320,7 +4308,6 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" @@ -4613,6 +4600,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Buffer + offset είναι πολύ μικρά %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Byte buffer πρέπει να είναι 16 bytes." + #~ msgid "%q moved from %q to %q" #~ msgstr "%q μετακινήθηκε από το %q στο %q" diff --git a/locale/hi.po b/locale/hi.po index 046cea6b3d4..f9a35f0b41b 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -478,7 +478,7 @@ msgstr "" msgid "AP could not be started" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "" @@ -675,11 +675,6 @@ msgstr "" msgid "Brightness not adjustable" msgstr "" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "" @@ -722,10 +717,6 @@ msgstr "" msgid "Bus pin %d is already in use" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "" - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "" @@ -1031,12 +1022,18 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "" @@ -2249,10 +2246,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" @@ -3395,10 +3388,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3810,7 +3799,6 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4294,7 +4282,6 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 311803d7630..03c658395e0 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -507,7 +507,7 @@ msgstr "pow() 는 3개의 인수를 지원하지 않습니다" msgid "AP could not be started" msgstr "AP를 시작할 수 없습니다" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "주소 길이는 %d 바이트 여야합니다" @@ -716,11 +716,6 @@ msgstr "플로우 제어에 RX와 TX가 모두 필요합니다" msgid "Brightness not adjustable" msgstr "밝기를 조절할 수 없습니다" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Buffer + offset이 너무 작습니다 %d %d %d" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "버퍼 요소는 4바이트 이하여야 합니다" @@ -763,10 +758,6 @@ msgstr "버퍼가 너무 작습니다" msgid "Bus pin %d is already in use" msgstr "Bus 핀 %d은 이미 사용 중입니다" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "잘못된 크기의 버퍼. 16 바이트 여야합니다." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "CBC 블록은 16 바이트의 배수여야 합니다" @@ -1079,12 +1070,18 @@ msgstr "wifi 검색 메모리 할당에 실패했습니다" msgid "Failed to buffer the sample" msgstr "샘플 버퍼링에 실패했습니다" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" msgstr "연결에 실패했습니다: 내부 오류" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "연결에 실패했습니다: 시간 초과" @@ -2322,10 +2319,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "UUID문자열이 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'형식이 아닙니다" @@ -3469,10 +3462,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3884,7 +3873,6 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4368,7 +4356,6 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" @@ -4661,6 +4648,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Buffer + offset이 너무 작습니다 %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "잘못된 크기의 버퍼. 16 바이트 여야합니다." + #, c-format #~ msgid "Invalid byte %.*s" #~ msgstr "잘못된 바이트 %.*s" diff --git a/locale/ru.po b/locale/ru.po index 1eac7b309a6..2beb4b1ba38 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -491,7 +491,7 @@ msgstr "Pow() с 3 аргументами не поддерживается" msgid "AP could not be started" msgstr "AP не может быть запущен" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "Адрес должен быть длиной %d байт" @@ -691,11 +691,6 @@ msgstr "Для управления потоком требуется как RX msgid "Brightness not adjustable" msgstr "Яркость не регулируется" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Буфер + сдвиг слишком малы %d %d %d" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "Элементы буфера должны иметь длину не более 4 байт" @@ -738,10 +733,6 @@ msgstr "Слишком маленький буфер" msgid "Bus pin %d is already in use" msgstr "Вывод шины %d уже используется" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Буфер байтов должен быть размером 16 байтам." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "Блоки CBC должны быть кратны 16 байтам" @@ -1060,12 +1051,18 @@ msgstr "Не удалось выделить память для сканиро msgid "Failed to buffer the sample" msgstr "Не удалось выполнить буферизацию образца" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" msgstr "Не удалось подключиться: внутренняя ошибка" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "Не удалось подключиться: таймаут" @@ -2305,10 +2302,6 @@ msgstr "USB-устройства указывают слишком много и msgid "USB error" msgstr "Ошибка USB" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "Целое значение UUID должно быть равно 0-0xffff" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "UUID строка не 'xxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxxx \"" @@ -3476,10 +3469,6 @@ msgstr "индексы должны быть целыми числами, сре msgid "initial values must be iterable" msgstr "Начальные значения должны быть итерируемыми" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "длина первоначального_значения ошибочна" - #: py/compile.c msgid "inline assembler must be a function" msgstr "Встроенный ассемблер должен быть функцией" @@ -3899,7 +3888,6 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "Ненулевое время ожидания должно быть > 0,01" @@ -4384,7 +4372,6 @@ msgstr "" "Продолжительность таймаута превысила максимальное поддерживаемое значение" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "таймаут должен быть < 655.35 сек" @@ -4680,6 +4667,19 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Буфер + сдвиг слишком малы %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Буфер байтов должен быть размером 16 байтам." + +#~ msgid "UUID integer value must be 0-0xffff" +#~ msgstr "Целое значение UUID должно быть равно 0-0xffff" + +#~ msgid "initial_value length is wrong" +#~ msgstr "длина первоначального_значения ошибочна" + #, c-format #~ msgid "Invalid byte %.*s" #~ msgstr "Неверный байт %.*s" diff --git a/locale/tr.po b/locale/tr.po index 4e75d975f55..34d654b11e4 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -489,7 +489,7 @@ msgstr "3-argümanlı pow() desteklenmemektedir" msgid "AP could not be started" msgstr "" -#: shared-bindings/_bleio/Address.c shared-bindings/ipaddress/IPv4Address.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format msgid "Address must be %d bytes long" msgstr "Adres %d byte uzunluğunda olmalıdır" @@ -688,11 +688,6 @@ msgstr "Hem RX hem de TX akış kontrolü için gerekli" msgid "Brightness not adjustable" msgstr "Parlaklık ayarlanabilir değil" -#: shared-bindings/_bleio/UUID.c -#, c-format -msgid "Buffer + offset too small %d %d %d" -msgstr "Buffer + offset çok küçük %d %d %d" - #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Buffer elements must be 4 bytes long or less" msgstr "Buffer elementleri 4 bit olmak zorunda" @@ -735,10 +730,6 @@ msgstr "" msgid "Bus pin %d is already in use" msgstr "Veriyolu pini %d kullanımda" -#: shared-bindings/_bleio/UUID.c -msgid "Byte buffer must be 16 bytes." -msgstr "Bit buffer'ı 16bit olmalı." - #: shared-bindings/aesio/aes.c msgid "CBC blocks must be multiples of 16 bytes" msgstr "CBC blokları 16 baytın katları şeklinde olmalı" @@ -1045,12 +1036,18 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: internal error" msgstr "Bağlantı kurulamadı: internal error" #: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "Failed to connect: timeout" msgstr "Bağlantı kurulamadı: timeout" @@ -2271,10 +2268,6 @@ msgstr "" msgid "USB error" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID integer value must be 0-0xffff" -msgstr "" - #: shared-bindings/_bleio/UUID.c msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" @@ -3417,10 +3410,6 @@ msgstr "" msgid "initial values must be iterable" msgstr "" -#: shared-bindings/_bleio/Characteristic.c shared-bindings/_bleio/Descriptor.c -msgid "initial_value length is wrong" -msgstr "" - #: py/compile.c msgid "inline assembler must be a function" msgstr "" @@ -3832,7 +3821,6 @@ msgid "non-hex digit" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "non-zero timeout must be > 0.01" msgstr "" @@ -4316,7 +4304,6 @@ msgid "timeout duration exceeded the maximum supported value" msgstr "" #: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c msgid "timeout must be < 655.35 secs" msgstr "" @@ -4609,6 +4596,13 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#, c-format +#~ msgid "Buffer + offset too small %d %d %d" +#~ msgstr "Buffer + offset çok küçük %d %d %d" + +#~ msgid "Byte buffer must be 16 bytes." +#~ msgstr "Bit buffer'ı 16bit olmalı." + #, c-format #~ msgid "%%c requires int or char" #~ msgstr "%%c int veya char tipine ihtiyaç duyar" From 687b4b3c401a6201fec0034cb3d8b3e0ce4e8333 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 5 Mar 2026 13:29:08 -0500 Subject: [PATCH 293/876] in *_make_new(), allocate obj only after all validations This was provoked by a specific safe-mode with SPI objects that were copied over VM instantiations, but there were some other cases. Also did some style cleanup. --- shared-bindings/_bleio/Address.c | 3 +- shared-bindings/_bleio/UUID.c | 10 ++-- shared-bindings/_stage/Layer.c | 48 +++++++++---------- shared-bindings/_stage/Text.c | 40 ++++++++-------- .../i2c_device/I2CDevice.c | 6 +-- .../spi_device/SPIDevice.c | 25 ++++++---- shared-bindings/aesio/aes.c | 4 +- shared-bindings/alarm/pin/PinAlarm.c | 2 +- shared-bindings/alarm/time/TimeAlarm.c | 3 +- shared-bindings/alarm/touch/TouchAlarm.c | 3 +- shared-bindings/analogbufio/BufferedIn.c | 6 +-- shared-bindings/audiobusio/PDMIn.c | 4 +- shared-bindings/audiocore/RawSample.c | 14 ++++-- shared-bindings/audiocore/WaveFile.c | 3 +- shared-bindings/audiodelays/PitchShift.c | 14 +++++- shared-bindings/audiofilters/Distortion.c | 17 ++++++- shared-bindings/audiofilters/Filter.c | 9 +++- shared-bindings/audiofilters/Phaser.c | 11 ++++- shared-bindings/audioio/AudioOut.c | 5 +- shared-bindings/audiomixer/MixerVoice.c | 2 +- shared-bindings/audiomp3/MP3Decoder.c | 4 +- shared-bindings/audiopwmio/PWMAudioOut.c | 6 ++- shared-bindings/bitbangio/I2C.c | 3 +- shared-bindings/bitbangio/SPI.c | 2 +- shared-bindings/busio/I2C.c | 2 +- shared-bindings/busio/SPI.c | 2 +- shared-bindings/busio/UART.c | 2 +- shared-bindings/camera/Camera.c | 2 +- shared-bindings/canio/Match.c | 3 +- shared-bindings/canio/Message.c | 3 +- .../canio/RemoteTransmissionRequest.c | 3 +- shared-bindings/countio/Counter.c | 2 +- shared-bindings/digitalio/DigitalInOut.c | 12 ++--- shared-bindings/displayio/ColorConverter.c | 1 - shared-bindings/displayio/TileGrid.c | 1 + shared-bindings/gnss/GNSS.c | 3 +- shared-bindings/i2cioexpander/IOExpander.c | 4 +- shared-bindings/i2ctarget/I2CTarget.c | 8 ++-- .../imagecapture/ParallelImageCapture.c | 1 - shared-bindings/ipaddress/IPv4Address.c | 1 - shared-bindings/is31fl3741/IS31FL3741.c | 1 - shared-bindings/jpegio/JpegDecoder.c | 1 - shared-bindings/keypad/Event.c | 3 +- shared-bindings/keypad/KeyMatrix.c | 3 +- shared-bindings/keypad/Keys.c | 2 +- shared-bindings/keypad/ShiftRegisterKeys.c | 4 +- shared-bindings/keypad_demux/DemuxKeyMatrix.c | 3 +- shared-bindings/memorymap/AddressRange.c | 1 - .../memorymonitor/AllocationAlarm.c | 1 - shared-bindings/msgpack/ExtType.c | 6 +-- shared-bindings/onewireio/OneWire.c | 2 +- shared-bindings/os/__init__.c | 2 +- shared-bindings/ps2io/Ps2.c | 1 - shared-bindings/pulseio/PulseIn.c | 1 - shared-bindings/pulseio/PulseOut.c | 1 + shared-bindings/qrio/QRDecoder.c | 2 +- shared-bindings/rclcpy/Node.c | 5 +- shared-bindings/rclcpy/__init__.c | 3 +- shared-bindings/sdcardio/SDCard.c | 3 +- shared-bindings/sdioio/SDCard.c | 2 +- shared-bindings/socketpool/SocketPool.c | 2 +- shared-bindings/spitarget/SPITarget.c | 3 +- shared-bindings/ssl/SSLContext.c | 1 - shared-bindings/ssl/__init__.c | 4 +- shared-bindings/synthio/LFO.c | 8 ++-- shared-bindings/synthio/Math.c | 6 +-- shared-bindings/synthio/MidiTrack.c | 1 - shared-bindings/synthio/Note.c | 6 +-- shared-bindings/synthio/Synthesizer.c | 1 - shared-bindings/synthio/__init__.c | 1 - shared-bindings/terminalio/Terminal.c | 2 +- .../tilepalettemapper/TilePaletteMapper.c | 1 - shared-bindings/touchio/TouchIn.c | 2 +- shared-bindings/usb/core/__init__.c | 3 +- shared-bindings/usb_hid/Device.c | 4 +- shared-bindings/usb_host/Port.c | 2 +- shared-bindings/vectorio/VectorShape.c | 2 +- 77 files changed, 223 insertions(+), 167 deletions(-) diff --git a/shared-bindings/_bleio/Address.c b/shared-bindings/_bleio/Address.c index 58f8a8adc1e..a3c5e3ed7f0 100644 --- a/shared-bindings/_bleio/Address.c +++ b/shared-bindings/_bleio/Address.c @@ -37,8 +37,6 @@ static mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - bleio_address_obj_t *self = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - const mp_obj_t address = args[ARG_address].u_obj; mp_buffer_info_t buf_info; mp_get_buffer_raise(address, &buf_info, MP_BUFFER_READ); @@ -51,6 +49,7 @@ static mp_obj_t bleio_address_make_new(const mp_obj_type_t *type, size_t n_args, mp_arg_error_invalid(MP_QSTR_address_type); } + bleio_address_obj_t *self = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); common_hal_bleio_address_construct(self, buf_info.buf, address_type); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/_bleio/UUID.c b/shared-bindings/_bleio/UUID.c index 2d28d5a9b61..af618ebe8fe 100644 --- a/shared-bindings/_bleio/UUID.c +++ b/shared-bindings/_bleio/UUID.c @@ -34,8 +34,6 @@ static mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); - bleio_uuid_obj_t *self = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); - const mp_obj_t value = all_args[0]; uint8_t uuid128[16]; @@ -46,8 +44,10 @@ static mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, si } // NULL means no 128-bit value. + bleio_uuid_obj_t *self = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); common_hal_bleio_uuid_construct(self, uuid16, NULL); + return MP_OBJ_FROM_PTR(self); } else { if (mp_obj_is_str(value)) { // 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' @@ -93,10 +93,12 @@ static mp_obj_t bleio_uuid_make_new(const mp_obj_type_t *type, size_t n_args, si uint32_t uuid16 = (uuid128[13] << 8) | uuid128[12]; uuid128[12] = 0; uuid128[13] = 0; + + bleio_uuid_obj_t *self = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); common_hal_bleio_uuid_construct(self, uuid16, uuid128); - } - return MP_OBJ_FROM_PTR(self); + return MP_OBJ_FROM_PTR(self); + } } //| uuid16: int diff --git a/shared-bindings/_stage/Layer.c b/shared-bindings/_stage/Layer.c index de4861a70ee..0d7a1bfbd5e 100644 --- a/shared-bindings/_stage/Layer.c +++ b/shared-bindings/_stage/Layer.c @@ -38,38 +38,38 @@ static mp_obj_t layer_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, 4, 5, false); - layer_obj_t *self = mp_obj_malloc(layer_obj_t, type); - - self->width = mp_obj_get_int(args[0]); - self->height = mp_obj_get_int(args[1]); - self->x = 0; - self->y = 0; - self->frame = 0; - self->rotation = false; + mp_uint_t width = mp_arg_validate_int_min(mp_obj_get_int(args[0]), 0, MP_QSTR_width); + mp_uint_t height = mp_arg_validate_int_min(mp_obj_get_int(args[1]), 0, MP_QSTR_height); - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); - self->graphic = bufinfo.buf; - if (bufinfo.len != 2048) { - mp_raise_ValueError(MP_ERROR_TEXT("graphic must be 2048 bytes long")); - } + mp_buffer_info_t graphic_bufinfo; + mp_get_buffer_raise(args[2], &graphic_bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(graphic_bufinfo.len, 2048, MP_QSTR_graphic); - mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); - self->palette = bufinfo.buf; - if (bufinfo.len != 32) { - mp_raise_ValueError(MP_ERROR_TEXT("palette must be 32 bytes long")); - } + mp_buffer_info_t palette_bufinfo; + mp_get_buffer_raise(args[3], &palette_bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(palette_bufinfo.len, 32, MP_QSTR_palette); + mp_buffer_info_t map_bufinfo = { .buf = NULL }; if (n_args > 4) { - mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ); - self->map = bufinfo.buf; - if (bufinfo.len < (self->width * self->height) / 2) { + mp_get_buffer_raise(args[4], &map_bufinfo, MP_BUFFER_READ); + if (map_bufinfo.len < (width * height) / 2) { mp_raise_ValueError(MP_ERROR_TEXT("map buffer too small")); } - } else { - self->map = NULL; } + // Only allocate after validation is finished. + layer_obj_t *self = mp_obj_malloc(layer_obj_t, type); + + self->width = width; + self->height = height; + self->x = 0; + self->y = 0; + self->frame = 0; + self->rotation = false; + self->graphic = graphic_bufinfo.buf; + self->palette = palette_bufinfo.buf; + self->map = map_bufinfo.buf; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/_stage/Text.c b/shared-bindings/_stage/Text.c index ecd4f644a78..f64a1b38190 100644 --- a/shared-bindings/_stage/Text.c +++ b/shared-bindings/_stage/Text.c @@ -38,32 +38,32 @@ static mp_obj_t text_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, 5, 5, false); - text_obj_t *self = mp_obj_malloc(text_obj_t, type); + mp_uint_t width = mp_arg_validate_int_min(mp_obj_get_int(args[0]), 0, MP_QSTR_width); + mp_uint_t height = mp_arg_validate_int_min(mp_obj_get_int(args[1]), 0, MP_QSTR_height); - self->width = mp_obj_get_int(args[0]); - self->height = mp_obj_get_int(args[1]); - self->x = 0; - self->y = 0; - - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[2], &bufinfo, MP_BUFFER_READ); - self->font = bufinfo.buf; - if (bufinfo.len != 2048) { - mp_raise_ValueError(MP_ERROR_TEXT("font must be 2048 bytes long")); - } + mp_buffer_info_t font_bufinfo; + mp_get_buffer_raise(args[2], &font_bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(font_bufinfo.len, 2048, MP_QSTR_font); - mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); - self->palette = bufinfo.buf; - if (bufinfo.len != 32) { - mp_raise_ValueError(MP_ERROR_TEXT("palette must be 32 bytes long")); - } + mp_buffer_info_t palette_bufinfo; + mp_get_buffer_raise(args[3], &palette_bufinfo, MP_BUFFER_READ); + mp_arg_validate_length(font_bufinfo.len, 32, MP_QSTR_palette); - mp_get_buffer_raise(args[4], &bufinfo, MP_BUFFER_READ); - self->chars = bufinfo.buf; - if (bufinfo.len < self->width * self->height) { + mp_buffer_info_t chars_bufinfo; + mp_get_buffer_raise(args[4], &chars_bufinfo, MP_BUFFER_READ); + if (chars_bufinfo.len < width * height) { mp_raise_ValueError(MP_ERROR_TEXT("chars buffer too small")); } + text_obj_t *self = mp_obj_malloc(text_obj_t, type); + self->width = width; + self->height = height; + self->x = 0; + self->y = 0; + self->font = font_bufinfo.buf; + self->palette = palette_bufinfo.buf; + self->chars = chars_bufinfo.buf; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c b/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c index 32d418923fb..5fb821ceade 100644 --- a/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c +++ b/shared-bindings/adafruit_bus_device/i2c_device/I2CDevice.c @@ -47,8 +47,6 @@ //| ... //| static mp_obj_t adafruit_bus_device_i2cdevice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - adafruit_bus_device_i2cdevice_obj_t *self = - mp_obj_malloc(adafruit_bus_device_i2cdevice_obj_t, &adafruit_bus_device_i2cdevice_type); enum { ARG_i2c, ARG_device_address, ARG_probe }; static const mp_arg_t allowed_args[] = { { MP_QSTR_i2c, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -60,12 +58,14 @@ static mp_obj_t adafruit_bus_device_i2cdevice_make_new(const mp_obj_type_t *type mp_obj_t *i2c = args[ARG_i2c].u_obj; + adafruit_bus_device_i2cdevice_obj_t *self = + mp_obj_malloc(adafruit_bus_device_i2cdevice_obj_t, &adafruit_bus_device_i2cdevice_type); common_hal_adafruit_bus_device_i2cdevice_construct(MP_OBJ_TO_PTR(self), i2c, args[ARG_device_address].u_int); if (args[ARG_probe].u_bool == true) { common_hal_adafruit_bus_device_i2cdevice_probe_for_device(self); } - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } //| def __enter__(self) -> I2CDevice: diff --git a/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c b/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c index f62aedc47e3..2f4895e38ce 100644 --- a/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +++ b/shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c @@ -59,8 +59,6 @@ //| ... //| static mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - adafruit_bus_device_spidevice_obj_t *self = - mp_obj_malloc(adafruit_bus_device_spidevice_obj_t, &adafruit_bus_device_spidevice_type); enum { ARG_spi, ARG_chip_select, ARG_cs_active_value, ARG_baudrate, ARG_polarity, ARG_phase, ARG_extra_clocks }; static const mp_arg_t allowed_args[] = { { MP_QSTR_spi, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -78,12 +76,11 @@ static mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type mp_arg_validate_type_or_none(args[ARG_chip_select].u_obj, &digitalio_digitalinout_type, MP_QSTR_chip_select); - common_hal_adafruit_bus_device_spidevice_construct(MP_OBJ_TO_PTR(self), spi, args[ARG_chip_select].u_obj, args[ARG_cs_active_value].u_bool, args[ARG_baudrate].u_int, args[ARG_polarity].u_int, - args[ARG_phase].u_int, args[ARG_extra_clocks].u_int); - if (args[ARG_chip_select].u_obj != mp_const_none) { - digitalinout_result_t result = common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), - true, DRIVE_MODE_PUSH_PULL); + digitalinout_result_t result = + common_hal_digitalio_digitalinout_switch_to_output(MP_OBJ_TO_PTR(args[ARG_chip_select].u_obj), + true, + DRIVE_MODE_PUSH_PULL); #if CIRCUITPY_DIGITALIO_HAVE_INPUT_ONLY if (result == DIGITALINOUT_INPUT_ONLY) { mp_raise_NotImplementedError(MP_ERROR_TEXT("Pin is input only")); @@ -93,7 +90,19 @@ static mp_obj_t adafruit_bus_device_spidevice_make_new(const mp_obj_type_t *type #endif } - return (mp_obj_t)self; + adafruit_bus_device_spidevice_obj_t *self = + mp_obj_malloc(adafruit_bus_device_spidevice_obj_t, &adafruit_bus_device_spidevice_type); + common_hal_adafruit_bus_device_spidevice_construct(MP_OBJ_TO_PTR(self), + spi, + args[ARG_chip_select].u_obj, + args[ARG_cs_active_value].u_bool, + args[ARG_baudrate].u_int, + args[ARG_polarity].u_int, + args[ARG_phase].u_int, + args[ARG_extra_clocks].u_int); + + + return MP_OBJ_FROM_PTR(self); } //| def __enter__(self) -> busio.SPI: diff --git a/shared-bindings/aesio/aes.c b/shared-bindings/aesio/aes.c index a6916042fda..75f2850a7ef 100644 --- a/shared-bindings/aesio/aes.c +++ b/shared-bindings/aesio/aes.c @@ -55,8 +55,6 @@ static mp_obj_t aesio_aes_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - aesio_aes_obj_t *self = mp_obj_malloc(aesio_aes_obj_t, &aesio_aes_type); - enum { ARG_key, ARG_mode, ARG_IV, ARG_counter, ARG_segment_size }; static const mp_arg_t allowed_args[] = { {MP_QSTR_key, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, @@ -100,8 +98,10 @@ static mp_obj_t aesio_aes_make_new(const mp_obj_type_t *type, size_t n_args, iv = bufinfo.buf; } + aesio_aes_obj_t *self = mp_obj_malloc(aesio_aes_obj_t, &aesio_aes_type); common_hal_aesio_aes_construct(self, key, key_length, iv, mode, args[ARG_counter].u_int); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/alarm/pin/PinAlarm.c b/shared-bindings/alarm/pin/PinAlarm.c index 8d93ca8d0de..4633fdb233c 100644 --- a/shared-bindings/alarm/pin/PinAlarm.c +++ b/shared-bindings/alarm/pin/PinAlarm.c @@ -42,7 +42,6 @@ //| ... //| static mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t n_args, size_t n_kw, const mp_obj_t *all_args) { - alarm_pin_pinalarm_obj_t *self = mp_obj_malloc(alarm_pin_pinalarm_obj_t, &alarm_pin_pinalarm_type); enum { ARG_pin, ARG_value, ARG_edge, ARG_pull }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -55,6 +54,7 @@ static mp_obj_t alarm_pin_pinalarm_make_new(const mp_obj_type_t *type, mp_uint_t const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); + alarm_pin_pinalarm_obj_t *self = mp_obj_malloc(alarm_pin_pinalarm_obj_t, &alarm_pin_pinalarm_type); common_hal_alarm_pin_pinalarm_construct(self, pin, args[ARG_value].u_bool, diff --git a/shared-bindings/alarm/time/TimeAlarm.c b/shared-bindings/alarm/time/TimeAlarm.c index 0277c22fc44..a3df6ddf7fd 100644 --- a/shared-bindings/alarm/time/TimeAlarm.c +++ b/shared-bindings/alarm/time/TimeAlarm.c @@ -46,8 +46,6 @@ mp_obj_t MP_WEAK rtc_get_time_source_time(void) { //| static mp_obj_t alarm_time_timealarm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - alarm_time_timealarm_obj_t *self = mp_obj_malloc(alarm_time_timealarm_obj_t, &alarm_time_timealarm_type); - enum { ARG_monotonic_time, ARG_epoch_time }; static const mp_arg_t allowed_args[] = { { MP_QSTR_monotonic_time, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, @@ -92,6 +90,7 @@ static mp_obj_t alarm_time_timealarm_make_new(const mp_obj_type_t *type, mp_raise_ValueError(MP_ERROR_TEXT("Time is in the past.")); } + alarm_time_timealarm_obj_t *self = mp_obj_malloc(alarm_time_timealarm_obj_t, &alarm_time_timealarm_type); common_hal_alarm_time_timealarm_construct(self, monotonic_time); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/alarm/touch/TouchAlarm.c b/shared-bindings/alarm/touch/TouchAlarm.c index f25e826cff0..42b149c9eee 100644 --- a/shared-bindings/alarm/touch/TouchAlarm.c +++ b/shared-bindings/alarm/touch/TouchAlarm.c @@ -26,8 +26,6 @@ //| static mp_obj_t alarm_touch_touchalarm_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - alarm_touch_touchalarm_obj_t *self = mp_obj_malloc(alarm_touch_touchalarm_obj_t, &alarm_touch_touchalarm_type); - enum { ARG_pin }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pin, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -38,6 +36,7 @@ static mp_obj_t alarm_touch_touchalarm_make_new(const mp_obj_type_t *type, const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); + alarm_touch_touchalarm_obj_t *self = mp_obj_malloc(alarm_touch_touchalarm_obj_t, &alarm_touch_touchalarm_type); common_hal_alarm_touch_touchalarm_construct(self, pin); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/analogbufio/BufferedIn.c b/shared-bindings/analogbufio/BufferedIn.c index a25610207b4..2c42ee1f325 100644 --- a/shared-bindings/analogbufio/BufferedIn.c +++ b/shared-bindings/analogbufio/BufferedIn.c @@ -60,10 +60,8 @@ static mp_obj_t analogbufio_bufferedin_make_new(const mp_obj_type_t *type, size_ // Validate Pin const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); - // Create local object - analogbufio_bufferedin_obj_t *self = mp_obj_malloc_with_finaliser(analogbufio_bufferedin_obj_t, &analogbufio_bufferedin_type); - - // Call local interface in ports/common-hal/analogbufio + analogbufio_bufferedin_obj_t *self = + mp_obj_malloc_with_finaliser(analogbufio_bufferedin_obj_t, &analogbufio_bufferedin_type); common_hal_analogbufio_bufferedin_construct(self, pin, args[ARG_sample_rate].u_int); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index 2890afda0fd..092897a15cf 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -96,9 +96,6 @@ static mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar const mcu_pin_obj_t *clock_pin = validate_obj_is_free_pin(args[ARG_clock_pin].u_obj, MP_QSTR_clock_pin); const mcu_pin_obj_t *data_pin = validate_obj_is_free_pin(args[ARG_data_pin].u_obj, MP_QSTR_data_pin); - // create PDMIn object from the given pin - audiobusio_pdmin_obj_t *self = mp_obj_malloc_with_finaliser(audiobusio_pdmin_obj_t, &audiobusio_pdmin_type); - uint32_t sample_rate = args[ARG_sample_rate].u_int; uint8_t bit_depth = args[ARG_bit_depth].u_int; if (bit_depth % 8 != 0) { @@ -115,6 +112,7 @@ static mp_obj_t audiobusio_pdmin_make_new(const mp_obj_type_t *type, size_t n_ar : mp_obj_get_float(args[ARG_startup_delay].u_obj); mp_arg_validate_float_range(startup_delay, 0.0f, 1.0f, MP_QSTR_startup_delay); + audiobusio_pdmin_obj_t *self = mp_obj_malloc_with_finaliser(audiobusio_pdmin_obj_t, &audiobusio_pdmin_type); common_hal_audiobusio_pdmin_construct(self, clock_pin, data_pin, sample_rate, bit_depth, mono, oversample); diff --git a/shared-bindings/audiocore/RawSample.c b/shared-bindings/audiocore/RawSample.c index 30c1d1ad600..8dc57903286 100644 --- a/shared-bindings/audiocore/RawSample.c +++ b/shared-bindings/audiocore/RawSample.c @@ -90,7 +90,6 @@ static mp_obj_t audioio_rawsample_make_new(const mp_obj_type_t *type, size_t n_a mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - audioio_rawsample_obj_t *self = mp_obj_malloc(audioio_rawsample_obj_t, &audioio_rawsample_type); mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); uint8_t bytes_per_sample = 1; @@ -103,9 +102,16 @@ static mp_obj_t audioio_rawsample_make_new(const mp_obj_type_t *type, size_t n_a if (!args[ARG_single_buffer].u_bool && bufinfo.len % (bytes_per_sample * args[ARG_channel_count].u_int * 2) != 0) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Length of %q must be an even multiple of channel_count * type_size"), MP_QSTR_buffer); } - common_hal_audioio_rawsample_construct(self, ((uint8_t *)bufinfo.buf), bufinfo.len, - bytes_per_sample, signed_samples, args[ARG_channel_count].u_int, - args[ARG_sample_rate].u_int, args[ARG_single_buffer].u_bool); + + audioio_rawsample_obj_t *self = mp_obj_malloc(audioio_rawsample_obj_t, &audioio_rawsample_type); + common_hal_audioio_rawsample_construct(self, + ((uint8_t *)bufinfo.buf), + bufinfo.len, + bytes_per_sample, + signed_samples, + args[ARG_channel_count].u_int, + args[ARG_sample_rate].u_int, + args[ARG_single_buffer].u_bool); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiocore/WaveFile.c b/shared-bindings/audiocore/WaveFile.c index 4ba7d24bfd2..c93bedd4213 100644 --- a/shared-bindings/audiocore/WaveFile.c +++ b/shared-bindings/audiocore/WaveFile.c @@ -60,7 +60,6 @@ static mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_ar arg = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), arg, MP_ROM_QSTR(MP_QSTR_rb)); } - audioio_wavefile_obj_t *self = mp_obj_malloc(audioio_wavefile_obj_t, &audioio_wavefile_type); if (!mp_obj_is_type(arg, &mp_type_vfs_fat_fileio)) { mp_raise_TypeError(MP_ERROR_TEXT("file must be a file opened in byte mode")); } @@ -72,6 +71,8 @@ static mp_obj_t audioio_wavefile_make_new(const mp_obj_type_t *type, size_t n_ar buffer = bufinfo.buf; buffer_size = mp_arg_validate_length_range(bufinfo.len, 8, 1024, MP_QSTR_buffer); } + + audioio_wavefile_obj_t *self = mp_obj_malloc(audioio_wavefile_obj_t, &audioio_wavefile_type); common_hal_audioio_wavefile_construct(self, MP_OBJ_TO_PTR(arg), buffer, buffer_size); diff --git a/shared-bindings/audiodelays/PitchShift.c b/shared-bindings/audiodelays/PitchShift.c index b94df7d9edd..ee3bf5afdd7 100644 --- a/shared-bindings/audiodelays/PitchShift.c +++ b/shared-bindings/audiodelays/PitchShift.c @@ -94,8 +94,18 @@ static mp_obj_t audiodelays_pitch_shift_make_new(const mp_obj_type_t *type, size mp_raise_ValueError(MP_ERROR_TEXT("bits_per_sample must be 8 or 16")); } - audiodelays_pitch_shift_obj_t *self = mp_obj_malloc(audiodelays_pitch_shift_obj_t, &audiodelays_pitch_shift_type); - common_hal_audiodelays_pitch_shift_construct(self, args[ARG_semitones].u_obj, args[ARG_mix].u_obj, args[ARG_window].u_int, args[ARG_overlap].u_int, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + audiodelays_pitch_shift_obj_t *self = + mp_obj_malloc(audiodelays_pitch_shift_obj_t, &audiodelays_pitch_shift_type); + common_hal_audiodelays_pitch_shift_construct(self, + args[ARG_semitones].u_obj, + args[ARG_mix].u_obj, + args[ARG_window].u_int, + args[ARG_overlap].u_int, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiofilters/Distortion.c b/shared-bindings/audiofilters/Distortion.c index 8de4c1d1ea3..bed28f5ed49 100644 --- a/shared-bindings/audiofilters/Distortion.c +++ b/shared-bindings/audiofilters/Distortion.c @@ -145,8 +145,21 @@ static mp_obj_t audiofilters_distortion_make_new(const mp_obj_type_t *type, size mode = validate_distortion_mode(args[ARG_mode].u_obj, MP_QSTR_mode); } - audiofilters_distortion_obj_t *self = mp_obj_malloc(audiofilters_distortion_obj_t, &audiofilters_distortion_type); - common_hal_audiofilters_distortion_construct(self, args[ARG_drive].u_obj, args[ARG_pre_gain].u_obj, args[ARG_post_gain].u_obj, mode, args[ARG_soft_clip].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + audiofilters_distortion_obj_t *self = + mp_obj_malloc(audiofilters_distortion_obj_t, &audiofilters_distortion_type); + common_hal_audiofilters_distortion_construct(self, + args[ARG_drive].u_obj, + args[ARG_pre_gain].u_obj, + args[ARG_post_gain].u_obj, + mode, + args[ARG_soft_clip].u_obj, + args[ARG_mix].u_obj, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiofilters/Filter.c b/shared-bindings/audiofilters/Filter.c index 426fff22616..2d0d12b226a 100644 --- a/shared-bindings/audiofilters/Filter.c +++ b/shared-bindings/audiofilters/Filter.c @@ -91,7 +91,14 @@ static mp_obj_t audiofilters_filter_make_new(const mp_obj_type_t *type, size_t n } audiofilters_filter_obj_t *self = mp_obj_malloc(audiofilters_filter_obj_t, &audiofilters_filter_type); - common_hal_audiofilters_filter_construct(self, args[ARG_filter].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + common_hal_audiofilters_filter_construct(self, + args[ARG_filter].u_obj, + args[ARG_mix].u_obj, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiofilters/Phaser.c b/shared-bindings/audiofilters/Phaser.c index 9f713afce5f..2aed9623b72 100644 --- a/shared-bindings/audiofilters/Phaser.c +++ b/shared-bindings/audiofilters/Phaser.c @@ -91,7 +91,16 @@ static mp_obj_t audiofilters_phaser_make_new(const mp_obj_type_t *type, size_t n } audiofilters_phaser_obj_t *self = mp_obj_malloc(audiofilters_phaser_obj_t, &audiofilters_phaser_type); - common_hal_audiofilters_phaser_construct(self, args[ARG_frequency].u_obj, args[ARG_feedback].u_obj, args[ARG_mix].u_obj, args[ARG_stages].u_int, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + common_hal_audiofilters_phaser_construct(self, + args[ARG_frequency].u_obj, + args[ARG_feedback].u_obj, + args[ARG_mix].u_obj, + args[ARG_stages].u_int, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audioio/AudioOut.c b/shared-bindings/audioio/AudioOut.c index 82aecefa370..8ea068ceb8f 100644 --- a/shared-bindings/audioio/AudioOut.c +++ b/shared-bindings/audioio/AudioOut.c @@ -103,7 +103,10 @@ static mp_obj_t audioio_audioout_make_new(const mp_obj_type_t *type, size_t n_ar // create AudioOut object from the given pin audioio_audioout_obj_t *self = mp_obj_malloc_with_finaliser(audioio_audioout_obj_t, &audioio_audioout_type); - common_hal_audioio_audioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int); + common_hal_audioio_audioout_construct(self, + left_channel_pin, + right_channel_pin, + args[ARG_quiescent_value].u_int); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/audiomixer/MixerVoice.c b/shared-bindings/audiomixer/MixerVoice.c index 128c214d447..4957fab3884 100644 --- a/shared-bindings/audiomixer/MixerVoice.c +++ b/shared-bindings/audiomixer/MixerVoice.c @@ -29,8 +29,8 @@ // TODO: support mono or stereo voices static mp_obj_t audiomixer_mixervoice_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { mp_arg_check_num(n_args, n_kw, 0, 0, false); - audiomixer_mixervoice_obj_t *self = mp_obj_malloc(audiomixer_mixervoice_obj_t, &audiomixer_mixervoice_type); + audiomixer_mixervoice_obj_t *self = mp_obj_malloc(audiomixer_mixervoice_obj_t, &audiomixer_mixervoice_type); common_hal_audiomixer_mixervoice_construct(self); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/audiomp3/MP3Decoder.c b/shared-bindings/audiomp3/MP3Decoder.c index ff6c77e8572..433b308c156 100644 --- a/shared-bindings/audiomp3/MP3Decoder.c +++ b/shared-bindings/audiomp3/MP3Decoder.c @@ -91,8 +91,6 @@ static mp_obj_t audiomp3_mp3file_make_new(const mp_obj_type_t *type, size_t n_ar stream = mp_call_function_2(MP_OBJ_FROM_PTR(&mp_builtin_open_obj), stream, MP_ROM_QSTR(MP_QSTR_rb)); } - audiomp3_mp3file_obj_t *self = mp_obj_malloc_with_finaliser(audiomp3_mp3file_obj_t, &audiomp3_mp3file_type); - const mp_stream_p_t *stream_p = mp_get_stream_raise(stream, MP_STREAM_OP_READ); if (stream_p->is_text) { @@ -106,6 +104,8 @@ static mp_obj_t audiomp3_mp3file_make_new(const mp_obj_type_t *type, size_t n_ar buffer = bufinfo.buf; buffer_size = bufinfo.len; } + + audiomp3_mp3file_obj_t *self = mp_obj_malloc_with_finaliser(audiomp3_mp3file_obj_t, &audiomp3_mp3file_type); common_hal_audiomp3_mp3file_construct(self, stream, buffer, buffer_size); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/audiopwmio/PWMAudioOut.c b/shared-bindings/audiopwmio/PWMAudioOut.c index 3c961433641..5b8d071924b 100644 --- a/shared-bindings/audiopwmio/PWMAudioOut.c +++ b/shared-bindings/audiopwmio/PWMAudioOut.c @@ -100,8 +100,10 @@ static mp_obj_t audiopwmio_pwmaudioout_make_new(const mp_obj_type_t *type, size_ // create AudioOut object from the given pin // The object is created with a finaliser as some ports use these (rather than 'reset' functions) // to ensure resources are collected at interpreter shutdown. - audiopwmio_pwmaudioout_obj_t *self = mp_obj_malloc_with_finaliser(audiopwmio_pwmaudioout_obj_t, &audiopwmio_pwmaudioout_type); - common_hal_audiopwmio_pwmaudioout_construct(self, left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int); + audiopwmio_pwmaudioout_obj_t *self = + mp_obj_malloc_with_finaliser(audiopwmio_pwmaudioout_obj_t, &audiopwmio_pwmaudioout_type); + common_hal_audiopwmio_pwmaudioout_construct(self, + left_channel_pin, right_channel_pin, args[ARG_quiescent_value].u_int); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/bitbangio/I2C.c b/shared-bindings/bitbangio/I2C.c index ddd8824eb58..e1413392699 100644 --- a/shared-bindings/bitbangio/I2C.c +++ b/shared-bindings/bitbangio/I2C.c @@ -59,7 +59,8 @@ static mp_obj_t bitbangio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, bitbangio_i2c_obj_t *self = mp_obj_malloc_with_finaliser(bitbangio_i2c_obj_t, &bitbangio_i2c_type); shared_module_bitbangio_i2c_construct(self, args[ARG_scl].u_obj, args[ARG_sda].u_obj, args[ARG_frequency].u_int, args[ARG_timeout].u_int); - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: diff --git a/shared-bindings/bitbangio/SPI.c b/shared-bindings/bitbangio/SPI.c index f2e635b47bb..de021867f3c 100644 --- a/shared-bindings/bitbangio/SPI.c +++ b/shared-bindings/bitbangio/SPI.c @@ -67,7 +67,7 @@ static mp_obj_t bitbangio_spi_make_new(const mp_obj_type_t *type, size_t n_args, bitbangio_spi_obj_t *self = mp_obj_malloc(bitbangio_spi_obj_t, &bitbangio_spi_type); shared_module_bitbangio_spi_construct(self, args[ARG_clock].u_obj, args[ARG_MOSI].u_obj, args[ARG_MISO].u_obj); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index a2724e60c34..c93566c0b62 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -67,7 +67,7 @@ static mp_obj_t busio_i2c_make_new(const mp_obj_type_t *type, size_t n_args, siz busio_i2c_obj_t *self = mp_obj_malloc_with_finaliser(busio_i2c_obj_t, &busio_i2c_type); common_hal_busio_i2c_construct(self, scl, sda, args[ARG_frequency].u_int, args[ARG_timeout].u_int); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError(NULL); #endif // CIRCUITPY_BUSIO_I2C diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 24c02a16e63..132da473af9 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -88,7 +88,6 @@ // TODO(tannewt): Support LSB SPI. static mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_BUSIO_SPI - busio_spi_obj_t *self = mp_obj_malloc_with_finaliser(busio_spi_obj_t, &busio_spi_type); enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -107,6 +106,7 @@ static mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz mp_raise_ValueError(MP_ERROR_TEXT("Must provide MISO or MOSI pin")); } + busio_spi_obj_t *self = mp_obj_malloc_with_finaliser(busio_spi_obj_t, &busio_spi_type); common_hal_busio_spi_construct(self, clock, mosi, miso, args[ARG_half_duplex].u_bool); return MP_OBJ_FROM_PTR(self); #else diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c index 4714c3ee073..017b9837781 100644 --- a/shared-bindings/busio/UART.c +++ b/shared-bindings/busio/UART.c @@ -157,7 +157,7 @@ static mp_obj_t busio_uart_make_new(const mp_obj_type_t *type, size_t n_args, si common_hal_busio_uart_construct(self, tx, rx, rts, cts, rs485_dir, rs485_invert, args[ARG_baudrate].u_int, bits, parity, stop, timeout, buffer_size, NULL, false); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError(NULL); #endif // CIRCUITPY_BUSIO_UART diff --git a/shared-bindings/camera/Camera.c b/shared-bindings/camera/Camera.c index 6f42fa08bcf..f0991082e50 100644 --- a/shared-bindings/camera/Camera.c +++ b/shared-bindings/camera/Camera.c @@ -41,10 +41,10 @@ //| ... //| static mp_obj_t camera_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - camera_obj_t *self = mp_obj_malloc(camera_obj_t, &camera_type); // No arguments mp_arg_check_num(n_args, n_kw, 0, 0, false); + camera_obj_t *self = mp_obj_malloc(camera_obj_t, &camera_type); common_hal_camera_construct(self); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/canio/Match.c b/shared-bindings/canio/Match.c index 5e44a7ce4ed..e7c3dba42aa 100644 --- a/shared-bindings/canio/Match.c +++ b/shared-bindings/canio/Match.c @@ -47,7 +47,8 @@ static mp_obj_t canio_match_make_new(const mp_obj_type_t *type, size_t n_args, s canio_match_obj_t *self = mp_obj_malloc(canio_match_obj_t, &canio_match_type); common_hal_canio_match_construct(self, id, mask, args[ARG_extended].u_bool); - return self; + + return MP_OBJ_FROM_PTR(self); } //| id: int diff --git a/shared-bindings/canio/Message.c b/shared-bindings/canio/Message.c index c40892b5edb..848b5b15e43 100644 --- a/shared-bindings/canio/Message.c +++ b/shared-bindings/canio/Message.c @@ -41,7 +41,8 @@ static mp_obj_t canio_message_make_new(const mp_obj_type_t *type, size_t n_args, canio_message_obj_t *self = mp_obj_malloc(canio_message_obj_t, &canio_message_type); common_hal_canio_message_construct(self, args[ARG_id].u_int, data.buf, data.len, args[ARG_extended].u_bool); - return self; + + return MP_OBJ_FROM_PTR(self); } //| id: int diff --git a/shared-bindings/canio/RemoteTransmissionRequest.c b/shared-bindings/canio/RemoteTransmissionRequest.c index 966fee71215..bdc91c494a4 100644 --- a/shared-bindings/canio/RemoteTransmissionRequest.c +++ b/shared-bindings/canio/RemoteTransmissionRequest.c @@ -42,7 +42,8 @@ static mp_obj_t canio_remote_transmission_request_make_new(const mp_obj_type_t * canio_remote_transmission_request_obj_t *self = mp_obj_malloc(canio_remote_transmission_request_obj_t, &canio_remote_transmission_request_type); common_hal_canio_remote_transmission_request_construct(self, args[ARG_id].u_int, length, args[ARG_extended].u_bool); - return self; + + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/countio/Counter.c b/shared-bindings/countio/Counter.c index c2e3ddc7404..9f8bd00645c 100644 --- a/shared-bindings/countio/Counter.c +++ b/shared-bindings/countio/Counter.c @@ -66,8 +66,8 @@ static mp_obj_t countio_counter_make_new(const mp_obj_type_t *type, size_t n_arg const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); const countio_edge_t edge = validate_edge(args[ARG_edge].u_obj, MP_QSTR_edge); const digitalio_pull_t pull = validate_pull(args[ARG_pull].u_obj, MP_QSTR_pull); - countio_counter_obj_t *self = mp_obj_malloc_with_finaliser(countio_counter_obj_t, &countio_counter_type); + countio_counter_obj_t *self = mp_obj_malloc_with_finaliser(countio_counter_obj_t, &countio_counter_type); common_hal_countio_counter_construct(self, pin, edge, pull); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/digitalio/DigitalInOut.c b/shared-bindings/digitalio/DigitalInOut.c index c868ca7d443..58f90b0b141 100644 --- a/shared-bindings/digitalio/DigitalInOut.c +++ b/shared-bindings/digitalio/DigitalInOut.c @@ -71,9 +71,9 @@ static mp_obj_t digitalio_digitalinout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); - digitalio_digitalinout_obj_t *self = mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); - const mcu_pin_obj_t *pin = common_hal_digitalio_validate_pin(args[0]); + + digitalio_digitalinout_obj_t *self = mp_obj_malloc(digitalio_digitalinout_obj_t, &digitalio_digitalinout_type); common_hal_digitalio_digitalinout_construct(self, pin); return MP_OBJ_FROM_PTR(self); @@ -191,9 +191,9 @@ static mp_obj_t digitalio_digitalinout_obj_get_direction(mp_obj_t self_in) { check_for_deinit(self); digitalio_direction_t direction = common_hal_digitalio_digitalinout_get_direction(self); if (direction == DIRECTION_INPUT) { - return (mp_obj_t)&digitalio_direction_input_obj; + return MP_OBJ_FROM_PTR(&digitalio_direction_input_obj); } - return (mp_obj_t)&digitalio_direction_output_obj; + return MP_OBJ_FROM_PTR(&digitalio_direction_output_obj); } MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_direction_obj, digitalio_digitalinout_obj_get_direction); @@ -255,9 +255,9 @@ static mp_obj_t digitalio_digitalinout_obj_get_drive_mode(mp_obj_t self_in) { } digitalio_drive_mode_t drive_mode = common_hal_digitalio_digitalinout_get_drive_mode(self); if (drive_mode == DRIVE_MODE_PUSH_PULL) { - return (mp_obj_t)&digitalio_drive_mode_push_pull_obj; + return MP_OBJ_FROM_PTR(&digitalio_drive_mode_push_pull_obj); } - return (mp_obj_t)&digitalio_drive_mode_open_drain_obj; + return MP_OBJ_FROM_PTR(&digitalio_drive_mode_open_drain_obj); } MP_DEFINE_CONST_FUN_OBJ_1(digitalio_digitalinout_get_drive_mode_obj, digitalio_digitalinout_obj_get_drive_mode); diff --git a/shared-bindings/displayio/ColorConverter.c b/shared-bindings/displayio/ColorConverter.c index e2721cfdef2..bfd037016d4 100644 --- a/shared-bindings/displayio/ColorConverter.c +++ b/shared-bindings/displayio/ColorConverter.c @@ -39,7 +39,6 @@ static mp_obj_t displayio_colorconverter_make_new(const mp_obj_type_t *type, siz mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); displayio_colorconverter_t *self = mp_obj_malloc(displayio_colorconverter_t, &displayio_colorconverter_type); - common_hal_displayio_colorconverter_construct(self, args[ARG_dither].u_bool, (displayio_colorspace_t)cp_enum_value(&displayio_colorspace_type, args[ARG_input_colorspace].u_obj, MP_QSTR_input_colorspace)); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index 560fb66a675..5d54c1e3e30 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -133,6 +133,7 @@ static mp_obj_t displayio_tilegrid_make_new(const mp_obj_type_t *type, size_t n_ bitmap_width / tile_width, bitmap_height / tile_height, pixel_shader, args[ARG_width].u_int, args[ARG_height].u_int, tile_width, tile_height, x, y, args[ARG_default_tile].u_int); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/gnss/GNSS.c b/shared-bindings/gnss/GNSS.c index 95c3ed975d5..3df23979c9e 100644 --- a/shared-bindings/gnss/GNSS.c +++ b/shared-bindings/gnss/GNSS.c @@ -38,7 +38,6 @@ //| ... //| static mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - gnss_obj_t *self = mp_obj_malloc(gnss_obj_t, &gnss_type); enum { ARG_system }; static const mp_arg_t allowed_args[] = { { MP_QSTR_system, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -63,7 +62,9 @@ static mp_obj_t gnss_make_new(const mp_obj_type_t *type, size_t n_args, size_t n mp_raise_TypeError(MP_ERROR_TEXT("System entry must be gnss.SatelliteSystem")); } + gnss_obj_t *self = mp_obj_malloc(gnss_obj_t, &gnss_type); common_hal_gnss_construct(self, selection); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/i2cioexpander/IOExpander.c b/shared-bindings/i2cioexpander/IOExpander.c index c828c6dc5c7..3efa0fd1868 100644 --- a/shared-bindings/i2cioexpander/IOExpander.c +++ b/shared-bindings/i2cioexpander/IOExpander.c @@ -72,8 +72,6 @@ static mp_obj_t i2cioexpander_ioexpander_make_new(const mp_obj_type_t *type, siz mp_raise_ValueError(MP_ERROR_TEXT("num_pins must be 8 or 16")); } - i2cioexpander_ioexpander_obj_t *self = mp_obj_malloc(i2cioexpander_ioexpander_obj_t, &i2cioexpander_ioexpander_type); - // Convert and validate register parameters uint16_t set_value_reg = NO_REGISTER; if (args[ARG_set_value_reg].u_obj != mp_const_none) { @@ -96,6 +94,8 @@ static mp_obj_t i2cioexpander_ioexpander_make_new(const mp_obj_type_t *type, siz set_direction_reg = reg; } + i2cioexpander_ioexpander_obj_t *self = + mp_obj_malloc(i2cioexpander_ioexpander_obj_t, &i2cioexpander_ioexpander_type); common_hal_i2cioexpander_ioexpander_construct( self, i2c, diff --git a/shared-bindings/i2ctarget/I2CTarget.c b/shared-bindings/i2ctarget/I2CTarget.c index 8586d1843cc..94dbf4e8be4 100644 --- a/shared-bindings/i2ctarget/I2CTarget.c +++ b/shared-bindings/i2ctarget/I2CTarget.c @@ -26,7 +26,8 @@ static mp_obj_t mp_obj_new_i2ctarget_i2c_target_request(i2ctarget_i2c_target_obj self->address = address; self->is_read = is_read; self->is_restart = is_restart; - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } //| class I2CTarget: @@ -50,7 +51,6 @@ static mp_obj_t mp_obj_new_i2ctarget_i2c_target_request(i2ctarget_i2c_target_obj //| ... //| static mp_obj_t i2ctarget_i2c_target_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - i2ctarget_i2c_target_obj_t *self = mp_obj_malloc_with_finaliser(i2ctarget_i2c_target_obj_t, &i2ctarget_i2c_target_type); enum { ARG_scl, ARG_sda, ARG_addresses, ARG_smbus }; static const mp_arg_t allowed_args[] = { { MP_QSTR_scl, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -78,8 +78,10 @@ static mp_obj_t i2ctarget_i2c_target_make_new(const mp_obj_type_t *type, size_t mp_raise_ValueError(MP_ERROR_TEXT("addresses is empty")); } + i2ctarget_i2c_target_obj_t *self = mp_obj_malloc_with_finaliser(i2ctarget_i2c_target_obj_t, &i2ctarget_i2c_target_type); common_hal_i2ctarget_i2c_target_construct(self, scl, sda, addresses, i, args[ARG_smbus].u_bool); - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: diff --git a/shared-bindings/imagecapture/ParallelImageCapture.c b/shared-bindings/imagecapture/ParallelImageCapture.c index 866edb489ce..427eaeb3793 100644 --- a/shared-bindings/imagecapture/ParallelImageCapture.c +++ b/shared-bindings/imagecapture/ParallelImageCapture.c @@ -58,7 +58,6 @@ static mp_obj_t imagecapture_parallelimagecapture_make_new(const mp_obj_type_t * imagecapture_parallelimagecapture_obj_t *self = mp_obj_malloc(imagecapture_parallelimagecapture_obj_t, &imagecapture_parallelimagecapture_type); - common_hal_imagecapture_parallelimagecapture_construct(self, pins, pin_count, clock, vsync, href); return self; diff --git a/shared-bindings/ipaddress/IPv4Address.c b/shared-bindings/ipaddress/IPv4Address.c index 5aab02e9f5c..7705e500e7e 100644 --- a/shared-bindings/ipaddress/IPv4Address.c +++ b/shared-bindings/ipaddress/IPv4Address.c @@ -59,7 +59,6 @@ static mp_obj_t ipaddress_ipv4address_make_new(const mp_obj_type_t *type, size_t ipaddress_ipv4address_obj_t *self = mp_obj_malloc(ipaddress_ipv4address_obj_t, &ipaddress_ipv4address_type); - common_hal_ipaddress_ipv4address_construct(self, buf, 4); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/is31fl3741/IS31FL3741.c b/shared-bindings/is31fl3741/IS31FL3741.c index 0c6b3479b04..71c4437a1d2 100644 --- a/shared-bindings/is31fl3741/IS31FL3741.c +++ b/shared-bindings/is31fl3741/IS31FL3741.c @@ -38,7 +38,6 @@ static mp_obj_t is31fl3741_IS31FL3741_make_new(const mp_obj_type_t *type, size_t mp_obj_t i2c = mp_arg_validate_type(args[ARG_i2c].u_obj, &busio_i2c_type, MP_QSTR_i2c_bus); is31fl3741_IS31FL3741_obj_t *self = mp_obj_malloc(is31fl3741_IS31FL3741_obj_t, &is31fl3741_IS31FL3741_type); - common_hal_is31fl3741_IS31FL3741_construct(self, MP_OBJ_TO_PTR(i2c), args[ARG_addr].u_int diff --git a/shared-bindings/jpegio/JpegDecoder.c b/shared-bindings/jpegio/JpegDecoder.c index 13287a23650..ad2a0622e7a 100644 --- a/shared-bindings/jpegio/JpegDecoder.c +++ b/shared-bindings/jpegio/JpegDecoder.c @@ -43,7 +43,6 @@ static mp_obj_t jpegio_jpegdecoder_make_new(const mp_obj_type_t *type, size_t n_ mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); jpegio_jpegdecoder_obj_t *self = mp_obj_malloc(jpegio_jpegdecoder_obj_t, &jpegio_jpegdecoder_type); - self->base.type = &jpegio_jpegdecoder_type; common_hal_jpegio_jpegdecoder_construct(self); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/keypad/Event.c b/shared-bindings/keypad/Event.c index 51e446e8362..f83e01e785e 100644 --- a/shared-bindings/keypad/Event.c +++ b/shared-bindings/keypad/Event.c @@ -26,7 +26,6 @@ //| ... //| static mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - keypad_event_obj_t *self = mp_obj_malloc(keypad_event_obj_t, &keypad_event_type); enum { ARG_key_number, ARG_pressed, ARG_timestamp }; static const mp_arg_t allowed_args[] = { { MP_QSTR_key_number, MP_ARG_INT, {.u_int = 0} }, @@ -45,7 +44,9 @@ static mp_obj_t keypad_event_make_new(const mp_obj_type_t *type, size_t n_args, } (void)mp_obj_get_int_truncated(timestamp); // ensure that timestamp is an integer + keypad_event_obj_t *self = mp_obj_malloc(keypad_event_obj_t, &keypad_event_type); common_hal_keypad_event_construct(self, key_number, args[ARG_pressed].u_bool, timestamp); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/keypad/KeyMatrix.c b/shared-bindings/keypad/KeyMatrix.c index edb32c2c5c7..01416a2f8a1 100644 --- a/shared-bindings/keypad/KeyMatrix.c +++ b/shared-bindings/keypad/KeyMatrix.c @@ -81,7 +81,6 @@ static mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_KEYPAD_KEYMATRIX - keypad_keymatrix_obj_t *self = mp_obj_malloc(keypad_keymatrix_obj_t, &keypad_keymatrix_type); enum { ARG_row_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_interval, ARG_max_events, ARG_debounce_threshold }; static const mp_arg_t allowed_args[] = { { MP_QSTR_row_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -123,7 +122,9 @@ static mp_obj_t keypad_keymatrix_make_new(const mp_obj_type_t *type, size_t n_ar column_pins_array[column] = pin; } + keypad_keymatrix_obj_t *self = mp_obj_malloc(keypad_keymatrix_obj_t, &keypad_keymatrix_type); common_hal_keypad_keymatrix_construct(self, num_row_pins, row_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, interval, max_events, debounce_threshold); + return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_KeyMatrix); diff --git a/shared-bindings/keypad/Keys.c b/shared-bindings/keypad/Keys.c index 64e8e51a67d..5fd065fc627 100644 --- a/shared-bindings/keypad/Keys.c +++ b/shared-bindings/keypad/Keys.c @@ -81,7 +81,6 @@ static mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_KEYPAD_KEYS - keypad_keys_obj_t *self = mp_obj_malloc(keypad_keys_obj_t, &keypad_keys_type); enum { ARG_pins, ARG_value_when_pressed, ARG_pull, ARG_interval, ARG_max_events, ARG_debounce_threshold }; static const mp_arg_t allowed_args[] = { { MP_QSTR_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -112,6 +111,7 @@ static mp_obj_t keypad_keys_make_new(const mp_obj_type_t *type, size_t n_args, s validate_obj_is_free_pin(mp_obj_subscr(pins, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL), MP_QSTR_pin); } + keypad_keys_obj_t *self = mp_obj_malloc(keypad_keys_obj_t, &keypad_keys_type); common_hal_keypad_keys_construct(self, num_pins, pins_array, value_when_pressed, args[ARG_pull].u_bool, interval, max_events, debounce_threshold); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/keypad/ShiftRegisterKeys.c b/shared-bindings/keypad/ShiftRegisterKeys.c index 1347735b5d2..7f89a11ecf1 100644 --- a/shared-bindings/keypad/ShiftRegisterKeys.c +++ b/shared-bindings/keypad/ShiftRegisterKeys.c @@ -88,8 +88,6 @@ static mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { #if CIRCUITPY_KEYPAD_SHIFTREGISTERKEYS - keypad_shiftregisterkeys_obj_t *self = - mp_obj_malloc(keypad_shiftregisterkeys_obj_t, &keypad_shiftregisterkeys_type); enum { ARG_clock, ARG_data, ARG_latch, ARG_value_to_latch, ARG_key_count, ARG_value_when_pressed, ARG_interval, ARG_max_events, ARG_debounce_threshold }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -160,6 +158,8 @@ static mp_obj_t keypad_shiftregisterkeys_make_new(const mp_obj_type_t *type, siz const size_t max_events = (size_t)mp_arg_validate_int_min(args[ARG_max_events].u_int, 1, MP_QSTR_max_events); const uint8_t debounce_threshold = (uint8_t)mp_arg_validate_int_range(args[ARG_debounce_threshold].u_int, 1, 127, MP_QSTR_debounce_threshold); + keypad_shiftregisterkeys_obj_t *self = + mp_obj_malloc(keypad_shiftregisterkeys_obj_t, &keypad_shiftregisterkeys_type); common_hal_keypad_shiftregisterkeys_construct( self, clock, num_data_pins, data_pins_array, latch, value_to_latch, num_key_counts, key_count_array, value_when_pressed, interval, max_events, debounce_threshold); diff --git a/shared-bindings/keypad_demux/DemuxKeyMatrix.c b/shared-bindings/keypad_demux/DemuxKeyMatrix.c index f1b5ecae9ce..554e461c228 100644 --- a/shared-bindings/keypad_demux/DemuxKeyMatrix.c +++ b/shared-bindings/keypad_demux/DemuxKeyMatrix.c @@ -80,7 +80,6 @@ //| static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - keypad_demux_demuxkeymatrix_obj_t *self = mp_obj_malloc(keypad_demux_demuxkeymatrix_obj_t, &keypad_demux_demuxkeymatrix_type); enum { ARG_row_addr_pins, ARG_column_pins, ARG_columns_to_anodes, ARG_transpose, ARG_interval, ARG_max_events, ARG_debounce_threshold }; static const mp_arg_t allowed_args[] = { { MP_QSTR_row_addr_pins, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -123,8 +122,10 @@ static mp_obj_t keypad_demux_demuxkeymatrix_make_new(const mp_obj_type_t *type, column_pins_array[column] = pin; } + keypad_demux_demuxkeymatrix_obj_t *self = mp_obj_malloc(keypad_demux_demuxkeymatrix_obj_t, &keypad_demux_demuxkeymatrix_type); // Last arg is use_gc_allocator, true during VM use. common_hal_keypad_demux_demuxkeymatrix_construct(self, num_row_addr_pins, row_addr_pins_array, num_column_pins, column_pins_array, args[ARG_columns_to_anodes].u_bool, args[ARG_transpose].u_bool, interval, max_events, debounce_threshold, true); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/memorymap/AddressRange.c b/shared-bindings/memorymap/AddressRange.c index efc55ad37d7..5f7ee0deb95 100644 --- a/shared-bindings/memorymap/AddressRange.c +++ b/shared-bindings/memorymap/AddressRange.c @@ -92,7 +92,6 @@ static mp_obj_t memorymap_addressrange_make_new(const mp_obj_type_t *type, size_ } memorymap_addressrange_obj_t *self = mp_obj_malloc(memorymap_addressrange_obj_t, &memorymap_addressrange_type); - common_hal_memorymap_addressrange_construct(self, (uint8_t *)start, length); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/memorymonitor/AllocationAlarm.c b/shared-bindings/memorymonitor/AllocationAlarm.c index 5475e2d7db4..00cfbbd9fe1 100644 --- a/shared-bindings/memorymonitor/AllocationAlarm.c +++ b/shared-bindings/memorymonitor/AllocationAlarm.c @@ -48,7 +48,6 @@ static mp_obj_t memorymonitor_allocationalarm_make_new(const mp_obj_type_t *type memorymonitor_allocationalarm_obj_t *self = mp_obj_malloc(memorymonitor_allocationalarm_obj_t, &memorymonitor_allocationalarm_type); - common_hal_memorymonitor_allocationalarm_construct(self, minimum_block_count); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/msgpack/ExtType.c b/shared-bindings/msgpack/ExtType.c index f66abda8fa2..c69416f9773 100644 --- a/shared-bindings/msgpack/ExtType.c +++ b/shared-bindings/msgpack/ExtType.c @@ -18,7 +18,6 @@ //| :param bytes data: representation.""" //| static mp_obj_t mod_msgpack_exttype_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - mod_msgpack_extype_obj_t *self = mp_obj_malloc(mod_msgpack_extype_obj_t, &mod_msgpack_exttype_type); enum { ARG_code, ARG_data }; static const mp_arg_t allowed_args[] = { { MP_QSTR_code, MP_ARG_INT | MP_ARG_REQUIRED }, @@ -28,11 +27,12 @@ static mp_obj_t mod_msgpack_exttype_make_new(const mp_obj_type_t *type, size_t n mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); int code = mp_arg_validate_int_range(args[ARG_code].u_int, 0, 127, MP_QSTR_code); + mp_obj_t data = args[ARG_data].u_obj; + mod_msgpack_extype_obj_t *self = mp_obj_malloc(mod_msgpack_extype_obj_t, &mod_msgpack_exttype_type); self->code = code; - - mp_obj_t data = args[ARG_data].u_obj; self->data = data; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/onewireio/OneWire.c b/shared-bindings/onewireio/OneWire.c index a3750ae5e07..2f69424cc23 100644 --- a/shared-bindings/onewireio/OneWire.c +++ b/shared-bindings/onewireio/OneWire.c @@ -43,8 +43,8 @@ static mp_obj_t onewireio_onewire_make_new(const mp_obj_type_t *type, size_t n_a const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); onewireio_onewire_obj_t *self = mp_obj_malloc(onewireio_onewire_obj_t, &onewireio_onewire_type); - common_hal_onewireio_onewire_construct(self, pin); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/os/__init__.c b/shared-bindings/os/__init__.c index 5e28c02452d..678b444de64 100644 --- a/shared-bindings/os/__init__.c +++ b/shared-bindings/os/__init__.c @@ -67,7 +67,7 @@ static MP_DEFINE_ATTRTUPLE( ); static mp_obj_t os_uname(void) { - return (mp_obj_t)&os_uname_info_obj; + return MP_OBJ_FROM_PTR(&os_uname_info_obj); } static MP_DEFINE_CONST_FUN_OBJ_0(os_uname_obj, os_uname); diff --git a/shared-bindings/ps2io/Ps2.c b/shared-bindings/ps2io/Ps2.c index 8766ea7a2a1..90e6b0b6045 100644 --- a/shared-bindings/ps2io/Ps2.c +++ b/shared-bindings/ps2io/Ps2.c @@ -58,7 +58,6 @@ static mp_obj_t ps2io_ps2_make_new(const mp_obj_type_t *type, size_t n_args, siz const mcu_pin_obj_t *data_pin = validate_obj_is_free_pin(args[ARG_data_pin].u_obj, MP_QSTR_data_pin); ps2io_ps2_obj_t *self = mp_obj_malloc(ps2io_ps2_obj_t, &ps2io_ps2_type); - common_hal_ps2io_ps2_construct(self, data_pin, clock_pin); return MP_OBJ_FROM_PTR(self); diff --git a/shared-bindings/pulseio/PulseIn.c b/shared-bindings/pulseio/PulseIn.c index d9e6bfd7aec..830f7b7c62c 100644 --- a/shared-bindings/pulseio/PulseIn.c +++ b/shared-bindings/pulseio/PulseIn.c @@ -69,7 +69,6 @@ static mp_obj_t pulseio_pulsein_make_new(const mp_obj_type_t *type, size_t n_arg const mcu_pin_obj_t *pin = validate_obj_is_free_pin(args[ARG_pin].u_obj, MP_QSTR_pin); pulseio_pulsein_obj_t *self = mp_obj_malloc_with_finaliser(pulseio_pulsein_obj_t, &pulseio_pulsein_type); - common_hal_pulseio_pulsein_construct(self, pin, args[ARG_maxlen].u_int, args[ARG_idle_state].u_bool); diff --git a/shared-bindings/pulseio/PulseOut.c b/shared-bindings/pulseio/PulseOut.c index 947aa4b518e..58c98b8e2cc 100644 --- a/shared-bindings/pulseio/PulseOut.c +++ b/shared-bindings/pulseio/PulseOut.c @@ -62,6 +62,7 @@ static mp_obj_t pulseio_pulseout_make_new(const mp_obj_type_t *type, size_t n_ar pulseio_pulseout_obj_t *self = mp_obj_malloc_with_finaliser(pulseio_pulseout_obj_t, &pulseio_pulseout_type); common_hal_pulseio_pulseout_construct(self, pin, frequency, duty_cycle); + return MP_OBJ_FROM_PTR(self); #else mp_raise_NotImplementedError(NULL); diff --git a/shared-bindings/qrio/QRDecoder.c b/shared-bindings/qrio/QRDecoder.c index 6a36d8b0265..e8977bc1efe 100644 --- a/shared-bindings/qrio/QRDecoder.c +++ b/shared-bindings/qrio/QRDecoder.c @@ -34,7 +34,7 @@ static mp_obj_t qrio_qrdecoder_make_new(const mp_obj_type_t *type, size_t n_args qrio_qrdecoder_obj_t *self = mp_obj_malloc(qrio_qrdecoder_obj_t, &qrio_qrdecoder_type_obj); shared_module_qrio_qrdecoder_construct(self, args[ARG_width].u_int, args[ARG_height].u_int); - return self; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/rclcpy/Node.c b/shared-bindings/rclcpy/Node.c index a2fa9bd36a6..4097fbc1515 100644 --- a/shared-bindings/rclcpy/Node.c +++ b/shared-bindings/rclcpy/Node.c @@ -50,7 +50,8 @@ static mp_obj_t rclcpy_node_make_new(const mp_obj_type_t *type, size_t n_args, s rclcpy_node_obj_t *self = mp_obj_malloc_with_finaliser(rclcpy_node_obj_t, &rclcpy_node_type); common_hal_rclcpy_node_construct(self, node_name, namespace); - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: @@ -90,7 +91,7 @@ static mp_obj_t rclcpy_node_create_publisher(mp_obj_t self_in, mp_obj_t topic) { rclcpy_publisher_obj_t *publisher = mp_obj_malloc_with_finaliser(rclcpy_publisher_obj_t, &rclcpy_publisher_type); common_hal_rclcpy_publisher_construct(publisher, self, topic_name); - return (mp_obj_t)publisher; + return MP_OBJ_FROM_PTR(publisher); } static MP_DEFINE_CONST_FUN_OBJ_2(rclcpy_node_create_publisher_obj, rclcpy_node_create_publisher); diff --git a/shared-bindings/rclcpy/__init__.c b/shared-bindings/rclcpy/__init__.c index a6631642ea7..e195294cde6 100644 --- a/shared-bindings/rclcpy/__init__.c +++ b/shared-bindings/rclcpy/__init__.c @@ -112,7 +112,8 @@ static mp_obj_t rclcpy_create_node(size_t n_args, const mp_obj_t *pos_args, mp_m rclcpy_node_obj_t *self = mp_obj_malloc_with_finaliser(rclcpy_node_obj_t, &rclcpy_node_type); common_hal_rclcpy_node_construct(self, node_name, namespace); - return (mp_obj_t)self; + + return MP_OBJ_FROM_PTR(self); } static MP_DEFINE_CONST_FUN_OBJ_KW(rclcpy_create_node_obj, 2, rclcpy_create_node); diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index 65c5f80b52b..2802499956c 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -82,10 +82,9 @@ static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); sdcardio_sdcard_obj_t *self = mp_obj_malloc_with_finaliser(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type); - common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int); - return self; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/sdioio/SDCard.c b/shared-bindings/sdioio/SDCard.c index 892cecd3fb4..baf1e1660e8 100644 --- a/shared-bindings/sdioio/SDCard.c +++ b/shared-bindings/sdioio/SDCard.c @@ -67,7 +67,6 @@ //| static mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - sdioio_sdcard_obj_t *self = mp_obj_malloc(sdioio_sdcard_obj_t, &sdioio_SDCard_type); enum { ARG_clock, ARG_command, ARG_data, ARG_frequency, NUM_ARGS }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_KW_ONLY | MP_ARG_OBJ }, @@ -86,6 +85,7 @@ static mp_obj_t sdioio_sdcard_make_new(const mp_obj_type_t *type, size_t n_args, uint8_t num_data; validate_list_is_free_pins(MP_QSTR_data, data_pins, MP_ARRAY_SIZE(data_pins), args[ARG_data].u_obj, &num_data); + sdioio_sdcard_obj_t *self = mp_obj_malloc(sdioio_sdcard_obj_t, &sdioio_SDCard_type); common_hal_sdioio_sdcard_construct(self, clock, command, num_data, data_pins, args[ARG_frequency].u_int); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c index e139e3a077a..72b15ba9edd 100644 --- a/shared-bindings/socketpool/SocketPool.c +++ b/shared-bindings/socketpool/SocketPool.c @@ -36,9 +36,9 @@ static mp_obj_t socketpool_socketpool_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); - socketpool_socketpool_obj_t *s = mp_obj_malloc_with_finaliser(socketpool_socketpool_obj_t, &socketpool_socketpool_type); mp_obj_t radio = args[0]; + socketpool_socketpool_obj_t *s = mp_obj_malloc_with_finaliser(socketpool_socketpool_obj_t, &socketpool_socketpool_type); common_hal_socketpool_socketpool_construct(s, radio); return MP_OBJ_FROM_PTR(s); diff --git a/shared-bindings/spitarget/SPITarget.c b/shared-bindings/spitarget/SPITarget.c index eca92d80027..08f6d554f3a 100644 --- a/shared-bindings/spitarget/SPITarget.c +++ b/shared-bindings/spitarget/SPITarget.c @@ -33,7 +33,6 @@ //| ... //| static mp_obj_t spitarget_spi_target_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - spitarget_spi_target_obj_t *self = mp_obj_malloc(spitarget_spi_target_obj_t, &spitarget_spi_target_type); enum { ARG_sck, ARG_mosi, ARG_miso, ARG_ss }; static const mp_arg_t allowed_args[] = { { MP_QSTR_sck, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -49,7 +48,9 @@ static mp_obj_t spitarget_spi_target_make_new(const mp_obj_type_t *type, size_t const mcu_pin_obj_t *miso = validate_obj_is_free_pin(args[ARG_miso].u_obj, MP_QSTR_miso); const mcu_pin_obj_t *ss = validate_obj_is_free_pin(args[ARG_ss].u_obj, MP_QSTR_ss); + spitarget_spi_target_obj_t *self = mp_obj_malloc(spitarget_spi_target_obj_t, &spitarget_spi_target_type); common_hal_spitarget_spi_target_construct(self, sck, mosi, miso, ss); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/ssl/SSLContext.c b/shared-bindings/ssl/SSLContext.c index 078a716cdb8..9546c50ed7c 100644 --- a/shared-bindings/ssl/SSLContext.c +++ b/shared-bindings/ssl/SSLContext.c @@ -26,7 +26,6 @@ static mp_obj_t ssl_sslcontext_make_new(const mp_obj_type_t *type, size_t n_args mp_arg_check_num(n_args, n_kw, 0, 1, false); ssl_sslcontext_obj_t *s = mp_obj_malloc(ssl_sslcontext_obj_t, &ssl_sslcontext_type); - common_hal_ssl_sslcontext_construct(s); return MP_OBJ_FROM_PTR(s); diff --git a/shared-bindings/ssl/__init__.c b/shared-bindings/ssl/__init__.c index 0d10090e9cb..51a3ad3cfc4 100644 --- a/shared-bindings/ssl/__init__.c +++ b/shared-bindings/ssl/__init__.c @@ -27,9 +27,9 @@ static mp_obj_t ssl_create_default_context(void) { ssl_sslcontext_obj_t *s = mp_obj_malloc(ssl_sslcontext_obj_t, &ssl_sslcontext_type); - common_hal_ssl_create_default_context(s); - return s; + + return MP_OBJ_FROM_PTR(s); } MP_DEFINE_CONST_FUN_OBJ_0(ssl_create_default_context_obj, ssl_create_default_context); diff --git a/shared-bindings/synthio/LFO.c b/shared-bindings/synthio/LFO.c index ee2d67d3089..2dfae22a577 100644 --- a/shared-bindings/synthio/LFO.c +++ b/shared-bindings/synthio/LFO.c @@ -103,17 +103,17 @@ static mp_obj_t synthio_lfo_make_new(const mp_obj_type_t *type_in, size_t n_args } self->waveform_obj = args[ARG_waveform].u_obj; - mp_obj_t result = MP_OBJ_FROM_PTR(self); - properties_construct_helper(result, lfo_properties + 1, args + 1, MP_ARRAY_SIZE(lfo_properties) - 1); + mp_obj_t self_obj = MP_OBJ_FROM_PTR(self); + properties_construct_helper(self_obj, lfo_properties + 1, args + 1, MP_ARRAY_SIZE(lfo_properties) - 1); // Force computation of the LFO's initial output synthio_global_rate_scale = 0; self->base.last_tick = synthio_global_tick - 1; synthio_block_slot_t slot; - synthio_block_assign_slot(MP_OBJ_FROM_PTR(result), &slot, MP_QSTR_self); + synthio_block_assign_slot(self_obj, &slot, MP_QSTR_self); (void)synthio_block_slot_get(&slot); - return result; + return self_obj; }; //| waveform: Optional[ReadableBuffer] diff --git a/shared-bindings/synthio/Math.c b/shared-bindings/synthio/Math.c index 5e943b44d0f..96857fb3513 100644 --- a/shared-bindings/synthio/Math.c +++ b/shared-bindings/synthio/Math.c @@ -157,10 +157,10 @@ static mp_obj_t synthio_math_make_new_common(mp_arg_val_t args[MP_ARRAY_SIZE(mat self->base.last_tick = synthio_global_tick; - mp_obj_t result = MP_OBJ_FROM_PTR(self); - properties_construct_helper(result, math_properties, args, MP_ARRAY_SIZE(math_properties)); + mp_obj_t self_obj = MP_OBJ_FROM_PTR(self); + properties_construct_helper(self_obj, math_properties, args, MP_ARRAY_SIZE(math_properties)); - return result; + return self_obj; }; //| a: BlockInput diff --git a/shared-bindings/synthio/MidiTrack.c b/shared-bindings/synthio/MidiTrack.c index db75a543c61..0304df12a81 100644 --- a/shared-bindings/synthio/MidiTrack.c +++ b/shared-bindings/synthio/MidiTrack.c @@ -70,7 +70,6 @@ static mp_obj_t synthio_miditrack_make_new(const mp_obj_type_t *type, size_t n_a mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_READ); synthio_miditrack_obj_t *self = mp_obj_malloc(synthio_miditrack_obj_t, &synthio_miditrack_type); - common_hal_synthio_miditrack_construct(self, (uint8_t *)bufinfo.buf, bufinfo.len, args[ARG_tempo].u_int, diff --git a/shared-bindings/synthio/Note.c b/shared-bindings/synthio/Note.c index 95dd51fe6b0..183c59d5fbd 100644 --- a/shared-bindings/synthio/Note.c +++ b/shared-bindings/synthio/Note.c @@ -61,11 +61,11 @@ static mp_obj_t synthio_note_make_new(const mp_obj_type_t *type_in, size_t n_arg mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(note_properties), note_properties, args); synthio_note_obj_t *self = mp_obj_malloc(synthio_note_obj_t, &synthio_note_type); + mp_obj_t self_obj = MP_OBJ_FROM_PTR(self); - mp_obj_t result = MP_OBJ_FROM_PTR(self); - properties_construct_helper(result, note_properties, args, MP_ARRAY_SIZE(note_properties)); + properties_construct_helper(self_obj, note_properties, args, MP_ARRAY_SIZE(note_properties)); - return result; + return self_obj; }; //| frequency: float diff --git a/shared-bindings/synthio/Synthesizer.c b/shared-bindings/synthio/Synthesizer.c index fb39e8ef50e..35cc42a2037 100644 --- a/shared-bindings/synthio/Synthesizer.c +++ b/shared-bindings/synthio/Synthesizer.c @@ -62,7 +62,6 @@ static mp_obj_t synthio_synthesizer_make_new(const mp_obj_type_t *type, size_t n mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); synthio_synthesizer_obj_t *self = mp_obj_malloc(synthio_synthesizer_obj_t, &synthio_synthesizer_type); - common_hal_synthio_synthesizer_construct(self, args[ARG_sample_rate].u_int, args[ARG_channel_count].u_int, diff --git a/shared-bindings/synthio/__init__.c b/shared-bindings/synthio/__init__.c index 6d42880541d..6a21834751b 100644 --- a/shared-bindings/synthio/__init__.c +++ b/shared-bindings/synthio/__init__.c @@ -252,7 +252,6 @@ static mp_obj_t synthio_from_file(size_t n_args, const mp_obj_t *pos_args, mp_ma } synthio_miditrack_obj_t *result = mp_obj_malloc(synthio_miditrack_obj_t, &synthio_miditrack_type); - common_hal_synthio_miditrack_construct(result, buffer, track_size, tempo, args[ARG_sample_rate].u_int, args[ARG_waveform].u_obj, mp_const_none, diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c index 199128e56e9..72c43ba2dc1 100644 --- a/shared-bindings/terminalio/Terminal.c +++ b/shared-bindings/terminalio/Terminal.c @@ -176,8 +176,8 @@ static mp_obj_t terminalio_terminal_make_new(const mp_obj_type_t *type, size_t n mp_arg_validate_int_min(scroll_area->width_in_tiles * scroll_area->height_in_tiles, 2, MP_QSTR_scroll_area_area); terminalio_terminal_obj_t *self = mp_obj_malloc(terminalio_terminal_obj_t, &terminalio_terminal_type); - common_hal_terminalio_terminal_construct(self, scroll_area, font, status_bar); + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/tilepalettemapper/TilePaletteMapper.c b/shared-bindings/tilepalettemapper/TilePaletteMapper.c index ed3e928957f..c22ea47bf26 100644 --- a/shared-bindings/tilepalettemapper/TilePaletteMapper.c +++ b/shared-bindings/tilepalettemapper/TilePaletteMapper.c @@ -45,7 +45,6 @@ static mp_obj_t tilepalettemapper_tilepalettemapper_make_new(const mp_obj_type_t mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported %q type"), MP_QSTR_pixel_shader); } - tilepalettemapper_tilepalettemapper_t *self = mp_obj_malloc(tilepalettemapper_tilepalettemapper_t, &tilepalettemapper_tilepalettemapper_type); common_hal_tilepalettemapper_tilepalettemapper_construct(self, pixel_shader, args[ARG_input_color_count].u_int); diff --git a/shared-bindings/touchio/TouchIn.c b/shared-bindings/touchio/TouchIn.c index 19d97bd9d7c..2250e88f599 100644 --- a/shared-bindings/touchio/TouchIn.c +++ b/shared-bindings/touchio/TouchIn.c @@ -56,7 +56,7 @@ static mp_obj_t touchio_touchin_make_new(const mp_obj_type_t *type, touchio_touchin_obj_t *self = mp_obj_malloc(touchio_touchin_obj_t, &touchio_touchin_type); common_hal_touchio_touchin_construct(self, pin, pull); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } //| def deinit(self) -> None: diff --git a/shared-bindings/usb/core/__init__.c b/shared-bindings/usb/core/__init__.c index 545e182ea99..3907effb8ff 100644 --- a/shared-bindings/usb/core/__init__.c +++ b/shared-bindings/usb/core/__init__.c @@ -90,9 +90,10 @@ static mp_obj_t _next_device(usb_core_devices_obj_t *iter) { // We passed the filters. Now make a properly allocated object to // return to the user. usb_core_device_obj_t *self = mp_obj_malloc(usb_core_device_obj_t, &usb_core_device_type); - common_hal_usb_core_device_construct(self, i); + iter->next_index = i + 1; + return MP_OBJ_FROM_PTR(self); } // Iter is done. diff --git a/shared-bindings/usb_hid/Device.c b/shared-bindings/usb_hid/Device.c index a4a0e8680e5..66c9c01ad6e 100644 --- a/shared-bindings/usb_hid/Device.c +++ b/shared-bindings/usb_hid/Device.c @@ -75,7 +75,6 @@ //| static mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - usb_hid_device_obj_t *self = mp_obj_malloc(usb_hid_device_obj_t, &usb_hid_device_type); enum { ARG_report_descriptor, ARG_usage_page, ARG_usage, ARG_report_ids, ARG_in_report_lengths, ARG_out_report_lengths }; static const mp_arg_t allowed_args[] = { { MP_QSTR_report_descriptor, MP_ARG_KW_ONLY | MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -141,9 +140,10 @@ static mp_obj_t usb_hid_device_make_new(const mp_obj_type_t *type, size_t n_args mp_raise_ValueError_varg(MP_ERROR_TEXT("%q length must be %d"), MP_QSTR_report_id_space_0, 1); } + usb_hid_device_obj_t *self = mp_obj_malloc(usb_hid_device_obj_t, &usb_hid_device_type); common_hal_usb_hid_device_construct( self, descriptor, usage_page, usage, report_ids_count, report_ids_array, in_report_lengths_array, out_report_lengths_array); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/usb_host/Port.c b/shared-bindings/usb_host/Port.c index 41e8513a1e8..2c61e641a05 100644 --- a/shared-bindings/usb_host/Port.c +++ b/shared-bindings/usb_host/Port.c @@ -42,7 +42,7 @@ static mp_obj_t usb_host_port_make_new(const mp_obj_type_t *type, usb_host_port_obj_t *self = common_hal_usb_host_port_construct(dp, dm); - return (mp_obj_t)self; + return MP_OBJ_FROM_PTR(self); } static const mp_rom_map_elem_t usb_host_port_locals_dict_table[] = { diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index ff29609fc4e..834f1fbff50 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -69,7 +69,7 @@ mp_obj_t vectorio_vector_shape_make_new(const mp_obj_t shape, const mp_obj_t pix } else if (mp_obj_is_type(shape, &vectorio_circle_type)) { common_hal_vectorio_circle_set_on_dirty(self->ishape.shape, on_dirty); } else { - mp_raise_TypeError_varg(MP_ERROR_TEXT("unsupported %q type"), MP_QSTR_shape); + // Already excluded due to previous else-if chain. } return MP_OBJ_FROM_PTR(self); From 2fac7c9572ffac3eb156f33028685887b2e5b975 Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Fri, 6 Mar 2026 11:49:17 +0100 Subject: [PATCH 294/876] Review fixes --- shared-module/displayio/bus_core.c | 36 +++++++++--------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/shared-module/displayio/bus_core.c b/shared-module/displayio/bus_core.c index df6c5d36f4b..6bba0065ad9 100644 --- a/shared-module/displayio/bus_core.c +++ b/shared-module/displayio/bus_core.c @@ -117,7 +117,7 @@ void displayio_display_bus_end_transaction(displayio_display_bus_t *self) { self->end_transaction(self->bus); } -static void _displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area, bool manage_transactions) { +static void _displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { uint16_t x1 = area->x1 + self->colstart; uint16_t x2 = area->x2 + self->colstart; uint16_t y1 = area->y1 + self->rowstart; @@ -144,9 +144,7 @@ static void _displayio_display_bus_send_region_commands(displayio_display_bus_t } // Set column. - if (manage_transactions) { - displayio_display_bus_begin_transaction(self); - } + displayio_display_bus_begin_transaction(self); uint8_t data[5]; data[0] = self->column_command; uint8_t data_length = 1; @@ -181,28 +179,20 @@ static void _displayio_display_bus_send_region_commands(displayio_display_bus_t } self->send(self->bus, data_type, chip_select, data, data_length); - if (manage_transactions) { - displayio_display_bus_end_transaction(self); - } + displayio_display_bus_end_transaction(self); if (self->set_current_column_command != NO_COMMAND) { uint8_t command = self->set_current_column_command; - if (manage_transactions) { - displayio_display_bus_begin_transaction(self); - } + displayio_display_bus_begin_transaction(self); self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); // Only send the first half of data because it is the first coordinate. self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); - if (manage_transactions) { - displayio_display_bus_end_transaction(self); - } + displayio_display_bus_end_transaction(self); } // Set row. - if (manage_transactions) { - displayio_display_bus_begin_transaction(self); - } + displayio_display_bus_begin_transaction(self); data[0] = self->row_command; data_length = 1; if (!self->data_as_commands) { @@ -233,26 +223,20 @@ static void _displayio_display_bus_send_region_commands(displayio_display_bus_t } self->send(self->bus, data_type, chip_select, data, data_length); - if (manage_transactions) { - displayio_display_bus_end_transaction(self); - } + displayio_display_bus_end_transaction(self); if (self->set_current_row_command != NO_COMMAND) { uint8_t command = self->set_current_row_command; - if (manage_transactions) { - displayio_display_bus_begin_transaction(self); - } + displayio_display_bus_begin_transaction(self); self->send(self->bus, DISPLAY_COMMAND, chip_select, &command, 1); // Only send the first half of data because it is the first coordinate. self->send(self->bus, DISPLAY_DATA, chip_select, data, data_length / 2); - if (manage_transactions) { - displayio_display_bus_end_transaction(self); - } + displayio_display_bus_end_transaction(self); } } void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { - _displayio_display_bus_send_region_commands(self, display, area, true); + _displayio_display_bus_send_region_commands(self, display, area); } void displayio_display_bus_flush(displayio_display_bus_t *self) { From a2d29c55085ab7157c26298a550b2384d546db88 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 6 Mar 2026 13:07:59 -0500 Subject: [PATCH 295/876] atmel-samd SPI: don't mark_deinit before resetting pin --- ports/atmel-samd/common-hal/busio/SPI.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index fe53580afdf..19fd81e425d 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -194,14 +194,14 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } allow_reset_sercom(self->spi_desc.dev.prvt); - // Mark as deinit early in case we are used in an interrupt. - common_hal_busio_spi_mark_deinit(self); - spi_m_sync_disable(&self->spi_desc); spi_m_sync_deinit(&self->spi_desc); reset_pin_number(self->clock_pin); reset_pin_number(self->MOSI_pin); reset_pin_number(self->MISO_pin); + + // This smashes self->clock_pin, so don't do it before resetting the pin above. + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, From c2ab75323aeefe98c508922f63f6c64b885c2755 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 8 Mar 2026 19:07:26 -0400 Subject: [PATCH 296/876] shared-bindings/busdisplay/BusDisplay.c: remove obsolete set_vertical_scroll arg Fixes #5189. --- shared-bindings/busdisplay/BusDisplay.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-bindings/busdisplay/BusDisplay.c b/shared-bindings/busdisplay/BusDisplay.c index 297a8690577..0bf171a5d08 100644 --- a/shared-bindings/busdisplay/BusDisplay.c +++ b/shared-bindings/busdisplay/BusDisplay.c @@ -122,7 +122,6 @@ //| :param int native_frames_per_second: Number of display refreshes per second that occur with the given init_sequence. //| :param bool backlight_on_high: If True, pulling the backlight pin high turns the backlight on. //| :param bool SH1107_addressing: Special quirk for SH1107, use upper/lower column set and page set -//| :param int set_vertical_scroll: This parameter is accepted but ignored for backwards compatibility. It will be removed in a future release. //| :param int backlight_pwm_frequency: The frequency to use to drive the PWM for backlight brightness control. Default is 50000. //| """ //| ... @@ -133,7 +132,7 @@ static mp_obj_t busdisplay_busdisplay_make_new(const mp_obj_type_t *type, size_t ARG_rotation, ARG_color_depth, ARG_grayscale, ARG_pixels_in_byte_share_row, ARG_bytes_per_cell, ARG_reverse_pixels_in_byte, ARG_reverse_bytes_in_word, ARG_set_column_command, ARG_set_row_command, ARG_write_ram_command, - ARG_set_vertical_scroll, ARG_backlight_pin, ARG_brightness_command, + ARG_backlight_pin, ARG_brightness_command, ARG_brightness, ARG_single_byte_bounds, ARG_data_as_commands, ARG_auto_refresh, ARG_native_frames_per_second, ARG_backlight_on_high, ARG_SH1107_addressing, ARG_backlight_pwm_frequency }; @@ -154,7 +153,6 @@ static mp_obj_t busdisplay_busdisplay_make_new(const mp_obj_type_t *type, size_t { MP_QSTR_set_column_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2a} }, { MP_QSTR_set_row_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2b} }, { MP_QSTR_write_ram_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x2c} }, - { MP_QSTR_set_vertical_scroll, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0x0} }, { MP_QSTR_backlight_pin, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_brightness_command, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = NO_BRIGHTNESS_COMMAND} }, { MP_QSTR_brightness, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NEW_SMALL_INT(1)} }, From 113688a090d9cfa49ec4c1633e7f100defe65741 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 8 Mar 2026 19:10:28 -0400 Subject: [PATCH 297/876] espressif SPI: wait_for_lock impl specific to FreeRTOS --- ports/espressif/common-hal/busio/SPI.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ports/espressif/common-hal/busio/SPI.c b/ports/espressif/common-hal/busio/SPI.c index fc12d40fccb..21dc8c38379 100644 --- a/ports/espressif/common-hal/busio/SPI.c +++ b/ports/espressif/common-hal/busio/SPI.c @@ -157,11 +157,17 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, return true; } -bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { +// Wait as long as needed for the lock. This is used by SD card access from USB. +// Overrides the default busy-wait implementation in shared-bindings/busio/SPI.c +bool common_hal_busio_spi_wait_for_lock(busio_spi_obj_t *self, uint32_t timeout_ms) { if (common_hal_busio_spi_deinited(self)) { return false; } - return xSemaphoreTake(self->mutex, 0) == pdTRUE; + return xSemaphoreTake(self->mutex, pdMS_TO_TICKS(timeout_ms)) == pdTRUE; +} + +bool common_hal_busio_spi_try_lock(busio_spi_obj_t *self) { + return common_hal_busio_spi_wait_for_lock(self, 0); } bool common_hal_busio_spi_has_lock(busio_spi_obj_t *self) { From 76aa0c7ea24464fa15f8fc086f13d07e5df77bc9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 8 Mar 2026 20:25:32 -0400 Subject: [PATCH 298/876] shared-module/displayio/__init__.c: fix keep_primary logic in common_hal_displayio_release_displays_impl() --- shared-module/displayio/__init__.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/shared-module/displayio/__init__.c b/shared-module/displayio/__init__.c index e325a7857f4..c4e8a14af9f 100644 --- a/shared-module/displayio/__init__.c +++ b/shared-module/displayio/__init__.c @@ -146,6 +146,9 @@ static void common_hal_displayio_release_displays_impl(bool keep_primary) { displays[i].display_base.type = &mp_type_NoneType; } for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { + if (i == primary_display_number) { + continue; + } mp_const_obj_t bus_type = display_buses[i].bus_base.type; if (bus_type == NULL || bus_type == &mp_type_NoneType) { continue; @@ -193,7 +196,9 @@ static void common_hal_displayio_release_displays_impl(bool keep_primary) { display_buses[i].bus_base.type = &mp_type_NoneType; } - supervisor_stop_terminal(); + if (!keep_primary) { + supervisor_stop_terminal(); + } } void common_hal_displayio_release_displays(void) { @@ -201,8 +206,9 @@ void common_hal_displayio_release_displays(void) { } void reset_displays(void) { - // In CircuitPython 10, release secondary displays before doing anything else: - // common_hal_displayio_release_displays_impl(true); + // TODO: In CircuitPython 11, uncomment the call. + // Release secondary displays. + // common_hal_displayio_release_displays_impl(/*keep_primary*/ true); // The SPI buses used by FourWires may be allocated on the heap so we need to move them inline. for (uint8_t i = 0; i < CIRCUITPY_DISPLAY_LIMIT; i++) { From 8808458a9b401711acea7a173d4d85dcc1054160 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 8 Mar 2026 20:28:24 -0400 Subject: [PATCH 299/876] add common_hal_busio_spi_wait_for_lock() --- shared-bindings/busio/SPI.c | 23 ++++++++++++++++++----- shared-bindings/busio/SPI.h | 4 ++++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 132da473af9..39cf2516d51 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -9,16 +9,16 @@ #include +#include "py/binary.h" +#include "py/mperrno.h" +#include "py/objproperty.h" +#include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/util.h" - #include "shared/runtime/buffer_helper.h" #include "shared/runtime/context_manager_helpers.h" -#include "py/binary.h" -#include "py/mperrno.h" -#include "py/objproperty.h" -#include "py/runtime.h" +#include "supervisor/shared/tick.h" //| class SPI: @@ -494,3 +494,16 @@ MP_DEFINE_CONST_OBJ_TYPE( busio_spi_obj_t *validate_obj_is_spi_bus(mp_obj_t obj, qstr arg_name) { return mp_arg_validate_type(obj, &busio_spi_type, arg_name); } + +// Wait as long as needed for the lock. This is used by SD card access from USB. +// The default implementation is to busy-wait while running the background tasks. espressif is different. +bool common_hal_busio_spi_wait_for_lock(busio_spi_obj_t *self, uint32_t timeout_ms) { + uint64_t deadline = supervisor_ticks_ms64() + timeout_ms; + while (supervisor_ticks_ms64() < deadline) { + if (common_hal_busio_spi_try_lock(self)) { + return true; + } + RUN_BACKGROUND_TASKS; + } + return false; +} diff --git a/shared-bindings/busio/SPI.h b/shared-bindings/busio/SPI.h index 34f34c927f6..76ed697d665 100644 --- a/shared-bindings/busio/SPI.h +++ b/shared-bindings/busio/SPI.h @@ -54,3 +54,7 @@ uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self); extern void common_hal_busio_spi_never_reset(busio_spi_obj_t *self); extern busio_spi_obj_t *validate_obj_is_spi_bus(mp_obj_t obj_in, qstr arg_name); + +// Wait as long as needed for the lock. This is used by SD card access from USB. +// For most ports, busy-wait while running the background tasks. +MP_WEAK bool common_hal_busio_spi_wait_for_lock(busio_spi_obj_t *self, uint32_t timeout_ms); From 77e1fa3ed1a67c4e4e161dc562b5d66080596edb Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 8 Mar 2026 20:30:15 -0400 Subject: [PATCH 300/876] SDCard: do not return until readblocks(), writeblocks(), or sync() have completed --- shared-module/sdcardio/SDCard.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index f9b937686b7..a93736056e4 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -7,13 +7,13 @@ // This implementation largely follows the structure of adafruit_sdcard.py #include "extmod/vfs.h" -#include "esp_log.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/sdcardio/SDCard.h" #include "shared-bindings/time/__init__.h" #include "shared-bindings/util.h" #include "shared-module/sdcardio/SDCard.h" +#include "supervisor/shared/tick.h" #include "py/mperrno.h" @@ -29,6 +29,7 @@ // So let's allow a nice long time, but don't wait in a tight loop: allow background tasks to run. #define CMD_TIMEOUT_MS (500) #define TIMEOUT_MS (500) +#define SPI_TIMEOUT_MS (10000) #define R1_IDLE_STATE (1 << 0) #define R1_ILLEGAL_COMMAND (1 << 2) @@ -59,9 +60,8 @@ static bool lock_and_configure_bus(sdcardio_sdcard_obj_t *self) { if (common_hal_sdcardio_sdcard_deinited(self)) { return false; } - common_hal_sdcardio_check_for_deinit(self); - if (!common_hal_busio_spi_try_lock(self->bus)) { + if (!common_hal_busio_spi_wait_for_lock(self->bus, SPI_TIMEOUT_MS)) { return false; } @@ -268,7 +268,6 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { { bool reached_idle_state = false; for (int i = 0; i < 5; i++) { - ESP_LOGW("init_card", "loop: %d", i); // do not call cmd with wait=true, because that will return // prematurely if the idle state is not reached. we can't depend on // this when the card is not yet in SPI mode @@ -403,7 +402,7 @@ mp_uint_t sdcardio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, uint32_t st // deinit check is in lock_and_configure_bus() sdcardio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!lock_and_configure_bus(self)) { - return -MP_EAGAIN; + return -MP_ETIMEDOUT; } int r = 0; size_t buflen = 512 * nblocks; @@ -503,7 +502,7 @@ mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t s // deinit check is in lock_and_configure_bus() sdcardio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); if (!lock_and_configure_bus(self)) { - return -MP_EAGAIN; + return -MP_ETIMEDOUT; } if (!self->in_cmd25 || start_block != self->next_block) { @@ -538,7 +537,7 @@ mp_uint_t sdcardio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, uint32_t s mp_negative_errno_t common_hal_sdcardio_sdcard_sync(sdcardio_sdcard_obj_t *self) { // deinit check is in lock_and_configure_bus() if (!lock_and_configure_bus(self)) { - return -MP_EAGAIN; + return -MP_ETIMEDOUT; } int r = exit_cmd25(self); extraclock_and_unlock_bus(self); From 5cdcf88e4bef6b0c2a0a905256233e27c8c3520a Mon Sep 17 00:00:00 2001 From: "P. Patrick Socha" Date: Mon, 9 Mar 2026 18:56:10 +0100 Subject: [PATCH 301/876] Fixes after the review --- shared-module/busdisplay/BusDisplay.c | 4 ++-- shared-module/displayio/bus_core.c | 6 +----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 3626d2d2c3e..5d8d396cbb4 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -214,7 +214,7 @@ static void _send_pixels(busdisplay_busdisplay_obj_t *self, uint8_t *pixels, uin } static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_area_t *area) { - uint32_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); // In uint32_ts + uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); // In uint32_ts displayio_area_t clipped; // Clip the area to the display by overlapping the areas. If there is no overlap then we're done. @@ -223,7 +223,7 @@ static bool _refresh_area(busdisplay_busdisplay_obj_t *self, const displayio_are } uint16_t rows_per_buffer = displayio_area_height(&clipped); uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; - uint32_t pixels_per_buffer = displayio_area_size(&clipped); + uint16_t pixels_per_buffer = displayio_area_size(&clipped); uint16_t subrectangles = 1; // for SH1107 and other boundary constrained controllers diff --git a/shared-module/displayio/bus_core.c b/shared-module/displayio/bus_core.c index 6bba0065ad9..bfa61923511 100644 --- a/shared-module/displayio/bus_core.c +++ b/shared-module/displayio/bus_core.c @@ -117,7 +117,7 @@ void displayio_display_bus_end_transaction(displayio_display_bus_t *self) { self->end_transaction(self->bus); } -static void _displayio_display_bus_send_region_commands(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { +void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { uint16_t x1 = area->x1 + self->colstart; uint16_t x2 = area->x2 + self->colstart; uint16_t y1 = area->y1 + self->rowstart; @@ -235,10 +235,6 @@ static void _displayio_display_bus_send_region_commands(displayio_display_bus_t } } -void displayio_display_bus_set_region_to_update(displayio_display_bus_t *self, displayio_display_core_t *display, displayio_area_t *area) { - _displayio_display_bus_send_region_commands(self, display, area); -} - void displayio_display_bus_flush(displayio_display_bus_t *self) { if (self->flush != NULL) { self->flush(self->bus); From 8961a09a795225186ce4ccc4798dc40788eae782 Mon Sep 17 00:00:00 2001 From: Liz Date: Tue, 10 Mar 2026 10:57:49 -0400 Subject: [PATCH 302/876] Update mpconfigboard.mk to use creators vid/pid --- ports/espressif/boards/xteink_x4/mpconfigboard.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/xteink_x4/mpconfigboard.mk b/ports/espressif/boards/xteink_x4/mpconfigboard.mk index bed8b2c3fa9..f14b23b8fa0 100644 --- a/ports/espressif/boards/xteink_x4/mpconfigboard.mk +++ b/ports/espressif/boards/xteink_x4/mpconfigboard.mk @@ -1,5 +1,5 @@ -CIRCUITPY_CREATOR_ID = 0x0000303A -CIRCUITPY_CREATION_ID = 0x00001001 +CIRCUITPY_CREATOR_ID = 0x000C303C +CIRCUITPY_CREATION_ID = 0x00C30001 IDF_TARGET = esp32c3 From ef23f87a9bc1ebefe62a14bf8eb822d584bab988 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 10 Mar 2026 19:01:29 +0100 Subject: [PATCH 303/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 10 +++++++--- locale/el.po | 10 +++++++--- locale/hi.po | 10 +++++++--- locale/ko.po | 10 +++++++--- locale/ru.po | 10 +++++++--- locale/tr.po | 10 +++++++--- 6 files changed, 42 insertions(+), 18 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 1b653528f19..759d65d8760 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -110,6 +110,7 @@ msgid "%q contains duplicate pins" msgstr "%q obsahuje duplicitní piny" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q: selhání %d" @@ -872,7 +873,7 @@ msgstr "Pole souřadnic mají různé délky" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c +#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -976,6 +977,7 @@ msgstr "ECB operuje najednou pouze 16 bajtů" #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "ESP-IDF memory allocation failed" msgstr "ESP-IDF alokace paměti selhala" @@ -1259,7 +1261,8 @@ msgstr "Interní audio buffer je příliš malý" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "Interní chyba" @@ -1534,7 +1537,7 @@ msgstr "" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "Žádný %q pin" @@ -1764,6 +1767,7 @@ msgid "Operation or feature not supported" msgstr "Operace nebo funkce není podporována" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "Časový limit operace vypršel" diff --git a/locale/el.po b/locale/el.po index 74e0da7b28b..872166169db 100644 --- a/locale/el.po +++ b/locale/el.po @@ -114,6 +114,7 @@ msgid "%q contains duplicate pins" msgstr "%q περιέχει διπλότυπα pins" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q αποτυχία: %d" @@ -878,7 +879,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c +#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -984,6 +985,7 @@ msgstr "ECB δουλεύει μόνο σε 16 bytes κάθε φορά" #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "ESP-IDF memory allocation failed" msgstr "ESP-IDF δέσμευση μνήμης απέτυχε" @@ -1265,7 +1267,8 @@ msgstr "" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1540,7 +1543,7 @@ msgstr "" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "" @@ -1769,6 +1772,7 @@ msgid "Operation or feature not supported" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index f9a35f0b41b..e0bb53003d7 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -101,6 +101,7 @@ msgid "%q contains duplicate pins" msgstr "" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "" @@ -857,7 +858,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c +#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -960,6 +961,7 @@ msgstr "" #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "ESP-IDF memory allocation failed" msgstr "" @@ -1241,7 +1243,8 @@ msgstr "" msgid "Internal define error" msgstr "" -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1516,7 +1519,7 @@ msgstr "" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "" @@ -1745,6 +1748,7 @@ msgid "Operation or feature not supported" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 03c658395e0..09f4776dfde 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -112,6 +112,7 @@ msgid "%q contains duplicate pins" msgstr "%q에 중복된 핀이 포함" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q 실패: %d" @@ -901,7 +902,7 @@ msgstr "좌표 배열의 길이가 다릅니다" msgid "Coordinate arrays types have different sizes" msgstr "좌표 배열 유형은 크기가 다릅니다" -#: shared-module/usb/core/Device.c +#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1005,6 +1006,7 @@ msgstr "ECB는 한 번에 16 바이트에서만 작동합니다" #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "ESP-IDF memory allocation failed" msgstr "ESP-IDF 메모리 할당에 실패하였습니다" @@ -1292,7 +1294,8 @@ msgstr "내부 오디오 버퍼가 너무 작습니다" msgid "Internal define error" msgstr "내부 정의 오류" -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "내부 오류" @@ -1571,7 +1574,7 @@ msgstr "빠른 메모리 부족" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "%q 핀이 없습니다" @@ -1808,6 +1811,7 @@ msgid "Operation or feature not supported" msgstr "작업 또는 기능이 지원되지 않습니다" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #, fuzzy msgid "Operation timed out" msgstr "작업 시간 초과되었습니다" diff --git a/locale/ru.po b/locale/ru.po index 2beb4b1ba38..2c68943f6e4 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -114,6 +114,7 @@ msgid "%q contains duplicate pins" msgstr "%q содержит пины дупликаты" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q сбой: %d" @@ -881,7 +882,7 @@ msgstr "Координатные массивы имеют разные длин msgid "Coordinate arrays types have different sizes" msgstr "Типы массивов координат имеют разные размеры" -#: shared-module/usb/core/Device.c +#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -987,6 +988,7 @@ msgstr "ECB работает только с 16 байтами за раз" #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "ESP-IDF memory allocation failed" msgstr "Ошибка выделения памяти ESP-IDF" @@ -1280,7 +1282,8 @@ msgstr "Внутренний звуковой буфер слишком мал" msgid "Internal define error" msgstr "Внутренняя ошибка определения" -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "Внутренняя ошибка" @@ -1557,7 +1560,7 @@ msgstr "Изображение памяти" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "Нет пина %q" @@ -1790,6 +1793,7 @@ msgid "Operation or feature not supported" msgstr "Операция или функция, не поддерживаемые" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "Истекло время ожидания операции" diff --git a/locale/tr.po b/locale/tr.po index 34d654b11e4..d9d90eddfe8 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -112,6 +112,7 @@ msgid "%q contains duplicate pins" msgstr "%q yinelenen pinler içeriyor" #: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "%q failure: %d" msgstr "%q hata: %d" @@ -871,7 +872,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c +#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -974,6 +975,7 @@ msgstr "ECB aynı anda yalnızca 16 baytla çalışır" #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "ESP-IDF memory allocation failed" msgstr "" @@ -1259,7 +1261,8 @@ msgstr "Dahili ses arabelleği çok küçük" msgid "Internal define error" msgstr "Dahili tanımlama hatası" -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "Dahili hata" @@ -1535,7 +1538,7 @@ msgstr "" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "%q pini yok" @@ -1764,6 +1767,7 @@ msgid "Operation or feature not supported" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c msgid "Operation timed out" msgstr "" From 74e5edd86f693d94a9d821b761dd082423979c1f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 11 Mar 2026 12:35:39 -0400 Subject: [PATCH 304/876] wip --- ports/atmel-samd/common-hal/busio/SPI.c | 6 +++--- ports/espressif/background.c | 4 ++-- ports/espressif/supervisor/port.c | 13 +++++++++---- ports/espressif/supervisor/usb.c | 5 +++-- ports/raspberrypi/supervisor/port.c | 2 +- ports/renode/supervisor/port.c | 2 +- ports/zephyr-cp/supervisor/port.c | 6 +++++- supervisor/port.h | 14 +++++++++++--- supervisor/shared/background_callback.c | 4 ++-- supervisor/shared/port.c | 7 ++++++- supervisor/shared/safe_mode.c | 2 +- supervisor/shared/usb/usb.c | 6 +++--- supervisor/shared/web_workflow/web_workflow.c | 2 +- 13 files changed, 48 insertions(+), 25 deletions(-) diff --git a/ports/atmel-samd/common-hal/busio/SPI.c b/ports/atmel-samd/common-hal/busio/SPI.c index fe53580afdf..19fd81e425d 100644 --- a/ports/atmel-samd/common-hal/busio/SPI.c +++ b/ports/atmel-samd/common-hal/busio/SPI.c @@ -194,14 +194,14 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { } allow_reset_sercom(self->spi_desc.dev.prvt); - // Mark as deinit early in case we are used in an interrupt. - common_hal_busio_spi_mark_deinit(self); - spi_m_sync_disable(&self->spi_desc); spi_m_sync_deinit(&self->spi_desc); reset_pin_number(self->clock_pin); reset_pin_number(self->MOSI_pin); reset_pin_number(self->MISO_pin); + + // This smashes self->clock_pin, so don't do it before resetting the pin above. + common_hal_busio_spi_mark_deinit(self); } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, diff --git a/ports/espressif/background.c b/ports/espressif/background.c index 61615c01615..b1b81ac2c83 100644 --- a/ports/espressif/background.c +++ b/ports/espressif/background.c @@ -13,8 +13,8 @@ #include "freertos/task.h" void port_background_tick(void) { - // Zero delay in case FreeRTOS wants to switch to something else. - vTaskDelay(0); + // Yield with zero delay in case FreeRTOS wants to switch to something else. + port_task_yield(); } void port_background_task(void) { diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 46914330798..b3045026e12 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -404,8 +404,8 @@ void reset_port(void) { watchdog_reset(); #endif - // Yield so the idle task can run and do any IDF cleanup needed. - port_yield(); + // Yield so the idle task, at priority 0, can run and do any IDF cleanup needed. + port_task_sleep_ms(4); } void reset_to_bootloader(void) { @@ -483,8 +483,13 @@ void port_wake_main_task_from_isr(void) { } } -void port_yield(void) { - vTaskDelay(4); +// Yield to other tasks at the same priority. +void port_task_yield(void) { + vTaskDelay(0); +} + +void port_task_sleep_ms(uint32_t msecs) { + vTaskDelay(pdMS_TO_TICKS(msecs)); } void sleep_timer_cb(void *arg) { diff --git a/ports/espressif/supervisor/usb.c b/ports/espressif/supervisor/usb.c index 62feea6981e..e4d34ee7694 100644 --- a/ports/espressif/supervisor/usb.c +++ b/ports/espressif/supervisor/usb.c @@ -56,7 +56,8 @@ static void usb_device_task(void *param) { tud_task(); tud_cdc_write_flush(); } - vTaskDelay(1); + // Yield with zero delay to switch to any other tasks at same priority. + port_task_yield(); } } #endif // CIRCUITPY_USB_DEVICE @@ -112,7 +113,7 @@ void init_usb_hardware(void) { "usbd", USBD_STACK_SIZE, NULL, - 5, + 1, usb_device_stack, &usb_device_taskdef, xPortGetCoreID()); diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 5cfbdfa66a3..bb6482240a6 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -600,7 +600,7 @@ __attribute__((used)) void __not_in_flash_func(isr_hardfault)(void) { } } -void port_yield(void) { +void port_task_yield(void) { #if CIRCUITPY_CYW43 cyw43_arch_poll(); #endif diff --git a/ports/renode/supervisor/port.c b/ports/renode/supervisor/port.c index d12ebd2efdd..a40e222d34d 100644 --- a/ports/renode/supervisor/port.c +++ b/ports/renode/supervisor/port.c @@ -210,7 +210,7 @@ __attribute__((used)) void HardFault_Handler(void) { } } -void port_yield(void) { +void port_task_yield(void) { } void port_boot_info(void) { diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 7be2beb1d20..ff194fcbc8d 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -65,7 +65,7 @@ void port_wake_main_task_from_isr(void) { k_event_set(&main_needed, 1); } -void port_yield(void) { +void port_task_yield(void) { k_yield(); // Make sure time advances in the simulator. #if defined(CONFIG_ARCH_POSIX) @@ -73,6 +73,10 @@ void port_yield(void) { #endif } +void port_task_sleep_ms(uint32_t msecs) { + k_msleep(msecs)); +} + void port_boot_info(void) { } diff --git a/supervisor/port.h b/supervisor/port.h index 192307a5f57..7e2463032f7 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -92,9 +92,17 @@ void port_wake_main_task(void); void port_wake_main_task_from_isr(void); // Some ports may use real RTOS tasks besides the background task framework of -// CircuitPython. Calling this will yield to other tasks and then return to the -// CircuitPython task when others are done. -void port_yield(void); +// CircuitPython. Calling this will yield to other tasks at the same priority level +// (or higher priority level if pre-emption is not immediate in the RTOS) +// and then return to the CircuitPython task when others are done. +// Note that this does NOT yield to lower priority tasks. Use port_task_sleep_ms() instead. +void port_task_yield(void); + +// On ports using real RTOS tasks, yield to other tasks for at least msecs. +// This will allow lower priority tasks to run. +// On non-RTOS implementations, this just sleeps for msecs and will run CircuitPython +// background tasks. +void port_task_sleep_ms(uint32_t msecs); // Some ports want to add information to boot_out.txt. // A default weak implementation is provided that does nothing. diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c index 79b18f7a137..afb55446961 100644 --- a/supervisor/shared/background_callback.c +++ b/supervisor/shared/background_callback.c @@ -63,7 +63,7 @@ void PLACE_IN_ITCM(background_callback_run_all)(void) { if (!background_callback_pending()) { // TEMPORARY to fix #10822 #ifdef __ZEPHYR__ - port_yield(); + port_task_yield(); #endif return; } @@ -93,7 +93,7 @@ void PLACE_IN_ITCM(background_callback_run_all)(void) { CALLBACK_CRITICAL_END; // TEMPORARY to fix #10822 #ifdef __ZEPHYR__ - port_yield(); + port_task_yield(); #endif } diff --git a/supervisor/shared/port.c b/supervisor/shared/port.c index f908e3f0bd8..3c95f2b7409 100644 --- a/supervisor/shared/port.c +++ b/supervisor/shared/port.c @@ -8,6 +8,7 @@ #include +#include "py/mphal.h" #include "py/runtime.h" #include "py/gc.h" @@ -26,7 +27,11 @@ MP_WEAK void port_wake_main_task(void) { MP_WEAK void port_wake_main_task_from_isr(void) { } -MP_WEAK void port_yield(void) { +MP_WEAK void port_task_yield(void) { +} + +MP_WEAK void port_task_sleep_ms(uint32_t msecs) { + mp_hal_delay_ms(msecs); } MP_WEAK void port_boot_info(void) { diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index bfe27ac7c65..d697cad6756 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -84,7 +84,7 @@ safe_mode_t wait_for_safe_mode_reset(void) { } // TEMPORARY to fix #10822 #ifdef __ZEPHYR__ - port_yield(); + port_task_yield(); #endif diff = supervisor_ticks_ms64() - start_ticks; } diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index fbe8be97882..5061fee0063 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -7,6 +7,7 @@ #include "py/objstr.h" #include "supervisor/background_callback.h" #include "supervisor/linker.h" +#include "supervisor/port.h" #include "supervisor/shared/tick.h" #include "supervisor/usb.h" #include "shared/readline/readline.h" @@ -160,9 +161,8 @@ void usb_background(void) { tuh_task(); #endif #elif CFG_TUSB_OS == OPT_OS_FREERTOS - // Yield to FreeRTOS in case TinyUSB runs in a separate task. Don't use - // port_yield() because it has a longer delay. - vTaskDelay(0); + // TinyUSB may run in a separate task, at the same priority as CircuitPython. + port_task_yield(); #endif // No need to flush if there's no REPL. #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_CDC diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index 553fe8694c6..10c0239ec5c 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -373,7 +373,7 @@ void web_workflow_send_raw(socketpool_socket_obj_t *socket, bool flush, const ui total_sent += sent; if (total_sent < len) { // Yield so that network code can run. - port_yield(); + port_task_sleep_ms(4); } } } From ac38142a90ac3bba013a8e1bdd1e05e509a11e26 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 12 Mar 2026 11:37:20 -0500 Subject: [PATCH 305/876] add type validation for Bitmaps in bitmaptools --- shared-bindings/bitmaptools/__init__.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index f3aad1b67b0..4d56f393189 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -206,9 +206,9 @@ static mp_obj_t bitmaptools_obj_rotozoom(size_t n_args, const mp_obj_t *pos_args mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap - displayio_bitmap_t *source = MP_OBJ_TO_PTR(args[ARG_source_bitmap].u_obj); // the source bitmap + displayio_bitmap_t *source = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_source_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_source_bitmap)); // the source bitmap // ensure that the destination bitmap has at least as many `bits_per_value` as the source if (destination->bits_per_value < source->bits_per_value) { @@ -485,7 +485,7 @@ static mp_obj_t bitmaptools_obj_fill_region(size_t n_args, const mp_obj_t *pos_a mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap uint32_t value, color_depth; value = args[ARG_value].u_int; @@ -598,7 +598,7 @@ static mp_obj_t bitmaptools_obj_draw_line(size_t n_args, const mp_obj_t *pos_arg mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap uint32_t value, color_depth; value = args[ARG_value].u_int; @@ -684,7 +684,7 @@ static mp_obj_t bitmaptools_obj_draw_polygon(size_t n_args, const mp_obj_t *pos_ mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap mp_buffer_info_t xs_buf, ys_buf; mp_get_buffer_raise(args[ARG_xs].u_obj, &xs_buf, MP_BUFFER_READ); @@ -1017,7 +1017,7 @@ static mp_obj_t bitmaptools_obj_draw_circle(size_t n_args, const mp_obj_t *pos_a mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - displayio_bitmap_t *destination = MP_OBJ_TO_PTR(args[ARG_dest_bitmap].u_obj); // the destination bitmap + displayio_bitmap_t *destination = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_dest_bitmap].u_obj, &displayio_bitmap_type, MP_QSTR_dest_bitmap)); // the destination bitmap uint32_t value, color_depth; value = args[ARG_value].u_int; From 5bec6a617cc91db7bb58b0fc77bda65616316580 Mon Sep 17 00:00:00 2001 From: Liz Date: Thu, 12 Mar 2026 12:57:01 -0400 Subject: [PATCH 306/876] update creators id --- ports/espressif/boards/xteink_x4/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/xteink_x4/mpconfigboard.mk b/ports/espressif/boards/xteink_x4/mpconfigboard.mk index f14b23b8fa0..8668aad1818 100644 --- a/ports/espressif/boards/xteink_x4/mpconfigboard.mk +++ b/ports/espressif/boards/xteink_x4/mpconfigboard.mk @@ -1,4 +1,4 @@ -CIRCUITPY_CREATOR_ID = 0x000C303C +CIRCUITPY_CREATOR_ID = 0x0EEE0000 CIRCUITPY_CREATION_ID = 0x00C30001 IDF_TARGET = esp32c3 From 236dec029c2c13ab0c72fcfb4acaefb9110b3dac Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 12 Mar 2026 20:45:28 -0400 Subject: [PATCH 307/876] shorten SDCard SPI timeouts, which were freezing out ESP32SPI access; remove RUN_BACKGROUND_TASKS in SDCard --- .../adafruit_metro_esp32s3/mpconfigboard.mk | 2 -- shared-bindings/busio/SPI.c | 5 +-- shared-module/sdcardio/SDCard.c | 34 +++++++++---------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk b/ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk index 57ccf4a4074..2fd5a40f259 100644 --- a/ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_metro_esp32s3/mpconfigboard.mk @@ -12,5 +12,3 @@ CIRCUITPY_ESP_FLASH_SIZE = 16MB CIRCUITPY_ESP_PSRAM_MODE = opi CIRCUITPY_ESP_PSRAM_FREQ = 80m CIRCUITPY_ESP_PSRAM_SIZE = 8MB - -CIRCUITPY_ULAB = 0 diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 39cf2516d51..962080648ce 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -18,9 +18,9 @@ #include "shared-bindings/util.h" #include "shared/runtime/buffer_helper.h" #include "shared/runtime/context_manager_helpers.h" +#include "shared/runtime/interrupt_char.h" #include "supervisor/shared/tick.h" - //| class SPI: //| """A 3-4 wire serial protocol //| @@ -499,7 +499,8 @@ busio_spi_obj_t *validate_obj_is_spi_bus(mp_obj_t obj, qstr arg_name) { // The default implementation is to busy-wait while running the background tasks. espressif is different. bool common_hal_busio_spi_wait_for_lock(busio_spi_obj_t *self, uint32_t timeout_ms) { uint64_t deadline = supervisor_ticks_ms64() + timeout_ms; - while (supervisor_ticks_ms64() < deadline) { + while (supervisor_ticks_ms64() < deadline && + !mp_hal_is_interrupted()) { if (common_hal_busio_spi_try_lock(self)) { return true; } diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index a93736056e4..3af4c89a1c3 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -16,6 +16,7 @@ #include "supervisor/shared/tick.h" #include "py/mperrno.h" +#include "py/mphal.h" #if 0 #define DEBUG_PRINT(...) ((void)mp_printf(&mp_plat_print,##__VA_ARGS__)) @@ -23,13 +24,16 @@ #define DEBUG_PRINT(...) ((void)0) #endif +// https://nodeloop.org/guides/sd-card-spi-init-guide/ is an excellent source of info for SPI card use. + // https://www.taterli.com/wp-content/uploads/2017/05/Physical-Layer-Simplified-SpecificationV6.0.pdf // specifies timeouts for read (100 ms), write (250 ms), erase (depends on size), and other operations. // But the document also suggests allowing 500 ms even if a shorter timeout is specified. -// So let's allow a nice long time, but don't wait in a tight loop: allow background tasks to run. -#define CMD_TIMEOUT_MS (500) -#define TIMEOUT_MS (500) -#define SPI_TIMEOUT_MS (10000) +#define CMD_TIMEOUT_MS (250) +#define SPI_TIMEOUT_MS (250) +// Init ready timeout. +#define READY_TIMEOUT_MS (300) + #define R1_IDLE_STATE (1 << 0) #define R1_ILLEGAL_COMMAND (1 << 2) @@ -84,11 +88,10 @@ static void lock_bus_or_throw(sdcardio_sdcard_obj_t *self) { } static void clock_card(sdcardio_sdcard_obj_t *self, int bytes) { - uint8_t buf[] = {0xff}; + uint8_t buf[bytes]; + memset(buf, 0xff, bytes); common_hal_digitalio_digitalinout_set_value(&self->cs, true); - for (int i = 0; i < bytes; i++) { - common_hal_busio_spi_write(self->bus, buf, 1); - } + common_hal_busio_spi_write(self->bus, buf, bytes); } static void extraclock_and_unlock_bus(sdcardio_sdcard_obj_t *self) { @@ -124,19 +127,16 @@ static int32_t wait_for_masked_response(sdcardio_sdcard_obj_t *self, uint8_t mas if (((b & mask) == response) ^ not_match) { return b; } - RUN_BACKGROUND_TASKS; } return -1; } // Wait for the given response byte. static bool wait_for_response(sdcardio_sdcard_obj_t *self, uint8_t response) { - return wait_for_masked_response(self, 0xff, response, false, TIMEOUT_MS) != -1; + return wait_for_masked_response(self, 0xff, response, false, CMD_TIMEOUT_MS) != -1; } -#define READY_TIMEOUT_MS (300) - -// Wait for 0xff, with a shorter timeout. +// Wait for 0xff, with a specific timeout. static bool wait_for_ready(sdcardio_sdcard_obj_t *self) { return wait_for_masked_response(self, 0xff, 0xff, false, READY_TIMEOUT_MS) != -1; } @@ -232,7 +232,6 @@ static mp_rom_error_text_t init_card_v1(sdcardio_sdcard_obj_t *self) { if (cmd(self, 41, 0, NULL, 0, true, true) == 0) { return NULL; } - RUN_BACKGROUND_TASKS; } return MP_ERROR_TEXT("timeout waiting for v1 card"); } @@ -251,12 +250,13 @@ static mp_rom_error_text_t init_card_v2(sdcardio_sdcard_obj_t *self) { } return NULL; } - RUN_BACKGROUND_TASKS; } return MP_ERROR_TEXT("timeout waiting for v2 card"); } static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { + // https://nodeloop.org/guides/sd-card-spi-init-guide/ recommends at least 74 bit clocks + // and says 80 bit clocks(10*8) is common. Value below is bytes, not bits. clock_card(self, 10); common_hal_digitalio_digitalinout_set_value(&self->cs, false); @@ -476,7 +476,6 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t uint64_t deadline = supervisor_ticks_ms64() + CMD_TIMEOUT_MS; while (supervisor_ticks_ms64() < deadline) { common_hal_busio_spi_read(self->bus, cmd, 1, 0xff); - DEBUG_PRINT("i=%02d cmd[0] = 0x%02x\n", i, cmd[0]); if ((cmd[0] & 0b00010001) == 0b00000001) { if ((cmd[0] & 0x1f) != 0x5) { return -MP_EIO; @@ -484,13 +483,12 @@ static int _write(sdcardio_sdcard_obj_t *self, uint8_t token, void *buf, size_t break; } } - RUN_BACKGROUND_TASKS; } // Wait for the write to finish // Wait for a non-zero value. - if (wait_for_masked_response(self, 0xff /*mask*/, 0, true /*not_match*/, TIMEOUT_MS) == -1) { + if (wait_for_masked_response(self, 0xff /*mask*/, 0, true /*not_match*/, CMD_TIMEOUT_MS) == -1) { return -MP_EIO; } From c7b687d8b3a1a90247db1e8b5a0ffe39321d19f3 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 17 Mar 2026 16:24:41 -0500 Subject: [PATCH 308/876] fix return type --- shared-bindings/busio/I2C.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/busio/I2C.c b/shared-bindings/busio/I2C.c index c93566c0b62..5fa62f9df38 100644 --- a/shared-bindings/busio/I2C.c +++ b/shared-bindings/busio/I2C.c @@ -112,7 +112,7 @@ static void check_lock(busio_i2c_obj_t *self) { } } -//| def probe(self, address: int) -> List[int]: +//| def probe(self, address: int) -> bool: //| """Check if a device at the specified address responds. //| //| :param int address: 7-bit device address From 9dc83288f444a2f2a3d4cec67b5cddc2e8545d80 Mon Sep 17 00:00:00 2001 From: Kong Wai Weng Date: Thu, 19 Mar 2026 17:41:05 +0800 Subject: [PATCH 309/876] Added pin definitions for GP29. --- ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c b/ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c index 53fae76ac1b..dbfc713930b 100644 --- a/ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c +++ b/ports/raspberrypi/boards/cytron_maker_pi_rp2040/pins.c @@ -62,6 +62,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP29_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VBATT), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO29) }, From 0d6017538c7f4abc839a29c5f1d48c27209db0ea Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 17 Feb 2026 10:09:52 -0800 Subject: [PATCH 310/876] Add support for fixed Zephyr displays This adds zephyr_display. It acts similar to BusDisplay because we write regions to update to Zephyr. --- .../actions/deps/ports/zephyr-cp/action.yml | 11 +- AGENTS.md | 1 + locale/circuitpython.pot | 36 +- ports/zephyr-cp/AGENTS.md | 1 + ports/zephyr-cp/CLAUDE.md | 1 + ports/zephyr-cp/Makefile | 28 +- ports/zephyr-cp/README.md | 30 ++ .../bindings/zephyr_display/Display.c | 195 ++++++++ .../bindings/zephyr_display/Display.h | 37 ++ .../bindings/zephyr_display/__init__.c | 24 + .../bindings/zephyr_display/__init__.h | 7 + .../autogen_board_info.toml | 1 + ports/zephyr-cp/boards/board_aliases.cmake | 1 + ports/zephyr-cp/boards/ek_ra8d1.conf | 3 + .../native/native_sim/autogen_board_info.toml | 3 +- .../nrf5340bsim/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/native_sim.conf | 4 + .../nordic/nrf5340dk/autogen_board_info.toml | 1 + .../nordic/nrf54h20dk/autogen_board_info.toml | 1 + .../nordic/nrf54l15dk/autogen_board_info.toml | 1 + .../nordic/nrf7002dk/autogen_board_info.toml | 1 + .../nxp/frdm_mcxn947/autogen_board_info.toml | 1 + .../nxp/frdm_rw612/autogen_board_info.toml | 1 + .../mimxrt1170_evk/autogen_board_info.toml | 1 + .../da14695_dk_usb/autogen_board_info.toml | 1 + .../renesas/ek_ra6m5/autogen_board_info.toml | 1 + .../renesas/ek_ra8d1/autogen_board_info.toml | 3 +- .../renesas/ek_ra8d1/circuitpython.toml | 1 + .../nucleo_n657x0_q/autogen_board_info.toml | 1 + .../nucleo_u575zi_q/autogen_board_info.toml | 1 + .../st/stm32h750b_dk/autogen_board_info.toml | 118 +++++ .../st/stm32h750b_dk/circuitpython.toml | 1 + .../st/stm32h7b3i_dk/autogen_board_info.toml | 5 +- .../stm32wba65i_dk1/autogen_board_info.toml | 1 + ...m32h750b_dk_stm32h750xx_ext_flash_app.conf | 2 + ...h750b_dk_stm32h750xx_ext_flash_app.overlay | 14 + ports/zephyr-cp/boards/stm32h7b3i_dk.conf | 2 + ports/zephyr-cp/boards/stm32h7b3i_dk.overlay | 22 + .../common-hal/zephyr_display/Display.c | 440 ++++++++++++++++++ .../common-hal/zephyr_display/Display.h | 31 ++ ports/zephyr-cp/cptools/board_tools.py | 27 ++ .../zephyr-cp/cptools/build_circuitpython.py | 3 + .../zephyr-cp/cptools/get_west_shield_args.py | 70 +++ .../cptools/pre_zephyr_build_prep.py | 8 +- ports/zephyr-cp/cptools/zephyr2cp.py | 48 ++ ports/zephyr-cp/debug.conf | 15 + ports/zephyr-cp/tests/__init__.py | 10 + .../tests/bsim/test_bsim_ble_scan.py | 2 +- ports/zephyr-cp/tests/conftest.py | 153 ++++-- ports/zephyr-cp/tests/perfetto_input_trace.py | 85 ++-- .../zephyr-cp/tests/zephyr_display/README.md | 45 ++ .../golden/color_gradient_320x240.png | Bin 0 -> 12102 bytes .../golden/color_gradient_320x240_AL_88.png | Bin 0 -> 17323 bytes .../color_gradient_320x240_ARGB_8888.png | Bin 0 -> 1024 bytes .../golden/color_gradient_320x240_BGR_565.png | Bin 0 -> 12102 bytes .../golden/color_gradient_320x240_L_8.png | Bin 0 -> 17323 bytes .../golden/color_gradient_320x240_MONO01.png | Bin 0 -> 1516 bytes .../golden/color_gradient_320x240_MONO10.png | Bin 0 -> 1516 bytes .../golden/color_gradient_320x240_RGB_565.png | Bin 0 -> 12102 bytes .../golden/color_gradient_320x240_RGB_888.png | Bin 0 -> 15287 bytes .../terminal_console_output_320x240.mask.png | Bin 0 -> 450 bytes .../terminal_console_output_320x240.png | Bin 0 -> 3930 bytes .../terminal_console_output_320x240_AL_88.png | Bin 0 -> 3900 bytes ...minal_console_output_320x240_ARGB_8888.png | Bin 0 -> 1024 bytes ...erminal_console_output_320x240_BGR_565.png | Bin 0 -> 3930 bytes .../terminal_console_output_320x240_L_8.png | Bin 0 -> 3900 bytes ...terminal_console_output_320x240_MONO01.png | Bin 0 -> 3655 bytes ...onsole_output_320x240_MONO01_no_vtiled.png | Bin 0 -> 3655 bytes ...terminal_console_output_320x240_MONO10.png | Bin 0 -> 3655 bytes ...onsole_output_320x240_MONO10_no_vtiled.png | Bin 0 -> 3655 bytes ...erminal_console_output_320x240_RGB_565.png | Bin 0 -> 3930 bytes ...erminal_console_output_320x240_RGB_888.png | Bin 0 -> 3930 bytes .../zephyr_display/test_zephyr_display.py | 365 +++++++++++++++ ports/zephyr-cp/zephyr-config/west.yml | 2 +- py/circuitpy_mpconfig.mk | 3 + shared-module/displayio/__init__.c | 19 + shared-module/displayio/__init__.h | 6 + 77 files changed, 1799 insertions(+), 97 deletions(-) create mode 100644 ports/zephyr-cp/CLAUDE.md create mode 100644 ports/zephyr-cp/bindings/zephyr_display/Display.c create mode 100644 ports/zephyr-cp/bindings/zephyr_display/Display.h create mode 100644 ports/zephyr-cp/bindings/zephyr_display/__init__.c create mode 100644 ports/zephyr-cp/bindings/zephyr_display/__init__.h create mode 100644 ports/zephyr-cp/boards/ek_ra8d1.conf create mode 100644 ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/st/stm32h750b_dk/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.conf create mode 100644 ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay create mode 100644 ports/zephyr-cp/boards/stm32h7b3i_dk.conf create mode 100644 ports/zephyr-cp/common-hal/zephyr_display/Display.c create mode 100644 ports/zephyr-cp/common-hal/zephyr_display/Display.h create mode 100644 ports/zephyr-cp/cptools/get_west_shield_args.py create mode 100644 ports/zephyr-cp/debug.conf create mode 100644 ports/zephyr-cp/tests/zephyr_display/README.md create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_AL_88.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_ARGB_8888.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_BGR_565.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_L_8.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_MONO01.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_MONO10.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_565.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_888.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.mask.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_AL_88.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_ARGB_8888.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_BGR_565.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_L_8.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01_no_vtiled.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10_no_vtiled.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_565.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_888.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py diff --git a/.github/actions/deps/ports/zephyr-cp/action.yml b/.github/actions/deps/ports/zephyr-cp/action.yml index 5f52cc7f0c2..6c538e3fa57 100644 --- a/.github/actions/deps/ports/zephyr-cp/action.yml +++ b/.github/actions/deps/ports/zephyr-cp/action.yml @@ -3,11 +3,18 @@ name: Fetch Zephyr port deps runs: using: composite steps: - - name: Get libusb and mtools + - name: Get Linux build dependencies if: runner.os == 'Linux' run: | + echo "--- cpu model ---" + grep "model name" /proc/cpuinfo | head -1 + sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y libusb-1.0-0-dev libudev-dev mtools + sudo apt-get install -y libusb-1.0-0-dev libudev-dev pkg-config mtools + # We have to hold python3 so the following install works. See https://github.com/actions/runner-images/issues/13803 + sudo apt-mark hold python3 + sudo apt-get install -y libsdl2-dev:i386 libsdl2-image-dev:i386 + echo "PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH}" >> $GITHUB_ENV shell: bash - name: Setup Zephyr project uses: zephyrproject-rtos/action-zephyr-setup@v1 diff --git a/AGENTS.md b/AGENTS.md index 145e31c1271..e7d2fdbbe8c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,3 +1,4 @@ - Capture CircuitPython output by finding the matching device in `/dev/serial/by-id` - You can mount the CIRCUITPY drive by doing `udisksctl mount -b /dev/disk/by-label/CIRCUITPY` and access it via `/run/media//CIRCUITPY`. - `circup` is a command line tool to install libraries and examples to CIRCUITPY. +- When connecting to serial devices on Linux use /dev/serial/by-id. These will be more stable than /dev/ttyACM*. diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index bf4c5d110f6..08196993c36 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -113,6 +113,7 @@ msgstr "" #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -135,6 +136,7 @@ msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" msgstr "" @@ -166,8 +168,8 @@ msgstr "" msgid "%q must be %d" msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/is31fl3741/FrameBuffer.c #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -459,6 +461,7 @@ msgstr "" msgid ", in %q\n" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -647,6 +650,7 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -669,6 +673,7 @@ msgstr "" msgid "Both RX and TX required for flow control" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid "Brightness not adjustable" @@ -856,8 +861,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1023,10 +1027,6 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c #: ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -1144,6 +1144,7 @@ msgstr "" msgid "Generic Failure" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -1242,8 +1243,8 @@ msgstr "" msgid "Internal define error" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c msgid "Internal error" msgstr "" @@ -1518,8 +1519,7 @@ msgstr "" #: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c #: shared-bindings/i2cdisplaybus/I2CDisplayBus.c #: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c -#: shared-module/bitbangio/SPI.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c msgid "No %q pin" msgstr "" @@ -3237,10 +3237,6 @@ msgstr "" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3322,10 +3318,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -4047,10 +4039,6 @@ msgstr "" msgid "pack expected %d items for packing (got %d)" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" diff --git a/ports/zephyr-cp/AGENTS.md b/ports/zephyr-cp/AGENTS.md index 47813886804..58a3912e2ba 100644 --- a/ports/zephyr-cp/AGENTS.md +++ b/ports/zephyr-cp/AGENTS.md @@ -4,3 +4,4 @@ - To flash it on a board do `make BOARD=_ flash`. - Zephyr board docs are at `zephyr/boards//`. - Run zephyr-cp tests with `make test`. +- Do not add new translatable error strings (`MP_ERROR_TEXT`). Instead, use `raise_zephyr_error()` or `CHECK_ZEPHYR_RESULT()` from `bindings/zephyr_kernel/__init__.h` to convert Zephyr errno values into Python exceptions. diff --git a/ports/zephyr-cp/CLAUDE.md b/ports/zephyr-cp/CLAUDE.md new file mode 100644 index 00000000000..43c994c2d36 --- /dev/null +++ b/ports/zephyr-cp/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index 5e905701668..ae1260c0f4d 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -8,13 +8,24 @@ BUILD ?= build-$(BOARD) TRANSLATION ?= en_US -.DEFAULT_GOAL := $(BUILD)/zephyr-cp/zephyr/zephyr.elf +# Compute shield args once. Command-line SHIELD/SHIELDS values override board defaults from circuitpython.toml. +ifneq ($(strip $(BOARD)),) +WEST_SHIELD_ARGS := $(shell SHIELD_ORIGIN="$(origin SHIELD)" SHIELDS_ORIGIN="$(origin SHIELDS)" SHIELD="$(SHIELD)" SHIELDS="$(SHIELDS)" python cptools/get_west_shield_args.py $(BOARD)) +endif -.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug run run-sim clean menuconfig all clean-all test fetch-port-submodules +WEST_CMAKE_ARGS := -DZEPHYR_BOARD_ALIASES=$(CURDIR)/boards/board_aliases.cmake -Dzephyr-cp_TRANSLATION=$(TRANSLATION) + +# When DEBUG=1, apply additional Kconfig fragments for debug-friendly settings. +DEBUG_CONF_FILE ?= $(CURDIR)/debug.conf +ifeq ($(DEBUG),1) +WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_CONF_FILE=$(DEBUG_CONF_FILE) +endif + +.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug debug-jlink debugserver attach run run-sim clean menuconfig all clean-all test fetch-port-submodules $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) - west build -b $(BOARD) -d $(BUILD) --sysbuild -- -DZEPHYR_BOARD_ALIASES=$(CURDIR)/boards/board_aliases.cmake -Dzephyr-cp_TRANSLATION=$(TRANSLATION) + west build -b $(BOARD) -d $(BUILD) $(WEST_SHIELD_ARGS) --sysbuild -- $(WEST_CMAKE_ARGS) $(BUILD)/firmware.elf: $(BUILD)/zephyr-cp/zephyr/zephyr.elf cp $^ $@ @@ -37,6 +48,15 @@ recover: $(BUILD)/zephyr-cp/zephyr/zephyr.elf debug: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west debug -d $(BUILD) +debug-jlink: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + west debug --runner jlink -d $(BUILD) + +debugserver: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + west debugserver -d $(BUILD) + +attach: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + west attach -d $(BUILD) + run: $(BUILD)/firmware.exe $^ @@ -51,7 +71,7 @@ run-sim: build-native_native_sim/firmware.exe --flash=build-native_native_sim/flash.bin --flash_rm -wait_uart -rt menuconfig: - west build --sysbuild -d $(BUILD) -t menuconfig + west build $(WEST_SHIELD_ARGS) --sysbuild -d $(BUILD) -t menuconfig -- $(WEST_CMAKE_ARGS) clean: rm -rf $(BUILD) diff --git a/ports/zephyr-cp/README.md b/ports/zephyr-cp/README.md index f4391fc4cb6..28bbfbf2984 100644 --- a/ports/zephyr-cp/README.md +++ b/ports/zephyr-cp/README.md @@ -42,6 +42,36 @@ If a local `./CIRCUITPY/` folder exists, its files are used as the simulator's C Edit files in `./CIRCUITPY` (for example `code.py`) and rerun `make run-sim` to test changes. +## Shields + +Board defaults can be set in `boards///circuitpython.toml`: + +```toml +SHIELDS = ["shield1", "shield2"] +``` + +For example, `boards/renesas/ek_ra8d1/circuitpython.toml` enables: + +```toml +SHIELDS = ["rtkmipilcdb00000be"] +``` + +You can override shield selection from the command line: + +```sh +# Single shield +make BOARD=renesas_ek_ra8d1 SHIELD=rtkmipilcdb00000be + +# Multiple shields (comma, semicolon, or space separated) +make BOARD=my_vendor_my_board SHIELDS="shield1,shield2" +``` + +Behavior and precedence: + +- If `SHIELD` or `SHIELDS` is explicitly provided, it overrides board defaults. +- If neither is provided, defaults from `circuitpython.toml` are used. +- Use `SHIELD=` (empty) to disable a board default shield for one build. + ## Testing other boards [Any Zephyr board](https://docs.zephyrproject.org/latest/boards/index.html#) can diff --git a/ports/zephyr-cp/bindings/zephyr_display/Display.c b/ports/zephyr-cp/bindings/zephyr_display/Display.c new file mode 100644 index 00000000000..0923618c50a --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_display/Display.c @@ -0,0 +1,195 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/zephyr_display/Display.h" + +#include "py/objproperty.h" +#include "py/objtype.h" +#include "py/runtime.h" +#include "shared-bindings/displayio/Group.h" +#include "shared-module/displayio/__init__.h" + +static mp_obj_t zephyr_display_display_make_new(const mp_obj_type_t *type, + size_t n_args, + size_t n_kw, + const mp_obj_t *all_args) { + (void)type; + (void)n_args; + (void)n_kw; + (void)all_args; + mp_raise_NotImplementedError(NULL); + return mp_const_none; +} + +static zephyr_display_display_obj_t *native_display(mp_obj_t display_obj) { + mp_obj_t native = mp_obj_cast_to_native_base(display_obj, &zephyr_display_display_type); + mp_obj_assert_native_inited(native); + return MP_OBJ_TO_PTR(native); +} + +static mp_obj_t zephyr_display_display_obj_show(mp_obj_t self_in, mp_obj_t group_in) { + (void)self_in; + (void)group_in; + mp_raise_AttributeError(MP_ERROR_TEXT(".show(x) removed. Use .root_group = x")); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_show_obj, zephyr_display_display_obj_show); + +static mp_obj_t zephyr_display_display_obj_refresh(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { + ARG_target_frames_per_second, + ARG_minimum_frames_per_second, + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_target_frames_per_second, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, + { MP_QSTR_minimum_frames_per_second, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + zephyr_display_display_obj_t *self = native_display(pos_args[0]); + + uint32_t maximum_ms_per_real_frame = NO_FPS_LIMIT; + mp_int_t minimum_frames_per_second = args[ARG_minimum_frames_per_second].u_int; + if (minimum_frames_per_second > 0) { + maximum_ms_per_real_frame = 1000 / minimum_frames_per_second; + } + + uint32_t target_ms_per_frame; + if (args[ARG_target_frames_per_second].u_obj == mp_const_none) { + target_ms_per_frame = NO_FPS_LIMIT; + } else { + target_ms_per_frame = 1000 / mp_obj_get_int(args[ARG_target_frames_per_second].u_obj); + } + + return mp_obj_new_bool(common_hal_zephyr_display_display_refresh( + self, + target_ms_per_frame, + maximum_ms_per_real_frame)); +} +MP_DEFINE_CONST_FUN_OBJ_KW(zephyr_display_display_refresh_obj, 1, zephyr_display_display_obj_refresh); + +static mp_obj_t zephyr_display_display_obj_get_auto_refresh(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return mp_obj_new_bool(common_hal_zephyr_display_display_get_auto_refresh(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_auto_refresh_obj, zephyr_display_display_obj_get_auto_refresh); + +static mp_obj_t zephyr_display_display_obj_set_auto_refresh(mp_obj_t self_in, mp_obj_t auto_refresh) { + zephyr_display_display_obj_t *self = native_display(self_in); + common_hal_zephyr_display_display_set_auto_refresh(self, mp_obj_is_true(auto_refresh)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_set_auto_refresh_obj, zephyr_display_display_obj_set_auto_refresh); + +MP_PROPERTY_GETSET(zephyr_display_display_auto_refresh_obj, + (mp_obj_t)&zephyr_display_display_get_auto_refresh_obj, + (mp_obj_t)&zephyr_display_display_set_auto_refresh_obj); + +static mp_obj_t zephyr_display_display_obj_get_brightness(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + mp_float_t brightness = common_hal_zephyr_display_display_get_brightness(self); + if (brightness < 0) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Brightness not adjustable")); + } + return mp_obj_new_float(brightness); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_brightness_obj, zephyr_display_display_obj_get_brightness); + +static mp_obj_t zephyr_display_display_obj_set_brightness(mp_obj_t self_in, mp_obj_t brightness_obj) { + zephyr_display_display_obj_t *self = native_display(self_in); + mp_float_t brightness = mp_obj_get_float(brightness_obj); + if (brightness < 0.0f || brightness > 1.0f) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be %d-%d"), MP_QSTR_brightness, 0, 1); + } + bool ok = common_hal_zephyr_display_display_set_brightness(self, brightness); + if (!ok) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Brightness not adjustable")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_set_brightness_obj, zephyr_display_display_obj_set_brightness); + +MP_PROPERTY_GETSET(zephyr_display_display_brightness_obj, + (mp_obj_t)&zephyr_display_display_get_brightness_obj, + (mp_obj_t)&zephyr_display_display_set_brightness_obj); + +static mp_obj_t zephyr_display_display_obj_get_width(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_zephyr_display_display_get_width(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_width_obj, zephyr_display_display_obj_get_width); +MP_PROPERTY_GETTER(zephyr_display_display_width_obj, (mp_obj_t)&zephyr_display_display_get_width_obj); + +static mp_obj_t zephyr_display_display_obj_get_height(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_zephyr_display_display_get_height(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_height_obj, zephyr_display_display_obj_get_height); +MP_PROPERTY_GETTER(zephyr_display_display_height_obj, (mp_obj_t)&zephyr_display_display_get_height_obj); + +static mp_obj_t zephyr_display_display_obj_get_rotation(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return MP_OBJ_NEW_SMALL_INT(common_hal_zephyr_display_display_get_rotation(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_rotation_obj, zephyr_display_display_obj_get_rotation); + +static mp_obj_t zephyr_display_display_obj_set_rotation(mp_obj_t self_in, mp_obj_t value) { + zephyr_display_display_obj_t *self = native_display(self_in); + common_hal_zephyr_display_display_set_rotation(self, mp_obj_get_int(value)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_set_rotation_obj, zephyr_display_display_obj_set_rotation); + +MP_PROPERTY_GETSET(zephyr_display_display_rotation_obj, + (mp_obj_t)&zephyr_display_display_get_rotation_obj, + (mp_obj_t)&zephyr_display_display_set_rotation_obj); + +static mp_obj_t zephyr_display_display_obj_get_root_group(mp_obj_t self_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + return common_hal_zephyr_display_display_get_root_group(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(zephyr_display_display_get_root_group_obj, zephyr_display_display_obj_get_root_group); + +static mp_obj_t zephyr_display_display_obj_set_root_group(mp_obj_t self_in, mp_obj_t group_in) { + zephyr_display_display_obj_t *self = native_display(self_in); + displayio_group_t *group = NULL; + if (group_in != mp_const_none) { + group = MP_OBJ_TO_PTR(native_group(group_in)); + } + + bool ok = common_hal_zephyr_display_display_set_root_group(self, group); + if (!ok) { + mp_raise_ValueError(MP_ERROR_TEXT("Group already used")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(zephyr_display_display_set_root_group_obj, zephyr_display_display_obj_set_root_group); + +MP_PROPERTY_GETSET(zephyr_display_display_root_group_obj, + (mp_obj_t)&zephyr_display_display_get_root_group_obj, + (mp_obj_t)&zephyr_display_display_set_root_group_obj); + +static const mp_rom_map_elem_t zephyr_display_display_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_show), MP_ROM_PTR(&zephyr_display_display_show_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&zephyr_display_display_refresh_obj) }, + + { MP_ROM_QSTR(MP_QSTR_auto_refresh), MP_ROM_PTR(&zephyr_display_display_auto_refresh_obj) }, + { MP_ROM_QSTR(MP_QSTR_brightness), MP_ROM_PTR(&zephyr_display_display_brightness_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&zephyr_display_display_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&zephyr_display_display_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_rotation), MP_ROM_PTR(&zephyr_display_display_rotation_obj) }, + { MP_ROM_QSTR(MP_QSTR_root_group), MP_ROM_PTR(&zephyr_display_display_root_group_obj) }, +}; +static MP_DEFINE_CONST_DICT(zephyr_display_display_locals_dict, zephyr_display_display_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + zephyr_display_display_type, + MP_QSTR_Display, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, zephyr_display_display_make_new, + locals_dict, &zephyr_display_display_locals_dict); diff --git a/ports/zephyr-cp/bindings/zephyr_display/Display.h b/ports/zephyr-cp/bindings/zephyr_display/Display.h new file mode 100644 index 00000000000..a50dda8fe8b --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_display/Display.h @@ -0,0 +1,37 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/displayio/Group.h" +#include "common-hal/zephyr_display/Display.h" + +extern const mp_obj_type_t zephyr_display_display_type; + +#define NO_FPS_LIMIT 0xffffffff + +void common_hal_zephyr_display_display_construct_from_device(zephyr_display_display_obj_t *self, + const struct device *device, + uint16_t rotation, + bool auto_refresh); + +bool common_hal_zephyr_display_display_refresh(zephyr_display_display_obj_t *self, + uint32_t target_ms_per_frame, + uint32_t maximum_ms_per_real_frame); + +bool common_hal_zephyr_display_display_get_auto_refresh(zephyr_display_display_obj_t *self); +void common_hal_zephyr_display_display_set_auto_refresh(zephyr_display_display_obj_t *self, bool auto_refresh); + +uint16_t common_hal_zephyr_display_display_get_width(zephyr_display_display_obj_t *self); +uint16_t common_hal_zephyr_display_display_get_height(zephyr_display_display_obj_t *self); +uint16_t common_hal_zephyr_display_display_get_rotation(zephyr_display_display_obj_t *self); +void common_hal_zephyr_display_display_set_rotation(zephyr_display_display_obj_t *self, int rotation); + +mp_float_t common_hal_zephyr_display_display_get_brightness(zephyr_display_display_obj_t *self); +bool common_hal_zephyr_display_display_set_brightness(zephyr_display_display_obj_t *self, mp_float_t brightness); + +mp_obj_t common_hal_zephyr_display_display_get_root_group(zephyr_display_display_obj_t *self); +bool common_hal_zephyr_display_display_set_root_group(zephyr_display_display_obj_t *self, displayio_group_t *root_group); diff --git a/ports/zephyr-cp/bindings/zephyr_display/__init__.c b/ports/zephyr-cp/bindings/zephyr_display/__init__.c new file mode 100644 index 00000000000..eecfeeaec58 --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_display/__init__.c @@ -0,0 +1,24 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" + +#include "bindings/zephyr_display/Display.h" + +static const mp_rom_map_elem_t zephyr_display_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_zephyr_display) }, + { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&zephyr_display_display_type) }, +}; + +static MP_DEFINE_CONST_DICT(zephyr_display_module_globals, zephyr_display_module_globals_table); + +const mp_obj_module_t zephyr_display_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&zephyr_display_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_zephyr_display, zephyr_display_module); diff --git a/ports/zephyr-cp/bindings/zephyr_display/__init__.h b/ports/zephyr-cp/bindings/zephyr_display/__init__.h new file mode 100644 index 00000000000..4256bfac2fe --- /dev/null +++ b/ports/zephyr-cp/bindings/zephyr_display/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 9712f467858..2c717fc83c1 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index dce5b100aa6..5914ae61f28 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -41,6 +41,7 @@ cp_board_alias(nxp_frdm_mcxn947 frdm_mcxn947/mcxn947/cpu0) cp_board_alias(nxp_frdm_rw612 frdm_rw612) cp_board_alias(nxp_mimxrt1170_evk mimxrt1170_evk@A/mimxrt1176/cm7) cp_board_alias(st_stm32h7b3i_dk stm32h7b3i_dk) +cp_board_alias(st_stm32h750b_dk stm32h750b_dk/stm32h750xx/ext_flash_app) cp_board_alias(st_stm32wba65i_dk1 stm32wba65i_dk1) cp_board_alias(st_nucleo_u575zi_q nucleo_u575zi_q/stm32u575xx) cp_board_alias(st_nucleo_n657x0_q nucleo_n657x0_q/stm32n657xx) diff --git a/ports/zephyr-cp/boards/ek_ra8d1.conf b/ports/zephyr-cp/boards/ek_ra8d1.conf new file mode 100644 index 00000000000..f979d31e751 --- /dev/null +++ b/ports/zephyr-cp/boards/ek_ra8d1.conf @@ -0,0 +1,3 @@ + +# Enable Zephyr display subsystem so DT chosen zephyr,display creates a device. +CONFIG_DISPLAY=y diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 80b1b4ebf7d..1b82d3ba00e 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -37,7 +37,7 @@ canio = false codeop = false countio = false digitalio = true -displayio = true # Zephyr board has busio +displayio = true # Zephyr board has displayio dotclockframebuffer = false dualbank = false epaperdisplay = true # Zephyr board has busio @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 1bc1b96e6cf..f995c03c2a2 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native_sim.conf index ddbfef11266..739a71eeeb6 100644 --- a/ports/zephyr-cp/boards/native_sim.conf +++ b/ports/zephyr-cp/boards/native_sim.conf @@ -14,6 +14,10 @@ CONFIG_TRACING_GPIO=y # I2C emulation for testing CONFIG_I2C_EMUL=y +# Display emulation for display/terminal golden tests. +CONFIG_DISPLAY=y +CONFIG_SDL_DISPLAY=y + # EEPROM emulation for testing CONFIG_EEPROM=y CONFIG_EEPROM_AT24=y diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 7869cca4faf..397d514a0da 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index c2233ddf8b5..69a657b8c98 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index a1e8de8822b..378cbc07e9a 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index b50b1966ed0..892b3dbbbd4 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = true # Zephyr board has wifi +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 21d55194a1c..718cd0bcfd3 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 90f84ab1586..10b0056c81d 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = true # Zephyr board has wifi +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index eb5db066c89..a3d6acdb79e 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index d6efa285fe2..3d5fbb08c65 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 7600b8bbd15..ec96d530726 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 8e49b95d334..132899d4248 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -37,7 +37,7 @@ canio = false codeop = false countio = false digitalio = true -displayio = true # Zephyr board has busio +displayio = true # Zephyr board has displayio dotclockframebuffer = false dualbank = false epaperdisplay = true # Zephyr board has busio @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/circuitpython.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/circuitpython.toml index 3272dd4c5f3..0e19d8d7157 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/circuitpython.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/circuitpython.toml @@ -1 +1,2 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +SHIELDS = ["rtkmipilcdb00000be"] diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index b28a9481c72..bc2a29aea08 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 6b0ef8d8480..aacda400a30 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml new file mode 100644 index 00000000000..a8c03d5a4e8 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -0,0 +1,118 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "STMicroelectronics STM32H750B Discovery Kit" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has displayio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = true # Zephyr board has zephyr_display +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/circuitpython.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/circuitpython.toml new file mode 100644 index 00000000000..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index b6f03f3d627..b66682c5923 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -37,7 +37,7 @@ canio = false codeop = false countio = false digitalio = true -displayio = true # Zephyr board has busio +displayio = true # Zephyr board has displayio dotclockframebuffer = false dualbank = false epaperdisplay = true # Zephyr board has busio @@ -103,7 +103,7 @@ touchio = false traceback = true uheap = false usb = false -usb_cdc = false +usb_cdc = true usb_hid = false usb_host = false usb_midi = false @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 8d1fd925348..cadd8b5ade3 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -113,5 +113,6 @@ vectorio = true # Zephyr board has busio warnings = true watchdog = false wifi = false +zephyr_display = false zephyr_kernel = false zlib = false diff --git a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.conf b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.conf new file mode 100644 index 00000000000..24afffb8e88 --- /dev/null +++ b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.conf @@ -0,0 +1,2 @@ +# Enable Zephyr display subsystem so the built-in LTDC panel is available. +CONFIG_DISPLAY=y diff --git a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay new file mode 100644 index 00000000000..fdb4960477b --- /dev/null +++ b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay @@ -0,0 +1,14 @@ +&ext_flash { + partitions { + /delete-node/ partition@7800000; + + circuitpy_partition: partition@7800000 { + label = "circuitpy"; + reg = <0x7800000 DT_SIZE_M(8)>; + }; + }; +}; + +&rng { + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/stm32h7b3i_dk.conf b/ports/zephyr-cp/boards/stm32h7b3i_dk.conf new file mode 100644 index 00000000000..24afffb8e88 --- /dev/null +++ b/ports/zephyr-cp/boards/stm32h7b3i_dk.conf @@ -0,0 +1,2 @@ +# Enable Zephyr display subsystem so the built-in LTDC panel is available. +CONFIG_DISPLAY=y diff --git a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay b/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay index 88ad0415485..c2b5f3129c4 100644 --- a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay +++ b/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay @@ -2,6 +2,28 @@ /delete-node/ partitions; }; +&sram5 { + status = "disabled"; +}; + &rng { status = "okay"; }; + +&fdcan1 { + status = "disabled"; +}; + +/ { + chosen { + /delete-property/ zephyr,canbus; + }; +}; + +zephyr_udc0: &usbotg_hs { + pinctrl-0 = <&usb_otg_hs_dm_pa11 &usb_otg_hs_dp_pa12>; + pinctrl-names = "default"; + status = "okay"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/common-hal/zephyr_display/Display.c b/ports/zephyr-cp/common-hal/zephyr_display/Display.c new file mode 100644 index 00000000000..d1585b5f291 --- /dev/null +++ b/ports/zephyr-cp/common-hal/zephyr_display/Display.c @@ -0,0 +1,440 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "bindings/zephyr_display/Display.h" + +#include + +#include "bindings/zephyr_kernel/__init__.h" +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/time/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/display.h" +#include "supervisor/shared/tick.h" + +static const displayio_area_t *zephyr_display_get_refresh_areas(zephyr_display_display_obj_t *self) { + if (self->core.full_refresh) { + self->core.area.next = NULL; + return &self->core.area; + } else if (self->core.current_group != NULL) { + return displayio_group_get_refresh_areas(self->core.current_group, NULL); + } + return NULL; +} + +static enum display_pixel_format zephyr_display_select_pixel_format(const struct display_capabilities *caps) { + uint32_t formats = caps->supported_pixel_formats; + + if (formats & PIXEL_FORMAT_RGB_565) { + return PIXEL_FORMAT_RGB_565; + } + if (formats & PIXEL_FORMAT_RGB_888) { + return PIXEL_FORMAT_RGB_888; + } + if (formats & PIXEL_FORMAT_ARGB_8888) { + return PIXEL_FORMAT_ARGB_8888; + } + if (formats & PIXEL_FORMAT_RGB_565X) { + return PIXEL_FORMAT_RGB_565X; + } + if (formats & PIXEL_FORMAT_L_8) { + return PIXEL_FORMAT_L_8; + } + if (formats & PIXEL_FORMAT_AL_88) { + return PIXEL_FORMAT_AL_88; + } + if (formats & PIXEL_FORMAT_MONO01) { + return PIXEL_FORMAT_MONO01; + } + if (formats & PIXEL_FORMAT_MONO10) { + return PIXEL_FORMAT_MONO10; + } + return caps->current_pixel_format; +} + +static void zephyr_display_select_colorspace(zephyr_display_display_obj_t *self, + uint16_t *color_depth, + uint8_t *bytes_per_cell, + bool *grayscale, + bool *pixels_in_byte_share_row, + bool *reverse_pixels_in_byte, + bool *reverse_bytes_in_word) { + *color_depth = 16; + *bytes_per_cell = 2; + *grayscale = false; + *pixels_in_byte_share_row = false; + *reverse_pixels_in_byte = false; + *reverse_bytes_in_word = false; + + if (self->pixel_format == PIXEL_FORMAT_RGB_565X) { + // RGB_565X is big-endian RGB_565, so byte-swap from native LE. + *reverse_bytes_in_word = true; + } else if (self->pixel_format == PIXEL_FORMAT_RGB_888) { + *color_depth = 24; + *bytes_per_cell = 3; + *reverse_bytes_in_word = false; + } else if (self->pixel_format == PIXEL_FORMAT_ARGB_8888) { + *color_depth = 32; + *bytes_per_cell = 4; + *reverse_bytes_in_word = false; + } else if (self->pixel_format == PIXEL_FORMAT_L_8 || + self->pixel_format == PIXEL_FORMAT_AL_88) { + *color_depth = 8; + *bytes_per_cell = 1; + *grayscale = true; + *reverse_bytes_in_word = false; + } else if (self->pixel_format == PIXEL_FORMAT_MONO01 || + self->pixel_format == PIXEL_FORMAT_MONO10) { + bool vtiled = self->capabilities.screen_info & SCREEN_INFO_MONO_VTILED; + bool msb_first = self->capabilities.screen_info & SCREEN_INFO_MONO_MSB_FIRST; + *color_depth = 1; + *bytes_per_cell = 1; + *grayscale = true; + *pixels_in_byte_share_row = !vtiled; + *reverse_pixels_in_byte = msb_first; + *reverse_bytes_in_word = false; + } +} + +void common_hal_zephyr_display_display_construct_from_device(zephyr_display_display_obj_t *self, + const struct device *device, + uint16_t rotation, + bool auto_refresh) { + self->auto_refresh = false; + + if (device == NULL || !device_is_ready(device)) { + raise_zephyr_error(-ENODEV); + } + + self->device = device; + display_get_capabilities(self->device, &self->capabilities); + + self->pixel_format = zephyr_display_select_pixel_format(&self->capabilities); + if (self->pixel_format != self->capabilities.current_pixel_format) { + (void)display_set_pixel_format(self->device, self->pixel_format); + display_get_capabilities(self->device, &self->capabilities); + self->pixel_format = self->capabilities.current_pixel_format; + } + + uint16_t color_depth; + uint8_t bytes_per_cell; + bool grayscale; + bool pixels_in_byte_share_row; + bool reverse_pixels_in_byte; + bool reverse_bytes_in_word; + zephyr_display_select_colorspace(self, &color_depth, &bytes_per_cell, + &grayscale, &pixels_in_byte_share_row, &reverse_pixels_in_byte, + &reverse_bytes_in_word); + + displayio_display_core_construct( + &self->core, + self->capabilities.x_resolution, + self->capabilities.y_resolution, + 0, + color_depth, + grayscale, + pixels_in_byte_share_row, + bytes_per_cell, + reverse_pixels_in_byte, + reverse_bytes_in_word); + + self->native_frames_per_second = 60; + self->native_ms_per_frame = 1000 / self->native_frames_per_second; + self->first_manual_refresh = !auto_refresh; + + if (rotation != 0) { + common_hal_zephyr_display_display_set_rotation(self, rotation); + } + + (void)display_blanking_off(self->device); + + displayio_display_core_set_root_group(&self->core, &circuitpython_splash); + common_hal_zephyr_display_display_set_auto_refresh(self, auto_refresh); +} + +uint16_t common_hal_zephyr_display_display_get_width(zephyr_display_display_obj_t *self) { + return displayio_display_core_get_width(&self->core); +} + +uint16_t common_hal_zephyr_display_display_get_height(zephyr_display_display_obj_t *self) { + return displayio_display_core_get_height(&self->core); +} + +mp_float_t common_hal_zephyr_display_display_get_brightness(zephyr_display_display_obj_t *self) { + (void)self; + return -1; +} + +bool common_hal_zephyr_display_display_set_brightness(zephyr_display_display_obj_t *self, mp_float_t brightness) { + (void)self; + (void)brightness; + return false; +} + +static bool zephyr_display_refresh_area(zephyr_display_display_obj_t *self, const displayio_area_t *area) { + uint16_t buffer_size = CIRCUITPY_DISPLAY_AREA_BUFFER_SIZE / sizeof(uint32_t); + + displayio_area_t clipped; + if (!displayio_display_core_clip_area(&self->core, area, &clipped)) { + return true; + } + + uint16_t rows_per_buffer = displayio_area_height(&clipped); + uint8_t pixels_per_word = (sizeof(uint32_t) * 8) / self->core.colorspace.depth; + // For AL_88, displayio fills at 1 byte/pixel (L_8) but output needs 2 bytes/pixel, + // so halve the effective pixels_per_word for buffer sizing. + uint8_t effective_pixels_per_word = pixels_per_word; + if (self->pixel_format == PIXEL_FORMAT_AL_88) { + effective_pixels_per_word = sizeof(uint32_t) / 2; + } + uint16_t pixels_per_buffer = displayio_area_size(&clipped); + uint16_t subrectangles = 1; + + // When pixels_in_byte_share_row is false (mono vtiled), 8 vertical pixels + // pack into one column byte. The byte layout needs width * ceil(height/8) + // bytes, which can exceed the pixel-count-based buffer size. + bool vtiled = self->core.colorspace.depth < 8 && + !self->core.colorspace.pixels_in_byte_share_row; + + bool needs_subdivision = displayio_area_size(&clipped) > buffer_size * effective_pixels_per_word; + if (vtiled && !needs_subdivision) { + uint16_t width = displayio_area_width(&clipped); + uint16_t height = displayio_area_height(&clipped); + uint32_t vtiled_bytes = (uint32_t)width * ((height + 7) / 8); + needs_subdivision = vtiled_bytes > buffer_size * sizeof(uint32_t); + } + + if (needs_subdivision) { + rows_per_buffer = buffer_size * effective_pixels_per_word / displayio_area_width(&clipped); + if (vtiled) { + rows_per_buffer = (rows_per_buffer / 8) * 8; + if (rows_per_buffer == 0) { + rows_per_buffer = 8; + } + } + if (rows_per_buffer == 0) { + rows_per_buffer = 1; + } + subrectangles = displayio_area_height(&clipped) / rows_per_buffer; + if (displayio_area_height(&clipped) % rows_per_buffer != 0) { + subrectangles++; + } + pixels_per_buffer = rows_per_buffer * displayio_area_width(&clipped); + buffer_size = pixels_per_buffer / pixels_per_word; + if (pixels_per_buffer % pixels_per_word) { + buffer_size += 1; + } + // Ensure buffer is large enough for vtiled packing. + if (vtiled) { + uint16_t width = displayio_area_width(&clipped); + uint16_t vtiled_words = (width * ((rows_per_buffer + 7) / 8) + sizeof(uint32_t) - 1) / sizeof(uint32_t); + if (vtiled_words > buffer_size) { + buffer_size = vtiled_words; + } + } + // Ensure buffer is large enough for AL_88 expansion. + if (self->pixel_format == PIXEL_FORMAT_AL_88) { + uint16_t al88_words = (pixels_per_buffer * 2 + sizeof(uint32_t) - 1) / sizeof(uint32_t); + if (al88_words > buffer_size) { + buffer_size = al88_words; + } + } + } + + uint32_t buffer[buffer_size]; + uint32_t mask_length = (pixels_per_buffer / 32) + 1; + uint32_t mask[mask_length]; + + uint16_t remaining_rows = displayio_area_height(&clipped); + + for (uint16_t j = 0; j < subrectangles; j++) { + displayio_area_t subrectangle = { + .x1 = clipped.x1, + .y1 = clipped.y1 + rows_per_buffer * j, + .x2 = clipped.x2, + .y2 = clipped.y1 + rows_per_buffer * (j + 1), + }; + + if (remaining_rows < rows_per_buffer) { + subrectangle.y2 = subrectangle.y1 + remaining_rows; + } + remaining_rows -= rows_per_buffer; + + memset(mask, 0, mask_length * sizeof(mask[0])); + memset(buffer, 0, buffer_size * sizeof(buffer[0])); + + displayio_display_core_fill_area(&self->core, &subrectangle, mask, buffer); + + uint16_t width = displayio_area_width(&subrectangle); + uint16_t height = displayio_area_height(&subrectangle); + size_t pixel_count = (size_t)width * (size_t)height; + + if (self->pixel_format == PIXEL_FORMAT_MONO10) { + uint8_t *bytes = (uint8_t *)buffer; + size_t byte_count = (pixel_count + 7) / 8; + for (size_t i = 0; i < byte_count; i++) { + bytes[i] = ~bytes[i]; + } + } + + if (self->pixel_format == PIXEL_FORMAT_AL_88) { + uint8_t *bytes = (uint8_t *)buffer; + for (size_t i = pixel_count; i > 0; i--) { + bytes[(i - 1) * 2 + 1] = 0xFF; + bytes[(i - 1) * 2] = bytes[i - 1]; + } + } + + // Compute buf_size based on the Zephyr pixel format. + uint32_t buf_size_bytes; + if (self->pixel_format == PIXEL_FORMAT_MONO01 || + self->pixel_format == PIXEL_FORMAT_MONO10) { + buf_size_bytes = (pixel_count + 7) / 8; + } else if (self->pixel_format == PIXEL_FORMAT_AL_88) { + buf_size_bytes = pixel_count * 2; + } else { + buf_size_bytes = pixel_count * (self->core.colorspace.depth / 8); + } + + struct display_buffer_descriptor desc = { + .buf_size = buf_size_bytes, + .width = width, + .height = height, + .pitch = width, + .frame_incomplete = false, + }; + + int err = display_write(self->device, subrectangle.x1, subrectangle.y1, &desc, buffer); + if (err < 0) { + return false; + } + + RUN_BACKGROUND_TASKS; + } + + return true; +} + +static void zephyr_display_refresh(zephyr_display_display_obj_t *self) { + if (!displayio_display_core_start_refresh(&self->core)) { + return; + } + + const displayio_area_t *current_area = zephyr_display_get_refresh_areas(self); + while (current_area != NULL) { + if (!zephyr_display_refresh_area(self, current_area)) { + break; + } + current_area = current_area->next; + } + + displayio_display_core_finish_refresh(&self->core); +} + +void common_hal_zephyr_display_display_set_rotation(zephyr_display_display_obj_t *self, int rotation) { + bool transposed = (self->core.rotation == 90 || self->core.rotation == 270); + bool will_transposed = (rotation == 90 || rotation == 270); + if (transposed != will_transposed) { + int tmp = self->core.width; + self->core.width = self->core.height; + self->core.height = tmp; + } + + displayio_display_core_set_rotation(&self->core, rotation); + + if (self == &displays[0].zephyr_display) { + supervisor_stop_terminal(); + supervisor_start_terminal(self->core.width, self->core.height); + } + + if (self->core.current_group != NULL) { + displayio_group_update_transform(self->core.current_group, &self->core.transform); + } +} + +uint16_t common_hal_zephyr_display_display_get_rotation(zephyr_display_display_obj_t *self) { + return self->core.rotation; +} + +bool common_hal_zephyr_display_display_refresh(zephyr_display_display_obj_t *self, + uint32_t target_ms_per_frame, + uint32_t maximum_ms_per_real_frame) { + if (!self->auto_refresh && !self->first_manual_refresh && (target_ms_per_frame != NO_FPS_LIMIT)) { + uint64_t current_time = supervisor_ticks_ms64(); + uint32_t current_ms_since_real_refresh = current_time - self->core.last_refresh; + if (current_ms_since_real_refresh > maximum_ms_per_real_frame) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Below minimum frame rate")); + } + uint32_t current_ms_since_last_call = current_time - self->last_refresh_call; + self->last_refresh_call = current_time; + if (current_ms_since_last_call > target_ms_per_frame) { + return false; + } + uint32_t remaining_time = target_ms_per_frame - (current_ms_since_real_refresh % target_ms_per_frame); + while (supervisor_ticks_ms64() - self->last_refresh_call < remaining_time) { + RUN_BACKGROUND_TASKS; + } + } + self->first_manual_refresh = false; + zephyr_display_refresh(self); + return true; +} + +bool common_hal_zephyr_display_display_get_auto_refresh(zephyr_display_display_obj_t *self) { + return self->auto_refresh; +} + +void common_hal_zephyr_display_display_set_auto_refresh(zephyr_display_display_obj_t *self, bool auto_refresh) { + self->first_manual_refresh = !auto_refresh; + if (auto_refresh != self->auto_refresh) { + if (auto_refresh) { + supervisor_enable_tick(); + } else { + supervisor_disable_tick(); + } + } + self->auto_refresh = auto_refresh; +} + +void zephyr_display_display_background(zephyr_display_display_obj_t *self) { + if (self->auto_refresh && (supervisor_ticks_ms64() - self->core.last_refresh) > self->native_ms_per_frame) { + zephyr_display_refresh(self); + } +} + +void release_zephyr_display(zephyr_display_display_obj_t *self) { + common_hal_zephyr_display_display_set_auto_refresh(self, false); + release_display_core(&self->core); + self->device = NULL; + self->base.type = &mp_type_NoneType; +} + +void zephyr_display_display_collect_ptrs(zephyr_display_display_obj_t *self) { + (void)self; + displayio_display_core_collect_ptrs(&self->core); +} + +void zephyr_display_display_reset(zephyr_display_display_obj_t *self) { + if (self->device != NULL && device_is_ready(self->device)) { + common_hal_zephyr_display_display_set_auto_refresh(self, true); + displayio_display_core_set_root_group(&self->core, &circuitpython_splash); + self->core.full_refresh = true; + } else { + release_zephyr_display(self); + } +} + +mp_obj_t common_hal_zephyr_display_display_get_root_group(zephyr_display_display_obj_t *self) { + if (self->core.current_group == NULL) { + return mp_const_none; + } + return self->core.current_group; +} + +bool common_hal_zephyr_display_display_set_root_group(zephyr_display_display_obj_t *self, displayio_group_t *root_group) { + return displayio_display_core_set_root_group(&self->core, root_group); +} diff --git a/ports/zephyr-cp/common-hal/zephyr_display/Display.h b/ports/zephyr-cp/common-hal/zephyr_display/Display.h new file mode 100644 index 00000000000..bdec1e96ba5 --- /dev/null +++ b/ports/zephyr-cp/common-hal/zephyr_display/Display.h @@ -0,0 +1,31 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" +#include "shared-module/displayio/display_core.h" + +typedef struct { + mp_obj_base_t base; + displayio_display_core_t core; + const struct device *device; + struct display_capabilities capabilities; + enum display_pixel_format pixel_format; + uint64_t last_refresh_call; + uint16_t native_frames_per_second; + uint16_t native_ms_per_frame; + bool auto_refresh; + bool first_manual_refresh; +} zephyr_display_display_obj_t; + +void zephyr_display_display_background(zephyr_display_display_obj_t *self); +void zephyr_display_display_collect_ptrs(zephyr_display_display_obj_t *self); +void zephyr_display_display_reset(zephyr_display_display_obj_t *self); +void release_zephyr_display(zephyr_display_display_obj_t *self); diff --git a/ports/zephyr-cp/cptools/board_tools.py b/ports/zephyr-cp/cptools/board_tools.py index 088b4bb5491..305abab3f19 100644 --- a/ports/zephyr-cp/cptools/board_tools.py +++ b/ports/zephyr-cp/cptools/board_tools.py @@ -1,3 +1,6 @@ +import tomllib + + def find_mpconfigboard(portdir, board_id): next_underscore = board_id.find("_") while next_underscore != -1: @@ -8,3 +11,27 @@ def find_mpconfigboard(portdir, board_id): return p next_underscore = board_id.find("_", next_underscore + 1) return None + + +def load_mpconfigboard(portdir, board_id): + mpconfigboard_path = find_mpconfigboard(portdir, board_id) + if mpconfigboard_path is None or not mpconfigboard_path.exists(): + return None, {} + + with mpconfigboard_path.open("rb") as f: + return mpconfigboard_path, tomllib.load(f) + + +def get_shields(mpconfigboard): + shields = mpconfigboard.get("SHIELDS") + if shields is None: + shields = mpconfigboard.get("SHIELD") + + if shields is None: + return [] + if isinstance(shields, str): + return [shields] + if isinstance(shields, (list, tuple)): + return [str(shield) for shield in shields] + + return [str(shields)] diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 3da878e0f5b..2022d82f1b7 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -68,6 +68,9 @@ "busio": ["fourwire", "i2cdisplaybus", "sdcardio", "sharpdisplay"], "fourwire": ["displayio", "busdisplay", "epaperdisplay"], "i2cdisplaybus": ["displayio", "busdisplay", "epaperdisplay"], + # Zephyr display backends need displayio and, by extension, terminalio so + # the REPL console appears on the display by default. + "zephyr_display": ["displayio"], "displayio": [ "vectorio", "bitmapfilter", diff --git a/ports/zephyr-cp/cptools/get_west_shield_args.py b/ports/zephyr-cp/cptools/get_west_shield_args.py new file mode 100644 index 00000000000..deda6bf5f26 --- /dev/null +++ b/ports/zephyr-cp/cptools/get_west_shield_args.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +"""Resolve shield arguments for west build. + +Priority: +1. SHIELD / SHIELDS make variables (if explicitly provided) +2. SHIELD / SHIELDS from boards///circuitpython.toml +""" + +import argparse +import os +import pathlib +import re +import shlex + +import board_tools + + +def split_shields(raw): + if not raw: + return [] + + return [shield for shield in re.split(r"[,;\s]+", raw.strip()) if shield] + + +def dedupe(values): + deduped = [] + seen = set() + + for value in values: + if value in seen: + continue + seen.add(value) + deduped.append(value) + + return deduped + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("board") + args = parser.parse_args() + + portdir = pathlib.Path(__file__).resolve().parent.parent + + _, mpconfigboard = board_tools.load_mpconfigboard(portdir, args.board) + + shield_origin = os.environ.get("SHIELD_ORIGIN", "undefined") + shields_origin = os.environ.get("SHIELDS_ORIGIN", "undefined") + + shield_override = os.environ.get("SHIELD", "") + shields_override = os.environ.get("SHIELDS", "") + + override_requested = shield_origin != "undefined" or shields_origin != "undefined" + + if override_requested: + shields = split_shields(shield_override) + split_shields(shields_override) + else: + shields = board_tools.get_shields(mpconfigboard) + + shields = dedupe(shields) + + west_shield_args = [] + for shield in shields: + west_shield_args.extend(("--shield", shield)) + + print(shlex.join(west_shield_args)) + + +if __name__ == "__main__": + main() diff --git a/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py b/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py index acc3ae78619..f42fc1a3a85 100644 --- a/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py +++ b/ports/zephyr-cp/cptools/pre_zephyr_build_prep.py @@ -2,7 +2,6 @@ import pathlib import subprocess import sys -import tomllib import board_tools @@ -10,14 +9,11 @@ board = sys.argv[-1] -mpconfigboard = board_tools.find_mpconfigboard(portdir, board) -if mpconfigboard is None: +_, mpconfigboard = board_tools.load_mpconfigboard(portdir, board) +if not mpconfigboard: # Assume it doesn't need any prep. sys.exit(0) -with mpconfigboard.open("rb") as f: - mpconfigboard = tomllib.load(f) - blobs = mpconfigboard.get("BLOBS", []) blob_fetch_args = mpconfigboard.get("blob_fetch_args", {}) for blob in blobs: diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index f7d79517195..c123d90ce78 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -488,6 +488,14 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa value = device_tree.root.nodes["chosen"].props[k] path2chosen[value.to_path()] = k chosen2path[k] = value.to_path() + + chosen_display = chosen2path.get("zephyr,display") + if chosen_display is not None: + status = chosen_display.props.get("status", None) + if status is None or status.to_string() == "okay": + board_info["zephyr_display"] = True + board_info["displayio"] = True + remaining_nodes = set([device_tree.root]) while remaining_nodes: node = remaining_nodes.pop() @@ -724,6 +732,43 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa zephyr_binding_objects = "\n".join(zephyr_binding_objects) zephyr_binding_labels = "\n".join(zephyr_binding_labels) + zephyr_display_header = "" + zephyr_display_object = "" + zephyr_display_board_entry = "" + if board_info.get("zephyr_display", False): + zephyr_display_header = """ +#include +#include +#include "shared-module/displayio/__init__.h" +#include "bindings/zephyr_display/Display.h" + """.strip() + zephyr_display_object = """ +void board_init(void) { +#if CIRCUITPY_ZEPHYR_DISPLAY && DT_HAS_CHOSEN(zephyr_display) + // Always allocate a display slot so board.DISPLAY is at least a valid + // NoneType object even if the underlying Zephyr display is unavailable. + primary_display_t *display_obj = allocate_display(); + if (display_obj == NULL) { + return; + } + + zephyr_display_display_obj_t *display = &display_obj->zephyr_display; + display->base.type = &mp_type_NoneType; + + const struct device *display_dev = device_get_binding(DEVICE_DT_NAME(DT_CHOSEN(zephyr_display))); + if (display_dev == NULL || !device_is_ready(display_dev)) { + return; + } + + display->base.type = &zephyr_display_display_type; + common_hal_zephyr_display_display_construct_from_device(display, display_dev, 0, true); +#endif +} + """.strip() + zephyr_display_board_entry = ( + "{ MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].zephyr_display) }," + ) + board_dir.mkdir(exist_ok=True, parents=True) header = board_dir / "mpconfigboard.h" if status_led: @@ -797,6 +842,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa #include "py/mphal.h" {zephyr_binding_headers} +{zephyr_display_header} const struct device* const flashes[] = {{ {", ".join(flashes)} }}; const int circuitpy_flash_device_count = {len(flashes)}; @@ -810,6 +856,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa {pin_defs} {zephyr_binding_objects} +{zephyr_display_object} static const mp_rom_map_elem_t mcu_pin_globals_table[] = {{ {mcu_pin_mapping} @@ -820,6 +867,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS {hostnetwork_entry} +{zephyr_display_board_entry} {board_pin_mapping} {zephyr_binding_labels} diff --git a/ports/zephyr-cp/debug.conf b/ports/zephyr-cp/debug.conf new file mode 100644 index 00000000000..90c1f52d4db --- /dev/null +++ b/ports/zephyr-cp/debug.conf @@ -0,0 +1,15 @@ +CONFIG_DEBUG=y +CONFIG_DEBUG_OPTIMIZATIONS=y +CONFIG_LOG_MAX_LEVEL=4 + +CONFIG_STACK_SENTINEL=y +CONFIG_DEBUG_THREAD_INFO=y +CONFIG_DEBUG_INFO=y +CONFIG_EXCEPTION_STACK_TRACE=y + +CONFIG_ASSERT=y +CONFIG_LOG_BLOCK_IN_THREAD=y +CONFIG_FRAME_POINTER=y + +CONFIG_FLASH_LOG_LEVEL_DBG=y +CONFIG_LOG_MODE_IMMEDIATE=y diff --git a/ports/zephyr-cp/tests/__init__.py b/ports/zephyr-cp/tests/__init__.py index 18e596e8e70..8ab7610ce0f 100644 --- a/ports/zephyr-cp/tests/__init__.py +++ b/ports/zephyr-cp/tests/__init__.py @@ -1,3 +1,5 @@ +from pathlib import Path + import serial import subprocess import threading @@ -144,6 +146,14 @@ def shutdown(self): self.serial.close() self.debug_serial.close() + def display_capture_paths(self) -> list[Path]: + """Return paths to numbered PNG capture files produced by trace-driven capture.""" + pattern = getattr(self, "_capture_png_pattern", None) + count = getattr(self, "_capture_count", 0) + if not pattern or count == 0: + return [] + return [Path(pattern % i) for i in range(count)] + def wait_until_done(self): start_time = time.monotonic() while self._proc.poll() is None and time.monotonic() - start_time < self._timeout: diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py index ffc4cb6eabe..19455b7bfa3 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -91,7 +91,7 @@ def test_bsim_scan_zephyr_beacon_reload(bsim_phy, circuitpython, zephyr_sample): assert output.count("scan run done True") >= 2 -@pytest.mark.flaky(reruns=3) +@pytest.mark.xfail(strict=False, reason="scan without stop_scan may fail on reload") @pytest.mark.zephyr_sample("bluetooth/beacon") @pytest.mark.code_py_runs(2) @pytest.mark.duration(8) diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index 1a364ba2995..b0047f0c947 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -4,23 +4,31 @@ """Pytest fixtures for CircuitPython native_sim testing.""" import logging -import re -import select +import os import subprocess -import time -from dataclasses import dataclass from pathlib import Path import pytest import serial -from . import NativeSimProcess + from .perfetto_input_trace import write_input_trace from perfetto.trace_processor import TraceProcessor +from . import NativeSimProcess + logger = logging.getLogger(__name__) +def pytest_addoption(parser): + parser.addoption( + "--update-goldens", + action="store_true", + default=False, + help="Overwrite golden images with captured output instead of comparing.", + ) + + def pytest_configure(config): config.addinivalue_line( "markers", "circuitpy_drive(files): run CircuitPython with files in the flash image" @@ -51,6 +59,20 @@ def pytest_configure(config): "markers", "native_sim_rt: run native_sim in realtime mode (-rt instead of -no-rt)", ) + config.addinivalue_line( + "markers", + "display(capture_times_ns=None): run test with SDL display; " + "capture_times_ns is a list of nanosecond timestamps for trace-triggered captures", + ) + config.addinivalue_line( + "markers", + "display_pixel_format(format): override the display pixel format " + "(e.g. 'RGB_565', 'ARGB_8888')", + ) + config.addinivalue_line( + "markers", + "display_mono_vtiled(value): override the mono vtiled screen_info flag (True or False)", + ) ZEPHYR_CP = Path(__file__).parent.parent @@ -136,7 +158,6 @@ def board(request): @pytest.fixture def native_sim_binary(request, board): """Return path to native_sim binary, skip if not built.""" - ZEPHYR_CP = Path(__file__).parent.parent build_dir = ZEPHYR_CP / f"build-{board}" binary = build_dir / "zephyr-cp/zephyr/zephyr.exe" @@ -150,6 +171,26 @@ def native_sim_env() -> dict[str, str]: return {} +PIXEL_FORMAT_BITMASK = { + "RGB_888": 1 << 0, + "MONO01": 1 << 1, + "MONO10": 1 << 2, + "ARGB_8888": 1 << 3, + "RGB_565": 1 << 4, + "BGR_565": 1 << 5, + "L_8": 1 << 6, + "AL_88": 1 << 7, +} + + +@pytest.fixture +def pixel_format(request) -> str: + """Indirect-parametrize fixture: adds display_pixel_format marker.""" + fmt = request.param + request.node.add_marker(pytest.mark.display_pixel_format(fmt)) + return fmt + + @pytest.fixture def sim_id(request) -> str: return request.node.nodeid.replace("/", "_") @@ -175,6 +216,54 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp if input_trace_markers and len(input_trace_markers[0][1].args) == 1: input_trace = input_trace_markers[0][1].args[0] + input_trace_file = None + if input_trace is not None: + input_trace_file = tmp_path / "input.perfetto" + write_input_trace(input_trace_file, input_trace) + + marker = request.node.get_closest_marker("duration") + if marker is None: + timeout = 10 + else: + timeout = marker.args[0] + + runs_marker = request.node.get_closest_marker("code_py_runs") + if runs_marker is None: + code_py_runs = 1 + else: + code_py_runs = int(runs_marker.args[0]) + + display_marker = request.node.get_closest_marker("display") + if display_marker is None: + display_marker = request.node.get_closest_marker("display_capture") + + capture_times_ns = None + if display_marker is not None: + capture_times_ns = display_marker.kwargs.get("capture_times_ns", None) + + pixel_format_marker = request.node.get_closest_marker("display_pixel_format") + pixel_format = None + if pixel_format_marker is not None and pixel_format_marker.args: + pixel_format = pixel_format_marker.args[0] + + mono_vtiled_marker = request.node.get_closest_marker("display_mono_vtiled") + mono_vtiled = None + if mono_vtiled_marker is not None and mono_vtiled_marker.args: + mono_vtiled = mono_vtiled_marker.args[0] + + # If capture_times_ns is set, merge display_capture track into input trace. + if capture_times_ns is not None: + if input_trace is None: + input_trace = {} + else: + input_trace = dict(input_trace) + input_trace["display_capture"] = list(capture_times_ns) + if input_trace_file is None: + input_trace_file = tmp_path / "input.perfetto" + write_input_trace(input_trace_file, input_trace) + + use_realtime = request.node.get_closest_marker("native_sim_rt") is not None + procs = [] for i in range(instance_count): flash = tmp_path / f"flash-{i}.bin" @@ -189,30 +278,14 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp for name, content in files.items(): src = tmp_drive / name - src.write_text(content) + if isinstance(content, bytes): + src.write_bytes(content) + else: + src.write_text(content) subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) trace_file = tmp_path / f"trace-{i}.perfetto" - input_trace_file = None - if input_trace is not None: - input_trace_file = tmp_path / f"input-{i}.perfetto" - write_input_trace(input_trace_file, input_trace) - - marker = request.node.get_closest_marker("duration") - if marker is None: - timeout = 10 - else: - timeout = marker.args[0] - - runs_marker = request.node.get_closest_marker("code_py_runs") - if runs_marker is None: - code_py_runs = 1 - else: - code_py_runs = int(runs_marker.args[0]) - - use_realtime = request.node.get_closest_marker("native_sim_rt") is not None - if "bsim" in board: cmd = [str(native_sim_binary), f"--flash_app={flash}"] if instance_count > 1: @@ -231,7 +304,9 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp cmd = [str(native_sim_binary), f"--flash={flash}"] # native_sim vm-runs includes the boot VM setup run. realtime_flag = "-rt" if use_realtime else "-no-rt" - cmd.extend((realtime_flag, "-wait_uart", f"--vm-runs={code_py_runs + 1}")) + cmd.extend( + (realtime_flag, "-display_headless", "-wait_uart", f"--vm-runs={code_py_runs + 1}") + ) if input_trace_file is not None: cmd.append(f"--input-trace={input_trace_file}") @@ -240,9 +315,31 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp if marker and len(marker.args) > 0: for device in marker.args: cmd.append(f"--disable-i2c={device}") + + if pixel_format is not None: + cmd.append(f"--display_pixel_format={PIXEL_FORMAT_BITMASK[pixel_format]}") + + if mono_vtiled is not None: + cmd.append(f"--display_mono_vtiled={'true' if mono_vtiled else 'false'}") + + env = os.environ.copy() + env.update(native_sim_env) + + capture_png_pattern = None + if capture_times_ns is not None: + if instance_count == 1: + capture_png_pattern = str(tmp_path / "frame_%d.png") + else: + capture_png_pattern = str(tmp_path / f"frame-{i}_%d.png") + cmd.append(f"--display_capture_png={capture_png_pattern}") + logger.info("Running: %s", " ".join(cmd)) + proc = NativeSimProcess(cmd, timeout, trace_file, env) + proc.display_dump = None + proc._capture_png_pattern = capture_png_pattern + proc._capture_count = len(capture_times_ns) if capture_times_ns is not None else 0 + procs.append(proc) - procs.append(NativeSimProcess(cmd, timeout, trace_file, native_sim_env)) if instance_count == 1: yield procs[0] else: diff --git a/ports/zephyr-cp/tests/perfetto_input_trace.py b/ports/zephyr-cp/tests/perfetto_input_trace.py index d0cde49be08..494c9cdcadf 100644 --- a/ports/zephyr-cp/tests/perfetto_input_trace.py +++ b/ports/zephyr-cp/tests/perfetto_input_trace.py @@ -7,11 +7,12 @@ python -m tests.perfetto_input_trace input_trace.json output.perfetto -Input JSON format: +Input JSON format — counter tracks use [timestamp, value] pairs, instant +tracks use bare timestamps: { "gpio_emul.01": [[8000000000, 0], [9000000000, 1], [10000000000, 0]], - "gpio_emul.02": [[8000000000, 0], [9200000000, 1]] + "display_capture": [500000000, 1000000000] } """ @@ -22,7 +23,9 @@ from pathlib import Path from typing import Mapping, Sequence -InputTraceData = Mapping[str, Sequence[tuple[int, int]]] +# Counter tracks: list of (timestamp, value) pairs. +# Instant tracks: list of timestamps (bare ints). +InputTraceData = Mapping[str, Sequence[tuple[int, int] | int]] def _load_perfetto_pb2(): @@ -31,8 +34,15 @@ def _load_perfetto_pb2(): return perfetto_pb2 +def _is_instant_track(events: Sequence) -> bool: + """Return True if *events* is a list of bare timestamps (instant track).""" + if not events: + return False + return isinstance(events[0], int) + + def build_input_trace(trace_data: InputTraceData, *, sequence_id: int = 1): - """Build a Perfetto Trace protobuf for input replay counter tracks.""" + """Build a Perfetto Trace protobuf for input replay counter and instant tracks.""" perfetto_pb2 = _load_perfetto_pb2() trace = perfetto_pb2.Trace() @@ -41,6 +51,7 @@ def build_input_trace(trace_data: InputTraceData, *, sequence_id: int = 1): for idx, (track_name, events) in enumerate(trace_data.items()): track_uuid = 1001 + idx + instant = _is_instant_track(events) desc_packet = trace.packet.add() desc_packet.timestamp = 0 @@ -49,16 +60,28 @@ def build_input_trace(trace_data: InputTraceData, *, sequence_id: int = 1): desc_packet.sequence_flags = seq_incremental_state_cleared desc_packet.track_descriptor.uuid = track_uuid desc_packet.track_descriptor.name = track_name - desc_packet.track_descriptor.counter.unit = perfetto_pb2.CounterDescriptor.Unit.UNIT_COUNT + if not instant: + desc_packet.track_descriptor.counter.unit = ( + perfetto_pb2.CounterDescriptor.Unit.UNIT_COUNT + ) - for ts, value in events: - event_packet = trace.packet.add() - event_packet.timestamp = ts - event_packet.trusted_packet_sequence_id = sequence_id - event_packet.sequence_flags = seq_needs_incremental_state - event_packet.track_event.type = perfetto_pb2.TrackEvent.Type.TYPE_COUNTER - event_packet.track_event.track_uuid = track_uuid - event_packet.track_event.counter_value = value + if instant: + for ts in events: + event_packet = trace.packet.add() + event_packet.timestamp = ts + event_packet.trusted_packet_sequence_id = sequence_id + event_packet.sequence_flags = seq_needs_incremental_state + event_packet.track_event.type = perfetto_pb2.TrackEvent.Type.TYPE_INSTANT + event_packet.track_event.track_uuid = track_uuid + else: + for ts, value in events: + event_packet = trace.packet.add() + event_packet.timestamp = ts + event_packet.trusted_packet_sequence_id = sequence_id + event_packet.sequence_flags = seq_needs_incremental_state + event_packet.track_event.type = perfetto_pb2.TrackEvent.Type.TYPE_COUNTER + event_packet.track_event.track_uuid = track_uuid + event_packet.track_event.counter_value = value return trace @@ -72,27 +95,35 @@ def write_input_trace( trace_file.write_bytes(trace.SerializeToString()) -def _parse_trace_json(data: object) -> dict[str, list[tuple[int, int]]]: +def _parse_trace_json(data: object) -> dict[str, list[tuple[int, int]] | list[int]]: if not isinstance(data, dict): raise ValueError("top-level JSON value must be an object") - parsed: dict[str, list[tuple[int, int]]] = {} + parsed: dict[str, list[tuple[int, int]] | list[int]] = {} for track_name, events in data.items(): if not isinstance(track_name, str): raise ValueError("track names must be strings") if not isinstance(events, list): - raise ValueError( - f"track {track_name!r} must map to a list of [timestamp, value] events" - ) - - parsed_events: list[tuple[int, int]] = [] - for event in events: - if not isinstance(event, (list, tuple)) or len(event) != 2: - raise ValueError(f"track {track_name!r} events must be [timestamp, value] pairs") - timestamp_ns, value = event - parsed_events.append((int(timestamp_ns), int(value))) - - parsed[track_name] = parsed_events + raise ValueError(f"track {track_name!r} must map to a list of events") + + if not events: + parsed[track_name] = [] + continue + + # Distinguish instant (bare ints) vs counter ([ts, value] pairs). + if isinstance(events[0], (int, float)): + parsed[track_name] = [int(ts) for ts in events] + else: + parsed_events: list[tuple[int, int]] = [] + for event in events: + if not isinstance(event, (list, tuple)) or len(event) != 2: + raise ValueError( + f"track {track_name!r} events must be [timestamp, value] pairs " + "or bare timestamps" + ) + timestamp_ns, value = event + parsed_events.append((int(timestamp_ns), int(value))) + parsed[track_name] = parsed_events return parsed diff --git a/ports/zephyr-cp/tests/zephyr_display/README.md b/ports/zephyr-cp/tests/zephyr_display/README.md new file mode 100644 index 00000000000..6b502021543 --- /dev/null +++ b/ports/zephyr-cp/tests/zephyr_display/README.md @@ -0,0 +1,45 @@ +# Zephyr Display Golden Tests + +This directory contains native_sim golden-image tests for the Zephyr-specific `zephyr_display` path. + +## What is tested + +- `board.DISPLAY` is present and usable. +- CircuitPython terminal/console tilegrids are attached to the default display root group. +- Deterministic console terminal output matches a checked-in golden image. +- `zephyr_display` pixel format constants are exposed. +- `displayio` rendering produces expected stripe colors at sampled pixel locations. + +## Files + +- `test_zephyr_display.py` – pytest tests. +- `golden/terminal_console_output_320x240.png` – console terminal output golden reference image. + +## How capture works + +These tests use trace-driven SDL display capture triggered by Perfetto instant events: + +- `--input-trace=` provides a Perfetto trace containing a `"display_capture"` track + with instant events at the desired capture timestamps. +- `--display_capture_png=` specifies the output PNG pattern (may contain `%d` for + a sequence number). +- `--display_headless` runs SDL in headless/hidden-window mode (always enabled for native_sim tests). + +The test harness sets these flags automatically when tests use +`@pytest.mark.display(capture_times_ns=[...])`. + +## Regenerating the console golden image + +```bash +rm -rf /tmp/zephyr-display-golden +pytest -q ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py::test_console_output_golden \ + --basetemp=/tmp/zephyr-display-golden +cp /tmp/zephyr-display-golden/test_console_output_golden0/frame_0.png \ + ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.png +``` + +## Running the tests + +```bash +pytest -q ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py +``` diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..5739b8ee156eb72f2fd419d5de58eb81d6750650 GIT binary patch literal 12102 zcmV-MFS*c(P)Pu@3^;LcfrASiT;SmL0sDY;AkFti6v?jYt|mEeRls5; zvdNh@-CZp9NTau3zkdBHFTC)=3%?=$wE6^Ic;ST?R^eOu30nR+^*mm9;Tk~m<%LV& z8*CYI{EIwa*bOftd!dx_t$h3#^=dE*wih`*Vc?Mg{vtk$i(>}CeegqGURs5AR=xfD z=RadNK~yAp;0qI?kJyy>!s(|bJO{Zc@r6B=0Doq^{rbNS0V;?sI>$xHa6QqnxM;d5 zNH0oslZo=8o)RD@tNH{uf|uC5<2EP4>k%G;jZ@7_d=au*tO$G9*h@jo$*Q+s|Ms;M57B{Rej`sgF+a1~1lR*ZT3NOWNifSj zIN71dOtnQR#*iOFVlxPGfGkg4hX~hZ)!VQC4Jg1>c9Tg^?IJzlAyB8<#1uox4<)Bn zb^tEyB@%mNRhs}?K*(vP%>)uuxo8dHji5@i3F)OIznL~7T*y-(_R6ZaUw{8QuK*P! zrZ`3t2`XHqa1S;|G({9CmY7}^0a|3FAT+@-6jyn3PXUN#mOiWAe*Mqie}%{>ljy9m z2?V&(MRE78B*TQ%$|S!`(n}`9sF&A}U?j8hvg$^FHN2!WyRQ@}39fKa?)KQ5D&BG8 z)EW_>mw+<*kp2N?d#RM!BcEp(v$E=-mfD$T!uja5pZm~uq>pJ|h#4+w+n-y}(D#fv#%aeY+X6G{i&bjb?Lifo=_U>7Az;Hl(_TP;Jq6ez zp=^Rv5@pG~^6cDsOI0@cX|nK>0MCe$-fY_d0WxmdllWT5N|{L{IGg;kYz^!}ggGR* zLuT2wpO3?8ZF{XYk1f*1+D<@*idu4qNyd`3P-=)kwJV$8|tM}^jF_g zywD+o{4z4|$B9l*B8!sSM#P4?N$n!sJywsJ2-Rtr3=vUfwVnN^@>GULldHA^tk0~s zU;p`E{Td+B<{hV=%drhc2vB+Hahx9o8~qNRi844zC?9p@jX^Z#tvqM| z_3<9`kOgH7T6W_r{;hnxAFpm`ee9*T6-KtpqxYyyjZHolqa;3Vj?tQqY>$!6k;*0k zip6!(nBLVvy)>EwwV8)m)UKlRcTxeO>W_Kv9g_@&3u0^2XnjLhz7dc)6e=&MEj+Q{ ziAhgf0}9Z(%BXI)FvF8^%=k;VozS-@<>pax(f5-P4LF61BIBPeqdLRV7?J*DL>J)f z_jg1+g{r|w|GJwY2j*v1Ujb&kFNyCbA=5=@g^nMIXiaPWNPiMCV=5Z&9Uz{v#z*?| zka^~c_->Ey*8rLKsM^a^hChqsd%=+a$_i|}28ig4k;ceUdQNQ-S@c-4%djnDPes(A z*Ap9ki0K3_`X3Qn*uVWjIuW8{ZBf$OZ0qcGlh;N4K8xtA^vWQ?$*DDi&;-XAc`9qU z+K=SCnUgOmZd>59d>?IHnQg7APYgX7%_hIvs%JUsi>#W9Fp3MN&l87iPIPXD^e{Vq zBDA7K)>XlC;}d?8h9GZ*M9U)V;_M|t z<8{wd9uIny;M#hilA6_$;)byT^eRKe>x&|v{Gzj}0xWjsZp?_mgcw#`#kn=QEU5l! zHqM(hz#kelm+@MR>=e(O|8wqI11L4dZ-_)fZFx$e*;&1=nqPyRvI&HN-zztSbD=ns>{$N+)Bw*lzxuUD&8byjl44}s$C4jv z%RdiLp#c>2K%v6)E_@7Gc}b2S!HB06N-anT7>A$s~-i1sh| zIvnbzDEWQbMHE|9Uqp2Ts9B*R@_xLb`^Z#|5)nB)j zPMc@U2H=Tm+~%LNrSN)R21m~(LkEcGjFMifEfTA(ocMUOjl@i^Jv!$)ME;tLId684 zkHhNK{SZ~>QGe>T3n3oJs2+$Y!N`0Q;32(M8@sp@3wq?LzHlJ2kdLzpSAc9=-KT1E zLamRK^R@I_uaYyjqLB=Y4&(Zt=H#6xri#suRZSbV=%`Jgb{Ih z`_Az8O@LPu%_G0_yYE$-hXk*cT1|LK&r5KlzMqeM-m4qEeWe(e3$NzXl3yw3kHM7k z=|D69dNycZZ8Ji2ya*~cMQ@-y_hbiEmdzcbC&8%VBO1F1`BmFseaen8_p5T5NAt!P zcO^d`hviX%s3NSPvI$^jihFF@ZnM^MrM{@KfeK`ZP(_F=`Q7ooL4ua2YV2m?gNn92 z3%%*pGvr3532js1UPMCr#vez*6G^0V|sh7M5ZlM`kvf-GTL z{|hwwZeyu88gv=@L;!CrM*jzML6OQY)KJIr zs0N5CLDl~gu^VOZw>4Nja1DL19fCq2>ZPa(yq1bwlU0}kB=F~@OrGxa*_vOW@wHOj z^>#kS{AW)^Jfl>Bd(DZg*BLz#QGpY` z8RA(?8QakUkCc5tl4U%@D7n3Ac`aluyb;@5hGGh^)y8~Aumw-RCV(L^?>r+n`Nck? zFMLPP=>_LJ(b$OWWDuJVdpuJ@iFk2@86Nf{>n|By+0S|G&jA*ruXJqCK93FCmjEwu zda3ENucr$}Iv}Dw6nzOmh;P(~5Z%u~AD{q_tHJ1OMz5pea^Q{fELq_@e*cNk$a4Wl zACguP;zVRzZnO_0zvG>np!Q0wFuAqb(7w?Qha|!Cl^c=Z?B!^`E%E`BxV$?0S&z4W z74H1M)rQ<1>$TN=C<0qzh2&SLKd-BwTbY|8Jv*lFjES2oFY&e7*toPvaF9DAPo3e3 zjnN!l%-s^BF{s#6we#e23tS4Wdlp555hy=^S2;JhlZH{W8g#D}(x zw!UE7_tyMnT(metp%8n=oePvw6?S~ajTIp3d}O;&zgDybp>~a}+@AY5J5=5)j@}!i zup^K~a_85PSnlMG-^aF{VsZA^#o;;g%stilt8k@^m7Udp{(!Wlu46$T%D4=D6{bc_}r3XP8OEEmsX`Up6*>Wc zDZt)q#}sxD%j~(>Gm4%m3-TCV|9gqArT%)afqco*+gWj!52dW=fzN@* zufi4bbxXk^Dv(isEJhD&Scpgv_iKPFRT-i>MdznjTqEU=70d>&wR1{hB*)z+yM`-{h zI&=YL6(4HX8KYKP*V6fG2o1;0_VzKD+p8Oxt?;PtOjao2dF%`*bc~nW*wwy;M_c7a zMonsy)6lcKsNeV0-)IhtAn)(LH%PDr_4ZV~JaJxCke>H$u}@|G>5o^SW2wHDE!x+! zn*;^XdB?Tpcz^1#sNGAsXDGJYB)oCJ^r_>#(bxCk__YPaxIHlA3fL0l@o`wC_*Gxe zw)gcok-}4Mjd=l$!J;ir(6`ogubT7PZUQgqmBOh%h7>=Z?HFa}Em$y0O{>+jXqX{7 z|DI~B02%d$+9K~q5UW9@`z)9F-4wIpZKM5O+Xk3eiNswr-Wy{TdcD=Zk$1#ku2M7` zZ*AimAo_l!>_#_3JnttXn<_9j9k0<6xKi0MRjdVwF1AskGird0UT-10KOYRKdHSt| zeY~`A3UKtkOn5&D%q91X=iSt*0Wwvl(ahGFG5wQ1Iunhf`XRn8`ydf|b^zH|e;>7% zAuD|QFRTW5et)#p?>%E!r6*E{ofP+dO^nLy(z$BTi|uPWm}`C`X(#HtQAy2qI?bTKvpeK zRR;vY_+1fW>ew$m%`vuP+Z5PGNh)LocQqd$iC@a2BfTo{Xm6>po^p%MF##+EuvCPV zck3G9xi_i-6q+IVJHb(6W7}EVyO=;Kw2E4ws&<$Q1)b~FUn%DrV6QmLtc1mAAN`0r z+U|tna*z7v+mBW}ma3IkM`3>l8ylW>mI%T2Jz@mwQ`q~Vlok9w>+xqXOX(}Xb6>BW z8FTcp3NJzZDL)dx1|g#U-k(}~nu1kuthN|oa@~+6yVe4K9^+ApbzfCVLcGG>wN+l_ z9HlsmhBYL4dm{81_3vp!$j#d~k^C$uT@as>Nfj@-dFM>RXeYoDnzs+x@l?B;zjTg~ zaph+bW-h#05$pTYQ~P-p^9I8xz*^hjbH5jYEpsNJY1AJ-!tSeWlzkIm5oCl2tr!Qk z!-!YdO8{ zZiAiUM~h-9_TpysBir9df8$dWKR)_f+o)o@hT=mCOHrEkX45BGJ}bbEL!WG-fm49~ zvz-Xh%Zk{H)+xrOy`~{SlS$KzjSvV4Ms1jw29%}W$9|g;HuNfRRP_~lssUC9A1S<% zO>H+)Yd-;-^L*?>5=2l3m3O`Rw5h*RttO>G;saR6N`Q6fai5LJICyYHPbj0%jZ zLB_@hHKoqXxEoov6(FJl&$gZ171$fgC^*lUV_XoC$6#f-a;zS*D3#F` zz2i+rB+k4sP1G3~6?nko1>XYtc)S>99XXPD?F__ffHitSz^XiUTs?{tO>G9N{Bd~3cWD6|YiYCW_Cy<+8?P4yF@h_fE4kxFx{J1{8Xs5fU0GO|Z8N8by0 z4R8c2I220FQ%?*aBh`CV3eMHFW{9Xj^cWLsdrI_FninHc;5bI_Dl6}yE7YRzsOq_t z%faUy&kC>l}=}0kFZhJ`h->rQd*#G=rkTlm+4(c3AX!#E7WBk9cj)^5`067e)RO zkDtTs|1r&E2jN9XE(0i0?zN&L5T@wN9fuewaqYB3tp}S8G4)qUs|NVk`@(kcrj}P* zuyzxGY+*sAM*U;vd|^X86Xfl2STCZ3;9ZBYf=;JRR>zAq*Y}}}C){3<$ z(Pq}|v_Mnhg*0490bZLZ=g5l3EpRqLA%StxkGOcxfmM=AA8#Sz*5f;b+BwP69_ z32SbsSj060_2aNSbr3ZYSJD}m79}=6X52wrd6!Ov8R{(I82RyopF_^98M4EFOY!kz zFzOFMU+@FaC^ELmwi`$5^9*&jgI?*NUZmCYktFy1V~!{G{WwepWh=9;^*AhbZ9~2K zI_JnBC&e86ny3f>eGn~Eh>Ez1#(7|T?spvG@Xeu6cnaN%U0uEg*mLfMAA~T%Y>M&S zh_Nb6=#f`G9D#tB^t?pp5CrcZy2n*SRNj8du!RWGMV62Ht8fwJ7g<5c0`ni^5)pZ_ z3p0i%Nlz`sbA}r}9xJ*FVeQfFv?E`XizI^l8-BCmgt=n&o(q2*R?Df@j~Jo0^_YbZ zL(K{*CTRO5+}2v|sW8>r0>NS};oX)pww6614!(c*6r4vXUdW55vtVsKnPc19kHZ=T zg(r9rB&)j?JT4g_vQG7FnChYW3~E~hBHh8n4XfBjKtJ)&$Qj$0St*TSP1RQYkbXRK zdRG#A92TnPka{9ob41nPX7xZ-P;*-&L^pU8V$?8?{LULsniJDrSv(31;dRukOP8qFPdO z7IRFRBgO`kx;5ZyqaFhu>~HjWTW;Pz+JKF z?F86O+(>An_ME#|s#VxWZ=_6sSG}p)2MVwhh2K9hS|CwqyvEMLZn70|I=UHn>-+Yk zwiv}`sYO)v^%UO*N|2=lbPnd`$8+0ATcEmw)d&hr0nWiJa*BnLAwEzn9AAYy1GyPu zwT+l5Yiy2og^j7nvGu#&9IdnQ z)E)2bKN<;PmqhKh5flaLxlr6&6yKjz*5jDDd*`wkXhoNuBUVLbE7-f-x_O=hSAZjo z0*DPnb|vp6zzMIraHZ^e7p{~7-&lBRuhDBS3)=}O;wbl12yFB#ZgS*)3gH{QY3eDv zgSc2V*ct<>yy2J+{&ISQ2esc9Ud1-j7L4vVfhEII#@`}RlI21ubol}HvxvuBKmK@k z{=c@g`g%uYpv%1ehfI2;cbCHno2>RpWH$l)13Z9`Vr>_(DWJ_^Hwn9W`f!Nc~CBM`QheJ?OO z3b1yQ+7$=Xw2}{|I)&X2e6&SAsteWt4=}{ovPZz!9`<4|o?$)^9r5CMY}>l^zjcIC zcE}vA2FM1;c?=tb$6YyAQG&&c^vX!+iWl$jg&4xpD1#*c4LB8;xVnU=(bf@$dIB^<|tBB+ql~4MrbWV;$UfW1xjA|ZT(+#}&4D9!7dRS7^&Ej0I(E@>)(Q2_kbGh|hu704*@JJkNYB81=#of;*seV-6y! z&YIJsEoz+Rh^jFKSt9dq1f?hHIY%mRJi3%QS*Oc3&BG8{$PUb;V_0H-2GQjl!&AFq z=SHty=PyJQV7>iSBP&+R+}O#B-x(P(FYDGka6S@P;2Hn8AA?QJ65+btjAaELbwv`bHIKUQ;kWh^Gwp((dBc_CP4+VH$O7486nPyFYV^Cg&l69 zJpMJ08t>z&C5B$$c#o0vxvWe#tWk=}4_H{*!h=B#(1RIU-N|HFD>nr+p3JGmjgOI+ zJ=%}K)GKy$4sReg?f`p8EyE4DM3@nLia7``AnK2Wnh+C7a2NV$(;72V#{Nq$Q9f&c z5%uS-8MXomnZqL2Z=Jb|rb?l7<$6REU8KU)sR1GoERYYx>OsP8B&w$)kHR0mR0Ff;1Uvom1gHxV9f zgv_Uk;dcIH#RY<#4B;M!h13ZVb%?0KIsjXCErK-^AmSdi3-id0S>I>QN2)-JoXEuw zB12|zM(h$W(;Hk3FrxmvHnnZk<_25=616wCjUo|FeJb_G*o?52EWJlnUm@c!MARP> z2S~hG5E9&sI8jkf+pAF@@0BSxy<{mnMStnoSZdJfuUGQB&5uUV&T!8@^*^R=*Fsc( zj5I}6TO5%Ux#*?z7odLhc!}n zy*@$Q7Gl4-a4oKSwFu1*aXs?dJx?+X>2=kO9y9BUXTp(dOK4eNAPkl^#3u2;E z`hSnuMmE=xBaWc6=YJKBQGQ-!*HU$eZG&hP>W^Kg_Iq;fXnoI`W26G>wi7JUtHBam zYcXC-jwsM8%Gx6;@OWLnDv~y@eG6Rn^%WrFmt~vPKf^1N)=ch zZ+x5)jR6I*C6e9DcyemfPok(AV>N*17zzz?LR9@_kYl8cMC7W^hyZ=`&y*U^h(8QL)g}(+ujQtz zprs#LADyV|S~osgN^hk8YP8yV+uw_0O{{+nS%KF8d$m8yrf%!0IfXJbw!sIoL^?C~ z9#Crw=iDulD?l4-gSJiH3isf->Mf{LV7msmtE|B0X)8d)*`A<5R$!0fYrQWzH$}&^ zF#kr0=PW%}&AH@QK4ol1V_G&XOeVa@W3j9@<W2cm-MUJO--)BI?f?W2rokG90}> z1#r|&sz9@#Q;J5NtqG5!i>ko;YiluMNv<`f^%0xV`xZQ78t{0>8e?5)j|#+VfSzpe z$P+z$H9#aFqwkrdXuMxRYS!Ae&sI44mqt}!qd)5NGU5FsWXGB1y}n3bNXw)CvNP}* z{O15`AWEd|-;9~cHFG7L`qTXTp5xri& zviDSb%L-coG64|@E+()YH9+PvX1mmDn-AtHF;@Z5+YzF(Y!%yIk1YUYtOPZ?g{urfbslZy{A!-o7j9UY1DpMJ3&#Ush#5e)o4)sRDjVy@T{=W0Bg(B{eI6UOF9BW;GhS;y38p?$=~#>; z#y+xQyah&_$^;b>oQ#d75Qt#3D#R* z?*eO$*#ykh?i3rs^M1}gI?K`f(LAcf7zg(-1STMmfVRf;0vy~PF>6$on`-Pqj>^FE zYLC-gR;;vQ#)=IO(Rm0@Op?mjiqKTQe$G_WBho-Qwh!Oqun-03oumH0RS!hwIDvJG z(oOR|{=%p{b}mD`QDa+k6`TY;B^L$J^^TDYOUWs%$TqxXBr3hm>t*Z|B7 z@;jpBr*spG*s*3(bMPv&ae-`oStOF?%9vql;K+NAM_9@Ao5wi3{qQ2jEbsPbW!iMVWSh`B;l6gvzGHHJdZlG zRNTlGQG!K7ek~}}Uk)L96dUu2v7QYwhqDGadcuo`pp?WYM26OGL7@aS`=M1?^f<;> z15^hb6VQkf{Lqn~$4z_x7FJepBAS=10W#!QoVL9&2qtfpRg1G<3BCi?o+Gv}hY-2% z0wW3!QG<-yYuQ>#@UXdqllJ@C_~6k6$ULoiy-Kje$xlso$=hC!&Yo#=#AB=mSc-39 zY#~Qhd@4XB7)J00lV>GAziuf(2l?&orXDgYi(cAxTuBf4jmD#Wwap08@gjIsV5<$; z?eyB(JxDAd^Nf$Gw#j`YKH7(Uzgnm0N6_H>+B9k-0P&Z-J3*EZP>aZ;@cB+UnmFX&{^Y_Ne`N%IVBp5fUtAxT!*) z>&KE9Vvk}GIiBGou67$UR~ugPLlM`iBk(st&>)Hgr?>5AX?|p)Rl5CA^2skUpH?NV z`YVV;h>#ykaFI4A)UlxSR4*6o7@QG9xrl9nSyk6-LsTErb|S&-_38J3QVI6#%9z}& zezdK1JXPC;5cE{pYXS9VujV&Fdi_=#+TUwy)q#u~APo5>=$wVf*vJd75bJAeOlxlM zm<^CY5576k{Sd*c!?Gp?da5VPu451F%{CoAk4U{85@$9dGle)I`XTUJ^k@RbX!pRtc8o+={H~wX<`_Y~zo^ioRCQXOQ1$ zeNvF$dPR3YaVFV;etH_TSLLe-?F{vN0x05<&4KYF@vSqgRDY+pqYS(~OfsDTJ&VNS+;msmT0IDmt!c%>o@I>)GG9mUkz^vB^0h~>K*TM|S zCp5-L0k&S339m1T?8P}g>nd5%M!%xxt^HZ!5yclBe+p#f`ZOZHHEPa+=Weh{UyS-X z?H-cKBDqb7(NnecD8bU`>$Ur`XEbI;L8(1g{#{_p&KuB%G8nBjv&e6R^_u|C8H@ro zpa#53FG_e(ViZChLmo=Obel)r%{o&aZ~sxsuZNaz!0Xw4-Z?6GFR7ROGWz-$DZO5w zXG|&MhbDOEEb&D$qt81>2i~i*nWrkuloZ-N%{M`qK5q~*eU0<^+T`a&)>R=@0;2$D z6QdZjVExqQqv{w%&IT zx!M^@ke@da;SuuFXWiSsj|k9uA0f!>xea(-WR11@BV)&iq>j}eAwgvP2~pC?Bs7t7 z%=AR&a%Ce+QbhaveX*M$*#Q-K-@!#BLT#dk#gjl8dqr+hyNQ7;F* z2;UdIFF^3IBS|B#a93&AcNNJ}r24;Cd;VHfbSjrqpf!K`u z-~P=*fUUOOYz)jIzKprXm_>r94MKz`AY{{O+s(#+>gp=zB0bf?%*=}0JQH9ke!@|b zmva6S(66#xll)4VpEjtSkzSd^w_+{;JCa~29wJm`6>6uM3nRd*wwhhtX?sEjNzJwevCEZ@e+KZ3 z9Wn*8efw*R085!qf-~Ch*oF8!_BgUrK%9=5M6{|M#NsO-vj0SOPJ!xh2A^iiaAh5Y#nVXqjk#TpZ2`sA*=_e4mYKuH& zV0LEl%l8F-3CggV@N=U1`e8bAj@Qoc4U@5soHSrh< z(%EGWKUSs}F^7V9GKrC~abVI_7R|AP90)uN;a{Qz$k@%a5kW;*Yl-g+)utzR^YjE2 zAZa@pNZgpEB#V9(6L2(T26WU_2M z_6D*DYG2~3k(CY!^D@M$%nVYx4)L`xLmLQcfQm6Q zj*)~-ymZI4v+C_TLx2aoDlDSjCf5BJT$}Jl*spT*2fRcyd)y>!?5P0eWR{Nr4=6|} zI>%&U{JMl^VZ)mq*>h}8d_7!`5Z7f@i~!G26VYPD_xlo^2Mbe9O;Q&nJp}8Calfq6 z5nzoO1UBIbFfXX!NWU3m^o0q}3m;KlGqc`G76Dq=w5IpM7sQL?Ug%&Q0ebNw&fgO+ w5_=&5*CW6eUU=aJ5n?}#{=y3{yl`RsKRYrR%_cZ=NB{r;07*qoM6N<$g3B>&DF6Tf literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_AL_88.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_AL_88.png new file mode 100644 index 0000000000000000000000000000000000000000..6bdb72b802c97f5981b6e59a0505d9f390d3de74 GIT binary patch literal 17323 zcmXtAS6EY7+YKdv0R=__L8Ll10!SG{2_>kY;~+&yLX6ZDETJe6dM_5LLlLA3qaX<_ zfq?WPp*JN!2u)B!2?A22`}1A=H|IIexi}a5dEd3yde_?fxs}C@n65-SbnPYn=;0hW zW&Nl{A^wdIN#k3bxi!DI&~J`A=)=_CEkD;bH+_5+T7PbBk$t6)zEu3Ye0h8N;sbyK zpAsvk8saFK;5%(lrh6Xx?Zsm%V;o@LxI*RoY#uvbGxg*nhZbp@jNc_fLyH8hfPQ z^v20GS|baBPRaHUY411*{T3)17b%%N(3;2X%7;O=X*zdO9uT{sYF4OHz}-#Z>Gu%_ zMebNMqqWYB$U%PV7F+AC3dt`?xN%NFTSSO{@(UqS-f{;I3yUkIR4>>CkGBM7aS#V9j_V%tur7aZgWymDqcNTk(<%&?bNdM3-caf52PpR zKiqxL^e8Yj+Lrlav8L{uH_VT<>+pc9qWDQoqjiA)=Hx|@#)LQ*hBP0G?*H~ltw(B^ zr0F_cl%Zl(P=W^s)-w*Jxfx39F+C@(F|ivsh0U2O}r4wvZl zR#_K%UDXnl&-kG-x$IgN3VcGrVfkF&9`NWo!0Ncrs`wYbRehTt8}2+=#c#c;n11lP z;}<{%z}1UP9?34Dae43bUeRnnJt31PY6 zlc4$HBo6SZltJ%wtXFY-0@Vmx+6hC-%1PAnd*Av!r(RkXZYc2zUt8;F;$V3wiqjJ*!3(I-(>H%iZ{ z6o&aL|5)@{X(q8ofrVj?}sa%Y|kr)7uzaev~yfkB%H_6iq4?}30mi(7rtj#^r5UEyOJv9%JKw4wu((a4y zgD^ATMwPvGNZn7+s)|n9uWOQfcpr?0e}FjIemD83QYIdLmu}bPquT459Zm!A2-&$E zjFXU`i1~;gIEG<)YsJ1?M}+m{!WlZ}kf+@&f=?B@ysMP{;HiD=Cv8RlT{%0IRnv+F z8t6lESZt7Xm_A>LoKrxfF+kVMozoMh>r<@sE>qJ$@va<)$RRhx5#HWA)=5niZsd_` z{z+TN<;wQ$83YVo%@w(Yky~m5U1a;rT`B&w%-um%w@+$dQVq_`(7 zxmPz&@ z9m2+xaza>gbc%4<&cT?RME{-1m$vjq=&~h(2eOI*RAPo9dh>54LJF-~Jk?K#lWzTB zm&f*|B$qES?D-s}p4|81PmxI~j()AD9F=0g@ANdwUH~fR$phH?aDq;|pu;y8&OPg! zPnl>{i%{yuTp${#%FI;6S*60iRJr6v2XFW(dKnQ4m0o=qLMf(4D-g-JRX0y5KUEtl z;QOETDi!p{XEn0JhTnThhvDK@mQ`9U2mxX-HQ!7%`gLJKn+oWpevJoyWdyrDusc+sfFHYV~=gEGwfWF?`W4(%Bj$BE1TE zPP8N2yu=0j{P`9-e8m=SdiqHhAU>hst!WRLWbvJjXuK!u730Ah_#PYLy!4giZyqX5oAQ!QZjpyObqeGzl1vJ^EHC&G-sMx=e!Ec_alt~#W;e4z=(hY3PQr;kEqwF_Iw5mAOkaFFzyq3!1(s(DR|3! zo|XibZ(609ysIr_AW(@NyM*(2ULr=nx@GE$t#?zeb9RgA)>1fUBVBe2?|Y7?eDH7t z&F6Tft!H<}CxESw{Wx@d@R*_Cy-i%lYx`uiq1T2Pe5mjme#*lGmEVaSbCMAQk!Og3 zNL{mXoXi8}G}Ku8I1RFNoYNzUR~f>O~<&CPywI z?D0eLYBss^Xsd;Wb-@s%Z zs|ATw*lO22m#u;-2r`2W>qQBxe}Tz%`7LWW&auZ|iw?n7v!)VymrRHg(L1 zx9%P@fAG~T?2^5po*)VsWX?Mge@yaaGD4MjG9K8sOv0r!m=b~Tzs71hlciE-F) z>sk)qcx18_78{$tQmcF&VF^elmkOUQTeOE{Fe{* zo;;$HPHBV4<&z(E9sCJ1m|!6kMWe0OE!1>?r2Q6TWZ+uf=C%2}`6(vv6}bOSU$0fD zzBYB<*O_&!@dPBK_isEqQ}{ZgZ_==XBp#k_c;hDRXECC8m-t1R5C&yuFZZZlXXk%h zSKZF{>fJ&OsO=lr1uS`j^^w!XIS0)y2P^y|4@As%#WPFTnPtIQxPiFbG*jdb5beImhhDn(uRJDx9;;qlT z{Z(olAx&Q=snt-A_iP#X3q^SKvNk9AJ|^%6x>p46-pCRcJts=n42c+2KP{>wswN%; z@&=J~HP>UDlkiq?=YN2`bEc95J?Wb#Zo1S_#b0KBLYHCH=0!rfErKQft@*Y|GueCe zm=|CHsDQS`j$hAozi7{AbnIxI3?vfPPLe@EQ&$n0=35=^A*q`LS~F5Ndyueqr;DdQ z^DZo{3g?y=R}wEKBD0-tAgXVvK#02k=pW$?2fqK{iap~>e_UX6=s}xPS5FcPu zfBsB2$*sdStxz#f>zZmAe)NIL(x7-(|78Q@WZQkcf8EvSiCk zzQF{#3bgiz-^>0qr0yi&b<1Bzc(y)I2t#HI>+r@(Ehfv0>p^2GZY9l$3+34_N(GV} zo-@Aa^l>Cq)2yUp+2i*_GCqzgf{ zGu3cLu_JT_D_3YUL(i2HDSl*SoNgIW0-ZW`(f;_r1pv*}9~W0x!aEanQQ#im^u50% z4JbOAC-|Z0Fj|i*FhsJPX4SLpf7pFq`-GSs7%LuRE!E+ISG0>B0{v$Z@o8NTSThOJ zI`lgX*T|G;f{Mqkqe5ST-YFUidxI~>Am77d1ztJA)|S^IrEF10p;Jz*uFE>L}KIQzl6Afo=h2b8o7`B=Y9=U13gwcg@R z)-&!MFHUx&wwBFCy7>@8S+gcDP2zTDYHeYvdz7n54T1|1Q|_>8j!;f+*fesjiLZ!J zx7EpLttpzCI^1JQ&uNZToKR9#n}2s(C_?ulqh5J}_ET<~(1PN-2lSInH*9{RDheN9 z3go8V{>{@iseihvPu4O#H|>V=fd+xcEOtIsHyn!{lfullr}Xpsr`07vLLz1%->-|Q!H`%65kPsF!5hM{}o;TM%` z{jyez1#OJO*A6CAw(P}${ZGv;CEuUAOU1WSjQNrXzVw8qP3I-4`*t17h5$jhxF00) z_USZqIDUjIYzqov{0J{T>(z_U7Pu;o&#)A7av(!k6)UN#D+ywjZa%5?N4s9@OF853 zAKB9^f(G6vlMl6sfspwmdnkyq(}9cnv@7Rs1fxRo{S-GAQ#X-(=X(H1Ileo5$q`@w zh7d{CBf(jll>J7&`_&AbL7Tfp>F$fT-Bewq>)H`b#Y_Y9U)S73rB3tpPnxfS6L|W| zS#$nU#FuJ~K>4|y(7n5>N+Q}mu+VHpZ2Zfv4O=maF|Y-iI1Tt1mtbFGh-T+S->tN= zemWpvs2DJl`M5!>TxGgynbcEPTBn3kgQ3W0s1}pYSc$+{>e)eqF@KqvEb01plOzvt zKwTIfSNhdHskQO?x}%=a!I9WIHD*hEcG*B9W?91_EZR=+qe#%yZNlXs(=8CACQN3# zEQ<5MNvmA*L-7hgv-{9MBEah%9yOK0N9O-D0yh~3)5rhUN+spphl4`eh$!~GGf2e% ziR(@NIl&1pU*?7_JTwQUo?NZtPv6=#=&V>P+VW9-;NR+2*;~&O zPK8Zv`HGz|Ogoof!arMit){{YF8SG!@YL={6xJ0kqEJSSSh}Tv9199uRZP2($GTp z&J$tUve#VWp=-9}^h+;QCrCB6$J!Ft{L zN?u-&m8MhB5z?<$cZ>LKlBP;34V$u%RnWz(M_icTwc}z6!(uL9*EpLMPoXC9CE6#^ zTKg2DR*VEDx_G7c1>7vcA4osT zxeW>%8oft4->G$7$RO&!=yOJGv55QC%{6(2=7jJjdsJ7w#XKojSq>^AF?+B7Y^LkI z!TXdj9p@`T17C-C+j#>5xGV738Jo>z_qOiRsOc`Uk?Mr4vquOwiZ14vGtfdmUR?56 zDq@S-mif1uJ~<~C@5OV^(7|L|w zBxL6%)1Zt7zbPOUzHBU?*pdDl@<2-HVX$DyZBrEckKCBiV-m!$SE>H1 z*l2vagFQXs9x4q36^l@X3hn-y}g4iqFO(ObE;AvV~vNOYe5buF+CLA-bGzoCv3yK#i3Ll+-jOr^BPaz$3u zy~61fS3bg$T++sF-p0kAZQ3KEr;Yyk8}~JTcY7gH4=Th4w;t*2^^AG%R_L*Tw$l6h zvj)MEcTM8Kz$?HW6~RJr3!yqIvcT9Aov*bnfr@k^nVC0kX3X*T+kWlX`kd@)`IH1g zu;i+WjMCO7C~TQo>Kus0@9Jc4>X)`k$JB7mo%Bk$pp`?eri1`3s% zVb6m(eSe@4ud2`zS&we=U4HR&3-T!8a;7n~j^7EKS(I2fQ}w8B_GBZ_0f?*acL-Cv z<$G?pv@(Ns60ua--l)=0%j`|JMZ6liRHKRc4|g!lH=PR0nNCG4mB(*P|Au6zszPKc zYnAR_h~X3W8PXQ}UiZigIdO!ZtU9-XJJHiAD`D!CYhy^KvEx*zHlng+{e-7ao5vNQ z1Lch~f?E+$;V;_L55a?96rnP)Ew_Y8rTos!j_&%Bm6Y3iC-ZFIo{ed+0A7L_+2^hA zLp5yku;Fvr2;^M--HykEpA?rK$7mcoJHUCC5QY(P>3}BL#L6y{`^$blcd-SeRV+}U z&6qmm(sH&zW1SJFk4Cr&^+-^jx|q+A5GJT$cf$vGANU-bg0KYwt@XI2K9Ghb+d?0 zTIw4IlfhjLLyml4HhSjc^NN!p!tvduE{-&TjK!byPBAiMo~o|aCsvi<1I4^W zOqVi&lgCy~-AX@Nc_qDHK@_(+vYMv(Z*cBz?GHpM!aGbqDi-O-N%!&G7GnB;_~Vl+ zs%a`b8rdO+Az*CKvGkl76OY`Av0ehY*)g8_Y&v6S;3m>0Vs2V8%9)A1W4_}))$1FH zL#`%(as8gtbga|JG4YtO$5|3pgAHAKx49Q7c+W{PxQM{BUHkreQp{XBcz6_L00)|` ze3-S*i|sF@(tJ>Jy!hXja@CuLu}+NTzN;DnH+Xqfn|b#y0DC59^n-KQyIPZRRs2_1 zzU%T`6OUT7J5ZdVJ^FlgF!0zDoq3C_X}(e$x6h%mU9={#eUw(qymEP4jRaCw^=-$l zhe0(>#NAJR=e@3j`2b_~)dvUcz?lZ0xvqNE%j2NA03uw{V;{Qi)v_szbg^-opA*{`*3+|VA;-E(lBiY=YwE3!nWE2gSWP5}6PcnQ>R?Lb;9mUjp0|B}n(k4i%GYlMjRm6sI;Xjv4u%ST4n= z`1(@oxCVwid6C`ykNAF8{~{{Lm+xM*xzu&=o_elkr(;x32S^Mok>N(PHp}=gTLejM zQzpr_z)@@Ma&&{CxyKH8)rzXA|id{(K5V zAr}vR015v7Y<{=wG2S(Me-9Le#7Vtr<7JN3L9+E*ok8~eYqB^h8?W;@6) z(($G~*%yuL5>!9hW>-lX3K$%#c3&loS_=E=D>3GN9T*~j2vO)6F(EU-HI8kr7wPDIAm(x__dsz%d6nS!!W>?2QSX~l z>JsQ9Tj)dm*jb zHB5J2Ap+r<8Lvj6@pVZEjDf?G;UWz;%mX{?HBJ>INt- z#tgqtCuKD}UWqzdXk2<(OL>XyUaiigE!0@F`Q%xfYJjk;*#-y8W!Vyy} zXitFI)rJ*#qdU+)vwPKLaf@0>alF)J1G7=Nl9Pm!3&R0@q+s?xNpPo8$!iPxCa5Yy z=ih?ODuNiP^zhu#wO&~la-^LcF^7FX{0()!<}Dqz&*HCh*&m+Wl|X2BlMD zDg#1bNLlBU{w#X$CD4i>kK)0{^8i$Ltgknzf)Z^%myNXsuPM|g<_A2rhcO@4$qag5TmJLn zIRFbbx_C5>xs*Pff42f1Iq(&kHvz0b!lP;tq)SK($EO#)Dz}g1|Ql2a$0mD5Z z9ULX>K4+6=aHhZ>4lkwVY_9QY6)P#z&*47m0Lh4xPE*=ftDGcW4~a_f3=XeX1)N{k zLKrv#Kd~y<%Gq!E4Tf)IV8AcNM&snmlKa$lU8N1X>#OTO8?Dc_F>xMGp`L8MPsbGA z!jD&h>h(920BZk@p@}3Ex8)D%IALSf1J2`K2{!Pq9L06np(|7>>gg*vnl7{%uao=` zXPW5cwp_3owqEKkv=?L%3|T$(6{5)XK(imUFQIBXU8VnnhuO}-m?9llPOrxqY5O9B zL1FR`)_TqSPWEV5?^Cr9_}{8Fcfk@Y=p)(?mo|1@W&|b$>+%xJPh7-1lC+k)A^pU(>acxVS^J7 z&p(TnHEKHgV|Z82I^j*H)J{DBc5IPZ{_WJWA90WVks^Oi13$`)#*Dx+*VsE9jIoJ; zIol5=5~R;J!o`E@b+>lw5Z-@yvhCQG%#gU#t273CYvH$GhL4br;MvH`>Vr+E`_&y} zrGD4oDd22hIA-Yi?)w^tz%dwSF~NGT`){GR9J%!_d|>g)lwHw>4*l^!g}v`O>z{DD z*9Z7lI(JcXL=G0%_u?Qc(Pr%kRlMwSb8}Dmk^V7YCSi%9rI;IvL}v)wT-T+(w{O_G zDgQXhLn`gy66Zl8&||pM=<|hvjx9`;oAjE&tRHp4@8NNFW*^--Z@vGqK`Ax&1qYZj zsYl(tv?o3>9x!-qM(L}8VI+3gnOA9eqrvbuc1iv(Vi$ksxa9}*piW&?)#%FyJ^k9< zR*8%$7gsGxEQ6lo5S~Q9%dzjhGver4H}TtLALgt)om`~3U5+f^&wm(2h-4-7n|3nV zhT>-z8UoHI(7HAX#|uA5EJu8_lRT4JwrIn8wOMe)B%a(m`%;x&s#>4oK0@afU3)f@ zu92CrOTx7?yDLIKcd{R=94a_EIvO(?MLvi;~^(x^T3F0(Qt8GZlvGg&d$y?vPxagFna>;M$KaR8hfe2 zXP24zp%Sc|8%gvKux@{Xc2R|B@7Nc;slV(ufB3O$(Vj|ygmalT{DkAd|DOd2#zbe2 zx}I@`4N#496hekaMj~@*IH$^k`IviGJ}>pEl!d(>HS_IVscr`0p`IV3TWKvkFT~1u zgjJF3Z1w0`tsRC>vaZW^0<&_lc(T_gU`e_5f$d}|k}PkyME41FFRM6tQ&+*f5$l@N z7w5aF&Gh#SST-VrZG&Iwy;og2>V0gPx5_7f(bw77rqTf4deUU~@NC&BayYsAH3-wp~xFSdG{0+eog;dqHfwT=%j{MF3F4|POll+Z~@!JZbVB{|L7 zaf}QaSb*mHe#Ce|VJg?Mvdc)1D3Mh*)ydykW&C#N2D%?sg_^61=_D+|b3q~vwacRx z-$x|R+6+{FzQQcqcnPq@WOW13+IpMsRRhQ;D>A$4*u|T0mwo6Xto^%c%+qSHS+H%j z#F+x=Cl2+~0^him*z^zWtuP){|O#bC?aH1UPQh&9@ zt>Ra2C%ii2oI_dd7ppQ}#%1Oj!$s_c^NGC53uRL2TZs#8|vUuLVY~j-XAO+(;Fp+La*wf$R zmiSVk2L>y>JlY!SARpov>>E6$8)$xqi;MfsuYpB1cWk6`BQmO)A|K6TJ{_YcuaSZs zIMW-}9@Z>b^jnu6+H>%TV~*z5ZBkd;f05?zA0VNH-C>nQbXWhArWId~U-x zlbw3T$SFrL0bI~`zrI}xz$zFO&iI*us|*nLZYBW}*kc*B@lQv6UEZa(HeC`Kid_FI%iq?yz0MQ%lws;|sh;gqG%;G8^9Sf>&|Nb9eE$J8~Xzqt?Sg z8W%%s;rUY6h}Q3G`SXFf!A|nwmJK2c#dEs$KunopC+f@B7P@R4*#g{2!#V@&NsL#~ z4uVE!$}}DJ&{IcrFmW!Ase(0-^20S?N%e(l<%Yk`H!T)A73QHUa8~$}zjTJ7m^2l5 zIWLZ|XCIyQijTO@oM}?%?x&M$n4w-mor^=SU2x^1JtB>%cB)&#p#Oo6H0c|?lu@S| zBWxm6>z~jx%CrBxpf5|I-u_x}3wSjtzdA=Ag<0=BIPy-p?w`I#CD z=poZDCtyaZ@6>%6xa`%bl|Gr#lR34)(U(!I*=~VlT)Yp@T zack4YR}w?-Ohvw-IVa&TF6STNIS!Q>(e3c#1vZZxwv_$+aosOEB+GdGe)7iY$-X$P z?TUcEAo7B0GX}Z-Cp9%_$7)Y{+E)yV3Zv4qX=ujQ&eYt?&@YlziEbA=O=s3;+P@CH zZmlX{G>|6e?)5E|4R_da4#~{TahuVM=*bgbwaz_)yXEBYsd(DD6B!6CiI2Vg@ah@- z<6)rh$jY;C_Kt$JA~!!XBhT<_Mqq_rOU|!$(%@BUr3UMnqftx2%<{SU5`WltviwTe zU9{>IBCi&mH=hdT6m?cNt9GhPs3_EBS8;8K1Dbm_I)BwQLIKrFD{803$@1P>k5!U- z#>VtE0nZRPEpd0sWnENDr@K~E>)*}GyJ(!VTv;{96jiGv-G1vpQ*gy4pPAoYDR8S- zhnF3yPQ$l~`$i7E!>DzwjrwDnO!gu4U27$db=} zQ~}3+^fOF4UOcwomLQ9C=G*TSzTz&tbl>S4ftA*m^_69NH&%Va-A1-|b{4Km3|O`- zMrEf`sPPNhc|T`ewe-ZFPLy*SIn;+}z$qpTV7uieV)NhL0f_I?XR0DwtfA?pPj^ZEqZ1N9% zE%kc>-TjXqwVx0zy$xi5B(#4b6)3LJje=bgIdN~`6yp3lq7v99@abCWym zNGltLj7Vv7VqfT$$lk`|44fp}X(24F5Dvb!Fl?uxM|Yh|j(6Tmd%nybP!2u$@zI}m zPeCkOKyJ3M`S5<6Qu|-xy=9d#LOTwL5<$B=DIY|&%U(k zUke&6t_97gC{`|)Fzv!;j#xm(i5Wzmy`V`|RbR72FjueVP$Sk_;Exs}@a_edyKI#W zD~IP9U0+d3_rsY8NO&Jds0=YEpd9J^*HemTCbulV?M`>m)UX-9f&VPgo~$lHU(D zG3P)_>H6hgRh!PfZikjoP$lC2EC8+i7n_A7P8eAV!jY=}fUD@eJgoloW&OP=O zSG+D6-AOY&G_f^%1pT$aPVAmP1u2M2B!n&o)brJy_5@?eePDL6qpPaH0Ae6yIJeJ5 zqQ~G`7LM1F6#laBCCwzyPk%|4T{=&m)fj|gnD0(Qp*_1@Wi5U_SJ+c7E+HZ?A!DJd zvI1{(nU*&vj#FQ_opSBYrw-(3W0>bN*#wgE(Rj;lGBRa+#0)#9cOt`Q+2kc(3G{3h zmr|RmOOhj--0Uibbq~-VA4QA=jd>8Pl?>#rW7@ZhUC7+u%<(RJ<14a>Ui6oYy?TM^9b9)Ds~dY!?U4`{K_uGZ}J!pgp**bro3I+an>=E_Mdf#s9FK zoRiBSaKVEF=jU^bCyCUF8#rAVCqW&Ou0W%h2>7eY;|7x{;Go=KB^SJk48wCUz`HD0 z2TO1O$Pc;Nw-i6(OOy+I44Gf8=P#0*P9^g`$i3oyh;QpJ2!wexE?zroQ#H^4jNUoM z?=onUAupfW*FTfRKkd%DgatZ#CnV_~HxX9`1x&@p&&%Xio2{i|_KFqr$cVyzco3z+ z!1KLVC7P>hv`9wu%!ZctyIu&9POw)HPru+i?4MI*55xj*soGFJG7fsPpyhV_O>GkzLvaUl_2zIVg{b1&b)I021b9$IMJ z^#?~Gr$K+74Ko8!Th-~{A4aG*50>Qea9-82@WB3=YJLVUm?hH#eeW7}iy^ABm33JF zCQdfr!hY%KmsDgp7!EM?Cd~vJdtDoEt~nIp-w-<{vA?N#eO**uf|q#IkRH>jmbG_T z`?8-yfGBB+GDuId(GqG(eWlC}KbprvGqOwQJk>dF`>K`^79B#tPMO2(c6yfvO23KZ z>w1K?>B$zTmMa^J|Eu!OHFFIbDn2*@9qegNYKd=0vfq@<38I9)rS=J6+U}LR!HZ2q}Oa8n-WG@x@Te@e{M0qVkyk2y>vfQQF5PTDB38- zBL>HD-O9T`P=Uw7oirWEZspFb%2=nguKhvxU*9@zeb*_wBw9Dmw0*RKY;OM}LhrJS zVVc-k8u_I-Er#v?grLLR-jTA?dw;@gwax1t9VRp8kI06Nz)n9y3pjiKAdnf2AWdX7 z7kWrv5la|aHyS2<;kIZ5Na=ROP6~I+b4d=A?6x|S!XRbCgm84n7L-hNA2@4adT2Lc z{ItEFz8Whf8Yv&48ZlW(_mRB}hxmp)?zj-~I<>%3C{5;B31W~Eh;@uQ6N$pNA)dp$ z%!lI%1Bt3%El@H-*oT1uskKO!kVmo@jL=a3y_R*unocOzuy)k{lA)Y6A_ezO4^p2vK zHL)y%MS*2+s%}v0_d6tPFQk|JypbItvySFCNwqB%)=tS~LT3Y#C=n_Vb1FQEa_cx! zT4D3o9oLzTk*W)n=AnL>ep&iL)ZO;;bGVLhmUYZB9*19|+TutDIB%?Dv?DMM_i+#x zi?$!|IP$E-#+0#0$11rw88YhKB1_HloB;0=yW-b~^yf)nmAb5u_&IF!97qtY^x&WE zy5_0d{(po>d1B_B$&gKBuXx`vzYusc{J06ncmz$z1ZKaIBsX7PcV15kmrtH_p4%ai zsH*(({>}`51o$3j0kq_jVgJ>?ICS^60D2XSfaQKK}k538avp&R4R_ z?GOAIDHrIj=0h3#bN|HU>@9~?@EZfo&xBUJGhFovzt1W=3rh%RxrRO6jWb?<&s+l? z;6%s>UbKcrfM|21LeCE#ha)C&6!Emb86fcZkEraBi#>qzXR+ZLg;= zkPqCz997xh>+9>soG^;TBuPFgx2N1)lbvEQZiRMT&-ii#m;jj;urYl%i^5a3rai)! zTeGyTh{(@Kyr}8a=()Ci+poe4ipD4sqaKEZP)New+0D2u8x%{k#(x#3$mtW}+7XRL zP<G zlUc3sDI1~dgkGHP`e;FT@v@|LbjWf|@#p&f*-Wat*xIO*M8MbsI3!&ze`=Q#tyA4f z%7kyKYU44ApDE9elKI7QFyp$sb&?jtrh{bl6lOhw9t!k4%DaZ-^!D@BeOSJN-2rPs zr(a_HH`7xIi0VHEpozl%qP;Vzz^O{>*p~65p7c%!x>OiFoI&C14(&DB_wWhe=Ds;~ zUF|g{M18FIGVIh?N>Bm;95NO3ejVPzVkM-yCdg>`m|Rimy|8cZ1c!)dq-bXt{_>Xc z+|sSSi8E+gYwsNxr-=@9mhsOPH}S`Qnp{qPo&j{)xHnh|1X>cXm=4H4?Aa_+8ki%; zzSRr*s)A^Hk~;7U>(t9z&0o6!IQ%PdKVPSwmqm!+1;woiq&s{7-7O@s$6U1y3=$;U z96YM{CgxDS{`0t@T)RfzGCK0tpd-@ur;7)d-$Is0DZW1bB zH0p{xw4yoT5tL@PxZI2>4u_NYN`5GF1|5Ylb?-SN8`$W@d-maUn}Cy`zIZyj_i@}8 zey{%L!p7&?^eEj>r`k^;!XacT*@f`qBuQYvrU}F~c@mc!854P0?bPKS`f3|BiSU9f zN>!hb)%8F)0%LSXNIW$CFL*UYCP(_(PH}a8Ms-7X>CYC|uo@Kl%d4&_ttVN&4Ea*p z3P8G!DL1yf{b_}7)|B$x#F&E986BpdP?2bCXfQk&&x*+X71&&8;zN*yOPs+ekYzgG zpIwh{ey4RU3IhKXq_leU z34d4WL)k*5^s1ISe6x^Q%US4{shkbgnfR0~H?A~HTkQ#v)c<79*T&ic4>F%Q5;Za} z^^DC7J!%^-f)Rf=h$YB@S83#8d!dgHWcfaifbSXDBO7IV7HLjZTuS-fa0Mvbt?%cC zVY4|Pl~7^&5~$QFMn?c|i2pm4NBA~r1Yffi>cC4TsYoD0Bq7MU`^n)B8wP`s_JTDe zG5C$tOqf79xZJ*24;&%7aie@J%b#N?0LyakJhlCwE1LXZWbyqNx$ACCI^3t)ILVMrW4yxd&&li~^g zUw+hmkyQ|rEYZ`6@?lpuLTlA;603)GpF&rEdQaw2E8Bxm&fnW#c(b;1EDjBu{Yyjg zHE*JvT$f zx4PXls_zUeZSTl<+$*V zPIGD4fB(Kc)T}+8=Z>hX5RGYxx9^-=+vfYQu;dopF_X8U9(3eQyAQvs>S`|G|0vds z!h@n1?tEyzTwzViejaZ-;7EQMo^Lw&@MV8&&xi~8hV%kdqmQ}8O9_c{5+%uvS%QED z^>3)z-Mjg{{oQK3si~=)8Q0&MwZ3bZNy<)X^Krt6>qrKbf8=7qr$9h&n5t-3r+PAQ z+`nrg#rImtEM?^MV%-dbzgEtPrrabHncQ|B%Ad3Nm%7GYuVpqCK{GE~I__!KG*>4Z zIPPuo;9O*!3u=SDEH@g;5cG$1Pl4$#EvzVCc5E(X}ah#k@}kh zBl(|l0S-*qQf|fZCLub1>m?j_?87D8zrx;P#$d2DwG+GFy*^huKXm?6!R^0Jpoa}J(C-@dq~8>9%|4qgP>&~T z=UtK&y}HpCwgL_tlRPW%pG77nm*5MhhIE>-?ML46SAfnmz=jPfG@Sy7Hqk?=npTZ> z(E$7R=(*lIhq;QV?>;VK4RR>h(FpyRH+@F*M3e(jG;3iU%JEB7tnbzMnMkr2aea?a z-)rZpY^NNLe3LExeSk#7@VPLFK)?GoL%Dzvq+9RL@Yp*hCpPK$16$|IS5^rz5z4z~ z&oqb*oUlTLnqo0UgvAlZque5iP4(n=i}UG39zcfcaZCm07o++;prYEm51&v{Rypp{ z_&TFoKMwU&>s#u@Gz9936nj^1U+&peRV;~96RP(^)*{HtY1P41up&yU7S7d;zFKKS zPgs5J1En{=zpB1h0T({X+gYSIpCK=Imx|(#TvoR-*JQpS&@hdhdT94yAE_(&x*JgP z<9dZ7$xNo_kmeZ0cq@v}UcLl}T}HVdXkn-POY@}I&ZNsZpDMV1a4o^RDB?GHu~adi z3v@=m-9tm7Q-f$}DFnL46v^Q$o_Q#G<(~@@3gS6m-ctv90A+yT1z6!SXxqRqfJ^_u zCWIZ;UCZCW%vJg|j&WSP)(87(h9Yf-XITTYag;6*TnUlFAv)UKX?$|!D={nQCwDEmMz3xF~ zMT^}90NF=&BT-31Q7aQuU-ASTBNgOj9q?Y47`%S6>g6ThHj6Gay~)4v;Zh&Lhtng4 z2Wr?e?9fKtBNY02FXIz^vV!ycLqG#MEGgU7EjL7Z?6l@06idM|km;J7BO6GtPBVlU z3^QZwqd2L{JarNDz*!DB>2~JL+-RlPr#^6X6`?5w2A&U9(Qq_T@cJVvHRSqXk!X{! zF4IfDM9S~o+&uivcau;2;*L))Dh7-uUn(R)w}xDng}xxUMK*}L(K#0e_$|WY+pimT zuhmxEJFaoL4*Q$~Y=!n)|JqtxTPt5J52dU`P2}XJxb|G~%dV6wIE;&rf9`5iHLX{6 zRrTM*7A5wj#NC%_sa1EYj0te2jE29W;n4S^&jLg94|#2BV1@^ zoIHC(cTW7N|u zI~Y1=mtGW*n1juWgC)!(=;>(uQ_kL(*bmJZe_^<5JM!gkr|h3?>m{LaMzO+8$ZR)9 zf**zL=xtaSq(Ao|6kU^zFcD|~rUyMy% zYB4J@@W=K#z`C7F2zz zs@e)7D-8pyCJ+BN*^HI0Znk#S;^2f}-!j8p-rYOSJTWacc$5P7Cy-@i7{~{0<3w7q z*s!wUNNU5+_D8GD+%C_1wrf8M!NvnRbahrkdieJV=a&ZO*597o zl^g7B@h438uEWkzI-!S@YIfwc^k(LMwXc%guEjztzsa`#JsKEZfDR zt~VZw`EyK~bAh8U{63RZ?M?KcR8SQ%6`<(#l=zeFE~7JDn5;_~&(FsI00MXacP{`o zIw>9l%%xSh`5oB8ioJOjTArNvW9;@PW%OQWvmjf8dPi zTc{|O<@51wcxKhL41H91?dR&rPYpSi6AJXK{tb)v0zlR#c-4>WAZwpzDvNZGAz9bY z@0JR>pabC&^c$7W5%0cY{x9wV5&gTU4OKc}bVsZ!A$7979{?O9m!UCR9Jmv;_T7EKasohC z!g2>%k!uYB>qZ&Ne!L71^9_!v&y{XCQ>~6`yKbR(A!&X1NlW zSHLQ3*V)z>K4j)G0-BOn{8oI}@d}X5auqapVbx{V)z;hF+uP&+D}x=4VM?y_JHAyv zC5y_H(CljSO5jy&D{bz;%G2-oM)IsprCbTju68@N#1*^lHYEUO$pCEEzuHE{f0jGo zc2)bG;99ZoYJUf0Rhw>q&*m<$UD1GqI}OPG369-SD)1IFZe* z`gHdt3%&{e+AAj@wHwp=M;Y15o4=~h%G=zoH^8&})*t3xIdM;QWr!{S zm5i0FZ+E<`?{6uE)ctTzu4`lGMMBoMJ6_iJ)k}4bueio5+xP*%F>=q@G9|n9-HEl* z#&2AtUFFUn44JRLWaZU3ov}LG_{~44v*phFEz|ZB0LSRv+N|3AFD#DVQ0|_GjvHuY z``q1!f2F6if5m7J0Ddc9aGQ1a4OuN$+&sT+OjgRPZoOU+j(4wzR~!>nTmar#?w-Vd vpQBuz?7x zqxufUulFZa1#h3Q8zdSiVKmY%=d#o^BC`L^C&hYl_ z+s)PDn5Ki&-DBReef#-$I83kPzi{uK-R^QmBsU>Ue`@PcUH$vbsKwCO8Vzc+WHKZZ b*H`APu@3^;LcfrASiT;SmL0sDY;AkFti6v?jYt|mEeRls5; zvdNh@-CZp9NTau3zkdBHFTC)=3%?=$wE6^Ic;ST?R^eOu30nR+^*mm9;Tk~m<%LV& z8*CYI{EIwa*bOftd!dx_t$h3#^=dE*wih`*Vc?Mg{vtk$i(>}CeegqGURs5AR=xfD z=RadNK~yAp;0qI?kJyy>!s(|bJO{Zc@r6B=0Doq^{rbNS0V;?sI>$xHa6QqnxM;d5 zNH0oslZo=8o)RD@tNH{uf|uC5<2EP4>k%G;jZ@7_d=au*tO$G9*h@jo$*Q+s|Ms;M57B{Rej`sgF+a1~1lR*ZT3NOWNifSj zIN71dOtnQR#*iOFVlxPGfGkg4hX~hZ)!VQC4Jg1>c9Tg^?IJzlAyB8<#1uox4<)Bn zb^tEyB@%mNRhs}?K*(vP%>)uuxo8dHji5@i3F)OIznL~7T*y-(_R6ZaUw{8QuK*P! zrZ`3t2`XHqa1S;|G({9CmY7}^0a|3FAT+@-6jyn3PXUN#mOiWAe*Mqie}%{>ljy9m z2?V&(MRE78B*TQ%$|S!`(n}`9sF&A}U?j8hvg$^FHN2!WyRQ@}39fKa?)KQ5D&BG8 z)EW_>mw+<*kp2N?d#RM!BcEp(v$E=-mfD$T!uja5pZm~uq>pJ|h#4+w+n-y}(D#fv#%aeY+X6G{i&bjb?Lifo=_U>7Az;Hl(_TP;Jq6ez zp=^Rv5@pG~^6cDsOI0@cX|nK>0MCe$-fY_d0WxmdllWT5N|{L{IGg;kYz^!}ggGR* zLuT2wpO3?8ZF{XYk1f*1+D<@*idu4qNyd`3P-=)kwJV$8|tM}^jF_g zywD+o{4z4|$B9l*B8!sSM#P4?N$n!sJywsJ2-Rtr3=vUfwVnN^@>GULldHA^tk0~s zU;p`E{Td+B<{hV=%drhc2vB+Hahx9o8~qNRi844zC?9p@jX^Z#tvqM| z_3<9`kOgH7T6W_r{;hnxAFpm`ee9*T6-KtpqxYyyjZHolqa;3Vj?tQqY>$!6k;*0k zip6!(nBLVvy)>EwwV8)m)UKlRcTxeO>W_Kv9g_@&3u0^2XnjLhz7dc)6e=&MEj+Q{ ziAhgf0}9Z(%BXI)FvF8^%=k;VozS-@<>pax(f5-P4LF61BIBPeqdLRV7?J*DL>J)f z_jg1+g{r|w|GJwY2j*v1Ujb&kFNyCbA=5=@g^nMIXiaPWNPiMCV=5Z&9Uz{v#z*?| zka^~c_->Ey*8rLKsM^a^hChqsd%=+a$_i|}28ig4k;ceUdQNQ-S@c-4%djnDPes(A z*Ap9ki0K3_`X3Qn*uVWjIuW8{ZBf$OZ0qcGlh;N4K8xtA^vWQ?$*DDi&;-XAc`9qU z+K=SCnUgOmZd>59d>?IHnQg7APYgX7%_hIvs%JUsi>#W9Fp3MN&l87iPIPXD^e{Vq zBDA7K)>XlC;}d?8h9GZ*M9U)V;_M|t z<8{wd9uIny;M#hilA6_$;)byT^eRKe>x&|v{Gzj}0xWjsZp?_mgcw#`#kn=QEU5l! zHqM(hz#kelm+@MR>=e(O|8wqI11L4dZ-_)fZFx$e*;&1=nqPyRvI&HN-zztSbD=ns>{$N+)Bw*lzxuUD&8byjl44}s$C4jv z%RdiLp#c>2K%v6)E_@7Gc}b2S!HB06N-anT7>A$s~-i1sh| zIvnbzDEWQbMHE|9Uqp2Ts9B*R@_xLb`^Z#|5)nB)j zPMc@U2H=Tm+~%LNrSN)R21m~(LkEcGjFMifEfTA(ocMUOjl@i^Jv!$)ME;tLId684 zkHhNK{SZ~>QGe>T3n3oJs2+$Y!N`0Q;32(M8@sp@3wq?LzHlJ2kdLzpSAc9=-KT1E zLamRK^R@I_uaYyjqLB=Y4&(Zt=H#6xri#suRZSbV=%`Jgb{Ih z`_Az8O@LPu%_G0_yYE$-hXk*cT1|LK&r5KlzMqeM-m4qEeWe(e3$NzXl3yw3kHM7k z=|D69dNycZZ8Ji2ya*~cMQ@-y_hbiEmdzcbC&8%VBO1F1`BmFseaen8_p5T5NAt!P zcO^d`hviX%s3NSPvI$^jihFF@ZnM^MrM{@KfeK`ZP(_F=`Q7ooL4ua2YV2m?gNn92 z3%%*pGvr3532js1UPMCr#vez*6G^0V|sh7M5ZlM`kvf-GTL z{|hwwZeyu88gv=@L;!CrM*jzML6OQY)KJIr zs0N5CLDl~gu^VOZw>4Nja1DL19fCq2>ZPa(yq1bwlU0}kB=F~@OrGxa*_vOW@wHOj z^>#kS{AW)^Jfl>Bd(DZg*BLz#QGpY` z8RA(?8QakUkCc5tl4U%@D7n3Ac`aluyb;@5hGGh^)y8~Aumw-RCV(L^?>r+n`Nck? zFMLPP=>_LJ(b$OWWDuJVdpuJ@iFk2@86Nf{>n|By+0S|G&jA*ruXJqCK93FCmjEwu zda3ENucr$}Iv}Dw6nzOmh;P(~5Z%u~AD{q_tHJ1OMz5pea^Q{fELq_@e*cNk$a4Wl zACguP;zVRzZnO_0zvG>np!Q0wFuAqb(7w?Qha|!Cl^c=Z?B!^`E%E`BxV$?0S&z4W z74H1M)rQ<1>$TN=C<0qzh2&SLKd-BwTbY|8Jv*lFjES2oFY&e7*toPvaF9DAPo3e3 zjnN!l%-s^BF{s#6we#e23tS4Wdlp555hy=^S2;JhlZH{W8g#D}(x zw!UE7_tyMnT(metp%8n=oePvw6?S~ajTIp3d}O;&zgDybp>~a}+@AY5J5=5)j@}!i zup^K~a_85PSnlMG-^aF{VsZA^#o;;g%stilt8k@^m7Udp{(!Wlu46$T%D4=D6{bc_}r3XP8OEEmsX`Up6*>Wc zDZt)q#}sxD%j~(>Gm4%m3-TCV|9gqArT%)afqco*+gWj!52dW=fzN@* zufi4bbxXk^Dv(isEJhD&Scpgv_iKPFRT-i>MdznjTqEU=70d>&wR1{hB*)z+yM`-{h zI&=YL6(4HX8KYKP*V6fG2o1;0_VzKD+p8Oxt?;PtOjao2dF%`*bc~nW*wwy;M_c7a zMonsy)6lcKsNeV0-)IhtAn)(LH%PDr_4ZV~JaJxCke>H$u}@|G>5o^SW2wHDE!x+! zn*;^XdB?Tpcz^1#sNGAsXDGJYB)oCJ^r_>#(bxCk__YPaxIHlA3fL0l@o`wC_*Gxe zw)gcok-}4Mjd=l$!J;ir(6`ogubT7PZUQgqmBOh%h7>=Z?HFa}Em$y0O{>+jXqX{7 z|DI~B02%d$+9K~q5UW9@`z)9F-4wIpZKM5O+Xk3eiNswr-Wy{TdcD=Zk$1#ku2M7` zZ*AimAo_l!>_#_3JnttXn<_9j9k0<6xKi0MRjdVwF1AskGird0UT-10KOYRKdHSt| zeY~`A3UKtkOn5&D%q91X=iSt*0Wwvl(ahGFG5wQ1Iunhf`XRn8`ydf|b^zH|e;>7% zAuD|QFRTW5et)#p?>%E!r6*E{ofP+dO^nLy(z$BTi|uPWm}`C`X(#HtQAy2qI?bTKvpeK zRR;vY_+1fW>ew$m%`vuP+Z5PGNh)LocQqd$iC@a2BfTo{Xm6>po^p%MF##+EuvCPV zck3G9xi_i-6q+IVJHb(6W7}EVyO=;Kw2E4ws&<$Q1)b~FUn%DrV6QmLtc1mAAN`0r z+U|tna*z7v+mBW}ma3IkM`3>l8ylW>mI%T2Jz@mwQ`q~Vlok9w>+xqXOX(}Xb6>BW z8FTcp3NJzZDL)dx1|g#U-k(}~nu1kuthN|oa@~+6yVe4K9^+ApbzfCVLcGG>wN+l_ z9HlsmhBYL4dm{81_3vp!$j#d~k^C$uT@as>Nfj@-dFM>RXeYoDnzs+x@l?B;zjTg~ zaph+bW-h#05$pTYQ~P-p^9I8xz*^hjbH5jYEpsNJY1AJ-!tSeWlzkIm5oCl2tr!Qk z!-!YdO8{ zZiAiUM~h-9_TpysBir9df8$dWKR)_f+o)o@hT=mCOHrEkX45BGJ}bbEL!WG-fm49~ zvz-Xh%Zk{H)+xrOy`~{SlS$KzjSvV4Ms1jw29%}W$9|g;HuNfRRP_~lssUC9A1S<% zO>H+)Yd-;-^L*?>5=2l3m3O`Rw5h*RttO>G;saR6N`Q6fai5LJICyYHPbj0%jZ zLB_@hHKoqXxEoov6(FJl&$gZ171$fgC^*lUV_XoC$6#f-a;zS*D3#F` zz2i+rB+k4sP1G3~6?nko1>XYtc)S>99XXPD?F__ffHitSz^XiUTs?{tO>G9N{Bd~3cWD6|YiYCW_Cy<+8?P4yF@h_fE4kxFx{J1{8Xs5fU0GO|Z8N8by0 z4R8c2I220FQ%?*aBh`CV3eMHFW{9Xj^cWLsdrI_FninHc;5bI_Dl6}yE7YRzsOq_t z%faUy&kC>l}=}0kFZhJ`h->rQd*#G=rkTlm+4(c3AX!#E7WBk9cj)^5`067e)RO zkDtTs|1r&E2jN9XE(0i0?zN&L5T@wN9fuewaqYB3tp}S8G4)qUs|NVk`@(kcrj}P* zuyzxGY+*sAM*U;vd|^X86Xfl2STCZ3;9ZBYf=;JRR>zAq*Y}}}C){3<$ z(Pq}|v_Mnhg*0490bZLZ=g5l3EpRqLA%StxkGOcxfmM=AA8#Sz*5f;b+BwP69_ z32SbsSj060_2aNSbr3ZYSJD}m79}=6X52wrd6!Ov8R{(I82RyopF_^98M4EFOY!kz zFzOFMU+@FaC^ELmwi`$5^9*&jgI?*NUZmCYktFy1V~!{G{WwepWh=9;^*AhbZ9~2K zI_JnBC&e86ny3f>eGn~Eh>Ez1#(7|T?spvG@Xeu6cnaN%U0uEg*mLfMAA~T%Y>M&S zh_Nb6=#f`G9D#tB^t?pp5CrcZy2n*SRNj8du!RWGMV62Ht8fwJ7g<5c0`ni^5)pZ_ z3p0i%Nlz`sbA}r}9xJ*FVeQfFv?E`XizI^l8-BCmgt=n&o(q2*R?Df@j~Jo0^_YbZ zL(K{*CTRO5+}2v|sW8>r0>NS};oX)pww6614!(c*6r4vXUdW55vtVsKnPc19kHZ=T zg(r9rB&)j?JT4g_vQG7FnChYW3~E~hBHh8n4XfBjKtJ)&$Qj$0St*TSP1RQYkbXRK zdRG#A92TnPka{9ob41nPX7xZ-P;*-&L^pU8V$?8?{LULsniJDrSv(31;dRukOP8qFPdO z7IRFRBgO`kx;5ZyqaFhu>~HjWTW;Pz+JKF z?F86O+(>An_ME#|s#VxWZ=_6sSG}p)2MVwhh2K9hS|CwqyvEMLZn70|I=UHn>-+Yk zwiv}`sYO)v^%UO*N|2=lbPnd`$8+0ATcEmw)d&hr0nWiJa*BnLAwEzn9AAYy1GyPu zwT+l5Yiy2og^j7nvGu#&9IdnQ z)E)2bKN<;PmqhKh5flaLxlr6&6yKjz*5jDDd*`wkXhoNuBUVLbE7-f-x_O=hSAZjo z0*DPnb|vp6zzMIraHZ^e7p{~7-&lBRuhDBS3)=}O;wbl12yFB#ZgS*)3gH{QY3eDv zgSc2V*ct<>yy2J+{&ISQ2esc9Ud1-j7L4vVfhEII#@`}RlI21ubol}HvxvuBKmK@k z{=c@g`g%uYpv%1ehfI2;cbCHno2>RpWH$l)13Z9`Vr>_(DWJ_^Hwn9W`f!Nc~CBM`QheJ?OO z3b1yQ+7$=Xw2}{|I)&X2e6&SAsteWt4=}{ovPZz!9`<4|o?$)^9r5CMY}>l^zjcIC zcE}vA2FM1;c?=tb$6YyAQG&&c^vX!+iWl$jg&4xpD1#*c4LB8;xVnU=(bf@$dIB^<|tBB+ql~4MrbWV;$UfW1xjA|ZT(+#}&4D9!7dRS7^&Ej0I(E@>)(Q2_kbGh|hu704*@JJkNYB81=#of;*seV-6y! z&YIJsEoz+Rh^jFKSt9dq1f?hHIY%mRJi3%QS*Oc3&BG8{$PUb;V_0H-2GQjl!&AFq z=SHty=PyJQV7>iSBP&+R+}O#B-x(P(FYDGka6S@P;2Hn8AA?QJ65+btjAaELbwv`bHIKUQ;kWh^Gwp((dBc_CP4+VH$O7486nPyFYV^Cg&l69 zJpMJ08t>z&C5B$$c#o0vxvWe#tWk=}4_H{*!h=B#(1RIU-N|HFD>nr+p3JGmjgOI+ zJ=%}K)GKy$4sReg?f`p8EyE4DM3@nLia7``AnK2Wnh+C7a2NV$(;72V#{Nq$Q9f&c z5%uS-8MXomnZqL2Z=Jb|rb?l7<$6REU8KU)sR1GoERYYx>OsP8B&w$)kHR0mR0Ff;1Uvom1gHxV9f zgv_Uk;dcIH#RY<#4B;M!h13ZVb%?0KIsjXCErK-^AmSdi3-id0S>I>QN2)-JoXEuw zB12|zM(h$W(;Hk3FrxmvHnnZk<_25=616wCjUo|FeJb_G*o?52EWJlnUm@c!MARP> z2S~hG5E9&sI8jkf+pAF@@0BSxy<{mnMStnoSZdJfuUGQB&5uUV&T!8@^*^R=*Fsc( zj5I}6TO5%Ux#*?z7odLhc!}n zy*@$Q7Gl4-a4oKSwFu1*aXs?dJx?+X>2=kO9y9BUXTp(dOK4eNAPkl^#3u2;E z`hSnuMmE=xBaWc6=YJKBQGQ-!*HU$eZG&hP>W^Kg_Iq;fXnoI`W26G>wi7JUtHBam zYcXC-jwsM8%Gx6;@OWLnDv~y@eG6Rn^%WrFmt~vPKf^1N)=ch zZ+x5)jR6I*C6e9DcyemfPok(AV>N*17zzz?LR9@_kYl8cMC7W^hyZ=`&y*U^h(8QL)g}(+ujQtz zprs#LADyV|S~osgN^hk8YP8yV+uw_0O{{+nS%KF8d$m8yrf%!0IfXJbw!sIoL^?C~ z9#Crw=iDulD?l4-gSJiH3isf->Mf{LV7msmtE|B0X)8d)*`A<5R$!0fYrQWzH$}&^ zF#kr0=PW%}&AH@QK4ol1V_G&XOeVa@W3j9@<W2cm-MUJO--)BI?f?W2rokG90}> z1#r|&sz9@#Q;J5NtqG5!i>ko;YiluMNv<`f^%0xV`xZQ78t{0>8e?5)j|#+VfSzpe z$P+z$H9#aFqwkrdXuMxRYS!Ae&sI44mqt}!qd)5NGU5FsWXGB1y}n3bNXw)CvNP}* z{O15`AWEd|-;9~cHFG7L`qTXTp5xri& zviDSb%L-coG64|@E+()YH9+PvX1mmDn-AtHF;@Z5+YzF(Y!%yIk1YUYtOPZ?g{urfbslZy{A!-o7j9UY1DpMJ3&#Ush#5e)o4)sRDjVy@T{=W0Bg(B{eI6UOF9BW;GhS;y38p?$=~#>; z#y+xQyah&_$^;b>oQ#d75Qt#3D#R* z?*eO$*#ykh?i3rs^M1}gI?K`f(LAcf7zg(-1STMmfVRf;0vy~PF>6$on`-Pqj>^FE zYLC-gR;;vQ#)=IO(Rm0@Op?mjiqKTQe$G_WBho-Qwh!Oqun-03oumH0RS!hwIDvJG z(oOR|{=%p{b}mD`QDa+k6`TY;B^L$J^^TDYOUWs%$TqxXBr3hm>t*Z|B7 z@;jpBr*spG*s*3(bMPv&ae-`oStOF?%9vql;K+NAM_9@Ao5wi3{qQ2jEbsPbW!iMVWSh`B;l6gvzGHHJdZlG zRNTlGQG!K7ek~}}Uk)L96dUu2v7QYwhqDGadcuo`pp?WYM26OGL7@aS`=M1?^f<;> z15^hb6VQkf{Lqn~$4z_x7FJepBAS=10W#!QoVL9&2qtfpRg1G<3BCi?o+Gv}hY-2% z0wW3!QG<-yYuQ>#@UXdqllJ@C_~6k6$ULoiy-Kje$xlso$=hC!&Yo#=#AB=mSc-39 zY#~Qhd@4XB7)J00lV>GAziuf(2l?&orXDgYi(cAxTuBf4jmD#Wwap08@gjIsV5<$; z?eyB(JxDAd^Nf$Gw#j`YKH7(Uzgnm0N6_H>+B9k-0P&Z-J3*EZP>aZ;@cB+UnmFX&{^Y_Ne`N%IVBp5fUtAxT!*) z>&KE9Vvk}GIiBGou67$UR~ugPLlM`iBk(st&>)Hgr?>5AX?|p)Rl5CA^2skUpH?NV z`YVV;h>#ykaFI4A)UlxSR4*6o7@QG9xrl9nSyk6-LsTErb|S&-_38J3QVI6#%9z}& zezdK1JXPC;5cE{pYXS9VujV&Fdi_=#+TUwy)q#u~APo5>=$wVf*vJd75bJAeOlxlM zm<^CY5576k{Sd*c!?Gp?da5VPu451F%{CoAk4U{85@$9dGle)I`XTUJ^k@RbX!pRtc8o+={H~wX<`_Y~zo^ioRCQXOQ1$ zeNvF$dPR3YaVFV;etH_TSLLe-?F{vN0x05<&4KYF@vSqgRDY+pqYS(~OfsDTJ&VNS+;msmT0IDmt!c%>o@I>)GG9mUkz^vB^0h~>K*TM|S zCp5-L0k&S339m1T?8P}g>nd5%M!%xxt^HZ!5yclBe+p#f`ZOZHHEPa+=Weh{UyS-X z?H-cKBDqb7(NnecD8bU`>$Ur`XEbI;L8(1g{#{_p&KuB%G8nBjv&e6R^_u|C8H@ro zpa#53FG_e(ViZChLmo=Obel)r%{o&aZ~sxsuZNaz!0Xw4-Z?6GFR7ROGWz-$DZO5w zXG|&MhbDOEEb&D$qt81>2i~i*nWrkuloZ-N%{M`qK5q~*eU0<^+T`a&)>R=@0;2$D z6QdZjVExqQqv{w%&IT zx!M^@ke@da;SuuFXWiSsj|k9uA0f!>xea(-WR11@BV)&iq>j}eAwgvP2~pC?Bs7t7 z%=AR&a%Ce+QbhaveX*M$*#Q-K-@!#BLT#dk#gjl8dqr+hyNQ7;F* z2;UdIFF^3IBS|B#a93&AcNNJ}r24;Cd;VHfbSjrqpf!K`u z-~P=*fUUOOYz)jIzKprXm_>r94MKz`AY{{O+s(#+>gp=zB0bf?%*=}0JQH9ke!@|b zmva6S(66#xll)4VpEjtSkzSd^w_+{;JCa~29wJm`6>6uM3nRd*wwhhtX?sEjNzJwevCEZ@e+KZ3 z9Wn*8efw*R085!qf-~Ch*oF8!_BgUrK%9=5M6{|M#NsO-vj0SOPJ!xh2A^iiaAh5Y#nVXqjk#TpZ2`sA*=_e4mYKuH& zV0LEl%l8F-3CggV@N=U1`e8bAj@Qoc4U@5soHSrh< z(%EGWKUSs}F^7V9GKrC~abVI_7R|AP90)uN;a{Qz$k@%a5kW;*Yl-g+)utzR^YjE2 zAZa@pNZgpEB#V9(6L2(T26WU_2M z_6D*DYG2~3k(CY!^D@M$%nVYx4)L`xLmLQcfQm6Q zj*)~-ymZI4v+C_TLx2aoDlDSjCf5BJT$}Jl*spT*2fRcyd)y>!?5P0eWR{Nr4=6|} zI>%&U{JMl^VZ)mq*>h}8d_7!`5Z7f@i~!G26VYPD_xlo^2Mbe9O;Q&nJp}8Calfq6 z5nzoO1UBIbFfXX!NWU3m^o0q}3m;KlGqc`G76Dq=w5IpM7sQL?Ug%&Q0ebNw&fgO+ w5_=&5*CW6eUU=aJ5n?}#{=y3{yl`RsKRYrR%_cZ=NB{r;07*qoM6N<$g3B>&DF6Tf literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_L_8.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_L_8.png new file mode 100644 index 0000000000000000000000000000000000000000..6bdb72b802c97f5981b6e59a0505d9f390d3de74 GIT binary patch literal 17323 zcmXtAS6EY7+YKdv0R=__L8Ll10!SG{2_>kY;~+&yLX6ZDETJe6dM_5LLlLA3qaX<_ zfq?WPp*JN!2u)B!2?A22`}1A=H|IIexi}a5dEd3yde_?fxs}C@n65-SbnPYn=;0hW zW&Nl{A^wdIN#k3bxi!DI&~J`A=)=_CEkD;bH+_5+T7PbBk$t6)zEu3Ye0h8N;sbyK zpAsvk8saFK;5%(lrh6Xx?Zsm%V;o@LxI*RoY#uvbGxg*nhZbp@jNc_fLyH8hfPQ z^v20GS|baBPRaHUY411*{T3)17b%%N(3;2X%7;O=X*zdO9uT{sYF4OHz}-#Z>Gu%_ zMebNMqqWYB$U%PV7F+AC3dt`?xN%NFTSSO{@(UqS-f{;I3yUkIR4>>CkGBM7aS#V9j_V%tur7aZgWymDqcNTk(<%&?bNdM3-caf52PpR zKiqxL^e8Yj+Lrlav8L{uH_VT<>+pc9qWDQoqjiA)=Hx|@#)LQ*hBP0G?*H~ltw(B^ zr0F_cl%Zl(P=W^s)-w*Jxfx39F+C@(F|ivsh0U2O}r4wvZl zR#_K%UDXnl&-kG-x$IgN3VcGrVfkF&9`NWo!0Ncrs`wYbRehTt8}2+=#c#c;n11lP z;}<{%z}1UP9?34Dae43bUeRnnJt31PY6 zlc4$HBo6SZltJ%wtXFY-0@Vmx+6hC-%1PAnd*Av!r(RkXZYc2zUt8;F;$V3wiqjJ*!3(I-(>H%iZ{ z6o&aL|5)@{X(q8ofrVj?}sa%Y|kr)7uzaev~yfkB%H_6iq4?}30mi(7rtj#^r5UEyOJv9%JKw4wu((a4y zgD^ATMwPvGNZn7+s)|n9uWOQfcpr?0e}FjIemD83QYIdLmu}bPquT459Zm!A2-&$E zjFXU`i1~;gIEG<)YsJ1?M}+m{!WlZ}kf+@&f=?B@ysMP{;HiD=Cv8RlT{%0IRnv+F z8t6lESZt7Xm_A>LoKrxfF+kVMozoMh>r<@sE>qJ$@va<)$RRhx5#HWA)=5niZsd_` z{z+TN<;wQ$83YVo%@w(Yky~m5U1a;rT`B&w%-um%w@+$dQVq_`(7 zxmPz&@ z9m2+xaza>gbc%4<&cT?RME{-1m$vjq=&~h(2eOI*RAPo9dh>54LJF-~Jk?K#lWzTB zm&f*|B$qES?D-s}p4|81PmxI~j()AD9F=0g@ANdwUH~fR$phH?aDq;|pu;y8&OPg! zPnl>{i%{yuTp${#%FI;6S*60iRJr6v2XFW(dKnQ4m0o=qLMf(4D-g-JRX0y5KUEtl z;QOETDi!p{XEn0JhTnThhvDK@mQ`9U2mxX-HQ!7%`gLJKn+oWpevJoyWdyrDusc+sfFHYV~=gEGwfWF?`W4(%Bj$BE1TE zPP8N2yu=0j{P`9-e8m=SdiqHhAU>hst!WRLWbvJjXuK!u730Ah_#PYLy!4giZyqX5oAQ!QZjpyObqeGzl1vJ^EHC&G-sMx=e!Ec_alt~#W;e4z=(hY3PQr;kEqwF_Iw5mAOkaFFzyq3!1(s(DR|3! zo|XibZ(609ysIr_AW(@NyM*(2ULr=nx@GE$t#?zeb9RgA)>1fUBVBe2?|Y7?eDH7t z&F6Tft!H<}CxESw{Wx@d@R*_Cy-i%lYx`uiq1T2Pe5mjme#*lGmEVaSbCMAQk!Og3 zNL{mXoXi8}G}Ku8I1RFNoYNzUR~f>O~<&CPywI z?D0eLYBss^Xsd;Wb-@s%Z zs|ATw*lO22m#u;-2r`2W>qQBxe}Tz%`7LWW&auZ|iw?n7v!)VymrRHg(L1 zx9%P@fAG~T?2^5po*)VsWX?Mge@yaaGD4MjG9K8sOv0r!m=b~Tzs71hlciE-F) z>sk)qcx18_78{$tQmcF&VF^elmkOUQTeOE{Fe{* zo;;$HPHBV4<&z(E9sCJ1m|!6kMWe0OE!1>?r2Q6TWZ+uf=C%2}`6(vv6}bOSU$0fD zzBYB<*O_&!@dPBK_isEqQ}{ZgZ_==XBp#k_c;hDRXECC8m-t1R5C&yuFZZZlXXk%h zSKZF{>fJ&OsO=lr1uS`j^^w!XIS0)y2P^y|4@As%#WPFTnPtIQxPiFbG*jdb5beImhhDn(uRJDx9;;qlT z{Z(olAx&Q=snt-A_iP#X3q^SKvNk9AJ|^%6x>p46-pCRcJts=n42c+2KP{>wswN%; z@&=J~HP>UDlkiq?=YN2`bEc95J?Wb#Zo1S_#b0KBLYHCH=0!rfErKQft@*Y|GueCe zm=|CHsDQS`j$hAozi7{AbnIxI3?vfPPLe@EQ&$n0=35=^A*q`LS~F5Ndyueqr;DdQ z^DZo{3g?y=R}wEKBD0-tAgXVvK#02k=pW$?2fqK{iap~>e_UX6=s}xPS5FcPu zfBsB2$*sdStxz#f>zZmAe)NIL(x7-(|78Q@WZQkcf8EvSiCk zzQF{#3bgiz-^>0qr0yi&b<1Bzc(y)I2t#HI>+r@(Ehfv0>p^2GZY9l$3+34_N(GV} zo-@Aa^l>Cq)2yUp+2i*_GCqzgf{ zGu3cLu_JT_D_3YUL(i2HDSl*SoNgIW0-ZW`(f;_r1pv*}9~W0x!aEanQQ#im^u50% z4JbOAC-|Z0Fj|i*FhsJPX4SLpf7pFq`-GSs7%LuRE!E+ISG0>B0{v$Z@o8NTSThOJ zI`lgX*T|G;f{Mqkqe5ST-YFUidxI~>Am77d1ztJA)|S^IrEF10p;Jz*uFE>L}KIQzl6Afo=h2b8o7`B=Y9=U13gwcg@R z)-&!MFHUx&wwBFCy7>@8S+gcDP2zTDYHeYvdz7n54T1|1Q|_>8j!;f+*fesjiLZ!J zx7EpLttpzCI^1JQ&uNZToKR9#n}2s(C_?ulqh5J}_ET<~(1PN-2lSInH*9{RDheN9 z3go8V{>{@iseihvPu4O#H|>V=fd+xcEOtIsHyn!{lfullr}Xpsr`07vLLz1%->-|Q!H`%65kPsF!5hM{}o;TM%` z{jyez1#OJO*A6CAw(P}${ZGv;CEuUAOU1WSjQNrXzVw8qP3I-4`*t17h5$jhxF00) z_USZqIDUjIYzqov{0J{T>(z_U7Pu;o&#)A7av(!k6)UN#D+ywjZa%5?N4s9@OF853 zAKB9^f(G6vlMl6sfspwmdnkyq(}9cnv@7Rs1fxRo{S-GAQ#X-(=X(H1Ileo5$q`@w zh7d{CBf(jll>J7&`_&AbL7Tfp>F$fT-Bewq>)H`b#Y_Y9U)S73rB3tpPnxfS6L|W| zS#$nU#FuJ~K>4|y(7n5>N+Q}mu+VHpZ2Zfv4O=maF|Y-iI1Tt1mtbFGh-T+S->tN= zemWpvs2DJl`M5!>TxGgynbcEPTBn3kgQ3W0s1}pYSc$+{>e)eqF@KqvEb01plOzvt zKwTIfSNhdHskQO?x}%=a!I9WIHD*hEcG*B9W?91_EZR=+qe#%yZNlXs(=8CACQN3# zEQ<5MNvmA*L-7hgv-{9MBEah%9yOK0N9O-D0yh~3)5rhUN+spphl4`eh$!~GGf2e% ziR(@NIl&1pU*?7_JTwQUo?NZtPv6=#=&V>P+VW9-;NR+2*;~&O zPK8Zv`HGz|Ogoof!arMit){{YF8SG!@YL={6xJ0kqEJSSSh}Tv9199uRZP2($GTp z&J$tUve#VWp=-9}^h+;QCrCB6$J!Ft{L zN?u-&m8MhB5z?<$cZ>LKlBP;34V$u%RnWz(M_icTwc}z6!(uL9*EpLMPoXC9CE6#^ zTKg2DR*VEDx_G7c1>7vcA4osT zxeW>%8oft4->G$7$RO&!=yOJGv55QC%{6(2=7jJjdsJ7w#XKojSq>^AF?+B7Y^LkI z!TXdj9p@`T17C-C+j#>5xGV738Jo>z_qOiRsOc`Uk?Mr4vquOwiZ14vGtfdmUR?56 zDq@S-mif1uJ~<~C@5OV^(7|L|w zBxL6%)1Zt7zbPOUzHBU?*pdDl@<2-HVX$DyZBrEckKCBiV-m!$SE>H1 z*l2vagFQXs9x4q36^l@X3hn-y}g4iqFO(ObE;AvV~vNOYe5buF+CLA-bGzoCv3yK#i3Ll+-jOr^BPaz$3u zy~61fS3bg$T++sF-p0kAZQ3KEr;Yyk8}~JTcY7gH4=Th4w;t*2^^AG%R_L*Tw$l6h zvj)MEcTM8Kz$?HW6~RJr3!yqIvcT9Aov*bnfr@k^nVC0kX3X*T+kWlX`kd@)`IH1g zu;i+WjMCO7C~TQo>Kus0@9Jc4>X)`k$JB7mo%Bk$pp`?eri1`3s% zVb6m(eSe@4ud2`zS&we=U4HR&3-T!8a;7n~j^7EKS(I2fQ}w8B_GBZ_0f?*acL-Cv z<$G?pv@(Ns60ua--l)=0%j`|JMZ6liRHKRc4|g!lH=PR0nNCG4mB(*P|Au6zszPKc zYnAR_h~X3W8PXQ}UiZigIdO!ZtU9-XJJHiAD`D!CYhy^KvEx*zHlng+{e-7ao5vNQ z1Lch~f?E+$;V;_L55a?96rnP)Ew_Y8rTos!j_&%Bm6Y3iC-ZFIo{ed+0A7L_+2^hA zLp5yku;Fvr2;^M--HykEpA?rK$7mcoJHUCC5QY(P>3}BL#L6y{`^$blcd-SeRV+}U z&6qmm(sH&zW1SJFk4Cr&^+-^jx|q+A5GJT$cf$vGANU-bg0KYwt@XI2K9Ghb+d?0 zTIw4IlfhjLLyml4HhSjc^NN!p!tvduE{-&TjK!byPBAiMo~o|aCsvi<1I4^W zOqVi&lgCy~-AX@Nc_qDHK@_(+vYMv(Z*cBz?GHpM!aGbqDi-O-N%!&G7GnB;_~Vl+ zs%a`b8rdO+Az*CKvGkl76OY`Av0ehY*)g8_Y&v6S;3m>0Vs2V8%9)A1W4_}))$1FH zL#`%(as8gtbga|JG4YtO$5|3pgAHAKx49Q7c+W{PxQM{BUHkreQp{XBcz6_L00)|` ze3-S*i|sF@(tJ>Jy!hXja@CuLu}+NTzN;DnH+Xqfn|b#y0DC59^n-KQyIPZRRs2_1 zzU%T`6OUT7J5ZdVJ^FlgF!0zDoq3C_X}(e$x6h%mU9={#eUw(qymEP4jRaCw^=-$l zhe0(>#NAJR=e@3j`2b_~)dvUcz?lZ0xvqNE%j2NA03uw{V;{Qi)v_szbg^-opA*{`*3+|VA;-E(lBiY=YwE3!nWE2gSWP5}6PcnQ>R?Lb;9mUjp0|B}n(k4i%GYlMjRm6sI;Xjv4u%ST4n= z`1(@oxCVwid6C`ykNAF8{~{{Lm+xM*xzu&=o_elkr(;x32S^Mok>N(PHp}=gTLejM zQzpr_z)@@Ma&&{CxyKH8)rzXA|id{(K5V zAr}vR015v7Y<{=wG2S(Me-9Le#7Vtr<7JN3L9+E*ok8~eYqB^h8?W;@6) z(($G~*%yuL5>!9hW>-lX3K$%#c3&loS_=E=D>3GN9T*~j2vO)6F(EU-HI8kr7wPDIAm(x__dsz%d6nS!!W>?2QSX~l z>JsQ9Tj)dm*jb zHB5J2Ap+r<8Lvj6@pVZEjDf?G;UWz;%mX{?HBJ>INt- z#tgqtCuKD}UWqzdXk2<(OL>XyUaiigE!0@F`Q%xfYJjk;*#-y8W!Vyy} zXitFI)rJ*#qdU+)vwPKLaf@0>alF)J1G7=Nl9Pm!3&R0@q+s?xNpPo8$!iPxCa5Yy z=ih?ODuNiP^zhu#wO&~la-^LcF^7FX{0()!<}Dqz&*HCh*&m+Wl|X2BlMD zDg#1bNLlBU{w#X$CD4i>kK)0{^8i$Ltgknzf)Z^%myNXsuPM|g<_A2rhcO@4$qag5TmJLn zIRFbbx_C5>xs*Pff42f1Iq(&kHvz0b!lP;tq)SK($EO#)Dz}g1|Ql2a$0mD5Z z9ULX>K4+6=aHhZ>4lkwVY_9QY6)P#z&*47m0Lh4xPE*=ftDGcW4~a_f3=XeX1)N{k zLKrv#Kd~y<%Gq!E4Tf)IV8AcNM&snmlKa$lU8N1X>#OTO8?Dc_F>xMGp`L8MPsbGA z!jD&h>h(920BZk@p@}3Ex8)D%IALSf1J2`K2{!Pq9L06np(|7>>gg*vnl7{%uao=` zXPW5cwp_3owqEKkv=?L%3|T$(6{5)XK(imUFQIBXU8VnnhuO}-m?9llPOrxqY5O9B zL1FR`)_TqSPWEV5?^Cr9_}{8Fcfk@Y=p)(?mo|1@W&|b$>+%xJPh7-1lC+k)A^pU(>acxVS^J7 z&p(TnHEKHgV|Z82I^j*H)J{DBc5IPZ{_WJWA90WVks^Oi13$`)#*Dx+*VsE9jIoJ; zIol5=5~R;J!o`E@b+>lw5Z-@yvhCQG%#gU#t273CYvH$GhL4br;MvH`>Vr+E`_&y} zrGD4oDd22hIA-Yi?)w^tz%dwSF~NGT`){GR9J%!_d|>g)lwHw>4*l^!g}v`O>z{DD z*9Z7lI(JcXL=G0%_u?Qc(Pr%kRlMwSb8}Dmk^V7YCSi%9rI;IvL}v)wT-T+(w{O_G zDgQXhLn`gy66Zl8&||pM=<|hvjx9`;oAjE&tRHp4@8NNFW*^--Z@vGqK`Ax&1qYZj zsYl(tv?o3>9x!-qM(L}8VI+3gnOA9eqrvbuc1iv(Vi$ksxa9}*piW&?)#%FyJ^k9< zR*8%$7gsGxEQ6lo5S~Q9%dzjhGver4H}TtLALgt)om`~3U5+f^&wm(2h-4-7n|3nV zhT>-z8UoHI(7HAX#|uA5EJu8_lRT4JwrIn8wOMe)B%a(m`%;x&s#>4oK0@afU3)f@ zu92CrOTx7?yDLIKcd{R=94a_EIvO(?MLvi;~^(x^T3F0(Qt8GZlvGg&d$y?vPxagFna>;M$KaR8hfe2 zXP24zp%Sc|8%gvKux@{Xc2R|B@7Nc;slV(ufB3O$(Vj|ygmalT{DkAd|DOd2#zbe2 zx}I@`4N#496hekaMj~@*IH$^k`IviGJ}>pEl!d(>HS_IVscr`0p`IV3TWKvkFT~1u zgjJF3Z1w0`tsRC>vaZW^0<&_lc(T_gU`e_5f$d}|k}PkyME41FFRM6tQ&+*f5$l@N z7w5aF&Gh#SST-VrZG&Iwy;og2>V0gPx5_7f(bw77rqTf4deUU~@NC&BayYsAH3-wp~xFSdG{0+eog;dqHfwT=%j{MF3F4|POll+Z~@!JZbVB{|L7 zaf}QaSb*mHe#Ce|VJg?Mvdc)1D3Mh*)ydykW&C#N2D%?sg_^61=_D+|b3q~vwacRx z-$x|R+6+{FzQQcqcnPq@WOW13+IpMsRRhQ;D>A$4*u|T0mwo6Xto^%c%+qSHS+H%j z#F+x=Cl2+~0^him*z^zWtuP){|O#bC?aH1UPQh&9@ zt>Ra2C%ii2oI_dd7ppQ}#%1Oj!$s_c^NGC53uRL2TZs#8|vUuLVY~j-XAO+(;Fp+La*wf$R zmiSVk2L>y>JlY!SARpov>>E6$8)$xqi;MfsuYpB1cWk6`BQmO)A|K6TJ{_YcuaSZs zIMW-}9@Z>b^jnu6+H>%TV~*z5ZBkd;f05?zA0VNH-C>nQbXWhArWId~U-x zlbw3T$SFrL0bI~`zrI}xz$zFO&iI*us|*nLZYBW}*kc*B@lQv6UEZa(HeC`Kid_FI%iq?yz0MQ%lws;|sh;gqG%;G8^9Sf>&|Nb9eE$J8~Xzqt?Sg z8W%%s;rUY6h}Q3G`SXFf!A|nwmJK2c#dEs$KunopC+f@B7P@R4*#g{2!#V@&NsL#~ z4uVE!$}}DJ&{IcrFmW!Ase(0-^20S?N%e(l<%Yk`H!T)A73QHUa8~$}zjTJ7m^2l5 zIWLZ|XCIyQijTO@oM}?%?x&M$n4w-mor^=SU2x^1JtB>%cB)&#p#Oo6H0c|?lu@S| zBWxm6>z~jx%CrBxpf5|I-u_x}3wSjtzdA=Ag<0=BIPy-p?w`I#CD z=poZDCtyaZ@6>%6xa`%bl|Gr#lR34)(U(!I*=~VlT)Yp@T zack4YR}w?-Ohvw-IVa&TF6STNIS!Q>(e3c#1vZZxwv_$+aosOEB+GdGe)7iY$-X$P z?TUcEAo7B0GX}Z-Cp9%_$7)Y{+E)yV3Zv4qX=ujQ&eYt?&@YlziEbA=O=s3;+P@CH zZmlX{G>|6e?)5E|4R_da4#~{TahuVM=*bgbwaz_)yXEBYsd(DD6B!6CiI2Vg@ah@- z<6)rh$jY;C_Kt$JA~!!XBhT<_Mqq_rOU|!$(%@BUr3UMnqftx2%<{SU5`WltviwTe zU9{>IBCi&mH=hdT6m?cNt9GhPs3_EBS8;8K1Dbm_I)BwQLIKrFD{803$@1P>k5!U- z#>VtE0nZRPEpd0sWnENDr@K~E>)*}GyJ(!VTv;{96jiGv-G1vpQ*gy4pPAoYDR8S- zhnF3yPQ$l~`$i7E!>DzwjrwDnO!gu4U27$db=} zQ~}3+^fOF4UOcwomLQ9C=G*TSzTz&tbl>S4ftA*m^_69NH&%Va-A1-|b{4Km3|O`- zMrEf`sPPNhc|T`ewe-ZFPLy*SIn;+}z$qpTV7uieV)NhL0f_I?XR0DwtfA?pPj^ZEqZ1N9% zE%kc>-TjXqwVx0zy$xi5B(#4b6)3LJje=bgIdN~`6yp3lq7v99@abCWym zNGltLj7Vv7VqfT$$lk`|44fp}X(24F5Dvb!Fl?uxM|Yh|j(6Tmd%nybP!2u$@zI}m zPeCkOKyJ3M`S5<6Qu|-xy=9d#LOTwL5<$B=DIY|&%U(k zUke&6t_97gC{`|)Fzv!;j#xm(i5Wzmy`V`|RbR72FjueVP$Sk_;Exs}@a_edyKI#W zD~IP9U0+d3_rsY8NO&Jds0=YEpd9J^*HemTCbulV?M`>m)UX-9f&VPgo~$lHU(D zG3P)_>H6hgRh!PfZikjoP$lC2EC8+i7n_A7P8eAV!jY=}fUD@eJgoloW&OP=O zSG+D6-AOY&G_f^%1pT$aPVAmP1u2M2B!n&o)brJy_5@?eePDL6qpPaH0Ae6yIJeJ5 zqQ~G`7LM1F6#laBCCwzyPk%|4T{=&m)fj|gnD0(Qp*_1@Wi5U_SJ+c7E+HZ?A!DJd zvI1{(nU*&vj#FQ_opSBYrw-(3W0>bN*#wgE(Rj;lGBRa+#0)#9cOt`Q+2kc(3G{3h zmr|RmOOhj--0Uibbq~-VA4QA=jd>8Pl?>#rW7@ZhUC7+u%<(RJ<14a>Ui6oYy?TM^9b9)Ds~dY!?U4`{K_uGZ}J!pgp**bro3I+an>=E_Mdf#s9FK zoRiBSaKVEF=jU^bCyCUF8#rAVCqW&Ou0W%h2>7eY;|7x{;Go=KB^SJk48wCUz`HD0 z2TO1O$Pc;Nw-i6(OOy+I44Gf8=P#0*P9^g`$i3oyh;QpJ2!wexE?zroQ#H^4jNUoM z?=onUAupfW*FTfRKkd%DgatZ#CnV_~HxX9`1x&@p&&%Xio2{i|_KFqr$cVyzco3z+ z!1KLVC7P>hv`9wu%!ZctyIu&9POw)HPru+i?4MI*55xj*soGFJG7fsPpyhV_O>GkzLvaUl_2zIVg{b1&b)I021b9$IMJ z^#?~Gr$K+74Ko8!Th-~{A4aG*50>Qea9-82@WB3=YJLVUm?hH#eeW7}iy^ABm33JF zCQdfr!hY%KmsDgp7!EM?Cd~vJdtDoEt~nIp-w-<{vA?N#eO**uf|q#IkRH>jmbG_T z`?8-yfGBB+GDuId(GqG(eWlC}KbprvGqOwQJk>dF`>K`^79B#tPMO2(c6yfvO23KZ z>w1K?>B$zTmMa^J|Eu!OHFFIbDn2*@9qegNYKd=0vfq@<38I9)rS=J6+U}LR!HZ2q}Oa8n-WG@x@Te@e{M0qVkyk2y>vfQQF5PTDB38- zBL>HD-O9T`P=Uw7oirWEZspFb%2=nguKhvxU*9@zeb*_wBw9Dmw0*RKY;OM}LhrJS zVVc-k8u_I-Er#v?grLLR-jTA?dw;@gwax1t9VRp8kI06Nz)n9y3pjiKAdnf2AWdX7 z7kWrv5la|aHyS2<;kIZ5Na=ROP6~I+b4d=A?6x|S!XRbCgm84n7L-hNA2@4adT2Lc z{ItEFz8Whf8Yv&48ZlW(_mRB}hxmp)?zj-~I<>%3C{5;B31W~Eh;@uQ6N$pNA)dp$ z%!lI%1Bt3%El@H-*oT1uskKO!kVmo@jL=a3y_R*unocOzuy)k{lA)Y6A_ezO4^p2vK zHL)y%MS*2+s%}v0_d6tPFQk|JypbItvySFCNwqB%)=tS~LT3Y#C=n_Vb1FQEa_cx! zT4D3o9oLzTk*W)n=AnL>ep&iL)ZO;;bGVLhmUYZB9*19|+TutDIB%?Dv?DMM_i+#x zi?$!|IP$E-#+0#0$11rw88YhKB1_HloB;0=yW-b~^yf)nmAb5u_&IF!97qtY^x&WE zy5_0d{(po>d1B_B$&gKBuXx`vzYusc{J06ncmz$z1ZKaIBsX7PcV15kmrtH_p4%ai zsH*(({>}`51o$3j0kq_jVgJ>?ICS^60D2XSfaQKK}k538avp&R4R_ z?GOAIDHrIj=0h3#bN|HU>@9~?@EZfo&xBUJGhFovzt1W=3rh%RxrRO6jWb?<&s+l? z;6%s>UbKcrfM|21LeCE#ha)C&6!Emb86fcZkEraBi#>qzXR+ZLg;= zkPqCz997xh>+9>soG^;TBuPFgx2N1)lbvEQZiRMT&-ii#m;jj;urYl%i^5a3rai)! zTeGyTh{(@Kyr}8a=()Ci+poe4ipD4sqaKEZP)New+0D2u8x%{k#(x#3$mtW}+7XRL zP<G zlUc3sDI1~dgkGHP`e;FT@v@|LbjWf|@#p&f*-Wat*xIO*M8MbsI3!&ze`=Q#tyA4f z%7kyKYU44ApDE9elKI7QFyp$sb&?jtrh{bl6lOhw9t!k4%DaZ-^!D@BeOSJN-2rPs zr(a_HH`7xIi0VHEpozl%qP;Vzz^O{>*p~65p7c%!x>OiFoI&C14(&DB_wWhe=Ds;~ zUF|g{M18FIGVIh?N>Bm;95NO3ejVPzVkM-yCdg>`m|Rimy|8cZ1c!)dq-bXt{_>Xc z+|sSSi8E+gYwsNxr-=@9mhsOPH}S`Qnp{qPo&j{)xHnh|1X>cXm=4H4?Aa_+8ki%; zzSRr*s)A^Hk~;7U>(t9z&0o6!IQ%PdKVPSwmqm!+1;woiq&s{7-7O@s$6U1y3=$;U z96YM{CgxDS{`0t@T)RfzGCK0tpd-@ur;7)d-$Is0DZW1bB zH0p{xw4yoT5tL@PxZI2>4u_NYN`5GF1|5Ylb?-SN8`$W@d-maUn}Cy`zIZyj_i@}8 zey{%L!p7&?^eEj>r`k^;!XacT*@f`qBuQYvrU}F~c@mc!854P0?bPKS`f3|BiSU9f zN>!hb)%8F)0%LSXNIW$CFL*UYCP(_(PH}a8Ms-7X>CYC|uo@Kl%d4&_ttVN&4Ea*p z3P8G!DL1yf{b_}7)|B$x#F&E986BpdP?2bCXfQk&&x*+X71&&8;zN*yOPs+ekYzgG zpIwh{ey4RU3IhKXq_leU z34d4WL)k*5^s1ISe6x^Q%US4{shkbgnfR0~H?A~HTkQ#v)c<79*T&ic4>F%Q5;Za} z^^DC7J!%^-f)Rf=h$YB@S83#8d!dgHWcfaifbSXDBO7IV7HLjZTuS-fa0Mvbt?%cC zVY4|Pl~7^&5~$QFMn?c|i2pm4NBA~r1Yffi>cC4TsYoD0Bq7MU`^n)B8wP`s_JTDe zG5C$tOqf79xZJ*24;&%7aie@J%b#N?0LyakJhlCwE1LXZWbyqNx$ACCI^3t)ILVMrW4yxd&&li~^g zUw+hmkyQ|rEYZ`6@?lpuLTlA;603)GpF&rEdQaw2E8Bxm&fnW#c(b;1EDjBu{Yyjg zHE*JvT$f zx4PXls_zUeZSTl<+$*V zPIGD4fB(Kc)T}+8=Z>hX5RGYxx9^-=+vfYQu;dopF_X8U9(3eQyAQvs>S`|G|0vds z!h@n1?tEyzTwzViejaZ-;7EQMo^Lw&@MV8&&xi~8hV%kdqmQ}8O9_c{5+%uvS%QED z^>3)z-Mjg{{oQK3si~=)8Q0&MwZ3bZNy<)X^Krt6>qrKbf8=7qr$9h&n5t-3r+PAQ z+`nrg#rImtEM?^MV%-dbzgEtPrrabHncQ|B%Ad3Nm%7GYuVpqCK{GE~I__!KG*>4Z zIPPuo;9O*!3u=SDEH@g;5cG$1Pl4$#EvzVCc5E(X}ah#k@}kh zBl(|l0S-*qQf|fZCLub1>m?j_?87D8zrx;P#$d2DwG+GFy*^huKXm?6!R^0Jpoa}J(C-@dq~8>9%|4qgP>&~T z=UtK&y}HpCwgL_tlRPW%pG77nm*5MhhIE>-?ML46SAfnmz=jPfG@Sy7Hqk?=npTZ> z(E$7R=(*lIhq;QV?>;VK4RR>h(FpyRH+@F*M3e(jG;3iU%JEB7tnbzMnMkr2aea?a z-)rZpY^NNLe3LExeSk#7@VPLFK)?GoL%Dzvq+9RL@Yp*hCpPK$16$|IS5^rz5z4z~ z&oqb*oUlTLnqo0UgvAlZque5iP4(n=i}UG39zcfcaZCm07o++;prYEm51&v{Rypp{ z_&TFoKMwU&>s#u@Gz9936nj^1U+&peRV;~96RP(^)*{HtY1P41up&yU7S7d;zFKKS zPgs5J1En{=zpB1h0T({X+gYSIpCK=Imx|(#TvoR-*JQpS&@hdhdT94yAE_(&x*JgP z<9dZ7$xNo_kmeZ0cq@v}UcLl}T}HVdXkn-POY@}I&ZNsZpDMV1a4o^RDB?GHu~adi z3v@=m-9tm7Q-f$}DFnL46v^Q$o_Q#G<(~@@3gS6m-ctv90A+yT1z6!SXxqRqfJ^_u zCWIZ;UCZCW%vJg|j&WSP)(87(h9Yf-XITTYag;6*TnUlFAv)UKX?$|!D={nQCwDEmMz3xF~ zMT^}90NF=&BT-31Q7aQuU-ASTBNgOj9q?Y47`%S6>g6ThHj6Gay~)4v;Zh&Lhtng4 z2Wr?e?9fKtBNY02FXIz^vV!ycLqG#MEGgU7EjL7Z?6l@06idM|km;J7BO6GtPBVlU z3^QZwqd2L{JarNDz*!DB>2~JL+-RlPr#^6X6`?5w2A&U9(Qq_T@cJVvHRSqXk!X{! zF4IfDM9S~o+&uivcau;2;*L))Dh7-uUn(R)w}xDng}xxUMK*}L(K#0e_$|WY+pimT zuhmxEJFaoL4*Q$~Y=!n)|JqtxTPt5J52dU`P2}XJxb|G~%dV6wIE;&rf9`5iHLX{6 zRrTM*7A5wj#NC%_sa1EYj0te2jE29W;n4S^&jLg94|#2BV1@^ zoIHC(cTW7N|u zI~Y1=mtGW*n1juWgC)!(=;>(uQ_kL(*bmJZe_^<5JM!gkr|h3?>m{LaMzO+8$ZR)9 zf**zL=xtaSq(Ao|6kU^zFcD|~rUyMy% zYB4J@@W=K#z`C7F2zz zs@e)7D-8pyCJ+BN*^HI0Znk#S;^2f}-!j8p-rYOSJTWacc$5P7Cy-@i7{~{0<3w7q z*s!wUNNU5+_D8GD+%C_1wrf8M!NvnRbahrkdieJV=a&ZO*597o zl^g7B@h438uEWkzI-!S@YIfwc^k(LMwXc%guEjztzsa`#JsKEZfDR zt~VZw`EyK~bAh8U{63RZ?M?KcR8SQ%6`<(#l=zeFE~7JDn5;_~&(FsI00MXacP{`o zIw>9l%%xSh`5oB8ioJOjTArNvW9;@PW%OQWvmjf8dPi zTc{|O<@51wcxKhL41H91?dR&rPYpSi6AJXK{tb)v0zlR#c-4>WAZwpzDvNZGAz9bY z@0JR>pabC&^c$7W5%0cY{x9wV5&gTU4OKc}bVsZ!A$7979{?O9m!UCR9Jmv;_T7EKasohC z!g2>%k!uYB>qZ&Ne!L71^9_!v&y{XCQ>~6`yKbR(A!&X1NlW zSHLQ3*V)z>K4j)G0-BOn{8oI}@d}X5auqapVbx{V)z;hF+uP&+D}x=4VM?y_JHAyv zC5y_H(CljSO5jy&D{bz;%G2-oM)IsprCbTju68@N#1*^lHYEUO$pCEEzuHE{f0jGo zc2)bG;99ZoYJUf0Rhw>q&*m<$UD1GqI}OPG369-SD)1IFZe* z`gHdt3%&{e+AAj@wHwp=M;Y15o4=~h%G=zoH^8&})*t3xIdM;QWr!{S zm5i0FZ+E<`?{6uE)ctTzu4`lGMMBoMJ6_iJ)k}4bueio5+xP*%F>=q@G9|n9-HEl* z#&2AtUFFUn44JRLWaZU3ov}LG_{~44v*phFEz|ZB0LSRv+N|3AFD#DVQ0|_GjvHuY z``q1!f2F6if5m7J0Ddc9aGQ1a4OuN$+&sT+OjgRPZoOU+j(4wzR~!>nTmar#?w-Vd v}3|Ln`LHy?Zr=lkQf(4xI@oUcC;M*5s-OcKp3g2+S~@*7avBrIm(^dn88TcM8Y7rEjtDs@ zOk-f$$Rg08+TftW$dbgVAmBY@rD9iQMNV7#^)-XV*{4N6f2W7)hK4F}oOva+=l{Qb z|5!J8u{2iNbl$6_mt*x!)PMFHU^ti&js{H>pITnzry4=otcOPGw z%n;V8aG`x~)A#$2ukkak5prD6yLeIgcbTtB4M2nEJnngM_gC$!&5Sk$Wk2@K+a5ND zVf7rQ#@el2_wHt|m`}!G3{mwLQ zC#nCMLNy+Lj&1j5;AJvcbl0yz$wTO~9sBkJ4r^kWGs0CGE$6ojE9`On^K4T!122aG zm%2m5$!B)+otZKM8U!sE4{@1&wUiZeU}pYuj#D6R!_4!qFEB{SEJ*ij_`p2-#~nWY z1&mBpPgywpZ|r$q?!~|>bU|6&LE%~^V+mJ^$}`huVNlX~D7}2Y%yPC135>RdOrYd; zr(pV|r(YPP3>Jt34eCE@=|7o4%47k%A1FPx6opS(70JLWb72-(cjxmwmGH|9QZ@@z zfksbb5IP&{vF#b7NrQv-S!Rw4T?|5}@3P0TTu@-rEfI8R5M!C(@y=?+D~$#=A&Y2p zMiz_N3_{26vW3U8UPxd{f2Gw>U@}{0J23TMjb(Uy;XvdrZUvd6&rX%cvRzofl>Wk~ zfgxSML21Y82NUy{GZGpXmr6U_=sr6oeHY(?gRFg5N*NNhXKUEMv}<6Ku<-g0H2;(U z(6>*7pS6XzaVYHZ{u7ZrgFz}IA^$Loz_m@0o2~^gn%p=ruZ>G#PtxQkvWHnOG%#07 z>NR}mIXkhOSJI)G?@i(fhC}6Mu6Bkw47@fQu5JJ&qJKv0HCZnh)ON<`iTz@}C%kP( z$kj`~TywVS9F9LU-ITj(+3UMr3^$Xy7{YobTW!VOcU<2q{xNy={k8E2-t@&SxqjTA zd*P3b?U{ZJp}EQzPB-~*ChEU8PoAyS5PF|~%CUk1yon}3|Ln`LHy?Zr=lkQf(4xI@oUcC;M*5s-OcKp3g2+S~@*7avBrIm(^dn88TcM8Y7rEjtDs@ zOk-f$$Rg08+TftW$dbgVAmBY@rD9iQMNV7#^)-XV*{4N6f2W7)hK4F}oOva+=l{Qb z|5!J8u{2iNbl$6_mt*x!)PMFHU^ti&js{H>pITnzry4=otcOPGw z%n;V8aG`x~)A#$2ukkak5prD6yLeIgcbTtB4M2nEJnngM_gC$!&5Sk$Wk2@K+a5ND zVf7rQ#@el2_wHt|m`}!G3{mwLQ zC#nCMLNy+Lj&1j5;AJvcbl0yz$wTO~9sBkJ4r^kWGs0CGE$6ojE9`On^K4T!122aG zm%2m5$!B)+otZKM8U!sE4{@1&wUiZeU}pYuj#D6R!_4!qFEB{SEJ*ij_`p2-#~nWY z1&mBpPgywpZ|r$q?!~|>bU|6&LE%~^V+mJ^$}`huVNlX~D7}2Y%yPC135>RdOrYd; zr(pV|r(YPP3>Jt34eCE@=|7o4%47k%A1FPx6opS(70JLWb72-(cjxmwmGH|9QZ@@z zfksbb5IP&{vF#b7NrQv-S!Rw4T?|5}@3P0TTu@-rEfI8R5M!C(@y=?+D~$#=A&Y2p zMiz_N3_{26vW3U8UPxd{f2Gw>U@}{0J23TMjb(Uy;XvdrZUvd6&rX%cvRzofl>Wk~ zfgxSML21Y82NUy{GZGpXmr6U_=sr6oeHY(?gRFg5N*NNhXKUEMv}<6Ku<-g0H2;(U z(6>*7pS6XzaVYHZ{u7ZrgFz}IA^$Loz_m@0o2~^gn%p=ruZ>G#PtxQkvWHnOG%#07 z>NR}mIXkhOSJI)G?@i(fhC}6Mu6Bkw47@fQu5JJ&qJKv0HCZnh)ON<`iTz@}C%kP( z$kj`~TywVS9F9LU-ITj(+3UMr3^$Xy7{YobTW!VOcU<2q{xNy={k8E2-t@&SxqjTA zd*P3b?U{ZJp}EQzPB-~*ChEU8PoAyS5PF|~%CUk1yonPu@3^;LcfrASiT;SmL0sDY;AkFti6v?jYt|mEeRls5; zvdNh@-CZp9NTau3zkdBHFTC)=3%?=$wE6^Ic;ST?R^eOu30nR+^*mm9;Tk~m<%LV& z8*CYI{EIwa*bOftd!dx_t$h3#^=dE*wih`*Vc?Mg{vtk$i(>}CeegqGURs5AR=xfD z=RadNK~yAp;0qI?kJyy>!s(|bJO{Zc@r6B=0Doq^{rbNS0V;?sI>$xHa6QqnxM;d5 zNH0oslZo=8o)RD@tNH{uf|uC5<2EP4>k%G;jZ@7_d=au*tO$G9*h@jo$*Q+s|Ms;M57B{Rej`sgF+a1~1lR*ZT3NOWNifSj zIN71dOtnQR#*iOFVlxPGfGkg4hX~hZ)!VQC4Jg1>c9Tg^?IJzlAyB8<#1uox4<)Bn zb^tEyB@%mNRhs}?K*(vP%>)uuxo8dHji5@i3F)OIznL~7T*y-(_R6ZaUw{8QuK*P! zrZ`3t2`XHqa1S;|G({9CmY7}^0a|3FAT+@-6jyn3PXUN#mOiWAe*Mqie}%{>ljy9m z2?V&(MRE78B*TQ%$|S!`(n}`9sF&A}U?j8hvg$^FHN2!WyRQ@}39fKa?)KQ5D&BG8 z)EW_>mw+<*kp2N?d#RM!BcEp(v$E=-mfD$T!uja5pZm~uq>pJ|h#4+w+n-y}(D#fv#%aeY+X6G{i&bjb?Lifo=_U>7Az;Hl(_TP;Jq6ez zp=^Rv5@pG~^6cDsOI0@cX|nK>0MCe$-fY_d0WxmdllWT5N|{L{IGg;kYz^!}ggGR* zLuT2wpO3?8ZF{XYk1f*1+D<@*idu4qNyd`3P-=)kwJV$8|tM}^jF_g zywD+o{4z4|$B9l*B8!sSM#P4?N$n!sJywsJ2-Rtr3=vUfwVnN^@>GULldHA^tk0~s zU;p`E{Td+B<{hV=%drhc2vB+Hahx9o8~qNRi844zC?9p@jX^Z#tvqM| z_3<9`kOgH7T6W_r{;hnxAFpm`ee9*T6-KtpqxYyyjZHolqa;3Vj?tQqY>$!6k;*0k zip6!(nBLVvy)>EwwV8)m)UKlRcTxeO>W_Kv9g_@&3u0^2XnjLhz7dc)6e=&MEj+Q{ ziAhgf0}9Z(%BXI)FvF8^%=k;VozS-@<>pax(f5-P4LF61BIBPeqdLRV7?J*DL>J)f z_jg1+g{r|w|GJwY2j*v1Ujb&kFNyCbA=5=@g^nMIXiaPWNPiMCV=5Z&9Uz{v#z*?| zka^~c_->Ey*8rLKsM^a^hChqsd%=+a$_i|}28ig4k;ceUdQNQ-S@c-4%djnDPes(A z*Ap9ki0K3_`X3Qn*uVWjIuW8{ZBf$OZ0qcGlh;N4K8xtA^vWQ?$*DDi&;-XAc`9qU z+K=SCnUgOmZd>59d>?IHnQg7APYgX7%_hIvs%JUsi>#W9Fp3MN&l87iPIPXD^e{Vq zBDA7K)>XlC;}d?8h9GZ*M9U)V;_M|t z<8{wd9uIny;M#hilA6_$;)byT^eRKe>x&|v{Gzj}0xWjsZp?_mgcw#`#kn=QEU5l! zHqM(hz#kelm+@MR>=e(O|8wqI11L4dZ-_)fZFx$e*;&1=nqPyRvI&HN-zztSbD=ns>{$N+)Bw*lzxuUD&8byjl44}s$C4jv z%RdiLp#c>2K%v6)E_@7Gc}b2S!HB06N-anT7>A$s~-i1sh| zIvnbzDEWQbMHE|9Uqp2Ts9B*R@_xLb`^Z#|5)nB)j zPMc@U2H=Tm+~%LNrSN)R21m~(LkEcGjFMifEfTA(ocMUOjl@i^Jv!$)ME;tLId684 zkHhNK{SZ~>QGe>T3n3oJs2+$Y!N`0Q;32(M8@sp@3wq?LzHlJ2kdLzpSAc9=-KT1E zLamRK^R@I_uaYyjqLB=Y4&(Zt=H#6xri#suRZSbV=%`Jgb{Ih z`_Az8O@LPu%_G0_yYE$-hXk*cT1|LK&r5KlzMqeM-m4qEeWe(e3$NzXl3yw3kHM7k z=|D69dNycZZ8Ji2ya*~cMQ@-y_hbiEmdzcbC&8%VBO1F1`BmFseaen8_p5T5NAt!P zcO^d`hviX%s3NSPvI$^jihFF@ZnM^MrM{@KfeK`ZP(_F=`Q7ooL4ua2YV2m?gNn92 z3%%*pGvr3532js1UPMCr#vez*6G^0V|sh7M5ZlM`kvf-GTL z{|hwwZeyu88gv=@L;!CrM*jzML6OQY)KJIr zs0N5CLDl~gu^VOZw>4Nja1DL19fCq2>ZPa(yq1bwlU0}kB=F~@OrGxa*_vOW@wHOj z^>#kS{AW)^Jfl>Bd(DZg*BLz#QGpY` z8RA(?8QakUkCc5tl4U%@D7n3Ac`aluyb;@5hGGh^)y8~Aumw-RCV(L^?>r+n`Nck? zFMLPP=>_LJ(b$OWWDuJVdpuJ@iFk2@86Nf{>n|By+0S|G&jA*ruXJqCK93FCmjEwu zda3ENucr$}Iv}Dw6nzOmh;P(~5Z%u~AD{q_tHJ1OMz5pea^Q{fELq_@e*cNk$a4Wl zACguP;zVRzZnO_0zvG>np!Q0wFuAqb(7w?Qha|!Cl^c=Z?B!^`E%E`BxV$?0S&z4W z74H1M)rQ<1>$TN=C<0qzh2&SLKd-BwTbY|8Jv*lFjES2oFY&e7*toPvaF9DAPo3e3 zjnN!l%-s^BF{s#6we#e23tS4Wdlp555hy=^S2;JhlZH{W8g#D}(x zw!UE7_tyMnT(metp%8n=oePvw6?S~ajTIp3d}O;&zgDybp>~a}+@AY5J5=5)j@}!i zup^K~a_85PSnlMG-^aF{VsZA^#o;;g%stilt8k@^m7Udp{(!Wlu46$T%D4=D6{bc_}r3XP8OEEmsX`Up6*>Wc zDZt)q#}sxD%j~(>Gm4%m3-TCV|9gqArT%)afqco*+gWj!52dW=fzN@* zufi4bbxXk^Dv(isEJhD&Scpgv_iKPFRT-i>MdznjTqEU=70d>&wR1{hB*)z+yM`-{h zI&=YL6(4HX8KYKP*V6fG2o1;0_VzKD+p8Oxt?;PtOjao2dF%`*bc~nW*wwy;M_c7a zMonsy)6lcKsNeV0-)IhtAn)(LH%PDr_4ZV~JaJxCke>H$u}@|G>5o^SW2wHDE!x+! zn*;^XdB?Tpcz^1#sNGAsXDGJYB)oCJ^r_>#(bxCk__YPaxIHlA3fL0l@o`wC_*Gxe zw)gcok-}4Mjd=l$!J;ir(6`ogubT7PZUQgqmBOh%h7>=Z?HFa}Em$y0O{>+jXqX{7 z|DI~B02%d$+9K~q5UW9@`z)9F-4wIpZKM5O+Xk3eiNswr-Wy{TdcD=Zk$1#ku2M7` zZ*AimAo_l!>_#_3JnttXn<_9j9k0<6xKi0MRjdVwF1AskGird0UT-10KOYRKdHSt| zeY~`A3UKtkOn5&D%q91X=iSt*0Wwvl(ahGFG5wQ1Iunhf`XRn8`ydf|b^zH|e;>7% zAuD|QFRTW5et)#p?>%E!r6*E{ofP+dO^nLy(z$BTi|uPWm}`C`X(#HtQAy2qI?bTKvpeK zRR;vY_+1fW>ew$m%`vuP+Z5PGNh)LocQqd$iC@a2BfTo{Xm6>po^p%MF##+EuvCPV zck3G9xi_i-6q+IVJHb(6W7}EVyO=;Kw2E4ws&<$Q1)b~FUn%DrV6QmLtc1mAAN`0r z+U|tna*z7v+mBW}ma3IkM`3>l8ylW>mI%T2Jz@mwQ`q~Vlok9w>+xqXOX(}Xb6>BW z8FTcp3NJzZDL)dx1|g#U-k(}~nu1kuthN|oa@~+6yVe4K9^+ApbzfCVLcGG>wN+l_ z9HlsmhBYL4dm{81_3vp!$j#d~k^C$uT@as>Nfj@-dFM>RXeYoDnzs+x@l?B;zjTg~ zaph+bW-h#05$pTYQ~P-p^9I8xz*^hjbH5jYEpsNJY1AJ-!tSeWlzkIm5oCl2tr!Qk z!-!YdO8{ zZiAiUM~h-9_TpysBir9df8$dWKR)_f+o)o@hT=mCOHrEkX45BGJ}bbEL!WG-fm49~ zvz-Xh%Zk{H)+xrOy`~{SlS$KzjSvV4Ms1jw29%}W$9|g;HuNfRRP_~lssUC9A1S<% zO>H+)Yd-;-^L*?>5=2l3m3O`Rw5h*RttO>G;saR6N`Q6fai5LJICyYHPbj0%jZ zLB_@hHKoqXxEoov6(FJl&$gZ171$fgC^*lUV_XoC$6#f-a;zS*D3#F` zz2i+rB+k4sP1G3~6?nko1>XYtc)S>99XXPD?F__ffHitSz^XiUTs?{tO>G9N{Bd~3cWD6|YiYCW_Cy<+8?P4yF@h_fE4kxFx{J1{8Xs5fU0GO|Z8N8by0 z4R8c2I220FQ%?*aBh`CV3eMHFW{9Xj^cWLsdrI_FninHc;5bI_Dl6}yE7YRzsOq_t z%faUy&kC>l}=}0kFZhJ`h->rQd*#G=rkTlm+4(c3AX!#E7WBk9cj)^5`067e)RO zkDtTs|1r&E2jN9XE(0i0?zN&L5T@wN9fuewaqYB3tp}S8G4)qUs|NVk`@(kcrj}P* zuyzxGY+*sAM*U;vd|^X86Xfl2STCZ3;9ZBYf=;JRR>zAq*Y}}}C){3<$ z(Pq}|v_Mnhg*0490bZLZ=g5l3EpRqLA%StxkGOcxfmM=AA8#Sz*5f;b+BwP69_ z32SbsSj060_2aNSbr3ZYSJD}m79}=6X52wrd6!Ov8R{(I82RyopF_^98M4EFOY!kz zFzOFMU+@FaC^ELmwi`$5^9*&jgI?*NUZmCYktFy1V~!{G{WwepWh=9;^*AhbZ9~2K zI_JnBC&e86ny3f>eGn~Eh>Ez1#(7|T?spvG@Xeu6cnaN%U0uEg*mLfMAA~T%Y>M&S zh_Nb6=#f`G9D#tB^t?pp5CrcZy2n*SRNj8du!RWGMV62Ht8fwJ7g<5c0`ni^5)pZ_ z3p0i%Nlz`sbA}r}9xJ*FVeQfFv?E`XizI^l8-BCmgt=n&o(q2*R?Df@j~Jo0^_YbZ zL(K{*CTRO5+}2v|sW8>r0>NS};oX)pww6614!(c*6r4vXUdW55vtVsKnPc19kHZ=T zg(r9rB&)j?JT4g_vQG7FnChYW3~E~hBHh8n4XfBjKtJ)&$Qj$0St*TSP1RQYkbXRK zdRG#A92TnPka{9ob41nPX7xZ-P;*-&L^pU8V$?8?{LULsniJDrSv(31;dRukOP8qFPdO z7IRFRBgO`kx;5ZyqaFhu>~HjWTW;Pz+JKF z?F86O+(>An_ME#|s#VxWZ=_6sSG}p)2MVwhh2K9hS|CwqyvEMLZn70|I=UHn>-+Yk zwiv}`sYO)v^%UO*N|2=lbPnd`$8+0ATcEmw)d&hr0nWiJa*BnLAwEzn9AAYy1GyPu zwT+l5Yiy2og^j7nvGu#&9IdnQ z)E)2bKN<;PmqhKh5flaLxlr6&6yKjz*5jDDd*`wkXhoNuBUVLbE7-f-x_O=hSAZjo z0*DPnb|vp6zzMIraHZ^e7p{~7-&lBRuhDBS3)=}O;wbl12yFB#ZgS*)3gH{QY3eDv zgSc2V*ct<>yy2J+{&ISQ2esc9Ud1-j7L4vVfhEII#@`}RlI21ubol}HvxvuBKmK@k z{=c@g`g%uYpv%1ehfI2;cbCHno2>RpWH$l)13Z9`Vr>_(DWJ_^Hwn9W`f!Nc~CBM`QheJ?OO z3b1yQ+7$=Xw2}{|I)&X2e6&SAsteWt4=}{ovPZz!9`<4|o?$)^9r5CMY}>l^zjcIC zcE}vA2FM1;c?=tb$6YyAQG&&c^vX!+iWl$jg&4xpD1#*c4LB8;xVnU=(bf@$dIB^<|tBB+ql~4MrbWV;$UfW1xjA|ZT(+#}&4D9!7dRS7^&Ej0I(E@>)(Q2_kbGh|hu704*@JJkNYB81=#of;*seV-6y! z&YIJsEoz+Rh^jFKSt9dq1f?hHIY%mRJi3%QS*Oc3&BG8{$PUb;V_0H-2GQjl!&AFq z=SHty=PyJQV7>iSBP&+R+}O#B-x(P(FYDGka6S@P;2Hn8AA?QJ65+btjAaELbwv`bHIKUQ;kWh^Gwp((dBc_CP4+VH$O7486nPyFYV^Cg&l69 zJpMJ08t>z&C5B$$c#o0vxvWe#tWk=}4_H{*!h=B#(1RIU-N|HFD>nr+p3JGmjgOI+ zJ=%}K)GKy$4sReg?f`p8EyE4DM3@nLia7``AnK2Wnh+C7a2NV$(;72V#{Nq$Q9f&c z5%uS-8MXomnZqL2Z=Jb|rb?l7<$6REU8KU)sR1GoERYYx>OsP8B&w$)kHR0mR0Ff;1Uvom1gHxV9f zgv_Uk;dcIH#RY<#4B;M!h13ZVb%?0KIsjXCErK-^AmSdi3-id0S>I>QN2)-JoXEuw zB12|zM(h$W(;Hk3FrxmvHnnZk<_25=616wCjUo|FeJb_G*o?52EWJlnUm@c!MARP> z2S~hG5E9&sI8jkf+pAF@@0BSxy<{mnMStnoSZdJfuUGQB&5uUV&T!8@^*^R=*Fsc( zj5I}6TO5%Ux#*?z7odLhc!}n zy*@$Q7Gl4-a4oKSwFu1*aXs?dJx?+X>2=kO9y9BUXTp(dOK4eNAPkl^#3u2;E z`hSnuMmE=xBaWc6=YJKBQGQ-!*HU$eZG&hP>W^Kg_Iq;fXnoI`W26G>wi7JUtHBam zYcXC-jwsM8%Gx6;@OWLnDv~y@eG6Rn^%WrFmt~vPKf^1N)=ch zZ+x5)jR6I*C6e9DcyemfPok(AV>N*17zzz?LR9@_kYl8cMC7W^hyZ=`&y*U^h(8QL)g}(+ujQtz zprs#LADyV|S~osgN^hk8YP8yV+uw_0O{{+nS%KF8d$m8yrf%!0IfXJbw!sIoL^?C~ z9#Crw=iDulD?l4-gSJiH3isf->Mf{LV7msmtE|B0X)8d)*`A<5R$!0fYrQWzH$}&^ zF#kr0=PW%}&AH@QK4ol1V_G&XOeVa@W3j9@<W2cm-MUJO--)BI?f?W2rokG90}> z1#r|&sz9@#Q;J5NtqG5!i>ko;YiluMNv<`f^%0xV`xZQ78t{0>8e?5)j|#+VfSzpe z$P+z$H9#aFqwkrdXuMxRYS!Ae&sI44mqt}!qd)5NGU5FsWXGB1y}n3bNXw)CvNP}* z{O15`AWEd|-;9~cHFG7L`qTXTp5xri& zviDSb%L-coG64|@E+()YH9+PvX1mmDn-AtHF;@Z5+YzF(Y!%yIk1YUYtOPZ?g{urfbslZy{A!-o7j9UY1DpMJ3&#Ush#5e)o4)sRDjVy@T{=W0Bg(B{eI6UOF9BW;GhS;y38p?$=~#>; z#y+xQyah&_$^;b>oQ#d75Qt#3D#R* z?*eO$*#ykh?i3rs^M1}gI?K`f(LAcf7zg(-1STMmfVRf;0vy~PF>6$on`-Pqj>^FE zYLC-gR;;vQ#)=IO(Rm0@Op?mjiqKTQe$G_WBho-Qwh!Oqun-03oumH0RS!hwIDvJG z(oOR|{=%p{b}mD`QDa+k6`TY;B^L$J^^TDYOUWs%$TqxXBr3hm>t*Z|B7 z@;jpBr*spG*s*3(bMPv&ae-`oStOF?%9vql;K+NAM_9@Ao5wi3{qQ2jEbsPbW!iMVWSh`B;l6gvzGHHJdZlG zRNTlGQG!K7ek~}}Uk)L96dUu2v7QYwhqDGadcuo`pp?WYM26OGL7@aS`=M1?^f<;> z15^hb6VQkf{Lqn~$4z_x7FJepBAS=10W#!QoVL9&2qtfpRg1G<3BCi?o+Gv}hY-2% z0wW3!QG<-yYuQ>#@UXdqllJ@C_~6k6$ULoiy-Kje$xlso$=hC!&Yo#=#AB=mSc-39 zY#~Qhd@4XB7)J00lV>GAziuf(2l?&orXDgYi(cAxTuBf4jmD#Wwap08@gjIsV5<$; z?eyB(JxDAd^Nf$Gw#j`YKH7(Uzgnm0N6_H>+B9k-0P&Z-J3*EZP>aZ;@cB+UnmFX&{^Y_Ne`N%IVBp5fUtAxT!*) z>&KE9Vvk}GIiBGou67$UR~ugPLlM`iBk(st&>)Hgr?>5AX?|p)Rl5CA^2skUpH?NV z`YVV;h>#ykaFI4A)UlxSR4*6o7@QG9xrl9nSyk6-LsTErb|S&-_38J3QVI6#%9z}& zezdK1JXPC;5cE{pYXS9VujV&Fdi_=#+TUwy)q#u~APo5>=$wVf*vJd75bJAeOlxlM zm<^CY5576k{Sd*c!?Gp?da5VPu451F%{CoAk4U{85@$9dGle)I`XTUJ^k@RbX!pRtc8o+={H~wX<`_Y~zo^ioRCQXOQ1$ zeNvF$dPR3YaVFV;etH_TSLLe-?F{vN0x05<&4KYF@vSqgRDY+pqYS(~OfsDTJ&VNS+;msmT0IDmt!c%>o@I>)GG9mUkz^vB^0h~>K*TM|S zCp5-L0k&S339m1T?8P}g>nd5%M!%xxt^HZ!5yclBe+p#f`ZOZHHEPa+=Weh{UyS-X z?H-cKBDqb7(NnecD8bU`>$Ur`XEbI;L8(1g{#{_p&KuB%G8nBjv&e6R^_u|C8H@ro zpa#53FG_e(ViZChLmo=Obel)r%{o&aZ~sxsuZNaz!0Xw4-Z?6GFR7ROGWz-$DZO5w zXG|&MhbDOEEb&D$qt81>2i~i*nWrkuloZ-N%{M`qK5q~*eU0<^+T`a&)>R=@0;2$D z6QdZjVExqQqv{w%&IT zx!M^@ke@da;SuuFXWiSsj|k9uA0f!>xea(-WR11@BV)&iq>j}eAwgvP2~pC?Bs7t7 z%=AR&a%Ce+QbhaveX*M$*#Q-K-@!#BLT#dk#gjl8dqr+hyNQ7;F* z2;UdIFF^3IBS|B#a93&AcNNJ}r24;Cd;VHfbSjrqpf!K`u z-~P=*fUUOOYz)jIzKprXm_>r94MKz`AY{{O+s(#+>gp=zB0bf?%*=}0JQH9ke!@|b zmva6S(66#xll)4VpEjtSkzSd^w_+{;JCa~29wJm`6>6uM3nRd*wwhhtX?sEjNzJwevCEZ@e+KZ3 z9Wn*8efw*R085!qf-~Ch*oF8!_BgUrK%9=5M6{|M#NsO-vj0SOPJ!xh2A^iiaAh5Y#nVXqjk#TpZ2`sA*=_e4mYKuH& zV0LEl%l8F-3CggV@N=U1`e8bAj@Qoc4U@5soHSrh< z(%EGWKUSs}F^7V9GKrC~abVI_7R|AP90)uN;a{Qz$k@%a5kW;*Yl-g+)utzR^YjE2 zAZa@pNZgpEB#V9(6L2(T26WU_2M z_6D*DYG2~3k(CY!^D@M$%nVYx4)L`xLmLQcfQm6Q zj*)~-ymZI4v+C_TLx2aoDlDSjCf5BJT$}Jl*spT*2fRcyd)y>!?5P0eWR{Nr4=6|} zI>%&U{JMl^VZ)mq*>h}8d_7!`5Z7f@i~!G26VYPD_xlo^2Mbe9O;Q&nJp}8Calfq6 z5nzoO1UBIbFfXX!NWU3m^o0q}3m;KlGqc`G76Dq=w5IpM7sQL?Ug%&Q0ebNw&fgO+ w5_=&5*CW6eUU=aJ5n?}#{=y3{yl`RsKRYrR%_cZ=NB{r;07*qoM6N<$g3B>&DF6Tf literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_888.png b/ports/zephyr-cp/tests/zephyr_display/golden/color_gradient_320x240_RGB_888.png new file mode 100644 index 0000000000000000000000000000000000000000..c4301da47c53003aedb988f1c486a3b791f2d9d8 GIT binary patch literal 15287 zcmYMbcQl*-|NozaD4~i9(V_%J%xJ52?Nv1*ViT)&YmX{It=fCEsJ-{BO^IE!R?SkY zwRda(@_K*H_x%32p1DrWGgnTo>-l&-?vLC3k@uSFO1B~RAOHa1wu-Vm3IG5~6VCTZ zNeH7eUz@2ph8b z2!H|&98~xw3v(=Ewwo6A{$BjM@4xc;GRoiV()z7m#m@4SE6X19N@Ppt#ol9oGh;gn zs*a$E&tkmo07bj(YMo#WSS~!N`749Pl4fw3-f|GKg6l0CSDtc8xOJqn@$!-5tG_qb zuUjz%B)L)#~=mV30x!%uU-;Us=Iq<95>FJoxMg7He$LNz?^;aXcqhp+r z%NeJmBRe7P{y$-R^o>vGi(zZc%HGbsu-Ejhu|AiSW10Dl+r=B)^lPcsyI(Ez$ZFOG zg?;+44*3xME2gD&@ElTtz^_a~21=Hrt z&vLutPekP88JWeU5o{S2o*#WCP&N6PokDPw9Gi!-M$Y?`-m_@Ul-evE^zJ>a1UQTs zTK`B+zy|pQ35-Z_B*hZtKFg)YI^C0rRwlEU9=JcoRR;H^eU&jMkWBL z@}zmbG$Q&Sft3RsTR%nW(tYgRCH1^4va4xJRyuwD$X+n6QAj``91+lJ>550jrZ_~~ z?in;<0FMljpqDvt!>>ER$k@X5)5*>-u+uB+AP@agR|?Ab6!H7Rt{(+(Whtp1v}GxD zy?WeU4nEU<9Uz$xbIfH3n1F=d(ZQ3*J_dS}*n5Hbbk1zD!h;}me)hw7wBSCQwBz_~`8<&(&B zMt7;@rfyDv3ZV^zpXP3Xe4dRI+9G-=HDJ8I%0Ubpa=aW0m%3BBcP<4ABEU zT0U79@*51od>E}#{)%rNu#&=8*FpwvCun!)3Ktl4!Q8kX=KSQ@R$CFxN8yM zO_QngP^1&D>HSnwK%duFgDPZ3^gXQ;FMC|jo`e*vf-pYmXcs64C}tkgMsU4c)~fNI6Np}B ztvRD$eHUV^^e3iEz9GCUI7?x9X0w0vV*hXzwzwP93ffWQ3I>Ih>CSjwVbZD$hx*XvB@A!m^Q`NG=E)rOO-f`iNpTQ^QW{d zZTfki=;WggwFEoO<{ojJn*M=BIFsC}dReUvn_Z+kCvxk!JA#~Lg(EnTJ}o8ZB)Gqo zw%jxg(`bF#K_bT&$yFoUS8)f<7Mv){PX<`z(6to zE%8C0sbeVA@GAI>Qm-`c8qD6;BI68paz7t0(xvU_^!%i9qk9Q<4u2{HivT-4eg9Lt z6(eH_-uJq*Kl)=MfAov6#qVc#i{>cKJ|s65!;c&FgO9i?V&F9A%&X+d!_rk-o?lp} zpP9USkB(L@ix)*J3MtI(#|22wrSILVyIvvNmpX)}QV-ks(rgVsmWaCl$}uekA%)VK zIM;6}3RZ8Dv!WY|C8y?Z1Kn2WP~pw_LN8BZKumPv z-ZZdx@#gkA%af4Z(lE>fhRceXrfuzZhBucTPguzh6W6qiXkl$qsECPSHS~3Ep{B%> z#-!pqBicUK7?I>iyJ}^)JW2f%gTZ>CM%{&pt(p!0us6ex%#%ZYaVGx|%Pz#;vBGQc zCcla1dt(v}OzQfWjV@2@Y~d6oNlb~5b_}G4N(=l|kBBO6vq3sNKJBkqsc8i;yRHg^ z7+~C^eHBGR?os!fQV2n{f&k0K&`yh2+1tdyyGAdv#?0IT%&|6E-$6y1V(N~Z`Q8r< zmbImI$bZ5qngNS_TQS`pyISUNdo<+}!==LE_nHGk@t6#I@YqOcRt@=^%-6(tM%n3! zTL?a!N4s6AT8>5f*9LfWV6ankZ9623?=3~t=H(bJyIRCr6TPv()!MXCDL{P(D=x!y z^nh|Rb&q%raFogE*IYgVbg!tr+yiIMd5nxv#^B0PgyY-t*PW8adsz$XD~$F%a6|^-V6V1CS7rpr_+HEhk!KkG=P?C7Q2O#fJI;E=MQGPZXW*A94;49Ii#u+Q(uZzWc%A^JW zN~rXxDxx|(Nl3O^zgH^&XN892q4b>; z@hOJEXrON6s}&tJ@u+$Yy?q2sdRX!4vU#n49M$2dt>i@+vAN#<_t~!&#BXjUgIw7^b<#0F?d=t znf7qW#_yFn%*0H0%?vki8lFIO;G`OT4<41Flib z4crTF^*Kn?r}^~j97;pJ3Q-ydQwCU)FFCF%jA~y$`qQ{k9#5kpv_HYxrj0=sb3MDB z;pf4H{>v9FQOZDR*Y!2R~X9?hk=rdEic-XaaLveHVlk-Q$$@% zXz&W5%GqaW1TLT-$>)peNdCl5k*{z_GJ>Qd6h3y zD1;O722rI9{rEtAQ4vrE>KkIkW;g)^(SVkLBFsIRSHw*sR8^34e(a?MSQk*kw~J0_D8l$}V3X zF2vFbATvSWvG4mX%&d5WG)86hkK=&>t80nH_rDiv5-OWR9lSO*U*4zN(iG*<{KR|+YhEeiwdM#M|u0~kuD9RcY2MDW2r>Y z#HHXdwlA9662ZrVQ)wIWg0VAl=2wYls`#}I(wzYDbsncgvf^plQYQ?cCbl4E`?aUq zdg`Mf%x|mjGezIDnR?1XHEjWL~E zi7=k>S@GCd#=z?J{MKW?-a8nchvk7<%SiB;&+YZpTDM)9ieF55_TLP7KR{o5hyD1~ zr(ptQRF4i8e(*;jJKNZpVOFwWWvxQq0mm5qDBCxXk!WY@FSOD$GJ5vZj15jlJy>LQ zETeJk%%1FfZ z4g+451irkMl}{CZq%d2(!&39&+df4Nsa8mY?K8i|OyGyP%zB59!CwLm0IT3xV=xs_ zY_O~ZkU5*mERz%V94TZ)vyq)z3qiQ*tT#-8Y>F-Y%vD%lSf6__$)jlQ$& zH>)|5hF@7@Pt`}EMU;fqf&6DTHCLbnyaokUZ-}HFpiNIvYBdTVl>1Jkl!tVODH&1) zCyGV@h6to3`nkg4?W!^bX!I{$I`!R}={@jEU#K@vPEYL73 z?T~|{`~)p+8>=38xr|q7&I0C=HapzOD$Lw1E~?cCim|L!=J+_8$Sgxy7LN56C9VST zfJk>Sgc30_KXww4hb~nRieaHwdRj(`1t;IxKVWlutk5GN#vE0~rMQu4YeRIbU~JPk zn620zF39rC?30eP4whROWyX<=GAqu~(_<*2m}(nEA-LJe+5XHwP~$t={@quZ`-?v);b3p{moFIg-UU6?)U zu44kYN%h5Wy_^tpGct-|_@IDR_)K_D&8LK}*SLzoMogeN3etK zlD?QuW@t=Uepgxd_rc>sxBCB!fyW;A>QPN!o~*2S-w}nNQJ-Tt1&lFXsnk``-kGcyvKSEkrFT! zcS!R8g$a*TY3K6WC%soEnBedS&lRf^m5}kTaaMfIOH~yptPVNLVZtWI`X$@K%NK18 zWW+Q(luWYgtOcXp3Ay2rEYvnt8AN0*I=M}ll!Q`@Vp5xe5lUEribbSwJ7qX~?QOO4 zA(f�i~jU>H#B-Jo0@FkIX5`)dUo`*lS+Q$eD2lGU3J z&jj!>ge1yFXG3kRPUM>(c2RUQqQKhgOfNG=k-b}cJech4N1D&N4%c6N1Lr}axZfVp z=lZ*#(JnlXG25s2cph3UTS-r4JA=nQ>i*%nTk6V+`NoxLcrt0xe5Yd{iC53i<<(B# zo4XgBM!C-Gt=TXSiYF6C!Pi`JF8qpGH0UQBrXkJ_U|^CS*ALQbYtP8*#F{MTlpXftU*!76`S#qr`2JC7&i zVMtzcOXdwNKVh4t$tm#S9k&~q5oTaGw&^b^gx#t38zg6`f!gzdQ6wV`TIxT72v>tC zGl;Cca*rX$HrCe+Bn%~tCw#m^5}#5^+s^Mf^DH=mYeqPyMwaJ$*>}po6PodnF|PLT z+3~%}1W@YCpgoVUIhGH10NNqsk4N0tnm^Y|g(&@MI<}bUQ_JXFyJ19Gc*|!p`pz)a zYQE}0t%1Cl)xCFBrS4~gElSAL&GtbE7PIZ(15I^Q8Zx<0Ohn40h}T}|+^uxO*ebYb zK8Pn%+2QM}{>9ZYzs$w_V?|Orh6u8No<^LV4*-jM5sjkzNOmt}Y&AI(8)yJBlw zPxoam>M89zMVWQ8_hXjVgJwlIKct|5Cry>1CSWuRPZi0|G$QoC8mJ9eCIpUR&~`f? zG={>E>d^~{ow5;2`HxD!X&=WGN~i^<6#S9;EIxsF3{KT~sO>>4T7?K)Su1fuW4|3= zF|)vPzn8?mw^68xW}&|Y3R&_JB`&)=>$*$0=mcDqIw{FeCr>}G9yX&;{YxMS#42+Ug|F-H$;ev7bFfK@)TAG?I{D*OQpxl0JR& z)Y#5@j_)#jSHGunWkWJl~-&w%T`Ki&5u zl>PcHuzqbM@BD%%kXIlB-Thf5@}dWn=IKt57t>dJoX#QDo^%Cg8q0`9)TkL}7u@|s z(}UG=+Vs}Am6FakS-0B@+~7Y^D^F4p8%glu!R)?p86A-f{@U@rV>Ur;;#y>y1={BE zS-)aK%l1B+7QsI;3N&y&EosZ40@SpWh;^(;X>s8w{^~?n6@D6+xeK)@4VL9ouf)HO z-1fv#9NP?U|C@=Rx7`9~^>4@5e-5ws&Gu+P>21m;DCj)rQOv|KygF_3JHNCt^9lcx zwp;ybW%;FUh|_R6aFC)^gd9|Jx2hHJ(oz%nax`MHe>{nT?iBLS?ZKd+%XPREu}m!5 zDI->%aI_k&moh6`yltoJRF_56E7vG5Qm_7!UJ_$1UaAp?UJ!?!rZ7F9)Kz{~>Pka# zyd9`@AV@D7W6O`*-a}wmbULjz>CB(zK|WJ_|7*B4bC<>Eg_{9SJoVb4UhwLghnzV% z%j{Dzx+Jt>zacZ0f%r?3vBb753)yB-G^j|rMAo8gg5tJ2j~w@ykP6znQ00nR1o4&! zgCe7}W>C6SNBOjP><1|9ZIBIj9xO1fT|R4atb*Z2urQikwq}<5<~dct4|nMZ+QSJs z#5-(fR<~Y2fhw7%U`M%5u^W{f%^b^n4jm*NT&M$MT;euHooQ}w#rB3(+-O55{%{2{Y2!X>vqM#A@?9`e~-nDZbwC|;R+o^bG z7=<>Kj(KKCX0K&ci_rllC|Cwh*WKnMgw2%I`rpPTFG@j@_^X&=@p1NFfWFI&d!AaH zB}VGwxOvLZhh??9H{62vv=68^kB+f*w4k$ygXBPR<9_8u1E3{u?~muzcTqg36pEL+ z)`2u_P-tg(`AC)}$GRLaIC6xR6zyO)@|{2%?$yeManS#1r5YAAz8fEr#(Zb{FY@}V za%`KkOGgu;mS?G57Kl=Bf^4rKpItLyLd%;A)Os^Ty7f!5m^(jf1c+}yqLR)W_jaMQ zn-ZBde*vC2G2jn|EOn9)De!f1gIM3^jle^4?5_M*@y#BadKh%CNW1 z+Ocqa%z=dKTklk?R;)m!L(c9rLPfu;Tia$GPh)pk=$SsLa^=#kh3#WvsJunpiXv%~ zd|nsw7d@(tY0dQ|)hl$L;?t$$a|B;59%hIYVc zdK=G@l+n)F?(7!Bc%ZKDD;5q>E>4LKaWk zIUL2z7ZWf0b-dqhi1!_K`@{0)zV1WY$F^CpP~EIzRmyRXWGzqVy})?B+Oa^gE7D=T z;x|6#6{eUe30e!xLXUK5^B>pC4ZjZiK}27(#iv!+k*)FXD!R4S-8jA%^pa&z(Hj&0 z4Q74!^U-N-{NF=H&+(Tjx^=d#M3qv**KI^RW1F5!w8l3^8exn&B}t}IE& z{3!$N)SqVsqAQ2BRZffliyE_r`Tf>Lv|y1& za4&{C8-VdB4J_$j8Mqy2)gsH0i>{B~X}Pkf;(zKcdz5&L_M_|oyqxp+Ub8C1l=gAV zI#Pupq$vw6-;klgbgQ<0+9aU6K}ER;@RGUoiHb5_Oh+Bg}bh+yj;gGVfH7%TNKqBtwKtmobmRsbWBYBkiNc)$RvsU~B&TrK1+ zl<@7v!;fOTr>cl3kH?Vow4OAy~ZiGm428Zlp;+`4WPQ1eQyJqUqBG zT4w96LlK+vM+AgC?+gp~EIGPjYXv6i0{q1^$8_!h0QX(~>jfyfxL)W8pdm~mvlFPg z(!eFt)~W}OY2sitB$%C?2gwk2 zChowYiD&`fDwQ(l=IB9q>B%Gb+0&9n*Xyu<2Loq`mD&ug2xy!h zR~tbg$IX^<_KpX~^#69ntNAT^!EenC#`!&(N3*{Y3CWkAB&d9ovtWnt`~xlK2EU<~ zxK#b3H~fF^AEXmjLtSZBY-`t?TaUmFw12k{HTj36-Oy7u5)bcG#4y{ zT-Gh`h4>Bs)7o(Ri|zn(>FFO_?_zn_Bql3ktGEz5Q$bZ~REemL@sCyvs3S7Si!EeE zo$;Jr^Hmv-^ds^7hEfs=?YCe%LM^GZYBPt7d6j|nJY%#z?lNqI+;v+l2x?R2M#TGW zUs$Iyh0^>NpWWN&-`ZGw7Vl&Hi_G|MhhF;Ygv}+Yi{@}-JhxtU`=8-b9^g&Oh)YSO z#Cr(_E&doCWs_G=*=qop&T`oj-19)I1zWzg=9k63Q0cY1ONczC-NTh8z?&^r18QWl zK>;~DS+f=_I4f}vA;wFm;UUB3t@Izv-U`YKWGm12vZZH-&Xc;xxEYit#LDvd->K?0 z&WLq!nlJ1ehLu&0iCP;}x1amn5p2;w(g(Qw`(4M@1W#Mh1ZHc^L{vgZW#Hu42A=hO zJ%83>SlX@rgci%+SyFBbbbr*qnr+%T03AlU;y-v-scS0YCe5}m_`R}e$m+z0ViS?1 zh`X!IuC2dk5%@o`{}+Q80lDeERcy?GHva8`iOj9|2wfyUe|LChjUZj zH}k(1?;M0}*X3wu19C33)-+4PrX+P{Y9Q9ohg!r*9mK_*#b3($4d=@)J{UBO^?V{_v$o$nX^sN4eFUbqR8u(|Qut%1&jJjF#u98ON#5awd zuIbJ)e0JrnB(6__IKAz{pLSp3gSWySVAH;W_dis4@5OYcW%@(rcxgKaS@(Ks*R@WH zJmz*ZT3-;GH+CR|-dBHVlVzIGN^-aZH3tTC#@x*uY-X1kD(F1eL1G zhF@Iyn7kX{7wi?M$o_rN^{nq->ze7$FaKVyNd>c;=dI=Z(mPSpvl(8n%?8wr?Xs8# zhpa;7s%bWdY!n)~lYUJ94Jg_JzH!3*p9H^F+V-I~IMBizQ?d4G%=qB?<@Ay0w>{XJ z>@zap(0rLeG5H7AX@lT|g*LG)R#UPu1YIeWoPq|+ktOn4dr8LzB3PN!66O26-LI(g>#M{fS7t6V&2+#fEu_CLXjaAe_Q1?$l16$fzM0FAZ)}Qxa~H95d4ojoa!1KMSNou zbDiUUV*+eFy!nwnmpSY#h->qJ($yq5a(X_@2fUOjl|{Ac#4!**54NqOF`w9)Pw(d`%D<#U zda$$F#oHyJ%f*_Ed#Z%ygX?Gx8=oXtV&-2$H*xyirv( zl!c>r>ViQ7L)-)~?bauTjq)X&u!G}ANN_z=gi4xKzWhCv7GOpky|!BiA`58wPM>Qi zq}D~Wno6H7$xHDtpX=p!DZe|3e^t|PLQPt+sM1Y~^# zF~%5f7G+7sy)*OU$RM%Co}ims{YzSV8pil4y3%0vH1vHaBnwpGBkRJih!z`YtpgIZuW9sKru$D1{KCC8>2gAi$;t23mTTs@)CUqMseZFOfgGH7v%Rq zO~>gC1{S019Jh4elEKVx@TU=30C6&^Cx$Kj;V0CZ$_3)#t_sms#2BA)l`a zkmObKnS2hZ=u!GIwfzm9WeKLP|GLLB;$`+IFm<3?mBKt}WFF&?Pc;z!>k(k>TMozy zZx%OL>73C)T#X-ze}5jXf$P_0fYUvQCmnDgx`+tCcgpyZGS*NxYk#c@S?8o<-1_ul zNw0us0)AhIH(ASvE0)YorN)D^@iKxi}choYT*5P!|`I7lcqA3P9^+XxbCLyO94ftjtjX&80s$H9$75D z?>s^wX|1fs+Y;M4k0_%U21zvhW);W)#>7dGCB>&~J+v;C&ueeEzQF$$F-UqZ_9IdkXO{m+WD5+q#-Vi0&A3vIpoLESFTs?^<_)3#J(Klp zF1d@L+&_7eO8QEeWQ#L~4!)`-o7Zkz><^(|eow{f_WPJYW#d}pKNPBvRZ^wMG{LV| zmUkp(o+4ZPF;SKKh6x*5+HB^1knaDJKG$b);BC+=q4@bm+9tU75q4_+ zHV+ZL^B!Z^LKRx`ol&Ts7oZ(@pc@ZuejyO9K1jwDh;?4FLYsWu*ykwwFt?-1MgZnY-n^iGvd$W9~u+A+@bH z?y?ni8dS}N`-@#oalc-v;5RR}{p#6Ll9T*k?~JMkVUkZeH6R79coVA7`yVd9RlD9| zMlHzj8husZr2>A^?@kaVl^h}85!{qLs?PIdLwi4u@V|fmdzth|jG{hE0D+^1-?{ZA z(1}$a_TT-~6Ibvip{q%RkS~-g-YE-jjO9&B_h71yXcMMIG2}y0FjDPfjL{@`OZ4WF z0C(b|x|mCq29MG<1Y(BwT|N7BAyU0^+mbx-Yzf{3-?G_^6$jM=N<+gTB_IVbR34Ag zfg?E3+m~M$M8kaHM$QBS=Bu@8OyPW!KcsK0c9oYbDD2gkXfMY+SqR05eqwhRO}XS)Zn_JrkfB%di8}J+iXXPr4HM`-xTFveinS^xHY* zT1S^fc#YEM zvMC6GH`WenE*Jenlg`Kp=FG_ghLB0ASOu!3B36%Pg{wATdfUNyo#xAeRf;?6^`Hv) z5O4XkaF@{6qH1A-eBr=TS0Fk)v8#B#8lEHpmURELa&<#B$rf_yR@c{=**tmEw?2>Y z#baxBlz&O2mg~w`35U-{*0;}XW+2{uKVdIYrO1)xw9{4LKCQv{Fv_gOfuQ)!pu}*r zU)0~L=a*sXiVo~ed%_puox_IVDMH+_iNf?s(AX3U0CEh1n*jaxjsejZt!1s^On2^VCYabPzA8Kwho>xT!Q zE?hHSS0>X6l49s##N@>07er-`zgkm0!@qzTT$Vct=O7bTUP?m0DhYZ{z1Q^Sf*FN( zz|w?Nj<5{|!Rt_Q=wkoIq__@A9*Q>3!Id@(IX}5oWS1Yl&>qd|v#HHAttA~>B68}F zJV#m&pf@ZNYp(mT&#kZaPF05bkXikWh zVjTSz>2p2L>?2dZzx^x^w3Mv-RjJmTvO?nPT;yRs^#>;hLNB>V8I>tN8GWyrs>??g z_or%#;M1){d`luL4qds|K{Tu!b+F0v@&2ge$un6cFDjv+ZwX%#1P5oNp6Q9ZOAnR_ zOTWq#Z`vGxu);HGAL%9xU=JbO;tI}S&CvQw`fSgpQgRxQXRt;<8zZ6T&E8J8o%VfK zLiXUQw99Nd9R<5Uq1xBjA0U{_V5g1*{@+l;0Jh0fpNA)~+g7QmuV0*X$0bEFRH^lb z0C}UQnY;gLj+va9Eb*HnQBk(9=A2msi^_2pT~$*bDjy$-NBrh2fxrsNrE6$vc32ST zb&p9DL((?pL?nFs)tXEhPTzSNu(R=b$~2I12Wj$N-nXyDR`(~7C9?WQtQt{W+nNXr zt0S%xz$#rJ5cr*J+sITB{HwWJeW5NhM$>tM602NnGh^?MCs4*nnifVT9ywd$p=9+2 zi5(EDd91gM5L%f;qsDA@*o6t^lP4aKhLxNItHqh&)~E$|BueYH>po6RBe`%Rfc0WJ zzL=CX`|GEvND~z%QJ>D}PtkH`jL-f)h?@8n3YxnemL}mXK^9u8rudZUxp{6zLHi>{ zcjl_24wz()aEQjM5udtNh@X!F&dE!;B$zVen$hI{?}AVww3sTcbB=0T%SA{NsIolX z+?pza*W*}n9YJW4h(ieP72B-DwJiDvNrAk#e&33z93%)l+#XW-Y3?nstt@}>~1Clw!C|b(Obu6N&ag4NhTCx zO8V#~>w1Oi)n&IB!Ojjk_%T$?akY3pZ!lQ2jfct%>|#xbF&1q-|3dlRma)5rE$KDz zOypRT$p>+Vn=FA~k|#*b#1@?bHCn%$C+*M?@_NA!MSgq*EVJ@R+?xc zMDF)!XP?(KLMq>E1{Voc#!3fQ$&Qfxg+JE*jp<@ls6VN^XzSEb{aJmE|Gi+cB|m?k z9&q-mT7yu3FdXvwrPyC5f%o6QN}PMs(y`^A{0ha${#~d%us31|q5JpKOu<6_Q<5j* zy09urG*S6FqaT6#{a;5Yx|0P4hwXhvw4>B5pbx$8K~o2p=OJ@NXv*)4!ls3dpn_UK z#q9E!XT)0M8M41&B8PN2AzUv)u^bgy+JeYJW+wY@&w7|8Q@6ndvzr><_n0<5-ODn* z13TT<`$X42r+negutuYUfcH4)`kQ&;gEH$lv|BMZx?X!7@Rwvc@DFNW4_+ z*4pmCwOC(Qtum4QDnnYUpZy7Tu4(0Ja;!&uBFU zA=jep(SQ98`Lc&o<+9JiSVfG6~%Pp)5ORbMi(f8FC zd)ZPtNLIcbT&~82M>A;E_LTL(-ZaM1b&|da3daYjPY#NN88IW+1*UJm2P)BaQlP-; zkoUk8dBy&ra+=L5I$gkyOK3~#00NuD_;90-;LsVulSyhL`@Q9PZ@*-SYxXaH2Vs$g zWgGYw!3uWx?hpty_`@v{CcZ#A8O9Z8;tkOx?A@)q-jFj}=qzdSEj^ND>QcP{@rkp< zzOnMeyC1)2TAW2H^k_;rFq-r~K6?cb%UWVQ42xYLZ2vk*N5P5ybvY;b*#Vyn0*D*9VP zn(Xg-Hk1-D-Q&>;fgd5c3!gQHjz<%9$vEOoNGa`jPMh}v#(|Esb23$rQyV-#>j*{S znfpe*nC)pgENdGHOJ9f*(6GLXNrz|pBL;y`n+54tcB6+cZ4!;3X`J1Hj^8xY1+!?M z6RMy@m+59>dUX=Du&_w;(x z-4l{aIN|n!KUN0aZ*HX3YJ=_)R!0(V2&#%(CD=Jv@FE+;d(^1>U;gd zG*mTUmlzM|KKMr{dU`k0v#Z5AV*FqE_Jy+iwf&djiWi?e6U~bL<`H;r+{@qZLD7Z9 zX#`i)#x!;W)BwPx{*?d>`UzMBaL;804e3`DvkA z5F>-!%F=!fs#kqqJ&DM-xVF)SEU7CYJDtjID4mE!LlQZDtx>8{h-L#2qIhvq@^{LA zQ$T~Di0GH#iE4kEiRw}WBNR@=dxS}3GcT}oU1&ITv2QSkETv_U^eb#i^vxD_TI^qc zmM>dx17;aF%?i z#G4~zSClr&_a-O<^SkPDvw1A_A|w?J!Bubi2Iqrl-%wr&$S78o{j;N}*q^cL(#7!8 zg$9NyJe8gsG=Ikv()VF|VQ{zUt^qO0v5vHxmtCxH8ZXOBnxe`f)glcJ;l>Aj&8Ye2 z>=}=`?fQkxBxDveHS zv#ZXt?El4nN>nR^8|Z1JO!1jrNY_QiT);XK+B8u zYnwc-2f!NNwE7;d;L$ltyopKI$0J^*pC)Nxx~{48qi6r*Vv%n@ zwe7A@r&X?pDbM)DP;8oV;TAFnHJRd0wy0-FPDZI0vbV*k(~Eve6g&`+(+ye#yHe6+ z!H!4r84!oJn8cc=? zEMvkBmY!U7x5XFw#_ujw*se{hInbIRK5~uHyH=rV=B6!r6a zaQOr#kn^b(kx2c--FKzf;v~bXWUlJ_L{#@H{j09cABxo)ReqsWo99P=UhyXOz5KSu zSY8<&z?!4_Zc6P*nnEt&(jO8pZz22Og9QmeFhlQ$a)lF&sh!d z5ZEI+^|~X7dbOCTuSi>qgrhtdw9=!866{`io)llaPY$gzx)lO&2WmSAJ1+9M(GS~r z_Y5hEwzPJuFT!{{-faIht|$f!2J8^*Hmxiq3>8MB573=uy117`XnyDdSUBo1un{HB zZPIq>_QA4l2Xd<&?P7KkqqM3CU3+P#>apKyrmrE_N=y8xL0H%XEcJ(1(!daM$9QXY z$3Z+=t*)rN(||#)aneJON1A7cMGv87$i&9;Hu7r)_#sb_$%W{f8;)y0(M%x zN4!lV{d!>*5}DTph0>UU1(6x|shlD8QVS=KS(nDm`RRw6y4jCIWH(DHiboGRx<6QO za(hHZ#yZA)NH5)Ti>AJX5StO>Z5=^U)!FJUGM;4Ij+)V+LPV*Xhmkzr_NJZlYt**m zKWFG5itM#P{P#Yf_rO{`oB-qv`u% zeMR%a(%K)rzh%e@&f`tk$_H72Xy+$M;!{`Q5oB#u3p+PCps?8_#}Q_W2`lrtJ;Drg z!VHdpkF)fsM)%0);l_+Br~a)Vn-r~2HM;{AOK?qP-e4?Sj1u zIs%c-S^@NjjW=DFL6ZyqQ!p8p_cQL83!hVGX!cLit?Tk?We$%V?j~vcH`v6)pE_kG$WSJ>wGe!G6daJ8> m!0h;2L6A(6^gI` literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.mask.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.mask.png new file mode 100644 index 0000000000000000000000000000000000000000..3ebb967560f0a9d474e71d36edf028375d984561 GIT binary patch literal 450 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX3pEh7h+$+kpa|o-U3d6?5L+b>uyuz`$}a z=>NQKwoUvCW(F2SGMmraT(g^fO;tJnj=2pJ@j#G)SilG4$Gglg9IhztVCfl!_(MP~ Xr-j+IP3CSbC>%Xq{an^LB{Ts5OZSCr literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..77577a65601abe1b7eb8d0771e8e1ceb795e8400 GIT binary patch literal 3930 zcmeH~c~lZ;yTH-Rv?kYS`O2-d8ke$0GdDD+!qn1qOc4|r7Xk^$psJ)xb)rgoqNvx>)vzjpZA~VyyrRZdDi#+J@5PY zinsgjodd7ti|v04isd>#rK>N*Q;Yf&>7x4|$w-^G6l)rd&y1T6KG`Jw<4L zjGsGrv5eSAj9)RW7Vd|*ckaBSUND?f{GrUo+~556&C;I;u{MrZs2bYZyYFP|e)fkv zaMmWvT_y(o4_jLgnX^p5tn9Wrn}5k zHmZm9PeXS5SyA?r1vd)@`litlQQ9#T+AgW9=On+&fA{lTaP5&kcdU+L(|L&)!ClzV zl)#^{%#EV`Vc`qf3^ZgEJw79y#-kvz9=p&QJcWI)G6iu8y?zs^-2h4#JM@S`WfDGeuodVqHj5rjLMUNPanaaSftP&!Jea||SoN4H{!%$G;{L|Mro?$J>qh3u+Jpxm= z(En&kRckOzCdOIpbMuq%8bzbnn9(ymOn#hgDN;li8~HdH^EPl`P$hHaPxoQU+!DEq zC8iZM2ry*(+bnsIl>OtY+&MO4Frb(&tgP=5C@A6<7v@$76h9(qDdGZt_FVWJnszb} zedfT}yh!verjo*o&G&utsGQ-|@d*ODDe4=O_OKqE|Ct7SKr&iN<|{&iNw(2ZEvj;Cu!1@EotY5fCjz&J=o?I_phLXUtazl(=cAJH2;O`;KQGA zmnw3qtZX0lQ*_xDMy9ZC67@Vf`lbSpP$f0!_ zgqvc;CDm~|5CTypkIKXVg_7ri#T4`!A9b9+EF9a|K^1#GCZyQP>I@RHH@I|osG1{Q}N|J>9aG1lY&)IgRW6Y@)?qqB70*hnFVns^AUL^6?-t^ z4u3lvIZQ^kWeM^NBH5#sO(Buo(I4p`n;>bLWn!dROb`Q>mV3RR^$1URs48xqD255VIH-Lk_fLhrp?NTG2!aqJYRIBsYsT}b=m3XE3cT_a>e08s2P z!b&h zj^1?Fhwu<=?S_6-@hD!cDGx(sLVO&kk07^9XE5rxglB2+8?}S{8+V+(;v2@_=bF?X z+ttFEUMDkt_P)IbUJ}0cM+37&g%-vUpdw_jmbh2JY7X%eyf`T+D1aS%ToYQvKua(4 z5^({l#uQ$~R<>JwfGu1h93^a=@Wkc2%Sz zRAo+Q+R>Asnur)6tYD0wOKeevj6$`_L{IOZUZ;MZ91XxF&PS!&xSQ15lUKQ%1GV*o zFxiccqbt)JHtZQ&)yYm$#W~iq%Dy&`dJ!7k1a?4?oo`8`o?s_;h;I>t0s!oG(^XhM9H{-H9LG0#&)b%rG9&It?3sgLY;v3j;&9 zx2~kXR|=gcqj~T{Sk{%(LZeq74}h`Um*k#Bi&*&#<^ui7q+^QpL_E3y9kEpMu)5?- zJ_yT_U`*p9S(Npt@$jgJHrnGzd;$oIs(z^YD9(M474o@k-+&uJ&S=OrxT?n7MM!6U>fuNix>`Q~47$1K=^ViLUe0yk< z=XySFmpxQ8r~^6Zjm)rck_5%<@QTb5QHXl*rQ4C+NyP@F&z}A6pX#{t73l1U!Zvrk z=%`7Uhukv`#v@$lHLBcK&V6Svl4O5475gQ2z+OCV;+#o{$;i$OpPB;Nv}VqwXz2pT|_(ru9`9itP`-8Bif(GwS0~)ETBR*-Z2Pr#d-HA?ZobTSZ`DBGZ1w>8d)VK1;GDM3j7}rKN} zodtdo%a(zz!w?ysIb#PVUL7l@JdBD`qhCB4gDn?s)=Rn=ofWO}_4q7?`uw{`?XEVDfZzq;k$gj(uB%ZUZGM-AJzJFq)!1VvM z_RbMuFV#WKB`e!eSc14?+sxEGIJ{Gn`^4FO4*qrjpXhh{5+~K0HHOPRG#_y25B~6v zVd-00Rpqxa0W(uANL`8uJcMnq-rV?O-~RWYMy)V*XbLy*wk7z7R^9| zypu)OpMlCK9K**0EaNU*U?*kSVF#FT#>w@&@mxLr_BTk3yHO4Z0cH|wd(W;Q_GP3S zfxaQxXq} z-Gduff}Pp}o&A8A*}r=%$D7wQ+%emDMh1KP*ejtK9eNEY=cT5n{zL{ofMvQJD^by& zRJZxZu??)-!SMcC-7xVo{uiOmW6aVBV;mC@=W~hU46^>73MS^jy@ye@!xc4EPY2hQ zk2mh{`4ym%c`od~_=|(81`8|Hfm_;RI{`Bx_C8vM^P*LTGr|kU~S$#o24y2o+IJWbl}SXoXtv%zqiQJRTj+nr-+k%}YQ-~gngIWVX+oOZjd zCf3fJ5<~+uQ-W^iXj@bg1r!xDB~wIF0|W;y?fc=L``nNBd^}&)v(|dnde>U-df(rF zt-EJ~{WfpdwE+MCY!2}M5efhpc<1hB+5$$)^8z5uI`4+)Z%bpZITiqDsi7iH)Zj@A&c6%r;u*5Px@740c!b7oG%!BAwirx@(YttM*r@z056wRoj z)nk?ToP%ihjRzL7iyN-g3-e(bILOyoLxw(%L*kvz;;bJ8Ab8nGj`Uasx-Na|-YVS| zd|X^yKbp0=Z+rZxJ>pH#RMVV>u5n7S{DV4rtFRi+moeH!S{NU-3a60V~sj36W?(ZNph=1b%HgSzg}9v0R1DY$|b-WAB~Y^{>F0eFxh zyzy6mvNXc&bRE2IZova|!{1|(1L=Q$uR#WC9yK#K%o?0Ou28E~#JrWIzVdZ~f;sne z!IoC!m&c6dbZhGsum?*zle_x(+zQsaV~k{x({<_I_oK{&RJU4_$SLzXrOw*wRGi$LP(AK$KrKf z>+O(|1J$#lYdid;r4g>Kbvb8nYmu_{LTL<935HQt;9@vaEK8d-zw(^KOkYr7oD?%_ z0|o1QG=X=k2uCN#<(c;jrg+YfycNt7rIg0f-_oLI|0Rbbf>iPNfbV@M^OOpdxnh+;IRV(byYsVJpDkZ>Ipp z=GzU-y(9kJ@h|m?Za_H}FX*2XzJBuFslX3JYvGvuxUm#cu5cS{8iLv8E-5xwdn(3DY*SGw-amp+uop z6GUHESP4;U*3)fRaTFdY;U8EZP%oEGK}B6Ebyw*^vJh5LEf1lxv#LlT9DiHNWosR! zIS7R1ywr!?Ko%mJml{V@`OCfpQLeu{+(QR*_sidsX=Q@nZ*^`8aE$BEIU;+I= zl?Q|{r`#XmPxf=;5$>VI9fZ~b(GaOw9KI&f7K{3$6uj5X1$V?pkS)%LRx)`a2E4wO z(*1F!e|-HJ4;V=p6S;=8IXN0tNWb;K-@_H0MxZWXf)h z7}Q8ETJi80X0F10TZ|Mq%1;%>2+zo;XVeYCsNhFaj=d*3C(luZBm-{zloFGufz#y~ zt)}Ud^x+BBy(5(7@hHRQVj*t%j691N4zOj)pRe2xr4|cc8X*}pp&0`QBblQ|9Ty5@ zO<`G763_StnoYDaP#!a+d$A0_Zx)L4U5{X*4Uo-N)SwyOCRmgKWrgVT`O%}sYH>RW zl$$VpM{M#c-Gqm%XuSF^N^jhTwJbnfJM77DTvJMhyB7yRd&sCdtcdV%gmJzGPt zT^DdZ4YdZp#94t$$pR0va~^2N9vg;Koj3^<58(C(WR-?kCQjBtMjp>ds-N!au|W1Q|Kp8vR|$R{i2?$UvBr4=c(w-1m%Xb($q+OMHBsNM); zMXg#Uo&5l_eJQ@JU6EOuWeED_I+51O4$y6K8S^_a-PCVJ zG6;NIZSgnY$*%9Z!GGGuSGO6nqkesOpJg!Sn0k;e*;u}w9`(A|O&5IVfU2vsYnpV3 zUL0~_`gv!t&KzK1_g#gt!T(5RCc(TULze*%epq!e=H>Pq#P})ABVOMr%#dUNrnG+r zP{01x1*$PRF1Z81Fzn{Z(}0F?A3(8d_@9G~THXRoW$!Al!rEddBlWY5xQ0fi`9AUg z4|P5&T3zSY)Mi!7eA1q|o#NJPe6vwoJH4?^rQBAC; zS44(nW6r5U^;|`mx%_oq>H<9nb~1a7$Uy3>N!%1r6eTti7ou~m2%6W8_1d7e%!>_{$4QaXeuL@Y7MKL zc>A)QB2Vr(ZFy+o)&NBCMq$DxhWk8cp^#Yp!%rPUDcMt(*_avf3THMfGJXE&wAj{9 zJ|8W`QnCY5R;Q+SQ8s@-fg=|2Nw$Vm@{|uC#=X`z2}HX;7?EXq95(3=g6K6& zK!Xpa?e5+Oypza9PMTj!N&+fCg-^=n+}UF6gO$Z$`KLV7v(;6hkXA?ju!kbyT)hy- z%T)dc?b8Qn+c|yoscHt$f^^^D9JOd~&kuNx2XDI!^Cb!{R~@;wr4fkE%-QL<-$A^w zfSZ_P^B@s9C>#ijx65YapY%2Z>4~F9h|e<;u=AQec2I6wFIpHUn{9;jcwf)*jX zM727|1XgAbLp7vFsu+f%sWc?y=0Kv2$V0`!-#zM<-rUvHeG@02X7smtGMl}~gTGQZ z4vZ!XGO{L+3>qF%nH#&HX3R0l3%_Ju$20sKld3&6*;VOT730b1r=+(RT-wj*c6FCv z7@agL&S@!f6;b60{c^ze3p?d-e%cSZonKvibIJ^e+_`{oNYU}=`^{uA?H5prqiiSh zEd64uZ-u+laAoAaGwum^AXjV%!hEM^snxe^_=eqY1RXIPYk-Zv^4t7#zNNnD6|=6{ zi-yQm(W=9KQufsdK<$ilAa_eNr-{Cs?Jiar6}w&y!qt~=FH8da$@pH&VCa_XsBN~l z9}oTJZmY7rx#wzZP@dVZ_iWf({+@4FpP1H{c&CrJWAKlKd^?6Bx$ARo_@$I24OW3Y zALNeR1-dv^7EIV4vD@zchP}o>yZb?`ZI`EPP1jw`t>FR;#(?0z7}}BFQ4NjQVTX;3 z&BK*UwgU%5gXRHVm3^YIp*R_{p`B&H{+>8u@=oIe@ED8KC;FeFp#XVLuTpFjMG3y9 sW54|0v;Qv*`foY;CsF$64jDni4?hl58{O0YiU9$qf`4rIA^zrn0aVg%82|tP literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_ARGB_8888.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_ARGB_8888.png new file mode 100644 index 0000000000000000000000000000000000000000..90b422792db10a0205ab8fdaecbad4e1588d2106 GIT binary patch literal 1024 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fQK$30yfLn`LHy>pQBuz?7x zqxufUulFZa1#h3Q8zdSiVKmY%=d#o^BC`L^C&hYl_ z+s)PDn5Ki&-DBReef#-$I83kPzi{uK-R^QmBsU>Ue`@PcUH$vbsKwCO8Vzc+WHKZZ b*H`Ar7Xk^$psJ)xb)rgoqNvx>)vzjpZA~VyyrRZdDi#+J@5PY zinsgjodd7ti|v04isd>#rK>N*Q;Yf&>7x4|$w-^G6l)rd&y1T6KG`Jw<4L zjGsGrv5eSAj9)RW7Vd|*ckaBSUND?f{GrUo+~556&C;I;u{MrZs2bYZyYFP|e)fkv zaMmWvT_y(o4_jLgnX^p5tn9Wrn}5k zHmZm9PeXS5SyA?r1vd)@`litlQQ9#T+AgW9=On+&fA{lTaP5&kcdU+L(|L&)!ClzV zl)#^{%#EV`Vc`qf3^ZgEJw79y#-kvz9=p&QJcWI)G6iu8y?zs^-2h4#JM@S`WfDGeuodVqHj5rjLMUNPanaaSftP&!Jea||SoN4H{!%$G;{L|Mro?$J>qh3u+Jpxm= z(En&kRckOzCdOIpbMuq%8bzbnn9(ymOn#hgDN;li8~HdH^EPl`P$hHaPxoQU+!DEq zC8iZM2ry*(+bnsIl>OtY+&MO4Frb(&tgP=5C@A6<7v@$76h9(qDdGZt_FVWJnszb} zedfT}yh!verjo*o&G&utsGQ-|@d*ODDe4=O_OKqE|Ct7SKr&iN<|{&iNw(2ZEvj;Cu!1@EotY5fCjz&J=o?I_phLXUtazl(=cAJH2;O`;KQGA zmnw3qtZX0lQ*_xDMy9ZC67@Vf`lbSpP$f0!_ zgqvc;CDm~|5CTypkIKXVg_7ri#T4`!A9b9+EF9a|K^1#GCZyQP>I@RHH@I|osG1{Q}N|J>9aG1lY&)IgRW6Y@)?qqB70*hnFVns^AUL^6?-t^ z4u3lvIZQ^kWeM^NBH5#sO(Buo(I4p`n;>bLWn!dROb`Q>mV3RR^$1URs48xqD255VIH-Lk_fLhrp?NTG2!aqJYRIBsYsT}b=m3XE3cT_a>e08s2P z!b&h zj^1?Fhwu<=?S_6-@hD!cDGx(sLVO&kk07^9XE5rxglB2+8?}S{8+V+(;v2@_=bF?X z+ttFEUMDkt_P)IbUJ}0cM+37&g%-vUpdw_jmbh2JY7X%eyf`T+D1aS%ToYQvKua(4 z5^({l#uQ$~R<>JwfGu1h93^a=@Wkc2%Sz zRAo+Q+R>Asnur)6tYD0wOKeevj6$`_L{IOZUZ;MZ91XxF&PS!&xSQ15lUKQ%1GV*o zFxiccqbt)JHtZQ&)yYm$#W~iq%Dy&`dJ!7k1a?4?oo`8`o?s_;h;I>t0s!oG(^XhM9H{-H9LG0#&)b%rG9&It?3sgLY;v3j;&9 zx2~kXR|=gcqj~T{Sk{%(LZeq74}h`Um*k#Bi&*&#<^ui7q+^QpL_E3y9kEpMu)5?- zJ_yT_U`*p9S(Npt@$jgJHrnGzd;$oIs(z^YD9(M474o@k-+&uJ&S=OrxT?n7MM!6U>fuNix>`Q~47$1K=^ViLUe0yk< z=XySFmpxQ8r~^6Zjm)rck_5%<@QTb5QHXl*rQ4C+NyP@F&z}A6pX#{t73l1U!Zvrk z=%`7Uhukv`#v@$lHLBcK&V6Svl4O5475gQ2z+OCV;+#o{$;i$OpPB;Nv}VqwXz2pT|_(ru9`9itP`-8Bif(GwS0~)ETBR*-Z2Pr#d-HA?ZobTSZ`DBGZ1w>8d)VK1;GDM3j7}rKN} zodtdo%a(zz!w?ysIb#PVUL7l@JdBD`qhCB4gDn?s)=Rn=ofWO}_4q7?`uw{`?XEVDfZzq;k$gj(uB%ZUZGM-AJzJFq)!1VvM z_RbMuFV#WKB`e!eSc14?+sxEGIJ{Gn`^4FO4*qrjpXhh{5+~K0HHOPRG#_y25B~6v zVd-00Rpqxa0W(uANL`8uJcMnq-rV?O-~RWYMy)V*XbLy*wk7z7R^9| zypu)OpMlCK9K**0EaNU*U?*kSVF#FT#>w@&@mxLr_BTk3yHO4Z0cH|wd(W;Q_GP3S zfxaQxXq} z-Gduff}Pp}o&A8A*}r=%$D7wQ+%emDMh1KP*ejtK9eNEY=cT5n{zL{ofMvQJD^by& zRJZxZu??)-!SMcC-7xVo{uiOmW6aVBV;mC@=W~hU46^>73MS^jy@ye@!xc4EPY2hQ zk2mh{`4ym%c`od~_=|(81`8|Hfm_;RI{`Bx_C8vM^P*LTGr|kU~S$#o24y2o+IJWbl}SXoXtv%zqiQJRTj+nr-+k%}YQ-~gngIWVX+oOZjd zCf3fJ5<~+uQ-W^iXj@bg1r!xDB~wIF0|W;y?fc=L``nNBd^}&)v(|dnde>U-df(rF zt-EJ~{WfpdwE+MCY!2}M5efhpc<1hB+5$$)^8z5uI`4+)Z%bpZITiqDsi7iH)Zj@A&c6%r;u*5Px@740c!b7oG%!BAwirx@(YttM*r@z056wRoj z)nk?ToP%ihjRzL7iyN-g3-e(bILOyoLxw(%L*kvz;;bJ8Ab8nGj`Uasx-Na|-YVS| zd|X^yKbp0=Z+rZxJ>pH#RMVV>u5n7S{DV4rtFRi+moeH!S{NU-3a60V~sj36W?(ZNph=1b%HgSzg}9v0R1DY$|b-WAB~Y^{>F0eFxh zyzy6mvNXc&bRE2IZova|!{1|(1L=Q$uR#WC9yK#K%o?0Ou28E~#JrWIzVdZ~f;sne z!IoC!m&c6dbZhGsum?*zle_x(+zQsaV~k{x({<_I_oK{&RJU4_$SLzXrOw*wRGi$LP(AK$KrKf z>+O(|1J$#lYdid;r4g>Kbvb8nYmu_{LTL<935HQt;9@vaEK8d-zw(^KOkYr7oD?%_ z0|o1QG=X=k2uCN#<(c;jrg+YfycNt7rIg0f-_oLI|0Rbbf>iPNfbV@M^OOpdxnh+;IRV(byYsVJpDkZ>Ipp z=GzU-y(9kJ@h|m?Za_H}FX*2XzJBuFslX3JYvGvuxUm#cu5cS{8iLv8E-5xwdn(3DY*SGw-amp+uop z6GUHESP4;U*3)fRaTFdY;U8EZP%oEGK}B6Ebyw*^vJh5LEf1lxv#LlT9DiHNWosR! zIS7R1ywr!?Ko%mJml{V@`OCfpQLeu{+(QR*_sidsX=Q@nZ*^`8aE$BEIU;+I= zl?Q|{r`#XmPxf=;5$>VI9fZ~b(GaOw9KI&f7K{3$6uj5X1$V?pkS)%LRx)`a2E4wO z(*1F!e|-HJ4;V=p6S;=8IXN0tNWb;K-@_H0MxZWXf)h z7}Q8ETJi80X0F10TZ|Mq%1;%>2+zo;XVeYCsNhFaj=d*3C(luZBm-{zloFGufz#y~ zt)}Ud^x+BBy(5(7@hHRQVj*t%j691N4zOj)pRe2xr4|cc8X*}pp&0`QBblQ|9Ty5@ zO<`G763_StnoYDaP#!a+d$A0_Zx)L4U5{X*4Uo-N)SwyOCRmgKWrgVT`O%}sYH>RW zl$$VpM{M#c-Gqm%XuSF^N^jhTwJbnfJM77DTvJMhyB7yRd&sCdtcdV%gmJzGPt zT^DdZ4YdZp#94t$$pR0va~^2N9vg;Koj3^<58(C(WR-?kCQjBtMjp>ds-N!au|W1Q|Kp8vR|$R{i2?$UvBr4=c(w-1m%Xb($q+OMHBsNM); zMXg#Uo&5l_eJQ@JU6EOuWeED_I+51O4$y6K8S^_a-PCVJ zG6;NIZSgnY$*%9Z!GGGuSGO6nqkesOpJg!Sn0k;e*;u}w9`(A|O&5IVfU2vsYnpV3 zUL0~_`gv!t&KzK1_g#gt!T(5RCc(TULze*%epq!e=H>Pq#P})ABVOMr%#dUNrnG+r zP{01x1*$PRF1Z81Fzn{Z(}0F?A3(8d_@9G~THXRoW$!Al!rEddBlWY5xQ0fi`9AUg z4|P5&T3zSY)Mi!7eA1q|o#NJPe6vwoJH4?^rQBAC; zS44(nW6r5U^;|`mx%_oq>H<9nb~1a7$Uy3>N!%1r6eTti7ou~m2%6W8_1d7e%!>_{$4QaXeuL@Y7MKL zc>A)QB2Vr(ZFy+o)&NBCMq$DxhWk8cp^#Yp!%rPUDcMt(*_avf3THMfGJXE&wAj{9 zJ|8W`QnCY5R;Q+SQ8s@-fg=|2Nw$Vm@{|uC#=X`z2}HX;7?EXq95(3=g6K6& zK!Xpa?e5+Oypza9PMTj!N&+fCg-^=n+}UF6gO$Z$`KLV7v(;6hkXA?ju!kbyT)hy- z%T)dc?b8Qn+c|yoscHt$f^^^D9JOd~&kuNx2XDI!^Cb!{R~@;wr4fkE%-QL<-$A^w zfSZ_P^B@s9C>#ijx65YapY%2Z>4~F9h|e<;u=AQec2I6wFIpHUn{9;jcwf)*jX zM727|1XgAbLp7vFsu+f%sWc?y=0Kv2$V0`!-#zM<-rUvHeG@02X7smtGMl}~gTGQZ z4vZ!XGO{L+3>qF%nH#&HX3R0l3%_Ju$20sKld3&6*;VOT730b1r=+(RT-wj*c6FCv z7@agL&S@!f6;b60{c^ze3p?d-e%cSZonKvibIJ^e+_`{oNYU}=`^{uA?H5prqiiSh zEd64uZ-u+laAoAaGwum^AXjV%!hEM^snxe^_=eqY1RXIPYk-Zv^4t7#zNNnD6|=6{ zi-yQm(W=9KQufsdK<$ilAa_eNr-{Cs?Jiar6}w&y!qt~=FH8da$@pH&VCa_XsBN~l z9}oTJZmY7rx#wzZP@dVZ_iWf({+@4FpP1H{c&CrJWAKlKd^?6Bx$ARo_@$I24OW3Y zALNeR1-dv^7EIV4vD@zchP}o>yZb?`ZI`EPP1jw`t>FR;#(?0z7}}BFQ4NjQVTX;3 z&BK*UwgU%5gXRHVm3^YIp*R_{p`B&H{+>8u@=oIe@ED8KC;FeFp#XVLuTpFjMG3y9 sW54|0v;Qv*`foY;CsF$64jDni4?hl58{O0YiU9$qf`4rIA^zrn0aVg%82|tP literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01.png new file mode 100644 index 0000000000000000000000000000000000000000..59928bcd1070454803935e4a81b825c039f3eac1 GIT binary patch literal 3655 zcmeHKZ9LNp``@I{ITRg~GLFZ)7&@Io47apdy6vDiCUhv0ki-~`>J;+0WKPPIrx|7* zhM1v)RMU1dwwkO54fDf1Z1Xs~o%_xGx!?Z(|Cj$a*XR0NFTO9X>+^lMGJo+zsPER> z4FZAGk?wBZAQ0GPyI)YF)p&8!K&3XoDl8eWz4 zTjhL%G5G-7d)E6?;7}<&y=NG5cEd9dV{M{;#O-YNgZMr5g^|)L@Rd~y3fdaaoU}jp zi0jA5<_?v_ckv|@oJoJV)Pl?&gy4}!r8Bhb6a-oAI(K|PPQNw_ZJxW{MCW=iGAoY<{Yg+3dm=Nc?Fk6cOqJ-P0tHF)#hYOzT^CRnetu9K zesi{5u3-7-aO2w1`lMBRm0wHQe?%+{{oc-z4EerOh=j%3jSyq_AE=gzXh3{yUGh|R z@&jA-`la6jrpRb>OT!T;$#T2X1@l_%@BPt6Gw zio(=KFS~-Mlez+N+p2#gno@tjIJWM=WjFoQaW6-vFE4K3r`E}1!>n3fD76F@@BbA) z!<)2#`o$yxbCFf02$We?}ag$?=ES~%2NL1n%byMKa`qWU@O^{2;?wD$nJ zvZ-)!Wu~aAv7XvA$R}=7k5rNuR*~boBuj-RM3{*Exk0G~Aw{jGfJ~T)K&LCv+9QSj z_l3fn!;nFTnjsB+Be=V_obVpH+-z-3zQeBJVB zRSX4n7!t+s0QejOEc42ESA}qCNfx(w=vjOiguW-;*)q2NB(=S1Yt-mr2gYew18y|; zzEhfr$rw&)De1pvG|YFeMLAr>e_ei0j!~RRV-)n8LYG4aJ@rHT_UQ(fO&-vvhle*{ z9hS^aM)Ymuw05hTq0gxpf7x(56zG<1Q;LqEON-dk&GBE%3g+#51W9%NXqXT=#7(kd z3Xl$d<)bl_srl6wHe&2$ZOa8?X)?b%{?5nck|8^aJe8(+6iX0#N!z}bieiW&7|?b; zSp36nQ(`ndkk`ViSF543nxE&$Qhjf3U=V4E0+BAl6S3hOd3ocQl5)OpN0uRd!bFZ) zqRtEFG2+bo> z+lbiWK*#vp!y#Q>m|ZD%3wRR+Qbgmc12;6kv3|q!%^i&QkL;D2T#G=9=WHos{xoGL z>=;t6AJH{TBkJetgj4m=%YpH(7wG4|9psh!VyrzQK)?CtZ7aK-Uu(C>sVC?&H+cwt zl1g|M24r?rSmj)=)PD94vHkDF18M=20k7;izQly-s5A?NA^ItIm3bqJ!wscwb$ryq z#H<(2iS@v&dP`A$YnW((|GLK;Wt|XXKJ-xXJ!Kg?6Ks#2$vo-0&{ro_p=JZIQr4@` z%NtMjU9|2Es47xAxMo>KoIbVE6vw)GgS`nSb=ThgG^7FbV!pzraA#z;!8>L1xBTWG z8+8V)H|Jxbs&$&vt={hd7X2wQ+rXVx3dK1S^?n9t74ul}v=*Eh&qBy1rRBmm27(<{fICLpn|D{XP3HVT9btK*iqqRS*HQbY=uyBu;)CT!GH`uuhh_(DT`5BdkDOESV>W4fwrg%avb(J> z*8>xrHM@I>ol@Uw_9s+-;+dwTBP<`j$_uLr4}67J(a)}c`~vO=k$M2%;~aLeNa!8N zSj)-wMP>SAoiC=+F7$9ZobNx2vg7YMkCBiB8VP~nonq-DyB2ok8X@+^>)euzyg!rJ zLrCezcgMsTCUsFCy^uJP9VR(K)23G%A{j0)?oh?_8Q>2kWETXh|Ji1@eqz7qmyKxB zA%2OL`SqfCdlymuK(cniw;IZnNjEQAoD4H%jfyLG&i6I<*g6PrQAvGjgNEB~0!+uH zfo$&nwM&i%zKr-r>g46kiKfl7Rs-~G+$z8AmsFK2zy~WGe#eL<_+A#m1rVFhT;E>9ZpC$>G6H|Ft;0g zQI`r_?bdy9_6p@j1b@i^?L9kcJ<4(Lnryu6&*Jp8tgpPv2bsF4r?J^*GrD)$ zao3=5?u5IX)ND1-W*I{cA})!26^EG#>^+e26(#ZXvS6Gv$!Hc}vojQLWO+u?81k${ z*fPA%KD_pFA~;5g@^`0_vg7X%RQy}rOx~x(t%}V-6gMEHiW*7=8ZF~sls1i8?$XsL z8$I@GjggzX)YDr0ccJl zusGjND>RBY-he^9!0xGyQXY1%x|T$B2z)zzeKk_O zf62i=S1d6Hw?<3kVYLLYJlfg8zo^LkeWeI7Wgud$&zu1HemV5nm2mJ3lq0@!`I?vC zY8r8}z>xp0nz4lUka)uc9+QGZN2Y@o+ouy~^vgRJ#2cbVk+)c99qFww*3uL*pZmHO zJAk`ojTgc_DG>JGs&!G;tm#B-Bd+d!K7(o6Uu{~;C2NUaC!ByhGz|NPz7o~x>|(+~ zbz%iJ?Carfi_y3x)dB2|x$iZyG^5se7ZbF!QI}vu{M+a`(Pfx-MzujkPn1notg8Y- zI||=C0Oqpik-p9ab^&=U^@8RH$BvFJ?`Ql%3u%WF?I{zDmIal>lMr@uThI4IW$=Hq zfYP9xICI`^-fPEF$hMGBg8gnY*w?V7@@qpg3r_15u->tnf#unTHVEn?h`1PM@Qijl z`E3jKXH9luE{nH5yX+1F$;_N~+cqDKbDDKFIejtM1GgtX2hyX~mt|NBkNp5o|3J{S zd$W{fND==!GkuHuHK%#2bET6^A~t1f9&I2Elr`aRMN()*-9QlesW+^szsWQWxM+Q<#do| zPxCg%x38T>!@<*rHv)_W=FE(}J-LZm$}Z?bN<021p&U@)4*dQ%T@}rP+YcfLdD_#h J-u2?0e*wX57cBq) literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01_no_vtiled.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO01_no_vtiled.png new file mode 100644 index 0000000000000000000000000000000000000000..59928bcd1070454803935e4a81b825c039f3eac1 GIT binary patch literal 3655 zcmeHKZ9LNp``@I{ITRg~GLFZ)7&@Io47apdy6vDiCUhv0ki-~`>J;+0WKPPIrx|7* zhM1v)RMU1dwwkO54fDf1Z1Xs~o%_xGx!?Z(|Cj$a*XR0NFTO9X>+^lMGJo+zsPER> z4FZAGk?wBZAQ0GPyI)YF)p&8!K&3XoDl8eWz4 zTjhL%G5G-7d)E6?;7}<&y=NG5cEd9dV{M{;#O-YNgZMr5g^|)L@Rd~y3fdaaoU}jp zi0jA5<_?v_ckv|@oJoJV)Pl?&gy4}!r8Bhb6a-oAI(K|PPQNw_ZJxW{MCW=iGAoY<{Yg+3dm=Nc?Fk6cOqJ-P0tHF)#hYOzT^CRnetu9K zesi{5u3-7-aO2w1`lMBRm0wHQe?%+{{oc-z4EerOh=j%3jSyq_AE=gzXh3{yUGh|R z@&jA-`la6jrpRb>OT!T;$#T2X1@l_%@BPt6Gw zio(=KFS~-Mlez+N+p2#gno@tjIJWM=WjFoQaW6-vFE4K3r`E}1!>n3fD76F@@BbA) z!<)2#`o$yxbCFf02$We?}ag$?=ES~%2NL1n%byMKa`qWU@O^{2;?wD$nJ zvZ-)!Wu~aAv7XvA$R}=7k5rNuR*~boBuj-RM3{*Exk0G~Aw{jGfJ~T)K&LCv+9QSj z_l3fn!;nFTnjsB+Be=V_obVpH+-z-3zQeBJVB zRSX4n7!t+s0QejOEc42ESA}qCNfx(w=vjOiguW-;*)q2NB(=S1Yt-mr2gYew18y|; zzEhfr$rw&)De1pvG|YFeMLAr>e_ei0j!~RRV-)n8LYG4aJ@rHT_UQ(fO&-vvhle*{ z9hS^aM)Ymuw05hTq0gxpf7x(56zG<1Q;LqEON-dk&GBE%3g+#51W9%NXqXT=#7(kd z3Xl$d<)bl_srl6wHe&2$ZOa8?X)?b%{?5nck|8^aJe8(+6iX0#N!z}bieiW&7|?b; zSp36nQ(`ndkk`ViSF543nxE&$Qhjf3U=V4E0+BAl6S3hOd3ocQl5)OpN0uRd!bFZ) zqRtEFG2+bo> z+lbiWK*#vp!y#Q>m|ZD%3wRR+Qbgmc12;6kv3|q!%^i&QkL;D2T#G=9=WHos{xoGL z>=;t6AJH{TBkJetgj4m=%YpH(7wG4|9psh!VyrzQK)?CtZ7aK-Uu(C>sVC?&H+cwt zl1g|M24r?rSmj)=)PD94vHkDF18M=20k7;izQly-s5A?NA^ItIm3bqJ!wscwb$ryq z#H<(2iS@v&dP`A$YnW((|GLK;Wt|XXKJ-xXJ!Kg?6Ks#2$vo-0&{ro_p=JZIQr4@` z%NtMjU9|2Es47xAxMo>KoIbVE6vw)GgS`nSb=ThgG^7FbV!pzraA#z;!8>L1xBTWG z8+8V)H|Jxbs&$&vt={hd7X2wQ+rXVx3dK1S^?n9t74ul}v=*Eh&qBy1rRBmm27(<{fICLpn|D{XP3HVT9btK*iqqRS*HQbY=uyBu;)CT!GH`uuhh_(DT`5BdkDOESV>W4fwrg%avb(J> z*8>xrHM@I>ol@Uw_9s+-;+dwTBP<`j$_uLr4}67J(a)}c`~vO=k$M2%;~aLeNa!8N zSj)-wMP>SAoiC=+F7$9ZobNx2vg7YMkCBiB8VP~nonq-DyB2ok8X@+^>)euzyg!rJ zLrCezcgMsTCUsFCy^uJP9VR(K)23G%A{j0)?oh?_8Q>2kWETXh|Ji1@eqz7qmyKxB zA%2OL`SqfCdlymuK(cniw;IZnNjEQAoD4H%jfyLG&i6I<*g6PrQAvGjgNEB~0!+uH zfo$&nwM&i%zKr-r>g46kiKfl7Rs-~G+$z8AmsFK2zy~WGe#eL<_+A#m1rVFhT;E>9ZpC$>G6H|Ft;0g zQI`r_?bdy9_6p@j1b@i^?L9kcJ<4(Lnryu6&*Jp8tgpPv2bsF4r?J^*GrD)$ zao3=5?u5IX)ND1-W*I{cA})!26^EG#>^+e26(#ZXvS6Gv$!Hc}vojQLWO+u?81k${ z*fPA%KD_pFA~;5g@^`0_vg7X%RQy}rOx~x(t%}V-6gMEHiW*7=8ZF~sls1i8?$XsL z8$I@GjggzX)YDr0ccJl zusGjND>RBY-he^9!0xGyQXY1%x|T$B2z)zzeKk_O zf62i=S1d6Hw?<3kVYLLYJlfg8zo^LkeWeI7Wgud$&zu1HemV5nm2mJ3lq0@!`I?vC zY8r8}z>xp0nz4lUka)uc9+QGZN2Y@o+ouy~^vgRJ#2cbVk+)c99qFww*3uL*pZmHO zJAk`ojTgc_DG>JGs&!G;tm#B-Bd+d!K7(o6Uu{~;C2NUaC!ByhGz|NPz7o~x>|(+~ zbz%iJ?Carfi_y3x)dB2|x$iZyG^5se7ZbF!QI}vu{M+a`(Pfx-MzujkPn1notg8Y- zI||=C0Oqpik-p9ab^&=U^@8RH$BvFJ?`Ql%3u%WF?I{zDmIal>lMr@uThI4IW$=Hq zfYP9xICI`^-fPEF$hMGBg8gnY*w?V7@@qpg3r_15u->tnf#unTHVEn?h`1PM@Qijl z`E3jKXH9luE{nH5yX+1F$;_N~+cqDKbDDKFIejtM1GgtX2hyX~mt|NBkNp5o|3J{S zd$W{fND==!GkuHuHK%#2bET6^A~t1f9&I2Elr`aRMN()*-9QlesW+^szsWQWxM+Q<#do| zPxCg%x38T>!@<*rHv)_W=FE(}J-LZm$}Z?bN<021p&U@)4*dQ%T@}rP+YcfLdD_#h J-u2?0e*wX57cBq) literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10.png new file mode 100644 index 0000000000000000000000000000000000000000..59928bcd1070454803935e4a81b825c039f3eac1 GIT binary patch literal 3655 zcmeHKZ9LNp``@I{ITRg~GLFZ)7&@Io47apdy6vDiCUhv0ki-~`>J;+0WKPPIrx|7* zhM1v)RMU1dwwkO54fDf1Z1Xs~o%_xGx!?Z(|Cj$a*XR0NFTO9X>+^lMGJo+zsPER> z4FZAGk?wBZAQ0GPyI)YF)p&8!K&3XoDl8eWz4 zTjhL%G5G-7d)E6?;7}<&y=NG5cEd9dV{M{;#O-YNgZMr5g^|)L@Rd~y3fdaaoU}jp zi0jA5<_?v_ckv|@oJoJV)Pl?&gy4}!r8Bhb6a-oAI(K|PPQNw_ZJxW{MCW=iGAoY<{Yg+3dm=Nc?Fk6cOqJ-P0tHF)#hYOzT^CRnetu9K zesi{5u3-7-aO2w1`lMBRm0wHQe?%+{{oc-z4EerOh=j%3jSyq_AE=gzXh3{yUGh|R z@&jA-`la6jrpRb>OT!T;$#T2X1@l_%@BPt6Gw zio(=KFS~-Mlez+N+p2#gno@tjIJWM=WjFoQaW6-vFE4K3r`E}1!>n3fD76F@@BbA) z!<)2#`o$yxbCFf02$We?}ag$?=ES~%2NL1n%byMKa`qWU@O^{2;?wD$nJ zvZ-)!Wu~aAv7XvA$R}=7k5rNuR*~boBuj-RM3{*Exk0G~Aw{jGfJ~T)K&LCv+9QSj z_l3fn!;nFTnjsB+Be=V_obVpH+-z-3zQeBJVB zRSX4n7!t+s0QejOEc42ESA}qCNfx(w=vjOiguW-;*)q2NB(=S1Yt-mr2gYew18y|; zzEhfr$rw&)De1pvG|YFeMLAr>e_ei0j!~RRV-)n8LYG4aJ@rHT_UQ(fO&-vvhle*{ z9hS^aM)Ymuw05hTq0gxpf7x(56zG<1Q;LqEON-dk&GBE%3g+#51W9%NXqXT=#7(kd z3Xl$d<)bl_srl6wHe&2$ZOa8?X)?b%{?5nck|8^aJe8(+6iX0#N!z}bieiW&7|?b; zSp36nQ(`ndkk`ViSF543nxE&$Qhjf3U=V4E0+BAl6S3hOd3ocQl5)OpN0uRd!bFZ) zqRtEFG2+bo> z+lbiWK*#vp!y#Q>m|ZD%3wRR+Qbgmc12;6kv3|q!%^i&QkL;D2T#G=9=WHos{xoGL z>=;t6AJH{TBkJetgj4m=%YpH(7wG4|9psh!VyrzQK)?CtZ7aK-Uu(C>sVC?&H+cwt zl1g|M24r?rSmj)=)PD94vHkDF18M=20k7;izQly-s5A?NA^ItIm3bqJ!wscwb$ryq z#H<(2iS@v&dP`A$YnW((|GLK;Wt|XXKJ-xXJ!Kg?6Ks#2$vo-0&{ro_p=JZIQr4@` z%NtMjU9|2Es47xAxMo>KoIbVE6vw)GgS`nSb=ThgG^7FbV!pzraA#z;!8>L1xBTWG z8+8V)H|Jxbs&$&vt={hd7X2wQ+rXVx3dK1S^?n9t74ul}v=*Eh&qBy1rRBmm27(<{fICLpn|D{XP3HVT9btK*iqqRS*HQbY=uyBu;)CT!GH`uuhh_(DT`5BdkDOESV>W4fwrg%avb(J> z*8>xrHM@I>ol@Uw_9s+-;+dwTBP<`j$_uLr4}67J(a)}c`~vO=k$M2%;~aLeNa!8N zSj)-wMP>SAoiC=+F7$9ZobNx2vg7YMkCBiB8VP~nonq-DyB2ok8X@+^>)euzyg!rJ zLrCezcgMsTCUsFCy^uJP9VR(K)23G%A{j0)?oh?_8Q>2kWETXh|Ji1@eqz7qmyKxB zA%2OL`SqfCdlymuK(cniw;IZnNjEQAoD4H%jfyLG&i6I<*g6PrQAvGjgNEB~0!+uH zfo$&nwM&i%zKr-r>g46kiKfl7Rs-~G+$z8AmsFK2zy~WGe#eL<_+A#m1rVFhT;E>9ZpC$>G6H|Ft;0g zQI`r_?bdy9_6p@j1b@i^?L9kcJ<4(Lnryu6&*Jp8tgpPv2bsF4r?J^*GrD)$ zao3=5?u5IX)ND1-W*I{cA})!26^EG#>^+e26(#ZXvS6Gv$!Hc}vojQLWO+u?81k${ z*fPA%KD_pFA~;5g@^`0_vg7X%RQy}rOx~x(t%}V-6gMEHiW*7=8ZF~sls1i8?$XsL z8$I@GjggzX)YDr0ccJl zusGjND>RBY-he^9!0xGyQXY1%x|T$B2z)zzeKk_O zf62i=S1d6Hw?<3kVYLLYJlfg8zo^LkeWeI7Wgud$&zu1HemV5nm2mJ3lq0@!`I?vC zY8r8}z>xp0nz4lUka)uc9+QGZN2Y@o+ouy~^vgRJ#2cbVk+)c99qFww*3uL*pZmHO zJAk`ojTgc_DG>JGs&!G;tm#B-Bd+d!K7(o6Uu{~;C2NUaC!ByhGz|NPz7o~x>|(+~ zbz%iJ?Carfi_y3x)dB2|x$iZyG^5se7ZbF!QI}vu{M+a`(Pfx-MzujkPn1notg8Y- zI||=C0Oqpik-p9ab^&=U^@8RH$BvFJ?`Ql%3u%WF?I{zDmIal>lMr@uThI4IW$=Hq zfYP9xICI`^-fPEF$hMGBg8gnY*w?V7@@qpg3r_15u->tnf#unTHVEn?h`1PM@Qijl z`E3jKXH9luE{nH5yX+1F$;_N~+cqDKbDDKFIejtM1GgtX2hyX~mt|NBkNp5o|3J{S zd$W{fND==!GkuHuHK%#2bET6^A~t1f9&I2Elr`aRMN()*-9QlesW+^szsWQWxM+Q<#do| zPxCg%x38T>!@<*rHv)_W=FE(}J-LZm$}Z?bN<021p&U@)4*dQ%T@}rP+YcfLdD_#h J-u2?0e*wX57cBq) literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10_no_vtiled.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_MONO10_no_vtiled.png new file mode 100644 index 0000000000000000000000000000000000000000..59928bcd1070454803935e4a81b825c039f3eac1 GIT binary patch literal 3655 zcmeHKZ9LNp``@I{ITRg~GLFZ)7&@Io47apdy6vDiCUhv0ki-~`>J;+0WKPPIrx|7* zhM1v)RMU1dwwkO54fDf1Z1Xs~o%_xGx!?Z(|Cj$a*XR0NFTO9X>+^lMGJo+zsPER> z4FZAGk?wBZAQ0GPyI)YF)p&8!K&3XoDl8eWz4 zTjhL%G5G-7d)E6?;7}<&y=NG5cEd9dV{M{;#O-YNgZMr5g^|)L@Rd~y3fdaaoU}jp zi0jA5<_?v_ckv|@oJoJV)Pl?&gy4}!r8Bhb6a-oAI(K|PPQNw_ZJxW{MCW=iGAoY<{Yg+3dm=Nc?Fk6cOqJ-P0tHF)#hYOzT^CRnetu9K zesi{5u3-7-aO2w1`lMBRm0wHQe?%+{{oc-z4EerOh=j%3jSyq_AE=gzXh3{yUGh|R z@&jA-`la6jrpRb>OT!T;$#T2X1@l_%@BPt6Gw zio(=KFS~-Mlez+N+p2#gno@tjIJWM=WjFoQaW6-vFE4K3r`E}1!>n3fD76F@@BbA) z!<)2#`o$yxbCFf02$We?}ag$?=ES~%2NL1n%byMKa`qWU@O^{2;?wD$nJ zvZ-)!Wu~aAv7XvA$R}=7k5rNuR*~boBuj-RM3{*Exk0G~Aw{jGfJ~T)K&LCv+9QSj z_l3fn!;nFTnjsB+Be=V_obVpH+-z-3zQeBJVB zRSX4n7!t+s0QejOEc42ESA}qCNfx(w=vjOiguW-;*)q2NB(=S1Yt-mr2gYew18y|; zzEhfr$rw&)De1pvG|YFeMLAr>e_ei0j!~RRV-)n8LYG4aJ@rHT_UQ(fO&-vvhle*{ z9hS^aM)Ymuw05hTq0gxpf7x(56zG<1Q;LqEON-dk&GBE%3g+#51W9%NXqXT=#7(kd z3Xl$d<)bl_srl6wHe&2$ZOa8?X)?b%{?5nck|8^aJe8(+6iX0#N!z}bieiW&7|?b; zSp36nQ(`ndkk`ViSF543nxE&$Qhjf3U=V4E0+BAl6S3hOd3ocQl5)OpN0uRd!bFZ) zqRtEFG2+bo> z+lbiWK*#vp!y#Q>m|ZD%3wRR+Qbgmc12;6kv3|q!%^i&QkL;D2T#G=9=WHos{xoGL z>=;t6AJH{TBkJetgj4m=%YpH(7wG4|9psh!VyrzQK)?CtZ7aK-Uu(C>sVC?&H+cwt zl1g|M24r?rSmj)=)PD94vHkDF18M=20k7;izQly-s5A?NA^ItIm3bqJ!wscwb$ryq z#H<(2iS@v&dP`A$YnW((|GLK;Wt|XXKJ-xXJ!Kg?6Ks#2$vo-0&{ro_p=JZIQr4@` z%NtMjU9|2Es47xAxMo>KoIbVE6vw)GgS`nSb=ThgG^7FbV!pzraA#z;!8>L1xBTWG z8+8V)H|Jxbs&$&vt={hd7X2wQ+rXVx3dK1S^?n9t74ul}v=*Eh&qBy1rRBmm27(<{fICLpn|D{XP3HVT9btK*iqqRS*HQbY=uyBu;)CT!GH`uuhh_(DT`5BdkDOESV>W4fwrg%avb(J> z*8>xrHM@I>ol@Uw_9s+-;+dwTBP<`j$_uLr4}67J(a)}c`~vO=k$M2%;~aLeNa!8N zSj)-wMP>SAoiC=+F7$9ZobNx2vg7YMkCBiB8VP~nonq-DyB2ok8X@+^>)euzyg!rJ zLrCezcgMsTCUsFCy^uJP9VR(K)23G%A{j0)?oh?_8Q>2kWETXh|Ji1@eqz7qmyKxB zA%2OL`SqfCdlymuK(cniw;IZnNjEQAoD4H%jfyLG&i6I<*g6PrQAvGjgNEB~0!+uH zfo$&nwM&i%zKr-r>g46kiKfl7Rs-~G+$z8AmsFK2zy~WGe#eL<_+A#m1rVFhT;E>9ZpC$>G6H|Ft;0g zQI`r_?bdy9_6p@j1b@i^?L9kcJ<4(Lnryu6&*Jp8tgpPv2bsF4r?J^*GrD)$ zao3=5?u5IX)ND1-W*I{cA})!26^EG#>^+e26(#ZXvS6Gv$!Hc}vojQLWO+u?81k${ z*fPA%KD_pFA~;5g@^`0_vg7X%RQy}rOx~x(t%}V-6gMEHiW*7=8ZF~sls1i8?$XsL z8$I@GjggzX)YDr0ccJl zusGjND>RBY-he^9!0xGyQXY1%x|T$B2z)zzeKk_O zf62i=S1d6Hw?<3kVYLLYJlfg8zo^LkeWeI7Wgud$&zu1HemV5nm2mJ3lq0@!`I?vC zY8r8}z>xp0nz4lUka)uc9+QGZN2Y@o+ouy~^vgRJ#2cbVk+)c99qFww*3uL*pZmHO zJAk`ojTgc_DG>JGs&!G;tm#B-Bd+d!K7(o6Uu{~;C2NUaC!ByhGz|NPz7o~x>|(+~ zbz%iJ?Carfi_y3x)dB2|x$iZyG^5se7ZbF!QI}vu{M+a`(Pfx-MzujkPn1notg8Y- zI||=C0Oqpik-p9ab^&=U^@8RH$BvFJ?`Ql%3u%WF?I{zDmIal>lMr@uThI4IW$=Hq zfYP9xICI`^-fPEF$hMGBg8gnY*w?V7@@qpg3r_15u->tnf#unTHVEn?h`1PM@Qijl z`E3jKXH9luE{nH5yX+1F$;_N~+cqDKbDDKFIejtM1GgtX2hyX~mt|NBkNp5o|3J{S zd$W{fND==!GkuHuHK%#2bET6^A~t1f9&I2Elr`aRMN()*-9QlesW+^szsWQWxM+Q<#do| zPxCg%x38T>!@<*rHv)_W=FE(}J-LZm$}Z?bN<021p&U@)4*dQ%T@}rP+YcfLdD_#h J-u2?0e*wX57cBq) literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_565.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240_RGB_565.png new file mode 100644 index 0000000000000000000000000000000000000000..77577a65601abe1b7eb8d0771e8e1ceb795e8400 GIT binary patch literal 3930 zcmeH~c~lZ;yTH-Rv?kYS`O2-d8ke$0GdDD+!qn1qOc4|r7Xk^$psJ)xb)rgoqNvx>)vzjpZA~VyyrRZdDi#+J@5PY zinsgjodd7ti|v04isd>#rK>N*Q;Yf&>7x4|$w-^G6l)rd&y1T6KG`Jw<4L zjGsGrv5eSAj9)RW7Vd|*ckaBSUND?f{GrUo+~556&C;I;u{MrZs2bYZyYFP|e)fkv zaMmWvT_y(o4_jLgnX^p5tn9Wrn}5k zHmZm9PeXS5SyA?r1vd)@`litlQQ9#T+AgW9=On+&fA{lTaP5&kcdU+L(|L&)!ClzV zl)#^{%#EV`Vc`qf3^ZgEJw79y#-kvz9=p&QJcWI)G6iu8y?zs^-2h4#JM@S`WfDGeuodVqHj5rjLMUNPanaaSftP&!Jea||SoN4H{!%$G;{L|Mro?$J>qh3u+Jpxm= z(En&kRckOzCdOIpbMuq%8bzbnn9(ymOn#hgDN;li8~HdH^EPl`P$hHaPxoQU+!DEq zC8iZM2ry*(+bnsIl>OtY+&MO4Frb(&tgP=5C@A6<7v@$76h9(qDdGZt_FVWJnszb} zedfT}yh!verjo*o&G&utsGQ-|@d*ODDe4=O_OKqE|Ct7SKr&iN<|{&iNw(2ZEvj;Cu!1@EotY5fCjz&J=o?I_phLXUtazl(=cAJH2;O`;KQGA zmnw3qtZX0lQ*_xDMy9ZC67@Vf`lbSpP$f0!_ zgqvc;CDm~|5CTypkIKXVg_7ri#T4`!A9b9+EF9a|K^1#GCZyQP>I@RHH@I|osG1{Q}N|J>9aG1lY&)IgRW6Y@)?qqB70*hnFVns^AUL^6?-t^ z4u3lvIZQ^kWeM^NBH5#sO(Buo(I4p`n;>bLWn!dROb`Q>mV3RR^$1URs48xqD255VIH-Lk_fLhrp?NTG2!aqJYRIBsYsT}b=m3XE3cT_a>e08s2P z!b&h zj^1?Fhwu<=?S_6-@hD!cDGx(sLVO&kk07^9XE5rxglB2+8?}S{8+V+(;v2@_=bF?X z+ttFEUMDkt_P)IbUJ}0cM+37&g%-vUpdw_jmbh2JY7X%eyf`T+D1aS%ToYQvKua(4 z5^({l#uQ$~R<>JwfGu1h93^a=@Wkc2%Sz zRAo+Q+R>Asnur)6tYD0wOKeevj6$`_L{IOZUZ;MZ91XxF&PS!&xSQ15lUKQ%1GV*o zFxiccqbt)JHtZQ&)yYm$#W~iq%Dy&`dJ!7k1a?4?oo`8`o?s_;h;I>t0s!oG(^XhM9H{-H9LG0#&)b%rG9&It?3sgLY;v3j;&9 zx2~kXR|=gcqj~T{Sk{%(LZeq74}h`Um*k#Bi&*&#<^ui7q+^QpL_E3y9kEpMu)5?- zJ_yT_U`*p9S(Npt@$jgJHrnGzd;$oIs(z^YD9(M474o@k-+&uJ&S=OrxT?n7MM!6U>fuNix>`Q~47$1K=^ViLUe0yk< z=XySFmpxQ8r~^6Zjm)rck_5%<@QTb5QHXl*rQ4C+NyP@F&z}A6pX#{t73l1U!Zvrk z=%`7Uhukv`#v@$lHLBcK&V6Svl4O5475gQ2z+OCV;+#o{$;i$OpPB;Nv}VqwXz2pT|_(ru9`9itP`-8Bif(GwS0~)ETBR*-Z2Pr#d-HA?ZobTSZ`DBGZ1w>8d)VK1;GDM3j7}rKN} zodtdo%a(zz!w?ysIb#PVUL7l@JdBD`qhCB4gDn?s)=Rn=ofWO}_4q7?`uw{`?XEVDfZzq;k$gj(uB%ZUZGM-AJzJFq)!1VvM z_RbMuFV#WKB`e!eSc14?+sxEGIJ{Gn`^4FO4*qrjpXhh{5+~K0HHOPRG#_y25B~6v zVd-00Rpqxa0W(uANL`8uJcMnq-rV?O-~RWYMy)V*XbLy*wk7z7R^9| zypu)OpMlCK9K**0EaNU*U?*kSVF#FT#>w@&@mxLr_BTk3yHO4Z0cH|wd(W;Q_GP3S zfxaQxXq} z-Gduff}Pp}o&A8A*}r=%$D7wQ+%emDMh1KP*ejtK9eNEY=cT5n{zL{ofMvQJD^by& zRJZxZu??)-!SMcC-7xVo{uiOmW6aVBV;mC@=W~hU46^>73MS^jy@ye@!xc4EPY2hQ zk2mh{`4ym%c`od~_=|(81`8|Hfm_;RI{`Bx_C8vM^P*LTGr|kU~S$#o8+N~3a06jU6u2+@#C5mSL@_r0}#|G)SCeE;mV*FNj)wa-55e7&*40F z9?X)gOxpA?bFcAA^uY4Z&vu_0t%N3F62lsy)2xjE7&<*)dsK~g@uwQ99p)z$E%8P2KA4C{uR* z*z1>14E$j@@!k2s5qC{bYzZidC!Ypm+U8QZtULbJ2zw|77#GE#-`@H50B_9C5C?UX z5*>;vf!zh5NgZLNeo@GFVgRHF)>Z`pwdYjx(pZ}6kAHvTeOYU)FU%BG+QjT?*%k?r2>Zc{eR&9v>%1wR8G`+*SZ?s zvZ`beZ$B_3DO9|U(w_)tAwV~?C)43jb0BxIH|KExlTNTMJZ4u;h$S=`q9l|W@_xe_ zB{!*3_{0M9A~}0LhMZy@*d3sd&*TEAcBbUDyQxHGP`w`Pf@)_v#WMmvBX%wBxfQ0c zww+%d6O{c40i%B+B|VMsr%a>~8|A3slJj}Cmf@_#1nS^Cmm-|emW1IrSVdXIj>IJv z#MW9FsNmXAr;k{o&|q>aliNkAAZ1_UE~xyzalJz7DGcR-HcK>!I#hJP5MjW6fAJoa zf7~2T%3HWB`0bqd2OW)>zM(V~dRJejGN`2C;! z=;@!xX>U?M+eOg>^RK9z;Vsq!3BZtm<^sO`Imd+x2YhkeGk!@e;M zQ8JRyBC5Ztd{Fsh+xX;%`&x(#76xpaN2bkfUyC>bjSpmwvvux53HZu6<9E`Q*iL|zB`J8I*W>Kzw%OYXrLHz*ubXN2l2 zxkb<-<1cwxB6KVnRT_Uc^~z|npCqdK``Ga%M(KIAfB;Njw`jgJk|P#foG zuHI+2sd~%IKb!T{*ZenXA8{=kHU{q$SxVNV-5b_4C`neU5T2RlZlS#mv;G!svS=Bl zegu0=Jqx!lS9bT#H;X(N5hR`<`K+=}0dY~0C;Aofo2W>{rWb>9TO zz48TeZhAL$W_!396v5_3tND|ay6%WKX6W+>&*mw~W#ezN?Ec^h^JL3TyPUjJv6RzE zJA4y!e4mJJ6eqw;KXKop3%>Yg#4w6<)Jz~&XYj!ekLx4PtmwS|z0Lk7Z?AJE6>~dR zi_y(&|9fP$$nYA%ntZJUy8rKqGy&502a3AzD}SjXByilvc~jD};8FPtP-%sP6VMjhkPbn!l52VuT6VDt~8%i{FgiES2k=S15n5Sll% za;aAu2>xdo77?wPRPJV8bQ)P+z$WJMd+(QeR*_1hKgi8p75bNp(@{cJch2YdmEJyL zx~CIRn16vCnjj}ep3r%PoSLcm>x-v@klhY8P&@m+DnHG}`)po^IqAO=*mG4<3 z+krq){bT?hD3j7|IuODV;Nl;xIMEU~h>1=4Sk2xQ?;)4Zgq)BT@c2ZJ6@O;)&Kevj ztkDWX_EQb+cfJ0y=G=MYy+qQxb20v?ibanJaU9*%%=Jf}%wndO^t3`oH;-|oGIO9T zp#{SY;|z5ASeU>GW26jh4|i_r!@!2vj8NIa`pzGPOyV|^n;jin{Fbi|v5Ntqv$wo( zqAyiFeBww<0W`z3zeNE2^bL3eVRG-x@u973l;6>d&VZH|X! zM(F6WhepUbv|=Vx!#?JL6*_(v2V=ueV2)TXydcKfLl7e$x#GmQ5bOMjEY(a;{mc5C zJv0{$f&Zg&NXVHkwJKR>*Op*eT1(=sS;6GHH@#k)m-oEb_^(!Iqpn8Z z(N(_a>~j0qHuOH)ndHCWXdF>$UBXD>8fGI|fk&jQ(^foU(^XowXZ=gyY>-FeDx1B82m{7YAy=B!T8|up zTh$UY-e)@pN(aEw{YX}BJp_Mk2PBiEL%QkAxFo%HlcV9!jXHy`2E&uNlm>jc~Mb>0ZR*S?~(9yV;p+L#pZ1Q*CMuUC&# zTGSg}`Mlkri23+-au%uaz@_ovLxs=8bs+U7k8n{x-K@-0dgt-(cHUeEVh_0eIHND` zEiqw1NB33UUcm6gR^5NoH>?m4*R+uXM5cyjt-@F~aky^b;W=_|(ZG zCd6KX;SWRr`s0V!A3~28|L_Cu*XfR5=xUG+iU?Q$FD6EqV-5LtF^RvF)0l6UBRC#OXXg;Z|DU z<#j352-K{7Rb-^OwvOHInF@&9N%#eSvHvZ#%R7G+SdeTLd3LUYVgm$Fsus=bAR*Y= zBT~%Tx=gc%SCPuCEn4w9tH=9CGT<7AnwohN$ literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py b/ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py new file mode 100644 index 00000000000..6700c42ec4a --- /dev/null +++ b/ports/zephyr-cp/tests/zephyr_display/test_zephyr_display.py @@ -0,0 +1,365 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +import colorsys +import shutil +import struct +from pathlib import Path + +import pytest +from PIL import Image + + +def _read_image(path: Path) -> tuple[int, int, bytes]: + """Read an image file and return (width, height, RGB bytes).""" + with Image.open(path) as img: + rgb = img.convert("RGB") + return rgb.width, rgb.height, rgb.tobytes() + + +def _read_mask(golden_path: Path) -> bytes | None: + """Load the companion mask PNG for a golden image, if it exists. + + Non-zero pixels are masked (skipped during comparison). + """ + mask_path = golden_path.with_suffix(".mask.png") + if not mask_path.exists(): + return None + with Image.open(mask_path) as img: + return img.convert("L").tobytes() + + +def _assert_pixels_equal_masked( + golden_pixels: bytes, actual_pixels: bytes, mask: bytes | None = None +): + """Assert pixels match, skipping positions where the mask is non-zero.""" + assert len(golden_pixels) == len(actual_pixels) + for i in range(0, len(golden_pixels), 3): + if mask is not None and mask[i // 3] != 0: + continue + if golden_pixels[i : i + 3] != actual_pixels[i : i + 3]: + pixel = i // 3 + assert False, ( + f"Pixel {pixel} mismatch: " + f"golden={tuple(golden_pixels[i : i + 3])} " + f"actual={tuple(actual_pixels[i : i + 3])}" + ) + + +BOARD_DISPLAY_AVAILABLE_CODE = """\ +import board +print(hasattr(board, 'DISPLAY')) +print(type(board.DISPLAY).__name__) +print(board.DISPLAY.width, board.DISPLAY.height) +print('done') +""" + + +@pytest.mark.circuitpy_drive({"code.py": BOARD_DISPLAY_AVAILABLE_CODE}) +@pytest.mark.display +@pytest.mark.duration(8) +def test_board_display_available(circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "True" in output + assert "Display" in output + assert "320 240" in output + assert "done" in output + + +CONSOLE_TERMINAL_PRESENT_CODE = """\ +import board + +root = board.DISPLAY.root_group +has_terminal_tilegrids = ( + type(root).__name__ == 'Group' and + len(root) >= 2 and + type(root[0]).__name__ == 'TileGrid' and + type(root[-1]).__name__ == 'TileGrid' +) +print('has_terminal_tilegrids:', has_terminal_tilegrids) +print('done') +""" + + +@pytest.mark.circuitpy_drive({"code.py": CONSOLE_TERMINAL_PRESENT_CODE}) +@pytest.mark.display +@pytest.mark.duration(8) +def test_console_terminal_present_by_default(circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "has_terminal_tilegrids: True" in output + assert "done" in output + + +CONSOLE_OUTPUT_GOLDEN_CODE = """\ +import time +time.sleep(0.25) +print('done') +while True: + time.sleep(1) +""" + + +def _golden_compare_or_update(request, captures, golden_path, mask_path=None): + """Compare captured PNG against golden, or update golden if --update-goldens. + + mask_path overrides the default companion mask lookup (golden.mask.png). + """ + if not captures or not captures[0].exists(): + pytest.skip("display capture was not produced") + + if request.config.getoption("--update-goldens"): + golden_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(captures[0], golden_path) + return + + gw, gh, gpx = _read_image(golden_path) + dw, dh, dpx = _read_image(captures[0]) + if mask_path is not None: + mask = _read_mask(mask_path) + else: + mask = _read_mask(golden_path) + + assert (dw, dh) == (gw, gh) + _assert_pixels_equal_masked(gpx, dpx, mask) + + +@pytest.mark.circuitpy_drive({"code.py": CONSOLE_OUTPUT_GOLDEN_CODE}) +@pytest.mark.display(capture_times_ns=[4_000_000_000]) +@pytest.mark.duration(8) +def test_console_output_golden(request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "done" in output + + golden = Path(__file__).parent / "golden" / "terminal_console_output_320x240.png" + _golden_compare_or_update(request, circuitpython.display_capture_paths(), golden) + + +PIXEL_FORMATS = ["ARGB_8888", "RGB_888", "RGB_565", "BGR_565", "L_8", "AL_88", "MONO01", "MONO10"] + +# Shared mask: the same screen regions vary regardless of pixel format. +_CONSOLE_GOLDEN_MASK = Path(__file__).parent / "golden" / "terminal_console_output_320x240.png" + + +@pytest.mark.circuitpy_drive({"code.py": CONSOLE_OUTPUT_GOLDEN_CODE}) +@pytest.mark.display(capture_times_ns=[4_000_000_000]) +@pytest.mark.duration(8) +@pytest.mark.parametrize( + "pixel_format", + PIXEL_FORMATS, + indirect=True, +) +def test_console_output_golden_pixel_format(pixel_format, request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "done" in output + + golden_name = f"terminal_console_output_320x240_{pixel_format}.png" + golden = Path(__file__).parent / "golden" / golden_name + _golden_compare_or_update( + request, circuitpython.display_capture_paths(), golden, _CONSOLE_GOLDEN_MASK + ) + + +MONO_NO_VTILED_FORMATS = ["MONO01", "MONO10"] + + +@pytest.mark.circuitpy_drive({"code.py": CONSOLE_OUTPUT_GOLDEN_CODE}) +@pytest.mark.display(capture_times_ns=[4_000_000_000]) +@pytest.mark.display_mono_vtiled(False) +@pytest.mark.duration(8) +@pytest.mark.parametrize( + "pixel_format", + MONO_NO_VTILED_FORMATS, + indirect=True, +) +def test_console_output_golden_mono_no_vtiled(pixel_format, request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "done" in output + + golden_name = f"terminal_console_output_320x240_{pixel_format}_no_vtiled.png" + golden = Path(__file__).parent / "golden" / golden_name + _golden_compare_or_update( + request, circuitpython.display_capture_paths(), golden, _CONSOLE_GOLDEN_MASK + ) + + +def _generate_gradient_bmp(width, height): + """Generate a 24-bit BMP with HSL color gradient. + + Hue sweeps left to right, lightness goes from black (bottom) to white (top), + saturation is 1.0. + """ + row_size = width * 3 + row_padding = (4 - (row_size % 4)) % 4 + padded_row_size = row_size + row_padding + pixel_data_size = padded_row_size * height + file_size = 14 + 40 + pixel_data_size + + header = struct.pack( + "<2sIHHI", + b"BM", + file_size, + 0, + 0, + 14 + 40, + ) + info = struct.pack( + " Date: Sat, 21 Mar 2026 10:13:02 -0700 Subject: [PATCH 311/876] mtm_computer: Add DAC audio out module --- .../boards/mtm_computer/module/DACOut.c | 276 ++++++++++++++++++ .../boards/mtm_computer/module/DACOut.h | 38 +++ .../boards/mtm_computer/mpconfigboard.mk | 4 + 3 files changed, 318 insertions(+) create mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.c create mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.h diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c new file mode 100644 index 00000000000..84f4296cb00 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c @@ -0,0 +1,276 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT +// +// MCP4822 dual-channel 12-bit SPI DAC driver for the MTM Workshop Computer. +// Uses PIO + DMA for non-blocking audio playback, mirroring audiobusio.I2SOut. + +#include +#include + +#include "mpconfigport.h" + +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "boards/mtm_computer/module/DACOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" +#include "bindings/rp2pio/StateMachine.h" + +// ───────────────────────────────────────────────────────────────────────────── +// PIO program for MCP4822 SPI DAC +// ───────────────────────────────────────────────────────────────────────────── +// +// Pin assignment: +// OUT pin (1) = MOSI — serial data out +// SET pins (N) = MOSI through CS — for CS control & command-bit injection +// SIDE-SET pin (1) = SCK — serial clock +// +// On the MTM Workshop Computer: MOSI=GP19, CS=GP21, SCK=GP18. +// The SET group spans GP19..GP21 (3 pins). GP20 is unused and driven low. +// +// SET PINS bit mapping (bit0=MOSI/GP19, bit1=GP20, bit2=CS/GP21): +// 0 = CS low, MOSI low 1 = CS low, MOSI high 4 = CS high, MOSI low +// +// SIDE-SET (1 pin, SCK): side 0 = SCK low, side 1 = SCK high +// +// MCP4822 16-bit command word: +// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x) +// [12] output enable (1) [11:0] 12-bit data +// +// DMA feeds unsigned 16-bit audio samples. RP2040 narrow-write replication +// fills both halves of the 32-bit PIO FIFO entry with the same value, +// giving mono→stereo for free. +// +// The PIO pulls 32 bits, then sends two SPI transactions: +// Channel A: cmd nibble 0b0011, then all 16 sample bits from upper half-word +// Channel B: cmd nibble 0b1011, then all 16 sample bits from lower half-word +// The MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data), +// so only the top 12 of the 16 sample bits become DAC data. The bottom +// 4 sample bits clock out harmlessly after the DAC has latched. +// This gives correct 16-bit → 12-bit scaling (effectively sample >> 4). +// +// PIO instruction encoding with .side_set 1 (no opt): +// [15:13] opcode [12] side-set [11:8] delay [7:0] operands +// +// Total: 26 instructions, 86 PIO clocks per audio sample. +// ───────────────────────────────────────────────────────────────────────────── + +static const uint16_t mcp4822_pio_program[] = { + // side SCK + // 0: pull noblock side 0 ; Get 32 bits or keep X if FIFO empty + 0x8080, + // 1: mov x, osr side 0 ; Save for pull-noblock fallback + 0xA027, + + // ── Channel A: command nibble 0b0011 ────────────────────────────────── + // Send 4 cmd bits via SET, then all 16 sample bits via OUT. + // MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data); + // the extra 4 clocks shift out the LSBs which the DAC ignores. + // This gives correct 16→12 bit scaling (top 12 bits become DAC data). + // 2: set pins, 0 side 0 ; CS low, MOSI=0 (bit15=0: channel A) + 0xE000, + // 3: nop side 1 ; SCK high — latch bit 15 + 0xB042, + // 4: set pins, 0 side 0 ; MOSI=0 (bit14=0: don't care) + 0xE000, + // 5: nop side 1 ; SCK high + 0xB042, + // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + 0xE001, + // 7: nop side 1 ; SCK high + 0xB042, + // 8: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) + 0xE001, + // 9: nop side 1 ; SCK high + 0xB042, + // 10: set y, 15 side 0 ; Loop counter: 16 sample bits + 0xE04F, + // 11: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopA) + 0x6001, + // 12: jmp y--, 11 side 1 ; SCK high, loop back + 0x108B, + // 13: set pins, 4 side 0 ; CS high — DAC A latches + 0xE004, + + // ── Channel B: command nibble 0b1011 ────────────────────────────────── + // 14: set pins, 1 side 0 ; CS low, MOSI=1 (bit15=1: channel B) + 0xE001, + // 15: nop side 1 ; SCK high + 0xB042, + // 16: set pins, 0 side 0 ; MOSI=0 (bit14=0) + 0xE000, + // 17: nop side 1 ; SCK high + 0xB042, + // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + 0xE001, + // 19: nop side 1 ; SCK high + 0xB042, + // 20: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) + 0xE001, + // 21: nop side 1 ; SCK high + 0xB042, + // 22: set y, 15 side 0 ; Loop counter: 16 sample bits + 0xE04F, + // 23: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopB) + 0x6001, + // 24: jmp y--, 23 side 1 ; SCK high, loop back + 0x1097, + // 25: set pins, 4 side 0 ; CS high — DAC B latches + 0xE004, +}; + +// Clocks per sample: 2 (pull+mov) + 42 (chanA) + 42 (chanB) = 86 +// Per channel: 8(4 cmd bits × 2 clks) + 1(set y) + 32(16 bits × 2 clks) + 1(cs high) = 42 +#define MCP4822_CLOCKS_PER_SAMPLE 86 + + +void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs) { + + // SET pins span from MOSI to CS. MOSI must have a lower GPIO number + // than CS, with at most 4 pins between them (SET count max is 5). + if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { + mp_raise_ValueError( + MP_COMPRESSED_ROM_TEXT("cs pin must be 1-4 positions above mosi pin")); + } + + uint8_t set_count = cs->number - mosi->number + 1; + + // Initial SET pin state: CS high (bit at CS position), others low + uint32_t cs_bit_position = cs->number - mosi->number; + pio_pinmask32_t initial_set_state = PIO_PINMASK32_FROM_VALUE(1u << cs_bit_position); + pio_pinmask32_t initial_set_dir = PIO_PINMASK32_FROM_VALUE((1u << set_count) - 1); + + common_hal_rp2pio_statemachine_construct( + &self->state_machine, + mcp4822_pio_program, MP_ARRAY_SIZE(mcp4822_pio_program), + 44100 * MCP4822_CLOCKS_PER_SAMPLE, // Initial frequency; play() adjusts + NULL, 0, // No init program + NULL, 0, // No may_exec + mosi, 1, // OUT: MOSI, 1 pin + PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // OUT state=low, dir=output + NULL, 0, // IN: none + PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // IN pulls: none + mosi, set_count, // SET: MOSI..CS + initial_set_state, initial_set_dir, // SET state (CS high), dir=output + clock, 1, false, // SIDE-SET: SCK, 1 pin, not pindirs + PIO_PINMASK32_NONE, // SIDE-SET state: SCK low + PIO_PINMASK32_FROM_VALUE(0x1), // SIDE-SET dir: output + false, // No sideset enable + NULL, PULL_NONE, // No jump pin + PIO_PINMASK_NONE, // No wait GPIO + true, // Exclusive pin use + false, 32, false, // OUT shift: no autopull, 32-bit, shift left + false, // Don't wait for txstall + false, 32, false, // IN shift (unused) + false, // Not user-interruptible + 0, -1, // Wrap: whole program + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, + PIO_MOV_N_DEFAULT + ); + + self->playing = false; + audio_dma_init(&self->dma); +} + +bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self) { + return common_hal_rp2pio_statemachine_deinited(&self->state_machine); +} + +void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self) { + if (common_hal_mtm_hardware_dacout_deinited(self)) { + return; + } + if (common_hal_mtm_hardware_dacout_get_playing(self)) { + common_hal_mtm_hardware_dacout_stop(self); + } + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + audio_dma_deinit(&self->dma); +} + +void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, + mp_obj_t sample, bool loop) { + + if (common_hal_mtm_hardware_dacout_get_playing(self)) { + common_hal_mtm_hardware_dacout_stop(self); + } + + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); + if (bits_per_sample < 16) { + bits_per_sample = 16; + } + + uint32_t sample_rate = audiosample_get_sample_rate(sample); + uint8_t channel_count = audiosample_get_channel_count(sample); + if (channel_count > 2) { + mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("Too many channels in sample.")); + } + + // PIO clock = sample_rate × clocks_per_sample + common_hal_rp2pio_statemachine_set_frequency( + &self->state_machine, + (uint32_t)sample_rate * MCP4822_CLOCKS_PER_SAMPLE); + common_hal_rp2pio_statemachine_restart(&self->state_machine); + + // DMA feeds unsigned 16-bit samples. The PIO discards the top 4 bits + // of each 16-bit half and uses the remaining 12 as DAC data. + // RP2040 narrow-write replication: 16-bit DMA write → same value in + // both 32-bit FIFO halves → mono-to-stereo for free. + audio_dma_result result = audio_dma_setup_playback( + &self->dma, + sample, + loop, + false, // single_channel_output + 0, // audio_channel + false, // output_signed = false (unsigned for MCP4822) + bits_per_sample, // output_resolution + (uint32_t)&self->state_machine.pio->txf[self->state_machine.state_machine], + self->state_machine.tx_dreq, + false); // swap_channel + + if (result == AUDIO_DMA_DMA_BUSY) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("No DMA channel found")); + } else if (result == AUDIO_DMA_MEMORY_ERROR) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Unable to allocate buffers for signed conversion")); + } else if (result == AUDIO_DMA_SOURCE_ERROR) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Audio source error")); + } + + self->playing = true; +} + +void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self) { + audio_dma_pause(&self->dma); +} + +void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self) { + audio_dma_resume(&self->dma); +} + +bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self) { + return audio_dma_get_paused(&self->dma); +} + +void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self) { + audio_dma_stop(&self->dma); + common_hal_rp2pio_statemachine_stop(&self->state_machine); + self->playing = false; +} + +bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self) { + bool playing = audio_dma_get_playing(&self->dma); + if (!playing && self->playing) { + common_hal_mtm_hardware_dacout_stop(self); + } + return playing; +} diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h new file mode 100644 index 00000000000..f7c0c9eb806 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/rp2pio/StateMachine.h" + +#include "audio_dma.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + rp2pio_statemachine_obj_t state_machine; + audio_dma_t dma; + bool playing; +} mtm_hardware_dacout_obj_t; + +void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs); + +void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); + +void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, + mp_obj_t sample, bool loop); +void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self); + +void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self); +void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self); + +extern const mp_obj_type_t mtm_hardware_dacout_type; diff --git a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk index 718c393d168..74d9baac879 100644 --- a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk +++ b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk @@ -11,3 +11,7 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_AUDIOEFFECTS = 1 CIRCUITPY_IMAGECAPTURE = 0 CIRCUITPY_PICODVI = 0 + +SRC_C += \ + boards/$(BOARD)/module/mtm_hardware.c \ + boards/$(BOARD)/module/DACOut.c From 38b023338d43c8884d6abe568c0aa6b5e2d05ef4 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Sat, 21 Mar 2026 10:33:40 -0700 Subject: [PATCH 312/876] mtm_hardware.c added --- .../boards/mtm_computer/module/mtm_hardware.c | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c new file mode 100644 index 00000000000..a3dafbcf941 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c @@ -0,0 +1,267 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT +// +// Python bindings for the mtm_hardware module. +// Provides DACOut: a non-blocking audio player for the MCP4822 SPI DAC. + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "boards/mtm_computer/module/DACOut.h" + +// ───────────────────────────────────────────────────────────────────────────── +// DACOut class +// ───────────────────────────────────────────────────────────────────────────── + +//| class DACOut: +//| """Output audio to the MCP4822 dual-channel 12-bit SPI DAC.""" +//| +//| def __init__( +//| self, +//| clock: microcontroller.Pin, +//| mosi: microcontroller.Pin, +//| cs: microcontroller.Pin, +//| ) -> None: +//| """Create a DACOut object associated with the given SPI pins. +//| +//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin +//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin +//| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| +//| Simple 8ksps 440 Hz sine wave:: +//| +//| import mtm_hardware +//| import audiocore +//| import board +//| import array +//| import time +//| import math +//| +//| length = 8000 // 440 +//| sine_wave = array.array("H", [0] * length) +//| for i in range(length): +//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) +//| +//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) +//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(sine_wave, loop=True) +//| time.sleep(1) +//| dac.stop() +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audiocore +//| import mtm_hardware +//| +//| f = open("sound.wav", "rb") +//| wav = audiocore.WaveFile(f) +//| +//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(wav) +//| while dac.playing: +//| pass""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_clock, ARG_mosi, ARG_cs }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + + mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); + common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs); + + return MP_OBJ_FROM_PTR(self); +} + +static void check_for_deinit(mtm_hardware_dacout_obj_t *self) { + if (common_hal_mtm_hardware_dacout_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Deinitialises the DACOut and releases any hardware resources for reuse.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_deinit(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_mtm_hardware_dacout_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_deinit_obj, mtm_hardware_dacout_deinit); + +//| def __enter__(self) -> DACOut: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. +//| +//| The sample itself should consist of 8 bit or 16 bit samples.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_mtm_hardware_dacout_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mtm_hardware_dacout_play_obj, 1, mtm_hardware_dacout_obj_play); + +//| def stop(self) -> None: +//| """Stops playback.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_stop(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_mtm_hardware_dacout_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_stop_obj, mtm_hardware_dacout_obj_stop); + +//| playing: bool +//| """True when the audio sample is being output. (read-only)""" +//| +static mp_obj_t mtm_hardware_dacout_obj_get_playing(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_playing_obj, mtm_hardware_dacout_obj_get_playing); + +MP_PROPERTY_GETTER(mtm_hardware_dacout_playing_obj, + (mp_obj_t)&mtm_hardware_dacout_get_playing_obj); + +//| def pause(self) -> None: +//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_pause(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (!common_hal_mtm_hardware_dacout_get_playing(self)) { + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Not playing")); + } + common_hal_mtm_hardware_dacout_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_pause_obj, mtm_hardware_dacout_obj_pause); + +//| def resume(self) -> None: +//| """Resumes sample playback after :py:func:`pause`.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_resume(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_mtm_hardware_dacout_get_paused(self)) { + common_hal_mtm_hardware_dacout_resume(self); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_resume_obj, mtm_hardware_dacout_obj_resume); + +//| paused: bool +//| """True when playback is paused. (read-only)""" +//| +static mp_obj_t mtm_hardware_dacout_obj_get_paused(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_paused_obj, mtm_hardware_dacout_obj_get_paused); + +MP_PROPERTY_GETTER(mtm_hardware_dacout_paused_obj, + (mp_obj_t)&mtm_hardware_dacout_get_paused_obj); + +// ── DACOut type definition ─────────────────────────────────────────────────── + +static const mp_rom_map_elem_t mtm_hardware_dacout_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mtm_hardware_dacout_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mtm_hardware_dacout_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mtm_hardware_dacout_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mtm_hardware_dacout_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mtm_hardware_dacout_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mtm_hardware_dacout_paused_obj) }, +}; +static MP_DEFINE_CONST_DICT(mtm_hardware_dacout_locals_dict, mtm_hardware_dacout_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mtm_hardware_dacout_type, + MP_QSTR_DACOut, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, mtm_hardware_dacout_make_new, + locals_dict, &mtm_hardware_dacout_locals_dict + ); + +// ───────────────────────────────────────────────────────────────────────────── +// mtm_hardware module definition +// ───────────────────────────────────────────────────────────────────────────── + +//| """Hardware interface to Music Thing Modular Workshop Computer peripherals. +//| +//| Provides the `DACOut` class for non-blocking audio output via the +//| MCP4822 dual-channel 12-bit SPI DAC. +//| """ + +static const mp_rom_map_elem_t mtm_hardware_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mtm_hardware) }, + { MP_ROM_QSTR(MP_QSTR_DACOut), MP_ROM_PTR(&mtm_hardware_dacout_type) }, +}; + +static MP_DEFINE_CONST_DICT(mtm_hardware_module_globals, mtm_hardware_module_globals_table); + +const mp_obj_module_t mtm_hardware_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mtm_hardware_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_mtm_hardware, mtm_hardware_module); From a5f9f3b663fa4169c9ef4280aaff7b7f1e648494 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 12:58:15 -0700 Subject: [PATCH 313/876] mtm_hardware.dacout: add gain=1 or gain=2 argument --- .../boards/mtm_computer/module/DACOut.c | 21 +++++++++++++++++-- .../boards/mtm_computer/module/DACOut.h | 2 +- .../boards/mtm_computer/module/mtm_hardware.c | 13 ++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c index 84f4296cb00..fb4ce37d4d0 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c @@ -128,9 +128,19 @@ static const uint16_t mcp4822_pio_program[] = { #define MCP4822_CLOCKS_PER_SAMPLE 86 +// MCP4822 gain bit (bit 13) position in the PIO program: +// Instruction 6 = channel A gain bit +// Instruction 18 = channel B gain bit +// 1x gain: set pins, 1 (0xE001) — bit 13 = 1 +// 2x gain: set pins, 0 (0xE000) — bit 13 = 0 +#define MCP4822_PIO_GAIN_INSTR_A 6 +#define MCP4822_PIO_GAIN_INSTR_B 18 +#define MCP4822_PIO_GAIN_1X 0xE001 // set pins, 1 +#define MCP4822_PIO_GAIN_2X 0xE000 // set pins, 0 + void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs) { + const mcu_pin_obj_t *cs, uint8_t gain) { // SET pins span from MOSI to CS. MOSI must have a lower GPIO number // than CS, with at most 4 pins between them (SET count max is 5). @@ -141,6 +151,13 @@ void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, uint8_t set_count = cs->number - mosi->number + 1; + // Build a mutable copy of the PIO program and patch the gain bit + uint16_t program[MP_ARRAY_SIZE(mcp4822_pio_program)]; + memcpy(program, mcp4822_pio_program, sizeof(mcp4822_pio_program)); + uint16_t gain_instr = (gain == 2) ? MCP4822_PIO_GAIN_2X : MCP4822_PIO_GAIN_1X; + program[MCP4822_PIO_GAIN_INSTR_A] = gain_instr; + program[MCP4822_PIO_GAIN_INSTR_B] = gain_instr; + // Initial SET pin state: CS high (bit at CS position), others low uint32_t cs_bit_position = cs->number - mosi->number; pio_pinmask32_t initial_set_state = PIO_PINMASK32_FROM_VALUE(1u << cs_bit_position); @@ -148,7 +165,7 @@ void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, common_hal_rp2pio_statemachine_construct( &self->state_machine, - mcp4822_pio_program, MP_ARRAY_SIZE(mcp4822_pio_program), + program, MP_ARRAY_SIZE(mcp4822_pio_program), 44100 * MCP4822_CLOCKS_PER_SAMPLE, // Initial frequency; play() adjusts NULL, 0, // No init program NULL, 0, // No may_exec diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h index f7c0c9eb806..f9b5dd60108 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h @@ -21,7 +21,7 @@ typedef struct { void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs); + const mcu_pin_obj_t *cs, uint8_t gain); void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c index a3dafbcf941..8f875496f67 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c +++ b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c @@ -29,12 +29,15 @@ //| clock: microcontroller.Pin, //| mosi: microcontroller.Pin, //| cs: microcontroller.Pin, +//| *, +//| gain: int = 1, //| ) -> None: //| """Create a DACOut object associated with the given SPI pins. //| //| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin //| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin //| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. //| //| Simple 8ksps 440 Hz sine wave:: //| @@ -72,11 +75,12 @@ //| ... //| static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_clock, ARG_mosi, ARG_cs }; + enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -85,8 +89,13 @@ static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + mp_int_t gain = args[ARG_gain].u_int; + if (gain != 1 && gain != 2) { + mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("gain must be 1 or 2")); + } + mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); - common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs); + common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs, (uint8_t)gain); return MP_OBJ_FROM_PTR(self); } From 02675cbe1c009a07f4d71d1536db8c85dab5e4a9 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 16:42:55 -0700 Subject: [PATCH 314/876] rework mcp4822 module from mtm_hardware.DACOut --- locale/circuitpython.pot | 4579 ----------------- ports/raspberrypi/boards/mtm_computer/board.c | 19 + .../boards/mtm_computer/module/DACOut.h | 38 - .../boards/mtm_computer/module/mtm_hardware.c | 276 - .../boards/mtm_computer/mpconfigboard.mk | 5 +- ports/raspberrypi/boards/mtm_computer/pins.c | 6 +- .../DACOut.c => common-hal/mcp4822/MCP4822.c} | 90 +- .../raspberrypi/common-hal/mcp4822/MCP4822.h | 22 + .../raspberrypi/common-hal/mcp4822/__init__.c | 7 + ports/raspberrypi/mpconfigport.mk | 1 + py/circuitpy_defns.mk | 5 + shared-bindings/mcp4822/MCP4822.c | 247 + shared-bindings/mcp4822/MCP4822.h | 25 + shared-bindings/mcp4822/__init__.c | 36 + shared-bindings/mcp4822/__init__.h | 7 + 15 files changed, 417 insertions(+), 4946 deletions(-) delete mode 100644 locale/circuitpython.pot delete mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.h delete mode 100644 ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c rename ports/raspberrypi/{boards/mtm_computer/module/DACOut.c => common-hal/mcp4822/MCP4822.c} (75%) create mode 100644 ports/raspberrypi/common-hal/mcp4822/MCP4822.h create mode 100644 ports/raspberrypi/common-hal/mcp4822/__init__.c create mode 100644 shared-bindings/mcp4822/MCP4822.c create mode 100644 shared-bindings/mcp4822/MCP4822.h create mode 100644 shared-bindings/mcp4822/__init__.c create mode 100644 shared-bindings/mcp4822/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot deleted file mode 100644 index bf4c5d110f6..00000000000 --- a/locale/circuitpython.pot +++ /dev/null @@ -1,4579 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: main.c -msgid "" -"\n" -"Code done running.\n" -msgstr "" - -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" -msgstr "" - -#: py/obj.c -msgid " File \"%q\"" -msgstr "" - -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr "" - -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr "" - -#: main.c -msgid " not found.\n" -msgstr "" - -#: main.c -msgid " output:\n" -msgstr "" - -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" -msgstr "" - -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "" - -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" -msgstr "" - -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" -msgstr "" - -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" -msgstr "" - -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" - -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "" - -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "" - -#: py/objstr.c -msgid "%q index out of range" -msgstr "" - -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q init failed" -msgstr "" - -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "" - -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "" - -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "" - -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "" - -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "" - -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "" - -#: py/argcheck.c -msgid "%q must be %d" -msgstr "" - -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "" - -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "" - -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "" - -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "" - -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "" - -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "" - -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "" - -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "" - -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." -msgstr "" - -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "" - -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" -msgstr "" - -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "" - -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" -msgstr "" - -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "" - -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "" - -#: shared-module/bitbangio/I2C.c -msgid "%q too long" -msgstr "" - -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" -msgstr "" - -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "" - -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "" - -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "" - -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" -msgstr "" - -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "" - -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" -msgstr "" - -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "" - -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "" - -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "" - -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "" - -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "" - -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "" - -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "" - -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "" - -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "" - -#: py/compile.c -msgid "'await' outside function" -msgstr "" - -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "" - -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "" - -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "" - -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "" - -#: py/emitnative.c -msgid "'not' not implemented" -msgstr "" - -#: py/compile.c -msgid "'return' outside function" -msgstr "" - -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "" - -#: py/compile.c -msgid "'yield' outside function" -msgstr "" - -#: py/compile.c -msgid "* arg after **" -msgstr "" - -#: py/compile.c -msgid "*x must be assignment target" -msgstr "" - -#: py/obj.c -msgid ", in %q\n" -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" -msgstr "" - -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "" - -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "" - -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "" - -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "" - -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "" - -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "" - -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "" - -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "" - -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "" - -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "" - -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" -msgstr "" - -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "" - -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "" - -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" -msgstr "" - -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "" - -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "" - -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "" - -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "" - -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "" - -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" - -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "" - -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "" - -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "" - -#: main.c -msgid "Auto-reload is off.\n" -msgstr "" - -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "" - -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "" - -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" -msgstr "" - -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "" - -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "" - -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "" - -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "" - -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "" - -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "" - -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" -msgstr "" - -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "" - -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "" - -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" -msgstr "" - -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." -msgstr "" - -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." -msgstr "" - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "" - -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" - -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." -msgstr "" - -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "" - -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" -msgstr "" - -#: shared-module/usb/core/Device.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Could not allocate DMA capable buffer" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "" - -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" -msgstr "" - -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" -msgstr "" - -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" -msgstr "" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "" - -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" -msgstr "" - -#: main.c -msgid "Done" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." -msgstr "" - -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "" - -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" -msgstr "" - -#: extmod/modre.c -msgid "Error in regex" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "" - -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "" - -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "" - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "" - -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" -msgstr "" - -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "" - -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" -msgstr "" - -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" -msgstr "" - -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "" - -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" -msgstr "" - -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" -msgstr "" - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" -msgstr "" - -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "" - -#: py/moderrno.c -msgid "File exists" -msgstr "" - -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" -msgstr "" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" -msgstr "" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "" - -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "" - -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" -msgstr "" - -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "" - -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" -msgstr "" - -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "" - -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." -msgstr "" - -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "" - -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "" - -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "" - -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "" - -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "" - -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "" - -#: py/moderrno.c -msgid "Input/output error" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "" - -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "" - -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c -msgid "Internal error" -msgstr "" - -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" -msgstr "" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/espressif/common-hal/mipidsi/Display.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c -#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "" - -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" -msgstr "" - -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "" - -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" -msgstr "" - -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "" - -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" -msgstr "" - -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "" - -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "" - -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "" - -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "" - -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "" - -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "" - -#: py/compile.c -msgid "LHS of keyword arg must be an id" -msgstr "" - -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "" - -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "" - -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" -msgstr "" - -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" -msgstr "" - -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "" - -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "" - -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" -msgstr "" - -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "" - -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" -msgstr "" - -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." -msgstr "" - -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "" - -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" -msgstr "" - -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" -msgstr "" - -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "" - -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" -msgstr "" - -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" -msgstr "" - -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" -msgstr "" - -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "" - -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" -msgstr "" - -#: shared-module/usb/core/Device.c -msgid "No configuration set" -msgstr "" - -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" -msgstr "" - -#: shared-bindings/board/__init__.c -msgid "No default %q bus" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "" - -#: shared-bindings/os/__init__.c -msgid "No hardware random available" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" -msgstr "" - -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" -msgstr "" - -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "" - -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" -msgstr "" - -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" -msgstr "" - -#: py/moderrno.c -msgid "No space left on device" -msgstr "" - -#: py/moderrno.c -msgid "No such device" -msgstr "" - -#: py/moderrno.c -msgid "No such file/directory" -msgstr "" - -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" -msgstr "" - -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" -msgstr "" - -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" -msgstr "" - -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" -msgstr "" - -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" - -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." -msgstr "" - -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "" - -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" -msgstr "" - -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "" - -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" -msgstr "" - -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" -msgstr "" - -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" -msgstr "" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "" - -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" -msgstr "" - -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." -msgstr "" - -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." -msgstr "" - -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" -msgstr "" - -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" -msgstr "" - -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." -msgstr "" - -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" -msgstr "" - -#: py/moderrno.c -msgid "Operation not permitted" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Operation timed out" -msgstr "" - -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" -msgstr "" - -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "" - -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" -msgstr "" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" -msgstr "" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" -msgstr "" - -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" -msgstr "" - -#: ports/espressif/common-hal/audiobusio/__init__.c -msgid "Peripheral in use" -msgstr "" - -#: py/moderrno.c -msgid "Permission denied" -msgstr "" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" -msgstr "" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" -msgstr "" - -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" -msgstr "" - -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" -msgstr "" - -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" -msgstr "" - -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" -msgstr "" - -#: shared-module/usb/core/Device.c -msgid "Pipe error" -msgstr "" - -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "" - -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" -msgstr "" - -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" -msgstr "" - -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "" - -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" -msgstr "" - -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Pull not used when direction is output." -msgstr "" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" -msgstr "" - -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" -msgstr "" - -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" -msgstr "" - -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "" - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" -msgstr "" - -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "" - -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "" - -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "" - -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "" - -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "" - -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" -msgstr "" - -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" -msgstr "" - -#: main.c -msgid "Running in safe mode! Not running saved code.\n" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" -msgstr "" - -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" -msgstr "" - -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" -msgstr "" - -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" -msgstr "" - -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" -msgstr "" - -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" -msgstr "" - -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" -msgstr "" - -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" -msgstr "" - -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" -msgstr "" - -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" -msgstr "" - -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "" - -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." -msgstr "" - -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" -msgstr "" - -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" -msgstr "" - -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" -msgstr "" - -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." -msgstr "" - -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" -msgstr "" - -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" -msgstr "" - -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." -msgstr "" - -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "" - -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." -msgstr "" - -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." -msgstr "" - -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." -msgstr "" - -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "" - -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "" - -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" -msgstr "" - -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" - -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" -msgstr "" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" -msgstr "" - -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" -msgstr "" - -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "" - -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" -msgstr "" - -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" -msgstr "" - -#: py/obj.c -msgid "Traceback (most recent call last):\n" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" -msgstr "" - -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" -msgstr "" - -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "" - -#: main.c -msgid "UID:" -msgstr "" - -#: shared-module/usb_hid/Device.c -msgid "USB busy" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." -msgstr "" - -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "" - -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -msgstr "" - -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" -msgstr "" - -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." -msgstr "" - -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" -msgstr "" - -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" -msgstr "" - -#: py/parse.c -msgid "Unable to init parser" -msgstr "" - -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" -msgstr "" - -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" - -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "" - -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." -msgstr "" - -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "" - -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." -msgstr "" - -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" -msgstr "" - -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" -msgstr "" - -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" -msgstr "" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" -msgstr "" - -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" -msgstr "" - -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" -msgstr "" - -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" -msgstr "" - -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" -msgstr "" - -#: ports/zephyr-cp/common-hal/busio/I2C.c -#: ports/zephyr-cp/common-hal/busio/SPI.c -#: ports/zephyr-cp/common-hal/busio/UART.c -msgid "Use device tree to define %q devices" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" -msgstr "" - -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" -msgstr "" - -#: main.c -msgid "WARNING: Your code filename has two extensions\n" -msgstr "" - -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" -msgstr "" - -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" -msgstr "" - -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" -msgstr "" - -#: main.c -msgid "Woken up by alarm.\n" -msgstr "" - -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" -msgstr "" - -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." -msgstr "" - -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." -msgstr "" - -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" -msgstr "" - -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." -msgstr "" - -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." -msgstr "" - -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." -msgstr "" - -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." -msgstr "" - -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." -msgstr "" - -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." -msgstr "" - -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." -msgstr "" - -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" -msgstr "" - -#: py/objtype.c -msgid "__init__() should return None" -msgstr "" - -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" -msgstr "" - -#: py/objobject.c -msgid "__new__ arg must be a user-type" -msgstr "" - -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" -msgstr "" - -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" -msgstr "" - -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" -msgstr "" - -#: py/compile.c -msgid "annotation must be an identifier" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" -msgstr "" - -#: py/modbuiltins.c -msgid "arg is an empty sequence" -msgstr "" - -#: py/objobject.c -msgid "arg must be user-type" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" -msgstr "" - -#: py/compile.c -msgid "argument name reused" -msgstr "" - -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "array is too big" -msgstr "" - -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" -msgstr "" - -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - -#: py/compile.c -msgid "async for/with outside async function" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" -msgstr "" - -#: py/objstr.c -msgid "attributes not supported" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" -msgstr "" - -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" -msgstr "" - -#: py/builtinevex.c -msgid "bad compile mode" -msgstr "" - -#: py/objstr.c -msgid "bad conversion specifier" -msgstr "" - -#: py/objstr.c -msgid "bad format string" -msgstr "" - -#: py/binary.c py/objarray.c -msgid "bad typecode" -msgstr "" - -#: py/emitnative.c -msgid "binary op %q not implemented" -msgstr "" - -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" -msgstr "" - -#: extmod/modrandom.c -msgid "bits must be 32 or less" -msgstr "" - -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" -msgstr "" - -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" -msgstr "" - -#: py/emitinlinethumb.c -msgid "branch not in range" -msgstr "" - -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" -msgstr "" - -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" -msgstr "" - -#: shared-module/struct/__init__.c -msgid "buffer size must match format" -msgstr "" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" -msgstr "" - -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" -msgstr "" - -#: py/emitbc.c -msgid "bytecode overflow" -msgstr "" - -#: py/objarray.c -msgid "bytes length not a multiple of item size" -msgstr "" - -#: py/objstr.c -msgid "bytes value out of range" -msgstr "" - -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" -msgstr "" - -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" -msgstr "" - -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" -msgstr "" - -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" -msgstr "" - -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" -msgstr "" - -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" -msgstr "" - -#: py/objtype.c -msgid "can't add special method to already-subclassed class" -msgstr "" - -#: py/compile.c -msgid "can't assign to expression" -msgstr "" - -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "" - -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" -msgstr "" - -#: py/obj.c -#, c-format -msgid "can't convert %s to complex" -msgstr "" - -#: py/obj.c -#, c-format -msgid "can't convert %s to float" -msgstr "" - -#: py/objint.c py/runtime.c -#, c-format -msgid "can't convert %s to int" -msgstr "" - -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" -msgstr "" - -#: py/obj.c -msgid "can't convert to complex" -msgstr "" - -#: py/obj.c -msgid "can't convert to float" -msgstr "" - -#: py/runtime.c -msgid "can't convert to int" -msgstr "" - -#: py/objstr.c -msgid "can't convert to str implicitly" -msgstr "" - -#: py/objtype.c -msgid "can't create '%q' instances" -msgstr "" - -#: py/compile.c -msgid "can't declare nonlocal in outer code" -msgstr "" - -#: py/compile.c -msgid "can't delete expression" -msgstr "" - -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't do unary op of '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" -msgstr "" - -#: py/runtime.c -msgid "can't import name %q" -msgstr "" - -#: py/emitnative.c -msgid "can't load from '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't load with '%q' index" -msgstr "" - -#: py/builtinimport.c -msgid "can't perform relative import" -msgstr "" - -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" -msgstr "" - -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" -msgstr "" - -#: py/runtime.c -msgid "can't set attribute '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't store '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't store to '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't store with '%q' index" -msgstr "" - -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" -msgstr "" - -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" -msgstr "" - -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" -msgstr "" - -#: extmod/modasyncio.c -msgid "can't wait" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" -msgstr "" - -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" -msgstr "" - -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" -msgstr "" - -#: py/emitnative.c -msgid "casting" -msgstr "" - -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" -msgstr "" - -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" -msgstr "" - -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" -msgstr "" - -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" -msgstr "" - -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" -msgstr "" - -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" -msgstr "" - -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" -msgstr "" - -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" -msgstr "" - -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" -msgstr "" - -#: py/emitnative.c -msgid "comparison of int and uint" -msgstr "" - -#: py/objcomplex.c -msgid "complex divide by zero" -msgstr "" - -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" -msgstr "" - -#: extmod/modzlib.c -msgid "compression header" -msgstr "" - -#: py/emitnative.c -msgid "conversion to object" -msgstr "" - -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" -msgstr "" - -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" -msgstr "" - -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" -msgstr "" - -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "data pin #%d in use" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" -msgstr "" - -#: py/parsenum.c -msgid "decimal numbers not supported" -msgstr "" - -#: py/compile.c -msgid "default 'except' must be last" -msgstr "" - -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" - -#: py/objdict.c -msgid "dict update sequence has wrong length" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" -msgstr "" - -#: py/emitnative.c -msgid "div/mod not implemented for uint" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" -msgstr "" - -#: py/runtime.c -msgid "division by zero" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" -msgstr "" - -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" -msgstr "" - -#: py/objdeque.c -msgid "empty" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" -msgstr "" - -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" -msgstr "" - -#: py/objstr.c -msgid "empty separator" -msgstr "" - -#: shared-bindings/random/__init__.c -msgid "empty sequence" -msgstr "" - -#: py/objstr.c -msgid "end of format while looking for conversion specifier" -msgstr "" - -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" -msgstr "" - -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" -msgstr "" - -#: py/runtime.c -msgid "exceptions must derive from BaseException" -msgstr "" - -#: py/objstr.c -msgid "expected ':' after format specifier" -msgstr "" - -#: py/obj.c -msgid "expected tuple/list" -msgstr "" - -#: py/modthread.c -msgid "expecting a dict for keyword args" -msgstr "" - -#: py/compile.c -msgid "expecting an assembler instruction" -msgstr "" - -#: py/compile.c -msgid "expecting just a value for set" -msgstr "" - -#: py/compile.c -msgid "expecting key:value for dict" -msgstr "" - -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" -msgstr "" - -#: py/argcheck.c -msgid "extra keyword arguments given" -msgstr "" - -#: py/argcheck.c -msgid "extra positional arguments given" -msgstr "" - -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" -msgstr "" - -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" -msgstr "" - -#: py/objtype.c -msgid "first argument to super() must be type" -msgstr "" - -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" -msgstr "" - -#: py/objint.c -msgid "float too big" -msgstr "" - -#: py/nativeglue.c -msgid "float unsupported" -msgstr "" - -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - -#: extmod/moddeflate.c -msgid "format" -msgstr "" - -#: py/objstr.c -msgid "format needs a dict" -msgstr "" - -#: py/objstr.c -msgid "format string didn't convert all arguments" -msgstr "" - -#: py/objstr.c -msgid "format string needs more arguments" -msgstr "" - -#: py/objdeque.c -msgid "full" -msgstr "" - -#: py/argcheck.c -msgid "function doesn't take keyword arguments" -msgstr "" - -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" -msgstr "" - -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" -msgstr "" - -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" -msgstr "" - -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" -msgstr "" - -#: py/bc.c -msgid "function missing keyword-only argument" -msgstr "" - -#: py/bc.c -msgid "function missing required keyword argument '%q'" -msgstr "" - -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" -msgstr "" - -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" -msgstr "" - -#: py/objgenerator.c -msgid "generator already executing" -msgstr "" - -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" -msgstr "" - -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" -msgstr "" - -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - -#: extmod/modhashlib.c -msgid "hash is final" -msgstr "" - -#: extmod/modheapq.c -msgid "heap must be a list" -msgstr "" - -#: py/compile.c -msgid "identifier redefined as global" -msgstr "" - -#: py/compile.c -msgid "identifier redefined as nonlocal" -msgstr "" - -#: py/compile.c -msgid "import * not at module level" -msgstr "" - -#: py/persistentcode.c -msgid "incompatible .mpy arch" -msgstr "" - -#: py/persistentcode.c -msgid "incompatible .mpy file" -msgstr "" - -#: py/objstr.c -msgid "incomplete format" -msgstr "" - -#: py/objstr.c -msgid "incomplete format key" -msgstr "" - -#: extmod/modbinascii.c -msgid "incorrect padding" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" -msgstr "" - -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" -msgstr "" - -#: py/obj.c -msgid "indices must be integers" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" -msgstr "" - -#: py/compile.c -msgid "inline assembler must be a function" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" -msgstr "" - -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" -msgstr "" - -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" -msgstr "" - -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" -msgstr "" - -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" -msgstr "" - -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" -msgstr "" - -#: py/compile.c -msgid "invalid arch" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" -msgstr "" - -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" -msgstr "" - -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" -msgstr "" - -#: py/objstr.c -msgid "invalid format specifier" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" -msgstr "" - -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" -msgstr "" - -#: py/compile.c -msgid "invalid micropython decorator" -msgstr "" - -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" -msgstr "" - -#: shared-bindings/random/__init__.c -msgid "invalid step" -msgstr "" - -#: py/compile.c py/parse.c -msgid "invalid syntax" -msgstr "" - -#: py/parsenum.c -msgid "invalid syntax for integer" -msgstr "" - -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" -msgstr "" - -#: py/parsenum.c -msgid "invalid syntax for number" -msgstr "" - -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" -msgstr "" - -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" -msgstr "" - -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" -msgstr "" - -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" -msgstr "" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" -msgstr "" - -#: py/compile.c -msgid "label redefined" -msgstr "" - -#: py/objarray.c -msgid "lhs and rhs should be compatible" -msgstr "" - -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" -msgstr "" - -#: py/emitnative.c -msgid "local '%q' used before type known" -msgstr "" - -#: py/vm.c -msgid "local variable referenced before assignment" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" -msgstr "" - -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" -msgstr "" - -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" -msgstr "" - -#: py/parse.c -msgid "malformed f-string" -msgstr "" - -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" -msgstr "" - -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "" - -#: py/runtime.c -msgid "maximum recursion depth exceeded" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" -msgstr "" - -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" -msgstr "" - -#: py/runtime.c -msgid "memory allocation failed, heap is locked" -msgstr "" - -#: py/objarray.c -msgid "memoryview offset too large" -msgstr "" - -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" -msgstr "" - -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" -msgstr "" - -#: py/builtinimport.c -msgid "module not found" -msgstr "" - -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" -msgstr "" - -#: py/compile.c -msgid "multiple *x in assignment" -msgstr "" - -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" -msgstr "" - -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "" - -#: py/emitnative.c -msgid "must raise an object" -msgstr "" - -#: py/modbuiltins.c -msgid "must use keyword argument for key function" -msgstr "" - -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "" - -#: py/runtime.c -msgid "name not defined" -msgstr "" - -#: py/qstr.c -msgid "name too long" -msgstr "" - -#: py/persistentcode.c -msgid "native code in .mpy unsupported" -msgstr "" - -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - -#: py/emitnative.c -msgid "native yield" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" -msgstr "" - -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" -msgstr "" - -#: py/modmath.c -msgid "negative factorial" -msgstr "" - -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" -msgstr "" - -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" -msgstr "" - -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "" - -#: py/vm.c -msgid "no active exception to reraise" -msgstr "" - -#: py/compile.c -msgid "no binding for nonlocal found" -msgstr "" - -#: shared-module/msgpack/__init__.c -msgid "no default packer" -msgstr "" - -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" -msgstr "" - -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" -msgstr "" - -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" -msgstr "" - -#: py/compile.c -msgid "non-default argument follows default argument" -msgstr "" - -#: py/objstr.c -msgid "non-hex digit" -msgstr "" - -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" -msgstr "" - -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" -msgstr "" - -#: py/parse.c -msgid "not a constant" -msgstr "" - -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" -msgstr "" - -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" -msgstr "" - -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" -msgstr "" - -#: py/builtinhelp.c -msgid "object " -msgstr "" - -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "object does not support DigitalInOut protocol" -msgstr "" - -#: py/obj.c -msgid "object doesn't support item assignment" -msgstr "" - -#: py/obj.c -msgid "object doesn't support item deletion" -msgstr "" - -#: py/obj.c -msgid "object has no len" -msgstr "" - -#: py/obj.c -msgid "object isn't subscriptable" -msgstr "" - -#: py/runtime.c -msgid "object not an iterator" -msgstr "" - -#: py/objtype.c py/runtime.c -msgid "object not callable" -msgstr "" - -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" -msgstr "" - -#: py/runtime.c -msgid "object not iterable" -msgstr "" - -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" -msgstr "" - -#: py/obj.c -msgid "object with buffer protocol required" -msgstr "" - -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" -msgstr "" - -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" -msgstr "" - -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" -msgstr "" - -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" -msgstr "" - -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" -msgstr "" - -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" -msgstr "" - -#: py/vm.c -msgid "opcode" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" -msgstr "" - -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" -msgstr "" - -#: py/modbuiltins.c -msgid "ord expects a character" -msgstr "" - -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" -msgstr "" - -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" -msgstr "" - -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" -msgstr "" - -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" -msgstr "" - -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "" - -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" - -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" -msgstr "" - -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" -msgstr "" - -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" -msgstr "" - -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" -msgstr "" - -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" -msgstr "" - -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" -msgstr "" - -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" -msgstr "" - -#: py/compile.c -msgid "positional arg after **" -msgstr "" - -#: py/compile.c -msgid "positional arg after keyword arg" -msgstr "" - -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" -msgstr "" - -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" -msgstr "" - -#: py/builtinimport.c -msgid "relative import" -msgstr "" - -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" -msgstr "" - -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" -msgstr "" - -#: py/compile.c -msgid "return annotation must be an identifier" -msgstr "" - -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" -msgstr "" - -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "" - -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" -msgstr "" - -#: py/modmicropython.c -msgid "schedule queue full" -msgstr "" - -#: py/builtinimport.c -msgid "script compilation not supported" -msgstr "" - -#: py/nativeglue.c -msgid "set unsupported" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" -msgstr "" - -#: shared-module/msgpack/__init__.c -msgid "short read" -msgstr "" - -#: py/objstr.c -msgid "sign not allowed in string format specifier" -msgstr "" - -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" -msgstr "" - -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" -msgstr "" - -#: py/nativeglue.c -msgid "slice unsupported" -msgstr "" - -#: py/objint.c py/sequence.c -msgid "small int overflow" -msgstr "" - -#: main.c -msgid "soft reboot\n" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" -msgstr "" - -#: extmod/modre.c -msgid "splitting with sub-captures" -msgstr "" - -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" -msgstr "" - -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" -msgstr "" - -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" -msgstr "" - -#: py/objstrunicode.c -msgid "string index out of range" -msgstr "" - -#: py/objstrunicode.c -#, c-format -msgid "string indices must be integers, not %s" -msgstr "" - -#: py/objarray.c py/objstr.c -msgid "substring not found" -msgstr "" - -#: py/compile.c -msgid "super() can't find self" -msgstr "" - -#: extmod/modjson.c -msgid "syntax error in JSON" -msgstr "" - -#: extmod/modtime.c -msgid "ticks interval overflow" -msgstr "" - -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" -msgstr "" - -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" -msgstr "" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" -msgstr "" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" -msgstr "" - -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" -msgstr "" - -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" -msgstr "" - -#: py/compile.c -msgid "too many args" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "too many indices" -msgstr "" - -#: py/asmthumb.c -msgid "too many locals for native method" -msgstr "" - -#: py/runtime.c -#, c-format -msgid "too many values to unpack (expected %d)" -msgstr "" - -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" -msgstr "" - -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" -msgstr "" - -#: py/obj.c -msgid "tuple/list has wrong length" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" -msgstr "" - -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" -msgstr "" - -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" -msgstr "" - -#: py/objtype.c -msgid "type isn't an acceptable base type" -msgstr "" - -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" -msgstr "" - -#: py/objtype.c -msgid "type takes 1 or 3 arguments" -msgstr "" - -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - -#: py/parse.c -msgid "unexpected indent" -msgstr "" - -#: py/bc.c -msgid "unexpected keyword argument" -msgstr "" - -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" -msgstr "" - -#: py/lexer.c -msgid "unicode name escapes" -msgstr "" - -#: py/parse.c -msgid "unindent doesn't match any outer indent level" -msgstr "" - -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" -msgstr "" - -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" -msgstr "" - -#: py/compile.c -msgid "unknown type" -msgstr "" - -#: py/compile.c -msgid "unknown type '%q'" -msgstr "" - -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" -msgstr "" - -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" -msgstr "" - -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" -msgstr "" - -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" -msgstr "" - -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" -msgstr "" - -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" -msgstr "" - -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" -msgstr "" - -#: py/runtime.c -msgid "unsupported type for %q: '%s'" -msgstr "" - -#: py/runtime.c -msgid "unsupported type for operator" -msgstr "" - -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" -msgstr "" - -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" -msgstr "" - -#: extmod/moddeflate.c -msgid "wbits" -msgstr "" - -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" -msgstr "" - -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "" - -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" -msgstr "" - -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" -msgstr "" - -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" -msgstr "" - -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" -msgstr "" - -#: py/runtime.c -msgid "wrong number of values to unpack" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" -msgstr "" diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index e6a868ab212..9065ffebcf8 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -5,5 +5,24 @@ // SPDX-License-Identifier: MIT #include "supervisor/board.h" +#include "shared-bindings/mcp4822/MCP4822.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "peripherals/pins.h" +#include "py/runtime.h" + +// board.DAC() — factory function that constructs an mcp4822.MCP4822 with +// the MTM Workshop Computer's DAC pins (GP18=SCK, GP19=SDI, GP21=CS). +static mp_obj_t board_dac_factory(void) { + mcp4822_mcp4822_obj_t *dac = mp_obj_malloc_with_finaliser( + mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); + common_hal_mcp4822_mcp4822_construct( + dac, + &pin_GPIO18, // clock (SCK) + &pin_GPIO19, // mosi (SDI) + &pin_GPIO21, // cs + 1); // gain 1x + return MP_OBJ_FROM_PTR(dac); +} +MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h deleted file mode 100644 index f9b5dd60108..00000000000 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h +++ /dev/null @@ -1,38 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/rp2pio/StateMachine.h" - -#include "audio_dma.h" -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - rp2pio_statemachine_obj_t state_machine; - audio_dma_t dma; - bool playing; -} mtm_hardware_dacout_obj_t; - -void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, - const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs, uint8_t gain); - -void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); - -void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, - mp_obj_t sample, bool loop); -void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self); - -void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self); -void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self); - -extern const mp_obj_type_t mtm_hardware_dacout_type; diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c deleted file mode 100644 index 8f875496f67..00000000000 --- a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c +++ /dev/null @@ -1,276 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT -// -// Python bindings for the mtm_hardware module. -// Provides DACOut: a non-blocking audio player for the MCP4822 SPI DAC. - -#include - -#include "shared/runtime/context_manager_helpers.h" -#include "py/binary.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/util.h" -#include "boards/mtm_computer/module/DACOut.h" - -// ───────────────────────────────────────────────────────────────────────────── -// DACOut class -// ───────────────────────────────────────────────────────────────────────────── - -//| class DACOut: -//| """Output audio to the MCP4822 dual-channel 12-bit SPI DAC.""" -//| -//| def __init__( -//| self, -//| clock: microcontroller.Pin, -//| mosi: microcontroller.Pin, -//| cs: microcontroller.Pin, -//| *, -//| gain: int = 1, -//| ) -> None: -//| """Create a DACOut object associated with the given SPI pins. -//| -//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin -//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin -//| :param ~microcontroller.Pin cs: The chip select (CS) pin -//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. -//| -//| Simple 8ksps 440 Hz sine wave:: -//| -//| import mtm_hardware -//| import audiocore -//| import board -//| import array -//| import time -//| import math -//| -//| length = 8000 // 440 -//| sine_wave = array.array("H", [0] * length) -//| for i in range(length): -//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) -//| -//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) -//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) -//| dac.play(sine_wave, loop=True) -//| time.sleep(1) -//| dac.stop() -//| -//| Playing a wave file from flash:: -//| -//| import board -//| import audiocore -//| import mtm_hardware -//| -//| f = open("sound.wav", "rb") -//| wav = audiocore.WaveFile(f) -//| -//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) -//| dac.play(wav) -//| while dac.playing: -//| pass""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); - const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); - const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); - - mp_int_t gain = args[ARG_gain].u_int; - if (gain != 1 && gain != 2) { - mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("gain must be 1 or 2")); - } - - mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); - common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs, (uint8_t)gain); - - return MP_OBJ_FROM_PTR(self); -} - -static void check_for_deinit(mtm_hardware_dacout_obj_t *self) { - if (common_hal_mtm_hardware_dacout_deinited(self)) { - raise_deinited_error(); - } -} - -//| def deinit(self) -> None: -//| """Deinitialises the DACOut and releases any hardware resources for reuse.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_deinit(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_mtm_hardware_dacout_deinit(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_deinit_obj, mtm_hardware_dacout_deinit); - -//| def __enter__(self) -> DACOut: -//| """No-op used by Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -// Provided by context manager helper. - -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: -//| """Plays the sample once when loop=False and continuously when loop=True. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. -//| -//| The sample itself should consist of 8 bit or 16 bit samples.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_mtm_hardware_dacout_play(self, sample, args[ARG_loop].u_bool); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(mtm_hardware_dacout_play_obj, 1, mtm_hardware_dacout_obj_play); - -//| def stop(self) -> None: -//| """Stops playback.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_stop(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_mtm_hardware_dacout_stop(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_stop_obj, mtm_hardware_dacout_obj_stop); - -//| playing: bool -//| """True when the audio sample is being output. (read-only)""" -//| -static mp_obj_t mtm_hardware_dacout_obj_get_playing(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_playing(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_playing_obj, mtm_hardware_dacout_obj_get_playing); - -MP_PROPERTY_GETTER(mtm_hardware_dacout_playing_obj, - (mp_obj_t)&mtm_hardware_dacout_get_playing_obj); - -//| def pause(self) -> None: -//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_pause(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - if (!common_hal_mtm_hardware_dacout_get_playing(self)) { - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Not playing")); - } - common_hal_mtm_hardware_dacout_pause(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_pause_obj, mtm_hardware_dacout_obj_pause); - -//| def resume(self) -> None: -//| """Resumes sample playback after :py:func:`pause`.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_resume(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - if (common_hal_mtm_hardware_dacout_get_paused(self)) { - common_hal_mtm_hardware_dacout_resume(self); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_resume_obj, mtm_hardware_dacout_obj_resume); - -//| paused: bool -//| """True when playback is paused. (read-only)""" -//| -static mp_obj_t mtm_hardware_dacout_obj_get_paused(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_paused(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_paused_obj, mtm_hardware_dacout_obj_get_paused); - -MP_PROPERTY_GETTER(mtm_hardware_dacout_paused_obj, - (mp_obj_t)&mtm_hardware_dacout_get_paused_obj); - -// ── DACOut type definition ─────────────────────────────────────────────────── - -static const mp_rom_map_elem_t mtm_hardware_dacout_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mtm_hardware_dacout_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mtm_hardware_dacout_stop_obj) }, - { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mtm_hardware_dacout_pause_obj) }, - { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mtm_hardware_dacout_resume_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mtm_hardware_dacout_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mtm_hardware_dacout_paused_obj) }, -}; -static MP_DEFINE_CONST_DICT(mtm_hardware_dacout_locals_dict, mtm_hardware_dacout_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - mtm_hardware_dacout_type, - MP_QSTR_DACOut, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, mtm_hardware_dacout_make_new, - locals_dict, &mtm_hardware_dacout_locals_dict - ); - -// ───────────────────────────────────────────────────────────────────────────── -// mtm_hardware module definition -// ───────────────────────────────────────────────────────────────────────────── - -//| """Hardware interface to Music Thing Modular Workshop Computer peripherals. -//| -//| Provides the `DACOut` class for non-blocking audio output via the -//| MCP4822 dual-channel 12-bit SPI DAC. -//| """ - -static const mp_rom_map_elem_t mtm_hardware_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mtm_hardware) }, - { MP_ROM_QSTR(MP_QSTR_DACOut), MP_ROM_PTR(&mtm_hardware_dacout_type) }, -}; - -static MP_DEFINE_CONST_DICT(mtm_hardware_module_globals, mtm_hardware_module_globals_table); - -const mp_obj_module_t mtm_hardware_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&mtm_hardware_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_mtm_hardware, mtm_hardware_module); diff --git a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk index 74d9baac879..45c99711d72 100644 --- a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk +++ b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk @@ -11,7 +11,4 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_AUDIOEFFECTS = 1 CIRCUITPY_IMAGECAPTURE = 0 CIRCUITPY_PICODVI = 0 - -SRC_C += \ - boards/$(BOARD)/module/mtm_hardware.c \ - boards/$(BOARD)/module/DACOut.c +CIRCUITPY_MCP4822 = 1 diff --git a/ports/raspberrypi/boards/mtm_computer/pins.c b/ports/raspberrypi/boards/mtm_computer/pins.c index 69878182331..ffdf2687702 100644 --- a/ports/raspberrypi/boards/mtm_computer/pins.c +++ b/ports/raspberrypi/boards/mtm_computer/pins.c @@ -6,6 +6,8 @@ #include "shared-bindings/board/__init__.h" +extern const mp_obj_fun_builtin_fixed_t board_dac_obj; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -21,7 +23,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PULSE_2_IN), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_NORM_PROBE), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, @@ -105,6 +106,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + // Factory function: dac = board.DAC() returns a configured mcp4822.MCP4822 + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&board_dac_obj) }, + // { MP_ROM_QSTR(MP_QSTR_EEPROM_I2C), MP_ROM_PTR(&board_i2c_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c similarity index 75% rename from ports/raspberrypi/boards/mtm_computer/module/DACOut.c rename to ports/raspberrypi/common-hal/mcp4822/MCP4822.c index fb4ce37d4d0..cb6cddb8343 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT // -// MCP4822 dual-channel 12-bit SPI DAC driver for the MTM Workshop Computer. +// MCP4822 dual-channel 12-bit SPI DAC audio output. // Uses PIO + DMA for non-blocking audio playback, mirroring audiobusio.I2SOut. #include @@ -15,7 +15,8 @@ #include "py/gc.h" #include "py/mperrno.h" #include "py/runtime.h" -#include "boards/mtm_computer/module/DACOut.h" +#include "common-hal/mcp4822/MCP4822.h" +#include "shared-bindings/mcp4822/MCP4822.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/audiocore/__init__.h" #include "bindings/rp2pio/StateMachine.h" @@ -29,16 +30,14 @@ // SET pins (N) = MOSI through CS — for CS control & command-bit injection // SIDE-SET pin (1) = SCK — serial clock // -// On the MTM Workshop Computer: MOSI=GP19, CS=GP21, SCK=GP18. -// The SET group spans GP19..GP21 (3 pins). GP20 is unused and driven low. -// -// SET PINS bit mapping (bit0=MOSI/GP19, bit1=GP20, bit2=CS/GP21): -// 0 = CS low, MOSI low 1 = CS low, MOSI high 4 = CS high, MOSI low +// SET PINS bit mapping (bit0=MOSI, ..., bit N=CS): +// 0 = CS low, MOSI low 1 = CS low, MOSI high +// (1 << cs_bit_pos) = CS high, MOSI low // // SIDE-SET (1 pin, SCK): side 0 = SCK low, side 1 = SCK high // // MCP4822 16-bit command word: -// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x) +// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x, 0=2x) // [12] output enable (1) [11:0] 12-bit data // // DMA feeds unsigned 16-bit audio samples. RP2040 narrow-write replication @@ -46,8 +45,8 @@ // giving mono→stereo for free. // // The PIO pulls 32 bits, then sends two SPI transactions: -// Channel A: cmd nibble 0b0011, then all 16 sample bits from upper half-word -// Channel B: cmd nibble 0b1011, then all 16 sample bits from lower half-word +// Channel A: cmd nibble, then all 16 sample bits from upper half-word +// Channel B: cmd nibble, then all 16 sample bits from lower half-word // The MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data), // so only the top 12 of the 16 sample bits become DAC data. The bottom // 4 sample bits clock out harmlessly after the DAC has latched. @@ -66,11 +65,7 @@ static const uint16_t mcp4822_pio_program[] = { // 1: mov x, osr side 0 ; Save for pull-noblock fallback 0xA027, - // ── Channel A: command nibble 0b0011 ────────────────────────────────── - // Send 4 cmd bits via SET, then all 16 sample bits via OUT. - // MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data); - // the extra 4 clocks shift out the LSBs which the DAC ignores. - // This gives correct 16→12 bit scaling (top 12 bits become DAC data). + // ── Channel A: command nibble 0b0011 (1x gain) ──────────────────────── // 2: set pins, 0 side 0 ; CS low, MOSI=0 (bit15=0: channel A) 0xE000, // 3: nop side 1 ; SCK high — latch bit 15 @@ -79,7 +74,7 @@ static const uint16_t mcp4822_pio_program[] = { 0xE000, // 5: nop side 1 ; SCK high 0xB042, - // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) [patched for 2x] 0xE001, // 7: nop side 1 ; SCK high 0xB042, @@ -96,7 +91,7 @@ static const uint16_t mcp4822_pio_program[] = { // 13: set pins, 4 side 0 ; CS high — DAC A latches 0xE004, - // ── Channel B: command nibble 0b1011 ────────────────────────────────── + // ── Channel B: command nibble 0b1011 (1x gain) ──────────────────────── // 14: set pins, 1 side 0 ; CS low, MOSI=1 (bit15=1: channel B) 0xE001, // 15: nop side 1 ; SCK high @@ -105,7 +100,7 @@ static const uint16_t mcp4822_pio_program[] = { 0xE000, // 17: nop side 1 ; SCK high 0xB042, - // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) [patched for 2x] 0xE001, // 19: nop side 1 ; SCK high 0xB042, @@ -127,7 +122,6 @@ static const uint16_t mcp4822_pio_program[] = { // Per channel: 8(4 cmd bits × 2 clks) + 1(set y) + 32(16 bits × 2 clks) + 1(cs high) = 42 #define MCP4822_CLOCKS_PER_SAMPLE 86 - // MCP4822 gain bit (bit 13) position in the PIO program: // Instruction 6 = channel A gain bit // Instruction 18 = channel B gain bit @@ -138,15 +132,19 @@ static const uint16_t mcp4822_pio_program[] = { #define MCP4822_PIO_GAIN_1X 0xE001 // set pins, 1 #define MCP4822_PIO_GAIN_2X 0xE000 // set pins, 0 -void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, +void mcp4822_reset(void) { +} + +// Caller validates that pins are free. +void common_hal_mcp4822_mcp4822_construct(mcp4822_mcp4822_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *cs, uint8_t gain) { - // SET pins span from MOSI to CS. MOSI must have a lower GPIO number - // than CS, with at most 4 pins between them (SET count max is 5). + // The SET pin group spans from MOSI to CS. + // MOSI must have a lower GPIO number than CS, gap at most 4. if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { mp_raise_ValueError( - MP_COMPRESSED_ROM_TEXT("cs pin must be 1-4 positions above mosi pin")); + MP_ERROR_TEXT("cs pin must be 1-4 positions above mosi pin")); } uint8_t set_count = cs->number - mosi->number + 1; @@ -197,26 +195,26 @@ void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, audio_dma_init(&self->dma); } -bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self) { +bool common_hal_mcp4822_mcp4822_deinited(mcp4822_mcp4822_obj_t *self) { return common_hal_rp2pio_statemachine_deinited(&self->state_machine); } -void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self) { - if (common_hal_mtm_hardware_dacout_deinited(self)) { +void common_hal_mcp4822_mcp4822_deinit(mcp4822_mcp4822_obj_t *self) { + if (common_hal_mcp4822_mcp4822_deinited(self)) { return; } - if (common_hal_mtm_hardware_dacout_get_playing(self)) { - common_hal_mtm_hardware_dacout_stop(self); + if (common_hal_mcp4822_mcp4822_get_playing(self)) { + common_hal_mcp4822_mcp4822_stop(self); } common_hal_rp2pio_statemachine_deinit(&self->state_machine); audio_dma_deinit(&self->dma); } -void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, +void common_hal_mcp4822_mcp4822_play(mcp4822_mcp4822_obj_t *self, mp_obj_t sample, bool loop) { - if (common_hal_mtm_hardware_dacout_get_playing(self)) { - common_hal_mtm_hardware_dacout_stop(self); + if (common_hal_mcp4822_mcp4822_get_playing(self)) { + common_hal_mcp4822_mcp4822_stop(self); } uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); @@ -227,7 +225,7 @@ void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, uint32_t sample_rate = audiosample_get_sample_rate(sample); uint8_t channel_count = audiosample_get_channel_count(sample); if (channel_count > 2) { - mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("Too many channels in sample.")); + mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample.")); } // PIO clock = sample_rate × clocks_per_sample @@ -236,10 +234,6 @@ void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, (uint32_t)sample_rate * MCP4822_CLOCKS_PER_SAMPLE); common_hal_rp2pio_statemachine_restart(&self->state_machine); - // DMA feeds unsigned 16-bit samples. The PIO discards the top 4 bits - // of each 16-bit half and uses the remaining 12 as DAC data. - // RP2040 narrow-write replication: 16-bit DMA write → same value in - // both 32-bit FIFO halves → mono-to-stereo for free. audio_dma_result result = audio_dma_setup_playback( &self->dma, sample, @@ -253,41 +247,41 @@ void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, false); // swap_channel if (result == AUDIO_DMA_DMA_BUSY) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("No DMA channel found")); + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("No DMA channel found")); } else if (result == AUDIO_DMA_MEMORY_ERROR) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Unable to allocate buffers for signed conversion")); + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to allocate buffers for signed conversion")); } else if (result == AUDIO_DMA_SOURCE_ERROR) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Audio source error")); + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("Audio source error")); } self->playing = true; } -void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self) { +void common_hal_mcp4822_mcp4822_pause(mcp4822_mcp4822_obj_t *self) { audio_dma_pause(&self->dma); } -void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self) { +void common_hal_mcp4822_mcp4822_resume(mcp4822_mcp4822_obj_t *self) { audio_dma_resume(&self->dma); } -bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self) { +bool common_hal_mcp4822_mcp4822_get_paused(mcp4822_mcp4822_obj_t *self) { return audio_dma_get_paused(&self->dma); } -void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self) { +void common_hal_mcp4822_mcp4822_stop(mcp4822_mcp4822_obj_t *self) { audio_dma_stop(&self->dma); common_hal_rp2pio_statemachine_stop(&self->state_machine); self->playing = false; } -bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self) { +bool common_hal_mcp4822_mcp4822_get_playing(mcp4822_mcp4822_obj_t *self) { bool playing = audio_dma_get_playing(&self->dma); if (!playing && self->playing) { - common_hal_mtm_hardware_dacout_stop(self); + common_hal_mcp4822_mcp4822_stop(self); } return playing; } diff --git a/ports/raspberrypi/common-hal/mcp4822/MCP4822.h b/ports/raspberrypi/common-hal/mcp4822/MCP4822.h new file mode 100644 index 00000000000..53c8e862b63 --- /dev/null +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/rp2pio/StateMachine.h" + +#include "audio_dma.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + rp2pio_statemachine_obj_t state_machine; + audio_dma_t dma; + bool playing; +} mcp4822_mcp4822_obj_t; + +void mcp4822_reset(void); diff --git a/ports/raspberrypi/common-hal/mcp4822/__init__.c b/ports/raspberrypi/common-hal/mcp4822/__init__.c new file mode 100644 index 00000000000..48981fc88a7 --- /dev/null +++ b/ports/raspberrypi/common-hal/mcp4822/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +// No module-level init needed. diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 8401c5d7545..30fc75c106b 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -16,6 +16,7 @@ CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 CIRCUITPY_IMAGECAPTURE ?= 1 CIRCUITPY_MAX3421E ?= 0 +CIRCUITPY_MCP4822 ?= 0 CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_PWMIO ?= 1 CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_DISPLAYIO) diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 886ba96f3e5..14c8c52802e 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -288,6 +288,9 @@ endif ifeq ($(CIRCUITPY_MAX3421E),1) SRC_PATTERNS += max3421e/% endif +ifeq ($(CIRCUITPY_MCP4822),1) +SRC_PATTERNS += mcp4822/% +endif ifeq ($(CIRCUITPY_MDNS),1) SRC_PATTERNS += mdns/% endif @@ -532,6 +535,8 @@ SRC_COMMON_HAL_ALL = \ i2ctarget/I2CTarget.c \ i2ctarget/__init__.c \ max3421e/Max3421E.c \ + mcp4822/__init__.c \ + mcp4822/MCP4822.c \ memorymap/__init__.c \ memorymap/AddressRange.c \ microcontroller/__init__.c \ diff --git a/shared-bindings/mcp4822/MCP4822.c b/shared-bindings/mcp4822/MCP4822.c new file mode 100644 index 00000000000..c48f5426e66 --- /dev/null +++ b/shared-bindings/mcp4822/MCP4822.c @@ -0,0 +1,247 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/mcp4822/MCP4822.h" +#include "shared-bindings/util.h" + +//| class MCP4822: +//| """Output audio to an MCP4822 dual-channel 12-bit SPI DAC.""" +//| +//| def __init__( +//| self, +//| clock: microcontroller.Pin, +//| mosi: microcontroller.Pin, +//| cs: microcontroller.Pin, +//| *, +//| gain: int = 1, +//| ) -> None: +//| """Create an MCP4822 object associated with the given SPI pins. +//| +//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin +//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin +//| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. +//| +//| Simple 8ksps 440 Hz sine wave:: +//| +//| import mcp4822 +//| import audiocore +//| import board +//| import array +//| import time +//| import math +//| +//| length = 8000 // 440 +//| sine_wave = array.array("H", [0] * length) +//| for i in range(length): +//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) +//| +//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) +//| dac = mcp4822.MCP4822(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(sine_wave, loop=True) +//| time.sleep(1) +//| dac.stop() +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audiocore +//| import mcp4822 +//| +//| f = open("sound.wav", "rb") +//| wav = audiocore.WaveFile(f) +//| +//| dac = mcp4822.MCP4822(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(wav) +//| while dac.playing: +//| pass""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + + mp_int_t gain = args[ARG_gain].u_int; + if (gain != 1 && gain != 2) { + mp_raise_ValueError(MP_ERROR_TEXT("gain must be 1 or 2")); + } + + mcp4822_mcp4822_obj_t *self = mp_obj_malloc_with_finaliser(mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); + common_hal_mcp4822_mcp4822_construct(self, clock, mosi, cs, (uint8_t)gain); + + return MP_OBJ_FROM_PTR(self); +} + +static void check_for_deinit(mcp4822_mcp4822_obj_t *self) { + if (common_hal_mcp4822_mcp4822_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Deinitialises the MCP4822 and releases any hardware resources for reuse.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_deinit(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_mcp4822_mcp4822_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_deinit_obj, mcp4822_mcp4822_deinit); + +//| def __enter__(self) -> MCP4822: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. +//| +//| The sample itself should consist of 8 bit or 16 bit samples.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_mcp4822_mcp4822_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mcp4822_mcp4822_play_obj, 1, mcp4822_mcp4822_obj_play); + +//| def stop(self) -> None: +//| """Stops playback.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_stop(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_mcp4822_mcp4822_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_stop_obj, mcp4822_mcp4822_obj_stop); + +//| playing: bool +//| """True when the audio sample is being output. (read-only)""" +//| +static mp_obj_t mcp4822_mcp4822_obj_get_playing(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mcp4822_mcp4822_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_get_playing_obj, mcp4822_mcp4822_obj_get_playing); + +MP_PROPERTY_GETTER(mcp4822_mcp4822_playing_obj, + (mp_obj_t)&mcp4822_mcp4822_get_playing_obj); + +//| def pause(self) -> None: +//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_pause(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (!common_hal_mcp4822_mcp4822_get_playing(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Not playing")); + } + common_hal_mcp4822_mcp4822_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_pause_obj, mcp4822_mcp4822_obj_pause); + +//| def resume(self) -> None: +//| """Resumes sample playback after :py:func:`pause`.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_resume(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (common_hal_mcp4822_mcp4822_get_paused(self)) { + common_hal_mcp4822_mcp4822_resume(self); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_resume_obj, mcp4822_mcp4822_obj_resume); + +//| paused: bool +//| """True when playback is paused. (read-only)""" +//| +//| +static mp_obj_t mcp4822_mcp4822_obj_get_paused(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mcp4822_mcp4822_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_get_paused_obj, mcp4822_mcp4822_obj_get_paused); + +MP_PROPERTY_GETTER(mcp4822_mcp4822_paused_obj, + (mp_obj_t)&mcp4822_mcp4822_get_paused_obj); + +static const mp_rom_map_elem_t mcp4822_mcp4822_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mcp4822_mcp4822_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mcp4822_mcp4822_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mcp4822_mcp4822_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mcp4822_mcp4822_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mcp4822_mcp4822_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mcp4822_mcp4822_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mcp4822_mcp4822_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mcp4822_mcp4822_paused_obj) }, +}; +static MP_DEFINE_CONST_DICT(mcp4822_mcp4822_locals_dict, mcp4822_mcp4822_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mcp4822_mcp4822_type, + MP_QSTR_MCP4822, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, mcp4822_mcp4822_make_new, + locals_dict, &mcp4822_mcp4822_locals_dict + ); diff --git a/shared-bindings/mcp4822/MCP4822.h b/shared-bindings/mcp4822/MCP4822.h new file mode 100644 index 00000000000..b129aec3061 --- /dev/null +++ b/shared-bindings/mcp4822/MCP4822.h @@ -0,0 +1,25 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/mcp4822/MCP4822.h" +#include "common-hal/microcontroller/Pin.h" + +extern const mp_obj_type_t mcp4822_mcp4822_type; + +void common_hal_mcp4822_mcp4822_construct(mcp4822_mcp4822_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs, uint8_t gain); + +void common_hal_mcp4822_mcp4822_deinit(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_deinited(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_play(mcp4822_mcp4822_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_mcp4822_mcp4822_stop(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_get_playing(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_pause(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_resume(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_get_paused(mcp4822_mcp4822_obj_t *self); diff --git a/shared-bindings/mcp4822/__init__.c b/shared-bindings/mcp4822/__init__.c new file mode 100644 index 00000000000..bac2136d9e7 --- /dev/null +++ b/shared-bindings/mcp4822/__init__.c @@ -0,0 +1,36 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/mcp4822/__init__.h" +#include "shared-bindings/mcp4822/MCP4822.h" + +//| """Audio output via MCP4822 dual-channel 12-bit SPI DAC. +//| +//| The `mcp4822` module provides the `MCP4822` class for non-blocking +//| audio playback through the Microchip MCP4822 SPI DAC using PIO and DMA. +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed. To do so, either call :py:meth:`!deinit` or use a +//| context manager.""" + +static const mp_rom_map_elem_t mcp4822_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mcp4822) }, + { MP_ROM_QSTR(MP_QSTR_MCP4822), MP_ROM_PTR(&mcp4822_mcp4822_type) }, +}; + +static MP_DEFINE_CONST_DICT(mcp4822_module_globals, mcp4822_module_globals_table); + +const mp_obj_module_t mcp4822_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mcp4822_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_mcp4822, mcp4822_module); diff --git a/shared-bindings/mcp4822/__init__.h b/shared-bindings/mcp4822/__init__.h new file mode 100644 index 00000000000..c4a52e5819d --- /dev/null +++ b/shared-bindings/mcp4822/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once From 3b9eaf9f2788ecbbc12d0c0cdbe6f2ee7eb04cc0 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Sat, 21 Mar 2026 10:13:02 -0700 Subject: [PATCH 315/876] mtm_computer: Add DAC audio out module --- .../boards/mtm_computer/module/DACOut.c | 276 ++++++++++++++++++ .../boards/mtm_computer/module/DACOut.h | 38 +++ .../boards/mtm_computer/mpconfigboard.mk | 4 + 3 files changed, 318 insertions(+) create mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.c create mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.h diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c new file mode 100644 index 00000000000..84f4296cb00 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c @@ -0,0 +1,276 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT +// +// MCP4822 dual-channel 12-bit SPI DAC driver for the MTM Workshop Computer. +// Uses PIO + DMA for non-blocking audio playback, mirroring audiobusio.I2SOut. + +#include +#include + +#include "mpconfigport.h" + +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "boards/mtm_computer/module/DACOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" +#include "bindings/rp2pio/StateMachine.h" + +// ───────────────────────────────────────────────────────────────────────────── +// PIO program for MCP4822 SPI DAC +// ───────────────────────────────────────────────────────────────────────────── +// +// Pin assignment: +// OUT pin (1) = MOSI — serial data out +// SET pins (N) = MOSI through CS — for CS control & command-bit injection +// SIDE-SET pin (1) = SCK — serial clock +// +// On the MTM Workshop Computer: MOSI=GP19, CS=GP21, SCK=GP18. +// The SET group spans GP19..GP21 (3 pins). GP20 is unused and driven low. +// +// SET PINS bit mapping (bit0=MOSI/GP19, bit1=GP20, bit2=CS/GP21): +// 0 = CS low, MOSI low 1 = CS low, MOSI high 4 = CS high, MOSI low +// +// SIDE-SET (1 pin, SCK): side 0 = SCK low, side 1 = SCK high +// +// MCP4822 16-bit command word: +// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x) +// [12] output enable (1) [11:0] 12-bit data +// +// DMA feeds unsigned 16-bit audio samples. RP2040 narrow-write replication +// fills both halves of the 32-bit PIO FIFO entry with the same value, +// giving mono→stereo for free. +// +// The PIO pulls 32 bits, then sends two SPI transactions: +// Channel A: cmd nibble 0b0011, then all 16 sample bits from upper half-word +// Channel B: cmd nibble 0b1011, then all 16 sample bits from lower half-word +// The MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data), +// so only the top 12 of the 16 sample bits become DAC data. The bottom +// 4 sample bits clock out harmlessly after the DAC has latched. +// This gives correct 16-bit → 12-bit scaling (effectively sample >> 4). +// +// PIO instruction encoding with .side_set 1 (no opt): +// [15:13] opcode [12] side-set [11:8] delay [7:0] operands +// +// Total: 26 instructions, 86 PIO clocks per audio sample. +// ───────────────────────────────────────────────────────────────────────────── + +static const uint16_t mcp4822_pio_program[] = { + // side SCK + // 0: pull noblock side 0 ; Get 32 bits or keep X if FIFO empty + 0x8080, + // 1: mov x, osr side 0 ; Save for pull-noblock fallback + 0xA027, + + // ── Channel A: command nibble 0b0011 ────────────────────────────────── + // Send 4 cmd bits via SET, then all 16 sample bits via OUT. + // MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data); + // the extra 4 clocks shift out the LSBs which the DAC ignores. + // This gives correct 16→12 bit scaling (top 12 bits become DAC data). + // 2: set pins, 0 side 0 ; CS low, MOSI=0 (bit15=0: channel A) + 0xE000, + // 3: nop side 1 ; SCK high — latch bit 15 + 0xB042, + // 4: set pins, 0 side 0 ; MOSI=0 (bit14=0: don't care) + 0xE000, + // 5: nop side 1 ; SCK high + 0xB042, + // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + 0xE001, + // 7: nop side 1 ; SCK high + 0xB042, + // 8: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) + 0xE001, + // 9: nop side 1 ; SCK high + 0xB042, + // 10: set y, 15 side 0 ; Loop counter: 16 sample bits + 0xE04F, + // 11: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopA) + 0x6001, + // 12: jmp y--, 11 side 1 ; SCK high, loop back + 0x108B, + // 13: set pins, 4 side 0 ; CS high — DAC A latches + 0xE004, + + // ── Channel B: command nibble 0b1011 ────────────────────────────────── + // 14: set pins, 1 side 0 ; CS low, MOSI=1 (bit15=1: channel B) + 0xE001, + // 15: nop side 1 ; SCK high + 0xB042, + // 16: set pins, 0 side 0 ; MOSI=0 (bit14=0) + 0xE000, + // 17: nop side 1 ; SCK high + 0xB042, + // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + 0xE001, + // 19: nop side 1 ; SCK high + 0xB042, + // 20: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) + 0xE001, + // 21: nop side 1 ; SCK high + 0xB042, + // 22: set y, 15 side 0 ; Loop counter: 16 sample bits + 0xE04F, + // 23: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopB) + 0x6001, + // 24: jmp y--, 23 side 1 ; SCK high, loop back + 0x1097, + // 25: set pins, 4 side 0 ; CS high — DAC B latches + 0xE004, +}; + +// Clocks per sample: 2 (pull+mov) + 42 (chanA) + 42 (chanB) = 86 +// Per channel: 8(4 cmd bits × 2 clks) + 1(set y) + 32(16 bits × 2 clks) + 1(cs high) = 42 +#define MCP4822_CLOCKS_PER_SAMPLE 86 + + +void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs) { + + // SET pins span from MOSI to CS. MOSI must have a lower GPIO number + // than CS, with at most 4 pins between them (SET count max is 5). + if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { + mp_raise_ValueError( + MP_COMPRESSED_ROM_TEXT("cs pin must be 1-4 positions above mosi pin")); + } + + uint8_t set_count = cs->number - mosi->number + 1; + + // Initial SET pin state: CS high (bit at CS position), others low + uint32_t cs_bit_position = cs->number - mosi->number; + pio_pinmask32_t initial_set_state = PIO_PINMASK32_FROM_VALUE(1u << cs_bit_position); + pio_pinmask32_t initial_set_dir = PIO_PINMASK32_FROM_VALUE((1u << set_count) - 1); + + common_hal_rp2pio_statemachine_construct( + &self->state_machine, + mcp4822_pio_program, MP_ARRAY_SIZE(mcp4822_pio_program), + 44100 * MCP4822_CLOCKS_PER_SAMPLE, // Initial frequency; play() adjusts + NULL, 0, // No init program + NULL, 0, // No may_exec + mosi, 1, // OUT: MOSI, 1 pin + PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // OUT state=low, dir=output + NULL, 0, // IN: none + PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // IN pulls: none + mosi, set_count, // SET: MOSI..CS + initial_set_state, initial_set_dir, // SET state (CS high), dir=output + clock, 1, false, // SIDE-SET: SCK, 1 pin, not pindirs + PIO_PINMASK32_NONE, // SIDE-SET state: SCK low + PIO_PINMASK32_FROM_VALUE(0x1), // SIDE-SET dir: output + false, // No sideset enable + NULL, PULL_NONE, // No jump pin + PIO_PINMASK_NONE, // No wait GPIO + true, // Exclusive pin use + false, 32, false, // OUT shift: no autopull, 32-bit, shift left + false, // Don't wait for txstall + false, 32, false, // IN shift (unused) + false, // Not user-interruptible + 0, -1, // Wrap: whole program + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, + PIO_MOV_N_DEFAULT + ); + + self->playing = false; + audio_dma_init(&self->dma); +} + +bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self) { + return common_hal_rp2pio_statemachine_deinited(&self->state_machine); +} + +void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self) { + if (common_hal_mtm_hardware_dacout_deinited(self)) { + return; + } + if (common_hal_mtm_hardware_dacout_get_playing(self)) { + common_hal_mtm_hardware_dacout_stop(self); + } + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + audio_dma_deinit(&self->dma); +} + +void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, + mp_obj_t sample, bool loop) { + + if (common_hal_mtm_hardware_dacout_get_playing(self)) { + common_hal_mtm_hardware_dacout_stop(self); + } + + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); + if (bits_per_sample < 16) { + bits_per_sample = 16; + } + + uint32_t sample_rate = audiosample_get_sample_rate(sample); + uint8_t channel_count = audiosample_get_channel_count(sample); + if (channel_count > 2) { + mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("Too many channels in sample.")); + } + + // PIO clock = sample_rate × clocks_per_sample + common_hal_rp2pio_statemachine_set_frequency( + &self->state_machine, + (uint32_t)sample_rate * MCP4822_CLOCKS_PER_SAMPLE); + common_hal_rp2pio_statemachine_restart(&self->state_machine); + + // DMA feeds unsigned 16-bit samples. The PIO discards the top 4 bits + // of each 16-bit half and uses the remaining 12 as DAC data. + // RP2040 narrow-write replication: 16-bit DMA write → same value in + // both 32-bit FIFO halves → mono-to-stereo for free. + audio_dma_result result = audio_dma_setup_playback( + &self->dma, + sample, + loop, + false, // single_channel_output + 0, // audio_channel + false, // output_signed = false (unsigned for MCP4822) + bits_per_sample, // output_resolution + (uint32_t)&self->state_machine.pio->txf[self->state_machine.state_machine], + self->state_machine.tx_dreq, + false); // swap_channel + + if (result == AUDIO_DMA_DMA_BUSY) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("No DMA channel found")); + } else if (result == AUDIO_DMA_MEMORY_ERROR) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Unable to allocate buffers for signed conversion")); + } else if (result == AUDIO_DMA_SOURCE_ERROR) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Audio source error")); + } + + self->playing = true; +} + +void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self) { + audio_dma_pause(&self->dma); +} + +void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self) { + audio_dma_resume(&self->dma); +} + +bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self) { + return audio_dma_get_paused(&self->dma); +} + +void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self) { + audio_dma_stop(&self->dma); + common_hal_rp2pio_statemachine_stop(&self->state_machine); + self->playing = false; +} + +bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self) { + bool playing = audio_dma_get_playing(&self->dma); + if (!playing && self->playing) { + common_hal_mtm_hardware_dacout_stop(self); + } + return playing; +} diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h new file mode 100644 index 00000000000..f7c0c9eb806 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/rp2pio/StateMachine.h" + +#include "audio_dma.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + rp2pio_statemachine_obj_t state_machine; + audio_dma_t dma; + bool playing; +} mtm_hardware_dacout_obj_t; + +void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs); + +void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); + +void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, + mp_obj_t sample, bool loop); +void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self); + +void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self); +void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self); + +extern const mp_obj_type_t mtm_hardware_dacout_type; diff --git a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk index 718c393d168..74d9baac879 100644 --- a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk +++ b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk @@ -11,3 +11,7 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_AUDIOEFFECTS = 1 CIRCUITPY_IMAGECAPTURE = 0 CIRCUITPY_PICODVI = 0 + +SRC_C += \ + boards/$(BOARD)/module/mtm_hardware.c \ + boards/$(BOARD)/module/DACOut.c From f63ea5c6fdfb31bd2be26b4a202ce189a16df37e Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Sat, 21 Mar 2026 10:33:40 -0700 Subject: [PATCH 316/876] mtm_hardware.c added --- .../boards/mtm_computer/module/mtm_hardware.c | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c new file mode 100644 index 00000000000..a3dafbcf941 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c @@ -0,0 +1,267 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT +// +// Python bindings for the mtm_hardware module. +// Provides DACOut: a non-blocking audio player for the MCP4822 SPI DAC. + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "boards/mtm_computer/module/DACOut.h" + +// ───────────────────────────────────────────────────────────────────────────── +// DACOut class +// ───────────────────────────────────────────────────────────────────────────── + +//| class DACOut: +//| """Output audio to the MCP4822 dual-channel 12-bit SPI DAC.""" +//| +//| def __init__( +//| self, +//| clock: microcontroller.Pin, +//| mosi: microcontroller.Pin, +//| cs: microcontroller.Pin, +//| ) -> None: +//| """Create a DACOut object associated with the given SPI pins. +//| +//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin +//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin +//| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| +//| Simple 8ksps 440 Hz sine wave:: +//| +//| import mtm_hardware +//| import audiocore +//| import board +//| import array +//| import time +//| import math +//| +//| length = 8000 // 440 +//| sine_wave = array.array("H", [0] * length) +//| for i in range(length): +//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) +//| +//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) +//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(sine_wave, loop=True) +//| time.sleep(1) +//| dac.stop() +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audiocore +//| import mtm_hardware +//| +//| f = open("sound.wav", "rb") +//| wav = audiocore.WaveFile(f) +//| +//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(wav) +//| while dac.playing: +//| pass""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_clock, ARG_mosi, ARG_cs }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + + mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); + common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs); + + return MP_OBJ_FROM_PTR(self); +} + +static void check_for_deinit(mtm_hardware_dacout_obj_t *self) { + if (common_hal_mtm_hardware_dacout_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Deinitialises the DACOut and releases any hardware resources for reuse.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_deinit(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_mtm_hardware_dacout_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_deinit_obj, mtm_hardware_dacout_deinit); + +//| def __enter__(self) -> DACOut: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. +//| +//| The sample itself should consist of 8 bit or 16 bit samples.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_mtm_hardware_dacout_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mtm_hardware_dacout_play_obj, 1, mtm_hardware_dacout_obj_play); + +//| def stop(self) -> None: +//| """Stops playback.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_stop(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_mtm_hardware_dacout_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_stop_obj, mtm_hardware_dacout_obj_stop); + +//| playing: bool +//| """True when the audio sample is being output. (read-only)""" +//| +static mp_obj_t mtm_hardware_dacout_obj_get_playing(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_playing_obj, mtm_hardware_dacout_obj_get_playing); + +MP_PROPERTY_GETTER(mtm_hardware_dacout_playing_obj, + (mp_obj_t)&mtm_hardware_dacout_get_playing_obj); + +//| def pause(self) -> None: +//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_pause(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (!common_hal_mtm_hardware_dacout_get_playing(self)) { + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Not playing")); + } + common_hal_mtm_hardware_dacout_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_pause_obj, mtm_hardware_dacout_obj_pause); + +//| def resume(self) -> None: +//| """Resumes sample playback after :py:func:`pause`.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_resume(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_mtm_hardware_dacout_get_paused(self)) { + common_hal_mtm_hardware_dacout_resume(self); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_resume_obj, mtm_hardware_dacout_obj_resume); + +//| paused: bool +//| """True when playback is paused. (read-only)""" +//| +static mp_obj_t mtm_hardware_dacout_obj_get_paused(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_paused_obj, mtm_hardware_dacout_obj_get_paused); + +MP_PROPERTY_GETTER(mtm_hardware_dacout_paused_obj, + (mp_obj_t)&mtm_hardware_dacout_get_paused_obj); + +// ── DACOut type definition ─────────────────────────────────────────────────── + +static const mp_rom_map_elem_t mtm_hardware_dacout_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mtm_hardware_dacout_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mtm_hardware_dacout_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mtm_hardware_dacout_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mtm_hardware_dacout_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mtm_hardware_dacout_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mtm_hardware_dacout_paused_obj) }, +}; +static MP_DEFINE_CONST_DICT(mtm_hardware_dacout_locals_dict, mtm_hardware_dacout_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mtm_hardware_dacout_type, + MP_QSTR_DACOut, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, mtm_hardware_dacout_make_new, + locals_dict, &mtm_hardware_dacout_locals_dict + ); + +// ───────────────────────────────────────────────────────────────────────────── +// mtm_hardware module definition +// ───────────────────────────────────────────────────────────────────────────── + +//| """Hardware interface to Music Thing Modular Workshop Computer peripherals. +//| +//| Provides the `DACOut` class for non-blocking audio output via the +//| MCP4822 dual-channel 12-bit SPI DAC. +//| """ + +static const mp_rom_map_elem_t mtm_hardware_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mtm_hardware) }, + { MP_ROM_QSTR(MP_QSTR_DACOut), MP_ROM_PTR(&mtm_hardware_dacout_type) }, +}; + +static MP_DEFINE_CONST_DICT(mtm_hardware_module_globals, mtm_hardware_module_globals_table); + +const mp_obj_module_t mtm_hardware_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mtm_hardware_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_mtm_hardware, mtm_hardware_module); From c7fc0c07a78ad14a213fd307036682d92926756d Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 12:58:15 -0700 Subject: [PATCH 317/876] mtm_hardware.dacout: add gain=1 or gain=2 argument --- .../boards/mtm_computer/module/DACOut.c | 21 +++++++++++++++++-- .../boards/mtm_computer/module/DACOut.h | 2 +- .../boards/mtm_computer/module/mtm_hardware.c | 13 ++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c index 84f4296cb00..fb4ce37d4d0 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c @@ -128,9 +128,19 @@ static const uint16_t mcp4822_pio_program[] = { #define MCP4822_CLOCKS_PER_SAMPLE 86 +// MCP4822 gain bit (bit 13) position in the PIO program: +// Instruction 6 = channel A gain bit +// Instruction 18 = channel B gain bit +// 1x gain: set pins, 1 (0xE001) — bit 13 = 1 +// 2x gain: set pins, 0 (0xE000) — bit 13 = 0 +#define MCP4822_PIO_GAIN_INSTR_A 6 +#define MCP4822_PIO_GAIN_INSTR_B 18 +#define MCP4822_PIO_GAIN_1X 0xE001 // set pins, 1 +#define MCP4822_PIO_GAIN_2X 0xE000 // set pins, 0 + void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs) { + const mcu_pin_obj_t *cs, uint8_t gain) { // SET pins span from MOSI to CS. MOSI must have a lower GPIO number // than CS, with at most 4 pins between them (SET count max is 5). @@ -141,6 +151,13 @@ void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, uint8_t set_count = cs->number - mosi->number + 1; + // Build a mutable copy of the PIO program and patch the gain bit + uint16_t program[MP_ARRAY_SIZE(mcp4822_pio_program)]; + memcpy(program, mcp4822_pio_program, sizeof(mcp4822_pio_program)); + uint16_t gain_instr = (gain == 2) ? MCP4822_PIO_GAIN_2X : MCP4822_PIO_GAIN_1X; + program[MCP4822_PIO_GAIN_INSTR_A] = gain_instr; + program[MCP4822_PIO_GAIN_INSTR_B] = gain_instr; + // Initial SET pin state: CS high (bit at CS position), others low uint32_t cs_bit_position = cs->number - mosi->number; pio_pinmask32_t initial_set_state = PIO_PINMASK32_FROM_VALUE(1u << cs_bit_position); @@ -148,7 +165,7 @@ void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, common_hal_rp2pio_statemachine_construct( &self->state_machine, - mcp4822_pio_program, MP_ARRAY_SIZE(mcp4822_pio_program), + program, MP_ARRAY_SIZE(mcp4822_pio_program), 44100 * MCP4822_CLOCKS_PER_SAMPLE, // Initial frequency; play() adjusts NULL, 0, // No init program NULL, 0, // No may_exec diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h index f7c0c9eb806..f9b5dd60108 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h @@ -21,7 +21,7 @@ typedef struct { void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs); + const mcu_pin_obj_t *cs, uint8_t gain); void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c index a3dafbcf941..8f875496f67 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c +++ b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c @@ -29,12 +29,15 @@ //| clock: microcontroller.Pin, //| mosi: microcontroller.Pin, //| cs: microcontroller.Pin, +//| *, +//| gain: int = 1, //| ) -> None: //| """Create a DACOut object associated with the given SPI pins. //| //| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin //| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin //| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. //| //| Simple 8ksps 440 Hz sine wave:: //| @@ -72,11 +75,12 @@ //| ... //| static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_clock, ARG_mosi, ARG_cs }; + enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -85,8 +89,13 @@ static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + mp_int_t gain = args[ARG_gain].u_int; + if (gain != 1 && gain != 2) { + mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("gain must be 1 or 2")); + } + mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); - common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs); + common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs, (uint8_t)gain); return MP_OBJ_FROM_PTR(self); } From 2e4fc89120625dfeb6acabd229eba7e36664c4a5 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 16:42:55 -0700 Subject: [PATCH 318/876] rework mcp4822 module from mtm_hardware.DACOut --- locale/circuitpython.pot | 4579 ----------------- ports/raspberrypi/boards/mtm_computer/board.c | 19 + .../boards/mtm_computer/module/DACOut.h | 38 - .../boards/mtm_computer/module/mtm_hardware.c | 276 - .../boards/mtm_computer/mpconfigboard.mk | 5 +- ports/raspberrypi/boards/mtm_computer/pins.c | 6 +- .../DACOut.c => common-hal/mcp4822/MCP4822.c} | 90 +- .../raspberrypi/common-hal/mcp4822/MCP4822.h | 22 + .../raspberrypi/common-hal/mcp4822/__init__.c | 7 + ports/raspberrypi/mpconfigport.mk | 1 + py/circuitpy_defns.mk | 5 + shared-bindings/mcp4822/MCP4822.c | 247 + shared-bindings/mcp4822/MCP4822.h | 25 + shared-bindings/mcp4822/__init__.c | 36 + shared-bindings/mcp4822/__init__.h | 7 + 15 files changed, 417 insertions(+), 4946 deletions(-) delete mode 100644 locale/circuitpython.pot delete mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.h delete mode 100644 ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c rename ports/raspberrypi/{boards/mtm_computer/module/DACOut.c => common-hal/mcp4822/MCP4822.c} (75%) create mode 100644 ports/raspberrypi/common-hal/mcp4822/MCP4822.h create mode 100644 ports/raspberrypi/common-hal/mcp4822/__init__.c create mode 100644 shared-bindings/mcp4822/MCP4822.c create mode 100644 shared-bindings/mcp4822/MCP4822.h create mode 100644 shared-bindings/mcp4822/__init__.c create mode 100644 shared-bindings/mcp4822/__init__.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot deleted file mode 100644 index bf4c5d110f6..00000000000 --- a/locale/circuitpython.pot +++ /dev/null @@ -1,4579 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=CHARSET\n" -"Content-Transfer-Encoding: 8bit\n" - -#: main.c -msgid "" -"\n" -"Code done running.\n" -msgstr "" - -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" -msgstr "" - -#: py/obj.c -msgid " File \"%q\"" -msgstr "" - -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr "" - -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr "" - -#: main.c -msgid " not found.\n" -msgstr "" - -#: main.c -msgid " output:\n" -msgstr "" - -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" -msgstr "" - -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "" - -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" -msgstr "" - -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" -msgstr "" - -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" -msgstr "" - -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" - -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "" - -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "" - -#: py/objstr.c -msgid "%q index out of range" -msgstr "" - -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q init failed" -msgstr "" - -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "" - -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "" - -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "" - -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "" - -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "" - -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "" - -#: py/argcheck.c -msgid "%q must be %d" -msgstr "" - -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "" - -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "" - -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "" - -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "" - -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "" - -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "" - -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "" - -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "" - -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." -msgstr "" - -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "" - -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" -msgstr "" - -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "" - -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" -msgstr "" - -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "" - -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "" - -#: shared-module/bitbangio/I2C.c -msgid "%q too long" -msgstr "" - -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" -msgstr "" - -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "" - -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "" - -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "" - -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" -msgstr "" - -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "" - -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" -msgstr "" - -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "" - -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "" - -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "" - -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "" - -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "" - -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "" - -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "" - -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "" - -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "" - -#: py/compile.c -msgid "'await' outside function" -msgstr "" - -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "" - -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "" - -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "" - -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "" - -#: py/emitnative.c -msgid "'not' not implemented" -msgstr "" - -#: py/compile.c -msgid "'return' outside function" -msgstr "" - -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "" - -#: py/compile.c -msgid "'yield' outside function" -msgstr "" - -#: py/compile.c -msgid "* arg after **" -msgstr "" - -#: py/compile.c -msgid "*x must be assignment target" -msgstr "" - -#: py/obj.c -msgid ", in %q\n" -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" -msgstr "" - -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "" - -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "" - -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "" - -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "" - -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "" - -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "" - -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "" - -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "" - -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "" - -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "" - -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" -msgstr "" - -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "" - -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "" - -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" -msgstr "" - -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "" - -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "" - -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "" - -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "" - -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "" - -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" - -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "" - -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Audio source error" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "" - -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "" - -#: main.c -msgid "Auto-reload is off.\n" -msgstr "" - -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "" - -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "" - -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" -msgstr "" - -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "" - -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "" - -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "" - -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "" - -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "" - -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "" - -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" -msgstr "" - -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "" - -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "" - -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "Cannot record to a file" -msgstr "" - -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." -msgstr "" - -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." -msgstr "" - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "" - -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" - -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" -msgstr "" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." -msgstr "" - -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "" - -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" -msgstr "" - -#: shared-module/usb/core/Device.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Could not allocate DMA capable buffer" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "" - -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" -msgstr "" - -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" -msgstr "" - -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Device Init Error" -msgstr "" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "" - -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" -msgstr "" - -#: main.c -msgid "Done" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." -msgstr "" - -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "" - -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" -msgstr "" - -#: extmod/modre.c -msgid "Error in regex" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "" - -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "" - -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "" - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "" - -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" -msgstr "" - -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "" - -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" -msgstr "" - -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" -msgstr "" - -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "" - -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" -msgstr "" - -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" -msgstr "" - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" -msgstr "" - -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "" - -#: py/moderrno.c -msgid "File exists" -msgstr "" - -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" -msgstr "" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" -msgstr "" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "" - -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "" - -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" -msgstr "" - -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "" - -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" -msgstr "" - -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "" - -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." -msgstr "" - -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "" - -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "" - -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "" - -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "" - -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "" - -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "" - -#: py/moderrno.c -msgid "Input/output error" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "" - -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "" - -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: shared-bindings/pwmio/PWMOut.c supervisor/shared/settings.c -msgid "Internal error" -msgstr "" - -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" -msgstr "" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/espressif/common-hal/mipidsi/Display.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c -#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "" - -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" -msgstr "" - -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "" - -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" -msgstr "" - -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "" - -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" -msgstr "" - -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "" - -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "" - -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "" - -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "" - -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "" - -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "" - -#: py/compile.c -msgid "LHS of keyword arg must be an id" -msgstr "" - -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "" - -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "" - -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" -msgstr "" - -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" -msgstr "" - -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "" - -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "" - -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" -msgstr "" - -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "" - -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" -msgstr "" - -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." -msgstr "" - -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "" - -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" -msgstr "" - -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" -msgstr "" - -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c -#: shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "" - -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -msgid "No DAC on chip" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA channel found" -msgstr "" - -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" -msgstr "" - -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" -msgstr "" - -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "" - -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" -msgstr "" - -#: shared-module/usb/core/Device.c -msgid "No configuration set" -msgstr "" - -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" -msgstr "" - -#: shared-bindings/board/__init__.c -msgid "No default %q bus" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "" - -#: shared-bindings/os/__init__.c -msgid "No hardware random available" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" -msgstr "" - -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" -msgstr "" - -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "" - -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" -msgstr "" - -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" -msgstr "" - -#: py/moderrno.c -msgid "No space left on device" -msgstr "" - -#: py/moderrno.c -msgid "No such device" -msgstr "" - -#: py/moderrno.c -msgid "No such file/directory" -msgstr "" - -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" -msgstr "" - -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" -msgstr "" - -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" -msgstr "" - -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c -msgid "Not playing" -msgstr "" - -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" - -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." -msgstr "" - -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "" - -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" -msgstr "" - -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "" - -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" -msgstr "" - -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" -msgstr "" - -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" -msgstr "" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "" - -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" -msgstr "" - -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." -msgstr "" - -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." -msgstr "" - -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" -msgstr "" - -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" -msgstr "" - -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." -msgstr "" - -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" -msgstr "" - -#: py/moderrno.c -msgid "Operation not permitted" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Operation timed out" -msgstr "" - -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" -msgstr "" - -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "" - -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" -msgstr "" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" -msgstr "" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" -msgstr "" - -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" -msgstr "" - -#: ports/espressif/common-hal/audiobusio/__init__.c -msgid "Peripheral in use" -msgstr "" - -#: py/moderrno.c -msgid "Permission denied" -msgstr "" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" -msgstr "" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" -msgstr "" - -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" -msgstr "" - -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" -msgstr "" - -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" -msgstr "" - -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" -msgstr "" - -#: shared-module/usb/core/Device.c -msgid "Pipe error" -msgstr "" - -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "" - -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" -msgstr "" - -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" -msgstr "" - -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "" - -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" -msgstr "" - -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Pull not used when direction is output." -msgstr "" - -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" -msgstr "" - -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" -msgstr "" - -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" -msgstr "" - -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" -msgstr "" - -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "" - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" -msgstr "" - -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "" - -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "" - -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "" - -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "" - -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "" - -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" -msgstr "" - -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" -msgstr "" - -#: main.c -msgid "Running in safe mode! Not running saved code.\n" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" -msgstr "" - -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" -msgstr "" - -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" -msgstr "" - -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" -msgstr "" - -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" -msgstr "" - -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" -msgstr "" - -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" -msgstr "" - -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" -msgstr "" - -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" -msgstr "" - -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" -msgstr "" - -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" -msgstr "" - -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "" - -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." -msgstr "" - -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" -msgstr "" - -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" -msgstr "" - -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" -msgstr "" - -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." -msgstr "" - -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" -msgstr "" - -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" -msgstr "" - -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." -msgstr "" - -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "" - -#: shared-module/audiocore/__init__.c -msgid "The sample's %q does not match" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." -msgstr "" - -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." -msgstr "" - -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." -msgstr "" - -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "" - -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "" - -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" -msgstr "" - -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" - -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" -msgstr "" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample." -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" -msgstr "" - -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" -msgstr "" - -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "" - -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" -msgstr "" - -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" -msgstr "" - -#: py/obj.c -msgid "Traceback (most recent call last):\n" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" -msgstr "" - -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" -msgstr "" - -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" -msgstr "" - -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "" - -#: main.c -msgid "UID:" -msgstr "" - -#: shared-module/usb_hid/Device.c -msgid "USB busy" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." -msgstr "" - -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "" - -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -msgstr "" - -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" -msgstr "" - -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Unable to allocate buffers for signed conversion" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." -msgstr "" - -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" -msgstr "" - -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" -msgstr "" - -#: py/parse.c -msgid "Unable to init parser" -msgstr "" - -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" -msgstr "" - -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" - -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "" - -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." -msgstr "" - -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "" - -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." -msgstr "" - -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" -msgstr "" - -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" -msgstr "" - -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" -msgstr "" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" -msgstr "" - -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" -msgstr "" - -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." -msgstr "" - -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." -msgstr "" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" -msgstr "" - -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" -msgstr "" - -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" -msgstr "" - -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" -msgstr "" - -#: ports/zephyr-cp/common-hal/busio/I2C.c -#: ports/zephyr-cp/common-hal/busio/SPI.c -#: ports/zephyr-cp/common-hal/busio/UART.c -msgid "Use device tree to define %q devices" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" -msgstr "" - -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" -msgstr "" - -#: main.c -msgid "WARNING: Your code filename has two extensions\n" -msgstr "" - -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" -msgstr "" - -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" -msgstr "" - -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" -msgstr "" - -#: main.c -msgid "Woken up by alarm.\n" -msgstr "" - -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" -msgstr "" - -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." -msgstr "" - -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." -msgstr "" - -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" -msgstr "" - -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." -msgstr "" - -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." -msgstr "" - -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." -msgstr "" - -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." -msgstr "" - -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." -msgstr "" - -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." -msgstr "" - -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." -msgstr "" - -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" -msgstr "" - -#: py/objtype.c -msgid "__init__() should return None" -msgstr "" - -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" -msgstr "" - -#: py/objobject.c -msgid "__new__ arg must be a user-type" -msgstr "" - -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" -msgstr "" - -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" -msgstr "" - -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" -msgstr "" - -#: py/compile.c -msgid "annotation must be an identifier" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" -msgstr "" - -#: py/modbuiltins.c -msgid "arg is an empty sequence" -msgstr "" - -#: py/objobject.c -msgid "arg must be user-type" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" -msgstr "" - -#: py/compile.c -msgid "argument name reused" -msgstr "" - -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "array is too big" -msgstr "" - -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" -msgstr "" - -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - -#: py/compile.c -msgid "async for/with outside async function" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" -msgstr "" - -#: py/objstr.c -msgid "attributes not supported" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" -msgstr "" - -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" -msgstr "" - -#: py/builtinevex.c -msgid "bad compile mode" -msgstr "" - -#: py/objstr.c -msgid "bad conversion specifier" -msgstr "" - -#: py/objstr.c -msgid "bad format string" -msgstr "" - -#: py/binary.c py/objarray.c -msgid "bad typecode" -msgstr "" - -#: py/emitnative.c -msgid "binary op %q not implemented" -msgstr "" - -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" -msgstr "" - -#: extmod/modrandom.c -msgid "bits must be 32 or less" -msgstr "" - -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" -msgstr "" - -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" -msgstr "" - -#: py/emitinlinethumb.c -msgid "branch not in range" -msgstr "" - -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" -msgstr "" - -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" -msgstr "" - -#: shared-module/struct/__init__.c -msgid "buffer size must match format" -msgstr "" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" -msgstr "" - -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" -msgstr "" - -#: py/emitbc.c -msgid "bytecode overflow" -msgstr "" - -#: py/objarray.c -msgid "bytes length not a multiple of item size" -msgstr "" - -#: py/objstr.c -msgid "bytes value out of range" -msgstr "" - -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" -msgstr "" - -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" -msgstr "" - -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" -msgstr "" - -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" -msgstr "" - -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" -msgstr "" - -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" -msgstr "" - -#: py/objtype.c -msgid "can't add special method to already-subclassed class" -msgstr "" - -#: py/compile.c -msgid "can't assign to expression" -msgstr "" - -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "" - -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" -msgstr "" - -#: py/obj.c -#, c-format -msgid "can't convert %s to complex" -msgstr "" - -#: py/obj.c -#, c-format -msgid "can't convert %s to float" -msgstr "" - -#: py/objint.c py/runtime.c -#, c-format -msgid "can't convert %s to int" -msgstr "" - -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" -msgstr "" - -#: py/obj.c -msgid "can't convert to complex" -msgstr "" - -#: py/obj.c -msgid "can't convert to float" -msgstr "" - -#: py/runtime.c -msgid "can't convert to int" -msgstr "" - -#: py/objstr.c -msgid "can't convert to str implicitly" -msgstr "" - -#: py/objtype.c -msgid "can't create '%q' instances" -msgstr "" - -#: py/compile.c -msgid "can't declare nonlocal in outer code" -msgstr "" - -#: py/compile.c -msgid "can't delete expression" -msgstr "" - -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't do unary op of '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" -msgstr "" - -#: py/runtime.c -msgid "can't import name %q" -msgstr "" - -#: py/emitnative.c -msgid "can't load from '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't load with '%q' index" -msgstr "" - -#: py/builtinimport.c -msgid "can't perform relative import" -msgstr "" - -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" -msgstr "" - -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" -msgstr "" - -#: py/runtime.c -msgid "can't set attribute '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't store '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't store to '%q'" -msgstr "" - -#: py/emitnative.c -msgid "can't store with '%q' index" -msgstr "" - -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" -msgstr "" - -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" -msgstr "" - -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" -msgstr "" - -#: extmod/modasyncio.c -msgid "can't wait" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" -msgstr "" - -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" -msgstr "" - -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" -msgstr "" - -#: py/emitnative.c -msgid "casting" -msgstr "" - -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" -msgstr "" - -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" -msgstr "" - -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" -msgstr "" - -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" -msgstr "" - -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" -msgstr "" - -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" -msgstr "" - -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" -msgstr "" - -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" -msgstr "" - -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" -msgstr "" - -#: py/emitnative.c -msgid "comparison of int and uint" -msgstr "" - -#: py/objcomplex.c -msgid "complex divide by zero" -msgstr "" - -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" -msgstr "" - -#: extmod/modzlib.c -msgid "compression header" -msgstr "" - -#: py/emitnative.c -msgid "conversion to object" -msgstr "" - -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" -msgstr "" - -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" -msgstr "" - -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" -msgstr "" - -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "data pin #%d in use" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" -msgstr "" - -#: py/parsenum.c -msgid "decimal numbers not supported" -msgstr "" - -#: py/compile.c -msgid "default 'except' must be last" -msgstr "" - -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" -msgstr "" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" - -#: py/objdict.c -msgid "dict update sequence has wrong length" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" -msgstr "" - -#: py/emitnative.c -msgid "div/mod not implemented for uint" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "divide by zero" -msgstr "" - -#: py/runtime.c -msgid "division by zero" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" -msgstr "" - -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" -msgstr "" - -#: py/objdeque.c -msgid "empty" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" -msgstr "" - -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" -msgstr "" - -#: py/objstr.c -msgid "empty separator" -msgstr "" - -#: shared-bindings/random/__init__.c -msgid "empty sequence" -msgstr "" - -#: py/objstr.c -msgid "end of format while looking for conversion specifier" -msgstr "" - -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" -msgstr "" - -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" -msgstr "" - -#: py/runtime.c -msgid "exceptions must derive from BaseException" -msgstr "" - -#: py/objstr.c -msgid "expected ':' after format specifier" -msgstr "" - -#: py/obj.c -msgid "expected tuple/list" -msgstr "" - -#: py/modthread.c -msgid "expecting a dict for keyword args" -msgstr "" - -#: py/compile.c -msgid "expecting an assembler instruction" -msgstr "" - -#: py/compile.c -msgid "expecting just a value for set" -msgstr "" - -#: py/compile.c -msgid "expecting key:value for dict" -msgstr "" - -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" -msgstr "" - -#: py/argcheck.c -msgid "extra keyword arguments given" -msgstr "" - -#: py/argcheck.c -msgid "extra positional arguments given" -msgstr "" - -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" -msgstr "" - -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" -msgstr "" - -#: py/objtype.c -msgid "first argument to super() must be type" -msgstr "" - -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" -msgstr "" - -#: py/objint.c -msgid "float too big" -msgstr "" - -#: py/nativeglue.c -msgid "float unsupported" -msgstr "" - -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - -#: extmod/moddeflate.c -msgid "format" -msgstr "" - -#: py/objstr.c -msgid "format needs a dict" -msgstr "" - -#: py/objstr.c -msgid "format string didn't convert all arguments" -msgstr "" - -#: py/objstr.c -msgid "format string needs more arguments" -msgstr "" - -#: py/objdeque.c -msgid "full" -msgstr "" - -#: py/argcheck.c -msgid "function doesn't take keyword arguments" -msgstr "" - -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" -msgstr "" - -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" -msgstr "" - -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" -msgstr "" - -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" -msgstr "" - -#: py/bc.c -msgid "function missing keyword-only argument" -msgstr "" - -#: py/bc.c -msgid "function missing required keyword argument '%q'" -msgstr "" - -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" -msgstr "" - -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" -msgstr "" - -#: py/objgenerator.c -msgid "generator already executing" -msgstr "" - -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" -msgstr "" - -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" -msgstr "" - -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - -#: extmod/modhashlib.c -msgid "hash is final" -msgstr "" - -#: extmod/modheapq.c -msgid "heap must be a list" -msgstr "" - -#: py/compile.c -msgid "identifier redefined as global" -msgstr "" - -#: py/compile.c -msgid "identifier redefined as nonlocal" -msgstr "" - -#: py/compile.c -msgid "import * not at module level" -msgstr "" - -#: py/persistentcode.c -msgid "incompatible .mpy arch" -msgstr "" - -#: py/persistentcode.c -msgid "incompatible .mpy file" -msgstr "" - -#: py/objstr.c -msgid "incomplete format" -msgstr "" - -#: py/objstr.c -msgid "incomplete format key" -msgstr "" - -#: extmod/modbinascii.c -msgid "incorrect padding" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" -msgstr "" - -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" -msgstr "" - -#: py/obj.c -msgid "indices must be integers" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" -msgstr "" - -#: py/compile.c -msgid "inline assembler must be a function" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" -msgstr "" - -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" -msgstr "" - -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" -msgstr "" - -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" -msgstr "" - -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" -msgstr "" - -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" -msgstr "" - -#: py/compile.c -msgid "invalid arch" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" -msgstr "" - -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" -msgstr "" - -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" -msgstr "" - -#: py/objstr.c -msgid "invalid format specifier" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" -msgstr "" - -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" -msgstr "" - -#: py/compile.c -msgid "invalid micropython decorator" -msgstr "" - -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" -msgstr "" - -#: shared-bindings/random/__init__.c -msgid "invalid step" -msgstr "" - -#: py/compile.c py/parse.c -msgid "invalid syntax" -msgstr "" - -#: py/parsenum.c -msgid "invalid syntax for integer" -msgstr "" - -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" -msgstr "" - -#: py/parsenum.c -msgid "invalid syntax for number" -msgstr "" - -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" -msgstr "" - -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" -msgstr "" - -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" -msgstr "" - -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" -msgstr "" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" -msgstr "" - -#: py/compile.c -msgid "label redefined" -msgstr "" - -#: py/objarray.c -msgid "lhs and rhs should be compatible" -msgstr "" - -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" -msgstr "" - -#: py/emitnative.c -msgid "local '%q' used before type known" -msgstr "" - -#: py/vm.c -msgid "local variable referenced before assignment" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" -msgstr "" - -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" -msgstr "" - -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" -msgstr "" - -#: py/parse.c -msgid "malformed f-string" -msgstr "" - -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" -msgstr "" - -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "" - -#: py/runtime.c -msgid "maximum recursion depth exceeded" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" -msgstr "" - -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" -msgstr "" - -#: py/runtime.c -msgid "memory allocation failed, heap is locked" -msgstr "" - -#: py/objarray.c -msgid "memoryview offset too large" -msgstr "" - -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" -msgstr "" - -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" -msgstr "" - -#: py/builtinimport.c -msgid "module not found" -msgstr "" - -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" -msgstr "" - -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" -msgstr "" - -#: py/compile.c -msgid "multiple *x in assignment" -msgstr "" - -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" -msgstr "" - -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "" - -#: py/emitnative.c -msgid "must raise an object" -msgstr "" - -#: py/modbuiltins.c -msgid "must use keyword argument for key function" -msgstr "" - -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "" - -#: py/runtime.c -msgid "name not defined" -msgstr "" - -#: py/qstr.c -msgid "name too long" -msgstr "" - -#: py/persistentcode.c -msgid "native code in .mpy unsupported" -msgstr "" - -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - -#: py/emitnative.c -msgid "native yield" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" -msgstr "" - -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" -msgstr "" - -#: py/modmath.c -msgid "negative factorial" -msgstr "" - -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" -msgstr "" - -#: py/objint_mpz.c py/runtime.c -msgid "negative shift count" -msgstr "" - -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "" - -#: py/vm.c -msgid "no active exception to reraise" -msgstr "" - -#: py/compile.c -msgid "no binding for nonlocal found" -msgstr "" - -#: shared-module/msgpack/__init__.c -msgid "no default packer" -msgstr "" - -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" -msgstr "" - -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" -msgstr "" - -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" -msgstr "" - -#: py/compile.c -msgid "non-default argument follows default argument" -msgstr "" - -#: py/objstr.c -msgid "non-hex digit" -msgstr "" - -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" -msgstr "" - -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" -msgstr "" - -#: py/parse.c -msgid "not a constant" -msgstr "" - -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" -msgstr "" - -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" -msgstr "" - -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" -msgstr "" - -#: py/builtinhelp.c -msgid "object " -msgstr "" - -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" -msgstr "" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "object does not support DigitalInOut protocol" -msgstr "" - -#: py/obj.c -msgid "object doesn't support item assignment" -msgstr "" - -#: py/obj.c -msgid "object doesn't support item deletion" -msgstr "" - -#: py/obj.c -msgid "object has no len" -msgstr "" - -#: py/obj.c -msgid "object isn't subscriptable" -msgstr "" - -#: py/runtime.c -msgid "object not an iterator" -msgstr "" - -#: py/objtype.c py/runtime.c -msgid "object not callable" -msgstr "" - -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" -msgstr "" - -#: py/runtime.c -msgid "object not iterable" -msgstr "" - -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" -msgstr "" - -#: py/obj.c -msgid "object with buffer protocol required" -msgstr "" - -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" -msgstr "" - -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" -msgstr "" - -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" -msgstr "" - -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" -msgstr "" - -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" -msgstr "" - -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" -msgstr "" - -#: py/vm.c -msgid "opcode" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" -msgstr "" - -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" -msgstr "" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" -msgstr "" - -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" -msgstr "" - -#: py/modbuiltins.c -msgid "ord expects a character" -msgstr "" - -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" -msgstr "" - -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" -msgstr "" - -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" -msgstr "" - -#: py/objint_mpz.c -msgid "overflow converting long int to machine word" -msgstr "" - -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "" - -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" - -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" -msgstr "" - -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" -msgstr "" - -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" -msgstr "" - -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" -msgstr "" - -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" -msgstr "" - -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" -msgstr "" - -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" -msgstr "" - -#: py/compile.c -msgid "positional arg after **" -msgstr "" - -#: py/compile.c -msgid "positional arg after keyword arg" -msgstr "" - -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" -msgstr "" - -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" -msgstr "" - -#: py/builtinimport.c -msgid "relative import" -msgstr "" - -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" -msgstr "" - -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" -msgstr "" - -#: py/compile.c -msgid "return annotation must be an identifier" -msgstr "" - -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" -msgstr "" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" -msgstr "" - -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "" - -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" -msgstr "" - -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" -msgstr "" - -#: py/modmicropython.c -msgid "schedule queue full" -msgstr "" - -#: py/builtinimport.c -msgid "script compilation not supported" -msgstr "" - -#: py/nativeglue.c -msgid "set unsupported" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" -msgstr "" - -#: shared-module/msgpack/__init__.c -msgid "short read" -msgstr "" - -#: py/objstr.c -msgid "sign not allowed in string format specifier" -msgstr "" - -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" -msgstr "" - -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" -msgstr "" - -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" -msgstr "" - -#: py/nativeglue.c -msgid "slice unsupported" -msgstr "" - -#: py/objint.c py/sequence.c -msgid "small int overflow" -msgstr "" - -#: main.c -msgid "soft reboot\n" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" -msgstr "" - -#: extmod/modre.c -msgid "splitting with sub-captures" -msgstr "" - -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" -msgstr "" - -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" -msgstr "" - -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" -msgstr "" - -#: py/objstrunicode.c -msgid "string index out of range" -msgstr "" - -#: py/objstrunicode.c -#, c-format -msgid "string indices must be integers, not %s" -msgstr "" - -#: py/objarray.c py/objstr.c -msgid "substring not found" -msgstr "" - -#: py/compile.c -msgid "super() can't find self" -msgstr "" - -#: extmod/modjson.c -msgid "syntax error in JSON" -msgstr "" - -#: extmod/modtime.c -msgid "ticks interval overflow" -msgstr "" - -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" -msgstr "" - -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" -msgstr "" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" -msgstr "" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" -msgstr "" - -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" -msgstr "" - -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" -msgstr "" - -#: py/compile.c -msgid "too many args" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" -msgstr "" - -#: extmod/ulab/code/ndarray.c -msgid "too many indices" -msgstr "" - -#: py/asmthumb.c -msgid "too many locals for native method" -msgstr "" - -#: py/runtime.c -#, c-format -msgid "too many values to unpack (expected %d)" -msgstr "" - -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" -msgstr "" - -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" -msgstr "" - -#: py/obj.c -msgid "tuple/list has wrong length" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" -msgstr "" - -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" -msgstr "" - -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" -msgstr "" - -#: py/objtype.c -msgid "type isn't an acceptable base type" -msgstr "" - -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" -msgstr "" - -#: py/objtype.c -msgid "type takes 1 or 3 arguments" -msgstr "" - -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - -#: py/parse.c -msgid "unexpected indent" -msgstr "" - -#: py/bc.c -msgid "unexpected keyword argument" -msgstr "" - -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" -msgstr "" - -#: py/lexer.c -msgid "unicode name escapes" -msgstr "" - -#: py/parse.c -msgid "unindent doesn't match any outer indent level" -msgstr "" - -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" -msgstr "" - -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" -msgstr "" - -#: py/compile.c -msgid "unknown type" -msgstr "" - -#: py/compile.c -msgid "unknown type '%q'" -msgstr "" - -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" -msgstr "" - -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" -msgstr "" - -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" -msgstr "" - -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" -msgstr "" - -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" -msgstr "" - -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" -msgstr "" - -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" -msgstr "" - -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" -msgstr "" - -#: py/runtime.c -msgid "unsupported type for %q: '%s'" -msgstr "" - -#: py/runtime.c -msgid "unsupported type for operator" -msgstr "" - -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" -msgstr "" - -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" -msgstr "" - -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" -msgstr "" - -#: extmod/moddeflate.c -msgid "wbits" -msgstr "" - -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" -msgstr "" - -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "" - -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" -msgstr "" - -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" -msgstr "" - -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" -msgstr "" - -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" -msgstr "" - -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "" - -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" -msgstr "" - -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" -msgstr "" - -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" -msgstr "" - -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" -msgstr "" - -#: py/runtime.c -msgid "wrong number of values to unpack" -msgstr "" - -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" -msgstr "" - -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" -msgstr "" diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index e6a868ab212..9065ffebcf8 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -5,5 +5,24 @@ // SPDX-License-Identifier: MIT #include "supervisor/board.h" +#include "shared-bindings/mcp4822/MCP4822.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "peripherals/pins.h" +#include "py/runtime.h" + +// board.DAC() — factory function that constructs an mcp4822.MCP4822 with +// the MTM Workshop Computer's DAC pins (GP18=SCK, GP19=SDI, GP21=CS). +static mp_obj_t board_dac_factory(void) { + mcp4822_mcp4822_obj_t *dac = mp_obj_malloc_with_finaliser( + mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); + common_hal_mcp4822_mcp4822_construct( + dac, + &pin_GPIO18, // clock (SCK) + &pin_GPIO19, // mosi (SDI) + &pin_GPIO21, // cs + 1); // gain 1x + return MP_OBJ_FROM_PTR(dac); +} +MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h deleted file mode 100644 index f9b5dd60108..00000000000 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h +++ /dev/null @@ -1,38 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/rp2pio/StateMachine.h" - -#include "audio_dma.h" -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - rp2pio_statemachine_obj_t state_machine; - audio_dma_t dma; - bool playing; -} mtm_hardware_dacout_obj_t; - -void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, - const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs, uint8_t gain); - -void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); - -void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, - mp_obj_t sample, bool loop); -void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self); - -void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self); -void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self); - -extern const mp_obj_type_t mtm_hardware_dacout_type; diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c deleted file mode 100644 index 8f875496f67..00000000000 --- a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c +++ /dev/null @@ -1,276 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT -// -// Python bindings for the mtm_hardware module. -// Provides DACOut: a non-blocking audio player for the MCP4822 SPI DAC. - -#include - -#include "shared/runtime/context_manager_helpers.h" -#include "py/binary.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/util.h" -#include "boards/mtm_computer/module/DACOut.h" - -// ───────────────────────────────────────────────────────────────────────────── -// DACOut class -// ───────────────────────────────────────────────────────────────────────────── - -//| class DACOut: -//| """Output audio to the MCP4822 dual-channel 12-bit SPI DAC.""" -//| -//| def __init__( -//| self, -//| clock: microcontroller.Pin, -//| mosi: microcontroller.Pin, -//| cs: microcontroller.Pin, -//| *, -//| gain: int = 1, -//| ) -> None: -//| """Create a DACOut object associated with the given SPI pins. -//| -//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin -//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin -//| :param ~microcontroller.Pin cs: The chip select (CS) pin -//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. -//| -//| Simple 8ksps 440 Hz sine wave:: -//| -//| import mtm_hardware -//| import audiocore -//| import board -//| import array -//| import time -//| import math -//| -//| length = 8000 // 440 -//| sine_wave = array.array("H", [0] * length) -//| for i in range(length): -//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) -//| -//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) -//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) -//| dac.play(sine_wave, loop=True) -//| time.sleep(1) -//| dac.stop() -//| -//| Playing a wave file from flash:: -//| -//| import board -//| import audiocore -//| import mtm_hardware -//| -//| f = open("sound.wav", "rb") -//| wav = audiocore.WaveFile(f) -//| -//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) -//| dac.play(wav) -//| while dac.playing: -//| pass""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); - const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); - const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); - - mp_int_t gain = args[ARG_gain].u_int; - if (gain != 1 && gain != 2) { - mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("gain must be 1 or 2")); - } - - mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); - common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs, (uint8_t)gain); - - return MP_OBJ_FROM_PTR(self); -} - -static void check_for_deinit(mtm_hardware_dacout_obj_t *self) { - if (common_hal_mtm_hardware_dacout_deinited(self)) { - raise_deinited_error(); - } -} - -//| def deinit(self) -> None: -//| """Deinitialises the DACOut and releases any hardware resources for reuse.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_deinit(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_mtm_hardware_dacout_deinit(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_deinit_obj, mtm_hardware_dacout_deinit); - -//| def __enter__(self) -> DACOut: -//| """No-op used by Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -// Provided by context manager helper. - -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: -//| """Plays the sample once when loop=False and continuously when loop=True. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. -//| -//| The sample itself should consist of 8 bit or 16 bit samples.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_mtm_hardware_dacout_play(self, sample, args[ARG_loop].u_bool); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(mtm_hardware_dacout_play_obj, 1, mtm_hardware_dacout_obj_play); - -//| def stop(self) -> None: -//| """Stops playback.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_stop(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_mtm_hardware_dacout_stop(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_stop_obj, mtm_hardware_dacout_obj_stop); - -//| playing: bool -//| """True when the audio sample is being output. (read-only)""" -//| -static mp_obj_t mtm_hardware_dacout_obj_get_playing(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_playing(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_playing_obj, mtm_hardware_dacout_obj_get_playing); - -MP_PROPERTY_GETTER(mtm_hardware_dacout_playing_obj, - (mp_obj_t)&mtm_hardware_dacout_get_playing_obj); - -//| def pause(self) -> None: -//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_pause(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - if (!common_hal_mtm_hardware_dacout_get_playing(self)) { - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Not playing")); - } - common_hal_mtm_hardware_dacout_pause(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_pause_obj, mtm_hardware_dacout_obj_pause); - -//| def resume(self) -> None: -//| """Resumes sample playback after :py:func:`pause`.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_resume(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - if (common_hal_mtm_hardware_dacout_get_paused(self)) { - common_hal_mtm_hardware_dacout_resume(self); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_resume_obj, mtm_hardware_dacout_obj_resume); - -//| paused: bool -//| """True when playback is paused. (read-only)""" -//| -static mp_obj_t mtm_hardware_dacout_obj_get_paused(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_paused(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_paused_obj, mtm_hardware_dacout_obj_get_paused); - -MP_PROPERTY_GETTER(mtm_hardware_dacout_paused_obj, - (mp_obj_t)&mtm_hardware_dacout_get_paused_obj); - -// ── DACOut type definition ─────────────────────────────────────────────────── - -static const mp_rom_map_elem_t mtm_hardware_dacout_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mtm_hardware_dacout_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mtm_hardware_dacout_stop_obj) }, - { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mtm_hardware_dacout_pause_obj) }, - { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mtm_hardware_dacout_resume_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mtm_hardware_dacout_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mtm_hardware_dacout_paused_obj) }, -}; -static MP_DEFINE_CONST_DICT(mtm_hardware_dacout_locals_dict, mtm_hardware_dacout_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - mtm_hardware_dacout_type, - MP_QSTR_DACOut, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, mtm_hardware_dacout_make_new, - locals_dict, &mtm_hardware_dacout_locals_dict - ); - -// ───────────────────────────────────────────────────────────────────────────── -// mtm_hardware module definition -// ───────────────────────────────────────────────────────────────────────────── - -//| """Hardware interface to Music Thing Modular Workshop Computer peripherals. -//| -//| Provides the `DACOut` class for non-blocking audio output via the -//| MCP4822 dual-channel 12-bit SPI DAC. -//| """ - -static const mp_rom_map_elem_t mtm_hardware_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mtm_hardware) }, - { MP_ROM_QSTR(MP_QSTR_DACOut), MP_ROM_PTR(&mtm_hardware_dacout_type) }, -}; - -static MP_DEFINE_CONST_DICT(mtm_hardware_module_globals, mtm_hardware_module_globals_table); - -const mp_obj_module_t mtm_hardware_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&mtm_hardware_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_mtm_hardware, mtm_hardware_module); diff --git a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk index 74d9baac879..45c99711d72 100644 --- a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk +++ b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk @@ -11,7 +11,4 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_AUDIOEFFECTS = 1 CIRCUITPY_IMAGECAPTURE = 0 CIRCUITPY_PICODVI = 0 - -SRC_C += \ - boards/$(BOARD)/module/mtm_hardware.c \ - boards/$(BOARD)/module/DACOut.c +CIRCUITPY_MCP4822 = 1 diff --git a/ports/raspberrypi/boards/mtm_computer/pins.c b/ports/raspberrypi/boards/mtm_computer/pins.c index 69878182331..ffdf2687702 100644 --- a/ports/raspberrypi/boards/mtm_computer/pins.c +++ b/ports/raspberrypi/boards/mtm_computer/pins.c @@ -6,6 +6,8 @@ #include "shared-bindings/board/__init__.h" +extern const mp_obj_fun_builtin_fixed_t board_dac_obj; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -21,7 +23,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_PULSE_2_IN), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, - { MP_ROM_QSTR(MP_QSTR_NORM_PROBE), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, @@ -105,6 +106,9 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + // Factory function: dac = board.DAC() returns a configured mcp4822.MCP4822 + { MP_ROM_QSTR(MP_QSTR_DAC), MP_ROM_PTR(&board_dac_obj) }, + // { MP_ROM_QSTR(MP_QSTR_EEPROM_I2C), MP_ROM_PTR(&board_i2c_obj) }, }; MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c similarity index 75% rename from ports/raspberrypi/boards/mtm_computer/module/DACOut.c rename to ports/raspberrypi/common-hal/mcp4822/MCP4822.c index fb4ce37d4d0..cb6cddb8343 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT // -// MCP4822 dual-channel 12-bit SPI DAC driver for the MTM Workshop Computer. +// MCP4822 dual-channel 12-bit SPI DAC audio output. // Uses PIO + DMA for non-blocking audio playback, mirroring audiobusio.I2SOut. #include @@ -15,7 +15,8 @@ #include "py/gc.h" #include "py/mperrno.h" #include "py/runtime.h" -#include "boards/mtm_computer/module/DACOut.h" +#include "common-hal/mcp4822/MCP4822.h" +#include "shared-bindings/mcp4822/MCP4822.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/audiocore/__init__.h" #include "bindings/rp2pio/StateMachine.h" @@ -29,16 +30,14 @@ // SET pins (N) = MOSI through CS — for CS control & command-bit injection // SIDE-SET pin (1) = SCK — serial clock // -// On the MTM Workshop Computer: MOSI=GP19, CS=GP21, SCK=GP18. -// The SET group spans GP19..GP21 (3 pins). GP20 is unused and driven low. -// -// SET PINS bit mapping (bit0=MOSI/GP19, bit1=GP20, bit2=CS/GP21): -// 0 = CS low, MOSI low 1 = CS low, MOSI high 4 = CS high, MOSI low +// SET PINS bit mapping (bit0=MOSI, ..., bit N=CS): +// 0 = CS low, MOSI low 1 = CS low, MOSI high +// (1 << cs_bit_pos) = CS high, MOSI low // // SIDE-SET (1 pin, SCK): side 0 = SCK low, side 1 = SCK high // // MCP4822 16-bit command word: -// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x) +// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x, 0=2x) // [12] output enable (1) [11:0] 12-bit data // // DMA feeds unsigned 16-bit audio samples. RP2040 narrow-write replication @@ -46,8 +45,8 @@ // giving mono→stereo for free. // // The PIO pulls 32 bits, then sends two SPI transactions: -// Channel A: cmd nibble 0b0011, then all 16 sample bits from upper half-word -// Channel B: cmd nibble 0b1011, then all 16 sample bits from lower half-word +// Channel A: cmd nibble, then all 16 sample bits from upper half-word +// Channel B: cmd nibble, then all 16 sample bits from lower half-word // The MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data), // so only the top 12 of the 16 sample bits become DAC data. The bottom // 4 sample bits clock out harmlessly after the DAC has latched. @@ -66,11 +65,7 @@ static const uint16_t mcp4822_pio_program[] = { // 1: mov x, osr side 0 ; Save for pull-noblock fallback 0xA027, - // ── Channel A: command nibble 0b0011 ────────────────────────────────── - // Send 4 cmd bits via SET, then all 16 sample bits via OUT. - // MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data); - // the extra 4 clocks shift out the LSBs which the DAC ignores. - // This gives correct 16→12 bit scaling (top 12 bits become DAC data). + // ── Channel A: command nibble 0b0011 (1x gain) ──────────────────────── // 2: set pins, 0 side 0 ; CS low, MOSI=0 (bit15=0: channel A) 0xE000, // 3: nop side 1 ; SCK high — latch bit 15 @@ -79,7 +74,7 @@ static const uint16_t mcp4822_pio_program[] = { 0xE000, // 5: nop side 1 ; SCK high 0xB042, - // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) [patched for 2x] 0xE001, // 7: nop side 1 ; SCK high 0xB042, @@ -96,7 +91,7 @@ static const uint16_t mcp4822_pio_program[] = { // 13: set pins, 4 side 0 ; CS high — DAC A latches 0xE004, - // ── Channel B: command nibble 0b1011 ────────────────────────────────── + // ── Channel B: command nibble 0b1011 (1x gain) ──────────────────────── // 14: set pins, 1 side 0 ; CS low, MOSI=1 (bit15=1: channel B) 0xE001, // 15: nop side 1 ; SCK high @@ -105,7 +100,7 @@ static const uint16_t mcp4822_pio_program[] = { 0xE000, // 17: nop side 1 ; SCK high 0xB042, - // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) [patched for 2x] 0xE001, // 19: nop side 1 ; SCK high 0xB042, @@ -127,7 +122,6 @@ static const uint16_t mcp4822_pio_program[] = { // Per channel: 8(4 cmd bits × 2 clks) + 1(set y) + 32(16 bits × 2 clks) + 1(cs high) = 42 #define MCP4822_CLOCKS_PER_SAMPLE 86 - // MCP4822 gain bit (bit 13) position in the PIO program: // Instruction 6 = channel A gain bit // Instruction 18 = channel B gain bit @@ -138,15 +132,19 @@ static const uint16_t mcp4822_pio_program[] = { #define MCP4822_PIO_GAIN_1X 0xE001 // set pins, 1 #define MCP4822_PIO_GAIN_2X 0xE000 // set pins, 0 -void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, +void mcp4822_reset(void) { +} + +// Caller validates that pins are free. +void common_hal_mcp4822_mcp4822_construct(mcp4822_mcp4822_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *cs, uint8_t gain) { - // SET pins span from MOSI to CS. MOSI must have a lower GPIO number - // than CS, with at most 4 pins between them (SET count max is 5). + // The SET pin group spans from MOSI to CS. + // MOSI must have a lower GPIO number than CS, gap at most 4. if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { mp_raise_ValueError( - MP_COMPRESSED_ROM_TEXT("cs pin must be 1-4 positions above mosi pin")); + MP_ERROR_TEXT("cs pin must be 1-4 positions above mosi pin")); } uint8_t set_count = cs->number - mosi->number + 1; @@ -197,26 +195,26 @@ void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, audio_dma_init(&self->dma); } -bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self) { +bool common_hal_mcp4822_mcp4822_deinited(mcp4822_mcp4822_obj_t *self) { return common_hal_rp2pio_statemachine_deinited(&self->state_machine); } -void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self) { - if (common_hal_mtm_hardware_dacout_deinited(self)) { +void common_hal_mcp4822_mcp4822_deinit(mcp4822_mcp4822_obj_t *self) { + if (common_hal_mcp4822_mcp4822_deinited(self)) { return; } - if (common_hal_mtm_hardware_dacout_get_playing(self)) { - common_hal_mtm_hardware_dacout_stop(self); + if (common_hal_mcp4822_mcp4822_get_playing(self)) { + common_hal_mcp4822_mcp4822_stop(self); } common_hal_rp2pio_statemachine_deinit(&self->state_machine); audio_dma_deinit(&self->dma); } -void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, +void common_hal_mcp4822_mcp4822_play(mcp4822_mcp4822_obj_t *self, mp_obj_t sample, bool loop) { - if (common_hal_mtm_hardware_dacout_get_playing(self)) { - common_hal_mtm_hardware_dacout_stop(self); + if (common_hal_mcp4822_mcp4822_get_playing(self)) { + common_hal_mcp4822_mcp4822_stop(self); } uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); @@ -227,7 +225,7 @@ void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, uint32_t sample_rate = audiosample_get_sample_rate(sample); uint8_t channel_count = audiosample_get_channel_count(sample); if (channel_count > 2) { - mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("Too many channels in sample.")); + mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample.")); } // PIO clock = sample_rate × clocks_per_sample @@ -236,10 +234,6 @@ void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, (uint32_t)sample_rate * MCP4822_CLOCKS_PER_SAMPLE); common_hal_rp2pio_statemachine_restart(&self->state_machine); - // DMA feeds unsigned 16-bit samples. The PIO discards the top 4 bits - // of each 16-bit half and uses the remaining 12 as DAC data. - // RP2040 narrow-write replication: 16-bit DMA write → same value in - // both 32-bit FIFO halves → mono-to-stereo for free. audio_dma_result result = audio_dma_setup_playback( &self->dma, sample, @@ -253,41 +247,41 @@ void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, false); // swap_channel if (result == AUDIO_DMA_DMA_BUSY) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("No DMA channel found")); + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("No DMA channel found")); } else if (result == AUDIO_DMA_MEMORY_ERROR) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Unable to allocate buffers for signed conversion")); + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("Unable to allocate buffers for signed conversion")); } else if (result == AUDIO_DMA_SOURCE_ERROR) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Audio source error")); + common_hal_mcp4822_mcp4822_stop(self); + mp_raise_RuntimeError(MP_ERROR_TEXT("Audio source error")); } self->playing = true; } -void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self) { +void common_hal_mcp4822_mcp4822_pause(mcp4822_mcp4822_obj_t *self) { audio_dma_pause(&self->dma); } -void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self) { +void common_hal_mcp4822_mcp4822_resume(mcp4822_mcp4822_obj_t *self) { audio_dma_resume(&self->dma); } -bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self) { +bool common_hal_mcp4822_mcp4822_get_paused(mcp4822_mcp4822_obj_t *self) { return audio_dma_get_paused(&self->dma); } -void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self) { +void common_hal_mcp4822_mcp4822_stop(mcp4822_mcp4822_obj_t *self) { audio_dma_stop(&self->dma); common_hal_rp2pio_statemachine_stop(&self->state_machine); self->playing = false; } -bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self) { +bool common_hal_mcp4822_mcp4822_get_playing(mcp4822_mcp4822_obj_t *self) { bool playing = audio_dma_get_playing(&self->dma); if (!playing && self->playing) { - common_hal_mtm_hardware_dacout_stop(self); + common_hal_mcp4822_mcp4822_stop(self); } return playing; } diff --git a/ports/raspberrypi/common-hal/mcp4822/MCP4822.h b/ports/raspberrypi/common-hal/mcp4822/MCP4822.h new file mode 100644 index 00000000000..53c8e862b63 --- /dev/null +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/rp2pio/StateMachine.h" + +#include "audio_dma.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + rp2pio_statemachine_obj_t state_machine; + audio_dma_t dma; + bool playing; +} mcp4822_mcp4822_obj_t; + +void mcp4822_reset(void); diff --git a/ports/raspberrypi/common-hal/mcp4822/__init__.c b/ports/raspberrypi/common-hal/mcp4822/__init__.c new file mode 100644 index 00000000000..48981fc88a7 --- /dev/null +++ b/ports/raspberrypi/common-hal/mcp4822/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +// No module-level init needed. diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 8401c5d7545..30fc75c106b 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -16,6 +16,7 @@ CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 CIRCUITPY_IMAGECAPTURE ?= 1 CIRCUITPY_MAX3421E ?= 0 +CIRCUITPY_MCP4822 ?= 0 CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_PWMIO ?= 1 CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_DISPLAYIO) diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 886ba96f3e5..14c8c52802e 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -288,6 +288,9 @@ endif ifeq ($(CIRCUITPY_MAX3421E),1) SRC_PATTERNS += max3421e/% endif +ifeq ($(CIRCUITPY_MCP4822),1) +SRC_PATTERNS += mcp4822/% +endif ifeq ($(CIRCUITPY_MDNS),1) SRC_PATTERNS += mdns/% endif @@ -532,6 +535,8 @@ SRC_COMMON_HAL_ALL = \ i2ctarget/I2CTarget.c \ i2ctarget/__init__.c \ max3421e/Max3421E.c \ + mcp4822/__init__.c \ + mcp4822/MCP4822.c \ memorymap/__init__.c \ memorymap/AddressRange.c \ microcontroller/__init__.c \ diff --git a/shared-bindings/mcp4822/MCP4822.c b/shared-bindings/mcp4822/MCP4822.c new file mode 100644 index 00000000000..c48f5426e66 --- /dev/null +++ b/shared-bindings/mcp4822/MCP4822.c @@ -0,0 +1,247 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/mcp4822/MCP4822.h" +#include "shared-bindings/util.h" + +//| class MCP4822: +//| """Output audio to an MCP4822 dual-channel 12-bit SPI DAC.""" +//| +//| def __init__( +//| self, +//| clock: microcontroller.Pin, +//| mosi: microcontroller.Pin, +//| cs: microcontroller.Pin, +//| *, +//| gain: int = 1, +//| ) -> None: +//| """Create an MCP4822 object associated with the given SPI pins. +//| +//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin +//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin +//| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. +//| +//| Simple 8ksps 440 Hz sine wave:: +//| +//| import mcp4822 +//| import audiocore +//| import board +//| import array +//| import time +//| import math +//| +//| length = 8000 // 440 +//| sine_wave = array.array("H", [0] * length) +//| for i in range(length): +//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) +//| +//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) +//| dac = mcp4822.MCP4822(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(sine_wave, loop=True) +//| time.sleep(1) +//| dac.stop() +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audiocore +//| import mcp4822 +//| +//| f = open("sound.wav", "rb") +//| wav = audiocore.WaveFile(f) +//| +//| dac = mcp4822.MCP4822(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(wav) +//| while dac.playing: +//| pass""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + + mp_int_t gain = args[ARG_gain].u_int; + if (gain != 1 && gain != 2) { + mp_raise_ValueError(MP_ERROR_TEXT("gain must be 1 or 2")); + } + + mcp4822_mcp4822_obj_t *self = mp_obj_malloc_with_finaliser(mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); + common_hal_mcp4822_mcp4822_construct(self, clock, mosi, cs, (uint8_t)gain); + + return MP_OBJ_FROM_PTR(self); +} + +static void check_for_deinit(mcp4822_mcp4822_obj_t *self) { + if (common_hal_mcp4822_mcp4822_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Deinitialises the MCP4822 and releases any hardware resources for reuse.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_deinit(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_mcp4822_mcp4822_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_deinit_obj, mcp4822_mcp4822_deinit); + +//| def __enter__(self) -> MCP4822: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. +//| +//| The sample itself should consist of 8 bit or 16 bit samples.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_mcp4822_mcp4822_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mcp4822_mcp4822_play_obj, 1, mcp4822_mcp4822_obj_play); + +//| def stop(self) -> None: +//| """Stops playback.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_stop(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_mcp4822_mcp4822_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_stop_obj, mcp4822_mcp4822_obj_stop); + +//| playing: bool +//| """True when the audio sample is being output. (read-only)""" +//| +static mp_obj_t mcp4822_mcp4822_obj_get_playing(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mcp4822_mcp4822_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_get_playing_obj, mcp4822_mcp4822_obj_get_playing); + +MP_PROPERTY_GETTER(mcp4822_mcp4822_playing_obj, + (mp_obj_t)&mcp4822_mcp4822_get_playing_obj); + +//| def pause(self) -> None: +//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_pause(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (!common_hal_mcp4822_mcp4822_get_playing(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Not playing")); + } + common_hal_mcp4822_mcp4822_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_pause_obj, mcp4822_mcp4822_obj_pause); + +//| def resume(self) -> None: +//| """Resumes sample playback after :py:func:`pause`.""" +//| ... +//| +static mp_obj_t mcp4822_mcp4822_obj_resume(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (common_hal_mcp4822_mcp4822_get_paused(self)) { + common_hal_mcp4822_mcp4822_resume(self); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_resume_obj, mcp4822_mcp4822_obj_resume); + +//| paused: bool +//| """True when playback is paused. (read-only)""" +//| +//| +static mp_obj_t mcp4822_mcp4822_obj_get_paused(mp_obj_t self_in) { + mcp4822_mcp4822_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mcp4822_mcp4822_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mcp4822_mcp4822_get_paused_obj, mcp4822_mcp4822_obj_get_paused); + +MP_PROPERTY_GETTER(mcp4822_mcp4822_paused_obj, + (mp_obj_t)&mcp4822_mcp4822_get_paused_obj); + +static const mp_rom_map_elem_t mcp4822_mcp4822_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mcp4822_mcp4822_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mcp4822_mcp4822_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mcp4822_mcp4822_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mcp4822_mcp4822_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mcp4822_mcp4822_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mcp4822_mcp4822_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mcp4822_mcp4822_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mcp4822_mcp4822_paused_obj) }, +}; +static MP_DEFINE_CONST_DICT(mcp4822_mcp4822_locals_dict, mcp4822_mcp4822_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mcp4822_mcp4822_type, + MP_QSTR_MCP4822, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, mcp4822_mcp4822_make_new, + locals_dict, &mcp4822_mcp4822_locals_dict + ); diff --git a/shared-bindings/mcp4822/MCP4822.h b/shared-bindings/mcp4822/MCP4822.h new file mode 100644 index 00000000000..b129aec3061 --- /dev/null +++ b/shared-bindings/mcp4822/MCP4822.h @@ -0,0 +1,25 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/mcp4822/MCP4822.h" +#include "common-hal/microcontroller/Pin.h" + +extern const mp_obj_type_t mcp4822_mcp4822_type; + +void common_hal_mcp4822_mcp4822_construct(mcp4822_mcp4822_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs, uint8_t gain); + +void common_hal_mcp4822_mcp4822_deinit(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_deinited(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_play(mcp4822_mcp4822_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_mcp4822_mcp4822_stop(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_get_playing(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_pause(mcp4822_mcp4822_obj_t *self); +void common_hal_mcp4822_mcp4822_resume(mcp4822_mcp4822_obj_t *self); +bool common_hal_mcp4822_mcp4822_get_paused(mcp4822_mcp4822_obj_t *self); diff --git a/shared-bindings/mcp4822/__init__.c b/shared-bindings/mcp4822/__init__.c new file mode 100644 index 00000000000..bac2136d9e7 --- /dev/null +++ b/shared-bindings/mcp4822/__init__.c @@ -0,0 +1,36 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/mcp4822/__init__.h" +#include "shared-bindings/mcp4822/MCP4822.h" + +//| """Audio output via MCP4822 dual-channel 12-bit SPI DAC. +//| +//| The `mcp4822` module provides the `MCP4822` class for non-blocking +//| audio playback through the Microchip MCP4822 SPI DAC using PIO and DMA. +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed. To do so, either call :py:meth:`!deinit` or use a +//| context manager.""" + +static const mp_rom_map_elem_t mcp4822_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mcp4822) }, + { MP_ROM_QSTR(MP_QSTR_MCP4822), MP_ROM_PTR(&mcp4822_mcp4822_type) }, +}; + +static MP_DEFINE_CONST_DICT(mcp4822_module_globals, mcp4822_module_globals_table); + +const mp_obj_module_t mcp4822_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mcp4822_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_mcp4822, mcp4822_module); diff --git a/shared-bindings/mcp4822/__init__.h b/shared-bindings/mcp4822/__init__.h new file mode 100644 index 00000000000..c4a52e5819d --- /dev/null +++ b/shared-bindings/mcp4822/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once From 6651ac123a90771b8d89d0fa6f4adac793dfef67 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 16:51:02 -0700 Subject: [PATCH 319/876] restore deleted circuitpython.pot, update translation --- locale/circuitpython.pot | 4575 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 4575 insertions(+) create mode 100644 locale/circuitpython.pot diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot new file mode 100644 index 00000000000..5d0be48fe3a --- /dev/null +++ b/locale/circuitpython.pot @@ -0,0 +1,4575 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: main.c +msgid "" +"\n" +"Code done running.\n" +msgstr "" + +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" +msgstr "" + +#: py/obj.c +msgid " File \"%q\"" +msgstr "" + +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr "" + +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr "" + +#: main.c +msgid " not found.\n" +msgstr "" + +#: main.c +msgid " output:\n" +msgstr "" + +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +msgstr "" + +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "" + +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" +msgstr "" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" +msgstr "" + +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" +msgstr "" + +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" +msgstr "" + +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" +msgstr "" + +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "" + +#: py/objstr.c +msgid "%q index out of range" +msgstr "" + +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" +msgstr "" + +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "" + +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "" + +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "" + +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "" + +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "" + +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "" + +#: py/argcheck.c +msgid "%q must be %d" +msgstr "" + +#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "" + +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "" + +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "" + +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "" + +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "" + +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "" + +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "" + +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "" + +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." +msgstr "" + +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "" + +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" +msgstr "" + +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "" + +#: py/objmodule.c +msgid "%q renamed %q" +msgstr "" + +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "" + +#: shared-module/bitbangio/I2C.c +msgid "%q too long" +msgstr "" + +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" +msgstr "" + +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "" + +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" +msgstr "" + +#: py/argcheck.c +msgid "'%q' argument required" +msgstr "" + +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "" + +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "" + +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" +msgstr "" + +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "" + +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "" + +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "" + +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "" + +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "" + +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "" + +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "" + +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "" + +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "" + +#: py/compile.c +msgid "'await' outside function" +msgstr "" + +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "" + +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "" + +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "" + +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "" + +#: py/emitnative.c +msgid "'not' not implemented" +msgstr "" + +#: py/compile.c +msgid "'return' outside function" +msgstr "" + +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "" + +#: py/compile.c +msgid "'yield' outside function" +msgstr "" + +#: py/compile.c +msgid "* arg after **" +msgstr "" + +#: py/compile.c +msgid "*x must be assignment target" +msgstr "" + +#: py/obj.c +msgid ", in %q\n" +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" +msgstr "" + +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "" + +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "" + +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "" + +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "" + +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "" + +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "" + +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "" + +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "" + +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "" + +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "" + +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "" + +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "" + +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" +msgstr "" + +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "" + +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "" + +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "" + +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "" + +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." +msgstr "" + +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" +msgstr "" + +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "" + +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "" + +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "" + +#: main.c +msgid "Auto-reload is off.\n" +msgstr "" + +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "" + +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "" + +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "" + +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" +msgstr "" + +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "" + +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "" + +#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c +#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c +#: shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "" + +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "" + +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "Cannot record to a file" +msgstr "" + +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." +msgstr "" + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "" + +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "" + +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "" + +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "" + +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "" + +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + +#: ports/stm/common-hal/analogio/AnalogOut.c +msgid "DAC Channel Init Error" +msgstr "" + +#: ports/stm/common-hal/analogio/AnalogOut.c +msgid "DAC Device Init Error" +msgstr "" + +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" +msgstr "" + +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "" + +#: main.c +msgid "Done" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "" + +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "" + +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "" + +#: extmod/modre.c +msgid "Error in regex" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "" + +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." +msgstr "" + +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "" + +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "" + +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "" + +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "" + +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" +msgstr "" + +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "" + +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" +msgstr "" + +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" +msgstr "" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "" + +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" +msgstr "" + +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" +msgstr "" + +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." +msgstr "" + +#: py/moderrno.c +msgid "File exists" +msgstr "" + +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" +msgstr "" + +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" +msgstr "" + +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "" + +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "" + +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +msgstr "" + +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "" + +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" +msgstr "" + +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." +msgstr "" + +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." +msgstr "" + +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "" + +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "" + +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "" + +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" +msgstr "" + +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "" + +#: py/moderrno.c +msgid "Input/output error" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" +msgstr "" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "" + +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "" + +#: shared-module/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Internal error #%d" +msgstr "" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-bindings/pwmio/PWMOut.c +msgid "Internal resource(s) in use" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "" + +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" +msgstr "" + +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "" + +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "" + +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" +msgstr "" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" +msgstr "" + +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" +msgstr "" + +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" +msgstr "" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "" + +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "" + +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "" + +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "" + +#: py/compile.c +msgid "LHS of keyword arg must be an id" +msgstr "" + +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "" + +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "" + +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" +msgstr "" + +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" +msgstr "" + +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" +msgstr "" + +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" +msgstr "" + +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" +msgstr "" + +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." +msgstr "" + +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" +msgstr "" + +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." +msgstr "" + +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "" + +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" +msgstr "" + +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +msgid "No DAC on chip" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" +msgstr "" + +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" +msgstr "" + +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" +msgstr "" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "" + +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "" + +#: shared-module/usb/core/Device.c +msgid "No configuration set" +msgstr "" + +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" +msgstr "" + +#: shared-bindings/board/__init__.c +msgid "No default %q bus" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" +msgstr "" + +#: shared-bindings/os/__init__.c +msgid "No hardware random available" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" +msgstr "" + +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "" + +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" +msgstr "" + +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" +msgstr "" + +#: py/moderrno.c +msgid "No space left on device" +msgstr "" + +#: py/moderrno.c +msgid "No such device" +msgstr "" + +#: py/moderrno.c +msgid "No such file/directory" +msgstr "" + +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" +msgstr "" + +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" +msgstr "" + +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" +msgstr "" + +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +msgid "Not playing" +msgstr "" + +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" +msgstr "" + +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." +msgstr "" + +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" +msgstr "" + +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" +msgstr "" + +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgstr "" + +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" +msgstr "" + +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" +msgstr "" + +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" +msgstr "" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" +msgstr "" + +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." +msgstr "" + +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." +msgstr "" + +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" +msgstr "" + +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "" + +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." +msgstr "" + +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" +msgstr "" + +#: py/moderrno.c +msgid "Operation not permitted" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" +msgstr "" + +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" +msgstr "" + +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" +msgstr "" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" +msgstr "" + +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/__init__.c +msgid "Peripheral in use" +msgstr "" + +#: py/moderrno.c +msgid "Permission denied" +msgstr "" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" +msgstr "" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" +msgstr "" + +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" +msgstr "" + +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" +msgstr "" + +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" +msgstr "" + +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" +msgstr "" + +#: shared-module/usb/core/Device.c +msgid "Pipe error" +msgstr "" + +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" +msgstr "" + +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" +msgstr "" + +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +msgstr "" + +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" +msgstr "" + +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" +msgstr "" + +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" +msgstr "" + +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" +msgstr "" + +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" +msgstr "" + +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" +msgstr "" + +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" +msgstr "" + +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" +msgstr "" + +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" +msgstr "" + +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" +msgstr "" + +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" +msgstr "" + +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" +msgstr "" + +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" +msgstr "" + +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" +msgstr "" + +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" +msgstr "" + +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" +msgstr "" + +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error %x" +msgstr "" + +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" +msgstr "" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + +#: ports/raspberrypi/common-hal/busio/SPI.c +msgid "SPI peripheral in use" +msgstr "" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" +msgstr "" + +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" +msgstr "" + +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "" + +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." +msgstr "" + +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" +msgstr "" + +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" +msgstr "" + +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" +msgstr "" + +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." +msgstr "" + +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" +msgstr "" + +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" +msgstr "" + +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." +msgstr "" + +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +msgstr "" + +#: shared-module/audiocore/__init__.c +msgid "The sample's %q does not match" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." +msgstr "" + +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." +msgstr "" + +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." +msgstr "" + +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" +msgstr "" + +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" +msgstr "" + +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" +msgstr "" + +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" +msgstr "" + +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" +msgstr "" + +#: shared-module/displayio/__init__.c +msgid "Too many displays" +msgstr "" + +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" +msgstr "" + +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" +msgstr "" + +#: py/obj.c +msgid "Traceback (most recent call last):\n" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" +msgstr "" + +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" +msgstr "" + +#: main.c +msgid "UID:" +msgstr "" + +#: shared-module/usb_hid/Device.c +msgid "USB busy" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." +msgstr "" + +#: shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "" + +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +msgstr "" + +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" +msgstr "" + +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." +msgstr "" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" +msgstr "" + +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" +msgstr "" + +#: py/parse.c +msgid "Unable to init parser" +msgstr "" + +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" +msgstr "" + +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" +msgstr "" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" +msgstr "" + +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." +msgstr "" + +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" +msgstr "" + +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." +msgstr "" + +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" +msgstr "" + +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" +msgstr "" + +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" +msgstr "" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown security error: 0x%04x" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" +msgstr "" + +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" +msgstr "" + +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" +msgstr "" + +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" +msgstr "" + +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" +msgstr "" + +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" +msgstr "" + +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" +msgstr "" + +#: main.c +msgid "WARNING: Your code filename has two extensions\n" +msgstr "" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +msgstr "" + +#: py/builtinhelp.c +#, c-format +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" +msgstr "" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" +msgstr "" + +#: main.c +msgid "Woken up by alarm.\n" +msgstr "" + +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" +msgstr "" + +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" +msgstr "" + +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "" + +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "" + +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "" + +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "" + +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "" + +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." +msgstr "" + +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + +#: py/objtype.c +msgid "__init__() should return None" +msgstr "" + +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" +msgstr "" + +#: py/objobject.c +msgid "__new__ arg must be a user-type" +msgstr "" + +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" +msgstr "" + +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" +msgstr "" + +#: py/compile.c +msgid "annotation must be an identifier" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" +msgstr "" + +#: py/modbuiltins.c +msgid "arg is an empty sequence" +msgstr "" + +#: py/objobject.c +msgid "arg must be user-type" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" + +#: py/compile.c +msgid "argument name reused" +msgstr "" + +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c +msgid "argument num/types mismatch" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "" + +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" +msgstr "" + +#: py/asmxtensa.c +msgid "asm overflow" +msgstr "" + +#: py/compile.c +msgid "async for/with outside async function" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" + +#: py/objstr.c +msgid "attributes not supported" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" +msgstr "" + +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" +msgstr "" + +#: py/builtinevex.c +msgid "bad compile mode" +msgstr "" + +#: py/objstr.c +msgid "bad conversion specifier" +msgstr "" + +#: py/objstr.c +msgid "bad format string" +msgstr "" + +#: py/binary.c py/objarray.c +msgid "bad typecode" +msgstr "" + +#: py/emitnative.c +msgid "binary op %q not implemented" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +msgid "bit_depth must be 8, 16, 24, or 32." +msgstr "" + +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" +msgstr "" + +#: extmod/modrandom.c +msgid "bits must be 32 or less" +msgstr "" + +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" +msgstr "" + +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" +msgstr "" + +#: py/emitinlinethumb.c +msgid "branch not in range" +msgstr "" + +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "" + +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "" + +#: shared-module/struct/__init__.c +msgid "buffer size must match format" +msgstr "" + +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" +msgstr "" + +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" +msgstr "" + +#: py/emitbc.c +msgid "bytecode overflow" +msgstr "" + +#: py/objarray.c +msgid "bytes length not a multiple of item size" +msgstr "" + +#: py/objstr.c +msgid "bytes value out of range" +msgstr "" + +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "" + +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "" + +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" +msgstr "" + +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" +msgstr "" + +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" +msgstr "" + +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "" + +#: py/objtype.c +msgid "can't add special method to already-subclassed class" +msgstr "" + +#: py/compile.c +msgid "can't assign to expression" +msgstr "" + +#: extmod/modasyncio.c +msgid "can't cancel self" +msgstr "" + +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" +msgstr "" + +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" +msgstr "" + +#: py/obj.c +#, c-format +msgid "can't convert %s to float" +msgstr "" + +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" +msgstr "" + +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "" + +#: py/obj.c +msgid "can't convert to complex" +msgstr "" + +#: py/obj.c +msgid "can't convert to float" +msgstr "" + +#: py/runtime.c +msgid "can't convert to int" +msgstr "" + +#: py/objstr.c +msgid "can't convert to str implicitly" +msgstr "" + +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + +#: py/compile.c +msgid "can't declare nonlocal in outer code" +msgstr "" + +#: py/compile.c +msgid "can't delete expression" +msgstr "" + +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't do unary op of '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" +msgstr "" + +#: py/runtime.c +msgid "can't import name %q" +msgstr "" + +#: py/emitnative.c +msgid "can't load from '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't load with '%q' index" +msgstr "" + +#: py/builtinimport.c +msgid "can't perform relative import" +msgstr "" + +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" +msgstr "" + +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" +msgstr "" + +#: py/runtime.c +msgid "can't set attribute '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't store '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't store to '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't store with '%q' index" +msgstr "" + +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" +msgstr "" + +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" +msgstr "" + +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" +msgstr "" + +#: extmod/modasyncio.c +msgid "can't wait" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "" + +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "" + +#: py/objtype.c +msgid "cannot create instance" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "" + +#: py/emitnative.c +msgid "casting" +msgstr "" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" +msgstr "" + +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" +msgstr "" + +#: py/modbuiltins.c +msgid "chr() arg not in range(0x110000)" +msgstr "" + +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" +msgstr "" + +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" +msgstr "" + +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +msgstr "" + +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" +msgstr "" + +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +msgstr "" + +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" +msgstr "" + +#: py/emitnative.c +msgid "comparison of int and uint" +msgstr "" + +#: py/objcomplex.c +msgid "complex divide by zero" +msgstr "" + +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" +msgstr "" + +#: extmod/modzlib.c +msgid "compression header" +msgstr "" + +#: py/emitnative.c +msgid "conversion to object" +msgstr "" + +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" + +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" + +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "" + +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "cs pin must be 1-4 positions above mosi pin" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "" + +#: py/parsenum.c +msgid "decimal numbers not supported" +msgstr "" + +#: py/compile.c +msgid "default 'except' must be last" +msgstr "" + +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +msgstr "" + +#: py/objdict.c +msgid "dict update sequence has wrong length" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "" + +#: py/emitnative.c +msgid "div/mod not implemented for uint" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "divide by zero" +msgstr "" + +#: py/runtime.c +msgid "division by zero" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" +msgstr "" + +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "" + +#: py/objdeque.c +msgid "empty" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "" + +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" +msgstr "" + +#: py/objstr.c +msgid "empty separator" +msgstr "" + +#: shared-bindings/random/__init__.c +msgid "empty sequence" +msgstr "" + +#: py/objstr.c +msgid "end of format while looking for conversion specifier" +msgstr "" + +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" +msgstr "" + +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" +msgstr "" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" +msgstr "" + +#: py/objstr.c +msgid "expected ':' after format specifier" +msgstr "" + +#: py/obj.c +msgid "expected tuple/list" +msgstr "" + +#: py/modthread.c +msgid "expecting a dict for keyword args" +msgstr "" + +#: py/compile.c +msgid "expecting an assembler instruction" +msgstr "" + +#: py/compile.c +msgid "expecting just a value for set" +msgstr "" + +#: py/compile.c +msgid "expecting key:value for dict" +msgstr "" + +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" +msgstr "" + +#: py/argcheck.c +msgid "extra keyword arguments given" +msgstr "" + +#: py/argcheck.c +msgid "extra positional arguments given" +msgstr "" + +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" +msgstr "" + +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "" + +#: py/objtype.c +msgid "first argument to super() must be type" +msgstr "" + +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "" + +#: py/objint.c +msgid "float too big" +msgstr "" + +#: py/nativeglue.c +msgid "float unsupported" +msgstr "" + +#: extmod/moddeflate.c +msgid "format" +msgstr "" + +#: py/objstr.c +msgid "format needs a dict" +msgstr "" + +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" +msgstr "" + +#: py/objdeque.c +msgid "full" +msgstr "" + +#: py/argcheck.c +msgid "function doesn't take keyword arguments" +msgstr "" + +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" +msgstr "" + +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "" + +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "" + +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" +msgstr "" + +#: py/bc.c +msgid "function missing keyword-only argument" +msgstr "" + +#: py/bc.c +msgid "function missing required keyword argument '%q'" +msgstr "" + +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" +msgstr "" + +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" +msgstr "" + +#: shared-bindings/mcp4822/MCP4822.c +msgid "gain must be 1 or 2" +msgstr "" + +#: py/objgenerator.c +msgid "generator already executing" +msgstr "" + +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" +msgstr "" + +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" +msgstr "" + +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "" + +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "" + +#: py/compile.c +msgid "identifier redefined as global" +msgstr "" + +#: py/compile.c +msgid "identifier redefined as nonlocal" +msgstr "" + +#: py/compile.c +msgid "import * not at module level" +msgstr "" + +#: py/persistentcode.c +msgid "incompatible .mpy arch" +msgstr "" + +#: py/persistentcode.c +msgid "incompatible .mpy file" +msgstr "" + +#: py/objstr.c +msgid "incomplete format" +msgstr "" + +#: py/objstr.c +msgid "incomplete format key" +msgstr "" + +#: extmod/modbinascii.c +msgid "incorrect padding" +msgstr "" + +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" + +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "" + +#: py/obj.c +msgid "indices must be integers" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "" + +#: py/compile.c +msgid "inline assembler must be a function" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "" + +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "" + +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "" + +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "" + +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "" + +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" + +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +#, c-format +msgid "interval must be in range %s-%s" +msgstr "" + +#: py/compile.c +msgid "invalid arch" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgstr "" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" +msgstr "" + +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" +msgstr "" + +#: py/objstr.c +msgid "invalid format specifier" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" +msgstr "" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" +msgstr "" + +#: py/compile.c +msgid "invalid micropython decorator" +msgstr "" + +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" +msgstr "" + +#: shared-bindings/random/__init__.c +msgid "invalid step" +msgstr "" + +#: py/compile.c py/parse.c +msgid "invalid syntax" +msgstr "" + +#: py/parsenum.c +msgid "invalid syntax for integer" +msgstr "" + +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" +msgstr "" + +#: py/parsenum.c +msgid "invalid syntax for number" +msgstr "" + +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" +msgstr "" + +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" + +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" +msgstr "" + +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" +msgstr "" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" +msgstr "" + +#: py/compile.c +msgid "label redefined" +msgstr "" + +#: py/objarray.c +msgid "lhs and rhs should be compatible" +msgstr "" + +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" +msgstr "" + +#: py/emitnative.c +msgid "local '%q' used before type known" +msgstr "" + +#: py/vm.c +msgid "local variable referenced before assignment" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" +msgstr "" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" +msgstr "" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" +msgstr "" + +#: py/parse.c +msgid "malformed f-string" +msgstr "" + +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" +msgstr "" + +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "" + +#: py/runtime.c +msgid "maximum recursion depth exceeded" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "" + +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" +msgstr "" + +#: py/runtime.c +msgid "memory allocation failed, heap is locked" +msgstr "" + +#: py/objarray.c +msgid "memoryview offset too large" +msgstr "" + +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" +msgstr "" + +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "" + +#: py/builtinimport.c +msgid "module not found" +msgstr "" + +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" + +#: py/compile.c +msgid "multiple *x in assignment" +msgstr "" + +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" +msgstr "" + +#: py/objtype.c +msgid "multiple inheritance not supported" +msgstr "" + +#: py/emitnative.c +msgid "must raise an object" +msgstr "" + +#: py/modbuiltins.c +msgid "must use keyword argument for key function" +msgstr "" + +#: py/runtime.c +msgid "name '%q' isn't defined" +msgstr "" + +#: py/runtime.c +msgid "name not defined" +msgstr "" + +#: py/qstr.c +msgid "name too long" +msgstr "" + +#: py/persistentcode.c +msgid "native code in .mpy unsupported" +msgstr "" + +#: py/asmthumb.c +msgid "native method too big" +msgstr "" + +#: py/emitnative.c +msgid "native yield" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "" + +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" +msgstr "" + +#: py/modmath.c +msgid "negative factorial" +msgstr "" + +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" +msgstr "" + +#: py/objint_mpz.c py/runtime.c +msgid "negative shift count" +msgstr "" + +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" +msgstr "" + +#: py/vm.c +msgid "no active exception to reraise" +msgstr "" + +#: py/compile.c +msgid "no binding for nonlocal found" +msgstr "" + +#: shared-module/msgpack/__init__.c +msgid "no default packer" +msgstr "" + +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" +msgstr "" + +#: py/builtinimport.c +msgid "no module named '%q'" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" +msgstr "" + +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" +msgstr "" + +#: py/compile.c +msgid "non-default argument follows default argument" +msgstr "" + +#: py/objstr.c +msgid "non-hex digit" +msgstr "" + +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" +msgstr "" + +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" +msgstr "" + +#: py/parse.c +msgid "not a constant" +msgstr "" + +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "" + +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "" + +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" + +#: py/builtinhelp.c +msgid "object " +msgstr "" + +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + +#: py/obj.c +msgid "object doesn't support item assignment" +msgstr "" + +#: py/obj.c +msgid "object doesn't support item deletion" +msgstr "" + +#: py/obj.c +msgid "object has no len" +msgstr "" + +#: py/obj.c +msgid "object isn't subscriptable" +msgstr "" + +#: py/runtime.c +msgid "object not an iterator" +msgstr "" + +#: py/objtype.c py/runtime.c +msgid "object not callable" +msgstr "" + +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" +msgstr "" + +#: py/runtime.c +msgid "object not iterable" +msgstr "" + +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" +msgstr "" + +#: py/obj.c +msgid "object with buffer protocol required" +msgstr "" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" +msgstr "" + +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" +msgstr "" + +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "" + +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "" + +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" +msgstr "" + +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" +msgstr "" + +#: py/vm.c +msgid "opcode" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" +msgstr "" + +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "" + +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "" + +#: py/modbuiltins.c +msgid "ord expects a character" +msgstr "" + +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" +msgstr "" + +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "" + +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" + +#: py/objint_mpz.c +msgid "overflow converting long int to machine word" +msgstr "" + +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" +msgstr "" + +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" +msgstr "" + +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" +msgstr "" + +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" +msgstr "" + +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" +msgstr "" + +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "" + +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" +msgstr "" + +#: py/compile.c +msgid "positional arg after **" +msgstr "" + +#: py/compile.c +msgid "positional arg after keyword arg" +msgstr "" + +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" +msgstr "" + +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" +msgstr "" + +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" + +#: py/builtinimport.c +msgid "relative import" +msgstr "" + +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" +msgstr "" + +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "" + +#: py/compile.c +msgid "return annotation must be an identifier" +msgstr "" + +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "" + +#: py/objstr.c +msgid "rsplit(None,n)" +msgstr "" + +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" +msgstr "" + +#: py/modmicropython.c +msgid "schedule queue full" +msgstr "" + +#: py/builtinimport.c +msgid "script compilation not supported" +msgstr "" + +#: py/nativeglue.c +msgid "set unsupported" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "" + +#: shared-module/msgpack/__init__.c +msgid "short read" +msgstr "" + +#: py/objstr.c +msgid "sign not allowed in string format specifier" +msgstr "" + +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" +msgstr "" + +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" + +#: py/nativeglue.c +msgid "slice unsupported" +msgstr "" + +#: py/objint.c py/sequence.c +msgid "small int overflow" +msgstr "" + +#: main.c +msgid "soft reboot\n" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" +msgstr "" + +#: extmod/modre.c +msgid "splitting with sub-captures" +msgstr "" + +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" +msgstr "" + +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" +msgstr "" + +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" +msgstr "" + +#: py/objstrunicode.c +msgid "string index out of range" +msgstr "" + +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" +msgstr "" + +#: py/objarray.c py/objstr.c +msgid "substring not found" +msgstr "" + +#: py/compile.c +msgid "super() can't find self" +msgstr "" + +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "" + +#: extmod/modtime.c +msgid "ticks interval overflow" +msgstr "" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" +msgstr "" + +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" +msgstr "" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" +msgstr "" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" +msgstr "" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" +msgstr "" + +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" + +#: py/compile.c +msgid "too many args" +msgstr "" + +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "" + +#: py/asmthumb.c +msgid "too many locals for native method" +msgstr "" + +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" +msgstr "" + +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "" + +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "" + +#: py/obj.c +msgid "tuple/list has wrong length" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" +msgstr "" + +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" +msgstr "" + +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" +msgstr "" + +#: py/objtype.c +msgid "type isn't an acceptable base type" +msgstr "" + +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" +msgstr "" + +#: py/objtype.c +msgid "type takes 1 or 3 arguments" +msgstr "" + +#: py/objint_longlong.c +msgid "ulonglong too large" +msgstr "" + +#: py/parse.c +msgid "unexpected indent" +msgstr "" + +#: py/bc.c +msgid "unexpected keyword argument" +msgstr "" + +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" +msgstr "" + +#: py/lexer.c +msgid "unicode name escapes" +msgstr "" + +#: py/parse.c +msgid "unindent doesn't match any outer indent level" +msgstr "" + +#: py/emitinlinerv32.c +msgid "unknown RV32 instruction '%q'" +msgstr "" + +#: py/objstr.c +#, c-format +msgid "unknown conversion specifier %c" +msgstr "" + +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" +msgstr "" + +#: py/compile.c +msgid "unknown type" +msgstr "" + +#: py/compile.c +msgid "unknown type '%q'" +msgstr "" + +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" +msgstr "" + +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" +msgstr "" + +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" +msgstr "" + +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" +msgstr "" + +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" +msgstr "" + +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" +msgstr "" + +#: py/runtime.c +msgid "unsupported type for %q: '%s'" +msgstr "" + +#: py/runtime.c +msgid "unsupported type for operator" +msgstr "" + +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" + +#: py/objint.c +#, c-format +msgid "value must fit in %d byte(s)" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" +msgstr "" + +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" + +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" +msgstr "" + +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +msgstr "" + +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" +msgstr "" + +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "" + +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" +msgstr "" + +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "" + +#: py/runtime.c +msgid "wrong number of values to unpack" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "" From 8bf51dbc821e051301a9a7057e6f2ea1a8a559fe Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 16:58:33 -0700 Subject: [PATCH 320/876] mtm_computer: set DAC gain 2x --- ports/raspberrypi/boards/mtm_computer/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index 9065ffebcf8..666d584af2c 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -20,7 +20,7 @@ static mp_obj_t board_dac_factory(void) { &pin_GPIO18, // clock (SCK) &pin_GPIO19, // mosi (SDI) &pin_GPIO21, // cs - 1); // gain 1x + 2); // gain 2x return MP_OBJ_FROM_PTR(dac); } MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); From bde1ee481ba54e15c462083c665518dec5977657 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 18:26:08 -0700 Subject: [PATCH 321/876] Revert "mtm_computer: set DAC gain 2x" This reverts commit 8bf51dbc821e051301a9a7057e6f2ea1a8a559fe. --- ports/raspberrypi/boards/mtm_computer/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index 666d584af2c..9065ffebcf8 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -20,7 +20,7 @@ static mp_obj_t board_dac_factory(void) { &pin_GPIO18, // clock (SCK) &pin_GPIO19, // mosi (SDI) &pin_GPIO21, // cs - 2); // gain 2x + 1); // gain 1x return MP_OBJ_FROM_PTR(dac); } MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); From 8529d44c8a1650f1cca9af07afad911977fcfd45 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Tue, 24 Mar 2026 12:50:23 -0400 Subject: [PATCH 322/876] Allow building and uploading native-sim executable --- ports/zephyr-cp/boards/native/native_sim/circuitpython.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml index 3272dd4c5f3..fbda7c563b8 100644 --- a/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml +++ b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml @@ -1 +1 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "exe"] From c2395d98770388ef8c6bfd9efe4e28448b18238a Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 09:51:01 -0700 Subject: [PATCH 323/876] fix zephyr builds by running update_boardnfo.py --- .../adafruit/feather_nrf52840_zephyr/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml | 1 + .../zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml | 1 + .../zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml | 1 + .../boards/renesas/da14695_dk_usb/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml | 1 + 17 files changed, 17 insertions(+) diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 9712f467858..277386cd1da 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 80b1b4ebf7d..dbf98f10768 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 1bc1b96e6cf..06f944e3e90 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 7869cca4faf..1e0cc856db1 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index c2233ddf8b5..a43e3169ada 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index a1e8de8822b..90203c4c0ec 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index b50b1966ed0..8f05a53587e 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 21d55194a1c..09f5cc6c580 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 90f84ab1586..e641099db76 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index eb5db066c89..d94b69eb813 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index d6efa285fe2..0874538a408 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 7600b8bbd15..b8657eb040a 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 8e49b95d334..04e75b39eee 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index b28a9481c72..e881b822190 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 6b0ef8d8480..6bdc58b12af 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index b6f03f3d627..ba745440b8d 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 8d1fd925348..dd571f02834 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false From f010f37f314188c441aeb3e0ea84a969b451f09b Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 24 Mar 2026 19:47:09 +0100 Subject: [PATCH 324/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 28 +++++++++------------------- locale/el.po | 28 +++++++++------------------- locale/hi.po | 28 +++++++++------------------- locale/ko.po | 28 +++++++++------------------- locale/ru.po | 37 ++++++++++++++++++------------------- locale/tr.po | 28 +++++++++------------------- 6 files changed, 63 insertions(+), 114 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 759d65d8760..d23583f4e6b 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -124,6 +124,7 @@ msgstr "%q v %q musí být typu %q, ne %q" #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -146,6 +147,7 @@ msgstr "Indexy %q musí být celá čísla, nikoli %s" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" msgstr "Inicializace %q selhala" @@ -177,8 +179,8 @@ msgstr "Délka %q musí být >= %d" msgid "%q must be %d" msgstr "%q musí být %d" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/is31fl3741/FrameBuffer.c #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -470,6 +472,7 @@ msgstr "∗x musí být cíl přiřazení" msgid ", in %q\n" msgstr ", v% q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -660,6 +663,7 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "Baudrate není podporován periférií" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -682,6 +686,7 @@ msgstr "Bootovací zařízení musí být první (rozhraní #0)." msgid "Both RX and TX required for flow control" msgstr "RX a TX jsou vyžadovány pro kontrolu toku" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid "Brightness not adjustable" @@ -873,7 +878,7 @@ msgstr "Pole souřadnic mají různé délky" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1040,10 +1045,6 @@ msgstr "Nepodařilo se alokovat paměť pro wifi scan" msgid "Failed to buffer the sample" msgstr "Nepodařilo se nabufferovat sample" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c #: ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -1163,6 +1164,7 @@ msgstr "Inicializace GNSS" msgid "Generic Failure" msgstr "Základní chyba" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -3264,10 +3266,6 @@ msgstr "" msgid "float unsupported" msgstr "float není podporován" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3349,10 +3347,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "generátor způsobil StopIteration" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "hash je konečný" @@ -4074,10 +4068,6 @@ msgstr "" msgid "pack expected %d items for packing (got %d)" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" diff --git a/locale/el.po b/locale/el.po index 872166169db..06a24a1486f 100644 --- a/locale/el.po +++ b/locale/el.po @@ -128,6 +128,7 @@ msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %q" #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -150,6 +151,7 @@ msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" msgstr "%q εκκίνηση απέτυχε" @@ -181,8 +183,8 @@ msgstr "%q μήκος πρέπει να είναι >= %d" msgid "%q must be %d" msgstr "%q πρέπει να είναι %d" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/is31fl3741/FrameBuffer.c #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -474,6 +476,7 @@ msgstr "*x πρέπει να είναι στόχος ανάθεσης" msgid ", in %q\n" msgstr ", στο %q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -664,6 +667,7 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "Baudrate δεν υποστηρίζεται από την περιφεριακή συσκευή" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -686,6 +690,7 @@ msgstr "Η συσκευή εκκίνησης πρέπει να επιλεχθε msgid "Both RX and TX required for flow control" msgstr "Και RX και TX απαιτούνται για έλεγχο flow" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid "Brightness not adjustable" @@ -879,7 +884,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1048,10 +1053,6 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c #: ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -1169,6 +1170,7 @@ msgstr "" msgid "Generic Failure" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -3263,10 +3265,6 @@ msgstr "" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3348,10 +3346,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -4073,10 +4067,6 @@ msgstr "" msgid "pack expected %d items for packing (got %d)" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index e0bb53003d7..a6d5cf49c0a 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -115,6 +115,7 @@ msgstr "" #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -137,6 +138,7 @@ msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" msgstr "" @@ -168,8 +170,8 @@ msgstr "" msgid "%q must be %d" msgstr "" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/is31fl3741/FrameBuffer.c #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -461,6 +463,7 @@ msgstr "" msgid ", in %q\n" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -649,6 +652,7 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -671,6 +675,7 @@ msgstr "" msgid "Both RX and TX required for flow control" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid "Brightness not adjustable" @@ -858,7 +863,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1024,10 +1029,6 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c #: ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -1145,6 +1146,7 @@ msgstr "" msgid "Generic Failure" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -3237,10 +3239,6 @@ msgstr "" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3322,10 +3320,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -4047,10 +4041,6 @@ msgstr "" msgid "pack expected %d items for packing (got %d)" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 09f4776dfde..cc65afaa7c0 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -126,6 +126,7 @@ msgstr "%q의 %q는 %q가 아니라 %q 유형이어야 합니다" #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -148,6 +149,7 @@ msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" msgstr "%q 초기화 실패" @@ -179,8 +181,8 @@ msgstr "%q 길이는 >= %d이어야 합니다" msgid "%q must be %d" msgstr "%q는 %d이어야 합니다" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/is31fl3741/FrameBuffer.c #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -489,6 +491,7 @@ msgstr "*x는 할당 대상이어야 합니다" msgid ", in %q\n" msgstr ", 에서 %q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -690,6 +693,7 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "주변 기기에서 전송 속도가 지원되지 않습니다" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -712,6 +716,7 @@ msgstr "부팅 장치는 첫 번째(인터페이스 #0)여야 합니다." msgid "Both RX and TX required for flow control" msgstr "플로우 제어에 RX와 TX가 모두 필요합니다" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid "Brightness not adjustable" @@ -902,7 +907,7 @@ msgstr "좌표 배열의 길이가 다릅니다" msgid "Coordinate arrays types have different sizes" msgstr "좌표 배열 유형은 크기가 다릅니다" -#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1072,10 +1077,6 @@ msgstr "wifi 검색 메모리 할당에 실패했습니다" msgid "Failed to buffer the sample" msgstr "샘플 버퍼링에 실패했습니다" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c #: ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -1196,6 +1197,7 @@ msgstr "GNSS 초기화" msgid "Generic Failure" msgstr "일반 오류" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -3311,10 +3313,6 @@ msgstr "float이 너무 큽니다" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3396,10 +3394,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -4121,10 +4115,6 @@ msgstr "" msgid "pack expected %d items for packing (got %d)" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 2c68943f6e4..7f31c3a73a6 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -128,6 +128,7 @@ msgstr "%q в %q должно быть типа %q, а не %q" #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -150,6 +151,7 @@ msgstr "Индексы %q должны быть целыми числами, а #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" msgstr "Инициализация %q не удалась" @@ -181,8 +183,8 @@ msgstr "Длинна %q должна быть >= %d" msgid "%q must be %d" msgstr "%q должно быть %d" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/is31fl3741/FrameBuffer.c #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -474,6 +476,7 @@ msgstr "*x должно быть целью назначения" msgid ", in %q\n" msgstr ", в %q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -664,6 +667,7 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "Скорость передачи данных не поддерживается периферийным устройством" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -687,6 +691,7 @@ msgstr "Загрузочное устройство должно быть пер msgid "Both RX and TX required for flow control" msgstr "Для управления потоком требуется как RX так и TX" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid "Brightness not adjustable" @@ -882,7 +887,7 @@ msgstr "Координатные массивы имеют разные длин msgid "Coordinate arrays types have different sizes" msgstr "Типы массивов координат имеют разные размеры" -#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1053,10 +1058,6 @@ msgstr "Не удалось выделить память для сканиро msgid "Failed to buffer the sample" msgstr "Не удалось выполнить буферизацию образца" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c #: ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -1180,6 +1181,7 @@ msgstr "Инициализация GNSS" msgid "Generic Failure" msgstr "Общий сбой" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -3318,10 +3320,6 @@ msgstr "Поплавок слишком большой" msgid "float unsupported" msgstr "Плавающий без поддержки" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "Длина шрифта должна составлять 2048 байт" - #: extmod/moddeflate.c msgid "format" msgstr "формат" @@ -3403,10 +3401,6 @@ msgstr "генератор проигнорировал Выход" msgid "generator raised StopIteration" msgstr "генератор поднят Остановить итерацию" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "Длина рисунка должна составлять 2048 байт" - #: extmod/modhashlib.c msgid "hash is final" msgstr "хэш является окончательным" @@ -4136,10 +4130,6 @@ msgstr "переполнение преобразование длинного msgid "pack expected %d items for packing (got %d)" msgstr "Упаковка ожидаемых %d товаров для упаковки (получил %d)" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "Длина палитры должна составлять 32 байта" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" @@ -4671,6 +4661,15 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#~ msgid "font must be 2048 bytes long" +#~ msgstr "Длина шрифта должна составлять 2048 байт" + +#~ msgid "graphic must be 2048 bytes long" +#~ msgstr "Длина рисунка должна составлять 2048 байт" + +#~ msgid "palette must be 32 bytes long" +#~ msgstr "Длина палитры должна составлять 32 байта" + #, c-format #~ msgid "Buffer + offset too small %d %d %d" #~ msgstr "Буфер + сдвиг слишком малы %d %d %d" diff --git a/locale/tr.po b/locale/tr.po index d9d90eddfe8..96037c5426f 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -126,6 +126,7 @@ msgstr "" #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #: ports/mimxrt10xx/common-hal/audiobusio/__init__.c #: ports/mimxrt10xx/common-hal/usb_host/Port.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -148,6 +149,7 @@ msgstr "%q indeksleri integer olmalı, %s değil" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" msgstr "%q init başarısız oldu" @@ -179,8 +181,8 @@ msgstr "%q boyutu >= %d olmalıdır" msgid "%q must be %d" msgstr "%q, %d olmalıdır" -#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/displayio/Bitmap.c +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/is31fl3741/FrameBuffer.c #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -472,6 +474,7 @@ msgstr "*x atama hedefi olmalıdır" msgid ", in %q\n" msgstr ", içinde %q\n" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/epaperdisplay/EPaperDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c @@ -662,6 +665,7 @@ msgstr "" msgid "Baudrate not supported by peripheral" msgstr "Baudhızı, çevre birimi tarafından desteklenmiyor" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c msgid "Below minimum frame rate" @@ -684,6 +688,7 @@ msgstr "" msgid "Both RX and TX required for flow control" msgstr "Hem RX hem de TX akış kontrolü için gerekli" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/busdisplay/BusDisplay.c #: shared-bindings/framebufferio/FramebufferDisplay.c msgid "Brightness not adjustable" @@ -872,7 +877,7 @@ msgstr "" msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-module/usb/core/Device.c ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" msgstr "" @@ -1038,10 +1043,6 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c #: ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -1163,6 +1164,7 @@ msgstr "GNSS init" msgid "Generic Failure" msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-module/busdisplay/BusDisplay.c #: shared-module/framebufferio/FramebufferDisplay.c @@ -3259,10 +3261,6 @@ msgstr "" msgid "float unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "font must be 2048 bytes long" -msgstr "" - #: extmod/moddeflate.c msgid "format" msgstr "" @@ -3344,10 +3342,6 @@ msgstr "" msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "graphic must be 2048 bytes long" -msgstr "" - #: extmod/modhashlib.c msgid "hash is final" msgstr "" @@ -4069,10 +4063,6 @@ msgstr "" msgid "pack expected %d items for packing (got %d)" msgstr "" -#: shared-bindings/_stage/Layer.c shared-bindings/_stage/Text.c -msgid "palette must be 32 bytes long" -msgstr "" - #: py/emitinlinerv32.c msgid "parameters must be registers in sequence a0 to a3" msgstr "" From 2de067b1c08d28a16d7dfae47f1de2efaf8dc990 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 14:46:04 -0700 Subject: [PATCH 325/876] mcp4822 gain argument fix, as per requested --- shared-bindings/mcp4822/MCP4822.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/shared-bindings/mcp4822/MCP4822.c b/shared-bindings/mcp4822/MCP4822.c index c48f5426e66..f192caf4052 100644 --- a/shared-bindings/mcp4822/MCP4822.c +++ b/shared-bindings/mcp4822/MCP4822.c @@ -81,11 +81,7 @@ static mp_obj_t mcp4822_mcp4822_make_new(const mp_obj_type_t *type, size_t n_arg const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); - - mp_int_t gain = args[ARG_gain].u_int; - if (gain != 1 && gain != 2) { - mp_raise_ValueError(MP_ERROR_TEXT("gain must be 1 or 2")); - } + const mp_int_t gain = mp_arg_validate_int_range(args[ARG_gain].u_int, 1, 2, MP_QSTR_gain); mcp4822_mcp4822_obj_t *self = mp_obj_malloc_with_finaliser(mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); common_hal_mcp4822_mcp4822_construct(self, clock, mosi, cs, (uint8_t)gain); From ad21609394514b0227f84da8632e8dcf95a44c15 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 14:46:57 -0700 Subject: [PATCH 326/876] mcp4822 gain argument fix, as per requested --- locale/circuitpython.pot | 4 ---- 1 file changed, 4 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 5d0be48fe3a..8bfc2d5bde3 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -3310,10 +3310,6 @@ msgstr "" msgid "function takes %d positional arguments but %d were given" msgstr "" -#: shared-bindings/mcp4822/MCP4822.c -msgid "gain must be 1 or 2" -msgstr "" - #: py/objgenerator.c msgid "generator already executing" msgstr "" From dd1c9572ec2f780a518ed78486331c4989dc51d0 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 14:56:30 -0700 Subject: [PATCH 327/876] mtm_computer: make board.DAC() an actual singleton --- ports/raspberrypi/boards/mtm_computer/board.c | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index 9065ffebcf8..0b1e34eaacd 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -12,16 +12,22 @@ // board.DAC() — factory function that constructs an mcp4822.MCP4822 with // the MTM Workshop Computer's DAC pins (GP18=SCK, GP19=SDI, GP21=CS). + +static mp_obj_t board_dac_singleton = MP_OBJ_NULL; + static mp_obj_t board_dac_factory(void) { - mcp4822_mcp4822_obj_t *dac = mp_obj_malloc_with_finaliser( - mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); - common_hal_mcp4822_mcp4822_construct( - dac, - &pin_GPIO18, // clock (SCK) - &pin_GPIO19, // mosi (SDI) - &pin_GPIO21, // cs - 1); // gain 1x - return MP_OBJ_FROM_PTR(dac); + if (board_dac_singleton == MP_OBJ_NULL) { + mcp4822_mcp4822_obj_t *dac = mp_obj_malloc_with_finaliser( + mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); + common_hal_mcp4822_mcp4822_construct( + dac, + &pin_GPIO18, // clock (SCK) + &pin_GPIO19, // mosi (SDI) + &pin_GPIO21, // cs + 1); // gain 1x + board_dac_singleton = MP_OBJ_FROM_PTR(dac); + } + return board_dac_singleton; } MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); From 5bd2a4233509830083f42008de8a10cb68ef39c3 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 15:21:02 -0700 Subject: [PATCH 328/876] mtm_computer: make sure board.DAC() gets deallocated on board deinit --- ports/raspberrypi/boards/mtm_computer/board.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index 0b1e34eaacd..4fec0cd5b8b 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -31,4 +31,10 @@ static mp_obj_t board_dac_factory(void) { } MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); +void board_deinit(void) { + if (board_dac_singleton != MP_OBJ_NULL) { + common_hal_mcp4822_mcp4822_deinit(MP_OBJ_TO_PTR(board_dac_singleton)); + board_dac_singleton = MP_OBJ_NULL; + } +} // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. From 13d6feac4dfcc58cec6e870bd0dfe1544084f0dd Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 15:21:28 -0700 Subject: [PATCH 329/876] mcp4822 CS/MOSI argument fix, as per requested --- ports/raspberrypi/common-hal/mcp4822/MCP4822.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/raspberrypi/common-hal/mcp4822/MCP4822.c b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c index cb6cddb8343..7a8ad7d4df2 100644 --- a/ports/raspberrypi/common-hal/mcp4822/MCP4822.c +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c @@ -143,8 +143,7 @@ void common_hal_mcp4822_mcp4822_construct(mcp4822_mcp4822_obj_t *self, // The SET pin group spans from MOSI to CS. // MOSI must have a lower GPIO number than CS, gap at most 4. if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { - mp_raise_ValueError( - MP_ERROR_TEXT("cs pin must be 1-4 positions above mosi pin")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q and %q"), MP_QSTR_CS, MP_QSTR_MOSI); } uint8_t set_count = cs->number - mosi->number + 1; From 62ffc25927d62a8ddbc3322e6e43fab71185ba08 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 15:21:55 -0700 Subject: [PATCH 330/876] mcp4822 CS/MOSI argument fix, as per requested --- locale/circuitpython.pot | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 8bfc2d5bde3..57c0a13e991 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1297,6 +1297,7 @@ msgstr "" msgid "Invalid %q" msgstr "" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" @@ -3040,10 +3041,6 @@ msgstr "" msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "cs pin must be 1-4 positions above mosi pin" -msgstr "" - #: extmod/ulab/code/scipy/optimize/optimize.c msgid "data must be iterable" msgstr "" From bec871e9c608a2364a639b100ae8051ae5f050c9 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Sat, 21 Mar 2026 10:13:02 -0700 Subject: [PATCH 331/876] mtm_computer: Add DAC audio out module --- .../boards/mtm_computer/module/DACOut.c | 276 ++++++++++++++++++ .../boards/mtm_computer/module/DACOut.h | 38 +++ .../boards/mtm_computer/mpconfigboard.mk | 7 + 3 files changed, 321 insertions(+) create mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.c create mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.h diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c new file mode 100644 index 00000000000..84f4296cb00 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c @@ -0,0 +1,276 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT +// +// MCP4822 dual-channel 12-bit SPI DAC driver for the MTM Workshop Computer. +// Uses PIO + DMA for non-blocking audio playback, mirroring audiobusio.I2SOut. + +#include +#include + +#include "mpconfigport.h" + +#include "py/gc.h" +#include "py/mperrno.h" +#include "py/runtime.h" +#include "boards/mtm_computer/module/DACOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" +#include "bindings/rp2pio/StateMachine.h" + +// ───────────────────────────────────────────────────────────────────────────── +// PIO program for MCP4822 SPI DAC +// ───────────────────────────────────────────────────────────────────────────── +// +// Pin assignment: +// OUT pin (1) = MOSI — serial data out +// SET pins (N) = MOSI through CS — for CS control & command-bit injection +// SIDE-SET pin (1) = SCK — serial clock +// +// On the MTM Workshop Computer: MOSI=GP19, CS=GP21, SCK=GP18. +// The SET group spans GP19..GP21 (3 pins). GP20 is unused and driven low. +// +// SET PINS bit mapping (bit0=MOSI/GP19, bit1=GP20, bit2=CS/GP21): +// 0 = CS low, MOSI low 1 = CS low, MOSI high 4 = CS high, MOSI low +// +// SIDE-SET (1 pin, SCK): side 0 = SCK low, side 1 = SCK high +// +// MCP4822 16-bit command word: +// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x) +// [12] output enable (1) [11:0] 12-bit data +// +// DMA feeds unsigned 16-bit audio samples. RP2040 narrow-write replication +// fills both halves of the 32-bit PIO FIFO entry with the same value, +// giving mono→stereo for free. +// +// The PIO pulls 32 bits, then sends two SPI transactions: +// Channel A: cmd nibble 0b0011, then all 16 sample bits from upper half-word +// Channel B: cmd nibble 0b1011, then all 16 sample bits from lower half-word +// The MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data), +// so only the top 12 of the 16 sample bits become DAC data. The bottom +// 4 sample bits clock out harmlessly after the DAC has latched. +// This gives correct 16-bit → 12-bit scaling (effectively sample >> 4). +// +// PIO instruction encoding with .side_set 1 (no opt): +// [15:13] opcode [12] side-set [11:8] delay [7:0] operands +// +// Total: 26 instructions, 86 PIO clocks per audio sample. +// ───────────────────────────────────────────────────────────────────────────── + +static const uint16_t mcp4822_pio_program[] = { + // side SCK + // 0: pull noblock side 0 ; Get 32 bits or keep X if FIFO empty + 0x8080, + // 1: mov x, osr side 0 ; Save for pull-noblock fallback + 0xA027, + + // ── Channel A: command nibble 0b0011 ────────────────────────────────── + // Send 4 cmd bits via SET, then all 16 sample bits via OUT. + // MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data); + // the extra 4 clocks shift out the LSBs which the DAC ignores. + // This gives correct 16→12 bit scaling (top 12 bits become DAC data). + // 2: set pins, 0 side 0 ; CS low, MOSI=0 (bit15=0: channel A) + 0xE000, + // 3: nop side 1 ; SCK high — latch bit 15 + 0xB042, + // 4: set pins, 0 side 0 ; MOSI=0 (bit14=0: don't care) + 0xE000, + // 5: nop side 1 ; SCK high + 0xB042, + // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + 0xE001, + // 7: nop side 1 ; SCK high + 0xB042, + // 8: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) + 0xE001, + // 9: nop side 1 ; SCK high + 0xB042, + // 10: set y, 15 side 0 ; Loop counter: 16 sample bits + 0xE04F, + // 11: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopA) + 0x6001, + // 12: jmp y--, 11 side 1 ; SCK high, loop back + 0x108B, + // 13: set pins, 4 side 0 ; CS high — DAC A latches + 0xE004, + + // ── Channel B: command nibble 0b1011 ────────────────────────────────── + // 14: set pins, 1 side 0 ; CS low, MOSI=1 (bit15=1: channel B) + 0xE001, + // 15: nop side 1 ; SCK high + 0xB042, + // 16: set pins, 0 side 0 ; MOSI=0 (bit14=0) + 0xE000, + // 17: nop side 1 ; SCK high + 0xB042, + // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) + 0xE001, + // 19: nop side 1 ; SCK high + 0xB042, + // 20: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) + 0xE001, + // 21: nop side 1 ; SCK high + 0xB042, + // 22: set y, 15 side 0 ; Loop counter: 16 sample bits + 0xE04F, + // 23: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopB) + 0x6001, + // 24: jmp y--, 23 side 1 ; SCK high, loop back + 0x1097, + // 25: set pins, 4 side 0 ; CS high — DAC B latches + 0xE004, +}; + +// Clocks per sample: 2 (pull+mov) + 42 (chanA) + 42 (chanB) = 86 +// Per channel: 8(4 cmd bits × 2 clks) + 1(set y) + 32(16 bits × 2 clks) + 1(cs high) = 42 +#define MCP4822_CLOCKS_PER_SAMPLE 86 + + +void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs) { + + // SET pins span from MOSI to CS. MOSI must have a lower GPIO number + // than CS, with at most 4 pins between them (SET count max is 5). + if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { + mp_raise_ValueError( + MP_COMPRESSED_ROM_TEXT("cs pin must be 1-4 positions above mosi pin")); + } + + uint8_t set_count = cs->number - mosi->number + 1; + + // Initial SET pin state: CS high (bit at CS position), others low + uint32_t cs_bit_position = cs->number - mosi->number; + pio_pinmask32_t initial_set_state = PIO_PINMASK32_FROM_VALUE(1u << cs_bit_position); + pio_pinmask32_t initial_set_dir = PIO_PINMASK32_FROM_VALUE((1u << set_count) - 1); + + common_hal_rp2pio_statemachine_construct( + &self->state_machine, + mcp4822_pio_program, MP_ARRAY_SIZE(mcp4822_pio_program), + 44100 * MCP4822_CLOCKS_PER_SAMPLE, // Initial frequency; play() adjusts + NULL, 0, // No init program + NULL, 0, // No may_exec + mosi, 1, // OUT: MOSI, 1 pin + PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // OUT state=low, dir=output + NULL, 0, // IN: none + PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // IN pulls: none + mosi, set_count, // SET: MOSI..CS + initial_set_state, initial_set_dir, // SET state (CS high), dir=output + clock, 1, false, // SIDE-SET: SCK, 1 pin, not pindirs + PIO_PINMASK32_NONE, // SIDE-SET state: SCK low + PIO_PINMASK32_FROM_VALUE(0x1), // SIDE-SET dir: output + false, // No sideset enable + NULL, PULL_NONE, // No jump pin + PIO_PINMASK_NONE, // No wait GPIO + true, // Exclusive pin use + false, 32, false, // OUT shift: no autopull, 32-bit, shift left + false, // Don't wait for txstall + false, 32, false, // IN shift (unused) + false, // Not user-interruptible + 0, -1, // Wrap: whole program + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, + PIO_MOV_N_DEFAULT + ); + + self->playing = false; + audio_dma_init(&self->dma); +} + +bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self) { + return common_hal_rp2pio_statemachine_deinited(&self->state_machine); +} + +void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self) { + if (common_hal_mtm_hardware_dacout_deinited(self)) { + return; + } + if (common_hal_mtm_hardware_dacout_get_playing(self)) { + common_hal_mtm_hardware_dacout_stop(self); + } + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + audio_dma_deinit(&self->dma); +} + +void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, + mp_obj_t sample, bool loop) { + + if (common_hal_mtm_hardware_dacout_get_playing(self)) { + common_hal_mtm_hardware_dacout_stop(self); + } + + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); + if (bits_per_sample < 16) { + bits_per_sample = 16; + } + + uint32_t sample_rate = audiosample_get_sample_rate(sample); + uint8_t channel_count = audiosample_get_channel_count(sample); + if (channel_count > 2) { + mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("Too many channels in sample.")); + } + + // PIO clock = sample_rate × clocks_per_sample + common_hal_rp2pio_statemachine_set_frequency( + &self->state_machine, + (uint32_t)sample_rate * MCP4822_CLOCKS_PER_SAMPLE); + common_hal_rp2pio_statemachine_restart(&self->state_machine); + + // DMA feeds unsigned 16-bit samples. The PIO discards the top 4 bits + // of each 16-bit half and uses the remaining 12 as DAC data. + // RP2040 narrow-write replication: 16-bit DMA write → same value in + // both 32-bit FIFO halves → mono-to-stereo for free. + audio_dma_result result = audio_dma_setup_playback( + &self->dma, + sample, + loop, + false, // single_channel_output + 0, // audio_channel + false, // output_signed = false (unsigned for MCP4822) + bits_per_sample, // output_resolution + (uint32_t)&self->state_machine.pio->txf[self->state_machine.state_machine], + self->state_machine.tx_dreq, + false); // swap_channel + + if (result == AUDIO_DMA_DMA_BUSY) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("No DMA channel found")); + } else if (result == AUDIO_DMA_MEMORY_ERROR) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Unable to allocate buffers for signed conversion")); + } else if (result == AUDIO_DMA_SOURCE_ERROR) { + common_hal_mtm_hardware_dacout_stop(self); + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Audio source error")); + } + + self->playing = true; +} + +void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self) { + audio_dma_pause(&self->dma); +} + +void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self) { + audio_dma_resume(&self->dma); +} + +bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self) { + return audio_dma_get_paused(&self->dma); +} + +void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self) { + audio_dma_stop(&self->dma); + common_hal_rp2pio_statemachine_stop(&self->state_machine); + self->playing = false; +} + +bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self) { + bool playing = audio_dma_get_playing(&self->dma); + if (!playing && self->playing) { + common_hal_mtm_hardware_dacout_stop(self); + } + return playing; +} diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h new file mode 100644 index 00000000000..f7c0c9eb806 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/rp2pio/StateMachine.h" + +#include "audio_dma.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + rp2pio_statemachine_obj_t state_machine; + audio_dma_t dma; + bool playing; +} mtm_hardware_dacout_obj_t; + +void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, + const mcu_pin_obj_t *cs); + +void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); + +void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, + mp_obj_t sample, bool loop); +void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self); + +void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self); +void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self); +bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self); + +extern const mp_obj_type_t mtm_hardware_dacout_type; diff --git a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk index 45c99711d72..0383e0777fa 100644 --- a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk +++ b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk @@ -11,4 +11,11 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_AUDIOEFFECTS = 1 CIRCUITPY_IMAGECAPTURE = 0 CIRCUITPY_PICODVI = 0 +<<<<<<< HEAD CIRCUITPY_MCP4822 = 1 +======= + +SRC_C += \ + boards/$(BOARD)/module/mtm_hardware.c \ + boards/$(BOARD)/module/DACOut.c +>>>>>>> d8bbe2a87f (mtm_computer: Add DAC audio out module) From 7e66d51d93b43a12e7b32ca2ba76d522256384f3 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Sat, 21 Mar 2026 10:33:40 -0700 Subject: [PATCH 332/876] mtm_hardware.c added --- .../boards/mtm_computer/module/mtm_hardware.c | 267 ++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c new file mode 100644 index 00000000000..a3dafbcf941 --- /dev/null +++ b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c @@ -0,0 +1,267 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT +// +// Python bindings for the mtm_hardware module. +// Provides DACOut: a non-blocking audio player for the MCP4822 SPI DAC. + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/util.h" +#include "boards/mtm_computer/module/DACOut.h" + +// ───────────────────────────────────────────────────────────────────────────── +// DACOut class +// ───────────────────────────────────────────────────────────────────────────── + +//| class DACOut: +//| """Output audio to the MCP4822 dual-channel 12-bit SPI DAC.""" +//| +//| def __init__( +//| self, +//| clock: microcontroller.Pin, +//| mosi: microcontroller.Pin, +//| cs: microcontroller.Pin, +//| ) -> None: +//| """Create a DACOut object associated with the given SPI pins. +//| +//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin +//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin +//| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| +//| Simple 8ksps 440 Hz sine wave:: +//| +//| import mtm_hardware +//| import audiocore +//| import board +//| import array +//| import time +//| import math +//| +//| length = 8000 // 440 +//| sine_wave = array.array("H", [0] * length) +//| for i in range(length): +//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) +//| +//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) +//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(sine_wave, loop=True) +//| time.sleep(1) +//| dac.stop() +//| +//| Playing a wave file from flash:: +//| +//| import board +//| import audiocore +//| import mtm_hardware +//| +//| f = open("sound.wav", "rb") +//| wav = audiocore.WaveFile(f) +//| +//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) +//| dac.play(wav) +//| while dac.playing: +//| pass""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_clock, ARG_mosi, ARG_cs }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); + const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); + const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + + mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); + common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs); + + return MP_OBJ_FROM_PTR(self); +} + +static void check_for_deinit(mtm_hardware_dacout_obj_t *self) { + if (common_hal_mtm_hardware_dacout_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Deinitialises the DACOut and releases any hardware resources for reuse.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_deinit(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_mtm_hardware_dacout_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_deinit_obj, mtm_hardware_dacout_deinit); + +//| def __enter__(self) -> DACOut: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. +//| +//| The sample itself should consist of 8 bit or 16 bit samples.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_mtm_hardware_dacout_play(self, sample, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(mtm_hardware_dacout_play_obj, 1, mtm_hardware_dacout_obj_play); + +//| def stop(self) -> None: +//| """Stops playback.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_stop(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_mtm_hardware_dacout_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_stop_obj, mtm_hardware_dacout_obj_stop); + +//| playing: bool +//| """True when the audio sample is being output. (read-only)""" +//| +static mp_obj_t mtm_hardware_dacout_obj_get_playing(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_playing_obj, mtm_hardware_dacout_obj_get_playing); + +MP_PROPERTY_GETTER(mtm_hardware_dacout_playing_obj, + (mp_obj_t)&mtm_hardware_dacout_get_playing_obj); + +//| def pause(self) -> None: +//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_pause(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (!common_hal_mtm_hardware_dacout_get_playing(self)) { + mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Not playing")); + } + common_hal_mtm_hardware_dacout_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_pause_obj, mtm_hardware_dacout_obj_pause); + +//| def resume(self) -> None: +//| """Resumes sample playback after :py:func:`pause`.""" +//| ... +//| +static mp_obj_t mtm_hardware_dacout_obj_resume(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + if (common_hal_mtm_hardware_dacout_get_paused(self)) { + common_hal_mtm_hardware_dacout_resume(self); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_resume_obj, mtm_hardware_dacout_obj_resume); + +//| paused: bool +//| """True when playback is paused. (read-only)""" +//| +static mp_obj_t mtm_hardware_dacout_obj_get_paused(mp_obj_t self_in) { + mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_paused_obj, mtm_hardware_dacout_obj_get_paused); + +MP_PROPERTY_GETTER(mtm_hardware_dacout_paused_obj, + (mp_obj_t)&mtm_hardware_dacout_get_paused_obj); + +// ── DACOut type definition ─────────────────────────────────────────────────── + +static const mp_rom_map_elem_t mtm_hardware_dacout_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mtm_hardware_dacout_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mtm_hardware_dacout_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mtm_hardware_dacout_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mtm_hardware_dacout_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mtm_hardware_dacout_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mtm_hardware_dacout_paused_obj) }, +}; +static MP_DEFINE_CONST_DICT(mtm_hardware_dacout_locals_dict, mtm_hardware_dacout_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + mtm_hardware_dacout_type, + MP_QSTR_DACOut, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, mtm_hardware_dacout_make_new, + locals_dict, &mtm_hardware_dacout_locals_dict + ); + +// ───────────────────────────────────────────────────────────────────────────── +// mtm_hardware module definition +// ───────────────────────────────────────────────────────────────────────────── + +//| """Hardware interface to Music Thing Modular Workshop Computer peripherals. +//| +//| Provides the `DACOut` class for non-blocking audio output via the +//| MCP4822 dual-channel 12-bit SPI DAC. +//| """ + +static const mp_rom_map_elem_t mtm_hardware_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mtm_hardware) }, + { MP_ROM_QSTR(MP_QSTR_DACOut), MP_ROM_PTR(&mtm_hardware_dacout_type) }, +}; + +static MP_DEFINE_CONST_DICT(mtm_hardware_module_globals, mtm_hardware_module_globals_table); + +const mp_obj_module_t mtm_hardware_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&mtm_hardware_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_mtm_hardware, mtm_hardware_module); From eb3fd7080b8651156427649fd4975f876083073d Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 12:58:15 -0700 Subject: [PATCH 333/876] mtm_hardware.dacout: add gain=1 or gain=2 argument --- .../boards/mtm_computer/module/DACOut.c | 21 +++++++++++++++++-- .../boards/mtm_computer/module/DACOut.h | 2 +- .../boards/mtm_computer/module/mtm_hardware.c | 13 ++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c index 84f4296cb00..fb4ce37d4d0 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c @@ -128,9 +128,19 @@ static const uint16_t mcp4822_pio_program[] = { #define MCP4822_CLOCKS_PER_SAMPLE 86 +// MCP4822 gain bit (bit 13) position in the PIO program: +// Instruction 6 = channel A gain bit +// Instruction 18 = channel B gain bit +// 1x gain: set pins, 1 (0xE001) — bit 13 = 1 +// 2x gain: set pins, 0 (0xE000) — bit 13 = 0 +#define MCP4822_PIO_GAIN_INSTR_A 6 +#define MCP4822_PIO_GAIN_INSTR_B 18 +#define MCP4822_PIO_GAIN_1X 0xE001 // set pins, 1 +#define MCP4822_PIO_GAIN_2X 0xE000 // set pins, 0 + void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs) { + const mcu_pin_obj_t *cs, uint8_t gain) { // SET pins span from MOSI to CS. MOSI must have a lower GPIO number // than CS, with at most 4 pins between them (SET count max is 5). @@ -141,6 +151,13 @@ void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, uint8_t set_count = cs->number - mosi->number + 1; + // Build a mutable copy of the PIO program and patch the gain bit + uint16_t program[MP_ARRAY_SIZE(mcp4822_pio_program)]; + memcpy(program, mcp4822_pio_program, sizeof(mcp4822_pio_program)); + uint16_t gain_instr = (gain == 2) ? MCP4822_PIO_GAIN_2X : MCP4822_PIO_GAIN_1X; + program[MCP4822_PIO_GAIN_INSTR_A] = gain_instr; + program[MCP4822_PIO_GAIN_INSTR_B] = gain_instr; + // Initial SET pin state: CS high (bit at CS position), others low uint32_t cs_bit_position = cs->number - mosi->number; pio_pinmask32_t initial_set_state = PIO_PINMASK32_FROM_VALUE(1u << cs_bit_position); @@ -148,7 +165,7 @@ void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, common_hal_rp2pio_statemachine_construct( &self->state_machine, - mcp4822_pio_program, MP_ARRAY_SIZE(mcp4822_pio_program), + program, MP_ARRAY_SIZE(mcp4822_pio_program), 44100 * MCP4822_CLOCKS_PER_SAMPLE, // Initial frequency; play() adjusts NULL, 0, // No init program NULL, 0, // No may_exec diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h index f7c0c9eb806..f9b5dd60108 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h +++ b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h @@ -21,7 +21,7 @@ typedef struct { void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs); + const mcu_pin_obj_t *cs, uint8_t gain); void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c index a3dafbcf941..8f875496f67 100644 --- a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c +++ b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c @@ -29,12 +29,15 @@ //| clock: microcontroller.Pin, //| mosi: microcontroller.Pin, //| cs: microcontroller.Pin, +//| *, +//| gain: int = 1, //| ) -> None: //| """Create a DACOut object associated with the given SPI pins. //| //| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin //| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin //| :param ~microcontroller.Pin cs: The chip select (CS) pin +//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. //| //| Simple 8ksps 440 Hz sine wave:: //| @@ -72,11 +75,12 @@ //| ... //| static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_clock, ARG_mosi, ARG_cs }; + enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; static const mp_arg_t allowed_args[] = { { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, + { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -85,8 +89,13 @@ static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); + mp_int_t gain = args[ARG_gain].u_int; + if (gain != 1 && gain != 2) { + mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("gain must be 1 or 2")); + } + mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); - common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs); + common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs, (uint8_t)gain); return MP_OBJ_FROM_PTR(self); } From 8d282d59d8dac1193b0d586e5519b2da86b31c36 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 16:42:55 -0700 Subject: [PATCH 334/876] rework mcp4822 module from mtm_hardware.DACOut --- .../boards/mtm_computer/module/DACOut.c | 293 ------------------ .../boards/mtm_computer/module/DACOut.h | 38 --- .../boards/mtm_computer/module/mtm_hardware.c | 276 ----------------- .../boards/mtm_computer/mpconfigboard.mk | 7 - 4 files changed, 614 deletions(-) delete mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.c delete mode 100644 ports/raspberrypi/boards/mtm_computer/module/DACOut.h delete mode 100644 ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c b/ports/raspberrypi/boards/mtm_computer/module/DACOut.c deleted file mode 100644 index fb4ce37d4d0..00000000000 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.c +++ /dev/null @@ -1,293 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT -// -// MCP4822 dual-channel 12-bit SPI DAC driver for the MTM Workshop Computer. -// Uses PIO + DMA for non-blocking audio playback, mirroring audiobusio.I2SOut. - -#include -#include - -#include "mpconfigport.h" - -#include "py/gc.h" -#include "py/mperrno.h" -#include "py/runtime.h" -#include "boards/mtm_computer/module/DACOut.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-module/audiocore/__init__.h" -#include "bindings/rp2pio/StateMachine.h" - -// ───────────────────────────────────────────────────────────────────────────── -// PIO program for MCP4822 SPI DAC -// ───────────────────────────────────────────────────────────────────────────── -// -// Pin assignment: -// OUT pin (1) = MOSI — serial data out -// SET pins (N) = MOSI through CS — for CS control & command-bit injection -// SIDE-SET pin (1) = SCK — serial clock -// -// On the MTM Workshop Computer: MOSI=GP19, CS=GP21, SCK=GP18. -// The SET group spans GP19..GP21 (3 pins). GP20 is unused and driven low. -// -// SET PINS bit mapping (bit0=MOSI/GP19, bit1=GP20, bit2=CS/GP21): -// 0 = CS low, MOSI low 1 = CS low, MOSI high 4 = CS high, MOSI low -// -// SIDE-SET (1 pin, SCK): side 0 = SCK low, side 1 = SCK high -// -// MCP4822 16-bit command word: -// [15] channel (0=A, 1=B) [14] don't care [13] gain (1=1x) -// [12] output enable (1) [11:0] 12-bit data -// -// DMA feeds unsigned 16-bit audio samples. RP2040 narrow-write replication -// fills both halves of the 32-bit PIO FIFO entry with the same value, -// giving mono→stereo for free. -// -// The PIO pulls 32 bits, then sends two SPI transactions: -// Channel A: cmd nibble 0b0011, then all 16 sample bits from upper half-word -// Channel B: cmd nibble 0b1011, then all 16 sample bits from lower half-word -// The MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data), -// so only the top 12 of the 16 sample bits become DAC data. The bottom -// 4 sample bits clock out harmlessly after the DAC has latched. -// This gives correct 16-bit → 12-bit scaling (effectively sample >> 4). -// -// PIO instruction encoding with .side_set 1 (no opt): -// [15:13] opcode [12] side-set [11:8] delay [7:0] operands -// -// Total: 26 instructions, 86 PIO clocks per audio sample. -// ───────────────────────────────────────────────────────────────────────────── - -static const uint16_t mcp4822_pio_program[] = { - // side SCK - // 0: pull noblock side 0 ; Get 32 bits or keep X if FIFO empty - 0x8080, - // 1: mov x, osr side 0 ; Save for pull-noblock fallback - 0xA027, - - // ── Channel A: command nibble 0b0011 ────────────────────────────────── - // Send 4 cmd bits via SET, then all 16 sample bits via OUT. - // MCP4822 captures exactly 16 bits per CS frame (4 cmd + 12 data); - // the extra 4 clocks shift out the LSBs which the DAC ignores. - // This gives correct 16→12 bit scaling (top 12 bits become DAC data). - // 2: set pins, 0 side 0 ; CS low, MOSI=0 (bit15=0: channel A) - 0xE000, - // 3: nop side 1 ; SCK high — latch bit 15 - 0xB042, - // 4: set pins, 0 side 0 ; MOSI=0 (bit14=0: don't care) - 0xE000, - // 5: nop side 1 ; SCK high - 0xB042, - // 6: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) - 0xE001, - // 7: nop side 1 ; SCK high - 0xB042, - // 8: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) - 0xE001, - // 9: nop side 1 ; SCK high - 0xB042, - // 10: set y, 15 side 0 ; Loop counter: 16 sample bits - 0xE04F, - // 11: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopA) - 0x6001, - // 12: jmp y--, 11 side 1 ; SCK high, loop back - 0x108B, - // 13: set pins, 4 side 0 ; CS high — DAC A latches - 0xE004, - - // ── Channel B: command nibble 0b1011 ────────────────────────────────── - // 14: set pins, 1 side 0 ; CS low, MOSI=1 (bit15=1: channel B) - 0xE001, - // 15: nop side 1 ; SCK high - 0xB042, - // 16: set pins, 0 side 0 ; MOSI=0 (bit14=0) - 0xE000, - // 17: nop side 1 ; SCK high - 0xB042, - // 18: set pins, 1 side 0 ; MOSI=1 (bit13=1: gain 1x) - 0xE001, - // 19: nop side 1 ; SCK high - 0xB042, - // 20: set pins, 1 side 0 ; MOSI=1 (bit12=1: output active) - 0xE001, - // 21: nop side 1 ; SCK high - 0xB042, - // 22: set y, 15 side 0 ; Loop counter: 16 sample bits - 0xE04F, - // 23: out pins, 1 side 0 ; Data bit → MOSI; SCK low (bitloopB) - 0x6001, - // 24: jmp y--, 23 side 1 ; SCK high, loop back - 0x1097, - // 25: set pins, 4 side 0 ; CS high — DAC B latches - 0xE004, -}; - -// Clocks per sample: 2 (pull+mov) + 42 (chanA) + 42 (chanB) = 86 -// Per channel: 8(4 cmd bits × 2 clks) + 1(set y) + 32(16 bits × 2 clks) + 1(cs high) = 42 -#define MCP4822_CLOCKS_PER_SAMPLE 86 - - -// MCP4822 gain bit (bit 13) position in the PIO program: -// Instruction 6 = channel A gain bit -// Instruction 18 = channel B gain bit -// 1x gain: set pins, 1 (0xE001) — bit 13 = 1 -// 2x gain: set pins, 0 (0xE000) — bit 13 = 0 -#define MCP4822_PIO_GAIN_INSTR_A 6 -#define MCP4822_PIO_GAIN_INSTR_B 18 -#define MCP4822_PIO_GAIN_1X 0xE001 // set pins, 1 -#define MCP4822_PIO_GAIN_2X 0xE000 // set pins, 0 - -void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, - const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs, uint8_t gain) { - - // SET pins span from MOSI to CS. MOSI must have a lower GPIO number - // than CS, with at most 4 pins between them (SET count max is 5). - if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { - mp_raise_ValueError( - MP_COMPRESSED_ROM_TEXT("cs pin must be 1-4 positions above mosi pin")); - } - - uint8_t set_count = cs->number - mosi->number + 1; - - // Build a mutable copy of the PIO program and patch the gain bit - uint16_t program[MP_ARRAY_SIZE(mcp4822_pio_program)]; - memcpy(program, mcp4822_pio_program, sizeof(mcp4822_pio_program)); - uint16_t gain_instr = (gain == 2) ? MCP4822_PIO_GAIN_2X : MCP4822_PIO_GAIN_1X; - program[MCP4822_PIO_GAIN_INSTR_A] = gain_instr; - program[MCP4822_PIO_GAIN_INSTR_B] = gain_instr; - - // Initial SET pin state: CS high (bit at CS position), others low - uint32_t cs_bit_position = cs->number - mosi->number; - pio_pinmask32_t initial_set_state = PIO_PINMASK32_FROM_VALUE(1u << cs_bit_position); - pio_pinmask32_t initial_set_dir = PIO_PINMASK32_FROM_VALUE((1u << set_count) - 1); - - common_hal_rp2pio_statemachine_construct( - &self->state_machine, - program, MP_ARRAY_SIZE(mcp4822_pio_program), - 44100 * MCP4822_CLOCKS_PER_SAMPLE, // Initial frequency; play() adjusts - NULL, 0, // No init program - NULL, 0, // No may_exec - mosi, 1, // OUT: MOSI, 1 pin - PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // OUT state=low, dir=output - NULL, 0, // IN: none - PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // IN pulls: none - mosi, set_count, // SET: MOSI..CS - initial_set_state, initial_set_dir, // SET state (CS high), dir=output - clock, 1, false, // SIDE-SET: SCK, 1 pin, not pindirs - PIO_PINMASK32_NONE, // SIDE-SET state: SCK low - PIO_PINMASK32_FROM_VALUE(0x1), // SIDE-SET dir: output - false, // No sideset enable - NULL, PULL_NONE, // No jump pin - PIO_PINMASK_NONE, // No wait GPIO - true, // Exclusive pin use - false, 32, false, // OUT shift: no autopull, 32-bit, shift left - false, // Don't wait for txstall - false, 32, false, // IN shift (unused) - false, // Not user-interruptible - 0, -1, // Wrap: whole program - PIO_ANY_OFFSET, - PIO_FIFO_TYPE_DEFAULT, - PIO_MOV_STATUS_DEFAULT, - PIO_MOV_N_DEFAULT - ); - - self->playing = false; - audio_dma_init(&self->dma); -} - -bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self) { - return common_hal_rp2pio_statemachine_deinited(&self->state_machine); -} - -void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self) { - if (common_hal_mtm_hardware_dacout_deinited(self)) { - return; - } - if (common_hal_mtm_hardware_dacout_get_playing(self)) { - common_hal_mtm_hardware_dacout_stop(self); - } - common_hal_rp2pio_statemachine_deinit(&self->state_machine); - audio_dma_deinit(&self->dma); -} - -void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, - mp_obj_t sample, bool loop) { - - if (common_hal_mtm_hardware_dacout_get_playing(self)) { - common_hal_mtm_hardware_dacout_stop(self); - } - - uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); - if (bits_per_sample < 16) { - bits_per_sample = 16; - } - - uint32_t sample_rate = audiosample_get_sample_rate(sample); - uint8_t channel_count = audiosample_get_channel_count(sample); - if (channel_count > 2) { - mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("Too many channels in sample.")); - } - - // PIO clock = sample_rate × clocks_per_sample - common_hal_rp2pio_statemachine_set_frequency( - &self->state_machine, - (uint32_t)sample_rate * MCP4822_CLOCKS_PER_SAMPLE); - common_hal_rp2pio_statemachine_restart(&self->state_machine); - - // DMA feeds unsigned 16-bit samples. The PIO discards the top 4 bits - // of each 16-bit half and uses the remaining 12 as DAC data. - // RP2040 narrow-write replication: 16-bit DMA write → same value in - // both 32-bit FIFO halves → mono-to-stereo for free. - audio_dma_result result = audio_dma_setup_playback( - &self->dma, - sample, - loop, - false, // single_channel_output - 0, // audio_channel - false, // output_signed = false (unsigned for MCP4822) - bits_per_sample, // output_resolution - (uint32_t)&self->state_machine.pio->txf[self->state_machine.state_machine], - self->state_machine.tx_dreq, - false); // swap_channel - - if (result == AUDIO_DMA_DMA_BUSY) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("No DMA channel found")); - } else if (result == AUDIO_DMA_MEMORY_ERROR) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Unable to allocate buffers for signed conversion")); - } else if (result == AUDIO_DMA_SOURCE_ERROR) { - common_hal_mtm_hardware_dacout_stop(self); - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Audio source error")); - } - - self->playing = true; -} - -void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self) { - audio_dma_pause(&self->dma); -} - -void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self) { - audio_dma_resume(&self->dma); -} - -bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self) { - return audio_dma_get_paused(&self->dma); -} - -void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self) { - audio_dma_stop(&self->dma); - common_hal_rp2pio_statemachine_stop(&self->state_machine); - self->playing = false; -} - -bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self) { - bool playing = audio_dma_get_playing(&self->dma); - if (!playing && self->playing) { - common_hal_mtm_hardware_dacout_stop(self); - } - return playing; -} diff --git a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h b/ports/raspberrypi/boards/mtm_computer/module/DACOut.h deleted file mode 100644 index f9b5dd60108..00000000000 --- a/ports/raspberrypi/boards/mtm_computer/module/DACOut.h +++ /dev/null @@ -1,38 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "common-hal/microcontroller/Pin.h" -#include "common-hal/rp2pio/StateMachine.h" - -#include "audio_dma.h" -#include "py/obj.h" - -typedef struct { - mp_obj_base_t base; - rp2pio_statemachine_obj_t state_machine; - audio_dma_t dma; - bool playing; -} mtm_hardware_dacout_obj_t; - -void common_hal_mtm_hardware_dacout_construct(mtm_hardware_dacout_obj_t *self, - const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi, - const mcu_pin_obj_t *cs, uint8_t gain); - -void common_hal_mtm_hardware_dacout_deinit(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_deinited(mtm_hardware_dacout_obj_t *self); - -void common_hal_mtm_hardware_dacout_play(mtm_hardware_dacout_obj_t *self, - mp_obj_t sample, bool loop); -void common_hal_mtm_hardware_dacout_stop(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_get_playing(mtm_hardware_dacout_obj_t *self); - -void common_hal_mtm_hardware_dacout_pause(mtm_hardware_dacout_obj_t *self); -void common_hal_mtm_hardware_dacout_resume(mtm_hardware_dacout_obj_t *self); -bool common_hal_mtm_hardware_dacout_get_paused(mtm_hardware_dacout_obj_t *self); - -extern const mp_obj_type_t mtm_hardware_dacout_type; diff --git a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c b/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c deleted file mode 100644 index 8f875496f67..00000000000 --- a/ports/raspberrypi/boards/mtm_computer/module/mtm_hardware.c +++ /dev/null @@ -1,276 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT -// -// Python bindings for the mtm_hardware module. -// Provides DACOut: a non-blocking audio player for the MCP4822 SPI DAC. - -#include - -#include "shared/runtime/context_manager_helpers.h" -#include "py/binary.h" -#include "py/objproperty.h" -#include "py/runtime.h" -#include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/util.h" -#include "boards/mtm_computer/module/DACOut.h" - -// ───────────────────────────────────────────────────────────────────────────── -// DACOut class -// ───────────────────────────────────────────────────────────────────────────── - -//| class DACOut: -//| """Output audio to the MCP4822 dual-channel 12-bit SPI DAC.""" -//| -//| def __init__( -//| self, -//| clock: microcontroller.Pin, -//| mosi: microcontroller.Pin, -//| cs: microcontroller.Pin, -//| *, -//| gain: int = 1, -//| ) -> None: -//| """Create a DACOut object associated with the given SPI pins. -//| -//| :param ~microcontroller.Pin clock: The SPI clock (SCK) pin -//| :param ~microcontroller.Pin mosi: The SPI data (SDI/MOSI) pin -//| :param ~microcontroller.Pin cs: The chip select (CS) pin -//| :param int gain: DAC output gain, 1 for 1x (0-2.048V) or 2 for 2x (0-4.096V). Default 1. -//| -//| Simple 8ksps 440 Hz sine wave:: -//| -//| import mtm_hardware -//| import audiocore -//| import board -//| import array -//| import time -//| import math -//| -//| length = 8000 // 440 -//| sine_wave = array.array("H", [0] * length) -//| for i in range(length): -//| sine_wave[i] = int(math.sin(math.pi * 2 * i / length) * (2 ** 15) + 2 ** 15) -//| -//| sine_wave = audiocore.RawSample(sine_wave, sample_rate=8000) -//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) -//| dac.play(sine_wave, loop=True) -//| time.sleep(1) -//| dac.stop() -//| -//| Playing a wave file from flash:: -//| -//| import board -//| import audiocore -//| import mtm_hardware -//| -//| f = open("sound.wav", "rb") -//| wav = audiocore.WaveFile(f) -//| -//| dac = mtm_hardware.DACOut(clock=board.GP18, mosi=board.GP19, cs=board.GP21) -//| dac.play(wav) -//| while dac.playing: -//| pass""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_clock, ARG_mosi, ARG_cs, ARG_gain }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_mosi, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_cs, MP_ARG_OBJ | MP_ARG_KW_ONLY | MP_ARG_REQUIRED }, - { MP_QSTR_gain, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); - const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); - const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); - - mp_int_t gain = args[ARG_gain].u_int; - if (gain != 1 && gain != 2) { - mp_raise_ValueError(MP_COMPRESSED_ROM_TEXT("gain must be 1 or 2")); - } - - mtm_hardware_dacout_obj_t *self = mp_obj_malloc_with_finaliser(mtm_hardware_dacout_obj_t, &mtm_hardware_dacout_type); - common_hal_mtm_hardware_dacout_construct(self, clock, mosi, cs, (uint8_t)gain); - - return MP_OBJ_FROM_PTR(self); -} - -static void check_for_deinit(mtm_hardware_dacout_obj_t *self) { - if (common_hal_mtm_hardware_dacout_deinited(self)) { - raise_deinited_error(); - } -} - -//| def deinit(self) -> None: -//| """Deinitialises the DACOut and releases any hardware resources for reuse.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_deinit(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_mtm_hardware_dacout_deinit(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_deinit_obj, mtm_hardware_dacout_deinit); - -//| def __enter__(self) -> DACOut: -//| """No-op used by Context Managers.""" -//| ... -//| -// Provided by context manager helper. - -//| def __exit__(self) -> None: -//| """Automatically deinitializes the hardware when exiting a context. See -//| :ref:`lifetime-and-contextmanagers` for more info.""" -//| ... -//| -// Provided by context manager helper. - -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: -//| """Plays the sample once when loop=False and continuously when loop=True. -//| Does not block. Use `playing` to block. -//| -//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. -//| -//| The sample itself should consist of 8 bit or 16 bit samples.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, - { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, - }; - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - check_for_deinit(self); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_mtm_hardware_dacout_play(self, sample, args[ARG_loop].u_bool); - - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_KW(mtm_hardware_dacout_play_obj, 1, mtm_hardware_dacout_obj_play); - -//| def stop(self) -> None: -//| """Stops playback.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_stop(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - common_hal_mtm_hardware_dacout_stop(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_stop_obj, mtm_hardware_dacout_obj_stop); - -//| playing: bool -//| """True when the audio sample is being output. (read-only)""" -//| -static mp_obj_t mtm_hardware_dacout_obj_get_playing(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_playing(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_playing_obj, mtm_hardware_dacout_obj_get_playing); - -MP_PROPERTY_GETTER(mtm_hardware_dacout_playing_obj, - (mp_obj_t)&mtm_hardware_dacout_get_playing_obj); - -//| def pause(self) -> None: -//| """Stops playback temporarily while remembering the position. Use `resume` to resume playback.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_pause(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - if (!common_hal_mtm_hardware_dacout_get_playing(self)) { - mp_raise_RuntimeError(MP_COMPRESSED_ROM_TEXT("Not playing")); - } - common_hal_mtm_hardware_dacout_pause(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_pause_obj, mtm_hardware_dacout_obj_pause); - -//| def resume(self) -> None: -//| """Resumes sample playback after :py:func:`pause`.""" -//| ... -//| -static mp_obj_t mtm_hardware_dacout_obj_resume(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - if (common_hal_mtm_hardware_dacout_get_paused(self)) { - common_hal_mtm_hardware_dacout_resume(self); - } - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_resume_obj, mtm_hardware_dacout_obj_resume); - -//| paused: bool -//| """True when playback is paused. (read-only)""" -//| -static mp_obj_t mtm_hardware_dacout_obj_get_paused(mp_obj_t self_in) { - mtm_hardware_dacout_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return mp_obj_new_bool(common_hal_mtm_hardware_dacout_get_paused(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(mtm_hardware_dacout_get_paused_obj, mtm_hardware_dacout_obj_get_paused); - -MP_PROPERTY_GETTER(mtm_hardware_dacout_paused_obj, - (mp_obj_t)&mtm_hardware_dacout_get_paused_obj); - -// ── DACOut type definition ─────────────────────────────────────────────────── - -static const mp_rom_map_elem_t mtm_hardware_dacout_locals_dict_table[] = { - // Methods - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&mtm_hardware_dacout_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, - { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&mtm_hardware_dacout_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&mtm_hardware_dacout_stop_obj) }, - { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&mtm_hardware_dacout_pause_obj) }, - { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&mtm_hardware_dacout_resume_obj) }, - - // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&mtm_hardware_dacout_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&mtm_hardware_dacout_paused_obj) }, -}; -static MP_DEFINE_CONST_DICT(mtm_hardware_dacout_locals_dict, mtm_hardware_dacout_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - mtm_hardware_dacout_type, - MP_QSTR_DACOut, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, mtm_hardware_dacout_make_new, - locals_dict, &mtm_hardware_dacout_locals_dict - ); - -// ───────────────────────────────────────────────────────────────────────────── -// mtm_hardware module definition -// ───────────────────────────────────────────────────────────────────────────── - -//| """Hardware interface to Music Thing Modular Workshop Computer peripherals. -//| -//| Provides the `DACOut` class for non-blocking audio output via the -//| MCP4822 dual-channel 12-bit SPI DAC. -//| """ - -static const mp_rom_map_elem_t mtm_hardware_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_mtm_hardware) }, - { MP_ROM_QSTR(MP_QSTR_DACOut), MP_ROM_PTR(&mtm_hardware_dacout_type) }, -}; - -static MP_DEFINE_CONST_DICT(mtm_hardware_module_globals, mtm_hardware_module_globals_table); - -const mp_obj_module_t mtm_hardware_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&mtm_hardware_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_mtm_hardware, mtm_hardware_module); diff --git a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk index 0383e0777fa..45c99711d72 100644 --- a/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk +++ b/ports/raspberrypi/boards/mtm_computer/mpconfigboard.mk @@ -11,11 +11,4 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_AUDIOEFFECTS = 1 CIRCUITPY_IMAGECAPTURE = 0 CIRCUITPY_PICODVI = 0 -<<<<<<< HEAD CIRCUITPY_MCP4822 = 1 -======= - -SRC_C += \ - boards/$(BOARD)/module/mtm_hardware.c \ - boards/$(BOARD)/module/DACOut.c ->>>>>>> d8bbe2a87f (mtm_computer: Add DAC audio out module) From d0e286a7fdd519dd536d45b3ba29fea54cc24315 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 16:51:02 -0700 Subject: [PATCH 335/876] restore deleted circuitpython.pot, update translation --- locale/circuitpython.pot | 4575 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 4575 insertions(+) create mode 100644 locale/circuitpython.pot diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot new file mode 100644 index 00000000000..5d0be48fe3a --- /dev/null +++ b/locale/circuitpython.pot @@ -0,0 +1,4575 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#: main.c +msgid "" +"\n" +"Code done running.\n" +msgstr "" + +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" +msgstr "" + +#: py/obj.c +msgid " File \"%q\"" +msgstr "" + +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr "" + +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr "" + +#: main.c +msgid " not found.\n" +msgstr "" + +#: main.c +msgid " output:\n" +msgstr "" + +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +msgstr "" + +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "" + +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" +msgstr "" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" +msgstr "" + +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" +msgstr "" + +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" +msgstr "" + +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" +msgstr "" + +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "" + +#: py/objstr.c +msgid "%q index out of range" +msgstr "" + +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" +msgstr "" + +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "" + +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "" + +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "" + +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "" + +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "" + +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "" + +#: py/argcheck.c +msgid "%q must be %d" +msgstr "" + +#: py/argcheck.c shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "" + +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "" + +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "" + +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "" + +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "" + +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "" + +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "" + +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "" + +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." +msgstr "" + +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "" + +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" +msgstr "" + +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" + +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "" + +#: py/objmodule.c +msgid "%q renamed %q" +msgstr "" + +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "" + +#: shared-module/bitbangio/I2C.c +msgid "%q too long" +msgstr "" + +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" +msgstr "" + +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "" + +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" +msgstr "" + +#: py/argcheck.c +msgid "'%q' argument required" +msgstr "" + +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "" + +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "" + +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" +msgstr "" + +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "" + +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "" + +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "" + +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "" + +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "" + +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "" + +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "" + +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "" + +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "" + +#: py/compile.c +msgid "'await' outside function" +msgstr "" + +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "" + +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "" + +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "" + +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "" + +#: py/emitnative.c +msgid "'not' not implemented" +msgstr "" + +#: py/compile.c +msgid "'return' outside function" +msgstr "" + +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "" + +#: py/compile.c +msgid "'yield' outside function" +msgstr "" + +#: py/compile.c +msgid "* arg after **" +msgstr "" + +#: py/compile.c +msgid "*x must be assignment target" +msgstr "" + +#: py/obj.c +msgid ", in %q\n" +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" +msgstr "" + +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "" + +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "" + +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "" + +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "" + +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "" + +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "" + +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "" + +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "" + +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "" + +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "" + +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "" + +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "" + +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" +msgstr "" + +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "" + +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "" + +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "" + +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "" + +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." +msgstr "" + +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" +msgstr "" + +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "" + +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "" + +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "" + +#: main.c +msgid "Auto-reload is off.\n" +msgstr "" + +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "" + +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "" + +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "" + +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" +msgstr "" + +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "" + +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "" + +#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c +#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c +#: shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "" + +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "" + +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "" + +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "Cannot record to a file" +msgstr "" + +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." +msgstr "" + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "" + +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "" + +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "" + +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "" + +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "" + +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" + +#: ports/stm/common-hal/analogio/AnalogOut.c +msgid "DAC Channel Init Error" +msgstr "" + +#: ports/stm/common-hal/analogio/AnalogOut.c +msgid "DAC Device Init Error" +msgstr "" + +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" +msgstr "" + +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "" + +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "" + +#: main.c +msgid "Done" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "" + +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "" + +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "" + +#: extmod/modre.c +msgid "Error in regex" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "" + +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." +msgstr "" + +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "" + +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "" + +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "" + +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "" + +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" +msgstr "" + +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "" + +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" +msgstr "" + +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" +msgstr "" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "" + +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" +msgstr "" + +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" +msgstr "" + +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" + +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." +msgstr "" + +#: py/moderrno.c +msgid "File exists" +msgstr "" + +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" +msgstr "" + +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" +msgstr "" + +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" +msgstr "" + +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "" + +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "" + +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +msgstr "" + +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "" + +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" +msgstr "" + +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." +msgstr "" + +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." +msgstr "" + +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "" + +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "" + +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "" + +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" +msgstr "" + +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "" + +#: py/moderrno.c +msgid "Input/output error" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" +msgstr "" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "" + +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "" + +#: shared-module/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Internal error #%d" +msgstr "" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-bindings/pwmio/PWMOut.c +msgid "Internal resource(s) in use" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "" + +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" +msgstr "" + +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "" + +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" + +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "" + +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" +msgstr "" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" +msgstr "" + +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" +msgstr "" + +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" +msgstr "" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "" + +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "" + +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "" + +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "" + +#: py/compile.c +msgid "LHS of keyword arg must be an id" +msgstr "" + +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "" + +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "" + +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" +msgstr "" + +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" +msgstr "" + +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" +msgstr "" + +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" +msgstr "" + +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" +msgstr "" + +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." +msgstr "" + +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" +msgstr "" + +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." +msgstr "" + +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "" + +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" +msgstr "" + +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +msgid "No DAC on chip" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" +msgstr "" + +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" +msgstr "" + +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" +msgstr "" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "" + +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "" + +#: shared-module/usb/core/Device.c +msgid "No configuration set" +msgstr "" + +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" +msgstr "" + +#: shared-bindings/board/__init__.c +msgid "No default %q bus" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" +msgstr "" + +#: shared-bindings/os/__init__.c +msgid "No hardware random available" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" +msgstr "" + +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "" + +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" +msgstr "" + +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" +msgstr "" + +#: py/moderrno.c +msgid "No space left on device" +msgstr "" + +#: py/moderrno.c +msgid "No such device" +msgstr "" + +#: py/moderrno.c +msgid "No such file/directory" +msgstr "" + +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" +msgstr "" + +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" +msgstr "" + +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" +msgstr "" + +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +msgid "Not playing" +msgstr "" + +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" +msgstr "" + +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." +msgstr "" + +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" +msgstr "" + +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" +msgstr "" + +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgstr "" + +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" +msgstr "" + +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" +msgstr "" + +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" +msgstr "" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" +msgstr "" + +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "" + +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." +msgstr "" + +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." +msgstr "" + +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" +msgstr "" + +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "" + +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." +msgstr "" + +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" +msgstr "" + +#: py/moderrno.c +msgid "Operation not permitted" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" +msgstr "" + +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" +msgstr "" + +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" +msgstr "" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" +msgstr "" + +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/__init__.c +msgid "Peripheral in use" +msgstr "" + +#: py/moderrno.c +msgid "Permission denied" +msgstr "" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" +msgstr "" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" +msgstr "" + +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" +msgstr "" + +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" +msgstr "" + +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" +msgstr "" + +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" +msgstr "" + +#: shared-module/usb/core/Device.c +msgid "Pipe error" +msgstr "" + +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" +msgstr "" + +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" +msgstr "" + +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +msgstr "" + +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" +msgstr "" + +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" +msgstr "" + +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." +msgstr "" + +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" +msgstr "" + +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" +msgstr "" + +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" +msgstr "" + +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" + +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" +msgstr "" + +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" +msgstr "" + +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" +msgstr "" + +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" +msgstr "" + +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" +msgstr "" + +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" +msgstr "" + +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "" + +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" +msgstr "" + +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" +msgstr "" + +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" +msgstr "" + +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" +msgstr "" + +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" +msgstr "" + +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error %x" +msgstr "" + +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" +msgstr "" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" +msgstr "" + +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" + +#: ports/raspberrypi/common-hal/busio/SPI.c +msgid "SPI peripheral in use" +msgstr "" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" +msgstr "" + +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" +msgstr "" + +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "" + +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." +msgstr "" + +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" +msgstr "" + +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" +msgstr "" + +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" +msgstr "" + +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." +msgstr "" + +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" +msgstr "" + +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" +msgstr "" + +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." +msgstr "" + +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +msgstr "" + +#: shared-module/audiocore/__init__.c +msgid "The sample's %q does not match" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." +msgstr "" + +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." +msgstr "" + +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." +msgstr "" + +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" +msgstr "" + +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" +msgstr "" + +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" +msgstr "" + +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" +msgstr "" + +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" +msgstr "" + +#: shared-module/displayio/__init__.c +msgid "Too many displays" +msgstr "" + +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" +msgstr "" + +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" +msgstr "" + +#: py/obj.c +msgid "Traceback (most recent call last):\n" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" +msgstr "" + +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" + +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" + +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" + +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" +msgstr "" + +#: main.c +msgid "UID:" +msgstr "" + +#: shared-module/usb_hid/Device.c +msgid "USB busy" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." +msgstr "" + +#: shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "" + +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +msgstr "" + +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" +msgstr "" + +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." +msgstr "" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" +msgstr "" + +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" +msgstr "" + +#: py/parse.c +msgid "Unable to init parser" +msgstr "" + +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" +msgstr "" + +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" +msgstr "" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" +msgstr "" + +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." +msgstr "" + +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" +msgstr "" + +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." +msgstr "" + +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" +msgstr "" + +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" +msgstr "" + +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" +msgstr "" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown security error: 0x%04x" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" +msgstr "" + +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." +msgstr "" + +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." +msgstr "" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" +msgstr "" + +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" +msgstr "" + +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" +msgstr "" + +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" +msgstr "" + +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" +msgstr "" + +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" +msgstr "" + +#: main.c +msgid "WARNING: Your code filename has two extensions\n" +msgstr "" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +msgstr "" + +#: py/builtinhelp.c +#, c-format +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" +msgstr "" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" +msgstr "" + +#: main.c +msgid "Woken up by alarm.\n" +msgstr "" + +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" +msgstr "" + +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" +msgstr "" + +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "" + +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "" + +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "" + +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "" + +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "" + +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." +msgstr "" + +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." +msgstr "" + +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "" + +#: py/objtype.c +msgid "__init__() should return None" +msgstr "" + +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" +msgstr "" + +#: py/objobject.c +msgid "__new__ arg must be a user-type" +msgstr "" + +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" +msgstr "" + +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" + +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" +msgstr "" + +#: py/compile.c +msgid "annotation must be an identifier" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" +msgstr "" + +#: py/modbuiltins.c +msgid "arg is an empty sequence" +msgstr "" + +#: py/objobject.c +msgid "arg must be user-type" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" + +#: py/compile.c +msgid "argument name reused" +msgstr "" + +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c +msgid "argument num/types mismatch" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "" + +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" +msgstr "" + +#: py/asmxtensa.c +msgid "asm overflow" +msgstr "" + +#: py/compile.c +msgid "async for/with outside async function" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" + +#: py/objstr.c +msgid "attributes not supported" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" +msgstr "" + +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" +msgstr "" + +#: py/builtinevex.c +msgid "bad compile mode" +msgstr "" + +#: py/objstr.c +msgid "bad conversion specifier" +msgstr "" + +#: py/objstr.c +msgid "bad format string" +msgstr "" + +#: py/binary.c py/objarray.c +msgid "bad typecode" +msgstr "" + +#: py/emitnative.c +msgid "binary op %q not implemented" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +msgid "bit_depth must be 8, 16, 24, or 32." +msgstr "" + +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" +msgstr "" + +#: extmod/modrandom.c +msgid "bits must be 32 or less" +msgstr "" + +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" +msgstr "" + +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" +msgstr "" + +#: py/emitinlinethumb.c +msgid "branch not in range" +msgstr "" + +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "" + +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "" + +#: shared-module/struct/__init__.c +msgid "buffer size must match format" +msgstr "" + +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" +msgstr "" + +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" +msgstr "" + +#: py/emitbc.c +msgid "bytecode overflow" +msgstr "" + +#: py/objarray.c +msgid "bytes length not a multiple of item size" +msgstr "" + +#: py/objstr.c +msgid "bytes value out of range" +msgstr "" + +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "" + +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "" + +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" +msgstr "" + +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" +msgstr "" + +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" +msgstr "" + +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "" + +#: py/objtype.c +msgid "can't add special method to already-subclassed class" +msgstr "" + +#: py/compile.c +msgid "can't assign to expression" +msgstr "" + +#: extmod/modasyncio.c +msgid "can't cancel self" +msgstr "" + +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" +msgstr "" + +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" +msgstr "" + +#: py/obj.c +#, c-format +msgid "can't convert %s to float" +msgstr "" + +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" +msgstr "" + +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "" + +#: py/obj.c +msgid "can't convert to complex" +msgstr "" + +#: py/obj.c +msgid "can't convert to float" +msgstr "" + +#: py/runtime.c +msgid "can't convert to int" +msgstr "" + +#: py/objstr.c +msgid "can't convert to str implicitly" +msgstr "" + +#: py/objtype.c +msgid "can't create '%q' instances" +msgstr "" + +#: py/compile.c +msgid "can't declare nonlocal in outer code" +msgstr "" + +#: py/compile.c +msgid "can't delete expression" +msgstr "" + +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't do unary op of '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" +msgstr "" + +#: py/runtime.c +msgid "can't import name %q" +msgstr "" + +#: py/emitnative.c +msgid "can't load from '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't load with '%q' index" +msgstr "" + +#: py/builtinimport.c +msgid "can't perform relative import" +msgstr "" + +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" +msgstr "" + +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" +msgstr "" + +#: py/runtime.c +msgid "can't set attribute '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't store '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't store to '%q'" +msgstr "" + +#: py/emitnative.c +msgid "can't store with '%q' index" +msgstr "" + +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" +msgstr "" + +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" +msgstr "" + +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" +msgstr "" + +#: extmod/modasyncio.c +msgid "can't wait" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "" + +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "" + +#: py/objtype.c +msgid "cannot create instance" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "" + +#: py/emitnative.c +msgid "casting" +msgstr "" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" +msgstr "" + +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" +msgstr "" + +#: py/modbuiltins.c +msgid "chr() arg not in range(0x110000)" +msgstr "" + +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" +msgstr "" + +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" +msgstr "" + +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +msgstr "" + +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" +msgstr "" + +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +msgstr "" + +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" +msgstr "" + +#: py/emitnative.c +msgid "comparison of int and uint" +msgstr "" + +#: py/objcomplex.c +msgid "complex divide by zero" +msgstr "" + +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" +msgstr "" + +#: extmod/modzlib.c +msgid "compression header" +msgstr "" + +#: py/emitnative.c +msgid "conversion to object" +msgstr "" + +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" + +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" + +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "" + +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "cs pin must be 1-4 positions above mosi pin" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "" + +#: py/parsenum.c +msgid "decimal numbers not supported" +msgstr "" + +#: py/compile.c +msgid "default 'except' must be last" +msgstr "" + +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +msgstr "" + +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +msgstr "" + +#: py/objdict.c +msgid "dict update sequence has wrong length" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "" + +#: py/emitnative.c +msgid "div/mod not implemented for uint" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "divide by zero" +msgstr "" + +#: py/runtime.c +msgid "division by zero" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" +msgstr "" + +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "" + +#: py/objdeque.c +msgid "empty" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "" + +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" +msgstr "" + +#: py/objstr.c +msgid "empty separator" +msgstr "" + +#: shared-bindings/random/__init__.c +msgid "empty sequence" +msgstr "" + +#: py/objstr.c +msgid "end of format while looking for conversion specifier" +msgstr "" + +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" +msgstr "" + +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" +msgstr "" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" +msgstr "" + +#: py/objstr.c +msgid "expected ':' after format specifier" +msgstr "" + +#: py/obj.c +msgid "expected tuple/list" +msgstr "" + +#: py/modthread.c +msgid "expecting a dict for keyword args" +msgstr "" + +#: py/compile.c +msgid "expecting an assembler instruction" +msgstr "" + +#: py/compile.c +msgid "expecting just a value for set" +msgstr "" + +#: py/compile.c +msgid "expecting key:value for dict" +msgstr "" + +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" +msgstr "" + +#: py/argcheck.c +msgid "extra keyword arguments given" +msgstr "" + +#: py/argcheck.c +msgid "extra positional arguments given" +msgstr "" + +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" +msgstr "" + +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "" + +#: py/objtype.c +msgid "first argument to super() must be type" +msgstr "" + +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "" + +#: py/objint.c +msgid "float too big" +msgstr "" + +#: py/nativeglue.c +msgid "float unsupported" +msgstr "" + +#: extmod/moddeflate.c +msgid "format" +msgstr "" + +#: py/objstr.c +msgid "format needs a dict" +msgstr "" + +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" + +#: py/objstr.c +msgid "format string needs more arguments" +msgstr "" + +#: py/objdeque.c +msgid "full" +msgstr "" + +#: py/argcheck.c +msgid "function doesn't take keyword arguments" +msgstr "" + +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" +msgstr "" + +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "" + +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "" + +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" +msgstr "" + +#: py/bc.c +msgid "function missing keyword-only argument" +msgstr "" + +#: py/bc.c +msgid "function missing required keyword argument '%q'" +msgstr "" + +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" +msgstr "" + +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" +msgstr "" + +#: shared-bindings/mcp4822/MCP4822.c +msgid "gain must be 1 or 2" +msgstr "" + +#: py/objgenerator.c +msgid "generator already executing" +msgstr "" + +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" +msgstr "" + +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" +msgstr "" + +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "" + +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "" + +#: py/compile.c +msgid "identifier redefined as global" +msgstr "" + +#: py/compile.c +msgid "identifier redefined as nonlocal" +msgstr "" + +#: py/compile.c +msgid "import * not at module level" +msgstr "" + +#: py/persistentcode.c +msgid "incompatible .mpy arch" +msgstr "" + +#: py/persistentcode.c +msgid "incompatible .mpy file" +msgstr "" + +#: py/objstr.c +msgid "incomplete format" +msgstr "" + +#: py/objstr.c +msgid "incomplete format key" +msgstr "" + +#: extmod/modbinascii.c +msgid "incorrect padding" +msgstr "" + +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" + +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "" + +#: py/obj.c +msgid "indices must be integers" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "" + +#: py/compile.c +msgid "inline assembler must be a function" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "" + +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "" + +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "" + +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "" + +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "" + +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" + +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +#, c-format +msgid "interval must be in range %s-%s" +msgstr "" + +#: py/compile.c +msgid "invalid arch" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgstr "" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" +msgstr "" + +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" +msgstr "" + +#: py/objstr.c +msgid "invalid format specifier" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" +msgstr "" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" +msgstr "" + +#: py/compile.c +msgid "invalid micropython decorator" +msgstr "" + +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" +msgstr "" + +#: shared-bindings/random/__init__.c +msgid "invalid step" +msgstr "" + +#: py/compile.c py/parse.c +msgid "invalid syntax" +msgstr "" + +#: py/parsenum.c +msgid "invalid syntax for integer" +msgstr "" + +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" +msgstr "" + +#: py/parsenum.c +msgid "invalid syntax for number" +msgstr "" + +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" +msgstr "" + +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" + +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" +msgstr "" + +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" +msgstr "" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" +msgstr "" + +#: py/compile.c +msgid "label redefined" +msgstr "" + +#: py/objarray.c +msgid "lhs and rhs should be compatible" +msgstr "" + +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" +msgstr "" + +#: py/emitnative.c +msgid "local '%q' used before type known" +msgstr "" + +#: py/vm.c +msgid "local variable referenced before assignment" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" +msgstr "" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" +msgstr "" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" +msgstr "" + +#: py/parse.c +msgid "malformed f-string" +msgstr "" + +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" +msgstr "" + +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" + +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "" + +#: py/runtime.c +msgid "maximum recursion depth exceeded" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "" + +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "" + +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" +msgstr "" + +#: py/runtime.c +msgid "memory allocation failed, heap is locked" +msgstr "" + +#: py/objarray.c +msgid "memoryview offset too large" +msgstr "" + +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" +msgstr "" + +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "" + +#: py/builtinimport.c +msgid "module not found" +msgstr "" + +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" +msgstr "" + +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" + +#: py/compile.c +msgid "multiple *x in assignment" +msgstr "" + +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" +msgstr "" + +#: py/objtype.c +msgid "multiple inheritance not supported" +msgstr "" + +#: py/emitnative.c +msgid "must raise an object" +msgstr "" + +#: py/modbuiltins.c +msgid "must use keyword argument for key function" +msgstr "" + +#: py/runtime.c +msgid "name '%q' isn't defined" +msgstr "" + +#: py/runtime.c +msgid "name not defined" +msgstr "" + +#: py/qstr.c +msgid "name too long" +msgstr "" + +#: py/persistentcode.c +msgid "native code in .mpy unsupported" +msgstr "" + +#: py/asmthumb.c +msgid "native method too big" +msgstr "" + +#: py/emitnative.c +msgid "native yield" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "" + +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" +msgstr "" + +#: py/modmath.c +msgid "negative factorial" +msgstr "" + +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" +msgstr "" + +#: py/objint_mpz.c py/runtime.c +msgid "negative shift count" +msgstr "" + +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" +msgstr "" + +#: py/vm.c +msgid "no active exception to reraise" +msgstr "" + +#: py/compile.c +msgid "no binding for nonlocal found" +msgstr "" + +#: shared-module/msgpack/__init__.c +msgid "no default packer" +msgstr "" + +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" +msgstr "" + +#: py/builtinimport.c +msgid "no module named '%q'" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" +msgstr "" + +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" +msgstr "" + +#: py/compile.c +msgid "non-default argument follows default argument" +msgstr "" + +#: py/objstr.c +msgid "non-hex digit" +msgstr "" + +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" +msgstr "" + +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" +msgstr "" + +#: py/parse.c +msgid "not a constant" +msgstr "" + +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "" + +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "" + +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" + +#: py/builtinhelp.c +msgid "object " +msgstr "" + +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" +msgstr "" + +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" +msgstr "" + +#: py/obj.c +msgid "object doesn't support item assignment" +msgstr "" + +#: py/obj.c +msgid "object doesn't support item deletion" +msgstr "" + +#: py/obj.c +msgid "object has no len" +msgstr "" + +#: py/obj.c +msgid "object isn't subscriptable" +msgstr "" + +#: py/runtime.c +msgid "object not an iterator" +msgstr "" + +#: py/objtype.c py/runtime.c +msgid "object not callable" +msgstr "" + +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" +msgstr "" + +#: py/runtime.c +msgid "object not iterable" +msgstr "" + +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" +msgstr "" + +#: py/obj.c +msgid "object with buffer protocol required" +msgstr "" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" +msgstr "" + +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" +msgstr "" + +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "" + +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "" + +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "" + +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" +msgstr "" + +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "" + +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" +msgstr "" + +#: py/vm.c +msgid "opcode" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" +msgstr "" + +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" +msgstr "" + +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "" + +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "" + +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "" + +#: py/modbuiltins.c +msgid "ord expects a character" +msgstr "" + +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" +msgstr "" + +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "" + +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" + +#: py/objint_mpz.c +msgid "overflow converting long int to machine word" +msgstr "" + +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" +msgstr "" + +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" +msgstr "" + +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" +msgstr "" + +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" +msgstr "" + +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" +msgstr "" + +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "" + +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" +msgstr "" + +#: py/compile.c +msgid "positional arg after **" +msgstr "" + +#: py/compile.c +msgid "positional arg after keyword arg" +msgstr "" + +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" +msgstr "" + +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" +msgstr "" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" +msgstr "" + +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" + +#: py/builtinimport.c +msgid "relative import" +msgstr "" + +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" +msgstr "" + +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "" + +#: py/compile.c +msgid "return annotation must be an identifier" +msgstr "" + +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" +msgstr "" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "" + +#: py/objstr.c +msgid "rsplit(None,n)" +msgstr "" + +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" +msgstr "" + +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" +msgstr "" + +#: py/modmicropython.c +msgid "schedule queue full" +msgstr "" + +#: py/builtinimport.c +msgid "script compilation not supported" +msgstr "" + +#: py/nativeglue.c +msgid "set unsupported" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "" + +#: shared-module/msgpack/__init__.c +msgid "short read" +msgstr "" + +#: py/objstr.c +msgid "sign not allowed in string format specifier" +msgstr "" + +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" +msgstr "" + +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "" + +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" + +#: py/nativeglue.c +msgid "slice unsupported" +msgstr "" + +#: py/objint.c py/sequence.c +msgid "small int overflow" +msgstr "" + +#: main.c +msgid "soft reboot\n" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" +msgstr "" + +#: extmod/modre.c +msgid "splitting with sub-captures" +msgstr "" + +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" +msgstr "" + +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" +msgstr "" + +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" +msgstr "" + +#: py/objstrunicode.c +msgid "string index out of range" +msgstr "" + +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" +msgstr "" + +#: py/objarray.c py/objstr.c +msgid "substring not found" +msgstr "" + +#: py/compile.c +msgid "super() can't find self" +msgstr "" + +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "" + +#: extmod/modtime.c +msgid "ticks interval overflow" +msgstr "" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" +msgstr "" + +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" +msgstr "" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" +msgstr "" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" +msgstr "" + +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" +msgstr "" + +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" +msgstr "" + +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" + +#: py/compile.c +msgid "too many args" +msgstr "" + +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "" + +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "" + +#: py/asmthumb.c +msgid "too many locals for native method" +msgstr "" + +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" +msgstr "" + +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "" + +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "" + +#: py/obj.c +msgid "tuple/list has wrong length" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" +msgstr "" + +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" +msgstr "" + +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" +msgstr "" + +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" +msgstr "" + +#: py/objtype.c +msgid "type isn't an acceptable base type" +msgstr "" + +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" +msgstr "" + +#: py/objtype.c +msgid "type takes 1 or 3 arguments" +msgstr "" + +#: py/objint_longlong.c +msgid "ulonglong too large" +msgstr "" + +#: py/parse.c +msgid "unexpected indent" +msgstr "" + +#: py/bc.c +msgid "unexpected keyword argument" +msgstr "" + +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" +msgstr "" + +#: py/lexer.c +msgid "unicode name escapes" +msgstr "" + +#: py/parse.c +msgid "unindent doesn't match any outer indent level" +msgstr "" + +#: py/emitinlinerv32.c +msgid "unknown RV32 instruction '%q'" +msgstr "" + +#: py/objstr.c +#, c-format +msgid "unknown conversion specifier %c" +msgstr "" + +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" +msgstr "" + +#: py/compile.c +msgid "unknown type" +msgstr "" + +#: py/compile.c +msgid "unknown type '%q'" +msgstr "" + +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" +msgstr "" + +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" +msgstr "" + +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" +msgstr "" + +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" +msgstr "" + +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" +msgstr "" + +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" +msgstr "" + +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" +msgstr "" + +#: py/runtime.c +msgid "unsupported type for %q: '%s'" +msgstr "" + +#: py/runtime.c +msgid "unsupported type for operator" +msgstr "" + +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" + +#: py/objint.c +#, c-format +msgid "value must fit in %d byte(s)" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" +msgstr "" + +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" + +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" +msgstr "" + +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +msgstr "" + +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" +msgstr "" + +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" +msgstr "" + +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "" + +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "" + +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" +msgstr "" + +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" +msgstr "" + +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "" + +#: py/runtime.c +msgid "wrong number of values to unpack" +msgstr "" + +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" +msgstr "" + +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "" From a20f1f9401519b427c5b57b7723fd28cd23a8133 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 16:58:33 -0700 Subject: [PATCH 336/876] mtm_computer: set DAC gain 2x --- ports/raspberrypi/boards/mtm_computer/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index 9065ffebcf8..666d584af2c 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -20,7 +20,7 @@ static mp_obj_t board_dac_factory(void) { &pin_GPIO18, // clock (SCK) &pin_GPIO19, // mosi (SDI) &pin_GPIO21, // cs - 1); // gain 1x + 2); // gain 2x return MP_OBJ_FROM_PTR(dac); } MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); From 2793baa87b5fb251a282e0c02b5234246026b2d5 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 23 Mar 2026 18:26:08 -0700 Subject: [PATCH 337/876] Revert "mtm_computer: set DAC gain 2x" This reverts commit 8bf51dbc821e051301a9a7057e6f2ea1a8a559fe. --- ports/raspberrypi/boards/mtm_computer/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index 666d584af2c..9065ffebcf8 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -20,7 +20,7 @@ static mp_obj_t board_dac_factory(void) { &pin_GPIO18, // clock (SCK) &pin_GPIO19, // mosi (SDI) &pin_GPIO21, // cs - 2); // gain 2x + 1); // gain 1x return MP_OBJ_FROM_PTR(dac); } MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); From 32165ce455ca39acbefd7c1513d1bbd854215e10 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 09:51:01 -0700 Subject: [PATCH 338/876] fix zephyr builds by running update_boardnfo.py --- .../adafruit/feather_nrf52840_zephyr/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml | 1 + .../zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml | 1 + .../zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml | 1 + .../boards/renesas/da14695_dk_usb/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml | 1 + 17 files changed, 17 insertions(+) diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 9712f467858..277386cd1da 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 80b1b4ebf7d..dbf98f10768 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 1bc1b96e6cf..06f944e3e90 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 7869cca4faf..1e0cc856db1 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index c2233ddf8b5..a43e3169ada 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index a1e8de8822b..90203c4c0ec 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index b50b1966ed0..8f05a53587e 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 21d55194a1c..09f5cc6c580 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 90f84ab1586..e641099db76 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index eb5db066c89..d94b69eb813 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index d6efa285fe2..0874538a408 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 7600b8bbd15..b8657eb040a 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 8e49b95d334..04e75b39eee 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index b28a9481c72..e881b822190 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 6b0ef8d8480..6bdc58b12af 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index b6f03f3d627..ba745440b8d 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 8d1fd925348..dd571f02834 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false From b66baecb2614acee05c2740e3752d33248c2c9d0 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 14:46:04 -0700 Subject: [PATCH 339/876] mcp4822 gain argument fix, as per requested --- shared-bindings/mcp4822/MCP4822.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/shared-bindings/mcp4822/MCP4822.c b/shared-bindings/mcp4822/MCP4822.c index c48f5426e66..f192caf4052 100644 --- a/shared-bindings/mcp4822/MCP4822.c +++ b/shared-bindings/mcp4822/MCP4822.c @@ -81,11 +81,7 @@ static mp_obj_t mcp4822_mcp4822_make_new(const mp_obj_type_t *type, size_t n_arg const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock); const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi); const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); - - mp_int_t gain = args[ARG_gain].u_int; - if (gain != 1 && gain != 2) { - mp_raise_ValueError(MP_ERROR_TEXT("gain must be 1 or 2")); - } + const mp_int_t gain = mp_arg_validate_int_range(args[ARG_gain].u_int, 1, 2, MP_QSTR_gain); mcp4822_mcp4822_obj_t *self = mp_obj_malloc_with_finaliser(mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); common_hal_mcp4822_mcp4822_construct(self, clock, mosi, cs, (uint8_t)gain); From 16285c158db2225188217b927bb81df704b87619 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 14:46:57 -0700 Subject: [PATCH 340/876] mcp4822 gain argument fix, as per requested --- locale/circuitpython.pot | 4 ---- 1 file changed, 4 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 5d0be48fe3a..8bfc2d5bde3 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -3310,10 +3310,6 @@ msgstr "" msgid "function takes %d positional arguments but %d were given" msgstr "" -#: shared-bindings/mcp4822/MCP4822.c -msgid "gain must be 1 or 2" -msgstr "" - #: py/objgenerator.c msgid "generator already executing" msgstr "" From afb64e0f3c913b69596ef3c722cf9becf7a9bf52 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 14:56:30 -0700 Subject: [PATCH 341/876] mtm_computer: make board.DAC() an actual singleton --- ports/raspberrypi/boards/mtm_computer/board.c | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index 9065ffebcf8..0b1e34eaacd 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -12,16 +12,22 @@ // board.DAC() — factory function that constructs an mcp4822.MCP4822 with // the MTM Workshop Computer's DAC pins (GP18=SCK, GP19=SDI, GP21=CS). + +static mp_obj_t board_dac_singleton = MP_OBJ_NULL; + static mp_obj_t board_dac_factory(void) { - mcp4822_mcp4822_obj_t *dac = mp_obj_malloc_with_finaliser( - mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); - common_hal_mcp4822_mcp4822_construct( - dac, - &pin_GPIO18, // clock (SCK) - &pin_GPIO19, // mosi (SDI) - &pin_GPIO21, // cs - 1); // gain 1x - return MP_OBJ_FROM_PTR(dac); + if (board_dac_singleton == MP_OBJ_NULL) { + mcp4822_mcp4822_obj_t *dac = mp_obj_malloc_with_finaliser( + mcp4822_mcp4822_obj_t, &mcp4822_mcp4822_type); + common_hal_mcp4822_mcp4822_construct( + dac, + &pin_GPIO18, // clock (SCK) + &pin_GPIO19, // mosi (SDI) + &pin_GPIO21, // cs + 1); // gain 1x + board_dac_singleton = MP_OBJ_FROM_PTR(dac); + } + return board_dac_singleton; } MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); From 072c27785580ddd8db1144164718a4edddc322e6 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 15:21:02 -0700 Subject: [PATCH 342/876] mtm_computer: make sure board.DAC() gets deallocated on board deinit --- ports/raspberrypi/boards/mtm_computer/board.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/raspberrypi/boards/mtm_computer/board.c b/ports/raspberrypi/boards/mtm_computer/board.c index 0b1e34eaacd..4fec0cd5b8b 100644 --- a/ports/raspberrypi/boards/mtm_computer/board.c +++ b/ports/raspberrypi/boards/mtm_computer/board.c @@ -31,4 +31,10 @@ static mp_obj_t board_dac_factory(void) { } MP_DEFINE_CONST_FUN_OBJ_0(board_dac_obj, board_dac_factory); +void board_deinit(void) { + if (board_dac_singleton != MP_OBJ_NULL) { + common_hal_mcp4822_mcp4822_deinit(MP_OBJ_TO_PTR(board_dac_singleton)); + board_dac_singleton = MP_OBJ_NULL; + } +} // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. From 8309a23932fd0f67c1b64d7a25687bd4c5536190 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 15:21:28 -0700 Subject: [PATCH 343/876] mcp4822 CS/MOSI argument fix, as per requested --- ports/raspberrypi/common-hal/mcp4822/MCP4822.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/raspberrypi/common-hal/mcp4822/MCP4822.c b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c index cb6cddb8343..7a8ad7d4df2 100644 --- a/ports/raspberrypi/common-hal/mcp4822/MCP4822.c +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c @@ -143,8 +143,7 @@ void common_hal_mcp4822_mcp4822_construct(mcp4822_mcp4822_obj_t *self, // The SET pin group spans from MOSI to CS. // MOSI must have a lower GPIO number than CS, gap at most 4. if (cs->number <= mosi->number || (cs->number - mosi->number) > 4) { - mp_raise_ValueError( - MP_ERROR_TEXT("cs pin must be 1-4 positions above mosi pin")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q and %q"), MP_QSTR_CS, MP_QSTR_MOSI); } uint8_t set_count = cs->number - mosi->number + 1; From 74aee24aa9bee0ff61324d062cc09181620fe5aa Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Tue, 24 Mar 2026 15:21:55 -0700 Subject: [PATCH 344/876] mcp4822 CS/MOSI argument fix, as per requested --- locale/circuitpython.pot | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 8bfc2d5bde3..57c0a13e991 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1297,6 +1297,7 @@ msgstr "" msgid "Invalid %q" msgstr "" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" @@ -3040,10 +3041,6 @@ msgstr "" msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "cs pin must be 1-4 positions above mosi pin" -msgstr "" - #: extmod/ulab/code/scipy/optimize/optimize.c msgid "data must be iterable" msgstr "" From 0f690b7009c08a3854a7f6e1b3a5b485c9848f55 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Wed, 25 Mar 2026 09:22:27 -0700 Subject: [PATCH 345/876] fix zephyr builds by running update_boardnfo.py --- ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index a8c03d5a4e8..cb705c48af5 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -64,6 +64,7 @@ locale = false lvfontio = true # Zephyr board has busio math = false max3421e = false +mcp4822 = false mdns = false memorymap = false memorymonitor = false From 14c1815654f59ac9088faf5b801047db88f680e1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 27 Mar 2026 13:49:25 -0400 Subject: [PATCH 346/876] wip --- .gitattributes | 1 + LICENSE_MicroPython | 2 +- docs/library/collections.rst | 16 + docs/library/platform.rst | 8 + docs/library/re.rst | 14 +- docs/library/sys.rst | 18 +- docs/reference/glossary.rst | 7 + extmod/cyw43_config_common.h | 126 +++ extmod/extmod.mk | 4 +- extmod/littlefs-include/lfs2_defines.h | 12 + extmod/lwip-include/arch/cc.h | 41 - extmod/lwip-include/arch/perf.h | 7 - extmod/lwip-include/lwipopts.h | 36 - extmod/lwip-include/lwipopts_common.h | 3 + extmod/modjson.c | 3 +- extmod/modplatform.c | 38 + extmod/modre.c | 48 +- extmod/modtime.c | 30 +- extmod/vfs.c | 2 +- extmod/vfs_blockdev.c | 2 +- extmod/vfs_fat.c | 73 +- extmod/vfs_lfsx.c | 16 +- extmod/vfs_lfsx_file.c | 4 +- extmod/vfs_posix.c | 19 +- extmod/vfs_reader.c | 2 +- lib/berkeley-db-1.xx | 2 +- lib/libm_dbl/libm.h | 2 + lib/libm_dbl/rint.c | 2 +- lib/littlefs/lfs2.c | 870 +++++++++++------- lib/littlefs/lfs2.h | 100 +- lib/littlefs/lfs2_util.c | 3 + lib/littlefs/lfs2_util.h | 56 +- lib/micropython-lib | 2 +- main.c | 4 +- mpy-cross/main.c | 100 +- mpy-cross/mpconfigport.h | 25 +- mpy-cross/mpy_cross/__init__.py | 2 +- mpy-cross/mpy_cross/__main__.py | 1 - ports/analog/supervisor/port.c | 2 +- ports/atmel-samd/common-hal/alarm/__init__.c | 2 +- .../common-hal/alarm/touch/TouchAlarm.c | 2 +- ports/atmel-samd/reset.c | 2 +- ports/atmel-samd/reset.h | 4 +- ports/atmel-samd/supervisor/port.c | 2 +- ports/espressif/bindings/espidf/__init__.c | 2 +- ports/espressif/bindings/espidf/__init__.h | 4 +- ports/espressif/common-hal/alarm/__init__.c | 2 +- .../common-hal/microcontroller/__init__.c | 2 +- ports/espressif/supervisor/port.c | 2 +- ports/mimxrt10xx/reset.h | 4 +- ports/nordic/common-hal/alarm/__init__.c | 2 +- ports/raspberrypi/common-hal/alarm/__init__.c | 2 +- ports/raspberrypi/common-hal/wifi/Radio.c | 2 +- ports/raspberrypi/common-hal/wifi/__init__.h | 2 +- ports/raspberrypi/supervisor/port.c | 2 +- ports/stm/common-hal/alarm/__init__.c | 2 +- ports/stm/supervisor/port.c | 2 +- ports/unix/Makefile | 34 +- ports/unix/README.md | 26 + ports/unix/coverage.c | 133 ++- ports/unix/coveragecpp.cpp | 51 + ports/unix/input.c | 3 + ports/unix/main.c | 181 ++-- ports/unix/modtime.c | 12 +- ports/unix/mpconfigport.h | 30 +- ports/unix/mpconfigport.mk | 1 + ports/unix/mphalport.h | 3 + ports/unix/mpthreadport.c | 41 +- ports/unix/stack_size.h | 54 ++ .../unix/variants/coverage/mpconfigvariant.h | 11 + .../unix/variants/longlong/mpconfigvariant.h | 33 +- .../unix/variants/longlong/mpconfigvariant.mk | 8 + ports/unix/variants/minimal/mpconfigvariant.h | 4 +- ports/unix/variants/mpconfigvariant_common.h | 8 +- ports/unix/variants/nanbox/mpconfigvariant.h | 7 - py/argcheck.c | 6 +- py/asmarm.c | 114 ++- py/asmarm.h | 61 +- py/asmbase.c | 4 +- py/asmrv32.c | 137 +-- py/asmrv32.h | 83 +- py/asmthumb.c | 122 ++- py/asmthumb.h | 128 ++- py/asmx64.h | 37 +- py/asmx86.h | 37 +- py/asmxtensa.c | 178 +++- py/asmxtensa.h | 85 +- py/bc.c | 2 +- py/bc.h | 43 +- py/binary.c | 39 +- py/builtin.h | 1 + py/builtinhelp.c | 5 +- py/builtinimport.c | 33 +- py/circuitpy_mpconfig.h | 2 +- py/compile.c | 16 +- py/cstack.h | 4 +- py/dynruntime.h | 6 +- py/dynruntime.mk | 13 +- py/emitcommon.c | 17 +- py/emitglue.c | 4 + py/emitinlinerv32.c | 422 ++++----- py/emitinlinextensa.c | 211 ++++- py/emitnative.c | 263 ++---- py/emitndebug.c | 12 +- py/formatfloat.c | 759 ++++++++------- py/formatfloat.h | 1 + py/gc.c | 4 +- py/gc.h | 5 + py/make_root_pointers.py | 2 - py/makecompresseddata.py | 2 - py/makemoduledefs.py | 18 +- py/makeqstrdata.py | 23 +- py/makeqstrdefs.py | 4 +- py/makeversionhdr.py | 21 +- py/malloc.c | 56 +- py/misc.h | 164 +++- py/mkrules.cmake | 52 ++ py/mkrules.mk | 13 +- py/modio.c | 9 +- py/modmath.c | 13 +- py/modmicropython.c | 2 +- py/modsys.c | 34 +- py/mpconfig.h | 298 +++++- py/mphal.h | 1 + py/mpprint.c | 93 +- py/mpprint.h | 18 +- py/mpstate.h | 6 + py/mpz.c | 16 +- py/nativeglue.h | 2 +- py/nlr.c | 2 +- py/nlr.h | 6 +- py/nlraarch64.c | 2 +- py/nlrmips.c | 2 +- py/nlrpowerpc.c | 4 +- py/nlrrv32.c | 2 +- py/nlrrv64.c | 2 +- py/nlrthumb.c | 2 +- py/nlrx64.c | 2 +- py/nlrx86.c | 2 +- py/nlrxtensa.c | 2 +- py/obj.c | 32 +- py/obj.h | 56 +- py/objarray.c | 37 +- py/objboundmeth.c | 4 + py/objcell.c | 2 +- py/objcode.c | 71 ++ py/objcode.h | 5 +- py/objcomplex.c | 31 +- py/objdict.c | 5 +- py/objfloat.c | 34 +- py/objint.c | 13 +- py/objint_longlong.c | 78 +- py/objint_mpz.c | 7 +- py/objlist.c | 160 ++-- py/objmodule.c | 22 +- py/objmodule.h | 3 + py/objnamedtuple.c | 2 +- py/objrange.c | 14 +- py/objringio.c | 19 +- py/objstr.c | 19 +- py/objtuple.c | 3 - py/objtuple.h | 5 +- py/objtype.c | 98 +- py/parse.c | 81 +- py/parsenum.c | 336 ++++--- py/parsenum.h | 5 + py/persistentcode.c | 48 +- py/persistentcode.h | 7 +- py/profile.c | 2 +- py/py.cmake | 1 + py/py.mk | 2 +- py/repl.c | 11 +- py/runtime.c | 158 ++-- py/runtime.h | 117 ++- py/runtime_utils.c | 56 ++ py/scheduler.c | 39 +- py/showbc.c | 14 +- py/smallint.c | 26 - py/smallint.h | 1 - py/stream.c | 55 +- py/stream.h | 3 +- py/vm.c | 33 +- pyproject.toml | 120 ++- shared-bindings/_bleio/__init__.c | 6 +- shared-bindings/_bleio/__init__.h | 6 +- shared-bindings/adafruit_pixelbuf/PixelBuf.c | 2 +- shared-bindings/alarm/__init__.h | 2 +- shared-bindings/math/__init__.c | 2 +- shared-bindings/memorymonitor/__init__.c | 2 +- shared-bindings/memorymonitor/__init__.h | 2 +- shared-bindings/microcontroller/Pin.c | 6 +- shared-bindings/microcontroller/Pin.h | 6 +- shared-bindings/microcontroller/__init__.h | 2 +- shared-bindings/paralleldisplaybus/__init__.c | 3 - shared-bindings/socketpool/SocketPool.c | 2 +- shared-bindings/socketpool/SocketPool.h | 2 +- shared-bindings/storage/__init__.h | 2 +- shared-bindings/usb/core/__init__.c | 4 +- shared-bindings/usb/core/__init__.h | 4 +- shared-bindings/util.h | 2 +- shared-module/ssl/SSLSocket.c | 2 +- shared-module/struct/__init__.c | 3 +- shared/libc/abort_.c | 4 +- shared/memzip/make-memzip.py | 2 - shared/netutils/dhcpserver.c | 315 ------- shared/netutils/netutils.c | 100 -- shared/netutils/netutils.h | 58 -- shared/netutils/trace.c | 170 ---- shared/runtime/mpirq.c | 40 +- shared/runtime/mpirq.h | 1 + shared/runtime/pyexec.c | 45 +- shared/runtime/pyexec.h | 11 + shared/timeutils/timeutils.c | 134 ++- shared/timeutils/timeutils.h | 119 ++- supervisor/port.h | 4 +- supervisor/shared/safe_mode.h | 2 +- tests/README.md | 27 +- tests/basics/annotate_var.py.exp | 5 - tests/basics/array_add.py | 6 + tests/basics/assign_expr.py.exp | 16 - tests/basics/assign_expr_scope.py.exp | 23 - tests/basics/async_await.py.exp | 32 - tests/basics/async_await2.py.exp | 5 - tests/basics/async_def.py.exp | 3 - tests/basics/async_for.py.exp | 51 - tests/basics/async_for2.py | 2 +- tests/basics/async_for2.py.exp | 32 - tests/basics/async_syntaxerror.py.exp | 2 - tests/basics/async_with.py.exp | 11 - tests/basics/async_with2.py | 2 +- tests/basics/async_with2.py.exp | 17 - tests/basics/async_with_break.py.exp | 15 - tests/basics/async_with_return.py.exp | 15 - tests/basics/attrtuple2.py | 25 + tests/basics/boundmeth1.py | 2 +- tests/basics/builtin_help.py | 6 + tests/basics/builtin_pow3_intbig.py | 5 + tests/basics/builtin_range.py | 18 +- tests/basics/builtin_range_maxsize.py | 38 + tests/basics/builtin_setattr.py | 2 +- tests/basics/builtin_slice.py | 37 +- tests/basics/bytes_format_modulo.py.exp | 5 - tests/basics/class_bind_self.py | 2 +- tests/basics/class_descriptor.py | 20 +- tests/basics/class_inplace_op2.py.exp | 12 - tests/basics/class_ordereddict.py.exp | 1 - tests/basics/class_setname_hazard.py | 182 ++++ tests/basics/class_setname_hazard_rand.py | 111 +++ tests/basics/del_attr.py | 2 +- tests/basics/del_global.py | 2 +- tests/basics/del_name.py | 2 +- tests/basics/dict_views.py | 5 + tests/basics/exception_chain.py | 7 + tests/basics/frozenset_set.py | 2 +- tests/basics/fun_code_colines.py | 81 ++ tests/basics/fun_code_colines.py.exp | 20 + tests/basics/fun_code_full.py | 40 + tests/basics/fun_code_full.py.exp | 9 + tests/basics/fun_code_lnotab.py | 34 + tests/basics/fun_name.py | 2 +- tests/basics/gc1.py | 4 +- tests/basics/import_instance_method.py | 38 + tests/basics/int_64_basics.py | 161 ++++ tests/basics/int_big_to_small.py | 11 + tests/basics/int_big_to_small_int29.py | 22 + tests/basics/int_big_to_small_int29.py.exp | 25 + tests/basics/io_buffered_writer.py | 31 +- tests/basics/io_buffered_writer.py.exp | 5 + tests/basics/io_bytesio_cow.py | 8 +- tests/basics/io_bytesio_ext.py | 8 +- tests/basics/io_bytesio_ext2.py | 7 +- tests/basics/io_iobase.py | 10 +- tests/basics/io_stringio1.py | 7 +- tests/basics/io_stringio_base.py | 6 +- tests/basics/io_stringio_with.py | 7 +- tests/basics/io_write_ext.py | 7 +- tests/basics/list_pop.py | 2 +- tests/basics/module2.py | 2 +- tests/basics/namedtuple1.py | 3 + tests/basics/parser.py | 2 +- tests/basics/python34.py | 2 +- tests/basics/python36.py.exp | 5 - tests/basics/self_type_check.py | 8 + tests/basics/slice_optimise.py | 23 + tests/basics/slice_optimise.py.exp | 2 + tests/basics/special_methods2.py.exp | 19 - tests/basics/string_format.py | 10 + tests/basics/string_format_sep.py | 9 + tests/basics/string_fstring_debug.py.exp | 9 - tests/basics/subclass_native_init.py | 4 + tests/basics/syntaxerror.py | 4 +- tests/basics/sys1.py | 6 + tests/basics/sys_tracebacklimit.py | 2 +- tests/basics/sys_tracebacklimit.py.native.exp | 22 + tests/basics/try_finally_continue.py.exp | 9 - tests/basics/tuple1.py | 2 +- tests/cmdline/cmd_compile_only.py | 13 + tests/cmdline/cmd_compile_only.py.exp | 1 + tests/cmdline/cmd_compile_only_error.py | 6 + tests/cmdline/cmd_compile_only_error.py.exp | 1 + tests/cmdline/cmd_file_variable.py | 5 + tests/cmdline/cmd_file_variable.py.exp | 1 + tests/cmdline/cmd_module_atexit.py | 16 + tests/cmdline/cmd_module_atexit.py.exp | 3 + tests/cmdline/cmd_module_atexit_exc.py | 19 + tests/cmdline/cmd_module_atexit_exc.py.exp | 3 + tests/cmdline/cmd_sys_exit_0.py | 5 + tests/cmdline/cmd_sys_exit_0.py.exp | 1 + tests/cmdline/cmd_sys_exit_error.py | 5 + tests/cmdline/cmd_sys_exit_error.py.exp | 1 + tests/cmdline/cmd_sys_exit_none.py | 5 + tests/cmdline/cmd_sys_exit_none.py.exp | 1 + tests/cmdline/repl_autocomplete_underscore.py | 33 + .../repl_autocomplete_underscore.py.exp | 41 + tests/cmdline/repl_lock.py | 7 + tests/cmdline/repl_lock.py.exp | 10 + tests/cmdline/repl_paste.py | 90 ++ tests/cmdline/repl_paste.py.exp | 133 +++ tests/cpydiff/core_class_initsubclass.py | 21 + ...core_class_initsubclass_autoclassmethod.py | 31 + .../cpydiff/core_class_initsubclass_kwargs.py | 22 + .../cpydiff/core_class_initsubclass_super.py | 22 + tests/cpydiff/core_fstring_concat.py | 2 +- tests/cpydiff/core_fstring_parser.py | 2 +- tests/cpydiff/core_fstring_repr.py | 2 +- tests/cpydiff/core_import_all.py | 10 - tests/cpydiff/modules3/__init__.py | 1 - tests/cpydiff/modules3/foo.py | 2 - tests/cpydiff/modules_errno_enotsup.py | 10 + tests/cpydiff/modules_struct_fewargs.py | 2 +- tests/cpydiff/modules_struct_manyargs.py | 2 +- .../modules_struct_whitespace_in_format.py | 2 +- tests/cpydiff/syntax_arg_unpacking.py | 2 +- tests/cpydiff/syntax_literal_underscore.py | 19 + tests/cpydiff/syntax_spaces.py | 19 +- tests/cpydiff/types_complex_parser.py | 14 + .../types_float_implicit_conversion.py | 2 +- tests/cpydiff/types_float_rounding.py | 8 - tests/cpydiff/types_oserror_errnomap.py | 48 + tests/cpydiff/types_range_limits.py | 26 + tests/cpydiff/types_str_formatsep.py | 19 + tests/cpydiff/types_str_formatsep_float.py | 11 + tests/extmod/asyncio_basic.py.exp | 6 - tests/extmod/asyncio_event_queue.py | 64 ++ tests/extmod/asyncio_event_queue.py.exp | 5 + tests/extmod/asyncio_heaplock.py | 12 +- tests/extmod/asyncio_iterator_event.py | 86 ++ tests/extmod/asyncio_iterator_event.py.exp | 5 + tests/extmod/asyncio_lock.py.exp | 41 - tests/extmod/asyncio_set_exception_handler.py | 2 +- tests/extmod/asyncio_wait_for_linked_task.py | 66 ++ tests/extmod/asyncio_wait_task.py.exp | 12 - tests/extmod/binascii_hexlify.py | 8 +- tests/extmod/binascii_unhexlify.py | 8 +- tests/extmod/framebuf_blit.py | 68 ++ tests/extmod/framebuf_blit.py.exp | 45 + tests/extmod/hashlib_md5.py | 3 +- tests/extmod/hashlib_sha1.py | 3 +- tests/extmod/hashlib_sha256.py | 3 +- tests/extmod/json_dump.py | 4 +- tests/extmod/json_dump_iobase.py | 2 +- tests/extmod/json_dump_separators.py | 6 +- tests/extmod/json_dumps_extra.py | 2 +- tests/extmod/json_dumps_separators.py | 2 +- tests/extmod/json_loads.py | 24 + tests/extmod/json_loads_bytes.py.exp | 2 - tests/extmod/json_loads_int_64.py | 16 + tests/extmod/machine_hard_timer.py | 45 + tests/extmod/machine_hard_timer.py.exp | 16 + tests/extmod/machine_timer.py | 48 + tests/extmod/machine_timer.py.exp | 16 + tests/extmod/platform_basic.py | 8 + tests/extmod/random_extra_float.py | 8 +- tests/extmod/re_error.py | 2 +- tests/extmod/re_start_end_pos.py | 78 ++ tests/extmod/re_sub.py | 2 +- tests/extmod/re_sub_unmatched.py.exp | 1 - tests/extmod/socket_badconstructor.py | 22 + tests/extmod/socket_fileno.py | 17 + tests/extmod/time_mktime.py | 120 +++ tests/extmod/time_res.py | 7 +- tests/extmod/tls_dtls.py | 12 +- tests/extmod/tls_dtls.py.exp | 1 + tests/extmod/{ssl_noleak.py => tls_noleak.py} | 0 tests/extmod/tls_threads.py | 58 ++ tests/extmod/uctypes_addressof.py | 7 +- tests/extmod/uctypes_array_load_store.py | 7 + tests/extmod/vfs_blockdev_invalid.py | 8 +- tests/extmod/vfs_blockdev_invalid.py.exp | 24 +- tests/extmod/vfs_fat_ilistdir_del.py | 3 +- tests/extmod/vfs_lfs.py | 2 +- tests/extmod/vfs_lfs_error.py | 46 +- tests/extmod/vfs_lfs_error.py.exp | 44 +- tests/extmod/vfs_lfs_ilistdir_del.py | 10 +- tests/extmod/vfs_mountinfo.py | 1 - tests/extmod/vfs_posix.py | 16 +- tests/extmod/vfs_posix_ilistdir_del.py | 3 +- tests/extmod/vfs_posix_paths.py | 2 +- tests/extmod/vfs_posix_paths.py.exp | 2 +- tests/extmod/vfs_posix_readonly.py | 99 ++ tests/extmod/vfs_posix_readonly.py.exp | 7 + tests/extmod/vfs_rom.py | 3 +- tests/extmod/websocket_toobig.py | 28 + tests/extmod/websocket_toobig.py.exp | 1 + tests/extmod_hardware/machine_counter.py | 90 ++ tests/extmod_hardware/machine_encoder.py | 153 +++ tests/extmod_hardware/machine_i2c_target.py | 307 ++++++ tests/feature_check/float.py | 13 - tests/feature_check/float.py.exp | 1 - tests/feature_check/inlineasm_rv32_zba.py | 10 + tests/feature_check/inlineasm_rv32_zba.py.exp | 1 + tests/feature_check/int_64.py | 2 + tests/feature_check/int_64.py.exp | 1 + tests/feature_check/io_module.py | 6 - tests/feature_check/io_module.py.exp | 0 tests/feature_check/repl_emacs_check.py.exp | 2 +- .../repl_words_move_check.py.exp | 2 +- tests/feature_check/target_info.py | 20 +- tests/float/cmath_fun.py | 3 + tests/float/float_array.py | 8 +- tests/float/float_format.py | 17 +- tests/float/float_format_accuracy.py | 73 ++ tests/float/float_format_ints.py | 32 +- tests/float/float_parse_doubleprec.py | 6 + tests/float/float_struct_e.py | 2 +- tests/float/float_struct_e_doubleprec.py | 43 + tests/float/float_struct_e_fp30.py | 43 + tests/float/int_64_float.py | 25 + tests/float/math_constants.py | 27 +- tests/float/math_constants_extra.py | 3 + tests/float/math_fun_special.py | 5 + tests/float/string_format2.py | 4 +- tests/float/string_format_fp30.py | 42 - tests/float/string_format_modulo.py | 2 +- tests/float/string_format_modulo3.py | 2 +- tests/float/string_format_modulo3.py.exp | 2 - tests/frozen/frozentest.mpy | Bin 196 -> 200 bytes tests/frozen/frozentest.py | 2 +- tests/import/builtin_ext.py | 6 + tests/import/builtin_import.py | 9 + tests/import/import_broken.py | 6 + tests/import/import_file.py | 4 + tests/import/import_override.py | 4 + tests/import/import_override.py.exp | 2 - tests/import/import_override2.py | 18 + tests/import/import_pkg7.py.exp | 8 - tests/import/import_pkg9.py | 2 +- tests/import/import_star.py | 59 ++ tests/import/import_star_error.py | 5 + tests/import/module_getattr.py.exp | 1 - tests/import/pkg7/subpkg1/subpkg2/mod3.py | 4 +- tests/import/pkgstar_all_array/__init__.py | 49 + tests/import/pkgstar_all_array/funcs.py | 2 + tests/import/pkgstar_all_inval/__init__.py | 1 + tests/import/pkgstar_all_miss/__init__.py | 8 + tests/import/pkgstar_all_tuple/__init__.py | 22 + tests/import/pkgstar_default/__init__.py | 20 + tests/inlineasm/rv32/asmzba.py | 18 + tests/inlineasm/rv32/asmzba.py.exp | 3 + tests/inlineasm/thumb/asmerrors.py | 4 + tests/inlineasm/thumb/asmerrors.py.exp | 1 + tests/inlineasm/xtensa/asmargs.py | 44 + tests/inlineasm/xtensa/asmargs.py.exp | 5 + tests/inlineasm/xtensa/asmarith.py | 119 +++ tests/inlineasm/xtensa/asmarith.py.exp | 40 + tests/inlineasm/xtensa/asmbranch.py | 299 ++++++ tests/inlineasm/xtensa/asmbranch.py.exp | 66 ++ tests/inlineasm/xtensa/asmjump.py | 26 + tests/inlineasm/xtensa/asmjump.py.exp | 2 + tests/inlineasm/xtensa/asmloadstore.py | 98 ++ tests/inlineasm/xtensa/asmloadstore.py.exp | 9 + tests/inlineasm/xtensa/asmmisc.py | 25 + tests/inlineasm/xtensa/asmmisc.py.exp | 3 + tests/inlineasm/xtensa/asmshift.py | 137 +++ tests/inlineasm/xtensa/asmshift.py.exp | 17 + tests/internal_bench/class_create-0-empty.py | 11 + tests/internal_bench/class_create-1-slots.py | 12 + .../internal_bench/class_create-1.1-slots5.py | 12 + .../class_create-2-classattr.py | 11 + .../class_create-2.1-classattr5.py | 15 + .../class_create-2.3-classattr5objs.py | 20 + .../class_create-3-instancemethod.py | 12 + .../class_create-4-classmethod.py | 13 + .../class_create-4.1-classmethod_implicit.py | 12 + .../class_create-5-staticmethod.py | 13 + .../class_create-6-getattribute.py | 12 + .../class_create-6.1-getattr.py | 12 + .../class_create-6.2-property.py | 13 + .../class_create-6.3-descriptor.py | 17 + .../internal_bench/class_create-7-inherit.py | 14 + .../class_create-7.1-inherit_initsubclass.py | 16 + .../class_create-8-metaclass_setname.py | 17 + .../class_create-8.1-metaclass_setname5.py | 21 + .../internal_bench/class_instance-0-object.py | 11 + .../class_instance-0.1-object-gc.py | 13 + .../internal_bench/class_instance-1-empty.py | 13 + .../class_instance-1.1-classattr.py | 13 + .../internal_bench/class_instance-1.2-func.py | 14 + .../class_instance-1.3-empty-gc.py | 15 + tests/internal_bench/class_instance-2-init.py | 14 + .../class_instance-2.1-init_super.py | 14 + .../internal_bench/class_instance-2.2-new.py | 14 + tests/internal_bench/class_instance-3-del.py | 14 + .../class_instance-3.1-del-gc.py | 16 + .../internal_bench/class_instance-4-slots.py | 13 + .../class_instance-4.1-slots5.py | 13 + .../var-6.2-instance-speciallookup.py | 19 + .../var-6.3-instance-property.py | 17 + .../var-6.4-instance-descriptor.py | 20 + .../var-6.5-instance-getattr.py | 16 + .../var-6.6-instance-builtin_ordered.py | 12 + tests/internal_bench/var-9-getattr.py | 16 + .../internal_bench/var-9.1-getattr_default.py | 15 + .../var-9.2-getattr_default_special.py | 16 + tests/internal_bench/var-9.3-except_ok.py | 23 + .../var-9.4-except_selfinduced.py | 22 + tests/internal_bench/var-9.5-except_error.py | 22 + .../var-9.6-except_error_special.py | 23 + tests/io/builtin_print_file.py | 2 +- tests/io/file_seek.py | 2 +- tests/micropython/builtin_execfile.py | 21 + tests/micropython/builtin_execfile.py.exp | 3 + tests/micropython/const_error.py | 2 - tests/micropython/const_error.py.exp | 2 - tests/micropython/const_float.py | 23 + tests/micropython/const_float.py.exp | 4 + tests/micropython/const_math.py | 18 + tests/micropython/const_math.py.exp | 1 + tests/micropython/decorator_error.py | 2 +- tests/micropython/emg_exc.py | 3 +- tests/micropython/emg_exc.py.native.exp | 2 + tests/micropython/extreme_exc.py | 6 +- tests/micropython/heap_lock.py | 6 +- tests/micropython/heap_locked.py | 6 +- tests/micropython/heapalloc.py | 6 +- tests/micropython/heapalloc_exc_compressed.py | 8 +- .../heapalloc_exc_compressed_emg_exc.py | 8 +- tests/micropython/heapalloc_exc_raise.py | 8 +- tests/micropython/heapalloc_fail_bytearray.py | 8 +- tests/micropython/heapalloc_fail_dict.py | 8 +- tests/micropython/heapalloc_fail_list.py | 8 +- .../micropython/heapalloc_fail_memoryview.py | 8 +- tests/micropython/heapalloc_fail_set.py | 8 +- tests/micropython/heapalloc_fail_tuple.py | 8 +- tests/micropython/heapalloc_inst_call.py | 9 +- tests/micropython/heapalloc_int_from_bytes.py | 9 +- tests/micropython/heapalloc_slice.py | 18 + tests/micropython/heapalloc_str.py | 9 +- tests/micropython/heapalloc_super.py | 9 +- .../heapalloc_traceback.py.native.exp | 3 + tests/micropython/heapalloc_yield_from.py | 8 +- tests/micropython/import_mpy_native.py | 5 +- tests/micropython/import_mpy_native_gc.py | 10 +- tests/micropython/kbd_intr.py | 6 +- tests/micropython/meminfo.py | 18 +- tests/micropython/memstats.py | 24 +- tests/micropython/opt_level.py | 8 +- tests/micropython/opt_level_lineno.py | 9 +- tests/micropython/opt_level_lineno.py.exp | 2 +- tests/micropython/ringio_big.py | 29 + tests/micropython/ringio_big.py.exp | 2 + tests/micropython/schedule.py | 6 +- tests/micropython/stack_use.py | 12 +- tests/micropython/test_normalize_newlines.py | 14 + .../test_normalize_newlines.py.exp | 8 + tests/micropython/viper_large_jump.py | 20 + tests/micropython/viper_large_jump.py.exp | 1 + .../micropython/viper_ptr16_load_boundary.py | 39 + .../viper_ptr16_load_boundary.py.exp | 20 + .../micropython/viper_ptr16_store_boundary.py | 63 ++ .../viper_ptr16_store_boundary.py.exp | 28 + .../micropython/viper_ptr32_load_boundary.py | 39 + .../viper_ptr32_load_boundary.py.exp | 20 + .../micropython/viper_ptr32_store_boundary.py | 68 ++ .../viper_ptr32_store_boundary.py.exp | 28 + tests/micropython/viper_ptr8_load_boundary.py | 38 + .../viper_ptr8_load_boundary.py.exp | 20 + .../micropython/viper_ptr8_store_boundary.py | 63 ++ .../viper_ptr8_store_boundary.py.exp | 28 + tests/misc/non_compliant.py | 6 +- tests/misc/non_compliant_lexer.py | 2 +- tests/misc/print_exception.py.native.exp | 18 + tests/misc/rge_sm.py | 59 +- tests/misc/sys_exc_info.py | 5 +- tests/misc/sys_settrace_cov.py | 23 + tests/misc/sys_settrace_cov.py.exp | 2 + tests/multi_extmod/machine_i2c_target_irq.py | 137 +++ .../machine_i2c_target_irq.py.exp | 15 + .../multi_extmod/machine_i2c_target_memory.py | 79 ++ .../machine_i2c_target_memory.py.exp | 16 + tests/perf_bench/bm_fft.py | 2 +- tests/perf_bench/bm_pidigits.py | 6 + tests/perf_bench/core_import_mpy_multi.py | 4 +- tests/perf_bench/core_import_mpy_single.py | 4 +- tests/run-internalbench.py | 101 +- tests/run-multitests.py | 93 +- tests/run-natmodtests.py | 88 +- tests/run-perfbench.py | 71 +- tests/run-tests.py | 742 ++++++++++----- tests/serial_test.py | 338 +++++++ tests/stress/bytecode_limit.py | 18 +- tests/stress/bytecode_limit.py.exp | 2 +- tests/stress/dict_copy.py | 7 +- tests/stress/dict_create.py | 6 +- tests/stress/fun_call_limit.py | 10 +- tests/stress/fun_call_limit.py.exp | 2 +- tests/stress/qstr_limit.py | 42 +- tests/stress/qstr_limit.py.exp | 55 +- tests/stress/qstr_limit_str_modulo.py | 21 + tests/stress/qstr_limit_str_modulo.py.exp | 5 + tests/stress/recursive_iternext.py | 64 +- tests/target_wiring/EK_RA6M2.py | 8 + tests/target_wiring/NUCLEO_WB55.py | 8 + tests/target_wiring/PYBx.py | 8 + tests/target_wiring/ZEPHYR_NUCLEO_WB55RG.py | 7 + tests/target_wiring/alif.py | 7 + tests/target_wiring/esp32.py | 12 + tests/target_wiring/mimxrt.py | 7 + tests/target_wiring/nrf.py | 7 + tests/target_wiring/rp2.py | 7 + tests/target_wiring/samd.py | 7 + tests/thread/mutate_bytearray.py | 3 +- tests/thread/mutate_dict.py | 3 +- tests/thread/mutate_instance.py | 3 +- tests/thread/mutate_list.py | 3 +- tests/thread/mutate_set.py | 3 +- tests/thread/stress_aes.py | 2 +- tests/thread/stress_recurse.py | 3 +- tests/thread/stress_schedule.py | 4 +- tests/thread/thread_coop.py | 3 + tests/thread/thread_exc1.py | 3 +- tests/thread/thread_exc2.py.native.exp | 3 + tests/thread/thread_gc1.py | 3 +- tests/thread/thread_ident1.py | 3 +- tests/thread/thread_lock3.py | 3 +- ...thread_lock4.py => thread_lock4_intbig.py} | 0 tests/thread/thread_shared1.py | 3 +- tests/thread/thread_shared2.py | 3 +- tests/thread/thread_stacksize1.py | 3 +- tests/thread/thread_stdin.py | 3 +- tests/unix/extra_coverage.py | 35 +- tests/unix/extra_coverage.py.exp | 63 +- tests/unix/ffi_float2.py | 3 +- tests/unix/ffi_float2.py.exp | 12 +- tests/unix/mod_os.py | 3 + tests/unix/time_mktime_localtime.py | 6 +- tools/boardgen.py | 8 +- tools/cc1 | 90 +- tools/ci.sh | 469 +++++++--- tools/codeformat.py | 2 +- tools/file2h.py | 2 - tools/insert-usb-ids.py | 2 - tools/makemanifest.py | 1 - tools/manifestfile.py | 1 - tools/metrics.py | 63 +- tools/mpy-tool.py | 450 ++++++++- tools/mpy_ld.py | 95 +- tools/pyboard.py | 72 +- tools/pydfu.py | 8 +- tools/verifygitlog.py | 31 +- 660 files changed, 14475 insertions(+), 5156 deletions(-) create mode 100644 extmod/cyw43_config_common.h create mode 100644 extmod/littlefs-include/lfs2_defines.h delete mode 100644 extmod/lwip-include/arch/cc.h delete mode 100644 extmod/lwip-include/arch/perf.h delete mode 100644 extmod/lwip-include/lwipopts.h create mode 100644 ports/unix/stack_size.h rename shared/netutils/dhcpserver.h => ports/unix/variants/longlong/mpconfigvariant.h (60%) create mode 100644 ports/unix/variants/longlong/mpconfigvariant.mk delete mode 100644 shared/netutils/dhcpserver.c delete mode 100644 shared/netutils/netutils.c delete mode 100644 shared/netutils/netutils.h delete mode 100644 shared/netutils/trace.c delete mode 100644 tests/basics/annotate_var.py.exp delete mode 100644 tests/basics/assign_expr.py.exp delete mode 100644 tests/basics/assign_expr_scope.py.exp delete mode 100644 tests/basics/async_await.py.exp delete mode 100644 tests/basics/async_await2.py.exp delete mode 100644 tests/basics/async_def.py.exp delete mode 100644 tests/basics/async_for.py.exp delete mode 100644 tests/basics/async_for2.py.exp delete mode 100644 tests/basics/async_syntaxerror.py.exp delete mode 100644 tests/basics/async_with.py.exp delete mode 100644 tests/basics/async_with2.py.exp delete mode 100644 tests/basics/async_with_break.py.exp delete mode 100644 tests/basics/async_with_return.py.exp create mode 100644 tests/basics/attrtuple2.py create mode 100644 tests/basics/builtin_range_maxsize.py delete mode 100644 tests/basics/bytes_format_modulo.py.exp delete mode 100644 tests/basics/class_inplace_op2.py.exp delete mode 100644 tests/basics/class_ordereddict.py.exp create mode 100644 tests/basics/class_setname_hazard.py create mode 100644 tests/basics/class_setname_hazard_rand.py create mode 100644 tests/basics/fun_code_colines.py create mode 100644 tests/basics/fun_code_colines.py.exp create mode 100644 tests/basics/fun_code_full.py create mode 100644 tests/basics/fun_code_full.py.exp create mode 100644 tests/basics/fun_code_lnotab.py create mode 100644 tests/basics/import_instance_method.py create mode 100644 tests/basics/int_64_basics.py create mode 100644 tests/basics/int_big_to_small_int29.py create mode 100644 tests/basics/int_big_to_small_int29.py.exp delete mode 100644 tests/basics/python36.py.exp create mode 100644 tests/basics/slice_optimise.py create mode 100644 tests/basics/slice_optimise.py.exp delete mode 100644 tests/basics/special_methods2.py.exp create mode 100644 tests/basics/string_format_sep.py delete mode 100644 tests/basics/string_fstring_debug.py.exp create mode 100644 tests/basics/sys_tracebacklimit.py.native.exp delete mode 100644 tests/basics/try_finally_continue.py.exp create mode 100644 tests/cmdline/cmd_compile_only.py create mode 100644 tests/cmdline/cmd_compile_only.py.exp create mode 100644 tests/cmdline/cmd_compile_only_error.py create mode 100644 tests/cmdline/cmd_compile_only_error.py.exp create mode 100644 tests/cmdline/cmd_file_variable.py create mode 100644 tests/cmdline/cmd_file_variable.py.exp create mode 100644 tests/cmdline/cmd_module_atexit.py create mode 100644 tests/cmdline/cmd_module_atexit.py.exp create mode 100644 tests/cmdline/cmd_module_atexit_exc.py create mode 100644 tests/cmdline/cmd_module_atexit_exc.py.exp create mode 100644 tests/cmdline/cmd_sys_exit_0.py create mode 100644 tests/cmdline/cmd_sys_exit_0.py.exp create mode 100644 tests/cmdline/cmd_sys_exit_error.py create mode 100644 tests/cmdline/cmd_sys_exit_error.py.exp create mode 100644 tests/cmdline/cmd_sys_exit_none.py create mode 100644 tests/cmdline/cmd_sys_exit_none.py.exp create mode 100644 tests/cmdline/repl_autocomplete_underscore.py create mode 100644 tests/cmdline/repl_autocomplete_underscore.py.exp create mode 100644 tests/cmdline/repl_lock.py create mode 100644 tests/cmdline/repl_lock.py.exp create mode 100644 tests/cmdline/repl_paste.py create mode 100644 tests/cmdline/repl_paste.py.exp create mode 100644 tests/cpydiff/core_class_initsubclass.py create mode 100644 tests/cpydiff/core_class_initsubclass_autoclassmethod.py create mode 100644 tests/cpydiff/core_class_initsubclass_kwargs.py create mode 100644 tests/cpydiff/core_class_initsubclass_super.py delete mode 100644 tests/cpydiff/core_import_all.py delete mode 100644 tests/cpydiff/modules3/__init__.py delete mode 100644 tests/cpydiff/modules3/foo.py create mode 100644 tests/cpydiff/modules_errno_enotsup.py create mode 100644 tests/cpydiff/syntax_literal_underscore.py create mode 100644 tests/cpydiff/types_complex_parser.py delete mode 100644 tests/cpydiff/types_float_rounding.py create mode 100644 tests/cpydiff/types_oserror_errnomap.py create mode 100644 tests/cpydiff/types_range_limits.py create mode 100644 tests/cpydiff/types_str_formatsep.py create mode 100644 tests/cpydiff/types_str_formatsep_float.py delete mode 100644 tests/extmod/asyncio_basic.py.exp create mode 100644 tests/extmod/asyncio_event_queue.py create mode 100644 tests/extmod/asyncio_event_queue.py.exp create mode 100644 tests/extmod/asyncio_iterator_event.py create mode 100644 tests/extmod/asyncio_iterator_event.py.exp delete mode 100644 tests/extmod/asyncio_lock.py.exp create mode 100644 tests/extmod/asyncio_wait_for_linked_task.py delete mode 100644 tests/extmod/asyncio_wait_task.py.exp create mode 100644 tests/extmod/framebuf_blit.py create mode 100644 tests/extmod/framebuf_blit.py.exp delete mode 100644 tests/extmod/json_loads_bytes.py.exp create mode 100644 tests/extmod/json_loads_int_64.py create mode 100644 tests/extmod/machine_hard_timer.py create mode 100644 tests/extmod/machine_hard_timer.py.exp create mode 100644 tests/extmod/machine_timer.py create mode 100644 tests/extmod/machine_timer.py.exp create mode 100644 tests/extmod/platform_basic.py create mode 100644 tests/extmod/re_start_end_pos.py delete mode 100644 tests/extmod/re_sub_unmatched.py.exp create mode 100644 tests/extmod/socket_badconstructor.py create mode 100644 tests/extmod/socket_fileno.py create mode 100644 tests/extmod/time_mktime.py rename tests/extmod/{ssl_noleak.py => tls_noleak.py} (100%) create mode 100644 tests/extmod/tls_threads.py create mode 100644 tests/extmod/vfs_posix_readonly.py create mode 100644 tests/extmod/vfs_posix_readonly.py.exp create mode 100644 tests/extmod/websocket_toobig.py create mode 100644 tests/extmod/websocket_toobig.py.exp create mode 100644 tests/extmod_hardware/machine_counter.py create mode 100644 tests/extmod_hardware/machine_encoder.py create mode 100644 tests/extmod_hardware/machine_i2c_target.py delete mode 100644 tests/feature_check/float.py delete mode 100644 tests/feature_check/float.py.exp create mode 100644 tests/feature_check/inlineasm_rv32_zba.py create mode 100644 tests/feature_check/inlineasm_rv32_zba.py.exp create mode 100644 tests/feature_check/int_64.py create mode 100644 tests/feature_check/int_64.py.exp delete mode 100644 tests/feature_check/io_module.py delete mode 100644 tests/feature_check/io_module.py.exp create mode 100644 tests/float/float_format_accuracy.py create mode 100644 tests/float/float_struct_e_doubleprec.py create mode 100644 tests/float/float_struct_e_fp30.py create mode 100644 tests/float/int_64_float.py delete mode 100644 tests/float/string_format_fp30.py delete mode 100644 tests/float/string_format_modulo3.py.exp delete mode 100644 tests/import/import_override.py.exp create mode 100644 tests/import/import_override2.py delete mode 100644 tests/import/import_pkg7.py.exp create mode 100644 tests/import/import_star.py delete mode 100644 tests/import/module_getattr.py.exp create mode 100644 tests/import/pkgstar_all_array/__init__.py create mode 100644 tests/import/pkgstar_all_array/funcs.py create mode 100644 tests/import/pkgstar_all_inval/__init__.py create mode 100644 tests/import/pkgstar_all_miss/__init__.py create mode 100644 tests/import/pkgstar_all_tuple/__init__.py create mode 100644 tests/import/pkgstar_default/__init__.py create mode 100644 tests/inlineasm/rv32/asmzba.py create mode 100644 tests/inlineasm/rv32/asmzba.py.exp create mode 100644 tests/inlineasm/thumb/asmerrors.py create mode 100644 tests/inlineasm/thumb/asmerrors.py.exp create mode 100644 tests/inlineasm/xtensa/asmargs.py create mode 100644 tests/inlineasm/xtensa/asmargs.py.exp create mode 100644 tests/inlineasm/xtensa/asmarith.py create mode 100644 tests/inlineasm/xtensa/asmarith.py.exp create mode 100644 tests/inlineasm/xtensa/asmbranch.py create mode 100644 tests/inlineasm/xtensa/asmbranch.py.exp create mode 100644 tests/inlineasm/xtensa/asmjump.py create mode 100644 tests/inlineasm/xtensa/asmjump.py.exp create mode 100644 tests/inlineasm/xtensa/asmloadstore.py create mode 100644 tests/inlineasm/xtensa/asmloadstore.py.exp create mode 100644 tests/inlineasm/xtensa/asmmisc.py create mode 100644 tests/inlineasm/xtensa/asmmisc.py.exp create mode 100644 tests/inlineasm/xtensa/asmshift.py create mode 100644 tests/inlineasm/xtensa/asmshift.py.exp create mode 100644 tests/internal_bench/class_create-0-empty.py create mode 100644 tests/internal_bench/class_create-1-slots.py create mode 100644 tests/internal_bench/class_create-1.1-slots5.py create mode 100644 tests/internal_bench/class_create-2-classattr.py create mode 100644 tests/internal_bench/class_create-2.1-classattr5.py create mode 100644 tests/internal_bench/class_create-2.3-classattr5objs.py create mode 100644 tests/internal_bench/class_create-3-instancemethod.py create mode 100644 tests/internal_bench/class_create-4-classmethod.py create mode 100644 tests/internal_bench/class_create-4.1-classmethod_implicit.py create mode 100644 tests/internal_bench/class_create-5-staticmethod.py create mode 100644 tests/internal_bench/class_create-6-getattribute.py create mode 100644 tests/internal_bench/class_create-6.1-getattr.py create mode 100644 tests/internal_bench/class_create-6.2-property.py create mode 100644 tests/internal_bench/class_create-6.3-descriptor.py create mode 100644 tests/internal_bench/class_create-7-inherit.py create mode 100644 tests/internal_bench/class_create-7.1-inherit_initsubclass.py create mode 100644 tests/internal_bench/class_create-8-metaclass_setname.py create mode 100644 tests/internal_bench/class_create-8.1-metaclass_setname5.py create mode 100644 tests/internal_bench/class_instance-0-object.py create mode 100644 tests/internal_bench/class_instance-0.1-object-gc.py create mode 100644 tests/internal_bench/class_instance-1-empty.py create mode 100644 tests/internal_bench/class_instance-1.1-classattr.py create mode 100644 tests/internal_bench/class_instance-1.2-func.py create mode 100644 tests/internal_bench/class_instance-1.3-empty-gc.py create mode 100644 tests/internal_bench/class_instance-2-init.py create mode 100644 tests/internal_bench/class_instance-2.1-init_super.py create mode 100644 tests/internal_bench/class_instance-2.2-new.py create mode 100644 tests/internal_bench/class_instance-3-del.py create mode 100644 tests/internal_bench/class_instance-3.1-del-gc.py create mode 100644 tests/internal_bench/class_instance-4-slots.py create mode 100644 tests/internal_bench/class_instance-4.1-slots5.py create mode 100644 tests/internal_bench/var-6.2-instance-speciallookup.py create mode 100644 tests/internal_bench/var-6.3-instance-property.py create mode 100644 tests/internal_bench/var-6.4-instance-descriptor.py create mode 100644 tests/internal_bench/var-6.5-instance-getattr.py create mode 100644 tests/internal_bench/var-6.6-instance-builtin_ordered.py create mode 100644 tests/internal_bench/var-9-getattr.py create mode 100644 tests/internal_bench/var-9.1-getattr_default.py create mode 100644 tests/internal_bench/var-9.2-getattr_default_special.py create mode 100644 tests/internal_bench/var-9.3-except_ok.py create mode 100644 tests/internal_bench/var-9.4-except_selfinduced.py create mode 100644 tests/internal_bench/var-9.5-except_error.py create mode 100644 tests/internal_bench/var-9.6-except_error_special.py create mode 100644 tests/micropython/const_float.py create mode 100644 tests/micropython/const_float.py.exp create mode 100644 tests/micropython/const_math.py create mode 100644 tests/micropython/const_math.py.exp create mode 100644 tests/micropython/emg_exc.py.native.exp create mode 100644 tests/micropython/heapalloc_slice.py create mode 100644 tests/micropython/heapalloc_traceback.py.native.exp create mode 100644 tests/micropython/ringio_big.py create mode 100644 tests/micropython/ringio_big.py.exp create mode 100644 tests/micropython/test_normalize_newlines.py create mode 100644 tests/micropython/test_normalize_newlines.py.exp create mode 100644 tests/micropython/viper_large_jump.py create mode 100644 tests/micropython/viper_large_jump.py.exp create mode 100644 tests/micropython/viper_ptr16_load_boundary.py create mode 100644 tests/micropython/viper_ptr16_load_boundary.py.exp create mode 100644 tests/micropython/viper_ptr16_store_boundary.py create mode 100644 tests/micropython/viper_ptr16_store_boundary.py.exp create mode 100644 tests/micropython/viper_ptr32_load_boundary.py create mode 100644 tests/micropython/viper_ptr32_load_boundary.py.exp create mode 100644 tests/micropython/viper_ptr32_store_boundary.py create mode 100644 tests/micropython/viper_ptr32_store_boundary.py.exp create mode 100644 tests/micropython/viper_ptr8_load_boundary.py create mode 100644 tests/micropython/viper_ptr8_load_boundary.py.exp create mode 100644 tests/micropython/viper_ptr8_store_boundary.py create mode 100644 tests/micropython/viper_ptr8_store_boundary.py.exp create mode 100644 tests/misc/print_exception.py.native.exp create mode 100644 tests/misc/sys_settrace_cov.py create mode 100644 tests/misc/sys_settrace_cov.py.exp create mode 100644 tests/multi_extmod/machine_i2c_target_irq.py create mode 100644 tests/multi_extmod/machine_i2c_target_irq.py.exp create mode 100644 tests/multi_extmod/machine_i2c_target_memory.py create mode 100644 tests/multi_extmod/machine_i2c_target_memory.py.exp create mode 100755 tests/serial_test.py create mode 100644 tests/stress/qstr_limit_str_modulo.py create mode 100644 tests/stress/qstr_limit_str_modulo.py.exp create mode 100644 tests/target_wiring/EK_RA6M2.py create mode 100644 tests/target_wiring/NUCLEO_WB55.py create mode 100644 tests/target_wiring/PYBx.py create mode 100644 tests/target_wiring/ZEPHYR_NUCLEO_WB55RG.py create mode 100644 tests/target_wiring/alif.py create mode 100644 tests/target_wiring/esp32.py create mode 100644 tests/target_wiring/mimxrt.py create mode 100644 tests/target_wiring/nrf.py create mode 100644 tests/target_wiring/rp2.py create mode 100644 tests/target_wiring/samd.py create mode 100644 tests/thread/thread_exc2.py.native.exp rename tests/thread/{thread_lock4.py => thread_lock4_intbig.py} (100%) diff --git a/.gitattributes b/.gitattributes index 38bba729fc1..d226cebf5d8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -27,4 +27,5 @@ # These should also not be modified by git. tests/basics/string_cr_conversion.py -text tests/basics/string_crlf_conversion.py -text +tests/micropython/test_normalize_newlines.py.exp -text # CIRCUITPY-CHANGE: remove non-CircuitPython tests diff --git a/LICENSE_MicroPython b/LICENSE_MicroPython index 469ae192739..1fad9b4134e 100644 --- a/LICENSE_MicroPython +++ b/LICENSE_MicroPython @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2013-2024 Damien P. George +Copyright (c) 2013-2025 Damien P. George Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/library/collections.rst b/docs/library/collections.rst index b006a97dcaf..c3ec763d20e 100644 --- a/docs/library/collections.rst +++ b/docs/library/collections.rst @@ -109,3 +109,19 @@ Classes a 2 w 5 b 3 + + .. method:: OrderedDict.popitem() + + Remove and return a (key, value) pair from the dictionary. + Pairs are returned in LIFO order. + + .. admonition:: Difference to CPython + :class: attention + + ``OrderedDict.popitem()`` does not support the ``last=False`` argument and + will always remove and return the last item if present. + + A workaround for this is to use ``pop()`` to remove the first item:: + + first_key = next(iter(d)) + d.pop(first_key) diff --git a/docs/library/platform.rst b/docs/library/platform.rst index c091477d84c..c19ef0f5df5 100644 --- a/docs/library/platform.rst +++ b/docs/library/platform.rst @@ -36,3 +36,11 @@ Functions Returns a tuple of strings *(lib, version)*, where *lib* is the name of the libc that MicroPython is linked to, and *version* the corresponding version of this libc. + +.. function:: processor() + + Returns a string with a detailed name of the processor, if one is available. + If no name for the processor is known, it will return an empty string + instead. + + This is currently available only on RISC-V targets (both 32 and 64 bits). diff --git a/docs/library/re.rst b/docs/library/re.rst index 19b15d2d2c2..b8aeefd90cf 100644 --- a/docs/library/re.rst +++ b/docs/library/re.rst @@ -154,8 +154,8 @@ Regex objects Compiled regular expression. Instances of this class are created using `re.compile()`. -.. method:: regex.match(string) - regex.search(string) +.. method:: regex.match(string, [pos, [endpos]]) + regex.search(string, [pos, [endpos]]) regex.sub(replace, string, count=0, flags=0, /) Similar to the module-level functions :meth:`match`, :meth:`search` @@ -163,6 +163,16 @@ Compiled regular expression. Instances of this class are created using Using methods is (much) more efficient if the same regex is applied to multiple strings. + The optional second parameter *pos* gives an index in the string where the + search is to start; it defaults to ``0``. This is not completely equivalent + to slicing the string; the ``'^'`` pattern character matches at the real + beginning of the string and at positions just after a newline, but not + necessarily at the index where the search is to start. + + The optional parameter *endpos* limits how far the string will be searched; + it will be as if the string is *endpos* characters long, so only the + characters from *pos* to ``endpos - 1`` will be searched for a match. + .. method:: regex.split(string, max_split=-1, /) Split a *string* using regex. If *max_split* is given, it specifies diff --git a/docs/library/sys.rst b/docs/library/sys.rst index 8def36a2b07..c9c687df359 100644 --- a/docs/library/sys.rst +++ b/docs/library/sys.rst @@ -12,17 +12,9 @@ Functions .. function:: exit(retval=0, /) Terminate current program with a given exit code. Underlyingly, this - function raise as `SystemExit` exception. If an argument is given, its + function raises a `SystemExit` exception. If an argument is given, its value given as an argument to `SystemExit`. -.. function:: print_exception(exc, file=sys.stdout, /) - - This function is deprecated and will be removed starting in - CircuitPython 10.x, `traceback.print_exception()` should be used instead. - - Print exception with a traceback to a file-like object *file* (or - `sys.stdout` by default). - .. admonition:: Difference to CPython :class: attention @@ -52,6 +44,8 @@ Constants * *version* - tuple (major, minor, micro), e.g. (1, 7, 0) * *_machine* - string describing the underlying machine * *_mpy* - supported mpy file-format version (optional attribute) + * *_build* - string that can help identify the configuration that + MicroPython was built with This object is the recommended way to distinguish CircuitPython from other Python implementations (note that it still may not exist in the very @@ -116,15 +110,15 @@ Constants .. data:: stderr - Standard error ``stream``. + Standard error `stream`. .. data:: stdin - Standard input ``stream``. + Standard input `stream`. .. data:: stdout - Standard output ``stream``. + Standard output `stream`. .. data:: version diff --git a/docs/reference/glossary.rst b/docs/reference/glossary.rst index 9e9330de4cc..391dc307d23 100644 --- a/docs/reference/glossary.rst +++ b/docs/reference/glossary.rst @@ -186,6 +186,13 @@ Glossary Most MicroPython boards make a REPL available over a UART, and this is typically accessible on a host PC via USB. + small integer + MicroPython optimises the internal representation of integers such that + "small" values do not take up space on the heap, and calculations with + them do not require heap allocation. On most 32-bit ports, this + corresponds to values in the interval ``-2**30 <= x < 2**30``, but this + should be considered an implementation detail and not relied upon. + stream Also known as a "file-like object". A Python object which provides sequential read-write access to the underlying data. A stream object diff --git a/extmod/cyw43_config_common.h b/extmod/cyw43_config_common.h new file mode 100644 index 00000000000..595af37d713 --- /dev/null +++ b/extmod/cyw43_config_common.h @@ -0,0 +1,126 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Damien P. George, Angus Gratton + * + * 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. + */ +#ifndef MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H +#define MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H + +// The board-level config will be included here, so it can set some CYW43 values. +#include "py/mpconfig.h" +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "extmod/modnetwork.h" +#include "lwip/apps/mdns.h" +#include "pendsv.h" + +// This file is included at the top of port-specific cyw43_configport.h files, +// and holds the MicroPython-specific but non-port-specific parts. +// +// It's included into both MicroPython sources and the lib/cyw43-driver sources. + +#define CYW43_IOCTL_TIMEOUT_US (1000000) +#define CYW43_NETUTILS (1) +#define CYW43_PRINTF(...) mp_printf(MP_PYTHON_PRINTER, __VA_ARGS__) + +#define CYW43_EPERM MP_EPERM // Operation not permitted +#define CYW43_EIO MP_EIO // I/O error +#define CYW43_EINVAL MP_EINVAL // Invalid argument +#define CYW43_ETIMEDOUT MP_ETIMEDOUT // Connection timed out + +#define CYW43_THREAD_ENTER MICROPY_PY_LWIP_ENTER +#define CYW43_THREAD_EXIT MICROPY_PY_LWIP_EXIT +#define CYW43_THREAD_LOCK_CHECK + +#define CYW43_HOST_NAME mod_network_hostname_data + +#define CYW43_ARRAY_SIZE(a) MP_ARRAY_SIZE(a) + +#define CYW43_HAL_PIN_MODE_INPUT MP_HAL_PIN_MODE_INPUT +#define CYW43_HAL_PIN_MODE_OUTPUT MP_HAL_PIN_MODE_OUTPUT +#define CYW43_HAL_PIN_PULL_NONE MP_HAL_PIN_PULL_NONE +#define CYW43_HAL_PIN_PULL_UP MP_HAL_PIN_PULL_UP +#define CYW43_HAL_PIN_PULL_DOWN MP_HAL_PIN_PULL_DOWN + +#define CYW43_HAL_MAC_WLAN0 MP_HAL_MAC_WLAN0 +#define CYW43_HAL_MAC_BDADDR MP_HAL_MAC_BDADDR + +#define cyw43_hal_ticks_us mp_hal_ticks_us +#define cyw43_hal_ticks_ms mp_hal_ticks_ms + +#define cyw43_hal_pin_obj_t mp_hal_pin_obj_t +#define cyw43_hal_pin_config mp_hal_pin_config +#define cyw43_hal_pin_read mp_hal_pin_read +#define cyw43_hal_pin_low mp_hal_pin_low +#define cyw43_hal_pin_high mp_hal_pin_high + +#define cyw43_hal_get_mac mp_hal_get_mac +#define cyw43_hal_get_mac_ascii mp_hal_get_mac_ascii +#define cyw43_hal_generate_laa_mac mp_hal_generate_laa_mac + +#define cyw43_schedule_internal_poll_dispatch(func) pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, func) + +// Note: this function is only called if CYW43_POST_POLL_HOOK is defined in cyw43_configport.h +void cyw43_post_poll_hook(void); + +#ifdef MICROPY_EVENT_POLL_HOOK +// Older style hook macros on some ports +#define CYW43_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK +#else +// Newer style hooks on other ports +#define CYW43_EVENT_POLL_HOOK mp_event_handle_nowait() +#endif + +static inline void cyw43_delay_us(uint32_t us) { + uint32_t start = mp_hal_ticks_us(); + while (mp_hal_ticks_us() - start < us) { + } +} + +static inline void cyw43_delay_ms(uint32_t ms) { + // PendSV may be disabled via CYW43_THREAD_ENTER, so this delay is a busy loop. + uint32_t us = ms * 1000; + uint32_t start = mp_hal_ticks_us(); + while (mp_hal_ticks_us() - start < us) { + CYW43_EVENT_POLL_HOOK; + } +} + +#if LWIP_MDNS_RESPONDER == 1 + +// Hook for any additional TCP/IP initialization than needs to be done. +// Called after the netif specified by `itf` has been set up. +#ifndef CYW43_CB_TCPIP_INIT_EXTRA +#define CYW43_CB_TCPIP_INIT_EXTRA(self, itf) mdns_resp_add_netif(&self->netif[itf], mod_network_hostname_data) +#endif + +// Hook for any additional TCP/IP deinitialization than needs to be done. +// Called before the netif specified by `itf` is removed. +#ifndef CYW43_CB_TCPIP_DEINIT_EXTRA +#define CYW43_CB_TCPIP_DEINIT_EXTRA(self, itf) mdns_resp_remove_netif(&self->netif[itf]) +#endif + +#endif + +#endif // MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H diff --git a/extmod/extmod.mk b/extmod/extmod.mk index daa6f267342..5b2772e4e2a 100644 --- a/extmod/extmod.mk +++ b/extmod/extmod.mk @@ -162,7 +162,7 @@ endif ifeq ($(MICROPY_VFS_LFS2),1) CFLAGS_EXTMOD += -DMICROPY_VFS_LFS2=1 -CFLAGS_THIRDPARTY += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT +CFLAGS_THIRDPARTY += -DLFS2_NO_MALLOC -DLFS2_NO_DEBUG -DLFS2_NO_WARN -DLFS2_NO_ERROR -DLFS2_NO_ASSERT -DLFS2_DEFINES=extmod/littlefs-include/lfs2_defines.h SRC_THIRDPARTY_C += $(addprefix $(LITTLEFS_DIR)/,\ lfs2.c \ lfs2_util.c \ @@ -461,7 +461,7 @@ ESP_HOSTED_SRC_C = $(addprefix $(ESP_HOSTED_DIR)/,\ ) ifeq ($(MICROPY_PY_BLUETOOTH),1) -ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci.c +ESP_HOSTED_SRC_C += $(ESP_HOSTED_DIR)/esp_hosted_bthci_uart.c endif # Include the protobuf-c support functions diff --git a/extmod/littlefs-include/lfs2_defines.h b/extmod/littlefs-include/lfs2_defines.h new file mode 100644 index 00000000000..4ae566f508a --- /dev/null +++ b/extmod/littlefs-include/lfs2_defines.h @@ -0,0 +1,12 @@ +#ifndef LFS2_DEFINES_H +#define LFS2_DEFINES_H + +#include "py/mpconfig.h" + +#if MICROPY_PY_DEFLATE +// We reuse the CRC32 implementation from uzlib to save a few bytes +#include "lib/uzlib/uzlib.h" +#define LFS2_CRC(crc, buffer, size) uzlib_crc32(buffer, size, crc) +#endif + +#endif \ No newline at end of file diff --git a/extmod/lwip-include/arch/cc.h b/extmod/lwip-include/arch/cc.h deleted file mode 100644 index 400dc6ec75d..00000000000 --- a/extmod/lwip-include/arch/cc.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H -#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H - -#include - -// Generate lwip's internal types from stdint - -typedef uint8_t u8_t; -typedef int8_t s8_t; -typedef uint16_t u16_t; -typedef int16_t s16_t; -typedef uint32_t u32_t; -typedef int32_t s32_t; - -typedef u32_t mem_ptr_t; - -#define U16_F "hu" -#define S16_F "hd" -#define X16_F "hx" -#define U32_F "u" -#define S32_F "d" -#define X32_F "x" - -#define X8_F "02x" -#define SZT_F "u" - -#define BYTE_ORDER LITTLE_ENDIAN - -#define LWIP_CHKSUM_ALGORITHM 2 - -#include -#define LWIP_PLATFORM_DIAG(x) -#define LWIP_PLATFORM_ASSERT(x) { assert(1); } - -//#define PACK_STRUCT_FIELD(x) x __attribute__((packed)) -#define PACK_STRUCT_FIELD(x) x -#define PACK_STRUCT_STRUCT __attribute__((packed)) -#define PACK_STRUCT_BEGIN -#define PACK_STRUCT_END - -#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_CC_H diff --git a/extmod/lwip-include/arch/perf.h b/extmod/lwip-include/arch/perf.h deleted file mode 100644 index d310fc339f1..00000000000 --- a/extmod/lwip-include/arch/perf.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H -#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H - -#define PERF_START /* null definition */ -#define PERF_STOP(x) /* null definition */ - -#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_ARCH_PERF_H diff --git a/extmod/lwip-include/lwipopts.h b/extmod/lwip-include/lwipopts.h deleted file mode 100644 index 584decfe85f..00000000000 --- a/extmod/lwip-include/lwipopts.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H -#define MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H - -#include -#include -#include - -// We're running without an OS for this port. We don't provide any services except light protection. -#define NO_SYS 1 - -#define SYS_LIGHTWEIGHT_PROT 1 -#include -typedef uint32_t sys_prot_t; - -#define TCP_LISTEN_BACKLOG 1 - -// We'll put these into a proper ifdef once somebody implements an ethernet driver -#define LWIP_ARP 0 -#define LWIP_ETHERNET 0 - -#define LWIP_DNS 1 - -#define LWIP_NETCONN 0 -#define LWIP_SOCKET 0 - -// CIRCUITPY-CHANGE: #if instead of #ifdef -#if MICROPY_PY_LWIP_SLIP -#define LWIP_HAVE_SLIPIF 1 -#endif - -// For now, we can simply define this as a macro for the timer code. But this function isn't -// universal and other ports will need to do something else. It may be necessary to move -// things like this into a port-provided header file. -#define sys_now mp_hal_ticks_ms - -#endif // MICROPY_INCLUDED_EXTMOD_LWIP_INCLUDE_LWIPOPTS_H diff --git a/extmod/lwip-include/lwipopts_common.h b/extmod/lwip-include/lwipopts_common.h index 3e423090949..8cb1acfe2ca 100644 --- a/extmod/lwip-include/lwipopts_common.h +++ b/extmod/lwip-include/lwipopts_common.h @@ -28,6 +28,9 @@ #include "py/mpconfig.h" +// This is needed to access `next_timeout` via `sys_timeouts_get_next_timeout()`. +#define LWIP_TESTMODE 1 + // This sys-arch protection is not needed. // Ports either protect lwIP code with flags, or run it at PendSV priority. #define SYS_ARCH_DECL_PROTECT(lev) do { } while (0) diff --git a/extmod/modjson.c b/extmod/modjson.c index 67da36f0ccf..77f4a336aa8 100644 --- a/extmod/modjson.c +++ b/extmod/modjson.c @@ -227,7 +227,8 @@ static mp_obj_t _mod_json_load(mp_obj_t stream_obj, bool return_first_json) { for (;;) { cont: if (S_END(s)) { - break; + // Input finished abruptly in the middle of a composite entity. + goto fail; } mp_obj_t next = MP_OBJ_NULL; bool enter = false; diff --git a/extmod/modplatform.c b/extmod/modplatform.c index c6d4d31b97e..e1f5476c3b3 100644 --- a/extmod/modplatform.c +++ b/extmod/modplatform.c @@ -61,11 +61,49 @@ static mp_obj_t platform_libc_ver(size_t n_args, const mp_obj_t *pos_args, mp_ma } static MP_DEFINE_CONST_FUN_OBJ_KW(platform_libc_ver_obj, 0, platform_libc_ver); +#ifdef __riscv +static mp_obj_t platform_processor(void) { + #if (__riscv_xlen <= 64) && !defined(__linux__) + uintptr_t misa_csr = 0; + + // Load the MISA CSR directly. + __asm volatile ( + "csrr %0, misa \n" + : "+r" (misa_csr) + : + : + ); + + char processor_buffer[31] = { // "RV32"/"RV64" + up to 26 chars. + #if (__riscv_xlen < 64) + "RV32" + #else + "RV64" + #endif + }; + mp_uint_t offset = 4; + for (mp_uint_t bit = 0; bit < 26; bit++) { + if (misa_csr & (1U << bit)) { + processor_buffer[offset++] = 'A' + bit; + } + } + + return mp_obj_new_str(processor_buffer, offset); + #else + return MP_OBJ_NEW_QSTR(MP_QSTR_); + #endif +} +static MP_DEFINE_CONST_FUN_OBJ_0(platform_processor_obj, platform_processor); +#endif + static const mp_rom_map_elem_t modplatform_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_platform) }, { MP_ROM_QSTR(MP_QSTR_platform), MP_ROM_PTR(&platform_platform_obj) }, { MP_ROM_QSTR(MP_QSTR_python_compiler), MP_ROM_PTR(&platform_python_compiler_obj) }, { MP_ROM_QSTR(MP_QSTR_libc_ver), MP_ROM_PTR(&platform_libc_ver_obj) }, + #ifdef __riscv + { MP_ROM_QSTR(MP_QSTR_processor), MP_ROM_PTR(&platform_processor_obj) }, + #endif }; static MP_DEFINE_CONST_DICT(modplatform_globals, modplatform_globals_table); diff --git a/extmod/modre.c b/extmod/modre.c index ba2927eb4a8..36fff1d1dc6 100644 --- a/extmod/modre.c +++ b/extmod/modre.c @@ -196,10 +196,11 @@ static void re_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t // Note: this function can't be named re_exec because it may clash with system headers, eg on FreeBSD static mp_obj_t re_exec_helper(bool is_anchored, uint n_args, const mp_obj_t *args) { - (void)n_args; mp_obj_re_t *self; + bool was_compiled = false; if (mp_obj_is_type(args[0], (mp_obj_type_t *)&re_type)) { self = MP_OBJ_TO_PTR(args[0]); + was_compiled = true; } else { self = MP_OBJ_TO_PTR(mod_re_compile(1, args)); } @@ -207,37 +208,28 @@ static mp_obj_t re_exec_helper(bool is_anchored, uint n_args, const mp_obj_t *ar size_t len; subj.begin_line = subj.begin = mp_obj_str_get_data(args[1], &len); subj.end = subj.begin + len; - // CIRCUITPY-CHANGE - #if MICROPY_PY_RE_MATCH_SPAN_START_END && !(defined(MICROPY_ENABLE_DYNRUNTIME) && MICROPY_ENABLE_DYNRUNTIME) - - if (n_args > 2) { - const mp_obj_type_t *self_type = mp_obj_get_type(args[1]); - mp_int_t str_len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(args[1])); - const byte *begin = (const byte *)subj.begin; - int pos = mp_obj_get_int(args[2]); - if (pos >= str_len) { - return mp_const_none; - } - if (pos < 0) { - pos = 0; + if (was_compiled && n_args > 2) { + // Arg #2 is starting-pos + mp_int_t startpos = mp_obj_get_int(args[2]); + if (startpos > (mp_int_t)len) { + startpos = len; + } else if (startpos < 0) { + startpos = 0; } - const byte *pos_ptr = str_index_to_ptr(self_type, begin, len, MP_OBJ_NEW_SMALL_INT(pos), true); - - const byte *endpos_ptr = (const byte *)subj.end; + subj.begin += startpos; if (n_args > 3) { - int endpos = mp_obj_get_int(args[3]); - if (endpos <= pos) { - return mp_const_none; + // Arg #3 is ending-pos + mp_int_t endpos = mp_obj_get_int(args[3]); + if (endpos > (mp_int_t)len) { + endpos = len; + } else if (endpos < startpos) { + endpos = startpos; } - // Will cap to length - endpos_ptr = str_index_to_ptr(self_type, begin, len, args[3], true); + subj.end = subj.begin_line + endpos; } - - subj.begin = (const char *)pos_ptr; - subj.end = (const char *)endpos_ptr; } - #endif + int caps_num = (self->re.sub + 1) * 2; mp_obj_match_t *match = m_new_obj_var(mp_obj_match_t, caps, char *, caps_num); // cast is a workaround for a bug in msvc: it treats const char** as a const pointer instead of a pointer to pointer to const char @@ -458,6 +450,9 @@ static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { const char *re_str = mp_obj_str_get_str(args[0]); int size = re1_5_sizecode(re_str); if (size == -1) { + #if MICROPY_ERROR_REPORTING >= MICROPY_ERROR_REPORTING_NORMAL + mp_raise_ValueError(MP_ERROR_TEXT("regex too complex")); + #endif goto error; } mp_obj_re_t *o = mp_obj_malloc_var(mp_obj_re_t, re.insts, char, size, (mp_obj_type_t *)&re_type); @@ -470,6 +465,7 @@ static mp_obj_t mod_re_compile(size_t n_args, const mp_obj_t *args) { int error = re1_5_compilecode(&o->re, re_str); if (error != 0) { error: + // CIRCUITPY-CHANGE: capitalized mp_raise_ValueError(MP_ERROR_TEXT("Error in regex")); } #if MICROPY_PY_RE_DEBUG diff --git a/extmod/modtime.c b/extmod/modtime.c index deb4bb4c9ac..ee898828a4a 100644 --- a/extmod/modtime.c +++ b/extmod/modtime.c @@ -53,26 +53,26 @@ // - weekday is 0-6 for Mon-Sun // - yearday is 1-366 static mp_obj_t time_localtime(size_t n_args, const mp_obj_t *args) { + timeutils_struct_time_t tm; if (n_args == 0 || args[0] == mp_const_none) { // Get current date and time. - return mp_time_localtime_get(); + mp_time_localtime_get(&tm); } else { // Convert given seconds to tuple. - mp_int_t seconds = mp_obj_get_int(args[0]); - timeutils_struct_time_t tm; + mp_timestamp_t seconds = timeutils_obj_get_timestamp(args[0]); timeutils_seconds_since_epoch_to_struct_time(seconds, &tm); - mp_obj_t tuple[8] = { - tuple[0] = mp_obj_new_int(tm.tm_year), - tuple[1] = mp_obj_new_int(tm.tm_mon), - tuple[2] = mp_obj_new_int(tm.tm_mday), - tuple[3] = mp_obj_new_int(tm.tm_hour), - tuple[4] = mp_obj_new_int(tm.tm_min), - tuple[5] = mp_obj_new_int(tm.tm_sec), - tuple[6] = mp_obj_new_int(tm.tm_wday), - tuple[7] = mp_obj_new_int(tm.tm_yday), - }; - return mp_obj_new_tuple(8, tuple); } + mp_obj_t tuple[8] = { + mp_obj_new_int(tm.tm_year), + mp_obj_new_int(tm.tm_mon), + mp_obj_new_int(tm.tm_mday), + mp_obj_new_int(tm.tm_hour), + mp_obj_new_int(tm.tm_min), + mp_obj_new_int(tm.tm_sec), + mp_obj_new_int(tm.tm_wday), + mp_obj_new_int(tm.tm_yday), + }; + return mp_obj_new_tuple(8, tuple); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_time_localtime_obj, 0, 1, time_localtime); @@ -90,7 +90,7 @@ static mp_obj_t time_mktime(mp_obj_t tuple) { mp_raise_TypeError(MP_ERROR_TEXT("mktime needs a tuple of length 8 or 9")); } - return mp_obj_new_int_from_uint(timeutils_mktime(mp_obj_get_int(elem[0]), + return timeutils_obj_from_timestamp(timeutils_mktime(mp_obj_get_int(elem[0]), 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]))); } diff --git a/extmod/vfs.c b/extmod/vfs.c index 0cf93c3966c..c4156990bcc 100644 --- a/extmod/vfs.c +++ b/extmod/vfs.c @@ -101,7 +101,7 @@ mp_vfs_mount_t *mp_vfs_lookup_path(const char *path, const char **path_out) { return MP_STATE_VM(vfs_cur); } -// Version of mp_vfs_lookup_path that takes and returns uPy string objects. +// Version of mp_vfs_lookup_path that takes and returns MicroPython string objects. static mp_vfs_mount_t *lookup_path(mp_obj_t path_in, mp_obj_t *path_out) { const char *path = mp_obj_str_get_str(path_in); const char *p_out; diff --git a/extmod/vfs_blockdev.c b/extmod/vfs_blockdev.c index 0cd3cc6f0c6..74d1262364e 100644 --- a/extmod/vfs_blockdev.c +++ b/extmod/vfs_blockdev.c @@ -108,7 +108,7 @@ static int mp_vfs_blockdev_call_rw(mp_obj_t *args, size_t block_num, size_t bloc // and negative integer on errors. Check for positive integer // results as some callers (i.e. littlefs) will produce corrupt // results from these. - int i = MP_OBJ_SMALL_INT_VALUE(ret); + int i = mp_obj_get_int(ret); return i > 0 ? (-MP_EINVAL) : i; } } diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index 6267452cd32..cb5fb649a1e 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -58,7 +58,7 @@ // CIRCUITPY-CHANGE // Factoring this common call saves about 90 bytes. -static NORETURN void mp_raise_OSError_fresult(FRESULT res) { +static MP_NORETURN void mp_raise_OSError_fresult(FRESULT res) { mp_raise_OSError(fresult_to_errno_table[res]); } @@ -455,77 +455,6 @@ static mp_obj_t vfs_fat_umount(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount); -// CIRCUITPY-CHANGE -static mp_obj_t vfs_fat_utime(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t times_in) { - mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); - const char *path = mp_obj_str_get_str(path_in); - if (!mp_obj_is_tuple_compatible(times_in)) { - mp_raise_type_arg(&mp_type_TypeError, times_in); - } - - mp_obj_t *otimes; - mp_obj_get_array_fixed_n(times_in, 2, &otimes); - - // Validate that both elements of the tuple are int and discard the second one - int time[2]; - time[0] = mp_obj_get_int(otimes[0]); - time[1] = mp_obj_get_int(otimes[1]); - timeutils_struct_time_t tm; - timeutils_seconds_since_epoch_to_struct_time(time[0], &tm); - - FILINFO fno; - fno.fdate = (WORD)(((tm.tm_year - 1980) * 512U) | tm.tm_mon * 32U | tm.tm_mday); - fno.ftime = (WORD)(tm.tm_hour * 2048U | tm.tm_min * 32U | tm.tm_sec / 2U); - FRESULT res = f_utime(&self->fatfs, path, &fno); - if (res != FR_OK) { - mp_raise_OSError_fresult(res); - } - - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_utime_obj, vfs_fat_utime); - -static mp_obj_t vfs_fat_getreadonly(mp_obj_t self_in) { - fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_bool(!filesystem_is_writable_by_python(self)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getreadonly_obj, vfs_fat_getreadonly); - -static MP_PROPERTY_GETTER(fat_vfs_readonly_obj, - (mp_obj_t)&fat_vfs_getreadonly_obj); - -#if MICROPY_FATFS_USE_LABEL -static mp_obj_t vfs_fat_getlabel(mp_obj_t self_in) { - fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); - char working_buf[12]; - FRESULT res = f_getlabel(&self->fatfs, working_buf, NULL); - if (res != FR_OK) { - mp_raise_OSError_fresult(res); - } - return mp_obj_new_str(working_buf, strlen(working_buf)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getlabel_obj, vfs_fat_getlabel); - -static mp_obj_t vfs_fat_setlabel(mp_obj_t self_in, mp_obj_t label_in) { - fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); - verify_fs_writable(self); - const char *label_str = mp_obj_str_get_str(label_in); - FRESULT res = f_setlabel(&self->fatfs, label_str); - if (res != FR_OK) { - if (res == FR_WRITE_PROTECTED) { - mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Read-only filesystem")); - } - mp_raise_OSError_fresult(res); - } - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_setlabel_obj, vfs_fat_setlabel); - -static MP_PROPERTY_GETSET(fat_vfs_label_obj, - (mp_obj_t)&fat_vfs_getlabel_obj, - (mp_obj_t)&fat_vfs_setlabel_obj); -#endif - static const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { // CIRCUITPY-CHANGE: correct name #if FF_FS_REENTRANT diff --git a/extmod/vfs_lfsx.c b/extmod/vfs_lfsx.c index 4b10ca3aa59..bbdd21cfb91 100644 --- a/extmod/vfs_lfsx.c +++ b/extmod/vfs_lfsx.c @@ -104,6 +104,12 @@ static void MP_VFS_LFSx(init_config)(MP_OBJ_VFS_LFSx * self, mp_obj_t bdev, size config->read_buffer = m_new(uint8_t, config->cache_size); config->prog_buffer = m_new(uint8_t, config->cache_size); config->lookahead_buffer = m_new(uint8_t, config->lookahead_size); + #ifdef LFS2_MULTIVERSION + // This can be set to override the on-disk lfs version. + // eg. for compat with lfs2 < v2.6 add the following to make: + // CFLAGS += '-DLFS2_MULTIVERSION=0x00020000' + config->disk_version = LFS2_MULTIVERSION; + #endif #endif } @@ -300,7 +306,7 @@ static mp_obj_t MP_VFS_LFSx(chdir)(mp_obj_t self_in, mp_obj_t path_in) { struct LFSx_API (info) info; int ret = LFSx_API(stat)(&self->lfs, path, &info); if (ret < 0 || info.type != LFSx_MACRO(_TYPE_DIR)) { - mp_raise_OSError(-MP_ENOENT); + mp_raise_OSError(MP_ENOENT); } } @@ -378,7 +384,7 @@ static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) { mp_raise_OSError(-ret); } - mp_uint_t mtime = 0; + mp_timestamp_t mtime = 0; #if LFS_BUILD_VERSION == 2 uint8_t mtime_buf[8]; lfs2_ssize_t sz = lfs2_getattr(&self->lfs, path, LFS_ATTR_MTIME, &mtime_buf, sizeof(mtime_buf)); @@ -400,9 +406,9 @@ static mp_obj_t MP_VFS_LFSx(stat)(mp_obj_t self_in, mp_obj_t path_in) { t->items[4] = MP_OBJ_NEW_SMALL_INT(0); // st_uid t->items[5] = MP_OBJ_NEW_SMALL_INT(0); // st_gid t->items[6] = mp_obj_new_int_from_uint(info.size); // st_size - t->items[7] = mp_obj_new_int_from_uint(mtime); // st_atime - t->items[8] = mp_obj_new_int_from_uint(mtime); // st_mtime - t->items[9] = mp_obj_new_int_from_uint(mtime); // st_ctime + t->items[7] = timeutils_obj_from_timestamp(mtime); // st_atime + t->items[8] = timeutils_obj_from_timestamp(mtime); // st_mtime + t->items[9] = timeutils_obj_from_timestamp(mtime); // st_ctime return MP_OBJ_FROM_PTR(t); } diff --git a/extmod/vfs_lfsx_file.c b/extmod/vfs_lfsx_file.c index ab5cce50088..56daa53e068 100644 --- a/extmod/vfs_lfsx_file.c +++ b/extmod/vfs_lfsx_file.c @@ -90,9 +90,9 @@ mp_obj_t MP_VFS_LFSx(file_open)(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mod } #if LFS_BUILD_VERSION == 1 - MP_OBJ_VFS_LFSx_FILE *o = mp_obj_malloc_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, uint8_t, self->lfs.cfg->prog_size, type); + MP_OBJ_VFS_LFSx_FILE *o = mp_obj_malloc_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, file_buffer, uint8_t, self->lfs.cfg->prog_size, type); #else - MP_OBJ_VFS_LFSx_FILE *o = mp_obj_malloc_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, uint8_t, self->lfs.cfg->cache_size, type); + MP_OBJ_VFS_LFSx_FILE *o = mp_obj_malloc_var_with_finaliser(MP_OBJ_VFS_LFSx_FILE, file_buffer, uint8_t, self->lfs.cfg->cache_size, type); #endif o->vfs = self; #if !MICROPY_GC_CONSERVATIVE_CLEAR diff --git a/extmod/vfs_posix.c b/extmod/vfs_posix.c index bd9a6d84062..27f833e802f 100644 --- a/extmod/vfs_posix.c +++ b/extmod/vfs_posix.c @@ -137,7 +137,7 @@ static mp_obj_t vfs_posix_make_new(const mp_obj_type_t *type, size_t n_args, siz vstr_add_char(&vfs->root, '/'); } vfs->root_len = vfs->root.len; - vfs->readonly = false; + vfs->readonly = !MICROPY_VFS_POSIX_WRITABLE; return MP_OBJ_FROM_PTR(vfs); } @@ -160,10 +160,21 @@ static mp_obj_t vfs_posix_umount(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(vfs_posix_umount_obj, vfs_posix_umount); +static inline bool vfs_posix_is_readonly(mp_obj_vfs_posix_t *self) { + return !MICROPY_VFS_POSIX_WRITABLE || self->readonly; +} + +static void vfs_posix_require_writable(mp_obj_t self_in) { + mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); + if (vfs_posix_is_readonly(self)) { + mp_raise_OSError(MP_EROFS); + } +} + static mp_obj_t vfs_posix_open(mp_obj_t self_in, mp_obj_t path_in, mp_obj_t mode_in) { mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); const char *mode = mp_obj_str_get_str(mode_in); - if (self->readonly + if (vfs_posix_is_readonly(self) && (strchr(mode, 'w') != NULL || strchr(mode, 'a') != NULL || strchr(mode, '+') != NULL)) { mp_raise_OSError(MP_EROFS); } @@ -303,6 +314,7 @@ typedef struct _mp_obj_listdir_t { } mp_obj_listdir_t; static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { + vfs_posix_require_writable(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); const char *path = vfs_posix_get_path_str(self, path_in); MP_THREAD_GIL_EXIT(); @@ -320,11 +332,13 @@ static mp_obj_t vfs_posix_mkdir(mp_obj_t self_in, mp_obj_t path_in) { static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_mkdir_obj, vfs_posix_mkdir); static mp_obj_t vfs_posix_remove(mp_obj_t self_in, mp_obj_t path_in) { + vfs_posix_require_writable(self_in); return vfs_posix_fun1_helper(self_in, path_in, unlink); } static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_remove_obj, vfs_posix_remove); static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_t new_path_in) { + vfs_posix_require_writable(self_in); mp_obj_vfs_posix_t *self = MP_OBJ_TO_PTR(self_in); const char *old_path = vfs_posix_get_path_str(self, old_path_in); const char *new_path = vfs_posix_get_path_str(self, new_path_in); @@ -339,6 +353,7 @@ static mp_obj_t vfs_posix_rename(mp_obj_t self_in, mp_obj_t old_path_in, mp_obj_ static MP_DEFINE_CONST_FUN_OBJ_3(vfs_posix_rename_obj, vfs_posix_rename); static mp_obj_t vfs_posix_rmdir(mp_obj_t self_in, mp_obj_t path_in) { + vfs_posix_require_writable(self_in); return vfs_posix_fun1_helper(self_in, path_in, rmdir); } static MP_DEFINE_CONST_FUN_OBJ_2(vfs_posix_rmdir_obj, vfs_posix_rmdir); diff --git a/extmod/vfs_reader.c b/extmod/vfs_reader.c index de5c4e03d3c..6c36770295b 100644 --- a/extmod/vfs_reader.c +++ b/extmod/vfs_reader.c @@ -83,7 +83,7 @@ void mp_reader_new_file(mp_reader_t *reader, qstr filename) { }; mp_obj_t file = mp_vfs_open(MP_ARRAY_SIZE(args), &args[0], (mp_map_t *)&mp_const_empty_map); - const mp_stream_p_t *stream_p = mp_get_stream(file); + const mp_stream_p_t *stream_p = mp_get_stream_raise(file, MP_STREAM_OP_READ); int errcode = 0; #if MICROPY_VFS_ROM diff --git a/lib/berkeley-db-1.xx b/lib/berkeley-db-1.xx index 85373b548f1..0f3bb6947c2 160000 --- a/lib/berkeley-db-1.xx +++ b/lib/berkeley-db-1.xx @@ -1 +1 @@ -Subproject commit 85373b548f1fb0119a463582570b44189dfb09ae +Subproject commit 0f3bb6947c2f57233916dccd7bb425d7bf86e5a6 diff --git a/lib/libm_dbl/libm.h b/lib/libm_dbl/libm.h index cbae6916625..fa49ad1cddd 100644 --- a/lib/libm_dbl/libm.h +++ b/lib/libm_dbl/libm.h @@ -89,7 +89,9 @@ do { \ (d) = __u.f; \ } while (0) +#if !defined(DBL_EPSILON) #define DBL_EPSILON 2.22044604925031308085e-16 +#endif int __rem_pio2(double, double*); int __rem_pio2_large(double*, double*, int, int, int); diff --git a/lib/libm_dbl/rint.c b/lib/libm_dbl/rint.c index fbba390e7d7..b85dec8f246 100644 --- a/lib/libm_dbl/rint.c +++ b/lib/libm_dbl/rint.c @@ -2,7 +2,7 @@ #include #include -#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 +#if FLT_EVAL_METHOD==0 || FLT_EVAL_METHOD==1 || FLT_EVAL_METHOD==16 #define EPS DBL_EPSILON #elif FLT_EVAL_METHOD==2 #define EPS LDBL_EPSILON diff --git a/lib/littlefs/lfs2.c b/lib/littlefs/lfs2.c index 613213669c8..aec2ddab9b6 100644 --- a/lib/littlefs/lfs2.c +++ b/lib/littlefs/lfs2.c @@ -93,6 +93,7 @@ static int lfs2_bd_read(lfs2_t *lfs2, // bypass cache? diff = lfs2_aligndown(diff, lfs2->cfg->read_size); int err = lfs2->cfg->read(lfs2->cfg, block, off, data, diff); + LFS2_ASSERT(err <= 0); if (err) { return err; } @@ -282,6 +283,21 @@ static int lfs2_bd_erase(lfs2_t *lfs2, lfs2_block_t block) { /// Small type-level utilities /// + +// some operations on paths +static inline lfs2_size_t lfs2_path_namelen(const char *path) { + return strcspn(path, "/"); +} + +static inline bool lfs2_path_islast(const char *path) { + lfs2_size_t namelen = lfs2_path_namelen(path); + return path[namelen + strspn(path + namelen, "/")] == '\0'; +} + +static inline bool lfs2_path_isdir(const char *path) { + return path[lfs2_path_namelen(path)] != '\0'; +} + // operations on block pairs static inline void lfs2_pair_swap(lfs2_block_t pair[2]) { lfs2_block_t t = pair[0]; @@ -389,18 +405,15 @@ struct lfs2_diskoff { // operations on global state static inline void lfs2_gstate_xor(lfs2_gstate_t *a, const lfs2_gstate_t *b) { - for (int i = 0; i < 3; i++) { - ((uint32_t*)a)[i] ^= ((const uint32_t*)b)[i]; - } + a->tag ^= b->tag; + a->pair[0] ^= b->pair[0]; + a->pair[1] ^= b->pair[1]; } static inline bool lfs2_gstate_iszero(const lfs2_gstate_t *a) { - for (int i = 0; i < 3; i++) { - if (((uint32_t*)a)[i] != 0) { - return false; - } - } - return true; + return a->tag == 0 + && a->pair[0] == 0 + && a->pair[1] == 0; } #ifndef LFS2_READONLY @@ -550,9 +563,9 @@ static int lfs2_dir_compact(lfs2_t *lfs2, lfs2_mdir_t *source, uint16_t begin, uint16_t end); static lfs2_ssize_t lfs2_file_flushedwrite(lfs2_t *lfs2, lfs2_file_t *file, const void *buffer, lfs2_size_t size); -static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_write_(lfs2_t *lfs2, lfs2_file_t *file, const void *buffer, lfs2_size_t size); -static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file); +static int lfs2_file_sync_(lfs2_t *lfs2, lfs2_file_t *file); static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file); static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file); @@ -574,65 +587,72 @@ static int lfs21_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); #endif -static int lfs2_dir_rawrewind(lfs2_t *lfs2, lfs2_dir_t *dir); +static int lfs2_dir_rewind_(lfs2_t *lfs2, lfs2_dir_t *dir); static lfs2_ssize_t lfs2_file_flushedread(lfs2_t *lfs2, lfs2_file_t *file, void *buffer, lfs2_size_t size); -static lfs2_ssize_t lfs2_file_rawread(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_read_(lfs2_t *lfs2, lfs2_file_t *file, void *buffer, lfs2_size_t size); -static int lfs2_file_rawclose(lfs2_t *lfs2, lfs2_file_t *file); -static lfs2_soff_t lfs2_file_rawsize(lfs2_t *lfs2, lfs2_file_t *file); +static int lfs2_file_close_(lfs2_t *lfs2, lfs2_file_t *file); +static lfs2_soff_t lfs2_file_size_(lfs2_t *lfs2, lfs2_file_t *file); -static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2); -static int lfs2_fs_rawtraverse(lfs2_t *lfs2, +static lfs2_ssize_t lfs2_fs_size_(lfs2_t *lfs2); +static int lfs2_fs_traverse_(lfs2_t *lfs2, int (*cb)(void *data, lfs2_block_t block), void *data, bool includeorphans); static int lfs2_deinit(lfs2_t *lfs2); -static int lfs2_rawunmount(lfs2_t *lfs2); +static int lfs2_unmount_(lfs2_t *lfs2); /// Block allocator /// + +// allocations should call this when all allocated blocks are committed to +// the filesystem +// +// after a checkpoint, the block allocator may realloc any untracked blocks +static void lfs2_alloc_ckpoint(lfs2_t *lfs2) { + lfs2->lookahead.ckpoint = lfs2->block_count; +} + +// drop the lookahead buffer, this is done during mounting and failed +// traversals in order to avoid invalid lookahead state +static void lfs2_alloc_drop(lfs2_t *lfs2) { + lfs2->lookahead.size = 0; + lfs2->lookahead.next = 0; + lfs2_alloc_ckpoint(lfs2); +} + #ifndef LFS2_READONLY static int lfs2_alloc_lookahead(void *p, lfs2_block_t block) { lfs2_t *lfs2 = (lfs2_t*)p; - lfs2_block_t off = ((block - lfs2->free.off) + lfs2_block_t off = ((block - lfs2->lookahead.start) + lfs2->block_count) % lfs2->block_count; - if (off < lfs2->free.size) { - lfs2->free.buffer[off / 32] |= 1U << (off % 32); + if (off < lfs2->lookahead.size) { + lfs2->lookahead.buffer[off / 8] |= 1U << (off % 8); } return 0; } #endif -// indicate allocated blocks have been committed into the filesystem, this -// is to prevent blocks from being garbage collected in the middle of a -// commit operation -static void lfs2_alloc_ack(lfs2_t *lfs2) { - lfs2->free.ack = lfs2->block_count; -} - -// drop the lookahead buffer, this is done during mounting and failed -// traversals in order to avoid invalid lookahead state -static void lfs2_alloc_drop(lfs2_t *lfs2) { - lfs2->free.size = 0; - lfs2->free.i = 0; - lfs2_alloc_ack(lfs2); -} - #ifndef LFS2_READONLY -static int lfs2_fs_rawgc(lfs2_t *lfs2) { - // Move free offset at the first unused block (lfs2->free.i) - // lfs2->free.i is equal lfs2->free.size when all blocks are used - lfs2->free.off = (lfs2->free.off + lfs2->free.i) % lfs2->block_count; - lfs2->free.size = lfs2_min(8*lfs2->cfg->lookahead_size, lfs2->free.ack); - lfs2->free.i = 0; +static int lfs2_alloc_scan(lfs2_t *lfs2) { + // move lookahead buffer to the first unused block + // + // note we limit the lookahead buffer to at most the amount of blocks + // checkpointed, this prevents the math in lfs2_alloc from underflowing + lfs2->lookahead.start = (lfs2->lookahead.start + lfs2->lookahead.next) + % lfs2->block_count; + lfs2->lookahead.next = 0; + lfs2->lookahead.size = lfs2_min( + 8*lfs2->cfg->lookahead_size, + lfs2->lookahead.ckpoint); // find mask of free blocks from tree - memset(lfs2->free.buffer, 0, lfs2->cfg->lookahead_size); - int err = lfs2_fs_rawtraverse(lfs2, lfs2_alloc_lookahead, lfs2, true); + memset(lfs2->lookahead.buffer, 0, lfs2->cfg->lookahead_size); + int err = lfs2_fs_traverse_(lfs2, lfs2_alloc_lookahead, lfs2, true); if (err) { lfs2_alloc_drop(lfs2); return err; @@ -645,36 +665,49 @@ static int lfs2_fs_rawgc(lfs2_t *lfs2) { #ifndef LFS2_READONLY static int lfs2_alloc(lfs2_t *lfs2, lfs2_block_t *block) { while (true) { - while (lfs2->free.i != lfs2->free.size) { - lfs2_block_t off = lfs2->free.i; - lfs2->free.i += 1; - lfs2->free.ack -= 1; - - if (!(lfs2->free.buffer[off / 32] & (1U << (off % 32)))) { + // scan our lookahead buffer for free blocks + while (lfs2->lookahead.next < lfs2->lookahead.size) { + if (!(lfs2->lookahead.buffer[lfs2->lookahead.next / 8] + & (1U << (lfs2->lookahead.next % 8)))) { // found a free block - *block = (lfs2->free.off + off) % lfs2->block_count; - - // eagerly find next off so an alloc ack can - // discredit old lookahead blocks - while (lfs2->free.i != lfs2->free.size && - (lfs2->free.buffer[lfs2->free.i / 32] - & (1U << (lfs2->free.i % 32)))) { - lfs2->free.i += 1; - lfs2->free.ack -= 1; + *block = (lfs2->lookahead.start + lfs2->lookahead.next) + % lfs2->block_count; + + // eagerly find next free block to maximize how many blocks + // lfs2_alloc_ckpoint makes available for scanning + while (true) { + lfs2->lookahead.next += 1; + lfs2->lookahead.ckpoint -= 1; + + if (lfs2->lookahead.next >= lfs2->lookahead.size + || !(lfs2->lookahead.buffer[lfs2->lookahead.next / 8] + & (1U << (lfs2->lookahead.next % 8)))) { + return 0; + } } - - return 0; } + + lfs2->lookahead.next += 1; + lfs2->lookahead.ckpoint -= 1; } - // check if we have looked at all blocks since last ack - if (lfs2->free.ack == 0) { - LFS2_ERROR("No more free space %"PRIu32, - lfs2->free.i + lfs2->free.off); + // In order to keep our block allocator from spinning forever when our + // filesystem is full, we mark points where there are no in-flight + // allocations with a checkpoint before starting a set of allocations. + // + // If we've looked at all blocks since the last checkpoint, we report + // the filesystem as out of storage. + // + if (lfs2->lookahead.ckpoint <= 0) { + LFS2_ERROR("No more free space 0x%"PRIx32, + (lfs2->lookahead.start + lfs2->lookahead.next) + % lfs2->block_count); return LFS2_ERR_NOSPC; } - int err = lfs2_fs_rawgc(lfs2); + // No blocks in our lookahead buffer, we need to scan the filesystem for + // unused blocks in the next lookahead window. + int err = lfs2_alloc_scan(lfs2); if(err) { return err; } @@ -690,11 +723,14 @@ static lfs2_stag_t lfs2_dir_getslice(lfs2_t *lfs2, const lfs2_mdir_t *dir, lfs2_tag_t ntag = dir->etag; lfs2_stag_t gdiff = 0; + // synthetic moves if (lfs2_gstate_hasmovehere(&lfs2->gdisk, dir->pair) && - lfs2_tag_id(gmask) != 0 && - lfs2_tag_id(lfs2->gdisk.tag) <= lfs2_tag_id(gtag)) { - // synthetic moves - gdiff -= LFS2_MKTAG(0, 1, 0); + lfs2_tag_id(gmask) != 0) { + if (lfs2_tag_id(lfs2->gdisk.tag) == lfs2_tag_id(gtag)) { + return LFS2_ERR_NOENT; + } else if (lfs2_tag_id(lfs2->gdisk.tag) < lfs2_tag_id(gtag)) { + gdiff -= LFS2_MKTAG(0, 1, 0); + } } // iterate over dir block backwards (for faster lookups) @@ -704,6 +740,7 @@ static lfs2_stag_t lfs2_dir_getslice(lfs2_t *lfs2, const lfs2_mdir_t *dir, int err = lfs2_bd_read(lfs2, NULL, &lfs2->rcache, sizeof(ntag), dir->pair[0], off, &ntag, sizeof(ntag)); + LFS2_ASSERT(err <= 0); if (err) { return err; } @@ -732,6 +769,7 @@ static lfs2_stag_t lfs2_dir_getslice(lfs2_t *lfs2, const lfs2_mdir_t *dir, err = lfs2_bd_read(lfs2, NULL, &lfs2->rcache, diff, dir->pair[0], off+sizeof(tag)+goff, gbuffer, diff); + LFS2_ASSERT(err <= 0); if (err) { return err; } @@ -793,9 +831,6 @@ static int lfs2_dir_getread(lfs2_t *lfs2, const lfs2_mdir_t *dir, size -= diff; continue; } - - // rcache takes priority - diff = lfs2_min(diff, rcache->off-off); } // load to cache, first condition can no longer fail @@ -1247,6 +1282,7 @@ static lfs2_stag_t lfs2_dir_fetchmatch(lfs2_t *lfs2, if (err == LFS2_ERR_CORRUPT) { break; } + return err; } lfs2_fcrc_fromle32(&fcrc); @@ -1438,32 +1474,46 @@ static int lfs2_dir_find_match(void *data, return LFS2_CMP_EQ; } +// lfs2_dir_find tries to set path and id even if file is not found +// +// returns: +// - 0 if file is found +// - LFS2_ERR_NOENT if file or parent is not found +// - LFS2_ERR_NOTDIR if parent is not a dir static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, const char **path, uint16_t *id) { // we reduce path to a single name if we can find it const char *name = *path; - if (id) { - *id = 0x3ff; - } // default to root dir lfs2_stag_t tag = LFS2_MKTAG(LFS2_TYPE_DIR, 0x3ff, 0); dir->tail[0] = lfs2->root[0]; dir->tail[1] = lfs2->root[1]; + // empty paths are not allowed + if (*name == '\0') { + return LFS2_ERR_INVAL; + } + while (true) { nextname: - // skip slashes - name += strspn(name, "/"); + // skip slashes if we're a directory + if (lfs2_tag_type3(tag) == LFS2_TYPE_DIR) { + name += strspn(name, "/"); + } lfs2_size_t namelen = strcspn(name, "/"); - // skip '.' and root '..' - if ((namelen == 1 && memcmp(name, ".", 1) == 0) || - (namelen == 2 && memcmp(name, "..", 2) == 0)) { + // skip '.' + if (namelen == 1 && memcmp(name, ".", 1) == 0) { name += namelen; goto nextname; } + // error on unmatched '..', trying to go above root? + if (namelen == 2 && memcmp(name, "..", 2) == 0) { + return LFS2_ERR_INVAL; + } + // skip if matched by '..' in name const char *suffix = name + namelen; lfs2_size_t sufflen; @@ -1475,7 +1525,9 @@ static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, break; } - if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { + if (sufflen == 1 && memcmp(suffix, ".", 1) == 0) { + // noop + } else if (sufflen == 2 && memcmp(suffix, "..", 2) == 0) { depth -= 1; if (depth == 0) { name = suffix + sufflen; @@ -1489,14 +1541,14 @@ static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, } // found path - if (name[0] == '\0') { + if (*name == '\0') { return tag; } // update what we've found so far *path = name; - // only continue if we hit a directory + // only continue if we're a directory if (lfs2_tag_type3(tag) != LFS2_TYPE_DIR) { return LFS2_ERR_NOTDIR; } @@ -1516,8 +1568,7 @@ static lfs2_stag_t lfs2_dir_find(lfs2_t *lfs2, lfs2_mdir_t *dir, tag = lfs2_dir_fetchmatch(lfs2, dir, dir->tail, LFS2_MKTAG(0x780, 0, 0), LFS2_MKTAG(LFS2_TYPE_NAME, 0, namelen), - // are we last name? - (strchr(name, '/') == NULL) ? id : NULL, + id, lfs2_dir_find_match, &(struct lfs2_dir_find_match){ lfs2, name, namelen}); if (tag < 0) { @@ -2105,13 +2156,14 @@ static int lfs2_dir_splittingcompact(lfs2_t *lfs2, lfs2_mdir_t *dir, // And we cap at half a block to avoid degenerate cases with // nearly-full metadata blocks. // + lfs2_size_t metadata_max = (lfs2->cfg->metadata_max) + ? lfs2->cfg->metadata_max + : lfs2->cfg->block_size; if (end - split < 0xff && size <= lfs2_min( - lfs2->cfg->block_size - 40, + metadata_max - 40, lfs2_alignup( - (lfs2->cfg->metadata_max - ? lfs2->cfg->metadata_max - : lfs2->cfg->block_size)/2, + metadata_max/2, lfs2->cfg->prog_size))) { break; } @@ -2146,14 +2198,16 @@ static int lfs2_dir_splittingcompact(lfs2_t *lfs2, lfs2_mdir_t *dir, && lfs2_pair_cmp(dir->pair, (const lfs2_block_t[2]){0, 1}) == 0) { // oh no! we're writing too much to the superblock, // should we expand? - lfs2_ssize_t size = lfs2_fs_rawsize(lfs2); + lfs2_ssize_t size = lfs2_fs_size_(lfs2); if (size < 0) { return size; } - // do we have extra space? littlefs can't reclaim this space - // by itself, so expand cautiously - if ((lfs2_size_t)size < lfs2->block_count/2) { + // littlefs cannot reclaim expanded superblocks, so expand cautiously + // + // if our filesystem is more than ~88% full, don't expand, this is + // somewhat arbitrary + if (lfs2->block_count - size > lfs2->block_count/8) { LFS2_DEBUG("Expanding superblock at rev %"PRIu32, dir->rev); int err = lfs2_dir_split(lfs2, dir, attrs, attrcount, source, begin, end); @@ -2166,7 +2220,8 @@ static int lfs2_dir_splittingcompact(lfs2_t *lfs2, lfs2_mdir_t *dir, // we can do, we'll error later if we've become frozen LFS2_WARN("Unable to expand superblock"); } else { - end = begin; + // duplicate the superblock entry into the new superblock + end = 1; } } } @@ -2213,7 +2268,7 @@ static int lfs2_dir_relocatingcommit(lfs2_t *lfs2, lfs2_mdir_t *dir, } } - if (dir->erased) { + if (dir->erased && dir->count < 0xff) { // try to commit struct lfs2_commit commit = { .block = dir->pair[0], @@ -2312,7 +2367,8 @@ fixmlist:; if (d->m.pair != pair) { for (int i = 0; i < attrcount; i++) { if (lfs2_tag_type3(attrs[i].tag) == LFS2_TYPE_DELETE && - d->id == lfs2_tag_id(attrs[i].tag)) { + d->id == lfs2_tag_id(attrs[i].tag) && + d->type != LFS2_TYPE_DIR) { d->m.pair[0] = LFS2_BLOCK_NULL; d->m.pair[1] = LFS2_BLOCK_NULL; } else if (lfs2_tag_type3(attrs[i].tag) == LFS2_TYPE_DELETE && @@ -2333,7 +2389,9 @@ fixmlist:; while (d->id >= d->m.count && d->m.split) { // we split and id is on tail now - d->id -= d->m.count; + if (lfs2_pair_cmp(d->m.tail, lfs2->root) != 0) { + d->id -= d->m.count; + } int err = lfs2_dir_fetch(lfs2, &d->m, d->m.tail); if (err) { return err; @@ -2499,7 +2557,7 @@ static int lfs2_dir_orphaningcommit(lfs2_t *lfs2, lfs2_mdir_t *dir, if (err != LFS2_ERR_NOENT) { if (lfs2_gstate_hasorphans(&lfs2->gstate)) { // next step, clean up orphans - err = lfs2_fs_preporphans(lfs2, -hasparent); + err = lfs2_fs_preporphans(lfs2, -(int8_t)hasparent); if (err) { return err; } @@ -2564,7 +2622,7 @@ static int lfs2_dir_commit(lfs2_t *lfs2, lfs2_mdir_t *dir, /// Top level directory operations /// #ifndef LFS2_READONLY -static int lfs2_rawmkdir(lfs2_t *lfs2, const char *path) { +static int lfs2_mkdir_(lfs2_t *lfs2, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { @@ -2575,18 +2633,18 @@ static int lfs2_rawmkdir(lfs2_t *lfs2, const char *path) { cwd.next = lfs2->mlist; uint16_t id; err = lfs2_dir_find(lfs2, &cwd.m, &path, &id); - if (!(err == LFS2_ERR_NOENT && id != 0x3ff)) { + if (!(err == LFS2_ERR_NOENT && lfs2_path_islast(path))) { return (err < 0) ? err : LFS2_ERR_EXIST; } // check that name fits - lfs2_size_t nlen = strlen(path); + lfs2_size_t nlen = lfs2_path_namelen(path); if (nlen > lfs2->name_max) { return LFS2_ERR_NAMETOOLONG; } // build up new directory - lfs2_alloc_ack(lfs2); + lfs2_alloc_ckpoint(lfs2); lfs2_mdir_t dir; err = lfs2_dir_alloc(lfs2, &dir); if (err) { @@ -2660,7 +2718,7 @@ static int lfs2_rawmkdir(lfs2_t *lfs2, const char *path) { } #endif -static int lfs2_dir_rawopen(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { +static int lfs2_dir_open_(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { lfs2_stag_t tag = lfs2_dir_find(lfs2, &dir->m, &path, NULL); if (tag < 0) { return tag; @@ -2704,14 +2762,14 @@ static int lfs2_dir_rawopen(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { return 0; } -static int lfs2_dir_rawclose(lfs2_t *lfs2, lfs2_dir_t *dir) { +static int lfs2_dir_close_(lfs2_t *lfs2, lfs2_dir_t *dir) { // remove from list of mdirs lfs2_mlist_remove(lfs2, (struct lfs2_mlist *)dir); return 0; } -static int lfs2_dir_rawread(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { +static int lfs2_dir_read_(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { memset(info, 0, sizeof(*info)); // special offset for '.' and '..' @@ -2756,9 +2814,9 @@ static int lfs2_dir_rawread(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *inf return true; } -static int lfs2_dir_rawseek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { +static int lfs2_dir_seek_(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { // simply walk from head dir - int err = lfs2_dir_rawrewind(lfs2, dir); + int err = lfs2_dir_rewind_(lfs2, dir); if (err) { return err; } @@ -2793,12 +2851,12 @@ static int lfs2_dir_rawseek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { return 0; } -static lfs2_soff_t lfs2_dir_rawtell(lfs2_t *lfs2, lfs2_dir_t *dir) { +static lfs2_soff_t lfs2_dir_tell_(lfs2_t *lfs2, lfs2_dir_t *dir) { (void)lfs2; return dir->pos; } -static int lfs2_dir_rawrewind(lfs2_t *lfs2, lfs2_dir_t *dir) { +static int lfs2_dir_rewind_(lfs2_t *lfs2, lfs2_dir_t *dir) { // reload the head dir int err = lfs2_dir_fetch(lfs2, &dir->m, dir->head); if (err) { @@ -3004,7 +3062,7 @@ static int lfs2_ctz_traverse(lfs2_t *lfs2, /// Top level file operations /// -static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, +static int lfs2_file_opencfg_(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags, const struct lfs2_file_config *cfg) { #ifndef LFS2_READONLY @@ -3029,7 +3087,7 @@ static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, // allocate entry for file if it doesn't exist lfs2_stag_t tag = lfs2_dir_find(lfs2, &file->m, &path, &file->id); - if (tag < 0 && !(tag == LFS2_ERR_NOENT && file->id != 0x3ff)) { + if (tag < 0 && !(tag == LFS2_ERR_NOENT && lfs2_path_islast(path))) { err = tag; goto cleanup; } @@ -3049,8 +3107,14 @@ static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, goto cleanup; } + // don't allow trailing slashes + if (lfs2_path_isdir(path)) { + err = LFS2_ERR_NOTDIR; + goto cleanup; + } + // check that name fits - lfs2_size_t nlen = strlen(path); + lfs2_size_t nlen = lfs2_path_namelen(path); if (nlen > lfs2->name_max) { err = LFS2_ERR_NAMETOOLONG; goto cleanup; @@ -3166,22 +3230,22 @@ static int lfs2_file_rawopencfg(lfs2_t *lfs2, lfs2_file_t *file, #ifndef LFS2_READONLY file->flags |= LFS2_F_ERRED; #endif - lfs2_file_rawclose(lfs2, file); + lfs2_file_close_(lfs2, file); return err; } #ifndef LFS2_NO_MALLOC -static int lfs2_file_rawopen(lfs2_t *lfs2, lfs2_file_t *file, +static int lfs2_file_open_(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags) { static const struct lfs2_file_config defaults = {0}; - int err = lfs2_file_rawopencfg(lfs2, file, path, flags, &defaults); + int err = lfs2_file_opencfg_(lfs2, file, path, flags, &defaults); return err; } #endif -static int lfs2_file_rawclose(lfs2_t *lfs2, lfs2_file_t *file) { +static int lfs2_file_close_(lfs2_t *lfs2, lfs2_file_t *file) { #ifndef LFS2_READONLY - int err = lfs2_file_rawsync(lfs2, file); + int err = lfs2_file_sync_(lfs2, file); #else int err = 0; #endif @@ -3272,7 +3336,7 @@ static int lfs2_file_relocate(lfs2_t *lfs2, lfs2_file_t *file) { #ifndef LFS2_READONLY static int lfs2_file_outline(lfs2_t *lfs2, lfs2_file_t *file) { file->off = file->pos; - lfs2_alloc_ack(lfs2); + lfs2_alloc_ckpoint(lfs2); int err = lfs2_file_relocate(lfs2, file); if (err) { return err; @@ -3364,7 +3428,7 @@ static int lfs2_file_flush(lfs2_t *lfs2, lfs2_file_t *file) { } #ifndef LFS2_READONLY -static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file) { +static int lfs2_file_sync_(lfs2_t *lfs2, lfs2_file_t *file) { if (file->flags & LFS2_F_ERRED) { // it's not safe to do anything if our file errored return 0; @@ -3379,6 +3443,15 @@ static int lfs2_file_rawsync(lfs2_t *lfs2, lfs2_file_t *file) { if ((file->flags & LFS2_F_DIRTY) && !lfs2_pair_isnull(file->m.pair)) { + // before we commit metadata, we need sync the disk to make sure + // data writes don't complete after metadata writes + if (!(file->flags & LFS2_F_INLINE)) { + err = lfs2_bd_sync(lfs2, &lfs2->pcache, &lfs2->rcache, false); + if (err) { + return err; + } + } + // update dir entry uint16_t type; const void *buffer; @@ -3477,7 +3550,7 @@ static lfs2_ssize_t lfs2_file_flushedread(lfs2_t *lfs2, lfs2_file_t *file, return size; } -static lfs2_ssize_t lfs2_file_rawread(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_read_(lfs2_t *lfs2, lfs2_file_t *file, void *buffer, lfs2_size_t size) { LFS2_ASSERT((file->flags & LFS2_O_RDONLY) == LFS2_O_RDONLY); @@ -3502,11 +3575,7 @@ static lfs2_ssize_t lfs2_file_flushedwrite(lfs2_t *lfs2, lfs2_file_t *file, lfs2_size_t nsize = size; if ((file->flags & LFS2_F_INLINE) && - lfs2_max(file->pos+nsize, file->ctz.size) > - lfs2_min(0x3fe, lfs2_min( - lfs2->cfg->cache_size, - (lfs2->cfg->metadata_max ? - lfs2->cfg->metadata_max : lfs2->cfg->block_size) / 8))) { + lfs2_max(file->pos+nsize, file->ctz.size) > lfs2->inline_max) { // inline file doesn't fit anymore int err = lfs2_file_outline(lfs2, file); if (err) { @@ -3535,7 +3604,7 @@ static lfs2_ssize_t lfs2_file_flushedwrite(lfs2_t *lfs2, lfs2_file_t *file, } // extend file with new blocks - lfs2_alloc_ack(lfs2); + lfs2_alloc_ckpoint(lfs2); int err = lfs2_ctz_extend(lfs2, &file->cache, &lfs2->rcache, file->block, file->pos, &file->block, &file->off); @@ -3578,13 +3647,13 @@ static lfs2_ssize_t lfs2_file_flushedwrite(lfs2_t *lfs2, lfs2_file_t *file, data += diff; nsize -= diff; - lfs2_alloc_ack(lfs2); + lfs2_alloc_ckpoint(lfs2); } return size; } -static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_ssize_t lfs2_file_write_(lfs2_t *lfs2, lfs2_file_t *file, const void *buffer, lfs2_size_t size) { LFS2_ASSERT((file->flags & LFS2_O_WRONLY) == LFS2_O_WRONLY); @@ -3628,25 +3697,19 @@ static lfs2_ssize_t lfs2_file_rawwrite(lfs2_t *lfs2, lfs2_file_t *file, } #endif -static lfs2_soff_t lfs2_file_rawseek(lfs2_t *lfs2, lfs2_file_t *file, +static lfs2_soff_t lfs2_file_seek_(lfs2_t *lfs2, lfs2_file_t *file, lfs2_soff_t off, int whence) { // find new pos + // + // fortunately for us, littlefs is limited to 31-bit file sizes, so we + // don't have to worry too much about integer overflow lfs2_off_t npos = file->pos; if (whence == LFS2_SEEK_SET) { npos = off; } else if (whence == LFS2_SEEK_CUR) { - if ((lfs2_soff_t)file->pos + off < 0) { - return LFS2_ERR_INVAL; - } else { - npos = file->pos + off; - } + npos = file->pos + (lfs2_off_t)off; } else if (whence == LFS2_SEEK_END) { - lfs2_soff_t res = lfs2_file_rawsize(lfs2, file) + off; - if (res < 0) { - return LFS2_ERR_INVAL; - } else { - npos = res; - } + npos = (lfs2_off_t)lfs2_file_size_(lfs2, file) + (lfs2_off_t)off; } if (npos > lfs2->file_max) { @@ -3661,13 +3724,8 @@ static lfs2_soff_t lfs2_file_rawseek(lfs2_t *lfs2, lfs2_file_t *file, // if we're only reading and our new offset is still in the file's cache // we can avoid flushing and needing to reread the data - if ( -#ifndef LFS2_READONLY - !(file->flags & LFS2_F_WRITING) -#else - true -#endif - ) { + if ((file->flags & LFS2_F_READING) + && file->off != lfs2->cfg->block_size) { int oindex = lfs2_ctz_index(lfs2, &(lfs2_off_t){file->pos}); lfs2_off_t noff = npos; int nindex = lfs2_ctz_index(lfs2, &noff); @@ -3692,7 +3750,7 @@ static lfs2_soff_t lfs2_file_rawseek(lfs2_t *lfs2, lfs2_file_t *file, } #ifndef LFS2_READONLY -static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { +static int lfs2_file_truncate_(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { LFS2_ASSERT((file->flags & LFS2_O_WRONLY) == LFS2_O_WRONLY); if (size > LFS2_FILE_MAX) { @@ -3700,15 +3758,12 @@ static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t siz } lfs2_off_t pos = file->pos; - lfs2_off_t oldsize = lfs2_file_rawsize(lfs2, file); + lfs2_off_t oldsize = lfs2_file_size_(lfs2, file); if (size < oldsize) { // revert to inline file? - if (size <= lfs2_min(0x3fe, lfs2_min( - lfs2->cfg->cache_size, - (lfs2->cfg->metadata_max ? - lfs2->cfg->metadata_max : lfs2->cfg->block_size) / 8))) { + if (size <= lfs2->inline_max) { // flush+seek to head - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, 0, LFS2_SEEK_SET); + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, 0, LFS2_SEEK_SET); if (res < 0) { return (int)res; } @@ -3753,14 +3808,14 @@ static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t siz } } else if (size > oldsize) { // flush+seek if not already at end - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, 0, LFS2_SEEK_END); + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, 0, LFS2_SEEK_END); if (res < 0) { return (int)res; } // fill with zeros while (file->pos < size) { - res = lfs2_file_rawwrite(lfs2, file, &(uint8_t){0}, 1); + res = lfs2_file_write_(lfs2, file, &(uint8_t){0}, 1); if (res < 0) { return (int)res; } @@ -3768,7 +3823,7 @@ static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t siz } // restore pos - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, pos, LFS2_SEEK_SET); + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, pos, LFS2_SEEK_SET); if (res < 0) { return (int)res; } @@ -3777,13 +3832,13 @@ static int lfs2_file_rawtruncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t siz } #endif -static lfs2_soff_t lfs2_file_rawtell(lfs2_t *lfs2, lfs2_file_t *file) { +static lfs2_soff_t lfs2_file_tell_(lfs2_t *lfs2, lfs2_file_t *file) { (void)lfs2; return file->pos; } -static int lfs2_file_rawrewind(lfs2_t *lfs2, lfs2_file_t *file) { - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, 0, LFS2_SEEK_SET); +static int lfs2_file_rewind_(lfs2_t *lfs2, lfs2_file_t *file) { + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, 0, LFS2_SEEK_SET); if (res < 0) { return (int)res; } @@ -3791,7 +3846,7 @@ static int lfs2_file_rawrewind(lfs2_t *lfs2, lfs2_file_t *file) { return 0; } -static lfs2_soff_t lfs2_file_rawsize(lfs2_t *lfs2, lfs2_file_t *file) { +static lfs2_soff_t lfs2_file_size_(lfs2_t *lfs2, lfs2_file_t *file) { (void)lfs2; #ifndef LFS2_READONLY @@ -3805,18 +3860,24 @@ static lfs2_soff_t lfs2_file_rawsize(lfs2_t *lfs2, lfs2_file_t *file) { /// General fs operations /// -static int lfs2_rawstat(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { +static int lfs2_stat_(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { lfs2_mdir_t cwd; lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); if (tag < 0) { return (int)tag; } + // only allow trailing slashes on dirs + if (strchr(path, '/') != NULL + && lfs2_tag_type3(tag) != LFS2_TYPE_DIR) { + return LFS2_ERR_NOTDIR; + } + return lfs2_dir_getinfo(lfs2, &cwd, lfs2_tag_id(tag), info); } #ifndef LFS2_READONLY -static int lfs2_rawremove(lfs2_t *lfs2, const char *path) { +static int lfs2_remove_(lfs2_t *lfs2, const char *path) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { @@ -3872,7 +3933,9 @@ static int lfs2_rawremove(lfs2_t *lfs2, const char *path) { } lfs2->mlist = dir.next; - if (lfs2_tag_type3(tag) == LFS2_TYPE_DIR) { + if (lfs2_gstate_hasorphans(&lfs2->gstate)) { + LFS2_ASSERT(lfs2_tag_type3(tag) == LFS2_TYPE_DIR); + // fix orphan err = lfs2_fs_preporphans(lfs2, -1); if (err) { @@ -3895,7 +3958,7 @@ static int lfs2_rawremove(lfs2_t *lfs2, const char *path) { #endif #ifndef LFS2_READONLY -static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { +static int lfs2_rename_(lfs2_t *lfs2, const char *oldpath, const char *newpath) { // deorphan if we haven't yet, needed at most once after poweron int err = lfs2_fs_forceconsistency(lfs2); if (err) { @@ -3914,7 +3977,7 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath uint16_t newid; lfs2_stag_t prevtag = lfs2_dir_find(lfs2, &newcwd, &newpath, &newid); if ((prevtag < 0 || lfs2_tag_id(prevtag) == 0x3ff) && - !(prevtag == LFS2_ERR_NOENT && newid != 0x3ff)) { + !(prevtag == LFS2_ERR_NOENT && lfs2_path_islast(newpath))) { return (prevtag < 0) ? (int)prevtag : LFS2_ERR_INVAL; } @@ -3925,8 +3988,14 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath struct lfs2_mlist prevdir; prevdir.next = lfs2->mlist; if (prevtag == LFS2_ERR_NOENT) { + // if we're a file, don't allow trailing slashes + if (lfs2_path_isdir(newpath) + && lfs2_tag_type3(oldtag) != LFS2_TYPE_DIR) { + return LFS2_ERR_NOTDIR; + } + // check that name fits - lfs2_size_t nlen = strlen(newpath); + lfs2_size_t nlen = lfs2_path_namelen(newpath); if (nlen > lfs2->name_max) { return LFS2_ERR_NAMETOOLONG; } @@ -3938,7 +4007,9 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath newoldid += 1; } } else if (lfs2_tag_type3(prevtag) != lfs2_tag_type3(oldtag)) { - return LFS2_ERR_ISDIR; + return (lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR) + ? LFS2_ERR_ISDIR + : LFS2_ERR_NOTDIR; } else if (samepair && newid == newoldid) { // we're renaming to ourselves?? return 0; @@ -3984,7 +4055,8 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath {LFS2_MKTAG_IF(prevtag != LFS2_ERR_NOENT, LFS2_TYPE_DELETE, newid, 0), NULL}, {LFS2_MKTAG(LFS2_TYPE_CREATE, newid, 0), NULL}, - {LFS2_MKTAG(lfs2_tag_type3(oldtag), newid, strlen(newpath)), newpath}, + {LFS2_MKTAG(lfs2_tag_type3(oldtag), + newid, lfs2_path_namelen(newpath)), newpath}, {LFS2_MKTAG(LFS2_FROM_MOVE, newid, lfs2_tag_id(oldtag)), &oldcwd}, {LFS2_MKTAG_IF(samepair, LFS2_TYPE_DELETE, newoldid, 0), NULL})); @@ -4007,8 +4079,10 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath } lfs2->mlist = prevdir.next; - if (prevtag != LFS2_ERR_NOENT - && lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR) { + if (lfs2_gstate_hasorphans(&lfs2->gstate)) { + LFS2_ASSERT(prevtag != LFS2_ERR_NOENT + && lfs2_tag_type3(prevtag) == LFS2_TYPE_DIR); + // fix orphan err = lfs2_fs_preporphans(lfs2, -1); if (err) { @@ -4030,7 +4104,7 @@ static int lfs2_rawrename(lfs2_t *lfs2, const char *oldpath, const char *newpath } #endif -static lfs2_ssize_t lfs2_rawgetattr(lfs2_t *lfs2, const char *path, +static lfs2_ssize_t lfs2_getattr_(lfs2_t *lfs2, const char *path, uint8_t type, void *buffer, lfs2_size_t size) { lfs2_mdir_t cwd; lfs2_stag_t tag = lfs2_dir_find(lfs2, &cwd, &path, NULL); @@ -4088,7 +4162,7 @@ static int lfs2_commitattr(lfs2_t *lfs2, const char *path, #endif #ifndef LFS2_READONLY -static int lfs2_rawsetattr(lfs2_t *lfs2, const char *path, +static int lfs2_setattr_(lfs2_t *lfs2, const char *path, uint8_t type, const void *buffer, lfs2_size_t size) { if (size > lfs2->attr_max) { return LFS2_ERR_NOSPC; @@ -4099,13 +4173,28 @@ static int lfs2_rawsetattr(lfs2_t *lfs2, const char *path, #endif #ifndef LFS2_READONLY -static int lfs2_rawremoveattr(lfs2_t *lfs2, const char *path, uint8_t type) { +static int lfs2_removeattr_(lfs2_t *lfs2, const char *path, uint8_t type) { return lfs2_commitattr(lfs2, path, type, NULL, 0x3ff); } #endif /// Filesystem operations /// + +// compile time checks, see lfs2.h for why these limits exist +#if LFS2_NAME_MAX > 1022 +#error "Invalid LFS2_NAME_MAX, must be <= 1022" +#endif + +#if LFS2_FILE_MAX > 2147483647 +#error "Invalid LFS2_FILE_MAX, must be <= 2147483647" +#endif + +#if LFS2_ATTR_MAX > 1022 +#error "Invalid LFS2_ATTR_MAX, must be <= 1022" +#endif + +// common filesystem initialization static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { lfs2->cfg = cfg; lfs2->block_count = cfg->block_count; // May be 0 @@ -4126,6 +4215,14 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { // which littlefs currently does not support LFS2_ASSERT((bool)0x80000000); + // check that the required io functions are provided + LFS2_ASSERT(lfs2->cfg->read != NULL); +#ifndef LFS2_READONLY + LFS2_ASSERT(lfs2->cfg->prog != NULL); + LFS2_ASSERT(lfs2->cfg->erase != NULL); + LFS2_ASSERT(lfs2->cfg->sync != NULL); +#endif + // validate that the lfs2-cfg sizes were initiated properly before // performing any arithmetic logics with them LFS2_ASSERT(lfs2->cfg->read_size != 0); @@ -4153,6 +4250,23 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { // wear-leveling. LFS2_ASSERT(lfs2->cfg->block_cycles != 0); + // check that compact_thresh makes sense + // + // metadata can't be compacted below block_size/2, and metadata can't + // exceed a block_size + LFS2_ASSERT(lfs2->cfg->compact_thresh == 0 + || lfs2->cfg->compact_thresh >= lfs2->cfg->block_size/2); + LFS2_ASSERT(lfs2->cfg->compact_thresh == (lfs2_size_t)-1 + || lfs2->cfg->compact_thresh <= lfs2->cfg->block_size); + + // check that metadata_max is a multiple of read_size and prog_size, + // and a factor of the block_size + LFS2_ASSERT(!lfs2->cfg->metadata_max + || lfs2->cfg->metadata_max % lfs2->cfg->read_size == 0); + LFS2_ASSERT(!lfs2->cfg->metadata_max + || lfs2->cfg->metadata_max % lfs2->cfg->prog_size == 0); + LFS2_ASSERT(!lfs2->cfg->metadata_max + || lfs2->cfg->block_size % lfs2->cfg->metadata_max == 0); // setup read cache if (lfs2->cfg->read_buffer) { @@ -4180,15 +4294,14 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { lfs2_cache_zero(lfs2, &lfs2->rcache); lfs2_cache_zero(lfs2, &lfs2->pcache); - // setup lookahead, must be multiple of 64-bits, 32-bit aligned + // setup lookahead buffer, note mount finishes initializing this after + // we establish a decent pseudo-random seed LFS2_ASSERT(lfs2->cfg->lookahead_size > 0); - LFS2_ASSERT(lfs2->cfg->lookahead_size % 8 == 0 && - (uintptr_t)lfs2->cfg->lookahead_buffer % 4 == 0); if (lfs2->cfg->lookahead_buffer) { - lfs2->free.buffer = lfs2->cfg->lookahead_buffer; + lfs2->lookahead.buffer = lfs2->cfg->lookahead_buffer; } else { - lfs2->free.buffer = lfs2_malloc(lfs2->cfg->lookahead_size); - if (!lfs2->free.buffer) { + lfs2->lookahead.buffer = lfs2_malloc(lfs2->cfg->lookahead_size); + if (!lfs2->lookahead.buffer) { err = LFS2_ERR_NOMEM; goto cleanup; } @@ -4215,6 +4328,27 @@ static int lfs2_init(lfs2_t *lfs2, const struct lfs2_config *cfg) { LFS2_ASSERT(lfs2->cfg->metadata_max <= lfs2->cfg->block_size); + LFS2_ASSERT(lfs2->cfg->inline_max == (lfs2_size_t)-1 + || lfs2->cfg->inline_max <= lfs2->cfg->cache_size); + LFS2_ASSERT(lfs2->cfg->inline_max == (lfs2_size_t)-1 + || lfs2->cfg->inline_max <= lfs2->attr_max); + LFS2_ASSERT(lfs2->cfg->inline_max == (lfs2_size_t)-1 + || lfs2->cfg->inline_max <= ((lfs2->cfg->metadata_max) + ? lfs2->cfg->metadata_max + : lfs2->cfg->block_size)/8); + lfs2->inline_max = lfs2->cfg->inline_max; + if (lfs2->inline_max == (lfs2_size_t)-1) { + lfs2->inline_max = 0; + } else if (lfs2->inline_max == 0) { + lfs2->inline_max = lfs2_min( + lfs2->cfg->cache_size, + lfs2_min( + lfs2->attr_max, + ((lfs2->cfg->metadata_max) + ? lfs2->cfg->metadata_max + : lfs2->cfg->block_size)/8)); + } + // setup default state lfs2->root[0] = LFS2_BLOCK_NULL; lfs2->root[1] = LFS2_BLOCK_NULL; @@ -4245,7 +4379,7 @@ static int lfs2_deinit(lfs2_t *lfs2) { } if (!lfs2->cfg->lookahead_buffer) { - lfs2_free(lfs2->free.buffer); + lfs2_free(lfs2->lookahead.buffer); } return 0; @@ -4254,7 +4388,7 @@ static int lfs2_deinit(lfs2_t *lfs2) { #ifndef LFS2_READONLY -static int lfs2_rawformat(lfs2_t *lfs2, const struct lfs2_config *cfg) { +static int lfs2_format_(lfs2_t *lfs2, const struct lfs2_config *cfg) { int err = 0; { err = lfs2_init(lfs2, cfg); @@ -4265,12 +4399,12 @@ static int lfs2_rawformat(lfs2_t *lfs2, const struct lfs2_config *cfg) { LFS2_ASSERT(cfg->block_count != 0); // create free lookahead - memset(lfs2->free.buffer, 0, lfs2->cfg->lookahead_size); - lfs2->free.off = 0; - lfs2->free.size = lfs2_min(8*lfs2->cfg->lookahead_size, + memset(lfs2->lookahead.buffer, 0, lfs2->cfg->lookahead_size); + lfs2->lookahead.start = 0; + lfs2->lookahead.size = lfs2_min(8*lfs2->cfg->lookahead_size, lfs2->block_count); - lfs2->free.i = 0; - lfs2_alloc_ack(lfs2); + lfs2->lookahead.next = 0; + lfs2_alloc_ckpoint(lfs2); // create root dir lfs2_mdir_t root; @@ -4321,7 +4455,31 @@ static int lfs2_rawformat(lfs2_t *lfs2, const struct lfs2_config *cfg) { } #endif -static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { +struct lfs2_tortoise_t { + lfs2_block_t pair[2]; + lfs2_size_t i; + lfs2_size_t period; +}; + +static int lfs2_tortoise_detectcycles( + const lfs2_mdir_t *dir, struct lfs2_tortoise_t *tortoise) { + // detect cycles with Brent's algorithm + if (lfs2_pair_issync(dir->tail, tortoise->pair)) { + LFS2_WARN("Cycle detected in tail list"); + return LFS2_ERR_CORRUPT; + } + if (tortoise->i == tortoise->period) { + tortoise->pair[0] = dir->tail[0]; + tortoise->pair[1] = dir->tail[1]; + tortoise->i = 0; + tortoise->period *= 2; + } + tortoise->i += 1; + + return LFS2_ERR_OK; +} + +static int lfs2_mount_(lfs2_t *lfs2, const struct lfs2_config *cfg) { int err = lfs2_init(lfs2, cfg); if (err) { return err; @@ -4329,23 +4487,16 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { // scan directory blocks for superblock and any global updates lfs2_mdir_t dir = {.tail = {0, 1}}; - lfs2_block_t tortoise[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; - lfs2_size_t tortoise_i = 1; - lfs2_size_t tortoise_period = 1; + struct lfs2_tortoise_t tortoise = { + .pair = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}, + .i = 1, + .period = 1, + }; while (!lfs2_pair_isnull(dir.tail)) { - // detect cycles with Brent's algorithm - if (lfs2_pair_issync(dir.tail, tortoise)) { - LFS2_WARN("Cycle detected in tail list"); - err = LFS2_ERR_CORRUPT; + err = lfs2_tortoise_detectcycles(&dir, &tortoise); + if (err < 0) { goto cleanup; } - if (tortoise_i == tortoise_period) { - tortoise[0] = dir.tail[0]; - tortoise[1] = dir.tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; // fetch next block in tail list lfs2_stag_t tag = lfs2_dir_fetchmatch(lfs2, &dir, dir.tail, @@ -4394,6 +4545,7 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { // found older minor version? set an in-device only bit in the // gstate so we know we need to rewrite the superblock before // the first write + bool needssuperblock = false; if (minor_version < lfs2_fs_disk_version_minor(lfs2)) { LFS2_DEBUG("Found older minor version " "v%"PRIu16".%"PRIu16" < v%"PRIu16".%"PRIu16, @@ -4401,10 +4553,11 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { minor_version, lfs2_fs_disk_version_major(lfs2), lfs2_fs_disk_version_minor(lfs2)); - // note this bit is reserved on disk, so fetching more gstate - // will not interfere here - lfs2_fs_prepsuperblock(lfs2, true); + needssuperblock = true; } + // note this bit is reserved on disk, so fetching more gstate + // will not interfere here + lfs2_fs_prepsuperblock(lfs2, needssuperblock); // check superblock configuration if (superblock.name_max) { @@ -4438,6 +4591,9 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { } lfs2->attr_max = superblock.attr_max; + + // we also need to update inline_max in case attr_max changed + lfs2->inline_max = lfs2_min(lfs2->inline_max, lfs2->attr_max); } // this is where we get the block_count from disk if block_count=0 @@ -4478,23 +4634,23 @@ static int lfs2_rawmount(lfs2_t *lfs2, const struct lfs2_config *cfg) { // setup free lookahead, to distribute allocations uniformly across // boots, we start the allocator at a random location - lfs2->free.off = lfs2->seed % lfs2->block_count; + lfs2->lookahead.start = lfs2->seed % lfs2->block_count; lfs2_alloc_drop(lfs2); return 0; cleanup: - lfs2_rawunmount(lfs2); + lfs2_unmount_(lfs2); return err; } -static int lfs2_rawunmount(lfs2_t *lfs2) { +static int lfs2_unmount_(lfs2_t *lfs2) { return lfs2_deinit(lfs2); } /// Filesystem filesystem operations /// -static int lfs2_fs_rawstat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) { +static int lfs2_fs_stat_(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) { // if the superblock is up-to-date, we must be on the most recent // minor version of littlefs if (!lfs2_gstate_needssuperblock(&lfs2->gstate)) { @@ -4534,7 +4690,7 @@ static int lfs2_fs_rawstat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) { return 0; } -int lfs2_fs_rawtraverse(lfs2_t *lfs2, +int lfs2_fs_traverse_(lfs2_t *lfs2, int (*cb)(void *data, lfs2_block_t block), void *data, bool includeorphans) { // iterate over metadata pairs @@ -4553,22 +4709,17 @@ int lfs2_fs_rawtraverse(lfs2_t *lfs2, } #endif - lfs2_block_t tortoise[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; - lfs2_size_t tortoise_i = 1; - lfs2_size_t tortoise_period = 1; + struct lfs2_tortoise_t tortoise = { + .pair = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS2_ERR_OK; while (!lfs2_pair_isnull(dir.tail)) { - // detect cycles with Brent's algorithm - if (lfs2_pair_issync(dir.tail, tortoise)) { - LFS2_WARN("Cycle detected in tail list"); + err = lfs2_tortoise_detectcycles(&dir, &tortoise); + if (err < 0) { return LFS2_ERR_CORRUPT; } - if (tortoise_i == tortoise_period) { - tortoise[0] = dir.tail[0]; - tortoise[1] = dir.tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; for (int i = 0; i < 2; i++) { int err = cb(data, dir.tail[i]); @@ -4647,22 +4798,17 @@ static int lfs2_fs_pred(lfs2_t *lfs2, // iterate over all directory directory entries pdir->tail[0] = 0; pdir->tail[1] = 1; - lfs2_block_t tortoise[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; - lfs2_size_t tortoise_i = 1; - lfs2_size_t tortoise_period = 1; + struct lfs2_tortoise_t tortoise = { + .pair = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS2_ERR_OK; while (!lfs2_pair_isnull(pdir->tail)) { - // detect cycles with Brent's algorithm - if (lfs2_pair_issync(pdir->tail, tortoise)) { - LFS2_WARN("Cycle detected in tail list"); + err = lfs2_tortoise_detectcycles(pdir, &tortoise); + if (err < 0) { return LFS2_ERR_CORRUPT; } - if (tortoise_i == tortoise_period) { - tortoise[0] = pdir->tail[0]; - tortoise[1] = pdir->tail[1]; - tortoise_i = 0; - tortoise_period *= 2; - } - tortoise_i += 1; if (lfs2_pair_cmp(pdir->tail, pair) == 0) { return 0; @@ -4712,22 +4858,17 @@ static lfs2_stag_t lfs2_fs_parent(lfs2_t *lfs2, const lfs2_block_t pair[2], // use fetchmatch with callback to find pairs parent->tail[0] = 0; parent->tail[1] = 1; - lfs2_block_t tortoise[2] = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}; - lfs2_size_t tortoise_i = 1; - lfs2_size_t tortoise_period = 1; + struct lfs2_tortoise_t tortoise = { + .pair = {LFS2_BLOCK_NULL, LFS2_BLOCK_NULL}, + .i = 1, + .period = 1, + }; + int err = LFS2_ERR_OK; while (!lfs2_pair_isnull(parent->tail)) { - // detect cycles with Brent's algorithm - if (lfs2_pair_issync(parent->tail, tortoise)) { - LFS2_WARN("Cycle detected in tail list"); - return LFS2_ERR_CORRUPT; - } - if (tortoise_i == tortoise_period) { - tortoise[0] = parent->tail[0]; - tortoise[1] = parent->tail[1]; - tortoise_i = 0; - tortoise_period *= 2; + err = lfs2_tortoise_detectcycles(parent, &tortoise); + if (err < 0) { + return err; } - tortoise_i += 1; lfs2_stag_t tag = lfs2_dir_fetchmatch(lfs2, parent, parent->tail, LFS2_MKTAG(0x7ff, 0, 0x3ff), @@ -4999,7 +5140,7 @@ static int lfs2_fs_forceconsistency(lfs2_t *lfs2) { #endif #ifndef LFS2_READONLY -static int lfs2_fs_rawmkconsistent(lfs2_t *lfs2) { +static int lfs2_fs_mkconsistent_(lfs2_t *lfs2) { // lfs2_fs_forceconsistency does most of the work here int err = lfs2_fs_forceconsistency(lfs2); if (err) { @@ -5035,9 +5176,9 @@ static int lfs2_fs_size_count(void *p, lfs2_block_t block) { return 0; } -static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2) { +static lfs2_ssize_t lfs2_fs_size_(lfs2_t *lfs2) { lfs2_size_t size = 0; - int err = lfs2_fs_rawtraverse(lfs2, lfs2_fs_size_count, &size, false); + int err = lfs2_fs_traverse_(lfs2, lfs2_fs_size_count, &size, false); if (err) { return err; } @@ -5045,41 +5186,118 @@ static lfs2_ssize_t lfs2_fs_rawsize(lfs2_t *lfs2) { return size; } +// explicit garbage collection #ifndef LFS2_READONLY -static int lfs2_fs_rawgrow(lfs2_t *lfs2, lfs2_size_t block_count) { - // shrinking is not supported - LFS2_ASSERT(block_count >= lfs2->block_count); +static int lfs2_fs_gc_(lfs2_t *lfs2) { + // force consistency, even if we're not necessarily going to write, + // because this function is supposed to take care of janitorial work + // isn't it? + int err = lfs2_fs_forceconsistency(lfs2); + if (err) { + return err; + } - if (block_count > lfs2->block_count) { - lfs2->block_count = block_count; + // try to compact metadata pairs, note we can't really accomplish + // anything if compact_thresh doesn't at least leave a prog_size + // available + if (lfs2->cfg->compact_thresh + < lfs2->cfg->block_size - lfs2->cfg->prog_size) { + // iterate over all mdirs + lfs2_mdir_t mdir = {.tail = {0, 1}}; + while (!lfs2_pair_isnull(mdir.tail)) { + err = lfs2_dir_fetch(lfs2, &mdir, mdir.tail); + if (err) { + return err; + } - // fetch the root - lfs2_mdir_t root; - int err = lfs2_dir_fetch(lfs2, &root, lfs2->root); + // not erased? exceeds our compaction threshold? + if (!mdir.erased || ((lfs2->cfg->compact_thresh == 0) + ? mdir.off > lfs2->cfg->block_size - lfs2->cfg->block_size/8 + : mdir.off > lfs2->cfg->compact_thresh)) { + // the easiest way to trigger a compaction is to mark + // the mdir as unerased and add an empty commit + mdir.erased = false; + err = lfs2_dir_commit(lfs2, &mdir, NULL, 0); + if (err) { + return err; + } + } + } + } + + // try to populate the lookahead buffer, unless it's already full + if (lfs2->lookahead.size < lfs2_min( + 8 * lfs2->cfg->lookahead_size, + lfs2->block_count)) { + err = lfs2_alloc_scan(lfs2); if (err) { return err; } + } - // update the superblock - lfs2_superblock_t superblock; - lfs2_stag_t tag = lfs2_dir_get(lfs2, &root, LFS2_MKTAG(0x7ff, 0x3ff, 0), - LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)), - &superblock); - if (tag < 0) { - return tag; - } - lfs2_superblock_fromle32(&superblock); + return 0; +} +#endif - superblock.block_count = lfs2->block_count; +#ifndef LFS2_READONLY +#ifdef LFS2_SHRINKNONRELOCATING +static int lfs2_shrink_checkblock(void *data, lfs2_block_t block) { + lfs2_size_t threshold = *((lfs2_size_t*)data); + if (block >= threshold) { + return LFS2_ERR_NOTEMPTY; + } + return 0; +} +#endif - lfs2_superblock_tole32(&superblock); - err = lfs2_dir_commit(lfs2, &root, LFS2_MKATTRS( - {tag, &superblock})); +static int lfs2_fs_grow_(lfs2_t *lfs2, lfs2_size_t block_count) { + int err; + + if (block_count == lfs2->block_count) { + return 0; + } + + +#ifndef LFS2_SHRINKNONRELOCATING + // shrinking is not supported + LFS2_ASSERT(block_count >= lfs2->block_count); +#endif +#ifdef LFS2_SHRINKNONRELOCATING + if (block_count < lfs2->block_count) { + err = lfs2_fs_traverse_(lfs2, lfs2_shrink_checkblock, &block_count, true); if (err) { return err; } } +#endif + + lfs2->block_count = block_count; + // fetch the root + lfs2_mdir_t root; + err = lfs2_dir_fetch(lfs2, &root, lfs2->root); + if (err) { + return err; + } + + // update the superblock + lfs2_superblock_t superblock; + lfs2_stag_t tag = lfs2_dir_get(lfs2, &root, LFS2_MKTAG(0x7ff, 0x3ff, 0), + LFS2_MKTAG(LFS2_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock); + if (tag < 0) { + return tag; + } + lfs2_superblock_fromle32(&superblock); + + superblock.block_count = lfs2->block_count; + + lfs2_superblock_tole32(&superblock); + err = lfs2_dir_commit(lfs2, &root, LFS2_MKATTRS( + {tag, &superblock})); + if (err) { + return err; + } return 0; } #endif @@ -5451,10 +5669,10 @@ static int lfs21_mount(lfs2_t *lfs2, struct lfs21 *lfs21, lfs2->lfs21->root[1] = LFS2_BLOCK_NULL; // setup free lookahead - lfs2->free.off = 0; - lfs2->free.size = 0; - lfs2->free.i = 0; - lfs2_alloc_ack(lfs2); + lfs2->lookahead.start = 0; + lfs2->lookahead.size = 0; + lfs2->lookahead.next = 0; + lfs2_alloc_ckpoint(lfs2); // load superblock lfs21_dir_t dir; @@ -5505,7 +5723,7 @@ static int lfs21_unmount(lfs2_t *lfs2) { } /// v1 migration /// -static int lfs2_rawmigrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { +static int lfs2_migrate_(lfs2_t *lfs2, const struct lfs2_config *cfg) { struct lfs21 lfs21; // Indeterminate filesystem size not allowed for migration. @@ -5759,7 +5977,7 @@ int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " @@ -5772,7 +5990,7 @@ int lfs2_format(lfs2_t *lfs2, const struct lfs2_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs2_rawformat(lfs2, cfg); + err = lfs2_format_(lfs2, cfg); LFS2_TRACE("lfs2_format -> %d", err); LFS2_UNLOCK(cfg); @@ -5789,7 +6007,7 @@ int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " @@ -5802,7 +6020,7 @@ int lfs2_mount(lfs2_t *lfs2, const struct lfs2_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs2_rawmount(lfs2, cfg); + err = lfs2_mount_(lfs2, cfg); LFS2_TRACE("lfs2_mount -> %d", err); LFS2_UNLOCK(cfg); @@ -5816,7 +6034,7 @@ int lfs2_unmount(lfs2_t *lfs2) { } LFS2_TRACE("lfs2_unmount(%p)", (void*)lfs2); - err = lfs2_rawunmount(lfs2); + err = lfs2_unmount_(lfs2); LFS2_TRACE("lfs2_unmount -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5831,7 +6049,7 @@ int lfs2_remove(lfs2_t *lfs2, const char *path) { } LFS2_TRACE("lfs2_remove(%p, \"%s\")", (void*)lfs2, path); - err = lfs2_rawremove(lfs2, path); + err = lfs2_remove_(lfs2, path); LFS2_TRACE("lfs2_remove -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5847,7 +6065,7 @@ int lfs2_rename(lfs2_t *lfs2, const char *oldpath, const char *newpath) { } LFS2_TRACE("lfs2_rename(%p, \"%s\", \"%s\")", (void*)lfs2, oldpath, newpath); - err = lfs2_rawrename(lfs2, oldpath, newpath); + err = lfs2_rename_(lfs2, oldpath, newpath); LFS2_TRACE("lfs2_rename -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5862,7 +6080,7 @@ int lfs2_stat(lfs2_t *lfs2, const char *path, struct lfs2_info *info) { } LFS2_TRACE("lfs2_stat(%p, \"%s\", %p)", (void*)lfs2, path, (void*)info); - err = lfs2_rawstat(lfs2, path, info); + err = lfs2_stat_(lfs2, path, info); LFS2_TRACE("lfs2_stat -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5878,7 +6096,7 @@ lfs2_ssize_t lfs2_getattr(lfs2_t *lfs2, const char *path, LFS2_TRACE("lfs2_getattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", (void*)lfs2, path, type, buffer, size); - lfs2_ssize_t res = lfs2_rawgetattr(lfs2, path, type, buffer, size); + lfs2_ssize_t res = lfs2_getattr_(lfs2, path, type, buffer, size); LFS2_TRACE("lfs2_getattr -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -5895,7 +6113,7 @@ int lfs2_setattr(lfs2_t *lfs2, const char *path, LFS2_TRACE("lfs2_setattr(%p, \"%s\", %"PRIu8", %p, %"PRIu32")", (void*)lfs2, path, type, buffer, size); - err = lfs2_rawsetattr(lfs2, path, type, buffer, size); + err = lfs2_setattr_(lfs2, path, type, buffer, size); LFS2_TRACE("lfs2_setattr -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5911,7 +6129,7 @@ int lfs2_removeattr(lfs2_t *lfs2, const char *path, uint8_t type) { } LFS2_TRACE("lfs2_removeattr(%p, \"%s\", %"PRIu8")", (void*)lfs2, path, type); - err = lfs2_rawremoveattr(lfs2, path, type); + err = lfs2_removeattr_(lfs2, path, type); LFS2_TRACE("lfs2_removeattr -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5926,10 +6144,10 @@ int lfs2_file_open(lfs2_t *lfs2, lfs2_file_t *file, const char *path, int flags) return err; } LFS2_TRACE("lfs2_file_open(%p, %p, \"%s\", %x)", - (void*)lfs2, (void*)file, path, flags); + (void*)lfs2, (void*)file, path, (unsigned)flags); LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawopen(lfs2, file, path, flags); + err = lfs2_file_open_(lfs2, file, path, flags); LFS2_TRACE("lfs2_file_open -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5946,11 +6164,11 @@ int lfs2_file_opencfg(lfs2_t *lfs2, lfs2_file_t *file, } LFS2_TRACE("lfs2_file_opencfg(%p, %p, \"%s\", %x, %p {" ".buffer=%p, .attrs=%p, .attr_count=%"PRIu32"})", - (void*)lfs2, (void*)file, path, flags, + (void*)lfs2, (void*)file, path, (unsigned)flags, (void*)cfg, cfg->buffer, (void*)cfg->attrs, cfg->attr_count); LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawopencfg(lfs2, file, path, flags, cfg); + err = lfs2_file_opencfg_(lfs2, file, path, flags, cfg); LFS2_TRACE("lfs2_file_opencfg -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5965,7 +6183,7 @@ int lfs2_file_close(lfs2_t *lfs2, lfs2_file_t *file) { LFS2_TRACE("lfs2_file_close(%p, %p)", (void*)lfs2, (void*)file); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawclose(lfs2, file); + err = lfs2_file_close_(lfs2, file); LFS2_TRACE("lfs2_file_close -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5981,7 +6199,7 @@ int lfs2_file_sync(lfs2_t *lfs2, lfs2_file_t *file) { LFS2_TRACE("lfs2_file_sync(%p, %p)", (void*)lfs2, (void*)file); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawsync(lfs2, file); + err = lfs2_file_sync_(lfs2, file); LFS2_TRACE("lfs2_file_sync -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -5999,7 +6217,7 @@ lfs2_ssize_t lfs2_file_read(lfs2_t *lfs2, lfs2_file_t *file, (void*)lfs2, (void*)file, buffer, size); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_ssize_t res = lfs2_file_rawread(lfs2, file, buffer, size); + lfs2_ssize_t res = lfs2_file_read_(lfs2, file, buffer, size); LFS2_TRACE("lfs2_file_read -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6017,7 +6235,7 @@ lfs2_ssize_t lfs2_file_write(lfs2_t *lfs2, lfs2_file_t *file, (void*)lfs2, (void*)file, buffer, size); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_ssize_t res = lfs2_file_rawwrite(lfs2, file, buffer, size); + lfs2_ssize_t res = lfs2_file_write_(lfs2, file, buffer, size); LFS2_TRACE("lfs2_file_write -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6035,7 +6253,7 @@ lfs2_soff_t lfs2_file_seek(lfs2_t *lfs2, lfs2_file_t *file, (void*)lfs2, (void*)file, off, whence); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_soff_t res = lfs2_file_rawseek(lfs2, file, off, whence); + lfs2_soff_t res = lfs2_file_seek_(lfs2, file, off, whence); LFS2_TRACE("lfs2_file_seek -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6052,7 +6270,7 @@ int lfs2_file_truncate(lfs2_t *lfs2, lfs2_file_t *file, lfs2_off_t size) { (void*)lfs2, (void*)file, size); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - err = lfs2_file_rawtruncate(lfs2, file, size); + err = lfs2_file_truncate_(lfs2, file, size); LFS2_TRACE("lfs2_file_truncate -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6068,7 +6286,7 @@ lfs2_soff_t lfs2_file_tell(lfs2_t *lfs2, lfs2_file_t *file) { LFS2_TRACE("lfs2_file_tell(%p, %p)", (void*)lfs2, (void*)file); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_soff_t res = lfs2_file_rawtell(lfs2, file); + lfs2_soff_t res = lfs2_file_tell_(lfs2, file); LFS2_TRACE("lfs2_file_tell -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6082,7 +6300,7 @@ int lfs2_file_rewind(lfs2_t *lfs2, lfs2_file_t *file) { } LFS2_TRACE("lfs2_file_rewind(%p, %p)", (void*)lfs2, (void*)file); - err = lfs2_file_rawrewind(lfs2, file); + err = lfs2_file_rewind_(lfs2, file); LFS2_TRACE("lfs2_file_rewind -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6097,9 +6315,9 @@ lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file) { LFS2_TRACE("lfs2_file_size(%p, %p)", (void*)lfs2, (void*)file); LFS2_ASSERT(lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)file)); - lfs2_soff_t res = lfs2_file_rawsize(lfs2, file); + lfs2_soff_t res = lfs2_file_size_(lfs2, file); - LFS2_TRACE("lfs2_file_size -> %"PRId32, res); + LFS2_TRACE("lfs2_file_size -> %"PRIu32, res); LFS2_UNLOCK(lfs2->cfg); return res; } @@ -6112,7 +6330,7 @@ int lfs2_mkdir(lfs2_t *lfs2, const char *path) { } LFS2_TRACE("lfs2_mkdir(%p, \"%s\")", (void*)lfs2, path); - err = lfs2_rawmkdir(lfs2, path); + err = lfs2_mkdir_(lfs2, path); LFS2_TRACE("lfs2_mkdir -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6128,7 +6346,7 @@ int lfs2_dir_open(lfs2_t *lfs2, lfs2_dir_t *dir, const char *path) { LFS2_TRACE("lfs2_dir_open(%p, %p, \"%s\")", (void*)lfs2, (void*)dir, path); LFS2_ASSERT(!lfs2_mlist_isopen(lfs2->mlist, (struct lfs2_mlist*)dir)); - err = lfs2_dir_rawopen(lfs2, dir, path); + err = lfs2_dir_open_(lfs2, dir, path); LFS2_TRACE("lfs2_dir_open -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6142,7 +6360,7 @@ int lfs2_dir_close(lfs2_t *lfs2, lfs2_dir_t *dir) { } LFS2_TRACE("lfs2_dir_close(%p, %p)", (void*)lfs2, (void*)dir); - err = lfs2_dir_rawclose(lfs2, dir); + err = lfs2_dir_close_(lfs2, dir); LFS2_TRACE("lfs2_dir_close -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6157,7 +6375,7 @@ int lfs2_dir_read(lfs2_t *lfs2, lfs2_dir_t *dir, struct lfs2_info *info) { LFS2_TRACE("lfs2_dir_read(%p, %p, %p)", (void*)lfs2, (void*)dir, (void*)info); - err = lfs2_dir_rawread(lfs2, dir, info); + err = lfs2_dir_read_(lfs2, dir, info); LFS2_TRACE("lfs2_dir_read -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6172,7 +6390,7 @@ int lfs2_dir_seek(lfs2_t *lfs2, lfs2_dir_t *dir, lfs2_off_t off) { LFS2_TRACE("lfs2_dir_seek(%p, %p, %"PRIu32")", (void*)lfs2, (void*)dir, off); - err = lfs2_dir_rawseek(lfs2, dir, off); + err = lfs2_dir_seek_(lfs2, dir, off); LFS2_TRACE("lfs2_dir_seek -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6186,7 +6404,7 @@ lfs2_soff_t lfs2_dir_tell(lfs2_t *lfs2, lfs2_dir_t *dir) { } LFS2_TRACE("lfs2_dir_tell(%p, %p)", (void*)lfs2, (void*)dir); - lfs2_soff_t res = lfs2_dir_rawtell(lfs2, dir); + lfs2_soff_t res = lfs2_dir_tell_(lfs2, dir); LFS2_TRACE("lfs2_dir_tell -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6200,7 +6418,7 @@ int lfs2_dir_rewind(lfs2_t *lfs2, lfs2_dir_t *dir) { } LFS2_TRACE("lfs2_dir_rewind(%p, %p)", (void*)lfs2, (void*)dir); - err = lfs2_dir_rawrewind(lfs2, dir); + err = lfs2_dir_rewind_(lfs2, dir); LFS2_TRACE("lfs2_dir_rewind -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6214,7 +6432,7 @@ int lfs2_fs_stat(lfs2_t *lfs2, struct lfs2_fsinfo *fsinfo) { } LFS2_TRACE("lfs2_fs_stat(%p, %p)", (void*)lfs2, (void*)fsinfo); - err = lfs2_fs_rawstat(lfs2, fsinfo); + err = lfs2_fs_stat_(lfs2, fsinfo); LFS2_TRACE("lfs2_fs_stat -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6228,7 +6446,7 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2) { } LFS2_TRACE("lfs2_fs_size(%p)", (void*)lfs2); - lfs2_ssize_t res = lfs2_fs_rawsize(lfs2); + lfs2_ssize_t res = lfs2_fs_size_(lfs2); LFS2_TRACE("lfs2_fs_size -> %"PRId32, res); LFS2_UNLOCK(lfs2->cfg); @@ -6243,7 +6461,7 @@ int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void *, lfs2_block_t), void *data) LFS2_TRACE("lfs2_fs_traverse(%p, %p, %p)", (void*)lfs2, (void*)(uintptr_t)cb, data); - err = lfs2_fs_rawtraverse(lfs2, cb, data, true); + err = lfs2_fs_traverse_(lfs2, cb, data, true); LFS2_TRACE("lfs2_fs_traverse -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6251,32 +6469,32 @@ int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void *, lfs2_block_t), void *data) } #ifndef LFS2_READONLY -int lfs2_fs_gc(lfs2_t *lfs2) { +int lfs2_fs_mkconsistent(lfs2_t *lfs2) { int err = LFS2_LOCK(lfs2->cfg); if (err) { return err; } - LFS2_TRACE("lfs2_fs_gc(%p)", (void*)lfs2); + LFS2_TRACE("lfs2_fs_mkconsistent(%p)", (void*)lfs2); - err = lfs2_fs_rawgc(lfs2); + err = lfs2_fs_mkconsistent_(lfs2); - LFS2_TRACE("lfs2_fs_gc -> %d", err); + LFS2_TRACE("lfs2_fs_mkconsistent -> %d", err); LFS2_UNLOCK(lfs2->cfg); return err; } #endif #ifndef LFS2_READONLY -int lfs2_fs_mkconsistent(lfs2_t *lfs2) { +int lfs2_fs_gc(lfs2_t *lfs2) { int err = LFS2_LOCK(lfs2->cfg); if (err) { return err; } - LFS2_TRACE("lfs2_fs_mkconsistent(%p)", (void*)lfs2); + LFS2_TRACE("lfs2_fs_gc(%p)", (void*)lfs2); - err = lfs2_fs_rawmkconsistent(lfs2); + err = lfs2_fs_gc_(lfs2); - LFS2_TRACE("lfs2_fs_mkconsistent -> %d", err); + LFS2_TRACE("lfs2_fs_gc -> %d", err); LFS2_UNLOCK(lfs2->cfg); return err; } @@ -6290,7 +6508,7 @@ int lfs2_fs_grow(lfs2_t *lfs2, lfs2_size_t block_count) { } LFS2_TRACE("lfs2_fs_grow(%p, %"PRIu32")", (void*)lfs2, block_count); - err = lfs2_fs_rawgrow(lfs2, block_count); + err = lfs2_fs_grow_(lfs2, block_count); LFS2_TRACE("lfs2_fs_grow -> %d", err); LFS2_UNLOCK(lfs2->cfg); @@ -6308,7 +6526,7 @@ int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { ".read=%p, .prog=%p, .erase=%p, .sync=%p, " ".read_size=%"PRIu32", .prog_size=%"PRIu32", " ".block_size=%"PRIu32", .block_count=%"PRIu32", " - ".block_cycles=%"PRIu32", .cache_size=%"PRIu32", " + ".block_cycles=%"PRId32", .cache_size=%"PRIu32", " ".lookahead_size=%"PRIu32", .read_buffer=%p, " ".prog_buffer=%p, .lookahead_buffer=%p, " ".name_max=%"PRIu32", .file_max=%"PRIu32", " @@ -6321,7 +6539,7 @@ int lfs2_migrate(lfs2_t *lfs2, const struct lfs2_config *cfg) { cfg->read_buffer, cfg->prog_buffer, cfg->lookahead_buffer, cfg->name_max, cfg->file_max, cfg->attr_max); - err = lfs2_rawmigrate(lfs2, cfg); + err = lfs2_migrate_(lfs2, cfg); LFS2_TRACE("lfs2_migrate -> %d", err); LFS2_UNLOCK(cfg); diff --git a/lib/littlefs/lfs2.h b/lib/littlefs/lfs2.h index 559ccebac92..aee0619e932 100644 --- a/lib/littlefs/lfs2.h +++ b/lib/littlefs/lfs2.h @@ -21,7 +21,7 @@ extern "C" // Software library version // Major (top-nibble), incremented on backwards incompatible changes // Minor (bottom-nibble), incremented on feature additions -#define LFS2_VERSION 0x00020008 +#define LFS2_VERSION 0x0002000b #define LFS2_VERSION_MAJOR (0xffff & (LFS2_VERSION >> 16)) #define LFS2_VERSION_MINOR (0xffff & (LFS2_VERSION >> 0)) @@ -52,16 +52,15 @@ typedef uint32_t lfs2_block_t; #endif // Maximum size of a file in bytes, may be redefined to limit to support other -// drivers. Limited on disk to <= 4294967296. However, above 2147483647 the -// functions lfs2_file_seek, lfs2_file_size, and lfs2_file_tell will return -// incorrect values due to using signed integers. Stored in superblock and -// must be respected by other littlefs drivers. +// drivers. Limited on disk to <= 2147483647. Stored in superblock and must be +// respected by other littlefs drivers. #ifndef LFS2_FILE_MAX #define LFS2_FILE_MAX 2147483647 #endif // Maximum size of custom attributes in bytes, may be redefined, but there is -// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022. +// no real benefit to using a smaller LFS2_ATTR_MAX. Limited to <= 1022. Stored +// in superblock and must be respected by other littlefs drivers. #ifndef LFS2_ATTR_MAX #define LFS2_ATTR_MAX 1022 #endif @@ -205,7 +204,8 @@ struct lfs2_config { // program sizes. lfs2_size_t block_size; - // Number of erasable blocks on the device. + // Number of erasable blocks on the device. Defaults to block_count stored + // on disk when zero. lfs2_size_t block_count; // Number of erase cycles before littlefs evicts metadata logs and moves @@ -226,9 +226,20 @@ struct lfs2_config { // Size of the lookahead buffer in bytes. A larger lookahead buffer // increases the number of blocks found during an allocation pass. The // lookahead buffer is stored as a compact bitmap, so each byte of RAM - // can track 8 blocks. Must be a multiple of 8. + // can track 8 blocks. lfs2_size_t lookahead_size; + // Threshold for metadata compaction during lfs2_fs_gc in bytes. Metadata + // pairs that exceed this threshold will be compacted during lfs2_fs_gc. + // Defaults to ~88% block_size when zero, though the default may change + // in the future. + // + // Note this only affects lfs2_fs_gc. Normal compactions still only occur + // when full. + // + // Set to -1 to disable metadata compaction during lfs2_fs_gc. + lfs2_size_t compact_thresh; + // Optional statically allocated read buffer. Must be cache_size. // By default lfs2_malloc is used to allocate this buffer. void *read_buffer; @@ -237,25 +248,24 @@ struct lfs2_config { // By default lfs2_malloc is used to allocate this buffer. void *prog_buffer; - // Optional statically allocated lookahead buffer. Must be lookahead_size - // and aligned to a 32-bit boundary. By default lfs2_malloc is used to - // allocate this buffer. + // Optional statically allocated lookahead buffer. Must be lookahead_size. + // By default lfs2_malloc is used to allocate this buffer. void *lookahead_buffer; // Optional upper limit on length of file names in bytes. No downside for // larger names except the size of the info struct which is controlled by - // the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX when zero. Stored in - // superblock and must be respected by other littlefs drivers. + // the LFS2_NAME_MAX define. Defaults to LFS2_NAME_MAX or name_max stored on + // disk when zero. lfs2_size_t name_max; // Optional upper limit on files in bytes. No downside for larger files - // but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX when zero. Stored - // in superblock and must be respected by other littlefs drivers. + // but must be <= LFS2_FILE_MAX. Defaults to LFS2_FILE_MAX or file_max stored + // on disk when zero. lfs2_size_t file_max; // Optional upper limit on custom attributes in bytes. No downside for // larger attributes size but must be <= LFS2_ATTR_MAX. Defaults to - // LFS2_ATTR_MAX when zero. + // LFS2_ATTR_MAX or attr_max stored on disk when zero. lfs2_size_t attr_max; // Optional upper limit on total space given to metadata pairs in bytes. On @@ -264,6 +274,15 @@ struct lfs2_config { // Defaults to block_size when zero. lfs2_size_t metadata_max; + // Optional upper limit on inlined files in bytes. Inlined files live in + // metadata and decrease storage requirements, but may be limited to + // improve metadata-related performance. Must be <= cache_size, <= + // attr_max, and <= block_size/8. Defaults to the largest possible + // inline_max when zero. + // + // Set to -1 to disable inlined files. + lfs2_size_t inline_max; + #ifdef LFS2_MULTIVERSION // On-disk version to use when writing in the form of 16-bit major version // + 16-bit minor version. This limiting metadata to what is supported by @@ -430,19 +449,20 @@ typedef struct lfs2 { lfs2_gstate_t gdisk; lfs2_gstate_t gdelta; - struct lfs2_free { - lfs2_block_t off; + struct lfs2_lookahead { + lfs2_block_t start; lfs2_block_t size; - lfs2_block_t i; - lfs2_block_t ack; - uint32_t *buffer; - } free; + lfs2_block_t next; + lfs2_block_t ckpoint; + uint8_t *buffer; + } lookahead; const struct lfs2_config *cfg; lfs2_size_t block_count; lfs2_size_t name_max; lfs2_size_t file_max; lfs2_size_t attr_max; + lfs2_size_t inline_max; #ifdef LFS2_MIGRATE struct lfs21 *lfs21; @@ -712,18 +732,6 @@ lfs2_ssize_t lfs2_fs_size(lfs2_t *lfs2); // Returns a negative error code on failure. int lfs2_fs_traverse(lfs2_t *lfs2, int (*cb)(void*, lfs2_block_t), void *data); -// Attempt to proactively find free blocks -// -// Calling this function is not required, but may allowing the offloading of -// the expensive block allocation scan to a less time-critical code path. -// -// Note: littlefs currently does not persist any found free blocks to disk. -// This may change in the future. -// -// Returns a negative error code on failure. Finding no free blocks is -// not an error. -int lfs2_fs_gc(lfs2_t *lfs2); - #ifndef LFS2_READONLY // Attempt to make the filesystem consistent and ready for writing // @@ -736,11 +744,33 @@ int lfs2_fs_gc(lfs2_t *lfs2); int lfs2_fs_mkconsistent(lfs2_t *lfs2); #endif +#ifndef LFS2_READONLY +// Attempt any janitorial work +// +// This currently: +// 1. Calls mkconsistent if not already consistent +// 2. Compacts metadata > compact_thresh +// 3. Populates the block allocator +// +// Though additional janitorial work may be added in the future. +// +// Calling this function is not required, but may allow the offloading of +// expensive janitorial work to a less time-critical code path. +// +// Returns a negative error code on failure. Accomplishing nothing is not +// an error. +int lfs2_fs_gc(lfs2_t *lfs2); +#endif + #ifndef LFS2_READONLY // Grows the filesystem to a new size, updating the superblock with the new // block count. // -// Note: This is irreversible. +// If LFS2_SHRINKNONRELOCATING is defined, this function will also accept +// block_counts smaller than the current configuration, after checking +// that none of the blocks that are being removed are in use. +// Note that littlefs's pseudorandom block allocation means that +// this is very unlikely to work in the general case. // // Returns a negative error code on failure. int lfs2_fs_grow(lfs2_t *lfs2, lfs2_size_t block_count); diff --git a/lib/littlefs/lfs2_util.c b/lib/littlefs/lfs2_util.c index c9850e78869..4fe7e5340ce 100644 --- a/lib/littlefs/lfs2_util.c +++ b/lib/littlefs/lfs2_util.c @@ -11,6 +11,8 @@ #ifndef LFS2_CONFIG +// If user provides their own CRC impl we don't need this +#ifndef LFS2_CRC // Software CRC implementation with small lookup table uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) { static const uint32_t rtable[16] = { @@ -29,6 +31,7 @@ uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) { return crc; } +#endif #endif diff --git a/lib/littlefs/lfs2_util.h b/lib/littlefs/lfs2_util.h index dd2cbcc106d..12c82a630b0 100644 --- a/lib/littlefs/lfs2_util.h +++ b/lib/littlefs/lfs2_util.h @@ -8,6 +8,9 @@ #ifndef LFS2_UTIL_H #define LFS2_UTIL_H +#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x) +#define LFS2_STRINGIZE2(x) #x + // Users can override lfs2_util.h with their own configuration by defining // LFS2_CONFIG as a header file to include (-DLFS2_CONFIG=lfs2_config.h). // @@ -15,11 +18,26 @@ // provided by the config file. To start, I would suggest copying lfs2_util.h // and modifying as needed. #ifdef LFS2_CONFIG -#define LFS2_STRINGIZE(x) LFS2_STRINGIZE2(x) -#define LFS2_STRINGIZE2(x) #x #include LFS2_STRINGIZE(LFS2_CONFIG) #else +// Alternatively, users can provide a header file which defines +// macros and other things consumed by littlefs. +// +// For example, provide my_defines.h, which contains +// something like: +// +// #include +// extern void *my_malloc(size_t sz); +// #define LFS2_MALLOC(sz) my_malloc(sz) +// +// And build littlefs with the header by defining LFS2_DEFINES. +// (-DLFS2_DEFINES=my_defines.h) + +#ifdef LFS2_DEFINES +#include LFS2_STRINGIZE(LFS2_DEFINES) +#endif + // System includes #include #include @@ -177,10 +195,10 @@ static inline uint32_t lfs2_fromle32(uint32_t a) { (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)) return __builtin_bswap32(a); #else - return (((uint8_t*)&a)[0] << 0) | - (((uint8_t*)&a)[1] << 8) | - (((uint8_t*)&a)[2] << 16) | - (((uint8_t*)&a)[3] << 24); + return ((uint32_t)((uint8_t*)&a)[0] << 0) | + ((uint32_t)((uint8_t*)&a)[1] << 8) | + ((uint32_t)((uint8_t*)&a)[2] << 16) | + ((uint32_t)((uint8_t*)&a)[3] << 24); #endif } @@ -200,10 +218,10 @@ static inline uint32_t lfs2_frombe32(uint32_t a) { (defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) return a; #else - return (((uint8_t*)&a)[0] << 24) | - (((uint8_t*)&a)[1] << 16) | - (((uint8_t*)&a)[2] << 8) | - (((uint8_t*)&a)[3] << 0); + return ((uint32_t)((uint8_t*)&a)[0] << 24) | + ((uint32_t)((uint8_t*)&a)[1] << 16) | + ((uint32_t)((uint8_t*)&a)[2] << 8) | + ((uint32_t)((uint8_t*)&a)[3] << 0); #endif } @@ -212,12 +230,22 @@ static inline uint32_t lfs2_tobe32(uint32_t a) { } // Calculate CRC-32 with polynomial = 0x04c11db7 +#ifdef LFS2_CRC +static inline uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size) { + return LFS2_CRC(crc, buffer, size); +} +#else uint32_t lfs2_crc(uint32_t crc, const void *buffer, size_t size); +#endif // Allocate memory, only used if buffers are not provided to littlefs -// Note, memory must be 64-bit aligned +// +// littlefs current has no alignment requirements, as it only allocates +// byte-level buffers. static inline void *lfs2_malloc(size_t size) { -#ifndef LFS2_NO_MALLOC +#if defined(LFS2_MALLOC) + return LFS2_MALLOC(size); +#elif !defined(LFS2_NO_MALLOC) return malloc(size); #else (void)size; @@ -227,7 +255,9 @@ static inline void *lfs2_malloc(size_t size) { // Deallocate memory, only used if buffers are not provided to littlefs static inline void lfs2_free(void *p) { -#ifndef LFS2_NO_MALLOC +#if defined(LFS2_FREE) + LFS2_FREE(p); +#elif !defined(LFS2_NO_MALLOC) free(p); #else (void)p; diff --git a/lib/micropython-lib b/lib/micropython-lib index 5b496e944ec..6ae440a8a14 160000 --- a/lib/micropython-lib +++ b/lib/micropython-lib @@ -1 +1 @@ -Subproject commit 5b496e944ec045177afa1620920a168410b7f60b +Subproject commit 6ae440a8a144233e6e703f6759b7e7a0afaa37a4 diff --git a/main.c b/main.c index 46b54f522b5..e1cc7e391cc 100644 --- a/main.c +++ b/main.c @@ -1202,7 +1202,7 @@ size_t gc_get_max_new_split(void) { return port_heap_get_largest_free_size(); } -void NORETURN nlr_jump_fail(void *val) { +void MP_NORETURN nlr_jump_fail(void *val) { reset_into_safe_mode(SAFE_MODE_NLR_JUMP_FAIL); while (true) { } @@ -1213,7 +1213,7 @@ bool vm_is_running(void) { } #ifndef NDEBUG -static void NORETURN __fatal_error(const char *msg) { +static void MP_NORETURN __fatal_error(const char *msg) { #if CIRCUITPY_DEBUG == 0 reset_into_safe_mode(SAFE_MODE_HARD_FAULT); #endif diff --git a/mpy-cross/main.c b/mpy-cross/main.c index 989aec68bb5..add07c3d49b 100644 --- a/mpy-cross/main.c +++ b/mpy-cross/main.c @@ -34,13 +34,19 @@ #include "py/persistentcode.h" #include "py/runtime.h" #include "py/gc.h" -#include "py/stackctrl.h" +#include "py/parsenum.h" #include "genhdr/mpversion.h" #ifdef _WIN32 // CIRCUITPY-CHANGE #include "fmode.h" #endif +#if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 +#include "py/asmrv32.h" + +static asm_rv32_backend_options_t rv32_options = { 0 }; +#endif + // Command line options, with their defaults static uint emit_opt = MP_EMIT_OPT_NONE; mp_uint_t mp_verbose_flag = 0; @@ -82,13 +88,20 @@ static int compile_and_save(const char *file, const char *output_file, const cha source_name = qstr_from_str(source_file); } - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif mp_parse_tree_t parse_tree = mp_parse(lex, MP_PARSE_FILE_INPUT); mp_compiled_module_t cm; cm.context = m_new_obj(mp_module_context_t); + cm.arch_flags = 0; + #if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_RV32IMC && mp_dynamic_compiler.backend_options != NULL) { + cm.arch_flags = ((asm_rv32_backend_options_t *)mp_dynamic_compiler.backend_options)->allowed_extensions; + } + #endif + mp_compile_to_raw_code(&parse_tree, source_name, false, &cm); if ((output_file != NULL && strcmp(output_file, "-") == 0) || @@ -131,7 +144,10 @@ static int usage(char **argv) { "Target specific options:\n" "-msmall-int-bits=number : set the maximum bits used to encode a small-int\n" "-march= : set architecture for native emitter;\n" - " x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp, armv7emdp, xtensa, xtensawin, rv32imc, debug\n" + " x86, x64, armv6, armv6m, armv7m, armv7em, armv7emsp,\n" + " armv7emdp, xtensa, xtensawin, rv32imc, rv64imc, host, debug\n" + "-march-flags= : set architecture-specific flags (can be either a dec/hex/bin value or a string)\n" + " supported flags for rv32imc: zba\n" "\n" "Implementation specific options:\n", argv[0] ); @@ -212,9 +228,39 @@ static char *backslash_to_forwardslash(char *path) { return path; } -MP_NOINLINE int main_(int argc, char **argv) { - mp_stack_set_limit(40000 * (sizeof(void *) / 4)); +// This will need to be reworked in case mpy-cross needs to set more bits than +// what its small int representation allows to fit in there. +static bool parse_integer(const char *value, mp_uint_t *integer) { + assert(value && "Attempting to parse a NULL string"); + assert(integer && "Attempting to store into a NULL integer buffer"); + + size_t value_length = strlen(value); + int base = 10; + if (value_length > 2 && value[0] == '0') { + if ((value[1] | 0x20) == 'b') { + base = 2; + } else if ((value[1] | 0x20) == 'x') { + base = 16; + } else { + return false; + } + } + + bool valid = false; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t parsed = mp_parse_num_integer(value, value_length, base, NULL); + if (mp_obj_is_small_int(parsed)) { + *integer = MP_OBJ_SMALL_INT_VALUE(parsed); + valid = true; + } + nlr_pop(); + } + return valid; +} + +MP_NOINLINE int main_(int argc, char **argv) { pre_process_options(argc, argv); char *heap = malloc(heap_size); @@ -237,11 +283,13 @@ MP_NOINLINE int main_(int argc, char **argv) { // don't support native emitter unless -march is specified mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_NONE; mp_dynamic_compiler.nlr_buf_num_regs = 0; + mp_dynamic_compiler.backend_options = NULL; const char *input_file = NULL; const char *output_file = NULL; const char *source_file = NULL; bool option_parsing_active = true; + const char *arch_flags = NULL; // parse main options for (int a = 1; a < argc; a++) { @@ -318,6 +366,9 @@ MP_NOINLINE int main_(int argc, char **argv) { } else if (strcmp(arch, "rv32imc") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_RV32IMC; mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_RV32I; + } else if (strcmp(arch, "rv64imc") == 0) { + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_RV64IMC; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_RV64I; } else if (strcmp(arch, "debug") == 0) { mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_DEBUG; mp_dynamic_compiler.nlr_buf_num_regs = 0; @@ -331,6 +382,9 @@ MP_NOINLINE int main_(int argc, char **argv) { #elif defined(__arm__) && !defined(__thumb2__) mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_ARMV6; mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_ARM_THUMB_FP; + #elif defined(__riscv) && (__riscv_xlen == 64) + mp_dynamic_compiler.native_arch = MP_NATIVE_ARCH_RV64IMC; + mp_dynamic_compiler.nlr_buf_num_regs = MICROPY_NLR_NUM_REGS_RV64I; #else mp_printf(&mp_stderr_print, "unable to determine host architecture for -march=host\n"); exit(1); @@ -338,6 +392,8 @@ MP_NOINLINE int main_(int argc, char **argv) { } else { return usage(argv); } + } else if (strncmp(argv[a], "-march-flags=", sizeof("-march-flags=") - 1) == 0) { + arch_flags = argv[a] + sizeof("-march-flags=") - 1; } else if (strcmp(argv[a], "--") == 0) { option_parsing_active = false; } else { @@ -352,6 +408,38 @@ MP_NOINLINE int main_(int argc, char **argv) { } } + if (arch_flags && mp_dynamic_compiler.native_arch != MP_NATIVE_ARCH_NONE) { + bool processed = false; + #if MICROPY_EMIT_NATIVE && MICROPY_EMIT_RV32 + if (mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_RV32IMC) { + mp_dynamic_compiler.backend_options = (void *)&rv32_options; + mp_uint_t raw_flags = 0; + if (parse_integer(arch_flags, &raw_flags)) { + if ((raw_flags & ~((mp_uint_t)RV32_EXT_ALL)) == 0) { + rv32_options.allowed_extensions = raw_flags; + processed = true; + } + } else if (strncmp(arch_flags, "zba", sizeof("zba") - 1) == 0) { + rv32_options.allowed_extensions |= RV32_EXT_ZBA; + processed = true; + } + } + #endif + if (!processed) { + mp_printf(&mp_stderr_print, "unrecognised arch flags\n"); + exit(1); + } + } + + #if MICROPY_EMIT_NATIVE + if ((MP_STATE_VM(default_emit_opt) == MP_EMIT_OPT_NATIVE_PYTHON + || MP_STATE_VM(default_emit_opt) == MP_EMIT_OPT_VIPER) + && mp_dynamic_compiler.native_arch == MP_NATIVE_ARCH_NONE) { + mp_printf(&mp_stderr_print, "arch not specified\n"); + exit(1); + } + #endif + if (input_file == NULL) { mp_printf(&mp_stderr_print, "no input file\n"); exit(1); @@ -371,7 +459,7 @@ MP_NOINLINE int main_(int argc, char **argv) { } int main(int argc, char **argv) { - mp_stack_ctrl_init(); + mp_cstack_init_with_sp_here(40000 * (sizeof(void *) / 4)); return main_(argc, argv); } diff --git a/mpy-cross/mpconfigport.h b/mpy-cross/mpconfigport.h index edbd9f87c05..36bcbc11394 100644 --- a/mpy-cross/mpconfigport.h +++ b/mpy-cross/mpconfigport.h @@ -59,6 +59,7 @@ #define MICROPY_COMP_CONST_FOLDING (1) #define MICROPY_COMP_MODULE_CONST (1) #define MICROPY_COMP_CONST (1) +#define MICROPY_COMP_CONST_FLOAT (1) #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) #define MICROPY_COMP_TRIPLE_TUPLE_ASSIGN (1) #define MICROPY_COMP_RETURN_IF_EXPR (1) @@ -90,11 +91,12 @@ #define MICROPY_GCREGS_SETJMP (1) #endif -#define MICROPY_PY___FILE__ (0) +#define MICROPY_MODULE___FILE__ (0) #define MICROPY_PY_ARRAY (0) #define MICROPY_PY_ATTRTUPLE (0) #define MICROPY_PY_COLLECTIONS (0) -#define MICROPY_PY_MATH (0) +#define MICROPY_PY_MATH (MICROPY_COMP_CONST_FLOAT) +#define MICROPY_PY_MATH_CONSTANTS (MICROPY_COMP_CONST_FLOAT) #define MICROPY_PY_CMATH (0) #define MICROPY_PY_GC (0) #define MICROPY_PY_IO (0) @@ -102,23 +104,6 @@ // type definitions for the specific machine -#ifdef __LP64__ -typedef long mp_int_t; // must be pointer size -typedef unsigned long mp_uint_t; // must be pointer size -#elif defined(__MINGW32__) && defined(_WIN64) -#include -typedef __int64 mp_int_t; -typedef unsigned __int64 mp_uint_t; -#elif defined(_MSC_VER) && defined(_WIN64) -typedef __int64 mp_int_t; -typedef unsigned __int64 mp_uint_t; -#else -// These are definitions for machines where sizeof(int) == sizeof(void*), -// regardless for actual size. -typedef int mp_int_t; // must be pointer size -typedef unsigned int mp_uint_t; // must be pointer size -#endif - // Cannot include , as it may lead to symbol name clashes #if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) typedef long long mp_off_t; @@ -143,7 +128,7 @@ typedef long mp_off_t; #ifdef _MSC_VER #define MP_ENDIANNESS_LITTLE (1) -#define NORETURN __declspec(noreturn) +#define MP_NORETURN __declspec(noreturn) #define MP_NOINLINE __declspec(noinline) #define MP_ALWAYSINLINE __forceinline #define MP_LIKELY(x) (x) diff --git a/mpy-cross/mpy_cross/__init__.py b/mpy-cross/mpy_cross/__init__.py index 91cd6f99335..6d7002a3b89 100644 --- a/mpy-cross/mpy_cross/__init__.py +++ b/mpy-cross/mpy_cross/__init__.py @@ -25,7 +25,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from __future__ import print_function import os import re import stat @@ -44,6 +43,7 @@ "NATIVE_ARCH_XTENSA": "xtensa", "NATIVE_ARCH_XTENSAWIN": "xtensawin", "NATIVE_ARCH_RV32IMC": "rv32imc", + "NATIVE_ARCH_RV64IMC": "rv64imc", } globals().update(NATIVE_ARCHS) diff --git a/mpy-cross/mpy_cross/__main__.py b/mpy-cross/mpy_cross/__main__.py index 2b6b81c3333..fe78a9e077e 100644 --- a/mpy-cross/mpy_cross/__main__.py +++ b/mpy-cross/mpy_cross/__main__.py @@ -25,7 +25,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from __future__ import print_function import argparse import sys diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index 86d96bc251b..ee410a38148 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -67,7 +67,7 @@ static uint32_t subsec, sec = 0; static uint32_t tick_flag = 0; // defined by cmsis core files -extern void NVIC_SystemReset(void) NORETURN; +extern void NVIC_SystemReset(void) MP_NORETURN; volatile uint32_t system_ticks = 0; diff --git a/ports/atmel-samd/common-hal/alarm/__init__.c b/ports/atmel-samd/common-hal/alarm/__init__.c index 483aa1a9679..38ef58bea76 100644 --- a/ports/atmel-samd/common-hal/alarm/__init__.c +++ b/ports/atmel-samd/common-hal/alarm/__init__.c @@ -133,7 +133,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_time_timealarm_prepare_for_deep_sleep(); // port_disable_tick(); // TODO: Required for SAMD? diff --git a/ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c b/ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c index 3c1fbb5ba7b..de98b7ec85a 100644 --- a/ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c +++ b/ports/atmel-samd/common-hal/alarm/touch/TouchAlarm.c @@ -7,6 +7,6 @@ #include "shared-bindings/alarm/touch/TouchAlarm.h" #include "shared-bindings/microcontroller/__init__.h" -NORETURN void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin) { +MP_NORETURN void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_TouchAlarm); } diff --git a/ports/atmel-samd/reset.c b/ports/atmel-samd/reset.c index 9cacd4ab951..816e23e3251 100644 --- a/ports/atmel-samd/reset.c +++ b/ports/atmel-samd/reset.c @@ -9,7 +9,7 @@ #include "reset.h" #include "supervisor/filesystem.h" -void NVIC_SystemReset(void) NORETURN; +void NVIC_SystemReset(void) MP_NORETURN; void reset(void) { filesystem_flush(); diff --git a/ports/atmel-samd/reset.h b/ports/atmel-samd/reset.h index c74d25fa01e..248d43779fd 100644 --- a/ports/atmel-samd/reset.h +++ b/ports/atmel-samd/reset.h @@ -16,6 +16,6 @@ extern uint32_t _bootloader_dbl_tap; -void reset_to_bootloader(void) NORETURN; -void reset(void) NORETURN; +void reset_to_bootloader(void) MP_NORETURN; +void reset(void) MP_NORETURN; bool bootloader_available(void); diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 31bc5faf827..83c8e295d26 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -687,7 +687,7 @@ void port_idle_until_interrupt(void) { /** * \brief Default interrupt handler for unused IRQs. */ -__attribute__((used)) NORETURN void HardFault_Handler(void) { +__attribute__((used)) MP_NORETURN void HardFault_Handler(void) { #ifdef ENABLE_MICRO_TRACE_BUFFER // Turn off the micro trace buffer so we don't fill it up in the infinite // loop below. diff --git a/ports/espressif/bindings/espidf/__init__.c b/ports/espressif/bindings/espidf/__init__.c index 012ed7d9f9a..897da0eb571 100644 --- a/ports/espressif/bindings/espidf/__init__.c +++ b/ports/espressif/bindings/espidf/__init__.c @@ -106,7 +106,7 @@ MP_DEFINE_CONST_OBJ_TYPE( //| ... //| //| -NORETURN void mp_raise_espidf_MemoryError(void) { +MP_NORETURN void mp_raise_espidf_MemoryError(void) { nlr_raise(mp_obj_new_exception(&mp_type_espidf_MemoryError)); } diff --git a/ports/espressif/bindings/espidf/__init__.h b/ports/espressif/bindings/espidf/__init__.h index 7c112abf736..92d2e0c2769 100644 --- a/ports/espressif/bindings/espidf/__init__.h +++ b/ports/espressif/bindings/espidf/__init__.h @@ -15,9 +15,9 @@ extern const mp_obj_type_t mp_type_espidf_IDFError; extern const mp_obj_type_t mp_type_espidf_MemoryError; -NORETURN void mp_raise_espidf_MemoryError(void); +MP_NORETURN void mp_raise_espidf_MemoryError(void); -void raise_esp_error(esp_err_t err) NORETURN; +void raise_esp_error(esp_err_t err) MP_NORETURN; #define CHECK_ESP_RESULT(x) do { int res = (x); if (res != ESP_OK) raise_esp_error(res); } while (0) size_t common_hal_espidf_get_total_psram(void); diff --git a/ports/espressif/common-hal/alarm/__init__.c b/ports/espressif/common-hal/alarm/__init__.c index 629f976039f..4f8e7e53042 100644 --- a/ports/espressif/common-hal/alarm/__init__.c +++ b/ports/espressif/common-hal/alarm/__init__.c @@ -189,7 +189,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_pin_pinalarm_prepare_for_deep_sleep(); #if CIRCUITPY_ALARM_TOUCH alarm_touch_touchalarm_prepare_for_deep_sleep(); diff --git a/ports/espressif/common-hal/microcontroller/__init__.c b/ports/espressif/common-hal/microcontroller/__init__.c index d23afce4d99..9b50cd7b5d2 100644 --- a/ports/espressif/common-hal/microcontroller/__init__.c +++ b/ports/espressif/common-hal/microcontroller/__init__.c @@ -142,7 +142,7 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { } } -void NORETURN common_hal_mcu_reset(void) { +void MP_NORETURN common_hal_mcu_reset(void) { filesystem_flush(); // TODO: implement as part of flash improvements esp_restart(); } diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 192a9171716..53564c05bf6 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -103,7 +103,7 @@ static esp_timer_handle_t _sleep_timer; TaskHandle_t circuitpython_task = NULL; -extern void esp_restart(void) NORETURN; +extern void esp_restart(void) MP_NORETURN; static void tick_on_cp_core(void *arg) { supervisor_tick(); diff --git a/ports/mimxrt10xx/reset.h b/ports/mimxrt10xx/reset.h index 04c951221e9..cae838556bc 100644 --- a/ports/mimxrt10xx/reset.h +++ b/ports/mimxrt10xx/reset.h @@ -16,6 +16,6 @@ #define DBL_TAP_MAGIC 0xf01669ef // Randomly selected, adjusted to have first and last bit set #define DBL_TAP_MAGIC_QUICK_BOOT 0xf02669ef -void reset_to_bootloader(void) NORETURN; -void reset(void) NORETURN; +void reset_to_bootloader(void) MP_NORETURN; +void reset(void) MP_NORETURN; bool bootloader_available(void); diff --git a/ports/nordic/common-hal/alarm/__init__.c b/ports/nordic/common-hal/alarm/__init__.c index 9753b0321fd..026e117b9a6 100644 --- a/ports/nordic/common-hal/alarm/__init__.c +++ b/ports/nordic/common-hal/alarm/__init__.c @@ -240,7 +240,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala #define PRESCALER_VALUE_IN_DEEP_SLEEP (1024) -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_time_timealarm_prepare_for_deep_sleep(); diff --git a/ports/raspberrypi/common-hal/alarm/__init__.c b/ports/raspberrypi/common-hal/alarm/__init__.c index c47ddc31505..a72b3a368d4 100644 --- a/ports/raspberrypi/common-hal/alarm/__init__.c +++ b/ports/raspberrypi/common-hal/alarm/__init__.c @@ -197,7 +197,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { bool timealarm_set = alarm_time_timealarm_is_set(); #if CIRCUITPY_CYW43 diff --git a/ports/raspberrypi/common-hal/wifi/Radio.c b/ports/raspberrypi/common-hal/wifi/Radio.c index 3c22c3548d1..73e7794ecc2 100644 --- a/ports/raspberrypi/common-hal/wifi/Radio.c +++ b/ports/raspberrypi/common-hal/wifi/Radio.c @@ -48,7 +48,7 @@ static inline void nw_put_le32(uint8_t *buf, uint32_t x) { buf[3] = x >> 24; } -NORETURN static void ro_attribute(qstr attr) { +MP_NORETURN static void ro_attribute(qstr attr) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q is read-only for this board"), attr); } diff --git a/ports/raspberrypi/common-hal/wifi/__init__.h b/ports/raspberrypi/common-hal/wifi/__init__.h index 73988e84379..4005c48a3cd 100644 --- a/ports/raspberrypi/common-hal/wifi/__init__.h +++ b/ports/raspberrypi/common-hal/wifi/__init__.h @@ -11,7 +11,7 @@ #include "lwip/ip_addr.h" void wifi_reset(void); -NORETURN void raise_cyw_error(int err); +MP_NORETURN void raise_cyw_error(int err); #define CHECK_CYW_RESULT(x) do { int res = (x); if (res != 0) raise_cyw_error(res); } while (0) void ipaddress_ipaddress_to_lwip(mp_obj_t ip_address, ip_addr_t *lwip_ip_address); diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 5cfbdfa66a3..aadcd56dde1 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -588,7 +588,7 @@ void port_idle_until_interrupt(void) { /** * \brief Default interrupt handler for unused IRQs. */ -extern NORETURN void isr_hardfault(void); // provide a prototype to avoid a missing-prototypes diagnostic +extern MP_NORETURN void isr_hardfault(void); // provide a prototype to avoid a missing-prototypes diagnostic __attribute__((used)) void __not_in_flash_func(isr_hardfault)(void) { // Only safe mode from core 0 which is running CircuitPython. Core 1 faulting // should not be fatal to CP. (Fingers crossed.) diff --git a/ports/stm/common-hal/alarm/__init__.c b/ports/stm/common-hal/alarm/__init__.c index 3d6c4466882..1be8f8dc10d 100644 --- a/ports/stm/common-hal/alarm/__init__.c +++ b/ports/stm/common-hal/alarm/__init__.c @@ -135,7 +135,7 @@ void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *ala _setup_sleep_alarms(true, n_alarms, alarms); } -void NORETURN common_hal_alarm_enter_deep_sleep(void) { +void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { alarm_set_wakeup_reason(STM_WAKEUP_UNDEF); alarm_pin_pinalarm_prepare_for_deep_sleep(); alarm_time_timealarm_prepare_for_deep_sleep(); diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 3820a046fc4..1ffc8656a88 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -39,7 +39,7 @@ #include STM32_HAL_H -void NVIC_SystemReset(void) NORETURN; +void NVIC_SystemReset(void) MP_NORETURN; #if (CPY_STM32H7) || (CPY_STM32F7) #if defined(CIRCUITPY_HW_SDRAM_SIZE) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 6461c310eeb..8be34feed3c 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -27,6 +27,9 @@ FROZEN_MANIFEST ?= variants/manifest.py # This should be configured by the mpconfigvariant.mk PROG ?= micropython +# For use in test rules below +ABS_PROG = $(abspath $(BUILD)/$(PROG)) + # qstr definitions (must come before including py.mk) QSTR_DEFS += qstrdefsport.h QSTR_GLOBAL_DEPENDENCIES += $(VARIANT_DIR)/mpconfigvariant.h @@ -46,13 +49,18 @@ INC += -I$(BUILD) # compiler settings CWARN = -Wall -Werror -CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -Wno-missing-field-initializers +// CIRCUITPY-CHANGE: add -Wno-missing-field-initializers +CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) # Force the use of 64-bits for file sizes in C library functions on 32-bit platforms. # This option has no effect on 64-bit builds. CFLAGS += -D_FILE_OFFSET_BITS=64 +# Force the use of 64-bits for time_t in C library functions on 32-bit platforms. +# This option has no effect on 64-bit builds. +CFLAGS += -D_TIME_BITS=64 + # Debugging/Optimization ifdef DEBUG COPT ?= -Og @@ -139,7 +147,11 @@ ifeq ($(MICROPY_PY_SOCKET),1) CFLAGS += -DMICROPY_PY_SOCKET=1 endif ifeq ($(MICROPY_PY_THREAD),1) +ifeq ($(MICROPY_PY_THREAD_GIL),1) +CFLAGS += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=1 +else CFLAGS += -DMICROPY_PY_THREAD=1 -DMICROPY_PY_THREAD_GIL=0 +endif LDFLAGS += $(LIBPTHREAD) endif @@ -198,7 +210,6 @@ ifeq ($(MICROPY_PY_JNI),1) CFLAGS += -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1 endif -# CIRCUITPY-CHANGE: CircuitPython-specific files. # source files SRC_C += \ main.c \ @@ -208,13 +219,15 @@ SRC_C += \ input.c \ alloc.c \ fatfs_port.c \ - shared-module/os/__init__.c \ - supervisor/shared/settings.c \ - supervisor/stub/filesystem.c \ - supervisor/stub/safe_mode.c \ - supervisor/stub/stack.c \ - supervisor/shared/translate/translate.c \ - $(SRC_MOD) \ + mpbthciport.c \ + mpbtstackport_common.c \ + mpbtstackport_h4.c \ + mpbtstackport_usb.c \ + mpnimbleport.c \ + modtermios.c \ + modsocket.c \ + modffi.c \ + modjni.c \ $(wildcard $(VARIANT_DIR)/*.c) # CIRCUITPY-CHANGE @@ -225,6 +238,7 @@ $(BUILD)/supervisor/shared/translate/translate.o: $(HEADER_BUILD)/qstrdefs.gener SHARED_SRC_C += $(addprefix shared/,\ runtime/gchelper_generic.c \ + runtime/pyexec.c \ timeutils/timeutils.c \ $(SHARED_SRC_C_EXTRA) \ ) @@ -280,7 +294,7 @@ print-failures clean-failures: TEST_ARGS ?= test: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py $(eval DIRNAME=ports/$(notdir $(CURDIR))) - cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py $(TEST_ARGS) + cd $(TOP)/tests && MICROPY_MICROPYTHON=../$(DIRNAME)/$(BUILD)/$(PROG) ./run-tests.py test_full: $(BUILD)/$(PROG) $(TOP)/tests/run-tests.py $(eval DIRNAME=ports/$(notdir $(CURDIR))) diff --git a/ports/unix/README.md b/ports/unix/README.md index b7aa6e3fef7..ee983a882cc 100644 --- a/ports/unix/README.md +++ b/ports/unix/README.md @@ -72,6 +72,14 @@ To run the complete testsuite, use: $ make test +There are other make targets to interact with the testsuite: + + $ make test//int # Run all tests matching the pattern "int" + $ make test/ports/unix # Run all tests in ports/unix + $ make test-failures # Re-run only the failed tests + $ make print-failures # print the differences for failed tests + $ make clean-failures # delete the .exp and .out files from failed tests + The Unix port comes with a built-in package manager called `mip`, e.g.: $ ./build-standard/micropython -m mip install hmac @@ -155,3 +163,21 @@ The default compiler optimisation level is -Os, or -Og if `DEBUG=1` is set. Setting the variable `COPT` will explicitly set the optimisation level. For example `make [other arguments] COPT=-O0 DEBUG=1` will build a binary with no optimisations, assertions enabled, and debug symbols. + +### Sanitizers + +Sanitizers are extra runtime checks supported by gcc and clang. The CI process +supports building with the "undefined behavior" (UBSan) or "address" (ASan) +sanitizers. The script `tools/ci.sh` is the source of truth about how to build +and run in these modes. + +Several classes of checks are disabled via compiler flags: + +* In the undefined behavior sanitizer, checks based on the presence of the + `non_null` attribute are disabled because the code makes technically incorrect + calls like `memset(NULL, 0, 0)`. A future C standard is likely to permit such + calls. +* In the address sanitizer, `detect_stack_use_after_return` is disabled. This + check is intended to make sure locals in a "returned from" stack frame are not + used. However, this mode interferes with various assumptions that + MicroPython's stack checking, NLR, and GC rely on. diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index 7f13f9756f1..ba20dba3595 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -97,6 +97,7 @@ static const mp_rom_map_elem_t rawfile_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) }, { MP_ROM_QSTR(MP_QSTR_write1), MP_ROM_PTR(&mp_stream_write1_obj) }, { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) }, + { MP_ROM_QSTR(MP_QSTR_readinto1), MP_ROM_PTR(&mp_stream_readinto1_obj) }, { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) }, { MP_ROM_QSTR(MP_QSTR_ioctl), MP_ROM_PTR(&mp_stream_ioctl_obj) }, }; @@ -171,19 +172,31 @@ static void pairheap_test(size_t nops, int *ops) { if (mp_pairheap_is_empty(pairheap_lt, heap)) { mp_printf(&mp_plat_print, " -"); } else { - mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]); + mp_printf(&mp_plat_print, " %d", (int)(mp_pairheap_peek(pairheap_lt, heap) - &node[0])); ; } } mp_printf(&mp_plat_print, "\npop all:"); while (!mp_pairheap_is_empty(pairheap_lt, heap)) { - mp_printf(&mp_plat_print, " %d", mp_pairheap_peek(pairheap_lt, heap) - &node[0]); + mp_printf(&mp_plat_print, " %d", (int)(mp_pairheap_peek(pairheap_lt, heap) - &node[0])); ; heap = mp_pairheap_pop(pairheap_lt, heap); } mp_printf(&mp_plat_print, "\n"); } +static mp_sched_node_t mp_coverage_sched_node; +static bool coverage_sched_function_continue; + +static void coverage_sched_function(mp_sched_node_t *node) { + (void)node; + mp_printf(&mp_plat_print, "scheduled function\n"); + if (coverage_sched_function_continue) { + // Re-scheduling node will cause it to run again next time scheduled functions are run + mp_sched_schedule_node(&mp_coverage_sched_node, coverage_sched_function); + } +} + // function to run extra tests for things that can't be checked by scripts static mp_obj_t extra_coverage(void) { // mp_printf (used by ports that don't have a native printf) @@ -191,10 +204,22 @@ static mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# mp_printf\n"); mp_printf(&mp_plat_print, "%d %+d % d\n", -123, 123, 123); // sign mp_printf(&mp_plat_print, "%05d\n", -123); // negative number with zero padding - mp_printf(&mp_plat_print, "%ld\n", 123); // long - mp_printf(&mp_plat_print, "%lx\n", 0x123); // long hex - mp_printf(&mp_plat_print, "%X\n", 0x1abcdef); // capital hex - mp_printf(&mp_plat_print, "%.2s %.3s '%4.4s' '%5.5q' '%.3q'\n", "abc", "abc", "abc", MP_QSTR_True, MP_QSTR_True); // fixed string precision + mp_printf(&mp_plat_print, "%ld\n", 123l); // long + mp_printf(&mp_plat_print, "%lx\n", 0x123fl); // long hex + mp_printf(&mp_plat_print, "%lX\n", 0x123fl); // capital long hex + if (sizeof(mp_int_t) == 8) { + mp_printf(&mp_plat_print, "%llx\n", LLONG_MAX); // long long hex + mp_printf(&mp_plat_print, "%llX\n", LLONG_MAX); // capital long long hex + mp_printf(&mp_plat_print, "%llu\n", ULLONG_MAX); // unsigned long long + } else { + // fake for platforms without narrower mp_int_t + mp_printf(&mp_plat_print, "7fffffffffffffff\n"); + mp_printf(&mp_plat_print, "7FFFFFFFFFFFFFFF\n"); + mp_printf(&mp_plat_print, "18446744073709551615\n"); + } + mp_printf(&mp_plat_print, "%p\n", (void *)0x789f); // pointer + mp_printf(&mp_plat_print, "%P\n", (void *)0x789f); // pointer uppercase + mp_printf(&mp_plat_print, "%.2s %.3s '%4.4s' '%5.5q' '%.3q'\n", "abc", "abc", "abc", (qstr)MP_QSTR_True, (qstr)MP_QSTR_True); // fixed string precision mp_printf(&mp_plat_print, "%.*s\n", -1, "abc"); // negative string precision mp_printf(&mp_plat_print, "%b %b\n", 0, 1); // bools #ifndef NDEBUG @@ -204,10 +229,36 @@ static mp_obj_t extra_coverage(void) { #endif mp_printf(&mp_plat_print, "%d\n", 0x80000000); // should print signed mp_printf(&mp_plat_print, "%u\n", 0x80000000); // should print unsigned - mp_printf(&mp_plat_print, "%x\n", 0x80000000); // should print unsigned - mp_printf(&mp_plat_print, "%X\n", 0x80000000); // should print unsigned - mp_printf(&mp_plat_print, "abc\n%"); // string ends in middle of format specifier + mp_printf(&mp_plat_print, "%x\n", 0x8000000f); // should print unsigned + mp_printf(&mp_plat_print, "%X\n", 0x8000000f); // should print unsigned + // note: storing the string in a variable is enough to prevent the + // format string checker from checking this format string. Otherwise, + // it would be a compile time diagnostic under the format string + // checker. + const char msg[] = "abc\n%"; + mp_printf(&mp_plat_print, msg); // string ends in middle of format specifier mp_printf(&mp_plat_print, "%%\n"); // literal % character + mp_printf(&mp_plat_print, ".%-3s.\n", "a"); // left adjust + + // Check that all kinds of mp_printf arguments are parsed out + // correctly, by having a char argument before and after each main type + // of value that can be formatted. + mp_printf(&mp_plat_print, "%c%%%c\n", '<', '>'); + mp_printf(&mp_plat_print, "%c%p%c\n", '<', (void *)0xaaaa, '>'); + mp_printf(&mp_plat_print, "%c%b%c\n", '<', true, '>'); + mp_printf(&mp_plat_print, "%c%d%c\n", '<', 0xaaaa, '>'); + mp_printf(&mp_plat_print, "%c%ld%c\n", '<', 0xaaaal, '>'); + mp_printf(&mp_plat_print, "%c" INT_FMT "%c\n", '<', (mp_int_t)0xaaaa, '>'); + mp_printf(&mp_plat_print, "%c%s%c\n", '<', "test", '>'); + mp_printf(&mp_plat_print, "%c%f%c\n", '<', MICROPY_FLOAT_CONST(1000.), '>'); + mp_printf(&mp_plat_print, "%c%q%c\n", '<', (qstr)MP_QSTR_True, '>'); + if (sizeof(mp_int_t) == 8) { + mp_printf(&mp_plat_print, "%c%lld%c\n", '<', LLONG_MAX, '>'); + } else { + mp_printf(&mp_plat_print, "<9223372036854775807>\n"); + } + + } // GC @@ -220,11 +271,11 @@ 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, 0); mp_printf(&mp_plat_print, "%p\n", gc_realloc(p, 0, false)); // calling gc_nbytes with a non-heap pointer - mp_printf(&mp_plat_print, "%p\n", gc_nbytes(NULL)); + mp_printf(&mp_plat_print, "%d\n", (int)gc_nbytes(NULL)); } // GC initialisation and allocation stress test, to check the logic behind ALLOC_TABLE_GAP_BYTE @@ -285,7 +336,7 @@ static mp_obj_t extra_coverage(void) { } ptrs[i][j] = j; } - mp_printf(&mp_plat_print, "%d %d\n", i, all_zero); + mp_printf(&mp_plat_print, "%d %d\n", (int)i, (int)all_zero); // hide the pointer from the GC and collect ptrs[i] = FLIP_POINTER(ptrs[i]); @@ -301,7 +352,7 @@ static mp_obj_t extra_coverage(void) { break; } } - mp_printf(&mp_plat_print, "%d %d\n", i, correct_contents); + mp_printf(&mp_plat_print, "%d %d\n", (int)i, (int)correct_contents); } // free the memory blocks @@ -400,7 +451,7 @@ static mp_obj_t extra_coverage(void) { // create a bytearray via mp_obj_new_bytearray mp_buffer_info_t bufinfo; mp_get_buffer_raise(mp_obj_new_bytearray(4, "data"), &bufinfo, MP_BUFFER_RW); - mp_printf(&mp_plat_print, "%.*s\n", bufinfo.len, bufinfo.buf); + mp_printf(&mp_plat_print, "%.*s\n", (int)bufinfo.len, bufinfo.buf); } // mpz @@ -464,6 +515,38 @@ static mp_obj_t extra_coverage(void) { mp_int_t value_signed; mpz_as_int_checked(&mpz, &value_signed); mp_printf(&mp_plat_print, "%d\n", (int)value_signed); + + // hash the zero mpz integer + mpz_set_from_int(&mpz, 0); + mp_printf(&mp_plat_print, "%d\n", (int)mpz_hash(&mpz)); + + // convert the mpz zero integer to int + mp_printf(&mp_plat_print, "%d\n", mpz_as_int_checked(&mpz, &value_signed)); + mp_printf(&mp_plat_print, "%d\n", (int)value_signed); + + // mpz_set_from_float with 0 as argument + mpz_set_from_float(&mpz, 0); + mp_printf(&mp_plat_print, "%f\n", mpz_as_float(&mpz)); + + // convert a large integer value (stored in a mpz) to mp_uint_t and to ll; + mp_obj_t obj_bigint = mp_obj_new_int_from_uint((mp_uint_t)0xdeadbeef); + mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint)); + obj_bigint = mp_obj_new_int_from_ll(0xc0ffee777c0ffeell); + long long value_ll = mp_obj_get_ll(obj_bigint); + mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); + + // convert a large integer value (stored via a struct object) to uint and to ll + // `deadbeef` global is an uctypes.struct defined by extra_coverage.py + obj_bigint = mp_load_global(MP_QSTR_deadbeef); + mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint)); + value_ll = mp_obj_get_ll(obj_bigint); + mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); + + // convert a smaller integer value to mp_uint_t and to ll + obj_bigint = mp_obj_new_int_from_uint(0xc0ffee); + mp_printf(&mp_plat_print, "%x\n", (int)mp_obj_get_uint(obj_bigint)); + value_ll = mp_obj_get_ll(obj_bigint); + mp_printf(&mp_plat_print, "%x%08x\n", (uint32_t)(value_ll >> 32), (uint32_t)value_ll); } // runtime utils @@ -481,7 +564,7 @@ static mp_obj_t extra_coverage(void) { mp_call_function_2_protected(MP_OBJ_FROM_PTR(&mp_builtin_divmod_obj), mp_obj_new_str_from_cstr("abc"), mp_obj_new_str_from_cstr("abc")); // mp_obj_int_get_checked with mp_obj_int_t that has a value that is a small integer - mp_printf(&mp_plat_print, "%d\n", mp_obj_int_get_checked(mp_obj_int_new_mpz())); + mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_checked(MP_OBJ_FROM_PTR(mp_obj_int_new_mpz()))); // mp_obj_int_get_uint_checked with non-negative small-int mp_printf(&mp_plat_print, "%d\n", (int)mp_obj_int_get_uint_checked(MP_OBJ_NEW_SMALL_INT(1))); @@ -636,36 +719,36 @@ static mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# ringbuf\n"); // Single-byte put/get with empty ringbuf. - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_free(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); ringbuf_put(&ringbuf, 22); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_get(&ringbuf)); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); // Two-byte put/get with empty ringbuf. ringbuf_put16(&ringbuf, 0xaa55); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); // Two-byte put with full ringbuf. for (int i = 0; i < RINGBUF_SIZE; ++i) { ringbuf_put(&ringbuf, i); } - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x11bb)); // Two-byte put with one byte free. ringbuf_get(&ringbuf); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0x3377)); ringbuf_get(&ringbuf); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_put16(&ringbuf, 0xcc99)); for (int i = 0; i < RINGBUF_SIZE - 2; ++i) { ringbuf_get(&ringbuf); } mp_printf(&mp_plat_print, "%04x\n", ringbuf_get16(&ringbuf)); - mp_printf(&mp_plat_print, "%d %d\n", ringbuf_num_empty(&ringbuf), ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); // Two-byte put with wrap around on first byte: ringbuf_clear(&ringbuf); @@ -777,7 +860,7 @@ static mp_obj_t extra_coverage(void) { mp_obj_streamtest_t *s2 = mp_obj_malloc(mp_obj_streamtest_t, &mp_type_stest_textio2); // return a tuple of data for testing on the Python side - mp_obj_t items[] = {(mp_obj_t)&str_no_hash_obj, (mp_obj_t)&bytes_no_hash_obj, MP_OBJ_FROM_PTR(s), MP_OBJ_FROM_PTR(s2)}; + mp_obj_t items[] = {MP_OBJ_FROM_PTR(&str_no_hash_obj), MP_OBJ_FROM_PTR(&bytes_no_hash_obj), MP_OBJ_FROM_PTR(s), MP_OBJ_FROM_PTR(s2)}; return mp_obj_new_tuple(MP_ARRAY_SIZE(items), items); } MP_DEFINE_CONST_FUN_OBJ_0(extra_coverage_obj, extra_coverage); diff --git a/ports/unix/coveragecpp.cpp b/ports/unix/coveragecpp.cpp index 377b5acf763..4d21398142d 100644 --- a/ports/unix/coveragecpp.cpp +++ b/ports/unix/coveragecpp.cpp @@ -3,10 +3,61 @@ extern "C" { #include "py/obj.h" } +// Invoke all (except one, see below) public API macros which initialize structs to make sure +// they are C++-compatible, meaning they explicitly initialize all struct members. +mp_obj_t f0(); +MP_DEFINE_CONST_FUN_OBJ_0(f0_obj, f0); +mp_obj_t f1(mp_obj_t); +MP_DEFINE_CONST_FUN_OBJ_1(f1_obj, f1); +mp_obj_t f2(mp_obj_t, mp_obj_t); +MP_DEFINE_CONST_FUN_OBJ_2(f2_obj, f2); +mp_obj_t f3(mp_obj_t, mp_obj_t, mp_obj_t); +MP_DEFINE_CONST_FUN_OBJ_3(f3_obj, f3); +mp_obj_t fvar(size_t, const mp_obj_t *); +MP_DEFINE_CONST_FUN_OBJ_VAR(fvar_obj, 1, fvar); +mp_obj_t fvarbetween(size_t, const mp_obj_t *); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fvarbetween_obj, 1, 2, fvarbetween); +mp_obj_t fkw(size_t, const mp_obj_t *, mp_map_t *); +MP_DEFINE_CONST_FUN_OBJ_KW(fkw_obj, 1, fkw); + +static const mp_rom_map_elem_t table[] = { + { MP_ROM_QSTR(MP_QSTR_f0), MP_ROM_PTR(&f0_obj) }, +}; +MP_DEFINE_CONST_MAP(map, table); +MP_DEFINE_CONST_DICT(dict, table); + +static const qstr attrtuple_fields[] = { + MP_QSTR_f0, +}; +MP_DEFINE_ATTRTUPLE(attrtuple, attrtuple_fields, 1, MP_ROM_PTR(&f0_obj)); + +void nlr_cb(void *); +void nlr_cb(void *){ +} + +// The MP_DEFINE_CONST_OBJ_TYPE macro is not C++-compatible because each of the +// MP_DEFINE_CONST_OBJ_TYPE_NARGS_X macros only initializes some of _mp_obj_type_t's +// .slot_index_xxx members but that cannot be fixed to be done in a deterministic way. + + #if defined(MICROPY_UNIX_COVERAGE) // Just to test building of C++ code. static mp_obj_t extra_cpp_coverage_impl() { + MP_DEFINE_NLR_JUMP_CALLBACK_FUNCTION_1(ctx, nlr_cb, (void *) nlr_cb); + + // To avoid 'error: unused variable [-Werror,-Wunused-const-variable]'. + (void) ctx; + (void) f0_obj; + (void) f1_obj; + (void) f2_obj; + (void) f3_obj; + (void) fvar_obj; + (void) fvarbetween_obj; + (void) fkw_obj; + (void) map; + (void) dict; + (void) attrtuple; return mp_const_none; } diff --git a/ports/unix/input.c b/ports/unix/input.c index 31926a5a8e1..260e9eac8c9 100644 --- a/ports/unix/input.c +++ b/ports/unix/input.c @@ -104,6 +104,9 @@ void prompt_write_history(void) { #if MICROPY_USE_READLINE == 1 char *home = getenv("HOME"); if (home != NULL) { + if (MP_STATE_THREAD(gc_lock_depth) != 0) { + return; + } vstr_t vstr; vstr_init(&vstr, 50); vstr_printf(&vstr, "%s/.micropython.history", home); diff --git a/ports/unix/main.c b/ports/unix/main.c index 259b183eb76..89937008e05 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -54,9 +54,11 @@ #include "extmod/vfs_posix.h" #include "genhdr/mpversion.h" #include "input.h" +#include "stack_size.h" +#include "shared/runtime/pyexec.h" // Command line options, with their defaults -static bool compile_only = false; +bool mp_compile_only = false; static uint emit_opt = MP_EMIT_OPT_NONE; #if MICROPY_ENABLE_GC @@ -112,8 +114,6 @@ static int handle_uncaught_exception(mp_obj_base_t *exc) { } #define LEX_SRC_STR (1) -#define LEX_SRC_VSTR (2) -#define LEX_SRC_FILENAME (3) #define LEX_SRC_STDIN (4) // Returns standard error codes: 0 for success, 1 for all other errors, @@ -129,19 +129,13 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu if (source_kind == LEX_SRC_STR) { const char *line = source; lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, line, strlen(line), false); - } else if (source_kind == LEX_SRC_VSTR) { - const vstr_t *vstr = source; - lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, false); - } else if (source_kind == LEX_SRC_FILENAME) { - const char *filename = (const char *)source; - lex = mp_lexer_new_from_file(qstr_from_str(filename)); } else { // LEX_SRC_STDIN lex = mp_lexer_new_from_fd(MP_QSTR__lt_stdin_gt_, 0, false); } qstr source_name = lex->source_name; - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ if (input_kind == MP_PARSE_FILE_INPUT) { mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); } @@ -160,7 +154,7 @@ static int execute_from_lexer(int source_kind, const void *source, mp_parse_inpu mp_obj_t module_fun = mp_compile(&parse_tree, source_name, is_repl); - if (!compile_only) { + if (!mp_compile_only) { // execute it mp_call_function_0(module_fun); } @@ -197,92 +191,32 @@ static char *strjoin(const char *s1, int sep_char, const char *s2) { #endif static int do_repl(void) { - mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION); - mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE); - mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n"); - #if MICROPY_USE_READLINE == 1 - // use MicroPython supplied readline + // use MicroPython supplied readline-based REPL - vstr_t line; - vstr_init(&line, 16); + int ret = 0; for (;;) { - mp_hal_stdio_mode_raw(); - - input_restart: - vstr_reset(&line); - int ret = readline(&line, mp_repl_get_ps1()); - mp_parse_input_kind_t parse_input_kind = MP_PARSE_SINGLE_INPUT; - - if (ret == CHAR_CTRL_C) { - // cancel input - mp_hal_stdout_tx_str("\r\n"); - goto input_restart; - } else if (ret == CHAR_CTRL_D) { - // EOF - printf("\n"); - mp_hal_stdio_mode_orig(); - vstr_clear(&line); - return 0; - } else if (ret == CHAR_CTRL_E) { - // paste mode - mp_hal_stdout_tx_str("\npaste mode; Ctrl-C to cancel, Ctrl-D to finish\n=== "); - vstr_reset(&line); - for (;;) { - char c = mp_hal_stdin_rx_chr(); - if (c == CHAR_CTRL_C) { - // cancel everything - mp_hal_stdout_tx_str("\n"); - goto input_restart; - } else if (c == CHAR_CTRL_D) { - // end of input - mp_hal_stdout_tx_str("\n"); - break; - } else { - // add char to buffer and echo - vstr_add_byte(&line, c); - if (c == '\r') { - mp_hal_stdout_tx_str("\n=== "); - } else { - mp_hal_stdout_tx_strn(&c, 1); - } - } - } - parse_input_kind = MP_PARSE_FILE_INPUT; - } else if (line.len == 0) { - if (ret != 0) { - printf("\n"); + if (pyexec_mode_kind == PYEXEC_MODE_RAW_REPL) { + if ((ret = pyexec_raw_repl()) != 0) { + break; } - goto input_restart; } else { - // got a line with non-zero length, see if it needs continuing - while (mp_repl_continue_with_input(vstr_null_terminated_str(&line))) { - vstr_add_byte(&line, '\n'); - ret = readline(&line, mp_repl_get_ps2()); - if (ret == CHAR_CTRL_C) { - // cancel everything - printf("\n"); - goto input_restart; - } else if (ret == CHAR_CTRL_D) { - // stop entering compound statement - break; - } + if ((ret = pyexec_friendly_repl()) != 0) { + break; } } - - mp_hal_stdio_mode_orig(); - - ret = execute_from_lexer(LEX_SRC_VSTR, &line, parse_input_kind, true); - if (ret & FORCED_EXIT) { - return ret; - } } + return ret; #else // use simple readline + mp_hal_stdout_tx_str(MICROPY_BANNER_NAME_AND_VERSION); + mp_hal_stdout_tx_str("; " MICROPY_BANNER_MACHINE); + mp_hal_stdout_tx_str("\nUse Ctrl-D to exit, Ctrl-E for paste mode\n"); + for (;;) { char *line = prompt((char *)mp_repl_get_ps1()); if (line == NULL) { @@ -310,12 +244,40 @@ static int do_repl(void) { #endif } +static inline int convert_pyexec_result(int ret) { + #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING + // With exit code handling enabled: + // pyexec returns exit code with PYEXEC_FORCED_EXIT flag set for SystemExit + // Unix port expects: 0 for success, non-zero for error/exit + if (ret & PYEXEC_FORCED_EXIT) { + // SystemExit: extract exit code from lower bits + return ret & 0xFF; + } + // Normal execution or exception: return as-is (0 for success, 1 for exception) + return ret; + #else + // pyexec returns 1 for success, 0 for exception, PYEXEC_FORCED_EXIT for SystemExit + // Convert to unix port's expected codes: 0 for success, 1 for exception, FORCED_EXIT|val for SystemExit + if (ret == 1) { + return 0; // success + } else if (ret & PYEXEC_FORCED_EXIT) { + return ret; // SystemExit with exit value in lower 8 bits + } else { + return 1; // exception + } + #endif +} + static int do_file(const char *file) { - return execute_from_lexer(LEX_SRC_FILENAME, file, MP_PARSE_FILE_INPUT, false); + return convert_pyexec_result(pyexec_file(file)); } static int do_str(const char *str) { - return execute_from_lexer(LEX_SRC_STR, str, MP_PARSE_FILE_INPUT, false); + vstr_t vstr; + vstr.buf = (char *)str; + vstr.len = strlen(str); + int ret = pyexec_vstr(&vstr, true); + return convert_pyexec_result(ret); } static void print_help(char **argv) { @@ -384,7 +346,7 @@ static void pre_process_options(int argc, char **argv) { } if (0) { } else if (strcmp(argv[a + 1], "compile-only") == 0) { - compile_only = true; + mp_compile_only = true; } else if (strcmp(argv[a + 1], "emit=bytecode") == 0) { emit_opt = MP_EMIT_OPT_BYTECODE; #if MICROPY_EMIT_NATIVE @@ -456,10 +418,13 @@ static void set_sys_argv(char *argv[], int argc, int start_arg) { #if MICROPY_PY_SYS_EXECUTABLE extern mp_obj_str_t mp_sys_executable_obj; -static char executable_path[MICROPY_ALLOC_PATH_MAX]; +static char *executable_path = NULL; static void sys_set_excecutable(char *argv0) { - if (realpath(argv0, executable_path)) { + if (executable_path == NULL) { + executable_path = realpath(argv0, NULL); + } + if (executable_path != NULL) { mp_obj_str_set_data(&mp_sys_executable_obj, (byte *)executable_path, strlen(executable_path)); } } @@ -479,11 +444,7 @@ int main(int argc, char **argv) { #endif // Define a reasonable stack limit to detect stack overflow. - mp_uint_t stack_size = 40000 * (sizeof(void *) / 4); - #if defined(__arm__) && !defined(__thumb2__) - // ARM (non-Thumb) architectures require more stack. - stack_size *= 2; - #endif + mp_uint_t stack_size = 40000 * UNIX_STACK_MULTIPLIER; // We should capture stack top ASAP after start, and it should be // captured guaranteedly before any other stack variables are allocated. @@ -619,19 +580,6 @@ MP_NOINLINE int main_(int argc, char **argv) { } #endif - // Here is some example code to create a class and instance of that class. - // First is the Python, then the C code. - // - // class TestClass: - // pass - // test_obj = TestClass() - // test_obj.attr = 42 - // - // mp_obj_t test_class_type, test_class_instance; - // test_class_type = mp_obj_new_type(qstr_from_str("TestClass"), mp_const_empty_tuple, mp_obj_new_dict(0)); - // mp_store_name(qstr_from_str("test_obj"), test_class_instance = mp_call_function_0(test_class_type)); - // mp_store_attr(test_class_instance, qstr_from_str("attr"), mp_obj_new_int(42)); - /* printf("bytes:\n"); printf(" total %d\n", m_get_total_bytes_allocated()); @@ -685,12 +633,18 @@ MP_NOINLINE int main_(int argc, char **argv) { subpkg_tried = false; reimport: + mp_hal_set_interrupt_char(CHAR_CTRL_C); if (nlr_push(&nlr) == 0) { mod = mp_builtin___import__(MP_ARRAY_SIZE(import_args), import_args); + mp_hal_set_interrupt_char(-1); + mp_handle_pending(true); nlr_pop(); } else { // uncaught exception - return handle_uncaught_exception(nlr.ret_val) & 0xff; + mp_hal_set_interrupt_char(-1); + mp_handle_pending(false); + ret = handle_uncaught_exception(nlr.ret_val) & 0xff; + break; } // If this module is a package, see if it has a `__main__.py`. @@ -727,11 +681,9 @@ MP_NOINLINE int main_(int argc, char **argv) { return invalid_args(); } } else { - char *pathbuf = malloc(PATH_MAX); - char *basedir = realpath(argv[a], pathbuf); + char *basedir = realpath(argv[a], NULL); if (basedir == NULL) { mp_printf(&mp_stderr_print, "%s: can't open file '%s': [Errno %d] %s\n", argv[0], argv[a], errno, strerror(errno)); - free(pathbuf); // CPython exits with 2 in such case ret = 2; break; @@ -740,7 +692,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, '/'); mp_obj_list_store(mp_sys_path, MP_OBJ_NEW_SMALL_INT(0), mp_obj_new_str_via_qstr(basedir, p - basedir)); - free(pathbuf); + free(basedir); set_sys_argv(argv, argc, a); ret = do_file(argv[a]); @@ -780,7 +732,7 @@ MP_NOINLINE int main_(int argc, char **argv) { #endif #if MICROPY_PY_BLUETOOTH - void mp_bluetooth_deinit(void); + int mp_bluetooth_deinit(void); mp_bluetooth_deinit(); #endif @@ -806,6 +758,11 @@ MP_NOINLINE int main_(int argc, char **argv) { #endif #endif + #if MICROPY_PY_SYS_EXECUTABLE && !defined(NDEBUG) + // Again, make memory leak detector happy + free(executable_path); + #endif + // printf("total bytes = %d\n", m_get_total_bytes_allocated()); return ret & 0xff; } diff --git a/ports/unix/modtime.c b/ports/unix/modtime.c index fbd94b5ecd1..4f0550dbea7 100644 --- a/ports/unix/modtime.c +++ b/ports/unix/modtime.c @@ -34,6 +34,7 @@ #include "py/mphal.h" #include "py/runtime.h" +#include "shared/timeutils/timeutils.h" #ifdef _WIN32 static inline int msec_sleep_tv(struct timeval *tv) { @@ -130,12 +131,7 @@ static mp_obj_t mod_time_gm_local_time(size_t n_args, const mp_obj_t *args, stru if (n_args == 0) { t = time(NULL); } else { - #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE - mp_float_t val = mp_obj_get_float(args[0]); - t = (time_t)MICROPY_FLOAT_C_FUN(trunc)(val); - #else - t = mp_obj_get_int(args[0]); - #endif + t = (time_t)timeutils_obj_get_timestamp(args[0]); } struct tm *tm = time_func(&t); @@ -193,10 +189,10 @@ static mp_obj_t mod_time_mktime(mp_obj_t tuple) { time.tm_isdst = -1; // auto-detect } time_t ret = mktime(&time); - if (ret == -1) { + if (ret == (time_t)-1) { mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("invalid mktime usage")); } - return mp_obj_new_int(ret); + return timeutils_obj_from_timestamp(ret); } MP_DEFINE_CONST_FUN_OBJ_1(mod_time_mktime_obj, mod_time_mktime); diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 4d9fe9f1dc4..991db97f921 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -32,6 +32,9 @@ // features to work on Unix-like systems, see mpconfigvariant.h (and // mpconfigvariant_common.h) for feature enabling. +// For time_t, needed by MICROPY_TIMESTAMP_IMPL_TIME_T. +#include + // For size_t and ssize_t #include @@ -78,21 +81,6 @@ #define MICROPY_EMIT_ARM (1) #endif -// Type definitions for the specific machine based on the word size. -#ifndef MICROPY_OBJ_REPR -#ifdef __LP64__ -typedef long mp_int_t; // must be pointer size -typedef unsigned long mp_uint_t; // must be pointer size -#else -// These are definitions for machines where sizeof(int) == sizeof(void*), -// regardless of actual size. -typedef int mp_int_t; // must be pointer size -typedef unsigned int mp_uint_t; // must be pointer size -#endif -#else -// Assume that if we already defined the obj repr then we also defined types. -#endif - // Cannot include , as it may lead to symbol name clashes #if _FILE_OFFSET_BITS == 64 && !defined(__LP64__) typedef long long mp_off_t; @@ -135,6 +123,9 @@ typedef long mp_off_t; // VFS stat functions should return time values relative to 1970/1/1 #define MICROPY_EPOCH_IS_1970 (1) +// port modtime functions use time_t +#define MICROPY_TIMESTAMP_IMPL (MICROPY_TIMESTAMP_IMPL_TIME_T) + // Assume that select() call, interrupted with a signal, and erroring // with EINTR, updates remaining timeout value. #define MICROPY_SELECT_REMAINING_TIME (1) @@ -145,6 +136,9 @@ typedef long mp_off_t; #define MICROPY_STACKLESS_STRICT (0) #endif +// Recursive mutex is needed when threading is enabled, regardless of GIL setting. +#define MICROPY_PY_THREAD_RECURSIVE_MUTEX (MICROPY_PY_THREAD) + // Implementation of the machine module. #define MICROPY_PY_MACHINE_INCLUDEFILE "ports/unix/modmachine.c" @@ -172,6 +166,12 @@ typedef long mp_off_t; // Enable sys.executable. #define MICROPY_PY_SYS_EXECUTABLE (1) +// Enable support for compile-only mode. +#define MICROPY_PYEXEC_COMPILE_ONLY (1) + +// Enable handling of sys.exit() exit codes. +#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (1) + #define MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT (SOMAXCONN < 128 ? SOMAXCONN : 128) // Bare-metal ports don't have stderr. Printing debug to stderr may give tests diff --git a/ports/unix/mpconfigport.mk b/ports/unix/mpconfigport.mk index 26c04faf4c5..c836663cd23 100644 --- a/ports/unix/mpconfigport.mk +++ b/ports/unix/mpconfigport.mk @@ -14,6 +14,7 @@ MICROPY_PY_BTREE = 0 # _thread module using pthreads MICROPY_PY_THREAD = 1 +MICROPY_PY_THREAD_GIL = 0 # Subset of CPython termios module MICROPY_PY_TERMIOS = 1 diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index 7f71217632a..afac25bf865 100644 --- a/ports/unix/mphalport.h +++ b/ports/unix/mphalport.h @@ -110,3 +110,6 @@ enum { void mp_hal_get_mac(int idx, uint8_t buf[6]); #endif + +// Global variable to control compile-only mode. +extern bool mp_compile_only; diff --git a/ports/unix/mpthreadport.c b/ports/unix/mpthreadport.c index 5172645bc14..a41b3ec9f47 100644 --- a/ports/unix/mpthreadport.c +++ b/ports/unix/mpthreadport.c @@ -31,6 +31,7 @@ #include "py/runtime.h" #include "py/mpthread.h" #include "py/gc.h" +#include "stack_size.h" #if MICROPY_PY_THREAD @@ -45,8 +46,14 @@ // potential conflict with other uses of the more commonly used SIGUSR1. #ifdef SIGRTMIN #define MP_THREAD_GC_SIGNAL (SIGRTMIN + 5) +#ifdef __ANDROID__ +#define MP_THREAD_TERMINATE_SIGNAL (SIGRTMIN + 6) +#endif #else #define MP_THREAD_GC_SIGNAL (SIGUSR1) +#ifdef __ANDROID__ +#define MP_THREAD_TERMINATE_SIGNAL (SIGUSR2) +#endif #endif // This value seems to be about right for both 32-bit and 64-bit builds. @@ -107,6 +114,18 @@ static void mp_thread_gc(int signo, siginfo_t *info, void *context) { } } +// On Android, pthread_cancel and pthread_setcanceltype are not implemented. +// To achieve that result a new signal handler responding on either +// (SIGRTMIN + 6) or SIGUSR2 is installed on every child thread. The sole +// purpose of this new signal handler is to terminate the thread in a safe +// asynchronous manner. + +#ifdef __ANDROID__ +static void mp_thread_terminate(int signo, siginfo_t *info, void *context) { + pthread_exit(NULL); +} +#endif + void mp_thread_init(void) { pthread_key_create(&tls_key, NULL); pthread_setspecific(tls_key, &mp_state_ctx.thread); @@ -135,6 +154,14 @@ void mp_thread_init(void) { sa.sa_sigaction = mp_thread_gc; sigemptyset(&sa.sa_mask); sigaction(MP_THREAD_GC_SIGNAL, &sa, NULL); + + // Install a signal handler for asynchronous termination if needed. + #if defined(__ANDROID__) + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = mp_thread_terminate; + sigemptyset(&sa.sa_mask); + sigaction(MP_THREAD_TERMINATE_SIGNAL, &sa, NULL); + #endif } void mp_thread_deinit(void) { @@ -142,7 +169,11 @@ void mp_thread_deinit(void) { while (thread->next != NULL) { mp_thread_t *th = thread; thread = thread->next; + #if defined(__ANDROID__) + pthread_kill(th->id, MP_THREAD_TERMINATE_SIGNAL); + #else pthread_cancel(th->id); + #endif free(th); } mp_thread_unix_end_atomic_section(); @@ -200,7 +231,9 @@ void mp_thread_start(void) { } #endif + #if !defined(__ANDROID__) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + #endif mp_thread_unix_begin_atomic_section(); for (mp_thread_t *th = thread; th != NULL; th = th->next) { if (th->id == pthread_self()) { @@ -212,14 +245,14 @@ void mp_thread_start(void) { } mp_uint_t mp_thread_create(void *(*entry)(void *), void *arg, size_t *stack_size) { - // default stack size is 8k machine-words + // default stack size if (*stack_size == 0) { - *stack_size = 8192 * sizeof(void *); + *stack_size = 32768 * UNIX_STACK_MULTIPLIER; } // minimum stack size is set by pthreads - if (*stack_size < PTHREAD_STACK_MIN) { - *stack_size = PTHREAD_STACK_MIN; + if (*stack_size < (size_t)PTHREAD_STACK_MIN) { + *stack_size = (size_t)PTHREAD_STACK_MIN; } // ensure there is enough stack to include a stack-overflow margin diff --git a/ports/unix/stack_size.h b/ports/unix/stack_size.h new file mode 100644 index 00000000000..f6159bb69d5 --- /dev/null +++ b/ports/unix/stack_size.h @@ -0,0 +1,54 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2025 Angus Gratton + * + * 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. + */ +#ifndef MICROPY_INCLUDED_UNIX_STACK_SIZE_H +#define MICROPY_INCLUDED_UNIX_STACK_SIZE_H + +#include "py/misc.h" + +// Define scaling factors for the stack size (also applies to main thread) +#ifndef UNIX_STACK_MULTIPLIER + +#if defined(__arm__) && !defined(__thumb2__) +// ARM (non-Thumb) architectures require more stack. +#define UNIX_STACK_MUL_ARM 2 +#else +#define UNIX_STACK_MUL_ARM 1 +#endif + +#if MP_SANITIZER_BUILD +// Sanitizer features consume significant stack in some cases +// This multiplier can probably be removed when using GCC 12 or newer. +#define UNIX_STACK_MUL_SANITIZERS 4 +#else +#define UNIX_STACK_MUL_SANITIZERS 1 +#endif + +// Double the stack size for 64-bit builds, plus additional scaling +#define UNIX_STACK_MULTIPLIER ((sizeof(void *) / 4) * UNIX_STACK_MUL_ARM * UNIX_STACK_MUL_SANITIZERS) + +#endif // UNIX_STACK_MULTIPLIER + +#endif // MICROPY_INCLUDED_UNIX_STACK_SIZE_H diff --git a/ports/unix/variants/coverage/mpconfigvariant.h b/ports/unix/variants/coverage/mpconfigvariant.h index ca79d3d0d2b..03f77ec14c6 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.h +++ b/ports/unix/variants/coverage/mpconfigvariant.h @@ -39,11 +39,22 @@ // Enable additional features. #define MICROPY_DEBUG_PARSE_RULE_NAME (1) +// CIRCUITPY-CHANGE: off +#define MICROPY_PY_SYS_SETTRACE (0) #define MICROPY_TRACKED_ALLOC (1) #define MICROPY_WARNINGS_CATEGORY (1) #undef MICROPY_VFS_ROM_IOCTL #define MICROPY_VFS_ROM_IOCTL (1) #define MICROPY_PY_CRYPTOLIB_CTR (1) +// CIRCUITPY-CHANGE: off +#define MICROPY_SCHEDULER_STATIC_NODES (0) + +// Enable os.uname for attrtuple coverage test +#define MICROPY_PY_OS_UNAME (1) +#define MICROPY_HW_BOARD_NAME "a machine" +#define MICROPY_HW_MCU_NAME MICROPY_PY_SYS_PLATFORM +// Keep the standard banner message +#define MICROPY_BANNER_MACHINE MICROPY_PY_SYS_PLATFORM " [" MICROPY_PLATFORM_COMPILER "] version" // CIRCUITPY-CHANGE: Disable things never used in circuitpython #define MICROPY_PY_CRYPTOLIB (0) diff --git a/shared/netutils/dhcpserver.h b/ports/unix/variants/longlong/mpconfigvariant.h similarity index 60% rename from shared/netutils/dhcpserver.h rename to ports/unix/variants/longlong/mpconfigvariant.h index 2349d2ea427..d50d360b1fe 100644 --- a/shared/netutils/dhcpserver.h +++ b/ports/unix/variants/longlong/mpconfigvariant.h @@ -3,7 +3,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2018-2019 Damien P. George + * Copyright (c) 2016 Damien P. George * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,27 +23,22 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H -#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H -#include "lwip/ip_addr.h" +// This config exists to test that the MICROPY_LONGINT_IMPL_LONGLONG variant +// (i.e. minimal form of "big integer" that's backed by 64-bit int only) builds +// and passes tests. -#define DHCPS_BASE_IP (16) -#define DHCPS_MAX_IP (8) +#define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) -typedef struct _dhcp_server_lease_t { - uint8_t mac[6]; - uint16_t expiry; -} dhcp_server_lease_t; +// We build it on top of REPR C, which uses memory-efficient floating point +// objects encoded directly mp_obj_t (30 bits only). +// Therefore this variant should be built using MICROPY_FORCE_32BIT=1 -typedef struct _dhcp_server_t { - ip_addr_t ip; - ip_addr_t nm; - dhcp_server_lease_t lease[DHCPS_MAX_IP]; - struct udp_pcb *udp; -} dhcp_server_t; +#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) +#define MICROPY_FLOAT_IMPL (MICROPY_FLOAT_IMPL_FLOAT) -void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm); -void dhcp_server_deinit(dhcp_server_t *d); +// Set base feature level. +#define MICROPY_CONFIG_ROM_LEVEL (MICROPY_CONFIG_ROM_LEVEL_EXTRA_FEATURES) -#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H +// Enable extra Unix features. +#include "../mpconfigvariant_common.h" diff --git a/ports/unix/variants/longlong/mpconfigvariant.mk b/ports/unix/variants/longlong/mpconfigvariant.mk new file mode 100644 index 00000000000..2d2c3706469 --- /dev/null +++ b/ports/unix/variants/longlong/mpconfigvariant.mk @@ -0,0 +1,8 @@ +# build interpreter with "bigints" implemented as "longlong" + +# otherwise, small int is essentially 64-bit +MICROPY_FORCE_32BIT := 1 + +MICROPY_PY_FFI := 0 + +MPY_TOOL_FLAGS = -mlongint-impl longlong diff --git a/ports/unix/variants/minimal/mpconfigvariant.h b/ports/unix/variants/minimal/mpconfigvariant.h index 97ed786b8f4..0e280a8f730 100644 --- a/ports/unix/variants/minimal/mpconfigvariant.h +++ b/ports/unix/variants/minimal/mpconfigvariant.h @@ -49,6 +49,7 @@ #define MICROPY_COMP_DOUBLE_TUPLE_ASSIGN (1) #define MICROPY_ENABLE_COMPILER (1) #define MICROPY_ENABLE_EXTERNAL_IMPORT (1) +#define MICROPY_STACK_CHECK (1) #define MICROPY_FULL_CHECKS (1) #define MICROPY_HELPER_REPL (1) #define MICROPY_KBD_EXCEPTION (1) @@ -61,6 +62,5 @@ #define MICROPY_PY_BUILTINS_RANGE_ATTRS (1) #define MICROPY_PY_GENERATOR_PEND_THROW (1) -// Enable just the sys and os built-in modules. -#define MICROPY_PY_SYS (1) +// Add just the os built-in module. #define MICROPY_PY_OS (1) diff --git a/ports/unix/variants/mpconfigvariant_common.h b/ports/unix/variants/mpconfigvariant_common.h index 9eeed879736..1ac59c95572 100644 --- a/ports/unix/variants/mpconfigvariant_common.h +++ b/ports/unix/variants/mpconfigvariant_common.h @@ -29,7 +29,7 @@ // Send raise KeyboardInterrupt directly from the signal handler rather than // scheduling it into the VM. -#define MICROPY_ASYNC_KBD_INTR (1) +#define MICROPY_ASYNC_KBD_INTR (!MICROPY_PY_THREAD_GIL) // Enable helpers for printing debugging information. #ifndef MICROPY_DEBUG_PRINTERS @@ -104,12 +104,6 @@ #define MICROPY_PY_TIME_CUSTOM_SLEEP (1) #define MICROPY_PY_TIME_INCLUDEFILE "ports/unix/modtime.c" -#if MICROPY_PY_SSL -#define MICROPY_PY_HASHLIB_MD5 (1) -#define MICROPY_PY_HASHLIB_SHA1 (1) -#define MICROPY_PY_CRYPTOLIB (1) -#endif - // The "select" module is enabled by default, but disable select.select(). #define MICROPY_PY_SELECT_POSIX_OPTIMISATIONS (1) #define MICROPY_PY_SELECT_SELECT (0) diff --git a/ports/unix/variants/nanbox/mpconfigvariant.h b/ports/unix/variants/nanbox/mpconfigvariant.h index 7b13b7dc6ce..c9e9c1f63d9 100644 --- a/ports/unix/variants/nanbox/mpconfigvariant.h +++ b/ports/unix/variants/nanbox/mpconfigvariant.h @@ -41,10 +41,3 @@ #define MICROPY_EMIT_X64 (0) #define MICROPY_EMIT_THUMB (0) #define MICROPY_EMIT_ARM (0) - -#include - -typedef int64_t mp_int_t; -typedef uint64_t mp_uint_t; -#define UINT_FMT "%llu" -#define INT_FMT "%lld" diff --git a/py/argcheck.c b/py/argcheck.c index 9302dec96c3..155e29bdc15 100644 --- a/py/argcheck.c +++ b/py/argcheck.c @@ -170,13 +170,13 @@ void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, } #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE -NORETURN void mp_arg_error_terse_mismatch(void) { +MP_NORETURN void mp_arg_error_terse_mismatch(void) { mp_raise_TypeError(MP_ERROR_TEXT("argument num/types mismatch")); } #endif #if MICROPY_CPYTHON_COMPAT -NORETURN void mp_arg_error_unimpl_kw(void) { +MP_NORETURN void mp_arg_error_unimpl_kw(void) { mp_raise_NotImplementedError(MP_ERROR_TEXT("keyword argument(s) not implemented - use normal args instead")); } #endif @@ -312,6 +312,6 @@ mp_int_t mp_arg_validate_type_int(mp_obj_t obj, qstr arg_name) { return an_int; } -NORETURN void mp_arg_error_invalid(qstr arg_name) { +MP_NORETURN void mp_arg_error_invalid(qstr arg_name) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q"), arg_name); } diff --git a/py/asmarm.c b/py/asmarm.c index 6fa751b32eb..15bc73b61ec 100644 --- a/py/asmarm.c +++ b/py/asmarm.c @@ -36,7 +36,7 @@ #include "py/asmarm.h" -#define SIGNED_FIT24(x) (((x) & 0xff800000) == 0) || (((x) & 0xff000000) == 0xff000000) +#define REG_TEMP ASM_ARM_REG_R8 // Insert word into instruction flow static void emit(asm_arm_t *as, uint op) { @@ -171,8 +171,8 @@ void asm_arm_entry(asm_arm_t *as, int num_locals) { if (as->stack_adjust < 0x100) { emit_al(as, asm_arm_op_sub_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust)); } else { - asm_arm_mov_reg_i32_optimised(as, ASM_ARM_REG_R8, as->stack_adjust); - emit_al(as, asm_arm_op_sub_reg(ASM_ARM_REG_SP, ASM_ARM_REG_SP, ASM_ARM_REG_R8)); + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, as->stack_adjust); + emit_al(as, asm_arm_op_sub_reg(ASM_ARM_REG_SP, ASM_ARM_REG_SP, REG_TEMP)); } } } @@ -182,8 +182,8 @@ void asm_arm_exit(asm_arm_t *as) { if (as->stack_adjust < 0x100) { emit_al(as, asm_arm_op_add_imm(ASM_ARM_REG_SP, ASM_ARM_REG_SP, as->stack_adjust)); } else { - asm_arm_mov_reg_i32_optimised(as, ASM_ARM_REG_R8, as->stack_adjust); - emit_al(as, asm_arm_op_add_reg(ASM_ARM_REG_SP, ASM_ARM_REG_SP, ASM_ARM_REG_R8)); + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, as->stack_adjust); + emit_al(as, asm_arm_op_add_reg(ASM_ARM_REG_SP, ASM_ARM_REG_SP, REG_TEMP)); } } @@ -293,10 +293,10 @@ void asm_arm_orr_reg_reg_reg(asm_arm_t *as, uint rd, uint rn, uint rm) { void asm_arm_mov_reg_local_addr(asm_arm_t *as, uint rd, int local_num) { if (local_num >= 0x40) { - // mov r8, #local_num*4 - // add rd, sp, r8 - asm_arm_mov_reg_i32_optimised(as, ASM_ARM_REG_R8, local_num << 2); - emit_al(as, asm_arm_op_add_reg(rd, ASM_ARM_REG_SP, ASM_ARM_REG_R8)); + // mov temp, #local_num*4 + // add rd, sp, temp + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, local_num << 2); + emit_al(as, asm_arm_op_add_reg(rd, ASM_ARM_REG_SP, REG_TEMP)); } else { // add rd, sp, #local_num*4 emit_al(as, asm_arm_op_add_imm(rd, ASM_ARM_REG_SP, local_num << 2)); @@ -333,14 +333,22 @@ void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs) { emit_al(as, 0x1a00050 | (rd << 12) | (rs << 8) | rd); } -void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { - // ldr rd, [rn, #off] - emit_al(as, 0x5900000 | (rn << 16) | (rd << 12) | byte_offset); +void asm_arm_ldr_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + if (byte_offset < 0x1000) { + // ldr rd, [rn, #off] + emit_al(as, 0x5900000 | (rn << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // ldr rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7900000 | (rn << 16) | (rd << 12) | REG_TEMP); + } } -void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn) { - // ldrh rd, [rn] - emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12)); +void asm_arm_ldrh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // ldrh doesn't support scaled register index + emit_al(as, 0x1a00080 | (REG_TEMP << 12) | rn); // mov temp, rn, lsl #1 + emit_al(as, 0x19000b0 | (rm << 16) | (rd << 12) | REG_TEMP); // ldrh rd, [rm, temp]; } void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { @@ -348,31 +356,69 @@ void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offs // ldrh rd, [rn, #off] emit_al(as, 0x1d000b0 | (rn << 16) | (rd << 12) | ((byte_offset & 0xf0) << 4) | (byte_offset & 0xf)); } else { - // mov r8, #off - // ldrh rd, [rn, r8] - asm_arm_mov_reg_i32_optimised(as, ASM_ARM_REG_R8, byte_offset); - emit_al(as, 0x19000b0 | (rn << 16) | (rd << 12) | ASM_ARM_REG_R8); + // mov temp, #off + // ldrh rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x19000b0 | (rn << 16) | (rd << 12) | REG_TEMP); } } -void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn) { - // ldrb rd, [rn] - emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12)); +void asm_arm_ldrb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // ldrb rd, [rm, rn] + emit_al(as, 0x7d00000 | (rm << 16) | (rd << 12) | rn); +} + +void asm_arm_ldrb_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + if (byte_offset < 0x1000) { + // ldrb rd, [rn, #off] + emit_al(as, 0x5d00000 | (rn << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // ldrb rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7d00000 | (rn << 16) | (rd << 12) | REG_TEMP); + } } -void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm, uint byte_offset) { - // str rd, [rm, #off] - emit_al(as, 0x5800000 | (rm << 16) | (rd << 12) | byte_offset); +void asm_arm_ldr_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { + // ldr rd, [rm, rn, lsl #2] + emit_al(as, 0x7900100 | (rm << 16) | (rd << 12) | rn); } -void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm) { - // strh rd, [rm] - emit_al(as, 0x1c000b0 | (rm << 16) | (rd << 12)); +void asm_arm_str_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset) { + if (byte_offset < 0x1000) { + // str rd, [rm, #off] + emit_al(as, 0x5800000 | (rm << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // str rd, [rm, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7800000 | (rm << 16) | (rd << 12) | REG_TEMP); + } } -void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm) { - // strb rd, [rm] - emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12)); +void asm_arm_strh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset) { + if (byte_offset < 0x100) { + // strh rd, [rn, #off] + emit_al(as, 0x1c000b0 | (rn << 16) | (rd << 12) | ((byte_offset & 0xf0) << 4) | (byte_offset & 0xf)); + } else { + // mov temp, #off + // strh rd, [rn, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x18000b0 | (rn << 16) | (rd << 12) | REG_TEMP); + } +} + +void asm_arm_strb_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset) { + if (byte_offset < 0x1000) { + // strb rd, [rm, #off] + emit_al(as, 0x5c00000 | (rm << 16) | (rd << 12) | byte_offset); + } else { + // mov temp, #off + // strb rd, [rm, temp] + asm_arm_mov_reg_i32_optimised(as, REG_TEMP, byte_offset); + emit_al(as, 0x7c00000 | (rm << 16) | (rd << 12) | REG_TEMP); + } } void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { @@ -382,8 +428,8 @@ void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { // strh doesn't support scaled register index - emit_al(as, 0x1a00080 | (ASM_ARM_REG_R8 << 12) | rn); // mov r8, rn, lsl #1 - emit_al(as, 0x18000b0 | (rm << 16) | (rd << 12) | ASM_ARM_REG_R8); // strh rd, [rm, r8] + emit_al(as, 0x1a00080 | (REG_TEMP << 12) | rn); // mov temp, rn, lsl #1 + emit_al(as, 0x18000b0 | (rm << 16) | (rd << 12) | REG_TEMP); // strh rd, [rm, temp] } void asm_arm_strb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn) { @@ -398,7 +444,7 @@ void asm_arm_bcc_label(asm_arm_t *as, int cond, uint label) { rel -= 8; // account for instruction prefetch, PC is 8 bytes ahead of this instruction rel >>= 2; // in ARM mode the branch target is 32-bit aligned, so the 2 LSB are omitted - if (SIGNED_FIT24(rel)) { + if (MP_FIT_SIGNED(24, rel)) { emit(as, cond | 0xa000000 | (rel & 0xffffff)); } else { printf("asm_arm_bcc: branch does not fit in 24 bits\n"); diff --git a/py/asmarm.h b/py/asmarm.h index a0e057fce44..f3fd586a375 100644 --- a/py/asmarm.h +++ b/py/asmarm.h @@ -109,13 +109,18 @@ void asm_arm_lsr_reg_reg(asm_arm_t *as, uint rd, uint rs); void asm_arm_asr_reg_reg(asm_arm_t *as, uint rd, uint rs); // memory -void asm_arm_ldr_reg_reg(asm_arm_t *as, uint rd, uint rn, uint byte_offset); -void asm_arm_ldrh_reg_reg(asm_arm_t *as, uint rd, uint rn); +void asm_arm_ldr_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); void asm_arm_ldrh_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); -void asm_arm_ldrb_reg_reg(asm_arm_t *as, uint rd, uint rn); -void asm_arm_str_reg_reg(asm_arm_t *as, uint rd, uint rm, uint byte_offset); -void asm_arm_strh_reg_reg(asm_arm_t *as, uint rd, uint rm); -void asm_arm_strb_reg_reg(asm_arm_t *as, uint rd, uint rm); +void asm_arm_ldrb_reg_reg_offset(asm_arm_t *as, uint rd, uint rn, uint byte_offset); +void asm_arm_str_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); +void asm_arm_strh_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); +void asm_arm_strb_reg_reg_offset(asm_arm_t *as, uint rd, uint rm, uint byte_offset); + +// load from array +void asm_arm_ldr_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); +void asm_arm_ldrh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); +void asm_arm_ldrb_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); + // store to array void asm_arm_str_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); void asm_arm_strh_reg_reg_reg(asm_arm_t *as, uint rd, uint rm, uint rn); @@ -160,12 +165,12 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_ARM_REG_FUN_TABLE -#define ASM_T asm_arm_t -#define ASM_END_PASS asm_arm_end_pass -#define ASM_ENTRY asm_arm_entry -#define ASM_EXIT asm_arm_exit +#define ASM_T asm_arm_t +#define ASM_END_PASS asm_arm_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_arm_entry((as), (num_locals)) +#define ASM_EXIT asm_arm_exit -#define ASM_JUMP asm_arm_b_label +#define ASM_JUMP asm_arm_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ asm_arm_cmp_reg_i8(as, reg, 0); \ @@ -203,18 +208,28 @@ void asm_arm_bx_reg(asm_arm_t *as, uint reg_src); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_arm_sub_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_arm_mul_reg_reg_reg((as), (reg_dest), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 4 * (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_arm_ldrb_reg_reg((as), (reg_dest), (reg_base)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_arm_ldrh_reg_reg((as), (reg_dest), (reg_base)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_arm_ldrh_reg_reg_offset((as), (reg_dest), (reg_base), 2 * (uint16_offset)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_arm_ldr_reg_reg((as), (reg_dest), (reg_base), 0) - -#define ASM_STORE_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_str_reg_reg((as), (reg_dest), (reg_base), 4 * (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_value, reg_base) asm_arm_strb_reg_reg((as), (reg_value), (reg_base)) -#define ASM_STORE16_REG_REG(as, reg_value, reg_base) asm_arm_strh_reg_reg((as), (reg_value), (reg_base)) -#define ASM_STORE32_REG_REG(as, reg_value, reg_base) asm_arm_str_reg_reg((as), (reg_value), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_arm_ldrb_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_arm_ldrh_reg_reg_offset((as), (reg_dest), (reg_base), 2 * (halfword_offset)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_arm_ldr_reg_reg_offset((as), (reg_dest), (reg_base), 4 * (word_offset)) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_value, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_value), (reg_base), (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_value, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_value, reg_base, byte_offset) asm_arm_strb_reg_reg_offset((as), (reg_value), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_value, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_value, reg_base, halfword_offset) asm_arm_strh_reg_reg_offset((as), (reg_value), (reg_base), 2 * (halfword_offset)) +#define ASM_STORE32_REG_REG(as, reg_value, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_value), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_value, reg_base, word_offset) asm_arm_str_reg_reg_offset((as), (reg_value), (reg_base), 4 * (word_offset)) + +#define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_arm_ldrb_reg_reg_reg((as), (reg_dest), (reg_base), (reg_index)) +#define ASM_LOAD16_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_arm_ldrh_reg_reg_reg((as), (reg_dest), (reg_base), (reg_index)) +#define ASM_LOAD32_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_arm_ldr_reg_reg_reg((as), (reg_dest), (reg_base), (reg_index)) +#define ASM_STORE8_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_arm_strb_reg_reg_reg((as), (reg_val), (reg_base), (reg_index)) +#define ASM_STORE16_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_arm_strh_reg_reg_reg((as), (reg_val), (reg_base), (reg_index)) +#define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_arm_str_reg_reg_reg((as), (reg_val), (reg_base), (reg_index)) #endif // GENERIC_ASM_API diff --git a/py/asmbase.c b/py/asmbase.c index 3fce543a7f4..07dbf4430f9 100644 --- a/py/asmbase.c +++ b/py/asmbase.c @@ -53,7 +53,7 @@ void mp_asm_base_start_pass(mp_asm_base_t *as, int pass) { } else { // allocating executable RAM is platform specific MP_PLAT_ALLOC_EXEC(as->code_offset, (void **)&as->code_base, &as->code_size); - assert(as->code_base != NULL); + assert(as->code_size == 0 || as->code_base != NULL); } as->pass = pass; as->suppress = false; @@ -102,7 +102,7 @@ void mp_asm_base_label_assign(mp_asm_base_t *as, size_t label) { // align must be a multiple of 2 void mp_asm_base_align(mp_asm_base_t *as, unsigned int align) { - as->code_offset = (as->code_offset + align - 1) & (~(align - 1)); + as->code_offset = (as->code_offset + align - 1) & (~(size_t)(align - 1)); } // this function assumes a little endian machine diff --git a/py/asmrv32.c b/py/asmrv32.c index c24d05a1384..1d0cea6c026 100644 --- a/py/asmrv32.c +++ b/py/asmrv32.c @@ -36,6 +36,8 @@ #if MICROPY_EMIT_RV32 #include "py/asmrv32.h" +#include "py/mpstate.h" +#include "py/persistentcode.h" #if MICROPY_DEBUG_VERBOSE #define DEBUG_PRINT (1) @@ -450,18 +452,24 @@ void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t asm_rv32_opcode_cadd(state, rd, ASM_RV32_REG_SP); } -void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { - mp_int_t scaled_offset = offset * sizeof(ASM_WORD_SIZE); +static const uint8_t RV32_LOAD_OPCODE_TABLE[3] = { + 0x04, 0x05, 0x02 +}; - if (scaled_offset >= 0 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && FIT_UNSIGNED(scaled_offset, 6)) { +void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + int32_t scaled_offset = offset << operation_size; + + if (scaled_offset >= 0 && operation_size == 2 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && MP_FIT_UNSIGNED(6, scaled_offset)) { // c.lw rd', offset(rs') asm_rv32_opcode_clw(state, RV32_MAP_IN_C_REGISTER_WINDOW(rd), RV32_MAP_IN_C_REGISTER_WINDOW(rs), scaled_offset); return; } - if (FIT_SIGNED(scaled_offset, 12)) { - // lw rd, offset(rs) - asm_rv32_opcode_lw(state, rd, rs, scaled_offset); + if (MP_FIT_SIGNED(12, scaled_offset)) { + // lbu|lhu|lw rd, offset(rs) + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, RV32_LOAD_OPCODE_TABLE[operation_size], rd, rs, scaled_offset)); return; } @@ -469,12 +477,12 @@ void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_ mp_uint_t lower = 0; split_immediate(scaled_offset, &upper, &lower); - // lui rd, HI(offset) ; Or c.lui if possible - // c.add rd, rs - // lw rd, LO(offset)(rd) + // lui rd, HI(offset) ; Or c.lui if possible + // c.add rd, rs + // lbu|lhu|lw rd, LO(offset)(rd) load_upper_immediate(state, rd, upper); asm_rv32_opcode_cadd(state, rd, rs); - asm_rv32_opcode_lw(state, rd, rd, lower); + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x03, RV32_LOAD_OPCODE_TABLE[operation_size], rd, rd, lower)); } void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) { @@ -497,12 +505,20 @@ void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label) { asm_rv32_opcode_jalr(state, ASM_RV32_REG_ZERO, REG_TEMP2, lower); } -void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { - mp_int_t scaled_offset = offset * ASM_WORD_SIZE; +void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); - if (FIT_SIGNED(scaled_offset, 12)) { - // sw rd, offset(rs) - asm_rv32_opcode_sw(state, rd, rs, scaled_offset); + int32_t scaled_offset = offset << operation_size; + + if (scaled_offset >= 0 && operation_size == 2 && RV32_IS_IN_C_REGISTER_WINDOW(rd) && RV32_IS_IN_C_REGISTER_WINDOW(rs) && MP_FIT_UNSIGNED(6, scaled_offset)) { + // c.sw rd', offset(rs') + asm_rv32_opcode_csw(state, RV32_MAP_IN_C_REGISTER_WINDOW(rd), RV32_MAP_IN_C_REGISTER_WINDOW(rs), scaled_offset); + return; + } + + if (MP_FIT_SIGNED(12, scaled_offset)) { + // sb|sh|sw rd, offset(rs) + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, operation_size, rs, rd, scaled_offset)); return; } @@ -510,12 +526,12 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint mp_uint_t lower = 0; split_immediate(scaled_offset, &upper, &lower); - // lui temporary, HI(offset) ; Or c.lui if possible - // c.add temporary, rs - // sw rd, LO(offset)(temporary) + // lui temporary, HI(offset) ; Or c.lui if possible + // c.add temporary, rs + // sb|sh|sw rd, LO(offset)(temporary) load_upper_immediate(state, REG_TEMP2, upper); asm_rv32_opcode_cadd(state, REG_TEMP2, rs); - asm_rv32_opcode_sw(state, rd, REG_TEMP2, lower); + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_S(0x23, operation_size, REG_TEMP2, rd, lower)); } void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label) { @@ -530,27 +546,6 @@ void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t labe asm_rv32_opcode_addi(state, rd, rd, lower); } -void asm_rv32_emit_load16_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset) { - mp_int_t scaled_offset = offset * sizeof(uint16_t); - - if (FIT_SIGNED(scaled_offset, 12)) { - // lhu rd, offset(rs) - asm_rv32_opcode_lhu(state, rd, rs, scaled_offset); - return; - } - - mp_uint_t upper = 0; - mp_uint_t lower = 0; - split_immediate(scaled_offset, &upper, &lower); - - // lui rd, HI(offset) ; Or c.lui if possible - // c.add rd, rs - // lhu rd, LO(offset)(rd) - load_upper_immediate(state, rd, upper); - asm_rv32_opcode_cadd(state, rd, rs); - asm_rv32_opcode_lhu(state, rd, rd, lower); -} - void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) { if (rs == rd) { // c.li rd, 0 @@ -562,14 +557,39 @@ void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs) asm_rv32_opcode_xor(state, rd, rd, rs); } +static bool asm_rv32_allow_zba_opcodes(void) { + return asm_rv32_allowed_extensions() & RV32_EXT_ZBA; +} + +static void asm_rv32_fix_up_scaled_reg_reg_reg(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + if (operation_size > 0 && asm_rv32_allow_zba_opcodes()) { + // sh{1,2}add rs1, rs2, rs1 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 1 << operation_size, 0x10, rs1, rs2, rs1)); + } else { + if (operation_size > 0) { + asm_rv32_opcode_cslli(state, rs2, operation_size); + } + asm_rv32_opcode_cadd(state, rs1, rs2); + } +} + +void asm_rv32_emit_load_reg_reg_reg(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size) { + asm_rv32_fix_up_scaled_reg_reg_reg(state, rs1, rs2, operation_size); + asm_rv32_emit_load_reg_reg_offset(state, rd, rs1, 0, operation_size); +} + +void asm_rv32_emit_store_reg_reg_reg(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size) { + asm_rv32_fix_up_scaled_reg_reg_reg(state, rs1, rs2, operation_size); + asm_rv32_emit_store_reg_reg_offset(state, rd, rs1, 0, operation_size); +} + void asm_rv32_meta_comparison_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd) { - // c.li rd, 1 ; - // beq rs1, rs2, 6 ; PC + 0 - // c.li rd, 0 ; PC + 4 - // ... ; PC + 6 - asm_rv32_opcode_cli(state, rd, 1); - asm_rv32_opcode_beq(state, rs1, rs2, 6); - asm_rv32_opcode_cli(state, rd, 0); + // sub rd, rs1, rs2 + // sltiu rd, rd, 1 + asm_rv32_opcode_sub(state, rd, rs1, rs2); + asm_rv32_opcode_sltiu(state, rd, rd, 1); } void asm_rv32_meta_comparison_ne(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd) { @@ -580,26 +600,15 @@ void asm_rv32_meta_comparison_ne(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2 } void asm_rv32_meta_comparison_lt(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison) { - // slt(u) rd, rs1, rs2 - if (unsigned_comparison) { - asm_rv32_opcode_sltu(state, rd, rs1, rs2); - } else { - asm_rv32_opcode_slt(state, rd, rs1, rs2); - } + // slt|sltu rd, rs1, rs2 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, (0x02 | (unsigned_comparison ? 1 : 0)), 0x00, rd, rs1, rs2)); } void asm_rv32_meta_comparison_le(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison) { - // c.li rd, 1 ; - // beq rs1, rs2, 8 ; PC + 0 - // slt(u) rd, rs1, rs2 ; PC + 4 - // ... ; PC + 8 - asm_rv32_opcode_cli(state, rd, 1); - asm_rv32_opcode_beq(state, rs1, rs2, 8); - if (unsigned_comparison) { - asm_rv32_opcode_sltu(state, rd, rs1, rs2); - } else { - asm_rv32_opcode_slt(state, rd, rs1, rs2); - } + // slt[u] rd, rs2, rs1 + // xori rd, rd, 1 + asm_rv32_meta_comparison_lt(state, rs2, rs1, rd, unsigned_comparison); + asm_rv32_opcode_xori(state, rd, rd, 1); } #endif // MICROPY_EMIT_RV32 diff --git a/py/asmrv32.h b/py/asmrv32.h index b09f48eb12f..6f709daa11b 100644 --- a/py/asmrv32.h +++ b/py/asmrv32.h @@ -122,6 +122,18 @@ typedef struct _asm_rv32_t { mp_uint_t locals_stack_offset; } asm_rv32_t; +enum { + RV32_EXT_NONE = 0, + RV32_EXT_ZBA = 1 << 0, + + RV32_EXT_ALL = RV32_EXT_ZBA +}; + +typedef struct _asm_rv32_backend_options_t { + // This is a bitmask holding a combination of RV32_EXT_* entries. + uint8_t allowed_extensions; +} asm_rv32_backend_options_t; + void asm_rv32_entry(asm_rv32_t *state, mp_uint_t locals); void asm_rv32_exit(asm_rv32_t *state); void asm_rv32_end_pass(asm_rv32_t *state); @@ -583,6 +595,24 @@ static inline void asm_rv32_opcode_remu(asm_rv32_t *state, mp_uint_t rd, mp_uint asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x07, 0x01, rd, rs1, rs2)); } +// SH1ADD RD, RS1, RS2 +static inline void asm_rv32_opcode_sh1add(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0010000 ..... ..... 010 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x02, 0x10, rd, rs1, rs2)); +} + +// SH2ADD RD, RS1, RS2 +static inline void asm_rv32_opcode_sh2add(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0010000 ..... ..... 100 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x04, 0x10, rd, rs1, rs2)); +} + +// SH3ADD RD, RS1, RS2 +static inline void asm_rv32_opcode_sh3add(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { + // R: 0010000 ..... ..... 110 ..... 0110011 + asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_R(0x33, 0x06, 0x10, rd, rs1, rs2)); +} + // SLL RD, RS1, RS2 static inline void asm_rv32_opcode_sll(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2) { // R: 0000000 ..... ..... 001 ..... 0110011 @@ -679,6 +709,19 @@ static inline void asm_rv32_opcode_xori(asm_rv32_t *state, mp_uint_t rd, mp_uint asm_rv32_emit_word_opcode(state, RV32_ENCODE_TYPE_I(0x13, 0x04, rd, rs, immediate)); } +#define MICROPY_RV32_EXTENSIONS \ + (MICROPY_EMIT_RV32_ZBA ? RV32_EXT_ZBA : 0) + +static inline uint8_t asm_rv32_allowed_extensions(void) { + uint8_t extensions = MICROPY_RV32_EXTENSIONS; + #if MICROPY_DYNAMIC_COMPILER + if (mp_dynamic_compiler.backend_options != NULL) { + extensions |= ((asm_rv32_backend_options_t *)mp_dynamic_compiler.backend_options)->allowed_extensions; + } + #endif + return extensions; +} + #define ASM_WORD_SIZE (4) #define ASM_HALFWORD_SIZE (2) @@ -702,6 +745,8 @@ void asm_rv32_meta_comparison_lt(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2 void asm_rv32_meta_comparison_le(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t rd, bool unsigned_comparison); void asm_rv32_emit_optimised_load_immediate(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate); +void asm_rv32_emit_load_reg_reg_reg(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size); +void asm_rv32_emit_store_reg_reg_reg(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t operation_size); #ifdef GENERIC_ASM_API @@ -709,17 +754,16 @@ void asm_rv32_emit_call_ind(asm_rv32_t *state, mp_uint_t index); void asm_rv32_emit_jump(asm_rv32_t *state, mp_uint_t label); void asm_rv32_emit_jump_if_reg_eq(asm_rv32_t *state, mp_uint_t rs1, mp_uint_t rs2, mp_uint_t label); void asm_rv32_emit_jump_if_reg_nonzero(asm_rv32_t *state, mp_uint_t rs, mp_uint_t label); -void asm_rv32_emit_load16_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset); -void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, mp_int_t offset); +void asm_rv32_emit_load_reg_reg_offset(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs, int32_t offset, mp_uint_t operation_size); void asm_rv32_emit_mov_local_reg(asm_rv32_t *state, mp_uint_t local, mp_uint_t rs); void asm_rv32_emit_mov_reg_local_addr(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local); void asm_rv32_emit_mov_reg_local(asm_rv32_t *state, mp_uint_t rd, mp_uint_t local); void asm_rv32_emit_mov_reg_pcrel(asm_rv32_t *state, mp_uint_t rd, mp_uint_t label); void asm_rv32_emit_optimised_xor(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs); -void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_uint_t base, mp_int_t offset); +void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_uint_t base, int32_t offset, mp_uint_t operation_size); #define ASM_T asm_rv32_t -#define ASM_ENTRY(state, labels) asm_rv32_entry(state, labels) +#define ASM_ENTRY(state, labels, name) asm_rv32_entry(state, labels) #define ASM_EXIT(state) asm_rv32_exit(state) #define ASM_END_PASS(state) asm_rv32_end_pass(state) @@ -732,12 +776,13 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_ #define ASM_JUMP_IF_REG_NONZERO(state, rs, label, bool_test) asm_rv32_emit_jump_if_reg_nonzero(state, rs, label) #define ASM_JUMP_IF_REG_ZERO(state, rs, label, bool_test) asm_rv32_emit_jump_if_reg_eq(state, rs, ASM_RV32_REG_ZERO, label) #define ASM_JUMP_REG(state, rs) asm_rv32_opcode_cjr(state, rs) -#define ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load16_reg_reg_offset(state, rd, rs, offset) -#define ASM_LOAD16_REG_REG(state, rd, rs) asm_rv32_opcode_lhu(state, rd, rs, 0) -#define ASM_LOAD32_REG_REG(state, rd, rs) ASM_LOAD_REG_REG_OFFSET(state, rd, rs, 0) -#define ASM_LOAD8_REG_REG(state, rd, rs) asm_rv32_opcode_lbu(state, rd, rs, 0) -#define ASM_LOAD_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset) -#define ASM_LOAD_REG_REG(state, rd, rs) ASM_LOAD32_REG_REG(state, rd, rs) +#define ASM_LOAD_REG_REG_OFFSET(state, rd, rs, offset) ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) +#define ASM_LOAD8_REG_REG(state, rd, rs) ASM_LOAD8_REG_REG_OFFSET(state, rd, rs, 0) +#define ASM_LOAD16_REG_REG(state, rd, rs) ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, 0) +#define ASM_LOAD32_REG_REG(state, rd, rs) ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, 0) +#define ASM_LOAD8_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 0) +#define ASM_LOAD16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 1) +#define ASM_LOAD32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_load_reg_reg_offset(state, rd, rs, offset, 2) #define ASM_LSL_REG_REG(state, rd, rs) asm_rv32_opcode_sll(state, rd, rd, rs) #define ASM_LSR_REG_REG(state, rd, rs) asm_rv32_opcode_srl(state, rd, rd, rs) #define ASM_MOV_LOCAL_REG(state, local, rs) asm_rv32_emit_mov_local_reg(state, local, rs) @@ -750,14 +795,22 @@ void asm_rv32_emit_store_reg_reg_offset(asm_rv32_t *state, mp_uint_t source, mp_ #define ASM_NEG_REG(state, rd) asm_rv32_opcode_sub(state, rd, ASM_RV32_REG_ZERO, rd) #define ASM_NOT_REG(state, rd) asm_rv32_opcode_xori(state, rd, rd, -1) #define ASM_OR_REG_REG(state, rd, rs) asm_rv32_opcode_or(state, rd, rd, rs) -#define ASM_STORE16_REG_REG(state, rs1, rs2) asm_rv32_opcode_sh(state, rs1, rs2, 0) -#define ASM_STORE32_REG_REG(state, rs1, rs2) ASM_STORE_REG_REG_OFFSET(state, rs1, rs2, 0) -#define ASM_STORE8_REG_REG(state, rs1, rs2) asm_rv32_opcode_sb(state, rs1, rs2, 0) -#define ASM_STORE_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset) -#define ASM_STORE_REG_REG(state, rs1, rs2) ASM_STORE32_REG_REG(state, rs1, rs2) +#define ASM_STORE_REG_REG_OFFSET(state, rd, rs, offset) ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) +#define ASM_STORE8_REG_REG(state, rs1, rs2) ASM_STORE8_REG_REG_OFFSET(state, rs1, rs2, 0) +#define ASM_STORE16_REG_REG(state, rs1, rs2) ASM_STORE16_REG_REG_OFFSET(state, rs1, rs2, 0) +#define ASM_STORE32_REG_REG(state, rs1, rs2) ASM_STORE32_REG_REG_OFFSET(state, rs1, rs2, 0) +#define ASM_STORE8_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 0) +#define ASM_STORE16_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 1) +#define ASM_STORE32_REG_REG_OFFSET(state, rd, rs, offset) asm_rv32_emit_store_reg_reg_offset(state, rd, rs, offset, 2) #define ASM_SUB_REG_REG(state, rd, rs) asm_rv32_opcode_sub(state, rd, rd, rs) #define ASM_XOR_REG_REG(state, rd, rs) asm_rv32_emit_optimised_xor(state, rd, rs) #define ASM_CLR_REG(state, rd) +#define ASM_LOAD8_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 0) +#define ASM_LOAD16_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 1) +#define ASM_LOAD32_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_load_reg_reg_reg(state, rd, rs1, rs2, 2) +#define ASM_STORE8_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_store_reg_reg_reg(state, rd, rs1, rs2, 0) +#define ASM_STORE16_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_store_reg_reg_reg(state, rd, rs1, rs2, 1) +#define ASM_STORE32_REG_REG_REG(state, rd, rs1, rs2) asm_rv32_emit_store_reg_reg_reg(state, rd, rs1, rs2, 2) #endif diff --git a/py/asmthumb.c b/py/asmthumb.c index 420815e8026..58cc7aea880 100644 --- a/py/asmthumb.c +++ b/py/asmthumb.c @@ -37,7 +37,6 @@ #include "py/asmthumb.h" #include "py/misc.h" -#define UNSIGNED_FIT5(x) ((uint32_t)(x) < 32) #define UNSIGNED_FIT7(x) ((uint32_t)(x) < 128) #define UNSIGNED_FIT8(x) (((x) & 0xffffff00) == 0) #define UNSIGNED_FIT16(x) (((x) & 0xffff0000) == 0) @@ -52,12 +51,6 @@ #define OP_SUB_W_RRI_HI(reg_src) (0xf2a0 | (reg_src)) #define OP_SUB_W_RRI_LO(reg_dest, imm11) ((imm11 << 4 & 0x7000) | reg_dest << 8 | (imm11 & 0xff)) -#define OP_LDR_W_HI(reg_base) (0xf8d0 | (reg_base)) -#define OP_LDR_W_LO(reg_dest, imm12) ((reg_dest) << 12 | (imm12)) - -#define OP_LDRH_W_HI(reg_base) (0xf8b0 | (reg_base)) -#define OP_LDRH_W_LO(reg_dest, imm12) ((reg_dest) << 12 | (imm12)) - static inline byte *asm_thumb_get_cur_to_write_bytes(asm_thumb_t *as, int n) { return mp_asm_base_get_cur_to_write_bytes(&as->base, n); } @@ -274,9 +267,8 @@ bool asm_thumb_b_n_label(asm_thumb_t *as, uint label) { #define OP_BCC_N(cond, byte_offset) (0xd000 | ((cond) << 8) | (((byte_offset) >> 1) & 0x00ff)) -// all these bit-arithmetic operations need coverage testing! -#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 14) & 0x003f)) -#define OP_BCC_W_LO(byte_offset) (0x8000 | ((byte_offset) & 0x2000) | (((byte_offset) >> 1) & 0x0fff)) +#define OP_BCC_W_HI(cond, byte_offset) (0xf000 | ((cond) << 6) | (((byte_offset) >> 10) & 0x0400) | (((byte_offset) >> 12) & 0x003f)) +#define OP_BCC_W_LO(byte_offset) (0x8000 | (((byte_offset) >> 5) & 0x2000) | (((byte_offset) >> 8) & 0x0800) | (((byte_offset) >> 1) & 0x07ff)) bool asm_thumb_bcc_nw_label(asm_thumb_t *as, int cond, uint label, bool wide) { mp_uint_t dest = get_label_dest(as, label); @@ -432,11 +424,6 @@ void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label) { asm_thumb_add_reg_reg(as, rlo_dest, ASM_THUMB_REG_R15); // 2 bytes } -// ARMv7-M only -static inline void asm_thumb_ldr_reg_reg_i12(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) { - asm_thumb_op32(as, OP_LDR_W_HI(reg_base), OP_LDR_W_LO(reg_dest, word_offset * 4)); -} - // emits code for: reg_dest = reg_base + offset << offset_shift static void asm_thumb_add_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint offset_shift) { if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8) { @@ -450,12 +437,12 @@ static void asm_thumb_add_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint re asm_thumb_lsl_rlo_rlo_i5(as, reg_dest, reg_dest, offset_shift); asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_base); } else if (reg_dest != reg_base) { - asm_thumb_mov_rlo_i16(as, reg_dest, offset << offset_shift); - asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_dest); + asm_thumb_mov_reg_i32_optimised(as, reg_dest, offset << offset_shift); + asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_base); } else { uint reg_other = reg_dest ^ 7; asm_thumb_op16(as, OP_PUSH_RLIST((1 << reg_other))); - asm_thumb_mov_rlo_i16(as, reg_other, offset << offset_shift); + asm_thumb_mov_reg_i32_optimised(as, reg_other, offset << offset_shift); asm_thumb_add_rlo_rlo_rlo(as, reg_dest, reg_dest, reg_other); asm_thumb_op16(as, OP_POP_RLIST((1 << reg_other))); } @@ -464,30 +451,50 @@ static void asm_thumb_add_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint re } } -void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset) { - if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5(word_offset)) { - asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_base, word_offset); - } else if (asm_thumb_allow_armv7m(as)) { - asm_thumb_ldr_reg_reg_i12(as, reg_dest, reg_base, word_offset); +#define OP_LDR_STR_W_HI(operation_size, reg) ((0xf880 | (operation_size) << 5) | (reg)) +#define OP_LDR_STR_W_LO(reg, imm12) (((reg) << 12) | (imm12)) + +#define OP_LDR 0x01 +#define OP_STR 0x00 + +#define OP_LDR_W 0x10 +#define OP_STR_W 0x00 + +static const uint8_t OP_LDR_STR_TABLE[3] = { + 0x0E, 0x10, 0x0C +}; + +void asm_thumb_load_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size out of range."); + + if (MP_FIT_UNSIGNED(5, offset) && (reg_dest < ASM_THUMB_REG_R8) && (reg_base < ASM_THUMB_REG_R8)) { + // Can use T1 encoding + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_LDR) << 11) | (offset << 6) | (reg_base << 3) | reg_dest); + } else if (asm_thumb_allow_armv7m(as) && MP_FIT_UNSIGNED(12, offset << operation_size)) { + // Can use T3 encoding + asm_thumb_op32(as, (OP_LDR_STR_W_HI(operation_size, reg_base) | OP_LDR_W), OP_LDR_STR_W_LO(reg_dest, (offset << operation_size))); } else { - asm_thumb_add_reg_reg_offset(as, reg_dest, reg_base, word_offset - 31, 2); - asm_thumb_ldr_rlo_rlo_i5(as, reg_dest, reg_dest, 31); + // Must use the generic sequence + asm_thumb_add_reg_reg_offset(as, reg_dest, reg_base, offset - 31, operation_size); + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_LDR) << 11) | (31 << 6) | (reg_dest << 3) | (reg_dest)); } } -// ARMv7-M only -static inline void asm_thumb_ldrh_reg_reg_i12(asm_thumb_t *as, uint reg_dest, uint reg_base, uint uint16_offset) { - asm_thumb_op32(as, OP_LDRH_W_HI(reg_base), OP_LDRH_W_LO(reg_dest, uint16_offset * 2)); -} +void asm_thumb_store_reg_reg_offset(asm_thumb_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size out of range."); -void asm_thumb_ldrh_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint uint16_offset) { - if (reg_dest < ASM_THUMB_REG_R8 && reg_base < ASM_THUMB_REG_R8 && UNSIGNED_FIT5(uint16_offset)) { - asm_thumb_ldrh_rlo_rlo_i5(as, reg_dest, reg_base, uint16_offset); - } else if (asm_thumb_allow_armv7m(as)) { - asm_thumb_ldrh_reg_reg_i12(as, reg_dest, reg_base, uint16_offset); + if (MP_FIT_UNSIGNED(5, offset) && (reg_src < ASM_THUMB_REG_R8) && (reg_base < ASM_THUMB_REG_R8)) { + // Can use T1 encoding + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_STR) << 11) | (offset << 6) | (reg_base << 3) | reg_src); + } else if (asm_thumb_allow_armv7m(as) && MP_FIT_UNSIGNED(12, offset << operation_size)) { + // Can use T3 encoding + asm_thumb_op32(as, (OP_LDR_STR_W_HI(operation_size, reg_base) | OP_STR_W), OP_LDR_STR_W_LO(reg_src, (offset << operation_size))); } else { - asm_thumb_add_reg_reg_offset(as, reg_dest, reg_base, uint16_offset - 31, 1); - asm_thumb_ldrh_rlo_rlo_i5(as, reg_dest, reg_dest, 31); + // Must use the generic sequence + asm_thumb_op16(as, OP_PUSH_RLIST(1 << reg_base)); + asm_thumb_add_reg_reg_offset(as, reg_base, reg_base, offset - 31, operation_size); + asm_thumb_op16(as, ((OP_LDR_STR_TABLE[operation_size] | OP_STR) << 11) | (31 << 6) | (reg_base << 3) | reg_src); + asm_thumb_op16(as, OP_POP_RLIST(1 << reg_base)); } } @@ -495,6 +502,7 @@ void asm_thumb_ldrh_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint r #define OP_BW_HI(byte_offset) (0xf000 | (((byte_offset) >> 12) & 0x07ff)) #define OP_BW_LO(byte_offset) (0xb800 | (((byte_offset) >> 1) & 0x07ff)) +// In Thumb1 mode, this may clobber r1. void asm_thumb_b_label(asm_thumb_t *as, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; @@ -514,19 +522,40 @@ void asm_thumb_b_label(asm_thumb_t *as, uint label) { if (asm_thumb_allow_armv7m(as)) { asm_thumb_op32(as, OP_BW_HI(rel), OP_BW_LO(rel)); } else { + // this code path has to be the same instruction size irrespective of the value of rel + bool need_align = as->base.code_offset & 2u; if (SIGNED_FIT12(rel)) { - // this code path has to be the same number of instructions irrespective of rel asm_thumb_op16(as, OP_B_N(rel)); - } else { asm_thumb_op16(as, ASM_THUMB_OP_NOP); - if (dest != (mp_uint_t)-1) { - // we have an actual branch > 12 bits; this is not handled yet - mp_raise_NotImplementedError(MP_ERROR_TEXT("native method too big")); + asm_thumb_op16(as, ASM_THUMB_OP_NOP); + asm_thumb_op16(as, ASM_THUMB_OP_NOP); + if (need_align) { + asm_thumb_op16(as, ASM_THUMB_OP_NOP); + } + } else { + // do a large jump using: + // (nop) + // ldr r1, [pc, _data] + // add pc, r1 + // _data: .word rel + // + // note: can't use r0 as a temporary because native code can have the return value + // in that register and use a large jump to get to the exit point of the function + + rel -= 2; // account for the "ldr r1, [pc, _data]" + if (need_align) { + asm_thumb_op16(as, ASM_THUMB_OP_NOP); + rel -= 2; // account for this nop } + asm_thumb_ldr_rlo_pcrel_i8(as, ASM_THUMB_REG_R1, 0); + asm_thumb_add_reg_reg(as, ASM_THUMB_REG_R15, ASM_THUMB_REG_R1); + asm_thumb_op16(as, rel & 0xffff); + asm_thumb_op16(as, rel >> 16); } } } +// In Thumb1 mode, this may clobber r1. void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { mp_uint_t dest = get_label_dest(as, label); mp_int_t rel = dest - as->base.code_offset; @@ -547,8 +576,15 @@ void asm_thumb_bcc_label(asm_thumb_t *as, int cond, uint label) { asm_thumb_op32(as, OP_BCC_W_HI(cond, rel), OP_BCC_W_LO(rel)); } else { // reverse the sense of the branch to jump over a longer branch - asm_thumb_op16(as, OP_BCC_N(cond ^ 1, 0)); + size_t code_offset_start = as->base.code_offset; + byte *c = asm_thumb_get_cur_to_write_bytes(as, 2); asm_thumb_b_label(as, label); + size_t bytes_to_skip = as->base.code_offset - code_offset_start; + uint16_t op = OP_BCC_N(cond ^ 1, bytes_to_skip - 4); + if (c != NULL) { + c[0] = op; + c[1] = op >> 8; + } } } @@ -569,7 +605,7 @@ void asm_thumb_b_rel12(asm_thumb_t *as, int rel) { void asm_thumb_bl_ind(asm_thumb_t *as, uint fun_id, uint reg_temp) { // Load ptr to function from table, indexed by fun_id, then call it - asm_thumb_ldr_reg_reg_i12_optimised(as, reg_temp, ASM_THUMB_REG_FUN_TABLE, fun_id); + asm_thumb_load_reg_reg_offset(as, reg_temp, ASM_THUMB_REG_FUN_TABLE, fun_id, 2); asm_thumb_op16(as, OP_BLX(reg_temp)); } diff --git a/py/asmthumb.h b/py/asmthumb.h index 0584ed3227a..cb786694f0b 100644 --- a/py/asmthumb.h +++ b/py/asmthumb.h @@ -251,6 +251,50 @@ static inline void asm_thumb_bx_reg(asm_thumb_t *as, uint r_src) { asm_thumb_format_5(as, ASM_THUMB_FORMAT_5_BX, 0, r_src); } +// FORMAT 7: load/store with register offset +// FORMAT 8: load/store sign-extended byte/halfword + +#define ASM_THUMB_FORMAT_7_LDR (0x5800) +#define ASM_THUMB_FORMAT_7_STR (0x5000) +#define ASM_THUMB_FORMAT_7_WORD_TRANSFER (0x0000) +#define ASM_THUMB_FORMAT_7_BYTE_TRANSFER (0x0400) +#define ASM_THUMB_FORMAT_8_LDRH (0x5A00) +#define ASM_THUMB_FORMAT_8_STRH (0x5200) + +#define ASM_THUMB_FORMAT_7_8_ENCODE(op, rlo_dest, rlo_base, rlo_index) \ + ((op) | ((rlo_index) << 6) | ((rlo_base) << 3) | ((rlo_dest))) + +static inline void asm_thumb_format_7_8(asm_thumb_t *as, uint op, uint rlo_dest, uint rlo_base, uint rlo_index) { + assert(rlo_dest < ASM_THUMB_REG_R8); + assert(rlo_base < ASM_THUMB_REG_R8); + assert(rlo_index < ASM_THUMB_REG_R8); + asm_thumb_op16(as, ASM_THUMB_FORMAT_7_8_ENCODE(op, rlo_dest, rlo_base, rlo_index)); +} + +static inline void asm_thumb_ldrb_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_LDR | ASM_THUMB_FORMAT_7_BYTE_TRANSFER, rlo_dest, rlo_base, rlo_index); +} + +static inline void asm_thumb_ldrh_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_8_LDRH, rlo_dest, rlo_base, rlo_index); +} + +static inline void asm_thumb_ldr_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_LDR | ASM_THUMB_FORMAT_7_WORD_TRANSFER, rlo_dest, rlo_base, rlo_index); +} + +static inline void asm_thumb_strb_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_STR | ASM_THUMB_FORMAT_7_BYTE_TRANSFER, rlo_src, rlo_base, rlo_index); +} + +static inline void asm_thumb_strh_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_8_STRH, rlo_dest, rlo_base, rlo_index); +} + +static inline void asm_thumb_str_rlo_rlo_rlo(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint rlo_index) { + asm_thumb_format_7_8(as, ASM_THUMB_FORMAT_7_STR | ASM_THUMB_FORMAT_7_WORD_TRANSFER, rlo_src, rlo_base, rlo_index); +} + // FORMAT 9: load/store with immediate offset // For word transfers the offset must be aligned, and >>2 @@ -273,24 +317,6 @@ static inline void asm_thumb_format_9_10(asm_thumb_t *as, uint op, uint rlo_dest asm_thumb_op16(as, ASM_THUMB_FORMAT_9_10_ENCODE(op, rlo_dest, rlo_base, offset)); } -static inline void asm_thumb_str_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint word_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_src, rlo_base, word_offset); -} -static inline void asm_thumb_strb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint byte_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_STR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_src, rlo_base, byte_offset); -} -static inline void asm_thumb_strh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_src, uint rlo_base, uint uint16_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_STRH, rlo_src, rlo_base, uint16_offset); -} -static inline void asm_thumb_ldr_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint word_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_WORD_TRANSFER, rlo_dest, rlo_base, word_offset); -} -static inline void asm_thumb_ldrb_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint byte_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_9_LDR | ASM_THUMB_FORMAT_9_BYTE_TRANSFER, rlo_dest, rlo_base, byte_offset); -} -static inline void asm_thumb_ldrh_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_base, uint uint16_offset) { - asm_thumb_format_9_10(as, ASM_THUMB_FORMAT_10_LDRH, rlo_dest, rlo_base, uint16_offset); -} static inline void asm_thumb_lsl_rlo_rlo_i5(asm_thumb_t *as, uint rlo_dest, uint rlo_src, uint shift) { asm_thumb_format_1(as, ASM_THUMB_FORMAT_1_LSL, rlo_dest, rlo_src, shift); } @@ -338,8 +364,10 @@ void asm_thumb_mov_reg_local(asm_thumb_t *as, uint rlo_dest, int local_num); // void asm_thumb_mov_reg_local_addr(asm_thumb_t *as, uint rlo_dest, int local_num); // convenience void asm_thumb_mov_reg_pcrel(asm_thumb_t *as, uint rlo_dest, uint label); -void asm_thumb_ldr_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint word_offset); // convenience -void asm_thumb_ldrh_reg_reg_i12_optimised(asm_thumb_t *as, uint reg_dest, uint reg_base, uint uint16_offset); // convenience +// Generate optimised load dest, [src, #offset] sequence +void asm_thumb_load_reg_reg_offset(asm_thumb_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size); +// Generate optimised store src, [dest, #offset] sequence +void asm_thumb_store_reg_reg_offset(asm_thumb_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size); void asm_thumb_b_label(asm_thumb_t *as, uint label); // convenience: picks narrow or wide branch void asm_thumb_bcc_label(asm_thumb_t *as, int cc, uint label); // convenience: picks narrow or wide branch @@ -376,12 +404,12 @@ void asm_thumb_b_rel12(asm_thumb_t *as, int rel); #define REG_FUN_TABLE ASM_THUMB_REG_FUN_TABLE -#define ASM_T asm_thumb_t -#define ASM_END_PASS asm_thumb_end_pass -#define ASM_ENTRY asm_thumb_entry -#define ASM_EXIT asm_thumb_exit +#define ASM_T asm_thumb_t +#define ASM_END_PASS asm_thumb_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_thumb_entry((as), (num_locals)) +#define ASM_EXIT asm_thumb_exit -#define ASM_JUMP asm_thumb_b_label +#define ASM_JUMP asm_thumb_b_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ asm_thumb_cmp_rlo_i8(as, reg, 0); \ @@ -419,18 +447,44 @@ void asm_thumb_b_rel12(asm_thumb_t *as, int rel); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_thumb_sub_rlo_rlo_rlo((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_thumb_format_4((as), ASM_THUMB_FORMAT_4_MUL, (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_thumb_ldr_reg_reg_i12_optimised((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrb_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_thumb_ldrh_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_thumb_ldrh_reg_reg_i12_optimised((as), (reg_dest), (reg_base), (uint16_offset)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_thumb_ldr_rlo_rlo_i5((as), (reg_dest), (reg_base), 0) - -#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_thumb_strb_rlo_rlo_i5((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_thumb_strh_rlo_rlo_i5((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_thumb_str_rlo_rlo_i5((as), (reg_src), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_thumb_load_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset), 0) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_thumb_load_reg_reg_offset((as), (reg_dest), (reg_base), (halfword_offset), 1) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_thumb_load_reg_reg_offset((as), (reg_dest), (reg_base), (word_offset), 2) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_thumb_store_reg_reg_offset((as), (reg_src), (reg_base), (byte_offset), 0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, halfword_offset) asm_thumb_store_reg_reg_offset((as), (reg_src), (reg_base), (halfword_offset), 1) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_thumb_store_reg_reg_offset((as), (reg_src), (reg_base), (word_offset), 2) + +#define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) asm_thumb_ldrb_rlo_rlo_rlo((as), (reg_dest), (reg_base), (reg_index)) +#define ASM_LOAD16_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_thumb_lsl_rlo_rlo_i5((as), (reg_index), (reg_index), 1); \ + asm_thumb_ldrh_rlo_rlo_rlo((as), (reg_dest), (reg_base), (reg_index)); \ + } while (0) +#define ASM_LOAD32_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_thumb_lsl_rlo_rlo_i5((as), (reg_index), (reg_index), 2); \ + asm_thumb_ldr_rlo_rlo_rlo((as), (reg_dest), (reg_base), (reg_index)); \ + } while (0) +#define ASM_STORE8_REG_REG_REG(as, reg_val, reg_base, reg_index) asm_thumb_strb_rlo_rlo_rlo((as), (reg_val), (reg_base), (reg_index)) +#define ASM_STORE16_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_thumb_lsl_rlo_rlo_i5((as), (reg_index), (reg_index), 1); \ + asm_thumb_strh_rlo_rlo_rlo((as), (reg_val), (reg_base), (reg_index)); \ + } while (0) +#define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_thumb_lsl_rlo_rlo_i5((as), (reg_index), (reg_index), 2); \ + asm_thumb_str_rlo_rlo_rlo((as), (reg_val), (reg_base), (reg_index)); \ + } while (0) #endif // GENERIC_ASM_API diff --git a/py/asmx64.h b/py/asmx64.h index 03070b5f63d..1e8cb0c905f 100644 --- a/py/asmx64.h +++ b/py/asmx64.h @@ -155,12 +155,12 @@ void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32); // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_X64_REG_FUN_TABLE -#define ASM_T asm_x64_t -#define ASM_END_PASS asm_x64_end_pass -#define ASM_ENTRY asm_x64_entry -#define ASM_EXIT asm_x64_exit +#define ASM_T asm_x64_t +#define ASM_END_PASS asm_x64_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_x64_entry((as), (num_locals)) +#define ASM_EXIT asm_x64_exit -#define ASM_JUMP asm_x64_jmp_label +#define ASM_JUMP asm_x64_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ if (bool_test) { \ @@ -206,18 +206,21 @@ void asm_x64_call_ind(asm_x64_t *as, size_t fun_id, int temp_r32); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x64_sub_r64_r64((as), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x64_mul_r64_r64((as), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem64_to_r64((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (word_offset), (reg_dest)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem8_to_r64zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 2 * (uint16_offset), (reg_dest)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x64_mov_mem32_to_r64zx((as), (reg_base), 0, (reg_dest)) - -#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, qword_offset) asm_x64_mov_mem64_to_r64((as), (reg_base), 8 * (qword_offset), (reg_dest)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_x64_mov_mem8_to_r64zx((as), (reg_base), (byte_offset), (reg_dest)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x64_mov_mem16_to_r64zx((as), (reg_base), 2 * (word_offset), (reg_dest)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) asm_x64_mov_mem32_to_r64zx((as), (reg_base), 4 * (dword_offset), (reg_dest)) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, qword_offset) asm_x64_mov_r64_to_mem64((as), (reg_src), (reg_base), 8 * (qword_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_x64_mov_r8_to_mem8((as), (reg_src), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x64_mov_r16_to_mem16((as), (reg_src), (reg_base), 2 * (word_offset)) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) asm_x64_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (dword_offset)) #endif // GENERIC_ASM_API diff --git a/py/asmx86.h b/py/asmx86.h index 7796d697626..f5d37228a2f 100644 --- a/py/asmx86.h +++ b/py/asmx86.h @@ -150,12 +150,12 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r // Holds a pointer to mp_fun_table #define REG_FUN_TABLE ASM_X86_REG_FUN_TABLE -#define ASM_T asm_x86_t -#define ASM_END_PASS asm_x86_end_pass -#define ASM_ENTRY asm_x86_entry -#define ASM_EXIT asm_x86_exit +#define ASM_T asm_x86_t +#define ASM_END_PASS asm_x86_end_pass +#define ASM_ENTRY(as, num_locals, name) asm_x86_entry((as), (num_locals)) +#define ASM_EXIT asm_x86_exit -#define ASM_JUMP asm_x86_jmp_label +#define ASM_JUMP asm_x86_jmp_label #define ASM_JUMP_IF_REG_ZERO(as, reg, label, bool_test) \ do { \ if (bool_test) { \ @@ -201,18 +201,21 @@ void asm_x86_call_ind(asm_x86_t *as, size_t fun_id, mp_uint_t n_args, int temp_r #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_x86_sub_r32_r32((as), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_x86_mul_r32_r32((as), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (word_offset), (reg_dest)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem8_to_r32zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 0, (reg_dest)) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 2 * (uint16_offset), (reg_dest)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_x86_mov_mem32_to_r32((as), (reg_base), 0, (reg_dest)) - -#define ASM_STORE_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (dword_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_x86_mov_mem8_to_r32zx((as), (reg_base), (byte_offset), (reg_dest)) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_x86_mov_mem16_to_r32zx((as), (reg_base), 2 * (word_offset), (reg_dest)) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, dword_offset) asm_x86_mov_mem32_to_r32((as), (reg_base), 4 * (dword_offset), (reg_dest)) + +#define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), (dword_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_x86_mov_r8_to_mem8((as), (reg_src), (reg_base), (byte_offset)) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) asm_x86_mov_r16_to_mem16((as), (reg_src), (reg_base), 2 * (word_offset)) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_src, reg_base, dword_offset) asm_x86_mov_r32_to_mem32((as), (reg_src), (reg_base), 4 * (dword_offset)) #endif // GENERIC_ASM_API diff --git a/py/asmxtensa.c b/py/asmxtensa.c index 0fbe351dcf3..bc3e717d9f3 100644 --- a/py/asmxtensa.c +++ b/py/asmxtensa.c @@ -34,9 +34,20 @@ #include "py/asmxtensa.h" +#if N_XTENSAWIN +#define REG_TEMP ASM_XTENSA_REG_TEMPORARY_WIN +#else +#define REG_TEMP ASM_XTENSA_REG_TEMPORARY +#endif + #define WORD_SIZE (4) +#define SIGNED_FIT6(x) ((((x) & 0xffffffe0) == 0) || (((x) & 0xffffffe0) == 0xffffffe0)) #define SIGNED_FIT8(x) ((((x) & 0xffffff80) == 0) || (((x) & 0xffffff80) == 0xffffff80)) #define SIGNED_FIT12(x) ((((x) & 0xfffff800) == 0) || (((x) & 0xfffff800) == 0xfffff800)) +#define SIGNED_FIT18(x) ((((x) & 0xfffe0000) == 0) || (((x) & 0xfffe0000) == 0xfffe0000)) + +#define ET_OUT_OF_RANGE MP_ERROR_TEXT("ERROR: xtensa %q out of range") +#define ET_NOT_ALIGNED MP_ERROR_TEXT("ERROR: %q %q not word-aligned") void asm_xtensa_end_pass(asm_xtensa_t *as) { as->num_const = as->cur_const; @@ -47,9 +58,9 @@ void asm_xtensa_end_pass(asm_xtensa_t *as) { if (as->base.pass == MP_ASM_PASS_EMIT) { uint8_t *d = as->base.code_base; printf("XTENSA ASM:"); - for (int i = 0; i < ((as->base.code_size + 15) & ~15); ++i) { + for (size_t i = 0; i < ((as->base.code_size + 15) & ~15); ++i) { if (i % 16 == 0) { - printf("\n%08x:", (uint32_t)&d[i]); + printf("\n%p:", &d[i]); } if (i % 2 == 0) { printf(" "); @@ -62,10 +73,12 @@ void asm_xtensa_end_pass(asm_xtensa_t *as) { } void asm_xtensa_entry(asm_xtensa_t *as, int num_locals) { - // jump over the constants - asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); - mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte - as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + if (as->num_const > 0) { + // jump over the constants + asm_xtensa_op_j(as, as->num_const * WORD_SIZE + 4 - 4); + mp_asm_base_get_cur_to_write_bytes(&as->base, 1); // padding/alignment byte + as->const_table = (uint32_t *)mp_asm_base_get_cur_to_write_bytes(&as->base, as->num_const * 4); + } // adjust the stack-pointer to store a0, a12, a13, a14, a15 and locals, 16-byte aligned as->stack_adjust = (((ASM_XTENSA_NUM_REGS_SAVED + num_locals) * WORD_SIZE) + 15) & ~15; @@ -146,22 +159,60 @@ void asm_xtensa_j_label(asm_xtensa_t *as, uint label) { asm_xtensa_op_j(as, rel); } +static bool calculate_branch_displacement(asm_xtensa_t *as, uint label, ptrdiff_t *displacement) { + assert(displacement != NULL && "Displacement pointer is NULL"); + + uint32_t label_offset = get_label_dest(as, label); + *displacement = (ptrdiff_t)(label_offset - as->base.code_offset - 4); + return (label_offset != (uint32_t)-1) && (*displacement < 0); +} + void asm_xtensa_bccz_reg_label(asm_xtensa_t *as, uint cond, uint reg, uint label) { - uint32_t dest = get_label_dest(as, label); - int32_t rel = dest - as->base.code_offset - 4; - if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT12(rel)) { - printf("ERROR: xtensa bccz out of range\n"); + ptrdiff_t rel = 0; + bool can_emit_short_jump = calculate_branch_displacement(as, label, &rel); + + if (can_emit_short_jump && SIGNED_FIT12(rel)) { + // Backwards BCCZ opcodes with an offset that fits in 12 bits can + // be emitted without any change. + asm_xtensa_op_bccz(as, cond, reg, rel); + return; } - asm_xtensa_op_bccz(as, cond, reg, rel); + + // Range is effectively extended to 18 bits, as a more complex jump code + // sequence is emitted. + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT18(rel - 6)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_bccz); + } + + // ~BCCZ skip ; +0 <- Condition is flipped here (EQ -> NE, etc.) + // J addr ; +3 + // skip: ; +6 + asm_xtensa_op_bccz(as, cond ^ 1, reg, 6 - 4); + asm_xtensa_op_j(as, rel - 3); } void asm_xtensa_bcc_reg_reg_label(asm_xtensa_t *as, uint cond, uint reg1, uint reg2, uint label) { - uint32_t dest = get_label_dest(as, label); - int32_t rel = dest - as->base.code_offset - 4; - if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT8(rel)) { - printf("ERROR: xtensa bcc out of range\n"); + ptrdiff_t rel = 0; + bool can_emit_short_jump = calculate_branch_displacement(as, label, &rel); + + if (can_emit_short_jump && SIGNED_FIT8(rel)) { + // Backwards BCC opcodes with an offset that fits in 8 bits can + // be emitted without any change. + asm_xtensa_op_bcc(as, cond, reg1, reg2, rel); + return; + } + + // Range is effectively extended to 18 bits, as a more complex jump code + // sequence is emitted. + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT18(rel - 6)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_bcc); } - asm_xtensa_op_bcc(as, cond, reg1, reg2, rel); + + // ~BCC skip ; +0 <- Condition is flipped here (EQ -> NE, etc.) + // J addr ; +3 + // skip: ; +6 + asm_xtensa_op_bcc(as, cond ^ 8, reg1, reg2, 6 - 4); + asm_xtensa_op_j(as, rel - 3); } // convenience function; reg_dest must be different from reg_src[12] @@ -179,6 +230,8 @@ size_t asm_xtensa_mov_reg_i32(asm_xtensa_t *as, uint reg_dest, uint32_t i32) { // store the constant in the table if (as->const_table != NULL) { as->const_table[as->cur_const] = i32; + } else { + assert((as->base.pass != MP_ASM_PASS_EMIT) && "Constants table was not built."); } ++as->cur_const; return loc; @@ -240,17 +293,53 @@ void asm_xtensa_l32i_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, u } else if (word_offset < 256) { asm_xtensa_op_l32i(as, reg_dest, reg_base, word_offset); } else { - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("asm overflow")); + asm_xtensa_mov_reg_i32_optimised(as, reg_dest, word_offset * 4); + asm_xtensa_op_add_n(as, reg_dest, reg_base, reg_dest); + asm_xtensa_op_l32i_n(as, reg_dest, reg_dest, 0); } } -void asm_xtensa_s32i_optimised(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset) { - if (word_offset < 16) { - asm_xtensa_op_s32i_n(as, reg_src, reg_base, word_offset); - } else if (word_offset < 256) { - asm_xtensa_op_s32i(as, reg_src, reg_base, word_offset); +void asm_xtensa_load_reg_reg_offset(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + if (operation_size == 2 && MP_FIT_UNSIGNED(4, offset)) { + asm_xtensa_op_l32i_n(as, reg_dest, reg_base, offset); + return; + } + + if (MP_FIT_UNSIGNED(8, offset)) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, operation_size, reg_base, reg_dest, offset)); + return; + } + + asm_xtensa_mov_reg_i32_optimised(as, reg_dest, offset << operation_size); + asm_xtensa_op_add_n(as, reg_dest, reg_base, reg_dest); + if (operation_size == 2) { + asm_xtensa_op_l32i_n(as, reg_dest, reg_dest, 0); } else { - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("asm overflow")); + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, operation_size, reg_dest, reg_dest, 0)); + } +} + +void asm_xtensa_store_reg_reg_offset(asm_xtensa_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size) { + assert(operation_size <= 2 && "Operation size value out of range."); + + if (operation_size == 2 && MP_FIT_UNSIGNED(4, offset)) { + asm_xtensa_op_s32i_n(as, reg_src, reg_base, offset); + return; + } + + if (MP_FIT_UNSIGNED(8, offset)) { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0x04 | operation_size, reg_base, reg_src, offset)); + return; + } + + asm_xtensa_mov_reg_i32_optimised(as, REG_TEMP, offset << operation_size); + asm_xtensa_op_add_n(as, REG_TEMP, reg_base, REG_TEMP); + if (operation_size == 2) { + asm_xtensa_op_s32i_n(as, reg_src, REG_TEMP, 0); + } else { + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(2, 0x04 | operation_size, REG_TEMP, reg_src, 0)); } } @@ -264,4 +353,47 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx) { asm_xtensa_op_callx8(as, ASM_XTENSA_REG_A8); } +void asm_xtensa_bit_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t bit, mp_uint_t label, mp_uint_t condition) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset - 4; + if (as->base.pass == MP_ASM_PASS_EMIT && !SIGNED_FIT8(rel)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_bit_branch); + } + asm_xtensa_op24(as, ASM_XTENSA_ENCODE_RRI8(7, condition | ((bit >> 4) & 0x01), reg, bit & 0x0F, rel & 0xFF)); +} + +void asm_xtensa_call0(asm_xtensa_t *as, mp_uint_t label) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset - 3; + if (as->base.pass == MP_ASM_PASS_EMIT) { + if ((dest & 0x03) != 0) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_call0, MP_QSTR_target); + } + if ((rel & 0x03) != 0) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_call0, MP_QSTR_location); + } + if (!SIGNED_FIT18(rel)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_call0); + } + } + asm_xtensa_op_call0(as, rel); +} + +void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label) { + uint32_t dest = get_label_dest(as, label); + int32_t rel = dest - as->base.code_offset; + if (as->base.pass == MP_ASM_PASS_EMIT) { + if ((dest & 0x03) != 0) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_l32r, MP_QSTR_target); + } + if ((rel & 0x03) != 0) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_NOT_ALIGNED, MP_QSTR_l32r, MP_QSTR_location); + } + if (!SIGNED_FIT18(rel) || (rel >= 0)) { + mp_raise_msg_varg(&mp_type_RuntimeError, ET_OUT_OF_RANGE, MP_QSTR_l32r); + } + } + asm_xtensa_op_l32r(as, reg, as->base.code_offset, dest); +} + #endif // MICROPY_EMIT_XTENSA || MICROPY_EMIT_INLINE_XTENSA || MICROPY_EMIT_XTENSAWIN diff --git a/py/asmxtensa.h b/py/asmxtensa.h index a8c39206bd0..559b3cacd5d 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -64,9 +64,11 @@ #define ASM_XTENSA_REG_A14 (14) #define ASM_XTENSA_REG_A15 (15) -// for bccz +// for bccz and bcci #define ASM_XTENSA_CCZ_EQ (0) #define ASM_XTENSA_CCZ_NE (1) +#define ASM_XTENSA_CCZ_LT (2) +#define ASM_XTENSA_CCZ_GE (3) // for bcc and setcc #define ASM_XTENSA_CC_NONE (0) @@ -291,17 +293,25 @@ void asm_xtensa_mov_local_reg(asm_xtensa_t *as, int local_num, uint reg_src); void asm_xtensa_mov_reg_local(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_local_addr(asm_xtensa_t *as, uint reg_dest, int local_num); void asm_xtensa_mov_reg_pcrel(asm_xtensa_t *as, uint reg_dest, uint label); -void asm_xtensa_l32i_optimised(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint word_offset); -void asm_xtensa_s32i_optimised(asm_xtensa_t *as, uint reg_src, uint reg_base, uint word_offset); +void asm_xtensa_load_reg_reg_offset(asm_xtensa_t *as, uint reg_dest, uint reg_base, uint offset, uint operation_size); +void asm_xtensa_store_reg_reg_offset(asm_xtensa_t *as, uint reg_src, uint reg_base, uint offset, uint operation_size); void asm_xtensa_call_ind(asm_xtensa_t *as, uint idx); void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); +void asm_xtensa_bit_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t bit, mp_uint_t label, mp_uint_t condition); +void asm_xtensa_immediate_branch(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t immediate, mp_uint_t label, mp_uint_t cond); +void asm_xtensa_call0(asm_xtensa_t *as, mp_uint_t label); +void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label); // Holds a pointer to mp_fun_table #define ASM_XTENSA_REG_FUN_TABLE ASM_XTENSA_REG_A15 #define ASM_XTENSA_REG_FUN_TABLE_WIN ASM_XTENSA_REG_A7 -// CIRCUITPY-CHANGE: prevent #if warning -#if defined(GENERIC_ASM_API) && GENERIC_ASM_API +// Internal temporary register (currently aliased to REG_ARG_5 for xtensa, +// and to REG_TEMP2 for xtensawin). +#define ASM_XTENSA_REG_TEMPORARY ASM_XTENSA_REG_A6 +#define ASM_XTENSA_REG_TEMPORARY_WIN ASM_XTENSA_REG_A12 + +#if GENERIC_ASM_API // The following macros provide a (mostly) arch-independent API to // generate native code, and are used by the native emitter. @@ -330,9 +340,9 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); #define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED #define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE -#define ASM_ENTRY(as, nlocal) asm_xtensa_entry((as), (nlocal)) -#define ASM_EXIT(as) asm_xtensa_exit((as)) -#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) +#define ASM_ENTRY(as, nlocal, name) asm_xtensa_entry((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind((as), (idx)) #else // Configuration for windowed calls with window size 8 @@ -360,9 +370,9 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); #define ASM_NUM_REGS_SAVED ASM_XTENSA_NUM_REGS_SAVED_WIN #define REG_FUN_TABLE ASM_XTENSA_REG_FUN_TABLE_WIN -#define ASM_ENTRY(as, nlocal) asm_xtensa_entry_win((as), (nlocal)) -#define ASM_EXIT(as) asm_xtensa_exit_win((as)) -#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx)) +#define ASM_ENTRY(as, nlocal, name) asm_xtensa_entry_win((as), (nlocal)) +#define ASM_EXIT(as) asm_xtensa_exit_win((as)) +#define ASM_CALL_IND(as, idx) asm_xtensa_call_ind_win((as), (idx)) #endif @@ -408,16 +418,51 @@ void asm_xtensa_call_ind_win(asm_xtensa_t *as, uint idx); #define ASM_SUB_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_sub((as), (reg_dest), (reg_dest), (reg_src)) #define ASM_MUL_REG_REG(as, reg_dest, reg_src) asm_xtensa_op_mull((as), (reg_dest), (reg_dest), (reg_src)) -#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_l32i_optimised((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0) -#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, uint16_offset) asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), (uint16_offset)) -#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) ASM_LOAD8_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD8_REG_REG_OFFSET(as, reg_dest, reg_base, byte_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (byte_offset), 0) +#define ASM_LOAD8_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_xtensa_op_add_n((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_l8ui((as), (reg_dest), (reg_base), 0); \ + } while (0) +#define ASM_LOAD16_REG_REG(as, reg_dest, reg_base) ASM_LOAD16_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD16_REG_REG_OFFSET(as, reg_dest, reg_base, halfword_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (halfword_offset), 1) +#define ASM_LOAD16_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_xtensa_op_addx2((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_l16ui((as), (reg_dest), (reg_base), 0); \ + } while (0) +#define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) ASM_LOAD32_REG_REG_OFFSET((as), (reg_dest), (reg_base), 0) +#define ASM_LOAD32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_load_reg_reg_offset((as), (reg_dest), (reg_base), (word_offset), 2) +#define ASM_LOAD32_REG_REG_REG(as, reg_dest, reg_base, reg_index) \ + do { \ + asm_xtensa_op_addx4((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_l32i_n((as), (reg_dest), (reg_base), 0); \ + } while (0) -#define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_s32i_optimised((as), (reg_dest), (reg_base), (word_offset)) -#define ASM_STORE8_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s8i((as), (reg_src), (reg_base), 0) -#define ASM_STORE16_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s16i((as), (reg_src), (reg_base), 0) -#define ASM_STORE32_REG_REG(as, reg_src, reg_base) asm_xtensa_op_s32i_n((as), (reg_src), (reg_base), 0) +#define ASM_STORE_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) ASM_STORE32_REG_REG_OFFSET((as), (reg_dest), (reg_base), (word_offset)) +#define ASM_STORE8_REG_REG(as, reg_src, reg_base) ASM_STORE8_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE8_REG_REG_OFFSET(as, reg_src, reg_base, byte_offset) asm_xtensa_store_reg_reg_offset((as), (reg_src), (reg_base), (byte_offset), 0) +#define ASM_STORE8_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_xtensa_op_add_n((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_s8i((as), (reg_val), (reg_base), 0); \ + } while (0) +#define ASM_STORE16_REG_REG(as, reg_src, reg_base) ASM_STORE16_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE16_REG_REG_OFFSET(as, reg_src, reg_base, halfword_offset) asm_xtensa_store_reg_reg_offset((as), (reg_src), (reg_base), (halfword_offset), 1) +#define ASM_STORE16_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_xtensa_op_addx2((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_s16i((as), (reg_val), (reg_base), 0); \ + } while (0) +#define ASM_STORE32_REG_REG(as, reg_src, reg_base) ASM_STORE32_REG_REG_OFFSET((as), (reg_src), (reg_base), 0) +#define ASM_STORE32_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) asm_xtensa_store_reg_reg_offset((as), (reg_dest), (reg_base), (word_offset), 2) +#define ASM_STORE32_REG_REG_REG(as, reg_val, reg_base, reg_index) \ + do { \ + asm_xtensa_op_addx4((as), (reg_base), (reg_index), (reg_base)); \ + asm_xtensa_op_s32i_n((as), (reg_val), (reg_base), 0); \ + } while (0) #endif // GENERIC_ASM_API diff --git a/py/bc.c b/py/bc.c index c2956030e38..4caa022e3d8 100644 --- a/py/bc.c +++ b/py/bc.c @@ -88,7 +88,7 @@ const byte *mp_decode_uint_skip(const byte *ptr) { return ptr; } -static NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { +static MP_NORETURN void fun_pos_args_mismatch(mp_obj_fun_bc_t *f, size_t expected, size_t given) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE // generic message, used also for other argument issues (void)f; diff --git a/py/bc.h b/py/bc.h index 7658f66414f..c299560ef2b 100644 --- a/py/bc.h +++ b/py/bc.h @@ -226,6 +226,7 @@ typedef struct _mp_compiled_module_t { bool has_native; size_t n_qstr; size_t n_obj; + size_t arch_flags; #endif } mp_compiled_module_t; @@ -316,25 +317,35 @@ static inline void mp_module_context_alloc_tables(mp_module_context_t *context, #endif } +typedef struct _mp_code_lineinfo_t { + size_t bc_increment; + size_t line_increment; +} mp_code_lineinfo_t; + +static inline mp_code_lineinfo_t mp_bytecode_decode_lineinfo(const byte **line_info) { + mp_code_lineinfo_t result; + size_t c = (*line_info)[0]; + if ((c & 0x80) == 0) { + // 0b0LLBBBBB encoding + result.bc_increment = c & 0x1f; + result.line_increment = c >> 5; + *line_info += 1; + } else { + // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + result.bc_increment = c & 0xf; + result.line_increment = ((c << 4) & 0x700) | (*line_info)[1]; + *line_info += 2; + } + return result; +} + static inline size_t mp_bytecode_get_source_line(const byte *line_info, const byte *line_info_top, size_t bc_offset) { size_t source_line = 1; while (line_info < line_info_top) { - size_t c = *line_info; - size_t b, l; - if ((c & 0x80) == 0) { - // 0b0LLBBBBB encoding - b = c & 0x1f; - l = c >> 5; - line_info += 1; - } else { - // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) - b = c & 0xf; - l = ((c << 4) & 0x700) | line_info[1]; - line_info += 2; - } - if (bc_offset >= b) { - bc_offset -= b; - source_line += l; + mp_code_lineinfo_t decoded = mp_bytecode_decode_lineinfo(&line_info); + if (bc_offset >= decoded.bc_increment) { + bc_offset -= decoded.bc_increment; + source_line += decoded.line_increment; } else { // found source line corresponding to bytecode offset break; diff --git a/py/binary.c b/py/binary.c index 728f29815cd..59353b918f9 100644 --- a/py/binary.c +++ b/py/binary.c @@ -71,8 +71,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) { case 'Q': size = 8; break; - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'P': case 'O': case 'S': @@ -128,8 +127,7 @@ size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) { align = alignof(long long); size = sizeof(long long); break; - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'P': case 'O': case 'S': @@ -208,7 +206,7 @@ static float mp_decode_half_float(uint16_t hf) { ++e; } - fpu.i = ((hf & 0x8000) << 16) | (e << 23) | (m << 13); + fpu.i = ((hf & 0x8000u) << 16) | (e << 23) | (m << 13); return fpu.f; } @@ -289,20 +287,20 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) { #if MICROPY_PY_BUILTINS_FLOAT case 'f': return mp_obj_new_float_from_f(((float *)p)[index]); + // CIRCUITPY-CHANGE: #if MICROPY_PY_DOUBLE_TYPECODE case 'd': return mp_obj_new_float_from_d(((double *)p)[index]); #endif #endif - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES - // Extension to CPython: array of objects + // Extension to CPython: array of objects + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'O': return ((mp_obj_t *)p)[index]; // Extension to CPython: array of pointers case 'P': return mp_obj_new_int((mp_int_t)(uintptr_t)((void **)p)[index]); - #endif + #endif } return MP_OBJ_NEW_SMALL_INT(val); } @@ -352,14 +350,11 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p); - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - if (MICROPY_NONSTANDARD_TYPECODES && (val_type == 'O')) { + if (MICROPY_PY_STRUCT_UNSAFE_TYPECODES && val_type == 'O') { return (mp_obj_t)(mp_uint_t)val; - #if MICROPY_NONSTANDARD_TYPECODES - } else if (val_type == 'S') { + } else if (MICROPY_PY_STRUCT_UNSAFE_TYPECODES && val_type == 'S') { const char *s_val = (const char *)(uintptr_t)(mp_uint_t)val; return mp_obj_new_str_from_cstr(s_val); - #endif #if MICROPY_PY_BUILTINS_FLOAT } else if (val_type == 'e') { return mp_obj_new_float_from_f(mp_decode_half_float(val)); @@ -369,6 +364,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * float f; } fpu = {val}; return mp_obj_new_float_from_f(fpu.f); + // CIRCUITPY-CHANGE #if MICROPY_PY_DOUBLE_TYPECODE } else if (val_type == 'd') { union { @@ -430,8 +426,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p mp_uint_t val; switch (val_type) { - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'O': val = (mp_uint_t)val_in; break; @@ -449,6 +444,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p val = fp_sp.i; break; } + // CIRCUITPY-CHANGE #if MICROPY_PY_DOUBLE_TYPECODE case 'd': { union { @@ -513,8 +509,7 @@ void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_ break; #endif #endif - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES // Extension to CPython: array of objects case 'O': ((mp_obj_t *)p)[index] = val_in; @@ -582,18 +577,18 @@ void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_i case 'f': ((float *)p)[index] = (float)val; break; + // CIRCUITPY-CHANGE #if MICROPY_PY_DOUBLE_TYPECODE case 'd': ((double *)p)[index] = (double)val; break; #endif #endif - // CIRCUITPY-CHANGE: non-standard typecodes can be turned off - #if MICROPY_NONSTANDARD_TYPECODES - // Extension to CPython: array of pointers + // Extension to CPython: array of pointers + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES case 'P': ((void **)p)[index] = (void *)(uintptr_t)val; break; - #endif + #endif } } diff --git a/py/builtin.h b/py/builtin.h index 6efe3e8faca..388bc847005 100644 --- a/py/builtin.h +++ b/py/builtin.h @@ -138,6 +138,7 @@ extern const mp_obj_module_t mp_module_sys; extern const mp_obj_module_t mp_module_errno; extern const mp_obj_module_t mp_module_uctypes; extern const mp_obj_module_t mp_module_machine; +extern const mp_obj_module_t mp_module_math; extern const char MICROPY_PY_BUILTINS_HELP_TEXT[]; diff --git a/py/builtinhelp.c b/py/builtinhelp.c index d041d6915a6..9ab2a12d214 100644 --- a/py/builtinhelp.c +++ b/py/builtinhelp.c @@ -162,9 +162,8 @@ static void mp_help_print_obj(const mp_obj_t obj) { } if (map != NULL) { for (uint i = 0; i < map->alloc; i++) { - mp_obj_t key = map->table[i].key; - if (key != MP_OBJ_NULL) { - mp_help_print_info_about_object(key, map->table[i].value); + if (mp_map_slot_is_filled(map, i)) { + mp_help_print_info_about_object(map->table[i].key, map->table[i].value); } } } diff --git a/py/builtinimport.c b/py/builtinimport.c index e4e06d8e2cc..8fcac22ccb4 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -118,7 +118,7 @@ static mp_import_stat_t stat_module(vstr_t *path) { // path (i.e. "/mod_name(.py)"). static mp_import_stat_t stat_top_level(qstr mod_name, vstr_t *dest) { DEBUG_printf("stat_top_level: '%s'\n", qstr_str(mod_name)); - #if MICROPY_PY_SYS + #if MICROPY_PY_SYS && MICROPY_PY_SYS_PATH size_t path_num; mp_obj_t *path_items; mp_obj_get_array(mp_sys_path, &path_num, &path_items); @@ -155,7 +155,7 @@ static mp_import_stat_t stat_top_level(qstr mod_name, vstr_t *dest) { #if MICROPY_MODULE_FROZEN_STR || MICROPY_ENABLE_COMPILER static void do_load_from_lexer(mp_module_context_t *context, mp_lexer_t *lex) { - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ qstr source_name = lex->source_name; mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #endif @@ -168,7 +168,7 @@ static void do_load_from_lexer(mp_module_context_t *context, mp_lexer_t *lex) { #if (MICROPY_HAS_FILE_READER && MICROPY_PERSISTENT_CODE_LOAD) || MICROPY_MODULE_FROZEN_MPY static void do_execute_proto_fun(const mp_module_context_t *context, mp_proto_fun_t proto_fun, qstr source_name) { - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ mp_store_attr(MP_OBJ_FROM_PTR(&context->module), MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); #else (void)source_name; @@ -227,7 +227,7 @@ static void do_load(mp_module_context_t *module_obj, vstr_t *file) { if (frozen_type == MP_FROZEN_MPY) { const mp_frozen_module_t *frozen = modref; module_obj->constants = frozen->constants; - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ qstr frozen_file_qstr = qstr_from_str(file_str + frozen_path_prefix_len); #else qstr frozen_file_qstr = MP_QSTRnull; @@ -270,7 +270,7 @@ static void do_load(mp_module_context_t *module_obj, vstr_t *file) { // Convert a relative (to the current module) import, going up "level" levels, // into an absolute import. -static void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len) { +static void evaluate_relative_import(mp_int_t level, const char **module_name, size_t *module_name_len, mp_obj_t globals) { // What we want to do here is to take the name of the current module, // remove trailing components, and concatenate the passed-in // module name. @@ -279,7 +279,7 @@ static void evaluate_relative_import(mp_int_t level, const char **module_name, s // module's position in the package hierarchy." // http://legacy.python.org/dev/peps/pep-0328/#relative-imports-and-name - mp_obj_t current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___name__)); + mp_obj_t current_module_name_obj = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___name__)); assert(current_module_name_obj != MP_OBJ_NULL); #if MICROPY_MODULE_OVERRIDE_MAIN_IMPORT && MICROPY_CPYTHON_COMPAT @@ -287,12 +287,12 @@ static void evaluate_relative_import(mp_int_t level, const char **module_name, s // This is a module loaded by -m command-line switch (e.g. unix port), // and so its __name__ has been set to "__main__". Get its real name // that we stored during import in the __main__ attribute. - current_module_name_obj = mp_obj_dict_get(MP_OBJ_FROM_PTR(mp_globals_get()), MP_OBJ_NEW_QSTR(MP_QSTR___main__)); + current_module_name_obj = mp_obj_dict_get(globals, MP_OBJ_NEW_QSTR(MP_QSTR___main__)); } #endif // If we have a __path__ in the globals dict, then we're a package. - bool is_pkg = mp_map_lookup(&mp_globals_get()->map, MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); + bool is_pkg = mp_map_lookup(mp_obj_dict_get_map(globals), MP_OBJ_NEW_QSTR(MP_QSTR___path__), MP_MAP_LOOKUP); #if DEBUG_PRINT DEBUG_printf("Current module/package: "); @@ -370,7 +370,7 @@ static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, // Immediately return if the module at this level is already loaded. mp_map_elem_t *elem; - #if MICROPY_PY_SYS + #if MICROPY_PY_SYS && MICROPY_PY_SYS_PATH // If sys.path is empty, the intention is to force using a built-in. This // means we should also ignore any loaded modules with the same name // which may have come from the filesystem. @@ -406,6 +406,7 @@ static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, // all the locations in sys.path. stat = stat_top_level(level_mod_name, &path); + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES // If filesystem failed, now try and see if it matches an extensible // built-in module. if (stat == MP_IMPORT_STAT_NO_EXIST) { @@ -414,6 +415,7 @@ static mp_obj_t process_import_at_level(qstr full_mod_name, qstr level_mod_name, return module_obj; } } + #endif } else { DEBUG_printf("Searching for sub-module\n"); @@ -577,10 +579,19 @@ mp_obj_t mp_builtin___import___default(size_t n_args, const mp_obj_t *args) { const char *module_name = mp_obj_str_get_data(module_name_obj, &module_name_len); if (level != 0) { + // This is the dict with all global symbols. + mp_obj_t globals = MP_OBJ_FROM_PTR(mp_globals_get()); + if (n_args >= 2 && args[1] != mp_const_none) { + globals = args[1]; + if (!mp_obj_is_type(globals, &mp_type_dict)) { + mp_raise_TypeError(NULL); + } + } + // Turn "foo.bar" with level=3 into ".foo.bar". // Current module name is extracted from globals().__name__. - evaluate_relative_import(level, &module_name, &module_name_len); // module_name is now an absolute module path. + evaluate_relative_import(level, &module_name, &module_name_len, globals); } if (module_name_len == 0) { @@ -656,11 +667,13 @@ mp_obj_t mp_builtin___import___default(size_t n_args, const mp_obj_t *args) { if (module_obj != MP_OBJ_NULL) { return module_obj; } + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES // Now try as an extensible built-in (e.g. `time`). module_obj = mp_module_get_builtin(module_name_qstr, true); if (module_obj != MP_OBJ_NULL) { return module_obj; } + #endif // Couldn't find the module, so fail #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index f6310dfaf68..fc74144dc80 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -88,7 +88,6 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_MEM_STATS (0) #define MICROPY_MODULE_BUILTIN_INIT (1) #define MICROPY_MODULE_BUILTIN_SUBPACKAGES (1) -#define MICROPY_NONSTANDARD_TYPECODES (0) #define MICROPY_OPT_COMPUTED_GOTO (1) #define MICROPY_OPT_COMPUTED_GOTO_SAVE_SPACE (CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE) #define MICROPY_OPT_LOAD_ATTR_FAST_PATH (CIRCUITPY_OPT_LOAD_ATTR_FAST_PATH) @@ -141,6 +140,7 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_PY_RE (CIRCUITPY_RE) // Supplanted by shared-bindings/struct #define MICROPY_PY_STRUCT (0) +#define MICROPY_PY_STRUCT_UNSAFE_TYPECODES (0) #define MICROPY_PY_SYS (CIRCUITPY_SYS) #define MICROPY_PY_SYS_MAXSIZE (1) #define MICROPY_PY_SYS_STDFILES (1) diff --git a/py/compile.c b/py/compile.c index c7dd2fd4761..c8704131234 100644 --- a/py/compile.c +++ b/py/compile.c @@ -103,6 +103,7 @@ static const emit_method_table_t *emit_native_table[] = { &emit_native_xtensa_method_table, &emit_native_xtensawin_method_table, &emit_native_rv32_method_table, + NULL, &emit_native_debug_method_table, }; @@ -3295,7 +3296,9 @@ static void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind } // check structure of parse node - assert(MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0])); + if (!MP_PARSE_NODE_IS_STRUCT(pns2->nodes[0])) { + goto not_an_instruction; + } if (!MP_PARSE_NODE_IS_NULL(pns2->nodes[1])) { goto not_an_instruction; } @@ -3587,6 +3590,13 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool case MP_EMIT_OPT_NATIVE_PYTHON: case MP_EMIT_OPT_VIPER: if (emit_native == NULL) { + // The check looks like this to work around a false + // warning in GCC 13 (and possibly later), where it + // assumes that the check will always fail. + if ((uintptr_t)NATIVE_EMITTER_TABLE == (uintptr_t)NULL) { + comp->compile_error = mp_obj_new_exception_msg(&mp_type_NotImplementedError, MP_ERROR_TEXT("cannot emit native code for this architecture")); + goto emit_finished; + } emit_native = NATIVE_EMITTER(new)(&comp->emit_common, &comp->compile_error, &comp->next_label, max_num_labels); } comp->emit_method_table = NATIVE_EMITTER_TABLE; @@ -3619,6 +3629,10 @@ void mp_compile_to_raw_code(mp_parse_tree_t *parse_tree, qstr source_file, bool } } + #if MICROPY_EMIT_NATIVE +emit_finished: + #endif + if (comp->compile_error != MP_OBJ_NULL) { // if there is no line number for the error then use the line // number for the start of this scope diff --git a/py/cstack.h b/py/cstack.h index b12a18e13fc..bcd919d31f9 100644 --- a/py/cstack.h +++ b/py/cstack.h @@ -35,7 +35,7 @@ void mp_cstack_init_with_sp_here(size_t stack_size); -inline static void mp_cstack_init_with_top(void *top, size_t stack_size) { +static inline void mp_cstack_init_with_top(void *top, size_t stack_size) { MP_STATE_THREAD(stack_top) = (char *)top; #if MICROPY_STACK_CHECK @@ -54,7 +54,7 @@ void mp_cstack_check(void); #else -inline static void mp_cstack_check(void) { +static inline void mp_cstack_check(void) { // No-op when stack checking is disabled } diff --git a/py/dynruntime.h b/py/dynruntime.h index e87cf6591c4..b41a31f48f7 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -70,7 +70,7 @@ #define m_realloc(ptr, new_num_bytes) (m_realloc_dyn((ptr), (new_num_bytes))) #define m_realloc_maybe(ptr, new_num_bytes, allow_move) (m_realloc_maybe_dyn((ptr), (new_num_bytes), (allow_move))) -static NORETURN inline void m_malloc_fail_dyn(size_t num_bytes) { +static MP_NORETURN inline void m_malloc_fail_dyn(size_t num_bytes) { mp_fun_table.raise_msg( mp_fun_table.load_global(MP_QSTR_MemoryError), "memory allocation failed"); @@ -301,14 +301,14 @@ static inline mp_obj_t mp_obj_new_exception_arg1_dyn(const mp_obj_type_t *exc_ty return mp_call_function_n_kw(MP_OBJ_FROM_PTR(exc_type), 1, 0, &args[0]); } -static NORETURN inline void mp_raise_dyn(mp_obj_t o) { +static MP_NORETURN inline void mp_raise_dyn(mp_obj_t o) { mp_fun_table.raise(o); for (;;) { } } // CIRCUITPY-CHANGE: new routine -static NORETURN inline void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) { +static MP_NORETURN inline void mp_raise_arg1(const mp_obj_type_t *exc_type, mp_obj_t arg) { mp_fun_table.raise(mp_obj_new_exception_arg1_dyn(exc_type, arg)); for (;;) { } diff --git a/py/dynruntime.mk b/py/dynruntime.mk index 807befb464a..030728cfc9a 100644 --- a/py/dynruntime.mk +++ b/py/dynruntime.mk @@ -63,14 +63,14 @@ else ifeq ($(ARCH),armv6m) # thumb CROSS = arm-none-eabi- CFLAGS_ARCH += -mthumb -mcpu=cortex-m0 -MICROPY_FLOAT_IMPL ?= none +MICROPY_FLOAT_IMPL ?= float else ifeq ($(ARCH),armv7m) # thumb CROSS = arm-none-eabi- CFLAGS_ARCH += -mthumb -mcpu=cortex-m3 -MICROPY_FLOAT_IMPL ?= none +MICROPY_FLOAT_IMPL ?= float else ifeq ($(ARCH),armv7emsp) @@ -124,6 +124,10 @@ else $(error architecture '$(ARCH)' not supported) endif +ifneq ($(findstring -musl,$(shell $(CROSS)gcc -dumpmachine)),) +USE_MUSL := 1 +endif + MICROPY_FLOAT_IMPL_UPPER = $(shell echo $(MICROPY_FLOAT_IMPL) | tr '[:lower:]' '[:upper:]') CFLAGS += $(CFLAGS_ARCH) -DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_$(MICROPY_FLOAT_IMPL_UPPER) @@ -147,6 +151,8 @@ ifeq ($(LINK_RUNTIME),1) # distribution. ifeq ($(USE_PICOLIBC),1) LIBM_NAME := libc.a +else ifeq ($(USE_MUSL),1) +LIBM_NAME := libc.a else LIBM_NAME := libm.a endif @@ -166,6 +172,9 @@ endif endif MPY_LD_FLAGS += $(addprefix -l, $(LIBGCC_PATH) $(LIBM_PATH)) endif +ifneq ($(MPY_EXTERN_SYM_FILE),) +MPY_LD_FLAGS += --externs "$(realpath $(MPY_EXTERN_SYM_FILE))" +endif CFLAGS += $(CFLAGS_EXTRA) diff --git a/py/emitcommon.c b/py/emitcommon.c index a9eb6e2021f..1f701db80a0 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -25,6 +25,7 @@ */ #include +#include #include "py/emit.h" #include "py/nativeglue.h" @@ -72,7 +73,21 @@ static bool strictly_equal(mp_obj_t a, mp_obj_t b) { } return true; } else { - return mp_obj_equal(a, b); + if (!mp_obj_equal(a, b)) { + return false; + } + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_COMP_CONST_FLOAT + if (a_type == &mp_type_float) { + mp_float_t a_val = mp_obj_float_get(a); + if (a_val == (mp_float_t)0.0) { + // Although 0.0 == -0.0, they are not strictly_equal and + // must be stored as two different constants in .mpy files + mp_float_t b_val = mp_obj_float_get(b); + return signbit(a_val) == signbit(b_val); + } + } + #endif + return true; } } diff --git a/py/emitglue.c b/py/emitglue.c index 8cc14bdc54e..c6ad3e3bc38 100644 --- a/py/emitglue.c +++ b/py/emitglue.c @@ -32,6 +32,7 @@ #include #include "py/emitglue.h" +#include "py/mphal.h" #include "py/runtime0.h" #include "py/bc.h" #include "py/objfun.h" @@ -133,6 +134,9 @@ void mp_emit_glue_assign_native(mp_raw_code_t *rc, mp_raw_code_kind_t kind, cons "mcr p15, 0, r0, c7, c7, 0\n" // invalidate I-cache and D-cache : : : "r0", "cc"); #endif + #elif (MICROPY_EMIT_RV32 || MICROPY_EMIT_INLINE_RV32) && defined(MP_HAL_CLEAN_DCACHE) + // Flush the D-cache. + MP_HAL_CLEAN_DCACHE(fun_data, fun_len); #endif rc->kind = kind; diff --git a/py/emitinlinerv32.c b/py/emitinlinerv32.c index a539242b84d..e81b152087d 100644 --- a/py/emitinlinerv32.c +++ b/py/emitinlinerv32.c @@ -196,7 +196,6 @@ typedef enum { CALL_R, // Opcode Register CALL_RL, // Opcode Register, Label CALL_N, // Opcode - CALL_I, // Opcode Immediate CALL_RII, // Opcode Register, Register, Immediate CALL_RIR, // Opcode Register, Immediate(Register) CALL_COUNT @@ -210,7 +209,6 @@ typedef enum { #define U (1 << 2) // Unsigned immediate #define Z (1 << 3) // Non-zero -typedef void (*call_l_t)(asm_rv32_t *state, mp_uint_t label_index); typedef void (*call_ri_t)(asm_rv32_t *state, mp_uint_t rd, mp_int_t immediate); typedef void (*call_rri_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t rs1, mp_int_t immediate); typedef void (*call_rii_t)(asm_rv32_t *state, mp_uint_t rd, mp_uint_t immediate1, mp_int_t immediate2); @@ -225,7 +223,7 @@ typedef struct _opcode_t { uint16_t argument1_mask : 4; uint16_t argument2_mask : 4; uint16_t argument3_mask : 4; - uint16_t arguments_count : 2; + uint16_t parse_nodes : 2; // 2 bits available here uint32_t calling_convention : 4; uint32_t argument1_kind : 4; @@ -234,7 +232,8 @@ typedef struct _opcode_t { uint32_t argument2_shift : 4; uint32_t argument3_kind : 4; uint32_t argument3_shift : 4; - // 4 bits available here + uint32_t required_extensions : 1; + // 3 bits available here void *emitter; } opcode_t; @@ -297,88 +296,91 @@ static const uint32_t OPCODE_MASKS[] = { }; static const opcode_t OPCODES[] = { - { MP_QSTR_add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_add }, - { MP_QSTR_addi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_addi }, - { MP_QSTR_and_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_and }, - { MP_QSTR_andi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_andi }, - { MP_QSTR_auipc, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, asm_rv32_opcode_auipc }, - { MP_QSTR_beq, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_beq }, - { MP_QSTR_bge, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bge }, - { MP_QSTR_bgeu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bgeu }, - { MP_QSTR_blt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_blt }, - { MP_QSTR_bltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bltu }, - { MP_QSTR_bne, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, asm_rv32_opcode_bne }, - { MP_QSTR_csrrc, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrc }, - { MP_QSTR_csrrs, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrs }, - { MP_QSTR_csrrw, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_csrrw }, - { MP_QSTR_csrrci, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrci }, - { MP_QSTR_csrrsi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrsi }, - { MP_QSTR_csrrwi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, asm_rv32_opcode_csrrwi }, - { MP_QSTR_c_add, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cadd }, - { MP_QSTR_c_addi, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, IZ, 0, N, 0, asm_rv32_opcode_caddi }, - { MP_QSTR_c_addi4spn, MASK_0000FF00, MASK_000003FC, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 0, N, 0, asm_rv32_opcode_caddi4spn }, - { MP_QSTR_c_and, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cand }, - { MP_QSTR_c_andi, MASK_0000FF00, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, RC, 0, I, 0, N, 0, asm_rv32_opcode_candi }, - { MP_QSTR_c_beqz, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, asm_rv32_opcode_cbeqz }, - { MP_QSTR_c_bnez, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, asm_rv32_opcode_cbnez }, - { MP_QSTR_c_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_cebreak }, - { MP_QSTR_c_j, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, asm_rv32_opcode_cj }, - { MP_QSTR_c_jal, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, asm_rv32_opcode_cjal }, - { MP_QSTR_c_jalr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, asm_rv32_opcode_cjalr }, - { MP_QSTR_c_jr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, asm_rv32_opcode_cjr }, - { MP_QSTR_c_li, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_cli }, - { MP_QSTR_c_lui, MASK_FFFFFFFA, MASK_0001F800, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 12, N, 0, asm_rv32_opcode_clui }, - { MP_QSTR_c_lw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 3, CALL_RIR, RC, 0, I, 0, RC, 0, asm_rv32_opcode_clw }, - { MP_QSTR_c_lwsp, MASK_FFFFFFFE, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_clwsp }, - { MP_QSTR_c_mv, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cmv }, - { MP_QSTR_c_nop, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_cnop }, - { MP_QSTR_c_or, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cor }, - { MP_QSTR_c_slli, MASK_FFFFFFFE, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, R, 0, IU, 0, N, 0, asm_rv32_opcode_cslli }, - { MP_QSTR_c_srai, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, asm_rv32_opcode_csrai }, - { MP_QSTR_c_srli, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, asm_rv32_opcode_csrli }, - { MP_QSTR_c_sub, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_csub }, - { MP_QSTR_c_sw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 3, CALL_RIR, RC, 0, I, 0, RC, 0, asm_rv32_opcode_csw }, - { MP_QSTR_c_swsp, MASK_FFFFFFFF, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, asm_rv32_opcode_cswsp }, - { MP_QSTR_c_xor, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, asm_rv32_opcode_cxor }, - { MP_QSTR_div, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_div }, - { MP_QSTR_divu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_divu }, - { MP_QSTR_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_ebreak }, - { MP_QSTR_ecall, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, asm_rv32_opcode_ecall }, - { MP_QSTR_jal, MASK_FFFFFFFF, MASK_001FFFFE, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, asm_rv32_opcode_jal }, - { MP_QSTR_jalr, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_jalr }, - { MP_QSTR_la, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, opcode_la }, - { MP_QSTR_lb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lb }, - { MP_QSTR_lbu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lbu }, - { MP_QSTR_lh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lh }, - { MP_QSTR_lhu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lhu }, - { MP_QSTR_li, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, opcode_li }, - { MP_QSTR_lui, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, asm_rv32_opcode_lui }, - { MP_QSTR_lw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_lw }, - { MP_QSTR_mv, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, asm_rv32_opcode_cmv }, - { MP_QSTR_mul, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mul }, - { MP_QSTR_mulh, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulh }, - { MP_QSTR_mulhsu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulhsu }, - { MP_QSTR_mulhu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_mulhu }, - { MP_QSTR_or_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_or }, - { MP_QSTR_ori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_ori }, - { MP_QSTR_rem, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_rem }, - { MP_QSTR_remu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_remu }, - { MP_QSTR_sb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sb }, - { MP_QSTR_sh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sh }, - { MP_QSTR_sll, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sll }, - { MP_QSTR_slli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_slli }, - { MP_QSTR_slt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_slt }, - { MP_QSTR_slti, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_slti }, - { MP_QSTR_sltiu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_sltiu }, - { MP_QSTR_sltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sltu }, - { MP_QSTR_sra, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sra }, - { MP_QSTR_srai, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_srai }, - { MP_QSTR_srl, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_srl }, - { MP_QSTR_srli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, asm_rv32_opcode_srli }, - { MP_QSTR_sub, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_sub }, - { MP_QSTR_sw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 3, CALL_RIR, R, 0, I, 0, R, 0, asm_rv32_opcode_sw }, - { MP_QSTR_xor, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, asm_rv32_opcode_xor }, - { MP_QSTR_xori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, asm_rv32_opcode_xori }, + { MP_QSTR_add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_add }, + { MP_QSTR_addi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_addi }, + { MP_QSTR_and_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_and }, + { MP_QSTR_andi, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_andi }, + { MP_QSTR_auipc, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, RV32_EXT_NONE, asm_rv32_opcode_auipc }, + { MP_QSTR_beq, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_beq }, + { MP_QSTR_bge, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_bge }, + { MP_QSTR_bgeu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_bgeu }, + { MP_QSTR_blt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_blt }, + { MP_QSTR_bltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_bltu }, + { MP_QSTR_bne, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00001FFE, 3, CALL_RRL, R, 0, R, 0, L, 0, RV32_EXT_NONE, asm_rv32_opcode_bne }, + { MP_QSTR_csrrc, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrc }, + { MP_QSTR_csrrs, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrs }, + { MP_QSTR_csrrw, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrw }, + { MP_QSTR_csrrci, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrci }, + { MP_QSTR_csrrsi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrsi }, + { MP_QSTR_csrrwi, MASK_FFFFFFFF, MASK_00000FFF, MASK_0000001F, 3, CALL_RII, R, 0, IU, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_csrrwi }, + { MP_QSTR_c_add, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cadd }, + { MP_QSTR_c_addi, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, IZ, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_caddi }, + { MP_QSTR_c_addi4spn, MASK_0000FF00, MASK_000003FC, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_caddi4spn }, + { MP_QSTR_c_and, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cand }, + { MP_QSTR_c_andi, MASK_0000FF00, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, RC, 0, I, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_candi }, + { MP_QSTR_c_beqz, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cbeqz }, + { MP_QSTR_c_bnez, MASK_0000FF00, MASK_000001FE, MASK_NOT_USED, 2, CALL_RL, RC, 0, L, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cbnez }, + { MP_QSTR_c_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cebreak }, + { MP_QSTR_c_j, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cj }, + { MP_QSTR_c_jal, MASK_00000FFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_L, L, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cjal }, + { MP_QSTR_c_jalr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cjalr }, + { MP_QSTR_c_jr, MASK_FFFFFFFE, MASK_NOT_USED, MASK_NOT_USED, 1, CALL_R, R, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cjr }, + { MP_QSTR_c_li, MASK_FFFFFFFE, MASK_0000003F, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cli }, + { MP_QSTR_c_lui, MASK_FFFFFFFA, MASK_0001F800, MASK_NOT_USED, 2, CALL_RI, R, 0, IUZ, 12, N, 0, RV32_EXT_NONE, asm_rv32_opcode_clui }, + { MP_QSTR_c_lw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 2, CALL_RIR, RC, 0, I, 0, RC, 0, RV32_EXT_NONE, asm_rv32_opcode_clw }, + { MP_QSTR_c_lwsp, MASK_FFFFFFFE, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_clwsp }, + { MP_QSTR_c_mv, MASK_FFFFFFFE, MASK_FFFFFFFE, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cmv }, + { MP_QSTR_c_nop, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cnop }, + { MP_QSTR_c_or, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cor }, + { MP_QSTR_c_slli, MASK_FFFFFFFE, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, R, 0, IU, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cslli }, + { MP_QSTR_c_srai, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_csrai }, + { MP_QSTR_c_srli, MASK_0000FF00, MASK_0000001F, MASK_NOT_USED, 2, CALL_RI, RC, 0, IU, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_csrli }, + { MP_QSTR_c_sub, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_csub }, + { MP_QSTR_c_sw, MASK_0000FF00, MASK_0000007C, MASK_0000FF00, 2, CALL_RIR, RC, 0, I, 0, RC, 0, RV32_EXT_NONE, asm_rv32_opcode_csw }, + { MP_QSTR_c_swsp, MASK_FFFFFFFF, MASK_000000FC, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cswsp }, + { MP_QSTR_c_xor, MASK_0000FF00, MASK_0000FF00, MASK_NOT_USED, 2, CALL_RR, RC, 0, RC, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cxor }, + { MP_QSTR_div, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_div }, + { MP_QSTR_divu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_divu }, + { MP_QSTR_ebreak, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_ebreak }, + { MP_QSTR_ecall, MASK_NOT_USED, MASK_NOT_USED, MASK_NOT_USED, 0, CALL_N, N, 0, N, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_ecall }, + { MP_QSTR_jal, MASK_FFFFFFFF, MASK_001FFFFE, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_jal }, + { MP_QSTR_jalr, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_jalr }, + { MP_QSTR_la, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RL, R, 0, L, 0, N, 0, RV32_EXT_NONE, opcode_la }, + { MP_QSTR_lb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lb }, + { MP_QSTR_lbu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lbu }, + { MP_QSTR_lh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lh }, + { MP_QSTR_lhu, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lhu }, + { MP_QSTR_li, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 0, N, 0, RV32_EXT_NONE, opcode_li }, + { MP_QSTR_lui, MASK_FFFFFFFF, MASK_FFFFF000, MASK_NOT_USED, 2, CALL_RI, R, 0, I, 12, N, 0, RV32_EXT_NONE, asm_rv32_opcode_lui }, + { MP_QSTR_lw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_lw }, + { MP_QSTR_mv, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_NOT_USED, 2, CALL_RR, R, 0, R, 0, N, 0, RV32_EXT_NONE, asm_rv32_opcode_cmv }, + { MP_QSTR_mul, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_mul }, + { MP_QSTR_mulh, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_mulh }, + { MP_QSTR_mulhsu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_mulhsu }, + { MP_QSTR_mulhu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_mulhu }, + { MP_QSTR_or_, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_or }, + { MP_QSTR_ori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_ori }, + { MP_QSTR_rem, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_rem }, + { MP_QSTR_remu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_remu }, + { MP_QSTR_sb, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sb }, + { MP_QSTR_sh, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sh }, + { MP_QSTR_sh1add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_ZBA, asm_rv32_opcode_sh1add }, + { MP_QSTR_sh2add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_ZBA, asm_rv32_opcode_sh2add }, + { MP_QSTR_sh3add, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_ZBA, asm_rv32_opcode_sh3add }, + { MP_QSTR_sll, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sll }, + { MP_QSTR_slli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_slli }, + { MP_QSTR_slt, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_slt }, + { MP_QSTR_slti, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_slti }, + { MP_QSTR_sltiu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_sltiu }, + { MP_QSTR_sltu, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sltu }, + { MP_QSTR_sra, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sra }, + { MP_QSTR_srai, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_srai }, + { MP_QSTR_srl, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_srl }, + { MP_QSTR_srli, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_0000001F, 3, CALL_RRI, R, 0, R, 0, IU, 0, RV32_EXT_NONE, asm_rv32_opcode_srli }, + { MP_QSTR_sub, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sub }, + { MP_QSTR_sw, MASK_FFFFFFFF, MASK_00000FFF, MASK_FFFFFFFF, 2, CALL_RIR, R, 0, I, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_sw }, + { MP_QSTR_xor, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_FFFFFFFF, 3, CALL_RRR, R, 0, R, 0, R, 0, RV32_EXT_NONE, asm_rv32_opcode_xor }, + { MP_QSTR_xori, MASK_FFFFFFFF, MASK_FFFFFFFF, MASK_00000FFF, 3, CALL_RRI, R, 0, R, 0, I, 0, RV32_EXT_NONE, asm_rv32_opcode_xori }, }; #undef RC @@ -388,9 +390,9 @@ static const opcode_t OPCODES[] = { // These two checks assume the bitmasks are contiguous. -static bool is_in_signed_mask(mp_uint_t mask, mp_uint_t value) { - mp_uint_t leading_zeroes = mp_clz(mask); - if (leading_zeroes == 0 || leading_zeroes > 32) { +static bool is_in_signed_mask(uint32_t mask, mp_uint_t value) { + uint32_t leading_zeroes = mp_clz(mask); + if (leading_zeroes == 0) { return true; } mp_uint_t positive_mask = ~(mask & ~(1U << (31 - leading_zeroes))); @@ -435,9 +437,9 @@ static bool validate_integer(mp_uint_t value, mp_uint_t mask, mp_uint_t flags) { #define ET_WRONG_ARGUMENTS_COUNT MP_ERROR_TEXT("opcode '%q': expecting %d arguments") #define ET_OUT_OF_RANGE MP_ERROR_TEXT("opcode '%q' argument %d: out of range") -static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, - const opcode_t *opcode, mp_parse_node_t node, mp_uint_t node_index) { +static bool serialise_argument(emit_inline_asm_t *emit, const opcode_t *opcode, mp_parse_node_t node, mp_uint_t node_index, mp_uint_t *serialised) { assert((node_index < 3) && "Invalid argument node number."); + assert(serialised && "Serialised value pointer is NULL."); uint32_t kind = 0; uint32_t shift = 0; @@ -466,17 +468,19 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, break; } + mp_uint_t serialised_value = 0; + switch (kind & 0x03) { case N: assert(mask == OPCODE_MASKS[MASK_NOT_USED] && "Invalid mask index for missing operand."); - return true; + break; case R: { mp_uint_t register_index; if (!parse_register_node(node, ®ister_index, false)) { emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_register)); + ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_register)); return false; } @@ -484,11 +488,11 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("opcode '%q' argument %d: unknown register"), - opcode_qstr, node_index + 1)); + opcode->qstring, node_index + 1)); return false; } - return true; + serialised_value = (kind & C) ? RV32_MAP_IN_C_REGISTER_WINDOW(register_index) : register_index; } break; @@ -497,7 +501,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, if (!mp_parse_node_get_int_maybe(node, &object)) { emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_integer)); + ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_integer)); return false; } @@ -516,7 +520,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, goto zero_immediate; } - return true; + serialised_value = immediate; } break; @@ -524,7 +528,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, if (!MP_PARSE_NODE_IS_ID(node)) { emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_label)); + ET_WRONG_ARGUMENT_KIND, opcode->qstring, node_index + 1, MP_QSTR_label)); return false; } @@ -534,7 +538,7 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("opcode '%q' argument %d: undefined label '%q'"), - opcode_qstr, node_index + 1, qstring)); + opcode->qstring, node_index + 1, qstring)); return false; } @@ -548,43 +552,45 @@ static bool validate_argument(emit_inline_asm_t *emit, qstr opcode_qstr, goto out_of_range; } } - return true; + + serialised_value = displacement; } break; default: assert(!"Unknown argument kind"); + MP_UNREACHABLE; break; } - return false; + *serialised = serialised_value; + return true; out_of_range: emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_qstr, node_index + 1)); + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode->qstring, node_index + 1)); return false; zero_immediate: emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("opcode '%q' argument %d: must not be zero"), - opcode_qstr, node_index + 1)); + opcode->qstring, node_index + 1)); return false; } -static bool parse_register_offset_node(emit_inline_asm_t *emit, qstr opcode_qstr, const opcode_t *opcode_data, mp_parse_node_t node, mp_uint_t node_index, mp_parse_node_t *register_node, mp_parse_node_t *offset_node, bool *negative) { - assert(register_node != NULL && "Register node pointer is NULL."); - assert(offset_node != NULL && "Offset node pointer is NULL."); - assert(negative != NULL && "Negative pointer is NULL."); +static bool serialise_register_offset_node(emit_inline_asm_t *emit, const opcode_t *opcode_data, mp_parse_node_t node, mp_uint_t node_index, mp_uint_t *offset, mp_uint_t *base) { + assert(offset && "Attempting to store the offset value into NULL."); + assert(base && "Attempting to store the base register into NULL."); if (!MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_atom_expr_normal) && !MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_factor_2)) { goto invalid_structure; } mp_parse_node_struct_t *node_struct = (mp_parse_node_struct_t *)node; - *negative = false; + bool negative = false; if (MP_PARSE_NODE_IS_STRUCT_KIND(node, PN_factor_2)) { if (MP_PARSE_NODE_IS_TOKEN_KIND(node_struct->nodes[0], MP_TOKEN_OP_MINUS)) { - *negative = true; + negative = true; } else { if (!MP_PARSE_NODE_IS_TOKEN_KIND(node_struct->nodes[0], MP_TOKEN_OP_PLUS)) { goto invalid_structure; @@ -596,186 +602,97 @@ static bool parse_register_offset_node(emit_inline_asm_t *emit, qstr opcode_qstr node_struct = (mp_parse_node_struct_t *)node_struct->nodes[1]; } - if (*negative) { + if (negative) { // If the value is negative, RULE_atom_expr_normal's first token will be the // offset stripped of its negative marker; range check will then fail if the // default method is used, so a custom check is used instead. mp_obj_t object; if (!mp_parse_node_get_int_maybe(node_struct->nodes[0], &object)) { emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_WRONG_ARGUMENT_KIND, opcode_qstr, 2, MP_QSTR_integer)); + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_WRONG_ARGUMENT_KIND, opcode_data->qstring, 2, MP_QSTR_integer)); return false; } mp_uint_t value = mp_obj_get_int_truncated(object); value = (~value + 1) & (mp_uint_t)-1; if (!validate_integer(value << opcode_data->argument2_shift, OPCODE_MASKS[opcode_data->argument2_mask], opcode_data->argument2_kind)) { emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_qstr, 2)); + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode_data->qstring, 2)); return false; } + *offset = value; } else { - if (!validate_argument(emit, opcode_qstr, opcode_data, node_struct->nodes[0], 1)) { + if (!serialise_argument(emit, opcode_data, node_struct->nodes[0], 1, offset)) { return false; } } - *offset_node = node_struct->nodes[0]; node_struct = (mp_parse_node_struct_t *)node_struct->nodes[1]; - if (!validate_argument(emit, opcode_qstr, opcode_data, node_struct->nodes[0], 2)) { + if (!serialise_argument(emit, opcode_data, node_struct->nodes[0], 2, base)) { return false; } - *register_node = node_struct->nodes[0]; return true; invalid_structure: emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENT_KIND, opcode_qstr, node_index + 1, MP_QSTR_offset)); + ET_WRONG_ARGUMENT_KIND, opcode_data->qstring, node_index + 1, MP_QSTR_offset)); return false; } -static void handle_opcode(emit_inline_asm_t *emit, qstr opcode, const opcode_t *opcode_data, mp_parse_node_t *arguments) { - mp_uint_t rd = 0; - mp_uint_t rs1 = 0; - mp_uint_t rs2 = 0; - +static void handle_opcode(emit_inline_asm_t *emit, const opcode_t *opcode_data, mp_uint_t *arguments) { switch (opcode_data->calling_convention) { - case CALL_RRR: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C); - parse_register_node(arguments[2], &rs2, opcode_data->argument3_kind & C); - ((call_rrr_t)opcode_data->emitter)(&emit->as, rd, rs1, rs2); + case CALL_RRR: + ((call_rrr_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]); break; - } - case CALL_RR: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C); - ((call_rr_t)opcode_data->emitter)(&emit->as, rd, rs1); + case CALL_RR: + ((call_rr_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1]); break; - } - case CALL_RRI: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C); - mp_obj_t object; - mp_parse_node_get_int_maybe(arguments[2], &object); - mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument3_shift; - ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, immediate); + case CALL_RRI: + ((call_rri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]); break; - } - case CALL_RI: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - mp_obj_t object; - mp_parse_node_get_int_maybe(arguments[1], &object); - mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift; - ((call_ri_t)opcode_data->emitter)(&emit->as, rd, immediate); + case CALL_RI: + ((call_ri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1]); break; - } - case CALL_R: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - ((call_r_t)opcode_data->emitter)(&emit->as, rd); + case CALL_R: + ((call_r_t)opcode_data->emitter)(&emit->as, arguments[0]); break; - } - case CALL_RRL: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - parse_register_node(arguments[1], &rs1, opcode_data->argument2_kind & C); - qstr qstring; - mp_uint_t label_index = lookup_label(emit, arguments[2], &qstring); - ptrdiff_t displacement = label_code_offset(emit, label_index); - ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, displacement); + case CALL_RRL: + ((call_rri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], (ptrdiff_t)arguments[2]); break; - } - case CALL_RL: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - qstr qstring; - mp_uint_t label_index = lookup_label(emit, arguments[1], &qstring); - ptrdiff_t displacement = label_code_offset(emit, label_index); - ((call_ri_t)opcode_data->emitter)(&emit->as, rd, displacement); + case CALL_RL: + ((call_ri_t)opcode_data->emitter)(&emit->as, arguments[0], (ptrdiff_t)arguments[1]); break; - } - case CALL_L: { - qstr qstring; - mp_uint_t label_index = lookup_label(emit, arguments[0], &qstring); - ptrdiff_t displacement = label_code_offset(emit, label_index); - ((call_i_t)opcode_data->emitter)(&emit->as, displacement); + case CALL_L: + ((call_i_t)opcode_data->emitter)(&emit->as, (ptrdiff_t)arguments[0]); break; - } case CALL_N: ((call_n_t)opcode_data->emitter)(&emit->as); break; - case CALL_I: { - mp_obj_t object; - mp_parse_node_get_int_maybe(arguments[0], &object); - mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument1_shift; - ((call_i_t)opcode_data->emitter)(&emit->as, immediate); + case CALL_RII: + ((call_rii_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[1], arguments[2]); break; - } - - case CALL_RII: { - parse_register_node(arguments[0], &rd, opcode_data->argument1_kind & C); - mp_obj_t object; - mp_parse_node_get_int_maybe(arguments[1], &object); - mp_uint_t immediate1 = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift; - mp_parse_node_get_int_maybe(arguments[2], &object); - mp_uint_t immediate2 = mp_obj_get_int_truncated(object) << opcode_data->argument3_shift; - ((call_rii_t)opcode_data->emitter)(&emit->as, rd, immediate1, immediate2); - break; - } case CALL_RIR: - assert(!"Should not get here."); + // The last two arguments indices are swapped on purpose. + ((call_rri_t)opcode_data->emitter)(&emit->as, arguments[0], arguments[2], arguments[1]); break; default: assert(!"Unhandled call convention."); + MP_UNREACHABLE; break; } } -static bool handle_load_store_opcode_with_offset(emit_inline_asm_t *emit, qstr opcode, const opcode_t *opcode_data, mp_parse_node_t *argument_nodes) { - mp_parse_node_t nodes[3] = {0}; - if (!validate_argument(emit, opcode, opcode_data, argument_nodes[0], 0)) { - return false; - } - nodes[0] = argument_nodes[0]; - bool negative = false; - if (!parse_register_offset_node(emit, opcode, opcode_data, argument_nodes[1], 1, &nodes[1], &nodes[2], &negative)) { - return false; - } - - mp_uint_t rd = 0; - mp_uint_t rs1 = 0; - if (!parse_register_node(nodes[0], &rd, opcode_data->argument1_kind & C)) { - return false; - } - if (!parse_register_node(nodes[1], &rs1, opcode_data->argument3_kind & C)) { - return false; - } - - mp_obj_t object; - mp_parse_node_get_int_maybe(nodes[2], &object); - mp_uint_t immediate = mp_obj_get_int_truncated(object) << opcode_data->argument2_shift; - if (negative) { - immediate = (~immediate + 1) & (mp_uint_t)-1; - } - if (!is_in_signed_mask(OPCODE_MASKS[opcode_data->argument2_mask], immediate)) { - emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_OUT_OF_RANGE, opcode, 2)); - return false; - } - - ((call_rri_t)opcode_data->emitter)(&emit->as, rd, rs1, immediate); - return true; -} - static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uint_t arguments_count, mp_parse_node_t *argument_nodes) { const opcode_t *opcode_data = NULL; for (mp_uint_t index = 0; index < MP_ARRAY_SIZE(OPCODES); index++) { @@ -785,10 +702,9 @@ static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uin } } - if (!opcode_data) { - emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - MP_ERROR_TEXT("unknown RV32 instruction '%q'"), opcode)); + if (!opcode_data || (asm_rv32_allowed_extensions() & opcode_data->required_extensions) != opcode_data->required_extensions) { + emit_inline_rv32_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + MP_ERROR_TEXT("invalid RV32 instruction '%q'"), opcode)); return; } @@ -796,36 +712,36 @@ static void emit_inline_rv32_opcode(emit_inline_asm_t *emit, qstr opcode, mp_uin assert((opcode_data->argument2_mask < MP_ARRAY_SIZE(OPCODE_MASKS)) && "Argument #2 opcode mask index out of bounds."); assert((opcode_data->argument3_mask < MP_ARRAY_SIZE(OPCODE_MASKS)) && "Argument #3 opcode mask index out of bounds."); assert((opcode_data->calling_convention < CALL_COUNT) && "Calling convention index out of bounds."); - if (opcode_data->calling_convention != CALL_RIR) { - if (opcode_data->arguments_count != arguments_count) { - emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, - ET_WRONG_ARGUMENTS_COUNT, opcode, opcode_data->arguments_count)); - return; - } - if (opcode_data->arguments_count >= 1 && !validate_argument(emit, opcode, opcode_data, argument_nodes[0], 0)) { + mp_uint_t serialised_arguments[3] = { 0 }; + if (arguments_count != opcode_data->parse_nodes) { + emit_inline_rv32_error_exc(emit, + mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, + ET_WRONG_ARGUMENTS_COUNT, opcode, opcode_data->parse_nodes)); + return; + } + + if (opcode_data->parse_nodes >= 1 && !serialise_argument(emit, opcode_data, argument_nodes[0], 0, &serialised_arguments[0])) { + return; + } + if (opcode_data->calling_convention == CALL_RIR) { + // "register, offset(base)" calls require some preprocessing to + // split the offset and base nodes - not to mention that if the offset + // is negative, the parser won't see the offset as a single node but as + // a sequence of the minus sign token followed by the number itself. + + if (!serialise_register_offset_node(emit, opcode_data, argument_nodes[1], 1, &serialised_arguments[1], &serialised_arguments[2])) { return; } - if (opcode_data->arguments_count >= 2 && !validate_argument(emit, opcode, opcode_data, argument_nodes[1], 1)) { + } else { + if (opcode_data->parse_nodes >= 2 && !serialise_argument(emit, opcode_data, argument_nodes[1], 1, &serialised_arguments[1])) { return; } - if (opcode_data->arguments_count >= 3 && !validate_argument(emit, opcode, opcode_data, argument_nodes[2], 2)) { + if (opcode_data->parse_nodes >= 3 && !serialise_argument(emit, opcode_data, argument_nodes[2], 2, &serialised_arguments[2])) { return; } - handle_opcode(emit, opcode, opcode_data, argument_nodes); - return; - } - - assert((opcode_data->argument2_kind & U) == 0 && "Offset must not be unsigned."); - assert((opcode_data->argument2_kind & Z) == 0 && "Offset can be zero."); - - if (arguments_count != 2) { - emit_inline_rv32_error_exc(emit, - mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, ET_WRONG_ARGUMENTS_COUNT, opcode, 2)); - return; } - handle_load_store_opcode_with_offset(emit, opcode, opcode_data, argument_nodes); + handle_opcode(emit, opcode_data, serialised_arguments); } #undef N diff --git a/py/emitinlinextensa.c b/py/emitinlinextensa.c index fed259cfc6b..d0eb3d566fc 100644 --- a/py/emitinlinextensa.c +++ b/py/emitinlinextensa.c @@ -173,7 +173,7 @@ static int get_arg_label(emit_inline_asm_t *emit, const char *op, mp_parse_node_ #define RRI8_B (2) typedef struct _opcode_table_3arg_t { - uint16_t name; // actually a qstr, which should fit in 16 bits + qstr_short_t name; uint8_t type; uint8_t a0 : 4; uint8_t a1 : 4; @@ -187,6 +187,13 @@ static const opcode_table_3arg_t opcode_table_3arg[] = { {MP_QSTR_add, RRR, 0, 8}, {MP_QSTR_sub, RRR, 0, 12}, {MP_QSTR_mull, RRR, 2, 8}, + {MP_QSTR_addx2, RRR, 0, 9}, + {MP_QSTR_addx4, RRR, 0, 10}, + {MP_QSTR_addx8, RRR, 0, 11}, + {MP_QSTR_subx2, RRR, 0, 13}, + {MP_QSTR_subx4, RRR, 0, 14}, + {MP_QSTR_subx8, RRR, 0, 15}, + {MP_QSTR_src, RRR, 1, 8}, // load/store/addi opcodes: reg, reg, imm // upper nibble of type encodes the range of the immediate arg @@ -208,21 +215,62 @@ static const opcode_table_3arg_t opcode_table_3arg[] = { {MP_QSTR_bge, RRI8_B, ASM_XTENSA_CC_GE, 0}, {MP_QSTR_bgeu, RRI8_B, ASM_XTENSA_CC_GEU, 0}, {MP_QSTR_blt, RRI8_B, ASM_XTENSA_CC_LT, 0}, + {MP_QSTR_bltu, RRI8_B, ASM_XTENSA_CC_LTU, 0}, {MP_QSTR_bnall, RRI8_B, ASM_XTENSA_CC_NALL, 0}, {MP_QSTR_bne, RRI8_B, ASM_XTENSA_CC_NE, 0}, {MP_QSTR_bnone, RRI8_B, ASM_XTENSA_CC_NONE, 0}, }; +// The index of the first four qstrs matches the CCZ condition value to be +// embedded into the opcode. +static const qstr_short_t BCCZ_OPCODES[] = { + MP_QSTR_beqz, MP_QSTR_bnez, MP_QSTR_bltz, MP_QSTR_bgez, + MP_QSTR_beqz_n, MP_QSTR_bnez_n +}; + +#if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES +typedef struct _single_opcode_t { + qstr_short_t name; + uint16_t value; +} single_opcode_t; + +static const single_opcode_t NOARGS_OPCODES[] = { + {MP_QSTR_dsync, 0x2030}, + {MP_QSTR_esync, 0x2020}, + {MP_QSTR_extw, 0x20D0}, + {MP_QSTR_ill, 0x0000}, + {MP_QSTR_isync, 0x2000}, + {MP_QSTR_memw, 0x20C0}, + {MP_QSTR_rsync, 0x2010}, +}; +#endif + static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_args, mp_parse_node_t *pn_args) { size_t op_len; const char *op_str = (const char *)qstr_data(op, &op_len); if (n_args == 0) { - if (op == MP_QSTR_ret_n) { + if (op == MP_QSTR_ret_n || op == MP_QSTR_ret) { asm_xtensa_op_ret_n(&emit->as); - } else { - goto unknown_op; + return; + } else if (op == MP_QSTR_nop) { + asm_xtensa_op24(&emit->as, 0x20F0); + return; + } else if (op == MP_QSTR_nop_n) { + asm_xtensa_op16(&emit->as, 0xF03D); + return; } + #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES + for (size_t index = 0; index < MP_ARRAY_SIZE(NOARGS_OPCODES); index++) { + const single_opcode_t *opcode = &NOARGS_OPCODES[index]; + if (op == opcode->name) { + asm_xtensa_op24(&emit->as, opcode->value); + return; + } + } + #endif + + goto unknown_op; } else if (n_args == 1) { if (op == MP_QSTR_callx0) { @@ -234,19 +282,45 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_ } else if (op == MP_QSTR_jx) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); asm_xtensa_op_jx(&emit->as, r0); + } else if (op == MP_QSTR_ssl) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op_ssl(&emit->as, r0); + } else if (op == MP_QSTR_ssr) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op_ssr(&emit->as, r0); + } else if (op == MP_QSTR_ssai) { + mp_uint_t sa = get_arg_i(emit, op_str, pn_args[0], 0, 31); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 4, sa & 0x0F, (sa >> 4) & 0x01)); + } else if (op == MP_QSTR_ssa8b) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 3, r0, 0)); + } else if (op == MP_QSTR_ssa8l) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 2, r0, 0)); + } else if (op == MP_QSTR_call0) { + mp_uint_t label = get_arg_label(emit, op_str, pn_args[0]); + asm_xtensa_call0(&emit->as, label); + #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES + } else if (op == MP_QSTR_fsync) { + mp_uint_t imm3 = get_arg_i(emit, op_str, pn_args[0], 0, 7); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 0, 2, 8 | imm3, 0)); + } else if (op == MP_QSTR_ill_n) { + asm_xtensa_op16(&emit->as, 0xF06D); + #endif } else { goto unknown_op; } } else if (n_args == 2) { uint r0 = get_arg_reg(emit, op_str, pn_args[0]); - if (op == MP_QSTR_beqz) { - int label = get_arg_label(emit, op_str, pn_args[1]); - asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_EQ, r0, label); - } else if (op == MP_QSTR_bnez) { - int label = get_arg_label(emit, op_str, pn_args[1]); - asm_xtensa_bccz_reg_label(&emit->as, ASM_XTENSA_CCZ_NE, r0, label); - } else if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) { + for (size_t index = 0; index < MP_ARRAY_SIZE(BCCZ_OPCODES); index++) { + if (op == BCCZ_OPCODES[index]) { + mp_uint_t label = get_arg_label(emit, op_str, pn_args[1]); + asm_xtensa_bccz_reg_label(&emit->as, index & 0x03, r0, label); + return; + } + } + if (op == MP_QSTR_mov || op == MP_QSTR_mov_n) { // we emit mov.n for both "mov" and "mov_n" opcodes uint r1 = get_arg_reg(emit, op_str, pn_args[1]); asm_xtensa_op_mov_n(&emit->as, r0, r1); @@ -254,7 +328,53 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_ // for convenience we emit l32r if the integer doesn't fit in movi uint32_t imm = get_arg_i(emit, op_str, pn_args[1], 0, 0); asm_xtensa_mov_reg_i32(&emit->as, r0, imm); - } else { + } else if (op == MP_QSTR_abs_) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 6, r0, 1, r1)); + } else if (op == MP_QSTR_neg) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 6, r0, 0, r1)); + } else if (op == MP_QSTR_sll) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 10, r0, r1, 0)); + } else if (op == MP_QSTR_sra) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 11, r0, 0, r1)); + } else if (op == MP_QSTR_srl) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 9, r0, 0, r1)); + } else if (op == MP_QSTR_nsa) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 14, r1, r0)); + } else if (op == MP_QSTR_nsau) { + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 0, 4, 15, r1, r0)); + } else if (op == MP_QSTR_l32r) { + mp_uint_t label = get_arg_label(emit, op_str, pn_args[1]); + asm_xtensa_l32r(&emit->as, r0, label); + } else if (op == MP_QSTR_movi_n) { + mp_int_t imm = get_arg_i(emit, op_str, pn_args[1], -32, 95); + asm_xtensa_op_movi_n(&emit->as, r0, imm); + } else + #if MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES + if (op == MP_QSTR_rsr) { + mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 0, sr, r0)); + } else if (op == MP_QSTR_rur) { + mp_uint_t imm8 = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 3, 14, r0, (imm8 >> 4) & 0x0F, imm8 & 0x0F)); + } else if (op == MP_QSTR_wsr) { + mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 1, sr, r0)); + } else if (op == MP_QSTR_wur) { + mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 3, 15, sr, r0)); + } else if (op == MP_QSTR_xsr) { + mp_uint_t sr = get_arg_i(emit, op_str, pn_args[1], 0, 255); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RSR(0, 1, 6, sr, r0)); + } else + #endif + { goto unknown_op; } @@ -288,7 +408,72 @@ static void emit_inline_xtensa_op(emit_inline_asm_t *emit, qstr op, mp_uint_t n_ return; } } - goto unknown_op; + + if (op == MP_QSTR_add_n) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t r2 = get_arg_reg(emit, op_str, pn_args[2]); + asm_xtensa_op16(&emit->as, ASM_XTENSA_ENCODE_RRRN(10, r0, r1, r2)); + } else if (op == MP_QSTR_addi_n) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_int_t imm4 = get_arg_i(emit, op_str, pn_args[2], -1, 15); + asm_xtensa_op16(&emit->as, ASM_XTENSA_ENCODE_RRRN(11, r0, r1, (imm4 != 0 ? imm4 : -1))); + } else if (op == MP_QSTR_addmi) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_int_t imm8 = get_arg_i(emit, op_str, pn_args[2], -128 * 256, 127 * 256); + if ((imm8 & 0xFF) != 0) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm8, 256)); + } else { + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRI8(2, 13, r1, r0, imm8 >> 8)); + } + } else if (op == MP_QSTR_bbci) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t bit = get_arg_i(emit, op_str, pn_args[1], 0, 31); + mp_int_t label = get_arg_label(emit, op_str, pn_args[2]); + asm_xtensa_bit_branch(&emit->as, r0, bit, label, 6); + } else if (op == MP_QSTR_bbsi) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t bit = get_arg_i(emit, op_str, pn_args[1], 0, 31); + mp_uint_t label = get_arg_label(emit, op_str, pn_args[2]); + asm_xtensa_bit_branch(&emit->as, r0, bit, label, 14); + } else if (op == MP_QSTR_slli) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t bits = 32 - get_arg_i(emit, op_str, pn_args[2], 1, 31); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 0 | ((bits >> 4) & 0x01), r0, r1, bits & 0x0F)); + } else if (op == MP_QSTR_srai) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t bits = get_arg_i(emit, op_str, pn_args[2], 0, 31); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 2 | ((bits >> 4) & 0x01), r0, bits & 0x0F, r1)); + } else if (op == MP_QSTR_srli) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t bits = get_arg_i(emit, op_str, pn_args[2], 0, 15); + asm_xtensa_op24(&emit->as, ASM_XTENSA_ENCODE_RRR(0, 1, 4, r0, bits, r1)); + } else if (op == MP_QSTR_l32i_n) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t imm = get_arg_i(emit, op_str, pn_args[2], 0, 60); + if ((imm & 0x03) != 0) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm, 4)); + } else { + asm_xtensa_op_l32i_n(&emit->as, r0, r1, imm >> 2); + } + } else if (op == MP_QSTR_s32i_n) { + mp_uint_t r0 = get_arg_reg(emit, op_str, pn_args[0]); + mp_uint_t r1 = get_arg_reg(emit, op_str, pn_args[1]); + mp_uint_t imm = get_arg_i(emit, op_str, pn_args[2], 0, 60); + if ((imm & 0x03) != 0) { + emit_inline_xtensa_error_exc(emit, mp_obj_new_exception_msg_varg(&mp_type_SyntaxError, MP_ERROR_TEXT("%d is not a multiple of %d"), imm, 4)); + } else { + asm_xtensa_op_s32i_n(&emit->as, r0, r1, imm >> 2); + } + } else { + goto unknown_op; + } } else { goto unknown_op; diff --git a/py/emitnative.c b/py/emitnative.c index a888418e5df..6f12200f7e1 100644 --- a/py/emitnative.c +++ b/py/emitnative.c @@ -222,12 +222,6 @@ static const uint8_t reg_local_table[MAX_REGS_FOR_LOCAL_VARS] = {REG_LOCAL_1, RE *emit->error_slot = mp_obj_new_exception_msg_varg(&mp_type_ViperTypeError, __VA_ARGS__); \ } while (0) -#if N_RV32 -#define FIT_SIGNED(value, bits) \ - ((((value) & ~((1U << ((bits) - 1)) - 1)) == 0) || \ - (((value) & ~((1U << ((bits) - 1)) - 1)) == ~((1U << ((bits) - 1)) - 1))) -#endif - typedef enum { STACK_VALUE, STACK_REG, @@ -335,12 +329,27 @@ struct _emit_t { #define ASM_CLR_REG(state, rd) ASM_XOR_REG_REG(state, rd, rd) #endif +#if N_RV32 +#define ASM_MOV_LOCAL_MP_OBJ_NULL(as, local_num, reg_temp) \ + ASM_MOV_LOCAL_REG(as, local_num, REG_ZERO) +#else +#define ASM_MOV_LOCAL_MP_OBJ_NULL(as, local_num, reg_temp) \ + ASM_MOV_REG_IMM(as, reg_temp, (mp_uint_t)MP_OBJ_NULL); \ + ASM_MOV_LOCAL_REG(as, local_num, reg_temp) +#endif + static void emit_load_reg_with_object(emit_t *emit, int reg, mp_obj_t obj); static void emit_native_global_exc_entry(emit_t *emit); static void emit_native_global_exc_exit(emit_t *emit); static void emit_native_load_const_obj(emit_t *emit, mp_obj_t obj); emit_t *EXPORT_FUN(new)(mp_emit_common_t * emit_common, mp_obj_t *error_slot, uint *label_slot, mp_uint_t max_num_labels) { + // Generated code performing exception handling assumes that MP_OBJ_NULL + // equals to 0 to simplify some checks, leveraging dedicated opcodes for + // comparisons against 0. If this assumption does not hold true anymore + // then generated code won't work correctly. + MP_STATIC_ASSERT(MP_OBJ_NULL == 0); + emit_t *emit = m_new0(emit_t, 1); emit->emit_common = emit_common; emit->error_slot = error_slot; @@ -467,6 +476,30 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_info[i].vtype = VTYPE_UNBOUND; } + char *qualified_name = NULL; + + #if N_DEBUG + scope_t *current_scope = scope; + vstr_t *qualified_name_vstr = vstr_new(qstr_len(current_scope->simple_name)); + size_t fragment_length = 0; + const byte *fragment_pointer; + for (;;) { + fragment_pointer = qstr_data(current_scope->simple_name, &fragment_length); + vstr_hint_size(qualified_name_vstr, fragment_length); + memmove(qualified_name_vstr->buf + fragment_length, qualified_name_vstr->buf, qualified_name_vstr->len); + memcpy(qualified_name_vstr->buf, fragment_pointer, fragment_length); + qualified_name_vstr->len += fragment_length; + if (current_scope->parent == NULL || current_scope->parent->simple_name == MP_QSTR__lt_module_gt_) { + break; + } + vstr_ins_char(qualified_name_vstr, 0, '.'); + current_scope = current_scope->parent; + } + qualified_name = vstr_null_terminated_str(qualified_name_vstr); + #else + (void)qualified_name; + #endif + mp_asm_base_start_pass(&emit->as->base, pass == MP_PASS_EMIT ? MP_ASM_PASS_EMIT : MP_ASM_PASS_COMPUTE); // generate code for entry to function @@ -513,7 +546,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } // Entry to function - ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs); + ASM_ENTRY(emit->as, emit->stack_start + emit->n_state - num_locals_in_regs, qualified_name); #if N_X86 asm_x86_mov_arg_to_r32(emit->as, 0, REG_PARENT_ARG_1); @@ -584,7 +617,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop if (emit->scope->scope_flags & MP_SCOPE_FLAG_GENERATOR) { mp_asm_base_data(&emit->as->base, ASM_WORD_SIZE, (uintptr_t)emit->start_offset); - ASM_ENTRY(emit->as, emit->code_state_start); + ASM_ENTRY(emit->as, emit->code_state_start, qualified_name); // Reset the state size for the state pointed to by REG_GENERATOR_STATE emit->code_state_start = 0; @@ -616,7 +649,7 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop emit->stack_start = emit->code_state_start + SIZEOF_CODE_STATE; // Allocate space on C-stack for code_state structure, which includes state - ASM_ENTRY(emit->as, emit->stack_start + emit->n_state); + ASM_ENTRY(emit->as, emit->stack_start + emit->n_state, qualified_name); // Prepare incoming arguments for call to mp_setup_code_state @@ -682,6 +715,10 @@ static void emit_native_start_pass(emit_t *emit, pass_kind_t pass, scope_t *scop } } } + + #if N_DEBUG + vstr_free(qualified_name_vstr); + #endif } static inline void emit_native_write_code_info_byte(emit_t *emit, byte val) { @@ -1311,8 +1348,7 @@ static void emit_native_global_exc_entry(emit_t *emit) { // Check LOCAL_IDX_THROW_VAL for any injected value ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_THROW_VAL(emit)); - ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); emit_call(emit, MP_F_NATIVE_RAISE); } } @@ -1579,87 +1615,50 @@ static void emit_native_load_subscr(emit_t *emit) { switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory - // TODO optimise to use thumb ldrb r1, [r2, r3] + #ifdef ASM_LOAD8_REG_REG_OFFSET + ASM_LOAD8_REG_REG_OFFSET(emit->as, REG_RET, reg_base, index_value); + #else if (index_value != 0) { // index is non-zero - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_ldrb_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 12)) { - asm_rv32_opcode_lbu(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_op_l8ui(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base reg_base = reg_index; } ASM_LOAD8_REG_REG(emit->as, REG_RET, reg_base); // load from (base+index) + #endif break; } case VTYPE_PTR16: { // pointer to 16-bit memory + #ifdef ASM_LOAD16_REG_REG_OFFSET + ASM_LOAD16_REG_REG_OFFSET(emit->as, REG_RET, reg_base, index_value); + #else if (index_value != 0) { // index is a non-zero immediate - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_ldrh_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 11)) { - asm_rv32_opcode_lhu(emit->as, REG_RET, reg_base, index_value << 1); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_op_l16ui(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base reg_base = reg_index; } ASM_LOAD16_REG_REG(emit->as, REG_RET, reg_base); // load from (base+2*index) + #endif break; } case VTYPE_PTR32: { // pointer to 32-bit memory + #ifdef ASM_LOAD32_REG_REG_OFFSET + ASM_LOAD32_REG_REG_OFFSET(emit->as, REG_RET, reg_base, index_value); + #else if (index_value != 0) { // index is a non-zero immediate - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_ldr_rlo_rlo_i5(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 10)) { - asm_rv32_opcode_lw(emit->as, REG_RET, reg_base, index_value << 2); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_l32i_optimised(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif need_reg_single(emit, reg_index, 0); ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base reg_base = reg_index; } ASM_LOAD32_REG_REG(emit->as, REG_RET, reg_base); // load from (base+4*index) + #endif break; } default: @@ -1680,40 +1679,36 @@ static void emit_native_load_subscr(emit_t *emit) { switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory - // TODO optimise to use thumb ldrb r1, [r2, r3] + #ifdef ASM_LOAD8_REG_REG_REG + ASM_LOAD8_REG_REG_REG(emit->as, REG_RET, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_LOAD8_REG_REG(emit->as, REG_RET, REG_ARG_1); // store value to (base+index) + #endif break; } case VTYPE_PTR16: { // pointer to 16-bit memory - #if N_XTENSA || N_XTENSAWIN - asm_xtensa_op_addx2(emit->as, REG_ARG_1, reg_index, REG_ARG_1); - asm_xtensa_op_l16ui(emit->as, REG_RET, REG_ARG_1, 0); - break; - #endif + #ifdef ASM_LOAD16_REG_REG_REG + ASM_LOAD16_REG_REG_REG(emit->as, REG_RET, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_LOAD16_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+2*index) + #endif break; } case VTYPE_PTR32: { // pointer to word-size memory - #if N_RV32 - asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2); - asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2); - asm_rv32_opcode_lw(emit->as, REG_RET, REG_ARG_1, 0); - break; - #elif N_XTENSA || N_XTENSAWIN - asm_xtensa_op_addx4(emit->as, REG_ARG_1, reg_index, REG_ARG_1); - asm_xtensa_op_l32i_n(emit->as, REG_RET, REG_ARG_1, 0); - break; - #endif + #ifdef ASM_LOAD32_REG_REG_REG + ASM_LOAD32_REG_REG_REG(emit->as, REG_RET, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_LOAD32_REG_REG(emit->as, REG_RET, REG_ARG_1); // load from (base+4*index) + #endif break; } default: @@ -1856,92 +1851,47 @@ static void emit_native_store_subscr(emit_t *emit) { switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory - // TODO optimise to use thumb strb r1, [r2, r3] + #ifdef ASM_STORE8_REG_REG_OFFSET + ASM_STORE8_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value); + #else if (index_value != 0) { // index is non-zero - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_strb_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 12)) { - asm_rv32_opcode_sb(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_op_s8i(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif ASM_MOV_REG_IMM(emit->as, reg_index, index_value); - #if N_ARM - asm_arm_strb_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); - return; - #endif ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add index to base reg_base = reg_index; } ASM_STORE8_REG_REG(emit->as, reg_value, reg_base); // store value to (base+index) + #endif break; } case VTYPE_PTR16: { // pointer to 16-bit memory + #ifdef ASM_STORE16_REG_REG_OFFSET + ASM_STORE16_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value); + #else if (index_value != 0) { // index is a non-zero immediate - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_strh_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 11)) { - asm_rv32_opcode_sh(emit->as, reg_value, reg_base, index_value << 1); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_op_s16i(emit->as, REG_RET, reg_base, index_value); - break; - } - #endif ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 1); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 2*index to base reg_base = reg_index; } ASM_STORE16_REG_REG(emit->as, reg_value, reg_base); // store value to (base+2*index) + #endif break; } case VTYPE_PTR32: { // pointer to 32-bit memory + #ifdef ASM_STORE32_REG_REG_OFFSET + ASM_STORE32_REG_REG_OFFSET(emit->as, reg_value, reg_base, index_value); + #else if (index_value != 0) { // index is a non-zero immediate - #if N_THUMB - if (index_value > 0 && index_value < 32) { - asm_thumb_str_rlo_rlo_i5(emit->as, reg_value, reg_base, index_value); - break; - } - #elif N_RV32 - if (FIT_SIGNED(index_value, 10)) { - asm_rv32_opcode_sw(emit->as, reg_value, reg_base, index_value << 2); - break; - } - #elif N_XTENSA || N_XTENSAWIN - if (index_value > 0 && index_value < 256) { - asm_xtensa_s32i_optimised(emit->as, REG_RET, reg_base, index_value); - break; - } - #elif N_ARM - ASM_MOV_REG_IMM(emit->as, reg_index, index_value); - asm_arm_str_reg_reg_reg(emit->as, reg_value, reg_base, reg_index); - return; - #endif ASM_MOV_REG_IMM(emit->as, reg_index, index_value << 2); ASM_ADD_REG_REG(emit->as, reg_index, reg_base); // add 4*index to base reg_base = reg_index; } ASM_STORE32_REG_REG(emit->as, reg_value, reg_base); // store value to (base+4*index) + #endif break; } default: @@ -1972,50 +1922,36 @@ static void emit_native_store_subscr(emit_t *emit) { switch (vtype_base) { case VTYPE_PTR8: { // pointer to 8-bit memory - // TODO optimise to use thumb strb r1, [r2, r3] - #if N_ARM - asm_arm_strb_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); - break; - #endif + #ifdef ASM_STORE8_REG_REG_REG + ASM_STORE8_REG_REG_REG(emit->as, reg_value, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_STORE8_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+index) + #endif break; } case VTYPE_PTR16: { // pointer to 16-bit memory - #if N_ARM - asm_arm_strh_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); - break; - #elif N_XTENSA || N_XTENSAWIN - asm_xtensa_op_addx2(emit->as, REG_ARG_1, reg_index, REG_ARG_1); - asm_xtensa_op_s16i(emit->as, reg_value, REG_ARG_1, 0); - break; - #endif + #ifdef ASM_STORE16_REG_REG_REG + ASM_STORE16_REG_REG_REG(emit->as, reg_value, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_STORE16_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+2*index) + #endif break; } case VTYPE_PTR32: { // pointer to 32-bit memory - #if N_ARM - asm_arm_str_reg_reg_reg(emit->as, reg_value, REG_ARG_1, reg_index); - break; - #elif N_RV32 - asm_rv32_opcode_slli(emit->as, REG_TEMP2, reg_index, 2); - asm_rv32_opcode_cadd(emit->as, REG_ARG_1, REG_TEMP2); - asm_rv32_opcode_sw(emit->as, reg_value, REG_ARG_1, 0); - break; - #elif N_XTENSA || N_XTENSAWIN - asm_xtensa_op_addx4(emit->as, REG_ARG_1, reg_index, REG_ARG_1); - asm_xtensa_op_s32i_n(emit->as, reg_value, REG_ARG_1, 0); - break; - #endif + #ifdef ASM_STORE32_REG_REG_REG + ASM_STORE32_REG_REG_REG(emit->as, reg_value, REG_ARG_1, reg_index); + #else ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_ADD_REG_REG(emit->as, REG_ARG_1, reg_index); // add index to base ASM_STORE32_REG_REG(emit->as, reg_value, REG_ARG_1); // store value to (base+4*index) + #endif break; } default: @@ -2328,8 +2264,7 @@ static void emit_native_with_cleanup(emit_t *emit, mp_uint_t label) { // Replace exception with MP_OBJ_NULL. emit_native_label_assign(emit, *emit->label_slot); - ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); // end of with cleanup nlr_catch block emit_native_label_assign(emit, *emit->label_slot + 1); @@ -2436,8 +2371,7 @@ static void emit_native_for_iter_end(emit_t *emit) { static void emit_native_pop_except_jump(emit_t *emit, mp_uint_t label, bool within_exc_handler) { if (within_exc_handler) { // Cancel any active exception so subsequent handlers don't see it - ASM_MOV_REG_IMM(emit->as, REG_TEMP0, (mp_uint_t)MP_OBJ_NULL); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_EXC_VAL(emit), REG_TEMP0); } else { emit_native_leave_exc_stack(emit, false); } @@ -3122,8 +3056,7 @@ static void emit_native_yield(emit_t *emit, int kind) { if (kind == MP_EMIT_YIELD_VALUE) { // Check LOCAL_IDX_THROW_VAL for any injected value ASM_MOV_REG_LOCAL(emit->as, REG_ARG_1, LOCAL_IDX_THROW_VAL(emit)); - ASM_MOV_REG_IMM(emit->as, REG_ARG_2, (mp_uint_t)MP_OBJ_NULL); - ASM_MOV_LOCAL_REG(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); + ASM_MOV_LOCAL_MP_OBJ_NULL(emit->as, LOCAL_IDX_THROW_VAL(emit), REG_ARG_2); emit_call(emit, MP_F_NATIVE_RAISE); } else { // Label loop entry diff --git a/py/emitndebug.c b/py/emitndebug.c index bd896a75c8d..e49c5cdbffa 100644 --- a/py/emitndebug.c +++ b/py/emitndebug.c @@ -108,8 +108,8 @@ static void asm_debug_end_pass(asm_debug_t *as) { (void)as; } -static void asm_debug_entry(asm_debug_t *as, int num_locals) { - asm_debug_printf(as, "ENTRY(num_locals=%d)\n", num_locals); +static void asm_debug_entry(asm_debug_t *as, int num_locals, char *name) { + asm_debug_printf(as, "ENTRY(%s, num_locals=%d)\n", name != NULL ? name : "?", num_locals); } static void asm_debug_exit(asm_debug_t *as) { @@ -195,8 +195,8 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #define ASM_T asm_debug_t #define ASM_END_PASS asm_debug_end_pass -#define ASM_ENTRY(as, num_locals) \ - asm_debug_entry(as, num_locals) +#define ASM_ENTRY(as, num_locals, name) \ + asm_debug_entry(as, num_locals, name) #define ASM_EXIT(as) \ asm_debug_exit(as) @@ -251,8 +251,6 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #define ASM_MUL_REG_REG(as, reg_dest, reg_src) \ asm_debug_reg_reg(as, "mul", reg_dest, reg_src) -#define ASM_LOAD_REG_REG(as, reg_dest, reg_base) \ - asm_debug_reg_reg(as, "load", reg_dest, reg_base) #define ASM_LOAD_REG_REG_OFFSET(as, reg_dest, reg_base, word_offset) \ asm_debug_reg_reg_offset(as, "load", reg_dest, reg_base, word_offset) #define ASM_LOAD8_REG_REG(as, reg_dest, reg_base) \ @@ -264,8 +262,6 @@ static void asm_debug_setcc_reg_reg_reg(asm_debug_t *as, int op, int reg1, int r #define ASM_LOAD32_REG_REG(as, reg_dest, reg_base) \ asm_debug_reg_reg(as, "load32", reg_dest, reg_base) -#define ASM_STORE_REG_REG(as, reg_src, reg_base) \ - asm_debug_reg_reg(as, "store", reg_src, reg_base) #define ASM_STORE_REG_REG_OFFSET(as, reg_src, reg_base, word_offset) \ asm_debug_reg_reg_offset(as, "store", reg_src, reg_base, word_offset) #define ASM_STORE8_REG_REG(as, reg_src, reg_base) \ diff --git a/py/formatfloat.c b/py/formatfloat.c index b4348122ff4..1ea34f84bf7 100644 --- a/py/formatfloat.c +++ b/py/formatfloat.c @@ -33,394 +33,537 @@ #include #include #include "py/formatfloat.h" +#include "py/parsenum.h" /*********************************************************************** Routine for converting a arbitrary floating point number into a string. - The code in this function was inspired from Fred Bayer's pdouble.c. - Since pdouble.c was released as Public Domain, I'm releasing this - code as public domain as well. + The code in this function was inspired from Dave Hylands's previous + version, which was itself inspired from Fred Bayer's pdouble.c. The original code can be found in https://github.com/dhylands/format-float - Dave Hylands - ***********************************************************************/ -#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT -// 1 sign bit, 8 exponent bits, and 23 mantissa bits. -// exponent values 0 and 255 are reserved, exponent can be 1 to 254. -// exponent is stored with a bias of 127. -// The min and max floats are on the order of 1x10^37 and 1x10^-37 - -#define FPTYPE float -#define FPCONST(x) x##F -#define FPROUND_TO_ONE 0.9999995F -#define FPDECEXP 32 -#define FPMIN_BUF_SIZE 6 // +9e+99 +// Float formatting debug code is intended for use in ports/unix only, +// as it uses the libc float printing function as a reference. +#define DEBUG_FLOAT_FORMATTING 0 + +#if DEBUG_FLOAT_FORMATTING +#define DEBUG_PRINTF(...) fprintf(stderr, __VA_ARGS__) +#else +#define DEBUG_PRINTF(...) +#endif + +#if MICROPY_FLOAT_FORMAT_IMPL == MICROPY_FLOAT_FORMAT_IMPL_EXACT || MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define MP_FFUINT_FMT "%lu" +#else +#define MP_FFUINT_FMT "%u" +#endif + +static inline int fp_expval(mp_float_t x) { + mp_float_union_t fb = { x }; + return (int)fb.p.exp - MP_FLOAT_EXP_OFFSET; +} -#define FLT_SIGN_MASK 0x80000000 +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE -static inline int fp_signbit(float x) { - mp_float_union_t fb = {x}; - return fb.i & FLT_SIGN_MASK; +static inline int fp_isless1(mp_float_t x) { + return x < 1.0; } -#define fp_isnan(x) isnan(x) -#define fp_isinf(x) isinf(x) -static inline int fp_iszero(float x) { - mp_float_union_t fb = {x}; - return fb.i == 0; + +static inline int fp_iszero(mp_float_t x) { + return x == 0.0; } -static inline int fp_isless1(float x) { - mp_float_union_t fb = {x}; + +#if MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_APPROX +static inline int fp_equal(mp_float_t x, mp_float_t y) { + return x == y; +} +#else +static inline mp_float_t fp_diff(mp_float_t x, mp_float_t y) { + return x - y; +} +#endif + +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + +// The functions below are roughly equivalent to the ones above, +// but they are optimized to reduce code footprint by skipping +// handling for special values such as nan, inf, +/-0.0 +// for ports where FP support is done in software. +// +// They also take into account lost bits of REPR_C as needed. + +static inline int fp_isless1(mp_float_t x) { + mp_float_union_t fb = { x }; return fb.i < 0x3f800000; } -#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +static inline int fp_iszero(mp_float_t x) { + mp_float_union_t x_check = { x }; + return !x_check.i; // this is valid for REPR_C as well +} -// CIRCUITPY-CHANGE: prevent warnings -#pragma GCC diagnostic ignored "-Wfloat-equal" -#define FPTYPE double -#define FPCONST(x) x -#define FPROUND_TO_ONE 0.999999999995 -#define FPDECEXP 256 -#define FPMIN_BUF_SIZE 7 // +9e+199 -#define fp_signbit(x) signbit(x) -#define fp_isnan(x) isnan(x) -#define fp_isinf(x) isinf(x) -#define fp_iszero(x) (x == 0) -#define fp_isless1(x) (x < 1.0) +#if MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_APPROX +static inline int fp_equal(mp_float_t x, mp_float_t y) { + mp_float_union_t x_check = { x }; + mp_float_union_t y_check = { y }; + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + return (x_check.i & ~3) == (y_check.i & ~3); + #else + return x_check.i == y_check.i; + #endif +} +#else +static inline mp_float_t fp_diff(mp_float_t x, mp_float_t y) { + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C + mp_float_union_t x_check = { x }; + mp_float_union_t y_check = { y }; + x_check.i &= ~3; + y_check.i &= ~3; + return x_check.f - y_check.f; + #else + return x - y; + #endif +} +#endif -#endif // MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT/DOUBLE +#endif -static inline int fp_expval(FPTYPE x) { - mp_float_union_t fb = {x}; - return (int)((fb.i >> MP_FLOAT_FRAC_BITS) & (~(0xFFFFFFFF << MP_FLOAT_EXP_BITS))) - MP_FLOAT_EXP_OFFSET; +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define FPMIN_BUF_SIZE 6 // +9e+99 +#define MAX_MANTISSA_DIGITS (9) +#define SAFE_MANTISSA_DIGITS (6) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define FPMIN_BUF_SIZE 7 // +9e+199 +#define MAX_MANTISSA_DIGITS (19) +#define SAFE_MANTISSA_DIGITS (16) +#endif + +// Internal formatting flags +#define FMT_MODE_E 0x01 // render using scientific notation (%e) +#define FMT_MODE_G 0x02 // render using general format (%g) +#define FMT_MODE_F 0x04 // render using using expanded fixed-point format (%f) +#define FMT_E_CASE 0x20 // don't change this value (used for case conversion!) + +static char *mp_prepend_zeros(char *s, int cnt) { + *s++ = '0'; + *s++ = '.'; + while (cnt > 0) { + *s++ = '0'; + cnt--; + } + return s; } -int mp_format_float(FPTYPE f, char *buf, size_t buf_size, char fmt, int prec, char sign) { +// Helper to convert a decimal mantissa (provided as an mp_large_float_uint_t) to string +static int mp_format_mantissa(mp_large_float_uint_t mantissa, mp_large_float_uint_t mantissa_cap, char *buf, char *s, + int num_digits, int max_exp_zeros, int trailing_zeros, int dec, int e, int fmt_flags) { - char *s = buf; + DEBUG_PRINTF("mantissa=" MP_FFUINT_FMT " exp=%d (cap=" MP_FFUINT_FMT "):\n", mantissa, e, mantissa_cap); - if (buf_size <= FPMIN_BUF_SIZE) { - // FPMIN_BUF_SIZE is the minimum size needed to store any FP number. - // If the buffer does not have enough room for this (plus null terminator) - // then don't try to format the float. + if (mantissa) { + // If rounding/searching created an extra digit or removed too many, fix mantissa first + if (mantissa >= mantissa_cap) { + if (fmt_flags & FMT_MODE_F) { + assert(e >= 0); + num_digits++; + dec++; + } else { + mantissa /= 10; + e++; + } + } + } - if (buf_size >= 2) { - *s++ = '?'; + // When 'g' format is used, replace small exponents by explicit zeros + if ((fmt_flags & FMT_MODE_G) && e != 0) { + if (e >= 0) { + // If 0 < e < max_exp_zeros, expand positive exponent into trailing zeros + if (e < max_exp_zeros) { + dec += e; + if (dec >= num_digits) { + trailing_zeros = dec - (num_digits - 1); + } + e = 0; + } + } else { + // If -4 <= e < 0, expand negative exponent without losing significant digits + if (e >= -4) { + int cnt = 0; + while (e < 0 && !(mantissa % 10)) { + mantissa /= 10; + cnt++; + e++; + } + num_digits -= cnt; + s = mp_prepend_zeros(s, cnt - e - 1); + dec = 255; + e = 0; + } } - if (buf_size >= 1) { - *s = '\0'; + } + + // Convert the integer mantissa to string + for (int digit = num_digits - 1; digit >= 0; digit--) { + int digit_ofs = (digit > dec ? digit + 1 : digit); + s[digit_ofs] = '0' + (int)(mantissa % 10); + mantissa /= 10; + } + int dot = (dec >= 255); + if (dec + 1 < num_digits) { + dot = 1; + s++; + s[dec] = '.'; + } + s += num_digits; + #if DEBUG_FLOAT_FORMATTING + *s = 0; + DEBUG_PRINTF(" = %s exp=%d num_digits=%d zeros=%d dec=%d\n", buf, e, num_digits, trailing_zeros, dec); + #endif + + // Append or remove trailing zeros, as required by format + if (trailing_zeros) { + dec -= num_digits - 1; + while (trailing_zeros--) { + if (!dec--) { + *s++ = '.'; + dot = 1; + } + *s++ = '0'; } - return buf_size >= 2; } - if (fp_signbit(f) && !fp_isnan(f)) { - *s++ = '-'; - f = -f; - } else { - if (sign) { - *s++ = sign; + if (fmt_flags & FMT_MODE_G) { + // 'g' format requires to remove trailing zeros after decimal point + if (dot) { + while (s[-1] == '0') { + s--; + } + if (s[-1] == '.') { + s--; + } + } + } + + // Append the exponent if needed + if (((e != 0) || (fmt_flags & FMT_MODE_E)) && !(fmt_flags & FMT_MODE_F)) { + *s++ = 'E' | (fmt_flags & FMT_E_CASE); + if (e >= 0) { + *s++ = '+'; + } else { + *s++ = '-'; + e = -e; } + if (e >= 100) { + *s++ = '0' + (e / 100); + } + *s++ = '0' + ((e / 10) % 10); + *s++ = '0' + (e % 10); } + *s = '\0'; + DEBUG_PRINTF(" ===> %s\n", buf); - // buf_remaining contains bytes available for digits and exponent. - // It is buf_size minus room for the sign and null byte. - int buf_remaining = buf_size - 1 - (s - buf); + return s - buf; +} +// minimal value expected for buf_size, to avoid checking everywhere for overflow +#define MIN_BUF_SIZE (MAX_MANTISSA_DIGITS + 10) + +int mp_format_float(mp_float_t f_entry, char *buf_entry, size_t buf_size, char fmt, int prec, char sign) { + assert(buf_size >= MIN_BUF_SIZE); + + // Handle sign + mp_float_t f = f_entry; + char *buf = buf_entry; + if (signbit(f_entry) && !isnan(f_entry)) { + f = -f; + sign = '-'; + } + if (sign) { + *buf++ = sign; + buf_size--; + } + + // Handle inf/nan + char uc = fmt & 0x20; { - char uc = fmt & 0x20; - if (fp_isinf(f)) { + char *s = buf; + if (isinf(f)) { *s++ = 'I' ^ uc; *s++ = 'N' ^ uc; *s++ = 'F' ^ uc; goto ret; - } else if (fp_isnan(f)) { + } else if (isnan(f)) { *s++ = 'N' ^ uc; *s++ = 'A' ^ uc; *s++ = 'N' ^ uc; ret: *s = '\0'; - return s - buf; + return s - buf_entry; } } + // Decode format character + int fmt_flags = (unsigned char)uc; // setup FMT_E_CASE, clear all other bits + char lofmt = (char)(fmt | 0x20); // fmt in lowercase + if (lofmt == 'f') { + fmt_flags |= FMT_MODE_F; + } else if (lofmt == 'g') { + fmt_flags |= FMT_MODE_G; + } else { + fmt_flags |= FMT_MODE_E; + } + + // When precision is unspecified, default to 6 if (prec < 0) { prec = 6; } - char e_char = 'E' | (fmt & 0x20); // e_char will match case of fmt - fmt |= 0x20; // Force fmt to be lowercase - char org_fmt = fmt; - if (fmt == 'g' && prec == 0) { - prec = 1; + // Use high precision for `repr`, but switch to exponent mode + // after 16 digits in any case to match CPython behaviour + int max_exp_zeros = (prec < (int)buf_size - 3 ? prec : (int)buf_size - 3); + if (prec == MP_FLOAT_REPR_PREC) { + prec = MAX_MANTISSA_DIGITS; + max_exp_zeros = 16; } - int e; - int dec = 0; - char e_sign = '\0'; - int num_digits = 0; - int signed_e = 0; - // Approximate power of 10 exponent from binary exponent. - // abs(e_guess) is lower bound on abs(power of 10 exponent). - int e_guess = (int)(fp_expval(f) * FPCONST(0.3010299956639812)); // 1/log2(10). - if (fp_iszero(f)) { - e = 0; - if (fmt == 'f') { - // Truncate precision to prevent buffer overflow - if (prec + 2 > buf_remaining) { - prec = buf_remaining - 2; - } - num_digits = prec + 1; - } else { - // Truncate precision to prevent buffer overflow - if (prec + 6 > buf_remaining) { - prec = buf_remaining - 6; - } - if (fmt == 'e') { - e_sign = '+'; - } + // Precompute the exact decimal exponent of f, such that + // abs(e) is lower bound on abs(power of 10 exponent). + int e = 0; + if (!fp_iszero(f)) { + // Approximate power of 10 exponent from binary exponent. + e = (int)(fp_expval(f) * MICROPY_FLOAT_CONST(0.3010299956639812)); // 1/log2(10). + int positive_exp = !fp_isless1(f); + mp_float_t u_base = (mp_float_t)mp_decimal_exp((mp_large_float_t)1.0, e + positive_exp); + while ((f >= u_base) == positive_exp) { + e += (positive_exp ? 1 : -1); + u_base = (mp_float_t)mp_decimal_exp((mp_large_float_t)1.0, e + positive_exp); } - } else if (fp_isless1(f)) { - FPTYPE f_entry = f; // Save f in case we go to 'f' format. - // Build negative exponent - e = -e_guess; - FPTYPE u_base = MICROPY_FLOAT_C_FUN(pow)(10, -e); - while (u_base > f) { - ++e; - u_base = MICROPY_FLOAT_C_FUN(pow)(10, -e); - } - // Normalize out the inferred unit. Use divide because - // pow(10, e) * pow(10, -e) is slightly < 1 for some e in float32 - // (e.g. print("%.12f" % ((1e13) * (1e-13)))) - f /= u_base; - - // If the user specified 'g' format, and e is <= 4, then we'll switch - // to the fixed format ('f') - - if (fmt == 'f' || (fmt == 'g' && e <= 4)) { - fmt = 'f'; - dec = 0; + } - if (org_fmt == 'g') { - prec += (e - 1); - } + // For 'e' format, prec is # digits after the decimal + // For 'f' format, prec is # digits after the decimal + // For 'g' format, prec is the max number of significant digits + // + // For 'e' & 'g' format, there will be a single digit before the decimal + // For 'f' format, zeros must be expanded instead of using an exponent. + // Make sure there is enough room in the buffer for them, or switch to format 'g'. + if ((fmt_flags & FMT_MODE_F) && e > 0) { + int req_size = e + prec + 2; + if (req_size > (int)buf_size) { + fmt_flags ^= FMT_MODE_F; + fmt_flags |= FMT_MODE_G; + prec++; + } + } - // truncate precision to prevent buffer overflow - if (prec + 2 > buf_remaining) { - prec = buf_remaining - 2; + // To work independently of the format, we precompute: + // - the max number of significant digits to produce + // - the number of leading zeros to prepend (mode f only) + // - the number of trailing zeros to append + int max_digits = prec; + int lead_zeros = 0; + int trail_zeros = 0; + if (fmt_flags & FMT_MODE_F) { + if (max_digits > (int)buf_size - 3) { + // cannot satisfy requested number of decimals given buf_size, sorry + max_digits = (int)buf_size - 3; + } + if (e < 0) { + if (max_digits > 2 && e < -2) { + // Insert explicit leading zeros + lead_zeros = (-e < max_digits ? -e : max_digits) - 2; + max_digits -= lead_zeros; + } else { + max_digits++; } - - num_digits = prec; - signed_e = 0; - f = f_entry; - ++num_digits; } else { - // For e & g formats, we'll be printing the exponent, so set the - // sign. - e_sign = '-'; - dec = 0; - - if (prec > (buf_remaining - FPMIN_BUF_SIZE)) { - prec = buf_remaining - FPMIN_BUF_SIZE; - if (fmt == 'g') { - prec++; - } - } - signed_e = -e; + max_digits += e + 1; } } else { - // Build positive exponent. - // We don't modify f at this point to avoid inaccuracies from - // scaling it. Instead, we find the product of powers of 10 - // that is not greater than it, and use that to start the - // mantissa. - e = e_guess; - FPTYPE next_u = MICROPY_FLOAT_C_FUN(pow)(10, e + 1); - while (f >= next_u) { - ++e; - next_u = MICROPY_FLOAT_C_FUN(pow)(10, e + 1); + if (!(fmt_flags & FMT_MODE_G) || max_digits == 0) { + max_digits++; } + } + if (max_digits > MAX_MANTISSA_DIGITS) { + // use trailing zeros to avoid overflowing the mantissa + trail_zeros = max_digits - MAX_MANTISSA_DIGITS; + max_digits = MAX_MANTISSA_DIGITS; + } + int overhead = (fmt_flags & FMT_MODE_F ? 3 : FPMIN_BUF_SIZE + 1); + if (trail_zeros > (int)buf_size - max_digits - overhead) { + // cannot satisfy requested number of decimals given buf_size, sorry + trail_zeros = (int)buf_size - max_digits - overhead; + } - // If the user specified fixed format (fmt == 'f') and e makes the - // number too big to fit into the available buffer, then we'll - // switch to the 'e' format. - - if (fmt == 'f') { - if (e >= buf_remaining) { - fmt = 'e'; - } else if ((e + prec + 2) > buf_remaining) { - prec = buf_remaining - e - 2; - if (prec < 0) { - // This means no decimal point, so we can add one back - // for the decimal. - prec++; - } - } - } - if (fmt == 'e' && prec > (buf_remaining - FPMIN_BUF_SIZE)) { - prec = buf_remaining - FPMIN_BUF_SIZE; - } - if (fmt == 'g') { - // Truncate precision to prevent buffer overflow - if (prec + (FPMIN_BUF_SIZE - 1) > buf_remaining) { - prec = buf_remaining - (FPMIN_BUF_SIZE - 1); - } - } - // If the user specified 'g' format, and e is < prec, then we'll switch - // to the fixed format. + // When the caller asks for more precision than available for sure, + // Look for a shorter (rounded) representation first, and only dig + // into more digits if there is no short representation. + int num_digits = (SAFE_MANTISSA_DIGITS < max_digits ? SAFE_MANTISSA_DIGITS : max_digits); +try_again: + ; - if (fmt == 'g' && e < prec) { - fmt = 'f'; - prec -= (e + 1); - } - if (fmt == 'f') { - dec = e; - num_digits = prec + e + 1; + char *s = buf; + int extra_zeros = trail_zeros + (max_digits - num_digits); + int decexp; + int dec = 0; + + if (fp_iszero(f)) { + // no need for scaling 0.0 + decexp = 0; + } else if (fmt_flags & FMT_MODE_F) { + decexp = num_digits - 1; + if (e < 0) { + // Negative exponent: we keep a single leading zero in the mantissa, + // as using more would waste precious digits needed for accuracy. + if (lead_zeros > 0) { + // We are using leading zeros + s = mp_prepend_zeros(s, lead_zeros); + decexp += lead_zeros + 1; + dec = 255; // no decimal dot + } else { + // Small negative exponent, work directly on the mantissa + dec = 0; + } } else { - e_sign = '+'; + // Positive exponent: we will add trailing zeros separately + decexp -= e; + dec = e; } - signed_e = e; + } else { + decexp = num_digits - e - 1; } - if (prec < 0) { - // This can happen when the prec is trimmed to prevent buffer overflow - prec = 0; + DEBUG_PRINTF("input=%.19g e=%d fmt=%c max_d=%d num_d=%d decexp=%d dec=%d l0=%d r0=%d\n", + (double)f, e, lofmt, max_digits, num_digits, decexp, dec, lead_zeros, extra_zeros); + + // At this point, + // - buf points to beginning of output buffer for the unsigned representation + // - num_digits == the number of mantissa digits to add + // - (dec + 1) == the number of digits to print before adding a decimal point + // - decexp == the power of 10 exponent to apply to f to get the decimal mantissa + // - e == the power of 10 exponent to append ('e' or 'g' format) + mp_large_float_uint_t mantissa_cap = 10; + for (int n = 1; n < num_digits; n++) { + mantissa_cap *= 10; } - // At this point e contains the absolute value of the power of 10 exponent. - // (dec + 1) == the number of dgits before the decimal. - - // For e, prec is # digits after the decimal - // For f, prec is # digits after the decimal - // For g, prec is the max number of significant digits - // - // For e & g there will be a single digit before the decimal - // for f there will be e digits before the decimal - - if (fmt == 'e') { - num_digits = prec + 1; - } else if (fmt == 'g') { - if (prec == 0) { - prec = 1; + // Build the decimal mantissa into a large uint + mp_large_float_uint_t mantissa = 1; + if (sizeof(mp_large_float_t) == sizeof(mp_float_t) && num_digits > SAFE_MANTISSA_DIGITS && decexp > 1) { + // if we don't have large floats, use integer multiply to produce the last digits + if (num_digits > SAFE_MANTISSA_DIGITS + 1 && decexp > 2) { + mantissa = 100; + decexp -= 2; + } else { + mantissa = 10; + decexp -= 1; } - num_digits = prec; } - - int d = 0; - for (int digit_index = signed_e; num_digits >= 0; --digit_index) { - FPTYPE u_base = FPCONST(1.0); - if (digit_index > 0) { - // Generate 10^digit_index for positive digit_index. - u_base = MICROPY_FLOAT_C_FUN(pow)(10, digit_index); - } - for (d = 0; d < 9; ++d) { - if (f < u_base) { - break; - } - f -= u_base; - } - // We calculate one more digit than we display, to use in rounding - // below. So only emit the digit if it's one that we display. - if (num_digits > 0) { - // Emit this number (the leading digit). - *s++ = '0' + d; - if (dec == 0 && prec > 0) { - *s++ = '.'; - } - } - --dec; - --num_digits; - if (digit_index <= 0) { - // Once we get below 1.0, we scale up f instead of calculating - // negative powers of 10 in u_base. This provides better - // renditions of exact decimals like 1/16 etc. - f *= FPCONST(10.0); + mp_large_float_t mantissa_f = mp_decimal_exp((mp_large_float_t)f, decexp); + mantissa *= (mp_large_float_uint_t)(mantissa_f + (mp_large_float_t)0.5); + DEBUG_PRINTF("input=%.19g fmt=%c num_digits=%d dec=%d mantissa=" MP_FFUINT_FMT " r0=%d\n", (double)f, lofmt, num_digits, dec, mantissa, extra_zeros); + + // Finally convert the decimal mantissa to a floating-point string, according to formatting rules + int reprlen = mp_format_mantissa(mantissa, mantissa_cap, buf, s, num_digits, max_exp_zeros, extra_zeros, dec, e, fmt_flags); + assert(reprlen + 1 <= (int)buf_size); + + #if MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_APPROX + + if (num_digits < max_digits) { + // The initial precision might not be sufficient for an exact representation + // for all numbers. If the result is not exact, restart using next precision. + // parse the resulting number and compare against the original + mp_float_t check; + DEBUG_PRINTF("input=%.19g, compare to float('%s')\n", (double)f, buf); + mp_parse_float_internal(buf, reprlen, &check); + if (!fp_equal(check, f)) { + num_digits++; + DEBUG_PRINTF("Not perfect, retry using more digits (%d)\n", num_digits); + goto try_again; } } - // Rounding. If the next digit to print is >= 5, round up. - if (d >= 5) { - char *rs = s; - rs--; - while (1) { - if (*rs == '.') { - rs--; - continue; - } - if (*rs < '0' || *rs > '9') { - // + or - - rs++; // So we sit on the digit to the right of the sign - break; + + #else + + // The initial decimal mantissa might not have been be completely accurate due + // to the previous loating point operations. The best way to verify this is to + // parse the resulting number and compare against the original + mp_float_t check; + DEBUG_PRINTF("input=%.19g, compare to float('%s')\n", (double)f, buf); + mp_parse_float_internal(buf, reprlen, &check); + mp_float_t diff = fp_diff(check, f); + mp_float_t best_diff = diff; + mp_large_float_uint_t best_mantissa = mantissa; + + if (fp_iszero(diff)) { + // we have a perfect match + DEBUG_PRINTF(MP_FFUINT_FMT ": perfect match (direct)\n", mantissa); + } else { + // In order to get the best possible representation, we will perform a + // dichotomic search for a reversible representation. + // This will also provide optimal rounding on the fly. + unsigned err_range = 1; + if (num_digits > SAFE_MANTISSA_DIGITS) { + err_range <<= 3 * (num_digits - SAFE_MANTISSA_DIGITS); + } + int maxruns = 3 + 3 * (MAX_MANTISSA_DIGITS - SAFE_MANTISSA_DIGITS); + while (maxruns-- > 0) { + // update mantissa according to dichotomic search + if (signbit(diff)) { + mantissa += err_range; + } else { + // mantissa is expected to always have more significant digits than err_range + assert(mantissa >= err_range); + mantissa -= err_range; } - if (*rs < '9') { - (*rs)++; + // retry conversion + reprlen = mp_format_mantissa(mantissa, mantissa_cap, buf, s, num_digits, max_exp_zeros, extra_zeros, dec, e, fmt_flags); + assert(reprlen + 1 <= (int)buf_size); + DEBUG_PRINTF("input=%.19g, compare to float('%s')\n", (double)f, buf); + mp_parse_float_internal(buf, reprlen, &check); + DEBUG_PRINTF("check=%.19g num_digits=%d e=%d mantissa=" MP_FFUINT_FMT "\n", (double)check, num_digits, e, mantissa); + diff = fp_diff(check, f); + if (fp_iszero(diff)) { + // we have a perfect match + DEBUG_PRINTF(MP_FFUINT_FMT ": perfect match\n", mantissa); break; } - *rs = '0'; - if (rs == buf) { - break; + // keep track of our best estimate + mp_float_t delta = MICROPY_FLOAT_C_FUN(fabs)(diff) - MICROPY_FLOAT_C_FUN(fabs)(best_diff); + if (signbit(delta) || (fp_iszero(delta) && !(mantissa % 10u))) { + best_diff = diff; + best_mantissa = mantissa; } - rs--; - } - if (*rs == '0') { - // We need to insert a 1 - if (rs[1] == '.' && fmt != 'f') { - // We're going to round 9.99 to 10.00 - // Move the decimal point - rs[0] = '.'; - rs[1] = '0'; - if (e_sign == '-') { - e--; - if (e == 0) { - e_sign = '+'; - } - } else { - e++; - } + // string repr is not perfect: continue a dichotomic improvement + DEBUG_PRINTF(MP_FFUINT_FMT ": %.19g, err_range=%d\n", mantissa, (double)check, err_range); + if (err_range > 1) { + err_range >>= 1; } else { - // Need at extra digit at the end to make room for the leading '1' - // but if we're at the buffer size limit, just drop the final digit. - if ((size_t)(s + 1 - buf) < buf_size) { - s++; + // We have tried all possible mantissa, without finding a reversible repr. + // Check if we have an alternate precision to try. + if (num_digits < max_digits) { + num_digits++; + DEBUG_PRINTF("Failed to find a perfect match, try with more digits (%d)\n", num_digits); + goto try_again; } + // Otherwise, keep the closest one, which is either the first one or the last one. + if (mantissa == best_mantissa) { + // Last guess is the best one + DEBUG_PRINTF(MP_FFUINT_FMT ": last guess was the best one\n", mantissa); + } else { + // We had a better guess earlier + DEBUG_PRINTF(MP_FFUINT_FMT ": use best guess\n", mantissa); + reprlen = mp_format_mantissa(best_mantissa, mantissa_cap, buf, s, num_digits, max_exp_zeros, extra_zeros, dec, e, fmt_flags); + } + break; } - char *ss = s; - while (ss > rs) { - *ss = ss[-1]; - ss--; - } - *rs = '1'; } } + #endif - // verify that we did not overrun the input buffer so far - assert((size_t)(s + 1 - buf) <= buf_size); - - if (org_fmt == 'g' && prec > 0) { - // Remove trailing zeros and a trailing decimal point - while (s[-1] == '0') { - s--; - } - if (s[-1] == '.') { - s--; - } - } - // Append the exponent - if (e_sign) { - *s++ = e_char; - *s++ = e_sign; - if (FPMIN_BUF_SIZE == 7 && e >= 100) { - *s++ = '0' + (e / 100); - } - *s++ = '0' + ((e / 10) % 10); - *s++ = '0' + (e % 10); - } - *s = '\0'; - - // verify that we did not overrun the input buffer - assert((size_t)(s + 1 - buf) <= buf_size); - - return s - buf; + return buf + reprlen - buf_entry; } #endif // MICROPY_FLOAT_IMPL != MICROPY_FLOAT_IMPL_NONE diff --git a/py/formatfloat.h b/py/formatfloat.h index 9a1643b4ddf..7b1414672b7 100644 --- a/py/formatfloat.h +++ b/py/formatfloat.h @@ -29,6 +29,7 @@ #include "py/mpconfig.h" #if MICROPY_PY_BUILTINS_FLOAT +#define MP_FLOAT_REPR_PREC (99) // magic `prec` value for optimal `repr` behaviour int mp_format_float(mp_float_t f, char *buf, size_t bufSize, char fmt, int prec, char sign); #endif diff --git a/py/gc.c b/py/gc.c index fc7de6c4d3b..757c27e3de6 100644 --- a/py/gc.c +++ b/py/gc.c @@ -1447,7 +1447,7 @@ void gc_dump_alloc_table(const mp_print_t *print) { } if (bl2 - bl >= 2 * DUMP_BYTES_PER_LINE) { // there are at least 2 lines containing only free blocks, so abbreviate their printing - mp_printf(print, "\n (%u lines all free)", (uint)(bl2 - bl) / DUMP_BYTES_PER_LINE); + mp_printf(print, "\n (%u lines all free)", (uint)((bl2 - bl) / DUMP_BYTES_PER_LINE)); bl = bl2 & (~(DUMP_BYTES_PER_LINE - 1)); if (bl >= area->gc_alloc_table_byte_len * BLOCKS_PER_ATB) { // got to end of heap @@ -1490,7 +1490,7 @@ void gc_dump_alloc_table(const mp_print_t *print) { break; } */ - /* this prints the uPy object type of the head block */ + /* this prints the MicroPython object type of the head block */ case AT_HEAD: { // CIRCUITPY-CHANGE: compiler warning avoidance #pragma GCC diagnostic push diff --git a/py/gc.h b/py/gc.h index 0752478d1f2..f9028d637c5 100644 --- a/py/gc.h +++ b/py/gc.h @@ -71,6 +71,11 @@ bool gc_alloc_possible(void); // Use this function to sweep the whole heap and run all finalisers void gc_sweep_all(void); +// These functions are used to manage weakrefs. +void gc_weakref_mark(void *ptr); +void gc_weakref_about_to_be_freed(void *ptr); +void gc_weakref_sweep(void); + enum { GC_ALLOC_FLAG_HAS_FINALISER = 1, // CIRCUITPY-CHANGE diff --git a/py/make_root_pointers.py b/py/make_root_pointers.py index efe398b8227..5da343c1270 100644 --- a/py/make_root_pointers.py +++ b/py/make_root_pointers.py @@ -6,8 +6,6 @@ "struct _mp_state_vm_t" in py/mpstate.h """ -from __future__ import print_function - import argparse import io import re diff --git a/py/makecompresseddata.py b/py/makecompresseddata.py index 1bce3e8e837..a6fa7db00b2 100644 --- a/py/makecompresseddata.py +++ b/py/makecompresseddata.py @@ -1,5 +1,3 @@ -from __future__ import print_function - import collections import re import sys diff --git a/py/makemoduledefs.py b/py/makemoduledefs.py index 29162ab387c..c8fdc21f6fb 100644 --- a/py/makemoduledefs.py +++ b/py/makemoduledefs.py @@ -14,8 +14,6 @@ the built-in version. """ -from __future__ import print_function - import sys import re import io @@ -87,19 +85,25 @@ def generate_module_table_header(modules): ) ) + # There should always be at least one module (__main__ in runtime.c) + assert mod_defs + print("\n#define MICROPY_REGISTERED_MODULES \\") for mod_def in sorted(mod_defs): print(" {mod_def} \\".format(mod_def=mod_def)) - print("// MICROPY_REGISTERED_MODULES") - print("\n#define MICROPY_REGISTERED_EXTENSIBLE_MODULES \\") + # There are not necessarily any extensible modules (e.g., bare-arm or minimal x86) + print("\n#define MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES ", len(extensible_mod_defs)) - for mod_def in sorted(extensible_mod_defs): - print(" {mod_def} \\".format(mod_def=mod_def)) + if extensible_mod_defs: + print("\n#define MICROPY_REGISTERED_EXTENSIBLE_MODULES \\") + + for mod_def in sorted(extensible_mod_defs): + print(" {mod_def} \\".format(mod_def=mod_def)) - print("// MICROPY_REGISTERED_EXTENSIBLE_MODULES") + print("// MICROPY_REGISTERED_EXTENSIBLE_MODULES") def generate_module_delegations(delegations): diff --git a/py/makeqstrdata.py b/py/makeqstrdata.py index 998328bf1d2..3fdb2d5476b 100644 --- a/py/makeqstrdata.py +++ b/py/makeqstrdata.py @@ -1,31 +1,13 @@ """ Process raw qstr file and output qstr data with length, hash and data bytes. -This script works with Python 2.7, 3.3 and 3.4. - -CIRCUITPY-CHANGE: -For documentation about the format of compressed translated strings, see -supervisor/shared/translate/translate.h +This script works with Python 3.3+. """ -from __future__ import print_function - - import re import sys -# CIRCUITPY-CHANGE -if hasattr(sys.stdout, "reconfigure"): - sys.stdout.reconfigure(encoding="utf-8") - sys.stderr.reconfigure(errors="backslashreplace") - -# Python 2/3 compatibility: -# - iterating through bytes is different -# - codepoint2name from html.entities is hard-coded -if sys.version_info[0] == 2: - bytes_cons = lambda val, enc=None: bytearray(val) -elif sys.version_info[0] == 3: # Also handles MicroPython - bytes_cons = bytes +bytes_cons = bytes # fmt: off codepoint2name = { @@ -67,7 +49,6 @@ 253: "yacute", 165: "yen", 255: "yuml", 950: "zeta", 8205: "zwj", 8204: "zwnj" } # fmt: on -# end compatibility code codepoint2name[ord("-")] = "hyphen" diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index a4039857694..99ba6e2f9e5 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -2,11 +2,9 @@ This script processes the output from the C preprocessor and extracts all qstr. Each qstr is transformed into a qstr definition of the form 'Q(...)'. -This script works with Python 3.x (CIRCUITPY-CHANGE: not 2.x) +This script works with Python 3.3+. """ -from __future__ import print_function - import io import os import re diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py index 307bfac1e9a..09d67d87f8a 100644 --- a/py/makeversionhdr.py +++ b/py/makeversionhdr.py @@ -5,8 +5,6 @@ This script works with Python 3.7 and newer """ -from __future__ import print_function - import argparse import sys import os @@ -29,6 +27,25 @@ def cannot_determine_version(): make fetch-tags""" ) + with open(os.path.join(repo_path, "py", "mpconfig.h")) as f: + for line in f: + if line.startswith("#define MICROPY_VERSION_MAJOR "): + ver_major = int(line.strip().split()[2]) + elif line.startswith("#define MICROPY_VERSION_MINOR "): + ver_minor = int(line.strip().split()[2]) + elif line.startswith("#define MICROPY_VERSION_MICRO "): + ver_micro = int(line.strip().split()[2]) + elif line.startswith("#define MICROPY_VERSION_PRERELEASE "): + ver_prerelease = int(line.strip().split()[2]) + git_tag = "v%d.%d.%d%s" % ( + ver_major, + ver_minor, + ver_micro, + "-preview" if ver_prerelease else "", + ) + return git_tag + return None + def make_version_header(repo_path, filename): # Get version info using git (required) diff --git a/py/malloc.c b/py/malloc.c index fcf930ecfaa..c2a20cb817b 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -24,7 +24,6 @@ * THE SOFTWARE. */ -#include #include #include #include @@ -54,9 +53,11 @@ // freely accessed - for interfacing with system and 3rd-party libs for // example. On the other hand, some (e.g. bare-metal) ports may use GC // heap as system heap, so, to avoid warnings, we do undef's first. -// CIRCUITPY-CHANGE: Add selective collect support to malloc to optimize GC for large buffers +#undef malloc #undef free #undef realloc +#define malloc(b) gc_alloc((b), false) +#define malloc_with_finaliser(b) gc_alloc((b), true) #define free gc_free #define realloc(ptr, n) gc_realloc(ptr, n, true) #define realloc_ext(ptr, n, mv) gc_realloc(ptr, n, mv) @@ -85,7 +86,7 @@ static void *realloc_ext(void *ptr, size_t n_bytes, bool allow_move) { #endif // MICROPY_ENABLE_GC -// CIRCUITPY-CHANGE: Add malloc helper with flags instead of a list of bools. +// CIRCUITPY-CHANGE: Add malloc helper to factor out flag handling and allow combinations. void *m_malloc_helper(size_t num_bytes, uint8_t flags) { void *ptr; #if MICROPY_ENABLE_GC @@ -112,7 +113,6 @@ void *m_malloc_helper(size_t num_bytes, uint8_t flags) { MP_STATE_MEM(current_bytes_allocated) += num_bytes; UPDATE_PEAK(); #endif - // CIRCUITPY-CHANGE // If this config is set then the GC clears all memory, so we don't need to. #if !MICROPY_GC_CONSERVATIVE_CLEAR if (flags & M_MALLOC_ENSURE_ZEROED) { @@ -133,17 +133,25 @@ void *m_malloc_maybe(size_t num_bytes) { return m_malloc_helper(num_bytes, M_MALLOC_COLLECT); } +#if MICROPY_ENABLE_FINALISER +void *m_malloc_with_finaliser(size_t num_bytes) { + // CIRCUITPY-CHANGE + return m_malloc_helper(num_bytes, M_MALLOC_COLLECT | M_MALLOC_WITH_FINALISER); +#endif + void *m_malloc0(size_t num_bytes) { + // CIRCUITPY-CHANGE return m_malloc_helper(num_bytes, M_MALLOC_ENSURE_ZEROED | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); } +// CIRCUITPY-CHANGE: selective collect void *m_malloc_without_collect(size_t num_bytes) { - // CIRCUITPY-CHANGE return m_malloc_helper(num_bytes, M_MALLOC_RAISE_ERROR); } +// CIRCUITPY-CHANGE: selective collect void *m_malloc_maybe_without_collect(size_t num_bytes) { - // CIRCUITPY-CHANGE + return m_malloc_helper(num_bytes, 0); } @@ -224,6 +232,31 @@ void m_free(void *ptr) #if MICROPY_TRACKED_ALLOC +#if MICROPY_PY_THREAD && !MICROPY_PY_THREAD_GIL +// If there's no GIL, use the GC recursive mutex to protect the tracked node linked list +// under m_tracked_head. +// +// (For ports with GIL, the expectation is to only call tracked alloc functions +// while holding the GIL.) + +static inline void m_tracked_node_lock(void) { + mp_thread_recursive_mutex_lock(&MP_STATE_MEM(gc_mutex), 1); +} + +static inline void m_tracked_node_unlock(void) { + mp_thread_recursive_mutex_unlock(&MP_STATE_MEM(gc_mutex)); +} + +#else + +static inline void m_tracked_node_lock(void) { +} + +static inline void m_tracked_node_unlock(void) { +} + +#endif + #define MICROPY_TRACKED_ALLOC_STORE_SIZE (!MICROPY_ENABLE_GC) typedef struct _m_tracked_node_t { @@ -237,6 +270,7 @@ typedef struct _m_tracked_node_t { #if MICROPY_DEBUG_VERBOSE static size_t m_tracked_count_links(size_t *nb) { + m_tracked_node_lock(); m_tracked_node_t *node = MP_STATE_VM(m_tracked_head); size_t n = 0; *nb = 0; @@ -249,6 +283,7 @@ static size_t m_tracked_count_links(size_t *nb) { #endif node = node->next; } + m_tracked_node_unlock(); return n; } #endif @@ -263,12 +298,14 @@ void *m_tracked_calloc(size_t nmemb, size_t size) { size_t n = m_tracked_count_links(&nb); DEBUG_printf("m_tracked_calloc(%u, %u) -> (%u;%u) %p\n", (int)nmemb, (int)size, (int)n, (int)nb, node); #endif + m_tracked_node_lock(); if (MP_STATE_VM(m_tracked_head) != NULL) { MP_STATE_VM(m_tracked_head)->prev = node; } node->prev = NULL; node->next = MP_STATE_VM(m_tracked_head); MP_STATE_VM(m_tracked_head) = node; + m_tracked_node_unlock(); #if MICROPY_TRACKED_ALLOC_STORE_SIZE node->size = nmemb * size; #endif @@ -282,8 +319,7 @@ void m_tracked_free(void *ptr_in) { if (ptr_in == NULL) { return; } - // CIRCUITPY-CHANGE: cast to avoid compiler warning - m_tracked_node_t *node = (m_tracked_node_t *)(void *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t)); + m_tracked_node_t *node = (m_tracked_node_t *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t)); #if MICROPY_DEBUG_VERBOSE size_t data_bytes; #if MICROPY_TRACKED_ALLOC_STORE_SIZE @@ -294,7 +330,8 @@ void m_tracked_free(void *ptr_in) { size_t nb; size_t n = m_tracked_count_links(&nb); DEBUG_printf("m_tracked_free(%p, [%p, %p], nbytes=%u, links=%u;%u)\n", node, node->prev, node->next, (int)data_bytes, (int)n, (int)nb); - #endif + #endif // MICROPY_DEBUG_VERBOSE + m_tracked_node_lock(); if (node->next != NULL) { node->next->prev = node->prev; } @@ -303,6 +340,7 @@ void m_tracked_free(void *ptr_in) { } else { MP_STATE_VM(m_tracked_head) = node->next; } + m_tracked_node_unlock(); m_free(node #if MICROPY_MALLOC_USES_ALLOCATED_SIZE #if MICROPY_TRACKED_ALLOC_STORE_SIZE diff --git a/py/misc.h b/py/misc.h index 22f32147124..d977ee6a848 100644 --- a/py/misc.h +++ b/py/misc.h @@ -26,6 +26,8 @@ #ifndef MICROPY_INCLUDED_PY_MISC_H #define MICROPY_INCLUDED_PY_MISC_H +#include "py/mpconfig.h" + // a mini library of useful types and functions /** types *******************************************************/ @@ -34,9 +36,6 @@ #include #include -// CIRCUITPY-CHANGE: include directly instead of depending on previous includes -#include "mpconfig.h" - typedef unsigned char byte; typedef unsigned int uint; @@ -54,6 +53,7 @@ typedef unsigned int uint; #define MP_STRINGIFY(x) MP_STRINGIFY_HELPER(x) // Static assertion macro +// CIRCUITPY-CHANGE: defined() #if defined(__cplusplus) #define MP_STATIC_ASSERT(cond) static_assert((cond), #cond) #elif __GNUC__ >= 5 || __STDC_VERSION__ >= 201112L @@ -70,7 +70,7 @@ typedef unsigned int uint; #if defined(_MSC_VER) || defined(__cplusplus) #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)1) #else -#if defined(__clang__) +// CIRCUITPY-CHANGE: defined()#if defined(__clang__) #pragma GCC diagnostic ignored "-Wgnu-folding-constant" #endif #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)sizeof(char[1 - 2 * !(cond)])) @@ -98,9 +98,9 @@ typedef unsigned int uint; #define m_new0(type, num) ((type *)(m_malloc0(sizeof(type) * (num)))) #define m_new_obj(type) (m_new(type, 1)) #define m_new_obj_maybe(type) (m_new_maybe(type, 1)) -#define m_new_obj_var(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc_helper(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num), M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT)) -#define m_new_obj_var0(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc_helper(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num), M_MALLOC_ENSURE_ZEROED | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT)) -#define m_new_obj_var_maybe(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc_helper(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num), M_MALLOC_COLLECT)) +#define m_new_obj_var(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num))) +#define m_new_obj_var0(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc0(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num))) +#define m_new_obj_var_maybe(obj_type, var_field, var_type, var_num) ((obj_type *)m_malloc_maybe(offsetof(obj_type, var_field) + sizeof(var_type) * (var_num))) #if MICROPY_MALLOC_USES_ALLOCATED_SIZE #define m_renew(type, ptr, old_num, new_num) ((type *)(m_realloc((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num)))) #define m_renew_maybe(type, ptr, old_num, new_num, allow_move) ((type *)(m_realloc_maybe((ptr), sizeof(type) * (old_num), sizeof(type) * (new_num), (allow_move)))) @@ -126,9 +126,13 @@ typedef unsigned int uint; void *m_malloc_helper(size_t num_bytes, uint8_t flags); void *m_malloc(size_t num_bytes); void *m_malloc_maybe(size_t num_bytes); +void *m_malloc_with_finaliser(size_t num_bytes); void *m_malloc0(size_t num_bytes); + +// CIRCUITPY-CHANGE: _without_collect void *m_malloc_without_collect(size_t num_bytes); void *m_malloc_maybe_without_collect(size_t num_bytes); + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE void *m_realloc(void *ptr, size_t old_num_bytes, size_t new_num_bytes); void *m_realloc_maybe(void *ptr, size_t old_num_bytes, size_t new_num_bytes, bool allow_move); @@ -138,7 +142,7 @@ void *m_realloc(void *ptr, size_t new_num_bytes); void *m_realloc_maybe(void *ptr, size_t new_num_bytes, bool allow_move); void m_free(void *ptr); #endif -NORETURN void m_malloc_fail(size_t num_bytes); +MP_NORETURN void m_malloc_fail(size_t num_bytes); #if MICROPY_TRACKED_ALLOC // These alloc/free functions track the pointers in a linked list so the GC does not reclaim @@ -161,7 +165,7 @@ size_t m_get_peak_bytes_allocated(void); // align ptr to the nearest multiple of "alignment" #define MP_ALIGN(ptr, alignment) (void *)(((uintptr_t)(ptr) + ((alignment) - 1)) & ~((alignment) - 1)) -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: addition #define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) /** unichar / UTF-8 *********************************************/ @@ -308,6 +312,25 @@ typedef union _mp_float_union_t { mp_float_uint_t i; } mp_float_union_t; +#if MICROPY_FLOAT_FORMAT_IMPL == MICROPY_FLOAT_FORMAT_IMPL_EXACT + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +// Exact float conversion requires using internally a bigger sort of floating point +typedef double mp_large_float_t; +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +typedef long double mp_large_float_t; +#endif +// Always use a 64 bit mantissa for formatting and parsing +typedef uint64_t mp_large_float_uint_t; + +#else // MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_EXACT + +// No bigger floating points +typedef mp_float_t mp_large_float_t; +typedef mp_float_uint_t mp_large_float_uint_t; + +#endif + #endif // MICROPY_PY_BUILTINS_FLOAT /** ROM string compression *************/ @@ -413,26 +436,30 @@ static inline bool mp_check(bool value) { static inline uint32_t mp_popcount(uint32_t x) { return __popcnt(x); } -#else +#else // _MSC_VER #define mp_clz(x) __builtin_clz(x) #define mp_clzl(x) __builtin_clzl(x) #define mp_clzll(x) __builtin_clzll(x) #define mp_ctz(x) __builtin_ctz(x) #define mp_check(x) (x) +// CIRCUITPY-CHANGE: defined() #if defined __has_builtin #if __has_builtin(__builtin_popcount) #define mp_popcount(x) __builtin_popcount(x) -#endif -#endif -#if !defined(mp_popcount) +#else static inline uint32_t mp_popcount(uint32_t x) { x = x - ((x >> 1) & 0x55555555); x = (x & 0x33333333) + ((x >> 2) & 0x33333333); x = (x + (x >> 4)) & 0x0F0F0F0F; - return x * 0x01010101; + return (x * 0x01010101) >> 24; } -#endif -#endif +#endif // __has_builtin(__builtin_popcount) +#endif // _MSC_VER + +#define MP_FIT_UNSIGNED(bits, value) (((value) & (~0U << (bits))) == 0) +#define MP_FIT_SIGNED(bits, value) \ + (MP_FIT_UNSIGNED(((bits) - 1), (value)) || \ + (((value) & (~0U << ((bits) - 1))) == (~0U << ((bits) - 1)))) // 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) { @@ -448,16 +475,107 @@ static inline uint32_t mp_clz_mpi(mp_int_t x) { } return zeroes; #else - MP_STATIC_ASSERT(sizeof(mp_int_t) == sizeof(long long) - || sizeof(mp_int_t) == sizeof(long)); + #if MP_INT_MAX == INT_MAX + return mp_clz((unsigned)x); + #elif MP_INT_MAX == LONG_MAX + return mp_clzl((unsigned long)x); + #elif MP_INT_MAX == LLONG_MAX + return mp_clzll((unsigned long long)x); + #else + #error Unexpected MP_INT_MAX value + #endif + #endif +} + +// Overflow-checked operations + +// Integer overflow builtins were added to GCC 5, but __has_builtin only in GCC 10 +// +// Note that the builtins has a defined result when overflow occurs, whereas the custom +// functions below don't update the result if an overflow would occur (to avoid UB). +#define MP_GCC_HAS_BUILTIN_OVERFLOW (__GNUC__ >= 5) + +#if MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC + +#define mp_mul_ull_overflow __builtin_umulll_overflow +#define mp_mul_ll_overflow __builtin_smulll_overflow +static inline bool mp_mul_mp_int_t_overflow(mp_int_t x, mp_int_t y, mp_int_t *res) { + // __builtin_mul_overflow is a type-generic function, this inline ensures the argument + // types are checked to match mp_int_t. + return __builtin_mul_overflow(x, y, res); +} + +#else - // ugly, but should compile to single intrinsic unless O0 is set - if (mp_check(sizeof(mp_int_t) == sizeof(long))) { - return mp_clzl((unsigned long)x); +bool mp_mul_ll_overflow(long long int x, long long int y, long long int *res); +bool mp_mul_mp_int_t_overflow(mp_int_t x, mp_int_t y, mp_int_t *res); +static inline bool mp_mul_ull_overflow(unsigned long long int x, unsigned long long int y, unsigned long long int *res) { + if (y > 0 && x > (ULLONG_MAX / y)) { + return true; // overflow + } + *res = x * y; + return false; +} + +#endif + +#if __has_builtin(__builtin_saddll_overflow) || MP_GCC_HAS_BUILTIN_OVERFLOW +#define mp_add_ll_overflow __builtin_saddll_overflow +#else +static inline bool mp_add_ll_overflow(long long int lhs, long long int rhs, long long int *res) { + bool overflow; + + if (rhs > 0) { + overflow = (lhs > LLONG_MAX - rhs); } else { - return mp_clzll((unsigned long long)x); + overflow = (lhs < LLONG_MIN - rhs); } - #endif + + if (!overflow) { + *res = lhs + rhs; + } + + return overflow; } +#endif + +#if __has_builtin(__builtin_ssubll_overflow) || MP_GCC_HAS_BUILTIN_OVERFLOW +#define mp_sub_ll_overflow __builtin_ssubll_overflow +#else +static inline bool mp_sub_ll_overflow(long long int lhs, long long int rhs, long long int *res) { + bool overflow; + + if (rhs > 0) { + overflow = (lhs < LLONG_MIN + rhs); + } else { + overflow = (lhs > LLONG_MAX + rhs); + } + + if (!overflow) { + *res = lhs - rhs; + } + + return overflow; +} +#endif + + +// Helper macros for detecting if sanitizers are enabled +// +// Use sparingly, not for masking issues reported by sanitizers! +// +// Can be detected automatically in Clang and gcc>=14, need to be +// set manually otherwise. +#ifndef MP_UBSAN +#define MP_UBSAN __has_feature(undefined_behavior_sanitizer) +#endif + +#ifndef MP_ASAN +#define MP_ASAN __has_feature(address_sanitizer) +#endif + +#ifndef MP_SANITIZER_BUILD +#define MP_SANITIZER_BUILD (MP_UBSAN || MP_ASAN) +#endif #endif // MICROPY_INCLUDED_PY_MISC_H diff --git a/py/mkrules.cmake b/py/mkrules.cmake index 4374b8b4da3..e3d769cc59b 100644 --- a/py/mkrules.cmake +++ b/py/mkrules.cmake @@ -14,6 +14,9 @@ set(MICROPY_MODULEDEFS "${MICROPY_GENHDR_DIR}/moduledefs.h") set(MICROPY_ROOT_POINTERS_SPLIT "${MICROPY_GENHDR_DIR}/root_pointers.split") set(MICROPY_ROOT_POINTERS_COLLECTED "${MICROPY_GENHDR_DIR}/root_pointers.collected") set(MICROPY_ROOT_POINTERS "${MICROPY_GENHDR_DIR}/root_pointers.h") +set(MICROPY_COMPRESSED_SPLIT "${MICROPY_GENHDR_DIR}/compressed.split") +set(MICROPY_COMPRESSED_COLLECTED "${MICROPY_GENHDR_DIR}/compressed.collected") +set(MICROPY_COMPRESSED_DATA "${MICROPY_GENHDR_DIR}/compressed.data.h") if(NOT MICROPY_PREVIEW_VERSION_2) set(MICROPY_PREVIEW_VERSION_2 0) @@ -32,6 +35,13 @@ if(MICROPY_BOARD) ) endif() +# Need to do this before extracting MICROPY_CPP_DEF below. +if(MICROPY_ROM_TEXT_COMPRESSION) + target_compile_definitions(${MICROPY_TARGET} PUBLIC + MICROPY_ROM_TEXT_COMPRESSION=\(1\) + ) +endif() + # Need to do this before extracting MICROPY_CPP_DEF below. Rest of frozen # manifest handling is at the end of this file. if(MICROPY_FROZEN_MANIFEST) @@ -84,6 +94,18 @@ target_sources(${MICROPY_TARGET} PRIVATE ${MICROPY_ROOT_POINTERS} ) +if(MICROPY_ROM_TEXT_COMPRESSION) + target_sources(${MICROPY_TARGET} PRIVATE + ${MICROPY_COMPRESSED_DATA} + ) +endif() + +# Ensure genhdr directory is removed on clean + +set_property(TARGET ${MICROPY_TARGET} APPEND PROPERTY ADDITIONAL_CLEAN_FILES + "${MICROPY_GENHDR_DIR}" +) + # Command to force the build of another command # Generate mpversion.h @@ -197,11 +219,41 @@ add_custom_command( DEPENDS ${MICROPY_ROOT_POINTERS_COLLECTED} ${MICROPY_PY_DIR}/make_root_pointers.py ) +# Generate compressed.data.h + +add_custom_command( + OUTPUT ${MICROPY_COMPRESSED_SPLIT} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py split compress ${MICROPY_QSTRDEFS_LAST} ${MICROPY_GENHDR_DIR}/compress _ + COMMAND touch ${MICROPY_COMPRESSED_SPLIT} + DEPENDS ${MICROPY_QSTRDEFS_LAST} + VERBATIM + COMMAND_EXPAND_LISTS +) + +add_custom_command( + OUTPUT ${MICROPY_COMPRESSED_COLLECTED} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py cat compress _ ${MICROPY_GENHDR_DIR}/compress ${MICROPY_COMPRESSED_COLLECTED} + BYPRODUCTS "${MICROPY_COMPRESSED_COLLECTED}.hash" + DEPENDS ${MICROPY_COMPRESSED_SPLIT} + VERBATIM + COMMAND_EXPAND_LISTS +) + +add_custom_command( + OUTPUT ${MICROPY_COMPRESSED_DATA} + COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makecompresseddata.py ${MICROPY_COMPRESSED_COLLECTED} > ${MICROPY_COMPRESSED_DATA} + DEPENDS ${MICROPY_COMPRESSED_COLLECTED} ${MICROPY_PY_DIR}/makecompresseddata.py +) + # Build frozen code if enabled if(MICROPY_FROZEN_MANIFEST) set(MICROPY_FROZEN_CONTENT "${CMAKE_BINARY_DIR}/frozen_content.c") + set_property(TARGET ${MICROPY_TARGET} APPEND PROPERTY ADDITIONAL_CLEAN_FILES + "${CMAKE_BINARY_DIR}/frozen_mpy" + ) + target_sources(${MICROPY_TARGET} PRIVATE ${MICROPY_FROZEN_CONTENT} ) diff --git a/py/mkrules.mk b/py/mkrules.mk index f364297f0f2..03988996c71 100644 --- a/py/mkrules.mk +++ b/py/mkrules.mk @@ -11,6 +11,7 @@ ifeq ($(MICROPY_PREVIEW_VERSION_2),1) CFLAGS += -DMICROPY_PREVIEW_VERSION_2=1 endif +# CIRCUITPY-CHANGE: point to CircuitPython documentation HELP_BUILD_ERROR ?= "See \033[1;31mhttps://learn.adafruit.com/building-circuitpython; Adafruit Discord \#circuitpython-dev\033[0m" HELP_MPY_LIB_SUBMODULE ?= "\033[1;31mError: micropython-lib submodule is not initialized.\033[0m Run 'make submodules'" @@ -112,6 +113,14 @@ $(BUILD)/%.pp: %.c $(STEPECHO) "PreProcess $<" $(Q)$(CPP) $(CFLAGS) -Wp,-C,-dD,-dI -o $@ $< +.PHONY: $(BUILD)/%.sz +$(BUILD)/%.sz: $(BUILD)/%.o + $(Q)$(SIZE) $< + +# Special case for compiling auto-generated source files. +$(BUILD)/%.o: $(BUILD)/%.c + $(call compile_c) + # The following rule uses | to create an order only prerequisite. Order only # prerequisites only get built if they don't exist. They don't cause timestamp # checking to be performed. @@ -179,7 +188,7 @@ $(HEADER_BUILD)/compressed.collected: $(HEADER_BUILD)/compressed.split # will be created if they don't exist. OBJ_DIRS = $(sort $(dir $(OBJ))) $(OBJ): | $(OBJ_DIRS) -// CIRCUITPY-CHANGE: use $(Q) +# CIRCUITPY-CHANGE: use $(Q) $(OBJ_DIRS): $(Q)$(MKDIR) -p $@ @@ -260,7 +269,7 @@ submodules: $(ECHO) "Updating submodules: $(GIT_SUBMODULES)" ifneq ($(GIT_SUBMODULES),) $(Q)cd $(TOP) && git submodule sync $(GIT_SUBMODULES) - $(Q)cd $(TOP) && git submodule update --init --filter=blob:none $(GIT_SUBMODULES) || \ + $(Q)cd $(TOP) && git submodule update --init --filter=blob:none $(GIT_SUBMODULES) 2>/dev/null || \ git submodule update --init $(GIT_SUBMODULES) endif .PHONY: submodules diff --git a/py/modio.c b/py/modio.c index d3e563dbcf4..9aeb42d30aa 100644 --- a/py/modio.c +++ b/py/modio.c @@ -169,12 +169,13 @@ static mp_obj_t bufwriter_flush(mp_obj_t self_in) { int err; mp_uint_t out_sz = mp_stream_write_exactly(self->stream, self->buf, self->len, &err); (void)out_sz; - // TODO: try to recover from a case of non-blocking stream, e.g. move - // remaining chunk to the beginning of buffer. - assert(out_sz == self->len); - self->len = 0; if (err != 0) { mp_raise_OSError(err); + } else { + // TODO: try to recover from a case of non-blocking stream, e.g. move + // remaining chunk to the beginning of buffer. + assert(out_sz == self->len); + self->len = 0; } } diff --git a/py/modmath.c b/py/modmath.c index 2b41bbcd7d1..2a9ed1b7f22 100644 --- a/py/modmath.c +++ b/py/modmath.c @@ -37,7 +37,7 @@ #define MP_PI_4 MICROPY_FLOAT_CONST(0.78539816339744830962) #define MP_3_PI_4 MICROPY_FLOAT_CONST(2.35619449019234492885) -static NORETURN void math_error(void) { +static MP_NORETURN void math_error(void) { mp_raise_ValueError(MP_ERROR_TEXT("math domain error")); } @@ -99,12 +99,16 @@ mp_float_t MICROPY_FLOAT_C_FUN(log2)(mp_float_t x) { MATH_FUN_1(sqrt, sqrt) // pow(x, y): returns x to the power of y #if MICROPY_PY_MATH_POW_FIX_NAN -mp_float_t pow_func(mp_float_t x, mp_float_t y) { +mp_float_t MICROPY_FLOAT_C_FUN(pow_func)(mp_float_t x, mp_float_t y) { // pow(base, 0) returns 1 for any base, even when base is NaN // pow(+1, exponent) returns 1 for any exponent, even when exponent is NaN if (x == MICROPY_FLOAT_CONST(1.0) || y == MICROPY_FLOAT_CONST(0.0)) { return MICROPY_FLOAT_CONST(1.0); } + // pow(base, NaN) returns NaN for any other value of base + if (isnan(y)) { + return y; + } return MICROPY_FLOAT_C_FUN(pow)(x, y); } MATH_FUN_2(pow, pow_func) @@ -161,6 +165,11 @@ MATH_FUN_2(atan2, atan2) MATH_FUN_1_TO_INT(ceil, ceil) // copysign(x, y) static mp_float_t MICROPY_FLOAT_C_FUN(copysign_func)(mp_float_t x, mp_float_t y) { + #if MICROPY_PY_MATH_COPYSIGN_FIX_NAN + if (isnan(y)) { + y = 0.0; + } + #endif return MICROPY_FLOAT_C_FUN(copysign)(x, y); } MATH_FUN_2(copysign, copysign_func) diff --git a/py/modmicropython.c b/py/modmicropython.c index ff25af8ff7e..67bb32626c3 100644 --- a/py/modmicropython.c +++ b/py/modmicropython.c @@ -100,7 +100,7 @@ static mp_obj_t mp_micropython_qstr_info(size_t n_args, const mp_obj_t *args) { size_t n_pool, n_qstr, n_str_data_bytes, n_total_bytes; qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes); mp_printf(&mp_plat_print, "qstr pool: n_pool=%u, n_qstr=%u, n_str_data_bytes=%u, n_total_bytes=%u\n", - n_pool, n_qstr, n_str_data_bytes, n_total_bytes); + (uint)n_pool, (uint)n_qstr, (uint)n_str_data_bytes, (uint)n_total_bytes); if (n_args == 1) { // arg given means dump qstr data qstr_dump_data(); diff --git a/py/modsys.c b/py/modsys.c index 2adbc0b7bd6..bbae93d0c3f 100644 --- a/py/modsys.c +++ b/py/modsys.c @@ -95,8 +95,16 @@ static const MP_DEFINE_STR_OBJ(mp_sys_implementation_machine_obj, MICROPY_BANNER MP_ROM_PTR(&mp_sys_implementation_machine_obj) #if MICROPY_PERSISTENT_CODE_LOAD +// Note: Adding architecture flags to _mpy will break if the flags information +// takes up more bits than what is available in a small-int value. +#if MICROPY_EMIT_RV32 +#include "py/asmrv32.h" +#define MPY_FILE_ARCH_FLAGS (MICROPY_RV32_EXTENSIONS << 16) +#else +#define MPY_FILE_ARCH_FLAGS (0) +#endif #define SYS_IMPLEMENTATION_ELEMS__MPY \ - , MP_ROM_INT(MPY_FILE_HEADER_INT) + , MP_ROM_INT(MPY_FILE_HEADER_INT | MPY_FILE_ARCH_FLAGS) #else #define SYS_IMPLEMENTATION_ELEMS__MPY #endif @@ -113,6 +121,18 @@ static const MP_DEFINE_STR_OBJ(mp_sys_implementation__build_obj, MICROPY_BOARD_B #define SYS_IMPLEMENTATION_ELEMS__BUILD #endif +#if MICROPY_PY_THREAD +#if MICROPY_PY_THREAD_GIL +#define SYS_IMPLEMENTATION_ELEMS__THREAD \ + , MP_ROM_QSTR(MP_QSTR_GIL) +#else +#define SYS_IMPLEMENTATION_ELEMS__THREAD \ + , MP_ROM_QSTR(MP_QSTR_unsafe) +#endif +#else +#define SYS_IMPLEMENTATION_ELEMS__THREAD +#endif + #if MICROPY_PREVIEW_VERSION_2 #define SYS_IMPLEMENTATION_ELEMS__V2 \ , MP_ROM_TRUE @@ -130,6 +150,9 @@ static const qstr impl_fields[] = { #if defined(MICROPY_BOARD_BUILD_NAME) MP_QSTR__build, #endif + #if MICROPY_PY_THREAD + MP_QSTR__thread, + #endif #if MICROPY_PREVIEW_VERSION_2 MP_QSTR__v2, #endif @@ -137,20 +160,21 @@ static const qstr impl_fields[] = { static MP_DEFINE_ATTRTUPLE( mp_sys_implementation_obj, impl_fields, - 3 + MICROPY_PERSISTENT_CODE_LOAD + MICROPY_BOARD_BUILD + MICROPY_PREVIEW_VERSION_2, + 3 + MICROPY_PERSISTENT_CODE_LOAD + MICROPY_BOARD_BUILD + MICROPY_PY_THREAD + MICROPY_PREVIEW_VERSION_2, SYS_IMPLEMENTATION_ELEMS_BASE SYS_IMPLEMENTATION_ELEMS__MPY SYS_IMPLEMENTATION_ELEMS__BUILD + SYS_IMPLEMENTATION_ELEMS__THREAD SYS_IMPLEMENTATION_ELEMS__V2 ); #else static const mp_rom_obj_tuple_t mp_sys_implementation_obj = { {&mp_type_tuple}, 3 + MICROPY_PERSISTENT_CODE_LOAD, - // Do not include SYS_IMPLEMENTATION_ELEMS__BUILD or SYS_IMPLEMENTATION_ELEMS__V2 - // because SYS_IMPLEMENTATION_ELEMS__MPY may be empty if + // Do not include SYS_IMPLEMENTATION_ELEMS__BUILD, SYS_IMPLEMENTATION_ELEMS__THREAD + // or SYS_IMPLEMENTATION_ELEMS__V2 because SYS_IMPLEMENTATION_ELEMS__MPY may be empty if // MICROPY_PERSISTENT_CODE_LOAD is disabled, which means they'll share - // the same index. Cannot query _build or _v2 if MICROPY_PY_ATTRTUPLE is + // the same index. Cannot query _build, _thread or _v2 if MICROPY_PY_ATTRTUPLE is // disabled. { SYS_IMPLEMENTATION_ELEMS_BASE diff --git a/py/mpconfig.h b/py/mpconfig.h index a4895820061..5b09fc97c92 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -26,6 +26,14 @@ #ifndef MICROPY_INCLUDED_PY_MPCONFIG_H #define MICROPY_INCLUDED_PY_MPCONFIG_H +#include + +#if defined(__cplusplus) // Required on at least one compiler to get ULLONG_MAX +#include +#else +#include +#endif + // CIRCUITPY-CHANGE // Is this a CircuitPython build? #ifndef CIRCUITPY @@ -40,7 +48,7 @@ // as well as a fallback to generate MICROPY_GIT_TAG if the git repo or tags // are unavailable. #define MICROPY_VERSION_MAJOR 1 -#define MICROPY_VERSION_MINOR 25 +#define MICROPY_VERSION_MINOR 27 #define MICROPY_VERSION_MICRO 0 #define MICROPY_VERSION_PRERELEASE 0 @@ -173,6 +181,78 @@ #define MICROPY_OBJ_IMMEDIATE_OBJS (MICROPY_OBJ_REPR != MICROPY_OBJ_REPR_D) #endif +// Definition of the `mp_int_t` and `mp_uint_t` types and associated macros. +// Normally, it suffices for the platform to do nothing: A type as wide +// as a pointer is chosen, unless nanboxing (REPR_D) is selected, in +// which case a 64-bit type is chosen to match the assumed size of +// double-precision floats. +// +// In the case of exceptions, the port, board, or variant must define +// MP_INT_TYPE as MP_INT_TYPE_OTHER and provide all the typedefs and +// defines. +#define MP_INT_TYPE_INTPTR (0) +#define MP_INT_TYPE_INT64 (1) +#define MP_INT_TYPE_OTHER (2) + +#if !defined(MP_INT_TYPE) +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +#define MP_INT_TYPE (MP_INT_TYPE_INT64) +#else +#define MP_INT_TYPE (MP_INT_TYPE_INTPTR) +#endif +#endif + +#if MP_INT_TYPE == MP_INT_TYPE_INTPTR +typedef intptr_t mp_int_t; +typedef uintptr_t mp_uint_t; +#define MP_INT_MAX INTPTR_MAX +#define MP_INT_MIN INTPTR_MIN +#define MP_UINT_MAX INTPTR_UMAX +#elif MP_INT_TYPE == MP_INT_TYPE_INT64 +typedef int64_t mp_int_t; +typedef uint64_t mp_uint_t; +#define MP_INT_MAX INT64_MAX +#define MP_INT_MIN INT64_MIN +#define MP_UINT_MAX INT64_UMAX +#endif + +// mp_printf format support for mp_int_t. In the unusual case that MP_INT_MAX doesn't +// match any of the standard C types (int/long/long long), provide all 3 +// macros. Otherwise, rely on these automatic definitions. +#if !defined(INT_FMT) +#if MP_INT_MAX == INT_MAX +#define INT_FMT "%d" +#define UINT_FMT "%u" +#define HEX_FMT "%x" +#elif MP_INT_MAX == LONG_MAX +#define INT_FMT "%ld" +#define UINT_FMT "%lu" +#define HEX_FMT "%lx" +#elif MP_INT_MAX == LLONG_MAX +#define INT_FMT "%lld" +#define UINT_FMT "%llu" +#define HEX_FMT "%llx" +#else +#error Unexpected MP_INT_MAX value +#endif +#endif + +// mp_printf format support for size_t. In the unusual case that SIZE_MAX doesn't +// match any of the standard C types (int/long/long long), provide a +// macro. Otherwise, rely on these automatic definitions. +#if !defined(SIZE_FMT) +#if SIZE_MAX == UINT_MAX +#define SIZE_FMT "%u" +#elif SIZE_MAX == ULONG_MAX +#define SIZE_FMT "%lu" +#elif SIZE_MAX == ULLONG_MAX +#define SIZE_FMT "%llu" +#else +#error Unexpected SIZE_MAX value +#endif +#endif + + /*****************************************************************************/ /* Memory allocation policy */ @@ -418,6 +498,11 @@ #define MICROPY_EMIT_INLINE_XTENSA (0) #endif +// Whether to support uncommon Xtensa inline assembler opcodes +#ifndef MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES +#define MICROPY_EMIT_INLINE_XTENSA_UNCOMMON_OPCODES (0) +#endif + // Whether to emit Xtensa-Windowed native code #ifndef MICROPY_EMIT_XTENSAWIN #define MICROPY_EMIT_XTENSAWIN (0) @@ -428,9 +513,9 @@ #define MICROPY_EMIT_RV32 (0) #endif -// CIRCUITPY-CHANGE: make sure MICROPY_EMIT_NATIVE_DEBUG is defined -#ifndef MICROPY_EMIT_NATIVE_DEBUG -#define MICROPY_EMIT_NATIVE_DEBUG (0) +// Whether to emit RISC-V RV32 Zba opcodes in native code +#ifndef MICROPY_EMIT_RV32_ZBA +#define MICROPY_EMIT_RV32_ZBA (0) #endif // Whether to enable the RISC-V RV32 inline assembler @@ -438,6 +523,11 @@ #define MICROPY_EMIT_INLINE_RV32 (0) #endif +// Whether to enable the human-readable native instructions emitter +#ifndef MICROPY_EMIT_NATIVE_DEBUG +#define MICROPY_EMIT_NATIVE_DEBUG (0) +#endif + // Convenience definition for whether any native emitter is enabled #define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_X86 || MICROPY_EMIT_THUMB || MICROPY_EMIT_ARM || MICROPY_EMIT_XTENSA || MICROPY_EMIT_XTENSAWIN || MICROPY_EMIT_RV32 || MICROPY_EMIT_NATIVE_DEBUG) @@ -497,6 +587,13 @@ #define MICROPY_COMP_CONST (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif +// Whether to enable float constant folding like 1.2+3.4 (when MICROPY_COMP_CONST_FOLDING is also enabled) +// and constant optimisation like id = const(1.2) (when MICROPY_COMP_CONST is also enabled) +// and constant lookup like math.inf (when MICROPY_COMP_MODULE_CONST is also enabled) +#ifndef MICROPY_COMP_CONST_FLOAT +#define MICROPY_COMP_CONST_FLOAT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +#endif + // Whether to enable optimisation of: a, b = c, d // Costs 124 bytes (Thumb2) #ifndef MICROPY_COMP_DOUBLE_TUPLE_ASSIGN @@ -727,6 +824,13 @@ #define MICROPY_STACK_CHECK_MARGIN (0) #endif +// The size of a separate stack used for hard IRQ handlers, which should be +// checked instead of the main stack when running a hard callback. 0 implies +// there is no separate ISR stack to check. +#ifndef MICROPY_STACK_SIZE_HARD_IRQ +#define MICROPY_STACK_SIZE_HARD_IRQ (0) +#endif + // Whether to have an emergency exception buffer #ifndef MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF #define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (0) @@ -896,8 +1000,25 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_COMPLEX (MICROPY_PY_BUILTINS_FLOAT) #endif -#ifndef MICROPY_PY_DOUBLE_TYPECODE -#define MICROPY_PY_DOUBLE_TYPECODE (MICROPY_PY_BUILTINS_FLOAT) +// Float to string conversion implementations +// +// Note that the EXACT method is only available if the compiler supports +// floating points larger than mp_float_t: +// - with MICROPY_FLOAT_IMPL_FLOAT, the compiler needs to support `double` +// - with MICROPY_FLOAT_IMPL_DOUBLE, the compiler needs to support `long double` +// +#define MICROPY_FLOAT_FORMAT_IMPL_BASIC (0) // smallest code, but inexact +#define MICROPY_FLOAT_FORMAT_IMPL_APPROX (1) // slightly bigger, almost perfect +#define MICROPY_FLOAT_FORMAT_IMPL_EXACT (2) // bigger code, and 100% exact repr + +#ifndef MICROPY_FLOAT_FORMAT_IMPL +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define MICROPY_FLOAT_FORMAT_IMPL (MICROPY_FLOAT_FORMAT_IMPL_APPROX) +#elif defined(__SIZEOF_LONG_DOUBLE__) && __SIZEOF_LONG_DOUBLE__ > __SIZEOF_DOUBLE__ +#define MICROPY_FLOAT_FORMAT_IMPL (MICROPY_FLOAT_FORMAT_IMPL_EXACT) +#else +#define MICROPY_FLOAT_FORMAT_IMPL (MICROPY_FLOAT_FORMAT_IMPL_APPROX) +#endif #endif // Whether to use the native _Float16 for 16-bit float support @@ -932,6 +1053,64 @@ typedef double mp_float_t; #define MICROPY_FULL_CHECKS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif +// Ports can choose to use timestamps based on 2000-01-01 or 1970-01-01 +// Default is timestamps based on 2000-01-01 +#if !defined(MICROPY_EPOCH_IS_2000) && !defined(MICROPY_EPOCH_IS_1970) +#define MICROPY_EPOCH_IS_2000 (1) +#define MICROPY_EPOCH_IS_1970 (0) +#elif !defined(MICROPY_EPOCH_IS_1970) +#define MICROPY_EPOCH_IS_1970 (1 - (MICROPY_EPOCH_IS_2000)) +#elif !defined(MICROPY_EPOCH_IS_2000) +#define MICROPY_EPOCH_IS_2000 (1 - (MICROPY_EPOCH_IS_1970)) +#endif + +// To maintain reasonable compatibility with CPython on embedded systems, +// and avoid breaking anytime soon, time functions are defined to work +// at least between 1970 and 2099 (included) on any machine. +// +// Specific ports can enable extended date support +// - after 2099 using MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND +// - before 1970 using MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE +// The largest possible range is year 1600 to year 3000 +// +// By default, extended date support is only enabled for machines using 64 bit pointers, +// but it can be enabled by specific ports +#ifndef MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE +#if MP_SSIZE_MAX > 2147483647 +#define MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE (1) +#else +#define MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE (0) +#endif +#endif + +// When support for dates <1970 is enabled, supporting >=2100 does not cost anything +#ifndef MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND +#define MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND (MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE) +#endif + +// The type to be used to represent platform-specific timestamps depends on the choices above +#define MICROPY_TIMESTAMP_IMPL_LONG_LONG (0) +#define MICROPY_TIMESTAMP_IMPL_UINT (1) +#define MICROPY_TIMESTAMP_IMPL_TIME_T (2) + +#ifndef MICROPY_TIMESTAMP_IMPL +#if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE || MICROPY_EPOCH_IS_2000 +#define MICROPY_TIMESTAMP_IMPL (MICROPY_TIMESTAMP_IMPL_LONG_LONG) +#else +#define MICROPY_TIMESTAMP_IMPL (MICROPY_TIMESTAMP_IMPL_UINT) +#endif +#endif + +// `mp_timestamp_t` is the type that should be used by the port +// to represent timestamps, and is referenced to the platform epoch +#if MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_LONG_LONG +typedef long long mp_timestamp_t; +#elif MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_UINT +typedef mp_uint_t mp_timestamp_t; +#elif MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_TIME_T +typedef time_t mp_timestamp_t; +#endif + // Whether POSIX-semantics non-blocking streams are supported #ifndef MICROPY_STREAMS_NON_BLOCK #define MICROPY_STREAMS_NON_BLOCK (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) @@ -943,6 +1122,16 @@ typedef double mp_float_t; #define MICROPY_STREAMS_POSIX_API (0) #endif +// Whether to process __all__ when importing all public symbols from a module. +#ifndef MICROPY_MODULE___ALL__ +#define MICROPY_MODULE___ALL__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES) +#endif + +// Whether to set __file__ on imported modules. +#ifndef MICROPY_MODULE___FILE__ +#define MICROPY_MODULE___FILE__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +#endif + // Whether modules can use MP_REGISTER_MODULE_DELEGATION() to delegate failed // attribute lookups to a custom handler function. #ifndef MICROPY_MODULE_ATTR_DELEGATION @@ -1030,6 +1219,16 @@ typedef double mp_float_t; #define MICROPY_ENABLE_VM_ABORT (0) #endif +// Whether to handle abort behavior in pyexec code +#ifndef MICROPY_PYEXEC_ENABLE_VM_ABORT +#define MICROPY_PYEXEC_ENABLE_VM_ABORT (0) +#endif + +// Whether to set exit codes according to the exit reason (keyboard interrupt, crash, normal exit, ...) +#ifndef MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING +#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (0) +#endif + // Support for internal scheduler #ifndef MICROPY_ENABLE_SCHEDULER #define MICROPY_ENABLE_SCHEDULER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) @@ -1065,6 +1264,11 @@ typedef double mp_float_t; #define MICROPY_VFS_POSIX (0) #endif +// Whether to include support for writable POSIX filesystems. +#ifndef MICROPY_VFS_POSIX_WRITABLE +#define MICROPY_VFS_POSIX_WRITABLE (1) +#endif + // Support for VFS FAT component, to mount a FAT filesystem within VFS #ifndef MICROPY_VFS_FAT #define MICROPY_VFS_FAT (0) @@ -1105,7 +1309,15 @@ typedef double mp_float_t; #define MICROPY_PY_FUNCTION_ATTRS_CODE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_FULL_FEATURES) #endif -// Whether to support the descriptors __get__, __set__, __delete__ +// Whether bound_method can just use == (feature disabled), or requires a call to +// mp_obj_equal (feature enabled), to test equality of the self and meth entities. +// This is only needed if objects and functions can be identical without being the +// same thing, eg when using an object proxy. +#ifndef MICROPY_PY_BOUND_METHOD_FULL_EQUALITY_CHECK +#define MICROPY_PY_BOUND_METHOD_FULL_EQUALITY_CHECK (0) +#endif + +// Whether to support the descriptors __get__, __set__, __delete__, __set_name__ // This costs some code size and makes load/store/delete of instance // attributes slower for the classes that use this feature #ifndef MICROPY_PY_DESCRIPTORS @@ -1362,11 +1574,6 @@ typedef double mp_float_t; #define MICROPY_PY_BUILTINS_HELP_MODULES (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) #endif -// Whether to set __file__ for imported modules -#ifndef MICROPY_PY___FILE__ -#define MICROPY_PY___FILE__ (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) -#endif - // Whether to provide mem-info related functions in micropython module #ifndef MICROPY_PY_MICROPYTHON_MEM_INFO #define MICROPY_PY_MICROPYTHON_MEM_INFO (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) @@ -1482,6 +1689,7 @@ typedef double mp_float_t; #endif // Whether to provide fix for pow(1, NaN) and pow(NaN, 0), which both should be 1 not NaN. +// Also fixes pow(base, NaN) to return NaN for other values of base. #ifndef MICROPY_PY_MATH_POW_FIX_NAN #define MICROPY_PY_MATH_POW_FIX_NAN (0) #endif @@ -1518,7 +1726,7 @@ typedef double mp_float_t; // Whether to provide "io.IOBase" class to support user streams #ifndef MICROPY_PY_IO_IOBASE -#define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#define MICROPY_PY_IO_IOBASE (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif // Whether to provide "io.BytesIO" class @@ -1536,15 +1744,16 @@ typedef double mp_float_t; #define MICROPY_PY_STRUCT (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) #endif -// CIRCUITPY-CHANGE -// Whether to provide non-standard typecodes in "struct" module -#ifndef MICROPY_NONSTANDARD_TYPECODES -#define MICROPY_NONSTANDARD_TYPECODES (1) +// Whether struct module provides unsafe and non-standard typecodes O, P, S. +// These typecodes are not in CPython and can cause crashes by accessing arbitrary +// memory. +#ifndef MICROPY_PY_STRUCT_UNSAFE_TYPECODES +#define MICROPY_PY_STRUCT_UNSAFE_TYPECODES (1) #endif // Whether to provide "sys" module #ifndef MICROPY_PY_SYS -#define MICROPY_PY_SYS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES) +#define MICROPY_PY_SYS (1) #endif // Whether to initialise "sys.path" and "sys.argv" to their defaults in mp_init() @@ -1800,11 +2009,11 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_HASHLIB_MD5 -#define MICROPY_PY_HASHLIB_MD5 (0) +#define MICROPY_PY_HASHLIB_MD5 (MICROPY_PY_SSL) #endif #ifndef MICROPY_PY_HASHLIB_SHA1 -#define MICROPY_PY_HASHLIB_SHA1 (0) +#define MICROPY_PY_HASHLIB_SHA1 (MICROPY_PY_SSL) #endif #ifndef MICROPY_PY_HASHLIB_SHA256 @@ -1812,7 +2021,7 @@ typedef double mp_float_t; #endif #ifndef MICROPY_PY_CRYPTOLIB -#define MICROPY_PY_CRYPTOLIB (0) +#define MICROPY_PY_CRYPTOLIB (MICROPY_PY_SSL) #endif // Depends on MICROPY_PY_CRYPTOLIB @@ -1935,6 +2144,11 @@ typedef double mp_float_t; #define MICROPY_PY_SSL_MBEDTLS_NEED_ACTIVE_CONTEXT (MICROPY_PY_SSL_ECDSA_SIGN_ALT) #endif +// Whether to support DTLS protocol (non-CPython feature) +#ifndef MICROPY_PY_SSL_DTLS +#define MICROPY_PY_SSL_DTLS (MICROPY_SSL_MBEDTLS && MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES) +#endif + // Whether to provide the "vfs" module #ifndef MICROPY_PY_VFS #define MICROPY_PY_VFS (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES && MICROPY_VFS) @@ -2027,7 +2241,7 @@ typedef double mp_float_t; /*****************************************************************************/ /* Miscellaneous settings */ -// All uPy objects in ROM must be aligned on at least a 4 byte boundary +// All MicroPython objects in ROM must be aligned on at least a 4 byte boundary // so that the small-int/qstr/pointer distinction can be made. For machines // that don't do this (eg 16-bit CPU), define the following macro to something // like __attribute__((aligned(4))). @@ -2166,25 +2380,14 @@ typedef double mp_float_t; #define MP_SSIZE_MAX SSIZE_MAX #endif -// printf format spec to use for mp_int_t and friends -#ifndef INT_FMT -#if defined(__LP64__) -// Archs where mp_int_t == long, long != int -#define UINT_FMT "%lu" -#define INT_FMT "%ld" -#elif defined(_WIN64) -#define UINT_FMT "%llu" -#define INT_FMT "%lld" -#else -// Archs where mp_int_t == int -#define UINT_FMT "%u" -#define INT_FMT "%d" +// Modifier for function which doesn't return +#ifndef MP_NORETURN +#define MP_NORETURN __attribute__((noreturn)) #endif #endif // INT_FMT -// Modifier for function which doesn't return -#ifndef NORETURN -#define NORETURN __attribute__((noreturn)) +#if !MICROPY_PREVIEW_VERSION_2 +#define MP_NORETURN MP_NORETURN #endif // Modifier for weak functions @@ -2279,4 +2482,23 @@ typedef double mp_float_t; #define MP_WARN_CAT(x) (NULL) #endif +// If true, use __builtin_mul_overflow (a gcc intrinsic supported by clang) for +// overflow checking when multiplying two small ints. Otherwise, use a portable +// algorithm. +// +// Most MCUs have a 32x32->64 bit multiply instruction, in which case the +// intrinsic is likely to be faster and generate smaller code. The main exception is +// cortex-m0 with __ARM_ARCH_ISA_THUMB == 1. +// +// The intrinsic is in GCC starting with version 5. +#ifndef MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC +#if defined(__ARM_ARCH_ISA_THUMB) && (__GNUC__ >= 5) +#define MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC (__ARM_ARCH_ISA_THUMB >= 2) +#elif (__GNUC__ >= 5) +#define MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC (1) +#else +#define MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC (0) +#endif +#endif + #endif // MICROPY_INCLUDED_PY_MPCONFIG_H diff --git a/py/mphal.h b/py/mphal.h index 95289ac856c..3907641be83 100644 --- a/py/mphal.h +++ b/py/mphal.h @@ -27,6 +27,7 @@ #define MICROPY_INCLUDED_PY_MPHAL_H #include +#include #include "py/mpconfig.h" #ifdef MICROPY_MPHALPORT_H diff --git a/py/mpprint.c b/py/mpprint.c index e4e25f5a82e..605b8544f7f 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -40,8 +40,20 @@ #include "py/formatfloat.h" #endif -static const char pad_spaces[] = " "; -static const char pad_zeroes[] = "0000000000000000"; +static const char pad_spaces[16] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '}; +#define pad_spaces_size (sizeof(pad_spaces)) +static const char pad_common[23] = {'0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '_', '0', '0', '0', ',', '0', '0'}; +// The contents of pad_common is arranged to provide the following padding +// strings with minimal flash size: +// 0000000000000000 <- pad_zeroes +// 0000_000 <- pad_zeroes_underscore (offset: 12, size 5) +// 000,00 <- pad_zeroes_comma (offset: 17, size 4) +#define pad_zeroes (pad_common + 0) +#define pad_zeroes_size (16) +#define pad_zeroes_underscore (pad_common + 12) +#define pad_zeroes_underscore_size (5) +#define pad_zeroes_comma (pad_common + 17) +#define pad_zeroes_comma_size (4) static void plat_print_strn(void *env, const char *str, size_t len) { (void)env; @@ -58,20 +70,37 @@ int mp_print_str(const mp_print_t *print, const char *str) { return len; } -int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width) { +int mp_print_strn(const mp_print_t *print, const char *str, size_t len, unsigned int flags, char fill, int width) { int left_pad = 0; int right_pad = 0; int pad = width - len; int pad_size; int total_chars_printed = 0; const char *pad_chars; + char grouping = flags >> PF_FLAG_SEP_POS; if (!fill || fill == ' ') { pad_chars = pad_spaces; - pad_size = sizeof(pad_spaces) - 1; - } else if (fill == '0') { + pad_size = pad_spaces_size; + } else if (fill == '0' && !grouping) { pad_chars = pad_zeroes; - pad_size = sizeof(pad_zeroes) - 1; + pad_size = pad_zeroes_size; + } else if (fill == '0') { + if (grouping == '_') { + pad_chars = pad_zeroes_underscore; + pad_size = pad_zeroes_underscore_size; + } else { + pad_chars = pad_zeroes_comma; + pad_size = pad_zeroes_comma_size; + } + // The result will never start with a grouping character. An extra leading zero is added. + // width is dead after this so we can use it in calculation + if (width % pad_size == 0) { + pad++; + width++; + } + // position the grouping character correctly within the pad repetition + pad_chars += pad_size - 1 - width % pad_size; } else { // Other pad characters are fairly unusual, so we'll take the hit // and output them 1 at a time. @@ -201,7 +230,7 @@ static int mp_print_int(const mp_print_t *print, mp_uint_t x, int sgn, int base, return len; } -int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec) { +int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, unsigned int base, int base_char, int flags, char fill, int width, int prec) { // These are the only values for "base" that are required to be supported by this // function, since Python only allows the user to format integers in these bases. // If needed this function could be generalised to handle other values. @@ -248,10 +277,7 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char int prefix_len = prefix - prefix_buf; prefix = prefix_buf; - char comma = '\0'; - if (flags & PF_FLAG_SHOW_COMMA) { - comma = ','; - } + char comma = flags >> PF_FLAG_SEP_POS; // The size of this buffer is rather arbitrary. If it's not large // enough, a dynamic one will be allocated. @@ -340,8 +366,8 @@ int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char } #if MICROPY_PY_BUILTINS_FLOAT -int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec) { - char buf[32]; +int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, unsigned int flags, char fill, int width, int prec) { + char buf[36]; char sign = '\0'; int chrs = 0; @@ -352,11 +378,17 @@ int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, c sign = ' '; } - int len = mp_format_float(f, buf, sizeof(buf), fmt, prec, sign); + int len = mp_format_float(f, buf, sizeof(buf) - 3, fmt, prec, sign); char *s = buf; - if ((flags & PF_FLAG_ADD_PERCENT) && (size_t)(len + 1) < sizeof(buf)) { + if ((flags & PF_FLAG_ALWAYS_DECIMAL) && strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) { + buf[len++] = '.'; + buf[len++] = '0'; + buf[len] = '\0'; + } + + if (flags & PF_FLAG_ADD_PERCENT) { buf[len++] = '%'; buf[len] = '\0'; } @@ -424,8 +456,6 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { flags |= PF_FLAG_SHOW_SIGN; } else if (*fmt == ' ') { flags |= PF_FLAG_SPACE_SIGN; - } else if (*fmt == '!') { - flags |= PF_FLAG_NO_TRAILZ; } else if (*fmt == '0') { flags |= PF_FLAG_PAD_AFTER_SIGN; fill = '0'; @@ -459,16 +489,36 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { } } - // parse long specifiers (only for LP64 model where they make a difference) - #ifndef __LP64__ - const + // parse long and long long specifiers (only where they make a difference) + #if (MP_INT_MAX > INT_MAX && MP_INT_MAX == LONG_MAX) || defined(MICROPY_UNIX_COVERAGE) + #define SUPPORT_L_FORMAT (1) + #else + #define SUPPORT_L_FORMAT (0) #endif + #if SUPPORT_L_FORMAT bool long_arg = false; + #endif + + #if (MP_INT_MAX > LONG_MAX) || defined(MICROPY_UNIX_COVERAGE) + #define SUPPORT_LL_FORMAT (1) + #else + #define SUPPORT_LL_FORMAT (0) + #endif + #if SUPPORT_LL_FORMAT + bool long_long_arg = false; + #endif + if (*fmt == 'l') { ++fmt; - #ifdef __LP64__ + #if SUPPORT_L_FORMAT long_arg = true; #endif + #if SUPPORT_LL_FORMAT + if (*fmt == 'l') { + ++fmt; + long_long_arg = true; + } + #endif } if (*fmt == '\0') { @@ -522,6 +572,7 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_strn(print, str, len, flags, fill, width); break; } + // CIRCUITPY-CHANGE: separate from p and P case 'd': { mp_int_t val; if (long_arg) { diff --git a/py/mpprint.h b/py/mpprint.h index e883cc27047..614c61ea415 100644 --- a/py/mpprint.h +++ b/py/mpprint.h @@ -31,13 +31,13 @@ #define PF_FLAG_LEFT_ADJUST (0x001) #define PF_FLAG_SHOW_SIGN (0x002) #define PF_FLAG_SPACE_SIGN (0x004) -#define PF_FLAG_NO_TRAILZ (0x008) -#define PF_FLAG_SHOW_PREFIX (0x010) -#define PF_FLAG_SHOW_COMMA (0x020) -#define PF_FLAG_PAD_AFTER_SIGN (0x040) -#define PF_FLAG_CENTER_ADJUST (0x080) -#define PF_FLAG_ADD_PERCENT (0x100) -#define PF_FLAG_SHOW_OCTAL_LETTER (0x200) +#define PF_FLAG_SHOW_PREFIX (0x008) +#define PF_FLAG_PAD_AFTER_SIGN (0x010) +#define PF_FLAG_CENTER_ADJUST (0x020) +#define PF_FLAG_ADD_PERCENT (0x040) +#define PF_FLAG_SHOW_OCTAL_LETTER (0x080) +#define PF_FLAG_ALWAYS_DECIMAL (0x100) +#define PF_FLAG_SEP_POS (9) // must be above all the above PF_FLAGs #if MICROPY_PY_IO && MICROPY_PY_SYS_STDFILES #define MP_PYTHON_PRINTER &mp_sys_stdout_print @@ -69,9 +69,9 @@ extern const mp_print_t mp_sys_stdout_print; #endif int mp_print_str(const mp_print_t *print, const char *str); -int mp_print_strn(const mp_print_t *print, const char *str, size_t len, int flags, char fill, int width); +int mp_print_strn(const mp_print_t *print, const char *str, size_t len, unsigned int flags, char fill, int width); #if MICROPY_PY_BUILTINS_FLOAT -int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, int flags, char fill, int width, int prec); +int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, unsigned int flags, char fill, int width, int prec); #endif int mp_printf(const mp_print_t *print, const char *fmt, ...); diff --git a/py/mpstate.h b/py/mpstate.h index e5e5f8d9fa3..7934e843f06 100644 --- a/py/mpstate.h +++ b/py/mpstate.h @@ -71,6 +71,12 @@ enum { // This structure contains dynamic configuration for the compiler. #if MICROPY_DYNAMIC_COMPILER typedef struct mp_dynamic_compiler_t { + // This is used to let mpy-cross pass options to the emitter chosen with + // `native_arch`. The main use case for the time being is to give the + // RV32 emitter extended information about which extensions can be + // optionally used, in order to generate code that's better suited for the + // hardware platform the code will run on. + void *backend_options; uint8_t small_int_bits; // must be <= host small_int_bits uint8_t native_arch; uint8_t nlr_buf_num_regs; diff --git a/py/mpz.c b/py/mpz.c index 7d8bc03ca86..74fd1754636 100644 --- a/py/mpz.c +++ b/py/mpz.c @@ -1541,7 +1541,8 @@ mp_int_t mpz_hash(const mpz_t *z) { mp_uint_t val = 0; mpz_dig_t *d = z->dig + z->len; - while (d-- > z->dig) { + while (d > z->dig) { + d--; val = (val << DIG_SIZE) | *d; } @@ -1556,11 +1557,12 @@ bool mpz_as_int_checked(const mpz_t *i, mp_int_t *value) { mp_uint_t val = 0; mpz_dig_t *d = i->dig + i->len; - while (d-- > i->dig) { + while (d > i->dig) { if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> DIG_SIZE)) { // will overflow return false; } + d--; val = (val << DIG_SIZE) | *d; } @@ -1581,11 +1583,12 @@ bool mpz_as_uint_checked(const mpz_t *i, mp_uint_t *value) { mp_uint_t val = 0; mpz_dig_t *d = i->dig + i->len; - while (d-- > i->dig) { + while (d > i->dig) { if (val > (~(MP_OBJ_WORD_MSBIT_HIGH) >> (DIG_SIZE - 1))) { // will overflow return false; } + d--; val = (val << DIG_SIZE) | *d; } @@ -1646,7 +1649,8 @@ mp_float_t mpz_as_float(const mpz_t *i) { mp_float_t val = 0; mpz_dig_t *d = i->dig + i->len; - while (d-- > i->dig) { + while (d > i->dig) { + d--; val = val * DIG_BASE + *d; } @@ -1676,6 +1680,8 @@ size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, ch size_t ilen = i->len; + int n_comma = (base == 10) ? 3 : 4; + char *s = str; if (ilen == 0) { if (prefix) { @@ -1721,7 +1727,7 @@ size_t mpz_as_str_inpl(const mpz_t *i, unsigned int base, const char *prefix, ch break; } } - if (!done && comma && (s - last_comma) == 3) { + if (!done && comma && (s - last_comma) == n_comma) { *s++ = comma; last_comma = s; } diff --git a/py/nativeglue.h b/py/nativeglue.h index 00ed9f3f4fc..01825ac60ed 100644 --- a/py/nativeglue.h +++ b/py/nativeglue.h @@ -143,7 +143,7 @@ typedef struct _mp_fun_table_t { int (*printf_)(const mp_print_t *print, const char *fmt, ...); int (*vprintf_)(const mp_print_t *print, const char *fmt, va_list args); #if defined(__GNUC__) - NORETURN // Only certain compilers support no-return attributes in function pointer declarations + MP_NORETURN // Only certain compilers support no-return attributes in function pointer declarations #endif // CIRCUITPY-CHANGE: raise_msg_str instead of raise_msg void (*raise_msg_str)(const mp_obj_type_t *exc_type, const char *msg); diff --git a/py/nlr.c b/py/nlr.c index 7ab0c0955a2..de2a38ceff3 100644 --- a/py/nlr.c +++ b/py/nlr.c @@ -81,7 +81,7 @@ void nlr_call_jump_callbacks(nlr_buf_t *nlr) { } #if MICROPY_ENABLE_VM_ABORT -NORETURN void nlr_jump_abort(void) { +MP_NORETURN void nlr_jump_abort(void) { MP_STATE_THREAD(nlr_top) = MP_STATE_VM(nlr_abort); nlr_jump(NULL); } diff --git a/py/nlr.h b/py/nlr.h index 340627b7aa1..446e78c7ebb 100644 --- a/py/nlr.h +++ b/py/nlr.h @@ -233,18 +233,18 @@ unsigned int nlr_push(nlr_buf_t *); unsigned int nlr_push_tail(nlr_buf_t *top); void nlr_pop(void); -NORETURN void nlr_jump(void *val); +MP_NORETURN void nlr_jump(void *val); #if MICROPY_ENABLE_VM_ABORT #define nlr_set_abort(buf) MP_STATE_VM(nlr_abort) = buf #define nlr_get_abort() MP_STATE_VM(nlr_abort) -NORETURN void nlr_jump_abort(void); +MP_NORETURN void nlr_jump_abort(void); #endif // This must be implemented by a port. It's called by nlr_jump // if no nlr buf has been pushed. It must not return, but rather // should bail out with a fatal error. -NORETURN void nlr_jump_fail(void *val); +MP_NORETURN void nlr_jump_fail(void *val); // use nlr_raise instead of nlr_jump so that debugging is easier #ifndef MICROPY_DEBUG_NLR diff --git a/py/nlraarch64.c b/py/nlraarch64.c index d6d87ebc50d..3318004b5e0 100644 --- a/py/nlraarch64.c +++ b/py/nlraarch64.c @@ -56,7 +56,7 @@ __asm( #endif ); -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) MP_STATIC_ASSERT(offsetof(nlr_buf_t, regs) == 16); // asm assumes it diff --git a/py/nlrmips.c b/py/nlrmips.c index cba52b16a26..5c55db7e268 100644 --- a/py/nlrmips.c +++ b/py/nlrmips.c @@ -57,7 +57,7 @@ __asm( ".end nlr_push \n" ); -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm( "move $4, %0 \n" diff --git a/py/nlrpowerpc.c b/py/nlrpowerpc.c index 8a69fe1eeca..cf140400e68 100644 --- a/py/nlrpowerpc.c +++ b/py/nlrpowerpc.c @@ -78,7 +78,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm__ volatile ( @@ -167,7 +167,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm__ volatile ( diff --git a/py/nlrrv32.c b/py/nlrrv32.c index 9a12ede400d..565a8629db5 100644 --- a/py/nlrrv32.c +++ b/py/nlrrv32.c @@ -50,7 +50,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { ); } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "add x10, x0, %0 \n" // Load nlr_buf address. diff --git a/py/nlrrv64.c b/py/nlrrv64.c index e7ba79797b8..b7d1467b8f6 100644 --- a/py/nlrrv64.c +++ b/py/nlrrv64.c @@ -50,7 +50,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { ); } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( "add x10, x0, %0 \n" // Load nlr_buf address. diff --git a/py/nlrthumb.c b/py/nlrthumb.c index 265052568ff..1791d8b4929 100644 --- a/py/nlrthumb.c +++ b/py/nlrthumb.c @@ -104,7 +104,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) { #endif } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( diff --git a/py/nlrx64.c b/py/nlrx64.c index d1ad91ff7d7..51224729fc9 100644 --- a/py/nlrx64.c +++ b/py/nlrx64.c @@ -100,7 +100,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { #endif } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( diff --git a/py/nlrx86.c b/py/nlrx86.c index 085e30d2034..26bf0dc6ccb 100644 --- a/py/nlrx86.c +++ b/py/nlrx86.c @@ -78,7 +78,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { #endif } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( diff --git a/py/nlrxtensa.c b/py/nlrxtensa.c index ff7af6edeef..2d1bf35e381 100644 --- a/py/nlrxtensa.c +++ b/py/nlrxtensa.c @@ -55,7 +55,7 @@ unsigned int nlr_push(nlr_buf_t *nlr) { return 0; // needed to silence compiler warning } -NORETURN void nlr_jump(void *val) { +MP_NORETURN void nlr_jump(void *val) { MP_NLR_JUMP_HEAD(val, top) __asm volatile ( diff --git a/py/obj.c b/py/obj.c index 29ae76557f8..ba3e6a9a996 100644 --- a/py/obj.c +++ b/py/obj.c @@ -157,7 +157,7 @@ void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t if (MP_OBJ_TYPE_HAS_SLOT(type, print)) { MP_OBJ_TYPE_GET_SLOT(type, print)((mp_print_t *)print, o_in, kind); } else { - mp_printf(print, "<%q>", type->name); + mp_printf(print, "<%q>", (qstr)type->name); } } @@ -417,6 +417,36 @@ mp_int_t mp_obj_get_int(mp_const_obj_t arg) { return val; } +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE +mp_uint_t mp_obj_get_uint(mp_const_obj_t arg) { + if (!mp_obj_is_exact_type(arg, &mp_type_int)) { + mp_obj_t as_int = mp_unary_op(MP_UNARY_OP_INT_MAYBE, (mp_obj_t)arg); + if (as_int == MP_OBJ_NULL) { + mp_raise_TypeError_int_conversion(arg); + } + arg = as_int; + } + return mp_obj_int_get_uint_checked(arg); +} + +long long mp_obj_get_ll(mp_const_obj_t arg) { + if (!mp_obj_is_exact_type(arg, &mp_type_int)) { + mp_obj_t as_int = mp_unary_op(MP_UNARY_OP_INT_MAYBE, (mp_obj_t)arg); + if (as_int == MP_OBJ_NULL) { + mp_raise_TypeError_int_conversion(arg); + } + arg = as_int; + } + if (mp_obj_is_small_int(arg)) { + return MP_OBJ_SMALL_INT_VALUE(arg); + } else { + long long res; + mp_obj_int_to_bytes_impl((mp_obj_t)arg, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res); + return res; + } +} +#endif + mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg) { if (mp_obj_is_int(arg)) { return mp_obj_int_get_truncated(arg); diff --git a/py/obj.h b/py/obj.h index 38db17cba44..e85505ff3ae 100644 --- a/py/obj.h +++ b/py/obj.h @@ -184,13 +184,15 @@ static inline bool mp_obj_is_small_int(mp_const_obj_t o) { #define MP_OBJ_NEW_SMALL_INT(small_int) ((mp_obj_t)((((mp_uint_t)(small_int)) << 1) | 1)) #if MICROPY_PY_BUILTINS_FLOAT -#define MP_OBJ_NEW_CONST_FLOAT(f) MP_ROM_PTR((mp_obj_t)((((((uint64_t)f) & ~3) | 2) + 0x80800000) & 0xffffffff)) +#include +// note: MP_OBJ_NEW_CONST_FLOAT should be a MP_ROM_PTR but that macro isn't available yet +#define MP_OBJ_NEW_CONST_FLOAT(f) ((mp_obj_t)((((((uint64_t)f) & ~3) | 2) + 0x80800000) & 0xffffffff)) #define mp_const_float_e MP_OBJ_NEW_CONST_FLOAT(0x402df854) #define mp_const_float_pi MP_OBJ_NEW_CONST_FLOAT(0x40490fdb) +#define mp_const_float_nan MP_OBJ_NEW_CONST_FLOAT(0x7fc00000) #if MICROPY_PY_MATH_CONSTANTS #define mp_const_float_tau MP_OBJ_NEW_CONST_FLOAT(0x40c90fdb) #define mp_const_float_inf MP_OBJ_NEW_CONST_FLOAT(0x7f800000) -#define mp_const_float_nan MP_OBJ_NEW_CONST_FLOAT(0xffc00000) #endif static inline bool mp_obj_is_float(mp_const_obj_t o) { @@ -204,9 +206,17 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { mp_float_t f; mp_uint_t u; } num = {.u = ((mp_uint_t)o - 0x80800000u) & ~3u}; + // Rather than always truncating toward zero, which creates a strong + // bias, copy the two previous bits to fill in the two missing bits. + // This appears to be a pretty good heuristic. + num.u |= (num.u >> 2) & 3u; return num.f; } static inline mp_obj_t mp_obj_new_float(mp_float_t f) { + if (isnan(f)) { + // prevent creation of bad nanboxed pointers via array.array or struct + return mp_const_float_nan; + } union { mp_float_t f; mp_uint_t u; @@ -257,8 +267,10 @@ static inline bool mp_obj_is_immediate_obj(mp_const_obj_t o) { #error MICROPY_OBJ_REPR_D requires MICROPY_FLOAT_IMPL_DOUBLE #endif +#include #define mp_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))} #define mp_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))} +#define mp_const_float_nan {((mp_obj_t)((uint64_t)0x7ff8000000000000 + 0x8004000000000000))} #if MICROPY_PY_MATH_CONSTANTS #define mp_const_float_tau {((mp_obj_t)((uint64_t)0x401921fb54442d18 + 0x8004000000000000))} #define mp_const_float_inf {((mp_obj_t)((uint64_t)0x7ff0000000000000 + 0x8004000000000000))} @@ -276,6 +288,13 @@ static inline mp_float_t mp_obj_float_get(mp_const_obj_t o) { return num.f; } static inline mp_obj_t mp_obj_new_float(mp_float_t f) { + if (isnan(f)) { + // prevent creation of bad nanboxed pointers via array.array or struct + struct { + uint64_t r; + } num = mp_const_float_nan; + return num.r; + } union { mp_float_t f; uint64_t r; @@ -371,22 +390,22 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; #define MP_DEFINE_CONST_FUN_OBJ_0(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed_t obj_name = \ - {{&mp_type_fun_builtin_0}, .fun._0 = fun_name} + {.base = {.type = &mp_type_fun_builtin_0}, .fun = {._0 = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_1(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed_t obj_name = \ - {{&mp_type_fun_builtin_1}, .fun._1 = fun_name} + {.base = {.type = &mp_type_fun_builtin_1}, .fun = {._1 = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_2(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed_t obj_name = \ - {{&mp_type_fun_builtin_2}, .fun._2 = fun_name} + {.base = {.type = &mp_type_fun_builtin_2}, .fun = {._2 = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_3(obj_name, fun_name) \ const mp_obj_fun_builtin_fixed_t obj_name = \ - {{&mp_type_fun_builtin_3}, .fun._3 = fun_name} + {.base = {.type = &mp_type_fun_builtin_3}, .fun = {._3 = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_VAR(obj_name, n_args_min, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ - {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, false), .fun.var = fun_name} + {.base = {.type = &mp_type_fun_builtin_var}, .sig = MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, false), .fun = {.var = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ - {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun.var = fun_name} + {.base = {.type = &mp_type_fun_builtin_var}, .sig = MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun = {.var = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name} @@ -516,9 +535,7 @@ static inline bool mp_map_slot_is_filled(const mp_map_t *map, size_t pos) { void mp_map_init(mp_map_t *map, size_t n); void mp_map_init_fixed_table(mp_map_t *map, size_t n, const mp_obj_t *table); -mp_map_t *mp_map_new(size_t n); void mp_map_deinit(mp_map_t *map); -void mp_map_free(mp_map_t *map); mp_map_elem_t *mp_map_lookup(mp_map_t *map, mp_obj_t index, mp_map_lookup_kind_t lookup_kind); void mp_map_clear(mp_map_t *map); void mp_map_dump(mp_map_t *map); @@ -555,6 +572,10 @@ typedef mp_obj_t (*mp_fun_var_t)(size_t n, const mp_obj_t *); typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); // Flags for type behaviour (mp_obj_type_t.flags) +// If MP_TYPE_FLAG_IS_SUBCLASSED is set, then subclasses of this class have been created. +// Mutations to this class that would require updating all subclasses must be rejected. +// If MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS is set, then attribute lookups involving this +// class need to additionally check for special accessor methods, such as from descriptors. // If MP_TYPE_FLAG_EQ_NOT_REFLEXIVE is clear then __eq__ is reflexive (A==A returns True). // If MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE is clear then the type can't be equal to an // instance of any different class that also clears this flag. If this flag is set @@ -572,6 +593,8 @@ typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); // If MP_TYPE_FLAG_ITER_IS_STREAM is set then the type implicitly gets a "return self" // getiter, and mp_stream_unbuffered_iter for iternext. // If MP_TYPE_FLAG_INSTANCE_TYPE is set then this is an instance type (i.e. defined in Python). +// If MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE is set then the "subscr" slot allows a stack +// allocated slice to be passed in (no references to it will be retained after the call). #define MP_TYPE_FLAG_NONE (0x0000) #define MP_TYPE_FLAG_IS_SUBCLASSED (0x0001) #define MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS (0x0002) @@ -585,8 +608,9 @@ typedef mp_obj_t (*mp_fun_kw_t)(size_t n, const mp_obj_t *, mp_map_t *); #define MP_TYPE_FLAG_ITER_IS_CUSTOM (0x0100) #define MP_TYPE_FLAG_ITER_IS_STREAM (MP_TYPE_FLAG_ITER_IS_ITERNEXT | MP_TYPE_FLAG_ITER_IS_CUSTOM) #define MP_TYPE_FLAG_INSTANCE_TYPE (0x0200) +#define MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE (0x0400) // CIRCUITPY-CHANGE: check for valid types in json dumps -#define MP_TYPE_FLAG_PRINT_JSON (0x0400) +#define MP_TYPE_FLAG_PRINT_JSON (0x0800) typedef enum { PRINT_STR = 0, @@ -827,7 +851,7 @@ typedef struct _mp_obj_full_type_t { #define MP_DEFINE_CONST_OBJ_TYPE_NARGS(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, N, ...) MP_DEFINE_CONST_OBJ_TYPE_NARGS_##N // This macros is used to define a object type in ROM. -// Invoke as MP_DEFINE_CONST_OBJ_TYPE(_typename, _name, _flags, _make_new [, slot, func]*) +// Invoke as MP_DEFINE_CONST_OBJ_TYPE(_typename, _name, _flags, [, slot, func]*) // It uses the number of arguments to select which MP_DEFINE_CONST_OBJ_TYPE_* // macro to use based on the number of arguments. It works by shifting the // numeric values 12, 11, ... 0 by the number of arguments, such that the @@ -927,7 +951,6 @@ extern const mp_obj_type_t mp_type_StopAsyncIteration; extern const mp_obj_type_t mp_type_StopIteration; extern const mp_obj_type_t mp_type_SyntaxError; extern const mp_obj_type_t mp_type_SystemExit; -extern const mp_obj_type_t mp_type_TimeoutError; extern const mp_obj_type_t mp_type_TypeError; extern const mp_obj_type_t mp_type_UnicodeError; extern const mp_obj_type_t mp_type_ValueError; @@ -991,11 +1014,11 @@ void *mp_obj_malloc_helper(size_t num_bytes, const mp_obj_type_t *type); // Object allocation macros for allocating objects that have a finaliser. #if MICROPY_ENABLE_FINALISER #define mp_obj_malloc_with_finaliser(struct_type, obj_type) ((struct_type *)mp_obj_malloc_with_finaliser_helper(sizeof(struct_type), obj_type)) -#define mp_obj_malloc_var_with_finaliser(struct_type, var_type, var_num, obj_type) ((struct_type *)mp_obj_malloc_with_finaliser_helper(sizeof(struct_type) + sizeof(var_type) * (var_num), obj_type)) +#define mp_obj_malloc_var_with_finaliser(struct_type, var_field, var_type, var_num, obj_type) ((struct_type *)mp_obj_malloc_with_finaliser_helper(offsetof(struct_type, var_field) + sizeof(var_type) * (var_num), obj_type)) void *mp_obj_malloc_with_finaliser_helper(size_t num_bytes, const mp_obj_type_t *type); #else #define mp_obj_malloc_with_finaliser(struct_type, obj_type) mp_obj_malloc(struct_type, obj_type) -#define mp_obj_malloc_var_with_finaliser(struct_type, var_type, var_num, obj_type) mp_obj_malloc_var(struct_type, var_type, var_num, obj_type) +#define mp_obj_malloc_var_with_finaliser(struct_type, var_field, var_type, var_num, obj_type) mp_obj_malloc_var(struct_type, var_field, var_type, var_num, obj_type) #endif // These macros are derived from more primitive ones and are used to @@ -1032,7 +1055,6 @@ bool mp_obj_is_dict_or_ordereddict(mp_obj_t o); // type check is done on iter method to allow tuple, namedtuple, attrtuple #define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter) -mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); static inline mp_obj_t mp_obj_new_bool(mp_int_t x) { return x ? mp_const_true : mp_const_false; } @@ -1114,6 +1136,8 @@ static inline bool mp_obj_is_integer(mp_const_obj_t o) { } mp_int_t mp_obj_get_int(mp_const_obj_t arg); +mp_uint_t mp_obj_get_uint(mp_const_obj_t arg); +long long mp_obj_get_ll(mp_const_obj_t arg); mp_int_t mp_obj_get_int_truncated(mp_const_obj_t arg); bool mp_obj_get_int_maybe(mp_const_obj_t arg, mp_int_t *value); #if MICROPY_PY_BUILTINS_FLOAT diff --git a/py/objarray.c b/py/objarray.c index 0be1947167d..5b63f693698 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -126,6 +126,19 @@ static mp_obj_array_t *array_new(char typecode, size_t n) { #endif #if MICROPY_PY_BUILTINS_BYTEARRAY || MICROPY_PY_ARRAY +static void array_extend_impl(mp_obj_array_t *array, mp_obj_t arg, char typecode, size_t len) { + mp_obj_t iterable = mp_getiter(arg, NULL); + mp_obj_t item; + size_t i = 0; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if (len == 0) { + array_append(MP_OBJ_FROM_PTR(array), item); + } else { + mp_binary_set_val_array(typecode, array->items, i++, item); + } + } +} + static mp_obj_t array_construct(char typecode, mp_obj_t initializer) { // bytearrays can be raw-initialised from anything with the buffer protocol // other arrays can only be raw-initialised from bytes and bytearray objects @@ -158,18 +171,7 @@ static mp_obj_t array_construct(char typecode, mp_obj_t initializer) { } mp_obj_array_t *array = array_new(typecode, len); - - mp_obj_t iterable = mp_getiter(initializer, NULL); - mp_obj_t item; - size_t i = 0; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - if (len == 0) { - array_append(MP_OBJ_FROM_PTR(array), item); - } else { - mp_binary_set_val_array(typecode, array->items, i++, item); - } - } - + array_extend_impl(array, initializer, typecode, len); return MP_OBJ_FROM_PTR(array); } #endif @@ -493,9 +495,10 @@ static mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) { // allow to extend by anything that has the buffer protocol (extension to CPython) mp_buffer_info_t arg_bufinfo; - // CIRCUITPY-CHANGE: allow appending an iterable - if (mp_get_buffer(arg_in, &arg_bufinfo, MP_BUFFER_READ)) { - size_t sz = mp_binary_get_size('@', self->typecode, NULL); + if (!mp_get_buffer(arg_in, &arg_bufinfo, MP_BUFFER_READ)) { + array_extend_impl(self, arg_in, 0, 0); + return mp_const_none; + } // convert byte count to element count size_t len = arg_bufinfo.len / sz; @@ -561,6 +564,8 @@ static mp_obj_t buffer_finder(size_t n_args, const mp_obj_t *args, int direction } else { return MP_OBJ_NEW_SMALL_INT(-1); } + } else { + self->free -= len; } return MP_OBJ_NEW_SMALL_INT(p - (const byte *)haystack_bufinfo.buf); } @@ -667,7 +672,7 @@ static mp_obj_t array_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value mp_seq_replace_slice_no_grow(dest_items, o->len, slice.start, slice.stop, src_items + src_offs, src_len, item_sz); // CIRCUITPY-CHANGE - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES // Clear "freed" elements at the end of list // TODO: This is actually only needed for typecode=='O' mp_seq_clear(dest_items, o->len + len_adj, o->len, item_sz); diff --git a/py/objboundmeth.c b/py/objboundmeth.c index e3503ff154a..6df67f7bf9e 100644 --- a/py/objboundmeth.c +++ b/py/objboundmeth.c @@ -102,7 +102,11 @@ static mp_obj_t bound_meth_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_ } mp_obj_bound_meth_t *lhs = MP_OBJ_TO_PTR(lhs_in); mp_obj_bound_meth_t *rhs = MP_OBJ_TO_PTR(rhs_in); + #if MICROPY_PY_BOUND_METHOD_FULL_EQUALITY_CHECK + return mp_obj_new_bool(mp_obj_equal(lhs->self, rhs->self) && mp_obj_equal(lhs->meth, rhs->meth)); + #else return mp_obj_new_bool(lhs->self == rhs->self && lhs->meth == rhs->meth); + #endif } #if MICROPY_PY_FUNCTION_ATTRS diff --git a/py/objcell.c b/py/objcell.c index 95966c7917c..5c030c7405a 100644 --- a/py/objcell.c +++ b/py/objcell.c @@ -30,7 +30,7 @@ static void cell_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_cell_t *o = MP_OBJ_TO_PTR(o_in); - mp_printf(print, "obj); + mp_printf(print, "obj); if (o->obj == MP_OBJ_NULL) { mp_print_str(print, "(nil)"); } else { diff --git a/py/objcode.c b/py/objcode.c index 9b98a696798..09904f10f36 100644 --- a/py/objcode.c +++ b/py/objcode.c @@ -69,6 +69,7 @@ static mp_obj_tuple_t *code_consts(const mp_module_context_t *context, const mp_ return consts; } +#if !MICROPY_PREVIEW_VERSION_2 static mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) { // const mp_bytecode_prelude_t *prelude = &rc->prelude; uint start = 0; @@ -106,6 +107,68 @@ static mp_obj_t raw_code_lnotab(const mp_raw_code_t *rc) { m_del(byte, buffer, buffer_size); return o; } +#endif + +static mp_obj_t code_colines_iter(mp_obj_t); +static mp_obj_t code_colines_next(mp_obj_t); +typedef struct _mp_obj_colines_iter_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + const mp_raw_code_t *rc; + mp_uint_t bc; + mp_uint_t source_line; + const byte *ci; +} mp_obj_colines_iter_t; + +static mp_obj_t code_colines_iter(mp_obj_t self_in) { + mp_obj_code_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_colines_iter_t *iter = mp_obj_malloc(mp_obj_colines_iter_t, &mp_type_polymorph_iter); + iter->iternext = code_colines_next; + iter->rc = self->rc; + iter->bc = 0; + iter->source_line = 1; + iter->ci = self->rc->prelude.line_info; + return MP_OBJ_FROM_PTR(iter); +} +static MP_DEFINE_CONST_FUN_OBJ_1(code_colines_obj, code_colines_iter); + +static mp_obj_t code_colines_next(mp_obj_t iter_in) { + mp_obj_colines_iter_t *iter = MP_OBJ_TO_PTR(iter_in); + const byte *ci_end = iter->rc->prelude.line_info_top; + + mp_uint_t start = iter->bc; + mp_uint_t line_no = iter->source_line; + bool another = true; + + while (another && iter->ci < ci_end) { + another = false; + mp_code_lineinfo_t decoded = mp_bytecode_decode_lineinfo(&iter->ci); + iter->bc += decoded.bc_increment; + iter->source_line += decoded.line_increment; + + if (decoded.bc_increment == 0) { + line_no = iter->source_line; + another = true; + } else if (decoded.line_increment == 0) { + another = true; + } + } + + if (another) { + mp_uint_t prelude_size = (iter->rc->prelude.opcodes - (const byte *)iter->rc->fun_data); + mp_uint_t bc_end = iter->rc->fun_data_len - prelude_size; + if (iter->bc >= bc_end) { + return MP_OBJ_STOP_ITERATION; + } else { + iter->bc = bc_end; + } + } + + mp_uint_t end = iter->bc; + mp_obj_t next[3] = {MP_OBJ_NEW_SMALL_INT(start), MP_OBJ_NEW_SMALL_INT(end), MP_OBJ_NEW_SMALL_INT(line_no)}; + + return mp_obj_new_tuple(MP_ARRAY_SIZE(next), next); +} static void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { if (dest[0] != MP_OBJ_NULL) { @@ -137,12 +200,18 @@ static void code_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { case MP_QSTR_co_names: dest[0] = MP_OBJ_FROM_PTR(o->dict_locals); break; + #if !MICROPY_PREVIEW_VERSION_2 case MP_QSTR_co_lnotab: if (!o->lnotab) { o->lnotab = raw_code_lnotab(rc); } dest[0] = o->lnotab; break; + #endif + case MP_QSTR_co_lines: + dest[0] = MP_OBJ_FROM_PTR(&code_colines_obj); + dest[1] = self_in; + break; } } @@ -168,7 +237,9 @@ mp_obj_t mp_obj_new_code(const mp_module_context_t *context, const mp_raw_code_t o->context = context; o->rc = rc; o->dict_locals = mp_locals_get(); // this is a wrong! how to do this properly? + #if !MICROPY_PREVIEW_VERSION_2 o->lnotab = MP_OBJ_NULL; + #endif return MP_OBJ_FROM_PTR(o); } diff --git a/py/objcode.h b/py/objcode.h index 8db9a34b6e1..7be15e23f52 100644 --- a/py/objcode.h +++ b/py/objcode.h @@ -72,15 +72,16 @@ static inline const void *mp_code_get_proto_fun(mp_obj_code_t *self) { #include "py/emitglue.h" -#define MP_CODE_QSTR_MAP(context, idx) (context->constants.qstr_table[idx]) +#define MP_CODE_QSTR_MAP(context, idx) ((qstr)(context->constants.qstr_table[idx])) typedef struct _mp_obj_code_t { - // TODO this was 4 words mp_obj_base_t base; const mp_module_context_t *context; const mp_raw_code_t *rc; mp_obj_dict_t *dict_locals; + #if !MICROPY_PREVIEW_VERSION_2 mp_obj_t lnotab; + #endif } mp_obj_code_t; mp_obj_t mp_obj_new_code(const mp_module_context_t *context, const mp_raw_code_t *rc, bool result_required); diff --git a/py/objcomplex.c b/py/objcomplex.c index d7287efdc13..88f4444f09e 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -49,29 +49,18 @@ typedef struct _mp_obj_complex_t { static void complex_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_complex_t *o = MP_OBJ_TO_PTR(o_in); - #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT - char buf[16]; - #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C - const int precision = 6; - #else - const int precision = 7; - #endif - #else - char buf[32]; - const int precision = 16; - #endif - if (o->real == 0) { - mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); - mp_printf(print, "%sj", buf); + const char *suffix; + int flags = 0; + if (o->real != 0) { + mp_print_str(print, "("); + mp_print_float(print, o->real, 'g', 0, '\0', -1, MP_FLOAT_REPR_PREC); + flags = PF_FLAG_SHOW_SIGN; + suffix = "j)"; } else { - mp_format_float(o->real, buf, sizeof(buf), 'g', precision, '\0'); - mp_printf(print, "(%s", buf); - if (o->imag >= 0 || isnan(o->imag)) { - mp_print_str(print, "+"); - } - mp_format_float(o->imag, buf, sizeof(buf), 'g', precision, '\0'); - mp_printf(print, "%sj)", buf); + suffix = "j"; } + mp_print_float(print, o->imag, 'g', flags, '\0', -1, MP_FLOAT_REPR_PREC); + mp_print_str(print, suffix); } static mp_obj_t complex_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { diff --git a/py/objdict.c b/py/objdict.c index 79a606f0970..d459d1ae486 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -101,7 +101,7 @@ static void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ #endif } if (MICROPY_PY_COLLECTIONS_ORDEREDDICT && self->base.type != &mp_type_dict && kind != PRINT_JSON) { - mp_printf(print, "%q(", self->base.type->name); + mp_printf(print, "%q(", (qstr)self->base.type->name); } mp_print_str(print, "{"); size_t cur = 0; @@ -616,7 +616,8 @@ static mp_obj_t dict_view_unary_op(mp_unary_op_t op, mp_obj_t o_in) { if (op == MP_UNARY_OP_HASH && o->kind == MP_DICT_VIEW_VALUES) { return MP_OBJ_NEW_SMALL_INT((mp_uint_t)o_in); } - return MP_OBJ_NULL; + // delegate all other ops to dict unary op handler + return dict_unary_op(op, o->dict); } static mp_obj_t dict_view_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { diff --git a/py/objfloat.c b/py/objfloat.c index 3610c2b8586..ecc0f61a6ab 100644 --- a/py/objfloat.c +++ b/py/objfloat.c @@ -34,6 +34,11 @@ #if MICROPY_PY_BUILTINS_FLOAT +// Workaround a bug in Windows SDK version 10.0.26100.0, where NAN is no longer constant. +#if defined(_MSC_VER) && !defined(_UCRT_NOISY_NAN) +#define _UCRT_NOISY_NAN +#endif + #include #include "py/formatfloat.h" @@ -51,13 +56,6 @@ #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; @@ -116,23 +114,7 @@ mp_int_t mp_float_hash(mp_float_t src) { static void float_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_float_t o_val = mp_obj_float_get(o_in); - #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT - char buf[16]; - #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C - const int precision = 6; - #else - const int precision = 7; - #endif - #else - char buf[32]; - const int precision = 16; - #endif - mp_format_float(o_val, buf, sizeof(buf), 'g', precision, '\0'); - mp_print_str(print, buf); - if (strchr(buf, '.') == NULL && strchr(buf, 'e') == NULL && strchr(buf, 'n') == NULL) { - // Python floats always have decimal point (unless inf or nan) - mp_print_str(print, ".0"); - } + mp_print_float(print, o_val, 'g', PF_FLAG_ALWAYS_DECIMAL, '\0', -1, MP_FLOAT_REPR_PREC); } static mp_obj_t float_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -324,6 +306,10 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t lhs_val = MICROPY_FLOAT_CONST(1.0); break; } + if (isnan(rhs_val)) { + lhs_val = rhs_val; + break; + } #endif lhs_val = MICROPY_FLOAT_C_FUN(pow)(lhs_val, rhs_val); break; diff --git a/py/objint.c b/py/objint.c index b12f09c9d38..cabbd7b8f0e 100644 --- a/py/objint.c +++ b/py/objint.c @@ -117,9 +117,15 @@ static mp_fp_as_int_class_t mp_classify_fp_as_int(mp_float_t val) { } // 8 * sizeof(uintptr_t) counts the number of bits for a small int // TODO provide a way to configure this properly + #if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B + if (e <= ((8 * sizeof(uintptr_t) + MP_FLOAT_EXP_BIAS - 4) << MP_FLOAT_EXP_SHIFT_I32)) { + return MP_FP_CLASS_FIT_SMALLINT; + } + #else if (e <= ((8 * sizeof(uintptr_t) + MP_FLOAT_EXP_BIAS - 3) << MP_FLOAT_EXP_SHIFT_I32)) { return MP_FP_CLASS_FIT_SMALLINT; } + #endif #if MICROPY_LONGINT_IMPL == MICROPY_LONGINT_IMPL_LONGLONG if (e <= (((sizeof(long long) * MP_BITS_PER_BYTE) + MP_FLOAT_EXP_BIAS - 2) << MP_FLOAT_EXP_SHIFT_I32)) { return MP_FP_CLASS_FIT_LONGINT; @@ -211,7 +217,7 @@ static const uint8_t log_base2_floor[] = { size_t mp_int_format_size(size_t num_bits, int base, const char *prefix, char comma) { assert(2 <= base && base <= 16); size_t num_digits = num_bits / log_base2_floor[base - 1] + 1; - size_t num_commas = comma ? num_digits / 3 : 0; + size_t num_commas = comma ? (base == 10 ? num_digits / 3 : num_digits / 4): 0; size_t prefix_len = prefix ? strlen(prefix) : 0; return num_digits + num_commas + prefix_len + 2; // +1 for sign, +1 for null byte } @@ -249,10 +255,11 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co char sign = '\0'; if (num < 0) { - num = -num; + num = -(fmt_uint_t)num; sign = '-'; } + int n_comma = (base == 10) ? 3 : 4; size_t needed_size = mp_int_format_size(sizeof(fmt_int_t) * 8, base, prefix, comma); if (needed_size > *buf_size) { *buf = m_new(char, needed_size); @@ -277,7 +284,7 @@ char *mp_obj_int_formatted(char **buf, size_t *buf_size, size_t *fmt_size, mp_co c += '0'; } *(--b) = c; - if (comma && num != 0 && b > str && (last_comma - b) == 3) { + if (comma && num != 0 && b > str && (last_comma - b) == n_comma) { *(--b) = comma; last_comma = b; } diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 0fad693c7ad..4ff6ee6cff8 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -43,6 +43,9 @@ const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; #endif +static void raise_long_long_overflow(void) { + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("result overflows long long storage")); + // CIRCUITPY-CHANGE: bit_length mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in) { assert(mp_obj_is_type(self_in, &mp_type_int)); @@ -132,7 +135,6 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { // small int if the value fits without truncation case MP_UNARY_OP_HASH: return MP_OBJ_NEW_SMALL_INT((mp_int_t)o->val); - case MP_UNARY_OP_POSITIVE: return o_in; case MP_UNARY_OP_NEGATIVE: @@ -159,6 +161,8 @@ mp_obj_t mp_obj_int_unary_op(mp_unary_op_t op, mp_obj_t o_in) { mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_in) { long long lhs_val; long long rhs_val; + bool overflow = false; + long long result; if (mp_obj_is_small_int(lhs_in)) { lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs_in); @@ -171,21 +175,41 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs_in); } else if (mp_obj_is_exact_type(rhs_in, &mp_type_int)) { rhs_val = ((mp_obj_int_t *)rhs_in)->val; + #if MICROPY_PY_BUILTINS_FLOAT + } else if (mp_obj_is_float(rhs_in)) { + return mp_obj_float_binary_op(op, (mp_float_t)lhs_val, rhs_in); + #endif + #if MICROPY_PY_BUILTINS_COMPLEX + } else if (mp_obj_is_type(rhs_in, &mp_type_complex)) { + return mp_obj_complex_binary_op(op, (mp_float_t)lhs_val, 0, rhs_in); + #endif } else { // delegate to generic function to check for extra cases return mp_obj_int_binary_op_extra_cases(op, lhs_in, rhs_in); } + #if MICROPY_PY_BUILTINS_FLOAT + if (op == MP_BINARY_OP_TRUE_DIVIDE || op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE) { + if (rhs_val == 0) { + goto zero_division; + } + return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val); + } + #endif + switch (op) { case MP_BINARY_OP_ADD: case MP_BINARY_OP_INPLACE_ADD: - return mp_obj_new_int_from_ll(lhs_val + rhs_val); + overflow = mp_add_ll_overflow(lhs_val, rhs_val, &result); + break; case MP_BINARY_OP_SUBTRACT: case MP_BINARY_OP_INPLACE_SUBTRACT: - return mp_obj_new_int_from_ll(lhs_val - rhs_val); + overflow = mp_sub_ll_overflow(lhs_val, rhs_val, &result); + break; case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: - return mp_obj_new_int_from_ll(lhs_val * rhs_val); + overflow = mp_mul_ll_overflow(lhs_val, rhs_val, &result); + break; case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: if (rhs_val == 0) { @@ -211,9 +235,21 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i case MP_BINARY_OP_LSHIFT: case MP_BINARY_OP_INPLACE_LSHIFT: - return mp_obj_new_int_from_ll(lhs_val << (int)rhs_val); + if (rhs_val < 0) { + // negative shift not allowed + mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); + } + overflow = rhs_val >= (sizeof(long long) * MP_BITS_PER_BYTE) + || lhs_val > (LLONG_MAX >> rhs_val) + || lhs_val < (LLONG_MIN >> rhs_val); + result = (unsigned long long)lhs_val << rhs_val; + break; case MP_BINARY_OP_RSHIFT: case MP_BINARY_OP_INPLACE_RSHIFT: + if ((int)rhs_val < 0) { + // negative shift not allowed + mp_raise_ValueError(MP_ERROR_TEXT("negative shift count")); + } return mp_obj_new_int_from_ll(lhs_val >> (int)rhs_val); case MP_BINARY_OP_POWER: @@ -225,18 +261,18 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mp_raise_ValueError(MP_ERROR_TEXT("negative power with no float support")); #endif } - long long ans = 1; - while (rhs_val > 0) { + result = 1; + while (rhs_val > 0 && !overflow) { if (rhs_val & 1) { - ans *= lhs_val; + overflow = mp_mul_ll_overflow(result, lhs_val, &result); } - if (rhs_val == 1) { + if (rhs_val == 1 || overflow) { break; } rhs_val /= 2; - lhs_val *= lhs_val; + overflow = mp_mul_ll_overflow(lhs_val, lhs_val, &lhs_val); } - return mp_obj_new_int_from_ll(ans); + break; } case MP_BINARY_OP_LESS: @@ -254,8 +290,14 @@ mp_obj_t mp_obj_int_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i return MP_OBJ_NULL; // op not supported } + if (overflow) { + raise_long_long_overflow(); + } + + return mp_obj_new_int_from_ll(result); + zero_division: - mp_raise_ZeroDivisionError(); + mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("divide by zero")); } mp_obj_t mp_obj_new_int(mp_int_t value) { @@ -277,22 +319,12 @@ mp_obj_t mp_obj_new_int_from_ll(long long val) { } mp_obj_t mp_obj_new_int_from_ull(unsigned long long val) { - // TODO raise an exception if the unsigned long long won't fit if (val >> (sizeof(unsigned long long) * 8 - 1) != 0) { - mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("ulonglong too large")); + raise_long_long_overflow(); } return mp_obj_new_int_from_ll(val); } -mp_obj_t mp_obj_new_int_from_str_len(const char **str, size_t len, bool neg, unsigned int base) { - // TODO this does not honor the given length of the string, but it all cases it should anyway be null terminated - // TODO check overflow - char *endptr; - mp_obj_t result = mp_obj_new_int_from_ll(strtoll(*str, &endptr, base)); - *str = endptr; - return result; -} - mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { if (mp_obj_is_small_int(self_in)) { return MP_OBJ_SMALL_INT_VALUE(self_in); diff --git a/py/objint_mpz.c b/py/objint_mpz.c index 111f53009fb..1bede811a4a 100644 --- a/py/objint_mpz.c +++ b/py/objint_mpz.c @@ -364,9 +364,10 @@ static mpz_t *mp_mpz_for_int(mp_obj_t arg, mpz_t *temp) { mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { if (!mp_obj_is_int(base) || !mp_obj_is_int(exponent) || !mp_obj_is_int(modulus)) { mp_raise_TypeError(MP_ERROR_TEXT("pow() with 3 arguments requires integers")); + } else if (modulus == MP_OBJ_NEW_SMALL_INT(0)) { + mp_raise_ValueError(MP_ERROR_TEXT("divide by zero")); } else { - mp_obj_t result = mp_obj_new_int_from_ull(0); // Use the _from_ull version as this forces an mpz int - mp_obj_int_t *res_p = (mp_obj_int_t *)MP_OBJ_TO_PTR(result); + mp_obj_int_t *res_p = mp_obj_int_new_mpz(); mpz_t l_temp, r_temp, m_temp; mpz_t *lhs = mp_mpz_for_int(base, &l_temp); @@ -389,7 +390,7 @@ mp_obj_t mp_obj_int_pow3(mp_obj_t base, mp_obj_t exponent, mp_obj_t modulus) { if (mod == &m_temp) { mpz_deinit(mod); } - return result; + return MP_OBJ_FROM_PTR(res_p); } } #endif diff --git a/py/objlist.c b/py/objlist.c index 3137e9fa534..beb647917d9 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -118,7 +118,7 @@ static mp_obj_t list_unary_op(mp_unary_op_t op, mp_obj_t self_in) { } static mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: allow subclassing mp_obj_list_t *o = native_list(lhs); switch (op) { case MP_BINARY_OP_ADD: { @@ -142,7 +142,7 @@ static mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { if (n < 0) { n = 0; } - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: overflow check (PR#1279) size_t new_len = mp_seq_multiply_len(o->len, n); mp_obj_list_t *s = list_new(new_len); mp_seq_multiply(o->items, sizeof(*o->items), o->len, n, s->items); @@ -171,76 +171,66 @@ static mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { } static mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { - // CIRCUITPY-CHANGE + #if MICROPY_PY_BUILTINS_SLICE + if (mp_obj_is_type(index, &mp_type_slice)) { + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); - if (value == MP_OBJ_NULL) { - // delete - #if MICROPY_PY_BUILTINS_SLICE - if (mp_obj_is_type(index, &mp_type_slice)) { - mp_bound_slice_t slice; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { - mp_raise_NotImplementedError(NULL); + mp_bound_slice_t slice; + bool fast = mp_seq_get_fast_slice_indexes(self->len, index, &slice); + if (value == MP_OBJ_SENTINEL) { + // load + if (!fast) { + return mp_seq_extract_slice(self->items, &slice); } - - mp_int_t len_adj = slice.start - slice.stop; - assert(len_adj <= 0); - mp_seq_replace_slice_no_grow(self->items, self->len, slice.start, slice.stop, self->items /*NULL*/, 0, sizeof(*self->items)); + mp_obj_list_t *res = list_new(slice.stop - slice.start); + mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); + return MP_OBJ_FROM_PTR(res); + } + // assign/delete + if (value == MP_OBJ_NULL) { + // delete is equivalent to slice assignment of an empty sequence + value = mp_const_empty_tuple; + } + if (!fast) { + mp_raise_NotImplementedError(NULL); + } + size_t value_len; + mp_obj_t *value_items; + mp_obj_get_array(value, &value_len, &value_items); + mp_int_t len_adj = value_len - (slice.stop - slice.start); + if (len_adj > 0) { + if (self->len + len_adj > self->alloc) { + // TODO: Might optimize memory copies here by checking if block can + // be grown inplace or not + self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); + self->alloc = self->len + len_adj; + } + mp_seq_replace_slice_grow_inplace(self->items, self->len, + slice.start, slice.stop, value_items, value_len, len_adj, sizeof(*self->items)); + } else { + mp_seq_replace_slice_no_grow(self->items, self->len, + slice.start, slice.stop, value_items, value_len, sizeof(*self->items)); // Clear "freed" elements at the end of list mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); - self->len += len_adj; - return mp_const_none; + // TODO: apply allocation policy re: alloc_size } - #endif - // CIRCUITPY-CHANGE + self->len += len_adj; + return mp_const_none; + } + #endif + if (value == MP_OBJ_NULL) { + // delete + // CIRCUITPY-CHANGE: handle subclassing mp_obj_t args[2] = {MP_OBJ_FROM_PTR(self), index}; list_pop(2, args); return mp_const_none; } else if (value == MP_OBJ_SENTINEL) { // load - #if MICROPY_PY_BUILTINS_SLICE - if (mp_obj_is_type(index, &mp_type_slice)) { - mp_bound_slice_t slice; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice)) { - return mp_seq_extract_slice(self->items, &slice); - } - mp_obj_list_t *res = list_new(slice.stop - slice.start); - mp_seq_copy(res->items, self->items + slice.start, res->len, mp_obj_t); - return MP_OBJ_FROM_PTR(res); - } - #endif + // CIRCUITPY-CHANGE: handle subclassing + mp_obj_list_t *self = native_list(self_in); size_t index_val = mp_get_index(self->base.type, self->len, index, false); return self->items[index_val]; } else { - #if MICROPY_PY_BUILTINS_SLICE - if (mp_obj_is_type(index, &mp_type_slice)) { - size_t value_len; - mp_obj_t *value_items; - mp_obj_get_array(value, &value_len, &value_items); - mp_bound_slice_t slice_out; - if (!mp_seq_get_fast_slice_indexes(self->len, index, &slice_out)) { - mp_raise_NotImplementedError(NULL); - } - mp_int_t len_adj = value_len - (slice_out.stop - slice_out.start); - if (len_adj > 0) { - if (self->len + len_adj > self->alloc) { - // TODO: Might optimize memory copies here by checking if block can - // be grown inplace or not - self->items = m_renew(mp_obj_t, self->items, self->alloc, self->len + len_adj); - self->alloc = self->len + len_adj; - } - mp_seq_replace_slice_grow_inplace(self->items, self->len, - slice_out.start, slice_out.stop, value_items, value_len, len_adj, sizeof(*self->items)); - } else { - mp_seq_replace_slice_no_grow(self->items, self->len, - slice_out.start, slice_out.stop, value_items, value_len, sizeof(*self->items)); - // Clear "freed" elements at the end of list - mp_seq_clear(self->items, self->len + len_adj, self->len, sizeof(*self->items)); - // TODO: apply allocation policy re: alloc_size - } - self->len += len_adj; - return mp_const_none; - } - #endif mp_obj_list_store(self_in, index, value); return mp_const_none; } @@ -252,7 +242,7 @@ static mp_obj_t list_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); if (self->len >= self->alloc) { self->items = m_renew(mp_obj_t, self->items, self->alloc, self->alloc * 2); @@ -266,7 +256,7 @@ mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg) { static mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); if (mp_obj_is_type(arg_in, &mp_type_list)) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); mp_obj_list_t *arg = native_list(arg_in); @@ -285,12 +275,13 @@ static mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { return mp_const_none; // return None, as per CPython } -// CIRCUITPY-CHANGE: used elsewhere so not static; impl is different -inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self, size_t index) { +// CIRCUITPY-CHANGE: provide version for C use outside this file +inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self_in, size_t index) { if (self->len == 0) { // CIRCUITPY-CHANGE: more specific mp_raise mp_raise_IndexError_varg(MP_ERROR_TEXT("pop from empty %q"), MP_QSTR_list); } + size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); mp_obj_t ret = self->items[index]; self->len -= 1; memmove(self->items + index, self->items + index + 1, (self->len - index) * sizeof(mp_obj_t)); @@ -303,18 +294,28 @@ inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self, size_t index) { return ret; } -// CIRCUITPY-CHANGE static mp_obj_t list_pop(size_t n_args, const mp_obj_t *args) { mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); mp_obj_list_t *self = native_list(args[0]); size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); + // CIRCUITPY-CHANGE: use factored-out pop code return mp_obj_list_pop(self, index); } +// "head" is actually the *exclusive lower bound* of the range to sort. That is, +// the first element to be sorted is `head[1]`, not `head[0]`. Similarly `tail` +// is an *inclusive upper bound* of the range to sort. That is, the final +// element to sort is `tail[0]`, not `tail[-1]`. +// +// The pivot element is always chosen as `tail[0]`. +// +// These unusual choices allows structuring the partitioning +// process as a do/while loop, which generates smaller code than the equivalent +// code with usual C bounds & a while or for loop. static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj_t binop_less_result) { mp_cstack_check(); - while (head < tail) { - mp_obj_t *h = head - 1; + while (tail - head > 1) { // So long as at least 2 elements remain + mp_obj_t *h = head; mp_obj_t *t = tail; mp_obj_t v = key_fn == MP_OBJ_NULL ? tail[0] : mp_call_function_1(key_fn, tail[0]); // get pivot using key_fn for (;;) { @@ -325,19 +326,21 @@ static void mp_quicksort(mp_obj_t *head, mp_obj_t *tail, mp_obj_t key_fn, mp_obj if (h >= t) { break; } + // A pair of objects must be swapped to the other side of the partition mp_obj_t x = h[0]; h[0] = t[0]; t[0] = x; } + // Place the pivot element in the proper position mp_obj_t x = h[0]; h[0] = tail[0]; tail[0] = x; // do the smaller recursive call first, to keep stack within O(log(N)) - if (t - head < tail - h - 1) { + if (t - head < tail - h) { mp_quicksort(head, t, key_fn, binop_less_result); - head = h + 1; + head = h; } else { - mp_quicksort(h + 1, tail, key_fn, binop_less_result); + mp_quicksort(h, tail, key_fn, binop_less_result); tail = t; } } @@ -362,7 +365,7 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ mp_obj_list_t *self = native_list(pos_args[0]); if (self->len > 1) { - mp_quicksort(self->items, self->items + self->len - 1, + mp_quicksort(self->items - 1, self->items + self->len - 1, args.key.u_obj == mp_const_none ? MP_OBJ_NULL : args.key.u_obj, args.reverse.u_bool ? mp_const_false : mp_const_true); } @@ -370,10 +373,10 @@ mp_obj_t mp_obj_list_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ return mp_const_none; } -// CIRCUITPY-CHANGE: used elsewhere so not static +// CIRCUITPY-CHANGE: rename and make not static for use elsewhere mp_obj_t mp_obj_list_clear(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); self->len = 0; self->items = m_renew(mp_obj_t, self->items, self->alloc, LIST_MIN_ALLOC); @@ -384,27 +387,28 @@ mp_obj_t mp_obj_list_clear(mp_obj_t self_in) { static mp_obj_t list_copy(mp_obj_t self_in) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); return mp_obj_new_list(self->len, self->items); } static mp_obj_t list_count(mp_obj_t self_in, mp_obj_t value) { mp_check_self(mp_obj_is_type(self_in, &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(self_in); return mp_seq_count_obj(self->items, self->len, value); } static mp_obj_t list_index(size_t n_args, const mp_obj_t *args) { mp_check_self(mp_obj_is_type(args[0], &mp_type_list)); - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: handle subclassing mp_obj_list_t *self = native_list(args[0]); return mp_seq_index_obj(self->items, self->len, n_args, args); } -// CIRCUITPY-CHANGE: used elsewhere so not static -inline void mp_obj_list_insert(mp_obj_list_t *self, size_t index, mp_obj_t obj) { +// CIRCUITPY-CHANGE: factor out for C use elsewhere; not meant to emulate Python API +inline void mp_obj_list_insert(mp_obj_list_t *self_in, size_t index, mp_obj_t obj) { + mp_obj_list_t *self = native_list(self_in); mp_obj_list_append(MP_OBJ_FROM_PTR(self), mp_const_none); for (size_t i = self->len - 1; i > index; --i) { @@ -428,7 +432,7 @@ static mp_obj_t list_insert(mp_obj_t self_in, mp_obj_t idx, mp_obj_t obj) { if ((size_t)index > self->len) { index = self->len; } - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: use factored-out insert code mp_obj_list_insert(self, index, obj); return mp_const_none; } diff --git a/py/objmodule.c b/py/objmodule.c index a5c1dee968e..60b0368abac 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -34,11 +34,6 @@ #include "py/runtime.h" #include "py/builtin.h" -// CIRCUITPY-CHANGE -#if CIRCUITPY_WARNINGS -#include "shared-module/warnings/__init__.h" -#endif - static void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_module_t *self = MP_OBJ_TO_PTR(self_in); @@ -49,7 +44,7 @@ static void module_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kin module_name = mp_obj_str_get_str(elem->value); } - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ // If we store __file__ to imported modules then try to lookup this // symbol to give more information about the module. elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(MP_QSTR___file__), MP_MAP_LOOKUP); @@ -157,11 +152,13 @@ static const mp_rom_map_elem_t mp_builtin_module_table[] = { }; MP_DEFINE_CONST_MAP(mp_builtin_module_map, mp_builtin_module_table); +#if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES static const mp_rom_map_elem_t mp_builtin_extensible_module_table[] = { // built-in modules declared with MP_REGISTER_EXTENSIBLE_MODULE() MICROPY_REGISTERED_EXTENSIBLE_MODULES }; MP_DEFINE_CONST_MAP(mp_builtin_extensible_module_map, mp_builtin_extensible_module_table); +#endif #if MICROPY_MODULE_ATTR_DELEGATION && defined(MICROPY_MODULE_DELEGATIONS) typedef struct _mp_module_delegation_entry_t { @@ -178,13 +175,13 @@ static const mp_module_delegation_entry_t mp_builtin_module_delegation_table[] = // Attempts to find (and initialise) a built-in, otherwise returns // MP_OBJ_NULL. mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) { - // CIRCUITPY-CHANGE - #if CIRCUITPY_PARALLELDISPLAYBUS && CIRCUITPY_WARNINGS - if (module_name == MP_QSTR_paralleldisplay) { - warnings_warn(&mp_type_FutureWarning, MP_ERROR_TEXT("%q renamed %q"), MP_QSTR_paralleldisplay, MP_QSTR_paralleldisplaybus); - } + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES + const mp_map_t *map = extensible ? &mp_builtin_extensible_module_map : &mp_builtin_module_map; + #else + const mp_map_t *map = &mp_builtin_module_map; #endif - mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)(extensible ? &mp_builtin_extensible_module_map : &mp_builtin_module_map), MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup((mp_map_t *)map, MP_OBJ_NEW_QSTR(module_name), MP_MAP_LOOKUP); + if (!elem) { #if MICROPY_PY_SYS // Special case for sys, which isn't extensible but can always be @@ -194,6 +191,7 @@ mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) { } #endif + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES if (extensible) { // At this point we've already tried non-extensible built-ins, the // filesystem, and now extensible built-ins. No match, so fail diff --git a/py/objmodule.h b/py/objmodule.h index 8b14cd9fc3d..78e4da3cac6 100644 --- a/py/objmodule.h +++ b/py/objmodule.h @@ -35,7 +35,10 @@ #endif extern const mp_map_t mp_builtin_module_map; + +#if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES extern const mp_map_t mp_builtin_extensible_module_map; +#endif mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible); diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index b6bbe6e05d8..d687dbfda59 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -73,7 +73,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(namedtuple_asdict_obj, namedtuple_asdict); void namedtuple_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_namedtuple_t *o = MP_OBJ_TO_PTR(o_in); - mp_printf(print, "%q", o->tuple.base.type->name); + mp_printf(print, "%q", (qstr)o->tuple.base.type->name); const qstr *fields = ((mp_obj_namedtuple_type_t *)o->tuple.base.type)->fields; mp_obj_attrtuple_print_helper(print, fields, &o->tuple); } diff --git a/py/objrange.c b/py/objrange.c index bde2ebaabb4..dea9fe5f296 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -41,9 +41,9 @@ typedef struct _mp_obj_range_it_t { static mp_obj_t range_it_iternext(mp_obj_t o_in) { mp_obj_range_it_t *o = MP_OBJ_TO_PTR(o_in); if ((o->step > 0 && o->cur < o->stop) || (o->step < 0 && o->cur > o->stop)) { - mp_obj_t o_out = MP_OBJ_NEW_SMALL_INT(o->cur); + mp_int_t cur = o->cur; o->cur += o->step; - return o_out; + return mp_obj_new_int(cur); } else { return MP_OBJ_STOP_ITERATION; } @@ -133,7 +133,7 @@ static mp_obj_t range_unary_op(mp_unary_op_t op, mp_obj_t self_in) { case MP_UNARY_OP_BOOL: return mp_obj_new_bool(len > 0); case MP_UNARY_OP_LEN: - return MP_OBJ_NEW_SMALL_INT(len); + return mp_obj_new_int(len); default: return MP_OBJ_NULL; // op not supported } @@ -165,20 +165,16 @@ static mp_obj_t range_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { #if MICROPY_PY_BUILTINS_SLICE if (mp_obj_is_type(index, &mp_type_slice)) { mp_bound_slice_t slice; - mp_seq_get_fast_slice_indexes(len, index, &slice); + mp_obj_slice_indices(index, len, &slice); mp_obj_range_t *o = mp_obj_malloc(mp_obj_range_t, &mp_type_range); o->start = self->start + slice.start * self->step; o->stop = self->start + slice.stop * self->step; o->step = slice.step * self->step; - if (slice.step < 0) { - // Negative slice steps have inclusive stop, so adjust for exclusive - o->stop -= self->step; - } return MP_OBJ_FROM_PTR(o); } #endif size_t index_val = mp_get_index(self->base.type, len, index, false); - return MP_OBJ_NEW_SMALL_INT(self->start + index_val * self->step); + return mp_obj_new_int(self->start + index_val * self->step); } else { return MP_OBJ_NULL; // op not supported } diff --git a/py/objringio.c b/py/objringio.c index ba1ec25307e..0025b26be3b 100644 --- a/py/objringio.c +++ b/py/objringio.c @@ -39,22 +39,19 @@ typedef struct _micropython_ringio_obj_t { static mp_obj_t micropython_ringio_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 1, false); - mp_int_t buff_size = -1; mp_buffer_info_t bufinfo = {NULL, 0, 0}; if (!mp_get_buffer(args[0], &bufinfo, MP_BUFFER_RW)) { - buff_size = mp_obj_get_int(args[0]); + bufinfo.len = mp_obj_get_int(args[0]) + 1; + bufinfo.buf = m_new(uint8_t, bufinfo.len); } - micropython_ringio_obj_t *self = mp_obj_malloc(micropython_ringio_obj_t, type); - if (bufinfo.buf != NULL) { - // buffer passed in, use it directly for ringbuffer. - self->ringbuffer.buf = bufinfo.buf; - self->ringbuffer.size = bufinfo.len; - self->ringbuffer.iget = self->ringbuffer.iput = 0; - } else { - // Allocate new buffer, add one extra to buff_size as ringbuf consumes one byte for tracking. - ringbuf_alloc(&(self->ringbuffer), buff_size + 1); + if (bufinfo.len < 2 || bufinfo.len > UINT16_MAX) { + mp_raise_ValueError(NULL); } + micropython_ringio_obj_t *self = mp_obj_malloc(micropython_ringio_obj_t, type); + self->ringbuffer.buf = bufinfo.buf; + self->ringbuffer.size = bufinfo.len; + self->ringbuffer.iget = self->ringbuffer.iput = 0; return MP_OBJ_FROM_PTR(self); } diff --git a/py/objstr.c b/py/objstr.c index 1874cdb01d0..bd650bbe18a 100644 --- a/py/objstr.c +++ b/py/objstr.c @@ -33,6 +33,7 @@ #include "py/objlist.h" #include "py/runtime.h" #include "py/cstack.h" +#include "py/objtuple.h" // CIRCUITPY-CHANGE const char nibble_to_hex_upper[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', @@ -46,7 +47,7 @@ static mp_obj_t str_modulo_format(mp_obj_t pattern, size_t n_args, const mp_obj_ #endif static mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str, mp_obj_iter_buf_t *iter_buf); -static NORETURN void bad_implicit_conversion(mp_obj_t self_in); +static MP_NORETURN void bad_implicit_conversion(mp_obj_t self_in); static mp_obj_t mp_obj_new_str_type_from_vstr(const mp_obj_type_t *type, vstr_t *vstr); @@ -372,8 +373,7 @@ mp_obj_t mp_obj_str_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_obj_t rhs_i mp_obj_t *args = &rhs_in; size_t n_args = 1; mp_obj_t dict = MP_OBJ_NULL; - if (mp_obj_is_type(rhs_in, &mp_type_tuple)) { - // TODO: Support tuple subclasses? + if (mp_obj_is_tuple_compatible(rhs_in)) { mp_obj_tuple_get(rhs_in, &n_args, &args); } else if (mp_obj_is_type(rhs_in, &mp_type_dict)) { dict = rhs_in; @@ -1018,7 +1018,7 @@ static mp_obj_t arg_as_int(mp_obj_t arg) { #endif #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE -static NORETURN void terse_str_format_value_error(void) { +static MP_NORETURN void terse_str_format_value_error(void) { mp_raise_ValueError(MP_ERROR_TEXT("bad format string")); } #else @@ -1205,7 +1205,7 @@ static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar int width = -1; int precision = -1; char type = '\0'; - int flags = 0; + unsigned int flags = 0; if (format_spec) { // The format specifier (from http://docs.python.org/2/library/string.html#formatspec) @@ -1250,8 +1250,9 @@ static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } } s = str_to_int(s, stop, &width); - if (*s == ',') { - flags |= PF_FLAG_SHOW_COMMA; + if (*s == ',' || *s == '_') { + MP_STATIC_ASSERT((unsigned)'_' << PF_FLAG_SEP_POS >> PF_FLAG_SEP_POS == '_'); + flags |= (unsigned)*s << PF_FLAG_SEP_POS; s++; } if (*s == '.') { @@ -1324,7 +1325,7 @@ static vstr_t mp_obj_str_format_helper(const char *str, const char *top, int *ar } case '\0': // No explicit format type implies 'd' - case 'n': // I don't think we support locales in uPy so use 'd' + case 'n': // I don't think we support locales in MicroPython so use 'd' case 'd': mp_print_mp_int(&print, arg, 10, 'a', flags, fill, width, 0); continue; @@ -2395,7 +2396,7 @@ bool mp_obj_str_equal(mp_obj_t s1, mp_obj_t s2) { } } -static NORETURN void bad_implicit_conversion(mp_obj_t self_in) { +static MP_NORETURN void bad_implicit_conversion(mp_obj_t self_in) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE mp_raise_TypeError(MP_ERROR_TEXT("can't convert to str implicitly")); #else diff --git a/py/objtuple.c b/py/objtuple.c index e0b31edaf23..b2ccbbb2990 100644 --- a/py/objtuple.c +++ b/py/objtuple.c @@ -31,9 +31,6 @@ #include "py/objtuple.h" #include "py/runtime.h" -// type check is done on getiter method to allow tuple, namedtuple, attrtuple -#define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter) - /******************************************************************************/ /* tuple */ diff --git a/py/objtuple.h b/py/objtuple.h index e2d010e6c5a..783522a6222 100644 --- a/py/objtuple.h +++ b/py/objtuple.h @@ -57,7 +57,7 @@ extern const mp_obj_type_t mp_type_attrtuple; #define MP_DEFINE_ATTRTUPLE(tuple_obj_name, fields, nitems, ...) \ const mp_rom_obj_tuple_t tuple_obj_name = { \ - .base = {&mp_type_attrtuple}, \ + .base = {.type = &mp_type_attrtuple}, \ .len = nitems, \ .items = { __VA_ARGS__, MP_ROM_PTR((void *)fields) } \ } @@ -68,4 +68,7 @@ void mp_obj_attrtuple_print_helper(const mp_print_t *print, const qstr *fields, mp_obj_t mp_obj_new_attrtuple(const qstr *fields, size_t n, const mp_obj_t *items); +// type check is done on getiter method to allow tuple, namedtuple, attrtuple +#define mp_obj_is_tuple_compatible(o) (MP_OBJ_TYPE_GET_SLOT_OR_NULL(mp_obj_get_type(o), iter) == mp_obj_tuple_getiter) + #endif // MICROPY_INCLUDED_PY_OBJTUPLE_H diff --git a/py/objtype.c b/py/objtype.c index 074d6f39293..83bafa14e88 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -44,6 +44,7 @@ #define ENABLE_SPECIAL_ACCESSORS \ (MICROPY_PY_DESCRIPTORS || MICROPY_PY_DELATTR_SETATTR || MICROPY_PY_BUILTINS_PROPERTY) +static mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict); static mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo); static mp_obj_t static_class_method_make_new(const mp_obj_type_t *self_in, size_t n_args, size_t n_kw, const mp_obj_t *args); @@ -690,8 +691,8 @@ static void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des // try __getattr__ if (attr != MP_QSTR___getattr__) { #if MICROPY_PY_DESCRIPTORS - // With descriptors enabled, don't delegate lookups of __get__/__set__/__delete__. - if (attr == MP_QSTR___get__ || attr == MP_QSTR___set__ || attr == MP_QSTR___delete__) { + // With descriptors enabled, don't delegate lookups of __get__/__set__/__delete__/__set_name__. + if (attr == MP_QSTR___get__ || attr == MP_QSTR___set__ || attr == MP_QSTR___delete__ || attr == MP_QSTR___set_name__) { return; } #endif @@ -996,7 +997,7 @@ static bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { #endif #if MICROPY_PY_DESCRIPTORS static const uint8_t to_check[] = { - MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__, + MP_QSTR___get__, MP_QSTR___set__, MP_QSTR___delete__, // not needed for MP_QSTR___set_name__ though }; for (size_t i = 0; i < MP_ARRAY_SIZE(to_check); ++i) { mp_obj_t dest_temp[2]; @@ -1010,10 +1011,52 @@ static bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) { } #endif +#if MICROPY_PY_DESCRIPTORS +// Shared data layout for the __set_name__ call and a linked list of calls to be made. +typedef union _setname_list_t setname_list_t; +union _setname_list_t { + mp_obj_t call[4]; + struct { + mp_obj_t _meth; + mp_obj_t _self; + setname_list_t *next; // can use the "owner" argument position temporarily for the linked list + mp_obj_t _name; + }; +}; + +// Append any `__set_name__` method on `value` to the setname list, with its per-attr args +static setname_list_t *setname_maybe_bind_append(setname_list_t *tail, mp_obj_t name, mp_obj_t value) { + // make certain our type-punning is safe: + MP_STATIC_ASSERT_NONCONSTEXPR(offsetof(setname_list_t, next) == offsetof(setname_list_t, call[2])); + + // tail is a blank list entry + mp_load_method_maybe(value, MP_QSTR___set_name__, tail->call); + if (tail->call[1] != MP_OBJ_NULL) { + // Each time a __set_name__ is found, leave it in-place in the former tail and allocate a new tail + tail->next = m_new_obj(setname_list_t); + tail->next->next = NULL; + tail->call[3] = name; + return tail->next; + } else { + return tail; + } +} + +// Execute the captured `__set_name__` calls, destroying the setname list in the process. +static inline void setname_consume_call_all(setname_list_t *head, mp_obj_t owner) { + setname_list_t *next; + while ((next = head->next) != NULL) { + head->call[2] = owner; + mp_call_method_n_kw(2, 0, head->call); + head = next; + } +} +#endif + static void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in); - mp_printf(print, "", self->name); + mp_printf(print, "", (qstr)self->name); } static mp_obj_t type_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { @@ -1159,7 +1202,7 @@ MP_DEFINE_CONST_OBJ_TYPE( attr, type_attr ); -mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { +static mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { // Verify input objects have expected type if (!mp_obj_is_type(bases_tuple, &mp_type_tuple)) { mp_raise_TypeError(NULL); @@ -1252,20 +1295,38 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) } } + #if MICROPY_PY_DESCRIPTORS + // To avoid any dynamic allocations when no __set_name__ exists, + // the head of this list is kept on the stack (marked blank with `next = NULL`). + setname_list_t setname_list = { .next = NULL }; + setname_list_t *setname_tail = &setname_list; + #endif + #if ENABLE_SPECIAL_ACCESSORS - // Check if the class has any special accessor methods - if (!(o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS)) { - for (size_t i = 0; i < locals_ptr->map.alloc; i++) { - if (mp_map_slot_is_filled(&locals_ptr->map, i)) { - const mp_map_elem_t *elem = &locals_ptr->map.table[i]; - if (check_for_special_accessors(elem->key, elem->value)) { - o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; - break; - } + // Check if the class has any special accessor methods, + // and accumulate bound __set_name__ methods that need to be called + for (size_t i = 0; i < locals_ptr->map.alloc; i++) { + #if !MICROPY_PY_DESCRIPTORS + // __set_name__ needs to scan the entire locals map, can't early-terminate + if (o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS) { + break; + } + #endif + + if (mp_map_slot_is_filled(&locals_ptr->map, i)) { + const mp_map_elem_t *elem = &locals_ptr->map.table[i]; + + if (!(o->flags & MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS) // elidable when the early-termination check is enabled + && check_for_special_accessors(elem->key, elem->value)) { + o->flags |= MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS; } + + #if MICROPY_PY_DESCRIPTORS + setname_tail = setname_maybe_bind_append(setname_tail, elem->key, elem->value); + #endif } } - #endif + #endif // ENABLE_SPECIAL_ACCESSORS const mp_obj_type_t *native_base; size_t num_native_bases = instance_count_native_bases(o, &native_base); @@ -1273,8 +1334,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) mp_raise_TypeError(MP_ERROR_TEXT("multiple bases have instance lay-out conflict")); } - mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(o, locals_dict)->map; - mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); + mp_map_elem_t *elem = mp_map_lookup(&locals_ptr->map, MP_OBJ_NEW_QSTR(MP_QSTR___new__), MP_MAP_LOOKUP); if (elem != NULL) { // __new__ slot exists; check if it is a function if (mp_obj_is_fun(elem->value)) { @@ -1283,6 +1343,10 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) } } + #if MICROPY_PY_DESCRIPTORS + setname_consume_call_all(&setname_list, MP_OBJ_FROM_PTR(o)); + #endif + return MP_OBJ_FROM_PTR(o); } diff --git a/py/parse.c b/py/parse.c index a393b0ee8c1..36150ef468b 100644 --- a/py/parse.c +++ b/py/parse.c @@ -341,18 +341,34 @@ static uint8_t peek_rule(parser_t *parser, size_t n) { } #endif -bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { +#if MICROPY_COMP_CONST_FOLDING || MICROPY_EMIT_INLINE_ASM +static bool mp_parse_node_get_number_maybe(mp_parse_node_t pn, mp_obj_t *o) { if (MP_PARSE_NODE_IS_SMALL_INT(pn)) { *o = MP_OBJ_NEW_SMALL_INT(MP_PARSE_NODE_LEAF_SMALL_INT(pn)); return true; } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, RULE_const_object)) { mp_parse_node_struct_t *pns = (mp_parse_node_struct_t *)pn; *o = mp_parse_node_extract_const_object(pns); - return mp_obj_is_int(*o); + return mp_obj_is_int(*o) + #if MICROPY_COMP_CONST_FLOAT + || mp_obj_is_float(*o) + #endif + ; } else { return false; } } +#endif + +#if MICROPY_EMIT_INLINE_ASM +bool mp_parse_node_get_int_maybe(mp_parse_node_t pn, mp_obj_t *o) { + return mp_parse_node_get_number_maybe(pn, o) + #if MICROPY_COMP_CONST_FLOAT + && mp_obj_is_int(*o) + #endif + ; +} +#endif #if MICROPY_COMP_CONST_TUPLE || MICROPY_COMP_CONST static bool mp_parse_node_is_const(mp_parse_node_t pn) { @@ -647,12 +663,32 @@ static const mp_rom_map_elem_t mp_constants_table[] = { #if MICROPY_PY_UCTYPES { MP_ROM_QSTR(MP_QSTR_uctypes), MP_ROM_PTR(&mp_module_uctypes) }, #endif + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_PY_MATH && MICROPY_COMP_CONST_FLOAT + { MP_ROM_QSTR(MP_QSTR_math), MP_ROM_PTR(&mp_module_math) }, + #endif // Extra constants as defined by a port MICROPY_PORT_CONSTANTS }; static MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table); #endif +static bool binary_op_maybe(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs, mp_obj_t *res) { + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_obj_t tmp = mp_binary_op(op, lhs, rhs); + nlr_pop(); + #if MICROPY_PY_BUILTINS_COMPLEX + if (mp_obj_is_type(tmp, &mp_type_complex)) { + return false; + } + #endif + *res = tmp; + return true; + } else { + return false; + } +} + static bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *num_args) { if (rule_id == RULE_or_test || rule_id == RULE_and_test) { @@ -711,7 +747,7 @@ static bool fold_logical_constants(parser_t *parser, uint8_t rule_id, size_t *nu } static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { - // this code does folding of arbitrary integer expressions, eg 1 + 2 * 3 + 4 + // this code does folding of arbitrary numeric expressions, eg 1 + 2 * 3 + 4 // it does not do partial folding, eg 1 + 2 + x -> 3 + x mp_obj_t arg0; @@ -721,7 +757,7 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { || rule_id == RULE_power) { // folding for binary ops: | ^ & ** mp_parse_node_t pn = peek_result(parser, num_args - 1); - if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + if (!mp_parse_node_get_number_maybe(pn, &arg0)) { return false; } mp_binary_op_t op; @@ -737,58 +773,45 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { for (ssize_t i = num_args - 2; i >= 0; --i) { pn = peek_result(parser, i); mp_obj_t arg1; - if (!mp_parse_node_get_int_maybe(pn, &arg1)) { + if (!mp_parse_node_get_number_maybe(pn, &arg1)) { return false; } - if (op == MP_BINARY_OP_POWER && mp_obj_int_sign(arg1) < 0) { - // ** can't have negative rhs + if (!binary_op_maybe(op, arg0, arg1, &arg0)) { return false; } - arg0 = mp_binary_op(op, arg0, arg1); } } else if (rule_id == RULE_shift_expr || rule_id == RULE_arith_expr || rule_id == RULE_term) { // folding for binary ops: << >> + - * @ / % // mp_parse_node_t pn = peek_result(parser, num_args - 1); - if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + if (!mp_parse_node_get_number_maybe(pn, &arg0)) { return false; } for (ssize_t i = num_args - 2; i >= 1; i -= 2) { pn = peek_result(parser, i - 1); mp_obj_t arg1; - if (!mp_parse_node_get_int_maybe(pn, &arg1)) { + if (!mp_parse_node_get_number_maybe(pn, &arg1)) { return false; } mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, i)); - if (tok == MP_TOKEN_OP_AT || tok == MP_TOKEN_OP_SLASH) { - // Can't fold @ or / - return false; - } mp_binary_op_t op = MP_BINARY_OP_LSHIFT + (tok - MP_TOKEN_OP_DBL_LESS); - int rhs_sign = mp_obj_int_sign(arg1); - if (op <= MP_BINARY_OP_RSHIFT) { - // << and >> can't have negative rhs - if (rhs_sign < 0) { - return false; - } - } else if (op >= MP_BINARY_OP_FLOOR_DIVIDE) { - // % and // can't have zero rhs - if (rhs_sign == 0) { - return false; - } + if (!binary_op_maybe(op, arg0, arg1, &arg0)) { + return false; } - arg0 = mp_binary_op(op, arg0, arg1); } } else if (rule_id == RULE_factor_2) { // folding for unary ops: + - ~ mp_parse_node_t pn = peek_result(parser, 0); - if (!mp_parse_node_get_int_maybe(pn, &arg0)) { + if (!mp_parse_node_get_number_maybe(pn, &arg0)) { return false; } mp_token_kind_t tok = MP_PARSE_NODE_LEAF_ARG(peek_result(parser, 1)); mp_unary_op_t op; if (tok == MP_TOKEN_OP_TILDE) { + if (!mp_obj_is_int(arg0)) { + return false; + } op = MP_UNARY_OP_INVERT; } else { assert(tok == MP_TOKEN_OP_PLUS || tok == MP_TOKEN_OP_MINUS); // should be @@ -860,7 +883,7 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { return false; } // id1.id2 - // look it up in constant table, see if it can be replaced with an integer + // look it up in constant table, see if it can be replaced with an integer or a float mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t *)pn1; assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0])); qstr q_base = MP_PARSE_NODE_LEAF_ARG(pn0); @@ -871,7 +894,7 @@ static bool fold_constants(parser_t *parser, uint8_t rule_id, size_t num_args) { } mp_obj_t dest[2]; mp_load_method_maybe(elem->value, q_attr, dest); - if (!(dest[0] != MP_OBJ_NULL && mp_obj_is_int(dest[0]) && dest[1] == MP_OBJ_NULL)) { + if (!(dest[0] != MP_OBJ_NULL && (mp_obj_is_int(dest[0]) || mp_obj_is_float(dest[0])) && dest[1] == MP_OBJ_NULL)) { return false; } arg0 = dest[0]; diff --git a/py/parsenum.c b/py/parsenum.c index 874216f08d0..91340fd2a18 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -28,6 +28,7 @@ #include #include "py/runtime.h" +#include "py/misc.h" #include "py/parsenumbase.h" #include "py/parsenum.h" #include "py/smallint.h" @@ -36,7 +37,7 @@ #include #endif -static NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { +static MP_NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { // if lex!=NULL then the parser called us and we need to convert the // exception's type from ValueError to SyntaxError and add traceback info if (lex != NULL) { @@ -46,6 +47,27 @@ static NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) { nlr_raise(exc); } +#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_LONGLONG +// For the common small integer parsing case, we parse directly to mp_int_t and +// check that the value doesn't overflow a smallint (in which case we fail over +// to bigint parsing if supported) +typedef mp_int_t parsed_int_t; + +#define PARSED_INT_MUL_OVERFLOW mp_mul_mp_int_t_overflow +#define PARSED_INT_FITS MP_SMALL_INT_FITS +#else +// In the special case where bigint support is long long, we save code size by +// parsing directly to long long and then return either a bigint or smallint +// from the same result. +// +// To avoid pulling in (slow) signed 64-bit math routines we do the initial +// parsing to an unsigned long long and only convert to signed at the end. +typedef unsigned long long parsed_int_t; + +#define PARSED_INT_MUL_OVERFLOW mp_mul_ull_overflow +#define PARSED_INT_FITS(I) ((I) <= (unsigned long long)LLONG_MAX + 1) +#endif + mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex) { const byte *restrict str = (const byte *)str_; const byte *restrict top = str + len; @@ -77,7 +99,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m str += mp_parse_num_base((const char *)str, top - str, &base); // string should be an integer number - mp_int_t int_val = 0; + parsed_int_t parsed_val = 0; const byte *restrict str_val_start = str; for (; str < top; str++) { // get next digit as a value @@ -99,25 +121,32 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m break; } - // add next digi and check for overflow - if (mp_small_int_mul_overflow(int_val, base)) { + // add next digit and check for overflow + if (PARSED_INT_MUL_OVERFLOW(parsed_val, base, &parsed_val)) { goto overflow; } - int_val = int_val * base + dig; - if (!MP_SMALL_INT_FITS(int_val)) { + parsed_val += dig; + if (!PARSED_INT_FITS(parsed_val)) { goto overflow; } } - // negate value if needed - if (neg) { - int_val = -int_val; + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_LONGLONG + // The PARSED_INT_FITS check above ensures parsed_val fits in small int representation + ret_val = MP_OBJ_NEW_SMALL_INT(neg ? (-parsed_val) : parsed_val); +have_ret_val: + #else + // The PARSED_INT_FITS check above ensures parsed_val won't overflow signed long long + long long signed_val = -parsed_val; + if (!neg) { + if (signed_val == LLONG_MIN) { + goto overflow; + } + signed_val = -signed_val; } + ret_val = mp_obj_new_int_from_ll(signed_val); // Could be large or small int + #endif - // create the small int - ret_val = MP_OBJ_NEW_SMALL_INT(int_val); - -have_ret_val: // check we parsed something if (str == str_val_start) { goto value_error; @@ -136,6 +165,7 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m return ret_val; overflow: + #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_LONGLONG // reparse using long int { const char *s2 = (const char *)str_val_start; @@ -143,6 +173,9 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m str = (const byte *)s2; goto have_ret_val; } + #else + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("result overflows long long storage")); + #endif value_error: { @@ -167,6 +200,8 @@ mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, m } } +#if MICROPY_PY_BUILTINS_FLOAT + enum { REAL_IMAG_STATE_START = 0, REAL_IMAG_STATE_HAVE_REAL = 1, @@ -179,27 +214,77 @@ typedef enum { PARSE_DEC_IN_EXP, } parse_dec_in_t; -#if MICROPY_PY_BUILTINS_FLOAT // MANTISSA_MAX is used to retain precision while not overflowing mantissa -// SMALL_NORMAL_VAL is the smallest power of 10 that is still a normal float -// EXACT_POWER_OF_10 is the largest value of x so that 10^x can be stored exactly in a float -// Note: EXACT_POWER_OF_10 is at least floor(log_5(2^mantissa_length)). Indeed, 10^n = 2^n * 5^n -// so we only have to store the 5^n part in the mantissa (the 2^n part will go into the float's -// exponent). +#define MANTISSA_MAX (sizeof(mp_large_float_uint_t) == 8 ? 0x1999999999999998ULL : 0x19999998U) + +// MAX_EXACT_POWER_OF_5 is the largest value of x so that 5^x can be stored exactly in a float #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT -#define MANTISSA_MAX 0x19999998U -#define SMALL_NORMAL_VAL (1e-37F) -#define SMALL_NORMAL_EXP (-37) -#define EXACT_POWER_OF_10 (9) +#define MAX_EXACT_POWER_OF_5 (10) #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE -#define MANTISSA_MAX 0x1999999999999998ULL -#define SMALL_NORMAL_VAL (1e-307) -#define SMALL_NORMAL_EXP (-307) -#define EXACT_POWER_OF_10 (22) +#define MAX_EXACT_POWER_OF_5 (22) #endif +// Helper to compute `num * (10.0 ** dec_exp)` +mp_large_float_t mp_decimal_exp(mp_large_float_t num, int dec_exp) { + if (dec_exp == 0 || num == (mp_large_float_t)(0.0)) { + return num; + } + + #if MICROPY_FLOAT_FORMAT_IMPL == MICROPY_FLOAT_FORMAT_IMPL_EXACT + + // If the assert below fails, it means you have chosen MICROPY_FLOAT_FORMAT_IMPL_EXACT + // manually on a platform where `larger floats` are not supported, which would + // result in inexact conversions. To fix this issue, change your `mpconfigport.h` + // and select MICROPY_FLOAT_FORMAT_IMPL_APPROX instead + assert(sizeof(mp_large_float_t) > sizeof(mp_float_t)); + + // Perform power using simple multiplications, to avoid + // dependency to higher-precision pow() function + int neg_exp = (dec_exp < 0); + if (neg_exp) { + dec_exp = -dec_exp; + } + mp_large_float_t res = num; + mp_large_float_t expo = (mp_large_float_t)10.0; + while (dec_exp) { + if (dec_exp & 1) { + if (neg_exp) { + res /= expo; + } else { + res *= expo; + } + } + dec_exp >>= 1; + if (dec_exp) { + expo *= expo; + } + } + return res; + + #else + // MICROPY_FLOAT_FORMAT_IMPL != MICROPY_FLOAT_FORMAT_IMPL_EXACT + + mp_float_union_t res = {num}; + // Multiply first by (2.0 ** dec_exp) via the exponent + // - this will ensure that the result of `pow()` is always in mp_float_t range + // when the result is expected to be in mp_float_t range (e.g. during format) + // - we don't need to care about p.exp overflow, as (5.0 ** dec_exp) will anyway + // force the final result toward the proper edge if needed (0.0 or inf) + res.p.exp += dec_exp; + // Use positive exponents when they are more precise then negative + if (dec_exp < 0 && dec_exp >= -MAX_EXACT_POWER_OF_5) { + res.f /= MICROPY_FLOAT_C_FUN(pow)(5, -dec_exp); + } else { + res.f *= MICROPY_FLOAT_C_FUN(pow)(5, dec_exp); + } + return (mp_large_float_t)res.f; + + #endif +} + + // Break out inner digit accumulation routine to ease trailing zero deferral. -static mp_float_uint_t accept_digit(mp_float_uint_t p_mantissa, unsigned int dig, int *p_exp_extra, int in) { +static mp_large_float_uint_t accept_digit(mp_large_float_uint_t p_mantissa, unsigned int dig, int *p_exp_extra, int in) { // Core routine to ingest an additional digit. if (p_mantissa < MANTISSA_MAX) { // dec_val won't overflow so keep accumulating @@ -216,6 +301,85 @@ static mp_float_uint_t accept_digit(mp_float_uint_t p_mantissa, unsigned int dig return p_mantissa; } } + +// Helper to parse an unsigned decimal number into a mp_float_t +const char *mp_parse_float_internal(const char *str, size_t len, mp_float_t *res) { + const char *top = str + len; + + parse_dec_in_t in = PARSE_DEC_IN_INTG; + bool exp_neg = false; + mp_large_float_uint_t mantissa = 0; + int exp_val = 0; + int exp_extra = 0; + int trailing_zeros_intg = 0, trailing_zeros_frac = 0; + while (str < top) { + unsigned int dig = *str++; + if ('0' <= dig && dig <= '9') { + dig -= '0'; + if (in == PARSE_DEC_IN_EXP) { + // don't overflow exp_val when adding next digit, instead just truncate + // it and the resulting float will still be correct, either inf or 0.0 + // (use INT_MAX/2 to allow adding exp_extra at the end without overflow) + if (exp_val < (INT_MAX / 2 - 9) / 10) { + exp_val = 10 * exp_val + dig; + } + } else { + if (dig == 0 || mantissa >= MANTISSA_MAX) { + // Defer treatment of zeros in fractional part. If nothing comes afterwards, ignore them. + // Also, once we reach MANTISSA_MAX, treat every additional digit as a trailing zero. + if (in == PARSE_DEC_IN_INTG) { + ++trailing_zeros_intg; + } else { + ++trailing_zeros_frac; + } + } else { + // Time to un-defer any trailing zeros. Intg zeros first. + while (trailing_zeros_intg) { + mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_INTG); + --trailing_zeros_intg; + } + while (trailing_zeros_frac) { + mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_FRAC); + --trailing_zeros_frac; + } + mantissa = accept_digit(mantissa, dig, &exp_extra, in); + } + } + } else if (in == PARSE_DEC_IN_INTG && dig == '.') { + in = PARSE_DEC_IN_FRAC; + } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) { + in = PARSE_DEC_IN_EXP; + if (str < top) { + if (str[0] == '+') { + str++; + } else if (str[0] == '-') { + str++; + exp_neg = true; + } + } + if (str == top) { + return NULL; + } + } else if (dig == '_') { + continue; + } else { + // unknown character + str--; + break; + } + } + + // work out the exponent + if (exp_neg) { + exp_val = -exp_val; + } + exp_val += exp_extra + trailing_zeros_intg; + + // At this point, we just need to multiply the mantissa by its base 10 exponent. + *res = (mp_float_t)mp_decimal_exp(mantissa, exp_val); + + return str; +} #endif // MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_COMPLEX @@ -253,111 +417,23 @@ parse_start:; const char *str_val_start = str; // determine what the string is - if (str < top && (str[0] | 0x20) == 'i') { - // string starts with 'i', should be 'inf' or 'infinity' (case insensitive) - if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') { - // inf - str += 3; - dec_val = (mp_float_t)INFINITY; - if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') { - // infinity - str += 5; - } - } - } else if (str < top && (str[0] | 0x20) == 'n') { - // string starts with 'n', should be 'nan' (case insensitive) - if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') { - // NaN - str += 3; - dec_val = MICROPY_FLOAT_C_FUN(nan)(""); + if (str + 2 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') { + // 'inf' or 'infinity' (case insensitive) + str += 3; + dec_val = (mp_float_t)INFINITY; + if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') { + // infinity + str += 5; } + } else if (str + 2 < top && (str[0] | 0x20) == 'n' && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') { + // 'nan' (case insensitive) + str += 3; + dec_val = MICROPY_FLOAT_C_FUN(nan)(""); } else { // string should be a decimal number - parse_dec_in_t in = PARSE_DEC_IN_INTG; - bool exp_neg = false; - mp_float_uint_t mantissa = 0; - int exp_val = 0; - int exp_extra = 0; - int trailing_zeros_intg = 0, trailing_zeros_frac = 0; - while (str < top) { - unsigned int dig = *str++; - if ('0' <= dig && dig <= '9') { - dig -= '0'; - if (in == PARSE_DEC_IN_EXP) { - // don't overflow exp_val when adding next digit, instead just truncate - // it and the resulting float will still be correct, either inf or 0.0 - // (use INT_MAX/2 to allow adding exp_extra at the end without overflow) - if (exp_val < (INT_MAX / 2 - 9) / 10) { - exp_val = 10 * exp_val + dig; - } - } else { - if (dig == 0 || mantissa >= MANTISSA_MAX) { - // Defer treatment of zeros in fractional part. If nothing comes afterwards, ignore them. - // Also, once we reach MANTISSA_MAX, treat every additional digit as a trailing zero. - if (in == PARSE_DEC_IN_INTG) { - ++trailing_zeros_intg; - } else { - ++trailing_zeros_frac; - } - } else { - // Time to un-defer any trailing zeros. Intg zeros first. - while (trailing_zeros_intg) { - mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_INTG); - --trailing_zeros_intg; - } - while (trailing_zeros_frac) { - mantissa = accept_digit(mantissa, 0, &exp_extra, PARSE_DEC_IN_FRAC); - --trailing_zeros_frac; - } - mantissa = accept_digit(mantissa, dig, &exp_extra, in); - } - } - } else if (in == PARSE_DEC_IN_INTG && dig == '.') { - in = PARSE_DEC_IN_FRAC; - } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) { - in = PARSE_DEC_IN_EXP; - if (str < top) { - if (str[0] == '+') { - str++; - } else if (str[0] == '-') { - str++; - exp_neg = true; - } - } - if (str == top) { - goto value_error; - } - } else if (dig == '_') { - continue; - } else { - // unknown character - str--; - break; - } - } - - // work out the exponent - if (exp_neg) { - exp_val = -exp_val; - } - - // apply the exponent, making sure it's not a subnormal value - exp_val += exp_extra + trailing_zeros_intg; - dec_val = (mp_float_t)mantissa; - if (exp_val < SMALL_NORMAL_EXP) { - exp_val -= SMALL_NORMAL_EXP; - dec_val *= SMALL_NORMAL_VAL; - } - - // At this point, we need to multiply the mantissa by its base 10 exponent. If possible, - // we would rather manipulate numbers that have an exact representation in IEEE754. It - // turns out small positive powers of 10 do, whereas small negative powers of 10 don't. - // So in that case, we'll yield a division of exact values rather than a multiplication - // of slightly erroneous values. - if (exp_val < 0 && exp_val >= -EXACT_POWER_OF_10) { - dec_val /= MICROPY_FLOAT_C_FUN(pow)(10, -exp_val); - } else { - dec_val *= MICROPY_FLOAT_C_FUN(pow)(10, exp_val); + str = mp_parse_float_internal(str, top - str, &dec_val); + if (!str) { + goto value_error; } } diff --git a/py/parsenum.h b/py/parsenum.h index f444632d230..d532cb194a5 100644 --- a/py/parsenum.h +++ b/py/parsenum.h @@ -34,6 +34,11 @@ mp_obj_t mp_parse_num_integer(const char *restrict str, size_t len, int base, mp_lexer_t *lex); +#if MICROPY_PY_BUILTINS_FLOAT +mp_large_float_t mp_decimal_exp(mp_large_float_t num, int dec_exp); +const char *mp_parse_float_internal(const char *str, size_t len, mp_float_t *res); +#endif + #if MICROPY_PY_BUILTINS_COMPLEX mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool force_complex, mp_lexer_t *lex); diff --git a/py/persistentcode.c b/py/persistentcode.c index 93f4c33deb4..5c3de3174bc 100644 --- a/py/persistentcode.c +++ b/py/persistentcode.c @@ -63,6 +63,10 @@ typedef struct _bytecode_prelude_t { uint code_info_size; } bytecode_prelude_t; +#if MICROPY_EMIT_RV32 +#include "py/asmrv32.h" +#endif + #endif // MICROPY_PERSISTENT_CODE_LOAD || MICROPY_PERSISTENT_CODE_SAVE #if MICROPY_PERSISTENT_CODE_LOAD @@ -72,6 +76,8 @@ typedef struct _bytecode_prelude_t { static int read_byte(mp_reader_t *reader); static size_t read_uint(mp_reader_t *reader); +#if MICROPY_EMIT_MACHINE_CODE + #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA // An mp_obj_list_t that tracks native text/BSS/rodata to prevent the GC from reclaiming them. @@ -86,8 +92,6 @@ static void track_root_pointer(void *ptr) { #endif -#if MICROPY_EMIT_MACHINE_CODE - typedef struct _reloc_info_t { mp_reader_t *reader; mp_module_context_t *context; @@ -422,15 +426,17 @@ static mp_raw_code_t *load_raw_code(mp_reader_t *reader, mp_module_context_t *co // Relocate and commit code to executable address space reloc_info_t ri = {reader, context, rodata, bss}; + #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA + if (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) { + // Track the function data memory so it's not reclaimed by the GC. + track_root_pointer(fun_data); + } + #endif #if defined(MP_PLAT_COMMIT_EXEC) void *opt_ri = (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) ? &ri : NULL; fun_data = MP_PLAT_COMMIT_EXEC(fun_data, fun_data_len, opt_ri); #else if (native_scope_flags & MP_SCOPE_FLAG_VIPERRELOC) { - #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA - // Track the function data memory so it's not reclaimed by the GC. - track_root_pointer(fun_data); - #endif // Do the relocations. mp_native_relocate(&ri, fun_data, (uintptr_t)fun_data); } @@ -480,7 +486,7 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { || header[3] > MP_SMALL_INT_BITS) { mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); } - if (MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE) { + if (arch != MP_NATIVE_ARCH_NONE) { if (!MPY_FEATURE_ARCH_TEST(arch)) { if (MPY_FEATURE_ARCH_TEST(MP_NATIVE_ARCH_NONE)) { // On supported ports this can be resolved by enabling feature, eg @@ -492,6 +498,23 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { } } + size_t arch_flags = 0; + if (MPY_FEATURE_ARCH_FLAGS_TEST(header[2])) { + #if MICROPY_EMIT_RV32 + arch_flags = read_uint(reader); + + if (MPY_FEATURE_ARCH_TEST(MP_NATIVE_ARCH_RV32IMC)) { + if ((arch_flags & (size_t)asm_rv32_allowed_extensions()) != arch_flags) { + mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); + } + } else + #endif + { + (void)arch_flags; + mp_raise_ValueError(MP_ERROR_TEXT("incompatible .mpy file")); + } + } + size_t n_qstr = read_uint(reader); size_t n_obj = read_uint(reader); mp_module_context_alloc_tables(cm->context, n_qstr, n_obj); @@ -513,6 +536,7 @@ void mp_raw_code_load(mp_reader_t *reader, mp_compiled_module_t *cm) { cm->has_native = MPY_FEATURE_DECODE_ARCH(header[2]) != MP_NATIVE_ARCH_NONE; cm->n_qstr = n_qstr; cm->n_obj = n_obj; + cm->arch_flags = arch_flags; #endif // Deregister exception handler and close the reader. @@ -682,7 +706,7 @@ void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) { byte header[4] = { 'C', MPY_VERSION, - cm->has_native ? MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC) : 0, + (cm->arch_flags != 0 ? MPY_FEATURE_ARCH_FLAGS : 0) | (cm->has_native ? MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH_DYNAMIC) : 0), #if MICROPY_DYNAMIC_COMPILER mp_dynamic_compiler.small_int_bits, #else @@ -691,6 +715,10 @@ void mp_raw_code_save(mp_compiled_module_t *cm, mp_print_t *print) { }; mp_print_bytes(print, header, sizeof(header)); + if (cm->arch_flags) { + mp_print_uint(print, cm->arch_flags); + } + // Number of entries in constant table. mp_print_uint(print, cm->n_qstr); mp_print_uint(print, cm->n_obj); @@ -769,7 +797,7 @@ static void bit_vector_clear(bit_vector_t *self) { static bool bit_vector_is_set(bit_vector_t *self, size_t index) { const size_t bits_size = sizeof(*self->bits) * MP_BITS_PER_BYTE; return index / bits_size < self->alloc - && (self->bits[index / bits_size] & (1 << (index % bits_size))) != 0; + && (self->bits[index / bits_size] & ((uintptr_t)1 << (index % bits_size))) != 0; } static void bit_vector_set(bit_vector_t *self, size_t index) { @@ -780,7 +808,7 @@ static void bit_vector_set(bit_vector_t *self, size_t index) { self->bits = m_renew(uintptr_t, self->bits, self->alloc, new_alloc); self->alloc = new_alloc; } - self->bits[index / bits_size] |= 1 << (index % bits_size); + self->bits[index / bits_size] |= (uintptr_t)1 << (index % bits_size); } typedef struct _mp_opcode_t { diff --git a/py/persistentcode.h b/py/persistentcode.h index 46b474e57f7..85668e608c8 100644 --- a/py/persistentcode.h +++ b/py/persistentcode.h @@ -50,7 +50,7 @@ // Macros to encode/decode native architecture to/from the feature byte #define MPY_FEATURE_ENCODE_ARCH(arch) ((arch) << 2) -#define MPY_FEATURE_DECODE_ARCH(feat) ((feat) >> 2) +#define MPY_FEATURE_DECODE_ARCH(feat) (((feat) >> 2) & 0x2F) // Define the host architecture #if MICROPY_EMIT_X86 @@ -90,6 +90,10 @@ #define MPY_FILE_HEADER_INT (MPY_VERSION \ | (MPY_FEATURE_ENCODE_SUB_VERSION(MPY_SUB_VERSION) | MPY_FEATURE_ENCODE_ARCH(MPY_FEATURE_ARCH)) << 8) +// Architecture-specific flags are present in the .mpy file +#define MPY_FEATURE_ARCH_FLAGS (0x40) +#define MPY_FEATURE_ARCH_FLAGS_TEST(x) (((x) & MPY_FEATURE_ARCH_FLAGS) == MPY_FEATURE_ARCH_FLAGS) + enum { MP_NATIVE_ARCH_NONE = 0, MP_NATIVE_ARCH_X86, @@ -103,6 +107,7 @@ enum { MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN, MP_NATIVE_ARCH_RV32IMC, + MP_NATIVE_ARCH_RV64IMC, MP_NATIVE_ARCH_DEBUG, // this entry should always be last }; diff --git a/py/profile.c b/py/profile.c index 397d0291f9f..b5a0c54728c 100644 --- a/py/profile.c +++ b/py/profile.c @@ -80,7 +80,7 @@ static void frame_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t "", frame, MP_CODE_QSTR_MAP(code->context, 0), - frame->lineno, + (int)frame->lineno, MP_CODE_QSTR_MAP(code->context, prelude->qstr_block_name_idx) ); } diff --git a/py/py.cmake b/py/py.cmake index 6c180ae53e6..b99d2d24b5d 100644 --- a/py/py.cmake +++ b/py/py.cmake @@ -58,6 +58,7 @@ set(MICROPY_SOURCE_PY ${MICROPY_PY_DIR}/mpz.c ${MICROPY_PY_DIR}/nativeglue.c ${MICROPY_PY_DIR}/nlr.c + ${MICROPY_PY_DIR}/nlraarch64.c ${MICROPY_PY_DIR}/nlrmips.c ${MICROPY_PY_DIR}/nlrpowerpc.c ${MICROPY_PY_DIR}/nlrrv32.c diff --git a/py/py.mk b/py/py.mk index c05327bf81d..71b44f84d65 100644 --- a/py/py.mk +++ b/py/py.mk @@ -289,7 +289,7 @@ $(HEADER_BUILD)/compressed_translations.generated.h: $(PY_SRC)/maketranslationda PY_CORE_O += $(PY_BUILD)/translations-$(TRANSLATION).o # build a list of registered modules for py/objmodule.c. -$(HEADER_BUILD)/moduledefs.h: $(HEADER_BUILD)/moduledefs.collected +$(HEADER_BUILD)/moduledefs.h: $(HEADER_BUILD)/moduledefs.collected $(PY_SRC)/makemoduledefs.py @$(ECHO) "GEN $@" $(Q)$(PYTHON) $(PY_SRC)/makemoduledefs.py $< > $@ diff --git a/py/repl.c b/py/repl.c index c9a20305c79..bbfdd2ea6a6 100644 --- a/py/repl.c +++ b/py/repl.c @@ -181,8 +181,11 @@ static bool test_qstr(mp_obj_t obj, qstr name) { return dest[0] != MP_OBJ_NULL; } else { // try builtin module - return mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP) || - mp_map_lookup((mp_map_t *)&mp_builtin_extensible_module_map, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP); + return mp_map_lookup((mp_map_t *)&mp_builtin_module_map, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP) + #if MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES + || mp_map_lookup((mp_map_t *)&mp_builtin_extensible_module_map, MP_OBJ_NEW_QSTR(name), MP_MAP_LOOKUP) + #endif + ; } } @@ -237,6 +240,10 @@ static void print_completions(const mp_print_t *print, for (qstr q = q_first; q <= q_last; ++q) { size_t d_len; const char *d_str = (const char *)qstr_data(q, &d_len); + // filter out words that begin with underscore unless there's already a partial match + if (s_len == 0 && d_str[0] == '_') { + continue; + } if (s_len <= d_len && strncmp(s_start, d_str, s_len) == 0) { if (test_qstr(obj, q)) { int gap = (line_len + WORD_SLOT_LEN - 1) / WORD_SLOT_LEN * WORD_SLOT_LEN - line_len; diff --git a/py/runtime.c b/py/runtime.c index 9def98380fa..0b62500cc2a 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -134,7 +134,7 @@ void mp_init(void) { MP_STATE_VM(mp_module_builtins_override_dict) = NULL; #endif - #if MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA + #if MICROPY_EMIT_MACHINE_CODE && (MICROPY_PERSISTENT_CODE_TRACK_FUN_DATA || MICROPY_PERSISTENT_CODE_TRACK_BSS_RODATA) MP_STATE_VM(persistent_code_root_pointers) = MP_OBJ_NULL; #endif @@ -446,7 +446,7 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs // Operations that can overflow: // + result always fits in mp_int_t, then handled by SMALL_INT check // - result always fits in mp_int_t, then handled by SMALL_INT check - // * checked explicitly + // * checked explicitly for fit in mp_int_t, then handled by SMALL_INT check // / if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check // % if lhs=MIN and rhs=-1; result always fits in mp_int_t, then handled by SMALL_INT check // << checked explicitly @@ -505,30 +505,16 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs break; case MP_BINARY_OP_MULTIPLY: case MP_BINARY_OP_INPLACE_MULTIPLY: { - - // If long long type exists and is larger than mp_int_t, then - // we can use the following code to perform overflow-checked multiplication. - // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow. - #if 0 - // compute result using long long precision - long long res = (long long)lhs_val * (long long)rhs_val; - if (res > MP_SMALL_INT_MAX || res < MP_SMALL_INT_MIN) { - // result overflowed SMALL_INT, so return higher precision integer - return mp_obj_new_int_from_ll(res); - } else { - // use standard precision - lhs_val = (mp_int_t)res; - } - #endif - - if (mp_small_int_mul_overflow(lhs_val, rhs_val)) { + mp_int_t int_res; + if (mp_mul_mp_int_t_overflow(lhs_val, rhs_val, &int_res)) { // use higher precision lhs = mp_obj_new_int_from_ll(lhs_val); goto generic_binary_op; } else { // use standard precision - return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val); + lhs_val = int_res; } + break; } case MP_BINARY_OP_FLOOR_DIVIDE: case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE: @@ -568,19 +554,19 @@ mp_obj_t MICROPY_WRAP_MP_BINARY_OP(mp_binary_op)(mp_binary_op_t op, mp_obj_t lhs mp_int_t ans = 1; while (rhs_val > 0) { if (rhs_val & 1) { - if (mp_small_int_mul_overflow(ans, lhs_val)) { + if (mp_mul_mp_int_t_overflow(ans, lhs_val, &ans)) { goto power_overflow; } - ans *= lhs_val; } if (rhs_val == 1) { break; } rhs_val /= 2; - if (mp_small_int_mul_overflow(lhs_val, lhs_val)) { + mp_int_t int_res; + if (mp_mul_mp_int_t_overflow(lhs_val, lhs_val, &int_res)) { goto power_overflow; } - lhs_val *= lhs_val; + lhs_val = int_res; } lhs_val = ans; } @@ -976,7 +962,7 @@ mp_obj_t mp_call_method_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_ob // unpacked items are stored in reverse order into the array pointed to by items // CIRCUITPY-CHANGE: noline -void __attribute__((noinline, )) mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { +MP_NOINLINE void mp_unpack_sequence(mp_obj_t seq_in, size_t num, mp_obj_t *items) { size_t seq_len; if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { mp_obj_t *seq_items; @@ -1301,6 +1287,19 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("type object '%q' has no attribute '%q'"), ((mp_obj_type_t *)MP_OBJ_TO_PTR(base))->name, attr); + #if MICROPY_MODULE___ALL__ && MICROPY_ERROR_REPORTING >= MICROPY_ERROR_REPORTING_DETAILED + } else if (mp_obj_is_type(base, &mp_type_module)) { + // report errors in __all__ as done by CPython + mp_obj_t dest_name[2]; + qstr module_name = MP_QSTR_; + mp_load_method_maybe(base, MP_QSTR___name__, dest_name); + if (mp_obj_is_qstr(dest_name[0])) { + module_name = mp_obj_str_get_qstr(dest_name[0]); + } + mp_raise_msg_varg(&mp_type_AttributeError, + MP_ERROR_TEXT("module '%q' has no attribute '%q'"), + module_name, attr); + #endif } else { mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("'%s' object has no attribute '%q'"), @@ -1619,7 +1618,7 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { // build args array mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(name); - args[1] = mp_const_none; // TODO should be globals + args[1] = MP_OBJ_FROM_PTR(mp_globals_get()); // globals of the current context args[2] = mp_const_none; // TODO should be locals args[3] = fromlist; args[4] = level; @@ -1639,20 +1638,17 @@ mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { } // CIRCUITPY-CHANGE: noinline -mp_obj_t __attribute__((noinline, )) mp_import_from(mp_obj_t module, qstr name) { +MP_NOINLINE mp_obj_t mp_import_from(mp_obj_t module, qstr name) { DEBUG_printf("import from %p %s\n", module, qstr_str(name)); mp_obj_t dest[2]; mp_load_method_maybe(module, name, dest); - if (dest[1] != MP_OBJ_NULL) { - // Hopefully we can't import bound method from an object - import_error: - mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("can't import name %q"), name); - } - - if (dest[0] != MP_OBJ_NULL) { + // Importing a bound method from a class instance. + return mp_obj_new_bound_meth(dest[0], dest[1]); + } else if (dest[0] != MP_OBJ_NULL) { + // Importing a function or attribute. return dest[0]; } @@ -1685,13 +1681,36 @@ mp_obj_t __attribute__((noinline, )) mp_import_from(mp_obj_t module, qstr name) goto import_error; #endif + +import_error: + mp_raise_msg_varg(&mp_type_ImportError, MP_ERROR_TEXT("can't import name %q"), name); } void mp_import_all(mp_obj_t module) { DEBUG_printf("import all %p\n", module); - // TODO: Support __all__ mp_map_t *map = &mp_obj_module_get_globals(module)->map; + + #if MICROPY_MODULE___ALL__ + mp_map_elem_t *elem = mp_map_lookup(map, MP_OBJ_NEW_QSTR(MP_QSTR___all__), MP_MAP_LOOKUP); + if (elem != NULL) { + // When __all__ is defined, we must explicitly load all specified + // symbols, possibly invoking the module __getattr__ function + size_t len; + mp_obj_t *items; + mp_obj_get_array(elem->value, &len, &items); + for (size_t i = 0; i < len; i++) { + qstr qname = mp_obj_str_get_qstr(items[i]); + mp_obj_t dest[2]; + mp_load_method(module, qname, dest); + mp_store_name(qname, dest[0]); + } + return; + } + #endif + + // By default, the set of public names includes all names found in the module's + // namespace which do not begin with an underscore character ('_') for (size_t i = 0; i < map->alloc; i++) { if (mp_map_slot_is_filled(map, i)) { // Entry in module global scope may be generated programmatically @@ -1747,7 +1766,7 @@ mp_obj_t mp_parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t parse_i #endif // MICROPY_ENABLE_COMPILER // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void m_malloc_fail(size_t num_bytes) { +MP_COLD MP_NORETURN void m_malloc_fail(size_t num_bytes) { DEBUG_printf("memory allocation failed, allocating %u bytes\n", (uint)num_bytes); #if MICROPY_ENABLE_GC if (gc_is_locked()) { @@ -1761,29 +1780,29 @@ NORETURN MP_COLD void m_malloc_fail(size_t num_bytes) { #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_type(const mp_obj_type_t *exc_type) { +MP_COLD MP_NORETURN void mp_raise_type(const mp_obj_type_t *exc_type) { nlr_raise(mp_obj_new_exception(exc_type)); } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_ValueError_no_msg(void) { +MP_COLD MP_NORETURN void mp_raise_ValueError_no_msg(void) { mp_raise_type(&mp_type_ValueError); } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_TypeError_no_msg(void) { +MP_COLD MP_NORETURN void mp_raise_TypeError_no_msg(void) { mp_raise_type(&mp_type_TypeError); } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_NotImplementedError_no_msg(void) { +MP_COLD MP_NORETURN void mp_raise_NotImplementedError_no_msg(void) { mp_raise_type(&mp_type_NotImplementedError); } #else // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg) { if (msg == NULL) { nlr_raise(mp_obj_new_exception(exc_type)); } else { @@ -1792,24 +1811,24 @@ NORETURN MP_COLD void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_t } // CIRCUITPY-CHANGE: new function for use below. -NORETURN MP_COLD void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list argptr) { +MP_COLD MP_NORETURN void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list argptr) { mp_obj_t exception = mp_obj_new_exception_msg_vlist(exc_type, fmt, argptr); nlr_raise(exception); } // CIRCUITPY-CHANGE: MP_COLD and use mp_raise_msg_vlist() -NORETURN MP_COLD void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(exc_type, fmt, argptr); va_end(argptr); } -NORETURN MP_COLD void mp_raise_ValueError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_ValueError, msg); } -NORETURN MP_COLD void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg) { +MP_COLD MP_NORETURN void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg) { if (msg == NULL) { nlr_raise(mp_obj_new_exception(exc_type)); } else { @@ -1818,17 +1837,17 @@ NORETURN MP_COLD void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_AttributeError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_AttributeError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_AttributeError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_RuntimeError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_RuntimeError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_RuntimeError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_RuntimeError, fmt, argptr); @@ -1836,17 +1855,17 @@ NORETURN MP_COLD void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_ImportError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_ImportError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_ImportError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_IndexError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_IndexError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_IndexError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_IndexError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_IndexError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_IndexError, fmt, argptr); @@ -1854,7 +1873,7 @@ NORETURN MP_COLD void mp_raise_IndexError_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_ValueError, fmt, argptr); @@ -1862,12 +1881,12 @@ NORETURN MP_COLD void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_TypeError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_TypeError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_TypeError, fmt, argptr); @@ -1875,12 +1894,12 @@ NORETURN MP_COLD void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_OSError_msg(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_OSError_msg(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_OSError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) { +MP_COLD MP_NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) { mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(errno_), str, @@ -1889,7 +1908,7 @@ NORETURN MP_COLD void mp_raise_OSError_errno_str(int errno_, mp_obj_t str) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_OSError, fmt, argptr); @@ -1897,21 +1916,21 @@ NORETURN MP_COLD void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...) { } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_ConnectionError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_ConnectionError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_ConnectionError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_BrokenPipeError(void) { +MP_COLD MP_NORETURN void mp_raise_BrokenPipeError(void) { mp_raise_type_arg(&mp_type_BrokenPipeError, MP_OBJ_NEW_SMALL_INT(MP_EPIPE)); } -NORETURN MP_COLD void mp_raise_NotImplementedError(mp_rom_error_text_t msg) { +MP_COLD MP_NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_NotImplementedError, fmt, argptr); @@ -1919,7 +1938,7 @@ NORETURN MP_COLD void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...) { +MP_COLD MP_NORETURN void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_raise_msg_vlist(&mp_type_OverflowError, fmt, argptr); @@ -1927,11 +1946,11 @@ NORETURN MP_COLD void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...) } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg) { +MP_COLD MP_NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg) { nlr_raise(mp_obj_new_exception_arg1(exc_type, arg)); } -NORETURN void mp_raise_StopIteration(mp_obj_t arg) { +MP_NORETURN void mp_raise_StopIteration(mp_obj_t arg) { if (arg == MP_OBJ_NULL) { mp_raise_type(&mp_type_StopIteration); } else { @@ -1939,7 +1958,7 @@ NORETURN void mp_raise_StopIteration(mp_obj_t arg) { } } -NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg) { +MP_NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE (void)arg; mp_raise_TypeError(MP_ERROR_TEXT("can't convert to int")); @@ -1950,12 +1969,12 @@ NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg) { } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_OSError(int errno_) { +MP_COLD MP_NORETURN void mp_raise_OSError(int errno_) { mp_raise_type_arg(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(errno_)); } // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_OSError_with_filename(int errno_, const char *filename) { +MP_COLD MP_NORETURN void mp_raise_OSError_with_filename(int errno_, const char *filename) { vstr_t vstr; vstr_init(&vstr, 32); vstr_printf(&vstr, "can't open %s", filename); @@ -1965,13 +1984,12 @@ NORETURN MP_COLD void mp_raise_OSError_with_filename(int errno_, const char *fil } // CIRCUITPY-CHANGE: added -NORETURN MP_COLD void mp_raise_ZeroDivisionError(void) { +MP_COLD MP_NORETURN void mp_raise_ZeroDivisionError(void) { mp_raise_msg(&mp_type_ZeroDivisionError, MP_ERROR_TEXT("division by zero")); } #if MICROPY_STACK_CHECK || MICROPY_ENABLE_PYSTACK // CIRCUITPY-CHANGE: MP_COLD -NORETURN MP_COLD void mp_raise_recursion_depth(void) { +MP_COLD MP_NORETURN void mp_raise_recursion_depth(void) { mp_raise_RuntimeError(MP_ERROR_TEXT("maximum recursion depth exceeded")); } #endif -#endif diff --git a/py/runtime.h b/py/runtime.h index a2d69638ffc..8bdd1982b96 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -26,17 +26,12 @@ #ifndef MICROPY_INCLUDED_PY_RUNTIME_H #define MICROPY_INCLUDED_PY_RUNTIME_H -#include - #include "py/mpstate.h" #include "py/pystack.h" #include "py/cstack.h" -// CIRCUITPY-CHANGE -#include "supervisor/linker.h" -#include "supervisor/shared/translate/translate.h" - -// For use with mp_call_function_1_from_nlr_jump_callback. +// Initialize an nlr_jump_callback_node_call_function_1_t struct for use with +// nlr_push_jump_callback(&ctx.callback, mp_call_function_1_from_nlr_jump_callback); #define MP_DEFINE_NLR_JUMP_CALLBACK_FUNCTION_1(ctx, f, a) \ nlr_jump_callback_node_call_function_1_t ctx = { \ .func = (void (*)(void *))(f), \ @@ -58,6 +53,12 @@ typedef enum { MP_ARG_KW_ONLY = 0x200, } mp_arg_flag_t; +typedef enum { + MP_HANDLE_PENDING_CALLBACKS_ONLY, + MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS, + MP_HANDLE_PENDING_CALLBACKS_AND_CLEAR_EXCEPTIONS, +} mp_handle_pending_behaviour_t; + typedef union _mp_arg_val_t { bool u_bool; mp_int_t u_int; @@ -106,7 +107,14 @@ void mp_sched_keyboard_interrupt(void); #if MICROPY_ENABLE_VM_ABORT void mp_sched_vm_abort(void); #endif -void mp_handle_pending(bool raise_exc); + +void mp_handle_pending_internal(mp_handle_pending_behaviour_t behavior); + +static inline void mp_handle_pending(bool raise_exc) { + mp_handle_pending_internal(raise_exc ? + MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS : + MP_HANDLE_PENDING_CALLBACKS_AND_CLEAR_EXCEPTIONS); +} #if MICROPY_ENABLE_SCHEDULER void mp_sched_lock(void); @@ -134,7 +142,7 @@ void mp_event_wait_indefinite(void); void mp_event_wait_ms(mp_uint_t timeout_ms); // extra printing method specifically for mp_obj_t's which are integral type -int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, int base, int base_char, int flags, char fill, int width, int prec); +int mp_print_mp_int(const mp_print_t *print, mp_obj_t x, unsigned base, int base_char, int flags, char fill, int width, int prec); void mp_arg_check_num_sig(size_t n_args, size_t n_kw, uint32_t sig); static inline void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_min, size_t n_args_max, bool takes_kw) { @@ -142,11 +150,11 @@ static inline void mp_arg_check_num(size_t n_args, size_t n_kw, size_t n_args_mi } void mp_arg_parse_all(size_t n_pos, const mp_obj_t *pos, mp_map_t *kws, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); void mp_arg_parse_all_kw_array(size_t n_pos, size_t n_kw, const mp_obj_t *args, size_t n_allowed, const mp_arg_t *allowed, mp_arg_val_t *out_vals); -NORETURN void mp_arg_error_terse_mismatch(void); -NORETURN void mp_arg_error_unimpl_kw(void); +MP_NORETURN void mp_arg_error_terse_mismatch(void); +MP_NORETURN void mp_arg_error_unimpl_kw(void); // CIRCUITPY-CHANGE: arg validation routines -NORETURN void mp_arg_error_invalid(qstr arg_name); +MP_NORETURN void mp_arg_error_invalid(qstr arg_name); mp_int_t mp_arg_validate_int(mp_int_t i, mp_int_t required_i, qstr arg_name); mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name); mp_int_t mp_arg_validate_int_max(mp_int_t i, mp_int_t j, qstr arg_name); @@ -194,9 +202,16 @@ static inline void mp_thread_init_state(mp_state_thread_t *ts, size_t stack_size ts->gc_lock_depth = 0; // There are no pending jump callbacks or exceptions yet + ts->nlr_top = NULL; ts->nlr_jump_callback_top = NULL; ts->mp_pending_exception = MP_OBJ_NULL; + #if MICROPY_PY_SYS_SETTRACE + ts->prof_trace_callback = MP_OBJ_NULL; + ts->prof_callback_is_executing = false; + ts->current_code_state = NULL; + #endif + // If locals/globals are not given, inherit from main thread if (locals == NULL) { locals = mp_state_ctx.thread.dict_locals; @@ -274,10 +289,10 @@ mp_obj_t mp_import_from(mp_obj_t module, qstr name); void mp_import_all(mp_obj_t module); #if MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NONE -NORETURN void mp_raise_type(const mp_obj_type_t *exc_type); -NORETURN void mp_raise_ValueError_no_msg(void); -NORETURN void mp_raise_TypeError_no_msg(void); -NORETURN void mp_raise_NotImplementedError_no_msg(void); +MP_NORETURN void mp_raise_type(const mp_obj_type_t *exc_type); +MP_NORETURN void mp_raise_ValueError_no_msg(void); +MP_NORETURN void mp_raise_TypeError_no_msg(void); +MP_NORETURN void mp_raise_NotImplementedError_no_msg(void); #define mp_raise_msg(exc_type, msg) mp_raise_type(exc_type) #define mp_raise_msg_varg(exc_type, ...) mp_raise_type(exc_type) #define mp_raise_ValueError(msg) mp_raise_ValueError_no_msg() @@ -285,46 +300,46 @@ NORETURN void mp_raise_NotImplementedError_no_msg(void); #define mp_raise_NotImplementedError(msg) mp_raise_NotImplementedError_no_msg() #else #define mp_raise_type(exc_type) mp_raise_msg(exc_type, NULL) -NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg); -NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg); -NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg); -NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg); #endif // CIRCUITPY-CHANGE: new mp_raise routines -NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg); -NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg); -NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt +MP_NORETURN void mp_raise_type_arg(const mp_obj_type_t *exc_type, mp_obj_t arg); +MP_NORETURN void mp_raise_msg(const mp_obj_type_t *exc_type, mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_msg_varg(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt , ...); -NORETURN void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list argptr); +MP_NORETURN void mp_raise_msg_vlist(const mp_obj_type_t *exc_type, mp_rom_error_text_t fmt, va_list argptr); // Only use this string version in native mpy files. Otherwise, use the compressed string version. -NORETURN void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg); - -NORETURN void mp_raise_AttributeError(mp_rom_error_text_t msg); -NORETURN void mp_raise_BrokenPipeError(void); -NORETURN void mp_raise_ConnectionError(mp_rom_error_text_t msg); -NORETURN void mp_raise_ImportError(mp_rom_error_text_t msg); -NORETURN void mp_raise_IndexError(mp_rom_error_text_t msg); -NORETURN void mp_raise_IndexError_varg(mp_rom_error_text_t msg, ...); -NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg); -NORETURN void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str); -NORETURN void mp_raise_OSError(int errno_); -NORETURN void mp_raise_OSError_msg(mp_rom_error_text_t msg); -NORETURN void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_OSError_with_filename(int errno_, const char *filename); -NORETURN void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_recursion_depth(void); -NORETURN void mp_raise_RuntimeError(mp_rom_error_text_t msg); -NORETURN void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_StopIteration(mp_obj_t arg); -NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg); -NORETURN void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg); -NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg); -NORETURN void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_ZeroDivisionError(void); +MP_NORETURN void mp_raise_msg_str(const mp_obj_type_t *exc_type, const char *msg); + +MP_NORETURN void mp_raise_AttributeError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_BrokenPipeError(void); +MP_NORETURN void mp_raise_ConnectionError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_ImportError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_IndexError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_IndexError_varg(mp_rom_error_text_t msg, ...); +MP_NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_OSError_errno_str(int errno_, mp_obj_t str); +MP_NORETURN void mp_raise_OSError(int errno_); +MP_NORETURN void mp_raise_OSError_msg(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_OSError_msg_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_OSError_with_filename(int errno_, const char *filename); +MP_NORETURN void mp_raise_OverflowError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_recursion_depth(void); +MP_NORETURN void mp_raise_RuntimeError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_RuntimeError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_StopIteration(mp_obj_t arg); +MP_NORETURN void mp_raise_TypeError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_TypeError_int_conversion(mp_const_obj_t arg); +MP_NORETURN void mp_raise_ValueError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_ZeroDivisionError(void); #if MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG #undef mp_check_self diff --git a/py/runtime_utils.c b/py/runtime_utils.c index 98252c31220..33da558e30f 100644 --- a/py/runtime_utils.c +++ b/py/runtime_utils.c @@ -53,3 +53,59 @@ mp_obj_t mp_call_function_2_protected(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2 return MP_OBJ_NULL; } } + +#if !MICROPY_USE_GCC_MUL_OVERFLOW_INTRINSIC +bool mp_mul_ll_overflow(long long int x, long long int y, long long int *res) { + bool overflow; + + // Check for multiply overflow; see CERT INT32-C + if (x > 0) { // x is positive + if (y > 0) { // x and y are positive + overflow = (x > (LLONG_MAX / y)); + } else { // x positive, y nonpositive + overflow = (y < (LLONG_MIN / x)); + } // x positive, y nonpositive + } else { // x is nonpositive + if (y > 0) { // x is nonpositive, y is positive + overflow = (x < (LLONG_MIN / y)); + } else { // x and y are nonpositive + overflow = (x != 0 && y < (LLONG_MAX / x)); + } // End if x and y are nonpositive + } // End if x is nonpositive + + if (!overflow) { + *res = x * y; + } + + return overflow; +} + +bool mp_mul_mp_int_t_overflow(mp_int_t x, mp_int_t y, mp_int_t *res) { + // Check for multiply overflow; see CERT INT32-C + if (x > 0) { // x is positive + if (y > 0) { // x and y are positive + if (x > (MP_INT_MAX / y)) { + return true; + } + } else { // x positive, y nonpositive + if (y < (MP_INT_MIN / x)) { + return true; + } + } // x positive, y nonpositive + } else { // x is nonpositive + if (y > 0) { // x is nonpositive, y is positive + if (x < (MP_INT_MIN / y)) { + return true; + } + } else { // x and y are nonpositive + if (x != 0 && y < (MP_INT_MAX / x)) { + return true; + } + } // End if x and y are nonpositive + } // End if x is nonpositive + + // Result doesn't overflow + *res = x * y; + return false; +} +#endif diff --git a/py/scheduler.c b/py/scheduler.c index 92e5af6b31b..ee9cd96b331 100644 --- a/py/scheduler.c +++ b/py/scheduler.c @@ -97,17 +97,21 @@ static inline void mp_sched_run_pending(void) { #if MICROPY_SCHEDULER_STATIC_NODES // Run all pending C callbacks. - while (MP_STATE_VM(sched_head) != NULL) { - mp_sched_node_t *node = MP_STATE_VM(sched_head); - MP_STATE_VM(sched_head) = node->next; - if (MP_STATE_VM(sched_head) == NULL) { - MP_STATE_VM(sched_tail) = NULL; - } - mp_sched_callback_t callback = node->callback; - node->callback = NULL; - MICROPY_END_ATOMIC_SECTION(atomic_state); - callback(node); - atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + mp_sched_node_t *original_tail = MP_STATE_VM(sched_tail); + if (original_tail != NULL) { + mp_sched_node_t *node; + do { + node = MP_STATE_VM(sched_head); + MP_STATE_VM(sched_head) = node->next; + if (MP_STATE_VM(sched_head) == NULL) { + MP_STATE_VM(sched_tail) = NULL; + } + mp_sched_callback_t callback = node->callback; + node->callback = NULL; + MICROPY_END_ATOMIC_SECTION(atomic_state); + callback(node); + atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + } while (node != original_tail); // Don't execute any callbacks scheduled during this run } #endif @@ -218,24 +222,27 @@ MP_REGISTER_ROOT_POINTER(mp_sched_item_t sched_queue[MICROPY_SCHEDULER_DEPTH]); // Called periodically from the VM or from "waiting" code (e.g. sleep) to // process background tasks and pending exceptions (e.g. KeyboardInterrupt). -void mp_handle_pending(bool raise_exc) { +void mp_handle_pending_internal(mp_handle_pending_behaviour_t behavior) { + bool handle_exceptions = (behavior != MP_HANDLE_PENDING_CALLBACKS_ONLY); + bool raise_exceptions = (behavior == MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS); + // Handle pending VM abort. #if MICROPY_ENABLE_VM_ABORT - if (MP_STATE_VM(vm_abort) && mp_thread_is_main_thread()) { + if (handle_exceptions && MP_STATE_VM(vm_abort) && mp_thread_is_main_thread()) { MP_STATE_VM(vm_abort) = false; - if (raise_exc && nlr_get_abort() != NULL) { + if (raise_exceptions && nlr_get_abort() != NULL) { nlr_jump_abort(); } } #endif // Handle any pending exception. - if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) { + if (handle_exceptions && MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) { mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception); if (obj != MP_OBJ_NULL) { MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL; - if (raise_exc) { + if (raise_exceptions) { MICROPY_END_ATOMIC_SECTION(atomic_state); nlr_raise(obj); } diff --git a/py/showbc.c b/py/showbc.c index 6913d18c1ca..792fccd0133 100644 --- a/py/showbc.c +++ b/py/showbc.c @@ -144,17 +144,9 @@ void mp_bytecode_print(const mp_print_t *print, const mp_raw_code_t *rc, size_t mp_uint_t source_line = 1; mp_printf(print, " bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); for (const byte *ci = code_info; ci < line_info_top;) { - if ((ci[0] & 0x80) == 0) { - // 0b0LLBBBBB encoding - bc += ci[0] & 0x1f; - source_line += ci[0] >> 5; - ci += 1; - } else { - // 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) - bc += ci[0] & 0xf; - source_line += ((ci[0] << 4) & 0x700) | ci[1]; - ci += 2; - } + mp_code_lineinfo_t decoded = mp_bytecode_decode_lineinfo(&ci); + bc += decoded.bc_increment; + source_line += decoded.line_increment; mp_printf(print, " bc=" INT_FMT " line=" UINT_FMT "\n", bc, source_line); } } diff --git a/py/smallint.c b/py/smallint.c index aa542ca7bf2..eb99b58667a 100644 --- a/py/smallint.c +++ b/py/smallint.c @@ -26,32 +26,6 @@ #include "py/smallint.h" -bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y) { - // Check for multiply overflow; see CERT INT32-C - if (x > 0) { // x is positive - if (y > 0) { // x and y are positive - if (x > (MP_SMALL_INT_MAX / y)) { - return true; - } - } else { // x positive, y nonpositive - if (y < (MP_SMALL_INT_MIN / x)) { - return true; - } - } // x positive, y nonpositive - } else { // x is nonpositive - if (y > 0) { // x is nonpositive, y is positive - if (x < (MP_SMALL_INT_MIN / y)) { - return true; - } - } else { // x and y are nonpositive - if (x != 0 && y < (MP_SMALL_INT_MAX / x)) { - return true; - } - } // End if x and y are nonpositive - } // End if x is nonpositive - return false; -} - mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor) { // Python specs require that mod has same sign as second operand dividend %= divisor; diff --git a/py/smallint.h b/py/smallint.h index 584e0018d1b..ec5b0af3b28 100644 --- a/py/smallint.h +++ b/py/smallint.h @@ -68,7 +68,6 @@ // The number of bits in a MP_SMALL_INT including the sign bit. #define MP_SMALL_INT_BITS (MP_IMAX_BITS(MP_SMALL_INT_MAX) + 1) -bool mp_small_int_mul_overflow(mp_int_t x, mp_int_t y); mp_int_t mp_small_int_modulo(mp_int_t dividend, mp_int_t divisor); mp_int_t mp_small_int_floor_divide(mp_int_t num, mp_int_t denom); diff --git a/py/stream.c b/py/stream.c index fbf7fd878a1..520422cc92f 100644 --- a/py/stream.c +++ b/py/stream.c @@ -260,9 +260,14 @@ void mp_stream_write_adaptor(void *self, const char *buf, size_t len) { mp_stream_write(MP_OBJ_FROM_PTR(self), buf, len, MP_STREAM_RW_WRITE); } -static mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { +static mp_obj_t stream_readinto_write_generic(size_t n_args, const mp_obj_t *args, byte flags) { mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ); + mp_get_buffer_raise(args[1], &bufinfo, (flags & MP_STREAM_RW_WRITE) ? MP_BUFFER_READ : MP_BUFFER_WRITE); + + // CPython extension, allow optional maximum length and offset: + // - stream.operation(buf, max_len) + // - stream.operation(buf, off, max_len) + // Similar to https://docs.python.org/3/library/socket.html#socket.socket.recv_into size_t max_len = (size_t)-1; size_t off = 0; if (n_args == 3) { @@ -275,45 +280,31 @@ static mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { } } bufinfo.len -= off; - return mp_stream_write(args[0], (byte *)bufinfo.buf + off, MIN(bufinfo.len, max_len), MP_STREAM_RW_WRITE); + + // Perform the readinto or write operation. + return mp_stream_write(args[0], (byte *)bufinfo.buf + off, MIN(bufinfo.len, max_len), flags); +} + +static mp_obj_t stream_write_method(size_t n_args, const mp_obj_t *args) { + return stream_readinto_write_generic(n_args, args, MP_STREAM_RW_WRITE); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj, 2, 4, stream_write_method); -static mp_obj_t stream_write1_method(mp_obj_t self_in, mp_obj_t arg) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(arg, &bufinfo, MP_BUFFER_READ); - return mp_stream_write(self_in, bufinfo.buf, bufinfo.len, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE); +static mp_obj_t stream_write1_method(size_t n_args, const mp_obj_t *args) { + return stream_readinto_write_generic(n_args, args, MP_STREAM_RW_WRITE | MP_STREAM_RW_ONCE); } -MP_DEFINE_CONST_FUN_OBJ_2(mp_stream_write1_obj, stream_write1_method); +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write1_obj, 2, 4, stream_write1_method); static mp_obj_t stream_readinto(size_t n_args, const mp_obj_t *args) { - mp_buffer_info_t bufinfo; - mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_WRITE); - - // CPython extension: if 2nd arg is provided, that's max len to read, - // instead of full buffer. Similar to - // https://docs.python.org/3/library/socket.html#socket.socket.recv_into - mp_uint_t len = bufinfo.len; - if (n_args > 2) { - len = mp_obj_get_int(args[2]); - if (len > bufinfo.len) { - len = bufinfo.len; - } - } - - int error; - mp_uint_t out_sz = mp_stream_read_exactly(args[0], bufinfo.buf, len, &error); - if (error != 0) { - if (mp_is_nonblocking_error(error)) { - return mp_const_none; - } - mp_raise_OSError(error); - } else { - return MP_OBJ_NEW_SMALL_INT(out_sz); - } + return stream_readinto_write_generic(n_args, args, MP_STREAM_RW_READ); } MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj, 2, 3, stream_readinto); +static mp_obj_t stream_readinto1(size_t n_args, const mp_obj_t *args) { + return stream_readinto_write_generic(n_args, args, MP_STREAM_RW_READ | MP_STREAM_RW_ONCE); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto1_obj, 2, 3, stream_readinto1); + static mp_obj_t stream_readall(mp_obj_t self_in) { const mp_stream_p_t *stream_p = mp_get_stream(self_in); diff --git a/py/stream.h b/py/stream.h index 5e1cd5d4413..6e60e849b5f 100644 --- a/py/stream.h +++ b/py/stream.h @@ -87,10 +87,11 @@ typedef struct _mp_stream_p_t { MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_read1_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_readinto1_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_unbuffered_readline_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_unbuffered_readlines_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write_obj); -MP_DECLARE_CONST_FUN_OBJ_2(mp_stream_write1_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_write1_obj); MP_DECLARE_CONST_FUN_OBJ_1(mp_stream_close_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream___exit___obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream_seek_obj); diff --git a/py/vm.c b/py/vm.c index 6fd17782619..860aa36e397 100644 --- a/py/vm.c +++ b/py/vm.c @@ -205,6 +205,22 @@ static mp_obj_t get_active_exception(mp_exc_stack_t *exc_sp, mp_exc_stack_t *exc return MP_OBJ_NULL; } +#if MICROPY_PY_BUILTINS_SLICE +// This function is marked "no inline" so it doesn't increase the C stack usage of the main VM function. +MP_NOINLINE static mp_obj_t *build_slice_stack_allocated(byte op, mp_obj_t *sp, mp_obj_t step) { + mp_obj_t stop = sp[2]; + mp_obj_t start = sp[1]; + mp_obj_slice_t slice = { .base = { .type = &mp_type_slice }, .start = start, .stop = stop, .step = step }; + if (op == MP_BC_LOAD_SUBSCR) { + SET_TOP(mp_obj_subscr(TOP(), MP_OBJ_FROM_PTR(&slice), MP_OBJ_SENTINEL)); + } else { // MP_BC_STORE_SUBSCR + mp_obj_subscr(TOP(), MP_OBJ_FROM_PTR(&slice), sp[-1]); + sp -= 2; + } + return sp; +} +#endif + // fastn has items in reverse order (fastn[0] is local[0], fastn[-1] is local[1], etc) // sp points to bottom of stack which grows up // returns: @@ -871,9 +887,20 @@ unwind_jump:; // 3-argument slice includes step step = POP(); } - mp_obj_t stop = POP(); - mp_obj_t start = TOP(); - SET_TOP(mp_obj_new_slice(start, stop, step)); + if ((*ip == MP_BC_LOAD_SUBSCR || *ip == MP_BC_STORE_SUBSCR) + && (mp_obj_get_type(sp[-2])->flags & MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE)) { + // Fast path optimisation for when the BUILD_SLICE is immediately followed + // by a LOAD/STORE_SUBSCR for an accepting type, to avoid needing to allocate + // the slice on the heap. In some cases (e.g. a[1:3] = x) this can result + // in no allocations at all. We can't do this for instance types because + // the get/set/delattr implementation may keep a reference to the slice. + byte op = *ip++; + sp = build_slice_stack_allocated(op, sp - 2, step); + } else { + mp_obj_t stop = POP(); + mp_obj_t start = TOP(); + SET_TOP(mp_obj_new_slice(start, stop, step)); + } DISPATCH(); } #endif diff --git a/pyproject.toml b/pyproject.toml index 7003a6af9ae..e88137bb0f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,20 +1,29 @@ -# SPDX-FileCopyrightText: 2024 Scott Shawcroft for Adafruit Industries -# -# SPDX-License-Identifier: MIT - -[tool.setuptools_scm] -# can be empty if no extra settings are needed, presence enables setuptools-scm - -# Codespell settings copied from MicroPython +[tool.codespell] +count = "" +ignore-regex = '\b[A-Z]{3}\b' +# CIRCUITPY-CHANGE: aranges +ignore-words-list = "ans,asend,aranges,deques,dout,emac,extint,hsi,iput,mis,notin,numer,ser,shft,synopsys,technic,ure,curren" +quiet-level = 3 +skip = """ +*/build*,\ +./.git,\ +./drivers/cc3100,\ +./lib,\ +./ports/cc3200/FreeRTOS,\ +./ports/cc3200/bootmgr/sl,\ +./ports/cc3200/hal,\ +./ports/cc3200/simplelink,\ +./ports/cc3200/telnet,\ +./ports/esp32/managed_components,\ +./ports/nrf/drivers/bluetooth/s1*,\ +./ports/stm32/usbhost,\ +./tests,\ +ACKNOWLEDGEMENTS,\ +""" +# CIRCUITPY-CHANGES: additions and removals [tool.ruff] -target-version = "py37" - -line-length = 99 -# Exclude third-party code from linting and formatting. Ruff doesn't know how to ignore submodules. -# Exclude the following tests: -# repl_: not real python files -# viper_args: uses f(*) +# Exclude third-party code from linting and formatting extend-exclude = [ "extmod/ulab", "frozen", @@ -28,8 +37,6 @@ extend-exclude = [ "ports/silabs/gecko_sdk", "ports/silabs/tools/slc_cli_linux", "ports/stm/st_driver", - "tests/*/repl_*.py", - "tests/micropython/viper_args.py", "tools/adabot", "tools/bitmap_font", "tools/cc1", @@ -38,11 +45,27 @@ extend-exclude = [ "tools/python-semver", "tools/uf2", ] -# Exclude third-party code, and exclude the following tests: -# basics: needs careful attention before applying automatic formatting -format.exclude = [ "tests/basics/*.py" ] -lint.extend-select = [ "C9", "PLC" ] -lint.ignore = [ +# Include Python source files that don't end with .py +line-length = 99 +target-version = "py38" + +[tool.ruff.lint] +exclude = [ # Ruff finds Python SyntaxError in these files + "tests/cmdline/cmd_compile_only_error.py", + "tests/cmdline/repl_autocomplete.py", + "tests/cmdline/repl_autocomplete_underscore.py", + "tests/cmdline/repl_autoindent.py", + "tests/cmdline/repl_basic.py", + "tests/cmdline/repl_cont.py", + "tests/cmdline/repl_emacs_keys.py", + "tests/cmdline/repl_paste.py", + "tests/cmdline/repl_words_move.py", + "tests/feature_check/repl_emacs_check.py", + "tests/feature_check/repl_words_move_check.py", + "tests/micropython/viper_args.py", +] +extend-select = ["C9", "PLC"] +extend-ignore = [ "E401", "E402", "E722", @@ -51,35 +74,30 @@ lint.ignore = [ "F401", "F403", "F405", - "PLC1901", + "PLC0206", + "PLC0415", # conditional imports are common in MicroPython ] -# manifest.py files are evaluated with some global names pre-defined -lint.per-file-ignores."**/manifest.py" = [ "F821" ] -lint.per-file-ignores."ports/**/boards/**/manifest_*.py" = [ "F821" ] -# Exclude all tests from linting (does not apply to formatting). -lint.per-file-ignores."tests/**/*.py" = [ "ALL" ] -lint.mccabe.max-complexity = 40 +mccabe.max-complexity = 40 -[tool.codespell] -count = "" -ignore-regex = '\b[A-Z]{3}\b' -ignore-words-list = "ans,asend,aranges,deques,dout,emac,extint,hsi,iput,mis,notin,numer,ser,shft,synopsys,technic,ure,curren" -quiet-level = 3 -skip = """ -*/build*,\ -./.git,\ -./drivers/cc3100,\ -./lib,\ -./ports/cc3200/FreeRTOS,\ -./ports/cc3200/bootmgr/sl,\ -./ports/cc3200/hal,\ -./ports/cc3200/simplelink,\ -./ports/cc3200/telnet,\ -./ports/esp32/managed_components,\ -./ports/nrf/drivers/bluetooth/s1*,\ -./ports/stm32/usbhost,\ -./tests,\ -ACKNOWLEDGEMENTS,\ -""" +[tool.ruff.lint.per-file-ignores] +# Exclude all tests from linting. +"tests/**/*.py" = ["ALL"] +"ports/cc3200/tools/uniflash.py" = ["E711"] +# manifest.py files are evaluated with some global names pre-defined +"**/manifest.py" = ["F821"] +"ports/**/boards/**/manifest_*.py" = ["F821"] +# Uses assignment expressions. +"tests/cpydiff/syntax_assign_expr.py" = ["F821"] -# Ruff settings copied from MicroPython +[tool.ruff.format] +# Exclude third-party code, and exclude the following tests: +# basics: needs careful attention before applying automatic formatting +# repl_: not real python files +# viper_args: uses f(*) +exclude = [ + "tests/basics/*.py", + "tests/*/repl_*.py", + "tests/cmdline/cmd_compile_only_error.py", + "tests/micropython/test_normalize_newlines.py", + "tests/micropython/viper_args.py", +] diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c index 3bf8c1a2c9c..1ec9fd96e76 100644 --- a/shared-bindings/_bleio/__init__.c +++ b/shared-bindings/_bleio/__init__.c @@ -56,7 +56,7 @@ //| //| MP_DEFINE_BLEIO_EXCEPTION(BluetoothError, Exception) -NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t fmt, ...) { +MP_NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_BluetoothError, fmt, argptr); @@ -72,7 +72,7 @@ NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t fmt, ...) { //| //| MP_DEFINE_BLEIO_EXCEPTION(RoleError, bleio_BluetoothError) -NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg) { +MP_NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_bleio_RoleError, msg); } @@ -83,7 +83,7 @@ NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg) { //| //| MP_DEFINE_BLEIO_EXCEPTION(SecurityError, bleio_BluetoothError) -NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t fmt, ...) { +MP_NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_bleio_SecurityError, fmt, argptr); diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index f7428d2fb21..0c5a5fec06b 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -45,9 +45,9 @@ void common_hal_bleio_init(void); extern mp_obj_t bleio_set_adapter(mp_obj_t adapter_obj); -NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t msg, ...); -NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg); -NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t msg, ...); +MP_NORETURN void mp_raise_bleio_BluetoothError(mp_rom_error_text_t msg, ...); +MP_NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg); +MP_NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t msg, ...); bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void); void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); diff --git a/shared-bindings/adafruit_pixelbuf/PixelBuf.c b/shared-bindings/adafruit_pixelbuf/PixelBuf.c index cdffbfa627a..4144f086b98 100644 --- a/shared-bindings/adafruit_pixelbuf/PixelBuf.c +++ b/shared-bindings/adafruit_pixelbuf/PixelBuf.c @@ -24,7 +24,7 @@ #include "extmod/ulab/code/ndarray.h" #endif -static NORETURN void invalid_byteorder(void) { +static MP_NORETURN void invalid_byteorder(void) { mp_arg_error_invalid(MP_QSTR_byteorder); } diff --git a/shared-bindings/alarm/__init__.h b/shared-bindings/alarm/__init__.h index af92b381137..37bfd9c51b7 100644 --- a/shared-bindings/alarm/__init__.h +++ b/shared-bindings/alarm/__init__.h @@ -24,7 +24,7 @@ extern mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const // it will exit idle as if deep sleep was exited extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios); -extern NORETURN void common_hal_alarm_enter_deep_sleep(void); +extern MP_NORETURN void common_hal_alarm_enter_deep_sleep(void); // May be used to re-initialize peripherals like GPIO, if the VM reset returned // them to a default state diff --git a/shared-bindings/math/__init__.c b/shared-bindings/math/__init__.c index 54fe53280ca..49ca2958d8c 100644 --- a/shared-bindings/math/__init__.c +++ b/shared-bindings/math/__init__.c @@ -26,7 +26,7 @@ //| """ //| -static NORETURN void math_error(void) { +static MP_NORETURN void math_error(void) { mp_raise_ValueError(MP_ERROR_TEXT("math domain error")); } diff --git a/shared-bindings/memorymonitor/__init__.c b/shared-bindings/memorymonitor/__init__.c index 64d0140ff79..e364344b363 100644 --- a/shared-bindings/memorymonitor/__init__.c +++ b/shared-bindings/memorymonitor/__init__.c @@ -25,7 +25,7 @@ //| MP_DEFINE_MEMORYMONITOR_EXCEPTION(AllocationError, Exception) -NORETURN void mp_raise_memorymonitor_AllocationError(mp_rom_error_text_t fmt, ...) { +MP_NORETURN void mp_raise_memorymonitor_AllocationError(mp_rom_error_text_t fmt, ...) { va_list argptr; va_start(argptr, fmt); mp_obj_t exception = mp_obj_new_exception_msg_vlist(&mp_type_memorymonitor_AllocationError, fmt, argptr); diff --git a/shared-bindings/memorymonitor/__init__.h b/shared-bindings/memorymonitor/__init__.h index 28480bea7b5..5f141b924d0 100644 --- a/shared-bindings/memorymonitor/__init__.h +++ b/shared-bindings/memorymonitor/__init__.h @@ -23,4 +23,4 @@ void memorymonitor_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_pr extern const mp_obj_type_t mp_type_memorymonitor_AllocationError; -NORETURN void mp_raise_memorymonitor_AllocationError(mp_rom_error_text_t msg, ...); +MP_NORETURN void mp_raise_memorymonitor_AllocationError(mp_rom_error_text_t msg, ...); diff --git a/shared-bindings/microcontroller/Pin.c b/shared-bindings/microcontroller/Pin.c index e74d54b0770..1fcde50e060 100644 --- a/shared-bindings/microcontroller/Pin.c +++ b/shared-bindings/microcontroller/Pin.c @@ -175,14 +175,14 @@ void validate_pins(qstr what, uint8_t *pin_nos, mp_int_t max_pins, mp_obj_t seq, } } -NORETURN void raise_ValueError_invalid_pin(void) { +MP_NORETURN void raise_ValueError_invalid_pin(void) { mp_arg_error_invalid(MP_QSTR_pin); } -NORETURN void raise_ValueError_invalid_pins(void) { +MP_NORETURN void raise_ValueError_invalid_pins(void) { mp_arg_error_invalid(MP_QSTR_pins); } -NORETURN void raise_ValueError_invalid_pin_name(qstr pin_name) { +MP_NORETURN void raise_ValueError_invalid_pin_name(qstr pin_name) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Invalid %q pin"), pin_name); } diff --git a/shared-bindings/microcontroller/Pin.h b/shared-bindings/microcontroller/Pin.h index 1245b5f23e4..8ddca71bfbb 100644 --- a/shared-bindings/microcontroller/Pin.h +++ b/shared-bindings/microcontroller/Pin.h @@ -21,9 +21,9 @@ void validate_no_duplicate_pins(mp_obj_t seq, qstr arg_name); void validate_no_duplicate_pins_2(mp_obj_t seq1, mp_obj_t seq2, qstr arg_name1, qstr arg_name2); void validate_list_is_free_pins(qstr what, const mcu_pin_obj_t **pins_out, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out); void validate_pins(qstr what, uint8_t *pin_nos, mp_int_t max_pins, mp_obj_t seq, uint8_t *count_out); -NORETURN void raise_ValueError_invalid_pin(void); -NORETURN void raise_ValueError_invalid_pins(void); -NORETURN void raise_ValueError_invalid_pin_name(qstr pin_name); +MP_NORETURN void raise_ValueError_invalid_pin(void); +MP_NORETURN void raise_ValueError_invalid_pins(void); +MP_NORETURN void raise_ValueError_invalid_pin_name(qstr pin_name); void assert_pin_free(const mcu_pin_obj_t *pin); diff --git a/shared-bindings/microcontroller/__init__.h b/shared-bindings/microcontroller/__init__.h index 2a4a9732781..5c5902ff965 100644 --- a/shared-bindings/microcontroller/__init__.h +++ b/shared-bindings/microcontroller/__init__.h @@ -20,7 +20,7 @@ extern void common_hal_mcu_disable_interrupts(void); extern void common_hal_mcu_enable_interrupts(void); extern void common_hal_mcu_on_next_reset(mcu_runmode_t runmode); -NORETURN extern void common_hal_mcu_reset(void); +MP_NORETURN extern void common_hal_mcu_reset(void); extern const mp_obj_dict_t mcu_pin_globals; diff --git a/shared-bindings/paralleldisplaybus/__init__.c b/shared-bindings/paralleldisplaybus/__init__.c index 24d968c9e31..19a381570ba 100644 --- a/shared-bindings/paralleldisplaybus/__init__.c +++ b/shared-bindings/paralleldisplaybus/__init__.c @@ -29,6 +29,3 @@ const mp_obj_module_t paralleldisplaybus_module = { }; MP_REGISTER_MODULE(MP_QSTR_paralleldisplaybus, paralleldisplaybus_module); - -// Remove in CircuitPython 10 -MP_REGISTER_MODULE(MP_QSTR_paralleldisplay, paralleldisplaybus_module); diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c index 06b63b80ea7..ee35429926f 100644 --- a/shared-bindings/socketpool/SocketPool.c +++ b/shared-bindings/socketpool/SocketPool.c @@ -189,7 +189,7 @@ MP_DEFINE_CONST_OBJ_TYPE( locals_dict, &socketpool_socketpool_locals_dict ); -MP_WEAK NORETURN +MP_WEAK MP_NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void) { vstr_t vstr; mp_print_t print; diff --git a/shared-bindings/socketpool/SocketPool.h b/shared-bindings/socketpool/SocketPool.h index 36035ed00e1..60d58372b91 100644 --- a/shared-bindings/socketpool/SocketPool.h +++ b/shared-bindings/socketpool/SocketPool.h @@ -25,6 +25,6 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self, socketpool_socketpool_addressfamily_t family, socketpool_socketpool_sock_t type, int proto, socketpool_socket_obj_t *sock); -NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void); +MP_NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void); mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags); diff --git a/shared-bindings/storage/__init__.h b/shared-bindings/storage/__init__.h index ed3e8d44e4a..6df60426295 100644 --- a/shared-bindings/storage/__init__.h +++ b/shared-bindings/storage/__init__.h @@ -16,7 +16,7 @@ void common_hal_storage_umount_path(const char *path); void common_hal_storage_umount_object(mp_obj_t vfs_obj); void common_hal_storage_remount(const char *path, bool readonly, bool disable_concurrent_write_protection); mp_obj_t common_hal_storage_getmount(const char *path); -NORETURN void common_hal_storage_erase_filesystem(bool extended); +MP_NORETURN void common_hal_storage_erase_filesystem(bool extended); bool common_hal_storage_disable_usb_drive(void); bool common_hal_storage_enable_usb_drive(void); diff --git a/shared-bindings/usb/core/__init__.c b/shared-bindings/usb/core/__init__.c index 545e182ea99..89cec5bbe1d 100644 --- a/shared-bindings/usb/core/__init__.c +++ b/shared-bindings/usb/core/__init__.c @@ -30,7 +30,7 @@ //| //| MP_DEFINE_USB_CORE_EXCEPTION(USBError, OSError) -NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...) { +MP_NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...) { mp_obj_t exception; if (fmt == NULL) { exception = mp_obj_new_exception(&mp_type_usb_core_USBError); @@ -50,7 +50,7 @@ NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...) { //| //| MP_DEFINE_USB_CORE_EXCEPTION(USBTimeoutError, usb_core_USBError) -NORETURN void mp_raise_usb_core_USBTimeoutError(void) { +MP_NORETURN void mp_raise_usb_core_USBTimeoutError(void) { mp_raise_type(&mp_type_usb_core_USBTimeoutError); } diff --git a/shared-bindings/usb/core/__init__.h b/shared-bindings/usb/core/__init__.h index 0dc08fae532..adb8430a6c3 100644 --- a/shared-bindings/usb/core/__init__.h +++ b/shared-bindings/usb/core/__init__.h @@ -25,8 +25,8 @@ void usb_core_exception_print(const mp_print_t *print, mp_obj_t o_in, mp_print_k extern const mp_obj_type_t mp_type_usb_core_USBError; extern const mp_obj_type_t mp_type_usb_core_USBTimeoutError; -NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...); -NORETURN void mp_raise_usb_core_USBTimeoutError(void); +MP_NORETURN void mp_raise_usb_core_USBError(mp_rom_error_text_t fmt, ...); +MP_NORETURN void mp_raise_usb_core_USBTimeoutError(void); // Find is all Python object oriented so we don't need a separate common-hal API // for it. It uses the device common-hal instead. diff --git a/shared-bindings/util.h b/shared-bindings/util.h index d53e5c6e8da..11f0a00db71 100644 --- a/shared-bindings/util.h +++ b/shared-bindings/util.h @@ -9,7 +9,7 @@ #include "py/mpprint.h" #include "py/runtime.h" -NORETURN void raise_deinited_error(void); +MP_NORETURN void raise_deinited_error(void); void properties_print_helper(const mp_print_t *print, mp_obj_t self_in, const mp_arg_t *properties, size_t n_properties); void properties_construct_helper(mp_obj_t self_in, const mp_arg_t *args, const mp_arg_val_t *vals, size_t n_properties); bool path_exists(const char *path); diff --git a/shared-module/ssl/SSLSocket.c b/shared-module/ssl/SSLSocket.c index 8911fa2f454..fa1de8bb484 100644 --- a/shared-module/ssl/SSLSocket.c +++ b/shared-module/ssl/SSLSocket.c @@ -44,7 +44,7 @@ static void mbedtls_debug(void *ctx, int level, const char *file, int line, cons #define DEBUG_PRINT(...) do {} while (0) #endif -static NORETURN void mbedtls_raise_error(int err) { +static MP_NORETURN void mbedtls_raise_error(int err) { // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the // underlying socket into negative codes to pass them through mbedtls. Here we turn them // positive again so they get interpreted as the OSError they really are. The diff --git a/shared-module/struct/__init__.c b/shared-module/struct/__init__.c index 715b5043021..4b6b2b589ef 100644 --- a/shared-module/struct/__init__.c +++ b/shared-module/struct/__init__.c @@ -14,7 +14,8 @@ #include "shared-bindings/struct/__init__.h" static void struct_validate_format(char fmt) { - #if MICROPY_NONSTANDARD_TYPECODES + #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES + if (fmt == 'S' || fmt == 'O') { mp_raise_RuntimeError(MP_ERROR_TEXT("'S' and 'O' are not supported format types")); } diff --git a/shared/libc/abort_.c b/shared/libc/abort_.c index 3051eae81e0..54eab67d3fb 100644 --- a/shared/libc/abort_.c +++ b/shared/libc/abort_.c @@ -1,7 +1,7 @@ #include -NORETURN void abort_(void); +MP_NORETURN void abort_(void); -NORETURN void abort_(void) { +MP_NORETURN void abort_(void) { mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("abort() called")); } diff --git a/shared/memzip/make-memzip.py b/shared/memzip/make-memzip.py index 92a5d6168bb..e406c55a43c 100755 --- a/shared/memzip/make-memzip.py +++ b/shared/memzip/make-memzip.py @@ -7,8 +7,6 @@ # This is somewhat like frozen modules in python, but allows arbitrary files # to be used. -from __future__ import print_function - import argparse import os import subprocess diff --git a/shared/netutils/dhcpserver.c b/shared/netutils/dhcpserver.c deleted file mode 100644 index 6d9cdb97d1f..00000000000 --- a/shared/netutils/dhcpserver.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018-2019 Damien P. George - * - * 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. - */ - -// For DHCP specs see: -// https://www.ietf.org/rfc/rfc2131.txt -// https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions - -#include -#include -#include "py/mperrno.h" -#include "py/mphal.h" -#include "lwip/opt.h" - -// CIRCUITPY-CHANGE: comment -// Used in CIRCUITPY without MICROPY_PY_LWIP - -#if LWIP_UDP - -#include "shared/netutils/dhcpserver.h" -#include "lwip/udp.h" - -#define DHCPDISCOVER (1) -#define DHCPOFFER (2) -#define DHCPREQUEST (3) -#define DHCPDECLINE (4) -#define DHCPACK (5) -#define DHCPNACK (6) -#define DHCPRELEASE (7) -#define DHCPINFORM (8) - -#define DHCP_OPT_PAD (0) -#define DHCP_OPT_SUBNET_MASK (1) -#define DHCP_OPT_ROUTER (3) -#define DHCP_OPT_DNS (6) -#define DHCP_OPT_HOST_NAME (12) -#define DHCP_OPT_REQUESTED_IP (50) -#define DHCP_OPT_IP_LEASE_TIME (51) -#define DHCP_OPT_MSG_TYPE (53) -#define DHCP_OPT_SERVER_ID (54) -#define DHCP_OPT_PARAM_REQUEST_LIST (55) -#define DHCP_OPT_MAX_MSG_SIZE (57) -#define DHCP_OPT_VENDOR_CLASS_ID (60) -#define DHCP_OPT_CLIENT_ID (61) -#define DHCP_OPT_END (255) - -#define PORT_DHCP_SERVER (67) -#define PORT_DHCP_CLIENT (68) - -#define DEFAULT_DNS MAKE_IP4(192, 168, 4, 1) -#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds - -#define MAC_LEN (6) -#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) - -typedef struct { - uint8_t op; // message opcode - uint8_t htype; // hardware address type - uint8_t hlen; // hardware address length - uint8_t hops; - uint32_t xid; // transaction id, chosen by client - uint16_t secs; // client seconds elapsed - uint16_t flags; - uint8_t ciaddr[4]; // client IP address - uint8_t yiaddr[4]; // your IP address - uint8_t siaddr[4]; // next server IP address - uint8_t giaddr[4]; // relay agent IP address - uint8_t chaddr[16]; // client hardware address - uint8_t sname[64]; // server host name - uint8_t file[128]; // boot file name - uint8_t options[312]; // optional parameters, variable, starts with magic -} dhcp_msg_t; - -static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) { - // family is AF_INET - // type is SOCK_DGRAM - - *udp = udp_new(); - if (*udp == NULL) { - return -MP_ENOMEM; - } - - // Register callback - udp_recv(*udp, cb_udp_recv, (void *)cb_data); - - return 0; // success -} - -static void dhcp_socket_free(struct udp_pcb **udp) { - if (*udp != NULL) { - udp_remove(*udp); - *udp = NULL; - } -} - -static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) { - ip_addr_t addr; - IP_ADDR4(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); - // TODO convert lwIP errors to errno - return udp_bind(*udp, &addr, port); -} - -static int dhcp_socket_sendto(struct udp_pcb **udp, struct netif *netif, const void *buf, size_t len, uint32_t ip, uint16_t port) { - if (len > 0xffff) { - len = 0xffff; - } - - struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); - if (p == NULL) { - return -MP_ENOMEM; - } - - memcpy(p->payload, buf, len); - - ip_addr_t dest; - IP_ADDR4(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); - err_t err; - if (netif != NULL) { - err = udp_sendto_if(*udp, p, &dest, port, netif); - } else { - err = udp_sendto(*udp, p, &dest, port); - } - - pbuf_free(p); - - if (err != ERR_OK) { - return err; - } - - return len; -} - -static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) { - for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) { - if (opt[i] == cmd) { - return &opt[i]; - } - i += 2 + opt[i + 1]; - } - return NULL; -} - -static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, const void *data) { - uint8_t *o = *opt; - *o++ = cmd; - *o++ = n; - memcpy(o, data, n); - *opt = o + n; -} - -static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) { - uint8_t *o = *opt; - *o++ = cmd; - *o++ = 1; - *o++ = val; - *opt = o; -} - -static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) { - uint8_t *o = *opt; - *o++ = cmd; - *o++ = 4; - *o++ = val >> 24; - *o++ = val >> 16; - *o++ = val >> 8; - *o++ = val; - *opt = o; -} - -static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) { - dhcp_server_t *d = arg; - (void)upcb; - (void)src_addr; - (void)src_port; - - // This is around 548 bytes - dhcp_msg_t dhcp_msg; - - #define DHCP_MIN_SIZE (240 + 3) - if (p->tot_len < DHCP_MIN_SIZE) { - goto ignore_request; - } - - size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0); - if (len < DHCP_MIN_SIZE) { - goto ignore_request; - } - - dhcp_msg.op = DHCPOFFER; - memcpy(&dhcp_msg.yiaddr, &ip_2_ip4(&d->ip)->addr, 4); - - uint8_t *opt = (uint8_t *)&dhcp_msg.options; - opt += 4; // assume magic cookie: 99, 130, 83, 99 - - switch (opt[2]) { - case DHCPDISCOVER: { - int yi = DHCPS_MAX_IP; - for (int i = 0; i < DHCPS_MAX_IP; ++i) { - if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { - // MAC match, use this IP address - yi = i; - break; - } - if (yi == DHCPS_MAX_IP) { - // Look for a free IP address - if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { - // IP available - yi = i; - } - uint32_t expiry = d->lease[i].expiry << 16 | 0xffff; - if ((int32_t)(expiry - mp_hal_ticks_ms()) < 0) { - // IP expired, reuse it - memset(d->lease[i].mac, 0, MAC_LEN); - yi = i; - } - } - } - if (yi == DHCPS_MAX_IP) { - // No more IP addresses left - goto ignore_request; - } - dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; - opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER); - break; - } - - case DHCPREQUEST: { - uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP); - if (o == NULL) { - // Should be NACK - goto ignore_request; - } - if (memcmp(o + 2, &ip_2_ip4(&d->ip)->addr, 3) != 0) { - // Should be NACK - goto ignore_request; - } - uint8_t yi = o[5] - DHCPS_BASE_IP; - if (yi >= DHCPS_MAX_IP) { - // Should be NACK - goto ignore_request; - } - if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { - // MAC match, ok to use this IP address - } else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { - // IP unused, ok to use this IP address - memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN); - } else { - // IP already in use - // Should be NACK - goto ignore_request; - } - d->lease[yi].expiry = (mp_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16; - dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; - opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK); - // CIRCUITPY-CHANGE: use LWIP_DEBUGF instead of printf - LWIP_DEBUGF(DHCP_DEBUG, ("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n", - dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5], - dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3])); - break; - } - - default: - goto ignore_request; - } - - opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &ip_2_ip4(&d->ip)->addr); - opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &ip_2_ip4(&d->nm)->addr); - opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &ip_2_ip4(&d->ip)->addr); // aka gateway; can have multiple addresses - opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have multiple addresses - opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S); - *opt++ = DHCP_OPT_END; - struct netif *netif = ip_current_input_netif(); - dhcp_socket_sendto(&d->udp, netif, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT); - -ignore_request: - pbuf_free(p); -} - -void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) { - ip_addr_copy(d->ip, *ip); - ip_addr_copy(d->nm, *nm); - memset(d->lease, 0, sizeof(d->lease)); - if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) { - return; - } - dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER); -} - -void dhcp_server_deinit(dhcp_server_t *d) { - dhcp_socket_free(&d->udp); -} - -#endif // MICROPY_PY_LWIP diff --git a/shared/netutils/netutils.c b/shared/netutils/netutils.c deleted file mode 100644 index cd1422f7c80..00000000000 --- a/shared/netutils/netutils.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2015 Daniel Campora - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include - -#include "py/runtime.h" -#include "shared/netutils/netutils.h" - -// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'. -mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) { - char ip_str[16]; - mp_uint_t ip_len; - if (endian == NETUTILS_LITTLE) { - ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[3], ip[2], ip[1], ip[0]); - } 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); -} - -// Takes an array with a raw IP address, and a port, and returns a net-address -// tuple such as ('192.168.0.1', 8080). -mp_obj_t netutils_format_inet_addr(uint8_t *ip, mp_uint_t port, netutils_endian_t endian) { - mp_obj_t tuple[2] = { - tuple[0] = netutils_format_ipv4_addr(ip, endian), - tuple[1] = mp_obj_new_int(port), - }; - return mp_obj_new_tuple(2, tuple); -} - -void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian) { - size_t addr_len; - const char *addr_str = mp_obj_str_get_data(addr_in, &addr_len); - if (addr_len == 0) { - // special case of no address given - memset(out_ip, 0, NETUTILS_IPV4ADDR_BUFSIZE); - return; - } - const char *s = addr_str; - const char *s_top; - // Scan for the end of valid address characters - for (s_top = addr_str; s_top < addr_str + addr_len; s_top++) { - if (!(*s_top == '.' || (*s_top >= '0' && *s_top <= '9'))) { - break; - } - } - for (mp_uint_t i = 3; ; i--) { - mp_uint_t val = 0; - for (; s < s_top && *s != '.'; s++) { - val = val * 10 + *s - '0'; - } - if (endian == NETUTILS_LITTLE) { - out_ip[i] = val; - } else { - out_ip[NETUTILS_IPV4ADDR_BUFSIZE - 1 - i] = val; - } - if (i == 0 && s == s_top) { - return; - } else if (i > 0 && s < s_top && *s == '.') { - s++; - } else { - mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments")); - } - } -} - -// Takes an address of the form ('192.168.0.1', 8080), returns the port and -// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). -mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian) { - mp_obj_t *addr_items; - mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); - netutils_parse_ipv4_addr(addr_items[0], out_ip, endian); - return mp_obj_get_int(addr_items[1]); -} diff --git a/shared/netutils/netutils.h b/shared/netutils/netutils.h deleted file mode 100644 index f82960ba800..00000000000 --- a/shared/netutils/netutils.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2013, 2014 Damien P. George - * Copyright (c) 2015 Daniel Campora - * - * 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. - */ -#ifndef MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H -#define MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H - -#include "py/obj.h" - -#define NETUTILS_IPV4ADDR_BUFSIZE 4 - -#define NETUTILS_TRACE_IS_TX (0x0001) -#define NETUTILS_TRACE_PAYLOAD (0x0002) -#define NETUTILS_TRACE_NEWLINE (0x0004) - -typedef enum _netutils_endian_t { - NETUTILS_LITTLE, - NETUTILS_BIG, -} netutils_endian_t; - -// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'. -mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian); - -// Takes an array with a raw IP address, and a port, and returns a net-address -// tuple such as ('192.168.0.1', 8080). -mp_obj_t netutils_format_inet_addr(uint8_t *ip, mp_uint_t port, netutils_endian_t endian); - -void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian); - -// Takes an address of the form ('192.168.0.1', 8080), returns the port and -// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). -mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian); - -void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags); - -#endif // MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H diff --git a/shared/netutils/trace.c b/shared/netutils/trace.c deleted file mode 100644 index a6dfb42c28f..00000000000 --- a/shared/netutils/trace.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Damien P. George - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "py/mphal.h" -#include "shared/netutils/netutils.h" - -static uint32_t get_be16(const uint8_t *buf) { - return buf[0] << 8 | buf[1]; -} - -static uint32_t get_be32(const uint8_t *buf) { - return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; -} - -static void dump_hex_bytes(const mp_print_t *print, size_t len, const uint8_t *buf) { - for (size_t i = 0; i < len; ++i) { - mp_printf(print, " %02x", buf[i]); - } -} - -static const char *ethertype_str(uint16_t type) { - // A value between 0x0000 - 0x05dc (inclusive) indicates a length, not type - switch (type) { - case 0x0800: - return "IPv4"; - case 0x0806: - return "ARP"; - case 0x86dd: - return "IPv6"; - default: - return NULL; - } -} - -void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags) { - mp_printf(print, "[% 8d] ETH%cX len=%u", mp_hal_ticks_ms(), flags & NETUTILS_TRACE_IS_TX ? 'T' : 'R', len); - mp_printf(print, " dst=%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); - mp_printf(print, " src=%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); - - const char *ethertype = ethertype_str(buf[12] << 8 | buf[13]); - if (ethertype) { - mp_printf(print, " type=%s", ethertype); - } else { - mp_printf(print, " type=0x%04x", buf[12] << 8 | buf[13]); - } - if (len > 14) { - len -= 14; - buf += 14; - if (buf[-2] == 0x08 && buf[-1] == 0x00 && buf[0] == 0x45) { - // IPv4 packet - len = get_be16(buf + 2); - mp_printf(print, " srcip=%u.%u.%u.%u dstip=%u.%u.%u.%u", - buf[12], buf[13], buf[14], buf[15], - buf[16], buf[17], buf[18], buf[19]); - uint8_t prot = buf[9]; - buf += 20; - len -= 20; - if (prot == 6) { - // TCP packet - uint16_t srcport = get_be16(buf); - uint16_t dstport = get_be16(buf + 2); - uint32_t seqnum = get_be32(buf + 4); - uint32_t acknum = get_be32(buf + 8); - uint16_t dataoff_flags = get_be16(buf + 12); - uint16_t winsz = get_be16(buf + 14); - mp_printf(print, " TCP srcport=%u dstport=%u seqnum=%u acknum=%u dataoff=%u flags=%x winsz=%u", - srcport, dstport, (unsigned)seqnum, (unsigned)acknum, dataoff_flags >> 12, dataoff_flags & 0x1ff, winsz); - buf += 20; - len -= 20; - if (dataoff_flags >> 12 > 5) { - mp_printf(print, " opts="); - size_t opts_len = ((dataoff_flags >> 12) - 5) * 4; - dump_hex_bytes(print, opts_len, buf); - buf += opts_len; - len -= opts_len; - } - } else if (prot == 17) { - // UDP packet - uint16_t srcport = get_be16(buf); - uint16_t dstport = get_be16(buf + 2); - mp_printf(print, " UDP srcport=%u dstport=%u", srcport, dstport); - len = get_be16(buf + 4); - buf += 8; - if ((srcport == 67 && dstport == 68) || (srcport == 68 && dstport == 67)) { - // DHCP - if (srcport == 67) { - mp_printf(print, " DHCPS"); - } else { - mp_printf(print, " DHCPC"); - } - dump_hex_bytes(print, 12 + 16 + 16 + 64, buf); - size_t n = 12 + 16 + 16 + 64 + 128; - len -= n; - buf += n; - mp_printf(print, " opts:"); - switch (buf[6]) { - case 1: - mp_printf(print, " DISCOVER"); - break; - case 2: - mp_printf(print, " OFFER"); - break; - case 3: - mp_printf(print, " REQUEST"); - break; - case 4: - mp_printf(print, " DECLINE"); - break; - case 5: - mp_printf(print, " ACK"); - break; - case 6: - mp_printf(print, " NACK"); - break; - case 7: - mp_printf(print, " RELEASE"); - break; - case 8: - mp_printf(print, " INFORM"); - break; - } - } - } else { - // Non-UDP packet - mp_printf(print, " prot=%u", prot); - } - } else if (buf[-2] == 0x86 && buf[-1] == 0xdd && (buf[0] >> 4) == 6) { - // IPv6 packet - uint32_t h = get_be32(buf); - uint16_t l = get_be16(buf + 4); - mp_printf(print, " tclass=%u flow=%u len=%u nexthdr=%u hoplimit=%u", (unsigned)((h >> 20) & 0xff), (unsigned)(h & 0xfffff), l, buf[6], buf[7]); - mp_printf(print, " srcip="); - dump_hex_bytes(print, 16, buf + 8); - mp_printf(print, " dstip="); - dump_hex_bytes(print, 16, buf + 24); - buf += 40; - len -= 40; - } - if (flags & NETUTILS_TRACE_PAYLOAD) { - mp_printf(print, " data="); - dump_hex_bytes(print, len, buf); - } - } - if (flags & NETUTILS_TRACE_NEWLINE) { - mp_printf(print, "\n"); - } -} diff --git a/shared/runtime/mpirq.c b/shared/runtime/mpirq.c index 6111b9b10cf..4d848ae7e91 100644 --- a/shared/runtime/mpirq.c +++ b/shared/runtime/mpirq.c @@ -65,9 +65,19 @@ void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t p self->ishard = false; } -void mp_irq_handler(mp_irq_obj_t *self) { - if (self->handler != mp_const_none) { - if (self->ishard) { +int mp_irq_dispatch(mp_obj_t handler, mp_obj_t parent, bool ishard) { + int result = 0; + if (handler != mp_const_none) { + if (ishard) { + #if MICROPY_STACK_CHECK && MICROPY_STACK_SIZE_HARD_IRQ > 0 + // This callback executes in an ISR context so the stack-limit + // check must be changed to use the ISR stack for the duration + // of this function. + char *orig_stack_top = MP_STATE_THREAD(stack_top); + size_t orig_stack_limit = MP_STATE_THREAD(stack_limit); + mp_cstack_init_with_sp_here(MICROPY_STACK_SIZE_HARD_IRQ); + #endif + // When executing code within a handler we must lock the scheduler to // prevent any scheduled callbacks from running, and lock the GC to // prevent any memory allocations. @@ -75,22 +85,36 @@ void mp_irq_handler(mp_irq_obj_t *self) { gc_lock(); nlr_buf_t nlr; if (nlr_push(&nlr) == 0) { - mp_call_function_1(self->handler, self->parent); + mp_call_function_1(handler, parent); nlr_pop(); } else { - // Uncaught exception; disable the callback so that it doesn't run again - self->methods->trigger(self->parent, 0); - self->handler = mp_const_none; mp_printf(MICROPY_ERROR_PRINTER, "Uncaught exception in IRQ callback handler\n"); mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val)); + result = -1; } gc_unlock(); mp_sched_unlock(); + + #if MICROPY_STACK_CHECK && MICROPY_STACK_SIZE_HARD_IRQ > 0 + // Restore original stack-limit checking values. + MP_STATE_THREAD(stack_top) = orig_stack_top; + MP_STATE_THREAD(stack_limit) = orig_stack_limit; + #endif } else { // Schedule call to user function - mp_sched_schedule(self->handler, self->parent); + mp_sched_schedule(handler, parent); } } + return result; +} + + +void mp_irq_handler(mp_irq_obj_t *self) { + if (mp_irq_dispatch(self->handler, self->parent, self->ishard) < 0) { + // Uncaught exception; disable the callback so that it doesn't run again + self->methods->trigger(self->parent, 0); + self->handler = mp_const_none; + } } /******************************************************************************/ diff --git a/shared/runtime/mpirq.h b/shared/runtime/mpirq.h index dd423c01011..c65741e0e49 100644 --- a/shared/runtime/mpirq.h +++ b/shared/runtime/mpirq.h @@ -77,6 +77,7 @@ extern const mp_obj_type_t mp_irq_type; mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent); void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent); +int mp_irq_dispatch(mp_obj_t handler, mp_obj_t parent, bool ishard); void mp_irq_handler(mp_irq_obj_t *self); #endif // MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 06680ff2dd1..a44fdf724d1 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -38,12 +38,9 @@ #include "py/gc.h" #include "py/frozenmod.h" #include "py/mphal.h" -#if MICROPY_HW_ENABLE_USB -#include "irq.h" -#include "usb.h" -#endif #include "shared/readline/readline.h" #include "shared/runtime/pyexec.h" +#include "extmod/modplatform.h" #include "genhdr/mpversion.h" // CIRCUITPY-CHANGE: atexit support @@ -484,7 +481,9 @@ static int pyexec_friendly_repl_process_char(int c) { // CIRCUITPY-CHANGE: print CircuitPython-style banner. mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO); mp_hal_stdout_tx_str("\r\n"); - // mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); + #if MICROPY_PY_BUILTINS_HELP + mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); + #endif goto input_restart; } else if (ret == CHAR_CTRL_C) { // break @@ -570,10 +569,20 @@ MP_REGISTER_ROOT_POINTER(vstr_t * repl_line); #else // MICROPY_REPL_EVENT_DRIVEN +#if !MICROPY_HAL_HAS_STDIO_MODE_SWITCH +// If the port doesn't need any stdio mode switching calls then provide trivial ones. +static inline void mp_hal_stdio_mode_raw(void) { +} +static inline void mp_hal_stdio_mode_orig(void) { +} +#endif + int pyexec_raw_repl(void) { vstr_t line; vstr_init(&line, 32); + mp_hal_stdio_mode_raw(); + raw_repl_reset: mp_hal_stdout_tx_str("raw REPL; CTRL-B to exit\r\n"); @@ -587,6 +596,7 @@ int pyexec_raw_repl(void) { if (vstr_len(&line) == 2 && vstr_str(&line)[0] == CHAR_CTRL_E) { int ret = do_reader_stdin(vstr_str(&line)[1]); if (ret & PYEXEC_FORCED_EXIT) { + mp_hal_stdio_mode_orig(); return ret; } vstr_reset(&line); @@ -599,6 +609,7 @@ int pyexec_raw_repl(void) { mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); pyexec_mode_kind = PYEXEC_MODE_FRIENDLY_REPL; + mp_hal_stdio_mode_orig(); return 0; } else if (c == CHAR_CTRL_C) { // clear line @@ -619,14 +630,18 @@ int pyexec_raw_repl(void) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); + mp_hal_stdio_mode_orig(); return PYEXEC_FORCED_EXIT; } + // Switch to original terminal mode to execute code, eg to support keyboard interrupt (SIGINT). + mp_hal_stdio_mode_orig(); // CIRCUITPY-CHANGE: add last arg, handle reload int ret = parse_compile_execute(&line, MP_PARSE_FILE_INPUT, EXEC_FLAG_PRINT_EOF | EXEC_FLAG_SOURCE_IS_VSTR, NULL); if (ret & (PYEXEC_FORCED_EXIT | PYEXEC_RELOAD)) { return ret; } + mp_hal_stdio_mode_raw(); } } @@ -634,6 +649,8 @@ int pyexec_friendly_repl(void) { vstr_t line; vstr_init(&line, 32); + mp_hal_stdio_mode_raw(); + friendly_repl_reset: // CIRCUITPY-CHANGE: CircuitPython-style banner. mp_hal_stdout_tx_str("\r\n"); @@ -661,20 +678,6 @@ int pyexec_friendly_repl(void) { for (;;) { input_restart: - - #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 - // interrupts to be enabled or no transfers occur. So we try to - // do the user a favor and re-enable interrupts. - if (query_irq() == IRQ_STATE_DISABLED) { - enable_irq(IRQ_STATE_ENABLED); - mp_hal_stdout_tx_str("MPY: enabling IRQs\r\n"); - } - } - #endif - // If the GC is locked at this point there is no way out except a reset, // so force the GC to be unlocked to help the user debug what went wrong. if (MP_STATE_THREAD(gc_lock_depth) != 0) { @@ -705,6 +708,7 @@ int pyexec_friendly_repl(void) { mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); pyexec_mode_kind = PYEXEC_MODE_RAW_REPL; + mp_hal_stdio_mode_orig(); return 0; } else if (ret == CHAR_CTRL_B) { // reset friendly REPL @@ -718,6 +722,7 @@ int pyexec_friendly_repl(void) { // exit for a soft reset mp_hal_stdout_tx_str("\r\n"); vstr_clear(&line); + mp_hal_stdio_mode_orig(); return PYEXEC_FORCED_EXIT; } else if (ret == CHAR_CTRL_E) { // paste mode @@ -762,6 +767,8 @@ int pyexec_friendly_repl(void) { } } + // Switch to original terminal mode to execute code, eg to support keyboard interrupt (SIGINT). + mp_hal_stdio_mode_orig(); // CIRCUITPY-CHANGE: add last arg ret = parse_compile_execute(&line, parse_input_kind, EXEC_FLAG_ALLOW_DEBUGGING | EXEC_FLAG_IS_REPL | EXEC_FLAG_SOURCE_IS_VSTR, NULL); if (ret & (PYEXEC_FORCED_EXIT | PYEXEC_RELOAD)) { diff --git a/shared/runtime/pyexec.h b/shared/runtime/pyexec.h index 55a3003791c..9d1ef2a3cb0 100644 --- a/shared/runtime/pyexec.h +++ b/shared/runtime/pyexec.h @@ -51,6 +51,17 @@ extern pyexec_mode_kind_t pyexec_mode_kind; #define PYEXEC_DEEP_SLEEP (0x400) #define PYEXEC_RELOAD (0x800) +#if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING +#define PYEXEC_NORMAL_EXIT (0) +#define PYEXEC_UNHANDLED_EXCEPTION (1) +#define PYEXEC_KEYBOARD_INTERRUPT (128 + 2) // same as SIG INT exit code +#define PYEXEC_ABORT (128 + 9) // same as SIG KILL exit code +#else +#define PYEXEC_NORMAL_EXIT (1) +#define PYEXEC_UNHANDLED_EXCEPTION (0) +#define PYEXEC_ABORT PYEXEC_FORCED_EXIT +#endif + int pyexec_raw_repl(void); int pyexec_friendly_repl(void); // CIRCUITPY-CHANGE: result out argument diff --git a/shared/timeutils/timeutils.c b/shared/timeutils/timeutils.c index 4282a0178dd..0c6916e06dd 100644 --- a/shared/timeutils/timeutils.c +++ b/shared/timeutils/timeutils.c @@ -29,12 +29,27 @@ #include "shared/timeutils/timeutils.h" -// LEAPOCH corresponds to 2000-03-01, which is a mod-400 year, immediately -// after Feb 29. We calculate seconds as a signed integer relative to that. +// To maintain reasonable compatibility with CPython on embedded systems, +// and avoid breaking anytime soon, timeutils functions are required to +// work properly between 1970 and 2099 on all ports. // -// Our timebase is relative to 2000-01-01. - -#define LEAPOCH ((31 + 29) * 86400) +// During that period of time, leap years occur every 4 years without +// exception, so we can keep the code short for 32 bit machines. + +// The last leap day before the required period is Feb 29, 1968. +// This is the number of days to add to get to that date. +#define PREV_LEAP_DAY ((mp_uint_t)(365 + 366 - (31 + 29))) +#define PREV_LEAP_YEAR 1968 + +// On ports where either MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND or +// MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE is enabled, we include extra +// code to support leap years outside of the 'easy' period. +// Computation is then made based on 1600 (a mod-400 year). +// This is the number of days between 1600 and 1968. +#define QC_BASE_DAY 134409 +#define QC_LEAP_YEAR 1600 +// This is the number of leap days between 1600 and 1970 +#define QC_LEAP_DAYS 89 #define DAYS_PER_400Y (365 * 400 + 97) #define DAYS_PER_100Y (365 * 100 + 24) @@ -42,8 +57,20 @@ static const uint16_t days_since_jan1[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; +// type used internally to count small integers relative to epoch +// (using uint when possible produces smaller code on some platforms) +#if MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE +typedef mp_int_t relint_t; +#else +typedef mp_uint_t relint_t; +#endif + bool timeutils_is_leap_year(mp_uint_t year) { + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; + #else + return year % 4 == 0; + #endif } // month is one based @@ -65,67 +92,67 @@ mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date) { return yday; } -void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_time_t *tm) { - // The following algorithm was adapted from musl's __secs_to_tm and adapted - // for differences in MicroPython's timebase. - - mp_int_t seconds = t - LEAPOCH; +void timeutils_seconds_since_1970_to_struct_time(timeutils_timestamp_t seconds, timeutils_struct_time_t *tm) { + // The following algorithm was inspired from musl's __secs_to_tm + // and simplified to reduce code footprint in the simple case - mp_int_t days = seconds / 86400; + relint_t days = seconds / 86400; seconds %= 86400; + #if MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE if (seconds < 0) { seconds += 86400; days -= 1; } + #endif tm->tm_hour = seconds / 3600; tm->tm_min = seconds / 60 % 60; tm->tm_sec = seconds % 60; - mp_int_t wday = (days + 2) % 7; // Mar 1, 2000 was a Wednesday (2) + relint_t wday = (days + 3) % 7; // Jan 1, 1970 was a Thursday (3) + #if MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE if (wday < 0) { wday += 7; } + #endif tm->tm_wday = wday; - mp_int_t qc_cycles = days / DAYS_PER_400Y; + days += PREV_LEAP_DAY; + + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE + // rebase day to the oldest supported date (=> always positive) + mp_uint_t base_year = QC_LEAP_YEAR; + days += QC_BASE_DAY; + mp_uint_t qc_cycles = days / DAYS_PER_400Y; days %= DAYS_PER_400Y; - if (days < 0) { - days += DAYS_PER_400Y; - qc_cycles--; - } - mp_int_t c_cycles = days / DAYS_PER_100Y; + mp_uint_t c_cycles = days / DAYS_PER_100Y; if (c_cycles == 4) { c_cycles--; } days -= (c_cycles * DAYS_PER_100Y); - - mp_int_t q_cycles = days / DAYS_PER_4Y; + #else + mp_uint_t base_year = PREV_LEAP_YEAR; + mp_uint_t qc_cycles = 0; + mp_uint_t c_cycles = 0; + #endif + + mp_uint_t q_cycles = days / DAYS_PER_4Y; + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE if (q_cycles == 25) { q_cycles--; } + #endif days -= q_cycles * DAYS_PER_4Y; - mp_int_t years = days / 365; + relint_t years = days / 365; if (years == 4) { years--; } days -= (years * 365); - /* We will compute tm_yday at the very end - mp_int_t leap = !years && (q_cycles || !c_cycles); - - tm->tm_yday = days + 31 + 28 + leap; - if (tm->tm_yday >= 365 + leap) { - tm->tm_yday -= 365 + leap; - } - - tm->tm_yday++; // Make one based - */ - - tm->tm_year = 2000 + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles; + tm->tm_year = base_year + years + 4 * q_cycles + 100 * c_cycles + 400 * qc_cycles; // Note: days_in_month[0] corresponds to March - static const int8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; + static const uint8_t days_in_month[] = {31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 31, 29}; mp_int_t month; for (month = 0; days_in_month[month] <= days; month++) { @@ -144,21 +171,28 @@ void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, timeutils_struct_t } // returns the number of seconds, as an integer, since 2000-01-01 -mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, +timeutils_timestamp_t timeutils_seconds_since_1970(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { - return - second - + minute * 60 - + hour * 3600 - + (timeutils_year_day(year, month, date) - 1 - + ((year - 2000 + 3) / 4) // add a day each 4 years starting with 2001 - - ((year - 2000 + 99) / 100) // subtract a day each 100 years starting with 2001 - + ((year - 2000 + 399) / 400) // add a day each 400 years starting with 2001 - ) * 86400 - + (year - 2000) * 31536000; + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE + mp_uint_t ref_year = QC_LEAP_YEAR; + #else + mp_uint_t ref_year = PREV_LEAP_YEAR; + #endif + timeutils_timestamp_t res; + res = ((relint_t)year - 1970) * 365; + res += (year - (ref_year + 1)) / 4; // add a day each 4 years + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE + res -= (year - (ref_year + 1)) / 100; // subtract a day each 100 years + res += (year - (ref_year + 1)) / 400; // add a day each 400 years + res -= QC_LEAP_DAYS; + #endif + res += timeutils_year_day(year, month, date) - 1; + res *= 86400; + res += hour * 3600 + minute * 60 + second; + return res; } -mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, +timeutils_timestamp_t timeutils_mktime_1970(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { // Normalize the tuple. This allows things like: @@ -211,12 +245,16 @@ mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, year++; } } - return timeutils_seconds_since_2000(year, month, mday, hours, minutes, seconds); + return timeutils_seconds_since_1970(year, month, mday, hours, minutes, seconds); } // Calculate the weekday from the date. // The result is zero based with 0 = Monday. // by Michael Keith and Tom Craver, 1990. int timeutils_calc_weekday(int y, int m, int d) { - return ((d += m < 3 ? y-- : y - 2, 23 * m / 9 + d + 4 + y / 4 - y / 100 + y / 400) + 6) % 7; + return ((d += m < 3 ? y-- : y - 2, 23 * m / 9 + d + 4 + y / 4 + #if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE + - y / 100 + y / 400 + #endif + ) + 6) % 7; } diff --git a/shared/timeutils/timeutils.h b/shared/timeutils/timeutils.h index b41903d3b27..35356b462aa 100644 --- a/shared/timeutils/timeutils.h +++ b/shared/timeutils/timeutils.h @@ -27,12 +27,23 @@ #ifndef MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H #define MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H -// CIRCUITPY-CHANGE: MICROPY_EPOCH_IS_1970 -#include "mpconfigport.h" +#include "py/obj.h" +#if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#include // required for trunc() +#endif + +// `timeutils_timestamp_t` is the type used internally by timeutils to +// represent timestamps, and is always referenced to 1970. +// It may not match the platform-specific `mp_timestamp_t`. +#if MICROPY_TIME_SUPPORT_Y2100_AND_BEYOND || MICROPY_TIME_SUPPORT_Y1969_AND_BEFORE +typedef long long timeutils_timestamp_t; +#else +typedef mp_uint_t timeutils_timestamp_t; +#endif // The number of seconds between 1970/1/1 and 2000/1/1 is calculated using: // time.mktime((2000,1,1,0,0,0,0,0,0)) - time.mktime((1970,1,1,0,0,0,0,0,0)) -#define TIMEUTILS_SECONDS_1970_TO_2000 (946684800ULL) +#define TIMEUTILS_SECONDS_1970_TO_2000 (946684800LL) typedef struct _timeutils_struct_time_t { uint16_t tm_year; // i.e. 2014 @@ -48,66 +59,116 @@ typedef struct _timeutils_struct_time_t { bool timeutils_is_leap_year(mp_uint_t year); mp_uint_t timeutils_days_in_month(mp_uint_t year, mp_uint_t month); mp_uint_t timeutils_year_day(mp_uint_t year, mp_uint_t month, mp_uint_t date); +int timeutils_calc_weekday(int y, int m, int d); -void timeutils_seconds_since_2000_to_struct_time(mp_uint_t t, +void timeutils_seconds_since_1970_to_struct_time(timeutils_timestamp_t t, timeutils_struct_time_t *tm); // Year is absolute, month/date are 1-based, hour/minute/second are 0-based. -mp_uint_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, +timeutils_timestamp_t timeutils_seconds_since_1970(mp_uint_t year, mp_uint_t month, mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second); // Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. -mp_uint_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, +timeutils_timestamp_t timeutils_mktime_1970(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds); +static inline mp_timestamp_t timeutils_obj_get_timestamp(mp_obj_t o_in) { + #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE + mp_float_t val = mp_obj_get_float(o_in); + return (mp_timestamp_t)MICROPY_FLOAT_C_FUN(trunc)(val); + #elif MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_UINT + return mp_obj_get_uint(o_in); + #else + return mp_obj_get_ll(o_in); + #endif +} + +static inline mp_obj_t timeutils_obj_from_timestamp(mp_timestamp_t t) { + #if MICROPY_TIMESTAMP_IMPL == MICROPY_TIMESTAMP_IMPL_UINT + return mp_obj_new_int_from_uint(t); + #else + return mp_obj_new_int_from_ll(t); + #endif +} + +static inline void timeutils_seconds_since_2000_to_struct_time(mp_timestamp_t t, timeutils_struct_time_t *tm) { + timeutils_seconds_since_1970_to_struct_time((timeutils_timestamp_t)(t + TIMEUTILS_SECONDS_1970_TO_2000), tm); +} + +// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. +static inline mp_timestamp_t timeutils_seconds_since_2000(mp_uint_t year, mp_uint_t month, mp_uint_t date, + mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { + return (mp_timestamp_t)timeutils_seconds_since_1970(year, month, date, hour, minute, second) - TIMEUTILS_SECONDS_1970_TO_2000; +} + +// Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. +static inline mp_timestamp_t timeutils_mktime_2000(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { + return (mp_timestamp_t)timeutils_mktime_1970(year, month, mday, hours, minutes, seconds) - TIMEUTILS_SECONDS_1970_TO_2000; +} + + // Select the Epoch used by the port. #if MICROPY_EPOCH_IS_1970 -static inline void timeutils_seconds_since_epoch_to_struct_time(uint64_t t, timeutils_struct_time_t *tm) { - // TODO this will give incorrect results for dates before 2000/1/1 - timeutils_seconds_since_2000_to_struct_time((mp_uint_t)(t - TIMEUTILS_SECONDS_1970_TO_2000), tm); +static inline void timeutils_seconds_since_epoch_to_struct_time(mp_timestamp_t t, timeutils_struct_time_t *tm) { + timeutils_seconds_since_1970_to_struct_time(t, tm); +} + +// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. +static inline mp_timestamp_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date, + mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { + return timeutils_seconds_since_1970(year, month, date, hour, minute, second); } // Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. -static inline uint64_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { - return timeutils_mktime_2000(year, month, mday, hours, minutes, seconds) + TIMEUTILS_SECONDS_1970_TO_2000; +static inline mp_timestamp_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { + return timeutils_mktime_1970(year, month, mday, hours, minutes, seconds); } -// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. -static inline uint64_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, - mp_uint_t date, mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { - // TODO this will give incorrect results for dates before 2000/1/1 - return timeutils_seconds_since_2000(year, month, date, hour, minute, second) + TIMEUTILS_SECONDS_1970_TO_2000; +static inline mp_timestamp_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(int64_t ns) { + return (mp_timestamp_t)(ns / 1000000000LL); } -static inline mp_uint_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(uint64_t ns) { - return (mp_uint_t)(ns / 1000000000ULL); +static inline int64_t timeutils_seconds_since_epoch_to_nanoseconds_since_1970(mp_timestamp_t s) { + return (int64_t)s * 1000000000LL; } -static inline uint64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(uint64_t ns) { +static inline int64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(int64_t ns) { return ns; } #else // Epoch is 2000 -#define timeutils_seconds_since_epoch_to_struct_time timeutils_seconds_since_2000_to_struct_time -#define timeutils_seconds_since_epoch timeutils_seconds_since_2000 -#define timeutils_mktime timeutils_mktime_2000 +static inline void timeutils_seconds_since_epoch_to_struct_time(mp_timestamp_t t, timeutils_struct_time_t *tm) { + timeutils_seconds_since_2000_to_struct_time(t, tm); +} -static inline uint64_t timeutils_seconds_since_epoch_to_nanoseconds_since_1970(mp_uint_t s) { - return ((uint64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000ULL; +// Year is absolute, month/date are 1-based, hour/minute/second are 0-based. +static inline mp_timestamp_t timeutils_seconds_since_epoch(mp_uint_t year, mp_uint_t month, mp_uint_t date, + mp_uint_t hour, mp_uint_t minute, mp_uint_t second) { + return timeutils_seconds_since_2000(year, month, date, hour, minute, second); } -static inline mp_uint_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(uint64_t ns) { - return ns / 1000000000ULL - TIMEUTILS_SECONDS_1970_TO_2000; +// Year is absolute, month/mday are 1-based, hours/minutes/seconds are 0-based. +static inline mp_timestamp_t timeutils_mktime(mp_uint_t year, mp_int_t month, mp_int_t mday, + mp_int_t hours, mp_int_t minutes, mp_int_t seconds) { + return timeutils_mktime_2000(year, month, mday, hours, minutes, seconds); +} + +static inline mp_timestamp_t timeutils_seconds_since_epoch_from_nanoseconds_since_1970(int64_t ns) { + return (mp_timestamp_t)(ns / 1000000000LL - TIMEUTILS_SECONDS_1970_TO_2000); +} + +static inline int64_t timeutils_seconds_since_epoch_to_nanoseconds_since_1970(mp_timestamp_t s) { + return ((int64_t)s + TIMEUTILS_SECONDS_1970_TO_2000) * 1000000000LL; } static inline int64_t timeutils_nanoseconds_since_epoch_to_nanoseconds_since_1970(int64_t ns) { - return ns + TIMEUTILS_SECONDS_1970_TO_2000 * 1000000000ULL; + return ns + TIMEUTILS_SECONDS_1970_TO_2000 * 1000000000LL; } #endif -int timeutils_calc_weekday(int y, int m, int d); - #endif // MICROPY_INCLUDED_LIB_TIMEUTILS_TIMEUTILS_H diff --git a/supervisor/port.h b/supervisor/port.h index 192307a5f57..4a6ff4c8d1d 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -24,13 +24,13 @@ extern uint32_t _ebss; safe_mode_t port_init(void); // Reset the microcontroller completely. -void reset_cpu(void) NORETURN; +void reset_cpu(void) MP_NORETURN; // Reset the microcontroller state. void reset_port(void); // Reset to the bootloader -void reset_to_bootloader(void) NORETURN; +void reset_to_bootloader(void) MP_NORETURN; // Get stack limit address uint32_t *port_stack_get_limit(void); diff --git a/supervisor/shared/safe_mode.h b/supervisor/shared/safe_mode.h index 8f4037cbe20..87f65d867ea 100644 --- a/supervisor/shared/safe_mode.h +++ b/supervisor/shared/safe_mode.h @@ -38,6 +38,6 @@ void set_safe_mode(safe_mode_t safe_mode); safe_mode_t wait_for_safe_mode_reset(void); void safe_mode_on_next_reset(safe_mode_t reason); -void reset_into_safe_mode(safe_mode_t reason) NORETURN; +void reset_into_safe_mode(safe_mode_t reason) MP_NORETURN; void print_safe_mode_message(safe_mode_t reason); diff --git a/tests/README.md b/tests/README.md index 21e14eee5e1..534e7e0a059 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,7 @@ # MicroPython Test Suite -This directory contains tests for most parts of MicroPython. +This directory contains tests for most parts of MicroPython. To run it you will need +CPython 3.8.2 or newer, which is used to validate MicroPython's behaviour. To run all stable tests, run the "run-tests.py" script in this directory. By default that will run the test suite against the unix port of MicroPython. @@ -67,16 +68,14 @@ for a full list of command line options. ### Benchmarking a target -To run tests on a firmware target using `pyboard.py`, run the command line like +To run tests on a firmware target using a serial port, run the command line like this: ``` -./run-perfbench.py -p -d /dev/ttyACM0 168 100 +./run-perfbench.py -t /dev/ttyACM0 168 100 ``` -* `-p` indicates running on a remote target via pyboard.py, not the host. -* `-d PORTNAME` is the serial port, `/dev/ttyACM0` is the default if not - provided. +* `-t PORTNAME` is the serial port to use (and it supports shorthand like `a0`). * `168` is value `N`, the approximate CPU frequency in MHz (in this case Pyboard V1.1 is 168MHz). It's possible to choose other values as well: lower values like `10` will run much the tests much quicker, higher values like `1000` will @@ -136,11 +135,11 @@ Usually you want to know if something is faster or slower than a reference. To do this, copy the output of each `run-perfbench.py` run to a text file. This can be done multiple ways, but one way on Linux/macOS is with the `tee` -utility: `./run-perfbench.py -p 168 100 | tee pyb-run1.txt` +utility: `./run-perfbench.py -t a0 168 100 | tee pyb-run1.txt` Once you have two files with output from two different runs (maybe with different code or configuration), compare the runtimes with `./run-perfbench.py --t pybv-run1.txt pybv-run2.txt` or compare scores with `./run-perfbench.py -s +-m pybv-run1.txt pybv-run2.txt` or compare scores with `./run-perfbench.py -s pybv-run1.txt pybv-run2.txt`: ``` @@ -204,6 +203,18 @@ internal_bench/bytebuf: 1 tests performed (3 individual testcases) ``` +## Serial reliability and performance test + +Serial port reliability and performance can be tested using the `serial_test.py` script. +Pass the name of the port to test against, for example: + + $ ./serial_test.py -t /dev/ttyACM0 + +If no port is specified then `/dev/ttyACM0` is used as the default. + +The test will send data out to the target, and receive data from the target, in various +chunk sizes. The throughput of the serial connection will be reported for each sub-test. + ## Test key/certificates SSL/TLS tests in `multi_net` and `net_inet` use self-signed key/cert pairs diff --git a/tests/basics/annotate_var.py.exp b/tests/basics/annotate_var.py.exp deleted file mode 100644 index 9b6536e966b..00000000000 --- a/tests/basics/annotate_var.py.exp +++ /dev/null @@ -1,5 +0,0 @@ -False -1 -(1, 2) -NameError -1 diff --git a/tests/basics/array_add.py b/tests/basics/array_add.py index 76ce59f761e..e78615541c3 100644 --- a/tests/basics/array_add.py +++ b/tests/basics/array_add.py @@ -14,3 +14,9 @@ a1.extend(array.array('I', [5])) print(a1) + +a1.extend([6, 7]) +print(a1) + +a1.extend(i for i in (8, 9)) +print(a1) diff --git a/tests/basics/assign_expr.py.exp b/tests/basics/assign_expr.py.exp deleted file mode 100644 index 47da56b80d4..00000000000 --- a/tests/basics/assign_expr.py.exp +++ /dev/null @@ -1,16 +0,0 @@ -4 -True -2 -4 5 -5 -1 5 5 -5 -2 1 -1 0 -any True -8 -123 -any True -8 -[(1, 0), (2, 2), (3, 6), (4, 12)] -4 diff --git a/tests/basics/assign_expr_scope.py.exp b/tests/basics/assign_expr_scope.py.exp deleted file mode 100644 index 5c780b38221..00000000000 --- a/tests/basics/assign_expr_scope.py.exp +++ /dev/null @@ -1,23 +0,0 @@ -scope0 -1 -None -scope1 -[1] -1 -None -scope2 -[0, 1] -1 -1 -scope3 -[0, 1] -None -None -scope4 -[0, 1] -1 -1 -scope5 -[0, 1] -1 -None diff --git a/tests/basics/async_await.py.exp b/tests/basics/async_await.py.exp deleted file mode 100644 index b51c388a933..00000000000 --- a/tests/basics/async_await.py.exp +++ /dev/null @@ -1,32 +0,0 @@ -4 -3 -2 -1 -0 -0 -1 -0 -0 -2 -1 -0 -0 -1 -0 -0 -3 -2 -1 -0 -0 -1 -0 -0 -2 -1 -0 -0 -1 -0 -0 -finished diff --git a/tests/basics/async_await2.py.exp b/tests/basics/async_await2.py.exp deleted file mode 100644 index fc9ff0aa535..00000000000 --- a/tests/basics/async_await2.py.exp +++ /dev/null @@ -1,5 +0,0 @@ -wait value: 1 -return from send: message from wait(1) -wait got back: message from main -x = 100 -got StopIteration diff --git a/tests/basics/async_def.py.exp b/tests/basics/async_def.py.exp deleted file mode 100644 index f555ace99ab..00000000000 --- a/tests/basics/async_def.py.exp +++ /dev/null @@ -1,3 +0,0 @@ -decorator -foo -StopIteration diff --git a/tests/basics/async_for.py.exp b/tests/basics/async_for.py.exp deleted file mode 100644 index 6f59979c065..00000000000 --- a/tests/basics/async_for.py.exp +++ /dev/null @@ -1,51 +0,0 @@ -== start == -init -aiter -init -anext -a -anext -b -anext -c -anext -== finish == -== start == -init -aiter -init -anext -d -anext -e -anext -f -anext -AsyncIteratorWrapper-def -== finish == -init -== start == -aiter -init -anext -g -anext -h -anext -i -anext -AsyncIteratorWrapper-ghi -== finish == -init -== start == -aiter -init -anext -j -anext -k -anext -l -anext -AsyncIteratorWrapper-jkl -== finish == diff --git a/tests/basics/async_for2.py b/tests/basics/async_for2.py index bbdb02c49b2..82232d52fc2 100644 --- a/tests/basics/async_for2.py +++ b/tests/basics/async_for2.py @@ -1,7 +1,7 @@ # test waiting within "async for" __anext__ function # CIRCUITPY-CHANGE -# uPy allows normal generators to be awaitables. +# MicroPython allows normal generators to be awaitables. # CircuitPython does not. # In CircuitPython you need to have an __await__ method on an awaitable like in CPython; # and like in CPython, generators do not have __await__. diff --git a/tests/basics/async_for2.py.exp b/tests/basics/async_for2.py.exp deleted file mode 100644 index 52bbe90c853..00000000000 --- a/tests/basics/async_for2.py.exp +++ /dev/null @@ -1,32 +0,0 @@ -init -aiter -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -x 0 -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -x 1 -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -x 2 -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -x 3 -anext -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -finished diff --git a/tests/basics/async_syntaxerror.py.exp b/tests/basics/async_syntaxerror.py.exp deleted file mode 100644 index 5275689b413..00000000000 --- a/tests/basics/async_syntaxerror.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -SyntaxError -SyntaxError diff --git a/tests/basics/async_with.py.exp b/tests/basics/async_with.py.exp deleted file mode 100644 index 6bbf84cb4b5..00000000000 --- a/tests/basics/async_with.py.exp +++ /dev/null @@ -1,11 +0,0 @@ -enter -body -exit None None -finished -enter -1 -exit error -ValueError -enter -exit -BaseException diff --git a/tests/basics/async_with2.py b/tests/basics/async_with2.py index 5bac38236fe..b18fa6bdee1 100644 --- a/tests/basics/async_with2.py +++ b/tests/basics/async_with2.py @@ -1,7 +1,7 @@ # test waiting within async with enter/exit functions # CIRCUITPY-CHANGE -# uPy allows normal generators to be awaitables. +# MicroPython allows normal generators to be awaitables. # CircuitPython does not. # In CircuitPython you need to have an __await__ method on an awaitable like in CPython; # and like in CPython, generators do not have __await__. diff --git a/tests/basics/async_with2.py.exp b/tests/basics/async_with2.py.exp deleted file mode 100644 index 76b173b4c24..00000000000 --- a/tests/basics/async_with2.py.exp +++ /dev/null @@ -1,17 +0,0 @@ -enter -f start: 10 -coro yielded: 11 -coro yielded: 12 -f returned: 13 -body start -f start: 30 -coro yielded: 31 -coro yielded: 32 -body f returned: 33 -body end -exit None None -f start: 20 -coro yielded: 21 -coro yielded: 22 -f returned: 23 -finished diff --git a/tests/basics/async_with_break.py.exp b/tests/basics/async_with_break.py.exp deleted file mode 100644 index d077a88fad0..00000000000 --- a/tests/basics/async_with_break.py.exp +++ /dev/null @@ -1,15 +0,0 @@ -enter -body -exit None None -finished -enter -body -exit None None -finally -finished -enter -body -exit None None -finally inner -finally outer -finished diff --git a/tests/basics/async_with_return.py.exp b/tests/basics/async_with_return.py.exp deleted file mode 100644 index d077a88fad0..00000000000 --- a/tests/basics/async_with_return.py.exp +++ /dev/null @@ -1,15 +0,0 @@ -enter -body -exit None None -finished -enter -body -exit None None -finally -finished -enter -body -exit None None -finally inner -finally outer -finished diff --git a/tests/basics/attrtuple2.py b/tests/basics/attrtuple2.py new file mode 100644 index 00000000000..081d24b6ae9 --- /dev/null +++ b/tests/basics/attrtuple2.py @@ -0,0 +1,25 @@ +# test os.uname() attrtuple, if available +try: + import os +except ImportError: + print("SKIP") + raise SystemExit + +try: + u = os.uname() +except AttributeError: + print("SKIP") + raise SystemExit + +# test printing of attrtuple +print(str(u).find("machine=") > 0) + +# test read attr +print(isinstance(u.machine, str)) + +# test str modulo operator for attrtuple +impl_str = ("%s " * len(u)) % u +test_str = "" +for val in u: + test_str += val + " " +print(impl_str == test_str) diff --git a/tests/basics/boundmeth1.py b/tests/basics/boundmeth1.py index fe1b454688d..9f08d9bbb25 100644 --- a/tests/basics/boundmeth1.py +++ b/tests/basics/boundmeth1.py @@ -1,6 +1,6 @@ # tests basics of bound methods -# uPy and CPython differ when printing a bound method, so just print the type +# MicroPython and CPython differ when printing a bound method, so just print the type print(type(repr([].append))) diff --git a/tests/basics/builtin_help.py b/tests/basics/builtin_help.py index 6ec39653fe9..3d4e4f26bd2 100644 --- a/tests/basics/builtin_help.py +++ b/tests/basics/builtin_help.py @@ -14,4 +14,10 @@ help(micropython) # help for a module help('modules') # list available modules +class A: + x = 1 + y = 2 + del x +help(A) + print('done') # so last bit of output is predictable diff --git a/tests/basics/builtin_pow3_intbig.py b/tests/basics/builtin_pow3_intbig.py index bedc8b36b7e..41d2acbc0cc 100644 --- a/tests/basics/builtin_pow3_intbig.py +++ b/tests/basics/builtin_pow3_intbig.py @@ -20,3 +20,8 @@ print(hex(pow(y, x-1, x))) # Should be 1, since x is prime print(hex(pow(y, y-1, x))) # Should be a 'big value' print(hex(pow(y, y-1, y))) # Should be a 'big value' + +try: + print(pow(1, 2, 0)) +except ValueError: + print("ValueError") diff --git a/tests/basics/builtin_range.py b/tests/basics/builtin_range.py index 66226bad16a..9608a816310 100644 --- a/tests/basics/builtin_range.py +++ b/tests/basics/builtin_range.py @@ -32,13 +32,29 @@ print(range(1, 4)[0:]) print(range(1, 4)[1:]) print(range(1, 4)[:-1]) +print(range(4, 1)[:]) +print(range(4, 1)[0:]) +print(range(4, 1)[1:]) +print(range(4, 1)[:-1]) print(range(7, -2, -4)[:]) print(range(1, 100, 5)[5:15:3]) print(range(1, 100, 5)[15:5:-3]) print(range(100, 1, -5)[5:15:3]) print(range(100, 1, -5)[15:5:-3]) +print(range(1, 100, 5)[5:15:-3]) +print(range(1, 100, 5)[15:5:3]) +print(range(100, 1, -5)[5:15:-3]) +print(range(100, 1, -5)[15:5:3]) +print(range(1, 100, 5)[5:15:3]) +print(range(1, 100, 5)[15:5:-3]) +print(range(1, 100, -5)[5:15:3]) +print(range(1, 100, -5)[15:5:-3]) +print(range(1, 100, 5)[5:15:-3]) +print(range(1, 100, 5)[15:5:3]) +print(range(1, 100, -5)[5:15:-3]) +print(range(1, 100, -5)[15:5:3]) -# for this case uPy gives a different stop value but the listed elements are still correct +# for this case MicroPython gives a different stop value but the listed elements are still correct print(list(range(7, -2, -4)[2:-2:])) # zero step diff --git a/tests/basics/builtin_range_maxsize.py b/tests/basics/builtin_range_maxsize.py new file mode 100644 index 00000000000..b0f3a5e5129 --- /dev/null +++ b/tests/basics/builtin_range_maxsize.py @@ -0,0 +1,38 @@ +try: + from sys import maxsize +except ImportError: + print("SKIP") + raise SystemExit + +# Test the range builtin at extreme values. (https://github.com/micropython/micropython/issues/17684) +# +# This is written using asserts instead of prints because the value of `maxsize` differs. +# +# Numbers & counts right up against the max of mp_int_t also cause overflows, such as +# objrange.c:115:14: runtime error: signed integer overflow: 9223372036854775807 + 1 cannot be represented in type 'long int' +# so just avoid them for the purposes of this test. + +r = range(-maxsize + 1, -1) +assert r.start == -maxsize + 1 +assert r.stop == -1 +assert r[0] == -maxsize + 1 +assert r[1] == -maxsize + 2 +assert r[-1] == -2 +assert r[-2] == -3 + +ir = iter(r) +assert next(ir) == -maxsize + 1 +assert next(ir) == -maxsize + 2 + +r = range(0, maxsize - 1) +assert len(r) == maxsize - 1 +assert r.stop == maxsize - 1 + +r = range(maxsize, 0, -1) +assert len(r) == maxsize +assert r.start == maxsize +assert r[0] == maxsize +assert r[1] == maxsize - 1 +ir = iter(r) +assert next(ir) == maxsize +assert next(ir) == maxsize - 1 diff --git a/tests/basics/builtin_setattr.py b/tests/basics/builtin_setattr.py index e4acb14cac3..2c9a452c327 100644 --- a/tests/basics/builtin_setattr.py +++ b/tests/basics/builtin_setattr.py @@ -21,5 +21,5 @@ def __init__(self): try: setattr(int, 'to_bytes', 1) except (AttributeError, TypeError): - # uPy raises AttributeError, CPython raises TypeError + # MicroPython raises AttributeError, CPython raises TypeError print('AttributeError/TypeError') diff --git a/tests/basics/builtin_slice.py b/tests/basics/builtin_slice.py index 3ff3c3dd04d..7f548ee3358 100644 --- a/tests/basics/builtin_slice.py +++ b/tests/basics/builtin_slice.py @@ -1,11 +1,44 @@ # test builtin slice +# ensures that slices passed to user types are heap-allocated and can be +# safely stored as well as not overriden by subsequent slices. + # print slice class A: def __getitem__(self, idx): - print(idx) + print("get", idx) + print("abc"[1:]) + print("get", idx) + return idx + + def __setitem__(self, idx, value): + print("set", idx) + print("abc"[1:]) + print("set", idx) + self.saved_idx = idx + return idx + + def __delitem__(self, idx): + print("del", idx) + print("abc"[1:]) + print("del", idx) return idx -s = A()[1:2:3] + + +a = A() +s = a[1:2:3] +a[4:5:6] = s +del a[7:8:9] + +print(a.saved_idx) + +# nested slicing +print(A()[1 : A()[A()[2:3:4] : 5]]) + +# tuple slicing +a[1:2, 4:5, 7:8] +a[1, 4:5, 7:8, 2] +a[1:2, a[3:4], 5:6] # check type print(type(s) is slice) diff --git a/tests/basics/bytes_format_modulo.py.exp b/tests/basics/bytes_format_modulo.py.exp deleted file mode 100644 index 782b7f91fcb..00000000000 --- a/tests/basics/bytes_format_modulo.py.exp +++ /dev/null @@ -1,5 +0,0 @@ -b'%' -b'=1=' -b'=1=2=' -b'=str=' -b"=b'str'=" diff --git a/tests/basics/class_bind_self.py b/tests/basics/class_bind_self.py index 813f876446e..8bece902ca2 100644 --- a/tests/basics/class_bind_self.py +++ b/tests/basics/class_bind_self.py @@ -52,7 +52,7 @@ def f4(self, arg): # generator print(C.f8(13)) print(C.f9(14)) -# not working in uPy +# not working in MicroPython #class C(list): # # this acts like a method and binds self # f1 = list.extend diff --git a/tests/basics/class_descriptor.py b/tests/basics/class_descriptor.py index 83d31674301..feaed2fbb2a 100644 --- a/tests/basics/class_descriptor.py +++ b/tests/basics/class_descriptor.py @@ -1,22 +1,28 @@ class Descriptor: def __get__(self, obj, cls): - print('get') + print("get") print(type(obj) is Main) print(cls is Main) - return 'result' + return "result" def __set__(self, obj, val): - print('set') + print("set") print(type(obj) is Main) print(val) def __delete__(self, obj): - print('delete') + print("delete") print(type(obj) is Main) + def __set_name__(self, owner, name): + print("set_name", name) + print(owner.__name__ == "Main") + + class Main: Forward = Descriptor() + m = Main() try: m.__class__ @@ -26,15 +32,15 @@ class Main: raise SystemExit r = m.Forward -if 'Descriptor' in repr(r.__class__): +if "Descriptor" in repr(r.__class__): # Target doesn't support descriptors. - print('SKIP') + print("SKIP") raise SystemExit # Test assignment and deletion. print(r) -m.Forward = 'a' +m.Forward = "a" del m.Forward # Test that lookup of descriptors like __get__ are not passed into __getattr__. diff --git a/tests/basics/class_inplace_op2.py.exp b/tests/basics/class_inplace_op2.py.exp deleted file mode 100644 index 8c323b5178e..00000000000 --- a/tests/basics/class_inplace_op2.py.exp +++ /dev/null @@ -1,12 +0,0 @@ -__imul__ -__imatmul__ -__ifloordiv__ -__itruediv__ -__imod__ -__ipow__ -__ior__ -__ixor__ -__iand__ -__ilshift__ -__irshift__ -TypeError diff --git a/tests/basics/class_ordereddict.py.exp b/tests/basics/class_ordereddict.py.exp deleted file mode 100644 index b723e327515..00000000000 --- a/tests/basics/class_ordereddict.py.exp +++ /dev/null @@ -1 +0,0 @@ -['a', 'b', 'c', 'd', 'e'] diff --git a/tests/basics/class_setname_hazard.py b/tests/basics/class_setname_hazard.py new file mode 100644 index 00000000000..77c04093462 --- /dev/null +++ b/tests/basics/class_setname_hazard.py @@ -0,0 +1,182 @@ +# Test that __set_name__ can access and mutate its owner argument. + + +def skip_if_no_descriptors(): + class Descriptor: + def __get__(self, obj, cls): + return + + class TestClass: + Forward = Descriptor() + + a = TestClass() + try: + a.__class__ + except AttributeError: + # Target doesn't support __class__. + print("SKIP") + raise SystemExit + + b = a.Forward + if "Descriptor" in repr(b.__class__): + # Target doesn't support descriptors. + print("SKIP") + raise SystemExit + + +skip_if_no_descriptors() + + +# Test basic accesses and mutations. + + +class GetSibling: + def __set_name__(self, owner, name): + print(getattr(owner, name + "_sib")) + + +class GetSiblingTest: + desc = GetSibling() + desc_sib = 111 + + +t110 = GetSiblingTest() + + +class SetSibling: + def __set_name__(self, owner, name): + setattr(owner, name + "_sib", 121) + + +class SetSiblingTest: + desc = SetSibling() + + +t120 = SetSiblingTest() + +print(t120.desc_sib) + + +class DelSibling: + def __set_name__(self, owner, name): + delattr(owner, name + "_sib") + + +class DelSiblingTest: + desc = DelSibling() + desc_sib = 131 + + +t130 = DelSiblingTest() + +try: + print(t130.desc_sib) +except AttributeError: + print("AttributeError") + + +class GetSelf: + x = 211 + + def __set_name__(self, owner, name): + print(getattr(owner, name).x) + + +class GetSelfTest: + desc = GetSelf() + + +t210 = GetSelfTest() + + +class SetSelf: + def __set_name__(self, owner, name): + setattr(owner, name, 221) + + +class SetSelfTest: + desc = SetSelf() + + +t220 = SetSelfTest() + +print(t220.desc) + + +class DelSelf: + def __set_name__(self, owner, name): + delattr(owner, name) + + +class DelSelfTest: + desc = DelSelf() + + +t230 = DelSelfTest() + +try: + print(t230.desc) +except AttributeError: + print("AttributeError") + + +# Test exception behavior. + + +class Raise: + def __set_name__(self, owner, name): + raise Exception() + + +try: + + class RaiseTest: + desc = Raise() +except Exception as e: # CPython raises RuntimeError, MicroPython propagates the original exception + print("Exception") + + +# Ensure removed/overwritten class members still get __set_name__ called. + + +class SetSpecific: + def __init__(self, sib_name, sib_replace): + self.sib_name = sib_name + self.sib_replace = sib_replace + + def __set_name__(self, owner, name): + setattr(owner, self.sib_name, self.sib_replace) + + +class SetReplaceTest: + a = SetSpecific("b", 312) # one of these is changed first + b = SetSpecific("a", 311) + + +t310 = SetReplaceTest() +print(t310.a) +print(t310.b) + + +class DelSpecific: + def __init__(self, sib_name): + self.sib_name = sib_name + + def __set_name__(self, owner, name): + delattr(owner, self.sib_name) + + +class DelReplaceTest: + a = DelSpecific("b") # one of these is removed first + b = DelSpecific("a") + + +t320 = DelReplaceTest() +try: + print(t320.a) +except AttributeError: + print("AttributeError") +try: + print(t320.b) +except AttributeError: + print("AttributeError") diff --git a/tests/basics/class_setname_hazard_rand.py b/tests/basics/class_setname_hazard_rand.py new file mode 100644 index 00000000000..4c9934c3bf0 --- /dev/null +++ b/tests/basics/class_setname_hazard_rand.py @@ -0,0 +1,111 @@ +# Test to make sure there's no sequence hazard even when a __set_name__ implementation +# mutates and reorders the namespace of its owner class. +# VERY hard bug to prove out except via a stochastic test. + + +try: + from random import choice + import re +except ImportError: + print("SKIP") + raise SystemExit + + +def skip_if_no_descriptors(): + class Descriptor: + def __get__(self, obj, cls): + return + + class TestClass: + Forward = Descriptor() + + a = TestClass() + try: + a.__class__ + except AttributeError: + # Target doesn't support __class__. + print("SKIP") + raise SystemExit + + b = a.Forward + if "Descriptor" in repr(b.__class__): + # Target doesn't support descriptors. + print("SKIP") + raise SystemExit + + +skip_if_no_descriptors() + +letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +# Would be r"[A-Z]{5}", but not all ports support the {n} quantifier. +junk_re = re.compile(r"[A-Z][A-Z][A-Z][A-Z][A-Z]") + + +def junk_fill(obj, n=10): # Add randomly-generated attributes to an object. + for i in range(n): + name = "".join(choice(letters) for j in range(5)) + setattr(obj, name, object()) + + +def junk_clear(obj): # Remove attributes added by junk_fill. + to_del = [name for name in dir(obj) if junk_re.match(name)] + for name in to_del: + delattr(obj, name) + + +def junk_sequencer(): + global runs + try: + while True: + owner, name = yield + runs[name] = runs.get(name, 0) + 1 + junk_fill(owner) + finally: + junk_clear(owner) + + +class JunkMaker: + def __set_name__(self, owner, name): + global seq + seq.send((owner, name)) + + +runs = {} +seq = junk_sequencer() +next(seq) + + +class Main: + a = JunkMaker() + b = JunkMaker() + c = JunkMaker() + d = JunkMaker() + e = JunkMaker() + f = JunkMaker() + g = JunkMaker() + h = JunkMaker() + i = JunkMaker() + j = JunkMaker() + k = JunkMaker() + l = JunkMaker() + m = JunkMaker() + n = JunkMaker() + o = JunkMaker() + p = JunkMaker() + q = JunkMaker() + r = JunkMaker() + s = JunkMaker() + t = JunkMaker() + u = JunkMaker() + v = JunkMaker() + w = JunkMaker() + x = JunkMaker() + y = JunkMaker() + z = JunkMaker() + + +seq.close() + +for k in letters.lower(): + print(k, runs.get(k, 0)) diff --git a/tests/basics/del_attr.py b/tests/basics/del_attr.py index 8487b97e311..90a8a5a6f83 100644 --- a/tests/basics/del_attr.py +++ b/tests/basics/del_attr.py @@ -35,5 +35,5 @@ def f(): try: del int.to_bytes except (AttributeError, TypeError): - # uPy raises AttributeError, CPython raises TypeError + # MicroPython raises AttributeError, CPython raises TypeError print('AttributeError/TypeError') diff --git a/tests/basics/del_global.py b/tests/basics/del_global.py index d740357b033..e1aa074b97a 100644 --- a/tests/basics/del_global.py +++ b/tests/basics/del_global.py @@ -14,7 +14,7 @@ def do_del(): try: do_del() except: # NameError: - # FIXME uPy returns KeyError for this + # FIXME MicroPython returns KeyError for this print("NameError") # delete globals using a list diff --git a/tests/basics/del_name.py b/tests/basics/del_name.py index c92be54d3b6..8393b2df92a 100644 --- a/tests/basics/del_name.py +++ b/tests/basics/del_name.py @@ -10,7 +10,7 @@ try: del x except: # NameError: - # FIXME uPy returns KeyError for this + # FIXME MicroPython returns KeyError for this print("NameError") class C: diff --git a/tests/basics/dict_views.py b/tests/basics/dict_views.py index a82f47b6be2..45f3238f1c6 100644 --- a/tests/basics/dict_views.py +++ b/tests/basics/dict_views.py @@ -6,6 +6,11 @@ # print a view with more than one item print({1:1, 2:1}.values()) +# `bool` and `len` unary ops +for d in ({}, {1: 2}, {1: 2, 3: 4}): + for op in (bool, len): + print(op(d.keys()), op(d.values()), op(d.items())) + # unsupported binary op on a dict values view try: {1:1}.values() + 1 diff --git a/tests/basics/exception_chain.py b/tests/basics/exception_chain.py index 579756c85fa..96c06c847ab 100644 --- a/tests/basics/exception_chain.py +++ b/tests/basics/exception_chain.py @@ -1,5 +1,12 @@ # CIRCUITPY-CHANGE: exception chaining is supported +import sys + +# The unix minimal build doesn't enable MICROPY_WARNINGS (required for this test). +if getattr(sys.implementation, "_build", None) == "minimal": + print("SKIP") + raise SystemExit + try: Exception().__cause__ except AttributeError: diff --git a/tests/basics/frozenset_set.py b/tests/basics/frozenset_set.py index 3bf456acfd7..2b3c6832609 100644 --- a/tests/basics/frozenset_set.py +++ b/tests/basics/frozenset_set.py @@ -8,5 +8,5 @@ # "Instances of set are compared to instances of frozenset based on their # members. For example:" print(set('abc') == frozenset('abc')) -# This doesn't work in uPy +# This doesn't work in MicroPython #print(set('abc') in set([frozenset('abc')])) diff --git a/tests/basics/fun_code_colines.py b/tests/basics/fun_code_colines.py new file mode 100644 index 00000000000..a8867770edd --- /dev/null +++ b/tests/basics/fun_code_colines.py @@ -0,0 +1,81 @@ +# Check that we have sensical bytecode offsets in function.__code__.co_lines + +def f1(x, y, obj, obj2, obj3): + a = x + y # line 4: bc+4 line+4 + b = x - y # line 5: bc+4 line+1 + # line 6 + # line 7 + # line 8 + # line 9 + # line 10 + # line 11 + # line 12 + # line 13 + # line 14 + # line 15 + # line 16 + # line 17 + # line 18 + # line 19 + c = a * b # line 20: bc+4 line+15 + obj.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.fun() # line 21: bc+31 line+1; bc+27 line+0 + # line 22 + # line 23 + # line 24: bc+0 line+3 + # line 25 + # line 26 + # line 27: bc+0 line+3 + # line 28 + # line 29 + obj2.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.fun() # line 30: bc+31 line+3; bc+27 line+0 + # line 31 + # line 32 + # line 33: bc+0 line+3 + # line 34 + # line 35 + # line 36 + # line 37 + # line 38 + # line 39 + # line 40 + # line 41 + # line 42 + # line 43 + # line 44 + # line 45 + # line 46 + # line 47 + # line 48 + # line 49 + # line 50 + # line 51 + # line 52 + # line 53 + # line 54 + # line 55 + # line 56 + # line 57 + # line 58 + # line 59 + return obj3.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.fun() # line 60: bc+31 line+27; bc+27 line+0 + +def f2(x, y): + a = x + y # line 63 + b = x - y # line 64 + return a * b # line 65 + +try: + f1.__code__.co_lines +except AttributeError: + print("SKIP") + raise SystemExit + +print("f1") +for start, end, line_no in f1.__code__.co_lines(): + print("line {} start: {}".format(line_no, start)) + print("line {} end: {}".format(line_no, end)) + +print("f2") +for start, end, line_no in f2.__code__.co_lines(): + print("line {} start: {}".format(line_no, start)) + print("line {} end: {}".format(line_no, end)) diff --git a/tests/basics/fun_code_colines.py.exp b/tests/basics/fun_code_colines.py.exp new file mode 100644 index 00000000000..19bd4ef6e2a --- /dev/null +++ b/tests/basics/fun_code_colines.py.exp @@ -0,0 +1,20 @@ +f1 +line 4 start: 0 +line 4 end: 4 +line 5 start: 4 +line 5 end: 8 +line 20 start: 8 +line 20 end: 12 +line 21 start: 12 +line 21 end: 70 +line 30 start: 70 +line 30 end: 128 +line 60 start: 128 +line 60 end: 186 +f2 +line 63 start: 0 +line 63 end: 4 +line 64 start: 4 +line 64 end: 8 +line 65 start: 8 +line 65 end: 12 diff --git a/tests/basics/fun_code_full.py b/tests/basics/fun_code_full.py new file mode 100644 index 00000000000..e1c867939a2 --- /dev/null +++ b/tests/basics/fun_code_full.py @@ -0,0 +1,40 @@ +# Test function.__code__ attributes not available with MICROPY_PY_BUILTINS_CODE <= MICROPY_PY_BUILTINS_CODE_BASIC + +try: + (lambda: 0).__code__.co_code +except AttributeError: + print("SKIP") + raise SystemExit + +def f(x, y): + a = x + y + b = x - y + return a * b + +code = f.__code__ + +print(type(code.co_code)) # both bytes (but mpy and cpy have different instruction sets) +print(code.co_consts) # (not necessarily the same set, but in this function they are) +print(code.co_filename.rsplit('/')[-1]) # same terminal filename but might be different paths on other ports +print(type(code.co_firstlineno)) # both ints (but mpy points to first line inside, cpy points to declaration) +print(code.co_name) +print(iter(code.co_names) is not None) # both iterable (but mpy returns dict with names as keys, cpy only the names; and not necessarily the same set) + +co_lines = code.co_lines() + +l = list(co_lines) +first_start = l[0][0] +last_end = l[-1][1] +print(first_start) # co_lines should start at the start of the bytecode +print(len(code.co_code) - last_end) # and end at the end of the bytecode + +prev_end = 0 +for start, end, line_no in l: + if end != prev_end: + print("non-contiguous") + break # the offset ranges should be contiguous + prev_end = end +else: + print("contiguous") + + diff --git a/tests/basics/fun_code_full.py.exp b/tests/basics/fun_code_full.py.exp new file mode 100644 index 00000000000..830effadfc6 --- /dev/null +++ b/tests/basics/fun_code_full.py.exp @@ -0,0 +1,9 @@ + +(None,) +fun_code_full.py + +f +True +0 +0 +non-contiguous diff --git a/tests/basics/fun_code_lnotab.py b/tests/basics/fun_code_lnotab.py new file mode 100644 index 00000000000..9223e5730f0 --- /dev/null +++ b/tests/basics/fun_code_lnotab.py @@ -0,0 +1,34 @@ +# Test deprecation of co_lnotab + +try: + (lambda: 0).__code__.co_code +except AttributeError: + print("SKIP") + raise SystemExit + + +import unittest +import sys + + +mpy_is_v2 = getattr(sys.implementation, '_v2', False) + + +def f(): + pass + + +class Test(unittest.TestCase): + + @unittest.skipIf(mpy_is_v2, "Removed in MicroPython v2 and later.") + def test_co_lnotab_exists(self): + self.assertIsInstance(f.__code__.co_lnotab, bytes) + + @unittest.skipUnless(mpy_is_v2, "Not removed before MicroPython v2.") + def test_co_lnotab_removed(self): + with self.assertRaises(AttributeError): + f.__code__.co_lnotab + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/basics/fun_name.py b/tests/basics/fun_name.py index b2642280a2a..8aac35eeafa 100644 --- a/tests/basics/fun_name.py +++ b/tests/basics/fun_name.py @@ -16,7 +16,7 @@ def Fun(self): print('SKIP') raise SystemExit -# __name__ of a bound native method is not implemented in uPy +# __name__ of a bound native method is not implemented in MicroPython # the test here is to make sure it doesn't crash try: str((1).to_bytes.__name__) diff --git a/tests/basics/gc1.py b/tests/basics/gc1.py index 332bf9744c0..dff9538b14b 100644 --- a/tests/basics/gc1.py +++ b/tests/basics/gc1.py @@ -15,13 +15,13 @@ gc.collect() if hasattr(gc, 'mem_free'): - # uPy has these extra functions + # MicroPython has these extra functions # just test they execute and return an int assert type(gc.mem_free()) is int assert type(gc.mem_alloc()) is int if hasattr(gc, 'threshold'): - # uPy has this extra function + # MicroPython has this extra function # check execution and returns assert(gc.threshold(1) is None) assert(gc.threshold() == 0) diff --git a/tests/basics/import_instance_method.py b/tests/basics/import_instance_method.py new file mode 100644 index 00000000000..d25b70ac5f0 --- /dev/null +++ b/tests/basics/import_instance_method.py @@ -0,0 +1,38 @@ +# Test importing a method from a class instance. +# This is not a common thing to do, but ensures MicroPython has the same semantics as CPython. + +import sys + +if not hasattr(sys, "modules"): + print("SKIP") + raise SystemExit + + +class A: + def __init__(self, value): + self.value = value + + def meth(self): + return self.value + + def meth_with_arg(self, a): + return [self.value, a] + + +# Register a class instance as the module "mod". +sys.modules["mod"] = A(1) + +# Try importing it as a module. +import mod + +print(mod.meth()) +print(mod.meth_with_arg(2)) + +# Change the module. +sys.modules["mod"] = A(3) + +# Try importing it using "from ... import". +from mod import meth, meth_with_arg + +print(meth()) +print(meth_with_arg(4)) diff --git a/tests/basics/int_64_basics.py b/tests/basics/int_64_basics.py new file mode 100644 index 00000000000..ef76793317e --- /dev/null +++ b/tests/basics/int_64_basics.py @@ -0,0 +1,161 @@ +# test support for 64-bit long integers +# (some ports don't support arbitrary precision but do support these) + +# this test is adapted from int_big1.py with numbers kept within 64-bit signed range + +# to test arbitrary precision integers + +x = 1000000000000000000 +xn = -1000000000000000000 +y = 2000000000000000000 + +# printing +print(x) +print(y) +print('%#X' % (x - x)) # print prefix +print('{:#,}'.format(x)) # print with commas + +# construction +print(int(x)) + +# addition +print(x + 1) +print(x + y) +print(x + xn == 0) +print(bool(x + xn)) + +# subtraction +print(x - 1) +print(x - y) +print(y - x) +print(x - x == 0) +print(bool(x - x)) + +# multiplication +print(x * 2) +print(1090511627776 * 1048500) + +# integer division +print(x // 2) +print(y // x) + +# bit inversion +print(~x) +print(~(-x)) + +# left shift +print("left shift positive") +x = 0x40000000 +for i in range(32): + x = x << 1 + print(x) + +# right shift +print("right shift positive") +x = 0x2000000000000000 # TODO: why can't second-tip bit be set? +for i in range(64): + x = x >> 1 + print(x) + +# left shift of a negative number +print("left shift negative") +for i in range(8): + print(-10000000000000000 << i) + print(-10000000000000001 << i) + print(-10000000000000002 << i) + print(-10000000000000003 << i) + print(-10000000000000004 << i) + + +# right shift of a negative number +print("right shift negative") +for i in range(8): + print(-1000000000000000000 >> i) + print(-1000000000000000001 >> i) + print(-1000000000000000002 >> i) + print(-1000000000000000003 >> i) + print(-1000000000000000004 >> i) + +# conversion from string +print(int("1234567890123456789")) +print(int("-1234567890123456789")) +print(int("1234567890abcdef", 16)) +print(int("1234567890ABCDEF", 16)) +print(int("-1234567890ABCDEF", 16)) +print(int("ijklmnopqrsz", 36)) + +# numbers close to 64-bit limits +print(int("-9111222333444555666")) +print(int("9111222333444555666")) + +# numbers with preceding 0s +print(int("-00000000000000000000009111222333444555666")) +print(int("0000000000000000000000009111222333444555666")) + +# invalid characters in string +try: + print(int("1234567890abcdef")) +except ValueError: + print('ValueError'); +try: + print(int("123456789\x01")) +except ValueError: + print('ValueError'); + +# test parsing ints just on threshold of small to big +# for 32 bit archs +x = 1073741823 # small +x = -1073741823 # small +x = 1073741824 # big +x = -1073741824 # big +# for 64 bit archs +x = 4611686018427387903 # small +x = -4611686018427387903 # small +x = 4611686018427387904 # big +x = -4611686018427387904 # big + +# sys.maxsize is a constant bigint, so test it's compatible with dynamic ones +import sys +if hasattr(sys, "maxsize"): + print(sys.maxsize - 1 + 1 == sys.maxsize) +else: + print(True) # No maxsize property in this config + +# test extraction of big int value via mp_obj_get_int_maybe +x = 1 << 62 +print('a' * (x + 4 - x)) + +# test overflow check in mp_obj_get_int_maybe +x = 1 << 32 +r = None +try: + r = range(0, x) +except OverflowError: + # 32-bit target, correctly handled the overflow of x + print("ok") +if r is not None: + if len(r) == x: + # 64-bit target, everything is just a small-int + print("ok") + else: + # 32-bit target that did not handle the overflow of x + print("unhandled overflow") + +# negative shifts are invalid +try: + print((1 << 48) >> -4) +except ValueError as e: + print(e) + +try: + print((1 << 48) << -6) +except ValueError as e: + print(e) + +# Test that the most extreme 64 bit integer values all parse with int() +print(int("-9223372036854775807")) +print(int("-9223372036854775808")) +print(int("9223372036854775807")) + +# Test that the most negative 64 bit integer can be formed via arithmetic +print(-9223372036854775807-1) diff --git a/tests/basics/int_big_to_small.py b/tests/basics/int_big_to_small.py index 64280d0c635..c92d263fc28 100644 --- a/tests/basics/int_big_to_small.py +++ b/tests/basics/int_big_to_small.py @@ -5,6 +5,17 @@ print("SKIP") raise SystemExit +# Skip this test on "REPR B" where (1<<29 + 1) is not a small int. +k = 1 << 29 +micropython.heap_lock() +try: + k = k + 1 +except MemoryError: + print("SKIP") + raise SystemExit +finally: + micropython.heap_unlock() + # All less than small int max. for d in (0, 27, 1<<29, -1861, -(1<<29)): i = 1<<70 diff --git a/tests/basics/int_big_to_small_int29.py b/tests/basics/int_big_to_small_int29.py new file mode 100644 index 00000000000..438a74d2bc6 --- /dev/null +++ b/tests/basics/int_big_to_small_int29.py @@ -0,0 +1,22 @@ +try: + import micropython + micropython.heap_lock +except: + print("SKIP") + raise SystemExit + +# All less than small int max. +for d in (0, 27, 1<<28, -1861, -(1<<28)): + i = 1<<70 + print(i) + j = (1<<70) + d + print(j) + # k should now be a small int. + k = j - i + print(k) + + # Now verify that working with k doesn't allocate (i.e. it's a small int). + micropython.heap_lock() + print(k + 20) + print(k // 20) + micropython.heap_unlock() diff --git a/tests/basics/int_big_to_small_int29.py.exp b/tests/basics/int_big_to_small_int29.py.exp new file mode 100644 index 00000000000..0920101924a --- /dev/null +++ b/tests/basics/int_big_to_small_int29.py.exp @@ -0,0 +1,25 @@ +1180591620717411303424 +1180591620717411303424 +0 +20 +0 +1180591620717411303424 +1180591620717411303451 +27 +47 +1 +1180591620717411303424 +1180591620717679738880 +268435456 +268435476 +13421772 +1180591620717411303424 +1180591620717411301563 +-1861 +-1841 +-94 +1180591620717411303424 +1180591620717142867968 +-268435456 +-268435436 +-13421773 diff --git a/tests/basics/io_buffered_writer.py b/tests/basics/io_buffered_writer.py index 11df0324e24..31d3eb489c4 100644 --- a/tests/basics/io_buffered_writer.py +++ b/tests/basics/io_buffered_writer.py @@ -1,10 +1,11 @@ -import io +try: + import io try: io.BytesIO io.BufferedWriter -except AttributeError: - print("SKIP") +except (AttributeError, ImportError): + print('SKIP') raise SystemExit bts = io.BytesIO() @@ -28,3 +29,27 @@ # hashing a BufferedWriter print(type(hash(buf))) + +# Test failing flush() +class MyIO(io.IOBase): + def __init__(self): + self.count = 0 + + def write(self, buf): + self.count += 1 + if self.count < 3: + return None + print("writing", buf) + return len(buf) + + +buf = io.BufferedWriter(MyIO(), 8) + +buf.write(b"foobar") + +for _ in range(4): + try: + buf.flush() + print("flushed") + except OSError: + print("OSError") diff --git a/tests/basics/io_buffered_writer.py.exp b/tests/basics/io_buffered_writer.py.exp index 2209348f5af..d61eb148b45 100644 --- a/tests/basics/io_buffered_writer.py.exp +++ b/tests/basics/io_buffered_writer.py.exp @@ -4,3 +4,8 @@ b'foobarfoobar' b'foobarfoobar' b'foo' +OSError +OSError +writing bytearray(b'foobar') +flushed +flushed diff --git a/tests/basics/io_bytesio_cow.py b/tests/basics/io_bytesio_cow.py index 2edb7136a96..543c12ad42a 100644 --- a/tests/basics/io_bytesio_cow.py +++ b/tests/basics/io_bytesio_cow.py @@ -1,6 +1,12 @@ # Make sure that write operations on io.BytesIO don't # change original object it was constructed from. -import io + +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + b = b"foobar" a = io.BytesIO(b) diff --git a/tests/basics/io_bytesio_ext.py b/tests/basics/io_bytesio_ext.py index 4d4c60c1363..92e71517811 100644 --- a/tests/basics/io_bytesio_ext.py +++ b/tests/basics/io_bytesio_ext.py @@ -1,5 +1,11 @@ # Extended stream operations on io.BytesIO -import io + +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + a = io.BytesIO(b"foobar") a.seek(10) print(a.read(10)) diff --git a/tests/basics/io_bytesio_ext2.py b/tests/basics/io_bytesio_ext2.py index 414ac90a3b0..f60a6a9a604 100644 --- a/tests/basics/io_bytesio_ext2.py +++ b/tests/basics/io_bytesio_ext2.py @@ -1,4 +1,9 @@ -import io +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + a = io.BytesIO(b"foobar") try: a.seek(-10) diff --git a/tests/basics/io_iobase.py b/tests/basics/io_iobase.py index b2ee5cd63a6..31f2616310e 100644 --- a/tests/basics/io_iobase.py +++ b/tests/basics/io_iobase.py @@ -1,15 +1,17 @@ import io try: + import io + io.IOBase -except AttributeError: +except (AttributeError, ImportError): print("SKIP") raise SystemExit class MyIO(io.IOBase): def write(self, buf): - # CPython and uPy pass in different types for buf (str vs bytearray) - print("write", len(buf)) + # CPython and MicroPython pass in different types for buf (str vs bytearray) + print('write', len(buf)) return len(buf) -print("test", file=MyIO()) +print('test', file=MyIO()) diff --git a/tests/basics/io_stringio1.py b/tests/basics/io_stringio1.py index 7d355930f5a..889e3ce6973 100644 --- a/tests/basics/io_stringio1.py +++ b/tests/basics/io_stringio1.py @@ -1,4 +1,9 @@ -import io +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + a = io.StringIO() print('io.StringIO' in repr(a)) print(a.getvalue()) diff --git a/tests/basics/io_stringio_base.py b/tests/basics/io_stringio_base.py index 0f65fb3fabc..c8890dab73a 100644 --- a/tests/basics/io_stringio_base.py +++ b/tests/basics/io_stringio_base.py @@ -1,7 +1,11 @@ # Checks that an instance type inheriting from a native base that uses # MP_TYPE_FLAG_ITER_IS_STREAM will still have a getiter. -import io +try: + import io +except ImportError: + print("SKIP") + raise SystemExit a = io.StringIO() a.write("hello\nworld\nmicro\npython\n") diff --git a/tests/basics/io_stringio_with.py b/tests/basics/io_stringio_with.py index a3aa6ec84e0..0155ad5382d 100644 --- a/tests/basics/io_stringio_with.py +++ b/tests/basics/io_stringio_with.py @@ -1,4 +1,9 @@ -import io +try: + import io +except ImportError: + print("SKIP") + raise SystemExit + # test __enter__/__exit__ with io.StringIO() as b: b.write("foo") diff --git a/tests/basics/io_write_ext.py b/tests/basics/io_write_ext.py index 79f7450954e..5af1de7a6c3 100644 --- a/tests/basics/io_write_ext.py +++ b/tests/basics/io_write_ext.py @@ -1,11 +1,12 @@ # This tests extended (MicroPython-specific) form of write: # write(buf, len) and write(buf, offset, len) -import io try: + import io + io.BytesIO -except AttributeError: - print("SKIP") +except (AttributeError, ImportError): + print('SKIP') raise SystemExit buf = io.BytesIO() diff --git a/tests/basics/list_pop.py b/tests/basics/list_pop.py index 87ed456f851..58bcdd91e41 100644 --- a/tests/basics/list_pop.py +++ b/tests/basics/list_pop.py @@ -10,7 +10,7 @@ else: raise AssertionError("No IndexError raised") -# popping such that list storage shrinks (tests implementation detail of uPy) +# popping such that list storage shrinks (tests implementation detail of MicroPython) l = list(range(20)) for i in range(len(l)): l.pop() diff --git a/tests/basics/module2.py b/tests/basics/module2.py index a135601579c..d1dc18930f0 100644 --- a/tests/basics/module2.py +++ b/tests/basics/module2.py @@ -1,4 +1,4 @@ -# uPy behaviour only: builtin modules are read-only +# MicroPython behaviour only: builtin modules are read-only import sys try: sys.x = 1 diff --git a/tests/basics/namedtuple1.py b/tests/basics/namedtuple1.py index 362c60583ec..b9689b58423 100644 --- a/tests/basics/namedtuple1.py +++ b/tests/basics/namedtuple1.py @@ -21,6 +21,9 @@ print(isinstance(t, tuple)) + # a NamedTuple can be used as a tuple + print("(%d, %d)" % t) + # Check tuple can compare equal to namedtuple with same elements print(t == (t[0], t[1]), (t[0], t[1]) == t) diff --git a/tests/basics/parser.py b/tests/basics/parser.py index 626b67ad7a9..6ae5f05ba45 100644 --- a/tests/basics/parser.py +++ b/tests/basics/parser.py @@ -7,7 +7,7 @@ raise SystemExit # completely empty string -# uPy and CPy differ for this case +# MPy and CPy differ for this case #try: # compile("", "stdin", "single") #except SyntaxError: diff --git a/tests/basics/python34.py b/tests/basics/python34.py index 922234d22db..3071b55eff8 100644 --- a/tests/basics/python34.py +++ b/tests/basics/python34.py @@ -28,7 +28,7 @@ def test_syntax(code): test_syntax("del ()") # can't delete empty tuple (in 3.6 we can) # from basics/sys1.py -# uPy prints version 3.4 +# MicroPython prints version 3.4 import sys print(sys.version[:3]) print(sys.version_info[0], sys.version_info[1]) diff --git a/tests/basics/python36.py.exp b/tests/basics/python36.py.exp deleted file mode 100644 index 4b65daafa18..00000000000 --- a/tests/basics/python36.py.exp +++ /dev/null @@ -1,5 +0,0 @@ -100000 -165 -65535 -123 -83 diff --git a/tests/basics/self_type_check.py b/tests/basics/self_type_check.py index 3bd5b3eed60..5f6f6f2ca65 100644 --- a/tests/basics/self_type_check.py +++ b/tests/basics/self_type_check.py @@ -3,6 +3,14 @@ import skip_if skip_if.board_in("gemma_m0", "trinket_m0") +import sys + +# Minimal builds usually don't enable MICROPY_BUILTIN_METHOD_CHECK_SELF_ARG, +# which is required for this test. +if getattr(sys.implementation, "_build", None) == "minimal": + print("SKIP") + raise SystemExit + list.append try: diff --git a/tests/basics/slice_optimise.py b/tests/basics/slice_optimise.py new file mode 100644 index 00000000000..f663e16b8c2 --- /dev/null +++ b/tests/basics/slice_optimise.py @@ -0,0 +1,23 @@ +# Test that the slice-on-stack optimisation does not break various uses of slice +# (see MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE type option). +# +# Note: this test has a corresponding .py.exp file because hashing slice objects +# was not allowed in CPython until 3.12. + +try: + from collections import OrderedDict +except ImportError: + print("SKIP") + raise SystemExit + +# Attempt to index with a slice, error should contain the slice (failed key). +try: + dict()[:] +except KeyError as e: + print("KeyError", e.args) + +# Put a slice and another object into an OrderedDict, and retrieve them. +x = OrderedDict() +x[:"a"] = 1 +x["b"] = 2 +print(list(x.keys()), list(x.values())) diff --git a/tests/basics/slice_optimise.py.exp b/tests/basics/slice_optimise.py.exp new file mode 100644 index 00000000000..3fa59aae15a --- /dev/null +++ b/tests/basics/slice_optimise.py.exp @@ -0,0 +1,2 @@ +KeyError (slice(None, None, None),) +[slice(None, 'a', None), 'b'] [1, 2] diff --git a/tests/basics/special_methods2.py.exp b/tests/basics/special_methods2.py.exp deleted file mode 100644 index a9ae75be55c..00000000000 --- a/tests/basics/special_methods2.py.exp +++ /dev/null @@ -1,19 +0,0 @@ -__pos__ called -__pos__ called -__neg__ called -__invert__ called -__mul__ called -__matmul__ called -__truediv__ called -__floordiv__ called -__iadd__ called -__isub__ called -__mod__ called -__pow__ called -__or__ called -__and__ called -__xor__ called -__lshift__ called -__rshift__ called -['a', 'b', 'c'] -False diff --git a/tests/basics/string_format.py b/tests/basics/string_format.py index e8600f58361..11e7836a73e 100644 --- a/tests/basics/string_format.py +++ b/tests/basics/string_format.py @@ -22,7 +22,17 @@ def test(fmt, *args): test("{:4x}", 123) test("{:4X}", 123) +test("{:4,d}", 1) +test("{:4_d}", 1) +test("{:4_o}", 1) +test("{:4_b}", 1) +test("{:4_x}", 1) + test("{:4,d}", 12345678) +test("{:4_d}", 12345678) +test("{:4_o}", 12345678) +test("{:4_b}", 12345678) +test("{:4_x}", 12345678) test("{:#4b}", 10) test("{:#4o}", 123) diff --git a/tests/basics/string_format_sep.py b/tests/basics/string_format_sep.py new file mode 100644 index 00000000000..de131fdaf33 --- /dev/null +++ b/tests/basics/string_format_sep.py @@ -0,0 +1,9 @@ +try: + "%d" % 1 +except TypeError: + print("SKIP") + raise SystemExit + +for v in (0, 0x10, 0x1000, -0x10, -0x1000): + for sz in range(1, 12): print(("{:0%d,d}" % sz).format(v)) + for sz in range(1, 12): print(("{:0%d_x}" % sz).format(v)) diff --git a/tests/basics/string_fstring_debug.py.exp b/tests/basics/string_fstring_debug.py.exp deleted file mode 100644 index f0309e1c98a..00000000000 --- a/tests/basics/string_fstring_debug.py.exp +++ /dev/null @@ -1,9 +0,0 @@ -x=1 -x=00000001 -a x=1 b 2 c -a x=00000001 b 2 c -a f() + g("foo") + h()=15 b -a f() + g("foo") + h()=0000000f b -a 1,=(1,) b -a x,y,=(1, 2) b -a x,1=(1, 1) b diff --git a/tests/basics/subclass_native_init.py b/tests/basics/subclass_native_init.py index 64167fa037e..102befd551f 100644 --- a/tests/basics/subclass_native_init.py +++ b/tests/basics/subclass_native_init.py @@ -1,5 +1,9 @@ # test subclassing a native type and overriding __init__ +if not hasattr(object, "__init__"): + print("SKIP") + raise SystemExit + # overriding list.__init__() class L(list): def __init__(self, a, b): diff --git a/tests/basics/syntaxerror.py b/tests/basics/syntaxerror.py index c0702cb2452..7b6ef9b7550 100644 --- a/tests/basics/syntaxerror.py +++ b/tests/basics/syntaxerror.py @@ -86,7 +86,7 @@ def test_syntax(code): test_syntax("nonlocal a") test_syntax("await 1") -# error on uPy, warning on CPy +# error on MPy, warning on CPy #test_syntax("def f():\n a = 1\n global a") # default except must be last @@ -98,7 +98,7 @@ def test_syntax(code): # non-keyword after keyword test_syntax("f(a=1, 2)") -# doesn't error on uPy but should +# doesn't error on MPy but should #test_syntax("f(1, i for i in i)") # all elements of dict/set must be pairs or singles diff --git a/tests/basics/sys1.py b/tests/basics/sys1.py index 7f261aa9645..02946abc220 100644 --- a/tests/basics/sys1.py +++ b/tests/basics/sys1.py @@ -31,6 +31,12 @@ # Effectively skip subtests print(str) +if hasattr(sys.implementation, '_thread'): + print(sys.implementation._thread in ("GIL", "unsafe")) +else: + # Effectively skip subtests + print(True) + try: print(sys.intern('micropython') == 'micropython') has_intern = True diff --git a/tests/basics/sys_tracebacklimit.py b/tests/basics/sys_tracebacklimit.py index 3ae372b8d52..6f575fde654 100644 --- a/tests/basics/sys_tracebacklimit.py +++ b/tests/basics/sys_tracebacklimit.py @@ -30,7 +30,7 @@ def print_exc(e): if l.startswith(" File "): l = l.split('"') print(l[0], l[2]) - # uPy and CPy tracebacks differ in that CPy prints a source line for + # MPy and CPy tracebacks differ in that CPy prints a source line for # each traceback entry. In this case, we know that offending line # has 4-space indent, so filter it out. elif not l.startswith(" "): diff --git a/tests/basics/sys_tracebacklimit.py.native.exp b/tests/basics/sys_tracebacklimit.py.native.exp new file mode 100644 index 00000000000..f9d30c05856 --- /dev/null +++ b/tests/basics/sys_tracebacklimit.py.native.exp @@ -0,0 +1,22 @@ +ValueError: value + +limit 4 +ValueError: value + +limit 3 +ValueError: value + +limit 2 +ValueError: value + +limit 1 +ValueError: value + +limit 0 +ValueError: value + +limit -1 +ValueError: value + +True +False diff --git a/tests/basics/try_finally_continue.py.exp b/tests/basics/try_finally_continue.py.exp deleted file mode 100644 index 2901997b1aa..00000000000 --- a/tests/basics/try_finally_continue.py.exp +++ /dev/null @@ -1,9 +0,0 @@ -4 0 -continue -4 1 -continue -4 2 -continue -4 3 -continue -None diff --git a/tests/basics/tuple1.py b/tests/basics/tuple1.py index 72bb3f01bff..70ae071898e 100644 --- a/tests/basics/tuple1.py +++ b/tests/basics/tuple1.py @@ -17,7 +17,7 @@ x += (10, 11, 12) print(x) -# construction of tuple from large iterator (tests implementation detail of uPy) +# construction of tuple from large iterator (tests implementation detail of MicroPython) print(tuple(range(20))) # unsupported unary operation diff --git a/tests/cmdline/cmd_compile_only.py b/tests/cmdline/cmd_compile_only.py new file mode 100644 index 00000000000..89964c1b5bd --- /dev/null +++ b/tests/cmdline/cmd_compile_only.py @@ -0,0 +1,13 @@ +# cmdline: -X compile-only +# test compile-only functionality +print("This should not be printed") +x = 1 + 2 + + +def hello(): + return "world" + + +class TestClass: + def __init__(self): + self.value = 42 diff --git a/tests/cmdline/cmd_compile_only.py.exp b/tests/cmdline/cmd_compile_only.py.exp new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/cmdline/cmd_compile_only.py.exp @@ -0,0 +1 @@ + diff --git a/tests/cmdline/cmd_compile_only_error.py b/tests/cmdline/cmd_compile_only_error.py new file mode 100644 index 00000000000..326937a5c07 --- /dev/null +++ b/tests/cmdline/cmd_compile_only_error.py @@ -0,0 +1,6 @@ +# cmdline: -X compile-only +# test compile-only with syntax error +print("This should not be printed") +def broken_syntax( + # Missing closing parenthesis + return "error" diff --git a/tests/cmdline/cmd_compile_only_error.py.exp b/tests/cmdline/cmd_compile_only_error.py.exp new file mode 100644 index 00000000000..3911f71d624 --- /dev/null +++ b/tests/cmdline/cmd_compile_only_error.py.exp @@ -0,0 +1 @@ +CRASH \ No newline at end of file diff --git a/tests/cmdline/cmd_file_variable.py b/tests/cmdline/cmd_file_variable.py new file mode 100644 index 00000000000..6cac6744d90 --- /dev/null +++ b/tests/cmdline/cmd_file_variable.py @@ -0,0 +1,5 @@ +# Test that __file__ is set correctly for script execution +try: + print("__file__ =", __file__) +except NameError: + print("__file__ not defined") diff --git a/tests/cmdline/cmd_file_variable.py.exp b/tests/cmdline/cmd_file_variable.py.exp new file mode 100644 index 00000000000..6807569f662 --- /dev/null +++ b/tests/cmdline/cmd_file_variable.py.exp @@ -0,0 +1 @@ +__file__ = cmdline/cmd_file_variable.py diff --git a/tests/cmdline/cmd_module_atexit.py b/tests/cmdline/cmd_module_atexit.py new file mode 100644 index 00000000000..100bc112777 --- /dev/null +++ b/tests/cmdline/cmd_module_atexit.py @@ -0,0 +1,16 @@ +# cmdline: -m cmdline.cmd_module_atexit +# +# Test running as a module and using sys.atexit. + +import sys + +if not hasattr(sys, "atexit"): + print("SKIP") + raise SystemExit + +# Verify we ran as a module. +print(sys.argv) + +sys.atexit(lambda: print("done")) + +print("start") diff --git a/tests/cmdline/cmd_module_atexit.py.exp b/tests/cmdline/cmd_module_atexit.py.exp new file mode 100644 index 00000000000..2a0f756b1e7 --- /dev/null +++ b/tests/cmdline/cmd_module_atexit.py.exp @@ -0,0 +1,3 @@ +['cmdline.cmd_module_atexit', 'cmdline/cmd_module_atexit.py'] +start +done diff --git a/tests/cmdline/cmd_module_atexit_exc.py b/tests/cmdline/cmd_module_atexit_exc.py new file mode 100644 index 00000000000..88940a7741f --- /dev/null +++ b/tests/cmdline/cmd_module_atexit_exc.py @@ -0,0 +1,19 @@ +# cmdline: -m cmdline.cmd_module_atexit_exc +# +# Test running as a module and using sys.atexit, with script completion via sys.exit. + +import sys + +if not hasattr(sys, "atexit"): + print("SKIP") + raise SystemExit + +# Verify we ran as a module. +print(sys.argv) + +sys.atexit(lambda: print("done")) + +print("start") + +# This will raise SystemExit to finish the script, and atexit should still be run. +sys.exit(0) diff --git a/tests/cmdline/cmd_module_atexit_exc.py.exp b/tests/cmdline/cmd_module_atexit_exc.py.exp new file mode 100644 index 00000000000..6320d9d2d30 --- /dev/null +++ b/tests/cmdline/cmd_module_atexit_exc.py.exp @@ -0,0 +1,3 @@ +['cmdline.cmd_module_atexit_exc', 'cmdline/cmd_module_atexit_exc.py'] +start +done diff --git a/tests/cmdline/cmd_sys_exit_0.py b/tests/cmdline/cmd_sys_exit_0.py new file mode 100644 index 00000000000..1294b739e8f --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_0.py @@ -0,0 +1,5 @@ +# cmdline: +# test sys.exit(0) - success exit code +import sys + +sys.exit(0) diff --git a/tests/cmdline/cmd_sys_exit_0.py.exp b/tests/cmdline/cmd_sys_exit_0.py.exp new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_0.py.exp @@ -0,0 +1 @@ + diff --git a/tests/cmdline/cmd_sys_exit_error.py b/tests/cmdline/cmd_sys_exit_error.py new file mode 100644 index 00000000000..ecac15e94f1 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_error.py @@ -0,0 +1,5 @@ +# cmdline: +# test sys.exit() functionality and exit codes +import sys + +sys.exit(123) diff --git a/tests/cmdline/cmd_sys_exit_error.py.exp b/tests/cmdline/cmd_sys_exit_error.py.exp new file mode 100644 index 00000000000..3911f71d624 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_error.py.exp @@ -0,0 +1 @@ +CRASH \ No newline at end of file diff --git a/tests/cmdline/cmd_sys_exit_none.py b/tests/cmdline/cmd_sys_exit_none.py new file mode 100644 index 00000000000..66e19666589 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_none.py @@ -0,0 +1,5 @@ +# cmdline: +# test sys.exit(None) - should exit with code 0 +import sys + +sys.exit(None) diff --git a/tests/cmdline/cmd_sys_exit_none.py.exp b/tests/cmdline/cmd_sys_exit_none.py.exp new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/tests/cmdline/cmd_sys_exit_none.py.exp @@ -0,0 +1 @@ + diff --git a/tests/cmdline/repl_autocomplete_underscore.py b/tests/cmdline/repl_autocomplete_underscore.py new file mode 100644 index 00000000000..98bbb699200 --- /dev/null +++ b/tests/cmdline/repl_autocomplete_underscore.py @@ -0,0 +1,33 @@ +# Test REPL autocompletion filtering of underscore attributes + +# Start paste mode +{\x05} +class TestClass: + def __init__(self): + self.public_attr = 1 + self._private_attr = 2 + self.__very_private = 3 + + def public_method(self): + pass + + def _private_method(self): + pass + + @property + def public_property(self): + return 42 + + @property + def _private_property(self): + return 99 + +{\x04} +# Paste executed + +# Create an instance +obj = TestClass() + +# Test tab completion on the instance +# The tab character after `obj.` and 'a' below triggers the completions +obj.{\x09}{\x09}a{\x09} diff --git a/tests/cmdline/repl_autocomplete_underscore.py.exp b/tests/cmdline/repl_autocomplete_underscore.py.exp new file mode 100644 index 00000000000..f9720ef2331 --- /dev/null +++ b/tests/cmdline/repl_autocomplete_underscore.py.exp @@ -0,0 +1,41 @@ +MicroPython \.\+ version +Type "help()" for more information. +>>> # Test REPL autocompletion filtering of underscore attributes +>>> +>>> # Start paste mode +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== class TestClass: +=== def __init__(self): +=== self.public_attr = 1 +=== self._private_attr = 2 +=== self.__very_private = 3 +=== +=== def public_method(self): +=== pass +=== +=== def _private_method(self): +=== pass +=== +=== @property +=== def public_property(self): +=== return 42 +=== +=== @property +=== def _private_property(self): +=== return 99 +=== +=== +>>> # Paste executed +>>> +>>> # Create an instance +>>> obj = TestClass() +>>> +>>> # Test tab completion on the instance +>>> # The tab character after `obj.` and 'a' below triggers the completions +>>> obj.public_ +public_attr public_method public_property +>>> obj.public_attr +1 +>>> diff --git a/tests/cmdline/repl_lock.py b/tests/cmdline/repl_lock.py new file mode 100644 index 00000000000..77e2e932740 --- /dev/null +++ b/tests/cmdline/repl_lock.py @@ -0,0 +1,7 @@ +import micropython +micropython.heap_lock() +1+1 +micropython.heap_lock() +None # Cause the repl's line storage to be enlarged ---------------- +micropython.heap_lock() +raise SystemExit diff --git a/tests/cmdline/repl_lock.py.exp b/tests/cmdline/repl_lock.py.exp new file mode 100644 index 00000000000..d921fd6ae8e --- /dev/null +++ b/tests/cmdline/repl_lock.py.exp @@ -0,0 +1,10 @@ +MicroPython \.\+ version +Type "help()" for more information. +>>> import micropython +>>> micropython.heap_lock() +>>> 1+1 +2 +>>> micropython.heap_lock() +>>> None # Cause the repl's line storage to be enlarged ---------------- +>>> micropython.heap_lock() +>>> raise SystemExit diff --git a/tests/cmdline/repl_paste.py b/tests/cmdline/repl_paste.py new file mode 100644 index 00000000000..7cec450fce7 --- /dev/null +++ b/tests/cmdline/repl_paste.py @@ -0,0 +1,90 @@ +# Test REPL paste mode functionality + +# Basic paste mode with a simple function +{\x05} +def hello(): + print('Hello from paste mode!') +hello() +{\x04} + +# Paste mode with multiple indentation levels +{\x05} +def calculate(n): + if n > 0: + for i in range(n): + if i % 2 == 0: + print(f'Even: {i}') + else: + print(f'Odd: {i}') + else: + print('n must be positive') + +calculate(5) +{\x04} + +# Paste mode with blank lines +{\x05} +def function_with_blanks(): + print('First line') + + print('After blank line') + + + print('After two blank lines') + +function_with_blanks() +{\x04} + +# Paste mode with class definition and multiple methods +{\x05} +class TestClass: + def __init__(self, value): + self.value = value + + def display(self): + print(f'Value is: {self.value}') + + def double(self): + self.value *= 2 + return self.value + +obj = TestClass(21) +obj.display() +print(f'Doubled: {obj.double()}') +obj.display() +{\x04} + +# Paste mode with exception handling +{\x05} +try: + x = 1 / 0 +except ZeroDivisionError: + print('Caught division by zero') +finally: + print('Finally block executed') +{\x04} + +# Cancel paste mode with Ctrl-C +{\x05} +print('This should not execute') +{\x03} + +# Normal REPL still works after cancelled paste +print('Back to normal REPL') + +# Paste mode with syntax error +{\x05} +def bad_syntax(: + print('Missing parameter') +{\x04} + +# Paste mode with runtime error +{\x05} +def will_error(): + undefined_variable + +will_error() +{\x04} + +# Final test to show REPL is still functioning +1 + 2 + 3 diff --git a/tests/cmdline/repl_paste.py.exp b/tests/cmdline/repl_paste.py.exp new file mode 100644 index 00000000000..2b837f85cf9 --- /dev/null +++ b/tests/cmdline/repl_paste.py.exp @@ -0,0 +1,133 @@ +MicroPython \.\+ version +Type "help()" for more information. +>>> # Test REPL paste mode functionality +>>> +>>> # Basic paste mode with a simple function +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== def hello(): +=== print('Hello from paste mode!') +=== hello() +=== +Hello from paste mode! +>>> +>>> # Paste mode with multiple indentation levels +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== def calculate(n): +=== if n > 0: +=== for i in range(n): +=== if i % 2 == 0: +=== print(f'Even: {i}') +=== else: +=== print(f'Odd: {i}') +=== else: +=== print('n must be positive') +=== +=== calculate(5) +=== +Even: 0 +Odd: 1 +Even: 2 +Odd: 3 +Even: 4 +>>> +>>> # Paste mode with blank lines +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== def function_with_blanks(): +=== print('First line') +=== +=== print('After blank line') +=== +=== +=== print('After two blank lines') +=== +=== function_with_blanks() +=== +First line +After blank line +After two blank lines +>>> +>>> # Paste mode with class definition and multiple methods +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== class TestClass: +=== def __init__(self, value): +=== self.value = value +=== +=== def display(self): +=== print(f'Value is: {self.value}') +=== +=== def double(self): +=== self.value *= 2 +=== return self.value +=== +=== obj = TestClass(21) +=== obj.display() +=== print(f'Doubled: {obj.double()}') +=== obj.display() +=== +Value is: 21 +Doubled: 42 +Value is: 42 +>>> +>>> # Paste mode with exception handling +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== try: +=== x = 1 / 0 +=== except ZeroDivisionError: +=== print('Caught division by zero') +=== finally: +=== print('Finally block executed') +=== +Caught division by zero +Finally block executed +>>> +>>> # Cancel paste mode with Ctrl-C +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== print('This should not execute') +=== +>>> +>>> +>>> # Normal REPL still works after cancelled paste +>>> print('Back to normal REPL') +Back to normal REPL +>>> +>>> # Paste mode with syntax error +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== def bad_syntax(: +=== print('Missing parameter') +=== +Traceback (most recent call last): + File "", line 2 +SyntaxError: invalid syntax +>>> +>>> # Paste mode with runtime error +>>> +paste mode; Ctrl-C to cancel, Ctrl-D to finish +=== +=== def will_error(): +=== undefined_variable +=== +=== will_error() +=== +Traceback (most recent call last): + File "", line 5, in + File "", line 3, in will_error +NameError: name 'undefined_variable' isn't defined +>>> +>>> # Final test to show REPL is still functioning +>>> 1 + 2 + 3 +6 +>>> diff --git a/tests/cpydiff/core_class_initsubclass.py b/tests/cpydiff/core_class_initsubclass.py new file mode 100644 index 00000000000..8683271dcb0 --- /dev/null +++ b/tests/cpydiff/core_class_initsubclass.py @@ -0,0 +1,21 @@ +""" +categories: Core,Classes +description: ``__init_subclass__`` isn't automatically called. +cause: MicroPython does not currently implement PEP 487. +workaround: Manually call ``__init_subclass__`` after class creation if needed. e.g.:: + + class A(Base): + pass + A.__init_subclass__() + +""" + + +class Base: + @classmethod + def __init_subclass__(cls): + print(f"Base.__init_subclass__({cls.__name__})") + + +class A(Base): + pass diff --git a/tests/cpydiff/core_class_initsubclass_autoclassmethod.py b/tests/cpydiff/core_class_initsubclass_autoclassmethod.py new file mode 100644 index 00000000000..b2f7628976c --- /dev/null +++ b/tests/cpydiff/core_class_initsubclass_autoclassmethod.py @@ -0,0 +1,31 @@ +""" +categories: Core,Classes +description: ``__init_subclass__`` isn't an implicit classmethod. +cause: MicroPython does not currently implement PEP 487. ``__init_subclass__`` is not currently in the list of special-cased class/static methods. +workaround: Decorate declarations of ``__init_subclass__`` with ``@classmethod``. +""" + + +def regularize_spelling(text, prefix="bound_"): + # for regularizing across the CPython "method" vs MicroPython "bound_method" spelling for the type of a bound classmethod + if text.startswith(prefix): + return text[len(prefix) :] + return text + + +class A: + def __init_subclass__(cls): + pass + + @classmethod + def manual_decorated(cls): + pass + + +a = type(A.__init_subclass__).__name__ +b = type(A.manual_decorated).__name__ + +print(regularize_spelling(a)) +print(regularize_spelling(b)) +if a != b: + print("FAIL") diff --git a/tests/cpydiff/core_class_initsubclass_kwargs.py b/tests/cpydiff/core_class_initsubclass_kwargs.py new file mode 100644 index 00000000000..ed5157afeae --- /dev/null +++ b/tests/cpydiff/core_class_initsubclass_kwargs.py @@ -0,0 +1,22 @@ +""" +categories: Core,Classes +description: MicroPython doesn't support parameterized ``__init_subclass__`` class customization. +cause: MicroPython does not currently implement PEP 487. The MicroPython syntax tree does not include a kwargs node after the class inheritance list. +workaround: Use class variables or another mechanism to specify base-class customizations. +""" + + +class Base: + @classmethod + def __init_subclass__(cls, arg=None, **kwargs): + cls.init_subclass_was_called = True + print(f"Base.__init_subclass__({cls.__name__}, {arg=!r}, {kwargs=!r})") + + +class A(Base, arg="arg"): + pass + + +# Regularize across MicroPython not automatically calling __init_subclass__ either. +if not getattr(A, "init_subclass_was_called", False): + A.__init_subclass__() diff --git a/tests/cpydiff/core_class_initsubclass_super.py b/tests/cpydiff/core_class_initsubclass_super.py new file mode 100644 index 00000000000..d18671a74bf --- /dev/null +++ b/tests/cpydiff/core_class_initsubclass_super.py @@ -0,0 +1,22 @@ +""" +categories: Core,Classes +description: ``__init_subclass__`` can't be defined a cooperatively-recursive way. +cause: MicroPython does not currently implement PEP 487. The base object type does not have an ``__init_subclass__`` implementation. +workaround: Omit the recursive ``__init_subclass__`` call unless it's known that the grandparent also defines it. +""" + + +class Base: + @classmethod + def __init_subclass__(cls, **kwargs): + cls.init_subclass_was_called = True + super().__init_subclass__(**kwargs) + + +class A(Base): + pass + + +# Regularize across MicroPython not automatically calling __init_subclass__ either. +if not getattr(A, "init_subclass_was_called", False): + A.__init_subclass__() diff --git a/tests/cpydiff/core_fstring_concat.py b/tests/cpydiff/core_fstring_concat.py index 3daa13d7536..2fbe1b961a1 100644 --- a/tests/cpydiff/core_fstring_concat.py +++ b/tests/cpydiff/core_fstring_concat.py @@ -1,5 +1,5 @@ """ -categories: Core +categories: Core,f-strings description: f-strings don't support concatenation with adjacent literals if the adjacent literals contain braces cause: MicroPython is optimised for code space. workaround: Use the + operator between literal strings when they are not both f-strings diff --git a/tests/cpydiff/core_fstring_parser.py b/tests/cpydiff/core_fstring_parser.py index 87cf1e63ed8..4964b9707ac 100644 --- a/tests/cpydiff/core_fstring_parser.py +++ b/tests/cpydiff/core_fstring_parser.py @@ -1,5 +1,5 @@ """ -categories: Core +categories: Core,f-strings description: f-strings cannot support expressions that require parsing to resolve unbalanced nested braces and brackets cause: MicroPython is optimised for code space. workaround: Always use balanced braces and brackets in expressions inside f-strings diff --git a/tests/cpydiff/core_fstring_repr.py b/tests/cpydiff/core_fstring_repr.py index d37fb48db75..2589a34b7e3 100644 --- a/tests/cpydiff/core_fstring_repr.py +++ b/tests/cpydiff/core_fstring_repr.py @@ -1,5 +1,5 @@ """ -categories: Core +categories: Core,f-strings description: f-strings don't support !a conversions cause: MicropPython does not implement ascii() workaround: None diff --git a/tests/cpydiff/core_import_all.py b/tests/cpydiff/core_import_all.py deleted file mode 100644 index 0fbe9d4d4ec..00000000000 --- a/tests/cpydiff/core_import_all.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -categories: Core,import -description: __all__ is unsupported in __init__.py in MicroPython. -cause: Not implemented. -workaround: Manually import the sub-modules directly in __init__.py using ``from . import foo, bar``. -""" - -from modules3 import * - -foo.hello() diff --git a/tests/cpydiff/modules3/__init__.py b/tests/cpydiff/modules3/__init__.py deleted file mode 100644 index 27a2bf2ad90..00000000000 --- a/tests/cpydiff/modules3/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ["foo"] diff --git a/tests/cpydiff/modules3/foo.py b/tests/cpydiff/modules3/foo.py deleted file mode 100644 index dd9b9d4ddd4..00000000000 --- a/tests/cpydiff/modules3/foo.py +++ /dev/null @@ -1,2 +0,0 @@ -def hello(): - print("hello") diff --git a/tests/cpydiff/modules_errno_enotsup.py b/tests/cpydiff/modules_errno_enotsup.py new file mode 100644 index 00000000000..80e5ad9d032 --- /dev/null +++ b/tests/cpydiff/modules_errno_enotsup.py @@ -0,0 +1,10 @@ +""" +categories: Modules,errno +description: MicroPython does not include ``ENOTSUP`` as a name for errno 95. +cause: MicroPython does not implement the ``ENOTSUP`` canonical alias for ``EOPNOTSUPP`` added in CPython 3.2. +workaround: Use ``errno.EOPNOTSUPP`` in place of ``errno.ENOTSUP``. +""" + +import errno + +print(f"{errno.errorcode[errno.EOPNOTSUPP]=!s}") diff --git a/tests/cpydiff/modules_struct_fewargs.py b/tests/cpydiff/modules_struct_fewargs.py index 49b2a3213c8..f6346a67938 100644 --- a/tests/cpydiff/modules_struct_fewargs.py +++ b/tests/cpydiff/modules_struct_fewargs.py @@ -1,6 +1,6 @@ """ categories: Modules,struct -description: Struct pack with too few args, not checked by uPy +description: Struct pack with too few args, not checked by MicroPython cause: Unknown workaround: Unknown """ diff --git a/tests/cpydiff/modules_struct_manyargs.py b/tests/cpydiff/modules_struct_manyargs.py index e3b78930f21..b2ea93b6c93 100644 --- a/tests/cpydiff/modules_struct_manyargs.py +++ b/tests/cpydiff/modules_struct_manyargs.py @@ -1,6 +1,6 @@ """ categories: Modules,struct -description: Struct pack with too many args, not checked by uPy +description: Struct pack with too many args, not checked by MicroPython cause: Unknown workaround: Unknown """ diff --git a/tests/cpydiff/modules_struct_whitespace_in_format.py b/tests/cpydiff/modules_struct_whitespace_in_format.py index a7a1d2facdf..8b609425eb0 100644 --- a/tests/cpydiff/modules_struct_whitespace_in_format.py +++ b/tests/cpydiff/modules_struct_whitespace_in_format.py @@ -1,6 +1,6 @@ """ categories: Modules,struct -description: Struct pack with whitespace in format, whitespace ignored by CPython, error on uPy +description: Struct pack with whitespace in format, whitespace ignored by CPython, error on MicroPython cause: MicroPython is optimised for code size. workaround: Don't use spaces in format strings. """ diff --git a/tests/cpydiff/syntax_arg_unpacking.py b/tests/cpydiff/syntax_arg_unpacking.py index e54832ddb91..7133a8a2827 100644 --- a/tests/cpydiff/syntax_arg_unpacking.py +++ b/tests/cpydiff/syntax_arg_unpacking.py @@ -1,5 +1,5 @@ """ -categories: Syntax +categories: Syntax,Unpacking description: Argument unpacking does not work if the argument being unpacked is the nth or greater argument where n is the number of bits in an MP_SMALL_INT. cause: The implementation uses an MP_SMALL_INT to flag args that need to be unpacked. workaround: Use fewer arguments. diff --git a/tests/cpydiff/syntax_literal_underscore.py b/tests/cpydiff/syntax_literal_underscore.py new file mode 100644 index 00000000000..4b1406e9f3f --- /dev/null +++ b/tests/cpydiff/syntax_literal_underscore.py @@ -0,0 +1,19 @@ +""" +categories: Syntax,Literals +description: MicroPython accepts underscores in numeric literals where CPython doesn't +cause: Different parser implementation + +MicroPython's tokenizer ignores underscores in numeric literals, while CPython +rejects multiple consecutive underscores and underscores after the last digit. + +workaround: Remove the underscores not accepted by CPython. +""" + +try: + print(eval("1__1")) +except SyntaxError: + print("Should not work") +try: + print(eval("1_")) +except SyntaxError: + print("Should not work") diff --git a/tests/cpydiff/syntax_spaces.py b/tests/cpydiff/syntax_spaces.py index 03d25d56199..670cefdeac2 100644 --- a/tests/cpydiff/syntax_spaces.py +++ b/tests/cpydiff/syntax_spaces.py @@ -1,8 +1,15 @@ """ -categories: Syntax,Spaces -description: uPy requires spaces between literal numbers and keywords, CPy doesn't -cause: Unknown -workaround: Unknown +categories: Syntax,Literals +description: MicroPython requires spaces between literal numbers and keywords or ".", CPython doesn't +cause: Different parser implementation + +MicroPython's tokenizer treats a sequence like ``1and`` as a single token, while CPython treats it as two tokens. + +Since CPython 3.11, when the literal number is followed by a token, this syntax causes a ``SyntaxWarning`` for an "invalid literal". When a literal number is followed by a "." denoting attribute access, CPython does not warn. + +workaround: Add a space between the integer literal and the intended next token. + +This also fixes the ``SyntaxWarning`` in CPython. """ try: @@ -17,3 +24,7 @@ print(eval("1if 1else 0")) except SyntaxError: print("Should have worked") +try: + print(eval("0x1.to_bytes(1)")) +except SyntaxError: + print("Should have worked") diff --git a/tests/cpydiff/types_complex_parser.py b/tests/cpydiff/types_complex_parser.py new file mode 100644 index 00000000000..4a012987d9e --- /dev/null +++ b/tests/cpydiff/types_complex_parser.py @@ -0,0 +1,14 @@ +""" +categories: Types,complex +description: MicroPython's complex() accepts certain incorrect values that CPython rejects +cause: MicroPython is highly optimized for memory usage. +workaround: Do not use non-standard complex literals as argument to complex() + +MicroPython's ``complex()`` function accepts literals that contain a space and +no sign between the real and imaginary parts, and interprets it as a plus. +""" + +try: + print(complex("1 1j")) +except ValueError: + print("ValueError") diff --git a/tests/cpydiff/types_float_implicit_conversion.py b/tests/cpydiff/types_float_implicit_conversion.py index 3726839fac6..764c9e4e6ed 100644 --- a/tests/cpydiff/types_float_implicit_conversion.py +++ b/tests/cpydiff/types_float_implicit_conversion.py @@ -1,6 +1,6 @@ """ categories: Types,float -description: uPy allows implicit conversion of objects in maths operations while CPython does not. +description: MicroPython allows implicit conversion of objects in maths operations while CPython does not. cause: Unknown workaround: Objects should be wrapped in ``float(obj)`` for compatibility with CPython. """ diff --git a/tests/cpydiff/types_float_rounding.py b/tests/cpydiff/types_float_rounding.py deleted file mode 100644 index 206e359ed9b..00000000000 --- a/tests/cpydiff/types_float_rounding.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -categories: Types,float -description: uPy and CPython outputs formats may differ -cause: Unknown -workaround: Unknown -""" - -print("%.1g" % -9.9) diff --git a/tests/cpydiff/types_oserror_errnomap.py b/tests/cpydiff/types_oserror_errnomap.py new file mode 100644 index 00000000000..6627bd2af4a --- /dev/null +++ b/tests/cpydiff/types_oserror_errnomap.py @@ -0,0 +1,48 @@ +""" +categories: Types,OSError +description: OSError constructor returns a plain OSError for all errno values, rather than a relevant subtype. +cause: MicroPython does not include the CPython-standard OSError subclasses. +workaround: Catch OSError and use its errno attribute to discriminate the cause. +""" + +import errno + +errno_list = [ # i.e. the set implemented by micropython + errno.EPERM, + errno.ENOENT, + errno.EIO, + errno.EBADF, + errno.EAGAIN, + errno.ENOMEM, + errno.EACCES, + errno.EEXIST, + errno.ENODEV, + errno.EISDIR, + errno.EINVAL, + errno.EOPNOTSUPP, + errno.EADDRINUSE, + errno.ECONNABORTED, + errno.ECONNRESET, + errno.ENOBUFS, + errno.ENOTCONN, + errno.ETIMEDOUT, + errno.ECONNREFUSED, + errno.EHOSTUNREACH, + errno.EALREADY, + errno.EINPROGRESS, +] + + +def errno_output_type(n): + try: + raise OSError(n, "") + except OSError as e: + return f"{type(e).__name__}" + except Exception as e: + return f"non-OSError {type(e).__name__}" + else: + return "no error" + + +for n in errno_list: + print(errno.errorcode[n], "=", errno_output_type(n)) diff --git a/tests/cpydiff/types_range_limits.py b/tests/cpydiff/types_range_limits.py new file mode 100644 index 00000000000..e53d5fd4088 --- /dev/null +++ b/tests/cpydiff/types_range_limits.py @@ -0,0 +1,26 @@ +""" +categories: Types,range +description: Range objects with large start or stop arguments misbehave. +cause: Intermediate calculations overflow the C mp_int_t type +workaround: Avoid using such ranges +""" + +from sys import maxsize + +# A range including `maxsize-1` cannot be created +try: + print(range(-maxsize - 1, 0)) +except OverflowError: + print("OverflowError") + +# A range with `stop-start` exceeding sys.maxsize has incorrect len(), while CPython cannot calculate len(). +try: + print(len(range(-maxsize, maxsize))) +except OverflowError: + print("OverflowError") + +# A range with `stop-start` exceeding sys.maxsize has incorrect len() +try: + print(len(range(-maxsize, maxsize, maxsize))) +except OverflowError: + print("OverflowError") diff --git a/tests/cpydiff/types_str_formatsep.py b/tests/cpydiff/types_str_formatsep.py new file mode 100644 index 00000000000..05d0b8d3d2c --- /dev/null +++ b/tests/cpydiff/types_str_formatsep.py @@ -0,0 +1,19 @@ +""" +categories: Types,str +description: MicroPython accepts the "," grouping option with any radix, unlike CPython +cause: To reduce code size, MicroPython does not issue an error for this combination +workaround: Do not use a format string like ``{:,b}`` if CPython compatibility is required. +""" + +try: + print("{:,b}".format(99)) +except ValueError: + print("ValueError") +try: + print("{:,x}".format(99)) +except ValueError: + print("ValueError") +try: + print("{:,o}".format(99)) +except ValueError: + print("ValueError") diff --git a/tests/cpydiff/types_str_formatsep_float.py b/tests/cpydiff/types_str_formatsep_float.py new file mode 100644 index 00000000000..b487cd3758e --- /dev/null +++ b/tests/cpydiff/types_str_formatsep_float.py @@ -0,0 +1,11 @@ +""" +categories: Types,str +description: MicroPython accepts but does not properly implement the "," or "_" grouping character for float values +cause: To reduce code size, MicroPython does not implement this combination. Grouping characters will not appear in the number's significant digits and will appear at incorrect locations in leading zeros. +workaround: Do not use a format string like ``{:,f}`` if exact CPython compatibility is required. +""" + +print("{:,f}".format(3141.159)) +print("{:_f}".format(3141.159)) +print("{:011,.2f}".format(3141.159)) +print("{:011_.2f}".format(3141.159)) diff --git a/tests/extmod/asyncio_basic.py.exp b/tests/extmod/asyncio_basic.py.exp deleted file mode 100644 index 478e22abc8f..00000000000 --- a/tests/extmod/asyncio_basic.py.exp +++ /dev/null @@ -1,6 +0,0 @@ -start -after sleep -short -long -negative -took 200 400 0 diff --git a/tests/extmod/asyncio_event_queue.py b/tests/extmod/asyncio_event_queue.py new file mode 100644 index 00000000000..e0125b1aefe --- /dev/null +++ b/tests/extmod/asyncio_event_queue.py @@ -0,0 +1,64 @@ +# Ensure that an asyncio task can wait on an Event when the +# _task_queue is empty +# https://github.com/micropython/micropython/issues/16569 + +try: + import asyncio +except ImportError: + print("SKIP") + raise SystemExit + +# This test requires checking that the asyncio scheduler +# remains active "indefinitely" when the task queue is empty. +# +# To check this, we need another independent scheduler that +# can wait for a certain amount of time. So we have to +# create one using micropython.schedule() and time.ticks_ms() +# +# Technically, this code breaks the rules, as it is clearly +# documented that Event.set() should _NOT_ be called from a +# schedule (soft IRQ) because in some cases, a race condition +# can occur, resulting in a crash. However: +# - since the risk of a race condition in that specific +# case has been analysed and excluded +# - given that there is no other simple alternative to +# write this test case, +# an exception to the rule was deemed acceptable. See +# https://github.com/micropython/micropython/pull/16772 + +import micropython, time + +try: + micropython.schedule +except AttributeError: + print("SKIP") + raise SystemExit + + +evt = asyncio.Event() + + +def schedule_watchdog(end_ticks): + if time.ticks_diff(end_ticks, time.ticks_ms()) <= 0: + print("asyncio still pending, unlocking event") + # Caution: about to call Event.set() from a schedule + # (see the note in the comment above) + evt.set() + return + micropython.schedule(schedule_watchdog, end_ticks) + + +async def foo(): + print("foo waiting") + schedule_watchdog(time.ticks_add(time.ticks_ms(), 100)) + await evt.wait() + print("foo done") + + +async def main(): + print("main started") + await foo() + print("main done") + + +asyncio.run(main()) diff --git a/tests/extmod/asyncio_event_queue.py.exp b/tests/extmod/asyncio_event_queue.py.exp new file mode 100644 index 00000000000..ee42c96d83e --- /dev/null +++ b/tests/extmod/asyncio_event_queue.py.exp @@ -0,0 +1,5 @@ +main started +foo waiting +asyncio still pending, unlocking event +foo done +main done diff --git a/tests/extmod/asyncio_heaplock.py b/tests/extmod/asyncio_heaplock.py index 8326443f0e6..9e9908de1cb 100644 --- a/tests/extmod/asyncio_heaplock.py +++ b/tests/extmod/asyncio_heaplock.py @@ -4,7 +4,11 @@ # - StreamWriter.write, stream is blocked and data to write is a bytes object # - StreamWriter.write, when stream is not blocked -import micropython +try: + import asyncio, micropython +except ImportError: + print("SKIP") + raise SystemExit # strict stackless builds can't call functions without allocating a frame on the heap try: @@ -24,12 +28,6 @@ def f(x): print("SKIP") raise SystemExit -try: - import asyncio -except ImportError: - print("SKIP") - raise SystemExit - class TestStream: def __init__(self, blocked): diff --git a/tests/extmod/asyncio_iterator_event.py b/tests/extmod/asyncio_iterator_event.py new file mode 100644 index 00000000000..f61fefcf051 --- /dev/null +++ b/tests/extmod/asyncio_iterator_event.py @@ -0,0 +1,86 @@ +# Ensure that an asyncio task can wait on an Event when the +# _task_queue is empty, in the context of an async iterator +# https://github.com/micropython/micropython/issues/16318 + +try: + import asyncio +except ImportError: + print("SKIP") + raise SystemExit + +# This test requires checking that the asyncio scheduler +# remains active "indefinitely" when the task queue is empty. +# +# To check this, we need another independent scheduler that +# can wait for a certain amount of time. So we have to +# create one using micropython.schedule() and time.ticks_ms() +# +# Technically, this code breaks the rules, as it is clearly +# documented that Event.set() should _NOT_ be called from a +# schedule (soft IRQ) because in some cases, a race condition +# can occur, resulting in a crash. However: +# - since the risk of a race condition in that specific +# case has been analysed and excluded +# - given that there is no other simple alternative to +# write this test case, +# an exception to the rule was deemed acceptable. See +# https://github.com/micropython/micropython/pull/16772 + +import micropython, time + +try: + micropython.schedule +except AttributeError: + print("SKIP") + raise SystemExit + +ai = None + + +def schedule_watchdog(end_ticks): + if time.ticks_diff(end_ticks, time.ticks_ms()) <= 0: + print("good: asyncio iterator is still pending, exiting") + # Caution: ai.fetch_data() will invoke Event.set() + # (see the note in the comment above) + ai.fetch_data(None) + return + micropython.schedule(schedule_watchdog, end_ticks) + + +async def test(ai): + for x in range(3): + await asyncio.sleep(0.1) + ai.fetch_data("bar {}".format(x)) + + +class AsyncIterable: + def __init__(self): + self.message = None + self.evt = asyncio.Event() + + def __aiter__(self): + return self + + async def __anext__(self): + await self.evt.wait() + self.evt.clear() + if self.message is None: + raise StopAsyncIteration + return self.message + + def fetch_data(self, message): + self.message = message + self.evt.set() + + +async def main(): + global ai + ai = AsyncIterable() + asyncio.create_task(test(ai)) + schedule_watchdog(time.ticks_add(time.ticks_ms(), 500)) + async for message in ai: + print(message) + print("end main") + + +asyncio.run(main()) diff --git a/tests/extmod/asyncio_iterator_event.py.exp b/tests/extmod/asyncio_iterator_event.py.exp new file mode 100644 index 00000000000..a1893197d02 --- /dev/null +++ b/tests/extmod/asyncio_iterator_event.py.exp @@ -0,0 +1,5 @@ +bar 0 +bar 1 +bar 2 +good: asyncio iterator is still pending, exiting +end main diff --git a/tests/extmod/asyncio_lock.py.exp b/tests/extmod/asyncio_lock.py.exp deleted file mode 100644 index a37dfcbd2e5..00000000000 --- a/tests/extmod/asyncio_lock.py.exp +++ /dev/null @@ -1,41 +0,0 @@ -False -True -False -have lock ----- -task start 1 -task start 2 -task start 3 -task have 1 0 -task have 2 0 -task have 3 0 -task have 1 1 -task have 2 1 -task have 3 1 -task have 1 2 -task end 1 -task have 2 2 -task end 2 -task have 3 2 -task end 3 ----- -task have True -task release False -task have True -task release False -task have again -task have again ----- -task got 0 -task release 0 -task cancel 1 -task got 2 -task release 2 -False ----- -task got 0 -task cancel 1 -task release 0 -task got 2 -task cancel 2 -False diff --git a/tests/extmod/asyncio_set_exception_handler.py b/tests/extmod/asyncio_set_exception_handler.py index 5935f0f4ebe..0ac4a624224 100644 --- a/tests/extmod/asyncio_set_exception_handler.py +++ b/tests/extmod/asyncio_set_exception_handler.py @@ -12,7 +12,7 @@ def custom_handler(loop, context): async def task(i): - # Raise with 2 args so exception prints the same in uPy and CPython + # Raise with 2 args so exception prints the same in MicroPython and CPython raise ValueError(i, i + 1) diff --git a/tests/extmod/asyncio_wait_for_linked_task.py b/tests/extmod/asyncio_wait_for_linked_task.py new file mode 100644 index 00000000000..4dda62d5476 --- /dev/null +++ b/tests/extmod/asyncio_wait_for_linked_task.py @@ -0,0 +1,66 @@ +# Test asyncio.wait_for, with dependent tasks +# https://github.com/micropython/micropython/issues/16759 + +try: + import asyncio +except ImportError: + print("SKIP") + raise SystemExit + + +# CPython 3.12 deprecated calling get_event_loop() when there is no current event +# loop, so to make this test run on CPython requires setting the event loop. +if hasattr(asyncio, "set_event_loop"): + asyncio.set_event_loop(asyncio.new_event_loop()) + + +class Worker: + def __init__(self): + self._eventLoop = None + self._tasks = [] + + def launchTask(self, asyncJob): + if self._eventLoop is None: + self._eventLoop = asyncio.get_event_loop() + return self._eventLoop.create_task(asyncJob) + + async def job(self, prerequisite, taskName): + if prerequisite: + await prerequisite + await asyncio.sleep(0.1) + print(taskName, "work completed") + + def planTasks(self): + self._tasks.append(self.launchTask(self.job(None, "task0"))) + self._tasks.append(self.launchTask(self.job(self._tasks[0], "task1"))) + self._tasks.append(self.launchTask(self.job(self._tasks[1], "task2"))) + + async def waitForTask(self, taskIdx): + return await self._tasks[taskIdx] + + def syncWaitForTask(self, taskIdx): + return self._eventLoop.run_until_complete(self._tasks[taskIdx]) + + +async def async_test(): + print("--- async test") + worker = Worker() + worker.planTasks() + await worker.waitForTask(0) + print("-> task0 done") + await worker.waitForTask(2) + print("-> task2 done") + + +def sync_test(): + print("--- sync test") + worker = Worker() + worker.planTasks() + worker.syncWaitForTask(0) + print("-> task0 done") + worker.syncWaitForTask(2) + print("-> task2 done") + + +asyncio.get_event_loop().run_until_complete(async_test()) +sync_test() diff --git a/tests/extmod/asyncio_wait_task.py.exp b/tests/extmod/asyncio_wait_task.py.exp deleted file mode 100644 index 514a4342233..00000000000 --- a/tests/extmod/asyncio_wait_task.py.exp +++ /dev/null @@ -1,12 +0,0 @@ -start -task 1 -task 2 ----- -start -hello -world -took 200 200 -task_raise -ValueError -task_raise -ValueError diff --git a/tests/extmod/binascii_hexlify.py b/tests/extmod/binascii_hexlify.py index d06029aabaf..ae90b673365 100644 --- a/tests/extmod/binascii_hexlify.py +++ b/tests/extmod/binascii_hexlify.py @@ -1,5 +1,5 @@ try: - import binascii + from binascii import hexlify except ImportError: print("SKIP") raise SystemExit @@ -10,10 +10,10 @@ b"\x7f\x80\xff", b"1234ABCDabcd", ): - print(binascii.hexlify(x)) + print(hexlify(x)) # Two-argument version (now supported in CPython) -print(binascii.hexlify(b"123", ":")) +print(hexlify(b"123", ":")) # zero length buffer -print(binascii.hexlify(b"", b":")) +print(hexlify(b"", b":")) diff --git a/tests/extmod/binascii_unhexlify.py b/tests/extmod/binascii_unhexlify.py index 731b6a2bd4d..fe1d50780ee 100644 --- a/tests/extmod/binascii_unhexlify.py +++ b/tests/extmod/binascii_unhexlify.py @@ -1,5 +1,5 @@ try: - import binascii + from binascii import unhexlify except ImportError: print("SKIP") raise SystemExit @@ -10,18 +10,18 @@ b"7f80ff", b"313233344142434461626364", ): - print(binascii.unhexlify(x)) + print(unhexlify(x)) # CIRCUITPY-CHANGE # Unicode strings can be decoded print(binascii.unhexlify("313233344142434461626364")) try: - a = binascii.unhexlify(b"0") # odd buffer length + a = unhexlify(b"0") # odd buffer length except ValueError: print("ValueError") try: - a = binascii.unhexlify(b"gg") # digit not hex + a = unhexlify(b"gg") # digit not hex except ValueError: print("ValueError") diff --git a/tests/extmod/framebuf_blit.py b/tests/extmod/framebuf_blit.py new file mode 100644 index 00000000000..b1d98b330a8 --- /dev/null +++ b/tests/extmod/framebuf_blit.py @@ -0,0 +1,68 @@ +# Test FrameBuffer.blit method. + +try: + import framebuf +except ImportError: + print("SKIP") + raise SystemExit + + +def printbuf(): + print("--8<--") + for y in range(h): + for x in range(w): + print("%02x" % buf[(x + y * w)], end="") + print() + print("-->8--") + + +w = 5 +h = 4 +buf = bytearray(w * h) +fbuf = framebuf.FrameBuffer(buf, w, h, framebuf.GS8) + +fbuf2 = framebuf.FrameBuffer(bytearray(4), 2, 2, framebuf.GS8) +fbuf2.fill(0xFF) + +# Blit another FrameBuffer, at various locations. +for x, y in ((-1, -1), (0, 0), (1, 1), (4, 3)): + fbuf.fill(0) + fbuf.blit(fbuf2, x, y) + printbuf() + +# Blit a bytes object. +fbuf.fill(0) +image = (b"\x10\x11\x12\x13", 2, 2, framebuf.GS8) +fbuf.blit(image, 1, 1) +printbuf() + +# Blit a bytes object that has a stride. +fbuf.fill(0) +image = (b"\x20\x21\xff\x22\x23\xff", 2, 2, framebuf.GS8, 3) +fbuf.blit(image, 1, 1) +printbuf() + +# Blit a bytes object with a bytes palette. +fbuf.fill(0) +image = (b"\x00\x01\x01\x00", 2, 2, framebuf.GS8) +palette = (b"\xa1\xa2", 2, 1, framebuf.GS8) +fbuf.blit(image, 1, 1, -1, palette) +printbuf() + +# Not enough elements in the tuple. +try: + fbuf.blit((0, 0, 0), 0, 0) +except ValueError: + print("ValueError") + +# Too many elements in the tuple. +try: + fbuf.blit((0, 0, 0, 0, 0, 0), 0, 0) +except ValueError: + print("ValueError") + +# Bytes too small. +try: + fbuf.blit((b"", 1, 1, framebuf.GS8), 0, 0) +except ValueError: + print("ValueError") diff --git a/tests/extmod/framebuf_blit.py.exp b/tests/extmod/framebuf_blit.py.exp new file mode 100644 index 00000000000..e340f1990c7 --- /dev/null +++ b/tests/extmod/framebuf_blit.py.exp @@ -0,0 +1,45 @@ +--8<-- +ff00000000 +0000000000 +0000000000 +0000000000 +-->8-- +--8<-- +ffff000000 +ffff000000 +0000000000 +0000000000 +-->8-- +--8<-- +0000000000 +00ffff0000 +00ffff0000 +0000000000 +-->8-- +--8<-- +0000000000 +0000000000 +0000000000 +00000000ff +-->8-- +--8<-- +0000000000 +0010110000 +0012130000 +0000000000 +-->8-- +--8<-- +0000000000 +0020210000 +0022230000 +0000000000 +-->8-- +--8<-- +0000000000 +00a1a20000 +00a2a10000 +0000000000 +-->8-- +ValueError +ValueError +ValueError diff --git a/tests/extmod/hashlib_md5.py b/tests/extmod/hashlib_md5.py index 5f925fc97d0..ebbe9155e04 100644 --- a/tests/extmod/hashlib_md5.py +++ b/tests/extmod/hashlib_md5.py @@ -1,8 +1,7 @@ try: import hashlib except ImportError: - # This is neither uPy, nor cPy, so must be uPy with - # hashlib module disabled. + # MicroPython with hashlib module disabled. print("SKIP") raise SystemExit diff --git a/tests/extmod/hashlib_sha1.py b/tests/extmod/hashlib_sha1.py index af23033a591..46ffb73fcbe 100644 --- a/tests/extmod/hashlib_sha1.py +++ b/tests/extmod/hashlib_sha1.py @@ -1,8 +1,7 @@ try: import hashlib except ImportError: - # This is neither uPy, nor cPy, so must be uPy with - # hashlib module disabled. + # MicroPython with hashlib module disabled. print("SKIP") raise SystemExit diff --git a/tests/extmod/hashlib_sha256.py b/tests/extmod/hashlib_sha256.py index 95cd301d160..209fcb39877 100644 --- a/tests/extmod/hashlib_sha256.py +++ b/tests/extmod/hashlib_sha256.py @@ -1,8 +1,7 @@ try: import hashlib except ImportError: - # This is neither uPy, nor cPy, so must be uPy with - # hashlib module disabled. + # MicroPython with hashlib module disabled. print("SKIP") raise SystemExit diff --git a/tests/extmod/json_dump.py b/tests/extmod/json_dump.py index 897d33cc812..0beb4f5f856 100644 --- a/tests/extmod/json_dump.py +++ b/tests/extmod/json_dump.py @@ -16,11 +16,11 @@ # dump to a small-int not allowed try: json.dump(123, 1) -except (AttributeError, OSError): # CPython and uPy have different errors +except (AttributeError, OSError): # CPython and MicroPython have different errors print("Exception") # dump to an object not allowed try: json.dump(123, {}) -except (AttributeError, OSError): # CPython and uPy have different errors +except (AttributeError, OSError): # CPython and MicroPython have different errors print("Exception") diff --git a/tests/extmod/json_dump_iobase.py b/tests/extmod/json_dump_iobase.py index 94d317b8796..81105e36dcc 100644 --- a/tests/extmod/json_dump_iobase.py +++ b/tests/extmod/json_dump_iobase.py @@ -18,7 +18,7 @@ def __init__(self): def write(self, buf): if type(buf) == bytearray: - # uPy passes a bytearray, CPython passes a str + # MicroPython passes a bytearray, CPython passes a str buf = str(buf, "ascii") self.buf += buf return len(buf) diff --git a/tests/extmod/json_dump_separators.py b/tests/extmod/json_dump_separators.py index 4f8e56dceb5..ce39294820f 100644 --- a/tests/extmod/json_dump_separators.py +++ b/tests/extmod/json_dump_separators.py @@ -25,20 +25,20 @@ # dump to a small-int not allowed try: json.dump(123, 1, separators=sep) - except (AttributeError, OSError): # CPython and uPy have different errors + except (AttributeError, OSError): # CPython and MicroPython have different errors print("Exception") # dump to an object not allowed try: json.dump(123, {}, separators=sep) - except (AttributeError, OSError): # CPython and uPy have different errors + except (AttributeError, OSError): # CPython and MicroPython have different errors print("Exception") try: s = StringIO() json.dump(False, s, separators={"a": 1}) -except (TypeError, ValueError): # CPython and uPy have different errors +except (TypeError, ValueError): # CPython and MicroPython have different errors print("Exception") # invalid separator types diff --git a/tests/extmod/json_dumps_extra.py b/tests/extmod/json_dumps_extra.py index a410b0ee0ef..70efc866451 100644 --- a/tests/extmod/json_dumps_extra.py +++ b/tests/extmod/json_dumps_extra.py @@ -1,4 +1,4 @@ -# test uPy json behaviour that's not valid in CPy +# test MicroPython json behaviour that's not valid in CPy # CIRCUITPY-CHANGE: This behavior matches CPython print("SKIP") raise SystemExit diff --git a/tests/extmod/json_dumps_separators.py b/tests/extmod/json_dumps_separators.py index a3a9ec308f0..0a95f489a08 100644 --- a/tests/extmod/json_dumps_separators.py +++ b/tests/extmod/json_dumps_separators.py @@ -39,7 +39,7 @@ try: json.dumps(False, separators={"a": 1}) -except (TypeError, ValueError): # CPython and uPy have different errors +except (TypeError, ValueError): # CPython and MicroPython have different errors print("Exception") # invalid separator types diff --git a/tests/extmod/json_loads.py b/tests/extmod/json_loads.py index f9073c121e2..092402d715d 100644 --- a/tests/extmod/json_loads.py +++ b/tests/extmod/json_loads.py @@ -71,3 +71,27 @@ def my_print(o): my_print(json.loads("[null] a")) except ValueError: print("ValueError") + +# incomplete object declaration +try: + my_print(json.loads('{"a":0,')) +except ValueError: + print("ValueError") + +# incomplete nested array declaration +try: + my_print(json.loads('{"a":0, [')) +except ValueError: + print("ValueError") + +# incomplete array declaration +try: + my_print(json.loads("[0,")) +except ValueError: + print("ValueError") + +# incomplete nested object declaration +try: + my_print(json.loads('[0, {"a":0, ')) +except ValueError: + print("ValueError") diff --git a/tests/extmod/json_loads_bytes.py.exp b/tests/extmod/json_loads_bytes.py.exp deleted file mode 100644 index c2735a99052..00000000000 --- a/tests/extmod/json_loads_bytes.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -[1, 2] -[None] diff --git a/tests/extmod/json_loads_int_64.py b/tests/extmod/json_loads_int_64.py new file mode 100644 index 00000000000..f6236f1904a --- /dev/null +++ b/tests/extmod/json_loads_int_64.py @@ -0,0 +1,16 @@ +# Parse 64-bit integers from JSON payloads. +# +# This also exercises parsing integers from strings +# where the value may not be null terminated (last line) +try: + import json +except ImportError: + print("SKIP") + raise SystemExit + + +print(json.loads("9111222333444555666")) +print(json.loads("-9111222333444555666")) +print(json.loads("9111222333444555666")) +print(json.loads("-9111222333444555666")) +print(json.loads('["9111222333444555666777",9111222333444555666]')) diff --git a/tests/extmod/machine_hard_timer.py b/tests/extmod/machine_hard_timer.py new file mode 100644 index 00000000000..8fe42ea8508 --- /dev/null +++ b/tests/extmod/machine_hard_timer.py @@ -0,0 +1,45 @@ +import sys + +try: + from machine import Timer + from time import sleep_ms +except: + print("SKIP") + raise SystemExit + +if sys.platform == "esp8266": + timer = Timer(0) +else: + # Hardware timers are not implemented. + print("SKIP") + raise SystemExit + +# Test both hard and soft IRQ handlers and both one-shot and periodic +# timers. We adjust period in tests/extmod/machine_soft_timer.py, so try +# adjusting freq here instead. The heap should be locked in hard callbacks +# and unlocked in soft callbacks. + + +def callback(t): + print("callback", mode[1], kind[1], freq, end=" ") + try: + allocate = bytearray(1) + print("unlocked") + except MemoryError: + print("locked") + + +modes = [(Timer.ONE_SHOT, "one-shot"), (Timer.PERIODIC, "periodic")] +kinds = [(False, "soft"), (True, "hard")] + +for mode in modes: + for kind in kinds: + for freq in 50, 25: + timer.init( + mode=mode[0], + freq=freq, + hard=kind[0], + callback=callback, + ) + sleep_ms(90) + timer.deinit() diff --git a/tests/extmod/machine_hard_timer.py.exp b/tests/extmod/machine_hard_timer.py.exp new file mode 100644 index 00000000000..26cdc644fdd --- /dev/null +++ b/tests/extmod/machine_hard_timer.py.exp @@ -0,0 +1,16 @@ +callback one-shot soft 50 unlocked +callback one-shot soft 25 unlocked +callback one-shot hard 50 locked +callback one-shot hard 25 locked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 25 unlocked +callback periodic soft 25 unlocked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 25 locked +callback periodic hard 25 locked diff --git a/tests/extmod/machine_timer.py b/tests/extmod/machine_timer.py new file mode 100644 index 00000000000..ef97ea4e949 --- /dev/null +++ b/tests/extmod/machine_timer.py @@ -0,0 +1,48 @@ +import sys + +try: + from machine import Timer + from time import sleep_ms +except: + print("SKIP") + raise SystemExit + +if sys.platform in ("esp32", "esp8266", "nrf"): + # Software timers aren't implemented on the esp32 and esp8266 ports. + # The nrf port doesn't support selection of hard and soft callbacks, + # and only allows Timer(period=N), not Timer(freq=N). + print("SKIP") + raise SystemExit +else: + timer_id = -1 + +# Test both hard and soft IRQ handlers and both one-shot and periodic +# timers. We adjust period in tests/extmod/machine_soft_timer.py, so try +# adjusting freq here instead. The heap should be locked in hard callbacks +# and unlocked in soft callbacks. + + +def callback(t): + print("callback", mode[1], kind[1], freq, end=" ") + try: + allocate = bytearray(1) + print("unlocked") + except MemoryError: + print("locked") + + +modes = [(Timer.ONE_SHOT, "one-shot"), (Timer.PERIODIC, "periodic")] +kinds = [(False, "soft"), (True, "hard")] + +for mode in modes: + for kind in kinds: + for freq in 50, 25: + timer = Timer( + timer_id, + mode=mode[0], + freq=freq, + hard=kind[0], + callback=callback, + ) + sleep_ms(90) + timer.deinit() diff --git a/tests/extmod/machine_timer.py.exp b/tests/extmod/machine_timer.py.exp new file mode 100644 index 00000000000..26cdc644fdd --- /dev/null +++ b/tests/extmod/machine_timer.py.exp @@ -0,0 +1,16 @@ +callback one-shot soft 50 unlocked +callback one-shot soft 25 unlocked +callback one-shot hard 50 locked +callback one-shot hard 25 locked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 50 unlocked +callback periodic soft 25 unlocked +callback periodic soft 25 unlocked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 50 locked +callback periodic hard 25 locked +callback periodic hard 25 locked diff --git a/tests/extmod/platform_basic.py b/tests/extmod/platform_basic.py new file mode 100644 index 00000000000..eb6f2be13c1 --- /dev/null +++ b/tests/extmod/platform_basic.py @@ -0,0 +1,8 @@ +try: + import platform +except ImportError: + print("SKIP") + raise SystemExit + +print(type(platform.python_compiler())) +print(type(platform.libc_ver())) diff --git a/tests/extmod/random_extra_float.py b/tests/extmod/random_extra_float.py index 3b37ed8dcef..03973c58349 100644 --- a/tests/extmod/random_extra_float.py +++ b/tests/extmod/random_extra_float.py @@ -1,12 +1,8 @@ try: import random -except ImportError: - print("SKIP") - raise SystemExit -try: - random.randint -except AttributeError: + random.random +except (ImportError, AttributeError): print("SKIP") raise SystemExit diff --git a/tests/extmod/re_error.py b/tests/extmod/re_error.py index f61d0913289..bd678c9d251 100644 --- a/tests/extmod/re_error.py +++ b/tests/extmod/re_error.py @@ -11,7 +11,7 @@ def test_re(r): try: re.compile(r) print("OK") - except: # uPy and CPy use different errors, so just ignore the type + except: # MPy and CPy use different errors, so just ignore the type print("Error") diff --git a/tests/extmod/re_start_end_pos.py b/tests/extmod/re_start_end_pos.py new file mode 100644 index 00000000000..bd16584374b --- /dev/null +++ b/tests/extmod/re_start_end_pos.py @@ -0,0 +1,78 @@ +# test start and end pos specification + +try: + import re +except ImportError: + print("SKIP") + raise SystemExit + + +def print_groups(match): + print("----") + try: + if match is not None: + i = 0 + while True: + print(match.group(i)) + i += 1 + except IndexError: + pass + + +p = re.compile(r"o") +m = p.match("dog") +print_groups(m) + +m = p.match("dog", 1) +print_groups(m) + +m = p.match("dog", 2) +print_groups(m) + +# No match past end of input +m = p.match("dog", 5) +print_groups(m) + +m = p.match("dog", 0, 1) +print_groups(m) + +# Caret only matches the actual beginning +p = re.compile(r"^o") +m = p.match("dog", 1) +print_groups(m) + +# End at beginning means searching empty string +p = re.compile(r"o") +m = p.match("dog", 1, 1) +print_groups(m) + +# End before the beginning doesn't match anything +m = p.match("dog", 2, 1) +print_groups(m) + +# Negative starting values don't crash +m = p.search("dog", -2) +print_groups(m) + +m = p.search("dog", -2, -5) +print_groups(m) + +# Search also works +print("--search") + +p = re.compile(r"o") +m = p.search("dog") +print_groups(m) + +m = p.search("dog", 1) +print_groups(m) + +m = p.search("dog", 2) +print_groups(m) + +# Negative starting values don't crash +m = p.search("dog", -2) +print_groups(m) + +m = p.search("dog", -2, -5) +print_groups(m) diff --git a/tests/extmod/re_sub.py b/tests/extmod/re_sub.py index 3959949724d..bb9aa111287 100644 --- a/tests/extmod/re_sub.py +++ b/tests/extmod/re_sub.py @@ -62,7 +62,7 @@ def A(): except: print("invalid group") -# invalid group with very large number (to test overflow in uPy) +# invalid group with very large number (to test overflow in MicroPython) try: re.sub("(a)", "b\\199999999999999999999999999999999999999", "a") except: diff --git a/tests/extmod/re_sub_unmatched.py.exp b/tests/extmod/re_sub_unmatched.py.exp deleted file mode 100644 index 1e5f0fda055..00000000000 --- a/tests/extmod/re_sub_unmatched.py.exp +++ /dev/null @@ -1 +0,0 @@ -1-a2 diff --git a/tests/extmod/socket_badconstructor.py b/tests/extmod/socket_badconstructor.py new file mode 100644 index 00000000000..4a9d2668c7f --- /dev/null +++ b/tests/extmod/socket_badconstructor.py @@ -0,0 +1,22 @@ +# Test passing in bad values to socket.socket constructor. + +try: + import socket +except: + print("SKIP") + raise SystemExit + +try: + s = socket.socket(None) +except TypeError: + print("TypeError") + +try: + s = socket.socket(socket.AF_INET, None) +except TypeError: + print("TypeError") + +try: + s = socket.socket(socket.AF_INET, socket.SOCK_RAW, None) +except TypeError: + print("TypeError") diff --git a/tests/extmod/socket_fileno.py b/tests/extmod/socket_fileno.py new file mode 100644 index 00000000000..da15825e3d5 --- /dev/null +++ b/tests/extmod/socket_fileno.py @@ -0,0 +1,17 @@ +# Test socket.fileno() functionality + +try: + import socket +except ImportError: + print("SKIP") + raise SystemExit + +if not hasattr(socket.socket, "fileno"): + print("SKIP") + raise SystemExit + +s = socket.socket() +print(s.fileno() >= 0) + +s.close() +print(s.fileno()) # should print -1 diff --git a/tests/extmod/time_mktime.py b/tests/extmod/time_mktime.py new file mode 100644 index 00000000000..7fc643dc3cb --- /dev/null +++ b/tests/extmod/time_mktime.py @@ -0,0 +1,120 @@ +# test conversion from date tuple to timestamp and back + +try: + import time + + time.localtime +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +# Range of date expected to work on all MicroPython platforms +MIN_YEAR = 1970 +MAX_YEAR = 2099 +# CPython properly supported date range: +# - on Windows: year 1970 to 3000+ +# - on Unix: year 1583 to 3000+ + +# Start test from Jan 1, 2001 13:00 (Feb 2000 might already be broken) +SAFE_DATE = (2001, 1, 1, 13, 0, 0, 0, 0, -1) + + +# mktime function that checks that the result is reversible +def safe_mktime(date_tuple): + try: + res = time.mktime(date_tuple) + chk = time.localtime(res) + except OverflowError: + print("safe_mktime:", date_tuple, "overflow error") + return None + if chk[0:5] != date_tuple[0:5]: + print("safe_mktime:", date_tuple[0:5], " -> ", res, " -> ", chk[0:5]) + return None + return res + + +# localtime function that checks that the result is reversible +def safe_localtime(timestamp): + try: + res = time.localtime(timestamp) + chk = time.mktime(res) + except OverflowError: + print("safe_localtime:", timestamp, "overflow error") + return None + if chk != timestamp: + print("safe_localtime:", timestamp, " -> ", res, " -> ", chk) + return None + return res + + +# look for smallest valid timestamps by iterating backwards on tuple +def test_bwd(date_tuple): + curr_stamp = safe_mktime(date_tuple) + year = date_tuple[0] + month = date_tuple[1] - 1 + if month < 1: + year -= 1 + month = 12 + while year >= MIN_YEAR: + while month >= 1: + next_tuple = (year, month) + date_tuple[2:] + next_stamp = safe_mktime(next_tuple) + # at this stage, only test consistency and monotonicity + if next_stamp is None or next_stamp >= curr_stamp: + return date_tuple + date_tuple = next_tuple + curr_stamp = next_stamp + month -= 1 + year -= 1 + month = 12 + return date_tuple + + +# test day-by-day to ensure that every date is properly converted +def test_fwd(start_date): + DAYS_PER_MONTH = (0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31) + curr_stamp = safe_mktime(start_date) + curr_date = safe_localtime(curr_stamp) + while curr_date[0] <= MAX_YEAR: + if curr_date[2] < 15: + skip_days = 13 + else: + skip_days = 1 + next_stamp = curr_stamp + skip_days * 86400 + next_date = safe_localtime(next_stamp) + if next_date is None: + return curr_date + if next_date[2] != curr_date[2] + skip_days: + # next month + if next_date[2] != 1: + print("wrong day of month:", next_date) + return curr_date + # check the number of days in previous month + month_days = DAYS_PER_MONTH[curr_date[1]] + if month_days == 28 and curr_date[0] % 4 == 0: + if curr_date[0] % 100 != 0 or curr_date[0] % 400 == 0: + month_days += 1 + if curr_date[2] != month_days: + print("wrong day count in prev month:", curr_date[2], "vs", month_days) + return curr_date + if next_date[1] != curr_date[1] + 1: + # next year + if curr_date[1] != 12: + print("wrong month count in prev year:", curr_date[1]) + return curr_date + if next_date[1] != 1: + print("wrong month:", next_date) + return curr_date + if next_date[0] != curr_date[0] + 1: + print("wrong year:", next_date) + return curr_date + curr_stamp = next_stamp + curr_date = next_date + return curr_date + + +small_date = test_bwd(SAFE_DATE) +large_date = test_fwd(small_date) +print("tested from", small_date[0:3], "to", large_date[0:3]) +print(small_date[0:3], "wday is", small_date[6]) +print(large_date[0:3], "wday is", large_date[6]) diff --git a/tests/extmod/time_res.py b/tests/extmod/time_res.py index 548bef1f174..ef20050b914 100644 --- a/tests/extmod/time_res.py +++ b/tests/extmod/time_res.py @@ -37,9 +37,12 @@ def test(): time.sleep_ms(100) for func_name, _ in EXPECTED_MAP: try: - time_func = getattr(time, func_name, None) or globals()[func_name] + if func_name.endswith("_time"): + time_func = globals()[func_name] + else: + time_func = getattr(time, func_name) now = time_func() # may raise AttributeError - except (KeyError, AttributeError): + except AttributeError: continue try: results_map[func_name].add(now) diff --git a/tests/extmod/tls_dtls.py b/tests/extmod/tls_dtls.py index b2d716769d3..753ab2fee4f 100644 --- a/tests/extmod/tls_dtls.py +++ b/tests/extmod/tls_dtls.py @@ -34,9 +34,19 @@ def ioctl(self, req, arg): # Wrap the DTLS Server dtls_server_ctx = SSLContext(PROTOCOL_DTLS_SERVER) dtls_server_ctx.verify_mode = CERT_NONE -dtls_server = dtls_server_ctx.wrap_socket(server_socket, do_handshake_on_connect=False) +dtls_server = dtls_server_ctx.wrap_socket( + server_socket, do_handshake_on_connect=False, client_id=b"dummy_client_id" +) print("Wrapped DTLS Server") +# wrap DTLS server with invalid client_id +try: + dtls_server = dtls_server_ctx.wrap_socket( + server_socket, do_handshake_on_connect=False, client_id=4 + ) +except OSError: + print("Failed to wrap DTLS Server with invalid client_id") + # Wrap the DTLS Client dtls_client_ctx = SSLContext(PROTOCOL_DTLS_CLIENT) dtls_client_ctx.verify_mode = CERT_NONE diff --git a/tests/extmod/tls_dtls.py.exp b/tests/extmod/tls_dtls.py.exp index 78d72bff188..dbd005d0edf 100644 --- a/tests/extmod/tls_dtls.py.exp +++ b/tests/extmod/tls_dtls.py.exp @@ -1,3 +1,4 @@ Wrapped DTLS Server +Failed to wrap DTLS Server with invalid client_id Wrapped DTLS Client OK diff --git a/tests/extmod/ssl_noleak.py b/tests/extmod/tls_noleak.py similarity index 100% rename from tests/extmod/ssl_noleak.py rename to tests/extmod/tls_noleak.py diff --git a/tests/extmod/tls_threads.py b/tests/extmod/tls_threads.py new file mode 100644 index 00000000000..1e0c3d23d2f --- /dev/null +++ b/tests/extmod/tls_threads.py @@ -0,0 +1,58 @@ +# Ensure that SSL sockets can be allocated from multiple +# threads without thread safety issues + +try: + import _thread + import io + import tls + import time +except ImportError: + print("SKIP") + raise SystemExit + +import unittest + + +class TestSocket(io.IOBase): + def write(self, buf): + return len(buf) + + def readinto(self, buf): + return 0 + + def ioctl(self, cmd, arg): + return 0 + + def setblocking(self, value): + pass + + +ITERS = 256 + + +class TLSThreads(unittest.TestCase): + def test_sslsocket_threaded(self): + self.done = False + # only run in two threads: too much RAM demand otherwise, and rp2 only + # supports two anyhow + _thread.start_new_thread(self._alloc_many_sockets, (True,)) + self._alloc_many_sockets(False) + while not self.done: + time.sleep(0.1) + print("done") + + def _alloc_many_sockets(self, set_done_flag): + print("start", _thread.get_ident()) + ctx = tls.SSLContext(tls.PROTOCOL_TLS_CLIENT) + ctx.verify_mode = tls.CERT_NONE + for n in range(ITERS): + s = TestSocket() + s = ctx.wrap_socket(s, do_handshake_on_connect=False) + s.close() # Free associated resources now from thread, not in a GC pass + print("done", _thread.get_ident()) + if set_done_flag: + self.done = True + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod/uctypes_addressof.py b/tests/extmod/uctypes_addressof.py index c83089d0f72..213fcc05eee 100644 --- a/tests/extmod/uctypes_addressof.py +++ b/tests/extmod/uctypes_addressof.py @@ -12,5 +12,8 @@ print(uctypes.addressof(uctypes.bytearray_at(1 << i, 8))) # Test address that is bigger than the greatest small-int but still within the address range. -large_addr = maxsize + 1 -print(uctypes.addressof(uctypes.bytearray_at(large_addr, 8)) == large_addr) +try: + large_addr = maxsize + 1 + print(uctypes.addressof(uctypes.bytearray_at(large_addr, 8)) == large_addr) +except OverflowError: + print(True) # systems with 64-bit bigints will overflow on the above operation diff --git a/tests/extmod/uctypes_array_load_store.py b/tests/extmod/uctypes_array_load_store.py index 9de07999856..695352da579 100644 --- a/tests/extmod/uctypes_array_load_store.py +++ b/tests/extmod/uctypes_array_load_store.py @@ -6,6 +6,13 @@ print("SKIP") raise SystemExit +# 'int' needs to be able to represent UINT64 for this test +try: + int("FF" * 8, 16) +except OverflowError: + print("SKIP") + raise SystemExit + N = 5 for endian in ("NATIVE", "LITTLE_ENDIAN", "BIG_ENDIAN"): diff --git a/tests/extmod/vfs_blockdev_invalid.py b/tests/extmod/vfs_blockdev_invalid.py index 4d00f4b0027..29d6bd6b2f9 100644 --- a/tests/extmod/vfs_blockdev_invalid.py +++ b/tests/extmod/vfs_blockdev_invalid.py @@ -70,8 +70,8 @@ def test(vfs_class): try: with fs.open("test", "r") as f: print("opened") - except OSError as e: - print("OSError", e) + except Exception as e: + print(type(e), e) # This variant should succeed on open, may fail on read # unless the filesystem cached the contents already @@ -81,8 +81,8 @@ def test(vfs_class): bdev.read_res = res print("read 1", f.read(1)) print("read rest", f.read()) - except OSError as e: - print("OSError", e) + except Exception as e: + print(type(e), e) test(vfs.VfsLfs2) diff --git a/tests/extmod/vfs_blockdev_invalid.py.exp b/tests/extmod/vfs_blockdev_invalid.py.exp index 13695e0d889..0ea0353501d 100644 --- a/tests/extmod/vfs_blockdev_invalid.py.exp +++ b/tests/extmod/vfs_blockdev_invalid.py.exp @@ -2,27 +2,27 @@ opened read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 5] EIO + [Errno 5] EIO read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL + [Errno 22] EINVAL read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL + [Errno 22] EINVAL read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 22] EINVAL + can't convert str to int read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa opened read 1 a read rest aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO -OSError [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + [Errno 5] EIO + can't convert str to int + can't convert str to int diff --git a/tests/extmod/vfs_fat_ilistdir_del.py b/tests/extmod/vfs_fat_ilistdir_del.py index a6e24ec92f3..964e6b12868 100644 --- a/tests/extmod/vfs_fat_ilistdir_del.py +++ b/tests/extmod/vfs_fat_ilistdir_del.py @@ -1,8 +1,7 @@ # Test ilistdir __del__ for VfsFat using a RAM device. -import gc try: - import os, vfs + import gc, os, vfs vfs.VfsFat except (ImportError, AttributeError): diff --git a/tests/extmod/vfs_lfs.py b/tests/extmod/vfs_lfs.py index 3ad57fd9c38..40d58e9c9f7 100644 --- a/tests/extmod/vfs_lfs.py +++ b/tests/extmod/vfs_lfs.py @@ -136,7 +136,7 @@ def test(bdev, vfs_class): print(fs.getcwd()) fs.chdir("../testdir") print(fs.getcwd()) - fs.chdir("../..") + fs.chdir("..") print(fs.getcwd()) fs.chdir(".//testdir") print(fs.getcwd()) diff --git a/tests/extmod/vfs_lfs_error.py b/tests/extmod/vfs_lfs_error.py index 2ac7629bfa8..73cdf343733 100644 --- a/tests/extmod/vfs_lfs_error.py +++ b/tests/extmod/vfs_lfs_error.py @@ -1,7 +1,7 @@ # Test for VfsLittle using a RAM device, testing error handling try: - import vfs + import errno, vfs vfs.VfsLfs1 vfs.VfsLfs2 @@ -41,14 +41,14 @@ def test(bdev, vfs_class): # mkfs with too-small block device try: vfs_class.mkfs(RAMBlockDevice(1)) - except OSError: - print("mkfs OSError") + except OSError as er: + print("mkfs OSError", er.errno > 0) # mount with invalid filesystem try: vfs_class(bdev) - except OSError: - print("mount OSError") + except OSError as er: + print("mount OSError", er.errno > 0) # set up for following tests vfs_class.mkfs(bdev) @@ -60,60 +60,60 @@ def test(bdev, vfs_class): # ilistdir try: fs.ilistdir("noexist") - except OSError: - print("ilistdir OSError") + except OSError as er: + print("ilistdir OSError", er) # remove try: fs.remove("noexist") - except OSError: - print("remove OSError") + except OSError as er: + print("remove OSError", er) # rmdir try: fs.rmdir("noexist") - except OSError: - print("rmdir OSError") + except OSError as er: + print("rmdir OSError", er) # rename try: fs.rename("noexist", "somethingelse") - except OSError: - print("rename OSError") + except OSError as er: + print("rename OSError", er) # mkdir try: fs.mkdir("testdir") - except OSError: - print("mkdir OSError") + except OSError as er: + print("mkdir OSError", er) # chdir to nonexistent try: fs.chdir("noexist") - except OSError: - print("chdir OSError") + except OSError as er: + print("chdir OSError", er) print(fs.getcwd()) # check still at root # chdir to file try: fs.chdir("testfile") - except OSError: - print("chdir OSError") + except OSError as er: + print("chdir OSError", er) print(fs.getcwd()) # check still at root # stat try: fs.stat("noexist") - except OSError: - print("stat OSError") + except OSError as er: + print("stat OSError", er) # error during seek with fs.open("testfile", "r") as f: f.seek(1 << 30) # SEEK_SET try: f.seek(1 << 30, 1) # SEEK_CUR - except OSError: - print("seek OSError") + except OSError as er: + print("seek OSError", er) bdev = RAMBlockDevice(30) diff --git a/tests/extmod/vfs_lfs_error.py.exp b/tests/extmod/vfs_lfs_error.py.exp index f4327f6962e..440607ed84b 100644 --- a/tests/extmod/vfs_lfs_error.py.exp +++ b/tests/extmod/vfs_lfs_error.py.exp @@ -1,28 +1,28 @@ test -mkfs OSError -mount OSError -ilistdir OSError -remove OSError -rmdir OSError -rename OSError -mkdir OSError -chdir OSError +mkfs OSError True +mount OSError True +ilistdir OSError [Errno 2] ENOENT +remove OSError [Errno 2] ENOENT +rmdir OSError [Errno 2] ENOENT +rename OSError [Errno 2] ENOENT +mkdir OSError [Errno 17] EEXIST +chdir OSError [Errno 2] ENOENT / -chdir OSError +chdir OSError [Errno 2] ENOENT / -stat OSError -seek OSError +stat OSError [Errno 2] ENOENT +seek OSError [Errno 22] EINVAL test -mkfs OSError -mount OSError -ilistdir OSError -remove OSError -rmdir OSError -rename OSError -mkdir OSError -chdir OSError +mkfs OSError True +mount OSError True +ilistdir OSError [Errno 2] ENOENT +remove OSError [Errno 2] ENOENT +rmdir OSError [Errno 2] ENOENT +rename OSError [Errno 2] ENOENT +mkdir OSError [Errno 17] EEXIST +chdir OSError [Errno 2] ENOENT / -chdir OSError +chdir OSError [Errno 2] ENOENT / -stat OSError -seek OSError +stat OSError [Errno 2] ENOENT +seek OSError [Errno 22] EINVAL diff --git a/tests/extmod/vfs_lfs_ilistdir_del.py b/tests/extmod/vfs_lfs_ilistdir_del.py index 7b59bc412d9..828c85a2588 100644 --- a/tests/extmod/vfs_lfs_ilistdir_del.py +++ b/tests/extmod/vfs_lfs_ilistdir_del.py @@ -1,8 +1,7 @@ # Test ilistdir __del__ for VfsLittle using a RAM device. -import gc try: - import vfs + import gc, vfs vfs.VfsLfs2 except (ImportError, AttributeError): @@ -71,5 +70,10 @@ def test(bdev, vfs_class): fs.open("/test", "w").close() -bdev = RAMBlockDevice(30) +try: + bdev = RAMBlockDevice(30) +except MemoryError: + print("SKIP") + raise SystemExit + test(bdev, vfs.VfsLfs2) diff --git a/tests/extmod/vfs_mountinfo.py b/tests/extmod/vfs_mountinfo.py index f674e807634..b31dc60ce76 100644 --- a/tests/extmod/vfs_mountinfo.py +++ b/tests/extmod/vfs_mountinfo.py @@ -5,7 +5,6 @@ except ImportError: print("SKIP") raise SystemExit -import errno class Filesystem: diff --git a/tests/extmod/vfs_posix.py b/tests/extmod/vfs_posix.py index d060c0b9c84..b3ca2753ba9 100644 --- a/tests/extmod/vfs_posix.py +++ b/tests/extmod/vfs_posix.py @@ -29,7 +29,21 @@ print(type(os.stat("/"))) # listdir and ilistdir -print(type(os.listdir("/"))) +target = "/" +try: + import platform + + # On Android non-root users are permitted full filesystem access only to + # selected directories. To let this test pass on bionic, the internal + # user-accessible storage area root is enumerated instead of the + # filesystem root. "/storage/emulated/0" should be there on pretty much + # any recent-ish device; querying the proper location requires a JNI + # round-trip, not really worth it. + if platform.platform().startswith("Android-"): + target = "/storage/emulated/0" +except ImportError: + pass +print(type(os.listdir(target))) # mkdir os.mkdir(temp_dir) diff --git a/tests/extmod/vfs_posix_ilistdir_del.py b/tests/extmod/vfs_posix_ilistdir_del.py index 78d7c854c54..8b5984cd81c 100644 --- a/tests/extmod/vfs_posix_ilistdir_del.py +++ b/tests/extmod/vfs_posix_ilistdir_del.py @@ -1,8 +1,7 @@ # Test ilistdir __del__ for VfsPosix. -import gc try: - import os, vfs + import gc, os, vfs vfs.VfsPosix except (ImportError, AttributeError): diff --git a/tests/extmod/vfs_posix_paths.py b/tests/extmod/vfs_posix_paths.py index b4fedc6716f..c06318748a3 100644 --- a/tests/extmod/vfs_posix_paths.py +++ b/tests/extmod/vfs_posix_paths.py @@ -31,7 +31,7 @@ fs.mkdir("subdir/one") print('listdir("/"):', sorted(i[0] for i in fs.ilistdir("/"))) print('listdir("."):', sorted(i[0] for i in fs.ilistdir("."))) -print('getcwd() in {"", "/"}:', fs.getcwd() in {"", "/"}) +print('getcwd() in ("", "/"):', fs.getcwd() in ("", "/")) print('chdir("subdir"):', fs.chdir("subdir")) print("getcwd():", fs.getcwd()) print('mkdir("two"):', fs.mkdir("two")) diff --git a/tests/extmod/vfs_posix_paths.py.exp b/tests/extmod/vfs_posix_paths.py.exp index ecc13222aaa..d6a0960efd2 100644 --- a/tests/extmod/vfs_posix_paths.py.exp +++ b/tests/extmod/vfs_posix_paths.py.exp @@ -1,6 +1,6 @@ listdir("/"): ['subdir'] listdir("."): ['subdir'] -getcwd() in {"", "/"}: True +getcwd() in ("", "/"): True chdir("subdir"): None getcwd(): /subdir mkdir("two"): None diff --git a/tests/extmod/vfs_posix_readonly.py b/tests/extmod/vfs_posix_readonly.py new file mode 100644 index 00000000000..e7821381006 --- /dev/null +++ b/tests/extmod/vfs_posix_readonly.py @@ -0,0 +1,99 @@ +# Test for VfsPosix + +try: + import gc, os, vfs, errno + + vfs.VfsPosix +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +# We need a directory for testing that doesn't already exist. +# Skip the test if it does exist. +temp_dir = "vfs_posix_readonly_test_dir" +try: + os.stat(temp_dir) + raise SystemExit("Target directory {} exists".format(temp_dir)) +except OSError: + pass + +# mkdir (skip test if whole filesystem is readonly) +try: + os.mkdir(temp_dir) +except OSError as e: + if e.errno == errno.EROFS: + print("SKIP") + raise SystemExit + +fs_factory = lambda: vfs.VfsPosix(temp_dir) + +# mount +fs = fs_factory() +vfs.mount(fs, "/vfs") + +with open("/vfs/file", "w") as f: + f.write("content") + +# test reading works +with open("/vfs/file") as f: + print("file:", f.read()) + +os.mkdir("/vfs/emptydir") + +# umount +vfs.umount("/vfs") + +# mount read-only +fs = fs_factory() +vfs.mount(fs, "/vfs", readonly=True) + +# test reading works +with open("/vfs/file") as f: + print("file 2:", f.read()) + +# test writing fails +try: + with open("/vfs/test_write", "w"): + pass + print("opened") +except OSError as er: + print(repr(er)) + +# test removing fails +try: + os.unlink("/vfs/file") + print("unlinked") +except OSError as er: + print(repr(er)) + +# test renaming fails +try: + os.rename("/vfs/file2", "/vfs/renamed") + print("renamed") +except OSError as er: + print(repr(er)) + +# test removing directory fails +try: + os.rmdir("/vfs/emptydir") + print("rmdir'd") +except OSError as er: + print(repr(er)) + +# test creating directory fails +try: + os.mkdir("/vfs/emptydir2") + print("mkdir'd") +except OSError as er: + print(repr(er)) + +# umount +vfs.umount("/vfs") + +fs = fs_factory() +vfs.mount(fs, "/vfs") + +os.rmdir("/vfs/emptydir") +os.unlink("/vfs/file") + +os.rmdir(temp_dir) diff --git a/tests/extmod/vfs_posix_readonly.py.exp b/tests/extmod/vfs_posix_readonly.py.exp new file mode 100644 index 00000000000..40e4316775f --- /dev/null +++ b/tests/extmod/vfs_posix_readonly.py.exp @@ -0,0 +1,7 @@ +file: content +file 2: content +OSError(30,) +OSError(30,) +OSError(30,) +OSError(30,) +OSError(30,) diff --git a/tests/extmod/vfs_rom.py b/tests/extmod/vfs_rom.py index 770b6863b9c..18ae1f5cf96 100644 --- a/tests/extmod/vfs_rom.py +++ b/tests/extmod/vfs_rom.py @@ -25,7 +25,7 @@ # An mpy file with four constant objects: str, bytes, long-int, float. test_mpy = ( # header - b"M\x06\x00\x1f" # mpy file header + b"M\x06\x00\x1e" # mpy file header, -msmall-int-bits=30 b"\x06" # n_qstr b"\x05" # n_obj # qstrs @@ -394,6 +394,7 @@ class TestMounted(TestBase): def setUp(self): self.orig_sys_path = list(sys.path) self.orig_cwd = os.getcwd() + sys.path = [] vfs.mount(vfs.VfsRom(self.romfs), "/test_rom") def tearDown(self): diff --git a/tests/extmod/websocket_toobig.py b/tests/extmod/websocket_toobig.py new file mode 100644 index 00000000000..f4c5a74bbce --- /dev/null +++ b/tests/extmod/websocket_toobig.py @@ -0,0 +1,28 @@ +try: + import io + import errno + import websocket +except ImportError: + print("SKIP") + raise SystemExit + +try: + buf = "x" * 65536 +except MemoryError: + print("SKIP") + raise SystemExit + + +# do a websocket write and then return the raw data from the stream +def ws_write(msg, sz): + s = io.BytesIO() + ws = websocket.websocket(s) + ws.write(msg) + s.seek(0) + return s.read(sz) + + +try: + print(ws_write(buf, 1)) +except OSError as e: + print("ioctl: ENOBUFS:", e.errno == errno.ENOBUFS) diff --git a/tests/extmod/websocket_toobig.py.exp b/tests/extmod/websocket_toobig.py.exp new file mode 100644 index 00000000000..3bbd95282fd --- /dev/null +++ b/tests/extmod/websocket_toobig.py.exp @@ -0,0 +1 @@ +ioctl: ENOBUFS: True diff --git a/tests/extmod_hardware/machine_counter.py b/tests/extmod_hardware/machine_counter.py new file mode 100644 index 00000000000..62ac1fed47c --- /dev/null +++ b/tests/extmod_hardware/machine_counter.py @@ -0,0 +1,90 @@ +# Test machine.Counter implementation +# +# IMPORTANT: This test requires hardware connections: the out_pin and in_pin +# must be wired together. + +try: + from machine import Counter +except ImportError: + print("SKIP") + raise SystemExit + +import sys +from machine import Pin + +if "esp32" in sys.platform: + id = 0 + out_pin = 4 + in_pin = 5 +else: + print("Please add support for this test on this platform.") + raise SystemExit + +import unittest + +out_pin = Pin(out_pin, mode=Pin.OUT) +in_pin = Pin(in_pin, mode=Pin.IN) + + +def toggle(times): + for _ in range(times): + out_pin(1) + out_pin(0) + + +class TestCounter(unittest.TestCase): + def setUp(self): + out_pin(0) + self.counter = Counter(id, in_pin) + + def tearDown(self): + self.counter.deinit() + + def assertCounter(self, value): + self.assertEqual(self.counter.value(), value) + + def test_connections(self): + # Test the hardware connections are correct. If this test fails, all tests will fail. + out_pin(1) + self.assertEqual(1, in_pin()) + out_pin(0) + self.assertEqual(0, in_pin()) + + def test_count_rising(self): + self.assertCounter(0) + toggle(100) + self.assertCounter(100) + out_pin(1) + self.assertEqual(self.counter.value(0), 101) + self.assertCounter(0) # calling value(0) resets + out_pin(0) + self.assertCounter(0) # no rising edge + out_pin(1) + self.assertCounter(1) + + def test_change_directions(self): + self.assertCounter(0) + toggle(100) + self.assertCounter(100) + self.counter.init(in_pin, direction=Counter.DOWN) + self.assertCounter(0) # calling init() zeroes the counter + self.counter.value(100) # need to manually reset the value + self.assertCounter(100) + toggle(25) + self.assertCounter(75) + + def test_count_falling(self): + self.counter.init(in_pin, direction=Counter.UP, edge=Counter.FALLING) + toggle(20) + self.assertCounter(20) + out_pin(1) + self.assertCounter(20) # no falling edge + out_pin(0) + self.assertCounter(21) + self.counter.value(-(2**24)) + toggle(20) + self.assertCounter(-(2**24 - 20)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod_hardware/machine_encoder.py b/tests/extmod_hardware/machine_encoder.py new file mode 100644 index 00000000000..c218c8bfb64 --- /dev/null +++ b/tests/extmod_hardware/machine_encoder.py @@ -0,0 +1,153 @@ +# Test machine.Encoder implementation +# +# IMPORTANT: This test requires hardware connections: +# - out0_pin and in0_pin must be wired together. +# - out1_pin and in1_pin must be wired together. + +try: + from machine import Encoder +except ImportError: + print("SKIP") + raise SystemExit + +import sys +import unittest +from machine import Pin +from target_wiring import encoder_loopback_id, encoder_loopback_out_pins, encoder_loopback_in_pins + +PRINT = False +PIN_INIT_VALUE = 1 + +id = encoder_loopback_id +out0_pin, out1_pin = encoder_loopback_out_pins +in0_pin, in1_pin = encoder_loopback_in_pins + +out0_pin = Pin(out0_pin, mode=Pin.OUT) +in0_pin = Pin(in0_pin, mode=Pin.IN) +out1_pin = Pin(out1_pin, mode=Pin.OUT) +in1_pin = Pin(in1_pin, mode=Pin.IN) + + +class TestEncoder(unittest.TestCase): + def setUp(self): + out0_pin(PIN_INIT_VALUE) + out1_pin(PIN_INIT_VALUE) + self.enc = Encoder(id, in0_pin, in1_pin, phases=1) + self.enc2 = Encoder(id + 1, in0_pin, in1_pin, phases=2) + self.enc4 = Encoder(id + 2, in0_pin, in1_pin, phases=4) + self.pulses = 0 # track the expected encoder position in software + if PRINT: + print( + "\nout0_pin() out1_pin() enc.value() enc2.value() enc4.value() |", + out0_pin(), + out1_pin(), + "|", + self.enc.value(), + self.enc2.value(), + self.enc4.value(), + ) + + def tearDown(self): + self.enc.deinit() + try: + self.enc2.deinit() + except: + pass + try: + self.enc4.deinit() + except: + pass + + def rotate(self, pulses): + for _ in range(abs(pulses)): + self.pulses += 1 if (pulses > 0) else -1 + if pulses > 0: + if self.pulses % 2: + out0_pin(not out0_pin()) + else: + out1_pin(not out1_pin()) + else: + if self.pulses % 2: + out1_pin(not out1_pin()) + else: + out0_pin(not out0_pin()) + if PRINT: + print( + "out0_pin() out1_pin() enc.value() enc2.value() enc4.value() pulses self.pulses |", + out0_pin(), + out1_pin(), + "|", + self.enc.value(), + self.enc2.value(), + self.enc4.value(), + "|", + pulses, + self.pulses, + ) + + def assertPosition(self, value, value2=None, value4=None): + self.assertEqual(self.enc.value(), value) + if not value2 is None: + self.assertEqual(self.enc2.value(), value2) + if not value4 is None: + self.assertEqual(self.enc4.value(), value4) + pass + + @unittest.skipIf(sys.platform == "mimxrt", "cannot read back the pin") + def test_connections(self): + # Test the hardware connections are correct. If this test fails, all tests will fail. + for ch, outp, inp in ((0, out0_pin, in0_pin), (1, out1_pin, in1_pin)): + print("Testing channel ", ch) + outp(1) + self.assertEqual(1, inp()) + outp(0) + self.assertEqual(0, inp()) + + def test_basics(self): + self.assertPosition(0) + self.rotate(100) + self.assertPosition(100 // 4, 100 // 2, 100) + self.rotate(-100) + self.assertPosition(0) + + def test_partial(self): + # With phase=1 (default), need 4x pulses to count a rotation + self.assertPosition(0) + self.rotate(1) + self.assertPosition(1, 1, 1) + self.rotate(1) + self.assertPosition(1, 1, 2) + self.rotate(1) + self.assertPosition(1, 2, 3) + self.rotate(1) + self.assertPosition(1, 2, 4) # +4 + self.rotate(1) + self.assertPosition(2, 3, 5) + self.rotate(1) + self.assertPosition(2, 3, 6) + self.rotate(1) + self.assertPosition(2, 4, 7) + self.rotate(1) + self.assertPosition(2, 4, 8) # +4 + self.rotate(-1) + self.assertPosition(2, 4, 7) + self.rotate(-3) + self.assertPosition(1, 2, 4) # -4 + self.rotate(-4) + self.assertPosition(0, 0, 0) # -4 + self.rotate(-1) + self.assertPosition(0, 0, -1) + self.rotate(-1) + self.assertPosition(0, -1, -2) + self.rotate(-1) + self.assertPosition(0, -1, -3) + self.rotate(-1) + self.assertPosition(-1, -2, -4) # -4 + self.rotate(-1) + self.assertPosition(-1, -2, -5) + self.rotate(-3) + self.assertPosition(-2, -4, -8) # -4 + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/extmod_hardware/machine_i2c_target.py b/tests/extmod_hardware/machine_i2c_target.py new file mode 100644 index 00000000000..763e6f4771e --- /dev/null +++ b/tests/extmod_hardware/machine_i2c_target.py @@ -0,0 +1,307 @@ +# Test machine.I2CTarget. +# +# IMPORTANT: This test requires hardware connections: a SoftI2C instance must be +# wired to a hardware I2C target. See pin definitions below. + +import sys + +try: + from machine import Pin, SoftI2C, I2CTarget +except ImportError: + print("SKIP") + raise SystemExit + +import unittest + +ADDR = 67 + +kwargs_target = {} + +# Configure pins based on the target. +if sys.platform == "alif" and sys.implementation._build == "ALIF_ENSEMBLE": + args_controller = {"scl": "P1_1", "sda": "P1_0"} + args_target = (0,) # on pins P0_3/P0_2 +elif sys.platform == "esp32": + args_controller = {"scl": 5, "sda": 6} + args_target = (0,) # on pins 9/8 for C3 and S3, 18/19 for others + kwargs_target = {"scl": 9, "sda": 8} +elif sys.platform == "rp2": + args_controller = {"scl": 5, "sda": 4} + args_target = (1,) +elif sys.platform == "pyboard": + if sys.implementation._build == "NUCLEO_WB55": + args_controller = {"scl": "B8", "sda": "B9"} + args_target = (3,) + else: + args_controller = {"scl": "X1", "sda": "X2"} + args_target = ("X",) +elif "zephyr-nucleo_wb55rg" in sys.implementation._machine: + # PB8=I2C1_SCL, PB9=I2C1_SDA (on Arduino header D15/D14) + # PC0=I2C3_SCL, PC1=I2C3_SDA (on Arduino header A0/A1) + args_controller = {"scl": Pin(("gpiob", 8)), "sda": Pin(("gpiob", 9))} + args_target = ("i2c3",) +elif "zephyr-rpi_pico" in sys.implementation._machine: + args_controller = {"scl": Pin(("gpio0", 5)), "sda": Pin(("gpio0", 4))} + args_target = ("i2c1",) # on gpio7/gpio6 +elif sys.platform == "mimxrt": + if "Teensy" in sys.implementation._machine: + args_controller = {"scl": "A6", "sda": "A3"} # D20/D17 + else: + args_controller = {"scl": "D0", "sda": "D1"} + args_target = (0,) # pins 19/18 On Teensy 4.x +elif sys.platform == "samd": + args_controller = {"scl": "D5", "sda": "D1"} + args_target = () +else: + print("Please add support for this test on this platform.") + raise SystemExit + + +def config_pull_up(): + Pin(args_controller["scl"], Pin.OPEN_DRAIN, Pin.PULL_UP) + Pin(args_controller["sda"], Pin.OPEN_DRAIN, Pin.PULL_UP) + + +class TestMemory(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.mem = bytearray(8) + cls.i2c = SoftI2C(**args_controller) + cls.i2c_target = I2CTarget(*args_target, **kwargs_target, addr=ADDR, mem=cls.mem) + config_pull_up() + + @classmethod + def tearDownClass(cls): + cls.i2c_target.deinit() + + def test_scan(self): + self.assertIn(ADDR, self.i2c.scan()) + + def test_write(self): + self.mem[:] = b"01234567" + self.i2c.writeto_mem(ADDR, 0, b"test") + self.assertEqual(self.mem, bytearray(b"test4567")) + self.i2c.writeto_mem(ADDR, 4, b"TEST") + self.assertEqual(self.mem, bytearray(b"testTEST")) + + def test_write_wrap(self): + self.mem[:] = b"01234567" + self.i2c.writeto_mem(ADDR, 6, b"test") + self.assertEqual(self.mem, bytearray(b"st2345te")) + + @unittest.skipIf(sys.platform == "esp32", "write lengths larger than buffer unsupported") + def test_write_wrap_large(self): + self.mem[:] = b"01234567" + self.i2c.writeto_mem(ADDR, 0, b"testTESTmore") + self.assertEqual(self.mem, bytearray(b"moreTEST")) + + def test_read(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.readfrom_mem(ADDR, 0, 4), b"0123") + self.assertEqual(self.i2c.readfrom_mem(ADDR, 4, 4), b"4567") + + def test_read_wrap(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.readfrom_mem(ADDR, 0, 4), b"0123") + self.assertEqual(self.i2c.readfrom_mem(ADDR, 2, 4), b"2345") + self.assertEqual(self.i2c.readfrom_mem(ADDR, 6, 4), b"6701") + + @unittest.skipIf(sys.platform == "esp32", "read lengths larger than buffer unsupported") + def test_read_wrap_large(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.readfrom_mem(ADDR, 0, 12), b"012345670123") + + def test_write_read(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.writeto(ADDR, b"\x02"), 1) + self.assertEqual(self.i2c.readfrom(ADDR, 4), b"2345") + + @unittest.skipIf(sys.platform == "esp32", "read after read unsupported") + def test_write_read_read(self): + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.writeto(ADDR, b"\x02"), 1) + self.assertEqual(self.i2c.readfrom(ADDR, 4), b"2345") + self.assertEqual(self.i2c.readfrom(ADDR, 4), b"7012") + + +@unittest.skipUnless(hasattr(I2CTarget, "IRQ_END_READ"), "IRQ unsupported") +class TestMemoryIRQ(unittest.TestCase): + @staticmethod + def irq_handler(i2c_target): + flags = i2c_target.irq().flags() + TestMemoryIRQ.events[TestMemoryIRQ.num_events] = flags + TestMemoryIRQ.events[TestMemoryIRQ.num_events + 1] = i2c_target.memaddr + TestMemoryIRQ.num_events += 2 + + @classmethod + def setUpClass(cls): + cls.mem = bytearray(8) + cls.events = [0] * 8 + cls.num_events = 0 + cls.i2c = SoftI2C(**args_controller) + cls.i2c_target = I2CTarget(*args_target, **kwargs_target, addr=ADDR, mem=cls.mem) + cls.i2c_target.irq(TestMemoryIRQ.irq_handler) + config_pull_up() + + @classmethod + def tearDownClass(cls): + cls.i2c_target.deinit() + + @unittest.skipIf(sys.platform == "esp32", "scan doesn't trigger IRQ_END_WRITE") + def test_scan(self): + TestMemoryIRQ.num_events = 0 + self.i2c.scan() + self.assertEqual(self.events[: self.num_events], [I2CTarget.IRQ_END_WRITE, 0]) + + def test_write(self): + TestMemoryIRQ.num_events = 0 + self.mem[:] = b"01234567" + self.i2c.writeto_mem(ADDR, 2, b"test") + self.assertEqual(self.mem, bytearray(b"01test67")) + self.assertEqual(self.events[: self.num_events], [I2CTarget.IRQ_END_WRITE, 2]) + + def test_read(self): + TestMemoryIRQ.num_events = 0 + self.mem[:] = b"01234567" + self.assertEqual(self.i2c.readfrom_mem(ADDR, 2, 4), b"2345") + self.assertEqual(self.events[: self.num_events], [I2CTarget.IRQ_END_READ, 2]) + + +@unittest.skipUnless(hasattr(I2CTarget, "IRQ_WRITE_REQ"), "IRQ unsupported") +@unittest.skipIf(sys.platform == "mimxrt", "not working") +@unittest.skipIf(sys.platform == "pyboard", "can't queue more than one byte") +@unittest.skipIf(sys.platform == "samd", "not working") +@unittest.skipIf(sys.platform == "zephyr", "must call readinto/write in IRQ handler") +class TestPolling(unittest.TestCase): + @staticmethod + def irq_handler(i2c_target, buf=bytearray(1)): + flags = i2c_target.irq().flags() + if flags & I2CTarget.IRQ_READ_REQ: + i2c_target.write(b"0123") + + @classmethod + def setUpClass(cls): + cls.i2c = SoftI2C(**args_controller) + cls.i2c_target = I2CTarget(*args_target, addr=ADDR) + cls.i2c_target.irq( + TestPolling.irq_handler, + I2CTarget.IRQ_WRITE_REQ | I2CTarget.IRQ_READ_REQ, + hard=True, + ) + config_pull_up() + + @classmethod + def tearDownClass(cls): + cls.i2c_target.deinit() + + def test_read(self): + # Can't write data up front, must wait until IRQ_READ_REQ. + # self.assertEqual(self.i2c_target.write(b"abcd"), 4) + self.assertEqual(self.i2c.readfrom(ADDR, 4), b"0123") + + def test_write(self): + # Can do the read outside the IRQ, but requires IRQ_WRITE_REQ trigger to be set. + self.assertEqual(self.i2c.writeto(ADDR, b"0123"), 4) + buf = bytearray(8) + self.assertEqual(self.i2c_target.readinto(buf), 4) + self.assertEqual(buf, b"0123\x00\x00\x00\x00") + + +@unittest.skipUnless(hasattr(I2CTarget, "IRQ_ADDR_MATCH_READ"), "IRQ unsupported") +class TestIRQ(unittest.TestCase): + @staticmethod + def irq_handler(i2c_target, buf=bytearray(1)): + flags = i2c_target.irq().flags() + TestIRQ.events[TestIRQ.num_events] = flags + TestIRQ.num_events += 1 + if flags & I2CTarget.IRQ_READ_REQ: + i2c_target.write(b"Y") + if flags & I2CTarget.IRQ_WRITE_REQ: + i2c_target.readinto(buf) + TestIRQ.events[TestIRQ.num_events] = buf[0] + TestIRQ.num_events += 1 + + @classmethod + def setUpClass(cls): + cls.events = [0] * 8 + cls.num_events = 0 + cls.i2c = SoftI2C(**args_controller) + cls.i2c_target = I2CTarget(*args_target, addr=ADDR) + cls.i2c_target.irq( + TestIRQ.irq_handler, + I2CTarget.IRQ_ADDR_MATCH_READ + | I2CTarget.IRQ_ADDR_MATCH_WRITE + | I2CTarget.IRQ_WRITE_REQ + | I2CTarget.IRQ_READ_REQ + | I2CTarget.IRQ_END_READ + | I2CTarget.IRQ_END_WRITE, + hard=True, + ) + config_pull_up() + + @classmethod + def tearDownClass(cls): + cls.i2c_target.deinit() + + def test_scan(self): + TestIRQ.num_events = 0 + self.i2c.scan() + self.assertEqual( + self.events[: self.num_events], + [ + I2CTarget.IRQ_ADDR_MATCH_WRITE, + I2CTarget.IRQ_END_WRITE, + ], + ) + + def test_write(self): + TestIRQ.num_events = 0 + self.i2c.writeto(ADDR, b"XYZ") + self.assertEqual( + self.events[: self.num_events], + [ + I2CTarget.IRQ_ADDR_MATCH_WRITE, + I2CTarget.IRQ_WRITE_REQ, + ord(b"X"), + I2CTarget.IRQ_WRITE_REQ, + ord(b"Y"), + I2CTarget.IRQ_WRITE_REQ, + ord(b"Z"), + I2CTarget.IRQ_END_WRITE, + ], + ) + + def test_read(self): + TestIRQ.num_events = 0 + self.assertEqual(self.i2c.readfrom(ADDR, 1), b"Y") + self.assertEqual( + self.events[: self.num_events], + [ + I2CTarget.IRQ_ADDR_MATCH_READ, + I2CTarget.IRQ_READ_REQ, + I2CTarget.IRQ_READ_REQ, + I2CTarget.IRQ_END_READ, + ], + ) + + def test_write_read(self): + TestIRQ.num_events = 0 + self.i2c.writeto(ADDR, b"X", False) + self.assertEqual(self.i2c.readfrom(ADDR, 1), b"Y") + self.assertEqual( + self.events[: self.num_events], + [ + I2CTarget.IRQ_ADDR_MATCH_WRITE, + I2CTarget.IRQ_WRITE_REQ, + ord(b"X"), + I2CTarget.IRQ_END_WRITE, + I2CTarget.IRQ_ADDR_MATCH_READ, + I2CTarget.IRQ_READ_REQ, + I2CTarget.IRQ_READ_REQ, + I2CTarget.IRQ_END_READ, + ], + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/feature_check/float.py b/tests/feature_check/float.py deleted file mode 100644 index d6d2a99d242..00000000000 --- a/tests/feature_check/float.py +++ /dev/null @@ -1,13 +0,0 @@ -# detect how many bits of precision the floating point implementation has - -try: - float -except NameError: - print(0) -else: - if float("1.0000001") == float("1.0"): - print(30) - elif float("1e300") == float("inf"): - print(32) - else: - print(64) diff --git a/tests/feature_check/float.py.exp b/tests/feature_check/float.py.exp deleted file mode 100644 index 900731ffd51..00000000000 --- a/tests/feature_check/float.py.exp +++ /dev/null @@ -1 +0,0 @@ -64 diff --git a/tests/feature_check/inlineasm_rv32_zba.py b/tests/feature_check/inlineasm_rv32_zba.py new file mode 100644 index 00000000000..81228819042 --- /dev/null +++ b/tests/feature_check/inlineasm_rv32_zba.py @@ -0,0 +1,10 @@ +# check if RISC-V 32 inline asm supported Zba opcodes + + +@micropython.asm_rv32 +def f(): + sh1add(a0, a0, a0) + + +f() +print("rv32_zba") diff --git a/tests/feature_check/inlineasm_rv32_zba.py.exp b/tests/feature_check/inlineasm_rv32_zba.py.exp new file mode 100644 index 00000000000..fde22f5f400 --- /dev/null +++ b/tests/feature_check/inlineasm_rv32_zba.py.exp @@ -0,0 +1 @@ +rv32_zba diff --git a/tests/feature_check/int_64.py b/tests/feature_check/int_64.py new file mode 100644 index 00000000000..4d053782ca8 --- /dev/null +++ b/tests/feature_check/int_64.py @@ -0,0 +1,2 @@ +# Check whether 64-bit long integers are supported +print(1 << 62) diff --git a/tests/feature_check/int_64.py.exp b/tests/feature_check/int_64.py.exp new file mode 100644 index 00000000000..aef5454e662 --- /dev/null +++ b/tests/feature_check/int_64.py.exp @@ -0,0 +1 @@ +4611686018427387904 diff --git a/tests/feature_check/io_module.py b/tests/feature_check/io_module.py deleted file mode 100644 index 9094e605316..00000000000 --- a/tests/feature_check/io_module.py +++ /dev/null @@ -1,6 +0,0 @@ -try: - import io - - print("io") -except ImportError: - print("no") diff --git a/tests/feature_check/io_module.py.exp b/tests/feature_check/io_module.py.exp deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/tests/feature_check/repl_emacs_check.py.exp b/tests/feature_check/repl_emacs_check.py.exp index 82a4e28ee4f..5fe8ba1cd2d 100644 --- a/tests/feature_check/repl_emacs_check.py.exp +++ b/tests/feature_check/repl_emacs_check.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # Check for emacs keys in REPL >>> t = \.\+ >>> t == 2 diff --git a/tests/feature_check/repl_words_move_check.py.exp b/tests/feature_check/repl_words_move_check.py.exp index 82a4e28ee4f..5fe8ba1cd2d 100644 --- a/tests/feature_check/repl_words_move_check.py.exp +++ b/tests/feature_check/repl_words_move_check.py.exp @@ -1,5 +1,5 @@ MicroPython \.\+ version -Use \.\+ +Type "help()" for more information. >>> # Check for emacs keys in REPL >>> t = \.\+ >>> t == 2 diff --git a/tests/feature_check/target_info.py b/tests/feature_check/target_info.py index f60f3b31919..e95530023d7 100644 --- a/tests/feature_check/target_info.py +++ b/tests/feature_check/target_info.py @@ -19,5 +19,21 @@ "xtensa", "xtensawin", "rv32imc", -][sys_mpy >> 10] -print(platform, arch) + "rv64imc", +][(sys_mpy >> 10) & 0x0F] +arch_flags = sys_mpy >> 16 +build = getattr(sys.implementation, "_build", "unknown") +thread = getattr(sys.implementation, "_thread", None) + +# Detect how many bits of precision the floating point implementation has. +try: + if float("1.0000001") == float("1.0"): + float_prec = 30 + elif float("1e300") == float("inf"): + float_prec = 32 + else: + float_prec = 64 +except NameError: + float_prec = 0 + +print(platform, arch, arch_flags, build, thread, float_prec, len("α") == 1) diff --git a/tests/float/cmath_fun.py b/tests/float/cmath_fun.py index 39011733b02..0037d7c6559 100644 --- a/tests/float/cmath_fun.py +++ b/tests/float/cmath_fun.py @@ -51,6 +51,9 @@ print("%.5g" % ret) elif type(ret) == tuple: print("%.5g %.5g" % ret) + elif f_name == "exp": + # exp amplifies REPR_C inaccuracies, so we need to check one digit less + print("complex(%.4g, %.4g)" % (real, ret.imag)) else: # some test (eg cmath.sqrt(-0.5)) disagree with CPython with tiny real part real = ret.real diff --git a/tests/float/float_array.py b/tests/float/float_array.py index 3d128da8381..cfff3b220c6 100644 --- a/tests/float/float_array.py +++ b/tests/float/float_array.py @@ -19,4 +19,10 @@ def test(a): test(array("f")) test(array("d")) -print("{:.4f}".format(array("f", bytes(array("I", [0x3DCCCCCC])))[0])) +# hand-crafted floats, including non-standard nan +for float_hex in (0x3DCCCCCC, 0x7F800024, 0x7FC00004): + f = array("f", bytes(array("I", [float_hex])))[0] + if type(f) is float: + print("{:.4e}".format(f)) + else: + print(f) diff --git a/tests/float/float_format.py b/tests/float/float_format.py index 98ed0eb096f..0eb8b232b06 100644 --- a/tests/float/float_format.py +++ b/tests/float/float_format.py @@ -2,14 +2,25 @@ # general rounding for val in (116, 1111, 1234, 5010, 11111): - print("%.0f" % val) - print("%.1f" % val) - print("%.3f" % val) + print("Test on %d / 1000:" % val) + for fmt in ("%.5e", "%.3e", "%.1e", "%.0e", "%.3f", "%.1f", "%.0f", "%.3g", "%.1g", "%.0g"): + print(fmt, fmt % (val / 1000)) + +# make sure round-up to the next unit is handled properly +for val in range(4, 9): + divi = 10**val + print("Test on 99994 / (10 ** %d):" % val) + for fmt in ("%.5e", "%.3e", "%.1e", "%.0e", "%.3f", "%.1f", "%.0f", "%.3g", "%.1g", "%.0g"): + print(fmt, fmt % (99994 / divi)) # make sure rounding is done at the correct precision for prec in range(8): print(("%%.%df" % prec) % 6e-5) +# make sure trailing zeroes are added properly +for prec in range(8): + print(("%%.%df" % prec) % 1e19) + # check certain cases that had a digit value of 10 render as a ":" character print("%.2e" % float("9" * 51 + "e-39")) print("%.2e" % float("9" * 40 + "e-21")) diff --git a/tests/float/float_format_accuracy.py b/tests/float/float_format_accuracy.py new file mode 100644 index 00000000000..f9467f9c05d --- /dev/null +++ b/tests/float/float_format_accuracy.py @@ -0,0 +1,73 @@ +# Test accuracy of `repr` conversions. +# This test also increases code coverage for corner cases. + +try: + import array, math, random +except ImportError: + print("SKIP") + raise SystemExit + +# The largest errors come from seldom used very small numbers, near the +# limit of the representation. So we keep them out of this test to keep +# the max relative error display useful. +if float("1e-100") == 0.0: + # single-precision + float_type = "f" + float_size = 4 + # testing range + min_expo = -96 # i.e. not smaller than 1.0e-29 + # Expected results (given >=50'000 samples): + # - MICROPY_FLTCONV_IMPL_EXACT: 100% exact conversions + # - MICROPY_FLTCONV_IMPL_APPROX: >=98.53% exact conversions, max relative error <= 1.01e-7 + min_success = 0.980 # with only 1200 samples, the success rate is lower + max_rel_err = 1.1e-7 + # REPR_C is typically used with FORMAT_IMPL_BASIC, which has a larger error + is_REPR_C = float("1.0000001") == float("1.0") + if is_REPR_C: # REPR_C + min_success = 0.83 + max_rel_err = 5.75e-07 +else: + # double-precision + float_type = "d" + float_size = 8 + # testing range + min_expo = -845 # i.e. not smaller than 1.0e-254 + # Expected results (given >=200'000 samples): + # - MICROPY_FLTCONV_IMPL_EXACT: 100% exact conversions + # - MICROPY_FLTCONV_IMPL_APPROX: >=99.83% exact conversions, max relative error <= 2.7e-16 + min_success = 0.997 # with only 1200 samples, the success rate is lower + max_rel_err = 2.7e-16 + + +# Deterministic pseudorandom generator. Designed to be uniform +# on mantissa values and exponents, not on the represented number +def pseudo_randfloat(): + rnd_buff = bytearray(float_size) + for _ in range(float_size): + rnd_buff[_] = random.getrandbits(8) + return array.array(float_type, rnd_buff)[0] + + +random.seed(42) +stats = 0 +N = 1200 +max_err = 0 +for _ in range(N): + f = pseudo_randfloat() + while type(f) is not float or math.isinf(f) or math.isnan(f) or math.frexp(f)[1] <= min_expo: + f = pseudo_randfloat() + + str_f = repr(f) + f2 = float(str_f) + if f2 == f: + stats += 1 + else: + error = abs((f2 - f) / f) + if max_err < error: + max_err = error + +print(N, "values converted") +if stats / N >= min_success and max_err <= max_rel_err: + print("float format accuracy OK") +else: + print("FAILED: repr rate=%.3f%% max_err=%.3e" % (100 * stats / N, max_err)) diff --git a/tests/float/float_format_ints.py b/tests/float/float_format_ints.py index df4444166c5..7b7b30c4b34 100644 --- a/tests/float/float_format_ints.py +++ b/tests/float/float_format_ints.py @@ -12,14 +12,42 @@ print(title, "with format", f_fmt, "gives", f_fmt.format(f)) print(title, "with format", g_fmt, "gives", g_fmt.format(f)) +# The tests below check border cases involving all mantissa bits. +# In case of REPR_C, where the mantissa is missing two bits, the +# the string representation for such numbers might not always be exactly +# the same but nevertheless be correct, so we must allow a few exceptions. +is_REPR_C = float("1.0000001") == float("1.0") + # 16777215 is 2^24 - 1, the largest integer that can be completely held # in a float32. -print("{:f}".format(16777215)) +val_str = "{:f}".format(16777215) + +# When using REPR_C, 16777215.0 is the same as 16777212.0 or 16777214.4 +# (depending on the implementation of pow() function, the result may differ) +if is_REPR_C and (val_str == "16777212.000000" or val_str == "16777214.400000"): + val_str = "16777215.000000" + +print(val_str) + # 4294967040 = 16777215 * 128 is the largest integer that is exactly # represented by a float32 and that will also fit within a (signed) int32. # The upper bound of our integer-handling code is actually double this, # but that constant might cause trouble on systems using 32 bit ints. -print("{:f}".format(2147483520)) +val_str = "{:f}".format(2147483520) + +# When using FLOAT_IMPL_FLOAT, 2147483520.0 == 2147483500.0 +# Both representations are valid, the second being "simpler" +is_float32 = float("1e300") == float("inf") +if is_float32 and val_str == "2147483500.000000": + val_str = "2147483520.000000" + +# When using REPR_C, 2147483520.0 is the same as 2147483200.0 +# Both representations are valid, the second being "simpler" +if is_REPR_C and val_str == "2147483200.000000": + val_str = "2147483520.000000" + +print(val_str) + # Very large positive integers can be a test for precision and resolution. # This is a weird way to represent 1e38 (largest power of 10 for float32). print("{:.6e}".format(float("9" * 30 + "e8"))) diff --git a/tests/float/float_parse_doubleprec.py b/tests/float/float_parse_doubleprec.py index 81fcadcee88..c1b0b4823b0 100644 --- a/tests/float/float_parse_doubleprec.py +++ b/tests/float/float_parse_doubleprec.py @@ -19,3 +19,9 @@ print(float("1.00000000000000000000e-307")) print(float("10.0000000000000000000e-308")) print(float("100.000000000000000000e-309")) + +# ensure repr() adds an extra digit when needed for accurate parsing +print(float(repr(float("2.0") ** 100)) == float("2.0") ** 100) + +# ensure repr does not add meaningless extra digits (1.234999999999) +print(repr(1.2345)) diff --git a/tests/float/float_struct_e.py b/tests/float/float_struct_e.py index 403fbc5db4c..ba4134f3393 100644 --- a/tests/float/float_struct_e.py +++ b/tests/float/float_struct_e.py @@ -32,7 +32,7 @@ for i in (j, -j): x = struct.pack("", "=", "^"): for fill in ("", " ", "0", "@"): for sign in ("", "+", "-", " "): - # An empty precision defaults to 6, but when uPy is + # An empty precision defaults to 6, but when MicroPython is # configured to use a float, we can only use a # precision of 6 with numbers less than 10 and still # get results that compare to CPython (which uses @@ -164,7 +164,7 @@ def test_fmt(conv, fill, alignment, sign, prefix, width, precision, type, arg): for alignment in ("", "<", ">", "=", "^"): for fill in ("", " ", "0", "@"): for sign in ("", "+", "-", " "): - # An empty precision defaults to 6, but when uPy is + # An empty precision defaults to 6, but when MicroPython is # configured to use a float, we can only use a # precision of 6 with numbers less than 10 and still # get results that compare to CPython (which uses diff --git a/tests/float/string_format_fp30.py b/tests/float/string_format_fp30.py deleted file mode 100644 index 5f0b213daa3..00000000000 --- a/tests/float/string_format_fp30.py +++ /dev/null @@ -1,42 +0,0 @@ -def test(fmt, *args): - print("{:8s}".format(fmt) + ">" + fmt.format(*args) + "<") - - -test("{:10.4}", 123.456) -test("{:10.4e}", 123.456) -test("{:10.4e}", -123.456) -# test("{:10.4f}", 123.456) -# test("{:10.4f}", -123.456) -test("{:10.4g}", 123.456) -test("{:10.4g}", -123.456) -test("{:10.4n}", 123.456) -test("{:e}", 100) -test("{:f}", 200) -test("{:g}", 300) - -test("{:10.4E}", 123.456) -test("{:10.4E}", -123.456) -# test("{:10.4F}", 123.456) -# test("{:10.4F}", -123.456) -test("{:10.4G}", 123.456) -test("{:10.4G}", -123.456) - -test("{:06e}", float("inf")) -test("{:06e}", float("-inf")) -test("{:06e}", float("nan")) - -# The following fails right now -# test("{:10.1}", 0.0) - -print("%.0f" % (1.750000 % 0.08333333333)) -# Below isn't compatible with single-precision float -# print("%.1f" % (1.750000 % 0.08333333333)) -# print("%.2f" % (1.750000 % 0.08333333333)) -# print("%.12f" % (1.750000 % 0.08333333333)) - -# tests for errors in format string - -try: - "{:10.1b}".format(0.0) -except ValueError: - print("ValueError") diff --git a/tests/float/string_format_modulo.py b/tests/float/string_format_modulo.py index 3c206b73935..55314643351 100644 --- a/tests/float/string_format_modulo.py +++ b/tests/float/string_format_modulo.py @@ -6,7 +6,7 @@ print("%u" % 1.0) # these 3 have different behaviour in Python 3.x versions -# uPy raises a TypeError, following Python 3.5 (earlier versions don't) +# MicroPython raises a TypeError, following Python 3.5 (earlier versions don't) # print("%x" % 18.0) # print("%o" % 18.0) # print("%X" % 18.0) diff --git a/tests/float/string_format_modulo3.py b/tests/float/string_format_modulo3.py index f9d9c43cdf4..f8aeeda20f2 100644 --- a/tests/float/string_format_modulo3.py +++ b/tests/float/string_format_modulo3.py @@ -1,3 +1,3 @@ -# uPy and CPython outputs differ for the following +# Test corner cases where MicroPython and CPython outputs used to differ in the past print("%.1g" % -9.9) # round up 'g' with '-' sign print("%.2g" % 99.9) # round up diff --git a/tests/float/string_format_modulo3.py.exp b/tests/float/string_format_modulo3.py.exp deleted file mode 100644 index 71432b34045..00000000000 --- a/tests/float/string_format_modulo3.py.exp +++ /dev/null @@ -1,2 +0,0 @@ --10 -100 diff --git a/tests/frozen/frozentest.mpy b/tests/frozen/frozentest.mpy index 7f1163956bafeacef9bda191aa3376fbf589c350..c16da5d20fb73f0e09e3136812783ff305a25b0f 100644 GIT binary patch delta 12 TcmX@Yc!H7X|Gx=Gn79}KBo_qk delta 7 OcmX@Xc!Y5x(-8m**aGGN diff --git a/tests/frozen/frozentest.py b/tests/frozen/frozentest.py index 78cdd60bf04..74bdfb3b267 100644 --- a/tests/frozen/frozentest.py +++ b/tests/frozen/frozentest.py @@ -1,4 +1,4 @@ -print("uPy") +print("interned") print("a long string that is not interned") print("a string that has unicode αβγ chars") print(b"bytes 1234\x01") diff --git a/tests/import/builtin_ext.py b/tests/import/builtin_ext.py index 9d2344d400d..79ee901ea67 100644 --- a/tests/import/builtin_ext.py +++ b/tests/import/builtin_ext.py @@ -1,3 +1,9 @@ +try: + import uos, utime +except ImportError: + print("SKIP") + raise SystemExit + # Verify that sys is a builtin. import sys diff --git a/tests/import/builtin_import.py b/tests/import/builtin_import.py index 734498d1be4..364b0bae912 100644 --- a/tests/import/builtin_import.py +++ b/tests/import/builtin_import.py @@ -20,3 +20,12 @@ __import__("xyz", None, None, None, -1) except ValueError: print("ValueError") + +# globals is not checked for level=0 +__import__("builtins", "globals") + +# globals must be a dict (or None) for level>0 +try: + __import__("builtins", "globals", None, None, 1) +except TypeError: + print("TypeError") diff --git a/tests/import/import_broken.py b/tests/import/import_broken.py index 3c7cf4a4985..440922157ef 100644 --- a/tests/import/import_broken.py +++ b/tests/import/import_broken.py @@ -1,3 +1,9 @@ +try: + Exception.__class__ +except AttributeError: + print("SKIP") + raise SystemExit + import sys, pkg # Modules we import are usually added to sys.modules. diff --git a/tests/import/import_file.py b/tests/import/import_file.py index 90ec4e41e77..4cf307641c6 100644 --- a/tests/import/import_file.py +++ b/tests/import/import_file.py @@ -1,3 +1,7 @@ +if "__file__" not in globals(): + print("SKIP") + raise SystemExit + import import1b print(import1b.__file__) diff --git a/tests/import/import_override.py b/tests/import/import_override.py index 029ebe54c1f..0144e78cb9f 100644 --- a/tests/import/import_override.py +++ b/tests/import/import_override.py @@ -2,6 +2,10 @@ def custom_import(name, globals, locals, fromlist, level): + # CPython always tries to import _io, so just let that through as-is. + if name == "_io": + return orig_import(name, globals, locals, fromlist, level) + print("import", name, fromlist, level) class M: diff --git a/tests/import/import_override.py.exp b/tests/import/import_override.py.exp deleted file mode 100644 index 365248da6d8..00000000000 --- a/tests/import/import_override.py.exp +++ /dev/null @@ -1,2 +0,0 @@ -import import1b None 0 -456 diff --git a/tests/import/import_override2.py b/tests/import/import_override2.py new file mode 100644 index 00000000000..25aac44fe98 --- /dev/null +++ b/tests/import/import_override2.py @@ -0,0 +1,18 @@ +# test overriding __import__ combined with importing from the filesystem + + +def custom_import(name, globals, locals, fromlist, level): + if level > 0: + print("import", name, fromlist, level) + return orig_import(name, globals, locals, fromlist, level) + + +orig_import = __import__ +try: + __import__("builtins").__import__ = custom_import +except AttributeError: + print("SKIP") + raise SystemExit + +# import calls __import__ behind the scenes +import pkg7.subpkg1.subpkg2.mod3 diff --git a/tests/import/import_pkg7.py.exp b/tests/import/import_pkg7.py.exp deleted file mode 100644 index 8f21a615f6a..00000000000 --- a/tests/import/import_pkg7.py.exp +++ /dev/null @@ -1,8 +0,0 @@ -pkg __name__: pkg7 -pkg __name__: pkg7.subpkg1 -pkg __name__: pkg7.subpkg1.subpkg2 -mod1 -mod2 -mod1.foo -mod2.bar -ImportError diff --git a/tests/import/import_pkg9.py b/tests/import/import_pkg9.py index 4de028494f1..c2e0b618b69 100644 --- a/tests/import/import_pkg9.py +++ b/tests/import/import_pkg9.py @@ -13,4 +13,4 @@ import pkg9.mod2 pkg9.mod1() -print(pkg9.mod2.__name__, type(pkg9.mod2).__name__) +print(pkg9.mod2.__name__, type(pkg9.mod2)) diff --git a/tests/import/import_star.py b/tests/import/import_star.py new file mode 100644 index 00000000000..2cb21b877d7 --- /dev/null +++ b/tests/import/import_star.py @@ -0,0 +1,59 @@ +# test `from package import *` conventions, including __all__ support +# +# This test requires MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_BASIC_FEATURES + +try: + next(iter([]), 42) +except TypeError: + # 2-argument version of next() not supported + # we are probably not at MICROPY_CONFIG_ROM_LEVEL_BASIC_FEATURES + print("SKIP") + raise SystemExit + +# 1. test default visibility +from pkgstar_default import * + +print("visibleFun" in globals()) +print("VisibleClass" in globals()) +print("_hiddenFun" in globals()) +print("_HiddenClass" in globals()) +print(visibleFun()) + +# 2. test explicit visibility as defined by __all__ (as an array) +from pkgstar_all_array import * + +print("publicFun" in globals()) +print("PublicClass" in globals()) +print("unlistedFun" in globals()) +print("UnlistedClass" in globals()) +print("_privateFun" in globals()) +print("_PrivateClass" in globals()) +print(publicFun()) +# test dynamic import as used in asyncio +print("dynamicFun" in globals()) +print(dynamicFun()) + +# 3. test explicit visibility as defined by __all__ (as an tuple) +from pkgstar_all_tuple import * + +print("publicFun2" in globals()) +print("PublicClass2" in globals()) +print("unlistedFun2" in globals()) +print("UnlistedClass2" in globals()) +print(publicFun2()) + +# 4. test reporting of missing entries in __all__ +try: + from pkgstar_all_miss import * + + print("missed detection of incorrect __all__ definition") +except AttributeError as er: + print("AttributeError triggered for bad __all__ definition") + +# 5. test reporting of invalid __all__ definition +try: + from pkgstar_all_inval import * + + print("missed detection of incorrect __all__ definition") +except TypeError as er: + print("TypeError triggered for bad __all__ definition") diff --git a/tests/import/import_star_error.py b/tests/import/import_star_error.py index 9e1757b6ef5..73d9c863d6f 100644 --- a/tests/import/import_star_error.py +++ b/tests/import/import_star_error.py @@ -1,5 +1,10 @@ # test errors with import * +if not hasattr(object, "__init__"): + # target doesn't have MICROPY_CPYTHON_COMPAT enabled, so doesn't check for "import *" + print("SKIP") + raise SystemExit + # 'import *' is not allowed in function scope try: exec("def foo(): from x import *") diff --git a/tests/import/module_getattr.py.exp b/tests/import/module_getattr.py.exp deleted file mode 100644 index bc59c12aa16..00000000000 --- a/tests/import/module_getattr.py.exp +++ /dev/null @@ -1 +0,0 @@ -False diff --git a/tests/import/pkg7/subpkg1/subpkg2/mod3.py b/tests/import/pkg7/subpkg1/subpkg2/mod3.py index b0f4279fcf5..f7f4c1e65f4 100644 --- a/tests/import/pkg7/subpkg1/subpkg2/mod3.py +++ b/tests/import/pkg7/subpkg1/subpkg2/mod3.py @@ -5,7 +5,9 @@ print(bar) # attempted relative import beyond top-level package +# On older versions of CPython (eg 3.8) this is a ValueError, but on +# newer CPython (eg 3.11) and MicroPython it's an ImportError. try: from .... import mod1 -except ImportError: +except (ImportError, ValueError): print("ImportError") diff --git a/tests/import/pkgstar_all_array/__init__.py b/tests/import/pkgstar_all_array/__init__.py new file mode 100644 index 00000000000..03b012123fe --- /dev/null +++ b/tests/import/pkgstar_all_array/__init__.py @@ -0,0 +1,49 @@ +__all__ = ["publicFun", "PublicClass", "dynamicFun"] + + +# Definitions below should always be imported by a star import +def publicFun(): + return 1 + + +class PublicClass: + def __init__(self): + self._val = 1 + + +# If __all__ support is enabled, definitions below +# should not be imported by a star import +def unlistedFun(): + return 0 + + +class UnlistedClass: + def __init__(self): + self._val = 0 + + +# Definitions below should be not be imported by a star import +# (they start with an underscore, and are not listed in __all__) +def _privateFun(): + return -1 + + +class _PrivateClass: + def __init__(self): + self._val = -1 + + +# Test lazy loaded function, as used by extmod/asyncio: +# Works with a star import only if __all__ support is enabled +_attrs = { + "dynamicFun": "funcs", +} + + +def __getattr__(attr): + mod = _attrs.get(attr, None) + if mod is None: + raise AttributeError(attr) + value = getattr(__import__(mod, globals(), locals(), True, 1), attr) + globals()[attr] = value + return value diff --git a/tests/import/pkgstar_all_array/funcs.py b/tests/import/pkgstar_all_array/funcs.py new file mode 100644 index 00000000000..7540d70f66b --- /dev/null +++ b/tests/import/pkgstar_all_array/funcs.py @@ -0,0 +1,2 @@ +def dynamicFun(): + return 777 diff --git a/tests/import/pkgstar_all_inval/__init__.py b/tests/import/pkgstar_all_inval/__init__.py new file mode 100644 index 00000000000..7022476c19b --- /dev/null +++ b/tests/import/pkgstar_all_inval/__init__.py @@ -0,0 +1 @@ +__all__ = 42 diff --git a/tests/import/pkgstar_all_miss/__init__.py b/tests/import/pkgstar_all_miss/__init__.py new file mode 100644 index 00000000000..f9bbb538072 --- /dev/null +++ b/tests/import/pkgstar_all_miss/__init__.py @@ -0,0 +1,8 @@ +__all__ = ("existingFun", "missingFun") + + +def existingFun(): + return None + + +# missingFun is not defined, should raise an error on import diff --git a/tests/import/pkgstar_all_tuple/__init__.py b/tests/import/pkgstar_all_tuple/__init__.py new file mode 100644 index 00000000000..433ddc8e976 --- /dev/null +++ b/tests/import/pkgstar_all_tuple/__init__.py @@ -0,0 +1,22 @@ +__all__ = ("publicFun2", "PublicClass2") + + +# Definitions below should always be imported by a star import +def publicFun2(): + return 2 + + +class PublicClass2: + def __init__(self): + self._val = 2 + + +# If __all__ support is enabled, definitions below +# should not be imported by a star import +def unlistedFun2(): + return 0 + + +class UnlistedClass2: + def __init__(self): + self._val = 0 diff --git a/tests/import/pkgstar_default/__init__.py b/tests/import/pkgstar_default/__init__.py new file mode 100644 index 00000000000..4947e4ce7f1 --- /dev/null +++ b/tests/import/pkgstar_default/__init__.py @@ -0,0 +1,20 @@ +# When __all__ is undefined, star import should only +# show objects that do not start with an underscore + + +def visibleFun(): + return 42 + + +class VisibleClass: + def __init__(self): + self._val = 42 + + +def _hiddenFun(): + return -1 + + +class _HiddenClass: + def __init__(self): + self._val = -1 diff --git a/tests/inlineasm/rv32/asmzba.py b/tests/inlineasm/rv32/asmzba.py new file mode 100644 index 00000000000..75f3573c864 --- /dev/null +++ b/tests/inlineasm/rv32/asmzba.py @@ -0,0 +1,18 @@ +@micropython.asm_rv32 +def test_sh1add(a0, a1): + sh1add(a0, a0, a1) + + +@micropython.asm_rv32 +def test_sh2add(a0, a1): + sh2add(a0, a0, a1) + + +@micropython.asm_rv32 +def test_sh3add(a0, a1): + sh3add(a0, a0, a1) + + +print(hex(test_sh1add(10, 20))) +print(hex(test_sh2add(10, 20))) +print(hex(test_sh3add(10, 20))) diff --git a/tests/inlineasm/rv32/asmzba.py.exp b/tests/inlineasm/rv32/asmzba.py.exp new file mode 100644 index 00000000000..5f56bd95642 --- /dev/null +++ b/tests/inlineasm/rv32/asmzba.py.exp @@ -0,0 +1,3 @@ +0x28 +0x3c +0x64 diff --git a/tests/inlineasm/thumb/asmerrors.py b/tests/inlineasm/thumb/asmerrors.py new file mode 100644 index 00000000000..a26f9322540 --- /dev/null +++ b/tests/inlineasm/thumb/asmerrors.py @@ -0,0 +1,4 @@ +try: + exec("@micropython.asm_thumb\ndef l():\n a = di(a2, a2, -1)") +except SyntaxError as e: + print(e) diff --git a/tests/inlineasm/thumb/asmerrors.py.exp b/tests/inlineasm/thumb/asmerrors.py.exp new file mode 100644 index 00000000000..7590f171e51 --- /dev/null +++ b/tests/inlineasm/thumb/asmerrors.py.exp @@ -0,0 +1 @@ +expecting an assembler instruction diff --git a/tests/inlineasm/xtensa/asmargs.py b/tests/inlineasm/xtensa/asmargs.py new file mode 100644 index 00000000000..2bfccfcc69b --- /dev/null +++ b/tests/inlineasm/xtensa/asmargs.py @@ -0,0 +1,44 @@ +# test passing arguments + + +@micropython.asm_xtensa +def arg0(): + movi(a2, 1) + + +print(arg0()) + + +@micropython.asm_xtensa +def arg1(a2): + addi(a2, a2, 1) + + +print(arg1(1)) + + +@micropython.asm_xtensa +def arg2(a2, a3): + add(a2, a2, a3) + + +print(arg2(1, 2)) + + +@micropython.asm_xtensa +def arg3(a2, a3, a4): + add(a2, a2, a3) + add(a2, a2, a4) + + +print(arg3(1, 2, 3)) + + +@micropython.asm_xtensa +def arg4(a2, a3, a4, a5): + add(a2, a2, a3) + add(a2, a2, a4) + add(a2, a2, a5) + + +print(arg4(1, 2, 3, 4)) diff --git a/tests/inlineasm/xtensa/asmargs.py.exp b/tests/inlineasm/xtensa/asmargs.py.exp new file mode 100644 index 00000000000..e33a6964f46 --- /dev/null +++ b/tests/inlineasm/xtensa/asmargs.py.exp @@ -0,0 +1,5 @@ +1 +2 +3 +6 +10 diff --git a/tests/inlineasm/xtensa/asmarith.py b/tests/inlineasm/xtensa/asmarith.py new file mode 100644 index 00000000000..1c0934eb7a6 --- /dev/null +++ b/tests/inlineasm/xtensa/asmarith.py @@ -0,0 +1,119 @@ +@micropython.asm_xtensa +def f1(a2): + abs_(a2, a2) + + +for value in (10, -10, 0): + print(f1(value)) + + +ADDMI_TEMPLATE = """ +@micropython.asm_xtensa +def f1(a2) -> int: + addmi(a2, a2, {}) +print(f1(0)) +""" + +for value in (-32768, -32767, 32512, 32513, 0): + try: + exec(ADDMI_TEMPLATE.format(value)) + except SyntaxError as error: + print(error) + + +@micropython.asm_xtensa +def a2(a2, a3) -> int: + addx2(a2, a2, a3) + + +@micropython.asm_xtensa +def a4(a2, a3) -> int: + addx4(a2, a2, a3) + + +@micropython.asm_xtensa +def a8(a2, a3) -> int: + addx8(a2, a2, a3) + + +@micropython.asm_xtensa +def s2(a2, a3) -> int: + subx2(a2, a2, a3) + + +@micropython.asm_xtensa +def s4(a2, a3) -> int: + subx4(a2, a2, a3) + + +@micropython.asm_xtensa +def s8(a2, a3) -> int: + subx8(a2, a2, a3) + + +for first, second in ((100, 100), (-100, 100), (-100, -100), (100, -100)): + print("a2", a2(first, second)) + print("a4", a4(first, second)) + print("a8", a8(first, second)) + print("s2", s2(first, second)) + print("s4", s4(first, second)) + print("s8", s8(first, second)) + + +@micropython.asm_xtensa +def f5(a2) -> int: + neg(a2, a2) + + +for value in (0, -100, 100): + print(f5(value)) + + +@micropython.asm_xtensa +def f6(): + movi(a2, 0x100) + movi(a3, 1) + add(a2, a2, a3) + addi(a2, a2, 1) + addi(a2, a2, -2) + sub(a2, a2, a3) + + +print(hex(f6())) + + +@micropython.asm_xtensa +def f7(): + movi(a2, 0x10FF) + movi(a3, 1) + and_(a4, a2, a3) + or_(a4, a4, a3) + movi(a3, 0x200) + xor(a2, a4, a3) + + +print(hex(f7())) + + +@micropython.asm_xtensa +def f8(a2, a3): + add_n(a2, a2, a3) + + +print(f8(100, 200)) + + +@micropython.asm_xtensa +def f9(a2): + addi_n(a2, a2, 1) + + +print(f9(100)) + + +@micropython.asm_xtensa +def f10(a2, a3) -> uint: + mull(a2, a2, a3) + + +print(hex(f10(0xC0000000, 2))) diff --git a/tests/inlineasm/xtensa/asmarith.py.exp b/tests/inlineasm/xtensa/asmarith.py.exp new file mode 100644 index 00000000000..7aba46a27d9 --- /dev/null +++ b/tests/inlineasm/xtensa/asmarith.py.exp @@ -0,0 +1,40 @@ +10 +10 +0 +-32768 +-32767 is not a multiple of 256 +32512 +'addmi' integer 32513 isn't within range -32768..32512 +0 +a2 300 +a4 500 +a8 900 +s2 100 +s4 300 +s8 700 +a2 -100 +a4 -300 +a8 -700 +s2 -300 +s4 -500 +s8 -900 +a2 -300 +a4 -500 +a8 -900 +s2 -100 +s4 -300 +s8 -700 +a2 100 +a4 300 +a8 700 +s2 300 +s4 500 +s8 900 +0 +100 +-100 +0xff +0x201 +300 +101 +0x80000000 diff --git a/tests/inlineasm/xtensa/asmbranch.py b/tests/inlineasm/xtensa/asmbranch.py new file mode 100644 index 00000000000..22bcd5a7c71 --- /dev/null +++ b/tests/inlineasm/xtensa/asmbranch.py @@ -0,0 +1,299 @@ +# test branch instructions + + +@micropython.asm_xtensa +def tball(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + ball(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tball(0xFFFFFFFF, 0xFFFFFFFF)) +print(tball(0xFFFEFFFF, 0xFFFFFFFF)) +print(tball(0x00000000, 0xFFFFFFFF)) +print(tball(0xFFFFFFFF, 0x01010101)) + + +@micropython.asm_xtensa +def tbany(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bany(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbany(0xFFFFFFFF, 0xFFFFFFFF)) +print(tbany(0xFFFEFFFF, 0xFFFFFFFF)) +print(tbany(0x00000000, 0xFFFFFFFF)) +print(tbany(0xFFFFFFFF, 0x01010101)) + + +@micropython.asm_xtensa +def tbbc(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bbc(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbbc(0xFFFFFFFF, 4)) +print(tbbc(0xFFFEFFFF, 16)) +print(tbbc(0x00000000, 1)) + + +BBCI_TEMPLATE = """ +@micropython.asm_xtensa +def tbbci(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bbci(a3, {}, end) + movi(a2, -1) + label(end) + +print(tbbci({})) +""" + + +for value, bit in ((0xFFFFFFFF, 4), (0xFFFEFFFF, 16), (0x00000000, 1)): + try: + exec(BBCI_TEMPLATE.format(bit, value)) + except SyntaxError as error: + print(error) + + +@micropython.asm_xtensa +def tbbs(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bbs(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbbs(0x00000000, 4)) +print(tbbs(0x00010000, 16)) +print(tbbs(0xFFFFFFFF, 1)) + + +BBSI_TEMPLATE = """ +@micropython.asm_xtensa +def tbbsi(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bbsi(a3, {}, end) + movi(a2, -1) + label(end) + +print(tbbsi({})) +""" + + +for value, bit in ((0x00000000, 4), (0x00010000, 16), (0xFFFFFFFF, 1)): + try: + exec(BBSI_TEMPLATE.format(bit, value)) + except SyntaxError as error: + print(error) + + +@micropython.asm_xtensa +def tbeq(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + beq(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbeq(0x00000000, 0x00000000)) +print(tbeq(0x00010000, 0x00000000)) +print(tbeq(0xFFFFFFFF, 0xFFFFFFFF)) + + +@micropython.asm_xtensa +def tbeqz(a2) -> int: + mov(a3, a2) + movi(a2, 0) + beqz(a3, end) + movi(a2, -1) + label(end) + + +print(tbeqz(0)) +print(tbeqz(0x12345678)) +print(tbeqz(-1)) + + +@micropython.asm_xtensa +def tbge(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bge(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbge(0x00000000, 0x00000000)) +print(tbge(0x00010000, 0x00000000)) +print(tbge(0xF0000000, 0xFFFFFFFF)) + + +@micropython.asm_xtensa +def tbgeu(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bgeu(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbgeu(0x00000000, 0x00000000)) +print(tbgeu(0x00010000, 0x00000000)) +print(tbgeu(0xF0000000, 0xFFFFFFFF)) +print(tbgeu(0xFFFFFFFF, 0xF0000000)) + + +@micropython.asm_xtensa +def tbgez(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bgez(a3, end) + movi(a2, -1) + label(end) + + +print(tbgez(0)) +print(tbgez(0x12345678)) +print(tbgez(-1)) + + +@micropython.asm_xtensa +def tblt(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + blt(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tblt(0x00000000, 0x00000000)) +print(tblt(0x00010000, 0x00000000)) +print(tblt(0xF0000000, 0xFFFFFFFF)) + + +@micropython.asm_xtensa +def tbltu(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bltu(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbltu(0x00000000, 0x00000000)) +print(tbltu(0x00010000, 0x00000000)) +print(tbltu(0xF0000000, 0xFFFFFFFF)) +print(tbltu(0xFFFFFFFF, 0xF0000000)) + + +@micropython.asm_xtensa +def tbltz(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bltz(a3, end) + movi(a2, -1) + label(end) + + +print(tbltz(0)) +print(tbltz(0x12345678)) +print(tbltz(-1)) + + +@micropython.asm_xtensa +def tbnall(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bnall(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbnall(0xFFFFFFFF, 0xFFFFFFFF)) +print(tbnall(0xFFFEFFFF, 0xFFFFFFFF)) +print(tbnall(0x00000000, 0xFFFFFFFF)) +print(tbnall(0xFFFFFFFF, 0x01010101)) + + +@micropython.asm_xtensa +def tbne(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bne(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbne(0x00000000, 0x00000000)) +print(tbne(0x00010000, 0x00000000)) +print(tbne(0xFFFFFFFF, 0xFFFFFFFF)) + + +@micropython.asm_xtensa +def tbnez(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bnez(a3, end) + movi(a2, -1) + label(end) + + +print(tbnez(0)) +print(tbnez(0x12345678)) +print(tbnez(-1)) + + +@micropython.asm_xtensa +def tbnone(a2, a3) -> int: + mov(a4, a2) + movi(a2, 0) + bnone(a4, a3, end) + movi(a2, -1) + label(end) + + +print(tbnone(0xFFFFFFFF, 0xFFFFFFFF)) +print(tbnone(0xFFFEFFFF, 0xFFFFFFFF)) +print(tbnone(0x00000000, 0xFFFFFFFF)) +print(tbnone(0x10101010, 0x01010101)) + + +@micropython.asm_xtensa +def tbeqz_n(a2) -> int: + mov(a3, a2) + movi(a2, 0) + beqz_n(a3, end) + movi(a2, -1) + label(end) + + +print(tbeqz_n(0)) +print(tbeqz_n(0x12345678)) +print(tbeqz_n(-1)) + + +@micropython.asm_xtensa +def tbnez_n(a2) -> int: + mov(a3, a2) + movi(a2, 0) + bnez(a3, end) + movi(a2, -1) + label(end) + + +print(tbnez_n(0)) +print(tbnez_n(0x12345678)) +print(tbnez_n(-1)) diff --git a/tests/inlineasm/xtensa/asmbranch.py.exp b/tests/inlineasm/xtensa/asmbranch.py.exp new file mode 100644 index 00000000000..319a4b435ef --- /dev/null +++ b/tests/inlineasm/xtensa/asmbranch.py.exp @@ -0,0 +1,66 @@ +0 +-1 +-1 +0 +0 +0 +-1 +0 +-1 +0 +0 +-1 +0 +0 +-1 +0 +0 +-1 +0 +0 +0 +-1 +0 +0 +-1 +-1 +0 +0 +-1 +0 +0 +-1 +0 +0 +0 +-1 +-1 +-1 +0 +-1 +-1 +0 +-1 +-1 +-1 +0 +-1 +0 +0 +-1 +-1 +0 +-1 +-1 +0 +0 +-1 +-1 +0 +0 +0 +-1 +-1 +-1 +0 +0 diff --git a/tests/inlineasm/xtensa/asmjump.py b/tests/inlineasm/xtensa/asmjump.py new file mode 100644 index 00000000000..f41c9482319 --- /dev/null +++ b/tests/inlineasm/xtensa/asmjump.py @@ -0,0 +1,26 @@ +@micropython.asm_xtensa +def jump() -> int: + movi(a2, 0) + j(NEXT) + addi(a2, a2, 1) + j(DONE) + label(NEXT) + addi(a2, a2, 2) + label(DONE) + + +print(jump()) + + +@micropython.asm_xtensa +def jumpx() -> int: + call0(ENTRY) + label(ENTRY) + movi(a2, 0) + addi(a3, a0, 12) + jx(a3) + movi(a2, 1) + movi(a2, 2) + + +print(jumpx()) diff --git a/tests/inlineasm/xtensa/asmjump.py.exp b/tests/inlineasm/xtensa/asmjump.py.exp new file mode 100644 index 00000000000..51993f072d5 --- /dev/null +++ b/tests/inlineasm/xtensa/asmjump.py.exp @@ -0,0 +1,2 @@ +2 +2 diff --git a/tests/inlineasm/xtensa/asmloadstore.py b/tests/inlineasm/xtensa/asmloadstore.py new file mode 100644 index 00000000000..b185e30520c --- /dev/null +++ b/tests/inlineasm/xtensa/asmloadstore.py @@ -0,0 +1,98 @@ +import array + +# On the 8266 the generated code gets put into the IRAM segment, which is only +# word-addressable. Therefore, to test byte and halfword load/store opcodes +# some memory must be reserved in the DRAM segment. + +BYTE_DATA = array.array("B", (0x11, 0x22, 0x33, 0x44)) +WORD_DATA = array.array("h", (100, 200, -100, -200)) +DWORD_DATA = array.array("i", (100_000, -200_000, 300_000, -400_000)) + + +@micropython.asm_xtensa +def tl32r() -> int: + nop() + j(CODE) + align(4) + label(DATA) + data(1, 1, 2, 3, 4, 5, 6, 7) + align(4) + label(CODE) + nop_n() + nop_n() + l32r(a2, DATA) + + +print(hex(tl32r())) + + +@micropython.asm_xtensa +def tl32i() -> uint: + call0(ENTRY) + label(ENTRY) + l32i(a2, a0, 0) + + +print(hex(tl32i())) + + +@micropython.asm_xtensa +def tl8ui(a2) -> uint: + mov(a3, a2) + l8ui(a2, a3, 1) + + +print(hex(tl8ui(BYTE_DATA))) + + +@micropython.asm_xtensa +def tl16ui(a2) -> uint: + mov(a3, a2) + l16ui(a2, a3, 2) + + +print(tl16ui(WORD_DATA)) + + +@micropython.asm_xtensa +def tl16si(a2) -> int: + mov(a3, a2) + l16si(a2, a3, 6) + + +print(tl16si(WORD_DATA)) + + +@micropython.asm_xtensa +def ts8i(a2, a3): + s8i(a3, a2, 1) + + +ts8i(BYTE_DATA, 0xFF) +print(BYTE_DATA) + + +@micropython.asm_xtensa +def ts16i(a2, a3): + s16i(a3, a2, 2) + + +ts16i(WORD_DATA, -123) +print(WORD_DATA) + + +@micropython.asm_xtensa +def ts32i(a2, a3) -> uint: + s32i(a3, a2, 4) + + +ts32i(DWORD_DATA, -123456) +print(DWORD_DATA) + + +@micropython.asm_xtensa +def tl32i_n(a2) -> uint: + l32i_n(a2, a2, 8) + + +print(tl32i_n(DWORD_DATA)) diff --git a/tests/inlineasm/xtensa/asmloadstore.py.exp b/tests/inlineasm/xtensa/asmloadstore.py.exp new file mode 100644 index 00000000000..e6672df6f81 --- /dev/null +++ b/tests/inlineasm/xtensa/asmloadstore.py.exp @@ -0,0 +1,9 @@ +0x4030201 +0xf8002022 +0x22 +200 +-200 +array('B', [17, 255, 51, 68]) +array('h', [100, -123, -100, -200]) +array('i', [100000, -123456, 300000, -400000]) +300000 diff --git a/tests/inlineasm/xtensa/asmmisc.py b/tests/inlineasm/xtensa/asmmisc.py new file mode 100644 index 00000000000..271ab836625 --- /dev/null +++ b/tests/inlineasm/xtensa/asmmisc.py @@ -0,0 +1,25 @@ +@micropython.asm_xtensa +def tnop(a2, a3, a4, a5): + nop() + + +out2 = tnop(0x100, 0x200, 0x300, 0x400) +print(out2 == 0x100) + + +@micropython.asm_xtensa +def tnop_n(a2, a3, a4, a5): + nop_n() + + +out2 = tnop_n(0x100, 0x200, 0x300, 0x400) +print(out2 == 0x100) + + +@micropython.asm_xtensa +def tmov_n(a2, a3): + mov_n(a4, a3) + add(a2, a4, a3) + + +print(tmov_n(0, 1)) diff --git a/tests/inlineasm/xtensa/asmmisc.py.exp b/tests/inlineasm/xtensa/asmmisc.py.exp new file mode 100644 index 00000000000..eefaa35daf0 --- /dev/null +++ b/tests/inlineasm/xtensa/asmmisc.py.exp @@ -0,0 +1,3 @@ +True +True +2 diff --git a/tests/inlineasm/xtensa/asmshift.py b/tests/inlineasm/xtensa/asmshift.py new file mode 100644 index 00000000000..271ca1ccd49 --- /dev/null +++ b/tests/inlineasm/xtensa/asmshift.py @@ -0,0 +1,137 @@ +@micropython.asm_xtensa +def lsl1(a2): + slli(a2, a2, 1) + + +print(hex(lsl1(0x123))) + + +@micropython.asm_xtensa +def lsl23(a2): + slli(a2, a2, 23) + + +print(hex(lsl23(1))) + + +@micropython.asm_xtensa +def lsr1(a2): + srli(a2, a2, 1) + + +print(hex(lsr1(0x123))) + + +@micropython.asm_xtensa +def lsr15(a2): + srli(a2, a2, 15) + + +print(hex(lsr15(0x80000000))) + + +@micropython.asm_xtensa +def asr1(a2): + srai(a2, a2, 1) + + +print(hex(asr1(0x123))) + + +@micropython.asm_xtensa +def asr31(a2): + srai(a2, a2, 31) + + +print(hex(asr31(0x80000000))) + + +@micropython.asm_xtensa +def lsl1r(a2): + movi(a3, 1) + ssl(a3) + sll(a2, a2) + + +print(hex(lsl1r(0x123))) + + +@micropython.asm_xtensa +def lsr1r(a2): + movi(a3, 1) + ssr(a3) + srl(a2, a2) + + +print(hex(lsr1r(0x123))) + + +@micropython.asm_xtensa +def asr1r(a2): + movi(a3, 1) + ssr(a3) + sra(a2, a2) + + +print(hex(asr1r(0x123))) + + +@micropython.asm_xtensa +def sll9(a2): + ssai(9) + sll(a2, a2) + + +print(hex(sll9(1))) + + +@micropython.asm_xtensa +def srlr(a2, a3): + ssa8l(a3) + srl(a2, a2) + + +print(hex(srlr(0x12340000, 2))) + + +@micropython.asm_xtensa +def sllr(a2, a3): + ssa8b(a3) + sll(a2, a2) + + +print(hex(sllr(0x1234, 2))) + + +@micropython.asm_xtensa +def srcr(a2, a3, a4): + ssr(a4) + src(a2, a2, a3) + + +print(hex(srcr(0x00000001, 0x80000000, 2))) + + +@micropython.asm_xtensa +def srai24(a2): + srai(a2, a2, 24) + + +print(hex(srai24(0x12345678))) + + +@micropython.asm_xtensa +def nsar(a2, a3): + nsa(a2, a3) + + +print(nsar(0x12345678, 0)) +print(nsar(0x12345678, -1)) + + +@micropython.asm_xtensa +def nsaur(a2, a3): + nsau(a2, a3) + + +print(nsaur(0x12345678, 0)) diff --git a/tests/inlineasm/xtensa/asmshift.py.exp b/tests/inlineasm/xtensa/asmshift.py.exp new file mode 100644 index 00000000000..3e2bb3b4aef --- /dev/null +++ b/tests/inlineasm/xtensa/asmshift.py.exp @@ -0,0 +1,17 @@ +0x246 +0x800000 +0x91 +0x10000 +0x91 +-0x1 +0x246 +0x91 +0x91 +0x800000 +0x1234 +0x12340000 +0x60000000 +0x12 +31 +31 +32 diff --git a/tests/internal_bench/class_create-0-empty.py b/tests/internal_bench/class_create-0-empty.py new file mode 100644 index 00000000000..1fd8ccd9257 --- /dev/null +++ b/tests/internal_bench/class_create-0-empty.py @@ -0,0 +1,11 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-1-slots.py b/tests/internal_bench/class_create-1-slots.py new file mode 100644 index 00000000000..9b3e4b9570d --- /dev/null +++ b/tests/internal_bench/class_create-1-slots.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + l = ["x"] + for i in range(num // 40): + + class X: + __slots__ = l + + +bench.run(test) diff --git a/tests/internal_bench/class_create-1.1-slots5.py b/tests/internal_bench/class_create-1.1-slots5.py new file mode 100644 index 00000000000..ccac77dec9d --- /dev/null +++ b/tests/internal_bench/class_create-1.1-slots5.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + l = ["a", "b", "c", "d", "x"] + for i in range(num // 40): + + class X: + __slots__ = l + + +bench.run(test) diff --git a/tests/internal_bench/class_create-2-classattr.py b/tests/internal_bench/class_create-2-classattr.py new file mode 100644 index 00000000000..049a7dab170 --- /dev/null +++ b/tests/internal_bench/class_create-2-classattr.py @@ -0,0 +1,11 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + x = 1 + + +bench.run(test) diff --git a/tests/internal_bench/class_create-2.1-classattr5.py b/tests/internal_bench/class_create-2.1-classattr5.py new file mode 100644 index 00000000000..5051e7dcca7 --- /dev/null +++ b/tests/internal_bench/class_create-2.1-classattr5.py @@ -0,0 +1,15 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + a = 0 + b = 0 + c = 0 + d = 0 + x = 1 + + +bench.run(test) diff --git a/tests/internal_bench/class_create-2.3-classattr5objs.py b/tests/internal_bench/class_create-2.3-classattr5objs.py new file mode 100644 index 00000000000..74540865dcd --- /dev/null +++ b/tests/internal_bench/class_create-2.3-classattr5objs.py @@ -0,0 +1,20 @@ +import bench + + +class Class: + pass + + +def test(num): + instance = Class() + for i in range(num // 40): + + class X: + a = instance + b = instance + c = instance + d = instance + x = instance + + +bench.run(test) diff --git a/tests/internal_bench/class_create-3-instancemethod.py b/tests/internal_bench/class_create-3-instancemethod.py new file mode 100644 index 00000000000..e8c201cb2c3 --- /dev/null +++ b/tests/internal_bench/class_create-3-instancemethod.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + def x(self): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-4-classmethod.py b/tests/internal_bench/class_create-4-classmethod.py new file mode 100644 index 00000000000..f34962bc671 --- /dev/null +++ b/tests/internal_bench/class_create-4-classmethod.py @@ -0,0 +1,13 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + @classmethod + def x(cls): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-4.1-classmethod_implicit.py b/tests/internal_bench/class_create-4.1-classmethod_implicit.py new file mode 100644 index 00000000000..f2d1fcfd188 --- /dev/null +++ b/tests/internal_bench/class_create-4.1-classmethod_implicit.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + def __new__(cls): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-5-staticmethod.py b/tests/internal_bench/class_create-5-staticmethod.py new file mode 100644 index 00000000000..06335566675 --- /dev/null +++ b/tests/internal_bench/class_create-5-staticmethod.py @@ -0,0 +1,13 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + @staticmethod + def x(): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-6-getattribute.py b/tests/internal_bench/class_create-6-getattribute.py new file mode 100644 index 00000000000..10a4fe7ce8d --- /dev/null +++ b/tests/internal_bench/class_create-6-getattribute.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + def __getattribute__(self, name): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-6.1-getattr.py b/tests/internal_bench/class_create-6.1-getattr.py new file mode 100644 index 00000000000..b4b9ba2f552 --- /dev/null +++ b/tests/internal_bench/class_create-6.1-getattr.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + def __getattr__(self, name): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-6.2-property.py b/tests/internal_bench/class_create-6.2-property.py new file mode 100644 index 00000000000..cf847b6dc9c --- /dev/null +++ b/tests/internal_bench/class_create-6.2-property.py @@ -0,0 +1,13 @@ +import bench + + +def test(num): + for i in range(num // 40): + + class X: + @property + def x(self): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-6.3-descriptor.py b/tests/internal_bench/class_create-6.3-descriptor.py new file mode 100644 index 00000000000..7b0a6357263 --- /dev/null +++ b/tests/internal_bench/class_create-6.3-descriptor.py @@ -0,0 +1,17 @@ +import bench + + +class D: + def __get__(self, instance, owner=None): + pass + + +def test(num): + descriptor = D() + for i in range(num // 40): + + class X: + x = descriptor + + +bench.run(test) diff --git a/tests/internal_bench/class_create-7-inherit.py b/tests/internal_bench/class_create-7-inherit.py new file mode 100644 index 00000000000..f48fb215e0a --- /dev/null +++ b/tests/internal_bench/class_create-7-inherit.py @@ -0,0 +1,14 @@ +import bench + + +def test(num): + class B: + pass + + for i in range(num // 40): + + class X(B): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-7.1-inherit_initsubclass.py b/tests/internal_bench/class_create-7.1-inherit_initsubclass.py new file mode 100644 index 00000000000..0660fa86258 --- /dev/null +++ b/tests/internal_bench/class_create-7.1-inherit_initsubclass.py @@ -0,0 +1,16 @@ +import bench + + +def test(num): + class B: + @classmethod + def __init_subclass__(cls): + pass + + for i in range(num // 40): + + class X(B): + pass + + +bench.run(test) diff --git a/tests/internal_bench/class_create-8-metaclass_setname.py b/tests/internal_bench/class_create-8-metaclass_setname.py new file mode 100644 index 00000000000..e4515b54279 --- /dev/null +++ b/tests/internal_bench/class_create-8-metaclass_setname.py @@ -0,0 +1,17 @@ +import bench + + +class D: + def __set_name__(self, owner, name): + pass + + +def test(num): + descriptor = D() + for i in range(num // 40): + + class X: + x = descriptor + + +bench.run(test) diff --git a/tests/internal_bench/class_create-8.1-metaclass_setname5.py b/tests/internal_bench/class_create-8.1-metaclass_setname5.py new file mode 100644 index 00000000000..5daa3f8471b --- /dev/null +++ b/tests/internal_bench/class_create-8.1-metaclass_setname5.py @@ -0,0 +1,21 @@ +import bench + + +class D: + def __set_name__(self, owner, name): + pass + + +def test(num): + descriptor = D() + for i in range(num // 40): + + class X: + a = descriptor + b = descriptor + c = descriptor + d = descriptor + x = descriptor + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-0-object.py b/tests/internal_bench/class_instance-0-object.py new file mode 100644 index 00000000000..401c8ea7e3c --- /dev/null +++ b/tests/internal_bench/class_instance-0-object.py @@ -0,0 +1,11 @@ +import bench + +X = object + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-0.1-object-gc.py b/tests/internal_bench/class_instance-0.1-object-gc.py new file mode 100644 index 00000000000..7c475963a8e --- /dev/null +++ b/tests/internal_bench/class_instance-0.1-object-gc.py @@ -0,0 +1,13 @@ +import bench +import gc + +X = object + + +def test(num): + for i in range(num // 5): + x = X() + gc.collect() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-1-empty.py b/tests/internal_bench/class_instance-1-empty.py new file mode 100644 index 00000000000..617d47a86e9 --- /dev/null +++ b/tests/internal_bench/class_instance-1-empty.py @@ -0,0 +1,13 @@ +import bench + + +class X: + pass + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-1.1-classattr.py b/tests/internal_bench/class_instance-1.1-classattr.py new file mode 100644 index 00000000000..4e667533d4a --- /dev/null +++ b/tests/internal_bench/class_instance-1.1-classattr.py @@ -0,0 +1,13 @@ +import bench + + +class X: + x = 0 + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-1.2-func.py b/tests/internal_bench/class_instance-1.2-func.py new file mode 100644 index 00000000000..21bf7a1ac48 --- /dev/null +++ b/tests/internal_bench/class_instance-1.2-func.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def f(self): + pass + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-1.3-empty-gc.py b/tests/internal_bench/class_instance-1.3-empty-gc.py new file mode 100644 index 00000000000..a5108ef8e81 --- /dev/null +++ b/tests/internal_bench/class_instance-1.3-empty-gc.py @@ -0,0 +1,15 @@ +import bench +import gc + + +class X: + pass + + +def test(num): + for i in range(num // 5): + x = X() + gc.collect() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-2-init.py b/tests/internal_bench/class_instance-2-init.py new file mode 100644 index 00000000000..86619d31548 --- /dev/null +++ b/tests/internal_bench/class_instance-2-init.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def __init__(self): + pass + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-2.1-init_super.py b/tests/internal_bench/class_instance-2.1-init_super.py new file mode 100644 index 00000000000..38bca5fef87 --- /dev/null +++ b/tests/internal_bench/class_instance-2.1-init_super.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def __init__(self): + return super().__init__() + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-2.2-new.py b/tests/internal_bench/class_instance-2.2-new.py new file mode 100644 index 00000000000..dc5e78ea5ef --- /dev/null +++ b/tests/internal_bench/class_instance-2.2-new.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def __new__(cls): + return super().__new__(cls) + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-3-del.py b/tests/internal_bench/class_instance-3-del.py new file mode 100644 index 00000000000..af700f72a94 --- /dev/null +++ b/tests/internal_bench/class_instance-3-del.py @@ -0,0 +1,14 @@ +import bench + + +class X: + def __del__(self): + pass + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-3.1-del-gc.py b/tests/internal_bench/class_instance-3.1-del-gc.py new file mode 100644 index 00000000000..311c71c3571 --- /dev/null +++ b/tests/internal_bench/class_instance-3.1-del-gc.py @@ -0,0 +1,16 @@ +import bench +import gc + + +class X: + def __del__(self): + pass + + +def test(num): + for i in range(num // 5): + x = X() + gc.collect() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-4-slots.py b/tests/internal_bench/class_instance-4-slots.py new file mode 100644 index 00000000000..51b067fedf0 --- /dev/null +++ b/tests/internal_bench/class_instance-4-slots.py @@ -0,0 +1,13 @@ +import bench + + +class X: + __slots__ = ["x"] + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/class_instance-4.1-slots5.py b/tests/internal_bench/class_instance-4.1-slots5.py new file mode 100644 index 00000000000..8f5c2ecb456 --- /dev/null +++ b/tests/internal_bench/class_instance-4.1-slots5.py @@ -0,0 +1,13 @@ +import bench + + +class X: + __slots__ = ["a", "b", "c", "d", "x"] + + +def test(num): + for i in range(num // 5): + x = X() + + +bench.run(test) diff --git a/tests/internal_bench/var-6.2-instance-speciallookup.py b/tests/internal_bench/var-6.2-instance-speciallookup.py new file mode 100644 index 00000000000..fee12b2f930 --- /dev/null +++ b/tests/internal_bench/var-6.2-instance-speciallookup.py @@ -0,0 +1,19 @@ +import bench + + +class Foo: + def __init__(self): + self.num = 20000000 + + def __delattr__(self, name): # just trigger the 'special lookups' flag on the class + pass + + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-6.3-instance-property.py b/tests/internal_bench/var-6.3-instance-property.py new file mode 100644 index 00000000000..b4426ef7928 --- /dev/null +++ b/tests/internal_bench/var-6.3-instance-property.py @@ -0,0 +1,17 @@ +import bench + + +class Foo: + @property + def num(self): + return 20000000 + + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-6.4-instance-descriptor.py b/tests/internal_bench/var-6.4-instance-descriptor.py new file mode 100644 index 00000000000..b4df69f878f --- /dev/null +++ b/tests/internal_bench/var-6.4-instance-descriptor.py @@ -0,0 +1,20 @@ +import bench + + +class Descriptor: + def __get__(self, instance, owner=None): + return 20000000 + + +class Foo: + num = Descriptor() + + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-6.5-instance-getattr.py b/tests/internal_bench/var-6.5-instance-getattr.py new file mode 100644 index 00000000000..3b2ef672110 --- /dev/null +++ b/tests/internal_bench/var-6.5-instance-getattr.py @@ -0,0 +1,16 @@ +import bench + + +class Foo: + def __getattr__(self, name): + return 20000000 + + +def test(num): + o = Foo() + i = 0 + while i < o.num: + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-6.6-instance-builtin_ordered.py b/tests/internal_bench/var-6.6-instance-builtin_ordered.py new file mode 100644 index 00000000000..02d75252301 --- /dev/null +++ b/tests/internal_bench/var-6.6-instance-builtin_ordered.py @@ -0,0 +1,12 @@ +import bench + + +def test(num): + i = 0 + o = set() # object with largest rom-frozen ordered locals_dict + n = "__contains__" # last element in that dict for longest lookup + while i < num: + i += hasattr(o, n) # True, converts to 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9-getattr.py b/tests/internal_bench/var-9-getattr.py new file mode 100644 index 00000000000..69d2bfed2e0 --- /dev/null +++ b/tests/internal_bench/var-9-getattr.py @@ -0,0 +1,16 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + o.num = num + i = 0 + while i < getattr(o, "num", num): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.1-getattr_default.py b/tests/internal_bench/var-9.1-getattr_default.py new file mode 100644 index 00000000000..e803d39b326 --- /dev/null +++ b/tests/internal_bench/var-9.1-getattr_default.py @@ -0,0 +1,15 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + i = 0 + while i < getattr(o, "num", num): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.2-getattr_default_special.py b/tests/internal_bench/var-9.2-getattr_default_special.py new file mode 100644 index 00000000000..c48ec0742cf --- /dev/null +++ b/tests/internal_bench/var-9.2-getattr_default_special.py @@ -0,0 +1,16 @@ +import bench + + +class Foo: + def __delattr__(self, name): # just trigger the 'special lookups' flag on the class + pass + + +def test(num): + o = Foo() + i = 0 + while i < getattr(o, "num", num): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.3-except_ok.py b/tests/internal_bench/var-9.3-except_ok.py new file mode 100644 index 00000000000..efc1a8f858c --- /dev/null +++ b/tests/internal_bench/var-9.3-except_ok.py @@ -0,0 +1,23 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + o.num = num + + def get(): + try: + return o.num + except AttributeError: + return num + + i = 0 + while i < get(): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.4-except_selfinduced.py b/tests/internal_bench/var-9.4-except_selfinduced.py new file mode 100644 index 00000000000..544609ca4b6 --- /dev/null +++ b/tests/internal_bench/var-9.4-except_selfinduced.py @@ -0,0 +1,22 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + + def get(): + try: + raise AttributeError + except AttributeError: + return num + + i = 0 + while i < get(): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.5-except_error.py b/tests/internal_bench/var-9.5-except_error.py new file mode 100644 index 00000000000..caf83fa46ab --- /dev/null +++ b/tests/internal_bench/var-9.5-except_error.py @@ -0,0 +1,22 @@ +import bench + + +class Foo: + pass + + +def test(num): + o = Foo() + + def get(): + try: + return o.num + except AttributeError: + return num + + i = 0 + while i < get(): + i += 1 + + +bench.run(test) diff --git a/tests/internal_bench/var-9.6-except_error_special.py b/tests/internal_bench/var-9.6-except_error_special.py new file mode 100644 index 00000000000..8bc395b4d7e --- /dev/null +++ b/tests/internal_bench/var-9.6-except_error_special.py @@ -0,0 +1,23 @@ +import bench + + +class Foo: + def __delattr__(self, name): # just trigger the 'special lookups' flag on the class + pass + + +def test(num): + o = Foo() + + def get(): + try: + return o.num + except AttributeError: + return num + + i = 0 + while i < get(): + i += 1 + + +bench.run(test) diff --git a/tests/io/builtin_print_file.py b/tests/io/builtin_print_file.py index 822356a6cc3..e00f58635a9 100644 --- a/tests/io/builtin_print_file.py +++ b/tests/io/builtin_print_file.py @@ -13,5 +13,5 @@ try: print(file=1) -except (AttributeError, OSError): # CPython and uPy differ in error message +except (AttributeError, OSError): # CPython and MicroPython differ in error message print("Error") diff --git a/tests/io/file_seek.py b/tests/io/file_seek.py index 3990df84090..b9f9593786f 100644 --- a/tests/io/file_seek.py +++ b/tests/io/file_seek.py @@ -30,5 +30,5 @@ try: f.seek(1) except (OSError, ValueError): - # CPy raises ValueError, uPy raises OSError + # CPy raises ValueError, MPy raises OSError print("OSError or ValueError") diff --git a/tests/micropython/builtin_execfile.py b/tests/micropython/builtin_execfile.py index 75a867bb940..4fd4d66d4ee 100644 --- a/tests/micropython/builtin_execfile.py +++ b/tests/micropython/builtin_execfile.py @@ -75,3 +75,24 @@ def open(self, file, mode): # Unmount the VFS object. vfs.umount(fs) + + +class EvilFilesystem: + def mount(self, readonly, mkfs): + print("mount", readonly, mkfs) + + def umount(self): + print("umount") + + def open(self, file, mode): + return None + + +fs = EvilFilesystem() +vfs.mount(fs, "/test_mnt") +try: + execfile("/test_mnt/test.py") + print("ExecFile succeeded") +except OSError: + print("OSError") +vfs.umount(fs) diff --git a/tests/micropython/builtin_execfile.py.exp b/tests/micropython/builtin_execfile.py.exp index 49703d57076..d93dee547b6 100644 --- a/tests/micropython/builtin_execfile.py.exp +++ b/tests/micropython/builtin_execfile.py.exp @@ -5,3 +5,6 @@ open /test.py rb 123 TypeError umount +mount False False +OSError +umount diff --git a/tests/micropython/const_error.py b/tests/micropython/const_error.py index d35be530a7c..950360e4dc7 100644 --- a/tests/micropython/const_error.py +++ b/tests/micropython/const_error.py @@ -18,8 +18,6 @@ def test_syntax(code): # these operations are not supported within const test_syntax("A = const(1 @ 2)") -test_syntax("A = const(1 / 2)") -test_syntax("A = const(1 ** -2)") test_syntax("A = const(1 << -2)") test_syntax("A = const(1 >> -2)") test_syntax("A = const(1 % 0)") diff --git a/tests/micropython/const_error.py.exp b/tests/micropython/const_error.py.exp index 3edc3efe9c3..bef69eb32ea 100644 --- a/tests/micropython/const_error.py.exp +++ b/tests/micropython/const_error.py.exp @@ -5,5 +5,3 @@ SyntaxError SyntaxError SyntaxError SyntaxError -SyntaxError -SyntaxError diff --git a/tests/micropython/const_float.py b/tests/micropython/const_float.py new file mode 100644 index 00000000000..c3a0df0276b --- /dev/null +++ b/tests/micropython/const_float.py @@ -0,0 +1,23 @@ +# test constant optimisation, with consts that are floats + +from micropython import const + +# check we can make consts from floats +F1 = const(2.5) +F2 = const(-0.3) +print(type(F1), F1) +print(type(F2), F2) + +# check arithmetic with floats +F3 = const(F1 + F2) +F4 = const(F1**2) +print(F3, F4) + +# check int operations with float results +F5 = const(1 / 2) +F6 = const(2**-2) +print(F5, F6) + +# note: we also test float expression folding when +# we're compiling test cases in tests/float, as +# many expressions are resolved at compile time. diff --git a/tests/micropython/const_float.py.exp b/tests/micropython/const_float.py.exp new file mode 100644 index 00000000000..17a86a6d936 --- /dev/null +++ b/tests/micropython/const_float.py.exp @@ -0,0 +1,4 @@ + 2.5 + -0.3 +2.2 6.25 +0.5 0.25 diff --git a/tests/micropython/const_math.py b/tests/micropython/const_math.py new file mode 100644 index 00000000000..7ee5edc6d32 --- /dev/null +++ b/tests/micropython/const_math.py @@ -0,0 +1,18 @@ +# Test expressions based on math module constants +try: + import math +except ImportError: + print("SKIP") + raise SystemExit + +from micropython import const + +# check that we can make consts from math constants +# (skip if the target has MICROPY_COMP_MODULE_CONST disabled) +try: + exec("two_pi = const(2.0 * math.pi)") +except SyntaxError: + print("SKIP") + raise SystemExit + +print(math.cos(two_pi)) diff --git a/tests/micropython/const_math.py.exp b/tests/micropython/const_math.py.exp new file mode 100644 index 00000000000..d3827e75a5c --- /dev/null +++ b/tests/micropython/const_math.py.exp @@ -0,0 +1 @@ +1.0 diff --git a/tests/micropython/decorator_error.py b/tests/micropython/decorator_error.py index 94772ac1e5f..b5eae65b292 100644 --- a/tests/micropython/decorator_error.py +++ b/tests/micropython/decorator_error.py @@ -1,4 +1,4 @@ -# test syntax errors for uPy-specific decorators +# test syntax errors for MicroPython-specific decorators def test_syntax(code): diff --git a/tests/micropython/emg_exc.py b/tests/micropython/emg_exc.py index a74757d028f..cf918b3dc8a 100644 --- a/tests/micropython/emg_exc.py +++ b/tests/micropython/emg_exc.py @@ -1,10 +1,9 @@ # test that emergency exceptions work -import micropython import sys try: - import io + import io, micropython except ImportError: print("SKIP") raise SystemExit diff --git a/tests/micropython/emg_exc.py.native.exp b/tests/micropython/emg_exc.py.native.exp new file mode 100644 index 00000000000..9677c526a9c --- /dev/null +++ b/tests/micropython/emg_exc.py.native.exp @@ -0,0 +1,2 @@ +ValueError: 1 + diff --git a/tests/micropython/extreme_exc.py b/tests/micropython/extreme_exc.py index ad819e408fd..17323b566d3 100644 --- a/tests/micropython/extreme_exc.py +++ b/tests/micropython/extreme_exc.py @@ -1,6 +1,10 @@ # test some extreme cases of allocating exceptions and tracebacks -import micropython +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit # Check for stackless build, which can't call functions without # allocating a frame on the heap. diff --git a/tests/micropython/heap_lock.py b/tests/micropython/heap_lock.py index f2892a6dc58..209a3143461 100644 --- a/tests/micropython/heap_lock.py +++ b/tests/micropython/heap_lock.py @@ -1,6 +1,10 @@ # check that heap_lock/heap_unlock work as expected -import micropython +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit l = [] l2 = list(range(100)) diff --git a/tests/micropython/heap_locked.py b/tests/micropython/heap_locked.py index d9e5b5d4090..d9d99493dd6 100644 --- a/tests/micropython/heap_locked.py +++ b/tests/micropython/heap_locked.py @@ -1,8 +1,10 @@ # test micropython.heap_locked() -import micropython +try: + import micropython -if not hasattr(micropython, "heap_locked"): + micropython.heap_locked +except (AttributeError, ImportError): print("SKIP") raise SystemExit diff --git a/tests/micropython/heapalloc.py b/tests/micropython/heapalloc.py index e19f8d0255d..010bf878a07 100644 --- a/tests/micropython/heapalloc.py +++ b/tests/micropython/heapalloc.py @@ -1,6 +1,10 @@ # check that we can do certain things without allocating heap memory -import micropython +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit # Check for stackless build, which can't call functions without # allocating a frame on heap. diff --git a/tests/micropython/heapalloc_exc_compressed.py b/tests/micropython/heapalloc_exc_compressed.py index aa071d641c2..96fe3ca4f7e 100644 --- a/tests/micropython/heapalloc_exc_compressed.py +++ b/tests/micropython/heapalloc_exc_compressed.py @@ -1,4 +1,10 @@ -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # Tests both code paths for built-in exception raising. # mp_obj_new_exception_msg_varg (exception requires decompression at raise-time to format) diff --git a/tests/micropython/heapalloc_exc_compressed_emg_exc.py b/tests/micropython/heapalloc_exc_compressed_emg_exc.py index 48ce9dd69e6..31d937b8f93 100644 --- a/tests/micropython/heapalloc_exc_compressed_emg_exc.py +++ b/tests/micropython/heapalloc_exc_compressed_emg_exc.py @@ -1,4 +1,10 @@ -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # Does the full test from heapalloc_exc_compressed.py but while the heap is # locked (this can only work when the emergency exception buf is enabled). diff --git a/tests/micropython/heapalloc_exc_raise.py b/tests/micropython/heapalloc_exc_raise.py index 99810e00750..917ccf42f1e 100644 --- a/tests/micropython/heapalloc_exc_raise.py +++ b/tests/micropython/heapalloc_exc_raise.py @@ -1,6 +1,12 @@ # Test that we can raise and catch (preallocated) exception # without memory allocation. -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit e = ValueError("error") diff --git a/tests/micropython/heapalloc_fail_bytearray.py b/tests/micropython/heapalloc_fail_bytearray.py index 1bf7ddd600b..9ee73d1c583 100644 --- a/tests/micropython/heapalloc_fail_bytearray.py +++ b/tests/micropython/heapalloc_fail_bytearray.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with bytearray -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit class GetSlice: diff --git a/tests/micropython/heapalloc_fail_dict.py b/tests/micropython/heapalloc_fail_dict.py index ce2d158bd09..04c79183578 100644 --- a/tests/micropython/heapalloc_fail_dict.py +++ b/tests/micropython/heapalloc_fail_dict.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with dict -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # create dict x = 1 diff --git a/tests/micropython/heapalloc_fail_list.py b/tests/micropython/heapalloc_fail_list.py index 9a2e9a555f3..7afb6dc1019 100644 --- a/tests/micropython/heapalloc_fail_list.py +++ b/tests/micropython/heapalloc_fail_list.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with list -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit class GetSlice: diff --git a/tests/micropython/heapalloc_fail_memoryview.py b/tests/micropython/heapalloc_fail_memoryview.py index da2d1abffa6..17e3e126247 100644 --- a/tests/micropython/heapalloc_fail_memoryview.py +++ b/tests/micropython/heapalloc_fail_memoryview.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with memoryview -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit class GetSlice: diff --git a/tests/micropython/heapalloc_fail_set.py b/tests/micropython/heapalloc_fail_set.py index 3c347660ad7..0c4d85eef62 100644 --- a/tests/micropython/heapalloc_fail_set.py +++ b/tests/micropython/heapalloc_fail_set.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with set -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # create set x = 1 diff --git a/tests/micropython/heapalloc_fail_tuple.py b/tests/micropython/heapalloc_fail_tuple.py index de79385e3e3..11718a8107b 100644 --- a/tests/micropython/heapalloc_fail_tuple.py +++ b/tests/micropython/heapalloc_fail_tuple.py @@ -1,6 +1,12 @@ # test handling of failed heap allocation with tuple -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # create tuple x = 1 diff --git a/tests/micropython/heapalloc_inst_call.py b/tests/micropython/heapalloc_inst_call.py index 14d8826bf06..f78aa3cf877 100644 --- a/tests/micropython/heapalloc_inst_call.py +++ b/tests/micropython/heapalloc_inst_call.py @@ -1,6 +1,13 @@ # Test that calling clazz.__call__() with up to at least 3 arguments # doesn't require heap allocation. -import micropython + +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit class Foo0: diff --git a/tests/micropython/heapalloc_int_from_bytes.py b/tests/micropython/heapalloc_int_from_bytes.py index 5fe50443ae3..3310ea95d14 100644 --- a/tests/micropython/heapalloc_int_from_bytes.py +++ b/tests/micropython/heapalloc_int_from_bytes.py @@ -1,6 +1,13 @@ # Test that int.from_bytes() for small number of bytes generates # small int. -import micropython + +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit micropython.heap_lock() print(int.from_bytes(b"1", "little")) diff --git a/tests/micropython/heapalloc_slice.py b/tests/micropython/heapalloc_slice.py new file mode 100644 index 00000000000..62d96595c71 --- /dev/null +++ b/tests/micropython/heapalloc_slice.py @@ -0,0 +1,18 @@ +# slice operations that don't require allocation +try: + from micropython import heap_lock, heap_unlock +except (ImportError, AttributeError): + heap_lock = heap_unlock = lambda: 0 + +b = bytearray(range(10)) + +m = memoryview(b) + +heap_lock() + +b[3:5] = b"aa" +m[5:7] = b"bb" + +heap_unlock() + +print(b) diff --git a/tests/micropython/heapalloc_str.py b/tests/micropython/heapalloc_str.py index 39aa56ccd78..6372df5d37b 100644 --- a/tests/micropython/heapalloc_str.py +++ b/tests/micropython/heapalloc_str.py @@ -1,5 +1,12 @@ # String operations which don't require allocation -import micropython + +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit micropython.heap_lock() diff --git a/tests/micropython/heapalloc_super.py b/tests/micropython/heapalloc_super.py index 51afae3d83d..6839eee330a 100644 --- a/tests/micropython/heapalloc_super.py +++ b/tests/micropython/heapalloc_super.py @@ -1,5 +1,12 @@ # test super() operations which don't require allocation -import micropython + +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # Check for stackless build, which can't call functions without # allocating a frame on heap. diff --git a/tests/micropython/heapalloc_traceback.py.native.exp b/tests/micropython/heapalloc_traceback.py.native.exp new file mode 100644 index 00000000000..d6ac26aa829 --- /dev/null +++ b/tests/micropython/heapalloc_traceback.py.native.exp @@ -0,0 +1,3 @@ +StopIteration +StopIteration: + diff --git a/tests/micropython/heapalloc_yield_from.py b/tests/micropython/heapalloc_yield_from.py index 95071718908..9d4f8c6940f 100644 --- a/tests/micropython/heapalloc_yield_from.py +++ b/tests/micropython/heapalloc_yield_from.py @@ -1,6 +1,12 @@ # Check that yield-from can work without heap allocation -import micropython +try: + import micropython + + micropython.heap_lock +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit # Yielding from a function generator diff --git a/tests/micropython/import_mpy_native.py b/tests/micropython/import_mpy_native.py index ad63e025db2..59181b203bb 100644 --- a/tests/micropython/import_mpy_native.py +++ b/tests/micropython/import_mpy_native.py @@ -54,12 +54,13 @@ def open(self, path, mode): # these are the test .mpy files # CIRCUITPY-CHANGE -valid_header = bytes([ord("C"), 6, mpy_arch, 31]) +small_int_bits = 31 +valid_header = bytes([77, 6, (mpy_arch & 0x3F), small_int_bits]) # fmt: off user_files = { # bad architecture (mpy_arch needed for sub-version) # CIRCUITPY-CHANGE - '/mod0.mpy': bytes([ord('C'), 6, 0xfc | mpy_arch, 31]), + '/mod0.mpy': bytes([ord('C'), 6, 0xfc | (mpy_arch & 3), small_int_bits]), # test loading of viper and asm '/mod1.mpy': valid_header + ( diff --git a/tests/micropython/import_mpy_native_gc.py b/tests/micropython/import_mpy_native_gc.py index 0d5b79f0a8d..5159cc9e9f9 100644 --- a/tests/micropython/import_mpy_native_gc.py +++ b/tests/micropython/import_mpy_native_gc.py @@ -57,9 +57,13 @@ def open(self, path, mode): # CIRCUITPY-CHANGE: 'C' instead of 'M' mpy marker. features0_file_contents = { # -march=x64 - 0x806: b'C\x06\n\x1f\x02\x004build/features0.native.mpy\x00\x12factorial\x00\x8a\x02\xe93\x00\x00\x00\xf3\x0f\x1e\xfaSH\x8b\x1d\x7f\x00\x00\x00\xbe\x02\x00\x00\x00\xffS\x18\xbf\x01\x00\x00\x00H\x85\xc0u\x0cH\x8bC \xbe\x02\x00\x00\x00[\xff\xe0H\x0f\xaf\xf8H\xff\xc8\xeb\xe6\xf3\x0f\x1e\xfaATUSH\x8b\x1dI\x00\x00\x00H\x8bG\x08L\x8bc(H\x8bx\x08A\xff\xd4H\x8d5#\x00\x00\x00H\x89\xc5H\x8b\x051\x00\x00\x00\x0f\xb7x\x02\xffShH\x89\xefA\xff\xd4H\x8b\x03[]A\\\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x11$\r&\xa5 \x01"\xff', + 0x806: b"C\x06\x0b\x1f\x03\x002build/test_x64.native.mpy\x00\x08add1\x00\x0cunused\x00\x91B\xe9I\x00\x00\x00H\x8b\x05\xf4\x00\x00\x00H\x8b\x00\xc3H\x8b\x05\xf9\x00\x00\x00\xbe\x02\x00\x00\x00\x8b8H\x8b\x05\xdb\x00\x00\x00H\x8b@ \xff\xe0H\x8b\x05\xce\x00\x00\x00S\xbe\x02\x00\x00\x00H\x8bX \xffP\x18\xbe\x02\x00\x00\x00H\x8dx\x01H\x89\xd8[\xff\xe0AVAUATUSH\x8b\x1d\xa3\x00\x00\x00H\x8bG\x08L\x8bk(H\x8bx\x08A\xff\xd5L\x8b5\x95\x00\x00\x00L\x8bchH\x8d5r\x00\x00\x00H\x89\xc5H\x8b\x05\x88\x00\x00\x00A\x0f\xb7~\x04\xc7\x00@\xe2\x01\x00A\xff\xd4H\x8d5C\x00\x00\x00\xbfV\x00\x00\x00A\xff\xd4A\x0f\xb7~\x02H\x8d5\x1f\x00\x00\x00A\xff\xd4H\x89\xefA\xff\xd5H\x8b\x03[]A\\A]A^\xc3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x04\x11@\rB\tD\xaf4\x016\xad8\x01:\xaf<\x01>\xff", # -march=armv6m - 0x1006: b"C\x06\x12\x1f\x02\x004build/features0.native.mpy\x00\x12factorial\x00\x88\x02\x18\xe0\x00\x00\x10\xb5\tK\tJ{D\x9cX\x02!\xe3h\x98G\x03\x00\x01 \x00+\x02\xd0XC\x01;\xfa\xe7\x02!#i\x98G\x10\xbd\xc0Fj\x00\x00\x00\x00\x00\x00\x00\xf8\xb5\nN\nK~D\xf4XChgiXh\xb8G\x05\x00\x07K\x08I\xf3XyDX\x88ck\x98G(\x00\xb8G h\xf8\xbd\xc0F:\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 \x11<\r>\xa58\x01:\xff", + 0x1006: b"C\x06\x13\x1f\x03\x008build/test_armv6m.native.mpy\x00\x08add1\x00\x0cunused\x00\x8eb0\xe0\x00\x00\x00\x00\x00\x00\x02K\x03J{D\x9bX\x18hpG\xd0\x00\x00\x00\x00\x00\x00\x00\x10\xb5\x05K\x05I\x06J{D\x9aX[X\x10h\x02!\x1bi\x98G\x10\xbd\xb8\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x10\xb5\x06K\x06J{D\x9bX\x02!\x1ci\xdbh\x98G\x02!\x010\xa0G\x10\xbd\xc0F\x96\x00\x00\x00\x00\x00\x00\x00\xf7\xb5\x12O\x12K\x7fD\xfdX\x12Lki|D\x00\x93ChXh\x00\x9b\x98G\x0fK\x01\x90\x0fJ\xfbXnk\x1a`\x0eK!\x00\xffX\xb8\x88\xb0G!\x00V \x081\xb0G!\x00x\x88\x101\xb0G\x01\x98\x00\x9b\x98G(h\xfe\xbd\xc0Fr\x00\x00\x00\x00\x00\x00\x00R\x00\x00\x00\x08\x00\x00\x00@\xe2\x01\x00\x04\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\x1d\x00\x00\x00\x00\x00\x00\x00A\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x04\x11p\rr\tt\xafd\x01f\xadh\x01j\xafl\x01n\xff", + # -march=xtensawin + 0x2806: b"C\x06+\x1f\x03\x00>build/test_xtensawin.native.mpy\x00\x08add1\x00\x0cunused\x00\x8a\x12\x06\x16\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x006A\x00\x81\xf9\xff(\x08\x1d\xf0\x00\x006A\x00\x91\xfb\xff\x81\xf5\xff\xa8\t\x88H\x0c+\xe0\x08\x00-\n\x1d\xf0\x00\x006A\x00\x81\xf0\xff\xad\x02xH\x888\x0c+\xe0\x08\x00\x0c+\x1b\xaa\xe0\x07\x00-\n\x1d\xf06A\x00a\xe9\xff\x88\x122&\x05\xa2(\x01\xe0\x03\x00q\xe6\xff\x81\xea\xff\x92\xa7\x89\xa0\x99\x11H\xd6]\n\xb1\xe3\xff\xa2\x17\x02\x99\x08\xe0\x04\x00\xb1\xe2\xff\\j\xe0\x04\x00\xb1\xe1\xff\xa2\x17\x01\xe0\x04\x00\xad\x05\xe0\x03\x00(\x06\x1d\xf0p\x18\x04\x00\x00\x00\x00@\x00\x00\x00\x00\x00\x00\x00(\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x00\x00\x11\x02\r\x04\x07\x06\x03\t\x0c\xaf\x01\x01\x03\xad\x05\x01\x07\xaf\t\x01\x0b\xff", + # -march=rv32imc + 0x2C06: b'C\x06/\x1f\x03\x00:build/test_rv32imc.native.mpy\x00\x08add1\x00\x0cunused\x00\x8fb\x97\x0f\x00\x00g\x80\x0f\x05\x97\x07\x00\x00\x83\xa7\x07\x0e\x88C\x82\x80\x97\x07\x00\x00\x83\xa7G\r\x17\x07\x00\x00\x03\'\xc7\r\x9cK\x08C\x89E\x82\x87A\x11\x97\x07\x00\x00\x83\xa7\xa7\x0b"\xc4\x80K\xdcG\x06\xc6\x89E\x82\x97\xa2\x87"D\xb2@\x89E\x05\x05A\x01\x82\x87\\A\x01\x11"\xcc\x17\x04\x00\x00\x03$$\tN\xc6\xc8C\x83)D\x01\x06\xce&\xcaJ\xc8R\xc4\x82\x99\x17\n\x00\x00\x03*\xca\x07\x03)D\x03\xaa\x84\xf9g\x03UJ\x00\x93\x87\x07$\x17\x07\x00\x00\x03\'\x07\x07\x1c\xc3\x97\x05\x00\x00\x93\x85\xe5\x03\x02\x99\x97\x05\x00\x00\x93\x85\xc5\x03\x13\x05`\x05\x02\x99\x03U*\x00\x97\x05\x00\x00\x93\x85%\x03\x02\x99&\x85\x82\x99\x08@\xf2@bD\xd2DBI\xb2I"J\x05a\x82\x80\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00,\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00P\x04\x11t\rv\xafx\xadz\t|\xafh\x01j\xadl\x01n\xafp\x01r\xff', } # Populate armv7m-derived archs based on armv6m. @@ -67,7 +71,7 @@ def open(self, path, mode): features0_file_contents[arch] = features0_file_contents[0x1006] # Check that a .mpy exists for the target (ignore sub-version in lookup). -sys_implementation_mpy = sys.implementation._mpy & ~(3 << 8) +sys_implementation_mpy = (sys.implementation._mpy & ~(3 << 8)) & 0xFFFF if sys_implementation_mpy not in features0_file_contents: print("SKIP") raise SystemExit diff --git a/tests/micropython/kbd_intr.py b/tests/micropython/kbd_intr.py index 81977aaa52f..e1ed7185ef0 100644 --- a/tests/micropython/kbd_intr.py +++ b/tests/micropython/kbd_intr.py @@ -1,10 +1,10 @@ # test the micropython.kbd_intr() function -import micropython - try: + import micropython + micropython.kbd_intr -except AttributeError: +except (ImportError, AttributeError): print("SKIP") raise SystemExit diff --git a/tests/micropython/meminfo.py b/tests/micropython/meminfo.py index 9df341fbb83..f4dd8fdb604 100644 --- a/tests/micropython/meminfo.py +++ b/tests/micropython/meminfo.py @@ -1,12 +1,14 @@ # tests meminfo functions in micropython module -import micropython +try: + import micropython -# these functions are not always available -if not hasattr(micropython, "mem_info"): + micropython.mem_info +except (ImportError, AttributeError): print("SKIP") -else: - micropython.mem_info() - micropython.mem_info(1) - micropython.qstr_info() - micropython.qstr_info(1) + raise SystemExit + +micropython.mem_info() +micropython.mem_info(1) +micropython.qstr_info() +micropython.qstr_info(1) diff --git a/tests/micropython/memstats.py b/tests/micropython/memstats.py index dee3a4ce2f2..0e2e7b1c0b3 100644 --- a/tests/micropython/memstats.py +++ b/tests/micropython/memstats.py @@ -1,17 +1,19 @@ # tests meminfo functions in micropython module -import micropython +try: + import micropython -# these functions are not always available -if not hasattr(micropython, "mem_total"): + micropython.mem_total +except (ImportError, AttributeError): print("SKIP") -else: - t = micropython.mem_total() - c = micropython.mem_current() - p = micropython.mem_peak() + raise SystemExit - l = list(range(10000)) +t = micropython.mem_total() +c = micropython.mem_current() +p = micropython.mem_peak() - print(micropython.mem_total() > t) - print(micropython.mem_current() > c) - print(micropython.mem_peak() > p) +l = list(range(10000)) + +print(micropython.mem_total() > t) +print(micropython.mem_current() > c) +print(micropython.mem_peak() > p) diff --git a/tests/micropython/opt_level.py b/tests/micropython/opt_level.py index dd5493a7a3c..789197d8825 100644 --- a/tests/micropython/opt_level.py +++ b/tests/micropython/opt_level.py @@ -1,4 +1,10 @@ -import micropython as micropython +# test micropython.opt_level() + +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit # check we can get and set the level micropython.opt_level(0) diff --git a/tests/micropython/opt_level_lineno.py b/tests/micropython/opt_level_lineno.py index 40650b68192..ebb404c59fc 100644 --- a/tests/micropython/opt_level_lineno.py +++ b/tests/micropython/opt_level_lineno.py @@ -1,7 +1,14 @@ -import micropython as micropython +# test micropython.opt_level() and line numbers + +try: + import micropython +except ImportError: + print("SKIP") + raise SystemExit # check that level 3 doesn't store line numbers # the expected output is that any line is printed as "line 1" micropython.opt_level(3) + # CIRCUITPY-CHANGE: use traceback.print_exception() instead of sys.print_exception() exec("try:\n xyz\nexcept NameError as er:\n import traceback\n traceback.print_exception(er)") diff --git a/tests/micropython/opt_level_lineno.py.exp b/tests/micropython/opt_level_lineno.py.exp index 469b90ba793..b50f0628c81 100644 --- a/tests/micropython/opt_level_lineno.py.exp +++ b/tests/micropython/opt_level_lineno.py.exp @@ -1,3 +1,3 @@ Traceback (most recent call last): - File "", line 1, in + File "", line 1, in f NameError: name 'xyz' isn't defined diff --git a/tests/micropython/ringio_big.py b/tests/micropython/ringio_big.py new file mode 100644 index 00000000000..ddbbae12a63 --- /dev/null +++ b/tests/micropython/ringio_big.py @@ -0,0 +1,29 @@ +# Check that micropython.RingIO works correctly. + +try: + import micropython + + micropython.RingIO +except (ImportError, AttributeError): + print("SKIP") + raise SystemExit + +try: + # The maximum possible size + micropython.RingIO(bytearray(65535)) + micropython.RingIO(65534) + + try: + # Buffer may not be too big + micropython.RingIO(bytearray(65536)) + except ValueError as ex: + print(type(ex)) + + try: + # Size may not be too big + micropython.RingIO(65535) + except ValueError as ex: + print(type(ex)) +except MemoryError: + print("SKIP") + raise SystemExit diff --git a/tests/micropython/ringio_big.py.exp b/tests/micropython/ringio_big.py.exp new file mode 100644 index 00000000000..72af34b3838 --- /dev/null +++ b/tests/micropython/ringio_big.py.exp @@ -0,0 +1,2 @@ + + diff --git a/tests/micropython/schedule.py b/tests/micropython/schedule.py index 6a91459ea3d..f3dd3266126 100644 --- a/tests/micropython/schedule.py +++ b/tests/micropython/schedule.py @@ -1,10 +1,10 @@ # test micropython.schedule() function -import micropython - try: + import micropython + micropython.schedule -except AttributeError: +except (ImportError, AttributeError): print("SKIP") raise SystemExit diff --git a/tests/micropython/stack_use.py b/tests/micropython/stack_use.py index 266885d9d18..5d36fdca2fe 100644 --- a/tests/micropython/stack_use.py +++ b/tests/micropython/stack_use.py @@ -1,7 +1,11 @@ # tests stack_use function in micropython module -import micropython -if not hasattr(micropython, "stack_use"): +try: + import micropython + + micropython.stack_use +except (ImportError, AttributeError): print("SKIP") -else: - print(type(micropython.stack_use())) # output varies + raise SystemExit + +print(type(micropython.stack_use())) # output varies diff --git a/tests/micropython/test_normalize_newlines.py b/tests/micropython/test_normalize_newlines.py new file mode 100644 index 00000000000..f19aaa69a3f --- /dev/null +++ b/tests/micropython/test_normalize_newlines.py @@ -0,0 +1,14 @@ +# Test for normalize_newlines functionality +# This test verifies that test framework handles various newline combinations correctly + +# Note: This is more of an integration test since normalize_newlines is in the test framework +# The actual testing happens when this test is run through run-tests.py + +print("Testing newline handling") +print("Line 1\r\nLine 2") # Windows-style line ending - should be normalized +print("Line 3") # Normal line +print("Line 4") # Normal line +print("Line 5\nLine 6") # Unix-style line ending - already normalized + +# Test that literal \r in strings is preserved +print(repr("test\rstring")) # Should show 'test\rstring' not 'test\nstring' diff --git a/tests/micropython/test_normalize_newlines.py.exp b/tests/micropython/test_normalize_newlines.py.exp new file mode 100644 index 00000000000..c4395468cf1 --- /dev/null +++ b/tests/micropython/test_normalize_newlines.py.exp @@ -0,0 +1,8 @@ +Testing newline handling +Line 1 +Line 2 +Line 3 +Line 4 +Line 5 +Line 6 +'test\rstring' diff --git a/tests/micropython/viper_large_jump.py b/tests/micropython/viper_large_jump.py new file mode 100644 index 00000000000..1c5913dec1e --- /dev/null +++ b/tests/micropython/viper_large_jump.py @@ -0,0 +1,20 @@ +COUNT = 600 + + +try: + code = """ +@micropython.viper +def f() -> int: + x = 0 + while x < 10: +""" + for i in range(COUNT): + code += " x += 1\n" + code += " return x" + exec(code) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + + +print(f()) diff --git a/tests/micropython/viper_large_jump.py.exp b/tests/micropython/viper_large_jump.py.exp new file mode 100644 index 00000000000..e9f960cf4ac --- /dev/null +++ b/tests/micropython/viper_large_jump.py.exp @@ -0,0 +1 @@ +600 diff --git a/tests/micropython/viper_ptr16_load_boundary.py b/tests/micropython/viper_ptr16_load_boundary.py new file mode 100644 index 00000000000..0d4c3105b68 --- /dev/null +++ b/tests/micropython/viper_ptr16_load_boundary.py @@ -0,0 +1,39 @@ +# Test boundary conditions for various architectures + +GET_TEMPLATE = """ +@micropython.viper +def get{off}(src: ptr16) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) +""" + + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 2 + + +@micropython.viper +def get_index(src: ptr16, i: int) -> int: + return src[i] + + +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = ((1 << bit) - (2 * SIZE), (1 << bit) - (1 * SIZE), 1 << bit) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) + + pre, idx, post = pre // SIZE, idx // SIZE, post // SIZE + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(GET_TEMPLATE.format(off=pre)) + exec(GET_TEMPLATE.format(off=idx)) + exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr16_load_boundary.py.exp b/tests/micropython/viper_ptr16_load_boundary.py.exp new file mode 100644 index 00000000000..56f1d322904 --- /dev/null +++ b/tests/micropython/viper_ptr16_load_boundary.py.exp @@ -0,0 +1,20 @@ +--- 5 +0x100 0x302 0x504 +0x100 +0x302 +0x504 +--- 8 +0x706 0x908 0xb0a +0x706 +0x908 +0xb0a +--- 11 +0xd0c 0xf0e 0x1110 +0xd0c +0xf0e +0x1110 +--- 12 +0x1312 0x1514 0x1716 +0x1312 +0x1514 +0x1716 diff --git a/tests/micropython/viper_ptr16_store_boundary.py b/tests/micropython/viper_ptr16_store_boundary.py new file mode 100644 index 00000000000..7c774d4d1ca --- /dev/null +++ b/tests/micropython/viper_ptr16_store_boundary.py @@ -0,0 +1,63 @@ +# Test boundary conditions for various architectures + +SET_TEMPLATE = """ +@micropython.viper +def set{off}(dest: ptr16): + saved = dest + dest[{off}] = {val} + assert int(saved) == int(dest) +""" + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 2 +MASK = (1 << (8 * SIZE)) - 1 + +next_int = 1 +test_buffer = bytearray(SIZE) + + +def next_value() -> uint: + global next_int + global test_buffer + for index in range(1, SIZE): + test_buffer[index - 1] = test_buffer[index] + test_buffer[SIZE - 1] = next_int + next_int += 1 + output = 0 + for byte in test_buffer: + output = (output << 8) | byte + return output & MASK + + +def get_index(src, i): + return src[i * SIZE] + (src[(i * SIZE) + 1] << 8) + + +@micropython.viper +def set_index(dest: ptr16, i: int, val: uint): + saved = dest + dest[i] = val + assert int(saved) == int(dest) + + +try: + buffer = bytearray((((1 << max(BIT_THRESHOLDS)) // 1024) + 1) * 1024) + + for bit in BIT_THRESHOLDS: + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + exec(SET_TEMPLATE.format(off=(offset + index) // SIZE, val=next_value())) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + + +for bit in BIT_THRESHOLDS: + print("---", bit) + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + globals()["set{}".format((offset + index) // SIZE)](buffer) + print(hex(get_index(buffer, (offset + index) // SIZE))) + for index in range(0, 3 * SIZE, SIZE): + set_index(buffer, (offset + index) // SIZE, next_value()) + print(hex(get_index(buffer, (offset + index) // SIZE))) diff --git a/tests/micropython/viper_ptr16_store_boundary.py.exp b/tests/micropython/viper_ptr16_store_boundary.py.exp new file mode 100644 index 00000000000..007a50b3eda --- /dev/null +++ b/tests/micropython/viper_ptr16_store_boundary.py.exp @@ -0,0 +1,28 @@ +--- 5 +0x1 +0x102 +0x203 +0xc0d +0xd0e +0xe0f +--- 8 +0x304 +0x405 +0x506 +0xf10 +0x1011 +0x1112 +--- 11 +0x607 +0x708 +0x809 +0x1213 +0x1314 +0x1415 +--- 12 +0x90a +0xa0b +0xb0c +0x1516 +0x1617 +0x1718 diff --git a/tests/micropython/viper_ptr32_load_boundary.py b/tests/micropython/viper_ptr32_load_boundary.py new file mode 100644 index 00000000000..971d1113c49 --- /dev/null +++ b/tests/micropython/viper_ptr32_load_boundary.py @@ -0,0 +1,39 @@ +# Test boundary conditions for various architectures + +GET_TEMPLATE = """ +@micropython.viper +def get{off}(src: ptr32) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) +""" + + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 4 + + +@micropython.viper +def get_index(src: ptr32, i: int) -> int: + return src[i] + + +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = (((1 << bit) - (2 * SIZE)), ((1 << bit) - (1 * SIZE)), (1 << bit)) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) + + pre, idx, post = pre // SIZE, idx // SIZE, post // SIZE + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(GET_TEMPLATE.format(off=pre)) + exec(GET_TEMPLATE.format(off=idx)) + exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr32_load_boundary.py.exp b/tests/micropython/viper_ptr32_load_boundary.py.exp new file mode 100644 index 00000000000..1e22a8b3613 --- /dev/null +++ b/tests/micropython/viper_ptr32_load_boundary.py.exp @@ -0,0 +1,20 @@ +--- 5 +0x3020100 0x7060504 0xb0a0908 +0x3020100 +0x7060504 +0xb0a0908 +--- 8 +0xf0e0d0c 0x13121110 0x17161514 +0xf0e0d0c +0x13121110 +0x17161514 +--- 11 +0x1b1a1918 0x1f1e1d1c 0x23222120 +0x1b1a1918 +0x1f1e1d1c +0x23222120 +--- 12 +0x27262524 0x2b2a2928 0x2f2e2d2c +0x27262524 +0x2b2a2928 +0x2f2e2d2c diff --git a/tests/micropython/viper_ptr32_store_boundary.py b/tests/micropython/viper_ptr32_store_boundary.py new file mode 100644 index 00000000000..96ca74ad3ca --- /dev/null +++ b/tests/micropython/viper_ptr32_store_boundary.py @@ -0,0 +1,68 @@ +# Test boundary conditions for various architectures + +SET_TEMPLATE = """ +@micropython.viper +def set{off}(dest: ptr32): + saved = dest + dest[{off}] = {val} + assert int(saved) == int(dest) +""" + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 4 +MASK = (1 << (8 * SIZE)) - 1 + +next_int = 1 +test_buffer = bytearray(SIZE) + + +def next_value() -> uint: + global next_int + global test_buffer + for index in range(1, SIZE): + test_buffer[index - 1] = test_buffer[index] + test_buffer[SIZE - 1] = next_int + next_int += 1 + output = 0 + for byte in test_buffer: + output = (output << 8) | byte + return output & MASK + + +def get_index(src, i): + return ( + src[i * SIZE] + + (src[(i * SIZE) + 1] << 8) + + (src[(i * SIZE) + 2] << 16) + + (src[(i * SIZE) + 3] << 24) + ) + + +@micropython.viper +def set_index(dest: ptr32, i: int, val: uint): + saved = dest + dest[i] = val + assert int(dest) == int(saved) + + +try: + buffer = bytearray((((1 << max(BIT_THRESHOLDS)) // 1024) + 1) * 1024) + + for bit in BIT_THRESHOLDS: + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + exec(SET_TEMPLATE.format(off=(offset + index) // SIZE, val=next_value())) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + + +for bit in BIT_THRESHOLDS: + print("---", bit) + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + globals()["set{}".format((offset + index) // SIZE)](buffer) + print(hex(get_index(buffer, (offset + index) // SIZE))) + for index in range(0, 3 * SIZE, SIZE): + set_index(buffer, (offset + index) // SIZE, next_value()) + print(hex(get_index(buffer, (offset + index) // SIZE))) diff --git a/tests/micropython/viper_ptr32_store_boundary.py.exp b/tests/micropython/viper_ptr32_store_boundary.py.exp new file mode 100644 index 00000000000..7a9a5162474 --- /dev/null +++ b/tests/micropython/viper_ptr32_store_boundary.py.exp @@ -0,0 +1,28 @@ +--- 5 +0x1 +0x102 +0x10203 +0xa0b0c0d +0xb0c0d0e +0xc0d0e0f +--- 8 +0x1020304 +0x2030405 +0x3040506 +0xd0e0f10 +0xe0f1011 +0xf101112 +--- 11 +0x4050607 +0x5060708 +0x6070809 +0x10111213 +0x11121314 +0x12131415 +--- 12 +0x708090a +0x8090a0b +0x90a0b0c +0x13141516 +0x14151617 +0x15161718 diff --git a/tests/micropython/viper_ptr8_load_boundary.py b/tests/micropython/viper_ptr8_load_boundary.py new file mode 100644 index 00000000000..57e06da5709 --- /dev/null +++ b/tests/micropython/viper_ptr8_load_boundary.py @@ -0,0 +1,38 @@ +# Test boundary conditions for various architectures + +GET_TEMPLATE = """ +@micropython.viper +def get{off}(src: ptr8) -> uint: + return uint(src[{off}]) +print(hex(get{off}(buffer))) +""" + + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 1 + + +@micropython.viper +def get_index(src: ptr8, i: int) -> int: + return src[i] + + +def data(start, len): + output = bytearray(len) + for idx in range(len): + output[idx] = (start + idx) & 0xFF + return output + + +buffer = bytearray((((1 << max(BIT_THRESHOLDS)) + 1) // 1024) * 1024) +val = 0 +for bit in BIT_THRESHOLDS: + print("---", bit) + pre, idx, post = (((1 << bit) - (2 * SIZE)), ((1 << bit) - (1 * SIZE)), (1 << bit)) + buffer[pre:post] = data(val, 3 * SIZE) + val = val + (3 * SIZE) + + print(hex(get_index(buffer, pre)), hex(get_index(buffer, idx)), hex(get_index(buffer, post))) + exec(GET_TEMPLATE.format(off=pre)) + exec(GET_TEMPLATE.format(off=idx)) + exec(GET_TEMPLATE.format(off=post)) diff --git a/tests/micropython/viper_ptr8_load_boundary.py.exp b/tests/micropython/viper_ptr8_load_boundary.py.exp new file mode 100644 index 00000000000..a0e423686b8 --- /dev/null +++ b/tests/micropython/viper_ptr8_load_boundary.py.exp @@ -0,0 +1,20 @@ +--- 5 +0x0 0x1 0x2 +0x0 +0x1 +0x2 +--- 8 +0x3 0x4 0x5 +0x3 +0x4 +0x5 +--- 11 +0x6 0x7 0x8 +0x6 +0x7 +0x8 +--- 12 +0x9 0xa 0xb +0x9 +0xa +0xb diff --git a/tests/micropython/viper_ptr8_store_boundary.py b/tests/micropython/viper_ptr8_store_boundary.py new file mode 100644 index 00000000000..68b76fd598b --- /dev/null +++ b/tests/micropython/viper_ptr8_store_boundary.py @@ -0,0 +1,63 @@ +# Test boundary conditions for various architectures + +SET_TEMPLATE = """ +@micropython.viper +def set{off}(dest: ptr8): + saved = dest + dest[{off}] = {val} + assert int(saved) == int(dest) +""" + +BIT_THRESHOLDS = (5, 8, 11, 12) +SIZE = 1 +MASK = (1 << (8 * SIZE)) - 1 + +next_int = 1 +test_buffer = bytearray(SIZE) + + +def next_value() -> uint: + global next_int + global test_buffer + for index in range(1, SIZE): + test_buffer[index - 1] = test_buffer[index] + test_buffer[SIZE - 1] = next_int + next_int += 1 + output = 0 + for byte in test_buffer: + output = (output << 8) | byte + return output & MASK + + +def get_index(src: ptr8, i: int): + return src[i] + + +@micropython.viper +def set_index(dest: ptr8, i: int, val: uint): + saved = dest + dest[i] = val + assert int(dest) == int(saved) + + +try: + buffer = bytearray((((1 << max(BIT_THRESHOLDS)) // 1024) + 1) * 1024) + + for bit in BIT_THRESHOLDS: + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + exec(SET_TEMPLATE.format(off=(offset + index) // SIZE, val=next_value())) +except MemoryError: + print("SKIP-TOO-LARGE") + raise SystemExit + + +for bit in BIT_THRESHOLDS: + print("---", bit) + offset = (1 << bit) - (2 * SIZE) + for index in range(0, 3 * SIZE, SIZE): + globals()["set{}".format((offset + index) // SIZE)](buffer) + print(hex(get_index(buffer, (offset + index) // SIZE))) + for index in range(0, 3 * SIZE, SIZE): + set_index(buffer, (offset + index) // SIZE, next_value()) + print(hex(get_index(buffer, (offset + index) // SIZE))) diff --git a/tests/micropython/viper_ptr8_store_boundary.py.exp b/tests/micropython/viper_ptr8_store_boundary.py.exp new file mode 100644 index 00000000000..621295d81a8 --- /dev/null +++ b/tests/micropython/viper_ptr8_store_boundary.py.exp @@ -0,0 +1,28 @@ +--- 5 +0x1 +0x2 +0x3 +0xd +0xe +0xf +--- 8 +0x4 +0x5 +0x6 +0x10 +0x11 +0x12 +--- 11 +0x7 +0x8 +0x9 +0x13 +0x14 +0x15 +--- 12 +0xa +0xb +0xc +0x16 +0x17 +0x18 diff --git a/tests/misc/non_compliant.py b/tests/misc/non_compliant.py index 31c9fa17c3b..8608f2322f8 100644 --- a/tests/misc/non_compliant.py +++ b/tests/misc/non_compliant.py @@ -39,7 +39,7 @@ except NotImplementedError: print("NotImplementedError") -# uPy raises TypeError, should be ValueError +# MicroPython raises TypeError, should be ValueError try: "%c" % b"\x01\x02" except (TypeError, ValueError): @@ -100,10 +100,10 @@ print("NotImplementedError") # CIRCUITPY-CHANGE: We do check these. -# struct pack with too many args, not checked by uPy +# struct pack with too many args, not checked by MicroPython # print(struct.pack("bb", 1, 2, 3)) -# struct pack with too few args, not checked by uPy +# struct pack with too few args, not checked by MicroPython # print(struct.pack("bb", 1)) # array slice assignment with unsupported RHS diff --git a/tests/misc/non_compliant_lexer.py b/tests/misc/non_compliant_lexer.py index e1c21f3d713..04c605953e7 100644 --- a/tests/misc/non_compliant_lexer.py +++ b/tests/misc/non_compliant_lexer.py @@ -11,7 +11,7 @@ def test(code): print("NotImplementedError") -# uPy requires spaces between literal numbers and keywords, CPy doesn't +# MPy requires spaces between literal numbers and keywords, CPy doesn't try: eval("1and 0") except SyntaxError: diff --git a/tests/misc/print_exception.py.native.exp b/tests/misc/print_exception.py.native.exp new file mode 100644 index 00000000000..59e856ae3c4 --- /dev/null +++ b/tests/misc/print_exception.py.native.exp @@ -0,0 +1,18 @@ +caught +Exception: msg + +caught +Exception: fail + +finally +caught +Exception: fail + +reraise +Exception: fail + +caught +Exception: fail + +AttributeError: 'function' object has no attribute 'X' + diff --git a/tests/misc/rge_sm.py b/tests/misc/rge_sm.py index 5e071687c49..56dad574977 100644 --- a/tests/misc/rge_sm.py +++ b/tests/misc/rge_sm.py @@ -39,14 +39,6 @@ def solve(self, finishtime): if not self.iterate(): break - def solveNSteps(self, nSteps): - for i in range(nSteps): - if not self.iterate(): - break - - def series(self): - return zip(*self.Trajectory) - # 1-loop RGES for the main parameters of the SM # couplings are: g1, g2, g3 of U(1), SU(2), SU(3); yt (top Yukawa), lambda (Higgs quartic) @@ -79,46 +71,8 @@ def series(self): ) -def drange(start, stop, step): - r = start - while r < stop: - yield r - r += step - - -def phaseDiagram(system, trajStart, trajPlot, h=0.1, tend=1.0, range=1.0): - tstart = 0.0 - for i in drange(0, range, 0.1 * range): - for j in drange(0, range, 0.1 * range): - rk = RungeKutta(system, trajStart(i, j), tstart, h) - rk.solve(tend) - # draw the line - for tr in rk.Trajectory: - x, y = trajPlot(tr) - print(x, y) - print() - # draw the arrow - continue - l = (len(rk.Trajectory) - 1) / 3 - if l > 0 and 2 * l < len(rk.Trajectory): - p1 = rk.Trajectory[l] - p2 = rk.Trajectory[2 * l] - x1, y1 = trajPlot(p1) - x2, y2 = trajPlot(p2) - dx = -0.5 * (y2 - y1) # orthogonal to line - dy = 0.5 * (x2 - x1) # orthogonal to line - # l = math.sqrt(dx*dx + dy*dy) - # if abs(l) > 1e-3: - # l = 0.1 / l - # dx *= l - # dy *= l - print(x1 + dx, y1 + dy) - print(x2, y2) - print(x1 - dx, y1 - dy) - print() - - def singleTraj(system, trajStart, h=0.02, tend=1.0): + is_REPR_C = float("1.0000001") == float("1.0") tstart = 0.0 # compute the trajectory @@ -130,10 +84,15 @@ def singleTraj(system, trajStart, h=0.02, tend=1.0): for i in range(len(rk.Trajectory)): tr = rk.Trajectory[i] - print(" ".join(["{:.4f}".format(t) for t in tr])) - + tr_str = " ".join(["{:.4f}".format(t) for t in tr]) + if is_REPR_C: + # allow two small deviations for REPR_C + if tr_str == "1.0000 0.3559 0.6485 1.1944 0.9271 0.1083": + tr_str = "1.0000 0.3559 0.6485 1.1944 0.9272 0.1083" + if tr_str == "16.0000 0.3894 0.5793 0.7017 0.5686 -0.0168": + tr_str = "16.0000 0.3894 0.5793 0.7017 0.5686 -0.0167" + print(tr_str) -# phaseDiagram(sysSM, (lambda i, j: [0.354, 0.654, 1.278, 0.8 + 0.2 * i, 0.1 + 0.1 * j]), (lambda a: (a[4], a[5])), h=0.1, tend=math.log(10**17)) # initial conditions at M_Z singleTraj(sysSM, [0.354, 0.654, 1.278, 0.983, 0.131], h=0.5, tend=math.log(10**17)) # true values diff --git a/tests/misc/sys_exc_info.py b/tests/misc/sys_exc_info.py index d7e8a2d943b..c076dd572b0 100644 --- a/tests/misc/sys_exc_info.py +++ b/tests/misc/sys_exc_info.py @@ -8,13 +8,14 @@ def f(): - print(sys.exc_info()[0:2]) + e = sys.exc_info() + print(e[0], e[1]) try: raise ValueError("value", 123) except: - print(sys.exc_info()[0:2]) + print(sys.exc_info()[0], sys.exc_info()[1]) f() # Outside except block, sys.exc_info() should be back to None's diff --git a/tests/misc/sys_settrace_cov.py b/tests/misc/sys_settrace_cov.py new file mode 100644 index 00000000000..579c8a4a25e --- /dev/null +++ b/tests/misc/sys_settrace_cov.py @@ -0,0 +1,23 @@ +import sys + +try: + sys.settrace +except AttributeError: + print("SKIP") + raise SystemExit + + +def trace_tick_handler(frame, event, arg): + print("FRAME", frame) + print("LASTI", frame.f_lasti) + return None + + +def f(): + x = 3 + return x + + +sys.settrace(trace_tick_handler) +f() +sys.settrace(None) diff --git a/tests/misc/sys_settrace_cov.py.exp b/tests/misc/sys_settrace_cov.py.exp new file mode 100644 index 00000000000..423d78ec42b --- /dev/null +++ b/tests/misc/sys_settrace_cov.py.exp @@ -0,0 +1,2 @@ +FRAME +LASTI \\d\+ diff --git a/tests/multi_extmod/machine_i2c_target_irq.py b/tests/multi_extmod/machine_i2c_target_irq.py new file mode 100644 index 00000000000..eafd9dfdca8 --- /dev/null +++ b/tests/multi_extmod/machine_i2c_target_irq.py @@ -0,0 +1,137 @@ +# Test I2CTarget IRQs and clock stretching. +# +# Requires two instances with their SCL and SDA lines connected together. +# Any combination of the below supported boards can be used. +# +# Notes: +# - pull-up resistors may be needed +# - alif use 1.8V signalling + +import sys +import time +from machine import I2C, I2CTarget + +if not hasattr(I2CTarget, "IRQ_ADDR_MATCH_READ"): + print("SKIP") + raise SystemExit + +ADDR = 67 +clock_stretch_us = 200 + +# Configure pins based on the target. +if sys.platform == "alif": + i2c_args = (1,) # pins P3_7/P3_6 + i2c_kwargs = {} +elif sys.platform == "mimxrt": + i2c_args = (0,) # pins 19/18 on Teensy 4.x + i2c_kwargs = {} + clock_stretch_us = 50 # mimxrt cannot delay too long in the IRQ handler +elif sys.platform == "rp2": + i2c_args = (0,) + i2c_kwargs = {"scl": 9, "sda": 8} +elif sys.platform == "pyboard": + i2c_args = ("Y",) + i2c_kwargs = {} +elif sys.platform == "samd": + i2c_args = () # pins SCL/SDA + i2c_kwargs = {} +elif "zephyr-rpi_pico" in sys.implementation._machine: + i2c_args = ("i2c1",) # on gpio7/gpio6 + i2c_kwargs = {} +else: + print("Please add support for this test on this platform.") + raise SystemExit + + +def simple_irq(i2c_target): + flags = i2c_target.irq().flags() + if flags & I2CTarget.IRQ_ADDR_MATCH_READ: + print("IRQ_ADDR_MATCH_READ") + if flags & I2CTarget.IRQ_ADDR_MATCH_WRITE: + print("IRQ_ADDR_MATCH_WRITE") + + # Force clock stretching. + time.sleep_us(clock_stretch_us) + + +class I2CTargetMemory: + def __init__(self, i2c_target, mem): + self.buf1 = bytearray(1) + self.mem = mem + self.memaddr = 0 + self.state = 0 + i2c_target.irq( + self.irq, + I2CTarget.IRQ_ADDR_MATCH_WRITE | I2CTarget.IRQ_READ_REQ | I2CTarget.IRQ_WRITE_REQ, + hard=True, + ) + + def irq(self, i2c_target): + # Force clock stretching. + time.sleep_us(clock_stretch_us) + + flags = i2c_target.irq().flags() + if flags & I2CTarget.IRQ_ADDR_MATCH_WRITE: + self.state = 0 + if flags & I2CTarget.IRQ_READ_REQ: + self.buf1[0] = self.mem[self.memaddr] + self.memaddr += 1 + i2c_target.write(self.buf1) + if flags & I2CTarget.IRQ_WRITE_REQ: + i2c_target.readinto(self.buf1) + if self.state == 0: + self.state = 1 + self.memaddr = self.buf1[0] + else: + self.mem[self.memaddr] = self.buf1[0] + self.memaddr += 1 + self.memaddr %= len(self.mem) + + # Force clock stretching. + time.sleep_us(clock_stretch_us) + + +# I2C controller +def instance0(): + i2c = I2C(*i2c_args, **i2c_kwargs) + multitest.next() + for iteration in range(2): + print("controller iteration", iteration) + multitest.wait("target stage 1") + i2c.writeto_mem(ADDR, 2, "0123") + multitest.broadcast("controller stage 2") + multitest.wait("target stage 3") + print(i2c.readfrom_mem(ADDR, 2, 4)) + multitest.broadcast("controller stage 4") + print("done") + + +# I2C target +def instance1(): + multitest.next() + + for iteration in range(2): + print("target iteration", iteration) + buf = bytearray(b"--------") + if iteration == 0: + # Use built-in memory capability of I2CTarget. + i2c_target = I2CTarget(*i2c_args, **i2c_kwargs, addr=ADDR, mem=buf) + i2c_target.irq( + simple_irq, + I2CTarget.IRQ_ADDR_MATCH_READ | I2CTarget.IRQ_ADDR_MATCH_WRITE, + hard=True, + ) + else: + # Implement a memory device by hand. + i2c_target = I2CTarget(*i2c_args, **i2c_kwargs, addr=ADDR) + I2CTargetMemory(i2c_target, buf) + + multitest.broadcast("target stage 1") + multitest.wait("controller stage 2") + print(buf) + multitest.broadcast("target stage 3") + multitest.wait("controller stage 4") + + i2c_target.deinit() + + print("done") diff --git a/tests/multi_extmod/machine_i2c_target_irq.py.exp b/tests/multi_extmod/machine_i2c_target_irq.py.exp new file mode 100644 index 00000000000..a17c8f43858 --- /dev/null +++ b/tests/multi_extmod/machine_i2c_target_irq.py.exp @@ -0,0 +1,15 @@ +--- instance0 --- +controller iteration 0 +b'0123' +controller iteration 1 +b'0123' +done +--- instance1 --- +target iteration 0 +IRQ_ADDR_MATCH_WRITE +bytearray(b'--0123--') +IRQ_ADDR_MATCH_WRITE +IRQ_ADDR_MATCH_READ +target iteration 1 +bytearray(b'--0123--') +done diff --git a/tests/multi_extmod/machine_i2c_target_memory.py b/tests/multi_extmod/machine_i2c_target_memory.py new file mode 100644 index 00000000000..6b3f0d03eb7 --- /dev/null +++ b/tests/multi_extmod/machine_i2c_target_memory.py @@ -0,0 +1,79 @@ +# Test basic use of I2CTarget and a memory buffer. +# +# Requires two instances with their SCL and SDA lines connected together. +# Any combination of the below supported boards can be used. +# +# Notes: +# - pull-up resistors may be needed +# - alif use 1.8V signalling + +import sys +from machine import I2C, I2CTarget + +ADDR = 67 + +# Configure pins based on the target. +if sys.platform == "alif": + i2c_args = (1,) # pins P3_7/P3_6 + i2c_kwargs = {} +elif sys.platform == "esp32": + i2c_args = (1,) # on pins 9/8 + i2c_kwargs = {} +elif sys.platform == "mimxrt": + i2c_args = (0,) # pins 19/18 on Teensy 4.x + i2c_kwargs = {} +elif sys.platform == "rp2": + i2c_args = (0,) + i2c_kwargs = {"scl": 9, "sda": 8} +elif sys.platform == "pyboard": + i2c_args = ("Y",) + i2c_kwargs = {} +elif sys.platform == "samd": + i2c_args = () # pins SCL/SDA + i2c_kwargs = {} +elif "zephyr-rpi_pico" in sys.implementation._machine: + i2c_args = ("i2c1",) # on gpio7/gpio6 + i2c_kwargs = {} +else: + print("Please add support for this test on this platform.") + raise SystemExit + + +def simple_irq(i2c_target): + flags = i2c_target.irq().flags() + if flags & I2CTarget.IRQ_END_READ: + print("IRQ_END_READ", i2c_target.memaddr) + if flags & I2CTarget.IRQ_END_WRITE: + print("IRQ_END_WRITE", i2c_target.memaddr) + + +# I2C controller +def instance0(): + i2c = I2C(*i2c_args, **i2c_kwargs) + multitest.next() + for iteration in range(2): + print("controller iteration", iteration) + multitest.wait("target stage 1") + i2c.writeto_mem(ADDR, 2 + iteration, "0123") + multitest.broadcast("controller stage 2") + multitest.wait("target stage 3") + print(i2c.readfrom_mem(ADDR, 2 + iteration, 4)) + multitest.broadcast("controller stage 4") + print("done") + + +# I2C target +def instance1(): + buf = bytearray(b"--------") + i2c_target = I2CTarget(*i2c_args, **i2c_kwargs, addr=ADDR, mem=buf) + i2c_target.irq(simple_irq) + multitest.next() + for iteration in range(2): + print("target iteration", iteration) + multitest.broadcast("target stage 1") + multitest.wait("controller stage 2") + print(buf) + multitest.broadcast("target stage 3") + multitest.wait("controller stage 4") + i2c_target.deinit() + print("done") diff --git a/tests/multi_extmod/machine_i2c_target_memory.py.exp b/tests/multi_extmod/machine_i2c_target_memory.py.exp new file mode 100644 index 00000000000..71386cfe769 --- /dev/null +++ b/tests/multi_extmod/machine_i2c_target_memory.py.exp @@ -0,0 +1,16 @@ +--- instance0 --- +controller iteration 0 +b'0123' +controller iteration 1 +b'0123' +done +--- instance1 --- +target iteration 0 +IRQ_END_WRITE 2 +bytearray(b'--0123--') +IRQ_END_READ 2 +target iteration 1 +IRQ_END_WRITE 3 +bytearray(b'--00123-') +IRQ_END_READ 3 +done diff --git a/tests/perf_bench/bm_fft.py b/tests/perf_bench/bm_fft.py index 9a2d03d11b9..e35c1216c13 100644 --- a/tests/perf_bench/bm_fft.py +++ b/tests/perf_bench/bm_fft.py @@ -15,7 +15,7 @@ def reverse(x, bits): # Initialization n = len(vector) - levels = int(math.log(n) / math.log(2)) + levels = int(round(math.log(n) / math.log(2))) coef = (2 if inverse else -2) * cmath.pi / n exptable = [cmath.rect(1, i * coef) for i in range(n // 2)] vector = [vector[reverse(i, levels)] for i in range(n)] # Copy with bit-reversed permutation diff --git a/tests/perf_bench/bm_pidigits.py b/tests/perf_bench/bm_pidigits.py index bdaa73cec7e..c935f103c5b 100644 --- a/tests/perf_bench/bm_pidigits.py +++ b/tests/perf_bench/bm_pidigits.py @@ -5,6 +5,12 @@ # This benchmark stresses big integer arithmetic. # Adapted from code on: http://benchmarksgame.alioth.debian.org/ +try: + int("0x10000000000000000", 16) +except: + print("SKIP") # No support for >64-bit integers + raise SystemExit + def compose(a, b): aq, ar, as_, at = a diff --git a/tests/perf_bench/core_import_mpy_multi.py b/tests/perf_bench/core_import_mpy_multi.py index 8affa157fa0..67deec05088 100644 --- a/tests/perf_bench/core_import_mpy_multi.py +++ b/tests/perf_bench/core_import_mpy_multi.py @@ -6,7 +6,7 @@ print("SKIP") raise SystemExit -# This is the test.py file that is compiled to test.mpy below. +# This is the test.py file that is compiled to test.mpy below. mpy-cross must be invoked with `-msmall-int-bits=30`. """ class A: def __init__(self, arg): @@ -23,7 +23,7 @@ def f(): x = ("const tuple", None, False, True, 1, 2, 3) result = 123 """ -file_data = b'M\x06\x00\x1f\x14\x03\x0etest.py\x00\x0f\x02A\x00\x02f\x00\x0cresult\x00/-5#\x82I\x81{\x81w\x82/\x81\x05\x81\x17Iom\x82\x13\x06arg\x00\x05\x1cthis will be a string object\x00\x06\x1bthis will be a bytes object\x00\n\x07\x05\x0bconst tuple\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x81\\\x10\n\x01\x89\x07d`T2\x00\x10\x024\x02\x16\x022\x01\x16\x03"\x80{\x16\x04Qc\x02\x81d\x00\x08\x02(DD\x11\x05\x16\x06\x10\x02\x16\x072\x00\x16\x082\x01\x16\t2\x02\x16\nQc\x03`\x1a\x08\x08\x12\x13@\xb1\xb0\x18\x13Qc@\t\x08\t\x12` Qc@\t\x08\n\x12``Qc\x82@ \x0e\x03\x80\x08+)##\x12\x0b\x12\x0c\x12\r\x12\x0e*\x04Y\x12\x0f\x12\x10\x12\x11*\x03Y#\x00\xc0#\x01\xc0#\x02\xc0Qc' +file_data = b'M\x06\x00\x1e\x14\x03\x0etest.py\x00\x0f\x02A\x00\x02f\x00\x0cresult\x00/-5#\x82I\x81{\x81w\x82/\x81\x05\x81\x17Iom\x82\x13\x06arg\x00\x05\x1cthis will be a string object\x00\x06\x1bthis will be a bytes object\x00\n\x07\x05\x0bconst tuple\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x81\\\x10\n\x01\x89\x07d`T2\x00\x10\x024\x02\x16\x022\x01\x16\x03"\x80{\x16\x04Qc\x02\x81d\x00\x08\x02(DD\x11\x05\x16\x06\x10\x02\x16\x072\x00\x16\x082\x01\x16\t2\x02\x16\nQc\x03`\x1a\x08\x08\x12\x13@\xb1\xb0\x18\x13Qc@\t\x08\t\x12` Qc@\t\x08\n\x12``Qc\x82@ \x0e\x03\x80\x08+)##\x12\x0b\x12\x0c\x12\r\x12\x0e*\x04Y\x12\x0f\x12\x10\x12\x11*\x03Y#\x00\xc0#\x01\xc0#\x02\xc0Qc' class File(io.IOBase): diff --git a/tests/perf_bench/core_import_mpy_single.py b/tests/perf_bench/core_import_mpy_single.py index 4d9aa67bf2f..f472bb64762 100644 --- a/tests/perf_bench/core_import_mpy_single.py +++ b/tests/perf_bench/core_import_mpy_single.py @@ -8,7 +8,7 @@ print("SKIP") raise SystemExit -# This is the test.py file that is compiled to test.mpy below. +# This is the test.py file that is compiled to test.mpy below. mpy-cross must be invoked with `-msmall-int-bits=30`. # Many known and unknown names/strings are included to test the linking process. """ class A0: @@ -78,7 +78,7 @@ def f1(): x = ("const tuple 9", None, False, True, 1, 2, 3) result = 123 """ -file_data = b"M\x06\x00\x1f\x81=\x1e\x0etest.py\x00\x0f\x04A0\x00\x04A1\x00\x04f0\x00\x04f1\x00\x0cresult\x00/-5\x04a0\x00\x04a1\x00\x04a2\x00\x04a3\x00\x13\x15\x17\x19\x1b\x1d\x1f!#%')+1379;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\x7f\x81\x01\x81\x03\x81\x05\x81\x07\x81\t\x81\x0b\x81\r\x81\x0f\x81\x11\x81\x13\x81\x15\x81\x17\x81\x19\x81\x1b\x81\x1d\x81\x1f\x81!\x81#\x81%\x81'\x81)\x81+\x81-\x81/\x811\x813\x815\x817\x819\x81;\x81=\x81?\x81A\x81C\x81E\x81G\x81I\x81K\x81M\x81O\x81Q\x81S\x81U\x81W\x81Y\x81[\x81]\x81_\x81a\x81c\x81e\x81g\x81i\x81k\x81m\x81o\x81q\x81s\x81u\x81w\x81y\x81{\x81}\x81\x7f\x82\x01\x82\x03\x82\x05\x82\x07\x82\t\x82\x0b\x82\r\x82\x0f\x82\x11\x82\x13\x82\x15\x82\x17\x82\x19\x82\x1b\x82\x1d\x82\x1f\x82!\x82#\x82%\x82'\x82)\x82+\x82-\x82/\x821\x823\x825\x827\x829\x82;\x82=\x82?\x82A\x82E\x82G\x82I\x82K\nname0\x00\nname1\x00\nname2\x00\nname3\x00\nname4\x00\nname5\x00\nname6\x00\nname7\x00\nname8\x00\nname9\x00$quite_a_long_name0\x00$quite_a_long_name1\x00$quite_a_long_name2\x00$quite_a_long_name3\x00$quite_a_long_name4\x00$quite_a_long_name5\x00$quite_a_long_name6\x00$quite_a_long_name7\x00$quite_a_long_name8\x00$quite_a_long_name9\x00&quite_a_long_name10\x00&quite_a_long_name11\x00\x05\x1ethis will be a string object 0\x00\x05\x1ethis will be a string object 1\x00\x05\x1ethis will be a string object 2\x00\x05\x1ethis will be a string object 3\x00\x05\x1ethis will be a string object 4\x00\x05\x1ethis will be a string object 5\x00\x05\x1ethis will be a string object 6\x00\x05\x1ethis will be a string object 7\x00\x05\x1ethis will be a string object 8\x00\x05\x1ethis will be a string object 9\x00\x06\x1dthis will be a bytes object 0\x00\x06\x1dthis will be a bytes object 1\x00\x06\x1dthis will be a bytes object 2\x00\x06\x1dthis will be a bytes object 3\x00\x06\x1dthis will be a bytes object 4\x00\x06\x1dthis will be a bytes object 5\x00\x06\x1dthis will be a bytes object 6\x00\x06\x1dthis will be a bytes object 7\x00\x06\x1dthis will be a bytes object 8\x00\x06\x1dthis will be a bytes object 9\x00\n\x07\x05\rconst tuple 0\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 1\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 2\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 3\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 4\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 5\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 6\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 7\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 8\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 9\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x82d\x10\x12\x01i@i@\x84\x18\x84\x1fT2\x00\x10\x024\x02\x16\x02T2\x01\x10\x034\x02\x16\x032\x02\x16\x042\x03\x16\x05\"\x80{\x16\x06Qc\x04\x82\x0c\x00\n\x02($$$\x11\x07\x16\x08\x10\x02\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04@\t\x08\n\x81\x0b Qc@\t\x08\x0b\x81\x0b@Qc@\t\x08\x0c\x81\x0b`QcH\t\n\r\x81\x0b` Qc\x82\x14\x00\x0c\x03h`$$$\x11\x07\x16\x08\x10\x03\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04H\t\n\n\x81\x0b``QcH\t\n\x0b\x81\x0b\x80\x07QcH\t\n\x0c\x81\x0b\x80\x08QcH\t\n\r\x81\x0b\x80\tQc\xa08P:\x04\x80\x0b13///---997799<\x1f%\x1f\"\x1f%)\x1f\"//\x12\x0e\x12\x0f\x12\x10\x12\x11\x12\x12\x12\x13\x12\x14*\x07Y\x12\x15\x12\x16\x12\x17\x12\x18\x12\x19\x12\x1a\x12\x08\x12\x07*\x08Y\x12\x1b\x12\x1c\x12\t\x12\x1d\x12\x1e\x12\x1f*\x06Y\x12 \x12!\x12\"\x12#\x12$\x12%*\x06Y\x12&\x12'\x12(\x12)\x12*\x12+*\x06Y\x12,\x12-\x12.\x12/\x120*\x05Y\x121\x122\x123\x124\x125*\x05Y\x126\x127\x128\x129\x12:*\x05Y\x12;\x12<\x12=\x12>\x12?\x12@\x12A\x12B\x12C\x12D\x12E*\x0bY\x12F\x12G\x12H\x12I\x12J\x12K\x12L\x12M\x12N\x12O\x12P*\x0bY\x12Q\x12R\x12S\x12T\x12U\x12V\x12W\x12X\x12Y\x12Z*\nY\x12[\x12\\\x12]\x12^\x12_\x12`\x12a\x12b\x12c\x12d*\nY\x12e\x12f\x12g\x12h\x12i\x12j\x12k\x12l\x12m\x12n\x12o*\x0bY\x12p\x12q\x12r\x12s\x12t\x12u\x12v\x12w\x12x\x12y\x12z*\x0bY\x12{\x12|\x12}\x12~\x12\x7f\x12\x81\x00\x12\x81\x01\x12\x81\x02\x12\x81\x03\x12\x81\x04*\nY\x12\x81\x05\x12\x81\x06\x12\x81\x07\x12\x81\x08\x12\x81\t\x12\x81\n\x12\x81\x0b\x12\x81\x0c\x12\x81\r\x12\x81\x0e\x12\x81\x0f*\x0bY\x12\x81\x10\x12\x81\x11\x12\x81\x12\x12\x81\x13\x12\x81\x14\x12\x81\x15\x12\x81\x16\x12\x81\x17\x12\x81\x18\x12\x81\x19*\nY\x12\x81\x1a\x12\x81\x1b\x12\x81\x1c\x12\x81\x1d\x12\x81\x1e\x12\x81\x1f\x12\x81 \x12\x81!\x12\x81\"\x12\x81#\x12\x81$*\x0bY\x12\x81%\x12\x81&*\x02Y\x12\x81'\x12\x81(\x12\x81)\x12\x81*\x12\x81+\x12\x81,\x12\x81-\x12\x81.\x12\x81/\x12\x810*\nY\x12\x811\x12\x812\x12\x813\x12\x814*\x04Y\x12\x815\x12\x816\x12\x817\x12\x818*\x04Y\x12\x819\x12\x81:\x12\x81;\x12\x81<*\x04YQc\x87p\x08@\x05\x80###############################\x00\xc0#\x01\xc0#\x02\xc0#\x03\xc0#\x04\xc0#\x05\xc0#\x06\xc0#\x07\xc0#\x08\xc0#\t\xc0#\n\xc0#\x0b\xc0#\x0c\xc0#\r\xc0#\x0e\xc0#\x0f\xc0#\x10\xc0#\x11\xc0#\x12\xc0#\x13\xc0#\x14\xc0#\x15\xc0#\x16\xc0#\x17\xc0#\x18\xc0#\x19\xc0#\x1a\xc0#\x1b\xc0#\x1c\xc0#\x1d\xc0Qc" +file_data = b"M\x06\x00\x1e\x81=\x1e\x0etest.py\x00\x0f\x04A0\x00\x04A1\x00\x04f0\x00\x04f1\x00\x0cresult\x00/-5\x04a0\x00\x04a1\x00\x04a2\x00\x04a3\x00\x13\x15\x17\x19\x1b\x1d\x1f!#%')+1379;=?ACEGIKMOQSUWY[]_acegikmoqsuwy{}\x7f\x81\x01\x81\x03\x81\x05\x81\x07\x81\t\x81\x0b\x81\r\x81\x0f\x81\x11\x81\x13\x81\x15\x81\x17\x81\x19\x81\x1b\x81\x1d\x81\x1f\x81!\x81#\x81%\x81'\x81)\x81+\x81-\x81/\x811\x813\x815\x817\x819\x81;\x81=\x81?\x81A\x81C\x81E\x81G\x81I\x81K\x81M\x81O\x81Q\x81S\x81U\x81W\x81Y\x81[\x81]\x81_\x81a\x81c\x81e\x81g\x81i\x81k\x81m\x81o\x81q\x81s\x81u\x81w\x81y\x81{\x81}\x81\x7f\x82\x01\x82\x03\x82\x05\x82\x07\x82\t\x82\x0b\x82\r\x82\x0f\x82\x11\x82\x13\x82\x15\x82\x17\x82\x19\x82\x1b\x82\x1d\x82\x1f\x82!\x82#\x82%\x82'\x82)\x82+\x82-\x82/\x821\x823\x825\x827\x829\x82;\x82=\x82?\x82A\x82E\x82G\x82I\x82K\nname0\x00\nname1\x00\nname2\x00\nname3\x00\nname4\x00\nname5\x00\nname6\x00\nname7\x00\nname8\x00\nname9\x00$quite_a_long_name0\x00$quite_a_long_name1\x00$quite_a_long_name2\x00$quite_a_long_name3\x00$quite_a_long_name4\x00$quite_a_long_name5\x00$quite_a_long_name6\x00$quite_a_long_name7\x00$quite_a_long_name8\x00$quite_a_long_name9\x00&quite_a_long_name10\x00&quite_a_long_name11\x00\x05\x1ethis will be a string object 0\x00\x05\x1ethis will be a string object 1\x00\x05\x1ethis will be a string object 2\x00\x05\x1ethis will be a string object 3\x00\x05\x1ethis will be a string object 4\x00\x05\x1ethis will be a string object 5\x00\x05\x1ethis will be a string object 6\x00\x05\x1ethis will be a string object 7\x00\x05\x1ethis will be a string object 8\x00\x05\x1ethis will be a string object 9\x00\x06\x1dthis will be a bytes object 0\x00\x06\x1dthis will be a bytes object 1\x00\x06\x1dthis will be a bytes object 2\x00\x06\x1dthis will be a bytes object 3\x00\x06\x1dthis will be a bytes object 4\x00\x06\x1dthis will be a bytes object 5\x00\x06\x1dthis will be a bytes object 6\x00\x06\x1dthis will be a bytes object 7\x00\x06\x1dthis will be a bytes object 8\x00\x06\x1dthis will be a bytes object 9\x00\n\x07\x05\rconst tuple 0\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 1\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 2\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 3\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 4\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 5\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 6\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 7\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 8\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\n\x07\x05\rconst tuple 9\x00\x01\x02\x03\x07\x011\x07\x012\x07\x013\x82d\x10\x12\x01i@i@\x84\x18\x84\x1fT2\x00\x10\x024\x02\x16\x02T2\x01\x10\x034\x02\x16\x032\x02\x16\x042\x03\x16\x05\"\x80{\x16\x06Qc\x04\x82\x0c\x00\n\x02($$$\x11\x07\x16\x08\x10\x02\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04@\t\x08\n\x81\x0b Qc@\t\x08\x0b\x81\x0b@Qc@\t\x08\x0c\x81\x0b`QcH\t\n\r\x81\x0b` Qc\x82\x14\x00\x0c\x03h`$$$\x11\x07\x16\x08\x10\x03\x16\t2\x00\x16\n2\x01\x16\x0b2\x02\x16\x0c2\x03\x16\rQc\x04H\t\n\n\x81\x0b``QcH\t\n\x0b\x81\x0b\x80\x07QcH\t\n\x0c\x81\x0b\x80\x08QcH\t\n\r\x81\x0b\x80\tQc\xa08P:\x04\x80\x0b13///---997799<\x1f%\x1f\"\x1f%)\x1f\"//\x12\x0e\x12\x0f\x12\x10\x12\x11\x12\x12\x12\x13\x12\x14*\x07Y\x12\x15\x12\x16\x12\x17\x12\x18\x12\x19\x12\x1a\x12\x08\x12\x07*\x08Y\x12\x1b\x12\x1c\x12\t\x12\x1d\x12\x1e\x12\x1f*\x06Y\x12 \x12!\x12\"\x12#\x12$\x12%*\x06Y\x12&\x12'\x12(\x12)\x12*\x12+*\x06Y\x12,\x12-\x12.\x12/\x120*\x05Y\x121\x122\x123\x124\x125*\x05Y\x126\x127\x128\x129\x12:*\x05Y\x12;\x12<\x12=\x12>\x12?\x12@\x12A\x12B\x12C\x12D\x12E*\x0bY\x12F\x12G\x12H\x12I\x12J\x12K\x12L\x12M\x12N\x12O\x12P*\x0bY\x12Q\x12R\x12S\x12T\x12U\x12V\x12W\x12X\x12Y\x12Z*\nY\x12[\x12\\\x12]\x12^\x12_\x12`\x12a\x12b\x12c\x12d*\nY\x12e\x12f\x12g\x12h\x12i\x12j\x12k\x12l\x12m\x12n\x12o*\x0bY\x12p\x12q\x12r\x12s\x12t\x12u\x12v\x12w\x12x\x12y\x12z*\x0bY\x12{\x12|\x12}\x12~\x12\x7f\x12\x81\x00\x12\x81\x01\x12\x81\x02\x12\x81\x03\x12\x81\x04*\nY\x12\x81\x05\x12\x81\x06\x12\x81\x07\x12\x81\x08\x12\x81\t\x12\x81\n\x12\x81\x0b\x12\x81\x0c\x12\x81\r\x12\x81\x0e\x12\x81\x0f*\x0bY\x12\x81\x10\x12\x81\x11\x12\x81\x12\x12\x81\x13\x12\x81\x14\x12\x81\x15\x12\x81\x16\x12\x81\x17\x12\x81\x18\x12\x81\x19*\nY\x12\x81\x1a\x12\x81\x1b\x12\x81\x1c\x12\x81\x1d\x12\x81\x1e\x12\x81\x1f\x12\x81 \x12\x81!\x12\x81\"\x12\x81#\x12\x81$*\x0bY\x12\x81%\x12\x81&*\x02Y\x12\x81'\x12\x81(\x12\x81)\x12\x81*\x12\x81+\x12\x81,\x12\x81-\x12\x81.\x12\x81/\x12\x810*\nY\x12\x811\x12\x812\x12\x813\x12\x814*\x04Y\x12\x815\x12\x816\x12\x817\x12\x818*\x04Y\x12\x819\x12\x81:\x12\x81;\x12\x81<*\x04YQc\x87p\x08@\x05\x80###############################\x00\xc0#\x01\xc0#\x02\xc0#\x03\xc0#\x04\xc0#\x05\xc0#\x06\xc0#\x07\xc0#\x08\xc0#\t\xc0#\n\xc0#\x0b\xc0#\x0c\xc0#\r\xc0#\x0e\xc0#\x0f\xc0#\x10\xc0#\x11\xc0#\x12\xc0#\x13\xc0#\x14\xc0#\x15\xc0#\x16\xc0#\x17\xc0#\x18\xc0#\x19\xc0#\x1a\xc0#\x1b\xc0#\x1c\xc0#\x1d\xc0Qc" class File(io.IOBase): diff --git a/tests/run-internalbench.py b/tests/run-internalbench.py index c9f783e474c..99c6304afe9 100755 --- a/tests/run-internalbench.py +++ b/tests/run-internalbench.py @@ -8,6 +8,10 @@ from glob import glob from collections import defaultdict +run_tests_module = __import__("run-tests") +sys.path.append(run_tests_module.base_path("../tools")) +import pyboard + if os.name == "nt": MICROPYTHON = os.getenv( "MICROPY_MICROPYTHON", "../ports/windows/build-standard/micropython.exe" @@ -15,13 +19,39 @@ else: MICROPYTHON = os.getenv("MICROPY_MICROPYTHON", "../ports/unix/build-standard/micropython") +injected_bench_code = b""" +import time + +class bench_class: + ITERS = 20000000 + + @staticmethod + def run(test): + t = time.ticks_us() + test(bench_class.ITERS) + t = time.ticks_diff(time.ticks_us(), t) + s, us = divmod(t, 1_000_000) + print("{}.{:06}".format(s, us)) + +import sys +sys.modules['bench'] = bench_class +""" + -def run_tests(pyb, test_dict): +def execbench(pyb, filename, iters): + with open(filename, "rb") as f: + pyfile = f.read() + code = (injected_bench_code + pyfile).replace(b"20000000", str(iters).encode("utf-8")) + return pyb.exec(code).replace(b"\r\n", b"\n") + + +def run_tests(pyb, test_dict, iters): test_count = 0 testcase_count = 0 for base_test, tests in sorted(test_dict.items()): print(base_test + ":") + baseline = None for test_file in tests: # run MicroPython if pyb is None: @@ -36,20 +66,25 @@ def run_tests(pyb, test_dict): # run on pyboard pyb.enter_raw_repl() try: - output_mupy = pyb.execfile(test_file).replace(b"\r\n", b"\n") + output_mupy = execbench(pyb, test_file[0], iters) except pyboard.PyboardError: output_mupy = b"CRASH" - output_mupy = float(output_mupy.strip()) + try: + output_mupy = float(output_mupy.strip()) + except ValueError: + output_mupy = -1 test_file[1] = output_mupy testcase_count += 1 - test_count += 1 - baseline = None - for t in tests: if baseline is None: - baseline = t[1] - print(" %.3fs (%+06.2f%%) %s" % (t[1], (t[1] * 100 / baseline) - 100, t[0])) + baseline = test_file[1] + print( + " %.3fs (%+06.2f%%) %s" + % (test_file[1], (test_file[1] * 100 / baseline) - 100, test_file[0]) + ) + + test_count += 1 print("{} tests performed ({} individual testcases)".format(test_count, testcase_count)) @@ -58,27 +93,47 @@ def run_tests(pyb, test_dict): def main(): - cmd_parser = argparse.ArgumentParser(description="Run tests for MicroPython.") - cmd_parser.add_argument("--pyboard", action="store_true", help="run the tests on the pyboard") + cmd_parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description=f"""Run and manage tests for MicroPython. + +{run_tests_module.test_instance_description} +{run_tests_module.test_directory_description} +""", + epilog=run_tests_module.test_instance_epilog, + ) + cmd_parser.add_argument( + "-t", "--test-instance", default="unix", help="the MicroPython instance to test" + ) + cmd_parser.add_argument( + "-b", "--baudrate", default=115200, help="the baud rate of the serial device" + ) + cmd_parser.add_argument("-u", "--user", default="micro", help="the telnet login username") + cmd_parser.add_argument("-p", "--password", default="python", help="the telnet login password") + cmd_parser.add_argument( + "-d", "--test-dirs", nargs="*", help="input test directories (if no files given)" + ) + cmd_parser.add_argument( + "-I", + "--iters", + type=int, + default=200_000, + help="number of test iterations, only for remote instances (default 200,000)", + ) cmd_parser.add_argument("files", nargs="*", help="input test files") args = cmd_parser.parse_args() # Note pyboard support is copied over from run-tests.py, not tests, and likely needs revamping - if args.pyboard: - import pyboard - - pyb = pyboard.Pyboard("/dev/ttyACM0") - pyb.enter_raw_repl() - else: - pyb = None + pyb = run_tests_module.get_test_instance( + args.test_instance, args.baudrate, args.user, args.password + ) if len(args.files) == 0: - if pyb is None: - # run PC tests - test_dirs = ("internal_bench",) + if args.test_dirs: + test_dirs = tuple(args.test_dirs) else: - # run pyboard tests - test_dirs = ("basics", "float", "pyb") + test_dirs = ("internal_bench",) + tests = sorted( test_file for test_files in (glob("{}/*.py".format(dir)) for dir in test_dirs) @@ -95,7 +150,7 @@ def main(): continue test_dict[m.group(1)].append([t, None]) - if not run_tests(pyb, test_dict): + if not run_tests(pyb, test_dict, args.iters): sys.exit(1) diff --git a/tests/run-multitests.py b/tests/run-multitests.py index 387eec7018b..e5458ffe0d0 100755 --- a/tests/run-multitests.py +++ b/tests/run-multitests.py @@ -15,6 +15,8 @@ import subprocess import tempfile +run_tests_module = __import__("run-tests") + test_dir = os.path.abspath(os.path.dirname(__file__)) if os.path.abspath(sys.path[0]) == test_dir: @@ -130,6 +132,11 @@ def get_host_ip(_ip_cache=[]): return _ip_cache[0] +def decode(output): + # Convenience function to convert raw process or serial output to ASCII + return str(output, "ascii", "backslashreplace") + + class PyInstance: def __init__(self): pass @@ -188,7 +195,7 @@ def run_script(self, script): output = p.stdout except subprocess.CalledProcessError as er: err = er - return str(output.strip(), "ascii"), err + return decode(output.strip()), err def start_script(self, script): self.popen = subprocess.Popen( @@ -215,7 +222,7 @@ def readline(self): self.finished = self.popen.poll() is not None return None, None else: - return str(out.rstrip(), "ascii"), None + return decode(out.rstrip()), None def write(self, data): self.popen.stdin.write(data) @@ -227,21 +234,12 @@ def is_finished(self): def wait_finished(self): self.popen.wait() out = self.popen.stdout.read() - return str(out, "ascii"), "" + return decode(out), "" class PyInstancePyboard(PyInstance): - @staticmethod - def map_device_shortcut(device): - if device[0] == "a" and device[1:].isdigit(): - return "/dev/ttyACM" + device[1:] - elif device[0] == "u" and device[1:].isdigit(): - return "/dev/ttyUSB" + device[1:] - else: - return device - def __init__(self, device): - device = self.map_device_shortcut(device) + device = device self.device = device self.pyb = pyboard.Pyboard(device) self.pyb.enter_raw_repl() @@ -262,7 +260,7 @@ def run_script(self, script): output = self.pyb.exec_(script) except pyboard.PyboardError as er: err = er - return str(output.strip(), "ascii"), err + return decode(output.strip()), err def start_script(self, script): self.pyb.enter_raw_repl() @@ -281,13 +279,13 @@ def readline(self): if out.endswith(b"\x04"): self.finished = True out = out[:-1] - err = str(self.pyb.read_until(1, b"\x04"), "ascii") + err = decode(self.pyb.read_until(1, b"\x04")) err = err[:-1] if not out and not err: return None, None else: err = None - return str(out.rstrip(), "ascii"), err + return decode(out.rstrip()), err def write(self, data): self.pyb.serial.write(data) @@ -297,7 +295,7 @@ def is_finished(self): def wait_finished(self): out, err = self.pyb.follow(10, None) - return str(out, "ascii"), str(err, "ascii") + return decode(out), decode(err) def prepare_test_file_list(test_files): @@ -488,9 +486,7 @@ def print_diff(a, b): def run_tests(test_files, instances_truth, instances_test): - skipped_tests = [] - passed_tests = [] - failed_tests = [] + test_results = [] for test_file, num_instances in test_files: instances_str = "|".join(str(instances_test[i]) for i in range(num_instances)) @@ -526,13 +522,13 @@ def run_tests(test_files, instances_truth, instances_test): # Print result of test if skip: print("skip") - skipped_tests.append(test_file) + test_results.append((test_file, "skip", "")) elif output_test == output_truth: print("pass") - passed_tests.append(test_file) + test_results.append((test_file, "pass", "")) else: print("FAIL") - failed_tests.append(test_file) + test_results.append((test_file, "fail", "")) if not cmd_args.show_output: print("### TEST ###") print(output_test, end="") @@ -549,15 +545,7 @@ def run_tests(test_files, instances_truth, instances_test): if cmd_args.show_output: print() - print("{} tests performed".format(len(skipped_tests) + len(passed_tests) + len(failed_tests))) - print("{} tests passed".format(len(passed_tests))) - - if skipped_tests: - print("{} tests skipped: {}".format(len(skipped_tests), " ".join(skipped_tests))) - if failed_tests: - print("{} tests failed: {}".format(len(failed_tests), " ".join(failed_tests))) - - return not failed_tests + return test_results def main(): @@ -565,16 +553,24 @@ def main(): cmd_parser = argparse.ArgumentParser( description="Run network tests for MicroPython", + epilog=( + run_tests_module.test_instance_epilog + + "Each instance arg can optionally have custom env provided, eg. ,ENV=VAR,ENV=VAR...\n" + ), formatter_class=argparse.RawTextHelpFormatter, ) cmd_parser.add_argument( "-s", "--show-output", action="store_true", help="show test output after running" ) cmd_parser.add_argument( - "-t", "--trace-output", action="store_true", help="trace test output while running" + "-c", "--trace-output", action="store_true", help="trace test output while running" ) cmd_parser.add_argument( - "-i", "--instance", action="append", default=[], help="instance(s) to run the tests on" + "-t", + "--test-instance", + action="append", + default=[], + help="instance(s) to run the tests on", ) cmd_parser.add_argument( "-p", @@ -583,13 +579,11 @@ def main(): default=1, help="repeat the test with this many permutations of the instance order", ) - cmd_parser.epilog = ( - "Supported instance types:\r\n" - " -i pyb: physical device (eg. pyboard) on provided repl port.\n" - " -i micropython unix micropython instance, path customised with MICROPY_MICROPYTHON env.\n" - " -i cpython desktop python3 instance, path customised with MICROPY_CPYTHON3 env.\n" - " -i exec: custom program run on provided path.\n" - "Each instance arg can optionally have custom env provided, eg. ,ENV=VAR,ENV=VAR...\n" + cmd_parser.add_argument( + "-r", + "--result-dir", + default=run_tests_module.base_path("results"), + help="directory for test results", ) cmd_parser.add_argument("files", nargs="+", help="input test files") cmd_args = cmd_parser.parse_args() @@ -603,33 +597,36 @@ def main(): instances_truth = [PyInstanceSubProcess([PYTHON_TRUTH]) for _ in range(max_instances)] instances_test = [] - for i in cmd_args.instance: + for i in cmd_args.test_instance: # Each instance arg is ,ENV=VAR,ENV=VAR... i = i.split(",") cmd = i[0] env = i[1:] if cmd.startswith("exec:"): instances_test.append(PyInstanceSubProcess([cmd[len("exec:") :]], env)) - elif cmd == "micropython": + elif cmd == "unix": instances_test.append(PyInstanceSubProcess([MICROPYTHON], env)) elif cmd == "cpython": instances_test.append(PyInstanceSubProcess([CPYTHON3], env)) - elif cmd.startswith("pyb:"): - instances_test.append(PyInstancePyboard(cmd[len("pyb:") :])) + elif cmd == "webassembly" or cmd.startswith("execpty:"): + print("unsupported instance string: {}".format(cmd), file=sys.stderr) + sys.exit(2) else: - print("unknown instance string: {}".format(cmd), file=sys.stderr) - sys.exit(1) + device = run_tests_module.convert_device_shortcut_to_real_device(cmd) + instances_test.append(PyInstancePyboard(device)) for _ in range(max_instances - len(instances_test)): instances_test.append(PyInstanceSubProcess([MICROPYTHON])) + os.makedirs(cmd_args.result_dir, exist_ok=True) all_pass = True try: for i, instances_test_permutation in enumerate(itertools.permutations(instances_test)): if i >= cmd_args.permutations: break - all_pass &= run_tests(test_files, instances_truth, instances_test_permutation) + test_results = run_tests(test_files, instances_truth, instances_test_permutation) + all_pass &= run_tests_module.create_test_report(cmd_args, test_results) finally: for i in instances_truth: diff --git a/tests/run-natmodtests.py b/tests/run-natmodtests.py index 340a7f004b0..6d2a975b82a 100755 --- a/tests/run-natmodtests.py +++ b/tests/run-natmodtests.py @@ -9,7 +9,7 @@ import sys import argparse -# CIRCUITPY-CHANGE: no pyboard +run_tests_module = __import__("run-tests") # Paths for host executables CPYTHON3 = os.getenv("MICROPY_CPYTHON3", "python3") @@ -72,6 +72,7 @@ def open(self, path, mode): # CIRCUITPY-CHANGE: no vfs, but still have os os.mount(__FS(), '/__remote') sys.path.insert(0, '/__remote') +{import_prelude} sys.modules['{}'] = __import__('__injected') """ @@ -108,7 +109,7 @@ def run_script(self, script): output = self.pyb.exec_(script) output = output.replace(b"\r\n", b"\n") return output, None - except pyboard.PyboardError as er: + except run_tests_module.pyboard.PyboardError as er: return b"", er @@ -131,7 +132,15 @@ def detect_architecture(target): return platform, arch, None -def run_tests(target_truth, target, args, stats, resolved_arch): +def run_tests(target_truth, target, args, resolved_arch): + global injected_import_hook_code + + prelude = "" + if args.begin: + prelude = args.begin.read() + injected_import_hook_code = injected_import_hook_code.replace("{import_prelude}", prelude) + + test_results = [] for test_file in args.files: # Find supported test test_file_basename = os.path.basename(test_file) @@ -154,9 +163,11 @@ def run_tests(target_truth, target, args, stats, resolved_arch): with open(NATMOD_EXAMPLE_DIR + test_mpy, "rb") as f: test_script += b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n" except OSError: - print("---- {} - mpy file not compiled".format(test_file)) + test_results.append((test_file, "skip", "mpy file not compiled")) + print("skip {} - mpy file not compiled".format(test_file)) continue test_script += bytes(injected_import_hook_code.format(test_module), "ascii") + test_script += b"print('START TEST')\n" test_script += test_file_data # Run test under MicroPython @@ -164,8 +175,18 @@ def run_tests(target_truth, target, args, stats, resolved_arch): # Work out result of test extra = "" + result_out = result_out.removeprefix(b"START TEST\n") if error is None and result_out == b"SKIP\n": result = "SKIP" + elif ( + error is not None + and error.args[0] == "exception" + and error.args[1] == b"" + and b"MemoryError" in error.args[2] + ): + # Test had a MemoryError before anything (should be at least "START TEST") + # was printed, so the test is too big for the target. + result = "LRGE" elif error is not None: result = "FAIL" extra = " - " + str(error) @@ -186,40 +207,63 @@ def run_tests(target_truth, target, args, stats, resolved_arch): result = "pass" # Accumulate statistics - stats["total"] += 1 if result == "pass": - stats["pass"] += 1 + test_results.append((test_file, "pass", "")) elif result == "SKIP": - stats["skip"] += 1 + test_results.append((test_file, "skip", "")) + elif result == "LRGE": + test_results.append((test_file, "skip", "too large")) else: - stats["fail"] += 1 + test_results.append((test_file, "fail", "")) # Print result print("{:4} {}{}".format(result, test_file, extra)) + return test_results + def main(): cmd_parser = argparse.ArgumentParser( - description="Run dynamic-native-module tests under MicroPython" + description="Run dynamic-native-module tests under MicroPython", + epilog=run_tests_module.test_instance_epilog, + formatter_class=argparse.RawDescriptionHelpFormatter, ) cmd_parser.add_argument( - "-p", "--pyboard", action="store_true", help="run tests via pyboard.py" + "-t", "--test-instance", default="unix", help="the MicroPython instance to test" ) + cmd_parser.add_argument("--baudrate", default=115200, help="baud rate of the serial device") + cmd_parser.add_argument("--user", default="micro", help="telnet login username") + cmd_parser.add_argument("--password", default="python", help="telnet login password") cmd_parser.add_argument( - "-d", "--device", default="/dev/ttyACM0", help="the device for pyboard.py" + "-a", "--arch", choices=AVAILABLE_ARCHS, help="override native architecture of the target" ) cmd_parser.add_argument( - "-a", "--arch", choices=AVAILABLE_ARCHS, help="override native architecture of the target" + "-b", + "--begin", + type=argparse.FileType("rt"), + default=None, + help="prologue python file to execute before module import", + ) + cmd_parser.add_argument( + "-r", + "--result-dir", + default=run_tests_module.base_path("results"), + help="directory for test results", ) cmd_parser.add_argument("files", nargs="*", help="input test files") args = cmd_parser.parse_args() target_truth = TargetSubprocess([CPYTHON3]) - if args.pyboard: - target = TargetPyboard(pyboard.Pyboard(args.device)) - else: + target = run_tests_module.get_test_instance( + args.test_instance, args.baudrate, args.user, args.password + ) + if target is None: + # Use the unix port of MicroPython. target = TargetSubprocess([MICROPYTHON]) + else: + # Use a remote target. + target = TargetPyboard(target) if hasattr(args, "arch") and args.arch is not None: target_arch = args.arch @@ -235,20 +279,14 @@ def main(): print("platform={} ".format(target_platform), end="") print("arch={}".format(target_arch)) - stats = {"total": 0, "pass": 0, "fail": 0, "skip": 0} - run_tests(target_truth, target, args, stats, target_arch) + os.makedirs(args.result_dir, exist_ok=True) + test_results = run_tests(target_truth, target, args, target_arch) + res = run_tests_module.create_test_report(args, test_results) target.close() target_truth.close() - print("{} tests performed".format(stats["total"])) - print("{} tests passed".format(stats["pass"])) - if stats["fail"]: - print("{} tests failed".format(stats["fail"])) - if stats["skip"]: - print("{} tests skipped".format(stats["skip"])) - - if stats["fail"]: + if not res: sys.exit(1) diff --git a/tests/run-perfbench.py b/tests/run-perfbench.py index 81d873c4599..039d11a3611 100755 --- a/tests/run-perfbench.py +++ b/tests/run-perfbench.py @@ -10,10 +10,9 @@ import argparse from glob import glob -sys.path.append("../tools") -import pyboard +run_tests_module = __import__("run-tests") -prepare_script_for_target = __import__("run-tests").prepare_script_for_target +prepare_script_for_target = run_tests_module.prepare_script_for_target # Paths for host executables if os.name == "nt": @@ -45,12 +44,12 @@ def run_script_on_target(target, script): output = b"" err = None - if isinstance(target, pyboard.Pyboard): + if hasattr(target, "enter_raw_repl"): # Run via pyboard interface try: target.enter_raw_repl() output = target.exec_(script) - except pyboard.PyboardError as er: + except run_tests_module.pyboard.PyboardError as er: err = er else: # Run local executable @@ -90,9 +89,9 @@ def run_benchmark_on_target(target, script): def run_benchmarks(args, target, param_n, param_m, n_average, test_list): + test_results = [] skip_complex = run_feature_test(target, "complex") != "complex" skip_native = run_feature_test(target, "native_check") != "native" - target_had_error = False for test_file in sorted(test_list): print(test_file + ": ", end="") @@ -105,6 +104,7 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): and test_file.find("viper_") != -1 ) if skip: + test_results.append((test_file, "skip", "")) print("SKIP") continue @@ -122,9 +122,10 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): f.write(test_script) # Process script through mpy-cross if needed - if isinstance(target, pyboard.Pyboard) or args.via_mpy: + if hasattr(target, "enter_raw_repl") or args.via_mpy: crash, test_script_target = prepare_script_for_target(args, script_text=test_script) if crash: + test_results.append((test_file, "fail", "preparation")) print("CRASH:", test_script_target) continue else: @@ -162,10 +163,13 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): error = "FAIL truth" if error is not None: - if not error.startswith("SKIP"): - target_had_error = True + if error.startswith("SKIP"): + test_results.append((test_file, "skip", error)) + else: + test_results.append((test_file, "fail", error)) print(error) else: + test_results.append((test_file, "pass", "")) t_avg, t_sd = compute_stats(times) s_avg, s_sd = compute_stats(scores) print( @@ -179,7 +183,7 @@ def run_benchmarks(args, target, param_n, param_m, n_average, test_list): sys.stdout.flush() - return target_had_error + return test_results def parse_output(filename): @@ -190,7 +194,13 @@ def parse_output(filename): m = int(m.split("=")[1]) data = [] for l in f: - if ": " in l and ": SKIP" not in l and "CRASH: " not in l: + if ( + ": " in l + and ": SKIP" not in l + and "CRASH: " not in l + and "skipped: " not in l + and "failed: " not in l + ): name, values = l.strip().split(": ") values = tuple(float(v) for v in values.split()) data.append((name,) + values) @@ -246,17 +256,17 @@ def compute_diff(file1, file2, diff_score): def main(): cmd_parser = argparse.ArgumentParser(description="Run benchmarks for MicroPython") cmd_parser.add_argument( - "-t", "--diff-time", action="store_true", help="diff time outputs from a previous run" + "-m", "--diff-time", action="store_true", help="diff time outputs from a previous run" ) cmd_parser.add_argument( "-s", "--diff-score", action="store_true", help="diff score outputs from a previous run" ) cmd_parser.add_argument( - "-p", "--pyboard", action="store_true", help="run tests via pyboard.py" - ) - cmd_parser.add_argument( - "-d", "--device", default="/dev/ttyACM0", help="the device for pyboard.py" + "-t", "--test-instance", default="unix", help="the MicroPython instance to test" ) + cmd_parser.add_argument("--baudrate", default=115200, help="baud rate of the serial device") + cmd_parser.add_argument("--user", default="micro", help="telnet login username") + cmd_parser.add_argument("--password", default="python", help="telnet login password") cmd_parser.add_argument("-a", "--average", default="8", help="averaging number") cmd_parser.add_argument( "--emit", default="bytecode", help="MicroPython emitter to use (bytecode or native)" @@ -264,6 +274,12 @@ def main(): cmd_parser.add_argument("--heapsize", help="heapsize to use (use default if not specified)") cmd_parser.add_argument("--via-mpy", action="store_true", help="compile code to .mpy first") cmd_parser.add_argument("--mpy-cross-flags", default="", help="flags to pass to mpy-cross") + cmd_parser.add_argument( + "-r", + "--result-dir", + default=run_tests_module.base_path("results"), + help="directory for test results", + ) cmd_parser.add_argument( "N", nargs=1, help="N parameter (approximate target CPU frequency in MHz)" ) @@ -282,15 +298,18 @@ def main(): M = int(args.M[0]) n_average = int(args.average) - if args.pyboard: - if not args.mpy_cross_flags: - args.mpy_cross_flags = "-march=armv7m" - target = pyboard.Pyboard(args.device) - target.enter_raw_repl() - else: + target = run_tests_module.get_test_instance( + args.test_instance, args.baudrate, args.user, args.password + ) + if target is None: + # Use the unix port of MicroPython. target = [MICROPYTHON, "-X", "emit=" + args.emit] if args.heapsize is not None: target.extend(["-X", "heapsize=" + args.heapsize]) + else: + # Use a remote target. + if not args.mpy_cross_flags: + args.mpy_cross_flags = "-march=armv7m" if len(args.files) == 0: tests_skip = ("benchrun.py",) @@ -307,13 +326,15 @@ def main(): print("N={} M={} n_average={}".format(N, M, n_average)) - target_had_error = run_benchmarks(args, target, N, M, n_average, tests) + os.makedirs(args.result_dir, exist_ok=True) + test_results = run_benchmarks(args, target, N, M, n_average, tests) + res = run_tests_module.create_test_report(args, test_results) - if isinstance(target, pyboard.Pyboard): + if hasattr(target, "exit_raw_repl"): target.exit_raw_repl() target.close() - if target_had_error: + if not res: sys.exit(1) diff --git a/tests/run-tests.py b/tests/run-tests.py index cb839ae23dc..71570292ce7 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -15,13 +15,15 @@ import threading import tempfile -# Maximum time to run a PC-based test, in seconds. -TEST_TIMEOUT = 30 +# Maximum time to run a single test, in seconds. +TEST_TIMEOUT = float(os.environ.get("MICROPY_TEST_TIMEOUT", 30)) # See stackoverflow.com/questions/2632199: __file__ nor sys.argv[0] # are guaranteed to always work, this one should though. BASEPATH = os.path.dirname(os.path.abspath(inspect.getsourcefile(lambda: None))) +RV32_ARCH_FLAGS = {"zba": 1 << 0} + def base_path(*p): return os.path.abspath(os.path.join(BASEPATH, *p)).replace("\\", "/") @@ -58,6 +60,23 @@ def base_path(*p): # Set PYTHONIOENCODING so that CPython will use utf-8 on systems which set another encoding in the locale os.environ["PYTHONIOENCODING"] = "utf-8" + +def normalize_newlines(data): + """Normalize newline variations to \\n. + + Only normalizes actual line endings, not literal \\r characters in strings. + Handles \\r\\r\\n and \\r\\n cases to ensure consistent comparison + across different platforms and terminals. + """ + if isinstance(data, bytes): + # Handle PTY double-newline issue first + data = data.replace(b"\r\r\n", b"\n") + # Then handle standard Windows line endings + data = data.replace(b"\r\n", b"\n") + # Don't convert standalone \r as it might be literal content + return data + + # Code to allow a target MicroPython to import an .mpy from RAM # Note: the module is named `__injected_test` but it needs to have `__name__` set to # `__main__` so that the test sees itself as the main module, eg so unittest works. @@ -88,31 +107,82 @@ def getcwd(self): return "" def stat(self, path): if path == '__injected_test.mpy': - return tuple(0 for _ in range(10)) + return (0,0,0,0,0,0,0,0,0,0) else: - raise OSError(-2) # ENOENT + raise OSError(2) # ENOENT def open(self, path, mode): + self.stat(path) return __File() vfs.mount(__FS(), '/__vfstest') os.chdir('/__vfstest') +{import_prologue} __import__('__injected_test') """ # Platforms associated with the unix port, values of `sys.platform`. PC_PLATFORMS = ("darwin", "linux", "win32") +# Mapping from `sys.platform` to the port name, for special cases. +# See `platform_to_port()` function. +platform_to_port_map = {"pyboard": "stm32", "WiPy": "cc3200"} +platform_to_port_map.update({p: "unix" for p in PC_PLATFORMS}) + +# Tests to skip for values of the `--via-mpy` argument. +via_mpy_tests_to_skip = { + # Skip the following when mpy is enabled. + True: ( + # These print out the filename and that's expected to match the .py name. + "import/import_file.py", + "io/argv.py", + "misc/sys_settrace_features.py", + "misc/sys_settrace_generator.py", + "misc/sys_settrace_loop.py", + ), +} + +# Tests to skip for specific emitters. +emitter_tests_to_skip = { + # Some tests are known to fail with native emitter. + # Remove them from the below when they work. + "native": ( + # These require raise_varargs. + "basics/gen_yield_from_close.py", + "basics/try_finally_return2.py", + "basics/try_reraise.py", + "basics/try_reraise2.py", + "misc/features.py", + # These require checking for unbound local. + "basics/annotate_var.py", + "basics/del_deref.py", + "basics/del_local.py", + "basics/scope_implicit.py", + "basics/unboundlocal.py", + # These require "raise from". + "basics/exception_chain.py", + # These require stack-allocated slice optimisation. + "micropython/heapalloc_slice.py", + # These require running the scheduler. + "micropython/schedule.py", + "extmod/asyncio_event_queue.py", + "extmod/asyncio_iterator_event.py", + # These require sys.exc_info(). + "misc/sys_exc_info.py", + # These require sys.settrace(). + "misc/sys_settrace_cov.py", + "misc/sys_settrace_features.py", + "misc/sys_settrace_generator.py", + "misc/sys_settrace_loop.py", + # These are bytecode-specific tests. + "stress/bytecode_limit.py", + ), +} + # Tests to skip on specific targets. # These are tests that are difficult to detect that they should not be run on the given target. platform_tests_to_skip = { - "esp8266": ( - "micropython/viper_args.py", # too large - "micropython/viper_binop_arith.py", # too large - "misc/rge_sm.py", # too large - ), "minimal": ( "basics/class_inplace_op.py", # all special methods not supported "basics/subclass_native_init.py", # native subclassing corner cases not support - "misc/rge_sm.py", # too large "micropython/opt_level.py", # don't assume line numbers are stored ), "nrf": ( @@ -140,14 +210,6 @@ def open(self, path, mode): "thread/thread_lock3.py", "thread/thread_shared2.py", ), - "qemu": ( - # Skip tests that require Cortex-M4. - "inlineasm/thumb/asmfpaddsub.py", - "inlineasm/thumb/asmfpcmp.py", - "inlineasm/thumb/asmfpldrstr.py", - "inlineasm/thumb/asmfpmuldiv.py", - "inlineasm/thumb/asmfpsqrt.py", - ), "webassembly": ( "basics/string_format_modulo.py", # can't print nulls to stdout "basics/string_strip.py", # can't print nulls to stdout @@ -162,6 +224,9 @@ def open(self, path, mode): "extmod/asyncio_new_event_loop.py", "extmod/asyncio_threadsafeflag.py", "extmod/asyncio_wait_for_fwd.py", + "extmod/asyncio_event_queue.py", + "extmod/asyncio_iterator_event.py", + "extmod/asyncio_wait_for_linked_task.py", "extmod/binascii_a2b_base64.py", "extmod/deflate_compress_memory_error.py", # tries to allocate unlimited memory "extmod/re_stack_overflow.py", @@ -184,6 +249,89 @@ def open(self, path, mode): ), } +# These tests don't test float explicitly but rather use it to perform the test. +tests_requiring_float = ( + "extmod/asyncio_basic.py", + "extmod/asyncio_basic2.py", + "extmod/asyncio_cancel_task.py", + "extmod/asyncio_event.py", + "extmod/asyncio_fair.py", + "extmod/asyncio_gather.py", + "extmod/asyncio_gather_notimpl.py", + "extmod/asyncio_get_event_loop.py", + "extmod/asyncio_iterator_event.py", + "extmod/asyncio_lock.py", + "extmod/asyncio_task_done.py", + "extmod/asyncio_wait_for.py", + "extmod/asyncio_wait_for_fwd.py", + "extmod/asyncio_wait_for_linked_task.py", + "extmod/asyncio_wait_task.py", + "extmod/json_dumps_float.py", + "extmod/json_loads_float.py", + "extmod/random_extra_float.py", + "extmod/select_poll_eintr.py", + "extmod/tls_threads.py", + "extmod/uctypes_le_float.py", + "extmod/uctypes_native_float.py", + "extmod/uctypes_sizeof_float.py", + "misc/rge_sm.py", + "ports/unix/ffi_float.py", + "ports/unix/ffi_float2.py", +) + +# These tests don't test slice explicitly but rather use it to perform the test. +tests_requiring_slice = ( + "basics/builtin_range.py", + "basics/bytearray1.py", + "basics/class_super.py", + "basics/containment.py", + "basics/errno1.py", + "basics/fun_str.py", + "basics/generator1.py", + "basics/globals_del.py", + "basics/memoryview1.py", + "basics/memoryview_gc.py", + "basics/object1.py", + "basics/python34.py", + "basics/struct_endian.py", + "extmod/btree1.py", + "extmod/deflate_decompress.py", + "extmod/framebuf16.py", + "extmod/framebuf4.py", + "extmod/machine1.py", + "extmod/time_mktime.py", + "extmod/time_res.py", + "extmod/tls_sslcontext_ciphers.py", + "extmod/vfs_fat_fileio1.py", + "extmod/vfs_fat_finaliser.py", + "extmod/vfs_fat_more.py", + "extmod/vfs_fat_ramdisk.py", + "extmod/vfs_fat_ramdisklarge.py", + "extmod/vfs_lfs.py", + "extmod/vfs_rom.py", + "float/string_format_modulo.py", + "micropython/builtin_execfile.py", + "micropython/extreme_exc.py", + "micropython/heapalloc_fail_bytearray.py", + "micropython/heapalloc_fail_list.py", + "micropython/heapalloc_fail_memoryview.py", + "micropython/import_mpy_invalid.py", + "micropython/import_mpy_native.py", + "micropython/import_mpy_native_gc.py", + "misc/non_compliant.py", + "misc/rge_sm.py", +) + +# Tests that require `import target_wiring` to work. +tests_requiring_target_wiring = ( + "extmod/machine_uart_irq_txidle.py", + "extmod/machine_uart_tx.py", + "extmod_hardware/machine_encoder.py", + "extmod_hardware/machine_uart_irq_break.py", + "extmod_hardware/machine_uart_irq_rx.py", + "extmod_hardware/machine_uart_irq_rxidle.py", +) + def rm_f(fname): if os.path.exists(fname): @@ -210,22 +358,31 @@ def convert_regex_escapes(line): return bytes("".join(cs), "utf8") +def platform_to_port(platform): + return platform_to_port_map.get(platform, platform) + + +def convert_device_shortcut_to_real_device(device): + if device.startswith("port:"): + return device.split(":", 1)[1] + elif device.startswith("a") and device[1:].isdigit(): + return "/dev/ttyACM" + device[1:] + elif device.startswith("u") and device[1:].isdigit(): + return "/dev/ttyUSB" + device[1:] + elif device.startswith("c") and device[1:].isdigit(): + return "COM" + device[1:] + else: + return device + + def get_test_instance(test_instance, baudrate, user, password): - if test_instance.startswith("port:"): - _, port = test_instance.split(":", 1) - elif test_instance == "unix": + if test_instance == "unix": return None elif test_instance == "webassembly": return PyboardNodeRunner() - elif test_instance.startswith("a") and test_instance[1:].isdigit(): - port = "/dev/ttyACM" + test_instance[1:] - elif test_instance.startswith("u") and test_instance[1:].isdigit(): - port = "/dev/ttyUSB" + test_instance[1:] - elif test_instance.startswith("c") and test_instance[1:].isdigit(): - port = "COM" + test_instance[1:] else: # Assume it's a device path. - port = test_instance + port = convert_device_shortcut_to_real_device(test_instance) global pyboard sys.path.append(base_path("../tools")) @@ -245,46 +402,114 @@ def detect_inline_asm_arch(pyb, args): return None +def map_rv32_arch_flags(flags): + mapped_flags = [] + for extension, bit in RV32_ARCH_FLAGS.items(): + if flags & bit: + mapped_flags.append(extension) + flags &= ~bit + if flags: + raise Exception("Unexpected flag bits set in value {}".format(flags)) + return mapped_flags + + def detect_test_platform(pyb, args): # Run a script to detect various bits of information about the target test instance. output = run_feature_check(pyb, args, "target_info.py") if output.endswith(b"CRASH"): raise ValueError("cannot detect platform: {}".format(output)) - platform, arch = str(output, "ascii").strip().split() + platform, arch, arch_flags, build, thread, float_prec, unicode = ( + str(output, "ascii").strip().split() + ) if arch == "None": arch = None inlineasm_arch = detect_inline_asm_arch(pyb, args) + if thread == "None": + thread = None + float_prec = int(float_prec) + unicode = unicode == "True" + if arch == "rv32imc": + arch_flags = map_rv32_arch_flags(int(arch_flags)) + else: + arch_flags = None args.platform = platform args.arch = arch + args.arch_flags = arch_flags if arch and not args.mpy_cross_flags: args.mpy_cross_flags = "-march=" + arch + if arch_flags: + args.mpy_cross_flags += " -march-flags=" + ",".join(arch_flags) args.inlineasm_arch = inlineasm_arch + args.build = build + args.thread = thread + args.float_prec = float_prec + args.unicode = unicode + # Print the detected information about the target. print("platform={}".format(platform), end="") if arch: print(" arch={}".format(arch), end="") + if arch_flags: + print(" arch_flags={}".format(",".join(arch_flags)), end="") if inlineasm_arch: print(" inlineasm={}".format(inlineasm_arch), end="") - print() - - -def prepare_script_for_target(args, *, script_filename=None, script_text=None, force_plain=False): + if thread: + print(" thread={}".format(thread), end="") + if float_prec: + print(" float={}-bit".format(float_prec), end="") + if unicode: + print(" unicode", end="") + + +def detect_target_wiring_script(pyb, args): + tw_data = b"" + tw_source = None + if args.target_wiring: + # A target_wiring path is explicitly provided, so use that. + tw_source = args.target_wiring + with open(tw_source, "rb") as f: + tw_data = f.read() + elif hasattr(pyb, "exec_raw") and pyb.exec_raw("import target_wiring") == (b"", b""): + # The board already has a target_wiring module available, so use that. + tw_source = "on-device" + else: + port = platform_to_port(args.platform) + build = args.build + tw_board_exact = None + tw_board_partial = None + tw_port = None + for file in os.listdir("target_wiring"): + file_base = file.removesuffix(".py") + if file_base == build: + # A file matching the target's board/build name. + tw_board_exact = file + elif file_base.endswith("x") and build.startswith(file_base.removesuffix("x")): + # A file with a partial match to the target's board/build name. + tw_board_partial = file + elif file_base == port: + # A file matching the target's port. + tw_port = file + tw_source = tw_board_exact or tw_board_partial or tw_port + if tw_source: + with open("target_wiring/" + tw_source, "rb") as f: + tw_data = f.read() + if tw_source: + print(" target_wiring={}".format(tw_source), end="") + pyb.target_wiring_script = tw_data + + +def prepare_script_for_target(args, *, script_text=None, force_plain=False): if force_plain or (not args.via_mpy and args.emit == "bytecode"): - if script_filename is not None: - with open(script_filename, "rb") as f: - script_text = f.read() + # A plain test to run as-is, no processing needed. + pass elif args.via_mpy: tempname = tempfile.mktemp(dir="") mpy_filename = tempname + ".mpy" - if script_filename is None: - script_filename = tempname + ".py" - cleanup_script_filename = True - with open(script_filename, "wb") as f: - f.write(script_text) - else: - cleanup_script_filename = False + script_filename = tempname + ".py" + with open(script_filename, "wb") as f: + f.write(script_text) try: subprocess.check_output( @@ -300,8 +525,7 @@ def prepare_script_for_target(args, *, script_filename=None, script_text=None, f script_text = b"__buf=" + bytes(repr(f.read()), "ascii") + b"\n" rm_f(mpy_filename) - if cleanup_script_filename: - rm_f(script_filename) + rm_f(script_filename) script_text += bytes(injected_import_hook_code, "ascii") else: @@ -312,34 +536,61 @@ def prepare_script_for_target(args, *, script_filename=None, script_text=None, f def run_script_on_remote_target(pyb, args, test_file, is_special): - had_crash, script = prepare_script_for_target( - args, script_filename=test_file, force_plain=is_special - ) + with open(test_file, "rb") as f: + script = f.read() + + # If the test is not a special test, prepend it with a print to indicate that it started. + # If the print does not execute this means that the test did not even start, eg it was + # too large for the target. + prepend_start_test = not is_special + if prepend_start_test: + if script.startswith(b"#"): + script = b"print('START TEST')" + script + else: + script = b"print('START TEST')\n" + script + + had_crash, script = prepare_script_for_target(args, script_text=script, force_plain=is_special) + if had_crash: return True, script try: had_crash = False pyb.enter_raw_repl() - output_mupy = pyb.exec_(script) + if test_file.endswith(tests_requiring_target_wiring) and pyb.target_wiring_script: + pyb.exec_( + "import sys;sys.modules['target_wiring']=__build_class__(lambda:exec(" + + repr(pyb.target_wiring_script) + + "),'target_wiring')" + ) + output_mupy = pyb.exec_(script, timeout=TEST_TIMEOUT) except pyboard.PyboardError as e: had_crash = True if not is_special and e.args[0] == "exception": - output_mupy = e.args[1] + e.args[2] + b"CRASH" + if prepend_start_test and e.args[1] == b"" and b"MemoryError" in e.args[2]: + output_mupy = b"SKIP-TOO-LARGE\n" + else: + output_mupy = e.args[1] + e.args[2] + b"CRASH" else: output_mupy = bytes(e.args[0], "ascii") + b"\nCRASH" + + if prepend_start_test: + if output_mupy.startswith(b"START TEST\r\n"): + output_mupy = output_mupy.removeprefix(b"START TEST\r\n") + else: + had_crash = True + return had_crash, output_mupy -special_tests = [ +tests_with_regex_output = [ base_path(file) for file in ( + # CIRCUITPY-CHANGE: removal and additions "micropython/meminfo.py", "basics/bytes_compare3.py", "basics/builtin_help.py", "thread/thread_exc2.py", - # CIRCUITPY-CHANGE: removal and additions - # REMOVE "esp32/partition_ota.py", "circuitpython/traceback_test.py", "circuitpython/traceback_test_chained.py", ) @@ -350,10 +601,7 @@ def run_micropython(pyb, args, test_file, test_file_abspath, is_special=False): had_crash = False if pyb is None: # run on PC - if ( - test_file_abspath.startswith((base_path("cmdline/"), base_path("feature_check/"))) - or test_file_abspath in special_tests - ): + if test_file_abspath.startswith((base_path("cmdline/"), base_path("feature_check/"))): # special handling for tests of the unix cmdline program is_special = True @@ -392,6 +640,10 @@ def get(required=False): return rv def send_get(what): + # Detect {\x00} pattern and convert to ctrl-key codes. + ctrl_code = lambda m: bytes([int(m.group(1))]) + what = re.sub(rb"{\\x(\d\d)}", ctrl_code, what) + os.write(master, what) return get() @@ -471,17 +723,17 @@ def send_get(what): ) # canonical form for all ports/platforms is to use \n for end-of-line - output_mupy = output_mupy.replace(b"\r\n", b"\n") + output_mupy = normalize_newlines(output_mupy) # don't try to convert the output if we should skip this test - if had_crash or output_mupy in (b"SKIP\n", b"CRASH"): + if had_crash or output_mupy in (b"SKIP\n", b"SKIP-TOO-LARGE\n", b"CRASH"): return output_mupy # skipped special tests will output "SKIP" surrounded by other interpreter debug output if is_special and not had_crash and b"\nSKIP\n" in output_mupy: return b"SKIP\n" - if is_special or test_file_abspath in special_tests: + if is_special or test_file_abspath in tests_with_regex_output: # convert parts of the output that are not stable across runs with open(test_file + ".exp", "rb") as f: lines_exp = [] @@ -603,30 +855,25 @@ def run_script_on_remote_target(self, args, test_file, is_special): def run_tests(pyb, tests, args, result_dir, num_threads=1): - test_count = ThreadSafeCounter() testcase_count = ThreadSafeCounter() - passed_count = ThreadSafeCounter() - failed_tests = ThreadSafeCounter([]) - skipped_tests = ThreadSafeCounter([]) + test_results = ThreadSafeCounter([]) skip_tests = set() skip_native = False skip_int_big = False + skip_int_64 = False skip_bytearray = False skip_set_type = False skip_slice = False skip_async = False skip_const = False skip_revops = False - skip_io_module = False skip_fstring = False skip_endian = False skip_inlineasm = False has_complex = True has_coverage = False - upy_float_precision = 32 - if True: # Even if we run completely different tests in a different directory, # we need to access feature_checks from the same directory as the @@ -642,6 +889,11 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): if output != b"1000000000000000000000000000000000000000000000\n": skip_int_big = True + # Check if 'long long' precision integers are supported, even if arbitrary precision is not + output = run_feature_check(pyb, args, "int_64.py") + if output != b"4611686018427387904\n": + skip_int_64 = True + # Check if bytearray is supported, and skip such tests if it's not output = run_feature_check(pyb, args, "bytearray.py") if output != b"bytearray\n": @@ -672,11 +924,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): if output == b"TypeError\n": skip_revops = True - # Check if io module exists, and skip such tests if it doesn't - output = run_feature_check(pyb, args, "io_module.py") - if output != b"io\n": - skip_io_module = True - # Check if fstring feature is enabled, and skip such tests if it doesn't output = run_feature_check(pyb, args, "fstring.py") if output != b"a=1\n": @@ -690,13 +937,20 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add("inlineasm/thumb/asmbitops.py") skip_tests.add("inlineasm/thumb/asmconst.py") skip_tests.add("inlineasm/thumb/asmdiv.py") + skip_tests.add("inlineasm/thumb/asmit.py") + skip_tests.add("inlineasm/thumb/asmspecialregs.py") + if args.arch not in ("armv7emsp", "armv7emdp"): skip_tests.add("inlineasm/thumb/asmfpaddsub.py") skip_tests.add("inlineasm/thumb/asmfpcmp.py") skip_tests.add("inlineasm/thumb/asmfpldrstr.py") skip_tests.add("inlineasm/thumb/asmfpmuldiv.py") skip_tests.add("inlineasm/thumb/asmfpsqrt.py") - skip_tests.add("inlineasm/thumb/asmit.py") - skip_tests.add("inlineasm/thumb/asmspecialregs.py") + + if args.inlineasm_arch == "rv32": + # Check if @micropython.asm_rv32 supports Zba instructions, and skip such tests if it doesn't + output = run_feature_check(pyb, args, "inlineasm_rv32_zba.py") + if output != b"rv32_zba\n": + skip_tests.add("inlineasm/rv32/asmzba.py") # Check if emacs repl is supported, and skip such tests if it's not t = run_feature_check(pyb, args, "repl_emacs_check.py") @@ -709,11 +963,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add("cmdline/repl_words_move.py") upy_byteorder = run_feature_check(pyb, args, "byteorder.py") - upy_float_precision = run_feature_check(pyb, args, "float.py") - try: - upy_float_precision = int(upy_float_precision) - except ValueError: - upy_float_precision = 0 has_complex = run_feature_check(pyb, args, "complex.py") == b"complex\n" has_coverage = run_feature_check(pyb, args, "coverage.py") == b"coverage\n" cpy_byteorder = subprocess.check_output( @@ -723,24 +972,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_inlineasm = args.inlineasm_arch is None - # These tests don't test slice explicitly but rather use it to perform the test - misc_slice_tests = ( - "builtin_range", - "bytearray1", - "class_super", - "containment", - "errno1", - "fun_str", - "generator1", - "globals_del", - "memoryview1", - "memoryview_gc", - "object1", - "python34", - "string_format_modulo", - "struct_endian", - ) - # Some tests shouldn't be run on GitHub Actions if os.getenv("GITHUB_ACTIONS") == "true": skip_tests.add("thread/stress_schedule.py") # has reliability issues @@ -749,30 +980,31 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): # fails with stack overflow on Debug builds skip_tests.add("misc/sys_settrace_features.py") - if upy_float_precision == 0: - skip_tests.add("extmod/uctypes_le_float.py") - skip_tests.add("extmod/uctypes_native_float.py") - skip_tests.add("extmod/uctypes_sizeof_float.py") - skip_tests.add("extmod/json_dumps_float.py") - skip_tests.add("extmod/json_loads_float.py") - skip_tests.add("extmod/random_extra_float.py") - skip_tests.add("misc/rge_sm.py") - if upy_float_precision < 32: + if args.float_prec == 0: + skip_tests.update(tests_requiring_float) + if args.float_prec < 32: skip_tests.add( "float/float2int_intbig.py" ) # requires fp32, there's float2int_fp30_intbig.py instead skip_tests.add( - "float/string_format.py" - ) # requires fp32, there's string_format_fp30.py instead + "float/float_struct_e.py" + ) # requires fp32, there's float_struct_e_fp30.py instead skip_tests.add("float/bytes_construct.py") # requires fp32 skip_tests.add("float/bytearray_construct.py") # requires fp32 skip_tests.add("float/float_format_ints_power10.py") # requires fp32 - if upy_float_precision < 64: + if args.float_prec < 64: skip_tests.add("float/float_divmod.py") # tested by float/float_divmod_relaxed.py instead skip_tests.add("float/float2int_doubleprec_intbig.py") + skip_tests.add("float/float_struct_e_doubleprec.py") skip_tests.add("float/float_format_ints_doubleprec.py") skip_tests.add("float/float_parse_doubleprec.py") + if not args.unicode: + skip_tests.add("extmod/json_loads.py") # tests loading a utf-8 character + + if skip_slice: + skip_tests.update(tests_requiring_slice) + if not has_complex: skip_tests.add("float/complex1.py") skip_tests.add("float/complex1_intbig.py") @@ -788,8 +1020,8 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): skip_tests.add("cmdline/repl_sys_ps1_ps2.py") skip_tests.add("extmod/ssl_poll.py") - # Skip thread mutation tests on targets that don't have the GIL. - if args.platform in PC_PLATFORMS + ("rp2",): + # Skip thread mutation tests on targets that have unsafe threading behaviour. + if args.thread == "unsafe": for t in tests: if t.startswith("thread/mutate_"): skip_tests.add(t) @@ -798,6 +1030,15 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): if args.platform not in PC_PLATFORMS: skip_tests.add("basics/exception_chain.py") # warning is not printed skip_tests.add("micropython/meminfo.py") # output is very different to PC output + skip_tests.add("unicode/file1.py") # requires local file access + skip_tests.add("unicode/file2.py") # requires local file access + skip_tests.add("unicode/file_invalid.py") # requires local file access + + # Skip certain tests when going via a .mpy file. + skip_tests.update(via_mpy_tests_to_skip.get(args.via_mpy, ())) + + # Skip emitter-specific tests. + skip_tests.update(emitter_tests_to_skip.get(args.emit, ())) # Skip platform-specific tests. skip_tests.update(platform_tests_to_skip.get(args.platform, ())) @@ -812,49 +1053,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1): # Works but CPython uses '\' path separator skip_tests.add("import/import_file.py") - # Some tests are known to fail with native emitter - # Remove them from the below when they work - if args.emit == "native": - skip_tests.add("basics/gen_yield_from_close.py") # require raise_varargs - skip_tests.update( - {"basics/%s.py" % t for t in "try_reraise try_reraise2".split()} - ) # require raise_varargs - skip_tests.add("basics/annotate_var.py") # requires checking for unbound local - skip_tests.add("basics/del_deref.py") # requires checking for unbound local - skip_tests.add("basics/del_local.py") # requires checking for unbound local - skip_tests.add("basics/exception_chain.py") # raise from is not supported - skip_tests.add("basics/scope_implicit.py") # requires checking for unbound local - skip_tests.add("basics/sys_tracebacklimit.py") # requires traceback info - skip_tests.add("basics/try_finally_return2.py") # requires raise_varargs - skip_tests.add("basics/unboundlocal.py") # requires checking for unbound local - skip_tests.add("misc/features.py") # requires raise_varargs - # CIRCUITPY-CHANGE - skip_tests.update( - ( - "basics/chained_exception.py", - "circuitpython/traceback_test.py", - "circuitpython/traceback_test_chained.py", - ) - ) # because native doesn't have proper traceback info - skip_tests.add( - "misc/print_exception.py" - ) # because native doesn't have proper traceback info - skip_tests.add("misc/sys_exc_info.py") # sys.exc_info() is not supported for native - skip_tests.add("misc/sys_settrace_features.py") # sys.settrace() not supported - skip_tests.add("misc/sys_settrace_generator.py") # sys.settrace() not supported - skip_tests.add("misc/sys_settrace_loop.py") # sys.settrace() not supported - skip_tests.add( - "micropython/emg_exc.py" - ) # because native doesn't have proper traceback info - skip_tests.add( - "micropython/heapalloc_traceback.py" - ) # because native doesn't have proper traceback info - skip_tests.add( - "micropython/opt_level_lineno.py" - ) # native doesn't have proper traceback info - skip_tests.add("micropython/schedule.py") # native code doesn't check pending events - skip_tests.add("stress/bytecode_limit.py") # bytecode specific test - def run_one_test(test_file): test_file = test_file.replace("\\", "/") test_file_abspath = os.path.abspath(test_file).replace("\\", "/") @@ -870,19 +1068,19 @@ def run_one_test(test_file): test_basename = test_file.replace("..", "_").replace("./", "").replace("/", "_") test_name = os.path.splitext(os.path.basename(test_file))[0] - is_native = ( - test_name.startswith("native_") - or test_name.startswith("viper_") - or args.emit == "native" - ) + is_native = test_name.startswith("native_") or test_name.startswith("viper_") is_endian = test_name.endswith("_endian") - is_int_big = test_name.startswith("int_big") or test_name.endswith("_intbig") + is_int_big = ( + test_name.startswith("int_big") + or test_name.endswith("_intbig") + or test_name.startswith("ffi_int") # these tests contain large integer literals + ) + is_int_64 = test_name.startswith("int_64") or test_name.endswith("_int64") is_bytearray = test_name.startswith("bytearray") or test_name.endswith("_bytearray") is_set_type = test_name.startswith(("set_", "frozenset")) or test_name.endswith("_set") - is_slice = test_name.find("slice") != -1 or test_name in misc_slice_tests - is_async = test_name.startswith(("async_", "asyncio_")) + is_slice = test_name.find("slice") != -1 + is_async = test_name.startswith(("async_", "asyncio_")) or test_name.endswith("_async") is_const = test_name.startswith("const") - is_io_module = test_name.startswith("io_") is_fstring = test_name.startswith("string_fstring") is_inlineasm = test_name.startswith("asm") @@ -890,19 +1088,19 @@ def run_one_test(test_file): skip_it |= skip_native and is_native skip_it |= skip_endian and is_endian skip_it |= skip_int_big and is_int_big + skip_it |= skip_int_64 and is_int_64 skip_it |= skip_bytearray and is_bytearray skip_it |= skip_set_type and is_set_type skip_it |= skip_slice and is_slice skip_it |= skip_async and is_async skip_it |= skip_const and is_const skip_it |= skip_revops and "reverse_op" in test_name - skip_it |= skip_io_module and is_io_module skip_it |= skip_fstring and is_fstring skip_it |= skip_inlineasm and is_inlineasm if skip_it: print("skip ", test_file) - skipped_tests.append(test_name) + test_results.append((test_file, "skip", "")) return # Run the test on the MicroPython target. @@ -917,7 +1115,11 @@ def run_one_test(test_file): # start-up code (eg boot.py) when preparing to run the next test. pyb.read_until(1, b"raw REPL; CTRL-B to exit\r\n") print("skip ", test_file) - skipped_tests.append(test_name) + test_results.append((test_file, "skip", "")) + return + elif output_mupy == b"SKIP-TOO-LARGE\n": + print("lrge ", test_file) + test_results.append((test_file, "skip", "too large")) return # Look at the output of the test to see if unittest was used. @@ -954,7 +1156,11 @@ def run_one_test(test_file): # Expected output is result of running unittest. output_expected = None else: - test_file_expected = test_file + ".exp" + # Prefer emitter-specific expected output. + test_file_expected = test_file + "." + args.emit + ".exp" + if not os.path.isfile(test_file_expected): + # Fall back to generic expected output. + test_file_expected = test_file + ".exp" if os.path.isfile(test_file_expected): # Expected output given by a file, so read that in. with open(test_file_expected, "rb") as f: @@ -1012,7 +1218,7 @@ def run_one_test(test_file): # Print test summary, update counters, and save .exp/.out files if needed. if test_passed: print("pass ", test_file, extra_info) - passed_count.increment() + test_results.append((test_file, "pass", "")) rm_f(filename_expected) rm_f(filename_mupy) else: @@ -1024,9 +1230,7 @@ def run_one_test(test_file): rm_f(filename_expected) # in case left over from previous failed run with open(filename_mupy, "wb") as f: f.write(output_mupy) - failed_tests.append((test_name, test_file)) - - test_count.increment() + test_results.append((test_file, "fail", "")) # Print a note if this looks like it might have been a misfired unittest if not uses_unittest and not test_passed: @@ -1053,17 +1257,49 @@ def run_one_test(test_file): print(line) sys.exit(1) - print( - "{} tests performed ({} individual testcases)".format( - test_count.value, testcase_count.value - ) + # Return test results. + return test_results.value, testcase_count.value + + +# Print a summary of the results and save them to a JSON file. +# Returns True if everything succeeded, False otherwise. +def create_test_report(args, test_results, testcase_count=None): + passed_tests = list(r for r in test_results if r[1] == "pass") + skipped_tests = list(r for r in test_results if r[1] == "skip" and r[2] != "too large") + skipped_tests_too_large = list( + r for r in test_results if r[1] == "skip" and r[2] == "too large" ) - print("{} tests passed".format(passed_count.value)) + failed_tests = list(r for r in test_results if r[1] == "fail") + + num_tests_performed = len(passed_tests) + len(failed_tests) + + testcase_count_info = "" + if testcase_count is not None: + testcase_count_info = " ({} individual testcases)".format(testcase_count) + print("{} tests performed{}".format(num_tests_performed, testcase_count_info)) + + print("{} tests passed".format(len(passed_tests))) - skipped_tests = sorted(skipped_tests.value) if len(skipped_tests) > 0: - print("{} tests skipped: {}".format(len(skipped_tests), " ".join(skipped_tests))) - failed_tests = sorted(failed_tests.value) + print( + "{} tests skipped: {}".format( + len(skipped_tests), " ".join(test[0] for test in skipped_tests) + ) + ) + + if len(skipped_tests_too_large) > 0: + print( + "{} tests skipped because they are too large: {}".format( + len(skipped_tests_too_large), " ".join(test[0] for test in skipped_tests_too_large) + ) + ) + + if len(failed_tests) > 0: + print( + "{} tests failed: {}".format( + len(failed_tests), " ".join(test[0] for test in failed_tests) + ) + ) # Serialize regex added by append_filter. def to_json(obj): @@ -1071,23 +1307,22 @@ def to_json(obj): return obj.pattern return obj - with open(os.path.join(result_dir, RESULTS_FILE), "w") as f: + with open(os.path.join(args.result_dir, RESULTS_FILE), "w") as f: json.dump( - {"args": vars(args), "failed_tests": [test[1] for test in failed_tests]}, + { + # The arguments passed on the command-line. + "args": vars(args), + # A list of all results of the form [(test, result, reason), ...]. + "results": list(test for test in test_results), + # A list of failed tests. This is deprecated, use the "results" above instead. + "failed_tests": [test[0] for test in failed_tests], + }, f, default=to_json, ) - if len(failed_tests) > 0: - print( - "{} tests failed: {}".format( - len(failed_tests), " ".join(test[0] for test in failed_tests) - ) - ) - return False - - # all tests succeeded - return True + # Return True only if all tests succeeded. + return len(failed_tests) == 0 class append_filter(argparse.Action): @@ -1104,27 +1339,11 @@ def __call__(self, parser, args, value, option): args.filters.append((option, re.compile(value))) -def main(): - cmd_parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description="""Run and manage tests for MicroPython. - +test_instance_description = """\ By default the tests are run against the unix port of MicroPython. To run it against something else, use the -t option. See below for details. - -Tests are discovered by scanning test directories for .py files or using the -specified test files. If test files nor directories are specified, the script -expects to be ran in the tests directory (where this file is located) and the -builtin tests suitable for the target platform are ran. - -When running tests, run-tests.py compares the MicroPython output of the test with the output -produced by running the test through CPython unless a .exp file is found, in which -case it is used as comparison. - -If a test fails, run-tests.py produces a pair of .out and .exp files in the result -directory with the MicroPython output and the expectations, respectively. -""", - epilog="""\ +""" +test_instance_epilog = """\ The -t option accepts the following for the test instance: - unix - use the unix port of MicroPython, specified by the MICROPY_MICROPYTHON environment variable (which defaults to the standard variant of either the unix @@ -1140,7 +1359,35 @@ def main(): - execpty: - execute a command and attach to the printed /dev/pts/ device - ... - connect to the given IPv4 address - anything else specifies a serial port +""" + +test_directory_description = """\ +Tests are discovered by scanning test directories for .py files or using the +specified test files. If test files nor directories are specified, the script +expects to be ran in the tests directory (where this file is located) and the +builtin tests suitable for the target platform are ran. +""" + +def main(): + global injected_import_hook_code + + cmd_parser = argparse.ArgumentParser( + formatter_class=argparse.RawDescriptionHelpFormatter, + description=f"""Run and manage tests for MicroPython. + +{test_instance_description} +{test_directory_description} + +When running tests, run-tests.py compares the MicroPython output of the test with the output +produced by running the test through CPython unless a .exp file is found (or a +.native.exp file when using the native emitter), in which case it is used as comparison. + +If a test fails, run-tests.py produces a pair of .out and .exp files in the result +directory with the MicroPython output and the expectations, respectively. +""", + epilog=f"""\ +{test_instance_epilog} Options -i and -e can be multiple and processed in the order given. Regex "search" (vs "match") operation is used. An action (include/exclude) of the last matching regex is used: @@ -1214,8 +1461,25 @@ def main(): action="store_true", help="re-run only the failed tests", ) + cmd_parser.add_argument( + "--begin", + metavar="PROLOGUE", + default=None, + help="prologue python file to execute before module import", + ) + cmd_parser.add_argument( + "--target-wiring", + default=None, + help="force the given script to be used as target_wiring.py", + ) args = cmd_parser.parse_args() + prologue = "" + if args.begin: + with open(args.begin, "rt") as source: + prologue = source.read() + injected_import_hook_code = injected_import_hook_code.replace("{import_prologue}", prologue) + if args.print_failures: for out in glob(os.path.join(args.result_dir, "*.out")): testbase = out[:-4] @@ -1256,7 +1520,7 @@ def main(): results_file = os.path.join(args.result_dir, RESULTS_FILE) if os.path.exists(results_file): with open(results_file, "r") as f: - tests = json.load(f)["failed_tests"] + tests = list(test[0] for test in json.load(f)["results"] if test[1] == "fail") else: tests = [] elif len(args.files) == 0: @@ -1267,47 +1531,27 @@ def main(): if args.test_dirs is None: test_dirs = ( "basics", - "circuitpython", # CIRCUITPY-CHANGE "micropython", "misc", "extmod", + "stress", ) if args.inlineasm_arch is not None: test_dirs += ("inlineasm/{}".format(args.inlineasm_arch),) - if args.platform == "pyboard": - # run pyboard tests - test_dirs += ("float", "stress", "ports/stm32") - elif args.platform == "mimxrt": - test_dirs += ("float", "stress") - elif args.platform == "renesas-ra": - test_dirs += ("float", "ports/renesas-ra") - elif args.platform == "rp2": - test_dirs += ("float", "stress", "thread", "ports/rp2") - elif args.platform == "esp32": - test_dirs += ("float", "stress", "thread") - elif args.platform in ("esp8266", "minimal", "samd", "nrf"): + if args.thread is not None: + test_dirs += ("thread",) + if args.float_prec > 0: test_dirs += ("float",) - elif args.platform == "WiPy": - # run WiPy tests - test_dirs += ("ports/cc3200",) - elif args.platform in PC_PLATFORMS: + if args.unicode: + test_dirs += ("unicode",) + port_specific_test_dir = "ports/{}".format(platform_to_port(args.platform)) + if os.path.isdir(port_specific_test_dir): + test_dirs += (port_specific_test_dir,) + if args.platform in PC_PLATFORMS: # run PC tests - test_dirs += ( - "float", - "import", - "io", - "stress", - "unicode", - "cmdline", - "ports/unix", - ) - elif args.platform == "qemu": - test_dirs += ( - "float", - "ports/qemu", - ) - elif args.platform == "webassembly": - test_dirs += ("float", "ports/webassembly") + test_dirs += ("import",) + if args.build != "minimal": + test_dirs += ("cmdline", "io") else: # run tests from these directories test_dirs = args.test_dirs @@ -1322,6 +1566,13 @@ def main(): # tests explicitly given tests = args.files + # If any tests need it, prepare the target_wiring script for the target. + if pyb and any(test.endswith(tests_requiring_target_wiring) for test in tests): + detect_target_wiring_script(pyb, args) + + # End the target information line. + print() + if not args.keep_path: # Clear search path to make sure tests use only builtin modules, those in # extmod, and a path to unittest in case it's needed. @@ -1342,7 +1593,8 @@ def main(): try: os.makedirs(args.result_dir, exist_ok=True) - res = run_tests(pyb, tests, args, args.result_dir, args.jobs) + test_results, testcase_count = run_tests(pyb, tests, args, args.result_dir, args.jobs) + res = create_test_report(args, test_results, testcase_count) finally: if pyb: pyb.close() diff --git a/tests/serial_test.py b/tests/serial_test.py new file mode 100755 index 00000000000..3b5940d91a9 --- /dev/null +++ b/tests/serial_test.py @@ -0,0 +1,338 @@ +#!/usr/bin/env python +# +# Performance and reliability test for serial port communication. +# +# Basic usage: +# serial_test.py [-t serial-device] +# +# The `serial-device` will default to /dev/ttyACM0. + +import argparse +import random +import serial +import sys +import time + +run_tests_module = __import__("run-tests") + +echo_test_script = """ +import sys +bytes_min=%u +bytes_max=%u +repeat=%u +b=memoryview(bytearray(bytes_max)) +for n in range(bytes_min,bytes_max+1): + for _ in range(repeat): + n2 = sys.stdin.readinto(b[:n]) + sys.stdout.write(b[:n2]) +""" + +read_test_script = """ +bin = True +try: + wr=__import__("pyb").USB_VCP(0).send +except: + import sys + if hasattr(sys.stdout,'buffer'): + wr=sys.stdout.buffer.write + else: + wr=sys.stdout.write + bin = False +b=bytearray(%u) +if bin: + wr('BIN') + for i in range(len(b)): + b[i] = i & 0xff +else: + wr('TXT') + for i in range(len(b)): + b[i] = 0x20 + (i & 0x3f) +for _ in range(%d): + wr(b) +""" + + +write_test_script_verified = """ +import sys +try: + rd=__import__("pyb").USB_VCP(0).recv +except: + rd=sys.stdin.readinto +b=bytearray(%u) +for _ in range(%u): + n = rd(b) + fail = 0 + for i in range(n): + if b[i] != 32 + (i & 0x3f): + fail += 1 + if fail: + sys.stdout.write(b'ER%%05u' %% fail) + else: + sys.stdout.write(b'OK%%05u' %% n) +""" + +write_test_script_unverified = """ +import sys +try: + rd=__import__("pyb").USB_VCP(0).recv +except: + rd=sys.stdin.readinto +b=bytearray(%u) +for _ in range(%u): + n = rd(b) + if n != len(b): + sys.stdout.write(b'ER%%05u' %% n) + else: + sys.stdout.write(b'OK%%05u' %% n) +""" + + +class TestError(Exception): + pass + + +def drain_input(ser): + time.sleep(0.1) + while ser.inWaiting() > 0: + data = ser.read(ser.inWaiting()) + time.sleep(0.1) + + +def send_script(ser, script): + ser.write(b"\x03\x01\x04") # break, raw-repl, soft-reboot + drain_input(ser) + chunk_size = 32 + for i in range(0, len(script), chunk_size): + ser.write(script[i : i + chunk_size]) + time.sleep(0.01) + ser.write(b"\x04") # eof + ser.flush() + response = ser.read(2) + if response != b"OK": + response += ser.read(ser.inWaiting()) + raise TestError("could not send script", response) + + +def echo_test(ser_repl, ser_data): + global test_passed + + # Make the test data deterministic. + random.seed(0) + + # Set parameters for the test. + # Go just a bit above the size of a USB high-speed packet. + bytes_min = 1 + bytes_max = 520 + num_repeat = 1 + + # Load and run the write_test_script. + script = bytes(echo_test_script % (bytes_min, bytes_max, num_repeat), "ascii") + send_script(ser_repl, script) + + # A selection of printable bytes for echo data. + printable_bytes = list(range(48, 58)) + list(range(65, 91)) + list(range(97, 123)) + + # Write data to the device and record the echo'd data. + # Use a different selection of random printable characters for each + # echo, to make it easier to debug when the echo doesn't match. + num_errors = 0 + echo_results = [] + for num_bytes in range(bytes_min, bytes_max + 1): + print(f"DATA ECHO: {num_bytes} / {bytes_max}", end="\r") + for repeat in range(num_repeat): + rand_bytes = list(random.choice(printable_bytes) for _ in range(8)) + buf = bytes(random.choice(rand_bytes) for _ in range(num_bytes)) + ser_data.write(buf) + buf2 = ser_data.read(len(buf)) + match = buf == buf2 + num_errors += not match + echo_results.append((match, buf, buf2)) + if num_errors > 8: + # Stop early if there are too many errors. + break + ser_repl.write(b"\x03") + + # Print results. + if all(match for match, _, _ in echo_results): + print("DATA ECHO: OK for {}-{} bytes at a time".format(bytes_min, bytes_max)) + else: + test_passed = False + print("DATA ECHO: FAIL ") + for match, buf, buf2 in echo_results: + print(" sent", len(buf), buf) + if match: + print(" echo match") + else: + print(" echo", len(buf), buf2) + + +def read_test(ser_repl, ser_data, bufsize, nbuf): + global test_passed + + assert bufsize % 256 == 0 # for verify to work + + # how long to wait for data from device + # (if UART TX is also enabled then it can take 1.4s to send + # out a 16KB butter at 115200bps) + READ_TIMEOUT_S = 2 + + # Load and run the read_test_script. + script = bytes(read_test_script % (bufsize, nbuf), "ascii") + send_script(ser_repl, script) + + # Read from the device the type of data that it will send (BIN or TXT). + data_type = ser_data.read(3) + + # Read data from the device, check it is correct, and measure throughput. + n = 0 + last_byte = None + t_start = time.time() + remain = nbuf * bufsize + total_data = bytearray(remain) + while remain: + t0 = time.monotonic_ns() + while ser_data.inWaiting() == 0: + if time.monotonic_ns() - t0 > READ_TIMEOUT_S * 1e9: + # timeout waiting for data from device + break + time.sleep(0.0001) + if not ser_data.inWaiting(): + test_passed = False + print("ERROR: timeout waiting for data") + print(total_data[:n]) + return 0 + to_read = min(ser_data.inWaiting(), remain) + data = ser_data.read(to_read) + remain -= len(data) + print(f"{n} / {nbuf * bufsize}", end="\r") + total_data[n : n + len(data)] = data + n += len(data) + t_end = time.time() + for i in range(0, len(total_data)): + if data_type == b"BIN": + wanted = i & 0xFF + else: + wanted = 0x20 + (i & 0x3F) + if total_data[i] != wanted: + test_passed = False + print("ERROR: data mismatch:", i, wanted, total_data[i]) + ser_repl.write(b"\x03") # break + t = t_end - t_start + + # Print results. + print( + "DATA IN: bufsize=%u, read %u bytes in %.2f msec = %.2f kibytes/sec = %.2f MBits/sec" + % (bufsize, n, t * 1000, n / 1024 / t, n * 8 / 1000000 / t) + ) + + return n / t + + +def write_test(ser_repl, ser_data, bufsize, nbuf, verified): + global test_passed + + # Load and run the write_test_script. + if verified: + script = write_test_script_verified + else: + script = write_test_script_unverified + script = bytes(script % (bufsize, nbuf), "ascii") + send_script(ser_repl, script) + drain_input(ser_repl) + + # Write data to the device, check it is correct, and measure throughput. + n = 0 + t_start = time.time() + buf = bytearray(bufsize) + for i in range(len(buf)): + buf[i] = 32 + (i & 0x3F) # don't want to send ctrl chars! + for i in range(nbuf): + ser_data.write(buf) + n += len(buf) + print(f"{n} / {nbuf * bufsize}", end="\r") + response = ser_repl.read(7) + if response != b"OK%05u" % bufsize: + test_passed = False + print("ERROR: bad response, expecting OK%05u, got %r" % (bufsize, response)) + t_end = time.time() + ser_repl.write(b"\x03") # break + t = t_end - t_start + + # Print results. + print( + "DATA OUT: verify=%d, bufsize=%u, wrote %u bytes in %.2f msec = %.2f kibytes/sec = %.2f MBits/sec" + % (verified, bufsize, n, t * 1000, n / 1024 / t, n * 8 / 1000000 / t) + ) + + return n / t + + +def do_test(dev_repl, dev_data=None, time_per_subtest=1): + if dev_data is None: + print("REPL and data on", dev_repl) + ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=1) + ser_data = ser_repl + else: + print("REPL on", dev_repl) + print("data on", dev_data) + ser_repl = serial.Serial(dev_repl, baudrate=115200, timeout=1) + ser_data = serial.Serial(dev_data, baudrate=115200, timeout=1) + + # Do echo test first, and abort if it doesn't pass. + echo_test(ser_repl, ser_data) + if not test_passed: + return + + # Do read and write throughput test. + for test_func, test_args, bufsize in ( + (read_test, (), 256), + (write_test, (True,), 128), + (write_test, (False,), 128), + ): + nbuf = 128 + while bufsize <= 16384: + rate = test_func(ser_repl, ser_data, bufsize, nbuf, *test_args) + bufsize *= 2 + if rate: + # Adjust the amount of data based on the rate, to keep each subtest + # at around time_per_subtest seconds long. + nbuf = max(min(128, int(rate * time_per_subtest / bufsize)), 1) + + ser_repl.close() + ser_data.close() + + +def main(): + global test_passed + + cmd_parser = argparse.ArgumentParser( + description="Test performance and reliability of serial port communication.", + epilog=run_tests_module.test_instance_epilog, + formatter_class=argparse.RawTextHelpFormatter, + ) + cmd_parser.add_argument( + "-t", + "--test-instance", + default="a0", + help="MicroPython instance to test", + ) + cmd_parser.add_argument( + "--time-per-subtest", default="1", help="approximate time to take per subtest (in seconds)" + ) + args = cmd_parser.parse_args() + + dev_repl = run_tests_module.convert_device_shortcut_to_real_device(args.test_instance) + + test_passed = True + try: + do_test(dev_repl, None, float(args.time_per_subtest)) + except TestError as er: + test_passed = False + print("ERROR:", er) + + if not test_passed: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/tests/stress/bytecode_limit.py b/tests/stress/bytecode_limit.py index 948d7668da5..0a72b66fa05 100644 --- a/tests/stress/bytecode_limit.py +++ b/tests/stress/bytecode_limit.py @@ -1,19 +1,29 @@ # Test the limits of bytecode generation. +import sys + +# Tune the test parameters based on the target's bytecode generator. +if hasattr(sys.implementation, "_mpy"): + # Target can load .mpy files so generated bytecode uses 1 byte per qstr. + number_of_body_copies = (433, 432, 431, 399) +else: + # Target can't load .mpy files so generated bytecode uses 2 bytes per qstr. + number_of_body_copies = (401, 400, 399, 398) + body = " with f()()() as a:\n try:\n f()()()\n except Exception:\n pass\n" # Test overflow of jump offset. # Print results at the end in case an intermediate value of n fails with MemoryError. results = [] -for n in (433, 432, 431, 430): +for n in number_of_body_copies: try: exec("cond = 0\nif cond:\n" + body * n + "else:\n print('cond false')\n") - results.append((n, "ok")) + results.append("ok") except MemoryError: print("SKIP") raise SystemExit - except RuntimeError: - results.append((n, "RuntimeError")) + except RuntimeError as er: + results.append(repr(er)) print(results) # Test changing size of code info (source line/bytecode mapping) due to changing diff --git a/tests/stress/bytecode_limit.py.exp b/tests/stress/bytecode_limit.py.exp index cda52b1b973..50511665f00 100644 --- a/tests/stress/bytecode_limit.py.exp +++ b/tests/stress/bytecode_limit.py.exp @@ -1,4 +1,4 @@ cond false cond false -[(433, 'RuntimeError'), (432, 'RuntimeError'), (431, 'ok'), (430, 'ok')] +["RuntimeError('bytecode overflow',)", "RuntimeError('bytecode overflow',)", 'ok', 'ok'] [123] diff --git a/tests/stress/dict_copy.py b/tests/stress/dict_copy.py index 73d3a5b51d6..f9b742e20f7 100644 --- a/tests/stress/dict_copy.py +++ b/tests/stress/dict_copy.py @@ -1,6 +1,11 @@ # copying a large dictionary -a = {i: 2 * i for i in range(1000)} +try: + a = {i: 2 * i for i in range(1000)} +except MemoryError: + print("SKIP") + raise SystemExit + b = a.copy() for i in range(1000): print(i, b[i]) diff --git a/tests/stress/dict_create.py b/tests/stress/dict_create.py index e9db40a8e6c..91a83a12f9d 100644 --- a/tests/stress/dict_create.py +++ b/tests/stress/dict_create.py @@ -3,6 +3,10 @@ d = {} x = 1 while x < 1000: - d[x] = x + try: + d[x] = x + except MemoryError: + print("SKIP") + raise SystemExit x += 1 print(d[500]) diff --git a/tests/stress/fun_call_limit.py b/tests/stress/fun_call_limit.py index b802aadd558..69f8aa5aec4 100644 --- a/tests/stress/fun_call_limit.py +++ b/tests/stress/fun_call_limit.py @@ -16,14 +16,16 @@ def test(n): # If the port has at least 32-bits then this test should pass. -print(test(29)) +print(test(28)) # This test should fail on all ports (overflows a small int). print(test(70)) -# Check that there is a correct transition to the limit of too many args before *args. +# 28 is the biggest number that will pass on a 32-bit port using object +# representation B, which has 1<<28 still fitting in a positive small int. reached_limit = False -for i in range(30, 70): +any_test_succeeded = False +for i in range(28, 70): result = test(i) if reached_limit: if result != "SyntaxError": @@ -34,3 +36,5 @@ def test(n): else: if result != i + 4: print("FAIL") + any_test_succeeded = True +assert any_test_succeeded # At least one iteration must have passed diff --git a/tests/stress/fun_call_limit.py.exp b/tests/stress/fun_call_limit.py.exp index 53d2b280430..491abbfa8be 100644 --- a/tests/stress/fun_call_limit.py.exp +++ b/tests/stress/fun_call_limit.py.exp @@ -1,2 +1,2 @@ -33 +32 SyntaxError diff --git a/tests/stress/qstr_limit.py b/tests/stress/qstr_limit.py index 08b10a039f5..c7bd437f3ad 100644 --- a/tests/stress/qstr_limit.py +++ b/tests/stress/qstr_limit.py @@ -12,8 +12,8 @@ def make_id(n, base="a"): var = make_id(l) try: exec(var + "=1", g) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print("RuntimeError", er, l) continue print(var in g) @@ -26,16 +26,16 @@ def f(**k): for l in range(254, 259): try: exec("f({}=1)".format(make_id(l))) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print("RuntimeError", er, l) # type construction for l in range(254, 259): id = make_id(l) try: - print(type(id, (), {}).__name__) - except RuntimeError: - print("RuntimeError", l) + print(type(id, (), {})) + except RuntimeError as er: + print("RuntimeError", er, l) # hasattr, setattr, getattr @@ -48,28 +48,20 @@ class A: a = A() try: setattr(a, id, 123) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print("RuntimeError", er, l) try: print(hasattr(a, id), getattr(a, id)) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print("RuntimeError", er, l) # format with keys for l in range(254, 259): id = make_id(l) try: print(("{" + id + "}").format(**{id: l})) - except RuntimeError: - print("RuntimeError", l) - -# modulo format with keys -for l in range(254, 259): - id = make_id(l) - try: - print(("%(" + id + ")d") % {id: l}) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print("RuntimeError", er, l) # import module # (different OS's have different results so only run those that are consistent) @@ -78,8 +70,8 @@ class A: __import__(make_id(l)) except ImportError: print("ok", l) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print("RuntimeError", er, l) # import package for l in (100, 101, 102, 128, 129): @@ -87,5 +79,5 @@ class A: exec("import " + make_id(l) + "." + make_id(l, "A")) except ImportError: print("ok", l) - except RuntimeError: - print("RuntimeError", l) + except RuntimeError as er: + print("RuntimeError", er, l) diff --git a/tests/stress/qstr_limit.py.exp b/tests/stress/qstr_limit.py.exp index 455761bc71e..2349adf220f 100644 --- a/tests/stress/qstr_limit.py.exp +++ b/tests/stress/qstr_limit.py.exp @@ -1,43 +1,38 @@ True True -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 {'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst': 1} {'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu': 1} -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 -abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrst -abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstu -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 + + +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 True 123 True 123 -RuntimeError 256 -RuntimeError 256 -RuntimeError 257 -RuntimeError 257 -RuntimeError 258 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 257 +RuntimeError name too long 258 +RuntimeError name too long 258 254 255 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 -254 -255 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 ok 100 ok 101 -RuntimeError 256 -RuntimeError 257 -RuntimeError 258 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 ok 100 ok 101 ok 102 -RuntimeError 128 -RuntimeError 129 +RuntimeError name too long 128 +RuntimeError name too long 129 diff --git a/tests/stress/qstr_limit_str_modulo.py b/tests/stress/qstr_limit_str_modulo.py new file mode 100644 index 00000000000..90b9f4364ec --- /dev/null +++ b/tests/stress/qstr_limit_str_modulo.py @@ -0,0 +1,21 @@ +# Test interning qstrs that go over the qstr length limit (255 bytes in default configuration). +# The tests here are specifically for str formatting with %. + +try: + "" % () +except TypeError: + print("SKIP") + raise SystemExit + + +def make_id(n, base="a"): + return "".join(chr(ord(base) + i % 26) for i in range(n)) + + +# modulo format with keys +for l in range(254, 259): + id = make_id(l) + try: + print(("%(" + id + ")d") % {id: l}) + except RuntimeError as er: + print("RuntimeError", er, l) diff --git a/tests/stress/qstr_limit_str_modulo.py.exp b/tests/stress/qstr_limit_str_modulo.py.exp new file mode 100644 index 00000000000..3632c85bffe --- /dev/null +++ b/tests/stress/qstr_limit_str_modulo.py.exp @@ -0,0 +1,5 @@ +254 +255 +RuntimeError name too long 256 +RuntimeError name too long 257 +RuntimeError name too long 258 diff --git a/tests/stress/recursive_iternext.py b/tests/stress/recursive_iternext.py index bbc389e7262..c737f1e36d7 100644 --- a/tests/stress/recursive_iternext.py +++ b/tests/stress/recursive_iternext.py @@ -1,4 +1,8 @@ # This tests that recursion with iternext doesn't lead to segfault. +# +# This test segfaults CPython, but that's not a bug as CPython doesn't enforce +# limits on C recursion - see +# https://github.com/python/cpython/issues/58218#issuecomment-1093570209 try: enumerate filter @@ -9,49 +13,25 @@ print("SKIP") raise SystemExit -# We need to pick an N that is large enough to hit the recursion -# limit, but not too large that we run out of heap memory. -try: - # large stack/heap, eg unix - [0] * 80000 - N = 5000 -except: - try: - # medium, eg pyboard - [0] * 10000 - N = 1000 - except: - # small, eg esp8266 - N = 100 - -try: - x = (1, 2) - for i in range(N): - x = enumerate(x) - tuple(x) -except RuntimeError: - print("RuntimeError") -try: +# Progressively build a bigger nested iterator structure (10 at a time for speed), +# and then try to evaluate it via tuple(x) which makes deep recursive function calls. +# +# Eventually this should raise a RuntimeError as MicroPython runs out of stack. +# It shouldn't ever raise a MemoryError, if it does then somehow MicroPython has +# run out of heap (for the nested structure) before running out of stack. +def recurse_iternext(nested_fn): x = (1, 2) - for i in range(N): - x = filter(None, x) - tuple(x) -except RuntimeError: - print("RuntimeError") + while True: + for _ in range(10): + x = nested_fn(x) + try: + tuple(x) + except RuntimeError: + print("RuntimeError") + break -try: - x = (1, 2) - for i in range(N): - x = map(max, x, ()) - tuple(x) -except RuntimeError: - print("RuntimeError") -try: - x = (1, 2) - for i in range(N): - x = zip(x) - tuple(x) -except RuntimeError: - print("RuntimeError") +# Test on various nested iterator structures +for nested_fn in [enumerate, lambda x: filter(None, x), lambda x: map(max, x, ()), zip]: + recurse_iternext(nested_fn) diff --git a/tests/target_wiring/EK_RA6M2.py b/tests/target_wiring/EK_RA6M2.py new file mode 100644 index 00000000000..7d4a8cbbd64 --- /dev/null +++ b/tests/target_wiring/EK_RA6M2.py @@ -0,0 +1,8 @@ +# Target wiring for EK_RA6M2. +# +# Connect: +# - P601 to P602 + +# UART(9) is on P602/P601. +uart_loopback_args = (9,) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/NUCLEO_WB55.py b/tests/target_wiring/NUCLEO_WB55.py new file mode 100644 index 00000000000..ad7c120d377 --- /dev/null +++ b/tests/target_wiring/NUCLEO_WB55.py @@ -0,0 +1,8 @@ +# Target wiring for NUCLEO_WB55. +# +# Connect: +# - PA2 to PA3 + +# LPUART(1) is on PA2/PA3. +uart_loopback_args = ("LP1",) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/PYBx.py b/tests/target_wiring/PYBx.py new file mode 100644 index 00000000000..10ce520ef0a --- /dev/null +++ b/tests/target_wiring/PYBx.py @@ -0,0 +1,8 @@ +# Target wiring for PYBV10, PYBV11, PYBLITEV10, PYBD_SF2, PYBD_SF3, PYBD_SF6. +# +# Connect: +# - X1 to X2 + +# UART("XA") is on X1/X2 (usually UART(4) on PA0/PA1). +uart_loopback_args = ("XA",) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/ZEPHYR_NUCLEO_WB55RG.py b/tests/target_wiring/ZEPHYR_NUCLEO_WB55RG.py new file mode 100644 index 00000000000..c7ca2ac26f7 --- /dev/null +++ b/tests/target_wiring/ZEPHYR_NUCLEO_WB55RG.py @@ -0,0 +1,7 @@ +# Target wiring for zephyr nucleo_wb55rg. +# +# Connect: +# - TX=PC0 to RX=PC1 + +uart_loopback_args = ("lpuart1",) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/alif.py b/tests/target_wiring/alif.py new file mode 100644 index 00000000000..18f3cbe7e5e --- /dev/null +++ b/tests/target_wiring/alif.py @@ -0,0 +1,7 @@ +# Target wiring for general alif board. +# +# Connect: +# - UART1 TX and RX, usually P0_5 and P0_4 + +uart_loopback_args = (1,) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/esp32.py b/tests/target_wiring/esp32.py new file mode 100644 index 00000000000..2767cd5acb2 --- /dev/null +++ b/tests/target_wiring/esp32.py @@ -0,0 +1,12 @@ +# Target wiring for general esp32 board. +# +# Connect: +# - GPIO4 to GPIO5 +# - GPIO12 to GPIO13 + +uart_loopback_args = (1,) +uart_loopback_kwargs = {"tx": 4, "rx": 5} + +encoder_loopback_id = 0 +encoder_loopback_out_pins = (4, 12) +encoder_loopback_in_pins = (5, 13) diff --git a/tests/target_wiring/mimxrt.py b/tests/target_wiring/mimxrt.py new file mode 100644 index 00000000000..669e9095990 --- /dev/null +++ b/tests/target_wiring/mimxrt.py @@ -0,0 +1,7 @@ +# Target wiring for general mimxrt board. +# +# Connect: +# - UART1 TX and RX, usually D0 and D1 + +uart_loopback_args = (1,) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/nrf.py b/tests/target_wiring/nrf.py new file mode 100644 index 00000000000..6979dd28ee5 --- /dev/null +++ b/tests/target_wiring/nrf.py @@ -0,0 +1,7 @@ +# Target wiring for general nrf board. +# +# Connect: +# - UART0 TX and RX + +uart_loopback_args = (0,) +uart_loopback_kwargs = {} diff --git a/tests/target_wiring/rp2.py b/tests/target_wiring/rp2.py new file mode 100644 index 00000000000..cb0fa0d6263 --- /dev/null +++ b/tests/target_wiring/rp2.py @@ -0,0 +1,7 @@ +# Target wiring for general rp2 board. +# +# Connect: +# - GPIO0 to GPIO1 + +uart_loopback_args = (0,) +uart_loopback_kwargs = {"tx": "GPIO0", "rx": "GPIO1"} diff --git a/tests/target_wiring/samd.py b/tests/target_wiring/samd.py new file mode 100644 index 00000000000..887c43a242f --- /dev/null +++ b/tests/target_wiring/samd.py @@ -0,0 +1,7 @@ +# Target wiring for general samd board. +# +# Connect: +# - D0 to D1 + +uart_loopback_args = () +uart_loopback_kwargs = {"tx": "D1", "rx": "D0"} diff --git a/tests/thread/mutate_bytearray.py b/tests/thread/mutate_bytearray.py index b4664781a15..7116d291cfe 100644 --- a/tests/thread/mutate_bytearray.py +++ b/tests/thread/mutate_bytearray.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread # the shared bytearray @@ -36,7 +37,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check bytearray has correct contents print(len(ba)) diff --git a/tests/thread/mutate_dict.py b/tests/thread/mutate_dict.py index 3777af66248..dd5f69e6c5d 100644 --- a/tests/thread/mutate_dict.py +++ b/tests/thread/mutate_dict.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread # the shared dict @@ -38,7 +39,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check dict has correct contents print(sorted(di.items())) diff --git a/tests/thread/mutate_instance.py b/tests/thread/mutate_instance.py index 306ad91c95c..63f7fb1e23d 100644 --- a/tests/thread/mutate_instance.py +++ b/tests/thread/mutate_instance.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -40,7 +41,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check user instance has correct contents print(user.a, user.b, user.c) diff --git a/tests/thread/mutate_list.py b/tests/thread/mutate_list.py index 6f1e8812541..d7398a2f1e0 100644 --- a/tests/thread/mutate_list.py +++ b/tests/thread/mutate_list.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread # the shared list @@ -39,7 +40,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check list has correct contents li.sort() diff --git a/tests/thread/mutate_set.py b/tests/thread/mutate_set.py index 2d9a3e0ce9e..7dcefa1d113 100644 --- a/tests/thread/mutate_set.py +++ b/tests/thread/mutate_set.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread # the shared set @@ -33,7 +34,7 @@ def th(n, lo, hi): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) # check set has correct contents print(sorted(se)) diff --git a/tests/thread/stress_aes.py b/tests/thread/stress_aes.py index d8d0acd568a..ca25f8ad2fd 100644 --- a/tests/thread/stress_aes.py +++ b/tests/thread/stress_aes.py @@ -277,7 +277,7 @@ def thread_entry(n_loop): n_thread = 2 n_loop = 2 else: - n_thread = 20 + n_thread = 10 n_loop = 5 for i in range(n_thread): _thread.start_new_thread(thread_entry, (n_loop,)) diff --git a/tests/thread/stress_recurse.py b/tests/thread/stress_recurse.py index 73b3a40f33d..ec8b43fe8fc 100644 --- a/tests/thread/stress_recurse.py +++ b/tests/thread/stress_recurse.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -24,5 +25,5 @@ def thread_entry(): # busy wait for thread to finish while not finished: - pass + time.sleep(0) print("done") diff --git a/tests/thread/stress_schedule.py b/tests/thread/stress_schedule.py index 97876f0f77c..362d71aa12e 100644 --- a/tests/thread/stress_schedule.py +++ b/tests/thread/stress_schedule.py @@ -27,6 +27,8 @@ def task(x): n += 1 +# This function must always use the bytecode emitter so it bounces the GIL when running. +@micropython.bytecode def thread(): while thread_run: try: @@ -46,7 +48,7 @@ def thread(): # Wait up to 10 seconds for 10000 tasks to be scheduled. t = time.ticks_ms() while n < _NUM_TASKS and time.ticks_diff(time.ticks_ms(), t) < _TIMEOUT_MS: - pass + time.sleep(0) # Stop all threads. thread_run = False diff --git a/tests/thread/thread_coop.py b/tests/thread/thread_coop.py index aefc4af074d..85cda789c93 100644 --- a/tests/thread/thread_coop.py +++ b/tests/thread/thread_coop.py @@ -7,6 +7,7 @@ import _thread import sys from time import ticks_ms, ticks_diff, sleep_ms +import micropython done = False @@ -21,6 +22,8 @@ MAX_DELTA = 100 +# This function must always use the bytecode emitter so the VM can bounce the GIL when running. +@micropython.bytecode def busy_thread(): while not done: pass diff --git a/tests/thread/thread_exc1.py b/tests/thread/thread_exc1.py index cd877409291..cd6599983c1 100644 --- a/tests/thread/thread_exc1.py +++ b/tests/thread/thread_exc1.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -34,5 +35,5 @@ def thread_entry(): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print("done") diff --git a/tests/thread/thread_exc2.py.native.exp b/tests/thread/thread_exc2.py.native.exp new file mode 100644 index 00000000000..9b2e715ef8d --- /dev/null +++ b/tests/thread/thread_exc2.py.native.exp @@ -0,0 +1,3 @@ +Unhandled exception in thread started by +ValueError: +done diff --git a/tests/thread/thread_gc1.py b/tests/thread/thread_gc1.py index b36ea9d4c84..45c17cc17be 100644 --- a/tests/thread/thread_gc1.py +++ b/tests/thread/thread_gc1.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import gc import _thread @@ -44,6 +45,6 @@ def thread_entry(n): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print(n_correct == n_finished) diff --git a/tests/thread/thread_ident1.py b/tests/thread/thread_ident1.py index 2a3732eff53..08cfd3eb36e 100644 --- a/tests/thread/thread_ident1.py +++ b/tests/thread/thread_ident1.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -27,6 +28,6 @@ def thread_entry(): new_tid = _thread.start_new_thread(thread_entry, ()) while not finished: - pass + time.sleep(0) print("done", type(new_tid) == int, new_tid == tid) diff --git a/tests/thread/thread_lock3.py b/tests/thread/thread_lock3.py index a927dc6829e..c5acfa21b7d 100644 --- a/tests/thread/thread_lock3.py +++ b/tests/thread/thread_lock3.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread lock = _thread.allocate_lock() @@ -26,4 +27,4 @@ def thread_entry(idx): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) diff --git a/tests/thread/thread_lock4.py b/tests/thread/thread_lock4_intbig.py similarity index 100% rename from tests/thread/thread_lock4.py rename to tests/thread/thread_lock4_intbig.py diff --git a/tests/thread/thread_shared1.py b/tests/thread/thread_shared1.py index 251e26fae6c..c2e33abcec7 100644 --- a/tests/thread/thread_shared1.py +++ b/tests/thread/thread_shared1.py @@ -2,6 +2,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -40,5 +41,5 @@ def thread_entry(n, tup): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print(tup) diff --git a/tests/thread/thread_shared2.py b/tests/thread/thread_shared2.py index a1223c2b94f..4ce9057ca01 100644 --- a/tests/thread/thread_shared2.py +++ b/tests/thread/thread_shared2.py @@ -3,6 +3,7 @@ # # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd +import time import _thread @@ -31,5 +32,5 @@ def thread_entry(n, lst, idx): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print(lst) diff --git a/tests/thread/thread_stacksize1.py b/tests/thread/thread_stacksize1.py index 140d165cb34..75e1da9642f 100644 --- a/tests/thread/thread_stacksize1.py +++ b/tests/thread/thread_stacksize1.py @@ -3,6 +3,7 @@ # MIT license; Copyright (c) 2016 Damien P. George on behalf of Pycom Ltd import sys +import time import _thread # different implementations have different minimum sizes @@ -51,5 +52,5 @@ def thread_entry(): # busy wait for threads to finish while n_finished < n_thread: - pass + time.sleep(0) print("done") diff --git a/tests/thread/thread_stdin.py b/tests/thread/thread_stdin.py index a469933f19b..498b0a3a270 100644 --- a/tests/thread/thread_stdin.py +++ b/tests/thread/thread_stdin.py @@ -5,6 +5,7 @@ # This is a regression test for https://github.com/micropython/micropython/issues/15230 # on rp2, but doubles as a general property to test across all ports. import sys +import time import _thread try: @@ -38,7 +39,7 @@ def is_done(self): # have run yet. The actual delay is <20ms but spinning here instead of # sleep(0.1) means the test can run on MP builds without float support. while not thread_waiter.is_done(): - pass + time.sleep(0) # The background thread should have completed its wait by now. print(thread_waiter.is_done()) diff --git a/tests/unix/extra_coverage.py b/tests/unix/extra_coverage.py index 0ea8f7886bf..ec10a44ff39 100644 --- a/tests/unix/extra_coverage.py +++ b/tests/unix/extra_coverage.py @@ -6,6 +6,16 @@ import errno import io +import uctypes + +# create an int-like variable used for coverage of `mp_obj_get_ll` +buf = bytearray(b"\xde\xad\xbe\xef") +struct = uctypes.struct( + uctypes.addressof(buf), + {"f32": uctypes.UINT32 | 0}, + uctypes.BIG_ENDIAN, +) +deadbeef = struct.f32 data = extra_coverage() @@ -23,6 +33,7 @@ print(stream.read(1)) # read 1 byte encounters non-blocking error print(stream.readline()) # readline encounters non-blocking error print(stream.readinto(bytearray(10))) # readinto encounters non-blocking error +print(stream.readinto1(bytearray(10))) # readinto1 encounters non-blocking error print(stream.write(b"1")) # write encounters non-blocking error print(stream.write1(b"1")) # write1 encounters non-blocking error stream.set_buf(b"123") @@ -38,6 +49,28 @@ stream.set_error(0) print(stream.ioctl(0, bytearray(10))) # successful ioctl call +print("# stream.readinto") + +# stream.readinto will read 3 bytes then try to read more to fill the buffer, +# but on the second attempt will encounter EIO and should raise that error. +stream.set_error(errno.EIO) +stream.set_buf(b"123") +buf = bytearray(4) +try: + stream.readinto(buf) +except OSError as er: + print("OSError", er.errno == errno.EIO) +print(buf) + +# stream.readinto1 will read 3 bytes then should return them immediately, and +# not encounter the EIO. +stream.set_error(errno.EIO) +stream.set_buf(b"123") +buf = bytearray(4) +print(stream.readinto1(buf), buf) + +print("# stream textio") + stream2 = data[3] # is textio print(stream2.read(1)) # read 1 byte encounters non-blocking error with textio stream @@ -92,7 +125,7 @@ print(returns_NULL()) -# test for freeze_mpy +# test for freeze_mpy (importing prints several lines) import frozentest print(frozentest.__file__) diff --git a/tests/unix/extra_coverage.py.exp b/tests/unix/extra_coverage.py.exp index 4cd8b8666d2..cdb11455694 100644 --- a/tests/unix/extra_coverage.py.exp +++ b/tests/unix/extra_coverage.py.exp @@ -2,25 +2,41 @@ -123 +123 123 -0123 123 -123 -1ABCDEF +123f +123F +7fffffffffffffff +7FFFFFFFFFFFFFFF +18446744073709551615 +789f +789F ab abc ' abc' ' True' 'Tru' false true (null) -2147483648 2147483648 -80000000 -80000000 +8000000f +8000000F abc % +.a . +<%> + + +<43690> +<43690> +<43690> + +<1000.000000> + +<9223372036854775807> # GC -0x0 -0x0 +0 +0 # GC part 2 pass # tracked allocation -m_tracked_head = 0x0 +m_tracked_head = 0 0 1 1 1 2 1 @@ -37,7 +53,7 @@ m_tracked_head = 0x0 5 1 6 1 7 1 -m_tracked_head = 0x0 +m_tracked_head = 0 # vstr tests sts @@ -91,6 +107,16 @@ data 12345 6 -1 +0 +1 +0 +0.000000 +deadbeef +c0ffee777c0ffee +deadbeef +0deadbeef +c0ffee +000c0ffee # runtime utils TypeError: unsupported type for __abs__: 'str' TypeError: unsupported types for __divmod__: 'str', 'str' @@ -99,12 +125,10 @@ TypeError: unsupported types for __divmod__: 'str', 'str' 2 OverflowError: overflow converting long int to machine word OverflowError: overflow converting long int to machine word +TypeError: can't convert NoneType to int +TypeError: can't convert NoneType to int ValueError: Warning: test -# format float -? -+1e+00 -+1e+00 # binary 123 456 @@ -124,6 +148,13 @@ unlocked KeyboardInterrupt: KeyboardInterrupt: 10 +loop +scheduled function +loop +scheduled function +loop +scheduled function +scheduled function # ringbuf 99 0 98 1 @@ -185,11 +216,17 @@ None None None None +None b'123' b'123' b'123' OSError 0 +# stream.readinto +OSError True +bytearray(b'123\x00') +3 bytearray(b'123\x00') +# stream textio None None cpp None @@ -215,7 +252,7 @@ b'\x00\xff' frzmpy4 1 frzmpy4 2 NULL -uPy +interned a long string that is not interned a string that has unicode αβγ chars b'bytes 1234\x01' diff --git a/tests/unix/ffi_float2.py b/tests/unix/ffi_float2.py index bbed6966627..eac6cd106cf 100644 --- a/tests/unix/ffi_float2.py +++ b/tests/unix/ffi_float2.py @@ -29,4 +29,5 @@ def ffi_open(names): for fun in (tgammaf,): for val in (0.5, 1, 1.0, 1.5, 4, 4.0): - print("%.6f" % fun(val)) + # limit to 5 decimals in order to pass with REPR_C with FORMAT_IMPL_BASIC + print("%.5f" % fun(val)) diff --git a/tests/unix/ffi_float2.py.exp b/tests/unix/ffi_float2.py.exp index 58fc6a01acb..4c750e223a3 100644 --- a/tests/unix/ffi_float2.py.exp +++ b/tests/unix/ffi_float2.py.exp @@ -1,6 +1,6 @@ -1.772454 -1.000000 -1.000000 -0.886227 -6.000000 -6.000000 +1.77245 +1.00000 +1.00000 +0.88623 +6.00000 +6.00000 diff --git a/tests/unix/mod_os.py b/tests/unix/mod_os.py index f69fa45b2b2..468f6badd1e 100644 --- a/tests/unix/mod_os.py +++ b/tests/unix/mod_os.py @@ -1,6 +1,9 @@ # This module is not entirely compatible with CPython import os +if not hasattr(os, "getenv"): + print("SKIP") + raise SystemExit os.putenv("TEST_VARIABLE", "TEST_VALUE") diff --git a/tests/unix/time_mktime_localtime.py b/tests/unix/time_mktime_localtime.py index d1c03c103d7..df5d6cda690 100644 --- a/tests/unix/time_mktime_localtime.py +++ b/tests/unix/time_mktime_localtime.py @@ -1,4 +1,8 @@ -import time +try: + import time +except ImportError: + print("SKIP") + raise SystemExit DAYS_PER_MONTH = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] diff --git a/tools/boardgen.py b/tools/boardgen.py index 39bedf71cd0..3723e7ce31b 100644 --- a/tools/boardgen.py +++ b/tools/boardgen.py @@ -108,6 +108,10 @@ def add_board_pin_name(self, board_pin_name, hidden=False): ) ) + # Iterate over board pin names in consistent sorted order. + def board_pin_names(self): + return sorted(self._board_pin_names, key=lambda x: x[0]) + # Override this to handle an af specified in af.csv. def add_af(self, af_idx, af_name, af): raise NotImplementedError @@ -295,7 +299,7 @@ def print_board_locals_dict(self, out_source): file=out_source, ) for pin in self.available_pins(): - for board_pin_name, board_hidden in pin._board_pin_names: + for board_pin_name, board_hidden in pin.board_pin_names(): if board_hidden: # Don't include hidden pins in Pins.board. continue @@ -389,7 +393,7 @@ def print_defines(self, out_header, cpu=True, board=True): # #define pin_BOARDNAME (pin_CPUNAME) if board: - for board_pin_name, _board_hidden in pin._board_pin_names: + for board_pin_name, _board_hidden in pin.board_pin_names(): # Note: Hidden board pins are still available to C via the macro. # Note: The RHS isn't wrapped in (), which is necessary to make the # STATIC_AF_ macro work on STM32. diff --git a/tools/cc1 b/tools/cc1 index 827d5886a04..aa2534f01e7 100755 --- a/tools/cc1 +++ b/tools/cc1 @@ -23,8 +23,8 @@ import re # TODO somehow make them externally configurable # this is the path to the true C compiler -cc1_path = '/usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/cc1' -#cc1_path = '/usr/lib/gcc/arm-none-eabi/5.3.0/cc1' +cc1_path = "/usr/lib/gcc/x86_64-unknown-linux-gnu/5.3.0/cc1" +# cc1_path = '/usr/lib/gcc/arm-none-eabi/5.3.0/cc1' # this must be the same as MICROPY_QSTR_BYTES_IN_HASH bytes_in_qstr_hash = 2 @@ -41,11 +41,16 @@ print_debug = False ################################################################################ # precompile regexs -re_preproc_line = re.compile(r'# [0-9]+ ') -re_map_entry = re.compile(r'\{.+?\(MP_QSTR_([A-Za-z0-9_]+)\).+\},') -re_mp_obj_dict_t = re.compile(r'(?P(static )?const mp_obj_dict_t (?P[a-z0-9_]+) = \{ \.base = \{&mp_type_dict\}, \.map = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$') -re_mp_map_t = re.compile(r'(?P(static )?const mp_map_t (?P[a-z0-9_]+) = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$') -re_mp_rom_map_elem_t = re.compile(r'static const mp_rom_map_elem_t [a-z_0-9]+\[\] = {$') +re_preproc_line = re.compile(r"# [0-9]+ ") +re_map_entry = re.compile(r"\{.+?\(MP_QSTR_([A-Za-z0-9_]+)\).+\},") +re_mp_obj_dict_t = re.compile( + r"(?P(static )?const mp_obj_dict_t (?P[a-z0-9_]+) = \{ \.base = \{&mp_type_dict\}, \.map = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$" +) +re_mp_map_t = re.compile( + r"(?P(static )?const mp_map_t (?P[a-z0-9_]+) = \{ \.all_keys_are_qstrs = 1, \.is_fixed = 1, \.is_ordered = )1(?P, \.used = .+ };)$" +) +re_mp_rom_map_elem_t = re.compile(r"static const mp_rom_map_elem_t [a-z_0-9]+\[\] = {$") + # this must match the equivalent function in qstr.c def compute_hash(qstr): @@ -55,18 +60,19 @@ def compute_hash(qstr): # Make sure that valid hash is never zero, zero means "hash not computed" return (hash & ((1 << (8 * bytes_in_qstr_hash)) - 1)) or 1 + # this algo must match the equivalent in map.c def hash_insert(map, key, value): hash = compute_hash(key) pos = hash % len(map) start_pos = pos if print_debug: - print(' insert %s: start at %u/%u -- ' % (key, pos, len(map)), end='') + print(" insert %s: start at %u/%u -- " % (key, pos, len(map)), end="") while True: if map[pos] is None: # found empty slot, so key is not in table if print_debug: - print('put at %u' % pos) + print("put at %u" % pos) map[pos] = (key, value) return else: @@ -76,6 +82,7 @@ def hash_insert(map, key, value): pos = (pos + 1) % len(map) assert pos != start_pos + def hash_find(map, key): hash = compute_hash(key) pos = hash % len(map) @@ -92,6 +99,7 @@ def hash_find(map, key): if pos == start_pos: return attempts, None + def process_map_table(file, line, output): output.append(line) @@ -101,7 +109,7 @@ def process_map_table(file, line, output): while True: line = file.readline() if len(line) == 0: - print('unexpected end of input') + print("unexpected end of input") sys.exit(1) line = line.strip() if len(line) == 0: @@ -110,38 +118,38 @@ def process_map_table(file, line, output): if re_preproc_line.match(line): # preprocessor line number comment continue - if line == '};': + if line == "};": # end of table (we assume it appears on a single line) break table_contents.append(line) # make combined string of entries - entries_str = ''.join(table_contents) + entries_str = "".join(table_contents) # split into individual entries entries = [] while entries_str: # look for single entry, by matching nested braces match = None - if entries_str[0] == '{': + if entries_str[0] == "{": nested_braces = 0 for i in range(len(entries_str)): - if entries_str[i] == '{': + if entries_str[i] == "{": nested_braces += 1 - elif entries_str[i] == '}': + elif entries_str[i] == "}": nested_braces -= 1 if nested_braces == 0: - match = re_map_entry.match(entries_str[:i + 2]) + match = re_map_entry.match(entries_str[: i + 2]) break if not match: - print('unknown line in table:', entries_str) + print("unknown line in table:", entries_str) sys.exit(1) # extract single entry line = match.group(0) qstr = match.group(1) - entries_str = entries_str[len(line):].lstrip() + entries_str = entries_str[len(line) :].lstrip() # add the qstr and the whole line to list of all entries entries.append((qstr, line)) @@ -164,28 +172,28 @@ def process_map_table(file, line, output): attempts, line = hash_find(map, qstr) assert line is not None if print_debug: - print(' %s lookup took %u attempts' % (qstr, attempts)) + print(" %s lookup took %u attempts" % (qstr, attempts)) total_attempts += attempts - if len(entries): + if entries: stats = len(map), len(entries) / len(map), total_attempts / len(entries) else: stats = 0, 0, 0 if print_debug: - print(' table stats: size=%d, load=%.2f, avg_lookups=%.1f' % stats) + print(" table stats: size=%d, load=%.2f, avg_lookups=%.1f" % stats) # output hash table for row in map: if row is None: - output.append('{ 0, 0 },\n') + output.append("{ 0, 0 },\n") else: - output.append(row[1] + '\n') - output.append('};\n') + output.append(row[1] + "\n") + output.append("};\n") # skip to next non-blank line while True: line = file.readline() if len(line) == 0: - print('unexpected end of input') + print("unexpected end of input") sys.exit(1) line = line.strip() if len(line) == 0: @@ -197,19 +205,20 @@ def process_map_table(file, line, output): if match is None: match = re_mp_map_t.match(line) if match is None: - print('expecting mp_obj_dict_t or mp_map_t definition') + print("expecting mp_obj_dict_t or mp_map_t definition") print(output[0]) print(line) sys.exit(1) - line = match.group('head') + '0' + match.group('tail') + '\n' + line = match.group("head") + "0" + match.group("tail") + "\n" output.append(line) - return (match.group('id'),) + stats + return (match.group("id"),) + stats + def process_file(filename): output = [] file_changed = False - with open(filename, 'rt') as f: + with open(filename, "rt") as f: while True: line = f.readline() if not line: @@ -218,39 +227,41 @@ def process_file(filename): file_changed = True stats = process_map_table(f, line, output) if print_stats: - print(' [%s: size=%d, load=%.2f, avg_lookups=%.1f]' % stats) + print(" [%s: size=%d, load=%.2f, avg_lookups=%.1f]" % stats) else: output.append(line) if file_changed: if print_debug: - print(' modifying static maps in', output[0].strip()) - with open(filename, 'wt') as f: + print(" modifying static maps in", output[0].strip()) + with open(filename, "wt") as f: for line in output: f.write(line) + def main(): # run actual C compiler # need to quote args that have special characters in them def quote(s): - if s.find('<') != -1 or s.find('>') != -1: + if s.find("<") != -1 or s.find(">") != -1: return "'" + s + "'" else: return s - ret = os.system(cc1_path + ' ' + ' '.join(quote(s) for s in sys.argv[1:])) + + ret = os.system(cc1_path + " " + " ".join(quote(s) for s in sys.argv[1:])) if ret != 0: - ret = (ret & 0x7f) or 127 # make it in range 0-127, but non-zero + ret = (ret & 0x7F) or 127 # make it in range 0-127, but non-zero sys.exit(ret) - if sys.argv[1] == '-E': + if sys.argv[1] == "-E": # CPP has been run, now do our processing stage for i, arg in enumerate(sys.argv): - if arg == '-o': + if arg == "-o": return process_file(sys.argv[i + 1]) print('%s: could not find "-o" option' % (sys.argv[0],)) sys.exit(1) - elif sys.argv[1] == '-fpreprocessed': + elif sys.argv[1] == "-fpreprocessed": # compiler has been run, nothing more to do return else: @@ -258,5 +269,6 @@ def main(): print('%s: unknown first option "%s"' % (sys.argv[0], sys.argv[1])) sys.exit(1) -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/tools/ci.sh b/tools/ci.sh index cfc9754837f..60e870ce65b 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -9,15 +9,20 @@ fi # Ensure known OPEN_MAX (NO_FILES) limit. ulimit -n 1024 +# Fail on some things which are warnings otherwise +export MICROPY_MAINTAINER_BUILD=1 + ######################################################################################## # general helper functions function ci_gcc_arm_setup { + sudo apt-get update sudo apt-get install gcc-arm-none-eabi libnewlib-arm-none-eabi arm-none-eabi-gcc --version } function ci_gcc_riscv_setup { + sudo apt-get update sudo apt-get install gcc-riscv64-unknown-elf picolibc-riscv64-unknown-elf riscv64-unknown-elf-gcc --version } @@ -35,6 +40,7 @@ function ci_picotool_setup { # c code formatting function ci_c_code_formatting_setup { + sudo apt-get update sudo apt-get install uncrustify uncrustify --version } @@ -74,42 +80,69 @@ function ci_code_size_setup { ci_picotool_setup } +function _ci_is_git_merge { + [[ $(git log -1 --format=%P "$1" | wc -w) > 1 ]] +} + function ci_code_size_build { # check the following ports for the change in their code size - PORTS_TO_CHECK=bmusxpdv + # Override the list by setting PORTS_TO_CHECK in the environment before invoking ci. + : ${PORTS_TO_CHECK:=bmusxpdv} + SUBMODULES="lib/asf4 lib/berkeley-db-1.xx lib/btstack lib/cyw43-driver lib/lwip lib/mbedtls lib/micropython-lib lib/nxp_driver lib/pico-sdk lib/stm32lib lib/tinyusb" # Default GitHub pull request sets HEAD to a generated merge commit # between PR branch (HEAD^2) and base branch (i.e. master) (HEAD^1). # # We want to compare this generated commit with the base branch, to see what - # the code size impact would be if we merged this PR. - REFERENCE=$(git rev-parse --short HEAD^1) - COMPARISON=$(git rev-parse --short HEAD) + # the code size impact would be if we merged this PR. During CI we are at a merge commit, + # so this tests the merged PR against its merge base. + # Override the refs by setting REFERENCE and/or COMPARISON in the environment before invoking ci. + : ${COMPARISON:=$(git rev-parse --short HEAD)} + : ${REFERENCE:=$(git rev-parse --short ${COMPARISON}^1)} echo "Comparing sizes of reference ${REFERENCE} to ${COMPARISON}..." git log --oneline $REFERENCE..$COMPARISON - function code_size_build_step { - COMMIT=$1 - OUTFILE=$2 - IGNORE_ERRORS=$3 - - echo "Building ${COMMIT}..." - git checkout --detach $COMMIT - git submodule update --init $SUBMODULES - git show -s - tools/metrics.py clean $PORTS_TO_CHECK - tools/metrics.py build $PORTS_TO_CHECK | tee $OUTFILE || $IGNORE_ERRORS - } - - # build reference, save to size0 - # ignore any errors with this build, in case master is failing - code_size_build_step $REFERENCE ~/size0 true - # build PR/branch, save to size1 - code_size_build_step $COMPARISON ~/size1 false - - unset -f code_size_build_step + OLD_BRANCH="$(git rev-parse --abbrev-ref HEAD)" + + ( # Execute in a subshell so the trap & code_size_build_step doesn't leak + function code_size_build_step { + if [ ! -z "$OLD_BRANCH" ]; then + trap 'git checkout "$OLD_BRANCH"' RETURN EXIT ERR + fi + + COMMIT=$1 + OUTFILE=$2 + IGNORE_ERRORS=$3 + + git checkout --detach $COMMIT + git submodule update --init $SUBMODULES + git show -s + tools/metrics.py clean "$PORTS_TO_CHECK" + # Allow errors from tools/metrics.py to propagate out of the pipe below. + set -o pipefail + tools/metrics.py build "$PORTS_TO_CHECK" | tee -a $OUTFILE || $IGNORE_ERRORS + return $? + } + + # build reference, save to size0 + # ignore any errors with this build, in case master is failing + echo "BUILDING $(git log --format='%s [%h]' -1 ${REFERENCE})" > ~/size0 + code_size_build_step $REFERENCE ~/size0 true + # build PR/branch, save to size1 + if _ci_is_git_merge "$COMPARISON"; then + echo "BUILDING $(git log --oneline -1 --format='%s [merge of %h]' ${COMPARISON}^2)" + else + echo "BUILDING $(git log --oneline -1 --formta='%s [%h]' ${COMPARISON})" + fi > ~/size1 + code_size_build_step $COMPARISON ~/size1 false + ) +} + +function ci_code_size_report { + # Allow errors from tools/metrics.py to propagate out of the pipe above. + (set -o pipefail; tools/metrics.py diff ~/size0 ~/size1 | tee diff) } ######################################################################################## @@ -117,15 +150,12 @@ function ci_code_size_build { function ci_mpy_format_setup { sudo apt-get update - sudo apt-get install python2.7 sudo pip3 install pyelftools - python2.7 --version python3 --version } function ci_mpy_format_test { # Test mpy-tool.py dump feature on bytecode - python2.7 ./tools/mpy-tool.py -xd tests/frozen/frozentest.mpy python3 ./tools/mpy-tool.py -xd tests/frozen/frozentest.mpy # Build MicroPython @@ -143,6 +173,15 @@ function ci_mpy_format_test { $micropython ./tools/mpy-tool.py -x -d examples/natmod/features1/features1.mpy } +function ci_mpy_cross_debug_emitter { + make ${MAKEOPTS} -C mpy-cross + mpy_cross=./mpy-cross/build/mpy-cross + + # Make sure the debug emitter does not crash or fail for simple files + $mpy_cross -X emit=native -march=debug ./tests/basics/0prelim.py | \ + grep -E "ENTRY|EXIT" | wc -l | grep "^2$" +} + ######################################################################################## # ports/cc3200 @@ -158,14 +197,17 @@ function ci_cc3200_build { ######################################################################################## # ports/esp32 -# GitHub tag of ESP-IDF to use for CI (note: must be a tag or a branch) -IDF_VER=v5.2.2 +# GitHub tag of ESP-IDF to use for CI, extracted from the esp32 dependency lockfile +# This should end up as a tag name like vX.Y.Z +# (note: This hacky parsing can be replaced with 'yq' once Ubuntu >=24.04 is in use) +IDF_VER=v$(grep -A10 "idf:" ports/esp32/lockfiles/dependencies.lock.esp32 | grep "version:" | head -n1 | sed -E 's/ +version: //') PYTHON=$(command -v python3 2> /dev/null) PYTHON_VER=$(${PYTHON:-python} --version | cut -d' ' -f2) export IDF_CCACHE_ENABLE=1 function ci_esp32_idf_setup { + echo "Using ESP-IDF version $IDF_VER" git clone --depth 1 --branch $IDF_VER https://github.com/espressif/esp-idf.git # doing a treeless clone isn't quite as good as --shallow-submodules, but it # is smaller than full clones and works when the submodule commit isn't a head. @@ -204,13 +246,28 @@ function ci_esp32_build_s3_c3 { make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C3 } +function ci_esp32_build_c2_c5_c6 { + ci_esp32_build_common + + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C2 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C5 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_C6 +} + +function ci_esp32_build_p4 { + ci_esp32_build_common + + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_P4 + make ${MAKEOPTS} -C ports/esp32 BOARD=ESP32_GENERIC_P4 BOARD_VARIANT=C6_WIFI +} + ######################################################################################## # ports/esp8266 function ci_esp8266_setup { sudo pip3 install pyserial esptool==3.3.1 pyelftools ar - wget https://github.com/jepler/esp-open-sdk/releases/download/2018-06-10/xtensa-lx106-elf-standalone.tar.gz - zcat xtensa-lx106-elf-standalone.tar.gz | tar x + wget https://micropython.org/resources/xtensa-lx106-elf-standalone.tar.gz + (set -o pipefail; zcat xtensa-lx106-elf-standalone.tar.gz | tar x) # Remove this esptool.py so pip version is used instead rm xtensa-lx106-elf/bin/esptool.py } @@ -317,17 +374,52 @@ function ci_qemu_setup_rv32 { qemu-system-riscv32 --version } -function ci_qemu_build_arm { +function ci_qemu_setup_rv64 { + ci_gcc_riscv_setup + sudo apt-get update + sudo apt-get install qemu-system + qemu-system-riscv64 --version +} + +function ci_qemu_build_arm_prepare { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/qemu submodules +} + +function ci_qemu_build_arm_bigendian { + ci_qemu_build_arm_prepare make ${MAKEOPTS} -C ports/qemu CFLAGS_EXTRA=-DMP_ENDIANNESS_BIG=1 - make ${MAKEOPTS} -C ports/qemu clean - make ${MAKEOPTS} -C ports/qemu test_full +} + +function ci_qemu_build_arm_sabrelite { + ci_qemu_build_arm_prepare make ${MAKEOPTS} -C ports/qemu BOARD=SABRELITE test_full +} - # Test building and running native .mpy with armv7m architecture. +function ci_qemu_build_arm_thumb_softfp { + ci_qemu_build_arm_prepare + make BOARD=MPS2_AN385 ${MAKEOPTS} -C ports/qemu test_full + + # Test building native .mpy with ARM-M softfp architectures. + ci_native_mpy_modules_build armv6m ci_native_mpy_modules_build armv7m - make ${MAKEOPTS} -C ports/qemu test_natmod + + # Test running native .mpy with all ARM-M architectures. + make BOARD=MPS2_AN385 ${MAKEOPTS} -C ports/qemu test_natmod RUN_TESTS_EXTRA="--arch armv6m" + make BOARD=MPS2_AN385 ${MAKEOPTS} -C ports/qemu test_natmod RUN_TESTS_EXTRA="--arch armv7m" +} + +function ci_qemu_build_arm_thumb_hardfp { + ci_qemu_build_arm_prepare + make BOARD=MPS2_AN500 ${MAKEOPTS} -C ports/qemu test_full + + # Test building native .mpy with all ARM-M hardfp architectures. + ci_native_mpy_modules_build armv7emsp + ci_native_mpy_modules_build armv7emdp + + # Test running native .mpy with all ARM-M hardfp architectures. + make BOARD=MPS2_AN500 ${MAKEOPTS} -C ports/qemu test_natmod RUN_TESTS_EXTRA="--arch armv7emsp" + make BOARD=MPS2_AN500 ${MAKEOPTS} -C ports/qemu test_natmod RUN_TESTS_EXTRA="--arch armv7emdp" } function ci_qemu_build_rv32 { @@ -340,6 +432,12 @@ function ci_qemu_build_rv32 { make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV32 test_natmod } +function ci_qemu_build_rv64 { + make ${MAKEOPTS} -C mpy-cross + make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 submodules + make ${MAKEOPTS} -C ports/qemu BOARD=VIRT_RV64 test +} + ######################################################################################## # ports/renesas-ra @@ -403,13 +501,22 @@ function ci_samd_build { # ports/stm32 function ci_stm32_setup { - ci_gcc_arm_setup + # Use a recent version of the ARM toolchain, to work with Cortex-M55. + wget https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz + xzcat arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz | tar x + pip3 install pyelftools pip3 install ar pip3 install pyhy } +function ci_stm32_path { + echo $(pwd)/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin +} + function ci_stm32_pyb_build { + # This function builds the following MCU families: F4, F7. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 MICROPY_PY_NETWORK_WIZNET5K=5200 submodules make ${MAKEOPTS} -C ports/stm32 BOARD=PYBD_SF2 submodules @@ -421,20 +528,18 @@ function ci_stm32_pyb_build { make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBV10 CFLAGS_EXTRA='-DMBOOT_FSLOAD=1 -DMBOOT_VFS_LFS2=1' make ${MAKEOPTS} -C ports/stm32/mboot BOARD=PYBD_SF6 make ${MAKEOPTS} -C ports/stm32/mboot BOARD=STM32F769DISC CFLAGS_EXTRA='-DMBOOT_ADDRESS_SPACE_64BIT=1 -DMBOOT_SDCARD_ADDR=0x100000000ULL -DMBOOT_SDCARD_BYTE_SIZE=0x400000000ULL -DMBOOT_FSLOAD=1 -DMBOOT_VFS_FAT=1' - - # Test building native .mpy with armv7emsp architecture. - git submodule update --init lib/berkeley-db-1.xx - ci_native_mpy_modules_build armv7emsp } function ci_stm32_nucleo_build { + # This function builds the following MCU families: F0, H5, H7, L0, L4, WB. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI submodules git submodule update --init lib/mynewt-nimble # Test building various MCU families, some with additional options. make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_F091RC - make ${MAKEOPTS} -C ports/stm32 BOARD=STM32H573I_DK + make ${MAKEOPTS} -C ports/stm32 BOARD=STM32H573I_DK CFLAGS_EXTRA='-DMICROPY_HW_TINYUSB_STACK=1' make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_H743ZI COPT=-O2 CFLAGS_EXTRA='-DMICROPY_PY_THREAD=1' make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L073RZ make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L476RG DEBUG=1 @@ -454,21 +559,22 @@ function ci_stm32_nucleo_build { } function ci_stm32_misc_build { + # This function builds the following MCU families: G0, G4, H7, L1, N6, U5, WL. + make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/stm32 BOARD=ARDUINO_GIGA submodules make ${MAKEOPTS} -C ports/stm32 BOARD=ARDUINO_GIGA + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_G0B1RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_G474RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_L152RE + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_N657X0 + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_U5A5ZJ_Q + make ${MAKEOPTS} -C ports/stm32 BOARD=NUCLEO_WL55 } ######################################################################################## # ports/unix -CI_UNIX_OPTS_SYS_SETTRACE=( - MICROPY_PY_BTREE=0 - MICROPY_PY_FFI=0 - MICROPY_PY_SSL=0 - CFLAGS_EXTRA="-DMICROPY_PY_SYS_SETTRACE=1" -) - CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS=( MICROPY_PY_BTREE=0 MICROPY_PY_FFI=0 @@ -494,6 +600,26 @@ CI_UNIX_OPTS_QEMU_RISCV64=( MICROPY_STANDALONE=1 ) +CI_UNIX_OPTS_SANITIZE_ADDRESS=( + # Macro MP_ASAN allows detecting ASan on gcc<=13 + CFLAGS_EXTRA="-fsanitize=address --param asan-use-after-return=0 -DMP_ASAN=1" + LDFLAGS_EXTRA="-fsanitize=address --param asan-use-after-return=0" +) + +CI_UNIX_OPTS_SANITIZE_UNDEFINED=( + # Macro MP_UBSAN allows detecting UBSan on gcc<=13 + CFLAGS_EXTRA="-fsanitize=undefined -fno-sanitize=nonnull-attribute -DMP_UBSAN=1" + LDFLAGS_EXTRA="-fsanitize=undefined -fno-sanitize=nonnull-attribute" +) + +CI_UNIX_OPTS_REPR_B=( + VARIANT=standard + CFLAGS_EXTRA="-DMICROPY_OBJ_REPR=MICROPY_OBJ_REPR_B -DMICROPY_PY_UCTYPES=0 -Dmp_int_t=int32_t -Dmp_uint_t=uint32_t" + MICROPY_FORCE_32BIT=1 + RUN_TESTS_MPY_CROSS_FLAGS="--mpy-cross-flags=\"-march=x86 -msmall-int-bits=30\"" + +) + function ci_unix_build_helper { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/unix "$@" submodules @@ -509,13 +635,26 @@ function ci_unix_run_tests_helper { make -C ports/unix "$@" test } +function ci_unix_run_tests_full_extra { + micropython=$1 + (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-multitests.py multi_net/*.py) + (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-perfbench.py --average 1 1000 1000) +} + +function ci_unix_run_tests_full_no_native_helper { + variant=$1 + shift + micropython=../ports/unix/build-$variant/micropython + make -C ports/unix VARIANT=$variant "$@" test_full_no_native + ci_unix_run_tests_full_extra $micropython +} + function ci_unix_run_tests_full_helper { variant=$1 shift micropython=../ports/unix/build-$variant/micropython make -C ports/unix VARIANT=$variant "$@" test_full - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-multitests.py multi_net/*.py) - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=$micropython ./run-perfbench.py 1000 1000) + ci_unix_run_tests_full_extra $micropython } function ci_native_mpy_modules_build { @@ -524,40 +663,19 @@ function ci_native_mpy_modules_build { else arch=$1 fi - for natmod in features1 features3 features4 heapq re + for natmod in btree deflate features1 features3 features4 framebuf heapq random re do - make -C examples/natmod/$natmod clean + make -C examples/natmod/$natmod ARCH=$arch clean make -C examples/natmod/$natmod ARCH=$arch done - # deflate, framebuf, and random currently cannot build on xtensa due to - # some symbols that have been removed from the compiler's runtime, in - # favour of being provided from ROM. - if [ $arch != "xtensa" ]; then - for natmod in deflate framebuf random - do - make -C examples/natmod/$natmod clean - make -C examples/natmod/$natmod ARCH=$arch - done - fi - - # features2 requires soft-float on armv7m, rv32imc, and xtensa. On armv6m - # the compiler generates absolute relocations in the object file - # referencing soft-float functions, which is not supported at the moment. - make -C examples/natmod/features2 clean - if [ $arch = "rv32imc" ] || [ $arch = "armv7m" ] || [ $arch = "xtensa" ]; then + # features2 requires soft-float on rv32imc and xtensa. + make -C examples/natmod/features2 ARCH=$arch clean + if [ $arch = "rv32imc" ] || [ $arch = "xtensa" ]; then make -C examples/natmod/features2 ARCH=$arch MICROPY_FLOAT_IMPL=float - elif [ $arch != "armv6m" ]; then + else make -C examples/natmod/features2 ARCH=$arch fi - - # btree requires thread local storage support on rv32imc, whilst on xtensa - # it relies on symbols that are provided from ROM but not exposed to - # natmods at the moment. - if [ $arch != "rv32imc" ] && [ $arch != "xtensa" ]; then - make -C examples/natmod/btree clean - make -C examples/natmod/btree ARCH=$arch - fi } function ci_native_mpy_modules_32bit_build { @@ -569,7 +687,7 @@ function ci_unix_minimal_build { } function ci_unix_minimal_run_tests { - (cd tests && MICROPY_CPYTHON3=python3 MICROPY_MICROPYTHON=../ports/unix/build-minimal/micropython ./run-tests.py -e exception_chain -e self_type_check -e subclass_native_init -d basics) + make -C ports/unix VARIANT=minimal test } function ci_unix_standard_build { @@ -591,9 +709,9 @@ function ci_unix_standard_v2_run_tests { } function ci_unix_coverage_setup { - sudo pip3 install setuptools - sudo pip3 install pyelftools - sudo pip3 install ar + pip3 install setuptools + pip3 install pyelftools + pip3 install ar gcc --version python3 --version } @@ -604,7 +722,7 @@ function ci_unix_coverage_build { } function ci_unix_coverage_run_tests { - ci_unix_run_tests_full_helper coverage + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage } function ci_unix_coverage_run_mpy_merge_tests { @@ -639,12 +757,11 @@ function ci_unix_coverage_run_native_mpy_tests { function ci_unix_32bit_setup { sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install gcc-multilib g++-multilib libffi-dev:i386 python2.7 + sudo apt-get install gcc-multilib g++-multilib libffi-dev:i386 sudo pip3 install setuptools sudo pip3 install pyelftools sudo pip3 install ar gcc --version - python2.7 --version python3 --version } @@ -662,13 +779,20 @@ function ci_unix_coverage_32bit_run_native_mpy_tests { } function ci_unix_nanbox_build { - # Use Python 2 to check that it can run the build scripts - ci_unix_build_helper PYTHON=python2.7 VARIANT=nanbox CFLAGS_EXTRA="-DMICROPY_PY_MATH_CONSTANTS=1" + ci_unix_build_helper VARIANT=nanbox CFLAGS_EXTRA="-DMICROPY_PY_MATH_CONSTANTS=1" ci_unix_build_ffi_lib_helper gcc -m32 } function ci_unix_nanbox_run_tests { - ci_unix_run_tests_full_helper nanbox PYTHON=python2.7 + ci_unix_run_tests_full_no_native_helper nanbox +} + +function ci_unix_longlong_build { + ci_unix_build_helper VARIANT=longlong "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" +} + +function ci_unix_longlong_run_tests { + ci_unix_run_tests_full_helper longlong } function ci_unix_float_build { @@ -681,7 +805,17 @@ function ci_unix_float_run_tests { ci_unix_run_tests_helper CFLAGS_EXTRA="-DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT" } +function ci_unix_gil_enabled_build { + ci_unix_build_helper VARIANT=standard MICROPY_PY_THREAD_GIL=1 + ci_unix_build_ffi_lib_helper gcc +} + +function ci_unix_gil_enabled_run_tests { + ci_unix_run_tests_full_helper standard MICROPY_PY_THREAD_GIL=1 +} + function ci_unix_clang_setup { + sudo apt-get update sudo apt-get install clang clang --version } @@ -693,7 +827,8 @@ function ci_unix_stackless_clang_build { } function ci_unix_stackless_clang_run_tests { - ci_unix_run_tests_helper CC=clang + # Timeout needs to be increased for thread/stress_aes.py test. + MICROPY_TEST_TIMEOUT=90 ci_unix_run_tests_helper CC=clang } function ci_unix_float_clang_build { @@ -706,24 +841,36 @@ function ci_unix_float_clang_run_tests { ci_unix_run_tests_helper CC=clang } -function ci_unix_settrace_build { +function ci_unix_settrace_stackless_build { + make ${MAKEOPTS} -C mpy-cross + make ${MAKEOPTS} -C ports/unix submodules + make ${MAKEOPTS} -C ports/unix "${CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS[@]}" +} + +function ci_unix_settrace_stackless_run_tests { + ci_unix_run_tests_full_helper standard "${CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS[@]}" +} + +function ci_unix_sanitize_undefined_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix "${CI_UNIX_OPTS_SYS_SETTRACE[@]}" + make ${MAKEOPTS} -C ports/unix VARIANT=coverage "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" + ci_unix_build_ffi_lib_helper gcc } -function ci_unix_settrace_run_tests { - ci_unix_run_tests_full_helper standard "${CI_UNIX_OPTS_SYS_SETTRACE[@]}" +function ci_unix_sanitize_undefined_run_tests { + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage VARIANT=coverage "${CI_UNIX_OPTS_SANITIZE_UNDEFINED[@]}" } -function ci_unix_settrace_stackless_build { +function ci_unix_sanitize_address_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/unix submodules - make ${MAKEOPTS} -C ports/unix "${CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS[@]}" + make ${MAKEOPTS} -C ports/unix VARIANT=coverage "${CI_UNIX_OPTS_SANITIZE_ADDRESS[@]}" + ci_unix_build_ffi_lib_helper gcc } -function ci_unix_settrace_stackless_run_tests { - ci_unix_run_tests_full_helper standard "${CI_UNIX_OPTS_SYS_SETTRACE_STACKLESS[@]}" +function ci_unix_sanitize_address_run_tests { + MICROPY_TEST_TIMEOUT=60 ci_unix_run_tests_full_helper coverage VARIANT=coverage "${CI_UNIX_OPTS_SANITIZE_ADDRESS[@]}" } function ci_unix_macos_build { @@ -740,7 +887,9 @@ function ci_unix_macos_run_tests { # Issues with macOS tests: # - float_parse and float_parse_doubleprec parse/print floats out by a few mantissa bits # - ffi_callback crashes for an unknown reason - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-standard/micropython ./run-tests.py --exclude '(float_parse|float_parse_doubleprec|ffi_callback).py') + # - thread/stress_heap.py is flaky + # - thread/thread_gc1.py is flaky + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-standard/micropython ./run-tests.py --exclude '(float_parse|float_parse_doubleprec|ffi_callback|thread/stress_heap|thread/thread_gc1).py') } function ci_unix_qemu_mips_setup { @@ -758,8 +907,12 @@ function ci_unix_qemu_mips_build { } function ci_unix_qemu_mips_run_tests { + # Issues with MIPS tests: + # - thread/stress_aes.py takes around 50 seconds + # - thread/stress_recurse.py is flaky + # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py) + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=90 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py') } function ci_unix_qemu_arm_setup { @@ -779,8 +932,11 @@ function ci_unix_qemu_arm_build { function ci_unix_qemu_arm_run_tests { # Issues with ARM tests: # - (i)listdir does not work, it always returns the empty list (it's an issue with the underlying C call) + # - thread/stress_aes.py takes around 70 seconds + # - thread/stress_recurse.py is flaky + # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py --exclude 'vfs_posix.*\.py') + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=90 ./run-tests.py --exclude 'vfs_posix.*\.py|thread/stress_recurse.py|thread/thread_gc1.py') } function ci_unix_qemu_riscv64_setup { @@ -798,14 +954,30 @@ function ci_unix_qemu_riscv64_build { } function ci_unix_qemu_riscv64_run_tests { + # Issues with RISCV-64 tests: + # - thread/stress_aes.py takes around 140 seconds + # - thread/stress_recurse.py is flaky + # - thread/thread_gc1.py is flaky file ./ports/unix/build-coverage/micropython - (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py) + (cd tests && MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython MICROPY_TEST_TIMEOUT=180 ./run-tests.py --exclude 'thread/stress_recurse.py|thread/thread_gc1.py') +} + +function ci_unix_repr_b_build { + ci_unix_build_helper "${CI_UNIX_OPTS_REPR_B[@]}" + ci_unix_build_ffi_lib_helper gcc -m32 +} + +function ci_unix_repr_b_run_tests { + # ci_unix_run_tests_full_no_native_helper is not used due to + # https://github.com/micropython/micropython/issues/18105 + ci_unix_run_tests_helper "${CI_UNIX_OPTS_REPR_B[@]}" } ######################################################################################## # ports/windows function ci_windows_setup { + sudo apt-get update sudo apt-get install gcc-mingw-w64 } @@ -813,14 +985,15 @@ function ci_windows_build { make ${MAKEOPTS} -C mpy-cross make ${MAKEOPTS} -C ports/windows submodules make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=i686-w64-mingw32- + make ${MAKEOPTS} -C ports/windows CROSS_COMPILE=x86_64-w64-mingw32- BUILD=build-standard-w64 } ######################################################################################## # ports/zephyr -ZEPHYR_DOCKER_VERSION=v0.26.13 -ZEPHYR_SDK_VERSION=0.16.8 -ZEPHYR_VERSION=v3.7.0 +ZEPHYR_DOCKER_VERSION=v0.28.1 +ZEPHYR_SDK_VERSION=0.17.2 +ZEPHYR_VERSION=v4.2.0 function ci_zephyr_setup { IMAGE=ghcr.io/zephyrproject-rtos/ci:${ZEPHYR_DOCKER_VERSION} @@ -859,6 +1032,7 @@ function ci_zephyr_install { } function ci_zephyr_build { + git submodule update --init lib/micropython-lib docker exec zephyr-ci west build -p auto -b qemu_x86 -- -DCONF_FILE=prj_minimal.conf docker exec zephyr-ci west build -p auto -b frdm_k64f docker exec zephyr-ci west build -p auto -b mimxrt1050_evk @@ -867,9 +1041,7 @@ function ci_zephyr_build { function ci_zephyr_run_tests { docker exec zephyr-ci west build -p auto -b qemu_cortex_m3 -- -DCONF_FILE=prj_minimal.conf - # Issues with zephyr tests: - # - inf_nan_arith fails pow(-1, nan) test - (cd tests && ./run-tests.py -t execpty:"qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -monitor null -serial pty -kernel ../ports/zephyr/build/zephyr/zephyr.elf" -d basics float --exclude inf_nan_arith) + (cd tests && ./run-tests.py -t execpty:"qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -monitor null -serial pty -kernel ../ports/zephyr/build/zephyr/zephyr.elf") } ######################################################################################## @@ -886,3 +1058,86 @@ function ci_alif_ae3_build { make ${MAKEOPTS} -C ports/alif BOARD=OPENMV_AE3 MCU_CORE=M55_DUAL make ${MAKEOPTS} -C ports/alif BOARD=ALIF_ENSEMBLE MCU_CORE=M55_DUAL } + +function _ci_help { + # Note: these lines must be indented with tab characters (required by bash <<-EOF) + cat <<-EOF + ci.sh: Script fragments used during CI + + When invoked as a script, runs a sequence of ci steps, + stopping after the first error. + + Usage: + ${BASH_SOURCE} step1 step2... + + Steps: + EOF + if type -path column > /dev/null 2>&1; then + grep '^function ci_' $0 | awk '{print $2}' | sed 's/^ci_//' | column + else + grep '^function ci_' $0 | awk '{print $2}' | sed 's/^ci_//' + fi + exit +} + +function _ci_bash_completion { + echo "alias ci=\"$(readlink -f "$0")\"; complete -W '$(grep '^function ci_' $0 | awk '{print $2}' | sed 's/^ci_//')' ci" +} + +function _ci_zsh_completion { + echo "alias ci=\"$(readlink -f "$0"\"); _complete_mpy_ci_zsh() { compadd $(grep '^function ci_' $0 | awk '{sub(/^ci_/,"",$2); print $2}' | tr '\n' ' ') }; autoload -Uz compinit; compinit; compdef _complete_mpy_ci_zsh $(readlink -f "$0")" +} + +function _ci_fish_completion { + echo "alias ci=\"$(readlink -f "$0"\"); complete -c ci -p $(readlink -f "$0") -f -a '$(grep '^function ci_' $(readlink -f "$0") | awk '{sub(/^ci_/,"",$2); print $2}' | tr '\n' ' ')'" +} + +function _ci_main { + case "$1" in + (-h|-?|--help) + _ci_help + ;; + (--bash-completion) + _ci_bash_completion + ;; + (--zsh-completion) + _ci_zsh_completion + ;; + (--fish-completion) + _ci_fish_completion + ;; + (-*) + echo "Unknown option: $1" 1>&2 + exit 1 + ;; + (*) + set -e + cd $(dirname "$0")/.. + while [ $# -ne 0 ]; do + ci_$1 + shift + done + ;; + esac +} + +# https://stackoverflow.com/questions/2683279/how-to-detect-if-a-script-is-being-sourced +sourced=0 +if [ -n "$ZSH_VERSION" ]; then + case $ZSH_EVAL_CONTEXT in *:file) sourced=1;; esac +elif [ -n "$KSH_VERSION" ]; then + [ "$(cd -- "$(dirname -- "$0")" && pwd -P)/$(basename -- "$0")" != "$(cd -- "$(dirname -- "${.sh.file}")" && pwd -P)/$(basename -- "${.sh.file}")" ] && sourced=1 +elif [ -n "$BASH_VERSION" ]; then + (return 0 2>/dev/null) && sourced=1 +else # All other shells: examine $0 for known shell binary filenames. + # Detects `sh` and `dash`; add additional shell filenames as needed. + case ${0##*/} in sh|-sh|dash|-dash) sourced=1;; esac +fi + +if [ $sourced -eq 0 ]; then + # invoked as a command + if [ "$#" -eq 0 ]; then + set -- --help + fi + _ci_main "$@" +fi diff --git a/tools/codeformat.py b/tools/codeformat.py index a648d401ec3..cf91049a731 100644 --- a/tools/codeformat.py +++ b/tools/codeformat.py @@ -231,7 +231,7 @@ def batch(cmd, files, N=200, check=False): command = ["python3", "tools/ruff_bindings.py"] batch(command, bindings_files(), check=True) - # Format Python files with black. + # Format Python files with "ruff format" (using config in pyproject.toml). if format_py: command = ["ruff", "format"] if args.v: diff --git a/tools/file2h.py b/tools/file2h.py index df9cc02fdab..2707d4a16e5 100644 --- a/tools/file2h.py +++ b/tools/file2h.py @@ -9,8 +9,6 @@ # ; # This script simply prints the escaped string straight to stdout -from __future__ import print_function - import sys # Can either be set explicitly, or left blank to auto-detect diff --git a/tools/insert-usb-ids.py b/tools/insert-usb-ids.py index 4691d5a710c..1b043e1fef0 100644 --- a/tools/insert-usb-ids.py +++ b/tools/insert-usb-ids.py @@ -6,8 +6,6 @@ # inserts those values into the template file specified by sys.argv[2], # printing the result to stdout -from __future__ import print_function - import sys import re import string diff --git a/tools/makemanifest.py b/tools/makemanifest.py index e076a03e0be..860935397af 100644 --- a/tools/makemanifest.py +++ b/tools/makemanifest.py @@ -24,7 +24,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from __future__ import print_function import sys import os import subprocess diff --git a/tools/manifestfile.py b/tools/manifestfile.py index beaa36d0f5f..9c7a6e140f9 100644 --- a/tools/manifestfile.py +++ b/tools/manifestfile.py @@ -25,7 +25,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -from __future__ import print_function import contextlib import os import sys diff --git a/tools/metrics.py b/tools/metrics.py index f6189e65abb..8bb96ba119a 100755 --- a/tools/metrics.py +++ b/tools/metrics.py @@ -43,20 +43,23 @@ """ -import collections, sys, re, subprocess +import collections, os, sys, re, shlex, subprocess, multiprocessing -MAKE_FLAGS = ["-j3", "CFLAGS_EXTRA=-DNDEBUG"] +MAKE_FLAGS = ["-j{}".format(multiprocessing.cpu_count()), "CFLAGS_EXTRA=-DNDEBUG"] class PortData: - def __init__(self, name, dir, output, make_flags=None): + def __init__(self, name, dir, output, make_flags=None, pre_cmd=None): self.name = name self.dir = dir self.output = output self.make_flags = make_flags self.needs_mpy_cross = dir not in ("bare-arm", "minimal") + self.pre_cmd = pre_cmd +mpy_cross_output = "mpy-cross/build/mpy-cross" + port_data = { "b": PortData("bare-arm", "bare-arm", "build/firmware.elf"), "m": PortData("minimal x86", "minimal", "build/firmware.elf"), @@ -65,7 +68,12 @@ def __init__(self, name, dir, output, make_flags=None): "s": PortData("stm32", "stm32", "build-PYBV10/firmware.elf", "BOARD=PYBV10"), "c": PortData("cc3200", "cc3200", "build/WIPY/release/application.axf", "BTARGET=application"), "8": PortData("esp8266", "esp8266", "build-ESP8266_GENERIC/firmware.elf"), - "3": PortData("esp32", "esp32", "build-ESP32_GENERIC/micropython.elf"), + "3": PortData( + "esp32", + "esp32", + "build-ESP32_GENERIC/micropython.elf", + pre_cmd=". esp-idf/export.sh", + ), "x": PortData("mimxrt", "mimxrt", "build-TEENSY40/firmware.elf"), "e": PortData("renesas-ra", "renesas-ra", "build-EK_RA6M2/firmware.elf"), "r": PortData("nrf", "nrf", "build-PCA10040/firmware.elf"), @@ -74,8 +82,15 @@ def __init__(self, name, dir, output, make_flags=None): "v": PortData("qemu rv32", "qemu", "build-VIRT_RV32/firmware.elf", "BOARD=VIRT_RV32"), } +for port_letter, port in port_data.items(): + port.pre_cmd = os.environ.get(f"PRE_CMD_{port_letter}", port.pre_cmd) + + +def quoted(args): + return " ".join(shlex.quote(word) for word in args) -def syscmd(*args): + +def syscmd(*args, pre_cmd=None): sys.stdout.flush() a2 = [] for a in args: @@ -83,6 +98,10 @@ def syscmd(*args): a2.append(a) elif a: a2.extend(a) + if pre_cmd is not None: + a2_quoted = quoted(a2) + a2 = ["bash", "-c", "{} && {}".format(pre_cmd, a2_quoted)] + print(a2) subprocess.check_call(a2) @@ -108,6 +127,8 @@ def read_build_log(filename): with open(filename) as f: for line in f: line = line.strip() + if line.startswith("BUILDING ") and "_ref" not in data: + data["_ref"] = line.removeprefix("BUILDING ") if line.strip() == "COMPUTING SIZES": found_sizes = True elif found_sizes: @@ -139,9 +160,15 @@ def do_diff(args): data1 = read_build_log(args[0]) data2 = read_build_log(args[1]) + ref1 = data1.pop("_ref", "(unknown ref)") + ref2 = data2.pop("_ref", "(unknown ref)") + print(f"Reference: {ref1}") + print(f"Comparison: {ref2}") max_delta = None for key, value1 in data1.items(): value2 = data2[key] + if key == mpy_cross_output: + name = "mpy-cross" for port in port_data.values(): if key == "ports/{}/{}".format(port.dir, port.output): name = port.name @@ -181,8 +208,19 @@ def do_clean(args): ports = parse_port_list(args) print("CLEANING") + + if any(port.needs_mpy_cross for port in ports): + syscmd("make", "-C", "mpy-cross", "clean") + for port in ports: - syscmd("make", "-C", "ports/{}".format(port.dir), port.make_flags, "clean") + syscmd( + "make", + "-C", + "ports/{}".format(port.dir), + port.make_flags, + "clean", + pre_cmd=port.pre_cmd, + ) def do_build(args): @@ -196,7 +234,14 @@ def do_build(args): print("BUILDING PORTS") for port in ports: - syscmd("make", "-C", "ports/{}".format(port.dir), MAKE_FLAGS, port.make_flags) + syscmd( + "make", + "-C", + "ports/{}".format(port.dir), + MAKE_FLAGS, + port.make_flags, + pre_cmd=port.pre_cmd, + ) do_sizes(args) @@ -207,6 +252,10 @@ def do_sizes(args): ports = parse_port_list(args) print("COMPUTING SIZES") + + if any(port.needs_mpy_cross for port in ports): + syscmd("size", mpy_cross_output) + for port in ports: syscmd("size", "ports/{}/{}".format(port.dir, port.output)) diff --git a/tools/mpy-tool.py b/tools/mpy-tool.py index 8849f2f1e59..bf0b89018e4 100755 --- a/tools/mpy-tool.py +++ b/tools/mpy-tool.py @@ -24,40 +24,21 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -# Python 2/3/MicroPython compatibility code -from __future__ import print_function +import io +import struct import sys +from binascii import hexlify -if sys.version_info[0] == 2: - from binascii import hexlify as hexlify_py2 - - str_cons = lambda val, enc=None: str(val) - bytes_cons = lambda val, enc=None: bytearray(val) - is_str_type = lambda o: isinstance(o, str) - is_bytes_type = lambda o: type(o) is bytearray - is_int_type = lambda o: isinstance(o, int) or isinstance(o, long) # noqa: F821 - - def hexlify_to_str(b): - x = hexlify_py2(b) - return ":".join(x[i : i + 2] for i in range(0, len(x), 2)) - -elif sys.version_info[0] == 3: # Also handles MicroPython - from binascii import hexlify - - str_cons = str - bytes_cons = bytes - is_str_type = lambda o: isinstance(o, str) - is_bytes_type = lambda o: isinstance(o, bytes) - is_int_type = lambda o: isinstance(o, int) - - def hexlify_to_str(b): - return str(hexlify(b, ":"), "ascii") +str_cons = str +bytes_cons = bytes +is_str_type = lambda o: isinstance(o, str) +is_bytes_type = lambda o: isinstance(o, bytes) +is_int_type = lambda o: isinstance(o, int) -# end compatibility code +def hexlify_to_str(b): + return str(hexlify(b, ":"), "ascii") -import sys -import struct sys.path.append(sys.path[0] + "/../py") import makeqstrdata as qstrutil @@ -114,6 +95,23 @@ class Config: MP_NATIVE_ARCH_XTENSA = 9 MP_NATIVE_ARCH_XTENSAWIN = 10 MP_NATIVE_ARCH_RV32IMC = 11 +MP_NATIVE_ARCH_RV64IMC = 12 + +MP_NATIVE_ARCH_NAMES = [ + "NONE", + "X86", + "X64", + "ARMV6", + "ARMV6M", + "ARMV7M", + "ARMV7EM", + "ARMV7EMSP", + "ARMV7EMDP", + "XTENSA", + "XTENSAWIN", + "RV32IMC", + "RV64IMC", +] MP_PERSISTENT_OBJ_FUN_TABLE = 0 MP_PERSISTENT_OBJ_NONE = 1 @@ -142,6 +140,8 @@ class Config: MP_BC_FORMAT_VAR_UINT = 2 MP_BC_FORMAT_OFFSET = 3 +MP_NATIVE_ARCH_FLAGS_PRESENT = 0x40 + mp_unary_op_method_name = ( "__pos__", "__neg__", @@ -306,6 +306,25 @@ class Opcode: MP_BC_POP_JUMP_IF_TRUE, MP_BC_POP_JUMP_IF_FALSE, ) + ALL_OFFSET = ( + MP_BC_UNWIND_JUMP, + MP_BC_JUMP, + MP_BC_POP_JUMP_IF_TRUE, + MP_BC_POP_JUMP_IF_FALSE, + MP_BC_JUMP_IF_TRUE_OR_POP, + MP_BC_JUMP_IF_FALSE_OR_POP, + MP_BC_SETUP_WITH, + MP_BC_SETUP_EXCEPT, + MP_BC_SETUP_FINALLY, + MP_BC_POP_EXCEPT_JUMP, + MP_BC_FOR_ITER, + ) + ALL_WITH_CHILD = ( + MP_BC_MAKE_FUNCTION, + MP_BC_MAKE_FUNCTION_DEFARGS, + MP_BC_MAKE_CLOSURE, + MP_BC_MAKE_CLOSURE_DEFARGS, + ) # Create a dict mapping opcode value to opcode name. mapping = ["unknown" for _ in range(256)] @@ -562,6 +581,7 @@ def __init__( mpy_source_file, mpy_segments, header, + arch_flags, qstr_table, obj_table, raw_code, @@ -574,6 +594,7 @@ def __init__( self.mpy_segments = mpy_segments self.source_file = qstr_table[0] self.header = header + self.arch_flags = arch_flags self.qstr_table = qstr_table self.obj_table = obj_table self.raw_code = raw_code @@ -651,6 +672,14 @@ def disassemble(self): print("mpy_source_file:", self.mpy_source_file) print("source_file:", self.source_file.str) print("header:", hexlify_to_str(self.header)) + arch_index = (self.header[2] >> 2) & 0x2F + if arch_index >= len(MP_NATIVE_ARCH_NAMES): + arch_name = "UNKNOWN" + else: + arch_name = MP_NATIVE_ARCH_NAMES[arch_index] + print("arch:", arch_name) + if self.header[2] & MP_NATIVE_ARCH_FLAGS_PRESENT != 0: + print("arch_flags:", hex(self.arch_flags)) print("qstr_table[%u]:" % len(self.qstr_table)) for q in self.qstr_table: print(" %s" % q.str) @@ -888,7 +917,7 @@ def __init__(self, parent_name, qstr_table, fun_data, prelude_offset, code_kind) self.escaped_name = unique_escaped_name def disassemble_children(self): - print(" children:", [rc.simple_name.str for rc in self.children]) + self.print_children_annotated() for rc in self.children: rc.disassemble() @@ -980,6 +1009,75 @@ def freeze_raw_code(self, prelude_ptr=None, type_sig=0): raw_code_count += 1 raw_code_content += 4 * 4 + @staticmethod + def decode_lineinfo(line_info: memoryview) -> "tuple[int, int, memoryview]": + c = line_info[0] + if (c & 0x80) == 0: + # 0b0LLBBBBB encoding + return (c & 0x1F), (c >> 5), line_info[1:] + else: + # 0b1LLLBBBB 0bLLLLLLLL encoding (l's LSB in second byte) + return (c & 0xF), (((c << 4) & 0x700) | line_info[1]), line_info[2:] + + def get_source_annotation(self, ip: int, file=None) -> dict: + bc_offset = ip - self.offset_opcodes + try: + line_info = memoryview(self.fun_data)[self.offset_line_info : self.offset_opcodes] + except AttributeError: + return {"file": file, "line": None} + + source_line = 1 + while line_info: + bc_increment, line_increment, line_info = self.decode_lineinfo(line_info) + if bc_offset >= bc_increment: + bc_offset -= bc_increment + source_line += line_increment + else: + break + + return {"file": file, "line": source_line} + + def get_label(self, ip: "int | None" = None, child_num: "int | None" = None) -> str: + if ip is not None: + assert child_num is None + return "%s.%d" % (self.escaped_name, ip) + elif child_num is not None: + return "%s.child%d" % (self.escaped_name, child_num) + else: + return "%s" % self.escaped_name + + def print_children_annotated(self) -> None: + """ + Equivalent to `print(" children:", [child.simple_name.str for child in self.children])`, + but also includes json markers for the start and end of each one's name in that line. + """ + + labels = ["%s.children" % self.escaped_name] + annotation_labels = [] + output = io.StringIO() + output.write(" children: [") + sep = ", " + for i, child in enumerate(self.children): + if i != 0: + output.write(sep) + start_col = output.tell() + 1 + output.write(child.simple_name.str) + end_col = output.tell() + 1 + labels.append(self.get_label(child_num=i)) + annotation_labels.append( + { + "name": self.get_label(child_num=i), + "target": child.get_label(), + "range": { + "startCol": start_col, + "endCol": end_col, + }, + }, + ) + output.write("]") + + print(output.getvalue(), annotations={"labels": annotation_labels}, labels=labels) + class RawCodeBytecode(RawCode): def __init__(self, parent_name, qstr_table, obj_table, fun_data): @@ -988,9 +1086,58 @@ def __init__(self, parent_name, qstr_table, obj_table, fun_data): parent_name, qstr_table, fun_data, 0, MP_CODE_BYTECODE ) + def get_opcode_annotations_labels( + self, opcode: int, ip: int, arg: int, sz: int, arg_pos: int, arg_len: int + ) -> "tuple[dict, list[str]]": + annotations = { + "source": self.get_source_annotation(ip), + "disassembly": Opcode.mapping[opcode], + } + labels = [self.get_label(ip)] + + if opcode in Opcode.ALL_OFFSET: + annotations["link"] = { + "offset": arg_pos, + "length": arg_len, + "to": ip + arg + sz, + } + annotations["labels"] = [ + { + "name": self.get_label(ip), + "target": self.get_label(ip + arg + sz), + "range": { + "startCol": arg_pos + 1, + "endCol": arg_pos + arg_len + 1, + }, + }, + ] + + elif opcode in Opcode.ALL_WITH_CHILD: + try: + child = self.children[arg] + except IndexError: + # link out-of-range child to the child array itself + target = "%s.children" % self.escaped_name + else: + # link resolvable child to the actual child + target = child.get_label() + + annotations["labels"] = [ + { + "name": self.get_label(ip), + "target": target, + "range": { + "startCol": arg_pos + 1, + "endCol": arg_pos + arg_len + 1, + }, + }, + ] + + return annotations, labels + def disassemble(self): bc = self.fun_data - print("simple_name:", self.simple_name.str) + print("simple_name:", self.simple_name.str, labels=[self.get_label()]) print(" raw bytecode:", len(bc), hexlify_to_str(bc)) print(" prelude:", self.prelude_signature) print(" args:", [self.qstr_table[i].str for i in self.names[1:]]) @@ -1006,9 +1153,22 @@ def disassemble(self): pass else: arg = "" - print( - " %-11s %s %s" % (hexlify_to_str(bc[ip : ip + sz]), Opcode.mapping[bc[ip]], arg) + + pre_arg_part = " %-11s %s" % ( + hexlify_to_str(bc[ip : ip + sz]), + Opcode.mapping[bc[ip]], + ) + arg_part = "%s" % arg + annotations, labels = self.get_opcode_annotations_labels( + opcode=bc[ip], + ip=ip, + arg=arg, + sz=sz, + arg_pos=len(pre_arg_part) + 1, + arg_len=len(arg_part), ) + + print(pre_arg_part, arg_part, annotations=annotations, labels=labels) ip += sz self.disassemble_children() @@ -1085,6 +1245,7 @@ def __init__( MP_NATIVE_ARCH_XTENSA, MP_NATIVE_ARCH_XTENSAWIN, MP_NATIVE_ARCH_RV32IMC, + MP_NATIVE_ARCH_RV64IMC, ): self.fun_data_attributes = '__attribute__((section(".text,\\"ax\\",@progbits # ")))' else: @@ -1102,13 +1263,13 @@ def __init__( self.fun_data_attributes += " __attribute__ ((aligned (4)))" elif ( MP_NATIVE_ARCH_ARMV6M <= config.native_arch <= MP_NATIVE_ARCH_ARMV7EMDP - ) or config.native_arch == MP_NATIVE_ARCH_RV32IMC: - # ARMVxxM or RV32IMC -- two byte align. + ) or MP_NATIVE_ARCH_RV32IMC <= config.native_arch <= MP_NATIVE_ARCH_RV64IMC: + # ARMVxxM or RV{32,64}IMC -- two byte align. self.fun_data_attributes += " __attribute__ ((aligned (2)))" def disassemble(self): fun_data = self.fun_data - print("simple_name:", self.simple_name.str) + print("simple_name:", self.simple_name.str, labels=[self.get_label()]) print( " raw data:", len(fun_data), @@ -1362,7 +1523,7 @@ def read_mpy(filename): if header[1] != config.MPY_VERSION: raise MPYReadError(filename, "incompatible .mpy version") feature_byte = header[2] - mpy_native_arch = feature_byte >> 2 + mpy_native_arch = (feature_byte >> 2) & 0x2F if mpy_native_arch != MP_NATIVE_ARCH_NONE: mpy_sub_version = feature_byte & 3 if mpy_sub_version != config.MPY_SUB_VERSION: @@ -1373,6 +1534,11 @@ def read_mpy(filename): raise MPYReadError(filename, "native architecture mismatch") config.mp_small_int_bits = header[3] + arch_flags = 0 + # Read the architecture-specific flag bits if present. + if (feature_byte & MP_NATIVE_ARCH_FLAGS_PRESENT) != 0: + arch_flags = reader.read_uint() + # Read number of qstrs, and number of objects. n_qstr = reader.read_uint() n_obj = reader.read_uint() @@ -1401,6 +1567,7 @@ def read_mpy(filename): filename, segments, header, + arch_flags, qstr_table, obj_table, raw_code, @@ -1696,26 +1863,40 @@ def merge_mpy(compiled_modules, output_file): merged_mpy.extend(f.read()) else: main_cm_idx = None + arch_flags = 0 for idx, cm in enumerate(compiled_modules): feature_byte = cm.header[2] - mpy_native_arch = feature_byte >> 2 + mpy_native_arch = (feature_byte >> 2) & 0x2F if mpy_native_arch: # Must use qstr_table and obj_table from this raw_code if main_cm_idx is not None: raise Exception("can't merge files when more than one contains native code") main_cm_idx = idx + arch_flags = cm.arch_flags if main_cm_idx is not None: # Shift main_cm to front of list. compiled_modules.insert(0, compiled_modules.pop(main_cm_idx)) + if config.arch_flags is not None: + arch_flags = config.arch_flags + header = bytearray(4) ## CIRCUITPY-CHANGE: "C" is used for CircuitPython header[0] = ord("C") header[1] = config.MPY_VERSION - header[2] = config.native_arch << 2 | config.MPY_SUB_VERSION if config.native_arch else 0 + header[2] = ( + (MP_NATIVE_ARCH_FLAGS_PRESENT if arch_flags != 0 else 0) + | config.native_arch << 2 + | config.MPY_SUB_VERSION + if config.native_arch + else 0 + ) header[3] = config.mp_small_int_bits merged_mpy.extend(header) + if arch_flags != 0: + merged_mpy.extend(mp_encode_uint(arch_flags)) + n_qstr = 0 n_obj = 0 for cm in compiled_modules: @@ -1771,6 +1952,138 @@ def copy_section(file, offset, offset2): f.write(merged_mpy) +def extract_segments(compiled_modules, basename, kinds_arg): + import re + + kind_str = ("META", "QSTR", "OBJ", "CODE") + kinds = set() + if kinds_arg is not None: + for kind in kinds_arg.upper().split(","): + if kind in kind_str: + kinds.add(kind) + else: + raise Exception('unknown segment kind "%s"' % (kind,)) + segments = [] + for module in compiled_modules: + for segment in module.mpy_segments: + if not kinds or kind_str[segment.kind] in kinds: + segments.append((module.mpy_source_file, module.source_file.str, segment)) + count_len = len(str(len(segments))) + sanitiser = re.compile("[^a-zA-Z0-9_.-]") + for counter, entry in enumerate(segments): + file_name, source_file, segment = entry + output_name = ( + basename + + "_" + + str(counter).rjust(count_len, "0") + + "_" + + sanitiser.sub("_", source_file) + + "_" + + kind_str[segment.kind] + + "_" + + sanitiser.sub("_", str(segment.name)) + + ".bin" + ) + with open(file_name, "rb") as source: + with open(output_name, "wb") as output: + source.seek(segment.start) + output.write(source.read(segment.end - segment.start)) + + +class PrintShim: + """Base class for interposing extra functionality onto the global `print` method.""" + + def __init__(self): + self.wrapped_print = None + + def __enter__(self): + global print + + if self.wrapped_print is not None: + raise RecursionError + + self.wrapped_print = print + print = self + + return self + + def __exit__(self, exc_type, exc_value, traceback): + global print + + if self.wrapped_print is None: + return + + print = self.wrapped_print + self.wrapped_print = None + + self.on_exit() + + def on_exit(self): + pass + + def __call__(self, *a, **k): + return self.wrapped_print(*a, **k) + + +class PrintIgnoreExtraArgs(PrintShim): + """Just strip the `annotations` and `labels` kwargs and pass down to the underlying print.""" + + def __call__(self, *a, annotations: dict = {}, labels: "list[str]" = (), **k): + return super().__call__(*a, **k) + + +class PrintJson(PrintShim): + """Output lines as godbolt-compatible JSON with extra annotation info from `annotations` and `labels`, rather than plain text.""" + + def __init__(self, fp=sys.stdout, language_id: str = "mpy"): + super().__init__() + self.fp = fp + self.asm = { + "asm": [], + "labelDefinitions": {}, + "languageId": language_id, + } + self.line_number: int = 0 + self.buf: "io.StringIO | None" = None + + def on_exit(self): + import json + + if self.buf is not None: + # flush last partial line + self.__call__() + + json.dump(self.asm, self.fp) + + def __call__(self, *a, annotations: dict = {}, labels: "list[str]" = (), **k): + # ignore prints directed to an explicit output + if "file" in k: + return super().__call__(*a, **k) + + if self.buf is None: + self.buf = io.StringIO() + + super().__call__(*a, file=sys.stderr, **k) + + if "end" in k: + # buffer partial-line prints to collect into a single AsmResultLine + return super().__call__(*a, file=self.buf, **k) + else: + retval = super().__call__(*a, file=self.buf, end="", **k) + output = self.buf.getvalue() + self.buf = None + + asm_line = {"text": output} + asm_line.update(annotations) + self.asm["asm"].append(asm_line) + + self.line_number += 1 + for label in labels: + self.asm["labelDefinitions"][label] = self.line_number + + return retval + + def main(args=None): global global_qstrs @@ -1784,9 +2097,23 @@ def main(args=None): "-d", "--disassemble", action="store_true", help="output disassembled contents of files" ) cmd_parser.add_argument("-f", "--freeze", action="store_true", help="freeze files") + cmd_parser.add_argument( + "-j", + "--json", + action="store_true", + help="output hexdump, disassembly, and frozen code as JSON with extra metadata", + ) cmd_parser.add_argument( "--merge", action="store_true", help="merge multiple .mpy files into one" ) + cmd_parser.add_argument( + "-e", "--extract", metavar="BASE", type=str, help="write segments into separate files" + ) + cmd_parser.add_argument( + "--extract-only", + metavar="KIND[,...]", + help="extract only segments of the given type (meta, qstr, obj, code)", + ) cmd_parser.add_argument("-q", "--qstr-header", help="qstr header file to freeze against") cmd_parser.add_argument( "-mlongint-impl", @@ -1801,6 +2128,12 @@ def main(args=None): default=16, help="mpz digit size used by target (default 16)", ) + cmd_parser.add_argument( + "-march-flags", + metavar="F", + type=int, + help="architecture flags value to set in the output file (strips existing flags if not present)", + ) cmd_parser.add_argument("-o", "--output", default=None, help="output file") cmd_parser.add_argument("files", nargs="+", help="input .mpy files") args = cmd_parser.parse_args(args) @@ -1813,6 +2146,7 @@ def main(args=None): }[args.mlongint_impl] config.MPZ_DIG_SIZE = args.mmpz_dig_size config.native_arch = MP_NATIVE_ARCH_NONE + config.arch_flags = args.march_flags # set config values for qstrs, and get the existing base set of qstrs # already in the firmware @@ -1836,24 +2170,40 @@ def main(args=None): print(er, file=sys.stderr) sys.exit(1) - if args.hexdump: - hexdump_mpy(compiled_modules) + if args.json: + if args.freeze: + print_shim = PrintJson(sys.stdout, language_id="c") + elif args.hexdump: + print_shim = PrintJson(sys.stdout, language_id="stderr") + elif args.disassemble: + print_shim = PrintJson(sys.stdout, language_id="mpy") + else: + print_shim = PrintJson(sys.stdout) + else: + print_shim = PrintIgnoreExtraArgs() - if args.disassemble: + with print_shim: if args.hexdump: - print() - disassemble_mpy(compiled_modules) + hexdump_mpy(compiled_modules) - if args.freeze: - try: - freeze_mpy(firmware_qstr_idents, compiled_modules) - except FreezeError as er: - print(er, file=sys.stderr) - sys.exit(1) + if args.disassemble: + if args.hexdump: + print() + disassemble_mpy(compiled_modules) + + if args.freeze: + try: + freeze_mpy(firmware_qstr_idents, compiled_modules) + except FreezeError as er: + print(er, file=sys.stderr) + sys.exit(1) if args.merge: merge_mpy(compiled_modules, args.output) + if args.extract: + extract_segments(compiled_modules, args.extract, args.extract_only) + if __name__ == "__main__": main() diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 219cd1a7468..26db0726163 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -402,6 +402,7 @@ def __init__(self, arch): self.known_syms = {} # dict of symbols that are defined self.unresolved_syms = [] # list of unresolved symbols self.mpy_relocs = [] # list of relocations needed in the output .mpy file + self.externs = {} # dict of externally-defined symbols def check_arch(self, arch_name): if arch_name != self.arch.name: @@ -491,10 +492,14 @@ def populate_got(env): sym = got_entry.sym if hasattr(sym, "resolved"): sym = sym.resolved - sec = sym.section - addr = sym["st_value"] - got_entry.sec_name = sec.name - got_entry.link_addr += sec.addr + addr + if sym.name in env.externs: + got_entry.sec_name = ".external.fixed_addr" + got_entry.link_addr = env.externs[sym.name] + else: + sec = sym.section + addr = sym["st_value"] + got_entry.sec_name = sec.name + got_entry.link_addr += sec.addr + addr # Get sorted GOT, sorted by external, text, rodata, bss so relocations can be combined got_list = sorted( @@ -520,6 +525,9 @@ def populate_got(env): dest = int(got_entry.name.split("+")[1], 16) // env.arch.word_size elif got_entry.sec_name == ".external.mp_fun_table": dest = got_entry.sym.mp_fun_table_offset + elif got_entry.sec_name == ".external.fixed_addr": + # Fixed-address symbols should not be relocated. + continue elif got_entry.sec_name.startswith(".text"): dest = ".text" elif got_entry.sec_name.startswith(".rodata"): @@ -703,8 +711,9 @@ def do_relocation_text(env, text_addr, r): (addr, value) = process_riscv32_relocation(env, text_addr, r) elif env.arch.name == "EM_ARM" and r_info_type == R_ARM_ABS32: - # happens for soft-float on armv6m - raise ValueError("Absolute relocations not supported on ARM") + # Absolute relocation, handled as a data relocation. + do_relocation_data(env, text_addr, r) + return else: # Unknown/unsupported relocation @@ -773,9 +782,9 @@ def do_relocation_data(env, text_addr, r): ): # Relocation in data.rel.ro to internal/external symbol if env.arch.word_size == 4: - struct_type = "/). + + symbols = {} + + LINE_REGEX = re.compile( + r"^(?PPROVIDE\()?" # optional weak marker start + r"(?P[a-zA-Z_]\w*)" # symbol name + r"=0x(?P
[\da-fA-F]{1,8})*" # symbol address + r"(?(weak)\));$", # optional weak marker end and line terminator + re.ASCII, + ) + + inside_comment = False + for line in (line.strip() for line in source.readlines()): + if line.startswith("/*") and not inside_comment: + if not line.endswith("*/"): + inside_comment = True + continue + if inside_comment: + if line.endswith("*/"): + inside_comment = False + continue + if line.startswith("//"): + continue + match = LINE_REGEX.match("".join(line.split())) + if not match: + continue + tokens = match.groupdict() + symbol = tokens["symbol"] + address = int(tokens["address"], 16) + if symbol in symbols: + raise ValueError(f"Symbol {symbol} already defined") + symbols[symbol] = address + return symbols + + def main(): import argparse @@ -1501,6 +1569,13 @@ def main(): cmd_parser.add_argument( "--output", "-o", default=None, help="output .mpy file (default to input with .o->.mpy)" ) + cmd_parser.add_argument( + "--externs", + "-e", + type=argparse.FileType("rt"), + default=None, + help="linkerscript providing fixed-address symbols to augment symbol resolution", + ) cmd_parser.add_argument("files", nargs="+", help="input files") args = cmd_parser.parse_args() diff --git a/tools/pyboard.py b/tools/pyboard.py index 20310ba7081..c9f65d5d873 100755 --- a/tools/pyboard.py +++ b/tools/pyboard.py @@ -248,14 +248,22 @@ def inWaiting(self): class Pyboard: def __init__( - self, device, baudrate=115200, user="micro", password="python", wait=0, exclusive=True + self, + device, + baudrate=115200, + user="micro", + password="python", + wait=0, + exclusive=True, + timeout=None, + write_timeout=5, ): self.in_raw_repl = False self.use_raw_paste = True if device.startswith("exec:"): self.serial = ProcessToSerial(device[len("exec:") :]) elif device.startswith("execpty:"): - self.serial = ProcessPtyToTerminal(device[len("qemupty:") :]) + self.serial = ProcessPtyToTerminal(device[len("execpty:") :]) elif device and device[0].isdigit() and device[-1].isdigit() and device.count(".") == 3: # device looks like an IP address self.serial = TelnetToSerial(device, user, password, read_timeout=10) @@ -264,7 +272,12 @@ def __init__( import serial.tools.list_ports # Set options, and exclusive if pyserial supports it - serial_kwargs = {"baudrate": baudrate, "interCharTimeout": 1} + serial_kwargs = { + "baudrate": baudrate, + "timeout": timeout, + "write_timeout": write_timeout, + "interCharTimeout": 1, + } if serial.__version__ >= "3.3": serial_kwargs["exclusive"] = exclusive @@ -304,14 +317,25 @@ def __init__( def close(self): self.serial.close() - def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): - # if data_consumer is used then data is not accumulated and the ending must be 1 byte long + def read_until( + self, min_num_bytes, ending, timeout=10, data_consumer=None, timeout_overall=None + ): + """ + min_num_bytes: Obsolete. + ending: Return if 'ending' matches. + timeout [s]: Return if timeout between characters. None: Infinite timeout. + timeout_overall [s]: Return not later than timeout_overall. None: Infinite timeout. + data_consumer: Use callback for incoming characters. + If data_consumer is used then data is not accumulated and the ending must be 1 byte long + + It is not visible to the caller why the function returned. It could be ending or timeout. + """ assert data_consumer is None or len(ending) == 1 + assert isinstance(timeout, (type(None), int, float)) + assert isinstance(timeout_overall, (type(None), int, float)) - data = self.serial.read(min_num_bytes) - if data_consumer: - data_consumer(data) - timeout_count = 0 + data = b"" + begin_overall_s = begin_char_s = time.monotonic() while True: if data.endswith(ending): break @@ -322,15 +346,25 @@ def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None): data = new_data else: data = data + new_data - timeout_count = 0 + begin_char_s = time.monotonic() else: - timeout_count += 1 - if timeout is not None and timeout_count >= 100 * timeout: + if timeout is not None and time.monotonic() >= begin_char_s + timeout: + break + if ( + timeout_overall is not None + and time.monotonic() >= begin_overall_s + timeout_overall + ): break time.sleep(0.01) return data - def enter_raw_repl(self, soft_reset=True): + def enter_raw_repl(self, soft_reset=True, timeout_overall=10): + try: + self._enter_raw_repl_unprotected(soft_reset, timeout_overall) + except OSError as er: + raise PyboardError("could not enter raw repl: {}".format(er)) + + def _enter_raw_repl_unprotected(self, soft_reset, timeout_overall): self.serial.write(b"\r\x03") # ctrl-C: interrupt any running program # flush input (without relying on serial.flushInput()) @@ -342,7 +376,9 @@ def enter_raw_repl(self, soft_reset=True): self.serial.write(b"\r\x01") # ctrl-A: enter raw REPL if soft_reset: - data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n>") + data = self.read_until( + 1, b"raw REPL; CTRL-B to exit\r\n>", timeout_overall=timeout_overall + ) if not data.endswith(b"raw REPL; CTRL-B to exit\r\n>"): print(data) raise PyboardError("could not enter raw repl") @@ -352,12 +388,12 @@ def enter_raw_repl(self, soft_reset=True): # Waiting for "soft reboot" independently to "raw REPL" (done below) # allows boot.py to print, which will show up after "soft reboot" # and before "raw REPL". - data = self.read_until(1, b"soft reboot\r\n") + data = self.read_until(1, b"soft reboot\r\n", timeout_overall=timeout_overall) if not data.endswith(b"soft reboot\r\n"): print(data) raise PyboardError("could not enter raw repl") - data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n") + data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n", timeout_overall=timeout_overall) if not data.endswith(b"raw REPL; CTRL-B to exit\r\n"): print(data) raise PyboardError("could not enter raw repl") @@ -475,8 +511,8 @@ def eval(self, expression, parse=False): return ret # In Python3, call as pyboard.exec(), see the setattr call below. - def exec_(self, command, data_consumer=None): - ret, ret_err = self.exec_raw(command, data_consumer=data_consumer) + def exec_(self, command, timeout=10, data_consumer=None): + ret, ret_err = self.exec_raw(command, timeout, data_consumer) if ret_err: raise PyboardError("exception", ret, ret_err) return ret diff --git a/tools/pydfu.py b/tools/pydfu.py index cd7354818cd..376c697cbd5 100755 --- a/tools/pydfu.py +++ b/tools/pydfu.py @@ -11,8 +11,6 @@ See document UM0391 for a description of the DFuse file. """ -from __future__ import print_function - import argparse import collections import inspect @@ -75,11 +73,7 @@ # USB DFU interface __DFU_INTERFACE = 0 -# Python 3 deprecated getargspec in favour of getfullargspec, but -# Python 2 doesn't have the latter, so detect which one to use -getargspec = getattr(inspect, "getfullargspec", getattr(inspect, "getargspec", None)) - -if "length" in getargspec(usb.util.get_string).args: +if "length" in inspect.getfullargspec(usb.util.get_string).args: # PyUSB 1.0.0.b1 has the length argument def get_string(dev, index): return usb.util.get_string(dev, 255, index) diff --git a/tools/verifygitlog.py b/tools/verifygitlog.py index 67215d5c5d0..dba6ebd6de5 100755 --- a/tools/verifygitlog.py +++ b/tools/verifygitlog.py @@ -96,20 +96,47 @@ def verify_message_body(raw_body, err): if len(subject_line) >= 73: err.error("Subject line must be 72 or fewer characters: " + subject_line) + # Do additional checks on the prefix of the subject line. + verify_subject_line_prefix(subject_line.split(": ")[0], err) + # Second one divides subject and body. if len(raw_body) > 1 and raw_body[1]: err.error("Second message line must be empty: " + raw_body[1]) # Message body lines. for line in raw_body[2:]: - # Long lines with URLs are exempt from the line length rule. - if len(line) >= 76 and "://" not in line: + # Long lines with URLs or human names are exempt from the line length rule. + if len(line) >= 76 and not ( + "://" in line + or line.startswith("Co-authored-by: ") + or line.startswith("Signed-off-by: ") + ): err.error("Message lines should be 75 or less characters: " + line) if not raw_body[-1].startswith("Signed-off-by: ") or "@" not in raw_body[-1]: err.error('Message must be signed-off. Use "git commit -s".') +def verify_subject_line_prefix(prefix, err): + ext = (".c", ".h", ".cpp", ".js", ".rst", ".md") + + if prefix.startswith((".", "/")): + err.error('Subject prefix cannot begin with "." or "/".') + + if prefix.endswith("/"): + err.error('Subject prefix cannot end with "/".') + + if prefix.startswith("ports/"): + err.error( + 'Subject prefix cannot begin with "ports/", start with the name of the port instead.' + ) + + if prefix.endswith(ext): + err.error( + "Subject prefix cannot end with a file extension, use the main part of the filename without the extension." + ) + + def run(args): verbose("run", *args) From 0208aa96cc7891f43333ab69c8462c6a39590348 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Fri, 27 Mar 2026 16:36:09 -0700 Subject: [PATCH 347/876] add new audiotools.SpeedChanger module for WAV/MP3 speed changing --- ports/raspberrypi/mpconfigport.mk | 1 + py/circuitpy_defns.mk | 5 + shared-bindings/audiotools/SpeedChanger.c | 138 +++++++++++++++++ shared-bindings/audiotools/SpeedChanger.h | 17 +++ shared-bindings/audiotools/__init__.c | 28 ++++ shared-bindings/audiotools/__init__.h | 7 + shared-module/audiotools/SpeedChanger.c | 175 ++++++++++++++++++++++ shared-module/audiotools/SpeedChanger.h | 35 +++++ shared-module/audiotools/__init__.c | 5 + shared-module/audiotools/__init__.h | 7 + 10 files changed, 418 insertions(+) create mode 100644 shared-bindings/audiotools/SpeedChanger.c create mode 100644 shared-bindings/audiotools/SpeedChanger.h create mode 100644 shared-bindings/audiotools/__init__.c create mode 100644 shared-bindings/audiotools/__init__.h create mode 100644 shared-module/audiotools/SpeedChanger.c create mode 100644 shared-module/audiotools/SpeedChanger.h create mode 100644 shared-module/audiotools/__init__.c create mode 100644 shared-module/audiotools/__init__.h diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 8401c5d7545..b8fc084322d 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -11,6 +11,7 @@ CIRCUITPY_FLOPPYIO ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_DISPLAYIO) CIRCUITPY_FULL_BUILD ?= 1 CIRCUITPY_AUDIOMP3 ?= 1 +CIRCUITPY_AUDIOTOOLS ?= 1 CIRCUITPY_BITOPS ?= 1 CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 886ba96f3e5..7e84d528c26 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -146,6 +146,9 @@ endif ifeq ($(CIRCUITPY_AUDIOMP3),1) SRC_PATTERNS += audiomp3/% endif +ifeq ($(CIRCUITPY_AUDIOTOOLS),1) +SRC_PATTERNS += audiotools/% +endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% endif @@ -688,6 +691,8 @@ SRC_SHARED_MODULE_ALL = \ audiocore/RawSample.c \ audiocore/WaveFile.c \ audiocore/__init__.c \ + audiotools/SpeedChanger.c \ + audiotools/__init__.c \ audiodelays/Echo.c \ audiodelays/Chorus.c \ audiodelays/PitchShift.c \ diff --git a/shared-bindings/audiotools/SpeedChanger.c b/shared-bindings/audiotools/SpeedChanger.c new file mode 100644 index 00000000000..ac46eb1dbc8 --- /dev/null +++ b/shared-bindings/audiotools/SpeedChanger.c @@ -0,0 +1,138 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/audiotools/SpeedChanger.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/util.h" +#include "shared-module/audiotools/SpeedChanger.h" + +// Convert a Python float to 16.16 fixed-point rate +static uint32_t rate_to_fp(mp_obj_t rate_obj) { + mp_float_t rate = mp_arg_validate_obj_float_range(rate_obj, 0.001, 1000.0, MP_QSTR_rate); + return (uint32_t)(rate * (1 << 16)); +} + +// Convert 16.16 fixed-point rate to Python float +static mp_obj_t fp_to_rate(uint32_t rate_fp) { + return mp_obj_new_float((mp_float_t)rate_fp / (1 << 16)); +} + +//| class SpeedChanger: +//| """Wraps an audio sample to play it back at a different speed. +//| +//| Uses nearest-neighbor resampling with a fixed-point phase accumulator +//| for CPU-efficient variable-speed playback.""" +//| +//| def __init__(self, source: audiosample, rate: float = 1.0) -> None: +//| """Create a SpeedChanger that wraps ``source``. +//| +//| :param audiosample source: The audio source to resample. +//| :param float rate: Playback speed multiplier. 1.0 = normal, 2.0 = double speed, +//| 0.5 = half speed. Must be positive. +//| +//| Playing a wave file at 1.5x speed:: +//| +//| import board +//| import audiocore +//| import audiotools +//| import audioio +//| +//| wav = audiocore.WaveFile("drum.wav") +//| fast = audiotools.SpeedChanger(wav, rate=1.5) +//| audio = audioio.AudioOut(board.A0) +//| audio.play(fast) +//| +//| # Change speed during playback: +//| fast.rate = 2.0 # double speed +//| fast.rate = 0.5 # half speed +//| """ +//| ... +//| +static mp_obj_t audiotools_speedchanger_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_source, ARG_rate }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_rate, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Validate source implements audiosample protocol + mp_obj_t source = args[ARG_source].u_obj; + audiosample_check(source); + + uint32_t rate_fp = 1 << 16; // default 1.0 + if (args[ARG_rate].u_obj != mp_const_none) { + rate_fp = rate_to_fp(args[ARG_rate].u_obj); + } + + audiotools_speedchanger_obj_t *self = mp_obj_malloc(audiotools_speedchanger_obj_t, &audiotools_speedchanger_type); + common_hal_audiotools_speedchanger_construct(self, source, rate_fp); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the SpeedChanger and releases all memory resources for reuse.""" +//| ... +//| +static mp_obj_t audiotools_speedchanger_deinit(mp_obj_t self_in) { + audiotools_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiotools_speedchanger_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiotools_speedchanger_deinit_obj, audiotools_speedchanger_deinit); + +//| rate: float +//| """Playback speed multiplier. Can be changed during playback.""" +//| +static mp_obj_t audiotools_speedchanger_obj_get_rate(mp_obj_t self_in) { + audiotools_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(&self->base); + return fp_to_rate(common_hal_audiotools_speedchanger_get_rate(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiotools_speedchanger_get_rate_obj, audiotools_speedchanger_obj_get_rate); + +static mp_obj_t audiotools_speedchanger_obj_set_rate(mp_obj_t self_in, mp_obj_t rate_obj) { + audiotools_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(&self->base); + common_hal_audiotools_speedchanger_set_rate(self, rate_to_fp(rate_obj)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiotools_speedchanger_set_rate_obj, audiotools_speedchanger_obj_set_rate); + +MP_PROPERTY_GETSET(audiotools_speedchanger_rate_obj, + (mp_obj_t)&audiotools_speedchanger_get_rate_obj, + (mp_obj_t)&audiotools_speedchanger_set_rate_obj); + +static const mp_rom_map_elem_t audiotools_speedchanger_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiotools_speedchanger_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiotools_speedchanger_rate_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(audiotools_speedchanger_locals_dict, audiotools_speedchanger_locals_dict_table); + +static const audiosample_p_t audiotools_speedchanger_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiotools_speedchanger_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiotools_speedchanger_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiotools_speedchanger_type, + MP_QSTR_SpeedChanger, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiotools_speedchanger_make_new, + locals_dict, &audiotools_speedchanger_locals_dict, + protocol, &audiotools_speedchanger_proto + ); diff --git a/shared-bindings/audiotools/SpeedChanger.h b/shared-bindings/audiotools/SpeedChanger.h new file mode 100644 index 00000000000..d31ae6d6bdc --- /dev/null +++ b/shared-bindings/audiotools/SpeedChanger.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiotools/SpeedChanger.h" + +extern const mp_obj_type_t audiotools_speedchanger_type; + +void common_hal_audiotools_speedchanger_construct(audiotools_speedchanger_obj_t *self, + mp_obj_t source, uint32_t rate_fp); +void common_hal_audiotools_speedchanger_deinit(audiotools_speedchanger_obj_t *self); +void common_hal_audiotools_speedchanger_set_rate(audiotools_speedchanger_obj_t *self, uint32_t rate_fp); +uint32_t common_hal_audiotools_speedchanger_get_rate(audiotools_speedchanger_obj_t *self); diff --git a/shared-bindings/audiotools/__init__.c b/shared-bindings/audiotools/__init__.c new file mode 100644 index 00000000000..3d610aa1dbf --- /dev/null +++ b/shared-bindings/audiotools/__init__.c @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/audiotools/SpeedChanger.h" + +//| """Audio processing tools""" + +static const mp_rom_map_elem_t audiotools_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiotools) }, + { MP_ROM_QSTR(MP_QSTR_SpeedChanger), MP_ROM_PTR(&audiotools_speedchanger_type) }, +}; + +static MP_DEFINE_CONST_DICT(audiotools_module_globals, audiotools_module_globals_table); + +const mp_obj_module_t audiotools_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&audiotools_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_audiotools, audiotools_module); diff --git a/shared-bindings/audiotools/__init__.h b/shared-bindings/audiotools/__init__.h new file mode 100644 index 00000000000..c4a52e5819d --- /dev/null +++ b/shared-bindings/audiotools/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-module/audiotools/SpeedChanger.c b/shared-module/audiotools/SpeedChanger.c new file mode 100644 index 00000000000..2bf03cf1aa9 --- /dev/null +++ b/shared-module/audiotools/SpeedChanger.c @@ -0,0 +1,175 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiotools/SpeedChanger.h" + +#include +#include "py/runtime.h" +#include "py/gc.h" + +#include "shared-module/audiocore/WaveFile.h" +#include "shared-bindings/audiocore/__init__.h" + +#define OUTPUT_BUFFER_FRAMES 128 + +void common_hal_audiotools_speedchanger_construct(audiotools_speedchanger_obj_t *self, + mp_obj_t source, uint32_t rate_fp) { + audiosample_base_t *src_base = audiosample_check(source); + + self->source = source; + self->rate_fp = rate_fp; + self->phase = 0; + self->src_buffer = NULL; + self->src_buffer_length = 0; + self->src_sample_count = 0; + self->source_done = false; + self->source_exhausted = false; + + // Copy format from source + self->base.sample_rate = src_base->sample_rate; + self->base.channel_count = src_base->channel_count; + self->base.bits_per_sample = src_base->bits_per_sample; + self->base.samples_signed = src_base->samples_signed; + self->base.single_buffer = true; + + uint8_t bytes_per_frame = (src_base->bits_per_sample / 8) * src_base->channel_count; + self->output_buffer_length = OUTPUT_BUFFER_FRAMES * bytes_per_frame; + self->base.max_buffer_length = self->output_buffer_length; + + self->output_buffer = m_malloc_without_collect(self->output_buffer_length); + if (self->output_buffer == NULL) { + m_malloc_fail(self->output_buffer_length); + } +} + +void common_hal_audiotools_speedchanger_deinit(audiotools_speedchanger_obj_t *self) { + self->output_buffer = NULL; + self->source = MP_OBJ_NULL; + audiosample_mark_deinit(&self->base); +} + +void common_hal_audiotools_speedchanger_set_rate(audiotools_speedchanger_obj_t *self, uint32_t rate_fp) { + self->rate_fp = rate_fp; +} + +uint32_t common_hal_audiotools_speedchanger_get_rate(audiotools_speedchanger_obj_t *self) { + return self->rate_fp; +} + +// Fetch the next buffer from the source. Returns false if no data available. +static bool fetch_source_buffer(audiotools_speedchanger_obj_t *self) { + if (self->source_exhausted) { + return false; + } + uint8_t *buf = NULL; + uint32_t len = 0; + audioio_get_buffer_result_t result = audiosample_get_buffer(self->source, false, 0, &buf, &len); + if (result == GET_BUFFER_ERROR) { + self->source_exhausted = true; + return false; + } + if (len == 0) { + self->source_exhausted = true; + return false; + } + self->src_buffer = buf; + self->src_buffer_length = len; + uint8_t bytes_per_frame = (self->base.bits_per_sample / 8) * self->base.channel_count; + self->src_sample_count = len / bytes_per_frame; + self->source_done = (result == GET_BUFFER_DONE); + // Reset phase to index within this new buffer + self->phase = 0; + return true; +} + +void audiotools_speedchanger_reset_buffer(audiotools_speedchanger_obj_t *self, + bool single_channel_output, uint8_t channel) { + if (single_channel_output && channel == 1) { + return; + } + audiosample_reset_buffer(self->source, false, 0); + self->phase = 0; + self->src_buffer = NULL; + self->src_buffer_length = 0; + self->src_sample_count = 0; + self->source_done = false; + self->source_exhausted = false; +} + +audioio_get_buffer_result_t audiotools_speedchanger_get_buffer(audiotools_speedchanger_obj_t *self, + bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + + // Ensure we have a source buffer + if (self->src_buffer == NULL) { + if (!fetch_source_buffer(self)) { + *buffer = NULL; + *buffer_length = 0; + return GET_BUFFER_DONE; + } + } + + uint8_t bytes_per_sample = self->base.bits_per_sample / 8; + uint8_t channels = self->base.channel_count; + uint8_t bytes_per_frame = bytes_per_sample * channels; + uint32_t out_frames = 0; + uint32_t max_out_frames = self->output_buffer_length / bytes_per_frame; + + if (bytes_per_sample == 1) { + // 8-bit samples + uint8_t *out = self->output_buffer; + while (out_frames < max_out_frames) { + uint32_t src_index = self->phase >> SPEED_SHIFT; + // Advance to next source buffer if needed + if (src_index >= self->src_sample_count) { + if (self->source_done) { + self->source_exhausted = true; + break; + } + if (!fetch_source_buffer(self)) { + break; + } + src_index = 0; // phase was reset by fetch + } + uint8_t *src = self->src_buffer + src_index * bytes_per_frame; + for (uint8_t c = 0; c < channels; c++) { + *out++ = src[c]; + } + out_frames++; + self->phase += self->rate_fp; + } + } else { + // 16-bit samples + int16_t *out = (int16_t *)self->output_buffer; + while (out_frames < max_out_frames) { + uint32_t src_index = self->phase >> SPEED_SHIFT; + if (src_index >= self->src_sample_count) { + if (self->source_done) { + self->source_exhausted = true; + break; + } + if (!fetch_source_buffer(self)) { + break; + } + src_index = 0; + } + int16_t *src = (int16_t *)(self->src_buffer + src_index * bytes_per_frame); + for (uint8_t c = 0; c < channels; c++) { + *out++ = src[c]; + } + out_frames++; + self->phase += self->rate_fp; + } + } + + *buffer = self->output_buffer; + *buffer_length = out_frames * bytes_per_frame; + + if (out_frames == 0) { + return GET_BUFFER_DONE; + } + return self->source_exhausted ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/audiotools/SpeedChanger.h b/shared-module/audiotools/SpeedChanger.h new file mode 100644 index 00000000000..05cbec56fde --- /dev/null +++ b/shared-module/audiotools/SpeedChanger.h @@ -0,0 +1,35 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-module/audiocore/__init__.h" + +// Fixed-point 16.16 format +#define SPEED_SHIFT 16 + +typedef struct { + audiosample_base_t base; + mp_obj_t source; + uint8_t *output_buffer; + uint32_t output_buffer_length; // in bytes, allocated size + // Source buffer cache + uint8_t *src_buffer; + uint32_t src_buffer_length; // in bytes + uint32_t src_sample_count; // in frames + // Phase accumulator and rate in 16.16 fixed-point (units: source frames) + uint32_t phase; + uint32_t rate_fp; // 16.16 fixed-point rate + bool source_done; // source returned DONE on last get_buffer + bool source_exhausted; // source DONE and we consumed all of it +} audiotools_speedchanger_obj_t; + +void audiotools_speedchanger_reset_buffer(audiotools_speedchanger_obj_t *self, + bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t audiotools_speedchanger_get_buffer(audiotools_speedchanger_obj_t *self, + bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length); diff --git a/shared-module/audiotools/__init__.c b/shared-module/audiotools/__init__.c new file mode 100644 index 00000000000..7c9b271a4b5 --- /dev/null +++ b/shared-module/audiotools/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT diff --git a/shared-module/audiotools/__init__.h b/shared-module/audiotools/__init__.h new file mode 100644 index 00000000000..c4a52e5819d --- /dev/null +++ b/shared-module/audiotools/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once From 032c129d5188d9cd3eb90ee85a27ab68f73d012b Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Fri, 27 Mar 2026 16:40:56 -0700 Subject: [PATCH 348/876] update_board_info for zephyr --- .../adafruit/feather_nrf52840_zephyr/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml | 1 + .../zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml | 1 + .../zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml | 1 + .../boards/renesas/da14695_dk_usb/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml | 1 + ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml | 1 + .../zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml | 1 + 18 files changed, 18 insertions(+) diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 2c717fc83c1..edfe80d5320 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 1b82d3ba00e..2074193d09b 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index f995c03c2a2..fcf372cfa6d 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 397d514a0da..a65c86ea272 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 69a657b8c98..9a588fbd75a 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 378cbc07e9a..e3f3f4fe6d2 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 892b3dbbbd4..41dde878d07 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 718cd0bcfd3..80755cdf421 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 10b0056c81d..a2d519ad611 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index a3d6acdb79e..d988846c0c3 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index 3d5fbb08c65..5e5028e0ac2 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index ec96d530726..4a1186f39bd 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 132899d4248..a22f8da260f 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index bc2a29aea08..d2a53571d10 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index aacda400a30..9a0c56a9023 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index a8c03d5a4e8..99ad0b01f0a 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index b66682c5923..77173e04378 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index cadd8b5ade3..c80145f73b2 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiotools = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio From 7038fe65bec80eeae15069578bc1e9cf58b247b0 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Fri, 27 Mar 2026 17:16:11 -0700 Subject: [PATCH 349/876] fix doc build hopefully --- shared-bindings/audiotools/SpeedChanger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/audiotools/SpeedChanger.c b/shared-bindings/audiotools/SpeedChanger.c index ac46eb1dbc8..ed7e8121d2d 100644 --- a/shared-bindings/audiotools/SpeedChanger.c +++ b/shared-bindings/audiotools/SpeedChanger.c @@ -31,7 +31,7 @@ static mp_obj_t fp_to_rate(uint32_t rate_fp) { //| Uses nearest-neighbor resampling with a fixed-point phase accumulator //| for CPU-efficient variable-speed playback.""" //| -//| def __init__(self, source: audiosample, rate: float = 1.0) -> None: +//| def __init__(self, source: circuitpython_typing.AudioSample, rate: float = 1.0) -> None: //| """Create a SpeedChanger that wraps ``source``. //| //| :param audiosample source: The audio source to resample. From 63460de8cbe700d6af7b6a6690ca96dc4389d3e3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 29 Mar 2026 20:58:39 -0400 Subject: [PATCH 350/876] second pass over diffs --- ports/unix/Makefile | 17 ++-- py/binary.c | 11 -- py/dynruntime.h | 2 +- py/makeqstrdefs.py | 3 + py/malloc.c | 1 + py/misc.h | 14 +++ py/mpconfig.h | 2 +- py/objtype.c | 2 +- py/py.mk | 1 + py/sequence.c | 7 +- py/vstr.c | 2 +- shared/runtime/gchelper_generic.c | 1 + shared/runtime/interrupt_char.c | 1 + shared/runtime/interrupt_char.h | 1 + shared/runtime/mpirq.c | 160 ------------------------------ shared/runtime/mpirq.h | 83 ---------------- shared/runtime/pyexec.c | 3 +- 17 files changed, 37 insertions(+), 274 deletions(-) delete mode 100644 shared/runtime/mpirq.c delete mode 100644 shared/runtime/mpirq.h diff --git a/ports/unix/Makefile b/ports/unix/Makefile index 8be34feed3c..fe73ae5278b 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -210,6 +210,7 @@ ifeq ($(MICROPY_PY_JNI),1) CFLAGS += -I/usr/lib/jvm/java-7-openjdk-amd64/include -DMICROPY_PY_JNI=1 endif +# CIRCUITPY-CHANGE: CircuitPython-specific files. # source files SRC_C += \ main.c \ @@ -219,15 +220,13 @@ SRC_C += \ input.c \ alloc.c \ fatfs_port.c \ - mpbthciport.c \ - mpbtstackport_common.c \ - mpbtstackport_h4.c \ - mpbtstackport_usb.c \ - mpnimbleport.c \ - modtermios.c \ - modsocket.c \ - modffi.c \ - modjni.c \ + shared-module/os/__init__.c \ + supervisor/shared/settings.c \ + supervisor/stub/filesystem.c \ + supervisor/stub/safe_mode.c \ + supervisor/stub/stack.c \ + supervisor/shared/translate/translate.c \ + $(SRC_MOD) \ $(wildcard $(VARIANT_DIR)/*.c) # CIRCUITPY-CHANGE diff --git a/py/binary.c b/py/binary.c index 59353b918f9..24c3a5d4298 100644 --- a/py/binary.c +++ b/py/binary.c @@ -287,11 +287,8 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) { #if MICROPY_PY_BUILTINS_FLOAT case 'f': return mp_obj_new_float_from_f(((float *)p)[index]); - // CIRCUITPY-CHANGE: - #if MICROPY_PY_DOUBLE_TYPECODE case 'd': return mp_obj_new_float_from_d(((double *)p)[index]); - #endif #endif // Extension to CPython: array of objects #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES @@ -364,8 +361,6 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * float f; } fpu = {val}; return mp_obj_new_float_from_f(fpu.f); - // CIRCUITPY-CHANGE - #if MICROPY_PY_DOUBLE_TYPECODE } else if (val_type == 'd') { union { uint64_t i; @@ -373,7 +368,6 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte * } fpu = {val}; return mp_obj_new_float_from_d(fpu.f); #endif - #endif } else if (is_signed(val_type)) { if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) { return mp_obj_new_int((mp_int_t)val); @@ -503,12 +497,10 @@ void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_ case 'f': ((float *)p)[index] = mp_obj_get_float_to_f(val_in); break; - #if MICROPY_PY_DOUBLE_TYPECODE case 'd': ((double *)p)[index] = mp_obj_get_float_to_d(val_in); break; #endif - #endif #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES // Extension to CPython: array of objects case 'O': @@ -577,12 +569,9 @@ void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_i case 'f': ((float *)p)[index] = (float)val; break; - // CIRCUITPY-CHANGE - #if MICROPY_PY_DOUBLE_TYPECODE case 'd': ((double *)p)[index] = (double)val; break; - #endif #endif // Extension to CPython: array of pointers #if MICROPY_PY_STRUCT_UNSAFE_TYPECODES diff --git a/py/dynruntime.h b/py/dynruntime.h index b41a31f48f7..ab155a13875 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -289,7 +289,7 @@ static inline void *mp_obj_malloc_helper_dyn(size_t num_bytes, const mp_obj_type #define nlr_raise(o) (mp_raise_dyn(o)) #define mp_raise_type_arg(type, arg) (mp_raise_dyn(mp_obj_new_exception_arg1_dyn((type), (arg)))) -// CIRCUITPY-CHANGE: use str +// CIRCUITPY-CHANGE: use mp_raise_msg_str #define mp_raise_msg(type, msg) (mp_fun_table.raise_msg_str((type), (msg))) #define mp_raise_OSError(er) (mp_raise_OSError_dyn(er)) #define mp_raise_NotImplementedError(msg) (mp_raise_msg(&mp_type_NotImplementedError, (msg))) diff --git a/py/makeqstrdefs.py b/py/makeqstrdefs.py index 99ba6e2f9e5..8c07899baf8 100644 --- a/py/makeqstrdefs.py +++ b/py/makeqstrdefs.py @@ -137,6 +137,7 @@ def qstr_unescape(qstr): return qstr +# CIRCUITPY-CHANGE: output_filename as an arg def process_file(f, output_filename=None): # match gcc-like output (# n "file") and msvc-like output (#line n "file") re_line = re.compile(r"^#(?:line)?\s+\d+\s\"([^\"]+)\"") @@ -290,6 +291,7 @@ class Args: args.input_filename = sys.argv[3] # Unused for command=cat args.output_dir = sys.argv[4] args.output_file = None if len(sys.argv) == 5 else sys.argv[5] # Unused for command=split + # CIRCUITPY-CHANGE if args.output_file == "_": args.output_file = None @@ -304,6 +306,7 @@ class Args: if args.command == "split": with io.open(args.input_filename, encoding="utf-8") as infile: + # CIRCUITPY-CHANGE: pass output_file process_file(infile, args.output_file) if args.command == "cat": diff --git a/py/malloc.c b/py/malloc.c index c2a20cb817b..c11fd507145 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -24,6 +24,7 @@ * THE SOFTWARE. */ +#include #include #include #include diff --git a/py/misc.h b/py/misc.h index d977ee6a848..b1bdb9517a4 100644 --- a/py/misc.h +++ b/py/misc.h @@ -35,10 +35,24 @@ #include #include #include +#if __cplusplus // Required on at least one compiler to get ULLONG_MAX +#include +#else +#include +#endif typedef unsigned char byte; typedef unsigned int uint; +#ifndef __has_builtin +#define __has_builtin(x) (0) +#endif +#ifndef __has_feature +// This macro is supported by Clang and gcc>=14 +#define __has_feature(x) (0) +#endif + + /** generic ops *************************************************/ #ifndef MIN diff --git a/py/mpconfig.h b/py/mpconfig.h index 5b09fc97c92..e970ea3ba7b 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -2387,7 +2387,7 @@ typedef time_t mp_timestamp_t; #endif // INT_FMT #if !MICROPY_PREVIEW_VERSION_2 -#define MP_NORETURN MP_NORETURN +#define NORETURN MP_NORETURN #endif // Modifier for weak functions diff --git a/py/objtype.c b/py/objtype.c index 83bafa14e88..b1a984b50e0 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -1086,7 +1086,7 @@ static mp_obj_t type_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp if (!MP_OBJ_TYPE_HAS_SLOT(self, make_new)) { #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE - mp_raise_TypeError(MP_ERROR_TEXT("cannot create instance")); + mp_raise_TypeError(MP_ERROR_TEXT("can't create instance")); #else // CIRCUITPY-CHANGE: more specific mp_raise mp_raise_TypeError_varg(MP_ERROR_TEXT("can't create '%q' instances"), self->name); diff --git a/py/py.mk b/py/py.mk index 71b44f84d65..21be07c794f 100644 --- a/py/py.mk +++ b/py/py.mk @@ -191,6 +191,7 @@ PY_CORE_O_BASENAME = $(addprefix py/,\ objnamedtuple.o \ objrange.o \ objreversed.o \ + objringio.o \ objset.o \ objsingleton.o \ objslice.o \ diff --git a/py/sequence.c b/py/sequence.c index ac7ad5368b9..490f6d9c672 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -34,15 +34,10 @@ #define SWAP(type, var1, var2) { type t = var2; var2 = var1; var1 = t; } // CIRCUITPY-CHANGE: detect sequence overflow -#if __GNUC__ < 5 -// n.b. does not actually detect overflow! -#define __builtin_mul_overflow(a, b, x) (*(x) = (a) * (b), false) -#endif - // Detect when a multiply causes an overflow. size_t mp_seq_multiply_len(size_t item_sz, size_t len) { size_t new_len; - if (__builtin_mul_overflow(item_sz, len, &new_len)) { + if (mp_mul_mp_int_t_overflow(item_sz, len, &new_len)) { mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow")); } return new_len; diff --git a/py/vstr.c b/py/vstr.c index 00972edf897..522509d0d05 100644 --- a/py/vstr.c +++ b/py/vstr.c @@ -51,7 +51,7 @@ void vstr_init(vstr_t *vstr, size_t alloc) { // Init the vstr so it allocs exactly enough ram to hold a null-terminated // string of the given length, and set the length. void vstr_init_len(vstr_t *vstr, size_t len) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: check for invalid length if (len == SIZE_MAX) { m_malloc_fail(len); } diff --git a/shared/runtime/gchelper_generic.c b/shared/runtime/gchelper_generic.c index 464aeaa9981..230a2444005 100644 --- a/shared/runtime/gchelper_generic.c +++ b/shared/runtime/gchelper_generic.c @@ -42,6 +42,7 @@ // stack already by the caller. #if defined(__x86_64__) +// CIRCUITPY-CHANGE: use __asm__ instead of asm static void gc_helper_get_regs(gc_helper_regs_t arr) { register long rbx __asm__ ("rbx"); register long rbp __asm__ ("rbp"); diff --git a/shared/runtime/interrupt_char.c b/shared/runtime/interrupt_char.c index 5cec1988f41..1f270201719 100644 --- a/shared/runtime/interrupt_char.c +++ b/shared/runtime/interrupt_char.c @@ -31,6 +31,7 @@ #if MICROPY_KBD_EXCEPTION +// CIRCUITPY-CHANGE #ifdef __ZEPHYR__ #include diff --git a/shared/runtime/interrupt_char.h b/shared/runtime/interrupt_char.h index c4a465456a8..44fd4b45a61 100644 --- a/shared/runtime/interrupt_char.h +++ b/shared/runtime/interrupt_char.h @@ -29,6 +29,7 @@ // CIRCUITPY-CHANGE #include +// CIRCUITPY-CHANGE #ifdef __ZEPHYR__ #include diff --git a/shared/runtime/mpirq.c b/shared/runtime/mpirq.c deleted file mode 100644 index 4d848ae7e91..00000000000 --- a/shared/runtime/mpirq.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Daniel Campora - * 2018 Tobias Badertscher - * - * 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/runtime.h" -#include "py/gc.h" -#include "shared/runtime/mpirq.h" - -#if MICROPY_ENABLE_SCHEDULER - -/****************************************************************************** - DECLARE PUBLIC DATA - ******************************************************************************/ - -const mp_arg_t mp_irq_init_args[] = { - { MP_QSTR_handler, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, - { MP_QSTR_trigger, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_hard, MP_ARG_BOOL, {.u_bool = false} }, -}; - -/****************************************************************************** - DECLARE PRIVATE DATA - ******************************************************************************/ - -/****************************************************************************** - DEFINE PUBLIC FUNCTIONS - ******************************************************************************/ - -mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent) { - mp_irq_obj_t *self = m_new0(mp_irq_obj_t, 1); - mp_irq_init(self, methods, parent); - return self; -} - -void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent) { - self->base.type = &mp_irq_type; - self->methods = (mp_irq_methods_t *)methods; - self->parent = parent; - self->handler = mp_const_none; - self->ishard = false; -} - -int mp_irq_dispatch(mp_obj_t handler, mp_obj_t parent, bool ishard) { - int result = 0; - if (handler != mp_const_none) { - if (ishard) { - #if MICROPY_STACK_CHECK && MICROPY_STACK_SIZE_HARD_IRQ > 0 - // This callback executes in an ISR context so the stack-limit - // check must be changed to use the ISR stack for the duration - // of this function. - char *orig_stack_top = MP_STATE_THREAD(stack_top); - size_t orig_stack_limit = MP_STATE_THREAD(stack_limit); - mp_cstack_init_with_sp_here(MICROPY_STACK_SIZE_HARD_IRQ); - #endif - - // When executing code within a handler we must lock the scheduler to - // prevent any scheduled callbacks from running, and lock the GC to - // prevent any memory allocations. - mp_sched_lock(); - gc_lock(); - nlr_buf_t nlr; - if (nlr_push(&nlr) == 0) { - mp_call_function_1(handler, parent); - nlr_pop(); - } else { - mp_printf(MICROPY_ERROR_PRINTER, "Uncaught exception in IRQ callback handler\n"); - mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val)); - result = -1; - } - gc_unlock(); - mp_sched_unlock(); - - #if MICROPY_STACK_CHECK && MICROPY_STACK_SIZE_HARD_IRQ > 0 - // Restore original stack-limit checking values. - MP_STATE_THREAD(stack_top) = orig_stack_top; - MP_STATE_THREAD(stack_limit) = orig_stack_limit; - #endif - } else { - // Schedule call to user function - mp_sched_schedule(handler, parent); - } - } - return result; -} - - -void mp_irq_handler(mp_irq_obj_t *self) { - if (mp_irq_dispatch(self->handler, self->parent, self->ishard) < 0) { - // Uncaught exception; disable the callback so that it doesn't run again - self->methods->trigger(self->parent, 0); - self->handler = mp_const_none; - } -} - -/******************************************************************************/ -// MicroPython bindings - -static mp_obj_t mp_irq_flags(mp_obj_t self_in) { - mp_irq_obj_t *self = MP_OBJ_TO_PTR(self_in); - return mp_obj_new_int(self->methods->info(self->parent, MP_IRQ_INFO_FLAGS)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(mp_irq_flags_obj, mp_irq_flags); - -static mp_obj_t mp_irq_trigger(size_t n_args, const mp_obj_t *args) { - mp_irq_obj_t *self = MP_OBJ_TO_PTR(args[0]); - mp_obj_t ret_obj = mp_obj_new_int(self->methods->info(self->parent, MP_IRQ_INFO_TRIGGERS)); - if (n_args == 2) { - // Set trigger - self->methods->trigger(self->parent, mp_obj_get_int(args[1])); - } - return ret_obj; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_irq_trigger_obj, 1, 2, mp_irq_trigger); - -static mp_obj_t mp_irq_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { - mp_arg_check_num(n_args, n_kw, 0, 0, false); - mp_irq_handler(MP_OBJ_TO_PTR(self_in)); - return mp_const_none; -} - -static const mp_rom_map_elem_t mp_irq_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_flags), MP_ROM_PTR(&mp_irq_flags_obj) }, - { MP_ROM_QSTR(MP_QSTR_trigger), MP_ROM_PTR(&mp_irq_trigger_obj) }, -}; -static MP_DEFINE_CONST_DICT(mp_irq_locals_dict, mp_irq_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - mp_irq_type, - MP_QSTR_irq, - MP_TYPE_FLAG_NONE, - call, mp_irq_call, - locals_dict, &mp_irq_locals_dict - ); - -#endif // MICROPY_ENABLE_SCHEDULER diff --git a/shared/runtime/mpirq.h b/shared/runtime/mpirq.h deleted file mode 100644 index c65741e0e49..00000000000 --- a/shared/runtime/mpirq.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2015 Daniel Campora - * - * 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. - */ -#ifndef MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H -#define MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H - -#include "py/runtime.h" - -/****************************************************************************** - DEFINE CONSTANTS - ******************************************************************************/ - -enum { - MP_IRQ_ARG_INIT_handler = 0, - MP_IRQ_ARG_INIT_trigger, - MP_IRQ_ARG_INIT_hard, - MP_IRQ_ARG_INIT_NUM_ARGS, -}; - -/****************************************************************************** - DEFINE TYPES - ******************************************************************************/ - -typedef mp_uint_t (*mp_irq_trigger_fun_t)(mp_obj_t self, mp_uint_t trigger); -typedef mp_uint_t (*mp_irq_info_fun_t)(mp_obj_t self, mp_uint_t info_type); - -enum { - MP_IRQ_INFO_FLAGS, - MP_IRQ_INFO_TRIGGERS, -}; - -typedef struct _mp_irq_methods_t { - mp_irq_trigger_fun_t trigger; - mp_irq_info_fun_t info; -} mp_irq_methods_t; - -typedef struct _mp_irq_obj_t { - mp_obj_base_t base; - mp_irq_methods_t *methods; - mp_obj_t parent; - mp_obj_t handler; - bool ishard; -} mp_irq_obj_t; - -/****************************************************************************** - DECLARE EXPORTED DATA - ******************************************************************************/ - -extern const mp_arg_t mp_irq_init_args[]; -extern const mp_obj_type_t mp_irq_type; - -/****************************************************************************** - DECLARE PUBLIC FUNCTIONS - ******************************************************************************/ - -mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent); -void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent); -int mp_irq_dispatch(mp_obj_t handler, mp_obj_t parent, bool ishard); -void mp_irq_handler(mp_irq_obj_t *self); - -#endif // MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index a44fdf724d1..b554199eeec 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -482,7 +482,8 @@ static int pyexec_friendly_repl_process_char(int c) { mp_hal_stdout_tx_str(MICROPY_FULL_VERSION_INFO); mp_hal_stdout_tx_str("\r\n"); #if MICROPY_PY_BUILTINS_HELP - mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); + // CIRCUITPY-CHANGE: don't print help info + // mp_hal_stdout_tx_str("Type \"help()\" for more information.\r\n"); #endif goto input_restart; } else if (ret == CHAR_CTRL_C) { From e9d1082b0a185a4e583c4105fe4961b70a6c7670 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Mon, 30 Mar 2026 15:15:59 +0200 Subject: [PATCH 351/876] Fix length validation for palette in the stage library bindings Right now it's impossible to use the Stage library, because it always throws a validation error. --- shared-bindings/_stage/Text.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/_stage/Text.c b/shared-bindings/_stage/Text.c index f64a1b38190..0013ffb6697 100644 --- a/shared-bindings/_stage/Text.c +++ b/shared-bindings/_stage/Text.c @@ -47,7 +47,7 @@ static mp_obj_t text_make_new(const mp_obj_type_t *type, size_t n_args, mp_buffer_info_t palette_bufinfo; mp_get_buffer_raise(args[3], &palette_bufinfo, MP_BUFFER_READ); - mp_arg_validate_length(font_bufinfo.len, 32, MP_QSTR_palette); + mp_arg_validate_length(palette_bufinfo.len, 32, MP_QSTR_palette); mp_buffer_info_t chars_bufinfo; mp_get_buffer_raise(args[4], &chars_bufinfo, MP_BUFFER_READ); From 6d4e865473686d2707e1d515a91a0301d035c154 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Thu, 12 Feb 2026 19:37:37 +0100 Subject: [PATCH 352/876] Add board definition for uGame S3 uGame S3 is a handheld game console with an ESP32-S3 chip. More information at https://deshipu.art/projects/project-178061/ Lower SPI speed on uGame S3 to avoid display glitches. (cherry picked from commit a2ab5536c857ea401058c609bf0f4d2f24f4fc86) --- .../espressif/boards/deshipu_ugame_s3/board.c | 123 ++++++++++++++++++ .../boards/deshipu_ugame_s3/mpconfigboard.h | 28 ++++ .../boards/deshipu_ugame_s3/mpconfigboard.mk | 27 ++++ .../espressif/boards/deshipu_ugame_s3/pins.c | 43 ++++++ .../boards/deshipu_ugame_s3/sdkconfig | 22 ++++ 5 files changed, 243 insertions(+) create mode 100644 ports/espressif/boards/deshipu_ugame_s3/board.c create mode 100644 ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h create mode 100644 ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk create mode 100644 ports/espressif/boards/deshipu_ugame_s3/pins.c create mode 100644 ports/espressif/boards/deshipu_ugame_s3/sdkconfig diff --git a/ports/espressif/boards/deshipu_ugame_s3/board.c b/ports/espressif/boards/deshipu_ugame_s3/board.c new file mode 100644 index 00000000000..dc09786e74c --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/board.c @@ -0,0 +1,123 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Scott Shawcroft for Adafruit Industries + * + * 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 "supervisor/board.h" +#include "mpconfigboard.h" + +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "shared-module/displayio/mipi_constants.h" +#include "shared-bindings/board/__init__.h" + +#include "esp_log.h" +#include "esp_err.h" + +fourwire_fourwire_obj_t board_display_obj; + +#define DELAY 0x80 + +uint8_t display_init_sequence[] = { + 0x01, 0 | DELAY, 0x80, // Software reset then delay 0x80 (128ms) + 0xEF, 3, 0x03, 0x80, 0x02, + 0xCF, 3, 0x00, 0xC1, 0x30, + 0xED, 4, 0x64, 0x03, 0x12, 0x81, + 0xE8, 3, 0x85, 0x00, 0x78, + 0xCB, 5, 0x39, 0x2C, 0x00, 0x34, 0x02, + 0xF7, 1, 0x20, + 0xEA, 2, 0x00, 0x00, + 0xc0, 1, 0x23, // Power control VRH[5:0] + 0xc1, 1, 0x10, // Power control SAP[2:0];BT[3:0] + 0xc5, 2, 0x3e, 0x28, // VCM control + 0xc7, 1, 0x86, // VCM control2 + 0x37, 1, 0x00, // Vertical scroll zero + 0x3a, 1, 0x55, // COLMOD: Pixel Format Set + 0xb1, 2, 0x00, 0x18, // Frame Rate Control (In Normal Mode/Full Colors) + 0xb6, 3, 0x08, 0x82, 0x27, // Display Function Control + 0xF2, 1, 0x00, // 3Gamma Function Disable + 0x26, 1, 0x01, // Gamma curve selected + 0xe0, 15, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, // Set Gamma + 0xe1, 15, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, // Set Gamma + 0x11, 0 | DELAY, 0x78, // Exit Sleep then delay 0x78 (120ms) + 0x29, 0 | DELAY, 0x78, // Display on then delay 0x78 (120ms) + 0x36, 1, 0x38, +}; + + +void board_init(void) { + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO12, &pin_GPIO11, NULL, false); + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO9), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO10), // TFT_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO13), // TFT_RESET Reset + 48000000L, // Baudrate + 0, // Polarity + 0); // Phase + + busdisplay_busdisplay_obj_t *display = &allocate_display()->display; + display->base.type = &busdisplay_busdisplay_type; + common_hal_busdisplay_busdisplay_construct( + display, + bus, + 320, // Width (after rotation) + 240, // Height (after rotation) + 0, // column start + 0, // row start + 0, // rotation + 16, // Color depth + false, // Grayscale + false, // Pixels in a byte share a row. Only used for depth < 8 + 1, // bytes per cell. Only valid for depths < 8 + false, // reverse_pixels_in_byte. Only valid for depths < 8 + true, // reverse_pixels_in_word + MIPI_COMMAND_SET_COLUMN_ADDRESS, // Set column command + MIPI_COMMAND_SET_PAGE_ADDRESS, // Set row command + MIPI_COMMAND_WRITE_MEMORY_START, // Write memory command + display_init_sequence, + sizeof(display_init_sequence), + &pin_GPIO21, // backlight pin + NO_BRIGHTNESS_COMMAND, + 1.0f, // brightness + false, // single_byte_bounds + false, // data_as_commands + true, // auto_refresh + 20, // native_frames_per_second + true, // backlight_on_high + false, // not SH1107 + 50000); // backlight pwm frequency +} + +void board_deinit(void) { +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h new file mode 100644 index 00000000000..da7c3b4e8a4 --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.h @@ -0,0 +1,28 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2023 Scott Shawcroft for Adafruit Industries + * + * 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. + */ + +#define MICROPY_HW_BOARD_NAME "uGame S3" +#define MICROPY_HW_MCU_NAME "ESP32S3" diff --git a/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk new file mode 100644 index 00000000000..36a0ce040c5 --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/mpconfigboard.mk @@ -0,0 +1,27 @@ +USB_VID = 0x1209 +USB_PID = 0xD187 +USB_PRODUCT = "uGameS3" +USB_MANUFACTURER = "deshipu" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 16MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +CIRCUITPY_STAGE = 1 +CIRCUITPY_KEYPAD = 1 + +CIRCUITPY_CANIO = 0 +CIRCUITPY_DUALBANK = 0 +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_FRAMEBUFFERIO = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_RGBMATRIX = 0 +CIRCUITPY_ROTARYIO = 0 + +FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/ugame_s3 diff --git a/ports/espressif/boards/deshipu_ugame_s3/pins.c b/ports/espressif/boards/deshipu_ugame_s3/pins.c new file mode 100644 index 00000000000..54bd5dcdb4f --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/pins.c @@ -0,0 +1,43 @@ +#include "py/objtuple.h" +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" + + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_P1), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_P2), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_P3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_P4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_P5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_P6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_P7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_LEFT), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_UP), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_RIGHT), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_DOWN), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_X), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_O), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_Z), MP_ROM_PTR(&pin_GPIO47) }, + + { MP_ROM_QSTR(MP_QSTR_LIGHT), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_BATTERY), MP_ROM_PTR(&pin_GPIO8) }, + + + { MP_ROM_QSTR(MP_QSTR_AUDIO_BCLK), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_LRCLK), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_DATA), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_AUDIO_GAIN), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_TFT_RESET), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_TFT_BACKLIGHT), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)}, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/deshipu_ugame_s3/sdkconfig b/ports/espressif/boards/deshipu_ugame_s3/sdkconfig new file mode 100644 index 00000000000..1bddb7a89fb --- /dev/null +++ b/ports/espressif/boards/deshipu_ugame_s3/sdkconfig @@ -0,0 +1,22 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +CONFIG_LWIP_LOCAL_HOSTNAME="espressif-esp32s3" +# end of LWIP + +# +# Camera configuration +# +# CONFIG_OV7725_SUPPORT is not set +# CONFIG_OV3660_SUPPORT is not set +# end of Camera configuration + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From ce2d6e96160aa1a6444f3234903f6db7aca7b675 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 30 Mar 2026 13:10:59 -0500 Subject: [PATCH 353/876] Remove unused inline functions --- shared-module/audiomixer/Mixer.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index b27eafb71a9..01d2a259d5e 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -165,16 +165,6 @@ static inline uint32_t copy16msb(uint32_t val) { return val | (val >> 16); } -static inline uint32_t copy8lsb(uint32_t val) { - val &= 0x00ff; - return val | (val << 8); -} - -static inline uint32_t copy8msb(uint32_t val) { - val &= 0xff00; - return val | (val >> 8); -} - #define ALMOST_ONE (MICROPY_FLOAT_CONST(32767.) / 32768) static void mix_down_one_voice(audiomixer_mixer_obj_t *self, From 9c763bae40992196ca3a219709c1ef598a2a9e8a Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 30 Mar 2026 13:16:09 -0500 Subject: [PATCH 354/876] Add ARM operations for 16-bit copy functions --- shared-module/audiomixer/Mixer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 01d2a259d5e..684f9fedaf4 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -156,13 +156,21 @@ static inline uint32_t pack8(uint32_t val) { } static inline uint32_t copy16lsb(uint32_t val) { + #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) + return __PKHBT(val, val, 16); + #else val &= 0x0000ffff; return val | (val << 16); + #endif; } static inline uint32_t copy16msb(uint32_t val) { + #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) + return __PKHTB(val, val, 16); + #else val &= 0xffff0000; return val | (val >> 16); + #endif; } #define ALMOST_ONE (MICROPY_FLOAT_CONST(32767.) / 32768) From a6291470dbad9b1402abc2f99df01111607c426a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 30 Mar 2026 16:35:49 -0400 Subject: [PATCH 355/876] fix warnings during RTD builds --- docs/rstjinja.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/rstjinja.py b/docs/rstjinja.py index e7d8a312f1f..04c855a1a40 100644 --- a/docs/rstjinja.py +++ b/docs/rstjinja.py @@ -38,3 +38,7 @@ def rstjinja(app, docname, source): def setup(app): app.connect("source-read", rstjinja) + return { + "parallel_read_safe": True, + "parallel_write_safe": True, + } From c2cf8306b82900256297b433942e2fd3d3ce0791 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Mon, 30 Mar 2026 22:59:16 +0200 Subject: [PATCH 356/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 7 ++++++- locale/el.po | 7 ++++++- locale/hi.po | 7 ++++++- locale/ko.po | 7 ++++++- locale/ru.po | 7 ++++++- locale/tr.po | 7 ++++++- 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index d23583f4e6b..0adef977617 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -636,6 +636,7 @@ msgstr "Konverze audia není implementována" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Audio source error" msgstr "" @@ -1320,6 +1321,7 @@ msgstr "" msgid "Invalid %q" msgstr "Špatný %s" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" @@ -1557,6 +1559,7 @@ msgstr "Žádný DAC na čipu" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "No DMA channel found" msgstr "Nebyl nalezen žádný kanál DMA" @@ -1671,7 +1674,7 @@ msgid "Not connected" msgstr "Nepřipojený" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c msgid "Not playing" msgstr "Nehraje" @@ -2191,6 +2194,7 @@ msgid "Too many channels in sample" msgstr "V samplu je příliš mnoho kanálů" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2290,6 +2294,7 @@ msgstr "Nelze přistupovat k nezarovnanému IO registru" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Unable to allocate buffers for signed conversion" msgstr "" diff --git a/locale/el.po b/locale/el.po index 06a24a1486f..df024f2b1fe 100644 --- a/locale/el.po +++ b/locale/el.po @@ -640,6 +640,7 @@ msgstr "Η μετατροπή ήχου δεν υποστηρίζεται" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Audio source error" msgstr "" @@ -1326,6 +1327,7 @@ msgstr "" msgid "Invalid %q" msgstr "" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" @@ -1563,6 +1565,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "No DMA channel found" msgstr "" @@ -1677,7 +1680,7 @@ msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c msgid "Not playing" msgstr "" @@ -2196,6 +2199,7 @@ msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2294,6 +2298,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Unable to allocate buffers for signed conversion" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index a6d5cf49c0a..48a8c6c26e1 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -627,6 +627,7 @@ msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Audio source error" msgstr "" @@ -1302,6 +1303,7 @@ msgstr "" msgid "Invalid %q" msgstr "" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" @@ -1539,6 +1541,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "No DMA channel found" msgstr "" @@ -1653,7 +1656,7 @@ msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c msgid "Not playing" msgstr "" @@ -2170,6 +2173,7 @@ msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2268,6 +2272,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Unable to allocate buffers for signed conversion" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index cc65afaa7c0..63c64a6952d 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -666,6 +666,7 @@ msgstr "오디오 변환이 구현되지 않음" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Audio source error" msgstr "" @@ -1353,6 +1354,7 @@ msgstr "출력 함수로 인해 종료되었다" msgid "Invalid %q" msgstr "잘못된 %q" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" @@ -1594,6 +1596,7 @@ msgstr "칩에 DAC가 없습니다" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "No DMA channel found" msgstr "DMA 채널을 찾을 수 없습니다" @@ -1711,7 +1714,7 @@ msgid "Not connected" msgstr "연결되지 않았습니다" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c msgid "Not playing" msgstr "재생되지 않았습니다" @@ -2243,6 +2246,7 @@ msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2342,6 +2346,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Unable to allocate buffers for signed conversion" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 7f31c3a73a6..a7f7a35d58b 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -640,6 +640,7 @@ msgstr "Преобразование звука не реализовано" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Audio source error" msgstr "" @@ -1341,6 +1342,7 @@ msgstr "Прерывается функцией выхода" msgid "Invalid %q" msgstr "Недопустимый %q" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" @@ -1580,6 +1582,7 @@ msgstr "DAC отсутствует на чипе" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "No DMA channel found" msgstr "Канал DMA не найден" @@ -1694,7 +1697,7 @@ msgid "Not connected" msgstr "Не подключено" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c msgid "Not playing" msgstr "Не воспроизводится (Not playing)" @@ -2226,6 +2229,7 @@ msgid "Too many channels in sample" msgstr "Слишком много каналов в выборке" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "Слишком много каналов в выборке." @@ -2324,6 +2328,7 @@ msgstr "Невозможно получить доступ к невыровне #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Unable to allocate buffers for signed conversion" msgstr "Не удается выделить буферы для подписанного преобразования" diff --git a/locale/tr.po b/locale/tr.po index 96037c5426f..00f1c82065a 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -638,6 +638,7 @@ msgstr "Ses dönüşümü implemente edilmedi" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Audio source error" msgstr "" @@ -1320,6 +1321,7 @@ msgstr "" msgid "Invalid %q" msgstr "Geçersiz %q" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c #: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: shared-module/aurora_epaper/aurora_framebuffer.c msgid "Invalid %q and %q" @@ -1558,6 +1560,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "No DMA channel found" msgstr "" @@ -1672,7 +1675,7 @@ msgid "Not connected" msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c msgid "Not playing" msgstr "" @@ -2192,6 +2195,7 @@ msgid "Too many channels in sample" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Too many channels in sample." msgstr "" @@ -2290,6 +2294,7 @@ msgstr "" #: ports/atmel-samd/common-hal/audioio/AudioOut.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Unable to allocate buffers for signed conversion" msgstr "" From b978712f19e2f58575267068698cdde9aaf31655 Mon Sep 17 00:00:00 2001 From: Radomir Dopieralski Date: Mon, 30 Mar 2026 15:15:59 +0200 Subject: [PATCH 357/876] Fix length validation for palette in the stage library bindings Right now it's impossible to use the Stage library, because it always throws a validation error. --- shared-bindings/_stage/Text.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/_stage/Text.c b/shared-bindings/_stage/Text.c index f64a1b38190..0013ffb6697 100644 --- a/shared-bindings/_stage/Text.c +++ b/shared-bindings/_stage/Text.c @@ -47,7 +47,7 @@ static mp_obj_t text_make_new(const mp_obj_type_t *type, size_t n_args, mp_buffer_info_t palette_bufinfo; mp_get_buffer_raise(args[3], &palette_bufinfo, MP_BUFFER_READ); - mp_arg_validate_length(font_bufinfo.len, 32, MP_QSTR_palette); + mp_arg_validate_length(palette_bufinfo.len, 32, MP_QSTR_palette); mp_buffer_info_t chars_bufinfo; mp_get_buffer_raise(args[4], &chars_bufinfo, MP_BUFFER_READ); From b4e21d108c687f1f23eb46499592f2e6257189db Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 30 Mar 2026 14:33:35 -0700 Subject: [PATCH 358/876] Relax Zephyr CI autogen check It is more annoying than helpful. We can set up an auto-updater later on when they get out of date. --- ports/zephyr-cp/cptools/build_circuitpython.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 2022d82f1b7..5f51281870c 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -522,16 +522,15 @@ async def build_circuitpython(): hal_source.extend(top.glob(f"shared-bindings/{module.name}/*.c")) if os.environ.get("CI", "false") == "true": - # Fail the build if it isn't up to date. + # Warn if it isn't up to date. if ( not autogen_board_info_fn.exists() or autogen_board_info_fn.read_text() != tomlkit.dumps(autogen_board_info) ): - logger.error("autogen_board_info.toml is out of date.") - raise RuntimeError( + logger.warning( f"autogen_board_info.toml is missing or out of date. Please run `make BOARD={board}` locally and commit {autogen_board_info_fn}." ) - elif autogen_board_info_fn.parent.exists(): + if autogen_board_info_fn.parent.exists(): autogen_board_info_fn.write_text(tomlkit.dumps(autogen_board_info)) for mpflag in MPCONFIG_FLAGS: From 81dfb880f789fb47292de771ab621b3b15764bd6 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 30 Mar 2026 17:39:26 -0400 Subject: [PATCH 359/876] update CI actions to latest versions, to use Node.24 --- .../actions/deps/ports/espressif/action.yml | 4 +-- .github/actions/deps/python/action.yml | 4 +-- .github/actions/deps/submodules/action.yml | 4 +-- .github/actions/mpy_cross/action.yml | 4 +-- .github/workflows/build-board-custom.yml | 4 +-- .github/workflows/build-boards.yml | 6 ++--- .github/workflows/build-mpy-cross.yml | 6 ++--- .github/workflows/build.yml | 26 +++++++++---------- .github/workflows/bundle_cron.yml | 6 ++--- .github/workflows/create-website-pr.yml | 4 +-- .github/workflows/learn_cron.yml | 2 +- .github/workflows/pre-commit.yml | 6 ++--- .github/workflows/reports_cron.yml | 4 +-- .github/workflows/run-tests.yml | 8 +++--- 14 files changed, 44 insertions(+), 44 deletions(-) diff --git a/.github/actions/deps/ports/espressif/action.yml b/.github/actions/deps/ports/espressif/action.yml index 25965eb7ef0..321a0fb2b30 100644 --- a/.github/actions/deps/ports/espressif/action.yml +++ b/.github/actions/deps/ports/espressif/action.yml @@ -19,7 +19,7 @@ runs: shell: bash - name: Cache IDF submodules - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: | .git/modules/ports/espressif/esp-idf @@ -27,7 +27,7 @@ runs: key: submodules-idf-${{ steps.idf-commit.outputs.commit }} - name: Cache IDF tools - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ${{ env.IDF_TOOLS_PATH }} key: ${{ runner.os }}-${{ env.pythonLocation }}-tools-idf-${{ steps.idf-commit.outputs.commit }} diff --git a/.github/actions/deps/python/action.yml b/.github/actions/deps/python/action.yml index da59b87b17a..bc8b578c147 100644 --- a/.github/actions/deps/python/action.yml +++ b/.github/actions/deps/python/action.yml @@ -16,7 +16,7 @@ runs: - name: Cache python dependencies id: cache-python-deps if: inputs.action == 'cache' - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .cp_tools key: ${{ runner.os }}-${{ env.pythonLocation }}-tools-cp-${{ hashFiles('requirements-dev.txt') }} @@ -24,7 +24,7 @@ runs: - name: Restore python dependencies id: restore-python-deps if: inputs.action == 'restore' - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: .cp_tools key: ${{ runner.os }}-${{ env.pythonLocation }}-tools-cp-${{ hashFiles('requirements-dev.txt') }} diff --git a/.github/actions/deps/submodules/action.yml b/.github/actions/deps/submodules/action.yml index eed83af41f4..5ec57b594c0 100644 --- a/.github/actions/deps/submodules/action.yml +++ b/.github/actions/deps/submodules/action.yml @@ -48,7 +48,7 @@ runs: - name: Cache submodules if: ${{ inputs.action == 'cache' }} - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ".git/modules/\n${{ join(fromJSON(steps.create-submodule-status.outputs.submodules), '\n') }}" key: submodules-common-${{ hashFiles('submodule_status') }} @@ -56,7 +56,7 @@ runs: - name: Restore submodules if: ${{ inputs.action == 'restore' }} - uses: actions/cache/restore@v4 + uses: actions/cache/restore@v5 with: path: ".git/modules/\n${{ join(fromJSON(steps.create-submodule-status.outputs.submodules), '\n') }}" key: submodules-common-${{ hashFiles('submodule_status') }} diff --git a/.github/actions/mpy_cross/action.yml b/.github/actions/mpy_cross/action.yml index 8839f790915..469b8b0763e 100644 --- a/.github/actions/mpy_cross/action.yml +++ b/.github/actions/mpy_cross/action.yml @@ -16,7 +16,7 @@ runs: id: download-mpy-cross if: inputs.download == 'true' continue-on-error: true - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: mpy-cross path: mpy-cross/build @@ -36,7 +36,7 @@ runs: - name: Upload mpy-cross if: inputs.download == 'false' || steps.download-mpy-cross.outcome == 'failure' continue-on-error: true - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: mpy-cross path: mpy-cross/build/mpy-cross diff --git a/.github/workflows/build-board-custom.yml b/.github/workflows/build-board-custom.yml index bf18d7d7259..c17e1b13f97 100644 --- a/.github/workflows/build-board-custom.yml +++ b/.github/workflows/build-board-custom.yml @@ -70,7 +70,7 @@ jobs: run: | > custom-build && git add custom-build - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Board to port @@ -124,7 +124,7 @@ jobs: run: make -j4 $FLAGS BOARD="$BOARD" DEBUG=$DEBUG TRANSLATION="$TRANSLATION" working-directory: ports/${{ steps.board-to-port.outputs.port }} - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ inputs.board }}-${{ inputs.language }}-${{ inputs.version }}${{ inputs.flags != '' && '-custom' || '' }}${{ inputs.debug && '-debug' || '' }} path: ports/${{ steps.board-to-port.outputs.port }}/build-${{ inputs.board }}/firmware.* diff --git a/.github/workflows/build-boards.yml b/.github/workflows/build-boards.yml index 7e5156d4011..6fbc5b6a08f 100644 --- a/.github/workflows/build-boards.yml +++ b/.github/workflows/build-boards.yml @@ -29,7 +29,7 @@ jobs: board: ${{ fromJSON(inputs.boards) }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false @@ -37,7 +37,7 @@ jobs: persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x @@ -87,7 +87,7 @@ jobs: HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }} - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ matrix.board }} path: bin/${{ matrix.board }} diff --git a/.github/workflows/build-mpy-cross.yml b/.github/workflows/build-mpy-cross.yml index 831ad308227..9e5c1cdfc4a 100644 --- a/.github/workflows/build-mpy-cross.yml +++ b/.github/workflows/build-mpy-cross.yml @@ -28,14 +28,14 @@ jobs: OS_static-raspbian: linux-raspbian steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules @@ -66,7 +66,7 @@ jobs: echo >> $GITHUB_ENV "OS=$OS" - name: Upload artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: mpy-cross.${{ env.EX }} path: mpy-cross/build-${{ matrix.mpy-cross }}/mpy-cross.${{ env.EX }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5b755eb398e..6a2329a4113 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -28,14 +28,14 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Duplicate USB VID/PID check @@ -114,14 +114,14 @@ jobs: CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules @@ -133,7 +133,7 @@ jobs: msgfmt --version - name: Build mpy-cross (arm64) run: make -C mpy-cross -j4 -f Makefile.m1 V=2 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: mpy-cross-macos-arm64 path: mpy-cross/build-arm64/mpy-cross-arm64 @@ -156,14 +156,14 @@ jobs: CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules @@ -177,20 +177,20 @@ jobs: pip install -r requirements-doc.txt - name: Build and Validate Stubs run: make check-stubs -j4 - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: stubs path: circuitpython-stubs/dist/* - name: Test Documentation Build (HTML) run: sphinx-build -E -W -b html -D version="$CP_VERSION" -D release="$CP_VERSION" . _build/html - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: docs-html path: _build/html - name: Test Documentation Build (LaTeX/PDF) run: | make latexpdf - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v7 with: name: docs-latexpdf path: _build/latex @@ -260,7 +260,7 @@ jobs: which python; python --version; python -c "import cascadetoml" which python3; python3 --version; python3 -c "import cascadetoml" - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false @@ -295,13 +295,13 @@ jobs: CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: '3.13' - name: Set up Zephyr diff --git a/.github/workflows/bundle_cron.yml b/.github/workflows/bundle_cron.yml index 606707d4102..eefffaaa5b9 100644 --- a/.github/workflows/bundle_cron.yml +++ b/.github/workflows/bundle_cron.yml @@ -29,18 +29,18 @@ jobs: if: startswith(github.repository, 'adafruit/') steps: - name: Set up Python 3.12 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.12 - name: Load contributor cache - uses: actions/cache@v4 + uses: actions/cache@v5 with: key: "contributor-cache" path: "contributors.json" - name: Versions run: | python3 --version - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: repository: 'adafruit/adabot' submodules: true diff --git a/.github/workflows/create-website-pr.yml b/.github/workflows/create-website-pr.yml index 32c1792fa6c..559a41e67e7 100644 --- a/.github/workflows/create-website-pr.yml +++ b/.github/workflows/create-website-pr.yml @@ -17,14 +17,14 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules diff --git a/.github/workflows/learn_cron.yml b/.github/workflows/learn_cron.yml index 6100e6637c2..135089bfd5e 100644 --- a/.github/workflows/learn_cron.yml +++ b/.github/workflows/learn_cron.yml @@ -26,7 +26,7 @@ jobs: # default branches). if: ${{ (github.repository_owner == 'adafruit') }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: repository: ${{ github.repository_owner }}/Adafruit_Learning_System_Guides token: ${{ secrets.ADABOT_GITHUB_ACCESS_TOKEN }} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 778270dc08c..21ae984e468 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -17,14 +17,14 @@ jobs: runs-on: ubuntu-24.04 steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 persist-credentials: false - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.x - name: Set up submodules @@ -42,7 +42,7 @@ jobs: run: git diff > ~/pre-commit.patch - name: Upload patch if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: patch path: ~/pre-commit.patch diff --git a/.github/workflows/reports_cron.yml b/.github/workflows/reports_cron.yml index b4e9a43024e..476ead95d25 100644 --- a/.github/workflows/reports_cron.yml +++ b/.github/workflows/reports_cron.yml @@ -38,13 +38,13 @@ jobs: BIGQUERY_CLIENT_EMAIL: ${{ secrets.BIGQUERY_CLIENT_EMAIL }} steps: - name: Set up Python 3.11 - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.11 - name: Versions run: | python3 --version - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: repository: 'adafruit/adabot' submodules: true diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 925ee469854..83154bbbd2b 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -24,13 +24,13 @@ jobs: TEST_native_mpy: --via-mpy --emit native -d basics float micropython steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.12 - name: Set up submodules @@ -75,13 +75,13 @@ jobs: CP_VERSION: ${{ inputs.cp-version }} steps: - name: Set up repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: false show-progress: false fetch-depth: 1 - name: Set up python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: 3.13 - name: Set up Zephyr From 8fcd82385be7826617a042e2259081651465fbab Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 30 Mar 2026 17:04:04 -0500 Subject: [PATCH 360/876] Remove extra tokens from #endif directives --- shared-module/audiomixer/Mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 684f9fedaf4..64488cc4297 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -161,7 +161,7 @@ static inline uint32_t copy16lsb(uint32_t val) { #else val &= 0x0000ffff; return val | (val << 16); - #endif; + #endif } static inline uint32_t copy16msb(uint32_t val) { @@ -170,7 +170,7 @@ static inline uint32_t copy16msb(uint32_t val) { #else val &= 0xffff0000; return val | (val >> 16); - #endif; + #endif } #define ALMOST_ONE (MICROPY_FLOAT_CONST(32767.) / 32768) From 9ce0c5d6010feb3c869892065ffb65d1dee01095 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Mon, 30 Mar 2026 16:48:19 -0700 Subject: [PATCH 361/876] rename audiotools to audiospeed --- ports/raspberrypi/mpconfigport.mk | 2 +- .../autogen_board_info.toml | 2 +- .../native/native_sim/autogen_board_info.toml | 2 +- .../nrf5340bsim/autogen_board_info.toml | 2 +- .../nordic/nrf5340dk/autogen_board_info.toml | 2 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 2 +- .../nordic/nrf7002dk/autogen_board_info.toml | 2 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 2 +- .../nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../mimxrt1170_evk/autogen_board_info.toml | 2 +- .../da14695_dk_usb/autogen_board_info.toml | 2 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../nucleo_n657x0_q/autogen_board_info.toml | 2 +- .../nucleo_u575zi_q/autogen_board_info.toml | 2 +- .../st/stm32h750b_dk/autogen_board_info.toml | 2 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 2 +- .../stm32wba65i_dk1/autogen_board_info.toml | 2 +- py/circuitpy_defns.mk | 8 +-- .../{audiotools => audiospeed}/SpeedChanger.c | 66 +++++++++---------- shared-bindings/audiospeed/SpeedChanger.h | 17 +++++ shared-bindings/audiospeed/__init__.c | 28 ++++++++ .../{audiotools => audiospeed}/__init__.h | 0 shared-bindings/audiotools/SpeedChanger.h | 17 ----- shared-bindings/audiotools/__init__.c | 28 -------- .../{audiotools => audiospeed}/SpeedChanger.c | 16 ++--- .../{audiotools => audiospeed}/SpeedChanger.h | 6 +- .../{audiotools => audiospeed}/__init__.c | 0 .../{audiotools => audiospeed}/__init__.h | 0 30 files changed, 112 insertions(+), 112 deletions(-) rename shared-bindings/{audiotools => audiospeed}/SpeedChanger.c (62%) create mode 100644 shared-bindings/audiospeed/SpeedChanger.h create mode 100644 shared-bindings/audiospeed/__init__.c rename shared-bindings/{audiotools => audiospeed}/__init__.h (100%) delete mode 100644 shared-bindings/audiotools/SpeedChanger.h delete mode 100644 shared-bindings/audiotools/__init__.c rename shared-module/{audiotools => audiospeed}/SpeedChanger.c (90%) rename shared-module/{audiotools => audiospeed}/SpeedChanger.h (84%) rename shared-module/{audiotools => audiospeed}/__init__.c (100%) rename shared-module/{audiotools => audiospeed}/__init__.h (100%) diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index b8fc084322d..c670f5aa5df 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -11,7 +11,7 @@ CIRCUITPY_FLOPPYIO ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_DISPLAYIO) CIRCUITPY_FULL_BUILD ?= 1 CIRCUITPY_AUDIOMP3 ?= 1 -CIRCUITPY_AUDIOTOOLS ?= 1 +CIRCUITPY_AUDIOSPEED ?= 1 CIRCUITPY_BITOPS ?= 1 CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index edfe80d5320..df33d7a7eb2 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 2074193d09b..7b7295a9045 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index fcf372cfa6d..75bfafe96d0 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index a65c86ea272..a6d27f14eda 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 9a588fbd75a..ec76cd7c1ab 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index e3f3f4fe6d2..aca4d701cf7 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 41dde878d07..5366f535612 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 80755cdf421..14aef6dfdf7 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index a2d519ad611..a76ec250ec7 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index d988846c0c3..f8acb436780 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index 5e5028e0ac2..11a693117ec 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 4a1186f39bd..00260356a8e 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index a22f8da260f..1742c507c3d 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index d2a53571d10..98ab65e270e 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 9a0c56a9023..a40eaac3b9d 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index 99ad0b01f0a..596391b40cc 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 77173e04378..adabe5cceec 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index c80145f73b2..07e9913a41a 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -24,7 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false -audiotools = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 7e84d528c26..f4245b01322 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -146,8 +146,8 @@ endif ifeq ($(CIRCUITPY_AUDIOMP3),1) SRC_PATTERNS += audiomp3/% endif -ifeq ($(CIRCUITPY_AUDIOTOOLS),1) -SRC_PATTERNS += audiotools/% +ifeq ($(CIRCUITPY_AUDIOSPEED),1) +SRC_PATTERNS += audiospeed/% endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% @@ -691,8 +691,8 @@ SRC_SHARED_MODULE_ALL = \ audiocore/RawSample.c \ audiocore/WaveFile.c \ audiocore/__init__.c \ - audiotools/SpeedChanger.c \ - audiotools/__init__.c \ + audiospeed/SpeedChanger.c \ + audiospeed/__init__.c \ audiodelays/Echo.c \ audiodelays/Chorus.c \ audiodelays/PitchShift.c \ diff --git a/shared-bindings/audiotools/SpeedChanger.c b/shared-bindings/audiospeed/SpeedChanger.c similarity index 62% rename from shared-bindings/audiotools/SpeedChanger.c rename to shared-bindings/audiospeed/SpeedChanger.c index ed7e8121d2d..34efa1516b0 100644 --- a/shared-bindings/audiotools/SpeedChanger.c +++ b/shared-bindings/audiospeed/SpeedChanger.c @@ -9,10 +9,10 @@ #include "shared/runtime/context_manager_helpers.h" #include "py/objproperty.h" #include "py/runtime.h" -#include "shared-bindings/audiotools/SpeedChanger.h" +#include "shared-bindings/audiospeed/SpeedChanger.h" #include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/util.h" -#include "shared-module/audiotools/SpeedChanger.h" +#include "shared-module/audiospeed/SpeedChanger.h" // Convert a Python float to 16.16 fixed-point rate static uint32_t rate_to_fp(mp_obj_t rate_obj) { @@ -42,11 +42,11 @@ static mp_obj_t fp_to_rate(uint32_t rate_fp) { //| //| import board //| import audiocore -//| import audiotools +//| import audiospeed //| import audioio //| //| wav = audiocore.WaveFile("drum.wav") -//| fast = audiotools.SpeedChanger(wav, rate=1.5) +//| fast = audiospeed.SpeedChanger(wav, rate=1.5) //| audio = audioio.AudioOut(board.A0) //| audio.play(fast) //| @@ -56,7 +56,7 @@ static mp_obj_t fp_to_rate(uint32_t rate_fp) { //| """ //| ... //| -static mp_obj_t audiotools_speedchanger_make_new(const mp_obj_type_t *type, +static mp_obj_t audiospeed_speedchanger_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_source, ARG_rate }; static const mp_arg_t allowed_args[] = { @@ -75,8 +75,8 @@ static mp_obj_t audiotools_speedchanger_make_new(const mp_obj_type_t *type, rate_fp = rate_to_fp(args[ARG_rate].u_obj); } - audiotools_speedchanger_obj_t *self = mp_obj_malloc(audiotools_speedchanger_obj_t, &audiotools_speedchanger_type); - common_hal_audiotools_speedchanger_construct(self, source, rate_fp); + audiospeed_speedchanger_obj_t *self = mp_obj_malloc(audiospeed_speedchanger_obj_t, &audiospeed_speedchanger_type); + common_hal_audiospeed_speedchanger_construct(self, source, rate_fp); return MP_OBJ_FROM_PTR(self); } @@ -84,55 +84,55 @@ static mp_obj_t audiotools_speedchanger_make_new(const mp_obj_type_t *type, //| """Deinitialises the SpeedChanger and releases all memory resources for reuse.""" //| ... //| -static mp_obj_t audiotools_speedchanger_deinit(mp_obj_t self_in) { - audiotools_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audiotools_speedchanger_deinit(self); +static mp_obj_t audiospeed_speedchanger_deinit(mp_obj_t self_in) { + audiospeed_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiospeed_speedchanger_deinit(self); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(audiotools_speedchanger_deinit_obj, audiotools_speedchanger_deinit); +static MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_speedchanger_deinit_obj, audiospeed_speedchanger_deinit); //| rate: float //| """Playback speed multiplier. Can be changed during playback.""" //| -static mp_obj_t audiotools_speedchanger_obj_get_rate(mp_obj_t self_in) { - audiotools_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); +static mp_obj_t audiospeed_speedchanger_obj_get_rate(mp_obj_t self_in) { + audiospeed_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); audiosample_check_for_deinit(&self->base); - return fp_to_rate(common_hal_audiotools_speedchanger_get_rate(self)); + return fp_to_rate(common_hal_audiospeed_speedchanger_get_rate(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(audiotools_speedchanger_get_rate_obj, audiotools_speedchanger_obj_get_rate); +MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_speedchanger_get_rate_obj, audiospeed_speedchanger_obj_get_rate); -static mp_obj_t audiotools_speedchanger_obj_set_rate(mp_obj_t self_in, mp_obj_t rate_obj) { - audiotools_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); +static mp_obj_t audiospeed_speedchanger_obj_set_rate(mp_obj_t self_in, mp_obj_t rate_obj) { + audiospeed_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); audiosample_check_for_deinit(&self->base); - common_hal_audiotools_speedchanger_set_rate(self, rate_to_fp(rate_obj)); + common_hal_audiospeed_speedchanger_set_rate(self, rate_to_fp(rate_obj)); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(audiotools_speedchanger_set_rate_obj, audiotools_speedchanger_obj_set_rate); +MP_DEFINE_CONST_FUN_OBJ_2(audiospeed_speedchanger_set_rate_obj, audiospeed_speedchanger_obj_set_rate); -MP_PROPERTY_GETSET(audiotools_speedchanger_rate_obj, - (mp_obj_t)&audiotools_speedchanger_get_rate_obj, - (mp_obj_t)&audiotools_speedchanger_set_rate_obj); +MP_PROPERTY_GETSET(audiospeed_speedchanger_rate_obj, + (mp_obj_t)&audiospeed_speedchanger_get_rate_obj, + (mp_obj_t)&audiospeed_speedchanger_set_rate_obj); -static const mp_rom_map_elem_t audiotools_speedchanger_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiotools_speedchanger_deinit_obj) }, +static const mp_rom_map_elem_t audiospeed_speedchanger_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiospeed_speedchanger_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiotools_speedchanger_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiospeed_speedchanger_rate_obj) }, AUDIOSAMPLE_FIELDS, }; -static MP_DEFINE_CONST_DICT(audiotools_speedchanger_locals_dict, audiotools_speedchanger_locals_dict_table); +static MP_DEFINE_CONST_DICT(audiospeed_speedchanger_locals_dict, audiospeed_speedchanger_locals_dict_table); -static const audiosample_p_t audiotools_speedchanger_proto = { +static const audiosample_p_t audiospeed_speedchanger_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .reset_buffer = (audiosample_reset_buffer_fun)audiotools_speedchanger_reset_buffer, - .get_buffer = (audiosample_get_buffer_fun)audiotools_speedchanger_get_buffer, + .reset_buffer = (audiosample_reset_buffer_fun)audiospeed_speedchanger_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiospeed_speedchanger_get_buffer, }; MP_DEFINE_CONST_OBJ_TYPE( - audiotools_speedchanger_type, + audiospeed_speedchanger_type, MP_QSTR_SpeedChanger, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, audiotools_speedchanger_make_new, - locals_dict, &audiotools_speedchanger_locals_dict, - protocol, &audiotools_speedchanger_proto + make_new, audiospeed_speedchanger_make_new, + locals_dict, &audiospeed_speedchanger_locals_dict, + protocol, &audiospeed_speedchanger_proto ); diff --git a/shared-bindings/audiospeed/SpeedChanger.h b/shared-bindings/audiospeed/SpeedChanger.h new file mode 100644 index 00000000000..64a126a7a61 --- /dev/null +++ b/shared-bindings/audiospeed/SpeedChanger.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiospeed/SpeedChanger.h" + +extern const mp_obj_type_t audiospeed_speedchanger_type; + +void common_hal_audiospeed_speedchanger_construct(audiospeed_speedchanger_obj_t *self, + mp_obj_t source, uint32_t rate_fp); +void common_hal_audiospeed_speedchanger_deinit(audiospeed_speedchanger_obj_t *self); +void common_hal_audiospeed_speedchanger_set_rate(audiospeed_speedchanger_obj_t *self, uint32_t rate_fp); +uint32_t common_hal_audiospeed_speedchanger_get_rate(audiospeed_speedchanger_obj_t *self); diff --git a/shared-bindings/audiospeed/__init__.c b/shared-bindings/audiospeed/__init__.c new file mode 100644 index 00000000000..b12e6db7e6b --- /dev/null +++ b/shared-bindings/audiospeed/__init__.c @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/audiospeed/SpeedChanger.h" + +//| """Audio processing tools""" + +static const mp_rom_map_elem_t audiospeed_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiospeed) }, + { MP_ROM_QSTR(MP_QSTR_SpeedChanger), MP_ROM_PTR(&audiospeed_speedchanger_type) }, +}; + +static MP_DEFINE_CONST_DICT(audiospeed_module_globals, audiospeed_module_globals_table); + +const mp_obj_module_t audiospeed_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&audiospeed_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_audiospeed, audiospeed_module); diff --git a/shared-bindings/audiotools/__init__.h b/shared-bindings/audiospeed/__init__.h similarity index 100% rename from shared-bindings/audiotools/__init__.h rename to shared-bindings/audiospeed/__init__.h diff --git a/shared-bindings/audiotools/SpeedChanger.h b/shared-bindings/audiotools/SpeedChanger.h deleted file mode 100644 index d31ae6d6bdc..00000000000 --- a/shared-bindings/audiotools/SpeedChanger.h +++ /dev/null @@ -1,17 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "shared-module/audiotools/SpeedChanger.h" - -extern const mp_obj_type_t audiotools_speedchanger_type; - -void common_hal_audiotools_speedchanger_construct(audiotools_speedchanger_obj_t *self, - mp_obj_t source, uint32_t rate_fp); -void common_hal_audiotools_speedchanger_deinit(audiotools_speedchanger_obj_t *self); -void common_hal_audiotools_speedchanger_set_rate(audiotools_speedchanger_obj_t *self, uint32_t rate_fp); -uint32_t common_hal_audiotools_speedchanger_get_rate(audiotools_speedchanger_obj_t *self); diff --git a/shared-bindings/audiotools/__init__.c b/shared-bindings/audiotools/__init__.c deleted file mode 100644 index 3d610aa1dbf..00000000000 --- a/shared-bindings/audiotools/__init__.c +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt -// -// SPDX-License-Identifier: MIT - -#include - -#include "py/obj.h" -#include "py/runtime.h" - -#include "shared-bindings/audiotools/SpeedChanger.h" - -//| """Audio processing tools""" - -static const mp_rom_map_elem_t audiotools_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiotools) }, - { MP_ROM_QSTR(MP_QSTR_SpeedChanger), MP_ROM_PTR(&audiotools_speedchanger_type) }, -}; - -static MP_DEFINE_CONST_DICT(audiotools_module_globals, audiotools_module_globals_table); - -const mp_obj_module_t audiotools_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&audiotools_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_audiotools, audiotools_module); diff --git a/shared-module/audiotools/SpeedChanger.c b/shared-module/audiospeed/SpeedChanger.c similarity index 90% rename from shared-module/audiotools/SpeedChanger.c rename to shared-module/audiospeed/SpeedChanger.c index 2bf03cf1aa9..e76bed1f17c 100644 --- a/shared-module/audiotools/SpeedChanger.c +++ b/shared-module/audiospeed/SpeedChanger.c @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT -#include "shared-bindings/audiotools/SpeedChanger.h" +#include "shared-bindings/audiospeed/SpeedChanger.h" #include #include "py/runtime.h" @@ -15,7 +15,7 @@ #define OUTPUT_BUFFER_FRAMES 128 -void common_hal_audiotools_speedchanger_construct(audiotools_speedchanger_obj_t *self, +void common_hal_audiospeed_speedchanger_construct(audiospeed_speedchanger_obj_t *self, mp_obj_t source, uint32_t rate_fp) { audiosample_base_t *src_base = audiosample_check(source); @@ -45,22 +45,22 @@ void common_hal_audiotools_speedchanger_construct(audiotools_speedchanger_obj_t } } -void common_hal_audiotools_speedchanger_deinit(audiotools_speedchanger_obj_t *self) { +void common_hal_audiospeed_speedchanger_deinit(audiospeed_speedchanger_obj_t *self) { self->output_buffer = NULL; self->source = MP_OBJ_NULL; audiosample_mark_deinit(&self->base); } -void common_hal_audiotools_speedchanger_set_rate(audiotools_speedchanger_obj_t *self, uint32_t rate_fp) { +void common_hal_audiospeed_speedchanger_set_rate(audiospeed_speedchanger_obj_t *self, uint32_t rate_fp) { self->rate_fp = rate_fp; } -uint32_t common_hal_audiotools_speedchanger_get_rate(audiotools_speedchanger_obj_t *self) { +uint32_t common_hal_audiospeed_speedchanger_get_rate(audiospeed_speedchanger_obj_t *self) { return self->rate_fp; } // Fetch the next buffer from the source. Returns false if no data available. -static bool fetch_source_buffer(audiotools_speedchanger_obj_t *self) { +static bool fetch_source_buffer(audiospeed_speedchanger_obj_t *self) { if (self->source_exhausted) { return false; } @@ -85,7 +85,7 @@ static bool fetch_source_buffer(audiotools_speedchanger_obj_t *self) { return true; } -void audiotools_speedchanger_reset_buffer(audiotools_speedchanger_obj_t *self, +void audiospeed_speedchanger_reset_buffer(audiospeed_speedchanger_obj_t *self, bool single_channel_output, uint8_t channel) { if (single_channel_output && channel == 1) { return; @@ -99,7 +99,7 @@ void audiotools_speedchanger_reset_buffer(audiotools_speedchanger_obj_t *self, self->source_exhausted = false; } -audioio_get_buffer_result_t audiotools_speedchanger_get_buffer(audiotools_speedchanger_obj_t *self, +audioio_get_buffer_result_t audiospeed_speedchanger_get_buffer(audiospeed_speedchanger_obj_t *self, bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { diff --git a/shared-module/audiotools/SpeedChanger.h b/shared-module/audiospeed/SpeedChanger.h similarity index 84% rename from shared-module/audiotools/SpeedChanger.h rename to shared-module/audiospeed/SpeedChanger.h index 05cbec56fde..e920c72caf4 100644 --- a/shared-module/audiotools/SpeedChanger.h +++ b/shared-module/audiospeed/SpeedChanger.h @@ -26,10 +26,10 @@ typedef struct { uint32_t rate_fp; // 16.16 fixed-point rate bool source_done; // source returned DONE on last get_buffer bool source_exhausted; // source DONE and we consumed all of it -} audiotools_speedchanger_obj_t; +} audiospeed_speedchanger_obj_t; -void audiotools_speedchanger_reset_buffer(audiotools_speedchanger_obj_t *self, +void audiospeed_speedchanger_reset_buffer(audiospeed_speedchanger_obj_t *self, bool single_channel_output, uint8_t channel); -audioio_get_buffer_result_t audiotools_speedchanger_get_buffer(audiotools_speedchanger_obj_t *self, +audioio_get_buffer_result_t audiospeed_speedchanger_get_buffer(audiospeed_speedchanger_obj_t *self, bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); diff --git a/shared-module/audiotools/__init__.c b/shared-module/audiospeed/__init__.c similarity index 100% rename from shared-module/audiotools/__init__.c rename to shared-module/audiospeed/__init__.c diff --git a/shared-module/audiotools/__init__.h b/shared-module/audiospeed/__init__.h similarity index 100% rename from shared-module/audiotools/__init__.h rename to shared-module/audiospeed/__init__.h From db2d03d643ea1aec45333f2329feb9f26d343c69 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 30 Mar 2026 15:05:40 -0700 Subject: [PATCH 362/876] Zephyr fixes 1. Fix flash writing with more than 32 filesystem blocks per erase page and add a test for it. 2. Fix Feather UF2 to place code in the right spot (the code partition). --- ports/zephyr-cp/Makefile | 9 +- ports/zephyr-cp/cptools/build_all_boards.py | 9 + ports/zephyr-cp/prj.conf | 1 + ports/zephyr-cp/supervisor/flash.c | 215 ++++++++++---------- ports/zephyr-cp/tests/__init__.py | 3 +- ports/zephyr-cp/tests/conftest.py | 25 ++- ports/zephyr-cp/tests/test_flash.py | 171 ++++++++++++++++ ports/zephyr-cp/zephyr-config/west.yml | 2 +- 8 files changed, 324 insertions(+), 111 deletions(-) create mode 100644 ports/zephyr-cp/tests/test_flash.py diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index ae1260c0f4d..5c4db4f9065 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -21,7 +21,7 @@ ifeq ($(DEBUG),1) WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_CONF_FILE=$(DEBUG_CONF_FILE) endif -.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug debug-jlink debugserver attach run run-sim clean menuconfig all clean-all test fetch-port-submodules +.PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug debug-jlink debugserver attach run run-sim clean menuconfig all clean-all sim clean-sim test fetch-port-submodules $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) @@ -87,6 +87,13 @@ all: clean-all: rm -rf build build-* +# Build all sim boards concurrently using the same jobserver as `make all`. +sim: + +python cptools/build_all_boards.py --vendor native --continue-on-error + +clean-sim: + rm -rf $(wildcard build-native_*) + test: build-native_native_sim/zephyr-cp/zephyr/zephyr.exe pytest cptools/tests pytest tests/ -v diff --git a/ports/zephyr-cp/cptools/build_all_boards.py b/ports/zephyr-cp/cptools/build_all_boards.py index da9f45ead1e..8505e732efe 100755 --- a/ports/zephyr-cp/cptools/build_all_boards.py +++ b/ports/zephyr-cp/cptools/build_all_boards.py @@ -426,6 +426,12 @@ def main(): action="store_true", help="Continue building remaining boards even if one fails", ) + parser.add_argument( + "--vendor", + type=str, + default=None, + help="Only build boards from this vendor (e.g. 'native' for sim boards)", + ) args = parser.parse_args() @@ -439,6 +445,9 @@ def main(): # Discover all boards boards = discover_boards(port_dir) + if args.vendor: + boards = [(v, b) for v, b in boards if v == args.vendor] + if not boards: print("ERROR: No boards found!") return 1 diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 9b4dcccb53e..6aa5bd65af5 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -1,6 +1,7 @@ CONFIG_SYS_HEAP_RUNTIME_STATS=n CONFIG_FLASH=y CONFIG_FLASH_MAP=y +CONFIG_USE_DT_CODE_PARTITION=y CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_UART_INTERRUPT_DRIVEN=y diff --git a/ports/zephyr-cp/supervisor/flash.c b/ports/zephyr-cp/supervisor/flash.c index 38f35a5235a..a13bb3cffcb 100644 --- a/ports/zephyr-cp/supervisor/flash.c +++ b/ports/zephyr-cp/supervisor/flash.c @@ -31,15 +31,14 @@ static struct flash_area _dynamic_area; extern const struct device *const flashes[]; extern const int circuitpy_flash_device_count; -// Size of an erase area +// Size of an erase page. static size_t _page_size; -// Size of a write area -static size_t _row_size; +// The value a flash byte has after being erased (usually 0xFF, but can differ). +static uint8_t _erase_value; -// Number of file system blocks in a page. +// Number of FILESYSTEM_BLOCK_SIZE blocks in an erase page. static size_t _blocks_per_page; -static size_t _rows_per_block; static uint32_t _page_mask; #define NO_PAGE_LOADED 0xFFFFFFFF @@ -49,14 +48,41 @@ static uint32_t _current_page_address; static uint32_t _scratch_page_address; -// Track which blocks (up to 32) in the current sector currently live in the -// cache. -static uint32_t _dirty_mask; -static uint32_t _loaded_mask; +// Per-block flags packed into a uint8_t array (one byte per block). +#define ROW_LOADED 0x01 // Block data is present in the cache. +#define ROW_DIRTY 0x02 // Block has been modified since last flush. +#define ROW_ERASED 0x04 // Block is all 0xFF; no need to write after erase. + +static uint8_t *_row_flags = NULL; + +static inline void _clear_row_flags(void) { + if (_row_flags != NULL) { + memset(_row_flags, 0, _blocks_per_page); + } +} + +static inline bool _any_dirty(void) { + for (size_t i = 0; i < _blocks_per_page; i++) { + if (_row_flags[i] & ROW_DIRTY) { + return true; + } + } + return false; +} + +// Check if a buffer is entirely the erase value. +static bool _buffer_is_erased(const uint8_t *buf, size_t len) { + for (size_t i = 0; i < len; i++) { + if (buf[i] != _erase_value) { + return false; + } + } + return true; +} // Table of pointers to each cached block. Should be zero'd after allocation. -#define FLASH_CACHE_TABLE_NUM_ENTRIES (_blocks_per_page * _rows_per_block) -#define FLASH_CACHE_TABLE_SIZE (FLASH_CACHE_TABLE_NUM_ENTRIES * sizeof (uint8_t *)) +#define FLASH_CACHE_TABLE_NUM_ENTRIES (_blocks_per_page) +#define FLASH_CACHE_TABLE_SIZE (FLASH_CACHE_TABLE_NUM_ENTRIES * sizeof(uint8_t *)) static uint8_t **flash_cache_table = NULL; static K_MUTEX_DEFINE(_mutex); @@ -171,52 +197,44 @@ void supervisor_flash_init(void) { return; } - const struct device *d = flash_area_get_device(filesystem_area); - _row_size = flash_get_write_block_size(d); - if (_row_size < 256) { - if (256 % _row_size == 0) { - _row_size = 256; - } else { - size_t new_row_size = _row_size; - while (new_row_size < 256) { - new_row_size += _row_size; - } - _row_size = new_row_size; - } - } struct flash_pages_info first_info; + const struct device *d = flash_area_get_device(filesystem_area); + const struct flash_parameters *fp = flash_get_parameters(d); + _erase_value = fp->erase_value; flash_get_page_info_by_offs(d, filesystem_area->fa_off, &first_info); struct flash_pages_info last_info; - flash_get_page_info_by_offs(d, filesystem_area->fa_off + filesystem_area->fa_size - _row_size, &last_info); + flash_get_page_info_by_offs(d, filesystem_area->fa_off + filesystem_area->fa_size - FILESYSTEM_BLOCK_SIZE, &last_info); _page_size = first_info.size; if (_page_size < FILESYSTEM_BLOCK_SIZE) { _page_size = FILESYSTEM_BLOCK_SIZE; } - printk(" erase page size %d\n", _page_size); - // Makes sure that a cached page has 32 or fewer rows. Our dirty mask is - // only 32 bits. - while (_page_size / _row_size > 32) { - _row_size *= 2; - } - printk(" write row size %d\n", _row_size); _blocks_per_page = _page_size / FILESYSTEM_BLOCK_SIZE; - printk(" blocks per page %d\n", _blocks_per_page); - _rows_per_block = FILESYSTEM_BLOCK_SIZE / _row_size; _page_mask = ~(_page_size - 1); + printk(" erase page size %d\n", _page_size); + printk(" blocks per page %d\n", _blocks_per_page); + + _row_flags = port_malloc(_blocks_per_page, false); + if (_row_flags == NULL) { + printk("Unable to allocate row flags (%d bytes)\n", _blocks_per_page); + filesystem_area = NULL; + return; + } + memset(_row_flags, 0, _blocks_per_page); + // The last page is the scratch sector. - _scratch_page_address = last_info.start_offset; + _scratch_page_address = last_info.start_offset - filesystem_area->fa_off; _current_page_address = NO_PAGE_LOADED; } uint32_t supervisor_flash_get_block_size(void) { - return 512; + return FILESYSTEM_BLOCK_SIZE; } uint32_t supervisor_flash_get_block_count(void) { if (filesystem_area == NULL) { return 0; } - return (_scratch_page_address - filesystem_area->fa_off) / 512; + return _scratch_page_address / FILESYSTEM_BLOCK_SIZE; } @@ -245,10 +263,8 @@ static bool write_flash(uint32_t address, const uint8_t *data, uint32_t data_len static bool block_erased(uint32_t sector_address) { uint8_t short_buffer[4]; if (read_flash(sector_address, short_buffer, 4)) { - for (uint16_t i = 0; i < 4; i++) { - if (short_buffer[i] != 0xff) { - return false; - } + if (!_buffer_is_erased(short_buffer, 4)) { + return false; } } else { return false; @@ -257,10 +273,8 @@ static bool block_erased(uint32_t sector_address) { // Now check the full length. uint8_t full_buffer[FILESYSTEM_BLOCK_SIZE]; if (read_flash(sector_address, full_buffer, FILESYSTEM_BLOCK_SIZE)) { - for (uint16_t i = 0; i < FILESYSTEM_BLOCK_SIZE; i++) { - if (short_buffer[i] != 0xff) { - return false; - } + if (!_buffer_is_erased(full_buffer, FILESYSTEM_BLOCK_SIZE)) { + return false; } } else { return false; @@ -278,17 +292,26 @@ static bool erase_page(uint32_t sector_address) { return res == 0; } -// Sector is really 24 bits. static bool copy_block(uint32_t src_address, uint32_t dest_address) { - // Copy row by row to minimize RAM buffer. - uint8_t buffer[_row_size]; - for (uint32_t i = 0; i < FILESYSTEM_BLOCK_SIZE / _row_size; i++) { - if (!read_flash(src_address + i * _row_size, buffer, _row_size)) { - return false; - } - if (!write_flash(dest_address + i * _row_size, buffer, _row_size)) { - return false; - } + uint8_t buffer[FILESYSTEM_BLOCK_SIZE]; + if (!read_flash(src_address, buffer, FILESYSTEM_BLOCK_SIZE)) { + return false; + } + if (!write_flash(dest_address, buffer, FILESYSTEM_BLOCK_SIZE)) { + return false; + } + return true; +} + +// Load a block into the ram cache and set its flags. Returns false on read error. +static bool _load_block_into_cache(size_t block_index) { + if (!read_flash(_current_page_address + block_index * FILESYSTEM_BLOCK_SIZE, + flash_cache_table[block_index], FILESYSTEM_BLOCK_SIZE)) { + return false; + } + _row_flags[block_index] |= ROW_LOADED; + if (_buffer_is_erased(flash_cache_table[block_index], FILESYSTEM_BLOCK_SIZE)) { + _row_flags[block_index] |= ROW_ERASED; } return true; } @@ -303,12 +326,12 @@ static bool flush_scratch_flash(void) { // cached. bool copy_to_scratch_ok = true; for (size_t i = 0; i < _blocks_per_page; i++) { - if ((_dirty_mask & (1 << i)) == 0) { + if (!(_row_flags[i] & ROW_DIRTY)) { copy_to_scratch_ok = copy_to_scratch_ok && copy_block(_current_page_address + i * FILESYSTEM_BLOCK_SIZE, _scratch_page_address + i * FILESYSTEM_BLOCK_SIZE); } - _loaded_mask |= (1 << i); + _row_flags[i] |= ROW_LOADED; } if (!copy_to_scratch_ok) { // TODO(tannewt): Do more here. We opted to not erase and copy bad data @@ -341,7 +364,7 @@ static void release_ram_cache(void) { port_free(flash_cache_table); flash_cache_table = NULL; _current_page_address = NO_PAGE_LOADED; - _loaded_mask = 0; + _clear_row_flags(); } // Attempts to allocate a new set of page buffers for caching a full sector in @@ -350,7 +373,7 @@ static void release_ram_cache(void) { static bool allocate_ram_cache(void) { flash_cache_table = port_malloc(FLASH_CACHE_TABLE_SIZE, false); if (flash_cache_table == NULL) { - // Not enough space even for the cache table. + printk("Unable to allocate ram cache table\n"); return false; } @@ -359,21 +382,20 @@ static bool allocate_ram_cache(void) { bool success = true; for (size_t i = 0; i < _blocks_per_page && success; i++) { - for (size_t j = 0; j < _rows_per_block && success; j++) { - uint8_t *page_cache = port_malloc(_row_size, false); - if (page_cache == NULL) { - success = false; - break; - } - flash_cache_table[i * _rows_per_block + j] = page_cache; + uint8_t *block_cache = port_malloc(FILESYSTEM_BLOCK_SIZE, false); + if (block_cache == NULL) { + success = false; + break; } + flash_cache_table[i] = block_cache; } // We couldn't allocate enough so give back what we got. if (!success) { + printk("Unable to allocate ram cache pages\n"); release_ram_cache(); } - _loaded_mask = 0; + _clear_row_flags(); _current_page_address = NO_PAGE_LOADED; return success; } @@ -386,7 +408,7 @@ static bool flush_ram_cache(bool keep_cache) { return true; } - if (_current_page_address == NO_PAGE_LOADED || _dirty_mask == 0) { + if (_current_page_address == NO_PAGE_LOADED || !_any_dirty()) { if (!keep_cache) { release_ram_cache(); } @@ -397,21 +419,12 @@ static bool flush_ram_cache(bool keep_cache) { // erase below. bool copy_to_ram_ok = true; for (size_t i = 0; i < _blocks_per_page; i++) { - if ((_loaded_mask & (1 << i)) == 0) { - for (size_t j = 0; j < _rows_per_block; j++) { - copy_to_ram_ok = read_flash( - _current_page_address + (i * _rows_per_block + j) * _row_size, - flash_cache_table[i * _rows_per_block + j], - _row_size); - if (!copy_to_ram_ok) { - break; - } + if (!(_row_flags[i] & ROW_LOADED)) { + if (!_load_block_into_cache(i)) { + copy_to_ram_ok = false; + break; } } - if (!copy_to_ram_ok) { - break; - } - _loaded_mask |= (1 << i); } if (!copy_to_ram_ok) { @@ -421,14 +434,19 @@ static bool flush_ram_cache(bool keep_cache) { erase_page(_current_page_address); // Lastly, write all the data in ram that we've cached. for (size_t i = 0; i < _blocks_per_page; i++) { - for (size_t j = 0; j < _rows_per_block; j++) { - write_flash(_current_page_address + (i * _rows_per_block + j) * _row_size, - flash_cache_table[i * _rows_per_block + j], - _row_size); + // Skip blocks that are entirely erased — the page erase already + // set them to 0xFF so writing would be redundant. + if (_row_flags[i] & ROW_ERASED) { + continue; } + write_flash(_current_page_address + i * FILESYSTEM_BLOCK_SIZE, + flash_cache_table[i], + FILESYSTEM_BLOCK_SIZE); + } + // Nothing is dirty anymore. Clear dirty but keep loaded and erased. + for (size_t i = 0; i < _blocks_per_page; i++) { + _row_flags[i] &= ~ROW_DIRTY; } - // Nothing is dirty anymore. Some may already be in the cache cleanly. - _dirty_mask = 0; // We're done with the cache for now so give it back. if (!keep_cache) { @@ -491,15 +509,10 @@ static bool _flash_read_block(uint8_t *dest, uint32_t block) { // Mask out the lower bits that designate the address within the sector. uint32_t page_address = address & _page_mask; size_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % _blocks_per_page; - uint32_t mask = 1 << (block_index); // We're reading from the currently cached sector. - if (_current_page_address == page_address && (mask & _loaded_mask) > 0) { + if (_current_page_address == page_address && (_row_flags[block_index] & ROW_LOADED)) { if (flash_cache_table != NULL) { - for (int i = 0; i < _rows_per_block; i++) { - memcpy(dest + i * _row_size, - flash_cache_table[block_index * _rows_per_block + i], - _row_size); - } + memcpy(dest, flash_cache_table[block_index], FILESYSTEM_BLOCK_SIZE); return true; } uint32_t scratch_block_address = _scratch_page_address + block_index * FILESYSTEM_BLOCK_SIZE; @@ -518,7 +531,6 @@ static bool _flash_write_block(const uint8_t *data, uint32_t block) { // Mask out the lower bits that designate the address within the sector. uint32_t page_address = address & _page_mask; size_t block_index = (address / FILESYSTEM_BLOCK_SIZE) % _blocks_per_page; - uint32_t mask = 1 << (block_index); // Flush the cache if we're moving onto a different page. if (_current_page_address != page_address) { // Check to see if we'd write to an erased block and aren't writing to @@ -533,19 +545,12 @@ static bool _flash_write_block(const uint8_t *data, uint32_t block) { erase_page(_scratch_page_address); } _current_page_address = page_address; - _dirty_mask = 0; - _loaded_mask = 0; + _clear_row_flags(); } - _dirty_mask |= mask; - _loaded_mask |= mask; - + _row_flags[block_index] = ROW_DIRTY | ROW_LOADED; // Copy the block to the appropriate cache. if (flash_cache_table != NULL) { - for (int i = 0; i < _rows_per_block; i++) { - memcpy(flash_cache_table[block_index * _rows_per_block + i], - data + i * _row_size, - _row_size); - } + memcpy(flash_cache_table[block_index], data, FILESYSTEM_BLOCK_SIZE); return true; } else { uint32_t scratch_block_address = _scratch_page_address + block_index * FILESYSTEM_BLOCK_SIZE; diff --git a/ports/zephyr-cp/tests/__init__.py b/ports/zephyr-cp/tests/__init__.py index 8ab7610ce0f..e9039dd88b3 100644 --- a/ports/zephyr-cp/tests/__init__.py +++ b/ports/zephyr-cp/tests/__init__.py @@ -108,12 +108,13 @@ def write(self, text): class NativeSimProcess: - def __init__(self, cmd, timeout=5, trace_file=None, env=None): + def __init__(self, cmd, timeout=5, trace_file=None, env=None, flash_file=None): if trace_file: cmd.append(f"--trace-file={trace_file}") self._timeout = timeout self.trace_file = trace_file + self.flash_file = flash_file print("Running", " ".join(cmd)) self._proc = subprocess.Popen( cmd, diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index b0047f0c947..cec867a9703 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -73,6 +73,10 @@ def pytest_configure(config): "markers", "display_mono_vtiled(value): override the mono vtiled screen_info flag (True or False)", ) + config.addinivalue_line( + "markers", + "flash_config(erase_block_size=N, total_size=N): override flash simulator parameters", + ) ZEPHYR_CP = Path(__file__).parent.parent @@ -264,10 +268,19 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp use_realtime = request.node.get_closest_marker("native_sim_rt") is not None + flash_config_marker = request.node.get_closest_marker("flash_config") + flash_total_size = 2 * 1024 * 1024 # default 2MB + flash_erase_block_size = None + flash_write_block_size = None + if flash_config_marker: + flash_total_size = flash_config_marker.kwargs.get("total_size", flash_total_size) + flash_erase_block_size = flash_config_marker.kwargs.get("erase_block_size", None) + flash_write_block_size = flash_config_marker.kwargs.get("write_block_size", None) + procs = [] for i in range(instance_count): flash = tmp_path / f"flash-{i}.bin" - flash.write_bytes(b"\xff" * (2 * 1024 * 1024)) + flash.write_bytes(b"\xff" * flash_total_size) files = None if len(drives[i][1].args) == 1: files = drives[i][1].args[0] @@ -308,6 +321,13 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp (realtime_flag, "-display_headless", "-wait_uart", f"--vm-runs={code_py_runs + 1}") ) + if flash_erase_block_size is not None: + cmd.append(f"--flash_erase_block_size={flash_erase_block_size}") + if flash_write_block_size is not None: + cmd.append(f"--flash_write_block_size={flash_write_block_size}") + if flash_config_marker and "total_size" in flash_config_marker.kwargs: + cmd.append(f"--flash_total_size={flash_total_size}") + if input_trace_file is not None: cmd.append(f"--input-trace={input_trace_file}") @@ -334,12 +354,11 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp cmd.append(f"--display_capture_png={capture_png_pattern}") logger.info("Running: %s", " ".join(cmd)) - proc = NativeSimProcess(cmd, timeout, trace_file, env) + proc = NativeSimProcess(cmd, timeout, trace_file, env, flash_file=flash) proc.display_dump = None proc._capture_png_pattern = capture_png_pattern proc._capture_count = len(capture_times_ns) if capture_times_ns is not None else 0 procs.append(proc) - if instance_count == 1: yield procs[0] else: diff --git a/ports/zephyr-cp/tests/test_flash.py b/ports/zephyr-cp/tests/test_flash.py new file mode 100644 index 00000000000..e2e5f4de14f --- /dev/null +++ b/ports/zephyr-cp/tests/test_flash.py @@ -0,0 +1,171 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test flash filesystem with various erase block sizes.""" + +import subprocess + +import pytest + + +def read_file_from_flash(flash_file, path): + """Extract a file from the FAT filesystem in the flash image.""" + result = subprocess.run( + ["mcopy", "-i", str(flash_file), f"::{path}", "-"], + capture_output=True, + ) + if result.returncode != 0: + raise FileNotFoundError( + f"Failed to read ::{path} from {flash_file}: {result.stderr.decode()}" + ) + return result.stdout.decode() + + +WRITE_READ_CODE = """\ +import storage +storage.remount("/", readonly=False) +with open("/test.txt", "w") as f: + f.write("hello flash") +with open("/test.txt", "r") as f: + content = f.read() +print(f"content: {content}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_READ_CODE}) +def test_flash_default_erase_size(circuitpython): + """Test filesystem write/read with default 4KB erase blocks.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "content: hello flash" in output + assert "done" in output + + content = read_file_from_flash(circuitpython.flash_file, "test.txt") + assert content == "hello flash" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_READ_CODE}) +@pytest.mark.flash_config(erase_block_size=65536) +def test_flash_64k_erase_blocks(circuitpython): + """Test filesystem write/read with 64KB erase blocks (128 blocks per page).""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "content: hello flash" in output + assert "done" in output + + content = read_file_from_flash(circuitpython.flash_file, "test.txt") + assert content == "hello flash" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_READ_CODE}) +@pytest.mark.flash_config(erase_block_size=262144, total_size=4 * 1024 * 1024) +def test_flash_256k_erase_blocks(circuitpython): + """Test filesystem write/read with 256KB erase blocks (like RA8D1 OSPI).""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "content: hello flash" in output + assert "done" in output + + content = read_file_from_flash(circuitpython.flash_file, "test.txt") + assert content == "hello flash" + + +MULTI_FILE_CODE = """\ +import storage +storage.remount("/", readonly=False) +for i in range(5): + name = f"/file{i}.txt" + with open(name, "w") as f: + f.write(f"data{i}" * 100) +print("multi_file_ok") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": MULTI_FILE_CODE}) +@pytest.mark.flash_config(erase_block_size=262144, total_size=4 * 1024 * 1024) +def test_flash_256k_multi_file(circuitpython): + """Test multiple file writes with 256KB erase blocks to exercise cache flushing.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "multi_file_ok" in output + + for i in range(5): + content = read_file_from_flash(circuitpython.flash_file, f"file{i}.txt") + assert content == f"data{i}" * 100, f"file{i}.txt mismatch" + + +EXISTING_DATA_CODE = """\ +import storage +storage.remount("/", readonly=False) + +# Write a file to populate the erase page. +original_data = "A" * 4000 +with open("/original.txt", "w") as f: + f.write(original_data) + +# Force a flush so the data is written to flash. +storage.remount("/", readonly=True) +storage.remount("/", readonly=False) + +# Now write a small new file. This updates FAT metadata and directory +# entries that share an erase page with original.txt, exercising the +# read-modify-write cycle on the cached page. +with open("/small.txt", "w") as f: + f.write("tiny") + +# Read back original to check it survived. +with open("/original.txt", "r") as f: + readback = f.read() +if readback == original_data: + print("existing_data_ok") +else: + print(f"MISMATCH: got {len(readback)} bytes") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EXISTING_DATA_CODE}) +@pytest.mark.flash_config(erase_block_size=262144, total_size=4 * 1024 * 1024) +def test_flash_256k_existing_data_survives(circuitpython): + """Test that existing data in an erase page survives when new data is written. + + With 256KB erase blocks (512 blocks per page), writing to any block in + the page triggers an erase-rewrite of the entire page. Existing blocks + must be preserved through the read-modify-write cycle. + """ + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "existing_data_ok" in output + + # Verify both files survived on the actual flash image. + original = read_file_from_flash(circuitpython.flash_file, "original.txt") + assert original == "A" * 4000, f"original.txt corrupted: got {len(original)} bytes" + + small = read_file_from_flash(circuitpython.flash_file, "small.txt") + assert small == "tiny" + + +OVERWRITE_CODE = """\ +import storage +storage.remount("/", readonly=False) +with open("/overwrite.txt", "w") as f: + f.write("first version") +with open("/overwrite.txt", "w") as f: + f.write("second version") +print("overwrite_ok") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": OVERWRITE_CODE}) +@pytest.mark.flash_config(erase_block_size=262144, total_size=4 * 1024 * 1024) +def test_flash_256k_overwrite(circuitpython): + """Test overwriting a file with 256KB erase blocks to exercise erase-rewrite cycle.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "overwrite_ok" in output + + content = read_file_from_flash(circuitpython.flash_file, "overwrite.txt") + assert content == "second version" diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 5433da0e81a..fd3eebc66f1 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -8,6 +8,6 @@ manifest: path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: 152e280f154a50035c2f054eceeb107fa3bb474f + revision: a768573cc42b18bc2e8b819d4686e52cdb9c848e clone-depth: 100 import: true From 5007e8b8e2cfd2f2c37e336f2bb9331f0b7eecd7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 31 Mar 2026 15:07:16 -0700 Subject: [PATCH 363/876] Only code partition for feather --- ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf | 2 ++ ports/zephyr-cp/prj.conf | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf index 4849c8ce2b4..20176b34be0 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf @@ -5,4 +5,6 @@ CONFIG_BT_BROADCASTER=y CONFIG_BT_OBSERVER=y CONFIG_BT_EXT_ADV=y +CONFIG_USE_DT_CODE_PARTITION=y + CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 6aa5bd65af5..9b4dcccb53e 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -1,7 +1,6 @@ CONFIG_SYS_HEAP_RUNTIME_STATS=n CONFIG_FLASH=y CONFIG_FLASH_MAP=y -CONFIG_USE_DT_CODE_PARTITION=y CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_UART_INTERRUPT_DRIVEN=y From abbd8b054a05a53654358b138d705f23bc03d97c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 30 Mar 2026 15:48:32 -0700 Subject: [PATCH 364/876] Add Zephyr board defs for Raspberry Pi Picos Add board defs for rpi_pico_zephyr, rpi_pico_w_zephyr, rpi_pico2_zephyr, and rpi_pico2_w_zephyr. Flash partitions (NVM at 0x180000, CircuitPy at 0x181000) match the native raspberrypi port so users can switch between ports without reformatting. Also enable MICROPY_NLR_THUMB_USE_LONG_JUMP for the Zephyr port to fix Cortex-M0+ linker relocation errors in nlr_push. Devices should enumerate but may have bugs after that. These board definitions are meant to make it easier to test the current state of the Zephyr port. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.rst | 2 +- ports/zephyr-cp/boards/board_aliases.cmake | 4 + ports/zephyr-cp/boards/frdm_rw612.conf | 1 + .../autogen_board_info.toml | 119 ++++++ .../rpi_pico2_w_zephyr/circuitpython.toml | 2 + .../rpi_pico2_zephyr/autogen_board_info.toml | 119 ++++++ .../rpi_pico2_zephyr/circuitpython.toml | 1 + .../rpi_pico_w_zephyr/autogen_board_info.toml | 119 ++++++ .../rpi_pico_w_zephyr/circuitpython.toml | 2 + .../rpi_pico_zephyr/autogen_board_info.toml | 119 ++++++ .../rpi_pico_zephyr/circuitpython.toml | 1 + .../boards/rpi_pico2_rp2350a_m33.overlay | 25 ++ .../boards/rpi_pico2_rp2350a_m33_w.conf | 24 ++ .../boards/rpi_pico2_rp2350a_m33_w.overlay | 25 ++ .../zephyr-cp/boards/rpi_pico_rp2040.overlay | 34 ++ ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf | 26 ++ .../boards/rpi_pico_rp2040_w.overlay | 34 ++ ports/zephyr-cp/common-hal/wifi/Radio.c | 10 +- ports/zephyr-cp/common-hal/wifi/__init__.c | 10 +- .../zephyr-cp/cptools/build_circuitpython.py | 2 + ports/zephyr-cp/cptools/compat2driver.py | 400 +++++++++++++++--- ports/zephyr-cp/cptools/gen_compat2driver.py | 2 +- ports/zephyr-cp/cptools/zephyr2cp.py | 34 +- ports/zephyr-cp/mpconfigport.h | 2 + ports/zephyr-cp/supervisor/port.c | 4 + 25 files changed, 1047 insertions(+), 74 deletions(-) create mode 100644 ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay create mode 100644 ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf create mode 100644 ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay create mode 100644 ports/zephyr-cp/boards/rpi_pico_rp2040.overlay create mode 100644 ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf create mode 100644 ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay diff --git a/README.rst b/README.rst index 80aa1b2aee2..89c7d9229d8 100644 --- a/README.rst +++ b/README.rst @@ -226,7 +226,7 @@ Ports Ports include the code unique to a microcontroller line. -The following ports are available: ``atmel-samd``, ``cxd56``, ``espressif``, ``litex``, ``mimxrt10xx``, ``nordic``, ``raspberrypi``, ``renode``, ``silabs`` (``efr32``), ``stm``, ``unix``. +The following ports are available: ``atmel-samd``, ``cxd56``, ``espressif``, ``litex``, ``mimxrt10xx``, ``nordic``, ``raspberrypi``, ``renode``, ``silabs`` (``efr32``), ``stm``, ``unix``, and ``zephyr-cp``. However, not all ports are fully functional. Some have limited functionality and known serious bugs. For details, refer to the **Port status** section in the `latest release `__ notes. diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index 5914ae61f28..e973eac72d4 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -44,4 +44,8 @@ cp_board_alias(st_stm32h7b3i_dk stm32h7b3i_dk) cp_board_alias(st_stm32h750b_dk stm32h750b_dk/stm32h750xx/ext_flash_app) cp_board_alias(st_stm32wba65i_dk1 stm32wba65i_dk1) cp_board_alias(st_nucleo_u575zi_q nucleo_u575zi_q/stm32u575xx) +cp_board_alias(raspberrypi_rpi_pico_zephyr rpi_pico/rp2040) +cp_board_alias(raspberrypi_rpi_pico_w_zephyr rpi_pico/rp2040/w) +cp_board_alias(raspberrypi_rpi_pico2_zephyr rpi_pico2/rp2350a/m33) +cp_board_alias(raspberrypi_rpi_pico2_w_zephyr rpi_pico2/rp2350a/m33/w) cp_board_alias(st_nucleo_n657x0_q nucleo_n657x0_q/stm32n657xx) diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf index 4fc5c8c5bf0..ac9a43646a1 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.conf +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -18,6 +18,7 @@ CONFIG_MBEDTLS_RSA_C=y CONFIG_MBEDTLS_PKCS1_V15=y CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=y CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CIPHER_AES_ENABLED=y CONFIG_MBEDTLS_CTR_DRBG_C=y CONFIG_MBEDTLS_SHA1=y CONFIG_MBEDTLS_USE_PSA_CRYPTO=n diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..8c1f7018f12 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -0,0 +1,119 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Raspberry Pi Foundation Raspberry Pi Pico 2" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = true # Zephyr networking enabled +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = true # Zephyr board has wifi +zephyr_display = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/circuitpython.toml new file mode 100644 index 00000000000..0f901d1149e --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/circuitpython.toml @@ -0,0 +1,2 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +BLOBS=["hal_infineon"] diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..cdffc295701 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -0,0 +1,119 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Raspberry Pi Foundation Raspberry Pi Pico 2" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/circuitpython.toml new file mode 100644 index 00000000000..9d3c229ed1b --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..d8cee739d65 --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -0,0 +1,119 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Raspberry Pi Foundation Raspberry Pi Pico" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = true # Zephyr networking enabled +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = true # Zephyr board has wifi +zephyr_display = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/circuitpython.toml new file mode 100644 index 00000000000..0f901d1149e --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/circuitpython.toml @@ -0,0 +1,2 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +BLOBS=["hal_infineon"] diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..40fb5baf34a --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -0,0 +1,119 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Raspberry Pi Foundation Raspberry Pi Pico" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/circuitpython.toml new file mode 100644 index 00000000000..9d3c229ed1b --- /dev/null +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay new file mode 100644 index 00000000000..eb94fe7de67 --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay @@ -0,0 +1,25 @@ +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + code_partition: partition@0 { + label = "code-partition"; + reg = <0x0 0x180000>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(4) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf new file mode 100644 index 00000000000..1a0d0010dca --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf @@ -0,0 +1,24 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +CONFIG_WIFI=y +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +CONFIG_NET_HOSTNAME_ENABLE=y +CONFIG_NET_HOSTNAME_DYNAMIC=y +CONFIG_NET_HOSTNAME="circuitpython" + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +CONFIG_MBEDTLS_RSA_C=y +CONFIG_MBEDTLS_PKCS1_V15=y +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=y +CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CIPHER_AES_ENABLED=y +CONFIG_MBEDTLS_CTR_DRBG_C=y +CONFIG_MBEDTLS_SHA1=y +CONFIG_MBEDTLS_USE_PSA_CRYPTO=n diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay new file mode 100644 index 00000000000..eb94fe7de67 --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay @@ -0,0 +1,25 @@ +&flash0 { + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + code_partition: partition@0 { + label = "code-partition"; + reg = <0x0 0x180000>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(4) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay new file mode 100644 index 00000000000..ce9083dd62d --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay @@ -0,0 +1,34 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (0x180000 - 0x100)>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf new file mode 100644 index 00000000000..11d26d946b1 --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf @@ -0,0 +1,26 @@ +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +CONFIG_WIFI=y +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +CONFIG_NET_HOSTNAME_ENABLE=y +CONFIG_NET_HOSTNAME_DYNAMIC=y +CONFIG_NET_HOSTNAME="circuitpython" + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +CONFIG_MBEDTLS_RSA_C=y +CONFIG_MBEDTLS_PKCS1_V15=y +CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=y +CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CIPHER_AES_ENABLED=y +CONFIG_MBEDTLS_CTR_DRBG_C=y +CONFIG_MBEDTLS_SHA1=y +CONFIG_MBEDTLS_USE_PSA_CRYPTO=n + +CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay new file mode 100644 index 00000000000..ce9083dd62d --- /dev/null +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay @@ -0,0 +1,34 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (0x180000 - 0x100)>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 726b406b3ca..35a0b76a362 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -86,13 +86,19 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { // mdns_server_deinit_singleton(); // #endif printk("net_if_down\n"); - CHECK_ZEPHYR_RESULT(net_if_down(self->sta_netif)); + int res = net_if_down(self->sta_netif); + if (res < 0 && res != -EALREADY) { + raise_zephyr_error(res); + } self->started = false; return; } if (!self->started && enabled) { printk("net_if_up\n"); - CHECK_ZEPHYR_RESULT(net_if_up(self->sta_netif)); + int res = net_if_up(self->sta_netif); + if (res < 0 && res != -EALREADY) { + raise_zephyr_error(res); + } self->started = true; self->current_scan = NULL; // common_hal_wifi_radio_set_tx_power(self, CIRCUITPY_WIFI_DEFAULT_TX_POWER); diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index da26d560724..f9e02be2476 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -52,16 +52,17 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve switch (mgmt_event) { case NET_EVENT_WIFI_SCAN_RESULT: { - #if defined(CONFIG_NET_MGMT_EVENT_INFO) + printk("NET_EVENT_WIFI_SCAN_RESULT\n"); const struct wifi_scan_result *result = cb->info; if (result != NULL && self->current_scan != NULL) { wifi_scannednetworks_scan_result(self->current_scan, result); } - #endif break; } case NET_EVENT_WIFI_SCAN_DONE: - printk("NET_EVENT_WIFI_SCAN_DONE\n"); + printk("NET_EVENT_WIFI_SCAN_DONE (thread: %s prio=%d)\n", + k_thread_name_get(k_current_get()), + k_thread_priority_get(k_current_get())); if (self->current_scan != NULL) { k_poll_signal_raise(&self->current_scan->channel_done, 0); } @@ -105,6 +106,9 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve case NET_EVENT_WIFI_AP_STA_DISCONNECTED: printk("NET_EVENT_WIFI_AP_STA_DISCONNECTED\n"); break; + default: + printk("unhandled net event %x\n", mgmt_event); + break; } } diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 5f51281870c..f6f10dde801 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -270,6 +270,8 @@ def determine_enabled_modules(board_info, portdir, srcdir): network_enabled = board_info.get("wifi", False) or board_info.get("hostnetwork", False) if network_enabled: + enabled_modules.add("ipaddress") + module_reasons["ipaddress"] = "Zephyr networking enabled" enabled_modules.add("socketpool") module_reasons["socketpool"] = "Zephyr networking enabled" enabled_modules.add("hashlib") diff --git a/ports/zephyr-cp/cptools/compat2driver.py b/ports/zephyr-cp/cptools/compat2driver.py index dff09787b28..aae490d8f74 100644 --- a/ports/zephyr-cp/cptools/compat2driver.py +++ b/ports/zephyr-cp/cptools/compat2driver.py @@ -15,13 +15,15 @@ "atmel_sam0_adc": "adc", "atmel_sam_adc": "adc", "atmel_sam_afec": "adc", + "bflb_adc": "adc", "ene_kb106x_adc": "adc", "ene_kb1200_adc": "adc", "espressif_esp32_adc": "adc", "gd_gd32_adc": "adc", + "infineon_adc": "adc", "infineon_autanalog_sar_adc": "adc", - "infineon_cat1_adc": "adc", "infineon_hppass_sar_adc": "adc", + "infineon_sar_adc": "adc", "infineon_xmc4xxx_adc": "adc", "ite_it51xxx_adc": "adc", "ite_it8xxx2_adc": "adc", @@ -37,6 +39,7 @@ "maxim_max11117": "adc", "maxim_max11253": "adc", "maxim_max11254": "adc", + "microchip_adc_g1": "adc", "microchip_mcp356xr": "adc", "microchip_xec_adc": "adc", "nordic_nrf_adc": "adc", @@ -53,12 +56,16 @@ "nxp_vf610_adc": "adc", "raspberrypi_pico_adc": "adc", "realtek_rts5912_adc": "adc", - "renesas_ra_adc": "adc", + "renesas_ra_adc12": "adc", + "renesas_ra_adc16": "adc", "renesas_rx_adc": "adc", "renesas_rz_adc": "adc", "renesas_rz_adc_c": "adc", + "renesas_rz_adc_e": "adc", + "renesas_rza2m_adc": "adc", "renesas_smartbond_adc": "adc", "renesas_smartbond_sdadc": "adc", + "sifli_sf32lb_gpadc": "adc", "silabs_gecko_adc": "adc", "silabs_iadc": "adc", "silabs_siwx91x_adc": "adc", @@ -79,6 +86,18 @@ "ti_ads124s08": "adc", "ti_ads131m02": "adc", "ti_ads7052": "adc", + "ti_ads7950": "adc", + "ti_ads7951": "adc", + "ti_ads7952": "adc", + "ti_ads7953": "adc", + "ti_ads7954": "adc", + "ti_ads7955": "adc", + "ti_ads7956": "adc", + "ti_ads7957": "adc", + "ti_ads7958": "adc", + "ti_ads7959": "adc", + "ti_ads7960": "adc", + "ti_ads7961": "adc", "ti_am335x_adc": "adc", "ti_cc13xx_cc26xx_adc": "adc", "ti_cc23x0_adc": "adc", @@ -103,8 +122,10 @@ "cirrus_cs43l22": "audio", "dlg_da7212": "audio", "maxim_max98091": "audio", + "nordic_nrf_pdm": "audio", "nxp_dmic": "audio", "nxp_micfil": "audio", + "sifli_sf32lb_audcodec": "audio", "st_mpxxdtyy": "audio", "ti_pcm1681": "audio", "ti_tas6422dac": "audio", @@ -134,16 +155,22 @@ "st_stm32_bbram": "bbram", "zephyr_bbram_emul": "bbram", # + # biometrics + "adh_tech_gt5x": "biometrics", + "zephyr_biometrics_emul": "biometrics", + "zhiantec_zfm_x0": "biometrics", + # # bluetooth/hci "ambiq_bt_hci_spi": "bluetooth/hci", "espressif_esp32_bt_hci": "bluetooth/hci", - "infineon_cat1_bless_hci": "bluetooth/hci", + "infineon_bless_hci": "bluetooth/hci", + "infineon_bt_hci_uart": "bluetooth/hci", "infineon_cyw208xx_hci": "bluetooth/hci", - "infineon_cyw43xxx_bt_hci": "bluetooth/hci", "nxp_bt_hci_uart": "bluetooth/hci", "nxp_hci_ble": "bluetooth/hci", "renesas_bt_hci_da1453x": "bluetooth/hci", "renesas_bt_hci_da1469x": "bluetooth/hci", + "sifli_sf32lb_mailbox": "bluetooth/hci", "silabs_bt_hci_efr32": "bluetooth/hci", "silabs_siwx91x_bt_hci": "bluetooth/hci", "st_hci_spi_v1": "bluetooth/hci", @@ -195,11 +222,15 @@ "sbs_sbs_charger": "charger", "ti_bq24190": "charger", "ti_bq25180": "charger", + "ti_bq25186": "charger", + "ti_bq25188": "charger", "ti_bq25713": "charger", "x_powers_axp2101_charger": "charger", + "zephyr_charger_gpio": "charger", # # clock_control "adi_max32_gcr": "clock_control", + "alif_clockctrl": "clock_control", "ambiq_clkctrl": "clock_control", "arm_beetle_syscon": "clock_control", "arm_scmi_clock": "clock_control", @@ -210,12 +241,16 @@ "bflb_bl70x_clock_controller": "clock_control", "espressif_esp32_clock": "clock_control", "fixed_clock": "clock_control", + "focaltech_ft9001_cpm": "clock_control", "gd_gd32_cctl": "clock_control", "infineon_fixed_clock": "clock_control", "infineon_fixed_factor_clock": "clock_control", "infineon_peri_div": "clock_control", "intel_agilex5_clock": "clock_control", "ite_it51xxx_ecpm": "clock_control", + "microchip_pic32cm_jh_clock": "clock_control", + "microchip_pic32cm_pl_clock": "clock_control", + "microchip_pic32cz_ca_clock": "clock_control", "microchip_sam_d5x_e5x_clock": "clock_control", "microchip_sam_pmc": "clock_control", "microchip_sama7g5_sckc": "clock_control", @@ -246,6 +281,8 @@ "openisa_rv32m1_pcc": "clock_control", "pwm_clock": "clock_control", "raspberrypi_pico_clock_controller": "clock_control", + "realtek_bee_cctl": "clock_control", + "realtek_rts5817_clock": "clock_control", "realtek_rts5912_sccon": "clock_control", "renesas_r8a7795_cpg_mssr": "clock_control", "renesas_r8a779f0_cpg_mssr": "clock_control", @@ -267,13 +304,17 @@ "st_stm32_clock_mco": "clock_control", "st_stm32_clock_mux": "clock_control", "st_stm32f1_clock_mco": "clock_control", + "ti_k2g_sci_clk": "clock_control", "wch_rcc": "clock_control", # # comparator "ite_it51xxx_vcmp": "comparator", + "microchip_ac_g1_comparator": "comparator", "nordic_nrf_comp": "comparator", "nordic_nrf_lpcomp": "comparator", + "nxp_acomp": "comparator", "nxp_cmp": "comparator", + "nxp_hscmp": "comparator", "renesas_ra_acmphs": "comparator", "renesas_ra_lvd": "comparator", "renesas_rx_lvd": "comparator", @@ -297,16 +338,23 @@ "espressif_esp32_counter": "counter", "espressif_esp32_rtc_timer": "counter", "gd_gd32_timer": "counter", - "infineon_cat1_counter": "counter", + "infineon_counter": "counter", "infineon_tcpwm_counter": "counter", "ite_it51xxx_counter": "counter", "ite_it8xxx2_counter": "counter", "maxim_ds3231": "counter", "microchip_mcp7940n": "counter", + "microchip_sam_pit64b_counter": "counter", + "microchip_tc_g1_counter": "counter", + "microchip_tcc_g1_counter": "counter", "microchip_xec_timer": "counter", + "microcrystal_rv3032_counter": "counter", "neorv32_gptmr": "counter", "nordic_nrf_rtc": "counter", "nordic_nrf_timer": "counter", + "nuvoton_npck_lct": "counter", + "nuvoton_npcx_lct_v1": "counter", + "nuvoton_npcx_lct_v2": "counter", "nxp_ftm": "counter", "nxp_imx_epit": "counter", "nxp_imx_gpt": "counter", @@ -320,9 +368,12 @@ "nxp_mrt": "counter", "nxp_pit": "counter", "nxp_rtc": "counter", + "nxp_rtc_jdp": "counter", "nxp_s32_sys_timer": "counter", "nxp_stm": "counter", "nxp_tpm_timer": "counter", + "raspberrypi_pico_pit": "counter", + "raspberrypi_pico_pit_channel": "counter", "raspberrypi_pico_timer": "counter", "realtek_rts5912_slwtimer": "counter", "realtek_rts5912_timer": "counter", @@ -330,18 +381,22 @@ "renesas_rz_cmtw_counter": "counter", "renesas_rz_gtm_counter": "counter", "renesas_smartbond_timer": "counter", + "silabs_burtc_counter": "counter", "silabs_gecko_rtcc": "counter", + "silabs_timer_counter": "counter", "snps_dw_timers": "counter", "st_stm32_counter": "counter", "ti_cc23x0_lgpt": "counter", "ti_cc23x0_rtc": "counter", "ti_mspm0_timer_counter": "counter", "xlnx_xps_timer_1_00_a": "counter", - "zephyr_native_posix_counter": "counter", "zephyr_native_sim_counter": "counter", # # crc + "nxp_crc": "crc", + "nxp_lpc_crc": "crc", "renesas_ra_crc": "crc", + "sifli_sf32lb_crc": "crc", # # crypto "atmel_ataes132a": "crypto", @@ -351,10 +406,13 @@ "ite_it51xxx_sha": "crypto", "ite_it8xxx2_sha": "crypto", "ite_it8xxx2_sha_v2": "crypto", + "microchip_sha_g1_crypto": "crypto", "microchip_xec_symcr": "crypto", "nordic_nrf_ecb": "crypto", "nuvoton_npcx_sha": "crypto", "nxp_mcux_dcp": "crypto", + "nxp_s32_crypto_hse_mu": "crypto", + "raspberrypi_pico_sha256": "crypto", "realtek_rts5912_sha": "crypto", "renesas_smartbond_crypto": "crypto", "silabs_si32_aes": "crypto", @@ -388,6 +446,7 @@ "atmel_samd5x_dac": "dac", "espressif_esp32_dac": "dac", "gd_gd32_dac": "dac", + "microchip_dac_g1": "dac", "microchip_mcp4725": "dac", "microchip_mcp4728": "dac", "nxp_dac12": "dac", @@ -414,6 +473,9 @@ # dai/intel/ssp "intel_ssp_dai": "dai/intel/ssp", # + # dai/nxp/esai + "nxp_dai_esai": "dai/nxp/esai", + # # dai/nxp/micfil "nxp_dai_micfil": "dai/nxp/micfil", # @@ -462,7 +524,7 @@ "sitronix_st7796s": "display", "solomon_ssd1322": "display", "st_stm32_ltdc": "display", - "waveshare_7inch_dsi_lcd_c": "display", + "waveshare_dsi2dpi": "display", "zephyr_dummy_dc": "display", "zephyr_hub12": "display", "zephyr_sdl_dc": "display", @@ -471,6 +533,7 @@ "adi_max32_dma": "dma", "altr_msgdma": "dma", "andestech_atcdmacx00": "dma", + "arm_dma_pl330": "dma", "atmel_sam0_dmac": "dma", "atmel_sam_xdmac": "dma", "bflb_dma": "dma", @@ -479,7 +542,7 @@ "espressif_esp32_gdma": "dma", "gd_gd32_dma": "dma", "gd_gd32_dma_v1": "dma", - "infineon_cat1_dma": "dma", + "infineon_dma": "dma", "infineon_xmc4xxx_dma": "dma", "intel_adsp_gpdma": "dma", "intel_adsp_hda_host_in": "dma", @@ -488,8 +551,11 @@ "intel_adsp_hda_link_out": "dma", "intel_lpss": "dma", "intel_sedi_dma": "dma", + "microchip_dmac_g1_dma": "dma", "microchip_xec_dmac": "dma", "nuvoton_npcx_gdma": "dma", + "nxp_4ch_dma": "dma", + "nxp_edma": "dma", "nxp_lpc_dma": "dma", "nxp_mcux_edma": "dma", "nxp_pxp": "dma", @@ -525,6 +591,7 @@ # # edac "intel_ibecc": "edac", + "nxp_erm": "edac", "xlnx_zynqmp_ddrc_2_40a": "edac", # # eeprom @@ -547,7 +614,9 @@ "atmel_sam_trng": "entropy", "brcm_iproc_rng200": "entropy", "espressif_esp32_trng": "entropy", + "gd_gd32_trng": "entropy", "litex_prbs": "entropy", + "microchip_trng_g1_entropy": "entropy", "neorv32_trng": "entropy", "nordic_nrf_cracen_ctrdrbg": "entropy", "nordic_nrf_rng": "entropy", @@ -558,16 +627,20 @@ "nxp_kinetis_trng": "entropy", "nxp_lpc_rng": "entropy", "openisa_rv32m1_trng": "entropy", + "raspberrypi_pico_rng": "entropy", "renesas_smartbond_trng": "entropy", "sensry_sy1xx_trng": "entropy", + "sifli_sf32lb_trng": "entropy", "silabs_gecko_semailbox": "entropy", "silabs_gecko_trng": "entropy", "silabs_siwx91x_rng": "entropy", + "st_stm32_rng": "entropy", + "st_stm32_rng_noirq": "entropy", "telink_b91_trng": "entropy", "ti_cc13xx_cc26xx_trng": "entropy", + "ti_mspm0_trng": "entropy", "virtio_device4": "entropy", "zephyr_bt_hci_entropy": "entropy", - "zephyr_native_posix_rng": "entropy", "zephyr_native_sim_rng": "entropy", "zephyr_psa_crypto_rng": "entropy", # @@ -618,7 +691,11 @@ "virtio_net": "ethernet", "vnd_ethernet": "ethernet", "wiznet_w5500": "ethernet", + "wiznet_w6100": "ethernet", "xlnx_axi_ethernet_1_00_a": "ethernet", + "xlnx_gem": "ethernet", + "xlnx_xps_ethernetlite_1_00_a_mac": "ethernet", + "xlnx_xps_ethernetlite_3_00_a_mac": "ethernet", # # ethernet/dsa "microchip_ksz8463": "ethernet/dsa", @@ -637,6 +714,28 @@ "intel_eth_plat": "ethernet/intel", "intel_igc_mac": "ethernet/intel", # + # ethernet/mdio + "adi_adin2111_mdio": "ethernet/mdio", + "atmel_sam_mdio": "ethernet/mdio", + "espressif_esp32_mdio": "ethernet/mdio", + "infineon_xmc4xxx_mdio": "ethernet/mdio", + "intel_igc_mdio": "ethernet/mdio", + "litex_liteeth_mdio": "ethernet/mdio", + "microchip_lan865x_mdio": "ethernet/mdio", + "nxp_enet_mdio": "ethernet/mdio", + "nxp_enet_qos_mdio": "ethernet/mdio", + "nxp_imx_netc_emdio": "ethernet/mdio", + "nxp_s32_gmac_mdio": "ethernet/mdio", + "nxp_s32_netc_emdio": "ethernet/mdio", + "renesas_ra_mdio": "ethernet/mdio", + "sensry_sy1xx_mdio": "ethernet/mdio", + "snps_dwcxgmac_mdio": "ethernet/mdio", + "st_stm32_mdio": "ethernet/mdio", + "xlnx_axi_ethernet_1_00_a_mdio": "ethernet/mdio", + "xlnx_xps_ethernetlite_1_00_a_mdio": "ethernet/mdio", + "xlnx_xps_ethernetlite_3_00_a_mdio": "ethernet/mdio", + "zephyr_mdio_gpio": "ethernet/mdio", + # # ethernet/nxp_imx_netc "nxp_imx_netc_blk_ctrl": "ethernet/nxp_imx_netc", "nxp_imx_netc_psi": "ethernet/nxp_imx_netc", @@ -646,10 +745,13 @@ "adi_adin2111_phy": "ethernet/phy", "davicom_dm8806_phy": "ethernet/phy", "ethernet_phy": "ethernet/phy", + "ethernet_phy_fixed_link": "ethernet/phy", "microchip_ksz8081": "ethernet/phy", "microchip_ksz9131": "ethernet/phy", + "microchip_lan8742": "ethernet/phy", "microchip_t1s_phy": "ethernet/phy", "microchip_vsc8541": "ethernet/phy", + "motorcomm_yt8521": "ethernet/phy", "nxp_tja1103": "ethernet/phy", "nxp_tja11xx": "ethernet/phy", "qca_ar8031": "ethernet/phy", @@ -658,6 +760,7 @@ "ti_dp83867": "ethernet/phy", # # firmware/scmi + "arm_scmi": "firmware/scmi", "arm_scmi_shmem": "firmware/scmi", # # firmware/tisci @@ -673,20 +776,23 @@ "atmel_at45": "flash", "atmel_sam0_nvmctrl": "flash", "atmel_sam_flash_controller": "flash", + "bflb_flash_controller": "flash", "cdns_nand": "flash", "cdns_qspi_nor": "flash", "espressif_esp32_flash_controller": "flash", "gd_gd32_flash_controller": "flash", - "infineon_cat1_flash_controller": "flash", - "infineon_cat1_qspi_flash": "flash", + "infineon_flash_controller": "flash", + "infineon_qspi_flash": "flash", "infineon_xmc4xxx_flash_controller": "flash", "ite_it51xxx_manual_flash_1k": "flash", "ite_it8xxx2_flash_controller": "flash", "jedec_mspi_nor": "flash", + "jedec_spi_nand": "flash", "jedec_spi_nor": "flash", "microchip_nvmctrl_g1_flash": "flash", "mspi_atxp032": "flash", "mspi_is25xx0xx": "flash", + "netsol_s3axx04": "flash", "nordic_mram": "flash", "nordic_nrf51_flash_controller": "flash", "nordic_nrf52_flash_controller": "flash", @@ -699,6 +805,7 @@ "nuvoton_npcx_fiu_qspi": "flash", "nuvoton_numaker_fmc": "flash", "nuvoton_numaker_rmc": "flash", + "nxp_c40_flash_controller": "flash", "nxp_iap_fmc11": "flash", "nxp_iap_fmc54": "flash", "nxp_iap_fmc55": "flash", @@ -707,16 +814,19 @@ "nxp_imx_flexspi_mx25um51345g": "flash", "nxp_imx_flexspi_nor": "flash", "nxp_kinetis_ftfa": "flash", + "nxp_kinetis_ftfc": "flash", "nxp_kinetis_ftfe": "flash", "nxp_kinetis_ftfl": "flash", "nxp_msf1": "flash", "nxp_s32_qspi_hyperflash": "flash", "nxp_s32_qspi_nor": "flash", + "nxp_s32_xspi_hyperram": "flash", "nxp_xspi_nor": "flash", "openisa_rv32m1_ftfe": "flash", "raspberrypi_pico_flash_controller": "flash", "realtek_rts5912_flash_controller": "flash", "renesas_ra_flash_hp_controller": "flash", + "renesas_ra_flash_lp_controller": "flash", "renesas_ra_mram_controller": "flash", "renesas_ra_ospi_b_nor": "flash", "renesas_ra_qspi_nor": "flash", @@ -763,6 +873,9 @@ # fuel_gauge/composite "zephyr_fuel_gauge_composite": "fuel_gauge/composite", # + # fuel_gauge/hy4245 + "hycon_hy4245": "fuel_gauge/hy4245", + # # fuel_gauge/lc709203f "onnn_lc709203f": "fuel_gauge/lc709203f", # @@ -785,10 +898,12 @@ "quectel_lc26g": "gnss", "quectel_lc76g": "gnss", "quectel_lc86g": "gnss", - "u_blox_f9p": "gnss", - "u_blox_m8": "gnss", "zephyr_gnss_emul": "gnss", # + # gnss/u_blox + "u_blox_f9p": "gnss/u_blox", + "u_blox_m8": "gnss/u_blox", + # # gpio "adi_ad559x_gpio": "gpio", "adi_adp5585_gpio": "gpio", @@ -825,7 +940,7 @@ "fcs_fxl6408": "gpio", "gaisler_grgpio": "gpio", "gd_gd32_gpio": "gpio", - "infineon_cat1_gpio": "gpio", + "infineon_gpio": "gpio", "infineon_tle9104_gpio": "gpio", "infineon_xmc4xxx_gpio": "gpio", "intel_gpio": "gpio", @@ -845,12 +960,10 @@ "microchip_mcp23s09": "gpio", "microchip_mcp23s17": "gpio", "microchip_mcp23s18": "gpio", - "microchip_mec5_gpio": "gpio", "microchip_mpfs_gpio": "gpio", "microchip_port_g1_gpio": "gpio", "microchip_sam_pio4": "gpio", "microchip_xec_gpio": "gpio", - "microchip_xec_gpio_v2": "gpio", "neorv32_gpio": "gpio", "nordic_npm1300_gpio": "gpio", "nordic_npm1304_gpio": "gpio", @@ -886,11 +999,14 @@ "nxp_pcal9722": "gpio", "nxp_pcf857x": "gpio", "nxp_sc18im704_gpio": "gpio", + "nxp_sc18is606_gpio": "gpio", "nxp_siul2_gpio": "gpio", "openisa_rv32m1_gpio": "gpio", "quicklogic_eos_s3_gpio": "gpio", "raspberrypi_pico_gpio_port": "gpio", "raspberrypi_rp1_gpio": "gpio", + "realtek_ameba_gpio": "gpio", + "realtek_bee_gpio": "gpio", "realtek_rts5912_gpio": "gpio", "renesas_ra_gpio_ioport": "gpio", "renesas_rcar_gpio": "gpio", @@ -937,8 +1053,11 @@ "zephyr_gpio_emul": "gpio", "zephyr_gpio_emul_sdl": "gpio", # - # haptics - "ti_drv2605": "haptics", + # haptics/cirrus + "cirrus_cs40l5x": "haptics/cirrus", + # + # haptics/ti + "ti_drv2605": "haptics/ti", # # hdlc_rcp_if "nxp_hdlc_rcp_if": "hdlc_rcp_if", @@ -956,7 +1075,9 @@ "nxp_lpc_uid": "hwinfo", # # hwspinlock + "nxp_sema42": "hwspinlock", "sqn_hwspinlock": "hwspinlock", + "vnd_hwspinlock": "hwspinlock", # # i2c "adi_max32_i2c": "i2c", @@ -968,6 +1089,7 @@ "atmel_sam_i2c_twi": "i2c", "atmel_sam_i2c_twihs": "i2c", "atmel_sam_i2c_twim": "i2c", + "bflb_i2c": "i2c", "brcm_iproc_i2c": "i2c", "cdns_i2c": "i2c", "ene_kb1200_i2c": "i2c", @@ -976,8 +1098,7 @@ "gd_gd32_i2c": "i2c", "gpio_i2c": "i2c", "gpio_i2c_switch": "i2c", - "infineon_cat1_i2c": "i2c", - "infineon_cat1_i2c_pdl": "i2c", + "infineon_i2c": "i2c", "infineon_xmc4xxx_i2c": "i2c", "intel_sedi_i2c": "i2c", "ite_enhance_i2c": "i2c", @@ -986,8 +1107,11 @@ "litex_i2c": "i2c", "litex_litei2c": "i2c", "microchip_mpfs_i2c": "i2c", + "microchip_sercom_g1_i2c": "i2c", "microchip_xec_i2c": "i2c", "microchip_xec_i2c_v2": "i2c", + "nordic_nrf_twi": "i2c", + "nordic_nrf_twim": "i2c", "nordic_nrf_twis": "i2c", "nuvoton_npcx_i2c_ctrl": "i2c", "nuvoton_npcx_i2c_port": "i2c", @@ -1007,11 +1131,14 @@ "renesas_rx_i2c": "i2c", "renesas_rz_iic": "i2c", "renesas_rz_riic": "i2c", + "renesas_rza2m_riic": "i2c", "renesas_smartbond_i2c": "i2c", "sensry_sy1xx_i2c": "i2c", "sifive_i2c0": "i2c", + "sifli_sf32lb_i2c": "i2c", "silabs_gecko_i2c": "i2c", "silabs_i2c": "i2c", + "snps_designware_i2c": "i2c", "st_stm32_i2c_v1": "i2c", "st_stm32_i2c_v2": "i2c", "telink_b91_i2c": "i2c", @@ -1032,9 +1159,12 @@ "zephyr_i2c_target_eeprom": "i2c/target", # # i2s + "adi_max32_i2s": "i2s", "ambiq_i2s": "i2s", "atmel_sam_ssc": "i2s", "espressif_esp32_i2s": "i2s", + "infineon_i2s": "i2s", + "nordic_nrf_i2s": "i2s", "nxp_lpc_i2s": "i2s", "nxp_mcux_i2s": "i2s", "renesas_ra_i2s_ssie": "i2s", @@ -1075,12 +1205,14 @@ "adc_keys": "input", "analog_axis": "input", "arduino_modulino_buttons": "input", + "bflb_irx": "input", "chipsemi_chsc5x": "input", "chipsemi_chsc6x": "input", "cirque_pinnacle": "input", "cypress_cy8cmbr3xxx": "input", "espressif_esp32_touch": "input", "focaltech_ft5336": "input", + "focaltech_ft6146": "input", "futaba_sbus": "input", "goodix_gt911": "input", "gpio_kbd_matrix": "input", @@ -1096,6 +1228,7 @@ "nintendo_nunchuk": "input", "nuvoton_npcx_kbd": "input", "nxp_mcux_kpp": "input", + "parade_tma525b": "input", "pixart_pat912x": "input", "pixart_paw32xx": "input", "pixart_pmw3610": "input", @@ -1109,11 +1242,13 @@ "st_stm32_tsc": "input", "st_stmpe811": "input", "vishay_vs1838b": "input", + "wch_ch9350l": "input", "xptek_xpt2046": "input", "zephyr_input_sdl_touch": "input", "zephyr_native_linux_evdev": "input", # # interrupt_controller + "adi_max32_rv32_intc": "interrupt_controller", "arm_gic_v1": "interrupt_controller", "arm_gic_v2": "interrupt_controller", "arm_gic_v3": "interrupt_controller", @@ -1132,17 +1267,22 @@ "ite_it8xxx2_wuc": "interrupt_controller", "litex_vexriscv_intc0": "interrupt_controller", "mediatek_adsp_intc": "interrupt_controller", + "microchip_eic_g1_intc": "interrupt_controller", "microchip_xec_ecia": "interrupt_controller", "nuclei_eclic": "interrupt_controller", "nuvoton_npcx_miwu": "interrupt_controller", + "nxp_gint": "interrupt_controller", "nxp_irqsteer_intc": "interrupt_controller", "nxp_pint": "interrupt_controller", "nxp_s32_wkpu": "interrupt_controller", "nxp_siul2_eirq": "interrupt_controller", "openisa_rv32m1_intmux": "interrupt_controller", + "renesas_rx_grp_intc": "interrupt_controller", "renesas_rx_icu": "interrupt_controller", "renesas_rz_ext_irq": "interrupt_controller", + "renesas_rz_tint": "interrupt_controller", "riscv_clic": "interrupt_controller", + "riscv_imsic": "interrupt_controller", "shared_irq": "interrupt_controller", "sifive_plic_1_0_0": "interrupt_controller", "snps_arcv2_intc": "interrupt_controller", @@ -1182,6 +1322,7 @@ "nxp_pca9633": "led", "onnn_ncp5623": "led", "pwm_leds": "led", + "sct_sct2024": "led", "ti_lp3943": "led", "ti_lp5009": "led", "ti_lp5012": "led", @@ -1209,9 +1350,14 @@ # lora "reyax_rylrxxx": "lora", # - # lora/loramac_node - "semtech_sx1272": "lora/loramac_node", - "semtech_sx1276": "lora/loramac_node", + # lora/loramac-node + "semtech_sx1272": "lora/loramac-node", + "semtech_sx1276": "lora/loramac-node", + # + # lora/native/sx126x + "semtech_sx1261": "lora/native/sx126x", + "semtech_sx1262": "lora/native/sx126x", + "st_stm32wl_subghz_radio": "lora/native/sx126x", # # mbox "andestech_mbox_plic_sw": "mbox", @@ -1228,31 +1374,13 @@ "nxp_mbox_imx_mu": "mbox", "nxp_mbox_mailbox": "mbox", "nxp_s32_mru": "mbox", + "raspberrypi_pico_mbox": "mbox", "renesas_ra_ipc_mbox": "mbox", "renesas_rz_mhu_mbox": "mbox", "st_mbox_stm32_hsem": "mbox", "ti_omap_mailbox": "mbox", "ti_secure_proxy": "mbox", - # - # mdio - "adi_adin2111_mdio": "mdio", - "atmel_sam_mdio": "mdio", - "espressif_esp32_mdio": "mdio", - "infineon_xmc4xxx_mdio": "mdio", - "intel_igc_mdio": "mdio", - "litex_liteeth_mdio": "mdio", - "microchip_lan865x_mdio": "mdio", - "nxp_enet_mdio": "mdio", - "nxp_enet_qos_mdio": "mdio", - "nxp_imx_netc_emdio": "mdio", - "nxp_s32_gmac_mdio": "mdio", - "nxp_s32_netc_emdio": "mdio", - "renesas_ra_mdio": "mdio", - "sensry_sy1xx_mdio": "mdio", - "snps_dwcxgmac_mdio": "mdio", - "st_stm32_mdio": "mdio", - "xlnx_axi_ethernet_1_00_a_mdio": "mdio", - "zephyr_mdio_gpio": "mdio", + "xlnx_mbox_versal_ipi_mailbox": "mbox", # # memc "adi_max32_hpb": "memc", @@ -1261,9 +1389,11 @@ "mspi_aps6404l": "memc", "mspi_aps_z8": "memc", "nxp_imx_flexspi": "memc", + "nxp_imx_flexspi_is66wvs8m8": "memc", "nxp_imx_flexspi_s27ks0641": "memc", "nxp_imx_flexspi_w956a8mbya": "memc", "nxp_s32_qspi": "memc", + "nxp_s32_xspi": "memc", "nxp_xspi": "memc", "nxp_xspi_psram": "memc", "renesas_ra_sdram": "memc", @@ -1290,6 +1420,7 @@ "maxim_max20335": "mfd", "maxim_max31790": "mfd", "microchip_sam_flexcom": "mfd", + "microcrystal_rv3032_mfd": "mfd", "motorola_mc146818_mfd": "mfd", "nordic_npm1300": "mfd", "nordic_npm1304": "mfd", @@ -1299,13 +1430,18 @@ "nxp_lp_flexcomm": "mfd", "nxp_pca9422": "mfd", "nxp_pf1550": "mfd", + "nxp_sc18is606": "mfd", "rohm_bd8lb600fs": "mfd", # # mipi_dbi + "bflb_dbi": "mipi_dbi", + "espressif_esp32_lcd_cam_mipi_dbi": "mipi_dbi", "nxp_lcdic": "mipi_dbi", "nxp_mipi_dbi_dcnano_lcdif": "mipi_dbi", "nxp_mipi_dbi_flexio_lcdif": "mipi_dbi", + "raspberrypi_pico_mipi_dbi_pio": "mipi_dbi", "renesas_smartbond_mipi_dbi": "mipi_dbi", + "sifli_sf32lb_lcdc_mipi_dbi": "mipi_dbi", "st_stm32_fmc_mipi_dbi": "mipi_dbi", "zephyr_mipi_dbi_bitbang": "mipi_dbi", "zephyr_mipi_dbi_spi": "mipi_dbi", @@ -1370,6 +1506,7 @@ "intel_timeaware_gpio": "misc/timeaware_gpio", # # mm + "intel_adsp_mtl_tlb": "mm", "intel_adsp_tlb": "mm", # # modem @@ -1381,6 +1518,7 @@ "quectel_eg800q": "modem", "simcom_a76xx": "modem", "sqn_gm02s": "modem", + "st_st87mxx": "modem", "telit_me310g1": "modem", "telit_me910g1": "modem", "u_blox_lara_r6": "modem", @@ -1390,8 +1528,10 @@ # # modem/hl78xx "swir_hl7800": "modem/hl78xx", + "swir_hl7800_gnss": "modem/hl78xx", "swir_hl7800_offload": "modem/hl78xx", "swir_hl7812": "modem/hl78xx", + "swir_hl7812_gnss": "modem/hl78xx", "swir_hl7812_offload": "modem/hl78xx", # # modem/simcom/sim7080 @@ -1400,11 +1540,21 @@ # mspi "ambiq_mspi_controller": "mspi", "snps_designware_ssi": "mspi", + "st_stm32_ospi_controller": "mspi", + "st_stm32_qspi_controller": "mspi", + "st_stm32_xspi_controller": "mspi", "zephyr_mspi_emul_controller": "mspi", # # opamp "nxp_opamp": "opamp", "nxp_opamp_fast": "opamp", + "st_stm32_opamp": "opamp", + # + # otp + "nxp_ocotp": "otp", + "sifli_sf32lb_efuse": "otp", + "st_stm32_bsec": "otp", + "zephyr_otp_emul": "otp", # # pcie/controller "brcm_brcmstb_pcie": "pcie/controller", @@ -1423,11 +1573,12 @@ "nuvoton_npcx_peci": "peci", # # pinctrl + "alif_pinctrl": "pinctrl", + "brcm_bcm2711_pinctrl": "pinctrl", "ene_kb106x_pinctrl": "pinctrl", "ene_kb1200_pinctrl": "pinctrl", "infineon_xmc4xxx_pinctrl": "pinctrl", "ite_it8xxx2_pinctrl_func": "pinctrl", - "microchip_mec5_pinctrl": "pinctrl", "microchip_xec_pinctrl": "pinctrl", "nuvoton_numaker_pinctrl": "pinctrl", "nuvoton_numicro_pinctrl": "pinctrl", @@ -1461,10 +1612,12 @@ "renesas_rzt2m_pinctrl": "pinctrl/renesas/rz", # # pm_cpu_ops + "arm_fvp_pwrc": "pm_cpu_ops", "arm_psci_0_2": "pm_cpu_ops", "arm_psci_1_1": "pm_cpu_ops", # # power_domain + "arm_scmi_power_domain": "power_domain", "intel_adsp_power_domain": "power_domain", "nordic_nrfs_gdpwr": "power_domain", "nordic_nrfs_swext": "power_domain", @@ -1476,6 +1629,7 @@ "ti_sci_pm_domain": "power_domain", # # ps2 + "ite_it51xxx_ps2": "ps2", "microchip_xec_ps2": "ps2", "nuvoton_npcx_ps2_channel": "ps2", "nuvoton_npcx_ps2_ctrl": "ps2", @@ -1494,6 +1648,8 @@ "atmel_sam0_tc_pwm": "pwm", "atmel_sam0_tcc_pwm": "pwm", "atmel_sam_pwm": "pwm", + "bflb_pwm_1": "pwm", + "bflb_pwm_2": "pwm", "ene_kb106x_pwm": "pwm", "ene_kb1200_pwm": "pwm", "espressif_esp32_ledc": "pwm", @@ -1509,10 +1665,12 @@ "ite_it8xxx2_pwm": "pwm", "litex_pwm": "pwm", "maxim_max31790_pwm": "pwm", + "microchip_tc_g1_pwm": "pwm", "microchip_tcc_g1_pwm": "pwm", "microchip_xec_pwm": "pwm", "microchip_xec_pwmbbled": "pwm", "neorv32_pwm": "pwm", + "nordic_nrf_pwm": "pwm", "nordic_nrf_sw_pwm": "pwm", "nuvoton_npcx_pwm": "pwm", "nuvoton_numaker_pwm": "pwm", @@ -1534,7 +1692,10 @@ "renesas_rx_mtu_pwm": "pwm", "renesas_rz_gpt_pwm": "pwm", "renesas_rz_mtu_pwm": "pwm", + "renesas_rza2m_gpt_pwm": "pwm", "sifive_pwm0": "pwm", + "sifli_sf32lb_atim_pwm": "pwm", + "sifli_sf32lb_gpt_pwm": "pwm", "silabs_gecko_pwm": "pwm", "silabs_letimer_pwm": "pwm", "silabs_siwx91x_pwm": "pwm", @@ -1568,10 +1729,13 @@ "regulator_fixed": "regulator", "regulator_gpio": "regulator", "renesas_smartbond_regulator": "regulator", + "st_stm32_vrefbuf": "regulator", + "ti_tps55287": "regulator", "zephyr_fake_regulator": "regulator", # # reset "aspeed_ast10x0_reset": "reset", + "focaltech_ft9001_cpm_rctl": "reset", "gd_gd32_rctl": "reset", "intel_socfpga_reset": "reset", "microchip_mpfs_reset": "reset", @@ -1582,6 +1746,7 @@ "nxp_mrcc_reset": "reset", "nxp_rstctl": "reset", "raspberrypi_pico_reset": "reset", + "realtek_rts5817_reset": "reset", "reset_mmio": "reset", "sifli_sf32lb_rcc_rctl": "reset", "st_stm32_rcc_rctl": "reset", @@ -1593,15 +1758,19 @@ "zephyr_retained_reg": "retained_mem", # # rtc + "adi_max31331": "rtc", "ambiq_am1805": "rtc", "ambiq_rtc": "rtc", "atmel_sam_rtc": "rtc", "epson_rx8130ce_rtc": "rtc", - "infineon_cat1_rtc": "rtc", + "infineon_rtc": "rtc", "infineon_xmc4xxx_rtc": "rtc", + "maxim_ds1302": "rtc", "maxim_ds1307": "rtc", "maxim_ds1337": "rtc", "maxim_ds3231_rtc": "rtc", + "microchip_rtc_g1": "rtc", + "microchip_rtc_g2": "rtc", "microcrystal_rv3028": "rtc", "microcrystal_rv3032": "rtc", "microcrystal_rv8803": "rtc", @@ -1617,6 +1786,7 @@ "realtek_rts5912_rtc": "rtc", "renesas_ra_rtc": "rtc", "renesas_smartbond_rtc": "rtc", + "sifli_sf32lb_rtc": "rtc", "silabs_siwx91x_rtc": "rtc", "st_stm32_rtc": "rtc", "ti_bq32002": "rtc", @@ -1631,7 +1801,7 @@ "atmel_sam_hsmci": "sdhc", "cdns_sdhc": "sdhc", "espressif_esp32_sdhc_slot": "sdhc", - "infineon_cat1_sdhc_sdio": "sdhc", + "infineon_sdhc_sdio": "sdhc", "intel_emmc_host": "sdhc", "microchip_sama7g5_sdmmc": "sdhc", "nxp_imx_usdhc": "sdhc", @@ -1648,6 +1818,9 @@ # sensor/adi/ad2s1210 "adi_ad2s1210": "sensor/adi/ad2s1210", # + # sensor/adi/ade7978 + "adi_ade7978": "sensor/adi/ade7978", + # # sensor/adi/adltc2990 "adi_adltc2990": "sensor/adi/adltc2990", # @@ -1670,6 +1843,9 @@ # sensor/adi/adxl372 "adi_adxl372": "sensor/adi/adxl372", # + # sensor/adi/max30210 + "adi_max30210": "sensor/adi/max30210", + # # sensor/adi/max32664c "maxim_max32664c": "sensor/adi/max32664c", # @@ -1682,6 +1858,9 @@ # sensor/amg88xx "panasonic_amg88xx": "sensor/amg88xx", # + # sensor/ams/ams_as5048 + "ams_as5048": "sensor/ams/ams_as5048", + # # sensor/ams/ams_as5600 "ams_as5600": "sensor/ams/ams_as5600", # @@ -1744,6 +1923,12 @@ # sensor/bosch/bmc150_magn "bosch_bmc150_magn": "sensor/bosch/bmc150_magn", # + # sensor/bosch/bme280 + "bosch_bme280": "sensor/bosch/bme280", + # + # sensor/bosch/bme680 + "bosch_bme680": "sensor/bosch/bme680", + # # sensor/bosch/bmg160 "bosch_bmg160": "sensor/bosch/bmg160", # @@ -1760,6 +1945,12 @@ # sensor/bosch/bmi323 "bosch_bmi323": "sensor/bosch/bmi323", # + # sensor/bosch/bmm150 + "bosch_bmm150": "sensor/bosch/bmm150", + # + # sensor/bosch/bmm350 + "bosch_bmm350": "sensor/bosch/bmm350", + # # sensor/bosch/bmp180 "bosch_bmp180": "sensor/bosch/bmp180", # @@ -1767,6 +1958,9 @@ "bosch_bmp388": "sensor/bosch/bmp388", "bosch_bmp390": "sensor/bosch/bmp388", # + # sensor/bosch/bmp581 + "bosch_bmp581": "sensor/bosch/bmp581", + # # sensor/broadcom/afbr_s50 "brcm_afbr_s50": "sensor/broadcom/afbr_s50", # @@ -1825,6 +2019,9 @@ # sensor/infineon/xmc4xxx_temp "infineon_xmc4xxx_temp": "sensor/infineon/xmc4xxx_temp", # + # sensor/ist8310 + "isentek_ist8310": "sensor/ist8310", + # # sensor/ite/ite_tach_it51xxx "ite_it51xxx_tach": "sensor/ite/ite_tach_it51xxx", # @@ -1837,9 +2034,6 @@ # sensor/jedec/jc42 "jedec_jc_42_4_temp": "sensor/jedec/jc42", # - # sensor/liteon/ltr329 - "liteon_ltr329": "sensor/liteon/ltr329", - # # sensor/liteon/ltrf216a "liteon_ltrf216a": "sensor/liteon/ltrf216a", # @@ -1875,6 +2069,9 @@ # sensor/maxim/max31855 "maxim_max31855": "sensor/maxim/max31855", # + # sensor/maxim/max31865 + "maxim_max31865": "sensor/maxim/max31865", + # # sensor/maxim/max31875 "maxim_max31875": "sensor/maxim/max31875", # @@ -1900,6 +2097,9 @@ # sensor/memsic/mc3419 "memsic_mc3419": "sensor/memsic/mc3419", # + # sensor/memsic/mmc56x3 + "memsic_mmc56x3": "sensor/memsic/mmc56x3", + # # sensor/mhz19b "winsen_mhz19b": "sensor/mhz19b", # @@ -1945,6 +2145,9 @@ # sensor/nuvoton/nuvoton_adc_cmp_npcx "nuvoton_adc_cmp": "sensor/nuvoton/nuvoton_adc_cmp_npcx", # + # sensor/nuvoton/nuvoton_adc_v2t_npcx + "nuvoton_npcx_adc_v2t": "sensor/nuvoton/nuvoton_adc_v2t_npcx", + # # sensor/nuvoton/nuvoton_tach_npcx "nuvoton_npcx_tach": "sensor/nuvoton/nuvoton_tach_npcx", # @@ -1975,6 +2178,9 @@ # sensor/nxp/nxp_tempmon "nxp_tempmon": "sensor/nxp/nxp_tempmon", # + # sensor/nxp/nxp_tempsense + "nxp_tempsense": "sensor/nxp/nxp_tempsense", + # # sensor/nxp/nxp_tmpsns "nxp_tmpsns": "sensor/nxp/nxp_tmpsns", # @@ -2045,6 +2251,9 @@ # sensor/rpi_pico_temp "raspberrypi_pico_temp": "sensor/rpi_pico_temp", # + # sensor/rv3032_temp + "microcrystal_rv3032_temp": "sensor/rv3032_temp", + # # sensor/s11059 "hamamatsu_s11059": "sensor/s11059", # @@ -2074,6 +2283,9 @@ # sensor/sensirion/sts4x "sensirion_sts4x": "sensor/sensirion/sts4x", # + # sensor/sifli/sf32lb_tsen + "sifli_sf32lb_tsen": "sensor/sifli/sf32lb_tsen", + # # sensor/silabs/si7006 "sensirion_sht21": "sensor/silabs/si7006", "silabs_si7006": "sensor/silabs/si7006", @@ -2175,6 +2387,14 @@ # sensor/st/lsm6dsv16x "DT_DRV_COMPAT_LSM6DSV16X": "sensor/st/lsm6dsv16x", "DT_DRV_COMPAT_LSM6DSV32X": "sensor/st/lsm6dsv16x", + "st_lsm6dsv16x": "sensor/st/lsm6dsv16x", + "st_lsm6dsv32x": "sensor/st/lsm6dsv16x", + # + # sensor/st/lsm6dsvxxx + "st_ism6hg256x": "sensor/st/lsm6dsvxxx", + "st_lsm6dsv320x": "sensor/st/lsm6dsvxxx", + "st_lsm6dsv80x": "sensor/st/lsm6dsvxxx", + "st_lsm6dsvxxx": "sensor/st/lsm6dsvxxx", # # sensor/st/lsm9ds0_gyro "st_lsm9ds0_gyro": "sensor/st/lsm9ds0_gyro", @@ -2239,7 +2459,11 @@ "invensense_icm42670s": "sensor/tdk/icm42x70", # # sensor/tdk/icm45686 + "invensense_icm45605": "sensor/tdk/icm45686", + "invensense_icm45605s": "sensor/tdk/icm45686", "invensense_icm45686": "sensor/tdk/icm45686", + "invensense_icm45686s": "sensor/tdk/icm45686", + "invensense_icm45688p": "sensor/tdk/icm45686", # # sensor/tdk/icp101xx "invensense_icp101xx": "sensor/tdk/icp101xx", @@ -2269,6 +2493,7 @@ "ti_ina226": "sensor/ti/ina2xx", "ti_ina228": "sensor/ti/ina2xx", "ti_ina230": "sensor/ti/ina2xx", + "ti_ina232": "sensor/ti/ina2xx", "ti_ina236": "sensor/ti/ina2xx", "ti_ina237": "sensor/ti/ina2xx", # @@ -2281,8 +2506,10 @@ # sensor/ti/lm95234 "national_lm95234": "sensor/ti/lm95234", # - # sensor/ti/opt3001 - "ti_opt3001": "sensor/ti/opt3001", + # sensor/ti/opt300x + "ti_opt3001": "sensor/ti/opt300x", + "ti_opt3004": "sensor/ti/opt300x", + "ti_opt300x": "sensor/ti/opt300x", # # sensor/ti/ti_hdc "ti_hdc": "sensor/ti/ti_hdc", @@ -2301,6 +2528,7 @@ # # sensor/ti/tmp108 "ams_as6212": "sensor/ti/tmp108", + "ams_as6221": "sensor/ti/tmp108", "ti_tmp108": "sensor/ti/tmp108", # # sensor/ti/tmp112 @@ -2388,10 +2616,10 @@ "espressif_esp32_lpuart": "serial", "espressif_esp32_uart": "serial", "espressif_esp32_usb_serial": "serial", + "focaltech_ft9001_usart": "serial", "gaisler_apbuart": "serial", "gd_gd32_usart": "serial", - "infineon_cat1_uart": "serial", - "infineon_cat1_uart_pdl": "serial", + "infineon_uart": "serial", "infineon_xmc4xxx_uart": "serial", "intel_lw_uart": "serial", "intel_sedi_uart": "serial", @@ -2400,7 +2628,6 @@ "litex_uart": "serial", "lowrisc_opentitan_uart": "serial", "microchip_coreuart": "serial", - "microchip_mec5_uart": "serial", "microchip_sercom_g1_uart": "serial", "microchip_xec_uart": "serial", "neorv32_uart": "serial", @@ -2420,6 +2647,8 @@ "openisa_rv32m1_lpuart": "serial", "quicklogic_usbserialport_s3b": "serial", "raspberrypi_pico_uart_pio": "serial", + "realtek_ameba_loguart": "serial", + "realtek_bee_uart": "serial", "realtek_rts5912_uart": "serial", "renesas_ra8_uart_sci_b": "serial", "renesas_ra_sci_uart": "serial", @@ -2458,7 +2687,6 @@ "xen_hvc_consoleio": "serial", "xlnx_xps_uartlite_1_00_a": "serial", "xlnx_xuartps": "serial", - "zephyr_native_posix_uart": "serial", "zephyr_native_pty_uart": "serial", "zephyr_native_tty_uart": "serial", "zephyr_nus_uart": "serial", @@ -2482,14 +2710,14 @@ "arm_pl022": "spi", "atmel_sam0_spi": "spi", "atmel_sam_spi": "spi", + "bflb_spi": "spi", "cdns_spi": "spi", "cypress_psoc6_spi": "spi", "egis_et171_spi": "spi", "espressif_esp32_spi": "spi", "gaisler_spimctrl": "spi", "gd_gd32_spi": "spi", - "infineon_cat1_spi": "spi", - "infineon_cat1_spi_pdl": "spi", + "infineon_spi": "spi", "infineon_xmc4xxx_spi": "spi", "intel_penwell_spi": "spi", "intel_sedi_spi": "spi", @@ -2498,11 +2726,13 @@ "litex_spi": "spi", "litex_spi_litespi": "spi", "lowrisc_opentitan_spi": "spi", - "microchip_mec5_qspi": "spi", "microchip_mpfs_qspi": "spi", "microchip_mpfs_spi": "spi", + "microchip_sercom_g1_spi": "spi", "microchip_xec_qmspi": "spi", "microchip_xec_qmspi_ldma": "spi", + "nordic_nrf_spi": "spi", + "nordic_nrf_spim": "spi", "nuvoton_npcx_spip": "spi", "nuvoton_numaker_spi": "spi", "nxp_dspi": "spi", @@ -2514,13 +2744,18 @@ "opencores_spi_simple": "spi", "openisa_rv32m1_lpspi": "spi", "raspberrypi_pico_spi_pio": "spi", + "realtek_rts5912_spi": "spi", "renesas_ra8_spi_b": "spi", "renesas_ra_spi": "spi", + "renesas_ra_spi_sci": "spi", + "renesas_ra_spi_sci_b": "spi", "renesas_rx_rspi": "spi", "renesas_rz_rspi": "spi", "renesas_rz_spi": "spi", "renesas_smartbond_spi": "spi", + "sensry_sy1xx_spi": "spi", "sifive_spi0": "spi", + "sifli_sf32lb_spi": "spi", "silabs_eusart_spi": "spi", "silabs_gspi": "spi", "silabs_usart_spi": "spi", @@ -2540,16 +2775,29 @@ "nxp_lpspi": "spi/spi_nxp_lpspi", # # stepper - "zephyr_fake_stepper": "stepper", - "zephyr_h_bridge_stepper": "stepper", + "zephyr_fake_stepper_ctrl": "stepper", + "zephyr_fake_stepper_driver": "stepper", + # + # stepper/adi_tmc/tmc22xx + "adi_tmc2209": "stepper/adi_tmc/tmc22xx", + # + # stepper/adi_tmc/tmc50xx + "adi_tmc50xx": "stepper/adi_tmc/tmc50xx", + "adi_tmc50xx_stepper_ctrl": "stepper/adi_tmc/tmc50xx", + "adi_tmc50xx_stepper_driver": "stepper/adi_tmc/tmc50xx", # - # stepper/adi_tmc - "adi_tmc2209": "stepper/adi_tmc", - "adi_tmc50xx": "stepper/adi_tmc", + # stepper/adi_tmc/tmc51xx + "adi_tmc51xx": "stepper/adi_tmc/tmc51xx", + "adi_tmc51xx_stepper_ctrl": "stepper/adi_tmc/tmc51xx", + "adi_tmc51xx_stepper_driver": "stepper/adi_tmc/tmc51xx", # # stepper/allegro "allegro_a4979": "stepper/allegro", # + # stepper/gpio_stepper + "zephyr_gpio_step_dir_stepper_ctrl": "stepper/gpio_stepper", + "zephyr_h_bridge_stepper_ctrl": "stepper/gpio_stepper", + # # stepper/ti "ti_drv84xx": "stepper/ti", # @@ -2561,10 +2809,11 @@ "linaro_optee_tz": "tee/optee", # # timer + "adi_max32_rv32_sys_timer": "timer", "ambiq_stimer": "timer", "atmel_sam0_rtc": "timer", "gaisler_gptimer": "timer", - "infineon_cat1_lp_timer": "timer", + "infineon_lp_timer": "timer", "intel_adsp_timer": "timer", "intel_hpet": "timer", "ite_it51xxx_timer": "timer", @@ -2597,6 +2846,10 @@ # usb/bc12 "diodes_pi3usb9201": "usb/bc12", # + # usb/common/stm32 + "*/": "usb/common/stm32", + "st_stm32u5_otghs_phy": "usb/common/stm32", + # # usb/device "atmel_sam_usbc": "usb/device", "atmel_sam_usbhs": "usb/device", @@ -2607,6 +2860,7 @@ "atmel_sam0_usb": "usb/udc", "ite_it82xx2_usb": "usb/udc", "nordic_nrf_usbd": "usb/udc", + "nuvoton_numaker_hsusbd": "usb/udc", "nuvoton_numaker_usbd": "usb/udc", "nxp_ehci": "usb/udc", "nxp_kinetis_usbd": "usb/udc", @@ -2647,15 +2901,18 @@ # # video "aptina_mt9m114": "video", - "espressif_esp32_lcd_cam": "video", + "espressif_esp32_lcd_cam_dvp": "video", "galaxycore_gc2145": "video", "himax_hm01b0": "video", + "himax_hm0360": "video", "nxp_imx_csi": "video", "nxp_mipi_csi2rx": "video", "nxp_video_smartdma": "video", "ovti_ov2640": "video", "ovti_ov5640": "video", + "ovti_ov5642": "video", "ovti_ov7670": "video", + "ovti_ov7675": "video", "ovti_ov7725": "video", "ovti_ov9655": "video", "renesas_ra_ceu": "video", @@ -2688,19 +2945,21 @@ # # watchdog "adi_max32_watchdog": "watchdog", + "adi_max42500_watchdog": "watchdog", "ambiq_watchdog": "watchdog", "andestech_atcwdt200": "watchdog", "arm_cmsdk_watchdog": "watchdog", "atmel_sam0_watchdog": "watchdog", "atmel_sam4l_watchdog": "watchdog", "atmel_sam_watchdog": "watchdog", + "bflb_wdt": "watchdog", "ene_kb106x_watchdog": "watchdog", "ene_kb1200_watchdog": "watchdog", "espressif_esp32_watchdog": "watchdog", "espressif_esp32_xt_wdt": "watchdog", "gd_gd32_fwdgt": "watchdog", "gd_gd32_wwdgt": "watchdog", - "infineon_cat1_watchdog": "watchdog", + "infineon_watchdog": "watchdog", "infineon_xmc4xxx_watchdog": "watchdog", "intel_adsp_watchdog": "watchdog", "intel_tco_wdt": "watchdog", @@ -2708,11 +2967,13 @@ "ite_it8xxx2_watchdog": "watchdog", "litex_watchdog": "watchdog", "lowrisc_opentitan_aontimer": "watchdog", + "microchip_wdt_g1": "watchdog", "microchip_xec_watchdog": "watchdog", "nordic_npm1300_wdt": "watchdog", "nordic_npm1304_wdt": "watchdog", "nordic_npm2100_wdt": "watchdog", "nordic_npm6001_wdt": "watchdog", + "nordic_nrf_wdt": "watchdog", "nuvoton_npcx_watchdog": "watchdog", "nuvoton_numaker_wwdt": "watchdog", "nxp_cop": "watchdog", @@ -2725,6 +2986,7 @@ "nxp_s32_swt": "watchdog", "nxp_wdog32": "watchdog", "raspberrypi_pico_watchdog": "watchdog", + "realtek_rts5817_watchdog": "watchdog", "realtek_rts5912_watchdog": "watchdog", "renesas_rx_iwdt": "watchdog", "renesas_rz_wdt": "watchdog", @@ -2751,10 +3013,16 @@ # wifi/esp_at "espressif_esp_at": "wifi/esp_at", # + # wifi/esp_hosted + "espressif_esp_hosted": "wifi/esp_hosted", + # # wifi/eswifi "inventek_eswifi": "wifi/eswifi", "inventek_eswifi_uart": "wifi/eswifi", # + # wifi/infineon + "infineon_airoc_wifi": "wifi/infineon", + # # wifi/nrf_wifi/off_raw_tx/src "nordic_wlan": "wifi/nrf_wifi/off_raw_tx/src", # diff --git a/ports/zephyr-cp/cptools/gen_compat2driver.py b/ports/zephyr-cp/cptools/gen_compat2driver.py index 1e529072dab..ffe8da18596 100644 --- a/ports/zephyr-cp/cptools/gen_compat2driver.py +++ b/ports/zephyr-cp/cptools/gen_compat2driver.py @@ -3,7 +3,7 @@ mapping = {} drivers = pathlib.Path("zephyr/drivers") -for p in drivers.glob("**/*.c"): +for p in drivers.glob("**/*.[ch]"): for line in p.open(): if line.startswith("#define DT_DRV_COMPAT"): compat = line.rsplit(None, 1)[-1].strip() diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index c123d90ce78..5000221d5c0 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -245,6 +245,34 @@ "D1", "D0", ], + "raspberrypi,pico-header": [ + "GP0", + "GP1", + "GP2", + "GP3", + "GP4", + "GP5", + "GP6", + "GP7", + "GP8", + "GP9", + "GP10", + "GP11", + "GP12", + "GP13", + "GP14", + "GP15", + "GP16", + "GP17", + "GP18", + "GP19", + "GP20", + "GP21", + "GP22", + ["GP26_A0", "GP26", "A0"], + ["GP27_A1", "GP27", "A1"], + ["GP28_A2", "GP28", "A2"], + ], } EXCEPTIONAL_DRIVERS = ["entropy", "gpio", "led"] @@ -583,7 +611,11 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa num = int.from_bytes(gpio_map.value[offset + 4 : offset + 8], "big") if (label, num) not in board_names: board_names[(label, num)] = [] - board_names[(label, num)].append(connector_pins[i]) + pin_entry = connector_pins[i] + if isinstance(pin_entry, list): + board_names[(label, num)].extend(pin_entry) + else: + board_names[(label, num)].append(pin_entry) i += 1 if "gpio-leds" in compatible: for led in node.nodes: diff --git a/ports/zephyr-cp/mpconfigport.h b/ports/zephyr-cp/mpconfigport.h index 491b5293e2e..23bb0b55b6f 100644 --- a/ports/zephyr-cp/mpconfigport.h +++ b/ports/zephyr-cp/mpconfigport.h @@ -20,6 +20,8 @@ // Disable native _Float16 handling for host builds. #define MICROPY_FLOAT_USE_NATIVE_FLT16 (0) +#define MICROPY_NLR_THUMB_USE_LONG_JUMP (1) + //////////////////////////////////////////////////////////////////////////////////////////////////// // This also includes mpconfigboard.h. diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index c40475177e0..847f864f0bb 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -25,6 +25,7 @@ #include "lib/tlsf/tlsf.h" #include +#include #if defined(CONFIG_TRACING_PERFETTO) && defined(CONFIG_BOARD_NATIVE_SIM) #include "perfetto_encoder.h" @@ -130,6 +131,9 @@ static void _tick_function(struct k_timer *timer_id) { } safe_mode_t port_init(void) { + // We run CircuitPython at the lowest priority (just higher than idle.) + // This allows networking and USB to preempt us. + k_thread_priority_set(k_current_get(), CONFIG_NUM_PREEMPT_PRIORITIES - 1); k_timer_init(&tick_timer, _tick_function, NULL); perfetto_emit_circuitpython_tracks(); return SAFE_MODE_NONE; From d07ee5b970eba8a604495a7db1fbda99d2d42648 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 18 Dec 2025 11:09:18 -0800 Subject: [PATCH 365/876] Add audiobusio.I2SOut() support to Zephyr Relies on added SDL audio emulation. --- locale/circuitpython.pot | 1 + ports/zephyr-cp/Makefile | 2 +- ports/zephyr-cp/background.c | 19 +- .../autogen_board_info.toml | 2 +- .../boards/frdm_mcxn947_mcxn947_cpu0.conf | 1 + .../boards/frdm_rw612_rw612_cpu0.overlay | 12 + .../boards/mimxrt1170_evk_mimxrt1176_cm7.conf | 1 + .../mimxrt1170_evk_mimxrt1176_cm7.overlay | 4 + .../native/native_sim/autogen_board_info.toml | 18 +- .../nrf5340bsim/autogen_board_info.toml | 2 +- ports/zephyr-cp/boards/native_sim.conf | 3 + .../nordic/nrf5340dk/autogen_board_info.toml | 18 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 2 +- .../nordic/nrf7002dk/autogen_board_info.toml | 2 +- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 24 ++ .../nxp/frdm_mcxn947/autogen_board_info.toml | 18 +- .../nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../mimxrt1170_evk/autogen_board_info.toml | 18 +- .../da14695_dk_usb/autogen_board_info.toml | 2 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../nucleo_n657x0_q/autogen_board_info.toml | 2 +- .../nucleo_u575zi_q/autogen_board_info.toml | 2 +- .../st/stm32h750b_dk/autogen_board_info.toml | 2 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 2 +- .../stm32wba65i_dk1/autogen_board_info.toml | 2 +- .../zephyr-cp/common-hal/audiobusio/I2SOut.c | 297 ++++++++++++++++++ .../zephyr-cp/common-hal/audiobusio/I2SOut.h | 47 +++ ports/zephyr-cp/common-hal/audiobusio/PDMIn.c | 39 +++ ports/zephyr-cp/common-hal/audiobusio/PDMIn.h | 18 ++ .../common-hal/audiobusio/__init__.c | 7 + .../common-hal/audiobusio/__init__.h | 9 + .../common-hal/zephyr_kernel/__init__.c | 8 +- .../zephyr-cp/cptools/build_circuitpython.py | 41 ++- ports/zephyr-cp/cptools/compat2driver.py | 1 + ports/zephyr-cp/cptools/zephyr2cp.py | 57 +++- ports/zephyr-cp/prj.conf | 4 + ports/zephyr-cp/supervisor/port.c | 8 + ports/zephyr-cp/tests/conftest.py | 8 +- ports/zephyr-cp/tests/test_audiobusio.py | 216 +++++++++++++ shared-bindings/audiobusio/I2SOut.c | 2 + shared-module/audiomixer/Mixer.c | 10 +- .../audiobusio/i2s_sample_loop.py | 74 +++-- 44 files changed, 906 insertions(+), 107 deletions(-) create mode 100644 ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf create mode 100644 ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay create mode 100644 ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf create mode 100644 ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay create mode 100644 ports/zephyr-cp/common-hal/audiobusio/I2SOut.c create mode 100644 ports/zephyr-cp/common-hal/audiobusio/I2SOut.h create mode 100644 ports/zephyr-cp/common-hal/audiobusio/PDMIn.c create mode 100644 ports/zephyr-cp/common-hal/audiobusio/PDMIn.h create mode 100644 ports/zephyr-cp/common-hal/audiobusio/__init__.c create mode 100644 ports/zephyr-cp/common-hal/audiobusio/__init__.h create mode 100644 ports/zephyr-cp/tests/test_audiobusio.py diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index efa38764c9a..07623ea94a0 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -2411,6 +2411,7 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c #: ports/zephyr-cp/common-hal/busio/I2C.c #: ports/zephyr-cp/common-hal/busio/SPI.c #: ports/zephyr-cp/common-hal/busio/UART.c diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index 5c4db4f9065..12f22d7c3ae 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -68,7 +68,7 @@ run-sim: echo "Populating build-native_native_sim/flash.bin from ./CIRCUITPY"; \ mcopy -s -i build-native_native_sim/flash.bin CIRCUITPY/* ::; \ fi - build-native_native_sim/firmware.exe --flash=build-native_native_sim/flash.bin --flash_rm -wait_uart -rt + build-native_native_sim/firmware.exe --flash=build-native_native_sim/flash.bin --flash_rm -wait_uart -rt --i2s_capture=build-native_native_sim/i2s_capture.wav menuconfig: west build $(WEST_SHIELD_ARGS) --sysbuild -d $(BUILD) -t menuconfig -- $(WEST_CMAKE_ARGS) diff --git a/ports/zephyr-cp/background.c b/ports/zephyr-cp/background.c index 1abc034e878..56e9e98f1f2 100644 --- a/ports/zephyr-cp/background.c +++ b/ports/zephyr-cp/background.c @@ -9,17 +9,7 @@ #include "py/runtime.h" #include "supervisor/port.h" -#if CIRCUITPY_DISPLAYIO -#include "shared-module/displayio/__init__.h" -#endif - -#if CIRCUITPY_AUDIOBUSIO -#include "common-hal/audiobusio/I2SOut.h" -#endif - -#if CIRCUITPY_AUDIOPWMIO -#include "common-hal/audiopwmio/PWMAudioOut.h" -#endif +#include void port_start_background_tick(void) { } @@ -28,12 +18,7 @@ void port_finish_background_tick(void) { } void port_background_tick(void) { - #if CIRCUITPY_AUDIOPWMIO - audiopwmout_background(); - #endif - #if CIRCUITPY_AUDIOBUSIO - i2s_background(); - #endif + // No, ticks. We use Zephyr threads instead. } void port_background_task(void) { diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 1672ab0b461..dc7b9364c2e 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf new file mode 100644 index 00000000000..61f2d18ca3c --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf @@ -0,0 +1 @@ +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay new file mode 100644 index 00000000000..9c517e43255 --- /dev/null +++ b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay @@ -0,0 +1,12 @@ +&w25q512jvfiq { + partitions { + /delete-node/ storage_partition; + circuitpy_partition: partition@620000 { + label = "circuitpy"; + reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; + }; + } + +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf new file mode 100644 index 00000000000..61f2d18ca3c --- /dev/null +++ b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf @@ -0,0 +1 @@ +CONFIG_DMA_TCD_QUEUE_SIZE=4 diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay index 89a78998cea..ac6fdd8654e 100644 --- a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay +++ b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -8,4 +8,8 @@ }; }; +&sai1 { + mclk-output; +}; + #include "../app.overlay" diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 51a9f1b3476..dd4040607fb 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -15,14 +15,14 @@ alarm = false analogbufio = false analogio = false atexit = false -audiobusio = false -audiocore = false -audiodelays = false -audiofilters = false -audiofreeverb = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio audioio = false -audiomixer = false -audiomp3 = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio audiopwmio = false audiospeed = false aurora_epaper = false @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -97,7 +97,7 @@ ssl = false storage = true # Zephyr board has flash struct = true supervisor = true -synthio = false +synthio = true # Zephyr board has audiobusio terminalio = true # Zephyr board has busio tilepalettemapper = true # Zephyr board has busio time = true diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 36df4d16caa..00f71783639 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native_sim.conf index 739a71eeeb6..e02cd0ac84e 100644 --- a/ports/zephyr-cp/boards/native_sim.conf +++ b/ports/zephyr-cp/boards/native_sim.conf @@ -23,6 +23,9 @@ CONFIG_EEPROM=y CONFIG_EEPROM_AT24=y CONFIG_EEPROM_AT2X_EMUL=y +# I2S SDL emulation for audio testing +CONFIG_I2S_SDL=y + CONFIG_NETWORKING=y CONFIG_NET_IPV4=y CONFIG_NET_TCP=y diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 9cb94909047..92cb4ef1a80 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -15,14 +15,14 @@ alarm = false analogbufio = false analogio = false atexit = false -audiobusio = false -audiocore = false -audiodelays = false -audiofilters = false -audiofreeverb = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio audioio = false -audiomixer = false -audiomp3 = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio audiopwmio = false audiospeed = false aurora_epaper = false @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -97,7 +97,7 @@ ssl = false storage = true # Zephyr board has flash struct = true supervisor = true -synthio = false +synthio = true # Zephyr board has audiobusio terminalio = true # Zephyr board has busio tilepalettemapper = true # Zephyr board has busio time = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index c900bcda2e9..5d5f325af81 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index ae95c3c01d6..9792f8aca74 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index e1d3834d7a7..62fa896c0ec 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000..eb899df8cc9 --- /dev/null +++ b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -0,0 +1,24 @@ +&pinctrl { + i2s0_default_alt: i2s0_default_alt { + group1 { + psels = , + , + , + , + ; + }; + }; +}; + +&clock { + hfclkaudio-frequency = <11289600>; +}; + +i2s_rxtx: &i2s0 { + status = "okay"; + pinctrl-0 = <&i2s0_default_alt>; + pinctrl-names = "default"; + clock-source = "ACLK"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index c21c176c856..b121a1e8234 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -15,14 +15,14 @@ alarm = false analogbufio = false analogio = false atexit = false -audiobusio = false -audiocore = false -audiodelays = false -audiofilters = false -audiofreeverb = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio audioio = false -audiomixer = false -audiomp3 = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio audiopwmio = false audiospeed = false aurora_epaper = false @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -97,7 +97,7 @@ ssl = false storage = true # Zephyr board has flash struct = true supervisor = true -synthio = false +synthio = true # Zephyr board has audiobusio terminalio = true # Zephyr board has busio tilepalettemapper = true # Zephyr board has busio time = true diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index a5214dfe774..e5b51390538 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 08eca8ba202..57ff5fe8c81 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -15,14 +15,14 @@ alarm = false analogbufio = false analogio = false atexit = false -audiobusio = false -audiocore = false -audiodelays = false -audiofilters = false -audiofreeverb = false +audiobusio = true # Zephyr board has audiobusio +audiocore = true # Zephyr board has audiobusio +audiodelays = true # Zephyr board has audiobusio +audiofilters = true # Zephyr board has audiobusio +audiofreeverb = true # Zephyr board has audiobusio audioio = false -audiomixer = false -audiomp3 = false +audiomixer = true # Zephyr board has audiobusio +audiomp3 = true # Zephyr board has audiobusio audiopwmio = false audiospeed = false aurora_epaper = false @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -97,7 +97,7 @@ ssl = false storage = false struct = true supervisor = true -synthio = false +synthio = true # Zephyr board has audiobusio terminalio = true # Zephyr board has busio tilepalettemapper = true # Zephyr board has busio time = true diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index 73538f827c4..e11d98ac9a1 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 2e765e145a4..47a54e9632a 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index fc17d889c0f..c4a071b0688 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index b108b2fd8e9..f526b1e90fa 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index bbe481d1713..2c904026fba 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index f9db69fb9d8..3e8208d82c9 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 53009db597d..a85cd9e3cc5 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index b2c1c15a0bd..36213878c29 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c new file mode 100644 index 00000000000..5e2e1fac8a4 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -0,0 +1,297 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiobusio/I2SOut.h" + +#include +#include +#include +#include +#include + +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" +#include "py/runtime.h" + +#if CIRCUITPY_AUDIOBUSIO_I2SOUT + +#define AUDIO_THREAD_STACK_SIZE 2048 +#define AUDIO_THREAD_PRIORITY 5 + +// Forward declarations +static void fill_buffer(audiobusio_i2sout_obj_t *self, uint8_t *buffer, size_t buffer_size); +static void audio_thread_func(void *self_in, void *unused1, void *unused2); + +// Helper function for Zephyr-specific initialization from device tree +mp_obj_t common_hal_audiobusio_i2sout_construct_from_device(audiobusio_i2sout_obj_t *self, const struct device *i2s_device) { + self->base.type = &audiobusio_i2sout_type; + self->i2s_dev = i2s_device; + self->left_justified = false; + self->playing = false; + self->paused = false; + self->sample = NULL; + self->slab_buffer = NULL; + self->thread_stack = NULL; + self->thread_id = NULL; + self->block_size = 0; + + return MP_OBJ_FROM_PTR(self); +} + +// Standard audiobusio construct - not used in Zephyr port (devices come from device tree) +void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_I2S); +} + +bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t *self) { + return self->i2s_dev == NULL; +} + +void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self) { + if (common_hal_audiobusio_i2sout_deinited(self)) { + return; + } + + // Stop playback (which will free buffers) + common_hal_audiobusio_i2sout_stop(self); + + // Note: Pins and I2S device are managed by Zephyr, not released here + self->i2s_dev = NULL; +} + +static void fill_buffer(audiobusio_i2sout_obj_t *self, uint8_t *buffer, size_t buffer_size) { + if (self->sample == NULL || self->paused || self->stopping) { + // Fill with silence + memset(buffer, 0, buffer_size); + return; + } + + uint32_t bytes_filled = 0; + while (bytes_filled < buffer_size) { + uint8_t *sample_buffer; + uint32_t sample_buffer_length; + + audioio_get_buffer_result_t result = audiosample_get_buffer( + self->sample, false, 0, &sample_buffer, &sample_buffer_length); + + if (result == GET_BUFFER_ERROR) { + // Error getting buffer, stop playback + self->stopping = true; + memset(buffer + bytes_filled, 0, buffer_size - bytes_filled); + return; + } + + if (result == GET_BUFFER_DONE) { + if (self->loop) { + // Reset to beginning + audiosample_reset_buffer(self->sample, false, 0); + } else { + // Done playing, fill rest with silence + self->stopping = true; + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DRAIN); + memset(buffer + bytes_filled, 0, buffer_size - bytes_filled); + return; + } + } + + // Copy data to buffer + uint32_t bytes_to_copy = sample_buffer_length; + if (bytes_filled + bytes_to_copy > buffer_size) { + bytes_to_copy = buffer_size - bytes_filled; + } + + memcpy(buffer + bytes_filled, sample_buffer, bytes_to_copy); + bytes_filled += bytes_to_copy; + } +} + +static void audio_thread_func(void *self_in, void *unused1, void *unused2) { + audiobusio_i2sout_obj_t *self = (audiobusio_i2sout_obj_t *)self_in; + + while (!self->stopping) { + uint8_t *next_buffer = NULL; + // Wait until I2S has freed the buffer it is sending. + if (k_mem_slab_alloc(&self->mem_slab, (void **)&next_buffer, K_FOREVER) != 0) { + break; + } + if (self->stopping) { + // Stopping so break. + k_mem_slab_free(&self->mem_slab, next_buffer); + break; + } + fill_buffer(self, next_buffer, self->block_size); + + // Write to I2S + int ret = i2s_write(self->i2s_dev, next_buffer, self->block_size); + if (ret < 0) { + printk("i2s_write failed: %d\n", ret); + // Error writing, stop playback + self->playing = false; + break; + } + } +} + +void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, + mp_obj_t sample, bool loop) { + // Stop any existing playback + if (self->playing) { + common_hal_audiobusio_i2sout_stop(self); + } + + // Get sample information + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); + uint32_t sample_rate = audiosample_get_sample_rate(sample); + uint8_t channel_count = audiosample_get_channel_count(sample); + + // Store sample parameters + self->sample = sample; + self->loop = loop; + self->bytes_per_sample = bits_per_sample / 8; + self->channel_count = channel_count; + self->stopping = false; + + // Get buffer structure from the sample + bool single_buffer, samples_signed; + uint32_t max_buffer_length; + uint8_t sample_spacing; + audiosample_get_buffer_structure(sample, /* single_channel_output */ false, + &single_buffer, &samples_signed, &max_buffer_length, &sample_spacing); + + // Use max_buffer_length from the sample as the block size + self->block_size = max_buffer_length; + if (channel_count == 1) { + // Make room for stereo samples. + self->block_size *= 2; + } + size_t block_size = self->block_size; + uint32_t num_blocks = 4; // Use 4 blocks for buffering + + // Allocate memory slab buffer + self->slab_buffer = m_malloc(self->block_size * num_blocks); + + // Initialize memory slab + int ret = k_mem_slab_init(&self->mem_slab, self->slab_buffer, block_size, num_blocks); + CHECK_ZEPHYR_RESULT(ret); + + // Configure I2S + struct i2s_config config; + config.word_size = bits_per_sample; + config.channels = 2; + config.format = self->left_justified ? I2S_FMT_DATA_FORMAT_LEFT_JUSTIFIED : I2S_FMT_DATA_FORMAT_I2S; + config.options = I2S_OPT_BIT_CLK_MASTER | I2S_OPT_FRAME_CLK_MASTER; + config.frame_clk_freq = sample_rate; + config.mem_slab = &self->mem_slab; + config.block_size = block_size; + config.timeout = 1000; // Not a k_timeout_t. In milliseconds. + + // Configure returns EINVAL if the I2S device is not ready. We loop on this + // because it should be ready after it comes to a complete stop. + ret = -EAGAIN; + while (ret == -EAGAIN) { + ret = i2s_configure(self->i2s_dev, I2S_DIR_TX, &config); + } + if (ret != 0) { + common_hal_audiobusio_i2sout_stop(self); + raise_zephyr_error(ret); + } + + // Fill every slab before starting playback to avoid underruns. + for (uint32_t i = 0; i < num_blocks; i++) { + uint8_t *buf = NULL; + k_mem_slab_alloc(&self->mem_slab, (void **)&buf, K_NO_WAIT); + fill_buffer(self, buf, block_size); + ret = i2s_write(self->i2s_dev, buf, block_size); + if (ret < 0) { + printk("i2s_write failed: %d\n", ret); + common_hal_audiobusio_i2sout_stop(self); + raise_zephyr_error(ret); + } + } + + // Allocate thread stack with proper MPU alignment for HW stack protection + self->thread_stack = k_thread_stack_alloc(AUDIO_THREAD_STACK_SIZE, 0); + + // Create and start audio processing thread + self->thread_id = k_thread_create(&self->thread, self->thread_stack, + AUDIO_THREAD_STACK_SIZE, + audio_thread_func, + self, NULL, NULL, + AUDIO_THREAD_PRIORITY, 0, K_NO_WAIT); + // Start I2S + ret = i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START); + if (ret < 0) { + common_hal_audiobusio_i2sout_stop(self); + raise_zephyr_error(ret); + } + + self->playing = true; +} + +void common_hal_audiobusio_i2sout_stop(audiobusio_i2sout_obj_t *self) { + if (!self->playing) { + return; + } + + self->playing = false; + self->paused = false; + self->stopping = true; + + // Stop I2S + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DROP); + + // Wait for thread to finish + if (self->thread_id != NULL) { + k_thread_join(self->thread_id, K_FOREVER); + self->thread_id = NULL; + } + + // Free thread stack + if (self->thread_stack != NULL) { + k_thread_stack_free(self->thread_stack); + self->thread_stack = NULL; + } + + // Free buffers + if (self->slab_buffer != NULL) { + m_free(self->slab_buffer); + self->slab_buffer = NULL; + } + + self->sample = NULL; +} + +bool common_hal_audiobusio_i2sout_get_playing(audiobusio_i2sout_obj_t *self) { + return self->playing; +} + +void common_hal_audiobusio_i2sout_pause(audiobusio_i2sout_obj_t *self) { + if (!self->playing || self->paused) { + return; + } + + self->paused = true; + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_STOP); +} + +void common_hal_audiobusio_i2sout_resume(audiobusio_i2sout_obj_t *self) { + if (!self->playing || !self->paused) { + return; + } + + self->paused = false; + // Thread will automatically resume filling buffers + i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_START); +} + +bool common_hal_audiobusio_i2sout_get_paused(audiobusio_i2sout_obj_t *self) { + return self->paused; +} + +#endif // CIRCUITPY_AUDIOBUSIO_I2SOUT diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.h b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.h new file mode 100644 index 00000000000..916471fa833 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.h @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "common-hal/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" + +#include +#include +#include + +#if CIRCUITPY_AUDIOBUSIO_I2SOUT + +typedef struct { + mp_obj_base_t base; + const struct device *i2s_dev; + const mcu_pin_obj_t *bit_clock; + const mcu_pin_obj_t *word_select; + const mcu_pin_obj_t *data; + const mcu_pin_obj_t *main_clock; + mp_obj_t sample; + struct k_mem_slab mem_slab; + char *slab_buffer; + struct k_thread thread; + k_thread_stack_t *thread_stack; + k_tid_t thread_id; + size_t block_size; + bool left_justified; + bool playing; + bool paused; + bool loop; + bool stopping; + bool single_buffer; + uint8_t bytes_per_sample; + uint8_t channel_count; +} audiobusio_i2sout_obj_t; + +mp_obj_t common_hal_audiobusio_i2sout_construct_from_device(audiobusio_i2sout_obj_t *self, const struct device *i2s_device); + +void i2sout_reset(void); + +#endif // CIRCUITPY_AUDIOBUSIO_I2SOUT diff --git a/ports/zephyr-cp/common-hal/audiobusio/PDMIn.c b/ports/zephyr-cp/common-hal/audiobusio/PDMIn.c new file mode 100644 index 00000000000..3d3cfef5258 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/PDMIn.c @@ -0,0 +1,39 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiobusio/PDMIn.h" + +#include "py/runtime.h" + +#if CIRCUITPY_AUDIOBUSIO_PDMIN + +void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, + const mcu_pin_obj_t *clock_pin, const mcu_pin_obj_t *data_pin, + uint32_t sample_rate, uint8_t bit_depth, bool mono, uint8_t oversample) { + mp_raise_NotImplementedError(NULL); +} + +bool common_hal_audiobusio_pdmin_deinited(audiobusio_pdmin_obj_t *self) { + return true; +} + +void common_hal_audiobusio_pdmin_deinit(audiobusio_pdmin_obj_t *self) { +} + +uint8_t common_hal_audiobusio_pdmin_get_bit_depth(audiobusio_pdmin_obj_t *self) { + return 0; +} + +uint32_t common_hal_audiobusio_pdmin_get_sample_rate(audiobusio_pdmin_obj_t *self) { + return 0; +} + +uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self, + uint16_t *output_buffer, uint32_t output_buffer_length) { + return 0; +} + +#endif // CIRCUITPY_AUDIOBUSIO_PDMIN diff --git a/ports/zephyr-cp/common-hal/audiobusio/PDMIn.h b/ports/zephyr-cp/common-hal/audiobusio/PDMIn.h new file mode 100644 index 00000000000..195a436f3cf --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/PDMIn.h @@ -0,0 +1,18 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "common-hal/microcontroller/Pin.h" + +#if CIRCUITPY_AUDIOBUSIO_PDMIN + +typedef struct { + mp_obj_base_t base; +} audiobusio_pdmin_obj_t; + +#endif // CIRCUITPY_AUDIOBUSIO_PDMIN diff --git a/ports/zephyr-cp/common-hal/audiobusio/__init__.c b/ports/zephyr-cp/common-hal/audiobusio/__init__.c new file mode 100644 index 00000000000..5d2e802904d --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// No special initialization required for audiobusio diff --git a/ports/zephyr-cp/common-hal/audiobusio/__init__.h b/ports/zephyr-cp/common-hal/audiobusio/__init__.h new file mode 100644 index 00000000000..8ba7882bf94 --- /dev/null +++ b/ports/zephyr-cp/common-hal/audiobusio/__init__.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// No common definitions needed for audiobusio diff --git a/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c b/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c index b7a5bf9dbf1..178f33e028d 100644 --- a/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c +++ b/ports/zephyr-cp/common-hal/zephyr_kernel/__init__.c @@ -9,7 +9,7 @@ #include #include - +#include void raise_zephyr_error(int err) { if (err == 0) { @@ -46,6 +46,12 @@ void raise_zephyr_error(int err) { case EADDRINUSE: printk("EADDRINUSE\n"); break; + case EIO: + printk("EIO\n"); + break; + case ENOSYS: + printk("ENOSYS\n"); + break; case EINVAL: printk("EINVAL\n"); break; diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 5f51281870c..bd4f22a03cd 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -59,12 +59,22 @@ "supervisor", "errno", "io", + "math", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests -MPCONFIG_FLAGS = ["array", "errno", "io", "json"] +MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] # List of other modules (the value) that can be enabled when another one (the key) is. REVERSE_DEPENDENCIES = { + "audiobusio": ["audiocore"], + "audiocore": [ + "audiodelays", + "audiofilters", + "audiofreeverb", + "audiomixer", + "audiomp3", + "synthio", + ], "busio": ["fourwire", "i2cdisplaybus", "sdcardio", "sharpdisplay"], "fourwire": ["displayio", "busdisplay", "epaperdisplay"], "i2cdisplaybus": ["displayio", "busdisplay", "epaperdisplay"], @@ -86,8 +96,16 @@ # Other flags to set when a module is enabled EXTRA_FLAGS = { - "busio": ["BUSIO_SPI", "BUSIO_I2C"], - "rotaryio": ["ROTARYIO_SOFTENCODER"], + "audiobusio": {"AUDIOBUSIO_I2SOUT": 1, "AUDIOBUSIO_PDMIN": 0}, + "busio": {"BUSIO_SPI": 1, "BUSIO_I2C": 1}, + "rotaryio": {"ROTARYIO_SOFTENCODER": 1}, + "synthio": {"SYNTHIO_MAX_CHANNELS": 12}, +} + +# Library sources. Will be globbed from the top level directory +# No QSTR processing or CIRCUITPY specific flags +LIBRARY_SOURCE = { + "audiomp3": ["lib/mp3/src/*.c"], } SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os", "rotaryio"] @@ -332,6 +350,9 @@ async def build_circuitpython(): circuitpython_flags.append("-DLONGINT_IMPL_MPZ") circuitpython_flags.append("-DCIRCUITPY_SSL_MBEDTLS") circuitpython_flags.append("-DFFCONF_H='\"lib/oofatfs/ffconf.h\"'") + circuitpython_flags.append( + "-D_DEFAULT_SOURCE" + ) # To get more from picolibc to match newlib such as M_PI circuitpython_flags.extend(("-I", srcdir)) circuitpython_flags.extend(("-I", builddir)) circuitpython_flags.extend(("-I", portdir)) @@ -482,6 +503,7 @@ async def build_circuitpython(): # Make sure all modules have a setting by filling in defaults. hal_source = [] + library_sources = [] autogen_board_info = tomlkit.document() autogen_board_info.add( tomlkit.comment( @@ -509,8 +531,8 @@ async def build_circuitpython(): if enabled: if module.name in EXTRA_FLAGS: - for flag in EXTRA_FLAGS[module.name]: - circuitpython_flags.append(f"-DCIRCUITPY_{flag}=1") + for flag, value in EXTRA_FLAGS[module.name].items(): + circuitpython_flags.append(f"-DCIRCUITPY_{flag}={value}") if enabled: hal_source.extend(portdir.glob(f"bindings/{module.name}/*.c")) @@ -520,6 +542,9 @@ async def build_circuitpython(): if len(hal_source) == len_before or module.name in SHARED_MODULE_AND_COMMON_HAL: hal_source.extend(top.glob(f"shared-module/{module.name}/*.c")) hal_source.extend(top.glob(f"shared-bindings/{module.name}/*.c")) + if module.name in LIBRARY_SOURCE: + for library_source in LIBRARY_SOURCE[module.name]: + library_sources.extend(top.glob(library_source)) if os.environ.get("CI", "false") == "true": # Warn if it isn't up to date. @@ -621,6 +646,12 @@ async def build_circuitpython(): objects = [] async with asyncio.TaskGroup() as tg: + for source_file in library_sources: + source_file = top / source_file + build_file = source_file.with_suffix(".o") + object_file = builddir / (build_file.relative_to(top)) + objects.append(object_file) + tg.create_task(compiler.compile(source_file, object_file)) for source_file in source_files: source_file = top / source_file build_file = source_file.with_suffix(".o") diff --git a/ports/zephyr-cp/cptools/compat2driver.py b/ports/zephyr-cp/cptools/compat2driver.py index dff09787b28..49c462b9ded 100644 --- a/ports/zephyr-cp/cptools/compat2driver.py +++ b/ports/zephyr-cp/cptools/compat2driver.py @@ -1042,6 +1042,7 @@ "st_stm32_i2s": "i2s", "st_stm32_sai": "i2s", "vnd_i2s": "i2s", + "zephyr_i2s_sdl": "i2s", # # i3c "adi_max32_i3c": "i3c", diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index c123d90ce78..20df229000b 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -23,6 +23,7 @@ "nordic_nrf_twi": "i2c", "nordic_nrf_spim": "spi", "nordic_nrf_spi": "spi", + "nordic_nrf_i2s": "i2s", } # These are controllers, not the flash devices themselves. @@ -34,6 +35,8 @@ BUSIO_CLASSES = {"serial": "UART", "i2c": "I2C", "spi": "SPI"} +AUDIOBUSIO_CLASSES = {"i2s": "I2SOut"} + CONNECTORS = { "mikro-bus": [ "AN", @@ -411,6 +414,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa "usb_device": False, "_bleio": False, "hostnetwork": board_id in ["native_sim"], + "audiobusio": False, } config_bt_enabled = False @@ -545,6 +549,13 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa board_info["wifi"] = True elif driver == "bluetooth/hci": ble_hardware_present = True + elif driver in AUDIOBUSIO_CLASSES: + # audiobusio driver (i2s, audio/dmic) + board_info["audiobusio"] = True + logger.info(f"Supported audiobusio driver: {driver}") + if driver not in active_zephyr_devices: + active_zephyr_devices[driver] = [] + active_zephyr_devices[driver].append(node.labels) elif driver in EXCEPTIONAL_DRIVERS: pass elif driver in BUSIO_CLASSES: @@ -673,15 +684,25 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa zephyr_binding_headers = [] zephyr_binding_objects = [] zephyr_binding_labels = [] + i2sout_instance_names = [] for driver, instances in active_zephyr_devices.items(): - driverclass = BUSIO_CLASSES[driver] - zephyr_binding_headers.append(f'#include "shared-bindings/busio/{driverclass}.h"') + # Determine if this is busio or audiobusio + if driver in BUSIO_CLASSES: + module = "busio" + driverclass = BUSIO_CLASSES[driver] + elif driver in AUDIOBUSIO_CLASSES: + module = "audiobusio" + driverclass = AUDIOBUSIO_CLASSES[driver] + else: + continue - # Designate a main bus such as board.I2C. + zephyr_binding_headers.append(f'#include "shared-bindings/{module}/{driverclass}.h"') + + # Designate a main device such as board.I2C or board.I2S. if len(instances) == 1: instances[0].append(driverclass) else: - # Check to see if a main bus has already been designated + # Check to see if a main device has already been designated found_main = False for labels in instances: for label in labels: @@ -697,23 +718,28 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa if found_main: break for labels in instances: - instance_name = f"{driver}_{labels[0]}" + instance_name = f"{driver.replace('/', '_')}_{labels[0]}" c_function_name = f"_{instance_name}" singleton_ptr = f"{c_function_name}_singleton" function_object = f"{c_function_name}_obj" - busio_type = f"busio_{driverclass.lower()}" + obj_type = f"{module}_{driverclass.lower()}" - # UART needs a receiver buffer + # Handle special cases for different drivers if driver == "serial": + # UART needs a receiver buffer buffer_decl = f"static byte {instance_name}_buffer[128];" construct_call = f"common_hal_busio_uart_construct_from_device(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]})), 128, {instance_name}_buffer)" else: + # Default case (I2C, SPI, I2S) buffer_decl = "" - construct_call = f"common_hal_busio_{driverclass.lower()}_construct_from_device(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]})))" + construct_call = f"common_hal_{module}_{driverclass.lower()}_construct_from_device(&{instance_name}_obj, DEVICE_DT_GET(DT_NODELABEL({labels[0]})))" + + if driver == "i2s": + i2sout_instance_names.append(instance_name) zephyr_binding_objects.append( f"""{buffer_decl} -static {busio_type}_obj_t {instance_name}_obj; +static {obj_type}_obj_t {instance_name}_obj; static mp_obj_t {singleton_ptr} = mp_const_none; static mp_obj_t {c_function_name}(void) {{ if ({singleton_ptr} != mp_const_none) {{ @@ -732,6 +758,18 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa zephyr_binding_objects = "\n".join(zephyr_binding_objects) zephyr_binding_labels = "\n".join(zephyr_binding_labels) + # Generate i2sout_reset() that stops all board I2SOut instances + if i2sout_instance_names: + stop_calls = "\n ".join( + f"common_hal_audiobusio_i2sout_stop(&{name}_obj);" for name in i2sout_instance_names + ) + i2sout_reset_func = f""" +void i2sout_reset(void) {{ + {stop_calls} +}}""" + else: + i2sout_reset_func = "" + zephyr_display_header = "" zephyr_display_object = "" zephyr_display_board_entry = "" @@ -857,6 +895,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa {zephyr_binding_objects} {zephyr_display_object} +{i2sout_reset_func} static const mp_rom_map_elem_t mcu_pin_globals_table[] = {{ {mcu_pin_mapping} diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 9b4dcccb53e..7eaeb898914 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -44,3 +44,7 @@ CONFIG_FRAME_POINTER=n CONFIG_NET_HOSTNAME_ENABLE=y CONFIG_NET_HOSTNAME_DYNAMIC=y CONFIG_NET_HOSTNAME="circuitpython" + +CONFIG_I2S=y +CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index c40475177e0..b36637bb81c 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -9,6 +9,10 @@ #include "mpconfigboard.h" #include "supervisor/shared/tick.h" +#if CIRCUITPY_AUDIOBUSIO_I2SOUT +#include "common-hal/audiobusio/I2SOut.h" +#endif + #include #include #include @@ -147,6 +151,10 @@ void reset_cpu(void) { } void reset_port(void) { + #if CIRCUITPY_AUDIOBUSIO_I2SOUT + i2sout_reset(); + #endif + #if defined(CONFIG_ARCH_POSIX) native_sim_reset_port_count++; if (native_sim_vm_runs != INT32_MAX && diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index cec867a9703..03451048324 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -318,7 +318,13 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp # native_sim vm-runs includes the boot VM setup run. realtime_flag = "-rt" if use_realtime else "-no-rt" cmd.extend( - (realtime_flag, "-display_headless", "-wait_uart", f"--vm-runs={code_py_runs + 1}") + ( + realtime_flag, + "-display_headless", + "-i2s_earless", + "-wait_uart", + f"--vm-runs={code_py_runs + 1}", + ) ) if flash_erase_block_size is not None: diff --git a/ports/zephyr-cp/tests/test_audiobusio.py b/ports/zephyr-cp/tests/test_audiobusio.py new file mode 100644 index 00000000000..5a899139c22 --- /dev/null +++ b/ports/zephyr-cp/tests/test_audiobusio.py @@ -0,0 +1,216 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries LLC +# SPDX-License-Identifier: MIT + +"""Test audiobusio I2SOut functionality on native_sim.""" + +from pathlib import Path + +import pytest +from perfetto.trace_processor import TraceProcessor + + +I2S_PLAY_CODE = """\ +import array +import math +import audiocore +import board +import time + +# Generate a 440 Hz sine wave, 16-bit signed stereo at 16000 Hz +sample_rate = 16000 +length = sample_rate // 440 # ~36 samples per period +values = [] +for i in range(length): + v = int(math.sin(math.pi * 2 * i / length) * 30000) + values.append(v) # left + values.append(v) # right + +sample = audiocore.RawSample( + array.array("h", values), + sample_rate=sample_rate, + channel_count=2, +) + +dac = board.I2S0() +print("playing") +dac.play(sample, loop=True) +time.sleep(0.5) +dac.stop() +print("stopped") +print("done") +""" + + +def parse_i2s_trace(trace_file: Path, track_name: str) -> list[tuple[int, int]]: + """Parse I2S counter trace from Perfetto trace file.""" + tp = TraceProcessor(file_path=str(trace_file)) + result = tp.query( + f""" + SELECT c.ts, c.value + FROM counter c + JOIN track t ON c.track_id = t.id + WHERE t.name LIKE "%{track_name}" + ORDER BY c.ts + """ + ) + return [(int(row.ts), int(row.value)) for row in result] + + +@pytest.mark.duration(10) +@pytest.mark.circuitpy_drive({"code.py": I2S_PLAY_CODE}) +def test_i2s_play_and_stop(circuitpython): + """Test I2SOut play and stop produce expected output and correct waveform traces.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "playing" in output + assert "stopped" in output + assert "done" in output + + # Check that Perfetto trace has I2S counter tracks with data + left_trace = parse_i2s_trace(circuitpython.trace_file, "Left") + right_trace = parse_i2s_trace(circuitpython.trace_file, "Right") + + # Should have counter events (initial zero + audio data) + assert len(left_trace) > 10, f"Expected many Left channel events, got {len(left_trace)}" + assert len(right_trace) > 10, f"Expected many Right channel events, got {len(right_trace)}" + + # Verify timestamps are spread out (not all the same) + left_timestamps = [ts for ts, _ in left_trace] + assert left_timestamps[-1] > left_timestamps[1], "Timestamps should increase over time" + time_span_ns = left_timestamps[-1] - left_timestamps[1] + # We play for 0.5s, so span should be at least 100ms + assert time_span_ns > 100_000_000, f"Expected >100ms time span, got {time_span_ns / 1e6:.1f}ms" + + # Audio data should contain non-zero values (sine wave) + # Skip the initial zero value + left_values = [v for _, v in left_trace if v != 0] + right_values = [v for _, v in right_trace if v != 0] + assert len(left_values) > 5, "Left channel has too few non-zero values" + assert len(right_values) > 5, "Right channel has too few non-zero values" + + # Sine wave should have both positive and negative values + assert any(v > 0 for v in left_values), "Left channel has no positive values" + assert any(v < 0 for v in left_values), "Left channel has no negative values" + + # Verify amplitude is in the expected range (we generate with amplitude 30000) + max_left = max(left_values) + min_left = min(left_values) + assert max_left > 20000, f"Left max {max_left} too low, expected >20000" + assert min_left < -20000, f"Left min {min_left} too high, expected <-20000" + + # Left and right should match (we write the same value to both channels) + # Compare a subset of matching timestamps + left_by_ts = dict(left_trace) + right_by_ts = dict(right_trace) + common_ts = sorted(set(left_by_ts.keys()) & set(right_by_ts.keys())) + mismatches = 0 + for ts in common_ts[:100]: + if left_by_ts[ts] != right_by_ts[ts]: + mismatches += 1 + assert mismatches == 0, ( + f"{mismatches} L/R mismatches in first {min(100, len(common_ts))} common timestamps" + ) + + +I2S_PLAY_NO_STOP_CODE = """\ +import array +import math +import audiocore +import board +import time + +sample_rate = 16000 +length = sample_rate // 440 +values = [] +for i in range(length): + v = int(math.sin(math.pi * 2 * i / length) * 30000) + values.append(v) + values.append(v) + +sample = audiocore.RawSample( + array.array("h", values), + sample_rate=sample_rate, + channel_count=2, +) + +dac = board.I2S0() +dac.play(sample, loop=True) +print("playing") +time.sleep(0.2) +# Exit without calling dac.stop() — reset_port should clean up +print("exiting") +""" + + +@pytest.mark.duration(15) +@pytest.mark.code_py_runs(2) +@pytest.mark.circuitpy_drive({"code.py": I2S_PLAY_NO_STOP_CODE}) +def test_i2s_stops_on_code_exit(circuitpython): + """Test I2S is stopped by reset_port when code.py exits without explicit stop.""" + # First run: plays audio then exits without stopping + circuitpython.serial.wait_for("exiting") + circuitpython.serial.wait_for("Press any key to enter the REPL") + # Trigger soft reload + circuitpython.serial.write("\x04") + + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # Should see "playing" and "exiting" at least twice (once per run) + assert output.count("playing") >= 2 + assert output.count("exiting") >= 2 + + +I2S_PAUSE_RESUME_CODE = """\ +import array +import math +import audiocore +import board +import time + +sample_rate = 16000 +length = sample_rate // 440 +values = [] +for i in range(length): + v = int(math.sin(math.pi * 2 * i / length) * 30000) + values.append(v) + values.append(v) + +sample = audiocore.RawSample( + array.array("h", values), + sample_rate=sample_rate, + channel_count=2, +) + +dac = board.I2S0() +dac.play(sample, loop=True) +print("playing") +time.sleep(0.2) + +dac.pause() +print("paused") +assert dac.paused +time.sleep(0.1) + +dac.resume() +print("resumed") +assert not dac.paused +time.sleep(0.2) + +dac.stop() +print("done") +""" + + +@pytest.mark.duration(10) +@pytest.mark.circuitpy_drive({"code.py": I2S_PAUSE_RESUME_CODE}) +def test_i2s_pause_resume(circuitpython): + """Test I2SOut pause and resume work correctly.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "playing" in output + assert "paused" in output + assert "resumed" in output + assert "done" in output diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c index 9aaf7421c65..952a00e2903 100644 --- a/shared-bindings/audiobusio/I2SOut.c +++ b/shared-bindings/audiobusio/I2SOut.c @@ -144,6 +144,8 @@ static void check_for_deinit(audiobusio_i2sout_obj_t *self) { //| //| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer` or `audiomp3.MP3Decoder`. //| +//| Mono samples will be converted to stereo by copying value to both the left channel and the right channel. +//| //| The sample itself should consist of 8 bit or 16 bit samples.""" //| ... //| diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index b27eafb71a9..212686a092e 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -99,11 +99,11 @@ static inline uint32_t mult16signed(uint32_t val, int32_t mul[2]) { int32_t hi, lo; enum { bits = 16 }; // saturate to 16 bits enum { shift = 15 }; // shift is done automatically - asm volatile ("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul[0]), "r" (val)); - asm volatile ("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul[1]), "r" (val)); - asm volatile ("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); - asm volatile ("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); - asm volatile ("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack + __asm__ volatile ("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul[0]), "r" (val)); + __asm__ volatile ("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul[1]), "r" (val)); + __asm__ volatile ("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); + __asm__ volatile ("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); + __asm__ volatile ("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack return val; #else uint32_t result = 0; diff --git a/tests/circuitpython-manual/audiobusio/i2s_sample_loop.py b/tests/circuitpython-manual/audiobusio/i2s_sample_loop.py index 75ed4c7ae6f..9778ac2b820 100644 --- a/tests/circuitpython-manual/audiobusio/i2s_sample_loop.py +++ b/tests/circuitpython-manual/audiobusio/i2s_sample_loop.py @@ -1,35 +1,73 @@ +# SPDX-FileCopyrightText: 2018 Kattni Rembor for Adafruit Industries +# +# SPDX-License-Identifier: MIT import audiocore -import audiobusio import board import digitalio import array +import struct import time import math -import rp2pio -import adafruit_pioasm - -time.sleep(10) trigger = digitalio.DigitalInOut(board.D4) trigger.switch_to_output(True) # Generate one period of sine wav. -length = 8000 // 440 +sample_names = [ + "mono unsigned 8 bit", + "stereo unsigned 8 bit", + "mono signed 8 bit", + "stereo signed 8 bit", + "mono unsigned 16 bit", + "stereo unsigned 16 bit", + "mono signed 16 bit", + "stereo signed 16 bit", +] +sample_config = { + "mono unsigned 8 bit": {"format": "B", "channel_count": 1}, + "stereo unsigned 8 bit": {"format": "B", "channel_count": 2}, + "mono signed 8 bit": {"format": "b", "channel_count": 1}, + "stereo signed 8 bit": {"format": "b", "channel_count": 2}, + "mono unsigned 16 bit": {"format": "H", "channel_count": 1}, + "stereo unsigned 16 bit": {"format": "H", "channel_count": 2}, + "mono signed 16 bit": {"format": "h", "channel_count": 1}, + "stereo signed 16 bit": {"format": "h", "channel_count": 2}, +} -# signed 16 bit -s16 = array.array("h", [0] * length) -for i in range(length): - s16[i] = int(math.sin(math.pi * 2 * i / length) * (2**15)) - print(s16[i]) +for sample_rate in [8000, 16000, 32000, 44100]: + print(f"{sample_rate / 1000} kHz") + length = sample_rate // 440 -sample = audiocore.RawSample(s16, sample_rate=8000) + samples = [] -dac = audiobusio.I2SOut(bit_clock=board.D10, word_select=board.D11, data=board.D12) + for name in sample_names: + config = sample_config[name] + format = config["format"] + channel_count = config["channel_count"] + length = sample_rate // 440 + values = [] + for i in range(length): + range = 2 ** (struct.calcsize(format) * 8 - 1) - 1 + value = int(math.sin(math.pi * 2 * i / length) * range) + if "unsigned" in name: + value += range + values.append(value) + if channel_count == 2: + values.append(value) + sample = audiocore.RawSample( + array.array(format, values), sample_rate=sample_rate, channel_count=channel_count + ) + samples.append(sample) -trigger.value = False -dac.play(sample, loop=True) -time.sleep(1) -dac.stop() -trigger.value = True + dac = board.I2S0() + for sample, name in zip(samples, sample_names): + print(" ", name) + trigger.value = False + dac.play(sample, loop=True) + time.sleep(1) + dac.stop() + time.sleep(0.1) + trigger.value = True + print() print("done") From 321b0bf566237184509d31fba5c90d5a31f665d0 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 30 Mar 2026 15:53:00 -0700 Subject: [PATCH 366/876] Add NVM support for Zephyr port Implement nvm.ByteArray using Zephyr flash_area API, auto-detect NVM partition size from device tree, and add 8KB NVM partition to feather nrf52840 matching the non-Zephyr Nordic port layout. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../autogen_board_info.toml | 2 +- .../adafruit_feather_nrf52840_uf2.overlay | 22 ++++ .../native/native_sim/autogen_board_info.toml | 2 +- ports/zephyr-cp/boards/native_sim.overlay | 7 +- .../common-hal/microcontroller/__init__.c | 6 +- ports/zephyr-cp/common-hal/nvm/ByteArray.c | 103 ++++++++++++++++++ ports/zephyr-cp/common-hal/nvm/ByteArray.h | 13 +++ ports/zephyr-cp/cptools/zephyr2cp.py | 5 + ports/zephyr-cp/mpconfigport.h | 3 + ports/zephyr-cp/tests/test_nvm.py | 73 +++++++++++++ 10 files changed, 229 insertions(+), 7 deletions(-) create mode 100644 ports/zephyr-cp/common-hal/nvm/ByteArray.c create mode 100644 ports/zephyr-cp/common-hal/nvm/ByteArray.h create mode 100644 ports/zephyr-cp/tests/test_nvm.py diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 1672ab0b461..762f1166996 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -73,7 +73,7 @@ microcontroller = true mipidsi = false msgpack = false neopixel_write = false -nvm = false +nvm = true # Zephyr board has nvm onewireio = false os = true paralleldisplaybus = false diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay index a61cbf2047d..e01ebd6df1f 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay @@ -17,6 +17,28 @@ /delete-node/ partitions; }; +/delete-node/ &storage_partition; +/delete-node/ &code_partition; + +&flash0 { + partitions { + code_partition: partition@26000 { + label = "Application"; + reg = <0x00026000 0x000c4000>; + }; + + storage_partition: partition@ea000 { + label = "storage"; + reg = <0x000ea000 0x00008000>; + }; + + nvm_partition: partition@f2000 { + label = "nvm"; + reg = <0x000f2000 0x00002000>; + }; + }; +}; + &uart0 { status = "okay"; }; diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 51a9f1b3476..7224381ec28 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -73,7 +73,7 @@ microcontroller = true mipidsi = false msgpack = false neopixel_write = false -nvm = false +nvm = true # Zephyr board has nvm onewireio = false os = true paralleldisplaybus = false diff --git a/ports/zephyr-cp/boards/native_sim.overlay b/ports/zephyr-cp/boards/native_sim.overlay index 2a07108627f..aee9d17f9d0 100644 --- a/ports/zephyr-cp/boards/native_sim.overlay +++ b/ports/zephyr-cp/boards/native_sim.overlay @@ -31,7 +31,12 @@ circuitpy_partition: partition@0 { label = "circuitpy"; - reg = <0x00000000 DT_SIZE_K(2048)>; + reg = <0x00000000 DT_SIZE_K(2040)>; + }; + + nvm_partition: partition@1fe000 { + label = "nvm"; + reg = <0x001fe000 0x00002000>; }; }; }; diff --git a/ports/zephyr-cp/common-hal/microcontroller/__init__.c b/ports/zephyr-cp/common-hal/microcontroller/__init__.c index 6ebf5f4c368..be33cd26c9a 100644 --- a/ports/zephyr-cp/common-hal/microcontroller/__init__.c +++ b/ports/zephyr-cp/common-hal/microcontroller/__init__.c @@ -11,7 +11,7 @@ #include "common-hal/microcontroller/Pin.h" #include "common-hal/microcontroller/Processor.h" -// #include "shared-bindings/nvm/ByteArray.h" +#include "shared-bindings/nvm/ByteArray.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/microcontroller/Processor.h" @@ -93,14 +93,12 @@ const mcu_processor_obj_t common_hal_mcu_processor_obj = { }, }; -#if CIRCUITPY_NVM && CIRCUITPY_INTERNAL_NVM_SIZE > 0 +#if CIRCUITPY_NVM // The singleton nvm.ByteArray object. const nvm_bytearray_obj_t common_hal_mcu_nvm_obj = { .base = { .type = &nvm_bytearray_type, }, - .start_address = (uint8_t *)CIRCUITPY_INTERNAL_NVM_START_ADDR, - .len = CIRCUITPY_INTERNAL_NVM_SIZE, }; #endif diff --git a/ports/zephyr-cp/common-hal/nvm/ByteArray.c b/ports/zephyr-cp/common-hal/nvm/ByteArray.c new file mode 100644 index 00000000000..b8f552d6773 --- /dev/null +++ b/ports/zephyr-cp/common-hal/nvm/ByteArray.c @@ -0,0 +1,103 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "common-hal/nvm/ByteArray.h" +#include "shared-bindings/nvm/ByteArray.h" + +#include + +#include +#include + +#define NVM_PARTITION nvm_partition + +#if FIXED_PARTITION_EXISTS(NVM_PARTITION) + +static const struct flash_area *nvm_area = NULL; +static size_t nvm_erase_size = 0; + +static bool ensure_nvm_open(void) { + if (nvm_area != NULL) { + return true; + } + int rc = flash_area_open(FIXED_PARTITION_ID(NVM_PARTITION), &nvm_area); + if (rc != 0) { + return false; + } + + const struct device *dev = flash_area_get_device(nvm_area); + struct flash_pages_info info; + flash_get_page_info_by_offs(dev, nvm_area->fa_off, &info); + nvm_erase_size = info.size; + + return true; +} + +uint32_t common_hal_nvm_bytearray_get_length(const nvm_bytearray_obj_t *self) { + if (!ensure_nvm_open()) { + return 0; + } + return nvm_area->fa_size; +} + +bool common_hal_nvm_bytearray_set_bytes(const nvm_bytearray_obj_t *self, + uint32_t start_index, uint8_t *values, uint32_t len) { + if (!ensure_nvm_open()) { + return false; + } + + uint32_t address = start_index; + while (len > 0) { + uint32_t page_offset = address % nvm_erase_size; + uint32_t page_start = address - page_offset; + uint32_t write_len = MIN(len, nvm_erase_size - page_offset); + + uint8_t *buffer = m_malloc(nvm_erase_size); + if (buffer == NULL) { + return false; + } + + // Read the full erase page. + int rc = flash_area_read(nvm_area, page_start, buffer, nvm_erase_size); + if (rc != 0) { + m_free(buffer); + return false; + } + + // Modify the relevant bytes. + memcpy(buffer + page_offset, values, write_len); + + // Erase the page. + rc = flash_area_erase(nvm_area, page_start, nvm_erase_size); + if (rc != 0) { + m_free(buffer); + return false; + } + + // Write the page back. + rc = flash_area_write(nvm_area, page_start, buffer, nvm_erase_size); + m_free(buffer); + if (rc != 0) { + return false; + } + + address += write_len; + values += write_len; + len -= write_len; + } + return true; +} + +void common_hal_nvm_bytearray_get_bytes(const nvm_bytearray_obj_t *self, + uint32_t start_index, uint32_t len, uint8_t *values) { + if (!ensure_nvm_open()) { + return; + } + flash_area_read(nvm_area, start_index, values, len); +} + +#endif // FIXED_PARTITION_EXISTS(NVM_PARTITION) diff --git a/ports/zephyr-cp/common-hal/nvm/ByteArray.h b/ports/zephyr-cp/common-hal/nvm/ByteArray.h new file mode 100644 index 00000000000..9c771aaa3a9 --- /dev/null +++ b/ports/zephyr-cp/common-hal/nvm/ByteArray.h @@ -0,0 +1,13 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; +} nvm_bytearray_obj_t; diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index c123d90ce78..d8372919f29 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -893,4 +893,9 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa board_info["flash_count"] = len(flashes) board_info["rotaryio"] = bool(ioports) board_info["usb_num_endpoint_pairs"] = usb_num_endpoint_pairs + + # Detect NVM partition from the device tree. + nvm_node = device_tree.label2node.get("nvm_partition") + board_info["nvm"] = nvm_node is not None + return board_info diff --git a/ports/zephyr-cp/mpconfigport.h b/ports/zephyr-cp/mpconfigport.h index 491b5293e2e..491c03592c0 100644 --- a/ports/zephyr-cp/mpconfigport.h +++ b/ports/zephyr-cp/mpconfigport.h @@ -17,6 +17,9 @@ #define CIRCUITPY_DEBUG_TINYUSB 0 +// NVM size is determined at runtime from the Zephyr partition table. +#define CIRCUITPY_INTERNAL_NVM_SIZE 1 + // Disable native _Float16 handling for host builds. #define MICROPY_FLOAT_USE_NATIVE_FLT16 (0) diff --git a/ports/zephyr-cp/tests/test_nvm.py b/ports/zephyr-cp/tests/test_nvm.py new file mode 100644 index 00000000000..5de304afc1b --- /dev/null +++ b/ports/zephyr-cp/tests/test_nvm.py @@ -0,0 +1,73 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test NVM functionality on native_sim.""" + +import pytest + + +NVM_BASIC_CODE = """\ +import microcontroller + +nvm = microcontroller.nvm +print(f"nvm length: {len(nvm)}") + +# Write some bytes +nvm[0] = 42 +nvm[1] = 99 +print(f"nvm[0]: {nvm[0]}") +print(f"nvm[1]: {nvm[1]}") + +# Write a slice +nvm[2:5] = b"\\x01\\x02\\x03" +print(f"nvm[2:5]: {list(nvm[2:5])}") + +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": NVM_BASIC_CODE}) +def test_nvm_read_write(circuitpython): + """Test basic NVM read and write operations.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "nvm length: 8192" in output + assert "nvm[0]: 42" in output + assert "nvm[1]: 99" in output + assert "nvm[2:5]: [1, 2, 3]" in output + assert "done" in output + + +NVM_PERSIST_CODE = """\ +import microcontroller + +nvm = microcontroller.nvm +value = nvm[0] +print(f"nvm[0]: {value}") + +if value == 255: + # First run: write a marker + nvm[0] = 123 + print("wrote marker") +else: + print(f"marker found: {value}") + +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": NVM_PERSIST_CODE}) +@pytest.mark.code_py_runs(2) +def test_nvm_persists_across_reload(circuitpython): + """Test that NVM data persists across soft reloads.""" + circuitpython.serial.wait_for("wrote marker") + # Trigger soft reload + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "nvm[0]: 255" in output + assert "wrote marker" in output + assert "marker found: 123" in output + assert "done" in output From 870cc04dcb9737592e3e2c3bf6af635f9a39fd99 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 1 Apr 2026 12:21:44 -0700 Subject: [PATCH 367/876] Enable dynamic thread stack alloc --- ports/zephyr-cp/prj.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 7eaeb898914..308333922f3 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -47,4 +47,5 @@ CONFIG_NET_HOSTNAME="circuitpython" CONFIG_I2S=y CONFIG_DYNAMIC_THREAD=y +CONFIG_DYNAMIC_THREAD_ALLOC=y CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y From 57a07fd5f248aa36aba5e5499baf516e27c4f91b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 1 Apr 2026 13:12:58 -0700 Subject: [PATCH 368/876] Use newer zephyr with uninit fix --- ports/zephyr-cp/zephyr-config/west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index fd3eebc66f1..82509b40cef 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -8,6 +8,6 @@ manifest: path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: a768573cc42b18bc2e8b819d4686e52cdb9c848e + revision: d991bfc190507849d510326b24ba7b7a6c51a0e6 clone-depth: 100 import: true From ee527d3b47f1a06dd060832dca81de7a9204c96c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 1 Apr 2026 15:31:54 -0700 Subject: [PATCH 369/876] Free the slab buffer on error --- ports/zephyr-cp/common-hal/audiobusio/I2SOut.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c index 5e2e1fac8a4..e858552c524 100644 --- a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -131,6 +131,7 @@ static void audio_thread_func(void *self_in, void *unused1, void *unused2) { int ret = i2s_write(self->i2s_dev, next_buffer, self->block_size); if (ret < 0) { printk("i2s_write failed: %d\n", ret); + k_mem_slab_free(&self->mem_slab, next_buffer); // Error writing, stop playback self->playing = false; break; @@ -210,6 +211,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, ret = i2s_write(self->i2s_dev, buf, block_size); if (ret < 0) { printk("i2s_write failed: %d\n", ret); + k_mem_slab_free(&self->mem_slab, buf); common_hal_audiobusio_i2sout_stop(self); raise_zephyr_error(ret); } From fa583096f7180259778f71c6930c57c66695b64b Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 2 Apr 2026 18:12:19 +0200 Subject: [PATCH 370/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 1 + locale/el.po | 1 + locale/hi.po | 1 + locale/ko.po | 1 + locale/ru.po | 1 + locale/tr.po | 1 + 6 files changed, 6 insertions(+) diff --git a/locale/cs.po b/locale/cs.po index 0adef977617..94a03f2e8b8 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -2435,6 +2435,7 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c #: ports/zephyr-cp/common-hal/busio/I2C.c #: ports/zephyr-cp/common-hal/busio/SPI.c #: ports/zephyr-cp/common-hal/busio/UART.c diff --git a/locale/el.po b/locale/el.po index df024f2b1fe..03a28bf863d 100644 --- a/locale/el.po +++ b/locale/el.po @@ -2439,6 +2439,7 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c #: ports/zephyr-cp/common-hal/busio/I2C.c #: ports/zephyr-cp/common-hal/busio/SPI.c #: ports/zephyr-cp/common-hal/busio/UART.c diff --git a/locale/hi.po b/locale/hi.po index 48a8c6c26e1..18e4eee167c 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -2413,6 +2413,7 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c #: ports/zephyr-cp/common-hal/busio/I2C.c #: ports/zephyr-cp/common-hal/busio/SPI.c #: ports/zephyr-cp/common-hal/busio/UART.c diff --git a/locale/ko.po b/locale/ko.po index 63c64a6952d..9f325552468 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -2487,6 +2487,7 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c #: ports/zephyr-cp/common-hal/busio/I2C.c #: ports/zephyr-cp/common-hal/busio/SPI.c #: ports/zephyr-cp/common-hal/busio/UART.c diff --git a/locale/ru.po b/locale/ru.po index a7f7a35d58b..8f222fb2534 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -2472,6 +2472,7 @@ msgstr "Неподдерживаемый тип сокета" msgid "Update failed" msgstr "Обновление не удалось" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c #: ports/zephyr-cp/common-hal/busio/I2C.c #: ports/zephyr-cp/common-hal/busio/SPI.c #: ports/zephyr-cp/common-hal/busio/UART.c diff --git a/locale/tr.po b/locale/tr.po index 00f1c82065a..c35a97623c6 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -2435,6 +2435,7 @@ msgstr "" msgid "Update failed" msgstr "" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c #: ports/zephyr-cp/common-hal/busio/I2C.c #: ports/zephyr-cp/common-hal/busio/SPI.c #: ports/zephyr-cp/common-hal/busio/UART.c From 50ba2e88c65ae3fa5d7b657ee6ed3e85774c0d86 Mon Sep 17 00:00:00 2001 From: Jesse Adams Date: Thu, 2 Apr 2026 12:18:36 -0400 Subject: [PATCH 371/876] Update adafruit_qtpy_esp32s3_* boards wifi power settings to fix common wifi connectivity issues This is related to #10914. This matches the setting for [adafruit_qtpy_esp32c3](https://github.com/adafruit/circuitpython/blob/main/ports/espressif/boards/adafruit_qtpy_esp32c3/mpconfigboard.h) --- .../adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h | 3 +++ .../boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h index ad97ab057fb..9760bbfeb44 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_qtpy_esp32s3_4mbflash_2mbpsram/mpconfigboard.h @@ -25,3 +25,6 @@ #define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO5, .rx = &pin_GPIO16}} #define DOUBLE_TAP_PIN (&pin_GPIO10) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h index fcdefda3b40..6073bd47d0e 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_qtpy_esp32s3_nopsram/mpconfigboard.h @@ -25,3 +25,6 @@ #define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO5, .rx = &pin_GPIO16}} #define DOUBLE_TAP_PIN (&pin_GPIO10) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) From 6a34aa10109699a70da78082f1f0c2787badfafd Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 31 Mar 2026 11:05:36 -0700 Subject: [PATCH 372/876] Migrate espressif port from ESP-IDF v5.5.3 to v6.0 Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/protomatter | 2 +- ports/espressif/CMakeLists.txt | 2 +- ports/espressif/Makefile | 245 ++++++++++---- .../adafruit_magtag_2.9_grayscale/board.c | 1 + .../ai_thinker_esp32-c3s-2m/mpconfigboard.mk | 7 +- .../mpconfigboard.mk | 2 +- .../espressif_esp32s3_usb_otg_n8/board.c | 1 + .../boards/hardkernel_odroid_go/board.c | 1 + .../boards/lilygo_tdisplay_s3/board.c | 1 + .../m5stack_cardputer_ros/mpconfigboard.mk | 2 +- .../boards/sunton_esp32_8048S050/board.c | 1 + .../boards/sunton_esp32_8048S070/board.c | 1 + ports/espressif/boards/vidi_x/board.c | 1 + ports/espressif/common-hal/_bleio/Adapter.c | 2 +- .../espressif/common-hal/_bleio/Connection.c | 2 +- .../espressif/common-hal/alarm/SleepMemory.c | 5 + ports/espressif/common-hal/alarm/__init__.c | 97 +++--- .../espressif/common-hal/alarm/pin/PinAlarm.c | 12 +- .../common-hal/alarm/touch/TouchAlarm.c | 185 +++++----- .../common-hal/analogbufio/BufferedIn.c | 2 +- .../espressif/common-hal/analogio/AnalogIn.c | 2 +- .../espressif/common-hal/analogio/AnalogIn.h | 2 +- .../common-hal/audiobusio/__init__.c | 2 +- ports/espressif/common-hal/busio/I2C.c | 2 +- ports/espressif/common-hal/busio/I2C.h | 2 +- .../dotclockframebuffer/DotClockFramebuffer.c | 5 +- ports/espressif/common-hal/espcamera/Camera.c | 3 +- ports/espressif/common-hal/espnow/ESPNow.c | 10 +- .../common-hal/i2ctarget/I2CTarget.c | 78 +++-- .../common-hal/i2ctarget/I2CTarget.h | 9 +- .../common-hal/microcontroller/Processor.c | 23 +- ports/espressif/common-hal/mipidsi/Display.c | 1 - .../common-hal/neopixel_write/__init__.c | 14 +- ports/espressif/common-hal/sdioio/SDCard.c | 8 +- ports/espressif/common-hal/wifi/Radio.c | 12 +- ports/espressif/common-hal/wifi/__init__.c | 319 +++++++++++++++++- ports/espressif/esp-camera | 2 +- ports/espressif/esp-idf | 2 +- .../esp-idf-config/sdkconfig-esp32.defaults | 6 +- .../esp-idf-config/sdkconfig-esp32c2.defaults | 6 +- .../esp-idf-config/sdkconfig-esp32c3.defaults | 6 +- .../esp-idf-config/sdkconfig-esp32s2.defaults | 12 +- .../esp-idf-config/sdkconfig-esp32s3.defaults | 6 +- .../sdkconfig-flash-120m.defaults | 2 + ...sdkconfig-flash-2MB-no-ota-no-uf2.defaults | 1 - .../sdkconfig-flash-32MB.defaults | 1 - .../esp-idf-config/sdkconfig.defaults | 9 +- ports/espressif/peripherals/esp32/pins.c | 20 +- ports/espressif/peripherals/esp32p4/pins.c | 28 +- ports/espressif/peripherals/esp32s2/pins.c | 28 +- ports/espressif/peripherals/esp32s3/pins.c | 28 +- ports/espressif/peripherals/pins.h | 9 +- ports/espressif/peripherals/touch.c | 127 +++++-- ports/espressif/peripherals/touch.h | 8 +- ports/espressif/supervisor/port.c | 2 +- ports/espressif/supervisor/usb.c | 2 - shared-module/hashlib/Hash.c | 51 ++- shared-module/hashlib/Hash.h | 16 + shared-module/hashlib/__init__.c | 36 +- shared-module/ssl/SSLSocket.c | 20 +- shared-module/ssl/SSLSocket.h | 5 + tools/ci_fetch_deps.py | 1 + 62 files changed, 1072 insertions(+), 426 deletions(-) diff --git a/lib/protomatter b/lib/protomatter index f83bac7e421..425b6c7f887 160000 --- a/lib/protomatter +++ b/lib/protomatter @@ -1 +1 @@ -Subproject commit f83bac7e421077812523fddb83d3e25f29753315 +Subproject commit 425b6c7f887cca5d24d768d8c80c74ba7eb88dc6 diff --git a/ports/espressif/CMakeLists.txt b/ports/espressif/CMakeLists.txt index 387a18dac09..e612e4f31de 100644 --- a/ports/espressif/CMakeLists.txt +++ b/ports/espressif/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required(VERSION 3.16) set(ENV{IDF_PATH} ${CMAKE_SOURCE_DIR}/esp-idf) # The component list here determines what options we get in menuconfig and what the ninja file can build. -set(COMPONENTS bt driver esp_driver_dac esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_i2s esp_driver_ledc esp_driver_pcnt esp_driver_rmt esp_driver_spi esp_driver_tsens esp_driver_uart esp-tls esp_adc_cal esp_event esp_netif esp_psram esp_wifi esptool_py freertos log lwip main mbedtls mdns soc ulp usb wpa_supplicant esp-camera esp_lcd vfs esp_vfs_console sdmmc) +set(COMPONENTS bt driver esp_driver_dac esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_i2s esp_driver_ledc esp_driver_pcnt esp_driver_rmt esp_driver_sdmmc esp_driver_spi esp_driver_touch_sens esp_driver_tsens esp_driver_uart esp-tls esp_adc esp_event esp_netif esp_psram esp_security esp_wifi esptool_py freertos log lwip main mbedtls mdns pthread soc ulp wpa_supplicant esp_lcd vfs esp_stdio sdmmc esp-camera) set(EXTRA_COMPONENT_DIRS "esp-protocols/components/mdns" "esp-camera") include($ENV{IDF_PATH}/tools/cmake/project.cmake) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 2545b33d22a..c1c2033dd67 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -47,41 +47,40 @@ INC += \ -isystem esp-idf/components/bt/host/nimble/nimble/porting/nimble/include \ -isystem esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/include \ -isystem esp-idf/components/bt/host/nimble/port/include \ - -isystem esp-idf/components/driver/touch_sensor/include \ - -isystem esp-idf/components/driver/touch_sensor/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_driver_touch_sens/include \ -isystem esp-idf/components/driver/twai/include \ + -isystem esp-idf/components/driver/i2c/include \ -isystem esp-idf/components/efuse/include \ -isystem esp-idf/components/efuse/$(IDF_TARGET)/include \ - -isystem esp-idf/components/$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_adc/include \ -isystem esp-idf/components/esp_adc/$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_app_format/include \ -isystem esp-idf/components/esp_bootloader_format/include \ -isystem esp-idf/components/esp_common/include \ - -isystem esp-idf/components/esp_driver_deprecated \ -isystem esp-idf/components/esp_driver_dac/include \ -isystem esp-idf/components/esp_driver_gpio/include \ -isystem esp-idf/components/esp_driver_gptimer/include \ -isystem esp-idf/components/esp_driver_i2c/include \ -isystem esp-idf/components/esp_driver_i2s/include \ - -isystem esp-idf/components/esp_driver_$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_driver_ledc/include \ -isystem esp-idf/components/esp_driver_parlio/include \ -isystem esp-idf/components/esp_driver_pcnt/include \ -isystem esp-idf/components/esp_driver_rmt/include \ -isystem esp-idf/components/esp_driver_sdio/include \ -isystem esp-idf/components/esp_driver_sdmmc/include \ + -isystem esp-idf/components/esp_driver_sdmmc/legacy/include \ + -isystem esp-idf/components/esp_driver_dma/include \ -isystem esp-idf/components/esp_driver_spi/include \ -isystem esp-idf/components/esp_driver_tsens/include \ -isystem esp-idf/components/esp_driver_uart/include \ -isystem esp-idf/components/esp_event/include \ - -isystem esp-idf/components/esp_hw_support/dma/include \ - -isystem esp-idf/components/esp_hw_support/ldo/include \ -isystem esp-idf/components/esp_hw_support/include \ -isystem esp-idf/components/esp_hw_support/include/soc \ -isystem esp-idf/components/esp_hw_support/port/$(IDF_TARGET)/private_include \ + -isystem esp-idf/components/esp_hw_support/etm/include \ -isystem esp-idf/components/esp_mm/include \ -isystem esp-idf/components/esp_netif/include \ + -isystem esp-idf/components/esp_blockdev/include \ -isystem esp-idf/components/esp_partition/include \ -isystem esp-idf/components/esp_pm/include \ -isystem esp-idf/components/esp_psram/include \ @@ -106,6 +105,36 @@ INC += \ -isystem esp-idf/components/hal/include \ -isystem esp-idf/components/hal/$(IDF_TARGET)/include \ -isystem esp-idf/components/hal/platform_port/include \ + -isystem esp-idf/components/esp_hal_gpio/include \ + -isystem esp-idf/components/esp_hal_gpio/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_timg/include \ + -isystem esp-idf/components/esp_hal_ana_conv/include \ + -isystem esp-idf/components/esp_hal_touch_sens/include \ + -isystem esp-idf/components/esp_hal_uart/include \ + -isystem esp-idf/components/esp_hal_gpspi/include \ + -isystem esp-idf/components/esp_hal_i2c/include \ + -isystem esp-idf/components/esp_hal_i2s/include \ + -isystem esp-idf/components/esp_hal_i2s/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_ledc/include \ + -isystem esp-idf/components/esp_hal_pcnt/include \ + -isystem esp-idf/components/esp_hal_rmt/include \ + -isystem esp-idf/components/esp_hal_rmt/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_twai/include \ + -isystem esp-idf/components/esp_hal_twai/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_timg/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_gpspi/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_dma/include \ + -isystem esp-idf/components/esp_hal_dma/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_lcd/include \ + -isystem esp-idf/components/esp_hal_lcd/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_usb/include \ + -isystem esp-idf/components/esp_hal_usb/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_parlio/include \ + -isystem esp-idf/components/esp_hal_pmu/include \ + -isystem esp-idf/components/esp_hal_pmu/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_wdt/include \ + -isystem esp-idf/components/esp_hal_wdt/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_security/include \ -isystem esp-idf/components/heap/include \ -isystem esp-idf/components/log/include \ -isystem esp-idf/components/lwip/include \ @@ -115,23 +144,20 @@ INC += \ -isystem esp-idf/components/lwip/port/freertos/include \ -isystem esp-idf/components/mbedtls/esp_crt_bundle/include \ -isystem esp-idf/components/mbedtls/mbedtls/include \ + -isystem esp-idf/components/mbedtls/mbedtls/tf-psa-crypto/include \ + -isystem esp-idf/components/mbedtls/mbedtls/tf-psa-crypto/drivers/builtin/include \ -isystem esp-idf/components/mbedtls/port/include \ - -isystem esp-idf/components/newlib/platform_include \ + -isystem esp-idf/components/mbedtls/port/psa_driver/include \ + -isystem esp-idf/components/esp_libc/platform_include \ -isystem esp-idf/components/nvs_flash/include \ - -isystem esp-idf/components/sdio/include \ -isystem esp-idf/components/sdmmc/include \ -isystem esp-idf/components/soc/include \ -isystem esp-idf/components/soc/$(IDF_TARGET)/include \ -isystem esp-idf/components/soc/$(IDF_TARGET)/register \ - -isystem esp-idf/components/soc/$(IDF_TARGET)/register/hw_ver3 \ - -isystem esp-idf/components/soc/$(IDF_TARGET)/register/hw_ver2 \ - -isystem esp-idf/components/soc/$(IDF_TARGET)/register/hw_ver1 \ -isystem esp-idf/components/spi_flash/include \ - -isystem esp-idf/components/usb/include \ -isystem esp-idf/components/ulp/ulp_fsm/include \ -isystem esp-idf/components/ulp/ulp_riscv/include \ -isystem esp-idf/components/ulp/ulp_common/include \ - -isystem esp-idf/components/ulp/ulp_common/include/$(IDF_TARGET) \ -isystem esp-idf/components/$(IDF_TARGET_ARCH)/include \ -isystem esp-idf/components/$(IDF_TARGET_ARCH)/$(IDF_TARGET)/include \ -isystem esp-protocols/components/mdns/include @@ -140,6 +166,7 @@ CFLAGS += \ -DHAVE_CONFIG_H \ -DESP_PLATFORM=1 \ -DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\" \ + -DMBEDTLS_DECLARE_PRIVATE_IDENTIFIERS \ -DMBEDTLS_PADLOCK_FILE=\"ports/espressif/esp-idf/components/mbedtls/mbedtls/library/padlock.h\" \ -DUNITY_INCLUDE_CONFIG_H -DWITH_POSIX \ -DMP3DEC_GENERIC @@ -176,7 +203,15 @@ REGISTRATION_FUNCTIONS = \ -u include_esp_phy_override \ -u vfs_include_syscalls_impl \ -u esp_vfs_include_nullfs_register \ - -u usb_serial_jtag_vfs_include_dev_init + -u usb_serial_jtag_vfs_include_dev_init \ + -u esp_flash_spi_init_include_func \ + -u pthread_include_pthread_impl \ + -u pthread_include_pthread_cond_var_impl \ + -u pthread_include_pthread_local_storage_impl \ + -u pthread_include_pthread_rwlock_impl \ + -u pthread_include_pthread_semaphore_impl \ + -u esp_security_init_include_impl \ + -u mbedtls_psa_crypto_init_include_impl #Debugging/Optimization @@ -205,20 +240,20 @@ endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk CFLAGS += $(OPTIMIZATION_FLAGS) -CFLAGS += $(INC) -Werror -Wall -std=gnu11 -Wl,--gc-sections $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition +CFLAGS += $(INC) -Werror -Wall -std=gnu11 -Wl,--gc-sections $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition -Wno-error=cpp -Wno-cpp -# Most current ESPs have nano versions of newlib in ROM so we use them. -ifneq ($(IDF_TARGET),esp32c6) - CFLAGS += --specs=nano.specs -else - LDFLAGS += -T$(IDF_TARGET).rom.newlib-normal.ld -endif +# ESP-IDF v6.0 uses picolibc instead of newlib. +CFLAGS += --specs=picolibc.specs ifeq ($(IDF_TARGET_ARCH),xtensa) # Remove the last two flags once TinyUSB is updated with the `#include ` instead of # `#include "xtensa/xtensa_api.h"`. - CFLAGS += -mlongcalls -isystem esp-idf/components/xtensa/deprecated_include/ -Wno-error=cpp + CFLAGS += -mlongcalls -fno-builtin-memcpy -fno-builtin-memset -fno-builtin-bzero + CFLAGS += -isystem esp-idf/components/xtensa/deprecated_include/ +ifeq ($(IDF_TARGET),esp32) + CFLAGS += -Wno-frame-address +endif CFLAGS += -DMICROPY_GCREGS_SETJMP=1 # Wrap longjmp with a patched version that protects register window update with a critical section @@ -228,9 +263,11 @@ ifeq ($(IDF_TARGET_ARCH),xtensa) else ifeq ($(IDF_TARGET_ARCH),riscv) ifeq ($(IDF_TARGET),esp32p4) - CFLAGS += -march=rv32imafc_zicsr_zifencei_xesppie -mabi=ilp32f + CFLAGS += -march=rv32imafc_zicsr_zifencei_zaamo_zalrsc -mabi=ilp32f + else ifeq ($(IDF_TARGET),$(filter $(IDF_TARGET),esp32c2 esp32c3)) + CFLAGS += -march=rv32imc_zicsr_zifencei else - CFLAGS += -march=rv32imac_zicsr_zifencei + CFLAGS += -march=rv32imac_zicsr_zifencei_zaamo_zalrsc endif LDFLAGS += \ @@ -242,12 +279,13 @@ else ifeq ($(IDF_TARGET_ARCH),riscv) endif -LDFLAGS += $(CFLAGS) -Wl,-nostdlib -Wl,-Map=$@.map -Wl,-cref -Wl,--undefined=uxTopUsedPriority +LDFLAGS += $(CFLAGS) -nostartfiles -Wl,-nostdlib -Wl,-Map=$@.map -Wl,-cref -Wl,--undefined=uxTopUsedPriority LDFLAGS += \ -L$(BUILD)/esp-idf/esp-idf/esp_system/ld \ -Lesp-idf/components/esp_rom/$(IDF_TARGET)/ld \ -Lesp-idf/components/soc/$(IDF_TARGET)/ld \ + -Lesp-idf/components/esp_hal_wdt/$(IDF_TARGET) \ -Tmemory.ld \ -Tsections.ld \ -T$(IDF_TARGET).peripherals.ld \ @@ -261,34 +299,39 @@ LDFLAGS += \ ifeq ($(IDF_TARGET),esp32) LDFLAGS += \ - -Tesp32.rom.newlib-data.ld \ - -Tesp32.rom.syscalls.ld \ - -Tesp32.rom.libc-funcs.ld \ - -Tesp32.rom.newlib-reent-funcs.ld \ - -Tesp32.rom.spiflash_legacy.ld + -Tesp32.rom.libc-funcs.ld + +CFLAGS += -isystem esp-idf/components/esp_driver_touch_sens/hw_ver1/include CHIP_COMPONENTS = \ - esp_driver_dac + esp_driver_dac \ + esp_driver_touch_sens \ + esp_hal_i2s \ + esp_hal_lcd \ + esp_hal_pcnt \ + esp_hal_rmt \ + esp_hal_touch_sens \ + esp_hal_twai else ifeq ($(IDF_TARGET),esp32c2) LDFLAGS += \ -Tesp32c2.rom.ble.ld \ -Tesp32c2.rom.heap.ld \ -Tesp32c2.rom.libc.ld \ - -Tesp32c2.rom.newlib.ld \ - -Tesp32c2.rom.newlib-nano.ld \ -Tesp32c2.rom.version.ld \ -Tesp32c2.rom.systimer.ld \ - -Tesp32c2.rom.wdt.ld + -Trom.wdt.ld CFLAGS += -DSOC_XTAL_FREQ_MHZ=CONFIG_XTAL_FREQ CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_hal_dma \ + esp_hal_pmu else ifeq ($(IDF_TARGET),esp32c3) +# esp32c2 has none of: esp_hal_i2s esp_hal_lcd esp_hal_pcnt esp_hal_touch_sens esp_hal_twai LDFLAGS += \ - -Tesp32c3.rom.newlib.ld \ -Tesp32c3.rom.libc.ld \ -Tesp32c3.rom.version.ld \ -Tesp32c3.rom.eco3_bt_funcs.ld \ @@ -296,7 +339,14 @@ LDFLAGS += \ -Tesp32c3.rom.bt_funcs.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32c6) LDFLAGS += \ @@ -304,15 +354,22 @@ LDFLAGS += \ -Tesp32c6.rom.pp.ld \ -Tesp32c6.rom.net80211.ld \ -Tesp32c6.rom.libc.ld \ - -Tesp32c6.rom.newlib.ld \ -Tesp32c6.rom.coexist.ld \ -Tesp32c6.rom.heap.ld \ -Tesp32c6.rom.systimer.ld \ - -Tesp32c6.rom.wdt.ld + -Trom.wdt.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32c61) LDFLAGS += \ @@ -320,62 +377,113 @@ LDFLAGS += \ -Tesp32c61.rom.pp.ld \ -Tesp32c61.rom.net80211.ld \ -Tesp32c61.rom.libc.ld \ - -Tesp32c61.rom.newlib.ld \ -Tesp32c61.rom.version.ld \ -Tesp32c61.rom.coexist.ld \ -Tesp32c61.rom.heap.ld \ -Tesp32c61.rom.systimer.ld \ - -Tesp32c61.rom.wdt.ld + -Trom.wdt.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pmu \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32p4) +CFLAGS += \ + -isystem esp-idf/components/soc/esp32p4/register/hw_ver3 \ + -isystem esp-idf/components/soc/esp32p4/register/hw_ver1 \ + -isystem esp-idf/components/esp_hw_support/ldo/include \ + -isystem esp-idf/components/esp_driver_touch_sens/hw_ver3/include + LDFLAGS += \ -Tesp32p4.rom.libc.ld \ - -Tesp32p4.rom.newlib.ld \ -Tesp32p4.rom.systimer.ld \ - -Tesp32p4.rom.wdt.ld + -Tesp32p4.rom.eco5.ld \ + -Tesp32p4.rom.eco5.libc.ld \ + -Tesp32p4.rom.eco5.rvfp.ld \ + -Tesp32p4.rom.version.ld \ + -Trom.wdt.ld CHIP_COMPONENTS = \ + esp_driver_touch_sens \ esp_driver_tsens \ - esp_driver_usb_serial_jtag + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_lcd \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_touch_sens \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32h2) LDFLAGS += \ -Tesp32h2.rom.heap.ld \ -Tesp32h2.rom.libc.ld \ - -Tesp32h2.rom.newlib.ld \ -Tesp32h2.rom.systimer.ld \ - -Tesp32h2.rom.wdt.ld + -Trom.wdt.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32s2) +CFLAGS += -isystem esp-idf/components/esp_driver_touch_sens/hw_ver2/include + LDFLAGS += \ -Tesp32s2.rom.libc-funcs.ld \ - -Tesp32s2.rom.newlib-data.ld \ - -Tesp32s2.rom.newlib-reent-funcs.ld \ -Tesp32s2.rom.spiflash_legacy.ld CHIP_COMPONENTS = \ esp_driver_dac \ - esp_driver_tsens + esp_driver_touch_sens \ + esp_driver_tsens \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_lcd \ + esp_hal_pcnt \ + esp_hal_rmt \ + esp_hal_touch_sens \ + esp_hal_twai \ + esp_hal_usb else ifeq ($(IDF_TARGET),esp32s3) +CFLAGS += -isystem esp-idf/components/esp_driver_touch_sens/hw_ver2/include + LDFLAGS += \ -Tesp32s3.rom.libc.ld \ - -Tesp32s3.rom.newlib.ld \ -Tesp32s3.rom.version.ld \ -Tesp32s3.rom.systimer.ld \ - -Tesp32s3.rom.wdt.ld \ - -Tesp32s3.rom.bt_funcs.ld + -Tesp32s3.rom.bt_funcs.ld \ + -Trom.wdt.ld CHIP_COMPONENTS = \ - esp_driver_tsens + esp_driver_touch_sens \ + esp_driver_tsens \ + esp_driver_usb_serial_jtag \ + esp_hal_dma \ + esp_hal_i2s \ + esp_hal_lcd \ + esp_hal_pcnt \ + esp_hal_pmu \ + esp_hal_rmt \ + esp_hal_touch_sens \ + esp_hal_twai \ + esp_hal_usb endif @@ -678,7 +786,7 @@ do-sdkconfig: $(BUILD)/esp-idf/config/sdkconfig.h QSTR_GLOBAL_REQUIREMENTS += $(BUILD)/esp-idf/config/sdkconfig.h $(BUILD)/esp-idf/config/sdkconfig.h: boards/$(BOARD)/sdkconfig boards/$(BOARD)/mpconfigboard.mk CMakeLists.txt | $(BUILD)/esp-idf $(STEPECHO) "LINK $@" - $(Q)env IDF_PATH=$(IDF_PATH) cmake -S . -B $(BUILD)/esp-idf -DSDKCONFIG=$(BUILD)/esp-idf/sdkconfig -DSDKCONFIG_DEFAULTS="$(SDKCONFIGS)" -DCMAKE_TOOLCHAIN_FILE=$(IDF_PATH)/tools/cmake/toolchain-$(IDF_TARGET).cmake -DIDF_TARGET=$(IDF_TARGET) -GNinja + $(Q)env IDF_PATH=$(IDF_PATH) IDF_COMPONENT_MANAGER=0 cmake -S . -B $(BUILD)/esp-idf -DSDKCONFIG=$(BUILD)/esp-idf/sdkconfig -DSDKCONFIG_DEFAULTS="$(SDKCONFIGS)" -DCMAKE_TOOLCHAIN_FILE=$(IDF_PATH)/tools/cmake/toolchain-$(IDF_TARGET).cmake -DIDF_TARGET=$(IDF_TARGET) -GNinja $(Q)$(PYTHON) tools/check-sdkconfig.py \ CIRCUITPY_DUALBANK=$(CIRCUITPY_DUALBANK) \ CIRCUITPY_STORAGE_EXTEND=$(CIRCUITPY_STORAGE_EXTEND) \ @@ -726,7 +834,7 @@ ifeq ($(IDF_TARGET),esp32) BINARY_BLOBS += esp-idf/components/esp_phy/lib/$(IDF_TARGET)/librtc.a endif -ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log newlib nvs_flash pthread soc spi_flash vfs esp_vfs_console +ESP_IDF_COMPONENTS_LINK = $(IDF_TARGET_ARCH) $(CHIP_COMPONENTS) app_update bootloader_support driver esp_driver_dma esp_driver_gpio esp_driver_gptimer esp_driver_i2c esp_driver_ledc esp_driver_spi esp_driver_uart efuse esp_adc esp_app_format esp_common esp_event esp_gdbstub esp_hal_ana_conv esp_hal_clock esp_hal_gpio esp_hal_gpspi esp_hal_i2c esp_hal_ledc esp_hal_mspi esp_hal_security esp_hal_timg esp_hal_uart esp_hal_wdt esp_hw_support esp_mm esp_partition esp_pm esp_ringbuf esp_rom esp_system esp_timer freertos hal heap log esp_libc nvs_flash nvs_sec_provider pthread soc spi_flash vfs esp_stdio ifneq ($(CIRCUITPY_WIFI),0) ESP_IDF_COMPONENTS_LINK += esp_coex esp_netif esp_security esp-tls esp_wifi lwip mbedtls mdns wpa_supplicant esp_phy endif @@ -783,17 +891,18 @@ endif ifneq ($(CIRCUITPY_QSPIBUS),0) ESP_IDF_COMPONENTS_LINK += esp_lcd endif -ifneq ($(CIRCUITPY_USB_DEVICE),0) - ESP_IDF_COMPONENTS_LINK += usb -endif ifneq ($(CIRCUITPY_SDIOIO),0) - ESP_IDF_COMPONENTS_LINK += sdmmc esp_driver_sdmmc + ESP_IDF_COMPONENTS_LINK += sdmmc esp_driver_sdmmc esp_driver_sd_intf endif ESP_IDF_COMPONENTS_EXPANDED = $(foreach component, $(ESP_IDF_COMPONENTS_LINK), $(BUILD)/esp-idf/esp-idf/$(component)/lib$(component).a) MBEDTLS_COMPONENTS_LINK = crypto tls x509 MBEDTLS_COMPONENTS_LINK_EXPANDED = $(foreach component, $(MBEDTLS_COMPONENTS_LINK), $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/library/libmbed$(component).a) +MBEDTLS_COMPONENTS_LINK_EXPANDED += $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/library/libtfpsacrypto.a +MBEDTLS_COMPONENTS_LINK_EXPANDED += $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/tf-psa-crypto/drivers/builtin/libmbed-builtin.a +MBEDTLS_COMPONENTS_LINK_EXPANDED += $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/tf-psa-crypto/drivers/everest/libeverest.a +MBEDTLS_COMPONENTS_LINK_EXPANDED += $(BUILD)/esp-idf/esp-idf/mbedtls/mbedtls/tf-psa-crypto/drivers/p256-m/libp256m.a ifeq ($(IDF_TARGET_ARCH),xtensa) BINARY_BLOBS += esp-idf/components/xtensa/$(IDF_TARGET)/libxt_hal.a @@ -870,9 +979,9 @@ else ESPTOOLPY_FLASHFREQ = $(CIRCUITPY_ESP_FLASH_FREQ) endif -FLASH_FLAGS = --flash_mode $(ESPTOOLPY_FLASHMODE) --flash_freq $(ESPTOOLPY_FLASHFREQ) --flash_size $(CIRCUITPY_ESP_FLASH_SIZE) +FLASH_FLAGS = --flash-mode $(ESPTOOLPY_FLASHMODE) --flash-freq $(ESPTOOLPY_FLASHFREQ) --flash-size $(CIRCUITPY_ESP_FLASH_SIZE) -ESPTOOL_FLAGS ?= --before=default_reset --after=no_reset --baud 921600 +ESPTOOL_FLAGS ?= --before=default-reset --after=no-reset --baud 921600 ifeq ($(UF2_BOOTLOADER),1) all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 @@ -892,7 +1001,7 @@ $(BUILD)/firmware.elf: $(OBJ) | esp-idf-stamp $(IDF_CMAKE_TARGETS) $(BUILD)/circuitpython-firmware.bin: $(BUILD)/firmware.elf | tools/build_memory_info.py $(STEPECHO) "Create $@" - $(Q)esptool.py --chip $(IDF_TARGET) elf2image $(FLASH_FLAGS) --elf-sha256-offset 0xb0 -o $@ $^ + $(Q)esptool --chip $(IDF_TARGET) elf2image $(FLASH_FLAGS) --elf-sha256-offset 0xb0 -o $@ $^ $(Q)$(PYTHON) tools/build_memory_info.py $< $(BUILD)/esp-idf/sdkconfig $@ $(BUILD) ifeq ($(VALID_BOARD),) @@ -911,10 +1020,10 @@ $(BUILD)/firmware.uf2: $(BUILD)/circuitpython-firmware.bin $(Q)$(PYTHON) $(TOP)/tools/uf2/utils/uf2conv.py -f $(UF2_FAMILY_ID_$(IDF_TARGET)) -b 0x0000 -c -o $@ $^ flash: $(BUILD)/firmware.bin - esptool.py --chip $(IDF_TARGET) -p $(PORT) $(ESPTOOL_FLAGS) write_flash $(FLASH_FLAGS) 0x0000 $^ + esptool --chip $(IDF_TARGET) -p $(PORT) $(ESPTOOL_FLAGS) write-flash $(FLASH_FLAGS) 0x0000 $^ flash-circuitpython-only: $(BUILD)/circuitpython-firmware.bin - esptool.py --chip $(IDF_TARGET) -p $(PORT) $(ESPTOOL_FLAGS) write_flash $(FLASH_FLAGS) $(FIRMWARE_OFFSET) $^ + esptool --chip $(IDF_TARGET) -p $(PORT) $(ESPTOOL_FLAGS) write-flash $(FLASH_FLAGS) $(FIRMWARE_OFFSET) $^ monitor: $(BUILD)/firmware.elf cp $< build/circuitpython.elf diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index 1437f75165d..641bb18ceed 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -7,6 +7,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" #include "shared-bindings/microcontroller/Pin.h" diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk index da3e6a14496..e51bdc7d8cc 100644 --- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk +++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/mpconfigboard.mk @@ -9,7 +9,12 @@ CIRCUITPY_ESP_FLASH_SIZE = 2MB CIRCUITPY_DUALBANK = 0 -CIRCUITPY_JPEGIO = 0 +CIRCUITPY_AESIO = 0 CIRCUITPY_CANIO = 0 +CIRCUITPY_GETPASS = 0 +CIRCUITPY_JPEGIO = 0 +CIRCUITPY_MSGPACK = 0 +CIRCUITPY_PS2IO = 0 +CIRCUITPY_ZLIB = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk index 336b9f4dd89..b6ae3cf73b4 100644 --- a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n8r2_ros/mpconfigboard.mk @@ -13,4 +13,4 @@ CIRCUITPY_ESP_PSRAM_SIZE = 2MB CIRCUITPY_ESP_PSRAM_MODE = qio CIRCUITPY_ESP_PSRAM_FREQ = 80m -CIRCUITPY_RCLCPY = 1 +CIRCUITPY_RCLCPY = 0 diff --git a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c index 3b5aa06b676..96513a14741 100644 --- a/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c +++ b/ports/espressif/boards/espressif_esp32s3_usb_otg_n8/board.c @@ -7,6 +7,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" #include "shared-bindings/microcontroller/Pin.h" +#include "driver/gpio.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" diff --git a/ports/espressif/boards/hardkernel_odroid_go/board.c b/ports/espressif/boards/hardkernel_odroid_go/board.c index 5a8b6ccaefe..a519d0cc8a9 100644 --- a/ports/espressif/boards/hardkernel_odroid_go/board.c +++ b/ports/espressif/boards/hardkernel_odroid_go/board.c @@ -6,6 +6,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" #include "shared-module/displayio/__init__.h" diff --git a/ports/espressif/boards/lilygo_tdisplay_s3/board.c b/ports/espressif/boards/lilygo_tdisplay_s3/board.c index fe62edf1ed8..a02dab7173d 100644 --- a/ports/espressif/boards/lilygo_tdisplay_s3/board.c +++ b/ports/espressif/boards/lilygo_tdisplay_s3/board.c @@ -6,6 +6,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/displayio/__init__.h" #include "shared-module/displayio/mipi_constants.h" diff --git a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk index ede48c2f015..98d2ad502dd 100644 --- a/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk +++ b/ports/espressif/boards/m5stack_cardputer_ros/mpconfigboard.mk @@ -9,7 +9,7 @@ CIRCUITPY_ESP_FLASH_MODE = qio CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_FLASH_SIZE = 8MB -CIRCUITPY_RCLCPY = 1 +CIRCUITPY_RCLCPY = 0 # Very few pins. CIRCUITPY_ESPCAMERA = 0 diff --git a/ports/espressif/boards/sunton_esp32_8048S050/board.c b/ports/espressif/boards/sunton_esp32_8048S050/board.c index a6f573a86e7..b1794529ff0 100644 --- a/ports/espressif/boards/sunton_esp32_8048S050/board.c +++ b/ports/espressif/boards/sunton_esp32_8048S050/board.c @@ -7,6 +7,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/dotclockframebuffer/DotClockFramebuffer.h" #include "shared-bindings/dotclockframebuffer/__init__.h" diff --git a/ports/espressif/boards/sunton_esp32_8048S070/board.c b/ports/espressif/boards/sunton_esp32_8048S070/board.c index ecc9b7c1236..3d6a9c81e6d 100644 --- a/ports/espressif/boards/sunton_esp32_8048S070/board.c +++ b/ports/espressif/boards/sunton_esp32_8048S070/board.c @@ -6,6 +6,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/board/__init__.h" #include "shared-bindings/dotclockframebuffer/DotClockFramebuffer.h" #include "shared-bindings/dotclockframebuffer/__init__.h" diff --git a/ports/espressif/boards/vidi_x/board.c b/ports/espressif/boards/vidi_x/board.c index 7ba7094b917..cd4d06a6053 100644 --- a/ports/espressif/boards/vidi_x/board.c +++ b/ports/espressif/boards/vidi_x/board.c @@ -6,6 +6,7 @@ #include "supervisor/board.h" #include "mpconfigboard.h" +#include "driver/gpio.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" #include "shared-module/displayio/__init__.h" diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index aca3f8c2042..bbf7b7e0e2f 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -61,7 +61,7 @@ static void nimble_host_task(void *param) { static void _on_sync(void) { - int rc = ble_hs_util_ensure_addr(false); + int rc __attribute__((unused)) = ble_hs_util_ensure_addr(false); assert(rc == 0); _nimble_sync = true; diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 8c88bfe3ec5..42816cffb6f 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -65,7 +65,7 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in) case BLE_GAP_EVENT_CONN_UPDATE: { struct ble_gap_conn_desc desc; - int rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc); + int rc __attribute__((unused)) = ble_gap_conn_find(event->conn_update.conn_handle, &desc); assert(rc == 0); connection->conn_params_updating = false; break; diff --git a/ports/espressif/common-hal/alarm/SleepMemory.c b/ports/espressif/common-hal/alarm/SleepMemory.c index 938772e53ca..7e7368f77d0 100644 --- a/ports/espressif/common-hal/alarm/SleepMemory.c +++ b/ports/espressif/common-hal/alarm/SleepMemory.c @@ -15,7 +15,12 @@ // Data storage for singleton instance of SleepMemory. // Might be RTC_SLOW_MEM or RTC_FAST_MEM, depending on setting of CONFIG_ESP32S2_RTCDATA_IN_FAST_MEM. +#if defined(CONFIG_SOC_RTC_FAST_MEM_SUPPORTED) || defined(CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED) static RTC_DATA_ATTR uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; +#else +// Chips without RTC memory can't persist SleepMemory across deep sleep. +static uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; +#endif void alarm_sleep_memory_reset(void) { // ESP-IDF build system takes care of doing esp_sleep_pd_config() or the equivalent with diff --git a/ports/espressif/common-hal/alarm/__init__.c b/ports/espressif/common-hal/alarm/__init__.c index 629f976039f..51f7b4f81a7 100644 --- a/ports/espressif/common-hal/alarm/__init__.c +++ b/ports/espressif/common-hal/alarm/__init__.c @@ -57,68 +57,61 @@ void alarm_reset(void) { esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_ALL); } -static esp_sleep_wakeup_cause_t _get_wakeup_cause(bool deep_sleep) { +static uint32_t _get_wakeup_causes(bool deep_sleep) { // First check if the modules remember what last woke up if (alarm_pin_pinalarm_woke_this_cycle()) { - return ESP_SLEEP_WAKEUP_GPIO; + return 1 << ESP_SLEEP_WAKEUP_GPIO; } if (alarm_time_timealarm_woke_this_cycle()) { - return ESP_SLEEP_WAKEUP_TIMER; + return 1 << ESP_SLEEP_WAKEUP_TIMER; } #if CIRCUITPY_ALARM_TOUCH if (alarm_touch_touchalarm_woke_this_cycle()) { - return ESP_SLEEP_WAKEUP_TOUCHPAD; + return 1 << ESP_SLEEP_WAKEUP_TOUCHPAD; } #endif #if CIRCUITPY_ESPULP if (espulp_ulpalarm_woke_this_cycle()) { - return ESP_SLEEP_WAKEUP_ULP; + return 1 << ESP_SLEEP_WAKEUP_ULP; } #endif // If waking from true deep sleep, modules will have lost their state, // so check the deep wakeup cause manually if (deep_sleep) { - return esp_sleep_get_wakeup_cause(); + return esp_sleep_get_wakeup_causes(); } - return ESP_SLEEP_WAKEUP_UNDEFINED; + return 0; } bool common_hal_alarm_woken_from_sleep(void) { - return _get_wakeup_cause(false) != ESP_SLEEP_WAKEUP_UNDEFINED; + return _get_wakeup_causes(false) != 0; } mp_obj_t common_hal_alarm_record_wake_alarm(void) { // If woken from deep sleep, create a copy alarm similar to what would have // been passed in originally. Otherwise, just return none - esp_sleep_wakeup_cause_t cause = _get_wakeup_cause(true); - switch (cause) { - case ESP_SLEEP_WAKEUP_TIMER: { - return alarm_time_timealarm_record_wake_alarm(); - } + uint32_t causes = _get_wakeup_causes(true); - case ESP_SLEEP_WAKEUP_GPIO: - case ESP_SLEEP_WAKEUP_EXT0: - case ESP_SLEEP_WAKEUP_EXT1: { - return alarm_pin_pinalarm_record_wake_alarm(); - } + if (causes & (1 << ESP_SLEEP_WAKEUP_TIMER)) { + return alarm_time_timealarm_record_wake_alarm(); + } - #if CIRCUITPY_ALARM_TOUCH - case ESP_SLEEP_WAKEUP_TOUCHPAD: { - return alarm_touch_touchalarm_record_wake_alarm(); - } - #endif + if (causes & ((1 << ESP_SLEEP_WAKEUP_GPIO) | (1 << ESP_SLEEP_WAKEUP_EXT0) | (1 << ESP_SLEEP_WAKEUP_EXT1))) { + return alarm_pin_pinalarm_record_wake_alarm(); + } - #if CIRCUITPY_ESPULP - case ESP_SLEEP_WAKEUP_ULP: { - return espulp_ulpalarm_record_wake_alarm(); - } - #endif + #if CIRCUITPY_ALARM_TOUCH + if (causes & (1 << ESP_SLEEP_WAKEUP_TOUCHPAD)) { + return alarm_touch_touchalarm_record_wake_alarm(); + } + #endif - case ESP_SLEEP_WAKEUP_UNDEFINED: - default: - // Not a deep sleep reset. - break; + #if CIRCUITPY_ESPULP + if (causes & (1 << ESP_SLEEP_WAKEUP_ULP)) { + return espulp_ulpalarm_record_wake_alarm(); } + #endif + return mp_const_none; } @@ -144,32 +137,22 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj RUN_BACKGROUND_TASKS; // Detect if interrupt was alarm or ctrl-C interrupt. if (common_hal_alarm_woken_from_sleep()) { - esp_sleep_wakeup_cause_t cause = _get_wakeup_cause(false); - switch (cause) { - case ESP_SLEEP_WAKEUP_TIMER: { - wake_alarm = alarm_time_timealarm_find_triggered_alarm(n_alarms, alarms); - break; - } - case ESP_SLEEP_WAKEUP_GPIO: { - wake_alarm = alarm_pin_pinalarm_find_triggered_alarm(n_alarms, alarms); - break; - } - #if CIRCUITPY_ALARM_TOUCH - case ESP_SLEEP_WAKEUP_TOUCHPAD: { - wake_alarm = alarm_touch_touchalarm_find_triggered_alarm(n_alarms, alarms); - break; - } - #endif - #if CIRCUITPY_ESPULP - case ESP_SLEEP_WAKEUP_ULP: { - wake_alarm = espulp_ulpalarm_find_triggered_alarm(n_alarms, alarms); - break; - } - #endif - default: - // Should not reach this, if all light sleep types are covered correctly - break; + uint32_t causes = _get_wakeup_causes(false); + if (causes & (1 << ESP_SLEEP_WAKEUP_TIMER)) { + wake_alarm = alarm_time_timealarm_find_triggered_alarm(n_alarms, alarms); + } else if (causes & (1 << ESP_SLEEP_WAKEUP_GPIO)) { + wake_alarm = alarm_pin_pinalarm_find_triggered_alarm(n_alarms, alarms); + } + #if CIRCUITPY_ALARM_TOUCH + else if (causes & (1 << ESP_SLEEP_WAKEUP_TOUCHPAD)) { + wake_alarm = alarm_touch_touchalarm_find_triggered_alarm(n_alarms, alarms); + } + #endif + #if CIRCUITPY_ESPULP + else if (causes & (1 << ESP_SLEEP_WAKEUP_ULP)) { + wake_alarm = espulp_ulpalarm_find_triggered_alarm(n_alarms, alarms); } + #endif shared_alarm_save_wake_alarm(wake_alarm); break; } diff --git a/ports/espressif/common-hal/alarm/pin/PinAlarm.c b/ports/espressif/common-hal/alarm/pin/PinAlarm.c index 97ad3b2a942..3301612356b 100644 --- a/ports/espressif/common-hal/alarm/pin/PinAlarm.c +++ b/ports/espressif/common-hal/alarm/pin/PinAlarm.c @@ -102,14 +102,14 @@ mp_obj_t alarm_pin_pinalarm_find_triggered_alarm(size_t n_alarms, const mp_obj_t } mp_obj_t alarm_pin_pinalarm_record_wake_alarm(void) { - esp_sleep_wakeup_cause_t cause = esp_sleep_get_wakeup_cause(); + uint32_t causes = esp_sleep_get_wakeup_causes(); // Pin status will persist into a fake deep sleep uint64_t pin_status = ((uint64_t)pin_63_32_status) << 32 | pin_31_0_status; size_t pin_number = 64; #ifdef SOC_PM_SUPPORT_EXT0_WAKEUP - if (cause == ESP_SLEEP_WAKEUP_EXT0) { + if (causes & (1 << ESP_SLEEP_WAKEUP_EXT0)) { int rtc_io_pin_number = REG_GET_FIELD(RTC_IO_EXT_WAKEUP0_REG, RTC_IO_EXT_WAKEUP0_SEL); // Look up the GPIO equivalent pin for this RTC GPIO pin. On ESP32, the numbering // is different for RTC_GPIO and regular GPIO, and there's no mapping table. @@ -124,12 +124,12 @@ mp_obj_t alarm_pin_pinalarm_record_wake_alarm(void) { } else { #endif #ifdef SOC_PM_SUPPORT_EXT1_WAKEUP - if (cause == ESP_SLEEP_WAKEUP_EXT1) { + if (causes & (1 << ESP_SLEEP_WAKEUP_EXT1)) { pin_status = esp_sleep_get_ext1_wakeup_status(); } #endif #ifdef SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP - if (cause == ESP_SLEEP_WAKEUP_GPIO) { + if (causes & (1 << ESP_SLEEP_WAKEUP_GPIO)) { pin_status = esp_sleep_get_gpio_wakeup_status(); } #endif @@ -307,11 +307,11 @@ static esp_err_t _setup_deep_sleep(size_t low_count, size_t high_count) { return _setup_ext1(low_count, high_count); } #endif - esp_err_t result = esp_deep_sleep_enable_gpio_wakeup(low_alarms, ESP_GPIO_WAKEUP_GPIO_LOW); + esp_err_t result = esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(low_alarms, ESP_GPIO_WAKEUP_GPIO_LOW); if (result != ESP_OK) { return result; } - result = esp_deep_sleep_enable_gpio_wakeup(high_alarms, ESP_GPIO_WAKEUP_GPIO_HIGH); + result = esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown(high_alarms, ESP_GPIO_WAKEUP_GPIO_HIGH); return result; } #else diff --git a/ports/espressif/common-hal/alarm/touch/TouchAlarm.c b/ports/espressif/common-hal/alarm/touch/TouchAlarm.c index 5791a980d54..617f7632e63 100644 --- a/ports/espressif/common-hal/alarm/touch/TouchAlarm.c +++ b/ports/espressif/common-hal/alarm/touch/TouchAlarm.c @@ -17,7 +17,7 @@ static uint16_t touch_channel_mask; static volatile bool woke_up = false; void common_hal_alarm_touch_touchalarm_construct(alarm_touch_touchalarm_obj_t *self, const mcu_pin_obj_t *pin) { - if (pin->touch_channel == TOUCH_PAD_MAX) { + if (pin->touch_channel == NO_TOUCH_CHANNEL) { raise_ValueError_invalid_pin(); } claim_pin(pin); @@ -40,35 +40,28 @@ mp_obj_t alarm_touch_touchalarm_record_wake_alarm(void) { alarm->base.type = &alarm_touch_touchalarm_type; alarm->pin = NULL; - #if defined(CONFIG_IDF_TARGET_ESP32) - touch_pad_t wake_channel; - if (touch_pad_get_wakeup_status(&wake_channel) != ESP_OK) { - return alarm; - } - #else - touch_pad_t wake_channel = touch_pad_get_current_meas_channel(); - if (wake_channel == TOUCH_PAD_MAX) { - return alarm; - } - #endif - // Map the pin number back to a pin object. for (size_t i = 0; i < mcu_pin_globals.map.used; i++) { const mcu_pin_obj_t *pin_obj = MP_OBJ_TO_PTR(mcu_pin_globals.map.table[i].value); - if (pin_obj->touch_channel == wake_channel) { - alarm->pin = mcu_pin_globals.map.table[i].value; - break; + if (pin_obj->touch_channel != NO_TOUCH_CHANNEL) { + if ((touch_channel_mask & (1 << pin_obj->touch_channel)) != 0) { + alarm->pin = mcu_pin_globals.map.table[i].value; + break; + } } } return alarm; } -// This is used to wake the main CircuitPython task. -static void touch_interrupt(void *arg) { - (void)arg; +// This callback is used to wake the main CircuitPython task during light sleep. +static bool touch_active_callback(touch_sensor_handle_t sens_handle, const touch_active_event_data_t *event, void *user_ctx) { + (void)sens_handle; + (void)event; + (void)user_ctx; woke_up = true; port_wake_main_task_from_isr(); + return false; } void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alarms, const mp_obj_t *alarms) { @@ -81,7 +74,7 @@ void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alar mp_raise_ValueError_varg(MP_ERROR_TEXT("Only one %q can be set in deep sleep."), MP_QSTR_TouchAlarm); } touch_alarm = MP_OBJ_TO_PTR(alarms[i]); - touch_channel_mask |= 1 << touch_alarm->pin->number; + touch_channel_mask |= 1 << touch_alarm->pin->touch_channel; // Resetting the pin will set a pull-up, which we don't want. skip_reset_once_pin_number(touch_alarm->pin->number); touch_alarm_set = true; @@ -92,47 +85,69 @@ void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alar return; } - // configure interrupt for pretend to deep sleep - // this will be disabled if we actually deep sleep - - // reset touch peripheral + // Reset touch peripheral and keep it from being reset again peripherals_touch_reset(); peripherals_touch_never_reset(true); - for (uint8_t i = 1; i <= 14; i++) { - if ((touch_channel_mask & 1 << i) != 0) { - touch_pad_t touch_channel = (touch_pad_t)i; - // initialize touchpad - peripherals_touch_init(touch_channel); - - // wait for touch data to reset - mp_hal_delay_ms(10); - - // configure trigger threshold - #if defined(CONFIG_IDF_TARGET_ESP32) - uint16_t touch_value; - // ESP32 touch_pad_read() returns a lower value when a pin is touched, not a higher value - // Typical values on a Feather ESP32 V2 are 600 with a short jumper untouched, - // 70 touched. - touch_pad_read(touch_channel, &touch_value); - touch_pad_set_thresh(touch_channel, touch_value / 2); - #else - uint32_t touch_value; - touch_pad_read_benchmark(touch_channel, &touch_value); - touch_pad_set_thresh(touch_channel, touch_value / 10); // 10% - #endif + // Initialize all touch channels used for alarms + for (uint8_t i = TOUCH_MIN_CHAN_ID; i <= TOUCH_MAX_CHAN_ID; i++) { + if ((touch_channel_mask & (1 << i)) != 0) { + peripherals_touch_init(i); } } - // configure touch interrupt - #if defined(CONFIG_IDF_TARGET_ESP32) - touch_pad_isr_register(touch_interrupt, NULL); - touch_pad_intr_enable(); - #else - touch_pad_timeout_set(true, TOUCH_PAD_THRESHOLD_MAX); - touch_pad_isr_register(touch_interrupt, NULL, TOUCH_PAD_INTR_MASK_ALL); - touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE); - #endif + // Wait for touch data to stabilize + mp_hal_delay_ms(10); + + // Now stop scanning and disable so we can reconfigure thresholds + touch_sensor_handle_t controller = peripherals_touch_get_controller(); + touch_sensor_stop_continuous_scanning(controller); + touch_sensor_disable(controller); + + // Configure thresholds based on initial readings + for (uint8_t i = TOUCH_MIN_CHAN_ID; i <= TOUCH_MAX_CHAN_ID; i++) { + if ((touch_channel_mask & (1 << i)) == 0) { + continue; + } + touch_channel_handle_t chan = peripherals_touch_get_handle(i); + + uint32_t benchmark = 0; + #if defined(SOC_TOUCH_SUPPORT_BENCHMARK) && SOC_TOUCH_SUPPORT_BENCHMARK + touch_channel_read_data(chan, TOUCH_CHAN_DATA_TYPE_BENCHMARK, &benchmark); + #else + touch_channel_read_data(chan, TOUCH_CHAN_DATA_TYPE_SMOOTH, &benchmark); + #endif + + #if SOC_TOUCH_SENSOR_VERSION == 1 + touch_channel_config_t chan_cfg = { + .abs_active_thresh = {(uint32_t)(benchmark / 2)}, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, + .group = TOUCH_CHAN_TRIG_GROUP_BOTH, + }; + #else + touch_channel_config_t chan_cfg = { + .active_thresh = {(uint32_t)(benchmark / 10)}, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, + }; + #endif + touch_sensor_reconfig_channel(chan, &chan_cfg); + } + + // Set up filter for proper active/inactive detection + touch_sensor_filter_config_t filter_cfg = TOUCH_SENSOR_DEFAULT_FILTER_CONFIG(); + touch_sensor_config_filter(controller, &filter_cfg); + + // Register callback for light sleep wakeup + touch_event_callbacks_t callbacks = { + .on_active = touch_active_callback, + }; + touch_sensor_register_callbacks(controller, &callbacks, NULL); + + // Re-enable and start scanning + touch_sensor_enable(controller); + touch_sensor_start_continuous_scanning(controller); } void alarm_touch_touchalarm_prepare_for_deep_sleep(void) { @@ -140,45 +155,43 @@ void alarm_touch_touchalarm_prepare_for_deep_sleep(void) { return; } - touch_pad_t touch_channel = TOUCH_PAD_MAX; - for (uint8_t i = 1; i <= 14; i++) { - if ((touch_channel_mask & 1 << i) != 0) { - touch_channel = (touch_pad_t)i; + touch_sensor_handle_t controller = peripherals_touch_get_controller(); + + // Find the first alarm channel for deep sleep + int deep_slp_chan_id = -1; + for (uint8_t i = TOUCH_MIN_CHAN_ID; i <= TOUCH_MAX_CHAN_ID; i++) { + if ((touch_channel_mask & (1 << i)) != 0) { + deep_slp_chan_id = i; break; } } - // reset touch peripheral - peripherals_touch_never_reset(false); - peripherals_touch_reset(); - - // initialize touchpad - peripherals_touch_init(touch_channel); + if (deep_slp_chan_id < 0) { + return; + } - #if !defined(CONFIG_IDF_TARGET_ESP32) - // configure touchpad for sleep - touch_pad_sleep_channel_enable(touch_channel, true); - touch_pad_sleep_channel_enable_proximity(touch_channel, false); + // Stop scanning and disable to reconfigure for deep sleep + touch_sensor_stop_continuous_scanning(controller); + touch_sensor_disable(controller); + + #if SOC_TOUCH_SUPPORT_SLEEP_WAKEUP + touch_sleep_config_t sleep_cfg = { + .slp_wakeup_lvl = TOUCH_DEEP_SLEEP_WAKEUP, + #if SOC_TOUCH_SENSOR_VERSION == 1 + .deep_slp_sens_cfg = NULL, + #else + .deep_slp_allow_pd = false, + .deep_slp_chan = peripherals_touch_get_handle(deep_slp_chan_id), + .deep_slp_sens_cfg = NULL, + #endif + }; + touch_sensor_config_sleep_wakeup(controller, &sleep_cfg); #endif - // wait for touch data to reset - mp_hal_delay_ms(10); - - // configure trigger threshold - #if defined(CONFIG_IDF_TARGET_ESP32) - uint16_t touch_value; - touch_pad_read(touch_channel, &touch_value); - // ESP32 touch_pad_read() returns a lower value when a pin is touched, not a higher value - // Typical values on a Feather ESP32 V2 are 600 with a short jumper untouched, - // 70 touched. - touch_pad_set_thresh(touch_channel, touch_value / 2); - #else - uint32_t touch_value; - touch_pad_sleep_channel_read_smooth(touch_channel, &touch_value); - touch_pad_sleep_set_threshold(touch_channel, touch_value / 10); // 10% - #endif + // Re-enable for sleep + touch_sensor_enable(controller); + touch_sensor_start_continuous_scanning(controller); - // enable touchpad wakeup esp_sleep_enable_touchpad_wakeup(); esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON); } diff --git a/ports/espressif/common-hal/analogbufio/BufferedIn.c b/ports/espressif/common-hal/analogbufio/BufferedIn.c index 20c5c060574..747d7d53878 100644 --- a/ports/espressif/common-hal/analogbufio/BufferedIn.c +++ b/ports/espressif/common-hal/analogbufio/BufferedIn.c @@ -23,7 +23,7 @@ #define NUM_SAMPLES_PER_INTERRUPT 256 #define NUM_ADC_CHANNELS 1 #define DMA_BUFFER_SIZE 1024 -#define ATTENUATION ADC_ATTEN_DB_11 +#define ATTENUATION ADC_ATTEN_DB_12 #define ADC_READ_TIMEOUT_MS 2000 #define ADC_PIN_MAX_VALUE 0xfff diff --git a/ports/espressif/common-hal/analogio/AnalogIn.c b/ports/espressif/common-hal/analogio/AnalogIn.c index 34cd5b846cf..9809962b394 100644 --- a/ports/espressif/common-hal/analogio/AnalogIn.c +++ b/ports/espressif/common-hal/analogio/AnalogIn.c @@ -23,7 +23,7 @@ #define DEFAULT_VREF 1100 #define NO_OF_SAMPLES 2 -#define ATTENUATION ADC_ATTEN_DB_11 +#define ATTENUATION ADC_ATTEN_DB_12 #if defined(CONFIG_IDF_TARGET_ESP32) #define DATA_WIDTH ADC_BITWIDTH_12 #elif defined(CONFIG_IDF_TARGET_ESP32C2) diff --git a/ports/espressif/common-hal/analogio/AnalogIn.h b/ports/espressif/common-hal/analogio/AnalogIn.h index 944039bec2a..cd5f1b5d9ef 100644 --- a/ports/espressif/common-hal/analogio/AnalogIn.h +++ b/ports/espressif/common-hal/analogio/AnalogIn.h @@ -8,7 +8,7 @@ #include "common-hal/microcontroller/Pin.h" -#include "components/hal/include/hal/adc_types.h" +#include "hal/adc_types.h" #include "FreeRTOS.h" #include "freertos/semphr.h" #include "py/obj.h" diff --git a/ports/espressif/common-hal/audiobusio/__init__.c b/ports/espressif/common-hal/audiobusio/__init__.c index d07a0b521ba..2ae34d04960 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -108,7 +108,7 @@ static void i2s_callback_fun(void *self_in) { static bool i2s_event_interrupt(i2s_chan_handle_t handle, i2s_event_data_t *event, void *self_in) { i2s_t *self = self_in; self->underrun = self->underrun || self->next_buffer != NULL; - self->next_buffer = *(int16_t **)event->data; + self->next_buffer = *(int16_t **)event->dma_buf; self->next_buffer_size = event->size; background_callback_add(&self->callback, i2s_callback_fun, self_in); return false; diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 890f9339c22..662633c638b 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -9,7 +9,7 @@ #include "py/mphal.h" #include "py/runtime.h" -#include "components/driver/i2c/include/driver/i2c.h" +#include "driver/gpio.h" #include "bindings/espidf/__init__.h" #include "shared-bindings/microcontroller/__init__.h" diff --git a/ports/espressif/common-hal/busio/I2C.h b/ports/espressif/common-hal/busio/I2C.h index 25d9791f252..52674e336e2 100644 --- a/ports/espressif/common-hal/busio/I2C.h +++ b/ports/espressif/common-hal/busio/I2C.h @@ -8,7 +8,7 @@ #include "common-hal/microcontroller/Pin.h" -#include "components/hal/include/hal/i2c_types.h" +#include "hal/i2c_types.h" #include "FreeRTOS.h" #include "freertos/semphr.h" #include "py/obj.h" diff --git a/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c b/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c index 591c455722e..5df379432a9 100644 --- a/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +++ b/ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c @@ -14,7 +14,7 @@ #include "hal/dma_types.h" #include "hal/lcd_hal.h" #include "hal/lcd_ll.h" -#include "soc/lcd_periph.h" +#include "hal/lcd_periph.h" #include "esp_log.h" #define TAG "LCD" @@ -109,8 +109,7 @@ void common_hal_dotclockframebuffer_framebuffer_construct(dotclockframebuffer_fr cfg->timings.flags.pclk_idle_high = pclk_idle_high; cfg->data_width = 16; - cfg->sram_trans_align = 8; - cfg->psram_trans_align = 64; + cfg->dma_burst_size = 64; cfg->hsync_gpio_num = valid_pin(hsync, MP_QSTR_hsync); cfg->vsync_gpio_num = valid_pin(vsync, MP_QSTR_vsync); cfg->de_gpio_num = valid_pin(de, MP_QSTR_de); diff --git a/ports/espressif/common-hal/espcamera/Camera.c b/ports/espressif/common-hal/espcamera/Camera.c index 5b45a26951e..e7d91febbfa 100644 --- a/ports/espressif/common-hal/espcamera/Camera.c +++ b/ports/espressif/common-hal/espcamera/Camera.c @@ -86,7 +86,8 @@ void common_hal_espcamera_camera_construct( self->camera_config.pin_reset = reset_pin ? common_hal_mcu_pin_number(reset_pin) : NO_PIN; self->camera_config.pin_xclk = external_clock_pin ? common_hal_mcu_pin_number(external_clock_pin) : NO_PIN; - self->camera_config.sccb_i2c_master_bus_handle = self->i2c->handle; + self->camera_config.pin_sccb_sda = common_hal_mcu_pin_number(i2c->sda_pin); + self->camera_config.pin_sccb_scl = common_hal_mcu_pin_number(i2c->scl_pin); self->camera_config.pin_d7 = data_pins[7]; self->camera_config.pin_d6 = data_pins[6]; diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index ae11db25032..6d7580429a9 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -17,6 +17,7 @@ #include "common-hal/espnow/ESPNow.h" +#include "esp_now.h" #include "mphalport.h" #include "esp_now.h" @@ -119,8 +120,13 @@ void common_hal_espnow_init(espnow_obj_t *self) { common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); } - CHECK_ESP_RESULT(esp_wifi_config_espnow_rate(ESP_IF_WIFI_STA, self->phy_rate)); - CHECK_ESP_RESULT(esp_wifi_config_espnow_rate(ESP_IF_WIFI_AP, self->phy_rate)); + esp_now_rate_config_t rate_config = { + .phymode = WIFI_PHY_MODE_LR, + .rate = self->phy_rate, + .ersu = false, + .dcm = false, + }; + CHECK_ESP_RESULT(esp_now_set_peer_rate_config(NULL, &rate_config)); CHECK_ESP_RESULT(esp_now_init()); CHECK_ESP_RESULT(esp_now_register_send_cb(send_cb)); diff --git a/ports/espressif/common-hal/i2ctarget/I2CTarget.c b/ports/espressif/common-hal/i2ctarget/I2CTarget.c index 003e7731faa..648f71e6953 100644 --- a/ports/espressif/common-hal/i2ctarget/I2CTarget.c +++ b/ports/espressif/common-hal/i2ctarget/I2CTarget.c @@ -12,6 +12,19 @@ #include "common-hal/i2ctarget/I2CTarget.h" #include "shared-bindings/microcontroller/Pin.h" +static bool i2c_slave_on_receive(i2c_slave_dev_handle_t i2c_slave, const i2c_slave_rx_done_event_data_t *evt_data, void *arg) { + i2ctarget_i2c_target_obj_t *self = (i2ctarget_i2c_target_obj_t *)arg; + for (uint32_t i = 0; i < evt_data->length; i++) { + uint16_t next_head = (self->recv_head + 1) % I2CTARGET_RECV_BUF_SIZE; + if (next_head == self->recv_tail) { + break; // buffer full + } + self->recv_buf[self->recv_head] = evt_data->buffer[i]; + self->recv_head = next_head; + } + return false; +} + void common_hal_i2ctarget_i2c_target_construct(i2ctarget_i2c_target_obj_t *self, const mcu_pin_obj_t *scl, const mcu_pin_obj_t *sda, uint8_t *addresses, unsigned int num_addresses, bool smbus) { @@ -31,32 +44,40 @@ void common_hal_i2ctarget_i2c_target_construct(i2ctarget_i2c_target_obj_t *self, self->sda_pin = sda; self->scl_pin = scl; - self->i2c_num = peripherals_i2c_get_free_num(); - if (self->i2c_num == I2C_NUM_MAX) { - mp_raise_ValueError(MP_ERROR_TEXT("All I2C peripherals are in use")); - } - - const i2c_config_t i2c_conf = { - .mode = I2C_MODE_SLAVE, - .sda_io_num = self->sda_pin->number, - .scl_io_num = self->scl_pin->number, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .slave.addr_10bit_en = 0, - .slave.slave_addr = self->addresses[0], + self->recv_head = 0; + self->recv_tail = 0; + + i2c_slave_config_t slave_config = { + .i2c_port = -1, // auto + .sda_io_num = sda->number, + .scl_io_num = scl->number, + .clk_source = I2C_CLK_SRC_DEFAULT, + .send_buf_depth = 256, + .receive_buf_depth = 256, + .slave_addr = addresses[0], + .addr_bit_len = I2C_ADDR_BIT_LEN_7, + .flags = { + .enable_internal_pullup = true, + }, }; - // Initialize I2C. - esp_err_t err = peripherals_i2c_init(self->i2c_num, &i2c_conf); + esp_err_t err = i2c_new_slave_device(&slave_config, &self->handle); if (err != ESP_OK) { - if (err == ESP_FAIL) { + if (err == ESP_ERR_NOT_FOUND) { + mp_raise_ValueError(MP_ERROR_TEXT("All I2C peripherals are in use")); + } else if (err == ESP_FAIL) { mp_raise_OSError(MP_EIO); } else { mp_arg_error_invalid(MP_QSTR_I2CTarget); } } + i2c_slave_event_callbacks_t cbs = { + .on_receive = i2c_slave_on_receive, + }; + i2c_slave_register_event_callbacks(self->handle, &cbs, self); + claim_pin(sda); claim_pin(scl); } @@ -70,7 +91,8 @@ void common_hal_i2ctarget_i2c_target_deinit(i2ctarget_i2c_target_obj_t *self) { return; } - peripherals_i2c_deinit(self->i2c_num); + i2c_del_slave_device(self->handle); + self->handle = NULL; common_hal_reset_pin(self->sda_pin); common_hal_reset_pin(self->scl_pin); @@ -83,24 +105,34 @@ int common_hal_i2ctarget_i2c_target_is_addressed(i2ctarget_i2c_target_obj_t *sel *address = self->addresses[0]; *is_read = true; *is_restart = false; - return 1; + // Check if we have received data + if (self->recv_head != self->recv_tail) { + *is_read = false; + return 1; + } + return 0; } int common_hal_i2ctarget_i2c_target_read_byte(i2ctarget_i2c_target_obj_t *self, uint8_t *data) { - i2c_slave_read_buffer(self->i2c_num, data, 128, 0); + if (self->recv_head == self->recv_tail) { + return 0; // no data available + } + *data = self->recv_buf[self->recv_tail]; + self->recv_tail = (self->recv_tail + 1) % I2CTARGET_RECV_BUF_SIZE; return 1; } int common_hal_i2ctarget_i2c_target_write_byte(i2ctarget_i2c_target_obj_t *self, uint8_t data) { - i2c_reset_tx_fifo(self->i2c_num); - i2c_slave_write_buffer(self->i2c_num, &data, 128, 0); + uint32_t write_len; + esp_err_t err = i2c_slave_write(self->handle, &data, 1, &write_len, 100); + if (err != ESP_OK || write_len == 0) { + return 0; + } return 1; } void common_hal_i2ctarget_i2c_target_ack(i2ctarget_i2c_target_obj_t *self, bool ack) { - } void common_hal_i2ctarget_i2c_target_close(i2ctarget_i2c_target_obj_t *self) { - } diff --git a/ports/espressif/common-hal/i2ctarget/I2CTarget.h b/ports/espressif/common-hal/i2ctarget/I2CTarget.h index 2dcfb581eb3..fc41ac84ebc 100644 --- a/ports/espressif/common-hal/i2ctarget/I2CTarget.h +++ b/ports/espressif/common-hal/i2ctarget/I2CTarget.h @@ -7,14 +7,19 @@ #pragma once #include "py/obj.h" -#include "peripherals/i2c.h" +#include "driver/i2c_slave.h" #include "common-hal/microcontroller/Pin.h" +#define I2CTARGET_RECV_BUF_SIZE 128 + typedef struct { mp_obj_base_t base; - i2c_port_t i2c_num; + i2c_slave_dev_handle_t handle; uint8_t *addresses; uint8_t num_addresses; const mcu_pin_obj_t *scl_pin; const mcu_pin_obj_t *sda_pin; + uint8_t recv_buf[I2CTARGET_RECV_BUF_SIZE]; + volatile uint16_t recv_head; + volatile uint16_t recv_tail; } i2ctarget_i2c_target_obj_t; diff --git a/ports/espressif/common-hal/microcontroller/Processor.c b/ports/espressif/common-hal/microcontroller/Processor.c index 0056465f1c5..e87025067a3 100644 --- a/ports/espressif/common-hal/microcontroller/Processor.c +++ b/ports/espressif/common-hal/microcontroller/Processor.c @@ -183,19 +183,18 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { case ESP_RST_EXT: return RESET_REASON_RESET_PIN; - case ESP_RST_DEEPSLEEP: - switch (esp_sleep_get_wakeup_cause()) { - case ESP_SLEEP_WAKEUP_TIMER: - case ESP_SLEEP_WAKEUP_EXT0: - case ESP_SLEEP_WAKEUP_EXT1: - case ESP_SLEEP_WAKEUP_TOUCHPAD: - case ESP_SLEEP_WAKEUP_ULP: - return RESET_REASON_DEEP_SLEEP_ALARM; - - case ESP_SLEEP_WAKEUP_UNDEFINED: - default: - return RESET_REASON_UNKNOWN; + case ESP_RST_DEEPSLEEP: { + uint32_t wakeup_causes = esp_sleep_get_wakeup_causes(); + uint32_t alarm_causes = (1 << ESP_SLEEP_WAKEUP_TIMER) | + (1 << ESP_SLEEP_WAKEUP_EXT0) | + (1 << ESP_SLEEP_WAKEUP_EXT1) | + (1 << ESP_SLEEP_WAKEUP_TOUCHPAD) | + (1 << ESP_SLEEP_WAKEUP_ULP); + if (wakeup_causes & alarm_causes) { + return RESET_REASON_DEEP_SLEEP_ALARM; } + return RESET_REASON_UNKNOWN; + } case ESP_RST_UNKNOWN: default: diff --git a/ports/espressif/common-hal/mipidsi/Display.c b/ports/espressif/common-hal/mipidsi/Display.c index 46ef46ed601..dc70f901437 100644 --- a/ports/espressif/common-hal/mipidsi/Display.c +++ b/ports/espressif/common-hal/mipidsi/Display.c @@ -88,7 +88,6 @@ void common_hal_mipidsi_display_construct(mipidsi_display_obj_t *self, .vsync_front_porch = vsync_front_porch, }, .flags = { - .use_dma2d = false, .disable_lp = false, }, }; diff --git a/ports/espressif/common-hal/neopixel_write/__init__.c b/ports/espressif/common-hal/neopixel_write/__init__.c index d0d46a31797..cd62220f620 100644 --- a/ports/espressif/common-hal/neopixel_write/__init__.c +++ b/ports/espressif/common-hal/neopixel_write/__init__.c @@ -31,6 +31,8 @@ #include "driver/gpio.h" #include "driver/rmt_tx.h" +#include "hal/rmt_periph.h" +#include "soc/soc_caps.h" // Use closer to WS2812-style timings instead of WS2812B, to accommodate more varieties. #define WS2812_T0H_NS (316) @@ -53,14 +55,13 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, .trans_queue_depth = 1, }; - // Greedily try and grab as much RMT memory as we can. The more we get, the - // smoother the output will be because we'll trigger fewer interrupts. We'll - // give it all back once we're done. + // Greedily allocate as much RMT memory as possible, stepping down by one + // channel's worth each time. More memory means fewer interrupts and smoother output. + // We'll give it all back once we're done. rmt_channel_handle_t channel; esp_err_t result = ESP_ERR_NOT_FOUND; - // If no other channels are in use, we can use all of the RMT RAM including the RX channels. - config.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL * SOC_RMT_CHANNELS_PER_GROUP; - while (result == ESP_ERR_NOT_FOUND && config.mem_block_symbols > 0) { + config.mem_block_symbols = SOC_RMT_MEM_WORDS_PER_CHANNEL * RMT_LL_CHANS_PER_INST; + while (result == ESP_ERR_NOT_FOUND && config.mem_block_symbols >= SOC_RMT_MEM_WORDS_PER_CHANNEL) { result = rmt_new_tx_channel(&config, &channel); config.mem_block_symbols -= SOC_RMT_MEM_WORDS_PER_CHANNEL; } @@ -117,6 +118,7 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, rmt_del_channel(channel); raise_esp_error(result); } + result = ESP_ERR_TIMEOUT; while (result == ESP_ERR_TIMEOUT) { RUN_BACKGROUND_TASKS; diff --git a/ports/espressif/common-hal/sdioio/SDCard.c b/ports/espressif/common-hal/sdioio/SDCard.c index 102f4a4048e..04a9b62ec3e 100644 --- a/ports/espressif/common-hal/sdioio/SDCard.c +++ b/ports/espressif/common-hal/sdioio/SDCard.c @@ -22,6 +22,7 @@ static const char *TAG = "SDCard.c"; static bool slot_in_use[2]; static bool never_reset_sdio[2] = { false, false }; +static bool host_initialized = false; static void common_hal_sdioio_sdcard_check_for_deinit(sdioio_sdcard_obj_t *self) { if (common_hal_sdioio_sdcard_deinited(self)) { @@ -112,6 +113,7 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, if (err != ESP_OK) { mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error %x"), err); } + host_initialized = true; } err = sdmmc_host_init_slot(sd_slot, &slot_config); @@ -252,8 +254,9 @@ void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self) { never_reset_sdio[get_slot_index(self)] = false; slot_in_use[get_slot_index(self)] = false; - if (!slot_in_use[0] && !slot_in_use[1]) { + if (!slot_in_use[0] && !slot_in_use[1] && host_initialized) { sdmmc_host_deinit(); + host_initialized = false; } reset_pin_number(self->command); @@ -293,8 +296,9 @@ void sdioio_reset(void) { slot_in_use[i] = false; } } - if (!slot_in_use[0] && !slot_in_use[1]) { + if (!slot_in_use[0] && !slot_in_use[1] && host_initialized) { sdmmc_host_deinit(); + host_initialized = false; } return; diff --git a/ports/espressif/common-hal/wifi/Radio.c b/ports/espressif/common-hal/wifi/Radio.c index dc5311bb8ad..31dd7e4317f 100644 --- a/ports/espressif/common-hal/wifi/Radio.c +++ b/ports/espressif/common-hal/wifi/Radio.c @@ -115,7 +115,7 @@ void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *host mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { uint8_t mac[MAC_ADDRESS_LENGTH]; - esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); + esp_wifi_get_mac(WIFI_IF_STA, mac); return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } @@ -126,7 +126,7 @@ void common_hal_wifi_radio_set_mac_address(wifi_radio_obj_t *self, const uint8_t if ((mac[0] & 0b1) == 0b1) { mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid multicast MAC address")); } - esp_wifi_set_mac(ESP_IF_WIFI_STA, mac); + esp_wifi_set_mac(WIFI_IF_STA, mac); } mp_float_t common_hal_wifi_radio_get_tx_power(wifi_radio_obj_t *self) { @@ -167,7 +167,7 @@ void common_hal_wifi_radio_set_power_management(wifi_radio_obj_t *self, wifi_pow // This is a typical value seen in various examples. config->sta.listen_interval = 3; esp_wifi_set_ps(WIFI_PS_MAX_MODEM); - esp_wifi_set_config(ESP_IF_WIFI_STA, config); + esp_wifi_set_config(WIFI_IF_STA, config); } break; case POWER_MANAGEMENT_NONE: @@ -181,7 +181,7 @@ void common_hal_wifi_radio_set_power_management(wifi_radio_obj_t *self, wifi_pow mp_obj_t common_hal_wifi_radio_get_mac_address_ap(wifi_radio_obj_t *self) { uint8_t mac[MAC_ADDRESS_LENGTH]; - esp_wifi_get_mac(ESP_IF_WIFI_AP, mac); + esp_wifi_get_mac(WIFI_IF_AP, mac); return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } @@ -192,7 +192,7 @@ void common_hal_wifi_radio_set_mac_address_ap(wifi_radio_obj_t *self, const uint if ((mac[0] & 0b1) == 0b1) { mp_raise_RuntimeError(MP_ERROR_TEXT("Invalid multicast MAC address")); } - esp_wifi_set_mac(ESP_IF_WIFI_AP, mac); + esp_wifi_set_mac(WIFI_IF_AP, mac); } mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self, uint8_t start_channel, uint8_t stop_channel) { @@ -386,7 +386,7 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t } else { config->sta.scan_method = WIFI_FAST_SCAN; } - esp_wifi_set_config(ESP_IF_WIFI_STA, config); + esp_wifi_set_config(WIFI_IF_STA, config); self->starting_retries = 5; self->retries_left = 5; esp_wifi_connect(); diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index 0eacd2bab3e..85908855f26 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -88,7 +88,192 @@ static void event_handler(void *arg, esp_event_base_t event_base, ESP_LOGW(TAG, "disconnected"); wifi_event_sta_disconnected_t *d = (wifi_event_sta_disconnected_t *)event_data; uint8_t reason = d->reason; - ESP_LOGW(TAG, "reason %d 0x%02x", reason, reason); + const char *reason_str = "unknown"; + switch (reason) { + case WIFI_REASON_UNSPECIFIED: + reason_str = "unspecified"; + break; + case WIFI_REASON_AUTH_EXPIRE: + reason_str = "auth expire"; + break; + case WIFI_REASON_AUTH_LEAVE: + reason_str = "auth leave"; + break; + case WIFI_REASON_DISASSOC_DUE_TO_INACTIVITY: + reason_str = "disassoc inactivity"; + break; + case WIFI_REASON_ASSOC_TOOMANY: + reason_str = "assoc toomany"; + break; + case WIFI_REASON_CLASS2_FRAME_FROM_NONAUTH_STA: + reason_str = "class2 from nonauth"; + break; + case WIFI_REASON_CLASS3_FRAME_FROM_NONASSOC_STA: + reason_str = "class3 from nonassoc"; + break; + case WIFI_REASON_ASSOC_LEAVE: + reason_str = "assoc leave"; + break; + case WIFI_REASON_ASSOC_NOT_AUTHED: + reason_str = "assoc not authed"; + break; + case WIFI_REASON_DISASSOC_PWRCAP_BAD: + reason_str = "disassoc pwrcap bad"; + break; + case WIFI_REASON_DISASSOC_SUPCHAN_BAD: + reason_str = "disassoc supchan bad"; + break; + case WIFI_REASON_BSS_TRANSITION_DISASSOC: + reason_str = "bss transition disassoc"; + break; + case WIFI_REASON_IE_INVALID: + reason_str = "ie invalid"; + break; + case WIFI_REASON_MIC_FAILURE: + reason_str = "mic failure"; + break; + case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: + reason_str = "4way handshake timeout"; + break; + case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT: + reason_str = "group key update timeout"; + break; + case WIFI_REASON_IE_IN_4WAY_DIFFERS: + reason_str = "ie in 4way differs"; + break; + case WIFI_REASON_GROUP_CIPHER_INVALID: + reason_str = "group cipher invalid"; + break; + case WIFI_REASON_PAIRWISE_CIPHER_INVALID: + reason_str = "pairwise cipher invalid"; + break; + case WIFI_REASON_AKMP_INVALID: + reason_str = "akmp invalid"; + break; + case WIFI_REASON_UNSUPP_RSN_IE_VERSION: + reason_str = "unsupp rsn ie version"; + break; + case WIFI_REASON_INVALID_RSN_IE_CAP: + reason_str = "invalid rsn ie cap"; + break; + case WIFI_REASON_802_1X_AUTH_FAILED: + reason_str = "802.1x auth failed"; + break; + case WIFI_REASON_CIPHER_SUITE_REJECTED: + reason_str = "cipher suite rejected"; + break; + case WIFI_REASON_TDLS_PEER_UNREACHABLE: + reason_str = "tdls peer unreachable"; + break; + case WIFI_REASON_TDLS_UNSPECIFIED: + reason_str = "tdls unspecified"; + break; + case WIFI_REASON_SSP_REQUESTED_DISASSOC: + reason_str = "ssp requested disassoc"; + break; + case WIFI_REASON_NO_SSP_ROAMING_AGREEMENT: + reason_str = "no ssp roaming agreement"; + break; + case WIFI_REASON_BAD_CIPHER_OR_AKM: + reason_str = "bad cipher or akm"; + break; + case WIFI_REASON_NOT_AUTHORIZED_THIS_LOCATION: + reason_str = "not authorized this location"; + break; + case WIFI_REASON_SERVICE_CHANGE_PERCLUDES_TS: + reason_str = "service change precludes ts"; + break; + case WIFI_REASON_UNSPECIFIED_QOS: + reason_str = "unspecified qos"; + break; + case WIFI_REASON_NOT_ENOUGH_BANDWIDTH: + reason_str = "not enough bandwidth"; + break; + case WIFI_REASON_MISSING_ACKS: + reason_str = "missing acks"; + break; + case WIFI_REASON_EXCEEDED_TXOP: + reason_str = "exceeded txop"; + break; + case WIFI_REASON_STA_LEAVING: + reason_str = "sta leaving"; + break; + case WIFI_REASON_END_BA: + reason_str = "end ba"; + break; + case WIFI_REASON_UNKNOWN_BA: + reason_str = "unknown ba"; + break; + case WIFI_REASON_TIMEOUT: + reason_str = "timeout"; + break; + case WIFI_REASON_PEER_INITIATED: + reason_str = "peer initiated"; + break; + case WIFI_REASON_AP_INITIATED: + reason_str = "ap initiated"; + break; + case WIFI_REASON_INVALID_FT_ACTION_FRAME_COUNT: + reason_str = "invalid ft action frame count"; + break; + case WIFI_REASON_INVALID_PMKID: + reason_str = "invalid pmkid"; + break; + case WIFI_REASON_INVALID_MDE: + reason_str = "invalid mde"; + break; + case WIFI_REASON_INVALID_FTE: + reason_str = "invalid fte"; + break; + case WIFI_REASON_TRANSMISSION_LINK_ESTABLISH_FAILED: + reason_str = "transmission link establish failed"; + break; + case WIFI_REASON_ALTERATIVE_CHANNEL_OCCUPIED: + reason_str = "alternative channel occupied"; + break; + case WIFI_REASON_BEACON_TIMEOUT: + reason_str = "beacon timeout"; + break; + case WIFI_REASON_NO_AP_FOUND: + reason_str = "no ap found"; + break; + case WIFI_REASON_AUTH_FAIL: + reason_str = "auth fail"; + break; + case WIFI_REASON_ASSOC_FAIL: + reason_str = "assoc fail"; + break; + case WIFI_REASON_HANDSHAKE_TIMEOUT: + reason_str = "handshake timeout"; + break; + case WIFI_REASON_CONNECTION_FAIL: + reason_str = "connection fail"; + break; + case WIFI_REASON_AP_TSF_RESET: + reason_str = "ap tsf reset"; + break; + case WIFI_REASON_ROAMING: + reason_str = "roaming"; + break; + case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG: + reason_str = "assoc comeback time too long"; + break; + case WIFI_REASON_SA_QUERY_TIMEOUT: + reason_str = "sa query timeout"; + break; + case WIFI_REASON_NO_AP_FOUND_W_COMPATIBLE_SECURITY: + reason_str = "no ap found w compatible security"; + break; + case WIFI_REASON_NO_AP_FOUND_IN_AUTHMODE_THRESHOLD: + reason_str = "no ap found in authmode threshold"; + break; + case WIFI_REASON_NO_AP_FOUND_IN_RSSI_THRESHOLD: + reason_str = "no ap found in rssi threshold"; + break; + default: + break; + } + ESP_LOGW(TAG, "reason %d 0x%02x %s", reason, reason, reason_str); if (radio->retries_left > 0 && reason != WIFI_REASON_AUTH_FAIL && reason != WIFI_REASON_NO_AP_FOUND && @@ -104,12 +289,132 @@ static void event_handler(void *arg, esp_event_base_t event_base, break; } - // Cases to handle later. - // case WIFI_EVENT_STA_AUTHMODE_CHANGE: - default: { - ESP_LOGW(TAG, "event %ld 0x%02ld", event_id, event_id); + case WIFI_EVENT_WIFI_READY: + ESP_LOGW(TAG, "wifi ready"); + break; + case WIFI_EVENT_STA_AUTHMODE_CHANGE: + ESP_LOGW(TAG, "sta authmode change"); + break; + case WIFI_EVENT_STA_WPS_ER_SUCCESS: + ESP_LOGW(TAG, "sta wps er success"); + break; + case WIFI_EVENT_STA_WPS_ER_FAILED: + ESP_LOGW(TAG, "sta wps er failed"); + break; + case WIFI_EVENT_STA_WPS_ER_TIMEOUT: + ESP_LOGW(TAG, "sta wps er timeout"); + break; + case WIFI_EVENT_STA_WPS_ER_PIN: + ESP_LOGW(TAG, "sta wps er pin"); + break; + case WIFI_EVENT_STA_WPS_ER_PBC_OVERLAP: + ESP_LOGW(TAG, "sta wps er pbc overlap"); + break; + case WIFI_EVENT_AP_PROBEREQRECVED: + ESP_LOGW(TAG, "ap probereqrecved"); + break; + case WIFI_EVENT_FTM_REPORT: + ESP_LOGW(TAG, "ftm report"); + break; + case WIFI_EVENT_STA_BSS_RSSI_LOW: + ESP_LOGW(TAG, "sta bss rssi low"); + break; + case WIFI_EVENT_ACTION_TX_STATUS: + ESP_LOGW(TAG, "action tx status"); + break; + case WIFI_EVENT_ROC_DONE: + ESP_LOGW(TAG, "roc done"); + break; + case WIFI_EVENT_STA_BEACON_TIMEOUT: + ESP_LOGW(TAG, "sta beacon timeout"); + break; + case WIFI_EVENT_CONNECTIONLESS_MODULE_WAKE_INTERVAL_START: + ESP_LOGW(TAG, "connectionless module wake interval start"); + break; + case WIFI_EVENT_AP_WPS_RG_SUCCESS: + ESP_LOGW(TAG, "ap wps rg success"); + break; + case WIFI_EVENT_AP_WPS_RG_FAILED: + ESP_LOGW(TAG, "ap wps rg failed"); + break; + case WIFI_EVENT_AP_WPS_RG_TIMEOUT: + ESP_LOGW(TAG, "ap wps rg timeout"); + break; + case WIFI_EVENT_AP_WPS_RG_PIN: + ESP_LOGW(TAG, "ap wps rg pin"); + break; + case WIFI_EVENT_AP_WPS_RG_PBC_OVERLAP: + ESP_LOGW(TAG, "ap wps rg pbc overlap"); + break; + case WIFI_EVENT_ITWT_SETUP: + ESP_LOGW(TAG, "itwt setup"); + break; + case WIFI_EVENT_ITWT_TEARDOWN: + ESP_LOGW(TAG, "itwt teardown"); + break; + case WIFI_EVENT_ITWT_PROBE: + ESP_LOGW(TAG, "itwt probe"); + break; + case WIFI_EVENT_ITWT_SUSPEND: + ESP_LOGW(TAG, "itwt suspend"); + break; + case WIFI_EVENT_TWT_WAKEUP: + ESP_LOGW(TAG, "twt wakeup"); + break; + case WIFI_EVENT_BTWT_SETUP: + ESP_LOGW(TAG, "btwt setup"); + break; + case WIFI_EVENT_BTWT_TEARDOWN: + ESP_LOGW(TAG, "btwt teardown"); + break; + case WIFI_EVENT_NAN_SYNC_STARTED: + ESP_LOGW(TAG, "nan sync started"); + break; + case WIFI_EVENT_NAN_SYNC_STOPPED: + ESP_LOGW(TAG, "nan sync stopped"); + break; + case WIFI_EVENT_NAN_SVC_MATCH: + ESP_LOGW(TAG, "nan svc match"); + break; + case WIFI_EVENT_NAN_REPLIED: + ESP_LOGW(TAG, "nan replied"); + break; + case WIFI_EVENT_NAN_RECEIVE: + ESP_LOGW(TAG, "nan receive"); + break; + case WIFI_EVENT_NDP_INDICATION: + ESP_LOGW(TAG, "ndp indication"); + break; + case WIFI_EVENT_NDP_CONFIRM: + ESP_LOGW(TAG, "ndp confirm"); + break; + case WIFI_EVENT_NDP_TERMINATED: + ESP_LOGW(TAG, "ndp terminated"); + break; + case WIFI_EVENT_HOME_CHANNEL_CHANGE: + ESP_LOGW(TAG, "home channel change"); + break; + case WIFI_EVENT_STA_NEIGHBOR_REP: + ESP_LOGW(TAG, "sta neighbor rep"); + break; + case WIFI_EVENT_AP_WRONG_PASSWORD: + ESP_LOGW(TAG, "ap wrong password"); + break; + case WIFI_EVENT_STA_BEACON_OFFSET_UNSTABLE: + ESP_LOGW(TAG, "sta beacon offset unstable"); + break; + case WIFI_EVENT_DPP_URI_READY: + ESP_LOGW(TAG, "dpp uri ready"); + break; + case WIFI_EVENT_DPP_CFG_RECVD: + ESP_LOGW(TAG, "dpp cfg recvd"); + break; + case WIFI_EVENT_DPP_FAILED: + ESP_LOGW(TAG, "dpp failed"); + break; + default: + ESP_LOGW(TAG, "unknown event %ld", event_id); break; - } } } @@ -214,7 +519,7 @@ void common_hal_wifi_init(bool user_initiated) { char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; uint8_t mac[MAC_ADDRESS_LENGTH]; - esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); + esp_wifi_get_mac(WIFI_IF_STA, mac); snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); const char *default_lwip_local_hostname = cpy_default_hostname; diff --git a/ports/espressif/esp-camera b/ports/espressif/esp-camera index 243560e9499..015eb6534c4 160000 --- a/ports/espressif/esp-camera +++ b/ports/espressif/esp-camera @@ -1 +1 @@ -Subproject commit 243560e94997c262565ed537154b0578b8ce2197 +Subproject commit 015eb6534c4efa406aa90e5b9f4752ef71af0d25 diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index 1d2c73f641a..e6c85f28eb0 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit 1d2c73f641af70c24274e2d3e74641592bee97e5 +Subproject commit e6c85f28eb03b78ba914cb05d072a4a506e6d4fd diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32.defaults index 5789c442a62..1b2698068ed 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32.defaults @@ -62,10 +62,10 @@ CONFIG_ESP_IPC_TASK_STACK_SIZE=1536 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # # SPI Flash driver diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c2.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c2.defaults index 19c73ca5ee5..661b2b52801 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32c2.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c2.defaults @@ -43,10 +43,10 @@ CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # end of Component config diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults index 19c73ca5ee5..661b2b52801 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32c3.defaults @@ -43,10 +43,10 @@ CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM=4 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # end of Component config diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults index 101f90f9fa4..126b49c6fd3 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32s2.defaults @@ -43,10 +43,10 @@ CONFIG_ESP_WIFI_RX_BA_WIN=4 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # # Ultra Low Power (ULP) Co-processor @@ -58,12 +58,6 @@ CONFIG_ULP_COPROC_TYPE_RISCV=y # Note: enabling both ULPs simultaneously only w CONFIG_ULP_COPROC_RESERVE_MEM=8144 # end of Ultra Low Power (ULP) Co-processor -# -# FreeRTOS -# -CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y -# end of FreeRTOS - # end of Component config # end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults b/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults index 2553c648018..b48bb58df3f 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-esp32s3.defaults @@ -83,10 +83,10 @@ CONFIG_ESP_WIFI_CACHE_TX_BUFFER_NUM=16 # end of Wi-Fi # -# Newlib +# LibC # -CONFIG_NEWLIB_NANO_FORMAT=y -# end of Newlib +CONFIG_LIBC_NEWLIB_NANO_FORMAT=y +# end of LibC # # Ultra Low Power (ULP) Co-processor diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults index 6a2285a2936..ae5a415ed12 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults @@ -1,2 +1,4 @@ CONFIG_ESPTOOLPY_FLASHFREQ_120M=y CONFIG_SPI_FLASH_UNDER_HIGH_FREQ=y +CONFIG_SPI_FLASH_HPM_ENA=y +CONFIG_SPI_FLASH_HPM_DC_DISABLE=y diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-2MB-no-ota-no-uf2.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-2MB-no-ota-no-uf2.defaults index 2d0b2ac5eb9..21365b751d1 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-2MB-no-ota-no-uf2.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-2MB-no-ota-no-uf2.defaults @@ -7,7 +7,6 @@ CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set CONFIG_ESPTOOLPY_FLASHSIZE="2MB" -CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y # end of Serial flasher config CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-2MB-no-ota-no-uf2.csv" diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-32MB.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-32MB.defaults index bbdd32afb81..a5a93778864 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-32MB.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-32MB.defaults @@ -8,7 +8,6 @@ # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set CONFIG_ESPTOOLPY_FLASHSIZE_32MB=y CONFIG_ESPTOOLPY_FLASHSIZE="32MB" -CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y # end of Serial flasher config CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="esp-idf-config/partitions-32MB.csv" diff --git a/ports/espressif/esp-idf-config/sdkconfig.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults index 5c4d6a31a62..941f879ed42 100644 --- a/ports/espressif/esp-idf-config/sdkconfig.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig.defaults @@ -17,7 +17,7 @@ CONFIG_PARTITION_TABLE_CUSTOM=y # GPTimer Configuration # CONFIG_GPTIMER_CTRL_FUNC_IN_IRAM=y -CONFIG_GPTIMER_ISR_IRAM_SAFE=y +CONFIG_GPTIMER_ISR_CACHE_SAFE=y # end of GPTimer Configuration # @@ -68,13 +68,12 @@ CONFIG_FREERTOS_HZ=1000 # # LibC # -# end of LWIP -CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS=y # end of LibC # # LWIP # +CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=4096 CONFIG_LWIP_MAX_SOCKETS=8 CONFIG_LWIP_SO_RCVBUF=y # @@ -116,11 +115,7 @@ CONFIG_MBEDTLS_SSL_PROTO_DTLS=y # CONFIG_MBEDTLS_PEM_WRITE_C is not set # end of Certificates -# CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED is not set -# CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED is not set -# CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED is not set -# CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED is not set diff --git a/ports/espressif/peripherals/esp32/pins.c b/ports/espressif/peripherals/esp32/pins.c index e2c45bd06fc..3aa12c9e675 100644 --- a/ports/espressif/peripherals/esp32/pins.c +++ b/ports/espressif/peripherals/esp32/pins.c @@ -6,11 +6,11 @@ #include "peripherals/pins.h" -const mcu_pin_obj_t pin_GPIO0 = PIN(0, ADC_UNIT_2, ADC_CHANNEL_1, TOUCH_PAD_NUM1); +const mcu_pin_obj_t pin_GPIO0 = PIN(0, ADC_UNIT_2, ADC_CHANNEL_1, 1); const mcu_pin_obj_t pin_GPIO1 = PIN(1, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_2, ADC_CHANNEL_2, TOUCH_PAD_NUM2); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_2, ADC_CHANNEL_2, 2); const mcu_pin_obj_t pin_GPIO3 = PIN(3, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_2, ADC_CHANNEL_0, TOUCH_PAD_NUM0); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_2, ADC_CHANNEL_0, 0); const mcu_pin_obj_t pin_GPIO5 = PIN(5, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO6 = PIN(6, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); @@ -18,10 +18,10 @@ const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL) const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_5, TOUCH_PAD_NUM5); -const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_4, TOUCH_PAD_NUM4); -const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_6, TOUCH_PAD_NUM6); -const mcu_pin_obj_t pin_GPIO15 = PIN(15, ADC_UNIT_2, ADC_CHANNEL_3, TOUCH_PAD_NUM3); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_5, 5); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_4, 4); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_6, 6); +const mcu_pin_obj_t pin_GPIO15 = PIN(15, ADC_UNIT_2, ADC_CHANNEL_3, 3); const mcu_pin_obj_t pin_GPIO16 = PIN(16, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO17 = PIN(17, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO18 = PIN(18, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); @@ -34,13 +34,13 @@ const mcu_pin_obj_t pin_GPIO23 = PIN(23, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNE // no GPIO24 const mcu_pin_obj_t pin_GPIO25 = PIN(25, ADC_UNIT_2, ADC_CHANNEL_8, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO26 = PIN(26, ADC_UNIT_2, ADC_CHANNEL_9, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO27 = PIN(27, ADC_UNIT_2, ADC_CHANNEL_7, TOUCH_PAD_NUM7); +const mcu_pin_obj_t pin_GPIO27 = PIN(27, ADC_UNIT_2, ADC_CHANNEL_7, 7); // no GPIO28 // no GPIO29 // no GPIO30 // no GPIO31 -const mcu_pin_obj_t pin_GPIO32 = PIN(32, ADC_UNIT_1, ADC_CHANNEL_4, TOUCH_PAD_NUM9); -const mcu_pin_obj_t pin_GPIO33 = PIN(33, ADC_UNIT_1, ADC_CHANNEL_5, TOUCH_PAD_NUM8); +const mcu_pin_obj_t pin_GPIO32 = PIN(32, ADC_UNIT_1, ADC_CHANNEL_4, 9); +const mcu_pin_obj_t pin_GPIO33 = PIN(33, ADC_UNIT_1, ADC_CHANNEL_5, 8); const mcu_pin_obj_t pin_GPIO34 = PIN(34, ADC_UNIT_1, ADC_CHANNEL_6, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO35 = PIN(35, ADC_UNIT_1, ADC_CHANNEL_7, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO36 = PIN(36, ADC_UNIT_1, ADC_CHANNEL_0, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32p4/pins.c b/ports/espressif/peripherals/esp32p4/pins.c index 24e509d40c6..a4e085e6971 100644 --- a/ports/espressif/peripherals/esp32p4/pins.c +++ b/ports/espressif/peripherals/esp32p4/pins.c @@ -8,20 +8,20 @@ const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO1 = PIN(1, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO2 = PIN(2, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM0); -const mcu_pin_obj_t pin_GPIO3 = PIN(3, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM1); -const mcu_pin_obj_t pin_GPIO4 = PIN(4, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM2); -const mcu_pin_obj_t pin_GPIO5 = PIN(5, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM3); -const mcu_pin_obj_t pin_GPIO6 = PIN(6, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM4); -const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM5); -const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM6); -const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM7); -const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM8); -const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM9); -const mcu_pin_obj_t pin_GPIO12 = PIN(12, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM10); -const mcu_pin_obj_t pin_GPIO13 = PIN(13, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM11); -const mcu_pin_obj_t pin_GPIO14 = PIN(14, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM12); -const mcu_pin_obj_t pin_GPIO15 = PIN(15, NO_ADC, NO_ADC_CHANNEL, TOUCH_PAD_NUM13); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, NO_ADC, NO_ADC_CHANNEL, 0); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, NO_ADC, NO_ADC_CHANNEL, 1); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, NO_ADC, NO_ADC_CHANNEL, 2); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, NO_ADC, NO_ADC_CHANNEL, 3); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, NO_ADC, NO_ADC_CHANNEL, 4); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, NO_ADC, NO_ADC_CHANNEL, 5); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, NO_ADC, NO_ADC_CHANNEL, 6); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, NO_ADC, NO_ADC_CHANNEL, 7); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, NO_ADC, NO_ADC_CHANNEL, 8); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, NO_ADC, NO_ADC_CHANNEL, 9); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, NO_ADC, NO_ADC_CHANNEL, 10); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, NO_ADC, NO_ADC_CHANNEL, 11); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, NO_ADC, NO_ADC_CHANNEL, 12); +const mcu_pin_obj_t pin_GPIO15 = PIN(15, NO_ADC, NO_ADC_CHANNEL, 13); const mcu_pin_obj_t pin_GPIO16 = PIN(16, ADC_UNIT_1, ADC_CHANNEL_0, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO17 = PIN(17, ADC_UNIT_1, ADC_CHANNEL_1, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO18 = PIN(18, ADC_UNIT_1, ADC_CHANNEL_2, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32s2/pins.c b/ports/espressif/peripherals/esp32s2/pins.c index b5e8d483175..cfaecd0ac6d 100644 --- a/ports/espressif/peripherals/esp32s2/pins.c +++ b/ports/espressif/peripherals/esp32s2/pins.c @@ -7,20 +7,20 @@ #include "peripherals/pins.h" const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, TOUCH_PAD_NUM1); -const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, TOUCH_PAD_NUM2); -const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, TOUCH_PAD_NUM3); -const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, TOUCH_PAD_NUM4); -const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, TOUCH_PAD_NUM5); -const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, TOUCH_PAD_NUM6); -const mcu_pin_obj_t pin_GPIO7 = PIN(7, ADC_UNIT_1, ADC_CHANNEL_6, TOUCH_PAD_NUM7); -const mcu_pin_obj_t pin_GPIO8 = PIN(8, ADC_UNIT_1, ADC_CHANNEL_7, TOUCH_PAD_NUM8); -const mcu_pin_obj_t pin_GPIO9 = PIN(9, ADC_UNIT_1, ADC_CHANNEL_8, TOUCH_PAD_NUM9); -const mcu_pin_obj_t pin_GPIO10 = PIN(10, ADC_UNIT_1, ADC_CHANNEL_9, TOUCH_PAD_NUM10); -const mcu_pin_obj_t pin_GPIO11 = PIN(11, ADC_UNIT_2, ADC_CHANNEL_0, TOUCH_PAD_NUM11); -const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_1, TOUCH_PAD_NUM12); -const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_2, TOUCH_PAD_NUM13); -const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_3, TOUCH_PAD_NUM14); +const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, 1); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, 2); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, 3); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, 4); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, 5); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, 6); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, ADC_UNIT_1, ADC_CHANNEL_6, 7); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, ADC_UNIT_1, ADC_CHANNEL_7, 8); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, ADC_UNIT_1, ADC_CHANNEL_8, 9); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, ADC_UNIT_1, ADC_CHANNEL_9, 10); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, ADC_UNIT_2, ADC_CHANNEL_0, 11); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_1, 12); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_2, 13); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_3, 14); const mcu_pin_obj_t pin_GPIO15 = PIN(15, ADC_UNIT_2, ADC_CHANNEL_4, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO16 = PIN(16, ADC_UNIT_2, ADC_CHANNEL_5, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO17 = PIN(17, ADC_UNIT_2, ADC_CHANNEL_6, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/esp32s3/pins.c b/ports/espressif/peripherals/esp32s3/pins.c index c51c4b93575..745cb4a7a67 100644 --- a/ports/espressif/peripherals/esp32s3/pins.c +++ b/ports/espressif/peripherals/esp32s3/pins.c @@ -9,20 +9,20 @@ // NOTE: These numbers do NOT always match the package and module pin number. // These are by solely by GPIO numbers. const mcu_pin_obj_t pin_GPIO0 = PIN(0, NO_ADC, NO_ADC_CHANNEL, NO_TOUCH_CHANNEL); -const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, TOUCH_PAD_NUM1); -const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, TOUCH_PAD_NUM2); -const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, TOUCH_PAD_NUM3); -const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, TOUCH_PAD_NUM4); -const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, TOUCH_PAD_NUM5); -const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, TOUCH_PAD_NUM6); -const mcu_pin_obj_t pin_GPIO7 = PIN(7, ADC_UNIT_1, ADC_CHANNEL_6, TOUCH_PAD_NUM7); -const mcu_pin_obj_t pin_GPIO8 = PIN(8, ADC_UNIT_1, ADC_CHANNEL_7, TOUCH_PAD_NUM8); -const mcu_pin_obj_t pin_GPIO9 = PIN(9, ADC_UNIT_1, ADC_CHANNEL_8, TOUCH_PAD_NUM9); -const mcu_pin_obj_t pin_GPIO10 = PIN(10, ADC_UNIT_1, ADC_CHANNEL_9, TOUCH_PAD_NUM10); -const mcu_pin_obj_t pin_GPIO11 = PIN(11, ADC_UNIT_2, ADC_CHANNEL_0, TOUCH_PAD_NUM11); -const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_1, TOUCH_PAD_NUM12); -const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_2, TOUCH_PAD_NUM13); -const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_3, TOUCH_PAD_NUM14); +const mcu_pin_obj_t pin_GPIO1 = PIN(1, ADC_UNIT_1, ADC_CHANNEL_0, 1); +const mcu_pin_obj_t pin_GPIO2 = PIN(2, ADC_UNIT_1, ADC_CHANNEL_1, 2); +const mcu_pin_obj_t pin_GPIO3 = PIN(3, ADC_UNIT_1, ADC_CHANNEL_2, 3); +const mcu_pin_obj_t pin_GPIO4 = PIN(4, ADC_UNIT_1, ADC_CHANNEL_3, 4); +const mcu_pin_obj_t pin_GPIO5 = PIN(5, ADC_UNIT_1, ADC_CHANNEL_4, 5); +const mcu_pin_obj_t pin_GPIO6 = PIN(6, ADC_UNIT_1, ADC_CHANNEL_5, 6); +const mcu_pin_obj_t pin_GPIO7 = PIN(7, ADC_UNIT_1, ADC_CHANNEL_6, 7); +const mcu_pin_obj_t pin_GPIO8 = PIN(8, ADC_UNIT_1, ADC_CHANNEL_7, 8); +const mcu_pin_obj_t pin_GPIO9 = PIN(9, ADC_UNIT_1, ADC_CHANNEL_8, 9); +const mcu_pin_obj_t pin_GPIO10 = PIN(10, ADC_UNIT_1, ADC_CHANNEL_9, 10); +const mcu_pin_obj_t pin_GPIO11 = PIN(11, ADC_UNIT_2, ADC_CHANNEL_0, 11); +const mcu_pin_obj_t pin_GPIO12 = PIN(12, ADC_UNIT_2, ADC_CHANNEL_1, 12); +const mcu_pin_obj_t pin_GPIO13 = PIN(13, ADC_UNIT_2, ADC_CHANNEL_2, 13); +const mcu_pin_obj_t pin_GPIO14 = PIN(14, ADC_UNIT_2, ADC_CHANNEL_3, 14); const mcu_pin_obj_t pin_GPIO15 = PIN(15, ADC_UNIT_2, ADC_CHANNEL_4, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO16 = PIN(16, ADC_UNIT_2, ADC_CHANNEL_5, NO_TOUCH_CHANNEL); const mcu_pin_obj_t pin_GPIO17 = PIN(17, ADC_UNIT_2, ADC_CHANNEL_6, NO_TOUCH_CHANNEL); diff --git a/ports/espressif/peripherals/pins.h b/ports/espressif/peripherals/pins.h index bbe42be1bca..431a136545a 100644 --- a/ports/espressif/peripherals/pins.h +++ b/ports/espressif/peripherals/pins.h @@ -12,16 +12,15 @@ #include "py/obj.h" -#include "components/hal/include/hal/gpio_types.h" -#include "components/hal/include/hal/adc_types.h" -#include "components/hal/include/hal/touch_sensor_legacy_types.h" +#include "hal/gpio_types.h" +#include "hal/adc_types.h" typedef struct { mp_obj_base_t base; gpio_num_t number; uint8_t adc_index : 2; uint8_t adc_channel : 6; - touch_pad_t touch_channel; + int8_t touch_channel; } mcu_pin_obj_t; extern const mp_obj_type_t mcu_pin_type; @@ -31,7 +30,7 @@ extern const mp_obj_type_t mcu_pin_type; #define NO_ADC SOC_ADC_PERIPH_NUM #define NO_ADC_CHANNEL SOC_ADC_MAX_CHANNEL_NUM -#define NO_TOUCH_CHANNEL TOUCH_PAD_MAX +#define NO_TOUCH_CHANNEL (-1) // This macro is used to simplify pin definition in peripherals//pins.c #define PIN(p_number, p_adc_index, p_adc_channel, p_touch_channel) \ diff --git a/ports/espressif/peripherals/touch.c b/ports/espressif/peripherals/touch.c index 71340d94371..1084a030ec8 100644 --- a/ports/espressif/peripherals/touch.c +++ b/ports/espressif/peripherals/touch.c @@ -4,51 +4,122 @@ // // SPDX-License-Identifier: MIT -#include "py/gc.h" #include "peripherals/touch.h" -static bool touch_inited = false; -static bool touch_never_reset = false; +static touch_sensor_handle_t touch_controller = NULL; +static touch_channel_handle_t touch_channels[TOUCH_TOTAL_CHAN_NUM] = {NULL}; +static bool touch_never_reset_flag = false; +static bool touch_enabled = false; +static bool touch_scanning = false; + +static int chan_index(int channel_id) { + return channel_id - TOUCH_MIN_CHAN_ID; +} + +touch_sensor_handle_t peripherals_touch_get_controller(void) { + return touch_controller; +} + +touch_channel_handle_t peripherals_touch_get_handle(int channel_id) { + return touch_channels[chan_index(channel_id)]; +} void peripherals_touch_reset(void) { - if (touch_inited && !touch_never_reset) { - touch_pad_deinit(); - touch_inited = false; + if (touch_controller != NULL && !touch_never_reset_flag) { + if (touch_scanning) { + touch_sensor_stop_continuous_scanning(touch_controller); + touch_scanning = false; + } + if (touch_enabled) { + touch_sensor_disable(touch_controller); + touch_enabled = false; + } + for (unsigned int i = 0; i < TOUCH_TOTAL_CHAN_NUM; i++) { + if (touch_channels[i] != NULL) { + touch_sensor_del_channel(touch_channels[i]); + touch_channels[i] = NULL; + } + } + touch_sensor_del_controller(touch_controller); + touch_controller = NULL; } } void peripherals_touch_never_reset(const bool enable) { - touch_never_reset = enable; + touch_never_reset_flag = enable; } -void peripherals_touch_init(const touch_pad_t touchpad) { - if (!touch_inited) { - touch_pad_init(); - touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER); +void peripherals_touch_init(const int channel_id) { + int idx = chan_index(channel_id); + + // Already initialized this channel + if (touch_channels[idx] != NULL) { + return; + } + + // Stop scanning and disable before modifying channels + if (touch_scanning) { + touch_sensor_stop_continuous_scanning(touch_controller); + touch_scanning = false; + } + if (touch_enabled) { + touch_sensor_disable(touch_controller); + touch_enabled = false; } - // touch_pad_config() must be done before touch_pad_fsm_start() the first time. - // Otherwise the calibration is wrong and we get maximum raw values if there is - // a trace of any significant length on the pin. - #if defined(CONFIG_IDF_TARGET_ESP32) - touch_pad_config(touchpad, 0); + + if (touch_controller == NULL) { + #if SOC_TOUCH_SENSOR_VERSION == 1 + touch_sensor_sample_config_t sample_cfg = TOUCH_SENSOR_V1_DEFAULT_SAMPLE_CONFIG(5.0, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_1V7); + #elif SOC_TOUCH_SENSOR_VERSION == 2 + touch_sensor_sample_config_t sample_cfg = TOUCH_SENSOR_V2_DEFAULT_SAMPLE_CONFIG(500, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_2V2); + #elif SOC_TOUCH_SENSOR_VERSION == 3 + touch_sensor_sample_config_t sample_cfg = TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(3, 29, 8, 3); + #endif + touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(1, &sample_cfg); + touch_sensor_new_controller(&sens_cfg, &touch_controller); + } + + #if SOC_TOUCH_SENSOR_VERSION == 1 + touch_channel_config_t chan_cfg = { + .abs_active_thresh = {1000}, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, + .group = TOUCH_CHAN_TRIG_GROUP_BOTH, + }; #else - touch_pad_config(touchpad); - touch_pad_fsm_start(); + touch_channel_config_t chan_cfg = { + .active_thresh = {2000}, + .charge_speed = TOUCH_CHARGE_SPEED_7, + .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, + }; #endif - touch_inited = true; + + touch_sensor_new_channel(touch_controller, channel_id, &chan_cfg, &touch_channels[idx]); + + // Enable and start continuous scanning + touch_sensor_enable(touch_controller); + touch_enabled = true; + touch_sensor_start_continuous_scanning(touch_controller); + touch_scanning = true; } -uint16_t peripherals_touch_read(touch_pad_t touchpad) { - #if defined(CONFIG_IDF_TARGET_ESP32) - uint16_t touch_value; - touch_pad_read(touchpad, &touch_value); +uint16_t peripherals_touch_read(int channel_id) { + int idx = chan_index(channel_id); + if (touch_channels[idx] == NULL) { + return 0; + } + + uint32_t touch_value = 0; + touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_RAW, &touch_value); - // ESP32 touch_pad_read() returns a lower value when a pin is touched instead of a higher value. - // Flip the values around to be consistent with TouchIn assumptions. - return UINT16_MAX - touch_value; + #if SOC_TOUCH_SENSOR_VERSION == 1 + // ESP32 touch reads a lower value when touched. + // Flip the values to be consistent with TouchIn assumptions. + if (touch_value > UINT16_MAX) { + return 0; + } + return UINT16_MAX - (uint16_t)touch_value; #else - uint32_t touch_value; - touch_pad_read_raw_data(touchpad, &touch_value); if (touch_value > UINT16_MAX) { return UINT16_MAX; } diff --git a/ports/espressif/peripherals/touch.h b/ports/espressif/peripherals/touch.h index 6be4f8c2be1..00a96193c88 100644 --- a/ports/espressif/peripherals/touch.h +++ b/ports/espressif/peripherals/touch.h @@ -6,9 +6,11 @@ #pragma once -#include "driver/touch_pad.h" +#include "driver/touch_sens.h" -extern uint16_t peripherals_touch_read(touch_pad_t touchpad); +extern void peripherals_touch_init(const int channel_id); +extern uint16_t peripherals_touch_read(int channel_id); extern void peripherals_touch_reset(void); extern void peripherals_touch_never_reset(const bool enable); -extern void peripherals_touch_init(const touch_pad_t touchpad); +extern touch_sensor_handle_t peripherals_touch_get_controller(void); +extern touch_channel_handle_t peripherals_touch_get_handle(int channel_id); diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index b3045026e12..c9b536d6c14 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -515,7 +515,7 @@ void port_idle_until_interrupt(void) { #if CIRCUITPY_WIFI void port_boot_info(void) { uint8_t mac[6]; - esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); + esp_wifi_get_mac(WIFI_IF_STA, mac); mp_printf(&mp_plat_print, "MAC"); for (int i = 0; i < 6; i++) { mp_printf(&mp_plat_print, ":%02X", mac[i]); diff --git a/ports/espressif/supervisor/usb.c b/ports/espressif/supervisor/usb.c index e4d34ee7694..7c3b1561a44 100644 --- a/ports/espressif/supervisor/usb.c +++ b/ports/espressif/supervisor/usb.c @@ -21,8 +21,6 @@ #include "driver/gpio.h" #include "esp_private/periph_ctrl.h" -#include "rom/gpio.h" - #include "freertos/FreeRTOS.h" #include "freertos/task.h" diff --git a/shared-module/hashlib/Hash.c b/shared-module/hashlib/Hash.c index b7e966e951b..64fcf2d941f 100644 --- a/shared-module/hashlib/Hash.c +++ b/shared-module/hashlib/Hash.c @@ -7,14 +7,55 @@ #include "shared-bindings/hashlib/Hash.h" #include "shared-module/hashlib/__init__.h" +#include "mbedtls/version.h" + +#if MBEDTLS_VERSION_MAJOR >= 4 + +#include "psa/crypto.h" + +void common_hal_hashlib_hash_update(hashlib_hash_obj_t *self, const uint8_t *data, size_t datalen) { + psa_hash_update(&self->hash_op, data, datalen); +} + +void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, size_t datalen) { + if (datalen < common_hal_hashlib_hash_get_digest_size(self)) { + return; + } + // Clone the operation so we can continue to update or get digest again. + psa_hash_operation_t clone = PSA_HASH_OPERATION_INIT; + psa_hash_clone(&self->hash_op, &clone); + size_t hash_len; + psa_hash_finish(&clone, data, datalen, &hash_len); +} + +size_t common_hal_hashlib_hash_get_digest_size(hashlib_hash_obj_t *self) { + return PSA_HASH_LENGTH(self->hash_alg); +} + +#else + #include "mbedtls/ssl.h" +// In mbedtls 2.x, the _ret suffix functions are the recommended API. +// In mbedtls 3.x, the _ret suffix was removed and the base names return int. +#if MBEDTLS_VERSION_MAJOR < 3 +#define SHA1_UPDATE mbedtls_sha1_update_ret +#define SHA1_FINISH mbedtls_sha1_finish_ret +#define SHA256_UPDATE mbedtls_sha256_update_ret +#define SHA256_FINISH mbedtls_sha256_finish_ret +#else +#define SHA1_UPDATE mbedtls_sha1_update +#define SHA1_FINISH mbedtls_sha1_finish +#define SHA256_UPDATE mbedtls_sha256_update +#define SHA256_FINISH mbedtls_sha256_finish +#endif + void common_hal_hashlib_hash_update(hashlib_hash_obj_t *self, const uint8_t *data, size_t datalen) { if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { - mbedtls_sha1_update_ret(&self->sha1, data, datalen); + SHA1_UPDATE(&self->sha1, data, datalen); return; } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { - mbedtls_sha256_update_ret(&self->sha256, data, datalen); + SHA256_UPDATE(&self->sha256, data, datalen); return; } } @@ -28,12 +69,12 @@ void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, siz // the digest a second time. mbedtls_sha1_context copy; mbedtls_sha1_clone(©, &self->sha1); - mbedtls_sha1_finish_ret(&self->sha1, data); + SHA1_FINISH(&self->sha1, data); mbedtls_sha1_clone(&self->sha1, ©); } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { mbedtls_sha256_context copy; mbedtls_sha256_clone(©, &self->sha256); - mbedtls_sha256_finish_ret(&self->sha256, data); + SHA256_FINISH(&self->sha256, data); mbedtls_sha256_clone(&self->sha256, ©); } } @@ -46,3 +87,5 @@ size_t common_hal_hashlib_hash_get_digest_size(hashlib_hash_obj_t *self) { } return 0; } + +#endif diff --git a/shared-module/hashlib/Hash.h b/shared-module/hashlib/Hash.h index f3c2979e59c..035368e7c2f 100644 --- a/shared-module/hashlib/Hash.h +++ b/shared-module/hashlib/Hash.h @@ -6,6 +6,20 @@ #pragma once +#include "mbedtls/version.h" + +#if MBEDTLS_VERSION_MAJOR >= 4 + +#include "psa/crypto.h" + +typedef struct { + mp_obj_base_t base; + psa_hash_operation_t hash_op; + psa_algorithm_t hash_alg; +} hashlib_hash_obj_t; + +#else + #include "mbedtls/sha1.h" #include "mbedtls/sha256.h" @@ -18,3 +32,5 @@ typedef struct { // Of MBEDTLS_SSL_HASH_* uint8_t hash_type; } hashlib_hash_obj_t; + +#endif diff --git a/shared-module/hashlib/__init__.c b/shared-module/hashlib/__init__.c index f9bc787d49f..d2a19386431 100644 --- a/shared-module/hashlib/__init__.c +++ b/shared-module/hashlib/__init__.c @@ -7,20 +7,52 @@ #include "shared-bindings/hashlib/__init__.h" #include "shared-module/hashlib/__init__.h" +#include "mbedtls/version.h" + +#if MBEDTLS_VERSION_MAJOR >= 4 + +#include "psa/crypto.h" + +bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { + if (strcmp(algorithm, "sha1") == 0) { + self->hash_alg = PSA_ALG_SHA_1; + } else if (strcmp(algorithm, "sha256") == 0) { + self->hash_alg = PSA_ALG_SHA_256; + } else { + return false; + } + self->hash_op = psa_hash_operation_init(); + psa_hash_setup(&self->hash_op, self->hash_alg); + return true; +} + +#else + #include "mbedtls/ssl.h" +// In mbedtls 2.x, the _ret suffix functions are the recommended API. +// In mbedtls 3.x, the _ret suffix was removed and the base names return int. +#if MBEDTLS_VERSION_MAJOR < 3 +#define SHA1_STARTS mbedtls_sha1_starts_ret +#define SHA256_STARTS mbedtls_sha256_starts_ret +#else +#define SHA1_STARTS mbedtls_sha1_starts +#define SHA256_STARTS mbedtls_sha256_starts +#endif bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { if (strcmp(algorithm, "sha1") == 0) { self->hash_type = MBEDTLS_SSL_HASH_SHA1; mbedtls_sha1_init(&self->sha1); - mbedtls_sha1_starts_ret(&self->sha1); + SHA1_STARTS(&self->sha1); return true; } else if (strcmp(algorithm, "sha256") == 0) { self->hash_type = MBEDTLS_SSL_HASH_SHA256; mbedtls_sha256_init(&self->sha256); - mbedtls_sha256_starts_ret(&self->sha256, 0); + SHA256_STARTS(&self->sha256, 0); return true; } return false; } + +#endif diff --git a/shared-module/ssl/SSLSocket.c b/shared-module/ssl/SSLSocket.c index 8911fa2f454..2bc0ee19260 100644 --- a/shared-module/ssl/SSLSocket.c +++ b/shared-module/ssl/SSLSocket.c @@ -200,7 +200,7 @@ static int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { } -#if MBEDTLS_VERSION_MAJOR >= 3 +#if MBEDTLS_VERSION_MAJOR == 3 static int urandom_adapter(void *unused, unsigned char *buf, size_t n) { int result = common_hal_os_urandom(buf, n); if (result) { @@ -238,18 +238,24 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t mbedtls_x509_crt_init(&o->cacert); mbedtls_x509_crt_init(&o->cert); mbedtls_pk_init(&o->pkey); + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ctr_drbg_init(&o->ctr_drbg); + #endif #ifdef MBEDTLS_DEBUG_C // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose mbedtls_debug_set_threshold(4); #endif + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_entropy_init(&o->entropy); const byte seed[] = "upy"; int ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); if (ret != 0) { goto cleanup; } + #else + int ret; + #endif ret = mbedtls_ssl_config_defaults(&o->conf, server_side ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, @@ -273,7 +279,9 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t } else { mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); } + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); + #endif #ifdef MBEDTLS_DEBUG_C mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); #endif @@ -293,7 +301,9 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t mbedtls_ssl_set_bio(&o->ssl, o, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); if (self->cert_buf.buf != NULL) { - #if MBEDTLS_VERSION_MAJOR >= 3 + #if MBEDTLS_VERSION_MAJOR >= 4 + ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0); + #elif MBEDTLS_VERSION_MAJOR >= 3 ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0, urandom_adapter, NULL); #else ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0); @@ -318,8 +328,10 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t mbedtls_x509_crt_free(&o->cacert); mbedtls_ssl_free(&o->ssl); mbedtls_ssl_config_free(&o->conf); + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ctr_drbg_free(&o->ctr_drbg); mbedtls_entropy_free(&o->entropy); + #endif if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_type(&mp_type_MemoryError); @@ -382,8 +394,10 @@ void common_hal_ssl_sslsocket_close(ssl_sslsocket_obj_t *self) { mbedtls_x509_crt_free(&self->cacert); mbedtls_ssl_free(&self->ssl); mbedtls_ssl_config_free(&self->conf); + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ctr_drbg_free(&self->ctr_drbg); mbedtls_entropy_free(&self->entropy); + #endif } static void do_handshake(ssl_sslsocket_obj_t *self) { @@ -408,8 +422,10 @@ static void do_handshake(ssl_sslsocket_obj_t *self) { mbedtls_x509_crt_free(&self->cacert); mbedtls_ssl_free(&self->ssl); mbedtls_ssl_config_free(&self->conf); + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_ctr_drbg_free(&self->ctr_drbg); mbedtls_entropy_free(&self->entropy); + #endif if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_type(&mp_type_MemoryError); diff --git a/shared-module/ssl/SSLSocket.h b/shared-module/ssl/SSLSocket.h index f7f3d1ae83c..9373734d27c 100644 --- a/shared-module/ssl/SSLSocket.h +++ b/shared-module/ssl/SSLSocket.h @@ -15,15 +15,20 @@ #include "mbedtls/ssl.h" #include "mbedtls/x509_crt.h" #include "mbedtls/pk.h" +#include "mbedtls/version.h" +#if MBEDTLS_VERSION_MAJOR < 4 #include "mbedtls/entropy.h" #include "mbedtls/ctr_drbg.h" +#endif typedef struct ssl_sslsocket_obj { mp_obj_base_t base; mp_obj_t sock_obj; ssl_sslcontext_obj_t *ssl_context; + #if MBEDTLS_VERSION_MAJOR < 4 mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; + #endif mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt cacert; diff --git a/tools/ci_fetch_deps.py b/tools/ci_fetch_deps.py index be190ad6606..339eec28712 100644 --- a/tools/ci_fetch_deps.py +++ b/tools/ci_fetch_deps.py @@ -59,6 +59,7 @@ def _all_submodules(): "espressif": [ "extmod/ulab/", "lib/certificates/", + "lib/mp3/", "lib/protomatter/", "lib/quirc/", "lib/tlsf", From ea772281519c10e9940b9a4da2326ccb6e8de725 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 3 Apr 2026 17:20:22 -0400 Subject: [PATCH 373/876] atmel-samd building and passing smoke tets --- extmod/vfs_fat.c | 71 ++++++++++++++++++ ports/stm/mpconfigport_nanbox.h | 25 ------- py/asmxtensa.h | 3 +- py/circuitpy_mpconfig.h | 6 +- py/emitcommon.c | 4 ++ py/malloc.c | 18 +++-- py/misc.h | 8 +-- py/mpconfig.h | 6 +- py/mpprint.c | 124 ++++++++++++++++---------------- py/obj.h | 24 ++++--- py/objarray.c | 47 ++++++------ py/objlist.c | 5 +- py/objmodule.c | 1 + py/objmodule.h | 3 + py/parsenum.c | 4 ++ py/runtime.c | 2 + py/runtime.h | 14 ++-- py/sequence.c | 4 +- tests/frozen/frozentest.mpy | Bin 200 -> 196 bytes 19 files changed, 224 insertions(+), 145 deletions(-) delete mode 100644 ports/stm/mpconfigport_nanbox.h diff --git a/extmod/vfs_fat.c b/extmod/vfs_fat.c index cb5fb649a1e..95ed79eb18b 100644 --- a/extmod/vfs_fat.c +++ b/extmod/vfs_fat.c @@ -455,6 +455,77 @@ static mp_obj_t vfs_fat_umount(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_umount_obj, vfs_fat_umount); +// CIRCUITPY-CHANGE +static mp_obj_t vfs_fat_utime(mp_obj_t vfs_in, mp_obj_t path_in, mp_obj_t times_in) { + mp_obj_fat_vfs_t *self = MP_OBJ_TO_PTR(vfs_in); + const char *path = mp_obj_str_get_str(path_in); + if (!mp_obj_is_tuple_compatible(times_in)) { + mp_raise_type_arg(&mp_type_TypeError, times_in); + } + + mp_obj_t *otimes; + mp_obj_get_array_fixed_n(times_in, 2, &otimes); + + // Validate that both elements of the tuple are int and discard the second one + int time[2]; + time[0] = mp_obj_get_int(otimes[0]); + time[1] = mp_obj_get_int(otimes[1]); + timeutils_struct_time_t tm; + timeutils_seconds_since_epoch_to_struct_time(time[0], &tm); + + FILINFO fno; + fno.fdate = (WORD)(((tm.tm_year - 1980) * 512U) | tm.tm_mon * 32U | tm.tm_mday); + fno.ftime = (WORD)(tm.tm_hour * 2048U | tm.tm_min * 32U | tm.tm_sec / 2U); + FRESULT res = f_utime(&self->fatfs, path, &fno); + if (res != FR_OK) { + mp_raise_OSError_fresult(res); + } + + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(fat_vfs_utime_obj, vfs_fat_utime); + +static mp_obj_t vfs_fat_getreadonly(mp_obj_t self_in) { + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(!filesystem_is_writable_by_python(self)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getreadonly_obj, vfs_fat_getreadonly); + +static MP_PROPERTY_GETTER(fat_vfs_readonly_obj, + (mp_obj_t)&fat_vfs_getreadonly_obj); + +#if MICROPY_FATFS_USE_LABEL +static mp_obj_t vfs_fat_getlabel(mp_obj_t self_in) { + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + char working_buf[12]; + FRESULT res = f_getlabel(&self->fatfs, working_buf, NULL); + if (res != FR_OK) { + mp_raise_OSError_fresult(res); + } + return mp_obj_new_str(working_buf, strlen(working_buf)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(fat_vfs_getlabel_obj, vfs_fat_getlabel); + +static mp_obj_t vfs_fat_setlabel(mp_obj_t self_in, mp_obj_t label_in) { + fs_user_mount_t *self = MP_OBJ_TO_PTR(self_in); + verify_fs_writable(self); + const char *label_str = mp_obj_str_get_str(label_in); + FRESULT res = f_setlabel(&self->fatfs, label_str); + if (res != FR_OK) { + if (res == FR_WRITE_PROTECTED) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Read-only filesystem")); + } + mp_raise_OSError_fresult(res); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(fat_vfs_setlabel_obj, vfs_fat_setlabel); + +static MP_PROPERTY_GETSET(fat_vfs_label_obj, + (mp_obj_t)&fat_vfs_getlabel_obj, + (mp_obj_t)&fat_vfs_setlabel_obj); +#endif + static const mp_rom_map_elem_t fat_vfs_locals_dict_table[] = { // CIRCUITPY-CHANGE: correct name #if FF_FS_REENTRANT diff --git a/ports/stm/mpconfigport_nanbox.h b/ports/stm/mpconfigport_nanbox.h deleted file mode 100644 index 164850112e0..00000000000 --- a/ports/stm/mpconfigport_nanbox.h +++ /dev/null @@ -1,25 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2016 Damien P. George -// -// SPDX-License-Identifier: MIT - -#pragma once - -// select nan-boxing object model -#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_D) - -// native emitters don't work with nan-boxing -#define MICROPY_EMIT_X86 (0) -#define MICROPY_EMIT_X64 (0) -#define MICROPY_EMIT_THUMB (0) -#define MICROPY_EMIT_ARM (0) - -#include - -typedef int64_t mp_int_t; -typedef uint64_t mp_uint_t; -#define UINT_FMT "%llu" -#define INT_FMT "%lld" - -#include diff --git a/py/asmxtensa.h b/py/asmxtensa.h index 559b3cacd5d..ed98c9d7305 100644 --- a/py/asmxtensa.h +++ b/py/asmxtensa.h @@ -311,7 +311,8 @@ void asm_xtensa_l32r(asm_xtensa_t *as, mp_uint_t reg, mp_uint_t label); #define ASM_XTENSA_REG_TEMPORARY ASM_XTENSA_REG_A6 #define ASM_XTENSA_REG_TEMPORARY_WIN ASM_XTENSA_REG_A12 -#if GENERIC_ASM_API +// CIRCUITPY-CHANGE: prevent #if warning +#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/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index fc74144dc80..e83c6175255 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -17,6 +17,10 @@ // Always 1: defined in circuitpy_mpconfig.mk // #define CIRCUITPY (1) +#ifndef MP_SSIZE_MAX +#define MP_SSIZE_MAX (0x7fffffff) +#endif + // REPR_C encodes qstrs, 31-bit ints, and 30-bit floats in a single 32-bit word. #ifndef MICROPY_OBJ_REPR #define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C) @@ -303,12 +307,10 @@ typedef long mp_off_t; #ifdef LONGINT_IMPL_MPZ #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_MPZ) -#define MP_SSIZE_MAX (0x7fffffff) #endif #ifdef LONGINT_IMPL_LONGLONG #define MICROPY_LONGINT_IMPL (MICROPY_LONGINT_IMPL_LONGLONG) -#define MP_SSIZE_MAX (0x7fffffff) #endif #ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS diff --git a/py/emitcommon.c b/py/emitcommon.c index 1f701db80a0..1369c544c54 100644 --- a/py/emitcommon.c +++ b/py/emitcommon.c @@ -79,12 +79,16 @@ static bool strictly_equal(mp_obj_t a, mp_obj_t b) { #if MICROPY_PY_BUILTINS_FLOAT && MICROPY_COMP_CONST_FLOAT if (a_type == &mp_type_float) { mp_float_t a_val = mp_obj_float_get(a); + // CIRCUITPY-CHANGE: ignore float equal warning + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" if (a_val == (mp_float_t)0.0) { // Although 0.0 == -0.0, they are not strictly_equal and // must be stored as two different constants in .mpy files mp_float_t b_val = mp_obj_float_get(b); return signbit(a_val) == signbit(b_val); } + #pragma GCC diagnostic pop } #endif return true; diff --git a/py/malloc.c b/py/malloc.c index c11fd507145..36eb10b7b85 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -70,6 +70,7 @@ #error MICROPY_ENABLE_FINALISER requires MICROPY_ENABLE_GC #endif +// CIRCUITPY-CHANGE: Add selective collect support to malloc to optimize GC for large buffers #if MICROPY_ENABLE_SELECTIVE_COLLECT #error MICROPY_ENABLE_SELECTIVE_COLLECT requires MICROPY_ENABLE_GC #endif @@ -125,32 +126,35 @@ void *m_malloc_helper(size_t num_bytes, uint8_t flags) { } void *m_malloc(size_t num_bytes) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: use helper return m_malloc_helper(num_bytes, M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); } void *m_malloc_maybe(size_t num_bytes) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: use helper return m_malloc_helper(num_bytes, M_MALLOC_COLLECT); } #if MICROPY_ENABLE_FINALISER void *m_malloc_with_finaliser(size_t num_bytes) { - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: use helper return m_malloc_helper(num_bytes, M_MALLOC_COLLECT | M_MALLOC_WITH_FINALISER); +} #endif void *m_malloc0(size_t num_bytes) { - // CIRCUITPY-CHANGE - return m_malloc_helper(num_bytes, M_MALLOC_ENSURE_ZEROED | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); + // CIRCUITPY-CHANGE: use helper + return m_malloc_helper(num_bytes, + (MICROPY_GC_CONSERVATIVE_CLEAR ? 0 : M_MALLOC_ENSURE_ZEROED) + | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); } -// CIRCUITPY-CHANGE: selective collect +// CIRCUITPY-CHANGE: add selective collect void *m_malloc_without_collect(size_t num_bytes) { return m_malloc_helper(num_bytes, M_MALLOC_RAISE_ERROR); } -// CIRCUITPY-CHANGE: selective collect +// CIRCUITPY-CHANGE: add selective collect void *m_malloc_maybe_without_collect(size_t num_bytes) { return m_malloc_helper(num_bytes, 0); diff --git a/py/misc.h b/py/misc.h index b1bdb9517a4..d5d7950574f 100644 --- a/py/misc.h +++ b/py/misc.h @@ -35,7 +35,8 @@ #include #include #include -#if __cplusplus // Required on at least one compiler to get ULLONG_MAX +// CIRCUITPY-CHANGE: #ifdef instead of #if +#ifdef __cplusplus // Required on at least one compiler to get ULLONG_MAX #include #else #include @@ -84,7 +85,8 @@ typedef unsigned int uint; #if defined(_MSC_VER) || defined(__cplusplus) #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)1) #else -// CIRCUITPY-CHANGE: defined()#if defined(__clang__) +// CIRCUITPY-CHANGE: defined() +#if defined(__clang__) #pragma GCC diagnostic ignored "-Wgnu-folding-constant" #endif #define MP_STATIC_ASSERT_NONCONSTEXPR(cond) ((void)sizeof(char[1 - 2 * !(cond)])) @@ -456,8 +458,6 @@ static inline uint32_t mp_popcount(uint32_t x) { #define mp_clzll(x) __builtin_clzll(x) #define mp_ctz(x) __builtin_ctz(x) #define mp_check(x) (x) -// CIRCUITPY-CHANGE: defined() -#if defined __has_builtin #if __has_builtin(__builtin_popcount) #define mp_popcount(x) __builtin_popcount(x) #else diff --git a/py/mpconfig.h b/py/mpconfig.h index e970ea3ba7b..0ef98009205 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -2384,7 +2384,6 @@ typedef time_t mp_timestamp_t; #ifndef MP_NORETURN #define MP_NORETURN __attribute__((noreturn)) #endif -#endif // INT_FMT #if !MICROPY_PREVIEW_VERSION_2 #define NORETURN MP_NORETURN @@ -2435,6 +2434,11 @@ typedef time_t mp_timestamp_t; #define MP_COLD __attribute__((cold)) #endif +// CIRCUITPY-CHANGE: avoid undefined warnings +#ifndef MICROPY_HAL_HAS_STDIO_MODE_SWITCH +#define MICROPY_HAL_HAS_STDIO_MODE_SWITCH (0) +#endif + // To annotate that code is unreachable #ifndef MP_UNREACHABLE #if defined(__GNUC__) diff --git a/py/mpprint.c b/py/mpprint.c index 605b8544f7f..b09ee398b6d 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -408,14 +408,6 @@ int mp_print_float(const mp_print_t *print, mp_float_t f, char fmt, unsigned int } #endif -// CIRCUITPY-CHANGE -static int print_str_common(const mp_print_t *print, const char *str, int prec, size_t len, int flags, int fill, int width) { - if (prec >= 0 && (size_t)prec < len) { - len = prec; - } - return mp_print_strn(print, str, len, flags, fill, width); -} - int mp_printf(const mp_print_t *print, const char *fmt, ...) { va_list ap; va_start(ap, fmt); @@ -542,27 +534,19 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { qstr qst = va_arg(args, qstr); size_t len; const char *str = (const char *)qstr_data(qst, &len); - // CIRCUITPY-CHANGE - chrs += print_str_common(print, str, prec, len, flags, fill, width); - break; - } - // CIRCUITPY-CHANGE: new code to print compressed strings - case 'S': { - mp_rom_error_text_t arg = va_arg(args, mp_rom_error_text_t); - size_t len_with_nul = decompress_length(arg); - size_t len = len_with_nul - 1; - char str[len_with_nul]; - decompress(arg, str); - chrs += print_str_common(print, str, prec, len, flags, fill, width); + if (prec >= 0 && (size_t)prec < len) { + len = prec; + } + chrs += mp_print_strn(print, str, len, flags, fill, width); break; } case 's': { const char *str = va_arg(args, const char *); #ifndef NDEBUG // With debugging enabled, catch printing of null string pointers - if (str == NULL) { - // CIRCUITPY-CHANGE - str = "(null)"; + if (prec != 0 && str == NULL) { + chrs += mp_print_strn(print, "(null)", 6, flags, fill, width); + break; } #endif size_t len = strlen(str); @@ -572,42 +556,57 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { chrs += mp_print_strn(print, str, len, flags, fill, width); break; } - // CIRCUITPY-CHANGE: separate from p and P - case 'd': { - mp_int_t val; - if (long_arg) { - val = va_arg(args, long int); - } else { - val = va_arg(args, int); - } - chrs += mp_print_int(print, val, 1, 10, 'a', flags, fill, width); - break; - } + case 'd': + case 'p': + case 'P': case 'u': case 'x': case 'X': { - int base = 16 - ((*fmt + 1) & 6); // maps char u/x/X to base 10/16/16 - char fmt_c = (*fmt & 0xf0) - 'P' + 'A'; // maps char u/x/X to char a/a/A + char fmt_chr = *fmt; mp_uint_t val; - if (long_arg) { - val = va_arg(args, unsigned long int); + if (fmt_chr == 'p' || fmt_chr == 'P') { + val = va_arg(args, uintptr_t); + } + #if SUPPORT_LL_FORMAT + else if (long_long_arg) { + val = va_arg(args, unsigned long long); + } + #endif + #if SUPPORT_L_FORMAT + else if (long_arg) { + if (sizeof(long) != sizeof(mp_uint_t) && fmt_chr == 'd') { + val = va_arg(args, long); + } else { + val = va_arg(args, unsigned long); + } + } + #endif + else { + if (sizeof(int) != sizeof(mp_uint_t) && fmt_chr == 'd') { + val = va_arg(args, int); + } else { + val = va_arg(args, unsigned); + } + } + int base; + // Map format char x/p/X/P to a/a/A/A for hex letters. + // It doesn't matter what d/u map to. + char fmt_c = (fmt_chr & 0xf0) - 'P' + 'A'; + if (fmt_chr == 'd' || fmt_chr == 'u') { + base = 10; } else { - val = va_arg(args, unsigned int); + base = 16; } - chrs += mp_print_int(print, val, 0, base, fmt_c, flags, fill, width); + if (fmt_chr == 'p' || fmt_chr == 'P') { + #if SUPPORT_INT_BASE_PREFIX + chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags | PF_FLAG_SHOW_PREFIX, fill, width); + #else + chrs += mp_print_strn(print, "0x", 2, flags, fill, width); + #endif + } + chrs += mp_print_int(print, val, fmt_chr == 'd', base, fmt_c, flags, fill, width); break; } - case 'p': - case 'P': // don't bother to handle upcase for 'P' - // Use unsigned long int to work on both ILP32 and LP64 systems - // CIRCUITPY-CHANGE: print 0x prefix - #if SUPPORT_INT_BASE_PREFIX - chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags | PF_FLAG_SHOW_PREFIX, fill, width); - #else - print->print_strn(print->data, "0x", 2); - chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags, fill, width) + 2; - #endif - break; #if MICROPY_PY_BUILTINS_FLOAT case 'e': case 'E': @@ -624,18 +623,21 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { break; } #endif - // Because 'l' is eaten above, another 'l' means %ll. We need to support - // this length specifier for OBJ_REPR_D (64-bit NaN boxing). - // TODO Either enable this unconditionally, or provide a specific config var. - #if (MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D) || defined(_WIN64) - case 'l': { - unsigned long long int arg_value = va_arg(args, unsigned long long int); - ++fmt; - assert(*fmt == 'u' || *fmt == 'd' || !"unsupported fmt char"); - chrs += mp_print_int(print, arg_value, *fmt == 'd', 10, 'a', flags, fill, width); + + // CIRCUITPY-CHANGE: new format code to print compressed strings + case 'S': { + mp_rom_error_text_t arg = va_arg(args, mp_rom_error_text_t); + size_t len_with_nul = decompress_length(arg); + size_t len = len_with_nul - 1; + char str[len_with_nul]; + decompress(arg, str); + if (prec >= 0 && (size_t)prec < len) { + len = prec; + } + chrs += mp_print_strn(print, str, len, flags, fill, width); break; } - #endif + default: // if it's not %% then it's an unsupported format character assert(*fmt == '%' || !"unsupported fmt char"); diff --git a/py/obj.h b/py/obj.h index e85505ff3ae..bddb86605e3 100644 --- a/py/obj.h +++ b/py/obj.h @@ -871,7 +871,7 @@ extern const mp_obj_type_t mp_type_bytearray; extern const mp_obj_type_t mp_type_memoryview; extern const mp_obj_type_t mp_type_float; extern const mp_obj_type_t mp_type_complex; -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: add traceback support extern const mp_obj_type_t mp_type_traceback; extern const mp_obj_type_t mp_type_tuple; extern const mp_obj_type_t mp_type_list; @@ -933,7 +933,7 @@ extern const mp_obj_type_t mp_type_ImportError; extern const mp_obj_type_t mp_type_IndentationError; extern const mp_obj_type_t mp_type_IndexError; extern const mp_obj_type_t mp_type_KeyboardInterrupt; -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: add ReloadException extern const mp_obj_type_t mp_type_ReloadException; extern const mp_obj_type_t mp_type_KeyError; extern const mp_obj_type_t mp_type_LookupError; @@ -941,9 +941,9 @@ extern const mp_obj_type_t mp_type_MemoryError; extern const mp_obj_type_t mp_type_NameError; extern const mp_obj_type_t mp_type_NotImplementedError; extern const mp_obj_type_t mp_type_OSError; -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: add ConnectionError extern const mp_obj_type_t mp_type_ConnectionError; -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: add BrokenPipeError extern const mp_obj_type_t mp_type_BrokenPipeError; extern const mp_obj_type_t mp_type_OverflowError; extern const mp_obj_type_t mp_type_RuntimeError; @@ -951,6 +951,8 @@ extern const mp_obj_type_t mp_type_StopAsyncIteration; extern const mp_obj_type_t mp_type_StopIteration; extern const mp_obj_type_t mp_type_SyntaxError; extern const mp_obj_type_t mp_type_SystemExit; +// CIRCUITPY-CHANGE: add TimeoutError +extern const mp_obj_type_t mp_type_TimeoutError; extern const mp_obj_type_t mp_type_TypeError; extern const mp_obj_type_t mp_type_UnicodeError; extern const mp_obj_type_t mp_type_ValueError; @@ -1075,10 +1077,10 @@ mp_obj_t mp_obj_new_str_from_utf8_vstr(vstr_t *vstr); // input data must be vali #endif mp_obj_t mp_obj_new_bytes_from_vstr(vstr_t *vstr); mp_obj_t mp_obj_new_bytes(const byte *data, size_t len); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine mp_obj_t mp_obj_new_bytes_of_zeros(size_t len); mp_obj_t mp_obj_new_bytearray(size_t n, const void *items); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine mp_obj_t mp_obj_new_bytearray_of_zeros(size_t n); mp_obj_t mp_obj_new_bytearray_by_ref(size_t n, void *items); #if MICROPY_PY_BUILTINS_FLOAT @@ -1114,7 +1116,7 @@ mp_obj_t mp_obj_new_memoryview(byte typecode, size_t nitems, void *items); const mp_obj_type_t *mp_obj_get_type(mp_const_obj_t o_in); const char *mp_obj_get_type_str(mp_const_obj_t o_in); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine #define mp_obj_get_type_qstr(o_in) (mp_obj_get_type((o_in))->name) bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo); // arguments should be type objects mp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type); @@ -1122,7 +1124,7 @@ mp_obj_t mp_obj_cast_to_native_base(mp_obj_t self_in, mp_const_obj_t native_type void mp_obj_print_helper(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind); void mp_obj_print(mp_obj_t o, mp_print_kind_t kind); void mp_obj_print_exception(const mp_print_t *print, mp_obj_t exc); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine void mp_obj_print_exception_with_limit(const mp_print_t *print, mp_obj_t exc, mp_int_t limit); bool mp_obj_is_true(mp_obj_t arg); @@ -1187,7 +1189,7 @@ bool mp_obj_exception_match(mp_obj_t exc, mp_const_obj_t exc_type); void mp_obj_exception_clear_traceback(mp_obj_t self_in); void mp_obj_exception_add_traceback(mp_obj_t self_in, qstr file, size_t line, qstr block); void mp_obj_exception_get_traceback(mp_obj_t self_in, size_t *n, size_t **values); -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: new routine mp_obj_t mp_obj_exception_get_traceback_obj(mp_obj_t self_in); mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in); mp_obj_t mp_obj_exception_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args); @@ -1264,7 +1266,7 @@ void mp_obj_tuple_del(mp_obj_t self_in); mp_int_t mp_obj_tuple_hash(mp_obj_t self_in); // list -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: public routine mp_obj_t mp_obj_list_clear(mp_obj_t self_in); mp_obj_t mp_obj_list_append(mp_obj_t self_in, mp_obj_t arg); mp_obj_t mp_obj_list_remove(mp_obj_t self_in, mp_obj_t value); @@ -1360,7 +1362,7 @@ typedef struct _mp_rom_obj_static_class_method_t { } mp_rom_obj_static_class_method_t; // property -// CIRCUITPY-CHANGE +// CIRCUITPY-CHANGE: extra args const mp_obj_t *mp_obj_property_get(mp_obj_t self_in, size_t *n_proxy); // sequence helpers diff --git a/py/objarray.c b/py/objarray.c index 5b63f693698..de6e158b057 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -300,7 +300,7 @@ static void memoryview_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_array_t *self = MP_OBJ_TO_PTR(self_in); dest[0] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->typecode & TYPECODE_MASK, NULL)); } - // CIRCUITPY-CHANGE: prevent warning + // CIRCUITPY-CHANGE: add MICROPY_CPYTHON_COMPAT #if MICROPY_PY_BUILTINS_BYTES_HEX || MICROPY_CPYTHON_COMPAT else { // Need to forward to locals dict. @@ -500,35 +500,37 @@ static mp_obj_t array_extend(mp_obj_t self_in, mp_obj_t arg_in) { return mp_const_none; } - // convert byte count to element count - size_t len = arg_bufinfo.len / sz; + size_t sz = mp_binary_get_size('@', self->typecode, NULL); - // make sure we have enough room to extend - // TODO: alloc policy; at the moment we go conservative - if (self->free < len) { - self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz); - self->free = 0; - } else { - self->free -= len; - } + // convert byte count to element count + size_t len = arg_bufinfo.len / sz; - // extend - mp_seq_copy((byte *)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte); - self->len += len; - } else { - // Otherwise argument must be an iterable of items to append - mp_obj_t iterable = mp_getiter(arg_in, NULL); - mp_obj_t item; - while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { - array_append(self_in, item); + // make sure we have enough room to extend + // TODO: alloc policy; at the moment we go conservative + if (self->free < len) { + self->items = m_renew(byte, self->items, (self->len + self->free) * sz, (self->len + len) * sz); + self->free = 0; + + if (self_in == arg_in) { + // Get arg_bufinfo again in case self->items has moved + // + // (Note not possible to handle case that arg_in is a memoryview into self) + mp_get_buffer_raise(arg_in, &arg_bufinfo, MP_BUFFER_READ); } + } else { + self->free -= len; } + + // extend + mp_seq_copy((byte *)self->items + self->len * sz, arg_bufinfo.buf, len * sz, byte); + self->len += len; + return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(mp_obj_array_extend_obj, array_extend); #endif -// CIRCUITPY-CHANGE: buffer_finder used belo +// CIRCUITPY-CHANGE: buffer_finder used below #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_CPYTHON_COMPAT static mp_obj_t buffer_finder(size_t n_args, const mp_obj_t *args, int direction, bool is_index) { mp_check_self(mp_obj_is_type(args[0], &mp_type_bytearray)); @@ -564,12 +566,9 @@ static mp_obj_t buffer_finder(size_t n_args, const mp_obj_t *args, int direction } else { return MP_OBJ_NEW_SMALL_INT(-1); } - } else { - self->free -= len; } return MP_OBJ_NEW_SMALL_INT(p - (const byte *)haystack_bufinfo.buf); } - // CIRCUITPY-CHANGE: provides find, rfind, index static mp_obj_t buffer_find(size_t n_args, const mp_obj_t *args) { return buffer_finder(n_args, args, 1, false); diff --git a/py/objlist.c b/py/objlist.c index beb647917d9..83bade273bf 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -221,7 +221,7 @@ static mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { if (value == MP_OBJ_NULL) { // delete // CIRCUITPY-CHANGE: handle subclassing - mp_obj_t args[2] = {MP_OBJ_FROM_PTR(self), index}; + mp_obj_t args[2] = {MP_OBJ_FROM_PTR(self_in), index}; list_pop(2, args); return mp_const_none; } else if (value == MP_OBJ_SENTINEL) { @@ -276,12 +276,11 @@ static mp_obj_t list_extend(mp_obj_t self_in, mp_obj_t arg_in) { } // CIRCUITPY-CHANGE: provide version for C use outside this file -inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self_in, size_t index) { +inline mp_obj_t mp_obj_list_pop(mp_obj_list_t *self, size_t index) { if (self->len == 0) { // CIRCUITPY-CHANGE: more specific mp_raise mp_raise_IndexError_varg(MP_ERROR_TEXT("pop from empty %q"), MP_QSTR_list); } - size_t index = mp_get_index(self->base.type, self->len, n_args == 1 ? MP_OBJ_NEW_SMALL_INT(-1) : args[1], false); mp_obj_t ret = self->items[index]; self->len -= 1; memmove(self->items + index, self->items + index + 1, (self->len - index) * sizeof(mp_obj_t)); diff --git a/py/objmodule.c b/py/objmodule.c index 60b0368abac..84b6a10f9ab 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -208,6 +208,7 @@ mp_obj_t mp_module_get_builtin(qstr module_name, bool extensible) { // the old behaviour of the u-prefix being used to force a built-in // import. // CIRCUITPY-CHANGE: Don't look for `ufoo`. + #endif return MP_OBJ_NULL; } diff --git a/py/objmodule.h b/py/objmodule.h index 78e4da3cac6..221392ccce4 100644 --- a/py/objmodule.h +++ b/py/objmodule.h @@ -32,6 +32,9 @@ // Only include module definitions when not doing qstr extraction, because the // qstr extraction stage also generates this module definition header file. #include "genhdr/moduledefs.h" +// CIRCUITPY-CHANGE: avoid undef warning +#else +#define MICROPY_HAVE_REGISTERED_EXTENSIBLE_MODULES (0) #endif extern const mp_map_t mp_builtin_module_map; diff --git a/py/parsenum.c b/py/parsenum.c index 91340fd2a18..c52f040e1a2 100644 --- a/py/parsenum.c +++ b/py/parsenum.c @@ -226,9 +226,13 @@ typedef enum { // Helper to compute `num * (10.0 ** dec_exp)` mp_large_float_t mp_decimal_exp(mp_large_float_t num, int dec_exp) { + // CIRCUITPY-CHANGE: ignore float equal warning + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" if (dec_exp == 0 || num == (mp_large_float_t)(0.0)) { return num; } + #pragma GCC diagnostic pop #if MICROPY_FLOAT_FORMAT_IMPL == MICROPY_FLOAT_FORMAT_IMPL_EXACT diff --git a/py/runtime.c b/py/runtime.c index 0b62500cc2a..81abc3de875 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -1929,6 +1929,8 @@ MP_COLD MP_NORETURN void mp_raise_NotImplementedError(mp_rom_error_text_t msg) { mp_raise_msg(&mp_type_NotImplementedError, msg); } +#endif + // CIRCUITPY-CHANGE: added MP_COLD MP_NORETURN void mp_raise_NotImplementedError_varg(mp_rom_error_text_t fmt, ...) { va_list argptr; diff --git a/py/runtime.h b/py/runtime.h index 8bdd1982b96..22ed9c3eaf9 100644 --- a/py/runtime.h +++ b/py/runtime.h @@ -26,17 +26,23 @@ #ifndef MICROPY_INCLUDED_PY_RUNTIME_H #define MICROPY_INCLUDED_PY_RUNTIME_H +#include + #include "py/mpstate.h" #include "py/pystack.h" #include "py/cstack.h" +// CIRCUITPY-CHANGE +#include "supervisor/linker.h" +#include "supervisor/shared/translate/translate.h" + +// For use with mp_call_function_1_from_nlr_jump_callback. // Initialize an nlr_jump_callback_node_call_function_1_t struct for use with // nlr_push_jump_callback(&ctx.callback, mp_call_function_1_from_nlr_jump_callback); #define MP_DEFINE_NLR_JUMP_CALLBACK_FUNCTION_1(ctx, f, a) \ - nlr_jump_callback_node_call_function_1_t ctx = { \ - .func = (void (*)(void *))(f), \ - .arg = (a), \ - } + nlr_jump_callback_node_call_function_1_t ctx; \ + ctx.func = (void (*)(void *))(f); \ + ctx.arg = (a) typedef enum { MP_VM_RETURN_NORMAL, diff --git a/py/sequence.c b/py/sequence.c index 490f6d9c672..33cc55eac40 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -36,11 +36,11 @@ // CIRCUITPY-CHANGE: detect sequence overflow // Detect when a multiply causes an overflow. size_t mp_seq_multiply_len(size_t item_sz, size_t len) { - size_t new_len; + mp_int_t new_len; if (mp_mul_mp_int_t_overflow(item_sz, len, &new_len)) { mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow")); } - return new_len; + return (size_t) new_len; } // Implements backend of sequence * integer operation. Assumes elements are diff --git a/tests/frozen/frozentest.mpy b/tests/frozen/frozentest.mpy index c16da5d20fb73f0e09e3136812783ff305a25b0f..7f1163956bafeacef9bda191aa3376fbf589c350 100644 GIT binary patch delta 7 OcmX@Xc!Y5x(-8m**aGGN delta 12 TcmX@Yc!H7X|Gx=Gn79}KBo_qk From 4d7a17612e48fb0a4b66612d43009275ab93e56c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 3 Apr 2026 22:32:06 -0400 Subject: [PATCH 374/876] fix ports/unix --- ports/unix/Makefile | 2 +- ports/unix/coverage.c | 73 ++++++++++++++++++++++++++------------ ports/unix/coveragecpp.cpp | 18 ++++++++-- ports/unix/main.c | 8 +++-- ports/unix/mphalport.h | 15 +++++++- py/bc.h | 2 +- py/mpconfig.h | 5 --- py/obj.h | 2 +- shared/runtime/pyexec.c | 3 +- 9 files changed, 91 insertions(+), 37 deletions(-) diff --git a/ports/unix/Makefile b/ports/unix/Makefile index fe73ae5278b..32e3b44b227 100644 --- a/ports/unix/Makefile +++ b/ports/unix/Makefile @@ -50,7 +50,7 @@ INC += -I$(BUILD) # compiler settings CWARN = -Wall -Werror // CIRCUITPY-CHANGE: add -Wno-missing-field-initializers -CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion +CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion -Wno-missing-field-initializers CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA) # Force the use of 64-bits for file sizes in C library functions on 32-bit platforms. diff --git a/ports/unix/coverage.c b/ports/unix/coverage.c index ba20dba3595..49426f0f3e8 100644 --- a/ports/unix/coverage.c +++ b/ports/unix/coverage.c @@ -185,6 +185,8 @@ static void pairheap_test(size_t nops, int *ops) { mp_printf(&mp_plat_print, "\n"); } +// CIRCUITPY-CHANGE: not turned on in CircuitPython +#if MICROPY_SCHEDULER_STATIC_NODES static mp_sched_node_t mp_coverage_sched_node; static bool coverage_sched_function_continue; @@ -196,6 +198,7 @@ static void coverage_sched_function(mp_sched_node_t *node) { mp_sched_schedule_node(&mp_coverage_sched_node, coverage_sched_function); } } +#endif // function to run extra tests for things that can't be checked by scripts static mp_obj_t extra_coverage(void) { @@ -589,6 +592,22 @@ static mp_obj_t extra_coverage(void) { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); } + // mp_obj_get_uint from a non-int object (should raise exception) + if (nlr_push(&nlr) == 0) { + mp_obj_get_uint(mp_const_none); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + + // mp_obj_int_get_ll from a non-int object (should raise exception) + if (nlr_push(&nlr) == 0) { + mp_obj_get_ll(mp_const_none); + nlr_pop(); + } else { + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + } + // call mp_obj_new_exception_args (it's a part of the public C API and not used in the core) mp_obj_print_exception(&mp_plat_print, mp_obj_new_exception_args(&mp_type_ValueError, 0, NULL)); } @@ -598,26 +617,6 @@ static mp_obj_t extra_coverage(void) { mp_emitter_warning(MP_PASS_CODE_SIZE, "test"); } - // format float - { - mp_printf(&mp_plat_print, "# format float\n"); - - // format with inadequate buffer size - char buf[5]; - mp_format_float(1, buf, sizeof(buf), 'g', 0, '+'); - mp_printf(&mp_plat_print, "%s\n", buf); - - // format with just enough buffer so that precision must be - // set from 0 to 1 twice - char buf2[8]; - mp_format_float(1, buf2, sizeof(buf2), 'g', 0, '+'); - mp_printf(&mp_plat_print, "%s\n", buf2); - - // format where precision is trimmed to avoid buffer overflow - mp_format_float(1, buf2, sizeof(buf2), 'e', 0, '+'); - mp_printf(&mp_plat_print, "%s\n", buf2); - } - // binary { mp_printf(&mp_plat_print, "# binary\n"); @@ -641,14 +640,26 @@ static mp_obj_t extra_coverage(void) { fun_bc.context = &context; fun_bc.child_table = NULL; fun_bc.bytecode = (const byte *)"\x01"; // just needed for n_state + #if MICROPY_PY_SYS_SETTRACE + struct _mp_raw_code_t rc = {}; + fun_bc.rc = &rc; + #endif mp_code_state_t *code_state = m_new_obj_var(mp_code_state_t, state, mp_obj_t, 1); code_state->fun_bc = &fun_bc; code_state->ip = (const byte *)"\x00"; // just needed for an invalid opcode code_state->sp = &code_state->state[0]; code_state->exc_sp_idx = 0; code_state->old_globals = NULL; + #if MICROPY_STACKLESS + code_state->prev = NULL; + #endif + #if MICROPY_PY_SYS_SETTRACE + code_state->prev_state = NULL; + code_state->frame = NULL; + #endif + mp_vm_return_kind_t ret = mp_execute_bytecode(code_state, MP_OBJ_NULL); - mp_printf(&mp_plat_print, "%d %d\n", ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError); + mp_printf(&mp_plat_print, "%d %d\n", (int)ret, mp_obj_get_type(code_state->state[0]) == &mp_type_NotImplementedError); } // scheduler @@ -705,9 +716,25 @@ static mp_obj_t extra_coverage(void) { mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); } mp_handle_pending(true); + + // CIRCUITPY-CHANGE: not turned on in CircuitPython + #if MICROPY_SCHEDULER_STATIC_NODES + coverage_sched_function_continue = true; + mp_sched_schedule_node(&mp_coverage_sched_node, coverage_sched_function); + for (int i = 0; i < 3; ++i) { + mp_printf(&mp_plat_print, "loop\n"); + mp_handle_pending(true); + } + // Clear this flag to prevent the function scheduling itself again + coverage_sched_function_continue = false; + // Will only run the first time through this loop, then not scheduled again + for (int i = 0; i < 3; ++i) { + mp_handle_pending(true); + } + #endif } - // CIRCUITPY-CHANGE: ringbuf is different + // CIRCUITPY-CHANGE: ringbuf is quite different // ringbuf { #define RINGBUF_SIZE 99 @@ -719,7 +746,7 @@ static mp_obj_t extra_coverage(void) { mp_printf(&mp_plat_print, "# ringbuf\n"); // Single-byte put/get with empty ringbuf. - mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_free(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); + mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); ringbuf_put(&ringbuf, 22); mp_printf(&mp_plat_print, "%d %d\n", (int)ringbuf_num_empty(&ringbuf), (int)ringbuf_num_filled(&ringbuf)); mp_printf(&mp_plat_print, "%d\n", ringbuf_get(&ringbuf)); diff --git a/ports/unix/coveragecpp.cpp b/ports/unix/coveragecpp.cpp index 4d21398142d..8ba308f6468 100644 --- a/ports/unix/coveragecpp.cpp +++ b/ports/unix/coveragecpp.cpp @@ -1,6 +1,20 @@ extern "C" { -// CIRCUITPY-CHANGE: do not include everything: it causes compilation warnings -#include "py/obj.h" +// Include the complete public API to verify everything compiles as C++. +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include } // Invoke all (except one, see below) public API macros which initialize structs to make sure diff --git a/ports/unix/main.c b/ports/unix/main.c index 89937008e05..25444df41ce 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -269,14 +269,18 @@ static inline int convert_pyexec_result(int ret) { } static int do_file(const char *file) { - return convert_pyexec_result(pyexec_file(file)); + // CIRCUITPY-CHANGE: pyexec_file result arg + pyexec_result_t pyexec_result; + return convert_pyexec_result(pyexec_file(file, &pyexec_result)); } static int do_str(const char *str) { vstr_t vstr; vstr.buf = (char *)str; vstr.len = strlen(str); - int ret = pyexec_vstr(&vstr, true); + // CIRCUITPY-CHANGE: pyexec_vstr result arg + pyexec_result_t pyexec_result; + int ret = pyexec_vstr(&vstr, true, &pyexec_result); return convert_pyexec_result(ret); } diff --git a/ports/unix/mphalport.h b/ports/unix/mphalport.h index afac25bf865..d9cd05b3de8 100644 --- a/ports/unix/mphalport.h +++ b/ports/unix/mphalport.h @@ -25,7 +25,6 @@ */ #include #include -// CIRCUITPY-CHANGE: extra include #include #ifndef CHAR_CTRL_C @@ -38,6 +37,20 @@ #define MICROPY_END_ATOMIC_SECTION(x) (void)x; mp_thread_unix_end_atomic_section() #endif +// In lieu of a WFI(), slow down polling from being a tight loop. +// +// Note that we don't delay for the full TIMEOUT_MS, as execution +// can't be woken from the delay. +#define MICROPY_INTERNAL_WFE(TIMEOUT_MS) \ + do { \ + MP_THREAD_GIL_EXIT(); \ + mp_hal_delay_us(500); \ + MP_THREAD_GIL_ENTER(); \ + } while (0) + +// The port provides `mp_hal_stdio_mode_raw()` and `mp_hal_stdio_mode_orig()`. +#define MICROPY_HAL_HAS_STDIO_MODE_SWITCH (1) + // CIRCUITPY-CHANGE: mp_hal_set_interrupt_char(int) instead of char void mp_hal_set_interrupt_char(int c); bool mp_hal_is_interrupted(void); diff --git a/py/bc.h b/py/bc.h index c299560ef2b..3b7a6fe1c96 100644 --- a/py/bc.h +++ b/py/bc.h @@ -304,7 +304,7 @@ static inline void mp_module_context_alloc_tables(mp_module_context_t *context, size_t nq = (n_qstr * sizeof(qstr_short_t) + sizeof(mp_uint_t) - 1) / sizeof(mp_uint_t); size_t no = n_obj; // CIRCUITPY-CHANGE - mp_uint_t *mem = m_malloc_items(nq + no); + mp_uint_t *mem = (mp_uint_t *)m_malloc_items(nq + no); context->constants.qstr_table = (qstr_short_t *)mem; context->constants.obj_table = (mp_obj_t *)(mem + nq); #else diff --git a/py/mpconfig.h b/py/mpconfig.h index 0ef98009205..522f6150dfd 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -2434,11 +2434,6 @@ typedef time_t mp_timestamp_t; #define MP_COLD __attribute__((cold)) #endif -// CIRCUITPY-CHANGE: avoid undefined warnings -#ifndef MICROPY_HAL_HAS_STDIO_MODE_SWITCH -#define MICROPY_HAL_HAS_STDIO_MODE_SWITCH (0) -#endif - // To annotate that code is unreachable #ifndef MP_UNREACHABLE #if defined(__GNUC__) diff --git a/py/obj.h b/py/obj.h index bddb86605e3..eb7143bd43f 100644 --- a/py/obj.h +++ b/py/obj.h @@ -408,7 +408,7 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t; {.base = {.type = &mp_type_fun_builtin_var}, .sig = MP_OBJ_FUN_MAKE_SIG(n_args_min, n_args_max, false), .fun = {.var = fun_name}} #define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, n_args_min, fun_name) \ const mp_obj_fun_builtin_var_t obj_name = \ - {{&mp_type_fun_builtin_var}, MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun.kw = fun_name} + {.base = {.type = &mp_type_fun_builtin_var}, .sig = MP_OBJ_FUN_MAKE_SIG(n_args_min, MP_OBJ_FUN_ARGS_MAX, true), .fun = {.kw = fun_name}} // CIRCUITPY-CHANGE #define MP_DEFINE_CONST_PROP_GET(obj_name, fun_name) \ diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index b554199eeec..65edb58e6b6 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -570,7 +570,8 @@ MP_REGISTER_ROOT_POINTER(vstr_t * repl_line); #else // MICROPY_REPL_EVENT_DRIVEN -#if !MICROPY_HAL_HAS_STDIO_MODE_SWITCH +// CIRCUITPY-CHANGE: avoid warnings +#if defined(MICROPY_HAL_HAS_STDIO_MODE_SWITCH) && !MICROPY_HAL_HAS_STDIO_MODE_SWITCH // If the port doesn't need any stdio mode switching calls then provide trivial ones. static inline void mp_hal_stdio_mode_raw(void) { } From d28f54587c4db5778ff63ce7b0dc4f70eaa71e6f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 1 Apr 2026 13:36:16 -0700 Subject: [PATCH 375/876] Add Zephyr build for the Feather nrf52840 Sense --- .../autogen_board_info.toml | 120 ++++++++++++++++++ .../circuitpython.toml | 4 + .../autogen_board_info.toml | 2 +- .../circuitpython.toml | 1 + ...t_feather_nrf52840_nrf52840_sense_uf2.conf | 10 ++ ...eather_nrf52840_nrf52840_sense_uf2.overlay | 46 +++++++ ports/zephyr-cp/boards/board_aliases.cmake | 1 + .../zephyr-cp/cptools/build_circuitpython.py | 21 +-- ports/zephyr-cp/cptools/zephyr2cp.py | 4 +- 9 files changed, 198 insertions(+), 11 deletions(-) create mode 100644 ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf create mode 100644 ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..cfcae400906 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Adafruit Industries LLC Feather Bluefruit Sense" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/circuitpython.toml new file mode 100644 index 00000000000..eacb0f9607d --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/circuitpython.toml @@ -0,0 +1,4 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] +USB_VID=0x239A +USB_PID=0x8088 +NAME="Feather Bluefruit Sense" diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 7b1fb9a0d6f..4f56f4d203e 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -1,5 +1,5 @@ # This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. -name = "Adafruit Industries LLC Feather nRF52840 (Express, Sense)" +name = "Adafruit Industries LLC Feather nRF52840 Express" [modules] __future__ = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml index e1a16cb74aa..c4d1099a77e 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/circuitpython.toml @@ -1,3 +1,4 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] USB_VID=0x239A USB_PID=0x802A +NAME="Feather nRF52840 Express" diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf new file mode 100644 index 00000000000..20176b34be0 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf @@ -0,0 +1,10 @@ +CONFIG_BT=y +CONFIG_BT_PERIPHERAL=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_BROADCASTER=y +CONFIG_BT_OBSERVER=y +CONFIG_BT_EXT_ADV=y + +CONFIG_USE_DT_CODE_PARTITION=y + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay new file mode 100644 index 00000000000..e01ebd6df1f --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay @@ -0,0 +1,46 @@ +/ { + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + }; +}; + +&zephyr_udc0 { + /delete-node/ board_cdc_acm_uart; +}; + + +&gd25q16 { + /delete-node/ partitions; +}; + +/delete-node/ &storage_partition; +/delete-node/ &code_partition; + +&flash0 { + partitions { + code_partition: partition@26000 { + label = "Application"; + reg = <0x00026000 0x000c4000>; + }; + + storage_partition: partition@ea000 { + label = "storage"; + reg = <0x000ea000 0x00008000>; + }; + + nvm_partition: partition@f2000 { + label = "nvm"; + reg = <0x000f2000 0x00002000>; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index e973eac72d4..e20a7b0cc62 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -28,6 +28,7 @@ endmacro() cp_board_alias(pca10056 nrf52840dk/nrf52840) cp_board_alias(adafruit_feather_nrf52840_zephyr adafruit_feather_nrf52840/nrf52840/uf2) +cp_board_alias(adafruit_feather_nrf52840_sense_zephyr adafruit_feather_nrf52840/nrf52840/sense/uf2) cp_board_alias(renesas_ek_ra6m5 ek_ra6m5) cp_board_alias(renesas_ek_ra8d1 ek_ra8d1) cp_board_alias(renesas_da14695_dk_usb da14695_dk_usb) diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 63a2ed96351..772c805a501 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -362,6 +362,11 @@ async def build_circuitpython(): genhdr = builddir / "genhdr" genhdr.mkdir(exist_ok=True, parents=True) version_header = genhdr / "mpversion.h" + mpconfigboard_fn = board_tools.find_mpconfigboard(portdir, board) + mpconfigboard = {"USB_VID": 0x1209, "USB_PID": 0x000C, "USB_INTERFACE_NAME": "CircuitPython"} + if mpconfigboard_fn is not None and mpconfigboard_fn.exists(): + with mpconfigboard_fn.open("rb") as f: + mpconfigboard.update(tomllib.load(f)) async with asyncio.TaskGroup() as tg: tg.create_task( cpbuild.run_command( @@ -379,11 +384,9 @@ async def build_circuitpython(): ) board_autogen_task = tg.create_task( - zephyr_dts_to_cp_board(zephyr_board, portdir, builddir, zephyrbuilddir) + zephyr_dts_to_cp_board(zephyr_board, portdir, builddir, zephyrbuilddir, mpconfigboard) ) board_info = board_autogen_task.result() - mpconfigboard_fn = board_tools.find_mpconfigboard(portdir, board) - mpconfigboard = {"USB_VID": 0x1209, "USB_PID": 0x000C, "USB_INTERFACE_NAME": "CircuitPython"} if mpconfigboard_fn is None: mpconfigboard_fn = ( portdir / "boards" / board_info["vendor_id"] / board / "circuitpython.toml" @@ -391,9 +394,6 @@ async def build_circuitpython(): logging.warning( f"Could not find board config at: boards/{board_info['vendor_id']}/{board}" ) - elif mpconfigboard_fn.exists(): - with mpconfigboard_fn.open("rb") as f: - mpconfigboard.update(tomllib.load(f)) autogen_board_info_fn = mpconfigboard_fn.parent / "autogen_board_info.toml" @@ -402,6 +402,9 @@ async def build_circuitpython(): circuitpython_flags.append(f"-DCIRCUITPY_CREATOR_ID=0x{creator_id:08x}") circuitpython_flags.append(f"-DCIRCUITPY_CREATION_ID=0x{creation_id:08x}") + vendor = mpconfigboard.get("VENDOR", board_info["vendor"]) + name = mpconfigboard.get("NAME", board_info["name"]) + enabled_modules, module_reasons = determine_enabled_modules(board_info, portdir, srcdir) web_workflow_enabled = board_info.get("wifi", False) or board_info.get("hostnetwork", False) @@ -459,8 +462,8 @@ async def build_circuitpython(): f"-DUSB_INTERFACE_NAME='\"{mpconfigboard['USB_INTERFACE_NAME']}\"'" ) for macro, limit, value in ( - ("USB_PRODUCT", 16, board_info["name"]), - ("USB_MANUFACTURER", 8, board_info["vendor"]), + ("USB_PRODUCT", 16, name), + ("USB_MANUFACTURER", 8, vendor), ): circuitpython_flags.append(f"-D{macro}='\"{value}\"'") circuitpython_flags.append(f"-D{macro}_{limit}='\"{value[:limit]}\"'") @@ -512,7 +515,7 @@ async def build_circuitpython(): "This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info." ) ) - autogen_board_info.add("name", board_info["vendor"] + " " + board_info["name"]) + autogen_board_info.add("name", vendor + " " + name) autogen_modules = tomlkit.table() autogen_board_info.add("modules", autogen_modules) for module in sorted( diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index 08a16da0cf6..d40501f1d1d 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -433,7 +433,7 @@ def find_ram_regions(device_tree): @cpbuild.run_in_thread -def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa: C901 +def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfigboard=None): # noqa: C901 board_dir = builddir / "board" # Auto generate board files from device tree. @@ -486,6 +486,8 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir): # noqa soc_name = board_yaml["socs"][0]["name"] board_info["soc"] = soc_name board_name = board_yaml["full_name"] + if mpconfigboard and "NAME" in mpconfigboard: + board_name = mpconfigboard["NAME"] board_info["name"] = board_name # board_id_yaml = zephyr_board_dir / (zephyr_board_dir.name + ".yaml") # board_id_yaml = yaml.safe_load(board_id_yaml.read_text()) From 205470281896d29a4de4bb3c5ba12679e3e8704b Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 6 Apr 2026 13:16:59 -0700 Subject: [PATCH 376/876] Switch cert bundle for small ai thinker board --- .../boards/ai_thinker_esp32-c3s-2m/sdkconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig index 5fd531f274a..79713bb57e8 100644 --- a/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig +++ b/ports/espressif/boards/ai_thinker_esp32-c3s-2m/sdkconfig @@ -21,6 +21,18 @@ # CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS is not set # end of LibC +# +# mbedTLS +# +# +# Certificate Bundle +# +# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL is not set +CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN=y +# end of Certificate Bundle +# +# end of mbedTLS + # end of Component config # end of Espressif IoT Development Framework Configuration From 5df11054c6382209fc4d8650bfaec844c4953a3a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 6 Apr 2026 21:54:11 -0400 Subject: [PATCH 377/876] fix some tests; allow running tests selectivly with --- Makefile | 3 ++- ports/unix/main.c | 9 ++++++++- shared/runtime/pyexec.c | 2 +- tests/basics/io_buffered_writer.py | 1 - 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index c2aebc61f1c..175a1b6a302 100644 --- a/Makefile +++ b/Makefile @@ -375,5 +375,6 @@ coverage-fresh: make -j -C ports/unix VARIANT=coverage .PHONY: run-tests +# If TESTS="abc.py def.py" is specified as an arg, run only those tests. Otherwise, run all tests. run-tests: - cd tests; MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py + cd tests; MICROPY_MICROPYTHON=../ports/unix/build-coverage/micropython ./run-tests.py $(TESTS) diff --git a/ports/unix/main.c b/ports/unix/main.c index 25444df41ce..81dc531d6bf 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -768,7 +768,14 @@ MP_NOINLINE int main_(int argc, char **argv) { #endif // printf("total bytes = %d\n", m_get_total_bytes_allocated()); - return ret & 0xff; + + // CIRCUITPY-CHANGE: handle PYEXEC_EXCEPTION + if (ret & PYEXEC_EXCEPTION) { + // Return exit status code 1 so the invoker knows there was an uncaught exception. + return 1; + } else { + return ret & 0xff; + } } void nlr_jump_fail(void *val) { diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 65edb58e6b6..530e5d27b90 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -118,7 +118,7 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input // source is a lexer, parse and compile the script qstr source_name = lex->source_name; // CIRCUITPY-CHANGE - #if MICROPY_PY___FILE__ + #if MICROPY_MODULE___FILE__ if (input_kind == MP_PARSE_FILE_INPUT) { mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); } diff --git a/tests/basics/io_buffered_writer.py b/tests/basics/io_buffered_writer.py index 31d3eb489c4..3cfee0103f7 100644 --- a/tests/basics/io_buffered_writer.py +++ b/tests/basics/io_buffered_writer.py @@ -1,7 +1,6 @@ try: import io -try: io.BytesIO io.BufferedWriter except (AttributeError, ImportError): From 8a115a2ac1c3a06fef28652d4e429d9e9cedf0ad Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 7 Apr 2026 09:26:30 -0500 Subject: [PATCH 378/876] board def for feather rp2040 --- .../autogen_board_info.toml | 120 ++++++++++++++++++ .../feather_rp2040_zephyr/circuitpython.toml | 1 + .../boards/adafruit_feather_rp2040.conf | 1 + .../boards/adafruit_feather_rp2040.overlay | 34 +++++ ports/zephyr-cp/boards/board_aliases.cmake | 1 + 5 files changed, 157 insertions(+) create mode 100644 ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/adafruit_feather_rp2040.conf create mode 100644 ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..116a604f857 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -0,0 +1,120 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Adafruit Industries LLC Feather RP2040" + +[modules] +__future__ = true +_bleio = false +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = false +adafruit_pixelbuf = false +aesio = false +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilters = false +audiofreeverb = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = false +gifio = false +gnss = false +hashlib = false +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = false +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = false +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = false +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = false +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/circuitpython.toml new file mode 100644 index 00000000000..9d3c229ed1b --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "uf2"] diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf b/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf new file mode 100644 index 00000000000..81c49269230 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf @@ -0,0 +1 @@ +CONFIG_GPIO=y \ No newline at end of file diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay new file mode 100644 index 00000000000..ce9083dd62d --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay @@ -0,0 +1,34 @@ +&flash0 { + /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + /* Reserved memory for the second stage bootloader */ + second_stage_bootloader: partition@0 { + label = "second_stage_bootloader"; + reg = <0x00000000 0x100>; + read-only; + }; + + code_partition: partition@100 { + label = "code-partition"; + reg = <0x100 (0x180000 - 0x100)>; + read-only; + }; + + nvm_partition: partition@180000 { + label = "nvm"; + reg = <0x180000 0x1000>; + }; + + circuitpy_partition: partition@181000 { + label = "circuitpy"; + reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; + }; + }; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index e973eac72d4..d1064e55e8f 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -28,6 +28,7 @@ endmacro() cp_board_alias(pca10056 nrf52840dk/nrf52840) cp_board_alias(adafruit_feather_nrf52840_zephyr adafruit_feather_nrf52840/nrf52840/uf2) +cp_board_alias(adafruit_feather_rp2040_zephyr adafruit_feather_rp2040/rp2040) cp_board_alias(renesas_ek_ra6m5 ek_ra6m5) cp_board_alias(renesas_ek_ra8d1 ek_ra8d1) cp_board_alias(renesas_da14695_dk_usb da14695_dk_usb) From e9d6e54365fd7e72f219fc0bd4ff18f61a9a90b6 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 7 Apr 2026 11:02:41 -0500 Subject: [PATCH 379/876] update feather rp2040 zephry board autogen for nvm --- .../adafruit/feather_rp2040_zephyr/autogen_board_info.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index 116a604f857..e2fdd505304 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -73,7 +73,7 @@ microcontroller = true mipidsi = false msgpack = false neopixel_write = false -nvm = false +nvm = true # Zephyr board has nvm onewireio = false os = true paralleldisplaybus = false From e834f0b17fa15975cbcd7b35ff57616cc1f6adae Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 7 Apr 2026 11:08:06 -0500 Subject: [PATCH 380/876] eof newline --- ports/zephyr-cp/boards/adafruit_feather_rp2040.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf b/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf index 81c49269230..91c3c15b37d 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf +++ b/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf @@ -1 +1 @@ -CONFIG_GPIO=y \ No newline at end of file +CONFIG_GPIO=y From 0d968ae411d04533f858101ab103fa4618e1757f Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Mon, 6 Apr 2026 22:56:16 -0700 Subject: [PATCH 381/876] Fix NULL pointer dereference in STM32 SPI construct Move mark_deinit() before check_pins() so that self->sck is not NULLed after check_pins sets it. The previous ordering caused a NULL dereference of self->sck->altfn_index, crashing all STM32 boards that use SPI (including STM32F405 boards whose CIRCUITPY filesystem lives on external SPI flash). Fixes adafruit/circuitpython#10866 Co-Authored-By: Claude Opus 4.6 (1M context) --- ports/stm/common-hal/busio/SPI.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ports/stm/common-hal/busio/SPI.c b/ports/stm/common-hal/busio/SPI.c index 1b86a9f55d5..24b65fbf54c 100644 --- a/ports/stm/common-hal/busio/SPI.c +++ b/ports/stm/common-hal/busio/SPI.c @@ -136,12 +136,13 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) { + // Ensure the object starts in its deinit state before check_pins sets + // self->sck, self->mosi, and self->miso. + common_hal_busio_spi_mark_deinit(self); + int periph_index = check_pins(self, sck, mosi, miso); SPI_TypeDef *SPIx = mcu_spi_banks[periph_index - 1]; - // Ensure the object starts in its deinit state. - common_hal_busio_spi_mark_deinit(self); - // Start GPIO for each pin GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = pin_mask(sck->number); From be90f6040cde656b0ee897cfd05c6efd3aadce2b Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 7 Apr 2026 13:46:15 -0500 Subject: [PATCH 382/876] enable msgpack in zephyr port and add test for it. fix dict order issue in msgpack unpack. --- .../autogen_board_info.toml | 2 +- .../native/native_sim/autogen_board_info.toml | 4 +- .../zephyr-cp/cptools/build_circuitpython.py | 1 + ports/zephyr-cp/tests/test_msgpack.py | 137 ++++++++++++++++++ shared-module/msgpack/__init__.c | 8 +- 5 files changed, 147 insertions(+), 5 deletions(-) create mode 100644 ports/zephyr-cp/tests/test_msgpack.py diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index e2fdd505304..05cc100c6e5 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = true # Zephyr board has nvm onewireio = false diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 327c4cbb7e5..4b657282ef6 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -56,7 +56,7 @@ i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false imagecapture = false -ipaddress = false +ipaddress = true # Zephyr networking enabled is31fl3741 = false jpegio = false keypad = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = true # Zephyr board has nvm onewireio = false diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 63a2ed96351..73918a06a5a 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -60,6 +60,7 @@ "errno", "io", "math", + "msgpack", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] diff --git a/ports/zephyr-cp/tests/test_msgpack.py b/ports/zephyr-cp/tests/test_msgpack.py new file mode 100644 index 00000000000..09bed35209c --- /dev/null +++ b/ports/zephyr-cp/tests/test_msgpack.py @@ -0,0 +1,137 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the msgpack module.""" + +import pytest + + +ROUNDTRIP_CODE = """\ +import msgpack +from io import BytesIO + +obj = {"list": [True, False, None, 1, 3.125], "str": "blah"} +b = BytesIO() +msgpack.pack(obj, b) +encoded = b.getvalue() +print(f"encoded_len: {len(encoded)}") +print(f"encoded_hex: {encoded.hex()}") + +b.seek(0) +decoded = msgpack.unpack(b) +print(f"decoded: {decoded}") +print(f"match: {decoded == obj}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": ROUNDTRIP_CODE}) +def test_msgpack_roundtrip(circuitpython): + """Pack and unpack a dict containing the basic msgpack types.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "match: True" in output + assert "done" in output + + +USE_LIST_CODE = """\ +import msgpack +from io import BytesIO + +b = BytesIO() +msgpack.pack([1, 2, 3], b) + +b.seek(0) +as_list = msgpack.unpack(b) +print(f"as_list: {as_list} type={type(as_list).__name__}") + +b.seek(0) +as_tuple = msgpack.unpack(b, use_list=False) +print(f"as_tuple: {as_tuple} type={type(as_tuple).__name__}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": USE_LIST_CODE}) +def test_msgpack_use_list(circuitpython): + """use_list=False should return a tuple instead of a list.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "as_list: [1, 2, 3] type=list" in output + assert "as_tuple: (1, 2, 3) type=tuple" in output + assert "done" in output + + +EXTTYPE_CODE = """\ +from msgpack import pack, unpack, ExtType +from io import BytesIO + +class MyClass: + def __init__(self, val): + self.value = val + +data = MyClass(b"my_value") + +def encoder(obj): + if isinstance(obj, MyClass): + return ExtType(1, obj.value) + return f"no encoder for {obj}" + +def decoder(code, data): + if code == 1: + return MyClass(data) + return f"no decoder for type {code}" + +buf = BytesIO() +pack(data, buf, default=encoder) +buf.seek(0) +decoded = unpack(buf, ext_hook=decoder) +print(f"decoded_type: {type(decoded).__name__}") +print(f"decoded_value: {decoded.value}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EXTTYPE_CODE}) +def test_msgpack_exttype(circuitpython): + """ExtType with a custom encoder/decoder should round-trip.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "decoded_type: MyClass" in output + assert "decoded_value: b'my_value'" in output + assert "done" in output + + +EXTTYPE_PROPS_CODE = """\ +from msgpack import ExtType + +e = ExtType(5, b"hello") +print(f"code: {e.code}") +print(f"data: {e.data}") + +e.code = 10 +print(f"new_code: {e.code}") + +try: + ExtType(128, b"x") +except (ValueError, OverflowError) as ex: + print(f"range_error: {type(ex).__name__}") + +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EXTTYPE_PROPS_CODE}) +def test_msgpack_exttype_properties(circuitpython): + """ExtType exposes code/data as read/write properties and rejects out-of-range codes.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "code: 5" in output + assert "data: b'hello'" in output + assert "new_code: 10" in output + assert "range_error:" in output + assert "done" in output diff --git a/shared-module/msgpack/__init__.c b/shared-module/msgpack/__init__.c index a98fb02de39..7c3e664bb6c 100644 --- a/shared-module/msgpack/__init__.c +++ b/shared-module/msgpack/__init__.c @@ -394,7 +394,9 @@ static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) { size_t len = code & 0b1111; mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(len)); for (size_t i = 0; i < len; i++) { - mp_obj_dict_store(d, unpack(s, ext_hook, use_list), unpack(s, ext_hook, use_list)); + mp_obj_t key = unpack(s, ext_hook, use_list); + mp_obj_t value = unpack(s, ext_hook, use_list); + mp_obj_dict_store(d, key, value); } return MP_OBJ_FROM_PTR(d); } @@ -462,7 +464,9 @@ static mp_obj_t unpack(msgpack_stream_t *s, mp_obj_t ext_hook, bool use_list) { size_t len = read_size(s, code - 0xde + 1); mp_obj_dict_t *d = MP_OBJ_TO_PTR(mp_obj_new_dict(len)); for (size_t i = 0; i < len; i++) { - mp_obj_dict_store(d, unpack(s, ext_hook, use_list), unpack(s, ext_hook, use_list)); + mp_obj_t key = unpack(s, ext_hook, use_list); + mp_obj_t value = unpack(s, ext_hook, use_list); + mp_obj_dict_store(d, key, value); } return MP_OBJ_FROM_PTR(d); } From 13b1a5edcdc9d4950589c5d489870f872debf51f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 8 Apr 2026 20:44:12 -0400 Subject: [PATCH 383/876] redo pyexec.c to be more like upstream; fix a bunch of tests --- ports/unix/main.c | 9 +- ports/unix/mpconfigport.h | 1 + py/objarray.c | 4 +- shared/runtime/pyexec.c | 194 +++++++++++------- tests/cmdline/repl_autocomplete.py.exp | 6 +- tests/cmdline/repl_autocomplete_underscore.py | 10 +- .../repl_autocomplete_underscore.py.exp | 30 +-- tests/cmdline/repl_autoindent.py.exp | 16 +- tests/cmdline/repl_basic.py.exp | 6 +- tests/cmdline/repl_cont.py.exp | 6 +- tests/cmdline/repl_emacs_keys.py.exp | 6 +- tests/cmdline/repl_inspect.py.exp | 6 +- tests/cmdline/repl_lock.py.exp | 4 +- tests/cmdline/repl_micropyinspect.py.exp | 6 +- tests/cmdline/repl_paste.py.exp | 94 ++++----- tests/cmdline/repl_sys_ps1_ps2.py.exp | 4 +- tests/cmdline/repl_words_move.py.exp | 10 +- tests/micropython/opt_level_lineno.py | 14 +- 18 files changed, 243 insertions(+), 183 deletions(-) diff --git a/ports/unix/main.c b/ports/unix/main.c index 81dc531d6bf..e42400fe5f9 100644 --- a/ports/unix/main.c +++ b/ports/unix/main.c @@ -92,7 +92,8 @@ static void stderr_print_strn(void *env, const char *str, size_t len) { const mp_print_t mp_stderr_print = {NULL, stderr_print_strn}; -#define FORCED_EXIT (0x100) +// CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT +// #define FORCED_EXIT (0x100) // If exc is SystemExit, return value where FORCED_EXIT bit set, // and lower 8 bits are SystemExit value. For all other exceptions, // return 1. @@ -105,7 +106,8 @@ static int handle_uncaught_exception(mp_obj_base_t *exc) { if (exit_val != mp_const_none && !mp_obj_get_int_maybe(exit_val, &val)) { val = 1; } - return FORCED_EXIT | (val & 255); + // CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT + return PYEXEC_FORCED_EXIT | (val & 255); } // Report all other exceptions @@ -236,7 +238,8 @@ static int do_repl(void) { int ret = execute_from_lexer(LEX_SRC_STR, line, MP_PARSE_SINGLE_INPUT, true); free(line); - if (ret & FORCED_EXIT) { + // CIRCUITPY-CHANGE: be consistent about using PYEXEC_FORCED_EXIT + if (ret & PYEXEC_FORCED_EXIT) { return ret; } } diff --git a/ports/unix/mpconfigport.h b/ports/unix/mpconfigport.h index 991db97f921..815be76b4e9 100644 --- a/ports/unix/mpconfigport.h +++ b/ports/unix/mpconfigport.h @@ -44,6 +44,7 @@ // CIRCUITPY-CHANGE #define CIRCUITPY_MICROPYTHON_ADVANCED (1) #define MICROPY_PY_ASYNC_AWAIT (1) +#define MICROPY_PY_DOUBLE_TYPECODE (1) #define MICROPY_PY_UCTYPES (0) #ifndef MICROPY_CONFIG_ROM_LEVEL diff --git a/py/objarray.c b/py/objarray.c index de6e158b057..1e259a20ac8 100644 --- a/py/objarray.c +++ b/py/objarray.c @@ -807,7 +807,7 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_DEFINE_CONST_OBJ_TYPE( mp_type_bytearray, MP_QSTR_bytearray, - MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER, + MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER | MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE, make_new, bytearray_make_new, print, array_print, iter, array_iterator_new, @@ -846,7 +846,7 @@ MP_DEFINE_CONST_DICT(memoryview_locals_dict, memoryview_locals_dict_table); MP_DEFINE_CONST_OBJ_TYPE( mp_type_memoryview, MP_QSTR_memoryview, - MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER, + MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_ITER_IS_GETITER | MP_TYPE_FLAG_SUBSCR_ALLOWS_STACK_SLICE, make_new, memoryview_make_new, iter, array_iterator_new, unary_op, array_unary_op, diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 530e5d27b90..09f1796c5d4 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -43,7 +43,7 @@ #include "extmod/modplatform.h" #include "genhdr/mpversion.h" -// CIRCUITPY-CHANGE: atexit support +// CIRCUITPY-CHANGE: add atexit support #if CIRCUITPY_ATEXIT #include "shared-module/atexit/__init__.h" #endif @@ -84,57 +84,71 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input nlr_buf_t nlr; nlr.ret_val = NULL; if (nlr_push(&nlr) == 0) { - // CIRCUITPY-CHANGE - mp_obj_t module_fun = mp_const_none; - // CIRCUITPY-CHANGE + #if MICROPY_PYEXEC_ENABLE_VM_ABORT + nlr_set_abort(&nlr); + #endif + + // CIRCUITPY-CHANGE: move declaration for easier handling of atexit #if. + // Also make it possible to determine if module_fun was set. + mp_obj_t module_fun = NULL; + + // CIRCUITPY-CHANGE: add atexit support #if CIRCUITPY_ATEXIT - if (!(exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT)) + if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT) { + atexit_callback_t *callback = (atexit_callback_t *)source; + mp_call_function_n_kw(callback->func, callback->n_pos, callback->n_kw, callback->args); + } else #endif - // CIRCUITPY-CHANGE: multiple code changes - { - #if MICROPY_MODULE_FROZEN_MPY - if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) { - // source is a raw_code object, create the function - const mp_frozen_module_t *frozen = source; - mp_module_context_t *ctx = m_new_obj(mp_module_context_t); - ctx->module.globals = mp_globals_get(); - ctx->constants = frozen->constants; - module_fun = mp_make_function_from_proto_fun(frozen->proto_fun, ctx, NULL); - } else - #endif - { - #if MICROPY_ENABLE_COMPILER - mp_lexer_t *lex; - if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) { - const vstr_t *vstr = source; - lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0); - } else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) { - lex = mp_lexer_new(MP_QSTR__lt_stdin_gt_, *(mp_reader_t *)source); - } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) { - lex = mp_lexer_new_from_file(qstr_from_str(source)); - } else { - lex = (mp_lexer_t *)source; - } - // source is a lexer, parse and compile the script - qstr source_name = lex->source_name; - // CIRCUITPY-CHANGE - #if MICROPY_MODULE___FILE__ - if (input_kind == MP_PARSE_FILE_INPUT) { - mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); - } - #endif - mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); - module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL); - #else - mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("script compilation not supported")); - #endif + #if MICROPY_MODULE_FROZEN_MPY + if (exec_flags & EXEC_FLAG_SOURCE_IS_RAW_CODE) { + // source is a raw_code object, create the function + const mp_frozen_module_t *frozen = source; + mp_module_context_t *ctx = m_new_obj(mp_module_context_t); + ctx->module.globals = mp_globals_get(); + ctx->constants = frozen->constants; + module_fun = mp_make_function_from_proto_fun(frozen->proto_fun, ctx, NULL); + } else + #endif + { + #if MICROPY_ENABLE_COMPILER + mp_lexer_t *lex; + if (exec_flags & EXEC_FLAG_SOURCE_IS_VSTR) { + const vstr_t *vstr = source; + lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr->buf, vstr->len, 0); + } else if (exec_flags & EXEC_FLAG_SOURCE_IS_READER) { + lex = mp_lexer_new(MP_QSTR__lt_stdin_gt_, *(mp_reader_t *)source); + } else if (exec_flags & EXEC_FLAG_SOURCE_IS_FILENAME) { + lex = mp_lexer_new_from_file(qstr_from_str(source)); + } else { + lex = (mp_lexer_t *)source; } - - // If the code was loaded from a file, collect any garbage before running. + // source is a lexer, parse and compile the script + qstr source_name = lex->source_name; + #if MICROPY_MODULE___FILE__ if (input_kind == MP_PARSE_FILE_INPUT) { - gc_collect(); + mp_store_global(MP_QSTR___file__, MP_OBJ_NEW_QSTR(source_name)); + } + #endif + mp_parse_tree_t parse_tree = mp_parse(lex, input_kind); + #if defined(MICROPY_UNIX_COVERAGE) + // allow to print the parse tree in the coverage build + if (mp_verbose_flag >= 3) { + printf("----------------\n"); + mp_parse_node_print(&mp_plat_print, parse_tree.root, 0); + printf("----------------\n"); } + #endif + module_fun = mp_compile(&parse_tree, source_name, exec_flags & EXEC_FLAG_IS_REPL); + #else + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("script compilation not supported")); + #endif + } + + // CIRCUITPY-CHANGE: garbage collect after loading + // If the code was loaded from a file, collect any garbage before running. + if (input_kind == MP_PARSE_FILE_INPUT) { + gc_collect(); } // execute code @@ -144,22 +158,19 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input #if MICROPY_REPL_INFO start = mp_hal_ticks_ms(); #endif - // CIRCUITPY-CHANGE - #if CIRCUITPY_ATEXIT - if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT) { - atexit_callback_t *callback = (atexit_callback_t *)source; - mp_call_function_n_kw(callback->func, callback->n_pos, callback->n_kw, callback->args); - } else + #if MICROPY_PYEXEC_COMPILE_ONLY + if (!mp_compile_only) #endif - // CIRCUITPY-CHANGE - if (module_fun != mp_const_none) { - mp_call_function_0(module_fun); + { + // CIRCUITPY-CHANGE: if atexit function was called, there is nothing to call. + if (module_fun != NULL) { + mp_call_function_0(module_fun); + } } mp_hal_set_interrupt_char(-1); // disable interrupt mp_handle_pending(true); // handle any pending exceptions (and any callbacks) nlr_pop(); - // CIRCUITPY-CHANGE - ret = 0; + ret = PYEXEC_NORMAL_EXIT; if (exec_flags & EXEC_FLAG_PRINT_EOF) { mp_hal_stdout_tx_strn("\x04", 1); } @@ -178,36 +189,66 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input mp_hal_stdout_tx_strn("\x04", 1); } - // check for SystemExit - - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE: Name and use some values. // nlr.ret_val is an exception object. mp_obj_t exception_obj = (mp_obj_t)nlr.ret_val; + const mp_obj_type_t *exception_obj_type = mp_obj_get_type(exception_obj); - if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exception_obj)), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { - // at the moment, the value of SystemExit is unused + #if MICROPY_PYEXEC_ENABLE_VM_ABORT + if (nlr.ret_val == NULL) { // abort + ret = PYEXEC_ABORT; + } else + #endif + + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exception_obj_type), MP_OBJ_FROM_PTR(&mp_type_SystemExit))) { // system exit + #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING + // None is an exit value of 0; an int is its value; anything else is 1 + mp_obj_t val = mp_obj_exception_get_value(MP_OBJ_FROM_PTR(nlr.ret_val)); + if (val != mp_const_none) { + if (mp_obj_is_int(val)) { + ret = (int)mp_obj_int_get_truncated(val); + } else { + mp_obj_print_helper(MICROPY_ERROR_PRINTER, val, PRINT_STR); + mp_print_str(MICROPY_ERROR_PRINTER, "\n"); + ret = PYEXEC_UNHANDLED_EXCEPTION; + } + } else { + ret = PYEXEC_NORMAL_EXIT; + } + // Set PYEXEC_FORCED_EXIT flag so REPL knows to exit + ret |= PYEXEC_FORCED_EXIT; + #else ret = PYEXEC_FORCED_EXIT; - // CIRCUITPY-CHANGE - #if CIRCUITPY_ALARM - } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exception_obj)), MP_OBJ_FROM_PTR(&mp_type_DeepSleepRequest))) { + #endif + // CIRCUITPY-CHANGE: support DeepSleepRequest + #if CIRCUITPY_ALARM + } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exception_obj_type), MP_OBJ_FROM_PTR(&mp_type_DeepSleepRequest))) { ret = PYEXEC_DEEP_SLEEP; - #endif + #endif + // CIRCUITPY-CHANGE: supprt ReloadException } else if (exception_obj == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) { ret = PYEXEC_RELOAD; - } else { - mp_obj_print_exception(&mp_plat_print, exception_obj); - ret = PYEXEC_EXCEPTION; + } else { // other exception + mp_obj_print_exception(&mp_plat_print, MP_OBJ_FROM_PTR(nlr.ret_val)); + ret = PYEXEC_UNHANDLED_EXCEPTION; + #if MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING + if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(((mp_obj_base_t *)nlr.ret_val)->type), MP_OBJ_FROM_PTR(&mp_type_KeyboardInterrupt))) { // keyboard interrupt + ret = PYEXEC_KEYBOARD_INTERRUPT; + } + #endif } - } + + // CIRCUITPY_CHANGE: Fill in result out argument. if (result != NULL) { result->return_code = ret; - #if CIRCUITPY_ALARM // Don't set the exception object if we exited for deep sleep. - if (ret != 0 && ret != PYEXEC_DEEP_SLEEP) { - #else - if (ret != 0) { + if (ret != 0 + #if CIRCUITPY_ALARM + && ret != PYEXEC_DEEP_SLEEP #endif + ) + { mp_obj_t return_value = (mp_obj_t)nlr.ret_val; result->exception = return_value; result->exception_line = -1; @@ -224,6 +265,10 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input } } + #if MICROPY_PYEXEC_ENABLE_VM_ABORT + nlr_set_abort(NULL); + #endif + #if MICROPY_REPL_INFO // display debugging info if wanted if ((exec_flags & EXEC_FLAG_ALLOW_DEBUGGING) && repl_display_debugging_info) { @@ -776,6 +821,7 @@ int pyexec_friendly_repl(void) { if (ret & (PYEXEC_FORCED_EXIT | PYEXEC_RELOAD)) { return ret; } + mp_hal_stdio_mode_raw(); } } diff --git a/tests/cmdline/repl_autocomplete.py.exp b/tests/cmdline/repl_autocomplete.py.exp index 2e2397bb028..7840e52e8a4 100644 --- a/tests/cmdline/repl_autocomplete.py.exp +++ b/tests/cmdline/repl_autocomplete.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # tests for autocompletion >>> import sys >>> not_exist. @@ -11,4 +11,4 @@ Use \.\+ >>> i.lower('ABC') 'abc' >>> None. ->>> +>>> \$ diff --git a/tests/cmdline/repl_autocomplete_underscore.py b/tests/cmdline/repl_autocomplete_underscore.py index 98bbb699200..e685a7fe7ff 100644 --- a/tests/cmdline/repl_autocomplete_underscore.py +++ b/tests/cmdline/repl_autocomplete_underscore.py @@ -7,18 +7,18 @@ def __init__(self): self.public_attr = 1 self._private_attr = 2 self.__very_private = 3 - + def public_method(self): pass - + def _private_method(self): pass - + @property def public_property(self): return 42 - - @property + + @property def _private_property(self): return 99 diff --git a/tests/cmdline/repl_autocomplete_underscore.py.exp b/tests/cmdline/repl_autocomplete_underscore.py.exp index f9720ef2331..98e6c2aeb05 100644 --- a/tests/cmdline/repl_autocomplete_underscore.py.exp +++ b/tests/cmdline/repl_autocomplete_underscore.py.exp @@ -1,41 +1,41 @@ -MicroPython \.\+ version -Type "help()" for more information. + +Adafruit CircuitPython \.\+ version >>> # Test REPL autocompletion filtering of underscore attributes ->>> +>>> \$ >>> # Start paste mode ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === class TestClass: === def __init__(self): === self.public_attr = 1 === self._private_attr = 2 === self.__very_private = 3 -=== +=== \$ === def public_method(self): === pass -=== +=== \$ === def _private_method(self): === pass -=== +=== \$ === @property === def public_property(self): === return 42 -=== -=== @property +=== \$ +=== @property === def _private_property(self): === return 99 -=== -=== +=== \$ +=== \$ >>> # Paste executed ->>> +>>> \$ >>> # Create an instance >>> obj = TestClass() ->>> +>>> \$ >>> # Test tab completion on the instance >>> # The tab character after `obj.` and 'a' below triggers the completions >>> obj.public_ public_attr public_method public_property >>> obj.public_attr 1 ->>> +>>> \$ diff --git a/tests/cmdline/repl_autoindent.py.exp b/tests/cmdline/repl_autoindent.py.exp index 9ff83a92870..04f00686b20 100644 --- a/tests/cmdline/repl_autoindent.py.exp +++ b/tests/cmdline/repl_autoindent.py.exp @@ -1,22 +1,22 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # tests for autoindent >>> if 1: ... print(1) -... -... -... +... \$ +... \$ +... \$ 1 >>> if 0: ...  print(2) ... else: ... print(3) -... +... \$ 3 >>> if 0: ... print(4) ... else: ... print(5) -... +... \$ 5 ->>> +>>> \$ diff --git a/tests/cmdline/repl_basic.py.exp b/tests/cmdline/repl_basic.py.exp index 26442b64455..5bdcc9d6d32 100644 --- a/tests/cmdline/repl_basic.py.exp +++ b/tests/cmdline/repl_basic.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # basic REPL tests >>> print(1) 1 @@ -7,4 +7,4 @@ Use \.\+ 1 >>> 2 2 ->>> +>>> \$ diff --git a/tests/cmdline/repl_cont.py.exp b/tests/cmdline/repl_cont.py.exp index 6eed4a3e02c..41f2436ac18 100644 --- a/tests/cmdline/repl_cont.py.exp +++ b/tests/cmdline/repl_cont.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # check REPL allows to continue input >>> 1 \\\\ ... + 2 @@ -54,4 +54,4 @@ two >>> if1 = 2 >>> print(if1) 2 ->>> +>>> \$ diff --git a/tests/cmdline/repl_emacs_keys.py.exp b/tests/cmdline/repl_emacs_keys.py.exp index 2e8667a8e6c..4979f8bbfc3 100644 --- a/tests/cmdline/repl_emacs_keys.py.exp +++ b/tests/cmdline/repl_emacs_keys.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # REPL tests of GNU-ish readline navigation >>> # history buffer navigation >>> 1 @@ -16,4 +16,4 @@ Use \.\+ >>> t = 121 >>> \.\+ 'foobar' ->>> +>>> \$ diff --git a/tests/cmdline/repl_inspect.py.exp b/tests/cmdline/repl_inspect.py.exp index 8ece5ffc37f..30257f31aab 100644 --- a/tests/cmdline/repl_inspect.py.exp +++ b/tests/cmdline/repl_inspect.py.exp @@ -1,6 +1,6 @@ test -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # cmdline: -i -c print("test") >>> # -c option combined with -i option results in REPL ->>> +>>> \$ diff --git a/tests/cmdline/repl_lock.py.exp b/tests/cmdline/repl_lock.py.exp index d921fd6ae8e..e6d63fcf200 100644 --- a/tests/cmdline/repl_lock.py.exp +++ b/tests/cmdline/repl_lock.py.exp @@ -1,5 +1,5 @@ -MicroPython \.\+ version -Type "help()" for more information. + +Adafruit CircuitPython \.\+ version >>> import micropython >>> micropython.heap_lock() >>> 1+1 diff --git a/tests/cmdline/repl_micropyinspect.py.exp b/tests/cmdline/repl_micropyinspect.py.exp index 3c9cbc030c0..36bef37c62c 100644 --- a/tests/cmdline/repl_micropyinspect.py.exp +++ b/tests/cmdline/repl_micropyinspect.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # cmdline: cmdline/repl_micropyinspect >>> # setting MICROPYINSPECT environment variable before program exit triggers REPL ->>> +>>> \$ diff --git a/tests/cmdline/repl_paste.py.exp b/tests/cmdline/repl_paste.py.exp index 2b837f85cf9..cc5ac2f0800 100644 --- a/tests/cmdline/repl_paste.py.exp +++ b/tests/cmdline/repl_paste.py.exp @@ -1,21 +1,21 @@ -MicroPython \.\+ version -Type "help()" for more information. + +Adafruit CircuitPython \.\+ version >>> # Test REPL paste mode functionality ->>> +>>> \$ >>> # Basic paste mode with a simple function ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === def hello(): === print('Hello from paste mode!') === hello() -=== +=== \$ Hello from paste mode! ->>> +>>> \$ >>> # Paste mode with multiple indentation levels ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === def calculate(n): === if n > 0: === for i in range(n): @@ -25,109 +25,109 @@ paste mode; Ctrl-C to cancel, Ctrl-D to finish === print(f'Odd: {i}') === else: === print('n must be positive') -=== +=== \$ === calculate(5) -=== +=== \$ Even: 0 Odd: 1 Even: 2 Odd: 3 Even: 4 ->>> +>>> \$ >>> # Paste mode with blank lines ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === def function_with_blanks(): === print('First line') -=== +=== \$ === print('After blank line') -=== -=== +=== \$ +=== \$ === print('After two blank lines') -=== +=== \$ === function_with_blanks() -=== +=== \$ First line After blank line After two blank lines ->>> +>>> \$ >>> # Paste mode with class definition and multiple methods ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === class TestClass: === def __init__(self, value): === self.value = value -=== +=== \$ === def display(self): === print(f'Value is: {self.value}') -=== +=== \$ === def double(self): === self.value *= 2 === return self.value -=== +=== \$ === obj = TestClass(21) === obj.display() === print(f'Doubled: {obj.double()}') === obj.display() -=== +=== \$ Value is: 21 Doubled: 42 Value is: 42 ->>> +>>> \$ >>> # Paste mode with exception handling ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === try: === x = 1 / 0 === except ZeroDivisionError: === print('Caught division by zero') === finally: === print('Finally block executed') -=== +=== \$ Caught division by zero Finally block executed ->>> +>>> \$ >>> # Cancel paste mode with Ctrl-C ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === print('This should not execute') -=== ->>> ->>> +=== \$ +>>> \$ +>>> \$ >>> # Normal REPL still works after cancelled paste >>> print('Back to normal REPL') Back to normal REPL ->>> +>>> \$ >>> # Paste mode with syntax error ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === def bad_syntax(: === print('Missing parameter') -=== +=== \$ Traceback (most recent call last): File "", line 2 SyntaxError: invalid syntax ->>> +>>> \$ >>> # Paste mode with runtime error ->>> +>>> \$ paste mode; Ctrl-C to cancel, Ctrl-D to finish -=== +=== \$ === def will_error(): === undefined_variable -=== +=== \$ === will_error() -=== +=== \$ Traceback (most recent call last): File "", line 5, in File "", line 3, in will_error NameError: name 'undefined_variable' isn't defined ->>> +>>> \$ >>> # Final test to show REPL is still functioning >>> 1 + 2 + 3 6 ->>> +>>> \$ diff --git a/tests/cmdline/repl_sys_ps1_ps2.py.exp b/tests/cmdline/repl_sys_ps1_ps2.py.exp index 452a54fe5ae..d4bcf7a44d5 100644 --- a/tests/cmdline/repl_sys_ps1_ps2.py.exp +++ b/tests/cmdline/repl_sys_ps1_ps2.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # test changing ps1/ps2 >>> import sys >>> sys.ps1 = "PS1" diff --git a/tests/cmdline/repl_words_move.py.exp b/tests/cmdline/repl_words_move.py.exp index ba5c3648cff..41ad3d8e733 100644 --- a/tests/cmdline/repl_words_move.py.exp +++ b/tests/cmdline/repl_words_move.py.exp @@ -1,5 +1,5 @@ -CircuitPython \.\+ version -Use \.\+ + +Adafruit CircuitPython \.\+ version >>> # word movement >>> # backward-word, start in word >>> \.\+ @@ -19,7 +19,7 @@ Use \.\+ >>> # forward-word on eol. if cursor is moved, this will result in a SyntaxError >>> \.\+ 6 ->>> +>>> \$ >>> # kill word >>> # backward-kill-word, start in word >>> \.\+ @@ -33,7 +33,7 @@ Use \.\+ >>> # forward-kill-word, don't start in word >>> \.\+ 3 ->>> +>>> \$ >>> # extra move/kill shortcuts >>> # ctrl-left >>> \.\+ @@ -44,4 +44,4 @@ Use \.\+ >>> # ctrl-w >>> \.\+ 1 ->>> +>>> \$ diff --git a/tests/micropython/opt_level_lineno.py b/tests/micropython/opt_level_lineno.py index ebb404c59fc..4ca76625de4 100644 --- a/tests/micropython/opt_level_lineno.py +++ b/tests/micropython/opt_level_lineno.py @@ -10,5 +10,15 @@ # the expected output is that any line is printed as "line 1" micropython.opt_level(3) -# CIRCUITPY-CHANGE: use traceback.print_exception() instead of sys.print_exception() -exec("try:\n xyz\nexcept NameError as er:\n import traceback\n traceback.print_exception(er)") +# force bytecode emitter, because native emitter doesn't store line numbers +exec(""" +@micropython.bytecode +def f(): + try: + xyz + except NameError as er: + # CIRCUITPY-CHANGE: use traceback.print_exception() instead of sys.print_exception() + import traceback + traceback.print_exception(er) +f() +""") From c5e9b89dd6a9d9bc758c4d615225ca0ad7f5d202 Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Thu, 9 Apr 2026 13:04:43 +0200 Subject: [PATCH 384/876] added support for Pimoroni Badger2350 --- .../pimoroni_badger2350/badger2350-shared.h | 15 ++ .../boards/pimoroni_badger2350/board.c | 225 ++++++++++++++++++ .../boards/pimoroni_badger2350/link.ld | 1 + .../pimoroni_badger2350/mpconfigboard.h | 21 ++ .../pimoroni_badger2350/mpconfigboard.mk | 38 +++ .../pico-sdk-configboard.h | 9 + .../boards/pimoroni_badger2350/pins.c | 131 ++++++++++ 7 files changed, 440 insertions(+) create mode 100644 ports/raspberrypi/boards/pimoroni_badger2350/badger2350-shared.h create mode 100644 ports/raspberrypi/boards/pimoroni_badger2350/board.c create mode 100644 ports/raspberrypi/boards/pimoroni_badger2350/link.ld create mode 100644 ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/pimoroni_badger2350/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/pimoroni_badger2350/pins.c diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/badger2350-shared.h b/ports/raspberrypi/boards/pimoroni_badger2350/badger2350-shared.h new file mode 100644 index 00000000000..4cc67efd4df --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/badger2350-shared.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/digitalio/DigitalInOut.h" + +extern digitalio_digitalinout_obj_t i2c_power_en_pin_obj; +extern const mp_obj_fun_builtin_fixed_t set_update_speed_obj; +extern const mp_obj_fun_builtin_fixed_t get_reset_state_obj; +extern const mp_obj_fun_builtin_fixed_t on_reset_pressed_obj; diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/board.c b/ports/raspberrypi/boards/pimoroni_badger2350/board.c new file mode 100644 index 00000000000..21e0e3f1ba5 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/board.c @@ -0,0 +1,225 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Bob Abeles +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" + +#include "mpconfigboard.h" +#include "shared-bindings/busio/SPI.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/displayio/__init__.h" +#include "supervisor/shared/board.h" +#include "supervisor/board.h" +#include "badger2350-shared.h" + +#include "hardware/gpio.h" +#include "hardware/structs/iobank0.h" + +digitalio_digitalinout_obj_t i2c_power_en_pin_obj; +static volatile uint32_t reset_button_state = 0; + +// Forward declaration to satisfy -Wmissing-prototypes +static void preinit_button_state(void) __attribute__((constructor(101))); + + +// pin definitions +// Button pin definitions for Badger2350 +#define SW_A_PIN 7 +#define SW_B_PIN 9 +#define SW_C_PIN 10 +#define SW_DOWN_PIN 6 +#define SW_UP_PIN 11 + +static const uint8_t _sw_pin_nrs[] = { + SW_A_PIN, SW_B_PIN, SW_C_PIN, SW_DOWN_PIN, SW_UP_PIN +}; + +// Mask of all front button pins +#define SW_MASK ((1 << SW_A_PIN) | (1 << SW_B_PIN) | (1 << SW_C_PIN) | \ + (1 << SW_DOWN_PIN) | (1 << SW_UP_PIN)) + +// This function runs BEFORE main() via constructor attribute! +// This is the key to fast button state detection. +// Priority 101 = runs very early + +static void preinit_button_state(void) { + // Configure button pins as inputs with pull-downs using direct register access + // This is faster than SDK functions and works before full init + + for (size_t i = 0; i < sizeof(_sw_pin_nrs); i++) { + uint8_t pin_nr = _sw_pin_nrs[i]; + // Set as input + sio_hw->gpio_oe_clr = 1u << pin_nr; + // enable pull-ups + pads_bank0_hw->io[pin_nr] = PADS_BANK0_GPIO0_IE_BITS | + PADS_BANK0_GPIO0_PUE_BITS; + // Set GPIO function + iobank0_hw->io[pin_nr].ctrl = 5; // SIO function + } + + // Small delay for pins to settle (just a few cycles) + for (volatile int i = 0; i < 100; i++) { + __asm volatile ("nop"); + } + + // Capture button states NOW - before anything else runs + reset_button_state = ~sio_hw->gpio_in & SW_MASK; +} + +static mp_obj_t _get_reset_state(void) { + return mp_obj_new_int(reset_button_state); +} +MP_DEFINE_CONST_FUN_OBJ_0(get_reset_state_obj,_get_reset_state); + +static mp_obj_t _on_reset_pressed(mp_obj_t pin_in) { + mcu_pin_obj_t *pin = MP_OBJ_TO_PTR(pin_in); + return mp_obj_new_bool( + (reset_button_state & (1<number)) != 0); +} +MP_DEFINE_CONST_FUN_OBJ_1(on_reset_pressed_obj,_on_reset_pressed); + +// The display uses an SSD1680 control chip. +uint8_t _start_sequence[] = { + 0x12, 0x80, 0x00, 0x14, // soft reset and wait 20ms + 0x11, 0x00, 0x01, 0x03, // Ram data entry mode + 0x3c, 0x00, 0x01, 0x03, // border color + 0x2c, 0x00, 0x01, 0x28, // Set vcom voltage + 0x03, 0x00, 0x01, 0x17, // Set gate voltage + 0x04, 0x00, 0x03, 0x41, 0xae, 0x32, // Set source voltage + 0x4e, 0x00, 0x01, 0x00, // ram x count + 0x4f, 0x00, 0x02, 0x00, 0x00, // ram y count + 0x01, 0x00, 0x03, 0x07, 0x01, 0x00, // set display size + 0x32, 0x00, 0x99, // Update waveforms + + // offset 44 + 0x40, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L0 + 0xA0, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L1 + 0xA8, 0x65, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L2 + 0xAA, 0x65, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L3 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L4 + + // offset 104 + 0x02, 0x00, 0x00, 0x05, 0x0A, 0x00, 0x03, // Group0 (with default speed==0) + // offset 111 + 0x19, 0x19, 0x00, 0x02, 0x00, 0x00, 0x03, // Group1 (with default speed==0) + // offset 118 + 0x05, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x03, // Group2 (with default speed==0) + + // offset 125 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group3 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group4 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group5 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group6 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group8 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group9 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group11 + 0x44, 0x42, 0x22, 0x22, 0x23, 0x32, 0x00, // Config + 0x00, 0x00, // FR, XON + + 0x22, 0x00, 0x01, 0xc7, // display update mode + +}; + +const uint8_t _stop_sequence[] = { + 0x10, 0x00, 0x01, 0x01 // DSM deep sleep mode 1 +}; + +const uint8_t _refresh_sequence[] = { + 0x20, 0x00, 0x00 // ADUS +}; + +// Change update speed. This changes the repeat-count in the LUTs +// Pimoroni uses: 0 == slow ... 3 == fast +// and calculates the LUT repeat count as 3-speed + +#define SPEED_OFFSET_1 110 +#define SPEED_OFFSET_2 117 +#define SPEED_OFFSET_3 124 + +static mp_obj_t _set_update_speed(mp_obj_t speed_in) { + mp_int_t speed = mp_obj_get_int(speed_in); + uint8_t count = (uint8_t)3 - (uint8_t)(speed & 3); + _start_sequence[SPEED_OFFSET_1] = count; + _start_sequence[SPEED_OFFSET_2] = count; + _start_sequence[SPEED_OFFSET_3] = count; + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(set_update_speed_obj,_set_update_speed); + +void board_init(void) { + // Drive the I2C_POWER_EN pin high + i2c_power_en_pin_obj.base.type = &digitalio_digitalinout_type; + common_hal_digitalio_digitalinout_construct( + &i2c_power_en_pin_obj, &pin_GPIO27); + common_hal_digitalio_digitalinout_switch_to_output( + &i2c_power_en_pin_obj, true, DRIVE_MODE_PUSH_PULL); + common_hal_digitalio_digitalinout_never_reset(&i2c_power_en_pin_obj); + + fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, NULL, false); + common_hal_busio_spi_never_reset(spi); + + bus->base.type = &fourwire_fourwire_type; + common_hal_fourwire_fourwire_construct(bus, + spi, + MP_OBJ_FROM_PTR(&pin_GPIO20), // EPD_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO17), // EPD_CS Chip select + MP_OBJ_FROM_PTR(&pin_GPIO21), // EPD_RST Reset + 12000000, // Baudrate + 0, // Polarity + 0); // Phase + + // create and configure display + epaperdisplay_epaperdisplay_obj_t *display = &allocate_display()->epaper_display; + display->base.type = &epaperdisplay_epaperdisplay_type; + + epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; + args.bus = bus; + args.start_sequence = _start_sequence; + args.start_sequence_len = sizeof(_start_sequence); + args.stop_sequence = _stop_sequence; + args.stop_sequence_len = sizeof(_stop_sequence); + args.width = 264; + args.height = 176; + args.ram_width = 250; + args.ram_height = 296; + args.rotation = 270; + args.set_column_window_command = 0x44; + args.set_row_window_command = 0x45; + args.set_current_column_command = 0x4e; + args.set_current_row_command = 0x4f; + args.write_black_ram_command = 0x24; + args.write_color_ram_command = 0x26; + args.color_bits_inverted = true; + args.refresh_sequence = _refresh_sequence; + args.refresh_sequence_len = sizeof(_refresh_sequence); + args.refresh_time = 1.0; + args.busy_pin = &pin_GPIO16; + args.busy_state = true; + args.seconds_per_frame = 3.0; + args.grayscale = true; + args.two_byte_sequence_length = true; + args.address_little_endian = true; + common_hal_epaperdisplay_epaperdisplay_construct(display, &args); +} + +void board_deinit(void) { + epaperdisplay_epaperdisplay_obj_t *display = &displays[0].epaper_display; + if (display->base.type == &epaperdisplay_epaperdisplay_type) { + while (common_hal_epaperdisplay_epaperdisplay_get_busy(display)) { + RUN_BACKGROUND_TASKS; + } + } + common_hal_displayio_release_displays(); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/link.ld b/ports/raspberrypi/boards/pimoroni_badger2350/link.ld new file mode 100644 index 00000000000..e814bead4c5 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/link.ld @@ -0,0 +1 @@ +firmware_size = 1532k; diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.h b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.h new file mode 100644 index 00000000000..6cffd190ad6 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Bernhard Bablok +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Pimoroni Badger 2350" +#define MICROPY_HW_MCU_NAME "rp2350a" + +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_PULL (1) +#define CIRCUITPY_DIGITALIO_HAVE_INVALID_DRIVE_MODE (1) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO0) + +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO18) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO19) + +#define CIRCUITPY_PSRAM_CHIP_SELECT (&pin_GPIO8) diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk new file mode 100644 index 00000000000..0157ccf1499 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk @@ -0,0 +1,38 @@ +USB_VID = 0x2E8A +USB_PID = 0x1100 +USB_PRODUCT = "Pimoroni Badger 2350" +USB_MANUFACTURER = "Pimoroni" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +CIRCUITPY__EVE = 1 + +CIRCUITPY_CYW43 = 1 +CIRCUITPY_SSL = 1 +CIRCUITPY_HASHLIB = 1 +CIRCUITPY_WEB_WORKFLOW = 1 +CIRCUITPY_MDNS = 1 +CIRCUITPY_SOCKETPOOL = 1 +CIRCUITPY_WIFI = 1 + +# PIO clock divider set to 2 (default), consider changing if TM2 gSPI +# becomes unreliable. +CFLAGS += \ + -DCYW43_PIN_WL_DYNAMIC=0 \ + -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ + -DCYW43_DEFAULT_PIN_WL_REG_ON=23 \ + -DCYW43_DEFAULT_PIN_WL_CLOCK=29 \ + -DCYW43_DEFAULT_PIN_WL_DATA_IN=24 \ + -DCYW43_DEFAULT_PIN_WL_DATA_OUT=24 \ + -DCYW43_DEFAULT_PIN_WL_CS=25 \ + -DCYW43_WL_GPIO_COUNT=3 \ + -DCYW43_PIO_CLOCK_DIV_INT=2 \ + -DCYW43_PIO_CLOCK_DIV_FRAC=0 +# Must be accompanied by a linker script change +CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' + +FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/pimoroni_badger2350/pico-sdk-configboard.h new file mode 100644 index 00000000000..42e0612bf8b --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Bob Abeles +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/pins.c b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c new file mode 100644 index 00000000000..64c1874e284 --- /dev/null +++ b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c @@ -0,0 +1,131 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 Bob Abeles +// +// SPDX-License-Identifier: MIT + +#include "py/objtuple.h" +#include "shared-bindings/board/__init__.h" +#include "shared-module/displayio/__init__.h" +#include "badger2350-shared.h" + + +// LUT manipulation +static const mp_rom_map_elem_t lut_update_table[] = { + { MP_ROM_QSTR(MP_QSTR_SET_UPDATE_SPEED), (mp_obj_t)&set_update_speed_obj }, + { MP_ROM_QSTR(MP_QSTR_SPEED_SLOW), MP_ROM_INT(0) }, + { MP_ROM_QSTR(MP_QSTR_SPEED_FAST), MP_ROM_INT(1) }, + { MP_ROM_QSTR(MP_QSTR_SPEED_FASTER), MP_ROM_INT(2) }, + { MP_ROM_QSTR(MP_QSTR_SPEED_FASTEST), MP_ROM_INT(3) }, +}; +MP_DEFINE_CONST_DICT(lut_update_dict, lut_update_table); + +MP_DEFINE_CONST_OBJ_TYPE( + display_type, + MP_QSTR_display, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS | ~MP_TYPE_FLAG_BINDS_SELF, + locals_dict, &lut_update_dict +); + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_PTR(&display_type) }, + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LED0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_LED1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_LED2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_LED3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SW_DOWN), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SW_A), MP_ROM_PTR(&pin_GPIO7) }, + + // GP8 is reserved for PSRAM chip select + + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_SW_B), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_SW_C), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SW_UP), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_VBUS_SENSE), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_RTC_ALARM), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SW_RESET), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SW_INT), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_INKY_BUSY), MP_ROM_PTR(&pin_GPIO16) }, + + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_INKY_CS), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_INKY_DC), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_INKY_RST), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_SW_HOME), MP_ROM_PTR(&pin_GPIO22) }, + + // GP23, GP24, GP25, and GP29 are reserved for RM2 gSPI + + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_VBAT_SENSE), MP_ROM_PTR(&pin_GPIO26) }, + + // GP27 is the used for I2C power-enable, driven high by board.c + { MP_ROM_QSTR(MP_QSTR_I2C_POWER_EN), MP_ROM_PTR(&i2c_power_en_pin_obj) }, + + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_SENSE_1V1), MP_ROM_PTR(&pin_GPIO28) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + + // Pins accessed though the RM2 module (CYW43439) + // CYW0, CYW1 is unconnected + { MP_ROM_QSTR(MP_QSTR_CHARGE_STAT), MP_ROM_PTR(&pin_CYW2) }, + + { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)}, + + // button-state on reset + { MP_ROM_QSTR(MP_QSTR_RESET_STATE), (mp_obj_t)&get_reset_state_obj }, + { MP_ROM_QSTR(MP_QSTR_ON_RESET_PRESSED), (mp_obj_t)&on_reset_pressed_obj }, + +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From 3d8c75f350cc26a2ed4adf8e773c50e02b39ed10 Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Thu, 9 Apr 2026 13:31:36 +0200 Subject: [PATCH 385/876] fixed formatting --- .../boards/pimoroni_badger2350/board.c | 38 +++++++++---------- .../boards/pimoroni_badger2350/pins.c | 2 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/board.c b/ports/raspberrypi/boards/pimoroni_badger2350/board.c index 21e0e3f1ba5..1da13b80339 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2350/board.c +++ b/ports/raspberrypi/boards/pimoroni_badger2350/board.c @@ -41,7 +41,7 @@ static const uint8_t _sw_pin_nrs[] = { // Mask of all front button pins #define SW_MASK ((1 << SW_A_PIN) | (1 << SW_B_PIN) | (1 << SW_C_PIN) | \ - (1 << SW_DOWN_PIN) | (1 << SW_UP_PIN)) + (1 << SW_DOWN_PIN) | (1 << SW_UP_PIN)) // This function runs BEFORE main() via constructor attribute! // This is the key to fast button state detection. @@ -50,38 +50,38 @@ static const uint8_t _sw_pin_nrs[] = { static void preinit_button_state(void) { // Configure button pins as inputs with pull-downs using direct register access // This is faster than SDK functions and works before full init - + for (size_t i = 0; i < sizeof(_sw_pin_nrs); i++) { uint8_t pin_nr = _sw_pin_nrs[i]; // Set as input sio_hw->gpio_oe_clr = 1u << pin_nr; // enable pull-ups - pads_bank0_hw->io[pin_nr] = PADS_BANK0_GPIO0_IE_BITS | - PADS_BANK0_GPIO0_PUE_BITS; + pads_bank0_hw->io[pin_nr] = PADS_BANK0_GPIO0_IE_BITS | + PADS_BANK0_GPIO0_PUE_BITS; // Set GPIO function iobank0_hw->io[pin_nr].ctrl = 5; // SIO function } - + // Small delay for pins to settle (just a few cycles) for (volatile int i = 0; i < 100; i++) { __asm volatile ("nop"); } - + // Capture button states NOW - before anything else runs reset_button_state = ~sio_hw->gpio_in & SW_MASK; } static mp_obj_t _get_reset_state(void) { - return mp_obj_new_int(reset_button_state); + return mp_obj_new_int(reset_button_state); } -MP_DEFINE_CONST_FUN_OBJ_0(get_reset_state_obj,_get_reset_state); +MP_DEFINE_CONST_FUN_OBJ_0(get_reset_state_obj, _get_reset_state); static mp_obj_t _on_reset_pressed(mp_obj_t pin_in) { - mcu_pin_obj_t *pin = MP_OBJ_TO_PTR(pin_in); - return mp_obj_new_bool( - (reset_button_state & (1<number)) != 0); + mcu_pin_obj_t *pin = MP_OBJ_TO_PTR(pin_in); + return mp_obj_new_bool( + (reset_button_state & (1 << pin->number)) != 0); } -MP_DEFINE_CONST_FUN_OBJ_1(on_reset_pressed_obj,_on_reset_pressed); +MP_DEFINE_CONST_FUN_OBJ_1(on_reset_pressed_obj, _on_reset_pressed); // The display uses an SSD1680 control chip. uint8_t _start_sequence[] = { @@ -144,15 +144,15 @@ const uint8_t _refresh_sequence[] = { #define SPEED_OFFSET_3 124 static mp_obj_t _set_update_speed(mp_obj_t speed_in) { - mp_int_t speed = mp_obj_get_int(speed_in); - uint8_t count = (uint8_t)3 - (uint8_t)(speed & 3); - _start_sequence[SPEED_OFFSET_1] = count; - _start_sequence[SPEED_OFFSET_2] = count; - _start_sequence[SPEED_OFFSET_3] = count; - return mp_const_none; + mp_int_t speed = mp_obj_get_int(speed_in); + uint8_t count = (uint8_t)3 - (uint8_t)(speed & 3); + _start_sequence[SPEED_OFFSET_1] = count; + _start_sequence[SPEED_OFFSET_2] = count; + _start_sequence[SPEED_OFFSET_3] = count; + return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_1(set_update_speed_obj,_set_update_speed); +MP_DEFINE_CONST_FUN_OBJ_1(set_update_speed_obj, _set_update_speed); void board_init(void) { // Drive the I2C_POWER_EN pin high diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/pins.c b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c index 64c1874e284..9ba93cd47cb 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2350/pins.c +++ b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c @@ -25,7 +25,7 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_QSTR_display, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS | ~MP_TYPE_FLAG_BINDS_SELF, locals_dict, &lut_update_dict -); + ); static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS From a5cbf06ffaa07dd5a2244cf613fc757b050a0cd0 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Apr 2026 12:21:35 -0500 Subject: [PATCH 386/876] enable aesio on zephyr port and add test for it. Add Containerfile and scripts for native_sim build. --- .../autogen_board_info.toml | 4 +- .../autogen_board_info.toml | 2 +- .../native/native_sim/autogen_board_info.toml | 2 +- .../nrf5340bsim/autogen_board_info.toml | 4 +- .../nordic/nrf5340dk/autogen_board_info.toml | 4 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 4 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 4 +- .../nordic/nrf7002dk/autogen_board_info.toml | 6 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 4 +- .../nxp/frdm_rw612/autogen_board_info.toml | 6 +- .../mimxrt1170_evk/autogen_board_info.toml | 4 +- .../autogen_board_info.toml | 9 +- .../rpi_pico2_zephyr/autogen_board_info.toml | 9 +- .../rpi_pico_w_zephyr/autogen_board_info.toml | 9 +- .../rpi_pico_zephyr/autogen_board_info.toml | 9 +- .../da14695_dk_usb/autogen_board_info.toml | 4 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 4 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 4 +- .../nucleo_n657x0_q/autogen_board_info.toml | 4 +- .../nucleo_u575zi_q/autogen_board_info.toml | 4 +- .../st/stm32h750b_dk/autogen_board_info.toml | 4 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 4 +- .../stm32wba65i_dk1/autogen_board_info.toml | 4 +- .../zephyr-cp/cptools/build_circuitpython.py | 1 + .../zephyr-cp/native_sim_build_Containerfile | 37 +++ .../native_sim_build_init_container.sh | 42 ++++ .../native_sim_build_run_container.sh | 23 ++ ports/zephyr-cp/tests/test_aesio.py | 223 ++++++++++++++++++ 28 files changed, 384 insertions(+), 54 deletions(-) create mode 100644 ports/zephyr-cp/native_sim_build_Containerfile create mode 100755 ports/zephyr-cp/native_sim_build_init_container.sh create mode 100755 ports/zephyr-cp/native_sim_build_run_container.sh create mode 100644 ports/zephyr-cp/tests/test_aesio.py diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 7b1fb9a0d6f..17065b90292 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = true # Zephyr board has nvm onewireio = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index 05cc100c6e5..3d7a2b29a3f 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 4b657282ef6..5b8fcfd0dea 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 00f71783639..9842ea3d88d 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 92cb4ef1a80..065a708c505 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 5d5f325af81..b8bad240351 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 9792f8aca74..22b92d49f49 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 62fa896c0ec..184ff34b7ef 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -56,7 +56,7 @@ i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false imagecapture = false -ipaddress = false +ipaddress = true # Zephyr networking enabled is31fl3741 = false jpegio = false keypad = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index b121a1e8234..6da4ebc66c5 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index e5b51390538..19b3b7cc0e1 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -56,7 +56,7 @@ i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false i2ctarget = false imagecapture = false -ipaddress = false +ipaddress = true # Zephyr networking enabled is31fl3741 = false jpegio = false keypad = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 57ff5fe8c81..702f5900eee 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index 8c1f7018f12..10ca2517b61 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio @@ -62,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -70,9 +71,9 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false -nvm = false +nvm = true # Zephyr board has nvm onewireio = false os = true paralleldisplaybus = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index cdffc295701..15b36b725af 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio @@ -62,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -70,9 +71,9 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false -nvm = false +nvm = true # Zephyr board has nvm onewireio = false os = true paralleldisplaybus = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index d8cee739d65..1f01990b5f2 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio @@ -62,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -70,9 +71,9 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false -nvm = false +nvm = true # Zephyr board has nvm onewireio = false os = true paralleldisplaybus = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index 40fb5baf34a..c8624cdde6c 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -24,6 +24,7 @@ audioio = false audiomixer = false audiomp3 = false audiopwmio = false +audiospeed = false aurora_epaper = false bitbangio = false bitmapfilter = true # Zephyr board has busio @@ -62,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -70,9 +71,9 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false -nvm = false +nvm = true # Zephyr board has nvm onewireio = false os = true paralleldisplaybus = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index e11d98ac9a1..ea9ed4c2577 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 47a54e9632a..c28c03b2c8e 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index c4a071b0688..1b0c652b7d5 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index f526b1e90fa..c05bfa1d17e 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 2c904026fba..d6a0a27e0cd 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index 3e8208d82c9..599ec4ec4d2 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index a85cd9e3cc5..c5505bee932 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 36213878c29..0fe01348348 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = false onewireio = false diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 73918a06a5a..3edbc1efdf6 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -61,6 +61,7 @@ "io", "math", "msgpack", + "aesio", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] diff --git a/ports/zephyr-cp/native_sim_build_Containerfile b/ports/zephyr-cp/native_sim_build_Containerfile new file mode 100644 index 00000000000..8b9db9dc559 --- /dev/null +++ b/ports/zephyr-cp/native_sim_build_Containerfile @@ -0,0 +1,37 @@ +FROM ubuntu:24.04 +ENV DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC +ENV PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig + +RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y --no-install-recommends \ + git cmake ninja-build gperf ccache dfu-util device-tree-compiler \ + wget python3 python3-dev python3-pip python3-venv python3-setuptools \ + python3-tk python3-wheel xz-utils file make gcc \ + gcc-multilib g++-multilib libc6-dev-i386 \ + libsdl2-dev:i386 libsdl2-image-dev:i386 \ + libmagic1 mtools pkg-config ca-certificates unzip \ + protobuf-compiler sudo \ + && rm -rf /var/lib/apt/lists/* + +RUN useradd -m -s /bin/bash dev \ + && echo 'dev ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/dev \ + && chmod 440 /etc/sudoers.d/dev +USER dev +WORKDIR /home/dev + +RUN python3 -m venv /home/dev/.venv +ENV PATH="/home/dev/.venv/bin:${PATH}" +RUN pip install --no-cache-dir west pytest pyelftools pyyaml intelhex protobuf grpcio-tools + +# The repo is expected to be bind-mounted here at runtime: +# podman run -v ~/circuitpython:/home/dev/circuitpython:Z --userns=keep-id ... +# On first run, inside the container do: +# cd ~/circuitpython/ports/zephyr-cp +# west init -l zephyr-config +# west update +# west zephyr-export +# pip install -r zephyr/scripts/requirements.txt +# pip install -r ../../requirements-dev.txt +# west sdk install -t x86_64-zephyr-elf +# python ../../tools/ci_fetch_deps.py zephyr-cp +WORKDIR /home/dev/circuitpython/ports/zephyr-cp +CMD ["/bin/bash"] diff --git a/ports/zephyr-cp/native_sim_build_init_container.sh b/ports/zephyr-cp/native_sim_build_init_container.sh new file mode 100755 index 00000000000..705fb3eb9ff --- /dev/null +++ b/ports/zephyr-cp/native_sim_build_init_container.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# One-time setup to run INSIDE the zephyr-cp-dev container on the first +# launch against a fresh bind-mounted circuitpython checkout. +# +# Usage (inside the container): +# cd ~/circuitpython/ports/zephyr-cp +# ./first_run.sh +# +# Safe to re-run; west/pip/etc. are idempotent. +set -euo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")" + +echo "==> west init" +if [ ! -d ../../.west ]; then + west init -l zephyr-config +else + echo " (already initialized, skipping)" +fi + +echo "==> west update" +west update + +echo "==> west zephyr-export" +west zephyr-export + +echo "==> pip install Zephyr requirements" +pip install -r zephyr/scripts/requirements.txt + +echo "==> pip install CircuitPython dev requirements" +pip install -r ../../requirements-dev.txt + +echo "==> west sdk install (x86_64-zephyr-elf)" +west sdk install -t x86_64-zephyr-elf + +echo "==> fetch port submodules" +git config --global --add safe.directory /home/dev/circuitpython +python ../../tools/ci_fetch_deps.py zephyr-cp + +echo +echo "First-run setup complete." +echo "You can now build with: make BOARD=native_native_sim" diff --git a/ports/zephyr-cp/native_sim_build_run_container.sh b/ports/zephyr-cp/native_sim_build_run_container.sh new file mode 100755 index 00000000000..e30aca22b46 --- /dev/null +++ b/ports/zephyr-cp/native_sim_build_run_container.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Launch (or re-attach to) the zephyr-cp-dev container with the enclosing +# circuitpython checkout bind-mounted at /home/dev/circuitpython. Works from +# any CWD — the mount is resolved relative to this script's location. +# +# On first invocation, creates a persistent container named "zcp". On +# subsequent invocations, re-starts the same container so installed state +# (e.g. the Zephyr SDK under /home/dev/zephyr-sdk-*) survives across sessions. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +CONTAINER_NAME="zcp" +IMAGE="zephyr-cp-dev" + +if podman container exists "$CONTAINER_NAME"; then + exec podman start -ai "$CONTAINER_NAME" +else + exec podman run -it --name "$CONTAINER_NAME" \ + -v "$REPO_ROOT:/home/dev/circuitpython:Z" \ + --userns=keep-id \ + "$IMAGE" "$@" +fi diff --git a/ports/zephyr-cp/tests/test_aesio.py b/ports/zephyr-cp/tests/test_aesio.py new file mode 100644 index 00000000000..3ae016ac8e3 --- /dev/null +++ b/ports/zephyr-cp/tests/test_aesio.py @@ -0,0 +1,223 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the aesio module.""" + +import pytest + +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes + + +KEY = b"Sixteen byte key" +PLAINTEXT = b"CircuitPython!!!" # 16 bytes + + +ECB_CODE = """\ +import aesio + +key = b'Sixteen byte key' +inp = b'CircuitPython!!!' +outp = bytearray(len(inp)) +cipher = aesio.AES(key, aesio.MODE_ECB) +cipher.encrypt_into(inp, outp) +print(f"ciphertext_hex: {outp.hex()}") + +decrypted = bytearray(len(outp)) +cipher.decrypt_into(bytes(outp), decrypted) +print(f"decrypted: {bytes(decrypted)}") +print(f"match: {bytes(decrypted) == inp}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": ECB_CODE}) +def test_aesio_ecb(circuitpython): + """AES-ECB round-trips and matches CPython cryptography's output.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + encryptor = Cipher(algorithms.AES(KEY), modes.ECB()).encryptor() + expected_hex = (encryptor.update(PLAINTEXT) + encryptor.finalize()).hex() + assert f"ciphertext_hex: {expected_hex}" in output + assert "match: True" in output + assert "done" in output + + +IV = b"InitializationVe" # 16 bytes +CBC_PLAINTEXT = b"CircuitPython!!!" * 2 # 32 bytes, multiple of 16 +CTR_PLAINTEXT = b"CircuitPython is fun to use!" # 28 bytes, arbitrary length + + +CBC_CODE = """\ +import aesio + +key = b'Sixteen byte key' +iv = b'InitializationVe' +inp = b'CircuitPython!!!' * 2 +outp = bytearray(len(inp)) +cipher = aesio.AES(key, aesio.MODE_CBC, iv) +print(f"mode: {cipher.mode}") +cipher.encrypt_into(inp, outp) +print(f"ciphertext_hex: {outp.hex()}") + +# Re-create cipher to reset IV state for decryption. +cipher2 = aesio.AES(key, aesio.MODE_CBC, iv) +decrypted = bytearray(len(outp)) +cipher2.decrypt_into(bytes(outp), decrypted) +print(f"match: {bytes(decrypted) == inp}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CBC_CODE}) +def test_aesio_cbc(circuitpython): + """AES-CBC round-trips and matches CPython cryptography's output.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + encryptor = Cipher(algorithms.AES(KEY), modes.CBC(IV)).encryptor() + expected_hex = (encryptor.update(CBC_PLAINTEXT) + encryptor.finalize()).hex() + assert "mode: 2" in output + assert f"ciphertext_hex: {expected_hex}" in output + assert "match: True" in output + assert "done" in output + + +CTR_CODE = """\ +import aesio + +key = b'Sixteen byte key' +iv = b'InitializationVe' +inp = b'CircuitPython is fun to use!' +outp = bytearray(len(inp)) +cipher = aesio.AES(key, aesio.MODE_CTR, iv) +print(f"mode: {cipher.mode}") +cipher.encrypt_into(inp, outp) +print(f"ciphertext_hex: {outp.hex()}") + +cipher2 = aesio.AES(key, aesio.MODE_CTR, iv) +decrypted = bytearray(len(outp)) +cipher2.decrypt_into(bytes(outp), decrypted) +print(f"decrypted: {bytes(decrypted)}") +print(f"match: {bytes(decrypted) == inp}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CTR_CODE}) +def test_aesio_ctr(circuitpython): + """AES-CTR handles arbitrary-length buffers and matches CPython output.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + encryptor = Cipher(algorithms.AES(KEY), modes.CTR(IV)).encryptor() + expected_hex = (encryptor.update(CTR_PLAINTEXT) + encryptor.finalize()).hex() + assert "mode: 6" in output + assert f"ciphertext_hex: {expected_hex}" in output + assert "match: True" in output + assert "done" in output + + +REKEY_CODE = """\ +import aesio + +key1 = b'Sixteen byte key' +key2 = b'Another 16 byte!' +inp = b'CircuitPython!!!' + +cipher = aesio.AES(key1, aesio.MODE_ECB) +out1 = bytearray(16) +cipher.encrypt_into(inp, out1) +print(f"ct1_hex: {out1.hex()}") + +cipher.rekey(key2) +out2 = bytearray(16) +cipher.encrypt_into(inp, out2) +print(f"ct2_hex: {out2.hex()}") +print(f"different: {bytes(out1) != bytes(out2)}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": REKEY_CODE}) +def test_aesio_rekey(circuitpython): + """rekey() switches the active key; ciphertexts match CPython for both keys.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + enc1 = Cipher(algorithms.AES(b"Sixteen byte key"), modes.ECB()).encryptor() + ct1 = (enc1.update(PLAINTEXT) + enc1.finalize()).hex() + enc2 = Cipher(algorithms.AES(b"Another 16 byte!"), modes.ECB()).encryptor() + ct2 = (enc2.update(PLAINTEXT) + enc2.finalize()).hex() + assert f"ct1_hex: {ct1}" in output + assert f"ct2_hex: {ct2}" in output + assert "different: True" in output + assert "done" in output + + +MODE_PROPERTY_CODE = """\ +import aesio + +key = b'Sixteen byte key' +iv = b'InitializationVe' +cipher = aesio.AES(key, aesio.MODE_ECB) +print(f"initial: {cipher.mode}") +print(f"ECB={aesio.MODE_ECB} CBC={aesio.MODE_CBC} CTR={aesio.MODE_CTR}") + +for name, m in (("ECB", aesio.MODE_ECB), ("CBC", aesio.MODE_CBC), ("CTR", aesio.MODE_CTR)): + cipher.mode = m + print(f"set_{name}: {cipher.mode}") + +try: + cipher.mode = 99 +except NotImplementedError as e: + print(f"bad_mode: NotImplementedError") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": MODE_PROPERTY_CODE}) +def test_aesio_mode_property(circuitpython): + """The mode property is readable, writable, and rejects unsupported values.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "initial: 1" in output + assert "ECB=1 CBC=2 CTR=6" in output + assert "set_ECB: 1" in output + assert "set_CBC: 2" in output + assert "set_CTR: 6" in output + assert "bad_mode: NotImplementedError" in output + assert "done" in output + + +KEY_LENGTHS_CODE = """\ +import aesio + +inp = b'CircuitPython!!!' +for key in (b'A' * 16, b'B' * 24, b'C' * 32): + cipher = aesio.AES(key, aesio.MODE_ECB) + out = bytearray(16) + cipher.encrypt_into(inp, out) + print(f"len{len(key)}: {out.hex()}") + +try: + aesio.AES(b'too short', aesio.MODE_ECB) +except ValueError: + print("bad_key: ValueError") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": KEY_LENGTHS_CODE}) +def test_aesio_key_lengths(circuitpython): + """AES-128/192/256 keys all work and match CPython; bad key length raises.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + for key in (b"A" * 16, b"B" * 24, b"C" * 32): + encryptor = Cipher(algorithms.AES(key), modes.ECB()).encryptor() + expected = (encryptor.update(PLAINTEXT) + encryptor.finalize()).hex() + assert f"len{len(key)}: {expected}" in output + assert "bad_key: ValueError" in output + assert "done" in output From b255a15053ca2cc2037705d8ce7625258bc06803 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 8 Apr 2026 22:23:16 -0400 Subject: [PATCH 387/876] fix more tests --- py/mpprint.c | 1 + py/objfun.c | 3 ++- tests/extmod/binascii_unhexlify.py | 2 +- tests/thread/disable_irq.py | 12 +++++++++--- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/py/mpprint.c b/py/mpprint.c index b09ee398b6d..bb1f3d45e8e 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -597,6 +597,7 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { } else { base = 16; } + // CIRCUITPY-CHANGE: include "0x" for 'p' and 'P'. if (fmt_chr == 'p' || fmt_chr == 'P') { #if SUPPORT_INT_BASE_PREFIX chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags | PF_FLAG_SHOW_PREFIX, fill, width); diff --git a/py/objfun.c b/py/objfun.c index e6a923d59e8..34565cf6336 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -184,7 +184,8 @@ static mp_obj_t fun_bc_make_new(const mp_obj_type_t *type, size_t n_args, size_t static void fun_bc_print(const mp_print_t *print, mp_obj_t o_in, mp_print_kind_t kind) { (void)kind; mp_obj_fun_bc_t *o = MP_OBJ_TO_PTR(o_in); - mp_printf(print, "", mp_obj_fun_get_name(o_in), o); + // CIRCUITPY-CHANGE: %p already prints "0x", so don't include it explicitly. + mp_printf(print, "", mp_obj_fun_get_name(o_in), o); } #endif diff --git a/tests/extmod/binascii_unhexlify.py b/tests/extmod/binascii_unhexlify.py index fe1d50780ee..b08704cba65 100644 --- a/tests/extmod/binascii_unhexlify.py +++ b/tests/extmod/binascii_unhexlify.py @@ -14,7 +14,7 @@ # CIRCUITPY-CHANGE # Unicode strings can be decoded -print(binascii.unhexlify("313233344142434461626364")) +print(unhexlify("313233344142434461626364")) try: a = unhexlify(b"0") # odd buffer length diff --git a/tests/thread/disable_irq.py b/tests/thread/disable_irq.py index 3f1ac74f308..596e3e477b9 100644 --- a/tests/thread/disable_irq.py +++ b/tests/thread/disable_irq.py @@ -1,8 +1,14 @@ # Ensure that disabling IRQs creates mutual exclusion between threads # (also tests nesting of disable_irq across threads) -import machine -import time -import _thread + +# CIRCUITPY-CHANGE: no machine +try: + import machine + import time + import _thread +except ImportError: + print("SKIP") + raise SystemExit if not hasattr(machine, "disable_irq"): print("SKIP") From e76bc123763d5c3c110d4ca80a2c7a1e8ebdde56 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 9 Apr 2026 19:11:33 -0400 Subject: [PATCH 388/876] update asyncio library, which fixes tests --- frozen/Adafruit_CircuitPython_asyncio | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frozen/Adafruit_CircuitPython_asyncio b/frozen/Adafruit_CircuitPython_asyncio index e69ac03dccf..1f9fee3c5d9 160000 --- a/frozen/Adafruit_CircuitPython_asyncio +++ b/frozen/Adafruit_CircuitPython_asyncio @@ -1 +1 @@ -Subproject commit e69ac03dccfd87ccaf3655dc751331ff922f525f +Subproject commit 1f9fee3c5d99d60b069c4a366678b391c198d955 From b74c906fe0925fb82ebc19a59c8023df24c94134 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 9 Apr 2026 20:40:58 -0400 Subject: [PATCH 389/876] update pre-commit config;remove non-CircuitPython extmod files --- .pre-commit-config.yaml | 6 +- extmod/cyw43_config_common.h | 126 ------------------------- extmod/littlefs-include/lfs2_defines.h | 12 --- extmod/lwip-include/lwipopts_common.h | 114 ---------------------- 4 files changed, 3 insertions(+), 255 deletions(-) delete mode 100644 extmod/cyw43_config_common.h delete mode 100644 extmod/littlefs-include/lfs2_defines.h delete mode 100644 extmod/lwip-include/lwipopts_common.h diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4db04e1d0ed..c39faf99f00 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: check-yaml - id: end-of-file-fixer @@ -55,7 +55,7 @@ repos: language: python - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.9.4 + rev: v0.15.7 hooks: # Run the linter. - id: ruff @@ -63,6 +63,6 @@ repos: # Run the formatter. - id: ruff-format - repo: https://github.com/tox-dev/pyproject-fmt - rev: "v2.5.0" + rev: "v2.21.0" hooks: - id: pyproject-fmt diff --git a/extmod/cyw43_config_common.h b/extmod/cyw43_config_common.h deleted file mode 100644 index 595af37d713..00000000000 --- a/extmod/cyw43_config_common.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Damien P. George, Angus Gratton - * - * 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. - */ -#ifndef MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H -#define MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H - -// The board-level config will be included here, so it can set some CYW43 values. -#include "py/mpconfig.h" -#include "py/mperrno.h" -#include "py/mphal.h" -#include "py/runtime.h" -#include "extmod/modnetwork.h" -#include "lwip/apps/mdns.h" -#include "pendsv.h" - -// This file is included at the top of port-specific cyw43_configport.h files, -// and holds the MicroPython-specific but non-port-specific parts. -// -// It's included into both MicroPython sources and the lib/cyw43-driver sources. - -#define CYW43_IOCTL_TIMEOUT_US (1000000) -#define CYW43_NETUTILS (1) -#define CYW43_PRINTF(...) mp_printf(MP_PYTHON_PRINTER, __VA_ARGS__) - -#define CYW43_EPERM MP_EPERM // Operation not permitted -#define CYW43_EIO MP_EIO // I/O error -#define CYW43_EINVAL MP_EINVAL // Invalid argument -#define CYW43_ETIMEDOUT MP_ETIMEDOUT // Connection timed out - -#define CYW43_THREAD_ENTER MICROPY_PY_LWIP_ENTER -#define CYW43_THREAD_EXIT MICROPY_PY_LWIP_EXIT -#define CYW43_THREAD_LOCK_CHECK - -#define CYW43_HOST_NAME mod_network_hostname_data - -#define CYW43_ARRAY_SIZE(a) MP_ARRAY_SIZE(a) - -#define CYW43_HAL_PIN_MODE_INPUT MP_HAL_PIN_MODE_INPUT -#define CYW43_HAL_PIN_MODE_OUTPUT MP_HAL_PIN_MODE_OUTPUT -#define CYW43_HAL_PIN_PULL_NONE MP_HAL_PIN_PULL_NONE -#define CYW43_HAL_PIN_PULL_UP MP_HAL_PIN_PULL_UP -#define CYW43_HAL_PIN_PULL_DOWN MP_HAL_PIN_PULL_DOWN - -#define CYW43_HAL_MAC_WLAN0 MP_HAL_MAC_WLAN0 -#define CYW43_HAL_MAC_BDADDR MP_HAL_MAC_BDADDR - -#define cyw43_hal_ticks_us mp_hal_ticks_us -#define cyw43_hal_ticks_ms mp_hal_ticks_ms - -#define cyw43_hal_pin_obj_t mp_hal_pin_obj_t -#define cyw43_hal_pin_config mp_hal_pin_config -#define cyw43_hal_pin_read mp_hal_pin_read -#define cyw43_hal_pin_low mp_hal_pin_low -#define cyw43_hal_pin_high mp_hal_pin_high - -#define cyw43_hal_get_mac mp_hal_get_mac -#define cyw43_hal_get_mac_ascii mp_hal_get_mac_ascii -#define cyw43_hal_generate_laa_mac mp_hal_generate_laa_mac - -#define cyw43_schedule_internal_poll_dispatch(func) pendsv_schedule_dispatch(PENDSV_DISPATCH_CYW43, func) - -// Note: this function is only called if CYW43_POST_POLL_HOOK is defined in cyw43_configport.h -void cyw43_post_poll_hook(void); - -#ifdef MICROPY_EVENT_POLL_HOOK -// Older style hook macros on some ports -#define CYW43_EVENT_POLL_HOOK MICROPY_EVENT_POLL_HOOK -#else -// Newer style hooks on other ports -#define CYW43_EVENT_POLL_HOOK mp_event_handle_nowait() -#endif - -static inline void cyw43_delay_us(uint32_t us) { - uint32_t start = mp_hal_ticks_us(); - while (mp_hal_ticks_us() - start < us) { - } -} - -static inline void cyw43_delay_ms(uint32_t ms) { - // PendSV may be disabled via CYW43_THREAD_ENTER, so this delay is a busy loop. - uint32_t us = ms * 1000; - uint32_t start = mp_hal_ticks_us(); - while (mp_hal_ticks_us() - start < us) { - CYW43_EVENT_POLL_HOOK; - } -} - -#if LWIP_MDNS_RESPONDER == 1 - -// Hook for any additional TCP/IP initialization than needs to be done. -// Called after the netif specified by `itf` has been set up. -#ifndef CYW43_CB_TCPIP_INIT_EXTRA -#define CYW43_CB_TCPIP_INIT_EXTRA(self, itf) mdns_resp_add_netif(&self->netif[itf], mod_network_hostname_data) -#endif - -// Hook for any additional TCP/IP deinitialization than needs to be done. -// Called before the netif specified by `itf` is removed. -#ifndef CYW43_CB_TCPIP_DEINIT_EXTRA -#define CYW43_CB_TCPIP_DEINIT_EXTRA(self, itf) mdns_resp_remove_netif(&self->netif[itf]) -#endif - -#endif - -#endif // MICROPY_INCLUDED_EXTMOD_CYW43_CONFIG_COMMON_H diff --git a/extmod/littlefs-include/lfs2_defines.h b/extmod/littlefs-include/lfs2_defines.h deleted file mode 100644 index 4ae566f508a..00000000000 --- a/extmod/littlefs-include/lfs2_defines.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef LFS2_DEFINES_H -#define LFS2_DEFINES_H - -#include "py/mpconfig.h" - -#if MICROPY_PY_DEFLATE -// We reuse the CRC32 implementation from uzlib to save a few bytes -#include "lib/uzlib/uzlib.h" -#define LFS2_CRC(crc, buffer, size) uzlib_crc32(buffer, size, crc) -#endif - -#endif \ No newline at end of file diff --git a/extmod/lwip-include/lwipopts_common.h b/extmod/lwip-include/lwipopts_common.h deleted file mode 100644 index 8cb1acfe2ca..00000000000 --- a/extmod/lwip-include/lwipopts_common.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2025 Damien P. George - * - * 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. - */ -#ifndef MICROPY_INCLUDED_LWIPOPTS_COMMON_H -#define MICROPY_INCLUDED_LWIPOPTS_COMMON_H - -#include "py/mpconfig.h" - -// This is needed to access `next_timeout` via `sys_timeouts_get_next_timeout()`. -#define LWIP_TESTMODE 1 - -// This sys-arch protection is not needed. -// Ports either protect lwIP code with flags, or run it at PendSV priority. -#define SYS_ARCH_DECL_PROTECT(lev) do { } while (0) -#define SYS_ARCH_PROTECT(lev) do { } while (0) -#define SYS_ARCH_UNPROTECT(lev) do { } while (0) - -#define NO_SYS 1 -#define SYS_LIGHTWEIGHT_PROT 1 -#define MEM_ALIGNMENT 4 - -#define LWIP_CHKSUM_ALGORITHM 3 -#define LWIP_CHECKSUM_CTRL_PER_NETIF 1 - -#define LWIP_ARP 1 -#define LWIP_ETHERNET 1 -#define LWIP_RAW 1 -#define LWIP_NETCONN 0 -#define LWIP_SOCKET 0 -#define LWIP_STATS 0 -#define LWIP_NETIF_HOSTNAME 1 - -#define LWIP_DHCP 1 -#define LWIP_DHCP_CHECK_LINK_UP 1 -#define LWIP_DHCP_DOES_ACD_CHECK 0 // to speed DHCP up -#define LWIP_DNS 1 -#define LWIP_DNS_SUPPORT_MDNS_QUERIES 1 -#define LWIP_MDNS_RESPONDER 1 -#define LWIP_IGMP 1 - -#if MICROPY_PY_LWIP_PPP -#define PPP_SUPPORT 1 -#define PAP_SUPPORT 1 -#define CHAP_SUPPORT 1 -#endif - -#define LWIP_NUM_NETIF_CLIENT_DATA LWIP_MDNS_RESPONDER -#define MEMP_NUM_UDP_PCB (4 + LWIP_MDNS_RESPONDER) - -// The mDNS responder requires 5 timers per IP version plus 2 others. Not having enough silently breaks it. -#define MEMP_NUM_SYS_TIMEOUT (LWIP_NUM_SYS_TIMEOUT_INTERNAL + (LWIP_MDNS_RESPONDER * (2 + (5 * (LWIP_IPV4 + LWIP_IPV6))))) - -#define SO_REUSE 1 -#define TCP_LISTEN_BACKLOG 1 - -// TCP memory settings. -// Default lwIP settings takes 15800 bytes; TCP d/l: 380k/s local, 7.2k/s remote; TCP u/l is very slow. -#ifndef MEM_SIZE - -#if 0 -// lwIP takes 19159 bytes; TCP d/l and u/l are around 320k/s on local network. -#define MEM_SIZE (5000) -#define TCP_WND (4 * TCP_MSS) -#define TCP_SND_BUF (4 * TCP_MSS) -#endif - -#if 1 -// lwIP takes 26700 bytes; TCP dl/ul are around 750/600 k/s on local network. -#define MEM_SIZE (8000) -#define TCP_MSS (800) -#define TCP_WND (8 * TCP_MSS) -#define TCP_SND_BUF (8 * TCP_MSS) -#define MEMP_NUM_TCP_SEG (32) -#endif - -#if 0 -// lwIP takes 45600 bytes; TCP dl/ul are around 1200/1000 k/s on local network. -#define MEM_SIZE (16000) -#define TCP_MSS (1460) -#define TCP_WND (8 * TCP_MSS) -#define TCP_SND_BUF (8 * TCP_MSS) -#define MEMP_NUM_TCP_SEG (32) -#endif - -#endif // MEM_SIZE - -// Needed for PPP. -#define sys_jiffies sys_now - -typedef uint32_t sys_prot_t; - -#endif // MICROPY_INCLUDED_LWIPOPTS_COMMON_H From dfa5f8e2282a6c6111ecacfd0355f958433a37d2 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 9 Apr 2026 20:41:08 -0400 Subject: [PATCH 390/876] fix precommit complaints --- lib/littlefs/lfs2.c | 4 +- locale/circuitpython.pot | 69 +++++++++-------- ports/espressif/tools/update_sdkconfig.py | 2 +- py/binary.c | 2 +- py/makeversionhdr.py | 19 ----- py/malloc.c | 4 +- py/mpprint.c | 10 +-- py/objint_longlong.c | 30 +++++++- py/objlist.c | 4 +- py/sequence.c | 2 +- pyproject.toml | 94 ++++++++++------------- shared/runtime/pyexec.c | 13 ++-- tests/basics/builtin_slice.py | 2 +- tests/basics/fun_code_full.py | 2 - tests/misc/rge_sm.py | 42 +++++----- tools/analyze_heap_dump.py | 2 +- tools/chart_code_size.py | 2 +- tools/ci.sh | 2 +- 18 files changed, 155 insertions(+), 150 deletions(-) diff --git a/lib/littlefs/lfs2.c b/lib/littlefs/lfs2.c index aec2ddab9b6..8d18b7d1105 100644 --- a/lib/littlefs/lfs2.c +++ b/lib/littlefs/lfs2.c @@ -643,7 +643,7 @@ static int lfs2_alloc_scan(lfs2_t *lfs2) { // // note we limit the lookahead buffer to at most the amount of blocks // checkpointed, this prevents the math in lfs2_alloc from underflowing - lfs2->lookahead.start = (lfs2->lookahead.start + lfs2->lookahead.next) + lfs2->lookahead.start = (lfs2->lookahead.start + lfs2->lookahead.next) % lfs2->block_count; lfs2->lookahead.next = 0; lfs2->lookahead.size = lfs2_min( @@ -5257,7 +5257,7 @@ static int lfs2_fs_grow_(lfs2_t *lfs2, lfs2_size_t block_count) { return 0; } - + #ifndef LFS2_SHRINKNONRELOCATING // shrinking is not supported LFS2_ASSERT(block_count >= lfs2->block_count); diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 2b67216cf50..bd9fe69cb31 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -78,6 +78,11 @@ msgid "" "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "" @@ -259,10 +264,6 @@ msgstr "" msgid "%q out of range" msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "" @@ -956,6 +957,14 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c msgid "ESP-IDF memory allocation failed" @@ -1020,10 +1029,6 @@ msgstr "" msgid "Failed to buffer the sample" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect" -msgstr "" - #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c #: ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -2615,10 +2620,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2832,6 +2833,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2930,14 +2935,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3092,7 +3097,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3476,6 +3481,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3670,6 +3679,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3718,10 +3731,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3743,7 +3752,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -4102,6 +4111,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4111,6 +4124,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4375,10 +4392,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4400,10 +4413,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" diff --git a/ports/espressif/tools/update_sdkconfig.py b/ports/espressif/tools/update_sdkconfig.py index 209b976b881..d40614edb75 100644 --- a/ports/espressif/tools/update_sdkconfig.py +++ b/ports/espressif/tools/update_sdkconfig.py @@ -157,7 +157,7 @@ def sym_default(sym): default=False, help="Updates the sdkconfigs outside of the board directory.", ) -def update(debug, board, update_all): # noqa: C901: too complex +def update(debug, board, update_all): # noqa: C901 too complex """Updates related sdkconfig files based on the build directory version that was likely modified by menuconfig.""" diff --git a/py/binary.c b/py/binary.c index 24c3a5d4298..180a13beec7 100644 --- a/py/binary.c +++ b/py/binary.c @@ -438,7 +438,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p val = fp_sp.i; break; } - // CIRCUITPY-CHANGE + // CIRCUITPY-CHANGE #if MICROPY_PY_DOUBLE_TYPECODE case 'd': { union { diff --git a/py/makeversionhdr.py b/py/makeversionhdr.py index 09d67d87f8a..94321ef0bad 100644 --- a/py/makeversionhdr.py +++ b/py/makeversionhdr.py @@ -27,25 +27,6 @@ def cannot_determine_version(): make fetch-tags""" ) - with open(os.path.join(repo_path, "py", "mpconfig.h")) as f: - for line in f: - if line.startswith("#define MICROPY_VERSION_MAJOR "): - ver_major = int(line.strip().split()[2]) - elif line.startswith("#define MICROPY_VERSION_MINOR "): - ver_minor = int(line.strip().split()[2]) - elif line.startswith("#define MICROPY_VERSION_MICRO "): - ver_micro = int(line.strip().split()[2]) - elif line.startswith("#define MICROPY_VERSION_PRERELEASE "): - ver_prerelease = int(line.strip().split()[2]) - git_tag = "v%d.%d.%d%s" % ( - ver_major, - ver_minor, - ver_micro, - "-preview" if ver_prerelease else "", - ) - return git_tag - return None - def make_version_header(repo_path, filename): # Get version info using git (required) diff --git a/py/malloc.c b/py/malloc.c index 36eb10b7b85..fa2878d5905 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -145,8 +145,8 @@ void *m_malloc_with_finaliser(size_t num_bytes) { void *m_malloc0(size_t num_bytes) { // CIRCUITPY-CHANGE: use helper return m_malloc_helper(num_bytes, - (MICROPY_GC_CONSERVATIVE_CLEAR ? 0 : M_MALLOC_ENSURE_ZEROED) - | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); + (MICROPY_GC_CONSERVATIVE_CLEAR ? 0 : M_MALLOC_ENSURE_ZEROED) + | M_MALLOC_RAISE_ERROR | M_MALLOC_COLLECT); } // CIRCUITPY-CHANGE: add selective collect diff --git a/py/mpprint.c b/py/mpprint.c index bb1f3d45e8e..62e80d1e8e8 100644 --- a/py/mpprint.c +++ b/py/mpprint.c @@ -599,11 +599,11 @@ int mp_vprintf(const mp_print_t *print, const char *fmt, va_list args) { } // CIRCUITPY-CHANGE: include "0x" for 'p' and 'P'. if (fmt_chr == 'p' || fmt_chr == 'P') { - #if SUPPORT_INT_BASE_PREFIX - chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags | PF_FLAG_SHOW_PREFIX, fill, width); - #else - chrs += mp_print_strn(print, "0x", 2, flags, fill, width); - #endif + #if SUPPORT_INT_BASE_PREFIX + chrs += mp_print_int(print, va_arg(args, unsigned long int), 0, 16, 'a', flags | PF_FLAG_SHOW_PREFIX, fill, width); + #else + chrs += mp_print_strn(print, "0x", 2, flags, fill, width); + #endif } chrs += mp_print_int(print, val, fmt_chr == 'd', base, fmt_c, flags, fill, width); break; diff --git a/py/objint_longlong.c b/py/objint_longlong.c index 4ff6ee6cff8..f24aa0cc186 100644 --- a/py/objint_longlong.c +++ b/py/objint_longlong.c @@ -45,6 +45,7 @@ const mp_obj_int_t mp_sys_maxsize_obj = {{&mp_type_int}, MP_SSIZE_MAX}; static void raise_long_long_overflow(void) { mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("result overflows long long storage")); +} // CIRCUITPY-CHANGE: bit_length mp_obj_t mp_obj_int_bit_length_impl(mp_obj_t self_in) { @@ -335,8 +336,33 @@ mp_int_t mp_obj_int_get_truncated(mp_const_obj_t self_in) { } mp_int_t mp_obj_int_get_checked(mp_const_obj_t self_in) { - // TODO: Check overflow - return mp_obj_int_get_truncated(self_in); + if (mp_obj_is_small_int(self_in)) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } else { + const mp_obj_int_t *self = self_in; + long long value = self->val; + mp_int_t truncated = (mp_int_t)value; + if ((long long)truncated == value) { + return truncated; + } + } + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word")); +} + +mp_uint_t mp_obj_int_get_uint_checked(mp_const_obj_t self_in) { + if (mp_obj_is_small_int(self_in)) { + if (MP_OBJ_SMALL_INT_VALUE(self_in) >= 0) { + return MP_OBJ_SMALL_INT_VALUE(self_in); + } + } else { + const mp_obj_int_t *self = self_in; + long long value = self->val; + mp_uint_t truncated = (mp_uint_t)value; + if (value >= 0 && (long long)truncated == value) { + return truncated; + } + } + mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("overflow converting long int to machine word")); } #if MICROPY_PY_BUILTINS_FLOAT diff --git a/py/objlist.c b/py/objlist.c index 83bade273bf..a29fc51b104 100644 --- a/py/objlist.c +++ b/py/objlist.c @@ -173,8 +173,8 @@ static mp_obj_t list_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) { static mp_obj_t list_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { #if MICROPY_PY_BUILTINS_SLICE if (mp_obj_is_type(index, &mp_type_slice)) { - // CIRCUITPY-CHANGE: handle subclassing - mp_obj_list_t *self = native_list(self_in); + // CIRCUITPY-CHANGE: handle subclassing + mp_obj_list_t *self = native_list(self_in); mp_bound_slice_t slice; bool fast = mp_seq_get_fast_slice_indexes(self->len, index, &slice); if (value == MP_OBJ_SENTINEL) { diff --git a/py/sequence.c b/py/sequence.c index 33cc55eac40..6bbc62f0f7f 100644 --- a/py/sequence.c +++ b/py/sequence.c @@ -40,7 +40,7 @@ size_t mp_seq_multiply_len(size_t item_sz, size_t len) { if (mp_mul_mp_int_t_overflow(item_sz, len, &new_len)) { mp_raise_msg(&mp_type_OverflowError, MP_ERROR_TEXT("small int overflow")); } - return (size_t) new_len; + return (size_t)new_len; } // Implements backend of sequence * integer operation. Assumes elements are diff --git a/pyproject.toml b/pyproject.toml index e88137bb0f7..5f84ca104ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,42 +1,26 @@ -[tool.codespell] -count = "" -ignore-regex = '\b[A-Z]{3}\b' -# CIRCUITPY-CHANGE: aranges -ignore-words-list = "ans,asend,aranges,deques,dout,emac,extint,hsi,iput,mis,notin,numer,ser,shft,synopsys,technic,ure,curren" -quiet-level = 3 -skip = """ -*/build*,\ -./.git,\ -./drivers/cc3100,\ -./lib,\ -./ports/cc3200/FreeRTOS,\ -./ports/cc3200/bootmgr/sl,\ -./ports/cc3200/hal,\ -./ports/cc3200/simplelink,\ -./ports/cc3200/telnet,\ -./ports/esp32/managed_components,\ -./ports/nrf/drivers/bluetooth/s1*,\ -./ports/stm32/usbhost,\ -./tests,\ -ACKNOWLEDGEMENTS,\ -""" - -# CIRCUITPY-CHANGES: additions and removals +# can be empty if no extra settings are needed, presence enables setuptools-scm [tool.ruff] +target-version = "py312" +line-length = 99 +# Include Python source files that don't end with .py +extend-include = [ "tools/cc1" ] # Exclude third-party code from linting and formatting extend-exclude = [ + # CIRCUITPY-CHANGES "extmod/ulab", "frozen", "lib", "ports/analog/msdk", "ports/atmel-samd/asf4", "ports/broadcom/peripherals", + "ports/espress/tools", "ports/espressif/esp-idf", "ports/espressif/esp-protocols", "ports/raspberrypi/sdk", "ports/silabs/gecko_sdk", "ports/silabs/tools/slc_cli_linux", "ports/stm/st_driver", + "tests/cpydiff/syntax_assign_expr.py", # intentionally incorrect CPython code "tools/adabot", "tools/bitmap_font", "tools/cc1", @@ -45,12 +29,20 @@ extend-exclude = [ "tools/python-semver", "tools/uf2", ] -# Include Python source files that don't end with .py -line-length = 99 -target-version = "py38" - -[tool.ruff.lint] -exclude = [ # Ruff finds Python SyntaxError in these files +# Exclude third-party code, and exclude the following tests: +# basics: needs careful attention before applying automatic formatting +# repl_: not real python files +# viper_args: uses f(*) +format.exclude = [ + "tests/*/repl_*.py", + "tests/basics/*.py", + "tests/cmdline/cmd_compile_only_error.py", + "tests/micropython/test_normalize_newlines.py", + "tests/micropython/viper_args.py", +] +lint.extend-select = [ "C9", "PLC" ] +lint.exclude = [ + # Ruff finds Python SyntaxError in these files "tests/cmdline/cmd_compile_only_error.py", "tests/cmdline/repl_autocomplete.py", "tests/cmdline/repl_autocomplete_underscore.py", @@ -64,8 +56,7 @@ exclude = [ # Ruff finds Python SyntaxError in these files "tests/feature_check/repl_words_move_check.py", "tests/micropython/viper_args.py", ] -extend-select = ["C9", "PLC"] -extend-ignore = [ +lint.extend-ignore = [ "E401", "E402", "E722", @@ -77,27 +68,24 @@ extend-ignore = [ "PLC0206", "PLC0415", # conditional imports are common in MicroPython ] -mccabe.max-complexity = 40 - -[tool.ruff.lint.per-file-ignores] -# Exclude all tests from linting. -"tests/**/*.py" = ["ALL"] -"ports/cc3200/tools/uniflash.py" = ["E711"] # manifest.py files are evaluated with some global names pre-defined -"**/manifest.py" = ["F821"] -"ports/**/boards/**/manifest_*.py" = ["F821"] +lint.per-file-ignores."**/manifest.py" = [ "F821" ] +lint.per-file-ignores."ports/**/boards/**/manifest_*.py" = [ "F821" ] +lint.per-file-ignores."ports/cc3200/tools/uniflash.py" = [ "E711" ] +# Exclude all tests from linting. +lint.per-file-ignores."tests/**/*.py" = [ "ALL" ] # Uses assignment expressions. -"tests/cpydiff/syntax_assign_expr.py" = ["F821"] +lint.per-file-ignores."tests/cpydiff/syntax_assign_expr.py" = [ "F821" ] +lint.mccabe.max-complexity = 40 -[tool.ruff.format] -# Exclude third-party code, and exclude the following tests: -# basics: needs careful attention before applying automatic formatting -# repl_: not real python files -# viper_args: uses f(*) -exclude = [ - "tests/basics/*.py", - "tests/*/repl_*.py", - "tests/cmdline/cmd_compile_only_error.py", - "tests/micropython/test_normalize_newlines.py", - "tests/micropython/viper_args.py", -] +[tool.codespell] +count = "" +ignore-regex = "\\b[A-Z]{3}\\b" +# CIRCUITPY-CHANGE: aranges +ignore-words-list = "ans,aranges,asend,deques,dout,emac,extint,hsi,iput,mis,notin,numer,ser,shft,synopsys,technic,ure,curren" +quiet-level = 3 +skip = """\ + */build*,./.git,./drivers/cc3100,./lib,./ports/cc3200/FreeRTOS,./ports/cc3200/bootmgr/sl,./ports/cc3200/hal,./ports/c\ + c3200/simplelink,./ports/cc3200/telnet,./ports/esp32/managed_components,./ports/nrf/drivers/bluetooth/s1*,./ports/stm\ + 32/usbhost,./tests,ACKNOWLEDGEMENTS,\ + """ diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 09f1796c5d4..430892a00bc 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -92,7 +92,7 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input // Also make it possible to determine if module_fun was set. mp_obj_t module_fun = NULL; - // CIRCUITPY-CHANGE: add atexit support + // CIRCUITPY-CHANGE: add atexit support #if CIRCUITPY_ATEXIT if (exec_flags & EXEC_FLAG_SOURCE_IS_ATEXIT) { atexit_callback_t *callback = (atexit_callback_t *)source; @@ -148,7 +148,7 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input // CIRCUITPY-CHANGE: garbage collect after loading // If the code was loaded from a file, collect any garbage before running. if (input_kind == MP_PARSE_FILE_INPUT) { - gc_collect(); + gc_collect(); } // execute code @@ -221,11 +221,11 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input ret = PYEXEC_FORCED_EXIT; #endif // CIRCUITPY-CHANGE: support DeepSleepRequest - #if CIRCUITPY_ALARM + #if CIRCUITPY_ALARM } else if (mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(exception_obj_type), MP_OBJ_FROM_PTR(&mp_type_DeepSleepRequest))) { ret = PYEXEC_DEEP_SLEEP; - #endif - // CIRCUITPY-CHANGE: supprt ReloadException + #endif + // CIRCUITPY-CHANGE: support ReloadException } else if (exception_obj == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_reload_exception))) { ret = PYEXEC_RELOAD; } else { // other exception @@ -247,8 +247,7 @@ static int parse_compile_execute(const void *source, mp_parse_input_kind_t input #if CIRCUITPY_ALARM && ret != PYEXEC_DEEP_SLEEP #endif - ) - { + ) { mp_obj_t return_value = (mp_obj_t)nlr.ret_val; result->exception = return_value; result->exception_line = -1; diff --git a/tests/basics/builtin_slice.py b/tests/basics/builtin_slice.py index 7f548ee3358..cbce3d14ed6 100644 --- a/tests/basics/builtin_slice.py +++ b/tests/basics/builtin_slice.py @@ -1,7 +1,7 @@ # test builtin slice # ensures that slices passed to user types are heap-allocated and can be -# safely stored as well as not overriden by subsequent slices. +# safely stored as well as not overridden by subsequent slices. # print slice class A: diff --git a/tests/basics/fun_code_full.py b/tests/basics/fun_code_full.py index e1c867939a2..538863631a6 100644 --- a/tests/basics/fun_code_full.py +++ b/tests/basics/fun_code_full.py @@ -36,5 +36,3 @@ def f(x, y): prev_end = end else: print("contiguous") - - diff --git a/tests/misc/rge_sm.py b/tests/misc/rge_sm.py index 56dad574977..33aa4edb742 100644 --- a/tests/misc/rge_sm.py +++ b/tests/misc/rge_sm.py @@ -47,26 +47,30 @@ def solve(self, finishtime): lambda *a: 41.0 / 96.0 / math.pi**2 * a[1] ** 3, # g1 lambda *a: -19.0 / 96.0 / math.pi**2 * a[2] ** 3, # g2 lambda *a: -42.0 / 96.0 / math.pi**2 * a[3] ** 3, # g3 - lambda *a: 1.0 - / 16.0 - / math.pi**2 - * ( - 9.0 / 2.0 * a[4] ** 3 - - 8.0 * a[3] ** 2 * a[4] - - 9.0 / 4.0 * a[2] ** 2 * a[4] - - 17.0 / 12.0 * a[1] ** 2 * a[4] + lambda *a: ( + 1.0 + / 16.0 + / math.pi**2 + * ( + 9.0 / 2.0 * a[4] ** 3 + - 8.0 * a[3] ** 2 * a[4] + - 9.0 / 4.0 * a[2] ** 2 * a[4] + - 17.0 / 12.0 * a[1] ** 2 * a[4] + ) ), # yt - lambda *a: 1.0 - / 16.0 - / math.pi**2 - * ( - 24.0 * a[5] ** 2 - + 12.0 * a[4] ** 2 * a[5] - - 9.0 * a[5] * (a[2] ** 2 + 1.0 / 3.0 * a[1] ** 2) - - 6.0 * a[4] ** 4 - + 9.0 / 8.0 * a[2] ** 4 - + 3.0 / 8.0 * a[1] ** 4 - + 3.0 / 4.0 * a[2] ** 2 * a[1] ** 2 + lambda *a: ( + 1.0 + / 16.0 + / math.pi**2 + * ( + 24.0 * a[5] ** 2 + + 12.0 * a[4] ** 2 * a[5] + - 9.0 * a[5] * (a[2] ** 2 + 1.0 / 3.0 * a[1] ** 2) + - 6.0 * a[4] ** 4 + + 9.0 / 8.0 * a[2] ** 4 + + 3.0 / 8.0 * a[1] ** 4 + + 3.0 / 4.0 * a[2] ** 2 * a[1] ** 2 + ) ), # lambda ) diff --git a/tools/analyze_heap_dump.py b/tools/analyze_heap_dump.py index ac1bb0c8ce5..a7be95db7d9 100755 --- a/tools/analyze_heap_dump.py +++ b/tools/analyze_heap_dump.py @@ -82,7 +82,7 @@ help="Draw the ownership graph of blocks on the heap", ) @click.option("--analyze-snapshots", default="last", type=click.Choice(["all", "last"])) -def do_all_the_things( # noqa: C901: too complex +def do_all_the_things( # noqa: C901 too complex ram_filename, bin_filename, map_filename, diff --git a/tools/chart_code_size.py b/tools/chart_code_size.py index cd62074fd0d..f3d9c5bdc40 100644 --- a/tools/chart_code_size.py +++ b/tools/chart_code_size.py @@ -24,7 +24,7 @@ def parse_hex(h): @click.command() @click.argument("elf_filename") -def do_all_the_things(elf_filename): # noqa: C901: too complex +def do_all_the_things(elf_filename): # noqa: C901 too complex symbol = None last_address = 0 all_symbols = {} diff --git a/tools/ci.sh b/tools/ci.sh index 60e870ce65b..132fbd8f81c 100755 --- a/tools/ci.sh +++ b/tools/ci.sh @@ -88,7 +88,7 @@ function ci_code_size_build { # check the following ports for the change in their code size # Override the list by setting PORTS_TO_CHECK in the environment before invoking ci. : ${PORTS_TO_CHECK:=bmusxpdv} - + SUBMODULES="lib/asf4 lib/berkeley-db-1.xx lib/btstack lib/cyw43-driver lib/lwip lib/mbedtls lib/micropython-lib lib/nxp_driver lib/pico-sdk lib/stm32lib lib/tinyusb" # Default GitHub pull request sets HEAD to a generated merge commit From 03c641a8568e5d2403f87b84f58a27c1458139df Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Apr 2026 19:45:04 -0500 Subject: [PATCH 391/876] add DISABLED_MODULES mechanism for zephyr boards. disable aesio for norf7002dk --- ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 2 +- ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml | 1 + ports/zephyr-cp/cptools/build_circuitpython.py | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 184ff34b7ef..5faed268cdb 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -10,7 +10,7 @@ _pixelmap = false _stage = false adafruit_bus_device = false adafruit_pixelbuf = false -aesio = true +aesio = false alarm = false analogbufio = false analogio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index 76b10578813..7fcb145588b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -2,3 +2,4 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] USB_VID=0x239A USB_PID=0x8168 BLOBS=["nrf_wifi"] +DISABLED_MODULES=["aesio"] diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 3edbc1efdf6..32173914a2a 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -405,6 +405,8 @@ async def build_circuitpython(): circuitpython_flags.append(f"-DCIRCUITPY_CREATION_ID=0x{creation_id:08x}") enabled_modules, module_reasons = determine_enabled_modules(board_info, portdir, srcdir) + for m in mpconfigboard.get("DISABLED_MODULES", []): + enabled_modules.discard(m) web_workflow_enabled = board_info.get("wifi", False) or board_info.get("hostnetwork", False) From ce39a6a7df2044f9b7e71a0849fdb6ca3cbeec2e Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Apr 2026 21:08:48 -0500 Subject: [PATCH 392/876] fix init_container script, fix container file ownership, add container info to readme. --- ports/zephyr-cp/README.md | 27 +++++++++++++++++++ .../zephyr-cp/native_sim_build_Containerfile | 5 +++- .../native_sim_build_init_container.sh | 5 ++-- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/ports/zephyr-cp/README.md b/ports/zephyr-cp/README.md index 28bbfbf2984..162ed90bcc8 100644 --- a/ports/zephyr-cp/README.md +++ b/ports/zephyr-cp/README.md @@ -28,6 +28,33 @@ make BOARD=nordic_nrf7002dk This uses Zephyr's cmake to generate Makefiles that then delegate to `tools/cpbuild/build_circuitpython.py` to build the CircuitPython bits in parallel. +## Native simulator build container + +Building the native sim requires `libsdl2-dev:i386` and other 32bit dependencies that +can cause conflicts on 64bit systems resulting in the removal of 64bit versions of critical +software such as the display manager and network manager. A Containerfile and a few scripts +are provided to set up a container to make the native sim build inside without affecting the +host system. + +The container automatically mounts this instance of the circuitpython repo inside at +`/home/dev/circuitpython`. Changes made in the repo inside the container and on the host PC +will sync automatically between host and container. + +To use the container file: + +1. Build the container with `podman build -t zephyr-cp-dev -f native_sim_build_Containerfile .` +2. Run/Start the container by running `./native_sim_build_run_container.sh` on the host PC. + The script will automatically run or start based on whether the container has been run before. +3. Init requirements inside the container with `./native_sim_build_init_container.sh` + +To delete the container and cleanup associated files: +```sh +podman ps -a --filter ancestor=zephyr-cp-dev -q | xargs -r podman rm -f +podman rmi zephyr-cp-dev +podman image prune -f +podman rm -f zcp +``` + ## Running the native simulator From `ports/zephyr-cp`, run: diff --git a/ports/zephyr-cp/native_sim_build_Containerfile b/ports/zephyr-cp/native_sim_build_Containerfile index 8b9db9dc559..3cd1a677da3 100644 --- a/ports/zephyr-cp/native_sim_build_Containerfile +++ b/ports/zephyr-cp/native_sim_build_Containerfile @@ -12,7 +12,10 @@ RUN dpkg --add-architecture i386 && apt-get update && apt-get install -y --no-in protobuf-compiler sudo \ && rm -rf /var/lib/apt/lists/* -RUN useradd -m -s /bin/bash dev \ +# Remove the default ubuntu:24.04 'ubuntu' user (UID 1000) so 'dev' can take +# UID 1000 — required for --userns=keep-id to map host UID 1000 to 'dev'. +RUN userdel -r ubuntu 2>/dev/null || true \ + && useradd -m -u 1000 -s /bin/bash dev \ && echo 'dev ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/dev \ && chmod 440 /etc/sudoers.d/dev USER dev diff --git a/ports/zephyr-cp/native_sim_build_init_container.sh b/ports/zephyr-cp/native_sim_build_init_container.sh index 705fb3eb9ff..b1b1453d27c 100755 --- a/ports/zephyr-cp/native_sim_build_init_container.sh +++ b/ports/zephyr-cp/native_sim_build_init_container.sh @@ -9,10 +9,12 @@ # Safe to re-run; west/pip/etc. are idempotent. set -euo pipefail +git config --global --add safe.directory /home/dev/circuitpython + cd "$(dirname "${BASH_SOURCE[0]}")" echo "==> west init" -if [ ! -d ../../.west ]; then +if [ ! -d .west ]; then west init -l zephyr-config else echo " (already initialized, skipping)" @@ -34,7 +36,6 @@ echo "==> west sdk install (x86_64-zephyr-elf)" west sdk install -t x86_64-zephyr-elf echo "==> fetch port submodules" -git config --global --add safe.directory /home/dev/circuitpython python ../../tools/ci_fetch_deps.py zephyr-cp echo From f0d6f587bf67480825ac604d53bf98a0e8d885b0 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Apr 2026 21:15:27 -0500 Subject: [PATCH 393/876] update init_container script usage example --- ports/zephyr-cp/native_sim_build_init_container.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/native_sim_build_init_container.sh b/ports/zephyr-cp/native_sim_build_init_container.sh index b1b1453d27c..19831e1fcc2 100755 --- a/ports/zephyr-cp/native_sim_build_init_container.sh +++ b/ports/zephyr-cp/native_sim_build_init_container.sh @@ -4,7 +4,7 @@ # # Usage (inside the container): # cd ~/circuitpython/ports/zephyr-cp -# ./first_run.sh +# ./native_sim_build_init_container.sh # # Safe to re-run; west/pip/etc. are idempotent. set -euo pipefail From 2b6945ae8264b876e288e54a193ffb0a792a01ef Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Fri, 10 Apr 2026 08:18:20 +0200 Subject: [PATCH 394/876] define board.display as a module, not a type --- ports/raspberrypi/boards/pimoroni_badger2350/pins.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/pins.c b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c index 9ba93cd47cb..ff9feb9cce4 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2350/pins.c +++ b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c @@ -20,17 +20,15 @@ static const mp_rom_map_elem_t lut_update_table[] = { }; MP_DEFINE_CONST_DICT(lut_update_dict, lut_update_table); -MP_DEFINE_CONST_OBJ_TYPE( - display_type, - MP_QSTR_display, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS | ~MP_TYPE_FLAG_BINDS_SELF, - locals_dict, &lut_update_dict - ); +const mp_obj_module_t display_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&lut_update_dict, +}; static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS - { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_PTR(&display_type) }, + { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_PTR(&display_module) }, { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO0) }, From d7ed38b92b111570d85e2fcbc55838a240280fb1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 10 Apr 2026 12:15:13 -0400 Subject: [PATCH 395/876] fix build errors --- py/circuitpy_mpconfig.h | 1 + shared/netutils/dhcpserver.c | 315 ++++++++++++++++++++++++ shared/netutils/dhcpserver.h | 49 ++++ shared/netutils/netutils.c | 100 ++++++++ shared/netutils/netutils.h | 58 +++++ shared/netutils/trace.c | 170 +++++++++++++ tests/micropython/emg_exc.py.native.exp | 3 +- 7 files changed, 694 insertions(+), 2 deletions(-) create mode 100644 shared/netutils/dhcpserver.c create mode 100644 shared/netutils/dhcpserver.h create mode 100644 shared/netutils/netutils.c create mode 100644 shared/netutils/netutils.h create mode 100644 shared/netutils/trace.c diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index e83c6175255..c02f0b4f870 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -46,6 +46,7 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_PY_BLUETOOTH (0) #define MICROPY_PY_LWIP_SLIP (0) #define MICROPY_PY_OS_DUPTERM (0) +#define MICROPY_PY_PYEXEC_COMPILE_ONLY (0) #define MICROPY_ROM_TEXT_COMPRESSION (0) #define MICROPY_VFS_LFS1 (0) #define MICROPY_VFS_LFS2 (0) diff --git a/shared/netutils/dhcpserver.c b/shared/netutils/dhcpserver.c new file mode 100644 index 00000000000..6d9cdb97d1f --- /dev/null +++ b/shared/netutils/dhcpserver.c @@ -0,0 +1,315 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Damien P. George + * + * 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. + */ + +// For DHCP specs see: +// https://www.ietf.org/rfc/rfc2131.txt +// https://tools.ietf.org/html/rfc2132 -- DHCP Options and BOOTP Vendor Extensions + +#include +#include +#include "py/mperrno.h" +#include "py/mphal.h" +#include "lwip/opt.h" + +// CIRCUITPY-CHANGE: comment +// Used in CIRCUITPY without MICROPY_PY_LWIP + +#if LWIP_UDP + +#include "shared/netutils/dhcpserver.h" +#include "lwip/udp.h" + +#define DHCPDISCOVER (1) +#define DHCPOFFER (2) +#define DHCPREQUEST (3) +#define DHCPDECLINE (4) +#define DHCPACK (5) +#define DHCPNACK (6) +#define DHCPRELEASE (7) +#define DHCPINFORM (8) + +#define DHCP_OPT_PAD (0) +#define DHCP_OPT_SUBNET_MASK (1) +#define DHCP_OPT_ROUTER (3) +#define DHCP_OPT_DNS (6) +#define DHCP_OPT_HOST_NAME (12) +#define DHCP_OPT_REQUESTED_IP (50) +#define DHCP_OPT_IP_LEASE_TIME (51) +#define DHCP_OPT_MSG_TYPE (53) +#define DHCP_OPT_SERVER_ID (54) +#define DHCP_OPT_PARAM_REQUEST_LIST (55) +#define DHCP_OPT_MAX_MSG_SIZE (57) +#define DHCP_OPT_VENDOR_CLASS_ID (60) +#define DHCP_OPT_CLIENT_ID (61) +#define DHCP_OPT_END (255) + +#define PORT_DHCP_SERVER (67) +#define PORT_DHCP_CLIENT (68) + +#define DEFAULT_DNS MAKE_IP4(192, 168, 4, 1) +#define DEFAULT_LEASE_TIME_S (24 * 60 * 60) // in seconds + +#define MAC_LEN (6) +#define MAKE_IP4(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d)) + +typedef struct { + uint8_t op; // message opcode + uint8_t htype; // hardware address type + uint8_t hlen; // hardware address length + uint8_t hops; + uint32_t xid; // transaction id, chosen by client + uint16_t secs; // client seconds elapsed + uint16_t flags; + uint8_t ciaddr[4]; // client IP address + uint8_t yiaddr[4]; // your IP address + uint8_t siaddr[4]; // next server IP address + uint8_t giaddr[4]; // relay agent IP address + uint8_t chaddr[16]; // client hardware address + uint8_t sname[64]; // server host name + uint8_t file[128]; // boot file name + uint8_t options[312]; // optional parameters, variable, starts with magic +} dhcp_msg_t; + +static int dhcp_socket_new_dgram(struct udp_pcb **udp, void *cb_data, udp_recv_fn cb_udp_recv) { + // family is AF_INET + // type is SOCK_DGRAM + + *udp = udp_new(); + if (*udp == NULL) { + return -MP_ENOMEM; + } + + // Register callback + udp_recv(*udp, cb_udp_recv, (void *)cb_data); + + return 0; // success +} + +static void dhcp_socket_free(struct udp_pcb **udp) { + if (*udp != NULL) { + udp_remove(*udp); + *udp = NULL; + } +} + +static int dhcp_socket_bind(struct udp_pcb **udp, uint32_t ip, uint16_t port) { + ip_addr_t addr; + IP_ADDR4(&addr, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); + // TODO convert lwIP errors to errno + return udp_bind(*udp, &addr, port); +} + +static int dhcp_socket_sendto(struct udp_pcb **udp, struct netif *netif, const void *buf, size_t len, uint32_t ip, uint16_t port) { + if (len > 0xffff) { + len = 0xffff; + } + + struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_RAM); + if (p == NULL) { + return -MP_ENOMEM; + } + + memcpy(p->payload, buf, len); + + ip_addr_t dest; + IP_ADDR4(&dest, ip >> 24 & 0xff, ip >> 16 & 0xff, ip >> 8 & 0xff, ip & 0xff); + err_t err; + if (netif != NULL) { + err = udp_sendto_if(*udp, p, &dest, port, netif); + } else { + err = udp_sendto(*udp, p, &dest, port); + } + + pbuf_free(p); + + if (err != ERR_OK) { + return err; + } + + return len; +} + +static uint8_t *opt_find(uint8_t *opt, uint8_t cmd) { + for (int i = 0; i < 308 && opt[i] != DHCP_OPT_END;) { + if (opt[i] == cmd) { + return &opt[i]; + } + i += 2 + opt[i + 1]; + } + return NULL; +} + +static void opt_write_n(uint8_t **opt, uint8_t cmd, size_t n, const void *data) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = n; + memcpy(o, data, n); + *opt = o + n; +} + +static void opt_write_u8(uint8_t **opt, uint8_t cmd, uint8_t val) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = 1; + *o++ = val; + *opt = o; +} + +static void opt_write_u32(uint8_t **opt, uint8_t cmd, uint32_t val) { + uint8_t *o = *opt; + *o++ = cmd; + *o++ = 4; + *o++ = val >> 24; + *o++ = val >> 16; + *o++ = val >> 8; + *o++ = val; + *opt = o; +} + +static void dhcp_server_process(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *src_addr, u16_t src_port) { + dhcp_server_t *d = arg; + (void)upcb; + (void)src_addr; + (void)src_port; + + // This is around 548 bytes + dhcp_msg_t dhcp_msg; + + #define DHCP_MIN_SIZE (240 + 3) + if (p->tot_len < DHCP_MIN_SIZE) { + goto ignore_request; + } + + size_t len = pbuf_copy_partial(p, &dhcp_msg, sizeof(dhcp_msg), 0); + if (len < DHCP_MIN_SIZE) { + goto ignore_request; + } + + dhcp_msg.op = DHCPOFFER; + memcpy(&dhcp_msg.yiaddr, &ip_2_ip4(&d->ip)->addr, 4); + + uint8_t *opt = (uint8_t *)&dhcp_msg.options; + opt += 4; // assume magic cookie: 99, 130, 83, 99 + + switch (opt[2]) { + case DHCPDISCOVER: { + int yi = DHCPS_MAX_IP; + for (int i = 0; i < DHCPS_MAX_IP; ++i) { + if (memcmp(d->lease[i].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { + // MAC match, use this IP address + yi = i; + break; + } + if (yi == DHCPS_MAX_IP) { + // Look for a free IP address + if (memcmp(d->lease[i].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { + // IP available + yi = i; + } + uint32_t expiry = d->lease[i].expiry << 16 | 0xffff; + if ((int32_t)(expiry - mp_hal_ticks_ms()) < 0) { + // IP expired, reuse it + memset(d->lease[i].mac, 0, MAC_LEN); + yi = i; + } + } + } + if (yi == DHCPS_MAX_IP) { + // No more IP addresses left + goto ignore_request; + } + dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; + opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPOFFER); + break; + } + + case DHCPREQUEST: { + uint8_t *o = opt_find(opt, DHCP_OPT_REQUESTED_IP); + if (o == NULL) { + // Should be NACK + goto ignore_request; + } + if (memcmp(o + 2, &ip_2_ip4(&d->ip)->addr, 3) != 0) { + // Should be NACK + goto ignore_request; + } + uint8_t yi = o[5] - DHCPS_BASE_IP; + if (yi >= DHCPS_MAX_IP) { + // Should be NACK + goto ignore_request; + } + if (memcmp(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN) == 0) { + // MAC match, ok to use this IP address + } else if (memcmp(d->lease[yi].mac, "\x00\x00\x00\x00\x00\x00", MAC_LEN) == 0) { + // IP unused, ok to use this IP address + memcpy(d->lease[yi].mac, dhcp_msg.chaddr, MAC_LEN); + } else { + // IP already in use + // Should be NACK + goto ignore_request; + } + d->lease[yi].expiry = (mp_hal_ticks_ms() + DEFAULT_LEASE_TIME_S * 1000) >> 16; + dhcp_msg.yiaddr[3] = DHCPS_BASE_IP + yi; + opt_write_u8(&opt, DHCP_OPT_MSG_TYPE, DHCPACK); + // CIRCUITPY-CHANGE: use LWIP_DEBUGF instead of printf + LWIP_DEBUGF(DHCP_DEBUG, ("DHCPS: client connected: MAC=%02x:%02x:%02x:%02x:%02x:%02x IP=%u.%u.%u.%u\n", + dhcp_msg.chaddr[0], dhcp_msg.chaddr[1], dhcp_msg.chaddr[2], dhcp_msg.chaddr[3], dhcp_msg.chaddr[4], dhcp_msg.chaddr[5], + dhcp_msg.yiaddr[0], dhcp_msg.yiaddr[1], dhcp_msg.yiaddr[2], dhcp_msg.yiaddr[3])); + break; + } + + default: + goto ignore_request; + } + + opt_write_n(&opt, DHCP_OPT_SERVER_ID, 4, &ip_2_ip4(&d->ip)->addr); + opt_write_n(&opt, DHCP_OPT_SUBNET_MASK, 4, &ip_2_ip4(&d->nm)->addr); + opt_write_n(&opt, DHCP_OPT_ROUTER, 4, &ip_2_ip4(&d->ip)->addr); // aka gateway; can have multiple addresses + opt_write_u32(&opt, DHCP_OPT_DNS, DEFAULT_DNS); // can have multiple addresses + opt_write_u32(&opt, DHCP_OPT_IP_LEASE_TIME, DEFAULT_LEASE_TIME_S); + *opt++ = DHCP_OPT_END; + struct netif *netif = ip_current_input_netif(); + dhcp_socket_sendto(&d->udp, netif, &dhcp_msg, opt - (uint8_t *)&dhcp_msg, 0xffffffff, PORT_DHCP_CLIENT); + +ignore_request: + pbuf_free(p); +} + +void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm) { + ip_addr_copy(d->ip, *ip); + ip_addr_copy(d->nm, *nm); + memset(d->lease, 0, sizeof(d->lease)); + if (dhcp_socket_new_dgram(&d->udp, d, dhcp_server_process) != 0) { + return; + } + dhcp_socket_bind(&d->udp, 0, PORT_DHCP_SERVER); +} + +void dhcp_server_deinit(dhcp_server_t *d) { + dhcp_socket_free(&d->udp); +} + +#endif // MICROPY_PY_LWIP diff --git a/shared/netutils/dhcpserver.h b/shared/netutils/dhcpserver.h new file mode 100644 index 00000000000..2349d2ea427 --- /dev/null +++ b/shared/netutils/dhcpserver.h @@ -0,0 +1,49 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2018-2019 Damien P. George + * + * 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. + */ +#ifndef MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H +#define MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H + +#include "lwip/ip_addr.h" + +#define DHCPS_BASE_IP (16) +#define DHCPS_MAX_IP (8) + +typedef struct _dhcp_server_lease_t { + uint8_t mac[6]; + uint16_t expiry; +} dhcp_server_lease_t; + +typedef struct _dhcp_server_t { + ip_addr_t ip; + ip_addr_t nm; + dhcp_server_lease_t lease[DHCPS_MAX_IP]; + struct udp_pcb *udp; +} dhcp_server_t; + +void dhcp_server_init(dhcp_server_t *d, ip_addr_t *ip, ip_addr_t *nm); +void dhcp_server_deinit(dhcp_server_t *d); + +#endif // MICROPY_INCLUDED_LIB_NETUTILS_DHCPSERVER_H diff --git a/shared/netutils/netutils.c b/shared/netutils/netutils.c new file mode 100644 index 00000000000..cd1422f7c80 --- /dev/null +++ b/shared/netutils/netutils.c @@ -0,0 +1,100 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include +#include +#include + +#include "py/runtime.h" +#include "shared/netutils/netutils.h" + +// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'. +mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian) { + char ip_str[16]; + mp_uint_t ip_len; + if (endian == NETUTILS_LITTLE) { + ip_len = snprintf(ip_str, 16, "%u.%u.%u.%u", ip[3], ip[2], ip[1], ip[0]); + } 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); +} + +// Takes an array with a raw IP address, and a port, and returns a net-address +// tuple such as ('192.168.0.1', 8080). +mp_obj_t netutils_format_inet_addr(uint8_t *ip, mp_uint_t port, netutils_endian_t endian) { + mp_obj_t tuple[2] = { + tuple[0] = netutils_format_ipv4_addr(ip, endian), + tuple[1] = mp_obj_new_int(port), + }; + return mp_obj_new_tuple(2, tuple); +} + +void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian) { + size_t addr_len; + const char *addr_str = mp_obj_str_get_data(addr_in, &addr_len); + if (addr_len == 0) { + // special case of no address given + memset(out_ip, 0, NETUTILS_IPV4ADDR_BUFSIZE); + return; + } + const char *s = addr_str; + const char *s_top; + // Scan for the end of valid address characters + for (s_top = addr_str; s_top < addr_str + addr_len; s_top++) { + if (!(*s_top == '.' || (*s_top >= '0' && *s_top <= '9'))) { + break; + } + } + for (mp_uint_t i = 3; ; i--) { + mp_uint_t val = 0; + for (; s < s_top && *s != '.'; s++) { + val = val * 10 + *s - '0'; + } + if (endian == NETUTILS_LITTLE) { + out_ip[i] = val; + } else { + out_ip[NETUTILS_IPV4ADDR_BUFSIZE - 1 - i] = val; + } + if (i == 0 && s == s_top) { + return; + } else if (i > 0 && s < s_top && *s == '.') { + s++; + } else { + mp_raise_ValueError(MP_ERROR_TEXT("invalid arguments")); + } + } +} + +// Takes an address of the form ('192.168.0.1', 8080), returns the port and +// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). +mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian) { + mp_obj_t *addr_items; + mp_obj_get_array_fixed_n(addr_in, 2, &addr_items); + netutils_parse_ipv4_addr(addr_items[0], out_ip, endian); + return mp_obj_get_int(addr_items[1]); +} diff --git a/shared/netutils/netutils.h b/shared/netutils/netutils.h new file mode 100644 index 00000000000..f82960ba800 --- /dev/null +++ b/shared/netutils/netutils.h @@ -0,0 +1,58 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * 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. + */ +#ifndef MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H +#define MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H + +#include "py/obj.h" + +#define NETUTILS_IPV4ADDR_BUFSIZE 4 + +#define NETUTILS_TRACE_IS_TX (0x0001) +#define NETUTILS_TRACE_PAYLOAD (0x0002) +#define NETUTILS_TRACE_NEWLINE (0x0004) + +typedef enum _netutils_endian_t { + NETUTILS_LITTLE, + NETUTILS_BIG, +} netutils_endian_t; + +// Takes an array with a raw IPv4 address and returns something like '192.168.0.1'. +mp_obj_t netutils_format_ipv4_addr(uint8_t *ip, netutils_endian_t endian); + +// Takes an array with a raw IP address, and a port, and returns a net-address +// tuple such as ('192.168.0.1', 8080). +mp_obj_t netutils_format_inet_addr(uint8_t *ip, mp_uint_t port, netutils_endian_t endian); + +void netutils_parse_ipv4_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian); + +// Takes an address of the form ('192.168.0.1', 8080), returns the port and +// puts IP in out_ip (which must take at least IPADDR_BUF_SIZE bytes). +mp_uint_t netutils_parse_inet_addr(mp_obj_t addr_in, uint8_t *out_ip, netutils_endian_t endian); + +void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags); + +#endif // MICROPY_INCLUDED_LIB_NETUTILS_NETUTILS_H diff --git a/shared/netutils/trace.c b/shared/netutils/trace.c new file mode 100644 index 00000000000..24af4d5ca31 --- /dev/null +++ b/shared/netutils/trace.c @@ -0,0 +1,170 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Damien P. George + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "py/mphal.h" +#include "shared/netutils/netutils.h" + +static uint32_t get_be16(const uint8_t *buf) { + return buf[0] << 8 | buf[1]; +} + +static uint32_t get_be32(const uint8_t *buf) { + return buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3]; +} + +static void dump_hex_bytes(const mp_print_t *print, size_t len, const uint8_t *buf) { + for (size_t i = 0; i < len; ++i) { + mp_printf(print, " %02x", buf[i]); + } +} + +static const char *ethertype_str(uint16_t type) { + // A value between 0x0000 - 0x05dc (inclusive) indicates a length, not type + switch (type) { + case 0x0800: + return "IPv4"; + case 0x0806: + return "ARP"; + case 0x86dd: + return "IPv6"; + default: + return NULL; + } +} + +void netutils_ethernet_trace(const mp_print_t *print, size_t len, const uint8_t *buf, unsigned int flags) { + mp_printf(print, "[% 8u] ETH%cX len=%u", (unsigned)mp_hal_ticks_ms(), flags & NETUTILS_TRACE_IS_TX ? 'T' : 'R', len); + mp_printf(print, " dst=%02x:%02x:%02x:%02x:%02x:%02x", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + mp_printf(print, " src=%02x:%02x:%02x:%02x:%02x:%02x", buf[6], buf[7], buf[8], buf[9], buf[10], buf[11]); + + const char *ethertype = ethertype_str(buf[12] << 8 | buf[13]); + if (ethertype) { + mp_printf(print, " type=%s", ethertype); + } else { + mp_printf(print, " type=0x%04x", buf[12] << 8 | buf[13]); + } + if (len > 14) { + len -= 14; + buf += 14; + if (buf[-2] == 0x08 && buf[-1] == 0x00 && buf[0] == 0x45) { + // IPv4 packet + len = get_be16(buf + 2); + mp_printf(print, " srcip=%u.%u.%u.%u dstip=%u.%u.%u.%u", + buf[12], buf[13], buf[14], buf[15], + buf[16], buf[17], buf[18], buf[19]); + uint8_t prot = buf[9]; + buf += 20; + len -= 20; + if (prot == 6) { + // TCP packet + uint16_t srcport = get_be16(buf); + uint16_t dstport = get_be16(buf + 2); + uint32_t seqnum = get_be32(buf + 4); + uint32_t acknum = get_be32(buf + 8); + uint16_t dataoff_flags = get_be16(buf + 12); + uint16_t winsz = get_be16(buf + 14); + mp_printf(print, " TCP srcport=%u dstport=%u seqnum=%u acknum=%u dataoff=%u flags=%x winsz=%u", + srcport, dstport, (unsigned)seqnum, (unsigned)acknum, dataoff_flags >> 12, dataoff_flags & 0x1ff, winsz); + buf += 20; + len -= 20; + if (dataoff_flags >> 12 > 5) { + mp_printf(print, " opts="); + size_t opts_len = ((dataoff_flags >> 12) - 5) * 4; + dump_hex_bytes(print, opts_len, buf); + buf += opts_len; + len -= opts_len; + } + } else if (prot == 17) { + // UDP packet + uint16_t srcport = get_be16(buf); + uint16_t dstport = get_be16(buf + 2); + mp_printf(print, " UDP srcport=%u dstport=%u", srcport, dstport); + len = get_be16(buf + 4); + buf += 8; + if ((srcport == 67 && dstport == 68) || (srcport == 68 && dstport == 67)) { + // DHCP + if (srcport == 67) { + mp_printf(print, " DHCPS"); + } else { + mp_printf(print, " DHCPC"); + } + dump_hex_bytes(print, 12 + 16 + 16 + 64, buf); + size_t n = 12 + 16 + 16 + 64 + 128; + len -= n; + buf += n; + mp_printf(print, " opts:"); + switch (buf[6]) { + case 1: + mp_printf(print, " DISCOVER"); + break; + case 2: + mp_printf(print, " OFFER"); + break; + case 3: + mp_printf(print, " REQUEST"); + break; + case 4: + mp_printf(print, " DECLINE"); + break; + case 5: + mp_printf(print, " ACK"); + break; + case 6: + mp_printf(print, " NACK"); + break; + case 7: + mp_printf(print, " RELEASE"); + break; + case 8: + mp_printf(print, " INFORM"); + break; + } + } + } else { + // Non-UDP packet + mp_printf(print, " prot=%u", prot); + } + } else if (buf[-2] == 0x86 && buf[-1] == 0xdd && (buf[0] >> 4) == 6) { + // IPv6 packet + uint32_t h = get_be32(buf); + uint16_t l = get_be16(buf + 4); + mp_printf(print, " tclass=%u flow=%u len=%u nexthdr=%u hoplimit=%u", (unsigned)((h >> 20) & 0xff), (unsigned)(h & 0xfffff), l, buf[6], buf[7]); + mp_printf(print, " srcip="); + dump_hex_bytes(print, 16, buf + 8); + mp_printf(print, " dstip="); + dump_hex_bytes(print, 16, buf + 24); + buf += 40; + len -= 40; + } + if (flags & NETUTILS_TRACE_PAYLOAD) { + mp_printf(print, " data="); + dump_hex_bytes(print, len, buf); + } + } + if (flags & NETUTILS_TRACE_NEWLINE) { + mp_printf(print, "\n"); + } +} diff --git a/tests/micropython/emg_exc.py.native.exp b/tests/micropython/emg_exc.py.native.exp index 9677c526a9c..879fa7ef5b9 100644 --- a/tests/micropython/emg_exc.py.native.exp +++ b/tests/micropython/emg_exc.py.native.exp @@ -1,2 +1 @@ -ValueError: 1 - +ValueError(1,) From 0882034015c259e6eda97fbeee65a378b297aac0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 10 Apr 2026 16:28:26 -0400 Subject: [PATCH 396/876] fix compile option problems --- py/circuitpy_mpconfig.h | 2 +- shared/runtime/pyexec.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index c02f0b4f870..b7b5288e8c5 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -46,7 +46,7 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_PY_BLUETOOTH (0) #define MICROPY_PY_LWIP_SLIP (0) #define MICROPY_PY_OS_DUPTERM (0) -#define MICROPY_PY_PYEXEC_COMPILE_ONLY (0) +#define MICROPY_PYEXEC_COMPILE_ONLY (0) #define MICROPY_ROM_TEXT_COMPRESSION (0) #define MICROPY_VFS_LFS1 (0) #define MICROPY_VFS_LFS2 (0) diff --git a/shared/runtime/pyexec.c b/shared/runtime/pyexec.c index 430892a00bc..bc5f89bdc81 100644 --- a/shared/runtime/pyexec.c +++ b/shared/runtime/pyexec.c @@ -615,7 +615,7 @@ MP_REGISTER_ROOT_POINTER(vstr_t * repl_line); #else // MICROPY_REPL_EVENT_DRIVEN // CIRCUITPY-CHANGE: avoid warnings -#if defined(MICROPY_HAL_HAS_STDIO_MODE_SWITCH) && !MICROPY_HAL_HAS_STDIO_MODE_SWITCH +#if !defined(MICROPY_HAL_HAS_STDIO_MODE_SWITCH) || !MICROPY_HAL_HAS_STDIO_MODE_SWITCH // If the port doesn't need any stdio mode switching calls then provide trivial ones. static inline void mp_hal_stdio_mode_raw(void) { } From e376e2416b84d7b06f3f74843682d1d74d13efd4 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 10 Apr 2026 15:52:45 -0500 Subject: [PATCH 397/876] refactor to remove common_hal_i2ctarget_i2c_target_is_stop(). Fix separate issue with read_byte returning early. --- .../common-hal/i2ctarget/I2CTarget.c | 38 +++++++++---------- .../common-hal/i2ctarget/I2CTarget.h | 2 - 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c index 655dfd867ca..a40f6e26608 100644 --- a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +++ b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c @@ -85,7 +85,12 @@ void common_hal_i2ctarget_i2c_target_deinit(i2ctarget_i2c_target_obj_t *self) { } int common_hal_i2ctarget_i2c_target_is_addressed(i2ctarget_i2c_target_obj_t *self, uint8_t *address, bool *is_read, bool *is_restart) { - common_hal_i2ctarget_i2c_target_is_stop(self); + // Interrupt bits must be cleared by software. Clear the STOP and + // RESTART interrupt bits after an I2C transaction finishes. + if (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { + self->peripheral->hw->clr_stop_det; + self->peripheral->hw->clr_restart_det; + } if (!((self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_RX_FULL_BITS) || (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_RD_REQ_BITS))) { return 0; @@ -100,12 +105,20 @@ int common_hal_i2ctarget_i2c_target_is_addressed(i2ctarget_i2c_target_obj_t *sel } int common_hal_i2ctarget_i2c_target_read_byte(i2ctarget_i2c_target_obj_t *self, uint8_t *data) { - if (self->peripheral->hw->status & I2C_IC_STATUS_RFNE_BITS) { - *data = (uint8_t)self->peripheral->hw->data_cmd; - return 1; - } else { - return 0; + // Wait for data to arrive or a STOP condition indicating the transfer is over. + // Without this wait, the CPU can drain the FIFO faster than bytes arrive on the + // I2C bus, causing transfers to be split into multiple partial reads. + for (int t = 0; t < 100; t++) { + if (self->peripheral->hw->status & I2C_IC_STATUS_RFNE_BITS) { + *data = (uint8_t)self->peripheral->hw->data_cmd; + return 1; + } + if (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { + break; + } + mp_hal_delay_us(10); } + return 0; } int common_hal_i2ctarget_i2c_target_write_byte(i2ctarget_i2c_target_obj_t *self, uint8_t data) { @@ -125,19 +138,6 @@ int common_hal_i2ctarget_i2c_target_write_byte(i2ctarget_i2c_target_obj_t *self, } } -int common_hal_i2ctarget_i2c_target_is_stop(i2ctarget_i2c_target_obj_t *self) { - // Interrupt bits must be cleared by software. Clear the STOP and - // RESTART interrupt bits after an I2C transaction finishes. - if (self->peripheral->hw->raw_intr_stat & I2C_IC_INTR_STAT_R_STOP_DET_BITS) { - self->peripheral->hw->clr_stop_det; - self->peripheral->hw->clr_restart_det; - return 1; - } else { - return 0; - } - -} - void common_hal_i2ctarget_i2c_target_ack(i2ctarget_i2c_target_obj_t *self, bool ack) { return; } diff --git a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.h b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.h index 67b09c18c2f..5d4e0690cbf 100644 --- a/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.h +++ b/ports/raspberrypi/common-hal/i2ctarget/I2CTarget.h @@ -21,5 +21,3 @@ typedef struct { uint8_t scl_pin; uint8_t sda_pin; } i2ctarget_i2c_target_obj_t; - -int common_hal_i2ctarget_i2c_target_is_stop(i2ctarget_i2c_target_obj_t *self); From 6fc9542d0cc56a52cc87f80ac61b44454990e438 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 10 Apr 2026 18:02:10 -0400 Subject: [PATCH 398/876] mp_int_t and mp_uint_t now defined in mpconfig.h --- py/circuitpy_mpconfig.h | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index b7b5288e8c5..b56ffaf076a 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -46,7 +46,7 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_PY_BLUETOOTH (0) #define MICROPY_PY_LWIP_SLIP (0) #define MICROPY_PY_OS_DUPTERM (0) -#define MICROPY_PYEXEC_COMPILE_ONLY (0) +#define MICROPY_PYEXEC_COMPILE_ONLY (0) #define MICROPY_ROM_TEXT_COMPRESSION (0) #define MICROPY_VFS_LFS1 (0) #define MICROPY_VFS_LFS2 (0) @@ -198,21 +198,6 @@ extern void common_hal_mcu_enable_interrupts(void); // Track stack usage. Expose results via ustack module. #define MICROPY_MAX_STACK_USAGE (0) -#define UINT_FMT "%u" -#define INT_FMT "%d" -#ifdef __LP64__ -typedef long mp_int_t; // must be pointer size -typedef unsigned long mp_uint_t; // must be pointer size -#else -// These are definitions for machines where sizeof(int) == sizeof(void*), -// regardless of actual size. -typedef int mp_int_t; // must be pointer size -typedef unsigned int mp_uint_t; // must be pointer size -#endif -#if __GNUC__ >= 10 // on recent gcc versions we can check that this is so -_Static_assert(sizeof(mp_int_t) == sizeof(void *)); -_Static_assert(sizeof(mp_uint_t) == sizeof(void *)); -#endif typedef long mp_off_t; #define MP_PLAT_PRINT_STRN(str, len) mp_hal_stdout_tx_strn_cooked(str, len) From 5b2e839d69b0b6b792c1ddaadf796a595032acf9 Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Sat, 11 Apr 2026 09:18:12 +0200 Subject: [PATCH 399/876] added documentation --- ports/raspberrypi/boards/pimoroni_badger2350/pins.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/pins.c b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c index ff9feb9cce4..1a66961e68f 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2350/pins.c +++ b/ports/raspberrypi/boards/pimoroni_badger2350/pins.c @@ -122,7 +122,13 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].epaper_display)}, // button-state on reset + // Use `board.RESET_STATE()` to query the state of all buttons at reset. + // To detect individual key-presses, `board.ON_RESET_PRESSED()` + // is simpler. { MP_ROM_QSTR(MP_QSTR_RESET_STATE), (mp_obj_t)&get_reset_state_obj }, + + // Use `board.ON_RESET_PRESSED(board.SW_A)` to check if `SW_A` was pressed + // during reset. { MP_ROM_QSTR(MP_QSTR_ON_RESET_PRESSED), (mp_obj_t)&on_reset_pressed_obj }, }; From e234e622e82179cdd5e357bd935acedc8f299bbe Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sun, 12 Apr 2026 13:14:33 -0500 Subject: [PATCH 400/876] enable hashlib and zlib in zephyr port and add tests for them --- .../autogen_board_info.toml | 4 +- .../autogen_board_info.toml | 4 +- .../native/native_sim/autogen_board_info.toml | 2 +- .../nrf5340bsim/autogen_board_info.toml | 4 +- .../nordic/nrf5340dk/autogen_board_info.toml | 4 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 4 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 4 +- .../nordic/nrf7002dk/autogen_board_info.toml | 2 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 4 +- .../nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../mimxrt1170_evk/autogen_board_info.toml | 4 +- .../autogen_board_info.toml | 2 +- .../rpi_pico2_zephyr/autogen_board_info.toml | 4 +- .../rpi_pico_w_zephyr/autogen_board_info.toml | 2 +- .../rpi_pico_zephyr/autogen_board_info.toml | 4 +- .../da14695_dk_usb/autogen_board_info.toml | 4 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 4 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 4 +- .../nucleo_n657x0_q/autogen_board_info.toml | 4 +- .../nucleo_u575zi_q/autogen_board_info.toml | 4 +- .../st/stm32h750b_dk/autogen_board_info.toml | 4 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 4 +- .../stm32wba65i_dk1/autogen_board_info.toml | 4 +- .../zephyr-cp/cptools/build_circuitpython.py | 9 ++ ports/zephyr-cp/prj.conf | 5 + ports/zephyr-cp/tests/test_hashlib.py | 152 ++++++++++++++++++ ports/zephyr-cp/tests/test_zlib.py | 110 +++++++++++++ 27 files changed, 317 insertions(+), 41 deletions(-) create mode 100644 ports/zephyr-cp/tests/test_hashlib.py create mode 100644 ports/zephyr-cp/tests/test_zlib.py diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 17065b90292..57e08082e9f 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index 3d7a2b29a3f..8e64638dc5a 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 5b8fcfd0dea..1bb931d29e4 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 9842ea3d88d..2ecfd08fb59 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 065a708c505..d2e690e3f0a 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index b8bad240351..9d320db9a99 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 22b92d49f49..9205f746e6a 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 5faed268cdb..f59f5ea345b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -117,4 +117,4 @@ watchdog = false wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 6da4ebc66c5..d70cd56fcfd 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 19b3b7cc0e1..045a7970018 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -117,4 +117,4 @@ watchdog = false wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 702f5900eee..a6d3e3a8462 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index 10ca2517b61..65fd81ed76f 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -117,4 +117,4 @@ watchdog = false wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index 15b36b725af..e4e52b59b93 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index 1f01990b5f2..ca9200e8180 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -117,4 +117,4 @@ watchdog = false wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index c8624cdde6c..ca05976aeb6 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index ea9ed4c2577..4d1b51291d0 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index c28c03b2c8e..8251b61be6e 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 1b0c652b7d5..ec1576e8d9b 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index c05bfa1d17e..e0d0b68c8b8 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index d6a0a27e0cd..7675df91e07 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index 599ec4ec4d2..55571241c71 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index c5505bee932..577b1681c69 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 0fe01348348..9296072a864 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 32173914a2a..2e9b120831e 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -62,6 +62,8 @@ "math", "msgpack", "aesio", + "hashlib", + "zlib", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] @@ -108,6 +110,13 @@ # No QSTR processing or CIRCUITPY specific flags LIBRARY_SOURCE = { "audiomp3": ["lib/mp3/src/*.c"], + "zlib": [ + "lib/uzlib/tinflate.c", + "lib/uzlib/tinfzlib.c", + "lib/uzlib/tinfgzip.c", + "lib/uzlib/adler32.c", + "lib/uzlib/crc32.c", + ], } SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os", "rotaryio"] diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 308333922f3..893ff259a97 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -49,3 +49,8 @@ CONFIG_I2S=y CONFIG_DYNAMIC_THREAD=y CONFIG_DYNAMIC_THREAD_ALLOC=y CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y + +CONFIG_MBEDTLS=y +CONFIG_MBEDTLS_BUILTIN=y +CONFIG_MBEDTLS_SHA1=y +CONFIG_MBEDTLS_SHA256=y diff --git a/ports/zephyr-cp/tests/test_hashlib.py b/ports/zephyr-cp/tests/test_hashlib.py new file mode 100644 index 00000000000..94463ba1e99 --- /dev/null +++ b/ports/zephyr-cp/tests/test_hashlib.py @@ -0,0 +1,152 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the hashlib module against CPython hashlib.""" + +import hashlib + +import pytest + + +SHORT_DATA = b"CircuitPython!" +CHUNK_A = b"Hello, " +CHUNK_B = b"CircuitPython world!" +LONG_DATA = b"The quick brown fox jumps over the lazy dog." * 64 + + +SHA256_CODE = """\ +import hashlib + +h = hashlib.new("sha256", b"CircuitPython!") +print(f"digest_size: {h.digest_size}") +print(f"digest_hex: {h.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": SHA256_CODE}) +def test_hashlib_sha256_basic(circuitpython): + """sha256 digest on a small buffer matches CPython hashlib.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + expected = hashlib.sha256(SHORT_DATA).hexdigest() + assert "digest_size: 32" in output + assert f"digest_hex: {expected}" in output + assert "done" in output + + +SHA1_CODE = """\ +import hashlib + +h = hashlib.new("sha1", b"CircuitPython!") +print(f"digest_size: {h.digest_size}") +print(f"digest_hex: {h.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": SHA1_CODE}) +def test_hashlib_sha1_basic(circuitpython): + """sha1 digest on a small buffer matches CPython hashlib.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + expected = hashlib.sha1(SHORT_DATA).hexdigest() + assert "digest_size: 20" in output + assert f"digest_hex: {expected}" in output + assert "done" in output + + +UPDATE_CODE = """\ +import hashlib + +h = hashlib.new("sha256") +h.update(b"Hello, ") +h.update(b"CircuitPython world!") +print(f"chunked_hex: {h.digest().hex()}") + +h2 = hashlib.new("sha256", b"Hello, CircuitPython world!") +print(f"oneshot_hex: {h2.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": UPDATE_CODE}) +def test_hashlib_sha256_update_chunks(circuitpython): + """Multiple update() calls produce the same digest as a single buffer, and match CPython.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + expected = hashlib.sha256(CHUNK_A + CHUNK_B).hexdigest() + assert f"chunked_hex: {expected}" in output + assert f"oneshot_hex: {expected}" in output + assert "done" in output + + +LONG_CODE = """\ +import hashlib + +data = b"The quick brown fox jumps over the lazy dog." * 64 +h = hashlib.new("sha256", data) +print(f"sha256_hex: {h.digest().hex()}") + +h1 = hashlib.new("sha1", data) +print(f"sha1_hex: {h1.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": LONG_CODE}) +def test_hashlib_long_input(circuitpython): + """Digests of a multi-block input match CPython for both sha1 and sha256.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"sha256_hex: {hashlib.sha256(LONG_DATA).hexdigest()}" in output + assert f"sha1_hex: {hashlib.sha1(LONG_DATA).hexdigest()}" in output + assert "done" in output + + +EMPTY_CODE = """\ +import hashlib + +h = hashlib.new("sha256", b"") +print(f"empty256: {h.digest().hex()}") + +h = hashlib.new("sha1", b"") +print(f"empty1: {h.digest().hex()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EMPTY_CODE}) +def test_hashlib_empty_input(circuitpython): + """Empty-input digests match CPython well-known values.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"empty256: {hashlib.sha256(b'').hexdigest()}" in output + assert f"empty1: {hashlib.sha1(b'').hexdigest()}" in output + assert "done" in output + + +BAD_ALGO_CODE = """\ +import hashlib + +try: + hashlib.new("md5", b"data") +except ValueError: + print("bad_algo: ValueError") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BAD_ALGO_CODE}) +def test_hashlib_unsupported_algorithm(circuitpython): + """Unsupported algorithm names raise ValueError.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "bad_algo: ValueError" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/test_zlib.py b/ports/zephyr-cp/tests/test_zlib.py new file mode 100644 index 00000000000..bd89d8e1c25 --- /dev/null +++ b/ports/zephyr-cp/tests/test_zlib.py @@ -0,0 +1,110 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the zlib module against CPython zlib. + +CircuitPython's zlib only implements ``decompress``; these tests compress data +with CPython and verify the zephyr-cp port decodes it back to the same bytes. +""" + +import zlib + +import pytest + + +PLAIN_TEXT = b"CircuitPython running on Zephyr says hello!" +REPEATED_TEXT = b"The quick brown fox jumps over the lazy dog. " * 32 +BINARY_BLOB = bytes(range(256)) * 4 + + +def _make_code(compressed: bytes, wbits: int, expected_len: int) -> str: + return ( + "import zlib\n" + f"compressed = {compressed!r}\n" + f"out = zlib.decompress(compressed, {wbits})\n" + f'print(f"out_len: {{len(out)}}")\n' + f'print(f"expected_len: {expected_len}")\n' + 'print(f"out_hex: {out.hex()}")\n' + 'print("done")\n' + ) + + +ZLIB_COMPRESSED = zlib.compress(PLAIN_TEXT) +ZLIB_CODE = _make_code(ZLIB_COMPRESSED, wbits=15, expected_len=len(PLAIN_TEXT)) + + +@pytest.mark.circuitpy_drive({"code.py": ZLIB_CODE}) +def test_zlib_decompress_zlib_format(circuitpython): + """Data produced by CPython zlib.compress() round-trips through CircuitPython zlib.decompress().""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(PLAIN_TEXT)}" in output + assert f"out_hex: {PLAIN_TEXT.hex()}" in output + assert "done" in output + + +REPEATED_COMPRESSED = zlib.compress(REPEATED_TEXT) +REPEATED_CODE = _make_code(REPEATED_COMPRESSED, wbits=15, expected_len=len(REPEATED_TEXT)) + + +@pytest.mark.circuitpy_drive({"code.py": REPEATED_CODE}) +def test_zlib_decompress_repeated(circuitpython): + """Highly-compressible repeated input decompresses correctly (back-references).""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(REPEATED_TEXT)}" in output + # Repeated text has many back-references; shrinks a lot. + assert len(REPEATED_COMPRESSED) < len(REPEATED_TEXT) // 4 + assert f"out_hex: {REPEATED_TEXT.hex()}" in output + assert "done" in output + + +BINARY_COMPRESSED = zlib.compress(BINARY_BLOB) +BINARY_CODE = _make_code(BINARY_COMPRESSED, wbits=15, expected_len=len(BINARY_BLOB)) + + +@pytest.mark.circuitpy_drive({"code.py": BINARY_CODE}) +def test_zlib_decompress_binary_bytes(circuitpython): + """Decompression preserves every byte value (0x00-0xFF).""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(BINARY_BLOB)}" in output + assert f"out_hex: {BINARY_BLOB.hex()}" in output + assert "done" in output + + +# Raw DEFLATE stream (no zlib header/trailer). +_raw_compressor = zlib.compressobj(wbits=-15) +RAW_COMPRESSED = _raw_compressor.compress(PLAIN_TEXT) + _raw_compressor.flush() +RAW_CODE = _make_code(RAW_COMPRESSED, wbits=-15, expected_len=len(PLAIN_TEXT)) + + +@pytest.mark.circuitpy_drive({"code.py": RAW_CODE}) +def test_zlib_decompress_raw_deflate(circuitpython): + """Raw DEFLATE streams (wbits=-15) decompress to the original bytes.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(PLAIN_TEXT)}" in output + assert f"out_hex: {PLAIN_TEXT.hex()}" in output + assert "done" in output + + +# Gzip wrapper (wbits=31). +_gzip_compressor = zlib.compressobj(wbits=31) +GZIP_COMPRESSED = _gzip_compressor.compress(PLAIN_TEXT) + _gzip_compressor.flush() +GZIP_CODE = _make_code(GZIP_COMPRESSED, wbits=31, expected_len=len(PLAIN_TEXT)) + + +@pytest.mark.circuitpy_drive({"code.py": GZIP_CODE}) +def test_zlib_decompress_gzip_format(circuitpython): + """Gzip-wrapped streams (wbits=31) decompress to the original bytes.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert f"out_len: {len(PLAIN_TEXT)}" in output + assert f"out_hex: {PLAIN_TEXT.hex()}" in output + assert "done" in output From b17cc70bd4ac0c14f9f9e6897b555e62334e482e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 13 Apr 2026 17:05:20 -0400 Subject: [PATCH 401/876] turn on MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING all the time --- main.c | 2 +- py/circuitpy_mpconfig.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index ca0cef419dc..ce058cc49c4 100644 --- a/main.c +++ b/main.c @@ -1149,7 +1149,7 @@ int __attribute__((used)) main(void) { } else { skip_repl = false; } - } else if (exit_code != 0) { + } else if (exit_code != PYEXEC_NORMAL_EXIT) { break; } diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index ceb4aef8026..4b23784c541 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -51,6 +51,9 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_VFS_LFS1 (0) #define MICROPY_VFS_LFS2 (0) +// Always turn on exit code handling +#define MICROPY_PYEXEC_ENABLE_EXIT_CODE_HANDLING (1) + #ifndef MICROPY_GCREGS_SETJMP #define MICROPY_GCREGS_SETJMP (0) #endif From 6caff40439be3ac9d04b6c5c319b4efb92ee2338 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 13 Apr 2026 18:20:09 -0400 Subject: [PATCH 402/876] re-merge previous cast in py/malloc.c --- py/malloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/py/malloc.c b/py/malloc.c index fa2878d5905..fc9795043a8 100644 --- a/py/malloc.c +++ b/py/malloc.c @@ -324,7 +324,8 @@ void m_tracked_free(void *ptr_in) { if (ptr_in == NULL) { return; } - m_tracked_node_t *node = (m_tracked_node_t *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t)); + // CIRCUITPY-CHANGE: cast to avoid compiler warning + m_tracked_node_t *node = (m_tracked_node_t *)(void *)((uint8_t *)ptr_in - sizeof(m_tracked_node_t)); #if MICROPY_DEBUG_VERBOSE size_t data_bytes; #if MICROPY_TRACKED_ALLOC_STORE_SIZE From 0cc24073393acbdbb9f2b9e48f62a9cbb8106748 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Apr 2026 10:54:15 -0500 Subject: [PATCH 403/876] enable adafruit_bus_device and add test --- .../autogen_board_info.toml | 2 +- .../native/native_sim/autogen_board_info.toml | 2 +- .../zephyr-cp/cptools/build_circuitpython.py | 5 +- .../tests/test_adafruit_bus_device.py | 236 ++++++++++++++++++ 4 files changed, 241 insertions(+), 4 deletions(-) create mode 100644 ports/zephyr-cp/tests/test_adafruit_bus_device.py diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index 3d7a2b29a3f..50181216122 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 5b8fcfd0dea..d5b253169b6 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 6c71ecd521c..3e43293d91a 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -62,6 +62,7 @@ "math", "msgpack", "aesio", + "adafruit_bus_device", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] @@ -549,8 +550,8 @@ async def build_circuitpython(): hal_source.extend(top.glob(f"ports/zephyr-cp/common-hal/{module.name}/*.c")) # Only include shared-module/*.c if no common-hal/*.c files were found if len(hal_source) == len_before or module.name in SHARED_MODULE_AND_COMMON_HAL: - hal_source.extend(top.glob(f"shared-module/{module.name}/*.c")) - hal_source.extend(top.glob(f"shared-bindings/{module.name}/*.c")) + hal_source.extend(top.glob(f"shared-module/{module.name}/**/*.c")) + hal_source.extend(top.glob(f"shared-bindings/{module.name}/**/*.c")) if module.name in LIBRARY_SOURCE: for library_source in LIBRARY_SOURCE[module.name]: library_sources.extend(top.glob(library_source)) diff --git a/ports/zephyr-cp/tests/test_adafruit_bus_device.py b/ports/zephyr-cp/tests/test_adafruit_bus_device.py new file mode 100644 index 00000000000..3022838506e --- /dev/null +++ b/ports/zephyr-cp/tests/test_adafruit_bus_device.py @@ -0,0 +1,236 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test adafruit_bus_device.i2c_device.I2CDevice against the AT24 EEPROM emulator.""" + +import pytest + + +PROBE_OK_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) +print(f"device created: {type(device).__name__}") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": PROBE_OK_CODE}) +def test_i2cdevice_probe_success(circuitpython): + """Constructing I2CDevice with probe=True succeeds when AT24 is present at 0x50.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "device created: I2CDevice" in output + assert "done" in output + + +PROBE_FAIL_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +try: + device = I2CDevice(i2c, 0x51) + print("unexpected_success") +except ValueError as e: + print(f"probe_failed: {e}") +except OSError as e: + print(f"probe_failed: {e}") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": PROBE_FAIL_CODE}) +def test_i2cdevice_probe_failure(circuitpython): + """Constructing I2CDevice with probe=True raises when no device responds.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "probe_failed" in output + assert "unexpected_success" not in output + assert "done" in output + + +PROBE_DISABLED_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +# probe=False should not raise even without a device at this address +device = I2CDevice(i2c, 0x51, probe=False) +print(f"device created: {type(device).__name__}") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": PROBE_DISABLED_CODE}) +def test_i2cdevice_probe_disabled(circuitpython): + """Constructing I2CDevice with probe=False succeeds regardless of device presence.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "device created: I2CDevice" in output + assert "done" in output + + +READ_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) + +# Read first byte by writing the memory address, then reading. +buf = bytearray(1) +with device: + device.write(bytes([0x00])) + device.readinto(buf) +print(f"AT24 byte 0: 0x{buf[0]:02X}") +if buf[0] == 0xFF: + print("eeprom_valid") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": READ_CODE}) +def test_i2cdevice_write_then_readinto_separate(circuitpython): + """write() followed by readinto() inside a single context manager block reads EEPROM data.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "AT24 byte 0: 0xFF" in output + assert "eeprom_valid" in output + assert "done" in output + + +WRITE_THEN_READINTO_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) + +out_buf = bytes([0x00]) +in_buf = bytearray(4) +with device: + device.write_then_readinto(out_buf, in_buf) +print(f"first 4 bytes: {[hex(b) for b in in_buf]}") +if all(b == 0xFF for b in in_buf): + print("eeprom_valid") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_THEN_READINTO_CODE}) +def test_i2cdevice_write_then_readinto_atomic(circuitpython): + """write_then_readinto() performs an atomic write+read against the EEPROM.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "first 4 bytes:" in output + assert "eeprom_valid" in output + assert "done" in output + + +WRITE_READBACK_CODE = """\ +import board +import time +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) + +# Write four bytes starting at EEPROM address 0x10. +payload = bytes([0xDE, 0xAD, 0xBE, 0xEF]) +with device: + device.write(bytes([0x10]) + payload) + +# EEPROM needs a moment to commit the write internally. +time.sleep(0.01) + +readback = bytearray(4) +with device: + device.write_then_readinto(bytes([0x10]), readback) +print(f"readback: {[hex(b) for b in readback]}") +if bytes(readback) == payload: + print("readback_ok") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": WRITE_READBACK_CODE}) +def test_i2cdevice_write_then_read_roundtrip(circuitpython): + """Writing bytes to the EEPROM and reading them back returns the written values.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "readback_ok" in output + assert "done" in output + + +SLICE_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +device = I2CDevice(i2c, 0x50) + +# Use start/end kwargs to send only a slice of the outgoing buffer. +out = bytearray([0xAA, 0x00, 0xBB]) +dest = bytearray(4) +with device: + # Only send the middle byte (the memory address 0x00). + device.write_then_readinto(out, dest, out_start=1, out_end=2, in_start=0, in_end=2) +print(f"partial read: {[hex(b) for b in dest]}") +# Only the first two entries should have been written by the read. +if dest[0] == 0xFF and dest[1] == 0xFF and dest[2] == 0x00 and dest[3] == 0x00: + print("slice_ok") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": SLICE_CODE}) +def test_i2cdevice_buffer_slices(circuitpython): + """write_then_readinto honors out_start/out_end and in_start/in_end bounds.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "slice_ok" in output + assert "done" in output + + +DISABLED_CODE = """\ +import board +from adafruit_bus_device.i2c_device import I2CDevice + +i2c = board.I2C() +try: + device = I2CDevice(i2c, 0x50) + print("unexpected_success") +except (ValueError, OSError) as e: + print(f"probe_failed: {e}") +i2c.deinit() +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": DISABLED_CODE}) +@pytest.mark.disable_i2c_devices("eeprom@50") +def test_i2cdevice_probe_fails_when_device_disabled(circuitpython): + """Probe fails when the AT24 emulator device is disabled on the bus.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "probe_failed" in output + assert "unexpected_success" not in output + assert "done" in output From f8d1c10e083c319ad313ec18504f2c60639805dd Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 14 Apr 2026 21:34:14 +0200 Subject: [PATCH 404/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 68 +++++++++++++++++++++++++++----------------- locale/el.po | 68 +++++++++++++++++++++++++++----------------- locale/hi.po | 65 +++++++++++++++++++++++++----------------- locale/ko.po | 68 +++++++++++++++++++++++++++----------------- locale/ru.po | 80 +++++++++++++++++++++++++++++++++++----------------- locale/tr.po | 65 +++++++++++++++++++++++++----------------- 6 files changed, 258 insertions(+), 156 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 94a03f2e8b8..14eb245b9b8 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -89,6 +89,11 @@ msgid "" "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "%d adresní pin, %d rgb pin a %d dlaždice indikuje výšku %d, ne %d" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q a %q obsahují duplicitní piny" @@ -273,10 +278,6 @@ msgstr "%q je mimo hranice" msgid "%q out of range" msgstr "%q je mimo rozsah" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "%q krok nemůže být nula" @@ -981,6 +982,14 @@ msgstr "Při zpracování uvedené výjimky nastala další výjimka:" msgid "ECB only operates on 16 bytes at a time" msgstr "ECB operuje najednou pouze 16 bajtů" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c #: ports/espressif/common-hal/qspibus/QSPIBus.c @@ -2656,10 +2665,6 @@ msgstr "pole je příliš velké" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "přetečení v asm" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2873,6 +2878,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2971,14 +2980,14 @@ msgstr "nelze převést complex na dtype" msgid "cannot convert complex type" msgstr "nelze převést typ complex" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "nelze smazat prvky pole" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "nelze změnit rozměry pole" @@ -3133,7 +3142,7 @@ msgstr "dimenze nesouhlasí" msgid "div/mod not implemented for uint" msgstr "div/mod nejsou implementované pro uint" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "dělení nulou" @@ -3509,6 +3518,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3703,6 +3716,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3751,10 +3768,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3776,7 +3789,7 @@ msgstr "záporný faktoriál" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -4131,6 +4144,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4140,6 +4157,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4404,10 +4425,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "neočekávané odsazení" @@ -4429,10 +4446,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4601,6 +4614,9 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ msgid "asm overflow" +#~ msgstr "přetečení v asm" + #, c-format #~ msgid "Buffer + offset too small %d %d %d" #~ msgstr "Vyrovnávací paměť + offset je příliš malý %d %d %d" diff --git a/locale/el.po b/locale/el.po index 03a28bf863d..f298c5c17e3 100644 --- a/locale/el.po +++ b/locale/el.po @@ -93,6 +93,11 @@ msgid "" msgstr "" "%d pin διεύθυνσης, %d rgb ping και %d πλακίδια αναδεικνύουν ύψος %d, όχι %d" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q και %q περιέχουν διπλότυπα pins" @@ -277,10 +282,6 @@ msgstr "%q εκτός ορίων" msgid "%q out of range" msgstr "%q εκτός εμβέλειας" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q μεταονομάστηκε σε %q" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "%q βήμα δεν μπορεί να είναι μηδέν" @@ -989,6 +990,14 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "ECB δουλεύει μόνο σε 16 bytes κάθε φορά" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c #: ports/espressif/common-hal/qspibus/QSPIBus.c @@ -2655,10 +2664,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2872,6 +2877,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2970,14 +2979,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3132,7 +3141,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3508,6 +3517,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3702,6 +3715,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3750,10 +3767,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3775,7 +3788,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -4130,6 +4143,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4139,6 +4156,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4403,10 +4424,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4428,10 +4445,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4600,6 +4613,9 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ msgid "%q renamed %q" +#~ msgstr "%q μεταονομάστηκε σε %q" + #, c-format #~ msgid "Buffer + offset too small %d %d %d" #~ msgstr "Buffer + offset είναι πολύ μικρά %d %d %d" diff --git a/locale/hi.po b/locale/hi.po index 18e4eee167c..f9d7b898198 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -80,6 +80,11 @@ msgid "" "%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "" @@ -264,10 +269,6 @@ msgstr "" msgid "%q out of range" msgstr "" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "" @@ -965,6 +966,14 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c #: ports/espressif/common-hal/qspibus/QSPIBus.c @@ -2629,10 +2638,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2846,6 +2851,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2944,14 +2953,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3106,7 +3115,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3482,6 +3491,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3676,6 +3689,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3724,10 +3741,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3749,7 +3762,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -4104,6 +4117,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4113,6 +4130,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4377,10 +4398,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4402,10 +4419,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" diff --git a/locale/ko.po b/locale/ko.po index 9f325552468..9e570208d39 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -91,6 +91,11 @@ msgid "" msgstr "" "%d 주소 핀들, %d rgb 핀들과 %d 타일 들은 높이가 %d임을 나타낸다, %d가 아니라" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q 및 %q에 중복된 핀이 포함" @@ -282,10 +287,6 @@ msgstr "%q가 경계를 벗어남" msgid "%q out of range" msgstr "%q가 범위를 벗어남" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q가 %q로 이름이 변경되었습니다" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c #, fuzzy msgid "%q step cannot be zero" @@ -1010,6 +1011,14 @@ msgstr "위 예외를 처리하는 동안, 또 다른 예외가 발생하였습 msgid "ECB only operates on 16 bytes at a time" msgstr "ECB는 한 번에 16 바이트에서만 작동합니다" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c #: ports/espressif/common-hal/qspibus/QSPIBus.c @@ -2703,10 +2712,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2920,6 +2925,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -3018,14 +3027,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3180,7 +3189,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3556,6 +3565,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3750,6 +3763,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3798,10 +3815,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3823,7 +3836,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -4178,6 +4191,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4187,6 +4204,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4451,10 +4472,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4476,10 +4493,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4648,6 +4661,9 @@ msgstr "" msgid "zi must be of shape (n_section, 2)" msgstr "" +#~ msgid "%q renamed %q" +#~ msgstr "%q가 %q로 이름이 변경되었습니다" + #, c-format #~ msgid "Buffer + offset too small %d %d %d" #~ msgstr "Buffer + offset이 너무 작습니다 %d %d %d" diff --git a/locale/ru.po b/locale/ru.po index 8f222fb2534..0f7c6c0944b 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -93,6 +93,11 @@ msgstr "" "Адресные контакты %d, контакты rgb %d и плитки %d обозначают высоту %d, а не " "%d" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q и %q содержат пины дупликаты" @@ -277,10 +282,6 @@ msgstr "%q за пределом" msgid "%q out of range" msgstr "%q вне диапазона" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "%q переименован %q" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "Шаг %q не может быть нулём" @@ -992,6 +993,14 @@ msgstr "" msgid "ECB only operates on 16 bytes at a time" msgstr "ECB работает только с 16 байтами за раз" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c #: ports/espressif/common-hal/qspibus/QSPIBus.c @@ -2695,10 +2704,6 @@ msgstr "массив слишком велик" msgid "array/bytes required on right side" msgstr "массив/байты, необходимые справа" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "Переполнение ASM" - #: py/compile.c msgid "async for/with outside async function" msgstr "async для/вместе с внешней async-функцией" @@ -2917,6 +2922,10 @@ msgstr "не может превратиться в полосу неявно" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "не может объявить нелокальный во внешнем коде" @@ -3019,14 +3028,14 @@ msgstr "не может превратить комплекс в dtype" msgid "cannot convert complex type" msgstr "Не удается преобразовать сложный тип" -#: py/objtype.c -msgid "cannot create instance" -msgstr "Не удается создать экземпляр" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "Не удается удалить элементы массива" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "Не удается изменить форму массива" @@ -3187,7 +3196,7 @@ msgstr "Размеры не совпадают" msgid "div/mod not implemented for uint" msgstr "div/mod не реализован для uint" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "Делим на ноль" @@ -3563,6 +3572,10 @@ msgstr "interp определен для 1D-итераций одинаково msgid "interval must be in range %s-%s" msgstr "Интервал должен находиться в диапазоне %s-%s" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "недействительная арка" @@ -3763,6 +3776,10 @@ msgstr "mktime нужен кортеж длины 8 или 9" msgid "mode must be complete, or reduced" msgstr "Режим должен быть завершенным или уменьшенным" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "модуль не найден" @@ -3811,10 +3828,6 @@ msgstr "слишком длинное имя" msgid "native code in .mpy unsupported" msgstr "Нативный код в .mpy не поддерживается" -#: py/asmthumb.c -msgid "native method too big" -msgstr "родной метод слишком большой" - #: py/emitnative.c msgid "native yield" msgstr "родной урожай" @@ -3836,7 +3849,7 @@ msgstr "отрицательный факториал" msgid "negative power with no float support" msgstr "Отрицательная мощность без поплавковой опоры" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "Количество отрицательных сдвигов" @@ -4193,6 +4206,10 @@ msgstr "Маски вытягивания конфликтуют с маскам msgid "real and imaginary parts must be of equal length" msgstr "реальные и воображаемые части должны быть одинаковой длины" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "Относительный импорт" @@ -4202,6 +4219,10 @@ msgstr "Относительный импорт" msgid "requested length %d but object has length %d" msgstr "запрашиваемая длина %d, но объект имеет длину %d" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "Результаты не могут быть приведены к указанному типу" @@ -4468,10 +4489,6 @@ msgstr "тип объекта '%q' не имеет атрибута '%q \"" msgid "type takes 1 or 3 arguments" msgstr "тип занимает 1 или 3 аргумента" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "голова длинная слишком большая" - #: py/parse.c msgid "unexpected indent" msgstr "Неожиданный отступ" @@ -4493,10 +4510,6 @@ msgstr "Экранирование имен в Юникоде" msgid "unindent doesn't match any outer indent level" msgstr "Отступ не совпадает ни с одним уровнем внешнего отступа" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" @@ -4667,6 +4680,21 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#~ msgid "%q renamed %q" +#~ msgstr "%q переименован %q" + +#~ msgid "asm overflow" +#~ msgstr "Переполнение ASM" + +#~ msgid "cannot create instance" +#~ msgstr "Не удается создать экземпляр" + +#~ msgid "native method too big" +#~ msgstr "родной метод слишком большой" + +#~ msgid "ulonglong too large" +#~ msgstr "голова длинная слишком большая" + #~ msgid "font must be 2048 bytes long" #~ msgstr "Длина шрифта должна составлять 2048 байт" diff --git a/locale/tr.po b/locale/tr.po index c35a97623c6..1012dbf8b39 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -91,6 +91,11 @@ msgstr "" "%d adres pinleri, %d RGB pinleri ve %d döşemeleri %d'nin yüksekliği " "gösterir, %d'nin değil" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" + #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" msgstr "%q ve %q yinelenen pinler içeriyor" @@ -275,10 +280,6 @@ msgstr "%q sınırların dışında" msgid "%q out of range" msgstr "%q aralık dışında" -#: py/objmodule.c -msgid "%q renamed %q" -msgstr "" - #: py/objrange.c py/objslice.c shared-bindings/random/__init__.c msgid "%q step cannot be zero" msgstr "%q sıfır olamaz" @@ -979,6 +980,14 @@ msgstr "Yukarıdaki hatanın işlenmesi sırasında başka bir hata oluştu:" msgid "ECB only operates on 16 bytes at a time" msgstr "ECB aynı anda yalnızca 16 baytla çalışır" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/canio/CAN.c #: ports/espressif/common-hal/qspibus/QSPIBus.c @@ -2651,10 +2660,6 @@ msgstr "" msgid "array/bytes required on right side" msgstr "" -#: py/asmxtensa.c -msgid "asm overflow" -msgstr "" - #: py/compile.c msgid "async for/with outside async function" msgstr "" @@ -2868,6 +2873,10 @@ msgstr "" msgid "can't create '%q' instances" msgstr "" +#: py/objtype.c +msgid "can't create instance" +msgstr "" + #: py/compile.c msgid "can't declare nonlocal in outer code" msgstr "" @@ -2966,14 +2975,14 @@ msgstr "" msgid "cannot convert complex type" msgstr "" -#: py/objtype.c -msgid "cannot create instance" -msgstr "" - #: extmod/ulab/code/ndarray.c msgid "cannot delete array elements" msgstr "" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" + #: extmod/ulab/code/ndarray.c msgid "cannot reshape array" msgstr "" @@ -3128,7 +3137,7 @@ msgstr "" msgid "div/mod not implemented for uint" msgstr "" -#: extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c msgid "divide by zero" msgstr "" @@ -3504,6 +3513,10 @@ msgstr "" msgid "interval must be in range %s-%s" msgstr "" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" + #: py/compile.c msgid "invalid arch" msgstr "" @@ -3698,6 +3711,10 @@ msgstr "" msgid "mode must be complete, or reduced" msgstr "" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" + #: py/builtinimport.c msgid "module not found" msgstr "" @@ -3746,10 +3763,6 @@ msgstr "" msgid "native code in .mpy unsupported" msgstr "" -#: py/asmthumb.c -msgid "native method too big" -msgstr "" - #: py/emitnative.c msgid "native yield" msgstr "" @@ -3771,7 +3784,7 @@ msgstr "" msgid "negative power with no float support" msgstr "" -#: py/objint_mpz.c py/runtime.c +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c msgid "negative shift count" msgstr "" @@ -4126,6 +4139,10 @@ msgstr "" msgid "real and imaginary parts must be of equal length" msgstr "" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" + #: py/builtinimport.c msgid "relative import" msgstr "" @@ -4135,6 +4152,10 @@ msgstr "" msgid "requested length %d but object has length %d" msgstr "" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" +msgstr "" + #: extmod/ulab/code/ndarray_operators.c msgid "results cannot be cast to specified type" msgstr "" @@ -4399,10 +4420,6 @@ msgstr "" msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objint_longlong.c -msgid "ulonglong too large" -msgstr "" - #: py/parse.c msgid "unexpected indent" msgstr "" @@ -4424,10 +4441,6 @@ msgstr "" msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/emitinlinerv32.c -msgid "unknown RV32 instruction '%q'" -msgstr "" - #: py/objstr.c #, c-format msgid "unknown conversion specifier %c" From 188358a2e8e8b906bd8dd125997ee71cbd1084b1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Apr 2026 16:47:43 -0500 Subject: [PATCH 405/876] build other zephyr autogen files --- .../feather_nrf52840_sense_zephyr/autogen_board_info.toml | 8 ++++---- .../feather_nrf52840_zephyr/autogen_board_info.toml | 2 +- .../boards/native/nrf5340bsim/autogen_board_info.toml | 2 +- .../boards/nordic/nrf5340dk/autogen_board_info.toml | 2 +- .../boards/nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../boards/nordic/nrf54l15dk/autogen_board_info.toml | 2 +- .../boards/nordic/nrf7002dk/autogen_board_info.toml | 2 +- .../boards/nxp/frdm_mcxn947/autogen_board_info.toml | 2 +- .../boards/nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../boards/nxp/mimxrt1170_evk/autogen_board_info.toml | 2 +- .../rpi_pico2_w_zephyr/autogen_board_info.toml | 2 +- .../raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml | 2 +- .../raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml | 2 +- .../raspberrypi/rpi_pico_zephyr/autogen_board_info.toml | 2 +- .../boards/renesas/da14695_dk_usb/autogen_board_info.toml | 2 +- .../boards/renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../boards/renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../boards/st/nucleo_n657x0_q/autogen_board_info.toml | 2 +- .../boards/st/nucleo_u575zi_q/autogen_board_info.toml | 2 +- .../boards/st/stm32h750b_dk/autogen_board_info.toml | 2 +- .../boards/st/stm32h7b3i_dk/autogen_board_info.toml | 2 +- .../boards/st/stm32wba65i_dk1/autogen_board_info.toml | 2 +- 22 files changed, 25 insertions(+), 25 deletions(-) diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml index cfcae400906..989332a1431 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -8,9 +8,9 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false -aesio = false +aesio = true alarm = false analogbufio = false analogio = false @@ -63,7 +63,7 @@ keypad = false keypad_demux = false locale = false lvfontio = true # Zephyr board has busio -math = false +math = true max3421e = false mcp4822 = false mdns = false @@ -71,7 +71,7 @@ memorymap = false memorymonitor = false microcontroller = true mipidsi = false -msgpack = false +msgpack = true neopixel_write = false nvm = true # Zephyr board has nvm onewireio = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 805cd8c1f33..e0bc721297a 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 9842ea3d88d..d5998f7f3bd 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 065a708c505..875757375d2 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index b8bad240351..eb00e58fe6b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 22b92d49f49..6debb1ab340 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 5faed268cdb..c5362b2cb76 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = false alarm = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 6da4ebc66c5..a0e0b6cb51a 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 19b3b7cc0e1..0ed7917934a 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 702f5900eee..efa46fcf0cb 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index 10ca2517b61..a8f5e7682c7 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index 15b36b725af..5a2a5d83197 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index 1f01990b5f2..03e4c710690 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index c8624cdde6c..4353ce7f8c5 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index ea9ed4c2577..371a647c877 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index c28c03b2c8e..53df62bae8d 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 1b0c652b7d5..3bc076dfe09 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index c05bfa1d17e..553ef877ae7 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index d6a0a27e0cd..e066ce2a9bc 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index 599ec4ec4d2..e53d7f9f1a0 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index c5505bee932..666408c6d7f 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 0fe01348348..d564f9786a0 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = false +adafruit_bus_device = true adafruit_pixelbuf = false aesio = true alarm = false From eb9a3aceaa97d52e61d942d5685954a50a4c1ba1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Apr 2026 21:13:38 -0500 Subject: [PATCH 406/876] disable adafruit_bus_device and zlib on nrf7002dk_zephyr --- .../zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml | 4 ++-- ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index ca5c6562a96..5faed268cdb 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -8,7 +8,7 @@ _eve = false _pew = false _pixelmap = false _stage = false -adafruit_bus_device = true +adafruit_bus_device = false adafruit_pixelbuf = false aesio = false alarm = false @@ -117,4 +117,4 @@ watchdog = false wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false -zlib = true +zlib = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index 7fcb145588b..191ed9d2d2c 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -2,4 +2,4 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] USB_VID=0x239A USB_PID=0x8168 BLOBS=["nrf_wifi"] -DISABLED_MODULES=["aesio"] +DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib"] From 5a2145b452f283bf39133e97b7a2366debbc04f2 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 15 Apr 2026 13:45:28 -0400 Subject: [PATCH 407/876] update frozen libraries --- frozen/Adafruit_CircuitPython_AHTx0 | 2 +- frozen/Adafruit_CircuitPython_APDS9960 | 2 +- frozen/Adafruit_CircuitPython_BLE | 2 +- frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center | 2 +- frozen/Adafruit_CircuitPython_Bitmap_Font | 2 +- frozen/Adafruit_CircuitPython_BusDevice | 2 +- frozen/Adafruit_CircuitPython_CircuitPlayground | 2 +- frozen/Adafruit_CircuitPython_ConnectionManager | 2 +- frozen/Adafruit_CircuitPython_Crickit | 2 +- frozen/Adafruit_CircuitPython_DRV2605 | 2 +- frozen/Adafruit_CircuitPython_DS3231 | 2 +- frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 | 2 +- frozen/Adafruit_CircuitPython_Display_Shapes | 2 +- frozen/Adafruit_CircuitPython_Display_Text | 2 +- frozen/Adafruit_CircuitPython_DotStar | 2 +- frozen/Adafruit_CircuitPython_ESP32SPI | 2 +- frozen/Adafruit_CircuitPython_FakeRequests | 2 +- frozen/Adafruit_CircuitPython_FocalTouch | 2 +- frozen/Adafruit_CircuitPython_HID | 2 +- frozen/Adafruit_CircuitPython_HTTPServer | 2 +- frozen/Adafruit_CircuitPython_IRRemote | 2 +- frozen/Adafruit_CircuitPython_IS31FL3731 | 2 +- frozen/Adafruit_CircuitPython_ImageLoad | 2 +- frozen/Adafruit_CircuitPython_LC709203F | 2 +- frozen/Adafruit_CircuitPython_LED_Animation | 2 +- frozen/Adafruit_CircuitPython_LIS3DH | 2 +- frozen/Adafruit_CircuitPython_LSM6DS | 2 +- frozen/Adafruit_CircuitPython_MIDI | 2 +- frozen/Adafruit_CircuitPython_MPU6050 | 2 +- frozen/Adafruit_CircuitPython_Motor | 2 +- frozen/Adafruit_CircuitPython_NeoPixel | 2 +- frozen/Adafruit_CircuitPython_OPT4048 | 2 +- frozen/Adafruit_CircuitPython_PCF8563 | 2 +- frozen/Adafruit_CircuitPython_Pixel_Framebuf | 2 +- frozen/Adafruit_CircuitPython_PortalBase | 2 +- frozen/Adafruit_CircuitPython_ProgressBar | 2 +- frozen/Adafruit_CircuitPython_RFM69 | 2 +- frozen/Adafruit_CircuitPython_RFM9x | 2 +- frozen/Adafruit_CircuitPython_Register | 2 +- frozen/Adafruit_CircuitPython_Requests | 2 +- frozen/Adafruit_CircuitPython_SD | 2 +- frozen/Adafruit_CircuitPython_SHT4x | 2 +- frozen/Adafruit_CircuitPython_SSD1306 | 2 +- frozen/Adafruit_CircuitPython_SSD1680 | 2 +- frozen/Adafruit_CircuitPython_ST7789 | 2 +- frozen/Adafruit_CircuitPython_SimpleIO | 2 +- frozen/Adafruit_CircuitPython_SimpleMath | 2 +- frozen/Adafruit_CircuitPython_Thermistor | 2 +- frozen/Adafruit_CircuitPython_Ticks | 2 +- frozen/Adafruit_CircuitPython_UC8151D | 2 +- frozen/Adafruit_CircuitPython_Wave | 2 +- frozen/Adafruit_CircuitPython_Wiznet5k | 2 +- frozen/Adafruit_CircuitPython_asyncio | 2 +- frozen/Adafruit_CircuitPython_framebuf | 2 +- frozen/Adafruit_CircuitPython_seesaw | 2 +- 55 files changed, 55 insertions(+), 55 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_AHTx0 b/frozen/Adafruit_CircuitPython_AHTx0 index 8c61ed111fc..043c7163c1d 160000 --- a/frozen/Adafruit_CircuitPython_AHTx0 +++ b/frozen/Adafruit_CircuitPython_AHTx0 @@ -1 +1 @@ -Subproject commit 8c61ed111fc83e4e1703cf5e014e645f4dbbef32 +Subproject commit 043c7163c1d66a9d3ef2150e6140f92af973c9b1 diff --git a/frozen/Adafruit_CircuitPython_APDS9960 b/frozen/Adafruit_CircuitPython_APDS9960 index f05a7239131..0134a126af8 160000 --- a/frozen/Adafruit_CircuitPython_APDS9960 +++ b/frozen/Adafruit_CircuitPython_APDS9960 @@ -1 +1 @@ -Subproject commit f05a7239131dc05df949e49c1bb5732529a864bf +Subproject commit 0134a126af8430126c9a569a29958802716262fc diff --git a/frozen/Adafruit_CircuitPython_BLE b/frozen/Adafruit_CircuitPython_BLE index 0058a10ba53..63c9af9a343 160000 --- a/frozen/Adafruit_CircuitPython_BLE +++ b/frozen/Adafruit_CircuitPython_BLE @@ -1 +1 @@ -Subproject commit 0058a10ba53e2d7bd6bcc84c7bf10dd30ee998dd +Subproject commit 63c9af9a343c68ebbd013054b799d2e35a513343 diff --git a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center index e162713efa5..a636fc984dc 160000 --- a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center +++ b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center @@ -1 +1 @@ -Subproject commit e162713efa578b9967f7ec921b129362036571b3 +Subproject commit a636fc984dced58f5f0815c5c531a03ee092f7ad diff --git a/frozen/Adafruit_CircuitPython_Bitmap_Font b/frozen/Adafruit_CircuitPython_Bitmap_Font index 47999fac242..2b320bb2649 160000 --- a/frozen/Adafruit_CircuitPython_Bitmap_Font +++ b/frozen/Adafruit_CircuitPython_Bitmap_Font @@ -1 +1 @@ -Subproject commit 47999fac242f673812315f42d1886ea54a2c5177 +Subproject commit 2b320bb26492b84d3ddabb2cd712d8db41a8b983 diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice index 69ebda79d40..d4b283c85b7 160000 --- a/frozen/Adafruit_CircuitPython_BusDevice +++ b/frozen/Adafruit_CircuitPython_BusDevice @@ -1 +1 @@ -Subproject commit 69ebda79d40d0e74c01e4f1aa293f219b8c7e086 +Subproject commit d4b283c85b7b2043eb0d095638a47305a1f4ef61 diff --git a/frozen/Adafruit_CircuitPython_CircuitPlayground b/frozen/Adafruit_CircuitPython_CircuitPlayground index 65be0763bed..2ee9b7ddd9d 160000 --- a/frozen/Adafruit_CircuitPython_CircuitPlayground +++ b/frozen/Adafruit_CircuitPython_CircuitPlayground @@ -1 +1 @@ -Subproject commit 65be0763beda780d3a1a8c4c49b033628bc54d28 +Subproject commit 2ee9b7ddd9d8574f1a154c67b5c849d2e44e3435 diff --git a/frozen/Adafruit_CircuitPython_ConnectionManager b/frozen/Adafruit_CircuitPython_ConnectionManager index 2c85f3b98d0..89e59ec81bd 160000 --- a/frozen/Adafruit_CircuitPython_ConnectionManager +++ b/frozen/Adafruit_CircuitPython_ConnectionManager @@ -1 +1 @@ -Subproject commit 2c85f3b98d08102d2494195074ad836fc3020610 +Subproject commit 89e59ec81bdfa7349b08ba3adf0d3cefc57af4d2 diff --git a/frozen/Adafruit_CircuitPython_Crickit b/frozen/Adafruit_CircuitPython_Crickit index 722f7937bfb..e3c372fecf7 160000 --- a/frozen/Adafruit_CircuitPython_Crickit +++ b/frozen/Adafruit_CircuitPython_Crickit @@ -1 +1 @@ -Subproject commit 722f7937bfb0c02340dcf737ebf37cc4ecf86b83 +Subproject commit e3c372fecf7209320826009de88818d91809cff6 diff --git a/frozen/Adafruit_CircuitPython_DRV2605 b/frozen/Adafruit_CircuitPython_DRV2605 index 616d61c7495..18b7397ec21 160000 --- a/frozen/Adafruit_CircuitPython_DRV2605 +++ b/frozen/Adafruit_CircuitPython_DRV2605 @@ -1 +1 @@ -Subproject commit 616d61c7495e5dadc6b77ea9fce07a3861580534 +Subproject commit 18b7397ec21235fc398625a52f995a3be31eb59a diff --git a/frozen/Adafruit_CircuitPython_DS3231 b/frozen/Adafruit_CircuitPython_DS3231 index 62cc4dc49b5..552104c8aed 160000 --- a/frozen/Adafruit_CircuitPython_DS3231 +++ b/frozen/Adafruit_CircuitPython_DS3231 @@ -1 +1 @@ -Subproject commit 62cc4dc49b587fad935368ed60b9ba1433250fdc +Subproject commit 552104c8aed472c7437413e94b8954e63b4a4d4d diff --git a/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 b/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 index 89463c9bd81..8c7acd451ad 160000 --- a/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 +++ b/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 @@ -1 +1 @@ -Subproject commit 89463c9bd81aaf43a14fd4f3c7bdbb75d4e48b40 +Subproject commit 8c7acd451ad53f7dc3b33a704c885032a03c1064 diff --git a/frozen/Adafruit_CircuitPython_Display_Shapes b/frozen/Adafruit_CircuitPython_Display_Shapes index e8867231041..bf6c2addf24 160000 --- a/frozen/Adafruit_CircuitPython_Display_Shapes +++ b/frozen/Adafruit_CircuitPython_Display_Shapes @@ -1 +1 @@ -Subproject commit e8867231041837735ef2769a6dc793887d1979ca +Subproject commit bf6c2addf2465625de747d2f4ea1613fcded7840 diff --git a/frozen/Adafruit_CircuitPython_Display_Text b/frozen/Adafruit_CircuitPython_Display_Text index 3b606a735a0..6450c7a3dc4 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit 3b606a735a01f0cb577447fba59e0190ba79b10e +Subproject commit 6450c7a3dc4c16c4af4b75eda549537dffb5a73c diff --git a/frozen/Adafruit_CircuitPython_DotStar b/frozen/Adafruit_CircuitPython_DotStar index 8d19e1b23cb..a12e2ce2046 160000 --- a/frozen/Adafruit_CircuitPython_DotStar +++ b/frozen/Adafruit_CircuitPython_DotStar @@ -1 +1 @@ -Subproject commit 8d19e1b23cbe6c1d17a29f321d06b16d21909b92 +Subproject commit a12e2ce2046afc1791ca6aa2bdeb33cb97f7def0 diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index 0b24c52f472..ec1d2e66ace 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit 0b24c52f472f870fcd417301521a6f7895416a4e +Subproject commit ec1d2e66ace176c13d7128a839287601a97a6bda diff --git a/frozen/Adafruit_CircuitPython_FakeRequests b/frozen/Adafruit_CircuitPython_FakeRequests index ff942eaae83..f9f9d061a66 160000 --- a/frozen/Adafruit_CircuitPython_FakeRequests +++ b/frozen/Adafruit_CircuitPython_FakeRequests @@ -1 +1 @@ -Subproject commit ff942eaae835144f7269d8206adf506c99f699f4 +Subproject commit f9f9d061a66453e0d3164ffd4e046ed3b6007669 diff --git a/frozen/Adafruit_CircuitPython_FocalTouch b/frozen/Adafruit_CircuitPython_FocalTouch index f20c13bdffa..e18ecd678ec 160000 --- a/frozen/Adafruit_CircuitPython_FocalTouch +++ b/frozen/Adafruit_CircuitPython_FocalTouch @@ -1 +1 @@ -Subproject commit f20c13bdffa9b586c648f331851f427368a995ae +Subproject commit e18ecd678ec3ac4fef884db18ddb2aab56bf44f9 diff --git a/frozen/Adafruit_CircuitPython_HID b/frozen/Adafruit_CircuitPython_HID index 788e46ca2cb..a147d3b5b97 160000 --- a/frozen/Adafruit_CircuitPython_HID +++ b/frozen/Adafruit_CircuitPython_HID @@ -1 +1 @@ -Subproject commit 788e46ca2cb2febddac83e0c660972598d6a8a27 +Subproject commit a147d3b5b976371601b460622209d327f51eb681 diff --git a/frozen/Adafruit_CircuitPython_HTTPServer b/frozen/Adafruit_CircuitPython_HTTPServer index 1419fc5c071..d55c6f54aba 160000 --- a/frozen/Adafruit_CircuitPython_HTTPServer +++ b/frozen/Adafruit_CircuitPython_HTTPServer @@ -1 +1 @@ -Subproject commit 1419fc5c071b7c631d9285c4efef4c4df23a079c +Subproject commit d55c6f54aba54df9b0e0b9d83ddf7fca46eea5e4 diff --git a/frozen/Adafruit_CircuitPython_IRRemote b/frozen/Adafruit_CircuitPython_IRRemote index 98bd8fad8cd..646cc051881 160000 --- a/frozen/Adafruit_CircuitPython_IRRemote +++ b/frozen/Adafruit_CircuitPython_IRRemote @@ -1 +1 @@ -Subproject commit 98bd8fad8cd65f481b8808e5de8cdbf62d0dd300 +Subproject commit 646cc051881a07d8bd5c442320479c6e5e553567 diff --git a/frozen/Adafruit_CircuitPython_IS31FL3731 b/frozen/Adafruit_CircuitPython_IS31FL3731 index 1babff02ea8..c011e8e0d02 160000 --- a/frozen/Adafruit_CircuitPython_IS31FL3731 +++ b/frozen/Adafruit_CircuitPython_IS31FL3731 @@ -1 +1 @@ -Subproject commit 1babff02ea87f5c4863aed20be0da553d76e9600 +Subproject commit c011e8e0d021a6c5870242eb721f012922002fc8 diff --git a/frozen/Adafruit_CircuitPython_ImageLoad b/frozen/Adafruit_CircuitPython_ImageLoad index 67532099f7a..458bc46b63e 160000 --- a/frozen/Adafruit_CircuitPython_ImageLoad +++ b/frozen/Adafruit_CircuitPython_ImageLoad @@ -1 +1 @@ -Subproject commit 67532099f7a574f08955b31efb7c1ca5cc3f143c +Subproject commit 458bc46b63ea2bfc51529b05b62b4df3c5902e17 diff --git a/frozen/Adafruit_CircuitPython_LC709203F b/frozen/Adafruit_CircuitPython_LC709203F index 7fe15ca666b..e32e39a18d2 160000 --- a/frozen/Adafruit_CircuitPython_LC709203F +++ b/frozen/Adafruit_CircuitPython_LC709203F @@ -1 +1 @@ -Subproject commit 7fe15ca666bd3730a17e13bb29ff884092345b5f +Subproject commit e32e39a18d23ae58fe97b3472253b6cbcbc8ebd0 diff --git a/frozen/Adafruit_CircuitPython_LED_Animation b/frozen/Adafruit_CircuitPython_LED_Animation index 515553f0b6c..7cc736df162 160000 --- a/frozen/Adafruit_CircuitPython_LED_Animation +++ b/frozen/Adafruit_CircuitPython_LED_Animation @@ -1 +1 @@ -Subproject commit 515553f0b6cb1290b92965f8e4e8beab9e83bcf1 +Subproject commit 7cc736df1628f767c4fc6f23287cedbf6e80f4ce diff --git a/frozen/Adafruit_CircuitPython_LIS3DH b/frozen/Adafruit_CircuitPython_LIS3DH index 83333f8f6a5..ca871b8bc59 160000 --- a/frozen/Adafruit_CircuitPython_LIS3DH +++ b/frozen/Adafruit_CircuitPython_LIS3DH @@ -1 +1 @@ -Subproject commit 83333f8f6a5501f9cbee215ebc791cd2fb67bd7d +Subproject commit ca871b8bc59b23acbfd779bf59d420599e8bcbb5 diff --git a/frozen/Adafruit_CircuitPython_LSM6DS b/frozen/Adafruit_CircuitPython_LSM6DS index 36247d1d9d7..9d94dc6a335 160000 --- a/frozen/Adafruit_CircuitPython_LSM6DS +++ b/frozen/Adafruit_CircuitPython_LSM6DS @@ -1 +1 @@ -Subproject commit 36247d1d9d769a23f40ca2c4371a5cd64e2a7204 +Subproject commit 9d94dc6a3350cb8766baa4a1247e36576b00f68a diff --git a/frozen/Adafruit_CircuitPython_MIDI b/frozen/Adafruit_CircuitPython_MIDI index 2bc55548577..5feb31fbd31 160000 --- a/frozen/Adafruit_CircuitPython_MIDI +++ b/frozen/Adafruit_CircuitPython_MIDI @@ -1 +1 @@ -Subproject commit 2bc555485772743b70f620fe939048020924a605 +Subproject commit 5feb31fbd31f2475862e0cb55c89359cb688ad34 diff --git a/frozen/Adafruit_CircuitPython_MPU6050 b/frozen/Adafruit_CircuitPython_MPU6050 index bb5100733f3..d3761591ccf 160000 --- a/frozen/Adafruit_CircuitPython_MPU6050 +++ b/frozen/Adafruit_CircuitPython_MPU6050 @@ -1 +1 @@ -Subproject commit bb5100733f339dcad24df7d32eeeb492023b5059 +Subproject commit d3761591ccf7629b39675dd1db45184b96a3b779 diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index 610c42f1187..f55b2910b01 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit 610c42f1187045fb962807ac8d895e66e2612298 +Subproject commit f55b2910b01094904461d769581221c20418a267 diff --git a/frozen/Adafruit_CircuitPython_NeoPixel b/frozen/Adafruit_CircuitPython_NeoPixel index 5b8fe0e7064..d3eaf5c45dd 160000 --- a/frozen/Adafruit_CircuitPython_NeoPixel +++ b/frozen/Adafruit_CircuitPython_NeoPixel @@ -1 +1 @@ -Subproject commit 5b8fe0e70646d55bfa75a14cbc5136b9328be850 +Subproject commit d3eaf5c45dde45588f9a2eb2ffbe0b9025251bee diff --git a/frozen/Adafruit_CircuitPython_OPT4048 b/frozen/Adafruit_CircuitPython_OPT4048 index b6a02e289e9..ddfe6b13ace 160000 --- a/frozen/Adafruit_CircuitPython_OPT4048 +++ b/frozen/Adafruit_CircuitPython_OPT4048 @@ -1 +1 @@ -Subproject commit b6a02e289e922b328fd395908b6b89f12ee137ea +Subproject commit ddfe6b13acef7076333ee8e0ecd27bc4186512b9 diff --git a/frozen/Adafruit_CircuitPython_PCF8563 b/frozen/Adafruit_CircuitPython_PCF8563 index 3f40c877acb..16e3112885b 160000 --- a/frozen/Adafruit_CircuitPython_PCF8563 +++ b/frozen/Adafruit_CircuitPython_PCF8563 @@ -1 +1 @@ -Subproject commit 3f40c877acbbda0ef82336c18f3620ce1b9013f5 +Subproject commit 16e3112885b0b6149b4dfa1749181424dd5da122 diff --git a/frozen/Adafruit_CircuitPython_Pixel_Framebuf b/frozen/Adafruit_CircuitPython_Pixel_Framebuf index d355df47c0d..555b30acf78 160000 --- a/frozen/Adafruit_CircuitPython_Pixel_Framebuf +++ b/frozen/Adafruit_CircuitPython_Pixel_Framebuf @@ -1 +1 @@ -Subproject commit d355df47c0d5c1f80da01c86d585223988f30a33 +Subproject commit 555b30acf78ba65cec48f64b3350e19fddada4ce diff --git a/frozen/Adafruit_CircuitPython_PortalBase b/frozen/Adafruit_CircuitPython_PortalBase index 067b1b80dfd..b67904c7bca 160000 --- a/frozen/Adafruit_CircuitPython_PortalBase +++ b/frozen/Adafruit_CircuitPython_PortalBase @@ -1 +1 @@ -Subproject commit 067b1b80dfd42fe1b62416eef2790b7d99d46206 +Subproject commit b67904c7bca12d7ee443e16bc40d64fd67c7cb48 diff --git a/frozen/Adafruit_CircuitPython_ProgressBar b/frozen/Adafruit_CircuitPython_ProgressBar index 9fa23112cea..fab168ab38f 160000 --- a/frozen/Adafruit_CircuitPython_ProgressBar +++ b/frozen/Adafruit_CircuitPython_ProgressBar @@ -1 +1 @@ -Subproject commit 9fa23112cea1a8db2b9b87cf2156cc4b039440a7 +Subproject commit fab168ab38f61f654735140c67c7defdad512de8 diff --git a/frozen/Adafruit_CircuitPython_RFM69 b/frozen/Adafruit_CircuitPython_RFM69 index 763992bb084..1837cb10b35 160000 --- a/frozen/Adafruit_CircuitPython_RFM69 +++ b/frozen/Adafruit_CircuitPython_RFM69 @@ -1 +1 @@ -Subproject commit 763992bb084343ee1a7cfce72585e028ced0d890 +Subproject commit 1837cb10b353a6349c33d87c0f045c80c08003e3 diff --git a/frozen/Adafruit_CircuitPython_RFM9x b/frozen/Adafruit_CircuitPython_RFM9x index ad05a38fc96..ad3a28df5e0 160000 --- a/frozen/Adafruit_CircuitPython_RFM9x +++ b/frozen/Adafruit_CircuitPython_RFM9x @@ -1 +1 @@ -Subproject commit ad05a38fc96edcae5d0ac9d107c268dd76e4a186 +Subproject commit ad3a28df5e0cab2a24b9a6acf0667fe7c5a26563 diff --git a/frozen/Adafruit_CircuitPython_Register b/frozen/Adafruit_CircuitPython_Register index 98faa16a0dd..2a7039c5484 160000 --- a/frozen/Adafruit_CircuitPython_Register +++ b/frozen/Adafruit_CircuitPython_Register @@ -1 +1 @@ -Subproject commit 98faa16a0dd6c63a2726b291a53fde760a0fcabb +Subproject commit 2a7039c548456ddf7573814967ce494f61adbc46 diff --git a/frozen/Adafruit_CircuitPython_Requests b/frozen/Adafruit_CircuitPython_Requests index 1479169b59d..44186adfc6a 160000 --- a/frozen/Adafruit_CircuitPython_Requests +++ b/frozen/Adafruit_CircuitPython_Requests @@ -1 +1 @@ -Subproject commit 1479169b59d069b15384da64645f1e2d711a4679 +Subproject commit 44186adfc6a982f26007cba2b103dd65cbb68c65 diff --git a/frozen/Adafruit_CircuitPython_SD b/frozen/Adafruit_CircuitPython_SD index dfbb9fd6ae2..c700b45d484 160000 --- a/frozen/Adafruit_CircuitPython_SD +++ b/frozen/Adafruit_CircuitPython_SD @@ -1 +1 @@ -Subproject commit dfbb9fd6ae297d6246554ea44e6c318970de98af +Subproject commit c700b45d484a7e5054cf1856b871f3f25edb5ebb diff --git a/frozen/Adafruit_CircuitPython_SHT4x b/frozen/Adafruit_CircuitPython_SHT4x index 9da248ca944..2b5317830e6 160000 --- a/frozen/Adafruit_CircuitPython_SHT4x +++ b/frozen/Adafruit_CircuitPython_SHT4x @@ -1 +1 @@ -Subproject commit 9da248ca944264cbc4278c1732f901f3e1229231 +Subproject commit 2b5317830e66233017e68f8b459261bc4240307d diff --git a/frozen/Adafruit_CircuitPython_SSD1306 b/frozen/Adafruit_CircuitPython_SSD1306 index 2d7fd1fd8f7..04d8d531e8e 160000 --- a/frozen/Adafruit_CircuitPython_SSD1306 +++ b/frozen/Adafruit_CircuitPython_SSD1306 @@ -1 +1 @@ -Subproject commit 2d7fd1fd8f7bb1b83d60926a28ab01ffaf67fa3b +Subproject commit 04d8d531e8ed2df45c061c8b3c6d91abda001f13 diff --git a/frozen/Adafruit_CircuitPython_SSD1680 b/frozen/Adafruit_CircuitPython_SSD1680 index c22e6d097b4..c98b43e11ec 160000 --- a/frozen/Adafruit_CircuitPython_SSD1680 +++ b/frozen/Adafruit_CircuitPython_SSD1680 @@ -1 +1 @@ -Subproject commit c22e6d097b44c6e9612ff6b866ebec569796e6f5 +Subproject commit c98b43e11eca52c9885c48e866325595f5614eb8 diff --git a/frozen/Adafruit_CircuitPython_ST7789 b/frozen/Adafruit_CircuitPython_ST7789 index 1060cf1753d..8fb8cbf7c4c 160000 --- a/frozen/Adafruit_CircuitPython_ST7789 +++ b/frozen/Adafruit_CircuitPython_ST7789 @@ -1 +1 @@ -Subproject commit 1060cf1753df0024a95070132045357ddd9ce559 +Subproject commit 8fb8cbf7c4cf404c1334df67a7512ccf99a00c52 diff --git a/frozen/Adafruit_CircuitPython_SimpleIO b/frozen/Adafruit_CircuitPython_SimpleIO index 054d2643744..b024e7276cf 160000 --- a/frozen/Adafruit_CircuitPython_SimpleIO +++ b/frozen/Adafruit_CircuitPython_SimpleIO @@ -1 +1 @@ -Subproject commit 054d2643744fe78fed3c4c8b371ced26c8ab2ebe +Subproject commit b024e7276cf3796dddcced3cbe438195d310661b diff --git a/frozen/Adafruit_CircuitPython_SimpleMath b/frozen/Adafruit_CircuitPython_SimpleMath index da27f052357..9ebbdae834c 160000 --- a/frozen/Adafruit_CircuitPython_SimpleMath +++ b/frozen/Adafruit_CircuitPython_SimpleMath @@ -1 +1 @@ -Subproject commit da27f05235713bc8e79cf3a005d11bab920e13bb +Subproject commit 9ebbdae834ca3225bf411ba54c9e3148d8c26b6c diff --git a/frozen/Adafruit_CircuitPython_Thermistor b/frozen/Adafruit_CircuitPython_Thermistor index f109e9d847b..bdfeb28d741 160000 --- a/frozen/Adafruit_CircuitPython_Thermistor +++ b/frozen/Adafruit_CircuitPython_Thermistor @@ -1 +1 @@ -Subproject commit f109e9d847b7f8ba8545a2b6be8d0c3dd6a8a280 +Subproject commit bdfeb28d741a0233c4d8789b610d116831c9c0dd diff --git a/frozen/Adafruit_CircuitPython_Ticks b/frozen/Adafruit_CircuitPython_Ticks index 83695404ab7..415f35dceaf 160000 --- a/frozen/Adafruit_CircuitPython_Ticks +++ b/frozen/Adafruit_CircuitPython_Ticks @@ -1 +1 @@ -Subproject commit 83695404ab734eb60d32c9e96784b9bd90c58a1a +Subproject commit 415f35dceaf43f6e2bbc879f7049fed5e52f3c4a diff --git a/frozen/Adafruit_CircuitPython_UC8151D b/frozen/Adafruit_CircuitPython_UC8151D index b9bd61a0bbe..ec3fd72eb42 160000 --- a/frozen/Adafruit_CircuitPython_UC8151D +++ b/frozen/Adafruit_CircuitPython_UC8151D @@ -1 +1 @@ -Subproject commit b9bd61a0bbef1f4705abb831739d4888f1dcec95 +Subproject commit ec3fd72eb4219520c2ad5dd33e2e865a7e4b9d6a diff --git a/frozen/Adafruit_CircuitPython_Wave b/frozen/Adafruit_CircuitPython_Wave index d302cd78d29..10f7ed33cbf 160000 --- a/frozen/Adafruit_CircuitPython_Wave +++ b/frozen/Adafruit_CircuitPython_Wave @@ -1 +1 @@ -Subproject commit d302cd78d29ef821faa1c18482a0b20fdca1d4ee +Subproject commit 10f7ed33cbf75b0f42ffe9aae721f57583a33ce6 diff --git a/frozen/Adafruit_CircuitPython_Wiznet5k b/frozen/Adafruit_CircuitPython_Wiznet5k index fa2e95d61fb..1e786b93a5a 160000 --- a/frozen/Adafruit_CircuitPython_Wiznet5k +++ b/frozen/Adafruit_CircuitPython_Wiznet5k @@ -1 +1 @@ -Subproject commit fa2e95d61fb5a90b8bd59234b56d1acbfe9fd995 +Subproject commit 1e786b93a5a1dede2fa6f44634336f666d153f6a diff --git a/frozen/Adafruit_CircuitPython_asyncio b/frozen/Adafruit_CircuitPython_asyncio index 1f9fee3c5d9..d0d63f113c7 160000 --- a/frozen/Adafruit_CircuitPython_asyncio +++ b/frozen/Adafruit_CircuitPython_asyncio @@ -1 +1 @@ -Subproject commit 1f9fee3c5d99d60b069c4a366678b391c198d955 +Subproject commit d0d63f113c7da0852bdc5aa303cd738e45d40fbc diff --git a/frozen/Adafruit_CircuitPython_framebuf b/frozen/Adafruit_CircuitPython_framebuf index 8a94ddb7257..3d2036d2926 160000 --- a/frozen/Adafruit_CircuitPython_framebuf +++ b/frozen/Adafruit_CircuitPython_framebuf @@ -1 +1 @@ -Subproject commit 8a94ddb7257bebfb856fe476d9b851dfa63ce443 +Subproject commit 3d2036d2926f7d04a00908845dd14cb18e3d8b90 diff --git a/frozen/Adafruit_CircuitPython_seesaw b/frozen/Adafruit_CircuitPython_seesaw index 50628104824..daab794981f 160000 --- a/frozen/Adafruit_CircuitPython_seesaw +++ b/frozen/Adafruit_CircuitPython_seesaw @@ -1 +1 @@ -Subproject commit 50628104824849fbdac093c8f18367623edff1c4 +Subproject commit daab794981f177041fe1a4a9266a9688c45480e9 From f466b49345749a2a1c9c2ec9a171303dc17a546b Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 15 Apr 2026 11:44:42 -0700 Subject: [PATCH 408/876] docs(sdcardio): clarify SD-first init rule for boards with floating CS pins The existing "Important" note says the SD card must always be initialized before any other SPI peripheral. This is correct in most cases, but is misleading for boards like the Feather RP2040 RFM where the co-located peripheral (RFM95) has a floating CS pin with no hardware pull-up. On those boards the floating CS corrupts the SPI bus during SD init, so that peripheral's CS must be driven HIGH first. Added an exception paragraph to the important block to document this case. --- shared-bindings/sdcardio/SDCard.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index 2802499956c..d9f0d3b4b40 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -43,6 +43,12 @@ //| Failure to do so can prevent the SD card from being recognized until it is //| powered off or re-inserted. //| +//| Exception: on boards where another SPI peripheral has a floating CS +//| pin with no hardware pull-up (such as the Feather RP2040 RFM), that +//| peripheral's CS must be driven HIGH before SD card initialization. +//| Failure to do so will corrupt the SPI bus during SD card init. In +//| these cases, initialize and drive the other peripheral's CS high +//| first, then initialize the SD card. //| Example usage: //| //| .. code-block:: python From 9abc9c962452e39cae0aa170c2fd6bbcee7b0da8 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 15 Apr 2026 13:14:27 -0700 Subject: [PATCH 409/876] Fix indentation of Exception block to match .. important:: level --- shared-bindings/sdcardio/SDCard.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index d9f0d3b4b40..2c8050b9038 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -43,12 +43,12 @@ //| Failure to do so can prevent the SD card from being recognized until it is //| powered off or re-inserted. //| -//| Exception: on boards where another SPI peripheral has a floating CS -//| pin with no hardware pull-up (such as the Feather RP2040 RFM), that -//| peripheral's CS must be driven HIGH before SD card initialization. -//| Failure to do so will corrupt the SPI bus during SD card init. In -//| these cases, initialize and drive the other peripheral's CS high -//| first, then initialize the SD card. +//| Exception: on boards where another SPI peripheral has a floating CS +//| pin with no hardware pull-up (such as the Feather RP2040 RFM), that +//| peripheral's CS must be driven HIGH before SD card initialization. +//| Failure to do so will corrupt the SPI bus during SD card init. In +//| these cases, initialize and drive the other peripheral's CS high +//| first, then initialize the SD card. //| Example usage: //| //| .. code-block:: python From 1a85bc65b4104563ca70ebde3f89ea351c7c64af Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 15 Apr 2026 16:19:51 -0400 Subject: [PATCH 410/876] Fix comment formatting in SDCard.c --- shared-bindings/sdcardio/SDCard.c | 1 + 1 file changed, 1 insertion(+) diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index 2c8050b9038..9a04cea57e5 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -49,6 +49,7 @@ //| Failure to do so will corrupt the SPI bus during SD card init. In //| these cases, initialize and drive the other peripheral's CS high //| first, then initialize the SD card. +//| //| Example usage: //| //| .. code-block:: python From 88e07ae53e1e6880ab6364fdb5cfe384c69e752c Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 16 Apr 2026 11:21:45 -0500 Subject: [PATCH 411/876] enable getpass in zephyr port and add test for it. --- .../autogen_board_info.toml | 6 +- .../autogen_board_info.toml | 2 +- .../autogen_board_info.toml | 2 +- .../native/native_sim/autogen_board_info.toml | 2 +- .../nrf5340bsim/autogen_board_info.toml | 2 +- .../nordic/nrf5340dk/autogen_board_info.toml | 2 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 2 +- .../nordic/nrf7002dk/autogen_board_info.toml | 2 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 2 +- .../nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../mimxrt1170_evk/autogen_board_info.toml | 2 +- .../autogen_board_info.toml | 2 +- .../rpi_pico2_zephyr/autogen_board_info.toml | 2 +- .../rpi_pico_w_zephyr/autogen_board_info.toml | 2 +- .../rpi_pico_zephyr/autogen_board_info.toml | 2 +- .../da14695_dk_usb/autogen_board_info.toml | 2 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../nucleo_n657x0_q/autogen_board_info.toml | 2 +- .../nucleo_u575zi_q/autogen_board_info.toml | 2 +- .../st/stm32h750b_dk/autogen_board_info.toml | 2 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 2 +- .../stm32wba65i_dk1/autogen_board_info.toml | 2 +- .../zephyr-cp/cptools/build_circuitpython.py | 1 + ports/zephyr-cp/tests/test_getpass.py | 182 ++++++++++++++++++ 26 files changed, 209 insertions(+), 26 deletions(-) create mode 100644 ports/zephyr-cp/tests/test_getpass.py diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml index 989332a1431..9d7af49936a 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -47,10 +47,10 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 51c02dad4cf..9860956ca23 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index c1d6e2ed3ce..54c1d4d578f 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index b293424b539..c9bbc0a9a43 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true # Zephyr networking enabled diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 6d6d5841bbc..a75b1eee5b4 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index b5d36e61566..e850884fd2e 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 2c72ba1570d..9b4d9933697 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index d981883bf65..a0ff21ffa30 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 5faed268cdb..54e2b89d638 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true # Zephyr networking enabled diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 8105f7731da..32d194c8702 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index a23bc81503c..db496abb531 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true # Zephyr networking enabled diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index e97292fee76..3144751db86 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index 83b54ae2fa2..aa41a95b8a0 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true # Zephyr networking enabled diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index 65c5bc003ae..a9305e511c9 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index 97288095e00..0658a5674dc 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true # Zephyr networking enabled diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index 18e1fc83565..c9184ee81cd 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index 529254cfec2..07463f618e8 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 7a1c0bfd21e..8f3d8612819 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 185859b0807..431d459f063 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 7686dbf320b..21f064f0577 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 4037dac0481..dcf94db57ae 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index 1a97bb36163..813039f6538 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 4723617a5a7..c4a3a0be44c 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 749b040b6d4..54f72b30063 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -47,7 +47,7 @@ fontio = true # Zephyr board has busio fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false -getpass = false +getpass = true gifio = false gnss = false hashlib = true diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 1a559979746..7f3a012064f 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -65,6 +65,7 @@ "hashlib", "zlib", "adafruit_bus_device", + "getpass", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] diff --git a/ports/zephyr-cp/tests/test_getpass.py b/ports/zephyr-cp/tests/test_getpass.py new file mode 100644 index 00000000000..541d91078b3 --- /dev/null +++ b/ports/zephyr-cp/tests/test_getpass.py @@ -0,0 +1,182 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the getpass core module.""" + +import pytest + + +DEFAULT_PROMPT_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass() +print(f"got: {pw}") +print(f"length: {len(pw)}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": DEFAULT_PROMPT_CODE}) +def test_getpass_default_prompt(circuitpython): + """getpass() with no args prints 'Password: ' and returns the typed string.""" + circuitpython.serial.wait_for("ready") + circuitpython.serial.wait_for("Password:") + circuitpython.serial.write("hunter2\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "Password:" in output + assert "got: hunter2" in output + assert "length: 7" in output + assert "done" in output + + +CUSTOM_PROMPT_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass("Enter secret: ") +print(f"got: {pw}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CUSTOM_PROMPT_CODE}) +def test_getpass_custom_prompt(circuitpython): + """A user-supplied prompt string is written before reading input.""" + circuitpython.serial.wait_for("Enter secret:") + circuitpython.serial.write("s3cr3t\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "Enter secret:" in output + assert "got: s3cr3t" in output + assert "done" in output + + +NO_ECHO_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass("Pwd: ") +print("---boundary---") +print(f"got: {pw}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": NO_ECHO_CODE}) +def test_getpass_does_not_echo(circuitpython): + """Characters typed during getpass are not echoed back to the terminal.""" + circuitpython.serial.wait_for("Pwd:") + secret = "TopSecret123" + circuitpython.serial.write(secret + "\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # Split around the boundary: nothing typed should appear before it, + # but the printed value appears after. + pre, _, post = output.partition("---boundary---") + assert secret not in pre + assert f"got: {secret}" in post + assert "done" in post + + +BACKSPACE_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass("P: ") +print(f"got: {pw}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BACKSPACE_CODE}) +def test_getpass_backspace(circuitpython): + """Backspace (0x7f) removes the previous character from the buffer.""" + circuitpython.serial.wait_for("P:") + # Type "abcX", then backspace, then "d" -> "abcd" + circuitpython.serial.write("abcX\x7fd\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "got: abcd" in output + assert "done" in output + + +CTRL_C_CODE = """\ +import getpass + +print("ready") +try: + getpass.getpass("Pwd: ") + print("no exception") +except KeyboardInterrupt: + print("interrupted") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CTRL_C_CODE}) +def test_getpass_ctrl_c_raises_keyboard_interrupt(circuitpython): + """Sending Ctrl+C while getpass is reading raises KeyboardInterrupt.""" + circuitpython.serial.wait_for("Pwd:") + circuitpython.serial.write("\x03") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "interrupted" in output + assert "no exception" not in output + assert "done" in output + + +CTRL_D_EMPTY_CODE = """\ +import getpass + +print("ready") +try: + getpass.getpass("Pwd: ") + print("no exception") +except EOFError: + print("eof") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": CTRL_D_EMPTY_CODE}) +def test_getpass_ctrl_d_empty_raises_eof(circuitpython): + """Ctrl+D with an empty buffer raises EOFError.""" + circuitpython.serial.wait_for("Pwd:") + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "eof" in output + assert "no exception" not in output + assert "done" in output + + +EMPTY_INPUT_CODE = """\ +import getpass + +print("ready") +pw = getpass.getpass("Pwd: ") +print(f"length: {len(pw)}") +print(f"empty: {pw == ''}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": EMPTY_INPUT_CODE}) +def test_getpass_empty_input(circuitpython): + """Pressing return immediately yields an empty string.""" + circuitpython.serial.wait_for("Pwd:") + circuitpython.serial.write("\r") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "length: 0" in output + assert "empty: True" in output + assert "done" in output From ce7f41076511ca252e47615cef2d91d8d889c5d0 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 16 Apr 2026 11:12:01 -0700 Subject: [PATCH 412/876] Fix typo in time.monotonic_ns() docstring The docstring for monotonic_ns referred to comparing against values from time.monotonic(), but should refer to time.monotonic_ns() since the two return different units. Fixes #10946 --- shared-bindings/time/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/time/__init__.c b/shared-bindings/time/__init__.c index e19d97251bc..b6d36baeb5f 100644 --- a/shared-bindings/time/__init__.c +++ b/shared-bindings/time/__init__.c @@ -206,7 +206,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(time_time_obj, time_time); //| def monotonic_ns() -> int: //| """Return the time of the monotonic clock, which cannot go backward, in nanoseconds. //| Not available on boards without long integer support. -//| Only use it to compare against other values from `time.monotonic()` +//| Only use it to compare against other values from `time.monotonic_ns()` //| during a single code run. //| //| :return: the current time From 68fc784df0407bc9d2edc30e36fbca275eaf861a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 16 Apr 2026 13:28:34 -0500 Subject: [PATCH 413/876] enable jpegio in zephyr port and add test for it. add more to jpegio docstring example --- .../autogen_board_info.toml | 6 +- .../autogen_board_info.toml | 2 +- .../autogen_board_info.toml | 2 +- .../native/native_sim/autogen_board_info.toml | 2 +- .../nrf5340bsim/autogen_board_info.toml | 2 +- .../nordic/nrf5340dk/autogen_board_info.toml | 2 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 2 +- .../nordic/nrf7002dk/circuitpython.toml | 2 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 2 +- .../nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../mimxrt1170_evk/autogen_board_info.toml | 2 +- .../autogen_board_info.toml | 2 +- .../rpi_pico2_zephyr/autogen_board_info.toml | 2 +- .../rpi_pico_w_zephyr/autogen_board_info.toml | 2 +- .../rpi_pico_zephyr/autogen_board_info.toml | 2 +- .../da14695_dk_usb/autogen_board_info.toml | 2 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../nucleo_n657x0_q/autogen_board_info.toml | 2 +- .../nucleo_u575zi_q/autogen_board_info.toml | 2 +- .../st/stm32h750b_dk/autogen_board_info.toml | 2 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 2 +- .../stm32wba65i_dk1/autogen_board_info.toml | 2 +- .../zephyr-cp/cptools/build_circuitpython.py | 4 + .../golden/jpegio_test_pattern_320x240.png | Bin 0 -> 1241 bytes ports/zephyr-cp/tests/zephyr_display/test.jpg | Bin 0 -> 553 bytes .../tests/zephyr_display/test_jpegio.py | 87 ++++++++++++++++++ shared-bindings/jpegio/JpegDecoder.c | 9 +- 29 files changed, 124 insertions(+), 28 deletions(-) create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/jpegio_test_pattern_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/test.jpg create mode 100644 ports/zephyr-cp/tests/zephyr_display/test_jpegio.py diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml index 989332a1431..e1ce04b1d01 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -50,7 +50,7 @@ frequencyio = false getpass = false gifio = false gnss = false -hashlib = false +hashlib = true hostnetwork = false i2cdisplaybus = true # Zephyr board has busio i2cioexpander = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false @@ -117,4 +117,4 @@ watchdog = false wifi = false zephyr_display = false zephyr_kernel = false -zlib = false +zlib = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 51c02dad4cf..84f02c443c6 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index c1d6e2ed3ce..af337d64012 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index b293424b539..79a6b2db70d 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 6d6d5841bbc..c056ef3628d 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index b5d36e61566..fff46155266 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 2c72ba1570d..a729d734fcd 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index d981883bf65..07211ace4fb 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index 191ed9d2d2c..b64fd8756a7 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -2,4 +2,4 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] USB_VID=0x239A USB_PID=0x8168 BLOBS=["nrf_wifi"] -DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib"] +DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib", "jpegio"] diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 8105f7731da..ded7470fce5 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index a23bc81503c..91cf937b426 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index e97292fee76..a9777d2df2c 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index 83b54ae2fa2..5d18f0a2d94 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index 65c5bc003ae..de81c81e876 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index 97288095e00..b3e3065f7ed 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index 18e1fc83565..e455ae541b0 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index 529254cfec2..1c7f0828644 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 7a1c0bfd21e..950ac83726c 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 185859b0807..a7663843003 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 7686dbf320b..4de6204ce4f 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 4037dac0481..15cfe0c52da 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index 1a97bb36163..053e04e6f6b 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 4723617a5a7..2afbdf32ad3 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 749b040b6d4..f5cd5041156 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = true keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 1a559979746..00f236bcf43 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -65,6 +65,7 @@ "hashlib", "zlib", "adafruit_bus_device", + "jpegio", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] @@ -118,6 +119,9 @@ "lib/uzlib/adler32.c", "lib/uzlib/crc32.c", ], + "jpegio": [ + "lib/tjpgd/src/tjpgd.c" + ] } SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os", "rotaryio"] diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/jpegio_test_pattern_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/jpegio_test_pattern_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..4987b76ff8089239f5cf4898c68e5236b6fe02d6 GIT binary patch literal 1241 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fOU3p`yMLn`LHy?e0hv73lP zpk|5lo-_adCw1^Vm^<|`d@N6~ZW$WMD z-MRlmXZpt_T=vTGSnP(o>KZVdi@&SIz5Mwndqc@X( zd#BF%Y*U{9a4CN89Q2%EUVlga@XYq}H_tfdHa)VdsekM_^=kU6J(iOd7zE)~Vg!Vm ziDxV1(o<=4Nmxs66&?(L2~ufpNbf*x=PlRPJg@8nPCI+h;l)2nWj zcDl^hEvLHPP|cA+33o~<0=nk^2UeW%f-oMp#gxiiJN}M$&#lit@9br*h<;xA?%pBq zpG>4DZ*sB(4n41vzq8eqU4LD=<=w}xGh*Lom+ig%cH6go+aK2cpL4goYVXT`dGWK~ zRmLJ%Z3brsW+o;O z0s6Oj-S z5fuR$!pIEN!@|nR%E~Fi%grl7GWdUhL6Cz%gh7OvQILU2kdaxC@&6G9aj^RtkN^h* zCmT@0M1X;TiG`Ds6CowU4s;nKGpDGSWcsovY-;Kzrj9Nt3tiokiy9XneE0#VONx<^ zfr*(Bp@)Him4k(iof9Z$B*?(X#K^|QjgS=-5@uv&6A?{fVi#9bF?0${OlA>Nc63fH zUby(-Z*fV%7K54%~-?i;W!*?2g@Ob65irFI5@$cLD^J(cKZxt{ z&i7x^rn;HkEHzwobwX-j@3vT<45k&wZtE>GVR-MiYft{<2aK~%{_gzBz*uxT|M tuple[int, int, bytes]: + with Image.open(path) as img: + rgb = img.convert("RGB") + return rgb.width, rgb.height, rgb.tobytes() + + +def _golden_compare_or_update(request, captures, golden_path): + if not captures or not captures[0].exists(): + pytest.skip("display capture was not produced") + + if request.config.getoption("--update-goldens"): + golden_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(captures[0], golden_path) + return + + gw, gh, gpx = _read_image(golden_path) + dw, dh, dpx = _read_image(captures[0]) + assert (dw, dh) == (gw, gh) + assert gpx == dpx + + +JPEGIO_DECODE_CODE = """\ +import board +import displayio +import time +from jpegio import JpegDecoder + +decoder = JpegDecoder() +width, height = decoder.open("/test.jpg") +print('size', width, height) + +bitmap = displayio.Bitmap(width, height, 65535) +decoder.decode(bitmap) + +for i in range(min(width, 8)): + print('px', i, hex(bitmap[i, 0])) + +scale = 10 +tg = displayio.TileGrid( + bitmap, + pixel_shader=displayio.ColorConverter( + input_colorspace=displayio.Colorspace.RGB565_SWAPPED + ), +) +g = displayio.Group(scale=scale) +g.x = (board.DISPLAY.width - width * scale) // 2 +g.y = (board.DISPLAY.height - height * scale) // 2 +g.append(tg) + +board.DISPLAY.auto_refresh = False +board.DISPLAY.root_group = g +board.DISPLAY.refresh() +print('rendered') +while True: + time.sleep(1) +""" + + +_JPEGIO_DRIVE = {"code.py": JPEGIO_DECODE_CODE, "test.jpg": _TEST_JPG_BYTES} + + +@pytest.mark.circuitpy_drive(_JPEGIO_DRIVE) +@pytest.mark.display(capture_times_ns=[14_000_000_000]) +@pytest.mark.duration(18) +def test_jpegio_decode(request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 20 20" in output + assert "rendered" in output + + golden = Path(__file__).parent / "golden" / "jpegio_test_pattern_320x240.png" + _golden_compare_or_update(request, circuitpython.display_capture_paths(), golden) diff --git a/shared-bindings/jpegio/JpegDecoder.c b/shared-bindings/jpegio/JpegDecoder.c index ad2a0622e7a..752d80b4733 100644 --- a/shared-bindings/jpegio/JpegDecoder.c +++ b/shared-bindings/jpegio/JpegDecoder.c @@ -23,13 +23,18 @@ //| Example:: //| //| from jpegio import JpegDecoder -//| from displayio import Bitmap +//| from displayio import Bitmap, TileGrid, ColorConverter, Colorspace +//| import supervisor //| //| decoder = JpegDecoder() //| width, height = decoder.open("/sd/example.jpg") //| bitmap = Bitmap(width, height, 65535) //| decoder.decode(bitmap) -//| # .. do something with bitmap +//| tg = TileGrid(bitmap, pixel_shader=ColorConverter(input_colorspace=Colorspace.RGB565_SWAPPED)) +//| supervisor.runtime.display.root_group = tg +//| while True: +//| pass +//| //| """ //| //| def __init__(self) -> None: From b7a29b5cfff6da983c9c675a5752fb5e6b08a505 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 16 Apr 2026 11:40:49 -0700 Subject: [PATCH 414/876] Import: .py module wins over namespace-package dir (#10614) When both `foo/` (no __init__.py) and `foo.py` existed on the filesystem, `import foo` silently imported the empty namespace package and skipped `foo.py`. CPython picks the `.py` in this case, and the docs define that precedence: regular package > module > namespace package. stat_module now probes for `__init__.py`/`.mpy` inside the directory first, then falls back to `.py`/`.mpy`, and only treats the bare directory as a namespace package when neither exists. Adds a native_sim regression test and extends the test harness so `circuitpy_drive` can include files inside subdirectories. Co-Authored-By: Claude Opus 4.7 (1M context) --- ports/zephyr-cp/tests/conftest.py | 10 ++++++++++ ports/zephyr-cp/tests/test_basics.py | 22 ++++++++++++++++++++++ py/builtinimport.c | 21 ++++++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index 03451048324..321bb8ae773 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -289,12 +289,22 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp tmp_drive = tmp_path / f"drive{i}" tmp_drive.mkdir(exist_ok=True) + created_dirs: set[str] = set() for name, content in files.items(): src = tmp_drive / name + src.parent.mkdir(parents=True, exist_ok=True) if isinstance(content, bytes): src.write_bytes(content) else: src.write_text(content) + parent = Path(name).parent + if parent != Path("."): + parts = parent.parts + for depth in range(1, len(parts) + 1): + sub = "/".join(parts[:depth]) + if sub not in created_dirs: + subprocess.run(["mmd", "-i", str(flash), f"::{sub}"], check=True) + created_dirs.add(sub) subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) trace_file = tmp_path / f"trace-{i}.perfetto" diff --git a/ports/zephyr-cp/tests/test_basics.py b/ports/zephyr-cp/tests/test_basics.py index 84b31849a8e..7247f375f15 100644 --- a/ports/zephyr-cp/tests/test_basics.py +++ b/ports/zephyr-cp/tests/test_basics.py @@ -92,6 +92,28 @@ def test_ctrl_c_interrupt(circuitpython): assert "completed" not in output +IMPORT_PRECEDENCE_CODE = """\ +import fake_lib +print("done") +""" + + +@pytest.mark.circuitpy_drive( + { + "code.py": IMPORT_PRECEDENCE_CODE, + "fake_lib/a_spritesheet.bmp": b"", + "fake_lib.py": 'print("hello fake_lib.py")\n', + } +) +def test_py_file_wins_over_namespace_dir(circuitpython): + """#10614: a .py module beats a sibling directory lacking __init__.py.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "hello fake_lib.py" in output + assert "done" in output + + RELOAD_CODE = """\ print("first run") import time diff --git a/py/builtinimport.c b/py/builtinimport.c index 8fcac22ccb4..5d77ac42859 100644 --- a/py/builtinimport.c +++ b/py/builtinimport.c @@ -105,7 +105,26 @@ static mp_import_stat_t stat_module(vstr_t *path) { mp_import_stat_t stat = stat_path(path); DEBUG_printf("stat %s: %d\n", vstr_str(path), stat); if (stat == MP_IMPORT_STAT_DIR) { - return stat; + // CIRCUITPY-CHANGE: match CPython import precedence. A regular + // package (directory with __init__.py/.mpy) takes precedence, then a + // sibling .py/.mpy module, and only then a namespace package + // (directory without __init__). See + // https://docs.python.org/3/reference/import.html#regular-packages + size_t orig_len = path->len; + vstr_add_str(path, PATH_SEP_CHAR "__init__.py"); + mp_import_stat_t init_stat = stat_file_py_or_mpy(path); + path->len = orig_len; + if (init_stat == MP_IMPORT_STAT_FILE) { + return MP_IMPORT_STAT_DIR; + } + + vstr_add_str(path, ".py"); + mp_import_stat_t file_stat = stat_file_py_or_mpy(path); + if (file_stat == MP_IMPORT_STAT_FILE) { + return file_stat; + } + path->len = orig_len; + return MP_IMPORT_STAT_DIR; } // Not a directory, add .py and try as a file. From 68a18ac59c007a3391bae95f2f92dd9d0e9ed141 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 16 Apr 2026 16:14:00 -0500 Subject: [PATCH 415/876] code format --- ports/zephyr-cp/cptools/build_circuitpython.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 00f236bcf43..4d964ed1eb5 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -119,9 +119,7 @@ "lib/uzlib/adler32.c", "lib/uzlib/crc32.c", ], - "jpegio": [ - "lib/tjpgd/src/tjpgd.c" - ] + "jpegio": ["lib/tjpgd/src/tjpgd.c"], } SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os", "rotaryio"] From 7150aa686ecf285dc6c4a7b6a5cac3339092f3e1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 17 Apr 2026 12:06:35 -0500 Subject: [PATCH 416/876] disable jpegio on zephyr nrf54h20dk --- .../zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml | 2 +- ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index c7c014955f7..9b4d9933697 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = false keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml index 3272dd4c5f3..f2a988e42ec 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml @@ -1 +1,2 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +DISABLED_MODULES=["jpegio"] \ No newline at end of file From 990a5b682e1383cdd608c2da0e281057eade3c06 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 17 Apr 2026 12:07:20 -0500 Subject: [PATCH 417/876] disable jpegio on zephyr nrf54h20dk, fix eof newline --- ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml index f2a988e42ec..010ae9953e4 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml @@ -1,2 +1,2 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] -DISABLED_MODULES=["jpegio"] \ No newline at end of file +DISABLED_MODULES=["jpegio"] From 12fbcd8924df0188337af9d99fbe588beffd3232 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 18 Apr 2026 16:43:00 -0400 Subject: [PATCH 418/876] shared-module/sdcardio/SDCard.c: revert cmd timeout to 500 ms --- shared-module/sdcardio/SDCard.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index 5d3c021f27e..3630e4ea167 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -28,7 +28,9 @@ // https://www.taterli.com/wp-content/uploads/2017/05/Physical-Layer-Simplified-SpecificationV6.0.pdf // specifies timeouts for read (100 ms), write (250 ms), erase (depends on size), and other operations. -#define CMD_TIMEOUT_MS (250) +// cmd timeout was 250, but did not work on some cards. +// See https://github.com/adafruit/circuitpython/issues/10954 +#define CMD_TIMEOUT_MS (500) #define SPI_TIMEOUT_MS (250) // Init ready timeout. #define READY_TIMEOUT_MS (300) From 2fd4bce95c6f5a90f1374dc4c54be2abcb14d65e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 20 Apr 2026 11:48:49 -0700 Subject: [PATCH 419/876] Switch to a micropython test --- ports/zephyr-cp/tests/conftest.py | 10 ---------- ports/zephyr-cp/tests/test_basics.py | 22 ---------------------- tests/import/import_shared_name.py | 7 +++++++ tests/import/shared_name.py | 1 + tests/import/shared_name/spritesheet.bmp | 0 5 files changed, 8 insertions(+), 32 deletions(-) create mode 100644 tests/import/import_shared_name.py create mode 100644 tests/import/shared_name.py create mode 100644 tests/import/shared_name/spritesheet.bmp diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index 321bb8ae773..03451048324 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -289,22 +289,12 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp tmp_drive = tmp_path / f"drive{i}" tmp_drive.mkdir(exist_ok=True) - created_dirs: set[str] = set() for name, content in files.items(): src = tmp_drive / name - src.parent.mkdir(parents=True, exist_ok=True) if isinstance(content, bytes): src.write_bytes(content) else: src.write_text(content) - parent = Path(name).parent - if parent != Path("."): - parts = parent.parts - for depth in range(1, len(parts) + 1): - sub = "/".join(parts[:depth]) - if sub not in created_dirs: - subprocess.run(["mmd", "-i", str(flash), f"::{sub}"], check=True) - created_dirs.add(sub) subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) trace_file = tmp_path / f"trace-{i}.perfetto" diff --git a/ports/zephyr-cp/tests/test_basics.py b/ports/zephyr-cp/tests/test_basics.py index 7247f375f15..84b31849a8e 100644 --- a/ports/zephyr-cp/tests/test_basics.py +++ b/ports/zephyr-cp/tests/test_basics.py @@ -92,28 +92,6 @@ def test_ctrl_c_interrupt(circuitpython): assert "completed" not in output -IMPORT_PRECEDENCE_CODE = """\ -import fake_lib -print("done") -""" - - -@pytest.mark.circuitpy_drive( - { - "code.py": IMPORT_PRECEDENCE_CODE, - "fake_lib/a_spritesheet.bmp": b"", - "fake_lib.py": 'print("hello fake_lib.py")\n', - } -) -def test_py_file_wins_over_namespace_dir(circuitpython): - """#10614: a .py module beats a sibling directory lacking __init__.py.""" - circuitpython.wait_until_done() - - output = circuitpython.serial.all_output - assert "hello fake_lib.py" in output - assert "done" in output - - RELOAD_CODE = """\ print("first run") import time diff --git a/tests/import/import_shared_name.py b/tests/import/import_shared_name.py new file mode 100644 index 00000000000..b76695f671e --- /dev/null +++ b/tests/import/import_shared_name.py @@ -0,0 +1,7 @@ +# https://github.com/adafruit/circuitpython/issues/10614 +# When a directory `shared_name/` (no __init__.py) and a module `shared_name.py` +# share a name, `import shared_name` must pick the .py module per PEP 420 +# precedence: regular package > module > namespace package. +import shared_name + +print("done") diff --git a/tests/import/shared_name.py b/tests/import/shared_name.py new file mode 100644 index 00000000000..0ba98242ed9 --- /dev/null +++ b/tests/import/shared_name.py @@ -0,0 +1 @@ +print("hello shared_name.py") diff --git a/tests/import/shared_name/spritesheet.bmp b/tests/import/shared_name/spritesheet.bmp new file mode 100644 index 00000000000..e69de29bb2d From 6b089ab6f5a4fa348e9f3feedc87a385ada41617 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 21 Apr 2026 08:41:44 -0500 Subject: [PATCH 420/876] fix flash size on zephyr feather rp2040 --- ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay index ce9083dd62d..af7295ffe35 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay +++ b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay @@ -26,7 +26,7 @@ circuitpy_partition: partition@181000 { label = "circuitpy"; - reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; + reg = <0x181000 (DT_SIZE_M(8) - 0x181000)>; }; }; }; From bfb650d199790d620144ca15362652915a3eeadc Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 21 Apr 2026 07:23:39 -0700 Subject: [PATCH 421/876] =?UTF-8?q?Revert=20"docs(sdcardio):=20clarify=20S?= =?UTF-8?q?D-first=20init=20rule=20for=20boards=20with=20floating=20C?= =?UTF-8?q?=E2=80=A6"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- shared-bindings/sdcardio/SDCard.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index 9a04cea57e5..2802499956c 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -43,13 +43,6 @@ //| Failure to do so can prevent the SD card from being recognized until it is //| powered off or re-inserted. //| -//| Exception: on boards where another SPI peripheral has a floating CS -//| pin with no hardware pull-up (such as the Feather RP2040 RFM), that -//| peripheral's CS must be driven HIGH before SD card initialization. -//| Failure to do so will corrupt the SPI bus during SD card init. In -//| these cases, initialize and drive the other peripheral's CS high -//| first, then initialize the SD card. -//| //| Example usage: //| //| .. code-block:: python From d06079ed1fa30a55d2509bdd214f2a84ae86d16c Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 21 Apr 2026 07:28:24 -0700 Subject: [PATCH 422/876] docs(sdcardio): describe the real shared-SPI CS invariant The previous ".. important::" note said SD card init must come first on a shared SPI bus. That rule happened to work when every co-resident CS line had a hardware pull-up, but it is not the real invariant: what actually matters is that every CS on the shared bus is in a known HIGH (deselected) state before any SPI transaction. On boards where a CS floats (e.g. the Feather RP2040 RFM, whose RFM_CS has no pull-up), it must be driven HIGH in software; init order is secondary. --- shared-bindings/sdcardio/SDCard.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index 2802499956c..aa1fecd85f3 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -38,10 +38,18 @@ //| the microcontroller) //| //| .. important:: -//| If the same SPI bus is shared with other peripherals, it is important that -//| the SD card be initialized before accessing any other peripheral on the bus. -//| Failure to do so can prevent the SD card from being recognized until it is -//| powered off or re-inserted. +//| When the SPI bus is shared with other peripherals, every CS pin on +//| the bus must be in a known HIGH (deselected) state before any SPI +//| transaction occurs. This is normally guaranteed by a hardware +//| pull-up on each CS line, but on boards where a co-resident +//| peripheral's CS floats (for example the Feather RP2040 RFM, whose +//| ``RFM_CS`` has no pull-up), that CS must be driven HIGH in +//| software before the SD card is initialized. If any CS is allowed +//| to float low, the SPI bus can be corrupted during SD card init +//| and the card may not be recognized until it is powered off or +//| re-inserted. The order in which peripherals are constructed is +//| secondary; what matters is that all CS lines are deselected +//| before any SPI transaction. //| //| Example usage: //| From 710b77b975d0fc0ad635d0b90cfe88a3ce12c582 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 21 Apr 2026 07:48:03 -0700 Subject: [PATCH 423/876] Update shared-bindings/sdcardio/SDCard.c Co-authored-by: Dan Halbert --- shared-bindings/sdcardio/SDCard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index aa1fecd85f3..79f0a83b8cf 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -48,7 +48,7 @@ //| to float low, the SPI bus can be corrupted during SD card init //| and the card may not be recognized until it is powered off or //| re-inserted. The order in which peripherals are constructed is -//| secondary; what matters is that all CS lines are deselected +//| secondary; what matters is that all CS lines are HIGH (deselected) //| before any SPI transaction. //| //| Example usage: From f826c05e1cfa4586be7ca804a472d5c602fa9039 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 21 Apr 2026 12:15:11 -0500 Subject: [PATCH 424/876] enable gifio and storage in zephyr port --- .../adafruit/feather_rp2040_zephyr/autogen_board_info.toml | 4 ++-- ports/zephyr-cp/cptools/build_circuitpython.py | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index 54c1d4d578f..49f03267e01 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true gnss = false hashlib = true hostnetwork = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 7f3a012064f..01fbd0e0207 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -66,6 +66,8 @@ "zlib", "adafruit_bus_device", "getpass", + "storage", + "gifio", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] @@ -119,6 +121,9 @@ "lib/uzlib/adler32.c", "lib/uzlib/crc32.c", ], + "gifio": [ + "lib/AnimatedGIF/gif.c" + ] } SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os", "rotaryio"] From 31aab5faeca30d979938ed60def7069750758703 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 21 Apr 2026 17:18:18 -0400 Subject: [PATCH 425/876] add background callbacks more carefully; remove improper clearing of callback state --- supervisor/shared/background_callback.c | 21 +++++++++++++++++---- supervisor/shared/workflow.c | 2 -- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c index ffeb78bbb83..224226d6a93 100644 --- a/supervisor/shared/background_callback.c +++ b/supervisor/shared/background_callback.c @@ -14,7 +14,9 @@ #include "supervisor/shared/tick.h" #include "shared-bindings/microcontroller/__init__.h" -static volatile background_callback_t *volatile callback_head, *volatile callback_tail; +static volatile background_callback_t *volatile callback_head = NULL; +static volatile background_callback_t *volatile callback_tail = NULL; +; #ifndef CALLBACK_CRITICAL_BEGIN #define CALLBACK_CRITICAL_BEGIN (common_hal_mcu_disable_interrupts()) @@ -28,15 +30,26 @@ MP_WEAK void PLACE_IN_ITCM(port_wake_main_task)(void) { void PLACE_IN_ITCM(background_callback_add_core)(background_callback_t * cb) { CALLBACK_CRITICAL_BEGIN; - if (cb->prev || callback_head == cb) { - CALLBACK_CRITICAL_END; - return; + // next_callback_on_list is volatile only to match callback_head declaration. + volatile background_callback_t *next_callback_on_list = callback_head; + // Add cb only if it is not already on the callback list. + while (next_callback_on_list) { + if (cb == next_callback_on_list) { + // Already on the list. Don't add. + CALLBACK_CRITICAL_END; + return; + } + next_callback_on_list = next_callback_on_list->next; } + + // Add the cb to the end of the list. cb->next = 0; cb->prev = (background_callback_t *)callback_tail; if (callback_tail) { callback_tail->next = cb; } + + // If the callback list was empty, record that cb is the first item. if (!callback_head) { callback_head = cb; } diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index 7370e34e860..890db0949d1 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -45,7 +45,6 @@ void supervisor_workflow_reset(void) { bool result = supervisor_start_web_workflow(); if (result) { if (!workflow_background_cb.fun) { - memset(&workflow_background_cb, 0, sizeof(workflow_background_cb)); workflow_background_cb.fun = supervisor_web_workflow_background; } supervisor_workflow_request_background(); @@ -108,7 +107,6 @@ void supervisor_workflow_start(void) { #if CIRCUITPY_WEB_WORKFLOW if (supervisor_start_web_workflow()) { // Enable background callbacks if web_workflow startup successful. - memset(&workflow_background_cb, 0, sizeof(workflow_background_cb)); workflow_background_cb.fun = supervisor_web_workflow_background; // Kick the first background run now that the callback is installed. supervisor_workflow_request_background(); From ed14186269a70489a7285de953b98d87f81f17ad Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 21 Apr 2026 22:35:26 -0400 Subject: [PATCH 426/876] undo background_callback.c changes --- supervisor/shared/background_callback.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/supervisor/shared/background_callback.c b/supervisor/shared/background_callback.c index 224226d6a93..ffeb78bbb83 100644 --- a/supervisor/shared/background_callback.c +++ b/supervisor/shared/background_callback.c @@ -14,9 +14,7 @@ #include "supervisor/shared/tick.h" #include "shared-bindings/microcontroller/__init__.h" -static volatile background_callback_t *volatile callback_head = NULL; -static volatile background_callback_t *volatile callback_tail = NULL; -; +static volatile background_callback_t *volatile callback_head, *volatile callback_tail; #ifndef CALLBACK_CRITICAL_BEGIN #define CALLBACK_CRITICAL_BEGIN (common_hal_mcu_disable_interrupts()) @@ -30,26 +28,15 @@ MP_WEAK void PLACE_IN_ITCM(port_wake_main_task)(void) { void PLACE_IN_ITCM(background_callback_add_core)(background_callback_t * cb) { CALLBACK_CRITICAL_BEGIN; - // next_callback_on_list is volatile only to match callback_head declaration. - volatile background_callback_t *next_callback_on_list = callback_head; - // Add cb only if it is not already on the callback list. - while (next_callback_on_list) { - if (cb == next_callback_on_list) { - // Already on the list. Don't add. - CALLBACK_CRITICAL_END; - return; - } - next_callback_on_list = next_callback_on_list->next; + if (cb->prev || callback_head == cb) { + CALLBACK_CRITICAL_END; + return; } - - // Add the cb to the end of the list. cb->next = 0; cb->prev = (background_callback_t *)callback_tail; if (callback_tail) { callback_tail->next = cb; } - - // If the callback list was empty, record that cb is the first item. if (!callback_head) { callback_head = cb; } From a5d1ac55b9da15371cd2fe40d7054d878a35fa9d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 22 Apr 2026 07:14:17 -0400 Subject: [PATCH 427/876] innocuous change to force a rebuild --- supervisor/shared/workflow.c | 1 + 1 file changed, 1 insertion(+) diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index 890db0949d1..09ed8ab2226 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -45,6 +45,7 @@ void supervisor_workflow_reset(void) { bool result = supervisor_start_web_workflow(); if (result) { if (!workflow_background_cb.fun) { + // Enable background callbacks if web_workflow startup successful. workflow_background_cb.fun = supervisor_web_workflow_background; } supervisor_workflow_request_background(); From b12c140a92ffd5b3b4db8998370335ac4e28c2ad Mon Sep 17 00:00:00 2001 From: mikeysklar Date: Tue, 21 Apr 2026 12:28:46 -0700 Subject: [PATCH 428/876] shared/filesystem: mount SD at filesystem_init for reliable MSC probe The lazy automount in tud_msc_test_unit_ready_cb can lose races with macOS's USB MSC probe timing -- the host asks whether LUN 1 is ready before the card has finished mounting, sees NOT_READY, and may give up before trying again. Mounting during filesystem_init ensures the SD card is live by the time USB enumerates, so the first probe succeeds. Affects boards that define DEFAULT_SD_CARD_DETECT; behavior on boards without an auto-mount path is unchanged. --- supervisor/shared/filesystem.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index eb4b6548d11..55fef541a67 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -219,6 +219,13 @@ bool filesystem_init(bool create_allowed, bool force_create) { #if CIRCUITPY_SDCARDIO sdcardio_init(); + #if defined(DEFAULT_SD_CARD_DETECT) && CIRCUITPY_SDCARD_USB + // Mount the SD card now so it's ready when USB enumerates. + // Lazy mount from tud_msc_test_unit_ready_cb can lose races with + // macOS's probe timing. Gated on CIRCUITPY_SDCARD_USB to match the + // existing call site in usb_msc_flash.c (guarded by SDCARD_LUN). + automount_sd_card(); + #endif #endif return true; From 060019fa60c46eaf4c76334aa07750b8861b1805 Mon Sep 17 00:00:00 2001 From: mikeysklar Date: Wed, 22 Apr 2026 16:45:15 -0700 Subject: [PATCH 429/876] shared/usb: per-LUN response to PREVENT_ALLOW_MEDIUM_REMOVAL Respond with "unsupported" for the SD LUN (removable media) and OK for internal flash / SAVES LUNs (non-removable). Responding OK for a removable LUN tells macOS the medium is always present, and macOS then skips TEST_UNIT_READY polling. If the SD isn't ready at the single enumeration probe, macOS never re-checks and LUN 1 fails to publish an IOMedia node. Hathach documented this behavior back in #6555; the SD case wasn't differentiated at the time. Fixes #10965. --- supervisor/shared/usb/usb_msc_flash.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index 5ea457ef328..f394040b74a 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -214,8 +214,22 @@ int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, u switch (scsi_cmd[0]) { case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - // Host is about to read/write etc ... better not to disconnect disk - resplen = 0; + #ifdef SDCARD_LUN + if (lun == SDCARD_LUN) { + // Removable media (SD card). Respond "unsupported" so macOS + // keeps sending TEST_UNIT_READY periodically to detect card + // insertion/removal. Responding OK here causes macOS to skip + // TUR polling and miss media-present events on the SD LUN. + // See the discussion in adafruit/circuitpython#6555. + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + resplen = -1; + } else + #endif + { + // Non-removable media (internal flash, SAVES). OK is fine; + // host assumes medium always present and skips TUR polling. + resplen = 0; + } break; default: From 9f21387297410a918a207cec3f36fa6b5b4222dc Mon Sep 17 00:00:00 2001 From: mikeysklar Date: Wed, 22 Apr 2026 16:46:10 -0700 Subject: [PATCH 430/876] raspberrypi/boards: add DEFAULT_SD_* for Metro RP2040 and Feather RP2040 Adalogger Both boards have onboard microSD slots but were missing the DEFAULT_SD_* pin defines that enable CircuitPython's native SD automount. Without these, SD-over-USB-MSC only worked via user boot.py code and hit the heap-mount race in get_vfs(). Pin wiring verified on hardware against the board schematics; CD pin polarity (DEFAULT_SD_CARD_INSERTED=true) confirmed by runtime test. Companion to #10963 (automount at filesystem init) and #NNNN (per-LUN PREVENT_ALLOW response). Fixes the last mile for #10965. --- .../adafruit_feather_rp2040_adalogger/mpconfigboard.h | 8 ++++++++ .../boards/adafruit_metro_rp2040/mpconfigboard.h | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.h index 34360169423..4c500366dfc 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.h @@ -23,3 +23,11 @@ // #define CIRCUITPY_CONSOLE_UART_RX DEFAULT_UART_BUS_RX // #define CIRCUITPY_CONSOLE_UART_TX DEFAULT_UART_BUS_TX + +// Onboard microSD slot on SPI1. +#define DEFAULT_SD_SCK (&pin_GPIO18) +#define DEFAULT_SD_MOSI (&pin_GPIO19) +#define DEFAULT_SD_MISO (&pin_GPIO20) +#define DEFAULT_SD_CS (&pin_GPIO23) +#define DEFAULT_SD_CARD_DETECT (&pin_GPIO16) +#define DEFAULT_SD_CARD_INSERTED true diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.h index 4242599354c..fdbd18c0e66 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.h @@ -20,3 +20,11 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO1) #define DEFAULT_UART_BUS_TX (&pin_GPIO0) + +// Onboard microSD slot. +#define DEFAULT_SD_SCK (&pin_GPIO18) +#define DEFAULT_SD_MOSI (&pin_GPIO19) +#define DEFAULT_SD_MISO (&pin_GPIO20) +#define DEFAULT_SD_CS (&pin_GPIO23) +#define DEFAULT_SD_CARD_DETECT (&pin_GPIO15) +#define DEFAULT_SD_CARD_INSERTED true From 2bb188cf44a006c8824a01972dd1e51bd78d0fbf Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 23 Apr 2026 09:18:16 -0500 Subject: [PATCH 431/876] move gifio and jpegio to depend on displayio. Build all boards. add tests for gifio and storage. --- .../autogen_board_info.toml | 4 +- .../autogen_board_info.toml | 4 +- .../autogen_board_info.toml | 4 +- .../native/native_sim/autogen_board_info.toml | 4 +- .../nrf5340bsim/autogen_board_info.toml | 6 +- .../nordic/nrf5340dk/autogen_board_info.toml | 4 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 6 +- .../nordic/nrf54h20dk/circuitpython.toml | 2 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 4 +- .../nordic/nrf7002dk/autogen_board_info.toml | 6 +- .../nordic/nrf7002dk/circuitpython.toml | 2 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 4 +- .../nxp/frdm_rw612/autogen_board_info.toml | 6 +- .../mimxrt1170_evk/autogen_board_info.toml | 6 +- .../autogen_board_info.toml | 6 +- .../rpi_pico2_zephyr/autogen_board_info.toml | 6 +- .../rpi_pico_w_zephyr/autogen_board_info.toml | 6 +- .../rpi_pico_zephyr/autogen_board_info.toml | 6 +- .../da14695_dk_usb/autogen_board_info.toml | 6 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 4 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 4 +- .../nucleo_n657x0_q/autogen_board_info.toml | 6 +- .../nucleo_u575zi_q/autogen_board_info.toml | 6 +- .../st/stm32h750b_dk/autogen_board_info.toml | 4 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 4 +- .../stm32wba65i_dk1/autogen_board_info.toml | 6 +- .../zephyr-cp/cptools/build_circuitpython.py | 8 +- ports/zephyr-cp/tests/test_storage.py | 162 ++++++++++++++ .../golden/gifio_frame_00_320x240.png | Bin 0 -> 866 bytes .../golden/gifio_frame_01_320x240.png | Bin 0 -> 1133 bytes .../golden/gifio_frame_02_320x240.png | Bin 0 -> 1150 bytes .../golden/gifio_frame_03_320x240.png | Bin 0 -> 1226 bytes .../golden/gifio_frame_04_320x240.png | Bin 0 -> 1235 bytes .../golden/gifio_frame_05_320x240.png | Bin 0 -> 1248 bytes .../golden/gifio_frame_06_320x240.png | Bin 0 -> 1257 bytes .../golden/gifio_frame_07_320x240.png | Bin 0 -> 1248 bytes .../golden/gifio_frame_08_320x240.png | Bin 0 -> 1235 bytes .../golden/gifio_frame_09_320x240.png | Bin 0 -> 1226 bytes .../golden/gifio_frame_10_320x240.png | Bin 0 -> 1150 bytes .../golden/gifio_frame_11_320x240.png | Bin 0 -> 1133 bytes .../golden/gifio_frame_12_320x240.png | Bin 0 -> 866 bytes ports/zephyr-cp/tests/zephyr_display/test.gif | Bin 0 -> 2760 bytes .../tests/zephyr_display/test_gifio.py | 201 ++++++++++++++++++ 43 files changed, 429 insertions(+), 68 deletions(-) create mode 100644 ports/zephyr-cp/tests/test_storage.py create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_00_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_01_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_02_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_03_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_04_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_05_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_06_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_07_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_08_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_09_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_10_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_11_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_12_320x240.png create mode 100644 ports/zephyr-cp/tests/zephyr_display/test.gif create mode 100644 ports/zephyr-cp/tests/zephyr_display/test_gifio.py diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml index 69896f950b5..d6aca312226 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 8cd4a71e3fe..dafe7811779 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index c55736a11a6..cecf8e55a83 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = true +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 9ad5fa7849d..4cc9f3e934c 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true # Zephyr networking enabled hostnetwork = true # Zephyr board has hostnetwork @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 19432b2dc1b..aa723b53f64 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 8f7bdba94bd..ee20efa6fee 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 9b4d9933697..ca2c90ceb0b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = false # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = false +jpegio = false # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -99,7 +99,7 @@ struct = true supervisor = true synthio = false terminalio = true # Zephyr board has busio -tilepalettemapper = true # Zephyr board has busio +tilepalettemapper = false # Zephyr board has busio time = true touchio = false traceback = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml index 010ae9953e4..415c471b3d4 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml @@ -1,2 +1,2 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] -DISABLED_MODULES=["jpegio"] +DISABLED_MODULES=["jpegio", "gifio", "tilepalettemapper"] diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index e13fba484b8..69fdc2da903 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 54e2b89d638..e0b759e01ce 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = false # Zephyr board has busio gnss = false hashlib = true # Zephyr networking enabled hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = false +jpegio = false # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -99,7 +99,7 @@ struct = true supervisor = true synthio = false terminalio = true # Zephyr board has busio -tilepalettemapper = true # Zephyr board has busio +tilepalettemapper = false # Zephyr board has busio time = true touchio = false traceback = true diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index b64fd8756a7..761d2631477 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -2,4 +2,4 @@ CIRCUITPY_BUILD_EXTENSIONS = ["elf"] USB_VID=0x239A USB_PID=0x8168 BLOBS=["nrf_wifi"] -DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib", "jpegio"] +DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib", "jpegio", "tilepalettemapper", "gifio"] diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index d4f903e5158..b8e2c0601aa 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 659089d20ad..557b4f0448f 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true # Zephyr networking enabled hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = true # Zephyr networking enabled spitarget = false ssl = true # Zephyr networking enabled -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index a5f343c7691..ee43ef86e8c 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = true # Zephyr board has audiobusio diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index ba59347f21e..2215bcf4135 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true # Zephyr networking enabled hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = true # Zephyr networking enabled spitarget = false ssl = true # Zephyr networking enabled -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index 138f7f14e4d..61324042092 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index f0b10b59783..203f5fd7048 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true # Zephyr networking enabled hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = true # Zephyr networking enabled is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = true # Zephyr networking enabled spitarget = false ssl = true # Zephyr networking enabled -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index 647d9ee9ac3..13c77bf2928 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index f4d6dee7f8a..e596ea1aebc 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index ff95cc49b42..7751ec96715 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 41d89235242..42bef11db0c 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 5611f62e33e..7ad9c4f2111 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 2ad6616e2ba..2796f76782f 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index ba7593fbc33..2d5385d90b2 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 1cd4ca1a87f..7f158d6f278 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 9751aea8fc6..19141f30065 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -48,7 +48,7 @@ fourwire = true # Zephyr board has busio framebufferio = true # Zephyr board has busio frequencyio = false getpass = true -gifio = false +gifio = true # Zephyr board has busio gnss = false hashlib = true hostnetwork = false @@ -58,7 +58,7 @@ i2ctarget = false imagecapture = false ipaddress = false is31fl3741 = false -jpegio = true +jpegio = true # Zephyr board has busio keypad = false keypad_demux = false locale = false @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = false spitarget = false ssl = false -storage = false +storage = true struct = true supervisor = true synthio = false diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 9c5885b4f93..0a37ad15938 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -66,9 +66,7 @@ "zlib", "adafruit_bus_device", "getpass", - "jpegio", "storage", - "gifio", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] @@ -98,6 +96,8 @@ "lvfontio", "tilepalettemapper", "fontio", + "gifio", + "jpegio", ], "sharpdisplay": ["framebufferio"], "framebufferio": ["displayio"], @@ -123,9 +123,7 @@ "lib/uzlib/crc32.c", ], "jpegio": ["lib/tjpgd/src/tjpgd.c"], - "gifio": [ - "lib/AnimatedGIF/gif.c" - ] + "gifio": ["lib/AnimatedGIF/gif.c"], } SHARED_MODULE_AND_COMMON_HAL = ["_bleio", "os", "rotaryio"] diff --git a/ports/zephyr-cp/tests/test_storage.py b/ports/zephyr-cp/tests/test_storage.py new file mode 100644 index 00000000000..33e63e5ea85 --- /dev/null +++ b/ports/zephyr-cp/tests/test_storage.py @@ -0,0 +1,162 @@ +# SPDX-FileCopyrightText: 2026 Tim Cocks for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test the `storage` core module on native_sim.""" + +import pytest + + +REMOUNT_READWRITE_CODE = """\ +import storage +storage.remount("/", readonly=False) +with open("/rw.txt", "w") as f: + f.write("writable") +with open("/rw.txt", "r") as f: + print(f"content: {f.read()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": REMOUNT_READWRITE_CODE}) +def test_storage_remount_readwrite(circuitpython): + """remount with readonly=False allows writes to /.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "content: writable" in output + assert "done" in output + + +REMOUNT_READONLY_CODE = """\ +import storage +storage.remount("/", readonly=True) +try: + with open("/should_fail.txt", "w") as f: + f.write("nope") + print("unexpected: write succeeded") +except OSError as e: + print(f"caught OSError: errno={e.errno}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": REMOUNT_READONLY_CODE}) +def test_storage_remount_readonly_blocks_writes(circuitpython): + """remount with readonly=True prevents writes to /.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "caught OSError" in output + assert "unexpected: write succeeded" not in output + assert "done" in output + + +GETMOUNT_CODE = """\ +import storage +mount = storage.getmount("/") +print(f"type: {type(mount).__name__}") +print(f"readonly: {mount.readonly}") +# label attribute should be accessible +print(f"label: {mount.label!r}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": GETMOUNT_CODE}) +def test_storage_getmount(circuitpython): + """getmount('/') returns the VfsFat object for the root mount.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "type: VfsFat" in output + assert "readonly:" in output + assert "label:" in output + assert "done" in output + + +GETMOUNT_MISSING_CODE = """\ +import storage +try: + storage.getmount("/does_not_exist") + print("unexpected: getmount succeeded") +except OSError as e: + print(f"caught OSError: errno={e.errno}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": GETMOUNT_MISSING_CODE}) +def test_storage_getmount_missing(circuitpython): + """getmount on an unmounted path raises OSError.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "caught OSError" in output + assert "unexpected: getmount succeeded" not in output + assert "done" in output + + +REMOUNT_PERSISTS_CODE = """\ +import storage +storage.remount("/", readonly=False) +with open("/persist.txt", "w") as f: + f.write("across-reload") +print("wrote persist.txt") +""" + +REMOUNT_PERSISTS_READ_CODE = """\ +with open("/persist.txt", "r") as f: + print(f"readback: {f.read()}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": REMOUNT_PERSISTS_CODE}) +@pytest.mark.code_py_runs(2) +def test_storage_remount_persists_across_reload(circuitpython): + """Data written after remount(readonly=False) persists across soft reload.""" + circuitpython.serial.wait_for("wrote persist.txt") + # Replace code.py via raw REPL-style approach: write new file then reload. + # Simpler: just trigger a soft reload and check the file is still there. + circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "wrote persist.txt" in output + + +LABEL_CODE = """\ +import storage +storage.remount("/", readonly=False) +mount = storage.getmount("/") +mount.label = "CIRCUITPY" +print(f"label: {mount.label!r}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": LABEL_CODE}) +def test_storage_set_label(circuitpython): + """VfsFat.label can be set when mounted read-write.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "label: 'CIRCUITPY'" in output + assert "done" in output + + +UMOUNT_MISSING_CODE = """\ +import storage +# Unmounting an unmounted path should raise. +try: + storage.umount("/not_mounted") + print("unexpected: umount succeeded") +except OSError as e: + print(f"umount OSError: errno={e.errno}") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": UMOUNT_MISSING_CODE}) +def test_storage_umount_missing(circuitpython): + """umount on an unmounted path raises OSError.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + assert "umount OSError" in output + assert "unexpected:" not in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_00_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_00_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..8f7fc051365c0a05abbbc3d845af514f64a53c9b GIT binary patch literal 866 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fQKnw~C>Ar*7pUNK~3P~bVR zp|SqFLbAIs>)xugXS@yf=O#*reaFd=o6Ga3dXF&)T<#xmWHkDBli Qn0FXFUHx3vIVCg!07p~czyJUM literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_01_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_01_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..67d17856c7dcadabab72fa630aa8c68d0dba31a0 GIT binary patch literal 1133 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fOUCY~;iAr*7p-rblN>?q)H z(bVf^Ro&CsYrUrtqoEyHgszkSvBOS@h_{(nfq%t65irz=jYo|sxWv*!Db=K}vf znEibB^-%ry&rfzg=l*{;a=+UB+WW;E=hB$*`GzmK=khB>t~j;(Yj=IvvE^p>#K_fp zHhO1|o+#bO$P~%Mk;17kLAAkQ8Uq?f&(UnxxBSq8*dpJC_JYtm}h;&srp{3e5AJN~2|S*q_AQ?Y>^ zui;OHS~joQwWZ+UK{>pJUQ6sLjIw1pz=bzm;7&2rlBr|n7uQHk?dsbMEJheSUHx3v IIVCg!0NTuVK>z>% literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_02_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_02_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..99c832b68ecd0d32eed35de6e34d54a36f60e764 GIT binary patch literal 1150 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fOUuAVNAAr*7p-c>9X4iss) z$SWM!y|~Xy#bUyr0u>9biEFj_y1BUy@;q9)`>gk;xr^Vw*>^H!U*)rN@1~_%>M%I2 zPm^az5MyN7#3FD)$U(uIp;3pvoLlGZ7|s`O{&?qo@AI^ey9;>C@wwu(+KJAdJh>W~ zIn{sfG_Uz$U{SvRWA%Ohb9Zz9+zZ^#_Iw}jxtltcym$@C-mY^x@tdOF%@=LQpZCr$ ze>cyp?%vyD=Vzyu9DaQI*!jo*@8AuF*$Ucoe{a{?;j?+)-k`^994VX%6I2@-<^?$Rj0Xf`>}c8xIw|43<#!%Da_!_g=rWd{T7m`m)&K zS8;2%%85H%SiP5@VS_j$%O)0q6G9FO-VBX8^yTcj_nX1y{A=d(f9>b|Hk@<&^x1-U z=O5nr&V0Tw>JDDl%vR7(*){QFoyGU-#r&V7FZ1^2AKvMI-u6VkPyKZB!#iIdJ8`8R zNWD+m{3LY;BU2<3M+&FH1l0zIX$)wb@a(n6_wpB>TPDpa-&TCNcVe*lU5S~q@+#)+ zdf9gT_`^FZ_g^e}MaVhQcX^-Rllv+XGfV&Q&fkmYJ^Hj0udUasKjTw1Oe~PaJZ`fYnUVM+G zQj(CPgg=*Al$T!#{t)v0@J@YqTUP(4Y&atj=$qL0wG4HpcSUwcp8NavPVt$`doDXxK9^a+&3_IB@aA7ycKPO)T?dOXIk|w|f5W_m=NJKgmBA z%Updg^6Bi-t=D$NF*wG{)G{lcQmUqo3ncgZ~sc~n|E&9{$f3&E<8WKTHsm~ zP~!~TA?rJ#cOEbf^e%nby@_*EuQa~EPZdsCd@EZ14)6V|cMF&?!vYaXIZZiV5-q-e zShD=VC7=D;+X@M)uCw_5*3y;DM01q^HV)3mOh=l9KK*1qaSMY!YG@+Rnk%zGLRgoA+kEm#JO- zJIv_oRpH;O)?bS%=T>+zcdt0Zjcx{}NG6UHPK61o4Gz=j%ZYuzm!W;9;LBX4$QHK$Yvkn*<)%u0!mfc@avH9a?xn1$* zb@z@-+vn?F&R6dHMd~oyC*$4lbSf zZ=FRSUW1>iotRiBd9JqVlI{+Z%lAc(6Bk%{ZN>I{&ugroZ1Uaz^<#=fdG!OiKc_iy z1~Sm&MZ!+~WJ23$78_Yrhs*nE$PRoQU6NcUUZg@AE&G<9$9)Zr6#K zRi<-h|FbThHwR0Kfv2T4tG8aed(V5r{`2j{=lypb{TRpdyykH8R-h&W^kfFtq+{+_ zp?$usI3Ac-Uv9UI%li|jH=95laj1W+c>H|ty&shurU@$usNqbHPt`akJjEM4G|%bR a>|K8wu9FMnISVYg7(8A5T-G@yGywn>Nx0_# literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_06_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_06_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..217b98f680bdfa04bd5afd52cf2a7fe38ae8cf1e GIT binary patch literal 1257 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fOU8$4YcLn`LHy{ouhCRL>2 zVPp}nkbB_TC6o3yx-==3u3fz2(JPI0r7TxJ@jpmc=zgMgAXG`eiKTYe?&9a~_MBhr zpXO&a+kE~{qxRIuJh6ra{M+If6115(QaBYRs5UrEV_=G;FQ;_tS0=I|=eV7mMc&KI`Q!MX+gX=Q6y7U&&erO4b-m2F z+RA6&{r;NG`JH89zIW!~%sC8=I*crvSOiW8IVgCean>B(q+=efUwCra{RI`)bAG?L z;reby{JB4S&Y%CYXYC&8bG9<)?tabRa;MY}Zy3#1P_MF_Q@!Vv*qgJfAKsZ9y8VW| zI;M39hn)7EApF;I&hG6X9r1^E`iI?3`j6MCI_8dkPmU*hx33l7QGnMq*REdUj@eb; zRxH167i+cg-}pi)!fvse^E>IP?v2?m|94%sV8oXgKnZAD+@nc%<Qh#6I8s zUq2RDl-E9y`*WNVYdAwa{t4*oSpMg7ywC5+>|~#w_{)ArTruar=LBQAPVSto#5r60 zGQqHqITq%BZSU$FDQzf4@9)zB#p!iRBRX6b%aLJ1mTw@VXk24$(6NwPb#Y ZuL&?^-1uNaEwBh<@O1TaS?83{1OOOQxpe>l literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_07_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_07_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..507a929093763598beb1766ebd5412c883c3a562 GIT binary patch literal 1248 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fOU%ROBjLn`LHy{kA`CRC*1 z;`S?D4-P1bpFF>y;DM01q^HV)3mOh=l9KK*1qaSMY!YG@+Rnk%zGLRgoA+kEm#JO- zJIv_oRpH;O)?bS%=T>+zcdt0Zjcx{}NG6UHPK61o4Gz=j%ZYuzm!W;9;LBX4$QHK$Yvkn*<)%u0!mfc@avH9a?xn1$* zb@z@-+vn?F&R6dHMd~oyC*$4lbSf zZ=FRSUW1>iotRiBd9JqVlI{+Z%lAc(6Bk%{ZN>I{&ugroZ1Uaz^<#=fdG!OiKc_iy z1~Sm&MZ!+~WJ23$78_Yrhs*nE$PRoQU6NcUUZg@AE&G<9$9)Zr6#K zRi<-h|FbThHwR0Kfv2T4tG8aed(V5r{`2j{=lypb{TRpdyykH8R-h&W^kfFtq+{+_ zp?$usI3Ac-Uv9UI%li|jH=95laj1W+c>H|ty&shurU@$usNqbHPt`akJjEM4G|%bR a>|K8wu9FMnISVYg7(8A5T-G@yGywn>Nx0_# literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_08_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_08_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..2a6649a0014c18e4c17b638372889465c520f1e4 GIT binary patch literal 1235 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fOUvpiiKLn`LHy{ou6G*qJD zVW})r;Ou`aN`X>t$`doDXxK9^a+&3_IB@aA7ycKPO)T?dOXIk|w|f5W_m=NJKgmBA z%Updg^6Bi-t=D$NF*wG{)G{lcQmUqo3ncgZ~sc~n|E&9{$f3&E<8WKTHsm~ zP~!~TA?rJ#cOEbf^e%nby@_*EuQa~EPZdsCd@EZ14)6V|cMF&?!vYaXIZZiV5-q-e zShD=VC7=D;+X@M)uCw_5*3?$Rj0Xf`>}c8xIw|43<#!%Da_!_g=rWd{T7m`m)&K zS8;2%%85H%SiP5@VS_j$%O)0q6G9FO-VBX8^yTcj_nX1y{A=d(f9>b|Hk@<&^x1-U z=O5nr&V0Tw>JDDl%vR7(*){QFoyGU-#r&V7FZ1^2AKvMI-u6VkPyKZB!#iIdJ8`8R zNWD+m{3LY;BU2<3M+&FH1l0zIX$)wb@a(n6_wpB>TPDpa-&TCNcVe*lU5S~q@+#)+ zdf9gT_`^FZ_g^e}MaVhQcX^-Rllv+XGfV&Q&fkmYJ^Hj0udUasKjTw1Oe~PaJZ`fYnUVM+G zQj(CPgg=*Al$T!#{t)v0@J@YqTUP(4Y&atj=$qL0wG4HpcSUwcp8NavPV9X4iss) z$SWM!y|~Xy#bUyr0u>9biEFj_y1BUy@;q9)`>gk;xr^Vw*>^H!U*)rN@1~_%>M%I2 zPm^az5MyN7#3FD)$U(uIp;3pvoLlGZ7|s`O{&?qo@AI^ey9;>C@wwu(+KJAdJh>W~ zIn{sfG_Uz$U{SvRWA%Ohb9Zz9+zZ^#_Iw}jxtltcym$@C-mY^x@tdOF%@=LQpZCr$ ze>cyp?%vyD=Vzyu9DaQI*!jo*@8AuF*$Ucoe{a{?;j?+)-k`^994VX%6I2@-<^?q)H z(bVf^Ro&CsYrUrtqoEyHgszkSvBOS@h_{(nfq%t65irz=jYo|sxWv*!Db=K}vf znEibB^-%ry&rfzg=l*{;a=+UB+WW;E=hB$*`GzmK=khB>t~j;(Yj=IvvE^p>#K_fp zHhO1|o+#bO$P~%Mk;17kLAAkQ8Uq?f&(UnxxBSq8*dpJC_JYtm}h;&srp{3e5AJN~2|S*q_AQ?Y>^ zui;OHS~joQwWZ+UK{>pJUQ6sLjIw1pz=bzm;7&2rlBr|n7uQHk?dsbMEJheSUHx3v IIVCg!0NTuVK>z>% literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_12_320x240.png b/ports/zephyr-cp/tests/zephyr_display/golden/gifio_frame_12_320x240.png new file mode 100644 index 0000000000000000000000000000000000000000..8f7fc051365c0a05abbbc3d845af514f64a53c9b GIT binary patch literal 866 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX9-C$wJ+|*$fQKnw~C>Ar*7pUNK~3P~bVR zp|SqFLbAIs>)xugXS@yf=O#*reaFd=o6Ga3dXF&)T<#xmWHkDBli Qn0FXFUHx3vIVCg!07p~czyJUM literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/test.gif b/ports/zephyr-cp/tests/zephyr_display/test.gif new file mode 100644 index 0000000000000000000000000000000000000000..4f96816a1f032d2ee7623f83c2e220c0eb03d8e7 GIT binary patch literal 2760 zcmchXeSA~p6~})FiYq#?Mh)uHOK7x-X@Y}2WGadUH&}_x#THoaZ_B+(Q)=n&|nMkM{rxKmgYQcL1}11;CBK)xdgSF0cx?AJ79D;8s8h zQG_`_J}?9<2Wa3m;69)hpnyi;Ccp=TfpVY^xB=J=^a3%U8h8TW02QzmV1V0zVn7ZY z1ImDvz~ewEpavX37ElPx22KDrzzSRiJO#Lc>w%krr2q+7fD+(JU?Fe~a0Rd!xCNL8 z$bcn4CvY8b7+3~$0YTs~pc3!`n}FMaCxN?xkAY@jKi~w`0UrQuz-K@Q@Ck4n=m92y z4B%xT2aqClfbRllfh4dIZ~=D$=kPx~3(w6fag?vHSxX(HMmKwwC>2dBou!1G4$$Au|nwXRmUXMloK)zGw4A__|@4Xv1X2ph*a`%R6x5*=4dKa;z z-dxWHSSCah^=yqVXs)-&X^+2>F^lVzSt}>byM(GOa%<`Xkz(5X97C8i`dqh8XCRCw zjj6z-qYI5|+-icc)cF8!&bmTegcAKqGS76K2>1VWdzq^)Ye4!bw z=L@ajlG;>5umO>5XE^UV##6-kS>k-vW^bBYj1GfIM;4m$tTt=LpfBWkvfBEyrfBNG` zfB60He*57E@Bik#cYpn>U%vD9TW|j2=Wo3Jv!DLt$3Hsz+L>2>c>2`I6F)e9?3JV6 zpFT2m_O@;KdjA?;HR2-m%e<;pg`xhjtGRB>MYy_4e%C(H-yF-uc|K zv5sfj+ggQfEnB0JEzO(5O^urx_@_5M_2jpncznb9`nq+sp&<8I!0%&gs=w*2TDykv zxGU+3M^``c@T!L%T=~E^T;(gu?k~Ns#JRlq>(ssX6glj+W!Afw-ep;`*la2^7Ubs{ zNWD(0$yMK}Qs&%oyCQp$d?Aq~``T@{-m*Y?^G!EOZpgfT{&ioy_L_MaU%7hjRaefL zeT6t87JfQsjyR)JV=^_7#hE;J!A6d6*wok*-rT$;65ZOeO=xXvf2JeW@N_!w<)Sx7 zH8eCfacVNE;#E;n-4JOdRYI)2GuGXz>e#WPcUNMdJ3ja#$!E663{8}zy`{LgQzoI>x_51Ru1`b^ zCEMeBwo@Z5O{x)9m`svexC4C$C%E2D;Sm2)%j7h#Zc!hfP@g)KwvvZL5Y!aUQ)+}c zC|xdvjF%|{WrUIn@r;bPAf+TdiG-wUAUTvw#)cDZV+k2X#}yHBTp+{6uXk@u^c`rJy`>L?%0x7PwlhP;F50yviT~Nn?eOMNwHog^}b`t7F2d zRoxYEmHnx9fCN lDoD>xE0w3yB2$NYS!=xPw|JSm^s@bZ|MxlaC1Y*ze*mhtkADCF literal 0 HcmV?d00001 diff --git a/ports/zephyr-cp/tests/zephyr_display/test_gifio.py b/ports/zephyr-cp/tests/zephyr_display/test_gifio.py new file mode 100644 index 00000000000..d4a665e2d44 --- /dev/null +++ b/ports/zephyr-cp/tests/zephyr_display/test_gifio.py @@ -0,0 +1,201 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +import shutil +from pathlib import Path + +import pytest +from PIL import Image + + +_TEST_GIF_PATH = Path(__file__).parent / "test.gif" +_TEST_GIF_BYTES = _TEST_GIF_PATH.read_bytes() + + +def _read_image(path: Path) -> tuple[int, int, bytes]: + with Image.open(path) as img: + rgb = img.convert("RGB") + return rgb.width, rgb.height, rgb.tobytes() + + +def _golden_compare_or_update(request, captures, golden_path): + if not captures or not captures[0].exists(): + pytest.skip("display capture was not produced") + + if request.config.getoption("--update-goldens"): + golden_path.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(captures[0], golden_path) + return + + gw, gh, gpx = _read_image(golden_path) + dw, dh, dpx = _read_image(captures[0]) + assert (dw, dh) == (gw, gh) + assert gpx == dpx + + +GIFIO_METADATA_CODE = """\ +import gifio + +odg = gifio.OnDiskGif('/test.gif') +print('size', odg.width, odg.height) +print('frame_count', odg.frame_count) +print('duration', round(odg.duration, 3)) +print('min_delay', round(odg.min_delay, 3)) +print('max_delay', round(odg.max_delay, 3)) + +delay = odg.next_frame() +print('delay', round(delay, 3)) + +bitmap = odg.bitmap +print('bitmap_size', bitmap.width, bitmap.height) + +for i in range(min(odg.width, 8)): + print('px', i, hex(bitmap[i, 0])) + +odg.deinit() +print('deinited') + +try: + odg.next_frame() +except Exception as e: + print('after_deinit', type(e).__name__) + +print('done') +""" + + +GIFIO_DECODE_CODE = """\ +import board +import displayio +import time +from gifio import OnDiskGif + +odg = OnDiskGif('/test.gif') +print('size', odg.width, odg.height) +print('frame_count', odg.frame_count) + +scale = 10 +tg = displayio.TileGrid( + odg.bitmap, + pixel_shader=displayio.ColorConverter( + input_colorspace=displayio.Colorspace.RGB565_SWAPPED + ), +) +g = displayio.Group(scale=scale) +g.x = (board.DISPLAY.width - odg.width * scale) // 2 +g.y = (board.DISPLAY.height - odg.height * scale) // 2 +g.append(tg) + +board.DISPLAY.auto_refresh = False +board.DISPLAY.root_group = g + +# Pin the render loop to a known point in simulated time so that the +# capture_times_ns schedule below lands on each GIF frame while it is on screen. +LOOP_START = 10.0 +FRAME_HOLD = 2.0 +while time.monotonic() < LOOP_START: + time.sleep(0.05) +print('loop_start', round(time.monotonic(), 3)) + +for frame_index in range(odg.frame_count): + odg.next_frame() + board.DISPLAY.refresh() + print('rendered', frame_index, round(time.monotonic(), 3)) + # Hold this frame on screen; the capture for this frame is scheduled + # for the middle of this window. + target = LOOP_START + (frame_index + 1) * FRAME_HOLD + while time.monotonic() < target: + time.sleep(0.05) + +print('done') +while True: + time.sleep(1) +""" + + +# Keep these in sync with LOOP_START / FRAME_HOLD in GIFIO_DECODE_CODE. +_DECODE_LOOP_START_S = 10.0 +_DECODE_FRAME_HOLD_S = 2.0 +_DECODE_FRAME_COUNT = 13 +# Capture at the midpoint of each frame's hold window. +_DECODE_CAPTURE_TIMES_NS = [ + int( + (_DECODE_LOOP_START_S + i * _DECODE_FRAME_HOLD_S + _DECODE_FRAME_HOLD_S / 2) + * 1_000_000_000 + ) + for i in range(_DECODE_FRAME_COUNT) +] + + +GIFIO_WRITER_CODE = """\ +import displayio +import gifio +import os + +width, height = 8, 4 +buf = bytearray(width * height * 2) +for i in range(width * height): + # RGB565 gradient + value = (i * 0x0841) & 0xFFFF + buf[2 * i] = (value >> 8) & 0xFF + buf[2 * i + 1] = value & 0xFF + +path = '/out.gif' +with gifio.GifWriter(path, width, height, displayio.Colorspace.RGB565, loop=True) as writer: + writer.add_frame(buf, 0.1) + writer.add_frame(buf, 0.2) + +size = os.stat(path)[6] +print('wrote_size', size) + +with open(path, 'rb') as f: + header = f.read(6) +print('header', header) + +print('done') +""" + + +_GIFIO_METADATA_DRIVE = {"code.py": GIFIO_METADATA_CODE, "test.gif": _TEST_GIF_BYTES} +_GIFIO_DECODE_DRIVE = {"code.py": GIFIO_DECODE_CODE, "test.gif": _TEST_GIF_BYTES} +_GIFIO_WRITER_DRIVE = {"code.py": GIFIO_WRITER_CODE} + + +@pytest.mark.circuitpy_drive(_GIFIO_METADATA_DRIVE) +def test_gifio_metadata(circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 16 16" in output + assert "frame_count 13" in output + assert "bitmap_size 16 16" in output + assert "min_delay 0.08" in output + assert "max_delay 0.08" in output + # 13 frames * 0.08s = 1.04s + assert "duration 1.04" in output + assert "delay 0.08" in output + assert "deinited" in output + # Using a deinited OnDiskGif should raise an exception. + assert "after_deinit" in output + assert "done" in output + + +@pytest.mark.circuitpy_drive(_GIFIO_DECODE_DRIVE) +@pytest.mark.display(capture_times_ns=_DECODE_CAPTURE_TIMES_NS) +@pytest.mark.duration(60) +def test_gifio_decode(request, circuitpython): + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 16 16" in output + assert "frame_count 13" in output + for frame_index in range(_DECODE_FRAME_COUNT): + assert f"rendered {frame_index}" in output + assert "done" in output + + captures = circuitpython.display_capture_paths() + assert len(captures) == _DECODE_FRAME_COUNT + golden_dir = Path(__file__).parent / "golden" + for frame_index, capture in enumerate(captures): + golden = golden_dir / f"gifio_frame_{frame_index:02d}_320x240.png" + _golden_compare_or_update(request, [capture], golden) From a2b9e970b3f5e8f53af213681ef16059dcfebd2c Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 23 Apr 2026 10:07:18 -0700 Subject: [PATCH 432/876] shared/usb: reply unsupported to PREVENT_ALLOW on all LUNs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per @tannewt review on #10967: tinyusb advertises is_removable=1 for every LUN in its default INQUIRY response (msc_device.c line 781), so the per-LUN branch was inconsistent with what the host already sees. Collapse to a single unconditional ILLEGAL_REQUEST reply — host keeps polling TUR on all LUNs, so eject/re-mount works uniformly across CIRCUITPY, SAVES, and SD. --- supervisor/shared/usb/usb_msc_flash.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index f394040b74a..2ddf38939d3 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -214,22 +214,13 @@ int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, u switch (scsi_cmd[0]) { case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - #ifdef SDCARD_LUN - if (lun == SDCARD_LUN) { - // Removable media (SD card). Respond "unsupported" so macOS - // keeps sending TEST_UNIT_READY periodically to detect card - // insertion/removal. Responding OK here causes macOS to skip - // TUR polling and miss media-present events on the SD LUN. - // See the discussion in adafruit/circuitpython#6555. - tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); - resplen = -1; - } else - #endif - { - // Non-removable media (internal flash, SAVES). OK is fine; - // host assumes medium always present and skips TUR polling. - resplen = 0; - } + // All LUNs advertise is_removable=1 in INQUIRY (tinyusb default). + // Reply "unsupported" so the host keeps polling TUR and can + // re-mount after an eject. Responding OK tells the host to skip + // TUR polling, which breaks re-mount and can miss SD insertion + // events at boot. See adafruit/circuitpython#6555. + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + resplen = -1; break; default: From 8835fc5994977f9c3e89f2ba97d8731cca331bb0 Mon Sep 17 00:00:00 2001 From: Kyle Mohr <6644803+kylefmohr@users.noreply.github.com> Date: Sat, 25 Apr 2026 19:12:24 -0500 Subject: [PATCH 433/876] fix incorrectly named pin --- ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c b/ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c index e21f542179c..a107cd61c22 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c +++ b/ports/espressif/boards/waveshare_esp32_s3_matrix/pins.c @@ -35,7 +35,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, - { MP_ROM_QSTR(MP_QSTR_I01), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, From ab66281e61a4d78ba434a6fc37c63abd22d5a4b5 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 27 Apr 2026 15:17:56 -0700 Subject: [PATCH 434/876] shared/usb: move SD card eject handler to the callback USB actually uses --- supervisor/shared/usb/usb_msc_flash.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index 2ddf38939d3..27277bc5ac5 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -204,25 +204,25 @@ uint8_t tud_msc_get_maxlun_cb(void) { return LUN_COUNT; } +// PREVENT ALLOW MEDIUM REMOVAL: TinyUSB routes this to its own dedicated callback, +// NOT tud_msc_scsi_cb. Reply unsupported on all LUNs so the host keeps TUR polling +// on every LUN — eject/storage.remount() works uniformly across CIRCUITPY, SAVES, SD. +bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control) { + (void)prohibit_removal; + (void)control; + tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); + return false; +} + // Callback invoked when received an SCSI command not in built-in list below // - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, TEST_UNIT_READY, START_STOP_UNIT, MODE_SENSE6, REQUEST_SENSE -// - READ10 and WRITE10 have their own callbacks +// - PREVENT_ALLOW_MEDIUM_REMOVAL, READ10, WRITE10 have their own callbacks int32_t tud_msc_scsi_cb(uint8_t lun, const uint8_t scsi_cmd[16], void *buffer, uint16_t bufsize) { // Note that no command uses a response right now. const void *response = NULL; int32_t resplen = 0; switch (scsi_cmd[0]) { - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - // All LUNs advertise is_removable=1 in INQUIRY (tinyusb default). - // Reply "unsupported" so the host keeps polling TUR and can - // re-mount after an eject. Responding OK tells the host to skip - // TUR polling, which breaks re-mount and can miss SD insertion - // events at boot. See adafruit/circuitpython#6555. - tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); - resplen = -1; - break; - default: // Set Sense = Invalid Command Operation tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00); From 34b61dc5a82c4b1014c211e4a7fa8df7b136b30f Mon Sep 17 00:00:00 2001 From: Andi Chandler Date: Wed, 29 Apr 2026 12:50:40 +0200 Subject: [PATCH 435/876] Translated using Weblate (English (United Kingdom)) Currently translated at 100.0% (998 of 998 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/en_GB/ --- locale/en_GB.po | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/locale/en_GB.po b/locale/en_GB.po index 8d640a3c680..29380c91c80 100644 --- a/locale/en_GB.po +++ b/locale/en_GB.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-06-15 23:04+0000\n" +"PO-Revision-Date: 2026-04-30 11:09+0000\n" "Last-Translator: Andi Chandler \n" "Language-Team: none\n" "Language: en_GB\n" @@ -15,7 +15,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.12-dev\n" +"X-Generator: Weblate 5.17.1\n" #: main.c msgid "" @@ -527,7 +527,7 @@ msgstr "All channels in use" #: ports/raspberrypi/common-hal/usb_host/Port.c msgid "All dma channels in use" -msgstr "All DMA channels in use" +msgstr "All dma channels in use" #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "All event channels in use" From 3d0c4a84582a2ddbea9668db21673120f1369cee Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 1 May 2026 15:10:12 -0400 Subject: [PATCH 436/876] add float support to settings.toml and supervisor.get_setting() --- shared-bindings/supervisor/__init__.c | 9 ++- supervisor/shared/settings.c | 62 +++++++++++++++++ supervisor/shared/settings.h | 15 ++++- tests/circuitpython-manual/settings/code.py | 66 +++++++++++++++++++ .../settings/settings.toml | 16 +++++ 5 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 tests/circuitpython-manual/settings/code.py create mode 100644 tests/circuitpython-manual/settings/settings.toml diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c index a0a01f124f7..1200679f2e2 100644 --- a/shared-bindings/supervisor/__init__.c +++ b/shared-bindings/supervisor/__init__.c @@ -364,13 +364,13 @@ static mp_obj_t supervisor_set_usb_identification(size_t n_args, const mp_obj_t } MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_usb_identification_obj, 0, supervisor_set_usb_identification); -//| def get_setting(key: str, default: object=None) -> int | str | bool: +//| def get_setting(key: str, default: object=None) -> int | float | str | bool: //| """ //| Get and parse the value for the given ``key`` from the ``/settings.toml`` file. //| If ``key`` is not found or ``settings.toml`` is not present, return the ``default`` value. //| //| :param str key: The setting key to retrieve -//| :return: The setting value as an ``int``, ``str``, or ``bool`` depending on the value in the file +//| :return: The setting value as an ``int``, ``float``, ``str``, or ``bool`` depending on the value in the file //| //| :raises ValueError: If the value cannot be parsed as a valid TOML value. //| @@ -380,8 +380,9 @@ MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_usb_identification_obj, 0, supervisor_ //| The string may include Unicode characters, and ``\\u`` Unicode escapes. Backslash-escaped characters //| ``\\b``, ``\\r``, ``\\n``, ``\\t``, ``\\v``, ``\\v`` are also allowed. //| - ``int``: signed or unsigned integer -//| - lower-case boolean words ``true`` and ``false``. +//| - ``bool``: lower-case `true`` or ``false``. //| The values are returned as Python ``True`` or ``False`` values. +//| - ``float``: signed or unsigned decimal number with a ``.`` or exponent, or ``inf``, ``inf``, ``nan``. //| //| Example:: //| @@ -389,11 +390,13 @@ MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_usb_identification_obj, 0, supervisor_ //| WIDTH = 42 //| color = "red" //| DEBUG = true +//| RATIO = 1.5 //| //| import supervisor //| print(supervisor.get_setting("WIDTH")) # prints 42 //| print(supervisor.get_setting("color")) # prints 'red' //| print(supervisor.get_setting("DEBUG")) # prints True +//| print(supervisor.get_setting("RATIO")) # prints 1.5 //| """ //| ... //| diff --git a/supervisor/shared/settings.c b/supervisor/shared/settings.c index d1b05a5da9d..1414195411e 100644 --- a/supervisor/shared/settings.c +++ b/supervisor/shared/settings.c @@ -5,6 +5,7 @@ // // SPDX-License-Identifier: MIT +#include #include #include #include @@ -419,6 +420,57 @@ settings_err_t settings_get_bool(const char *key, bool *value) { return result; } +#if MICROPY_PY_BUILTINS_FLOAT +static settings_err_t get_float(const char *key, mp_float_t *value) { + char buf[48]; + bool quoted; + settings_err_t result = settings_get_buf_terminated(key, buf, sizeof(buf), "ed); + if (result != SETTINGS_OK) { + return result; + } + if (quoted) { + return SETTINGS_ERR_BAD_VALUE; + } + + const char *str = buf; + const char *end = buf + strlen(buf); + bool neg = false; + + if (str < end && (*str == '+' || *str == '-')) { + neg = (*str == '-'); + str++; + } + + mp_float_t val; + if (end - str >= 3 && str[0] == 'i' && str[1] == 'n' && str[2] == 'f') { + str += 3; + val = (mp_float_t)INFINITY; + } else if (end - str >= 3 && str[0] == 'n' && str[1] == 'a' && str[2] == 'n') { + str += 3; + val = MICROPY_FLOAT_C_FUN(nan)(""); + } else { + const char *num_start = str; + str = mp_parse_float_internal(str, end - str, &val); + if (str == NULL || str == num_start) { + return SETTINGS_ERR_BAD_VALUE; + } + } + + if (str != end) { + return SETTINGS_ERR_BAD_VALUE; + } + + *value = neg ? -val : val; + return SETTINGS_OK; +} + +settings_err_t settings_get_float(const char *key, mp_float_t *value) { + settings_err_t result = get_float(key, value); + print_error(key, result); + return result; +} +#endif + // Get the raw value as a vstr, whether quoted or bare. Value may be an invalid TOML value. settings_err_t settings_get_raw_vstr(const char *key, vstr_t *vstr) { bool quoted; @@ -457,6 +509,16 @@ settings_err_t settings_get_obj(const char *key, mp_obj_t *value) { return SETTINGS_OK; } + // Not an integer, try float + #if MICROPY_PY_BUILTINS_FLOAT + mp_float_t float_val; + result = get_float(key, &float_val); + if (result == SETTINGS_OK) { + *value = mp_obj_new_float(float_val); + return SETTINGS_OK; + } + #endif + return SETTINGS_ERR_BAD_VALUE; } diff --git a/supervisor/shared/settings.h b/supervisor/shared/settings.h index eafa9962e95..6d92d45d79a 100644 --- a/supervisor/shared/settings.h +++ b/supervisor/shared/settings.h @@ -10,6 +10,7 @@ typedef enum { SETTINGS_OK = 0, + // The settings file could not be opened. SETTINGS_ERR_OPEN, SETTINGS_ERR_UNICODE, SETTINGS_ERR_LENGTH, @@ -20,7 +21,7 @@ typedef enum { // Read a string value from the settings file. // If it fits, the return value is 0-terminated. The passed-in buffer // may be modified even if an error is returned. Allocation free. -// An error that is not 'open' or 'not found' is printed on the repl. +// An error that is not SETTINGS_ERR_OPEN or SETTINGS_ERR_NOT_FOUND is printed on the repl. // Returns an error if the value is not a quoted string. settings_err_t settings_get_str(const char *key, char *value, size_t value_len); @@ -38,13 +39,23 @@ settings_err_t settings_get_int(const char *key, mp_int_t *value); // An error that is not 'open' or 'not found' is printed on the repl. settings_err_t settings_get_bool(const char *key, bool *value); +#if MICROPY_PY_BUILTINS_FLOAT +// Read a float value from the settings file. +// Returns SETTINGS_OK and sets value to the read value. Returns +// SETTINGS_ERR_... if the value was not a float. allocation-free. +// If any error code is returned, value is guaranteed not modified. +// An error that is not SETTINGS_ERR_OPEN or SETTINGS_ERR_NOT_FOUND is printed on the repl. +settings_err_t settings_get_float(const char *key, mp_float_t *value); +#endif + // Read a value from the settings file and return as parsed Python object. // Returns SETTINGS_OK and sets value to a parsed Python object from the RHS value: // - Quoted strings return as str // - Bare "true" or "false" return as bool // - Valid integers return as int +// - Valid floats (containing '.' or 'e'/'E') return as float // Returns SETTINGS_ERR_... if the value is not parseable as one of these types. -// An error that is not 'open' or 'not found' is printed on the repl. +// An error that is not SETTINGS_ERR_OPEN or SETTINGS_ERR_NOT_FOUND is printed on the repl. settings_err_t settings_get_obj(const char *key, mp_obj_t *value); // Read the raw value as a string, whether quoted or bare. diff --git a/tests/circuitpython-manual/settings/code.py b/tests/circuitpython-manual/settings/code.py new file mode 100644 index 00000000000..bebed3d11ae --- /dev/null +++ b/tests/circuitpython-manual/settings/code.py @@ -0,0 +1,66 @@ +# Test supervisor.get_setting() parsing of settings.toml values. +# Copy settings.toml to the root of the board, then run this script. +# All lines should print PASS. + +import math +import supervisor + + +def check(key, expected): + got = supervisor.get_setting(key) + if type(got) is not type(expected): + print( + f"FAIL {key}: expected type {type(expected).__name__}, got {type(got).__name__} ({got!r})" + ) + return + if isinstance(expected, float) and math.isnan(expected): + ok = math.isnan(got) + else: + ok = got == expected + if ok: + print(f"PASS {key}") + else: + print(f"FAIL {key}: expected {expected!r}, got {got!r}") + + +check("str_val", "hello") +check("int_val", 42) +check("neg_int_val", -7) +check("hex_int_val", 31) +check("bool_true", True) +check("bool_false", False) +check("float_val", 3.14) +check("neg_float_val", -1.5) +check("sci_float_val", 6.626e-34) +# math.nan and math.inf are not always available +check("pos_inf", float("inf")) +check("neg_inf", -float("inf")) +check("pos_nan", float("nan")) + + +def check_bad(key): + try: + got = supervisor.get_setting(key) + print(f"FAIL {key}: expected ValueError, got {got!r}") + except ValueError: + print(f"PASS {key} raises ValueError") + + +check_bad("bad_word") # unquoted non-boolean word +check_bad("bad_float_junk") # float with trailing garbage +check_bad("bad_inf_junk") # inf with trailing characters +check_bad("bad_lone_sign") # bare + with nothing after it + +# Missing key returns default +got = supervisor.get_setting("no_such_key", "default") +if got == "default": + print("PASS missing key default") +else: + print(f"FAIL missing key default: got {got!r}") + +# Invalid value raises ValueError +try: + supervisor.get_setting("str_val") # quoted string is valid + print("PASS str via get_setting") +except ValueError: + print("FAIL str via get_setting raised ValueError unexpectedly") diff --git a/tests/circuitpython-manual/settings/settings.toml b/tests/circuitpython-manual/settings/settings.toml new file mode 100644 index 00000000000..5df2d104afe --- /dev/null +++ b/tests/circuitpython-manual/settings/settings.toml @@ -0,0 +1,16 @@ +str_val = "hello" +bad_word = hello +bad_float_junk = 1.2abc +bad_inf_junk = infoo +bad_lone_sign = + +int_val = 42 +neg_int_val = -7 +hex_int_val = 0x1F +bool_true = true +bool_false = false +float_val = 3.14 +neg_float_val = -1.5 +sci_float_val = 6.626e-34 +pos_inf = inf +neg_inf = -inf +pos_nan = nan From 62adfdccd687231a2da6f066dd4ae84a5163baa7 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 5 Apr 2026 04:13:05 -0700 Subject: [PATCH 437/876] ports/stm: add DAC-based audioio.AudioOut for STM32F405/F407 Implements audioio.AudioOut using the STM32F405/F407 12-bit DAC on pin A0 (PA04, DAC channel 1). TIM6 clocks the sample rate; DMA1 Stream5 feeds samples in circular double-buffer mode so the CPU is free between half-transfer callbacks. Supported formats: 8-bit unsigned, 8-bit signed, 16-bit unsigned, 16-bit signed, mono and stereo (left channel only). play(), stop(), pause(), resume(), and deinit() are all implemented. A soft ramp on construct/deinit suppresses audible pops. Build changes: - mpconfigport.mk: set CIRCUITPY_AUDIOIO = 1 for STM32F405xx/F407xx; change the F4-series default to CIRCUITPY_AUDIOIO ?= 0 so the F405/F407 override takes effect. - AnalogOut.h: expose the shared DAC_HandleTypeDef handle so AudioOut can reuse it without double-initialising the peripheral. - port.c: call audioout_reset() from reset_port() so an in-progress playback is cleanly stopped on soft reset. Co-Authored-By: Claude Sonnet 4.6 --- ports/stm/common-hal/analogio/AnalogOut.h | 6 + ports/stm/common-hal/audioio/AudioOut.c | 524 ++++++++++++++++++++++ ports/stm/common-hal/audioio/AudioOut.h | 57 +++ ports/stm/common-hal/audioio/__init__.c | 7 + ports/stm/mpconfigport.mk | 5 +- ports/stm/supervisor/port.c | 6 + 6 files changed, 603 insertions(+), 2 deletions(-) create mode 100644 ports/stm/common-hal/audioio/AudioOut.c create mode 100644 ports/stm/common-hal/audioio/AudioOut.h create mode 100644 ports/stm/common-hal/audioio/__init__.c diff --git a/ports/stm/common-hal/analogio/AnalogOut.h b/ports/stm/common-hal/analogio/AnalogOut.h index 6a8fc2720bf..33c8abc21f8 100644 --- a/ports/stm/common-hal/analogio/AnalogOut.h +++ b/ports/stm/common-hal/analogio/AnalogOut.h @@ -28,3 +28,9 @@ typedef struct { } analogio_analogout_obj_t; void analogout_reset(void); + +// Shared DAC peripheral handle (defined in AnalogOut.c). +// AudioOut reuses this handle for DMA-triggered DAC operation on channel 1. +#if HAS_DAC +extern DAC_HandleTypeDef handle; +#endif diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c new file mode 100644 index 00000000000..34252cfe287 --- /dev/null +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -0,0 +1,524 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// DAC-based audio output for STM32F405 / STM32F407. +// +// Architecture: +// TIM6 (basic timer) generates an update event at the sample rate. +// DAC_CHANNEL_1 (PA04) is configured with DAC_TRIGGER_T6_TRGO so each +// TIM6 update latches the next sample from the DMA FIFO. +// DMA1 Stream5 Channel7 operates in circular mode, feeding 16-bit samples +// from a double-buffer (512 samples = two 256-sample halves). +// The DMA half-complete and complete callbacks queue a background_callback +// to refill the idle half from the audio sample source. +// +// The shared DAC handle (declared in AnalogOut.c) is reused here so both +// modules share state consistently and avoid double-init conflicts. + +#include + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/mphal.h" + +#include "common-hal/audioio/AudioOut.h" +#include "shared-bindings/audioio/AudioOut.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" +#include "supervisor/background_callback.h" + +#include STM32_HAL_H + +// Shared DAC handle declared in common-hal/analogio/AnalogOut.h. +// AudioOut reconfigures channel 1 for DMA-triggered operation and restores +// it on deinit. +#include "common-hal/analogio/AnalogOut.h" + +// TIM6 handle: only one instance ever active, so file-scope is fine. +static TIM_HandleTypeDef tim6_handle; + +// Pointer to the currently active AudioOut object, used by IRQ handlers. +static audioio_audioout_obj_t *active_audioout = NULL; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +// Return the TIM6 input clock frequency in Hz. +// TIM6 sits on APB1. The clock is doubled when the APB1 prescaler != 1 +// (same logic as stm_peripherals_timer_get_source_freq in timers.c but +// applied directly to APB1 since TIM6 is not in mcu_tim_banks[]). +static uint32_t get_tim6_freq(void) { + uint32_t apb1 = HAL_RCC_GetPCLK1Freq(); + uint32_t ppre1 = (RCC->CFGR & RCC_CFGR_PPRE1) >> RCC_CFGR_PPRE1_Pos; + #if defined(RCC_DCKCFGR_TIMPRE) + uint32_t timpre = RCC->DCKCFGR & RCC_DCKCFGR_TIMPRE; + if (timpre == 0) { + return (ppre1 >= 0b100) ? apb1 * 2 : apb1; + } else { + return (ppre1 > 0b101) ? apb1 * 4 : HAL_RCC_GetHCLKFreq(); + } + #else + return (ppre1 >= 0b100) ? apb1 * 2 : apb1; + #endif +} + +// Gently ramp the DAC CH1 output from from_12 to to_12 (both 12-bit, 0-4095) +// to avoid audible clicks. 64 steps, ~100 µs per step = ~6.4 ms total. +static void dac_ramp(uint32_t from_12, uint32_t to_12) { + if (from_12 == to_12) { + return; + } + int32_t delta = (int32_t)to_12 - (int32_t)from_12; + int32_t step = delta / 64; + if (step == 0) { + step = (delta > 0) ? 1 : -1; + } + int32_t v = (int32_t)from_12; + while (true) { + v += step; + if (step > 0 && v >= (int32_t)to_12) { + v = (int32_t)to_12; + } else if (step < 0 && v <= (int32_t)to_12) { + v = (int32_t)to_12; + } + HAL_DAC_SetValue(&handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, (uint16_t)v); + HAL_DAC_Start(&handle, DAC_CHANNEL_1); + mp_hal_delay_us(100); + if (v == (int32_t)to_12) { + break; + } + } +} + +// Convert a buffer of audio samples into 12-bit unsigned DAC values and write +// them into dest[]. Returns the number of DAC samples written. +// +// src - raw sample bytes from audiosample_get_buffer +// src_len - byte length of src +// dest - output array of 12-bit DAC values (uint16_t) +// dest_count - capacity of dest in samples +// bytes_per_sample - 1 or 2 +// samples_signed - true if source samples are signed +// channel_count - 1 (mono) or 2 (stereo); only channel 0 (L) is output +// quiescent_12 - value to pad with if src runs short +static uint32_t convert_to_dac12( + const uint8_t *src, uint32_t src_len, + uint16_t *dest, uint32_t dest_count, + uint8_t bytes_per_sample, bool samples_signed, + uint8_t channel_count, uint16_t quiescent_12) { + + // src_stride: bytes between consecutive left-channel samples + uint32_t src_stride = (uint32_t)bytes_per_sample * channel_count; + uint32_t src_frames = src_len / src_stride; + uint32_t frames = (src_frames < dest_count) ? src_frames : dest_count; + + if (bytes_per_sample == 1) { + for (uint32_t i = 0; i < frames; i++) { + uint8_t u8 = src[i * src_stride]; + if (samples_signed) { + // signed 8-bit: -128..127 → 0..4080 + dest[i] = (uint16_t)((int16_t)(int8_t)u8 + 128) << 4; + } else { + // unsigned 8-bit: 0..255 → 0..4080 + dest[i] = (uint16_t)u8 << 4; + } + } + } else { + for (uint32_t i = 0; i < frames; i++) { + uint16_t u16; + memcpy(&u16, src + i * src_stride, 2); + if (samples_signed) { + // signed 16-bit: -32768..32767 → 0..4095 + dest[i] = (uint16_t)((int32_t)(int16_t)u16 + 0x8000) >> 4; + } else { + // unsigned 16-bit: 0..65535 → 0..4095 + dest[i] = u16 >> 4; + } + } + } + + // Pad remainder with quiescent value. + for (uint32_t i = frames; i < dest_count; i++) { + dest[i] = quiescent_12; + } + return frames; +} + +// Load one half of the DMA circular buffer from the audio sample source. +// half: 0 = lower half (indices 0..HALF-1), 1 = upper half (HALF..END-1). +// +// Loops get_buffer calls until the full AUDIOOUT_DMA_HALF_SAMPLES-sample slot +// is filled. This is necessary because the audio sample source (e.g. WaveFile) +// delivers data in fixed-byte chunks (256 bytes) that may be smaller than the +// half-buffer in samples (e.g. 128 samples for 16-bit audio vs 256 slots). +static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { + uint16_t *dest = self->dma_buffer + ((uint32_t)half * AUDIOOUT_DMA_HALF_SAMPLES); + uint16_t quiescent_12 = self->quiescent_value >> 4; + uint32_t filled = 0; + + while (filled < AUDIOOUT_DMA_HALF_SAMPLES) { + uint8_t *src_buf; + uint32_t src_len; + audioio_get_buffer_result_t result = + audiosample_get_buffer(self->sample, false, 0, &src_buf, &src_len); + + if (result == GET_BUFFER_ERROR) { + for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { + dest[i] = quiescent_12; + } + self->stopping = true; + return; + } + + uint32_t written = convert_to_dac12( + src_buf, src_len, + dest + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, + self->bytes_per_sample, self->samples_signed, + self->channel_count, quiescent_12); + + filled += written; + + if (result == GET_BUFFER_DONE) { + if (self->loop) { + audiosample_reset_buffer(self->sample, false, 0); + // Continue filling the remainder of this half from the reset buffer. + } else { + for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { + dest[i] = quiescent_12; + } + self->stopping = true; + return; + } + } + } +} + +// Background callback: called from the main loop after a DMA half/full event. +static void audioout_fill_callback(void *arg) { + audioio_audioout_obj_t *self = (audioio_audioout_obj_t *)arg; + if (!self || active_audioout != self) { + return; + } + if (self->stopping) { + common_hal_audioio_audioout_stop(self); + return; + } + load_dma_buffer_half(self, self->buffer_half_to_fill); +} + +// --------------------------------------------------------------------------- +// IRQ handlers (must be defined at file scope, not inside functions) +// --------------------------------------------------------------------------- + +void DMA1_Stream5_IRQHandler(void) { + if (active_audioout) { + HAL_DMA_IRQHandler(&active_audioout->dma_handle); + } +} + +// HAL weak-symbol overrides: called from HAL_DMA_IRQHandler context. + +void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) { + if (active_audioout && !active_audioout->paused) { + active_audioout->buffer_half_to_fill = 0; + background_callback_add(&active_audioout->callback, + audioout_fill_callback, active_audioout); + } +} + +void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) { + if (active_audioout && !active_audioout->paused) { + active_audioout->buffer_half_to_fill = 1; + background_callback_add(&active_audioout->callback, + audioout_fill_callback, active_audioout); + } +} + +// --------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------- + +void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, + const mcu_pin_obj_t *left_channel, const mcu_pin_obj_t *right_channel, + uint16_t quiescent_value) { + + #if !HAS_DAC + mp_raise_ValueError(MP_ERROR_TEXT("No DAC on chip")); + #else + + // Right channel (stereo) support deferred to a future implementation. + if (right_channel != NULL) { + mp_raise_ValueError(MP_ERROR_TEXT("Stereo not supported on this board")); + } + + // Only PA04 (DAC_CH1) is supported. + if (left_channel != &pin_PA04) { + mp_raise_ValueError(MP_ERROR_TEXT("AudioOut requires pin A0 (PA04)")); + } + + self->left_channel = left_channel; + self->quiescent_value = quiescent_value; + self->sample = MP_OBJ_NULL; + self->dma_buffer = NULL; + memset(&self->dma_handle, 0, sizeof(self->dma_handle)); + memset(&self->callback, 0, sizeof(self->callback)); + self->stopping = false; + self->paused = false; + + // Configure PA04 for analog (DAC) mode. + GPIO_InitTypeDef gpio_init = {0}; + gpio_init.Pin = pin_mask(left_channel->number); + gpio_init.Mode = GPIO_MODE_ANALOG; + gpio_init.Pull = GPIO_NOPULL; + HAL_GPIO_Init(pin_port(left_channel->port), &gpio_init); + + // Initialise the shared DAC handle if it hasn't been set up yet + // (i.e. AnalogOut hasn't been used since last reset). + if (handle.Instance == NULL || handle.State == HAL_DAC_STATE_RESET) { + __HAL_RCC_DAC_CLK_ENABLE(); + handle.Instance = DAC; + if (HAL_DAC_Init(&handle) != HAL_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("DAC init error")); + } + } + + // Configure DAC channel 1 with TIM6_TRGO trigger (set at play() time; + // for now configure with no trigger so the ramp works correctly). + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + if (HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1) != HAL_OK) { + mp_raise_ValueError(MP_ERROR_TEXT("DAC channel config error")); + } + + // Ramp DAC output up to quiescent value to prevent an audible pop. + HAL_DAC_SetValue(&handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0); + HAL_DAC_Start(&handle, DAC_CHANNEL_1); + dac_ramp(0, quiescent_value >> 4); + + // Claim the pin last so any error above doesn't leave it claimed. + common_hal_mcu_pin_claim(left_channel); + #endif +} + +bool common_hal_audioio_audioout_deinited(audioio_audioout_obj_t *self) { + return self->left_channel == NULL; +} + +void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t *self) { + if (common_hal_audioio_audioout_deinited(self)) { + return; + } + + common_hal_audioio_audioout_stop(self); + + // Ramp DAC back to zero before disconnecting. + dac_ramp(self->quiescent_value >> 4, 0); + HAL_DAC_Stop(&handle, DAC_CHANNEL_1); + + // Restore channel 1 to no-trigger mode so AnalogOut can use it again. + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + + // Release the pin. Let AnalogOut manage DAC clock disable. + reset_pin_number(self->left_channel->port, self->left_channel->number); + self->left_channel = NULL; +} + +void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, + mp_obj_t sample, bool loop) { + if (common_hal_audioio_audioout_deinited(self)) { + mp_raise_ValueError(MP_ERROR_TEXT("AudioOut is deinited")); + } + common_hal_audioio_audioout_stop(self); + + // Extract sample format metadata. + audiosample_base_t *base = audiosample_check(sample); + self->bytes_per_sample = base->bits_per_sample / 8; + self->samples_signed = base->samples_signed; + self->channel_count = base->channel_count; + uint32_t sample_rate = base->sample_rate; + if (sample_rate == 0) { + mp_raise_ValueError(MP_ERROR_TEXT("sample_rate must be > 0")); + } + + self->sample = sample; + self->loop = loop; + self->stopping = false; + self->paused = false; + + // Allocate the DMA circular buffer. + self->dma_buffer = (uint16_t *)m_malloc( + AUDIOOUT_DMA_BUFFER_SAMPLES * sizeof(uint16_t)); + if (!self->dma_buffer) { + mp_raise_msg(&mp_type_MemoryError, + MP_ERROR_TEXT("insufficient memory for audio buffer")); + } + + // Pre-fill both halves before starting DMA. + audiosample_reset_buffer(sample, false, 0); + load_dma_buffer_half(self, 0); + load_dma_buffer_half(self, 1); + + // --- TIM6 setup --- + // TIM6 is a basic timer on APB1. It is not managed by the common timer + // infrastructure (stm_peripherals_find_timer etc.) because it has no GPIO + // pins and is reserved for DAC use (mcu_tim_banks[5] == NULL). + __HAL_RCC_TIM6_CLK_ENABLE(); + + uint32_t tim6_clk = get_tim6_freq(); + uint32_t period = (tim6_clk / sample_rate); + if (period < 2) { + period = 2; + } + period -= 1; + + tim6_handle.Instance = TIM6; + tim6_handle.Init.Prescaler = 0; + tim6_handle.Init.CounterMode = TIM_COUNTERMODE_UP; + tim6_handle.Init.Period = period; + tim6_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; + tim6_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; + HAL_TIM_Base_Init(&tim6_handle); + + // TRGO = Update event → triggers DAC conversion each period. + TIM_MasterConfigTypeDef master_cfg = {0}; + master_cfg.MasterOutputTrigger = TIM_TRGO_UPDATE; + master_cfg.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; + HAL_TIMEx_MasterConfigSynchronization(&tim6_handle, &master_cfg); + + // --- DAC channel reconfiguration for DMA-triggered mode --- + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_T6_TRGO; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + + // --- DMA1 Stream5 Channel7 setup --- + __HAL_RCC_DMA1_CLK_ENABLE(); + + DMA_HandleTypeDef *hdma = &self->dma_handle; + memset(hdma, 0, sizeof(*hdma)); + hdma->Instance = DMA1_Stream5; + hdma->Init.Channel = DMA_CHANNEL_7; + hdma->Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma->Init.PeriphInc = DMA_PINC_DISABLE; + hdma->Init.MemInc = DMA_MINC_ENABLE; + hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + hdma->Init.Mode = DMA_CIRCULAR; + hdma->Init.Priority = DMA_PRIORITY_HIGH; + hdma->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + HAL_DMA_Init(hdma); + + // Link DMA stream to DAC channel 1. + __HAL_LINKDMA(&handle, DMA_Handle1, *hdma); + + HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 6, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); + + // --- Start DMA transfer then timer --- + active_audioout = self; + + if (HAL_DAC_Start_DMA(&handle, DAC_CHANNEL_1, + (uint32_t *)self->dma_buffer, + AUDIOOUT_DMA_BUFFER_SAMPLES, + DAC_ALIGN_12B_R) != HAL_OK) { + active_audioout = NULL; + HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + m_free(self->dma_buffer); + self->dma_buffer = NULL; + mp_raise_RuntimeError(MP_ERROR_TEXT("DAC DMA start failed")); + } + + HAL_TIM_Base_Start(&tim6_handle); +} + +void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) { + if (active_audioout != self) { + return; + } + + // Stop the sample clock first so no more DMA requests are generated. + TIM6->CR1 &= ~TIM_CR1_CEN; + + // Stop DMA and DAC channel. + HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_1); + HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + + // Free the DMA buffer. + if (self->dma_buffer) { + m_free(self->dma_buffer); + self->dma_buffer = NULL; + } + + // Restore quiescent output (channel is still active from construct()). + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + HAL_DAC_SetValue(&handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, + self->quiescent_value >> 4); + HAL_DAC_Start(&handle, DAC_CHANNEL_1); + + self->sample = MP_OBJ_NULL; + self->stopping = false; + self->paused = false; + active_audioout = NULL; + + __HAL_RCC_TIM6_CLK_DISABLE(); +} + +bool common_hal_audioio_audioout_get_playing(audioio_audioout_obj_t *self) { + return active_audioout == self; +} + +void common_hal_audioio_audioout_pause(audioio_audioout_obj_t *self) { + if (active_audioout != self) { + return; + } + self->paused = true; + // Pause the sample clock; DMA remains armed but no new triggers fire. + TIM6->CR1 &= ~TIM_CR1_CEN; +} + +void common_hal_audioio_audioout_resume(audioio_audioout_obj_t *self) { + if (active_audioout != self || !self->paused) { + return; + } + self->paused = false; + // Restart the sample clock. + TIM6->CR1 |= TIM_CR1_CEN; +} + +bool common_hal_audioio_audioout_get_paused(audioio_audioout_obj_t *self) { + return self->paused; +} + +// --------------------------------------------------------------------------- +// Reset hook +// --------------------------------------------------------------------------- + +void audioout_reset(void) { + if (active_audioout != NULL) { + // Emergency stop: halt timer and DMA without ramping. + TIM6->CR1 &= ~TIM_CR1_CEN; + HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_1); + HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + if (active_audioout->dma_buffer) { + m_free(active_audioout->dma_buffer); + active_audioout->dma_buffer = NULL; + } + active_audioout->sample = MP_OBJ_NULL; + active_audioout->stopping = false; + active_audioout->paused = false; + active_audioout->left_channel = NULL; // mark deinited + active_audioout = NULL; + } + __HAL_RCC_TIM6_CLK_DISABLE(); +} diff --git a/ports/stm/common-hal/audioio/AudioOut.h b/ports/stm/common-hal/audioio/AudioOut.h new file mode 100644 index 00000000000..4b1cc388b85 --- /dev/null +++ b/ports/stm/common-hal/audioio/AudioOut.h @@ -0,0 +1,57 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "common-hal/microcontroller/Pin.h" +#include "supervisor/background_callback.h" +#include STM32_HAL_H + +// Total DMA circular buffer size in 16-bit samples. +// Split into two halves; one half plays while the other is refilled. +// 512 samples at 44100 Hz = ~5.8 ms per half-buffer interrupt. +#define AUDIOOUT_DMA_BUFFER_SAMPLES 512 +#define AUDIOOUT_DMA_HALF_SAMPLES 256 + +typedef struct { + mp_obj_base_t base; + + // Left channel pin (PA04 = DAC_CH1). NULL when deinited. + const mcu_pin_obj_t *left_channel; + // right_channel (PA05 = DAC_CH2) deferred to a future implementation. + + // DMA handle for DMA1 Stream5 Channel7 (DAC CH1). + // The DAC handle is the shared file-scope handle from AnalogOut.c. + DMA_HandleTypeDef dma_handle; + + // Circular DMA buffer: AUDIOOUT_DMA_BUFFER_SAMPLES uint16_t elements, + // allocated on play() and freed on stop(). + uint16_t *dma_buffer; + + // Current audio sample object being played. + mp_obj_t sample; + bool loop; + + // Set from ISR context to request a clean stop via background callback. + volatile bool stopping; + bool paused; + + // Sample format metadata, populated at play() time. + uint8_t bytes_per_sample; // 1 (8-bit) or 2 (16-bit) + bool samples_signed; + uint8_t channel_count; // 1 = mono, 2 = stereo (only L channel output) + uint16_t quiescent_value; // 16-bit resting value (default 0x8000) + + // Background callback queued from DMA ISR, processed in main loop. + background_callback_t callback; + + // Which half of dma_buffer to refill next: 0 = lower, 1 = upper. + volatile uint8_t buffer_half_to_fill; +} audioio_audioout_obj_t; + +// Called from reset_port() to stop any active playback on soft-reset. +void audioout_reset(void); diff --git a/ports/stm/common-hal/audioio/__init__.c b/ports/stm/common-hal/audioio/__init__.c new file mode 100644 index 00000000000..ebf626832f6 --- /dev/null +++ b/ports/stm/common-hal/audioio/__init__.c @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +// No audioio module functions. diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk index 96724a52960..9fd8cbfb2d7 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -3,6 +3,7 @@ INTERNAL_LIBM ?= 1 ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32F405xx STM32F407xx)) CIRCUITPY_ALARM = 1 + CIRCUITPY_AUDIOIO = 1 CIRCUITPY_CANIO = 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 CIRCUITPY_SDIOIO ?= 1 @@ -19,8 +20,8 @@ ifeq ($(MCU_VARIANT),STM32F407xx) endif ifeq ($(MCU_SERIES),F4) - # Audio via PWM - CIRCUITPY_AUDIOIO = 0 + # Audio via PWM (F405/F407 also supports DAC-based audioio; set above) + CIRCUITPY_AUDIOIO ?= 0 CIRCUITPY_AUDIOCORE ?= 1 CIRCUITPY_AUDIOPWMIO ?= 1 diff --git a/ports/stm/supervisor/port.c b/ports/stm/supervisor/port.c index 1ffc8656a88..1da862cd886 100644 --- a/ports/stm/supervisor/port.c +++ b/ports/stm/supervisor/port.c @@ -32,6 +32,9 @@ #if CIRCUITPY_RTC #include "shared-bindings/rtc/__init__.h" #endif +#if CIRCUITPY_AUDIOIO +#include "common-hal/audioio/AudioOut.h" +#endif #include "peripherals/clocks.h" #include "peripherals/gpio.h" @@ -315,6 +318,9 @@ void reset_port(void) { #if CIRCUITPY_ALARM exti_reset(); #endif + #if CIRCUITPY_AUDIOIO + audioout_reset(); + #endif } void reset_to_bootloader(void) { From 3f5fa6a07b0a797da86a27d03efa3c7de1e2b26c Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 5 Apr 2026 04:13:48 -0700 Subject: [PATCH 438/876] tests: add audioio manual test suite for STM32F405/F407 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds tests/circuitpython-manual/audioio/ with: - wavefile_playback.py — plays three WAV files (8-bit unsigned, 16-bit signed at 8 kHz and 44.1 kHz) - wavefile_pause_resume.py — exercises pause()/resume() during playback - single_buffer_loop.py — loops a 440 Hz RawSample in all four sample formats (u8, s8, u16, s16) - run_serial_tests.py — automates Tests 1–4 via mpremote: copies files to the board and checks serial output against expected patterns; exits 0/1 for CI - README.md — full test procedure including hardware setup, build instructions, expected output for each test, oscilloscope tips, and known limitations Tests 1–4 are fully automated (requires: pip install mpremote). Test 5 (soft-reset cleanup) remains a guided manual step. Co-Authored-By: Claude Sonnet 4.6 --- tests/circuitpython-manual/audioio/README.md | 255 ++++++++++++++++ tests/circuitpython-manual/audioio/TESTING.md | 255 ++++++++++++++++ .../audioio/run_serial_tests.py | 280 ++++++++++++++++++ .../audioio/single_buffer_loop.py | 58 ++++ .../audioio/wavefile_pause_resume.py | 53 ++++ .../audioio/wavefile_playback.py | 45 +++ 6 files changed, 946 insertions(+) create mode 100644 tests/circuitpython-manual/audioio/README.md create mode 100644 tests/circuitpython-manual/audioio/TESTING.md create mode 100644 tests/circuitpython-manual/audioio/run_serial_tests.py create mode 100644 tests/circuitpython-manual/audioio/single_buffer_loop.py create mode 100644 tests/circuitpython-manual/audioio/wavefile_pause_resume.py create mode 100644 tests/circuitpython-manual/audioio/wavefile_playback.py diff --git a/tests/circuitpython-manual/audioio/README.md b/tests/circuitpython-manual/audioio/README.md new file mode 100644 index 00000000000..596baebbe90 --- /dev/null +++ b/tests/circuitpython-manual/audioio/README.md @@ -0,0 +1,255 @@ +# Testing: STM32F405 / STM32F407 DAC AudioOut + +These tests exercise the DAC-based `audioio.AudioOut` implementation added for STM32F405xx and STM32F407xx. + +## Automated vs Manual Tests + +| Test | Automated | Requires audio/scope | +|------|-----------|----------------------| +| 1 — WAV File Playback | Yes | Yes (audio check) | +| 2 — Pause / Resume | Yes | Yes (audio check) | +| 3 — Looping Sine Wave | Yes | Yes (audio check) | +| 4 — deinit and Re-init | Yes | No | +| 5 — Soft Reset Cleanup | No (manual Ctrl-C/D) | No | + +`run_serial_tests.py` automates Tests 1, 2, 3, and 4: it copies the necessary +files to the board and runs each script over the serial REPL, comparing the +printed output to the expected patterns. You still need to listen to the audio +(and optionally use an oscilloscope) for the audio-quality checks. + +### Quick start + +```bash +# Install the one dependency (if not already present) +pip install mpremote + +# Run all automated tests (board must be connected and CIRCUITPY mounted) +python3 tests/circuitpython-manual/audioio/run_serial_tests.py + +# Skip file copy if files are already on the board +python3 tests/circuitpython-manual/audioio/run_serial_tests.py --no-copy + +# Override the serial port or CIRCUITPY path +python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ + --port /dev/cu.usbmodem1234 \ + --circuitpy /Volumes/CIRCUITPY + +# Run only specific tests +python3 tests/circuitpython-manual/audioio/run_serial_tests.py --tests 3,4 +``` + +The script exits 0 if all selected tests pass, 1 otherwise — suitable for CI. + +--- + +## Hardware Required + +- An STM32F405 or STM32F407 board running the freshly-built firmware (e.g. Feather STM32F405 Express). +- A passive speaker or audio amplifier connected to **pin A0 (PA04, DAC channel 1)** and GND. + - A simple test: 100 Ω resistor in series with a small speaker between A0 and GND. + - For better audio: connect A0 to a small amp module (e.g. PAM8403) then to a speaker. +- Optional: an oscilloscope or logic analyser probe on **D4** (used as a trigger output by the test scripts). +- A USB cable for REPL/filesystem access (CircuitPython storage must not be read-only). + +## Build + +Enable the feature by building for an F405 or F407 target: + +``` +make -C ports/stm BOARD=feather_stm32f405_express -j CROSS_COMPILE=~/arm-toolchain/arm-gnu-toolchain-14.3.rel1-darwin-arm64-arm-none-eabi/bin/arm-none-eabi- PYTHON=/opt/homebrew/bin/python3 +``` + +`CIRCUITPY_AUDIOIO` is now set to `1` automatically for those variants. Verify it is present in the build: + +``` +grep CIRCUITPY_AUDIOIO ports/stm/build-feather_stm32f405_express/mpconfigport.mk +# Expected output: CIRCUITPY_AUDIOIO = 1 +``` + +Flash the resulting `.bin` to the board using your preferred method (e.g. `dfu-util`). + +## File Setup + +> **If using `run_serial_tests.py`** this step is done automatically — skip ahead. + +Copy the WAV test samples onto the board's `CIRCUITPY` drive root: + +``` +cp \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-8bit-mono-unsigned.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-mono-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-mono-signed.wav \ + /Volumes/CIRCUITPY/ +``` + +These three files (~447 KB total) cover every exercised code path: +- `8000-8bit-mono-unsigned` — 8-bit unsigned decode path, audibly lo-fi +- `8000-16bit-mono-signed` — 16-bit signed decode path at lowest sample rate +- `44100-16bit-mono-signed` — 16-bit at highest sample rate (DMA reconfiguration, audible quality difference) + +Stereo, 24-bit, and the 16 kHz files are omitted: stereo and 24-bit will `OSError`; 16 kHz adds no new code paths over 8 kHz and 44.1 kHz. + +Copy the three test scripts to the board as well (or paste them into the REPL): + +``` +cp tests/circuitpython-manual/audioio/wavefile_playback.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/wavefile_pause_resume.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/single_buffer_loop.py /Volumes/CIRCUITPY/ +``` + +## Test 1 — WAV File Playback (`wavefile_playback.py`) *(automated)* + +Verifies that `AudioOut` can play WAV files at 8 kHz, 16 kHz, and 44.1 kHz in mono and stereo (only left channel output), with 8-bit unsigned and 16-bit signed encodings. + +**Note:** 24-bit WAV files and the stereo MP3 are intentionally excluded — `audiocore.WaveFile` does not support 24-bit, and those files will print an `OSError`. That is expected. + +**Run from the REPL:** + +```python +import os +os.chdir("/") +exec(open("wavefile_playback.py").read()) +``` + +**Expected output (order may vary by filename sort):** + +``` +playing jeplayer-splash-44100-16bit-mono-signed.wav +playing jeplayer-splash-8000-16bit-mono-signed.wav +playing jeplayer-splash-8000-8bit-mono-unsigned.wav +done +``` + +**What to listen for:** + +- Each supported WAV plays the "jeplayer splash" jingle to completion before the next starts. +- No loud pops at the start or end of each file (the DAC ramp-in / ramp-out should suppress them). +- Audio pitch should match the sample rate: the 44100 Hz file sounds the most natural; the 8000 Hz file sounds lower fidelity. + +## Test 2 — Pause and Resume (`wavefile_pause_resume.py`) *(automated)* + +Verifies `AudioOut.pause()` / `AudioOut.resume()` by toggling every 100 ms during playback. The audio will sound choppy — that is intentional. + +**Run from the REPL:** + +```python +exec(open("wavefile_pause_resume.py").read()) +``` + +**Expected output (repeating for each WAV):** + +``` +playing with pause/resume: jeplayer-splash-44100-16bit-mono-signed.wav + paused + resumed + ... +playing with pause/resume: jeplayer-splash-8000-16bit-mono-signed.wav + paused + resumed + ... +playing with pause/resume: jeplayer-splash-8000-8bit-mono-unsigned.wav + paused + resumed + ... +done +``` + +**What to verify:** + +- The REPL prints alternating "paused" / "resumed" lines. +- Audio cuts in and out in sync with the prints. +- Playback eventually completes (the `while dac.playing` loop exits normally). +- No hard fault or hang. + +## Test 3 — Looping Sine Wave (`single_buffer_loop.py`) *(automated)* + +Verifies `RawSample` with `loop=True` and tests all four sample formats: +`unsigned 8-bit`, `signed 8-bit`, `unsigned 16-bit`, `signed 16-bit`. + +Each sample generates one cycle of a 440 Hz sine wave and loops for 1 second. + +**Run from the REPL:** + +```python +exec(open("single_buffer_loop.py").read()) +``` + +**Expected output:** + +``` +unsigned 8 bit + +signed 8 bit + +unsigned 16 bit + +signed 16 bit + +done +``` + +**What to listen for:** + +- A 440 Hz tone (concert A) for approximately 1 second for each format. +- All four formats should sound essentially identical in pitch and volume. +- No pops or glitches during the loop. +- Clean silence between tones (quiescent DAC value holds between `stop()` calls). + +## Test 4 — `deinit` and Re-init *(automated)* + +Verifies that `AudioOut` can be deconstructed and reconstructed without rebooting, and that pin A0 is properly released. + +```python +import audioio, analogio, board + +# Construct and immediately deinit AudioOut +dac = audioio.AudioOut(board.A0) +dac.deinit() + +# PA04 should now be free for AnalogOut +aout = analogio.AnalogOut(board.A0) +aout.value = 32768 # mid-scale +aout.deinit() + +# Re-create AudioOut on the same pin +dac2 = audioio.AudioOut(board.A0) +dac2.deinit() +print("pass") +``` + +**Expected output:** `pass` with no exceptions. + +## Test 5 — Soft Reset Cleanup *(manual)* + +Verifies that `audioout_reset()` properly cleans up when the REPL soft-resets during active playback. + +1. Start a looping tone in the REPL: + +```python +import audiocore, audioio, board, array, math, time +length = 8000 // 440 +s16 = array.array("h", [int(math.sin(math.pi * 2 * i / length) * 32767) for i in range(length)]) +dac = audioio.AudioOut(board.A0) +dac.play(audiocore.RawSample(s16, sample_rate=8000), loop=True) +``` + +2. While the tone is playing, press **Ctrl-C** then **Ctrl-D** (soft reset). + +**Expected:** +- **Ctrl-C** interrupts the Python code but the tone *keeps playing* — this is normal. The DMA and TIM6 run in hardware independently of Python; a `KeyboardInterrupt` does not stop them. +- **Ctrl-D** triggers a soft reset which calls `audioout_reset()`. The tone stops immediately and the board returns to the `>>>` prompt with no crash or fault. +- Running any of the above tests again afterwards should work normally. + +## Oscilloscope Checks (Optional) + +Each test script drives `board.D4` (pin D4) low at the start of each playback and high when it ends. This provides a clean trigger edge for a scope. + +- **Test 1:** Probe A0 — should show a sampled waveform at the correct sample rate. Probe D4 for a gate signal that spans the file duration. +- **Test 3:** Probe A0 — should show a 440 Hz staircase-sine at the DAC output (12-bit steps visible at 44.1 kHz; fewer at 8 kHz). A simple RC low-pass filter (1 kΩ + 100 nF) on the A0 output will smooth the staircase significantly. + +## Known Limitations + +- **Right channel / stereo output** is not implemented. Passing `right_channel` to `AudioOut()` raises `ValueError: Stereo not supported on this board`. +- **Only pin A0 (PA04)** is supported as the left channel. Any other pin raises `ValueError: AudioOut requires pin A0 (PA04)`. +- **24-bit WAV files** are not supported by `audiocore.WaveFile` and will raise `OSError` when opened. +- Only one `AudioOut` instance can be active at a time (single DAC channel). diff --git a/tests/circuitpython-manual/audioio/TESTING.md b/tests/circuitpython-manual/audioio/TESTING.md new file mode 100644 index 00000000000..d8362a31e9f --- /dev/null +++ b/tests/circuitpython-manual/audioio/TESTING.md @@ -0,0 +1,255 @@ +# Testing: STM32F405 / STM32F407 DAC AudioOut + +These tests exercise the DAC-based `audioio.AudioOut` implementation added for STM32F405xx and STM32F407xx. + +## Automated vs Manual Tests + +| Test | Automated | Requires audio/scope | +|------|-----------|----------------------| +| 1 — WAV File Playback | Yes | Yes (audio check) | +| 2 — Pause / Resume | Yes | Yes (audio check) | +| 3 — Looping Sine Wave | Yes | Yes (audio check) | +| 4 — Soft Reset Cleanup | No (manual Ctrl-C/D) | No | +| 5 — deinit and Re-init | Yes | No | + +`run_serial_tests.py` automates Tests 1, 2, 3, and 5: it copies the necessary +files to the board and runs each script over the serial REPL, comparing the +printed output to the expected patterns. You still need to listen to the audio +(and optionally use an oscilloscope) for the audio-quality checks. + +### Quick start + +```bash +# Install the one dependency (if not already present) +pip install pyserial + +# Run all automated tests (board must be connected and CIRCUITPY mounted) +python3 tests/circuitpython-manual/audioio/run_serial_tests.py + +# Skip file copy if files are already on the board +python3 tests/circuitpython-manual/audioio/run_serial_tests.py --no-copy + +# Override the serial port or CIRCUITPY path +python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ + --port /dev/cu.usbmodem1234 \ + --circuitpy /Volumes/CIRCUITPY + +# Run only specific tests +python3 tests/circuitpython-manual/audioio/run_serial_tests.py --tests 3,5 +``` + +The script exits 0 if all selected tests pass, 1 otherwise — suitable for CI. + +--- + +## Hardware Required + +- An STM32F405 or STM32F407 board running the freshly-built firmware (e.g. Feather STM32F405 Express). +- A passive speaker or audio amplifier connected to **pin A0 (PA04, DAC channel 1)** and GND. + - A simple test: 100 Ω resistor in series with a small speaker between A0 and GND. + - For better audio: connect A0 to a small amp module (e.g. PAM8403) then to a speaker. +- Optional: an oscilloscope or logic analyser probe on **D4** (used as a trigger output by the test scripts). +- A USB cable for REPL/filesystem access (CircuitPython storage must not be read-only). + +## Build + +Enable the feature by building for an F405 or F407 target: + +``` +make -C ports/stm BOARD=feather_stm32f405_express -j CROSS_COMPILE=~/arm-toolchain/arm-gnu-toolchain-14.3.rel1-darwin-arm64-arm-none-eabi/bin/arm-none-eabi- +``` + +`CIRCUITPY_AUDIOIO` is now set to `1` automatically for those variants. Verify it is present in the build: + +``` +grep CIRCUITPY_AUDIOIO ports/stm/build-feather_stm32f405_express/mpconfigport.mk +# Expected output: CIRCUITPY_AUDIOIO = 1 +``` + +Flash the resulting `.bin` to the board using your preferred method (e.g. `dfu-util`). + +## File Setup + +> **If using `run_serial_tests.py`** this step is done automatically — skip ahead. + +Copy the WAV test samples onto the board's `CIRCUITPY` drive root: + +``` +cp \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-8bit-mono-unsigned.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-mono-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-mono-signed.wav \ + /Volumes/CIRCUITPY/ +``` + +These three files (~447 KB total) cover every exercised code path: +- `8000-8bit-mono-unsigned` — 8-bit unsigned decode path, audibly lo-fi +- `8000-16bit-mono-signed` — 16-bit signed decode path at lowest sample rate +- `44100-16bit-mono-signed` — 16-bit at highest sample rate (DMA reconfiguration, audible quality difference) + +Stereo, 24-bit, and the 16 kHz files are omitted: stereo and 24-bit will `OSError`; 16 kHz adds no new code paths over 8 kHz and 44.1 kHz. + +Copy the three test scripts to the board as well (or paste them into the REPL): + +``` +cp tests/circuitpython-manual/audioio/wavefile_playback.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/wavefile_pause_resume.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/single_buffer_loop.py /Volumes/CIRCUITPY/ +``` + +## Test 1 — WAV File Playback (`wavefile_playback.py`) *(automated)* + +Verifies that `AudioOut` can play WAV files at 8 kHz, 16 kHz, and 44.1 kHz in mono and stereo (only left channel output), with 8-bit unsigned and 16-bit signed encodings. + +**Note:** 24-bit WAV files and the stereo MP3 are intentionally excluded — `audiocore.WaveFile` does not support 24-bit, and those files will print an `OSError`. That is expected. + +**Run from the REPL:** + +```python +import os +os.chdir("/") +exec(open("wavefile_playback.py").read()) +``` + +**Expected output (order may vary by filename sort):** + +``` +playing jeplayer-splash-44100-16bit-mono-signed.wav +playing jeplayer-splash-8000-16bit-mono-signed.wav +playing jeplayer-splash-8000-8bit-mono-unsigned.wav +done +``` + +**What to listen for:** + +- Each supported WAV plays the "jeplayer splash" jingle to completion before the next starts. +- No loud pops at the start or end of each file (the DAC ramp-in / ramp-out should suppress them). +- Audio pitch should match the sample rate: the 44100 Hz file sounds the most natural; the 8000 Hz file sounds lower fidelity. + +## Test 2 — Pause and Resume (`wavefile_pause_resume.py`) *(automated)* + +Verifies `AudioOut.pause()` / `AudioOut.resume()` by toggling every 100 ms during playback. The audio will sound choppy — that is intentional. + +**Run from the REPL:** + +```python +exec(open("wavefile_pause_resume.py").read()) +``` + +**Expected output (repeating for each WAV):** + +``` +playing with pause/resume: jeplayer-splash-44100-16bit-mono-signed.wav + paused + resumed + ... +playing with pause/resume: jeplayer-splash-8000-16bit-mono-signed.wav + paused + resumed + ... +playing with pause/resume: jeplayer-splash-8000-8bit-mono-unsigned.wav + paused + resumed + ... +done +``` + +**What to verify:** + +- The REPL prints alternating "paused" / "resumed" lines. +- Audio cuts in and out in sync with the prints. +- Playback eventually completes (the `while dac.playing` loop exits normally). +- No hard fault or hang. + +## Test 3 — Looping Sine Wave (`single_buffer_loop.py`) *(automated)* + +Verifies `RawSample` with `loop=True` and tests all four sample formats: +`unsigned 8-bit`, `signed 8-bit`, `unsigned 16-bit`, `signed 16-bit`. + +Each sample generates one cycle of a 440 Hz sine wave and loops for 1 second. + +**Run from the REPL:** + +```python +exec(open("single_buffer_loop.py").read()) +``` + +**Expected output:** + +``` +unsigned 8 bit + +signed 8 bit + +unsigned 16 bit + +signed 16 bit + +done +``` + +**What to listen for:** + +- A 440 Hz tone (concert A) for approximately 1 second for each format. +- All four formats should sound essentially identical in pitch and volume. +- No pops or glitches during the loop. +- Clean silence between tones (quiescent DAC value holds between `stop()` calls). + +## Test 4 — Soft Reset Cleanup *(manual)* + +Verifies that `audioout_reset()` properly cleans up when the REPL soft-resets during active playback. + +1. Start a looping tone in the REPL: + +```python +import audiocore, audioio, board, array, math, time +length = 8000 // 440 +s16 = array.array("h", [int(math.sin(math.pi * 2 * i / length) * 32767) for i in range(length)]) +dac = audioio.AudioOut(board.A0) +dac.play(audiocore.RawSample(s16, sample_rate=8000), loop=True) +``` + +2. While the tone is playing, press **Ctrl-C** then **Ctrl-D** (soft reset). + +**Expected:** +- **Ctrl-C** interrupts the Python code but the tone *keeps playing* — this is normal. The DMA and TIM6 run in hardware independently of Python; a `KeyboardInterrupt` does not stop them. +- **Ctrl-D** triggers a soft reset which calls `audioout_reset()`. The tone stops immediately and the board returns to the `>>>` prompt with no crash or fault. +- Running any of the above tests again afterwards should work normally. + +## Test 5 — `deinit` and Re-init *(automated)* + +Verifies that `AudioOut` can be deconstructed and reconstructed without rebooting, and that pin A0 is properly released. + +```python +import audioio, analogio, board + +# Construct and immediately deinit AudioOut +dac = audioio.AudioOut(board.A0) +dac.deinit() + +# PA04 should now be free for AnalogOut +aout = analogio.AnalogOut(board.A0) +aout.value = 32768 # mid-scale +aout.deinit() + +# Re-create AudioOut on the same pin +dac2 = audioio.AudioOut(board.A0) +dac2.deinit() +print("pass") +``` + +**Expected output:** `pass` with no exceptions. + +## Oscilloscope Checks (Optional) + +Each test script drives `board.D4` (pin D4) low at the start of each playback and high when it ends. This provides a clean trigger edge for a scope. + +- **Test 1:** Probe A0 — should show a sampled waveform at the correct sample rate. Probe D4 for a gate signal that spans the file duration. +- **Test 3:** Probe A0 — should show a 440 Hz staircase-sine at the DAC output (12-bit steps visible at 44.1 kHz; fewer at 8 kHz). + +## Known Limitations + +- **Right channel / stereo output** is not implemented. Passing `right_channel` to `AudioOut()` raises `ValueError: Stereo not supported on this board`. +- **Only pin A0 (PA04)** is supported as the left channel. Any other pin raises `ValueError: AudioOut requires pin A0 (PA04)`. +- **24-bit WAV files** are not supported by `audiocore.WaveFile` and will raise `OSError` when opened. +- Only one `AudioOut` instance can be active at a time (single DAC channel). diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py new file mode 100644 index 00000000000..577be071c62 --- /dev/null +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -0,0 +1,280 @@ +#!/usr/bin/env python3 +""" +run_serial_tests.py — Automated REPL-based tests for STM32F405 audioio. + +Automates Tests 1, 2, 3, and 4 from README.md by: + 1. Copying WAV files and test scripts to the board via mpremote. + 2. Running each test on the device via the CircuitPython REPL. + 3. Comparing captured output to expected patterns and reporting PASS/FAIL. + +Test 5 (soft-reset cleanup) still requires manual interaction. + +Usage: + python3 run_serial_tests.py + python3 run_serial_tests.py --port /dev/cu.usbmodemXXX + python3 run_serial_tests.py --no-copy --tests 3,4 + +Requirements: + pip install mpremote +""" + +import argparse +import os +import subprocess +import sys + +# --------------------------------------------------------------------------- +# Paths +# --------------------------------------------------------------------------- +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +REPO_ROOT = os.path.abspath(os.path.join(SCRIPT_DIR, "../../..")) +AUDIOCORE_DIR = os.path.join(REPO_ROOT, "tests", "circuitpython-manual", "audiocore") + +WAV_FILES = [ + "jeplayer-splash-8000-8bit-mono-unsigned.wav", + "jeplayer-splash-8000-16bit-mono-signed.wav", + "jeplayer-splash-44100-16bit-mono-signed.wav", +] + +TEST_SCRIPTS = [ + "wavefile_playback.py", + "wavefile_pause_resume.py", + "single_buffer_loop.py", +] + +DEINIT_TEST_CODE = ( + "import audioio, analogio, board\n" + "dac = audioio.AudioOut(board.A0)\n" + "dac.deinit()\n" + "aout = analogio.AnalogOut(board.A0)\n" + "aout.value = 32768\n" + "aout.deinit()\n" + "dac2 = audioio.AudioOut(board.A0)\n" + "dac2.deinit()\n" + 'print("pass")\n' +) + +# --------------------------------------------------------------------------- +# mpremote helpers +# --------------------------------------------------------------------------- + +def _mpremote(args: list, timeout: float = 30.0): + """Run an mpremote command, return (stdout, stderr). Raises on timeout.""" + try: + result = subprocess.run( + ["mpremote"] + args, + capture_output=True, + text=True, + timeout=timeout, + ) + return result.stdout, result.stderr + except subprocess.TimeoutExpired: + raise TimeoutError(f"mpremote timed out after {timeout}s") + except FileNotFoundError: + sys.exit("mpremote not found. Run: pip install mpremote") + + +def find_port() -> str: + """Return the port of the first Adafruit device found by mpremote devs.""" + stdout, _ = _mpremote(["devs"]) + for line in stdout.splitlines(): + parts = line.split() + if not parts: + continue + # mpremote devs output: + # Filter for Adafruit VID (239a) + if any("239a" in p for p in parts): + return parts[0] + # Fall back to any USB serial port that isn't Bluetooth/wlan + for line in stdout.splitlines(): + parts = line.split() + if parts and parts[0].startswith("/dev/") and "Bluetooth" not in line and "wlan" not in line: + return parts[0] + raise RuntimeError( + "No board detected. Connect the board and/or pass --port.\n" + f"mpremote devs output:\n{stdout}" + ) + + +def copy_files(port: str): + """Copy WAV samples and test scripts to the board.""" + print("Copying files to board ...") + files = ( + [(os.path.join(AUDIOCORE_DIR, w), w) for w in WAV_FILES] + + [(os.path.join(SCRIPT_DIR, s), s) for s in TEST_SCRIPTS] + ) + missing = [] + for src, dst in files: + if not os.path.exists(src): + missing.append(src) + continue + stdout, stderr = _mpremote( + ["connect", port, "fs", "cp", src, f":{dst}"], timeout=30 + ) + # mpremote prints "Up to date: " if unchanged, "cp ..." otherwise + status = "up to date" if "Up to date" in stdout else "copied" + print(f" {dst} ({status})") + if missing: + print("WARNING: source files not found:") + for m in missing: + print(f" {m}") + print() + + +# --------------------------------------------------------------------------- +# Test runner +# --------------------------------------------------------------------------- + +PASS_TAG = "PASS" +FAIL_TAG = "FAIL" + + +def _check(condition: bool, message: str) -> bool: + print(f" [{PASS_TAG if condition else FAIL_TAG}] {message}") + return condition + + +def _run_exec(port: str, code: str, label: str, timeout: float): + """Execute *code* on the device via mpremote exec and print the output.""" + print(f"\n{'=' * 60}") + print(f" {label}") + print("=" * 60) + try: + stdout, stderr = _mpremote(["connect", port, "exec", code], timeout=timeout) + except TimeoutError as exc: + print(f" [FAIL] {exc}") + return False, "", "" + print("Output:") + for line in stdout.splitlines(): + print(f" {line}") + if stderr: + print("Stderr:") + for line in stderr.splitlines(): + print(f" {line}") + return True, stdout, stderr + + +# --------------------------------------------------------------------------- +# Individual tests +# --------------------------------------------------------------------------- + +def test1_wavefile_playback(port: str) -> bool: + code = 'import os; os.chdir("/")\nexec(open("wavefile_playback.py").read())' + ok, stdout, stderr = _run_exec( + port, code, "Test 1 — WAV File Playback (wavefile_playback.py)", timeout=180 + ) + if not ok: + return False + passed = True + passed &= _check("playing jeplayer-splash-44100-16bit-mono-signed.wav" in stdout, "44100 Hz 16-bit mono WAV played") + passed &= _check("playing jeplayer-splash-8000-16bit-mono-signed.wav" in stdout, "8000 Hz 16-bit mono WAV played") + passed &= _check("playing jeplayer-splash-8000-8bit-mono-unsigned.wav" in stdout, "8000 Hz 8-bit unsigned WAV played") + passed &= _check("done" in stdout, "Script completed with 'done'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +def test2_pause_resume(port: str) -> bool: + code = 'exec(open("wavefile_pause_resume.py").read())' + ok, stdout, stderr = _run_exec( + port, code, "Test 2 — Pause / Resume (wavefile_pause_resume.py)", timeout=180 + ) + if not ok: + return False + passed = True + for wav in sorted(WAV_FILES): + passed &= _check(f"playing with pause/resume: {wav}" in stdout, f"pause/resume header for {wav}") + passed &= _check("paused" in stdout, "At least one 'paused' line printed") + passed &= _check("resumed" in stdout, "At least one 'resumed' line printed") + passed &= _check("done" in stdout, "Script completed with 'done'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +def test3_single_buffer_loop(port: str) -> bool: + code = 'exec(open("single_buffer_loop.py").read())' + ok, stdout, stderr = _run_exec( + port, code, "Test 3 — Looping Sine Wave (single_buffer_loop.py)", timeout=30 + ) + if not ok: + return False + passed = True + for label in ("unsigned 8 bit", "signed 8 bit", "unsigned 16 bit", "signed 16 bit"): + passed &= _check(label in stdout, f"'{label}' label printed") + passed &= _check("done" in stdout, "Script completed with 'done'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +def test4_deinit(port: str) -> bool: + ok, stdout, stderr = _run_exec( + port, DEINIT_TEST_CODE, "Test 4 — deinit and Re-init (inline)", timeout=10 + ) + if not ok: + return False + passed = True + passed &= _check("pass" in stdout, "Script printed 'pass'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + +# --------------------------------------------------------------------------- +# Main +# --------------------------------------------------------------------------- + +def main(): + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument("--port", help="Serial port (auto-detected if omitted)") + parser.add_argument( + "--no-copy", + action="store_true", + help="Skip copying files to the board (assume they are already present)", + ) + parser.add_argument( + "--tests", + default="1,2,3,4", + help="Comma-separated list of test numbers to run (default: 1,2,3,4)", + ) + args = parser.parse_args() + + selected = set(args.tests.split(",")) + + port = args.port or find_port() + print(f"Using port: {port}\n") + + if not args.no_copy: + copy_files(port) + + results: dict[str, bool] = {} + if "1" in selected: + results["Test 1 — WAV Playback"] = test1_wavefile_playback(port) + if "2" in selected: + results["Test 2 — Pause/Resume"] = test2_pause_resume(port) + if "3" in selected: + results["Test 3 — Looping Sine"] = test3_single_buffer_loop(port) + if "4" in selected: + results["Test 4 — deinit/Re-init"] = test4_deinit(port) + + print(f"\n{'=' * 60}") + print("SUMMARY") + print("=" * 60) + all_passed = True + for name, passed in results.items(): + print(f" [{'PASS' if passed else 'FAIL'}] {name}") + all_passed = all_passed and passed + + print() + if all_passed: + print("All automated tests passed.") + print("Remaining manual step: Test 5 (soft-reset) and audio/oscilloscope verification.") + sys.exit(0) + else: + print("One or more tests FAILED — see details above.") + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/tests/circuitpython-manual/audioio/single_buffer_loop.py b/tests/circuitpython-manual/audioio/single_buffer_loop.py new file mode 100644 index 00000000000..bce6a7a2cf3 --- /dev/null +++ b/tests/circuitpython-manual/audioio/single_buffer_loop.py @@ -0,0 +1,58 @@ +import audiocore +import audioio +import board +import digitalio +import array +import time +import math + +# Optional trigger pin for oscilloscope synchronisation. +try: + trigger = digitalio.DigitalInOut(board.D4) + trigger.switch_to_output(True) +except AttributeError: + trigger = None + +# Generate one period of a 440 Hz sine wave at each sample rate. +sample_rate = 8000 +length = sample_rate // 440 # samples per cycle + +sample_names = ["unsigned 8 bit", "signed 8 bit", "unsigned 16 bit", "signed 16 bit"] + +# unsigned 8 bit +u8 = array.array("B", [0] * length) +for i in range(length): + u8[i] = int(math.sin(math.pi * 2 * i / length) * 127 + 128) +samples = [audiocore.RawSample(u8, sample_rate=8000)] + +# signed 8 bit +s8 = array.array("b", [0] * length) +for i in range(length): + s8[i] = int(math.sin(math.pi * 2 * i / length) * 127) +samples.append(audiocore.RawSample(s8, sample_rate=16000)) + +# unsigned 16 bit +u16 = array.array("H", [0] * length) +for i in range(length): + u16[i] = int(math.sin(math.pi * 2 * i / length) * 32767 + 32768) +samples.append(audiocore.RawSample(u16, sample_rate=8000)) + +# signed 16 bit +s16 = array.array("h", [0] * length) +for i in range(length): + s16[i] = int(math.sin(math.pi * 2 * i / length) * 32767) +samples.append(audiocore.RawSample(s16, sample_rate=44100)) + +dac = audioio.AudioOut(board.A0) +for sample, name in zip(samples, sample_names): + print(name) + if trigger: trigger.value = False + dac.play(sample, loop=True) + time.sleep(1) + dac.stop() + time.sleep(0.1) + if trigger: trigger.value = True + print() + +dac.deinit() +print("done") diff --git a/tests/circuitpython-manual/audioio/wavefile_pause_resume.py b/tests/circuitpython-manual/audioio/wavefile_pause_resume.py new file mode 100644 index 00000000000..13a227c0274 --- /dev/null +++ b/tests/circuitpython-manual/audioio/wavefile_pause_resume.py @@ -0,0 +1,53 @@ +import audiocore +import audioio +import board +import digitalio +import time +import os + +# Optional trigger pin for oscilloscope synchronisation. +try: + trigger = digitalio.DigitalInOut(board.D4) + trigger.switch_to_output(True) +except AttributeError: + trigger = None + +sample_prefix = "jeplayer-splash" + +samples = [] +for fn in os.listdir("/"): + if fn.startswith(sample_prefix): + samples.append(fn) + +if not samples: + print("No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board.") + +dac = audioio.AudioOut(board.A0) +for filename in sorted(samples): + print("playing with pause/resume:", filename) + with open(filename, "rb") as sample_file: + try: + sample = audiocore.WaveFile(sample_file) + except OSError as e: + print(e) + continue + if trigger: trigger.value = False + dac.play(sample) + # Deliberately toggle pause/resume every 100 ms to stress-test the + # pause/resume cycle. Audio will sound choppy — that is expected. + while dac.playing: + time.sleep(0.1) + if not dac.playing: # may have finished during sleep + break + if not dac.paused: + dac.pause() + print(" paused") + else: + dac.resume() + print(" resumed") + if trigger: trigger.value = True + time.sleep(0.1) + print() + +dac.deinit() +print("done") diff --git a/tests/circuitpython-manual/audioio/wavefile_playback.py b/tests/circuitpython-manual/audioio/wavefile_playback.py new file mode 100644 index 00000000000..fa1fa971309 --- /dev/null +++ b/tests/circuitpython-manual/audioio/wavefile_playback.py @@ -0,0 +1,45 @@ +import audiocore +import audioio +import board +import digitalio +import time +import os + +# Optional trigger pin for oscilloscope synchronisation. +try: + trigger = digitalio.DigitalInOut(board.D4) + trigger.switch_to_output(True) +except AttributeError: + trigger = None + +# List WAV files from the audiocore test samples directory on the device. +# Copy tests/circuitpython-manual/audiocore/*.wav to the board's filesystem. +sample_prefix = "jeplayer-splash" + +samples = [] +for fn in os.listdir("/"): + if fn.startswith(sample_prefix): + samples.append(fn) + +if not samples: + print("No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board.") + +dac = audioio.AudioOut(board.A0) +for filename in sorted(samples): + print("playing", filename) + with open(filename, "rb") as sample_file: + try: + sample = audiocore.WaveFile(sample_file) + except OSError as e: + print(e) + continue + if trigger: trigger.value = False + dac.play(sample) + while dac.playing: + time.sleep(0.1) + if trigger: trigger.value = True + time.sleep(0.1) + print() + +dac.deinit() +print("done") From ec21af4b39e9637e11fb048737effdc6e4be0d5f Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Mon, 6 Apr 2026 21:53:16 -0700 Subject: [PATCH 439/876] ports/stm: add stereo output via DAC CH2 (PA05/A1) for STM32F405 Enable right-channel audio output on PA05 (DAC_CH2) using DMA1 Stream6 Channel7, triggered by the same TIM6 as the left channel. Mono sources are duplicated to both channels when right_channel is provided. Co-Authored-By: Claude Opus 4.6 (1M context) --- ports/stm/common-hal/audioio/AudioOut.c | 183 ++++++++++++++++++++---- ports/stm/common-hal/audioio/AudioOut.h | 14 +- 2 files changed, 161 insertions(+), 36 deletions(-) diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index 34252cfe287..e4c3a70e860 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -97,28 +97,32 @@ static void dac_ramp(uint32_t from_12, uint32_t to_12) { // Convert a buffer of audio samples into 12-bit unsigned DAC values and write // them into dest[]. Returns the number of DAC samples written. // -// src - raw sample bytes from audiosample_get_buffer -// src_len - byte length of src -// dest - output array of 12-bit DAC values (uint16_t) -// dest_count - capacity of dest in samples +// src - raw sample bytes from audiosample_get_buffer +// src_len - byte length of src +// dest - output array of 12-bit DAC values (uint16_t) +// dest_count - capacity of dest in samples // bytes_per_sample - 1 or 2 // samples_signed - true if source samples are signed -// channel_count - 1 (mono) or 2 (stereo); only channel 0 (L) is output +// channel_count - 1 (mono) or 2 (stereo) +// channel_offset - 0 for left/mono, 1 for right channel of a stereo stream // quiescent_12 - value to pad with if src runs short static uint32_t convert_to_dac12( const uint8_t *src, uint32_t src_len, uint16_t *dest, uint32_t dest_count, uint8_t bytes_per_sample, bool samples_signed, - uint8_t channel_count, uint16_t quiescent_12) { + uint8_t channel_count, uint8_t channel_offset, + uint16_t quiescent_12) { - // src_stride: bytes between consecutive left-channel samples + // src_stride: bytes between consecutive samples of the same channel uint32_t src_stride = (uint32_t)bytes_per_sample * channel_count; + // src_offset: byte offset to the desired channel within each frame + uint32_t src_offset = (uint32_t)bytes_per_sample * channel_offset; uint32_t src_frames = src_len / src_stride; uint32_t frames = (src_frames < dest_count) ? src_frames : dest_count; if (bytes_per_sample == 1) { for (uint32_t i = 0; i < frames; i++) { - uint8_t u8 = src[i * src_stride]; + uint8_t u8 = src[i * src_stride + src_offset]; if (samples_signed) { // signed 8-bit: -128..127 → 0..4080 dest[i] = (uint16_t)((int16_t)(int8_t)u8 + 128) << 4; @@ -130,7 +134,7 @@ static uint32_t convert_to_dac12( } else { for (uint32_t i = 0; i < frames; i++) { uint16_t u16; - memcpy(&u16, src + i * src_stride, 2); + memcpy(&u16, src + i * src_stride + src_offset, 2); if (samples_signed) { // signed 16-bit: -32768..32767 → 0..4095 dest[i] = (uint16_t)((int32_t)(int16_t)u16 + 0x8000) >> 4; @@ -156,7 +160,10 @@ static uint32_t convert_to_dac12( // delivers data in fixed-byte chunks (256 bytes) that may be smaller than the // half-buffer in samples (e.g. 128 samples for 16-bit audio vs 256 slots). static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { - uint16_t *dest = self->dma_buffer + ((uint32_t)half * AUDIOOUT_DMA_HALF_SAMPLES); + uint16_t *dest_l = self->dma_buffer + ((uint32_t)half * AUDIOOUT_DMA_HALF_SAMPLES); + uint16_t *dest_r = self->dma_buffer_r + ? self->dma_buffer_r + ((uint32_t)half * AUDIOOUT_DMA_HALF_SAMPLES) + : NULL; uint16_t quiescent_12 = self->quiescent_value >> 4; uint32_t filled = 0; @@ -168,7 +175,10 @@ static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { if (result == GET_BUFFER_ERROR) { for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { - dest[i] = quiescent_12; + dest_l[i] = quiescent_12; + if (dest_r) { + dest_r[i] = quiescent_12; + } } self->stopping = true; return; @@ -176,9 +186,20 @@ static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { uint32_t written = convert_to_dac12( src_buf, src_len, - dest + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, + dest_l + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, self->bytes_per_sample, self->samples_signed, - self->channel_count, quiescent_12); + self->channel_count, 0, quiescent_12); + + if (dest_r) { + // Right channel: use channel_offset=1 for stereo, or 0 if the + // source is unexpectedly mono (duplicate left into right). + uint8_t r_offset = (self->channel_count >= 2) ? 1 : 0; + convert_to_dac12( + src_buf, src_len, + dest_r + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, + self->bytes_per_sample, self->samples_signed, + self->channel_count, r_offset, quiescent_12); + } filled += written; @@ -188,7 +209,10 @@ static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { // Continue filling the remainder of this half from the reset buffer. } else { for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { - dest[i] = quiescent_12; + dest_l[i] = quiescent_12; + if (dest_r) { + dest_r[i] = quiescent_12; + } } self->stopping = true; return; @@ -220,6 +244,12 @@ void DMA1_Stream5_IRQHandler(void) { } } +void DMA1_Stream6_IRQHandler(void) { + if (active_audioout && active_audioout->dma_buffer_r) { + HAL_DMA_IRQHandler(&active_audioout->dma_handle_r); + } +} + // HAL weak-symbol overrides: called from HAL_DMA_IRQHandler context. void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) { @@ -250,32 +280,40 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("No DAC on chip")); #else - // Right channel (stereo) support deferred to a future implementation. - if (right_channel != NULL) { - mp_raise_ValueError(MP_ERROR_TEXT("Stereo not supported on this board")); - } - - // Only PA04 (DAC_CH1) is supported. + // Only PA04 (DAC_CH1) is supported as left channel. if (left_channel != &pin_PA04) { mp_raise_ValueError(MP_ERROR_TEXT("AudioOut requires pin A0 (PA04)")); } + // Right channel must be PA05 (DAC_CH2 / A1) if provided. + if (right_channel != NULL && right_channel != &pin_PA05) { + mp_raise_ValueError(MP_ERROR_TEXT("AudioOut right channel requires pin A1 (PA05)")); + } + self->left_channel = left_channel; + self->right_channel = right_channel; self->quiescent_value = quiescent_value; self->sample = MP_OBJ_NULL; self->dma_buffer = NULL; + self->dma_buffer_r = NULL; memset(&self->dma_handle, 0, sizeof(self->dma_handle)); + memset(&self->dma_handle_r, 0, sizeof(self->dma_handle_r)); memset(&self->callback, 0, sizeof(self->callback)); self->stopping = false; self->paused = false; - // Configure PA04 for analog (DAC) mode. + // Configure PA04 (and PA05 if stereo) for analog (DAC) mode. GPIO_InitTypeDef gpio_init = {0}; gpio_init.Pin = pin_mask(left_channel->number); gpio_init.Mode = GPIO_MODE_ANALOG; gpio_init.Pull = GPIO_NOPULL; HAL_GPIO_Init(pin_port(left_channel->port), &gpio_init); + if (right_channel != NULL) { + gpio_init.Pin = pin_mask(right_channel->number); + HAL_GPIO_Init(pin_port(right_channel->port), &gpio_init); + } + // Initialise the shared DAC handle if it hasn't been set up yet // (i.e. AnalogOut hasn't been used since last reset). if (handle.Instance == NULL || handle.State == HAL_DAC_STATE_RESET) { @@ -300,8 +338,11 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, HAL_DAC_Start(&handle, DAC_CHANNEL_1); dac_ramp(0, quiescent_value >> 4); - // Claim the pin last so any error above doesn't leave it claimed. + // Claim pins last so any error above doesn't leave them claimed. common_hal_mcu_pin_claim(left_channel); + if (right_channel != NULL) { + common_hal_mcu_pin_claim(right_channel); + } #endif } @@ -320,13 +361,19 @@ void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t *self) { dac_ramp(self->quiescent_value >> 4, 0); HAL_DAC_Stop(&handle, DAC_CHANNEL_1); - // Restore channel 1 to no-trigger mode so AnalogOut can use it again. + // Restore channels to no-trigger mode so AnalogOut can use them again. DAC_ChannelConfTypeDef ch_cfg = {0}; ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + if (self->right_channel != NULL) { + HAL_DAC_Stop(&handle, DAC_CHANNEL_2); + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_2); + reset_pin_number(self->right_channel->port, self->right_channel->number); + self->right_channel = NULL; + } - // Release the pin. Let AnalogOut manage DAC clock disable. + // Release the left pin. Let AnalogOut manage DAC clock disable. reset_pin_number(self->left_channel->port, self->left_channel->number); self->left_channel = NULL; } @@ -353,13 +400,23 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, self->stopping = false; self->paused = false; - // Allocate the DMA circular buffer. + // Allocate DMA circular buffer(s). self->dma_buffer = (uint16_t *)m_malloc( AUDIOOUT_DMA_BUFFER_SAMPLES * sizeof(uint16_t)); if (!self->dma_buffer) { mp_raise_msg(&mp_type_MemoryError, MP_ERROR_TEXT("insufficient memory for audio buffer")); } + if (self->right_channel != NULL) { + self->dma_buffer_r = (uint16_t *)m_malloc( + AUDIOOUT_DMA_BUFFER_SAMPLES * sizeof(uint16_t)); + if (!self->dma_buffer_r) { + m_free(self->dma_buffer); + self->dma_buffer = NULL; + mp_raise_msg(&mp_type_MemoryError, + MP_ERROR_TEXT("insufficient memory for audio buffer")); + } + } // Pre-fill both halves before starting DMA. audiosample_reset_buffer(sample, false, 0); @@ -394,12 +451,19 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, HAL_TIMEx_MasterConfigSynchronization(&tim6_handle, &master_cfg); // --- DAC channel reconfiguration for DMA-triggered mode --- + // Stop single-mode DAC (started by stop() for quiescent output) before + // reconfiguring for DMA-triggered operation; otherwise the HAL state + // machine is left in BUSY and HAL_DAC_Start_DMA may reject the request. + HAL_DAC_Stop(&handle, DAC_CHANNEL_1); DAC_ChannelConfTypeDef ch_cfg = {0}; ch_cfg.DAC_Trigger = DAC_TRIGGER_T6_TRGO; ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + if (self->right_channel != NULL) { + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_2); + } - // --- DMA1 Stream5 Channel7 setup --- + // --- DMA1 Stream5 Channel7 setup (DAC CH1, left) --- __HAL_RCC_DMA1_CLK_ENABLE(); DMA_HandleTypeDef *hdma = &self->dma_handle; @@ -415,14 +479,35 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, hdma->Init.Priority = DMA_PRIORITY_HIGH; hdma->Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_Init(hdma); - - // Link DMA stream to DAC channel 1. __HAL_LINKDMA(&handle, DMA_Handle1, *hdma); HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 6, 0); + NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn); HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn); - // --- Start DMA transfer then timer --- + // --- DMA1 Stream6 Channel7 setup (DAC CH2, right) --- + if (self->right_channel != NULL) { + DMA_HandleTypeDef *hdma_r = &self->dma_handle_r; + memset(hdma_r, 0, sizeof(*hdma_r)); + hdma_r->Instance = DMA1_Stream6; + hdma_r->Init.Channel = DMA_CHANNEL_7; + hdma_r->Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_r->Init.PeriphInc = DMA_PINC_DISABLE; + hdma_r->Init.MemInc = DMA_MINC_ENABLE; + hdma_r->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; + hdma_r->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; + hdma_r->Init.Mode = DMA_CIRCULAR; + hdma_r->Init.Priority = DMA_PRIORITY_HIGH; + hdma_r->Init.FIFOMode = DMA_FIFOMODE_DISABLE; + HAL_DMA_Init(hdma_r); + __HAL_LINKDMA(&handle, DMA_Handle2, *hdma_r); + + HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 6, 0); + NVIC_ClearPendingIRQ(DMA1_Stream6_IRQn); + HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn); + } + + // --- Start DMA transfer(s) then timer --- active_audioout = self; if (HAL_DAC_Start_DMA(&handle, DAC_CHANNEL_1, @@ -431,11 +516,33 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, DAC_ALIGN_12B_R) != HAL_OK) { active_audioout = NULL; HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + if (self->right_channel != NULL) { + HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); + m_free(self->dma_buffer_r); + self->dma_buffer_r = NULL; + } m_free(self->dma_buffer); self->dma_buffer = NULL; mp_raise_RuntimeError(MP_ERROR_TEXT("DAC DMA start failed")); } + if (self->right_channel != NULL) { + if (HAL_DAC_Start_DMA(&handle, DAC_CHANNEL_2, + (uint32_t *)self->dma_buffer_r, + AUDIOOUT_DMA_BUFFER_SAMPLES, + DAC_ALIGN_12B_R) != HAL_OK) { + active_audioout = NULL; + HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_1); + HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); + m_free(self->dma_buffer); + self->dma_buffer = NULL; + m_free(self->dma_buffer_r); + self->dma_buffer_r = NULL; + mp_raise_RuntimeError(MP_ERROR_TEXT("DAC DMA start failed (right channel)")); + } + } + HAL_TIM_Base_Start(&tim6_handle); } @@ -447,11 +554,19 @@ void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) { // Stop the sample clock first so no more DMA requests are generated. TIM6->CR1 &= ~TIM_CR1_CEN; - // Stop DMA and DAC channel. + // Stop DMA and DAC channels. HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_1); HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn); + if (self->dma_buffer_r) { + HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_2); + HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); + NVIC_ClearPendingIRQ(DMA1_Stream6_IRQn); + m_free(self->dma_buffer_r); + self->dma_buffer_r = NULL; + } - // Free the DMA buffer. + // Free the left DMA buffer. if (self->dma_buffer) { m_free(self->dma_buffer); self->dma_buffer = NULL; @@ -510,6 +625,12 @@ void audioout_reset(void) { TIM6->CR1 &= ~TIM_CR1_CEN; HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_1); HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); + if (active_audioout->dma_buffer_r) { + HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_2); + HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); + m_free(active_audioout->dma_buffer_r); + active_audioout->dma_buffer_r = NULL; + } if (active_audioout->dma_buffer) { m_free(active_audioout->dma_buffer); active_audioout->dma_buffer = NULL; diff --git a/ports/stm/common-hal/audioio/AudioOut.h b/ports/stm/common-hal/audioio/AudioOut.h index 4b1cc388b85..4e0ffd70955 100644 --- a/ports/stm/common-hal/audioio/AudioOut.h +++ b/ports/stm/common-hal/audioio/AudioOut.h @@ -22,15 +22,19 @@ typedef struct { // Left channel pin (PA04 = DAC_CH1). NULL when deinited. const mcu_pin_obj_t *left_channel; - // right_channel (PA05 = DAC_CH2) deferred to a future implementation. + // Right channel pin (PA05 = DAC_CH2). NULL when mono. + const mcu_pin_obj_t *right_channel; - // DMA handle for DMA1 Stream5 Channel7 (DAC CH1). + // DMA handle for DMA1 Stream5 Channel7 (DAC CH1, left). + // DMA handle for DMA1 Stream6 Channel7 (DAC CH2, right). // The DAC handle is the shared file-scope handle from AnalogOut.c. DMA_HandleTypeDef dma_handle; + DMA_HandleTypeDef dma_handle_r; - // Circular DMA buffer: AUDIOOUT_DMA_BUFFER_SAMPLES uint16_t elements, + // Circular DMA buffers: AUDIOOUT_DMA_BUFFER_SAMPLES uint16_t elements each, // allocated on play() and freed on stop(). - uint16_t *dma_buffer; + uint16_t *dma_buffer; // left (CH1) + uint16_t *dma_buffer_r; // right (CH2), NULL when mono // Current audio sample object being played. mp_obj_t sample; @@ -43,7 +47,7 @@ typedef struct { // Sample format metadata, populated at play() time. uint8_t bytes_per_sample; // 1 (8-bit) or 2 (16-bit) bool samples_signed; - uint8_t channel_count; // 1 = mono, 2 = stereo (only L channel output) + uint8_t channel_count; // 1 = mono, 2 = stereo uint16_t quiescent_value; // 16-bit resting value (default 0x8000) // Background callback queued from DMA ISR, processed in main loop. From ff10e517adf32250349ff5b196e7c16748400f08 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Mon, 6 Apr 2026 21:53:38 -0700 Subject: [PATCH 440/876] tests: add stereo test and cross-platform support to audioio suite Add Test 5 (stereo_playback.py) for verifying dual-DAC output. Update run_serial_tests.py with cross-platform CIRCUITPY volume detection (macOS/Linux/Windows), direct filesystem copy via shutil, and Python 3.7+ compatibility via `from __future__ import annotations`. Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/circuitpython-manual/audioio/README.md | 72 +++++++++--- .../audioio/run_serial_tests.py | 108 +++++++++++++++--- .../audioio/stereo_playback.py | 50 ++++++++ 3 files changed, 201 insertions(+), 29 deletions(-) create mode 100644 tests/circuitpython-manual/audioio/stereo_playback.py diff --git a/tests/circuitpython-manual/audioio/README.md b/tests/circuitpython-manual/audioio/README.md index 596baebbe90..35c5f15518e 100644 --- a/tests/circuitpython-manual/audioio/README.md +++ b/tests/circuitpython-manual/audioio/README.md @@ -10,12 +10,13 @@ These tests exercise the DAC-based `audioio.AudioOut` implementation added for S | 2 — Pause / Resume | Yes | Yes (audio check) | | 3 — Looping Sine Wave | Yes | Yes (audio check) | | 4 — deinit and Re-init | Yes | No | -| 5 — Soft Reset Cleanup | No (manual Ctrl-C/D) | No | +| 5 — Stereo Playback | Yes | Yes (audio check) | +| 6 — Soft Reset Cleanup | No (manual Ctrl-C/D) | No | -`run_serial_tests.py` automates Tests 1, 2, 3, and 4: it copies the necessary -files to the board and runs each script over the serial REPL, comparing the -printed output to the expected patterns. You still need to listen to the audio -(and optionally use an oscilloscope) for the audio-quality checks. +`run_serial_tests.py` automates Tests 1–5: it copies the necessary files to the +board and runs each script over the serial REPL, comparing the printed output to +the expected patterns. You still need to listen to the audio (and optionally +use an oscilloscope) for the audio-quality checks. ### Quick start @@ -29,13 +30,19 @@ python3 tests/circuitpython-manual/audioio/run_serial_tests.py # Skip file copy if files are already on the board python3 tests/circuitpython-manual/audioio/run_serial_tests.py --no-copy -# Override the serial port or CIRCUITPY path +# Override the serial port or CIRCUITPY path (auto-detected on macOS/Linux/Windows) python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ --port /dev/cu.usbmodem1234 \ - --circuitpy /Volumes/CIRCUITPY + --circuitpy /Volumes/CIRCUITPY # macOS (auto-detected) +python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ + --port /dev/ttyACM0 \ + --circuitpy /media/user/CIRCUITPY # Linux (auto-detected) +python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ + --port COM5 \ + --circuitpy D:\ # Windows (auto-detected) # Run only specific tests -python3 tests/circuitpython-manual/audioio/run_serial_tests.py --tests 3,4 +python3 tests/circuitpython-manual/audioio/run_serial_tests.py --tests 3,4,5 ``` The script exits 0 if all selected tests pass, 1 otherwise — suitable for CI. @@ -79,22 +86,27 @@ cp \ tests/circuitpython-manual/audiocore/jeplayer-splash-8000-8bit-mono-unsigned.wav \ tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-mono-signed.wav \ tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-mono-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-stereo-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-stereo-signed.wav \ /Volumes/CIRCUITPY/ ``` -These three files (~447 KB total) cover every exercised code path: +These five files cover every exercised code path: - `8000-8bit-mono-unsigned` — 8-bit unsigned decode path, audibly lo-fi - `8000-16bit-mono-signed` — 16-bit signed decode path at lowest sample rate - `44100-16bit-mono-signed` — 16-bit at highest sample rate (DMA reconfiguration, audible quality difference) +- `8000-16bit-stereo-signed` — stereo decode path, left→A0, right→A1 +- `44100-16bit-stereo-signed` — stereo at 44.1 kHz Stereo, 24-bit, and the 16 kHz files are omitted: stereo and 24-bit will `OSError`; 16 kHz adds no new code paths over 8 kHz and 44.1 kHz. -Copy the three test scripts to the board as well (or paste them into the REPL): +Copy the test scripts to the board as well (or paste them into the REPL): ``` cp tests/circuitpython-manual/audioio/wavefile_playback.py /Volumes/CIRCUITPY/ cp tests/circuitpython-manual/audioio/wavefile_pause_resume.py /Volumes/CIRCUITPY/ cp tests/circuitpython-manual/audioio/single_buffer_loop.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/stereo_playback.py /Volumes/CIRCUITPY/ ``` ## Test 1 — WAV File Playback (`wavefile_playback.py`) *(automated)* @@ -219,7 +231,39 @@ print("pass") **Expected output:** `pass` with no exceptions. -## Test 5 — Soft Reset Cleanup *(manual)* +## Test 5 — Stereo Playback (`stereo_playback.py`) *(automated)* + +Verifies that `AudioOut(board.A0, right_channel=board.A1)` correctly splits a +stereo WAV file across both DAC channels: left audio on **A0 (PA04, DAC_CH1)** +and right audio on **A1 (PA05, DAC_CH2)**, both clocked by TIM6. + +**Hardware required:** connect a speaker or amp to both A0 and A1 (two separate +channels), or use an oscilloscope to probe each pin independently. + +**Run from the REPL:** + +```python +import os +os.chdir("/") +exec(open("stereo_playback.py").read()) +``` + +**Expected output:** + +``` +playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav +playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav +done +``` + +**What to listen / look for:** + +- Left and right channels play the correct sides of the stereo jingle. +- No cross-contamination between channels. +- On a scope: probe A0 and A1 simultaneously — waveforms should differ + (the splash sample is not phase-identical left/right). + +## Test 6 — Soft Reset Cleanup *(manual)* Verifies that `audioout_reset()` properly cleans up when the REPL soft-resets during active playback. @@ -249,7 +293,7 @@ Each test script drives `board.D4` (pin D4) low at the start of each playback an ## Known Limitations -- **Right channel / stereo output** is not implemented. Passing `right_channel` to `AudioOut()` raises `ValueError: Stereo not supported on this board`. -- **Only pin A0 (PA04)** is supported as the left channel. Any other pin raises `ValueError: AudioOut requires pin A0 (PA04)`. +- **Left channel must be A0 (PA04)**. Any other pin raises `ValueError: AudioOut requires pin A0 (PA04)`. +- **Right channel must be A1 (PA05)** when used. Any other pin raises `ValueError: AudioOut right channel requires pin A1 (PA05)`. - **24-bit WAV files** are not supported by `audiocore.WaveFile` and will raise `OSError` when opened. -- Only one `AudioOut` instance can be active at a time (single DAC channel). +- Only one `AudioOut` instance can be active at a time. diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py index 577be071c62..35b2c4630ac 100644 --- a/tests/circuitpython-manual/audioio/run_serial_tests.py +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -12,14 +12,20 @@ Usage: python3 run_serial_tests.py python3 run_serial_tests.py --port /dev/cu.usbmodemXXX + python3 run_serial_tests.py --circuitpy /Volumes/CIRCUITPY # macOS + python3 run_serial_tests.py --circuitpy /media/user/CIRCUITPY # Linux + python3 run_serial_tests.py --circuitpy D:\\ # Windows python3 run_serial_tests.py --no-copy --tests 3,4 Requirements: pip install mpremote """ +from __future__ import annotations + import argparse import os +import shutil import subprocess import sys @@ -34,12 +40,15 @@ "jeplayer-splash-8000-8bit-mono-unsigned.wav", "jeplayer-splash-8000-16bit-mono-signed.wav", "jeplayer-splash-44100-16bit-mono-signed.wav", + "jeplayer-splash-8000-16bit-stereo-signed.wav", + "jeplayer-splash-44100-16bit-stereo-signed.wav", ] TEST_SCRIPTS = [ "wavefile_playback.py", "wavefile_pause_resume.py", "single_buffer_loop.py", + "stereo_playback.py", ] DEINIT_TEST_CODE = ( @@ -96,9 +105,49 @@ def find_port() -> str: ) -def copy_files(port: str): +def find_circuitpy() -> str | None: + """Return the path to the mounted CIRCUITPY volume, or None if not found.""" + import platform + system = platform.system() + + if system == "Darwin": + candidates = ["/Volumes/CIRCUITPY"] + elif system == "Windows": + # Scan all drive letters for a CIRCUITPY volume label. + import string + import ctypes + candidates = [] + kernel32 = ctypes.windll.kernel32 # type: ignore[attr-defined] + buf = ctypes.create_unicode_buffer(256) + for letter in string.ascii_uppercase: + root = f"{letter}:\\" + if kernel32.GetVolumeInformationW(root, buf, 256, None, None, None, None, 0): + if buf.value == "CIRCUITPY": + candidates.append(root) + else: + # Linux: common udev/udisks mount points + candidates = ["/media/CIRCUITPY", "/run/media/CIRCUITPY"] + try: + import pwd + user = pwd.getpwuid(os.getuid()).pw_name + candidates.insert(0, f"/run/media/{user}/CIRCUITPY") + candidates.insert(0, f"/media/{user}/CIRCUITPY") + except Exception: + pass + + for path in candidates: + if os.path.isdir(path): + return path + return None + + +def copy_files(port: str, circuitpy: str | None = None): """Copy WAV samples and test scripts to the board.""" - print("Copying files to board ...") + mount = circuitpy or find_circuitpy() + if mount: + print(f"Copying files to board via {mount} ...") + else: + print("Copying files to board via mpremote ...") files = ( [(os.path.join(AUDIOCORE_DIR, w), w) for w in WAV_FILES] + [(os.path.join(SCRIPT_DIR, s), s) for s in TEST_SCRIPTS] @@ -108,12 +157,19 @@ def copy_files(port: str): if not os.path.exists(src): missing.append(src) continue - stdout, stderr = _mpremote( - ["connect", port, "fs", "cp", src, f":{dst}"], timeout=30 - ) - # mpremote prints "Up to date: " if unchanged, "cp ..." otherwise - status = "up to date" if "Up to date" in stdout else "copied" - print(f" {dst} ({status})") + if mount: + dest_path = os.path.join(mount, dst) + shutil.copy2(src, dest_path) + print(f" {dst} (copied)") + else: + stdout, stderr = _mpremote( + ["connect", port, "fs", "cp", src, f":/{dst}"], timeout=30 + ) + if stderr and "Error" in stderr: + print(f" {dst} (FAILED: {stderr.strip()})") + else: + status = "up to date" if "Up to date" in stdout else "copied" + print(f" {dst} ({status})") if missing: print("WARNING: source files not found:") for m in missing: @@ -159,7 +215,7 @@ def _run_exec(port: str, code: str, label: str, timeout: float): # --------------------------------------------------------------------------- def test1_wavefile_playback(port: str) -> bool: - code = 'import os; os.chdir("/")\nexec(open("wavefile_playback.py").read())' + code = 'exec(open("/wavefile_playback.py").read())' ok, stdout, stderr = _run_exec( port, code, "Test 1 — WAV File Playback (wavefile_playback.py)", timeout=180 ) @@ -175,7 +231,7 @@ def test1_wavefile_playback(port: str) -> bool: def test2_pause_resume(port: str) -> bool: - code = 'exec(open("wavefile_pause_resume.py").read())' + code = 'exec(open("/wavefile_pause_resume.py").read())' ok, stdout, stderr = _run_exec( port, code, "Test 2 — Pause / Resume (wavefile_pause_resume.py)", timeout=180 ) @@ -192,7 +248,7 @@ def test2_pause_resume(port: str) -> bool: def test3_single_buffer_loop(port: str) -> bool: - code = 'exec(open("single_buffer_loop.py").read())' + code = 'exec(open("/single_buffer_loop.py").read())' ok, stdout, stderr = _run_exec( port, code, "Test 3 — Looping Sine Wave (single_buffer_loop.py)", timeout=30 ) @@ -206,6 +262,21 @@ def test3_single_buffer_loop(port: str) -> bool: return passed +def test5_stereo_playback(port: str) -> bool: + code = 'exec(open("/stereo_playback.py").read())' + ok, stdout, stderr = _run_exec( + port, code, "Test 5 — Stereo Playback (stereo_playback.py)", timeout=180 + ) + if not ok: + return False + passed = True + passed &= _check("playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav" in stdout, "44100 Hz 16-bit stereo WAV played") + passed &= _check("playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav" in stdout, "8000 Hz 16-bit stereo WAV played") + passed &= _check("done" in stdout, "Script completed with 'done'") + passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") + return passed + + def test4_deinit(port: str) -> bool: ok, stdout, stderr = _run_exec( port, DEINIT_TEST_CODE, "Test 4 — deinit and Re-init (inline)", timeout=10 @@ -228,6 +299,11 @@ def main(): formatter_class=argparse.RawDescriptionHelpFormatter, ) parser.add_argument("--port", help="Serial port (auto-detected if omitted)") + parser.add_argument( + "--circuitpy", + metavar="PATH", + help="Path to mounted CIRCUITPY volume (auto-detected if omitted)", + ) parser.add_argument( "--no-copy", action="store_true", @@ -235,8 +311,8 @@ def main(): ) parser.add_argument( "--tests", - default="1,2,3,4", - help="Comma-separated list of test numbers to run (default: 1,2,3,4)", + default="1,2,3,4,5", + help="Comma-separated list of test numbers to run (default: 1,2,3,4,5)", ) args = parser.parse_args() @@ -246,7 +322,7 @@ def main(): print(f"Using port: {port}\n") if not args.no_copy: - copy_files(port) + copy_files(port, circuitpy=args.circuitpy) results: dict[str, bool] = {} if "1" in selected: @@ -257,6 +333,8 @@ def main(): results["Test 3 — Looping Sine"] = test3_single_buffer_loop(port) if "4" in selected: results["Test 4 — deinit/Re-init"] = test4_deinit(port) + if "5" in selected: + results["Test 5 — Stereo Playback"] = test5_stereo_playback(port) print(f"\n{'=' * 60}") print("SUMMARY") @@ -269,7 +347,7 @@ def main(): print() if all_passed: print("All automated tests passed.") - print("Remaining manual step: Test 5 (soft-reset) and audio/oscilloscope verification.") + print("Remaining manual step: Test 6 (soft-reset) and audio/oscilloscope verification.") sys.exit(0) else: print("One or more tests FAILED — see details above.") diff --git a/tests/circuitpython-manual/audioio/stereo_playback.py b/tests/circuitpython-manual/audioio/stereo_playback.py new file mode 100644 index 00000000000..c82e4ba40dd --- /dev/null +++ b/tests/circuitpython-manual/audioio/stereo_playback.py @@ -0,0 +1,50 @@ +import audiocore +import audioio +import board +import digitalio +import time +import os + +# Optional trigger pin for oscilloscope synchronisation. +try: + trigger = digitalio.DigitalInOut(board.D4) + trigger.switch_to_output(True) +except AttributeError: + trigger = None + +sample_prefix = "jeplayer-splash" + +samples = [] +for fn in os.listdir("/"): + if fn.startswith(sample_prefix): + samples.append(fn) + +if not samples: + print("No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board.") + +# Play each stereo WAV file through both DAC channels simultaneously. +# Left channel → A0 (PA04, DAC_CH1), Right channel → A1 (PA05, DAC_CH2). +dac = audioio.AudioOut(board.A0, right_channel=board.A1) +for filename in sorted(samples): + # Only play stereo files to exercise the right channel path. + if "stereo" not in filename: + continue + print("playing stereo:", filename) + with open(filename, "rb") as sample_file: + try: + sample = audiocore.WaveFile(sample_file) + except OSError as e: + print(e) + continue + if trigger: + trigger.value = False + dac.play(sample) + while dac.playing: + time.sleep(0.1) + if trigger: + trigger.value = True + time.sleep(0.1) + print() + +dac.deinit() +print("done") From 81467e58afc999cd5b328172d85bc4358b68a93d Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 26 Apr 2026 17:52:50 -0700 Subject: [PATCH 441/876] ports/stm: track source position across DMA half-fills in audioio load_dma_buffer_half() previously called audiosample_get_buffer() on every half-fill and discarded any unconsumed bytes. Sources that return buffers larger than AUDIOOUT_DMA_HALF_SAMPLES (e.g. a 4410-sample RawSample) had everything past the first half-buffer worth of samples silently dropped, producing the wrong waveform. Track src_ptr / src_remaining_len / src_done on the object so a single source buffer is consumed across as many half-fills as needed before the next get_buffer call. End-of-stream (GET_BUFFER_DONE) is handled on the next fill rather than mid-fill so any trailing data in the current buffer is played first. Co-Authored-By: Claude Opus 4.7 --- ports/stm/common-hal/audioio/AudioOut.c | 85 ++++++++++++++----------- ports/stm/common-hal/audioio/AudioOut.h | 6 ++ 2 files changed, 55 insertions(+), 36 deletions(-) diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index e4c3a70e860..a237ffbe101 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -155,69 +155,79 @@ static uint32_t convert_to_dac12( // Load one half of the DMA circular buffer from the audio sample source. // half: 0 = lower half (indices 0..HALF-1), 1 = upper half (HALF..END-1). // -// Loops get_buffer calls until the full AUDIOOUT_DMA_HALF_SAMPLES-sample slot -// is filled. This is necessary because the audio sample source (e.g. WaveFile) -// delivers data in fixed-byte chunks (256 bytes) that may be smaller than the -// half-buffer in samples (e.g. 128 samples for 16-bit audio vs 256 slots). +// Tracks position within the source buffer (src_ptr / src_remaining_len) +// across calls so that large source buffers (e.g. a 1024-sample RawSample) +// are consumed incrementally rather than re-reading from the start each time. static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { uint16_t *dest_l = self->dma_buffer + ((uint32_t)half * AUDIOOUT_DMA_HALF_SAMPLES); uint16_t *dest_r = self->dma_buffer_r ? self->dma_buffer_r + ((uint32_t)half * AUDIOOUT_DMA_HALF_SAMPLES) : NULL; uint16_t quiescent_12 = self->quiescent_value >> 4; + uint32_t src_stride = (uint32_t)self->bytes_per_sample * self->channel_count; uint32_t filled = 0; while (filled < AUDIOOUT_DMA_HALF_SAMPLES) { - uint8_t *src_buf; - uint32_t src_len; - audioio_get_buffer_result_t result = - audiosample_get_buffer(self->sample, false, 0, &src_buf, &src_len); - - if (result == GET_BUFFER_ERROR) { - for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { - dest_l[i] = quiescent_12; - if (dest_r) { - dest_r[i] = quiescent_12; + // Fetch new source data when the previous buffer is exhausted. + if (self->src_remaining_len == 0) { + // Handle end-of-stream from previous get_buffer call. + if (self->src_done) { + if (self->loop) { + audiosample_reset_buffer(self->sample, false, 0); + self->src_done = false; + } else { + for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { + dest_l[i] = quiescent_12; + if (dest_r) { + dest_r[i] = quiescent_12; + } + } + self->stopping = true; + return; } } - self->stopping = true; - return; + + uint8_t *buf; + uint32_t len; + audioio_get_buffer_result_t result = + audiosample_get_buffer(self->sample, false, 0, &buf, &len); + + if (result == GET_BUFFER_ERROR) { + for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { + dest_l[i] = quiescent_12; + if (dest_r) { + dest_r[i] = quiescent_12; + } + } + self->stopping = true; + return; + } + + self->src_ptr = buf; + self->src_remaining_len = len; + self->src_done = (result == GET_BUFFER_DONE); } uint32_t written = convert_to_dac12( - src_buf, src_len, + self->src_ptr, self->src_remaining_len, dest_l + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, self->bytes_per_sample, self->samples_signed, self->channel_count, 0, quiescent_12); if (dest_r) { - // Right channel: use channel_offset=1 for stereo, or 0 if the - // source is unexpectedly mono (duplicate left into right). uint8_t r_offset = (self->channel_count >= 2) ? 1 : 0; convert_to_dac12( - src_buf, src_len, + self->src_ptr, self->src_remaining_len, dest_r + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, self->bytes_per_sample, self->samples_signed, self->channel_count, r_offset, quiescent_12); } + // Advance source position by the amount consumed. + uint32_t bytes_consumed = written * src_stride; + self->src_ptr += bytes_consumed; + self->src_remaining_len -= bytes_consumed; filled += written; - - if (result == GET_BUFFER_DONE) { - if (self->loop) { - audiosample_reset_buffer(self->sample, false, 0); - // Continue filling the remainder of this half from the reset buffer. - } else { - for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { - dest_l[i] = quiescent_12; - if (dest_r) { - dest_r[i] = quiescent_12; - } - } - self->stopping = true; - return; - } - } } } @@ -399,6 +409,9 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, self->loop = loop; self->stopping = false; self->paused = false; + self->src_ptr = NULL; + self->src_remaining_len = 0; + self->src_done = false; // Allocate DMA circular buffer(s). self->dma_buffer = (uint16_t *)m_malloc( diff --git a/ports/stm/common-hal/audioio/AudioOut.h b/ports/stm/common-hal/audioio/AudioOut.h index 4e0ffd70955..5472ccb0c6e 100644 --- a/ports/stm/common-hal/audioio/AudioOut.h +++ b/ports/stm/common-hal/audioio/AudioOut.h @@ -55,6 +55,12 @@ typedef struct { // Which half of dma_buffer to refill next: 0 = lower, 1 = upper. volatile uint8_t buffer_half_to_fill; + + // Source buffer position tracking. Allows consuming large source buffers + // (e.g. RawSample > 256 samples) across multiple DMA half-fills. + const uint8_t *src_ptr; // current read position in source buffer + uint32_t src_remaining_len; // bytes remaining in current source buffer + bool src_done; // GET_BUFFER_DONE received for current buffer } audioio_audioout_obj_t; // Called from reset_port() to stop any active playback on soft-reset. From fcac2fc3f7c626356fed0d2570fb83d62cbf526d Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 26 Apr 2026 17:53:05 -0700 Subject: [PATCH 442/876] ports/stm: enlarge audioio DMA buffer to 2048 samples 256-sample halves left only ~5 ms of headroom before underrun at 44.1 kHz. USB enumeration, VFS sync and other main-loop work can exceed that, producing audible glitches. Bumping to 1024-sample halves (21 ms at 48 kHz) gives comfortable margin while still keeping total buffer memory at 4 KB per channel. Co-Authored-By: Claude Opus 4.7 --- ports/stm/common-hal/audioio/AudioOut.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ports/stm/common-hal/audioio/AudioOut.h b/ports/stm/common-hal/audioio/AudioOut.h index 5472ccb0c6e..6f47b2b1eea 100644 --- a/ports/stm/common-hal/audioio/AudioOut.h +++ b/ports/stm/common-hal/audioio/AudioOut.h @@ -13,9 +13,11 @@ // Total DMA circular buffer size in 16-bit samples. // Split into two halves; one half plays while the other is refilled. -// 512 samples at 44100 Hz = ~5.8 ms per half-buffer interrupt. -#define AUDIOOUT_DMA_BUFFER_SAMPLES 512 -#define AUDIOOUT_DMA_HALF_SAMPLES 256 +// 2048 samples at 48000 Hz = ~21 ms per half-buffer interrupt, which +// gives the main loop plenty of headroom against USB / VFS stalls +// before an underrun occurs. +#define AUDIOOUT_DMA_BUFFER_SAMPLES 2048 +#define AUDIOOUT_DMA_HALF_SAMPLES 1024 typedef struct { mp_obj_base_t base; From d112d01ed5520e81ccb3bf93dbfc17f22ed35b70 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 26 Apr 2026 17:53:20 -0700 Subject: [PATCH 443/876] ports/stm: round-to-nearest TIM6 period in audioio Truncating the divisor biased the realised sample rate slightly fast (e.g. 84 MHz / 44100 = 1904.76 truncated to 1904 yields 44117.6 Hz, ~0.7 cents sharp). Round to nearest so the rate is always the closest achievable, not the next one above. Co-Authored-By: Claude Opus 4.7 --- ports/stm/common-hal/audioio/AudioOut.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index a237ffbe101..575ce72510d 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -443,7 +443,9 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, __HAL_RCC_TIM6_CLK_ENABLE(); uint32_t tim6_clk = get_tim6_freq(); - uint32_t period = (tim6_clk / sample_rate); + // Round to nearest, not truncate, so the realised sample rate is the + // closest TIM6 division to the requested rate. + uint32_t period = (tim6_clk + sample_rate / 2) / sample_rate; if (period < 2) { period = 2; } From 53fef38ae39707b6ae72a9b8519be172889b075e Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 26 Apr 2026 17:56:06 -0700 Subject: [PATCH 444/876] ports/stm: ramp into first sample on audioio play start play() previously stopped the single-mode quiescent DAC output and went straight into DMA-driven mode. If dma_buffer[0] sat far from the quiescent value, the resulting jump produced an audible click at the start of every clip. Generalise dac_ramp() to either DAC channel and ramp from quiescent into dma_buffer[0] (and from 0 into dma_buffer_r[0] for the right channel) before reconfiguring for T6_TRGO. The pin already sits at the first DMA sample by the time the timer is started, so the transition into DMA output is seamless. Co-Authored-By: Claude Opus 4.7 --- ports/stm/common-hal/audioio/AudioOut.c | 28 ++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index 575ce72510d..9f8799f258b 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -66,9 +66,9 @@ static uint32_t get_tim6_freq(void) { #endif } -// Gently ramp the DAC CH1 output from from_12 to to_12 (both 12-bit, 0-4095) -// to avoid audible clicks. 64 steps, ~100 µs per step = ~6.4 ms total. -static void dac_ramp(uint32_t from_12, uint32_t to_12) { +// Gently ramp the given DAC channel output from from_12 to to_12 (both 12-bit, +// 0-4095) to avoid audible clicks. 64 steps, ~100 µs per step = ~6.4 ms total. +static void dac_ramp_channel(uint32_t channel, uint32_t from_12, uint32_t to_12) { if (from_12 == to_12) { return; } @@ -85,8 +85,8 @@ static void dac_ramp(uint32_t from_12, uint32_t to_12) { } else if (step < 0 && v <= (int32_t)to_12) { v = (int32_t)to_12; } - HAL_DAC_SetValue(&handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, (uint16_t)v); - HAL_DAC_Start(&handle, DAC_CHANNEL_1); + HAL_DAC_SetValue(&handle, channel, DAC_ALIGN_12B_R, (uint16_t)v); + HAL_DAC_Start(&handle, channel); mp_hal_delay_us(100); if (v == (int32_t)to_12) { break; @@ -94,6 +94,10 @@ static void dac_ramp(uint32_t from_12, uint32_t to_12) { } } +static inline void dac_ramp(uint32_t from_12, uint32_t to_12) { + dac_ramp_channel(DAC_CHANNEL_1, from_12, to_12); +} + // Convert a buffer of audio samples into 12-bit unsigned DAC values and write // them into dest[]. Returns the number of DAC samples written. // @@ -436,6 +440,20 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, load_dma_buffer_half(self, 0); load_dma_buffer_half(self, 1); + // Ramp from quiescent to the first sample so the transition into + // DMA-driven output is glitch-free. The DAC is still in single-mode + // (DAC_TRIGGER_NONE) at this point, set up by construct() / stop(), + // so HAL_DAC_SetValue takes effect immediately. After the ramp the + // pin is sitting at exactly dma_buffer[0], which is also the first + // value the timer-triggered DMA will latch. + uint16_t quiescent_12 = self->quiescent_value >> 4; + dac_ramp_channel(DAC_CHANNEL_1, quiescent_12, self->dma_buffer[0]); + if (self->right_channel != NULL) { + // CH2 was not started in construct(), so it has been outputting + // its reset value (0). Ramp from there. + dac_ramp_channel(DAC_CHANNEL_2, 0, self->dma_buffer_r[0]); + } + // --- TIM6 setup --- // TIM6 is a basic timer on APB1. It is not managed by the common timer // infrastructure (stm_peripherals_find_timer etc.) because it has no GPIO From dc6fb6b20c5404d34aaf149dc91755357056daf1 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sat, 2 May 2026 01:49:38 -0700 Subject: [PATCH 445/876] ports/stm: queue DMA halves via bitmask + grow audioio buffer Replace the scalar buffer_half_to_fill with a halves_to_fill bitmask so a back-to-back half/full IRQ pair queues both fills even if the background callback hasn't run yet. Grow the DMA circular buffer to 8192 samples (4096-sample halves) so each half-fill window covers ~186 ms at 22050 Hz, giving the background callback enough slack to absorb SDIO cluster reads, NeoPixel updates, and other main-loop stalls without underrun. Also expand the audioio manual test suite (stereo_playback, serial runner, README/TESTING docs) to cover the new behaviour. Co-Authored-By: Claude Opus 4.7 --- ports/stm/common-hal/audioio/AudioOut.c | 90 +++++++---- ports/stm/common-hal/audioio/AudioOut.h | 17 ++- tests/circuitpython-manual/audioio/README.md | 37 +++-- tests/circuitpython-manual/audioio/TESTING.md | 141 +++++++++++++----- .../audioio/run_serial_tests.py | 74 ++++++++- .../audioio/stereo_playback.py | 107 +++++++++++-- 6 files changed, 356 insertions(+), 110 deletions(-) diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index 9f8799f258b..31b10235176 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -127,25 +127,19 @@ static uint32_t convert_to_dac12( if (bytes_per_sample == 1) { for (uint32_t i = 0; i < frames; i++) { uint8_t u8 = src[i * src_stride + src_offset]; - if (samples_signed) { - // signed 8-bit: -128..127 → 0..4080 - dest[i] = (uint16_t)((int16_t)(int8_t)u8 + 128) << 4; - } else { - // unsigned 8-bit: 0..255 → 0..4080 - dest[i] = (uint16_t)u8 << 4; - } + int32_t s = samples_signed + ? (int32_t)(int8_t)u8 + : (int32_t)u8 - 128; + dest[i] = (uint16_t)((s + 128) & 0xFF) << 4; } } else { for (uint32_t i = 0; i < frames; i++) { uint16_t u16; memcpy(&u16, src + i * src_stride + src_offset, 2); - if (samples_signed) { - // signed 16-bit: -32768..32767 → 0..4095 - dest[i] = (uint16_t)((int32_t)(int16_t)u16 + 0x8000) >> 4; - } else { - // unsigned 16-bit: 0..65535 → 0..4095 - dest[i] = u16 >> 4; - } + int32_t s = samples_signed + ? (int32_t)(int16_t)u16 + : (int32_t)u16 - 0x8000; + dest[i] = (uint16_t)((s + 0x8000) & 0xFFFF) >> 4; } } @@ -245,7 +239,17 @@ static void audioout_fill_callback(void *arg) { common_hal_audioio_audioout_stop(self); return; } - load_dma_buffer_half(self, self->buffer_half_to_fill); + uint8_t mask; + __disable_irq(); + mask = self->halves_to_fill; + self->halves_to_fill = 0; + __enable_irq(); + if (mask & 0x1) { + load_dma_buffer_half(self, 0); + } + if (mask & 0x2) { + load_dma_buffer_half(self, 1); + } } // --------------------------------------------------------------------------- @@ -268,7 +272,7 @@ void DMA1_Stream6_IRQHandler(void) { void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) { if (active_audioout && !active_audioout->paused) { - active_audioout->buffer_half_to_fill = 0; + active_audioout->halves_to_fill |= 0x1; background_callback_add(&active_audioout->callback, audioout_fill_callback, active_audioout); } @@ -276,7 +280,7 @@ void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) { void HAL_DAC_ConvCpltCallbackCh1(DAC_HandleTypeDef *hdac) { if (active_audioout && !active_audioout->paused) { - active_audioout->buffer_half_to_fill = 1; + active_audioout->halves_to_fill |= 0x2; background_callback_add(&active_audioout->callback, audioout_fill_callback, active_audioout); } @@ -413,6 +417,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, self->loop = loop; self->stopping = false; self->paused = false; + self->halves_to_fill = 0; self->src_ptr = NULL; self->src_remaining_len = 0; self->src_done = false; @@ -484,10 +489,9 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, HAL_TIMEx_MasterConfigSynchronization(&tim6_handle, &master_cfg); // --- DAC channel reconfiguration for DMA-triggered mode --- - // Stop single-mode DAC (started by stop() for quiescent output) before - // reconfiguring for DMA-triggered operation; otherwise the HAL state - // machine is left in BUSY and HAL_DAC_Start_DMA may reject the request. - HAL_DAC_Stop(&handle, DAC_CHANNEL_1); + // Switch the trigger source to TIM6 *without* disabling the DAC channel. + // HAL_DAC_Stop would disable the channel and momentarily drop the output + // pin to 0 V — audible as a pop between samples. DAC_ChannelConfTypeDef ch_cfg = {0}; ch_cfg.DAC_Trigger = DAC_TRIGGER_T6_TRGO; ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; @@ -495,6 +499,9 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, if (self->right_channel != NULL) { HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_2); } + // Reset HAL state from BUSY (set by Start) back to READY so + // HAL_DAC_Start_DMA below doesn't reject the request. + handle.State = HAL_DAC_STATE_READY; // --- DMA1 Stream5 Channel7 setup (DAC CH1, left) --- __HAL_RCC_DMA1_CLK_ENABLE(); @@ -587,12 +594,30 @@ void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) { // Stop the sample clock first so no more DMA requests are generated. TIM6->CR1 &= ~TIM_CR1_CEN; - // Stop DMA and DAC channels. - HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_1); + // Switch the DAC channels to no-trigger mode while leaving them enabled. + // This is the key to a click-free stop: HAL_DAC_Stop_DMA / HAL_DAC_Stop + // disable the channel, which briefly pulls the output pin to 0 V before + // the ramp can run. Reconfiguring the trigger only keeps the channel + // enabled; the DAC keeps holding its last DHR value while DMA is aborted. + DAC_ChannelConfTypeDef ch_cfg = {0}; + ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; + ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); + if (self->dma_buffer_r) { + HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_2); + } + + // Capture the last DAC output now that no further DMA writes can land. + uint16_t last_l = (uint16_t)(DAC->DOR1 & 0xFFF); + uint16_t last_r = self->dma_buffer_r ? (uint16_t)(DAC->DOR2 & 0xFFF) : 0; + uint16_t quiescent_12 = self->quiescent_value >> 4; + + // Abort DMA without disabling the DAC channels (HAL_DAC_Stop_DMA would). + HAL_DMA_Abort(&self->dma_handle); HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn); if (self->dma_buffer_r) { - HAL_DAC_Stop_DMA(&handle, DAC_CHANNEL_2); + HAL_DMA_Abort(&self->dma_handle_r); HAL_NVIC_DisableIRQ(DMA1_Stream6_IRQn); NVIC_ClearPendingIRQ(DMA1_Stream6_IRQn); m_free(self->dma_buffer_r); @@ -605,14 +630,15 @@ void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) { self->dma_buffer = NULL; } - // Restore quiescent output (channel is still active from construct()). - DAC_ChannelConfTypeDef ch_cfg = {0}; - ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; - ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; - HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1); - HAL_DAC_SetValue(&handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, - self->quiescent_value >> 4); - HAL_DAC_Start(&handle, DAC_CHANNEL_1); + // Ramp left channel from last sample back to quiescent. + dac_ramp_channel(DAC_CHANNEL_1, last_l, quiescent_12); + + // Ramp right channel back to 0 (its reset value) before disabling it, + // so the next play() can ramp cleanly from 0 again. + if (self->right_channel != NULL) { + dac_ramp_channel(DAC_CHANNEL_2, last_r, 0); + HAL_DAC_Stop(&handle, DAC_CHANNEL_2); + } self->sample = MP_OBJ_NULL; self->stopping = false; diff --git a/ports/stm/common-hal/audioio/AudioOut.h b/ports/stm/common-hal/audioio/AudioOut.h index 6f47b2b1eea..ad8ff1c7680 100644 --- a/ports/stm/common-hal/audioio/AudioOut.h +++ b/ports/stm/common-hal/audioio/AudioOut.h @@ -13,11 +13,11 @@ // Total DMA circular buffer size in 16-bit samples. // Split into two halves; one half plays while the other is refilled. -// 2048 samples at 48000 Hz = ~21 ms per half-buffer interrupt, which -// gives the main loop plenty of headroom against USB / VFS stalls -// before an underrun occurs. -#define AUDIOOUT_DMA_BUFFER_SAMPLES 2048 -#define AUDIOOUT_DMA_HALF_SAMPLES 1024 +// 4096-sample halves at 22050 Hz = ~186 ms per half-buffer interrupt, +// giving the background callback enough headroom to absorb SDIO cluster +// reads, NeoPixel updates, and other main-loop stalls without underrun. +#define AUDIOOUT_DMA_BUFFER_SAMPLES 8192 +#define AUDIOOUT_DMA_HALF_SAMPLES 4096 typedef struct { mp_obj_base_t base; @@ -55,8 +55,11 @@ typedef struct { // Background callback queued from DMA ISR, processed in main loop. background_callback_t callback; - // Which half of dma_buffer to refill next: 0 = lower, 1 = upper. - volatile uint8_t buffer_half_to_fill; + // Bitmask of DMA halves pending refill: bit0 = lower, bit1 = upper. + // Set from half/full IRQ, drained by the background callback. A bitmask + // (not a scalar) so a back-to-back half+full pair queues both fills even + // if the callback hasn't run yet. + volatile uint8_t halves_to_fill; // Source buffer position tracking. Allows consuming large source buffers // (e.g. RawSample > 256 samples) across multiple DMA half-fills. diff --git a/tests/circuitpython-manual/audioio/README.md b/tests/circuitpython-manual/audioio/README.md index 35c5f15518e..7b2be500004 100644 --- a/tests/circuitpython-manual/audioio/README.md +++ b/tests/circuitpython-manual/audioio/README.md @@ -74,7 +74,9 @@ grep CIRCUITPY_AUDIOIO ports/stm/build-feather_stm32f405_express/mpconfigport.mk ``` Flash the resulting `.bin` to the board using your preferred method (e.g. `dfu-util`). - +``` +dfu-util -a 0 --dfuse-address 0x08000000:force:mass-erase -D PATH/TO/circuitpython/ports/stm/build-feather_stm32f405_express/firmware.bin +``` ## File Setup > **If using `run_serial_tests.py`** this step is done automatically — skip ahead. @@ -233,12 +235,20 @@ print("pass") ## Test 5 — Stereo Playback (`stereo_playback.py`) *(automated)* -Verifies that `AudioOut(board.A0, right_channel=board.A1)` correctly splits a -stereo WAV file across both DAC channels: left audio on **A0 (PA04, DAC_CH1)** -and right audio on **A1 (PA05, DAC_CH2)**, both clocked by TIM6. +Verifies that `AudioOut(board.A0, right_channel=board.A1)` drives both DAC +channels independently: left on **A0 (PA04, DAC_CH1)**, right on +**A1 (PA05, DAC_CH2)**, both clocked by TIM6. + +The script runs four phases in order: + +1. **Left-only 440 Hz tone** (~1 s) — only A0 should produce audio. +2. **Right-only 440 Hz tone** (~1 s) — only A1 should produce audio. +3. **Both-channel 440 Hz tone** (~1 s) — equal amplitude on both pins. +4. **Pan sweep L → R** (~2 s) — 8 stepped amplitude stages from A0 to A1 (small looped buffers; full continuous sweep would not fit in heap). +5. Then plays each stereo WAV (`44100` and `8000` Hz) in full. -**Hardware required:** connect a speaker or amp to both A0 and A1 (two separate -channels), or use an oscilloscope to probe each pin independently. +**Hardware required:** connect a stereo headphone/amp to A0 (left) and A1 +(right) with common ground, or scope-probe each pin separately. **Run from the REPL:** @@ -251,6 +261,10 @@ exec(open("stereo_playback.py").read()) **Expected output:** ``` +channel test: left only +channel test: right only +channel test: both channels +pan sweep: left to right playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav done @@ -258,10 +272,13 @@ done **What to listen / look for:** -- Left and right channels play the correct sides of the stereo jingle. -- No cross-contamination between channels. -- On a scope: probe A0 and A1 simultaneously — waveforms should differ - (the splash sample is not phase-identical left/right). +- "left only" → tone in left ear, silence in right. +- "right only" → tone in right ear, silence in left. +- "both channels" → centered tone in both ears. +- "pan sweep" → tone steps left → right across 8 amplitude stages over 2 s. +- Stereo WAVs play with proper L/R separation; no cross-contamination. +- On a scope: probing A0 and A1 simultaneously during phases 1 and 2 should + show one channel idle (mid-scale DC) while the other carries the sine. ## Test 6 — Soft Reset Cleanup *(manual)* diff --git a/tests/circuitpython-manual/audioio/TESTING.md b/tests/circuitpython-manual/audioio/TESTING.md index d8362a31e9f..7b2be500004 100644 --- a/tests/circuitpython-manual/audioio/TESTING.md +++ b/tests/circuitpython-manual/audioio/TESTING.md @@ -9,19 +9,20 @@ These tests exercise the DAC-based `audioio.AudioOut` implementation added for S | 1 — WAV File Playback | Yes | Yes (audio check) | | 2 — Pause / Resume | Yes | Yes (audio check) | | 3 — Looping Sine Wave | Yes | Yes (audio check) | -| 4 — Soft Reset Cleanup | No (manual Ctrl-C/D) | No | -| 5 — deinit and Re-init | Yes | No | +| 4 — deinit and Re-init | Yes | No | +| 5 — Stereo Playback | Yes | Yes (audio check) | +| 6 — Soft Reset Cleanup | No (manual Ctrl-C/D) | No | -`run_serial_tests.py` automates Tests 1, 2, 3, and 5: it copies the necessary -files to the board and runs each script over the serial REPL, comparing the -printed output to the expected patterns. You still need to listen to the audio -(and optionally use an oscilloscope) for the audio-quality checks. +`run_serial_tests.py` automates Tests 1–5: it copies the necessary files to the +board and runs each script over the serial REPL, comparing the printed output to +the expected patterns. You still need to listen to the audio (and optionally +use an oscilloscope) for the audio-quality checks. ### Quick start ```bash # Install the one dependency (if not already present) -pip install pyserial +pip install mpremote # Run all automated tests (board must be connected and CIRCUITPY mounted) python3 tests/circuitpython-manual/audioio/run_serial_tests.py @@ -29,13 +30,19 @@ python3 tests/circuitpython-manual/audioio/run_serial_tests.py # Skip file copy if files are already on the board python3 tests/circuitpython-manual/audioio/run_serial_tests.py --no-copy -# Override the serial port or CIRCUITPY path +# Override the serial port or CIRCUITPY path (auto-detected on macOS/Linux/Windows) python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ --port /dev/cu.usbmodem1234 \ - --circuitpy /Volumes/CIRCUITPY + --circuitpy /Volumes/CIRCUITPY # macOS (auto-detected) +python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ + --port /dev/ttyACM0 \ + --circuitpy /media/user/CIRCUITPY # Linux (auto-detected) +python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ + --port COM5 \ + --circuitpy D:\ # Windows (auto-detected) # Run only specific tests -python3 tests/circuitpython-manual/audioio/run_serial_tests.py --tests 3,5 +python3 tests/circuitpython-manual/audioio/run_serial_tests.py --tests 3,4,5 ``` The script exits 0 if all selected tests pass, 1 otherwise — suitable for CI. @@ -56,7 +63,7 @@ The script exits 0 if all selected tests pass, 1 otherwise — suitable for CI. Enable the feature by building for an F405 or F407 target: ``` -make -C ports/stm BOARD=feather_stm32f405_express -j CROSS_COMPILE=~/arm-toolchain/arm-gnu-toolchain-14.3.rel1-darwin-arm64-arm-none-eabi/bin/arm-none-eabi- +make -C ports/stm BOARD=feather_stm32f405_express -j CROSS_COMPILE=~/arm-toolchain/arm-gnu-toolchain-14.3.rel1-darwin-arm64-arm-none-eabi/bin/arm-none-eabi- PYTHON=/opt/homebrew/bin/python3 ``` `CIRCUITPY_AUDIOIO` is now set to `1` automatically for those variants. Verify it is present in the build: @@ -67,7 +74,9 @@ grep CIRCUITPY_AUDIOIO ports/stm/build-feather_stm32f405_express/mpconfigport.mk ``` Flash the resulting `.bin` to the board using your preferred method (e.g. `dfu-util`). - +``` +dfu-util -a 0 --dfuse-address 0x08000000:force:mass-erase -D PATH/TO/circuitpython/ports/stm/build-feather_stm32f405_express/firmware.bin +``` ## File Setup > **If using `run_serial_tests.py`** this step is done automatically — skip ahead. @@ -79,22 +88,27 @@ cp \ tests/circuitpython-manual/audiocore/jeplayer-splash-8000-8bit-mono-unsigned.wav \ tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-mono-signed.wav \ tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-mono-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-stereo-signed.wav \ + tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-stereo-signed.wav \ /Volumes/CIRCUITPY/ ``` -These three files (~447 KB total) cover every exercised code path: +These five files cover every exercised code path: - `8000-8bit-mono-unsigned` — 8-bit unsigned decode path, audibly lo-fi - `8000-16bit-mono-signed` — 16-bit signed decode path at lowest sample rate - `44100-16bit-mono-signed` — 16-bit at highest sample rate (DMA reconfiguration, audible quality difference) +- `8000-16bit-stereo-signed` — stereo decode path, left→A0, right→A1 +- `44100-16bit-stereo-signed` — stereo at 44.1 kHz Stereo, 24-bit, and the 16 kHz files are omitted: stereo and 24-bit will `OSError`; 16 kHz adds no new code paths over 8 kHz and 44.1 kHz. -Copy the three test scripts to the board as well (or paste them into the REPL): +Copy the test scripts to the board as well (or paste them into the REPL): ``` cp tests/circuitpython-manual/audioio/wavefile_playback.py /Volumes/CIRCUITPY/ cp tests/circuitpython-manual/audioio/wavefile_pause_resume.py /Volumes/CIRCUITPY/ cp tests/circuitpython-manual/audioio/single_buffer_loop.py /Volumes/CIRCUITPY/ +cp tests/circuitpython-manual/audioio/stereo_playback.py /Volumes/CIRCUITPY/ ``` ## Test 1 — WAV File Playback (`wavefile_playback.py`) *(automated)* @@ -195,28 +209,7 @@ done - No pops or glitches during the loop. - Clean silence between tones (quiescent DAC value holds between `stop()` calls). -## Test 4 — Soft Reset Cleanup *(manual)* - -Verifies that `audioout_reset()` properly cleans up when the REPL soft-resets during active playback. - -1. Start a looping tone in the REPL: - -```python -import audiocore, audioio, board, array, math, time -length = 8000 // 440 -s16 = array.array("h", [int(math.sin(math.pi * 2 * i / length) * 32767) for i in range(length)]) -dac = audioio.AudioOut(board.A0) -dac.play(audiocore.RawSample(s16, sample_rate=8000), loop=True) -``` - -2. While the tone is playing, press **Ctrl-C** then **Ctrl-D** (soft reset). - -**Expected:** -- **Ctrl-C** interrupts the Python code but the tone *keeps playing* — this is normal. The DMA and TIM6 run in hardware independently of Python; a `KeyboardInterrupt` does not stop them. -- **Ctrl-D** triggers a soft reset which calls `audioout_reset()`. The tone stops immediately and the board returns to the `>>>` prompt with no crash or fault. -- Running any of the above tests again afterwards should work normally. - -## Test 5 — `deinit` and Re-init *(automated)* +## Test 4 — `deinit` and Re-init *(automated)* Verifies that `AudioOut` can be deconstructed and reconstructed without rebooting, and that pin A0 is properly released. @@ -240,16 +233,84 @@ print("pass") **Expected output:** `pass` with no exceptions. +## Test 5 — Stereo Playback (`stereo_playback.py`) *(automated)* + +Verifies that `AudioOut(board.A0, right_channel=board.A1)` drives both DAC +channels independently: left on **A0 (PA04, DAC_CH1)**, right on +**A1 (PA05, DAC_CH2)**, both clocked by TIM6. + +The script runs four phases in order: + +1. **Left-only 440 Hz tone** (~1 s) — only A0 should produce audio. +2. **Right-only 440 Hz tone** (~1 s) — only A1 should produce audio. +3. **Both-channel 440 Hz tone** (~1 s) — equal amplitude on both pins. +4. **Pan sweep L → R** (~2 s) — 8 stepped amplitude stages from A0 to A1 (small looped buffers; full continuous sweep would not fit in heap). +5. Then plays each stereo WAV (`44100` and `8000` Hz) in full. + +**Hardware required:** connect a stereo headphone/amp to A0 (left) and A1 +(right) with common ground, or scope-probe each pin separately. + +**Run from the REPL:** + +```python +import os +os.chdir("/") +exec(open("stereo_playback.py").read()) +``` + +**Expected output:** + +``` +channel test: left only +channel test: right only +channel test: both channels +pan sweep: left to right +playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav +playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav +done +``` + +**What to listen / look for:** + +- "left only" → tone in left ear, silence in right. +- "right only" → tone in right ear, silence in left. +- "both channels" → centered tone in both ears. +- "pan sweep" → tone steps left → right across 8 amplitude stages over 2 s. +- Stereo WAVs play with proper L/R separation; no cross-contamination. +- On a scope: probing A0 and A1 simultaneously during phases 1 and 2 should + show one channel idle (mid-scale DC) while the other carries the sine. + +## Test 6 — Soft Reset Cleanup *(manual)* + +Verifies that `audioout_reset()` properly cleans up when the REPL soft-resets during active playback. + +1. Start a looping tone in the REPL: + +```python +import audiocore, audioio, board, array, math, time +length = 8000 // 440 +s16 = array.array("h", [int(math.sin(math.pi * 2 * i / length) * 32767) for i in range(length)]) +dac = audioio.AudioOut(board.A0) +dac.play(audiocore.RawSample(s16, sample_rate=8000), loop=True) +``` + +2. While the tone is playing, press **Ctrl-C** then **Ctrl-D** (soft reset). + +**Expected:** +- **Ctrl-C** interrupts the Python code but the tone *keeps playing* — this is normal. The DMA and TIM6 run in hardware independently of Python; a `KeyboardInterrupt` does not stop them. +- **Ctrl-D** triggers a soft reset which calls `audioout_reset()`. The tone stops immediately and the board returns to the `>>>` prompt with no crash or fault. +- Running any of the above tests again afterwards should work normally. + ## Oscilloscope Checks (Optional) Each test script drives `board.D4` (pin D4) low at the start of each playback and high when it ends. This provides a clean trigger edge for a scope. - **Test 1:** Probe A0 — should show a sampled waveform at the correct sample rate. Probe D4 for a gate signal that spans the file duration. -- **Test 3:** Probe A0 — should show a 440 Hz staircase-sine at the DAC output (12-bit steps visible at 44.1 kHz; fewer at 8 kHz). +- **Test 3:** Probe A0 — should show a 440 Hz staircase-sine at the DAC output (12-bit steps visible at 44.1 kHz; fewer at 8 kHz). A simple RC low-pass filter (1 kΩ + 100 nF) on the A0 output will smooth the staircase significantly. ## Known Limitations -- **Right channel / stereo output** is not implemented. Passing `right_channel` to `AudioOut()` raises `ValueError: Stereo not supported on this board`. -- **Only pin A0 (PA04)** is supported as the left channel. Any other pin raises `ValueError: AudioOut requires pin A0 (PA04)`. +- **Left channel must be A0 (PA04)**. Any other pin raises `ValueError: AudioOut requires pin A0 (PA04)`. +- **Right channel must be A1 (PA05)** when used. Any other pin raises `ValueError: AudioOut right channel requires pin A1 (PA05)`. - **24-bit WAV files** are not supported by `audiocore.WaveFile` and will raise `OSError` when opened. -- Only one `AudioOut` instance can be active at a time (single DAC channel). +- Only one `AudioOut` instance can be active at a time. diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py index 35b2c4630ac..a39b988f654 100644 --- a/tests/circuitpython-manual/audioio/run_serial_tests.py +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -28,6 +28,7 @@ import shutil import subprocess import sys +import time # --------------------------------------------------------------------------- # Paths @@ -83,6 +84,40 @@ def _mpremote(args: list, timeout: float = 30.0): sys.exit("mpremote not found. Run: pip install mpremote") +def _interrupt_running_code(port: str, soft_reset: bool = False) -> None: + """Halt any code running on the device so mpremote can enter raw REPL. + + Strategy: + 1. Ctrl-C burst — usually breaks a busy print loop. + 2. Optional Ctrl-D soft reset, followed by a Ctrl-C flood through the + reboot window so code.py is interrupted *before* it gets busy again. + """ + try: + import serial # type: ignore[import-not-found] + except ImportError: + return + try: + with serial.Serial(port, 115200, timeout=0.1) as ser: + for _ in range(5): + ser.write(b"\x03") + ser.flush() + time.sleep(0.05) + if soft_reset: + ser.write(b"\x04") # Ctrl-D → soft reboot + ser.flush() + # Flood Ctrl-C while CircuitPython reboots so code.py can't + # get past its first iteration before we break in. + deadline = time.time() + 3.0 + while time.time() < deadline: + ser.write(b"\x03") + ser.flush() + time.sleep(0.05) + time.sleep(0.3) + ser.reset_input_buffer() + except (serial.SerialException, OSError): + pass + + def find_port() -> str: """Return the port of the first Adafruit device found by mpremote devs.""" stdout, _ = _mpremote(["devs"]) @@ -190,16 +225,34 @@ def _check(condition: bool, message: str) -> bool: return condition -def _run_exec(port: str, code: str, label: str, timeout: float): - """Execute *code* on the device via mpremote exec and print the output.""" +def _run_exec(port: str, code: str, label: str, timeout: float, retries: int = 2): + """Execute *code* on the device via mpremote exec and print the output. + + Retries on `could not enter raw repl` after sending a Ctrl-C burst — this + handles the case where a busy code.py blocks mpremote's first handshake. + """ print(f"\n{'=' * 60}") print(f" {label}") print("=" * 60) - try: - stdout, stderr = _mpremote(["connect", port, "exec", code], timeout=timeout) - except TimeoutError as exc: - print(f" [FAIL] {exc}") - return False, "", "" + stdout = "" + stderr = "" + for attempt in range(retries + 1): + try: + stdout, stderr = _mpremote( + ["connect", port, "exec", code], timeout=timeout + ) + except TimeoutError as exc: + print(f" [FAIL] {exc}") + return False, "", "" + if "could not enter raw repl" not in stderr: + break + if attempt < retries: + # Escalate: first attempt = Ctrl-C burst; second = Ctrl-D reboot. + escalate = attempt >= 1 + tactic = "soft-reset + Ctrl-C flood" if escalate else "Ctrl-C burst" + print(f" [retry {attempt + 1}/{retries}] raw REPL busy — {tactic}") + _interrupt_running_code(port, soft_reset=escalate) + time.sleep(0.5) print("Output:") for line in stdout.splitlines(): print(f" {line}") @@ -270,6 +323,10 @@ def test5_stereo_playback(port: str) -> bool: if not ok: return False passed = True + passed &= _check("channel test: left only" in stdout, "Left-only channel tone played") + passed &= _check("channel test: right only" in stdout, "Right-only channel tone played") + passed &= _check("channel test: both channels" in stdout, "Both-channel tone played") + passed &= _check("pan sweep: left to right" in stdout, "Pan sweep played") passed &= _check("playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav" in stdout, "44100 Hz 16-bit stereo WAV played") passed &= _check("playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav" in stdout, "8000 Hz 16-bit stereo WAV played") passed &= _check("done" in stdout, "Script completed with 'done'") @@ -324,6 +381,9 @@ def main(): if not args.no_copy: copy_files(port, circuitpy=args.circuitpy) + # Halt any running code.py so the first test gets a clean raw-REPL entry. + _interrupt_running_code(port) + results: dict[str, bool] = {} if "1" in selected: results["Test 1 — WAV Playback"] = test1_wavefile_playback(port) diff --git a/tests/circuitpython-manual/audioio/stereo_playback.py b/tests/circuitpython-manual/audioio/stereo_playback.py index c82e4ba40dd..a3817e010d9 100644 --- a/tests/circuitpython-manual/audioio/stereo_playback.py +++ b/tests/circuitpython-manual/audioio/stereo_playback.py @@ -2,6 +2,9 @@ import audioio import board import digitalio +import array +import gc +import math import time import os @@ -12,23 +15,99 @@ except AttributeError: trigger = None -sample_prefix = "jeplayer-splash" +dac = audioio.AudioOut(board.A0, right_channel=board.A1) -samples = [] -for fn in os.listdir("/"): - if fn.startswith(sample_prefix): - samples.append(fn) +# --------------------------------------------------------------------------- +# Channel-isolation tones: prove each DAC channel can be driven independently. +# Listener should hear the 440 Hz tone shift between ears. +# --------------------------------------------------------------------------- +sample_rate = 8000 +freq = 440 +length = sample_rate // freq +sine = [int(math.sin(2 * math.pi * i / length) * 16000) for i in range(length)] +silence = [0] * length -if not samples: - print("No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board.") -# Play each stereo WAV file through both DAC channels simultaneously. -# Left channel → A0 (PA04, DAC_CH1), Right channel → A1 (PA05, DAC_CH2). -dac = audioio.AudioOut(board.A0, right_channel=board.A1) -for filename in sorted(samples): - # Only play stereo files to exercise the right channel path. - if "stereo" not in filename: - continue +def stereo_buffer(left, right): + # Init from bytes to avoid the temporary [0]*N int list (heavy on F405 RAM). + buf = array.array("h", b"\x00\x00" * (len(left) * 2)) + for i in range(len(left)): + buf[2 * i] = left[i] + buf[2 * i + 1] = right[i] + return buf + + +channel_tests = ( + ("left only", sine, silence), + ("right only", silence, sine), + ("both channels", sine, sine), +) + +for label, left, right in channel_tests: + print("channel test:", label) + sample = audiocore.RawSample( + stereo_buffer(left, right), channel_count=2, sample_rate=sample_rate + ) + if trigger: + trigger.value = False + dac.play(sample, loop=True) + time.sleep(1.0) + dac.stop() + if trigger: + trigger.value = True + time.sleep(0.2) + del sample + print() + +del channel_tests, sine, silence + +# --------------------------------------------------------------------------- +# Pan sweep: continuous equal-power L→R over 2 s. Single non-looped buffer, +# played once for a smooth crossfade with no DMA restart clicks. +# +# Linear amplitude pan sounds like centred stereo at the midpoint because both +# channels are equally loud. Equal-power (cos/sin) pan keeps total energy +# constant so the source is perceived as moving rather than collapsing inwards. +# +# 2 s @ 4 kHz stereo 8-bit signed = 16000 bytes. Halving the sample rate keeps +# the buffer small while doubling perceived motion duration; 220 Hz at 4 kHz +# has the same samples-per-cycle as the earlier 440 Hz @ 8 kHz tones. +# --------------------------------------------------------------------------- +gc.collect() +pan_sr = sample_rate // 2 +pan_freq = freq // 2 +pan_seconds = 3 +pan_frames = pan_sr * pan_seconds +pan_buf = array.array("b", bytes(pan_frames * 2)) +two_pi_freq_over_sr = 2 * math.pi * pan_freq / pan_sr +half_pi = math.pi / 2 +for i in range(pan_frames): + s = math.sin(two_pi_freq_over_sr * i) + t = i / pan_frames # 0 → 1 + l_gain = math.cos(t * half_pi) + r_gain = math.sin(t * half_pi) + pan_buf[2 * i] = int(s * l_gain * 120) + pan_buf[2 * i + 1] = int(s * r_gain * 120) + +print("pan sweep: left to right") +pan_sample = audiocore.RawSample(pan_buf, channel_count=2, sample_rate=pan_sr) +if trigger: + trigger.value = False +dac.play(pan_sample) +while dac.playing: + time.sleep(0.05) +if trigger: + trigger.value = True +time.sleep(0.2) +print() + +# --------------------------------------------------------------------------- +# Stereo WAV files: full-content check. +# --------------------------------------------------------------------------- +sample_prefix = "jeplayer-splash" +wavs = sorted(fn for fn in os.listdir("/") if fn.startswith(sample_prefix) and "stereo" in fn) + +for filename in wavs: print("playing stereo:", filename) with open(filename, "rb") as sample_file: try: From 2b10a4b214fe7f3e7e6fb35914e1324c7a408c98 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sat, 2 May 2026 18:39:43 -0700 Subject: [PATCH 446/876] ports/stm: harden audioio review fixes + bump DMA to VERY_HIGH Apply code-review fixes to the F405/F407 audioio implementation: - Fix infinite loop on partial-frame source data in load_dma_buffer_half (was spinning when convert returned 0 with leftover bytes). - Use canonical audiosample_get_* accessors for sample format. - Validate sample_rate via mp_arg_validate_int_max (1 MHz ceiling). - Replace m_malloc with m_malloc_without_collect to avoid GC during DAC configure. - Raise on HAL_TIM_Base_Init / HAL_TIMEx_MasterConfigSynchronization / HAL_DMA_Init failure rather than silently continuing. - Clear left/right pin refs and playing flag in audioout_reset so the next construct starts from a clean state. - Gate paused on playing in get_paused, matching espressif convention. - Claim pins first before any other allocation so the error path needs no rollback. - Bump DMA priority HIGH -> VERY_HIGH on both streams (sweep analysis shows this is safe and gives more refill headroom). - Make CIRCUITPY_AUDIOIO opt-out via ?= so boards reusing TIM6 / PA04 can disable it. --- ports/stm/common-hal/audioio/AudioOut.c | 221 ++++++++++++++++-------- ports/stm/common-hal/audioio/AudioOut.h | 14 +- ports/stm/mpconfigport.mk | 3 +- 3 files changed, 158 insertions(+), 80 deletions(-) diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index 31b10235176..d66c239c69a 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries LLC +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC // // SPDX-License-Identifier: MIT @@ -11,12 +11,15 @@ // DAC_CHANNEL_1 (PA04) is configured with DAC_TRIGGER_T6_TRGO so each // TIM6 update latches the next sample from the DMA FIFO. // DMA1 Stream5 Channel7 operates in circular mode, feeding 16-bit samples -// from a double-buffer (512 samples = two 256-sample halves). +// from a double-buffer. Stereo additionally drives DAC_CHANNEL_2 (PA05) +// via DMA1 Stream6 Channel7, sharing the same TIM6 trigger. // The DMA half-complete and complete callbacks queue a background_callback // to refill the idle half from the audio sample source. // // The shared DAC handle (declared in AnalogOut.c) is reused here so both -// modules share state consistently and avoid double-init conflicts. +// modules share state consistently and avoid double-init conflicts. Pin +// claims (common_hal_mcu_pin_claim) act as the inter-module mutex: a second +// AudioOut, or an AnalogOut on the same pin, fails at the claim step. #include @@ -33,14 +36,23 @@ #include STM32_HAL_H // Shared DAC handle declared in common-hal/analogio/AnalogOut.h. -// AudioOut reconfigures channel 1 for DMA-triggered operation and restores -// it on deinit. +// AudioOut reconfigures channel 1 (and 2 for stereo) for DMA-triggered +// operation and restores the no-trigger config on deinit so AnalogOut can +// resume use of the channel afterwards. #include "common-hal/analogio/AnalogOut.h" +// Highest sample rate accepted by play(). 1 MHz mirrors atmel-samd's SAMD51 +// limit and is comfortably above any reasonable audio rate; the real hardware +// ceiling is TIM6_CLK / 2 (~42 MHz on F405) but rates that high would just +// underrun the DMA refill path. +#define AUDIOOUT_MAX_SAMPLE_RATE 1000000u + // TIM6 handle: only one instance ever active, so file-scope is fine. static TIM_HandleTypeDef tim6_handle; // Pointer to the currently active AudioOut object, used by IRQ handlers. +// Pin claims prevent two instances from existing simultaneously, but this +// pointer is also used to early-out IRQs after stop(). static audioio_audioout_obj_t *active_audioout = NULL; // --------------------------------------------------------------------------- @@ -67,7 +79,8 @@ static uint32_t get_tim6_freq(void) { } // Gently ramp the given DAC channel output from from_12 to to_12 (both 12-bit, -// 0-4095) to avoid audible clicks. 64 steps, ~100 µs per step = ~6.4 ms total. +// 0-4095) to avoid audible clicks. 64 steps × 100 µs/step = ~6.4 ms total; +// shrink the step count and clicks reappear on the F405 output stage. static void dac_ramp_channel(uint32_t channel, uint32_t from_12, uint32_t to_12) { if (from_12 == to_12) { return; @@ -99,7 +112,14 @@ static inline void dac_ramp(uint32_t from_12, uint32_t to_12) { } // Convert a buffer of audio samples into 12-bit unsigned DAC values and write -// them into dest[]. Returns the number of DAC samples written. +// them into dest[]. Returns the number of DAC samples written; the caller is +// responsible for padding any remaining dest entries with the quiescent value. +// +// NOTE: ports/espressif/common-hal/audioio/AudioOut.c implements the same +// idea with a CONV_MATCH lookup table dispatching to per-format helpers in +// shared-module/audiocore — a more general-purpose pattern. If a future +// refactor lifts a 12-bit DAC variant into shared-module/audiocore, both +// this driver and any other ARM-DAC port could share it. // // src - raw sample bytes from audiosample_get_buffer // src_len - byte length of src @@ -109,13 +129,11 @@ static inline void dac_ramp(uint32_t from_12, uint32_t to_12) { // samples_signed - true if source samples are signed // channel_count - 1 (mono) or 2 (stereo) // channel_offset - 0 for left/mono, 1 for right channel of a stereo stream -// quiescent_12 - value to pad with if src runs short static uint32_t convert_to_dac12( const uint8_t *src, uint32_t src_len, uint16_t *dest, uint32_t dest_count, uint8_t bytes_per_sample, bool samples_signed, - uint8_t channel_count, uint8_t channel_offset, - uint16_t quiescent_12) { + uint8_t channel_count, uint8_t channel_offset) { // src_stride: bytes between consecutive samples of the same channel uint32_t src_stride = (uint32_t)bytes_per_sample * channel_count; @@ -142,12 +160,20 @@ static uint32_t convert_to_dac12( dest[i] = (uint16_t)((s + 0x8000) & 0xFFFF) >> 4; } } + return frames; +} - // Pad remainder with quiescent value. - for (uint32_t i = frames; i < dest_count; i++) { - dest[i] = quiescent_12; +// Pad [filled, AUDIOOUT_DMA_HALF_SAMPLES) of dest_l (and dest_r if non-NULL) +// with the quiescent value. Used at end-of-stream and on errors so the DAC +// returns smoothly to its resting voltage. +static void pad_quiescent(uint16_t *dest_l, uint16_t *dest_r, + uint32_t filled, uint16_t quiescent_12) { + for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { + dest_l[i] = quiescent_12; + if (dest_r) { + dest_r[i] = quiescent_12; + } } - return frames; } // Load one half of the DMA circular buffer from the audio sample source. @@ -171,15 +197,11 @@ static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { // Handle end-of-stream from previous get_buffer call. if (self->src_done) { if (self->loop) { - audiosample_reset_buffer(self->sample, false, 0); + audiosample_reset_buffer(self->sample, + self->channel_count == 1, 0); self->src_done = false; } else { - for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { - dest_l[i] = quiescent_12; - if (dest_r) { - dest_r[i] = quiescent_12; - } - } + pad_quiescent(dest_l, dest_r, filled, quiescent_12); self->stopping = true; return; } @@ -188,15 +210,11 @@ static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { uint8_t *buf; uint32_t len; audioio_get_buffer_result_t result = - audiosample_get_buffer(self->sample, false, 0, &buf, &len); + audiosample_get_buffer(self->sample, + self->channel_count == 1, 0, &buf, &len); if (result == GET_BUFFER_ERROR) { - for (uint32_t i = filled; i < AUDIOOUT_DMA_HALF_SAMPLES; i++) { - dest_l[i] = quiescent_12; - if (dest_r) { - dest_r[i] = quiescent_12; - } - } + pad_quiescent(dest_l, dest_r, filled, quiescent_12); self->stopping = true; return; } @@ -210,7 +228,7 @@ static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { self->src_ptr, self->src_remaining_len, dest_l + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, self->bytes_per_sample, self->samples_signed, - self->channel_count, 0, quiescent_12); + self->channel_count, 0); if (dest_r) { uint8_t r_offset = (self->channel_count >= 2) ? 1 : 0; @@ -218,7 +236,17 @@ static void load_dma_buffer_half(audioio_audioout_obj_t *self, uint8_t half) { self->src_ptr, self->src_remaining_len, dest_r + filled, AUDIOOUT_DMA_HALF_SAMPLES - filled, self->bytes_per_sample, self->samples_signed, - self->channel_count, r_offset, quiescent_12); + self->channel_count, r_offset); + } + + if (written == 0) { + // src had fewer than src_stride bytes left (e.g. a corrupt WAV + // returned an odd byte count for 16-bit data). Drop the partial + // frame so the next loop iteration calls get_buffer for fresh, + // aligned data — without this the loop spins forever because + // neither filled nor src_remaining_len would advance. + self->src_remaining_len = 0; + continue; } // Advance source position by the amount consumed. @@ -253,12 +281,16 @@ static void audioout_fill_callback(void *arg) { } // --------------------------------------------------------------------------- -// IRQ handlers (must be defined at file scope, not inside functions) +// IRQ handlers +// +// DMA1 Stream5/6 are claimed exclusively for DAC use here. If a future port +// change wires another peripheral onto either stream the weak-symbol override +// below will collide silently — add a build-time assertion in that file. // --------------------------------------------------------------------------- void DMA1_Stream5_IRQHandler(void) { if (active_audioout) { - HAL_DMA_IRQHandler(&active_audioout->dma_handle); + HAL_DMA_IRQHandler(&active_audioout->dma_handle_l); } } @@ -269,6 +301,13 @@ void DMA1_Stream6_IRQHandler(void) { } // HAL weak-symbol overrides: called from HAL_DMA_IRQHandler context. +// +// Only the Ch1 (left) callbacks are overridden. The Stream6 IRQ for the +// right channel still calls HAL_DACEx_ConvHalfCpltCallbackCh2 / +// HAL_DACEx_ConvCpltCallbackCh2 (the default empty weak implementations) — +// that is intentional. Both DMA streams are clocked by the same TIM6 trigger +// and started together, so their NDTR counters stay in lock-step. Refilling +// from the left-channel IRQ alone is sufficient and avoids redundant work. void HAL_DAC_ConvHalfCpltCallbackCh1(DAC_HandleTypeDef *hdac) { if (active_audioout && !active_audioout->paused) { @@ -308,17 +347,31 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("AudioOut right channel requires pin A1 (PA05)")); } + // Claim pins first. The pin-claim system is what serialises this driver + // against another AudioOut instance and against AnalogOut on the same + // pins — if either is already using PA04/PA05 the claim raises here, and + // because nothing else is configured yet, no cleanup is needed. + // + // NOTE: ports/atmel-samd/common-hal/audioio/AudioOut.c also claims pins + // first but L242 raises *after* claiming a timer and event channel + // without releasing them on the error path; worth a follow-up there. + common_hal_mcu_pin_claim(left_channel); + if (right_channel != NULL) { + common_hal_mcu_pin_claim(right_channel); + } + self->left_channel = left_channel; self->right_channel = right_channel; self->quiescent_value = quiescent_value; self->sample = MP_OBJ_NULL; self->dma_buffer = NULL; self->dma_buffer_r = NULL; - memset(&self->dma_handle, 0, sizeof(self->dma_handle)); + memset(&self->dma_handle_l, 0, sizeof(self->dma_handle_l)); memset(&self->dma_handle_r, 0, sizeof(self->dma_handle_r)); memset(&self->callback, 0, sizeof(self->callback)); self->stopping = false; self->paused = false; + self->playing = false; // Configure PA04 (and PA05 if stereo) for analog (DAC) mode. GPIO_InitTypeDef gpio_init = {0}; @@ -333,7 +386,9 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, } // Initialise the shared DAC handle if it hasn't been set up yet - // (i.e. AnalogOut hasn't been used since last reset). + // (i.e. AnalogOut hasn't been used since last reset). __HAL_RCC_DAC_CLK_ENABLE + // is idempotent so calling it unconditionally would be safe too, but + // matching AnalogOut's check keeps the two modules in sync. if (handle.Instance == NULL || handle.State == HAL_DAC_STATE_RESET) { __HAL_RCC_DAC_CLK_ENABLE(); handle.Instance = DAC; @@ -342,8 +397,8 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, } } - // Configure DAC channel 1 with TIM6_TRGO trigger (set at play() time; - // for now configure with no trigger so the ramp works correctly). + // Configure DAC channel 1 with no trigger so the ramp below works + // immediately. play() switches the trigger to TIM6_TRGO. DAC_ChannelConfTypeDef ch_cfg = {0}; ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; @@ -355,12 +410,6 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, HAL_DAC_SetValue(&handle, DAC_CHANNEL_1, DAC_ALIGN_12B_R, 0); HAL_DAC_Start(&handle, DAC_CHANNEL_1); dac_ramp(0, quiescent_value >> 4); - - // Claim pins last so any error above doesn't leave them claimed. - common_hal_mcu_pin_claim(left_channel); - if (right_channel != NULL) { - common_hal_mcu_pin_claim(right_channel); - } #endif } @@ -403,45 +452,47 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, } common_hal_audioio_audioout_stop(self); - // Extract sample format metadata. + // Extract sample format metadata via the canonical accessors so the + // shared sample-protocol contract is honoured. audiosample_base_t *base = audiosample_check(sample); - self->bytes_per_sample = base->bits_per_sample / 8; + self->bytes_per_sample = audiosample_get_bits_per_sample(base) / 8; self->samples_signed = base->samples_signed; - self->channel_count = base->channel_count; - uint32_t sample_rate = base->sample_rate; + self->channel_count = audiosample_get_channel_count(base); + uint32_t sample_rate = audiosample_get_sample_rate(base); if (sample_rate == 0) { mp_raise_ValueError(MP_ERROR_TEXT("sample_rate must be > 0")); } + mp_arg_validate_int_max(sample_rate, AUDIOOUT_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); self->sample = sample; self->loop = loop; self->stopping = false; self->paused = false; + self->playing = false; self->halves_to_fill = 0; self->src_ptr = NULL; self->src_remaining_len = 0; self->src_done = false; - // Allocate DMA circular buffer(s). - self->dma_buffer = (uint16_t *)m_malloc( + // Allocate DMA circular buffer(s). m_malloc_without_collect avoids + // triggering a GC cycle while the DAC is mid-configure; m_malloc itself + // raises on failure so no null check is needed. + // + // NOTE: ports/atmel-samd uses plain m_malloc for its audio_dma scratch + // buffers — the same GC-during-fill risk applies and should be migrated + // to m_malloc_without_collect for symmetry with espressif and stm. + self->dma_buffer = (uint16_t *)m_malloc_without_collect( AUDIOOUT_DMA_BUFFER_SAMPLES * sizeof(uint16_t)); - if (!self->dma_buffer) { - mp_raise_msg(&mp_type_MemoryError, - MP_ERROR_TEXT("insufficient memory for audio buffer")); - } if (self->right_channel != NULL) { - self->dma_buffer_r = (uint16_t *)m_malloc( + self->dma_buffer_r = (uint16_t *)m_malloc_without_collect( AUDIOOUT_DMA_BUFFER_SAMPLES * sizeof(uint16_t)); - if (!self->dma_buffer_r) { - m_free(self->dma_buffer); - self->dma_buffer = NULL; - mp_raise_msg(&mp_type_MemoryError, - MP_ERROR_TEXT("insufficient memory for audio buffer")); - } } - // Pre-fill both halves before starting DMA. - audiosample_reset_buffer(sample, false, 0); + // Pre-fill both halves before starting DMA. single_channel_output is + // true when this AudioOut renders only one DAC channel; for stereo + // output we want the audiocore to deliver interleaved frames. + bool single_channel_output = (self->right_channel == NULL); + audiosample_reset_buffer(sample, single_channel_output, 0); load_dma_buffer_half(self, 0); load_dma_buffer_half(self, 1); @@ -480,13 +531,21 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, tim6_handle.Init.Period = period; tim6_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; tim6_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; - HAL_TIM_Base_Init(&tim6_handle); + if (HAL_TIM_Base_Init(&tim6_handle) != HAL_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("TIM6 init failed")); + } // TRGO = Update event → triggers DAC conversion each period. TIM_MasterConfigTypeDef master_cfg = {0}; master_cfg.MasterOutputTrigger = TIM_TRGO_UPDATE; master_cfg.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; - HAL_TIMEx_MasterConfigSynchronization(&tim6_handle, &master_cfg); + if (HAL_TIMEx_MasterConfigSynchronization(&tim6_handle, &master_cfg) != HAL_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("TIM6 master cfg failed")); + } + // NOTE: ports/atmel-samd's audio_dma_setup_playback handles AUDIO_DMA_OK + // and two specific error codes but lets any other non-OK return fall + // through silently — worth tightening there to mirror this raise-on-fail + // pattern. // --- DAC channel reconfiguration for DMA-triggered mode --- // Switch the trigger source to TIM6 *without* disabling the DAC channel. @@ -506,7 +565,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, // --- DMA1 Stream5 Channel7 setup (DAC CH1, left) --- __HAL_RCC_DMA1_CLK_ENABLE(); - DMA_HandleTypeDef *hdma = &self->dma_handle; + DMA_HandleTypeDef *hdma = &self->dma_handle_l; memset(hdma, 0, sizeof(*hdma)); hdma->Instance = DMA1_Stream5; hdma->Init.Channel = DMA_CHANNEL_7; @@ -516,9 +575,11 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, hdma->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma->Init.Mode = DMA_CIRCULAR; - hdma->Init.Priority = DMA_PRIORITY_HIGH; + hdma->Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma->Init.FIFOMode = DMA_FIFOMODE_DISABLE; - HAL_DMA_Init(hdma); + if (HAL_DMA_Init(hdma) != HAL_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("DMA init failed")); + } __HAL_LINKDMA(&handle, DMA_Handle1, *hdma); HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 6, 0); @@ -537,9 +598,11 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, hdma_r->Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_r->Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_r->Init.Mode = DMA_CIRCULAR; - hdma_r->Init.Priority = DMA_PRIORITY_HIGH; + hdma_r->Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma_r->Init.FIFOMode = DMA_FIFOMODE_DISABLE; - HAL_DMA_Init(hdma_r); + if (HAL_DMA_Init(hdma_r) != HAL_OK) { + mp_raise_RuntimeError(MP_ERROR_TEXT("DMA init failed (right)")); + } __HAL_LINKDMA(&handle, DMA_Handle2, *hdma_r); HAL_NVIC_SetPriority(DMA1_Stream6_IRQn, 6, 0); @@ -584,6 +647,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, } HAL_TIM_Base_Start(&tim6_handle); + self->playing = true; } void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) { @@ -613,7 +677,7 @@ void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) { uint16_t quiescent_12 = self->quiescent_value >> 4; // Abort DMA without disabling the DAC channels (HAL_DAC_Stop_DMA would). - HAL_DMA_Abort(&self->dma_handle); + HAL_DMA_Abort(&self->dma_handle_l); HAL_NVIC_DisableIRQ(DMA1_Stream5_IRQn); NVIC_ClearPendingIRQ(DMA1_Stream5_IRQn); if (self->dma_buffer_r) { @@ -643,13 +707,14 @@ void common_hal_audioio_audioout_stop(audioio_audioout_obj_t *self) { self->sample = MP_OBJ_NULL; self->stopping = false; self->paused = false; + self->playing = false; active_audioout = NULL; __HAL_RCC_TIM6_CLK_DISABLE(); } bool common_hal_audioio_audioout_get_playing(audioio_audioout_obj_t *self) { - return active_audioout == self; + return active_audioout == self && self->playing; } void common_hal_audioio_audioout_pause(audioio_audioout_obj_t *self) { @@ -671,7 +736,14 @@ void common_hal_audioio_audioout_resume(audioio_audioout_obj_t *self) { } bool common_hal_audioio_audioout_get_paused(audioio_audioout_obj_t *self) { - return self->paused; + // Match espressif's convention: paused only reports true while a play() + // session is active, so a stale flag from a previous session can never + // leak through. + // + // NOTE: ports/atmel-samd delegates to audio_dma_get_paused() and does + // not gate on a "playing" state — it relies on the DMA hardware staying + // quiescent after stop. Worth aligning to the espressif/stm convention. + return self->playing && self->paused; } // --------------------------------------------------------------------------- @@ -697,7 +769,12 @@ void audioout_reset(void) { active_audioout->sample = MP_OBJ_NULL; active_audioout->stopping = false; active_audioout->paused = false; - active_audioout->left_channel = NULL; // mark deinited + active_audioout->playing = false; + // Mark the object deinited and drop both pin references so the next + // construct() starts from a fully clean state. reset_all_pins (run + // elsewhere in reset_port) releases the actual pin claims. + active_audioout->left_channel = NULL; + active_audioout->right_channel = NULL; active_audioout = NULL; } __HAL_RCC_TIM6_CLK_DISABLE(); diff --git a/ports/stm/common-hal/audioio/AudioOut.h b/ports/stm/common-hal/audioio/AudioOut.h index ad8ff1c7680..340118819a9 100644 --- a/ports/stm/common-hal/audioio/AudioOut.h +++ b/ports/stm/common-hal/audioio/AudioOut.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries LLC +// SPDX-FileCopyrightText: Copyright (c) 2024 Adafruit Industries LLC // // SPDX-License-Identifier: MIT @@ -17,7 +17,7 @@ // giving the background callback enough headroom to absorb SDIO cluster // reads, NeoPixel updates, and other main-loop stalls without underrun. #define AUDIOOUT_DMA_BUFFER_SAMPLES 8192 -#define AUDIOOUT_DMA_HALF_SAMPLES 4096 +#define AUDIOOUT_DMA_HALF_SAMPLES (AUDIOOUT_DMA_BUFFER_SAMPLES / 2) typedef struct { mp_obj_base_t base; @@ -27,11 +27,10 @@ typedef struct { // Right channel pin (PA05 = DAC_CH2). NULL when mono. const mcu_pin_obj_t *right_channel; - // DMA handle for DMA1 Stream5 Channel7 (DAC CH1, left). - // DMA handle for DMA1 Stream6 Channel7 (DAC CH2, right). - // The DAC handle is the shared file-scope handle from AnalogOut.c. - DMA_HandleTypeDef dma_handle; - DMA_HandleTypeDef dma_handle_r; + // DMA handles. The DAC handle itself is the shared file-scope handle + // from AnalogOut.c; we link these to it via __HAL_LINKDMA. + DMA_HandleTypeDef dma_handle_l; // DMA1 Stream5 Channel7 (DAC CH1, left) + DMA_HandleTypeDef dma_handle_r; // DMA1 Stream6 Channel7 (DAC CH2, right) // Circular DMA buffers: AUDIOOUT_DMA_BUFFER_SAMPLES uint16_t elements each, // allocated on play() and freed on stop(). @@ -41,6 +40,7 @@ typedef struct { // Current audio sample object being played. mp_obj_t sample; bool loop; + bool playing; // Set from ISR context to request a clean stop via background callback. volatile bool stopping; diff --git a/ports/stm/mpconfigport.mk b/ports/stm/mpconfigport.mk index 9fd8cbfb2d7..bd2b2238eef 100644 --- a/ports/stm/mpconfigport.mk +++ b/ports/stm/mpconfigport.mk @@ -3,7 +3,8 @@ INTERNAL_LIBM ?= 1 ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32F405xx STM32F407xx)) CIRCUITPY_ALARM = 1 - CIRCUITPY_AUDIOIO = 1 + # ?= so a board reusing TIM6 / PA04 for something else can opt out. + CIRCUITPY_AUDIOIO ?= 1 CIRCUITPY_CANIO = 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 CIRCUITPY_SDIOIO ?= 1 From e3e32802307de4df14066a25a5ebcbd769ab7ef8 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sat, 2 May 2026 18:39:57 -0700 Subject: [PATCH 447/876] tests: harden audioio runner + clean up manual test docs - run_serial_tests.py: pre-flight detects port held by other process (e.g. VS Code Serial Monitor) and reports the holder up front rather than spinning through opaque retries; add port-reappear wait, wider retry net (Errno 6/16, SerialException, "device in use"), and inter-test settle so a CDC drop in one test no longer cascades through the rest of the suite. - README: drop hardcoded toolchain paths, fix contradictory stereo-WAV description, correct pan-sweep description (continuous equal-power crossfade, not stepped amplitude), align Test 3 sample-rate notes. - Delete TESTING.md (was a near-duplicate of README.md). - single_buffer_loop.py: use the same sample_rate for all four format variants so the test isolates format conversion, not playback rate. - stereo_playback.py: use array initialiser instead of bytes literal for the stereo interleave buffer. - wavefile_pause_resume.py: 30s wall-clock guard prints TIMEOUT rather than hanging the runner. --- tests/circuitpython-manual/audioio/README.md | 33 +- tests/circuitpython-manual/audioio/TESTING.md | 316 ------------------ .../audioio/run_serial_tests.py | 176 ++++++++-- .../audioio/single_buffer_loop.py | 12 +- .../audioio/stereo_playback.py | 3 +- .../audioio/wavefile_pause_resume.py | 9 + 6 files changed, 193 insertions(+), 356 deletions(-) delete mode 100644 tests/circuitpython-manual/audioio/TESTING.md diff --git a/tests/circuitpython-manual/audioio/README.md b/tests/circuitpython-manual/audioio/README.md index 7b2be500004..bddeec83779 100644 --- a/tests/circuitpython-manual/audioio/README.md +++ b/tests/circuitpython-manual/audioio/README.md @@ -60,22 +60,24 @@ The script exits 0 if all selected tests pass, 1 otherwise — suitable for CI. ## Build -Enable the feature by building for an F405 or F407 target: +Enable the feature by building for an F405 or F407 target. `CIRCUITPY_AUDIOIO` +is set to `1` automatically for those variants. ``` -make -C ports/stm BOARD=feather_stm32f405_express -j CROSS_COMPILE=~/arm-toolchain/arm-gnu-toolchain-14.3.rel1-darwin-arm64-arm-none-eabi/bin/arm-none-eabi- PYTHON=/opt/homebrew/bin/python3 +make -C ports/stm BOARD=feather_stm32f405_express -j ``` -`CIRCUITPY_AUDIOIO` is now set to `1` automatically for those variants. Verify it is present in the build: +Verify the option is enabled in the generated build config: ``` grep CIRCUITPY_AUDIOIO ports/stm/build-feather_stm32f405_express/mpconfigport.mk # Expected output: CIRCUITPY_AUDIOIO = 1 ``` -Flash the resulting `.bin` to the board using your preferred method (e.g. `dfu-util`). +Flash the resulting `.bin` to the board using your preferred method (e.g. `dfu-util`): + ``` -dfu-util -a 0 --dfuse-address 0x08000000:force:mass-erase -D PATH/TO/circuitpython/ports/stm/build-feather_stm32f405_express/firmware.bin +dfu-util -a 0 --dfuse-address 0x08000000:force:mass-erase -D ports/stm/build-feather_stm32f405_express/firmware.bin ``` ## File Setup @@ -100,7 +102,10 @@ These five files cover every exercised code path: - `8000-16bit-stereo-signed` — stereo decode path, left→A0, right→A1 - `44100-16bit-stereo-signed` — stereo at 44.1 kHz -Stereo, 24-bit, and the 16 kHz files are omitted: stereo and 24-bit will `OSError`; 16 kHz adds no new code paths over 8 kHz and 44.1 kHz. +The 16 kHz files in the audiocore test set are skipped because they exercise +no code paths beyond 8 kHz and 44.1 kHz. 24-bit WAVs are not supported by +`audiocore.WaveFile` and will raise `OSError` if loaded — they are omitted on +purpose. Copy the test scripts to the board as well (or paste them into the REPL): @@ -113,9 +118,13 @@ cp tests/circuitpython-manual/audioio/stereo_playback.py /Volumes/CIRCUIT ## Test 1 — WAV File Playback (`wavefile_playback.py`) *(automated)* -Verifies that `AudioOut` can play WAV files at 8 kHz, 16 kHz, and 44.1 kHz in mono and stereo (only left channel output), with 8-bit unsigned and 16-bit signed encodings. +Verifies that `AudioOut(board.A0)` can play WAV files at 8 kHz and 44.1 kHz +with 8-bit unsigned and 16-bit signed encodings. Stereo WAVs are played here +through the mono `AudioOut` (only the left channel is mixed to A0); the +stereo path is exercised separately in Test 5. -**Note:** 24-bit WAV files and the stereo MP3 are intentionally excluded — `audiocore.WaveFile` does not support 24-bit, and those files will print an `OSError`. That is expected. +**Note:** 24-bit WAV files are not supported by `audiocore.WaveFile` and will +print an `OSError` if any are present on the filesystem. That is expected. **Run from the REPL:** @@ -205,7 +214,9 @@ done **What to listen for:** - A 440 Hz tone (concert A) for approximately 1 second for each format. -- All four formats should sound essentially identical in pitch and volume. +- All four formats use the same 8 kHz sample rate and should sound + essentially identical in pitch and volume — the test is comparing + format-conversion paths, not playback rates. - No pops or glitches during the loop. - Clean silence between tones (quiescent DAC value holds between `stop()` calls). @@ -244,7 +255,7 @@ The script runs four phases in order: 1. **Left-only 440 Hz tone** (~1 s) — only A0 should produce audio. 2. **Right-only 440 Hz tone** (~1 s) — only A1 should produce audio. 3. **Both-channel 440 Hz tone** (~1 s) — equal amplitude on both pins. -4. **Pan sweep L → R** (~2 s) — 8 stepped amplitude stages from A0 to A1 (small looped buffers; full continuous sweep would not fit in heap). +4. **Pan sweep L → R** (~3 s) — continuous equal-power (cos/sin) crossfade from A0 to A1 in a single non-looped buffer. 5. Then plays each stereo WAV (`44100` and `8000` Hz) in full. **Hardware required:** connect a stereo headphone/amp to A0 (left) and A1 @@ -275,7 +286,7 @@ done - "left only" → tone in left ear, silence in right. - "right only" → tone in right ear, silence in left. - "both channels" → centered tone in both ears. -- "pan sweep" → tone steps left → right across 8 amplitude stages over 2 s. +- "pan sweep" → tone smoothly travels left → right over ~3 s. - Stereo WAVs play with proper L/R separation; no cross-contamination. - On a scope: probing A0 and A1 simultaneously during phases 1 and 2 should show one channel idle (mid-scale DC) while the other carries the sine. diff --git a/tests/circuitpython-manual/audioio/TESTING.md b/tests/circuitpython-manual/audioio/TESTING.md deleted file mode 100644 index 7b2be500004..00000000000 --- a/tests/circuitpython-manual/audioio/TESTING.md +++ /dev/null @@ -1,316 +0,0 @@ -# Testing: STM32F405 / STM32F407 DAC AudioOut - -These tests exercise the DAC-based `audioio.AudioOut` implementation added for STM32F405xx and STM32F407xx. - -## Automated vs Manual Tests - -| Test | Automated | Requires audio/scope | -|------|-----------|----------------------| -| 1 — WAV File Playback | Yes | Yes (audio check) | -| 2 — Pause / Resume | Yes | Yes (audio check) | -| 3 — Looping Sine Wave | Yes | Yes (audio check) | -| 4 — deinit and Re-init | Yes | No | -| 5 — Stereo Playback | Yes | Yes (audio check) | -| 6 — Soft Reset Cleanup | No (manual Ctrl-C/D) | No | - -`run_serial_tests.py` automates Tests 1–5: it copies the necessary files to the -board and runs each script over the serial REPL, comparing the printed output to -the expected patterns. You still need to listen to the audio (and optionally -use an oscilloscope) for the audio-quality checks. - -### Quick start - -```bash -# Install the one dependency (if not already present) -pip install mpremote - -# Run all automated tests (board must be connected and CIRCUITPY mounted) -python3 tests/circuitpython-manual/audioio/run_serial_tests.py - -# Skip file copy if files are already on the board -python3 tests/circuitpython-manual/audioio/run_serial_tests.py --no-copy - -# Override the serial port or CIRCUITPY path (auto-detected on macOS/Linux/Windows) -python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ - --port /dev/cu.usbmodem1234 \ - --circuitpy /Volumes/CIRCUITPY # macOS (auto-detected) -python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ - --port /dev/ttyACM0 \ - --circuitpy /media/user/CIRCUITPY # Linux (auto-detected) -python3 tests/circuitpython-manual/audioio/run_serial_tests.py \ - --port COM5 \ - --circuitpy D:\ # Windows (auto-detected) - -# Run only specific tests -python3 tests/circuitpython-manual/audioio/run_serial_tests.py --tests 3,4,5 -``` - -The script exits 0 if all selected tests pass, 1 otherwise — suitable for CI. - ---- - -## Hardware Required - -- An STM32F405 or STM32F407 board running the freshly-built firmware (e.g. Feather STM32F405 Express). -- A passive speaker or audio amplifier connected to **pin A0 (PA04, DAC channel 1)** and GND. - - A simple test: 100 Ω resistor in series with a small speaker between A0 and GND. - - For better audio: connect A0 to a small amp module (e.g. PAM8403) then to a speaker. -- Optional: an oscilloscope or logic analyser probe on **D4** (used as a trigger output by the test scripts). -- A USB cable for REPL/filesystem access (CircuitPython storage must not be read-only). - -## Build - -Enable the feature by building for an F405 or F407 target: - -``` -make -C ports/stm BOARD=feather_stm32f405_express -j CROSS_COMPILE=~/arm-toolchain/arm-gnu-toolchain-14.3.rel1-darwin-arm64-arm-none-eabi/bin/arm-none-eabi- PYTHON=/opt/homebrew/bin/python3 -``` - -`CIRCUITPY_AUDIOIO` is now set to `1` automatically for those variants. Verify it is present in the build: - -``` -grep CIRCUITPY_AUDIOIO ports/stm/build-feather_stm32f405_express/mpconfigport.mk -# Expected output: CIRCUITPY_AUDIOIO = 1 -``` - -Flash the resulting `.bin` to the board using your preferred method (e.g. `dfu-util`). -``` -dfu-util -a 0 --dfuse-address 0x08000000:force:mass-erase -D PATH/TO/circuitpython/ports/stm/build-feather_stm32f405_express/firmware.bin -``` -## File Setup - -> **If using `run_serial_tests.py`** this step is done automatically — skip ahead. - -Copy the WAV test samples onto the board's `CIRCUITPY` drive root: - -``` -cp \ - tests/circuitpython-manual/audiocore/jeplayer-splash-8000-8bit-mono-unsigned.wav \ - tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-mono-signed.wav \ - tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-mono-signed.wav \ - tests/circuitpython-manual/audiocore/jeplayer-splash-8000-16bit-stereo-signed.wav \ - tests/circuitpython-manual/audiocore/jeplayer-splash-44100-16bit-stereo-signed.wav \ - /Volumes/CIRCUITPY/ -``` - -These five files cover every exercised code path: -- `8000-8bit-mono-unsigned` — 8-bit unsigned decode path, audibly lo-fi -- `8000-16bit-mono-signed` — 16-bit signed decode path at lowest sample rate -- `44100-16bit-mono-signed` — 16-bit at highest sample rate (DMA reconfiguration, audible quality difference) -- `8000-16bit-stereo-signed` — stereo decode path, left→A0, right→A1 -- `44100-16bit-stereo-signed` — stereo at 44.1 kHz - -Stereo, 24-bit, and the 16 kHz files are omitted: stereo and 24-bit will `OSError`; 16 kHz adds no new code paths over 8 kHz and 44.1 kHz. - -Copy the test scripts to the board as well (or paste them into the REPL): - -``` -cp tests/circuitpython-manual/audioio/wavefile_playback.py /Volumes/CIRCUITPY/ -cp tests/circuitpython-manual/audioio/wavefile_pause_resume.py /Volumes/CIRCUITPY/ -cp tests/circuitpython-manual/audioio/single_buffer_loop.py /Volumes/CIRCUITPY/ -cp tests/circuitpython-manual/audioio/stereo_playback.py /Volumes/CIRCUITPY/ -``` - -## Test 1 — WAV File Playback (`wavefile_playback.py`) *(automated)* - -Verifies that `AudioOut` can play WAV files at 8 kHz, 16 kHz, and 44.1 kHz in mono and stereo (only left channel output), with 8-bit unsigned and 16-bit signed encodings. - -**Note:** 24-bit WAV files and the stereo MP3 are intentionally excluded — `audiocore.WaveFile` does not support 24-bit, and those files will print an `OSError`. That is expected. - -**Run from the REPL:** - -```python -import os -os.chdir("/") -exec(open("wavefile_playback.py").read()) -``` - -**Expected output (order may vary by filename sort):** - -``` -playing jeplayer-splash-44100-16bit-mono-signed.wav -playing jeplayer-splash-8000-16bit-mono-signed.wav -playing jeplayer-splash-8000-8bit-mono-unsigned.wav -done -``` - -**What to listen for:** - -- Each supported WAV plays the "jeplayer splash" jingle to completion before the next starts. -- No loud pops at the start or end of each file (the DAC ramp-in / ramp-out should suppress them). -- Audio pitch should match the sample rate: the 44100 Hz file sounds the most natural; the 8000 Hz file sounds lower fidelity. - -## Test 2 — Pause and Resume (`wavefile_pause_resume.py`) *(automated)* - -Verifies `AudioOut.pause()` / `AudioOut.resume()` by toggling every 100 ms during playback. The audio will sound choppy — that is intentional. - -**Run from the REPL:** - -```python -exec(open("wavefile_pause_resume.py").read()) -``` - -**Expected output (repeating for each WAV):** - -``` -playing with pause/resume: jeplayer-splash-44100-16bit-mono-signed.wav - paused - resumed - ... -playing with pause/resume: jeplayer-splash-8000-16bit-mono-signed.wav - paused - resumed - ... -playing with pause/resume: jeplayer-splash-8000-8bit-mono-unsigned.wav - paused - resumed - ... -done -``` - -**What to verify:** - -- The REPL prints alternating "paused" / "resumed" lines. -- Audio cuts in and out in sync with the prints. -- Playback eventually completes (the `while dac.playing` loop exits normally). -- No hard fault or hang. - -## Test 3 — Looping Sine Wave (`single_buffer_loop.py`) *(automated)* - -Verifies `RawSample` with `loop=True` and tests all four sample formats: -`unsigned 8-bit`, `signed 8-bit`, `unsigned 16-bit`, `signed 16-bit`. - -Each sample generates one cycle of a 440 Hz sine wave and loops for 1 second. - -**Run from the REPL:** - -```python -exec(open("single_buffer_loop.py").read()) -``` - -**Expected output:** - -``` -unsigned 8 bit - -signed 8 bit - -unsigned 16 bit - -signed 16 bit - -done -``` - -**What to listen for:** - -- A 440 Hz tone (concert A) for approximately 1 second for each format. -- All four formats should sound essentially identical in pitch and volume. -- No pops or glitches during the loop. -- Clean silence between tones (quiescent DAC value holds between `stop()` calls). - -## Test 4 — `deinit` and Re-init *(automated)* - -Verifies that `AudioOut` can be deconstructed and reconstructed without rebooting, and that pin A0 is properly released. - -```python -import audioio, analogio, board - -# Construct and immediately deinit AudioOut -dac = audioio.AudioOut(board.A0) -dac.deinit() - -# PA04 should now be free for AnalogOut -aout = analogio.AnalogOut(board.A0) -aout.value = 32768 # mid-scale -aout.deinit() - -# Re-create AudioOut on the same pin -dac2 = audioio.AudioOut(board.A0) -dac2.deinit() -print("pass") -``` - -**Expected output:** `pass` with no exceptions. - -## Test 5 — Stereo Playback (`stereo_playback.py`) *(automated)* - -Verifies that `AudioOut(board.A0, right_channel=board.A1)` drives both DAC -channels independently: left on **A0 (PA04, DAC_CH1)**, right on -**A1 (PA05, DAC_CH2)**, both clocked by TIM6. - -The script runs four phases in order: - -1. **Left-only 440 Hz tone** (~1 s) — only A0 should produce audio. -2. **Right-only 440 Hz tone** (~1 s) — only A1 should produce audio. -3. **Both-channel 440 Hz tone** (~1 s) — equal amplitude on both pins. -4. **Pan sweep L → R** (~2 s) — 8 stepped amplitude stages from A0 to A1 (small looped buffers; full continuous sweep would not fit in heap). -5. Then plays each stereo WAV (`44100` and `8000` Hz) in full. - -**Hardware required:** connect a stereo headphone/amp to A0 (left) and A1 -(right) with common ground, or scope-probe each pin separately. - -**Run from the REPL:** - -```python -import os -os.chdir("/") -exec(open("stereo_playback.py").read()) -``` - -**Expected output:** - -``` -channel test: left only -channel test: right only -channel test: both channels -pan sweep: left to right -playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav -playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav -done -``` - -**What to listen / look for:** - -- "left only" → tone in left ear, silence in right. -- "right only" → tone in right ear, silence in left. -- "both channels" → centered tone in both ears. -- "pan sweep" → tone steps left → right across 8 amplitude stages over 2 s. -- Stereo WAVs play with proper L/R separation; no cross-contamination. -- On a scope: probing A0 and A1 simultaneously during phases 1 and 2 should - show one channel idle (mid-scale DC) while the other carries the sine. - -## Test 6 — Soft Reset Cleanup *(manual)* - -Verifies that `audioout_reset()` properly cleans up when the REPL soft-resets during active playback. - -1. Start a looping tone in the REPL: - -```python -import audiocore, audioio, board, array, math, time -length = 8000 // 440 -s16 = array.array("h", [int(math.sin(math.pi * 2 * i / length) * 32767) for i in range(length)]) -dac = audioio.AudioOut(board.A0) -dac.play(audiocore.RawSample(s16, sample_rate=8000), loop=True) -``` - -2. While the tone is playing, press **Ctrl-C** then **Ctrl-D** (soft reset). - -**Expected:** -- **Ctrl-C** interrupts the Python code but the tone *keeps playing* — this is normal. The DMA and TIM6 run in hardware independently of Python; a `KeyboardInterrupt` does not stop them. -- **Ctrl-D** triggers a soft reset which calls `audioout_reset()`. The tone stops immediately and the board returns to the `>>>` prompt with no crash or fault. -- Running any of the above tests again afterwards should work normally. - -## Oscilloscope Checks (Optional) - -Each test script drives `board.D4` (pin D4) low at the start of each playback and high when it ends. This provides a clean trigger edge for a scope. - -- **Test 1:** Probe A0 — should show a sampled waveform at the correct sample rate. Probe D4 for a gate signal that spans the file duration. -- **Test 3:** Probe A0 — should show a 440 Hz staircase-sine at the DAC output (12-bit steps visible at 44.1 kHz; fewer at 8 kHz). A simple RC low-pass filter (1 kΩ + 100 nF) on the A0 output will smooth the staircase significantly. - -## Known Limitations - -- **Left channel must be A0 (PA04)**. Any other pin raises `ValueError: AudioOut requires pin A0 (PA04)`. -- **Right channel must be A1 (PA05)** when used. Any other pin raises `ValueError: AudioOut right channel requires pin A1 (PA05)`. -- **24-bit WAV files** are not supported by `audiocore.WaveFile` and will raise `OSError` when opened. -- Only one `AudioOut` instance can be active at a time. diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py index a39b988f654..20156213c83 100644 --- a/tests/circuitpython-manual/audioio/run_serial_tests.py +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -84,6 +84,90 @@ def _mpremote(args: list, timeout: float = 30.0): sys.exit("mpremote not found. Run: pip install mpremote") +# stderr substrings that indicate a transient host/USB issue worth retrying. +# Matched case-insensitively. CircuitPython USB-CDC briefly disappears during +# soft-reset and after some heavy DMA activity; mpremote's next invocation then +# either can't open the port or sees the kernel still holding the previous +# descriptor. +_RETRYABLE_STDERR = ( + "could not enter raw repl", + "failed to access", + "device not configured", + "errno 6", + "errno 16", + "resource busy", + "could not open", + "no such file or directory", + "serialexception", + "device disconnected", + "could not exclusively lock", +) + + +def _is_retryable(stderr: str) -> bool: + s = stderr.lower() + return any(needle in s for needle in _RETRYABLE_STDERR) + + +def _port_holders(port: str) -> list[str]: + """Return a human-readable list of processes holding *port* (Unix only). + + macOS / Linux only — uses `lsof`. Returns lines like "Code Helper (51298)". + Empty list when nothing holds the port or `lsof` is unavailable. + """ + if not port.startswith("/"): + return [] + holders: list[str] = [] + # Both /dev/cu.* (callout) and /dev/tty.* (dial-in) refer to the same UART + # on macOS — VS Code typically opens /dev/tty.* while we ask for /dev/cu.*, + # so check both. + candidates = {port} + if "/cu." in port: + candidates.add(port.replace("/cu.", "/tty.", 1)) + elif "/tty." in port: + candidates.add(port.replace("/tty.", "/cu.", 1)) + for path in candidates: + if not os.path.exists(path): + continue + try: + result = subprocess.run( + ["lsof", "-Fcp", path], + capture_output=True, + text=True, + timeout=5, + ) + except (FileNotFoundError, subprocess.TimeoutExpired): + return [] + pid = command = None + for line in result.stdout.splitlines(): + if line.startswith("p"): + pid = line[1:] + elif line.startswith("c"): + command = line[1:] + if pid: + holders.append(f"{command} (PID {pid}) on {path}") + pid = command = None + return holders + + +def _wait_for_port(port: str, timeout: float = 10.0) -> bool: + """Block until *port* exists in the filesystem, or *timeout* elapses. + + macOS / Linux expose serial ports as /dev nodes; Windows uses COMx which is + not a filesystem path, so on Windows we just sleep briefly and trust the + next mpremote call to surface the real error. + """ + if not port.startswith("/"): + time.sleep(0.5) + return True + deadline = time.time() + timeout + while time.time() < deadline: + if os.path.exists(port): + return True + time.sleep(0.1) + return False + + def _interrupt_running_code(port: str, soft_reset: bool = False) -> None: """Halt any code running on the device so mpremote can enter raw REPL. @@ -146,7 +230,9 @@ def find_circuitpy() -> str | None: system = platform.system() if system == "Darwin": - candidates = ["/Volumes/CIRCUITPY"] + # Glob so a second CIRCUITPY volume (mounted as "CIRCUITPY 1") is found. + import glob + candidates = sorted(glob.glob("/Volumes/CIRCUITPY*")) elif system == "Windows": # Scan all drive letters for a CIRCUITPY volume label. import string @@ -225,11 +311,15 @@ def _check(condition: bool, message: str) -> bool: return condition -def _run_exec(port: str, code: str, label: str, timeout: float, retries: int = 2): +def _run_exec(port: str, code: str, label: str, timeout: float, retries: int = 3): """Execute *code* on the device via mpremote exec and print the output. - Retries on `could not enter raw repl` after sending a Ctrl-C burst — this - handles the case where a busy code.py blocks mpremote's first handshake. + Retries cover three failure modes: + * raw-REPL handshake blocked by a running code.py → Ctrl-C burst. + * Persistent handshake failure → soft-reset + Ctrl-C flood. + * Host-side serial drop ("device in use", "Errno 6", etc.) → wait for the + port node to re-appear, then retry. CircuitPython's USB-CDC can briefly + vanish after heavy DMA traffic or soft-reset. """ print(f"\n{'=' * 60}") print(f" {label}") @@ -237,6 +327,9 @@ def _run_exec(port: str, code: str, label: str, timeout: float, retries: int = 2 stdout = "" stderr = "" for attempt in range(retries + 1): + if not _wait_for_port(port, timeout=10.0): + print(f" [retry {attempt}/{retries}] port {port} not present — waited 10s") + continue try: stdout, stderr = _mpremote( ["connect", port, "exec", code], timeout=timeout @@ -244,13 +337,19 @@ def _run_exec(port: str, code: str, label: str, timeout: float, retries: int = 2 except TimeoutError as exc: print(f" [FAIL] {exc}") return False, "", "" - if "could not enter raw repl" not in stderr: + if not _is_retryable(stderr): break if attempt < retries: - # Escalate: first attempt = Ctrl-C burst; second = Ctrl-D reboot. - escalate = attempt >= 1 - tactic = "soft-reset + Ctrl-C flood" if escalate else "Ctrl-C burst" - print(f" [retry {attempt + 1}/{retries}] raw REPL busy — {tactic}") + handshake = "could not enter raw repl" in stderr.lower() + # Soft-reset only on persistent raw-REPL failures, not on host drops + # (a soft-reset there just makes the disconnect window longer). + escalate = handshake and attempt >= 1 + if handshake: + tactic = "soft-reset + Ctrl-C flood" if escalate else "Ctrl-C burst" + else: + tactic = f"port-drop recovery ({stderr.strip().splitlines()[-1] if stderr.strip() else '?'})" + print(f" [retry {attempt + 1}/{retries}] {tactic}") + _wait_for_port(port, timeout=10.0) _interrupt_running_code(port, soft_reset=escalate) time.sleep(0.5) print("Output:") @@ -263,6 +362,19 @@ def _run_exec(port: str, code: str, label: str, timeout: float, retries: int = 2 return True, stdout, stderr +def _settle_between_tests(port: str) -> None: + """Drain any lingering REPL output and wait for the port to be ready. + + CircuitPython occasionally re-enumerates its USB-CDC after a heavy test; + next mpremote call then races the kernel re-binding the tty. Polling for + the port node and then sending a Ctrl-C burst gives the host a clean + starting state before the next exec. + """ + _wait_for_port(port, timeout=10.0) + _interrupt_running_code(port, soft_reset=False) + time.sleep(0.3) + + # --------------------------------------------------------------------------- # Individual tests # --------------------------------------------------------------------------- @@ -275,9 +387,9 @@ def test1_wavefile_playback(port: str) -> bool: if not ok: return False passed = True - passed &= _check("playing jeplayer-splash-44100-16bit-mono-signed.wav" in stdout, "44100 Hz 16-bit mono WAV played") - passed &= _check("playing jeplayer-splash-8000-16bit-mono-signed.wav" in stdout, "8000 Hz 16-bit mono WAV played") - passed &= _check("playing jeplayer-splash-8000-8bit-mono-unsigned.wav" in stdout, "8000 Hz 8-bit unsigned WAV played") + for wav in sorted(WAV_FILES): + passed &= _check(f"playing {wav}" in stdout, f"played {wav}") + passed &= _check("OSError" not in stdout, "No OSError reported during playback") passed &= _check("done" in stdout, "Script completed with 'done'") passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") return passed @@ -295,6 +407,8 @@ def test2_pause_resume(port: str) -> bool: passed &= _check(f"playing with pause/resume: {wav}" in stdout, f"pause/resume header for {wav}") passed &= _check("paused" in stdout, "At least one 'paused' line printed") passed &= _check("resumed" in stdout, "At least one 'resumed' line printed") + passed &= _check("TIMEOUT" not in stdout, "No pause/resume hang timeout") + passed &= _check("OSError" not in stdout, "No OSError reported during playback") passed &= _check("done" in stdout, "Script completed with 'done'") passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") return passed @@ -378,23 +492,41 @@ def main(): port = args.port or find_port() print(f"Using port: {port}\n") + # Surface the common "VS Code has the serial monitor open" pitfall up front + # — otherwise every test fails with the opaque "in use by another program". + holders = _port_holders(port) + if holders: + print("ERROR: port is held by another process:") + for h in holders: + print(f" {h}") + print( + "Close the offending app (e.g. VS Code Serial Monitor, screen, tio)\n" + "and re-run. mpremote needs exclusive access." + ) + sys.exit(2) + if not args.no_copy: copy_files(port, circuitpy=args.circuitpy) # Halt any running code.py so the first test gets a clean raw-REPL entry. _interrupt_running_code(port) + test_runners = [ + ("1", "Test 1 — WAV Playback", test1_wavefile_playback), + ("2", "Test 2 — Pause/Resume", test2_pause_resume), + ("3", "Test 3 — Looping Sine", test3_single_buffer_loop), + ("4", "Test 4 — deinit/Re-init", test4_deinit), + ("5", "Test 5 — Stereo Playback", test5_stereo_playback), + ] results: dict[str, bool] = {} - if "1" in selected: - results["Test 1 — WAV Playback"] = test1_wavefile_playback(port) - if "2" in selected: - results["Test 2 — Pause/Resume"] = test2_pause_resume(port) - if "3" in selected: - results["Test 3 — Looping Sine"] = test3_single_buffer_loop(port) - if "4" in selected: - results["Test 4 — deinit/Re-init"] = test4_deinit(port) - if "5" in selected: - results["Test 5 — Stereo Playback"] = test5_stereo_playback(port) + first = True + for key, name, runner in test_runners: + if key not in selected: + continue + if not first: + _settle_between_tests(port) + first = False + results[name] = runner(port) print(f"\n{'=' * 60}") print("SUMMARY") diff --git a/tests/circuitpython-manual/audioio/single_buffer_loop.py b/tests/circuitpython-manual/audioio/single_buffer_loop.py index bce6a7a2cf3..929e03e6d10 100644 --- a/tests/circuitpython-manual/audioio/single_buffer_loop.py +++ b/tests/circuitpython-manual/audioio/single_buffer_loop.py @@ -13,7 +13,9 @@ except AttributeError: trigger = None -# Generate one period of a 440 Hz sine wave at each sample rate. +# Generate one period of a 440 Hz sine wave. All four samples use the same +# sample rate so each plays the same audible pitch — the test is comparing +# the four format-conversion paths, not playback rates. sample_rate = 8000 length = sample_rate // 440 # samples per cycle @@ -23,25 +25,25 @@ u8 = array.array("B", [0] * length) for i in range(length): u8[i] = int(math.sin(math.pi * 2 * i / length) * 127 + 128) -samples = [audiocore.RawSample(u8, sample_rate=8000)] +samples = [audiocore.RawSample(u8, sample_rate=sample_rate)] # signed 8 bit s8 = array.array("b", [0] * length) for i in range(length): s8[i] = int(math.sin(math.pi * 2 * i / length) * 127) -samples.append(audiocore.RawSample(s8, sample_rate=16000)) +samples.append(audiocore.RawSample(s8, sample_rate=sample_rate)) # unsigned 16 bit u16 = array.array("H", [0] * length) for i in range(length): u16[i] = int(math.sin(math.pi * 2 * i / length) * 32767 + 32768) -samples.append(audiocore.RawSample(u16, sample_rate=8000)) +samples.append(audiocore.RawSample(u16, sample_rate=sample_rate)) # signed 16 bit s16 = array.array("h", [0] * length) for i in range(length): s16[i] = int(math.sin(math.pi * 2 * i / length) * 32767) -samples.append(audiocore.RawSample(s16, sample_rate=44100)) +samples.append(audiocore.RawSample(s16, sample_rate=sample_rate)) dac = audioio.AudioOut(board.A0) for sample, name in zip(samples, sample_names): diff --git a/tests/circuitpython-manual/audioio/stereo_playback.py b/tests/circuitpython-manual/audioio/stereo_playback.py index a3817e010d9..cfdb4d39540 100644 --- a/tests/circuitpython-manual/audioio/stereo_playback.py +++ b/tests/circuitpython-manual/audioio/stereo_playback.py @@ -29,8 +29,7 @@ def stereo_buffer(left, right): - # Init from bytes to avoid the temporary [0]*N int list (heavy on F405 RAM). - buf = array.array("h", b"\x00\x00" * (len(left) * 2)) + buf = array.array("h", [0] * (len(left) * 2)) for i in range(len(left)): buf[2 * i] = left[i] buf[2 * i + 1] = right[i] diff --git a/tests/circuitpython-manual/audioio/wavefile_pause_resume.py b/tests/circuitpython-manual/audioio/wavefile_pause_resume.py index 13a227c0274..c3002c6b5d1 100644 --- a/tests/circuitpython-manual/audioio/wavefile_pause_resume.py +++ b/tests/circuitpython-manual/audioio/wavefile_pause_resume.py @@ -35,7 +35,16 @@ dac.play(sample) # Deliberately toggle pause/resume every 100 ms to stress-test the # pause/resume cycle. Audio will sound choppy — that is expected. + # The wall-clock guard makes the test fail loudly instead of hanging + # if pause() ever leaves the driver in a state where playing never + # clears. 30 s is enough for the longest 44.1 kHz mono WAV in the + # set even with pause-doubling. + deadline = time.monotonic() + 30.0 while dac.playing: + if time.monotonic() > deadline: + print(" TIMEOUT waiting for playback to finish") + dac.stop() + break time.sleep(0.1) if not dac.playing: # may have finished during sleep break From dce5290c4158d12776187c0a1d1541e35d809c3e Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sat, 2 May 2026 21:19:48 -0700 Subject: [PATCH 448/876] ports/stm: note atmel-samd freq bias near TIM6 round-to-nearest Sweep audits across boards showed atmel-samd has a constant -3.4 cent bias on every tone, consistent with truncating its TIM period. Flag that next to our round-to-nearest so the fix is portable. Co-Authored-By: Claude Opus 4.7 --- ports/stm/common-hal/audioio/AudioOut.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index d66c239c69a..b375da758fc 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -519,6 +519,10 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, uint32_t tim6_clk = get_tim6_freq(); // Round to nearest, not truncate, so the realised sample rate is the // closest TIM6 division to the requested rate. + // NOTE: a sweep audit on atmel-samd (Circuit Playground Express) shows a + // constant -3.4 cent frequency bias across all tones, consistent with a + // truncating period calculation there. The same round-to-nearest fix + // would likely tighten frequency accuracy on that port too. uint32_t period = (tim6_clk + sample_rate / 2) / sample_rate; if (period < 2) { period = 2; From 017e88013d2c1cd472bd46e66587aa5fbc866250 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 3 May 2026 09:26:45 -0400 Subject: [PATCH 449/876] docs/shared_bindings_matrix: stdout gets mixed up when print-SETTING runs in parallel --- docs/shared_bindings_matrix.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/shared_bindings_matrix.py b/docs/shared_bindings_matrix.py index 8fbee4beea5..2f9eb796788 100644 --- a/docs/shared_bindings_matrix.py +++ b/docs/shared_bindings_matrix.py @@ -200,6 +200,8 @@ def get_settings_from_makefile(port_dir, board_name): contents = subprocess.run( [ "make", + # Don't let make run in parallel; it can mix up the output from the various "print-" targets. + "-j1", "-C", port_dir, "-f", From ef2777a6dc8c408c0b5e67a9b585cb8a5e10edb7 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 3 May 2026 09:37:35 -0400 Subject: [PATCH 450/876] docs/rstjinja.py: use raw string for regexp --- docs/rstjinja.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rstjinja.py b/docs/rstjinja.py index 04c855a1a40..ab940dc7134 100644 --- a/docs/rstjinja.py +++ b/docs/rstjinja.py @@ -5,7 +5,7 @@ def render_with_jinja(docname, source): - if re.search("^\s*.. jinja$", source[0], re.M): + if re.search(r"^\s*.. jinja$", source[0], re.M): return True return False From 92d17a812b07e921d16e226e1943c2bed501d5a0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 3 May 2026 09:38:33 -0400 Subject: [PATCH 451/876] shared-bindings/supervisor/__init__.c: fix doc typo --- shared-bindings/supervisor/__init__.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-bindings/supervisor/__init__.c b/shared-bindings/supervisor/__init__.c index 1200679f2e2..a331249998a 100644 --- a/shared-bindings/supervisor/__init__.c +++ b/shared-bindings/supervisor/__init__.c @@ -379,8 +379,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(supervisor_set_usb_identification_obj, 0, supervisor_ //| - ``str``: Double-quoted string. //| The string may include Unicode characters, and ``\\u`` Unicode escapes. Backslash-escaped characters //| ``\\b``, ``\\r``, ``\\n``, ``\\t``, ``\\v``, ``\\v`` are also allowed. -//| - ``int``: signed or unsigned integer -//| - ``bool``: lower-case `true`` or ``false``. +//| - ``int``: signed or unsigned integer. +//| - ``bool``: lower-case ``true`` or ``false``. //| The values are returned as Python ``True`` or ``False`` values. //| - ``float``: signed or unsigned decimal number with a ``.`` or exponent, or ``inf``, ``inf``, ``nan``. //| From c48300771a1859aa86081d52b2bda47d0fd0df93 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 3 May 2026 15:18:56 -0700 Subject: [PATCH 452/876] tests: pre-flight CIRCUITPY free-space check in audioio runner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit STM32F4 CIRCUITPY is only ~2 MiB. With a leftover code.py + stale WAVs the runner can't fit the 5 test WAVs (~1.3 MiB), and macOS surfaces the resulting ENOSPC as a misleading "Operation not permitted" — the first attempt to run this suite on a fresh dev machine wasted real time chasing it as a permission issue. Sum the bytes we're about to write up front and bail with a concrete "need / free / short" summary so the next contributor knows immediately to clear unrelated files. Co-Authored-By: Claude Opus 4.7 --- .../audioio/run_serial_tests.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py index 20156213c83..03017c420f0 100644 --- a/tests/circuitpython-manual/audioio/run_serial_tests.py +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -273,6 +273,31 @@ def copy_files(port: str, circuitpy: str | None = None): [(os.path.join(AUDIOCORE_DIR, w), w) for w in WAV_FILES] + [(os.path.join(SCRIPT_DIR, s), s) for s in TEST_SCRIPTS] ) + # STM32F4 CIRCUITPY is only ~2 MiB. Leftover files from prior runs + # (a sweep generator code.py, stale WAVs) routinely fill it; macOS + # then reports ENOSPC as a misleading "Operation not permitted", + # which sent the first contributor chasing a permission red herring. + # Sum what we're about to write and bail loudly if it won't fit, + # discounting space the dst already occupies. + if mount: + needed = 0 + for src, dst in files: + if not os.path.exists(src): + continue + needed += os.path.getsize(src) + dest_path = os.path.join(mount, dst) + if os.path.exists(dest_path): + needed -= os.path.getsize(dest_path) + free = shutil.disk_usage(mount).free + if needed > free: + short = needed - free + print(f"ERROR: not enough space on {mount}.") + print(f" need: {needed/1024:.1f} KiB") + print(f" free: {free/1024:.1f} KiB") + print(f" short: {short/1024:.1f} KiB") + print(f" Delete unrelated files (e.g. an old code.py or " + f"stale WAVs) and re-run.") + sys.exit(1) missing = [] for src, dst in files: if not os.path.exists(src): From 11b441fcc71e2d522b491a14b16f9f8670be6d68 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 3 May 2026 15:19:39 -0700 Subject: [PATCH 453/876] tests: capture audioio runner results from F405 (all 5 PASS) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit run_serial_tests.py output from a Feather STM32F405 Express, captured via tee. Tests 1–5 (WAV playback, pause/resume, looping sine, deinit/re-init, stereo) all pass; manual Test 6 (soft-reset cleanup) is documented separately. Co-Authored-By: Claude Opus 4.7 --- tests/circuitpython-manual/audioio/results.md | 496 ++++++++++++++++++ .../audioio/run_serial_tests.py | 7 +- 2 files changed, 497 insertions(+), 6 deletions(-) create mode 100644 tests/circuitpython-manual/audioio/results.md diff --git a/tests/circuitpython-manual/audioio/results.md b/tests/circuitpython-manual/audioio/results.md new file mode 100644 index 00000000000..b994f84258f --- /dev/null +++ b/tests/circuitpython-manual/audioio/results.md @@ -0,0 +1,496 @@ +# audioio — `run_serial_tests.py` results + +- **Board:** Adafruit Feather STM32F405 Express +- **Suite:** Tests 1–5 automated (Test 6 soft-reset is manual) +- **Result:** all PASS + +``` +Using port: /dev/cu.usbmodem101 + +Copying files to board via /Volumes/CIRCUITPY ... + jeplayer-splash-8000-8bit-mono-unsigned.wav (copied) + jeplayer-splash-8000-16bit-mono-signed.wav (copied) + jeplayer-splash-44100-16bit-mono-signed.wav (copied) + jeplayer-splash-8000-16bit-stereo-signed.wav (copied) + jeplayer-splash-44100-16bit-stereo-signed.wav (copied) + wavefile_playback.py (copied) + wavefile_pause_resume.py (copied) + single_buffer_loop.py (copied) + stereo_playback.py (copied) + + +============================================================ + Test 1 — WAV File Playback (wavefile_playback.py) +============================================================ +Output: + playing jeplayer-splash-44100-16bit-mono-signed.wav + + playing jeplayer-splash-44100-16bit-stereo-signed.wav + + playing jeplayer-splash-8000-16bit-mono-signed.wav + + playing jeplayer-splash-8000-16bit-stereo-signed.wav + + playing jeplayer-splash-8000-8bit-mono-unsigned.wav + + done + [PASS] played jeplayer-splash-44100-16bit-mono-signed.wav + [PASS] played jeplayer-splash-44100-16bit-stereo-signed.wav + [PASS] played jeplayer-splash-8000-16bit-mono-signed.wav + [PASS] played jeplayer-splash-8000-16bit-stereo-signed.wav + [PASS] played jeplayer-splash-8000-8bit-mono-unsigned.wav + [PASS] No OSError reported during playback + [PASS] Script completed with 'done' + [PASS] No exceptions (stderr='') + +============================================================ + Test 2 — Pause / Resume (wavefile_pause_resume.py) +============================================================ +Output: + playing with pause/resume: jeplayer-splash-44100-16bit-mono-signed.wav + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + + playing with pause/resume: jeplayer-splash-44100-16bit-stereo-signed.wav + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + + playing with pause/resume: jeplayer-splash-8000-16bit-mono-signed.wav + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + + playing with pause/resume: jeplayer-splash-8000-16bit-stereo-signed.wav + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + + playing with pause/resume: jeplayer-splash-8000-8bit-mono-unsigned.wav + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + paused + resumed + + done + [PASS] pause/resume header for jeplayer-splash-44100-16bit-mono-signed.wav + [PASS] pause/resume header for jeplayer-splash-44100-16bit-stereo-signed.wav + [PASS] pause/resume header for jeplayer-splash-8000-16bit-mono-signed.wav + [PASS] pause/resume header for jeplayer-splash-8000-16bit-stereo-signed.wav + [PASS] pause/resume header for jeplayer-splash-8000-8bit-mono-unsigned.wav + [PASS] At least one 'paused' line printed + [PASS] At least one 'resumed' line printed + [PASS] No pause/resume hang timeout + [PASS] No OSError reported during playback + [PASS] Script completed with 'done' + [PASS] No exceptions (stderr='') + +============================================================ + Test 3 — Looping Sine Wave (single_buffer_loop.py) +============================================================ +Output: + unsigned 8 bit + + signed 8 bit + + unsigned 16 bit + + signed 16 bit + + done + [PASS] 'unsigned 8 bit' label printed + [PASS] 'signed 8 bit' label printed + [PASS] 'unsigned 16 bit' label printed + [PASS] 'signed 16 bit' label printed + [PASS] Script completed with 'done' + [PASS] No exceptions (stderr='') + +============================================================ + Test 4 — deinit and Re-init (inline) +============================================================ +Output: + pass + [PASS] Script printed 'pass' + [PASS] No exceptions (stderr='') + +============================================================ + Test 5 — Stereo Playback (stereo_playback.py) +============================================================ +Output: + channel test: left only + + channel test: right only + + channel test: both channels + + pan sweep: left to right + + playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav + + playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav + + done + [PASS] Left-only channel tone played + [PASS] Right-only channel tone played + [PASS] Both-channel tone played + [PASS] Pan sweep played + [PASS] 44100 Hz 16-bit stereo WAV played + [PASS] 8000 Hz 16-bit stereo WAV played + [PASS] Script completed with 'done' + [PASS] No exceptions (stderr='') + +============================================================ +SUMMARY +============================================================ + [PASS] Test 1 — WAV Playback + [PASS] Test 2 — Pause/Resume + [PASS] Test 3 — Looping Sine + [PASS] Test 4 — deinit/Re-init + [PASS] Test 5 — Stereo Playback + +All automated tests passed. +Remaining manual step: Test 6 (soft-reset) and audio/oscilloscope verification. +``` diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py index 03017c420f0..a63a4bace41 100644 --- a/tests/circuitpython-manual/audioio/run_serial_tests.py +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -273,12 +273,7 @@ def copy_files(port: str, circuitpy: str | None = None): [(os.path.join(AUDIOCORE_DIR, w), w) for w in WAV_FILES] + [(os.path.join(SCRIPT_DIR, s), s) for s in TEST_SCRIPTS] ) - # STM32F4 CIRCUITPY is only ~2 MiB. Leftover files from prior runs - # (a sweep generator code.py, stale WAVs) routinely fill it; macOS - # then reports ENOSPC as a misleading "Operation not permitted", - # which sent the first contributor chasing a permission red herring. - # Sum what we're about to write and bail loudly if it won't fit, - # discounting space the dst already occupies. + # Check if device has enough space for test files if mount: needed = 0 for src, dst in files: From 2e97b2790d65d2f702a145f79e9e89c521c49edb Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 3 May 2026 15:28:23 -0700 Subject: [PATCH 454/876] tests: drop manual soft-reset test from audioio suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test 6 (soft-reset during active playback) is covered in practice by the external frequency-sweep rig, which exercises start / stop / re- play across 30 tones in series — the same lifecycle paths the manual Ctrl-C/Ctrl-D test was checking. Drops the README section, the table row, the results-file note, and the trailing "remaining manual step" print so the docs/runner consistently say "Tests 1–5". Co-Authored-By: Claude Opus 4.7 --- tests/circuitpython-manual/audioio/README.md | 22 ------------------- tests/circuitpython-manual/audioio/results.md | 4 ++-- .../audioio/run_serial_tests.py | 6 ++--- 3 files changed, 4 insertions(+), 28 deletions(-) diff --git a/tests/circuitpython-manual/audioio/README.md b/tests/circuitpython-manual/audioio/README.md index bddeec83779..66377e75ffa 100644 --- a/tests/circuitpython-manual/audioio/README.md +++ b/tests/circuitpython-manual/audioio/README.md @@ -11,7 +11,6 @@ These tests exercise the DAC-based `audioio.AudioOut` implementation added for S | 3 — Looping Sine Wave | Yes | Yes (audio check) | | 4 — deinit and Re-init | Yes | No | | 5 — Stereo Playback | Yes | Yes (audio check) | -| 6 — Soft Reset Cleanup | No (manual Ctrl-C/D) | No | `run_serial_tests.py` automates Tests 1–5: it copies the necessary files to the board and runs each script over the serial REPL, comparing the printed output to @@ -291,27 +290,6 @@ done - On a scope: probing A0 and A1 simultaneously during phases 1 and 2 should show one channel idle (mid-scale DC) while the other carries the sine. -## Test 6 — Soft Reset Cleanup *(manual)* - -Verifies that `audioout_reset()` properly cleans up when the REPL soft-resets during active playback. - -1. Start a looping tone in the REPL: - -```python -import audiocore, audioio, board, array, math, time -length = 8000 // 440 -s16 = array.array("h", [int(math.sin(math.pi * 2 * i / length) * 32767) for i in range(length)]) -dac = audioio.AudioOut(board.A0) -dac.play(audiocore.RawSample(s16, sample_rate=8000), loop=True) -``` - -2. While the tone is playing, press **Ctrl-C** then **Ctrl-D** (soft reset). - -**Expected:** -- **Ctrl-C** interrupts the Python code but the tone *keeps playing* — this is normal. The DMA and TIM6 run in hardware independently of Python; a `KeyboardInterrupt` does not stop them. -- **Ctrl-D** triggers a soft reset which calls `audioout_reset()`. The tone stops immediately and the board returns to the `>>>` prompt with no crash or fault. -- Running any of the above tests again afterwards should work normally. - ## Oscilloscope Checks (Optional) Each test script drives `board.D4` (pin D4) low at the start of each playback and high when it ends. This provides a clean trigger edge for a scope. diff --git a/tests/circuitpython-manual/audioio/results.md b/tests/circuitpython-manual/audioio/results.md index b994f84258f..afb9c9ad870 100644 --- a/tests/circuitpython-manual/audioio/results.md +++ b/tests/circuitpython-manual/audioio/results.md @@ -1,7 +1,7 @@ # audioio — `run_serial_tests.py` results - **Board:** Adafruit Feather STM32F405 Express -- **Suite:** Tests 1–5 automated (Test 6 soft-reset is manual) +- **Suite:** Tests 1–5 automated - **Result:** all PASS ``` @@ -492,5 +492,5 @@ SUMMARY [PASS] Test 5 — Stereo Playback All automated tests passed. -Remaining manual step: Test 6 (soft-reset) and audio/oscilloscope verification. +Remaining manual step: audio/oscilloscope verification. ``` diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py index a63a4bace41..f6ec48cb847 100644 --- a/tests/circuitpython-manual/audioio/run_serial_tests.py +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -2,13 +2,11 @@ """ run_serial_tests.py — Automated REPL-based tests for STM32F405 audioio. -Automates Tests 1, 2, 3, and 4 from README.md by: +Automates Tests 1–5 from README.md by: 1. Copying WAV files and test scripts to the board via mpremote. 2. Running each test on the device via the CircuitPython REPL. 3. Comparing captured output to expected patterns and reporting PASS/FAIL. -Test 5 (soft-reset cleanup) still requires manual interaction. - Usage: python3 run_serial_tests.py python3 run_serial_tests.py --port /dev/cu.usbmodemXXX @@ -559,7 +557,7 @@ def main(): print() if all_passed: print("All automated tests passed.") - print("Remaining manual step: Test 6 (soft-reset) and audio/oscilloscope verification.") + print("Remaining manual step: audio/oscilloscope verification.") sys.exit(0) else: print("One or more tests FAILED — see details above.") From 0f28c948a4cf228db7f81e227da28eda81a5d83f Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Sun, 3 May 2026 23:19:09 -0700 Subject: [PATCH 455/876] chore: pre-commit fixups (locale, ruff-format, trailing whitespace) Auto-applied by pre-commit ahead of upstream PR: - locale/circuitpython.pot regenerated to include the new audioio MP_ERROR_TEXT strings ("DAC init error", "TIM6 init failed", etc.) - ruff-format reflow on the manual audioio test scripts - Trailing whitespace stripped from results.md No source-of-record changes; behaviour and APIs are identical. Co-Authored-By: Claude Opus 4.7 --- locale/circuitpython.pot | 51 +++++++++++++++++- tests/circuitpython-manual/audioio/results.md | 40 +++++++------- .../audioio/run_serial_tests.py | 52 ++++++++++++------- .../audioio/single_buffer_loop.py | 6 ++- .../audioio/wavefile_pause_resume.py | 10 ++-- .../audioio/wavefile_playback.py | 10 ++-- 6 files changed, 121 insertions(+), 48 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 833991ac476..d973a62cb5c 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -630,6 +630,18 @@ msgstr "" msgid "Audio source error" msgstr "" +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "AudioOut is deinited" +msgstr "" + +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "AudioOut requires pin A0 (PA04)" +msgstr "" + +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "AudioOut right channel requires pin A1 (PA05)" +msgstr "" + #: shared-bindings/wifi/Radio.c msgid "AuthMode.OPEN is not used with password" msgstr "" @@ -892,6 +904,14 @@ msgstr "" msgid "DAC Channel Init Error" msgstr "" +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC DMA start failed" +msgstr "" + +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC DMA start failed (right channel)" +msgstr "" + #: ports/stm/common-hal/analogio/AnalogOut.c msgid "DAC Device Init Error" msgstr "" @@ -900,6 +920,22 @@ msgstr "" msgid "DAC already in use" msgstr "" +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC channel config error" +msgstr "" + +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC init error" +msgstr "" + +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DMA init failed" +msgstr "" + +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DMA init failed (right)" +msgstr "" + #: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c #: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c msgid "Data 0 pin must be byte aligned" @@ -1541,6 +1577,7 @@ msgstr "" #: ports/atmel-samd/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "No DAC on chip" msgstr "" @@ -2109,6 +2146,14 @@ msgstr "" msgid "System entry must be gnss.SatelliteSystem" msgstr "" +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "TIM6 init failed" +msgstr "" + +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "TIM6 master cfg failed" +msgstr "" + #: ports/stm/common-hal/microcontroller/Processor.c msgid "Temperature read timed out" msgstr "" @@ -4049,7 +4094,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" @@ -4162,6 +4207,10 @@ msgstr "" msgid "rsplit(None,n)" msgstr "" +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "sample_rate must be > 0" +msgstr "" + #: shared-bindings/audiofreeverb/Freeverb.c msgid "samples_signed must be true" msgstr "" diff --git a/tests/circuitpython-manual/audioio/results.md b/tests/circuitpython-manual/audioio/results.md index afb9c9ad870..4e3459e6f80 100644 --- a/tests/circuitpython-manual/audioio/results.md +++ b/tests/circuitpython-manual/audioio/results.md @@ -24,15 +24,15 @@ Copying files to board via /Volumes/CIRCUITPY ... ============================================================ Output: playing jeplayer-splash-44100-16bit-mono-signed.wav - + playing jeplayer-splash-44100-16bit-stereo-signed.wav - + playing jeplayer-splash-8000-16bit-mono-signed.wav - + playing jeplayer-splash-8000-16bit-stereo-signed.wav - + playing jeplayer-splash-8000-8bit-mono-unsigned.wav - + done [PASS] played jeplayer-splash-44100-16bit-mono-signed.wav [PASS] played jeplayer-splash-44100-16bit-stereo-signed.wav @@ -124,7 +124,7 @@ Output: resumed paused resumed - + playing with pause/resume: jeplayer-splash-44100-16bit-stereo-signed.wav paused resumed @@ -198,7 +198,7 @@ Output: resumed paused resumed - + playing with pause/resume: jeplayer-splash-8000-16bit-mono-signed.wav paused resumed @@ -270,7 +270,7 @@ Output: resumed paused resumed - + playing with pause/resume: jeplayer-splash-8000-16bit-stereo-signed.wav paused resumed @@ -342,7 +342,7 @@ Output: resumed paused resumed - + playing with pause/resume: jeplayer-splash-8000-8bit-mono-unsigned.wav paused resumed @@ -414,7 +414,7 @@ Output: resumed paused resumed - + done [PASS] pause/resume header for jeplayer-splash-44100-16bit-mono-signed.wav [PASS] pause/resume header for jeplayer-splash-44100-16bit-stereo-signed.wav @@ -433,13 +433,13 @@ Output: ============================================================ Output: unsigned 8 bit - + signed 8 bit - + unsigned 16 bit - + signed 16 bit - + done [PASS] 'unsigned 8 bit' label printed [PASS] 'signed 8 bit' label printed @@ -461,17 +461,17 @@ Output: ============================================================ Output: channel test: left only - + channel test: right only - + channel test: both channels - + pan sweep: left to right - + playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav - + playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav - + done [PASS] Left-only channel tone played [PASS] Right-only channel tone played diff --git a/tests/circuitpython-manual/audioio/run_serial_tests.py b/tests/circuitpython-manual/audioio/run_serial_tests.py index f6ec48cb847..9fbbe555592 100644 --- a/tests/circuitpython-manual/audioio/run_serial_tests.py +++ b/tests/circuitpython-manual/audioio/run_serial_tests.py @@ -66,6 +66,7 @@ # mpremote helpers # --------------------------------------------------------------------------- + def _mpremote(args: list, timeout: float = 30.0): """Run an mpremote command, return (stdout, stderr). Raises on timeout.""" try: @@ -214,7 +215,12 @@ def find_port() -> str: # Fall back to any USB serial port that isn't Bluetooth/wlan for line in stdout.splitlines(): parts = line.split() - if parts and parts[0].startswith("/dev/") and "Bluetooth" not in line and "wlan" not in line: + if ( + parts + and parts[0].startswith("/dev/") + and "Bluetooth" not in line + and "wlan" not in line + ): return parts[0] raise RuntimeError( "No board detected. Connect the board and/or pass --port.\n" @@ -225,16 +231,19 @@ def find_port() -> str: def find_circuitpy() -> str | None: """Return the path to the mounted CIRCUITPY volume, or None if not found.""" import platform + system = platform.system() if system == "Darwin": # Glob so a second CIRCUITPY volume (mounted as "CIRCUITPY 1") is found. import glob + candidates = sorted(glob.glob("/Volumes/CIRCUITPY*")) elif system == "Windows": # Scan all drive letters for a CIRCUITPY volume label. import string import ctypes + candidates = [] kernel32 = ctypes.windll.kernel32 # type: ignore[attr-defined] buf = ctypes.create_unicode_buffer(256) @@ -248,6 +257,7 @@ def find_circuitpy() -> str | None: candidates = ["/media/CIRCUITPY", "/run/media/CIRCUITPY"] try: import pwd + user = pwd.getpwuid(os.getuid()).pw_name candidates.insert(0, f"/run/media/{user}/CIRCUITPY") candidates.insert(0, f"/media/{user}/CIRCUITPY") @@ -267,10 +277,9 @@ def copy_files(port: str, circuitpy: str | None = None): print(f"Copying files to board via {mount} ...") else: print("Copying files to board via mpremote ...") - files = ( - [(os.path.join(AUDIOCORE_DIR, w), w) for w in WAV_FILES] - + [(os.path.join(SCRIPT_DIR, s), s) for s in TEST_SCRIPTS] - ) + files = [(os.path.join(AUDIOCORE_DIR, w), w) for w in WAV_FILES] + [ + (os.path.join(SCRIPT_DIR, s), s) for s in TEST_SCRIPTS + ] # Check if device has enough space for test files if mount: needed = 0 @@ -285,11 +294,10 @@ def copy_files(port: str, circuitpy: str | None = None): if needed > free: short = needed - free print(f"ERROR: not enough space on {mount}.") - print(f" need: {needed/1024:.1f} KiB") - print(f" free: {free/1024:.1f} KiB") - print(f" short: {short/1024:.1f} KiB") - print(f" Delete unrelated files (e.g. an old code.py or " - f"stale WAVs) and re-run.") + print(f" need: {needed / 1024:.1f} KiB") + print(f" free: {free / 1024:.1f} KiB") + print(f" short: {short / 1024:.1f} KiB") + print(f" Delete unrelated files (e.g. an old code.py or stale WAVs) and re-run.") sys.exit(1) missing = [] for src, dst in files: @@ -301,9 +309,7 @@ def copy_files(port: str, circuitpy: str | None = None): shutil.copy2(src, dest_path) print(f" {dst} (copied)") else: - stdout, stderr = _mpremote( - ["connect", port, "fs", "cp", src, f":/{dst}"], timeout=30 - ) + stdout, stderr = _mpremote(["connect", port, "fs", "cp", src, f":/{dst}"], timeout=30) if stderr and "Error" in stderr: print(f" {dst} (FAILED: {stderr.strip()})") else: @@ -349,9 +355,7 @@ def _run_exec(port: str, code: str, label: str, timeout: float, retries: int = 3 print(f" [retry {attempt}/{retries}] port {port} not present — waited 10s") continue try: - stdout, stderr = _mpremote( - ["connect", port, "exec", code], timeout=timeout - ) + stdout, stderr = _mpremote(["connect", port, "exec", code], timeout=timeout) except TimeoutError as exc: print(f" [FAIL] {exc}") return False, "", "" @@ -397,6 +401,7 @@ def _settle_between_tests(port: str) -> None: # Individual tests # --------------------------------------------------------------------------- + def test1_wavefile_playback(port: str) -> bool: code = 'exec(open("/wavefile_playback.py").read())' ok, stdout, stderr = _run_exec( @@ -422,7 +427,9 @@ def test2_pause_resume(port: str) -> bool: return False passed = True for wav in sorted(WAV_FILES): - passed &= _check(f"playing with pause/resume: {wav}" in stdout, f"pause/resume header for {wav}") + passed &= _check( + f"playing with pause/resume: {wav}" in stdout, f"pause/resume header for {wav}" + ) passed &= _check("paused" in stdout, "At least one 'paused' line printed") passed &= _check("resumed" in stdout, "At least one 'resumed' line printed") passed &= _check("TIMEOUT" not in stdout, "No pause/resume hang timeout") @@ -459,8 +466,14 @@ def test5_stereo_playback(port: str) -> bool: passed &= _check("channel test: right only" in stdout, "Right-only channel tone played") passed &= _check("channel test: both channels" in stdout, "Both-channel tone played") passed &= _check("pan sweep: left to right" in stdout, "Pan sweep played") - passed &= _check("playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav" in stdout, "44100 Hz 16-bit stereo WAV played") - passed &= _check("playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav" in stdout, "8000 Hz 16-bit stereo WAV played") + passed &= _check( + "playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav" in stdout, + "44100 Hz 16-bit stereo WAV played", + ) + passed &= _check( + "playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav" in stdout, + "8000 Hz 16-bit stereo WAV played", + ) passed &= _check("done" in stdout, "Script completed with 'done'") passed &= _check(not stderr, f"No exceptions (stderr={stderr!r})") return passed @@ -482,6 +495,7 @@ def test4_deinit(port: str) -> bool: # Main # --------------------------------------------------------------------------- + def main(): parser = argparse.ArgumentParser( description=__doc__, diff --git a/tests/circuitpython-manual/audioio/single_buffer_loop.py b/tests/circuitpython-manual/audioio/single_buffer_loop.py index 929e03e6d10..4a4c4304275 100644 --- a/tests/circuitpython-manual/audioio/single_buffer_loop.py +++ b/tests/circuitpython-manual/audioio/single_buffer_loop.py @@ -48,12 +48,14 @@ dac = audioio.AudioOut(board.A0) for sample, name in zip(samples, sample_names): print(name) - if trigger: trigger.value = False + if trigger: + trigger.value = False dac.play(sample, loop=True) time.sleep(1) dac.stop() time.sleep(0.1) - if trigger: trigger.value = True + if trigger: + trigger.value = True print() dac.deinit() diff --git a/tests/circuitpython-manual/audioio/wavefile_pause_resume.py b/tests/circuitpython-manual/audioio/wavefile_pause_resume.py index c3002c6b5d1..7661a828b26 100644 --- a/tests/circuitpython-manual/audioio/wavefile_pause_resume.py +++ b/tests/circuitpython-manual/audioio/wavefile_pause_resume.py @@ -20,7 +20,9 @@ samples.append(fn) if not samples: - print("No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board.") + print( + "No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board." + ) dac = audioio.AudioOut(board.A0) for filename in sorted(samples): @@ -31,7 +33,8 @@ except OSError as e: print(e) continue - if trigger: trigger.value = False + if trigger: + trigger.value = False dac.play(sample) # Deliberately toggle pause/resume every 100 ms to stress-test the # pause/resume cycle. Audio will sound choppy — that is expected. @@ -54,7 +57,8 @@ else: dac.resume() print(" resumed") - if trigger: trigger.value = True + if trigger: + trigger.value = True time.sleep(0.1) print() diff --git a/tests/circuitpython-manual/audioio/wavefile_playback.py b/tests/circuitpython-manual/audioio/wavefile_playback.py index fa1fa971309..a7800c54ddc 100644 --- a/tests/circuitpython-manual/audioio/wavefile_playback.py +++ b/tests/circuitpython-manual/audioio/wavefile_playback.py @@ -22,7 +22,9 @@ samples.append(fn) if not samples: - print("No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board.") + print( + "No sample files found. Copy *.wav files from tests/circuitpython-manual/audiocore/ to the board." + ) dac = audioio.AudioOut(board.A0) for filename in sorted(samples): @@ -33,11 +35,13 @@ except OSError as e: print(e) continue - if trigger: trigger.value = False + if trigger: + trigger.value = False dac.play(sample) while dac.playing: time.sleep(0.1) - if trigger: trigger.value = True + if trigger: + trigger.value = True time.sleep(0.1) print() From 2a382217386bb53948b941810b0575526464dd3d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 4 May 2026 10:53:46 -0700 Subject: [PATCH 456/876] Update to v6.0.1 --- ports/espressif/esp-idf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/esp-idf b/ports/espressif/esp-idf index e6c85f28eb0..2b900d1222c 160000 --- a/ports/espressif/esp-idf +++ b/ports/espressif/esp-idf @@ -1 +1 @@ -Subproject commit e6c85f28eb03b78ba914cb05d072a4a506e6d4fd +Subproject commit 2b900d1222cfce5dfa340ed99375af69ec1ee192 From b434eb55bb71ee48d4dc21dc1d9a038dead9dd74 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 4 May 2026 11:10:38 -0700 Subject: [PATCH 457/876] Fix the update to v6.0.1 --- ports/espressif/Makefile | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index c1c2033dd67..4c40e71d310 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -47,6 +47,9 @@ INC += \ -isystem esp-idf/components/bt/host/nimble/nimble/porting/nimble/include \ -isystem esp-idf/components/bt/host/nimble/nimble/porting/npl/freertos/include \ -isystem esp-idf/components/bt/host/nimble/port/include \ + -isystem esp-idf/components/bt/porting/include \ + -isystem esp-idf/components/bt/porting/npl/freertos/include \ + -isystem esp-idf/components/bt/porting/transport/include \ -isystem esp-idf/components/esp_driver_touch_sens/include \ -isystem esp-idf/components/driver/twai/include \ -isystem esp-idf/components/driver/i2c/include \ @@ -127,6 +130,8 @@ INC += \ -isystem esp-idf/components/esp_hal_dma/$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_hal_lcd/include \ -isystem esp-idf/components/esp_hal_lcd/$(IDF_TARGET)/include \ + -isystem esp-idf/components/esp_hal_sd/include \ + -isystem esp-idf/components/esp_hal_sd/$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_hal_usb/include \ -isystem esp-idf/components/esp_hal_usb/$(IDF_TARGET)/include \ -isystem esp-idf/components/esp_hal_parlio/include \ @@ -309,6 +314,7 @@ CHIP_COMPONENTS = \ esp_hal_i2s \ esp_hal_lcd \ esp_hal_pcnt \ + esp_hal_pmu \ esp_hal_rmt \ esp_hal_touch_sens \ esp_hal_twai @@ -456,6 +462,7 @@ CHIP_COMPONENTS = \ esp_hal_i2s \ esp_hal_lcd \ esp_hal_pcnt \ + esp_hal_pmu \ esp_hal_rmt \ esp_hal_touch_sens \ esp_hal_twai \ @@ -892,7 +899,7 @@ ifneq ($(CIRCUITPY_QSPIBUS),0) ESP_IDF_COMPONENTS_LINK += esp_lcd endif ifneq ($(CIRCUITPY_SDIOIO),0) - ESP_IDF_COMPONENTS_LINK += sdmmc esp_driver_sdmmc esp_driver_sd_intf + ESP_IDF_COMPONENTS_LINK += sdmmc esp_driver_sdmmc esp_driver_sd_intf esp_hal_sd endif ESP_IDF_COMPONENTS_EXPANDED = $(foreach component, $(ESP_IDF_COMPONENTS_LINK), $(BUILD)/esp-idf/esp-idf/$(component)/lib$(component).a) From cd142d5ae7836baf9a6848d2709914f373895765 Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Mon, 4 May 2026 11:26:39 -0700 Subject: [PATCH 458/876] ports/stm: reuse existing translations and shared deinit guard in audioio Address review feedback on PR #10976: - Replace 11 audioio-specific MP_ERROR_TEXT strings with existing pot entries via %q substitution (Invalid %q pin, %q init failed) or by reusing analogio/AnalogOut's "DAC Device/Channel Init Error". - Drop the redundant in-driver deinit check in common_hal_audioio_audioout_play(); the shared-bindings layer already guards every entry point with check_for_deinit -> raise_deinited_error. - Net result: zero new entries in locale/circuitpython.pot. - Also remove tests/circuitpython-manual/audioio/results.md (committed in a prior commit; the test scripts stay, the captured run output shouldn't live in the repo). Co-Authored-By: Claude Opus 4.7 --- locale/circuitpython.pot | 47 +- ports/stm/common-hal/audioio/AudioOut.c | 25 +- tests/circuitpython-manual/audioio/results.md | 496 ------------------ 3 files changed, 15 insertions(+), 553 deletions(-) delete mode 100644 tests/circuitpython-manual/audioio/results.md diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index d973a62cb5c..db36f74b45f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -140,6 +140,7 @@ msgid "%q indices must be integers, not %s" msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c #: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" @@ -630,18 +631,6 @@ msgstr "" msgid "Audio source error" msgstr "" -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "AudioOut is deinited" -msgstr "" - -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "AudioOut requires pin A0 (PA04)" -msgstr "" - -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "AudioOut right channel requires pin A1 (PA05)" -msgstr "" - #: shared-bindings/wifi/Radio.c msgid "AuthMode.OPEN is not used with password" msgstr "" @@ -901,18 +890,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c -msgid "DAC Channel Init Error" -msgstr "" - #: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC DMA start failed" -msgstr "" - -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC DMA start failed (right channel)" +msgid "DAC Channel Init Error" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "" @@ -920,22 +903,6 @@ msgstr "" msgid "DAC already in use" msgstr "" -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC channel config error" -msgstr "" - -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC init error" -msgstr "" - -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DMA init failed" -msgstr "" - -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DMA init failed (right)" -msgstr "" - #: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c #: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c msgid "Data 0 pin must be byte aligned" @@ -2146,14 +2113,6 @@ msgstr "" msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "TIM6 init failed" -msgstr "" - -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "TIM6 master cfg failed" -msgstr "" - #: ports/stm/common-hal/microcontroller/Processor.c msgid "Temperature read timed out" msgstr "" diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index b375da758fc..44f8b8e8d51 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -339,12 +339,12 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, // Only PA04 (DAC_CH1) is supported as left channel. if (left_channel != &pin_PA04) { - mp_raise_ValueError(MP_ERROR_TEXT("AudioOut requires pin A0 (PA04)")); + raise_ValueError_invalid_pin_name(MP_QSTR_left_channel); } // Right channel must be PA05 (DAC_CH2 / A1) if provided. if (right_channel != NULL && right_channel != &pin_PA05) { - mp_raise_ValueError(MP_ERROR_TEXT("AudioOut right channel requires pin A1 (PA05)")); + raise_ValueError_invalid_pin_name(MP_QSTR_right_channel); } // Claim pins first. The pin-claim system is what serialises this driver @@ -393,7 +393,7 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, __HAL_RCC_DAC_CLK_ENABLE(); handle.Instance = DAC; if (HAL_DAC_Init(&handle) != HAL_OK) { - mp_raise_ValueError(MP_ERROR_TEXT("DAC init error")); + mp_raise_ValueError(MP_ERROR_TEXT("DAC Device Init Error")); } } @@ -403,7 +403,7 @@ void common_hal_audioio_audioout_construct(audioio_audioout_obj_t *self, ch_cfg.DAC_Trigger = DAC_TRIGGER_NONE; ch_cfg.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE; if (HAL_DAC_ConfigChannel(&handle, &ch_cfg, DAC_CHANNEL_1) != HAL_OK) { - mp_raise_ValueError(MP_ERROR_TEXT("DAC channel config error")); + mp_raise_ValueError(MP_ERROR_TEXT("DAC Channel Init Error")); } // Ramp DAC output up to quiescent value to prevent an audible pop. @@ -447,9 +447,8 @@ void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t *self) { void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, mp_obj_t sample, bool loop) { - if (common_hal_audioio_audioout_deinited(self)) { - mp_raise_ValueError(MP_ERROR_TEXT("AudioOut is deinited")); - } + // The shared-bindings layer guards every entry point with + // check_for_deinit, so a deinited self can't reach this function. common_hal_audioio_audioout_stop(self); // Extract sample format metadata via the canonical accessors so the @@ -536,7 +535,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, tim6_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; tim6_handle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&tim6_handle) != HAL_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("TIM6 init failed")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_TIM6); } // TRGO = Update event → triggers DAC conversion each period. @@ -544,7 +543,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, master_cfg.MasterOutputTrigger = TIM_TRGO_UPDATE; master_cfg.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&tim6_handle, &master_cfg) != HAL_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("TIM6 master cfg failed")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_TIM6); } // NOTE: ports/atmel-samd's audio_dma_setup_playback handles AUDIO_DMA_OK // and two specific error codes but lets any other non-OK return fall @@ -582,7 +581,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, hdma->Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma->Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(hdma) != HAL_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("DMA init failed")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_DMA); } __HAL_LINKDMA(&handle, DMA_Handle1, *hdma); @@ -605,7 +604,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, hdma_r->Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma_r->Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(hdma_r) != HAL_OK) { - mp_raise_RuntimeError(MP_ERROR_TEXT("DMA init failed (right)")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_DMA); } __HAL_LINKDMA(&handle, DMA_Handle2, *hdma_r); @@ -630,7 +629,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, } m_free(self->dma_buffer); self->dma_buffer = NULL; - mp_raise_RuntimeError(MP_ERROR_TEXT("DAC DMA start failed")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_DAC); } if (self->right_channel != NULL) { @@ -646,7 +645,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, self->dma_buffer = NULL; m_free(self->dma_buffer_r); self->dma_buffer_r = NULL; - mp_raise_RuntimeError(MP_ERROR_TEXT("DAC DMA start failed (right channel)")); + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_DAC); } } diff --git a/tests/circuitpython-manual/audioio/results.md b/tests/circuitpython-manual/audioio/results.md deleted file mode 100644 index 4e3459e6f80..00000000000 --- a/tests/circuitpython-manual/audioio/results.md +++ /dev/null @@ -1,496 +0,0 @@ -# audioio — `run_serial_tests.py` results - -- **Board:** Adafruit Feather STM32F405 Express -- **Suite:** Tests 1–5 automated -- **Result:** all PASS - -``` -Using port: /dev/cu.usbmodem101 - -Copying files to board via /Volumes/CIRCUITPY ... - jeplayer-splash-8000-8bit-mono-unsigned.wav (copied) - jeplayer-splash-8000-16bit-mono-signed.wav (copied) - jeplayer-splash-44100-16bit-mono-signed.wav (copied) - jeplayer-splash-8000-16bit-stereo-signed.wav (copied) - jeplayer-splash-44100-16bit-stereo-signed.wav (copied) - wavefile_playback.py (copied) - wavefile_pause_resume.py (copied) - single_buffer_loop.py (copied) - stereo_playback.py (copied) - - -============================================================ - Test 1 — WAV File Playback (wavefile_playback.py) -============================================================ -Output: - playing jeplayer-splash-44100-16bit-mono-signed.wav - - playing jeplayer-splash-44100-16bit-stereo-signed.wav - - playing jeplayer-splash-8000-16bit-mono-signed.wav - - playing jeplayer-splash-8000-16bit-stereo-signed.wav - - playing jeplayer-splash-8000-8bit-mono-unsigned.wav - - done - [PASS] played jeplayer-splash-44100-16bit-mono-signed.wav - [PASS] played jeplayer-splash-44100-16bit-stereo-signed.wav - [PASS] played jeplayer-splash-8000-16bit-mono-signed.wav - [PASS] played jeplayer-splash-8000-16bit-stereo-signed.wav - [PASS] played jeplayer-splash-8000-8bit-mono-unsigned.wav - [PASS] No OSError reported during playback - [PASS] Script completed with 'done' - [PASS] No exceptions (stderr='') - -============================================================ - Test 2 — Pause / Resume (wavefile_pause_resume.py) -============================================================ -Output: - playing with pause/resume: jeplayer-splash-44100-16bit-mono-signed.wav - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - - playing with pause/resume: jeplayer-splash-44100-16bit-stereo-signed.wav - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - - playing with pause/resume: jeplayer-splash-8000-16bit-mono-signed.wav - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - - playing with pause/resume: jeplayer-splash-8000-16bit-stereo-signed.wav - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - - playing with pause/resume: jeplayer-splash-8000-8bit-mono-unsigned.wav - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - paused - resumed - - done - [PASS] pause/resume header for jeplayer-splash-44100-16bit-mono-signed.wav - [PASS] pause/resume header for jeplayer-splash-44100-16bit-stereo-signed.wav - [PASS] pause/resume header for jeplayer-splash-8000-16bit-mono-signed.wav - [PASS] pause/resume header for jeplayer-splash-8000-16bit-stereo-signed.wav - [PASS] pause/resume header for jeplayer-splash-8000-8bit-mono-unsigned.wav - [PASS] At least one 'paused' line printed - [PASS] At least one 'resumed' line printed - [PASS] No pause/resume hang timeout - [PASS] No OSError reported during playback - [PASS] Script completed with 'done' - [PASS] No exceptions (stderr='') - -============================================================ - Test 3 — Looping Sine Wave (single_buffer_loop.py) -============================================================ -Output: - unsigned 8 bit - - signed 8 bit - - unsigned 16 bit - - signed 16 bit - - done - [PASS] 'unsigned 8 bit' label printed - [PASS] 'signed 8 bit' label printed - [PASS] 'unsigned 16 bit' label printed - [PASS] 'signed 16 bit' label printed - [PASS] Script completed with 'done' - [PASS] No exceptions (stderr='') - -============================================================ - Test 4 — deinit and Re-init (inline) -============================================================ -Output: - pass - [PASS] Script printed 'pass' - [PASS] No exceptions (stderr='') - -============================================================ - Test 5 — Stereo Playback (stereo_playback.py) -============================================================ -Output: - channel test: left only - - channel test: right only - - channel test: both channels - - pan sweep: left to right - - playing stereo: jeplayer-splash-44100-16bit-stereo-signed.wav - - playing stereo: jeplayer-splash-8000-16bit-stereo-signed.wav - - done - [PASS] Left-only channel tone played - [PASS] Right-only channel tone played - [PASS] Both-channel tone played - [PASS] Pan sweep played - [PASS] 44100 Hz 16-bit stereo WAV played - [PASS] 8000 Hz 16-bit stereo WAV played - [PASS] Script completed with 'done' - [PASS] No exceptions (stderr='') - -============================================================ -SUMMARY -============================================================ - [PASS] Test 1 — WAV Playback - [PASS] Test 2 — Pause/Resume - [PASS] Test 3 — Looping Sine - [PASS] Test 4 — deinit/Re-init - [PASS] Test 5 — Stereo Playback - -All automated tests passed. -Remaining manual step: audio/oscilloscope verification. -``` From d75e83a86472d01fedad8fc8d01e0c68271cd9f1 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 5 May 2026 09:49:10 -0700 Subject: [PATCH 459/876] Fix qualia --- ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults b/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults index ae5a415ed12..d582a77798c 100644 --- a/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig-flash-120m.defaults @@ -1,4 +1,4 @@ CONFIG_ESPTOOLPY_FLASHFREQ_120M=y CONFIG_SPI_FLASH_UNDER_HIGH_FREQ=y CONFIG_SPI_FLASH_HPM_ENA=y -CONFIG_SPI_FLASH_HPM_DC_DISABLE=y +CONFIG_BOOTLOADER_FLASH_DC_AWARE=y From d42941d1a38111b01a1862089c87ec832085ee3c Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Tue, 5 May 2026 10:35:24 -0700 Subject: [PATCH 460/876] ports/stm: use mp_arg_validate_int_min for audioio sample_rate floor Replace the custom "sample_rate must be > 0" raise with the standard mp_arg_validate_int_min helper, matching the existing _int_max call on the next line. Co-Authored-By: Claude Opus 4.7 --- ports/stm/common-hal/audioio/AudioOut.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ports/stm/common-hal/audioio/AudioOut.c b/ports/stm/common-hal/audioio/AudioOut.c index 44f8b8e8d51..e5dd620521c 100644 --- a/ports/stm/common-hal/audioio/AudioOut.c +++ b/ports/stm/common-hal/audioio/AudioOut.c @@ -458,9 +458,7 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, self->samples_signed = base->samples_signed; self->channel_count = audiosample_get_channel_count(base); uint32_t sample_rate = audiosample_get_sample_rate(base); - if (sample_rate == 0) { - mp_raise_ValueError(MP_ERROR_TEXT("sample_rate must be > 0")); - } + mp_arg_validate_int_min(sample_rate, 1, MP_QSTR_sample_rate); mp_arg_validate_int_max(sample_rate, AUDIOOUT_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); self->sample = sample; From 217effc92a3089b325c95bee6a660241095356f1 Mon Sep 17 00:00:00 2001 From: Jaimy Juliano Date: Tue, 5 May 2026 12:47:39 -0500 Subject: [PATCH 461/876] Add board support for JL401-S3 datalogger --- .../board.c | 26 ++++++ .../mpconfigboard.h | 36 ++++++++ .../mpconfigboard.mk | 14 +++ .../nhbsystems_jl401_4mbflash_2mbpsram/pins.c | 89 +++++++++++++++++++ .../sdkconfig | 14 +++ 5 files changed, 179 insertions(+) create mode 100755 ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/board.c create mode 100755 ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.h create mode 100755 ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.mk create mode 100644 ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/pins.c create mode 100755 ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/sdkconfig diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/board.c b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/board.c new file mode 100755 index 00000000000..e2517f8640a --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/board.c @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "driver/gpio.h" + +void board_init(void) { + reset_board(); +} + +void reset_board(void) { + // Turn on I2C power by default. + gpio_set_direction(14, GPIO_MODE_DEF_OUTPUT); + gpio_set_level(14, true); + + // Turn on SD power by default + gpio_set_direction(3, GPIO_MODE_DEF_OUTPUT); + gpio_set_level(3, true); +} + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.h b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.h new file mode 100755 index 00000000000..c3181ea9431 --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.h @@ -0,0 +1,36 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "NHB Systems JL401-S3 4MB Flash 2MB PSRAM" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO1) +#define CIRCUITPY_STATUS_LED_POWER (&pin_GPIO2) + +// #define MICROPY_HW_LED_STATUS (&pin_GPIO13) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO48) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO47) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO12) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO11) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO13) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO18) +#define DEFAULT_UART_BUS_TX (&pin_GPIO17) + +#define DOUBLE_TAP_PIN (&pin_GPIO38) + +#define DEFAULT_SD_SCK (&pin_GPIO12) +#define DEFAULT_SD_MOSI (&pin_GPIO11) +#define DEFAULT_SD_MISO (&pin_GPIO13) +#define DEFAULT_SD_CS (&pin_GPIO10) +#define DEFAULT_SD_CARD_DETECT (&pin_GPIO9) +#define DEFAULT_SD_CARD_INSERTED true diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.mk b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.mk new file mode 100755 index 00000000000..fdc981fdccc --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x834A +USB_PRODUCT = "NHB Systems JL401-S3 4MB Flash 2MB PSRAM" +USB_MANUFACTURER = "NHB Systems" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_SIZE = 4MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 2MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/pins.c b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/pins.c new file mode 100644 index 00000000000..111659bee61 --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/pins.c @@ -0,0 +1,89 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL_POWER), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_SD_PWR), MP_ROM_PTR(&pin_GPIO3)}, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_A5), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + + + // { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO13) }, + // { MP_ROM_QSTR(MP_QSTR_L), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_I2C_POWER), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_A4), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_D21), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_D11), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + + // D33 to D36 used for AD7124 SPI + { MP_ROM_QSTR(MP_QSTR_D33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_D34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_D35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_D36), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_D37), MP_ROM_PTR(&pin_GPIO37) }, + // { MP_ROM_QSTR(MP_QSTR_D38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_D39), MP_ROM_PTR(&pin_GPIO39) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_D43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO48) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) } +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/sdkconfig b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/sdkconfig new file mode 100755 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/nhbsystems_jl401_4mbflash_2mbpsram/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From 9e2d48a5050007f38bbec1f856b6fd8f0295632f Mon Sep 17 00:00:00 2001 From: Chris Nourse Date: Wed, 6 May 2026 10:28:49 -0700 Subject: [PATCH 462/876] ports/stm: drop stale audioio sample_rate pot entry Removed leftover msgid "sample_rate must be > 0" from locale/circuitpython.pot. The raise was replaced with mp_arg_validate_int_min in d42941d1a3 but the pot entry was not regenerated. Co-Authored-By: Claude Opus 4.7 --- locale/circuitpython.pot | 4 ---- 1 file changed, 4 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index db36f74b45f..e09df9d1781 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -4166,10 +4166,6 @@ msgstr "" msgid "rsplit(None,n)" msgstr "" -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "sample_rate must be > 0" -msgstr "" - #: shared-bindings/audiofreeverb/Freeverb.c msgid "samples_signed must be true" msgstr "" From f85766b6070d6cb1c7a59d17697301d5382e679e Mon Sep 17 00:00:00 2001 From: Francisco Serrador Date: Tue, 5 May 2026 20:04:30 +0200 Subject: [PATCH 463/876] Translated using Weblate (Spanish) Currently translated at 100.0% (998 of 998 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/es/ --- locale/es.po | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/locale/es.po b/locale/es.po index 85a03408b75..87589c2c28b 100644 --- a/locale/es.po +++ b/locale/es.po @@ -8,15 +8,15 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-01-04 12:55-0600\n" -"PO-Revision-Date: 2025-08-03 08:01+0000\n" -"Last-Translator: MAE \n" +"PO-Revision-Date: 2026-05-06 18:11+0000\n" +"Last-Translator: Francisco Serrador \n" "Language-Team: \n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.13-dev\n" +"X-Generator: Weblate 5.17.1\n" #: main.c msgid "" @@ -614,7 +614,6 @@ msgid "Array values should be single bytes." msgstr "Valores del array deben ser bytes individuales." #: ports/atmel-samd/common-hal/spitarget/SPITarget.c -#, fuzzy msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" "Transferencia SPI asíncrona en curso en este canal, manténgase esperando." @@ -1064,9 +1063,8 @@ msgid "Failed to create continuous channels: not found" msgstr "Error al crear canales continuos: no encontrado" #: ports/espressif/common-hal/audioio/AudioOut.c -#, fuzzy msgid "Failed to enable continuous" -msgstr "Fallo habilitando continous" +msgstr "Ha fallado al habilitar continuo" #: shared-module/audiomp3/MP3Decoder.c msgid "Failed to parse MP3 file" @@ -1912,9 +1910,8 @@ msgid "Program too long" msgstr "El programa es demasiado grande" #: shared-bindings/rclcpy/Publisher.c -#, fuzzy msgid "Publishers can only be created from a parent node" -msgstr "Publicadores solo pueden ser creados desde un nodo padre" +msgstr "Las publicadores solo pueden ser creadas desde un nodo antecesor" #: shared-bindings/digitalio/DigitalInOut.c msgid "Pull not used when direction is output." @@ -2170,9 +2167,8 @@ msgid "Tile width must exactly divide bitmap width" msgstr "Ancho del Tile debe dividir exactamente el ancho de mapa de bits" #: shared-module/tilepalettemapper/TilePaletteMapper.c -#, fuzzy msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "Tilepalettemapper sólo puede vincularse una vez a un TileGrid" +msgstr "TilePaletteMapper solo puede vincularse una vez a un TileGrid" #: shared-bindings/alarm/time/TimeAlarm.c msgid "Time is in the past." From 0a31153ff07fc1b9c4f76a5c3e4434ce1a02f6b8 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 6 May 2026 17:49:08 -0500 Subject: [PATCH 464/876] Fix unintentional pass by reference --- shared-module/audiomixer/Mixer.c | 55 ++++++++++++++++---------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 64488cc4297..fb4f76c3338 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -92,15 +92,15 @@ static inline uint32_t add16signed(uint32_t a, uint32_t b) { } __attribute__((always_inline)) -static inline uint32_t mult16signed(uint32_t val, int32_t mul[2]) { +static inline uint32_t mult16signed(uint32_t val, int32_t lomul, int32_t himul) { #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) - mul[0] <<= 16; - mul[1] <<= 16; + lomul <<= 16; + himul <<= 16; int32_t hi, lo; enum { bits = 16 }; // saturate to 16 bits enum { shift = 15 }; // shift is done automatically - asm volatile ("smulwb %0, %1, %2" : "=r" (lo) : "r" (mul[0]), "r" (val)); - asm volatile ("smulwt %0, %1, %2" : "=r" (hi) : "r" (mul[1]), "r" (val)); + asm volatile ("smulwb %0, %1, %2" : "=r" (lo) : "r" (lomul), "r" (val)); + asm volatile ("smulwt %0, %1, %2" : "=r" (hi) : "r" (himul), "r" (val)); asm volatile ("ssat %0, %1, %2, asr %3" : "=r" (lo) : "I" (bits), "r" (lo), "I" (shift)); asm volatile ("ssat %0, %1, %2, asr %3" : "=r" (hi) : "I" (bits), "r" (hi), "I" (shift)); asm volatile ("pkhbt %0, %1, %2, lsl #16" : "=r" (val) : "r" (lo), "r" (hi)); // pack @@ -108,7 +108,7 @@ static inline uint32_t mult16signed(uint32_t val, int32_t mul[2]) { #else uint32_t result = 0; for (int8_t i = 0; i < 2; i++) { - float mod_mul = (float)mul[i] / (float)((1 << 15) - 1); + float mod_mul = (float)(i ? himul : lomul) / (float)((1 << 15) - 1); int16_t ai = (val >> (sizeof(uint16_t) * 8 * i)); int32_t intermediate = (int32_t)(ai * mod_mul); if (intermediate > SHRT_MAX) { @@ -232,10 +232,11 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, } } - int32_t loudness[2] = { level, level }; + int32_t lo_level = level; + int32_t hi_level = level; if (MP_LIKELY(self->base.channel_count == 2)) { - loudness[0] = (left_panning_scaled * loudness[0]) >> 15; - loudness[1] = (right_panning_scaled * loudness[1]) >> 15; + lo_level = (left_panning_scaled * lo_level) >> 15; + hi_level = (right_panning_scaled * hi_level) >> 15; } // First active voice gets copied over verbatim. @@ -245,13 +246,13 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { uint32_t v = src[i]; - word_buffer[i] = mult16signed(v, loudness); + word_buffer[i] = mult16signed(v, lo_level, hi_level); } } else { for (uint32_t i = 0; i < n; i += 2) { uint32_t v = src[i >> 1]; - word_buffer[i] = mult16signed(copy16lsb(v), loudness); - word_buffer[i + 1] = mult16signed(copy16msb(v), loudness); + word_buffer[i] = mult16signed(copy16lsb(v), lo_level, hi_level); + word_buffer[i + 1] = mult16signed(copy16msb(v), lo_level, hi_level); } } } else { @@ -259,14 +260,14 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, for (uint32_t i = 0; i < n; i++) { uint32_t v = src[i]; v = tosigned16(v); - word_buffer[i] = mult16signed(v, loudness); + word_buffer[i] = mult16signed(v, lo_level, hi_level); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t v = src[i >> 1]; v = tosigned16(v); - word_buffer[i] = mult16signed(copy16lsb(v), loudness); - word_buffer[i + 1] = mult16signed(copy16msb(v), loudness); + word_buffer[i] = mult16signed(copy16lsb(v), lo_level, hi_level); + word_buffer[i + 1] = mult16signed(copy16msb(v), lo_level, hi_level); } } } @@ -279,7 +280,7 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - word = mult16signed(word, loudness); + word = mult16signed(word, lo_level, hi_level); hword_buffer[i] = pack8(word); } } else { @@ -288,8 +289,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - hword_buffer[i] = pack8(mult16signed(copy16lsb(word), loudness)); - hword_buffer[i + 1] = pack8(mult16signed(copy16msb(word), loudness)); + hword_buffer[i] = pack8(mult16signed(copy16lsb(word), lo_level, hi_level)); + hword_buffer[i + 1] = pack8(mult16signed(copy16msb(word), lo_level, hi_level)); } } } @@ -299,13 +300,13 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; - word_buffer[i] = add16signed(mult16signed(word, loudness), word_buffer[i]); + word_buffer[i] = add16signed(mult16signed(word, lo_level, hi_level), word_buffer[i]); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; - word_buffer[i] = add16signed(mult16signed(copy16lsb(word), loudness), word_buffer[i]); - word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), loudness), word_buffer[i + 1]); + word_buffer[i] = add16signed(mult16signed(copy16lsb(word), lo_level, hi_level), word_buffer[i]); + word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), lo_level, hi_level), word_buffer[i + 1]); } } } else { @@ -313,14 +314,14 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; word = tosigned16(word); - word_buffer[i] = add16signed(mult16signed(word, loudness), word_buffer[i]); + word_buffer[i] = add16signed(mult16signed(word, lo_level, hi_level), word_buffer[i]); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; word = tosigned16(word); - word_buffer[i] = add16signed(mult16signed(copy16lsb(word), loudness), word_buffer[i]); - word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), loudness), word_buffer[i + 1]); + word_buffer[i] = add16signed(mult16signed(copy16lsb(word), lo_level, hi_level), word_buffer[i]); + word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), lo_level, hi_level), word_buffer[i + 1]); } } } @@ -333,7 +334,7 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - word = mult16signed(word, loudness); + word = mult16signed(word, lo_level, hi_level); word = add16signed(word, unpack8(hword_buffer[i])); hword_buffer[i] = pack8(word); } @@ -343,8 +344,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - hword_buffer[i] = pack8(add16signed(mult16signed(copy16lsb(word), loudness), unpack8(hword_buffer[i]))); - hword_buffer[i + 1] = pack8(add16signed(mult16signed(copy16msb(word), loudness), unpack8(hword_buffer[i + 1]))); + hword_buffer[i] = pack8(add16signed(mult16signed(copy16lsb(word), lo_level, hi_level), unpack8(hword_buffer[i]))); + hword_buffer[i + 1] = pack8(add16signed(mult16signed(copy16msb(word), lo_level, hi_level), unpack8(hword_buffer[i + 1]))); } } } From 27f0816fcb9c659c0edee7c94dbd6fa06320688c Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 6 May 2026 17:49:31 -0500 Subject: [PATCH 465/876] Fix invalid unsigned type casting --- shared-module/audiomixer/MixerVoice.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/audiomixer/MixerVoice.c b/shared-module/audiomixer/MixerVoice.c index 6c23a39215c..3a598516e7c 100644 --- a/shared-module/audiomixer/MixerVoice.c +++ b/shared-module/audiomixer/MixerVoice.c @@ -51,7 +51,7 @@ void common_hal_audiomixer_mixervoice_set_panning(audiomixer_mixervoice_obj_t *s #if CIRCUITPY_SYNTHIO synthio_block_assign_slot(arg, &self->panning, MP_QSTR_panning); #else - self->panning = (uint16_t)(mp_arg_validate_obj_float_range(arg, -1, 1, MP_QSTR_panning) * ((1 << 15) - 1)); + self->panning = (int16_t)(mp_arg_validate_obj_float_range(arg, -1, 1, MP_QSTR_panning) * ((1 << 15) - 1)); #endif } From 0b7fa3795c5aa83cd00960cafed6db6c3af65731 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 6 May 2026 17:49:56 -0500 Subject: [PATCH 466/876] Fix polarity of panning calculations --- shared-module/audiomixer/Mixer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index fb4f76c3338..9dc76b439b3 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -226,9 +226,9 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, uint16_t left_panning_scaled = 32768, right_panning_scaled = 32768; if (MP_LIKELY(self->base.channel_count == 2)) { if (panning >= 0) { - right_panning_scaled = 32767 - panning; + left_panning_scaled = 32767 - panning; } else { - left_panning_scaled = 32767 + panning; + right_panning_scaled = 32767 + panning; } } From 9c64406a3ea742e963cf9a2310a5253e3512d5f3 Mon Sep 17 00:00:00 2001 From: JonNelson Date: Thu, 7 May 2026 11:03:53 -0500 Subject: [PATCH 467/876] Support pin IO41 (aka ANTENNA_SWITCH) Support pin IO41 (aka ANTENNA_SWITCH), which allows a user to switch from the built-in antenna to the uFL antenna. This pin is only on the "D" series of Unexpected Maker S3 series of boards. https://unexpectedmaker.com/shop.html#!/FeatherS3-D/p/759221736 --- ports/espressif/boards/unexpectedmaker_feathers3/pins.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/espressif/boards/unexpectedmaker_feathers3/pins.c b/ports/espressif/boards/unexpectedmaker_feathers3/pins.c index e611348caa0..63153d3d696 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers3/pins.c +++ b/ports/espressif/boards/unexpectedmaker_feathers3/pins.c @@ -128,6 +128,10 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_LDO2), MP_ROM_PTR(&pin_GPIO39) }, { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + // built-in vs uFL antenna switch (LOW=built-in, HIGH=uFL, default=built-in) + { MP_ROM_QSTR(MP_QSTR_ANTENNA_SWITCH), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + // I2C { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, From d74582d7ec0d8ccb6b08e813239443f6f431905d Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 7 May 2026 18:44:01 +0200 Subject: [PATCH 468/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 6 +++++- locale/el.po | 6 +++++- locale/hi.po | 6 +++++- locale/ko.po | 6 +++++- locale/ru.po | 6 +++++- locale/tr.po | 6 +++++- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 14eb245b9b8..0d4259c67b1 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -151,6 +151,7 @@ msgid "%q indices must be integers, not %s" msgstr "Indexy %q musí být celá čísla, nikoli %s" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c #: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" @@ -906,10 +907,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "Chyba inicializace kanálu DAC" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "Chyba inicializace zařízení DAC" @@ -1561,6 +1564,7 @@ msgstr "Žádné CCCD pro tuto charakteristiku" #: ports/atmel-samd/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "No DAC on chip" msgstr "Žádný DAC na čipu" @@ -4078,7 +4082,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" diff --git a/locale/el.po b/locale/el.po index f298c5c17e3..f38689079e1 100644 --- a/locale/el.po +++ b/locale/el.po @@ -155,6 +155,7 @@ msgid "%q indices must be integers, not %s" msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι %s" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c #: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" @@ -912,10 +913,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "Σφάλμα εκκίνησης καναλιού DAC" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "Σφάλμα εκκίνησης συσκευής DAC" @@ -1567,6 +1570,7 @@ msgstr "" #: ports/atmel-samd/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "No DAC on chip" msgstr "" @@ -4077,7 +4081,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index f9d7b898198..7f2a366edda 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -142,6 +142,7 @@ msgid "%q indices must be integers, not %s" msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c #: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" @@ -891,10 +892,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "" @@ -1543,6 +1546,7 @@ msgstr "" #: ports/atmel-samd/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "No DAC on chip" msgstr "" @@ -4051,7 +4055,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 9e570208d39..ce536446cf2 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -153,6 +153,7 @@ msgid "%q indices must be integers, not %s" msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c #: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" @@ -935,10 +936,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "DAC 채널 초기화 오류" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "DAC 장치 초기화 오류" @@ -1598,6 +1601,7 @@ msgstr "이 특성에 대한 CCCD가 없습니다" #: ports/atmel-samd/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "No DAC on chip" msgstr "칩에 DAC가 없습니다" @@ -4125,7 +4129,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 0f7c6c0944b..0e67d5b1653 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -155,6 +155,7 @@ msgid "%q indices must be integers, not %s" msgstr "Индексы %q должны быть целыми числами, а не %s" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c #: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" @@ -915,10 +916,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "Ошибка инициализации канала DAC" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "Ошибка инициализации устройства DAC" @@ -1584,6 +1587,7 @@ msgstr "Для этой характеристики нет CCCD" #: ports/atmel-samd/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "No DAC on chip" msgstr "DAC отсутствует на чипе" @@ -4140,7 +4144,7 @@ msgstr "Выходной массив имеет неправильный тип msgid "output array must be contiguous" msgstr "выходной массив должен быть непрерывным" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "переполнение преобразование длинного целого в машинное слово" diff --git a/locale/tr.po b/locale/tr.po index 1012dbf8b39..59f831c4e4e 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -153,6 +153,7 @@ msgid "%q indices must be integers, not %s" msgstr "%q indeksleri integer olmalı, %s değil" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c #: shared-module/busdisplay/BusDisplay.c msgid "%q init failed" @@ -905,10 +906,12 @@ msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" msgstr "" #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" msgstr "" @@ -1562,6 +1565,7 @@ msgstr "" #: ports/atmel-samd/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c msgid "No DAC on chip" msgstr "" @@ -4073,7 +4077,7 @@ msgstr "" msgid "output array must be contiguous" msgstr "" -#: py/objint_mpz.c +#: py/objint_longlong.c py/objint_mpz.c msgid "overflow converting long int to machine word" msgstr "" From 4a0a891fc83d34f1868026b102f8f5a8b0d07890 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 7 May 2026 09:59:33 -0700 Subject: [PATCH 469/876] Fix P4 for v1 and add P4GPIO board definition --- ports/espressif/Makefile | 13 ++- .../espressif/boards/adafruit_p4gpio/board.c | 9 ++ .../boards/adafruit_p4gpio/mpconfigboard.h | 26 ++++++ .../boards/adafruit_p4gpio/mpconfigboard.mk | 14 +++ ports/espressif/boards/adafruit_p4gpio/pins.c | 85 +++++++++++++++++++ .../boards/adafruit_p4gpio/sdkconfig | 70 +++++++++++++++ .../espressif_esp32p4_function_ev/sdkconfig | 2 + ports/espressif/boards/m5stack_tab5/sdkconfig | 2 + .../solderparty_esp32p4_stamp_xl/sdkconfig | 2 + ports/espressif/tools/update_sdkconfig.py | 9 +- 10 files changed, 226 insertions(+), 6 deletions(-) create mode 100644 ports/espressif/boards/adafruit_p4gpio/board.c create mode 100644 ports/espressif/boards/adafruit_p4gpio/mpconfigboard.h create mode 100644 ports/espressif/boards/adafruit_p4gpio/mpconfigboard.mk create mode 100644 ports/espressif/boards/adafruit_p4gpio/pins.c create mode 100644 ports/espressif/boards/adafruit_p4gpio/sdkconfig diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 4c40e71d310..8faad5fb5de 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -399,12 +399,13 @@ CHIP_COMPONENTS = \ esp_hal_usb else ifeq ($(IDF_TARGET),esp32p4) +CIRCUITPY_ESP32P4_REV ?= 1 CFLAGS += \ - -isystem esp-idf/components/soc/esp32p4/register/hw_ver3 \ - -isystem esp-idf/components/soc/esp32p4/register/hw_ver1 \ + -isystem esp-idf/components/soc/esp32p4/register/hw_ver$(CIRCUITPY_ESP32P4_REV) \ -isystem esp-idf/components/esp_hw_support/ldo/include \ -isystem esp-idf/components/esp_driver_touch_sens/hw_ver3/include +ifeq ($(CIRCUITPY_ESP32P4_REV),3) LDFLAGS += \ -Tesp32p4.rom.libc.ld \ -Tesp32p4.rom.systimer.ld \ @@ -413,6 +414,14 @@ LDFLAGS += \ -Tesp32p4.rom.eco5.rvfp.ld \ -Tesp32p4.rom.version.ld \ -Trom.wdt.ld +else +LDFLAGS += \ + -Tesp32p4.rom.libc.ld \ + -Tesp32p4.rom.systimer.ld \ + -Tesp32p4.rom.rvfp.ld \ + -Tesp32p4.rom.version.ld \ + -Trom.wdt.ld +endif CHIP_COMPONENTS = \ diff --git a/ports/espressif/boards/adafruit_p4gpio/board.c b/ports/espressif/boards/adafruit_p4gpio/board.c new file mode 100644 index 00000000000..8287c3ea247 --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.h b/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.h new file mode 100644 index 00000000000..294896c5c34 --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Adafruit P4 GPIO" +#define MICROPY_HW_MCU_NAME "ESP32P4" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO52) + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO35) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO54) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO53) + +// Use the second USB device (numbered 0 and 1) -- HS PHY routed to J1. +#define CIRCUITPY_USB_DEVICE_INSTANCE 1 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + +// FS USB on GPIO24/25 routed to J2. +#define CIRCUITPY_USB_HOST_INSTANCE 0 diff --git a/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.mk b/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.mk new file mode 100644 index 00000000000..dc1560b2bb5 --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x239A +USB_PID = 0x8174 +USB_PRODUCT = "Adafruit P4 GPIO" +USB_MANUFACTURER = "Adafruit" + +IDF_TARGET = esp32p4 + +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 32MB +CIRCUITPY_ESP_PSRAM_MODE = hpi +CIRCUITPY_ESP_PSRAM_FREQ = 200m diff --git a/ports/espressif/boards/adafruit_p4gpio/pins.c b/ports/espressif/boards/adafruit_p4gpio/pins.c new file mode 100644 index 00000000000..77ed1f89513 --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/pins.c @@ -0,0 +1,85 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Header J8 (B1) + { MP_ROM_QSTR(MP_QSTR_B1_0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_B1_1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_B1_2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_B1_3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_B1_4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_B1_5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_B1_6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_B1_7), MP_ROM_PTR(&pin_GPIO7) }, + + // Header J7 (B2) + { MP_ROM_QSTR(MP_QSTR_B2_0), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_B2_1), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_B2_2), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_B2_3), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_B2_4), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_B2_5), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_B2_6), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_B2_7), MP_ROM_PTR(&pin_GPIO15) }, + + // Header J6 (B3) + { MP_ROM_QSTR(MP_QSTR_B3_0), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_B3_1), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_B3_2), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_B3_3), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_B3_4), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_B3_5), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_B3_6), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_B3_7), MP_ROM_PTR(&pin_GPIO23) }, + + // Header J3 (T3) + { MP_ROM_QSTR(MP_QSTR_T3_0), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_T3_1), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_T3_2), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_T3_3), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_T3_4), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_T3_5), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_T3_6), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_T3_7), MP_ROM_PTR(&pin_GPIO26) }, + + // Header J4 (T2) + { MP_ROM_QSTR(MP_QSTR_T2_0), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_T2_1), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_T2_2), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_T2_3), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_T2_4), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_T2_5), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_T2_6), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_T2_7), MP_ROM_PTR(&pin_GPIO34) }, + + // Header J5 (T1) + { MP_ROM_QSTR(MP_QSTR_T1_0), MP_ROM_PTR(&pin_GPIO51) }, + { MP_ROM_QSTR(MP_QSTR_T1_1), MP_ROM_PTR(&pin_GPIO50) }, + { MP_ROM_QSTR(MP_QSTR_T1_2), MP_ROM_PTR(&pin_GPIO49) }, + { MP_ROM_QSTR(MP_QSTR_T1_3), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_T1_4), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_T1_5), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_T1_6), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_T1_7), MP_ROM_PTR(&pin_GPIO44) }, + + // Boot button (also exposed on J9/J10 pin 2) + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO35) }, + + // NeoPixel + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO52) }, + + // StemmaQT / Qwiic I2C (J11) + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO54) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/adafruit_p4gpio/sdkconfig b/ports/espressif/boards/adafruit_p4gpio/sdkconfig new file mode 100644 index 00000000000..681e52bf82c --- /dev/null +++ b/ports/espressif/boards/adafruit_p4gpio/sdkconfig @@ -0,0 +1,70 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Bootloader config +# +# +# Log +# +# +# Format +# +# CONFIG_BOOTLOADER_LOG_COLORS is not set +# end of Format + +# end of Log + +# default: +CONFIG_BOOTLOADER_CPU_CLK_FREQ_MHZ=90 +# +# Serial Flash Configurations +# +# CONFIG_BOOTLOADER_FLASH_XMC_SUPPORT is not set +# end of Serial Flash Configurations + +# end of Bootloader config + +# +# Component config +# +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +# end of Bluetooth + +# +# Hardware Settings +# +# +# Chip revision +# +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_100=y +# default: +CONFIG_ESP32P4_REV_MIN_FULL=100 +# default: +CONFIG_ESP_REV_MIN_FULL=100 +# default: +CONFIG_ESP32P4_REV_MAX_FULL=199 +# default: +CONFIG_ESP_REV_MAX_FULL=199 +# end of Chip revision + +# end of Hardware Settings + +# +# ESP System Settings +# +# default: +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_360=y +# default: +# CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_400 is not set +# default: +CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ=360 +# end of ESP System Settings + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/boards/espressif_esp32p4_function_ev/sdkconfig b/ports/espressif/boards/espressif_esp32p4_function_ev/sdkconfig index e69de29bb2d..3bce8cc0c13 100644 --- a/ports/espressif/boards/espressif_esp32p4_function_ev/sdkconfig +++ b/ports/espressif/boards/espressif_esp32p4_function_ev/sdkconfig @@ -0,0 +1,2 @@ +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_100=y diff --git a/ports/espressif/boards/m5stack_tab5/sdkconfig b/ports/espressif/boards/m5stack_tab5/sdkconfig index e69de29bb2d..3bce8cc0c13 100644 --- a/ports/espressif/boards/m5stack_tab5/sdkconfig +++ b/ports/espressif/boards/m5stack_tab5/sdkconfig @@ -0,0 +1,2 @@ +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_100=y diff --git a/ports/espressif/boards/solderparty_esp32p4_stamp_xl/sdkconfig b/ports/espressif/boards/solderparty_esp32p4_stamp_xl/sdkconfig index e69de29bb2d..3bce8cc0c13 100644 --- a/ports/espressif/boards/solderparty_esp32p4_stamp_xl/sdkconfig +++ b/ports/espressif/boards/solderparty_esp32p4_stamp_xl/sdkconfig @@ -0,0 +1,2 @@ +CONFIG_ESP32P4_SELECTS_REV_LESS_V3=y +CONFIG_ESP32P4_REV_MIN_100=y diff --git a/ports/espressif/tools/update_sdkconfig.py b/ports/espressif/tools/update_sdkconfig.py index d40614edb75..d46514873bd 100644 --- a/ports/espressif/tools/update_sdkconfig.py +++ b/ports/espressif/tools/update_sdkconfig.py @@ -5,7 +5,6 @@ import click import copy import kconfiglib -import kconfiglib.core import os OPT_SETTINGS = [ @@ -203,7 +202,7 @@ def update(debug, board, update_all): # noqa: C901 too complex kconfig_path = pathlib.Path(f"build-{board}/esp-idf/kconfigs.in") kconfig_path = pathlib.Path("esp-idf/Kconfig") - kconfig = kconfiglib.Kconfig(kconfig_path) + kconfig = kconfiglib.Kconfig(str(kconfig_path)) input_config = pathlib.Path(f"build-{board}/esp-idf/sdkconfig") kconfig.load_config(input_config) @@ -244,7 +243,7 @@ def update(debug, board, update_all): # noqa: C901 too complex # Don't include the board file in cp defaults. The board may have custom # overrides. - cp_kconfig_defaults = kconfiglib.Kconfig(kconfig_path) + cp_kconfig_defaults = kconfiglib.Kconfig(str(kconfig_path)) for default_file in sdkconfigs: cp_kconfig_defaults.load_config(default_file, replace=False) @@ -332,7 +331,7 @@ def update(debug, board, update_all): # noqa: C901 too complex shared_keys = {} first = True for path in pathlib.Path(".").glob(loc): - kc = kconfiglib.Kconfig(path) + kc = kconfiglib.Kconfig(str(path)) all_file_syms = set() for sym in kc.unique_defined_syms: all_file_syms.add(sym) @@ -378,6 +377,8 @@ def update(debug, board, update_all): # noqa: C901 too complex all_references.update(rdep.referenced) psram_reference = False for referenced in all_references: + if not referenced.name: + continue if referenced.name.startswith("IDF_TARGET"): target_reference = True if referenced.name in target_symbols: From 5f6f96aa93befb8421158076a2c419928b3cf158 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 7 May 2026 16:36:40 -0700 Subject: [PATCH 470/876] Add SSD1680 FPC-7519rev.b display detection for MagTag 2.9 --- .../boards/adafruit_magtag_2.9_grayscale/board.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index 1437f75165d..aa6a911de12 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -145,12 +145,16 @@ typedef enum { static display_type_t detect_display_type(void) { // Bitbang 4-wire SPI with a bidirectional data line to read the first word of register 0x2e, // which is the 10-byte USER ID. + // NOTE: the SSD1680 drives its response back on the MOSI/DATA line (GPIO35) in half-duplex + // mode, NOT on the separate MISO line (GPIO37). Read with GPIO35 switched to input. // On the IL0373 it will return 0xff because it's not a valid register. - // With SSD1680, we have seen two types: + // With SSD1680, we have seen three types: // 1. The first batch of displays, labeled "FPC-A005 20.06.15 TRX", which needs colstart=0. - // These have 10 byes of zeros in the User ID + // These have 10 bytes of zeros in the User ID. // 2. Second batch, labeled "FPC-7619rev.b", which needs colstart=8. // The USER ID for these boards is [0x44, 0x0, 0x4, 0x0, 0x25, 0x0, 0x1, 0x78, 0x2b, 0xe] + // 3. Third batch, labeled "FPC-7519rev.b", which needs colstart=8. + // The USER ID for these boards is [0xca, 0xfe, 0x0, 0x16, 0x80, 0x0, 0x75, 0x1, 0x0, 0x98] // So let's distinguish just by the first byte. digitalio_digitalinout_obj_t data; digitalio_digitalinout_obj_t clock; @@ -214,6 +218,8 @@ static display_type_t detect_display_type(void) { return DISPLAY_SSD1680_COLSTART_0; case 0x44: return DISPLAY_SSD1680_COLSTART_8; + case 0xca: + return DISPLAY_SSD1680_COLSTART_8; } } From 76f684bf6dfca009450aa948d33cb14a00871a53 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 8 May 2026 06:25:26 -0700 Subject: [PATCH 471/876] Update ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c Co-authored-by: Dan Halbert --- ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index aa6a911de12..c6d1a70e641 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -217,7 +217,6 @@ static display_type_t detect_display_type(void) { case 0x00: return DISPLAY_SSD1680_COLSTART_0; case 0x44: - return DISPLAY_SSD1680_COLSTART_8; case 0xca: return DISPLAY_SSD1680_COLSTART_8; } From cfa1a47aae93e1f7f735cef0e47fff2f9a60a0a1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 8 May 2026 09:35:02 -0400 Subject: [PATCH 472/876] Clarify comment on SPI data reading Updated comment to clarify reading from register 0x2e. --- ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index c6d1a70e641..76bf388d228 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -143,7 +143,7 @@ typedef enum { } display_type_t; static display_type_t detect_display_type(void) { - // Bitbang 4-wire SPI with a bidirectional data line to read the first word of register 0x2e, + // Bitbang 4-wire SPI with a bidirectional data line to read the first byte of register 0x2e, // which is the 10-byte USER ID. // NOTE: the SSD1680 drives its response back on the MOSI/DATA line (GPIO35) in half-duplex // mode, NOT on the separate MISO line (GPIO37). Read with GPIO35 switched to input. From fc33a71a1d8e4036d9b2e87b3eb6133d23e1f99f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 8 May 2026 11:21:04 -0400 Subject: [PATCH 473/876] adapt #10899 to main --- .../espressif/common-hal/alarm/SleepMemory.c | 36 ++++++- shared-bindings/alarm/SleepMemory.c | 12 ++- .../alarm/sleep_memory_persist.py | 100 ++++++++++++++++++ 3 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 tests/circuitpython-manual/alarm/sleep_memory_persist.py diff --git a/ports/espressif/common-hal/alarm/SleepMemory.c b/ports/espressif/common-hal/alarm/SleepMemory.c index 7e7368f77d0..f2a6aaa7a95 100644 --- a/ports/espressif/common-hal/alarm/SleepMemory.c +++ b/ports/espressif/common-hal/alarm/SleepMemory.c @@ -16,18 +16,44 @@ // Data storage for singleton instance of SleepMemory. // Might be RTC_SLOW_MEM or RTC_FAST_MEM, depending on setting of CONFIG_ESP32S2_RTCDATA_IN_FAST_MEM. #if defined(CONFIG_SOC_RTC_FAST_MEM_SUPPORTED) || defined(CONFIG_SOC_RTC_SLOW_MEM_SUPPORTED) -static RTC_DATA_ATTR uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; +static RTC_NOINIT_ATTR uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; + +void alarm_sleep_memory_reset(void) { + // With RTC_NOINIT_ATTR, the bootloader does not initialize sleep memory. + // Preserve contents on resets where the RTC domain stays powered (software + // reset, watchdog, panic, deep sleep wake). Clear on everything else — + // after power-on, SRAM contents are undefined; after brown-out, the RTC + // domain was reset by hardware (System Reset scope per TRM Figure 6.1-1). + esp_reset_reason_t reason = esp_reset_reason(); + switch (reason) { + case ESP_RST_SW: // microcontroller.reset() / esp_restart() + case ESP_RST_DEEPSLEEP: // deep sleep wake + case ESP_RST_PANIC: // unhandled exception + case ESP_RST_INT_WDT: // interrupt watchdog + case ESP_RST_TASK_WDT: // task watchdog + case ESP_RST_WDT: // other watchdog + // RTC domain was not reset — sleep memory is intact. + break; + default: + // Power-on, brown-out, unknown, or any other reason where + // RTC SRAM contents may be undefined. Clear to zero. + memset(_sleep_mem, 0, sizeof(_sleep_mem)); + break; + } +} + #else + // Chips without RTC memory can't persist SleepMemory across deep sleep. static uint8_t _sleep_mem[SLEEP_MEMORY_LENGTH]; -#endif void alarm_sleep_memory_reset(void) { - // ESP-IDF build system takes care of doing esp_sleep_pd_config() or the equivalent with - // the correct settings, depending on which RTC mem we are using. - // https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/system/sleep_modes.html#power-down-of-rtc-peripherals-and-memories + // Do nothing for chips without RTC memory. } +#endif + + uint32_t common_hal_alarm_sleep_memory_get_length(alarm_sleep_memory_obj_t *self) { return sizeof(_sleep_mem); } diff --git a/shared-bindings/alarm/SleepMemory.c b/shared-bindings/alarm/SleepMemory.c index e6d65de4555..5f66a429fbc 100644 --- a/shared-bindings/alarm/SleepMemory.c +++ b/shared-bindings/alarm/SleepMemory.c @@ -12,9 +12,17 @@ #include "shared-bindings/alarm/SleepMemory.h" //| class SleepMemory: -//| """Store raw bytes in RAM that persists during deep sleep. +//| """Store raw bytes in RAM that persists across deep sleep and software resets. //| The class acts as a ``bytearray``. -//| If power is lost, the memory contents are lost. +//| Contents are preserved across ``microcontroller.reset()``, watchdog resets, +//| and deep sleep wake. Contents are lost when power is removed and restored, +//| or on brown-out reset. +//| +//| .. note:: +//| Programs that call ``microcontroller.reset()`` should wait at least +//| one second after boot before resetting, otherwise CircuitPython's +//| double-reset safe mode detector may activate. See +//| ``supervisor/shared/safe_mode.c``. //| //| Note that this class can't be imported and used directly. The sole //| instance of :class:`SleepMemory` is available at diff --git a/tests/circuitpython-manual/alarm/sleep_memory_persist.py b/tests/circuitpython-manual/alarm/sleep_memory_persist.py new file mode 100644 index 00000000000..39e6baafca7 --- /dev/null +++ b/tests/circuitpython-manual/alarm/sleep_memory_persist.py @@ -0,0 +1,100 @@ +"""Reproducer for https://github.com/adafruit/circuitpython/issues/10896 + +Copy to code.py. Sequences through test steps using sleep_memory to +track state. + +The test scoreboard is printed to the magtag e-ink display after every +run so the final display shows cumulative results. +""" + +import alarm +import binascii +import microcontroller +import struct +import supervisor +import time + +# Safe mode avoidance +# On boot CircuitPython writes a SAFE_MODE_USER guard to an RTC register, +# If a second boot occurs before 1000ms elapses then we enter safe mode. +# So, wait for 1000+1ms before calling microcontroller.reset(). +_SAFE_MODE_WINDOW_MS = 1000 + + +def _wait_for_safe_mode_window(): + elapsed_ms = time.monotonic() * 1000 + remaining = _SAFE_MODE_WINDOW_MS + 1 - elapsed_ms + if remaining > 0: + time.sleep(remaining / 1000) + + +# Test result enum +_UNTESTED = 0 +_PASS = 1 +_FAIL = 2 +_LABEL = {_UNTESTED: "-", _PASS: "PASS", _FAIL: "FAIL"} + +# CRC32-protected state in sleep_memory +# [magic:2][step:1][r_reset:1][r_reload:1][pad:1][crc32:4] +_MAGIC = 0xBE01 +_FMT = " Date: Fri, 8 May 2026 15:06:15 -0500 Subject: [PATCH 474/876] audio_i2sin module for espressif and raspberrypi --- locale/circuitpython.pot | 22 +- .../boards/adafruit_sparkle_motion/pins.c | 4 + .../espressif/common-hal/audio_i2sin/I2SIn.c | 169 +++++++ .../espressif/common-hal/audio_i2sin/I2SIn.h | 29 ++ .../common-hal/audio_i2sin/__init__.c | 5 + ports/espressif/mpconfigport.mk | 1 + .../bindings/rp2pio/StateMachine.h | 12 + .../common-hal/audio_i2sin/I2SIn.c | 436 ++++++++++++++++++ .../common-hal/audio_i2sin/I2SIn.h | 29 ++ .../common-hal/audio_i2sin/README.pio | 14 + .../common-hal/audio_i2sin/__init__.c | 5 + .../common-hal/audio_i2sin/i2sin.pio | 27 ++ .../common-hal/audio_i2sin/i2sin_32.pio | 24 + .../common-hal/audio_i2sin/i2sin_left.pio | 23 + .../common-hal/audio_i2sin/i2sin_left_32.pio | 23 + .../common-hal/audio_i2sin/i2sin_swap.pio | 24 + .../common-hal/audio_i2sin/i2sin_swap_32.pio | 24 + .../audio_i2sin/i2sin_swap_left.pio | 24 + .../audio_i2sin/i2sin_swap_left_32.pio | 24 + .../common-hal/rp2pio/StateMachine.c | 30 ++ ports/raspberrypi/mpconfigport.mk | 1 + py/circuitpy_defns.mk | 5 + py/circuitpy_mpconfig.mk | 4 + shared-bindings/audio_i2sin/I2SIn.c | 223 +++++++++ shared-bindings/audio_i2sin/I2SIn.h | 28 ++ shared-bindings/audio_i2sin/__init__.c | 38 ++ shared-bindings/audio_i2sin/__init__.h | 7 + .../audio_i2sin/i2sin_neopixel_reactive.py | 109 +++++ .../audio_i2sin/i2sin_record_sdcard.py | 103 +++++ 29 files changed, 1462 insertions(+), 5 deletions(-) create mode 100644 ports/espressif/common-hal/audio_i2sin/I2SIn.c create mode 100644 ports/espressif/common-hal/audio_i2sin/I2SIn.h create mode 100644 ports/espressif/common-hal/audio_i2sin/__init__.c create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/I2SIn.h create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/README.pio create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/__init__.c create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/i2sin.pio create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/i2sin_32.pio create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/i2sin_left.pio create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/i2sin_left_32.pio create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap.pio create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_32.pio create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left.pio create mode 100644 ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left_32.pio create mode 100644 shared-bindings/audio_i2sin/I2SIn.c create mode 100644 shared-bindings/audio_i2sin/I2SIn.h create mode 100644 shared-bindings/audio_i2sin/__init__.c create mode 100644 shared-bindings/audio_i2sin/__init__.h create mode 100644 tests/circuitpython-manual/audio_i2sin/i2sin_neopixel_reactive.py create mode 100644 tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index e09df9d1781..84e9fd7edd6 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -219,7 +219,7 @@ msgstr "" msgid "%q must be array of type 'h'" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c msgid "%q must be multiple of 8." msgstr "" @@ -659,6 +659,7 @@ msgstr "" msgid "Below minimum frame rate" msgstr "" +#: ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" @@ -804,7 +805,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c msgid "Cannot record to a file" msgstr "" @@ -926,7 +927,7 @@ msgstr "" msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -1694,6 +1695,10 @@ msgstr "" msgid "Ok" msgstr "" +#: ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c +msgid "Only 16, 24, or 32 bit depth supported." +msgstr "" + #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c #, c-format @@ -1806,6 +1811,7 @@ msgstr "" msgid "Parameter error" msgstr "" +#: ports/espressif/common-hal/audio_i2sin/I2SIn.c #: ports/espressif/common-hal/audiobusio/__init__.c msgid "Peripheral in use" msgstr "" @@ -2696,6 +2702,7 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" +#: ports/espressif/common-hal/audio_i2sin/I2SIn.c #: ports/espressif/common-hal/audiobusio/PDMIn.c msgid "bit_depth must be 8, 16, 24, or 32." msgstr "" @@ -3088,15 +3095,20 @@ msgstr "" msgid "default is not a function" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/audio_i2sin/I2SIn.c +msgid "" +"destination buffer must be an array of type 'I' for bit_depth = 24 or 32" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" diff --git a/ports/espressif/boards/adafruit_sparkle_motion/pins.c b/ports/espressif/boards/adafruit_sparkle_motion/pins.c index d78c1e1c4c7..f22cb50608d 100644 --- a/ports/espressif/boards/adafruit_sparkle_motion/pins.c +++ b/ports/espressif/boards/adafruit_sparkle_motion/pins.c @@ -46,6 +46,10 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SIG4), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_D23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_D25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_D26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_D33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, diff --git a/ports/espressif/common-hal/audio_i2sin/I2SIn.c b/ports/espressif/common-hal/audio_i2sin/I2SIn.c new file mode 100644 index 00000000000..4362351c68d --- /dev/null +++ b/ports/espressif/common-hal/audio_i2sin/I2SIn.c @@ -0,0 +1,169 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "bindings/espidf/__init__.h" + +#include "common-hal/audio_i2sin/I2SIn.h" +#include "py/runtime.h" +#include "shared-bindings/audio_i2sin/I2SIn.h" +#include "shared-bindings/microcontroller/Pin.h" + +#include "driver/i2s_std.h" + +#if CIRCUITPY_AUDIO_I2SIN + +void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, + uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified) { + + if (bit_depth != 8 && bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { + mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32.")); + } + + i2s_data_bit_width_t bit_width = (i2s_data_bit_width_t)bit_depth; + + i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); + esp_err_t err = i2s_new_channel(&chan_cfg, NULL, &self->rx_chan); + if (err == ESP_ERR_NOT_FOUND) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Peripheral in use")); + } + CHECK_ESP_RESULT(err); + + // Always configure the bus as stereo. The newer-family I2S peripherals + // (S2/S3/C-series) ignore I2S_SLOT_MODE_MONO on RX and write both slots + // into the DMA buffer regardless, which yields buffers that fill at 2x + // the WS rate and produces half-speed audio. By configuring stereo and + // dropping one slot ourselves in record_to_buffer, behavior is uniform + // across chips. + i2s_std_slot_config_t slot_cfg = left_justified + ? (i2s_std_slot_config_t)I2S_STD_MSB_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO) + : (i2s_std_slot_config_t)I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(bit_width, I2S_SLOT_MODE_STEREO); + + i2s_std_config_t std_cfg = { + .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate), + .slot_cfg = slot_cfg, + .gpio_cfg = { + .mclk = main_clock != NULL ? main_clock->number : I2S_GPIO_UNUSED, + .bclk = bit_clock->number, + .ws = word_select->number, + .dout = I2S_GPIO_UNUSED, + .din = data->number, + }, + }; + CHECK_ESP_RESULT(i2s_channel_init_std_mode(self->rx_chan, &std_cfg)); + CHECK_ESP_RESULT(i2s_channel_enable(self->rx_chan)); + + self->bit_clock = bit_clock; + self->word_select = word_select; + self->data = data; + self->mclk = main_clock; + self->sample_rate = sample_rate; + self->bit_depth = bit_depth; + self->mono = mono; + + claim_pin(bit_clock); + claim_pin(word_select); + claim_pin(data); + if (main_clock) { + claim_pin(main_clock); + } +} + +bool common_hal_audio_i2sin_i2sin_deinited(audio_i2sin_i2sin_obj_t *self) { + return self->data == NULL; +} + +void common_hal_audio_i2sin_i2sin_deinit(audio_i2sin_i2sin_obj_t *self) { + if (common_hal_audio_i2sin_i2sin_deinited(self)) { + return; + } + + if (self->rx_chan) { + i2s_channel_disable(self->rx_chan); + i2s_del_channel(self->rx_chan); + self->rx_chan = NULL; + } + + if (self->bit_clock) { + reset_pin_number(self->bit_clock->number); + } + self->bit_clock = NULL; + + if (self->word_select) { + reset_pin_number(self->word_select->number); + } + self->word_select = NULL; + + if (self->data) { + reset_pin_number(self->data->number); + } + self->data = NULL; + + if (self->mclk) { + reset_pin_number(self->mclk->number); + } + self->mclk = NULL; +} + +uint32_t common_hal_audio_i2sin_i2sin_record_to_buffer(audio_i2sin_i2sin_obj_t *self, + void *buffer, uint32_t length) { + size_t element_size = self->bit_depth / 8; + // 24-bit samples occupy a 32-bit slot on the I2S bus. + if (self->bit_depth == 24) { + element_size = 4; + } + + if (!self->mono) { + size_t result = 0; + esp_err_t err = i2s_channel_read(self->rx_chan, buffer, length * element_size, + &result, portMAX_DELAY); + CHECK_ESP_RESULT(err); + return result / element_size; + } + + // Mono: bus is configured stereo, so each WS frame yields two slots in + // the DMA buffer. Read in chunks into a scratch and keep only the left + // slot of each frame. + uint8_t scratch[256]; + const size_t frame_bytes = 2 * element_size; + const size_t scratch_frames = sizeof(scratch) / frame_bytes; + uint8_t *out = (uint8_t *)buffer; + uint32_t produced = 0; + while (produced < length) { + size_t want_frames = length - produced; + if (want_frames > scratch_frames) { + want_frames = scratch_frames; + } + size_t got_bytes = 0; + esp_err_t err = i2s_channel_read(self->rx_chan, scratch, + want_frames * frame_bytes, &got_bytes, portMAX_DELAY); + CHECK_ESP_RESULT(err); + size_t got_frames = got_bytes / frame_bytes; + for (size_t i = 0; i < got_frames; i++) { + memcpy(out + produced * element_size, + scratch + i * frame_bytes, + element_size); + produced++; + } + if (got_frames < want_frames) { + break; + } + } + return produced; +} + +uint8_t common_hal_audio_i2sin_i2sin_get_bit_depth(audio_i2sin_i2sin_obj_t *self) { + return self->bit_depth; +} + +uint32_t common_hal_audio_i2sin_i2sin_get_sample_rate(audio_i2sin_i2sin_obj_t *self) { + return self->sample_rate; +} + +#endif // CIRCUITPY_AUDIO_I2SIN diff --git a/ports/espressif/common-hal/audio_i2sin/I2SIn.h b/ports/espressif/common-hal/audio_i2sin/I2SIn.h new file mode 100644 index 00000000000..917b72c954b --- /dev/null +++ b/ports/espressif/common-hal/audio_i2sin/I2SIn.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "common-hal/microcontroller/Pin.h" + +#include "driver/i2s_std.h" + +#if CIRCUITPY_AUDIO_I2SIN + +typedef struct { + mp_obj_base_t base; + i2s_chan_handle_t rx_chan; + const mcu_pin_obj_t *bit_clock; + const mcu_pin_obj_t *word_select; + const mcu_pin_obj_t *data; + const mcu_pin_obj_t *mclk; + uint32_t sample_rate; + uint8_t bit_depth; + bool mono; +} audio_i2sin_i2sin_obj_t; + +#endif diff --git a/ports/espressif/common-hal/audio_i2sin/__init__.c b/ports/espressif/common-hal/audio_i2sin/__init__.c new file mode 100644 index 00000000000..584c821b996 --- /dev/null +++ b/ports/espressif/common-hal/audio_i2sin/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 67f8ca2987b..e52d47d9113 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -68,6 +68,7 @@ CIRCUITPY_ALARM_TOUCH ?= 0 CIRCUITPY_ANALOGBUFIO ?= 1 CIRCUITPY_AUDIOBUSIO ?= 1 CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0 +CIRCUITPY_AUDIO_I2SIN ?= 1 CIRCUITPY_AUDIOIO ?= 1 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_BLEIO_NATIVE ?= 1 diff --git a/ports/raspberrypi/bindings/rp2pio/StateMachine.h b/ports/raspberrypi/bindings/rp2pio/StateMachine.h index 16f884bcfca..3c775a96449 100644 --- a/ports/raspberrypi/bindings/rp2pio/StateMachine.h +++ b/ports/raspberrypi/bindings/rp2pio/StateMachine.h @@ -62,6 +62,18 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s bool common_hal_rp2pio_statemachine_stop_background_write(rp2pio_statemachine_obj_t *self); bool common_hal_rp2pio_statemachine_stop_background_read(rp2pio_statemachine_obj_t *self); +// Set the once / loop / loop2 read buffers from raw pointers without going +// through an mp_obj_t wrapper. Pass NULL/0 for unused slots. The caller owns +// the memory; it must remain valid until stop_background_read. +void common_hal_rp2pio_statemachine_set_read_buffers_raw(rp2pio_statemachine_obj_t *self, + void *once, size_t once_len, + void *loop, size_t loop_len, + void *loop2, size_t loop2_len); + +// Returns the DMA channel index used by the current background read, or -1 +// if no background read is active. +int common_hal_rp2pio_statemachine_get_read_dma_channel(rp2pio_statemachine_obj_t *self); + mp_int_t common_hal_rp2pio_statemachine_get_pending_write(rp2pio_statemachine_obj_t *self); mp_int_t common_hal_rp2pio_statemachine_get_pending_read(rp2pio_statemachine_obj_t *self); diff --git a/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c b/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c new file mode 100644 index 00000000000..54d66df88c4 --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c @@ -0,0 +1,436 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include + +#include "py/mperrno.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "shared/runtime/interrupt_char.h" +#include "common-hal/audio_i2sin/I2SIn.h" +#include "shared-bindings/audio_i2sin/I2SIn.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "bindings/rp2pio/StateMachine.h" +#include "supervisor/port.h" + +#include "hardware/dma.h" + +#if CIRCUITPY_AUDIO_I2SIN + +// 16-bit programs sample a stereo frame of 16+16 = 32 bits and rely on +// auto-push at 32 to deliver one packed (right<<16 | left) word per frame. +// 32-bit programs sample 32 bits per channel and produce two FIFO words per +// frame (right first, then left). Each bit takes 6 PIO clocks (a [2]-delay +// pair). 24-bit recordings reuse the 32-bit programs because most 24-bit +// MEMS mics (SPH0645LM4H, INMP441, ICS-43434) transmit their 24 valid bits +// left-justified inside a 32-bit slot. +// +// `in pins 1` runs on a cycle where side-set drives BCLK high. The slave +// updates the data line on the BCLK falling edge, so by the rising edge it +// has settled and is safe to sample. Sampling at BCLK low (the previous, +// incorrect arrangement) catches the data mid-transition and the result is +// effectively noise. +#define PIO_CLOCKS_PER_BIT (6) + +// Master-mode RX, regular pin order (BCLK = WS - 1), Philips alignment. +static const uint16_t i2sin_program[] = { + // .wrap_target + 0xf04e, // 0: set y, 14 side 2 + 0x5a01, // 1: in pins, 1 side 3 [2] + 0x1281, // 2: jmp y--, 1 side 2 [2] + 0x4a01, // 3: in pins, 1 side 1 [2] + 0xe24e, // 4: set y, 14 side 0 [2] + 0x4a01, // 5: in pins, 1 side 1 [2] + 0x0285, // 6: jmp y--, 5 side 0 [2] + 0x5a01, // 7: in pins, 1 side 3 [2] + // .wrap +}; + +// Master-mode RX, regular pin order, left-justified. +static const uint16_t i2sin_program_left_justified[] = { + // .wrap_target + 0xe04e, // 0: set y, 14 side 0 + 0x5a01, // 1: in pins, 1 side 3 [2] + 0x1281, // 2: jmp y--, 1 side 2 [2] + 0x5a01, // 3: in pins, 1 side 3 [2] + 0xf24e, // 4: set y, 14 side 2 [2] + 0x4a01, // 5: in pins, 1 side 1 [2] + 0x0285, // 6: jmp y--, 5 side 0 [2] + 0x4a01, // 7: in pins, 1 side 1 [2] + // .wrap +}; + +// Master-mode RX, swapped pin order (BCLK = WS + 1), Philips alignment. +static const uint16_t i2sin_program_swap[] = { + // .wrap_target + 0xe84e, // 0: set y, 14 side 1 + 0x5a01, // 1: in pins, 1 side 3 [2] + 0x0a81, // 2: jmp y--, 1 side 1 [2] + 0x5201, // 3: in pins, 1 side 2 [2] + 0xe24e, // 4: set y, 14 side 0 [2] + 0x5201, // 5: in pins, 1 side 2 [2] + 0x0285, // 6: jmp y--, 5 side 0 [2] + 0x5a01, // 7: in pins, 1 side 3 [2] + // .wrap +}; + +// Master-mode RX, swapped pin order, left-justified. +static const uint16_t i2sin_program_left_justified_swap[] = { + // .wrap_target + 0xe04e, // 0: set y, 14 side 0 + 0x5a01, // 1: in pins, 1 side 3 [2] + 0x0a81, // 2: jmp y--, 1 side 1 [2] + 0x5a01, // 3: in pins, 1 side 3 [2] + 0xea4e, // 4: set y, 14 side 1 [2] + 0x5201, // 5: in pins, 1 side 2 [2] + 0x0285, // 6: jmp y--, 5 side 0 [2] + 0x5201, // 7: in pins, 1 side 2 [2] + // .wrap +}; + +// 32-bit-per-channel variants: identical to the 16-bit programs above except +// the loop counter is set to 30 (so each `bitloop` runs 31 in's, plus one +// outside the loop = 32 in's per channel). +static const uint16_t i2sin_program_32[] = { + // .wrap_target + 0xf05e, // 0: set y, 30 side 2 + 0x5a01, // 1: in pins, 1 side 3 [2] + 0x1281, // 2: jmp y--, 1 side 2 [2] + 0x4a01, // 3: in pins, 1 side 1 [2] + 0xe25e, // 4: set y, 30 side 0 [2] + 0x4a01, // 5: in pins, 1 side 1 [2] + 0x0285, // 6: jmp y--, 5 side 0 [2] + 0x5a01, // 7: in pins, 1 side 3 [2] + // .wrap +}; + +static const uint16_t i2sin_program_left_justified_32[] = { + // .wrap_target + 0xe05e, // 0: set y, 30 side 0 + 0x5a01, // 1: in pins, 1 side 3 [2] + 0x1281, // 2: jmp y--, 1 side 2 [2] + 0x5a01, // 3: in pins, 1 side 3 [2] + 0xf25e, // 4: set y, 30 side 2 [2] + 0x4a01, // 5: in pins, 1 side 1 [2] + 0x0285, // 6: jmp y--, 5 side 0 [2] + 0x4a01, // 7: in pins, 1 side 1 [2] + // .wrap +}; + +static const uint16_t i2sin_program_swap_32[] = { + // .wrap_target + 0xe85e, // 0: set y, 30 side 1 + 0x5a01, // 1: in pins, 1 side 3 [2] + 0x0a81, // 2: jmp y--, 1 side 1 [2] + 0x5201, // 3: in pins, 1 side 2 [2] + 0xe25e, // 4: set y, 30 side 0 [2] + 0x5201, // 5: in pins, 1 side 2 [2] + 0x0285, // 6: jmp y--, 5 side 0 [2] + 0x5a01, // 7: in pins, 1 side 3 [2] + // .wrap +}; + +static const uint16_t i2sin_program_left_justified_swap_32[] = { + // .wrap_target + 0xe05e, // 0: set y, 30 side 0 + 0x5a01, // 1: in pins, 1 side 3 [2] + 0x0a81, // 2: jmp y--, 1 side 1 [2] + 0x5a01, // 3: in pins, 1 side 3 [2] + 0xea5e, // 4: set y, 30 side 1 [2] + 0x5201, // 5: in pins, 1 side 2 [2] + 0x0285, // 6: jmp y--, 5 side 0 [2] + 0x5201, // 7: in pins, 1 side 2 [2] + // .wrap +}; + +// Caller validates that pins are free. +void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, + uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified) { + + if (main_clock != NULL) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); + } + if (bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("Only 16, 24, or 32 bit depth supported.")); + } + + // 24- and 32-bit recordings both clock 32 bits per channel; 24-bit MEMS + // mics deliver their data left-justified inside that 32-bit slot. + bool wide = (bit_depth != 16); + uint32_t bits_per_channel = wide ? 32 : 16; + uint32_t pio_clocks_per_frame = bits_per_channel * 2 * PIO_CLOCKS_PER_BIT; + + const mcu_pin_obj_t *sideset_pin = NULL; + const uint16_t *program = NULL; + size_t program_len = 0; + + if (bit_clock->number == word_select->number - 1) { + sideset_pin = bit_clock; + if (left_justified) { + program = wide ? i2sin_program_left_justified_32 : i2sin_program_left_justified; + program_len = wide ? MP_ARRAY_SIZE(i2sin_program_left_justified_32) + : MP_ARRAY_SIZE(i2sin_program_left_justified); + } else { + program = wide ? i2sin_program_32 : i2sin_program; + program_len = wide ? MP_ARRAY_SIZE(i2sin_program_32) + : MP_ARRAY_SIZE(i2sin_program); + } + } else if (bit_clock->number == word_select->number + 1) { + sideset_pin = word_select; + if (left_justified) { + program = wide ? i2sin_program_left_justified_swap_32 : i2sin_program_left_justified_swap; + program_len = wide ? MP_ARRAY_SIZE(i2sin_program_left_justified_swap_32) + : MP_ARRAY_SIZE(i2sin_program_left_justified_swap); + } else { + program = wide ? i2sin_program_swap_32 : i2sin_program_swap; + program_len = wide ? MP_ARRAY_SIZE(i2sin_program_swap_32) + : MP_ARRAY_SIZE(i2sin_program_swap); + } + } else { + mp_raise_ValueError(MP_ERROR_TEXT("Bit clock and word select must be sequential GPIO pins")); + } + + common_hal_rp2pio_statemachine_construct( + &self->state_machine, + program, program_len, + sample_rate * pio_clocks_per_frame, + NULL, 0, // init + NULL, 0, // may_exec + NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // out pin + data, 1, // in pins + PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // in pulls + NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // set pins + sideset_pin, 2, false, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // sideset pins + false, // No sideset enable + NULL, PULL_NONE, // jump pin + PIO_PINMASK_NONE, // wait gpio pins + true, // exclusive pin use + false, 32, false, // out settings (unused) + false, // Wait for txstall + true, 32, false, // in settings: auto-push at 32 bits, shift left (MSB first) + false, // Not user-interruptible. + 0, -1, // wrap settings + PIO_ANY_OFFSET, + PIO_FIFO_TYPE_DEFAULT, + PIO_MOV_STATUS_DEFAULT, + PIO_MOV_N_DEFAULT); + + uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); + self->sample_rate = actual_frequency / pio_clocks_per_frame; + self->bit_depth = bit_depth; + self->mono = mono; + self->settled = false; + self->ring = NULL; + self->ring_size = 0; + self->half_size = 0; + self->read_pos = 0; + self->dma_channel = -1; + self->overflow = false; + + // Each PIO frame produces 4 bytes in the FIFO regardless of bit depth + // (16-bit auto-pushes one packed stereo word, 24/32-bit pushes two + // separate 32-bit words). One stereo frame is therefore either 4 or + // 8 bytes; size the half-buffer for ~40 ms of audio so a slow consumer + // (SD card flush etc.) can complete without overrunning. + size_t bytes_per_frame = (bit_depth == 16) ? 4 : 8; + size_t target = (size_t)self->sample_rate * bytes_per_frame * 2 / 2; + size_t half_size = (target > 4096) ? target : 4096; + // Round up to a multiple of 8 so 24/32-bit pair reads never straddle + // the half boundary. + half_size = (half_size + 7u) & ~(size_t)7u; + + self->ring = (uint8_t *)port_malloc(2 * half_size, true); + if (self->ring == NULL) { + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + m_malloc_fail(2 * half_size); + } + self->half_size = half_size; + self->ring_size = 2 * half_size; + + common_hal_rp2pio_statemachine_set_read_buffers_raw(&self->state_machine, + NULL, 0, + self->ring, half_size, + self->ring + half_size, half_size); + if (!common_hal_rp2pio_statemachine_background_read(&self->state_machine, 4, false)) { + port_free(self->ring); + self->ring = NULL; + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + mp_raise_OSError(MP_EIO); + } + self->dma_channel = common_hal_rp2pio_statemachine_get_read_dma_channel(&self->state_machine); +} + +bool common_hal_audio_i2sin_i2sin_deinited(audio_i2sin_i2sin_obj_t *self) { + return common_hal_rp2pio_statemachine_deinited(&self->state_machine); +} + +void common_hal_audio_i2sin_i2sin_deinit(audio_i2sin_i2sin_obj_t *self) { + if (common_hal_audio_i2sin_i2sin_deinited(self)) { + return; + } + common_hal_rp2pio_statemachine_stop_background_read(&self->state_machine); + common_hal_rp2pio_statemachine_deinit(&self->state_machine); + if (self->ring != NULL) { + port_free(self->ring); + self->ring = NULL; + } + self->ring_size = 0; + self->half_size = 0; + self->dma_channel = -1; +} + +uint8_t common_hal_audio_i2sin_i2sin_get_bit_depth(audio_i2sin_i2sin_obj_t *self) { + return self->bit_depth; +} + +uint32_t common_hal_audio_i2sin_i2sin_get_sample_rate(audio_i2sin_i2sin_obj_t *self) { + return self->sample_rate; +} + +// In 16-bit mode, each PIO frame produces a single 32-bit FIFO word with bits +// 31..16 = right channel and bits 15..0 = left channel (both MSB-first signed +// 16-bit). In 24/32-bit mode each frame produces two FIFO words: right first, +// then left, each MSB-first in the full 32 bits. For mono we keep the left +// channel; for stereo we emit (left, right) pairs. +// +// `output_buffer_length` is the requested number of samples to write (sample +// width = 2 bytes for bit_depth=16, 4 bytes for bit_depth=24 or 32). Returns +// the number actually written. +// Compute the byte offset inside `ring` that the DMA is currently writing +// (one past the last word it finished). Always lies in [0, ring_size). +static size_t i2sin_write_pos(audio_i2sin_i2sin_obj_t *self) { + uintptr_t addr = (uintptr_t)dma_channel_hw_addr(self->dma_channel)->write_addr; + uintptr_t base = (uintptr_t)self->ring; + if (addr < base || addr >= base + self->ring_size) { + // The ISR retargets write_addr to the start of the next half right + // after a transfer completes; it should always be in-range, but if + // we observe it mid-update just report "no new data". + return self->read_pos; + } + return (size_t)(addr - base); +} + +uint32_t common_hal_audio_i2sin_i2sin_record_to_buffer(audio_i2sin_i2sin_obj_t *self, + void *buffer, uint32_t output_buffer_length) { + uint32_t output_count = 0; + const size_t ring_size = self->ring_size; + const size_t half_size = self->half_size; + + if (self->bit_depth == 16) { + // 16-bit mode auto-pushes one stereo frame per FIFO word. The DMA has + // been streaming since construct time, so the ring already contains + // settled data; drop the first 4 bytes once to discard a single + // pre-record frame (matches the prior synchronous behaviour). + uint16_t *output = (uint16_t *)buffer; + while (output_count < output_buffer_length) { + size_t write_pos = i2sin_write_pos(self); + size_t avail = (write_pos + ring_size - self->read_pos) % ring_size; + if (avail > half_size) { + // DMA has filled more than one half ahead of us -- we lost + // data. Snap to just behind the DMA on a 4-byte boundary. + self->overflow = true; + self->read_pos = write_pos & ~(size_t)3u; + avail = 0; + } + if (!self->settled && avail >= 4) { + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + self->settled = true; + } + if (avail < 4) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + return output_count; + } + continue; + } + while (avail >= 4 && output_count < output_buffer_length) { + uint32_t frame = *(volatile uint32_t *)(self->ring + self->read_pos); + uint16_t left = (uint16_t)(frame & 0xffff); + uint16_t right = (uint16_t)(frame >> 16); + if (self->mono) { + output[output_count++] = left; + } else { + output[output_count++] = left; + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + break; + } + output[output_count++] = right; + } + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + } + } + } else { + // 24-/32-bit mode emits two FIFO pushes per stereo frame (right then + // left). The state machine was started at instruction 0 by the + // constructor, so the very first push is the right channel and + // alternation is preserved as long as we never touch the program + // counter and always read an even number of words. half_size is a + // multiple of 8, so reading 8-byte pairs stays aligned across the + // ring wrap. + uint32_t *output = (uint32_t *)buffer; + while (output_count < output_buffer_length) { + size_t write_pos = i2sin_write_pos(self); + size_t avail = (write_pos + ring_size - self->read_pos) % ring_size; + if (avail > half_size) { + // Overflow: snap to a frame-aligned position one half behind + // the DMA's current half so we resume on the right channel. + self->overflow = true; + size_t cur_half = (write_pos < half_size) ? 0 : half_size; + self->read_pos = (cur_half + half_size) % ring_size; + self->settled = false; + avail = (write_pos + ring_size - self->read_pos) % ring_size; + } + if (!self->settled) { + if (avail < 8) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + return output_count; + } + continue; + } + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + self->settled = true; + } + if (avail < 8) { + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + return output_count; + } + continue; + } + while (avail >= 8 && output_count < output_buffer_length) { + uint32_t right = *(volatile uint32_t *)(self->ring + self->read_pos); + size_t next_pos = (self->read_pos + 4) % ring_size; + uint32_t left = *(volatile uint32_t *)(self->ring + next_pos); + if (self->mono) { + output[output_count++] = left; + } else { + output[output_count++] = left; + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + break; + } + output[output_count++] = right; + } + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + } + } + } + + return output_count; +} + +#endif // CIRCUITPY_AUDIO_I2SIN diff --git a/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.h b/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.h new file mode 100644 index 00000000000..9f825c79f72 --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "bindings/rp2pio/StateMachine.h" + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint32_t sample_rate; + uint8_t bit_depth; + bool mono; + bool settled; + rp2pio_statemachine_obj_t state_machine; + // Background DMA ring buffer. The state machine alternates DMA writes + // between the two halves so BCLK never stalls between record() calls. + uint8_t *ring; + size_t ring_size; + size_t half_size; + size_t read_pos; + int dma_channel; + bool overflow; +} audio_i2sin_i2sin_obj_t; diff --git a/ports/raspberrypi/common-hal/audio_i2sin/README.pio b/ports/raspberrypi/common-hal/audio_i2sin/README.pio new file mode 100644 index 00000000000..664c1301a72 --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/README.pio @@ -0,0 +1,14 @@ +.pio files right now are compiled by hand with pico-sdk/tools/pioasm and inserted into I2SIn.c + +i2sin.pio I2S RX, 16 bits/channel, regular pin order, not left_justified +i2sin_left.pio I2S RX, 16 bits/channel, regular pin order, left_justified +i2sin_swap.pio I2S RX, 16 bits/channel, swapped pin order, not left_justified +i2sin_swap_left.pio I2S RX, 16 bits/channel, swapped pin order, left_justified +i2sin_32.pio I2S RX, 32 bits/channel, regular pin order, not left_justified +i2sin_left_32.pio I2S RX, 32 bits/channel, regular pin order, left_justified +i2sin_swap_32.pio I2S RX, 32 bits/channel, swapped pin order, not left_justified +i2sin_swap_left_32.pio I2S RX, 32 bits/channel, swapped pin order, left_justified + +The 32-bit programs are also used for bit_depth=24 because most 24-bit I2S +mics (SPH0645LM4H, INMP441, ICS-43434) place their 24 valid data bits +left-justified inside a 32-bit slot. diff --git a/ports/raspberrypi/common-hal/audio_i2sin/__init__.c b/ports/raspberrypi/common-hal/audio_i2sin/__init__.c new file mode 100644 index 00000000000..584c821b996 --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin.pio b/ports/raspberrypi/common-hal/audio_i2sin/i2sin.pio new file mode 100644 index 00000000000..109d1ed5ab4 --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/i2sin.pio @@ -0,0 +1,27 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin +.side_set 2 + +; Master-mode I2S RX. Generates BCLK and LRCLK via side-set and samples the +; data pin. The slave updates `data` on BCLK falling edge, so the master +; samples on the rising edge: every `in pins 1` runs on a side-set value +; with BCLK=1, and the loop/transition instructions hold BCLK=0 so the +; slave has time to settle the next bit. + ; /--- LRCLK + ; |/-- BCLK + ; || + set y 14 side 0b10 +bitloop1: + in pins 1 side 0b11 [2] ; Right channel first + jmp y-- bitloop1 side 0b10 [2] + in pins 1 side 0b01 [2] + set y 14 side 0b00 [2] +bitloop0: + in pins 1 side 0b01 [2] ; Then left channel + jmp y-- bitloop0 side 0b00 [2] + in pins 1 side 0b11 [2] diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_32.pio b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_32.pio new file mode 100644 index 00000000000..d3d7fb5aa6f --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_32.pio @@ -0,0 +1,24 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_32 +.side_set 2 + +; Master-mode I2S RX, 32 bits per channel (also used for 24-bit mics that +; transmit data left-justified in a 32-bit slot). + ; /--- LRCLK + ; |/-- BCLK + ; || + set y 30 side 0b10 +bitloop1: + in pins 1 side 0b11 [2] ; Right channel first + jmp y-- bitloop1 side 0b10 [2] + in pins 1 side 0b01 [2] + set y 30 side 0b00 [2] +bitloop0: + in pins 1 side 0b01 [2] ; Then left channel + jmp y-- bitloop0 side 0b00 [2] + in pins 1 side 0b11 [2] diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_left.pio b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_left.pio new file mode 100644 index 00000000000..eb2b42a7031 --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_left.pio @@ -0,0 +1,23 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_left +.side_set 2 + +; Master-mode I2S RX, left-justified. Mirrors the timing of i2s_left.pio. + ; /--- LRCLK + ; |/-- BCLK + ; || + set y 14 side 0b00 +bitloop1: + in pins 1 side 0b11 [2] ; Right channel first + jmp y-- bitloop1 side 0b10 [2] + in pins 1 side 0b11 [2] + set y 14 side 0b10 [2] +bitloop0: + in pins 1 side 0b01 [2] ; Then left channel + jmp y-- bitloop0 side 0b00 [2] + in pins 1 side 0b01 [2] diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_left_32.pio b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_left_32.pio new file mode 100644 index 00000000000..d2502a21540 --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_left_32.pio @@ -0,0 +1,23 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_left_32 +.side_set 2 + +; Master-mode I2S RX, 32 bits per channel, left-justified. + ; /--- LRCLK + ; |/-- BCLK + ; || + set y 30 side 0b00 +bitloop1: + in pins 1 side 0b11 [2] ; Right channel first + jmp y-- bitloop1 side 0b10 [2] + in pins 1 side 0b11 [2] + set y 30 side 0b10 [2] +bitloop0: + in pins 1 side 0b01 [2] ; Then left channel + jmp y-- bitloop0 side 0b00 [2] + in pins 1 side 0b01 [2] diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap.pio b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap.pio new file mode 100644 index 00000000000..cbf3905bdbc --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap.pio @@ -0,0 +1,24 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_swap +.side_set 2 + +; Master-mode I2S RX with the LRCLK and BCLK pin order swapped (BCLK is the +; higher-numbered GPIO). + ; /--- BCLK + ; |/-- LRCLK + ; || + set y 14 side 0b01 +bitloop1: + in pins 1 side 0b11 [2] ; Right channel first + jmp y-- bitloop1 side 0b01 [2] + in pins 1 side 0b10 [2] + set y 14 side 0b00 [2] +bitloop0: + in pins 1 side 0b10 [2] ; Then left channel + jmp y-- bitloop0 side 0b00 [2] + in pins 1 side 0b11 [2] diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_32.pio b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_32.pio new file mode 100644 index 00000000000..4e00a5a8e54 --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_32.pio @@ -0,0 +1,24 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_swap_32 +.side_set 2 + +; Master-mode I2S RX, 32 bits per channel, with the LRCLK and BCLK pin order +; swapped (BCLK is the higher-numbered GPIO). + ; /--- BCLK + ; |/-- LRCLK + ; || + set y 30 side 0b01 +bitloop1: + in pins 1 side 0b11 [2] ; Right channel first + jmp y-- bitloop1 side 0b01 [2] + in pins 1 side 0b10 [2] + set y 30 side 0b00 [2] +bitloop0: + in pins 1 side 0b10 [2] ; Then left channel + jmp y-- bitloop0 side 0b00 [2] + in pins 1 side 0b11 [2] diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left.pio b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left.pio new file mode 100644 index 00000000000..90ae7ea8d0e --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left.pio @@ -0,0 +1,24 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_swap_left +.side_set 2 + +; Master-mode I2S RX, left-justified, with the LRCLK and BCLK pin order +; swapped (BCLK is the higher-numbered GPIO). + ; /--- BCLK + ; |/-- LRCLK + ; || + set y 14 side 0b00 +bitloop1: + in pins 1 side 0b11 [2] ; Right channel first + jmp y-- bitloop1 side 0b01 [2] + in pins 1 side 0b11 [2] + set y 14 side 0b01 [2] +bitloop0: + in pins 1 side 0b10 [2] ; Then left channel + jmp y-- bitloop0 side 0b00 [2] + in pins 1 side 0b10 [2] diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left_32.pio b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left_32.pio new file mode 100644 index 00000000000..49e0ec7dccf --- /dev/null +++ b/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left_32.pio @@ -0,0 +1,24 @@ +; This file is part of the CircuitPython project: https://circuitpython.org +; +; SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +; +; SPDX-License-Identifier: MIT + +.program i2sin_swap_left_32 +.side_set 2 + +; Master-mode I2S RX, 32 bits per channel, left-justified, with the LRCLK and +; BCLK pin order swapped (BCLK is the higher-numbered GPIO). + ; /--- BCLK + ; |/-- LRCLK + ; || + set y 30 side 0b00 +bitloop1: + in pins 1 side 0b11 [2] ; Right channel first + jmp y-- bitloop1 side 0b01 [2] + in pins 1 side 0b11 [2] + set y 30 side 0b01 [2] +bitloop0: + in pins 1 side 0b10 [2] ; Then left channel + jmp y-- bitloop0 side 0b00 [2] + in pins 1 side 0b10 [2] diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 71050677f22..af6e98bbc85 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -1482,6 +1482,36 @@ bool common_hal_rp2pio_statemachine_stop_background_read(rp2pio_statemachine_obj return true; } +void common_hal_rp2pio_statemachine_set_read_buffers_raw(rp2pio_statemachine_obj_t *self, + void *once, size_t once_len, + void *loop, size_t loop_len, + void *loop2, size_t loop2_len) { + memset(&self->once_read_buf_info, 0, sizeof(self->once_read_buf_info)); + memset(&self->loop_read_buf_info, 0, sizeof(self->loop_read_buf_info)); + memset(&self->loop2_read_buf_info, 0, sizeof(self->loop2_read_buf_info)); + if (once && once_len) { + self->once_read_buf_info.info.buf = once; + self->once_read_buf_info.info.len = once_len; + } + if (loop && loop_len) { + self->loop_read_buf_info.info.buf = loop; + self->loop_read_buf_info.info.len = loop_len; + } + if (loop2 && loop2_len) { + self->loop2_read_buf_info.info.buf = loop2; + self->loop2_read_buf_info.info.len = loop2_len; + } +} + +int common_hal_rp2pio_statemachine_get_read_dma_channel(rp2pio_statemachine_obj_t *self) { + uint8_t pio_index = pio_get_index(self->pio); + uint8_t sm = self->state_machine; + if (!SM_DMA_ALLOCATED_READ(pio_index, sm)) { + return -1; + } + return SM_DMA_GET_CHANNEL_READ(pio_index, sm); +} + bool common_hal_rp2pio_statemachine_get_reading(rp2pio_statemachine_obj_t *self) { return !self->dma_completed_read; } diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 90be1afd109..dd93e216481 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -44,6 +44,7 @@ CIRCUITPY_ANALOGBUFIO = 1 # Audio via PWM CIRCUITPY_AUDIOIO = 0 CIRCUITPY_AUDIOBUSIO ?= 1 +CIRCUITPY_AUDIO_I2SIN ?= $(CIRCUITPY_AUDIOBUSIO) CIRCUITPY_AUDIOCORE ?= 1 CIRCUITPY_AUDIOPWMIO ?= 1 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index e0ad8fa81bc..48fa62bf3c7 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -122,6 +122,9 @@ endif ifeq ($(CIRCUITPY_AUDIOBUSIO),1) SRC_PATTERNS += audiobusio/% endif +ifeq ($(CIRCUITPY_AUDIO_I2SIN),1) +SRC_PATTERNS += audio_i2sin/% +endif ifeq ($(CIRCUITPY_AUDIOIO),1) SRC_PATTERNS += audioio/% endif @@ -505,6 +508,8 @@ SRC_COMMON_HAL_ALL = \ audiobusio/I2SOut.c \ audiobusio/PDMIn.c \ audiobusio/__init__.c \ + audio_i2sin/I2SIn.c \ + audio_i2sin/__init__.c \ audioio/AudioOut.c \ audioio/__init__.c \ audiopwmio/PWMAudioOut.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 17012290328..a5ccd9273b1 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -135,6 +135,10 @@ CFLAGS += -DCIRCUITPY_AUDIOBUSIO_I2SOUT=$(CIRCUITPY_AUDIOBUSIO_I2SOUT) CIRCUITPY_AUDIOBUSIO_PDMIN ?= $(CIRCUITPY_AUDIOBUSIO) CFLAGS += -DCIRCUITPY_AUDIOBUSIO_PDMIN=$(CIRCUITPY_AUDIOBUSIO_PDMIN) +# I2S audio input (separate core module `audio_i2sin`). +CIRCUITPY_AUDIO_I2SIN ?= 0 +CFLAGS += -DCIRCUITPY_AUDIO_I2SIN=$(CIRCUITPY_AUDIO_I2SIN) + CIRCUITPY_AUDIOIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) diff --git a/shared-bindings/audio_i2sin/I2SIn.c b/shared-bindings/audio_i2sin/I2SIn.c new file mode 100644 index 00000000000..7c43d24bfa1 --- /dev/null +++ b/shared-bindings/audio_i2sin/I2SIn.c @@ -0,0 +1,223 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "extmod/vfs_fat.h" +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/mphal.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audio_i2sin/I2SIn.h" +#include "shared-bindings/util.h" + +//| class I2SIn: +//| """Record an input I2S audio stream from an external I2S source such as a MEMS microphone.""" +//| +//| def __init__( +//| self, +//| bit_clock: microcontroller.Pin, +//| word_select: microcontroller.Pin, +//| data: microcontroller.Pin, +//| *, +//| main_clock: Optional[microcontroller.Pin] = None, +//| sample_rate: int = 16000, +//| bit_depth: int = 16, +//| mono: bool = True, +//| left_justified: bool = False, +//| ) -> None: +//| """Create an I2SIn object associated with the given pins. This allows you to +//| record audio signals from an external I2S source (e.g. an I2S MEMS microphone +//| like the SPH0645LM4H or INMP441). +//| +//| The pin signature mirrors `audiobusio.I2SOut` so users can swap classes; +//| recording parameters mirror `audiobusio.PDMIn`. +//| +//| :param ~microcontroller.Pin bit_clock: The bit clock (or serial clock) pin +//| :param ~microcontroller.Pin word_select: The word select (or left/right clock) pin +//| :param ~microcontroller.Pin data: The data input pin +//| :param ~microcontroller.Pin main_clock: The main clock pin. Not all ports support this. +//| :param int sample_rate: Target sample rate of the resulting samples. Check `sample_rate` for actual value. +//| :param int bit_depth: Number of bits per sample. Must be 8, 16, 24, or 32. +//| For 8-bit, pass a ``bytearray`` or ``array.array('B', ...)``; for 16-bit, +//| ``array.array('H', ...)``; for 24- or 32-bit, ``array.array('I', ...)``. +//| Note that 24-bit samples from mics like the SPH0645LM4H / INMP441 are +//| transported in 32-bit slots, so use ``bit_depth=32`` and an ``'I'`` buffer. +//| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise. +//| :param bool left_justified: True when data bits are aligned with the word select clock. False +//| when they are shifted by one to match classic I2S protocol. Set True for mics like the SPH0645LM4H. +//| +//| Example, recording 16-bit mono samples from an INMP441:: +//| +//| import array +//| import audio_i2sin +//| import board +//| +//| buf = array.array("H", [0] * 16000) +//| with audio_i2sin.I2SIn(board.D9, board.D10, board.D11, +//| sample_rate=16000, bit_depth=16) as mic: +//| mic.record(buf, len(buf)) +//| """ +//| ... +//| +static mp_obj_t audio_i2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + #if !CIRCUITPY_AUDIO_I2SIN + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_I2SIn); + return NULL; // Not reachable. + #else + enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, + ARG_sample_rate, ARG_bit_depth, ARG_mono, ARG_left_justified }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bit_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_word_select, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_main_clock, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_sample_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} }, + { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_left_justified, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + const mcu_pin_obj_t *bit_clock = validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); + const mcu_pin_obj_t *word_select = validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); + const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj, MP_QSTR_data); + const mcu_pin_obj_t *main_clock = validate_obj_is_free_pin_or_none(args[ARG_main_clock].u_obj, MP_QSTR_main_clock); + + uint32_t sample_rate = args[ARG_sample_rate].u_int; + uint8_t bit_depth = args[ARG_bit_depth].u_int; + if (bit_depth % 8 != 0) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be multiple of 8."), MP_QSTR_bit_depth); + } + bool mono = args[ARG_mono].u_bool; + bool left_justified = args[ARG_left_justified].u_bool; + + audio_i2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audio_i2sin_i2sin_obj_t, &audio_i2sin_i2sin_type); + common_hal_audio_i2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, + sample_rate, bit_depth, mono, left_justified); + + return MP_OBJ_FROM_PTR(self); + #endif +} + +#if CIRCUITPY_AUDIO_I2SIN +//| def deinit(self) -> None: +//| """Deinitialises the I2SIn and releases any hardware resources for reuse.""" +//| ... +//| +static mp_obj_t audio_i2sin_i2sin_deinit(mp_obj_t self_in) { + audio_i2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audio_i2sin_i2sin_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audio_i2sin_i2sin_deinit_obj, audio_i2sin_i2sin_deinit); + +static void check_for_deinit(audio_i2sin_i2sin_obj_t *self) { + if (common_hal_audio_i2sin_i2sin_deinited(self)) { + raise_deinited_error(); + } +} + +//| def __enter__(self) -> I2SIn: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def record(self, destination: WriteableBuffer, destination_length: int) -> int: +//| """Records destination_length samples to destination. This is blocking. +//| +//| :return: The number of samples recorded. If this is less than ``destination_length``, +//| some samples were missed due to processing time.""" +//| ... +//| +static mp_obj_t audio_i2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) { + audio_i2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_obj); + check_for_deinit(self); + uint32_t length = mp_arg_validate_type_int(destination_length, MP_QSTR_length); + mp_arg_validate_length_min(length, 0, MP_QSTR_length); + + mp_buffer_info_t bufinfo; + if (mp_obj_is_type(destination, &mp_type_fileio)) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("Cannot record to a file")); + } + mp_get_buffer_raise(destination, &bufinfo, MP_BUFFER_WRITE); + if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { + mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); + } + uint8_t bit_depth = common_hal_audio_i2sin_i2sin_get_bit_depth(self); + if ((bit_depth == 24 || bit_depth == 32) && bufinfo.typecode != 'I') { + mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'I' for bit_depth = 24 or 32")); + } else if (bit_depth == 16 && bufinfo.typecode != 'H') { + mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'H' for bit_depth = 16")); + } else if (bit_depth == 8 && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8")); + } + uint32_t length_written = + common_hal_audio_i2sin_i2sin_record_to_buffer(self, bufinfo.buf, length); + return MP_OBJ_NEW_SMALL_INT(length_written); +} +MP_DEFINE_CONST_FUN_OBJ_3(audio_i2sin_i2sin_record_obj, audio_i2sin_i2sin_obj_record); + +//| sample_rate: int +//| """The actual sample rate of the recording. This may not match the constructed +//| sample rate due to internal clock limitations.""" +//| +static mp_obj_t audio_i2sin_i2sin_obj_get_sample_rate(mp_obj_t self_in) { + audio_i2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audio_i2sin_i2sin_get_sample_rate(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audio_i2sin_i2sin_get_sample_rate_obj, audio_i2sin_i2sin_obj_get_sample_rate); + +MP_PROPERTY_GETTER(audio_i2sin_i2sin_sample_rate_obj, + (mp_obj_t)&audio_i2sin_i2sin_get_sample_rate_obj); + +//| bit_depth: int +//| """The actual bit depth of the recording. (read-only)""" +//| +//| +static mp_obj_t audio_i2sin_i2sin_obj_get_bit_depth(mp_obj_t self_in) { + audio_i2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audio_i2sin_i2sin_get_bit_depth(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audio_i2sin_i2sin_get_bit_depth_obj, audio_i2sin_i2sin_obj_get_bit_depth); + +MP_PROPERTY_GETTER(audio_i2sin_i2sin_bit_depth_obj, + (mp_obj_t)&audio_i2sin_i2sin_get_bit_depth_obj); + +static const mp_rom_map_elem_t audio_i2sin_i2sin_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audio_i2sin_i2sin_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audio_i2sin_i2sin_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&audio_i2sin_i2sin_record_obj) }, + { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audio_i2sin_i2sin_sample_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audio_i2sin_i2sin_bit_depth_obj) }, +}; +static MP_DEFINE_CONST_DICT(audio_i2sin_i2sin_locals_dict, audio_i2sin_i2sin_locals_dict_table); +#endif // CIRCUITPY_AUDIO_I2SIN + +MP_DEFINE_CONST_OBJ_TYPE( + audio_i2sin_i2sin_type, + MP_QSTR_I2SIn, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audio_i2sin_i2sin_make_new + #if CIRCUITPY_AUDIO_I2SIN + , locals_dict, &audio_i2sin_i2sin_locals_dict + #endif + ); diff --git a/shared-bindings/audio_i2sin/I2SIn.h b/shared-bindings/audio_i2sin/I2SIn.h new file mode 100644 index 00000000000..183b646ecd8 --- /dev/null +++ b/shared-bindings/audio_i2sin/I2SIn.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-bindings/microcontroller/Pin.h" + +#if CIRCUITPY_AUDIO_I2SIN +#include "common-hal/audio_i2sin/I2SIn.h" +#endif + +extern const mp_obj_type_t audio_i2sin_i2sin_type; + +#if CIRCUITPY_AUDIO_I2SIN +void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, + uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified); +void common_hal_audio_i2sin_i2sin_deinit(audio_i2sin_i2sin_obj_t *self); +bool common_hal_audio_i2sin_i2sin_deinited(audio_i2sin_i2sin_obj_t *self); +uint32_t common_hal_audio_i2sin_i2sin_record_to_buffer(audio_i2sin_i2sin_obj_t *self, + void *buffer, uint32_t length); +uint8_t common_hal_audio_i2sin_i2sin_get_bit_depth(audio_i2sin_i2sin_obj_t *self); +uint32_t common_hal_audio_i2sin_i2sin_get_sample_rate(audio_i2sin_i2sin_obj_t *self); +#endif diff --git a/shared-bindings/audio_i2sin/__init__.c b/shared-bindings/audio_i2sin/__init__.c new file mode 100644 index 00000000000..ba163ae75f4 --- /dev/null +++ b/shared-bindings/audio_i2sin/__init__.c @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/audio_i2sin/__init__.h" +#include "shared-bindings/audio_i2sin/I2SIn.h" + +//| """Support for recording audio from an I2S input source. +//| +//| The `audio_i2sin` module contains the `I2SIn` class for recording audio +//| from an external I2S source such as a MEMS microphone (e.g. SPH0645LM4H +//| or INMP441). +//| +//| All classes change hardware state and should be deinitialized when they +//| are no longer needed. To do so, either call :py:meth:`!deinit` or use a +//| context manager.""" + +static const mp_rom_map_elem_t audio_i2sin_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audio_i2sin) }, + { MP_ROM_QSTR(MP_QSTR_I2SIn), MP_ROM_PTR(&audio_i2sin_i2sin_type) }, +}; + +static MP_DEFINE_CONST_DICT(audio_i2sin_module_globals, audio_i2sin_module_globals_table); + +const mp_obj_module_t audio_i2sin_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&audio_i2sin_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_audio_i2sin, audio_i2sin_module); diff --git a/shared-bindings/audio_i2sin/__init__.h b/shared-bindings/audio_i2sin/__init__.h new file mode 100644 index 00000000000..779b49ffd8d --- /dev/null +++ b/shared-bindings/audio_i2sin/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/tests/circuitpython-manual/audio_i2sin/i2sin_neopixel_reactive.py b/tests/circuitpython-manual/audio_i2sin/i2sin_neopixel_reactive.py new file mode 100644 index 00000000000..58a100547f2 --- /dev/null +++ b/tests/circuitpython-manual/audio_i2sin/i2sin_neopixel_reactive.py @@ -0,0 +1,109 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# Audio-reactive NeoPixel effect driven by an I2S MEMS microphone. +# +# Wiring (defaults assume an INMP441 / SPH0645 style mic): +# mic BCLK -> board.D5 +# mic LRCL -> board.D6 +# mic DOUT -> board.D9 +# neopixel -> board.D10 +# +# The mic's 24-bit samples ride in 32-bit slots, so we use bit_depth=32 and +# an array.array("I", ...). For SPH0645 set left_justified=True. + +import array +import math +import time + +import board +import audio_i2sin +import neopixel + +NUM_PIXELS = 30 +PIXEL_PIN = board.D10 + +SAMPLE_RATE = 16000 +SAMPLES_PER_FRAME = 512 # ~32 ms windows + +pixels = neopixel.NeoPixel(PIXEL_PIN, NUM_PIXELS, brightness=0.3, auto_write=False) + +mic = audio_i2sin.I2SIn( + bit_clock=board.D5, + word_select=board.D6, + data=board.D9, + sample_rate=SAMPLE_RATE, + bit_depth=32, + mono=True, + left_justified=False, # set True for SPH0645LM4H +) + +buf = array.array("I", [0] * SAMPLES_PER_FRAME) + + +def to_signed24(u32): + # The mic packs a 24-bit signed sample left-justified in 32 bits. + s = u32 >> 8 + if s & 0x800000: + s -= 0x1000000 + return s + + +def wheel(pos): + pos = pos % 256 + if pos < 85: + return (pos * 3, 255 - pos * 3, 0) + if pos < 170: + pos -= 85 + return (255 - pos * 3, 0, pos * 3) + pos -= 170 + return (0, pos * 3, 255 - pos * 3) + + +# Smoothed noise floor + peak so the effect adapts to the room. +noise_floor = 2000.0 +peak = 20000.0 +hue = 0 +smoothed_level = 0.0 + +while True: + mic.record(buf, len(buf)) + + # Compute RMS of the window. + acc = 0 + for raw in buf: + s = to_signed24(raw) + acc += s * s + rms = math.sqrt(acc / len(buf)) + + # Track a slow noise floor and a decaying peak for auto-gain. + noise_floor = 0.995 * noise_floor + 0.005 * rms + if rms > peak: + peak = rms + else: + peak *= 0.995 + if peak < noise_floor + 1000: + peak = noise_floor + 1000 + + level = (rms - noise_floor) / (peak - noise_floor) + if level < 0: + level = 0.0 + elif level > 1: + level = 1.0 + + # Smooth the bar so it doesn't jitter on every frame. + smoothed_level = 0.6 * smoothed_level + 0.4 * level + + lit = int(smoothed_level * NUM_PIXELS) + hue = (hue + 2) % 256 + + for i in range(NUM_PIXELS): + if i < lit: + r, g, b = wheel((hue + i * (256 // NUM_PIXELS)) % 256) + pixels[i] = (r, g, b) + else: + pixels[i] = (0, 0, 0) + pixels.show() + + time.sleep(0.005) diff --git a/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py b/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py new file mode 100644 index 00000000000..bdb77066f70 --- /dev/null +++ b/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py @@ -0,0 +1,103 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# Record a longer I2S audio capture to a WAV file on an SD card. +# +# Produces /sd/recording.wav. Set left_justified=True for SPH0645LM4H mics. + +import array +import struct +import time + +import ulab.numpy as np +import board +import busio +import sdcardio +import storage +import audio_i2sin + +# ---- Recording config ------------------------------------------------------ +SAMPLE_RATE = 16000 +RECORD_SECONDS = 10 +CHUNK_SAMPLES = 1024 # samples captured per record() call +OUTPUT_PATH = "/sd/talk.wav" + +# ---- Mount SD -------------------------------------------------------------- +spi = board.SPI() +sdcard = sdcardio.SDCard(spi, cs=board.D10, baudrate=24_000_000) +vfs = storage.VfsFat(sdcard) +storage.mount(vfs, "/sd") + +# ---- Mic ------------------------------------------------------------------- +# 24-bit MEMS mics ride in 32-bit slots. Downconvert each slot to a +# signed 16-bit PCM sample before writing. +mic = audio_i2sin.I2SIn( + bit_clock=board.D5, + word_select=board.D6, + data=board.D9, + sample_rate=SAMPLE_RATE, + bit_depth=32, + mono=True, + left_justified=False, # True for SPH0645LM4H +) + +actual_rate = mic.sample_rate +print("Recording at", actual_rate, "Hz for", RECORD_SECONDS, "s ->", OUTPUT_PATH) + +raw = array.array("I", [0] * CHUNK_SAMPLES) +pcm16 = array.array("h", [0] * CHUNK_SAMPLES) + + +def write_wav_header(f, sample_rate, num_samples, bits_per_sample=16, channels=1): + byte_rate = sample_rate * channels * bits_per_sample // 8 + block_align = channels * bits_per_sample // 8 + data_size = num_samples * block_align + f.write(b"RIFF") + f.write(struct.pack("> 16 # take top 16 bits + if s & 0x8000: + s -= 0x10000 # sign-extend + pcm16[i] = s + # Write only the valid portion. + f.write(memoryview(pcm16)[:n]) + written += n + + elapsed = time.monotonic() - start + # Rewrite header now that we know the true sample count. + f.seek(0) + write_wav_header(f, actual_rate, written) + +storage.umount("/sd") + +print("Done. Wrote", written, "samples in", round(elapsed, 2), "s") From da091385848d2ddef462c670569684268e5e6dcd Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 8 May 2026 15:19:00 -0500 Subject: [PATCH 475/876] format sdcard test --- .../audio_i2sin/i2sin_record_sdcard.py | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py b/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py index bdb77066f70..3045cac9d50 100644 --- a/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py +++ b/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py @@ -57,14 +57,18 @@ def write_wav_header(f, sample_rate, num_samples, bits_per_sample=16, channels=1 f.write(struct.pack("> 16 # take top 16 bits + s = v >> 16 # take top 16 bits if s & 0x8000: - s -= 0x10000 # sign-extend + s -= 0x10000 # sign-extend pcm16[i] = s # Write only the valid portion. f.write(memoryview(pcm16)[:n]) From c16d316649e36b2074411f1168ffec0f63035a76 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 8 May 2026 15:05:37 -0700 Subject: [PATCH 476/876] MagTag SSD1680 FPC-7519rev.b: use VCOM=0x20 for correct contrast The FPC-7519rev.b panel (User ID byte 0xca) shows a dark gray background with the default VCOM=0x28. Setting VCOM=0x20 (-1.5V) gives a light gray background with solid black text. Surgical fix: dedicated ssd1680_vcom20_display_start_sequence and DISPLAY_SSD1680_COLSTART_8_VCOM20 type routed to case 0xca: only. The 0x44 and 0x00 panels are untouched. --- .../adafruit_magtag_2.9_grayscale/board.c | 49 +++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index 701714db4b8..e8304dded4b 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -128,6 +128,40 @@ const uint8_t ssd1680_display_start_sequence[] = { 0x22, 0x00, 0x01, 0xc7 // display update mode }; +// FPC-7519rev.b (User ID byte 0xca) requires VCOM=0x20 (-1.5V) for correct contrast. +// The 0x44 panel works correctly with the default VCOM=0x28, so keep them separate. +const uint8_t ssd1680_vcom20_display_start_sequence[] = { + 0x12, DELAY, 0x00, 0x14, // soft reset and wait 20ms + 0x11, 0x00, 0x01, 0x03, // Ram data entry mode + 0x3c, 0x00, 0x01, 0x03, // border color + 0x2c, 0x00, 0x01, 0x20, // Set vcom voltage (0x20 = -1.5V, tuned for FPC-7519rev.b) + 0x03, 0x00, 0x01, 0x17, // Set gate voltage + 0x04, 0x00, 0x03, 0x41, 0xae, 0x32, // Set source voltage + 0x4e, 0x00, 0x01, 0x01, // ram x count + 0x4f, 0x00, 0x02, 0x00, 0x00, // ram y count + 0x01, 0x00, 0x03, 0x27, 0x01, 0x00, // set display size + 0x32, 0x00, 0x99, // Update waveforms + 0x2a, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L0 + 0x20, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L1 + 0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L2 + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L3 + 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L4 + 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, // TP, SR, RP of Group0 + 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, // TP, SR, RP of Group1 + 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, // TP, SR, RP of Group2 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group3 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group4 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group5 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group6 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group8 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group9 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group11 + 0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, // FR, XON + 0x22, 0x00, 0x01, 0xc7 // display update mode +}; + const uint8_t ssd1680_display_stop_sequence[] = { 0x10, DELAY, 0x01, 0x01, 0x64 }; @@ -141,6 +175,7 @@ typedef enum { DISPLAY_IL0373, DISPLAY_SSD1680_COLSTART_0, DISPLAY_SSD1680_COLSTART_8, + DISPLAY_SSD1680_COLSTART_8_VCOM20, // FPC-7519rev.b (User ID 0xca) } display_type_t; static display_type_t detect_display_type(void) { @@ -218,8 +253,9 @@ static display_type_t detect_display_type(void) { case 0x00: return DISPLAY_SSD1680_COLSTART_0; case 0x44: - case 0xca: return DISPLAY_SSD1680_COLSTART_8; + case 0xca: + return DISPLAY_SSD1680_COLSTART_8_VCOM20; } } @@ -268,12 +304,17 @@ void board_init(void) { } else { epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; // Default colstart is 0. - if (display_type == DISPLAY_SSD1680_COLSTART_8) { + if (display_type == DISPLAY_SSD1680_COLSTART_8 || display_type == DISPLAY_SSD1680_COLSTART_8_VCOM20) { args.colstart = 8; } args.bus = bus; - args.start_sequence = ssd1680_display_start_sequence; - args.start_sequence_len = sizeof(ssd1680_display_start_sequence); + if (display_type == DISPLAY_SSD1680_COLSTART_8_VCOM20) { + args.start_sequence = ssd1680_vcom20_display_start_sequence; + args.start_sequence_len = sizeof(ssd1680_vcom20_display_start_sequence); + } else { + args.start_sequence = ssd1680_display_start_sequence; + args.start_sequence_len = sizeof(ssd1680_display_start_sequence); + } args.stop_sequence = ssd1680_display_stop_sequence; args.stop_sequence_len = sizeof(ssd1680_display_stop_sequence); args.width = 296; From 5dd10979e6bf115877635b7c1fe9f03ba2d2c795 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 8 May 2026 17:18:52 -0700 Subject: [PATCH 477/876] MagTag SSD1680 FPC-7519rev.b: tune VCOM to 0x14 (-1.0V) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Testing across 0x28→0x20→0x1c→0x18→0x14→0x10 confirmed 0x14 as the sweet spot: background matches the FPC-7619rev.b panel without the dark halo fringe artifacts that appear below 0x14. Co-Authored-By: Claude Sonnet 4.6 --- ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index e8304dded4b..a988180f14a 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -128,13 +128,13 @@ const uint8_t ssd1680_display_start_sequence[] = { 0x22, 0x00, 0x01, 0xc7 // display update mode }; -// FPC-7519rev.b (User ID byte 0xca) requires VCOM=0x20 (-1.5V) for correct contrast. +// FPC-7519rev.b (User ID byte 0xca) requires lower VCOM for correct contrast. // The 0x44 panel works correctly with the default VCOM=0x28, so keep them separate. const uint8_t ssd1680_vcom20_display_start_sequence[] = { 0x12, DELAY, 0x00, 0x14, // soft reset and wait 20ms 0x11, 0x00, 0x01, 0x03, // Ram data entry mode 0x3c, 0x00, 0x01, 0x03, // border color - 0x2c, 0x00, 0x01, 0x20, // Set vcom voltage (0x20 = -1.5V, tuned for FPC-7519rev.b) + 0x2c, 0x00, 0x01, 0x14, // Set vcom voltage (0x14 = -1.0V, tuned for FPC-7519rev.b) 0x03, 0x00, 0x01, 0x17, // Set gate voltage 0x04, 0x00, 0x03, 0x41, 0xae, 0x32, // Set source voltage 0x4e, 0x00, 0x01, 0x01, // ram x count From 83576c6a1063afbf0ee156e08c64809d7303f716 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 8 May 2026 18:33:57 -0700 Subject: [PATCH 478/876] =?UTF-8?q?MagTag=20SSD1680=20FPC-7519rev.b:=20ren?= =?UTF-8?q?ame=20vcom20=20=E2=86=92=20vcom14,=20add=20OTP=20note?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename ssd1680_vcom20_display_start_sequence → ssd1680_vcom14_display_start_sequence and DISPLAY_SSD1680_COLSTART_8_VCOM20 → DISPLAY_SSD1680_COLSTART_8_VCOM14 to match the actual register value being set (0x14, not the earlier test value 0x20). Add comment noting that VCOM=0x14 was independently confirmed by reading OTP register 0x2D on the physical panel — byte 1 of the response is 0x14, matching what the panel manufacturer programmed as the recommended VCOM for this revision. Co-Authored-By: Claude Sonnet 4.6 --- .../boards/adafruit_magtag_2.9_grayscale/board.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index a988180f14a..cd3295a2e08 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -129,8 +129,9 @@ const uint8_t ssd1680_display_start_sequence[] = { }; // FPC-7519rev.b (User ID byte 0xca) requires lower VCOM for correct contrast. +// VCOM=0x14 (-1.0V) confirmed by reading the panel's OTP register (cmd 0x2D, byte 1 = 0x14). // The 0x44 panel works correctly with the default VCOM=0x28, so keep them separate. -const uint8_t ssd1680_vcom20_display_start_sequence[] = { +const uint8_t ssd1680_vcom14_display_start_sequence[] = { 0x12, DELAY, 0x00, 0x14, // soft reset and wait 20ms 0x11, 0x00, 0x01, 0x03, // Ram data entry mode 0x3c, 0x00, 0x01, 0x03, // border color @@ -175,7 +176,7 @@ typedef enum { DISPLAY_IL0373, DISPLAY_SSD1680_COLSTART_0, DISPLAY_SSD1680_COLSTART_8, - DISPLAY_SSD1680_COLSTART_8_VCOM20, // FPC-7519rev.b (User ID 0xca) + DISPLAY_SSD1680_COLSTART_8_VCOM14, // FPC-7519rev.b (User ID 0xca) } display_type_t; static display_type_t detect_display_type(void) { @@ -255,7 +256,7 @@ static display_type_t detect_display_type(void) { case 0x44: return DISPLAY_SSD1680_COLSTART_8; case 0xca: - return DISPLAY_SSD1680_COLSTART_8_VCOM20; + return DISPLAY_SSD1680_COLSTART_8_VCOM14; } } @@ -304,13 +305,13 @@ void board_init(void) { } else { epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; // Default colstart is 0. - if (display_type == DISPLAY_SSD1680_COLSTART_8 || display_type == DISPLAY_SSD1680_COLSTART_8_VCOM20) { + if (display_type == DISPLAY_SSD1680_COLSTART_8 || display_type == DISPLAY_SSD1680_COLSTART_8_VCOM14) { args.colstart = 8; } args.bus = bus; - if (display_type == DISPLAY_SSD1680_COLSTART_8_VCOM20) { - args.start_sequence = ssd1680_vcom20_display_start_sequence; - args.start_sequence_len = sizeof(ssd1680_vcom20_display_start_sequence); + if (display_type == DISPLAY_SSD1680_COLSTART_8_VCOM14) { + args.start_sequence = ssd1680_vcom14_display_start_sequence; + args.start_sequence_len = sizeof(ssd1680_vcom14_display_start_sequence); } else { args.start_sequence = ssd1680_display_start_sequence; args.start_sequence_len = sizeof(ssd1680_display_start_sequence); From 7979add36a4c3afa39201410cd72cc8ed3e23f45 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 10 May 2026 10:18:02 -0400 Subject: [PATCH 479/876] fourwire_construct no reset pin must be mp_const_none, not NULL --- ports/atmel-samd/boards/ugame10/board.c | 2 +- ports/espressif/boards/elecrow_crowpanel_3.5/board.c | 4 ++-- ports/espressif/boards/espressif_esp32s3_eye/board.c | 2 +- ports/espressif/boards/hardkernel_odroid_go/board.c | 4 ++-- ports/espressif/boards/hiibot_iots2/board.c | 2 +- ports/espressif/boards/lilygo_tdeck/board.c | 2 +- ports/espressif/boards/lilygo_twatch_2020_v3/board.c | 2 +- ports/espressif/boards/lilygo_twatch_s3/board.c | 2 +- ports/espressif/boards/m5stack_core2/board.c | 2 +- ports/espressif/boards/m5stack_cores3/board.c | 2 +- ports/espressif/boards/m5stack_cores3_se/board.c | 2 +- ports/espressif/boards/sunton_esp32_2424S012/board.c | 2 +- ports/espressif/boards/sunton_esp32_2432S024C/board.c | 2 +- ports/espressif/boards/sunton_esp32_2432S028/board.c | 2 +- ports/espressif/boards/sunton_esp32_2432S032C/board.c | 2 +- ports/espressif/boards/vidi_x/board.c | 2 +- ports/nordic/boards/espruino_banglejs2/board.c | 1 - ports/nordic/boards/hiibot_bluefi/board.c | 2 +- ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c | 2 +- ports/raspberrypi/boards/heiafr_picomo_v2/board.c | 2 +- ports/raspberrypi/boards/heiafr_picomo_v3/board.c | 2 +- ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c | 2 +- 22 files changed, 23 insertions(+), 24 deletions(-) diff --git a/ports/atmel-samd/boards/ugame10/board.c b/ports/atmel-samd/boards/ugame10/board.c index 78d03a3fd9a..34f769e358f 100644 --- a/ports/atmel-samd/boards/ugame10/board.c +++ b/ports/atmel-samd/boards/ugame10/board.c @@ -55,7 +55,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(&pin_PA09), // Command or data MP_OBJ_FROM_PTR(&pin_PA08), // Chip select - MP_OBJ_NULL, // Reset + mp_const_none, // Reset 24000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/elecrow_crowpanel_3.5/board.c b/ports/espressif/boards/elecrow_crowpanel_3.5/board.c index 0748e03fce8..f52f23a9ae8 100755 --- a/ports/espressif/boards/elecrow_crowpanel_3.5/board.c +++ b/ports/espressif/boards/elecrow_crowpanel_3.5/board.c @@ -54,9 +54,9 @@ void board_init(void) { bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct(bus, spi, - MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data + MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select - NULL, // TFT_RST Reset + mp_const_none, // TFT_RST Reset 20000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/espressif_esp32s3_eye/board.c b/ports/espressif/boards/espressif_esp32s3_eye/board.c index 09a05cc72c4..43445b034e4 100644 --- a/ports/espressif/boards/espressif_esp32s3_eye/board.c +++ b/ports/espressif/boards/espressif_esp32s3_eye/board.c @@ -58,7 +58,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO43), // DC MP_OBJ_FROM_PTR(&pin_GPIO44), // CS - NULL, // no reset pin + mp_const_none, // no reset pin 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/hardkernel_odroid_go/board.c b/ports/espressif/boards/hardkernel_odroid_go/board.c index 5a8b6ccaefe..4d8f61108f6 100644 --- a/ports/espressif/boards/hardkernel_odroid_go/board.c +++ b/ports/espressif/boards/hardkernel_odroid_go/board.c @@ -52,8 +52,8 @@ void board_init(void) { common_hal_fourwire_fourwire_construct(bus, spi, MP_OBJ_FROM_PTR(&pin_GPIO21), // TFT_DC Command or data - MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select - NULL, // TFT_RST Reset + MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select + mp_const_none, // TFT_RST Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/hiibot_iots2/board.c b/ports/espressif/boards/hiibot_iots2/board.c index e4bff05822c..e3af7b45835 100644 --- a/ports/espressif/boards/hiibot_iots2/board.c +++ b/ports/espressif/boards/hiibot_iots2/board.c @@ -64,7 +64,7 @@ static void display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO35), // DC MP_OBJ_FROM_PTR(&pin_GPIO36), // CS - NULL, // NO RST ? + mp_const_none, // NO RST ? 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_tdeck/board.c b/ports/espressif/boards/lilygo_tdeck/board.c index a1008f2173f..45b889760a1 100644 --- a/ports/espressif/boards/lilygo_tdeck/board.c +++ b/ports/espressif/boards/lilygo_tdeck/board.c @@ -34,7 +34,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO11), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_GPIO12), // TFT_CS Chip select - NULL, // TFT_RST Reset + mp_const_none, // TFT_RST Reset 60000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/lilygo_twatch_2020_v3/board.c b/ports/espressif/boards/lilygo_twatch_2020_v3/board.c index e88a82ea24f..5ea85ec00c6 100644 --- a/ports/espressif/boards/lilygo_twatch_2020_v3/board.c +++ b/ports/espressif/boards/lilygo_twatch_2020_v3/board.c @@ -48,7 +48,7 @@ static void display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO27), // DC MP_OBJ_FROM_PTR(&pin_GPIO5), // CS - NULL, // RST + mp_const_none, // RST 24000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/lilygo_twatch_s3/board.c b/ports/espressif/boards/lilygo_twatch_s3/board.c index 801914a4991..a9fd3db46e7 100644 --- a/ports/espressif/boards/lilygo_twatch_s3/board.c +++ b/ports/espressif/boards/lilygo_twatch_s3/board.c @@ -110,7 +110,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO38), // DC MP_OBJ_FROM_PTR(&pin_GPIO12), // CS - NULL, // RST + mp_const_none, // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_core2/board.c b/ports/espressif/boards/m5stack_core2/board.c index 2d63436235a..2e13c06c44f 100644 --- a/ports/espressif/boards/m5stack_core2/board.c +++ b/ports/espressif/boards/m5stack_core2/board.c @@ -320,7 +320,7 @@ static bool display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO15), // DC MP_OBJ_FROM_PTR(&pin_GPIO5), // CS - MP_OBJ_NULL, // RST + mp_const_none, // RST 32000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cores3/board.c b/ports/espressif/boards/m5stack_cores3/board.c index c14be4ae0d1..629472da526 100644 --- a/ports/espressif/boards/m5stack_cores3/board.c +++ b/ports/espressif/boards/m5stack_cores3/board.c @@ -47,7 +47,7 @@ static bool display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO35), // DC MP_OBJ_FROM_PTR(&pin_GPIO3), // CS - MP_OBJ_NULL, // RST + mp_const_none, // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/m5stack_cores3_se/board.c b/ports/espressif/boards/m5stack_cores3_se/board.c index bf5ccd17f36..623fe29f98f 100644 --- a/ports/espressif/boards/m5stack_cores3_se/board.c +++ b/ports/espressif/boards/m5stack_cores3_se/board.c @@ -48,7 +48,7 @@ static bool display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO35), // DC MP_OBJ_FROM_PTR(&pin_GPIO3), // CS - NULL, // RST + mp_const_none, // RST 40000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/sunton_esp32_2424S012/board.c b/ports/espressif/boards/sunton_esp32_2424S012/board.c index 731694a4e1b..4e56bee7d8b 100644 --- a/ports/espressif/boards/sunton_esp32_2424S012/board.c +++ b/ports/espressif/boards/sunton_esp32_2424S012/board.c @@ -107,7 +107,7 @@ static void display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO2), // DC MP_OBJ_FROM_PTR(&pin_GPIO10), // CS - MP_OBJ_NULL, // RST + mp_const_none, // RST 80000000, // baudrate 0, // polarity 0 // phase diff --git a/ports/espressif/boards/sunton_esp32_2432S024C/board.c b/ports/espressif/boards/sunton_esp32_2432S024C/board.c index de7504a8715..d50f19f9972 100644 --- a/ports/espressif/boards/sunton_esp32_2432S024C/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S024C/board.c @@ -53,7 +53,7 @@ static void display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select - MP_OBJ_NULL, // TFT_RST Reset + mp_const_none, // TFT_RST Reset 6000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/sunton_esp32_2432S028/board.c b/ports/espressif/boards/sunton_esp32_2432S028/board.c index 214e3b13e15..6cd4a080c99 100644 --- a/ports/espressif/boards/sunton_esp32_2432S028/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S028/board.c @@ -53,7 +53,7 @@ static void display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS Chip select - MP_OBJ_NULL, // TFT_RST Reset + mp_const_none, // TFT_RST Reset 6000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/espressif/boards/sunton_esp32_2432S032C/board.c b/ports/espressif/boards/sunton_esp32_2432S032C/board.c index 48e206040d8..db621cfe8c9 100644 --- a/ports/espressif/boards/sunton_esp32_2432S032C/board.c +++ b/ports/espressif/boards/sunton_esp32_2432S032C/board.c @@ -45,7 +45,7 @@ static void display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO2), // TFT_DC MP_OBJ_FROM_PTR(&pin_GPIO15), // TFT_CS - MP_OBJ_NULL, // TFT_RST + mp_const_none, // TFT_RST 26600000, // Baudrate 0, // Polarity 0 // Phase diff --git a/ports/espressif/boards/vidi_x/board.c b/ports/espressif/boards/vidi_x/board.c index 7ba7094b917..a9e267e8f0e 100644 --- a/ports/espressif/boards/vidi_x/board.c +++ b/ports/espressif/boards/vidi_x/board.c @@ -53,7 +53,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO21), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_GPIO5), // TFT_CS Chip select - MP_OBJ_NULL, // TFT_RST Reset + mp_const_none, // TFT_RST Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/nordic/boards/espruino_banglejs2/board.c b/ports/nordic/boards/espruino_banglejs2/board.c index 16af0269168..09adb43f8be 100644 --- a/ports/nordic/boards/espruino_banglejs2/board.c +++ b/ports/nordic/boards/espruino_banglejs2/board.c @@ -9,7 +9,6 @@ #include "mpconfigboard.h" #include "shared-bindings/busio/SPI.h" -#include "shared-bindings/fourwire/FourWire.h" #include "shared-bindings/framebufferio/FramebufferDisplay.h" #include "shared-bindings/sharpdisplay/SharpMemoryFramebuffer.h" #include "shared-module/displayio/__init__.h" diff --git a/ports/nordic/boards/hiibot_bluefi/board.c b/ports/nordic/boards/hiibot_bluefi/board.c index 7a681140ddb..a05be7a0a63 100644 --- a/ports/nordic/boards/hiibot_bluefi/board.c +++ b/ports/nordic/boards/hiibot_bluefi/board.c @@ -36,7 +36,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(&pin_P0_27), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_P0_05), // TFT_CS Chip select - MP_OBJ_NULL, // no TFT_RST Reset + mp_const_none, // no TFT_RST Reset // &pin_P1_14, // TFT_RST Reset 60000000, // Baudrate 0, // Polarity diff --git a/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c b/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c index 882bc9a1a9e..903ed6a9044 100644 --- a/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c +++ b/ports/raspberrypi/boards/adafruit_floppsy_rp2040/board.c @@ -36,7 +36,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_DC), MP_OBJ_FROM_PTR(CIRCUITPY_BOARD_TFT_CS), - MP_OBJ_NULL, // TFT_RESET Reset + mp_const_none, // TFT_RESET Reset 40000000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/heiafr_picomo_v2/board.c b/ports/raspberrypi/boards/heiafr_picomo_v2/board.c index 3824c5959f5..15324b40ecd 100644 --- a/ports/raspberrypi/boards/heiafr_picomo_v2/board.c +++ b/ports/raspberrypi/boards/heiafr_picomo_v2/board.c @@ -53,7 +53,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO16), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_GPIO17), // TFT_CS Chip select - MP_OBJ_NULL, // TFT_RST Reset + mp_const_none, // TFT_RST Reset 62500000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/heiafr_picomo_v3/board.c b/ports/raspberrypi/boards/heiafr_picomo_v3/board.c index 3824c5959f5..15324b40ecd 100644 --- a/ports/raspberrypi/boards/heiafr_picomo_v3/board.c +++ b/ports/raspberrypi/boards/heiafr_picomo_v3/board.c @@ -53,7 +53,7 @@ void board_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO16), // TFT_DC Command or data MP_OBJ_FROM_PTR(&pin_GPIO17), // TFT_CS Chip select - MP_OBJ_NULL, // TFT_RST Reset + mp_const_none, // TFT_RST Reset 62500000, // Baudrate 0, // Polarity 0); // Phase diff --git a/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c b/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c index 67e63daed1d..2e9ccd45d56 100644 --- a/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c +++ b/ports/raspberrypi/boards/lilygo_t_display_rp2040/board.c @@ -65,7 +65,7 @@ static void display_init(void) { spi, MP_OBJ_FROM_PTR(&pin_GPIO1), // DC MP_OBJ_FROM_PTR(&pin_GPIO5), // CS - MP_OBJ_NULL, // RST (Reset pin tie to 0, do not set here) + mp_const_none, // RST (Reset pin tie to 0, do not set here) 40000000, // baudrate 1, // polarity 0 // phase From fea7505206f4b825be7666e1a262dfb13eb847c5 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 10 May 2026 22:11:11 -0400 Subject: [PATCH 480/876] supervisor/shared/usb/usb_msc_flash.c: support CIRCUITPY_SDCARD_USB in settings.toml Document CIRCUITPY_SDCARD_USB and rework settings.toml documentation --- docs/environment.rst | 124 +++++++++++++++----------- supervisor/shared/usb/usb_msc_flash.c | 34 +++++-- 2 files changed, 101 insertions(+), 57 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index 36404eb81f9..a94154dfc13 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -1,65 +1,77 @@ Environment Variables ===================== -CircuitPython 8.0.0 introduces support for environment variables. Environment -variables are commonly used to store "secrets" such as Wi-Fi passwords and API -keys. This method *does not* make them secure. It only separates them from the -code. +CircuitPython provides support for environment variables. These values +can be examined by user code, and are also used as settings by CircuitPython during startup. -CircuitPython uses a file called ``settings.toml`` at the drive root (no -folder) as the environment. User code can access the values from the file -using `os.getenv()`. It is recommended to save any values used repeatedly in a -variable because `os.getenv()` will parse the ``settings.toml`` file contents -on every access. +CircuitPython looks for a file called ``settings.toml`` at the ``CIRCUITPY`` drive root +to find the values of environment variables, +The file format is a subset of the `TOML config file language `__. -CircuitPython only supports a subset of the full toml specification, see below -for more details. The subset is very "Python-like", which is a key reason we -selected the format. +User code can access the values from the file using either `os.getenv()` or `supervisor.get_setting()` +The value returned by `os.getenv()` is always a string, but `supervisor.get_setting()` +will parse a value into a Python object: a string, an integer, a float, or a boolean. -Due to technical limitations it probably also accepts some files that are -not valid TOML files; bugs of this nature are subject to change (i.e., be -fixed) without the usual deprecation period for incompatible changes. +Both `os.getenv()` and `supervisor.get_setting()` +read and parse the ``settings.toml`` file on every access. +It will save time to copy any values you use repeatedly into variables. -File format example: +Environment variables are sometimes used to store "secrets" such as Wi-Fi passwords and API +keys. The ``settings.toml`` file *does not* make the secrets secure. It only separates them from the +code. -.. code-block:: +CircuitPython supports onlya subset of the full TOML specification; see below for more details. +The subset is very "Python-like", which is a key reason the format was selected. +To make the code simpler, the implementation accepts some files that are +not valid TOML, but do not depend on this. - str_key="Hello world" # with trailing comment - int_key = 7 - unicode_key="œuvre" - unicode_key2="\\u0153uvre" # same as above - unicode_key3="\\U00000153uvre" # same as above - escape_codes="supported, including \\r\\n\\"\\\\" - # comment - [subtable] - subvalue="cannot retrieve this using getenv" +The full TOML specification provides for tables labeled with table names in brackets, like +``[table_name]``. +CircuitPython does not support this and ignores any explicit inline TOML tables. +Here is an example ``settings.toml`` file. +Entries consist of a key and value, separated by an ``=`` sign. +Upper and lower case may both be used in the key name. -Details of the toml language subset +.. code-block:: + + # Comment. + CIRCUITPY_WIFI_PASSWORD = "mypassword" + GREETING="Hello world" # trailing comments are ok + REPEAT_COUNT = 7 # an integer + CIRCUITPY_SDCARD_USB = false # a boolean + delay = 0.75 # a float + FRENCH="œuvre" # unicode can be used + FRENCH2="\\u0153uvre" # same unicode string, using a 16-bit escape code + FRENCH3="\\U00000153uvre" # same unicode string, using a 32-bit escape code + STRING_WITH_ESCAPE_CODES="supported, including \\r\\n\\"\\\\" + +Details of the TOML language subset ----------------------------------- -* The content is required to be in UTF-8 encoding -* The supported data types are string and integer -* Only basic strings are supported, not triple-quoted strings -* Only integers supported by strtol. (no 0o, no 0b, no underscores 1_000, 011 - is 9, not 11) -* Only bare keys are supported +* The content must be in UTF-8 encoding +* The supported data types are strings, integers, floats, and booleans. +* Whitespace is allowed. +* Only basic strings are supported, not triple-quoted strings. +* Only integers supported by ``strtol()`` can be parsed: + no ``0o``, no ``0b``, no underscores ``1_000``, ``011`` is 9, not 11. +* Only bare keys are supported. * Duplicate keys are not diagnosed. -* Comments are supported -* Only values from the "root table" can be retrieved -* due to technical limitations, the content of multi-line - strings can erroneously be parsed as a value. +* Comments are allowed. +* Only values from the "root table" can be retrieved. + CircuitPython behavior ---------------------- -CircuitPython will also read the environment to configure its behavior. Some keys are read at -startup once and others are read on reload (ctrl-D in the REPL). If a reload doesn't change things, -then try a reset (a power cycle or pressing the reset button). Other keys are ignored by CircuitPython. -Here are the keys it uses: +On startup, CircuitPython looks for for certain key/value pairs to use as configuration values. +Some values are read only once, after a hard reset, and others are read on each reload (ctrl-D in the REPL). +If you edit ``settings.toml`` and a reload doesn't read your changes, +then try a hard reset (a power cycle or pressing the reset button). +You can also include any other key/value pairs in the file for use with your own code. -Core CircuitPython keys -^^^^^^^^^^^^^^^^^^^^^^^ +Keys that affect CircuitPython behavior +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CIRCUITPY_BLE_NAME ~~~~~~~~~~~~~~~~~~ @@ -83,24 +95,36 @@ Used to avoid "Pystack exhausted" errors when the code can't be reworked to avoi CIRCUITPY_WEB_API_PASSWORD ~~~~~~~~~~~~~~~~~~~~~~~~~~ Password required to make modifications to the board from the Web Workflow. +If the password is not specified, the Web Workflow is not enabled. CIRCUITPY_WEB_API_PORT ~~~~~~~~~~~~~~~~~~~~~~ -TCP port number used for the web HTTP API. Defaults to 80 when omitted. +TCP port number used for the Web Workflow HTTP API. Defaults to 80 when omitted. CIRCUITPY_WEB_INSTANCE_NAME ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Name the board advertises as for the WEB workflow. Defaults to human readable board name if omitted. +Hostname the board advertises as, using mDNS, for the Web Workflow. +Defaults to a semi-unique name if omitted. +CIRCUITPY_WIFI_SSID +~~~~~~~~~~~~~~~~~~~ CIRCUITPY_WIFI_PASSWORD ~~~~~~~~~~~~~~~~~~~~~~~ -Wi-Fi password used to auto connect to CIRCUITPY_WIFI_SSID. +If these values are specified, +CircuitPython will connect automatically to a local WiFi network using the supplied SSID +and password before ``boot.py`` and/or ``code.py`` are run. + +CIRCUITPY_SDCARD_USB +^^^^^^^^^^^^^^^^^^^^ +Present a mounted SD card as a USB MSC device. If the board has default pins for an SD card socket, +the card is mounted automatically on startup. +Only one card can be presented. +Defaults to ``true``. +SD card presentation can slow down board startup, +so set this to ``false`` if you don't need this feature. -CIRCUITPY_WIFI_SSID -~~~~~~~~~~~~~~~~~~~ -Wi-Fi SSID to auto-connect to even if user code is not running. -Additional board specific keys +Additional board-specific keys ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ CIRCUITPY_DISPLAY_WIDTH (Sunton, MaTouch) diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index 27277bc5ac5..478d959f8f6 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -18,6 +18,7 @@ #include "shared-module/storage/__init__.h" #include "supervisor/filesystem.h" #include "supervisor/shared/reload.h" +#include "supervisor/shared/settings.h" #define MSC_FLASH_BLOCK_SIZE 512 @@ -365,6 +366,26 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 memcpy(product_rev, CFG_TUD_MSC_PRODUCT_REV, strlen(CFG_TUD_MSC_PRODUCT_REV)); } +#ifdef SDCARD_LUN +typedef enum { + SDCARD_USB_SETTING_NOT_YET_READ = 0, + SDCARD_USB_SETTING_TRUE, + SDCARD_USB_SETTING_FALSE, +} sdcard_usb_setting_state_t; + +static sdcard_usb_setting_state_t _sdcard_usb_setting_state = SDCARD_USB_SETTING_NOT_YET_READ; + +// Read only once to save file access time. +static bool sdcard_usb_enabled(void) { + if (_sdcard_usb_setting_state == SDCARD_USB_SETTING_NOT_YET_READ) { + bool setting = true; + (void)settings_get_bool("CIRCUITPY_SDCARD_USB", &setting); + _sdcard_usb_setting_state = setting ? SDCARD_USB_SETTING_TRUE : SDCARD_USB_SETTING_FALSE; + } + return _sdcard_usb_setting_state == SDCARD_USB_SETTING_TRUE; +} +#endif + // Invoked when received Test Unit Ready command. // return true allowing host to read/write this LUN e.g SD card inserted bool tud_msc_test_unit_ready_cb(uint8_t lun) { @@ -372,17 +393,16 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { return false; } - #ifdef SDCARD_LUN - if (lun == SDCARD_LUN) { - automount_sd_card(); - } - #endif - fs_user_mount_t *current_mount = get_vfs(lun); if (current_mount == NULL) { return false; } - if (ejected[lun] || eject_once[lun]) { + + if (ejected[lun] || eject_once[lun] + #ifdef SDCARD_LUN + || (lun == SDCARD_LUN && !sdcard_usb_enabled()) + #endif + ) { eject_once[lun] = false; // Set 0x3a for media not present. tud_msc_set_sense(lun, SCSI_SENSE_NOT_READY, 0x3A, 0x00); From d1fd820a848590dd0bc8fc6b7db7adeb1f5f953a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 11 May 2026 13:38:13 -0400 Subject: [PATCH 481/876] Update docs/environment.rst Co-authored-by: Scott Shawcroft --- docs/environment.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/environment.rst b/docs/environment.rst index a94154dfc13..ed32cfe89dc 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -20,7 +20,7 @@ Environment variables are sometimes used to store "secrets" such as Wi-Fi passwo keys. The ``settings.toml`` file *does not* make the secrets secure. It only separates them from the code. -CircuitPython supports onlya subset of the full TOML specification; see below for more details. +CircuitPython supports only a subset of the full TOML specification; see below for more details. The subset is very "Python-like", which is a key reason the format was selected. To make the code simpler, the implementation accepts some files that are not valid TOML, but do not depend on this. From b085a9727ea533e55d5a99f14d5de2eafb3626aa Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 11 May 2026 17:53:40 -0400 Subject: [PATCH 482/876] handle boards that support sdcardio but don't support settings.toml --- supervisor/shared/usb/usb_msc_flash.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index 478d959f8f6..6f15b508095 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -367,6 +367,7 @@ void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16 } #ifdef SDCARD_LUN +#if CIRCUITPY_SETTINGS_TOML typedef enum { SDCARD_USB_SETTING_NOT_YET_READ = 0, SDCARD_USB_SETTING_TRUE, @@ -384,6 +385,11 @@ static bool sdcard_usb_enabled(void) { } return _sdcard_usb_setting_state == SDCARD_USB_SETTING_TRUE; } +#else +static bool sdcard_usb_enabled(void) { + return CIRCUITPY_SDCARD_USB; +} +#endif #endif // Invoked when received Test Unit Ready command. From 718597b124d12da4bcc35f056d63da6333ac5a06 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 11 May 2026 18:44:16 -0400 Subject: [PATCH 483/876] update frozen libraries --- frozen/Adafruit_CircuitPython_AHTx0 | 2 +- frozen/Adafruit_CircuitPython_APDS9960 | 2 +- frozen/Adafruit_CircuitPython_BLE | 2 +- frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center | 2 +- frozen/Adafruit_CircuitPython_Bitmap_Font | 2 +- frozen/Adafruit_CircuitPython_BusDevice | 2 +- frozen/Adafruit_CircuitPython_CircuitPlayground | 2 +- frozen/Adafruit_CircuitPython_ConnectionManager | 2 +- frozen/Adafruit_CircuitPython_Crickit | 2 +- frozen/Adafruit_CircuitPython_DRV2605 | 2 +- frozen/Adafruit_CircuitPython_DS3231 | 2 +- frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 | 2 +- frozen/Adafruit_CircuitPython_Display_Shapes | 2 +- frozen/Adafruit_CircuitPython_Display_Text | 2 +- frozen/Adafruit_CircuitPython_DotStar | 2 +- frozen/Adafruit_CircuitPython_ESP32SPI | 2 +- frozen/Adafruit_CircuitPython_FakeRequests | 2 +- frozen/Adafruit_CircuitPython_FocalTouch | 2 +- frozen/Adafruit_CircuitPython_HID | 2 +- frozen/Adafruit_CircuitPython_HTTPServer | 2 +- frozen/Adafruit_CircuitPython_IRRemote | 2 +- frozen/Adafruit_CircuitPython_IS31FL3731 | 2 +- frozen/Adafruit_CircuitPython_ImageLoad | 2 +- frozen/Adafruit_CircuitPython_LC709203F | 2 +- frozen/Adafruit_CircuitPython_LED_Animation | 2 +- frozen/Adafruit_CircuitPython_LIS3DH | 2 +- frozen/Adafruit_CircuitPython_LSM6DS | 2 +- frozen/Adafruit_CircuitPython_MIDI | 2 +- frozen/Adafruit_CircuitPython_MPU6050 | 2 +- frozen/Adafruit_CircuitPython_Motor | 2 +- frozen/Adafruit_CircuitPython_NeoPixel | 2 +- frozen/Adafruit_CircuitPython_OPT4048 | 2 +- frozen/Adafruit_CircuitPython_PCF8563 | 2 +- frozen/Adafruit_CircuitPython_Pixel_Framebuf | 2 +- frozen/Adafruit_CircuitPython_PortalBase | 2 +- frozen/Adafruit_CircuitPython_ProgressBar | 2 +- frozen/Adafruit_CircuitPython_RFM69 | 2 +- frozen/Adafruit_CircuitPython_RFM9x | 2 +- frozen/Adafruit_CircuitPython_Register | 2 +- frozen/Adafruit_CircuitPython_Requests | 2 +- frozen/Adafruit_CircuitPython_SD | 2 +- frozen/Adafruit_CircuitPython_SHT4x | 2 +- frozen/Adafruit_CircuitPython_SSD1306 | 2 +- frozen/Adafruit_CircuitPython_SSD1680 | 2 +- frozen/Adafruit_CircuitPython_ST7789 | 2 +- frozen/Adafruit_CircuitPython_SimpleIO | 2 +- frozen/Adafruit_CircuitPython_SimpleMath | 2 +- frozen/Adafruit_CircuitPython_Thermistor | 2 +- frozen/Adafruit_CircuitPython_Ticks | 2 +- frozen/Adafruit_CircuitPython_UC8151D | 2 +- frozen/Adafruit_CircuitPython_Wave | 2 +- frozen/Adafruit_CircuitPython_Wiznet5k | 2 +- frozen/Adafruit_CircuitPython_framebuf | 2 +- frozen/Adafruit_CircuitPython_seesaw | 2 +- 54 files changed, 54 insertions(+), 54 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_AHTx0 b/frozen/Adafruit_CircuitPython_AHTx0 index 043c7163c1d..3dd249f5695 160000 --- a/frozen/Adafruit_CircuitPython_AHTx0 +++ b/frozen/Adafruit_CircuitPython_AHTx0 @@ -1 +1 @@ -Subproject commit 043c7163c1d66a9d3ef2150e6140f92af973c9b1 +Subproject commit 3dd249f56957d1927dee6e6e31742039c6699cef diff --git a/frozen/Adafruit_CircuitPython_APDS9960 b/frozen/Adafruit_CircuitPython_APDS9960 index 0134a126af8..75a7b1abef0 160000 --- a/frozen/Adafruit_CircuitPython_APDS9960 +++ b/frozen/Adafruit_CircuitPython_APDS9960 @@ -1 +1 @@ -Subproject commit 0134a126af8430126c9a569a29958802716262fc +Subproject commit 75a7b1abef02342a7cdead30271ce168243bf1fa diff --git a/frozen/Adafruit_CircuitPython_BLE b/frozen/Adafruit_CircuitPython_BLE index 63c9af9a343..82ada04a0f4 160000 --- a/frozen/Adafruit_CircuitPython_BLE +++ b/frozen/Adafruit_CircuitPython_BLE @@ -1 +1 @@ -Subproject commit 63c9af9a343c68ebbd013054b799d2e35a513343 +Subproject commit 82ada04a0f4019de00d103256621f73b80151a0d diff --git a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center index a636fc984dc..7c081325944 160000 --- a/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center +++ b/frozen/Adafruit_CircuitPython_BLE_Apple_Notification_Center @@ -1 +1 @@ -Subproject commit a636fc984dced58f5f0815c5c531a03ee092f7ad +Subproject commit 7c08132594453a021812f45e86a2972d6945672e diff --git a/frozen/Adafruit_CircuitPython_Bitmap_Font b/frozen/Adafruit_CircuitPython_Bitmap_Font index 2b320bb2649..fe0cdfd5501 160000 --- a/frozen/Adafruit_CircuitPython_Bitmap_Font +++ b/frozen/Adafruit_CircuitPython_Bitmap_Font @@ -1 +1 @@ -Subproject commit 2b320bb26492b84d3ddabb2cd712d8db41a8b983 +Subproject commit fe0cdfd5501070f5ca47b3e66dfd15e62c54011e diff --git a/frozen/Adafruit_CircuitPython_BusDevice b/frozen/Adafruit_CircuitPython_BusDevice index d4b283c85b7..686728c7b11 160000 --- a/frozen/Adafruit_CircuitPython_BusDevice +++ b/frozen/Adafruit_CircuitPython_BusDevice @@ -1 +1 @@ -Subproject commit d4b283c85b7b2043eb0d095638a47305a1f4ef61 +Subproject commit 686728c7b11eb0b7ffb62691b68ccead413e7cc5 diff --git a/frozen/Adafruit_CircuitPython_CircuitPlayground b/frozen/Adafruit_CircuitPython_CircuitPlayground index 2ee9b7ddd9d..852e7206e5e 160000 --- a/frozen/Adafruit_CircuitPython_CircuitPlayground +++ b/frozen/Adafruit_CircuitPython_CircuitPlayground @@ -1 +1 @@ -Subproject commit 2ee9b7ddd9d8574f1a154c67b5c849d2e44e3435 +Subproject commit 852e7206e5ed26ec3929a25bc8331b0951fee20e diff --git a/frozen/Adafruit_CircuitPython_ConnectionManager b/frozen/Adafruit_CircuitPython_ConnectionManager index 89e59ec81bd..69542345f3d 160000 --- a/frozen/Adafruit_CircuitPython_ConnectionManager +++ b/frozen/Adafruit_CircuitPython_ConnectionManager @@ -1 +1 @@ -Subproject commit 89e59ec81bdfa7349b08ba3adf0d3cefc57af4d2 +Subproject commit 69542345f3dc6f9060eb5d78d5dcd4e636bf66b9 diff --git a/frozen/Adafruit_CircuitPython_Crickit b/frozen/Adafruit_CircuitPython_Crickit index e3c372fecf7..aa213ba6f89 160000 --- a/frozen/Adafruit_CircuitPython_Crickit +++ b/frozen/Adafruit_CircuitPython_Crickit @@ -1 +1 @@ -Subproject commit e3c372fecf7209320826009de88818d91809cff6 +Subproject commit aa213ba6f897cdeb45ce4e961f44f862e3832c03 diff --git a/frozen/Adafruit_CircuitPython_DRV2605 b/frozen/Adafruit_CircuitPython_DRV2605 index 18b7397ec21..2b8443ff94a 160000 --- a/frozen/Adafruit_CircuitPython_DRV2605 +++ b/frozen/Adafruit_CircuitPython_DRV2605 @@ -1 +1 @@ -Subproject commit 18b7397ec21235fc398625a52f995a3be31eb59a +Subproject commit 2b8443ff94a179a027efd9f62d905c398f4f7b43 diff --git a/frozen/Adafruit_CircuitPython_DS3231 b/frozen/Adafruit_CircuitPython_DS3231 index 552104c8aed..5dc331cd999 160000 --- a/frozen/Adafruit_CircuitPython_DS3231 +++ b/frozen/Adafruit_CircuitPython_DS3231 @@ -1 +1 @@ -Subproject commit 552104c8aed472c7437413e94b8954e63b4a4d4d +Subproject commit 5dc331cd99930dd209c63f77256764c2b41016f2 diff --git a/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 b/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 index 8c7acd451ad..45520b642df 160000 --- a/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 +++ b/frozen/Adafruit_CircuitPython_DisplayIO_SSD1306 @@ -1 +1 @@ -Subproject commit 8c7acd451ad53f7dc3b33a704c885032a03c1064 +Subproject commit 45520b642df77b1718befb24e5e6853b1172792f diff --git a/frozen/Adafruit_CircuitPython_Display_Shapes b/frozen/Adafruit_CircuitPython_Display_Shapes index bf6c2addf24..7f0466c1d3a 160000 --- a/frozen/Adafruit_CircuitPython_Display_Shapes +++ b/frozen/Adafruit_CircuitPython_Display_Shapes @@ -1 +1 @@ -Subproject commit bf6c2addf2465625de747d2f4ea1613fcded7840 +Subproject commit 7f0466c1d3ac344bb8ef282d09c5eb8c1a521d72 diff --git a/frozen/Adafruit_CircuitPython_Display_Text b/frozen/Adafruit_CircuitPython_Display_Text index 6450c7a3dc4..eae352b0970 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit 6450c7a3dc4c16c4af4b75eda549537dffb5a73c +Subproject commit eae352b09700e57b78507aace7ff682cb1beff5a diff --git a/frozen/Adafruit_CircuitPython_DotStar b/frozen/Adafruit_CircuitPython_DotStar index a12e2ce2046..d08e231d5f9 160000 --- a/frozen/Adafruit_CircuitPython_DotStar +++ b/frozen/Adafruit_CircuitPython_DotStar @@ -1 +1 @@ -Subproject commit a12e2ce2046afc1791ca6aa2bdeb33cb97f7def0 +Subproject commit d08e231d5f95566a09f2a0c08cb647703882262d diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index ec1d2e66ace..b0e2124a175 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit ec1d2e66ace176c13d7128a839287601a97a6bda +Subproject commit b0e2124a175f421bb07ac5cc72b81f6209966a3b diff --git a/frozen/Adafruit_CircuitPython_FakeRequests b/frozen/Adafruit_CircuitPython_FakeRequests index f9f9d061a66..130a3d7fcfb 160000 --- a/frozen/Adafruit_CircuitPython_FakeRequests +++ b/frozen/Adafruit_CircuitPython_FakeRequests @@ -1 +1 @@ -Subproject commit f9f9d061a66453e0d3164ffd4e046ed3b6007669 +Subproject commit 130a3d7fcfbba67bb86232f22ca08ba862873947 diff --git a/frozen/Adafruit_CircuitPython_FocalTouch b/frozen/Adafruit_CircuitPython_FocalTouch index e18ecd678ec..2070d7853cd 160000 --- a/frozen/Adafruit_CircuitPython_FocalTouch +++ b/frozen/Adafruit_CircuitPython_FocalTouch @@ -1 +1 @@ -Subproject commit e18ecd678ec3ac4fef884db18ddb2aab56bf44f9 +Subproject commit 2070d7853cd1fe81381e02f4bc0af1bb145cb69e diff --git a/frozen/Adafruit_CircuitPython_HID b/frozen/Adafruit_CircuitPython_HID index a147d3b5b97..693baa60eb6 160000 --- a/frozen/Adafruit_CircuitPython_HID +++ b/frozen/Adafruit_CircuitPython_HID @@ -1 +1 @@ -Subproject commit a147d3b5b976371601b460622209d327f51eb681 +Subproject commit 693baa60eb684bb53379d98c6a036f56b8010666 diff --git a/frozen/Adafruit_CircuitPython_HTTPServer b/frozen/Adafruit_CircuitPython_HTTPServer index d55c6f54aba..c1d964fe7bf 160000 --- a/frozen/Adafruit_CircuitPython_HTTPServer +++ b/frozen/Adafruit_CircuitPython_HTTPServer @@ -1 +1 @@ -Subproject commit d55c6f54aba54df9b0e0b9d83ddf7fca46eea5e4 +Subproject commit c1d964fe7bf8734f7a858e798583d0f1304ae1c1 diff --git a/frozen/Adafruit_CircuitPython_IRRemote b/frozen/Adafruit_CircuitPython_IRRemote index 646cc051881..bb14c81e07a 160000 --- a/frozen/Adafruit_CircuitPython_IRRemote +++ b/frozen/Adafruit_CircuitPython_IRRemote @@ -1 +1 @@ -Subproject commit 646cc051881a07d8bd5c442320479c6e5e553567 +Subproject commit bb14c81e07aa798b36a53923059b5ab8a914915b diff --git a/frozen/Adafruit_CircuitPython_IS31FL3731 b/frozen/Adafruit_CircuitPython_IS31FL3731 index c011e8e0d02..3becc08e451 160000 --- a/frozen/Adafruit_CircuitPython_IS31FL3731 +++ b/frozen/Adafruit_CircuitPython_IS31FL3731 @@ -1 +1 @@ -Subproject commit c011e8e0d021a6c5870242eb721f012922002fc8 +Subproject commit 3becc08e451eeb2b6678a3d17547f5b0922e4660 diff --git a/frozen/Adafruit_CircuitPython_ImageLoad b/frozen/Adafruit_CircuitPython_ImageLoad index 458bc46b63e..3bc5c15c707 160000 --- a/frozen/Adafruit_CircuitPython_ImageLoad +++ b/frozen/Adafruit_CircuitPython_ImageLoad @@ -1 +1 @@ -Subproject commit 458bc46b63ea2bfc51529b05b62b4df3c5902e17 +Subproject commit 3bc5c15c7079e076b49f9929bb956de8812c62f8 diff --git a/frozen/Adafruit_CircuitPython_LC709203F b/frozen/Adafruit_CircuitPython_LC709203F index e32e39a18d2..bcbb0cfead8 160000 --- a/frozen/Adafruit_CircuitPython_LC709203F +++ b/frozen/Adafruit_CircuitPython_LC709203F @@ -1 +1 @@ -Subproject commit e32e39a18d23ae58fe97b3472253b6cbcbc8ebd0 +Subproject commit bcbb0cfead8650a61357a167bc47058f05fba159 diff --git a/frozen/Adafruit_CircuitPython_LED_Animation b/frozen/Adafruit_CircuitPython_LED_Animation index 7cc736df162..38a3c7844b4 160000 --- a/frozen/Adafruit_CircuitPython_LED_Animation +++ b/frozen/Adafruit_CircuitPython_LED_Animation @@ -1 +1 @@ -Subproject commit 7cc736df1628f767c4fc6f23287cedbf6e80f4ce +Subproject commit 38a3c7844b4c59235fac46ee01e20caf872dad43 diff --git a/frozen/Adafruit_CircuitPython_LIS3DH b/frozen/Adafruit_CircuitPython_LIS3DH index ca871b8bc59..cd40b482a09 160000 --- a/frozen/Adafruit_CircuitPython_LIS3DH +++ b/frozen/Adafruit_CircuitPython_LIS3DH @@ -1 +1 @@ -Subproject commit ca871b8bc59b23acbfd779bf59d420599e8bcbb5 +Subproject commit cd40b482a098a62ecce1b4c62a1f1930be984e16 diff --git a/frozen/Adafruit_CircuitPython_LSM6DS b/frozen/Adafruit_CircuitPython_LSM6DS index 9d94dc6a335..cdfc14a687a 160000 --- a/frozen/Adafruit_CircuitPython_LSM6DS +++ b/frozen/Adafruit_CircuitPython_LSM6DS @@ -1 +1 @@ -Subproject commit 9d94dc6a3350cb8766baa4a1247e36576b00f68a +Subproject commit cdfc14a687a138aa0f2c6abab061bfc1bfafa561 diff --git a/frozen/Adafruit_CircuitPython_MIDI b/frozen/Adafruit_CircuitPython_MIDI index 5feb31fbd31..6f5d6812474 160000 --- a/frozen/Adafruit_CircuitPython_MIDI +++ b/frozen/Adafruit_CircuitPython_MIDI @@ -1 +1 @@ -Subproject commit 5feb31fbd31f2475862e0cb55c89359cb688ad34 +Subproject commit 6f5d6812474a0460e9418278ea7da1e2269d2c0d diff --git a/frozen/Adafruit_CircuitPython_MPU6050 b/frozen/Adafruit_CircuitPython_MPU6050 index d3761591ccf..928d747a826 160000 --- a/frozen/Adafruit_CircuitPython_MPU6050 +++ b/frozen/Adafruit_CircuitPython_MPU6050 @@ -1 +1 @@ -Subproject commit d3761591ccf7629b39675dd1db45184b96a3b779 +Subproject commit 928d747a826fc8d8c4237ed1b40b53cf723cf1ee diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index f55b2910b01..20ebf51fe0d 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit f55b2910b01094904461d769581221c20418a267 +Subproject commit 20ebf51fe0d2bb48b1780c3c9bd74c16c73bc02e diff --git a/frozen/Adafruit_CircuitPython_NeoPixel b/frozen/Adafruit_CircuitPython_NeoPixel index d3eaf5c45dd..aa82c0724cc 160000 --- a/frozen/Adafruit_CircuitPython_NeoPixel +++ b/frozen/Adafruit_CircuitPython_NeoPixel @@ -1 +1 @@ -Subproject commit d3eaf5c45dde45588f9a2eb2ffbe0b9025251bee +Subproject commit aa82c0724ccb68fbd94605c9f4f09b19c5d2919d diff --git a/frozen/Adafruit_CircuitPython_OPT4048 b/frozen/Adafruit_CircuitPython_OPT4048 index ddfe6b13ace..97e63d8cd24 160000 --- a/frozen/Adafruit_CircuitPython_OPT4048 +++ b/frozen/Adafruit_CircuitPython_OPT4048 @@ -1 +1 @@ -Subproject commit ddfe6b13acef7076333ee8e0ecd27bc4186512b9 +Subproject commit 97e63d8cd2425248c0aee323c3d8a6422404eaa5 diff --git a/frozen/Adafruit_CircuitPython_PCF8563 b/frozen/Adafruit_CircuitPython_PCF8563 index 16e3112885b..c4ca8d355b7 160000 --- a/frozen/Adafruit_CircuitPython_PCF8563 +++ b/frozen/Adafruit_CircuitPython_PCF8563 @@ -1 +1 @@ -Subproject commit 16e3112885b0b6149b4dfa1749181424dd5da122 +Subproject commit c4ca8d355b79179b44716544577925442a801bc0 diff --git a/frozen/Adafruit_CircuitPython_Pixel_Framebuf b/frozen/Adafruit_CircuitPython_Pixel_Framebuf index 555b30acf78..ffd3e8a6926 160000 --- a/frozen/Adafruit_CircuitPython_Pixel_Framebuf +++ b/frozen/Adafruit_CircuitPython_Pixel_Framebuf @@ -1 +1 @@ -Subproject commit 555b30acf78ba65cec48f64b3350e19fddada4ce +Subproject commit ffd3e8a692676d076a2fa3f725e3a8ea63441139 diff --git a/frozen/Adafruit_CircuitPython_PortalBase b/frozen/Adafruit_CircuitPython_PortalBase index b67904c7bca..fc4aeea36ae 160000 --- a/frozen/Adafruit_CircuitPython_PortalBase +++ b/frozen/Adafruit_CircuitPython_PortalBase @@ -1 +1 @@ -Subproject commit b67904c7bca12d7ee443e16bc40d64fd67c7cb48 +Subproject commit fc4aeea36ae462463eb1317b66e0f772c439b28a diff --git a/frozen/Adafruit_CircuitPython_ProgressBar b/frozen/Adafruit_CircuitPython_ProgressBar index fab168ab38f..e720f6ff61a 160000 --- a/frozen/Adafruit_CircuitPython_ProgressBar +++ b/frozen/Adafruit_CircuitPython_ProgressBar @@ -1 +1 @@ -Subproject commit fab168ab38f61f654735140c67c7defdad512de8 +Subproject commit e720f6ff61aa41485a5611d8df3f7fa25fe8fb79 diff --git a/frozen/Adafruit_CircuitPython_RFM69 b/frozen/Adafruit_CircuitPython_RFM69 index 1837cb10b35..2f8a38c3cae 160000 --- a/frozen/Adafruit_CircuitPython_RFM69 +++ b/frozen/Adafruit_CircuitPython_RFM69 @@ -1 +1 @@ -Subproject commit 1837cb10b353a6349c33d87c0f045c80c08003e3 +Subproject commit 2f8a38c3cae772aa73216499dd40fde695878566 diff --git a/frozen/Adafruit_CircuitPython_RFM9x b/frozen/Adafruit_CircuitPython_RFM9x index ad3a28df5e0..b2a843ddff2 160000 --- a/frozen/Adafruit_CircuitPython_RFM9x +++ b/frozen/Adafruit_CircuitPython_RFM9x @@ -1 +1 @@ -Subproject commit ad3a28df5e0cab2a24b9a6acf0667fe7c5a26563 +Subproject commit b2a843ddff22cec5a2b6ee79ba0c52e17cbf9dd2 diff --git a/frozen/Adafruit_CircuitPython_Register b/frozen/Adafruit_CircuitPython_Register index 2a7039c5484..e168e97a2c9 160000 --- a/frozen/Adafruit_CircuitPython_Register +++ b/frozen/Adafruit_CircuitPython_Register @@ -1 +1 @@ -Subproject commit 2a7039c548456ddf7573814967ce494f61adbc46 +Subproject commit e168e97a2c9713ec0f82cb6171461873dfffd46d diff --git a/frozen/Adafruit_CircuitPython_Requests b/frozen/Adafruit_CircuitPython_Requests index 44186adfc6a..82a656aa807 160000 --- a/frozen/Adafruit_CircuitPython_Requests +++ b/frozen/Adafruit_CircuitPython_Requests @@ -1 +1 @@ -Subproject commit 44186adfc6a982f26007cba2b103dd65cbb68c65 +Subproject commit 82a656aa80797ae8c526b69061b9e75728d377c9 diff --git a/frozen/Adafruit_CircuitPython_SD b/frozen/Adafruit_CircuitPython_SD index c700b45d484..e85d264ad6e 160000 --- a/frozen/Adafruit_CircuitPython_SD +++ b/frozen/Adafruit_CircuitPython_SD @@ -1 +1 @@ -Subproject commit c700b45d484a7e5054cf1856b871f3f25edb5ebb +Subproject commit e85d264ad6eaa286333fd3dbbf7a95b9ea7f0af3 diff --git a/frozen/Adafruit_CircuitPython_SHT4x b/frozen/Adafruit_CircuitPython_SHT4x index 2b5317830e6..c29695027b1 160000 --- a/frozen/Adafruit_CircuitPython_SHT4x +++ b/frozen/Adafruit_CircuitPython_SHT4x @@ -1 +1 @@ -Subproject commit 2b5317830e66233017e68f8b459261bc4240307d +Subproject commit c29695027b1d5f5140b570f31c91ace373f45843 diff --git a/frozen/Adafruit_CircuitPython_SSD1306 b/frozen/Adafruit_CircuitPython_SSD1306 index 04d8d531e8e..f8fa41a320f 160000 --- a/frozen/Adafruit_CircuitPython_SSD1306 +++ b/frozen/Adafruit_CircuitPython_SSD1306 @@ -1 +1 @@ -Subproject commit 04d8d531e8ed2df45c061c8b3c6d91abda001f13 +Subproject commit f8fa41a320f0bb29be6f37d340e69eba16b7a311 diff --git a/frozen/Adafruit_CircuitPython_SSD1680 b/frozen/Adafruit_CircuitPython_SSD1680 index c98b43e11ec..292f58b987d 160000 --- a/frozen/Adafruit_CircuitPython_SSD1680 +++ b/frozen/Adafruit_CircuitPython_SSD1680 @@ -1 +1 @@ -Subproject commit c98b43e11eca52c9885c48e866325595f5614eb8 +Subproject commit 292f58b987db50dd622be5b83722893c58c16ab9 diff --git a/frozen/Adafruit_CircuitPython_ST7789 b/frozen/Adafruit_CircuitPython_ST7789 index 8fb8cbf7c4c..24a0feec2b2 160000 --- a/frozen/Adafruit_CircuitPython_ST7789 +++ b/frozen/Adafruit_CircuitPython_ST7789 @@ -1 +1 @@ -Subproject commit 8fb8cbf7c4cf404c1334df67a7512ccf99a00c52 +Subproject commit 24a0feec2b24517c9f606f5063b6b48db4ce370e diff --git a/frozen/Adafruit_CircuitPython_SimpleIO b/frozen/Adafruit_CircuitPython_SimpleIO index b024e7276cf..5762bd0ec13 160000 --- a/frozen/Adafruit_CircuitPython_SimpleIO +++ b/frozen/Adafruit_CircuitPython_SimpleIO @@ -1 +1 @@ -Subproject commit b024e7276cf3796dddcced3cbe438195d310661b +Subproject commit 5762bd0ec1309f9ef489633ed8bcc17d1bc7f560 diff --git a/frozen/Adafruit_CircuitPython_SimpleMath b/frozen/Adafruit_CircuitPython_SimpleMath index 9ebbdae834c..3653b67541b 160000 --- a/frozen/Adafruit_CircuitPython_SimpleMath +++ b/frozen/Adafruit_CircuitPython_SimpleMath @@ -1 +1 @@ -Subproject commit 9ebbdae834ca3225bf411ba54c9e3148d8c26b6c +Subproject commit 3653b67541b7dbf0fbaaa65628c25cc6900dea87 diff --git a/frozen/Adafruit_CircuitPython_Thermistor b/frozen/Adafruit_CircuitPython_Thermistor index bdfeb28d741..86b15255613 160000 --- a/frozen/Adafruit_CircuitPython_Thermistor +++ b/frozen/Adafruit_CircuitPython_Thermistor @@ -1 +1 @@ -Subproject commit bdfeb28d741a0233c4d8789b610d116831c9c0dd +Subproject commit 86b152556138624979cad2df3210cadc38b5b344 diff --git a/frozen/Adafruit_CircuitPython_Ticks b/frozen/Adafruit_CircuitPython_Ticks index 415f35dceaf..0b27bc3dad3 160000 --- a/frozen/Adafruit_CircuitPython_Ticks +++ b/frozen/Adafruit_CircuitPython_Ticks @@ -1 +1 @@ -Subproject commit 415f35dceaf43f6e2bbc879f7049fed5e52f3c4a +Subproject commit 0b27bc3dad368b2cd6f18cb4faba3fcb41d54477 diff --git a/frozen/Adafruit_CircuitPython_UC8151D b/frozen/Adafruit_CircuitPython_UC8151D index ec3fd72eb42..9a37fc43eeb 160000 --- a/frozen/Adafruit_CircuitPython_UC8151D +++ b/frozen/Adafruit_CircuitPython_UC8151D @@ -1 +1 @@ -Subproject commit ec3fd72eb4219520c2ad5dd33e2e865a7e4b9d6a +Subproject commit 9a37fc43eeb277f698614e8d657c4104a75a44aa diff --git a/frozen/Adafruit_CircuitPython_Wave b/frozen/Adafruit_CircuitPython_Wave index 10f7ed33cbf..b2dd41fa0e3 160000 --- a/frozen/Adafruit_CircuitPython_Wave +++ b/frozen/Adafruit_CircuitPython_Wave @@ -1 +1 @@ -Subproject commit 10f7ed33cbf75b0f42ffe9aae721f57583a33ce6 +Subproject commit b2dd41fa0e3757c187a4693147eb7d83a84b5119 diff --git a/frozen/Adafruit_CircuitPython_Wiznet5k b/frozen/Adafruit_CircuitPython_Wiznet5k index 1e786b93a5a..f01275e34ad 160000 --- a/frozen/Adafruit_CircuitPython_Wiznet5k +++ b/frozen/Adafruit_CircuitPython_Wiznet5k @@ -1 +1 @@ -Subproject commit 1e786b93a5a1dede2fa6f44634336f666d153f6a +Subproject commit f01275e34ad2e5f7ddd9d074e963a8359011a297 diff --git a/frozen/Adafruit_CircuitPython_framebuf b/frozen/Adafruit_CircuitPython_framebuf index 3d2036d2926..6f6c89891de 160000 --- a/frozen/Adafruit_CircuitPython_framebuf +++ b/frozen/Adafruit_CircuitPython_framebuf @@ -1 +1 @@ -Subproject commit 3d2036d2926f7d04a00908845dd14cb18e3d8b90 +Subproject commit 6f6c89891de7d96c43028c4fdff5765763dffe16 diff --git a/frozen/Adafruit_CircuitPython_seesaw b/frozen/Adafruit_CircuitPython_seesaw index daab794981f..13ba8ba2a2c 160000 --- a/frozen/Adafruit_CircuitPython_seesaw +++ b/frozen/Adafruit_CircuitPython_seesaw @@ -1 +1 @@ -Subproject commit daab794981f177041fe1a4a9266a9688c45480e9 +Subproject commit 13ba8ba2a2cecb9df5a41390f991ce6c0cd76e14 From 5a0ef547b2d5a3aeef62c24ea9524a8d29c51587 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 12 May 2026 10:53:52 -0700 Subject: [PATCH 484/876] MagTag SSD1680: GxEPD2_4G LUT, reset fix, unify 0x44+0xca MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pulse RESET low before User ID read so SSD1680 wakes from deep sleep - Replace ad-hoc LUT with GxEPD2_4G reference (VS L0↔L3 swapped, 0x48 DC balance) - VCOM=0x24 empirically tuned for FPC-7519rev.b contrast - Both 0x44 (FPC-7619rev.b) and 0xca (FPC-7519rev.b) share the same sequence Co-Authored-By: Claude Sonnet 4.6 --- .../adafruit_magtag_2.9_grayscale/board.c | 96 +++++++++++-------- 1 file changed, 55 insertions(+), 41 deletions(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index cd3295a2e08..1b8a6dfe86c 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -11,6 +11,7 @@ #include "shared-bindings/busio/SPI.h" #include "shared-bindings/fourwire/FourWire.h" #include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-module/displayio/__init__.h" #include "supervisor/shared/board.h" @@ -128,38 +129,49 @@ const uint8_t ssd1680_display_start_sequence[] = { 0x22, 0x00, 0x01, 0xc7 // display update mode }; -// FPC-7519rev.b (User ID byte 0xca) requires lower VCOM for correct contrast. -// VCOM=0x14 (-1.0V) confirmed by reading the panel's OTP register (cmd 0x2D, byte 1 = 0x14). -// The 0x44 panel works correctly with the default VCOM=0x28, so keep them separate. -const uint8_t ssd1680_vcom14_display_start_sequence[] = { +// FPC-7519rev.b panels (User ID byte 0x44 or 0xca) need colstart=8 and tuned VCOM + LUT. +// LUT: Good Display reference (GxEPD2_4G / GDEM029T94) with VS rows reversed (L0↔L3, L1↔L2). +// Reason: CircuitPython maps luma 0→L0 and luma 255→L3. On this panel VSH1(0x40) drives WHITE and +// VSL(0x20) drives BLACK, so L0 must carry the black-driving waveform and L3 the white-driving +// waveform — opposite from GxEPD2_4G's Arduino convention (where index 0 = white constant). +// VS=0x48 = VSH1/GND/VSL/GND alternating for DC balance. +// VCOM=0x24 empirically tuned for FPC-7519rev.b contrast. Both 0x44 and 0xca share this sequence. +const uint8_t ssd1680_fpc7519_display_start_sequence[] = { 0x12, DELAY, 0x00, 0x14, // soft reset and wait 20ms 0x11, 0x00, 0x01, 0x03, // Ram data entry mode 0x3c, 0x00, 0x01, 0x03, // border color - 0x2c, 0x00, 0x01, 0x14, // Set vcom voltage (0x14 = -1.0V, tuned for FPC-7519rev.b) + 0x2c, 0x00, 0x01, 0x24, // Set vcom voltage (0x24 tuned for FPC-7519rev.b contrast) 0x03, 0x00, 0x01, 0x17, // Set gate voltage 0x04, 0x00, 0x03, 0x41, 0xae, 0x32, // Set source voltage 0x4e, 0x00, 0x01, 0x01, // ram x count 0x4f, 0x00, 0x02, 0x00, 0x00, // ram y count 0x01, 0x00, 0x03, 0x27, 0x01, 0x00, // set display size - 0x32, 0x00, 0x99, // Update waveforms - 0x2a, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L0 - 0x20, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L1 - 0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L2 - 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L3 - 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L4 - 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, // TP, SR, RP of Group0 - 0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01, // TP, SR, RP of Group1 - 0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00, // TP, SR, RP of Group2 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group3 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group4 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group5 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group6 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group7 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group8 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group9 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group10 - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // TP, SR, RP of Group11 - 0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00, // FR, XON + 0x32, 0x00, 0x99, // Update waveforms (153 bytes follow) + // VS rows: only L0↔L3 are swapped relative to GxEPD2_4G; L1 and L2 stay in place. + // Reason: CircuitPython luma maps 0→L0, 64-127→L2, 128-191→L1, 255→L3. + // GxEPD2 uses L0=white-driver, L3=black-driver (opposite of CircuitPython for extremes). + // GxEPD2 L1=lighter-gray, L2=darker-gray; CircuitPython L1=mid-bright, L2=mid-dark — same ordering. + // So: swap only L0↔L3 (polarity); L1 and L2 keep their GxEPD2 positions (gradient preserved). + // 0x48 = VSH1/GND/VSL/GND alternating — better DC balance than 0x60 (VSH1/VSL/GND/GND) + 0x20, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L0 (darkest/black) ← GxEPD2 L3 + 0x08, 0x48, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L1 (mid-light) ← GxEPD2 L1 (luma 128-191 → lighter) + 0x02, 0x48, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L2 (mid-dark) ← GxEPD2 L2 (luma 64-127 → darker) + 0x40, 0x48, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L3 (lightest/white) ← GxEPD2 L0 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // VS L4 VCOM + // Timing groups — Good Display reference timing + 0x0A, 0x19, 0x00, 0x03, 0x08, 0x00, 0x00, // Group0: 10+25 / 3+8 frames activation + 0x14, 0x01, 0x00, 0x14, 0x01, 0x00, 0x03, // Group1: 20+1 / 20+1 frames, RP=3 repeats + 0x0A, 0x03, 0x00, 0x08, 0x19, 0x00, 0x00, // Group2: 10+3 / 8+25 frames (mirror of G0) + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // Group3: 1 frame settle + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group4 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group5 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group6 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group7 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group8 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group9 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Group11 + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, // XON 0x22, 0x00, 0x01, 0xc7 // display update mode }; @@ -175,8 +187,7 @@ const uint8_t ssd1680_display_refresh_sequence[] = { typedef enum { DISPLAY_IL0373, DISPLAY_SSD1680_COLSTART_0, - DISPLAY_SSD1680_COLSTART_8, - DISPLAY_SSD1680_COLSTART_8_VCOM14, // FPC-7519rev.b (User ID 0xca) + DISPLAY_SSD1680_COLSTART_8, // FPC-7519rev.b (User ID 0x44 or 0xca) } display_type_t; static display_type_t detect_display_type(void) { @@ -185,13 +196,14 @@ static display_type_t detect_display_type(void) { // NOTE: the SSD1680 drives its response back on the MOSI/DATA line (GPIO35) in half-duplex // mode, NOT on the separate MISO line (GPIO37). Read with GPIO35 switched to input. // On the IL0373 it will return 0xff because it's not a valid register. - // With SSD1680, we have seen three types: + // With SSD1680, we have seen two types: // 1. The first batch of displays, labeled "FPC-A005 20.06.15 TRX", which needs colstart=0. // These have 10 bytes of zeros in the User ID. - // 2. Second batch, labeled "FPC-7619rev.b", which needs colstart=8. - // The USER ID for these boards is [0x44, 0x0, 0x4, 0x0, 0x25, 0x0, 0x1, 0x78, 0x2b, 0xe] - // 3. Third batch, labeled "FPC-7519rev.b", which needs colstart=8. - // The USER ID for these boards is [0xca, 0xfe, 0x0, 0x16, 0x80, 0x0, 0x75, 0x1, 0x0, 0x98] + // 2. Later panels, labeled "FPC-7519rev.b", which need colstart=8 and a tuned LUT/VCOM. + // Two controller variants exist within this panel generation: + // User ID [0x44, 0x0, 0x4, 0x0, 0x25, 0x0, 0x1, 0x78, 0x2b, 0xe] + // User ID [0xca, 0xfe, 0x0, 0x16, 0x80, 0x0, 0x75, 0x1, 0x0, 0x98] + // Both carry the same ribbon label and show the same display characteristics. // So let's distinguish just by the first byte. digitalio_digitalinout_obj_t data; digitalio_digitalinout_obj_t clock; @@ -214,9 +226,15 @@ static display_type_t detect_display_type(void) { common_hal_digitalio_digitalinout_switch_to_output(&chip_select, false, DRIVE_MODE_PUSH_PULL); common_hal_digitalio_digitalinout_switch_to_output(&data_command, false, DRIVE_MODE_PUSH_PULL); common_hal_digitalio_digitalinout_switch_to_output(&data, false, DRIVE_MODE_PUSH_PULL); - common_hal_digitalio_digitalinout_switch_to_output(&reset, true, DRIVE_MODE_PUSH_PULL); common_hal_digitalio_digitalinout_switch_to_output(&clock, false, DRIVE_MODE_PUSH_PULL); + // Pulse RESET low to wake SSD1680 from deep sleep (entered via stop_sequence on prior run). + // SSD1680 ignores all SPI commands while in deep sleep; only a hardware reset exits it. + common_hal_digitalio_digitalinout_switch_to_output(&reset, false, DRIVE_MODE_PUSH_PULL); + common_hal_mcu_delay_us(200); + common_hal_digitalio_digitalinout_set_value(&reset, true); + common_hal_mcu_delay_us(10000); // 10ms for controller to come out of reset + uint8_t status_read = 0x2e; // SSD1680 User ID register. Not a valid register on IL0373. for (int i = 0; i < 8; i++) { common_hal_digitalio_digitalinout_set_value(&data, (status_read & (1 << (7 - i))) != 0); @@ -254,9 +272,8 @@ static display_type_t detect_display_type(void) { case 0x00: return DISPLAY_SSD1680_COLSTART_0; case 0x44: - return DISPLAY_SSD1680_COLSTART_8; case 0xca: - return DISPLAY_SSD1680_COLSTART_8_VCOM14; + return DISPLAY_SSD1680_COLSTART_8; } } @@ -304,14 +321,11 @@ void board_init(void) { common_hal_epaperdisplay_epaperdisplay_construct(display, &args); } else { epaperdisplay_construct_args_t args = EPAPERDISPLAY_CONSTRUCT_ARGS_DEFAULTS; - // Default colstart is 0. - if (display_type == DISPLAY_SSD1680_COLSTART_8 || display_type == DISPLAY_SSD1680_COLSTART_8_VCOM14) { - args.colstart = 8; - } args.bus = bus; - if (display_type == DISPLAY_SSD1680_COLSTART_8_VCOM14) { - args.start_sequence = ssd1680_vcom14_display_start_sequence; - args.start_sequence_len = sizeof(ssd1680_vcom14_display_start_sequence); + if (display_type == DISPLAY_SSD1680_COLSTART_8) { + args.colstart = 8; + args.start_sequence = ssd1680_fpc7519_display_start_sequence; + args.start_sequence_len = sizeof(ssd1680_fpc7519_display_start_sequence); } else { args.start_sequence = ssd1680_display_start_sequence; args.start_sequence_len = sizeof(ssd1680_display_start_sequence); From 243bf0b6e588853a883b4767172a756c9b952365 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 12 May 2026 11:04:07 -0700 Subject: [PATCH 485/876] MagTag SSD1680: make COLSTART_8 the default for unknown variants --- ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c index 1b8a6dfe86c..61659755be2 100644 --- a/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c +++ b/ports/espressif/boards/adafruit_magtag_2.9_grayscale/board.c @@ -268,9 +268,9 @@ static display_type_t detect_display_type(void) { switch (status) { case 0xff: return DISPLAY_IL0373; - default: // who knows? Just guess. case 0x00: return DISPLAY_SSD1680_COLSTART_0; + default: // unknown SSD1680 variant — assume newer panel needs colstart=8 case 0x44: case 0xca: return DISPLAY_SSD1680_COLSTART_8; From 599ef3f84ad7a3eb4005a791ec6f35f1277f2e4f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 12 May 2026 14:15:54 -0500 Subject: [PATCH 486/876] refactor to audioi2sin --- .../{audio_i2sin => audioi2sin}/I2SIn.c | 22 ++--- .../{audio_i2sin => audioi2sin}/I2SIn.h | 4 +- .../{audio_i2sin => audioi2sin}/__init__.c | 0 ports/espressif/mpconfigport.mk | 2 +- .../{audio_i2sin => audioi2sin}/I2SIn.c | 26 +++--- .../{audio_i2sin => audioi2sin}/I2SIn.h | 2 +- .../{audio_i2sin => audioi2sin}/README.pio | 0 .../{audio_i2sin => audioi2sin}/__init__.c | 0 .../{audio_i2sin => audioi2sin}/i2sin.pio | 0 .../{audio_i2sin => audioi2sin}/i2sin_32.pio | 0 .../i2sin_left.pio | 0 .../i2sin_left_32.pio | 0 .../i2sin_swap.pio | 0 .../i2sin_swap_32.pio | 0 .../i2sin_swap_left.pio | 0 .../i2sin_swap_left_32.pio | 0 ports/raspberrypi/mpconfigport.mk | 2 +- py/circuitpy_defns.mk | 8 +- py/circuitpy_mpconfig.mk | 6 +- shared-bindings/audio_i2sin/I2SIn.h | 28 ------ .../{audio_i2sin => audioi2sin}/I2SIn.c | 86 +++++++++---------- shared-bindings/audioi2sin/I2SIn.h | 28 ++++++ .../{audio_i2sin => audioi2sin}/__init__.c | 20 ++--- .../{audio_i2sin => audioi2sin}/__init__.h | 0 .../i2sin_neopixel_reactive.py | 4 +- .../i2sin_record_sdcard.py | 4 +- 26 files changed, 121 insertions(+), 121 deletions(-) rename ports/espressif/common-hal/{audio_i2sin => audioi2sin}/I2SIn.c (87%) rename ports/espressif/common-hal/{audio_i2sin => audioi2sin}/I2SIn.h (91%) rename ports/espressif/common-hal/{audio_i2sin => audioi2sin}/__init__.c (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/I2SIn.c (96%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/I2SIn.h (96%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/README.pio (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/__init__.c (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/i2sin.pio (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/i2sin_32.pio (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/i2sin_left.pio (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/i2sin_left_32.pio (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/i2sin_swap.pio (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/i2sin_swap_32.pio (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/i2sin_swap_left.pio (100%) rename ports/raspberrypi/common-hal/{audio_i2sin => audioi2sin}/i2sin_swap_left_32.pio (100%) delete mode 100644 shared-bindings/audio_i2sin/I2SIn.h rename shared-bindings/{audio_i2sin => audioi2sin}/I2SIn.c (72%) create mode 100644 shared-bindings/audioi2sin/I2SIn.h rename shared-bindings/{audio_i2sin => audioi2sin}/__init__.c (51%) rename shared-bindings/{audio_i2sin => audioi2sin}/__init__.h (100%) rename tests/circuitpython-manual/{audio_i2sin => audioi2sin}/i2sin_neopixel_reactive.py (98%) rename tests/circuitpython-manual/{audio_i2sin => audioi2sin}/i2sin_record_sdcard.py (98%) diff --git a/ports/espressif/common-hal/audio_i2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c similarity index 87% rename from ports/espressif/common-hal/audio_i2sin/I2SIn.c rename to ports/espressif/common-hal/audioi2sin/I2SIn.c index 4362351c68d..67395087d16 100644 --- a/ports/espressif/common-hal/audio_i2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -8,16 +8,16 @@ #include "bindings/espidf/__init__.h" -#include "common-hal/audio_i2sin/I2SIn.h" +#include "common-hal/audioi2sin/I2SIn.h" #include "py/runtime.h" -#include "shared-bindings/audio_i2sin/I2SIn.h" +#include "shared-bindings/audioi2sin/I2SIn.h" #include "shared-bindings/microcontroller/Pin.h" #include "driver/i2s_std.h" -#if CIRCUITPY_AUDIO_I2SIN +#if CIRCUITPY_AUDIOI2SIN -void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, +void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified) { @@ -75,12 +75,12 @@ void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, } } -bool common_hal_audio_i2sin_i2sin_deinited(audio_i2sin_i2sin_obj_t *self) { +bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self) { return self->data == NULL; } -void common_hal_audio_i2sin_i2sin_deinit(audio_i2sin_i2sin_obj_t *self) { - if (common_hal_audio_i2sin_i2sin_deinited(self)) { +void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { + if (common_hal_audioi2sin_i2sin_deinited(self)) { return; } @@ -111,7 +111,7 @@ void common_hal_audio_i2sin_i2sin_deinit(audio_i2sin_i2sin_obj_t *self) { self->mclk = NULL; } -uint32_t common_hal_audio_i2sin_i2sin_record_to_buffer(audio_i2sin_i2sin_obj_t *self, +uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t length) { size_t element_size = self->bit_depth / 8; // 24-bit samples occupy a 32-bit slot on the I2S bus. @@ -158,12 +158,12 @@ uint32_t common_hal_audio_i2sin_i2sin_record_to_buffer(audio_i2sin_i2sin_obj_t * return produced; } -uint8_t common_hal_audio_i2sin_i2sin_get_bit_depth(audio_i2sin_i2sin_obj_t *self) { +uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) { return self->bit_depth; } -uint32_t common_hal_audio_i2sin_i2sin_get_sample_rate(audio_i2sin_i2sin_obj_t *self) { +uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self) { return self->sample_rate; } -#endif // CIRCUITPY_AUDIO_I2SIN +#endif // CIRCUITPY_AUDIOI2SIN diff --git a/ports/espressif/common-hal/audio_i2sin/I2SIn.h b/ports/espressif/common-hal/audioi2sin/I2SIn.h similarity index 91% rename from ports/espressif/common-hal/audio_i2sin/I2SIn.h rename to ports/espressif/common-hal/audioi2sin/I2SIn.h index 917b72c954b..e16919b4cbb 100644 --- a/ports/espressif/common-hal/audio_i2sin/I2SIn.h +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.h @@ -12,7 +12,7 @@ #include "driver/i2s_std.h" -#if CIRCUITPY_AUDIO_I2SIN +#if CIRCUITPY_AUDIOI2SIN typedef struct { mp_obj_base_t base; @@ -24,6 +24,6 @@ typedef struct { uint32_t sample_rate; uint8_t bit_depth; bool mono; -} audio_i2sin_i2sin_obj_t; +} audioi2sin_i2sin_obj_t; #endif diff --git a/ports/espressif/common-hal/audio_i2sin/__init__.c b/ports/espressif/common-hal/audioi2sin/__init__.c similarity index 100% rename from ports/espressif/common-hal/audio_i2sin/__init__.c rename to ports/espressif/common-hal/audioi2sin/__init__.c diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index e52d47d9113..8396b89ee09 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -68,7 +68,7 @@ CIRCUITPY_ALARM_TOUCH ?= 0 CIRCUITPY_ANALOGBUFIO ?= 1 CIRCUITPY_AUDIOBUSIO ?= 1 CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0 -CIRCUITPY_AUDIO_I2SIN ?= 1 +CIRCUITPY_AUDIOI2SIN ?= 1 CIRCUITPY_AUDIOIO ?= 1 CIRCUITPY_BLEIO_HCI = 0 CIRCUITPY_BLEIO_NATIVE ?= 1 diff --git a/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c similarity index 96% rename from ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c rename to ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 54d66df88c4..f64bd299bda 100644 --- a/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -11,15 +11,15 @@ #include "py/mphal.h" #include "py/runtime.h" #include "shared/runtime/interrupt_char.h" -#include "common-hal/audio_i2sin/I2SIn.h" -#include "shared-bindings/audio_i2sin/I2SIn.h" +#include "common-hal/audioi2sin/I2SIn.h" +#include "shared-bindings/audioi2sin/I2SIn.h" #include "shared-bindings/microcontroller/Pin.h" #include "bindings/rp2pio/StateMachine.h" #include "supervisor/port.h" #include "hardware/dma.h" -#if CIRCUITPY_AUDIO_I2SIN +#if CIRCUITPY_AUDIOI2SIN // 16-bit programs sample a stereo frame of 16+16 = 32 bits and rely on // auto-push at 32 to deliver one packed (right<<16 | left) word per frame. @@ -148,7 +148,7 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { }; // Caller validates that pins are free. -void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, +void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified) { @@ -239,7 +239,7 @@ void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, // 8 bytes; size the half-buffer for ~40 ms of audio so a slow consumer // (SD card flush etc.) can complete without overrunning. size_t bytes_per_frame = (bit_depth == 16) ? 4 : 8; - size_t target = (size_t)self->sample_rate * bytes_per_frame * 2 / 2; + size_t target = (size_t)self->sample_rate * bytes_per_frame * 40 / 1000; size_t half_size = (target > 4096) ? target : 4096; // Round up to a multiple of 8 so 24/32-bit pair reads never straddle // the half boundary. @@ -266,12 +266,12 @@ void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, self->dma_channel = common_hal_rp2pio_statemachine_get_read_dma_channel(&self->state_machine); } -bool common_hal_audio_i2sin_i2sin_deinited(audio_i2sin_i2sin_obj_t *self) { +bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self) { return common_hal_rp2pio_statemachine_deinited(&self->state_machine); } -void common_hal_audio_i2sin_i2sin_deinit(audio_i2sin_i2sin_obj_t *self) { - if (common_hal_audio_i2sin_i2sin_deinited(self)) { +void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { + if (common_hal_audioi2sin_i2sin_deinited(self)) { return; } common_hal_rp2pio_statemachine_stop_background_read(&self->state_machine); @@ -285,11 +285,11 @@ void common_hal_audio_i2sin_i2sin_deinit(audio_i2sin_i2sin_obj_t *self) { self->dma_channel = -1; } -uint8_t common_hal_audio_i2sin_i2sin_get_bit_depth(audio_i2sin_i2sin_obj_t *self) { +uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) { return self->bit_depth; } -uint32_t common_hal_audio_i2sin_i2sin_get_sample_rate(audio_i2sin_i2sin_obj_t *self) { +uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self) { return self->sample_rate; } @@ -304,7 +304,7 @@ uint32_t common_hal_audio_i2sin_i2sin_get_sample_rate(audio_i2sin_i2sin_obj_t *s // the number actually written. // Compute the byte offset inside `ring` that the DMA is currently writing // (one past the last word it finished). Always lies in [0, ring_size). -static size_t i2sin_write_pos(audio_i2sin_i2sin_obj_t *self) { +static size_t i2sin_write_pos(audioi2sin_i2sin_obj_t *self) { uintptr_t addr = (uintptr_t)dma_channel_hw_addr(self->dma_channel)->write_addr; uintptr_t base = (uintptr_t)self->ring; if (addr < base || addr >= base + self->ring_size) { @@ -316,7 +316,7 @@ static size_t i2sin_write_pos(audio_i2sin_i2sin_obj_t *self) { return (size_t)(addr - base); } -uint32_t common_hal_audio_i2sin_i2sin_record_to_buffer(audio_i2sin_i2sin_obj_t *self, +uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t output_buffer_length) { uint32_t output_count = 0; const size_t ring_size = self->ring_size; @@ -433,4 +433,4 @@ uint32_t common_hal_audio_i2sin_i2sin_record_to_buffer(audio_i2sin_i2sin_obj_t * return output_count; } -#endif // CIRCUITPY_AUDIO_I2SIN +#endif // CIRCUITPY_AUDIOI2SIN diff --git a/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h similarity index 96% rename from ports/raspberrypi/common-hal/audio_i2sin/I2SIn.h rename to ports/raspberrypi/common-hal/audioi2sin/I2SIn.h index 9f825c79f72..06ae2ca774c 100644 --- a/ports/raspberrypi/common-hal/audio_i2sin/I2SIn.h +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -26,4 +26,4 @@ typedef struct { size_t read_pos; int dma_channel; bool overflow; -} audio_i2sin_i2sin_obj_t; +} audioi2sin_i2sin_obj_t; diff --git a/ports/raspberrypi/common-hal/audio_i2sin/README.pio b/ports/raspberrypi/common-hal/audioi2sin/README.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/README.pio rename to ports/raspberrypi/common-hal/audioi2sin/README.pio diff --git a/ports/raspberrypi/common-hal/audio_i2sin/__init__.c b/ports/raspberrypi/common-hal/audioi2sin/__init__.c similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/__init__.c rename to ports/raspberrypi/common-hal/audioi2sin/__init__.c diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/i2sin.pio rename to ports/raspberrypi/common-hal/audioi2sin/i2sin.pio diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/i2sin_32.pio rename to ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/i2sin_left.pio rename to ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/i2sin_left_32.pio rename to ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap.pio rename to ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_32.pio rename to ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left.pio rename to ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio diff --git a/ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio similarity index 100% rename from ports/raspberrypi/common-hal/audio_i2sin/i2sin_swap_left_32.pio rename to ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index dd93e216481..76f468beee6 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -44,7 +44,7 @@ CIRCUITPY_ANALOGBUFIO = 1 # Audio via PWM CIRCUITPY_AUDIOIO = 0 CIRCUITPY_AUDIOBUSIO ?= 1 -CIRCUITPY_AUDIO_I2SIN ?= $(CIRCUITPY_AUDIOBUSIO) +CIRCUITPY_AUDIOI2SIN ?= $(CIRCUITPY_AUDIOBUSIO) CIRCUITPY_AUDIOCORE ?= 1 CIRCUITPY_AUDIOPWMIO ?= 1 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 48fa62bf3c7..67be45325d5 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -122,8 +122,8 @@ endif ifeq ($(CIRCUITPY_AUDIOBUSIO),1) SRC_PATTERNS += audiobusio/% endif -ifeq ($(CIRCUITPY_AUDIO_I2SIN),1) -SRC_PATTERNS += audio_i2sin/% +ifeq ($(CIRCUITPY_AUDIOI2SIN),1) +SRC_PATTERNS += audioi2sin/% endif ifeq ($(CIRCUITPY_AUDIOIO),1) SRC_PATTERNS += audioio/% @@ -508,8 +508,8 @@ SRC_COMMON_HAL_ALL = \ audiobusio/I2SOut.c \ audiobusio/PDMIn.c \ audiobusio/__init__.c \ - audio_i2sin/I2SIn.c \ - audio_i2sin/__init__.c \ + audioi2sin/I2SIn.c \ + audioi2sin/__init__.c \ audioio/AudioOut.c \ audioio/__init__.c \ audiopwmio/PWMAudioOut.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index a5ccd9273b1..f56813f3b91 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -135,9 +135,9 @@ CFLAGS += -DCIRCUITPY_AUDIOBUSIO_I2SOUT=$(CIRCUITPY_AUDIOBUSIO_I2SOUT) CIRCUITPY_AUDIOBUSIO_PDMIN ?= $(CIRCUITPY_AUDIOBUSIO) CFLAGS += -DCIRCUITPY_AUDIOBUSIO_PDMIN=$(CIRCUITPY_AUDIOBUSIO_PDMIN) -# I2S audio input (separate core module `audio_i2sin`). -CIRCUITPY_AUDIO_I2SIN ?= 0 -CFLAGS += -DCIRCUITPY_AUDIO_I2SIN=$(CIRCUITPY_AUDIO_I2SIN) +# I2S audio input (separate core module `audioi2sin`). +CIRCUITPY_AUDIOI2SIN ?= 0 +CFLAGS += -DCIRCUITPY_AUDIOI2SIN=$(CIRCUITPY_AUDIOI2SIN) CIRCUITPY_AUDIOIO ?= $(CIRCUITPY_FULL_BUILD) CFLAGS += -DCIRCUITPY_AUDIOIO=$(CIRCUITPY_AUDIOIO) diff --git a/shared-bindings/audio_i2sin/I2SIn.h b/shared-bindings/audio_i2sin/I2SIn.h deleted file mode 100644 index 183b646ecd8..00000000000 --- a/shared-bindings/audio_i2sin/I2SIn.h +++ /dev/null @@ -1,28 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "shared-bindings/microcontroller/Pin.h" - -#if CIRCUITPY_AUDIO_I2SIN -#include "common-hal/audio_i2sin/I2SIn.h" -#endif - -extern const mp_obj_type_t audio_i2sin_i2sin_type; - -#if CIRCUITPY_AUDIO_I2SIN -void common_hal_audio_i2sin_i2sin_construct(audio_i2sin_i2sin_obj_t *self, - const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, - uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified); -void common_hal_audio_i2sin_i2sin_deinit(audio_i2sin_i2sin_obj_t *self); -bool common_hal_audio_i2sin_i2sin_deinited(audio_i2sin_i2sin_obj_t *self); -uint32_t common_hal_audio_i2sin_i2sin_record_to_buffer(audio_i2sin_i2sin_obj_t *self, - void *buffer, uint32_t length); -uint8_t common_hal_audio_i2sin_i2sin_get_bit_depth(audio_i2sin_i2sin_obj_t *self); -uint32_t common_hal_audio_i2sin_i2sin_get_sample_rate(audio_i2sin_i2sin_obj_t *self); -#endif diff --git a/shared-bindings/audio_i2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c similarity index 72% rename from shared-bindings/audio_i2sin/I2SIn.c rename to shared-bindings/audioi2sin/I2SIn.c index 7c43d24bfa1..4c2b2212547 100644 --- a/shared-bindings/audio_i2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -13,7 +13,7 @@ #include "py/objproperty.h" #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audio_i2sin/I2SIn.h" +#include "shared-bindings/audioi2sin/I2SIn.h" #include "shared-bindings/util.h" //| class I2SIn: @@ -55,18 +55,18 @@ //| Example, recording 16-bit mono samples from an INMP441:: //| //| import array -//| import audio_i2sin +//| import audioi2sin //| import board //| //| buf = array.array("H", [0] * 16000) -//| with audio_i2sin.I2SIn(board.D9, board.D10, board.D11, +//| with audioi2sin.I2SIn(board.D9, board.D10, board.D11, //| sample_rate=16000, bit_depth=16) as mic: //| mic.record(buf, len(buf)) //| """ //| ... //| -static mp_obj_t audio_i2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - #if !CIRCUITPY_AUDIO_I2SIN +static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + #if !CIRCUITPY_AUDIOI2SIN mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_I2SIn); return NULL; // Not reachable. #else @@ -98,28 +98,28 @@ static mp_obj_t audio_i2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_a bool mono = args[ARG_mono].u_bool; bool left_justified = args[ARG_left_justified].u_bool; - audio_i2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audio_i2sin_i2sin_obj_t, &audio_i2sin_i2sin_type); - common_hal_audio_i2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, + audioi2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audioi2sin_i2sin_obj_t, &audioi2sin_i2sin_type); + common_hal_audioi2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, sample_rate, bit_depth, mono, left_justified); return MP_OBJ_FROM_PTR(self); #endif } -#if CIRCUITPY_AUDIO_I2SIN +#if CIRCUITPY_AUDIOI2SIN //| def deinit(self) -> None: //| """Deinitialises the I2SIn and releases any hardware resources for reuse.""" //| ... //| -static mp_obj_t audio_i2sin_i2sin_deinit(mp_obj_t self_in) { - audio_i2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audio_i2sin_i2sin_deinit(self); +static mp_obj_t audioi2sin_i2sin_deinit(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audioi2sin_i2sin_deinit(self); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(audio_i2sin_i2sin_deinit_obj, audio_i2sin_i2sin_deinit); +static MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_deinit_obj, audioi2sin_i2sin_deinit); -static void check_for_deinit(audio_i2sin_i2sin_obj_t *self) { - if (common_hal_audio_i2sin_i2sin_deinited(self)) { +static void check_for_deinit(audioi2sin_i2sin_obj_t *self) { + if (common_hal_audioi2sin_i2sin_deinited(self)) { raise_deinited_error(); } } @@ -144,8 +144,8 @@ static void check_for_deinit(audio_i2sin_i2sin_obj_t *self) { //| some samples were missed due to processing time.""" //| ... //| -static mp_obj_t audio_i2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) { - audio_i2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_obj); +static mp_obj_t audioi2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destination, mp_obj_t destination_length) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_obj); check_for_deinit(self); uint32_t length = mp_arg_validate_type_int(destination_length, MP_QSTR_length); mp_arg_validate_length_min(length, 0, MP_QSTR_length); @@ -158,7 +158,7 @@ static mp_obj_t audio_i2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destina if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); } - uint8_t bit_depth = common_hal_audio_i2sin_i2sin_get_bit_depth(self); + uint8_t bit_depth = common_hal_audioi2sin_i2sin_get_bit_depth(self); if ((bit_depth == 24 || bit_depth == 32) && bufinfo.typecode != 'I') { mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'I' for bit_depth = 24 or 32")); } else if (bit_depth == 16 && bufinfo.typecode != 'H') { @@ -167,57 +167,57 @@ static mp_obj_t audio_i2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destina mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8")); } uint32_t length_written = - common_hal_audio_i2sin_i2sin_record_to_buffer(self, bufinfo.buf, length); + common_hal_audioi2sin_i2sin_record_to_buffer(self, bufinfo.buf, length); return MP_OBJ_NEW_SMALL_INT(length_written); } -MP_DEFINE_CONST_FUN_OBJ_3(audio_i2sin_i2sin_record_obj, audio_i2sin_i2sin_obj_record); +MP_DEFINE_CONST_FUN_OBJ_3(audioi2sin_i2sin_record_obj, audioi2sin_i2sin_obj_record); //| sample_rate: int //| """The actual sample rate of the recording. This may not match the constructed //| sample rate due to internal clock limitations.""" //| -static mp_obj_t audio_i2sin_i2sin_obj_get_sample_rate(mp_obj_t self_in) { - audio_i2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); +static mp_obj_t audioi2sin_i2sin_obj_get_sample_rate(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audio_i2sin_i2sin_get_sample_rate(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioi2sin_i2sin_get_sample_rate(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(audio_i2sin_i2sin_get_sample_rate_obj, audio_i2sin_i2sin_obj_get_sample_rate); +MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_sample_rate_obj, audioi2sin_i2sin_obj_get_sample_rate); -MP_PROPERTY_GETTER(audio_i2sin_i2sin_sample_rate_obj, - (mp_obj_t)&audio_i2sin_i2sin_get_sample_rate_obj); +MP_PROPERTY_GETTER(audioi2sin_i2sin_sample_rate_obj, + (mp_obj_t)&audioi2sin_i2sin_get_sample_rate_obj); //| bit_depth: int //| """The actual bit depth of the recording. (read-only)""" //| //| -static mp_obj_t audio_i2sin_i2sin_obj_get_bit_depth(mp_obj_t self_in) { - audio_i2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); +static mp_obj_t audioi2sin_i2sin_obj_get_bit_depth(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audio_i2sin_i2sin_get_bit_depth(self)); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioi2sin_i2sin_get_bit_depth(self)); } -MP_DEFINE_CONST_FUN_OBJ_1(audio_i2sin_i2sin_get_bit_depth_obj, audio_i2sin_i2sin_obj_get_bit_depth); +MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_bit_depth_obj, audioi2sin_i2sin_obj_get_bit_depth); -MP_PROPERTY_GETTER(audio_i2sin_i2sin_bit_depth_obj, - (mp_obj_t)&audio_i2sin_i2sin_get_bit_depth_obj); +MP_PROPERTY_GETTER(audioi2sin_i2sin_bit_depth_obj, + (mp_obj_t)&audioi2sin_i2sin_get_bit_depth_obj); -static const mp_rom_map_elem_t audio_i2sin_i2sin_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audio_i2sin_i2sin_deinit_obj) }, - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audio_i2sin_i2sin_deinit_obj) }, +static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&audio_i2sin_i2sin_record_obj) }, - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audio_i2sin_i2sin_sample_rate_obj) }, - { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audio_i2sin_i2sin_bit_depth_obj) }, + { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&audioi2sin_i2sin_record_obj) }, + { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioi2sin_i2sin_sample_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_bit_depth_obj) }, }; -static MP_DEFINE_CONST_DICT(audio_i2sin_i2sin_locals_dict, audio_i2sin_i2sin_locals_dict_table); -#endif // CIRCUITPY_AUDIO_I2SIN +static MP_DEFINE_CONST_DICT(audioi2sin_i2sin_locals_dict, audioi2sin_i2sin_locals_dict_table); +#endif // CIRCUITPY_AUDIOI2SIN MP_DEFINE_CONST_OBJ_TYPE( - audio_i2sin_i2sin_type, + audioi2sin_i2sin_type, MP_QSTR_I2SIn, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, audio_i2sin_i2sin_make_new - #if CIRCUITPY_AUDIO_I2SIN - , locals_dict, &audio_i2sin_i2sin_locals_dict + make_new, audioi2sin_i2sin_make_new + #if CIRCUITPY_AUDIOI2SIN + , locals_dict, &audioi2sin_i2sin_locals_dict #endif ); diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h new file mode 100644 index 00000000000..6e8254d875d --- /dev/null +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-bindings/microcontroller/Pin.h" + +#if CIRCUITPY_AUDIOI2SIN +#include "common-hal/audioi2sin/I2SIn.h" +#endif + +extern const mp_obj_type_t audioi2sin_i2sin_type; + +#if CIRCUITPY_AUDIOI2SIN +void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, + const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, + uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified); +void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self); +bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self); +uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, + void *buffer, uint32_t length); +uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self); +uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self); +#endif diff --git a/shared-bindings/audio_i2sin/__init__.c b/shared-bindings/audioi2sin/__init__.c similarity index 51% rename from shared-bindings/audio_i2sin/__init__.c rename to shared-bindings/audioi2sin/__init__.c index ba163ae75f4..45ba16cb01a 100644 --- a/shared-bindings/audio_i2sin/__init__.c +++ b/shared-bindings/audioi2sin/__init__.c @@ -10,12 +10,12 @@ #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" -#include "shared-bindings/audio_i2sin/__init__.h" -#include "shared-bindings/audio_i2sin/I2SIn.h" +#include "shared-bindings/audioi2sin/__init__.h" +#include "shared-bindings/audioi2sin/I2SIn.h" //| """Support for recording audio from an I2S input source. //| -//| The `audio_i2sin` module contains the `I2SIn` class for recording audio +//| The `audioi2sin` module contains the `I2SIn` class for recording audio //| from an external I2S source such as a MEMS microphone (e.g. SPH0645LM4H //| or INMP441). //| @@ -23,16 +23,16 @@ //| are no longer needed. To do so, either call :py:meth:`!deinit` or use a //| context manager.""" -static const mp_rom_map_elem_t audio_i2sin_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audio_i2sin) }, - { MP_ROM_QSTR(MP_QSTR_I2SIn), MP_ROM_PTR(&audio_i2sin_i2sin_type) }, +static const mp_rom_map_elem_t audioi2sin_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audioi2sin) }, + { MP_ROM_QSTR(MP_QSTR_I2SIn), MP_ROM_PTR(&audioi2sin_i2sin_type) }, }; -static MP_DEFINE_CONST_DICT(audio_i2sin_module_globals, audio_i2sin_module_globals_table); +static MP_DEFINE_CONST_DICT(audioi2sin_module_globals, audioi2sin_module_globals_table); -const mp_obj_module_t audio_i2sin_module = { +const mp_obj_module_t audioi2sin_module = { .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&audio_i2sin_module_globals, + .globals = (mp_obj_dict_t *)&audioi2sin_module_globals, }; -MP_REGISTER_MODULE(MP_QSTR_audio_i2sin, audio_i2sin_module); +MP_REGISTER_MODULE(MP_QSTR_audioi2sin, audioi2sin_module); diff --git a/shared-bindings/audio_i2sin/__init__.h b/shared-bindings/audioi2sin/__init__.h similarity index 100% rename from shared-bindings/audio_i2sin/__init__.h rename to shared-bindings/audioi2sin/__init__.h diff --git a/tests/circuitpython-manual/audio_i2sin/i2sin_neopixel_reactive.py b/tests/circuitpython-manual/audioi2sin/i2sin_neopixel_reactive.py similarity index 98% rename from tests/circuitpython-manual/audio_i2sin/i2sin_neopixel_reactive.py rename to tests/circuitpython-manual/audioi2sin/i2sin_neopixel_reactive.py index 58a100547f2..ac9c2c8ba0d 100644 --- a/tests/circuitpython-manual/audio_i2sin/i2sin_neopixel_reactive.py +++ b/tests/circuitpython-manual/audioi2sin/i2sin_neopixel_reactive.py @@ -18,7 +18,7 @@ import time import board -import audio_i2sin +import audioi2sin import neopixel NUM_PIXELS = 30 @@ -29,7 +29,7 @@ pixels = neopixel.NeoPixel(PIXEL_PIN, NUM_PIXELS, brightness=0.3, auto_write=False) -mic = audio_i2sin.I2SIn( +mic = audioi2sin.I2SIn( bit_clock=board.D5, word_select=board.D6, data=board.D9, diff --git a/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py similarity index 98% rename from tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py rename to tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py index 3045cac9d50..060df3dc1b7 100644 --- a/tests/circuitpython-manual/audio_i2sin/i2sin_record_sdcard.py +++ b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py @@ -15,7 +15,7 @@ import busio import sdcardio import storage -import audio_i2sin +import audioi2sin # ---- Recording config ------------------------------------------------------ SAMPLE_RATE = 16000 @@ -32,7 +32,7 @@ # ---- Mic ------------------------------------------------------------------- # 24-bit MEMS mics ride in 32-bit slots. Downconvert each slot to a # signed 16-bit PCM sample before writing. -mic = audio_i2sin.I2SIn( +mic = audioi2sin.I2SIn( bit_clock=board.D5, word_select=board.D6, data=board.D9, From 510307c1e4cd7234a770124ba693527c1d6b89f4 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 12 May 2026 14:42:13 -0500 Subject: [PATCH 487/876] add samples_signed argument --- ports/espressif/common-hal/audioi2sin/I2SIn.c | 94 +++++++++++++------ ports/espressif/common-hal/audioi2sin/I2SIn.h | 1 + .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 25 ++++- .../raspberrypi/common-hal/audioi2sin/I2SIn.h | 1 + shared-bindings/audioi2sin/I2SIn.c | 25 ++++- shared-bindings/audioi2sin/I2SIn.h | 4 +- 6 files changed, 113 insertions(+), 37 deletions(-) diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 67395087d16..1f458ec79a7 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -20,7 +20,8 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, - uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified) { + uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified, + bool samples_signed) { if (bit_depth != 8 && bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32.")); @@ -66,6 +67,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, self->sample_rate = sample_rate; self->bit_depth = bit_depth; self->mono = mono; + self->samples_signed = samples_signed; claim_pin(bit_clock); claim_pin(word_select); @@ -111,6 +113,31 @@ void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { self->mclk = NULL; } +// I2S delivers signed PCM. When samples_signed is false, XOR each sample with +// the sign bit for its width to convert to unsigned PCM (WAV convention). +static void i2sin_convert_to_unsigned(void *buffer, uint32_t samples, + uint8_t bit_depth, size_t element_size) { + if (bit_depth == 8) { + uint8_t *p = (uint8_t *)buffer; + for (uint32_t i = 0; i < samples; i++) { + p[i] ^= 0x80u; + } + } else if (bit_depth == 16) { + uint16_t *p = (uint16_t *)buffer; + for (uint32_t i = 0; i < samples; i++) { + p[i] ^= 0x8000u; + } + } else { + // 24- or 32-bit; both stored in 32-bit slots (element_size == 4). + (void)element_size; + uint32_t mask = (bit_depth == 24) ? 0x800000u : 0x80000000u; + uint32_t *p = (uint32_t *)buffer; + for (uint32_t i = 0; i < samples; i++) { + p[i] ^= mask; + } + } +} + uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t length) { size_t element_size = self->bit_depth / 8; @@ -119,41 +146,46 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se element_size = 4; } + uint32_t produced; if (!self->mono) { size_t result = 0; esp_err_t err = i2s_channel_read(self->rx_chan, buffer, length * element_size, &result, portMAX_DELAY); CHECK_ESP_RESULT(err); - return result / element_size; + produced = result / element_size; + } else { + // Mono: bus is configured stereo, so each WS frame yields two slots in + // the DMA buffer. Read in chunks into a scratch and keep only the left + // slot of each frame. + uint8_t scratch[256]; + const size_t frame_bytes = 2 * element_size; + const size_t scratch_frames = sizeof(scratch) / frame_bytes; + uint8_t *out = (uint8_t *)buffer; + produced = 0; + while (produced < length) { + size_t want_frames = length - produced; + if (want_frames > scratch_frames) { + want_frames = scratch_frames; + } + size_t got_bytes = 0; + esp_err_t err = i2s_channel_read(self->rx_chan, scratch, + want_frames * frame_bytes, &got_bytes, portMAX_DELAY); + CHECK_ESP_RESULT(err); + size_t got_frames = got_bytes / frame_bytes; + for (size_t i = 0; i < got_frames; i++) { + memcpy(out + produced * element_size, + scratch + i * frame_bytes, + element_size); + produced++; + } + if (got_frames < want_frames) { + break; + } + } } - // Mono: bus is configured stereo, so each WS frame yields two slots in - // the DMA buffer. Read in chunks into a scratch and keep only the left - // slot of each frame. - uint8_t scratch[256]; - const size_t frame_bytes = 2 * element_size; - const size_t scratch_frames = sizeof(scratch) / frame_bytes; - uint8_t *out = (uint8_t *)buffer; - uint32_t produced = 0; - while (produced < length) { - size_t want_frames = length - produced; - if (want_frames > scratch_frames) { - want_frames = scratch_frames; - } - size_t got_bytes = 0; - esp_err_t err = i2s_channel_read(self->rx_chan, scratch, - want_frames * frame_bytes, &got_bytes, portMAX_DELAY); - CHECK_ESP_RESULT(err); - size_t got_frames = got_bytes / frame_bytes; - for (size_t i = 0; i < got_frames; i++) { - memcpy(out + produced * element_size, - scratch + i * frame_bytes, - element_size); - produced++; - } - if (got_frames < want_frames) { - break; - } + if (!self->samples_signed && produced > 0) { + i2sin_convert_to_unsigned(buffer, produced, self->bit_depth, element_size); } return produced; } @@ -166,4 +198,8 @@ uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *sel return self->sample_rate; } +bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self) { + return self->samples_signed; +} + #endif // CIRCUITPY_AUDIOI2SIN diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.h b/ports/espressif/common-hal/audioi2sin/I2SIn.h index e16919b4cbb..74e6eb83d0d 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.h +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.h @@ -24,6 +24,7 @@ typedef struct { uint32_t sample_rate; uint8_t bit_depth; bool mono; + bool samples_signed; } audioi2sin_i2sin_obj_t; #endif diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index f64bd299bda..181ed219f2d 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -151,7 +151,8 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, - uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified) { + uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified, + bool samples_signed) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); @@ -225,6 +226,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, self->sample_rate = actual_frequency / pio_clocks_per_frame; self->bit_depth = bit_depth; self->mono = mono; + self->samples_signed = samples_signed; self->settled = false; self->ring = NULL; self->ring_size = 0; @@ -293,6 +295,10 @@ uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *sel return self->sample_rate; } +bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self) { + return self->samples_signed; +} + // In 16-bit mode, each PIO frame produces a single 32-bit FIFO word with bits // 31..16 = right channel and bits 15..0 = left channel (both MSB-first signed // 16-bit). In 24/32-bit mode each frame produces two FIFO words: right first, @@ -322,6 +328,15 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se const size_t ring_size = self->ring_size; const size_t half_size = self->half_size; + // I2S delivers signed PCM. When the caller asked for unsigned samples, + // flip the sign bit per sample (XOR with 0x8000 for 16-bit, 0x800000 for + // 24-bit data in a 32-bit slot, 0x80000000 for 32-bit), matching the WAV + // convention. + const uint16_t flip16 = self->samples_signed ? 0 : 0x8000u; + const uint32_t flip32 = self->samples_signed + ? 0u + : (self->bit_depth == 24 ? 0x800000u : 0x80000000u); + if (self->bit_depth == 16) { // 16-bit mode auto-pushes one stereo frame per FIFO word. The DMA has // been streaming since construct time, so the ring already contains @@ -352,8 +367,8 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se } while (avail >= 4 && output_count < output_buffer_length) { uint32_t frame = *(volatile uint32_t *)(self->ring + self->read_pos); - uint16_t left = (uint16_t)(frame & 0xffff); - uint16_t right = (uint16_t)(frame >> 16); + uint16_t left = (uint16_t)(frame & 0xffff) ^ flip16; + uint16_t right = (uint16_t)(frame >> 16) ^ flip16; if (self->mono) { output[output_count++] = left; } else { @@ -410,9 +425,9 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se continue; } while (avail >= 8 && output_count < output_buffer_length) { - uint32_t right = *(volatile uint32_t *)(self->ring + self->read_pos); + uint32_t right = *(volatile uint32_t *)(self->ring + self->read_pos) ^ flip32; size_t next_pos = (self->read_pos + 4) % ring_size; - uint32_t left = *(volatile uint32_t *)(self->ring + next_pos); + uint32_t left = *(volatile uint32_t *)(self->ring + next_pos) ^ flip32; if (self->mono) { output[output_count++] = left; } else { diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h index 06ae2ca774c..399d962afb2 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -16,6 +16,7 @@ typedef struct { uint32_t sample_rate; uint8_t bit_depth; bool mono; + bool samples_signed; bool settled; rp2pio_statemachine_obj_t state_machine; // Background DMA ring buffer. The state machine alternates DMA writes diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 4c2b2212547..d8d8e3ebcc3 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -30,6 +30,7 @@ //| bit_depth: int = 16, //| mono: bool = True, //| left_justified: bool = False, +//| samples_signed: bool = True, //| ) -> None: //| """Create an I2SIn object associated with the given pins. This allows you to //| record audio signals from an external I2S source (e.g. an I2S MEMS microphone @@ -51,6 +52,9 @@ //| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise. //| :param bool left_justified: True when data bits are aligned with the word select clock. False //| when they are shifted by one to match classic I2S protocol. Set True for mics like the SPH0645LM4H. +//| :param bool samples_signed: Samples are signed (True) or unsigned (False). I2S mics deliver signed +//| two's-complement PCM natively; set False to have the recorded samples converted to unsigned PCM +//| (the top/sign bit is flipped, matching the WAV convention for unsigned samples). //| //| Example, recording 16-bit mono samples from an INMP441:: //| @@ -71,7 +75,7 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar return NULL; // Not reachable. #else enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, - ARG_sample_rate, ARG_bit_depth, ARG_mono, ARG_left_justified }; + ARG_sample_rate, ARG_bit_depth, ARG_mono, ARG_left_justified, ARG_samples_signed }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bit_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_word_select, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -81,6 +85,7 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_left_justified, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_samples_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -97,10 +102,11 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar } bool mono = args[ARG_mono].u_bool; bool left_justified = args[ARG_left_justified].u_bool; + bool samples_signed = args[ARG_samples_signed].u_bool; audioi2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audioi2sin_i2sin_obj_t, &audioi2sin_i2sin_type); common_hal_audioi2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, - sample_rate, bit_depth, mono, left_justified); + sample_rate, bit_depth, mono, left_justified, samples_signed); return MP_OBJ_FROM_PTR(self); #endif @@ -200,6 +206,20 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_bit_depth_obj, audioi2sin_i2sin_o MP_PROPERTY_GETTER(audioi2sin_i2sin_bit_depth_obj, (mp_obj_t)&audioi2sin_i2sin_get_bit_depth_obj); +//| samples_signed: bool +//| """True if recorded samples are signed PCM, False for unsigned. (read-only)""" +//| +//| +static mp_obj_t audioi2sin_i2sin_obj_get_samples_signed(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audioi2sin_i2sin_get_samples_signed(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_samples_signed_obj, audioi2sin_i2sin_obj_get_samples_signed); + +MP_PROPERTY_GETTER(audioi2sin_i2sin_samples_signed_obj, + (mp_obj_t)&audioi2sin_i2sin_get_samples_signed_obj); + static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, @@ -208,6 +228,7 @@ static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&audioi2sin_i2sin_record_obj) }, { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioi2sin_i2sin_sample_rate_obj) }, { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_bit_depth_obj) }, + { MP_ROM_QSTR(MP_QSTR_samples_signed), MP_ROM_PTR(&audioi2sin_i2sin_samples_signed_obj) }, }; static MP_DEFINE_CONST_DICT(audioi2sin_i2sin_locals_dict, audioi2sin_i2sin_locals_dict_table); #endif // CIRCUITPY_AUDIOI2SIN diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h index 6e8254d875d..e75bdf2d34b 100644 --- a/shared-bindings/audioi2sin/I2SIn.h +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -18,11 +18,13 @@ extern const mp_obj_type_t audioi2sin_i2sin_type; void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, - uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified); + uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified, + bool samples_signed); void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t length); uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self); +bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self); #endif From 4bb08635130cd84fda331249aed5c491a10c217b Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 14 May 2026 12:09:10 -0500 Subject: [PATCH 488/876] try to fix c6 builds. implement changes from review --- locale/circuitpython.pot | 28 +++++----- ports/espressif/Makefile | 4 ++ ports/espressif/common-hal/audioi2sin/I2SIn.c | 32 +++++++---- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 32 ++++++----- .../raspberrypi/common-hal/audioi2sin/I2SIn.h | 1 + shared-bindings/audioi2sin/I2SIn.c | 54 +++++++++++++++---- .../audioi2sin/i2sin_neopixel_reactive.py | 13 +---- .../audioi2sin/i2sin_record_sdcard.py | 4 +- 8 files changed, 108 insertions(+), 60 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 84e9fd7edd6..b6af1d43f40 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -219,7 +219,7 @@ msgstr "" msgid "%q must be array of type 'h'" msgstr "" -#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "%q must be multiple of 8." msgstr "" @@ -659,8 +659,8 @@ msgstr "" msgid "Below minimum frame rate" msgstr "" -#: ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" @@ -805,7 +805,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "" -#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "" @@ -927,7 +927,7 @@ msgstr "" msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -1695,7 +1695,7 @@ msgstr "" msgid "Ok" msgstr "" -#: ports/raspberrypi/common-hal/audio_i2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Only 16, 24, or 32 bit depth supported." msgstr "" @@ -1811,8 +1811,8 @@ msgstr "" msgid "Parameter error" msgstr "" -#: ports/espressif/common-hal/audio_i2sin/I2SIn.c #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "" @@ -2702,8 +2702,8 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audio_i2sin/I2SIn.c #: ports/espressif/common-hal/audiobusio/PDMIn.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "bit_depth must be 8, 16, 24, or 32." msgstr "" @@ -3095,20 +3095,15 @@ msgstr "" msgid "default is not a function" msgstr "" -#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c msgid "" "destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: shared-bindings/audio_i2sin/I2SIn.c shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: shared-bindings/audio_i2sin/I2SIn.c -msgid "" -"destination buffer must be an array of type 'I' for bit_depth = 24 or 32" -msgstr "" - #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" @@ -3522,6 +3517,11 @@ msgstr "" msgid "invalid cert" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 8faad5fb5de..b0ba572d438 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -592,6 +592,10 @@ ifneq ($(CIRCUITPY_AUDIOBUSIO),0) CHIP_COMPONENTS += esp_driver_i2s endif +ifneq ($(CIRCUITPY_AUDIOI2SIN),0) +CHIP_COMPONENTS += esp_driver_i2s +endif + ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) SRC_C += common-hal/_bleio/ble_events.c endif diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 1f458ec79a7..3dc0d227b3e 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -117,27 +117,39 @@ void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { // the sign bit for its width to convert to unsigned PCM (WAV convention). static void i2sin_convert_to_unsigned(void *buffer, uint32_t samples, uint8_t bit_depth, size_t element_size) { + (void)element_size; + uint32_t *p = (uint32_t *)buffer; + if (bit_depth == 8) { - uint8_t *p = (uint8_t *)buffer; - for (uint32_t i = 0; i < samples; i++) { - p[i] ^= 0x80u; + // 4 samples per word + uint32_t words = samples / 4; + for (uint32_t i = 0; i < words; i++) { + p[i] ^= 0x80808080u; + } + // tail: 0–3 leftover bytes + uint8_t *tail = (uint8_t *)(p + words); + for (uint32_t i = 0; i < (samples & 3u); i++) { + tail[i] ^= 0x80u; } } else if (bit_depth == 16) { - uint16_t *p = (uint16_t *)buffer; - for (uint32_t i = 0; i < samples; i++) { - p[i] ^= 0x8000u; + // 2 samples per word + uint32_t words = samples / 2; + for (uint32_t i = 0; i < words; i++) { + p[i] ^= 0x80008000u; + } + if (samples & 1u) { + ((uint16_t *)(p + words))[0] ^= 0x8000u; } } else { - // 24- or 32-bit; both stored in 32-bit slots (element_size == 4). - (void)element_size; - uint32_t mask = (bit_depth == 24) ? 0x800000u : 0x80000000u; - uint32_t *p = (uint32_t *)buffer; + // 24- or 32-bit: one sample per 32-bit slot + uint32_t mask = (bit_depth == 24) ? 0x00800000u : 0x80000000u; for (uint32_t i = 0; i < samples; i++) { p[i] ^= mask; } } } + uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t length) { size_t element_size = self->bit_depth / 8; diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 181ed219f2d..906ca0ed55c 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -227,6 +227,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, self->bit_depth = bit_depth; self->mono = mono; self->samples_signed = samples_signed; + self->left_justified = left_justified; self->settled = false; self->ring = NULL; self->ring_size = 0; @@ -322,6 +323,13 @@ static size_t i2sin_write_pos(audioi2sin_i2sin_obj_t *self) { return (size_t)(addr - base); } +// 24-bit non-left-justified data arrives in the low 24 bits of the FIFO word +// with the sign bit at bit 23 and bits 31..24 zero. To make it decode +// correctly as int32 (array typecode "i"), lift the sign bit to bit 31. +static inline uint32_t movesign24(uint32_t val) { + return ((val & 0x800000u) << 8) | (val & 0x7fffffu); +} + uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t output_buffer_length) { uint32_t output_count = 0; @@ -332,10 +340,13 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se // flip the sign bit per sample (XOR with 0x8000 for 16-bit, 0x800000 for // 24-bit data in a 32-bit slot, 0x80000000 for 32-bit), matching the WAV // convention. - const uint16_t flip16 = self->samples_signed ? 0 : 0x8000u; + const uint32_t flip16 = self->samples_signed ? 0u : 0x80008000u; const uint32_t flip32 = self->samples_signed ? 0u : (self->bit_depth == 24 ? 0x800000u : 0x80000000u); + const bool fix_sign24 = self->bit_depth == 24 + && self->samples_signed + && !self->left_justified; if (self->bit_depth == 16) { // 16-bit mode auto-pushes one stereo frame per FIFO word. The DMA has @@ -366,9 +377,9 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se continue; } while (avail >= 4 && output_count < output_buffer_length) { - uint32_t frame = *(volatile uint32_t *)(self->ring + self->read_pos); - uint16_t left = (uint16_t)(frame & 0xffff) ^ flip16; - uint16_t right = (uint16_t)(frame >> 16) ^ flip16; + uint32_t frame = *(volatile uint32_t *)(self->ring + self->read_pos) ^ flip16; + uint16_t left = (uint16_t)(frame & 0xffff); + uint16_t right = (uint16_t)(frame >> 16); if (self->mono) { output[output_count++] = left; } else { @@ -405,14 +416,7 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se self->settled = false; avail = (write_pos + ring_size - self->read_pos) % ring_size; } - if (!self->settled) { - if (avail < 8) { - RUN_BACKGROUND_TASKS; - if (mp_hal_is_interrupted()) { - return output_count; - } - continue; - } + if (!self->settled && avail >= 8) { self->read_pos = (self->read_pos + 8) % ring_size; avail -= 8; self->settled = true; @@ -428,6 +432,10 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se uint32_t right = *(volatile uint32_t *)(self->ring + self->read_pos) ^ flip32; size_t next_pos = (self->read_pos + 4) % ring_size; uint32_t left = *(volatile uint32_t *)(self->ring + next_pos) ^ flip32; + if (fix_sign24) { + right = movesign24(right); + left = movesign24(left); + } if (self->mono) { output[output_count++] = left; } else { diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h index 399d962afb2..bdd0529c94d 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -17,6 +17,7 @@ typedef struct { uint8_t bit_depth; bool mono; bool samples_signed; + bool left_justified; bool settled; rp2pio_statemachine_obj_t state_machine; // Background DMA ring buffer. The state machine alternates DMA writes diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index d8d8e3ebcc3..0cbdbdb49d3 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -44,9 +44,24 @@ //| :param ~microcontroller.Pin data: The data input pin //| :param ~microcontroller.Pin main_clock: The main clock pin. Not all ports support this. //| :param int sample_rate: Target sample rate of the resulting samples. Check `sample_rate` for actual value. -//| :param int bit_depth: Number of bits per sample. Must be 8, 16, 24, or 32. -//| For 8-bit, pass a ``bytearray`` or ``array.array('B', ...)``; for 16-bit, -//| ``array.array('H', ...)``; for 24- or 32-bit, ``array.array('I', ...)``. +//| :param int bit_depth: Number of bits per sample. Must be 8, 16, 24, or 32. 8-bit only supported on espressif. +//| +//| +----------------+-----------+----------------------+ +//| | samples_signed | bit_depth | Required typecode(s) | +//| +================+===========+======================+ +//| | True | 24 or 32 | ``'i'`` | +//| +----------------+-----------+----------------------+ +//| | True | 16 | ``'h'`` | +//| +----------------+-----------+----------------------+ +//| | True | 8 | ``'b'`` or BYTEARRAY | +//| +----------------+-----------+----------------------+ +//| | False | 24 or 32 | ``'I'`` | +//| +----------------+-----------+----------------------+ +//| | False | 16 | ``'H'`` | +//| +----------------+-----------+----------------------+ +//| | False | 8 | ``'B'`` or BYTEARRAY | +//| +----------------+-----------+----------------------+ +//| //| Note that 24-bit samples from mics like the SPH0645LM4H / INMP441 are //| transported in 32-bit slots, so use ``bit_depth=32`` and an ``'I'`` buffer. //| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise. @@ -62,10 +77,11 @@ //| import audioi2sin //| import board //| -//| buf = array.array("H", [0] * 16000) +//| buf = array.array("h", [0] * 16000) //| with audioi2sin.I2SIn(board.D9, board.D10, board.D11, //| sample_rate=16000, bit_depth=16) as mic: //| mic.record(buf, len(buf)) +//| //| """ //| ... //| @@ -165,12 +181,30 @@ static mp_obj_t audioi2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destinat mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); } uint8_t bit_depth = common_hal_audioi2sin_i2sin_get_bit_depth(self); - if ((bit_depth == 24 || bit_depth == 32) && bufinfo.typecode != 'I') { - mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'I' for bit_depth = 24 or 32")); - } else if (bit_depth == 16 && bufinfo.typecode != 'H') { - mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be an array of type 'H' for bit_depth = 16")); - } else if (bit_depth == 8 && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { - mp_raise_ValueError(MP_ERROR_TEXT("destination buffer must be a bytearray or array of type 'B' for bit_depth = 8")); + char error_type = ' '; + bool samples_signed = common_hal_audioi2sin_i2sin_get_samples_signed(self); + if (samples_signed) { + if ((bit_depth == 24 || bit_depth == 32) && bufinfo.typecode != 'i') { + error_type = 'i'; + } else if (bit_depth == 16 && bufinfo.typecode != 'h') { + error_type = 'h'; + } else if (bit_depth == 8 && bufinfo.typecode != 'b' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + error_type = 'b'; // NOTE: Not identifying as bytearray + } + } else { + if ((bit_depth == 24 || bit_depth == 32) && bufinfo.typecode != 'I') { + error_type = 'I'; + } else if (bit_depth == 16 && bufinfo.typecode != 'H') { + error_type = 'H'; + } else if (bit_depth == 8 && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + error_type = 'B'; + } + } + if (error_type != ' ') { + mp_raise_TypeError_varg( + MP_ERROR_TEXT("invalid destination buffer, must be an array of type: %c"), + error_type + ); } uint32_t length_written = common_hal_audioi2sin_i2sin_record_to_buffer(self, bufinfo.buf, length); diff --git a/tests/circuitpython-manual/audioi2sin/i2sin_neopixel_reactive.py b/tests/circuitpython-manual/audioi2sin/i2sin_neopixel_reactive.py index ac9c2c8ba0d..fc5559c70b1 100644 --- a/tests/circuitpython-manual/audioi2sin/i2sin_neopixel_reactive.py +++ b/tests/circuitpython-manual/audioi2sin/i2sin_neopixel_reactive.py @@ -39,15 +39,7 @@ left_justified=False, # set True for SPH0645LM4H ) -buf = array.array("I", [0] * SAMPLES_PER_FRAME) - - -def to_signed24(u32): - # The mic packs a 24-bit signed sample left-justified in 32 bits. - s = u32 >> 8 - if s & 0x800000: - s -= 0x1000000 - return s +buf = array.array("i", [0] * SAMPLES_PER_FRAME) def wheel(pos): @@ -72,8 +64,7 @@ def wheel(pos): # Compute RMS of the window. acc = 0 - for raw in buf: - s = to_signed24(raw) + for s in buf: acc += s * s rms = math.sqrt(acc / len(buf)) diff --git a/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py index 060df3dc1b7..c381e272bf7 100644 --- a/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py +++ b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard.py @@ -45,7 +45,7 @@ actual_rate = mic.sample_rate print("Recording at", actual_rate, "Hz for", RECORD_SECONDS, "s ->", OUTPUT_PATH) -raw = array.array("I", [0] * CHUNK_SAMPLES) +raw = array.array("i", [0] * CHUNK_SAMPLES) pcm16 = array.array("h", [0] * CHUNK_SAMPLES) @@ -90,8 +90,6 @@ def write_wav_header(f, sample_rate, num_samples, bits_per_sample=16, channels=1 for i in range(n): v = raw[i] s = v >> 16 # take top 16 bits - if s & 0x8000: - s -= 0x10000 # sign-extend pcm16[i] = s # Write only the valid portion. f.write(memoryview(pcm16)[:n]) From 4bfcd6c9dd21174e62531c70ba9b5709ac00b42f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 14 May 2026 14:02:33 -0500 Subject: [PATCH 489/876] disable audioi2sin for esp32c2 --- ports/espressif/mpconfigport.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 8396b89ee09..cc8e29cecca 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -133,6 +133,7 @@ CIRCUITPY_ANALOGBUFIO = 0 # No I2S CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 # No DAC CIRCUITPY_AUDIOIO = 0 From d293209a28018b51bffcb27df5e153e860af1eee Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 14 May 2026 16:21:16 -0700 Subject: [PATCH 490/876] Add P4X EV Function board def This includes fixes to the Makefile to support the v3 P4. --- ports/espressif/Makefile | 53 +++++++++-- .../espressif_esp32p4x_function_ev/board.c | 9 ++ .../mpconfigboard.h | 26 ++++++ .../mpconfigboard.mk | 16 ++++ .../espressif_esp32p4x_function_ev/pins.c | 90 +++++++++++++++++++ .../espressif_esp32p4x_function_ev/sdkconfig | 68 ++++++++++++++ 6 files changed, 256 insertions(+), 6 deletions(-) create mode 100644 ports/espressif/boards/espressif_esp32p4x_function_ev/board.c create mode 100644 ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.h create mode 100644 ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.mk create mode 100644 ports/espressif/boards/espressif_esp32p4x_function_ev/pins.c create mode 100644 ports/espressif/boards/espressif_esp32p4x_function_ev/sdkconfig diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 8faad5fb5de..1e2e26e28ef 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -209,6 +209,7 @@ REGISTRATION_FUNCTIONS = \ -u vfs_include_syscalls_impl \ -u esp_vfs_include_nullfs_register \ -u usb_serial_jtag_vfs_include_dev_init \ + -u usb_serial_jtag_connection_monitor_include \ -u esp_flash_spi_init_include_func \ -u pthread_include_pthread_impl \ -u pthread_include_pthread_cond_var_impl \ @@ -218,6 +219,39 @@ REGISTRATION_FUNCTIONS = \ -u esp_security_init_include_impl \ -u mbedtls_psa_crypto_init_include_impl +# RISC-V picolibc ships optimized memcpy/memset/etc. that need forcing +# (gated by CONFIG_LIBC_OPTIMIZED_MISALIGNED_ACCESS in IDF's esp_libc CMake). +ifeq ($(IDF_TARGET_ARCH),riscv) +REGISTRATION_FUNCTIONS += \ + -u esp_libc_include_memcpy_impl \ + -u esp_libc_include_memmove_impl \ + -u esp_libc_include_memcmp_impl \ + -u esp_libc_include_memset_impl \ + -u esp_libc_include_strcpy_impl \ + -u esp_libc_include_strncpy_impl \ + -u esp_libc_include_strcmp_impl \ + -u esp_libc_include_strncmp_impl +endif + +# Chips with PAU + TOP power-down (SOC_PAU_SUPPORTED && SOC_PM_SUPPORT_TOP_PD): +# C5, C6, C61, H2, H21, H4, P4. These pull in sleep_gpio + system-peripheral +# retention, and the SW-driven RISC-V CPU register save/restore path. +ifneq ($(filter $(IDF_TARGET),esp32c5 esp32c6 esp32c61 esp32h2 esp32h21 esp32h4 esp32p4),) +REGISTRATION_FUNCTIONS += \ + -u esp_sleep_gpio_include \ + -u sleep_system_peripheral_dummy \ + -u rv_core_critical_regs_save \ + -u rv_core_critical_regs_restore +endif + +# RISC-V chips with a hardware FPU (H4, P4) need FPU register save/restore +# alongside the CPU retention path. +ifneq ($(filter $(IDF_TARGET),esp32h4 esp32p4),) +REGISTRATION_FUNCTIONS += \ + -u rv_core_fpu_save \ + -u rv_core_fpu_restore +endif + #Debugging/Optimization ifeq ($(DEBUG), 1) @@ -245,6 +279,14 @@ endif # option to override compiler optimization level, set in boards/$(BOARD)/mpconfigboard.mk CFLAGS += $(OPTIMIZATION_FLAGS) +# Default ROM symbol maps; per-chip blocks below may override. +IDF_TARGET_ROM_LD ?= $(IDF_TARGET).rom.ld +# Floating-point/libgcc ROM map. IDF picks between libgcc and rvfp based on +# CONFIG_COMPILER_FLOAT_LIB_FROM_GCCLIB (rvfp xor libgcc, never both). Default +# to libgcc; targets that ship the rvfp variant in ROM (P4 in particular) +# override this. +IDF_TARGET_ROM_FLOAT_LD ?= $(IDF_TARGET).rom.libgcc.ld + CFLAGS += $(INC) -Werror -Wall -std=gnu11 -Wl,--gc-sections $(BASE_CFLAGS) $(C_DEFS) $(CFLAGS_MOD) $(COPT) -Werror=missing-prototypes -Werror=old-style-definition -Wno-error=cpp -Wno-cpp # ESP-IDF v6.0 uses picolibc instead of newlib. @@ -294,9 +336,9 @@ LDFLAGS += \ -Tmemory.ld \ -Tsections.ld \ -T$(IDF_TARGET).peripherals.ld \ - -T$(IDF_TARGET).rom.ld \ + -T$(IDF_TARGET_ROM_LD) \ -T$(IDF_TARGET).rom.api.ld \ - -T$(IDF_TARGET).rom.libgcc.ld \ + -T$(IDF_TARGET_ROM_FLOAT_LD) \ -Wl,-Bstatic \ -Wl,--no-warn-mismatch \ -Wl,--build-id=none \ @@ -406,19 +448,18 @@ CFLAGS += \ -isystem esp-idf/components/esp_driver_touch_sens/hw_ver3/include ifeq ($(CIRCUITPY_ESP32P4_REV),3) +IDF_TARGET_ROM_LD = esp32p4.rom.eco5.ld +IDF_TARGET_ROM_FLOAT_LD = esp32p4.rom.eco5.rvfp.ld LDFLAGS += \ - -Tesp32p4.rom.libc.ld \ -Tesp32p4.rom.systimer.ld \ - -Tesp32p4.rom.eco5.ld \ -Tesp32p4.rom.eco5.libc.ld \ - -Tesp32p4.rom.eco5.rvfp.ld \ -Tesp32p4.rom.version.ld \ -Trom.wdt.ld else +IDF_TARGET_ROM_FLOAT_LD = esp32p4.rom.rvfp.ld LDFLAGS += \ -Tesp32p4.rom.libc.ld \ -Tesp32p4.rom.systimer.ld \ - -Tesp32p4.rom.rvfp.ld \ -Tesp32p4.rom.version.ld \ -Trom.wdt.ld endif diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/board.c b/ports/espressif/boards/espressif_esp32p4x_function_ev/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.h b/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.h new file mode 100644 index 00000000000..d0b44fdff58 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "ESP32-P4X-Function-EV" +#define MICROPY_HW_MCU_NAME "ESP32P4" + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO38) +#define DEFAULT_UART_BUS_TX (&pin_GPIO37) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO8) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO7) + +// Use the second USB device (numbered 0 and 1) +#define CIRCUITPY_USB_DEVICE_INSTANCE 1 +#define CIRCUITPY_USB_DEVICE_HIGH_SPEED (1) + +#define CIRCUITPY_USB_HOST_INSTANCE 0 diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.mk new file mode 100644 index 00000000000..bad638a0018 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/mpconfigboard.mk @@ -0,0 +1,16 @@ +USB_VID = 0x303A +USB_PID = 0x7014 +USB_PRODUCT = "ESP32-P4X-Function-EV" +USB_MANUFACTURER = "Espressif" + +IDF_TARGET = esp32p4 + +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 32MB +CIRCUITPY_ESP_PSRAM_MODE = hpi +CIRCUITPY_ESP_PSRAM_FREQ = 200m + +CIRCUITPY_ESP32P4_REV = 3 diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/pins.c b/ports/espressif/boards/espressif_esp32p4x_function_ev/pins.c new file mode 100644 index 00000000000..165ce711b73 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/pins.c @@ -0,0 +1,90 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // Header Block J1 + { MP_ROM_QSTR(MP_QSTR_I2C_SDA), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_I2C_SCL), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_C6_WAKEUP), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + + { MP_ROM_QSTR(MP_QSTR_IO32), MP_ROM_PTR(&pin_GPIO32) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + + { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_C6_EN), MP_ROM_PTR(&pin_GPIO54) }, + { MP_ROM_QSTR(MP_QSTR_IO54), MP_ROM_PTR(&pin_GPIO54) }, + + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + + { MP_ROM_QSTR(MP_QSTR_PA_CTRL), MP_ROM_PTR(&pin_GPIO53) }, + { MP_ROM_QSTR(MP_QSTR_IO53), MP_ROM_PTR(&pin_GPIO53) }, + + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + + // I2S + { MP_ROM_QSTR(MP_QSTR_I2S_DSDIN), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_I2S_LRCK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2S_ASDOUT), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_I2S_SCLK), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_ROM_PTR(&pin_GPIO13) }, + + // Ethernet + { MP_ROM_QSTR(MP_QSTR_RMII_RXDV), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_RMII_RXD0), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_RMII_RXD1), MP_ROM_PTR(&pin_GPIO30) }, + { MP_ROM_QSTR(MP_QSTR_MDC), MP_ROM_PTR(&pin_GPIO31) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXD0), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXD1), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_RMII_TXEN), MP_ROM_PTR(&pin_GPIO49) }, + { MP_ROM_QSTR(MP_QSTR_RMII_CLK), MP_ROM_PTR(&pin_GPIO50) }, + { MP_ROM_QSTR(MP_QSTR_PHY_RSTN), MP_ROM_PTR(&pin_GPIO51) }, + { MP_ROM_QSTR(MP_QSTR_MDIO), MP_ROM_PTR(&pin_GPIO52) }, + + // SD Card + { MP_ROM_QSTR(MP_QSTR_SD_DATA0), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA1), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA2), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_SD_DATA3), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_SD_PWRN), MP_ROM_PTR(&pin_GPIO45) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32p4x_function_ev/sdkconfig b/ports/espressif/boards/espressif_esp32p4x_function_ev/sdkconfig new file mode 100644 index 00000000000..a062a5b5c48 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32p4x_function_ev/sdkconfig @@ -0,0 +1,68 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Bootloader config +# +# +# Log +# +CONFIG_BOOTLOADER_LOG_LEVEL_WARN=y +# CONFIG_BOOTLOADER_LOG_LEVEL_INFO is not set +# default: +CONFIG_BOOTLOADER_LOG_LEVEL=2 +# +# Format +# +# CONFIG_BOOTLOADER_LOG_COLORS is not set +# end of Format + +# end of Log + +# end of Bootloader config + +# +# Component config +# +# +# Bluetooth +# +# CONFIG_BT_ENABLED is not set +# end of Bluetooth + +# +# Hardware Settings +# +# +# Chip revision +# +# CONFIG_ESP32P4_REV_MIN_300 is not set +CONFIG_ESP32P4_REV_MIN_301=y +# default: +CONFIG_ESP32P4_REV_MIN_FULL=301 +# default: +CONFIG_ESP_REV_MIN_FULL=301 +# end of Chip revision + +# default: +CONFIG_P4_REV3_MSPI_CRASH_AFTER_POWER_UP_WORKAROUND=y +# default: +CONFIG_P4_REV3_MSPI_WORKAROUND_SIZE=0x100 +# end of Hardware Settings + +# +# ESP-STDIO +# +# CONFIG_ESP_CONSOLE_UART_DEFAULT is not set +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y +# default: +CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y +# default: +CONFIG_ESP_CONSOLE_UART_NUM=-1 +# default: +CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM=6 +# end of ESP-STDIO + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From 17615f7c2c7c5b59f30452cf46e61e12acbce14c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 14 May 2026 16:26:06 -0700 Subject: [PATCH 491/876] espressif: force-link init_coexist after IDF v6.0-dev move IDF commit ea84e9118d5 ("fix(esp_coex): move coex init from esp_system to esp_coex component", 2026-03-10, between v6.0-dev-5454 and current submodule HEAD v6.0-dev-5728) relocates the ESP_SYSTEM_INIT_FN entry init_coexist out of components/esp_system/startup_funcs.c and into components/esp_coex/src/coexist.c. It also adds an esp_coex_init_include_func hook and `target_link_libraries(... INTERFACE "-u esp_coex_init_include_func")` to esp_coex/CMakeLists.txt to force the linker to retain the new compilation unit. CircuitPython's ports/espressif/Makefile does its own final link (--start-group ... --end-group around the expanded .a list) and never consumes the INTERFACE link options that CMake emits for esp_coex, so the hook is dropped. With coexist.c.obj absent from the link, init_coexist never runs, esp_coex_adapter_register() and coex_pre_init() are skipped, and the ROM-side coex_schm_env_ptr stays NULL. The first wifi-init call to coex_schm_register_callback then dereferences NULL+0x10, panicking with a Load access fault (MEPC in ROM, MCAUSE=5, MTVAL=0x10, RA inside coex_schm_register_callback). Observed on espressif_esp32c6_devkitm_1_n4 during boot, right after `wifi:Init dynamic rx buffer num: 32`. Pre-IDF6 builds (e.g. the older S3 build still on IDF5) link init_coexist transitively through libesp_system.a and don't hit this. Add `-u esp_coex_init_include_func` to REGISTRATION_FUNCTIONS so our explicit -u list matches what esp_coex's CMakeLists.txt expects. Gate on CIRCUITPY_WIFI and skip esp32s2/esp32p4 because IDF's Kconfig only compiles coexist.c when ESP_COEX_SW_COEXIST_ENABLE is set ((WIFI && BT) || (WIFI && 802.15.4) || (BT && 802.15.4)); on those targets the symbol does not exist and the -u would fail to resolve. Co-Authored-By: Claude Opus 4.7 (1M context) --- ports/espressif/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 1e2e26e28ef..792444948ad 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -252,6 +252,12 @@ REGISTRATION_FUNCTIONS += \ -u rv_core_fpu_restore endif +ifneq ($(CIRCUITPY_WIFI),0) +ifeq ($(filter $(IDF_TARGET),esp32s2 esp32p4),) +REGISTRATION_FUNCTIONS += -u esp_coex_init_include_func +endif +endif + #Debugging/Optimization ifeq ($(DEBUG), 1) From dc155497741cd5cc02c997b464a599a8d88a85ab Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 15 May 2026 08:31:03 -0400 Subject: [PATCH 492/876] remove doc note about two microcontroller.reset() in quick succession --- shared-bindings/alarm/SleepMemory.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/shared-bindings/alarm/SleepMemory.c b/shared-bindings/alarm/SleepMemory.c index 5f66a429fbc..383c2a4e613 100644 --- a/shared-bindings/alarm/SleepMemory.c +++ b/shared-bindings/alarm/SleepMemory.c @@ -18,12 +18,6 @@ //| and deep sleep wake. Contents are lost when power is removed and restored, //| or on brown-out reset. //| -//| .. note:: -//| Programs that call ``microcontroller.reset()`` should wait at least -//| one second after boot before resetting, otherwise CircuitPython's -//| double-reset safe mode detector may activate. See -//| ``supervisor/shared/safe_mode.c``. -//| //| Note that this class can't be imported and used directly. The sole //| instance of :class:`SleepMemory` is available at //| :attr:`alarm.sleep_memory`. From 372829824071f62ce94bde2cb189fe595d6ced7c Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 15 May 2026 09:45:37 -0500 Subject: [PATCH 493/876] output_bit_depth argument --- locale/circuitpython.pot | 12 +- ports/espressif/common-hal/audioi2sin/I2SIn.c | 118 ++++++++++++- ports/espressif/common-hal/audioi2sin/I2SIn.h | 1 + .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 158 +++++++++++++++--- .../raspberrypi/common-hal/audioi2sin/I2SIn.h | 1 + shared-bindings/audioi2sin/I2SIn.c | 105 ++++++++---- shared-bindings/audioi2sin/I2SIn.h | 5 +- 7 files changed, 331 insertions(+), 69 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index b6af1d43f40..7788c683fc0 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -186,6 +186,10 @@ msgstr "" msgid "%q must be 1 when %q is True" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -1695,10 +1699,6 @@ msgstr "" msgid "Ok" msgstr "" -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "Only 16, 24, or 32 bit depth supported." -msgstr "" - #: ports/atmel-samd/common-hal/audiobusio/PDMIn.c #: ports/raspberrypi/common-hal/audiobusio/PDMIn.c #, c-format @@ -2702,6 +2702,10 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "bit_depth must be 16, 24, or 32" +msgstr "" + #: ports/espressif/common-hal/audiobusio/PDMIn.c #: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "bit_depth must be 8, 16, 24, or 32." diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 3dc0d227b3e..782b691e529 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -20,8 +20,8 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, - uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified, - bool samples_signed) { + uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, + bool mono, bool left_justified, bool samples_signed) { if (bit_depth != 8 && bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32.")); @@ -66,6 +66,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, self->mclk = main_clock; self->sample_rate = sample_rate; self->bit_depth = bit_depth; + self->output_bit_depth = output_bit_depth; self->mono = mono; self->samples_signed = samples_signed; @@ -113,6 +114,72 @@ void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { self->mclk = NULL; } +// Sign-extend a raw I2S sample (in the low `in_depth` bits of `raw`) to a +// canonical int32 value. +static inline int32_t i2sin_normalize_signed(uint32_t raw, uint8_t in_depth) { + if (in_depth == 32) { + return (int32_t)raw; + } + if (in_depth == 24) { + uint32_t sign_bit = 0x800000u; + return (int32_t)((raw ^ sign_bit) - sign_bit); + } + if (in_depth == 16) { + return (int16_t)(raw & 0xffffu); + } + return (int8_t)(raw & 0xffu); +} + +// Read a single sample from the DMA scratch at the given byte offset for the +// configured input bit depth. +static inline uint32_t i2sin_read_raw(const uint8_t *src, uint8_t in_depth) { + if (in_depth == 8) { + return (uint32_t)(*src); + } + if (in_depth == 16) { + uint16_t v; + memcpy(&v, src, sizeof(v)); + return v; + } + uint32_t v; + memcpy(&v, src, sizeof(v)); + return v; +} + +// Convert `raw` from `in_depth` to `out_depth` (shift-only semantics, sign- +// preserving for signed) and write it to `buffer` at sample index `idx`. +// Output element size: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. +static inline void i2sin_write_converted(void *buffer, uint32_t idx, + uint32_t raw, uint8_t in_depth, uint8_t out_depth, bool samples_signed) { + int32_t s = i2sin_normalize_signed(raw, in_depth); + int32_t shifted; + if (out_depth >= in_depth) { + shifted = (int32_t)((uint32_t)s << (out_depth - in_depth)); + } else { + shifted = s >> (in_depth - out_depth); + } + uint32_t u = (uint32_t)shifted; + if (!samples_signed) { + if (out_depth >= 32) { + u ^= 0x80000000u; + } else { + uint32_t mask = (1u << out_depth) - 1u; + u = (u & mask) ^ (1u << (out_depth - 1)); + } + } + switch (out_depth) { + case 8: + ((uint8_t *)buffer)[idx] = (uint8_t)(u & 0xffu); + break; + case 16: + ((uint16_t *)buffer)[idx] = (uint16_t)(u & 0xffffu); + break; + default: // 24 or 32 + ((uint32_t *)buffer)[idx] = u; + break; + } +} + // I2S delivers signed PCM. When samples_signed is false, XOR each sample with // the sign bit for its width to convert to unsigned PCM (WAV convention). static void i2sin_convert_to_unsigned(void *buffer, uint32_t samples, @@ -158,6 +225,49 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se element_size = 4; } + if (self->output_bit_depth != self->bit_depth) { + // Bit-depth conversion path: always read at input width into scratch, + // convert each sample into the user's buffer at output width. + const uint8_t in_depth = self->bit_depth; + const uint8_t out_depth = self->output_bit_depth; + const bool samples_signed = self->samples_signed; + uint8_t scratch[256]; + const size_t in_frame_bytes = 2 * element_size; + const size_t scratch_frames = sizeof(scratch) / in_frame_bytes; + uint32_t produced = 0; + while (produced < length) { + size_t want_frames; + if (self->mono) { + want_frames = length - produced; + } else { + want_frames = (length - produced + 1) / 2; + } + if (want_frames > scratch_frames) { + want_frames = scratch_frames; + } + size_t got_bytes = 0; + esp_err_t err = i2s_channel_read(self->rx_chan, scratch, + want_frames * in_frame_bytes, &got_bytes, portMAX_DELAY); + CHECK_ESP_RESULT(err); + size_t got_frames = got_bytes / in_frame_bytes; + for (size_t i = 0; i < got_frames && produced < length; i++) { + const uint8_t *frame = scratch + i * in_frame_bytes; + uint32_t left_raw = i2sin_read_raw(frame, in_depth); + i2sin_write_converted(buffer, produced++, left_raw, + in_depth, out_depth, samples_signed); + if (!self->mono && produced < length) { + uint32_t right_raw = i2sin_read_raw(frame + element_size, in_depth); + i2sin_write_converted(buffer, produced++, right_raw, + in_depth, out_depth, samples_signed); + } + } + if (got_frames < want_frames) { + break; + } + } + return produced; + } + uint32_t produced; if (!self->mono) { size_t result = 0; @@ -206,6 +316,10 @@ uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) return self->bit_depth; } +uint8_t common_hal_audioi2sin_i2sin_get_output_bit_depth(audioi2sin_i2sin_obj_t *self) { + return self->output_bit_depth; +} + uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self) { return self->sample_rate; } diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.h b/ports/espressif/common-hal/audioi2sin/I2SIn.h index 74e6eb83d0d..05b533ac89d 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.h +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.h @@ -23,6 +23,7 @@ typedef struct { const mcu_pin_obj_t *mclk; uint32_t sample_rate; uint8_t bit_depth; + uint8_t output_bit_depth; bool mono; bool samples_signed; } audioi2sin_i2sin_obj_t; diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 906ca0ed55c..b359b3f77fd 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -151,14 +151,14 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, - uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified, - bool samples_signed) { + uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, + bool mono, bool left_justified, bool samples_signed) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } if (bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("Only 16, 24, or 32 bit depth supported.")); + mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 16, 24, or 32")); } // 24- and 32-bit recordings both clock 32 bits per channel; 24-bit MEMS @@ -225,6 +225,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); self->sample_rate = actual_frequency / pio_clocks_per_frame; self->bit_depth = bit_depth; + self->output_bit_depth = output_bit_depth; self->mono = mono; self->samples_signed = samples_signed; self->left_justified = left_justified; @@ -292,6 +293,10 @@ uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) return self->bit_depth; } +uint8_t common_hal_audioi2sin_i2sin_get_output_bit_depth(audioi2sin_i2sin_obj_t *self) { + return self->output_bit_depth; +} + uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self) { return self->sample_rate; } @@ -330,6 +335,69 @@ static inline uint32_t movesign24(uint32_t val) { return ((val & 0x800000u) << 8) | (val & 0x7fffffu); } +// Sign-extend a raw FIFO sample to a canonical int32 value. `raw` holds the +// sample as delivered by the PIO program for the given input bit depth and +// alignment. The returned int32 represents the same magnitude with the sign +// bit at bit 31. +static inline int32_t i2sin_normalize_signed(uint32_t raw, uint8_t in_depth, + bool left_justified) { + if (in_depth == 32) { + return (int32_t)raw; + } + if (in_depth == 24) { + if (left_justified) { + // value in bits 31..8, sign at 31; arithmetic shift right 8 + return (int32_t)raw >> 8; + } + // value in bits 23..0, sign at 23 + uint32_t sign_bit = 0x800000u; + return (int32_t)((raw ^ sign_bit) - sign_bit); + } + // 16-bit: low 16 bits, sign at 15 + return (int16_t)(raw & 0xffffu); +} + +// Write `raw` (input-depth bits, just-read FIFO sample) to `buffer` at sample +// index `idx`, converting from `in_depth` to `out_depth` and (if needed) +// flipping the sign bit for the unsigned-WAV convention. Output element size +// follows `out_depth`: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. +// +// For signed 24-bit output, the int32 slot holds the sign-extended value +// (range -2^23 .. 2^23-1) — unlike the default `output_bit_depth=bit_depth=24` +// path which uses `movesign24`, the converted path returns proper two's +// complement so the result decodes correctly as int32. +static inline void i2sin_write_converted(void *buffer, uint32_t idx, + uint32_t raw, uint8_t in_depth, uint8_t out_depth, + bool samples_signed, bool left_justified) { + int32_t s = i2sin_normalize_signed(raw, in_depth, left_justified); + int32_t shifted; + if (out_depth >= in_depth) { + shifted = (int32_t)((uint32_t)s << (out_depth - in_depth)); + } else { + shifted = s >> (in_depth - out_depth); + } + uint32_t u = (uint32_t)shifted; + if (!samples_signed) { + if (out_depth >= 32) { + u ^= 0x80000000u; + } else { + uint32_t mask = (1u << out_depth) - 1u; + u = (u & mask) ^ (1u << (out_depth - 1)); + } + } + switch (out_depth) { + case 8: + ((uint8_t *)buffer)[idx] = (uint8_t)(u & 0xffu); + break; + case 16: + ((uint16_t *)buffer)[idx] = (uint16_t)(u & 0xffffu); + break; + default: // 24 or 32 + ((uint32_t *)buffer)[idx] = u; + break; + } +} + uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t output_buffer_length) { uint32_t output_count = 0; @@ -339,21 +407,29 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se // I2S delivers signed PCM. When the caller asked for unsigned samples, // flip the sign bit per sample (XOR with 0x8000 for 16-bit, 0x800000 for // 24-bit data in a 32-bit slot, 0x80000000 for 32-bit), matching the WAV - // convention. - const uint32_t flip16 = self->samples_signed ? 0u : 0x80008000u; - const uint32_t flip32 = self->samples_signed - ? 0u - : (self->bit_depth == 24 ? 0x800000u : 0x80000000u); - const bool fix_sign24 = self->bit_depth == 24 + // convention. The default (no-conversion) path applies the flip to the + // raw FIFO word before splitting into channels; the conversion path + // applies the flip per output sample at output bit width. + const bool convert = self->output_bit_depth != self->bit_depth; + const uint32_t flip16 = (!convert && !self->samples_signed) ? 0x80008000u : 0u; + const uint32_t flip32 = (!convert && !self->samples_signed) + ? (self->bit_depth == 24 ? 0x800000u : 0x80000000u) + : 0u; + const bool fix_sign24 = !convert + && self->bit_depth == 24 && self->samples_signed && !self->left_justified; + const uint8_t in_depth = self->bit_depth; + const uint8_t out_depth = self->output_bit_depth; + const bool left_justified = self->left_justified; + const bool samples_signed = self->samples_signed; if (self->bit_depth == 16) { // 16-bit mode auto-pushes one stereo frame per FIFO word. The DMA has // been streaming since construct time, so the ring already contains // settled data; drop the first 4 bytes once to discard a single // pre-record frame (matches the prior synchronous behaviour). - uint16_t *output = (uint16_t *)buffer; + uint16_t *output = convert ? NULL : (uint16_t *)buffer; while (output_count < output_buffer_length) { size_t write_pos = i2sin_write_pos(self); size_t avail = (write_pos + ring_size - self->read_pos) % ring_size; @@ -380,16 +456,30 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se uint32_t frame = *(volatile uint32_t *)(self->ring + self->read_pos) ^ flip16; uint16_t left = (uint16_t)(frame & 0xffff); uint16_t right = (uint16_t)(frame >> 16); - if (self->mono) { - output[output_count++] = left; + if (!convert) { + if (self->mono) { + output[output_count++] = left; + } else { + output[output_count++] = left; + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + break; + } + output[output_count++] = right; + } } else { - output[output_count++] = left; - if (output_count >= output_buffer_length) { - self->read_pos = (self->read_pos + 4) % ring_size; - avail -= 4; - break; + i2sin_write_converted(buffer, output_count++, left, + in_depth, out_depth, samples_signed, left_justified); + if (!self->mono) { + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 4) % ring_size; + avail -= 4; + break; + } + i2sin_write_converted(buffer, output_count++, right, + in_depth, out_depth, samples_signed, left_justified); } - output[output_count++] = right; } self->read_pos = (self->read_pos + 4) % ring_size; avail -= 4; @@ -403,7 +493,7 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se // counter and always read an even number of words. half_size is a // multiple of 8, so reading 8-byte pairs stays aligned across the // ring wrap. - uint32_t *output = (uint32_t *)buffer; + uint32_t *output = convert ? NULL : (uint32_t *)buffer; while (output_count < output_buffer_length) { size_t write_pos = i2sin_write_pos(self); size_t avail = (write_pos + ring_size - self->read_pos) % ring_size; @@ -436,16 +526,30 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se right = movesign24(right); left = movesign24(left); } - if (self->mono) { - output[output_count++] = left; + if (!convert) { + if (self->mono) { + output[output_count++] = left; + } else { + output[output_count++] = left; + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + break; + } + output[output_count++] = right; + } } else { - output[output_count++] = left; - if (output_count >= output_buffer_length) { - self->read_pos = (self->read_pos + 8) % ring_size; - avail -= 8; - break; + i2sin_write_converted(buffer, output_count++, left, + in_depth, out_depth, samples_signed, left_justified); + if (!self->mono) { + if (output_count >= output_buffer_length) { + self->read_pos = (self->read_pos + 8) % ring_size; + avail -= 8; + break; + } + i2sin_write_converted(buffer, output_count++, right, + in_depth, out_depth, samples_signed, left_justified); } - output[output_count++] = right; } self->read_pos = (self->read_pos + 8) % ring_size; avail -= 8; diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h index bdd0529c94d..525c72e3c5e 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -15,6 +15,7 @@ typedef struct { mp_obj_base_t base; uint32_t sample_rate; uint8_t bit_depth; + uint8_t output_bit_depth; bool mono; bool samples_signed; bool left_justified; diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 0cbdbdb49d3..f85daa01a34 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -28,6 +28,7 @@ //| main_clock: Optional[microcontroller.Pin] = None, //| sample_rate: int = 16000, //| bit_depth: int = 16, +//| output_bit_depth: Optional[int] = None, //| mono: bool = True, //| left_justified: bool = False, //| samples_signed: bool = True, @@ -44,26 +45,33 @@ //| :param ~microcontroller.Pin data: The data input pin //| :param ~microcontroller.Pin main_clock: The main clock pin. Not all ports support this. //| :param int sample_rate: Target sample rate of the resulting samples. Check `sample_rate` for actual value. -//| :param int bit_depth: Number of bits per sample. Must be 8, 16, 24, or 32. 8-bit only supported on espressif. +//| :param int bit_depth: Number of bits per sample on the I2S bus. Must be 8, 16, 24, or +//| 32. 8-bit only supported on espressif. The destination buffer typecode is determined +//| by ``output_bit_depth`` (or ``bit_depth`` when ``output_bit_depth`` is ``None``): //| -//| +----------------+-----------+----------------------+ -//| | samples_signed | bit_depth | Required typecode(s) | -//| +================+===========+======================+ -//| | True | 24 or 32 | ``'i'`` | -//| +----------------+-----------+----------------------+ -//| | True | 16 | ``'h'`` | -//| +----------------+-----------+----------------------+ -//| | True | 8 | ``'b'`` or BYTEARRAY | -//| +----------------+-----------+----------------------+ -//| | False | 24 or 32 | ``'I'`` | -//| +----------------+-----------+----------------------+ -//| | False | 16 | ``'H'`` | -//| +----------------+-----------+----------------------+ -//| | False | 8 | ``'B'`` or BYTEARRAY | -//| +----------------+-----------+----------------------+ +//| +----------------+------------------+----------------------+ +//| | samples_signed | output_bit_depth | Required typecode(s) | +//| +================+==================+======================+ +//| | True | 24 or 32 | ``'i'`` | +//| +----------------+------------------+----------------------+ +//| | True | 16 | ``'h'`` | +//| +----------------+------------------+----------------------+ +//| | True | 8 | ``'b'`` or BYTEARRAY | +//| +----------------+------------------+----------------------+ +//| | False | 24 or 32 | ``'I'`` | +//| +----------------+------------------+----------------------+ +//| | False | 16 | ``'H'`` | +//| +----------------+------------------+----------------------+ +//| | False | 8 | ``'B'`` or BYTEARRAY | +//| +----------------+------------------+----------------------+ //| //| Note that 24-bit samples from mics like the SPH0645LM4H / INMP441 are //| transported in 32-bit slots, so use ``bit_depth=32`` and an ``'I'`` buffer. +//| :param int output_bit_depth: If set, recorded samples are bit-shifted from +//| ``bit_depth`` to this width before being written to the destination buffer +//| (8, 16, 24, or 32). Widening pads the new LSBs with zero; narrowing arithmetic- +//| shifts the value right (sign-preserving when ``samples_signed`` is True). When +//| ``None`` (the default) the destination buffer holds samples at ``bit_depth``. //| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise. //| :param bool left_justified: True when data bits are aligned with the word select clock. False //| when they are shifted by one to match classic I2S protocol. Set True for mics like the SPH0645LM4H. @@ -91,17 +99,19 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar return NULL; // Not reachable. #else enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, - ARG_sample_rate, ARG_bit_depth, ARG_mono, ARG_left_justified, ARG_samples_signed }; + ARG_sample_rate, ARG_bit_depth, ARG_output_bit_depth, + ARG_mono, ARG_left_justified, ARG_samples_signed }; static const mp_arg_t allowed_args[] = { - { MP_QSTR_bit_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_word_select, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_main_clock, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_sample_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} }, - { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, - { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - { MP_QSTR_left_justified, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_samples_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_bit_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_word_select, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_main_clock, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_sample_rate, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16000} }, + { MP_QSTR_bit_depth, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 16} }, + { MP_QSTR_output_bit_depth, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_left_justified, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_samples_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -116,13 +126,24 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar if (bit_depth % 8 != 0) { mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be multiple of 8."), MP_QSTR_bit_depth); } + uint8_t output_bit_depth; + mp_obj_t output_bit_depth_obj = args[ARG_output_bit_depth].u_obj; + if (output_bit_depth_obj == mp_const_none) { + output_bit_depth = bit_depth; + } else { + mp_int_t v = mp_obj_get_int(output_bit_depth_obj); + if (v != 8 && v != 16 && v != 24 && v != 32) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be 8, 16, 24, or 32"), MP_QSTR_output_bit_depth); + } + output_bit_depth = (uint8_t)v; + } bool mono = args[ARG_mono].u_bool; bool left_justified = args[ARG_left_justified].u_bool; bool samples_signed = args[ARG_samples_signed].u_bool; audioi2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audioi2sin_i2sin_obj_t, &audioi2sin_i2sin_type); common_hal_audioi2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, - sample_rate, bit_depth, mono, left_justified, samples_signed); + sample_rate, bit_depth, output_bit_depth, mono, left_justified, samples_signed); return MP_OBJ_FROM_PTR(self); #endif @@ -180,23 +201,23 @@ static mp_obj_t audioi2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destinat if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); } - uint8_t bit_depth = common_hal_audioi2sin_i2sin_get_bit_depth(self); + uint8_t output_bit_depth = common_hal_audioi2sin_i2sin_get_output_bit_depth(self); char error_type = ' '; bool samples_signed = common_hal_audioi2sin_i2sin_get_samples_signed(self); if (samples_signed) { - if ((bit_depth == 24 || bit_depth == 32) && bufinfo.typecode != 'i') { + if ((output_bit_depth == 24 || output_bit_depth == 32) && bufinfo.typecode != 'i') { error_type = 'i'; - } else if (bit_depth == 16 && bufinfo.typecode != 'h') { + } else if (output_bit_depth == 16 && bufinfo.typecode != 'h') { error_type = 'h'; - } else if (bit_depth == 8 && bufinfo.typecode != 'b' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + } else if (output_bit_depth == 8 && bufinfo.typecode != 'b' && bufinfo.typecode != BYTEARRAY_TYPECODE) { error_type = 'b'; // NOTE: Not identifying as bytearray } } else { - if ((bit_depth == 24 || bit_depth == 32) && bufinfo.typecode != 'I') { + if ((output_bit_depth == 24 || output_bit_depth == 32) && bufinfo.typecode != 'I') { error_type = 'I'; - } else if (bit_depth == 16 && bufinfo.typecode != 'H') { + } else if (output_bit_depth == 16 && bufinfo.typecode != 'H') { error_type = 'H'; - } else if (bit_depth == 8 && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { + } else if (output_bit_depth == 8 && bufinfo.typecode != 'B' && bufinfo.typecode != BYTEARRAY_TYPECODE) { error_type = 'B'; } } @@ -240,6 +261,21 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_bit_depth_obj, audioi2sin_i2sin_o MP_PROPERTY_GETTER(audioi2sin_i2sin_bit_depth_obj, (mp_obj_t)&audioi2sin_i2sin_get_bit_depth_obj); +//| output_bit_depth: int +//| """The bit depth of samples written to the destination buffer. Equals ``bit_depth`` when +//| ``output_bit_depth`` was not supplied (or was ``None``) at construction time. (read-only)""" +//| +//| +static mp_obj_t audioi2sin_i2sin_obj_get_output_bit_depth(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return MP_OBJ_NEW_SMALL_INT(common_hal_audioi2sin_i2sin_get_output_bit_depth(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_output_bit_depth_obj, audioi2sin_i2sin_obj_get_output_bit_depth); + +MP_PROPERTY_GETTER(audioi2sin_i2sin_output_bit_depth_obj, + (mp_obj_t)&audioi2sin_i2sin_get_output_bit_depth_obj); + //| samples_signed: bool //| """True if recorded samples are signed PCM, False for unsigned. (read-only)""" //| @@ -262,6 +298,7 @@ static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&audioi2sin_i2sin_record_obj) }, { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioi2sin_i2sin_sample_rate_obj) }, { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_bit_depth_obj) }, + { MP_ROM_QSTR(MP_QSTR_output_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_output_bit_depth_obj) }, { MP_ROM_QSTR(MP_QSTR_samples_signed), MP_ROM_PTR(&audioi2sin_i2sin_samples_signed_obj) }, }; static MP_DEFINE_CONST_DICT(audioi2sin_i2sin_locals_dict, audioi2sin_i2sin_locals_dict_table); diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h index e75bdf2d34b..dc9c671741a 100644 --- a/shared-bindings/audioi2sin/I2SIn.h +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -18,13 +18,14 @@ extern const mp_obj_type_t audioi2sin_i2sin_type; void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, - uint32_t sample_rate, uint8_t bit_depth, bool mono, bool left_justified, - bool samples_signed); + uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, + bool mono, bool left_justified, bool samples_signed); void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t length); uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self); +uint8_t common_hal_audioi2sin_i2sin_get_output_bit_depth(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self); #endif From cf41db1900c4ea9e0c75d76a1aa1d9d6eaa8bc14 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 15 May 2026 09:46:39 -0500 Subject: [PATCH 494/876] output_bit_depth manual test --- .../i2sin_record_sdcard_output_bit_depth.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard_output_bit_depth.py diff --git a/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard_output_bit_depth.py b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard_output_bit_depth.py new file mode 100644 index 00000000000..cc2d2e78c29 --- /dev/null +++ b/tests/circuitpython-manual/audioi2sin/i2sin_record_sdcard_output_bit_depth.py @@ -0,0 +1,100 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +# +# SPDX-License-Identifier: MIT + +# Record a longer I2S audio capture to a WAV file on an SD card, using the +# `output_bit_depth` argument to have the driver downconvert each 32-bit slot +# to signed 16-bit PCM. Compared to `i2sin_record_sdcard.py`, this avoids the +# Python-side shift loop and writes directly from the recording buffer. +# +# Produces /sd/talk.wav. Set left_justified=True for SPH0645LM4H mics. + +import array +import struct +import time + +import board +import sdcardio +import storage +import audioi2sin + +# ---- Recording config ------------------------------------------------------ +SAMPLE_RATE = 16000 +RECORD_SECONDS = 10 +CHUNK_SAMPLES = 1024 # samples captured per record() call +OUTPUT_PATH = "/sd/talk.wav" + +# ---- Mount SD -------------------------------------------------------------- +spi = board.SPI() +sdcard = sdcardio.SDCard(spi, cs=board.D10, baudrate=24_000_000) +vfs = storage.VfsFat(sdcard) +storage.mount(vfs, "/sd") + +# ---- Mic ------------------------------------------------------------------- +# 24-bit MEMS mics ride in 32-bit slots. Ask the driver to downconvert each +# slot to a signed 16-bit PCM sample, so `record()` writes straight into a +# WAV-ready 'h' buffer. +mic = audioi2sin.I2SIn( + bit_clock=board.D5, + word_select=board.D6, + data=board.D9, + sample_rate=SAMPLE_RATE, + bit_depth=32, + output_bit_depth=16, + mono=True, + left_justified=False, # True for SPH0645LM4H +) + +actual_rate = mic.sample_rate +print("Recording at", actual_rate, "Hz for", RECORD_SECONDS, "s ->", OUTPUT_PATH) + +pcm16 = array.array("h", [0] * CHUNK_SAMPLES) + + +def write_wav_header(f, sample_rate, num_samples, bits_per_sample=16, channels=1): + byte_rate = sample_rate * channels * bits_per_sample // 8 + block_align = channels * bits_per_sample // 8 + data_size = num_samples * block_align + f.write(b"RIFF") + f.write(struct.pack(" Date: Fri, 15 May 2026 11:04:02 -0500 Subject: [PATCH 495/876] improve argument validation logic and error messages --- locale/circuitpython.pot | 11 +++++------ ports/espressif/common-hal/audioi2sin/I2SIn.c | 4 ---- ports/raspberrypi/common-hal/audioi2sin/I2SIn.c | 2 +- shared-bindings/audioi2sin/I2SIn.c | 4 ++-- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 7788c683fc0..20425d2d77f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -186,6 +186,10 @@ msgstr "" msgid "%q must be 1 when %q is True" msgstr "" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" msgstr "" @@ -223,7 +227,7 @@ msgstr "" msgid "%q must be array of type 'h'" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +#: shared-bindings/audiobusio/PDMIn.c msgid "%q must be multiple of 8." msgstr "" @@ -2702,12 +2706,7 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "bit_depth must be 16, 24, or 32" -msgstr "" - #: ports/espressif/common-hal/audiobusio/PDMIn.c -#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "bit_depth must be 8, 16, 24, or 32." msgstr "" diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 782b691e529..9953f221b7f 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -23,10 +23,6 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, bool mono, bool left_justified, bool samples_signed) { - if (bit_depth != 8 && bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { - mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32.")); - } - i2s_data_bit_width_t bit_width = (i2s_data_bit_width_t)bit_depth; i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER); diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index b359b3f77fd..0de4fe69b8c 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -158,7 +158,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } if (bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { - mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 16, 24, or 32")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be 16, 24, or 32"), MP_QSTR_bit_depth); } // 24- and 32-bit recordings both clock 32 bits per channel; 24-bit MEMS diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index f85daa01a34..16ba7bf76f3 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -123,8 +123,8 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar uint32_t sample_rate = args[ARG_sample_rate].u_int; uint8_t bit_depth = args[ARG_bit_depth].u_int; - if (bit_depth % 8 != 0) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be multiple of 8."), MP_QSTR_bit_depth); + if (bit_depth != 8 && bit_depth != 16 && bit_depth != 24 && bit_depth != 32) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be 8, 16, 24, or 32"), MP_QSTR_bit_depth); } uint8_t output_bit_depth; mp_obj_t output_bit_depth_obj = args[ARG_output_bit_depth].u_obj; From 1de9e9b3e5e9be7443670c56d31117cb09743933 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 16 May 2026 14:14:56 -0400 Subject: [PATCH 496/876] py/circuitpy_mpconfig.h: Turn on MICROPY_PY_DELATTR_SETATTR for CIRCUITPY_FULL_BUILD --- py/circuitpy_mpconfig.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 4b23784c541..381cb9538e4 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -262,6 +262,10 @@ typedef long mp_off_t; #define MICROPY_PY_COLLECTIONS_DEQUE_SUBSCR (CIRCUITPY_FULL_BUILD) #endif +#ifndef MICROPY_PY_DELATTR_SETATTR +#define MICROPY_PY_DELATTR_SETATTR (CIRCUITPY_FULL_BUILD) +#endif + #ifndef MICROPY_PY_DOUBLE_TYPECODE #define MICROPY_PY_DOUBLE_TYPECODE (CIRCUITPY_FULL_BUILD ? 1 : 0) #endif From 529c262e668299d53c6f506043def52d0b7274ff Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 16 May 2026 17:17:56 -0400 Subject: [PATCH 497/876] turn off picodvi on boards without available pins --- .../boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk | 3 +++ .../boards/adafruit_tinychad_rp2350/mpconfigboard.mk | 3 +++ .../boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk | 4 ++++ .../raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk | 3 +++ .../boards/cytron_motion_2350_pro/mpconfigboard.mk | 4 ++++ .../raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk | 3 +++ ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk | 3 +++ .../raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk | 3 +++ ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk | 3 +++ .../raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk | 3 +++ ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk | 3 +++ .../raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk | 3 +++ .../boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk | 3 +++ .../boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk | 2 ++ .../boards/studiolab_picoexpander/mpconfigboard.mk | 3 +++ .../boards/tinycircuits_thumby_color/mpconfigboard.mk | 3 +++ .../raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk | 3 +++ .../boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk | 3 +++ .../raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk | 3 +++ .../raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk | 3 +++ .../boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk | 3 +++ .../raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk | 3 +++ .../boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk | 3 +++ .../boards/wiznet_w5500_evb_pico2/mpconfigboard.mk | 3 +++ 24 files changed, 73 insertions(+) diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk index 88cce7c4a4c..6ab89398de7 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_feather_rp2350_adalogger/mpconfigboard.mk @@ -8,3 +8,6 @@ CHIP_PACKAGE = A CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ" + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk index 8d2a9c2f527..36359c88fe4 100644 --- a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/mpconfigboard.mk @@ -8,3 +8,6 @@ CHIP_PACKAGE = A CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ" + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk b/ports/raspberrypi/boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk index d4f2cdb90d0..7663bcfb19d 100644 --- a/ports/raspberrypi/boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk +++ b/ports/raspberrypi/boards/challenger_rp2350_wifi6_ble5/mpconfigboard.mk @@ -12,5 +12,9 @@ EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_ALARM = 0 +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + + FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_HID FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register diff --git a/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk index ac0bb6d6f27..75d49696a13 100644 --- a/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_edu_v2_pico_2w/mpconfigboard.mk @@ -21,6 +21,9 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ diff --git a/ports/raspberrypi/boards/cytron_motion_2350_pro/mpconfigboard.mk b/ports/raspberrypi/boards/cytron_motion_2350_pro/mpconfigboard.mk index 0ac939ce6a2..9a766f42da7 100644 --- a/ports/raspberrypi/boards/cytron_motion_2350_pro/mpconfigboard.mk +++ b/ports/raspberrypi/boards/cytron_motion_2350_pro/mpconfigboard.mk @@ -11,6 +11,10 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY__EVE = 1 +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + + # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Motor diff --git a/ports/raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk b/ports/raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk index 1b5c6c5d548..42d747537af 100644 --- a/ports/raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk +++ b/ports/raspberrypi/boards/datanoise_picoadk_v2/mpconfigboard.mk @@ -9,5 +9,8 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q32C,W25Q32JVxQ" +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + # Include these Python libraries in firmware. FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD diff --git a/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk index 0157ccf1499..58f88af2518 100644 --- a/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_badger2350/mpconfigboard.mk @@ -19,6 +19,9 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + # PIO clock divider set to 2 (default), consider changing if TM2 gSPI # becomes unreliable. CFLAGS += \ diff --git a/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk index 4e4882910c8..4409dbf57df 100644 --- a/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_explorer2350/mpconfigboard.mk @@ -8,3 +8,6 @@ CHIP_PACKAGE = B CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +# GPIO12-19 needed for picodvi, but several are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk index 56fd7b641de..52dcd3fbe71 100644 --- a/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_plasma2350/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk index 8563f0d0034..cab35965a0f 100644 --- a/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_plasma2350w/mpconfigboard.mk @@ -21,6 +21,9 @@ CIRCUITPY_WIFI = 1 CIRCUITPY_PICODVI = 0 CIRCUITPY_USB_HOST = 0 +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 + CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ diff --git a/ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk index 9ffdf263003..b94022c1f6d 100644 --- a/ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_tiny2350/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but several are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk index d5f866bd89e..f51d5271215 100644 --- a/ports/raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/seeeduino_xiao_rp2350/mpconfigboard.mk @@ -8,3 +8,6 @@ CHIP_PACKAGE = A CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "P25Q16H" + +# GPIO12-19 needed for picodvi, but several are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk index e5d6e1b8ff8..53cdf72963f 100644 --- a/ports/raspberrypi/boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/sparkfun_pro_micro_rp2350/mpconfigboard.mk @@ -8,3 +8,6 @@ CHIP_PACKAGE = A CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk index 6e81a229961..81d7f660473 100644 --- a/ports/raspberrypi/boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/sparkfun_thing_plus_rp2350/mpconfigboard.mk @@ -23,6 +23,8 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 +# GPIO12-19 needed for picodvi, but GPIO14 is used for a NeoPixel. +CIRCUITPY_PICODVI = 0 CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ diff --git a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk index eabc2c41e07..7214b36da28 100644 --- a/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk +++ b/ports/raspberrypi/boards/studiolab_picoexpander/mpconfigboard.mk @@ -19,6 +19,9 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 +# GPIO12-19 needed for picodvi, but GPIO15 is used for a button. +CIRCUITPY_PICODVI = 0 + CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ diff --git a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk index 828d4a638d5..6159a39ba55 100644 --- a/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk +++ b/ports/raspberrypi/boards/tinycircuits_thumby_color/mpconfigboard.mk @@ -13,3 +13,6 @@ CIRCUITPY_STAGE = 1 CIRCUITPY_AUDIOIO = 1 CIRCUITPY_AUDIOPWMIO = 1 CIRCUITPY_KEYPAD = 1 + +# GPIO12-19 needed for picodvi, but many are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk index 38b69c182c7..e1d89c1fbca 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_geek/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but many of the pins are used for other purposes. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk index 8f703c5a932..f04b91f8b0d 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_lcd_1_28/mpconfigboard.mk @@ -11,6 +11,9 @@ EXTERNAL_FLASH_DEVICES = "P25Q32SH" CIRCUITPY__EVE = 1 +# GPIO12-19 needed for picodvi, but GPIO12 is used for display reset. +CIRCUITPY_PICODVI = 0 + # TODO: Add custom QMI8658 driver # FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython_qmi8658 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk index 75398b3269b..bde7153c029 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_one/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but GPIO16 is not broken out and is used for NeoPixel. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk index 464c7aff283..79fafbacf5c 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_tiny/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "P25Q32SH" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but GPIO16-19 are not available. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk index 11e927c7485..0ec6c4ec008 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_touch_lcd_1_28/mpconfigboard.mk @@ -11,6 +11,9 @@ EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" CIRCUITPY__EVE = 1 +# GPIO12-19 needed for picodvi, but GPIO12 is used for display reset. +CIRCUITPY_PICODVI = 0 + # TODO: Add custom QMI8658 driver # FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython_qmi8658 diff --git a/ports/raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk b/ports/raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk index 444850776a6..7f0a3c71cbb 100644 --- a/ports/raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk +++ b/ports/raspberrypi/boards/waveshare_rp2350_zero/mpconfigboard.mk @@ -10,3 +10,6 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "P25Q32SH" CIRCUITPY__EVE = 1 + +# GPIO12-19 needed for picodvi, but GPIO16 is not broken out and is used for NeoPixel. +CIRCUITPY_PICODVI = 0 diff --git a/ports/raspberrypi/boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk index 3e3542120e3..d47571e7950 100644 --- a/ports/raspberrypi/boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk +++ b/ports/raspberrypi/boards/wiznet_w5100s_evb_pico2/mpconfigboard.mk @@ -12,5 +12,8 @@ EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_SSL = 1 +# GPIO12-19 needed for picodvi, but GPIO16 is used for Wiznet. +CIRCUITPY_PICODVI = 0 + # The default is -O3. Change to -O2 because the build was overflowing. OPTIMIZATION_FLAGS = -O2 diff --git a/ports/raspberrypi/boards/wiznet_w5500_evb_pico2/mpconfigboard.mk b/ports/raspberrypi/boards/wiznet_w5500_evb_pico2/mpconfigboard.mk index c10c7aa7eb8..68b621fdf97 100644 --- a/ports/raspberrypi/boards/wiznet_w5500_evb_pico2/mpconfigboard.mk +++ b/ports/raspberrypi/boards/wiznet_w5500_evb_pico2/mpconfigboard.mk @@ -12,5 +12,8 @@ EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_SSL = 1 +# GPIO12-19 needed for picodvi, but GPIO16 is used for Wiznet. +CIRCUITPY_PICODVI = 0 + # The default is -O3. Change to -O2 because the build was overflowing. OPTIMIZATION_FLAGS = -O2 From ee9f3e1f0fafde5bceebd370e47be62191d7cc3b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 16 May 2026 18:00:46 -0400 Subject: [PATCH 498/876] adafruit_tinychad_rp2350: remove picodvi startup on boot --- ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c index fddd2572c1f..cfa2308f796 100644 --- a/ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c +++ b/ports/raspberrypi/boards/adafruit_tinychad_rp2350/board.c @@ -10,7 +10,3 @@ #include "common-hal/picodvi/__init__.h" // Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. - -void board_init(void) { - picodvi_autoconstruct(); -} From bde53c8c5e25c380ca2524daf771b55ff1fcd428 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 17 May 2026 13:14:44 -0400 Subject: [PATCH 499/876] use #if PICO_RP2040 and #if PICO_RP2350, not #ifdef --- ports/raspberrypi/Makefile | 5 ++--- ports/raspberrypi/audio_dma.c | 8 ++++---- ports/raspberrypi/common-hal/busio/UART.c | 4 ++-- ports/raspberrypi/common-hal/memorymap/AddressRange.c | 4 ++-- ports/raspberrypi/common-hal/microcontroller/Processor.c | 8 ++++---- ports/raspberrypi/common-hal/microcontroller/__init__.c | 2 +- ports/raspberrypi/common-hal/picodvi/Framebuffer.h | 2 +- ports/raspberrypi/common-hal/usb_host/Port.c | 4 ++-- ports/raspberrypi/mpconfigport.h | 4 ++-- ports/raspberrypi/supervisor/internal_flash.c | 2 +- ports/raspberrypi/supervisor/port.c | 8 ++++---- 11 files changed, 25 insertions(+), 26 deletions(-) diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index cef2806c874..d2c550c90fa 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -407,8 +407,7 @@ CFLAGS += \ -msoft-float \ -mfloat-abi=soft -CFLAGS += \ - -DPICO_RP2040 +CFLAGS += -DPICO_RP2040=1 -DPICO_RP2350=0 SRC_SDK_CHIP_VARIANT := \ src/rp2_common/hardware_rtc/rtc.c \ @@ -451,7 +450,7 @@ DOUBLE_EABI = dcp INC += \ -isystem sdk/src/rp2_common/hardware_dcp/include/ -CFLAGS += -DPICO_RP2350=1 +CFLAGS += -DPICO_RP2040=0 -DPICO_RP2350=1 SRC_SDK_CHIP_VARIANT := \ src/rp2_common/hardware_powman/powman.c \ diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index ae3997a128f..03d98ae876a 100644 --- a/ports/raspberrypi/audio_dma.c +++ b/ports/raspberrypi/audio_dma.c @@ -233,7 +233,7 @@ audio_dma_result audio_dma_setup_playback( max_buffer_length /= dma->sample_spacing; } - #ifdef PICO_RP2350 + #if PICO_RP2350 dma->buffer[0] = (uint8_t *)port_realloc(dma->buffer[0], max_buffer_length, true); #else dma->buffer[0] = (uint8_t *)m_realloc(dma->buffer[0], @@ -249,7 +249,7 @@ audio_dma_result audio_dma_setup_playback( } if (!single_buffer) { - #ifdef PICO_RP2350 + #if PICO_RP2350 dma->buffer[1] = (uint8_t *)port_realloc(dma->buffer[1], max_buffer_length, true); #else dma->buffer[1] = (uint8_t *)m_realloc(dma->buffer[1], @@ -460,7 +460,7 @@ void audio_dma_init(audio_dma_t *dma) { } void audio_dma_deinit(audio_dma_t *dma) { - #ifdef PICO_RP2350 + #if PICO_RP2350 port_free(dma->buffer[0]); #else #if MICROPY_MALLOC_USES_ALLOCATED_SIZE @@ -472,7 +472,7 @@ void audio_dma_deinit(audio_dma_t *dma) { dma->buffer[0] = NULL; dma->buffer_length[0] = 0; - #ifdef PICO_RP2350 + #if PICO_RP2350 port_free(dma->buffer[1]); #else #if MICROPY_MALLOC_USES_ALLOCATED_SIZE diff --git a/ports/raspberrypi/common-hal/busio/UART.c b/ports/raspberrypi/common-hal/busio/UART.c index 17fcfa17229..074c78c2f4a 100644 --- a/ports/raspberrypi/common-hal/busio/UART.c +++ b/ports/raspberrypi/common-hal/busio/UART.c @@ -50,7 +50,7 @@ static void pin_check(const uint8_t uart, const mcu_pin_obj_t *pin, const uint8_ if (pins_uart != uart) { raise_ValueError_invalid_pins(); } - #ifdef PICO_RP2350 + #if PICO_RP2350 if ((pin_type == 0 && pin->number % 4 == 2) || (pin_type == 1 && pin->number % 4 == 3)) { return; @@ -67,7 +67,7 @@ static uint8_t pin_init(const uint8_t uart, const mcu_pin_obj_t *pin, const uint } claim_pin(pin); gpio_function_t function = GPIO_FUNC_UART; - #ifdef PICO_RP2350 + #if PICO_RP2350 if ((pin_type == 0 && pin->number % 4 == 2) || (pin_type == 1 && pin->number % 4 == 3)) { function = GPIO_FUNC_UART_AUX; diff --git a/ports/raspberrypi/common-hal/memorymap/AddressRange.c b/ports/raspberrypi/common-hal/memorymap/AddressRange.c index 0796a3b860b..a5e860cb40c 100644 --- a/ports/raspberrypi/common-hal/memorymap/AddressRange.c +++ b/ports/raspberrypi/common-hal/memorymap/AddressRange.c @@ -14,7 +14,7 @@ #include "hardware/regs/addressmap.h" // RP2 address map ranges, must be arranged in order by ascending start address -#ifdef PICO_RP2040 +#if PICO_RP2040 addressmap_rp2_range_t rp2_ranges[] = { {(uint8_t *)ROM_BASE, 0x00004000, ROM}, // boot ROM {(uint8_t *)XIP_BASE, 0x00100000, XIP}, // XIP normal cache operation @@ -36,7 +36,7 @@ addressmap_rp2_range_t rp2_ranges[] = { {(uint8_t *)PPB_BASE, 0x00004000, IO} // PPB registers }; #endif -#ifdef PICO_RP2350 +#if PICO_RP2350 addressmap_rp2_range_t rp2_ranges[] = { {(uint8_t *)ROM_BASE, 0x00004000, ROM}, // boot ROM {(uint8_t *)XIP_BASE, 0x00100000, XIP}, // XIP normal cache operation diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.c b/ports/raspberrypi/common-hal/microcontroller/Processor.c index a3ea890d9af..5a4e7071544 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.c +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.c @@ -20,11 +20,11 @@ #include "hardware/vreg.h" #include "hardware/watchdog.h" -#ifdef PICO_RP2040 +#if PICO_RP2040 #include "hardware/regs/vreg_and_chip_reset.h" #include "hardware/structs/vreg_and_chip_reset.h" #endif -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "hardware/regs/powman.h" #include "hardware/structs/powman.h" #endif @@ -80,7 +80,7 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { mcu_reset_reason_t reason = RESET_REASON_UNKNOWN; - #ifdef PICO_RP2040 + #if PICO_RP2040 uint32_t chip_reset_reg = vreg_and_chip_reset_hw->chip_reset; if (chip_reset_reg & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) { @@ -96,7 +96,7 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { reason = RESET_REASON_POWER_ON; } #endif - #ifdef PICO_RP2350 + #if PICO_RP2350 uint32_t chip_reset_reg = powman_hw->chip_reset; if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) { diff --git a/ports/raspberrypi/common-hal/microcontroller/__init__.c b/ports/raspberrypi/common-hal/microcontroller/__init__.c index e287e551710..49dbc6082b0 100644 --- a/ports/raspberrypi/common-hal/microcontroller/__init__.c +++ b/ports/raspberrypi/common-hal/microcontroller/__init__.c @@ -30,7 +30,7 @@ void common_hal_mcu_delay_us(uint32_t delay) { } volatile uint32_t nesting_count = 0; -#ifdef PICO_RP2040 +#if PICO_RP2040 void common_hal_mcu_disable_interrupts(void) { // We don't use save_and_disable_interrupts() from the sdk because we don't want to worry about PRIMASK. // This is what we do on the SAMD21 via CMSIS. diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer.h b/ports/raspberrypi/common-hal/picodvi/Framebuffer.h index 50288578590..82c0b189b89 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer.h +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer.h @@ -6,7 +6,7 @@ #pragma once -#ifdef PICO_RP2040 +#if PICO_RP2040 #include "Framebuffer_RP2040.h" #else #include "Framebuffer_RP2350.h" diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c index b8a49725030..36f255df021 100644 --- a/ports/raspberrypi/common-hal/usb_host/Port.c +++ b/ports/raspberrypi/common-hal/usb_host/Port.c @@ -13,10 +13,10 @@ #include "pico/time.h" #include "hardware/structs/mpu.h" -#ifdef PICO_RP2040 +#if PICO_RP2040 #include "RP2040.h" // (cmsis) #endif -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "RP2350.h" // (cmsis) #endif #include "hardware/dma.h" diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index c4253937c98..d0802b25f00 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -8,11 +8,11 @@ #include "hardware/platform_defs.h" -#ifdef PICO_RP2040 +#if PICO_RP2040 #define MICROPY_PY_SYS_PLATFORM "RP2040" #endif -#ifdef PICO_RP2350 +#if PICO_RP2350 #define MICROPY_PY_SYS_PLATFORM "RP2350" // PSRAM can require more stack space for GC. diff --git a/ports/raspberrypi/supervisor/internal_flash.c b/ports/raspberrypi/supervisor/internal_flash.c index 9d5e13348aa..07b15564c60 100644 --- a/ports/raspberrypi/supervisor/internal_flash.c +++ b/ports/raspberrypi/supervisor/internal_flash.c @@ -23,7 +23,7 @@ #include "supervisor/flash.h" #include "supervisor/usb.h" -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "hardware/structs/qmi.h" #endif #include "hardware/structs/sio.h" diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 0316e34ad95..0335ba74d6f 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -53,7 +53,7 @@ #include "pico/bootrom.h" #include "hardware/watchdog.h" -#ifdef PICO_RP2350 +#if PICO_RP2350 #include "RP2350.h" // CMSIS #endif @@ -336,10 +336,10 @@ safe_mode_t port_init(void) { // Load from the XIP memory space that doesn't cache. That way we don't // evict anything else. The code we're loading is linked to the RAM address // anyway. - #ifdef PICO_RP2040 + #if PICO_RP2040 size_t nocache = 0x03000000; #endif - #ifdef PICO_RP2350 + #if PICO_RP2350 size_t nocache = 0x04000000; #endif @@ -547,7 +547,7 @@ void port_interrupt_after_ticks(uint32_t ticks) { } void port_idle_until_interrupt(void) { - #ifdef PICO_RP2040 + #if PICO_RP2040 common_hal_mcu_disable_interrupts(); #if CIRCUITPY_USB_HOST if (!background_callback_pending() && !tud_task_event_ready() && !tuh_task_event_ready() && !_woken_up) { From fc0c196a10e34115faf098dd3219e2ea7db8dc2f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 18 May 2026 09:52:35 -0400 Subject: [PATCH 500/876] simplify startup message printing --- main.c | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/main.c b/main.c index ce058cc49c4..f4b2bf8b362 100644 --- a/main.c +++ b/main.c @@ -441,17 +441,6 @@ static void print_code_py_status_message(safe_mode_t safe_mode) { } static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *simulate_reset) { - bool serial_connected_at_start = serial_connected(); - bool printed_safe_mode_message = false; - #if CIRCUITPY_AUTORELOAD_DELAY_MS > 0 - if (serial_connected_at_start) { - serial_write("\r\n"); - print_code_py_status_message(safe_mode); - print_safe_mode_message(safe_mode); - printed_safe_mode_message = true; - } - #endif - bool skip_repl = false; bool skip_wait = false; bool found_main = false; @@ -651,20 +640,13 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s // If messages haven't been printed yet, print them if (!printed_press_any_key && serial_connected() && !autoreload_pending()) { - if (!serial_connected_at_start) { - print_code_py_status_message(safe_mode); - } - - if (!printed_safe_mode_message) { - print_safe_mode_message(safe_mode); - printed_safe_mode_message = true; - } + print_code_py_status_message(safe_mode); + print_safe_mode_message(safe_mode); serial_write("\r\n"); serial_write_compressed(MP_ERROR_TEXT("Press any key to enter the REPL. Use CTRL-D to reload.\n")); printed_press_any_key = true; } if (!serial_connected()) { - serial_connected_at_start = false; printed_press_any_key = false; } From 359788210b84e1bcef02c765e6ce47ee4dc7cb3d Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 12 May 2026 13:49:46 -0700 Subject: [PATCH 501/876] Update Zephyr to post-4.4.0 --- lib/AnimatedGIF/gif.c | 2 +- lib/mbedtls_config/crt_bundle.c | 9 +++++++++ ports/zephyr-cp/Makefile | 3 +++ ports/zephyr-cp/boards/frdm_rw612.conf | 7 +------ .../native/native_sim/autogen_board_info.toml | 2 +- ports/zephyr-cp/boards/native_sim.conf | 4 ++-- .../boards/nrf7002dk_nrf5340_cpuapp.conf | 1 - .../boards/rpi_pico2_rp2350a_m33_w.conf | 7 +------ ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf | 7 +------ ports/zephyr-cp/common-hal/busio/UART.h | 4 ++++ ports/zephyr-cp/common-hal/usb_cdc/Serial.c | 1 + .../common-hal/wifi/ScannedNetworks.c | 1 + .../zephyr-cp/cptools/build_circuitpython.py | 14 ++++++++++++- ports/zephyr-cp/cptools/zephyr2cp.py | 19 ++++++++++++++++++ ports/zephyr-cp/prj.conf | 6 ++++-- ports/zephyr-cp/supervisor/port.c | 3 ++- .../terminal_console_output_320x240.mask.png | Bin 450 -> 453 bytes ports/zephyr-cp/zephyr-config/west.yml | 2 +- py/mpconfig.h | 8 ++++++-- shared-bindings/_bleio/CharacteristicBuffer.c | 2 +- shared-bindings/busio/UART.c | 2 +- shared-bindings/jpegio/JpegDecoder.c | 2 +- shared-bindings/socketpool/Socket.c | 2 +- shared-bindings/ssl/SSLSocket.c | 2 +- shared-bindings/terminalio/Terminal.c | 2 +- shared-bindings/usb_cdc/Serial.c | 2 +- shared-bindings/usb_midi/PortIn.c | 2 +- shared-bindings/usb_midi/PortOut.c | 2 +- supervisor/shared/workflow.c | 8 +++++--- 29 files changed, 84 insertions(+), 42 deletions(-) diff --git a/lib/AnimatedGIF/gif.c b/lib/AnimatedGIF/gif.c index 0822b608c18..316fc1ab749 100644 --- a/lib/AnimatedGIF/gif.c +++ b/lib/AnimatedGIF/gif.c @@ -23,7 +23,7 @@ // #include "AnimatedGIF_circuitpy.h" -#ifdef HAL_ESP32_HAL_H_ +#ifndef memcpy_P #define memcpy_P memcpy #endif diff --git a/lib/mbedtls_config/crt_bundle.c b/lib/mbedtls_config/crt_bundle.c index 9c546a26883..4a8836fb586 100644 --- a/lib/mbedtls_config/crt_bundle.c +++ b/lib/mbedtls_config/crt_bundle.c @@ -74,12 +74,14 @@ static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_b } + #if MBEDTLS_VERSION_MAJOR < 4 // Fast check to avoid expensive computations when not necessary if (!mbedtls_pk_can_do(&parent.pk, child->MBEDTLS_PRIVATE(sig_pk))) { LOGE(TAG, "Simple compare failed"); ret = -1; goto cleanup; } + #endif md_info = mbedtls_md_info_from_type(child->MBEDTLS_PRIVATE(sig_md)); if ((ret = mbedtls_md(md_info, child->tbs.p, child->tbs.len, hash)) != 0) { @@ -87,10 +89,17 @@ static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_b goto cleanup; } + #if MBEDTLS_VERSION_MAJOR >= 4 + if ((ret = mbedtls_pk_verify_ext( + child->MBEDTLS_PRIVATE(sig_pk), &parent.pk, + child->MBEDTLS_PRIVATE(sig_md), hash, mbedtls_md_get_size(md_info), + child->MBEDTLS_PRIVATE(sig).p, child->MBEDTLS_PRIVATE(sig).len)) != 0) { + #else if ((ret = mbedtls_pk_verify_ext( child->MBEDTLS_PRIVATE(sig_pk), child->MBEDTLS_PRIVATE(sig_opts), &parent.pk, child->MBEDTLS_PRIVATE(sig_md), hash, mbedtls_md_get_size(md_info), child->MBEDTLS_PRIVATE(sig).p, child->MBEDTLS_PRIVATE(sig).len)) != 0) { + #endif LOGE(TAG, "PK verify failed with error %X", ret); goto cleanup; diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index 12f22d7c3ae..ab730a8b339 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -23,6 +23,9 @@ endif .PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug debug-jlink debugserver attach run run-sim clean menuconfig all clean-all sim clean-sim test fetch-port-submodules +export BSIM_COMPONENTS_PATH := $(CURDIR)/tools/bsim/components +export BSIM_OUT_PATH := $(CURDIR)/tools/bsim + $(BUILD)/zephyr-cp/zephyr/zephyr.elf: python cptools/pre_zephyr_build_prep.py $(BOARD) west build -b $(BOARD) -d $(BUILD) $(WEST_SHIELD_ARGS) --sysbuild -- $(WEST_CMAKE_ARGS) diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf index ac9a43646a1..c06f78ae830 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.conf +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -14,14 +14,9 @@ CONFIG_NET_HOSTNAME="circuitpython" CONFIG_MBEDTLS=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y -CONFIG_MBEDTLS_RSA_C=y -CONFIG_MBEDTLS_PKCS1_V15=y -CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=y +CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y CONFIG_MBEDTLS_ENTROPY_C=y -CONFIG_MBEDTLS_CIPHER_AES_ENABLED=y CONFIG_MBEDTLS_CTR_DRBG_C=y -CONFIG_MBEDTLS_SHA1=y -CONFIG_MBEDTLS_USE_PSA_CRYPTO=n CONFIG_BT=y CONFIG_BT_PERIPHERAL=y diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 4cc9f3e934c..b565e8b139f 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -94,7 +94,7 @@ sharpdisplay = true # Zephyr board has busio socketpool = true # Zephyr networking enabled spitarget = false ssl = false -storage = true # Zephyr board has flash +storage = true struct = true supervisor = true synthio = true # Zephyr board has audiobusio diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native_sim.conf index e02cd0ac84e..00af0d01ac6 100644 --- a/ports/zephyr-cp/boards/native_sim.conf +++ b/ports/zephyr-cp/boards/native_sim.conf @@ -39,5 +39,5 @@ CONFIG_HEAP_MEM_POOL_SIZE=1024 CONFIG_NET_LOG=y CONFIG_MBEDTLS=y -CONFIG_MBEDTLS_SHA1=y -CONFIG_MBEDTLS_SHA256=y +CONFIG_PSA_WANT_ALG_SHA_1=y +CONFIG_PSA_WANT_ALG_SHA_256=y diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index afb546a980d..91c956fa676 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -2,7 +2,6 @@ CONFIG_NETWORKING=y CONFIG_WIFI=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y -CONFIG_MBEDTLS_USE_PSA_CRYPTO=n CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y CONFIG_BT_DEVICE_NAME_DYNAMIC=y diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf index 1a0d0010dca..d75b1cd20a9 100644 --- a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf @@ -14,11 +14,6 @@ CONFIG_NET_HOSTNAME="circuitpython" CONFIG_MBEDTLS=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y -CONFIG_MBEDTLS_RSA_C=y -CONFIG_MBEDTLS_PKCS1_V15=y -CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=y +CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y CONFIG_MBEDTLS_ENTROPY_C=y -CONFIG_MBEDTLS_CIPHER_AES_ENABLED=y CONFIG_MBEDTLS_CTR_DRBG_C=y -CONFIG_MBEDTLS_SHA1=y -CONFIG_MBEDTLS_USE_PSA_CRYPTO=n diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf index 11d26d946b1..975d6bfd6e1 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf @@ -14,13 +14,8 @@ CONFIG_NET_HOSTNAME="circuitpython" CONFIG_MBEDTLS=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y -CONFIG_MBEDTLS_RSA_C=y -CONFIG_MBEDTLS_PKCS1_V15=y -CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED=y +CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y CONFIG_MBEDTLS_ENTROPY_C=y -CONFIG_MBEDTLS_CIPHER_AES_ENABLED=y CONFIG_MBEDTLS_CTR_DRBG_C=y -CONFIG_MBEDTLS_SHA1=y -CONFIG_MBEDTLS_USE_PSA_CRYPTO=n CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/ports/zephyr-cp/common-hal/busio/UART.h b/ports/zephyr-cp/common-hal/busio/UART.h index 25e767c5b28..be0b7ff83a9 100644 --- a/ports/zephyr-cp/common-hal/busio/UART.h +++ b/ports/zephyr-cp/common-hal/busio/UART.h @@ -27,3 +27,7 @@ mp_obj_t common_hal_busio_uart_construct_from_device(busio_uart_obj_t *self, con // Internal helper for clearing buffer void common_hal_busio_uart_clear_rx_buffer(busio_uart_obj_t *self); + +// Zephyr-port-specific write-timeout accessors, used by usb_cdc/Serial.c. +mp_float_t common_hal_busio_uart_get_write_timeout(busio_uart_obj_t *self); +void common_hal_busio_uart_set_write_timeout(busio_uart_obj_t *self, mp_float_t write_timeout); diff --git a/ports/zephyr-cp/common-hal/usb_cdc/Serial.c b/ports/zephyr-cp/common-hal/usb_cdc/Serial.c index 272a78b3141..715955d6e0f 100644 --- a/ports/zephyr-cp/common-hal/usb_cdc/Serial.c +++ b/ports/zephyr-cp/common-hal/usb_cdc/Serial.c @@ -7,6 +7,7 @@ #include "shared/runtime/interrupt_char.h" #include "shared-bindings/usb_cdc/Serial.h" #include "shared-bindings/busio/UART.h" +#include "common-hal/busio/UART.h" #include "supervisor/shared/tick.h" mp_obj_t common_hal_usb_cdc_serial_construct_from_device(usb_cdc_serial_obj_t *self, const struct device *uart_device, uint16_t receiver_buffer_size, byte *receiver_buffer) { diff --git a/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c b/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c index 3a6c21c5b83..725bf1fa7cb 100644 --- a/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c +++ b/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c @@ -16,6 +16,7 @@ #include "shared-bindings/wifi/Network.h" #include "shared-bindings/wifi/Radio.h" #include "shared-bindings/wifi/ScannedNetworks.h" +#include "bindings/zephyr_kernel/__init__.h" #include #include diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 0a37ad15938..b7334402b74 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -520,7 +520,19 @@ async def build_circuitpython(): ("-isystem", portdir / "modules" / "crypto" / "mbedtls" / "configs") ) circuitpython_flags.extend( - ("-isystem", portdir / "modules" / "crypto" / "mbedtls" / "include") + ("-isystem", portdir / "modules" / "crypto" / "tf-psa-crypto" / "include") + ) + circuitpython_flags.extend( + ( + "-isystem", + portdir + / "modules" + / "crypto" + / "tf-psa-crypto" + / "drivers" + / "builtin" + / "include", + ) ) circuitpython_flags.extend(("-isystem", zephyrdir / "modules" / "mbedtls" / "configs")) if "ssl" in enabled_modules: diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index d40501f1d1d..a9b5ecf6e1d 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -350,6 +350,25 @@ def find_flash_devices(device_tree): ) continue + # Skip soc-nv-flash nodes whose parent is itself a flash device — the + # parent is the real Zephyr device (e.g. nxp,imx-flexspi-nor) and the + # child has no driver-instantiated symbol. + if "soc-nv-flash" in compatible and node.parent is not None: + parent_compat = [] + if "compatible" in node.parent.props: + parent_compat = node.parent.props["compatible"].to_strings() + parent_drivers = [] + for c in parent_compat: + underscored = c.replace(",", "_").replace("-", "_") + d = COMPAT_TO_DRIVER.get(underscored) or MANUAL_COMPAT_TO_DRIVER.get(underscored) + if d: + parent_drivers.append(d) + if "flash" in parent_drivers: + logger.debug( + f" skipping flash {node.labels[0] if node.labels else node.name} (parent is flash device)" + ) + continue + if node.labels: flashes.append(node.labels[0]) diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 893ff259a97..765132742bb 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -9,6 +9,7 @@ CONFIG_FLASH_MAP_LABELS=y CONFIG_MAIN_STACK_SIZE=24288 CONFIG_THREAD_STACK_INFO=y +CONFIG_ARCH_POSIX_UPDATE_STACK_INFO=y CONFIG_STACK_SENTINEL=n CONFIG_DEBUG_THREAD_INFO=n CONFIG_EXCEPTION_STACK_TRACE=n @@ -52,5 +53,6 @@ CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y CONFIG_MBEDTLS=y CONFIG_MBEDTLS_BUILTIN=y -CONFIG_MBEDTLS_SHA1=y -CONFIG_MBEDTLS_SHA256=y +CONFIG_MBEDTLS_PSA_CRYPTO_C=y +CONFIG_PSA_WANT_ALG_SHA_1=y +CONFIG_PSA_WANT_ALG_SHA_256=y diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 047a4efe8bf..1ecde0b0141 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -13,6 +13,8 @@ #include "common-hal/audiobusio/I2SOut.h" #endif +#include + #include #include #include @@ -20,7 +22,6 @@ #if defined(CONFIG_ARCH_POSIX) #include -#include #include "cmdline.h" #include "posix_board_if.h" diff --git a/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.mask.png b/ports/zephyr-cp/tests/zephyr_display/golden/terminal_console_output_320x240.mask.png index 3ebb967560f0a9d474e71d36edf028375d984561..c675e2e5fa7106c34501975836ebadaf88068620 100644 GIT binary patch literal 453 zcmeAS@N?(olHy`uVBq!ia0y~yU~~YoKX3pEh7h+$+kpZ-o-U3d6?5L+-N@Tuz{B8p z=%2N-|8Li%67$BdMUPLt-l_5KF0+q%f(i!QQpW$m@SVx_#)%Ce2r?53_+XrUhkeT7 iAI}6hB}O6s5ZJ4d$l`pI_r_FEIC{GJxvXuyuz`$}a z=>NQKwoUvCW(F2SGMmraT(g^fO;tJnj=2pJ@j#G)SilG4$Gglg9IhztVCfl!_(MP~ Xr-j+IP3CSbC>%Xq{an^LB{Ts5OZSCr diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 82509b40cef..4401481f966 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -8,6 +8,6 @@ manifest: path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: d991bfc190507849d510326b24ba7b7a6c51a0e6 + revision: e1dc85052bc8928572fdb972997c65eeb96f555b clone-depth: 100 import: true diff --git a/py/mpconfig.h b/py/mpconfig.h index 69a338d746a..0e440066d78 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -26,6 +26,7 @@ #ifndef MICROPY_INCLUDED_PY_MPCONFIG_H #define MICROPY_INCLUDED_PY_MPCONFIG_H +#include #include #if defined(__cplusplus) // Required on at least one compiler to get ULLONG_MAX @@ -204,10 +205,13 @@ #if MP_INT_TYPE == MP_INT_TYPE_INTPTR typedef intptr_t mp_int_t; -typedef uintptr_t mp_uint_t; +// Use size_t so kw-function signatures and other size-typed APIs match without +// triggering -Wincompatible-pointer-types under newer GCCs where size_t and +// uintptr_t are distinct types of the same width (e.g. picolibc on 32-bit ARM). +typedef size_t mp_uint_t; #define MP_INT_MAX INTPTR_MAX #define MP_INT_MIN INTPTR_MIN -#define MP_UINT_MAX INTPTR_UMAX +#define MP_UINT_MAX SIZE_MAX #elif MP_INT_TYPE == MP_INT_TYPE_INT64 typedef int64_t mp_int_t; typedef uint64_t mp_uint_t; diff --git a/shared-bindings/_bleio/CharacteristicBuffer.c b/shared-bindings/_bleio/CharacteristicBuffer.c index 5ffff0dcba7..07394256933 100644 --- a/shared-bindings/_bleio/CharacteristicBuffer.c +++ b/shared-bindings/_bleio/CharacteristicBuffer.c @@ -118,7 +118,7 @@ static mp_uint_t bleio_characteristic_buffer_write(mp_obj_t self_in, const void return 0; } -static mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t bleio_characteristic_buffer_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { bleio_characteristic_buffer_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); raise_error_if_not_connected(self); diff --git a/shared-bindings/busio/UART.c b/shared-bindings/busio/UART.c index 017b9837781..81e970a98f4 100644 --- a/shared-bindings/busio/UART.c +++ b/shared-bindings/busio/UART.c @@ -277,7 +277,7 @@ static mp_uint_t busio_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_ return common_hal_busio_uart_write(self, buf, size, errcode); } -static mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t busio_uart_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { busio_uart_obj_t *self = native_uart(self_in); check_for_deinit(self); mp_uint_t ret; diff --git a/shared-bindings/jpegio/JpegDecoder.c b/shared-bindings/jpegio/JpegDecoder.c index 752d80b4733..d55de7b67e0 100644 --- a/shared-bindings/jpegio/JpegDecoder.c +++ b/shared-bindings/jpegio/JpegDecoder.c @@ -141,7 +141,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(jpegio_jpegdecoder_open_obj, jpegio_jpegdecoder_open); //| """ //| //| -static mp_obj_t jpegio_jpegdecoder_decode(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +static mp_obj_t jpegio_jpegdecoder_decode(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { jpegio_jpegdecoder_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); enum { ARG_bitmap, ARG_scale, ARG_x, ARG_y, ARGS_X1_Y1_X2_Y2, ARG_skip_source_index, ARG_skip_dest_index }; diff --git a/shared-bindings/socketpool/Socket.c b/shared-bindings/socketpool/Socket.c index 5dac9d150e8..35adb20bbfb 100644 --- a/shared-bindings/socketpool/Socket.c +++ b/shared-bindings/socketpool/Socket.c @@ -446,7 +446,7 @@ static mp_uint_t socket_write(mp_obj_t self_in, const void *buf, mp_uint_t size, return ret; } -static mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { socketpool_socket_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/ssl/SSLSocket.c b/shared-bindings/ssl/SSLSocket.c index 4418a8e48d9..98f67878d04 100644 --- a/shared-bindings/ssl/SSLSocket.c +++ b/shared-bindings/ssl/SSLSocket.c @@ -291,7 +291,7 @@ static mp_uint_t sslsocket_write(mp_obj_t self_in, const void *buf, mp_uint_t si return readwrite_common(self_in, common_hal_ssl_sslsocket_send, buf, size, errorcode); } -static mp_uint_t sslsocket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t sslsocket_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { ssl_sslsocket_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c index 72c43ba2dc1..320d4cc667a 100644 --- a/shared-bindings/terminalio/Terminal.c +++ b/shared-bindings/terminalio/Terminal.c @@ -222,7 +222,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(terminalio_terminal_get_cursor_y_obj, terminalio_termi MP_PROPERTY_GETTER(terminalio_terminal_cursor_y_obj, (mp_obj_t)&terminalio_terminal_get_cursor_y_obj); -static mp_uint_t terminalio_terminal_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t terminalio_terminal_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { terminalio_terminal_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/usb_cdc/Serial.c b/shared-bindings/usb_cdc/Serial.c index eb526615927..9bbc2b78f35 100644 --- a/shared-bindings/usb_cdc/Serial.c +++ b/shared-bindings/usb_cdc/Serial.c @@ -100,7 +100,7 @@ static mp_uint_t usb_cdc_serial_write_stream(mp_obj_t self_in, const void *buf_i return common_hal_usb_cdc_serial_write(self, buf, size, errcode); } -static mp_uint_t usb_cdc_serial_ioctl_stream(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t usb_cdc_serial_ioctl_stream(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { usb_cdc_serial_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret = 0; switch (request) { diff --git a/shared-bindings/usb_midi/PortIn.c b/shared-bindings/usb_midi/PortIn.c index d62d0b53af1..3f4b19fdec2 100644 --- a/shared-bindings/usb_midi/PortIn.c +++ b/shared-bindings/usb_midi/PortIn.c @@ -60,7 +60,7 @@ static mp_uint_t usb_midi_portin_read(mp_obj_t self_in, void *buf_in, mp_uint_t return common_hal_usb_midi_portin_read(self, buf, size, errcode); } -static mp_uint_t usb_midi_portin_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t usb_midi_portin_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { usb_midi_portin_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/shared-bindings/usb_midi/PortOut.c b/shared-bindings/usb_midi/PortOut.c index 89c83810188..35856ff25fa 100644 --- a/shared-bindings/usb_midi/PortOut.c +++ b/shared-bindings/usb_midi/PortOut.c @@ -42,7 +42,7 @@ static mp_uint_t usb_midi_portout_write(mp_obj_t self_in, const void *buf_in, mp return common_hal_usb_midi_portout_write(self, buf, size, errcode); } -static mp_uint_t usb_midi_portout_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { +static mp_uint_t usb_midi_portout_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) { usb_midi_portout_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_uint_t ret; if (request == MP_STREAM_POLL) { diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index 09ed8ab2226..28ce682efd9 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -23,8 +23,10 @@ #endif #endif -#if CIRCUITPY_TINYUSB || CIRCUITPY_USB_KEYBOARD_WORKFLOW +#if CIRCUITPY_USB_DEVICE || CIRCUITPY_USB_KEYBOARD_WORKFLOW #include "supervisor/usb.h" +#endif +#if CIRCUITPY_TINYUSB #include "tusb.h" #endif @@ -70,8 +72,8 @@ void supervisor_workflow_request_background(void) { bool supervisor_workflow_active(void) { #if CIRCUITPY_USB_DEVICE // Eventually there might be other non-USB workflows, such as BLE. - // tud_ready() checks for usb mounted and not suspended. - if (tud_ready()) { + // usb_connected() checks for usb mounted and not suspended. + if (usb_connected()) { return true; } #endif From 98741a7f50d5f2f9a7144a8d5349ecbc6ae2ef51 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 18 May 2026 19:56:16 -0400 Subject: [PATCH 502/876] raspberrypi: use adafruit/Pico-PIO-USB fork for now --- .gitmodules | 2 +- ports/raspberrypi/lib/Pico-PIO-USB | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index a7b67b8d860..586de7ded11 100644 --- a/.gitmodules +++ b/.gitmodules @@ -346,7 +346,7 @@ url = https://github.com/adafruit/Adafruit_CircuitPython_Wave.git [submodule "ports/raspberrypi/lib/Pico-PIO-USB"] path = ports/raspberrypi/lib/Pico-PIO-USB - url = https://github.com/sekigon-gonnoc/Pico-PIO-USB.git + url = https://github.com/adafruit/Pico-PIO-USB.git branch = main [submodule "lib/micropython-lib"] path = lib/micropython-lib diff --git a/ports/raspberrypi/lib/Pico-PIO-USB b/ports/raspberrypi/lib/Pico-PIO-USB index 675543bcc9b..a584191fc37 160000 --- a/ports/raspberrypi/lib/Pico-PIO-USB +++ b/ports/raspberrypi/lib/Pico-PIO-USB @@ -1 +1 @@ -Subproject commit 675543bcc9baa8170f868ab7ba316d418dbcf41f +Subproject commit a584191fc374818cb0df307a293795354a17eefb From 6d2501f626221da412fe54e918ada88f389c019e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 19 May 2026 13:00:12 -0400 Subject: [PATCH 503/876] switch back to https://github.com/sekigon-gonnoc/Pico-PIO-USB --- .gitmodules | 2 +- ports/raspberrypi/lib/Pico-PIO-USB | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 586de7ded11..a7b67b8d860 100644 --- a/.gitmodules +++ b/.gitmodules @@ -346,7 +346,7 @@ url = https://github.com/adafruit/Adafruit_CircuitPython_Wave.git [submodule "ports/raspberrypi/lib/Pico-PIO-USB"] path = ports/raspberrypi/lib/Pico-PIO-USB - url = https://github.com/adafruit/Pico-PIO-USB.git + url = https://github.com/sekigon-gonnoc/Pico-PIO-USB.git branch = main [submodule "lib/micropython-lib"] path = lib/micropython-lib diff --git a/ports/raspberrypi/lib/Pico-PIO-USB b/ports/raspberrypi/lib/Pico-PIO-USB index a584191fc37..dc9193fed51 160000 --- a/ports/raspberrypi/lib/Pico-PIO-USB +++ b/ports/raspberrypi/lib/Pico-PIO-USB @@ -1 +1 @@ -Subproject commit a584191fc374818cb0df307a293795354a17eefb +Subproject commit dc9193fed510da5f81f4db520e98282f61db9054 From b2fdd17cf3f3350bae9b1fb35445840a36920da0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 19 May 2026 15:07:51 -0400 Subject: [PATCH 504/876] ports/espressif/common-hal/socketpool/SocketPool.c: remove old workaround for lwip issue --- ports/espressif/common-hal/socketpool/SocketPool.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ports/espressif/common-hal/socketpool/SocketPool.c b/ports/espressif/common-hal/socketpool/SocketPool.c index aa7461d3ffe..5d7890af171 100644 --- a/ports/espressif/common-hal/socketpool/SocketPool.c +++ b/ports/espressif/common-hal/socketpool/SocketPool.c @@ -24,18 +24,6 @@ void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *sel // common_hal_socketpool_socket is in socketpool/Socket.c to centralize open socket tracking. int socketpool_getaddrinfo_common(const char *host, int service, const struct addrinfo *hints, struct addrinfo **res) { - // As of 2022, the version of lwip in esp-idf does not handle the - // trailing-dot syntax of domain names, so emulate it. - // Remove this once https://github.com/espressif/esp-idf/issues/10013 has - // been implemented - if (host) { - size_t strlen_host = strlen(host); - if (strlen_host && host[strlen_host - 1] == '.') { - mp_obj_t nodot = mp_obj_new_str(host, strlen_host - 1); - host = mp_obj_str_get_str(nodot); - } - } - char service_buf[6]; snprintf(service_buf, sizeof(service_buf), "%d", service); From 569d726c9f243a978275ccc2ee74ec36e93da7d6 Mon Sep 17 00:00:00 2001 From: Piclaw Date: Tue, 19 May 2026 13:21:09 -0700 Subject: [PATCH 505/876] web_workflow: reply 409 Conflict instead of 500 when filesystem is write-protected When the host has CIRCUITPY mounted over USB Mass Storage, the CircuitPython side of FatFS sees STA_PROTECT on the block device and f_open(..., FA_WRITE) returns FR_WRITE_PROTECTED. _write_file_and_reply was lumping this into the generic 'result != FR_OK' branch and replying 500 Internal Server Error, which looks like a server crash. The mkdir, MOVE, and DELETE paths in the same file already check FR_WRITE_PROTECTED explicitly and reply 409 Conflict; this matches PUT to that pattern so clients can show actionable messages ('eject CIRCUITPY / disable USB MSC') instead of treating it as an unrecoverable error. Also tightens the f_size(&active_file) call so it only runs when f_open actually succeeded -- the previous 'else' branch would read from an uninitialized FIL on any non-FR_NO_FILE error result. Reproduction (before): connect a board with web workflow active, mount CIRCUITPY on the host over USB MSC, save code.py from the web editor -> the editor reports 'Saving file failed' with no clear cause and the device returns HTTP 500. Behavior (after): same flow returns HTTP 409 Conflict; the editor can map that to a user-facing hint about ejecting CIRCUITPY. See: circuitpython/web-editor#460 --- supervisor/shared/web_workflow/web_workflow.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index a14f79a5bb4..8da8dcc5184 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -1040,7 +1040,7 @@ static void _write_file_and_reply(socketpool_socket_obj_t *socket, _request *req if (result == FR_NO_FILE) { new_file = true; result = f_open(fs, &active_file, path, FA_WRITE | FA_OPEN_ALWAYS); - } else { + } else if (result == FR_OK) { old_length = f_size(&active_file); } @@ -1051,6 +1051,18 @@ static void _write_file_and_reply(socketpool_socket_obj_t *socket, _request *req _reply_missing(socket, request); return; } + if (result == FR_WRITE_PROTECTED) { + // The filesystem is held by something else with write access (most + // commonly USB-MSC: the host has CIRCUITPY mounted, so CircuitPython + // can't write through FatFS). Match the mkdir/move/delete paths and + // reply 409 Conflict so clients can show an actionable message + // ("eject CIRCUITPY / disable USB MSC") instead of a generic 500. + override_fattime(0); + filesystem_unlock(fs_mount); + _discard_incoming(socket, request->content_length); + _reply_conflict(socket, request); + return; + } if (result != FR_OK) { override_fattime(0); filesystem_unlock(fs_mount); From 6479ceb0cc92d52c78f4c246460d9e7b3a41534a Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 19 May 2026 16:50:03 -0500 Subject: [PATCH 506/876] update PIO programs --- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 186 +++++++++++------- .../common-hal/audioi2sin/i2sin.pio | 23 ++- .../common-hal/audioi2sin/i2sin_32.pio | 29 ++- .../common-hal/audioi2sin/i2sin_left.pio | 23 ++- .../common-hal/audioi2sin/i2sin_left_32.pio | 23 ++- .../common-hal/audioi2sin/i2sin_swap.pio | 23 ++- .../common-hal/audioi2sin/i2sin_swap_32.pio | 23 ++- .../common-hal/audioi2sin/i2sin_swap_left.pio | 23 ++- .../audioi2sin/i2sin_swap_left_32.pio | 23 ++- 9 files changed, 238 insertions(+), 138 deletions(-) diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 0de4fe69b8c..9331d975ded 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -38,57 +38,77 @@ // Master-mode RX, regular pin order (BCLK = WS - 1), Philips alignment. static const uint16_t i2sin_program[] = { - // .wrap_target - 0xf04e, // 0: set y, 14 side 2 - 0x5a01, // 1: in pins, 1 side 3 [2] - 0x1281, // 2: jmp y--, 1 side 2 [2] - 0x4a01, // 3: in pins, 1 side 1 [2] - 0xe24e, // 4: set y, 14 side 0 [2] - 0x4a01, // 5: in pins, 1 side 1 [2] - 0x0285, // 6: jmp y--, 5 side 0 [2] - 0x5a01, // 7: in pins, 1 side 3 [2] + 0xb842, // 0: nop side 3 + // .wrap_target + 0xf94e, // 1: set y, 14 side 3 [1] + 0xb242, // 2: nop side 2 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xa242, // 5: nop side 0 [2] + 0x4801, // 6: in pins, 1 side 1 + 0xe94e, // 7: set y, 14 side 1 [1] + 0xa242, // 8: nop side 0 [2] + 0x4801, // 9: in pins, 1 side 1 + 0x0988, // 10: jmp y--, 8 side 1 [1] + 0xb242, // 11: nop side 2 [2] + 0x5801, // 12: in pins, 1 side 3 // .wrap }; // Master-mode RX, regular pin order, left-justified. static const uint16_t i2sin_program_left_justified[] = { - // .wrap_target - 0xe04e, // 0: set y, 14 side 0 - 0x5a01, // 1: in pins, 1 side 3 [2] - 0x1281, // 2: jmp y--, 1 side 2 [2] - 0x5a01, // 3: in pins, 1 side 3 [2] - 0xf24e, // 4: set y, 14 side 2 [2] - 0x4a01, // 5: in pins, 1 side 1 [2] - 0x0285, // 6: jmp y--, 5 side 0 [2] - 0x4a01, // 7: in pins, 1 side 1 [2] + 0xa842, // 0: nop side 1 + // .wrap_target + 0xe94e, // 1: set y, 14 side 1 [1] + 0xb242, // 2: nop side 2 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xb242, // 5: nop side 2 [2] + 0x5801, // 6: in pins, 1 side 3 + 0xf94e, // 7: set y, 14 side 3 [1] + 0xa242, // 8: nop side 0 [2] + 0x4801, // 9: in pins, 1 side 1 + 0x0988, // 10: jmp y--, 8 side 1 [1] + 0xa242, // 11: nop side 0 [2] + 0x4801, // 12: in pins, 1 side 1 // .wrap }; // Master-mode RX, swapped pin order (BCLK = WS + 1), Philips alignment. static const uint16_t i2sin_program_swap[] = { - // .wrap_target - 0xe84e, // 0: set y, 14 side 1 - 0x5a01, // 1: in pins, 1 side 3 [2] - 0x0a81, // 2: jmp y--, 1 side 1 [2] - 0x5201, // 3: in pins, 1 side 2 [2] - 0xe24e, // 4: set y, 14 side 0 [2] - 0x5201, // 5: in pins, 1 side 2 [2] - 0x0285, // 6: jmp y--, 5 side 0 [2] - 0x5a01, // 7: in pins, 1 side 3 [2] + 0xb842, // 0: nop side 3 + // .wrap_target + 0xf94e, // 1: set y, 14 side 3 [1] + 0xaa42, // 2: nop side 1 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xa242, // 5: nop side 0 [2] + 0x5001, // 6: in pins, 1 side 2 + 0xf14e, // 7: set y, 14 side 2 [1] + 0xa242, // 8: nop side 0 [2] + 0x5001, // 9: in pins, 1 side 2 + 0x1188, // 10: jmp y--, 8 side 2 [1] + 0xaa42, // 11: nop side 1 [2] + 0x5801, // 12: in pins, 1 side 3 // .wrap }; // Master-mode RX, swapped pin order, left-justified. static const uint16_t i2sin_program_left_justified_swap[] = { - // .wrap_target - 0xe04e, // 0: set y, 14 side 0 - 0x5a01, // 1: in pins, 1 side 3 [2] - 0x0a81, // 2: jmp y--, 1 side 1 [2] - 0x5a01, // 3: in pins, 1 side 3 [2] - 0xea4e, // 4: set y, 14 side 1 [2] - 0x5201, // 5: in pins, 1 side 2 [2] - 0x0285, // 6: jmp y--, 5 side 0 [2] - 0x5201, // 7: in pins, 1 side 2 [2] + 0xb042, // 0: nop side 2 + // .wrap_target + 0xf14e, // 1: set y, 14 side 2 [1] + 0xaa42, // 2: nop side 1 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xaa42, // 5: nop side 1 [2] + 0x5801, // 6: in pins, 1 side 3 + 0xf94e, // 7: set y, 14 side 3 [1] + 0xa242, // 8: nop side 0 [2] + 0x5001, // 9: in pins, 1 side 2 + 0x1188, // 10: jmp y--, 8 side 2 [1] + 0xa242, // 11: nop side 0 [2] + 0x5001, // 12: in pins, 1 side 2 // .wrap }; @@ -96,54 +116,74 @@ static const uint16_t i2sin_program_left_justified_swap[] = { // the loop counter is set to 30 (so each `bitloop` runs 31 in's, plus one // outside the loop = 32 in's per channel). static const uint16_t i2sin_program_32[] = { - // .wrap_target - 0xf05e, // 0: set y, 30 side 2 - 0x5a01, // 1: in pins, 1 side 3 [2] - 0x1281, // 2: jmp y--, 1 side 2 [2] - 0x4a01, // 3: in pins, 1 side 1 [2] - 0xe25e, // 4: set y, 30 side 0 [2] - 0x4a01, // 5: in pins, 1 side 1 [2] - 0x0285, // 6: jmp y--, 5 side 0 [2] - 0x5a01, // 7: in pins, 1 side 3 [2] + 0xb842, // 0: nop side 3 + // .wrap_target + 0xf95e, // 1: set y, 30 side 3 [1] + 0xb242, // 2: nop side 2 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xa242, // 5: nop side 0 [2] + 0x4801, // 6: in pins, 1 side 1 + 0xe95e, // 7: set y, 30 side 1 [1] + 0xa242, // 8: nop side 0 [2] + 0x4801, // 9: in pins, 1 side 1 + 0x0988, // 10: jmp y--, 8 side 1 [1] + 0xb242, // 11: nop side 2 [2] + 0x5801, // 12: in pins, 1 side 3 // .wrap }; static const uint16_t i2sin_program_left_justified_32[] = { - // .wrap_target - 0xe05e, // 0: set y, 30 side 0 - 0x5a01, // 1: in pins, 1 side 3 [2] - 0x1281, // 2: jmp y--, 1 side 2 [2] - 0x5a01, // 3: in pins, 1 side 3 [2] - 0xf25e, // 4: set y, 30 side 2 [2] - 0x4a01, // 5: in pins, 1 side 1 [2] - 0x0285, // 6: jmp y--, 5 side 0 [2] - 0x4a01, // 7: in pins, 1 side 1 [2] + 0xa842, // 0: nop side 1 + // .wrap_target + 0xe95e, // 1: set y, 30 side 1 [1] + 0xb242, // 2: nop side 2 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xb242, // 5: nop side 2 [2] + 0x5801, // 6: in pins, 1 side 3 + 0xf95e, // 7: set y, 30 side 3 [1] + 0xa242, // 8: nop side 0 [2] + 0x4801, // 9: in pins, 1 side 1 + 0x0988, // 10: jmp y--, 8 side 1 [1] + 0xa242, // 11: nop side 0 [2] + 0x4801, // 12: in pins, 1 side 1 // .wrap }; static const uint16_t i2sin_program_swap_32[] = { - // .wrap_target - 0xe85e, // 0: set y, 30 side 1 - 0x5a01, // 1: in pins, 1 side 3 [2] - 0x0a81, // 2: jmp y--, 1 side 1 [2] - 0x5201, // 3: in pins, 1 side 2 [2] - 0xe25e, // 4: set y, 30 side 0 [2] - 0x5201, // 5: in pins, 1 side 2 [2] - 0x0285, // 6: jmp y--, 5 side 0 [2] - 0x5a01, // 7: in pins, 1 side 3 [2] + 0xb842, // 0: nop side 3 + // .wrap_target + 0xf95e, // 1: set y, 30 side 3 [1] + 0xaa42, // 2: nop side 1 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xa242, // 5: nop side 0 [2] + 0x5001, // 6: in pins, 1 side 2 + 0xf15e, // 7: set y, 30 side 2 [1] + 0xa242, // 8: nop side 0 [2] + 0x5001, // 9: in pins, 1 side 2 + 0x1188, // 10: jmp y--, 8 side 2 [1] + 0xaa42, // 11: nop side 1 [2] + 0x5801, // 12: in pins, 1 side 3 // .wrap }; static const uint16_t i2sin_program_left_justified_swap_32[] = { - // .wrap_target - 0xe05e, // 0: set y, 30 side 0 - 0x5a01, // 1: in pins, 1 side 3 [2] - 0x0a81, // 2: jmp y--, 1 side 1 [2] - 0x5a01, // 3: in pins, 1 side 3 [2] - 0xea5e, // 4: set y, 30 side 1 [2] - 0x5201, // 5: in pins, 1 side 2 [2] - 0x0285, // 6: jmp y--, 5 side 0 [2] - 0x5201, // 7: in pins, 1 side 2 [2] + 0xb042, // 0: nop side 2 + // .wrap_target + 0xf15e, // 1: set y, 30 side 2 [1] + 0xaa42, // 2: nop side 1 [2] + 0x5801, // 3: in pins, 1 side 3 + 0x1982, // 4: jmp y--, 2 side 3 [1] + 0xaa42, // 5: nop side 1 [2] + 0x5801, // 6: in pins, 1 side 3 + 0xf95e, // 7: set y, 30 side 3 [1] + 0xa242, // 8: nop side 0 [2] + 0x5001, // 9: in pins, 1 side 2 + 0x1188, // 10: jmp y--, 8 side 2 [1] + 0xa242, // 11: nop side 0 [2] + 0x5001, // 12: in pins, 1 side 2 // .wrap }; @@ -216,7 +256,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, false, // Wait for txstall true, 32, false, // in settings: auto-push at 32 bits, shift left (MSB first) false, // Not user-interruptible. - 0, -1, // wrap settings + 1, -1, // wrap settings PIO_ANY_OFFSET, PIO_FIFO_TYPE_DEFAULT, PIO_MOV_STATUS_DEFAULT, diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio index 109d1ed5ab4..97dc9c7f7e9 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio @@ -15,13 +15,20 @@ ; /--- LRCLK ; |/-- BCLK ; || - set y 14 side 0b10 + nop side 0b11 +.wrap_target + set y 14 side 0b11 [1] bitloop1: - in pins 1 side 0b11 [2] ; Right channel first - jmp y-- bitloop1 side 0b10 [2] - in pins 1 side 0b01 [2] - set y 14 side 0b00 [2] + nop side 0b10 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b00 [2] + in pins 1 side 0b01 + set y 14 side 0b01 [1] bitloop0: - in pins 1 side 0b01 [2] ; Then left channel - jmp y-- bitloop0 side 0b00 [2] - in pins 1 side 0b11 [2] + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b01 + jmp y-- bitloop0 side 0b01 [1] + nop side 0b10 [2] + in pins 1 side 0b11 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio index d3d7fb5aa6f..f09a02a85c2 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio @@ -8,17 +8,28 @@ .side_set 2 ; Master-mode I2S RX, 32 bits per channel (also used for 24-bit mics that -; transmit data left-justified in a 32-bit slot). +; transmit data left-justified in a 32-bit slot). Generates BCLK and LRCLK +; via side-set and samples the data pin. The slave updates `data` on BCLK +; falling edge, so the master samples on the rising edge: every `in pins 1` +; runs on a side-set value with BCLK=1, and the preceding nop holds BCLK=0 +; so the slave has time to settle the next bit. ; /--- LRCLK ; |/-- BCLK ; || - set y 30 side 0b10 + nop side 0b11 +.wrap_target + set y 30 side 0b11 [1] bitloop1: - in pins 1 side 0b11 [2] ; Right channel first - jmp y-- bitloop1 side 0b10 [2] - in pins 1 side 0b01 [2] - set y 30 side 0b00 [2] + nop side 0b10 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b00 [2] + in pins 1 side 0b01 + set y 30 side 0b01 [1] bitloop0: - in pins 1 side 0b01 [2] ; Then left channel - jmp y-- bitloop0 side 0b00 [2] - in pins 1 side 0b11 [2] + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b01 + jmp y-- bitloop0 side 0b01 [1] + nop side 0b10 [2] + in pins 1 side 0b11 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio index eb2b42a7031..8926d178635 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio @@ -11,13 +11,20 @@ ; /--- LRCLK ; |/-- BCLK ; || - set y 14 side 0b00 + nop side 0b01 +.wrap_target + set y 14 side 0b01 [1] bitloop1: - in pins 1 side 0b11 [2] ; Right channel first - jmp y-- bitloop1 side 0b10 [2] - in pins 1 side 0b11 [2] - set y 14 side 0b10 [2] + nop side 0b10 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b10 [2] + in pins 1 side 0b11 + set y 14 side 0b11 [1] bitloop0: - in pins 1 side 0b01 [2] ; Then left channel - jmp y-- bitloop0 side 0b00 [2] - in pins 1 side 0b01 [2] + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b01 + jmp y-- bitloop0 side 0b01 [1] + nop side 0b00 [2] + in pins 1 side 0b01 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio index d2502a21540..86fcf79a876 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio @@ -11,13 +11,20 @@ ; /--- LRCLK ; |/-- BCLK ; || - set y 30 side 0b00 + nop side 0b01 +.wrap_target + set y 30 side 0b01 [1] bitloop1: - in pins 1 side 0b11 [2] ; Right channel first - jmp y-- bitloop1 side 0b10 [2] - in pins 1 side 0b11 [2] - set y 30 side 0b10 [2] + nop side 0b10 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b10 [2] + in pins 1 side 0b11 + set y 30 side 0b11 [1] bitloop0: - in pins 1 side 0b01 [2] ; Then left channel - jmp y-- bitloop0 side 0b00 [2] - in pins 1 side 0b01 [2] + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b01 + jmp y-- bitloop0 side 0b01 [1] + nop side 0b00 [2] + in pins 1 side 0b01 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio index cbf3905bdbc..8b718ebae65 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio @@ -12,13 +12,20 @@ ; /--- BCLK ; |/-- LRCLK ; || - set y 14 side 0b01 + nop side 0b11 +.wrap_target + set y 14 side 0b11 [1] bitloop1: - in pins 1 side 0b11 [2] ; Right channel first - jmp y-- bitloop1 side 0b01 [2] - in pins 1 side 0b10 [2] - set y 14 side 0b00 [2] + nop side 0b01 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b00 [2] + in pins 1 side 0b10 + set y 14 side 0b10 [1] bitloop0: - in pins 1 side 0b10 [2] ; Then left channel - jmp y-- bitloop0 side 0b00 [2] - in pins 1 side 0b11 [2] + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b10 + jmp y-- bitloop0 side 0b10 [1] + nop side 0b01 [2] + in pins 1 side 0b11 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio index 4e00a5a8e54..8ac65a20f90 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio @@ -12,13 +12,20 @@ ; /--- BCLK ; |/-- LRCLK ; || - set y 30 side 0b01 + nop side 0b11 +.wrap_target + set y 30 side 0b11 [1] bitloop1: - in pins 1 side 0b11 [2] ; Right channel first - jmp y-- bitloop1 side 0b01 [2] - in pins 1 side 0b10 [2] - set y 30 side 0b00 [2] + nop side 0b01 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b00 [2] + in pins 1 side 0b10 + set y 30 side 0b10 [1] bitloop0: - in pins 1 side 0b10 [2] ; Then left channel - jmp y-- bitloop0 side 0b00 [2] - in pins 1 side 0b11 [2] + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b10 + jmp y-- bitloop0 side 0b10 [1] + nop side 0b01 [2] + in pins 1 side 0b11 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio index 90ae7ea8d0e..f6adc3d5bb8 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio @@ -12,13 +12,20 @@ ; /--- BCLK ; |/-- LRCLK ; || - set y 14 side 0b00 + nop side 0b10 +.wrap_target + set y 14 side 0b10 [1] bitloop1: - in pins 1 side 0b11 [2] ; Right channel first - jmp y-- bitloop1 side 0b01 [2] - in pins 1 side 0b11 [2] - set y 14 side 0b01 [2] + nop side 0b01 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b01 [2] + in pins 1 side 0b11 + set y 14 side 0b11 [1] bitloop0: - in pins 1 side 0b10 [2] ; Then left channel - jmp y-- bitloop0 side 0b00 [2] - in pins 1 side 0b10 [2] + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b10 + jmp y-- bitloop0 side 0b10 [1] + nop side 0b00 [2] + in pins 1 side 0b10 +.wrap diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio index 49e0ec7dccf..ae0ef8b8afb 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio @@ -12,13 +12,20 @@ ; /--- BCLK ; |/-- LRCLK ; || - set y 30 side 0b00 + nop side 0b10 +.wrap_target + set y 30 side 0b10 [1] bitloop1: - in pins 1 side 0b11 [2] ; Right channel first - jmp y-- bitloop1 side 0b01 [2] - in pins 1 side 0b11 [2] - set y 30 side 0b01 [2] + nop side 0b01 [2] ; Right channel first + in pins 1 side 0b11 + jmp y-- bitloop1 side 0b11 [1] + nop side 0b01 [2] + in pins 1 side 0b11 + set y 30 side 0b11 [1] bitloop0: - in pins 1 side 0b10 [2] ; Then left channel - jmp y-- bitloop0 side 0b00 [2] - in pins 1 side 0b10 [2] + nop side 0b00 [2] ; Then left channel + in pins 1 side 0b10 + jmp y-- bitloop0 side 0b10 [1] + nop side 0b00 [2] + in pins 1 side 0b10 +.wrap From 5282f62e10d3f36a588df0b018436d34625515b5 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 20 May 2026 09:57:46 -0500 Subject: [PATCH 507/876] mirror low bits. change error message in PDMIn --- ports/espressif/common-hal/audiobusio/PDMIn.c | 2 +- ports/espressif/common-hal/audioi2sin/I2SIn.c | 14 +++++++++++++- ports/raspberrypi/common-hal/audioi2sin/I2SIn.c | 14 +++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ports/espressif/common-hal/audiobusio/PDMIn.c b/ports/espressif/common-hal/audiobusio/PDMIn.c index c9d28ad7071..7718f096c89 100644 --- a/ports/espressif/common-hal/audiobusio/PDMIn.c +++ b/ports/espressif/common-hal/audiobusio/PDMIn.c @@ -40,7 +40,7 @@ void common_hal_audiobusio_pdmin_construct(audiobusio_pdmin_obj_t *self, && bit_depth != I2S_DATA_BIT_WIDTH_16BIT && bit_depth != I2S_DATA_BIT_WIDTH_24BIT && bit_depth != I2S_DATA_BIT_WIDTH_32BIT) { - mp_raise_ValueError(MP_ERROR_TEXT("bit_depth must be 8, 16, 24, or 32.")); + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q must be 8, 16, 24, or 32"), MP_QSTR_bit_depth); } i2s_chan_config_t chanConfig = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER); diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 9953f221b7f..fd2e9d33a2b 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -150,7 +150,19 @@ static inline void i2sin_write_converted(void *buffer, uint32_t idx, int32_t s = i2sin_normalize_signed(raw, in_depth); int32_t shifted; if (out_depth >= in_depth) { - shifted = (int32_t)((uint32_t)s << (out_depth - in_depth)); + // Bit-replicate the input across the wider output so that full-scale + // input maps to full-scale output (e.g. 8-bit 0xFF -> 16-bit 0xFFFF), + // rather than leaving the new low bits as zero. + uint32_t in_mask = (in_depth >= 32) ? 0xffffffffu : ((1u << in_depth) - 1u); + uint32_t in_bits = (uint32_t)s & in_mask; + uint32_t result = 0; + int remaining = out_depth; + while (remaining > 0) { + int take = (remaining >= (int)in_depth) ? (int)in_depth : remaining; + result = (result << take) | (in_bits >> (in_depth - take)); + remaining -= take; + } + shifted = (int32_t)result; } else { shifted = s >> (in_depth - out_depth); } diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 9331d975ded..b32c23ce984 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -412,7 +412,19 @@ static inline void i2sin_write_converted(void *buffer, uint32_t idx, int32_t s = i2sin_normalize_signed(raw, in_depth, left_justified); int32_t shifted; if (out_depth >= in_depth) { - shifted = (int32_t)((uint32_t)s << (out_depth - in_depth)); + // Bit-replicate the input across the wider output so that full-scale + // input maps to full-scale output (e.g. 8-bit 0xFF -> 16-bit 0xFFFF), + // rather than leaving the new low bits as zero. + uint32_t in_mask = (in_depth >= 32) ? 0xffffffffu : ((1u << in_depth) - 1u); + uint32_t in_bits = (uint32_t)s & in_mask; + uint32_t result = 0; + int remaining = out_depth; + while (remaining > 0) { + int take = (remaining >= (int)in_depth) ? (int)in_depth : remaining; + result = (result << take) | (in_bits >> (in_depth - take)); + remaining -= take; + } + shifted = (int32_t)result; } else { shifted = s >> (in_depth - out_depth); } From 4ff09c122e2be97dd5747ea3ff7662ff0849e8a4 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 20 May 2026 10:10:57 -0500 Subject: [PATCH 508/876] make translate --- locale/circuitpython.pot | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 20425d2d77f..d558a8960e2 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -190,6 +190,7 @@ msgstr "" msgid "%q must be 16, 24, or 32" msgstr "" +#: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" msgstr "" @@ -2706,10 +2707,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" From fb82da6332ab00c471f038299d293a8135a64873 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 20 May 2026 13:02:35 -0400 Subject: [PATCH 509/876] ports/raspberrypi/supervisor/port.c: #if PICO_RP2040, not #if defined(PICO_RP240) --- ports/raspberrypi/supervisor/port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 0335ba74d6f..01940acc079 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -624,7 +624,7 @@ bool __no_inline_not_in_flash_func(port_boot_button_pressed)(void) { // pressed, return is delayed until the button is released and // a delay has passed in order to debounce the button. const uint32_t CS_PIN_INDEX = 1; - #if defined(PICO_RP2040) + #if PICO_RP2040 const uint32_t CS_BIT = 1u << 1; #else const uint32_t CS_BIT = SIO_GPIO_HI_IN_QSPI_CSN_BITS; From f1a360fff56b359ffe0e329960daec2e92a74eb7 Mon Sep 17 00:00:00 2001 From: Tod Kurt Date: Fri, 22 May 2026 12:11:30 -0700 Subject: [PATCH 510/876] fix audiospeed.SpeedChanger direct playback, fixes #11020 Fix by setting "single_buffer = false". When single_buffer = true, the DMA driver sets up a hardware loop that resets the read address back to buffer[0] at full DMA speed, never calling get_buffer again. This caused SpeedChanger to replay its first 128-frame output buffer indefinitely when connected directly to audioio/audiobusio. Setting single_buffer = false enables the double-buffering path w/ DMA interrupts, which keeps calling get_buffer() so the phase accumulator can advance through the source audio correctly. Using AudioMixer as an intermediary masks the bug since Mixer/mix_down_one_voice() calls get_buffer() on its voices directly, bypassing the single_buffer optimization. --- shared-module/audiospeed/SpeedChanger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/audiospeed/SpeedChanger.c b/shared-module/audiospeed/SpeedChanger.c index e76bed1f17c..6f417e9d7b1 100644 --- a/shared-module/audiospeed/SpeedChanger.c +++ b/shared-module/audiospeed/SpeedChanger.c @@ -33,7 +33,7 @@ void common_hal_audiospeed_speedchanger_construct(audiospeed_speedchanger_obj_t self->base.channel_count = src_base->channel_count; self->base.bits_per_sample = src_base->bits_per_sample; self->base.samples_signed = src_base->samples_signed; - self->base.single_buffer = true; + self->base.single_buffer = false; uint8_t bytes_per_frame = (src_base->bits_per_sample / 8) * src_base->channel_count; self->output_buffer_length = OUTPUT_BUFFER_FRAMES * bytes_per_frame; From b3cabd6561cdb1350d035a0574234ab518bb2e62 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Fri, 22 May 2026 19:40:38 -0500 Subject: [PATCH 511/876] Separate filter processing for stereo data --- shared-module/audiofilters/Filter.c | 46 ++++++++++++++++------------- shared-module/audiofilters/Filter.h | 2 +- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index 4cedc810aba..f9c899e2995 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -40,8 +40,8 @@ void common_hal_audiofilters_filter_construct(audiofilters_filter_obj_t *self, self->last_buf_idx = 1; // Which buffer to use first, toggle between 0 and 1 // This buffer will be used to process samples through the biquad filter - self->filter_buffer = m_malloc_without_collect(SYNTHIO_MAX_DUR * sizeof(int32_t)); - memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * sizeof(int32_t)); + self->filter_buffer = m_malloc_without_collect(SYNTHIO_MAX_DUR * self->base.channel_count * sizeof(int32_t)); + memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * self->base.channel_count * sizeof(int32_t)); // Initialize other values most effects will need. self->sample = NULL; // The current playing sample @@ -106,9 +106,9 @@ void common_hal_audiofilters_filter_set_filter(audiofilters_filter_obj_t *self, self->filter_objs = filter_objs; self->filter_states = m_renew(biquad_filter_state, self->filter_states, - self->filter_states_len, - n_items); - self->filter_states_len = n_items; + self->filter_objs_len * self->base.channel_count, + n_items * self->base.channel_count); + self->filter_objs_len = n_items; } mp_obj_t common_hal_audiofilters_filter_get_filter(audiofilters_filter_obj_t *self) { @@ -129,10 +129,10 @@ void audiofilters_filter_reset_buffer(audiofilters_filter_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); - memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * sizeof(int32_t)); + memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * self->base.channel_count * sizeof(int32_t)); if (self->filter_states) { - for (uint8_t i = 0; i < self->filter_states_len; i++) { + for (uint8_t i = 0; i < self->filter_objs_len * self->base.channel_count; i++) { synthio_biquad_filter_reset(&self->filter_states[i]); } } @@ -207,7 +207,7 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o (void)synthio_block_slot_get(&self->mix); // Tick biquad filters - for (uint8_t j = 0; j < self->filter_states_len; j++) { + for (uint8_t j = 0; j < self->filter_objs_len; j++) { common_hal_synthio_biquad_tick(self->filter_objs[j]); } if (self->base.samples_signed) { @@ -248,46 +248,52 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o } else { uint32_t i = 0; while (i < n) { - uint32_t n_samples = MIN(SYNTHIO_MAX_DUR, n - i); + uint32_t n_samples = MIN(SYNTHIO_MAX_DUR, (n - i) >> (self->base.channel_count - 1)); // Fill filter buffer with samples - for (uint32_t j = 0; j < n_samples; j++) { + for (uint32_t j = 0; j < n_samples * self->base.channel_count; j++) { + bool buf_offset = (j % self->base.channel_count) == 1; + uint32_t k = j / self->base.channel_count; if (MP_LIKELY(self->base.bits_per_sample == 16)) { - self->filter_buffer[j] = sample_src[i + j]; + self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] = sample_src[i + j]; } else { if (self->base.samples_signed) { - self->filter_buffer[j] = sample_hsrc[i + j]; + self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] = sample_hsrc[i + j]; } else { // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed - self->filter_buffer[j] = (int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80); + self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] = (int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80); } } } // Process biquad filters - for (uint8_t j = 0; j < self->filter_states_len; j++) { + for (uint8_t j = 0; j < self->filter_objs_len; j++) { mp_obj_t filter_obj = self->filter_objs[j]; common_hal_synthio_biquad_tick(filter_obj); - synthio_biquad_filter_samples(filter_obj, &self->filter_states[j], self->filter_buffer, n_samples); + for (uint8_t k = 0; k < self->base.channel_count; k++) { + synthio_biquad_filter_samples(filter_obj, &self->filter_states[j * self->base.channel_count + k], self->filter_buffer + k * SYNTHIO_MAX_DUR, n_samples); + } } // Mix processed signal with original sample and transfer to output buffer - for (uint32_t j = 0; j < n_samples; j++) { + for (uint32_t j = 0; j < n_samples * self->base.channel_count; j++) { + bool buf_offset = (j % self->base.channel_count) == 1; + uint32_t k = j / self->base.channel_count; if (MP_LIKELY(self->base.bits_per_sample == 16)) { - word_buffer[i + j] = synthio_mix_down_sample((int32_t)((sample_src[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)), SYNTHIO_MIX_DOWN_SCALE(2)); + word_buffer[i + j] = synthio_mix_down_sample((int32_t)((sample_src[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)), SYNTHIO_MIX_DOWN_SCALE(2)); if (!self->base.samples_signed) { word_buffer[i + j] ^= 0x8000; } } else { if (self->base.samples_signed) { - hword_buffer[i + j] = (int8_t)((sample_hsrc[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)); + hword_buffer[i + j] = (int8_t)((sample_hsrc[i + j] * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)); } else { - hword_buffer[i + j] = (uint8_t)(((int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80) * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[j] * mix)) ^ 0x80; + hword_buffer[i + j] = (uint8_t)(((int8_t)(((uint8_t)sample_hsrc[i + j]) ^ 0x80) * (MICROPY_FLOAT_CONST(1.0) - mix)) + (self->filter_buffer[k + SYNTHIO_MAX_DUR * buf_offset] * mix)) ^ 0x80; } } } - i += n_samples; + i += n_samples * self->base.channel_count; } } diff --git a/shared-module/audiofilters/Filter.h b/shared-module/audiofilters/Filter.h index 4447f8a2988..e24827e44a8 100644 --- a/shared-module/audiofilters/Filter.h +++ b/shared-module/audiofilters/Filter.h @@ -21,7 +21,7 @@ typedef struct { synthio_block_slot_t mix; mp_obj_t *filter_objs; - size_t filter_states_len; + size_t filter_objs_len; biquad_filter_state *filter_states; int8_t *buffer[2]; From 8cabd2ad5fa09a33869d8aed55ea45e1934417e1 Mon Sep 17 00:00:00 2001 From: Piclaw Date: Sat, 23 May 2026 15:25:47 -0700 Subject: [PATCH 512/876] bitmaptools.alphablend: add optional L8 mask= kwarg Adds an optional mask= keyword argument to bitmaptools.alphablend() that scales source2's per-pixel contribution by an L8 bitmap (one byte per pixel, 0..255). When mask is None (default), behavior is unchanged from the existing alphablend. Mask bitmap must match the output bitmap's width and height and have a bits_per_value of 8. --- locale/circuitpython.pot | 8 ++++++ shared-bindings/bitmaptools/__init__.c | 22 +++++++++++++-- shared-bindings/bitmaptools/__init__.h | 3 +- shared-module/bitmaptools/__init__.c | 39 +++++++++++++++++++++++--- 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index e09df9d1781..91198cd1795 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1441,6 +1441,14 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" + #: py/persistentcode.c msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" diff --git a/shared-bindings/bitmaptools/__init__.c b/shared-bindings/bitmaptools/__init__.c index 4d56f393189..a56075344e8 100644 --- a/shared-bindings/bitmaptools/__init__.c +++ b/shared-bindings/bitmaptools/__init__.c @@ -311,6 +311,7 @@ MAKE_ENUM_TYPE(bitmaptools, BlendMode, bitmaptools_blendmode); //| blendmode: Optional[BlendMode] = BlendMode.Normal, //| skip_source1_index: Union[int, None] = None, //| skip_source2_index: Union[int, None] = None, +//| mask: Optional[displayio.Bitmap] = None, //| ) -> None: //| """Alpha blend the two source bitmaps into the destination. //| @@ -326,6 +327,11 @@ MAKE_ENUM_TYPE(bitmaptools, BlendMode, bitmaptools_blendmode); //| :param bitmaptools.BlendMode blendmode: The blend mode to use. Default is Normal. //| :param int skip_source1_index: Bitmap palette or luminance index in source_bitmap_1 that will not be blended, set to None to blend all pixels //| :param int skip_source2_index: Bitmap palette or luminance index in source_bitmap_2 that will not be blended, set to None to blend all pixels +//| :param displayio.Bitmap mask: Optional 8-bits-per-value grayscale mask bitmap controlling per-pixel opacity of ``source_bitmap_2``. +//| The mask must have the same width and height as the other bitmaps and a ``bits_per_value`` of 8. A mask value of 0 +//| means ``source_bitmap_2`` is fully transparent at that pixel (only ``source_bitmap_1`` contributes); a value of 255 means +//| ``source_bitmap_2`` is fully opaque at that pixel (subject to ``factor2``). Intermediate values scale ``factor2`` linearly. +//| Pass ``None`` to disable per-pixel masking. //| //| For the L8 colorspace, the bitmaps must have a bits-per-value of 8. //| For the RGB colorspaces, they must have a bits-per-value of 16.""" @@ -333,7 +339,7 @@ MAKE_ENUM_TYPE(bitmaptools, BlendMode, bitmaptools_blendmode); //| static mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum {ARG_dest_bitmap, ARG_source_bitmap_1, ARG_source_bitmap_2, ARG_colorspace, ARG_factor_1, ARG_factor_2, ARG_blendmode, ARG_skip_source1_index, ARG_skip_source2_index}; + enum {ARG_dest_bitmap, ARG_source_bitmap_1, ARG_source_bitmap_2, ARG_colorspace, ARG_factor_1, ARG_factor_2, ARG_blendmode, ARG_skip_source1_index, ARG_skip_source2_index, ARG_mask}; static const mp_arg_t allowed_args[] = { {MP_QSTR_dest_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = NULL}}, @@ -345,6 +351,7 @@ static mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, {MP_QSTR_blendmode, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = (void *)&bitmaptools_blendmode_Normal_obj}}, {MP_QSTR_skip_source1_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, {MP_QSTR_skip_source2_index, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + {MP_QSTR_mask, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -411,8 +418,19 @@ static mp_obj_t bitmaptools_alphablend(size_t n_args, const mp_obj_t *pos_args, skip_source2_index_none = false; } + displayio_bitmap_t *mask = NULL; + if (args[ARG_mask].u_obj != mp_const_none) { + mask = MP_OBJ_TO_PTR(mp_arg_validate_type(args[ARG_mask].u_obj, &displayio_bitmap_type, MP_QSTR_mask)); + if (mask->width != destination->width || mask->height != destination->height) { + mp_raise_ValueError(MP_ERROR_TEXT("Mask bitmap size must match the other bitmaps")); + } + if (mask->bits_per_value != 8) { + mp_raise_ValueError(MP_ERROR_TEXT("Mask bitmap must have 8 bits per pixel")); + } + } + common_hal_bitmaptools_alphablend(destination, source1, source2, colorspace, factor1, factor2, blendmode, skip_source1_index, - skip_source1_index_none, skip_source2_index, skip_source2_index_none); + skip_source1_index_none, skip_source2_index, skip_source2_index_none, mask); return mp_const_none; } diff --git a/shared-bindings/bitmaptools/__init__.h b/shared-bindings/bitmaptools/__init__.h index f193ef6d952..20236983bac 100644 --- a/shared-bindings/bitmaptools/__init__.h +++ b/shared-bindings/bitmaptools/__init__.h @@ -69,7 +69,8 @@ void common_hal_bitmaptools_arrayblit(displayio_bitmap_t *self, void *data, int void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bitmap_t *source_bitmap, displayio_colorspace_t colorspace, bitmaptools_dither_algorithm_t algorithm); void common_hal_bitmaptools_alphablend(displayio_bitmap_t *destination, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, mp_float_t factor1, mp_float_t factor2, - bitmaptools_blendmode_t blendmode, uint32_t skip_source1_index, bool skip_source1_index_none, uint32_t skip_source2_index, bool skip_source2_index_none); + bitmaptools_blendmode_t blendmode, uint32_t skip_source1_index, bool skip_source1_index_none, uint32_t skip_source2_index, bool skip_source2_index_none, + displayio_bitmap_t *mask); typedef struct { union { diff --git a/shared-module/bitmaptools/__init__.c b/shared-module/bitmaptools/__init__.c index 2f2b7aaf475..e51881aa5bb 100644 --- a/shared-module/bitmaptools/__init__.c +++ b/shared-module/bitmaptools/__init__.c @@ -857,12 +857,15 @@ void common_hal_bitmaptools_dither(displayio_bitmap_t *dest_bitmap, displayio_bi } void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitmap_t *source1, displayio_bitmap_t *source2, displayio_colorspace_t colorspace, mp_float_t factor1, mp_float_t factor2, - bitmaptools_blendmode_t blendmode, uint32_t skip_source1_index, bool skip_source1_index_none, uint32_t skip_source2_index, bool skip_source2_index_none) { + bitmaptools_blendmode_t blendmode, uint32_t skip_source1_index, bool skip_source1_index_none, uint32_t skip_source2_index, bool skip_source2_index_none, + displayio_bitmap_t *mask) { displayio_area_t a = {0, 0, dest->width, dest->height, NULL}; displayio_bitmap_set_dirty_area(dest, &a); - int ifactor1 = (int)(factor1 * 256); - int ifactor2 = (int)(factor2 * 256); + int ifactor1_base = (int)(factor1 * 256); + int ifactor2_base = (int)(factor2 * 256); + int ifactor1 = ifactor1_base; + int ifactor2 = ifactor2_base; bool blend_source1, blend_source2; if (colorspace == DISPLAYIO_COLORSPACE_L8) { @@ -870,10 +873,20 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma uint8_t *dptr = (uint8_t *)(dest->data + y * dest->stride); uint8_t *sptr1 = (uint8_t *)(source1->data + y * source1->stride); uint8_t *sptr2 = (uint8_t *)(source2->data + y * source2->stride); + uint8_t *mptr = mask ? (uint8_t *)(mask->data + y * mask->stride) : NULL; int pixel; for (int x = 0; x < dest->width; x++) { blend_source1 = skip_source1_index_none || *sptr1 != (uint8_t)skip_source1_index; blend_source2 = skip_source2_index_none || *sptr2 != (uint8_t)skip_source2_index; + if (mptr) { + uint8_t m = *mptr; + // Scale source2's contribution by the mask (0..255) + ifactor2 = (ifactor2_base * m + 127) / 255; + if (m == 0) { + // Mask says fully transparent: drop source2 entirely + blend_source2 = false; + } + } if (blend_source1 && blend_source2) { // Premultiply by the alpha factor int sda = *sptr1++ *ifactor1; @@ -886,7 +899,8 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma blend = sca + sda * (256 - ifactor2) / 256; } // Divide by the alpha factor - pixel = (blend / (ifactor1 + ifactor2 - ifactor1 * ifactor2 / 256)); + int denom = ifactor1 + ifactor2 - ifactor1 * ifactor2 / 256; + pixel = (denom > 0) ? (blend / denom) : 0; } else if (blend_source1) { // Apply iFactor1 to source1 only pixel = *sptr1++ *ifactor1 / 256; @@ -898,6 +912,9 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma pixel = *dptr; } *dptr++ = MIN(255, MAX(0, pixel)); + if (mptr) { + mptr++; + } } } } else { @@ -907,6 +924,7 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma uint16_t *dptr = (uint16_t *)(dest->data + y * dest->stride); uint16_t *sptr1 = (uint16_t *)(source1->data + y * source1->stride); uint16_t *sptr2 = (uint16_t *)(source2->data + y * source2->stride); + uint8_t *mptr = mask ? (uint8_t *)(mask->data + y * mask->stride) : NULL; for (int x = 0; x < dest->width; x++) { int spix1 = *sptr1++; int spix2 = *sptr2++; @@ -922,11 +940,24 @@ void common_hal_bitmaptools_alphablend(displayio_bitmap_t *dest, displayio_bitma blend_source1 = skip_source1_index_none || spix1 != (int)skip_source1_index; blend_source2 = skip_source2_index_none || spix2 != (int)skip_source2_index; + if (mptr) { + uint8_t m = *mptr++; + ifactor2 = (ifactor2_base * m + 127) / 255; + if (m == 0) { + blend_source2 = false; + } + } + if (blend_source1 && blend_source2) { // Blend based on the SVG alpha compositing specs // https://dev.w3.org/SVG/modules/compositing/master/#alphaCompositing int ifactor_blend = ifactor1 + ifactor2 - ifactor1 * ifactor2 / 256; + if (ifactor_blend <= 0) { + // Both factors are zero at this pixel; keep destination. + dptr++; + continue; + } // Premultiply the colors by the alpha factor int red_dca = ((spix1 & r_mask) >> 8) * ifactor1; From 074fb8824a84d6eb4be889bef5765ae0fa06f786 Mon Sep 17 00:00:00 2001 From: makermelissa-piclaw Date: Sat, 23 May 2026 16:58:50 -0700 Subject: [PATCH 513/876] dotclockframebuffer: fix gpio_data range validation The upper-bound expression used `max_bit * 8` instead of `gpio_data_len * 8`. With `gpio_data_len = 1` (the common case), `max_bit` is 7 and the shift becomes `(1 << 56) - 1`, which is undefined behavior on a 32-bit `mp_int_t`. In practice the upper bound wraps to 1, so any `gpio_data` value > 1 raises `ValueError: gpio_data must be 0..1` even though a full byte is legitimate. This blocks initializing displays through `dotclockframebuffer.ioexpander_send_init_sequence(...)` when the init sequence contains real one-byte register writes; e.g. the Adafruit Qualia ESP32-S3 + 4" 480x480 round TFT crashes during display init. The fix is to use `gpio_data_len` (which is already the field width in bytes) directly. For `gpio_data_len = 1` this gives the correct `(1 << 8) - 1 = 255` upper bound. --- shared-bindings/dotclockframebuffer/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/dotclockframebuffer/__init__.c b/shared-bindings/dotclockframebuffer/__init__.c index b8dbf8c1897..700cd067178 100644 --- a/shared-bindings/dotclockframebuffer/__init__.c +++ b/shared-bindings/dotclockframebuffer/__init__.c @@ -104,7 +104,7 @@ static mp_obj_t ioexpander_send_init_sequence(size_t n_args, const mp_obj_t *pos mp_arg_validate_int_range(cs_bit, 0, max_bit, MP_QSTR_cs_bit); mp_arg_validate_int_range(mosi_bit, 0, max_bit, MP_QSTR_mosi_bit); mp_arg_validate_int_range(clk_bit, 0, max_bit, MP_QSTR_clk_bit); - mp_arg_validate_int_range(gpio_data, 0, (1 << (max_bit * 8)) - 1, MP_QSTR_gpio_data); + mp_arg_validate_int_range(gpio_data, 0, (1 << (gpio_data_len * 8)) - 1, MP_QSTR_gpio_data); mp_int_t reset_mask = 0; if (args[ARG_reset_bit].u_obj != MP_ROM_NONE) { mp_int_t reset_bit = mp_arg_validate_int_range(mp_arg_validate_type_int(args[ARG_reset_bit].u_obj, MP_QSTR_reset_bit), 0, max_bit, MP_QSTR_reset_bit); From 32316e3c444edd442d955834debb34ed49072a75 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 26 May 2026 10:52:02 -0500 Subject: [PATCH 514/876] use not shift instead of bit-replication --- ports/espressif/common-hal/audioi2sin/I2SIn.c | 17 ++++---------- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 23 +++++++------------ 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index fd2e9d33a2b..787675cce7b 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -150,19 +150,10 @@ static inline void i2sin_write_converted(void *buffer, uint32_t idx, int32_t s = i2sin_normalize_signed(raw, in_depth); int32_t shifted; if (out_depth >= in_depth) { - // Bit-replicate the input across the wider output so that full-scale - // input maps to full-scale output (e.g. 8-bit 0xFF -> 16-bit 0xFFFF), - // rather than leaving the new low bits as zero. - uint32_t in_mask = (in_depth >= 32) ? 0xffffffffu : ((1u << in_depth) - 1u); - uint32_t in_bits = (uint32_t)s & in_mask; - uint32_t result = 0; - int remaining = out_depth; - while (remaining > 0) { - int take = (remaining >= (int)in_depth) ? (int)in_depth : remaining; - result = (result << take) | (in_bits >> (in_depth - take)); - remaining -= take; - } - shifted = (int32_t)result; + // Left-justify: place the input's bits in the high bits of the wider + // output and leave the new low bits as zero. The API contract is that + // for upscaled output the meaningful data is the high `in_depth` bits. + shifted = s << (out_depth - in_depth); } else { shifted = s >> (in_depth - out_depth); } diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index b32c23ce984..d641cf793fb 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -398,8 +398,10 @@ static inline int32_t i2sin_normalize_signed(uint32_t raw, uint8_t in_depth, } // Write `raw` (input-depth bits, just-read FIFO sample) to `buffer` at sample -// index `idx`, converting from `in_depth` to `out_depth` and (if needed) -// flipping the sign bit for the unsigned-WAV convention. Output element size +// index `idx`, converting from `in_depth` to `out_depth` (shift-only +// semantics, sign-preserving for signed) and (if needed) flipping the sign bit +// for the unsigned-WAV convention. When upscaling, the input occupies the high +// `in_depth` bits and the new low bits are left as zero. Output element size // follows `out_depth`: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. // // For signed 24-bit output, the int32 slot holds the sign-extended value @@ -412,19 +414,10 @@ static inline void i2sin_write_converted(void *buffer, uint32_t idx, int32_t s = i2sin_normalize_signed(raw, in_depth, left_justified); int32_t shifted; if (out_depth >= in_depth) { - // Bit-replicate the input across the wider output so that full-scale - // input maps to full-scale output (e.g. 8-bit 0xFF -> 16-bit 0xFFFF), - // rather than leaving the new low bits as zero. - uint32_t in_mask = (in_depth >= 32) ? 0xffffffffu : ((1u << in_depth) - 1u); - uint32_t in_bits = (uint32_t)s & in_mask; - uint32_t result = 0; - int remaining = out_depth; - while (remaining > 0) { - int take = (remaining >= (int)in_depth) ? (int)in_depth : remaining; - result = (result << take) | (in_bits >> (in_depth - take)); - remaining -= take; - } - shifted = (int32_t)result; + // Left-justify: place the input's bits in the high bits of the wider + // output and leave the new low bits as zero. The API contract is that + // for upscaled output the meaningful data is the high `in_depth` bits. + shifted = s << (out_depth - in_depth); } else { shifted = s >> (in_depth - out_depth); } From 6db3d754ad0508d2ea33158bef4c4c1c6bbcdb72 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 26 May 2026 21:13:21 +0200 Subject: [PATCH 515/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 8 ++++++++ locale/el.po | 8 ++++++++ locale/hi.po | 8 ++++++++ locale/ko.po | 8 ++++++++ locale/ru.po | 8 ++++++++ locale/tr.po | 8 ++++++++ 6 files changed, 48 insertions(+) diff --git a/locale/cs.po b/locale/cs.po index 0d4259c67b1..8b74ea65cf9 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1461,6 +1461,14 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" + #: py/persistentcode.c msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" diff --git a/locale/el.po b/locale/el.po index f38689079e1..35706161025 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1467,6 +1467,14 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" + #: py/persistentcode.c msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index 7f2a366edda..0ad0394d060 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1443,6 +1443,14 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" + #: py/persistentcode.c msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index ce536446cf2..8731a7e8d4b 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1494,6 +1494,14 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "매핑은 투플이어야 합니다" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" + #: py/persistentcode.c msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 0e67d5b1653..e535756a036 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1482,6 +1482,14 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "Сопоставление должно быть кортежом" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" + #: py/persistentcode.c msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" diff --git a/locale/tr.po b/locale/tr.po index 59f831c4e4e..7b367e53c12 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1462,6 +1462,14 @@ msgstr "" msgid "Mapping must be a tuple" msgstr "Map tuple olmalıdır" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" + #: py/persistentcode.c msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" From d3709fac211fcee4a96c08dbfc717bc9439f03ad Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 26 May 2026 16:44:37 -0500 Subject: [PATCH 516/876] right-justify 24 in 32 bit format. --- ports/espressif/common-hal/audioi2sin/I2SIn.c | 16 +++++++++------ .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 20 ++++++++++--------- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 787675cce7b..28c61aafc2f 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -142,18 +142,22 @@ static inline uint32_t i2sin_read_raw(const uint8_t *src, uint8_t in_depth) { return v; } -// Convert `raw` from `in_depth` to `out_depth` (shift-only semantics, sign- -// preserving for signed) and write it to `buffer` at sample index `idx`. +// Convert `raw` from `in_depth` to `out_depth` (sign-preserving for signed) and +// write it to `buffer` at sample index `idx`. When upscaling, the value is +// right-justified: the meaningful data stays in the low `in_depth` bits with the +// upper bits carrying the sign, so a wider output uses a larger container without +// scaling the magnitude up. (This means 24-bit-in-32-bit output is +// right-justified) // Output element size: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. static inline void i2sin_write_converted(void *buffer, uint32_t idx, uint32_t raw, uint8_t in_depth, uint8_t out_depth, bool samples_signed) { int32_t s = i2sin_normalize_signed(raw, in_depth); int32_t shifted; if (out_depth >= in_depth) { - // Left-justify: place the input's bits in the high bits of the wider - // output and leave the new low bits as zero. The API contract is that - // for upscaled output the meaningful data is the high `in_depth` bits. - shifted = s << (out_depth - in_depth); + // Right-justify: keep the value as-is so the meaningful bits stay in the + // low `in_depth` bits (upper bits already sign-extended). The wider + // output just provides a larger container. + shifted = s; } else { shifted = s >> (in_depth - out_depth); } diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index d641cf793fb..3617fa11a81 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -398,11 +398,13 @@ static inline int32_t i2sin_normalize_signed(uint32_t raw, uint8_t in_depth, } // Write `raw` (input-depth bits, just-read FIFO sample) to `buffer` at sample -// index `idx`, converting from `in_depth` to `out_depth` (shift-only -// semantics, sign-preserving for signed) and (if needed) flipping the sign bit -// for the unsigned-WAV convention. When upscaling, the input occupies the high -// `in_depth` bits and the new low bits are left as zero. Output element size -// follows `out_depth`: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. +// index `idx`, converting from `in_depth` to `out_depth` (sign-preserving for +// signed) and (if needed) flipping the sign bit for the unsigned-WAV +// convention. When upscaling, the value is right-justified: the meaningful data +// stays in the low `in_depth` bits with the upper bits carrying the sign, so a +// wider output simply uses a larger container without scaling the magnitude up. +// (Note this means 24-bit-in-32-bit output is right-justified.) Output element size follows `out_depth`: 1 byte +// at 8, 2 bytes at 16, 4 bytes at 24 or 32. // // For signed 24-bit output, the int32 slot holds the sign-extended value // (range -2^23 .. 2^23-1) — unlike the default `output_bit_depth=bit_depth=24` @@ -414,10 +416,10 @@ static inline void i2sin_write_converted(void *buffer, uint32_t idx, int32_t s = i2sin_normalize_signed(raw, in_depth, left_justified); int32_t shifted; if (out_depth >= in_depth) { - // Left-justify: place the input's bits in the high bits of the wider - // output and leave the new low bits as zero. The API contract is that - // for upscaled output the meaningful data is the high `in_depth` bits. - shifted = s << (out_depth - in_depth); + // Right-justify: keep the value as-is so the meaningful bits stay in the + // low `in_depth` bits (upper bits already sign-extended). The wider + // output just provides a larger container. + shifted = s; } else { shifted = s >> (in_depth - out_depth); } From bb0315f23e1dcda80bccee8f1a8f3102e74f0c3d Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Wed, 27 May 2026 07:27:11 +0000 Subject: [PATCH 517/876] Add PCBCupid Glyph Mini 2040 board --- .../boards/pcbcupid_glyph_mini_2040/board.c | 1 + .../pcbcupid_glyph_mini_2040/board.json | 9 +++++ .../pcbcupid_glyph_mini_2040/mpconfigboard.h | 12 ++++++ .../pcbcupid_glyph_mini_2040/mpconfigboard.mk | 9 +++++ .../pico-sdk-configboard.h | 9 +++++ .../boards/pcbcupid_glyph_mini_2040/pins.c | 37 +++++++++++++++++++ 6 files changed, 77 insertions(+) create mode 100644 ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.c create mode 100644 ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.json create mode 100644 ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pins.c diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.c b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.c new file mode 100644 index 00000000000..1ce23b26459 --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.c @@ -0,0 +1 @@ +#include "shared-bindings/board/__init__.h" diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.json b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.json new file mode 100644 index 00000000000..25c8b639a1b --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.json @@ -0,0 +1,9 @@ +{ + "manufacturer": "PCBCupid", + "name": "Glyph Mini 2040", + "downloads_display_name": "PCBCupid Glyph Mini 2040", + "boardname": "pcbcupid_glyph_mini_2040", + "url": "https://pcbcupid.com", + "blinka": false, + "aliases": [] +} diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.h b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.h new file mode 100644 index 00000000000..75deccbc8ed --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.h @@ -0,0 +1,12 @@ +#ifndef MICROPY_INCLUDED_RASPBERRYPI_BOARDS_PCBCUPID_Glyph_Mini_2040 +#define MICROPY_INCLUDED_RASPBERRYPI_BOARDS_PCBCUPID_Glyph_Mini_2040 + +#define MICROPY_HW_BOARD_NAME "PCBCupid Glyph Mini 2040" +#define MICROPY_HW_MCU_NAME "rp2040" + +#define FLASH_SIZE (8 * 1024 * 1024) +#define CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_SIZE (7 * 1024 * 1024) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO16) + +#endif diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.mk b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.mk new file mode 100644 index 00000000000..415aecd6395 --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/mpconfigboard.mk @@ -0,0 +1,9 @@ +USB_VID = 0x2E8A +USB_PID = 0x1123 +USB_PRODUCT = "Glyph Mini 2040" +USB_MANUFACTURER = "PCBCupid" + +CHIP_VARIANT = RP2040 +CHIP_FAMILY = rp2 + +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pico-sdk-configboard.h b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pico-sdk-configboard.h new file mode 100644 index 00000000000..110195b7794 --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pico-sdk-configboard.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2021 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pins.c b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pins.c new file mode 100644 index 00000000000..d2719b1ebea --- /dev/null +++ b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/pins.c @@ -0,0 +1,37 @@ +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO16) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); From ef4b32f22360f7ef64b0842d325d71891e7685e6 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 27 May 2026 13:12:51 -0500 Subject: [PATCH 518/876] update docs for output_depth --- shared-bindings/audioi2sin/I2SIn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 16ba7bf76f3..0f71b7f70a2 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -69,7 +69,7 @@ //| transported in 32-bit slots, so use ``bit_depth=32`` and an ``'I'`` buffer. //| :param int output_bit_depth: If set, recorded samples are bit-shifted from //| ``bit_depth`` to this width before being written to the destination buffer -//| (8, 16, 24, or 32). Widening pads the new LSBs with zero; narrowing arithmetic- +//| (8, 16, 24, or 32). Widening pads the new MSBs with zero; narrowing arithmetic- //| shifts the value right (sign-preserving when ``samples_signed`` is True). When //| ``None`` (the default) the destination buffer holds samples at ``bit_depth``. //| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise. From 21e44aa9dc5d644ebf8b040daf81961e4c949f45 Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Thu, 28 May 2026 11:30:51 +0000 Subject: [PATCH 519/876] Remove board.json from GLYPH Mini 2040 --- .../boards/pcbcupid_glyph_mini_2040/board.json | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.json diff --git a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.json b/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.json deleted file mode 100644 index 25c8b639a1b..00000000000 --- a/ports/raspberrypi/boards/pcbcupid_glyph_mini_2040/board.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "manufacturer": "PCBCupid", - "name": "Glyph Mini 2040", - "downloads_display_name": "PCBCupid Glyph Mini 2040", - "boardname": "pcbcupid_glyph_mini_2040", - "url": "https://pcbcupid.com", - "blinka": false, - "aliases": [] -} From 0de82f2684239cb0dc28b1e7be8cf0674e7873f6 Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Thu, 28 May 2026 13:17:17 +0000 Subject: [PATCH 520/876] Add Glyph S3 board files --- .../boards/pcbcupid_glyph_s3/board.c | 10 ++++ .../boards/pcbcupid_glyph_s3/mpconfigboard.h | 22 +++++++ .../boards/pcbcupid_glyph_s3/mpconfigboard.mk | 10 ++++ .../espressif/boards/pcbcupid_glyph_s3/pins.c | 59 +++++++++++++++++++ .../boards/pcbcupid_glyph_s3/sdkconfig | 0 5 files changed, 101 insertions(+) create mode 100644 ports/espressif/boards/pcbcupid_glyph_s3/board.c create mode 100644 ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.h create mode 100644 ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk create mode 100644 ports/espressif/boards/pcbcupid_glyph_s3/pins.c create mode 100644 ports/espressif/boards/pcbcupid_glyph_s3/sdkconfig diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/board.c b/ports/espressif/boards/pcbcupid_glyph_s3/board.c new file mode 100644 index 00000000000..27b058c946f --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_s3/board.c @@ -0,0 +1,10 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +void board_init(void) { +} diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.h new file mode 100644 index 00000000000..bc17cb65dfc --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "PCBCupid GLYPH S3" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO21) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO35) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO36) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk new file mode 100644 index 00000000000..5999a58eeeb --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk @@ -0,0 +1,10 @@ +USB_VID = 0x303A +USB_PID = 0x8371 +USB_PRODUCT = "GLYPH S3" +USB_MANUFACTURER = "PCBCupid" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/pins.c b/ports/espressif/boards/pcbcupid_glyph_s3/pins.c new file mode 100644 index 00000000000..5b962f2f74d --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_s3/pins.c @@ -0,0 +1,59 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_D1), MP_ROM_PTR(&pin_GPIO1) }, + + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_D2), MP_ROM_PTR(&pin_GPIO2) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_A6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_A7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + + { MP_ROM_QSTR(MP_QSTR_A8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_A9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_A10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_D17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO37) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/sdkconfig b/ports/espressif/boards/pcbcupid_glyph_s3/sdkconfig new file mode 100644 index 00000000000..e69de29bb2d From 2722f6bf8e97f7103f0606ba3b8b2b324a1fe705 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 28 May 2026 14:12:32 -0400 Subject: [PATCH 521/876] Espressif BLE fixes: advertising duration, _bleio.adapter.connected 1. The advertising duration value for "forever" is different for `ble_gap_adv_start()` and `ble_gap_ext_adv_start()`. It is `BLE_HS_FOREVER` and `0`, respectively. 2. Code was added in #9289 that required that the MTU value was non-zero when returning true for `_bleio.adapter.connected`. This caused a brief interval, while a central was connecting, for a peripheral with both `ble.connected()` and `ble.advertising()` being `False`. The transition between the two states did not appear atomic. This compares with `nordic` where it was. --- ports/espressif/common-hal/_bleio/Adapter.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index bbf7b7e0e2f..d39b22a3ae9 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -561,10 +561,6 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool high_duty_directed = directed_to != NULL && interval <= 3.5 && timeout <= 1; // Really 1.3, but it's an int uint32_t timeout_ms = timeout * 1000; - if (timeout_ms == 0) { - timeout_ms = BLE_HS_FOREVER; - } - #if MYNEWT_VAL(BLE_EXT_ADV) bool extended = advertising_data_len > BLE_ADV_LEGACY_DATA_MAX_LEN || @@ -626,8 +622,12 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, } } + // If timeout_ms is zero, it means advertise forever. This is different than ble_gap_adv_start(). rc = ble_gap_ext_adv_start(0, timeout_ms, 0); + #else + // Extended advertising not enabled. + uint8_t conn_mode = connectable ? BLE_GAP_CONN_MODE_UND : BLE_GAP_CONN_MODE_NON; if (directed_to != NULL) { conn_mode = BLE_GAP_CONN_MODE_DIR; @@ -654,8 +654,10 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, return rc; } } - rc = ble_gap_adv_start(own_addr_type, directed_to != NULL ? &peer: NULL, - timeout_ms, + // If timeout_ms is BLE_HS_FOREVER, it means advertise forever. This is different than ble_gap_ext_adv_start(). + rc = ble_gap_adv_start(own_addr_type, + directed_to != NULL ? &peer: NULL, + timeout_ms == 0 ? BLE_HS_FOREVER : timeout_ms, &adv_params, _advertising_event, self); #endif @@ -739,7 +741,7 @@ bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { bool common_hal_bleio_adapter_get_connected(bleio_adapter_obj_t *self) { for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; - if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->mtu != 0) { + if (connection->conn_handle != BLEIO_HANDLE_INVALID) { return true; } } @@ -754,7 +756,7 @@ mp_obj_t common_hal_bleio_adapter_get_connections(bleio_adapter_obj_t *self) { mp_obj_t items[BLEIO_TOTAL_CONNECTION_COUNT]; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; - if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->mtu != 0) { + if (connection->conn_handle != BLEIO_HANDLE_INVALID) { if (connection->connection_obj == mp_const_none) { connection->connection_obj = bleio_connection_new_from_internal(connection); } From db73edb00f296ff63a26ec5518b7b985e7b5f6e2 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 29 May 2026 08:53:48 -0500 Subject: [PATCH 522/876] update docs for output_depth --- shared-bindings/audioi2sin/I2SIn.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 0f71b7f70a2..45e3645ed2f 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -69,9 +69,12 @@ //| transported in 32-bit slots, so use ``bit_depth=32`` and an ``'I'`` buffer. //| :param int output_bit_depth: If set, recorded samples are bit-shifted from //| ``bit_depth`` to this width before being written to the destination buffer -//| (8, 16, 24, or 32). Widening pads the new MSBs with zero; narrowing arithmetic- -//| shifts the value right (sign-preserving when ``samples_signed`` is True). When -//| ``None`` (the default) the destination buffer holds samples at ``bit_depth``. +//| (8, 16, 24, or 32). Widening keeps the value right-justified: for signed +//| samples the new MSBs replicate the sign bit (zeros for positive values, ones +//| for negative), while for unsigned samples the new MSBs are zero. Narrowing +//| arithmetic-shifts the value right (sign-preserving when ``samples_signed`` is +//| True). When ``None`` (the default) the destination buffer holds samples at +//| ``bit_depth``. //| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise. //| :param bool left_justified: True when data bits are aligned with the word select clock. False //| when they are shifted by one to match classic I2S protocol. Set True for mics like the SPH0645LM4H. From 401a8e504ca3a0b37a98266a496574c75ef38d15 Mon Sep 17 00:00:00 2001 From: Danil Zagoskin Date: Sat, 30 May 2026 15:10:54 +0300 Subject: [PATCH 523/876] espressif: enable DUALBANK on large enough boards --- ports/espressif/mpconfigport.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 67f8ca2987b..39834c04678 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -339,6 +339,9 @@ CIRCUITPY_AUDIOIO = 0 endif #### end chip-specific choices ######################################## +# By default, enable dualbank, and it'll be disabled for small flash sizes +CIRCUITPY_DUALBANK = 1 + # No room for large modules on 2MB boards # 2MB boards have a single firmware partition, and can't do dualbank. ifeq ($(CIRCUITPY_ESP_FLASH_SIZE),2MB) From 620d9318a0066a75806f96fba69d0c03b06eff20 Mon Sep 17 00:00:00 2001 From: Danil Zagoskin Date: Sat, 23 May 2026 21:22:47 +0300 Subject: [PATCH 524/876] feat: espressif: add Waveshare ESP32-S3-Tiny-N8R8 board --- .../waveshare_esp32_s3_tiny_n8r8/board.c | 9 +++ .../mpconfigboard.h | 19 ++++++ .../mpconfigboard.mk | 16 +++++ .../waveshare_esp32_s3_tiny_n8r8/pins.c | 61 +++++++++++++++++++ .../waveshare_esp32_s3_tiny_n8r8/sdkconfig | 14 +++++ 5 files changed, 119 insertions(+) create mode 100644 ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/board.c create mode 100644 ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h create mode 100644 ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.mk create mode 100644 ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/pins.c create mode 100644 ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/sdkconfig diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/board.c b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h new file mode 100644 index 00000000000..296d751ab25 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Waveshare ESP32-S3-Tiny-N8R8" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +// This corrects the color ordering so that the CircuitPython status lights behave as expected +#define MICROPY_HW_NEOPIXEL_ORDER_GRB (1) +#define MICROPY_HW_NEOPIXEL (&pin_GPIO38) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO19) +#define DEFAULT_UART_BUS_TX (&pin_GPIO20) diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.mk b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.mk new file mode 100644 index 00000000000..ebb8317c457 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.mk @@ -0,0 +1,16 @@ +USB_VID = 0x303a +USB_PID = 0x8379 +USB_PRODUCT = "ESP32-S3-Tiny-N8R8" +USB_MANUFACTURER = "Waveshare Electronics" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 8MB + +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_NeoPixel diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/pins.c b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/pins.c new file mode 100644 index 00000000000..917ef0506ab --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/pins.c @@ -0,0 +1,61 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO33), MP_ROM_PTR(&pin_GPIO33) }, + { MP_ROM_QSTR(MP_QSTR_IO34), MP_ROM_PTR(&pin_GPIO34) }, + { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + + // NEOPIXEL (GRB Color Order) + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO38) }, + + // UART + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, + // Any pins can be I2C + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, + // Any pins can be SPI + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/sdkconfig b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From daec2dcbc9379c768b2659c7f84a5a2838e393f6 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 31 May 2026 13:38:10 -0400 Subject: [PATCH 525/876] Fix compressed translation qstr ids Teach maketranslationdata.py to assign qstr ids in the same QDEF0/QDEF1 order used by the runtime, including escaped qstr strings, and remove the decoder's compensating +1 offset.\n\nThis fixes compressed translation messages that start with certain qstr-backed words, including the bitmaptools ValueError for mismatched bitmap size and bits per value.\n\nCo-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- py/maketranslationdata.py | 20 ++++++++++++++++---- supervisor/shared/translate/translate.c | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/py/maketranslationdata.py b/py/maketranslationdata.py index 3933387b645..f6a6e85bf0e 100644 --- a/py/maketranslationdata.py +++ b/py/maketranslationdata.py @@ -527,11 +527,23 @@ def esc_char(m): def parse_qstrs(infile): r = {} - rx = re.compile(r'QDEF[01]\([A-Za-z0-9_]+,\s*\d+,\s*\d+,\s*(?P"(?:[^"\\\\]*|\\.)")\)') + rx = re.compile( + r'QDEF(?P[01])\([A-Za-z0-9_]+,\s*\d+,\s*\d+,\s*(?P"(?:[^"\\\\]|\\.)*")\)' + ) content = infile.read() - for i, mat in enumerate(rx.findall(content, re.M)): - mat = eval(mat) - r[mat] = i + matches = rx.finditer(content) + static_qstrs = [] + dynamic_qstrs = [] + for match in matches: + qstr = eval(match.group("cstr")) + if match.group("pool") == "0": + static_qstrs.append(qstr) + else: + dynamic_qstrs.append(qstr) + for i, qstr in enumerate(static_qstrs): + r[qstr] = i + for i, qstr in enumerate(dynamic_qstrs, start=len(static_qstrs)): + r[qstr] = i return r diff --git a/supervisor/shared/translate/translate.c b/supervisor/shared/translate/translate.c index 958e0a2144f..b590b385a71 100644 --- a/supervisor/shared/translate/translate.c +++ b/supervisor/shared/translate/translate.c @@ -114,7 +114,7 @@ static void decompress_vstr(mp_rom_error_text_t compressed, vstr_t *decompressed } int v = values[searched_length + bits - max_code]; if (v == 1) { - qstr q = get_nbits(&b, translation_qstr_bits) + 1; // honestly no idea why "+1"... + qstr q = get_nbits(&b, translation_qstr_bits); vstr_add_str(decompressed, qstr_str(q)); } else { put_utf8(decompressed, v); From d395a7429a73d9df6d9b4bc9aca9dde8be4b4f03 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 31 May 2026 20:51:18 -0400 Subject: [PATCH 526/876] doc improvements: fix #10353, #10378 --- shared-bindings/alarm/__init__.c | 3 +++ shared-bindings/displayio/__init__.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index e9f2db324d5..d229246e781 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -122,6 +122,9 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OB //| //| If no alarms are specified, the microcontroller will deep sleep until reset. //| +//| You cannot initiate a deep sleep from the REPL. +//| You must call `exit_and_deep_sleep_until_alarms()` from a program file. +//| //| :param circuitpython_typing.Alarm alarms: the alarms that can wake the microcontroller. //| :param Sequence[digitalio.DigitalInOut] preserve_dios: A sequence of `DigitalInOut` objects //| whose state should be preserved during deep sleep. diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index e0c35d3bce4..ff67be3501d 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -79,7 +79,12 @@ //| afterwards. This may take seconds to complete if an active EPaperDisplay is refreshing. //| //| Use this once in your code.py if you initialize a display. Place it right before the -//| initialization so the display is active as long as possible.""" +//| initialization so the display is active as long as possible. +//| +//| Once you release a builtin display (one that is initialized automatically, not by user code), +//| the display will remain released even if you restart the CircuitPython VM, for instance by typing ctrl-D. +//| The display is not re-initialized until you do a hard reset. +//| """ //| ... //| //| From 877b4549e1e8e7ed6e497f9bbb6767a9057b3634 Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Mon, 1 Jun 2026 06:34:23 +0000 Subject: [PATCH 527/876] Update USB PID to 0x8373 for GLYPH S3 --- ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk index 5999a58eeeb..9228197411f 100644 --- a/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk +++ b/ports/espressif/boards/pcbcupid_glyph_s3/mpconfigboard.mk @@ -1,5 +1,5 @@ USB_VID = 0x303A -USB_PID = 0x8371 +USB_PID = 0x8373 USB_PRODUCT = "GLYPH S3" USB_MANUFACTURER = "PCBCupid" From 167dcdb949e5b12120ce0d85427253273ae726c9 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 1 Jun 2026 12:59:27 -0500 Subject: [PATCH 528/876] Add stereo filter tests --- .../audiofilter_filter_stereo.py | 24 + .../audiofilter_filter_stereo.py.exp | 15360 +++ .../audiofilter_filter_stereo_biquads.py | 27 + .../audiofilter_filter_stereo_biquads.py.exp | 102400 +++++++++++++++ 4 files changed, 117811 insertions(+) create mode 100644 tests/circuitpython/audiofilter_filter_stereo.py create mode 100644 tests/circuitpython/audiofilter_filter_stereo.py.exp create mode 100644 tests/circuitpython/audiofilter_filter_stereo_biquads.py create mode 100644 tests/circuitpython/audiofilter_filter_stereo_biquads.py.exp diff --git a/tests/circuitpython/audiofilter_filter_stereo.py b/tests/circuitpython/audiofilter_filter_stereo.py new file mode 100644 index 00000000000..f260286f931 --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_stereo.py @@ -0,0 +1,24 @@ +from audiofilters import Filter +from audiofilterhelper import synth_test, sine8k +from audiomixer import Mixer +from synthio import LFO + + +@synth_test +def stereo_filter(): + args = { + "bits_per_sample": 16, + "samples_signed": True, + "channel_count": 2, + } + effect = Filter(**args) + mixer = Mixer(**args) + mixer.voice[0].panning = LFO() + effect.play(mixer) + yield effect, [] + + mixer.play(sine8k, loop=True) + yield 40 + + mixer.stop_voice() + yield 20 diff --git a/tests/circuitpython/audiofilter_filter_stereo.py.exp b/tests/circuitpython/audiofilter_filter_stereo.py.exp new file mode 100644 index 00000000000..960c143a1ef --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_stereo.py.exp @@ -0,0 +1,15360 @@ +0 0.0 +1 0.0 +2 0.0 +3 0.0 +4 0.0 +5 0.0 +6 0.0 +7 0.0 +8 0.0 +9 0.0 +10 0.0 +11 0.0 +12 0.0 +13 0.0 +14 0.0 +15 0.0 +16 0.0 +17 0.0 +18 0.0 +19 0.0 +20 0.0 +21 0.0 +22 0.0 +23 0.0 +24 0.0 +25 0.0 +26 0.0 +27 0.0 +28 0.0 +29 0.0 +30 0.0 +31 0.0 +32 0.0 +33 0.0 +34 0.0 +35 0.0 +36 0.0 +37 0.0 +38 0.0 +39 0.0 +40 0.0 +41 0.0 +42 0.0 +43 0.0 +44 0.0 +45 0.0 +46 0.0 +47 0.0 +48 0.0 +49 0.0 +50 0.0 +51 0.0 +52 0.0 +53 0.0 +54 0.0 +55 0.0 +56 0.0 +57 0.0 +58 0.0 +59 0.0 +60 0.0 +61 0.0 +62 0.0 +63 0.0 +64 0.0 +65 0.0 +66 0.0 +67 0.0 +68 0.0 +69 0.0 +70 0.0 +71 0.0 +72 0.0 +73 0.0 +74 0.0 +75 0.0 +76 0.0 +77 0.0 +78 0.0 +79 0.0 +80 0.0 +81 0.0 +82 0.0 +83 0.0 +84 0.0 +85 0.0 +86 0.0 +87 0.0 +88 0.0 +89 0.0 +90 0.0 +91 0.0 +92 0.0 +93 0.0 +94 0.0 +95 0.0 +96 0.0 +97 0.0 +98 0.0 +99 0.0 +100 0.0 +101 0.0 +102 0.0 +103 0.0 +104 0.0 +105 0.0 +106 0.0 +107 0.0 +108 0.0 +109 0.0 +110 0.0 +111 0.0 +112 0.0 +113 0.0 +114 0.0 +115 0.0 +116 0.0 +117 0.0 +118 0.0 +119 0.0 +120 0.0 +121 0.0 +122 0.0 +123 0.0 +124 0.0 +125 0.0 +126 0.0 +127 0.0 +128 0.0 +129 0.0 +130 0.0 +131 0.0 +132 0.0 +133 0.0 +134 0.0 +135 0.0 +136 0.0 +137 0.0 +138 0.0 +139 0.0 +140 0.0 +141 0.0 +142 0.0 +143 0.0 +144 0.0 +145 0.0 +146 0.0 +147 0.0 +148 0.0 +149 0.0 +150 0.0 +151 0.0 +152 0.0 +153 0.0 +154 0.0 +155 0.0 +156 0.0 +157 0.0 +158 0.0 +159 0.0 +160 0.0 +161 0.0 +162 0.0 +163 0.0 +164 0.0 +165 0.0 +166 0.0 +167 0.0 +168 0.0 +169 0.0 +170 0.0 +171 0.0 +172 0.0 +173 0.0 +174 0.0 +175 0.0 +176 0.0 +177 0.0 +178 0.0 +179 0.0 +180 0.0 +181 0.0 +182 0.0 +183 0.0 +184 0.0 +185 0.0 +186 0.0 +187 0.0 +188 0.0 +189 0.0 +190 0.0 +191 0.0 +192 0.0 +193 0.0 +194 0.0 +195 0.0 +196 0.0 +197 0.0 +198 0.0 +199 0.0 +200 0.0 +201 0.0 +202 0.0 +203 0.0 +204 0.0 +205 0.0 +206 0.0 +207 0.0 +208 0.0 +209 0.0 +210 0.0 +211 0.0 +212 0.0 +213 0.0 +214 0.0 +215 0.0 +216 0.0 +217 0.0 +218 0.0 +219 0.0 +220 0.0 +221 0.0 +222 0.0 +223 0.0 +224 0.0 +225 0.0 +226 0.0 +227 0.0 +228 0.0 +229 0.0 +230 0.0 +231 0.0 +232 0.0 +233 0.0 +234 0.0 +235 0.0 +236 0.0 +237 0.0 +238 0.0 +239 0.0 +240 0.0 +241 0.0 +242 0.0 +243 0.0 +244 0.0 +245 0.0 +246 0.0 +247 0.0 +248 0.0 +249 0.0 +250 0.0 +251 0.0 +252 0.0 +253 0.0 +254 0.0 +255 0.0 +256 0.0 +257 0.0 +258 0.0101318359375 +259 0.010467529296875 +260 0.020263671875 +261 0.02093505859375 +262 0.0303955078125 +263 0.031402587890625 +264 0.04052734375 +265 0.0418701171875 +266 0.050628662109375 +267 0.05230712890625 +268 0.060760498046875 +269 0.062774658203125 +270 0.07086181640625 +271 0.073211669921875 +272 0.080963134765625 +273 0.083648681640625 +274 0.091064453125 +275 0.094085693359375 +276 0.101165771484375 +277 0.104522705078125 +278 0.111236572265625 +279 0.11492919921875 +280 0.12127685546875 +281 0.12530517578125 +282 0.131317138671875 +283 0.13568115234375 +284 0.141357421875 +285 0.14605712890625 +286 0.1513671875 +287 0.156402587890625 +288 0.161407470703125 +289 0.166748046875 +290 0.17138671875 +291 0.17706298828125 +292 0.18133544921875 +293 0.187347412109375 +294 0.1912841796875 +295 0.1976318359375 +296 0.201202392578125 +297 0.2078857421875 +298 0.21112060546875 +299 0.218109130859375 +300 0.22100830078125 +301 0.22833251953125 +302 0.230865478515625 +303 0.238525390625 +304 0.240692138671875 +305 0.2486572265625 +306 0.25048828125 +307 0.2587890625 +308 0.26025390625 +309 0.268890380859375 +310 0.27001953125 +311 0.278961181640625 +312 0.27972412109375 +313 0.28900146484375 +314 0.2894287109375 +315 0.29901123046875 +316 0.299072265625 +317 0.308990478515625 +318 0.3087158203125 +319 0.318939208984375 +320 0.31829833984375 +321 0.328826904296875 +322 0.327850341796875 +323 0.338714599609375 +324 0.337371826171875 +325 0.348541259765625 +326 0.34686279296875 +327 0.35833740234375 +328 0.356292724609375 +329 0.36810302734375 +330 0.365692138671875 +331 0.3778076171875 +332 0.37506103515625 +333 0.387481689453125 +334 0.3843994140625 +335 0.397125244140625 +336 0.3936767578125 +337 0.406707763671875 +338 0.402923583984375 +339 0.416259765625 +340 0.412109375 +341 0.425750732421875 +342 0.4212646484375 +343 0.435211181640625 +344 0.43035888671875 +345 0.444610595703125 +346 0.43939208984375 +347 0.453948974609375 +348 0.44842529296875 +349 0.4632568359375 +350 0.4573974609375 +351 0.4725341796875 +352 0.466278076171875 +353 0.481719970703125 +354 0.47515869140625 +355 0.490875244140625 +356 0.48394775390625 +357 0.499969482421875 +358 0.492706298828125 +359 0.509002685546875 +360 0.50140380859375 +361 0.51800537109375 +362 0.510040283203125 +363 0.52691650390625 +364 0.51861572265625 +365 0.535797119140625 +366 0.52716064453125 +367 0.54461669921875 +368 0.535614013671875 +369 0.5533447265625 +370 0.544036865234375 +371 0.562042236328125 +372 0.552398681640625 +373 0.5706787109375 +374 0.560699462890625 +375 0.579254150390625 +376 0.56890869140625 +377 0.587738037109375 +378 0.57708740234375 +379 0.59619140625 +380 0.585174560546875 +381 0.60455322265625 +382 0.59326171875 +383 0.612884521484375 +384 0.601226806640625 +385 0.621124267578125 +386 0.609100341796875 +387 0.6292724609375 +388 0.616973876953125 +389 0.63739013671875 +390 0.624725341796875 +391 0.645416259765625 +392 0.6324462890625 +393 0.65338134765625 +394 0.640106201171875 +395 0.661285400390625 +396 0.647674560546875 +397 0.669097900390625 +398 0.6551513671875 +399 0.676849365234375 +400 0.662567138671875 +401 0.68450927734375 +402 0.669921875 +403 0.692108154296875 +404 0.677215576171875 +405 0.699615478515625 +406 0.684417724609375 +407 0.707061767578125 +408 0.691558837890625 +409 0.714447021484375 +410 0.698577880859375 +411 0.721710205078125 +412 0.705596923828125 +413 0.72894287109375 +414 0.71246337890625 +415 0.736053466796875 +416 0.71929931640625 +417 0.74310302734375 +418 0.726043701171875 +419 0.75006103515625 +420 0.732696533203125 +421 0.7569580078125 +422 0.739288330078125 +423 0.763763427734375 +424 0.74578857421875 +425 0.770477294921875 +426 0.752197265625 +427 0.777099609375 +428 0.758544921875 +429 0.783660888671875 +430 0.76483154296875 +431 0.790130615234375 +432 0.770965576171875 +433 0.796478271484375 +434 0.77703857421875 +435 0.802764892578125 +436 0.7830810546875 +437 0.808990478515625 +438 0.788970947265625 +439 0.815093994140625 +440 0.7947998046875 +441 0.82110595703125 +442 0.800537109375 +443 0.8270263671875 +444 0.80621337890625 +445 0.8328857421875 +446 0.811767578125 +447 0.838623046875 +448 0.8172607421875 +449 0.84429931640625 +450 0.8226318359375 +451 0.849853515625 +452 0.827911376953125 +453 0.855316162109375 +454 0.8331298828125 +455 0.860687255859375 +456 0.8382568359375 +457 0.865997314453125 +458 0.843292236328125 +459 0.871185302734375 +460 0.848175048828125 +461 0.876251220703125 +462 0.85302734375 +463 0.881256103515625 +464 0.8577880859375 +465 0.88616943359375 +466 0.8624267578125 +467 0.890960693359375 +468 0.866973876953125 +469 0.895660400390625 +470 0.871429443359375 +471 0.9002685546875 +472 0.87579345703125 +473 0.90478515625 +474 0.88006591796875 +475 0.9091796875 +476 0.884246826171875 +477 0.91351318359375 +478 0.888336181640625 +479 0.917724609375 +480 0.89227294921875 +481 0.92181396484375 +482 0.89617919921875 +483 0.92584228515625 +484 0.899932861328125 +485 0.929718017578125 +486 0.90362548828125 +487 0.93353271484375 +488 0.907196044921875 +489 0.937225341796875 +490 0.91070556640625 +491 0.940826416015625 +492 0.914093017578125 +493 0.9443359375 +494 0.9173583984375 +495 0.947723388671875 +496 0.920562744140625 +497 0.951019287109375 +498 0.92364501953125 +499 0.954193115234375 +500 0.926605224609375 +501 0.957275390625 +502 0.929473876953125 +503 0.960235595703125 +504 0.9322509765625 +505 0.963104248046875 +506 0.9349365234375 +507 0.96588134765625 +508 0.9375 +509 0.968536376953125 +510 0.94000244140625 +511 0.971099853515625 +512 0.911224365234375 +513 0.973541259765625 +514 0.91339111328125 +515 0.975860595703125 +516 0.91546630859375 +517 0.97808837890625 +518 0.91748046875 +519 0.980224609375 +520 0.91937255859375 +521 0.98223876953125 +522 0.921173095703125 +523 0.984161376953125 +524 0.9228515625 +525 0.9859619140625 +526 0.924407958984375 +527 0.987640380859375 +528 0.9259033203125 +529 0.989227294921875 +530 0.927276611328125 +531 0.990692138671875 +532 0.928558349609375 +533 0.9920654296875 +534 0.929718017578125 +535 0.993316650390625 +536 0.930816650390625 +537 0.994476318359375 +538 0.931793212890625 +539 0.995513916015625 +540 0.93267822265625 +541 0.9964599609375 +542 0.933441162109375 +543 0.997283935546875 +544 0.934112548828125 +545 0.99798583984375 +546 0.934661865234375 +547 0.99859619140625 +548 0.93511962890625 +549 0.999114990234375 +550 0.93548583984375 +551 0.999481201171875 +552 0.93572998046875 +553 0.999755859375 +554 0.9359130859375 +555 0.99993896484375 +556 0.93597412109375 +557 0.999969482421875 +558 0.9359130859375 +559 0.99993896484375 +560 0.93572998046875 +561 0.999755859375 +562 0.93548583984375 +563 0.999481201171875 +564 0.93511962890625 +565 0.999114990234375 +566 0.934661865234375 +567 0.99859619140625 +568 0.934112548828125 +569 0.99798583984375 +570 0.933441162109375 +571 0.997283935546875 +572 0.93267822265625 +573 0.9964599609375 +574 0.931793212890625 +575 0.995513916015625 +576 0.930816650390625 +577 0.994476318359375 +578 0.929718017578125 +579 0.993316650390625 +580 0.928558349609375 +581 0.9920654296875 +582 0.927276611328125 +583 0.990692138671875 +584 0.9259033203125 +585 0.989227294921875 +586 0.924407958984375 +587 0.987640380859375 +588 0.9228515625 +589 0.9859619140625 +590 0.921173095703125 +591 0.984161376953125 +592 0.91937255859375 +593 0.98223876953125 +594 0.91748046875 +595 0.980224609375 +596 0.91546630859375 +597 0.97808837890625 +598 0.91339111328125 +599 0.975860595703125 +600 0.911224365234375 +601 0.973541259765625 +602 0.908935546875 +603 0.971099853515625 +604 0.906524658203125 +605 0.968536376953125 +606 0.904052734375 +607 0.96588134765625 +608 0.901458740234375 +609 0.963104248046875 +610 0.898773193359375 +611 0.960235595703125 +612 0.89599609375 +613 0.957275390625 +614 0.893096923828125 +615 0.954193115234375 +616 0.89013671875 +617 0.951019287109375 +618 0.887054443359375 +619 0.947723388671875 +620 0.883880615234375 +621 0.9443359375 +622 0.880615234375 +623 0.940826416015625 +624 0.877227783203125 +625 0.937225341796875 +626 0.873779296875 +627 0.93353271484375 +628 0.870208740234375 +629 0.929718017578125 +630 0.8665771484375 +631 0.92584228515625 +632 0.86279296875 +633 0.92181396484375 +634 0.858978271484375 +635 0.917724609375 +636 0.85504150390625 +637 0.91351318359375 +638 0.850982666015625 +639 0.9091796875 +640 0.84686279296875 +641 0.90478515625 +642 0.8426513671875 +643 0.9002685546875 +644 0.83831787109375 +645 0.895660400390625 +646 0.83392333984375 +647 0.890960693359375 +648 0.829437255859375 +649 0.88616943359375 +650 0.8248291015625 +651 0.881256103515625 +652 0.820159912109375 +653 0.876251220703125 +654 0.8154296875 +655 0.871185302734375 +656 0.810546875 +657 0.865997314453125 +658 0.80560302734375 +659 0.860687255859375 +660 0.800567626953125 +661 0.855316162109375 +662 0.795440673828125 +663 0.849853515625 +664 0.790252685546875 +665 0.84429931640625 +666 0.784942626953125 +667 0.838623046875 +668 0.779571533203125 +669 0.8328857421875 +670 0.774078369140625 +671 0.8270263671875 +672 0.7685546875 +673 0.82110595703125 +674 0.762908935546875 +675 0.815093994140625 +676 0.7572021484375 +677 0.808990478515625 +678 0.751373291015625 +679 0.802764892578125 +680 0.7454833984375 +681 0.796478271484375 +682 0.73956298828125 +683 0.790130615234375 +684 0.733489990234375 +685 0.783660888671875 +686 0.72735595703125 +687 0.777099609375 +688 0.721160888671875 +689 0.770477294921875 +690 0.714874267578125 +691 0.763763427734375 +692 0.70849609375 +693 0.7569580078125 +694 0.702056884765625 +695 0.75006103515625 +696 0.695526123046875 +697 0.74310302734375 +698 0.688934326171875 +699 0.736053466796875 +700 0.682281494140625 +701 0.72894287109375 +702 0.675506591796875 +703 0.721710205078125 +704 0.668701171875 +705 0.714447021484375 +706 0.66180419921875 +707 0.707061767578125 +708 0.654815673828125 +709 0.699615478515625 +710 0.647796630859375 +711 0.692108154296875 +712 0.64068603515625 +713 0.68450927734375 +714 0.633514404296875 +715 0.676849365234375 +716 0.626251220703125 +717 0.669097900390625 +718 0.61895751953125 +719 0.661285400390625 +720 0.611541748046875 +721 0.65338134765625 +722 0.604095458984375 +723 0.645416259765625 +724 0.596588134765625 +725 0.63739013671875 +726 0.5889892578125 +727 0.6292724609375 +728 0.58135986328125 +729 0.621124267578125 +730 0.573638916015625 +731 0.612884521484375 +732 0.56585693359375 +733 0.60455322265625 +734 0.558013916015625 +735 0.59619140625 +736 0.55010986328125 +737 0.587738037109375 +738 0.54217529296875 +739 0.579254150390625 +740 0.534149169921875 +741 0.5706787109375 +742 0.52606201171875 +743 0.562042236328125 +744 0.517913818359375 +745 0.5533447265625 +746 0.509735107421875 +747 0.54461669921875 +748 0.501495361328125 +749 0.535797119140625 +750 0.493194580078125 +751 0.52691650390625 +752 0.484832763671875 +753 0.51800537109375 +754 0.476409912109375 +755 0.509002685546875 +756 0.46795654296875 +757 0.499969482421875 +758 0.459442138671875 +759 0.490875244140625 +760 0.45086669921875 +761 0.481719970703125 +762 0.442291259765625 +763 0.4725341796875 +764 0.43359375 +765 0.4632568359375 +766 0.424896240234375 +767 0.453948974609375 +768 0.40191650390625 +769 0.444610595703125 +770 0.393402099609375 +771 0.435211181640625 +772 0.384857177734375 +773 0.425750732421875 +774 0.37628173828125 +775 0.416259765625 +776 0.367645263671875 +777 0.406707763671875 +778 0.358978271484375 +779 0.397125244140625 +780 0.350250244140625 +781 0.387481689453125 +782 0.341522216796875 +783 0.3778076171875 +784 0.332733154296875 +785 0.36810302734375 +786 0.32391357421875 +787 0.35833740234375 +788 0.3150634765625 +789 0.348541259765625 +790 0.306182861328125 +791 0.338714599609375 +792 0.2972412109375 +793 0.328826904296875 +794 0.288299560546875 +795 0.318939208984375 +796 0.279296875 +797 0.308990478515625 +798 0.270294189453125 +799 0.29901123046875 +800 0.26123046875 +801 0.28900146484375 +802 0.252166748046875 +803 0.278961181640625 +804 0.243072509765625 +805 0.268890380859375 +806 0.233917236328125 +807 0.2587890625 +808 0.224761962890625 +809 0.2486572265625 +810 0.215606689453125 +811 0.238525390625 +812 0.206390380859375 +813 0.22833251953125 +814 0.1971435546875 +815 0.218109130859375 +816 0.187896728515625 +817 0.2078857421875 +818 0.17864990234375 +819 0.1976318359375 +820 0.169342041015625 +821 0.187347412109375 +822 0.1600341796875 +823 0.17706298828125 +824 0.150726318359375 +825 0.166748046875 +826 0.141357421875 +827 0.156402587890625 +828 0.13201904296875 +829 0.14605712890625 +830 0.122650146484375 +831 0.13568115234375 +832 0.113250732421875 +833 0.12530517578125 +834 0.1038818359375 +835 0.11492919921875 +836 0.094482421875 +837 0.104522705078125 +838 0.08502197265625 +839 0.094085693359375 +840 0.075592041015625 +841 0.083648681640625 +842 0.066162109375 +843 0.073211669921875 +844 0.056732177734375 +845 0.062774658203125 +846 0.047271728515625 +847 0.05230712890625 +848 0.037841796875 +849 0.0418701171875 +850 0.02838134765625 +851 0.031402587890625 +852 0.0189208984375 +853 0.02093505859375 +854 0.00946044921875 +855 0.010467529296875 +856 0.0 +857 0.0 +858 -0.00946044921875 +859 -0.010467529296875 +860 -0.0189208984375 +861 -0.02093505859375 +862 -0.02838134765625 +863 -0.031402587890625 +864 -0.037841796875 +865 -0.0418701171875 +866 -0.047271728515625 +867 -0.05230712890625 +868 -0.056732177734375 +869 -0.062774658203125 +870 -0.066162109375 +871 -0.073211669921875 +872 -0.075592041015625 +873 -0.083648681640625 +874 -0.08502197265625 +875 -0.094085693359375 +876 -0.094482421875 +877 -0.104522705078125 +878 -0.1038818359375 +879 -0.11492919921875 +880 -0.113250732421875 +881 -0.12530517578125 +882 -0.122650146484375 +883 -0.13568115234375 +884 -0.13201904296875 +885 -0.14605712890625 +886 -0.141357421875 +887 -0.156402587890625 +888 -0.150726318359375 +889 -0.166748046875 +890 -0.1600341796875 +891 -0.17706298828125 +892 -0.169342041015625 +893 -0.187347412109375 +894 -0.17864990234375 +895 -0.1976318359375 +896 -0.187896728515625 +897 -0.2078857421875 +898 -0.1971435546875 +899 -0.218109130859375 +900 -0.206390380859375 +901 -0.22833251953125 +902 -0.215606689453125 +903 -0.238525390625 +904 -0.224761962890625 +905 -0.2486572265625 +906 -0.233917236328125 +907 -0.2587890625 +908 -0.243072509765625 +909 -0.268890380859375 +910 -0.252166748046875 +911 -0.278961181640625 +912 -0.26123046875 +913 -0.28900146484375 +914 -0.270294189453125 +915 -0.29901123046875 +916 -0.279296875 +917 -0.308990478515625 +918 -0.288299560546875 +919 -0.318939208984375 +920 -0.2972412109375 +921 -0.328826904296875 +922 -0.306182861328125 +923 -0.338714599609375 +924 -0.3150634765625 +925 -0.348541259765625 +926 -0.32391357421875 +927 -0.35833740234375 +928 -0.332733154296875 +929 -0.36810302734375 +930 -0.341522216796875 +931 -0.3778076171875 +932 -0.350250244140625 +933 -0.387481689453125 +934 -0.358978271484375 +935 -0.397125244140625 +936 -0.367645263671875 +937 -0.406707763671875 +938 -0.37628173828125 +939 -0.416259765625 +940 -0.384857177734375 +941 -0.425750732421875 +942 -0.393402099609375 +943 -0.435211181640625 +944 -0.40191650390625 +945 -0.444610595703125 +946 -0.41033935546875 +947 -0.453948974609375 +948 -0.41876220703125 +949 -0.4632568359375 +950 -0.427154541015625 +951 -0.4725341796875 +952 -0.435455322265625 +953 -0.481719970703125 +954 -0.4437255859375 +955 -0.490875244140625 +956 -0.45196533203125 +957 -0.499969482421875 +958 -0.460113525390625 +959 -0.509002685546875 +960 -0.46826171875 +961 -0.51800537109375 +962 -0.476318359375 +963 -0.52691650390625 +964 -0.484344482421875 +965 -0.535797119140625 +966 -0.4923095703125 +967 -0.54461669921875 +968 -0.500213623046875 +969 -0.5533447265625 +970 -0.508056640625 +971 -0.562042236328125 +972 -0.515869140625 +973 -0.5706787109375 +974 -0.52362060546875 +975 -0.579254150390625 +976 -0.531280517578125 +977 -0.587738037109375 +978 -0.5389404296875 +979 -0.59619140625 +980 -0.5465087890625 +981 -0.60455322265625 +982 -0.55401611328125 +983 -0.612884521484375 +984 -0.56146240234375 +985 -0.621124267578125 +986 -0.56884765625 +987 -0.6292724609375 +988 -0.576171875 +989 -0.63739013671875 +990 -0.58343505859375 +991 -0.645416259765625 +992 -0.59063720703125 +993 -0.65338134765625 +994 -0.5977783203125 +995 -0.661285400390625 +996 -0.604827880859375 +997 -0.669097900390625 +998 -0.611846923828125 +999 -0.676849365234375 +1000 -0.6187744140625 +1001 -0.68450927734375 +1002 -0.625640869140625 +1003 -0.692108154296875 +1004 -0.632415771484375 +1005 -0.699615478515625 +1006 -0.63916015625 +1007 -0.707061767578125 +1008 -0.645843505859375 +1009 -0.714447021484375 +1010 -0.65240478515625 +1011 -0.721710205078125 +1012 -0.658935546875 +1013 -0.72894287109375 +1014 -0.665374755859375 +1015 -0.736053466796875 +1016 -0.6717529296875 +1017 -0.74310302734375 +1018 -0.67803955078125 +1019 -0.75006103515625 +1020 -0.68426513671875 +1021 -0.7569580078125 +1022 -0.6904296875 +1023 -0.763763427734375 +1024 -0.671844482421875 +1025 -0.770477294921875 +1026 -0.6776123046875 +1027 -0.777099609375 +1028 -0.683349609375 +1029 -0.783660888671875 +1030 -0.688995361328125 +1031 -0.790130615234375 +1032 -0.69451904296875 +1033 -0.796478271484375 +1034 -0.70001220703125 +1035 -0.802764892578125 +1036 -0.705413818359375 +1037 -0.808990478515625 +1038 -0.71075439453125 +1039 -0.815093994140625 +1040 -0.71600341796875 +1041 -0.82110595703125 +1042 -0.721160888671875 +1043 -0.8270263671875 +1044 -0.72625732421875 +1045 -0.8328857421875 +1046 -0.73126220703125 +1047 -0.838623046875 +1048 -0.7362060546875 +1049 -0.84429931640625 +1050 -0.741058349609375 +1051 -0.849853515625 +1052 -0.745819091796875 +1053 -0.855316162109375 +1054 -0.750518798828125 +1055 -0.860687255859375 +1056 -0.755126953125 +1057 -0.865997314453125 +1058 -0.759674072265625 +1059 -0.871185302734375 +1060 -0.764068603515625 +1061 -0.876251220703125 +1062 -0.7684326171875 +1063 -0.881256103515625 +1064 -0.772735595703125 +1065 -0.88616943359375 +1066 -0.77691650390625 +1067 -0.890960693359375 +1068 -0.781005859375 +1069 -0.895660400390625 +1070 -0.7850341796875 +1071 -0.9002685546875 +1072 -0.788970947265625 +1073 -0.90478515625 +1074 -0.79278564453125 +1075 -0.9091796875 +1076 -0.79656982421875 +1077 -0.91351318359375 +1078 -0.80023193359375 +1079 -0.917724609375 +1080 -0.803802490234375 +1081 -0.92181396484375 +1082 -0.80731201171875 +1083 -0.92584228515625 +1084 -0.810699462890625 +1085 -0.929718017578125 +1086 -0.81402587890625 +1087 -0.93353271484375 +1088 -0.8172607421875 +1089 -0.937225341796875 +1090 -0.820404052734375 +1091 -0.940826416015625 +1092 -0.823455810546875 +1093 -0.9443359375 +1094 -0.826416015625 +1095 -0.947723388671875 +1096 -0.82928466796875 +1097 -0.951019287109375 +1098 -0.83203125 +1099 -0.954193115234375 +1100 -0.834747314453125 +1101 -0.957275390625 +1102 -0.837310791015625 +1103 -0.960235595703125 +1104 -0.839813232421875 +1105 -0.963104248046875 +1106 -0.84222412109375 +1107 -0.96588134765625 +1108 -0.84454345703125 +1109 -0.968536376953125 +1110 -0.8468017578125 +1111 -0.971099853515625 +1112 -0.848907470703125 +1113 -0.973541259765625 +1114 -0.8509521484375 +1115 -0.975860595703125 +1116 -0.852874755859375 +1117 -0.97808837890625 +1118 -0.854736328125 +1119 -0.980224609375 +1120 -0.85650634765625 +1121 -0.98223876953125 +1122 -0.858184814453125 +1123 -0.984161376953125 +1124 -0.8597412109375 +1125 -0.9859619140625 +1126 -0.8612060546875 +1127 -0.987640380859375 +1128 -0.86260986328125 +1129 -0.989227294921875 +1130 -0.863861083984375 +1131 -0.990692138671875 +1132 -0.865081787109375 +1133 -0.9920654296875 +1134 -0.86614990234375 +1135 -0.993316650390625 +1136 -0.8671875 +1137 -0.994476318359375 +1138 -0.868072509765625 +1139 -0.995513916015625 +1140 -0.868896484375 +1141 -0.9964599609375 +1142 -0.86962890625 +1143 -0.997283935546875 +1144 -0.8702392578125 +1145 -0.99798583984375 +1146 -0.870758056640625 +1147 -0.99859619140625 +1148 -0.871185302734375 +1149 -0.999114990234375 +1150 -0.87152099609375 +1151 -0.999481201171875 +1152 -0.87176513671875 +1153 -0.999755859375 +1154 -0.871917724609375 +1155 -0.99993896484375 +1156 -0.871978759765625 +1157 -1.0 +1158 -0.871917724609375 +1159 -0.99993896484375 +1160 -0.87176513671875 +1161 -0.999755859375 +1162 -0.87152099609375 +1163 -0.999481201171875 +1164 -0.871185302734375 +1165 -0.999114990234375 +1166 -0.870758056640625 +1167 -0.99859619140625 +1168 -0.8702392578125 +1169 -0.99798583984375 +1170 -0.86962890625 +1171 -0.997283935546875 +1172 -0.868896484375 +1173 -0.9964599609375 +1174 -0.868072509765625 +1175 -0.995513916015625 +1176 -0.8671875 +1177 -0.994476318359375 +1178 -0.86614990234375 +1179 -0.993316650390625 +1180 -0.865081787109375 +1181 -0.9920654296875 +1182 -0.863861083984375 +1183 -0.990692138671875 +1184 -0.86260986328125 +1185 -0.989227294921875 +1186 -0.8612060546875 +1187 -0.987640380859375 +1188 -0.8597412109375 +1189 -0.9859619140625 +1190 -0.858184814453125 +1191 -0.984161376953125 +1192 -0.85650634765625 +1193 -0.98223876953125 +1194 -0.854736328125 +1195 -0.980224609375 +1196 -0.852874755859375 +1197 -0.97808837890625 +1198 -0.8509521484375 +1199 -0.975860595703125 +1200 -0.848907470703125 +1201 -0.973541259765625 +1202 -0.8468017578125 +1203 -0.971099853515625 +1204 -0.84454345703125 +1205 -0.968536376953125 +1206 -0.84222412109375 +1207 -0.96588134765625 +1208 -0.839813232421875 +1209 -0.963104248046875 +1210 -0.837310791015625 +1211 -0.960235595703125 +1212 -0.834747314453125 +1213 -0.957275390625 +1214 -0.83203125 +1215 -0.954193115234375 +1216 -0.82928466796875 +1217 -0.951019287109375 +1218 -0.826416015625 +1219 -0.947723388671875 +1220 -0.823455810546875 +1221 -0.9443359375 +1222 -0.820404052734375 +1223 -0.940826416015625 +1224 -0.8172607421875 +1225 -0.937225341796875 +1226 -0.81402587890625 +1227 -0.93353271484375 +1228 -0.810699462890625 +1229 -0.929718017578125 +1230 -0.80731201171875 +1231 -0.92584228515625 +1232 -0.803802490234375 +1233 -0.92181396484375 +1234 -0.80023193359375 +1235 -0.917724609375 +1236 -0.79656982421875 +1237 -0.91351318359375 +1238 -0.79278564453125 +1239 -0.9091796875 +1240 -0.788970947265625 +1241 -0.90478515625 +1242 -0.7850341796875 +1243 -0.9002685546875 +1244 -0.781005859375 +1245 -0.895660400390625 +1246 -0.77691650390625 +1247 -0.890960693359375 +1248 -0.772735595703125 +1249 -0.88616943359375 +1250 -0.7684326171875 +1251 -0.881256103515625 +1252 -0.764068603515625 +1253 -0.876251220703125 +1254 -0.759674072265625 +1255 -0.871185302734375 +1256 -0.755126953125 +1257 -0.865997314453125 +1258 -0.750518798828125 +1259 -0.860687255859375 +1260 -0.745819091796875 +1261 -0.855316162109375 +1262 -0.741058349609375 +1263 -0.849853515625 +1264 -0.7362060546875 +1265 -0.84429931640625 +1266 -0.73126220703125 +1267 -0.838623046875 +1268 -0.72625732421875 +1269 -0.8328857421875 +1270 -0.721160888671875 +1271 -0.8270263671875 +1272 -0.71600341796875 +1273 -0.82110595703125 +1274 -0.71075439453125 +1275 -0.815093994140625 +1276 -0.705413818359375 +1277 -0.808990478515625 +1278 -0.70001220703125 +1279 -0.802764892578125 +1280 -0.677001953125 +1281 -0.796478271484375 +1282 -0.671600341796875 +1283 -0.790130615234375 +1284 -0.666107177734375 +1285 -0.783660888671875 +1286 -0.6605224609375 +1287 -0.777099609375 +1288 -0.654876708984375 +1289 -0.770477294921875 +1290 -0.649169921875 +1291 -0.763763427734375 +1292 -0.643402099609375 +1293 -0.7569580078125 +1294 -0.637542724609375 +1295 -0.75006103515625 +1296 -0.631622314453125 +1297 -0.74310302734375 +1298 -0.625640869140625 +1299 -0.736053466796875 +1300 -0.619598388671875 +1301 -0.72894287109375 +1302 -0.613433837890625 +1303 -0.721710205078125 +1304 -0.607269287109375 +1305 -0.714447021484375 +1306 -0.600982666015625 +1307 -0.707061767578125 +1308 -0.59466552734375 +1309 -0.699615478515625 +1310 -0.588287353515625 +1311 -0.692108154296875 +1312 -0.581817626953125 +1313 -0.68450927734375 +1314 -0.5753173828125 +1315 -0.676849365234375 +1316 -0.5687255859375 +1317 -0.669097900390625 +1318 -0.56207275390625 +1319 -0.661285400390625 +1320 -0.55535888671875 +1321 -0.65338134765625 +1322 -0.548583984375 +1323 -0.645416259765625 +1324 -0.541778564453125 +1325 -0.63739013671875 +1326 -0.534881591796875 +1327 -0.6292724609375 +1328 -0.5279541015625 +1329 -0.621124267578125 +1330 -0.52093505859375 +1331 -0.612884521484375 +1332 -0.51385498046875 +1333 -0.60455322265625 +1334 -0.506744384765625 +1335 -0.59619140625 +1336 -0.49957275390625 +1337 -0.587738037109375 +1338 -0.492340087890625 +1339 -0.579254150390625 +1340 -0.485076904296875 +1341 -0.5706787109375 +1342 -0.47772216796875 +1343 -0.562042236328125 +1344 -0.4703369140625 +1345 -0.5533447265625 +1346 -0.462921142578125 +1347 -0.54461669921875 +1348 -0.455413818359375 +1349 -0.535797119140625 +1350 -0.4478759765625 +1351 -0.52691650390625 +1352 -0.440277099609375 +1353 -0.51800537109375 +1354 -0.432647705078125 +1355 -0.509002685546875 +1356 -0.424957275390625 +1357 -0.499969482421875 +1358 -0.417236328125 +1359 -0.490875244140625 +1360 -0.409454345703125 +1361 -0.481719970703125 +1362 -0.401641845703125 +1363 -0.4725341796875 +1364 -0.393768310546875 +1365 -0.4632568359375 +1366 -0.385833740234375 +1367 -0.453948974609375 +1368 -0.377899169921875 +1369 -0.444610595703125 +1370 -0.369903564453125 +1371 -0.435211181640625 +1372 -0.36187744140625 +1373 -0.425750732421875 +1374 -0.35382080078125 +1375 -0.416259765625 +1376 -0.345672607421875 +1377 -0.406707763671875 +1378 -0.337554931640625 +1379 -0.397125244140625 +1380 -0.329345703125 +1381 -0.387481689453125 +1382 -0.321136474609375 +1383 -0.3778076171875 +1384 -0.3128662109375 +1385 -0.36810302734375 +1386 -0.3045654296875 +1387 -0.35833740234375 +1388 -0.296234130859375 +1389 -0.348541259765625 +1390 -0.28790283203125 +1391 -0.338714599609375 +1392 -0.27947998046875 +1393 -0.328826904296875 +1394 -0.271087646484375 +1395 -0.318939208984375 +1396 -0.26263427734375 +1397 -0.308990478515625 +1398 -0.254150390625 +1399 -0.29901123046875 +1400 -0.245635986328125 +1401 -0.28900146484375 +1402 -0.237091064453125 +1403 -0.278961181640625 +1404 -0.228546142578125 +1405 -0.268890380859375 +1406 -0.219970703125 +1407 -0.2587890625 +1408 -0.211334228515625 +1409 -0.2486572265625 +1410 -0.202728271484375 +1411 -0.238525390625 +1412 -0.194061279296875 +1413 -0.22833251953125 +1414 -0.18536376953125 +1415 -0.218109130859375 +1416 -0.17669677734375 +1417 -0.2078857421875 +1418 -0.16796875 +1419 -0.1976318359375 +1420 -0.15924072265625 +1421 -0.187347412109375 +1422 -0.150482177734375 +1423 -0.17706298828125 +1424 -0.1417236328125 +1425 -0.166748046875 +1426 -0.1329345703125 +1427 -0.156402587890625 +1428 -0.1241455078125 +1429 -0.14605712890625 +1430 -0.115325927734375 +1431 -0.13568115234375 +1432 -0.10650634765625 +1433 -0.12530517578125 +1434 -0.097686767578125 +1435 -0.11492919921875 +1436 -0.088836669921875 +1437 -0.104522705078125 +1438 -0.0799560546875 +1439 -0.094085693359375 +1440 -0.071075439453125 +1441 -0.083648681640625 +1442 -0.062225341796875 +1443 -0.073211669921875 +1444 -0.0533447265625 +1445 -0.062774658203125 +1446 -0.04443359375 +1447 -0.05230712890625 +1448 -0.03558349609375 +1449 -0.0418701171875 +1450 -0.02667236328125 +1451 -0.031402587890625 +1452 -0.017791748046875 +1453 -0.02093505859375 +1454 -0.008880615234375 +1455 -0.010467529296875 +1456 0.0 +1457 0.0 +1458 0.0087890625 +1459 0.010467529296875 +1460 0.017578125 +1461 0.02093505859375 +1462 0.0263671875 +1463 0.031402587890625 +1464 0.03515625 +1465 0.0418701171875 +1466 0.043914794921875 +1467 0.05230712890625 +1468 0.052703857421875 +1469 0.062774658203125 +1470 0.061492919921875 +1471 0.073211669921875 +1472 0.07025146484375 +1473 0.083648681640625 +1474 0.079010009765625 +1475 0.094085693359375 +1476 0.0877685546875 +1477 0.104522705078125 +1478 0.096527099609375 +1479 0.11492919921875 +1480 0.105255126953125 +1481 0.12530517578125 +1482 0.11395263671875 +1483 0.13568115234375 +1484 0.1226806640625 +1485 0.14605712890625 +1486 0.13134765625 +1487 0.156402587890625 +1488 0.140045166015625 +1489 0.166748046875 +1490 0.148712158203125 +1491 0.17706298828125 +1492 0.1573486328125 +1493 0.187347412109375 +1494 0.165985107421875 +1495 0.1976318359375 +1496 0.17462158203125 +1497 0.2078857421875 +1498 0.183197021484375 +1499 0.218109130859375 +1500 0.1917724609375 +1501 0.22833251953125 +1502 0.200347900390625 +1503 0.238525390625 +1504 0.2088623046875 +1505 0.2486572265625 +1506 0.217376708984375 +1507 0.2587890625 +1508 0.225860595703125 +1509 0.268890380859375 +1510 0.23431396484375 +1511 0.278961181640625 +1512 0.24273681640625 +1513 0.28900146484375 +1514 0.25115966796875 +1515 0.29901123046875 +1516 0.259521484375 +1517 0.308990478515625 +1518 0.26788330078125 +1519 0.318939208984375 +1520 0.27618408203125 +1521 0.328826904296875 +1522 0.284515380859375 +1523 0.338714599609375 +1524 0.292755126953125 +1525 0.348541259765625 +1526 0.300994873046875 +1527 0.35833740234375 +1528 0.309173583984375 +1529 0.36810302734375 +1530 0.317352294921875 +1531 0.3778076171875 +1532 0.325469970703125 +1533 0.387481689453125 +1534 0.33355712890625 +1535 0.397125244140625 +1536 0.32861328125 +1537 0.406707763671875 +1538 0.336334228515625 +1539 0.416259765625 +1540 0.343994140625 +1541 0.425750732421875 +1542 0.351654052734375 +1543 0.435211181640625 +1544 0.359222412109375 +1545 0.444610595703125 +1546 0.366790771484375 +1547 0.453948974609375 +1548 0.374298095703125 +1549 0.4632568359375 +1550 0.381805419921875 +1551 0.4725341796875 +1552 0.38922119140625 +1553 0.481719970703125 +1554 0.3966064453125 +1555 0.490875244140625 +1556 0.403961181640625 +1557 0.499969482421875 +1558 0.4112548828125 +1559 0.509002685546875 +1560 0.418548583984375 +1561 0.51800537109375 +1562 0.425750732421875 +1563 0.52691650390625 +1564 0.43292236328125 +1565 0.535797119140625 +1566 0.440032958984375 +1567 0.54461669921875 +1568 0.44708251953125 +1569 0.5533447265625 +1570 0.454132080078125 +1571 0.562042236328125 +1572 0.461090087890625 +1573 0.5706787109375 +1574 0.468017578125 +1575 0.579254150390625 +1576 0.474884033203125 +1577 0.587738037109375 +1578 0.481719970703125 +1579 0.59619140625 +1580 0.48846435546875 +1581 0.60455322265625 +1582 0.495208740234375 +1583 0.612884521484375 +1584 0.501861572265625 +1585 0.621124267578125 +1586 0.508453369140625 +1587 0.6292724609375 +1588 0.5150146484375 +1589 0.63739013671875 +1590 0.521484375 +1591 0.645416259765625 +1592 0.527923583984375 +1593 0.65338134765625 +1594 0.5343017578125 +1595 0.661285400390625 +1596 0.540618896484375 +1597 0.669097900390625 +1598 0.546875 +1599 0.676849365234375 +1600 0.553070068359375 +1601 0.68450927734375 +1602 0.5592041015625 +1603 0.692108154296875 +1604 0.565277099609375 +1605 0.699615478515625 +1606 0.5712890625 +1607 0.707061767578125 +1608 0.5772705078125 +1609 0.714447021484375 +1610 0.5831298828125 +1611 0.721710205078125 +1612 0.5889892578125 +1613 0.72894287109375 +1614 0.5947265625 +1615 0.736053466796875 +1616 0.60040283203125 +1617 0.74310302734375 +1618 0.606048583984375 +1619 0.75006103515625 +1620 0.611602783203125 +1621 0.7569580078125 +1622 0.61712646484375 +1623 0.763763427734375 +1624 0.622528076171875 +1625 0.770477294921875 +1626 0.627899169921875 +1627 0.777099609375 +1628 0.6331787109375 +1629 0.783660888671875 +1630 0.638427734375 +1631 0.790130615234375 +1632 0.6435546875 +1633 0.796478271484375 +1634 0.64862060546875 +1635 0.802764892578125 +1636 0.653656005859375 +1637 0.808990478515625 +1638 0.658599853515625 +1639 0.815093994140625 +1640 0.6634521484375 +1641 0.82110595703125 +1642 0.668243408203125 +1643 0.8270263671875 +1644 0.6729736328125 +1645 0.8328857421875 +1646 0.6776123046875 +1647 0.838623046875 +1648 0.68218994140625 +1649 0.84429931640625 +1650 0.686676025390625 +1651 0.849853515625 +1652 0.69110107421875 +1653 0.855316162109375 +1654 0.6954345703125 +1655 0.860687255859375 +1656 0.69970703125 +1657 0.865997314453125 +1658 0.70391845703125 +1659 0.871185302734375 +1660 0.7080078125 +1661 0.876251220703125 +1662 0.7120361328125 +1663 0.881256103515625 +1664 0.71600341796875 +1665 0.88616943359375 +1666 0.719879150390625 +1667 0.890960693359375 +1668 0.72369384765625 +1669 0.895660400390625 +1670 0.7274169921875 +1671 0.9002685546875 +1672 0.731048583984375 +1673 0.90478515625 +1674 0.734619140625 +1675 0.9091796875 +1676 0.73809814453125 +1677 0.91351318359375 +1678 0.74151611328125 +1679 0.917724609375 +1680 0.74481201171875 +1681 0.92181396484375 +1682 0.748077392578125 +1683 0.92584228515625 +1684 0.751190185546875 +1685 0.929718017578125 +1686 0.7542724609375 +1687 0.93353271484375 +1688 0.75726318359375 +1689 0.937225341796875 +1690 0.76019287109375 +1691 0.940826416015625 +1692 0.763031005859375 +1693 0.9443359375 +1694 0.7657470703125 +1695 0.947723388671875 +1696 0.768402099609375 +1697 0.951019287109375 +1698 0.770965576171875 +1699 0.954193115234375 +1700 0.773468017578125 +1701 0.957275390625 +1702 0.775848388671875 +1703 0.960235595703125 +1704 0.778167724609375 +1705 0.963104248046875 +1706 0.780426025390625 +1707 0.96588134765625 +1708 0.782562255859375 +1709 0.968536376953125 +1710 0.784637451171875 +1711 0.971099853515625 +1712 0.78662109375 +1713 0.973541259765625 +1714 0.788482666015625 +1715 0.975860595703125 +1716 0.790283203125 +1717 0.97808837890625 +1718 0.792022705078125 +1719 0.980224609375 +1720 0.79364013671875 +1721 0.98223876953125 +1722 0.795196533203125 +1723 0.984161376953125 +1724 0.796661376953125 +1725 0.9859619140625 +1726 0.798004150390625 +1727 0.987640380859375 +1728 0.799285888671875 +1729 0.989227294921875 +1730 0.80047607421875 +1731 0.990692138671875 +1732 0.80157470703125 +1733 0.9920654296875 +1734 0.802581787109375 +1735 0.993316650390625 +1736 0.80352783203125 +1737 0.994476318359375 +1738 0.80438232421875 +1739 0.995513916015625 +1740 0.805145263671875 +1741 0.9964599609375 +1742 0.8057861328125 +1743 0.997283935546875 +1744 0.806365966796875 +1745 0.99798583984375 +1746 0.806854248046875 +1747 0.99859619140625 +1748 0.8072509765625 +1749 0.999114990234375 +1750 0.80755615234375 +1751 0.999481201171875 +1752 0.807769775390625 +1753 0.999755859375 +1754 0.80792236328125 +1755 0.99993896484375 +1756 0.8079833984375 +1757 0.999969482421875 +1758 0.80792236328125 +1759 0.99993896484375 +1760 0.807769775390625 +1761 0.999755859375 +1762 0.80755615234375 +1763 0.999481201171875 +1764 0.8072509765625 +1765 0.999114990234375 +1766 0.806854248046875 +1767 0.99859619140625 +1768 0.806365966796875 +1769 0.99798583984375 +1770 0.8057861328125 +1771 0.997283935546875 +1772 0.805145263671875 +1773 0.9964599609375 +1774 0.80438232421875 +1775 0.995513916015625 +1776 0.80352783203125 +1777 0.994476318359375 +1778 0.802581787109375 +1779 0.993316650390625 +1780 0.80157470703125 +1781 0.9920654296875 +1782 0.80047607421875 +1783 0.990692138671875 +1784 0.799285888671875 +1785 0.989227294921875 +1786 0.798004150390625 +1787 0.987640380859375 +1788 0.796661376953125 +1789 0.9859619140625 +1790 0.795196533203125 +1791 0.984161376953125 +1792 0.76220703125 +1793 0.98223876953125 +1794 0.7606201171875 +1795 0.980224609375 +1796 0.75897216796875 +1797 0.97808837890625 +1798 0.757232666015625 +1799 0.975860595703125 +1800 0.75543212890625 +1801 0.973541259765625 +1802 0.7535400390625 +1803 0.971099853515625 +1804 0.751556396484375 +1805 0.968536376953125 +1806 0.74951171875 +1807 0.96588134765625 +1808 0.747344970703125 +1809 0.963104248046875 +1810 0.7451171875 +1811 0.960235595703125 +1812 0.742828369140625 +1813 0.957275390625 +1814 0.740447998046875 +1815 0.954193115234375 +1816 0.73797607421875 +1817 0.951019287109375 +1818 0.73541259765625 +1819 0.947723388671875 +1820 0.7327880859375 +1821 0.9443359375 +1822 0.730072021484375 +1823 0.940826416015625 +1824 0.727264404296875 +1825 0.937225341796875 +1826 0.724395751953125 +1827 0.93353271484375 +1828 0.721435546875 +1829 0.929718017578125 +1830 0.71844482421875 +1831 0.92584228515625 +1832 0.715301513671875 +1833 0.92181396484375 +1834 0.712127685546875 +1835 0.917724609375 +1836 0.7088623046875 +1837 0.91351318359375 +1838 0.70550537109375 +1839 0.9091796875 +1840 0.70208740234375 +1841 0.90478515625 +1842 0.698577880859375 +1843 0.9002685546875 +1844 0.69500732421875 +1845 0.895660400390625 +1846 0.691375732421875 +1847 0.890960693359375 +1848 0.687652587890625 +1849 0.88616943359375 +1850 0.683837890625 +1851 0.881256103515625 +1852 0.679962158203125 +1853 0.876251220703125 +1854 0.676025390625 +1855 0.871185302734375 +1856 0.6719970703125 +1857 0.865997314453125 +1858 0.667877197265625 +1859 0.860687255859375 +1860 0.6636962890625 +1861 0.855316162109375 +1862 0.659454345703125 +1863 0.849853515625 +1864 0.6551513671875 +1865 0.84429931640625 +1866 0.6507568359375 +1867 0.838623046875 +1868 0.64630126953125 +1869 0.8328857421875 +1870 0.641754150390625 +1871 0.8270263671875 +1872 0.63714599609375 +1873 0.82110595703125 +1874 0.63250732421875 +1875 0.815093994140625 +1876 0.62774658203125 +1877 0.808990478515625 +1878 0.6229248046875 +1879 0.802764892578125 +1880 0.6180419921875 +1881 0.796478271484375 +1882 0.613128662109375 +1883 0.790130615234375 +1884 0.60809326171875 +1885 0.783660888671875 +1886 0.602996826171875 +1887 0.777099609375 +1888 0.597869873046875 +1889 0.770477294921875 +1890 0.5926513671875 +1891 0.763763427734375 +1892 0.587371826171875 +1893 0.7569580078125 +1894 0.58203125 +1895 0.75006103515625 +1896 0.576629638671875 +1897 0.74310302734375 +1898 0.5711669921875 +1899 0.736053466796875 +1900 0.565643310546875 +1901 0.72894287109375 +1902 0.560028076171875 +1903 0.721710205078125 +1904 0.55438232421875 +1905 0.714447021484375 +1906 0.548675537109375 +1907 0.707061767578125 +1908 0.542877197265625 +1909 0.699615478515625 +1910 0.53704833984375 +1911 0.692108154296875 +1912 0.531158447265625 +1913 0.68450927734375 +1914 0.52520751953125 +1915 0.676849365234375 +1916 0.519195556640625 +1917 0.669097900390625 +1918 0.513153076171875 +1919 0.661285400390625 +1920 0.50701904296875 +1921 0.65338134765625 +1922 0.500823974609375 +1923 0.645416259765625 +1924 0.494598388671875 +1925 0.63739013671875 +1926 0.48828125 +1927 0.6292724609375 +1928 0.481964111328125 +1929 0.621124267578125 +1930 0.4755859375 +1931 0.612884521484375 +1932 0.4691162109375 +1933 0.60455322265625 +1934 0.462615966796875 +1935 0.59619140625 +1936 0.4560546875 +1937 0.587738037109375 +1938 0.449493408203125 +1939 0.579254150390625 +1940 0.442840576171875 +1941 0.5706787109375 +1942 0.436126708984375 +1943 0.562042236328125 +1944 0.42938232421875 +1945 0.5533447265625 +1946 0.422607421875 +1947 0.54461669921875 +1948 0.415771484375 +1949 0.535797119140625 +1950 0.40887451171875 +1951 0.52691650390625 +1952 0.401947021484375 +1953 0.51800537109375 +1954 0.39495849609375 +1955 0.509002685546875 +1956 0.387969970703125 +1957 0.499969482421875 +1958 0.380889892578125 +1959 0.490875244140625 +1960 0.373809814453125 +1961 0.481719970703125 +1962 0.366668701171875 +1963 0.4725341796875 +1964 0.359466552734375 +1965 0.4632568359375 +1966 0.35223388671875 +1967 0.453948974609375 +1968 0.345001220703125 +1969 0.444610595703125 +1970 0.33770751953125 +1971 0.435211181640625 +1972 0.330352783203125 +1973 0.425750732421875 +1974 0.322998046875 +1975 0.416259765625 +1976 0.315582275390625 +1977 0.406707763671875 +1978 0.30816650390625 +1979 0.397125244140625 +1980 0.3006591796875 +1981 0.387481689453125 +1982 0.29315185546875 +1983 0.3778076171875 +1984 0.28564453125 +1985 0.36810302734375 +1986 0.278045654296875 +1987 0.35833740234375 +1988 0.27044677734375 +1989 0.348541259765625 +1990 0.2628173828125 +1991 0.338714599609375 +1992 0.255157470703125 +1993 0.328826904296875 +1994 0.247467041015625 +1995 0.318939208984375 +1996 0.23974609375 +1997 0.308990478515625 +1998 0.232025146484375 +1999 0.29901123046875 +2000 0.2242431640625 +2001 0.28900146484375 +2002 0.216461181640625 +2003 0.278961181640625 +2004 0.208648681640625 +2005 0.268890380859375 +2006 0.2008056640625 +2007 0.2587890625 +2008 0.19293212890625 +2009 0.2486572265625 +2010 0.185089111328125 +2011 0.238525390625 +2012 0.177154541015625 +2013 0.22833251953125 +2014 0.16925048828125 +2015 0.218109130859375 +2016 0.16131591796875 +2017 0.2078857421875 +2018 0.153350830078125 +2019 0.1976318359375 +2020 0.145355224609375 +2021 0.187347412109375 +2022 0.13739013671875 +2023 0.17706298828125 +2024 0.12939453125 +2025 0.166748046875 +2026 0.121337890625 +2027 0.156402587890625 +2028 0.113311767578125 +2029 0.14605712890625 +2030 0.10528564453125 +2031 0.13568115234375 +2032 0.09722900390625 +2033 0.12530517578125 +2034 0.08917236328125 +2035 0.11492919921875 +2036 0.081085205078125 +2037 0.104522705078125 +2038 0.072998046875 +2039 0.094085693359375 +2040 0.064910888671875 +2041 0.083648681640625 +2042 0.056793212890625 +2043 0.073211669921875 +2044 0.0487060546875 +2045 0.062774658203125 +2046 0.04058837890625 +2047 0.05230712890625 +2048 0.0311279296875 +2049 0.0418701171875 +2050 0.023345947265625 +2051 0.031402587890625 +2052 0.01556396484375 +2053 0.02093505859375 +2054 0.007781982421875 +2055 0.010467529296875 +2056 0.0 +2057 0.0 +2058 -0.007781982421875 +2059 -0.010467529296875 +2060 -0.01556396484375 +2061 -0.02093505859375 +2062 -0.023345947265625 +2063 -0.031402587890625 +2064 -0.0311279296875 +2065 -0.0418701171875 +2066 -0.038909912109375 +2067 -0.05230712890625 +2068 -0.04669189453125 +2069 -0.062774658203125 +2070 -0.054443359375 +2071 -0.073211669921875 +2072 -0.062225341796875 +2073 -0.083648681640625 +2074 -0.069976806640625 +2075 -0.094085693359375 +2076 -0.0777587890625 +2077 -0.104522705078125 +2078 -0.085479736328125 +2079 -0.11492919921875 +2080 -0.09320068359375 +2081 -0.12530517578125 +2082 -0.100921630859375 +2083 -0.13568115234375 +2084 -0.108642578125 +2085 -0.14605712890625 +2086 -0.116363525390625 +2087 -0.156402587890625 +2088 -0.124053955078125 +2089 -0.166748046875 +2090 -0.1317138671875 +2091 -0.17706298828125 +2092 -0.139373779296875 +2093 -0.187347412109375 +2094 -0.14703369140625 +2095 -0.1976318359375 +2096 -0.1546630859375 +2097 -0.2078857421875 +2098 -0.162261962890625 +2099 -0.218109130859375 +2100 -0.16986083984375 +2101 -0.22833251953125 +2102 -0.177459716796875 +2103 -0.238525390625 +2104 -0.18499755859375 +2105 -0.2486572265625 +2106 -0.192535400390625 +2107 -0.2587890625 +2108 -0.200042724609375 +2109 -0.268890380859375 +2110 -0.207550048828125 +2111 -0.278961181640625 +2112 -0.214996337890625 +2113 -0.28900146484375 +2114 -0.222442626953125 +2115 -0.29901123046875 +2116 -0.229888916015625 +2117 -0.308990478515625 +2118 -0.237274169921875 +2119 -0.318939208984375 +2120 -0.24462890625 +2121 -0.328826904296875 +2122 -0.251983642578125 +2123 -0.338714599609375 +2124 -0.259307861328125 +2125 -0.348541259765625 +2126 -0.2666015625 +2127 -0.35833740234375 +2128 -0.27386474609375 +2129 -0.36810302734375 +2130 -0.28106689453125 +2131 -0.3778076171875 +2132 -0.28826904296875 +2133 -0.387481689453125 +2134 -0.295440673828125 +2135 -0.397125244140625 +2136 -0.302581787109375 +2137 -0.406707763671875 +2138 -0.3096923828125 +2139 -0.416259765625 +2140 -0.316741943359375 +2141 -0.425750732421875 +2142 -0.32379150390625 +2143 -0.435211181640625 +2144 -0.330780029296875 +2145 -0.444610595703125 +2146 -0.337738037109375 +2147 -0.453948974609375 +2148 -0.34466552734375 +2149 -0.4632568359375 +2150 -0.3515625 +2151 -0.4725341796875 +2152 -0.3583984375 +2153 -0.481719970703125 +2154 -0.365203857421875 +2155 -0.490875244140625 +2156 -0.371978759765625 +2157 -0.499969482421875 +2158 -0.378692626953125 +2159 -0.509002685546875 +2160 -0.3853759765625 +2161 -0.51800537109375 +2162 -0.39202880859375 +2163 -0.52691650390625 +2164 -0.39862060546875 +2165 -0.535797119140625 +2166 -0.405181884765625 +2167 -0.54461669921875 +2168 -0.41168212890625 +2169 -0.5533447265625 +2170 -0.41815185546875 +2171 -0.562042236328125 +2172 -0.424591064453125 +2173 -0.5706787109375 +2174 -0.43096923828125 +2175 -0.579254150390625 +2176 -0.437255859375 +2177 -0.587738037109375 +2178 -0.44354248046875 +2179 -0.59619140625 +2180 -0.44976806640625 +2181 -0.60455322265625 +2182 -0.455963134765625 +2183 -0.612884521484375 +2184 -0.46209716796875 +2185 -0.621124267578125 +2186 -0.468170166015625 +2187 -0.6292724609375 +2188 -0.474212646484375 +2189 -0.63739013671875 +2190 -0.480194091796875 +2191 -0.645416259765625 +2192 -0.486114501953125 +2193 -0.65338134765625 +2194 -0.491973876953125 +2195 -0.661285400390625 +2196 -0.497802734375 +2197 -0.669097900390625 +2198 -0.503570556640625 +2199 -0.676849365234375 +2200 -0.50927734375 +2201 -0.68450927734375 +2202 -0.514923095703125 +2203 -0.692108154296875 +2204 -0.5205078125 +2205 -0.699615478515625 +2206 -0.526031494140625 +2207 -0.707061767578125 +2208 -0.53155517578125 +2209 -0.714447021484375 +2210 -0.536956787109375 +2211 -0.721710205078125 +2212 -0.542327880859375 +2213 -0.72894287109375 +2214 -0.547607421875 +2215 -0.736053466796875 +2216 -0.5528564453125 +2217 -0.74310302734375 +2218 -0.55804443359375 +2219 -0.75006103515625 +2220 -0.56317138671875 +2221 -0.7569580078125 +2222 -0.5682373046875 +2223 -0.763763427734375 +2224 -0.5732421875 +2225 -0.770477294921875 +2226 -0.578155517578125 +2227 -0.777099609375 +2228 -0.583038330078125 +2229 -0.783660888671875 +2230 -0.587860107421875 +2231 -0.790130615234375 +2232 -0.592559814453125 +2233 -0.796478271484375 +2234 -0.597259521484375 +2235 -0.802764892578125 +2236 -0.60186767578125 +2237 -0.808990478515625 +2238 -0.606414794921875 +2239 -0.815093994140625 +2240 -0.61090087890625 +2241 -0.82110595703125 +2242 -0.61529541015625 +2243 -0.8270263671875 +2244 -0.619659423828125 +2245 -0.8328857421875 +2246 -0.623931884765625 +2247 -0.838623046875 +2248 -0.628143310546875 +2249 -0.84429931640625 +2250 -0.632293701171875 +2251 -0.849853515625 +2252 -0.6363525390625 +2253 -0.855316162109375 +2254 -0.640350341796875 +2255 -0.860687255859375 +2256 -0.644287109375 +2257 -0.865997314453125 +2258 -0.648162841796875 +2259 -0.871185302734375 +2260 -0.65191650390625 +2261 -0.876251220703125 +2262 -0.6556396484375 +2263 -0.881256103515625 +2264 -0.6593017578125 +2265 -0.88616943359375 +2266 -0.662872314453125 +2267 -0.890960693359375 +2268 -0.666351318359375 +2269 -0.895660400390625 +2270 -0.6697998046875 +2271 -0.9002685546875 +2272 -0.67315673828125 +2273 -0.90478515625 +2274 -0.676422119140625 +2275 -0.9091796875 +2276 -0.679656982421875 +2277 -0.91351318359375 +2278 -0.682769775390625 +2279 -0.917724609375 +2280 -0.685821533203125 +2281 -0.92181396484375 +2282 -0.688812255859375 +2283 -0.92584228515625 +2284 -0.69171142578125 +2285 -0.929718017578125 +2286 -0.694549560546875 +2287 -0.93353271484375 +2288 -0.697296142578125 +2289 -0.937225341796875 +2290 -0.699981689453125 +2291 -0.940826416015625 +2292 -0.70257568359375 +2293 -0.9443359375 +2294 -0.705108642578125 +2295 -0.947723388671875 +2296 -0.707550048828125 +2297 -0.951019287109375 +2298 -0.70989990234375 +2299 -0.954193115234375 +2300 -0.71221923828125 +2301 -0.957275390625 +2302 -0.71441650390625 +2303 -0.960235595703125 +2304 -0.685699462890625 +2305 -0.963104248046875 +2306 -0.68768310546875 +2307 -0.96588134765625 +2308 -0.6895751953125 +2309 -0.968536376953125 +2310 -0.69140625 +2311 -0.971099853515625 +2312 -0.693145751953125 +2313 -0.973541259765625 +2314 -0.694793701171875 +2315 -0.975860595703125 +2316 -0.696380615234375 +2317 -0.97808837890625 +2318 -0.697906494140625 +2319 -0.980224609375 +2320 -0.6993408203125 +2321 -0.98223876953125 +2322 -0.700714111328125 +2323 -0.984161376953125 +2324 -0.701995849609375 +2325 -0.9859619140625 +2326 -0.70318603515625 +2327 -0.987640380859375 +2328 -0.704315185546875 +2329 -0.989227294921875 +2330 -0.705352783203125 +2331 -0.990692138671875 +2332 -0.706329345703125 +2333 -0.9920654296875 +2334 -0.70721435546875 +2335 -0.993316650390625 +2336 -0.708038330078125 +2337 -0.994476318359375 +2338 -0.70880126953125 +2339 -0.995513916015625 +2340 -0.70947265625 +2341 -0.9964599609375 +2342 -0.710052490234375 +2343 -0.997283935546875 +2344 -0.710540771484375 +2345 -0.99798583984375 +2346 -0.710968017578125 +2347 -0.99859619140625 +2348 -0.711334228515625 +2349 -0.999114990234375 +2350 -0.711578369140625 +2351 -0.999481201171875 +2352 -0.7117919921875 +2353 -0.999755859375 +2354 -0.7119140625 +2355 -0.99993896484375 +2356 -0.71197509765625 +2357 -1.0 +2358 -0.7119140625 +2359 -0.99993896484375 +2360 -0.7117919921875 +2361 -0.999755859375 +2362 -0.711578369140625 +2363 -0.999481201171875 +2364 -0.711334228515625 +2365 -0.999114990234375 +2366 -0.710968017578125 +2367 -0.99859619140625 +2368 -0.710540771484375 +2369 -0.99798583984375 +2370 -0.710052490234375 +2371 -0.997283935546875 +2372 -0.70947265625 +2373 -0.9964599609375 +2374 -0.70880126953125 +2375 -0.995513916015625 +2376 -0.708038330078125 +2377 -0.994476318359375 +2378 -0.70721435546875 +2379 -0.993316650390625 +2380 -0.706329345703125 +2381 -0.9920654296875 +2382 -0.705352783203125 +2383 -0.990692138671875 +2384 -0.704315185546875 +2385 -0.989227294921875 +2386 -0.70318603515625 +2387 -0.987640380859375 +2388 -0.701995849609375 +2389 -0.9859619140625 +2390 -0.700714111328125 +2391 -0.984161376953125 +2392 -0.6993408203125 +2393 -0.98223876953125 +2394 -0.697906494140625 +2395 -0.980224609375 +2396 -0.696380615234375 +2397 -0.97808837890625 +2398 -0.694793701171875 +2399 -0.975860595703125 +2400 -0.693145751953125 +2401 -0.973541259765625 +2402 -0.69140625 +2403 -0.971099853515625 +2404 -0.6895751953125 +2405 -0.968536376953125 +2406 -0.68768310546875 +2407 -0.96588134765625 +2408 -0.685699462890625 +2409 -0.963104248046875 +2410 -0.68365478515625 +2411 -0.960235595703125 +2412 -0.681549072265625 +2413 -0.957275390625 +2414 -0.67938232421875 +2415 -0.954193115234375 +2416 -0.677093505859375 +2417 -0.951019287109375 +2418 -0.674774169921875 +2419 -0.947723388671875 +2420 -0.67236328125 +2421 -0.9443359375 +2422 -0.66986083984375 +2423 -0.940826416015625 +2424 -0.66729736328125 +2425 -0.937225341796875 +2426 -0.664642333984375 +2427 -0.93353271484375 +2428 -0.66192626953125 +2429 -0.929718017578125 +2430 -0.6591796875 +2431 -0.92584228515625 +2432 -0.65631103515625 +2433 -0.92181396484375 +2434 -0.653411865234375 +2435 -0.917724609375 +2436 -0.650390625 +2437 -0.91351318359375 +2438 -0.647308349609375 +2439 -0.9091796875 +2440 -0.644195556640625 +2441 -0.90478515625 +2442 -0.640960693359375 +2443 -0.9002685546875 +2444 -0.6376953125 +2445 -0.895660400390625 +2446 -0.63433837890625 +2447 -0.890960693359375 +2448 -0.63092041015625 +2449 -0.88616943359375 +2450 -0.62744140625 +2451 -0.881256103515625 +2452 -0.623870849609375 +2453 -0.876251220703125 +2454 -0.620269775390625 +2455 -0.871185302734375 +2456 -0.6165771484375 +2457 -0.865997314453125 +2458 -0.61279296875 +2459 -0.860687255859375 +2460 -0.608978271484375 +2461 -0.855316162109375 +2462 -0.605072021484375 +2463 -0.849853515625 +2464 -0.60113525390625 +2465 -0.84429931640625 +2466 -0.597076416015625 +2467 -0.838623046875 +2468 -0.592987060546875 +2469 -0.8328857421875 +2470 -0.588836669921875 +2471 -0.8270263671875 +2472 -0.5845947265625 +2473 -0.82110595703125 +2474 -0.580322265625 +2475 -0.815093994140625 +2476 -0.57598876953125 +2477 -0.808990478515625 +2478 -0.571563720703125 +2479 -0.802764892578125 +2480 -0.56707763671875 +2481 -0.796478271484375 +2482 -0.56256103515625 +2483 -0.790130615234375 +2484 -0.557952880859375 +2485 -0.783660888671875 +2486 -0.55328369140625 +2487 -0.777099609375 +2488 -0.548553466796875 +2489 -0.770477294921875 +2490 -0.543792724609375 +2491 -0.763763427734375 +2492 -0.5389404296875 +2493 -0.7569580078125 +2494 -0.534027099609375 +2495 -0.75006103515625 +2496 -0.529083251953125 +2497 -0.74310302734375 +2498 -0.5240478515625 +2499 -0.736053466796875 +2500 -0.51898193359375 +2501 -0.72894287109375 +2502 -0.51385498046875 +2503 -0.721710205078125 +2504 -0.5086669921875 +2505 -0.714447021484375 +2506 -0.50341796875 +2507 -0.707061767578125 +2508 -0.49810791015625 +2509 -0.699615478515625 +2510 -0.492767333984375 +2511 -0.692108154296875 +2512 -0.48736572265625 +2513 -0.68450927734375 +2514 -0.481903076171875 +2515 -0.676849365234375 +2516 -0.47637939453125 +2517 -0.669097900390625 +2518 -0.4708251953125 +2519 -0.661285400390625 +2520 -0.465179443359375 +2521 -0.65338134765625 +2522 -0.45953369140625 +2523 -0.645416259765625 +2524 -0.45379638671875 +2525 -0.63739013671875 +2526 -0.448028564453125 +2527 -0.6292724609375 +2528 -0.442230224609375 +2529 -0.621124267578125 +2530 -0.436370849609375 +2531 -0.612884521484375 +2532 -0.430419921875 +2533 -0.60455322265625 +2534 -0.424468994140625 +2535 -0.59619140625 +2536 -0.41845703125 +2537 -0.587738037109375 +2538 -0.41241455078125 +2539 -0.579254150390625 +2540 -0.40631103515625 +2541 -0.5706787109375 +2542 -0.400146484375 +2543 -0.562042236328125 +2544 -0.393951416015625 +2545 -0.5533447265625 +2546 -0.38775634765625 +2547 -0.54461669921875 +2548 -0.3814697265625 +2549 -0.535797119140625 +2550 -0.375152587890625 +2551 -0.52691650390625 +2552 -0.368804931640625 +2553 -0.51800537109375 +2554 -0.362396240234375 +2555 -0.509002685546875 +2556 -0.35595703125 +2557 -0.499969482421875 +2558 -0.3494873046875 +2559 -0.490875244140625 +2560 -0.337188720703125 +2561 -0.481719970703125 +2562 -0.33074951171875 +2563 -0.4725341796875 +2564 -0.32427978515625 +2565 -0.4632568359375 +2566 -0.3177490234375 +2567 -0.453948974609375 +2568 -0.31121826171875 +2569 -0.444610595703125 +2570 -0.30462646484375 +2571 -0.435211181640625 +2572 -0.298004150390625 +2573 -0.425750732421875 +2574 -0.2913818359375 +2575 -0.416259765625 +2576 -0.28466796875 +2577 -0.406707763671875 +2578 -0.277984619140625 +2579 -0.397125244140625 +2580 -0.271209716796875 +2581 -0.387481689453125 +2582 -0.26446533203125 +2583 -0.3778076171875 +2584 -0.257659912109375 +2585 -0.36810302734375 +2586 -0.250823974609375 +2587 -0.35833740234375 +2588 -0.24395751953125 +2589 -0.348541259765625 +2590 -0.237091064453125 +2591 -0.338714599609375 +2592 -0.23016357421875 +2593 -0.328826904296875 +2594 -0.223236083984375 +2595 -0.318939208984375 +2596 -0.216278076171875 +2597 -0.308990478515625 +2598 -0.20928955078125 +2599 -0.29901123046875 +2600 -0.202301025390625 +2601 -0.28900146484375 +2602 -0.19525146484375 +2603 -0.278961181640625 +2604 -0.188201904296875 +2605 -0.268890380859375 +2606 -0.18115234375 +2607 -0.2587890625 +2608 -0.174041748046875 +2609 -0.2486572265625 +2610 -0.166961669921875 +2611 -0.238525390625 +2612 -0.159820556640625 +2613 -0.22833251953125 +2614 -0.15264892578125 +2615 -0.218109130859375 +2616 -0.1455078125 +2617 -0.2078857421875 +2618 -0.138336181640625 +2619 -0.1976318359375 +2620 -0.131134033203125 +2621 -0.187347412109375 +2622 -0.123931884765625 +2623 -0.17706298828125 +2624 -0.11669921875 +2625 -0.166748046875 +2626 -0.109466552734375 +2627 -0.156402587890625 +2628 -0.10223388671875 +2629 -0.14605712890625 +2630 -0.094970703125 +2631 -0.13568115234375 +2632 -0.08770751953125 +2633 -0.12530517578125 +2634 -0.0804443359375 +2635 -0.11492919921875 +2636 -0.073150634765625 +2637 -0.104522705078125 +2638 -0.06585693359375 +2639 -0.094085693359375 +2640 -0.05853271484375 +2641 -0.083648681640625 +2642 -0.051239013671875 +2643 -0.073211669921875 +2644 -0.043914794921875 +2645 -0.062774658203125 +2646 -0.036590576171875 +2647 -0.05230712890625 +2648 -0.029296875 +2649 -0.0418701171875 +2650 -0.02197265625 +2651 -0.031402587890625 +2652 -0.0146484375 +2653 -0.02093505859375 +2654 -0.00732421875 +2655 -0.010467529296875 +2656 0.0 +2657 0.0 +2658 0.007110595703125 +2659 0.010467529296875 +2660 0.01422119140625 +2661 0.02093505859375 +2662 0.021331787109375 +2663 0.031402587890625 +2664 0.0284423828125 +2665 0.0418701171875 +2666 0.035552978515625 +2667 0.05230712890625 +2668 0.04266357421875 +2669 0.062774658203125 +2670 0.049774169921875 +2671 0.073211669921875 +2672 0.056854248046875 +2673 0.083648681640625 +2674 0.06396484375 +2675 0.094085693359375 +2676 0.071075439453125 +2677 0.104522705078125 +2678 0.078125 +2679 0.11492919921875 +2680 0.085205078125 +2681 0.12530517578125 +2682 0.092254638671875 +2683 0.13568115234375 +2684 0.09930419921875 +2685 0.14605712890625 +2686 0.106353759765625 +2687 0.156402587890625 +2688 0.113372802734375 +2689 0.166748046875 +2690 0.120391845703125 +2691 0.17706298828125 +2692 0.12738037109375 +2693 0.187347412109375 +2694 0.134368896484375 +2695 0.1976318359375 +2696 0.141357421875 +2697 0.2078857421875 +2698 0.1483154296875 +2699 0.218109130859375 +2700 0.155242919921875 +2701 0.22833251953125 +2702 0.16217041015625 +2703 0.238525390625 +2704 0.1690673828125 +2705 0.2486572265625 +2706 0.17596435546875 +2707 0.2587890625 +2708 0.182830810546875 +2709 0.268890380859375 +2710 0.189697265625 +2711 0.278961181640625 +2712 0.196502685546875 +2713 0.28900146484375 +2714 0.20330810546875 +2715 0.29901123046875 +2716 0.210113525390625 +2717 0.308990478515625 +2718 0.21685791015625 +2719 0.318939208984375 +2720 0.223602294921875 +2721 0.328826904296875 +2722 0.230316162109375 +2723 0.338714599609375 +2724 0.23699951171875 +2725 0.348541259765625 +2726 0.24365234375 +2727 0.35833740234375 +2728 0.25030517578125 +2729 0.36810302734375 +2730 0.25689697265625 +2731 0.3778076171875 +2732 0.26348876953125 +2733 0.387481689453125 +2734 0.270050048828125 +2735 0.397125244140625 +2736 0.27655029296875 +2737 0.406707763671875 +2738 0.283050537109375 +2739 0.416259765625 +2740 0.28948974609375 +2741 0.425750732421875 +2742 0.295928955078125 +2743 0.435211181640625 +2744 0.302337646484375 +2745 0.444610595703125 +2746 0.308685302734375 +2747 0.453948974609375 +2748 0.31500244140625 +2749 0.4632568359375 +2750 0.321319580078125 +2751 0.4725341796875 +2752 0.32757568359375 +2753 0.481719970703125 +2754 0.33380126953125 +2755 0.490875244140625 +2756 0.3399658203125 +2757 0.499969482421875 +2758 0.346099853515625 +2759 0.509002685546875 +2760 0.35223388671875 +2761 0.51800537109375 +2762 0.358306884765625 +2763 0.52691650390625 +2764 0.36431884765625 +2765 0.535797119140625 +2766 0.370330810546875 +2767 0.54461669921875 +2768 0.37628173828125 +2769 0.5533447265625 +2770 0.382171630859375 +2771 0.562042236328125 +2772 0.3880615234375 +2773 0.5706787109375 +2774 0.393890380859375 +2775 0.579254150390625 +2776 0.399658203125 +2777 0.587738037109375 +2778 0.4053955078125 +2779 0.59619140625 +2780 0.411102294921875 +2781 0.60455322265625 +2782 0.416748046875 +2783 0.612884521484375 +2784 0.42236328125 +2785 0.621124267578125 +2786 0.427886962890625 +2787 0.6292724609375 +2788 0.43341064453125 +2789 0.63739013671875 +2790 0.438873291015625 +2791 0.645416259765625 +2792 0.444305419921875 +2793 0.65338134765625 +2794 0.449676513671875 +2795 0.661285400390625 +2796 0.454986572265625 +2797 0.669097900390625 +2798 0.46026611328125 +2799 0.676849365234375 +2800 0.4654541015625 +2801 0.68450927734375 +2802 0.47064208984375 +2803 0.692108154296875 +2804 0.475738525390625 +2805 0.699615478515625 +2806 0.480804443359375 +2807 0.707061767578125 +2808 0.485809326171875 +2809 0.714447021484375 +2810 0.490753173828125 +2811 0.721710205078125 +2812 0.49566650390625 +2813 0.72894287109375 +2814 0.500518798828125 +2815 0.736053466796875 +2816 0.48150634765625 +2817 0.74310302734375 +2818 0.48602294921875 +2819 0.75006103515625 +2820 0.490478515625 +2821 0.7569580078125 +2822 0.494903564453125 +2823 0.763763427734375 +2824 0.499267578125 +2825 0.770477294921875 +2826 0.5035400390625 +2827 0.777099609375 +2828 0.507781982421875 +2829 0.783660888671875 +2830 0.511993408203125 +2831 0.790130615234375 +2832 0.51611328125 +2833 0.796478271484375 +2834 0.520172119140625 +2835 0.802764892578125 +2836 0.524200439453125 +2837 0.808990478515625 +2838 0.528167724609375 +2839 0.815093994140625 +2840 0.532073974609375 +2841 0.82110595703125 +2842 0.535888671875 +2843 0.8270263671875 +2844 0.539703369140625 +2845 0.8328857421875 +2846 0.543426513671875 +2847 0.838623046875 +2848 0.547088623046875 +2849 0.84429931640625 +2850 0.550689697265625 +2851 0.849853515625 +2852 0.554229736328125 +2853 0.855316162109375 +2854 0.557708740234375 +2855 0.860687255859375 +2856 0.5611572265625 +2857 0.865997314453125 +2858 0.56451416015625 +2859 0.871185302734375 +2860 0.56781005859375 +2861 0.876251220703125 +2862 0.571044921875 +2863 0.881256103515625 +2864 0.57421875 +2865 0.88616943359375 +2866 0.57733154296875 +2867 0.890960693359375 +2868 0.58038330078125 +2869 0.895660400390625 +2870 0.583343505859375 +2871 0.9002685546875 +2872 0.586273193359375 +2873 0.90478515625 +2874 0.589141845703125 +2875 0.9091796875 +2876 0.591949462890625 +2877 0.91351318359375 +2878 0.59466552734375 +2879 0.917724609375 +2880 0.597320556640625 +2881 0.92181396484375 +2882 0.599945068359375 +2883 0.92584228515625 +2884 0.602447509765625 +2885 0.929718017578125 +2886 0.60491943359375 +2887 0.93353271484375 +2888 0.6072998046875 +2889 0.937225341796875 +2890 0.609649658203125 +2891 0.940826416015625 +2892 0.611907958984375 +2893 0.9443359375 +2894 0.614105224609375 +2895 0.947723388671875 +2896 0.616241455078125 +2897 0.951019287109375 +2898 0.618316650390625 +2899 0.954193115234375 +2900 0.62030029296875 +2901 0.957275390625 +2902 0.622222900390625 +2903 0.960235595703125 +2904 0.62408447265625 +2905 0.963104248046875 +2906 0.625885009765625 +2907 0.96588134765625 +2908 0.627593994140625 +2909 0.968536376953125 +2910 0.629241943359375 +2911 0.971099853515625 +2912 0.630828857421875 +2913 0.973541259765625 +2914 0.632354736328125 +2915 0.975860595703125 +2916 0.6337890625 +2917 0.97808837890625 +2918 0.635162353515625 +2919 0.980224609375 +2920 0.636474609375 +2921 0.98223876953125 +2922 0.637725830078125 +2923 0.984161376953125 +2924 0.638885498046875 +2925 0.9859619140625 +2926 0.639984130859375 +2927 0.987640380859375 +2928 0.6409912109375 +2929 0.989227294921875 +2930 0.6419677734375 +2931 0.990692138671875 +2932 0.642852783203125 +2933 0.9920654296875 +2934 0.643646240234375 +2935 0.993316650390625 +2936 0.6444091796875 +2937 0.994476318359375 +2938 0.64508056640625 +2939 0.995513916015625 +2940 0.64569091796875 +2941 0.9964599609375 +2942 0.646209716796875 +2943 0.997283935546875 +2944 0.64666748046875 +2945 0.99798583984375 +2946 0.647064208984375 +2947 0.99859619140625 +2948 0.64739990234375 +2949 0.999114990234375 +2950 0.647613525390625 +2951 0.999481201171875 +2952 0.647796630859375 +2953 0.999755859375 +2954 0.647918701171875 +2955 0.99993896484375 +2956 0.647979736328125 +2957 0.999969482421875 +2958 0.647918701171875 +2959 0.99993896484375 +2960 0.647796630859375 +2961 0.999755859375 +2962 0.647613525390625 +2963 0.999481201171875 +2964 0.64739990234375 +2965 0.999114990234375 +2966 0.647064208984375 +2967 0.99859619140625 +2968 0.64666748046875 +2969 0.99798583984375 +2970 0.646209716796875 +2971 0.997283935546875 +2972 0.64569091796875 +2973 0.9964599609375 +2974 0.64508056640625 +2975 0.995513916015625 +2976 0.6444091796875 +2977 0.994476318359375 +2978 0.643646240234375 +2979 0.993316650390625 +2980 0.642852783203125 +2981 0.9920654296875 +2982 0.6419677734375 +2983 0.990692138671875 +2984 0.6409912109375 +2985 0.989227294921875 +2986 0.639984130859375 +2987 0.987640380859375 +2988 0.638885498046875 +2989 0.9859619140625 +2990 0.637725830078125 +2991 0.984161376953125 +2992 0.636474609375 +2993 0.98223876953125 +2994 0.635162353515625 +2995 0.980224609375 +2996 0.6337890625 +2997 0.97808837890625 +2998 0.632354736328125 +2999 0.975860595703125 +3000 0.630828857421875 +3001 0.973541259765625 +3002 0.629241943359375 +3003 0.971099853515625 +3004 0.627593994140625 +3005 0.968536376953125 +3006 0.625885009765625 +3007 0.96588134765625 +3008 0.62408447265625 +3009 0.963104248046875 +3010 0.622222900390625 +3011 0.960235595703125 +3012 0.62030029296875 +3013 0.957275390625 +3014 0.618316650390625 +3015 0.954193115234375 +3016 0.616241455078125 +3017 0.951019287109375 +3018 0.614105224609375 +3019 0.947723388671875 +3020 0.611907958984375 +3021 0.9443359375 +3022 0.609649658203125 +3023 0.940826416015625 +3024 0.6072998046875 +3025 0.937225341796875 +3026 0.60491943359375 +3027 0.93353271484375 +3028 0.602447509765625 +3029 0.929718017578125 +3030 0.599945068359375 +3031 0.92584228515625 +3032 0.597320556640625 +3033 0.92181396484375 +3034 0.59466552734375 +3035 0.917724609375 +3036 0.591949462890625 +3037 0.91351318359375 +3038 0.589141845703125 +3039 0.9091796875 +3040 0.586273193359375 +3041 0.90478515625 +3042 0.583343505859375 +3043 0.9002685546875 +3044 0.58038330078125 +3045 0.895660400390625 +3046 0.57733154296875 +3047 0.890960693359375 +3048 0.57421875 +3049 0.88616943359375 +3050 0.571044921875 +3051 0.881256103515625 +3052 0.56781005859375 +3053 0.876251220703125 +3054 0.56451416015625 +3055 0.871185302734375 +3056 0.5611572265625 +3057 0.865997314453125 +3058 0.557708740234375 +3059 0.860687255859375 +3060 0.554229736328125 +3061 0.855316162109375 +3062 0.550689697265625 +3063 0.849853515625 +3064 0.547088623046875 +3065 0.84429931640625 +3066 0.543426513671875 +3067 0.838623046875 +3068 0.539703369140625 +3069 0.8328857421875 +3070 0.535888671875 +3071 0.8270263671875 +3072 0.505767822265625 +3073 0.82110595703125 +3074 0.5020751953125 +3075 0.815093994140625 +3076 0.498321533203125 +3077 0.808990478515625 +3078 0.494476318359375 +3079 0.802764892578125 +3080 0.4906005859375 +3081 0.796478271484375 +3082 0.4866943359375 +3083 0.790130615234375 +3084 0.482696533203125 +3085 0.783660888671875 +3086 0.478668212890625 +3087 0.777099609375 +3088 0.474578857421875 +3089 0.770477294921875 +3090 0.470458984375 +3091 0.763763427734375 +3092 0.46624755859375 +3093 0.7569580078125 +3094 0.462005615234375 +3095 0.75006103515625 +3096 0.457733154296875 +3097 0.74310302734375 +3098 0.453369140625 +3099 0.736053466796875 +3100 0.449005126953125 +3101 0.72894287109375 +3102 0.444549560546875 +3103 0.721710205078125 +3104 0.4400634765625 +3105 0.714447021484375 +3106 0.435516357421875 +3107 0.707061767578125 +3108 0.430938720703125 +3109 0.699615478515625 +3110 0.426300048828125 +3111 0.692108154296875 +3112 0.421630859375 +3113 0.68450927734375 +3114 0.416900634765625 +3115 0.676849365234375 +3116 0.412139892578125 +3117 0.669097900390625 +3118 0.407318115234375 +3119 0.661285400390625 +3120 0.4024658203125 +3121 0.65338134765625 +3122 0.397552490234375 +3123 0.645416259765625 +3124 0.392608642578125 +3125 0.63739013671875 +3126 0.387603759765625 +3127 0.6292724609375 +3128 0.382598876953125 +3129 0.621124267578125 +3130 0.37750244140625 +3131 0.612884521484375 +3132 0.37237548828125 +3133 0.60455322265625 +3134 0.367218017578125 +3135 0.59619140625 +3136 0.362030029296875 +3137 0.587738037109375 +3138 0.3568115234375 +3139 0.579254150390625 +3140 0.35150146484375 +3141 0.5706787109375 +3142 0.34619140625 +3143 0.562042236328125 +3144 0.340850830078125 +3145 0.5533447265625 +3146 0.33544921875 +3147 0.54461669921875 +3148 0.33001708984375 +3149 0.535797119140625 +3150 0.324554443359375 +3151 0.52691650390625 +3152 0.319061279296875 +3153 0.51800537109375 +3154 0.31353759765625 +3155 0.509002685546875 +3156 0.307952880859375 +3157 0.499969482421875 +3158 0.3023681640625 +3159 0.490875244140625 +3160 0.296722412109375 +3161 0.481719970703125 +3162 0.291046142578125 +3163 0.4725341796875 +3164 0.28533935546875 +3165 0.4632568359375 +3166 0.27960205078125 +3167 0.453948974609375 +3168 0.27386474609375 +3169 0.444610595703125 +3170 0.26806640625 +3171 0.435211181640625 +3172 0.262237548828125 +3173 0.425750732421875 +3174 0.25640869140625 +3175 0.416259765625 +3176 0.250518798828125 +3177 0.406707763671875 +3178 0.244598388671875 +3179 0.397125244140625 +3180 0.238677978515625 +3181 0.387481689453125 +3182 0.232696533203125 +3183 0.3778076171875 +3184 0.22674560546875 +3185 0.36810302734375 +3186 0.220703125 +3187 0.35833740234375 +3188 0.214691162109375 +3189 0.348541259765625 +3190 0.2086181640625 +3191 0.338714599609375 +3192 0.202545166015625 +3193 0.328826904296875 +3194 0.196441650390625 +3195 0.318939208984375 +3196 0.1903076171875 +3197 0.308990478515625 +3198 0.184173583984375 +3199 0.29901123046875 +3200 0.178009033203125 +3201 0.28900146484375 +3202 0.17181396484375 +3203 0.278961181640625 +3204 0.165618896484375 +3205 0.268890380859375 +3206 0.159393310546875 +3207 0.2587890625 +3208 0.153167724609375 +3209 0.2486572265625 +3210 0.14691162109375 +3211 0.238525390625 +3212 0.140625 +3213 0.22833251953125 +3214 0.13433837890625 +3215 0.218109130859375 +3216 0.1280517578125 +3217 0.2078857421875 +3218 0.121734619140625 +3219 0.1976318359375 +3220 0.115386962890625 +3221 0.187347412109375 +3222 0.109039306640625 +3223 0.17706298828125 +3224 0.102691650390625 +3225 0.166748046875 +3226 0.0963134765625 +3227 0.156402587890625 +3228 0.0899658203125 +3229 0.14605712890625 +3230 0.08355712890625 +3231 0.13568115234375 +3232 0.077178955078125 +3233 0.12530517578125 +3234 0.070770263671875 +3235 0.11492919921875 +3236 0.064361572265625 +3237 0.104522705078125 +3238 0.057952880859375 +3239 0.094085693359375 +3240 0.051513671875 +3241 0.083648681640625 +3242 0.045074462890625 +3243 0.073211669921875 +3244 0.038665771484375 +3245 0.062774658203125 +3246 0.032196044921875 +3247 0.05230712890625 +3248 0.025787353515625 +3249 0.0418701171875 +3250 0.019317626953125 +3251 0.031402587890625 +3252 0.01287841796875 +3253 0.02093505859375 +3254 0.006439208984375 +3255 0.010467529296875 +3256 0.0 +3257 0.0 +3258 -0.006439208984375 +3259 -0.010467529296875 +3260 -0.01287841796875 +3261 -0.02093505859375 +3262 -0.019317626953125 +3263 -0.031402587890625 +3264 -0.025787353515625 +3265 -0.0418701171875 +3266 -0.032196044921875 +3267 -0.05230712890625 +3268 -0.038665771484375 +3269 -0.062774658203125 +3270 -0.045074462890625 +3271 -0.073211669921875 +3272 -0.051513671875 +3273 -0.083648681640625 +3274 -0.057952880859375 +3275 -0.094085693359375 +3276 -0.064361572265625 +3277 -0.104522705078125 +3278 -0.070770263671875 +3279 -0.11492919921875 +3280 -0.077178955078125 +3281 -0.12530517578125 +3282 -0.08355712890625 +3283 -0.13568115234375 +3284 -0.0899658203125 +3285 -0.14605712890625 +3286 -0.0963134765625 +3287 -0.156402587890625 +3288 -0.102691650390625 +3289 -0.166748046875 +3290 -0.109039306640625 +3291 -0.17706298828125 +3292 -0.115386962890625 +3293 -0.187347412109375 +3294 -0.121734619140625 +3295 -0.1976318359375 +3296 -0.1280517578125 +3297 -0.2078857421875 +3298 -0.13433837890625 +3299 -0.218109130859375 +3300 -0.140625 +3301 -0.22833251953125 +3302 -0.14691162109375 +3303 -0.238525390625 +3304 -0.153167724609375 +3305 -0.2486572265625 +3306 -0.159393310546875 +3307 -0.2587890625 +3308 -0.165618896484375 +3309 -0.268890380859375 +3310 -0.17181396484375 +3311 -0.278961181640625 +3312 -0.178009033203125 +3313 -0.28900146484375 +3314 -0.184173583984375 +3315 -0.29901123046875 +3316 -0.1903076171875 +3317 -0.308990478515625 +3318 -0.196441650390625 +3319 -0.318939208984375 +3320 -0.202545166015625 +3321 -0.328826904296875 +3322 -0.2086181640625 +3323 -0.338714599609375 +3324 -0.214691162109375 +3325 -0.348541259765625 +3326 -0.220703125 +3327 -0.35833740234375 +3328 -0.2149658203125 +3329 -0.36810302734375 +3330 -0.220611572265625 +3331 -0.3778076171875 +3332 -0.226287841796875 +3333 -0.387481689453125 +3334 -0.231903076171875 +3335 -0.397125244140625 +3336 -0.23748779296875 +3337 -0.406707763671875 +3338 -0.243072509765625 +3339 -0.416259765625 +3340 -0.248626708984375 +3341 -0.425750732421875 +3342 -0.254150390625 +3343 -0.435211181640625 +3344 -0.2596435546875 +3345 -0.444610595703125 +3346 -0.265106201171875 +3347 -0.453948974609375 +3348 -0.270538330078125 +3349 -0.4632568359375 +3350 -0.27593994140625 +3351 -0.4725341796875 +3352 -0.28131103515625 +3353 -0.481719970703125 +3354 -0.286651611328125 +3355 -0.490875244140625 +3356 -0.291961669921875 +3357 -0.499969482421875 +3358 -0.2972412109375 +3359 -0.509002685546875 +3360 -0.302490234375 +3361 -0.51800537109375 +3362 -0.307708740234375 +3363 -0.52691650390625 +3364 -0.312896728515625 +3365 -0.535797119140625 +3366 -0.31805419921875 +3367 -0.54461669921875 +3368 -0.323150634765625 +3369 -0.5533447265625 +3370 -0.328216552734375 +3371 -0.562042236328125 +3372 -0.333251953125 +3373 -0.5706787109375 +3374 -0.3382568359375 +3375 -0.579254150390625 +3376 -0.343231201171875 +3377 -0.587738037109375 +3378 -0.348175048828125 +3379 -0.59619140625 +3380 -0.353057861328125 +3381 -0.60455322265625 +3382 -0.35791015625 +3383 -0.612884521484375 +3384 -0.36273193359375 +3385 -0.621124267578125 +3386 -0.36749267578125 +3387 -0.6292724609375 +3388 -0.372222900390625 +3389 -0.63739013671875 +3390 -0.376922607421875 +3391 -0.645416259765625 +3392 -0.381561279296875 +3393 -0.65338134765625 +3394 -0.38616943359375 +3395 -0.661285400390625 +3396 -0.3907470703125 +3397 -0.669097900390625 +3398 -0.395263671875 +3399 -0.676849365234375 +3400 -0.399749755859375 +3401 -0.68450927734375 +3402 -0.4041748046875 +3403 -0.692108154296875 +3404 -0.4085693359375 +3405 -0.699615478515625 +3406 -0.41290283203125 +3407 -0.707061767578125 +3408 -0.417236328125 +3409 -0.714447021484375 +3410 -0.421478271484375 +3411 -0.721710205078125 +3412 -0.425689697265625 +3413 -0.72894287109375 +3414 -0.429840087890625 +3415 -0.736053466796875 +3416 -0.4339599609375 +3417 -0.74310302734375 +3418 -0.438018798828125 +3419 -0.75006103515625 +3420 -0.442047119140625 +3421 -0.7569580078125 +3422 -0.446014404296875 +3423 -0.763763427734375 +3424 -0.449951171875 +3425 -0.770477294921875 +3426 -0.453826904296875 +3427 -0.777099609375 +3428 -0.4576416015625 +3429 -0.783660888671875 +3430 -0.46142578125 +3431 -0.790130615234375 +3432 -0.465118408203125 +3433 -0.796478271484375 +3434 -0.46881103515625 +3435 -0.802764892578125 +3436 -0.472442626953125 +3437 -0.808990478515625 +3438 -0.47601318359375 +3439 -0.815093994140625 +3440 -0.479522705078125 +3441 -0.82110595703125 +3442 -0.48297119140625 +3443 -0.8270263671875 +3444 -0.48638916015625 +3445 -0.8328857421875 +3446 -0.48974609375 +3447 -0.838623046875 +3448 -0.493072509765625 +3449 -0.84429931640625 +3450 -0.496307373046875 +3451 -0.849853515625 +3452 -0.499481201171875 +3453 -0.855316162109375 +3454 -0.50262451171875 +3455 -0.860687255859375 +3456 -0.5057373046875 +3457 -0.865997314453125 +3458 -0.508758544921875 +3459 -0.871185302734375 +3460 -0.51171875 +3461 -0.876251220703125 +3462 -0.5146484375 +3463 -0.881256103515625 +3464 -0.51751708984375 +3465 -0.88616943359375 +3466 -0.520294189453125 +3467 -0.890960693359375 +3468 -0.523040771484375 +3469 -0.895660400390625 +3470 -0.5257568359375 +3471 -0.9002685546875 +3472 -0.52838134765625 +3473 -0.90478515625 +3474 -0.53094482421875 +3475 -0.9091796875 +3476 -0.533477783203125 +3477 -0.91351318359375 +3478 -0.53594970703125 +3479 -0.917724609375 +3480 -0.538330078125 +3481 -0.92181396484375 +3482 -0.540679931640625 +3483 -0.92584228515625 +3484 -0.542938232421875 +3485 -0.929718017578125 +3486 -0.545166015625 +3487 -0.93353271484375 +3488 -0.547332763671875 +3489 -0.937225341796875 +3490 -0.5494384765625 +3491 -0.940826416015625 +3492 -0.551483154296875 +3493 -0.9443359375 +3494 -0.553466796875 +3495 -0.947723388671875 +3496 -0.555389404296875 +3497 -0.951019287109375 +3498 -0.557220458984375 +3499 -0.954193115234375 +3500 -0.55902099609375 +3501 -0.957275390625 +3502 -0.560760498046875 +3503 -0.960235595703125 +3504 -0.56243896484375 +3505 -0.963104248046875 +3506 -0.564056396484375 +3507 -0.96588134765625 +3508 -0.56561279296875 +3509 -0.968536376953125 +3510 -0.567108154296875 +3511 -0.971099853515625 +3512 -0.56854248046875 +3513 -0.973541259765625 +3514 -0.56988525390625 +3515 -0.975860595703125 +3516 -0.571197509765625 +3517 -0.97808837890625 +3518 -0.57244873046875 +3519 -0.980224609375 +3520 -0.5736083984375 +3521 -0.98223876953125 +3522 -0.574737548828125 +3523 -0.984161376953125 +3524 -0.575775146484375 +3525 -0.9859619140625 +3526 -0.5767822265625 +3527 -0.987640380859375 +3528 -0.57769775390625 +3529 -0.989227294921875 +3530 -0.57855224609375 +3531 -0.990692138671875 +3532 -0.579345703125 +3533 -0.9920654296875 +3534 -0.580078125 +3535 -0.993316650390625 +3536 -0.58074951171875 +3537 -0.994476318359375 +3538 -0.58135986328125 +3539 -0.995513916015625 +3540 -0.5819091796875 +3541 -0.9964599609375 +3542 -0.5823974609375 +3543 -0.997283935546875 +3544 -0.58282470703125 +3545 -0.99798583984375 +3546 -0.583160400390625 +3547 -0.99859619140625 +3548 -0.583465576171875 +3549 -0.999114990234375 +3550 -0.58367919921875 +3551 -0.999481201171875 +3552 -0.583831787109375 +3553 -0.999755859375 +3554 -0.58392333984375 +3555 -0.99993896484375 +3556 -0.583984375 +3557 -1.0 +3558 -0.58392333984375 +3559 -0.99993896484375 +3560 -0.583831787109375 +3561 -0.999755859375 +3562 -0.58367919921875 +3563 -0.999481201171875 +3564 -0.583465576171875 +3565 -0.999114990234375 +3566 -0.583160400390625 +3567 -0.99859619140625 +3568 -0.58282470703125 +3569 -0.99798583984375 +3570 -0.5823974609375 +3571 -0.997283935546875 +3572 -0.5819091796875 +3573 -0.9964599609375 +3574 -0.58135986328125 +3575 -0.995513916015625 +3576 -0.58074951171875 +3577 -0.994476318359375 +3578 -0.580078125 +3579 -0.993316650390625 +3580 -0.579345703125 +3581 -0.9920654296875 +3582 -0.57855224609375 +3583 -0.990692138671875 +3584 -0.5460205078125 +3585 -0.989227294921875 +3586 -0.545135498046875 +3587 -0.987640380859375 +3588 -0.544219970703125 +3589 -0.9859619140625 +3590 -0.543243408203125 +3591 -0.984161376953125 +3592 -0.54217529296875 +3593 -0.98223876953125 +3594 -0.541046142578125 +3595 -0.980224609375 +3596 -0.539886474609375 +3597 -0.97808837890625 +3598 -0.53863525390625 +3599 -0.975860595703125 +3600 -0.537353515625 +3601 -0.973541259765625 +3602 -0.5360107421875 +3603 -0.971099853515625 +3604 -0.53460693359375 +3605 -0.968536376953125 +3606 -0.53314208984375 +3607 -0.96588134765625 +3608 -0.5316162109375 +3609 -0.963104248046875 +3610 -0.530029296875 +3611 -0.960235595703125 +3612 -0.52838134765625 +3613 -0.957275390625 +3614 -0.526702880859375 +3615 -0.954193115234375 +3616 -0.524932861328125 +3617 -0.951019287109375 +3618 -0.523101806640625 +3619 -0.947723388671875 +3620 -0.521240234375 +3621 -0.9443359375 +3622 -0.519317626953125 +3623 -0.940826416015625 +3624 -0.517333984375 +3625 -0.937225341796875 +3626 -0.515289306640625 +3627 -0.93353271484375 +3628 -0.51318359375 +3629 -0.929718017578125 +3630 -0.51104736328125 +3631 -0.92584228515625 +3632 -0.508819580078125 +3633 -0.92181396484375 +3634 -0.506561279296875 +3635 -0.917724609375 +3636 -0.504241943359375 +3637 -0.91351318359375 +3638 -0.5018310546875 +3639 -0.9091796875 +3640 -0.499420166015625 +3641 -0.90478515625 +3642 -0.496917724609375 +3643 -0.9002685546875 +3644 -0.494384765625 +3645 -0.895660400390625 +3646 -0.491790771484375 +3647 -0.890960693359375 +3648 -0.4891357421875 +3649 -0.88616943359375 +3650 -0.486419677734375 +3651 -0.881256103515625 +3652 -0.483673095703125 +3653 -0.876251220703125 +3654 -0.480865478515625 +3655 -0.871185302734375 +3656 -0.477996826171875 +3657 -0.865997314453125 +3658 -0.475067138671875 +3659 -0.860687255859375 +3660 -0.47210693359375 +3661 -0.855316162109375 +3662 -0.469085693359375 +3663 -0.849853515625 +3664 -0.466033935546875 +3665 -0.84429931640625 +3666 -0.462890625 +3667 -0.838623046875 +3668 -0.459716796875 +3669 -0.8328857421875 +3670 -0.45648193359375 +3671 -0.8270263671875 +3672 -0.453216552734375 +3673 -0.82110595703125 +3674 -0.449920654296875 +3675 -0.815093994140625 +3676 -0.446533203125 +3677 -0.808990478515625 +3678 -0.443115234375 +3679 -0.802764892578125 +3680 -0.43963623046875 +3681 -0.796478271484375 +3682 -0.436126708984375 +3683 -0.790130615234375 +3684 -0.43255615234375 +3685 -0.783660888671875 +3686 -0.428924560546875 +3687 -0.777099609375 +3688 -0.42529296875 +3689 -0.770477294921875 +3690 -0.42156982421875 +3691 -0.763763427734375 +3692 -0.417816162109375 +3693 -0.7569580078125 +3694 -0.41400146484375 +3695 -0.75006103515625 +3696 -0.41015625 +3697 -0.74310302734375 +3698 -0.406280517578125 +3699 -0.736053466796875 +3700 -0.40234375 +3701 -0.72894287109375 +3702 -0.398345947265625 +3703 -0.721710205078125 +3704 -0.39434814453125 +3705 -0.714447021484375 +3706 -0.390289306640625 +3707 -0.707061767578125 +3708 -0.38616943359375 +3709 -0.699615478515625 +3710 -0.38201904296875 +3711 -0.692108154296875 +3712 -0.377838134765625 +3713 -0.68450927734375 +3714 -0.37359619140625 +3715 -0.676849365234375 +3716 -0.36932373046875 +3717 -0.669097900390625 +3718 -0.365020751953125 +3719 -0.661285400390625 +3720 -0.36065673828125 +3721 -0.65338134765625 +3722 -0.35626220703125 +3723 -0.645416259765625 +3724 -0.351806640625 +3725 -0.63739013671875 +3726 -0.347320556640625 +3727 -0.6292724609375 +3728 -0.34283447265625 +3729 -0.621124267578125 +3730 -0.338287353515625 +3731 -0.612884521484375 +3732 -0.33367919921875 +3733 -0.60455322265625 +3734 -0.329071044921875 +3735 -0.59619140625 +3736 -0.32440185546875 +3737 -0.587738037109375 +3738 -0.319732666015625 +3739 -0.579254150390625 +3740 -0.31500244140625 +3741 -0.5706787109375 +3742 -0.310211181640625 +3743 -0.562042236328125 +3744 -0.305419921875 +3745 -0.5533447265625 +3746 -0.30059814453125 +3747 -0.54461669921875 +3748 -0.295745849609375 +3749 -0.535797119140625 +3750 -0.29083251953125 +3751 -0.52691650390625 +3752 -0.285919189453125 +3753 -0.51800537109375 +3754 -0.28094482421875 +3755 -0.509002685546875 +3756 -0.275970458984375 +3757 -0.499969482421875 +3758 -0.27093505859375 +3759 -0.490875244140625 +3760 -0.265899658203125 +3761 -0.481719970703125 +3762 -0.26080322265625 +3763 -0.4725341796875 +3764 -0.255706787109375 +3765 -0.4632568359375 +3766 -0.25054931640625 +3767 -0.453948974609375 +3768 -0.245391845703125 +3769 -0.444610595703125 +3770 -0.240203857421875 +3771 -0.435211181640625 +3772 -0.2349853515625 +3773 -0.425750732421875 +3774 -0.229766845703125 +3775 -0.416259765625 +3776 -0.2244873046875 +3777 -0.406707763671875 +3778 -0.219207763671875 +3779 -0.397125244140625 +3780 -0.2138671875 +3781 -0.387481689453125 +3782 -0.208526611328125 +3783 -0.3778076171875 +3784 -0.20318603515625 +3785 -0.36810302734375 +3786 -0.197784423828125 +3787 -0.35833740234375 +3788 -0.1923828125 +3789 -0.348541259765625 +3790 -0.18695068359375 +3791 -0.338714599609375 +3792 -0.181488037109375 +3793 -0.328826904296875 +3794 -0.176025390625 +3795 -0.318939208984375 +3796 -0.1705322265625 +3797 -0.308990478515625 +3798 -0.1650390625 +3799 -0.29901123046875 +3800 -0.159515380859375 +3801 -0.28900146484375 +3802 -0.153961181640625 +3803 -0.278961181640625 +3804 -0.148406982421875 +3805 -0.268890380859375 +3806 -0.142822265625 +3807 -0.2587890625 +3808 -0.137237548828125 +3809 -0.2486572265625 +3810 -0.13165283203125 +3811 -0.238525390625 +3812 -0.126007080078125 +3813 -0.22833251953125 +3814 -0.120391845703125 +3815 -0.218109130859375 +3816 -0.11474609375 +3817 -0.2078857421875 +3818 -0.10906982421875 +3819 -0.1976318359375 +3820 -0.1033935546875 +3821 -0.187347412109375 +3822 -0.09771728515625 +3823 -0.17706298828125 +3824 -0.092041015625 +3825 -0.166748046875 +3826 -0.0863037109375 +3827 -0.156402587890625 +3828 -0.080596923828125 +3829 -0.14605712890625 +3830 -0.07489013671875 +3831 -0.13568115234375 +3832 -0.06915283203125 +3833 -0.12530517578125 +3834 -0.06341552734375 +3835 -0.11492919921875 +3836 -0.05767822265625 +3837 -0.104522705078125 +3838 -0.051910400390625 +3839 -0.094085693359375 +3840 -0.045989990234375 +3841 -0.083648681640625 +3842 -0.040252685546875 +3843 -0.073211669921875 +3844 -0.034515380859375 +3845 -0.062774658203125 +3846 -0.02874755859375 +3847 -0.05230712890625 +3848 -0.02301025390625 +3849 -0.0418701171875 +3850 -0.017242431640625 +3851 -0.031402587890625 +3852 -0.011505126953125 +3853 -0.02093505859375 +3854 -0.0057373046875 +3855 -0.010467529296875 +3856 0.0 +3857 0.0 +3858 0.00543212890625 +3859 0.010467529296875 +3860 0.0108642578125 +3861 0.02093505859375 +3862 0.016326904296875 +3863 0.031402587890625 +3864 0.021759033203125 +3865 0.0418701171875 +3866 0.027191162109375 +3867 0.05230712890625 +3868 0.032623291015625 +3869 0.062774658203125 +3870 0.038055419921875 +3871 0.073211669921875 +3872 0.043487548828125 +3873 0.083648681640625 +3874 0.048919677734375 +3875 0.094085693359375 +3876 0.054351806640625 +3877 0.104522705078125 +3878 0.05975341796875 +3879 0.11492919921875 +3880 0.065155029296875 +3881 0.12530517578125 +3882 0.070526123046875 +3883 0.13568115234375 +3884 0.075927734375 +3885 0.14605712890625 +3886 0.081329345703125 +3887 0.156402587890625 +3888 0.086700439453125 +3889 0.166748046875 +3890 0.092071533203125 +3891 0.17706298828125 +3892 0.097412109375 +3893 0.187347412109375 +3894 0.102752685546875 +3895 0.1976318359375 +3896 0.10809326171875 +3897 0.2078857421875 +3898 0.1134033203125 +3899 0.218109130859375 +3900 0.11871337890625 +3901 0.22833251953125 +3902 0.1240234375 +3903 0.238525390625 +3904 0.1292724609375 +3905 0.2486572265625 +3906 0.134552001953125 +3907 0.2587890625 +3908 0.139801025390625 +3909 0.268890380859375 +3910 0.145050048828125 +3911 0.278961181640625 +3912 0.1502685546875 +3913 0.28900146484375 +3914 0.155487060546875 +3915 0.29901123046875 +3916 0.160675048828125 +3917 0.308990478515625 +3918 0.16583251953125 +3919 0.318939208984375 +3920 0.170989990234375 +3921 0.328826904296875 +3922 0.176116943359375 +3923 0.338714599609375 +3924 0.18121337890625 +3925 0.348541259765625 +3926 0.186309814453125 +3927 0.35833740234375 +3928 0.19140625 +3929 0.36810302734375 +3930 0.196441650390625 +3931 0.3778076171875 +3932 0.20147705078125 +3933 0.387481689453125 +3934 0.20648193359375 +3935 0.397125244140625 +3936 0.21148681640625 +3937 0.406707763671875 +3938 0.2164306640625 +3939 0.416259765625 +3940 0.22137451171875 +3941 0.425750732421875 +3942 0.226287841796875 +3943 0.435211181640625 +3944 0.231170654296875 +3945 0.444610595703125 +3946 0.236053466796875 +3947 0.453948974609375 +3948 0.240875244140625 +3949 0.4632568359375 +3950 0.245697021484375 +3951 0.4725341796875 +3952 0.25048828125 +3953 0.481719970703125 +3954 0.2552490234375 +3955 0.490875244140625 +3956 0.259979248046875 +3957 0.499969482421875 +3958 0.264678955078125 +3959 0.509002685546875 +3960 0.26934814453125 +3961 0.51800537109375 +3962 0.27398681640625 +3963 0.52691650390625 +3964 0.278594970703125 +3965 0.535797119140625 +3966 0.283203125 +3967 0.54461669921875 +3968 0.2877197265625 +3969 0.5533447265625 +3970 0.292236328125 +3971 0.562042236328125 +3972 0.2967529296875 +3973 0.5706787109375 +3974 0.30120849609375 +3975 0.579254150390625 +3976 0.30560302734375 +3977 0.587738037109375 +3978 0.30999755859375 +3979 0.59619140625 +3980 0.314361572265625 +3981 0.60455322265625 +3982 0.318695068359375 +3983 0.612884521484375 +3984 0.322967529296875 +3985 0.621124267578125 +3986 0.32720947265625 +3987 0.6292724609375 +3988 0.3314208984375 +3989 0.63739013671875 +3990 0.335601806640625 +3991 0.645416259765625 +3992 0.339752197265625 +3993 0.65338134765625 +3994 0.343841552734375 +3995 0.661285400390625 +3996 0.347930908203125 +3997 0.669097900390625 +3998 0.351959228515625 +3999 0.676849365234375 +4000 0.355926513671875 +4001 0.68450927734375 +4002 0.359893798828125 +4003 0.692108154296875 +4004 0.363800048828125 +4005 0.699615478515625 +4006 0.367645263671875 +4007 0.707061767578125 +4008 0.371490478515625 +4009 0.714447021484375 +4010 0.375274658203125 +4011 0.721710205078125 +4012 0.3790283203125 +4013 0.72894287109375 +4014 0.382720947265625 +4015 0.736053466796875 +4016 0.38641357421875 +4017 0.74310302734375 +4018 0.3900146484375 +4019 0.75006103515625 +4020 0.39361572265625 +4021 0.7569580078125 +4022 0.39715576171875 +4023 0.763763427734375 +4024 0.400634765625 +4025 0.770477294921875 +4026 0.404083251953125 +4027 0.777099609375 +4028 0.407501220703125 +4029 0.783660888671875 +4030 0.410858154296875 +4031 0.790130615234375 +4032 0.414154052734375 +4033 0.796478271484375 +4034 0.41741943359375 +4035 0.802764892578125 +4036 0.420654296875 +4037 0.808990478515625 +4038 0.423828125 +4039 0.815093994140625 +4040 0.426971435546875 +4041 0.82110595703125 +4042 0.4300537109375 +4043 0.8270263671875 +4044 0.433074951171875 +4045 0.8328857421875 +4046 0.436065673828125 +4047 0.838623046875 +4048 0.43902587890625 +4049 0.84429931640625 +4050 0.441925048828125 +4051 0.849853515625 +4052 0.44476318359375 +4053 0.855316162109375 +4054 0.447540283203125 +4055 0.860687255859375 +4056 0.4503173828125 +4057 0.865997314453125 +4058 0.4530029296875 +4059 0.871185302734375 +4060 0.45562744140625 +4061 0.876251220703125 +4062 0.458251953125 +4063 0.881256103515625 +4064 0.460784912109375 +4065 0.88616943359375 +4066 0.463287353515625 +4067 0.890960693359375 +4068 0.465728759765625 +4069 0.895660400390625 +4070 0.4681396484375 +4071 0.9002685546875 +4072 0.470489501953125 +4073 0.90478515625 +4074 0.472747802734375 +4075 0.9091796875 +4076 0.475006103515625 +4077 0.91351318359375 +4078 0.477203369140625 +4079 0.917724609375 +4080 0.479339599609375 +4081 0.92181396484375 +4082 0.481414794921875 +4083 0.92584228515625 +4084 0.483428955078125 +4085 0.929718017578125 +4086 0.48541259765625 +4087 0.93353271484375 +4088 0.487335205078125 +4089 0.937225341796875 +4090 0.489227294921875 +4091 0.940826416015625 +4092 0.491058349609375 +4093 0.9443359375 +4094 0.4927978515625 +4095 0.947723388671875 +4096 0.464080810546875 +4097 0.951019287109375 +4098 0.46563720703125 +4099 0.954193115234375 +4100 0.467132568359375 +4101 0.957275390625 +4102 0.46856689453125 +4103 0.960235595703125 +4104 0.469970703125 +4105 0.963104248046875 +4106 0.4713134765625 +4107 0.96588134765625 +4108 0.472625732421875 +4109 0.968536376953125 +4110 0.473876953125 +4111 0.971099853515625 +4112 0.475067138671875 +4113 0.973541259765625 +4114 0.4761962890625 +4115 0.975860595703125 +4116 0.477294921875 +4117 0.97808837890625 +4118 0.47833251953125 +4119 0.980224609375 +4120 0.47930908203125 +4121 0.98223876953125 +4122 0.480255126953125 +4123 0.984161376953125 +4124 0.48114013671875 +4125 0.9859619140625 +4126 0.48193359375 +4127 0.987640380859375 +4128 0.48272705078125 +4129 0.989227294921875 +4130 0.483428955078125 +4131 0.990692138671875 +4132 0.484100341796875 +4133 0.9920654296875 +4134 0.484710693359375 +4135 0.993316650390625 +4136 0.48529052734375 +4137 0.994476318359375 +4138 0.48577880859375 +4139 0.995513916015625 +4140 0.486236572265625 +4141 0.9964599609375 +4142 0.486663818359375 +4143 0.997283935546875 +4144 0.48699951171875 +4145 0.99798583984375 +4146 0.4873046875 +4147 0.99859619140625 +4148 0.487518310546875 +4149 0.999114990234375 +4150 0.487701416015625 +4151 0.999481201171875 +4152 0.48785400390625 +4153 0.999755859375 +4154 0.487945556640625 +4155 0.99993896484375 +4156 0.48797607421875 +4157 0.999969482421875 +4158 0.487945556640625 +4159 0.99993896484375 +4160 0.48785400390625 +4161 0.999755859375 +4162 0.487701416015625 +4163 0.999481201171875 +4164 0.487518310546875 +4165 0.999114990234375 +4166 0.4873046875 +4167 0.99859619140625 +4168 0.48699951171875 +4169 0.99798583984375 +4170 0.486663818359375 +4171 0.997283935546875 +4172 0.486236572265625 +4173 0.9964599609375 +4174 0.48577880859375 +4175 0.995513916015625 +4176 0.48529052734375 +4177 0.994476318359375 +4178 0.484710693359375 +4179 0.993316650390625 +4180 0.484100341796875 +4181 0.9920654296875 +4182 0.483428955078125 +4183 0.990692138671875 +4184 0.48272705078125 +4185 0.989227294921875 +4186 0.48193359375 +4187 0.987640380859375 +4188 0.48114013671875 +4189 0.9859619140625 +4190 0.480255126953125 +4191 0.984161376953125 +4192 0.47930908203125 +4193 0.98223876953125 +4194 0.47833251953125 +4195 0.980224609375 +4196 0.477294921875 +4197 0.97808837890625 +4198 0.4761962890625 +4199 0.975860595703125 +4200 0.475067138671875 +4201 0.973541259765625 +4202 0.473876953125 +4203 0.971099853515625 +4204 0.472625732421875 +4205 0.968536376953125 +4206 0.4713134765625 +4207 0.96588134765625 +4208 0.469970703125 +4209 0.963104248046875 +4210 0.46856689453125 +4211 0.960235595703125 +4212 0.467132568359375 +4213 0.957275390625 +4214 0.46563720703125 +4215 0.954193115234375 +4216 0.464080810546875 +4217 0.951019287109375 +4218 0.46246337890625 +4219 0.947723388671875 +4220 0.4608154296875 +4221 0.9443359375 +4222 0.4591064453125 +4223 0.940826416015625 +4224 0.45733642578125 +4225 0.937225341796875 +4226 0.455535888671875 +4227 0.93353271484375 +4228 0.45367431640625 +4229 0.929718017578125 +4230 0.4517822265625 +4231 0.92584228515625 +4232 0.4498291015625 +4233 0.92181396484375 +4234 0.44781494140625 +4235 0.917724609375 +4236 0.445770263671875 +4237 0.91351318359375 +4238 0.44366455078125 +4239 0.9091796875 +4240 0.441497802734375 +4241 0.90478515625 +4242 0.439300537109375 +4243 0.9002685546875 +4244 0.43707275390625 +4245 0.895660400390625 +4246 0.43475341796875 +4247 0.890960693359375 +4248 0.43243408203125 +4249 0.88616943359375 +4250 0.430023193359375 +4251 0.881256103515625 +4252 0.427581787109375 +4253 0.876251220703125 +4254 0.42510986328125 +4255 0.871185302734375 +4256 0.422576904296875 +4257 0.865997314453125 +4258 0.41998291015625 +4259 0.860687255859375 +4260 0.4173583984375 +4261 0.855316162109375 +4262 0.414703369140625 +4263 0.849853515625 +4264 0.4119873046875 +4265 0.84429931640625 +4266 0.409210205078125 +4267 0.838623046875 +4268 0.40643310546875 +4269 0.8328857421875 +4270 0.403564453125 +4271 0.8270263671875 +4272 0.400665283203125 +4273 0.82110595703125 +4274 0.397735595703125 +4275 0.815093994140625 +4276 0.394775390625 +4277 0.808990478515625 +4278 0.3917236328125 +4279 0.802764892578125 +4280 0.388671875 +4281 0.796478271484375 +4282 0.38555908203125 +4283 0.790130615234375 +4284 0.382415771484375 +4285 0.783660888671875 +4286 0.37921142578125 +4287 0.777099609375 +4288 0.3759765625 +4289 0.770477294921875 +4290 0.3726806640625 +4291 0.763763427734375 +4292 0.369384765625 +4293 0.7569580078125 +4294 0.365997314453125 +4295 0.75006103515625 +4296 0.36260986328125 +4297 0.74310302734375 +4298 0.359161376953125 +4299 0.736053466796875 +4300 0.355712890625 +4301 0.72894287109375 +4302 0.3521728515625 +4303 0.721710205078125 +4304 0.3486328125 +4305 0.714447021484375 +4306 0.34503173828125 +4307 0.707061767578125 +4308 0.341400146484375 +4309 0.699615478515625 +4310 0.337738037109375 +4311 0.692108154296875 +4312 0.334014892578125 +4313 0.68450927734375 +4314 0.330291748046875 +4315 0.676849365234375 +4316 0.326507568359375 +4317 0.669097900390625 +4318 0.32269287109375 +4319 0.661285400390625 +4320 0.318817138671875 +4321 0.65338134765625 +4322 0.31494140625 +4323 0.645416259765625 +4324 0.31103515625 +4325 0.63739013671875 +4326 0.30706787109375 +4327 0.6292724609375 +4328 0.3031005859375 +4329 0.621124267578125 +4330 0.299072265625 +4331 0.612884521484375 +4332 0.295013427734375 +4333 0.60455322265625 +4334 0.290924072265625 +4335 0.59619140625 +4336 0.28680419921875 +4337 0.587738037109375 +4338 0.28265380859375 +4339 0.579254150390625 +4340 0.278472900390625 +4341 0.5706787109375 +4342 0.274261474609375 +4343 0.562042236328125 +4344 0.27001953125 +4345 0.5533447265625 +4346 0.2657470703125 +4347 0.54461669921875 +4348 0.261444091796875 +4349 0.535797119140625 +4350 0.257110595703125 +4351 0.52691650390625 +4352 0.2362060546875 +4353 0.51800537109375 +4354 0.232086181640625 +4355 0.509002685546875 +4356 0.22796630859375 +4357 0.499969482421875 +4358 0.22381591796875 +4359 0.490875244140625 +4360 0.21966552734375 +4361 0.481719970703125 +4362 0.2154541015625 +4363 0.4725341796875 +4364 0.21124267578125 +4365 0.4632568359375 +4366 0.207000732421875 +4367 0.453948974609375 +4368 0.202728271484375 +4369 0.444610595703125 +4370 0.198455810546875 +4371 0.435211181640625 +4372 0.194122314453125 +4373 0.425750732421875 +4374 0.189788818359375 +4375 0.416259765625 +4376 0.185455322265625 +4377 0.406707763671875 +4378 0.18109130859375 +4379 0.397125244140625 +4380 0.176666259765625 +4381 0.387481689453125 +4382 0.172271728515625 +4383 0.3778076171875 +4384 0.1678466796875 +4385 0.36810302734375 +4386 0.16339111328125 +4387 0.35833740234375 +4388 0.158935546875 +4389 0.348541259765625 +4390 0.154449462890625 +4391 0.338714599609375 +4392 0.149932861328125 +4393 0.328826904296875 +4394 0.145416259765625 +4395 0.318939208984375 +4396 0.140899658203125 +4397 0.308990478515625 +4398 0.136322021484375 +4399 0.29901123046875 +4400 0.13177490234375 +4401 0.28900146484375 +4402 0.127197265625 +4403 0.278961181640625 +4404 0.122589111328125 +4405 0.268890380859375 +4406 0.11798095703125 +4407 0.2587890625 +4408 0.113372802734375 +4409 0.2486572265625 +4410 0.1087646484375 +4411 0.238525390625 +4412 0.104095458984375 +4413 0.22833251953125 +4414 0.099456787109375 +4415 0.218109130859375 +4416 0.09478759765625 +4417 0.2078857421875 +4418 0.090118408203125 +4419 0.1976318359375 +4420 0.085418701171875 +4421 0.187347412109375 +4422 0.080718994140625 +4423 0.17706298828125 +4424 0.076019287109375 +4425 0.166748046875 +4426 0.071319580078125 +4427 0.156402587890625 +4428 0.06658935546875 +4429 0.14605712890625 +4430 0.061859130859375 +4431 0.13568115234375 +4432 0.05712890625 +4433 0.12530517578125 +4434 0.052398681640625 +4435 0.11492919921875 +4436 0.047637939453125 +4437 0.104522705078125 +4438 0.042877197265625 +4439 0.094085693359375 +4440 0.038116455078125 +4441 0.083648681640625 +4442 0.033355712890625 +4443 0.073211669921875 +4444 0.02862548828125 +4445 0.062774658203125 +4446 0.023834228515625 +4447 0.05230712890625 +4448 0.019073486328125 +4449 0.0418701171875 +4450 0.014312744140625 +4451 0.031402587890625 +4452 0.009521484375 +4453 0.02093505859375 +4454 0.0047607421875 +4455 0.010467529296875 +4456 0.0 +4457 0.0 +4458 -0.0047607421875 +4459 -0.010467529296875 +4460 -0.009521484375 +4461 -0.02093505859375 +4462 -0.014312744140625 +4463 -0.031402587890625 +4464 -0.019073486328125 +4465 -0.0418701171875 +4466 -0.023834228515625 +4467 -0.05230712890625 +4468 -0.02862548828125 +4469 -0.062774658203125 +4470 -0.033355712890625 +4471 -0.073211669921875 +4472 -0.038116455078125 +4473 -0.083648681640625 +4474 -0.042877197265625 +4475 -0.094085693359375 +4476 -0.047637939453125 +4477 -0.104522705078125 +4478 -0.052398681640625 +4479 -0.11492919921875 +4480 -0.05712890625 +4481 -0.12530517578125 +4482 -0.061859130859375 +4483 -0.13568115234375 +4484 -0.06658935546875 +4485 -0.14605712890625 +4486 -0.071319580078125 +4487 -0.156402587890625 +4488 -0.076019287109375 +4489 -0.166748046875 +4490 -0.080718994140625 +4491 -0.17706298828125 +4492 -0.085418701171875 +4493 -0.187347412109375 +4494 -0.090118408203125 +4495 -0.1976318359375 +4496 -0.09478759765625 +4497 -0.2078857421875 +4498 -0.099456787109375 +4499 -0.218109130859375 +4500 -0.104095458984375 +4501 -0.22833251953125 +4502 -0.1087646484375 +4503 -0.238525390625 +4504 -0.113372802734375 +4505 -0.2486572265625 +4506 -0.11798095703125 +4507 -0.2587890625 +4508 -0.122589111328125 +4509 -0.268890380859375 +4510 -0.127197265625 +4511 -0.278961181640625 +4512 -0.13177490234375 +4513 -0.28900146484375 +4514 -0.136322021484375 +4515 -0.29901123046875 +4516 -0.140899658203125 +4517 -0.308990478515625 +4518 -0.145416259765625 +4519 -0.318939208984375 +4520 -0.149932861328125 +4521 -0.328826904296875 +4522 -0.154449462890625 +4523 -0.338714599609375 +4524 -0.158935546875 +4525 -0.348541259765625 +4526 -0.16339111328125 +4527 -0.35833740234375 +4528 -0.1678466796875 +4529 -0.36810302734375 +4530 -0.172271728515625 +4531 -0.3778076171875 +4532 -0.176666259765625 +4533 -0.387481689453125 +4534 -0.18109130859375 +4535 -0.397125244140625 +4536 -0.185455322265625 +4537 -0.406707763671875 +4538 -0.189788818359375 +4539 -0.416259765625 +4540 -0.194122314453125 +4541 -0.425750732421875 +4542 -0.198455810546875 +4543 -0.435211181640625 +4544 -0.202728271484375 +4545 -0.444610595703125 +4546 -0.207000732421875 +4547 -0.453948974609375 +4548 -0.21124267578125 +4549 -0.4632568359375 +4550 -0.2154541015625 +4551 -0.4725341796875 +4552 -0.21966552734375 +4553 -0.481719970703125 +4554 -0.22381591796875 +4555 -0.490875244140625 +4556 -0.22796630859375 +4557 -0.499969482421875 +4558 -0.232086181640625 +4559 -0.509002685546875 +4560 -0.2362060546875 +4561 -0.51800537109375 +4562 -0.240264892578125 +4563 -0.52691650390625 +4564 -0.24432373046875 +4565 -0.535797119140625 +4566 -0.248321533203125 +4567 -0.54461669921875 +4568 -0.2523193359375 +4569 -0.5533447265625 +4570 -0.25628662109375 +4571 -0.562042236328125 +4572 -0.260223388671875 +4573 -0.5706787109375 +4574 -0.264129638671875 +4575 -0.579254150390625 +4576 -0.26800537109375 +4577 -0.587738037109375 +4578 -0.2718505859375 +4579 -0.59619140625 +4580 -0.275665283203125 +4581 -0.60455322265625 +4582 -0.27947998046875 +4583 -0.612884521484375 +4584 -0.283233642578125 +4585 -0.621124267578125 +4586 -0.28692626953125 +4587 -0.6292724609375 +4588 -0.2906494140625 +4589 -0.63739013671875 +4590 -0.2943115234375 +4591 -0.645416259765625 +4592 -0.297943115234375 +4593 -0.65338134765625 +4594 -0.301544189453125 +4595 -0.661285400390625 +4596 -0.305084228515625 +4597 -0.669097900390625 +4598 -0.308624267578125 +4599 -0.676849365234375 +4600 -0.3121337890625 +4601 -0.68450927734375 +4602 -0.315582275390625 +4603 -0.692108154296875 +4604 -0.319000244140625 +4605 -0.699615478515625 +4606 -0.322418212890625 +4607 -0.707061767578125 +4608 -0.30291748046875 +4609 -0.714447021484375 +4610 -0.305999755859375 +4611 -0.721710205078125 +4612 -0.309051513671875 +4613 -0.72894287109375 +4614 -0.31207275390625 +4615 -0.736053466796875 +4616 -0.3150634765625 +4617 -0.74310302734375 +4618 -0.3179931640625 +4619 -0.75006103515625 +4620 -0.3209228515625 +4621 -0.7569580078125 +4622 -0.323822021484375 +4623 -0.763763427734375 +4624 -0.32666015625 +4625 -0.770477294921875 +4626 -0.3294677734375 +4627 -0.777099609375 +4628 -0.332244873046875 +4629 -0.783660888671875 +4630 -0.334991455078125 +4631 -0.790130615234375 +4632 -0.337677001953125 +4633 -0.796478271484375 +4634 -0.340362548828125 +4635 -0.802764892578125 +4636 -0.342987060546875 +4637 -0.808990478515625 +4638 -0.3455810546875 +4639 -0.815093994140625 +4640 -0.348114013671875 +4641 -0.82110595703125 +4642 -0.35064697265625 +4643 -0.8270263671875 +4644 -0.353118896484375 +4645 -0.8328857421875 +4646 -0.355560302734375 +4647 -0.838623046875 +4648 -0.35797119140625 +4649 -0.84429931640625 +4650 -0.360321044921875 +4651 -0.849853515625 +4652 -0.362640380859375 +4653 -0.855316162109375 +4654 -0.364898681640625 +4655 -0.860687255859375 +4656 -0.367156982421875 +4657 -0.865997314453125 +4658 -0.369354248046875 +4659 -0.871185302734375 +4660 -0.37152099609375 +4661 -0.876251220703125 +4662 -0.373626708984375 +4663 -0.881256103515625 +4664 -0.375701904296875 +4665 -0.88616943359375 +4666 -0.37774658203125 +4667 -0.890960693359375 +4668 -0.379730224609375 +4669 -0.895660400390625 +4670 -0.381683349609375 +4671 -0.9002685546875 +4672 -0.38360595703125 +4673 -0.90478515625 +4674 -0.385467529296875 +4675 -0.9091796875 +4676 -0.387298583984375 +4677 -0.91351318359375 +4678 -0.38909912109375 +4679 -0.917724609375 +4680 -0.390838623046875 +4681 -0.92181396484375 +4682 -0.392547607421875 +4683 -0.92584228515625 +4684 -0.3941650390625 +4685 -0.929718017578125 +4686 -0.395782470703125 +4687 -0.93353271484375 +4688 -0.397369384765625 +4689 -0.937225341796875 +4690 -0.398895263671875 +4691 -0.940826416015625 +4692 -0.400390625 +4693 -0.9443359375 +4694 -0.401824951171875 +4695 -0.947723388671875 +4696 -0.4031982421875 +4697 -0.951019287109375 +4698 -0.404571533203125 +4699 -0.954193115234375 +4700 -0.405853271484375 +4701 -0.957275390625 +4702 -0.4071044921875 +4703 -0.960235595703125 +4704 -0.4083251953125 +4705 -0.963104248046875 +4706 -0.409515380859375 +4707 -0.96588134765625 +4708 -0.41064453125 +4709 -0.968536376953125 +4710 -0.411712646484375 +4711 -0.971099853515625 +4712 -0.412750244140625 +4713 -0.973541259765625 +4714 -0.41375732421875 +4715 -0.975860595703125 +4716 -0.4146728515625 +4717 -0.97808837890625 +4718 -0.41558837890625 +4719 -0.980224609375 +4720 -0.41644287109375 +4721 -0.98223876953125 +4722 -0.417266845703125 +4723 -0.984161376953125 +4724 -0.41802978515625 +4725 -0.9859619140625 +4726 -0.418731689453125 +4727 -0.987640380859375 +4728 -0.419403076171875 +4729 -0.989227294921875 +4730 -0.4200439453125 +4731 -0.990692138671875 +4732 -0.420623779296875 +4733 -0.9920654296875 +4734 -0.421142578125 +4735 -0.993316650390625 +4736 -0.421630859375 +4737 -0.994476318359375 +4738 -0.422088623046875 +4739 -0.995513916015625 +4740 -0.4224853515625 +4741 -0.9964599609375 +4742 -0.422821044921875 +4743 -0.997283935546875 +4744 -0.423126220703125 +4745 -0.99798583984375 +4746 -0.423370361328125 +4747 -0.99859619140625 +4748 -0.423583984375 +4749 -0.999114990234375 +4750 -0.423736572265625 +4751 -0.999481201171875 +4752 -0.423858642578125 +4753 -0.999755859375 +4754 -0.4239501953125 +4755 -0.99993896484375 +4756 -0.423980712890625 +4757 -1.0 +4758 -0.4239501953125 +4759 -0.99993896484375 +4760 -0.423858642578125 +4761 -0.999755859375 +4762 -0.423736572265625 +4763 -0.999481201171875 +4764 -0.423583984375 +4765 -0.999114990234375 +4766 -0.423370361328125 +4767 -0.99859619140625 +4768 -0.423126220703125 +4769 -0.99798583984375 +4770 -0.422821044921875 +4771 -0.997283935546875 +4772 -0.4224853515625 +4773 -0.9964599609375 +4774 -0.422088623046875 +4775 -0.995513916015625 +4776 -0.421630859375 +4777 -0.994476318359375 +4778 -0.421142578125 +4779 -0.993316650390625 +4780 -0.420623779296875 +4781 -0.9920654296875 +4782 -0.4200439453125 +4783 -0.990692138671875 +4784 -0.419403076171875 +4785 -0.989227294921875 +4786 -0.418731689453125 +4787 -0.987640380859375 +4788 -0.41802978515625 +4789 -0.9859619140625 +4790 -0.417266845703125 +4791 -0.984161376953125 +4792 -0.41644287109375 +4793 -0.98223876953125 +4794 -0.41558837890625 +4795 -0.980224609375 +4796 -0.4146728515625 +4797 -0.97808837890625 +4798 -0.41375732421875 +4799 -0.975860595703125 +4800 -0.412750244140625 +4801 -0.973541259765625 +4802 -0.411712646484375 +4803 -0.971099853515625 +4804 -0.41064453125 +4805 -0.968536376953125 +4806 -0.409515380859375 +4807 -0.96588134765625 +4808 -0.4083251953125 +4809 -0.963104248046875 +4810 -0.4071044921875 +4811 -0.960235595703125 +4812 -0.405853271484375 +4813 -0.957275390625 +4814 -0.404571533203125 +4815 -0.954193115234375 +4816 -0.4031982421875 +4817 -0.951019287109375 +4818 -0.401824951171875 +4819 -0.947723388671875 +4820 -0.400390625 +4821 -0.9443359375 +4822 -0.398895263671875 +4823 -0.940826416015625 +4824 -0.397369384765625 +4825 -0.937225341796875 +4826 -0.395782470703125 +4827 -0.93353271484375 +4828 -0.3941650390625 +4829 -0.929718017578125 +4830 -0.392547607421875 +4831 -0.92584228515625 +4832 -0.390838623046875 +4833 -0.92181396484375 +4834 -0.38909912109375 +4835 -0.917724609375 +4836 -0.387298583984375 +4837 -0.91351318359375 +4838 -0.385467529296875 +4839 -0.9091796875 +4840 -0.38360595703125 +4841 -0.90478515625 +4842 -0.381683349609375 +4843 -0.9002685546875 +4844 -0.379730224609375 +4845 -0.895660400390625 +4846 -0.37774658203125 +4847 -0.890960693359375 +4848 -0.375701904296875 +4849 -0.88616943359375 +4850 -0.373626708984375 +4851 -0.881256103515625 +4852 -0.37152099609375 +4853 -0.876251220703125 +4854 -0.369354248046875 +4855 -0.871185302734375 +4856 -0.367156982421875 +4857 -0.865997314453125 +4858 -0.364898681640625 +4859 -0.860687255859375 +4860 -0.362640380859375 +4861 -0.855316162109375 +4862 -0.360321044921875 +4863 -0.849853515625 +4864 -0.33770751953125 +4865 -0.84429931640625 +4866 -0.33544921875 +4867 -0.838623046875 +4868 -0.3331298828125 +4869 -0.8328857421875 +4870 -0.330810546875 +4871 -0.8270263671875 +4872 -0.32843017578125 +4873 -0.82110595703125 +4874 -0.326019287109375 +4875 -0.815093994140625 +4876 -0.323577880859375 +4877 -0.808990478515625 +4878 -0.32110595703125 +4879 -0.802764892578125 +4880 -0.318572998046875 +4881 -0.796478271484375 +4882 -0.3160400390625 +4883 -0.790130615234375 +4884 -0.313446044921875 +4885 -0.783660888671875 +4886 -0.310821533203125 +4887 -0.777099609375 +4888 -0.30816650390625 +4889 -0.770477294921875 +4890 -0.30548095703125 +4891 -0.763763427734375 +4892 -0.302764892578125 +4893 -0.7569580078125 +4894 -0.300018310546875 +4895 -0.75006103515625 +4896 -0.2972412109375 +4897 -0.74310302734375 +4898 -0.294403076171875 +4899 -0.736053466796875 +4900 -0.29156494140625 +4901 -0.72894287109375 +4902 -0.288665771484375 +4903 -0.721710205078125 +4904 -0.2857666015625 +4905 -0.714447021484375 +4906 -0.282806396484375 +4907 -0.707061767578125 +4908 -0.27984619140625 +4909 -0.699615478515625 +4910 -0.276824951171875 +4911 -0.692108154296875 +4912 -0.2738037109375 +4913 -0.68450927734375 +4914 -0.270721435546875 +4915 -0.676849365234375 +4916 -0.26763916015625 +4917 -0.669097900390625 +4918 -0.264495849609375 +4919 -0.661285400390625 +4920 -0.2613525390625 +4921 -0.65338134765625 +4922 -0.258148193359375 +4923 -0.645416259765625 +4924 -0.25494384765625 +4925 -0.63739013671875 +4926 -0.251708984375 +4927 -0.6292724609375 +4928 -0.248443603515625 +4929 -0.621124267578125 +4930 -0.245147705078125 +4931 -0.612884521484375 +4932 -0.2418212890625 +4933 -0.60455322265625 +4934 -0.23846435546875 +4935 -0.59619140625 +4936 -0.235076904296875 +4937 -0.587738037109375 +4938 -0.231689453125 +4939 -0.579254150390625 +4940 -0.228271484375 +4941 -0.5706787109375 +4942 -0.22479248046875 +4943 -0.562042236328125 +4944 -0.2213134765625 +4945 -0.5533447265625 +4946 -0.21783447265625 +4947 -0.54461669921875 +4948 -0.21429443359375 +4949 -0.535797119140625 +4950 -0.21075439453125 +4951 -0.52691650390625 +4952 -0.207183837890625 +4953 -0.51800537109375 +4954 -0.203582763671875 +4955 -0.509002685546875 +4956 -0.199981689453125 +4957 -0.499969482421875 +4958 -0.19635009765625 +4959 -0.490875244140625 +4960 -0.19268798828125 +4961 -0.481719970703125 +4962 -0.188995361328125 +4963 -0.4725341796875 +4964 -0.185302734375 +4965 -0.4632568359375 +4966 -0.18157958984375 +4967 -0.453948974609375 +4968 -0.177825927734375 +4969 -0.444610595703125 +4970 -0.174072265625 +4971 -0.435211181640625 +4972 -0.1702880859375 +4973 -0.425750732421875 +4974 -0.16650390625 +4975 -0.416259765625 +4976 -0.16265869140625 +4977 -0.406707763671875 +4978 -0.158843994140625 +4979 -0.397125244140625 +4980 -0.15496826171875 +4981 -0.387481689453125 +4982 -0.151123046875 +4983 -0.3778076171875 +4984 -0.147216796875 +4985 -0.36810302734375 +4986 -0.143310546875 +4987 -0.35833740234375 +4988 -0.139404296875 +4989 -0.348541259765625 +4990 -0.135467529296875 +4991 -0.338714599609375 +4992 -0.13153076171875 +4993 -0.328826904296875 +4994 -0.1275634765625 +4995 -0.318939208984375 +4996 -0.12359619140625 +4997 -0.308990478515625 +4998 -0.119598388671875 +4999 -0.29901123046875 +5000 -0.1156005859375 +5001 -0.28900146484375 +5002 -0.111572265625 +5003 -0.278961181640625 +5004 -0.1075439453125 +5005 -0.268890380859375 +5006 -0.103515625 +5007 -0.2587890625 +5008 -0.099456787109375 +5009 -0.2486572265625 +5010 -0.09539794921875 +5011 -0.238525390625 +5012 -0.09130859375 +5013 -0.22833251953125 +5014 -0.08721923828125 +5015 -0.218109130859375 +5016 -0.0831298828125 +5017 -0.2078857421875 +5018 -0.07904052734375 +5019 -0.1976318359375 +5020 -0.074920654296875 +5021 -0.187347412109375 +5022 -0.07080078125 +5023 -0.17706298828125 +5024 -0.066680908203125 +5025 -0.166748046875 +5026 -0.06256103515625 +5027 -0.156402587890625 +5028 -0.05841064453125 +5029 -0.14605712890625 +5030 -0.05426025390625 +5031 -0.13568115234375 +5032 -0.05010986328125 +5033 -0.12530517578125 +5034 -0.04595947265625 +5035 -0.11492919921875 +5036 -0.04180908203125 +5037 -0.104522705078125 +5038 -0.037628173828125 +5039 -0.094085693359375 +5040 -0.033447265625 +5041 -0.083648681640625 +5042 -0.029266357421875 +5043 -0.073211669921875 +5044 -0.02508544921875 +5045 -0.062774658203125 +5046 -0.020904541015625 +5047 -0.05230712890625 +5048 -0.0167236328125 +5049 -0.0418701171875 +5050 -0.012542724609375 +5051 -0.031402587890625 +5052 -0.00836181640625 +5053 -0.02093505859375 +5054 -0.004180908203125 +5055 -0.010467529296875 +5056 0.0 +5057 0.0 +5058 0.00408935546875 +5059 0.010467529296875 +5060 0.0081787109375 +5061 0.02093505859375 +5062 0.012298583984375 +5063 0.031402587890625 +5064 0.016387939453125 +5065 0.0418701171875 +5066 0.020477294921875 +5067 0.05230712890625 +5068 0.02459716796875 +5069 0.062774658203125 +5070 0.0286865234375 +5071 0.073211669921875 +5072 0.03277587890625 +5073 0.083648681640625 +5074 0.036865234375 +5075 0.094085693359375 +5076 0.04095458984375 +5077 0.104522705078125 +5078 0.0450439453125 +5079 0.11492919921875 +5080 0.049102783203125 +5081 0.12530517578125 +5082 0.05316162109375 +5083 0.13568115234375 +5084 0.0572509765625 +5085 0.14605712890625 +5086 0.061309814453125 +5087 0.156402587890625 +5088 0.065338134765625 +5089 0.166748046875 +5090 0.06939697265625 +5091 0.17706298828125 +5092 0.07342529296875 +5093 0.187347412109375 +5094 0.07745361328125 +5095 0.1976318359375 +5096 0.08148193359375 +5097 0.2078857421875 +5098 0.085479736328125 +5099 0.218109130859375 +5100 0.089508056640625 +5101 0.22833251953125 +5102 0.093475341796875 +5103 0.238525390625 +5104 0.09747314453125 +5105 0.2486572265625 +5106 0.1014404296875 +5107 0.2587890625 +5108 0.10540771484375 +5109 0.268890380859375 +5110 0.109344482421875 +5111 0.278961181640625 +5112 0.11328125 +5113 0.28900146484375 +5114 0.1171875 +5115 0.29901123046875 +5116 0.121124267578125 +5117 0.308990478515625 +5118 0.125 +5119 0.318939208984375 +5120 0.11834716796875 +5121 0.328826904296875 +5122 0.121917724609375 +5123 0.338714599609375 +5124 0.125457763671875 +5125 0.348541259765625 +5126 0.128997802734375 +5127 0.35833740234375 +5128 0.13250732421875 +5129 0.36810302734375 +5130 0.135986328125 +5131 0.3778076171875 +5132 0.13946533203125 +5133 0.387481689453125 +5134 0.1429443359375 +5135 0.397125244140625 +5136 0.146392822265625 +5137 0.406707763671875 +5138 0.14984130859375 +5139 0.416259765625 +5140 0.15325927734375 +5141 0.425750732421875 +5142 0.156646728515625 +5143 0.435211181640625 +5144 0.1600341796875 +5145 0.444610595703125 +5146 0.16339111328125 +5147 0.453948974609375 +5148 0.166748046875 +5149 0.4632568359375 +5150 0.17010498046875 +5151 0.4725341796875 +5152 0.17340087890625 +5153 0.481719970703125 +5154 0.17669677734375 +5155 0.490875244140625 +5156 0.179962158203125 +5157 0.499969482421875 +5158 0.1832275390625 +5159 0.509002685546875 +5160 0.18646240234375 +5161 0.51800537109375 +5162 0.189666748046875 +5163 0.52691650390625 +5164 0.19287109375 +5165 0.535797119140625 +5166 0.196044921875 +5167 0.54461669921875 +5168 0.199188232421875 +5169 0.5533447265625 +5170 0.20233154296875 +5171 0.562042236328125 +5172 0.205413818359375 +5173 0.5706787109375 +5174 0.208526611328125 +5175 0.579254150390625 +5176 0.211578369140625 +5177 0.587738037109375 +5178 0.214599609375 +5179 0.59619140625 +5180 0.217620849609375 +5181 0.60455322265625 +5182 0.220611572265625 +5183 0.612884521484375 +5184 0.223602294921875 +5185 0.621124267578125 +5186 0.226531982421875 +5187 0.6292724609375 +5188 0.22943115234375 +5189 0.63739013671875 +5190 0.232330322265625 +5191 0.645416259765625 +5192 0.235198974609375 +5193 0.65338134765625 +5194 0.238037109375 +5195 0.661285400390625 +5196 0.2408447265625 +5197 0.669097900390625 +5198 0.24365234375 +5199 0.676849365234375 +5200 0.24639892578125 +5201 0.68450927734375 +5202 0.2491455078125 +5203 0.692108154296875 +5204 0.2518310546875 +5205 0.699615478515625 +5206 0.2545166015625 +5207 0.707061767578125 +5208 0.257171630859375 +5209 0.714447021484375 +5210 0.259796142578125 +5211 0.721710205078125 +5212 0.26239013671875 +5213 0.72894287109375 +5214 0.26495361328125 +5215 0.736053466796875 +5216 0.267486572265625 +5217 0.74310302734375 +5218 0.269989013671875 +5219 0.75006103515625 +5220 0.272491455078125 +5221 0.7569580078125 +5222 0.274932861328125 +5223 0.763763427734375 +5224 0.27734375 +5225 0.770477294921875 +5226 0.27972412109375 +5227 0.777099609375 +5228 0.2821044921875 +5229 0.783660888671875 +5230 0.284423828125 +5231 0.790130615234375 +5232 0.286712646484375 +5233 0.796478271484375 +5234 0.288970947265625 +5235 0.802764892578125 +5236 0.291229248046875 +5237 0.808990478515625 +5238 0.293426513671875 +5239 0.815093994140625 +5240 0.29559326171875 +5241 0.82110595703125 +5242 0.297698974609375 +5243 0.8270263671875 +5244 0.299835205078125 +5245 0.8328857421875 +5246 0.3018798828125 +5247 0.838623046875 +5248 0.303924560546875 +5249 0.84429931640625 +5250 0.305938720703125 +5251 0.849853515625 +5252 0.307891845703125 +5253 0.855316162109375 +5254 0.309814453125 +5255 0.860687255859375 +5256 0.311737060546875 +5257 0.865997314453125 +5258 0.3135986328125 +5259 0.871185302734375 +5260 0.3154296875 +5261 0.876251220703125 +5262 0.317230224609375 +5263 0.881256103515625 +5264 0.319000244140625 +5265 0.88616943359375 +5266 0.32073974609375 +5267 0.890960693359375 +5268 0.322418212890625 +5269 0.895660400390625 +5270 0.324066162109375 +5271 0.9002685546875 +5272 0.325714111328125 +5273 0.90478515625 +5274 0.327301025390625 +5275 0.9091796875 +5276 0.328857421875 +5277 0.91351318359375 +5278 0.330352783203125 +5279 0.917724609375 +5280 0.33184814453125 +5281 0.92181396484375 +5282 0.333282470703125 +5283 0.92584228515625 +5284 0.334686279296875 +5285 0.929718017578125 +5286 0.3360595703125 +5287 0.93353271484375 +5288 0.337371826171875 +5289 0.937225341796875 +5290 0.33868408203125 +5291 0.940826416015625 +5292 0.339935302734375 +5293 0.9443359375 +5294 0.341156005859375 +5295 0.947723388671875 +5296 0.34234619140625 +5297 0.951019287109375 +5298 0.343505859375 +5299 0.954193115234375 +5300 0.3446044921875 +5301 0.957275390625 +5302 0.345672607421875 +5303 0.960235595703125 +5304 0.346710205078125 +5305 0.963104248046875 +5306 0.347686767578125 +5307 0.96588134765625 +5308 0.348663330078125 +5309 0.968536376953125 +5310 0.349578857421875 +5311 0.971099853515625 +5312 0.3504638671875 +5313 0.973541259765625 +5314 0.351287841796875 +5315 0.975860595703125 +5316 0.352081298828125 +5317 0.97808837890625 +5318 0.352874755859375 +5319 0.980224609375 +5320 0.35357666015625 +5321 0.98223876953125 +5322 0.354278564453125 +5323 0.984161376953125 +5324 0.35491943359375 +5325 0.9859619140625 +5326 0.35552978515625 +5327 0.987640380859375 +5328 0.356109619140625 +5329 0.989227294921875 +5330 0.35662841796875 +5331 0.990692138671875 +5332 0.35711669921875 +5333 0.9920654296875 +5334 0.357574462890625 +5335 0.993316650390625 +5336 0.358001708984375 +5337 0.994476318359375 +5338 0.358367919921875 +5339 0.995513916015625 +5340 0.35870361328125 +5341 0.9964599609375 +5342 0.3590087890625 +5343 0.997283935546875 +5344 0.3592529296875 +5345 0.99798583984375 +5346 0.359466552734375 +5347 0.99859619140625 +5348 0.359649658203125 +5349 0.999114990234375 +5350 0.359771728515625 +5351 0.999481201171875 +5352 0.359893798828125 +5353 0.999755859375 +5354 0.359954833984375 +5355 0.99993896484375 +5356 0.3599853515625 +5357 0.999969482421875 +5358 0.359954833984375 +5359 0.99993896484375 +5360 0.359893798828125 +5361 0.999755859375 +5362 0.359771728515625 +5363 0.999481201171875 +5364 0.359649658203125 +5365 0.999114990234375 +5366 0.359466552734375 +5367 0.99859619140625 +5368 0.3592529296875 +5369 0.99798583984375 +5370 0.3590087890625 +5371 0.997283935546875 +5372 0.35870361328125 +5373 0.9964599609375 +5374 0.358367919921875 +5375 0.995513916015625 +5376 0.326171875 +5377 0.994476318359375 +5378 0.3258056640625 +5379 0.993316650390625 +5380 0.325408935546875 +5381 0.9920654296875 +5382 0.324951171875 +5383 0.990692138671875 +5384 0.324462890625 +5385 0.989227294921875 +5386 0.323944091796875 +5387 0.987640380859375 +5388 0.323394775390625 +5389 0.9859619140625 +5390 0.32281494140625 +5391 0.984161376953125 +5392 0.322174072265625 +5393 0.98223876953125 +5394 0.321502685546875 +5395 0.980224609375 +5396 0.32080078125 +5397 0.97808837890625 +5398 0.320068359375 +5399 0.975860595703125 +5400 0.319305419921875 +5401 0.973541259765625 +5402 0.318511962890625 +5403 0.971099853515625 +5404 0.31768798828125 +5405 0.968536376953125 +5406 0.316802978515625 +5407 0.96588134765625 +5408 0.315887451171875 +5409 0.963104248046875 +5410 0.31494140625 +5411 0.960235595703125 +5412 0.313995361328125 +5413 0.957275390625 +5414 0.312957763671875 +5415 0.954193115234375 +5416 0.311920166015625 +5417 0.951019287109375 +5418 0.31085205078125 +5419 0.947723388671875 +5420 0.30975341796875 +5421 0.9443359375 +5422 0.30859375 +5423 0.940826416015625 +5424 0.307403564453125 +5425 0.937225341796875 +5426 0.306182861328125 +5427 0.93353271484375 +5428 0.304931640625 +5429 0.929718017578125 +5430 0.303680419921875 +5431 0.92584228515625 +5432 0.302337646484375 +5433 0.92181396484375 +5434 0.301025390625 +5435 0.917724609375 +5436 0.29962158203125 +5437 0.91351318359375 +5438 0.2982177734375 +5439 0.9091796875 +5440 0.2967529296875 +5441 0.90478515625 +5442 0.2952880859375 +5443 0.9002685546875 +5444 0.29376220703125 +5445 0.895660400390625 +5446 0.292236328125 +5447 0.890960693359375 +5448 0.2906494140625 +5449 0.88616943359375 +5450 0.2890625 +5451 0.881256103515625 +5452 0.28741455078125 +5453 0.876251220703125 +5454 0.285736083984375 +5455 0.871185302734375 +5456 0.2840576171875 +5457 0.865997314453125 +5458 0.28228759765625 +5459 0.860687255859375 +5460 0.280548095703125 +5461 0.855316162109375 +5462 0.27874755859375 +5463 0.849853515625 +5464 0.27691650390625 +5465 0.84429931640625 +5466 0.275054931640625 +5467 0.838623046875 +5468 0.273193359375 +5469 0.8328857421875 +5470 0.271270751953125 +5471 0.8270263671875 +5472 0.269317626953125 +5473 0.82110595703125 +5474 0.267333984375 +5475 0.815093994140625 +5476 0.265350341796875 +5477 0.808990478515625 +5478 0.2633056640625 +5479 0.802764892578125 +5480 0.26123046875 +5481 0.796478271484375 +5482 0.2591552734375 +5483 0.790130615234375 +5484 0.257049560546875 +5485 0.783660888671875 +5486 0.2548828125 +5487 0.777099609375 +5488 0.252716064453125 +5489 0.770477294921875 +5490 0.250518798828125 +5491 0.763763427734375 +5492 0.248291015625 +5493 0.7569580078125 +5494 0.246002197265625 +5495 0.75006103515625 +5496 0.243743896484375 +5497 0.74310302734375 +5498 0.241424560546875 +5499 0.736053466796875 +5500 0.23907470703125 +5501 0.72894287109375 +5502 0.236724853515625 +5503 0.721710205078125 +5504 0.234344482421875 +5505 0.714447021484375 +5506 0.231903076171875 +5507 0.707061767578125 +5508 0.229461669921875 +5509 0.699615478515625 +5510 0.227020263671875 +5511 0.692108154296875 +5512 0.224517822265625 +5513 0.68450927734375 +5514 0.22198486328125 +5515 0.676849365234375 +5516 0.219451904296875 +5517 0.669097900390625 +5518 0.216888427734375 +5519 0.661285400390625 +5520 0.21429443359375 +5521 0.65338134765625 +5522 0.211700439453125 +5523 0.645416259765625 +5524 0.20904541015625 +5525 0.63739013671875 +5526 0.206390380859375 +5527 0.6292724609375 +5528 0.2037353515625 +5529 0.621124267578125 +5530 0.201019287109375 +5531 0.612884521484375 +5532 0.198272705078125 +5533 0.60455322265625 +5534 0.195556640625 +5535 0.59619140625 +5536 0.192779541015625 +5537 0.587738037109375 +5538 0.19000244140625 +5539 0.579254150390625 +5540 0.187164306640625 +5541 0.5706787109375 +5542 0.184356689453125 +5543 0.562042236328125 +5544 0.181488037109375 +5545 0.5533447265625 +5546 0.178619384765625 +5547 0.54461669921875 +5548 0.17572021484375 +5549 0.535797119140625 +5550 0.172821044921875 +5551 0.52691650390625 +5552 0.169891357421875 +5553 0.51800537109375 +5554 0.16693115234375 +5555 0.509002685546875 +5556 0.163970947265625 +5557 0.499969482421875 +5558 0.1610107421875 +5559 0.490875244140625 +5560 0.157989501953125 +5561 0.481719970703125 +5562 0.15496826171875 +5563 0.4725341796875 +5564 0.151947021484375 +5565 0.4632568359375 +5566 0.148895263671875 +5567 0.453948974609375 +5568 0.14581298828125 +5569 0.444610595703125 +5570 0.142730712890625 +5571 0.435211181640625 +5572 0.1396484375 +5573 0.425750732421875 +5574 0.13653564453125 +5575 0.416259765625 +5576 0.133392333984375 +5577 0.406707763671875 +5578 0.1302490234375 +5579 0.397125244140625 +5580 0.1270751953125 +5581 0.387481689453125 +5582 0.1239013671875 +5583 0.3778076171875 +5584 0.1207275390625 +5585 0.36810302734375 +5586 0.117523193359375 +5587 0.35833740234375 +5588 0.11431884765625 +5589 0.348541259765625 +5590 0.111083984375 +5591 0.338714599609375 +5592 0.10784912109375 +5593 0.328826904296875 +5594 0.1046142578125 +5595 0.318939208984375 +5596 0.101348876953125 +5597 0.308990478515625 +5598 0.098052978515625 +5599 0.29901123046875 +5600 0.09478759765625 +5601 0.28900146484375 +5602 0.09149169921875 +5603 0.278961181640625 +5604 0.08819580078125 +5605 0.268890380859375 +5606 0.084869384765625 +5607 0.2587890625 +5608 0.08154296875 +5609 0.2486572265625 +5610 0.078216552734375 +5611 0.238525390625 +5612 0.07489013671875 +5613 0.22833251953125 +5614 0.071533203125 +5615 0.218109130859375 +5616 0.06817626953125 +5617 0.2078857421875 +5618 0.0648193359375 +5619 0.1976318359375 +5620 0.061431884765625 +5621 0.187347412109375 +5622 0.058074951171875 +5623 0.17706298828125 +5624 0.0546875 +5625 0.166748046875 +5626 0.051300048828125 +5627 0.156402587890625 +5628 0.047882080078125 +5629 0.14605712890625 +5630 0.04449462890625 +5631 0.13568115234375 +5632 0.037078857421875 +5633 0.12530517578125 +5634 0.03399658203125 +5635 0.11492919921875 +5636 0.030914306640625 +5637 0.104522705078125 +5638 0.02783203125 +5639 0.094085693359375 +5640 0.024749755859375 +5641 0.083648681640625 +5642 0.02166748046875 +5643 0.073211669921875 +5644 0.0185546875 +5645 0.062774658203125 +5646 0.015472412109375 +5647 0.05230712890625 +5648 0.01239013671875 +5649 0.0418701171875 +5650 0.00927734375 +5651 0.031402587890625 +5652 0.006195068359375 +5653 0.02093505859375 +5654 0.003082275390625 +5655 0.010467529296875 +5656 0.0 +5657 0.0 +5658 -0.003082275390625 +5659 -0.010467529296875 +5660 -0.006195068359375 +5661 -0.02093505859375 +5662 -0.00927734375 +5663 -0.031402587890625 +5664 -0.01239013671875 +5665 -0.0418701171875 +5666 -0.015472412109375 +5667 -0.05230712890625 +5668 -0.0185546875 +5669 -0.062774658203125 +5670 -0.02166748046875 +5671 -0.073211669921875 +5672 -0.024749755859375 +5673 -0.083648681640625 +5674 -0.02783203125 +5675 -0.094085693359375 +5676 -0.030914306640625 +5677 -0.104522705078125 +5678 -0.03399658203125 +5679 -0.11492919921875 +5680 -0.037078857421875 +5681 -0.12530517578125 +5682 -0.0401611328125 +5683 -0.13568115234375 +5684 -0.043212890625 +5685 -0.14605712890625 +5686 -0.0462646484375 +5687 -0.156402587890625 +5688 -0.049346923828125 +5689 -0.166748046875 +5690 -0.052398681640625 +5691 -0.17706298828125 +5692 -0.055450439453125 +5693 -0.187347412109375 +5694 -0.0584716796875 +5695 -0.1976318359375 +5696 -0.0615234375 +5697 -0.2078857421875 +5698 -0.064544677734375 +5699 -0.218109130859375 +5700 -0.06756591796875 +5701 -0.22833251953125 +5702 -0.070587158203125 +5703 -0.238525390625 +5704 -0.073577880859375 +5705 -0.2486572265625 +5706 -0.07659912109375 +5707 -0.2587890625 +5708 -0.07958984375 +5709 -0.268890380859375 +5710 -0.082550048828125 +5711 -0.278961181640625 +5712 -0.085540771484375 +5713 -0.28900146484375 +5714 -0.0885009765625 +5715 -0.29901123046875 +5716 -0.0914306640625 +5717 -0.308990478515625 +5718 -0.094390869140625 +5719 -0.318939208984375 +5720 -0.097320556640625 +5721 -0.328826904296875 +5722 -0.100250244140625 +5723 -0.338714599609375 +5724 -0.1031494140625 +5725 -0.348541259765625 +5726 -0.106048583984375 +5727 -0.35833740234375 +5728 -0.10894775390625 +5729 -0.36810302734375 +5730 -0.11181640625 +5731 -0.3778076171875 +5732 -0.11468505859375 +5733 -0.387481689453125 +5734 -0.117523193359375 +5735 -0.397125244140625 +5736 -0.120361328125 +5737 -0.406707763671875 +5738 -0.123199462890625 +5739 -0.416259765625 +5740 -0.126007080078125 +5741 -0.425750732421875 +5742 -0.128814697265625 +5743 -0.435211181640625 +5744 -0.131591796875 +5745 -0.444610595703125 +5746 -0.13433837890625 +5747 -0.453948974609375 +5748 -0.137115478515625 +5749 -0.4632568359375 +5750 -0.139862060546875 +5751 -0.4725341796875 +5752 -0.142578125 +5753 -0.481719970703125 +5754 -0.145294189453125 +5755 -0.490875244140625 +5756 -0.147979736328125 +5757 -0.499969482421875 +5758 -0.150634765625 +5759 -0.509002685546875 +5760 -0.1533203125 +5761 -0.51800537109375 +5762 -0.15594482421875 +5763 -0.52691650390625 +5764 -0.1585693359375 +5765 -0.535797119140625 +5766 -0.16119384765625 +5767 -0.54461669921875 +5768 -0.163787841796875 +5769 -0.5533447265625 +5770 -0.166351318359375 +5771 -0.562042236328125 +5772 -0.168914794921875 +5773 -0.5706787109375 +5774 -0.17144775390625 +5775 -0.579254150390625 +5776 -0.1739501953125 +5777 -0.587738037109375 +5778 -0.17645263671875 +5779 -0.59619140625 +5780 -0.178924560546875 +5781 -0.60455322265625 +5782 -0.181396484375 +5783 -0.612884521484375 +5784 -0.183837890625 +5785 -0.621124267578125 +5786 -0.186248779296875 +5787 -0.6292724609375 +5788 -0.18865966796875 +5789 -0.63739013671875 +5790 -0.1910400390625 +5791 -0.645416259765625 +5792 -0.193389892578125 +5793 -0.65338134765625 +5794 -0.19573974609375 +5795 -0.661285400390625 +5796 -0.198028564453125 +5797 -0.669097900390625 +5798 -0.2003173828125 +5799 -0.676849365234375 +5800 -0.202606201171875 +5801 -0.68450927734375 +5802 -0.204833984375 +5803 -0.692108154296875 +5804 -0.207061767578125 +5805 -0.699615478515625 +5806 -0.20928955078125 +5807 -0.707061767578125 +5808 -0.211456298828125 +5809 -0.714447021484375 +5810 -0.213623046875 +5811 -0.721710205078125 +5812 -0.21575927734375 +5813 -0.72894287109375 +5814 -0.217864990234375 +5815 -0.736053466796875 +5816 -0.219940185546875 +5817 -0.74310302734375 +5818 -0.222015380859375 +5819 -0.75006103515625 +5820 -0.224029541015625 +5821 -0.7569580078125 +5822 -0.226043701171875 +5823 -0.763763427734375 +5824 -0.228057861328125 +5825 -0.770477294921875 +5826 -0.230010986328125 +5827 -0.777099609375 +5828 -0.23193359375 +5829 -0.783660888671875 +5830 -0.233856201171875 +5831 -0.790130615234375 +5832 -0.235748291015625 +5833 -0.796478271484375 +5834 -0.23760986328125 +5835 -0.802764892578125 +5836 -0.23944091796875 +5837 -0.808990478515625 +5838 -0.241241455078125 +5839 -0.815093994140625 +5840 -0.2430419921875 +5841 -0.82110595703125 +5842 -0.244781494140625 +5843 -0.8270263671875 +5844 -0.24652099609375 +5845 -0.8328857421875 +5846 -0.24822998046875 +5847 -0.838623046875 +5848 -0.249908447265625 +5849 -0.84429931640625 +5850 -0.25152587890625 +5851 -0.849853515625 +5852 -0.253143310546875 +5853 -0.855316162109375 +5854 -0.2547607421875 +5855 -0.860687255859375 +5856 -0.256317138671875 +5857 -0.865997314453125 +5858 -0.257843017578125 +5859 -0.871185302734375 +5860 -0.259368896484375 +5861 -0.876251220703125 +5862 -0.260833740234375 +5863 -0.881256103515625 +5864 -0.262298583984375 +5865 -0.88616943359375 +5866 -0.263702392578125 +5867 -0.890960693359375 +5868 -0.265106201171875 +5869 -0.895660400390625 +5870 -0.266448974609375 +5871 -0.9002685546875 +5872 -0.267791748046875 +5873 -0.90478515625 +5874 -0.26910400390625 +5875 -0.9091796875 +5876 -0.2703857421875 +5877 -0.91351318359375 +5878 -0.271636962890625 +5879 -0.917724609375 +5880 -0.2728271484375 +5881 -0.92181396484375 +5882 -0.2740478515625 +5883 -0.92584228515625 +5884 -0.275177001953125 +5885 -0.929718017578125 +5886 -0.27630615234375 +5887 -0.93353271484375 +5888 -0.247406005859375 +5889 -0.937225341796875 +5890 -0.24835205078125 +5891 -0.940826416015625 +5892 -0.249267578125 +5893 -0.9443359375 +5894 -0.25018310546875 +5895 -0.947723388671875 +5896 -0.25103759765625 +5897 -0.951019287109375 +5898 -0.25189208984375 +5899 -0.954193115234375 +5900 -0.252685546875 +5901 -0.957275390625 +5902 -0.25347900390625 +5903 -0.960235595703125 +5904 -0.254241943359375 +5905 -0.963104248046875 +5906 -0.254974365234375 +5907 -0.96588134765625 +5908 -0.25567626953125 +5909 -0.968536376953125 +5910 -0.25634765625 +5911 -0.971099853515625 +5912 -0.256988525390625 +5913 -0.973541259765625 +5914 -0.257598876953125 +5915 -0.975860595703125 +5916 -0.2581787109375 +5917 -0.97808837890625 +5918 -0.258758544921875 +5919 -0.980224609375 +5920 -0.25927734375 +5921 -0.98223876953125 +5922 -0.259796142578125 +5923 -0.984161376953125 +5924 -0.26025390625 +5925 -0.9859619140625 +5926 -0.260711669921875 +5927 -0.987640380859375 +5928 -0.261138916015625 +5929 -0.989227294921875 +5930 -0.261505126953125 +5931 -0.990692138671875 +5932 -0.261871337890625 +5933 -0.9920654296875 +5934 -0.26220703125 +5935 -0.993316650390625 +5936 -0.26251220703125 +5937 -0.994476318359375 +5938 -0.262786865234375 +5939 -0.995513916015625 +5940 -0.263031005859375 +5941 -0.9964599609375 +5942 -0.26324462890625 +5943 -0.997283935546875 +5944 -0.263427734375 +5945 -0.99798583984375 +5946 -0.26361083984375 +5947 -0.99859619140625 +5948 -0.26373291015625 +5949 -0.999114990234375 +5950 -0.263824462890625 +5951 -0.999481201171875 +5952 -0.263885498046875 +5953 -0.999755859375 +5954 -0.263946533203125 +5955 -0.99993896484375 +5956 -0.26397705078125 +5957 -1.0 +5958 -0.263946533203125 +5959 -0.99993896484375 +5960 -0.263885498046875 +5961 -0.999755859375 +5962 -0.263824462890625 +5963 -0.999481201171875 +5964 -0.26373291015625 +5965 -0.999114990234375 +5966 -0.26361083984375 +5967 -0.99859619140625 +5968 -0.263427734375 +5969 -0.99798583984375 +5970 -0.26324462890625 +5971 -0.997283935546875 +5972 -0.263031005859375 +5973 -0.9964599609375 +5974 -0.262786865234375 +5975 -0.995513916015625 +5976 -0.26251220703125 +5977 -0.994476318359375 +5978 -0.26220703125 +5979 -0.993316650390625 +5980 -0.261871337890625 +5981 -0.9920654296875 +5982 -0.261505126953125 +5983 -0.990692138671875 +5984 -0.261138916015625 +5985 -0.989227294921875 +5986 -0.260711669921875 +5987 -0.987640380859375 +5988 -0.26025390625 +5989 -0.9859619140625 +5990 -0.259796142578125 +5991 -0.984161376953125 +5992 -0.25927734375 +5993 -0.98223876953125 +5994 -0.258758544921875 +5995 -0.980224609375 +5996 -0.2581787109375 +5997 -0.97808837890625 +5998 -0.257598876953125 +5999 -0.975860595703125 +6000 -0.256988525390625 +6001 -0.973541259765625 +6002 -0.25634765625 +6003 -0.971099853515625 +6004 -0.25567626953125 +6005 -0.968536376953125 +6006 -0.254974365234375 +6007 -0.96588134765625 +6008 -0.254241943359375 +6009 -0.963104248046875 +6010 -0.25347900390625 +6011 -0.960235595703125 +6012 -0.252685546875 +6013 -0.957275390625 +6014 -0.25189208984375 +6015 -0.954193115234375 +6016 -0.25103759765625 +6017 -0.951019287109375 +6018 -0.25018310546875 +6019 -0.947723388671875 +6020 -0.249267578125 +6021 -0.9443359375 +6022 -0.24835205078125 +6023 -0.940826416015625 +6024 -0.247406005859375 +6025 -0.937225341796875 +6026 -0.246429443359375 +6027 -0.93353271484375 +6028 -0.24542236328125 +6029 -0.929718017578125 +6030 -0.244384765625 +6031 -0.92584228515625 +6032 -0.243316650390625 +6033 -0.92181396484375 +6034 -0.24224853515625 +6035 -0.917724609375 +6036 -0.24114990234375 +6037 -0.91351318359375 +6038 -0.239990234375 +6039 -0.9091796875 +6040 -0.23883056640625 +6041 -0.90478515625 +6042 -0.237640380859375 +6043 -0.9002685546875 +6044 -0.236419677734375 +6045 -0.895660400390625 +6046 -0.235198974609375 +6047 -0.890960693359375 +6048 -0.233917236328125 +6049 -0.88616943359375 +6050 -0.232635498046875 +6051 -0.881256103515625 +6052 -0.231292724609375 +6053 -0.876251220703125 +6054 -0.229949951171875 +6055 -0.871185302734375 +6056 -0.228607177734375 +6057 -0.865997314453125 +6058 -0.227203369140625 +6059 -0.860687255859375 +6060 -0.22576904296875 +6061 -0.855316162109375 +6062 -0.224334716796875 +6063 -0.849853515625 +6064 -0.222869873046875 +6065 -0.84429931640625 +6066 -0.22137451171875 +6067 -0.838623046875 +6068 -0.2198486328125 +6069 -0.8328857421875 +6070 -0.218292236328125 +6071 -0.8270263671875 +6072 -0.21673583984375 +6073 -0.82110595703125 +6074 -0.21514892578125 +6075 -0.815093994140625 +6076 -0.213531494140625 +6077 -0.808990478515625 +6078 -0.2119140625 +6079 -0.802764892578125 +6080 -0.210235595703125 +6081 -0.796478271484375 +6082 -0.20855712890625 +6083 -0.790130615234375 +6084 -0.20684814453125 +6085 -0.783660888671875 +6086 -0.20513916015625 +6087 -0.777099609375 +6088 -0.203369140625 +6089 -0.770477294921875 +6090 -0.20159912109375 +6091 -0.763763427734375 +6092 -0.199798583984375 +6093 -0.7569580078125 +6094 -0.197998046875 +6095 -0.75006103515625 +6096 -0.1961669921875 +6097 -0.74310302734375 +6098 -0.194305419921875 +6099 -0.736053466796875 +6100 -0.192413330078125 +6101 -0.72894287109375 +6102 -0.19049072265625 +6103 -0.721710205078125 +6104 -0.1885986328125 +6105 -0.714447021484375 +6106 -0.1866455078125 +6107 -0.707061767578125 +6108 -0.184661865234375 +6109 -0.699615478515625 +6110 -0.18267822265625 +6111 -0.692108154296875 +6112 -0.180694580078125 +6113 -0.68450927734375 +6114 -0.17864990234375 +6115 -0.676849365234375 +6116 -0.176605224609375 +6117 -0.669097900390625 +6118 -0.174560546875 +6119 -0.661285400390625 +6120 -0.172454833984375 +6121 -0.65338134765625 +6122 -0.170379638671875 +6123 -0.645416259765625 +6124 -0.168243408203125 +6125 -0.63739013671875 +6126 -0.166107177734375 +6127 -0.6292724609375 +6128 -0.1639404296875 +6129 -0.621124267578125 +6130 -0.161773681640625 +6131 -0.612884521484375 +6132 -0.159576416015625 +6133 -0.60455322265625 +6134 -0.157379150390625 +6135 -0.59619140625 +6136 -0.1551513671875 +6137 -0.587738037109375 +6138 -0.15289306640625 +6139 -0.579254150390625 +6140 -0.150634765625 +6141 -0.5706787109375 +6142 -0.148345947265625 +6143 -0.562042236328125 +6144 -0.138336181640625 +6145 -0.5533447265625 +6146 -0.136138916015625 +6147 -0.54461669921875 +6148 -0.133941650390625 +6149 -0.535797119140625 +6150 -0.1317138671875 +6151 -0.52691650390625 +6152 -0.129486083984375 +6153 -0.51800537109375 +6154 -0.127227783203125 +6155 -0.509002685546875 +6156 -0.124969482421875 +6157 -0.499969482421875 +6158 -0.122711181640625 +6159 -0.490875244140625 +6160 -0.12042236328125 +6161 -0.481719970703125 +6162 -0.118133544921875 +6163 -0.4725341796875 +6164 -0.115814208984375 +6165 -0.4632568359375 +6166 -0.11346435546875 +6167 -0.453948974609375 +6168 -0.11114501953125 +6169 -0.444610595703125 +6170 -0.108795166015625 +6171 -0.435211181640625 +6172 -0.106414794921875 +6173 -0.425750732421875 +6174 -0.10406494140625 +6175 -0.416259765625 +6176 -0.101654052734375 +6177 -0.406707763671875 +6178 -0.099273681640625 +6179 -0.397125244140625 +6180 -0.09686279296875 +6181 -0.387481689453125 +6182 -0.094451904296875 +6183 -0.3778076171875 +6184 -0.092010498046875 +6185 -0.36810302734375 +6186 -0.089569091796875 +6187 -0.35833740234375 +6188 -0.087127685546875 +6189 -0.348541259765625 +6190 -0.08465576171875 +6191 -0.338714599609375 +6192 -0.082183837890625 +6193 -0.328826904296875 +6194 -0.0797119140625 +6195 -0.318939208984375 +6196 -0.077239990234375 +6197 -0.308990478515625 +6198 -0.074737548828125 +6199 -0.29901123046875 +6200 -0.072235107421875 +6201 -0.28900146484375 +6202 -0.069732666015625 +6203 -0.278961181640625 +6204 -0.06719970703125 +6205 -0.268890380859375 +6206 -0.064697265625 +6207 -0.2587890625 +6208 -0.062164306640625 +6209 -0.2486572265625 +6210 -0.05963134765625 +6211 -0.238525390625 +6212 -0.05706787109375 +6213 -0.22833251953125 +6214 -0.05450439453125 +6215 -0.218109130859375 +6216 -0.051971435546875 +6217 -0.2078857421875 +6218 -0.049407958984375 +6219 -0.1976318359375 +6220 -0.04681396484375 +6221 -0.187347412109375 +6222 -0.04425048828125 +6223 -0.17706298828125 +6224 -0.04168701171875 +6225 -0.166748046875 +6226 -0.039093017578125 +6227 -0.156402587890625 +6228 -0.0364990234375 +6229 -0.14605712890625 +6230 -0.033905029296875 +6231 -0.13568115234375 +6232 -0.03131103515625 +6233 -0.12530517578125 +6234 -0.028717041015625 +6235 -0.11492919921875 +6236 -0.026123046875 +6237 -0.104522705078125 +6238 -0.02349853515625 +6239 -0.094085693359375 +6240 -0.020904541015625 +6241 -0.083648681640625 +6242 -0.018280029296875 +6243 -0.073211669921875 +6244 -0.01568603515625 +6245 -0.062774658203125 +6246 -0.0130615234375 +6247 -0.05230712890625 +6248 -0.010467529296875 +6249 -0.0418701171875 +6250 -0.007843017578125 +6251 -0.031402587890625 +6252 -0.005218505859375 +6253 -0.02093505859375 +6254 -0.002593994140625 +6255 -0.010467529296875 +6256 0.0 +6257 0.0 +6258 0.002410888671875 +6259 0.010467529296875 +6260 0.004852294921875 +6261 0.02093505859375 +6262 0.00726318359375 +6263 0.031402587890625 +6264 0.00970458984375 +6265 0.0418701171875 +6266 0.012115478515625 +6267 0.05230712890625 +6268 0.014556884765625 +6269 0.062774658203125 +6270 0.0169677734375 +6271 0.073211669921875 +6272 0.019378662109375 +6273 0.083648681640625 +6274 0.021820068359375 +6275 0.094085693359375 +6276 0.02423095703125 +6277 0.104522705078125 +6278 0.026641845703125 +6279 0.11492919921875 +6280 0.029052734375 +6281 0.12530517578125 +6282 0.031463623046875 +6283 0.13568115234375 +6284 0.03387451171875 +6285 0.14605712890625 +6286 0.036285400390625 +6287 0.156402587890625 +6288 0.038665771484375 +6289 0.166748046875 +6290 0.04107666015625 +6291 0.17706298828125 +6292 0.04345703125 +6293 0.187347412109375 +6294 0.04583740234375 +6295 0.1976318359375 +6296 0.0482177734375 +6297 0.2078857421875 +6298 0.05059814453125 +6299 0.218109130859375 +6300 0.052947998046875 +6301 0.22833251953125 +6302 0.055328369140625 +6303 0.238525390625 +6304 0.05767822265625 +6305 0.2486572265625 +6306 0.060028076171875 +6307 0.2587890625 +6308 0.0623779296875 +6309 0.268890380859375 +6310 0.064697265625 +6311 0.278961181640625 +6312 0.067047119140625 +6313 0.28900146484375 +6314 0.069366455078125 +6315 0.29901123046875 +6316 0.071685791015625 +6317 0.308990478515625 +6318 0.073974609375 +6319 0.318939208984375 +6320 0.076263427734375 +6321 0.328826904296875 +6322 0.07855224609375 +6323 0.338714599609375 +6324 0.080841064453125 +6325 0.348541259765625 +6326 0.0831298828125 +6327 0.35833740234375 +6328 0.08538818359375 +6329 0.36810302734375 +6330 0.087646484375 +6331 0.3778076171875 +6332 0.089874267578125 +6333 0.387481689453125 +6334 0.092132568359375 +6335 0.397125244140625 +6336 0.094329833984375 +6337 0.406707763671875 +6338 0.0965576171875 +6339 0.416259765625 +6340 0.0987548828125 +6341 0.425750732421875 +6342 0.1009521484375 +6343 0.435211181640625 +6344 0.1031494140625 +6345 0.444610595703125 +6346 0.105316162109375 +6347 0.453948974609375 +6348 0.107452392578125 +6349 0.4632568359375 +6350 0.109619140625 +6351 0.4725341796875 +6352 0.11175537109375 +6353 0.481719970703125 +6354 0.113861083984375 +6355 0.490875244140625 +6356 0.115966796875 +6357 0.499969482421875 +6358 0.118072509765625 +6359 0.509002685546875 +6360 0.120147705078125 +6361 0.51800537109375 +6362 0.122222900390625 +6363 0.52691650390625 +6364 0.124298095703125 +6365 0.535797119140625 +6366 0.1263427734375 +6367 0.54461669921875 +6368 0.12835693359375 +6369 0.5533447265625 +6370 0.13037109375 +6371 0.562042236328125 +6372 0.13238525390625 +6373 0.5706787109375 +6374 0.134368896484375 +6375 0.579254150390625 +6376 0.1363525390625 +6377 0.587738037109375 +6378 0.1383056640625 +6379 0.59619140625 +6380 0.140228271484375 +6381 0.60455322265625 +6382 0.142181396484375 +6383 0.612884521484375 +6384 0.144073486328125 +6385 0.621124267578125 +6386 0.145965576171875 +6387 0.6292724609375 +6388 0.147857666015625 +6389 0.63739013671875 +6390 0.14971923828125 +6391 0.645416259765625 +6392 0.151580810546875 +6393 0.65338134765625 +6394 0.153411865234375 +6395 0.661285400390625 +6396 0.15521240234375 +6397 0.669097900390625 +6398 0.157012939453125 +6399 0.676849365234375 +6400 0.136871337890625 +6401 0.68450927734375 +6402 0.138397216796875 +6403 0.692108154296875 +6404 0.139892578125 +6405 0.699615478515625 +6406 0.141387939453125 +6407 0.707061767578125 +6408 0.142852783203125 +6409 0.714447021484375 +6410 0.144317626953125 +6411 0.721710205078125 +6412 0.145751953125 +6413 0.72894287109375 +6414 0.147186279296875 +6415 0.736053466796875 +6416 0.148590087890625 +6417 0.74310302734375 +6418 0.149993896484375 +6419 0.75006103515625 +6420 0.1513671875 +6421 0.7569580078125 +6422 0.152740478515625 +6423 0.763763427734375 +6424 0.154083251953125 +6425 0.770477294921875 +6426 0.1553955078125 +6427 0.777099609375 +6428 0.156707763671875 +6429 0.783660888671875 +6430 0.157989501953125 +6431 0.790130615234375 +6432 0.159271240234375 +6433 0.796478271484375 +6434 0.1605224609375 +6435 0.802764892578125 +6436 0.161773681640625 +6437 0.808990478515625 +6438 0.162994384765625 +6439 0.815093994140625 +6440 0.1641845703125 +6441 0.82110595703125 +6442 0.165374755859375 +6443 0.8270263671875 +6444 0.16656494140625 +6445 0.8328857421875 +6446 0.167694091796875 +6447 0.838623046875 +6448 0.1688232421875 +6449 0.84429931640625 +6450 0.169952392578125 +6451 0.849853515625 +6452 0.171051025390625 +6453 0.855316162109375 +6454 0.172119140625 +6455 0.860687255859375 +6456 0.173187255859375 +6457 0.865997314453125 +6458 0.174224853515625 +6459 0.871185302734375 +6460 0.17523193359375 +6461 0.876251220703125 +6462 0.176239013671875 +6463 0.881256103515625 +6464 0.177215576171875 +6465 0.88616943359375 +6466 0.17816162109375 +6467 0.890960693359375 +6468 0.179107666015625 +6469 0.895660400390625 +6470 0.180023193359375 +6471 0.9002685546875 +6472 0.180938720703125 +6473 0.90478515625 +6474 0.18182373046875 +6475 0.9091796875 +6476 0.18267822265625 +6477 0.91351318359375 +6478 0.18353271484375 +6479 0.917724609375 +6480 0.184326171875 +6481 0.92181396484375 +6482 0.185150146484375 +6483 0.92584228515625 +6484 0.1859130859375 +6485 0.929718017578125 +6486 0.186676025390625 +6487 0.93353271484375 +6488 0.187408447265625 +6489 0.937225341796875 +6490 0.188140869140625 +6491 0.940826416015625 +6492 0.1888427734375 +6493 0.9443359375 +6494 0.18951416015625 +6495 0.947723388671875 +6496 0.190185546875 +6497 0.951019287109375 +6498 0.190826416015625 +6499 0.954193115234375 +6500 0.191436767578125 +6501 0.957275390625 +6502 0.1920166015625 +6503 0.960235595703125 +6504 0.192596435546875 +6505 0.963104248046875 +6506 0.193145751953125 +6507 0.96588134765625 +6508 0.193695068359375 +6509 0.968536376953125 +6510 0.194183349609375 +6511 0.971099853515625 +6512 0.194671630859375 +6513 0.973541259765625 +6514 0.195159912109375 +6515 0.975860595703125 +6516 0.195587158203125 +6517 0.97808837890625 +6518 0.196014404296875 +6519 0.980224609375 +6520 0.1964111328125 +6521 0.98223876953125 +6522 0.196807861328125 +6523 0.984161376953125 +6524 0.197174072265625 +6525 0.9859619140625 +6526 0.197509765625 +6527 0.987640380859375 +6528 0.19781494140625 +6529 0.989227294921875 +6530 0.1981201171875 +6531 0.990692138671875 +6532 0.198394775390625 +6533 0.9920654296875 +6534 0.198638916015625 +6535 0.993316650390625 +6536 0.198883056640625 +6537 0.994476318359375 +6538 0.199066162109375 +6539 0.995513916015625 +6540 0.19927978515625 +6541 0.9964599609375 +6542 0.199432373046875 +6543 0.997283935546875 +6544 0.1995849609375 +6545 0.99798583984375 +6546 0.19970703125 +6547 0.99859619140625 +6548 0.199798583984375 +6549 0.999114990234375 +6550 0.199859619140625 +6551 0.999481201171875 +6552 0.199920654296875 +6553 0.999755859375 +6554 0.199951171875 +6555 0.99993896484375 +6556 0.199981689453125 +6557 0.999969482421875 +6558 0.199951171875 +6559 0.99993896484375 +6560 0.199920654296875 +6561 0.999755859375 +6562 0.199859619140625 +6563 0.999481201171875 +6564 0.199798583984375 +6565 0.999114990234375 +6566 0.19970703125 +6567 0.99859619140625 +6568 0.1995849609375 +6569 0.99798583984375 +6570 0.199432373046875 +6571 0.997283935546875 +6572 0.19927978515625 +6573 0.9964599609375 +6574 0.199066162109375 +6575 0.995513916015625 +6576 0.198883056640625 +6577 0.994476318359375 +6578 0.198638916015625 +6579 0.993316650390625 +6580 0.198394775390625 +6581 0.9920654296875 +6582 0.1981201171875 +6583 0.990692138671875 +6584 0.19781494140625 +6585 0.989227294921875 +6586 0.197509765625 +6587 0.987640380859375 +6588 0.197174072265625 +6589 0.9859619140625 +6590 0.196807861328125 +6591 0.984161376953125 +6592 0.1964111328125 +6593 0.98223876953125 +6594 0.196014404296875 +6595 0.980224609375 +6596 0.195587158203125 +6597 0.97808837890625 +6598 0.195159912109375 +6599 0.975860595703125 +6600 0.194671630859375 +6601 0.973541259765625 +6602 0.194183349609375 +6603 0.971099853515625 +6604 0.193695068359375 +6605 0.968536376953125 +6606 0.193145751953125 +6607 0.96588134765625 +6608 0.192596435546875 +6609 0.963104248046875 +6610 0.1920166015625 +6611 0.960235595703125 +6612 0.191436767578125 +6613 0.957275390625 +6614 0.190826416015625 +6615 0.954193115234375 +6616 0.190185546875 +6617 0.951019287109375 +6618 0.18951416015625 +6619 0.947723388671875 +6620 0.1888427734375 +6621 0.9443359375 +6622 0.188140869140625 +6623 0.940826416015625 +6624 0.187408447265625 +6625 0.937225341796875 +6626 0.186676025390625 +6627 0.93353271484375 +6628 0.1859130859375 +6629 0.929718017578125 +6630 0.185150146484375 +6631 0.92584228515625 +6632 0.184326171875 +6633 0.92181396484375 +6634 0.18353271484375 +6635 0.917724609375 +6636 0.18267822265625 +6637 0.91351318359375 +6638 0.18182373046875 +6639 0.9091796875 +6640 0.180938720703125 +6641 0.90478515625 +6642 0.180023193359375 +6643 0.9002685546875 +6644 0.179107666015625 +6645 0.895660400390625 +6646 0.17816162109375 +6647 0.890960693359375 +6648 0.177215576171875 +6649 0.88616943359375 +6650 0.176239013671875 +6651 0.881256103515625 +6652 0.17523193359375 +6653 0.876251220703125 +6654 0.174224853515625 +6655 0.871185302734375 +6656 0.145477294921875 +6657 0.865997314453125 +6658 0.14459228515625 +6659 0.860687255859375 +6660 0.1436767578125 +6661 0.855316162109375 +6662 0.14276123046875 +6663 0.849853515625 +6664 0.141845703125 +6665 0.84429931640625 +6666 0.140869140625 +6667 0.838623046875 +6668 0.139923095703125 +6669 0.8328857421875 +6670 0.138916015625 +6671 0.8270263671875 +6672 0.137939453125 +6673 0.82110595703125 +6674 0.136932373046875 +6675 0.815093994140625 +6676 0.135894775390625 +6677 0.808990478515625 +6678 0.134857177734375 +6679 0.802764892578125 +6680 0.1337890625 +6681 0.796478271484375 +6682 0.132720947265625 +6683 0.790130615234375 +6684 0.13165283203125 +6685 0.783660888671875 +6686 0.13055419921875 +6687 0.777099609375 +6688 0.129425048828125 +6689 0.770477294921875 +6690 0.1282958984375 +6691 0.763763427734375 +6692 0.127166748046875 +6693 0.7569580078125 +6694 0.126007080078125 +6695 0.75006103515625 +6696 0.12481689453125 +6697 0.74310302734375 +6698 0.1236572265625 +6699 0.736053466796875 +6700 0.1224365234375 +6701 0.72894287109375 +6702 0.121246337890625 +6703 0.721710205078125 +6704 0.120025634765625 +6705 0.714447021484375 +6706 0.1187744140625 +6707 0.707061767578125 +6708 0.117523193359375 +6709 0.699615478515625 +6710 0.11627197265625 +6711 0.692108154296875 +6712 0.114990234375 +6713 0.68450927734375 +6714 0.11370849609375 +6715 0.676849365234375 +6716 0.112396240234375 +6717 0.669097900390625 +6718 0.111083984375 +6719 0.661285400390625 +6720 0.1097412109375 +6721 0.65338134765625 +6722 0.108428955078125 +6723 0.645416259765625 +6724 0.1070556640625 +6725 0.63739013671875 +6726 0.105712890625 +6727 0.6292724609375 +6728 0.104339599609375 +6729 0.621124267578125 +6730 0.10296630859375 +6731 0.612884521484375 +6732 0.1015625 +6733 0.60455322265625 +6734 0.10015869140625 +6735 0.59619140625 +6736 0.098724365234375 +6737 0.587738037109375 +6738 0.0972900390625 +6739 0.579254150390625 +6740 0.095855712890625 +6741 0.5706787109375 +6742 0.09442138671875 +6743 0.562042236328125 +6744 0.09295654296875 +6745 0.5533447265625 +6746 0.09149169921875 +6747 0.54461669921875 +6748 0.089996337890625 +6749 0.535797119140625 +6750 0.0885009765625 +6751 0.52691650390625 +6752 0.087005615234375 +6753 0.51800537109375 +6754 0.08551025390625 +6755 0.509002685546875 +6756 0.083984375 +6757 0.499969482421875 +6758 0.08245849609375 +6759 0.490875244140625 +6760 0.080902099609375 +6761 0.481719970703125 +6762 0.079376220703125 +6763 0.4725341796875 +6764 0.07781982421875 +6765 0.4632568359375 +6766 0.076263427734375 +6767 0.453948974609375 +6768 0.074676513671875 +6769 0.444610595703125 +6770 0.073089599609375 +6771 0.435211181640625 +6772 0.071502685546875 +6773 0.425750732421875 +6774 0.069915771484375 +6775 0.416259765625 +6776 0.06829833984375 +6777 0.406707763671875 +6778 0.06671142578125 +6779 0.397125244140625 +6780 0.065093994140625 +6781 0.387481689453125 +6782 0.063446044921875 +6783 0.3778076171875 +6784 0.06182861328125 +6785 0.36810302734375 +6786 0.0601806640625 +6787 0.35833740234375 +6788 0.05853271484375 +6789 0.348541259765625 +6790 0.056884765625 +6791 0.338714599609375 +6792 0.05523681640625 +6793 0.328826904296875 +6794 0.053558349609375 +6795 0.318939208984375 +6796 0.051910400390625 +6797 0.308990478515625 +6798 0.05023193359375 +6799 0.29901123046875 +6800 0.048553466796875 +6801 0.28900146484375 +6802 0.046844482421875 +6803 0.278961181640625 +6804 0.045166015625 +6805 0.268890380859375 +6806 0.04345703125 +6807 0.2587890625 +6808 0.041748046875 +6809 0.2486572265625 +6810 0.040069580078125 +6811 0.238525390625 +6812 0.038360595703125 +6813 0.22833251953125 +6814 0.03662109375 +6815 0.218109130859375 +6816 0.034912109375 +6817 0.2078857421875 +6818 0.033172607421875 +6819 0.1976318359375 +6820 0.031463623046875 +6821 0.187347412109375 +6822 0.02972412109375 +6823 0.17706298828125 +6824 0.027984619140625 +6825 0.166748046875 +6826 0.026275634765625 +6827 0.156402587890625 +6828 0.0245361328125 +6829 0.14605712890625 +6830 0.02276611328125 +6831 0.13568115234375 +6832 0.021026611328125 +6833 0.12530517578125 +6834 0.019287109375 +6835 0.11492919921875 +6836 0.017547607421875 +6837 0.104522705078125 +6838 0.015777587890625 +6839 0.094085693359375 +6840 0.0140380859375 +6841 0.083648681640625 +6842 0.012298583984375 +6843 0.073211669921875 +6844 0.010528564453125 +6845 0.062774658203125 +6846 0.008758544921875 +6847 0.05230712890625 +6848 0.00701904296875 +6849 0.0418701171875 +6850 0.0052490234375 +6851 0.031402587890625 +6852 0.003509521484375 +6853 0.02093505859375 +6854 0.001739501953125 +6855 0.010467529296875 +6856 0.0 +6857 0.0 +6858 -0.001739501953125 +6859 -0.010467529296875 +6860 -0.003509521484375 +6861 -0.02093505859375 +6862 -0.0052490234375 +6863 -0.031402587890625 +6864 -0.00701904296875 +6865 -0.0418701171875 +6866 -0.008758544921875 +6867 -0.05230712890625 +6868 -0.010528564453125 +6869 -0.062774658203125 +6870 -0.012298583984375 +6871 -0.073211669921875 +6872 -0.0140380859375 +6873 -0.083648681640625 +6874 -0.015777587890625 +6875 -0.094085693359375 +6876 -0.017547607421875 +6877 -0.104522705078125 +6878 -0.019287109375 +6879 -0.11492919921875 +6880 -0.021026611328125 +6881 -0.12530517578125 +6882 -0.02276611328125 +6883 -0.13568115234375 +6884 -0.0245361328125 +6885 -0.14605712890625 +6886 -0.026275634765625 +6887 -0.156402587890625 +6888 -0.027984619140625 +6889 -0.166748046875 +6890 -0.02972412109375 +6891 -0.17706298828125 +6892 -0.031463623046875 +6893 -0.187347412109375 +6894 -0.033172607421875 +6895 -0.1976318359375 +6896 -0.034912109375 +6897 -0.2078857421875 +6898 -0.03662109375 +6899 -0.218109130859375 +6900 -0.038360595703125 +6901 -0.22833251953125 +6902 -0.040069580078125 +6903 -0.238525390625 +6904 -0.041748046875 +6905 -0.2486572265625 +6906 -0.04345703125 +6907 -0.2587890625 +6908 -0.045166015625 +6909 -0.268890380859375 +6910 -0.046844482421875 +6911 -0.278961181640625 +6912 -0.039276123046875 +6913 -0.28900146484375 +6914 -0.0406494140625 +6915 -0.29901123046875 +6916 -0.0419921875 +6917 -0.308990478515625 +6918 -0.043365478515625 +6919 -0.318939208984375 +6920 -0.044708251953125 +6921 -0.328826904296875 +6922 -0.046051025390625 +6923 -0.338714599609375 +6924 -0.047393798828125 +6925 -0.348541259765625 +6926 -0.0487060546875 +6927 -0.35833740234375 +6928 -0.050048828125 +6929 -0.36810302734375 +6930 -0.051361083984375 +6931 -0.3778076171875 +6932 -0.05267333984375 +6933 -0.387481689453125 +6934 -0.053985595703125 +6935 -0.397125244140625 +6936 -0.0552978515625 +6937 -0.406707763671875 +6938 -0.05657958984375 +6939 -0.416259765625 +6940 -0.057891845703125 +6941 -0.425750732421875 +6942 -0.059173583984375 +6943 -0.435211181640625 +6944 -0.060455322265625 +6945 -0.444610595703125 +6946 -0.06170654296875 +6947 -0.453948974609375 +6948 -0.06298828125 +6949 -0.4632568359375 +6950 -0.064239501953125 +6951 -0.4725341796875 +6952 -0.06549072265625 +6953 -0.481719970703125 +6954 -0.066741943359375 +6955 -0.490875244140625 +6956 -0.067962646484375 +6957 -0.499969482421875 +6958 -0.0692138671875 +6959 -0.509002685546875 +6960 -0.0704345703125 +6961 -0.51800537109375 +6962 -0.0716552734375 +6963 -0.52691650390625 +6964 -0.072845458984375 +6965 -0.535797119140625 +6966 -0.07403564453125 +6967 -0.54461669921875 +6968 -0.075225830078125 +6969 -0.5533447265625 +6970 -0.076416015625 +6971 -0.562042236328125 +6972 -0.077606201171875 +6973 -0.5706787109375 +6974 -0.078765869140625 +6975 -0.579254150390625 +6976 -0.079925537109375 +6977 -0.587738037109375 +6978 -0.0810546875 +6979 -0.59619140625 +6980 -0.082183837890625 +6981 -0.60455322265625 +6982 -0.083343505859375 +6983 -0.612884521484375 +6984 -0.084442138671875 +6985 -0.621124267578125 +6986 -0.0855712890625 +6987 -0.6292724609375 +6988 -0.086669921875 +6989 -0.63739013671875 +6990 -0.0877685546875 +6991 -0.645416259765625 +6992 -0.088836669921875 +6993 -0.65338134765625 +6994 -0.08990478515625 +6995 -0.661285400390625 +6996 -0.090972900390625 +6997 -0.669097900390625 +6998 -0.092041015625 +6999 -0.676849365234375 +7000 -0.09307861328125 +7001 -0.68450927734375 +7002 -0.0941162109375 +7003 -0.692108154296875 +7004 -0.095123291015625 +7005 -0.699615478515625 +7006 -0.09613037109375 +7007 -0.707061767578125 +7008 -0.097137451171875 +7009 -0.714447021484375 +7010 -0.09814453125 +7011 -0.721710205078125 +7012 -0.09912109375 +7013 -0.72894287109375 +7014 -0.100067138671875 +7015 -0.736053466796875 +7016 -0.101043701171875 +7017 -0.74310302734375 +7018 -0.10198974609375 +7019 -0.75006103515625 +7020 -0.102935791015625 +7021 -0.7569580078125 +7022 -0.103851318359375 +7023 -0.763763427734375 +7024 -0.104766845703125 +7025 -0.770477294921875 +7026 -0.10565185546875 +7027 -0.777099609375 +7028 -0.1065673828125 +7029 -0.783660888671875 +7030 -0.107421875 +7031 -0.790130615234375 +7032 -0.108306884765625 +7033 -0.796478271484375 +7034 -0.109161376953125 +7035 -0.802764892578125 +7036 -0.1099853515625 +7037 -0.808990478515625 +7038 -0.11083984375 +7039 -0.815093994140625 +7040 -0.11163330078125 +7041 -0.82110595703125 +7042 -0.112457275390625 +7043 -0.8270263671875 +7044 -0.113250732421875 +7045 -0.8328857421875 +7046 -0.114044189453125 +7047 -0.838623046875 +7048 -0.11480712890625 +7049 -0.84429931640625 +7050 -0.115570068359375 +7051 -0.849853515625 +7052 -0.116302490234375 +7053 -0.855316162109375 +7054 -0.117034912109375 +7055 -0.860687255859375 +7056 -0.117767333984375 +7057 -0.865997314453125 +7058 -0.11846923828125 +7059 -0.871185302734375 +7060 -0.119140625 +7061 -0.876251220703125 +7062 -0.11981201171875 +7063 -0.881256103515625 +7064 -0.1204833984375 +7065 -0.88616943359375 +7066 -0.12115478515625 +7067 -0.890960693359375 +7068 -0.121795654296875 +7069 -0.895660400390625 +7070 -0.122406005859375 +7071 -0.9002685546875 +7072 -0.123016357421875 +7073 -0.90478515625 +7074 -0.123626708984375 +7075 -0.9091796875 +7076 -0.12420654296875 +7077 -0.91351318359375 +7078 -0.124786376953125 +7079 -0.917724609375 +7080 -0.125335693359375 +7081 -0.92181396484375 +7082 -0.125885009765625 +7083 -0.92584228515625 +7084 -0.12640380859375 +7085 -0.929718017578125 +7086 -0.126922607421875 +7087 -0.93353271484375 +7088 -0.12744140625 +7089 -0.937225341796875 +7090 -0.1279296875 +7091 -0.940826416015625 +7092 -0.12841796875 +7093 -0.9443359375 +7094 -0.128875732421875 +7095 -0.947723388671875 +7096 -0.129302978515625 +7097 -0.951019287109375 +7098 -0.1297607421875 +7099 -0.954193115234375 +7100 -0.130157470703125 +7101 -0.957275390625 +7102 -0.13055419921875 +7103 -0.960235595703125 +7104 -0.130950927734375 +7105 -0.963104248046875 +7106 -0.13134765625 +7107 -0.96588134765625 +7108 -0.131683349609375 +7109 -0.968536376953125 +7110 -0.132049560546875 +7111 -0.971099853515625 +7112 -0.13238525390625 +7113 -0.973541259765625 +7114 -0.1326904296875 +7115 -0.975860595703125 +7116 -0.13299560546875 +7117 -0.97808837890625 +7118 -0.13330078125 +7119 -0.980224609375 +7120 -0.133544921875 +7121 -0.98223876953125 +7122 -0.133819580078125 +7123 -0.984161376953125 +7124 -0.134063720703125 +7125 -0.9859619140625 +7126 -0.134307861328125 +7127 -0.987640380859375 +7128 -0.134521484375 +7129 -0.989227294921875 +7130 -0.13470458984375 +7131 -0.990692138671875 +7132 -0.1348876953125 +7133 -0.9920654296875 +7134 -0.13507080078125 +7135 -0.993316650390625 +7136 -0.135223388671875 +7137 -0.994476318359375 +7138 -0.1353759765625 +7139 -0.995513916015625 +7140 -0.135498046875 +7141 -0.9964599609375 +7142 -0.1356201171875 +7143 -0.997283935546875 +7144 -0.135711669921875 +7145 -0.99798583984375 +7146 -0.135772705078125 +7147 -0.99859619140625 +7148 -0.1358642578125 +7149 -0.999114990234375 +7150 -0.135894775390625 +7151 -0.999481201171875 +7152 -0.13592529296875 +7153 -0.999755859375 +7154 -0.135955810546875 +7155 -0.99993896484375 +7156 -0.135986328125 +7157 -1.0 +7158 -0.135955810546875 +7159 -0.99993896484375 +7160 -0.13592529296875 +7161 -0.999755859375 +7162 -0.135894775390625 +7163 -0.999481201171875 +7164 -0.1358642578125 +7165 -0.999114990234375 +7166 -0.135772705078125 +7167 -0.99859619140625 +7168 -0.103790283203125 +7169 -0.99798583984375 +7170 -0.10369873046875 +7171 -0.997283935546875 +7172 -0.1036376953125 +7173 -0.9964599609375 +7174 -0.103515625 +7175 -0.995513916015625 +7176 -0.103424072265625 +7177 -0.994476318359375 +7178 -0.103302001953125 +7179 -0.993316650390625 +7180 -0.103179931640625 +7181 -0.9920654296875 +7182 -0.10302734375 +7183 -0.990692138671875 +7184 -0.102874755859375 +7185 -0.989227294921875 +7186 -0.102691650390625 +7187 -0.987640380859375 +7188 -0.1025390625 +7189 -0.9859619140625 +7190 -0.10235595703125 +7191 -0.984161376953125 +7192 -0.102142333984375 +7193 -0.98223876953125 +7194 -0.1019287109375 +7195 -0.980224609375 +7196 -0.101715087890625 +7197 -0.97808837890625 +7198 -0.101470947265625 +7199 -0.975860595703125 +7200 -0.101226806640625 +7201 -0.973541259765625 +7202 -0.100982666015625 +7203 -0.971099853515625 +7204 -0.1007080078125 +7205 -0.968536376953125 +7206 -0.100433349609375 +7207 -0.96588134765625 +7208 -0.10015869140625 +7209 -0.963104248046875 +7210 -0.099853515625 +7211 -0.960235595703125 +7212 -0.09954833984375 +7213 -0.957275390625 +7214 -0.099212646484375 +7215 -0.954193115234375 +7216 -0.098907470703125 +7217 -0.951019287109375 +7218 -0.098541259765625 +7219 -0.947723388671875 +7220 -0.09820556640625 +7221 -0.9443359375 +7222 -0.09783935546875 +7223 -0.940826416015625 +7224 -0.09747314453125 +7225 -0.937225341796875 +7226 -0.097076416015625 +7227 -0.93353271484375 +7228 -0.0966796875 +7229 -0.929718017578125 +7230 -0.096282958984375 +7231 -0.92584228515625 +7232 -0.095855712890625 +7233 -0.92181396484375 +7234 -0.095428466796875 +7235 -0.917724609375 +7236 -0.095001220703125 +7237 -0.91351318359375 +7238 -0.09454345703125 +7239 -0.9091796875 +7240 -0.094085693359375 +7241 -0.90478515625 +7242 -0.0936279296875 +7243 -0.9002685546875 +7244 -0.0931396484375 +7245 -0.895660400390625 +7246 -0.0926513671875 +7247 -0.890960693359375 +7248 -0.0921630859375 +7249 -0.88616943359375 +7250 -0.091644287109375 +7251 -0.881256103515625 +7252 -0.09112548828125 +7253 -0.876251220703125 +7254 -0.090606689453125 +7255 -0.871185302734375 +7256 -0.090057373046875 +7257 -0.865997314453125 +7258 -0.089508056640625 +7259 -0.860687255859375 +7260 -0.088958740234375 +7261 -0.855316162109375 +7262 -0.08837890625 +7263 -0.849853515625 +7264 -0.087799072265625 +7265 -0.84429931640625 +7266 -0.08721923828125 +7267 -0.838623046875 +7268 -0.08660888671875 +7269 -0.8328857421875 +7270 -0.08599853515625 +7271 -0.8270263671875 +7272 -0.08538818359375 +7273 -0.82110595703125 +7274 -0.084747314453125 +7275 -0.815093994140625 +7276 -0.084136962890625 +7277 -0.808990478515625 +7278 -0.083465576171875 +7279 -0.802764892578125 +7280 -0.08282470703125 +7281 -0.796478271484375 +7282 -0.0821533203125 +7283 -0.790130615234375 +7284 -0.08148193359375 +7285 -0.783660888671875 +7286 -0.080810546875 +7287 -0.777099609375 +7288 -0.080108642578125 +7289 -0.770477294921875 +7290 -0.07940673828125 +7291 -0.763763427734375 +7292 -0.078704833984375 +7293 -0.7569580078125 +7294 -0.0780029296875 +7295 -0.75006103515625 +7296 -0.0772705078125 +7297 -0.74310302734375 +7298 -0.0765380859375 +7299 -0.736053466796875 +7300 -0.0758056640625 +7301 -0.72894287109375 +7302 -0.075042724609375 +7303 -0.721710205078125 +7304 -0.07427978515625 +7305 -0.714447021484375 +7306 -0.073516845703125 +7307 -0.707061767578125 +7308 -0.07275390625 +7309 -0.699615478515625 +7310 -0.07196044921875 +7311 -0.692108154296875 +7312 -0.0711669921875 +7313 -0.68450927734375 +7314 -0.07037353515625 +7315 -0.676849365234375 +7316 -0.069580078125 +7317 -0.669097900390625 +7318 -0.068756103515625 +7319 -0.661285400390625 +7320 -0.06793212890625 +7321 -0.65338134765625 +7322 -0.067108154296875 +7323 -0.645416259765625 +7324 -0.0662841796875 +7325 -0.63739013671875 +7326 -0.0654296875 +7327 -0.6292724609375 +7328 -0.0645751953125 +7329 -0.621124267578125 +7330 -0.063720703125 +7331 -0.612884521484375 +7332 -0.0628662109375 +7333 -0.60455322265625 +7334 -0.061981201171875 +7335 -0.59619140625 +7336 -0.061126708984375 +7337 -0.587738037109375 +7338 -0.06024169921875 +7339 -0.579254150390625 +7340 -0.059326171875 +7341 -0.5706787109375 +7342 -0.058441162109375 +7343 -0.562042236328125 +7344 -0.057525634765625 +7345 -0.5533447265625 +7346 -0.056640625 +7347 -0.54461669921875 +7348 -0.05572509765625 +7349 -0.535797119140625 +7350 -0.054779052734375 +7351 -0.52691650390625 +7352 -0.053863525390625 +7353 -0.51800537109375 +7354 -0.05291748046875 +7355 -0.509002685546875 +7356 -0.051971435546875 +7357 -0.499969482421875 +7358 -0.051025390625 +7359 -0.490875244140625 +7360 -0.050079345703125 +7361 -0.481719970703125 +7362 -0.04913330078125 +7363 -0.4725341796875 +7364 -0.04815673828125 +7365 -0.4632568359375 +7366 -0.047210693359375 +7367 -0.453948974609375 +7368 -0.046234130859375 +7369 -0.444610595703125 +7370 -0.045257568359375 +7371 -0.435211181640625 +7372 -0.044281005859375 +7373 -0.425750732421875 +7374 -0.04327392578125 +7375 -0.416259765625 +7376 -0.04229736328125 +7377 -0.406707763671875 +7378 -0.041290283203125 +7379 -0.397125244140625 +7380 -0.040283203125 +7381 -0.387481689453125 +7382 -0.039276123046875 +7383 -0.3778076171875 +7384 -0.03826904296875 +7385 -0.36810302734375 +7386 -0.037261962890625 +7387 -0.35833740234375 +7388 -0.036224365234375 +7389 -0.348541259765625 +7390 -0.03521728515625 +7391 -0.338714599609375 +7392 -0.0341796875 +7393 -0.328826904296875 +7394 -0.03314208984375 +7395 -0.318939208984375 +7396 -0.032135009765625 +7397 -0.308990478515625 +7398 -0.031097412109375 +7399 -0.29901123046875 +7400 -0.030029296875 +7401 -0.28900146484375 +7402 -0.02899169921875 +7403 -0.278961181640625 +7404 -0.0279541015625 +7405 -0.268890380859375 +7406 -0.026885986328125 +7407 -0.2587890625 +7408 -0.025848388671875 +7409 -0.2486572265625 +7410 -0.0247802734375 +7411 -0.238525390625 +7412 -0.02374267578125 +7413 -0.22833251953125 +7414 -0.022674560546875 +7415 -0.218109130859375 +7416 -0.0216064453125 +7417 -0.2078857421875 +7418 -0.020538330078125 +7419 -0.1976318359375 +7420 -0.01947021484375 +7421 -0.187347412109375 +7422 -0.018402099609375 +7423 -0.17706298828125 +7424 -0.01666259765625 +7425 -0.166748046875 +7426 -0.015625 +7427 -0.156402587890625 +7428 -0.01458740234375 +7429 -0.14605712890625 +7430 -0.0135498046875 +7431 -0.13568115234375 +7432 -0.01251220703125 +7433 -0.12530517578125 +7434 -0.011474609375 +7435 -0.11492919921875 +7436 -0.01043701171875 +7437 -0.104522705078125 +7438 -0.0093994140625 +7439 -0.094085693359375 +7440 -0.00836181640625 +7441 -0.083648681640625 +7442 -0.007293701171875 +7443 -0.073211669921875 +7444 -0.006256103515625 +7445 -0.062774658203125 +7446 -0.005218505859375 +7447 -0.05230712890625 +7448 -0.004180908203125 +7449 -0.0418701171875 +7450 -0.00311279296875 +7451 -0.031402587890625 +7452 -0.0020751953125 +7453 -0.02093505859375 +7454 -0.00103759765625 +7455 -0.010467529296875 +7456 0.0 +7457 0.0 +7458 0.000732421875 +7459 0.010467529296875 +7460 0.001495361328125 +7461 0.02093505859375 +7462 0.00225830078125 +7463 0.031402587890625 +7464 0.00299072265625 +7465 0.0418701171875 +7466 0.003753662109375 +7467 0.05230712890625 +7468 0.0045166015625 +7469 0.062774658203125 +7470 0.0052490234375 +7471 0.073211669921875 +7472 0.006011962890625 +7473 0.083648681640625 +7474 0.006744384765625 +7475 0.094085693359375 +7476 0.00750732421875 +7477 0.104522705078125 +7478 0.008270263671875 +7479 0.11492919921875 +7480 0.009002685546875 +7481 0.12530517578125 +7482 0.009765625 +7483 0.13568115234375 +7484 0.010498046875 +7485 0.14605712890625 +7486 0.01123046875 +7487 0.156402587890625 +7488 0.011993408203125 +7489 0.166748046875 +7490 0.012725830078125 +7491 0.17706298828125 +7492 0.013458251953125 +7493 0.187347412109375 +7494 0.01422119140625 +7495 0.1976318359375 +7496 0.01495361328125 +7497 0.2078857421875 +7498 0.01568603515625 +7499 0.218109130859375 +7500 0.01641845703125 +7501 0.22833251953125 +7502 0.01715087890625 +7503 0.238525390625 +7504 0.01788330078125 +7505 0.2486572265625 +7506 0.01861572265625 +7507 0.2587890625 +7508 0.01934814453125 +7509 0.268890380859375 +7510 0.02008056640625 +7511 0.278961181640625 +7512 0.020782470703125 +7513 0.28900146484375 +7514 0.021514892578125 +7515 0.29901123046875 +7516 0.022216796875 +7517 0.308990478515625 +7518 0.02294921875 +7519 0.318939208984375 +7520 0.023651123046875 +7521 0.328826904296875 +7522 0.024383544921875 +7523 0.338714599609375 +7524 0.02508544921875 +7525 0.348541259765625 +7526 0.025787353515625 +7527 0.35833740234375 +7528 0.0264892578125 +7529 0.36810302734375 +7530 0.027191162109375 +7531 0.3778076171875 +7532 0.02789306640625 +7533 0.387481689453125 +7534 0.028564453125 +7535 0.397125244140625 +7536 0.029266357421875 +7537 0.406707763671875 +7538 0.029937744140625 +7539 0.416259765625 +7540 0.0306396484375 +7541 0.425750732421875 +7542 0.03131103515625 +7543 0.435211181640625 +7544 0.031982421875 +7545 0.444610595703125 +7546 0.03265380859375 +7547 0.453948974609375 +7548 0.0333251953125 +7549 0.4632568359375 +7550 0.03399658203125 +7551 0.4725341796875 +7552 0.03466796875 +7553 0.481719970703125 +7554 0.03533935546875 +7555 0.490875244140625 +7556 0.035980224609375 +7557 0.499969482421875 +7558 0.03662109375 +7559 0.509002685546875 +7560 0.03729248046875 +7561 0.51800537109375 +7562 0.037933349609375 +7563 0.52691650390625 +7564 0.038543701171875 +7565 0.535797119140625 +7566 0.0391845703125 +7567 0.54461669921875 +7568 0.039825439453125 +7569 0.5533447265625 +7570 0.040435791015625 +7571 0.562042236328125 +7572 0.04107666015625 +7573 0.5706787109375 +7574 0.04168701171875 +7575 0.579254150390625 +7576 0.04229736328125 +7577 0.587738037109375 +7578 0.04290771484375 +7579 0.59619140625 +7580 0.04351806640625 +7581 0.60455322265625 +7582 0.044097900390625 +7583 0.612884521484375 +7584 0.044708251953125 +7585 0.621124267578125 +7586 0.0452880859375 +7587 0.6292724609375 +7588 0.045867919921875 +7589 0.63739013671875 +7590 0.04644775390625 +7591 0.645416259765625 +7592 0.047027587890625 +7593 0.65338134765625 +7594 0.047607421875 +7595 0.661285400390625 +7596 0.04815673828125 +7597 0.669097900390625 +7598 0.0487060546875 +7599 0.676849365234375 +7600 0.04925537109375 +7601 0.68450927734375 +7602 0.0498046875 +7603 0.692108154296875 +7604 0.05035400390625 +7605 0.699615478515625 +7606 0.0509033203125 +7607 0.707061767578125 +7608 0.051422119140625 +7609 0.714447021484375 +7610 0.05194091796875 +7611 0.721710205078125 +7612 0.052459716796875 +7613 0.72894287109375 +7614 0.052978515625 +7615 0.736053466796875 +7616 0.053497314453125 +7617 0.74310302734375 +7618 0.053985595703125 +7619 0.75006103515625 +7620 0.054473876953125 +7621 0.7569580078125 +7622 0.054962158203125 +7623 0.763763427734375 +7624 0.055450439453125 +7625 0.770477294921875 +7626 0.055938720703125 +7627 0.777099609375 +7628 0.056396484375 +7629 0.783660888671875 +7630 0.056854248046875 +7631 0.790130615234375 +7632 0.05731201171875 +7633 0.796478271484375 +7634 0.057769775390625 +7635 0.802764892578125 +7636 0.0582275390625 +7637 0.808990478515625 +7638 0.05865478515625 +7639 0.815093994140625 +7640 0.059112548828125 +7641 0.82110595703125 +7642 0.059539794921875 +7643 0.8270263671875 +7644 0.0599365234375 +7645 0.8328857421875 +7646 0.06036376953125 +7647 0.838623046875 +7648 0.060760498046875 +7649 0.84429931640625 +7650 0.0611572265625 +7651 0.849853515625 +7652 0.061553955078125 +7653 0.855316162109375 +7654 0.06195068359375 +7655 0.860687255859375 +7656 0.06231689453125 +7657 0.865997314453125 +7658 0.062713623046875 +7659 0.871185302734375 +7660 0.063079833984375 +7661 0.876251220703125 +7662 0.06341552734375 +7663 0.881256103515625 +7664 0.06378173828125 +7665 0.88616943359375 +7666 0.064117431640625 +7667 0.890960693359375 +7668 0.064453125 +7669 0.895660400390625 +7670 0.064788818359375 +7671 0.9002685546875 +7672 0.06512451171875 +7673 0.90478515625 +7674 0.0654296875 +7675 0.9091796875 +7676 0.065765380859375 +7677 0.91351318359375 +7678 0.0660400390625 +7679 0.917724609375 +7680 0.036865234375 +7681 0.92181396484375 +7682 0.037017822265625 +7683 0.92584228515625 +7684 0.03717041015625 +7685 0.929718017578125 +7686 0.037322998046875 +7687 0.93353271484375 +7688 0.0374755859375 +7689 0.937225341796875 +7690 0.037628173828125 +7691 0.940826416015625 +7692 0.03778076171875 +7693 0.9443359375 +7694 0.03790283203125 +7695 0.947723388671875 +7696 0.03802490234375 +7697 0.951019287109375 +7698 0.03814697265625 +7699 0.954193115234375 +7700 0.038299560546875 +7701 0.957275390625 +7702 0.03839111328125 +7703 0.960235595703125 +7704 0.03851318359375 +7705 0.963104248046875 +7706 0.03863525390625 +7707 0.96588134765625 +7708 0.038726806640625 +7709 0.968536376953125 +7710 0.038848876953125 +7711 0.971099853515625 +7712 0.0389404296875 +7713 0.973541259765625 +7714 0.039031982421875 +7715 0.975860595703125 +7716 0.03912353515625 +7717 0.97808837890625 +7718 0.039215087890625 +7719 0.980224609375 +7720 0.039276123046875 +7721 0.98223876953125 +7722 0.03936767578125 +7723 0.984161376953125 +7724 0.0394287109375 +7725 0.9859619140625 +7726 0.03948974609375 +7727 0.987640380859375 +7728 0.03955078125 +7729 0.989227294921875 +7730 0.03961181640625 +7731 0.990692138671875 +7732 0.0396728515625 +7733 0.9920654296875 +7734 0.03973388671875 +7735 0.993316650390625 +7736 0.039764404296875 +7737 0.994476318359375 +7738 0.039825439453125 +7739 0.995513916015625 +7740 0.03985595703125 +7741 0.9964599609375 +7742 0.039886474609375 +7743 0.997283935546875 +7744 0.0399169921875 +7745 0.99798583984375 +7746 0.039947509765625 +7747 0.99859619140625 +7748 0.039947509765625 +7749 0.999114990234375 +7750 0.03997802734375 +7751 0.999481201171875 +7752 0.03997802734375 +7753 0.999755859375 +7754 0.03997802734375 +7755 0.99993896484375 +7756 0.040008544921875 +7757 0.999969482421875 +7758 0.03997802734375 +7759 0.99993896484375 +7760 0.03997802734375 +7761 0.999755859375 +7762 0.03997802734375 +7763 0.999481201171875 +7764 0.039947509765625 +7765 0.999114990234375 +7766 0.039947509765625 +7767 0.99859619140625 +7768 0.0399169921875 +7769 0.99798583984375 +7770 0.039886474609375 +7771 0.997283935546875 +7772 0.03985595703125 +7773 0.9964599609375 +7774 0.039825439453125 +7775 0.995513916015625 +7776 0.039764404296875 +7777 0.994476318359375 +7778 0.03973388671875 +7779 0.993316650390625 +7780 0.0396728515625 +7781 0.9920654296875 +7782 0.03961181640625 +7783 0.990692138671875 +7784 0.03955078125 +7785 0.989227294921875 +7786 0.03948974609375 +7787 0.987640380859375 +7788 0.0394287109375 +7789 0.9859619140625 +7790 0.03936767578125 +7791 0.984161376953125 +7792 0.039276123046875 +7793 0.98223876953125 +7794 0.039215087890625 +7795 0.980224609375 +7796 0.03912353515625 +7797 0.97808837890625 +7798 0.039031982421875 +7799 0.975860595703125 +7800 0.0389404296875 +7801 0.973541259765625 +7802 0.038848876953125 +7803 0.971099853515625 +7804 0.038726806640625 +7805 0.968536376953125 +7806 0.03863525390625 +7807 0.96588134765625 +7808 0.03851318359375 +7809 0.963104248046875 +7810 0.03839111328125 +7811 0.960235595703125 +7812 0.038299560546875 +7813 0.957275390625 +7814 0.03814697265625 +7815 0.954193115234375 +7816 0.03802490234375 +7817 0.951019287109375 +7818 0.03790283203125 +7819 0.947723388671875 +7820 0.03778076171875 +7821 0.9443359375 +7822 0.037628173828125 +7823 0.940826416015625 +7824 0.0374755859375 +7825 0.937225341796875 +7826 0.037322998046875 +7827 0.93353271484375 +7828 0.03717041015625 +7829 0.929718017578125 +7830 0.037017822265625 +7831 0.92584228515625 +7832 0.036865234375 +7833 0.92181396484375 +7834 0.036712646484375 +7835 0.917724609375 +7836 0.036529541015625 +7837 0.91351318359375 +7838 0.036346435546875 +7839 0.9091796875 +7840 0.03619384765625 +7841 0.90478515625 +7842 0.0360107421875 +7843 0.9002685546875 +7844 0.03582763671875 +7845 0.895660400390625 +7846 0.03564453125 +7847 0.890960693359375 +7848 0.035430908203125 +7849 0.88616943359375 +7850 0.035247802734375 +7851 0.881256103515625 +7852 0.0350341796875 +7853 0.876251220703125 +7854 0.03485107421875 +7855 0.871185302734375 +7856 0.034637451171875 +7857 0.865997314453125 +7858 0.034423828125 +7859 0.860687255859375 +7860 0.034210205078125 +7861 0.855316162109375 +7862 0.03399658203125 +7863 0.849853515625 +7864 0.03375244140625 +7865 0.84429931640625 +7866 0.033538818359375 +7867 0.838623046875 +7868 0.033294677734375 +7869 0.8328857421875 +7870 0.0330810546875 +7871 0.8270263671875 +7872 0.0328369140625 +7873 0.82110595703125 +7874 0.0325927734375 +7875 0.815093994140625 +7876 0.0323486328125 +7877 0.808990478515625 +7878 0.0321044921875 +7879 0.802764892578125 +7880 0.0318603515625 +7881 0.796478271484375 +7882 0.031585693359375 +7883 0.790130615234375 +7884 0.031341552734375 +7885 0.783660888671875 +7886 0.03106689453125 +7887 0.777099609375 +7888 0.03082275390625 +7889 0.770477294921875 +7890 0.030548095703125 +7891 0.763763427734375 +7892 0.0302734375 +7893 0.7569580078125 +7894 0.029998779296875 +7895 0.75006103515625 +7896 0.02972412109375 +7897 0.74310302734375 +7898 0.0294189453125 +7899 0.736053466796875 +7900 0.029144287109375 +7901 0.72894287109375 +7902 0.02886962890625 +7903 0.721710205078125 +7904 0.028564453125 +7905 0.714447021484375 +7906 0.02825927734375 +7907 0.707061767578125 +7908 0.027984619140625 +7909 0.699615478515625 +7910 0.027679443359375 +7911 0.692108154296875 +7912 0.027374267578125 +7913 0.68450927734375 +7914 0.027069091796875 +7915 0.676849365234375 +7916 0.026763916015625 +7917 0.669097900390625 +7918 0.02642822265625 +7919 0.661285400390625 +7920 0.026123046875 +7921 0.65338134765625 +7922 0.02581787109375 +7923 0.645416259765625 +7924 0.025482177734375 +7925 0.63739013671875 +7926 0.025177001953125 +7927 0.6292724609375 +7928 0.02484130859375 +7929 0.621124267578125 +7930 0.024505615234375 +7931 0.612884521484375 +7932 0.024169921875 +7933 0.60455322265625 +7934 0.023834228515625 +7935 0.59619140625 +7936 0.004669189453125 +7937 0.587738037109375 +7938 0.004608154296875 +7939 0.579254150390625 +7940 0.004547119140625 +7941 0.5706787109375 +7942 0.004486083984375 +7943 0.562042236328125 +7944 0.00439453125 +7945 0.5533447265625 +7946 0.00433349609375 +7947 0.54461669921875 +7948 0.0042724609375 +7949 0.535797119140625 +7950 0.00421142578125 +7951 0.52691650390625 +7952 0.004119873046875 +7953 0.51800537109375 +7954 0.004058837890625 +7955 0.509002685546875 +7956 0.00396728515625 +7957 0.499969482421875 +7958 0.00390625 +7959 0.490875244140625 +7960 0.00384521484375 +7961 0.481719970703125 +7962 0.003753662109375 +7963 0.4725341796875 +7964 0.003692626953125 +7965 0.4632568359375 +7966 0.00360107421875 +7967 0.453948974609375 +7968 0.0035400390625 +7969 0.444610595703125 +7970 0.00347900390625 +7971 0.435211181640625 +7972 0.003387451171875 +7973 0.425750732421875 +7974 0.003326416015625 +7975 0.416259765625 +7976 0.00323486328125 +7977 0.406707763671875 +7978 0.003173828125 +7979 0.397125244140625 +7980 0.003082275390625 +7981 0.387481689453125 +7982 0.00299072265625 +7983 0.3778076171875 +7984 0.0029296875 +7985 0.36810302734375 +7986 0.002838134765625 +7987 0.35833740234375 +7988 0.002777099609375 +7989 0.348541259765625 +7990 0.002685546875 +7991 0.338714599609375 +7992 0.00262451171875 +7993 0.328826904296875 +7994 0.002532958984375 +7995 0.318939208984375 +7996 0.00244140625 +7997 0.308990478515625 +7998 0.00238037109375 +7999 0.29901123046875 +8000 0.002288818359375 +8001 0.28900146484375 +8002 0.002227783203125 +8003 0.278961181640625 +8004 0.00213623046875 +8005 0.268890380859375 +8006 0.002044677734375 +8007 0.2587890625 +8008 0.001983642578125 +8009 0.2486572265625 +8010 0.00189208984375 +8011 0.238525390625 +8012 0.001800537109375 +8013 0.22833251953125 +8014 0.001739501953125 +8015 0.218109130859375 +8016 0.00164794921875 +8017 0.2078857421875 +8018 0.001556396484375 +8019 0.1976318359375 +8020 0.001495361328125 +8021 0.187347412109375 +8022 0.00140380859375 +8023 0.17706298828125 +8024 0.001312255859375 +8025 0.166748046875 +8026 0.001220703125 +8027 0.156402587890625 +8028 0.00115966796875 +8029 0.14605712890625 +8030 0.001068115234375 +8031 0.13568115234375 +8032 0.0009765625 +8033 0.12530517578125 +8034 0.00091552734375 +8035 0.11492919921875 +8036 0.000823974609375 +8037 0.104522705078125 +8038 0.000732421875 +8039 0.094085693359375 +8040 0.000640869140625 +8041 0.083648681640625 +8042 0.000579833984375 +8043 0.073211669921875 +8044 0.00048828125 +8045 0.062774658203125 +8046 0.000396728515625 +8047 0.05230712890625 +8048 0.00030517578125 +8049 0.0418701171875 +8050 0.000244140625 +8051 0.031402587890625 +8052 0.000152587890625 +8053 0.02093505859375 +8054 6.103515625e-05 +8055 0.010467529296875 +8056 0.0 +8057 0.0 +8058 -6.103515625e-05 +8059 -0.010467529296875 +8060 -0.000152587890625 +8061 -0.02093505859375 +8062 -0.000244140625 +8063 -0.031402587890625 +8064 -0.00030517578125 +8065 -0.0418701171875 +8066 -0.000396728515625 +8067 -0.05230712890625 +8068 -0.00048828125 +8069 -0.062774658203125 +8070 -0.000579833984375 +8071 -0.073211669921875 +8072 -0.000640869140625 +8073 -0.083648681640625 +8074 -0.000732421875 +8075 -0.094085693359375 +8076 -0.000823974609375 +8077 -0.104522705078125 +8078 -0.00091552734375 +8079 -0.11492919921875 +8080 -0.0009765625 +8081 -0.12530517578125 +8082 -0.001068115234375 +8083 -0.13568115234375 +8084 -0.00115966796875 +8085 -0.14605712890625 +8086 -0.001220703125 +8087 -0.156402587890625 +8088 -0.001312255859375 +8089 -0.166748046875 +8090 -0.00140380859375 +8091 -0.17706298828125 +8092 -0.001495361328125 +8093 -0.187347412109375 +8094 -0.001556396484375 +8095 -0.1976318359375 +8096 -0.00164794921875 +8097 -0.2078857421875 +8098 -0.001739501953125 +8099 -0.218109130859375 +8100 -0.001800537109375 +8101 -0.22833251953125 +8102 -0.00189208984375 +8103 -0.238525390625 +8104 -0.001983642578125 +8105 -0.2486572265625 +8106 -0.002044677734375 +8107 -0.2587890625 +8108 -0.00213623046875 +8109 -0.268890380859375 +8110 -0.002227783203125 +8111 -0.278961181640625 +8112 -0.002288818359375 +8113 -0.28900146484375 +8114 -0.00238037109375 +8115 -0.29901123046875 +8116 -0.00244140625 +8117 -0.308990478515625 +8118 -0.002532958984375 +8119 -0.318939208984375 +8120 -0.00262451171875 +8121 -0.328826904296875 +8122 -0.002685546875 +8123 -0.338714599609375 +8124 -0.002777099609375 +8125 -0.348541259765625 +8126 -0.002838134765625 +8127 -0.35833740234375 +8128 -0.0029296875 +8129 -0.36810302734375 +8130 -0.00299072265625 +8131 -0.3778076171875 +8132 -0.003082275390625 +8133 -0.387481689453125 +8134 -0.003173828125 +8135 -0.397125244140625 +8136 -0.00323486328125 +8137 -0.406707763671875 +8138 -0.003326416015625 +8139 -0.416259765625 +8140 -0.003387451171875 +8141 -0.425750732421875 +8142 -0.00347900390625 +8143 -0.435211181640625 +8144 -0.0035400390625 +8145 -0.444610595703125 +8146 -0.00360107421875 +8147 -0.453948974609375 +8148 -0.003692626953125 +8149 -0.4632568359375 +8150 -0.003753662109375 +8151 -0.4725341796875 +8152 -0.00384521484375 +8153 -0.481719970703125 +8154 -0.00390625 +8155 -0.490875244140625 +8156 -0.00396728515625 +8157 -0.499969482421875 +8158 -0.004058837890625 +8159 -0.509002685546875 +8160 -0.004119873046875 +8161 -0.51800537109375 +8162 -0.00421142578125 +8163 -0.52691650390625 +8164 -0.0042724609375 +8165 -0.535797119140625 +8166 -0.00433349609375 +8167 -0.54461669921875 +8168 -0.00439453125 +8169 -0.5533447265625 +8170 -0.004486083984375 +8171 -0.562042236328125 +8172 -0.004547119140625 +8173 -0.5706787109375 +8174 -0.004608154296875 +8175 -0.579254150390625 +8176 -0.004669189453125 +8177 -0.587738037109375 +8178 -0.0047607421875 +8179 -0.59619140625 +8180 -0.00482177734375 +8181 -0.60455322265625 +8182 -0.0048828125 +8183 -0.612884521484375 +8184 -0.00494384765625 +8185 -0.621124267578125 +8186 -0.0050048828125 +8187 -0.6292724609375 +8188 -0.005096435546875 +8189 -0.63739013671875 +8190 -0.005157470703125 +8191 -0.645416259765625 +8192 -0.015655517578125 +8193 -0.65338134765625 +8194 -0.015838623046875 +8195 -0.661285400390625 +8196 -0.016021728515625 +8197 -0.669097900390625 +8198 -0.0162353515625 +8199 -0.676849365234375 +8200 -0.01641845703125 +8201 -0.68450927734375 +8202 -0.0166015625 +8203 -0.692108154296875 +8204 -0.016754150390625 +8205 -0.699615478515625 +8206 -0.016937255859375 +8207 -0.707061767578125 +8208 -0.017120361328125 +8209 -0.714447021484375 +8210 -0.017303466796875 +8211 -0.721710205078125 +8212 -0.0174560546875 +8213 -0.72894287109375 +8214 -0.01763916015625 +8215 -0.736053466796875 +8216 -0.017822265625 +8217 -0.74310302734375 +8218 -0.017974853515625 +8219 -0.75006103515625 +8220 -0.01812744140625 +8221 -0.7569580078125 +8222 -0.018310546875 +8223 -0.763763427734375 +8224 -0.018463134765625 +8225 -0.770477294921875 +8226 -0.01861572265625 +8227 -0.777099609375 +8228 -0.018768310546875 +8229 -0.783660888671875 +8230 -0.018951416015625 +8231 -0.790130615234375 +8232 -0.01910400390625 +8233 -0.796478271484375 +8234 -0.01922607421875 +8235 -0.802764892578125 +8236 -0.019378662109375 +8237 -0.808990478515625 +8238 -0.01953125 +8239 -0.815093994140625 +8240 -0.019683837890625 +8241 -0.82110595703125 +8242 -0.01983642578125 +8243 -0.8270263671875 +8244 -0.01995849609375 +8245 -0.8328857421875 +8246 -0.020111083984375 +8247 -0.838623046875 +8248 -0.020233154296875 +8249 -0.84429931640625 +8250 -0.0203857421875 +8251 -0.849853515625 +8252 -0.0205078125 +8253 -0.855316162109375 +8254 -0.0206298828125 +8255 -0.860687255859375 +8256 -0.020751953125 +8257 -0.865997314453125 +8258 -0.0208740234375 +8259 -0.871185302734375 +8260 -0.02099609375 +8261 -0.876251220703125 +8262 -0.0211181640625 +8263 -0.881256103515625 +8264 -0.021240234375 +8265 -0.88616943359375 +8266 -0.0213623046875 +8267 -0.890960693359375 +8268 -0.021484375 +8269 -0.895660400390625 +8270 -0.021575927734375 +8271 -0.9002685546875 +8272 -0.021697998046875 +8273 -0.90478515625 +8274 -0.02178955078125 +8275 -0.9091796875 +8276 -0.02191162109375 +8277 -0.91351318359375 +8278 -0.022003173828125 +8279 -0.917724609375 +8280 -0.0220947265625 +8281 -0.92181396484375 +8282 -0.022186279296875 +8283 -0.92584228515625 +8284 -0.02227783203125 +8285 -0.929718017578125 +8286 -0.022369384765625 +8287 -0.93353271484375 +8288 -0.0224609375 +8289 -0.937225341796875 +8290 -0.022552490234375 +8291 -0.940826416015625 +8292 -0.02264404296875 +8293 -0.9443359375 +8294 -0.022705078125 +8295 -0.947723388671875 +8296 -0.022796630859375 +8297 -0.951019287109375 +8298 -0.02288818359375 +8299 -0.954193115234375 +8300 -0.02294921875 +8301 -0.957275390625 +8302 -0.02301025390625 +8303 -0.960235595703125 +8304 -0.023101806640625 +8305 -0.963104248046875 +8306 -0.023162841796875 +8307 -0.96588134765625 +8308 -0.023223876953125 +8309 -0.968536376953125 +8310 -0.023284912109375 +8311 -0.971099853515625 +8312 -0.023345947265625 +8313 -0.973541259765625 +8314 -0.023406982421875 +8315 -0.975860595703125 +8316 -0.0234375 +8317 -0.97808837890625 +8318 -0.02349853515625 +8319 -0.980224609375 +8320 -0.0235595703125 +8321 -0.98223876953125 +8322 -0.023590087890625 +8323 -0.984161376953125 +8324 -0.02362060546875 +8325 -0.9859619140625 +8326 -0.023681640625 +8327 -0.987640380859375 +8328 -0.023712158203125 +8329 -0.989227294921875 +8330 -0.02374267578125 +8331 -0.990692138671875 +8332 -0.023773193359375 +8333 -0.9920654296875 +8334 -0.0238037109375 +8335 -0.993316650390625 +8336 -0.023834228515625 +8337 -0.994476318359375 +8338 -0.02386474609375 +8339 -0.995513916015625 +8340 -0.023895263671875 +8341 -0.9964599609375 +8342 -0.023895263671875 +8343 -0.997283935546875 +8344 -0.02392578125 +8345 -0.99798583984375 +8346 -0.02392578125 +8347 -0.99859619140625 +8348 -0.023956298828125 +8349 -0.999114990234375 +8350 -0.023956298828125 +8351 -0.999481201171875 +8352 -0.023956298828125 +8353 -0.999755859375 +8354 -0.023956298828125 +8355 -0.99993896484375 +8356 -0.02398681640625 +8357 -1.0 +8358 -0.023956298828125 +8359 -0.99993896484375 +8360 -0.023956298828125 +8361 -0.999755859375 +8362 -0.023956298828125 +8363 -0.999481201171875 +8364 -0.023956298828125 +8365 -0.999114990234375 +8366 -0.02392578125 +8367 -0.99859619140625 +8368 -0.02392578125 +8369 -0.99798583984375 +8370 -0.023895263671875 +8371 -0.997283935546875 +8372 -0.023895263671875 +8373 -0.9964599609375 +8374 -0.02386474609375 +8375 -0.995513916015625 +8376 -0.023834228515625 +8377 -0.994476318359375 +8378 -0.0238037109375 +8379 -0.993316650390625 +8380 -0.023773193359375 +8381 -0.9920654296875 +8382 -0.02374267578125 +8383 -0.990692138671875 +8384 -0.023712158203125 +8385 -0.989227294921875 +8386 -0.023681640625 +8387 -0.987640380859375 +8388 -0.02362060546875 +8389 -0.9859619140625 +8390 -0.023590087890625 +8391 -0.984161376953125 +8392 -0.0235595703125 +8393 -0.98223876953125 +8394 -0.02349853515625 +8395 -0.980224609375 +8396 -0.0234375 +8397 -0.97808837890625 +8398 -0.023406982421875 +8399 -0.975860595703125 +8400 -0.023345947265625 +8401 -0.973541259765625 +8402 -0.023284912109375 +8403 -0.971099853515625 +8404 -0.023223876953125 +8405 -0.968536376953125 +8406 -0.023162841796875 +8407 -0.96588134765625 +8408 -0.023101806640625 +8409 -0.963104248046875 +8410 -0.02301025390625 +8411 -0.960235595703125 +8412 -0.02294921875 +8413 -0.957275390625 +8414 -0.02288818359375 +8415 -0.954193115234375 +8416 -0.022796630859375 +8417 -0.951019287109375 +8418 -0.022705078125 +8419 -0.947723388671875 +8420 -0.02264404296875 +8421 -0.9443359375 +8422 -0.022552490234375 +8423 -0.940826416015625 +8424 -0.0224609375 +8425 -0.937225341796875 +8426 -0.022369384765625 +8427 -0.93353271484375 +8428 -0.02227783203125 +8429 -0.929718017578125 +8430 -0.022186279296875 +8431 -0.92584228515625 +8432 -0.0220947265625 +8433 -0.92181396484375 +8434 -0.022003173828125 +8435 -0.917724609375 +8436 -0.02191162109375 +8437 -0.91351318359375 +8438 -0.02178955078125 +8439 -0.9091796875 +8440 -0.021697998046875 +8441 -0.90478515625 +8442 -0.021575927734375 +8443 -0.9002685546875 +8444 -0.021484375 +8445 -0.895660400390625 +8446 -0.0213623046875 +8447 -0.890960693359375 +8448 -0.044281005859375 +8449 -0.88616943359375 +8450 -0.044036865234375 +8451 -0.881256103515625 +8452 -0.043792724609375 +8453 -0.876251220703125 +8454 -0.043548583984375 +8455 -0.871185302734375 +8456 -0.04327392578125 +8457 -0.865997314453125 +8458 -0.042999267578125 +8459 -0.860687255859375 +8460 -0.042755126953125 +8461 -0.855316162109375 +8462 -0.04248046875 +8463 -0.849853515625 +8464 -0.042205810546875 +8465 -0.84429931640625 +8466 -0.041900634765625 +8467 -0.838623046875 +8468 -0.0416259765625 +8469 -0.8328857421875 +8470 -0.04132080078125 +8471 -0.8270263671875 +8472 -0.041046142578125 +8473 -0.82110595703125 +8474 -0.040740966796875 +8475 -0.815093994140625 +8476 -0.040435791015625 +8477 -0.808990478515625 +8478 -0.04010009765625 +8479 -0.802764892578125 +8480 -0.039794921875 +8481 -0.796478271484375 +8482 -0.03948974609375 +8483 -0.790130615234375 +8484 -0.039154052734375 +8485 -0.783660888671875 +8486 -0.038818359375 +8487 -0.777099609375 +8488 -0.03851318359375 +8489 -0.770477294921875 +8490 -0.038177490234375 +8491 -0.763763427734375 +8492 -0.037811279296875 +8493 -0.7569580078125 +8494 -0.0374755859375 +8495 -0.75006103515625 +8496 -0.037139892578125 +8497 -0.74310302734375 +8498 -0.036773681640625 +8499 -0.736053466796875 +8500 -0.03643798828125 +8501 -0.72894287109375 +8502 -0.03607177734375 +8503 -0.721710205078125 +8504 -0.03570556640625 +8505 -0.714447021484375 +8506 -0.03533935546875 +8507 -0.707061767578125 +8508 -0.03497314453125 +8509 -0.699615478515625 +8510 -0.034576416015625 +8511 -0.692108154296875 +8512 -0.034210205078125 +8513 -0.68450927734375 +8514 -0.0338134765625 +8515 -0.676849365234375 +8516 -0.033447265625 +8517 -0.669097900390625 +8518 -0.033050537109375 +8519 -0.661285400390625 +8520 -0.03265380859375 +8521 -0.65338134765625 +8522 -0.032257080078125 +8523 -0.645416259765625 +8524 -0.0318603515625 +8525 -0.63739013671875 +8526 -0.03143310546875 +8527 -0.6292724609375 +8528 -0.031036376953125 +8529 -0.621124267578125 +8530 -0.030609130859375 +8531 -0.612884521484375 +8532 -0.03021240234375 +8533 -0.60455322265625 +8534 -0.02978515625 +8535 -0.59619140625 +8536 -0.02935791015625 +8537 -0.587738037109375 +8538 -0.0289306640625 +8539 -0.579254150390625 +8540 -0.02850341796875 +8541 -0.5706787109375 +8542 -0.028076171875 +8543 -0.562042236328125 +8544 -0.02764892578125 +8545 -0.5533447265625 +8546 -0.0272216796875 +8547 -0.54461669921875 +8548 -0.026763916015625 +8549 -0.535797119140625 +8550 -0.026336669921875 +8551 -0.52691650390625 +8552 -0.02587890625 +8553 -0.51800537109375 +8554 -0.025421142578125 +8555 -0.509002685546875 +8556 -0.02496337890625 +8557 -0.499969482421875 +8558 -0.0245361328125 +8559 -0.490875244140625 +8560 -0.024078369140625 +8561 -0.481719970703125 +8562 -0.02362060546875 +8563 -0.4725341796875 +8564 -0.02313232421875 +8565 -0.4632568359375 +8566 -0.022674560546875 +8567 -0.453948974609375 +8568 -0.022216796875 +8569 -0.444610595703125 +8570 -0.021728515625 +8571 -0.435211181640625 +8572 -0.021270751953125 +8573 -0.425750732421875 +8574 -0.020782470703125 +8575 -0.416259765625 +8576 -0.02032470703125 +8577 -0.406707763671875 +8578 -0.01983642578125 +8579 -0.397125244140625 +8580 -0.01934814453125 +8581 -0.387481689453125 +8582 -0.01885986328125 +8583 -0.3778076171875 +8584 -0.01837158203125 +8585 -0.36810302734375 +8586 -0.01788330078125 +8587 -0.35833740234375 +8588 -0.01739501953125 +8589 -0.348541259765625 +8590 -0.01690673828125 +8591 -0.338714599609375 +8592 -0.01641845703125 +8593 -0.328826904296875 +8594 -0.01593017578125 +8595 -0.318939208984375 +8596 -0.01544189453125 +8597 -0.308990478515625 +8598 -0.014923095703125 +8599 -0.29901123046875 +8600 -0.014434814453125 +8601 -0.28900146484375 +8602 -0.013916015625 +8603 -0.278961181640625 +8604 -0.013427734375 +8605 -0.268890380859375 +8606 -0.012908935546875 +8607 -0.2587890625 +8608 -0.012420654296875 +8609 -0.2486572265625 +8610 -0.01190185546875 +8611 -0.238525390625 +8612 -0.01141357421875 +8613 -0.22833251953125 +8614 -0.010894775390625 +8615 -0.218109130859375 +8616 -0.0103759765625 +8617 -0.2078857421875 +8618 -0.009857177734375 +8619 -0.1976318359375 +8620 -0.00933837890625 +8621 -0.187347412109375 +8622 -0.00885009765625 +8623 -0.17706298828125 +8624 -0.008331298828125 +8625 -0.166748046875 +8626 -0.0078125 +8627 -0.156402587890625 +8628 -0.007293701171875 +8629 -0.14605712890625 +8630 -0.00677490234375 +8631 -0.13568115234375 +8632 -0.006256103515625 +8633 -0.12530517578125 +8634 -0.0057373046875 +8635 -0.11492919921875 +8636 -0.005218505859375 +8637 -0.104522705078125 +8638 -0.00469970703125 +8639 -0.094085693359375 +8640 -0.004180908203125 +8641 -0.083648681640625 +8642 -0.003631591796875 +8643 -0.073211669921875 +8644 -0.00311279296875 +8645 -0.062774658203125 +8646 -0.002593994140625 +8647 -0.05230712890625 +8648 -0.0020751953125 +8649 -0.0418701171875 +8650 -0.001556396484375 +8651 -0.031402587890625 +8652 -0.00103759765625 +8653 -0.02093505859375 +8654 -0.000518798828125 +8655 -0.010467529296875 +8656 0.0 +8657 0.0 +8658 0.000579833984375 +8659 0.010467529296875 +8660 0.00115966796875 +8661 0.02093505859375 +8662 0.001739501953125 +8663 0.031402587890625 +8664 0.0023193359375 +8665 0.0418701171875 +8666 0.002899169921875 +8667 0.05230712890625 +8668 0.003509521484375 +8669 0.062774658203125 +8670 0.00408935546875 +8671 0.073211669921875 +8672 0.004669189453125 +8673 0.083648681640625 +8674 0.0052490234375 +8675 0.094085693359375 +8676 0.005828857421875 +8677 0.104522705078125 +8678 0.00640869140625 +8679 0.11492919921875 +8680 0.006988525390625 +8681 0.12530517578125 +8682 0.007568359375 +8683 0.13568115234375 +8684 0.0081787109375 +8685 0.14605712890625 +8686 0.008758544921875 +8687 0.156402587890625 +8688 0.009307861328125 +8689 0.166748046875 +8690 0.0098876953125 +8691 0.17706298828125 +8692 0.010467529296875 +8693 0.187347412109375 +8694 0.01104736328125 +8695 0.1976318359375 +8696 0.011627197265625 +8697 0.2078857421875 +8698 0.01220703125 +8699 0.218109130859375 +8700 0.012786865234375 +8701 0.22833251953125 +8702 0.013336181640625 +8703 0.238525390625 +8704 0.0218505859375 +8705 0.2486572265625 +8706 0.02276611328125 +8707 0.2587890625 +8708 0.023651123046875 +8709 0.268890380859375 +8710 0.0245361328125 +8711 0.278961181640625 +8712 0.025421142578125 +8713 0.28900146484375 +8714 0.02630615234375 +8715 0.29901123046875 +8716 0.02716064453125 +8717 0.308990478515625 +8718 0.028045654296875 +8719 0.318939208984375 +8720 0.0289306640625 +8721 0.328826904296875 +8722 0.02978515625 +8723 0.338714599609375 +8724 0.0306396484375 +8725 0.348541259765625 +8726 0.031524658203125 +8727 0.35833740234375 +8728 0.032379150390625 +8729 0.36810302734375 +8730 0.033233642578125 +8731 0.3778076171875 +8732 0.034088134765625 +8733 0.387481689453125 +8734 0.034912109375 +8735 0.397125244140625 +8736 0.0357666015625 +8737 0.406707763671875 +8738 0.03662109375 +8739 0.416259765625 +8740 0.037445068359375 +8741 0.425750732421875 +8742 0.03826904296875 +8743 0.435211181640625 +8744 0.039093017578125 +8745 0.444610595703125 +8746 0.0399169921875 +8747 0.453948974609375 +8748 0.040740966796875 +8749 0.4632568359375 +8750 0.04156494140625 +8751 0.4725341796875 +8752 0.0423583984375 +8753 0.481719970703125 +8754 0.043182373046875 +8755 0.490875244140625 +8756 0.043975830078125 +8757 0.499969482421875 +8758 0.044769287109375 +8759 0.509002685546875 +8760 0.045562744140625 +8761 0.51800537109375 +8762 0.046356201171875 +8763 0.52691650390625 +8764 0.047119140625 +8765 0.535797119140625 +8766 0.04791259765625 +8767 0.54461669921875 +8768 0.048675537109375 +8769 0.5533447265625 +8770 0.0494384765625 +8771 0.562042236328125 +8772 0.050201416015625 +8773 0.5706787109375 +8774 0.05096435546875 +8775 0.579254150390625 +8776 0.05169677734375 +8777 0.587738037109375 +8778 0.05242919921875 +8779 0.59619140625 +8780 0.05316162109375 +8781 0.60455322265625 +8782 0.053924560546875 +8783 0.612884521484375 +8784 0.05462646484375 +8785 0.621124267578125 +8786 0.05535888671875 +8787 0.6292724609375 +8788 0.056060791015625 +8789 0.63739013671875 +8790 0.0567626953125 +8791 0.645416259765625 +8792 0.057464599609375 +8793 0.65338134765625 +8794 0.05816650390625 +8795 0.661285400390625 +8796 0.058868408203125 +8797 0.669097900390625 +8798 0.059539794921875 +8799 0.676849365234375 +8800 0.060211181640625 +8801 0.68450927734375 +8802 0.060882568359375 +8803 0.692108154296875 +8804 0.061553955078125 +8805 0.699615478515625 +8806 0.06219482421875 +8807 0.707061767578125 +8808 0.062835693359375 +8809 0.714447021484375 +8810 0.0634765625 +8811 0.721710205078125 +8812 0.064117431640625 +8813 0.72894287109375 +8814 0.06475830078125 +8815 0.736053466796875 +8816 0.06536865234375 +8817 0.74310302734375 +8818 0.06597900390625 +8819 0.75006103515625 +8820 0.06658935546875 +8821 0.7569580078125 +8822 0.067169189453125 +8823 0.763763427734375 +8824 0.067779541015625 +8825 0.770477294921875 +8826 0.068359375 +8827 0.777099609375 +8828 0.068939208984375 +8829 0.783660888671875 +8830 0.06951904296875 +8831 0.790130615234375 +8832 0.070068359375 +8833 0.796478271484375 +8834 0.07061767578125 +8835 0.802764892578125 +8836 0.0711669921875 +8837 0.808990478515625 +8838 0.071685791015625 +8839 0.815093994140625 +8840 0.072235107421875 +8841 0.82110595703125 +8842 0.07275390625 +8843 0.8270263671875 +8844 0.073272705078125 +8845 0.8328857421875 +8846 0.073760986328125 +8847 0.838623046875 +8848 0.07427978515625 +8849 0.84429931640625 +8850 0.07476806640625 +8851 0.849853515625 +8852 0.075225830078125 +8853 0.855316162109375 +8854 0.075714111328125 +8855 0.860687255859375 +8856 0.076171875 +8857 0.865997314453125 +8858 0.076629638671875 +8859 0.871185302734375 +8860 0.07708740234375 +8861 0.876251220703125 +8862 0.0775146484375 +8863 0.881256103515625 +8864 0.07794189453125 +8865 0.88616943359375 +8866 0.078369140625 +8867 0.890960693359375 +8868 0.07879638671875 +8869 0.895660400390625 +8870 0.079193115234375 +8871 0.9002685546875 +8872 0.07958984375 +8873 0.90478515625 +8874 0.079986572265625 +8875 0.9091796875 +8876 0.080352783203125 +8877 0.91351318359375 +8878 0.080718994140625 +8879 0.917724609375 +8880 0.081085205078125 +8881 0.92181396484375 +8882 0.081451416015625 +8883 0.92584228515625 +8884 0.081787109375 +8885 0.929718017578125 +8886 0.082122802734375 +8887 0.93353271484375 +8888 0.08245849609375 +8889 0.937225341796875 +8890 0.082763671875 +8891 0.940826416015625 +8892 0.08306884765625 +8893 0.9443359375 +8894 0.0833740234375 +8895 0.947723388671875 +8896 0.083648681640625 +8897 0.951019287109375 +8898 0.083953857421875 +8899 0.954193115234375 +8900 0.084197998046875 +8901 0.957275390625 +8902 0.08447265625 +8903 0.960235595703125 +8904 0.084716796875 +8905 0.963104248046875 +8906 0.0849609375 +8907 0.96588134765625 +8908 0.085205078125 +8909 0.968536376953125 +8910 0.085418701171875 +8911 0.971099853515625 +8912 0.08563232421875 +8913 0.973541259765625 +8914 0.085845947265625 +8915 0.975860595703125 +8916 0.086029052734375 +8917 0.97808837890625 +8918 0.08624267578125 +8919 0.980224609375 +8920 0.086395263671875 +8921 0.98223876953125 +8922 0.086578369140625 +8923 0.984161376953125 +8924 0.08673095703125 +8925 0.9859619140625 +8926 0.086883544921875 +8927 0.987640380859375 +8928 0.0870361328125 +8929 0.989227294921875 +8930 0.087158203125 +8931 0.990692138671875 +8932 0.0872802734375 +8933 0.9920654296875 +8934 0.087371826171875 +8935 0.993316650390625 +8936 0.087493896484375 +8937 0.994476318359375 +8938 0.08758544921875 +8939 0.995513916015625 +8940 0.087646484375 +8941 0.9964599609375 +8942 0.087738037109375 +8943 0.997283935546875 +8944 0.087799072265625 +8945 0.99798583984375 +8946 0.087860107421875 +8947 0.99859619140625 +8948 0.087890625 +8949 0.999114990234375 +8950 0.087921142578125 +8951 0.999481201171875 +8952 0.08795166015625 +8953 0.999755859375 +8954 0.08795166015625 +8955 0.99993896484375 +8956 0.087982177734375 +8957 0.999969482421875 +8958 0.08795166015625 +8959 0.99993896484375 +8960 0.119964599609375 +8961 0.999755859375 +8962 0.119903564453125 +8963 0.999481201171875 +8964 0.119873046875 +8965 0.999114990234375 +8966 0.11981201171875 +8967 0.99859619140625 +8968 0.1197509765625 +8969 0.99798583984375 +8970 0.119659423828125 +8971 0.997283935546875 +8972 0.11956787109375 +8973 0.9964599609375 +8974 0.11944580078125 +8975 0.995513916015625 +8976 0.11932373046875 +8977 0.994476318359375 +8978 0.119171142578125 +8979 0.993316650390625 +8980 0.1190185546875 +8981 0.9920654296875 +8982 0.118865966796875 +8983 0.990692138671875 +8984 0.118682861328125 +8985 0.989227294921875 +8986 0.118499755859375 +8987 0.987640380859375 +8988 0.1182861328125 +8989 0.9859619140625 +8990 0.118072509765625 +8991 0.984161376953125 +8992 0.11785888671875 +8993 0.98223876953125 +8994 0.11761474609375 +8995 0.980224609375 +8996 0.117340087890625 +8997 0.97808837890625 +8998 0.117095947265625 +8999 0.975860595703125 +9000 0.1168212890625 +9001 0.973541259765625 +9002 0.11651611328125 +9003 0.971099853515625 +9004 0.1162109375 +9005 0.968536376953125 +9006 0.115875244140625 +9007 0.96588134765625 +9008 0.115570068359375 +9009 0.963104248046875 +9010 0.115203857421875 +9011 0.960235595703125 +9012 0.1148681640625 +9013 0.957275390625 +9014 0.114501953125 +9015 0.954193115234375 +9016 0.114105224609375 +9017 0.951019287109375 +9018 0.11370849609375 +9019 0.947723388671875 +9020 0.113311767578125 +9021 0.9443359375 +9022 0.112884521484375 +9023 0.940826416015625 +9024 0.112457275390625 +9025 0.937225341796875 +9026 0.11199951171875 +9027 0.93353271484375 +9028 0.111541748046875 +9029 0.929718017578125 +9030 0.111083984375 +9031 0.92584228515625 +9032 0.110595703125 +9033 0.92181396484375 +9034 0.110107421875 +9035 0.917724609375 +9036 0.109619140625 +9037 0.91351318359375 +9038 0.109100341796875 +9039 0.9091796875 +9040 0.108551025390625 +9041 0.90478515625 +9042 0.108001708984375 +9043 0.9002685546875 +9044 0.107452392578125 +9045 0.895660400390625 +9046 0.106903076171875 +9047 0.890960693359375 +9048 0.1063232421875 +9049 0.88616943359375 +9050 0.105743408203125 +9051 0.881256103515625 +9052 0.105133056640625 +9053 0.876251220703125 +9054 0.104522705078125 +9055 0.871185302734375 +9056 0.103912353515625 +9057 0.865997314453125 +9058 0.103271484375 +9059 0.860687255859375 +9060 0.102630615234375 +9061 0.855316162109375 +9062 0.101959228515625 +9063 0.849853515625 +9064 0.101287841796875 +9065 0.84429931640625 +9066 0.100616455078125 +9067 0.838623046875 +9068 0.099945068359375 +9069 0.8328857421875 +9070 0.099212646484375 +9071 0.8270263671875 +9072 0.0985107421875 +9073 0.82110595703125 +9074 0.097808837890625 +9075 0.815093994140625 +9076 0.097076416015625 +9077 0.808990478515625 +9078 0.0963134765625 +9079 0.802764892578125 +9080 0.095550537109375 +9081 0.796478271484375 +9082 0.09478759765625 +9083 0.790130615234375 +9084 0.094024658203125 +9085 0.783660888671875 +9086 0.093231201171875 +9087 0.777099609375 +9088 0.092437744140625 +9089 0.770477294921875 +9090 0.091644287109375 +9091 0.763763427734375 +9092 0.0908203125 +9093 0.7569580078125 +9094 0.089996337890625 +9095 0.75006103515625 +9096 0.089141845703125 +9097 0.74310302734375 +9098 0.08831787109375 +9099 0.736053466796875 +9100 0.08746337890625 +9101 0.72894287109375 +9102 0.086578369140625 +9103 0.721710205078125 +9104 0.085723876953125 +9105 0.714447021484375 +9106 0.0848388671875 +9107 0.707061767578125 +9108 0.08392333984375 +9109 0.699615478515625 +9110 0.083038330078125 +9111 0.692108154296875 +9112 0.082122802734375 +9113 0.68450927734375 +9114 0.081207275390625 +9115 0.676849365234375 +9116 0.08026123046875 +9117 0.669097900390625 +9118 0.079345703125 +9119 0.661285400390625 +9120 0.078399658203125 +9121 0.65338134765625 +9122 0.077423095703125 +9123 0.645416259765625 +9124 0.07647705078125 +9125 0.63739013671875 +9126 0.07550048828125 +9127 0.6292724609375 +9128 0.07452392578125 +9129 0.621124267578125 +9130 0.073516845703125 +9131 0.612884521484375 +9132 0.072540283203125 +9133 0.60455322265625 +9134 0.071533203125 +9135 0.59619140625 +9136 0.070526123046875 +9137 0.587738037109375 +9138 0.069488525390625 +9139 0.579254150390625 +9140 0.068450927734375 +9141 0.5706787109375 +9142 0.06744384765625 +9143 0.562042236328125 +9144 0.066375732421875 +9145 0.5533447265625 +9146 0.065338134765625 +9147 0.54461669921875 +9148 0.06427001953125 +9149 0.535797119140625 +9150 0.063201904296875 +9151 0.52691650390625 +9152 0.0621337890625 +9153 0.51800537109375 +9154 0.061065673828125 +9155 0.509002685546875 +9156 0.059967041015625 +9157 0.499969482421875 +9158 0.05889892578125 +9159 0.490875244140625 +9160 0.05780029296875 +9161 0.481719970703125 +9162 0.05670166015625 +9163 0.4725341796875 +9164 0.055572509765625 +9165 0.4632568359375 +9166 0.054443359375 +9167 0.453948974609375 +9168 0.0533447265625 +9169 0.444610595703125 +9170 0.052215576171875 +9171 0.435211181640625 +9172 0.05108642578125 +9173 0.425750732421875 +9174 0.0499267578125 +9175 0.416259765625 +9176 0.048797607421875 +9177 0.406707763671875 +9178 0.047637939453125 +9179 0.397125244140625 +9180 0.046478271484375 +9181 0.387481689453125 +9182 0.045318603515625 +9183 0.3778076171875 +9184 0.044158935546875 +9185 0.36810302734375 +9186 0.042999267578125 +9187 0.35833740234375 +9188 0.04180908203125 +9189 0.348541259765625 +9190 0.040618896484375 +9191 0.338714599609375 +9192 0.0394287109375 +9193 0.328826904296875 +9194 0.03826904296875 +9195 0.318939208984375 +9196 0.03704833984375 +9197 0.308990478515625 +9198 0.035858154296875 +9199 0.29901123046875 +9200 0.03466796875 +9201 0.28900146484375 +9202 0.033447265625 +9203 0.278961181640625 +9204 0.032257080078125 +9205 0.268890380859375 +9206 0.031036376953125 +9207 0.2587890625 +9208 0.029815673828125 +9209 0.2486572265625 +9210 0.028594970703125 +9211 0.238525390625 +9212 0.027374267578125 +9213 0.22833251953125 +9214 0.026153564453125 +9215 0.218109130859375 +9216 0.031585693359375 +9217 0.2078857421875 +9218 0.030029296875 +9219 0.1976318359375 +9220 0.028472900390625 +9221 0.187347412109375 +9222 0.026885986328125 +9223 0.17706298828125 +9224 0.02532958984375 +9225 0.166748046875 +9226 0.023773193359375 +9227 0.156402587890625 +9228 0.022186279296875 +9229 0.14605712890625 +9230 0.020599365234375 +9231 0.13568115234375 +9232 0.01904296875 +9233 0.12530517578125 +9234 0.0174560546875 +9235 0.11492919921875 +9236 0.015869140625 +9237 0.104522705078125 +9238 0.0142822265625 +9239 0.094085693359375 +9240 0.0126953125 +9241 0.083648681640625 +9242 0.0111083984375 +9243 0.073211669921875 +9244 0.009521484375 +9245 0.062774658203125 +9246 0.0079345703125 +9247 0.05230712890625 +9248 0.00634765625 +9249 0.0418701171875 +9250 0.0047607421875 +9251 0.031402587890625 +9252 0.003173828125 +9253 0.02093505859375 +9254 0.0015869140625 +9255 0.010467529296875 +9256 0.0 +9257 0.0 +9258 -0.0015869140625 +9259 -0.010467529296875 +9260 -0.003173828125 +9261 -0.02093505859375 +9262 -0.0047607421875 +9263 -0.031402587890625 +9264 -0.00634765625 +9265 -0.0418701171875 +9266 -0.0079345703125 +9267 -0.05230712890625 +9268 -0.009521484375 +9269 -0.062774658203125 +9270 -0.0111083984375 +9271 -0.073211669921875 +9272 -0.0126953125 +9273 -0.083648681640625 +9274 -0.0142822265625 +9275 -0.094085693359375 +9276 -0.015869140625 +9277 -0.104522705078125 +9278 -0.0174560546875 +9279 -0.11492919921875 +9280 -0.01904296875 +9281 -0.12530517578125 +9282 -0.020599365234375 +9283 -0.13568115234375 +9284 -0.022186279296875 +9285 -0.14605712890625 +9286 -0.023773193359375 +9287 -0.156402587890625 +9288 -0.02532958984375 +9289 -0.166748046875 +9290 -0.026885986328125 +9291 -0.17706298828125 +9292 -0.028472900390625 +9293 -0.187347412109375 +9294 -0.030029296875 +9295 -0.1976318359375 +9296 -0.031585693359375 +9297 -0.2078857421875 +9298 -0.03314208984375 +9299 -0.218109130859375 +9300 -0.034698486328125 +9301 -0.22833251953125 +9302 -0.0362548828125 +9303 -0.238525390625 +9304 -0.03778076171875 +9305 -0.2486572265625 +9306 -0.039337158203125 +9307 -0.2587890625 +9308 -0.040863037109375 +9309 -0.268890380859375 +9310 -0.042388916015625 +9311 -0.278961181640625 +9312 -0.043914794921875 +9313 -0.28900146484375 +9314 -0.045440673828125 +9315 -0.29901123046875 +9316 -0.046966552734375 +9317 -0.308990478515625 +9318 -0.0484619140625 +9319 -0.318939208984375 +9320 -0.049957275390625 +9321 -0.328826904296875 +9322 -0.051483154296875 +9323 -0.338714599609375 +9324 -0.052978515625 +9325 -0.348541259765625 +9326 -0.054443359375 +9327 -0.35833740234375 +9328 -0.055938720703125 +9329 -0.36810302734375 +9330 -0.057403564453125 +9331 -0.3778076171875 +9332 -0.05889892578125 +9333 -0.387481689453125 +9334 -0.06036376953125 +9335 -0.397125244140625 +9336 -0.061798095703125 +9337 -0.406707763671875 +9338 -0.063262939453125 +9339 -0.416259765625 +9340 -0.064697265625 +9341 -0.425750732421875 +9342 -0.066131591796875 +9343 -0.435211181640625 +9344 -0.06756591796875 +9345 -0.444610595703125 +9346 -0.069000244140625 +9347 -0.453948974609375 +9348 -0.070404052734375 +9349 -0.4632568359375 +9350 -0.071807861328125 +9351 -0.4725341796875 +9352 -0.073211669921875 +9353 -0.481719970703125 +9354 -0.074615478515625 +9355 -0.490875244140625 +9356 -0.07598876953125 +9357 -0.499969482421875 +9358 -0.077362060546875 +9359 -0.509002685546875 +9360 -0.0787353515625 +9361 -0.51800537109375 +9362 -0.080078125 +9363 -0.52691650390625 +9364 -0.0814208984375 +9365 -0.535797119140625 +9366 -0.082763671875 +9367 -0.54461669921875 +9368 -0.0841064453125 +9369 -0.5533447265625 +9370 -0.085418701171875 +9371 -0.562042236328125 +9372 -0.08673095703125 +9373 -0.5706787109375 +9374 -0.088043212890625 +9375 -0.579254150390625 +9376 -0.089324951171875 +9377 -0.587738037109375 +9378 -0.090606689453125 +9379 -0.59619140625 +9380 -0.091888427734375 +9381 -0.60455322265625 +9382 -0.0931396484375 +9383 -0.612884521484375 +9384 -0.094390869140625 +9385 -0.621124267578125 +9386 -0.09564208984375 +9387 -0.6292724609375 +9388 -0.09686279296875 +9389 -0.63739013671875 +9390 -0.09808349609375 +9391 -0.645416259765625 +9392 -0.09930419921875 +9393 -0.65338134765625 +9394 -0.100494384765625 +9395 -0.661285400390625 +9396 -0.1016845703125 +9397 -0.669097900390625 +9398 -0.102874755859375 +9399 -0.676849365234375 +9400 -0.104034423828125 +9401 -0.68450927734375 +9402 -0.105194091796875 +9403 -0.692108154296875 +9404 -0.1063232421875 +9405 -0.699615478515625 +9406 -0.107452392578125 +9407 -0.707061767578125 +9408 -0.10858154296875 +9409 -0.714447021484375 +9410 -0.10968017578125 +9411 -0.721710205078125 +9412 -0.11077880859375 +9413 -0.72894287109375 +9414 -0.11187744140625 +9415 -0.736053466796875 +9416 -0.112945556640625 +9417 -0.74310302734375 +9418 -0.114013671875 +9419 -0.75006103515625 +9420 -0.11505126953125 +9421 -0.7569580078125 +9422 -0.1160888671875 +9423 -0.763763427734375 +9424 -0.117095947265625 +9425 -0.770477294921875 +9426 -0.11810302734375 +9427 -0.777099609375 +9428 -0.119110107421875 +9429 -0.783660888671875 +9430 -0.120086669921875 +9431 -0.790130615234375 +9432 -0.121063232421875 +9433 -0.796478271484375 +9434 -0.12200927734375 +9435 -0.802764892578125 +9436 -0.122955322265625 +9437 -0.808990478515625 +9438 -0.1239013671875 +9439 -0.815093994140625 +9440 -0.12481689453125 +9441 -0.82110595703125 +9442 -0.125701904296875 +9443 -0.8270263671875 +9444 -0.1265869140625 +9445 -0.8328857421875 +9446 -0.127471923828125 +9447 -0.838623046875 +9448 -0.128326416015625 +9449 -0.84429931640625 +9450 -0.129180908203125 +9451 -0.849853515625 +9452 -0.1300048828125 +9453 -0.855316162109375 +9454 -0.130828857421875 +9455 -0.860687255859375 +9456 -0.131622314453125 +9457 -0.865997314453125 +9458 -0.132415771484375 +9459 -0.871185302734375 +9460 -0.1331787109375 +9461 -0.876251220703125 +9462 -0.133941650390625 +9463 -0.881256103515625 +9464 -0.13470458984375 +9465 -0.88616943359375 +9466 -0.13543701171875 +9467 -0.890960693359375 +9468 -0.136138916015625 +9469 -0.895660400390625 +9470 -0.1368408203125 +9471 -0.9002685546875 +9472 -0.166473388671875 +9473 -0.90478515625 +9474 -0.167266845703125 +9475 -0.9091796875 +9476 -0.168060302734375 +9477 -0.91351318359375 +9478 -0.168853759765625 +9479 -0.917724609375 +9480 -0.169586181640625 +9481 -0.92181396484375 +9482 -0.17034912109375 +9483 -0.92584228515625 +9484 -0.171051025390625 +9485 -0.929718017578125 +9486 -0.1717529296875 +9487 -0.93353271484375 +9488 -0.17242431640625 +9489 -0.937225341796875 +9490 -0.173095703125 +9491 -0.940826416015625 +9492 -0.173736572265625 +9493 -0.9443359375 +9494 -0.174346923828125 +9495 -0.947723388671875 +9496 -0.174957275390625 +9497 -0.951019287109375 +9498 -0.175567626953125 +9499 -0.954193115234375 +9500 -0.176116943359375 +9501 -0.957275390625 +9502 -0.176666259765625 +9503 -0.960235595703125 +9504 -0.17718505859375 +9505 -0.963104248046875 +9506 -0.177703857421875 +9507 -0.96588134765625 +9508 -0.178192138671875 +9509 -0.968536376953125 +9510 -0.17864990234375 +9511 -0.971099853515625 +9512 -0.179107666015625 +9513 -0.973541259765625 +9514 -0.179534912109375 +9515 -0.975860595703125 +9516 -0.179962158203125 +9517 -0.97808837890625 +9518 -0.180328369140625 +9519 -0.980224609375 +9520 -0.18072509765625 +9521 -0.98223876953125 +9522 -0.181060791015625 +9523 -0.984161376953125 +9524 -0.181396484375 +9525 -0.9859619140625 +9526 -0.18170166015625 +9527 -0.987640380859375 +9528 -0.1820068359375 +9529 -0.989227294921875 +9530 -0.182281494140625 +9531 -0.990692138671875 +9532 -0.182525634765625 +9533 -0.9920654296875 +9534 -0.1827392578125 +9535 -0.993316650390625 +9536 -0.182952880859375 +9537 -0.994476318359375 +9538 -0.18316650390625 +9539 -0.995513916015625 +9540 -0.183319091796875 +9541 -0.9964599609375 +9542 -0.1834716796875 +9543 -0.997283935546875 +9544 -0.183624267578125 +9545 -0.99798583984375 +9546 -0.1837158203125 +9547 -0.99859619140625 +9548 -0.183807373046875 +9549 -0.999114990234375 +9550 -0.183868408203125 +9551 -0.999481201171875 +9552 -0.183929443359375 +9553 -0.999755859375 +9554 -0.1839599609375 +9555 -0.99993896484375 +9556 -0.183990478515625 +9557 -1.0 +9558 -0.1839599609375 +9559 -0.99993896484375 +9560 -0.183929443359375 +9561 -0.999755859375 +9562 -0.183868408203125 +9563 -0.999481201171875 +9564 -0.183807373046875 +9565 -0.999114990234375 +9566 -0.1837158203125 +9567 -0.99859619140625 +9568 -0.183624267578125 +9569 -0.99798583984375 +9570 -0.1834716796875 +9571 -0.997283935546875 +9572 -0.183319091796875 +9573 -0.9964599609375 +9574 -0.18316650390625 +9575 -0.995513916015625 +9576 -0.182952880859375 +9577 -0.994476318359375 +9578 -0.1827392578125 +9579 -0.993316650390625 +9580 -0.182525634765625 +9581 -0.9920654296875 +9582 -0.182281494140625 +9583 -0.990692138671875 +9584 -0.1820068359375 +9585 -0.989227294921875 +9586 -0.18170166015625 +9587 -0.987640380859375 +9588 -0.181396484375 +9589 -0.9859619140625 +9590 -0.181060791015625 +9591 -0.984161376953125 +9592 -0.18072509765625 +9593 -0.98223876953125 +9594 -0.180328369140625 +9595 -0.980224609375 +9596 -0.179962158203125 +9597 -0.97808837890625 +9598 -0.179534912109375 +9599 -0.975860595703125 +9600 -0.179107666015625 +9601 -0.973541259765625 +9602 -0.17864990234375 +9603 -0.971099853515625 +9604 -0.178192138671875 +9605 -0.968536376953125 +9606 -0.177703857421875 +9607 -0.96588134765625 +9608 -0.17718505859375 +9609 -0.963104248046875 +9610 -0.176666259765625 +9611 -0.960235595703125 +9612 -0.176116943359375 +9613 -0.957275390625 +9614 -0.175567626953125 +9615 -0.954193115234375 +9616 -0.174957275390625 +9617 -0.951019287109375 +9618 -0.174346923828125 +9619 -0.947723388671875 +9620 -0.173736572265625 +9621 -0.9443359375 +9622 -0.173095703125 +9623 -0.940826416015625 +9624 -0.17242431640625 +9625 -0.937225341796875 +9626 -0.1717529296875 +9627 -0.93353271484375 +9628 -0.171051025390625 +9629 -0.929718017578125 +9630 -0.17034912109375 +9631 -0.92584228515625 +9632 -0.169586181640625 +9633 -0.92181396484375 +9634 -0.168853759765625 +9635 -0.917724609375 +9636 -0.168060302734375 +9637 -0.91351318359375 +9638 -0.167266845703125 +9639 -0.9091796875 +9640 -0.166473388671875 +9641 -0.90478515625 +9642 -0.165618896484375 +9643 -0.9002685546875 +9644 -0.164794921875 +9645 -0.895660400390625 +9646 -0.163909912109375 +9647 -0.890960693359375 +9648 -0.16302490234375 +9649 -0.88616943359375 +9650 -0.162139892578125 +9651 -0.881256103515625 +9652 -0.161224365234375 +9653 -0.876251220703125 +9654 -0.1602783203125 +9655 -0.871185302734375 +9656 -0.159332275390625 +9657 -0.865997314453125 +9658 -0.158355712890625 +9659 -0.860687255859375 +9660 -0.1573486328125 +9661 -0.855316162109375 +9662 -0.156341552734375 +9663 -0.849853515625 +9664 -0.15533447265625 +9665 -0.84429931640625 +9666 -0.154296875 +9667 -0.838623046875 +9668 -0.153228759765625 +9669 -0.8328857421875 +9670 -0.15216064453125 +9671 -0.8270263671875 +9672 -0.15106201171875 +9673 -0.82110595703125 +9674 -0.14996337890625 +9675 -0.815093994140625 +9676 -0.148834228515625 +9677 -0.808990478515625 +9678 -0.147705078125 +9679 -0.802764892578125 +9680 -0.14654541015625 +9681 -0.796478271484375 +9682 -0.145355224609375 +9683 -0.790130615234375 +9684 -0.1441650390625 +9685 -0.783660888671875 +9686 -0.142974853515625 +9687 -0.777099609375 +9688 -0.141754150390625 +9689 -0.770477294921875 +9690 -0.1405029296875 +9691 -0.763763427734375 +9692 -0.139251708984375 +9693 -0.7569580078125 +9694 -0.13800048828125 +9695 -0.75006103515625 +9696 -0.13671875 +9697 -0.74310302734375 +9698 -0.135406494140625 +9699 -0.736053466796875 +9700 -0.13409423828125 +9701 -0.72894287109375 +9702 -0.132781982421875 +9703 -0.721710205078125 +9704 -0.131439208984375 +9705 -0.714447021484375 +9706 -0.130096435546875 +9707 -0.707061767578125 +9708 -0.12872314453125 +9709 -0.699615478515625 +9710 -0.1273193359375 +9711 -0.692108154296875 +9712 -0.125946044921875 +9713 -0.68450927734375 +9714 -0.12451171875 +9715 -0.676849365234375 +9716 -0.12310791015625 +9717 -0.669097900390625 +9718 -0.121673583984375 +9719 -0.661285400390625 +9720 -0.120208740234375 +9721 -0.65338134765625 +9722 -0.118743896484375 +9723 -0.645416259765625 +9724 -0.11724853515625 +9725 -0.63739013671875 +9726 -0.115753173828125 +9727 -0.6292724609375 +9728 -0.12420654296875 +9729 -0.621124267578125 +9730 -0.12255859375 +9731 -0.612884521484375 +9732 -0.120880126953125 +9733 -0.60455322265625 +9734 -0.11920166015625 +9735 -0.59619140625 +9736 -0.117523193359375 +9737 -0.587738037109375 +9738 -0.115814208984375 +9739 -0.579254150390625 +9740 -0.114105224609375 +9741 -0.5706787109375 +9742 -0.112396240234375 +9743 -0.562042236328125 +9744 -0.11065673828125 +9745 -0.5533447265625 +9746 -0.10888671875 +9747 -0.54461669921875 +9748 -0.107147216796875 +9749 -0.535797119140625 +9750 -0.1053466796875 +9751 -0.52691650390625 +9752 -0.10357666015625 +9753 -0.51800537109375 +9754 -0.101776123046875 +9755 -0.509002685546875 +9756 -0.0999755859375 +9757 -0.499969482421875 +9758 -0.09814453125 +9759 -0.490875244140625 +9760 -0.0963134765625 +9761 -0.481719970703125 +9762 -0.094482421875 +9763 -0.4725341796875 +9764 -0.092620849609375 +9765 -0.4632568359375 +9766 -0.09075927734375 +9767 -0.453948974609375 +9768 -0.088897705078125 +9769 -0.444610595703125 +9770 -0.0870361328125 +9771 -0.435211181640625 +9772 -0.08514404296875 +9773 -0.425750732421875 +9774 -0.083221435546875 +9775 -0.416259765625 +9776 -0.081329345703125 +9777 -0.406707763671875 +9778 -0.07940673828125 +9779 -0.397125244140625 +9780 -0.077484130859375 +9781 -0.387481689453125 +9782 -0.075531005859375 +9783 -0.3778076171875 +9784 -0.0736083984375 +9785 -0.36810302734375 +9786 -0.0716552734375 +9787 -0.35833740234375 +9788 -0.0697021484375 +9789 -0.348541259765625 +9790 -0.067718505859375 +9791 -0.338714599609375 +9792 -0.06573486328125 +9793 -0.328826904296875 +9794 -0.06378173828125 +9795 -0.318939208984375 +9796 -0.061767578125 +9797 -0.308990478515625 +9798 -0.059783935546875 +9799 -0.29901123046875 +9800 -0.057769775390625 +9801 -0.28900146484375 +9802 -0.0557861328125 +9803 -0.278961181640625 +9804 -0.05377197265625 +9805 -0.268890380859375 +9806 -0.051727294921875 +9807 -0.2587890625 +9808 -0.049713134765625 +9809 -0.2486572265625 +9810 -0.047698974609375 +9811 -0.238525390625 +9812 -0.045654296875 +9813 -0.22833251953125 +9814 -0.043609619140625 +9815 -0.218109130859375 +9816 -0.04156494140625 +9817 -0.2078857421875 +9818 -0.039520263671875 +9819 -0.1976318359375 +9820 -0.037445068359375 +9821 -0.187347412109375 +9822 -0.035400390625 +9823 -0.17706298828125 +9824 -0.0333251953125 +9825 -0.166748046875 +9826 -0.03125 +9827 -0.156402587890625 +9828 -0.029205322265625 +9829 -0.14605712890625 +9830 -0.027130126953125 +9831 -0.13568115234375 +9832 -0.025054931640625 +9833 -0.12530517578125 +9834 -0.022979736328125 +9835 -0.11492919921875 +9836 -0.0208740234375 +9837 -0.104522705078125 +9838 -0.018798828125 +9839 -0.094085693359375 +9840 -0.0167236328125 +9841 -0.083648681640625 +9842 -0.014617919921875 +9843 -0.073211669921875 +9844 -0.012542724609375 +9845 -0.062774658203125 +9846 -0.01043701171875 +9847 -0.05230712890625 +9848 -0.00836181640625 +9849 -0.0418701171875 +9850 -0.006256103515625 +9851 -0.031402587890625 +9852 -0.004180908203125 +9853 -0.02093505859375 +9854 -0.0020751953125 +9855 -0.010467529296875 +9856 0.0 +9857 0.0 +9858 0.00225830078125 +9859 0.010467529296875 +9860 0.0045166015625 +9861 0.02093505859375 +9862 0.00677490234375 +9863 0.031402587890625 +9864 0.009033203125 +9865 0.0418701171875 +9866 0.01129150390625 +9867 0.05230712890625 +9868 0.0135498046875 +9869 0.062774658203125 +9870 0.01580810546875 +9871 0.073211669921875 +9872 0.01806640625 +9873 0.083648681640625 +9874 0.020294189453125 +9875 0.094085693359375 +9876 0.022552490234375 +9877 0.104522705078125 +9878 0.024810791015625 +9879 0.11492919921875 +9880 0.02703857421875 +9881 0.12530517578125 +9882 0.029296875 +9883 0.13568115234375 +9884 0.031524658203125 +9885 0.14605712890625 +9886 0.033782958984375 +9887 0.156402587890625 +9888 0.0360107421875 +9889 0.166748046875 +9890 0.038238525390625 +9891 0.17706298828125 +9892 0.04046630859375 +9893 0.187347412109375 +9894 0.04266357421875 +9895 0.1976318359375 +9896 0.044891357421875 +9897 0.2078857421875 +9898 0.047088623046875 +9899 0.218109130859375 +9900 0.04931640625 +9901 0.22833251953125 +9902 0.051513671875 +9903 0.238525390625 +9904 0.0537109375 +9905 0.2486572265625 +9906 0.055877685546875 +9907 0.2587890625 +9908 0.058074951171875 +9909 0.268890380859375 +9910 0.06024169921875 +9911 0.278961181640625 +9912 0.062408447265625 +9913 0.28900146484375 +9914 0.0645751953125 +9915 0.29901123046875 +9916 0.066741943359375 +9917 0.308990478515625 +9918 0.068878173828125 +9919 0.318939208984375 +9920 0.071014404296875 +9921 0.328826904296875 +9922 0.073150634765625 +9923 0.338714599609375 +9924 0.075286865234375 +9925 0.348541259765625 +9926 0.077392578125 +9927 0.35833740234375 +9928 0.079498291015625 +9929 0.36810302734375 +9930 0.08160400390625 +9931 0.3778076171875 +9932 0.08367919921875 +9933 0.387481689453125 +9934 0.08575439453125 +9935 0.397125244140625 +9936 0.08782958984375 +9937 0.406707763671875 +9938 0.08990478515625 +9939 0.416259765625 +9940 0.091949462890625 +9941 0.425750732421875 +9942 0.093994140625 +9943 0.435211181640625 +9944 0.096038818359375 +9945 0.444610595703125 +9946 0.098052978515625 +9947 0.453948974609375 +9948 0.100067138671875 +9949 0.4632568359375 +9950 0.10205078125 +9951 0.4725341796875 +9952 0.104034423828125 +9953 0.481719970703125 +9954 0.10601806640625 +9955 0.490875244140625 +9956 0.10797119140625 +9957 0.499969482421875 +9958 0.10992431640625 +9959 0.509002685546875 +9960 0.11187744140625 +9961 0.51800537109375 +9962 0.113800048828125 +9963 0.52691650390625 +9964 0.11572265625 +9965 0.535797119140625 +9966 0.11761474609375 +9967 0.54461669921875 +9968 0.1195068359375 +9969 0.5533447265625 +9970 0.12139892578125 +9971 0.562042236328125 +9972 0.123260498046875 +9973 0.5706787109375 +9974 0.1251220703125 +9975 0.579254150390625 +9976 0.126953125 +9977 0.587738037109375 +9978 0.128753662109375 +9979 0.59619140625 +9980 0.130584716796875 +9981 0.60455322265625 +9982 0.13238525390625 +9983 0.612884521484375 +9984 0.154022216796875 +9985 0.621124267578125 +9986 0.156036376953125 +9987 0.6292724609375 +9988 0.158050537109375 +9989 0.63739013671875 +9990 0.1600341796875 +9991 0.645416259765625 +9992 0.162017822265625 +9993 0.65338134765625 +9994 0.163970947265625 +9995 0.661285400390625 +9996 0.165924072265625 +9997 0.669097900390625 +9998 0.1678466796875 +9999 0.676849365234375 +10000 0.16973876953125 +10001 0.68450927734375 +10002 0.171630859375 +10003 0.692108154296875 +10004 0.173492431640625 +10005 0.699615478515625 +10006 0.175323486328125 +10007 0.707061767578125 +10008 0.177154541015625 +10009 0.714447021484375 +10010 0.178955078125 +10011 0.721710205078125 +10012 0.180755615234375 +10013 0.72894287109375 +10014 0.182525634765625 +10015 0.736053466796875 +10016 0.18426513671875 +10017 0.74310302734375 +10018 0.186004638671875 +10019 0.75006103515625 +10020 0.187713623046875 +10021 0.7569580078125 +10022 0.18939208984375 +10023 0.763763427734375 +10024 0.191070556640625 +10025 0.770477294921875 +10026 0.19268798828125 +10027 0.777099609375 +10028 0.1943359375 +10029 0.783660888671875 +10030 0.1959228515625 +10031 0.790130615234375 +10032 0.197509765625 +10033 0.796478271484375 +10034 0.199066162109375 +10035 0.802764892578125 +10036 0.20062255859375 +10037 0.808990478515625 +10038 0.202117919921875 +10039 0.815093994140625 +10040 0.20361328125 +10041 0.82110595703125 +10042 0.205078125 +10043 0.8270263671875 +10044 0.20654296875 +10045 0.8328857421875 +10046 0.20794677734375 +10047 0.838623046875 +10048 0.2093505859375 +10049 0.84429931640625 +10050 0.21075439453125 +10051 0.849853515625 +10052 0.21209716796875 +10053 0.855316162109375 +10054 0.21343994140625 +10055 0.860687255859375 +10056 0.214752197265625 +10057 0.865997314453125 +10058 0.216033935546875 +10059 0.871185302734375 +10060 0.21728515625 +10061 0.876251220703125 +10062 0.218536376953125 +10063 0.881256103515625 +10064 0.219757080078125 +10065 0.88616943359375 +10066 0.220947265625 +10067 0.890960693359375 +10068 0.22210693359375 +10069 0.895660400390625 +10070 0.223236083984375 +10071 0.9002685546875 +10072 0.224365234375 +10073 0.90478515625 +10074 0.2254638671875 +10075 0.9091796875 +10076 0.226531982421875 +10077 0.91351318359375 +10078 0.227569580078125 +10079 0.917724609375 +10080 0.22857666015625 +10081 0.92181396484375 +10082 0.229583740234375 +10083 0.92584228515625 +10084 0.230560302734375 +10085 0.929718017578125 +10086 0.23150634765625 +10087 0.93353271484375 +10088 0.232421875 +10089 0.937225341796875 +10090 0.233306884765625 +10091 0.940826416015625 +10092 0.234161376953125 +10093 0.9443359375 +10094 0.235015869140625 +10095 0.947723388671875 +10096 0.23583984375 +10097 0.951019287109375 +10098 0.23663330078125 +10099 0.954193115234375 +10100 0.237396240234375 +10101 0.957275390625 +10102 0.238128662109375 +10103 0.960235595703125 +10104 0.23883056640625 +10105 0.963104248046875 +10106 0.239501953125 +10107 0.96588134765625 +10108 0.24017333984375 +10109 0.968536376953125 +10110 0.240814208984375 +10111 0.971099853515625 +10112 0.241424560546875 +10113 0.973541259765625 +10114 0.24200439453125 +10115 0.975860595703125 +10116 0.2425537109375 +10117 0.97808837890625 +10118 0.243072509765625 +10119 0.980224609375 +10120 0.243560791015625 +10121 0.98223876953125 +10122 0.244049072265625 +10123 0.984161376953125 +10124 0.2445068359375 +10125 0.9859619140625 +10126 0.244903564453125 +10127 0.987640380859375 +10128 0.24530029296875 +10129 0.989227294921875 +10130 0.24566650390625 +10131 0.990692138671875 +10132 0.246002197265625 +10133 0.9920654296875 +10134 0.246307373046875 +10135 0.993316650390625 +10136 0.246612548828125 +10137 0.994476318359375 +10138 0.246856689453125 +10139 0.995513916015625 +10140 0.247100830078125 +10141 0.9964599609375 +10142 0.247314453125 +10143 0.997283935546875 +10144 0.247467041015625 +10145 0.99798583984375 +10146 0.24761962890625 +10147 0.99859619140625 +10148 0.24774169921875 +10149 0.999114990234375 +10150 0.247833251953125 +10151 0.999481201171875 +10152 0.2479248046875 +10153 0.999755859375 +10154 0.247955322265625 +10155 0.99993896484375 +10156 0.24798583984375 +10157 0.999969482421875 +10158 0.247955322265625 +10159 0.99993896484375 +10160 0.2479248046875 +10161 0.999755859375 +10162 0.247833251953125 +10163 0.999481201171875 +10164 0.24774169921875 +10165 0.999114990234375 +10166 0.24761962890625 +10167 0.99859619140625 +10168 0.247467041015625 +10169 0.99798583984375 +10170 0.247314453125 +10171 0.997283935546875 +10172 0.247100830078125 +10173 0.9964599609375 +10174 0.246856689453125 +10175 0.995513916015625 +10176 0.246612548828125 +10177 0.994476318359375 +10178 0.246307373046875 +10179 0.993316650390625 +10180 0.246002197265625 +10181 0.9920654296875 +10182 0.24566650390625 +10183 0.990692138671875 +10184 0.24530029296875 +10185 0.989227294921875 +10186 0.244903564453125 +10187 0.987640380859375 +10188 0.2445068359375 +10189 0.9859619140625 +10190 0.244049072265625 +10191 0.984161376953125 +10192 0.243560791015625 +10193 0.98223876953125 +10194 0.243072509765625 +10195 0.980224609375 +10196 0.2425537109375 +10197 0.97808837890625 +10198 0.24200439453125 +10199 0.975860595703125 +10200 0.241424560546875 +10201 0.973541259765625 +10202 0.240814208984375 +10203 0.971099853515625 +10204 0.24017333984375 +10205 0.968536376953125 +10206 0.239501953125 +10207 0.96588134765625 +10208 0.23883056640625 +10209 0.963104248046875 +10210 0.238128662109375 +10211 0.960235595703125 +10212 0.237396240234375 +10213 0.957275390625 +10214 0.23663330078125 +10215 0.954193115234375 +10216 0.23583984375 +10217 0.951019287109375 +10218 0.235015869140625 +10219 0.947723388671875 +10220 0.234161376953125 +10221 0.9443359375 +10222 0.233306884765625 +10223 0.940826416015625 +10224 0.232421875 +10225 0.937225341796875 +10226 0.23150634765625 +10227 0.93353271484375 +10228 0.230560302734375 +10229 0.929718017578125 +10230 0.229583740234375 +10231 0.92584228515625 +10232 0.22857666015625 +10233 0.92181396484375 +10234 0.227569580078125 +10235 0.917724609375 +10236 0.226531982421875 +10237 0.91351318359375 +10238 0.2254638671875 +10239 0.9091796875 +10240 0.0 +10241 0.0 +10242 0.0 +10243 0.0 +10244 0.0 +10245 0.0 +10246 0.0 +10247 0.0 +10248 0.0 +10249 0.0 +10250 0.0 +10251 0.0 +10252 0.0 +10253 0.0 +10254 0.0 +10255 0.0 +10256 0.0 +10257 0.0 +10258 0.0 +10259 0.0 +10260 0.0 +10261 0.0 +10262 0.0 +10263 0.0 +10264 0.0 +10265 0.0 +10266 0.0 +10267 0.0 +10268 0.0 +10269 0.0 +10270 0.0 +10271 0.0 +10272 0.0 +10273 0.0 +10274 0.0 +10275 0.0 +10276 0.0 +10277 0.0 +10278 0.0 +10279 0.0 +10280 0.0 +10281 0.0 +10282 0.0 +10283 0.0 +10284 0.0 +10285 0.0 +10286 0.0 +10287 0.0 +10288 0.0 +10289 0.0 +10290 0.0 +10291 0.0 +10292 0.0 +10293 0.0 +10294 0.0 +10295 0.0 +10296 0.0 +10297 0.0 +10298 0.0 +10299 0.0 +10300 0.0 +10301 0.0 +10302 0.0 +10303 0.0 +10304 0.0 +10305 0.0 +10306 0.0 +10307 0.0 +10308 0.0 +10309 0.0 +10310 0.0 +10311 0.0 +10312 0.0 +10313 0.0 +10314 0.0 +10315 0.0 +10316 0.0 +10317 0.0 +10318 0.0 +10319 0.0 +10320 0.0 +10321 0.0 +10322 0.0 +10323 0.0 +10324 0.0 +10325 0.0 +10326 0.0 +10327 0.0 +10328 0.0 +10329 0.0 +10330 0.0 +10331 0.0 +10332 0.0 +10333 0.0 +10334 0.0 +10335 0.0 +10336 0.0 +10337 0.0 +10338 0.0 +10339 0.0 +10340 0.0 +10341 0.0 +10342 0.0 +10343 0.0 +10344 0.0 +10345 0.0 +10346 0.0 +10347 0.0 +10348 0.0 +10349 0.0 +10350 0.0 +10351 0.0 +10352 0.0 +10353 0.0 +10354 0.0 +10355 0.0 +10356 0.0 +10357 0.0 +10358 0.0 +10359 0.0 +10360 0.0 +10361 0.0 +10362 0.0 +10363 0.0 +10364 0.0 +10365 0.0 +10366 0.0 +10367 0.0 +10368 0.0 +10369 0.0 +10370 0.0 +10371 0.0 +10372 0.0 +10373 0.0 +10374 0.0 +10375 0.0 +10376 0.0 +10377 0.0 +10378 0.0 +10379 0.0 +10380 0.0 +10381 0.0 +10382 0.0 +10383 0.0 +10384 0.0 +10385 0.0 +10386 0.0 +10387 0.0 +10388 0.0 +10389 0.0 +10390 0.0 +10391 0.0 +10392 0.0 +10393 0.0 +10394 0.0 +10395 0.0 +10396 0.0 +10397 0.0 +10398 0.0 +10399 0.0 +10400 0.0 +10401 0.0 +10402 0.0 +10403 0.0 +10404 0.0 +10405 0.0 +10406 0.0 +10407 0.0 +10408 0.0 +10409 0.0 +10410 0.0 +10411 0.0 +10412 0.0 +10413 0.0 +10414 0.0 +10415 0.0 +10416 0.0 +10417 0.0 +10418 0.0 +10419 0.0 +10420 0.0 +10421 0.0 +10422 0.0 +10423 0.0 +10424 0.0 +10425 0.0 +10426 0.0 +10427 0.0 +10428 0.0 +10429 0.0 +10430 0.0 +10431 0.0 +10432 0.0 +10433 0.0 +10434 0.0 +10435 0.0 +10436 0.0 +10437 0.0 +10438 0.0 +10439 0.0 +10440 0.0 +10441 0.0 +10442 0.0 +10443 0.0 +10444 0.0 +10445 0.0 +10446 0.0 +10447 0.0 +10448 0.0 +10449 0.0 +10450 0.0 +10451 0.0 +10452 0.0 +10453 0.0 +10454 0.0 +10455 0.0 +10456 0.0 +10457 0.0 +10458 0.0 +10459 0.0 +10460 0.0 +10461 0.0 +10462 0.0 +10463 0.0 +10464 0.0 +10465 0.0 +10466 0.0 +10467 0.0 +10468 0.0 +10469 0.0 +10470 0.0 +10471 0.0 +10472 0.0 +10473 0.0 +10474 0.0 +10475 0.0 +10476 0.0 +10477 0.0 +10478 0.0 +10479 0.0 +10480 0.0 +10481 0.0 +10482 0.0 +10483 0.0 +10484 0.0 +10485 0.0 +10486 0.0 +10487 0.0 +10488 0.0 +10489 0.0 +10490 0.0 +10491 0.0 +10492 0.0 +10493 0.0 +10494 0.0 +10495 0.0 +10496 0.0 +10497 0.0 +10498 0.0 +10499 0.0 +10500 0.0 +10501 0.0 +10502 0.0 +10503 0.0 +10504 0.0 +10505 0.0 +10506 0.0 +10507 0.0 +10508 0.0 +10509 0.0 +10510 0.0 +10511 0.0 +10512 0.0 +10513 0.0 +10514 0.0 +10515 0.0 +10516 0.0 +10517 0.0 +10518 0.0 +10519 0.0 +10520 0.0 +10521 0.0 +10522 0.0 +10523 0.0 +10524 0.0 +10525 0.0 +10526 0.0 +10527 0.0 +10528 0.0 +10529 0.0 +10530 0.0 +10531 0.0 +10532 0.0 +10533 0.0 +10534 0.0 +10535 0.0 +10536 0.0 +10537 0.0 +10538 0.0 +10539 0.0 +10540 0.0 +10541 0.0 +10542 0.0 +10543 0.0 +10544 0.0 +10545 0.0 +10546 0.0 +10547 0.0 +10548 0.0 +10549 0.0 +10550 0.0 +10551 0.0 +10552 0.0 +10553 0.0 +10554 0.0 +10555 0.0 +10556 0.0 +10557 0.0 +10558 0.0 +10559 0.0 +10560 0.0 +10561 0.0 +10562 0.0 +10563 0.0 +10564 0.0 +10565 0.0 +10566 0.0 +10567 0.0 +10568 0.0 +10569 0.0 +10570 0.0 +10571 0.0 +10572 0.0 +10573 0.0 +10574 0.0 +10575 0.0 +10576 0.0 +10577 0.0 +10578 0.0 +10579 0.0 +10580 0.0 +10581 0.0 +10582 0.0 +10583 0.0 +10584 0.0 +10585 0.0 +10586 0.0 +10587 0.0 +10588 0.0 +10589 0.0 +10590 0.0 +10591 0.0 +10592 0.0 +10593 0.0 +10594 0.0 +10595 0.0 +10596 0.0 +10597 0.0 +10598 0.0 +10599 0.0 +10600 0.0 +10601 0.0 +10602 0.0 +10603 0.0 +10604 0.0 +10605 0.0 +10606 0.0 +10607 0.0 +10608 0.0 +10609 0.0 +10610 0.0 +10611 0.0 +10612 0.0 +10613 0.0 +10614 0.0 +10615 0.0 +10616 0.0 +10617 0.0 +10618 0.0 +10619 0.0 +10620 0.0 +10621 0.0 +10622 0.0 +10623 0.0 +10624 0.0 +10625 0.0 +10626 0.0 +10627 0.0 +10628 0.0 +10629 0.0 +10630 0.0 +10631 0.0 +10632 0.0 +10633 0.0 +10634 0.0 +10635 0.0 +10636 0.0 +10637 0.0 +10638 0.0 +10639 0.0 +10640 0.0 +10641 0.0 +10642 0.0 +10643 0.0 +10644 0.0 +10645 0.0 +10646 0.0 +10647 0.0 +10648 0.0 +10649 0.0 +10650 0.0 +10651 0.0 +10652 0.0 +10653 0.0 +10654 0.0 +10655 0.0 +10656 0.0 +10657 0.0 +10658 0.0 +10659 0.0 +10660 0.0 +10661 0.0 +10662 0.0 +10663 0.0 +10664 0.0 +10665 0.0 +10666 0.0 +10667 0.0 +10668 0.0 +10669 0.0 +10670 0.0 +10671 0.0 +10672 0.0 +10673 0.0 +10674 0.0 +10675 0.0 +10676 0.0 +10677 0.0 +10678 0.0 +10679 0.0 +10680 0.0 +10681 0.0 +10682 0.0 +10683 0.0 +10684 0.0 +10685 0.0 +10686 0.0 +10687 0.0 +10688 0.0 +10689 0.0 +10690 0.0 +10691 0.0 +10692 0.0 +10693 0.0 +10694 0.0 +10695 0.0 +10696 0.0 +10697 0.0 +10698 0.0 +10699 0.0 +10700 0.0 +10701 0.0 +10702 0.0 +10703 0.0 +10704 0.0 +10705 0.0 +10706 0.0 +10707 0.0 +10708 0.0 +10709 0.0 +10710 0.0 +10711 0.0 +10712 0.0 +10713 0.0 +10714 0.0 +10715 0.0 +10716 0.0 +10717 0.0 +10718 0.0 +10719 0.0 +10720 0.0 +10721 0.0 +10722 0.0 +10723 0.0 +10724 0.0 +10725 0.0 +10726 0.0 +10727 0.0 +10728 0.0 +10729 0.0 +10730 0.0 +10731 0.0 +10732 0.0 +10733 0.0 +10734 0.0 +10735 0.0 +10736 0.0 +10737 0.0 +10738 0.0 +10739 0.0 +10740 0.0 +10741 0.0 +10742 0.0 +10743 0.0 +10744 0.0 +10745 0.0 +10746 0.0 +10747 0.0 +10748 0.0 +10749 0.0 +10750 0.0 +10751 0.0 +10752 0.0 +10753 0.0 +10754 0.0 +10755 0.0 +10756 0.0 +10757 0.0 +10758 0.0 +10759 0.0 +10760 0.0 +10761 0.0 +10762 0.0 +10763 0.0 +10764 0.0 +10765 0.0 +10766 0.0 +10767 0.0 +10768 0.0 +10769 0.0 +10770 0.0 +10771 0.0 +10772 0.0 +10773 0.0 +10774 0.0 +10775 0.0 +10776 0.0 +10777 0.0 +10778 0.0 +10779 0.0 +10780 0.0 +10781 0.0 +10782 0.0 +10783 0.0 +10784 0.0 +10785 0.0 +10786 0.0 +10787 0.0 +10788 0.0 +10789 0.0 +10790 0.0 +10791 0.0 +10792 0.0 +10793 0.0 +10794 0.0 +10795 0.0 +10796 0.0 +10797 0.0 +10798 0.0 +10799 0.0 +10800 0.0 +10801 0.0 +10802 0.0 +10803 0.0 +10804 0.0 +10805 0.0 +10806 0.0 +10807 0.0 +10808 0.0 +10809 0.0 +10810 0.0 +10811 0.0 +10812 0.0 +10813 0.0 +10814 0.0 +10815 0.0 +10816 0.0 +10817 0.0 +10818 0.0 +10819 0.0 +10820 0.0 +10821 0.0 +10822 0.0 +10823 0.0 +10824 0.0 +10825 0.0 +10826 0.0 +10827 0.0 +10828 0.0 +10829 0.0 +10830 0.0 +10831 0.0 +10832 0.0 +10833 0.0 +10834 0.0 +10835 0.0 +10836 0.0 +10837 0.0 +10838 0.0 +10839 0.0 +10840 0.0 +10841 0.0 +10842 0.0 +10843 0.0 +10844 0.0 +10845 0.0 +10846 0.0 +10847 0.0 +10848 0.0 +10849 0.0 +10850 0.0 +10851 0.0 +10852 0.0 +10853 0.0 +10854 0.0 +10855 0.0 +10856 0.0 +10857 0.0 +10858 0.0 +10859 0.0 +10860 0.0 +10861 0.0 +10862 0.0 +10863 0.0 +10864 0.0 +10865 0.0 +10866 0.0 +10867 0.0 +10868 0.0 +10869 0.0 +10870 0.0 +10871 0.0 +10872 0.0 +10873 0.0 +10874 0.0 +10875 0.0 +10876 0.0 +10877 0.0 +10878 0.0 +10879 0.0 +10880 0.0 +10881 0.0 +10882 0.0 +10883 0.0 +10884 0.0 +10885 0.0 +10886 0.0 +10887 0.0 +10888 0.0 +10889 0.0 +10890 0.0 +10891 0.0 +10892 0.0 +10893 0.0 +10894 0.0 +10895 0.0 +10896 0.0 +10897 0.0 +10898 0.0 +10899 0.0 +10900 0.0 +10901 0.0 +10902 0.0 +10903 0.0 +10904 0.0 +10905 0.0 +10906 0.0 +10907 0.0 +10908 0.0 +10909 0.0 +10910 0.0 +10911 0.0 +10912 0.0 +10913 0.0 +10914 0.0 +10915 0.0 +10916 0.0 +10917 0.0 +10918 0.0 +10919 0.0 +10920 0.0 +10921 0.0 +10922 0.0 +10923 0.0 +10924 0.0 +10925 0.0 +10926 0.0 +10927 0.0 +10928 0.0 +10929 0.0 +10930 0.0 +10931 0.0 +10932 0.0 +10933 0.0 +10934 0.0 +10935 0.0 +10936 0.0 +10937 0.0 +10938 0.0 +10939 0.0 +10940 0.0 +10941 0.0 +10942 0.0 +10943 0.0 +10944 0.0 +10945 0.0 +10946 0.0 +10947 0.0 +10948 0.0 +10949 0.0 +10950 0.0 +10951 0.0 +10952 0.0 +10953 0.0 +10954 0.0 +10955 0.0 +10956 0.0 +10957 0.0 +10958 0.0 +10959 0.0 +10960 0.0 +10961 0.0 +10962 0.0 +10963 0.0 +10964 0.0 +10965 0.0 +10966 0.0 +10967 0.0 +10968 0.0 +10969 0.0 +10970 0.0 +10971 0.0 +10972 0.0 +10973 0.0 +10974 0.0 +10975 0.0 +10976 0.0 +10977 0.0 +10978 0.0 +10979 0.0 +10980 0.0 +10981 0.0 +10982 0.0 +10983 0.0 +10984 0.0 +10985 0.0 +10986 0.0 +10987 0.0 +10988 0.0 +10989 0.0 +10990 0.0 +10991 0.0 +10992 0.0 +10993 0.0 +10994 0.0 +10995 0.0 +10996 0.0 +10997 0.0 +10998 0.0 +10999 0.0 +11000 0.0 +11001 0.0 +11002 0.0 +11003 0.0 +11004 0.0 +11005 0.0 +11006 0.0 +11007 0.0 +11008 0.0 +11009 0.0 +11010 0.0 +11011 0.0 +11012 0.0 +11013 0.0 +11014 0.0 +11015 0.0 +11016 0.0 +11017 0.0 +11018 0.0 +11019 0.0 +11020 0.0 +11021 0.0 +11022 0.0 +11023 0.0 +11024 0.0 +11025 0.0 +11026 0.0 +11027 0.0 +11028 0.0 +11029 0.0 +11030 0.0 +11031 0.0 +11032 0.0 +11033 0.0 +11034 0.0 +11035 0.0 +11036 0.0 +11037 0.0 +11038 0.0 +11039 0.0 +11040 0.0 +11041 0.0 +11042 0.0 +11043 0.0 +11044 0.0 +11045 0.0 +11046 0.0 +11047 0.0 +11048 0.0 +11049 0.0 +11050 0.0 +11051 0.0 +11052 0.0 +11053 0.0 +11054 0.0 +11055 0.0 +11056 0.0 +11057 0.0 +11058 0.0 +11059 0.0 +11060 0.0 +11061 0.0 +11062 0.0 +11063 0.0 +11064 0.0 +11065 0.0 +11066 0.0 +11067 0.0 +11068 0.0 +11069 0.0 +11070 0.0 +11071 0.0 +11072 0.0 +11073 0.0 +11074 0.0 +11075 0.0 +11076 0.0 +11077 0.0 +11078 0.0 +11079 0.0 +11080 0.0 +11081 0.0 +11082 0.0 +11083 0.0 +11084 0.0 +11085 0.0 +11086 0.0 +11087 0.0 +11088 0.0 +11089 0.0 +11090 0.0 +11091 0.0 +11092 0.0 +11093 0.0 +11094 0.0 +11095 0.0 +11096 0.0 +11097 0.0 +11098 0.0 +11099 0.0 +11100 0.0 +11101 0.0 +11102 0.0 +11103 0.0 +11104 0.0 +11105 0.0 +11106 0.0 +11107 0.0 +11108 0.0 +11109 0.0 +11110 0.0 +11111 0.0 +11112 0.0 +11113 0.0 +11114 0.0 +11115 0.0 +11116 0.0 +11117 0.0 +11118 0.0 +11119 0.0 +11120 0.0 +11121 0.0 +11122 0.0 +11123 0.0 +11124 0.0 +11125 0.0 +11126 0.0 +11127 0.0 +11128 0.0 +11129 0.0 +11130 0.0 +11131 0.0 +11132 0.0 +11133 0.0 +11134 0.0 +11135 0.0 +11136 0.0 +11137 0.0 +11138 0.0 +11139 0.0 +11140 0.0 +11141 0.0 +11142 0.0 +11143 0.0 +11144 0.0 +11145 0.0 +11146 0.0 +11147 0.0 +11148 0.0 +11149 0.0 +11150 0.0 +11151 0.0 +11152 0.0 +11153 0.0 +11154 0.0 +11155 0.0 +11156 0.0 +11157 0.0 +11158 0.0 +11159 0.0 +11160 0.0 +11161 0.0 +11162 0.0 +11163 0.0 +11164 0.0 +11165 0.0 +11166 0.0 +11167 0.0 +11168 0.0 +11169 0.0 +11170 0.0 +11171 0.0 +11172 0.0 +11173 0.0 +11174 0.0 +11175 0.0 +11176 0.0 +11177 0.0 +11178 0.0 +11179 0.0 +11180 0.0 +11181 0.0 +11182 0.0 +11183 0.0 +11184 0.0 +11185 0.0 +11186 0.0 +11187 0.0 +11188 0.0 +11189 0.0 +11190 0.0 +11191 0.0 +11192 0.0 +11193 0.0 +11194 0.0 +11195 0.0 +11196 0.0 +11197 0.0 +11198 0.0 +11199 0.0 +11200 0.0 +11201 0.0 +11202 0.0 +11203 0.0 +11204 0.0 +11205 0.0 +11206 0.0 +11207 0.0 +11208 0.0 +11209 0.0 +11210 0.0 +11211 0.0 +11212 0.0 +11213 0.0 +11214 0.0 +11215 0.0 +11216 0.0 +11217 0.0 +11218 0.0 +11219 0.0 +11220 0.0 +11221 0.0 +11222 0.0 +11223 0.0 +11224 0.0 +11225 0.0 +11226 0.0 +11227 0.0 +11228 0.0 +11229 0.0 +11230 0.0 +11231 0.0 +11232 0.0 +11233 0.0 +11234 0.0 +11235 0.0 +11236 0.0 +11237 0.0 +11238 0.0 +11239 0.0 +11240 0.0 +11241 0.0 +11242 0.0 +11243 0.0 +11244 0.0 +11245 0.0 +11246 0.0 +11247 0.0 +11248 0.0 +11249 0.0 +11250 0.0 +11251 0.0 +11252 0.0 +11253 0.0 +11254 0.0 +11255 0.0 +11256 0.0 +11257 0.0 +11258 0.0 +11259 0.0 +11260 0.0 +11261 0.0 +11262 0.0 +11263 0.0 +11264 0.0 +11265 0.0 +11266 0.0 +11267 0.0 +11268 0.0 +11269 0.0 +11270 0.0 +11271 0.0 +11272 0.0 +11273 0.0 +11274 0.0 +11275 0.0 +11276 0.0 +11277 0.0 +11278 0.0 +11279 0.0 +11280 0.0 +11281 0.0 +11282 0.0 +11283 0.0 +11284 0.0 +11285 0.0 +11286 0.0 +11287 0.0 +11288 0.0 +11289 0.0 +11290 0.0 +11291 0.0 +11292 0.0 +11293 0.0 +11294 0.0 +11295 0.0 +11296 0.0 +11297 0.0 +11298 0.0 +11299 0.0 +11300 0.0 +11301 0.0 +11302 0.0 +11303 0.0 +11304 0.0 +11305 0.0 +11306 0.0 +11307 0.0 +11308 0.0 +11309 0.0 +11310 0.0 +11311 0.0 +11312 0.0 +11313 0.0 +11314 0.0 +11315 0.0 +11316 0.0 +11317 0.0 +11318 0.0 +11319 0.0 +11320 0.0 +11321 0.0 +11322 0.0 +11323 0.0 +11324 0.0 +11325 0.0 +11326 0.0 +11327 0.0 +11328 0.0 +11329 0.0 +11330 0.0 +11331 0.0 +11332 0.0 +11333 0.0 +11334 0.0 +11335 0.0 +11336 0.0 +11337 0.0 +11338 0.0 +11339 0.0 +11340 0.0 +11341 0.0 +11342 0.0 +11343 0.0 +11344 0.0 +11345 0.0 +11346 0.0 +11347 0.0 +11348 0.0 +11349 0.0 +11350 0.0 +11351 0.0 +11352 0.0 +11353 0.0 +11354 0.0 +11355 0.0 +11356 0.0 +11357 0.0 +11358 0.0 +11359 0.0 +11360 0.0 +11361 0.0 +11362 0.0 +11363 0.0 +11364 0.0 +11365 0.0 +11366 0.0 +11367 0.0 +11368 0.0 +11369 0.0 +11370 0.0 +11371 0.0 +11372 0.0 +11373 0.0 +11374 0.0 +11375 0.0 +11376 0.0 +11377 0.0 +11378 0.0 +11379 0.0 +11380 0.0 +11381 0.0 +11382 0.0 +11383 0.0 +11384 0.0 +11385 0.0 +11386 0.0 +11387 0.0 +11388 0.0 +11389 0.0 +11390 0.0 +11391 0.0 +11392 0.0 +11393 0.0 +11394 0.0 +11395 0.0 +11396 0.0 +11397 0.0 +11398 0.0 +11399 0.0 +11400 0.0 +11401 0.0 +11402 0.0 +11403 0.0 +11404 0.0 +11405 0.0 +11406 0.0 +11407 0.0 +11408 0.0 +11409 0.0 +11410 0.0 +11411 0.0 +11412 0.0 +11413 0.0 +11414 0.0 +11415 0.0 +11416 0.0 +11417 0.0 +11418 0.0 +11419 0.0 +11420 0.0 +11421 0.0 +11422 0.0 +11423 0.0 +11424 0.0 +11425 0.0 +11426 0.0 +11427 0.0 +11428 0.0 +11429 0.0 +11430 0.0 +11431 0.0 +11432 0.0 +11433 0.0 +11434 0.0 +11435 0.0 +11436 0.0 +11437 0.0 +11438 0.0 +11439 0.0 +11440 0.0 +11441 0.0 +11442 0.0 +11443 0.0 +11444 0.0 +11445 0.0 +11446 0.0 +11447 0.0 +11448 0.0 +11449 0.0 +11450 0.0 +11451 0.0 +11452 0.0 +11453 0.0 +11454 0.0 +11455 0.0 +11456 0.0 +11457 0.0 +11458 0.0 +11459 0.0 +11460 0.0 +11461 0.0 +11462 0.0 +11463 0.0 +11464 0.0 +11465 0.0 +11466 0.0 +11467 0.0 +11468 0.0 +11469 0.0 +11470 0.0 +11471 0.0 +11472 0.0 +11473 0.0 +11474 0.0 +11475 0.0 +11476 0.0 +11477 0.0 +11478 0.0 +11479 0.0 +11480 0.0 +11481 0.0 +11482 0.0 +11483 0.0 +11484 0.0 +11485 0.0 +11486 0.0 +11487 0.0 +11488 0.0 +11489 0.0 +11490 0.0 +11491 0.0 +11492 0.0 +11493 0.0 +11494 0.0 +11495 0.0 +11496 0.0 +11497 0.0 +11498 0.0 +11499 0.0 +11500 0.0 +11501 0.0 +11502 0.0 +11503 0.0 +11504 0.0 +11505 0.0 +11506 0.0 +11507 0.0 +11508 0.0 +11509 0.0 +11510 0.0 +11511 0.0 +11512 0.0 +11513 0.0 +11514 0.0 +11515 0.0 +11516 0.0 +11517 0.0 +11518 0.0 +11519 0.0 +11520 0.0 +11521 0.0 +11522 0.0 +11523 0.0 +11524 0.0 +11525 0.0 +11526 0.0 +11527 0.0 +11528 0.0 +11529 0.0 +11530 0.0 +11531 0.0 +11532 0.0 +11533 0.0 +11534 0.0 +11535 0.0 +11536 0.0 +11537 0.0 +11538 0.0 +11539 0.0 +11540 0.0 +11541 0.0 +11542 0.0 +11543 0.0 +11544 0.0 +11545 0.0 +11546 0.0 +11547 0.0 +11548 0.0 +11549 0.0 +11550 0.0 +11551 0.0 +11552 0.0 +11553 0.0 +11554 0.0 +11555 0.0 +11556 0.0 +11557 0.0 +11558 0.0 +11559 0.0 +11560 0.0 +11561 0.0 +11562 0.0 +11563 0.0 +11564 0.0 +11565 0.0 +11566 0.0 +11567 0.0 +11568 0.0 +11569 0.0 +11570 0.0 +11571 0.0 +11572 0.0 +11573 0.0 +11574 0.0 +11575 0.0 +11576 0.0 +11577 0.0 +11578 0.0 +11579 0.0 +11580 0.0 +11581 0.0 +11582 0.0 +11583 0.0 +11584 0.0 +11585 0.0 +11586 0.0 +11587 0.0 +11588 0.0 +11589 0.0 +11590 0.0 +11591 0.0 +11592 0.0 +11593 0.0 +11594 0.0 +11595 0.0 +11596 0.0 +11597 0.0 +11598 0.0 +11599 0.0 +11600 0.0 +11601 0.0 +11602 0.0 +11603 0.0 +11604 0.0 +11605 0.0 +11606 0.0 +11607 0.0 +11608 0.0 +11609 0.0 +11610 0.0 +11611 0.0 +11612 0.0 +11613 0.0 +11614 0.0 +11615 0.0 +11616 0.0 +11617 0.0 +11618 0.0 +11619 0.0 +11620 0.0 +11621 0.0 +11622 0.0 +11623 0.0 +11624 0.0 +11625 0.0 +11626 0.0 +11627 0.0 +11628 0.0 +11629 0.0 +11630 0.0 +11631 0.0 +11632 0.0 +11633 0.0 +11634 0.0 +11635 0.0 +11636 0.0 +11637 0.0 +11638 0.0 +11639 0.0 +11640 0.0 +11641 0.0 +11642 0.0 +11643 0.0 +11644 0.0 +11645 0.0 +11646 0.0 +11647 0.0 +11648 0.0 +11649 0.0 +11650 0.0 +11651 0.0 +11652 0.0 +11653 0.0 +11654 0.0 +11655 0.0 +11656 0.0 +11657 0.0 +11658 0.0 +11659 0.0 +11660 0.0 +11661 0.0 +11662 0.0 +11663 0.0 +11664 0.0 +11665 0.0 +11666 0.0 +11667 0.0 +11668 0.0 +11669 0.0 +11670 0.0 +11671 0.0 +11672 0.0 +11673 0.0 +11674 0.0 +11675 0.0 +11676 0.0 +11677 0.0 +11678 0.0 +11679 0.0 +11680 0.0 +11681 0.0 +11682 0.0 +11683 0.0 +11684 0.0 +11685 0.0 +11686 0.0 +11687 0.0 +11688 0.0 +11689 0.0 +11690 0.0 +11691 0.0 +11692 0.0 +11693 0.0 +11694 0.0 +11695 0.0 +11696 0.0 +11697 0.0 +11698 0.0 +11699 0.0 +11700 0.0 +11701 0.0 +11702 0.0 +11703 0.0 +11704 0.0 +11705 0.0 +11706 0.0 +11707 0.0 +11708 0.0 +11709 0.0 +11710 0.0 +11711 0.0 +11712 0.0 +11713 0.0 +11714 0.0 +11715 0.0 +11716 0.0 +11717 0.0 +11718 0.0 +11719 0.0 +11720 0.0 +11721 0.0 +11722 0.0 +11723 0.0 +11724 0.0 +11725 0.0 +11726 0.0 +11727 0.0 +11728 0.0 +11729 0.0 +11730 0.0 +11731 0.0 +11732 0.0 +11733 0.0 +11734 0.0 +11735 0.0 +11736 0.0 +11737 0.0 +11738 0.0 +11739 0.0 +11740 0.0 +11741 0.0 +11742 0.0 +11743 0.0 +11744 0.0 +11745 0.0 +11746 0.0 +11747 0.0 +11748 0.0 +11749 0.0 +11750 0.0 +11751 0.0 +11752 0.0 +11753 0.0 +11754 0.0 +11755 0.0 +11756 0.0 +11757 0.0 +11758 0.0 +11759 0.0 +11760 0.0 +11761 0.0 +11762 0.0 +11763 0.0 +11764 0.0 +11765 0.0 +11766 0.0 +11767 0.0 +11768 0.0 +11769 0.0 +11770 0.0 +11771 0.0 +11772 0.0 +11773 0.0 +11774 0.0 +11775 0.0 +11776 0.0 +11777 0.0 +11778 0.0 +11779 0.0 +11780 0.0 +11781 0.0 +11782 0.0 +11783 0.0 +11784 0.0 +11785 0.0 +11786 0.0 +11787 0.0 +11788 0.0 +11789 0.0 +11790 0.0 +11791 0.0 +11792 0.0 +11793 0.0 +11794 0.0 +11795 0.0 +11796 0.0 +11797 0.0 +11798 0.0 +11799 0.0 +11800 0.0 +11801 0.0 +11802 0.0 +11803 0.0 +11804 0.0 +11805 0.0 +11806 0.0 +11807 0.0 +11808 0.0 +11809 0.0 +11810 0.0 +11811 0.0 +11812 0.0 +11813 0.0 +11814 0.0 +11815 0.0 +11816 0.0 +11817 0.0 +11818 0.0 +11819 0.0 +11820 0.0 +11821 0.0 +11822 0.0 +11823 0.0 +11824 0.0 +11825 0.0 +11826 0.0 +11827 0.0 +11828 0.0 +11829 0.0 +11830 0.0 +11831 0.0 +11832 0.0 +11833 0.0 +11834 0.0 +11835 0.0 +11836 0.0 +11837 0.0 +11838 0.0 +11839 0.0 +11840 0.0 +11841 0.0 +11842 0.0 +11843 0.0 +11844 0.0 +11845 0.0 +11846 0.0 +11847 0.0 +11848 0.0 +11849 0.0 +11850 0.0 +11851 0.0 +11852 0.0 +11853 0.0 +11854 0.0 +11855 0.0 +11856 0.0 +11857 0.0 +11858 0.0 +11859 0.0 +11860 0.0 +11861 0.0 +11862 0.0 +11863 0.0 +11864 0.0 +11865 0.0 +11866 0.0 +11867 0.0 +11868 0.0 +11869 0.0 +11870 0.0 +11871 0.0 +11872 0.0 +11873 0.0 +11874 0.0 +11875 0.0 +11876 0.0 +11877 0.0 +11878 0.0 +11879 0.0 +11880 0.0 +11881 0.0 +11882 0.0 +11883 0.0 +11884 0.0 +11885 0.0 +11886 0.0 +11887 0.0 +11888 0.0 +11889 0.0 +11890 0.0 +11891 0.0 +11892 0.0 +11893 0.0 +11894 0.0 +11895 0.0 +11896 0.0 +11897 0.0 +11898 0.0 +11899 0.0 +11900 0.0 +11901 0.0 +11902 0.0 +11903 0.0 +11904 0.0 +11905 0.0 +11906 0.0 +11907 0.0 +11908 0.0 +11909 0.0 +11910 0.0 +11911 0.0 +11912 0.0 +11913 0.0 +11914 0.0 +11915 0.0 +11916 0.0 +11917 0.0 +11918 0.0 +11919 0.0 +11920 0.0 +11921 0.0 +11922 0.0 +11923 0.0 +11924 0.0 +11925 0.0 +11926 0.0 +11927 0.0 +11928 0.0 +11929 0.0 +11930 0.0 +11931 0.0 +11932 0.0 +11933 0.0 +11934 0.0 +11935 0.0 +11936 0.0 +11937 0.0 +11938 0.0 +11939 0.0 +11940 0.0 +11941 0.0 +11942 0.0 +11943 0.0 +11944 0.0 +11945 0.0 +11946 0.0 +11947 0.0 +11948 0.0 +11949 0.0 +11950 0.0 +11951 0.0 +11952 0.0 +11953 0.0 +11954 0.0 +11955 0.0 +11956 0.0 +11957 0.0 +11958 0.0 +11959 0.0 +11960 0.0 +11961 0.0 +11962 0.0 +11963 0.0 +11964 0.0 +11965 0.0 +11966 0.0 +11967 0.0 +11968 0.0 +11969 0.0 +11970 0.0 +11971 0.0 +11972 0.0 +11973 0.0 +11974 0.0 +11975 0.0 +11976 0.0 +11977 0.0 +11978 0.0 +11979 0.0 +11980 0.0 +11981 0.0 +11982 0.0 +11983 0.0 +11984 0.0 +11985 0.0 +11986 0.0 +11987 0.0 +11988 0.0 +11989 0.0 +11990 0.0 +11991 0.0 +11992 0.0 +11993 0.0 +11994 0.0 +11995 0.0 +11996 0.0 +11997 0.0 +11998 0.0 +11999 0.0 +12000 0.0 +12001 0.0 +12002 0.0 +12003 0.0 +12004 0.0 +12005 0.0 +12006 0.0 +12007 0.0 +12008 0.0 +12009 0.0 +12010 0.0 +12011 0.0 +12012 0.0 +12013 0.0 +12014 0.0 +12015 0.0 +12016 0.0 +12017 0.0 +12018 0.0 +12019 0.0 +12020 0.0 +12021 0.0 +12022 0.0 +12023 0.0 +12024 0.0 +12025 0.0 +12026 0.0 +12027 0.0 +12028 0.0 +12029 0.0 +12030 0.0 +12031 0.0 +12032 0.0 +12033 0.0 +12034 0.0 +12035 0.0 +12036 0.0 +12037 0.0 +12038 0.0 +12039 0.0 +12040 0.0 +12041 0.0 +12042 0.0 +12043 0.0 +12044 0.0 +12045 0.0 +12046 0.0 +12047 0.0 +12048 0.0 +12049 0.0 +12050 0.0 +12051 0.0 +12052 0.0 +12053 0.0 +12054 0.0 +12055 0.0 +12056 0.0 +12057 0.0 +12058 0.0 +12059 0.0 +12060 0.0 +12061 0.0 +12062 0.0 +12063 0.0 +12064 0.0 +12065 0.0 +12066 0.0 +12067 0.0 +12068 0.0 +12069 0.0 +12070 0.0 +12071 0.0 +12072 0.0 +12073 0.0 +12074 0.0 +12075 0.0 +12076 0.0 +12077 0.0 +12078 0.0 +12079 0.0 +12080 0.0 +12081 0.0 +12082 0.0 +12083 0.0 +12084 0.0 +12085 0.0 +12086 0.0 +12087 0.0 +12088 0.0 +12089 0.0 +12090 0.0 +12091 0.0 +12092 0.0 +12093 0.0 +12094 0.0 +12095 0.0 +12096 0.0 +12097 0.0 +12098 0.0 +12099 0.0 +12100 0.0 +12101 0.0 +12102 0.0 +12103 0.0 +12104 0.0 +12105 0.0 +12106 0.0 +12107 0.0 +12108 0.0 +12109 0.0 +12110 0.0 +12111 0.0 +12112 0.0 +12113 0.0 +12114 0.0 +12115 0.0 +12116 0.0 +12117 0.0 +12118 0.0 +12119 0.0 +12120 0.0 +12121 0.0 +12122 0.0 +12123 0.0 +12124 0.0 +12125 0.0 +12126 0.0 +12127 0.0 +12128 0.0 +12129 0.0 +12130 0.0 +12131 0.0 +12132 0.0 +12133 0.0 +12134 0.0 +12135 0.0 +12136 0.0 +12137 0.0 +12138 0.0 +12139 0.0 +12140 0.0 +12141 0.0 +12142 0.0 +12143 0.0 +12144 0.0 +12145 0.0 +12146 0.0 +12147 0.0 +12148 0.0 +12149 0.0 +12150 0.0 +12151 0.0 +12152 0.0 +12153 0.0 +12154 0.0 +12155 0.0 +12156 0.0 +12157 0.0 +12158 0.0 +12159 0.0 +12160 0.0 +12161 0.0 +12162 0.0 +12163 0.0 +12164 0.0 +12165 0.0 +12166 0.0 +12167 0.0 +12168 0.0 +12169 0.0 +12170 0.0 +12171 0.0 +12172 0.0 +12173 0.0 +12174 0.0 +12175 0.0 +12176 0.0 +12177 0.0 +12178 0.0 +12179 0.0 +12180 0.0 +12181 0.0 +12182 0.0 +12183 0.0 +12184 0.0 +12185 0.0 +12186 0.0 +12187 0.0 +12188 0.0 +12189 0.0 +12190 0.0 +12191 0.0 +12192 0.0 +12193 0.0 +12194 0.0 +12195 0.0 +12196 0.0 +12197 0.0 +12198 0.0 +12199 0.0 +12200 0.0 +12201 0.0 +12202 0.0 +12203 0.0 +12204 0.0 +12205 0.0 +12206 0.0 +12207 0.0 +12208 0.0 +12209 0.0 +12210 0.0 +12211 0.0 +12212 0.0 +12213 0.0 +12214 0.0 +12215 0.0 +12216 0.0 +12217 0.0 +12218 0.0 +12219 0.0 +12220 0.0 +12221 0.0 +12222 0.0 +12223 0.0 +12224 0.0 +12225 0.0 +12226 0.0 +12227 0.0 +12228 0.0 +12229 0.0 +12230 0.0 +12231 0.0 +12232 0.0 +12233 0.0 +12234 0.0 +12235 0.0 +12236 0.0 +12237 0.0 +12238 0.0 +12239 0.0 +12240 0.0 +12241 0.0 +12242 0.0 +12243 0.0 +12244 0.0 +12245 0.0 +12246 0.0 +12247 0.0 +12248 0.0 +12249 0.0 +12250 0.0 +12251 0.0 +12252 0.0 +12253 0.0 +12254 0.0 +12255 0.0 +12256 0.0 +12257 0.0 +12258 0.0 +12259 0.0 +12260 0.0 +12261 0.0 +12262 0.0 +12263 0.0 +12264 0.0 +12265 0.0 +12266 0.0 +12267 0.0 +12268 0.0 +12269 0.0 +12270 0.0 +12271 0.0 +12272 0.0 +12273 0.0 +12274 0.0 +12275 0.0 +12276 0.0 +12277 0.0 +12278 0.0 +12279 0.0 +12280 0.0 +12281 0.0 +12282 0.0 +12283 0.0 +12284 0.0 +12285 0.0 +12286 0.0 +12287 0.0 +12288 0.0 +12289 0.0 +12290 0.0 +12291 0.0 +12292 0.0 +12293 0.0 +12294 0.0 +12295 0.0 +12296 0.0 +12297 0.0 +12298 0.0 +12299 0.0 +12300 0.0 +12301 0.0 +12302 0.0 +12303 0.0 +12304 0.0 +12305 0.0 +12306 0.0 +12307 0.0 +12308 0.0 +12309 0.0 +12310 0.0 +12311 0.0 +12312 0.0 +12313 0.0 +12314 0.0 +12315 0.0 +12316 0.0 +12317 0.0 +12318 0.0 +12319 0.0 +12320 0.0 +12321 0.0 +12322 0.0 +12323 0.0 +12324 0.0 +12325 0.0 +12326 0.0 +12327 0.0 +12328 0.0 +12329 0.0 +12330 0.0 +12331 0.0 +12332 0.0 +12333 0.0 +12334 0.0 +12335 0.0 +12336 0.0 +12337 0.0 +12338 0.0 +12339 0.0 +12340 0.0 +12341 0.0 +12342 0.0 +12343 0.0 +12344 0.0 +12345 0.0 +12346 0.0 +12347 0.0 +12348 0.0 +12349 0.0 +12350 0.0 +12351 0.0 +12352 0.0 +12353 0.0 +12354 0.0 +12355 0.0 +12356 0.0 +12357 0.0 +12358 0.0 +12359 0.0 +12360 0.0 +12361 0.0 +12362 0.0 +12363 0.0 +12364 0.0 +12365 0.0 +12366 0.0 +12367 0.0 +12368 0.0 +12369 0.0 +12370 0.0 +12371 0.0 +12372 0.0 +12373 0.0 +12374 0.0 +12375 0.0 +12376 0.0 +12377 0.0 +12378 0.0 +12379 0.0 +12380 0.0 +12381 0.0 +12382 0.0 +12383 0.0 +12384 0.0 +12385 0.0 +12386 0.0 +12387 0.0 +12388 0.0 +12389 0.0 +12390 0.0 +12391 0.0 +12392 0.0 +12393 0.0 +12394 0.0 +12395 0.0 +12396 0.0 +12397 0.0 +12398 0.0 +12399 0.0 +12400 0.0 +12401 0.0 +12402 0.0 +12403 0.0 +12404 0.0 +12405 0.0 +12406 0.0 +12407 0.0 +12408 0.0 +12409 0.0 +12410 0.0 +12411 0.0 +12412 0.0 +12413 0.0 +12414 0.0 +12415 0.0 +12416 0.0 +12417 0.0 +12418 0.0 +12419 0.0 +12420 0.0 +12421 0.0 +12422 0.0 +12423 0.0 +12424 0.0 +12425 0.0 +12426 0.0 +12427 0.0 +12428 0.0 +12429 0.0 +12430 0.0 +12431 0.0 +12432 0.0 +12433 0.0 +12434 0.0 +12435 0.0 +12436 0.0 +12437 0.0 +12438 0.0 +12439 0.0 +12440 0.0 +12441 0.0 +12442 0.0 +12443 0.0 +12444 0.0 +12445 0.0 +12446 0.0 +12447 0.0 +12448 0.0 +12449 0.0 +12450 0.0 +12451 0.0 +12452 0.0 +12453 0.0 +12454 0.0 +12455 0.0 +12456 0.0 +12457 0.0 +12458 0.0 +12459 0.0 +12460 0.0 +12461 0.0 +12462 0.0 +12463 0.0 +12464 0.0 +12465 0.0 +12466 0.0 +12467 0.0 +12468 0.0 +12469 0.0 +12470 0.0 +12471 0.0 +12472 0.0 +12473 0.0 +12474 0.0 +12475 0.0 +12476 0.0 +12477 0.0 +12478 0.0 +12479 0.0 +12480 0.0 +12481 0.0 +12482 0.0 +12483 0.0 +12484 0.0 +12485 0.0 +12486 0.0 +12487 0.0 +12488 0.0 +12489 0.0 +12490 0.0 +12491 0.0 +12492 0.0 +12493 0.0 +12494 0.0 +12495 0.0 +12496 0.0 +12497 0.0 +12498 0.0 +12499 0.0 +12500 0.0 +12501 0.0 +12502 0.0 +12503 0.0 +12504 0.0 +12505 0.0 +12506 0.0 +12507 0.0 +12508 0.0 +12509 0.0 +12510 0.0 +12511 0.0 +12512 0.0 +12513 0.0 +12514 0.0 +12515 0.0 +12516 0.0 +12517 0.0 +12518 0.0 +12519 0.0 +12520 0.0 +12521 0.0 +12522 0.0 +12523 0.0 +12524 0.0 +12525 0.0 +12526 0.0 +12527 0.0 +12528 0.0 +12529 0.0 +12530 0.0 +12531 0.0 +12532 0.0 +12533 0.0 +12534 0.0 +12535 0.0 +12536 0.0 +12537 0.0 +12538 0.0 +12539 0.0 +12540 0.0 +12541 0.0 +12542 0.0 +12543 0.0 +12544 0.0 +12545 0.0 +12546 0.0 +12547 0.0 +12548 0.0 +12549 0.0 +12550 0.0 +12551 0.0 +12552 0.0 +12553 0.0 +12554 0.0 +12555 0.0 +12556 0.0 +12557 0.0 +12558 0.0 +12559 0.0 +12560 0.0 +12561 0.0 +12562 0.0 +12563 0.0 +12564 0.0 +12565 0.0 +12566 0.0 +12567 0.0 +12568 0.0 +12569 0.0 +12570 0.0 +12571 0.0 +12572 0.0 +12573 0.0 +12574 0.0 +12575 0.0 +12576 0.0 +12577 0.0 +12578 0.0 +12579 0.0 +12580 0.0 +12581 0.0 +12582 0.0 +12583 0.0 +12584 0.0 +12585 0.0 +12586 0.0 +12587 0.0 +12588 0.0 +12589 0.0 +12590 0.0 +12591 0.0 +12592 0.0 +12593 0.0 +12594 0.0 +12595 0.0 +12596 0.0 +12597 0.0 +12598 0.0 +12599 0.0 +12600 0.0 +12601 0.0 +12602 0.0 +12603 0.0 +12604 0.0 +12605 0.0 +12606 0.0 +12607 0.0 +12608 0.0 +12609 0.0 +12610 0.0 +12611 0.0 +12612 0.0 +12613 0.0 +12614 0.0 +12615 0.0 +12616 0.0 +12617 0.0 +12618 0.0 +12619 0.0 +12620 0.0 +12621 0.0 +12622 0.0 +12623 0.0 +12624 0.0 +12625 0.0 +12626 0.0 +12627 0.0 +12628 0.0 +12629 0.0 +12630 0.0 +12631 0.0 +12632 0.0 +12633 0.0 +12634 0.0 +12635 0.0 +12636 0.0 +12637 0.0 +12638 0.0 +12639 0.0 +12640 0.0 +12641 0.0 +12642 0.0 +12643 0.0 +12644 0.0 +12645 0.0 +12646 0.0 +12647 0.0 +12648 0.0 +12649 0.0 +12650 0.0 +12651 0.0 +12652 0.0 +12653 0.0 +12654 0.0 +12655 0.0 +12656 0.0 +12657 0.0 +12658 0.0 +12659 0.0 +12660 0.0 +12661 0.0 +12662 0.0 +12663 0.0 +12664 0.0 +12665 0.0 +12666 0.0 +12667 0.0 +12668 0.0 +12669 0.0 +12670 0.0 +12671 0.0 +12672 0.0 +12673 0.0 +12674 0.0 +12675 0.0 +12676 0.0 +12677 0.0 +12678 0.0 +12679 0.0 +12680 0.0 +12681 0.0 +12682 0.0 +12683 0.0 +12684 0.0 +12685 0.0 +12686 0.0 +12687 0.0 +12688 0.0 +12689 0.0 +12690 0.0 +12691 0.0 +12692 0.0 +12693 0.0 +12694 0.0 +12695 0.0 +12696 0.0 +12697 0.0 +12698 0.0 +12699 0.0 +12700 0.0 +12701 0.0 +12702 0.0 +12703 0.0 +12704 0.0 +12705 0.0 +12706 0.0 +12707 0.0 +12708 0.0 +12709 0.0 +12710 0.0 +12711 0.0 +12712 0.0 +12713 0.0 +12714 0.0 +12715 0.0 +12716 0.0 +12717 0.0 +12718 0.0 +12719 0.0 +12720 0.0 +12721 0.0 +12722 0.0 +12723 0.0 +12724 0.0 +12725 0.0 +12726 0.0 +12727 0.0 +12728 0.0 +12729 0.0 +12730 0.0 +12731 0.0 +12732 0.0 +12733 0.0 +12734 0.0 +12735 0.0 +12736 0.0 +12737 0.0 +12738 0.0 +12739 0.0 +12740 0.0 +12741 0.0 +12742 0.0 +12743 0.0 +12744 0.0 +12745 0.0 +12746 0.0 +12747 0.0 +12748 0.0 +12749 0.0 +12750 0.0 +12751 0.0 +12752 0.0 +12753 0.0 +12754 0.0 +12755 0.0 +12756 0.0 +12757 0.0 +12758 0.0 +12759 0.0 +12760 0.0 +12761 0.0 +12762 0.0 +12763 0.0 +12764 0.0 +12765 0.0 +12766 0.0 +12767 0.0 +12768 0.0 +12769 0.0 +12770 0.0 +12771 0.0 +12772 0.0 +12773 0.0 +12774 0.0 +12775 0.0 +12776 0.0 +12777 0.0 +12778 0.0 +12779 0.0 +12780 0.0 +12781 0.0 +12782 0.0 +12783 0.0 +12784 0.0 +12785 0.0 +12786 0.0 +12787 0.0 +12788 0.0 +12789 0.0 +12790 0.0 +12791 0.0 +12792 0.0 +12793 0.0 +12794 0.0 +12795 0.0 +12796 0.0 +12797 0.0 +12798 0.0 +12799 0.0 +12800 0.0 +12801 0.0 +12802 0.0 +12803 0.0 +12804 0.0 +12805 0.0 +12806 0.0 +12807 0.0 +12808 0.0 +12809 0.0 +12810 0.0 +12811 0.0 +12812 0.0 +12813 0.0 +12814 0.0 +12815 0.0 +12816 0.0 +12817 0.0 +12818 0.0 +12819 0.0 +12820 0.0 +12821 0.0 +12822 0.0 +12823 0.0 +12824 0.0 +12825 0.0 +12826 0.0 +12827 0.0 +12828 0.0 +12829 0.0 +12830 0.0 +12831 0.0 +12832 0.0 +12833 0.0 +12834 0.0 +12835 0.0 +12836 0.0 +12837 0.0 +12838 0.0 +12839 0.0 +12840 0.0 +12841 0.0 +12842 0.0 +12843 0.0 +12844 0.0 +12845 0.0 +12846 0.0 +12847 0.0 +12848 0.0 +12849 0.0 +12850 0.0 +12851 0.0 +12852 0.0 +12853 0.0 +12854 0.0 +12855 0.0 +12856 0.0 +12857 0.0 +12858 0.0 +12859 0.0 +12860 0.0 +12861 0.0 +12862 0.0 +12863 0.0 +12864 0.0 +12865 0.0 +12866 0.0 +12867 0.0 +12868 0.0 +12869 0.0 +12870 0.0 +12871 0.0 +12872 0.0 +12873 0.0 +12874 0.0 +12875 0.0 +12876 0.0 +12877 0.0 +12878 0.0 +12879 0.0 +12880 0.0 +12881 0.0 +12882 0.0 +12883 0.0 +12884 0.0 +12885 0.0 +12886 0.0 +12887 0.0 +12888 0.0 +12889 0.0 +12890 0.0 +12891 0.0 +12892 0.0 +12893 0.0 +12894 0.0 +12895 0.0 +12896 0.0 +12897 0.0 +12898 0.0 +12899 0.0 +12900 0.0 +12901 0.0 +12902 0.0 +12903 0.0 +12904 0.0 +12905 0.0 +12906 0.0 +12907 0.0 +12908 0.0 +12909 0.0 +12910 0.0 +12911 0.0 +12912 0.0 +12913 0.0 +12914 0.0 +12915 0.0 +12916 0.0 +12917 0.0 +12918 0.0 +12919 0.0 +12920 0.0 +12921 0.0 +12922 0.0 +12923 0.0 +12924 0.0 +12925 0.0 +12926 0.0 +12927 0.0 +12928 0.0 +12929 0.0 +12930 0.0 +12931 0.0 +12932 0.0 +12933 0.0 +12934 0.0 +12935 0.0 +12936 0.0 +12937 0.0 +12938 0.0 +12939 0.0 +12940 0.0 +12941 0.0 +12942 0.0 +12943 0.0 +12944 0.0 +12945 0.0 +12946 0.0 +12947 0.0 +12948 0.0 +12949 0.0 +12950 0.0 +12951 0.0 +12952 0.0 +12953 0.0 +12954 0.0 +12955 0.0 +12956 0.0 +12957 0.0 +12958 0.0 +12959 0.0 +12960 0.0 +12961 0.0 +12962 0.0 +12963 0.0 +12964 0.0 +12965 0.0 +12966 0.0 +12967 0.0 +12968 0.0 +12969 0.0 +12970 0.0 +12971 0.0 +12972 0.0 +12973 0.0 +12974 0.0 +12975 0.0 +12976 0.0 +12977 0.0 +12978 0.0 +12979 0.0 +12980 0.0 +12981 0.0 +12982 0.0 +12983 0.0 +12984 0.0 +12985 0.0 +12986 0.0 +12987 0.0 +12988 0.0 +12989 0.0 +12990 0.0 +12991 0.0 +12992 0.0 +12993 0.0 +12994 0.0 +12995 0.0 +12996 0.0 +12997 0.0 +12998 0.0 +12999 0.0 +13000 0.0 +13001 0.0 +13002 0.0 +13003 0.0 +13004 0.0 +13005 0.0 +13006 0.0 +13007 0.0 +13008 0.0 +13009 0.0 +13010 0.0 +13011 0.0 +13012 0.0 +13013 0.0 +13014 0.0 +13015 0.0 +13016 0.0 +13017 0.0 +13018 0.0 +13019 0.0 +13020 0.0 +13021 0.0 +13022 0.0 +13023 0.0 +13024 0.0 +13025 0.0 +13026 0.0 +13027 0.0 +13028 0.0 +13029 0.0 +13030 0.0 +13031 0.0 +13032 0.0 +13033 0.0 +13034 0.0 +13035 0.0 +13036 0.0 +13037 0.0 +13038 0.0 +13039 0.0 +13040 0.0 +13041 0.0 +13042 0.0 +13043 0.0 +13044 0.0 +13045 0.0 +13046 0.0 +13047 0.0 +13048 0.0 +13049 0.0 +13050 0.0 +13051 0.0 +13052 0.0 +13053 0.0 +13054 0.0 +13055 0.0 +13056 0.0 +13057 0.0 +13058 0.0 +13059 0.0 +13060 0.0 +13061 0.0 +13062 0.0 +13063 0.0 +13064 0.0 +13065 0.0 +13066 0.0 +13067 0.0 +13068 0.0 +13069 0.0 +13070 0.0 +13071 0.0 +13072 0.0 +13073 0.0 +13074 0.0 +13075 0.0 +13076 0.0 +13077 0.0 +13078 0.0 +13079 0.0 +13080 0.0 +13081 0.0 +13082 0.0 +13083 0.0 +13084 0.0 +13085 0.0 +13086 0.0 +13087 0.0 +13088 0.0 +13089 0.0 +13090 0.0 +13091 0.0 +13092 0.0 +13093 0.0 +13094 0.0 +13095 0.0 +13096 0.0 +13097 0.0 +13098 0.0 +13099 0.0 +13100 0.0 +13101 0.0 +13102 0.0 +13103 0.0 +13104 0.0 +13105 0.0 +13106 0.0 +13107 0.0 +13108 0.0 +13109 0.0 +13110 0.0 +13111 0.0 +13112 0.0 +13113 0.0 +13114 0.0 +13115 0.0 +13116 0.0 +13117 0.0 +13118 0.0 +13119 0.0 +13120 0.0 +13121 0.0 +13122 0.0 +13123 0.0 +13124 0.0 +13125 0.0 +13126 0.0 +13127 0.0 +13128 0.0 +13129 0.0 +13130 0.0 +13131 0.0 +13132 0.0 +13133 0.0 +13134 0.0 +13135 0.0 +13136 0.0 +13137 0.0 +13138 0.0 +13139 0.0 +13140 0.0 +13141 0.0 +13142 0.0 +13143 0.0 +13144 0.0 +13145 0.0 +13146 0.0 +13147 0.0 +13148 0.0 +13149 0.0 +13150 0.0 +13151 0.0 +13152 0.0 +13153 0.0 +13154 0.0 +13155 0.0 +13156 0.0 +13157 0.0 +13158 0.0 +13159 0.0 +13160 0.0 +13161 0.0 +13162 0.0 +13163 0.0 +13164 0.0 +13165 0.0 +13166 0.0 +13167 0.0 +13168 0.0 +13169 0.0 +13170 0.0 +13171 0.0 +13172 0.0 +13173 0.0 +13174 0.0 +13175 0.0 +13176 0.0 +13177 0.0 +13178 0.0 +13179 0.0 +13180 0.0 +13181 0.0 +13182 0.0 +13183 0.0 +13184 0.0 +13185 0.0 +13186 0.0 +13187 0.0 +13188 0.0 +13189 0.0 +13190 0.0 +13191 0.0 +13192 0.0 +13193 0.0 +13194 0.0 +13195 0.0 +13196 0.0 +13197 0.0 +13198 0.0 +13199 0.0 +13200 0.0 +13201 0.0 +13202 0.0 +13203 0.0 +13204 0.0 +13205 0.0 +13206 0.0 +13207 0.0 +13208 0.0 +13209 0.0 +13210 0.0 +13211 0.0 +13212 0.0 +13213 0.0 +13214 0.0 +13215 0.0 +13216 0.0 +13217 0.0 +13218 0.0 +13219 0.0 +13220 0.0 +13221 0.0 +13222 0.0 +13223 0.0 +13224 0.0 +13225 0.0 +13226 0.0 +13227 0.0 +13228 0.0 +13229 0.0 +13230 0.0 +13231 0.0 +13232 0.0 +13233 0.0 +13234 0.0 +13235 0.0 +13236 0.0 +13237 0.0 +13238 0.0 +13239 0.0 +13240 0.0 +13241 0.0 +13242 0.0 +13243 0.0 +13244 0.0 +13245 0.0 +13246 0.0 +13247 0.0 +13248 0.0 +13249 0.0 +13250 0.0 +13251 0.0 +13252 0.0 +13253 0.0 +13254 0.0 +13255 0.0 +13256 0.0 +13257 0.0 +13258 0.0 +13259 0.0 +13260 0.0 +13261 0.0 +13262 0.0 +13263 0.0 +13264 0.0 +13265 0.0 +13266 0.0 +13267 0.0 +13268 0.0 +13269 0.0 +13270 0.0 +13271 0.0 +13272 0.0 +13273 0.0 +13274 0.0 +13275 0.0 +13276 0.0 +13277 0.0 +13278 0.0 +13279 0.0 +13280 0.0 +13281 0.0 +13282 0.0 +13283 0.0 +13284 0.0 +13285 0.0 +13286 0.0 +13287 0.0 +13288 0.0 +13289 0.0 +13290 0.0 +13291 0.0 +13292 0.0 +13293 0.0 +13294 0.0 +13295 0.0 +13296 0.0 +13297 0.0 +13298 0.0 +13299 0.0 +13300 0.0 +13301 0.0 +13302 0.0 +13303 0.0 +13304 0.0 +13305 0.0 +13306 0.0 +13307 0.0 +13308 0.0 +13309 0.0 +13310 0.0 +13311 0.0 +13312 0.0 +13313 0.0 +13314 0.0 +13315 0.0 +13316 0.0 +13317 0.0 +13318 0.0 +13319 0.0 +13320 0.0 +13321 0.0 +13322 0.0 +13323 0.0 +13324 0.0 +13325 0.0 +13326 0.0 +13327 0.0 +13328 0.0 +13329 0.0 +13330 0.0 +13331 0.0 +13332 0.0 +13333 0.0 +13334 0.0 +13335 0.0 +13336 0.0 +13337 0.0 +13338 0.0 +13339 0.0 +13340 0.0 +13341 0.0 +13342 0.0 +13343 0.0 +13344 0.0 +13345 0.0 +13346 0.0 +13347 0.0 +13348 0.0 +13349 0.0 +13350 0.0 +13351 0.0 +13352 0.0 +13353 0.0 +13354 0.0 +13355 0.0 +13356 0.0 +13357 0.0 +13358 0.0 +13359 0.0 +13360 0.0 +13361 0.0 +13362 0.0 +13363 0.0 +13364 0.0 +13365 0.0 +13366 0.0 +13367 0.0 +13368 0.0 +13369 0.0 +13370 0.0 +13371 0.0 +13372 0.0 +13373 0.0 +13374 0.0 +13375 0.0 +13376 0.0 +13377 0.0 +13378 0.0 +13379 0.0 +13380 0.0 +13381 0.0 +13382 0.0 +13383 0.0 +13384 0.0 +13385 0.0 +13386 0.0 +13387 0.0 +13388 0.0 +13389 0.0 +13390 0.0 +13391 0.0 +13392 0.0 +13393 0.0 +13394 0.0 +13395 0.0 +13396 0.0 +13397 0.0 +13398 0.0 +13399 0.0 +13400 0.0 +13401 0.0 +13402 0.0 +13403 0.0 +13404 0.0 +13405 0.0 +13406 0.0 +13407 0.0 +13408 0.0 +13409 0.0 +13410 0.0 +13411 0.0 +13412 0.0 +13413 0.0 +13414 0.0 +13415 0.0 +13416 0.0 +13417 0.0 +13418 0.0 +13419 0.0 +13420 0.0 +13421 0.0 +13422 0.0 +13423 0.0 +13424 0.0 +13425 0.0 +13426 0.0 +13427 0.0 +13428 0.0 +13429 0.0 +13430 0.0 +13431 0.0 +13432 0.0 +13433 0.0 +13434 0.0 +13435 0.0 +13436 0.0 +13437 0.0 +13438 0.0 +13439 0.0 +13440 0.0 +13441 0.0 +13442 0.0 +13443 0.0 +13444 0.0 +13445 0.0 +13446 0.0 +13447 0.0 +13448 0.0 +13449 0.0 +13450 0.0 +13451 0.0 +13452 0.0 +13453 0.0 +13454 0.0 +13455 0.0 +13456 0.0 +13457 0.0 +13458 0.0 +13459 0.0 +13460 0.0 +13461 0.0 +13462 0.0 +13463 0.0 +13464 0.0 +13465 0.0 +13466 0.0 +13467 0.0 +13468 0.0 +13469 0.0 +13470 0.0 +13471 0.0 +13472 0.0 +13473 0.0 +13474 0.0 +13475 0.0 +13476 0.0 +13477 0.0 +13478 0.0 +13479 0.0 +13480 0.0 +13481 0.0 +13482 0.0 +13483 0.0 +13484 0.0 +13485 0.0 +13486 0.0 +13487 0.0 +13488 0.0 +13489 0.0 +13490 0.0 +13491 0.0 +13492 0.0 +13493 0.0 +13494 0.0 +13495 0.0 +13496 0.0 +13497 0.0 +13498 0.0 +13499 0.0 +13500 0.0 +13501 0.0 +13502 0.0 +13503 0.0 +13504 0.0 +13505 0.0 +13506 0.0 +13507 0.0 +13508 0.0 +13509 0.0 +13510 0.0 +13511 0.0 +13512 0.0 +13513 0.0 +13514 0.0 +13515 0.0 +13516 0.0 +13517 0.0 +13518 0.0 +13519 0.0 +13520 0.0 +13521 0.0 +13522 0.0 +13523 0.0 +13524 0.0 +13525 0.0 +13526 0.0 +13527 0.0 +13528 0.0 +13529 0.0 +13530 0.0 +13531 0.0 +13532 0.0 +13533 0.0 +13534 0.0 +13535 0.0 +13536 0.0 +13537 0.0 +13538 0.0 +13539 0.0 +13540 0.0 +13541 0.0 +13542 0.0 +13543 0.0 +13544 0.0 +13545 0.0 +13546 0.0 +13547 0.0 +13548 0.0 +13549 0.0 +13550 0.0 +13551 0.0 +13552 0.0 +13553 0.0 +13554 0.0 +13555 0.0 +13556 0.0 +13557 0.0 +13558 0.0 +13559 0.0 +13560 0.0 +13561 0.0 +13562 0.0 +13563 0.0 +13564 0.0 +13565 0.0 +13566 0.0 +13567 0.0 +13568 0.0 +13569 0.0 +13570 0.0 +13571 0.0 +13572 0.0 +13573 0.0 +13574 0.0 +13575 0.0 +13576 0.0 +13577 0.0 +13578 0.0 +13579 0.0 +13580 0.0 +13581 0.0 +13582 0.0 +13583 0.0 +13584 0.0 +13585 0.0 +13586 0.0 +13587 0.0 +13588 0.0 +13589 0.0 +13590 0.0 +13591 0.0 +13592 0.0 +13593 0.0 +13594 0.0 +13595 0.0 +13596 0.0 +13597 0.0 +13598 0.0 +13599 0.0 +13600 0.0 +13601 0.0 +13602 0.0 +13603 0.0 +13604 0.0 +13605 0.0 +13606 0.0 +13607 0.0 +13608 0.0 +13609 0.0 +13610 0.0 +13611 0.0 +13612 0.0 +13613 0.0 +13614 0.0 +13615 0.0 +13616 0.0 +13617 0.0 +13618 0.0 +13619 0.0 +13620 0.0 +13621 0.0 +13622 0.0 +13623 0.0 +13624 0.0 +13625 0.0 +13626 0.0 +13627 0.0 +13628 0.0 +13629 0.0 +13630 0.0 +13631 0.0 +13632 0.0 +13633 0.0 +13634 0.0 +13635 0.0 +13636 0.0 +13637 0.0 +13638 0.0 +13639 0.0 +13640 0.0 +13641 0.0 +13642 0.0 +13643 0.0 +13644 0.0 +13645 0.0 +13646 0.0 +13647 0.0 +13648 0.0 +13649 0.0 +13650 0.0 +13651 0.0 +13652 0.0 +13653 0.0 +13654 0.0 +13655 0.0 +13656 0.0 +13657 0.0 +13658 0.0 +13659 0.0 +13660 0.0 +13661 0.0 +13662 0.0 +13663 0.0 +13664 0.0 +13665 0.0 +13666 0.0 +13667 0.0 +13668 0.0 +13669 0.0 +13670 0.0 +13671 0.0 +13672 0.0 +13673 0.0 +13674 0.0 +13675 0.0 +13676 0.0 +13677 0.0 +13678 0.0 +13679 0.0 +13680 0.0 +13681 0.0 +13682 0.0 +13683 0.0 +13684 0.0 +13685 0.0 +13686 0.0 +13687 0.0 +13688 0.0 +13689 0.0 +13690 0.0 +13691 0.0 +13692 0.0 +13693 0.0 +13694 0.0 +13695 0.0 +13696 0.0 +13697 0.0 +13698 0.0 +13699 0.0 +13700 0.0 +13701 0.0 +13702 0.0 +13703 0.0 +13704 0.0 +13705 0.0 +13706 0.0 +13707 0.0 +13708 0.0 +13709 0.0 +13710 0.0 +13711 0.0 +13712 0.0 +13713 0.0 +13714 0.0 +13715 0.0 +13716 0.0 +13717 0.0 +13718 0.0 +13719 0.0 +13720 0.0 +13721 0.0 +13722 0.0 +13723 0.0 +13724 0.0 +13725 0.0 +13726 0.0 +13727 0.0 +13728 0.0 +13729 0.0 +13730 0.0 +13731 0.0 +13732 0.0 +13733 0.0 +13734 0.0 +13735 0.0 +13736 0.0 +13737 0.0 +13738 0.0 +13739 0.0 +13740 0.0 +13741 0.0 +13742 0.0 +13743 0.0 +13744 0.0 +13745 0.0 +13746 0.0 +13747 0.0 +13748 0.0 +13749 0.0 +13750 0.0 +13751 0.0 +13752 0.0 +13753 0.0 +13754 0.0 +13755 0.0 +13756 0.0 +13757 0.0 +13758 0.0 +13759 0.0 +13760 0.0 +13761 0.0 +13762 0.0 +13763 0.0 +13764 0.0 +13765 0.0 +13766 0.0 +13767 0.0 +13768 0.0 +13769 0.0 +13770 0.0 +13771 0.0 +13772 0.0 +13773 0.0 +13774 0.0 +13775 0.0 +13776 0.0 +13777 0.0 +13778 0.0 +13779 0.0 +13780 0.0 +13781 0.0 +13782 0.0 +13783 0.0 +13784 0.0 +13785 0.0 +13786 0.0 +13787 0.0 +13788 0.0 +13789 0.0 +13790 0.0 +13791 0.0 +13792 0.0 +13793 0.0 +13794 0.0 +13795 0.0 +13796 0.0 +13797 0.0 +13798 0.0 +13799 0.0 +13800 0.0 +13801 0.0 +13802 0.0 +13803 0.0 +13804 0.0 +13805 0.0 +13806 0.0 +13807 0.0 +13808 0.0 +13809 0.0 +13810 0.0 +13811 0.0 +13812 0.0 +13813 0.0 +13814 0.0 +13815 0.0 +13816 0.0 +13817 0.0 +13818 0.0 +13819 0.0 +13820 0.0 +13821 0.0 +13822 0.0 +13823 0.0 +13824 0.0 +13825 0.0 +13826 0.0 +13827 0.0 +13828 0.0 +13829 0.0 +13830 0.0 +13831 0.0 +13832 0.0 +13833 0.0 +13834 0.0 +13835 0.0 +13836 0.0 +13837 0.0 +13838 0.0 +13839 0.0 +13840 0.0 +13841 0.0 +13842 0.0 +13843 0.0 +13844 0.0 +13845 0.0 +13846 0.0 +13847 0.0 +13848 0.0 +13849 0.0 +13850 0.0 +13851 0.0 +13852 0.0 +13853 0.0 +13854 0.0 +13855 0.0 +13856 0.0 +13857 0.0 +13858 0.0 +13859 0.0 +13860 0.0 +13861 0.0 +13862 0.0 +13863 0.0 +13864 0.0 +13865 0.0 +13866 0.0 +13867 0.0 +13868 0.0 +13869 0.0 +13870 0.0 +13871 0.0 +13872 0.0 +13873 0.0 +13874 0.0 +13875 0.0 +13876 0.0 +13877 0.0 +13878 0.0 +13879 0.0 +13880 0.0 +13881 0.0 +13882 0.0 +13883 0.0 +13884 0.0 +13885 0.0 +13886 0.0 +13887 0.0 +13888 0.0 +13889 0.0 +13890 0.0 +13891 0.0 +13892 0.0 +13893 0.0 +13894 0.0 +13895 0.0 +13896 0.0 +13897 0.0 +13898 0.0 +13899 0.0 +13900 0.0 +13901 0.0 +13902 0.0 +13903 0.0 +13904 0.0 +13905 0.0 +13906 0.0 +13907 0.0 +13908 0.0 +13909 0.0 +13910 0.0 +13911 0.0 +13912 0.0 +13913 0.0 +13914 0.0 +13915 0.0 +13916 0.0 +13917 0.0 +13918 0.0 +13919 0.0 +13920 0.0 +13921 0.0 +13922 0.0 +13923 0.0 +13924 0.0 +13925 0.0 +13926 0.0 +13927 0.0 +13928 0.0 +13929 0.0 +13930 0.0 +13931 0.0 +13932 0.0 +13933 0.0 +13934 0.0 +13935 0.0 +13936 0.0 +13937 0.0 +13938 0.0 +13939 0.0 +13940 0.0 +13941 0.0 +13942 0.0 +13943 0.0 +13944 0.0 +13945 0.0 +13946 0.0 +13947 0.0 +13948 0.0 +13949 0.0 +13950 0.0 +13951 0.0 +13952 0.0 +13953 0.0 +13954 0.0 +13955 0.0 +13956 0.0 +13957 0.0 +13958 0.0 +13959 0.0 +13960 0.0 +13961 0.0 +13962 0.0 +13963 0.0 +13964 0.0 +13965 0.0 +13966 0.0 +13967 0.0 +13968 0.0 +13969 0.0 +13970 0.0 +13971 0.0 +13972 0.0 +13973 0.0 +13974 0.0 +13975 0.0 +13976 0.0 +13977 0.0 +13978 0.0 +13979 0.0 +13980 0.0 +13981 0.0 +13982 0.0 +13983 0.0 +13984 0.0 +13985 0.0 +13986 0.0 +13987 0.0 +13988 0.0 +13989 0.0 +13990 0.0 +13991 0.0 +13992 0.0 +13993 0.0 +13994 0.0 +13995 0.0 +13996 0.0 +13997 0.0 +13998 0.0 +13999 0.0 +14000 0.0 +14001 0.0 +14002 0.0 +14003 0.0 +14004 0.0 +14005 0.0 +14006 0.0 +14007 0.0 +14008 0.0 +14009 0.0 +14010 0.0 +14011 0.0 +14012 0.0 +14013 0.0 +14014 0.0 +14015 0.0 +14016 0.0 +14017 0.0 +14018 0.0 +14019 0.0 +14020 0.0 +14021 0.0 +14022 0.0 +14023 0.0 +14024 0.0 +14025 0.0 +14026 0.0 +14027 0.0 +14028 0.0 +14029 0.0 +14030 0.0 +14031 0.0 +14032 0.0 +14033 0.0 +14034 0.0 +14035 0.0 +14036 0.0 +14037 0.0 +14038 0.0 +14039 0.0 +14040 0.0 +14041 0.0 +14042 0.0 +14043 0.0 +14044 0.0 +14045 0.0 +14046 0.0 +14047 0.0 +14048 0.0 +14049 0.0 +14050 0.0 +14051 0.0 +14052 0.0 +14053 0.0 +14054 0.0 +14055 0.0 +14056 0.0 +14057 0.0 +14058 0.0 +14059 0.0 +14060 0.0 +14061 0.0 +14062 0.0 +14063 0.0 +14064 0.0 +14065 0.0 +14066 0.0 +14067 0.0 +14068 0.0 +14069 0.0 +14070 0.0 +14071 0.0 +14072 0.0 +14073 0.0 +14074 0.0 +14075 0.0 +14076 0.0 +14077 0.0 +14078 0.0 +14079 0.0 +14080 0.0 +14081 0.0 +14082 0.0 +14083 0.0 +14084 0.0 +14085 0.0 +14086 0.0 +14087 0.0 +14088 0.0 +14089 0.0 +14090 0.0 +14091 0.0 +14092 0.0 +14093 0.0 +14094 0.0 +14095 0.0 +14096 0.0 +14097 0.0 +14098 0.0 +14099 0.0 +14100 0.0 +14101 0.0 +14102 0.0 +14103 0.0 +14104 0.0 +14105 0.0 +14106 0.0 +14107 0.0 +14108 0.0 +14109 0.0 +14110 0.0 +14111 0.0 +14112 0.0 +14113 0.0 +14114 0.0 +14115 0.0 +14116 0.0 +14117 0.0 +14118 0.0 +14119 0.0 +14120 0.0 +14121 0.0 +14122 0.0 +14123 0.0 +14124 0.0 +14125 0.0 +14126 0.0 +14127 0.0 +14128 0.0 +14129 0.0 +14130 0.0 +14131 0.0 +14132 0.0 +14133 0.0 +14134 0.0 +14135 0.0 +14136 0.0 +14137 0.0 +14138 0.0 +14139 0.0 +14140 0.0 +14141 0.0 +14142 0.0 +14143 0.0 +14144 0.0 +14145 0.0 +14146 0.0 +14147 0.0 +14148 0.0 +14149 0.0 +14150 0.0 +14151 0.0 +14152 0.0 +14153 0.0 +14154 0.0 +14155 0.0 +14156 0.0 +14157 0.0 +14158 0.0 +14159 0.0 +14160 0.0 +14161 0.0 +14162 0.0 +14163 0.0 +14164 0.0 +14165 0.0 +14166 0.0 +14167 0.0 +14168 0.0 +14169 0.0 +14170 0.0 +14171 0.0 +14172 0.0 +14173 0.0 +14174 0.0 +14175 0.0 +14176 0.0 +14177 0.0 +14178 0.0 +14179 0.0 +14180 0.0 +14181 0.0 +14182 0.0 +14183 0.0 +14184 0.0 +14185 0.0 +14186 0.0 +14187 0.0 +14188 0.0 +14189 0.0 +14190 0.0 +14191 0.0 +14192 0.0 +14193 0.0 +14194 0.0 +14195 0.0 +14196 0.0 +14197 0.0 +14198 0.0 +14199 0.0 +14200 0.0 +14201 0.0 +14202 0.0 +14203 0.0 +14204 0.0 +14205 0.0 +14206 0.0 +14207 0.0 +14208 0.0 +14209 0.0 +14210 0.0 +14211 0.0 +14212 0.0 +14213 0.0 +14214 0.0 +14215 0.0 +14216 0.0 +14217 0.0 +14218 0.0 +14219 0.0 +14220 0.0 +14221 0.0 +14222 0.0 +14223 0.0 +14224 0.0 +14225 0.0 +14226 0.0 +14227 0.0 +14228 0.0 +14229 0.0 +14230 0.0 +14231 0.0 +14232 0.0 +14233 0.0 +14234 0.0 +14235 0.0 +14236 0.0 +14237 0.0 +14238 0.0 +14239 0.0 +14240 0.0 +14241 0.0 +14242 0.0 +14243 0.0 +14244 0.0 +14245 0.0 +14246 0.0 +14247 0.0 +14248 0.0 +14249 0.0 +14250 0.0 +14251 0.0 +14252 0.0 +14253 0.0 +14254 0.0 +14255 0.0 +14256 0.0 +14257 0.0 +14258 0.0 +14259 0.0 +14260 0.0 +14261 0.0 +14262 0.0 +14263 0.0 +14264 0.0 +14265 0.0 +14266 0.0 +14267 0.0 +14268 0.0 +14269 0.0 +14270 0.0 +14271 0.0 +14272 0.0 +14273 0.0 +14274 0.0 +14275 0.0 +14276 0.0 +14277 0.0 +14278 0.0 +14279 0.0 +14280 0.0 +14281 0.0 +14282 0.0 +14283 0.0 +14284 0.0 +14285 0.0 +14286 0.0 +14287 0.0 +14288 0.0 +14289 0.0 +14290 0.0 +14291 0.0 +14292 0.0 +14293 0.0 +14294 0.0 +14295 0.0 +14296 0.0 +14297 0.0 +14298 0.0 +14299 0.0 +14300 0.0 +14301 0.0 +14302 0.0 +14303 0.0 +14304 0.0 +14305 0.0 +14306 0.0 +14307 0.0 +14308 0.0 +14309 0.0 +14310 0.0 +14311 0.0 +14312 0.0 +14313 0.0 +14314 0.0 +14315 0.0 +14316 0.0 +14317 0.0 +14318 0.0 +14319 0.0 +14320 0.0 +14321 0.0 +14322 0.0 +14323 0.0 +14324 0.0 +14325 0.0 +14326 0.0 +14327 0.0 +14328 0.0 +14329 0.0 +14330 0.0 +14331 0.0 +14332 0.0 +14333 0.0 +14334 0.0 +14335 0.0 +14336 0.0 +14337 0.0 +14338 0.0 +14339 0.0 +14340 0.0 +14341 0.0 +14342 0.0 +14343 0.0 +14344 0.0 +14345 0.0 +14346 0.0 +14347 0.0 +14348 0.0 +14349 0.0 +14350 0.0 +14351 0.0 +14352 0.0 +14353 0.0 +14354 0.0 +14355 0.0 +14356 0.0 +14357 0.0 +14358 0.0 +14359 0.0 +14360 0.0 +14361 0.0 +14362 0.0 +14363 0.0 +14364 0.0 +14365 0.0 +14366 0.0 +14367 0.0 +14368 0.0 +14369 0.0 +14370 0.0 +14371 0.0 +14372 0.0 +14373 0.0 +14374 0.0 +14375 0.0 +14376 0.0 +14377 0.0 +14378 0.0 +14379 0.0 +14380 0.0 +14381 0.0 +14382 0.0 +14383 0.0 +14384 0.0 +14385 0.0 +14386 0.0 +14387 0.0 +14388 0.0 +14389 0.0 +14390 0.0 +14391 0.0 +14392 0.0 +14393 0.0 +14394 0.0 +14395 0.0 +14396 0.0 +14397 0.0 +14398 0.0 +14399 0.0 +14400 0.0 +14401 0.0 +14402 0.0 +14403 0.0 +14404 0.0 +14405 0.0 +14406 0.0 +14407 0.0 +14408 0.0 +14409 0.0 +14410 0.0 +14411 0.0 +14412 0.0 +14413 0.0 +14414 0.0 +14415 0.0 +14416 0.0 +14417 0.0 +14418 0.0 +14419 0.0 +14420 0.0 +14421 0.0 +14422 0.0 +14423 0.0 +14424 0.0 +14425 0.0 +14426 0.0 +14427 0.0 +14428 0.0 +14429 0.0 +14430 0.0 +14431 0.0 +14432 0.0 +14433 0.0 +14434 0.0 +14435 0.0 +14436 0.0 +14437 0.0 +14438 0.0 +14439 0.0 +14440 0.0 +14441 0.0 +14442 0.0 +14443 0.0 +14444 0.0 +14445 0.0 +14446 0.0 +14447 0.0 +14448 0.0 +14449 0.0 +14450 0.0 +14451 0.0 +14452 0.0 +14453 0.0 +14454 0.0 +14455 0.0 +14456 0.0 +14457 0.0 +14458 0.0 +14459 0.0 +14460 0.0 +14461 0.0 +14462 0.0 +14463 0.0 +14464 0.0 +14465 0.0 +14466 0.0 +14467 0.0 +14468 0.0 +14469 0.0 +14470 0.0 +14471 0.0 +14472 0.0 +14473 0.0 +14474 0.0 +14475 0.0 +14476 0.0 +14477 0.0 +14478 0.0 +14479 0.0 +14480 0.0 +14481 0.0 +14482 0.0 +14483 0.0 +14484 0.0 +14485 0.0 +14486 0.0 +14487 0.0 +14488 0.0 +14489 0.0 +14490 0.0 +14491 0.0 +14492 0.0 +14493 0.0 +14494 0.0 +14495 0.0 +14496 0.0 +14497 0.0 +14498 0.0 +14499 0.0 +14500 0.0 +14501 0.0 +14502 0.0 +14503 0.0 +14504 0.0 +14505 0.0 +14506 0.0 +14507 0.0 +14508 0.0 +14509 0.0 +14510 0.0 +14511 0.0 +14512 0.0 +14513 0.0 +14514 0.0 +14515 0.0 +14516 0.0 +14517 0.0 +14518 0.0 +14519 0.0 +14520 0.0 +14521 0.0 +14522 0.0 +14523 0.0 +14524 0.0 +14525 0.0 +14526 0.0 +14527 0.0 +14528 0.0 +14529 0.0 +14530 0.0 +14531 0.0 +14532 0.0 +14533 0.0 +14534 0.0 +14535 0.0 +14536 0.0 +14537 0.0 +14538 0.0 +14539 0.0 +14540 0.0 +14541 0.0 +14542 0.0 +14543 0.0 +14544 0.0 +14545 0.0 +14546 0.0 +14547 0.0 +14548 0.0 +14549 0.0 +14550 0.0 +14551 0.0 +14552 0.0 +14553 0.0 +14554 0.0 +14555 0.0 +14556 0.0 +14557 0.0 +14558 0.0 +14559 0.0 +14560 0.0 +14561 0.0 +14562 0.0 +14563 0.0 +14564 0.0 +14565 0.0 +14566 0.0 +14567 0.0 +14568 0.0 +14569 0.0 +14570 0.0 +14571 0.0 +14572 0.0 +14573 0.0 +14574 0.0 +14575 0.0 +14576 0.0 +14577 0.0 +14578 0.0 +14579 0.0 +14580 0.0 +14581 0.0 +14582 0.0 +14583 0.0 +14584 0.0 +14585 0.0 +14586 0.0 +14587 0.0 +14588 0.0 +14589 0.0 +14590 0.0 +14591 0.0 +14592 0.0 +14593 0.0 +14594 0.0 +14595 0.0 +14596 0.0 +14597 0.0 +14598 0.0 +14599 0.0 +14600 0.0 +14601 0.0 +14602 0.0 +14603 0.0 +14604 0.0 +14605 0.0 +14606 0.0 +14607 0.0 +14608 0.0 +14609 0.0 +14610 0.0 +14611 0.0 +14612 0.0 +14613 0.0 +14614 0.0 +14615 0.0 +14616 0.0 +14617 0.0 +14618 0.0 +14619 0.0 +14620 0.0 +14621 0.0 +14622 0.0 +14623 0.0 +14624 0.0 +14625 0.0 +14626 0.0 +14627 0.0 +14628 0.0 +14629 0.0 +14630 0.0 +14631 0.0 +14632 0.0 +14633 0.0 +14634 0.0 +14635 0.0 +14636 0.0 +14637 0.0 +14638 0.0 +14639 0.0 +14640 0.0 +14641 0.0 +14642 0.0 +14643 0.0 +14644 0.0 +14645 0.0 +14646 0.0 +14647 0.0 +14648 0.0 +14649 0.0 +14650 0.0 +14651 0.0 +14652 0.0 +14653 0.0 +14654 0.0 +14655 0.0 +14656 0.0 +14657 0.0 +14658 0.0 +14659 0.0 +14660 0.0 +14661 0.0 +14662 0.0 +14663 0.0 +14664 0.0 +14665 0.0 +14666 0.0 +14667 0.0 +14668 0.0 +14669 0.0 +14670 0.0 +14671 0.0 +14672 0.0 +14673 0.0 +14674 0.0 +14675 0.0 +14676 0.0 +14677 0.0 +14678 0.0 +14679 0.0 +14680 0.0 +14681 0.0 +14682 0.0 +14683 0.0 +14684 0.0 +14685 0.0 +14686 0.0 +14687 0.0 +14688 0.0 +14689 0.0 +14690 0.0 +14691 0.0 +14692 0.0 +14693 0.0 +14694 0.0 +14695 0.0 +14696 0.0 +14697 0.0 +14698 0.0 +14699 0.0 +14700 0.0 +14701 0.0 +14702 0.0 +14703 0.0 +14704 0.0 +14705 0.0 +14706 0.0 +14707 0.0 +14708 0.0 +14709 0.0 +14710 0.0 +14711 0.0 +14712 0.0 +14713 0.0 +14714 0.0 +14715 0.0 +14716 0.0 +14717 0.0 +14718 0.0 +14719 0.0 +14720 0.0 +14721 0.0 +14722 0.0 +14723 0.0 +14724 0.0 +14725 0.0 +14726 0.0 +14727 0.0 +14728 0.0 +14729 0.0 +14730 0.0 +14731 0.0 +14732 0.0 +14733 0.0 +14734 0.0 +14735 0.0 +14736 0.0 +14737 0.0 +14738 0.0 +14739 0.0 +14740 0.0 +14741 0.0 +14742 0.0 +14743 0.0 +14744 0.0 +14745 0.0 +14746 0.0 +14747 0.0 +14748 0.0 +14749 0.0 +14750 0.0 +14751 0.0 +14752 0.0 +14753 0.0 +14754 0.0 +14755 0.0 +14756 0.0 +14757 0.0 +14758 0.0 +14759 0.0 +14760 0.0 +14761 0.0 +14762 0.0 +14763 0.0 +14764 0.0 +14765 0.0 +14766 0.0 +14767 0.0 +14768 0.0 +14769 0.0 +14770 0.0 +14771 0.0 +14772 0.0 +14773 0.0 +14774 0.0 +14775 0.0 +14776 0.0 +14777 0.0 +14778 0.0 +14779 0.0 +14780 0.0 +14781 0.0 +14782 0.0 +14783 0.0 +14784 0.0 +14785 0.0 +14786 0.0 +14787 0.0 +14788 0.0 +14789 0.0 +14790 0.0 +14791 0.0 +14792 0.0 +14793 0.0 +14794 0.0 +14795 0.0 +14796 0.0 +14797 0.0 +14798 0.0 +14799 0.0 +14800 0.0 +14801 0.0 +14802 0.0 +14803 0.0 +14804 0.0 +14805 0.0 +14806 0.0 +14807 0.0 +14808 0.0 +14809 0.0 +14810 0.0 +14811 0.0 +14812 0.0 +14813 0.0 +14814 0.0 +14815 0.0 +14816 0.0 +14817 0.0 +14818 0.0 +14819 0.0 +14820 0.0 +14821 0.0 +14822 0.0 +14823 0.0 +14824 0.0 +14825 0.0 +14826 0.0 +14827 0.0 +14828 0.0 +14829 0.0 +14830 0.0 +14831 0.0 +14832 0.0 +14833 0.0 +14834 0.0 +14835 0.0 +14836 0.0 +14837 0.0 +14838 0.0 +14839 0.0 +14840 0.0 +14841 0.0 +14842 0.0 +14843 0.0 +14844 0.0 +14845 0.0 +14846 0.0 +14847 0.0 +14848 0.0 +14849 0.0 +14850 0.0 +14851 0.0 +14852 0.0 +14853 0.0 +14854 0.0 +14855 0.0 +14856 0.0 +14857 0.0 +14858 0.0 +14859 0.0 +14860 0.0 +14861 0.0 +14862 0.0 +14863 0.0 +14864 0.0 +14865 0.0 +14866 0.0 +14867 0.0 +14868 0.0 +14869 0.0 +14870 0.0 +14871 0.0 +14872 0.0 +14873 0.0 +14874 0.0 +14875 0.0 +14876 0.0 +14877 0.0 +14878 0.0 +14879 0.0 +14880 0.0 +14881 0.0 +14882 0.0 +14883 0.0 +14884 0.0 +14885 0.0 +14886 0.0 +14887 0.0 +14888 0.0 +14889 0.0 +14890 0.0 +14891 0.0 +14892 0.0 +14893 0.0 +14894 0.0 +14895 0.0 +14896 0.0 +14897 0.0 +14898 0.0 +14899 0.0 +14900 0.0 +14901 0.0 +14902 0.0 +14903 0.0 +14904 0.0 +14905 0.0 +14906 0.0 +14907 0.0 +14908 0.0 +14909 0.0 +14910 0.0 +14911 0.0 +14912 0.0 +14913 0.0 +14914 0.0 +14915 0.0 +14916 0.0 +14917 0.0 +14918 0.0 +14919 0.0 +14920 0.0 +14921 0.0 +14922 0.0 +14923 0.0 +14924 0.0 +14925 0.0 +14926 0.0 +14927 0.0 +14928 0.0 +14929 0.0 +14930 0.0 +14931 0.0 +14932 0.0 +14933 0.0 +14934 0.0 +14935 0.0 +14936 0.0 +14937 0.0 +14938 0.0 +14939 0.0 +14940 0.0 +14941 0.0 +14942 0.0 +14943 0.0 +14944 0.0 +14945 0.0 +14946 0.0 +14947 0.0 +14948 0.0 +14949 0.0 +14950 0.0 +14951 0.0 +14952 0.0 +14953 0.0 +14954 0.0 +14955 0.0 +14956 0.0 +14957 0.0 +14958 0.0 +14959 0.0 +14960 0.0 +14961 0.0 +14962 0.0 +14963 0.0 +14964 0.0 +14965 0.0 +14966 0.0 +14967 0.0 +14968 0.0 +14969 0.0 +14970 0.0 +14971 0.0 +14972 0.0 +14973 0.0 +14974 0.0 +14975 0.0 +14976 0.0 +14977 0.0 +14978 0.0 +14979 0.0 +14980 0.0 +14981 0.0 +14982 0.0 +14983 0.0 +14984 0.0 +14985 0.0 +14986 0.0 +14987 0.0 +14988 0.0 +14989 0.0 +14990 0.0 +14991 0.0 +14992 0.0 +14993 0.0 +14994 0.0 +14995 0.0 +14996 0.0 +14997 0.0 +14998 0.0 +14999 0.0 +15000 0.0 +15001 0.0 +15002 0.0 +15003 0.0 +15004 0.0 +15005 0.0 +15006 0.0 +15007 0.0 +15008 0.0 +15009 0.0 +15010 0.0 +15011 0.0 +15012 0.0 +15013 0.0 +15014 0.0 +15015 0.0 +15016 0.0 +15017 0.0 +15018 0.0 +15019 0.0 +15020 0.0 +15021 0.0 +15022 0.0 +15023 0.0 +15024 0.0 +15025 0.0 +15026 0.0 +15027 0.0 +15028 0.0 +15029 0.0 +15030 0.0 +15031 0.0 +15032 0.0 +15033 0.0 +15034 0.0 +15035 0.0 +15036 0.0 +15037 0.0 +15038 0.0 +15039 0.0 +15040 0.0 +15041 0.0 +15042 0.0 +15043 0.0 +15044 0.0 +15045 0.0 +15046 0.0 +15047 0.0 +15048 0.0 +15049 0.0 +15050 0.0 +15051 0.0 +15052 0.0 +15053 0.0 +15054 0.0 +15055 0.0 +15056 0.0 +15057 0.0 +15058 0.0 +15059 0.0 +15060 0.0 +15061 0.0 +15062 0.0 +15063 0.0 +15064 0.0 +15065 0.0 +15066 0.0 +15067 0.0 +15068 0.0 +15069 0.0 +15070 0.0 +15071 0.0 +15072 0.0 +15073 0.0 +15074 0.0 +15075 0.0 +15076 0.0 +15077 0.0 +15078 0.0 +15079 0.0 +15080 0.0 +15081 0.0 +15082 0.0 +15083 0.0 +15084 0.0 +15085 0.0 +15086 0.0 +15087 0.0 +15088 0.0 +15089 0.0 +15090 0.0 +15091 0.0 +15092 0.0 +15093 0.0 +15094 0.0 +15095 0.0 +15096 0.0 +15097 0.0 +15098 0.0 +15099 0.0 +15100 0.0 +15101 0.0 +15102 0.0 +15103 0.0 +15104 0.0 +15105 0.0 +15106 0.0 +15107 0.0 +15108 0.0 +15109 0.0 +15110 0.0 +15111 0.0 +15112 0.0 +15113 0.0 +15114 0.0 +15115 0.0 +15116 0.0 +15117 0.0 +15118 0.0 +15119 0.0 +15120 0.0 +15121 0.0 +15122 0.0 +15123 0.0 +15124 0.0 +15125 0.0 +15126 0.0 +15127 0.0 +15128 0.0 +15129 0.0 +15130 0.0 +15131 0.0 +15132 0.0 +15133 0.0 +15134 0.0 +15135 0.0 +15136 0.0 +15137 0.0 +15138 0.0 +15139 0.0 +15140 0.0 +15141 0.0 +15142 0.0 +15143 0.0 +15144 0.0 +15145 0.0 +15146 0.0 +15147 0.0 +15148 0.0 +15149 0.0 +15150 0.0 +15151 0.0 +15152 0.0 +15153 0.0 +15154 0.0 +15155 0.0 +15156 0.0 +15157 0.0 +15158 0.0 +15159 0.0 +15160 0.0 +15161 0.0 +15162 0.0 +15163 0.0 +15164 0.0 +15165 0.0 +15166 0.0 +15167 0.0 +15168 0.0 +15169 0.0 +15170 0.0 +15171 0.0 +15172 0.0 +15173 0.0 +15174 0.0 +15175 0.0 +15176 0.0 +15177 0.0 +15178 0.0 +15179 0.0 +15180 0.0 +15181 0.0 +15182 0.0 +15183 0.0 +15184 0.0 +15185 0.0 +15186 0.0 +15187 0.0 +15188 0.0 +15189 0.0 +15190 0.0 +15191 0.0 +15192 0.0 +15193 0.0 +15194 0.0 +15195 0.0 +15196 0.0 +15197 0.0 +15198 0.0 +15199 0.0 +15200 0.0 +15201 0.0 +15202 0.0 +15203 0.0 +15204 0.0 +15205 0.0 +15206 0.0 +15207 0.0 +15208 0.0 +15209 0.0 +15210 0.0 +15211 0.0 +15212 0.0 +15213 0.0 +15214 0.0 +15215 0.0 +15216 0.0 +15217 0.0 +15218 0.0 +15219 0.0 +15220 0.0 +15221 0.0 +15222 0.0 +15223 0.0 +15224 0.0 +15225 0.0 +15226 0.0 +15227 0.0 +15228 0.0 +15229 0.0 +15230 0.0 +15231 0.0 +15232 0.0 +15233 0.0 +15234 0.0 +15235 0.0 +15236 0.0 +15237 0.0 +15238 0.0 +15239 0.0 +15240 0.0 +15241 0.0 +15242 0.0 +15243 0.0 +15244 0.0 +15245 0.0 +15246 0.0 +15247 0.0 +15248 0.0 +15249 0.0 +15250 0.0 +15251 0.0 +15252 0.0 +15253 0.0 +15254 0.0 +15255 0.0 +15256 0.0 +15257 0.0 +15258 0.0 +15259 0.0 +15260 0.0 +15261 0.0 +15262 0.0 +15263 0.0 +15264 0.0 +15265 0.0 +15266 0.0 +15267 0.0 +15268 0.0 +15269 0.0 +15270 0.0 +15271 0.0 +15272 0.0 +15273 0.0 +15274 0.0 +15275 0.0 +15276 0.0 +15277 0.0 +15278 0.0 +15279 0.0 +15280 0.0 +15281 0.0 +15282 0.0 +15283 0.0 +15284 0.0 +15285 0.0 +15286 0.0 +15287 0.0 +15288 0.0 +15289 0.0 +15290 0.0 +15291 0.0 +15292 0.0 +15293 0.0 +15294 0.0 +15295 0.0 +15296 0.0 +15297 0.0 +15298 0.0 +15299 0.0 +15300 0.0 +15301 0.0 +15302 0.0 +15303 0.0 +15304 0.0 +15305 0.0 +15306 0.0 +15307 0.0 +15308 0.0 +15309 0.0 +15310 0.0 +15311 0.0 +15312 0.0 +15313 0.0 +15314 0.0 +15315 0.0 +15316 0.0 +15317 0.0 +15318 0.0 +15319 0.0 +15320 0.0 +15321 0.0 +15322 0.0 +15323 0.0 +15324 0.0 +15325 0.0 +15326 0.0 +15327 0.0 +15328 0.0 +15329 0.0 +15330 0.0 +15331 0.0 +15332 0.0 +15333 0.0 +15334 0.0 +15335 0.0 +15336 0.0 +15337 0.0 +15338 0.0 +15339 0.0 +15340 0.0 +15341 0.0 +15342 0.0 +15343 0.0 +15344 0.0 +15345 0.0 +15346 0.0 +15347 0.0 +15348 0.0 +15349 0.0 +15350 0.0 +15351 0.0 +15352 0.0 +15353 0.0 +15354 0.0 +15355 0.0 +15356 0.0 +15357 0.0 +15358 0.0 +15359 0.0 diff --git a/tests/circuitpython/audiofilter_filter_stereo_biquads.py b/tests/circuitpython/audiofilter_filter_stereo_biquads.py new file mode 100644 index 00000000000..526630f4bd7 --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_stereo_biquads.py @@ -0,0 +1,27 @@ +from audiofilters import Filter +from audiofilterhelper import synth_test, white8k +from audiomixer import Mixer +from synthio import Biquad, FilterMode, LFO + + +@synth_test +def stereo_filter(): + args = { + "bits_per_sample": 16, + "samples_signed": True, + "channel_count": 2, + } + effect = Filter( + filter=[ + Biquad(FilterMode.LOW_PASS, 400), + Biquad(FilterMode.HIGH_PASS, 300, Q=8), + ], + **args + ) + mixer = Mixer(**args) + mixer.voice[0].panning = LFO() + effect.play(mixer) + yield effect, [] + + mixer.play(white8k, loop=True) + yield 400 diff --git a/tests/circuitpython/audiofilter_filter_stereo_biquads.py.exp b/tests/circuitpython/audiofilter_filter_stereo_biquads.py.exp new file mode 100644 index 00000000000..7901d158079 --- /dev/null +++ b/tests/circuitpython/audiofilter_filter_stereo_biquads.py.exp @@ -0,0 +1,102400 @@ +0 0.0 +1 0.0 +2 0.0 +3 0.0 +4 0.0 +5 0.0 +6 0.0 +7 0.0 +8 0.0 +9 0.0 +10 0.0 +11 0.0 +12 0.0 +13 0.0 +14 0.0 +15 0.0 +16 0.0 +17 0.0 +18 0.0 +19 0.0 +20 0.0 +21 0.0 +22 0.0 +23 0.0 +24 0.0 +25 0.0 +26 0.0 +27 0.0 +28 0.0 +29 0.0 +30 0.0 +31 0.0 +32 0.0 +33 0.0 +34 0.0 +35 0.0 +36 0.0 +37 0.0 +38 0.0 +39 0.0 +40 0.0 +41 0.0 +42 0.0 +43 0.0 +44 0.0 +45 0.0 +46 0.0 +47 0.0 +48 0.0 +49 0.0 +50 0.0 +51 0.0 +52 0.0 +53 0.0 +54 0.0 +55 0.0 +56 0.0 +57 0.0 +58 0.0 +59 0.0 +60 0.0 +61 0.0 +62 0.0 +63 0.0 +64 0.0 +65 0.0 +66 0.0 +67 0.0 +68 0.0 +69 0.0 +70 0.0 +71 0.0 +72 0.0 +73 0.0 +74 0.0 +75 0.0 +76 0.0 +77 0.0 +78 0.0 +79 0.0 +80 0.0 +81 0.0 +82 0.0 +83 0.0 +84 0.0 +85 0.0 +86 0.0 +87 0.0 +88 0.0 +89 0.0 +90 0.0 +91 0.0 +92 0.0 +93 0.0 +94 0.0 +95 0.0 +96 0.0 +97 0.0 +98 0.0 +99 0.0 +100 0.0 +101 0.0 +102 0.0 +103 0.0 +104 0.0 +105 0.0 +106 0.0 +107 0.0 +108 0.0 +109 0.0 +110 0.0 +111 0.0 +112 0.0 +113 0.0 +114 0.0 +115 0.0 +116 0.0 +117 0.0 +118 0.0 +119 0.0 +120 0.0 +121 0.0 +122 0.0 +123 0.0 +124 0.0 +125 0.0 +126 0.0 +127 0.0 +128 0.0 +129 0.0 +130 0.0 +131 0.0 +132 0.0 +133 0.0 +134 0.0 +135 0.0 +136 0.0 +137 0.0 +138 0.0 +139 0.0 +140 0.0 +141 0.0 +142 0.0 +143 0.0 +144 0.0 +145 0.0 +146 0.0 +147 0.0 +148 0.0 +149 0.0 +150 0.0 +151 0.0 +152 0.0 +153 0.0 +154 0.0 +155 0.0 +156 0.0 +157 0.0 +158 0.0 +159 0.0 +160 0.0 +161 0.0 +162 0.0 +163 0.0 +164 0.0 +165 0.0 +166 0.0 +167 0.0 +168 0.0 +169 0.0 +170 0.0 +171 0.0 +172 0.0 +173 0.0 +174 0.0 +175 0.0 +176 0.0 +177 0.0 +178 0.0 +179 0.0 +180 0.0 +181 0.0 +182 0.0 +183 0.0 +184 0.0 +185 0.0 +186 0.0 +187 0.0 +188 0.0 +189 0.0 +190 0.0 +191 0.0 +192 0.0 +193 0.0 +194 0.0 +195 0.0 +196 0.0 +197 0.0 +198 0.0 +199 0.0 +200 0.0 +201 0.0 +202 0.0 +203 0.0 +204 0.0 +205 0.0 +206 0.0 +207 0.0 +208 0.0 +209 0.0 +210 0.0 +211 0.0 +212 0.0 +213 0.0 +214 0.0 +215 0.0 +216 0.0 +217 0.0 +218 0.0 +219 0.0 +220 0.0 +221 0.0 +222 0.0 +223 0.0 +224 0.0 +225 0.0 +226 0.0 +227 0.0 +228 0.0 +229 0.0 +230 0.0 +231 0.0 +232 0.0 +233 0.0 +234 0.0 +235 0.0 +236 0.0 +237 0.0 +238 0.0 +239 0.0 +240 0.0 +241 0.0 +242 0.0 +243 0.0 +244 0.0 +245 0.0 +246 0.0 +247 0.0 +248 0.0 +249 0.0 +250 0.0 +251 0.0 +252 0.0 +253 0.0 +254 0.0 +255 0.0 +256 0.002960205078125 +257 0.0030517578125 +258 0.020904541015625 +259 0.021575927734375 +260 0.049591064453125 +261 0.05120849609375 +262 0.052093505859375 +263 0.053802490234375 +264 9.1552734375e-05 +265 9.1552734375e-05 +266 -0.089752197265625 +267 -0.09271240234375 +268 -0.1788330078125 +269 -0.1846923828125 +270 -0.229644775390625 +271 -0.237152099609375 +272 -0.205322265625 +273 -0.21197509765625 +274 -0.1357421875 +275 -0.140045166015625 +276 -0.068145751953125 +277 -0.070159912109375 +278 0.0040283203125 +279 0.004425048828125 +280 0.085601806640625 +281 0.08868408203125 +282 0.19061279296875 +283 0.1971435546875 +284 0.28875732421875 +285 0.2984619140625 +286 0.32904052734375 +287 0.34002685546875 +288 0.328033447265625 +289 0.338958740234375 +290 0.301422119140625 +291 0.311431884765625 +292 0.248870849609375 +293 0.257110595703125 +294 0.164520263671875 +295 0.169921875 +296 0.047454833984375 +297 0.048919677734375 +298 -0.07232666015625 +299 -0.074859619140625 +300 -0.189605712890625 +301 -0.196044921875 +302 -0.30810546875 +303 -0.3184814453125 +304 -0.40386962890625 +305 -0.41741943359375 +306 -0.44793701171875 +307 -0.462921142578125 +308 -0.402435302734375 +309 -0.4158935546875 +310 -0.26312255859375 +311 -0.27197265625 +312 -0.093475341796875 +313 -0.0966796875 +314 0.030303955078125 +315 0.031219482421875 +316 0.106536865234375 +317 0.110015869140625 +318 0.16162109375 +319 0.166961669921875 +320 0.20147705078125 +321 0.20819091796875 +322 0.226287841796875 +323 0.23388671875 +324 0.201416015625 +325 0.208282470703125 +326 0.1470947265625 +327 0.152252197265625 +328 0.119049072265625 +329 0.123321533203125 +330 0.090087890625 +331 0.093414306640625 +332 0.018585205078125 +333 0.019500732421875 +334 -0.070709228515625 +335 -0.07281494140625 +336 -0.11651611328125 +337 -0.1202392578125 +338 -0.0858154296875 +339 -0.088623046875 +340 -0.024078369140625 +341 -0.024932861328125 +342 -0.006011962890625 +343 -0.00634765625 +344 -0.036468505859375 +345 -0.037872314453125 +346 -0.0826416015625 +347 -0.085601806640625 +348 -0.118194580078125 +349 -0.12237548828125 +350 -0.111480712890625 +351 -0.115478515625 +352 -0.051116943359375 +353 -0.05316162109375 +354 0.021331787109375 +355 0.02166748046875 +356 0.04974365234375 +357 0.051025390625 +358 0.0406494140625 +359 0.041656494140625 +360 0.05322265625 +361 0.0546875 +362 0.12335205078125 +363 0.127197265625 +364 0.210296630859375 +365 0.21710205078125 +366 0.254425048828125 +367 0.262786865234375 +368 0.27325439453125 +369 0.282318115234375 +370 0.30120849609375 +371 0.311279296875 +372 0.312896728515625 +373 0.32342529296875 +374 0.2645263671875 +375 0.273468017578125 +376 0.1497802734375 +377 0.1549072265625 +378 0.016937255859375 +379 0.017669677734375 +380 -0.08575439453125 +381 -0.088409423828125 +382 -0.154876708984375 +383 -0.15985107421875 +384 -0.191314697265625 +385 -0.197540283203125 +386 -0.22088623046875 +387 -0.2281494140625 +388 -0.287445068359375 +389 -0.296966552734375 +390 -0.38238525390625 +391 -0.39508056640625 +392 -0.488983154296875 +393 -0.505218505859375 +394 -0.577056884765625 +395 -0.59619140625 +396 -0.609649658203125 +397 -0.62982177734375 +398 -0.57977294921875 +399 -0.59893798828125 +400 -0.464447021484375 +401 -0.47979736328125 +402 -0.276885986328125 +403 -0.286041259765625 +404 -0.0714111328125 +405 -0.07379150390625 +406 0.12152099609375 +407 0.12548828125 +408 0.269439697265625 +409 0.278289794921875 +410 0.360321044921875 +411 0.3721923828125 +412 0.43292236328125 +413 0.44720458984375 +414 0.494903564453125 +415 0.511260986328125 +416 0.50244140625 +417 0.519073486328125 +418 0.444000244140625 +419 0.458740234375 +420 0.36920166015625 +421 0.38153076171875 +422 0.32666015625 +423 0.337646484375 +424 0.322052001953125 +425 0.332916259765625 +426 0.34649658203125 +427 0.358184814453125 +428 0.367218017578125 +429 0.379608154296875 +430 0.334686279296875 +431 0.34600830078125 +432 0.232086181640625 +433 0.239990234375 +434 0.082855224609375 +435 0.085784912109375 +436 -0.079559326171875 +437 -0.082061767578125 +438 -0.231689453125 +439 -0.239288330078125 +440 -0.358489990234375 +441 -0.370361328125 +442 -0.446044921875 +443 -0.460906982421875 +444 -0.4727783203125 +445 -0.48858642578125 +446 -0.45269775390625 +447 -0.467864990234375 +448 -0.43072509765625 +449 -0.4451904296875 +450 -0.40185546875 +451 -0.4154052734375 +452 -0.359283447265625 +453 -0.371429443359375 +454 -0.339935302734375 +455 -0.3514404296875 +456 -0.320892333984375 +457 -0.331756591796875 +458 -0.229156494140625 +459 -0.236968994140625 +460 -0.062042236328125 +461 -0.064300537109375 +462 0.1336669921875 +463 0.137908935546875 +464 0.320068359375 +465 0.33056640625 +466 0.473236083984375 +467 0.488922119140625 +468 0.56414794921875 +469 0.58294677734375 +470 0.56158447265625 +471 0.580413818359375 +472 0.481597900390625 +473 0.497894287109375 +474 0.36175537109375 +475 0.374176025390625 +476 0.243743896484375 +477 0.252288818359375 +478 0.151763916015625 +479 0.157257080078125 +480 0.0540771484375 +481 0.0562744140625 +482 -0.0638427734375 +483 -0.065643310546875 +484 -0.157470703125 +485 -0.1624755859375 +486 -0.222991943359375 +487 -0.230316162109375 +488 -0.279541015625 +489 -0.288909912109375 +490 -0.291900634765625 +491 -0.30181884765625 +492 -0.25115966796875 +493 -0.25982666015625 +494 -0.20123291015625 +495 -0.20831298828125 +496 -0.181121826171875 +497 -0.18756103515625 +498 -0.17724609375 +499 -0.18359375 +500 -0.142303466796875 +501 -0.147491455078125 +502 -0.074188232421875 +503 -0.077056884765625 +504 -0.01043701171875 +505 -0.011138916015625 +506 0.04486083984375 +507 0.04608154296875 +508 0.0850830078125 +509 0.087738037109375 +510 0.088409423828125 +511 0.091278076171875 +512 0.091705322265625 +513 0.09515380859375 +514 0.11151123046875 +515 0.11663818359375 +516 0.122528076171875 +517 0.1290283203125 +518 0.110137939453125 +519 0.116546630859375 +520 0.0689697265625 +521 0.07330322265625 +522 0.02484130859375 +523 0.026763916015625 +524 -0.02301025390625 +525 -0.02392578125 +526 -0.104278564453125 +527 -0.110504150390625 +528 -0.18359375 +529 -0.195220947265625 +530 -0.223724365234375 +531 -0.23822021484375 +532 -0.232635498046875 +533 -0.248016357421875 +534 -0.18865966796875 +535 -0.201385498046875 +536 -0.101318359375 +537 -0.108489990234375 +538 -0.002288818359375 +539 -0.00311279296875 +540 0.110382080078125 +541 0.11688232421875 +542 0.20416259765625 +543 0.21673583984375 +544 0.24432373046875 +545 0.259368896484375 +546 0.24310302734375 +547 0.257904052734375 +548 0.209259033203125 +549 0.221710205078125 +550 0.163360595703125 +551 0.1727294921875 +552 0.133575439453125 +553 0.141082763671875 +554 0.101165771484375 +555 0.106689453125 +556 0.06396484375 +557 0.0672607421875 +558 0.050018310546875 +559 0.052734375 +560 0.07598876953125 +561 0.08087158203125 +562 0.126983642578125 +563 0.1357421875 +564 0.160369873046875 +565 0.171783447265625 +566 0.154541015625 +567 0.1658935546875 +568 0.101318359375 +569 0.10931396484375 +570 0.005401611328125 +571 0.007080078125 +572 -0.1109619140625 +573 -0.1170654296875 +574 -0.2427978515625 +575 -0.2578125 +576 -0.380523681640625 +577 -0.404937744140625 +578 -0.49627685546875 +579 -0.5286865234375 +580 -0.548828125 +581 -0.58502197265625 +582 -0.498046875 +583 -0.531005859375 +584 -0.366180419921875 +585 -0.390411376953125 +586 -0.21160888671875 +587 -0.225616455078125 +588 -0.058380126953125 +589 -0.062255859375 +590 0.09466552734375 +591 0.100921630859375 +592 0.23687744140625 +593 0.252532958984375 +594 0.3428955078125 +595 0.365509033203125 +596 0.396331787109375 +597 0.422332763671875 +598 0.393890380859375 +599 0.41949462890625 +600 0.334259033203125 +601 0.355621337890625 +602 0.2401123046875 +603 0.254974365234375 +604 0.144622802734375 +605 0.152984619140625 +606 0.0594482421875 +607 0.062103271484375 +608 0.01043701171875 +609 0.00994873046875 +610 -0.004119873046875 +611 -0.00531005859375 +612 -0.013671875 +613 -0.015167236328125 +614 -0.00042724609375 +615 -0.000640869140625 +616 0.0472412109375 +617 0.050628662109375 +618 0.088409423828125 +619 0.094940185546875 +620 0.074005126953125 +621 0.079833984375 +622 0.019134521484375 +623 0.021453857421875 +624 -0.04058837890625 +625 -0.04217529296875 +626 -0.096221923828125 +627 -0.10150146484375 +628 -0.1370849609375 +629 -0.1451416015625 +630 -0.17352294921875 +631 -0.18408203125 +632 -0.21112060546875 +633 -0.224334716796875 +634 -0.250518798828125 +635 -0.2666015625 +636 -0.298919677734375 +637 -0.318572998046875 +638 -0.347076416015625 +639 -0.37030029296875 +640 -0.36907958984375 +641 -0.39410400390625 +642 -0.329833984375 +643 -0.35247802734375 +644 -0.22613525390625 +645 -0.241973876953125 +646 -0.074554443359375 +647 -0.08026123046875 +648 0.09942626953125 +649 0.105438232421875 +650 0.238983154296875 +651 0.25439453125 +652 0.31884765625 +653 0.339630126953125 +654 0.356597900390625 +655 0.379913330078125 +656 0.345703125 +657 0.368316650390625 +658 0.285797119140625 +659 0.304412841796875 +660 0.224578857421875 +661 0.239166259765625 +662 0.196319580078125 +663 0.20916748046875 +664 0.176422119140625 +665 0.188140869140625 +666 0.1492919921875 +667 0.159393310546875 +668 0.14080810546875 +669 0.150543212890625 +670 0.141937255859375 +671 0.151947021484375 +672 0.114501953125 +673 0.122833251953125 +674 0.08221435546875 +675 0.088531494140625 +676 0.06683349609375 +677 0.072296142578125 +678 0.034942626953125 +679 0.038360595703125 +680 -0.02557373046875 +681 -0.026214599609375 +682 -0.1142578125 +683 -0.1209716796875 +684 -0.230499267578125 +685 -0.245208740234375 +686 -0.34661865234375 +687 -0.369354248046875 +688 -0.4248046875 +689 -0.45306396484375 +690 -0.45147705078125 +691 -0.481781005859375 +692 -0.439483642578125 +693 -0.46917724609375 +694 -0.39300537109375 +695 -0.41973876953125 +696 -0.310028076171875 +697 -0.331298828125 +698 -0.207061767578125 +699 -0.221527099609375 +700 -0.106353759765625 +701 -0.1141357421875 +702 -0.014312744140625 +703 -0.015960693359375 +704 0.0859375 +705 0.09100341796875 +706 0.2137451171875 +707 0.22747802734375 +708 0.378204345703125 +709 0.403167724609375 +710 0.559051513671875 +711 0.596435546875 +712 0.69921875 +713 0.74627685546875 +714 0.759063720703125 +715 0.81036376953125 +716 0.736114501953125 +717 0.7860107421875 +718 0.6273193359375 +719 0.66998291015625 +720 0.431915283203125 +721 0.46142578125 +722 0.18505859375 +723 0.197906494140625 +724 -0.051727294921875 +725 -0.05487060546875 +726 -0.22491455078125 +727 -0.23974609375 +728 -0.3179931640625 +729 -0.339080810546875 +730 -0.355377197265625 +731 -0.37896728515625 +732 -0.366180419921875 +733 -0.3905029296875 +734 -0.3646240234375 +735 -0.388916015625 +736 -0.3668212890625 +737 -0.391326904296875 +738 -0.37689208984375 +739 -0.4022216796875 +740 -0.369598388671875 +741 -0.39459228515625 +742 -0.32696533203125 +743 -0.3492431640625 +744 -0.269439697265625 +745 -0.287933349609375 +746 -0.237701416015625 +747 -0.254180908203125 +748 -0.248779296875 +749 -0.26617431640625 +750 -0.25311279296875 +751 -0.270904541015625 +752 -0.197998046875 +753 -0.21209716796875 +754 -0.11328125 +755 -0.121612548828125 +756 -0.055572509765625 +757 -0.059967041015625 +758 -0.031158447265625 +759 -0.03387451171875 +760 -0.013275146484375 +761 -0.01470947265625 +762 0.028900146484375 +763 0.030426025390625 +764 0.125396728515625 +765 0.133636474609375 +766 0.249176025390625 +767 0.2659912109375 +768 0.360626220703125 +769 0.385772705078125 +770 0.4522705078125 +771 0.48480224609375 +772 0.495574951171875 +773 0.531097412109375 +774 0.478851318359375 +775 0.511962890625 +776 0.426971435546875 +777 0.454986572265625 +778 0.3798828125 +779 0.404327392578125 +780 0.354766845703125 +781 0.37890625 +782 0.32635498046875 +783 0.350616455078125 +784 0.281341552734375 +785 0.3045654296875 +786 0.22198486328125 +787 0.243011474609375 +788 0.1407470703125 +789 0.157379150390625 +790 0.0196533203125 +791 0.027496337890625 +792 -0.143341064453125 +793 -0.149139404296875 +794 -0.3201904296875 +795 -0.3416748046875 +796 -0.50091552734375 +797 -0.53924560546875 +798 -0.670166015625 +799 -0.725006103515625 +800 -0.77288818359375 +801 -0.838104248046875 +802 -0.767303466796875 +803 -0.832366943359375 +804 -0.6715087890625 +805 -0.727691650390625 +806 -0.535308837890625 +807 -0.579132080078125 +808 -0.40289306640625 +809 -0.435394287109375 +810 -0.294403076171875 +811 -0.318634033203125 +812 -0.179595947265625 +813 -0.195159912109375 +814 -0.034271240234375 +815 -0.038055419921875 +816 0.10321044921875 +817 0.1104736328125 +818 0.194732666015625 +819 0.208465576171875 +820 0.252716064453125 +821 0.26983642578125 +822 0.321044921875 +823 0.34326171875 +824 0.416107177734375 +825 0.446990966796875 +826 0.507049560546875 +827 0.546905517578125 +828 0.57098388671875 +829 0.61773681640625 +830 0.600738525390625 +831 0.6514892578125 +832 0.608062744140625 +833 0.661102294921875 +834 0.59857177734375 +835 0.652679443359375 +836 0.550811767578125 +837 0.602386474609375 +838 0.4521484375 +839 0.496124267578125 +840 0.314910888671875 +841 0.347320556640625 +842 0.152801513671875 +843 0.170989990234375 +844 -0.04058837890625 +845 -0.0401611328125 +846 -0.2442626953125 +847 -0.263031005859375 +848 -0.41192626953125 +849 -0.446502685546875 +850 -0.532440185546875 +851 -0.578399658203125 +852 -0.60150146484375 +853 -0.65399169921875 +854 -0.591156005859375 +855 -0.642364501953125 +856 -0.517791748046875 +857 -0.561676025390625 +858 -0.421661376953125 +859 -0.456390380859375 +860 -0.322113037109375 +861 -0.347869873046875 +862 -0.23809814453125 +863 -0.256988525390625 +864 -0.173553466796875 +865 -0.18792724609375 +866 -0.1256103515625 +867 -0.137359619140625 +868 -0.087310791015625 +869 -0.09747314453125 +870 -0.0498046875 +871 -0.058319091796875 +872 -0.002166748046875 +873 -0.007720947265625 +874 0.066497802734375 +875 0.06646728515625 +876 0.1446533203125 +877 0.151611328125 +878 0.228668212890625 +879 0.243743896484375 +880 0.32513427734375 +881 0.35015869140625 +882 0.42181396484375 +883 0.457366943359375 +884 0.49853515625 +885 0.542999267578125 +886 0.52288818359375 +887 0.57110595703125 +888 0.460906982421875 +889 0.504058837890625 +890 0.318328857421875 +891 0.34808349609375 +892 0.13116455078125 +893 0.142974853515625 +894 -0.053192138671875 +895 -0.0589599609375 +896 -0.20050048828125 +897 -0.219940185546875 +898 -0.309173583984375 +899 -0.33837890625 +900 -0.3717041015625 +901 -0.406005859375 +902 -0.406890869140625 +903 -0.4437255859375 +904 -0.456268310546875 +905 -0.497528076171875 +906 -0.514129638671875 +907 -0.561126708984375 +908 -0.550018310546875 +909 -0.600860595703125 +910 -0.533935546875 +911 -0.58355712890625 +912 -0.4376220703125 +913 -0.4779052734375 +914 -0.255218505859375 +915 -0.27734375 +916 -0.009002685546875 +917 -0.00640869140625 +918 0.243743896484375 +919 0.271636962890625 +920 0.4388427734375 +921 0.48583984375 +922 0.549591064453125 +923 0.60675048828125 +924 0.593017578125 +925 0.6533203125 +926 0.606170654296875 +927 0.666595458984375 +928 0.586334228515625 +929 0.64361572265625 +930 0.524200439453125 +931 0.5740966796875 +932 0.456756591796875 +933 0.499053955078125 +934 0.403167724609375 +935 0.439697265625 +936 0.34454345703125 +937 0.375091552734375 +938 0.25213623046875 +939 0.2734375 +940 0.10101318359375 +941 0.107147216796875 +942 -0.088592529296875 +943 -0.101470947265625 +944 -0.287841796875 +945 -0.320648193359375 +946 -0.497772216796875 +947 -0.551544189453125 +948 -0.7022705078125 +949 -0.77642822265625 +950 -0.853424072265625 +951 -0.864105224609375 +952 -0.861785888671875 +953 -0.870391845703125 +954 -0.861785888671875 +955 -0.868682861328125 +956 -0.855743408203125 +957 -0.86053466796875 +958 -0.739044189453125 +959 -0.759246826171875 +960 -0.530792236328125 +961 -0.52203369140625 +962 -0.247528076171875 +963 -0.20556640625 +964 0.07177734375 +965 0.146942138671875 +966 0.380706787109375 +967 0.48431396484375 +968 0.64703369140625 +969 0.771270751953125 +970 0.846282958984375 +971 0.868316650390625 +972 0.8680419921875 +973 0.870361328125 +974 0.870361328125 +975 0.86395263671875 +976 0.86505126953125 +977 0.8172607421875 +978 0.854766845703125 +979 0.657073974609375 +980 0.723175048828125 +981 0.470733642578125 +982 0.567535400390625 +983 0.279388427734375 +984 0.39276123046875 +985 0.086395263671875 +986 0.170318603515625 +987 -0.140350341796875 +988 -0.106231689453125 +989 -0.40960693359375 +990 -0.39886474609375 +991 -0.6817626953125 +992 -0.654388427734375 +993 -0.859619140625 +994 -0.83514404296875 +995 -0.870391845703125 +996 -0.8634033203125 +997 -0.870391845703125 +998 -0.8685302734375 +999 -0.86444091796875 +1000 -0.870391845703125 +1001 -0.85723876953125 +1002 -0.86846923828125 +1003 -0.790008544921875 +1004 -0.857635498046875 +1005 -0.62847900390625 +1006 -0.701019287109375 +1007 -0.3956298828125 +1008 -0.466644287109375 +1009 -0.126708984375 +1010 -0.205657958984375 +1011 0.150115966796875 +1012 0.07098388671875 +1013 0.424041748046875 +1014 0.339111328125 +1015 0.670623779296875 +1016 0.56427001953125 +1017 0.854522705078125 +1018 0.731414794921875 +1019 0.866485595703125 +1020 0.827880859375 +1021 0.86920166015625 +1022 0.8563232421875 +1023 0.8653564453125 +1024 0.85687255859375 +1025 0.857147216796875 +1026 0.841522216796875 +1027 0.766845703125 +1028 0.772613525390625 +1029 0.628509521484375 +1030 0.66552734375 +1031 0.462127685546875 +1032 0.544281005859375 +1033 0.297210693359375 +1034 0.421051025390625 +1035 0.14862060546875 +1036 0.2769775390625 +1037 -0.00537109375 +1038 0.119354248046875 +1039 -0.15753173828125 +1040 -0.05450439453125 +1041 -0.31304931640625 +1042 -0.2568359375 +1043 -0.48876953125 +1044 -0.44708251953125 +1045 -0.6416015625 +1046 -0.604278564453125 +1047 -0.751373291015625 +1048 -0.749481201171875 +1049 -0.84619140625 +1050 -0.8563232421875 +1051 -0.861297607421875 +1052 -0.863983154296875 +1053 -0.863250732421875 +1054 -0.863189697265625 +1055 -0.856597900390625 +1056 -0.855255126953125 +1057 -0.7498779296875 +1058 -0.775177001953125 +1059 -0.624542236328125 +1060 -0.657257080078125 +1061 -0.47808837890625 +1062 -0.45770263671875 +1063 -0.253387451171875 +1064 -0.217071533203125 +1065 0.003692626953125 +1066 0.004547119140625 +1067 0.2257080078125 +1068 0.217926025390625 +1069 0.427154541015625 +1070 0.451385498046875 +1071 0.643218994140625 +1072 0.6968994140625 +1073 0.855926513671875 +1074 0.859954833984375 +1075 0.870361328125 +1076 0.870361328125 +1077 0.870361328125 +1078 0.870361328125 +1079 0.862762451171875 +1080 0.8629150390625 +1081 0.79669189453125 +1082 0.790863037109375 +1083 0.595794677734375 +1084 0.6055908203125 +1085 0.362152099609375 +1086 0.402740478515625 +1087 0.1270751953125 +1088 0.2022705078125 +1089 -0.086944580078125 +1090 0.006622314453125 +1091 -0.2784423828125 +1092 -0.214813232421875 +1093 -0.484832763671875 +1094 -0.4798583984375 +1095 -0.729583740234375 +1096 -0.7462158203125 +1097 -0.86688232421875 +1098 -0.86614990234375 +1099 -0.870391845703125 +1100 -0.870391845703125 +1101 -0.86859130859375 +1102 -0.870147705078125 +1103 -0.86279296875 +1104 -0.863006591796875 +1105 -0.817962646484375 +1106 -0.77215576171875 +1107 -0.6116943359375 +1108 -0.5177001953125 +1109 -0.3128662109375 +1110 -0.203094482421875 +1111 0.039398193359375 +1112 0.15142822265625 +1113 0.422821044921875 +1114 0.5162353515625 +1115 0.805145263671875 +1116 0.83343505859375 +1117 0.870361328125 +1118 0.870361328125 +1119 0.870361328125 +1120 0.870361328125 +1121 0.860015869140625 +1122 0.860992431640625 +1123 0.727935791015625 +1124 0.75042724609375 +1125 0.48114013671875 +1126 0.542449951171875 +1127 0.2059326171875 +1128 0.320953369140625 +1129 -0.06103515625 +1130 0.1038818359375 +1131 -0.29913330078125 +1132 -0.114471435546875 +1133 -0.516204833984375 +1134 -0.343231201171875 +1135 -0.7252197265625 +1136 -0.55914306640625 +1137 -0.85980224609375 +1138 -0.733428955078125 +1139 -0.870391845703125 +1140 -0.844024658203125 +1141 -0.870391845703125 +1142 -0.8544921875 +1143 -0.858062744140625 +1144 -0.769134521484375 +1145 -0.673004150390625 +1146 -0.64306640625 +1147 -0.42694091796875 +1148 -0.52520751953125 +1149 -0.2100830078125 +1150 -0.424163818359375 +1151 -0.0362548828125 +1152 -0.324798583984375 +1153 0.10943603515625 +1154 -0.219085693359375 +1155 0.23516845703125 +1156 -0.078948974609375 +1157 0.373687744140625 +1158 0.087554931640625 +1159 0.517791748046875 +1160 0.221160888671875 +1161 0.602783203125 +1162 0.32427978515625 +1163 0.635711669921875 +1164 0.42608642578125 +1165 0.655181884765625 +1166 0.5201416015625 +1167 0.65948486328125 +1168 0.603668212890625 +1169 0.651275634765625 +1170 0.661163330078125 +1171 0.61846923828125 +1172 0.667572021484375 +1173 0.53753662109375 +1174 0.615203857421875 +1175 0.404144287109375 +1176 0.5040283203125 +1177 0.22186279296875 +1178 0.343505859375 +1179 0.003997802734375 +1180 0.157379150390625 +1181 -0.22100830078125 +1182 -0.02935791015625 +1183 -0.42449951171875 +1184 -0.192413330078125 +1185 -0.579833984375 +1186 -0.2904052734375 +1187 -0.641876220703125 +1188 -0.326690673828125 +1189 -0.6177978515625 +1190 -0.357025146484375 +1191 -0.575531005859375 +1192 -0.387298583984375 +1193 -0.526336669921875 +1194 -0.37518310546875 +1195 -0.42645263671875 +1196 -0.30108642578125 +1197 -0.2581787109375 +1198 -0.202239990234375 +1199 -0.068695068359375 +1200 -0.11859130859375 +1201 0.09222412109375 +1202 -0.040740966796875 +1203 0.232147216796875 +1204 0.033233642578125 +1205 0.3509521484375 +1206 0.07086181640625 +1207 0.410064697265625 +1208 0.040618896484375 +1209 0.372955322265625 +1210 -0.044189453125 +1211 0.2554931640625 +1212 -0.14190673828125 +1213 0.10711669921875 +1214 -0.23785400390625 +1215 -0.052886962890625 +1216 -0.3013916015625 +1217 -0.186279296875 +1218 -0.283233642578125 +1219 -0.23291015625 +1220 -0.20123291015625 +1221 -0.209442138671875 +1222 -0.10968017578125 +1223 -0.174163818359375 +1224 -0.011566162109375 +1225 -0.126739501953125 +1226 0.106658935546875 +1227 -0.048126220703125 +1228 0.225921630859375 +1229 0.0426025390625 +1230 0.311187744140625 +1231 0.10748291015625 +1232 0.35638427734375 +1233 0.1409912109375 +1234 0.4080810546875 +1235 0.19708251953125 +1236 0.464691162109375 +1237 0.273651123046875 +1238 0.48089599609375 +1239 0.31768798828125 +1240 0.4686279296875 +1241 0.341094970703125 +1242 0.4510498046875 +1243 0.368011474609375 +1244 0.407989501953125 +1245 0.37249755859375 +1246 0.29522705078125 +1247 0.30072021484375 +1248 0.11474609375 +1249 0.1517333984375 +1250 -0.07855224609375 +1251 -0.01470947265625 +1252 -0.27313232421875 +1253 -0.1883544921875 +1254 -0.469879150390625 +1255 -0.372711181640625 +1256 -0.620147705078125 +1257 -0.51397705078125 +1258 -0.687469482421875 +1259 -0.57177734375 +1260 -0.66546630859375 +1261 -0.53948974609375 +1262 -0.569793701171875 +1263 -0.43511962890625 +1264 -0.433807373046875 +1265 -0.2962646484375 +1266 -0.2918701171875 +1267 -0.161102294921875 +1268 -0.15771484375 +1269 -0.0435791015625 +1270 -0.029754638671875 +1271 0.060394287109375 +1272 0.07745361328125 +1273 0.13665771484375 +1274 0.148468017578125 +1275 0.170135498046875 +1276 0.185089111328125 +1277 0.16552734375 +1278 0.21514892578125 +1279 0.15728759765625 +1280 0.241607666015625 +1281 0.150787353515625 +1282 0.241943359375 +1283 0.12200927734375 +1284 0.222625732421875 +1285 0.080108642578125 +1286 0.205413818359375 +1287 0.05126953125 +1288 0.213592529296875 +1289 0.062896728515625 +1290 0.2286376953125 +1291 0.09271240234375 +1292 0.2108154296875 +1293 0.092987060546875 +1294 0.1739501953125 +1295 0.07855224609375 +1296 0.132232666015625 +1297 0.06427001953125 +1298 0.0743408203125 +1299 0.0347900390625 +1300 0.000518798828125 +1301 -0.01171875 +1302 -0.070953369140625 +1303 -0.056060791015625 +1304 -0.10198974609375 +1305 -0.055511474609375 +1306 -0.09124755859375 +1307 -0.010467529296875 +1308 -0.083221435546875 +1309 0.02508544921875 +1310 -0.0985107421875 +1311 0.025665283203125 +1312 -0.11431884765625 +1313 0.017333984375 +1314 -0.128875732421875 +1315 0.00189208984375 +1316 -0.151702880859375 +1317 -0.03173828125 +1318 -0.17315673828125 +1319 -0.071502685546875 +1320 -0.209381103515625 +1321 -0.13543701171875 +1322 -0.25848388671875 +1323 -0.219970703125 +1324 -0.30096435546875 +1325 -0.300506591796875 +1326 -0.337677001953125 +1327 -0.376312255859375 +1328 -0.343597412109375 +1329 -0.416107177734375 +1330 -0.278778076171875 +1331 -0.371124267578125 +1332 -0.145416259765625 +1333 -0.242279052734375 +1334 0.021087646484375 +1335 -0.069732666015625 +1336 0.201995849609375 +1337 0.125640869140625 +1338 0.370208740234375 +1339 0.31268310546875 +1340 0.494476318359375 +1341 0.45501708984375 +1342 0.57659912109375 +1343 0.554779052734375 +1344 0.615753173828125 +1345 0.61065673828125 +1346 0.602630615234375 +1347 0.610931396484375 +1348 0.517578125 +1349 0.531463623046875 +1350 0.37530517578125 +1351 0.3883056640625 +1352 0.22222900390625 +1353 0.23468017578125 +1354 0.08062744140625 +1355 0.095245361328125 +1356 -0.026092529296875 +1357 -0.00396728515625 +1358 -0.08447265625 +1359 -0.04852294921875 +1360 -0.107635498046875 +1361 -0.055145263671875 +1362 -0.138916015625 +1363 -0.0758056640625 +1364 -0.20166015625 +1365 -0.138702392578125 +1366 -0.266021728515625 +1367 -0.209197998046875 +1368 -0.3333740234375 +1369 -0.289031982421875 +1370 -0.404449462890625 +1371 -0.37884521484375 +1372 -0.460662841796875 +1373 -0.456329345703125 +1374 -0.4984130859375 +1375 -0.51641845703125 +1376 -0.484649658203125 +1377 -0.519287109375 +1378 -0.4146728515625 +1379 -0.458251953125 +1380 -0.33331298828125 +1381 -0.384796142578125 +1382 -0.26263427734375 +1383 -0.323699951171875 +1384 -0.198822021484375 +1385 -0.269287109375 +1386 -0.12042236328125 +1387 -0.1951904296875 +1388 -0.027008056640625 +1389 -0.100006103515625 +1390 0.0579833984375 +1391 -0.01055908203125 +1392 0.159881591796875 +1393 0.1033935546875 +1394 0.28466796875 +1395 0.24908447265625 +1396 0.387115478515625 +1397 0.373199462890625 +1398 0.452484130859375 +1399 0.45806884765625 +1400 0.48785400390625 +1401 0.511474609375 +1402 0.52105712890625 +1403 0.565399169921875 +1404 0.545684814453125 +1405 0.61138916015625 +1406 0.511810302734375 +1407 0.5897216796875 +1408 0.411956787109375 +1409 0.4906005859375 +1410 0.2618408203125 +1411 0.33148193359375 +1412 0.09234619140625 +1413 0.147796630859375 +1414 -0.06036376953125 +1415 -0.01873779296875 +1416 -0.172088623046875 +1417 -0.140289306640625 +1418 -0.221282958984375 +1419 -0.191986083984375 +1420 -0.2166748046875 +1421 -0.184295654296875 +1422 -0.196197509765625 +1423 -0.161834716796875 +1424 -0.1956787109375 +1425 -0.166595458984375 +1426 -0.21148681640625 +1427 -0.19390869140625 +1428 -0.227691650390625 +1429 -0.22442626953125 +1430 -0.26324462890625 +1431 -0.279754638671875 +1432 -0.301055908203125 +1433 -0.3389892578125 +1434 -0.30126953125 +1435 -0.3543701171875 +1436 -0.28350830078125 +1437 -0.348175048828125 +1438 -0.253173828125 +1439 -0.32598876953125 +1440 -0.185699462890625 +1441 -0.2581787109375 +1442 -0.077362060546875 +1443 -0.139801025390625 +1444 0.05914306640625 +1445 0.014617919921875 +1446 0.171966552734375 +1447 0.144378662109375 +1448 0.236907958984375 +1449 0.221038818359375 +1450 0.276214599609375 +1451 0.27069091796875 +1452 0.290740966796875 +1453 0.294036865234375 +1454 0.298431396484375 +1455 0.311767578125 +1456 0.31268310546875 +1457 0.339141845703125 +1458 0.320404052734375 +1459 0.360260009765625 +1460 0.309783935546875 +1461 0.360504150390625 +1462 0.2550048828125 +1463 0.308380126953125 +1464 0.1380615234375 +1465 0.18170166015625 +1466 -0.019989013671875 +1467 0.0047607421875 +1468 -0.1793212890625 +1469 -0.17559814453125 +1470 -0.301727294921875 +1471 -0.3143310546875 +1472 -0.350311279296875 +1473 -0.36785888671875 +1474 -0.3470458984375 +1475 -0.36248779296875 +1476 -0.329986572265625 +1477 -0.343536376953125 +1478 -0.2916259765625 +1479 -0.3018798828125 +1480 -0.227081298828125 +1481 -0.231414794921875 +1482 -0.12451171875 +1483 -0.117645263671875 +1484 -0.011505126953125 +1485 0.007049560546875 +1486 0.06549072265625 +1487 0.087982177734375 +1488 0.117950439453125 +1489 0.13946533203125 +1490 0.156097412109375 +1491 0.17425537109375 +1492 0.175933837890625 +1493 0.188201904296875 +1494 0.1685791015625 +1495 0.171234130859375 +1496 0.12957763671875 +1497 0.118438720703125 +1498 0.081573486328125 +1499 0.05706787109375 +1500 0.026214599609375 +1501 -0.010711669921875 +1502 -0.041961669921875 +1503 -0.0914306640625 +1504 -0.103759765625 +1505 -0.162322998046875 +1506 -0.134796142578125 +1507 -0.194549560546875 +1508 -0.102203369140625 +1509 -0.1492919921875 +1510 -0.00152587890625 +1511 -0.02166748046875 +1512 0.1136474609375 +1513 0.124053955078125 +1514 0.17926025390625 +1515 0.211151123046875 +1516 0.196441650390625 +1517 0.240447998046875 +1518 0.191009521484375 +1519 0.242218017578125 +1520 0.171112060546875 +1521 0.2257080078125 +1522 0.139923095703125 +1523 0.194366455078125 +1524 0.070220947265625 +1525 0.115509033203125 +1526 -0.017913818359375 +1527 0.0128173828125 +1528 -0.074127197265625 +1529 -0.053802490234375 +1530 -0.12054443359375 +1531 -0.110626220703125 +1532 -0.192413330078125 +1533 -0.199493408203125 +1534 -0.26806640625 +1535 -0.29437255859375 +1536 -0.295135498046875 +1537 -0.33221435546875 +1538 -0.246734619140625 +1539 -0.27972412109375 +1540 -0.162811279296875 +1541 -0.185333251953125 +1542 -0.108062744140625 +1543 -0.128204345703125 +1544 -0.089111328125 +1545 -0.115692138671875 +1546 -0.081298828125 +1547 -0.116455078125 +1548 -0.06536865234375 +1549 -0.105926513671875 +1550 -0.017364501953125 +1551 -0.053955078125 +1552 0.06988525390625 +1553 0.048797607421875 +1554 0.159881591796875 +1555 0.157318115234375 +1556 0.204376220703125 +1557 0.212005615234375 +1558 0.207977294921875 +1559 0.218475341796875 +1560 0.219757080078125 +1561 0.23724365234375 +1562 0.2698974609375 +1563 0.30535888671875 +1564 0.32513427734375 +1565 0.38128662109375 +1566 0.3369140625 +1567 0.404449462890625 +1568 0.32147216796875 +1569 0.3944091796875 +1570 0.3094482421875 +1571 0.3885498046875 +1572 0.281707763671875 +1573 0.362640380859375 +1574 0.203765869140625 +1575 0.27362060546875 +1576 0.072418212890625 +1577 0.11712646484375 +1578 -0.070098876953125 +1579 -0.054901123046875 +1580 -0.181915283203125 +1581 -0.19085693359375 +1582 -0.258941650390625 +1583 -0.28570556640625 +1584 -0.30108642578125 +1585 -0.339263916015625 +1586 -0.329437255859375 +1587 -0.3775634765625 +1588 -0.380645751953125 +1589 -0.445709228515625 +1590 -0.447998046875 +1591 -0.535064697265625 +1592 -0.51837158203125 +1593 -0.629058837890625 +1594 -0.567779541015625 +1595 -0.697601318359375 +1596 -0.56683349609375 +1597 -0.70391845703125 +1598 -0.51141357421875 +1599 -0.6424560546875 +1600 -0.384063720703125 +1601 -0.491241455078125 +1602 -0.197479248046875 +1603 -0.265716552734375 +1604 0.0013427734375 +1605 -0.023712158203125 +1606 0.185577392578125 +1607 0.201751708984375 +1608 0.326995849609375 +1609 0.375823974609375 +1610 0.414764404296875 +1611 0.485076904296875 +1612 0.480712890625 +1613 0.56884765625 +1614 0.5311279296875 +1615 0.634765625 +1616 0.529693603515625 +1617 0.63763427734375 +1618 0.4674072265625 +1619 0.5660400390625 +1620 0.3865966796875 +1621 0.4720458984375 +1622 0.328948974609375 +1623 0.40692138671875 +1624 0.300537109375 +1625 0.3778076171875 +1626 0.29534912109375 +1627 0.376953125 +1628 0.287445068359375 +1629 0.371978759765625 +1630 0.236846923828125 +1631 0.313140869140625 +1632 0.1307373046875 +1633 0.184417724609375 +1634 -0.010223388671875 +1635 0.011199951171875 +1636 -0.157379150390625 +1637 -0.171051025390625 +1638 -0.290618896484375 +1639 -0.33740234375 +1640 -0.397216796875 +1641 -0.47198486328125 +1642 -0.465728759765625 +1643 -0.560394287109375 +1644 -0.478485107421875 +1645 -0.58056640625 +1646 -0.447845458984375 +1647 -0.54754638671875 +1648 -0.412200927734375 +1649 -0.508575439453125 +1650 -0.368438720703125 +1651 -0.459503173828125 +1652 -0.311981201171875 +1653 -0.394378662109375 +1654 -0.27484130859375 +1655 -0.35260009765625 +1656 -0.239044189453125 +1657 -0.31170654296875 +1658 -0.14471435546875 +1659 -0.197418212890625 +1660 0.00946044921875 +1661 -0.007965087890625 +1662 0.1837158203125 +1663 0.207489013671875 +1664 0.345977783203125 +1665 0.409210205078125 +1666 0.47601318359375 +1667 0.57208251953125 +1668 0.549560546875 +1669 0.66595458984375 +1670 0.540863037109375 +1671 0.65875244140625 +1672 0.463836669921875 +1673 0.56744384765625 +1674 0.3504638671875 +1675 0.431396484375 +1676 0.236358642578125 +1677 0.29443359375 +1678 0.14263916015625 +1679 0.182464599609375 +1680 0.04376220703125 +1681 0.06365966796875 +1682 -0.0714111328125 +1683 -0.075958251953125 +1684 -0.16485595703125 +1685 -0.189422607421875 +1686 -0.23260498046875 +1687 -0.271942138671875 +1688 -0.28997802734375 +1689 -0.342529296875 +1690 -0.307098388671875 +1691 -0.364166259765625 +1692 -0.276214599609375 +1693 -0.327239990234375 +1694 -0.233917236328125 +1695 -0.2769775390625 +1696 -0.212921142578125 +1697 -0.253692626953125 +1698 -0.20220947265625 +1699 -0.24365234375 +1700 -0.162811279296875 +1701 -0.1983642578125 +1702 -0.093597412109375 +1703 -0.116241455078125 +1704 -0.026641845703125 +1705 -0.036834716796875 +1706 0.033843994140625 +1707 0.034881591796875 +1708 0.08154296875 +1709 0.09124755859375 +1710 0.09747314453125 +1711 0.10888671875 +1712 0.112030029296875 +1713 0.125518798828125 +1714 0.1385498046875 +1715 0.15771484375 +1716 0.155029296875 +1717 0.17828369140625 +1718 0.148468017578125 +1719 0.17108154296875 +1720 0.113983154296875 +1721 0.129974365234375 +1722 0.073822021484375 +1723 0.082427978515625 +1724 0.02752685546875 +1725 0.027679443359375 +1726 -0.050140380859375 +1727 -0.065643310546875 +1728 -0.128173828125 +1729 -0.15936279296875 +1730 -0.173828125 +1731 -0.21307373046875 +1732 -0.193359375 +1733 -0.234649658203125 +1734 -0.1673583984375 +1735 -0.2001953125 +1736 -0.103363037109375 +1737 -0.119171142578125 +1738 -0.02813720703125 +1739 -0.024749755859375 +1740 0.060577392578125 +1741 0.085784912109375 +1742 0.135101318359375 +1743 0.178131103515625 +1744 0.165771484375 +1745 0.215576171875 +1746 0.163299560546875 +1747 0.211456298828125 +1748 0.13525390625 +1749 0.17523193359375 +1750 0.099212646484375 +1751 0.128753662109375 +1752 0.079254150390625 +1753 0.1019287109375 +1754 0.058807373046875 +1755 0.0743408203125 +1756 0.035552978515625 +1757 0.04327392578125 +1758 0.033203125 +1759 0.038177490234375 +1760 0.065582275390625 +1761 0.076263427734375 +1762 0.119293212890625 +1763 0.14105224609375 +1764 0.157012939453125 +1765 0.186431884765625 +1766 0.15960693359375 +1767 0.188812255859375 +1768 0.11962890625 +1769 0.1390380859375 +1770 0.040863037109375 +1771 0.041778564453125 +1772 -0.0576171875 +1773 -0.079437255859375 +1774 -0.17156982421875 +1775 -0.219390869140625 +1776 -0.29266357421875 +1777 -0.367828369140625 +1778 -0.396697998046875 +1779 -0.494873046875 +1780 -0.447784423828125 +1781 -0.556243896484375 +1782 -0.410919189453125 +1783 -0.508697509765625 +1784 -0.304901123046875 +1785 -0.3756103515625 +1786 -0.179656982421875 +1787 -0.218902587890625 +1788 -0.05548095703125 +1789 -0.063751220703125 +1790 0.06903076171875 +1791 0.091552734375 +1792 0.18499755859375 +1793 0.23602294921875 +1794 0.27093505859375 +1795 0.342987060546875 +1796 0.313232421875 +1797 0.39520263671875 +1798 0.309539794921875 +1799 0.389373779296875 +1800 0.259063720703125 +1801 0.324249267578125 +1802 0.180816650390625 +1803 0.224090576171875 +1804 0.1024169921875 +1805 0.124267578125 +1806 0.033538818359375 +1807 0.037078857421875 +1808 -0.004425048828125 +1809 -0.010101318359375 +1810 -0.013092041015625 +1811 -0.019439697265625 +1812 -0.017059326171875 +1813 -0.022796630859375 +1814 -0.0018310546875 +1815 -0.001556396484375 +1816 0.0419921875 +1817 0.056304931640625 +1818 0.080230712890625 +1819 0.106719970703125 +1820 0.07196044921875 +1821 0.096893310546875 +1822 0.029510498046875 +1823 0.042694091796875 +1824 -0.017791748046875 +1825 -0.018035888671875 +1826 -0.062591552734375 +1827 -0.07586669921875 +1828 -0.096099853515625 +1829 -0.11944580078125 +1830 -0.12689208984375 +1831 -0.15972900390625 +1832 -0.1595458984375 +1833 -0.202606201171875 +1834 -0.194488525390625 +1835 -0.24859619140625 +1836 -0.237548828125 +1837 -0.30517578125 +1838 -0.280853271484375 +1839 -0.36212158203125 +1840 -0.302734375 +1841 -0.39141845703125 +1842 -0.273895263671875 +1843 -0.35528564453125 +1844 -0.191497802734375 +1845 -0.249969482421875 +1846 -0.069091796875 +1847 -0.092864990234375 +1848 0.0723876953125 +1849 0.08905029296875 +1850 0.185943603515625 +1851 0.2352294921875 +1852 0.250732421875 +1853 0.318817138671875 +1854 0.2813720703125 +1855 0.358642578125 +1856 0.272491455078125 +1857 0.347747802734375 +1858 0.2237548828125 +1859 0.28564453125 +1860 0.174652099609375 +1861 0.223175048828125 +1862 0.1534423828125 +1863 0.196746826171875 +1864 0.139617919921875 +1865 0.179840087890625 +1866 0.120086669921875 +1867 0.155548095703125 +1868 0.116119384765625 +1869 0.151214599609375 +1870 0.12005615234375 +1871 0.156951904296875 +1872 0.10009765625 +1873 0.13177490234375 +1874 0.075775146484375 +1875 0.100799560546875 +1876 0.06500244140625 +1877 0.087127685546875 +1878 0.03997802734375 +1879 0.05487060546875 +1880 -0.009429931640625 +1881 -0.009002685546875 +1882 -0.08282470703125 +1883 -0.10400390625 +1884 -0.1796875 +1885 -0.229400634765625 +1886 -0.27703857421875 +1887 -0.35552978515625 +1888 -0.343505859375 +1889 -0.441925048828125 +1890 -0.367706298828125 +1891 -0.473846435546875 +1892 -0.360137939453125 +1893 -0.464813232421875 +1894 -0.324127197265625 +1895 -0.419097900390625 +1896 -0.25787353515625 +1897 -0.334320068359375 +1898 -0.1749267578125 +1899 -0.227935791015625 +1900 -0.093597412109375 +1901 -0.12347412109375 +1902 -0.019073486328125 +1903 -0.02764892578125 +1904 0.06268310546875 +1905 0.077667236328125 +1906 0.167816162109375 +1907 0.2132568359375 +1908 0.303863525390625 +1909 0.38885498046875 +1910 0.45404052734375 +1911 0.582794189453125 +1912 0.57098388671875 +1913 0.734039306640625 +1914 0.621795654296875 +1915 0.800140380859375 +1916 0.604339599609375 +1917 0.7783203125 +1918 0.5159912109375 +1919 0.6651611328125 +1920 0.35601806640625 +1921 0.45965576171875 +1922 0.1534423828125 +1923 0.199188232421875 +1924 -0.040802001953125 +1925 -0.050689697265625 +1926 -0.1824951171875 +1927 -0.23297119140625 +1928 -0.258056640625 +1929 -0.33013916015625 +1930 -0.287811279296875 +1931 -0.368408203125 +1932 -0.295928955078125 +1933 -0.378936767578125 +1934 -0.294281005859375 +1935 -0.376983642578125 +1936 -0.296173095703125 +1937 -0.37969970703125 +1938 -0.305023193359375 +1939 -0.391510009765625 +1940 -0.29986572265625 +1941 -0.385345458984375 +1942 -0.2657470703125 +1943 -0.3419189453125 +1944 -0.219512939453125 +1945 -0.28289794921875 +1946 -0.194793701171875 +1947 -0.251617431640625 +1948 -0.205657958984375 +1949 -0.266143798828125 +1950 -0.210906982421875 +1951 -0.273345947265625 +1952 -0.166748046875 +1953 -0.216796875 +1954 -0.09783935546875 +1955 -0.128265380859375 +1956 -0.051055908203125 +1957 -0.068145751953125 +1958 -0.031585693359375 +1959 -0.0430908203125 +1960 -0.017181396484375 +1961 -0.024444580078125 +1962 0.0177001953125 +1963 0.020721435546875 +1964 0.097991943359375 +1965 0.124481201171875 +1966 0.201202392578125 +1967 0.25787353515625 +1968 0.294921875 +1969 0.379119873046875 +1970 0.37274169921875 +1971 0.47991943359375 +1972 0.4097900390625 +1973 0.5281982421875 +1974 0.396148681640625 +1975 0.511138916015625 +1976 0.3531494140625 +1977 0.456207275390625 +1978 0.31500244140625 +1979 0.407470703125 +1980 0.296356201171875 +1981 0.383758544921875 +1982 0.27532958984375 +1983 0.35687255859375 +1984 0.240325927734375 +1985 0.31182861328125 +1986 0.19305419921875 +1987 0.250885009765625 +1988 0.1268310546875 +1989 0.1654052734375 +1990 0.026031494140625 +1991 0.035247802734375 +1992 -0.111297607421875 +1993 -0.142059326171875 +1994 -0.261199951171875 +1995 -0.33563232421875 +1996 -0.415191650390625 +1997 -0.5345458984375 +1998 -0.56011962890625 +1999 -0.72186279296875 +2000 -0.648773193359375 +2001 -0.836669921875 +2002 -0.645233154296875 +2003 -0.8326416015625 +2004 -0.56494140625 +2005 -0.7296142578125 +2006 -0.4505615234375 +2007 -0.582550048828125 +2008 -0.339813232421875 +2009 -0.440093994140625 +2010 -0.249847412109375 +2011 -0.324310302734375 +2012 -0.154510498046875 +2013 -0.20147705078125 +2014 -0.032867431640625 +2015 -0.044647216796875 +2016 0.08233642578125 +2017 0.103973388671875 +2018 0.15850830078125 +2019 0.202392578125 +2020 0.2064208984375 +2021 0.264495849609375 +2022 0.263824462890625 +2023 0.338897705078125 +2024 0.3448486328125 +2025 0.443817138671875 +2026 0.42303466796875 +2027 0.545074462890625 +2028 0.478668212890625 +2029 0.6173095703125 +2030 0.50555419921875 +2031 0.6524658203125 +2032 0.513702392578125 +2033 0.66339111328125 +2034 0.5078125 +2035 0.6561279296875 +2036 0.469329833984375 +2037 0.606781005859375 +2038 0.38726806640625 +2039 0.501190185546875 +2040 0.272064208984375 +2041 0.352783203125 +2042 0.135345458984375 +2043 0.176544189453125 +2044 -0.028533935546875 +2045 -0.034820556640625 +2046 -0.201629638671875 +2047 -0.258209228515625 +2048 -0.344451904296875 +2049 -0.44244384765625 +2050 -0.4473876953125 +2051 -0.5753173828125 +2052 -0.50689697265625 +2053 -0.65203857421875 +2054 -0.5 +2055 -0.641632080078125 +2056 -0.440277099609375 +2057 -0.562164306640625 +2058 -0.36090087890625 +2059 -0.458038330078125 +2060 -0.277923583984375 +2061 -0.350555419921875 +2062 -0.20709228515625 +2063 -0.260528564453125 +2064 -0.15179443359375 +2065 -0.192108154296875 +2066 -0.109771728515625 +2067 -0.141937255859375 +2068 -0.075469970703125 +2069 -0.1021728515625 +2070 -0.041748046875 +2071 -0.062896728515625 +2072 0.00018310546875 +2073 -0.011932373046875 +2074 0.059173583984375 +2075 0.062835693359375 +2076 0.125640869140625 +2077 0.148712158203125 +2078 0.19647216796875 +2079 0.241729736328125 +2080 0.277008056640625 +2081 0.34912109375 +2082 0.357177734375 +2083 0.457305908203125 +2084 0.42034912109375 +2085 0.54388427734375 +2086 0.439849853515625 +2087 0.5728759765625 +2088 0.387786865234375 +2089 0.506591796875 +2090 0.268951416015625 +2091 0.351226806640625 +2092 0.11309814453125 +2093 0.146514892578125 +2094 -0.040679931640625 +2095 -0.05523681640625 +2096 -0.1640625 +2097 -0.21624755859375 +2098 -0.255645751953125 +2099 -0.334930419921875 +2100 -0.30908203125 +2101 -0.402984619140625 +2102 -0.33978271484375 +2103 -0.4412841796875 +2104 -0.3818359375 +2105 -0.49578857421875 +2106 -0.43048095703125 +2107 -0.5601806640625 +2108 -0.460601806640625 +2109 -0.600738525390625 +2110 -0.447509765625 +2111 -0.584228515625 +2112 -0.367950439453125 +2113 -0.47930908203125 +2114 -0.21710205078125 +2115 -0.27935791015625 +2116 -0.01336669921875 +2117 -0.0089111328125 +2118 0.196044921875 +2119 0.268798828125 +2120 0.35821533203125 +2121 0.482818603515625 +2122 0.451080322265625 +2123 0.60369873046875 +2124 0.488555908203125 +2125 0.650421142578125 +2126 0.50103759765625 +2127 0.66400146484375 +2128 0.486175537109375 +2129 0.6414794921875 +2130 0.436248779296875 +2131 0.572540283203125 +2132 0.38165283203125 +2133 0.498138427734375 +2134 0.338104248046875 +2135 0.439453125 +2136 0.2900390625 +2137 0.375518798828125 +2138 0.21380615234375 +2139 0.274505615234375 +2140 0.08892822265625 +2141 0.1087646484375 +2142 -0.067901611328125 +2143 -0.099395751953125 +2144 -0.232940673828125 +2145 -0.3182373046875 +2146 -0.406982421875 +2147 -0.5489501953125 +2148 -0.57666015625 +2149 -0.7738037109375 +2150 -0.702423095703125 +2151 -0.86383056640625 +2152 -0.759429931640625 +2153 -0.870391845703125 +2154 -0.760772705078125 +2155 -0.86895751953125 +2156 -0.716156005859375 +2157 -0.861053466796875 +2158 -0.612640380859375 +2159 -0.765869140625 +2160 -0.441802978515625 +2161 -0.5301513671875 +2162 -0.208953857421875 +2163 -0.214691162109375 +2164 0.0538330078125 +2165 0.137359619140625 +2166 0.308349609375 +2167 0.474822998046875 +2168 0.528106689453125 +2169 0.76239013671875 +2170 0.692901611328125 +2171 0.867462158203125 +2172 0.802978515625 +2173 0.870361328125 +2174 0.849609375 +2175 0.86480712890625 +2176 0.836669921875 +2177 0.831817626953125 +2178 0.78216552734375 +2179 0.677581787109375 +2180 0.690338134765625 +2181 0.495880126953125 +2182 0.574920654296875 +2183 0.30767822265625 +2184 0.4375 +2185 0.116180419921875 +2186 0.254425048828125 +2187 -0.110748291015625 +2188 0.02056884765625 +2189 -0.381805419921875 +2190 -0.232208251953125 +2191 -0.6572265625 +2192 -0.459320068359375 +2193 -0.857421875 +2194 -0.62872314453125 +2195 -0.870391845703125 +2196 -0.73504638671875 +2197 -0.870391845703125 +2198 -0.7982177734375 +2199 -0.86444091796875 +2200 -0.84466552734375 +2201 -0.85723876953125 +2202 -0.855194091796875 +2203 -0.790008544921875 +2204 -0.80572509765625 +2205 -0.62847900390625 +2206 -0.677398681640625 +2207 -0.3956298828125 +2208 -0.50006103515625 +2209 -0.126708984375 +2210 -0.294036865234375 +2211 0.150115966796875 +2212 -0.068023681640625 +2213 0.424041748046875 +2214 0.15789794921875 +2215 0.670623779296875 +2216 0.354888916015625 +2217 0.854522705078125 +2218 0.509765625 +2219 0.866485595703125 +2220 0.610992431640625 +2221 0.86920166015625 +2222 0.6719970703125 +2223 0.8653564453125 +2224 0.702667236328125 +2225 0.857147216796875 +2226 0.700714111328125 +2227 0.766845703125 +2228 0.669891357421875 +2229 0.628509521484375 +2230 0.605072021484375 +2231 0.462127685546875 +2232 0.525390625 +2233 0.297210693359375 +2234 0.44000244140625 +2235 0.14862060546875 +2236 0.3319091796875 +2237 -0.00537109375 +2238 0.2066650390625 +2239 -0.15753173828125 +2240 0.06158447265625 +2241 -0.31304931640625 +2242 -0.11370849609375 +2243 -0.48876953125 +2244 -0.2843017578125 +2245 -0.6416015625 +2246 -0.431732177734375 +2247 -0.751373291015625 +2248 -0.573089599609375 +2249 -0.84619140625 +2250 -0.69732666015625 +2251 -0.861297607421875 +2252 -0.779693603515625 +2253 -0.863250732421875 +2254 -0.796600341796875 +2255 -0.856597900390625 +2256 -0.75701904296875 +2257 -0.7498779296875 +2258 -0.703948974609375 +2259 -0.624542236328125 +2260 -0.620941162109375 +2261 -0.47808837890625 +2262 -0.464508056640625 +2263 -0.253387451171875 +2264 -0.268585205078125 +2265 0.003692626953125 +2266 -0.08404541015625 +2267 0.2257080078125 +2268 0.098358154296875 +2269 0.427154541015625 +2270 0.30267333984375 +2271 0.643218994140625 +2272 0.5216064453125 +2273 0.855926513671875 +2274 0.71197509765625 +2275 0.870361328125 +2276 0.836761474609375 +2277 0.870361328125 +2278 0.859588623046875 +2279 0.862762451171875 +2280 0.859771728515625 +2281 0.79669189453125 +2282 0.835174560546875 +2283 0.595794677734375 +2284 0.719207763671875 +2285 0.362152099609375 +2286 0.57598876953125 +2287 0.1270751953125 +2288 0.4212646484375 +2289 -0.086944580078125 +2290 0.256622314453125 +2291 -0.2784423828125 +2292 0.056243896484375 +2293 -0.484832763671875 +2294 -0.19403076171875 +2295 -0.729583740234375 +2296 -0.45648193359375 +2297 -0.86688232421875 +2298 -0.68389892578125 +2299 -0.870391845703125 +2300 -0.856475830078125 +2301 -0.86859130859375 +2302 -0.870391845703125 +2303 -0.86279296875 +2304 -0.870391845703125 +2305 -0.817962646484375 +2306 -0.860198974609375 +2307 -0.6116943359375 +2308 -0.718719482421875 +2309 -0.3128662109375 +2310 -0.463897705078125 +2311 0.039398193359375 +2312 -0.159515380859375 +2313 0.422821044921875 +2314 0.1685791015625 +2315 0.805145263671875 +2316 0.470794677734375 +2317 0.870361328125 +2318 0.706451416015625 +2319 0.870361328125 +2320 0.85595703125 +2321 0.860015869140625 +2322 0.8651123046875 +2323 0.727935791015625 +2324 0.8656005859375 +2325 0.48114013671875 +2326 0.859619140625 +2327 0.2059326171875 +2328 0.8074951171875 +2329 -0.06103515625 +2330 0.684539794921875 +2331 -0.29913330078125 +2332 0.526153564453125 +2333 -0.516204833984375 +2334 0.324798583984375 +2335 -0.7252197265625 +2336 0.101287841796875 +2337 -0.85980224609375 +2338 -0.1173095703125 +2339 -0.870391845703125 +2340 -0.3079833984375 +2341 -0.870391845703125 +2342 -0.434814453125 +2343 -0.858062744140625 +2344 -0.494354248046875 +2345 -0.673004150390625 +2346 -0.52423095703125 +2347 -0.42694091796875 +2348 -0.5570068359375 +2349 -0.2100830078125 +2350 -0.592803955078125 +2351 -0.0362548828125 +2352 -0.613128662109375 +2353 0.10943603515625 +2354 -0.60638427734375 +2355 0.23516845703125 +2356 -0.54595947265625 +2357 0.373687744140625 +2358 -0.4361572265625 +2359 0.517791748046875 +2360 -0.324737548828125 +2361 0.602783203125 +2362 -0.210723876953125 +2363 0.635711669921875 +2364 -0.072723388671875 +2365 0.655181884765625 +2366 0.080322265625 +2367 0.65948486328125 +2368 0.241363525390625 +2369 0.651275634765625 +2370 0.3922119140625 +2371 0.61846923828125 +2372 0.50640869140625 +2373 0.53753662109375 +2374 0.571563720703125 +2375 0.404144287109375 +2376 0.581817626953125 +2377 0.22186279296875 +2378 0.53961181640625 +2379 0.003997802734375 +2380 0.459808349609375 +2381 -0.22100830078125 +2382 0.359344482421875 +2383 -0.42449951171875 +2384 0.255828857421875 +2385 -0.579833984375 +2386 0.18206787109375 +2387 -0.641876220703125 +2388 0.1356201171875 +2389 -0.6177978515625 +2390 0.07257080078125 +2391 -0.575531005859375 +2392 -0.0091552734375 +2393 -0.526336669921875 +2394 -0.071380615234375 +2395 -0.42645263671875 +2396 -0.093719482421875 +2397 -0.2581787109375 +2398 -0.101776123046875 +2399 -0.068695068359375 +2400 -0.123138427734375 +2401 0.09222412109375 +2402 -0.145233154296875 +2403 0.232147216796875 +2404 -0.161895751953125 +2405 0.3509521484375 +2406 -0.1956787109375 +2407 0.410064697265625 +2408 -0.2691650390625 +2409 0.372955322265625 +2410 -0.36932373046875 +2411 0.2554931640625 +2412 -0.4609375 +2413 0.10711669921875 +2414 -0.531951904296875 +2415 -0.052886962890625 +2416 -0.55828857421875 +2417 -0.186279296875 +2418 -0.501617431640625 +2419 -0.23291015625 +2420 -0.379302978515625 +2421 -0.209442138671875 +2422 -0.239044189453125 +2423 -0.174163818359375 +2424 -0.087188720703125 +2425 -0.126739501953125 +2426 0.083282470703125 +2427 -0.048126220703125 +2428 0.252685546875 +2429 0.0426025390625 +2430 0.3885498046875 +2431 0.10748291015625 +2432 0.48248291015625 +2433 0.1409912109375 +2434 0.56964111328125 +2435 0.19708251953125 +2436 0.646636962890625 +2437 0.273651123046875 +2438 0.675201416015625 +2439 0.31768798828125 +2440 0.6646728515625 +2441 0.341094970703125 +2442 0.634429931640625 +2443 0.368011474609375 +2444 0.569305419921875 +2445 0.37249755859375 +2446 0.435272216796875 +2447 0.30072021484375 +2448 0.236572265625 +2449 0.1517333984375 +2450 0.02105712890625 +2451 -0.01470947265625 +2452 -0.198486328125 +2453 -0.1883544921875 +2454 -0.41937255859375 +2455 -0.372711181640625 +2456 -0.598602294921875 +2457 -0.51397705078125 +2458 -0.703460693359375 +2459 -0.57177734375 +2460 -0.726165771484375 +2461 -0.53948974609375 +2462 -0.677581787109375 +2463 -0.43511962890625 +2464 -0.583648681640625 +2465 -0.2962646484375 +2466 -0.471893310546875 +2467 -0.161102294921875 +2468 -0.353668212890625 +2469 -0.0435791015625 +2470 -0.228515625 +2471 0.060394287109375 +2472 -0.1097412109375 +2473 0.13665771484375 +2474 -0.011962890625 +2475 0.170135498046875 +2476 0.0638427734375 +2477 0.16552734375 +2478 0.137725830078125 +2479 0.15728759765625 +2480 0.209136962890625 +2481 0.150787353515625 +2482 0.2569580078125 +2483 0.12200927734375 +2484 0.284210205078125 +2485 0.080108642578125 +2486 0.3067626953125 +2487 0.05126953125 +2488 0.3421630859375 +2489 0.062896728515625 +2490 0.37353515625 +2491 0.09271240234375 +2492 0.3668212890625 +2493 0.092987060546875 +2494 0.333465576171875 +2495 0.07855224609375 +2496 0.2857666015625 +2497 0.06427001953125 +2498 0.215240478515625 +2499 0.0347900390625 +2500 0.12359619140625 +2501 -0.01171875 +2502 0.0279541015625 +2503 -0.056060791015625 +2504 -0.037567138671875 +2505 -0.055511474609375 +2506 -0.069580078125 +2507 -0.010467529296875 +2508 -0.10308837890625 +2509 0.02508544921875 +2510 -0.153167724609375 +2511 0.025665283203125 +2512 -0.198760986328125 +2513 0.017333984375 +2514 -0.23675537109375 +2515 0.00189208984375 +2516 -0.27392578125 +2517 -0.03173828125 +2518 -0.3013916015625 +2519 -0.071502685546875 +2520 -0.332427978515625 +2521 -0.13543701171875 +2522 -0.36566162109375 +2523 -0.219970703125 +2524 -0.38543701171875 +2525 -0.300506591796875 +2526 -0.393585205078125 +2527 -0.376312255859375 +2528 -0.370513916015625 +2529 -0.416107177734375 +2530 -0.284515380859375 +2531 -0.371124267578125 +2532 -0.13922119140625 +2533 -0.242279052734375 +2534 0.033843994140625 +2535 -0.069732666015625 +2536 0.2171630859375 +2537 0.125640869140625 +2538 0.38629150390625 +2539 0.31268310546875 +2540 0.513641357421875 +2541 0.45501708984375 +2542 0.599578857421875 +2543 0.554779052734375 +2544 0.6427001953125 +2545 0.61065673828125 +2546 0.634796142578125 +2547 0.610931396484375 +2548 0.559478759765625 +2549 0.531463623046875 +2550 0.42950439453125 +2551 0.3883056640625 +2552 0.2845458984375 +2553 0.23468017578125 +2554 0.144317626953125 +2555 0.095245361328125 +2556 0.02972412109375 +2557 -0.00396728515625 +2558 -0.046478271484375 +2559 -0.04852294921875 +2560 -0.09393310546875 +2561 -0.055145263671875 +2562 -0.14727783203125 +2563 -0.0758056640625 +2564 -0.22430419921875 +2565 -0.138702392578125 +2566 -0.299041748046875 +2567 -0.209197998046875 +2568 -0.37139892578125 +2569 -0.289031982421875 +2570 -0.441131591796875 +2571 -0.37884521484375 +2572 -0.492462158203125 +2573 -0.456329345703125 +2574 -0.52227783203125 +2575 -0.51641845703125 +2576 -0.50360107421875 +2577 -0.519287109375 +2578 -0.43310546875 +2579 -0.458251953125 +2580 -0.348541259765625 +2581 -0.384796142578125 +2582 -0.269195556640625 +2583 -0.323699951171875 +2584 -0.19317626953125 +2585 -0.269287109375 +2586 -0.104156494140625 +2587 -0.1951904296875 +2588 -0.003173828125 +2589 -0.100006103515625 +2590 0.08917236328125 +2591 -0.01055908203125 +2592 0.192535400390625 +2593 0.1033935546875 +2594 0.310882568359375 +2595 0.24908447265625 +2596 0.406219482421875 +2597 0.373199462890625 +2598 0.4659423828125 +2599 0.45806884765625 +2600 0.495697021484375 +2601 0.511474609375 +2602 0.518524169921875 +2603 0.565399169921875 +2604 0.529541015625 +2605 0.61138916015625 +2606 0.48828125 +2607 0.5897216796875 +2608 0.389404296875 +2609 0.4906005859375 +2610 0.24688720703125 +2611 0.33148193359375 +2612 0.087249755859375 +2613 0.147796630859375 +2614 -0.05859375 +2615 -0.01873779296875 +2616 -0.16961669921875 +2617 -0.140289306640625 +2618 -0.227081298828125 +2619 -0.191986083984375 +2620 -0.2373046875 +2621 -0.184295654296875 +2622 -0.2308349609375 +2623 -0.161834716796875 +2624 -0.236724853515625 +2625 -0.166595458984375 +2626 -0.25177001953125 +2627 -0.19390869140625 +2628 -0.262847900390625 +2629 -0.22442626953125 +2630 -0.285797119140625 +2631 -0.279754638671875 +2632 -0.307037353515625 +2633 -0.3389892578125 +2634 -0.29437255859375 +2635 -0.3543701171875 +2636 -0.264739990234375 +2637 -0.348175048828125 +2638 -0.223480224609375 +2639 -0.32598876953125 +2640 -0.151275634765625 +2641 -0.2581787109375 +2642 -0.04595947265625 +2643 -0.139801025390625 +2644 0.081146240234375 +2645 0.014617919921875 +2646 0.186553955078125 +2647 0.144378662109375 +2648 0.249725341796875 +2649 0.221038818359375 +2650 0.288543701171875 +2651 0.27069091796875 +2652 0.303436279296875 +2653 0.294036865234375 +2654 0.30914306640625 +2655 0.311767578125 +2656 0.316802978515625 +2657 0.339141845703125 +2658 0.315765380859375 +2659 0.360260009765625 +2660 0.296875 +2661 0.360504150390625 +2662 0.239898681640625 +2663 0.308380126953125 +2664 0.131072998046875 +2665 0.18170166015625 +2666 -0.011688232421875 +2667 0.0047607421875 +2668 -0.155303955078125 +2669 -0.17559814453125 +2670 -0.268035888671875 +2671 -0.3143310546875 +2672 -0.319305419921875 +2673 -0.36785888671875 +2674 -0.326263427734375 +2675 -0.36248779296875 +2676 -0.319305419921875 +2677 -0.343536376953125 +2678 -0.29205322265625 +2679 -0.3018798828125 +2680 -0.24041748046875 +2681 -0.231414794921875 +2682 -0.154876708984375 +2683 -0.117645263671875 +2684 -0.058013916015625 +2685 0.007049560546875 +2686 0.012176513671875 +2687 0.087982177734375 +2688 0.06451416015625 +2689 0.13946533203125 +2690 0.106658935546875 +2691 0.17425537109375 +2692 0.134735107421875 +2693 0.188201904296875 +2694 0.140869140625 +2695 0.171234130859375 +2696 0.120819091796875 +2697 0.118438720703125 +2698 0.09228515625 +2699 0.05706787109375 +2700 0.056060791015625 +2701 -0.010711669921875 +2702 0.00726318359375 +2703 -0.0914306640625 +2704 -0.038787841796875 +2705 -0.162322998046875 +2706 -0.0625 +2707 -0.194549560546875 +2708 -0.03729248046875 +2709 -0.1492919921875 +2710 0.04058837890625 +2711 -0.02166748046875 +2712 0.128021240234375 +2713 0.124053955078125 +2714 0.173553466796875 +2715 0.211151123046875 +2716 0.17852783203125 +2717 0.240447998046875 +2718 0.16436767578125 +2719 0.242218017578125 +2720 0.13824462890625 +2721 0.2257080078125 +2722 0.103302001953125 +2723 0.194366455078125 +2724 0.03802490234375 +2725 0.115509033203125 +2726 -0.0408935546875 +2727 0.0128173828125 +2728 -0.09228515625 +2729 -0.053802490234375 +2730 -0.1337890625 +2731 -0.110626220703125 +2732 -0.19378662109375 +2733 -0.199493408203125 +2734 -0.254730224609375 +2735 -0.29437255859375 +2736 -0.27398681640625 +2737 -0.33221435546875 +2738 -0.229400634765625 +2739 -0.27972412109375 +2740 -0.154449462890625 +2741 -0.185333251953125 +2742 -0.10357666015625 +2743 -0.128204345703125 +2744 -0.08245849609375 +2745 -0.115692138671875 +2746 -0.07049560546875 +2747 -0.116455078125 +2748 -0.051666259765625 +2749 -0.105926513671875 +2750 -0.006072998046875 +2751 -0.053955078125 +2752 0.07208251953125 +2753 0.048797607421875 +2754 0.15179443359375 +2755 0.157318115234375 +2756 0.192291259765625 +2757 0.212005615234375 +2758 0.197265625 +2759 0.218475341796875 +2760 0.207916259765625 +2761 0.23724365234375 +2762 0.2496337890625 +2763 0.30535888671875 +2764 0.29449462890625 +2765 0.38128662109375 +2766 0.301727294921875 +2767 0.404449462890625 +2768 0.28515625 +2769 0.3944091796875 +2770 0.270782470703125 +2771 0.3885498046875 +2772 0.24273681640625 +2773 0.362640380859375 +2774 0.172271728515625 +2775 0.27362060546875 +2776 0.056976318359375 +2777 0.11712646484375 +2778 -0.0673828125 +2779 -0.054901123046875 +2780 -0.16534423828125 +2781 -0.19085693359375 +2782 -0.233245849609375 +2783 -0.28570556640625 +2784 -0.270843505859375 +2785 -0.339263916015625 +2786 -0.29583740234375 +2787 -0.3775634765625 +2788 -0.339019775390625 +2789 -0.445709228515625 +2790 -0.394775390625 +2791 -0.535064697265625 +2792 -0.452117919921875 +2793 -0.629058837890625 +2794 -0.490997314453125 +2795 -0.697601318359375 +2796 -0.48687744140625 +2797 -0.70391845703125 +2798 -0.43646240234375 +2799 -0.6424560546875 +2800 -0.32525634765625 +2801 -0.491241455078125 +2802 -0.164215087890625 +2803 -0.265716552734375 +2804 0.00689697265625 +2805 -0.023712158203125 +2806 0.165313720703125 +2807 0.201751708984375 +2808 0.287078857421875 +2809 0.375823974609375 +2810 0.362945556640625 +2811 0.485076904296875 +2812 0.419647216796875 +2813 0.56884765625 +2814 0.462432861328125 +2815 0.634765625 +2816 0.461212158203125 +2817 0.63763427734375 +2818 0.409210205078125 +2819 0.5660400390625 +2820 0.341064453125 +2821 0.4720458984375 +2822 0.290252685546875 +2823 0.40692138671875 +2824 0.26177978515625 +2825 0.3778076171875 +2826 0.251068115234375 +2827 0.376953125 +2828 0.237640380859375 +2829 0.371978759765625 +2830 0.18975830078125 +2831 0.313140869140625 +2832 0.0975341796875 +2833 0.184417724609375 +2834 -0.022125244140625 +2835 0.011199951171875 +2836 -0.1458740234375 +2837 -0.171051025390625 +2838 -0.257293701171875 +2839 -0.33740234375 +2840 -0.345977783203125 +2841 -0.47198486328125 +2842 -0.402557373046875 +2843 -0.560394287109375 +2844 -0.412841796875 +2845 -0.58056640625 +2846 -0.38677978515625 +2847 -0.54754638671875 +2848 -0.35528564453125 +2849 -0.508575439453125 +2850 -0.3160400390625 +2851 -0.459503173828125 +2852 -0.265625 +2853 -0.394378662109375 +2854 -0.230010986328125 +2855 -0.35260009765625 +2856 -0.195098876953125 +2857 -0.31170654296875 +2858 -0.113250732421875 +2859 -0.197418212890625 +2860 0.016265869140625 +2861 -0.007965087890625 +2862 0.1612548828125 +2863 0.207489013671875 +2864 0.29571533203125 +2865 0.409210205078125 +2866 0.403228759765625 +2867 0.57208251953125 +2868 0.4642333984375 +2869 0.66595458984375 +2870 0.45794677734375 +2871 0.65875244140625 +2872 0.3955078125 +2873 0.56744384765625 +2874 0.302642822265625 +2875 0.431396484375 +2876 0.208038330078125 +2877 0.29443359375 +2878 0.128875732421875 +2879 0.182464599609375 +2880 0.044891357421875 +2881 0.06365966796875 +2882 -0.05255126953125 +2883 -0.075958251953125 +2884 -0.132659912109375 +2885 -0.189422607421875 +2886 -0.19195556640625 +2887 -0.271942138671875 +2888 -0.242462158203125 +2889 -0.342529296875 +2890 -0.260009765625 +2891 -0.364166259765625 +2892 -0.238189697265625 +2893 -0.327239990234375 +2894 -0.20623779296875 +2895 -0.2769775390625 +2896 -0.1903076171875 +2897 -0.253692626953125 +2898 -0.181549072265625 +2899 -0.24365234375 +2900 -0.14874267578125 +2901 -0.1983642578125 +2902 -0.091064453125 +2903 -0.116241455078125 +2904 -0.034393310546875 +2905 -0.036834716796875 +2906 0.0177001953125 +2907 0.034881591796875 +2908 0.0599365234375 +2909 0.09124755859375 +2910 0.076904296875 +2911 0.10888671875 +2912 0.092681884765625 +2913 0.125518798828125 +2914 0.117767333984375 +2915 0.15771484375 +2916 0.13433837890625 +2917 0.17828369140625 +2918 0.13177490234375 +2919 0.17108154296875 +2920 0.106048583984375 +2921 0.129974365234375 +2922 0.074920654296875 +2923 0.082427978515625 +2924 0.037994384765625 +2925 0.027679443359375 +2926 -0.024932861328125 +2927 -0.065643310546875 +2928 -0.0889892578125 +2929 -0.15936279296875 +2930 -0.127777099609375 +2931 -0.21307373046875 +2932 -0.14617919921875 +2933 -0.234649658203125 +2934 -0.12847900390625 +2935 -0.2001953125 +2936 -0.08050537109375 +2937 -0.119171142578125 +2938 -0.0235595703125 +2939 -0.024749755859375 +2940 0.04437255859375 +2941 0.085784912109375 +2942 0.101226806640625 +2943 0.178131103515625 +2944 0.123382568359375 +2945 0.215576171875 +2946 0.119537353515625 +2947 0.211456298828125 +2948 0.09588623046875 +2949 0.17523193359375 +2950 0.066558837890625 +2951 0.128753662109375 +2952 0.05084228515625 +2953 0.1019287109375 +2954 0.035430908203125 +2955 0.0743408203125 +2956 0.01837158203125 +2957 0.04327392578125 +2958 0.01861572265625 +2959 0.038177490234375 +2960 0.047088623046875 +2961 0.076263427734375 +2962 0.0928955078125 +2963 0.14105224609375 +2964 0.12591552734375 +2965 0.186431884765625 +2966 0.13067626953125 +2967 0.188812255859375 +2968 0.101104736328125 +2969 0.1390380859375 +2970 0.040069580078125 +2971 0.041778564453125 +2972 -0.0372314453125 +2973 -0.079437255859375 +2974 -0.12750244140625 +2975 -0.219390869140625 +2976 -0.224029541015625 +2977 -0.367828369140625 +2978 -0.30743408203125 +2979 -0.494873046875 +2980 -0.348968505859375 +2981 -0.556243896484375 +2982 -0.32049560546875 +2983 -0.508697509765625 +2984 -0.23699951171875 +2985 -0.3756103515625 +2986 -0.13848876953125 +2987 -0.218902587890625 +2988 -0.04107666015625 +2989 -0.063751220703125 +2990 0.056488037109375 +2991 0.091552734375 +2992 0.14727783203125 +2993 0.23602294921875 +2994 0.214141845703125 +2995 0.342987060546875 +2996 0.246063232421875 +2997 0.39520263671875 +2998 0.240997314453125 +2999 0.389373779296875 +3000 0.19818115234375 +3001 0.324249267578125 +3002 0.133331298828125 +3003 0.224090576171875 +3004 0.0693359375 +3005 0.124267578125 +3006 0.01409912109375 +3007 0.037078857421875 +3008 -0.014678955078125 +3009 -0.010101318359375 +3010 -0.0185546875 +3011 -0.019439697265625 +3012 -0.018280029296875 +3013 -0.022796630859375 +3014 -0.001953125 +3015 -0.001556396484375 +3016 0.038055419921875 +3017 0.056304931640625 +3018 0.07305908203125 +3019 0.106719970703125 +3020 0.068756103515625 +3021 0.096893310546875 +3022 0.035308837890625 +3023 0.042694091796875 +3024 -0.002838134765625 +3025 -0.018035888671875 +3026 -0.03961181640625 +3027 -0.07586669921875 +3028 -0.06768798828125 +3029 -0.11944580078125 +3030 -0.094146728515625 +3031 -0.15972900390625 +3032 -0.122772216796875 +3033 -0.202606201171875 +3034 -0.15380859375 +3035 -0.24859619140625 +3036 -0.1920166015625 +3037 -0.30517578125 +3038 -0.230743408203125 +3039 -0.36212158203125 +3040 -0.251708984375 +3041 -0.39141845703125 +3042 -0.23028564453125 +3043 -0.35528564453125 +3044 -0.163970947265625 +3045 -0.249969482421875 +3046 -0.06396484375 +3047 -0.092864990234375 +3048 0.0523681640625 +3049 0.08905029296875 +3050 0.145904541015625 +3051 0.2352294921875 +3052 0.199249267578125 +3053 0.318817138671875 +3054 0.22467041015625 +3055 0.358642578125 +3056 0.2176513671875 +3057 0.347747802734375 +3058 0.1778564453125 +3059 0.28564453125 +3060 0.138214111328125 +3061 0.223175048828125 +3062 0.122222900390625 +3063 0.196746826171875 +3064 0.1126708984375 +3065 0.179840087890625 +3066 0.0985107421875 +3067 0.155548095703125 +3068 0.097381591796875 +3069 0.151214599609375 +3070 0.102783203125 +3071 0.156951904296875 +3072 0.08819580078125 +3073 0.13177490234375 +3074 0.069366455078125 +3075 0.100799560546875 +3076 0.06103515625 +3077 0.087127685546875 +3078 0.040924072265625 +3079 0.05487060546875 +3080 0.000885009765625 +3081 -0.009002685546875 +3082 -0.0587158203125 +3083 -0.10400390625 +3084 -0.137420654296875 +3085 -0.229400634765625 +3086 -0.216888427734375 +3087 -0.35552978515625 +3088 -0.272064208984375 +3089 -0.441925048828125 +3090 -0.293792724609375 +3091 -0.473846435546875 +3092 -0.29022216796875 +3093 -0.464813232421875 +3094 -0.26385498046875 +3095 -0.419097900390625 +3096 -0.213104248046875 +3097 -0.334320068359375 +3098 -0.14862060546875 +3099 -0.227935791015625 +3100 -0.084869384765625 +3101 -0.12347412109375 +3102 -0.02593994140625 +3103 -0.02764892578125 +3104 0.039337158203125 +3105 0.077667236328125 +3106 0.12371826171875 +3107 0.2132568359375 +3108 0.233154296875 +3109 0.38885498046875 +3110 0.354217529296875 +3111 0.582794189453125 +3112 0.44921875 +3113 0.734039306640625 +3114 0.49188232421875 +3115 0.800140380859375 +3116 0.480377197265625 +3117 0.7783203125 +3118 0.412506103515625 +3119 0.6651611328125 +3120 0.287567138671875 +3121 0.45965576171875 +3122 0.128509521484375 +3123 0.199188232421875 +3124 -0.024383544921875 +3125 -0.050689697265625 +3126 -0.13604736328125 +3127 -0.23297119140625 +3128 -0.195709228515625 +3129 -0.33013916015625 +3130 -0.219482421875 +3131 -0.368408203125 +3132 -0.226531982421875 +3133 -0.378936767578125 +3134 -0.22625732421875 +3135 -0.376983642578125 +3136 -0.229156494140625 +3137 -0.37969970703125 +3138 -0.237884521484375 +3139 -0.391510009765625 +3140 -0.235687255859375 +3141 -0.385345458984375 +3142 -0.2105712890625 +3143 -0.3419189453125 +3144 -0.175811767578125 +3145 -0.28289794921875 +3146 -0.15802001953125 +3147 -0.251617431640625 +3148 -0.168212890625 +3149 -0.266143798828125 +3150 -0.17364501953125 +3151 -0.273345947265625 +3152 -0.13946533203125 +3153 -0.216796875 +3154 -0.085205078125 +3155 -0.128265380859375 +3156 -0.048095703125 +3157 -0.068145751953125 +3158 -0.0322265625 +3159 -0.0430908203125 +3160 -0.02001953125 +3161 -0.024444580078125 +3162 0.0087890625 +3163 0.020721435546875 +3164 0.073883056640625 +3165 0.124481201171875 +3166 0.1573486328125 +3167 0.25787353515625 +3168 0.23333740234375 +3169 0.379119873046875 +3170 0.296722412109375 +3171 0.47991943359375 +3172 0.32763671875 +3173 0.5281982421875 +3174 0.318145751953125 +3175 0.511138916015625 +3176 0.285125732421875 +3177 0.456207275390625 +3178 0.255706787109375 +3179 0.407470703125 +3180 0.241424560546875 +3181 0.383758544921875 +3182 0.224884033203125 +3183 0.35687255859375 +3184 0.1968994140625 +3185 0.31182861328125 +3186 0.158843994140625 +3187 0.250885009765625 +3188 0.105438232421875 +3189 0.1654052734375 +3190 0.02435302734375 +3191 0.035247802734375 +3192 -0.085906982421875 +3193 -0.142059326171875 +3194 -0.20623779296875 +3195 -0.33563232421875 +3196 -0.329803466796875 +3197 -0.5345458984375 +3198 -0.446136474609375 +3199 -0.72186279296875 +3200 -0.5177001953125 +3201 -0.836669921875 +3202 -0.515899658203125 +3203 -0.8326416015625 +3204 -0.452911376953125 +3205 -0.7296142578125 +3206 -0.36260986328125 +3207 -0.582550048828125 +3208 -0.274932861328125 +3209 -0.440093994140625 +3210 -0.203460693359375 +3211 -0.324310302734375 +3212 -0.12744140625 +3213 -0.20147705078125 +3214 -0.0302734375 +3215 -0.044647216796875 +3216 0.061981201171875 +3217 0.103973388671875 +3218 0.1234130859375 +3219 0.202392578125 +3220 0.16253662109375 +3221 0.264495849609375 +3222 0.209228515625 +3223 0.338897705078125 +3224 0.274658203125 +3225 0.443817138671875 +3226 0.337738037109375 +3227 0.545074462890625 +3228 0.382781982421875 +3229 0.6173095703125 +3230 0.40484619140625 +3231 0.6524658203125 +3232 0.41180419921875 +3233 0.66339111328125 +3234 0.4073486328125 +3235 0.6561279296875 +3236 0.376800537109375 +3237 0.606781005859375 +3238 0.311431884765625 +3239 0.501190185546875 +3240 0.21954345703125 +3241 0.352783203125 +3242 0.110382080078125 +3243 0.176544189453125 +3244 -0.020477294921875 +3245 -0.034820556640625 +3246 -0.15875244140625 +3247 -0.258209228515625 +3248 -0.27288818359375 +3249 -0.44244384765625 +3250 -0.355316162109375 +3251 -0.5753173828125 +3252 -0.403076171875 +3253 -0.65203857421875 +3254 -0.397064208984375 +3255 -0.641632080078125 +3256 -0.348388671875 +3257 -0.562164306640625 +3258 -0.284393310546875 +3259 -0.458038330078125 +3260 -0.21820068359375 +3261 -0.350555419921875 +3262 -0.162628173828125 +3263 -0.260528564453125 +3264 -0.120269775390625 +3265 -0.192108154296875 +3266 -0.08905029296875 +3267 -0.141937255859375 +3268 -0.06414794921875 +3269 -0.1021728515625 +3270 -0.03948974609375 +3271 -0.062896728515625 +3272 -0.007568359375 +3273 -0.011932373046875 +3274 0.03900146484375 +3275 0.062835693359375 +3276 0.0924072265625 +3277 0.148712158203125 +3278 0.150146484375 +3279 0.241729736328125 +3280 0.2166748046875 +3281 0.34912109375 +3282 0.283599853515625 +3283 0.457305908203125 +3284 0.33709716796875 +3285 0.54388427734375 +3286 0.355010986328125 +3287 0.5728759765625 +3288 0.31414794921875 +3289 0.506591796875 +3290 0.218292236328125 +3291 0.351226806640625 +3292 0.0919189453125 +3293 0.146514892578125 +3294 -0.032684326171875 +3295 -0.05523681640625 +3296 -0.132232666015625 +3297 -0.21624755859375 +3298 -0.205718994140625 +3299 -0.334930419921875 +3300 -0.248016357421875 +3301 -0.402984619140625 +3302 -0.27197265625 +3303 -0.4412841796875 +3304 -0.305908203125 +3305 -0.49578857421875 +3306 -0.345855712890625 +3307 -0.5601806640625 +3308 -0.371063232421875 +3309 -0.600738525390625 +3310 -0.361053466796875 +3311 -0.584228515625 +3312 -0.2965087890625 +3313 -0.47930908203125 +3314 -0.173370361328125 +3315 -0.27935791015625 +3316 -0.006744384765625 +3317 -0.0089111328125 +3318 0.164398193359375 +3319 0.268798828125 +3320 0.29638671875 +3321 0.482818603515625 +3322 0.371063232421875 +3323 0.60369873046875 +3324 0.40008544921875 +3325 0.650421142578125 +3326 0.408721923828125 +3327 0.66400146484375 +3328 0.395355224609375 +3329 0.6414794921875 +3330 0.353546142578125 +3331 0.572540283203125 +3332 0.307373046875 +3333 0.498138427734375 +3334 0.26947021484375 +3335 0.439453125 +3336 0.227874755859375 +3337 0.375518798828125 +3338 0.164276123046875 +3339 0.274505615234375 +3340 0.06280517578125 +3341 0.1087646484375 +3342 -0.063201904296875 +3343 -0.099395751953125 +3344 -0.1949462890625 +3345 -0.3182373046875 +3346 -0.33294677734375 +3347 -0.5489501953125 +3348 -0.4666748046875 +3349 -0.7738037109375 +3350 -0.56512451171875 +3351 -0.86383056640625 +3352 -0.60882568359375 +3353 -0.870391845703125 +3354 -0.608154296875 +3355 -0.86895751953125 +3356 -0.570831298828125 +3357 -0.861053466796875 +3358 -0.486846923828125 +3359 -0.765869140625 +3360 -0.349761962890625 +3361 -0.5301513671875 +3362 -0.163909912109375 +3363 -0.214691162109375 +3364 0.045379638671875 +3365 0.137359619140625 +3366 0.2479248046875 +3367 0.474822998046875 +3368 0.422760009765625 +3369 0.76239013671875 +3370 0.553924560546875 +3371 0.867462158203125 +3372 0.641510009765625 +3373 0.870361328125 +3374 0.678619384765625 +3375 0.86480712890625 +3376 0.668304443359375 +3377 0.831817626953125 +3378 0.624725341796875 +3379 0.677581787109375 +3380 0.55126953125 +3381 0.495880126953125 +3382 0.458831787109375 +3383 0.30767822265625 +3384 0.3487548828125 +3385 0.116180419921875 +3386 0.20263671875 +3387 -0.110748291015625 +3388 0.01654052734375 +3389 -0.381805419921875 +3390 -0.184326171875 +3391 -0.6572265625 +3392 -0.364837646484375 +3393 -0.857421875 +3394 -0.499755859375 +3395 -0.870391845703125 +3396 -0.584747314453125 +3397 -0.870391845703125 +3398 -0.635406494140625 +3399 -0.86444091796875 +3400 -0.67242431640625 +3401 -0.85723876953125 +3402 -0.68499755859375 +3403 -0.790008544921875 +3404 -0.641387939453125 +3405 -0.62847900390625 +3406 -0.539703369140625 +3407 -0.3956298828125 +3408 -0.39910888671875 +3409 -0.126708984375 +3410 -0.23565673828125 +3411 0.150115966796875 +3412 -0.0562744140625 +3413 0.424041748046875 +3414 0.123138427734375 +3415 0.670623779296875 +3416 0.279815673828125 +3417 0.854522705078125 +3418 0.403289794921875 +3419 0.866485595703125 +3420 0.48443603515625 +3421 0.86920166015625 +3422 0.53369140625 +3423 0.8653564453125 +3424 0.558746337890625 +3425 0.857147216796875 +3426 0.55780029296875 +3427 0.766845703125 +3428 0.533721923828125 +3429 0.628509521484375 +3430 0.482513427734375 +3431 0.462127685546875 +3432 0.41925048828125 +3433 0.297210693359375 +3434 0.351165771484375 +3435 0.14862060546875 +3436 0.26495361328125 +3437 -0.00537109375 +3438 0.16510009765625 +3439 -0.15753173828125 +3440 0.049560546875 +3441 -0.31304931640625 +3442 -0.0897216796875 +3443 -0.48876953125 +3444 -0.2252197265625 +3445 -0.6416015625 +3446 -0.34234619140625 +3447 -0.751373291015625 +3448 -0.4544677734375 +3449 -0.84619140625 +3450 -0.5528564453125 +3451 -0.861297607421875 +3452 -0.6180419921875 +3453 -0.863250732421875 +3454 -0.631500244140625 +3455 -0.856597900390625 +3456 -0.60028076171875 +3457 -0.7498779296875 +3458 -0.558135986328125 +3459 -0.624542236328125 +3460 -0.492218017578125 +3461 -0.47808837890625 +3462 -0.368408203125 +3463 -0.253387451171875 +3464 -0.21343994140625 +3465 0.003692626953125 +3466 -0.06732177734375 +3467 0.2257080078125 +3468 0.077178955078125 +3469 0.427154541015625 +3470 0.23883056640625 +3471 0.643218994140625 +3472 0.411865234375 +3473 0.855926513671875 +3474 0.56231689453125 +3475 0.870361328125 +3476 0.66107177734375 +3477 0.870361328125 +3478 0.712188720703125 +3479 0.862762451171875 +3480 0.7138671875 +3481 0.79669189453125 +3482 0.6605224609375 +3483 0.595794677734375 +3484 0.5692138671875 +3485 0.362152099609375 +3486 0.456298828125 +3487 0.1270751953125 +3488 0.33416748046875 +3489 -0.086944580078125 +3490 0.2041015625 +3491 -0.2784423828125 +3492 0.04583740234375 +3493 -0.484832763671875 +3494 -0.15167236328125 +3495 -0.729583740234375 +3496 -0.358734130859375 +3497 -0.86688232421875 +3498 -0.538238525390625 +3499 -0.870391845703125 +3500 -0.687103271484375 +3501 -0.86859130859375 +3502 -0.803955078125 +3503 -0.86279296875 +3504 -0.85595703125 +3505 -0.817962646484375 +3506 -0.851593017578125 +3507 -0.6116943359375 +3508 -0.751495361328125 +3509 -0.3128662109375 +3510 -0.5870361328125 +3511 0.039398193359375 +3512 -0.369903564453125 +3513 0.422821044921875 +3514 -0.119598388671875 +3515 0.805145263671875 +3516 0.1240234375 +3517 0.870361328125 +3518 0.3275146484375 +3519 0.870361328125 +3520 0.48382568359375 +3521 0.860015869140625 +3522 0.588226318359375 +3523 0.727935791015625 +3524 0.637176513671875 +3525 0.48114013671875 +3526 0.644561767578125 +3527 0.2059326171875 +3528 0.62335205078125 +3529 -0.06103515625 +3530 0.579193115234375 +3531 -0.29913330078125 +3532 0.503448486328125 +3533 -0.516204833984375 +3534 0.3870849609375 +3535 -0.7252197265625 +3536 0.24462890625 +3537 -0.85980224609375 +3538 0.096221923828125 +3539 -0.870391845703125 +3540 -0.0406494140625 +3541 -0.870391845703125 +3542 -0.13726806640625 +3543 -0.858062744140625 +3544 -0.190826416015625 +3545 -0.673004150390625 +3546 -0.231597900390625 +3547 -0.42694091796875 +3548 -0.285125732421875 +3549 -0.2100830078125 +3550 -0.3497314453125 +3551 -0.0362548828125 +3552 -0.4080810546875 +3553 0.10943603515625 +3554 -0.448211669921875 +3555 0.23516845703125 +3556 -0.4456787109375 +3557 0.373687744140625 +3558 -0.40142822265625 +3559 0.517791748046875 +3560 -0.352142333984375 +3561 0.602783203125 +3562 -0.294830322265625 +3563 0.635711669921875 +3564 -0.21014404296875 +3565 0.655181884765625 +3566 -0.104095458984375 +3567 0.65948486328125 +3568 0.018341064453125 +3569 0.651275634765625 +3570 0.142486572265625 +3571 0.61846923828125 +3572 0.246307373046875 +3573 0.53753662109375 +3574 0.318817138671875 +3575 0.404144287109375 +3576 0.353912353515625 +3577 0.22186279296875 +3578 0.351959228515625 +3579 0.003997802734375 +3580 0.32318115234375 +3581 -0.22100830078125 +3582 0.279327392578125 +3583 -0.42449951171875 +3584 0.23236083984375 +3585 -0.579833984375 +3586 0.206451416015625 +3587 -0.641876220703125 +3588 0.19830322265625 +3589 -0.6177978515625 +3590 0.17205810546875 +3591 -0.575531005859375 +3592 0.124725341796875 +3593 -0.526336669921875 +3594 0.084991455078125 +3595 -0.42645263671875 +3596 0.068267822265625 +3597 -0.2581787109375 +3598 0.0548095703125 +3599 -0.068695068359375 +3600 0.023773193359375 +3601 0.09222412109375 +3602 -0.014068603515625 +3603 0.232147216796875 +3604 -0.052642822265625 +3605 0.3509521484375 +3606 -0.107879638671875 +3607 0.410064697265625 +3608 -0.19561767578125 +3609 0.372955322265625 +3610 -0.303955078125 +3611 0.2554931640625 +3612 -0.4039306640625 +3613 0.10711669921875 +3614 -0.484588623046875 +3615 -0.052886962890625 +3616 -0.52593994140625 +3617 -0.186279296875 +3618 -0.497314453125 +3619 -0.23291015625 +3620 -0.411468505859375 +3621 -0.209442138671875 +3622 -0.3050537109375 +3623 -0.174163818359375 +3624 -0.183013916015625 +3625 -0.126739501953125 +3626 -0.040313720703125 +3627 -0.048126220703125 +3628 0.106964111328125 +3629 0.0426025390625 +3630 0.232635498046875 +3631 0.10748291015625 +3632 0.32891845703125 +3633 0.1409912109375 +3634 0.4217529296875 +3635 0.19708251953125 +3636 0.507049560546875 +3637 0.273651123046875 +3638 0.553741455078125 +3639 0.31768798828125 +3640 0.567779541015625 +3641 0.341094970703125 +3642 0.56304931640625 +3643 0.368011474609375 +3644 0.526885986328125 +3645 0.37249755859375 +3646 0.432220458984375 +3647 0.30072021484375 +3648 0.282012939453125 +3649 0.1517333984375 +3650 0.113311767578125 +3651 -0.01470947265625 +3652 -0.063751220703125 +3653 -0.1883544921875 +3654 -0.24658203125 +3655 -0.372711181640625 +3656 -0.401092529296875 +3657 -0.51397705078125 +3658 -0.50091552734375 +3659 -0.57177734375 +3660 -0.5389404296875 +3661 -0.53948974609375 +3662 -0.52239990234375 +3663 -0.43511962890625 +3664 -0.470245361328125 +3665 -0.2962646484375 +3666 -0.4027099609375 +3667 -0.161102294921875 +3668 -0.32757568359375 +3669 -0.0435791015625 +3670 -0.24365234375 +3671 0.060394287109375 +3672 -0.16064453125 +3673 0.13665771484375 +3674 -0.089508056640625 +3675 0.170135498046875 +3676 -0.0308837890625 +3677 0.16552734375 +3678 0.0306396484375 +3679 0.15728759765625 +3680 0.09429931640625 +3681 0.150787353515625 +3682 0.14312744140625 +3683 0.12200927734375 +3684 0.1787109375 +3685 0.080108642578125 +3686 0.212493896484375 +3687 0.05126953125 +3688 0.25714111328125 +3689 0.062896728515625 +3690 0.298583984375 +3691 0.09271240234375 +3692 0.309539794921875 +3693 0.092987060546875 +3694 0.2979736328125 +3695 0.07855224609375 +3696 0.272735595703125 +3697 0.06427001953125 +3698 0.2266845703125 +3699 0.0347900390625 +3700 0.1607666015625 +3701 -0.01171875 +3702 0.08807373046875 +3703 -0.056060791015625 +3704 0.0350341796875 +3705 -0.055511474609375 +3706 0.0045166015625 +3707 -0.010467529296875 +3708 -0.030181884765625 +3709 0.02508544921875 +3710 -0.0802001953125 +3711 0.025665283203125 +3712 -0.128509521484375 +3713 0.017333984375 +3714 -0.17193603515625 +3715 0.00189208984375 +3716 -0.214935302734375 +3717 -0.03173828125 +3718 -0.249847412109375 +3719 -0.071502685546875 +3720 -0.2862548828125 +3721 -0.13543701171875 +3722 -0.322479248046875 +3723 -0.219970703125 +3724 -0.3458251953125 +3725 -0.300506591796875 +3726 -0.357330322265625 +3727 -0.376312255859375 +3728 -0.341644287109375 +3729 -0.416107177734375 +3730 -0.27410888671875 +3731 -0.371124267578125 +3732 -0.157745361328125 +3733 -0.242279052734375 +3734 -0.017242431640625 +3735 -0.069732666015625 +3736 0.133392333984375 +3737 0.125640869140625 +3738 0.274688720703125 +3739 0.31268310546875 +3740 0.3846435546875 +3741 0.45501708984375 +3742 0.462921142578125 +3743 0.554779052734375 +3744 0.507781982421875 +3745 0.61065673828125 +3746 0.512237548828125 +3747 0.610931396484375 +3748 0.4630126953125 +3749 0.531463623046875 +3750 0.36956787109375 +3751 0.3883056640625 +3752 0.262298583984375 +3753 0.23468017578125 +3754 0.15631103515625 +3755 0.095245361328125 +3756 0.06768798828125 +3757 -0.00396728515625 +3758 0.006378173828125 +3759 -0.04852294921875 +3760 -0.03472900390625 +3761 -0.055145263671875 +3762 -0.082275390625 +3763 -0.0758056640625 +3764 -0.149871826171875 +3765 -0.138702392578125 +3766 -0.216705322265625 +3767 -0.209197998046875 +3768 -0.2823486328125 +3769 -0.289031982421875 +3770 -0.346160888671875 +3771 -0.37884521484375 +3772 -0.395263671875 +3773 -0.456329345703125 +3774 -0.4267578125 +3775 -0.51641845703125 +3776 -0.418975830078125 +3777 -0.519287109375 +3778 -0.368988037109375 +3779 -0.458251953125 +3780 -0.3062744140625 +3781 -0.384796142578125 +3782 -0.245880126953125 +3783 -0.323699951171875 +3784 -0.186248779296875 +3785 -0.269287109375 +3786 -0.114532470703125 +3787 -0.1951904296875 +3788 -0.03167724609375 +3789 -0.100006103515625 +3790 0.04583740234375 +3791 -0.01055908203125 +3792 0.13323974609375 +3793 0.1033935546875 +3794 0.233306884765625 +3795 0.24908447265625 +3796 0.315673828125 +3797 0.373199462890625 +3798 0.370025634765625 +3799 0.45806884765625 +3800 0.400390625 +3801 0.511474609375 +3802 0.424591064453125 +3803 0.565399169921875 +3804 0.43841552734375 +3805 0.61138916015625 +3806 0.40972900390625 +3807 0.5897216796875 +3808 0.334136962890625 +3809 0.4906005859375 +3810 0.222564697265625 +3811 0.33148193359375 +3812 0.095947265625 +3813 0.147796630859375 +3814 -0.021240234375 +3815 -0.01873779296875 +3816 -0.112274169921875 +3817 -0.140289306640625 +3818 -0.162139892578125 +3819 -0.191986083984375 +3820 -0.175537109375 +3821 -0.184295654296875 +3822 -0.176239013671875 +3823 -0.161834716796875 +3824 -0.18682861328125 +3825 -0.166595458984375 +3826 -0.204437255859375 +3827 -0.19390869140625 +3828 -0.218414306640625 +3829 -0.22442626953125 +3830 -0.240997314453125 +3831 -0.279754638671875 +3832 -0.26123046875 +3833 -0.3389892578125 +3834 -0.253570556640625 +3835 -0.3543701171875 +3836 -0.231292724609375 +3837 -0.348175048828125 +3838 -0.198577880859375 +3839 -0.32598876953125 +3840 -0.1402587890625 +3841 -0.2581787109375 +3842 -0.054779052734375 +3843 -0.139801025390625 +3844 0.04876708984375 +3845 0.014617919921875 +3846 0.135955810546875 +3847 0.144378662109375 +3848 0.1904296875 +3849 0.221038818359375 +3850 0.225921630859375 +3851 0.27069091796875 +3852 0.24249267578125 +3853 0.294036865234375 +3854 0.25146484375 +3855 0.311767578125 +3856 0.261322021484375 +3857 0.339141845703125 +3858 0.263336181640625 +3859 0.360260009765625 +3860 0.250213623046875 +3861 0.360504150390625 +3862 0.20654296875 +3863 0.308380126953125 +3864 0.121856689453125 +3865 0.18170166015625 +3866 0.010009765625 +3867 0.0047607421875 +3868 -0.10345458984375 +3869 -0.17559814453125 +3870 -0.194000244140625 +3871 -0.3143310546875 +3872 -0.238006591796875 +3873 -0.36785888671875 +3874 -0.248321533203125 +3875 -0.36248779296875 +3876 -0.247894287109375 +3877 -0.343536376953125 +3878 -0.2315673828125 +3879 -0.3018798828125 +3880 -0.19598388671875 +3881 -0.231414794921875 +3882 -0.133697509765625 +3883 -0.117645263671875 +3884 -0.06182861328125 +3885 0.007049560546875 +3886 -0.009307861328125 +3887 0.087982177734375 +3888 0.030609130859375 +3889 0.13946533203125 +3890 0.06378173828125 +3891 0.17425537109375 +3892 0.087158203125 +3893 0.188201904296875 +3894 0.094573974609375 +3895 0.171234130859375 +3896 0.08258056640625 +3897 0.118438720703125 +3898 0.064544677734375 +3899 0.05706787109375 +3900 0.040863037109375 +3901 -0.010711669921875 +3902 0.007568359375 +3903 -0.0914306640625 +3904 -0.023834228515625 +3905 -0.162322998046875 +3906 -0.03857421875 +3907 -0.194549560546875 +3908 -0.0164794921875 +3909 -0.1492919921875 +3910 0.045135498046875 +3911 -0.02166748046875 +3912 0.11322021484375 +3913 0.124053955078125 +3914 0.14837646484375 +3915 0.211151123046875 +3916 0.151641845703125 +3917 0.240447998046875 +3918 0.13946533203125 +3919 0.242218017578125 +3920 0.117431640625 +3921 0.2257080078125 +3922 0.08807373046875 +3923 0.194366455078125 +3924 0.03509521484375 +3925 0.115509033203125 +3926 -0.028533935546875 +3927 0.0128173828125 +3928 -0.0711669921875 +3929 -0.053802490234375 +3930 -0.1060791015625 +3931 -0.110626220703125 +3932 -0.15484619140625 +3933 -0.199493408203125 +3934 -0.203887939453125 +3935 -0.29437255859375 +3936 -0.220458984375 +3937 -0.33221435546875 +3938 -0.187530517578125 +3939 -0.27972412109375 +3940 -0.13067626953125 +3941 -0.185333251953125 +3942 -0.091522216796875 +3943 -0.128204345703125 +3944 -0.074462890625 +3945 -0.115692138671875 +3946 -0.0638427734375 +3947 -0.116455078125 +3948 -0.047454833984375 +3949 -0.105926513671875 +3950 -0.01025390625 +3951 -0.053955078125 +3952 0.052093505859375 +3953 0.048797607421875 +3954 0.115753173828125 +3955 0.157318115234375 +3956 0.14935302734375 +3957 0.212005615234375 +3958 0.155609130859375 +3959 0.218475341796875 +3960 0.165863037109375 +3961 0.23724365234375 +3962 0.199432373046875 +3963 0.30535888671875 +3964 0.234893798828125 +3965 0.38128662109375 +3966 0.24102783203125 +3967 0.404449462890625 +3968 0.228363037109375 +3969 0.3944091796875 +3970 0.216827392578125 +3971 0.3885498046875 +3972 0.194305419921875 +3973 0.362640380859375 +3974 0.138916015625 +3975 0.27362060546875 +3976 0.04888916015625 +3977 0.11712646484375 +3978 -0.04827880859375 +3979 -0.054901123046875 +3980 -0.125335693359375 +3981 -0.19085693359375 +3982 -0.17938232421875 +3983 -0.28570556640625 +3984 -0.21014404296875 +3985 -0.339263916015625 +3986 -0.23101806640625 +3987 -0.3775634765625 +3988 -0.2655029296875 +3989 -0.445709228515625 +3990 -0.309173583984375 +3991 -0.535064697265625 +3992 -0.3536376953125 +3993 -0.629058837890625 +3994 -0.383514404296875 +3995 -0.697601318359375 +3996 -0.38006591796875 +3997 -0.70391845703125 +3998 -0.340789794921875 +3999 -0.6424560546875 +4000 -0.254669189453125 +4001 -0.491241455078125 +4002 -0.130157470703125 +4003 -0.265716552734375 +4004 0.00225830078125 +4005 -0.023712158203125 +4006 0.125091552734375 +4007 0.201751708984375 +4008 0.219940185546875 +4009 0.375823974609375 +4010 0.27960205078125 +4011 0.485076904296875 +4012 0.324432373046875 +4013 0.56884765625 +4014 0.3583984375 +4015 0.634765625 +4016 0.3580322265625 +4017 0.63763427734375 +4018 0.317535400390625 +4019 0.5660400390625 +4020 0.26422119140625 +4021 0.4720458984375 +4022 0.225006103515625 +4023 0.40692138671875 +4024 0.203948974609375 +4025 0.3778076171875 +4026 0.197357177734375 +4027 0.376953125 +4028 0.188720703125 +4029 0.371978759765625 +4030 0.15252685546875 +4031 0.313140869140625 +4032 0.0806884765625 +4033 0.184417724609375 +4034 -0.0133056640625 +4035 0.011199951171875 +4036 -0.110809326171875 +4037 -0.171051025390625 +4038 -0.198760986328125 +4039 -0.33740234375 +4040 -0.268829345703125 +4041 -0.47198486328125 +4042 -0.3135986328125 +4043 -0.560394287109375 +4044 -0.321685791015625 +4045 -0.58056640625 +4046 -0.30108642578125 +4047 -0.54754638671875 +4048 -0.276580810546875 +4049 -0.508575439453125 +4050 -0.24627685546875 +4051 -0.459503173828125 +4052 -0.207366943359375 +4053 -0.394378662109375 +4054 -0.18060302734375 +4055 -0.35260009765625 +4056 -0.154571533203125 +4057 -0.31170654296875 +4058 -0.090911865234375 +4059 -0.197418212890625 +4060 0.01104736328125 +4061 -0.007965087890625 +4062 0.125579833984375 +4063 0.207489013671875 +4064 0.23193359375 +4065 0.409210205078125 +4066 0.3170166015625 +4067 0.57208251953125 +4068 0.365142822265625 +4069 0.66595458984375 +4070 0.359710693359375 +4071 0.65875244140625 +4072 0.30963134765625 +4073 0.56744384765625 +4074 0.235565185546875 +4075 0.431396484375 +4076 0.1605224609375 +4077 0.29443359375 +4078 0.098175048828125 +4079 0.182464599609375 +4080 0.0322265625 +4081 0.06365966796875 +4082 -0.044342041015625 +4083 -0.075958251953125 +4084 -0.10693359375 +4085 -0.189422607421875 +4086 -0.152862548828125 +4087 -0.271942138671875 +4088 -0.19183349609375 +4089 -0.342529296875 +4090 -0.204559326171875 +4091 -0.364166259765625 +4092 -0.18597412109375 +4093 -0.327239990234375 +4094 -0.159576416015625 +4095 -0.2769775390625 +4096 -0.146087646484375 +4097 -0.253692626953125 +4098 -0.138702392578125 +4099 -0.24365234375 +4100 -0.1134033203125 +4101 -0.1983642578125 +4102 -0.069488525390625 +4103 -0.116241455078125 +4104 -0.026336669921875 +4105 -0.036834716796875 +4106 0.013427734375 +4107 0.034881591796875 +4108 0.04583740234375 +4109 0.09124755859375 +4110 0.059234619140625 +4111 0.10888671875 +4112 0.071746826171875 +4113 0.125518798828125 +4114 0.09124755859375 +4115 0.15771484375 +4116 0.104248046875 +4117 0.17828369140625 +4118 0.10272216796875 +4119 0.17108154296875 +4120 0.083587646484375 +4121 0.129974365234375 +4122 0.060211181640625 +4123 0.082427978515625 +4124 0.032257080078125 +4125 0.027679443359375 +4126 -0.015472412109375 +4127 -0.065643310546875 +4128 -0.064178466796875 +4129 -0.15936279296875 +4130 -0.093994140625 +4131 -0.21307373046875 +4132 -0.108551025390625 +4133 -0.234649658203125 +4134 -0.095947265625 +4135 -0.2001953125 +4136 -0.060577392578125 +4137 -0.119171142578125 +4138 -0.018402099609375 +4139 -0.024749755859375 +4140 0.032073974609375 +4141 0.085784912109375 +4142 0.074310302734375 +4143 0.178131103515625 +4144 0.09051513671875 +4145 0.215576171875 +4146 0.0872802734375 +4147 0.211456298828125 +4148 0.06927490234375 +4149 0.17523193359375 +4150 0.04718017578125 +4151 0.128753662109375 +4152 0.0355224609375 +4153 0.1019287109375 +4154 0.02423095703125 +4155 0.0743408203125 +4156 0.0118408203125 +4157 0.04327392578125 +4158 0.012542724609375 +4159 0.038177490234375 +4160 0.034576416015625 +4161 0.076263427734375 +4162 0.069671630859375 +4163 0.14105224609375 +4164 0.09515380859375 +4165 0.186431884765625 +4166 0.099334716796875 +4167 0.188812255859375 +4168 0.07757568359375 +4169 0.1390380859375 +4170 0.03204345703125 +4171 0.041778564453125 +4172 -0.025848388671875 +4173 -0.079437255859375 +4174 -0.093597412109375 +4175 -0.219390869140625 +4176 -0.16619873046875 +4177 -0.367828369140625 +4178 -0.229034423828125 +4179 -0.494873046875 +4180 -0.260467529296875 +4181 -0.556243896484375 +4182 -0.239288330078125 +4183 -0.508697509765625 +4184 -0.176788330078125 +4185 -0.3756103515625 +4186 -0.10302734375 +4187 -0.218902587890625 +4188 -0.030120849609375 +4189 -0.063751220703125 +4190 0.042877197265625 +4191 0.091552734375 +4192 0.110748291015625 +4193 0.23602294921875 +4194 0.160614013671875 +4195 0.342987060546875 +4196 0.1842041015625 +4197 0.39520263671875 +4198 0.17999267578125 +4199 0.389373779296875 +4200 0.147430419921875 +4201 0.324249267578125 +4202 0.098388671875 +4203 0.224090576171875 +4204 0.050140380859375 +4205 0.124267578125 +4206 0.00860595703125 +4207 0.037078857421875 +4208 -0.012908935546875 +4209 -0.010101318359375 +4210 -0.01556396484375 +4211 -0.019439697265625 +4212 -0.0150146484375 +4213 -0.022796630859375 +4214 -0.002288818359375 +4215 -0.001556396484375 +4216 0.0283203125 +4217 0.056304931640625 +4218 0.05517578125 +4219 0.106719970703125 +4220 0.05242919921875 +4221 0.096893310546875 +4222 0.027679443359375 +4223 0.042694091796875 +4224 -0.00067138671875 +4225 -0.018035888671875 +4226 -0.028076171875 +4227 -0.07586669921875 +4228 -0.04901123046875 +4229 -0.11944580078125 +4230 -0.06884765625 +4231 -0.15972900390625 +4232 -0.0904541015625 +4233 -0.202606201171875 +4234 -0.113983154296875 +4235 -0.24859619140625 +4236 -0.143035888671875 +4237 -0.30517578125 +4238 -0.17254638671875 +4239 -0.36212158203125 +4240 -0.188720703125 +4241 -0.39141845703125 +4242 -0.173004150390625 +4243 -0.35528564453125 +4244 -0.12347412109375 +4245 -0.249969482421875 +4246 -0.04852294921875 +4247 -0.092864990234375 +4248 0.03875732421875 +4249 0.08905029296875 +4250 0.10888671875 +4251 0.2352294921875 +4252 0.148834228515625 +4253 0.318817138671875 +4254 0.167816162109375 +4255 0.358642578125 +4256 0.162445068359375 +4257 0.347747802734375 +4258 0.132476806640625 +4259 0.28564453125 +4260 0.102691650390625 +4261 0.223175048828125 +4262 0.090789794921875 +4263 0.196746826171875 +4264 0.08380126953125 +4265 0.179840087890625 +4266 0.073394775390625 +4267 0.155548095703125 +4268 0.07281494140625 +4269 0.151214599609375 +4270 0.0771484375 +4271 0.156951904296875 +4272 0.066314697265625 +4273 0.13177490234375 +4274 0.052520751953125 +4275 0.100799560546875 +4276 0.04693603515625 +4277 0.087127685546875 +4278 0.032012939453125 +4279 0.05487060546875 +4280 0.0013427734375 +4281 -0.009002685546875 +4282 -0.044830322265625 +4283 -0.10400390625 +4284 -0.10614013671875 +4285 -0.229400634765625 +4286 -0.1680908203125 +4287 -0.35552978515625 +4288 -0.210906982421875 +4289 -0.441925048828125 +4290 -0.227386474609375 +4291 -0.473846435546875 +4292 -0.22406005859375 +4293 -0.464813232421875 +4294 -0.202911376953125 +4295 -0.419097900390625 +4296 -0.1627197265625 +4297 -0.334320068359375 +4298 -0.111968994140625 +4299 -0.227935791015625 +4300 -0.06207275390625 +4301 -0.12347412109375 +4302 -0.0162353515625 +4303 -0.02764892578125 +4304 0.034423828125 +4305 0.077667236328125 +4306 0.100067138671875 +4307 0.2132568359375 +4308 0.185455322265625 +4309 0.38885498046875 +4310 0.280029296875 +4311 0.582794189453125 +4312 0.35400390625 +4313 0.734039306640625 +4314 0.38665771484375 +4315 0.800140380859375 +4316 0.3765869140625 +4317 0.7783203125 +4318 0.322113037109375 +4319 0.6651611328125 +4320 0.222686767578125 +4321 0.45965576171875 +4322 0.09649658203125 +4323 0.199188232421875 +4324 -0.024505615234375 +4325 -0.050689697265625 +4326 -0.112548828125 +4327 -0.23297119140625 +4328 -0.159149169921875 +4329 -0.33013916015625 +4330 -0.177093505859375 +4331 -0.368408203125 +4332 -0.181640625 +4333 -0.378936767578125 +4334 -0.1802978515625 +4335 -0.376983642578125 +4336 -0.18145751953125 +4337 -0.37969970703125 +4338 -0.187255859375 +4339 -0.391510009765625 +4340 -0.1844482421875 +4341 -0.385345458984375 +4342 -0.16363525390625 +4343 -0.3419189453125 +4344 -0.1353759765625 +4345 -0.28289794921875 +4346 -0.12078857421875 +4347 -0.251617431640625 +4348 -0.12860107421875 +4349 -0.266143798828125 +4350 -0.13287353515625 +4351 -0.273345947265625 +4352 -0.106170654296875 +4353 -0.216796875 +4354 -0.06365966796875 +4355 -0.128265380859375 +4356 -0.0338134765625 +4357 -0.068145751953125 +4358 -0.019805908203125 +4359 -0.0430908203125 +4360 -0.008697509765625 +4361 -0.024444580078125 +4362 0.01434326171875 +4363 0.020721435546875 +4364 0.06378173828125 +4365 0.124481201171875 +4366 0.126312255859375 +4367 0.25787353515625 +4368 0.182769775390625 +4369 0.379119873046875 +4370 0.229339599609375 +4371 0.47991943359375 +4372 0.251373291015625 +4373 0.5281982421875 +4374 0.243011474609375 +4375 0.511138916015625 +4376 0.216827392578125 +4377 0.456207275390625 +4378 0.193023681640625 +4379 0.407470703125 +4380 0.1802978515625 +4381 0.383758544921875 +4382 0.1658935546875 +4383 0.35687255859375 +4384 0.143096923828125 +4385 0.31182861328125 +4386 0.113037109375 +4387 0.250885009765625 +4388 0.071929931640625 +4389 0.1654052734375 +4390 0.010711669921875 +4391 0.035247802734375 +4392 -0.071624755859375 +4393 -0.142059326171875 +4394 -0.160919189453125 +4395 -0.33563232421875 +4396 -0.252166748046875 +4397 -0.5345458984375 +4398 -0.337615966796875 +4399 -0.72186279296875 +4400 -0.389495849609375 +4401 -0.836669921875 +4402 -0.386749267578125 +4403 -0.8326416015625 +4404 -0.3385009765625 +4405 -0.7296142578125 +4406 -0.2698974609375 +4407 -0.582550048828125 +4408 -0.20318603515625 +4409 -0.440093994140625 +4410 -0.1485595703125 +4411 -0.324310302734375 +4412 -0.0906982421875 +4413 -0.20147705078125 +4414 -0.017425537109375 +4415 -0.044647216796875 +4416 0.051910400390625 +4417 0.103973388671875 +4418 0.098052978515625 +4419 0.202392578125 +4420 0.12725830078125 +4421 0.264495849609375 +4422 0.16168212890625 +4423 0.338897705078125 +4424 0.209625244140625 +4425 0.443817138671875 +4426 0.2554931640625 +4427 0.545074462890625 +4428 0.287750244140625 +4429 0.6173095703125 +4430 0.302764892578125 +4431 0.6524658203125 +4432 0.30645751953125 +4433 0.66339111328125 +4434 0.301666259765625 +4435 0.6561279296875 +4436 0.277587890625 +4437 0.606781005859375 +4438 0.22784423828125 +4439 0.501190185546875 +4440 0.158660888671875 +4441 0.352783203125 +4442 0.076934814453125 +4443 0.176544189453125 +4444 -0.020538330078125 +4445 -0.034820556640625 +4446 -0.1231689453125 +4447 -0.258209228515625 +4448 -0.20758056640625 +4449 -0.44244384765625 +4450 -0.268218994140625 +4451 -0.5753173828125 +4452 -0.30291748046875 +4453 -0.65203857421875 +4454 -0.297576904296875 +4455 -0.641632080078125 +4456 -0.260467529296875 +4457 -0.562164306640625 +4458 -0.2119140625 +4459 -0.458038330078125 +4460 -0.16168212890625 +4461 -0.350555419921875 +4462 -0.11932373046875 +4463 -0.260528564453125 +4464 -0.086822509765625 +4465 -0.192108154296875 +4466 -0.062713623046875 +4467 -0.141937255859375 +4468 -0.043487548828125 +4469 -0.1021728515625 +4470 -0.024658203125 +4471 -0.062896728515625 +4472 -0.000701904296875 +4473 -0.011932373046875 +4474 0.033843994140625 +4475 0.062835693359375 +4476 0.07318115234375 +4477 0.148712158203125 +4478 0.115478515625 +4479 0.241729736328125 +4480 0.164031982421875 +4481 0.34912109375 +4482 0.212677001953125 +4483 0.457305908203125 +4484 0.251251220703125 +4485 0.54388427734375 +4486 0.263427734375 +4487 0.5728759765625 +4488 0.232086181640625 +4489 0.506591796875 +4490 0.16009521484375 +4491 0.351226806640625 +4492 0.065643310546875 +4493 0.146514892578125 +4494 -0.02734375 +4495 -0.05523681640625 +4496 -0.101593017578125 +4497 -0.21624755859375 +4498 -0.156341552734375 +4499 -0.334930419921875 +4500 -0.187774658203125 +4501 -0.402984619140625 +4502 -0.20538330078125 +4503 -0.4412841796875 +4504 -0.230133056640625 +4505 -0.49578857421875 +4506 -0.2591552734375 +4507 -0.5601806640625 +4508 -0.277099609375 +4509 -0.600738525390625 +4510 -0.268829345703125 +4511 -0.584228515625 +4512 -0.220123291015625 +4513 -0.47930908203125 +4514 -0.128021240234375 +4515 -0.27935791015625 +4516 -0.003753662109375 +4517 -0.0089111328125 +4518 0.123748779296875 +4519 0.268798828125 +4520 0.222137451171875 +4521 0.482818603515625 +4522 0.277923583984375 +4523 0.60369873046875 +4524 0.299713134765625 +4525 0.650421142578125 +4526 0.30621337890625 +4527 0.66400146484375 +4528 0.296051025390625 +4529 0.6414794921875 +4530 0.2645263671875 +4531 0.572540283203125 +4532 0.230316162109375 +4533 0.498138427734375 +4534 0.203094482421875 +4535 0.439453125 +4536 0.173370361328125 +4537 0.375518798828125 +4538 0.12664794921875 +4539 0.274505615234375 +4540 0.05035400390625 +4541 0.1087646484375 +4542 -0.0452880859375 +4543 -0.099395751953125 +4544 -0.145782470703125 +4545 -0.3182373046875 +4546 -0.251617431640625 +4547 -0.5489501953125 +4548 -0.35467529296875 +4549 -0.7738037109375 +4550 -0.4307861328125 +4551 -0.86383056640625 +4552 -0.464752197265625 +4553 -0.870391845703125 +4554 -0.46466064453125 +4555 -0.86895751953125 +4556 -0.436492919921875 +4557 -0.861053466796875 +4558 -0.37237548828125 +4559 -0.765869140625 +4560 -0.26715087890625 +4561 -0.5301513671875 +4562 -0.124114990234375 +4563 -0.214691162109375 +4564 0.037078857421875 +4565 0.137359619140625 +4566 0.1929931640625 +4567 0.474822998046875 +4568 0.327362060546875 +4569 0.76239013671875 +4570 0.427825927734375 +4571 0.867462158203125 +4572 0.49456787109375 +4573 0.870361328125 +4574 0.522308349609375 +4575 0.86480712890625 +4576 0.513458251953125 +4577 0.831817626953125 +4578 0.4791259765625 +4579 0.677581787109375 +4580 0.42193603515625 +4581 0.495880126953125 +4582 0.35040283203125 +4583 0.30767822265625 +4584 0.2655029296875 +4585 0.116180419921875 +4586 0.152801513671875 +4587 -0.110748291015625 +4588 0.009185791015625 +4589 -0.381805419921875 +4590 -0.14581298828125 +4591 -0.6572265625 +4592 -0.28485107421875 +4593 -0.857421875 +4594 -0.388336181640625 +4595 -0.870391845703125 +4596 -0.4530029296875 +4597 -0.870391845703125 +4598 -0.4910888671875 +4599 -0.86444091796875 +4600 -0.518829345703125 +4601 -0.85723876953125 +4602 -0.52783203125 +4603 -0.790008544921875 +4604 -0.49334716796875 +4605 -0.62847900390625 +4606 -0.413909912109375 +4607 -0.3956298828125 +4608 -0.3045654296875 +4609 -0.126708984375 +4610 -0.17779541015625 +4611 0.150115966796875 +4612 -0.039276123046875 +4613 0.424041748046875 +4614 0.098876953125 +4615 0.670623779296875 +4616 0.21966552734375 +4617 0.854522705078125 +4618 0.315093994140625 +4619 0.866485595703125 +4620 0.37823486328125 +4621 0.86920166015625 +4622 0.41650390625 +4623 0.8653564453125 +4624 0.4354248046875 +4625 0.857147216796875 +4626 0.433685302734375 +4627 0.766845703125 +4628 0.413543701171875 +4629 0.628509521484375 +4630 0.372314453125 +4631 0.462127685546875 +4632 0.3211669921875 +4633 0.297210693359375 +4634 0.265716552734375 +4635 0.14862060546875 +4636 0.1966552734375 +4637 -0.00537109375 +4638 0.11761474609375 +4639 -0.15753173828125 +4640 0.027496337890625 +4641 -0.31304931640625 +4642 -0.079193115234375 +4643 -0.48876953125 +4644 -0.182220458984375 +4645 -0.6416015625 +4646 -0.270751953125 +4647 -0.751373291015625 +4648 -0.35430908203125 +4649 -0.84619140625 +4650 -0.426513671875 +4651 -0.861297607421875 +4652 -0.47320556640625 +4653 -0.863250732421875 +4654 -0.480987548828125 +4655 -0.856597900390625 +4656 -0.455108642578125 +4657 -0.7498779296875 +4658 -0.420318603515625 +4659 -0.624542236328125 +4660 -0.367523193359375 +4661 -0.47808837890625 +4662 -0.27227783203125 +4663 -0.253387451171875 +4664 -0.154266357421875 +4665 0.003692626953125 +4666 -0.042877197265625 +4667 0.2257080078125 +4668 0.066802978515625 +4669 0.427154541015625 +4670 0.188201904296875 +4671 0.643218994140625 +4672 0.31695556640625 +4673 0.855926513671875 +4674 0.42822265625 +4675 0.870361328125 +4676 0.500823974609375 +4677 0.870361328125 +4678 0.537689208984375 +4679 0.862762451171875 +4680 0.53753662109375 +4681 0.79669189453125 +4682 0.496429443359375 +4683 0.595794677734375 +4684 0.4268798828125 +4685 0.362152099609375 +4686 0.340972900390625 +4687 0.1270751953125 +4688 0.2479248046875 +4689 -0.086944580078125 +4690 0.148956298828125 +4691 -0.2784423828125 +4692 0.02960205078125 +4693 -0.484832763671875 +4694 -0.117889404296875 +4695 -0.729583740234375 +4696 -0.27178955078125 +4697 -0.86688232421875 +4698 -0.404937744140625 +4699 -0.870391845703125 +4700 -0.514984130859375 +4701 -0.86859130859375 +4702 -0.600830078125 +4703 -0.86279296875 +4704 -0.6470947265625 +4705 -0.817962646484375 +4706 -0.634490966796875 +4707 -0.6116943359375 +4708 -0.56005859375 +4709 -0.3128662109375 +4710 -0.43817138671875 +4711 0.039398193359375 +4712 -0.2774658203125 +4713 0.422821044921875 +4714 -0.092254638671875 +4715 0.805145263671875 +4716 0.0882568359375 +4717 0.870361328125 +4718 0.239593505859375 +4719 0.870361328125 +4720 0.356475830078125 +4721 0.860015869140625 +4722 0.435302734375 +4723 0.727935791015625 +4724 0.473358154296875 +4725 0.48114013671875 +4726 0.480560302734375 +4727 0.2059326171875 +4728 0.46624755859375 +4729 -0.06103515625 +4730 0.43450927734375 +4731 -0.29913330078125 +4732 0.37908935546875 +4733 -0.516204833984375 +4734 0.29345703125 +4735 -0.7252197265625 +4736 0.188262939453125 +4737 -0.85980224609375 +4738 0.0782470703125 +4739 -0.870391845703125 +4740 -0.023773193359375 +4741 -0.870391845703125 +4742 -0.0968017578125 +4743 -0.858062744140625 +4744 -0.138641357421875 +4745 -0.673004150390625 +4746 -0.171112060546875 +4747 -0.42694091796875 +4748 -0.212615966796875 +4749 -0.2100830078125 +4750 -0.26177978515625 +4751 -0.0362548828125 +4752 -0.305877685546875 +4753 0.10943603515625 +4754 -0.336151123046875 +4755 0.23516845703125 +4756 -0.334808349609375 +4757 0.373687744140625 +4758 -0.302520751953125 +4759 0.517791748046875 +4760 -0.2659912109375 +4761 0.602783203125 +4762 -0.22308349609375 +4763 0.635711669921875 +4764 -0.15985107421875 +4765 0.655181884765625 +4766 -0.080718994140625 +4767 0.65948486328125 +4768 0.010498046875 +4769 0.651275634765625 +4770 0.10302734375 +4771 0.61846923828125 +4772 0.180755615234375 +4773 0.53753662109375 +4774 0.235565185546875 +4775 0.404144287109375 +4776 0.262939453125 +4777 0.22186279296875 +4778 0.263031005859375 +4779 0.003997802734375 +4780 0.243194580078125 +4781 -0.22100830078125 +4782 0.2119140625 +4783 -0.42449951171875 +4784 0.1781005859375 +4785 -0.579833984375 +4786 0.159820556640625 +4787 -0.641876220703125 +4788 0.154266357421875 +4789 -0.6177978515625 +4790 0.134185791015625 +4791 -0.575531005859375 +4792 0.097503662109375 +4793 -0.526336669921875 +4794 0.06646728515625 +4795 -0.42645263671875 +4796 0.053009033203125 +4797 -0.2581787109375 +4798 0.0421142578125 +4799 -0.068695068359375 +4800 0.017852783203125 +4801 0.09222412109375 +4802 -0.011474609375 +4803 0.232147216796875 +4804 -0.041168212890625 +4805 0.3509521484375 +4806 -0.08349609375 +4807 0.410064697265625 +4808 -0.150604248046875 +4809 0.372955322265625 +4810 -0.23345947265625 +4811 0.2554931640625 +4812 -0.309814453125 +4813 0.10711669921875 +4814 -0.371337890625 +4815 -0.052886962890625 +4816 -0.4027099609375 +4817 -0.186279296875 +4818 -0.380340576171875 +4819 -0.23291015625 +4820 -0.3140869140625 +4821 -0.209442138671875 +4822 -0.232147216796875 +4823 -0.174163818359375 +4824 -0.138336181640625 +4825 -0.126739501953125 +4826 -0.02880859375 +4827 -0.048126220703125 +4828 0.084136962890625 +4829 0.0426025390625 +4830 0.180389404296875 +4831 0.10748291015625 +4832 0.2540283203125 +4833 0.1409912109375 +4834 0.32489013671875 +4835 0.19708251953125 +4836 0.389923095703125 +4837 0.273651123046875 +4838 0.42529296875 +4839 0.31768798828125 +4840 0.43560791015625 +4841 0.341094970703125 +4842 0.4315185546875 +4843 0.368011474609375 +4844 0.403350830078125 +4845 0.37249755859375 +4846 0.330322265625 +4847 0.30072021484375 +4848 0.2147216796875 +4849 0.1517333984375 +4850 0.08502197265625 +4851 -0.01470947265625 +4852 -0.05096435546875 +4853 -0.1883544921875 +4854 -0.191253662109375 +4855 -0.372711181640625 +4856 -0.309661865234375 +4857 -0.51397705078125 +4858 -0.385986328125 +4859 -0.57177734375 +4860 -0.414794921875 +4861 -0.53948974609375 +4862 -0.40167236328125 +4863 -0.43511962890625 +4864 -0.3614501953125 +4865 -0.2962646484375 +4866 -0.309814453125 +4867 -0.161102294921875 +4868 -0.252593994140625 +4869 -0.0435791015625 +4870 -0.188812255859375 +4871 0.060394287109375 +4872 -0.125457763671875 +4873 0.13665771484375 +4874 -0.070465087890625 +4875 0.170135498046875 +4876 -0.02435302734375 +4877 0.16552734375 +4878 0.023895263671875 +4879 0.15728759765625 +4880 0.0736083984375 +4881 0.150787353515625 +4882 0.1123046875 +4883 0.12200927734375 +4884 0.1409912109375 +4885 0.080108642578125 +4886 0.16778564453125 +4887 0.05126953125 +4888 0.201751708984375 +4889 0.062896728515625 +4890 0.23260498046875 +4891 0.09271240234375 +4892 0.240509033203125 +4893 0.092987060546875 +4894 0.231292724609375 +4895 0.07855224609375 +4896 0.21136474609375 +4897 0.06427001953125 +4898 0.1756591796875 +4899 0.0347900390625 +4900 0.125 +4901 -0.01171875 +4902 0.069061279296875 +4903 -0.056060791015625 +4904 0.027191162109375 +4905 -0.055511474609375 +4906 0.001617431640625 +4907 -0.010467529296875 +4908 -0.02679443359375 +4909 0.02508544921875 +4910 -0.06591796875 +4911 0.025665283203125 +4912 -0.103302001953125 +4913 0.017333984375 +4914 -0.13653564453125 +4915 0.00189208984375 +4916 -0.16876220703125 +4917 -0.03173828125 +4918 -0.19439697265625 +4919 -0.071502685546875 +4920 -0.220367431640625 +4921 -0.13543701171875 +4922 -0.245513916015625 +4923 -0.219970703125 +4924 -0.26068115234375 +4925 -0.300506591796875 +4926 -0.266754150390625 +4927 -0.376312255859375 +4928 -0.252777099609375 +4929 -0.416107177734375 +4930 -0.2010498046875 +4931 -0.371124267578125 +4932 -0.113861083984375 +4933 -0.242279052734375 +4934 -0.00927734375 +4935 -0.069732666015625 +4936 0.102386474609375 +4937 0.125640869140625 +4938 0.206878662109375 +4939 0.31268310546875 +4940 0.288177490234375 +4941 0.45501708984375 +4942 0.345947265625 +4943 0.554779052734375 +4944 0.37890625 +4945 0.61065673828125 +4946 0.381988525390625 +4947 0.610931396484375 +4948 0.3455810546875 +4949 0.531463623046875 +4950 0.276580810546875 +4951 0.3883056640625 +4952 0.1971435546875 +4953 0.23468017578125 +4954 0.1182861328125 +4955 0.095245361328125 +4956 0.05181884765625 +4957 -0.00396728515625 +4958 0.00506591796875 +4959 -0.04852294921875 +4960 -0.027008056640625 +4961 -0.055145263671875 +4962 -0.063568115234375 +4963 -0.0758056640625 +4964 -0.1143798828125 +4965 -0.138702392578125 +4966 -0.164276123046875 +4967 -0.209197998046875 +4968 -0.212860107421875 +4969 -0.289031982421875 +4970 -0.259674072265625 +4971 -0.37884521484375 +4972 -0.295318603515625 +4973 -0.456329345703125 +4974 -0.31768798828125 +4975 -0.51641845703125 +4976 -0.3111572265625 +4977 -0.519287109375 +4978 -0.27362060546875 +4979 -0.458251953125 +4980 -0.2265625 +4981 -0.384796142578125 +4982 -0.18096923828125 +4983 -0.323699951171875 +4984 -0.13580322265625 +4985 -0.269287109375 +4986 -0.081878662109375 +4987 -0.1951904296875 +4988 -0.019989013671875 +4989 -0.100006103515625 +4990 0.037841796875 +4991 -0.01055908203125 +4992 0.1025390625 +4993 0.1033935546875 +4994 0.176055908203125 +4995 0.24908447265625 +4996 0.236328125 +4997 0.373199462890625 +4998 0.275848388671875 +4999 0.45806884765625 +5000 0.297576904296875 +5001 0.511474609375 +5002 0.314422607421875 +5003 0.565399169921875 +5004 0.32342529296875 +5005 0.61138916015625 +5006 0.30133056640625 +5007 0.5897216796875 +5008 0.24505615234375 +5009 0.4906005859375 +5010 0.16259765625 +5011 0.33148193359375 +5012 0.0692138671875 +5013 0.147796630859375 +5014 -0.01727294921875 +5015 -0.01873779296875 +5016 -0.084625244140625 +5017 -0.140289306640625 +5018 -0.121917724609375 +5019 -0.191986083984375 +5020 -0.13250732421875 +5021 -0.184295654296875 +5022 -0.133575439453125 +5023 -0.161834716796875 +5024 -0.141448974609375 +5025 -0.166595458984375 +5026 -0.154083251953125 +5027 -0.19390869140625 +5028 -0.163726806640625 +5029 -0.22442626953125 +5030 -0.179290771484375 +5031 -0.279754638671875 +5032 -0.192901611328125 +5033 -0.3389892578125 +5034 -0.1861572265625 +5035 -0.3543701171875 +5036 -0.168731689453125 +5037 -0.348175048828125 +5038 -0.143707275390625 +5039 -0.32598876953125 +5040 -0.100189208984375 +5041 -0.2581787109375 +5042 -0.037078857421875 +5043 -0.139801025390625 +5044 0.038970947265625 +5045 0.014617919921875 +5046 0.1029052734375 +5047 0.144378662109375 +5048 0.142822265625 +5049 0.221038818359375 +5050 0.168701171875 +5051 0.27069091796875 +5052 0.18060302734375 +5053 0.294036865234375 +5054 0.186737060546875 +5055 0.311767578125 +5056 0.193328857421875 +5057 0.339141845703125 +5058 0.194305419921875 +5059 0.360260009765625 +5060 0.184295654296875 +5061 0.360504150390625 +5062 0.151611328125 +5063 0.308380126953125 +5064 0.088348388671875 +5065 0.18170166015625 +5066 0.004852294921875 +5067 0.0047607421875 +5068 -0.0797119140625 +5069 -0.17559814453125 +5070 -0.146942138671875 +5071 -0.3143310546875 +5072 -0.179107666015625 +5073 -0.36785888671875 +5074 -0.185943603515625 +5075 -0.36248779296875 +5076 -0.184783935546875 +5077 -0.343536376953125 +5078 -0.17181396484375 +5079 -0.3018798828125 +5080 -0.144500732421875 +5081 -0.231414794921875 +5082 -0.097259521484375 +5083 -0.117645263671875 +5084 -0.042999267578125 +5085 0.007049560546875 +5086 -0.0035400390625 +5087 0.087982177734375 +5088 0.026214599609375 +5089 0.13946533203125 +5090 0.05072021484375 +5091 0.17425537109375 +5092 0.06768798828125 +5093 0.188201904296875 +5094 0.072540283203125 +5095 0.171234130859375 +5096 0.062744140625 +5097 0.118438720703125 +5098 0.04840087890625 +5099 0.05706787109375 +5100 0.02984619140625 +5101 -0.010711669921875 +5102 0.004119873046875 +5103 -0.0914306640625 +5104 -0.02008056640625 +5105 -0.162322998046875 +5106 -0.031585693359375 +5107 -0.194549560546875 +5108 -0.015167236328125 +5109 -0.1492919921875 +5110 0.031219482421875 +5111 -0.02166748046875 +5112 0.0826416015625 +5113 0.124053955078125 +5114 0.109375 +5115 0.211151123046875 +5116 0.112213134765625 +5117 0.240447998046875 +5118 0.103515625 +5119 0.242218017578125 +5120 0.086944580078125 +5121 0.2257080078125 +5122 0.06463623046875 +5123 0.194366455078125 +5124 0.025970458984375 +5125 0.115509033203125 +5126 -0.019927978515625 +5127 0.0128173828125 +5128 -0.05108642578125 +5129 -0.053802490234375 +5130 -0.076629638671875 +5131 -0.110626220703125 +5132 -0.111480712890625 +5133 -0.199493408203125 +5134 -0.146148681640625 +5135 -0.29437255859375 +5136 -0.15802001953125 +5137 -0.33221435546875 +5138 -0.13531494140625 +5139 -0.27972412109375 +5140 -0.095703125 +5141 -0.185333251953125 +5142 -0.06805419921875 +5143 -0.128204345703125 +5144 -0.055450439453125 +5145 -0.115692138671875 +5146 -0.047088623046875 +5147 -0.116455078125 +5148 -0.03460693359375 +5149 -0.105926513671875 +5150 -0.00762939453125 +5151 -0.053955078125 +5152 0.0367431640625 +5153 0.048797607421875 +5154 0.081939697265625 +5155 0.157318115234375 +5156 0.106201171875 +5157 0.212005615234375 +5158 0.111328125 +5159 0.218475341796875 +5160 0.1190185546875 +5161 0.23724365234375 +5162 0.142608642578125 +5163 0.30535888671875 +5164 0.167236328125 +5165 0.38128662109375 +5166 0.1712646484375 +5167 0.404449462890625 +5168 0.16204833984375 +5169 0.3944091796875 +5170 0.153411865234375 +5171 0.3885498046875 +5172 0.13702392578125 +5173 0.362640380859375 +5174 0.0977783203125 +5175 0.27362060546875 +5176 0.034515380859375 +5177 0.11712646484375 +5178 -0.03369140625 +5179 -0.054901123046875 +5180 -0.087921142578125 +5181 -0.19085693359375 +5182 -0.126129150390625 +5183 -0.28570556640625 +5184 -0.148101806640625 +5185 -0.339263916015625 +5186 -0.163055419921875 +5187 -0.3775634765625 +5188 -0.187225341796875 +5189 -0.445709228515625 +5190 -0.217559814453125 +5191 -0.535064697265625 +5192 -0.248260498046875 +5193 -0.629058837890625 +5194 -0.2686767578125 +5195 -0.697601318359375 +5196 -0.26580810546875 +5197 -0.70391845703125 +5198 -0.23797607421875 +5199 -0.6424560546875 +5200 -0.1776123046875 +5201 -0.491241455078125 +5202 -0.090606689453125 +5203 -0.265716552734375 +5204 0.00189208984375 +5205 -0.023712158203125 +5206 0.08770751953125 +5207 0.201751708984375 +5208 0.154052734375 +5209 0.375823974609375 +5210 0.1959228515625 +5211 0.485076904296875 +5212 0.227386474609375 +5213 0.56884765625 +5214 0.25115966796875 +5215 0.634765625 +5216 0.2509765625 +5217 0.63763427734375 +5218 0.22283935546875 +5219 0.5660400390625 +5220 0.185638427734375 +5221 0.4720458984375 +5222 0.158050537109375 +5223 0.40692138671875 +5224 0.1429443359375 +5225 0.3778076171875 +5226 0.137786865234375 +5227 0.376953125 +5228 0.13116455078125 +5229 0.371978759765625 +5230 0.10540771484375 +5231 0.313140869140625 +5232 0.055023193359375 +5233 0.184417724609375 +5234 -0.0106201171875 +5235 0.011199951171875 +5236 -0.078582763671875 +5237 -0.171051025390625 +5238 -0.139801025390625 +5239 -0.33740234375 +5240 -0.18853759765625 +5241 -0.47198486328125 +5242 -0.2196044921875 +5243 -0.560394287109375 +5244 -0.225128173828125 +5245 -0.58056640625 +5246 -0.210662841796875 +5247 -0.54754638671875 +5248 -0.193389892578125 +5249 -0.508575439453125 +5250 -0.1719970703125 +5251 -0.459503173828125 +5252 -0.144561767578125 +5253 -0.394378662109375 +5254 -0.125457763671875 +5255 -0.35260009765625 +5256 -0.106842041015625 +5257 -0.31170654296875 +5258 -0.06219482421875 +5259 -0.197418212890625 +5260 0.0089111328125 +5261 -0.007965087890625 +5262 0.088653564453125 +5263 0.207489013671875 +5264 0.16259765625 +5265 0.409210205078125 +5266 0.2216796875 +5267 0.57208251953125 +5268 0.25506591796875 +5269 0.66595458984375 +5270 0.251251220703125 +5271 0.65875244140625 +5272 0.2164306640625 +5273 0.56744384765625 +5274 0.164886474609375 +5275 0.431396484375 +5276 0.112579345703125 +5277 0.29443359375 +5278 0.069000244140625 +5279 0.182464599609375 +5280 0.02288818359375 +5281 0.06365966796875 +5282 -0.03057861328125 +5283 -0.075958251953125 +5284 -0.0743408203125 +5285 -0.189422607421875 +5286 -0.10650634765625 +5287 -0.271942138671875 +5288 -0.1337890625 +5289 -0.342529296875 +5290 -0.142822265625 +5291 -0.364166259765625 +5292 -0.130096435546875 +5293 -0.327239990234375 +5294 -0.111846923828125 +5295 -0.2769775390625 +5296 -0.1026611328125 +5297 -0.253692626953125 +5298 -0.097625732421875 +5299 -0.24365234375 +5300 -0.079376220703125 +5301 -0.1983642578125 +5302 -0.0474853515625 +5303 -0.116241455078125 +5304 -0.01629638671875 +5305 -0.036834716796875 +5306 0.01220703125 +5307 0.034881591796875 +5308 0.035125732421875 +5309 0.09124755859375 +5310 0.043914794921875 +5311 0.10888671875 +5312 0.052001953125 +5313 0.125518798828125 +5314 0.065277099609375 +5315 0.15771484375 +5316 0.0738525390625 +5317 0.17828369140625 +5318 0.071868896484375 +5319 0.17108154296875 +5320 0.057098388671875 +5321 0.129974365234375 +5322 0.039459228515625 +5323 0.082427978515625 +5324 0.018707275390625 +5325 0.027679443359375 +5326 -0.016357421875 +5327 -0.065643310546875 +5328 -0.0518798828125 +5329 -0.15936279296875 +5330 -0.0732421875 +5331 -0.21307373046875 +5332 -0.0831298828125 +5333 -0.234649658203125 +5334 -0.072845458984375 +5335 -0.2001953125 +5336 -0.045684814453125 +5337 -0.119171142578125 +5338 -0.013458251953125 +5339 -0.024749755859375 +5340 0.024871826171875 +5341 0.085784912109375 +5342 0.0570068359375 +5343 0.178131103515625 +5344 0.06976318359375 +5345 0.215576171875 +5346 0.0679931640625 +5347 0.211456298828125 +5348 0.05511474609375 +5349 0.17523193359375 +5350 0.038970947265625 +5351 0.128753662109375 +5352 0.030303955078125 +5353 0.1019287109375 +5354 0.021697998046875 +5355 0.0743408203125 +5356 0.012054443359375 +5357 0.04327392578125 +5358 0.01190185546875 +5359 0.038177490234375 +5360 0.027374267578125 +5361 0.076263427734375 +5362 0.052398681640625 +5363 0.14105224609375 +5364 0.070281982421875 +5365 0.186431884765625 +5366 0.07244873046875 +5367 0.188812255859375 +5368 0.055572509765625 +5369 0.1390380859375 +5370 0.02130126953125 +5371 0.041778564453125 +5372 -0.021942138671875 +5373 -0.079437255859375 +5374 -0.072296142578125 +5375 -0.219390869140625 +5376 -0.125701904296875 +5377 -0.367828369140625 +5378 -0.170928955078125 +5379 -0.494873046875 +5380 -0.192962646484375 +5381 -0.556243896484375 +5382 -0.1778564453125 +5383 -0.508697509765625 +5384 -0.133514404296875 +5385 -0.3756103515625 +5386 -0.080535888671875 +5387 -0.218902587890625 +5388 -0.027435302734375 +5389 -0.063751220703125 +5390 0.02606201171875 +5391 0.091552734375 +5392 0.07611083984375 +5393 0.23602294921875 +5394 0.113800048828125 +5395 0.342987060546875 +5396 0.13330078125 +5397 0.39520263671875 +5398 0.133392333984375 +5399 0.389373779296875 +5400 0.11358642578125 +5401 0.324249267578125 +5402 0.081787109375 +5403 0.224090576171875 +5404 0.049560546875 +5405 0.124267578125 +5406 0.02093505859375 +5407 0.037078857421875 +5408 0.0048828125 +5409 -0.010101318359375 +5410 0.000732421875 +5411 -0.019439697265625 +5412 -0.0018310546875 +5413 -0.022796630859375 +5414 0.003387451171875 +5415 -0.001556396484375 +5416 0.02044677734375 +5417 0.056304931640625 +5418 0.035003662109375 +5419 0.106719970703125 +5420 0.02984619140625 +5421 0.096893310546875 +5422 0.01031494140625 +5423 0.042694091796875 +5424 -0.011077880859375 +5425 -0.018035888671875 +5426 -0.031158447265625 +5427 -0.07586669921875 +5428 -0.046173095703125 +5429 -0.11944580078125 +5430 -0.0596923828125 +5431 -0.15972900390625 +5432 -0.073638916015625 +5433 -0.202606201171875 +5434 -0.088165283203125 +5435 -0.24859619140625 +5436 -0.10577392578125 +5437 -0.30517578125 +5438 -0.123199462890625 +5439 -0.36212158203125 +5440 -0.131317138671875 +5441 -0.39141845703125 +5442 -0.117828369140625 +5443 -0.35528564453125 +5444 -0.08160400390625 +5445 -0.249969482421875 +5446 -0.028472900390625 +5447 -0.092864990234375 +5448 0.032623291015625 +5449 0.08905029296875 +5450 0.081756591796875 +5451 0.2352294921875 +5452 0.110076904296875 +5453 0.318817138671875 +5454 0.12371826171875 +5455 0.358642578125 +5456 0.120391845703125 +5457 0.347747802734375 +5458 0.09991455078125 +5459 0.28564453125 +5460 0.0789794921875 +5461 0.223175048828125 +5462 0.069549560546875 +5463 0.196746826171875 +5464 0.06298828125 +5465 0.179840087890625 +5466 0.053802490234375 +5467 0.155548095703125 +5468 0.051055908203125 +5469 0.151214599609375 +5470 0.05157470703125 +5471 0.156951904296875 +5472 0.041961669921875 +5473 0.13177490234375 +5474 0.030548095703125 +5475 0.100799560546875 +5476 0.02496337890625 +5477 0.087127685546875 +5478 0.013519287109375 +5479 0.05487060546875 +5480 -0.00799560546875 +5481 -0.009002685546875 +5482 -0.039398193359375 +5483 -0.10400390625 +5484 -0.0804443359375 +5485 -0.229400634765625 +5486 -0.121429443359375 +5487 -0.35552978515625 +5488 -0.14910888671875 +5489 -0.441925048828125 +5490 -0.15869140625 +5491 -0.473846435546875 +5492 -0.1546630859375 +5493 -0.464813232421875 +5494 -0.13848876953125 +5495 -0.419097900390625 +5496 -0.109466552734375 +5497 -0.334320068359375 +5498 -0.0733642578125 +5499 -0.227935791015625 +5500 -0.0379638671875 +5501 -0.12347412109375 +5502 -0.00555419921875 +5503 -0.02764892578125 +5504 0.029754638671875 +5505 0.077667236328125 +5506 0.074737548828125 +5507 0.2132568359375 +5508 0.132568359375 +5509 0.38885498046875 +5510 0.196136474609375 +5511 0.582794189453125 +5512 0.24542236328125 +5513 0.734039306640625 +5514 0.266510009765625 +5515 0.800140380859375 +5516 0.258544921875 +5517 0.7783203125 +5518 0.220458984375 +5519 0.6651611328125 +5520 0.1519775390625 +5521 0.45965576171875 +5522 0.0654296875 +5523 0.199188232421875 +5524 -0.017608642578125 +5525 -0.050689697265625 +5526 -0.078338623046875 +5527 -0.23297119140625 +5528 -0.11102294921875 +5529 -0.33013916015625 +5530 -0.12420654296875 +5531 -0.368408203125 +5532 -0.1280517578125 +5533 -0.378936767578125 +5534 -0.127593994140625 +5535 -0.376983642578125 +5536 -0.128448486328125 +5537 -0.37969970703125 +5538 -0.132080078125 +5539 -0.391510009765625 +5540 -0.129608154296875 +5541 -0.385345458984375 +5542 -0.11474609375 +5543 -0.3419189453125 +5544 -0.094635009765625 +5545 -0.28289794921875 +5546 -0.08349609375 +5547 -0.251617431640625 +5548 -0.087310791015625 +5549 -0.266143798828125 +5550 -0.0887451171875 +5551 -0.273345947265625 +5552 -0.069305419921875 +5553 -0.216796875 +5554 -0.039459228515625 +5555 -0.128265380859375 +5556 -0.01904296875 +5557 -0.068145751953125 +5558 -0.01031494140625 +5559 -0.0430908203125 +5560 -0.003875732421875 +5561 -0.024444580078125 +5562 0.01104736328125 +5563 0.020721435546875 +5564 0.044921875 +5565 0.124481201171875 +5566 0.088287353515625 +5567 0.25787353515625 +5568 0.127471923828125 +5569 0.379119873046875 +5570 0.1597900390625 +5571 0.47991943359375 +5572 0.174774169921875 +5573 0.5281982421875 +5574 0.16827392578125 +5575 0.511138916015625 +5576 0.14935302734375 +5577 0.456207275390625 +5578 0.13250732421875 +5579 0.407470703125 +5580 0.12396240234375 +5581 0.383758544921875 +5582 0.114471435546875 +5583 0.35687255859375 +5584 0.099151611328125 +5585 0.31182861328125 +5586 0.078765869140625 +5587 0.250885009765625 +5588 0.050506591796875 +5589 0.1654052734375 +5590 0.0078125 +5591 0.035247802734375 +5592 -0.05010986328125 +5593 -0.142059326171875 +5594 -0.1131591796875 +5595 -0.33563232421875 +5596 -0.17779541015625 +5597 -0.5345458984375 +5598 -0.23846435546875 +5599 -0.72186279296875 +5600 -0.275238037109375 +5601 -0.836669921875 +5602 -0.272979736328125 +5603 -0.8326416015625 +5604 -0.238250732421875 +5605 -0.7296142578125 +5606 -0.18914794921875 +5607 -0.582550048828125 +5608 -0.14166259765625 +5609 -0.440093994140625 +5610 -0.10308837890625 +5611 -0.324310302734375 +5612 -0.0623779296875 +5613 -0.20147705078125 +5614 -0.01068115234375 +5615 -0.044647216796875 +5616 0.038116455078125 +5617 0.103973388671875 +5618 0.070220947265625 +5619 0.202392578125 +5620 0.090179443359375 +5621 0.264495849609375 +5622 0.113983154296875 +5623 0.338897705078125 +5624 0.14764404296875 +5625 0.443817138671875 +5626 0.17999267578125 +5627 0.545074462890625 +5628 0.202789306640625 +5629 0.6173095703125 +5630 0.21343994140625 +5631 0.6524658203125 +5632 0.2158203125 +5633 0.66339111328125 +5634 0.211822509765625 +5635 0.6561279296875 +5636 0.194244384765625 +5637 0.606781005859375 +5638 0.15911865234375 +5639 0.501190185546875 +5640 0.11065673828125 +5641 0.352783203125 +5642 0.053619384765625 +5643 0.176544189453125 +5644 -0.013824462890625 +5645 -0.034820556640625 +5646 -0.08453369140625 +5647 -0.258209228515625 +5648 -0.14312744140625 +5649 -0.44244384765625 +5650 -0.18572998046875 +5651 -0.5753173828125 +5652 -0.210784912109375 +5653 -0.65203857421875 +5654 -0.209014892578125 +5655 -0.641632080078125 +5656 -0.18572998046875 +5657 -0.562164306640625 +5658 -0.154083251953125 +5659 -0.458038330078125 +5660 -0.12042236328125 +5661 -0.350555419921875 +5662 -0.091064453125 +5663 -0.260528564453125 +5664 -0.067413330078125 +5665 -0.192108154296875 +5666 -0.04864501953125 +5667 -0.141937255859375 +5668 -0.03265380859375 +5669 -0.1021728515625 +5670 -0.016754150390625 +5671 -0.062896728515625 +5672 0.00238037109375 +5673 -0.011932373046875 +5674 0.02813720703125 +5675 0.062835693359375 +5676 0.05657958984375 +5677 0.148712158203125 +5678 0.086334228515625 +5679 0.241729736328125 +5680 0.119476318359375 +5681 0.34912109375 +5682 0.151947021484375 +5683 0.457305908203125 +5684 0.177093505859375 +5685 0.54388427734375 +5686 0.184326171875 +5687 0.5728759765625 +5688 0.16259765625 +5689 0.506591796875 +5690 0.1138916015625 +5691 0.351226806640625 +5692 0.05010986328125 +5693 0.146514892578125 +5694 -0.013031005859375 +5695 -0.05523681640625 +5696 -0.064178466796875 +5697 -0.21624755859375 +5698 -0.102630615234375 +5699 -0.334930419921875 +5700 -0.12579345703125 +5701 -0.402984619140625 +5702 -0.1396484375 +5703 -0.4412841796875 +5704 -0.15771484375 +5705 -0.49578857421875 +5706 -0.17803955078125 +5707 -0.5601806640625 +5708 -0.190582275390625 +5709 -0.600738525390625 +5710 -0.18548583984375 +5711 -0.584228515625 +5712 -0.15350341796875 +5713 -0.47930908203125 +5714 -0.0927734375 +5715 -0.27935791015625 +5716 -0.010650634765625 +5717 -0.0089111328125 +5718 0.073974609375 +5719 0.268798828125 +5720 0.139984130859375 +5721 0.482818603515625 +5722 0.178497314453125 +5723 0.60369873046875 +5724 0.194976806640625 +5725 0.650421142578125 +5726 0.201416015625 +5727 0.66400146484375 +5728 0.19683837890625 +5729 0.6414794921875 +5730 0.178070068359375 +5731 0.572540283203125 +5732 0.15716552734375 +5733 0.498138427734375 +5734 0.140380859375 +5735 0.439453125 +5736 0.1214599609375 +5737 0.375518798828125 +5738 0.09100341796875 +5739 0.274505615234375 +5740 0.0408935546875 +5741 0.1087646484375 +5742 -0.022186279296875 +5743 -0.099395751953125 +5744 -0.0887451171875 +5745 -0.3182373046875 +5746 -0.1590576171875 +5747 -0.5489501953125 +5748 -0.22772216796875 +5749 -0.7738037109375 +5750 -0.2789306640625 +5751 -0.86383056640625 +5752 -0.302764892578125 +5753 -0.870391845703125 +5754 -0.304351806640625 +5755 -0.86895751953125 +5756 -0.287506103515625 +5757 -0.861053466796875 +5758 -0.247039794921875 +5759 -0.765869140625 +5760 -0.179595947265625 +5761 -0.5301513671875 +5762 -0.087249755859375 +5763 -0.214691162109375 +5764 0.017242431640625 +5765 0.137359619140625 +5766 0.118682861328125 +5767 0.474822998046875 +5768 0.206512451171875 +5769 0.76239013671875 +5770 0.27264404296875 +5771 0.867462158203125 +5772 0.317138671875 +5773 0.870361328125 +5774 0.33648681640625 +5775 0.86480712890625 +5776 0.3321533203125 +5777 0.831817626953125 +5778 0.311279296875 +5779 0.677581787109375 +5780 0.2755126953125 +5781 0.495880126953125 +5782 0.23028564453125 +5783 0.30767822265625 +5784 0.17620849609375 +5785 0.116180419921875 +5786 0.103851318359375 +5787 -0.110748291015625 +5788 0.0111083984375 +5789 -0.381805419921875 +5790 -0.08929443359375 +5791 -0.6572265625 +5792 -0.179595947265625 +5793 -0.857421875 +5794 -0.247100830078125 +5795 -0.870391845703125 +5796 -0.289642333984375 +5797 -0.870391845703125 +5798 -0.315155029296875 +5799 -0.86444091796875 +5800 -0.3341064453125 +5801 -0.85723876953125 +5802 -0.34100341796875 +5803 -0.790008544921875 +5804 -0.3197021484375 +5805 -0.62847900390625 +5806 -0.26922607421875 +5807 -0.3956298828125 +5808 -0.199249267578125 +5809 -0.126708984375 +5810 -0.1177978515625 +5811 0.150115966796875 +5812 -0.0283203125 +5813 0.424041748046875 +5814 0.061187744140625 +5815 0.670623779296875 +5816 0.1392822265625 +5817 0.854522705078125 +5818 0.200714111328125 +5819 0.866485595703125 +5820 0.240936279296875 +5821 0.86920166015625 +5822 0.2652587890625 +5823 0.8653564453125 +5824 0.277618408203125 +5825 0.857147216796875 +5826 0.277099609375 +5827 0.766845703125 +5828 0.265167236328125 +5829 0.628509521484375 +5830 0.239776611328125 +5831 0.462127685546875 +5832 0.208526611328125 +5833 0.297210693359375 +5834 0.175018310546875 +5835 0.14862060546875 +5836 0.1324462890625 +5837 -0.00537109375 +5838 0.0830078125 +5839 -0.15753173828125 +5840 0.025634765625 +5841 -0.31304931640625 +5842 -0.0438232421875 +5843 -0.48876953125 +5844 -0.111480712890625 +5845 -0.6416015625 +5846 -0.16998291015625 +5847 -0.751373291015625 +5848 -0.22613525390625 +5849 -0.84619140625 +5850 -0.275543212890625 +5851 -0.861297607421875 +5852 -0.308380126953125 +5853 -0.863250732421875 +5854 -0.31524658203125 +5855 -0.856597900390625 +5856 -0.2996826171875 +5857 -0.7498779296875 +5858 -0.278778076171875 +5859 -0.624542236328125 +5860 -0.246002197265625 +5861 -0.47808837890625 +5862 -0.184051513671875 +5863 -0.253387451171875 +5864 -0.106414794921875 +5865 0.003692626953125 +5866 -0.0333251953125 +5867 0.2257080078125 +5868 0.038909912109375 +5869 0.427154541015625 +5870 0.119873046875 +5871 0.643218994140625 +5872 0.206695556640625 +5873 0.855926513671875 +5874 0.282196044921875 +5875 0.870361328125 +5876 0.3316650390625 +5877 0.870361328125 +5878 0.357208251953125 +5879 0.862762451171875 +5880 0.35791015625 +5881 0.79669189453125 +5882 0.330963134765625 +5883 0.595794677734375 +5884 0.28497314453125 +5885 0.362152099609375 +5886 0.22821044921875 +5887 0.1270751953125 +5888 0.166351318359375 +5889 -0.086944580078125 +5890 0.0997314453125 +5891 -0.2784423828125 +5892 0.01947021484375 +5893 -0.484832763671875 +5894 -0.078582763671875 +5895 -0.729583740234375 +5896 -0.1802978515625 +5897 -0.86688232421875 +5898 -0.268310546875 +5899 -0.870391845703125 +5900 -0.3408203125 +5901 -0.86859130859375 +5902 -0.3968505859375 +5903 -0.86279296875 +5904 -0.426727294921875 +5905 -0.817962646484375 +5906 -0.418426513671875 +5907 -0.6116943359375 +5908 -0.37017822265625 +5909 -0.3128662109375 +5910 -0.291107177734375 +5911 0.039398193359375 +5912 -0.186798095703125 +5913 0.422821044921875 +5914 -0.066497802734375 +5915 0.805145263671875 +5916 0.051300048828125 +5917 0.870361328125 +5918 0.15106201171875 +5919 0.870361328125 +5920 0.2291259765625 +5921 0.860015869140625 +5922 0.282958984375 +5923 0.727935791015625 +5924 0.310638427734375 +5925 0.48114013671875 +5926 0.318145751953125 +5927 0.2059326171875 +5928 0.3111572265625 +5929 -0.06103515625 +5930 0.292083740234375 +5931 -0.29913330078125 +5932 0.257049560546875 +5933 -0.516204833984375 +5934 0.202056884765625 +5935 -0.7252197265625 +5936 0.13385009765625 +5937 -0.85980224609375 +5938 0.061798095703125 +5939 -0.870391845703125 +5940 -0.005889892578125 +5941 -0.870391845703125 +5942 -0.055877685546875 +5943 -0.858062744140625 +5944 -0.0865478515625 +5945 -0.673004150390625 +5946 -0.111236572265625 +5947 -0.42694091796875 +5948 -0.141143798828125 +5949 -0.2100830078125 +5950 -0.17523193359375 +5951 -0.0362548828125 +5952 -0.205413818359375 +5953 0.10943603515625 +5954 -0.226043701171875 +5955 0.23516845703125 +5956 -0.225982666015625 +5957 0.373687744140625 +5958 -0.2056884765625 +5959 0.517791748046875 +5960 -0.181793212890625 +5961 0.602783203125 +5962 -0.153076171875 +5963 0.635711669921875 +5964 -0.1109619140625 +5965 0.655181884765625 +5966 -0.05841064453125 +5967 0.65948486328125 +5968 0.00201416015625 +5969 0.651275634765625 +5970 0.06341552734375 +5971 0.61846923828125 +5972 0.115509033203125 +5973 0.53753662109375 +5974 0.153076171875 +5975 0.404144287109375 +5976 0.173095703125 +5977 0.22186279296875 +5978 0.175537109375 +5979 0.003997802734375 +5980 0.16485595703125 +5981 -0.22100830078125 +5982 0.14630126953125 +5983 -0.42449951171875 +5984 0.125335693359375 +5985 -0.579833984375 +5986 0.113250732421875 +5987 -0.641876220703125 +5988 0.108367919921875 +5989 -0.6177978515625 +5990 0.09381103515625 +5991 -0.575531005859375 +5992 0.06842041015625 +5993 -0.526336669921875 +5994 0.04620361328125 +5995 -0.42645263671875 +5996 0.03472900390625 +5997 -0.2581787109375 +5998 0.02484130859375 +5999 -0.068695068359375 +6000 0.006805419921875 +6001 0.09222412109375 +6002 -0.0140380859375 +6003 0.232147216796875 +6004 -0.034637451171875 +6005 0.3509521484375 +6006 -0.062530517578125 +6007 0.410064697265625 +6008 -0.105224609375 +6009 0.372955322265625 +6010 -0.157073974609375 +6011 0.2554931640625 +6012 -0.2042236328125 +6013 0.10711669921875 +6014 -0.241485595703125 +6015 -0.052886962890625 +6016 -0.2593994140625 +6017 -0.186279296875 +6018 -0.243438720703125 +6019 -0.23291015625 +6020 -0.1998291015625 +6021 -0.209442138671875 +6022 -0.146270751953125 +6023 -0.174163818359375 +6024 -0.085296630859375 +6025 -0.126739501953125 +6026 -0.014617919921875 +6027 -0.048126220703125 +6028 0.05792236328125 +6029 0.0426025390625 +6030 0.11968994140625 +6031 0.10748291015625 +6032 0.166900634765625 +6033 0.1409912109375 +6034 0.211883544921875 +6035 0.19708251953125 +6036 0.252685546875 +6037 0.273651123046875 +6038 0.27447509765625 +6039 0.31768798828125 +6040 0.2801513671875 +6041 0.341094970703125 +6042 0.27642822265625 +6043 0.368011474609375 +6044 0.25732421875 +6045 0.37249755859375 +6046 0.209991455078125 +6047 0.30072021484375 +6048 0.135955810546875 +6049 0.1517333984375 +6050 0.053070068359375 +6051 -0.01470947265625 +6052 -0.03369140625 +6053 -0.1883544921875 +6054 -0.122955322265625 +6055 -0.372711181640625 +6056 -0.198333740234375 +6057 -0.51397705078125 +6058 -0.24713134765625 +6059 -0.57177734375 +6060 -0.26593017578125 +6061 -0.53948974609375 +6062 -0.258148193359375 +6063 -0.43511962890625 +6064 -0.232879638671875 +6065 -0.2962646484375 +6066 -0.199798583984375 +6067 -0.161102294921875 +6068 -0.162689208984375 +6069 -0.0435791015625 +6070 -0.121063232421875 +6071 0.060394287109375 +6072 -0.079681396484375 +6073 0.13665771484375 +6074 -0.04388427734375 +6075 0.170135498046875 +6076 -0.0140380859375 +6077 0.16552734375 +6078 0.017120361328125 +6079 0.15728759765625 +6080 0.049102783203125 +6081 0.150787353515625 +6082 0.07373046875 +6083 0.12200927734375 +6084 0.091705322265625 +6085 0.080108642578125 +6086 0.108428955078125 +6087 0.05126953125 +6088 0.129974365234375 +6089 0.062896728515625 +6090 0.14959716796875 +6091 0.09271240234375 +6092 0.154266357421875 +6093 0.092987060546875 +6094 0.1478271484375 +6095 0.07855224609375 +6096 0.13458251953125 +6097 0.06427001953125 +6098 0.111175537109375 +6099 0.0347900390625 +6100 0.078125 +6101 -0.01171875 +6102 0.041839599609375 +6103 -0.056060791015625 +6104 0.0150146484375 +6105 -0.055511474609375 +6106 -0.000885009765625 +6107 -0.010467529296875 +6108 -0.0185546875 +6109 0.02508544921875 +6110 -0.04327392578125 +6111 0.025665283203125 +6112 -0.066864013671875 +6113 0.017333984375 +6114 -0.087799072265625 +6115 0.00189208984375 +6116 -0.10821533203125 +6117 -0.03173828125 +6118 -0.12445068359375 +6119 -0.071502685546875 +6120 -0.14111328125 +6121 -0.13543701171875 +6122 -0.157470703125 +6123 -0.219970703125 +6124 -0.16748046875 +6125 -0.300506591796875 +6126 -0.171722412109375 +6127 -0.376312255859375 +6128 -0.1629638671875 +6129 -0.416107177734375 +6130 -0.12945556640625 +6131 -0.371124267578125 +6132 -0.072662353515625 +6133 -0.242279052734375 +6134 -0.004486083984375 +6135 -0.069732666015625 +6136 0.06829833984375 +6137 0.125640869140625 +6138 0.136322021484375 +6139 0.31268310546875 +6140 0.189056396484375 +6141 0.45501708984375 +6142 0.226348876953125 +6143 0.554779052734375 +6144 0.247161865234375 +6145 0.61065673828125 +6146 0.24835205078125 +6147 0.610931396484375 +6148 0.224212646484375 +6149 0.531463623046875 +6150 0.179229736328125 +6151 0.3883056640625 +6152 0.12738037109375 +6153 0.23468017578125 +6154 0.07574462890625 +6155 0.095245361328125 +6156 0.0318603515625 +6157 -0.00396728515625 +6158 0.000396728515625 +6159 -0.04852294921875 +6160 -0.021636962890625 +6161 -0.055145263671875 +6162 -0.046112060546875 +6163 -0.0758056640625 +6164 -0.079071044921875 +6165 -0.138702392578125 +6166 -0.1109619140625 +6167 -0.209197998046875 +6168 -0.14154052734375 +6169 -0.289031982421875 +6170 -0.170501708984375 +6171 -0.37884521484375 +6172 -0.1920166015625 +6173 -0.456329345703125 +6174 -0.204864501953125 +6175 -0.51641845703125 +6176 -0.199310302734375 +6177 -0.519287109375 +6178 -0.174163818359375 +6179 -0.458251953125 +6180 -0.142913818359375 +6181 -0.384796142578125 +6182 -0.112548828125 +6183 -0.323699951171875 +6184 -0.082489013671875 +6185 -0.269287109375 +6186 -0.047149658203125 +6187 -0.1951904296875 +6188 -0.007080078125 +6189 -0.100006103515625 +6190 0.030120849609375 +6191 -0.01055908203125 +6192 0.07122802734375 +6193 0.1033935546875 +6194 0.117431640625 +6195 0.24908447265625 +6196 0.15496826171875 +6197 0.373199462890625 +6198 0.17913818359375 +6199 0.45806884765625 +6200 0.191802978515625 +6201 0.511474609375 +6202 0.20111083984375 +6203 0.565399169921875 +6204 0.205291748046875 +6205 0.61138916015625 +6206 0.189910888671875 +6207 0.5897216796875 +6208 0.153106689453125 +6209 0.4906005859375 +6210 0.100006103515625 +6211 0.33148193359375 +6212 0.04022216796875 +6213 0.147796630859375 +6214 -0.015045166015625 +6215 -0.01873779296875 +6216 -0.058074951171875 +6217 -0.140289306640625 +6218 -0.082000732421875 +6219 -0.191986083984375 +6220 -0.088897705078125 +6221 -0.184295654296875 +6222 -0.089508056640625 +6223 -0.161834716796875 +6224 -0.094024658203125 +6225 -0.166595458984375 +6226 -0.1011962890625 +6227 -0.19390869140625 +6228 -0.10626220703125 +6229 -0.22442626953125 +6230 -0.114837646484375 +6231 -0.279754638671875 +6232 -0.1220703125 +6233 -0.3389892578125 +6234 -0.11651611328125 +6235 -0.3543701171875 +6236 -0.10430908203125 +6237 -0.348175048828125 +6238 -0.087432861328125 +6239 -0.32598876953125 +6240 -0.059112548828125 +6241 -0.2581787109375 +6242 -0.01873779296875 +6243 -0.139801025390625 +6244 0.029449462890625 +6245 0.014617919921875 +6246 0.069793701171875 +6247 0.144378662109375 +6248 0.09478759765625 +6249 0.221038818359375 +6250 0.110687255859375 +6251 0.27069091796875 +6252 0.117584228515625 +6253 0.294036865234375 +6254 0.12066650390625 +6255 0.311767578125 +6256 0.123809814453125 +6257 0.339141845703125 +6258 0.123077392578125 +6259 0.360260009765625 +6260 0.115264892578125 +6261 0.360504150390625 +6262 0.093658447265625 +6263 0.308380126953125 +6264 0.0537109375 +6265 0.18170166015625 +6266 0.001739501953125 +6267 0.0047607421875 +6268 -0.05072021484375 +6269 -0.17559814453125 +6270 -0.0926513671875 +6271 -0.3143310546875 +6272 -0.113433837890625 +6273 -0.36785888671875 +6274 -0.118743896484375 +6275 -0.36248779296875 +6276 -0.1187744140625 +6277 -0.343536376953125 +6278 -0.111236572265625 +6279 -0.3018798828125 +6280 -0.09466552734375 +6281 -0.231414794921875 +6282 -0.0657958984375 +6283 -0.117645263671875 +6284 -0.032318115234375 +6285 0.007049560546875 +6286 -0.007232666015625 +6287 0.087982177734375 +6288 0.012359619140625 +6289 0.13946533203125 +6290 0.028961181640625 +6291 0.17425537109375 +6292 0.041107177734375 +6293 0.188201904296875 +6294 0.04595947265625 +6295 0.171234130859375 +6296 0.041900634765625 +6297 0.118438720703125 +6298 0.034881591796875 +6299 0.05706787109375 +6300 0.02496337890625 +6301 -0.010711669921875 +6302 0.0103759765625 +6303 -0.0914306640625 +6304 -0.00372314453125 +6305 -0.162322998046875 +6306 -0.0107421875 +6307 -0.194549560546875 +6308 -0.001678466796875 +6309 -0.1492919921875 +6310 0.02471923828125 +6311 -0.02166748046875 +6312 0.053802490234375 +6313 0.124053955078125 +6314 0.068023681640625 +6315 0.211151123046875 +6316 0.067962646484375 +6317 0.240447998046875 +6318 0.061065673828125 +6319 0.242218017578125 +6320 0.049896240234375 +6321 0.2257080078125 +6322 0.035614013671875 +6323 0.194366455078125 +6324 0.011016845703125 +6325 0.115509033203125 +6326 -0.01800537109375 +6327 0.0128173828125 +6328 -0.037322998046875 +6329 -0.053802490234375 +6330 -0.0528564453125 +6331 -0.110626220703125 +6332 -0.074249267578125 +6333 -0.199493408203125 +6334 -0.095458984375 +6335 -0.29437255859375 +6336 -0.101959228515625 +6337 -0.33221435546875 +6338 -0.086181640625 +6339 -0.27972412109375 +6340 -0.059600830078125 +6341 -0.185333251953125 +6342 -0.0408935546875 +6343 -0.128204345703125 +6344 -0.032073974609375 +6345 -0.115692138671875 +6346 -0.02618408203125 +6347 -0.116455078125 +6348 -0.01788330078125 +6349 -0.105926513671875 +6350 -0.00048828125 +6351 -0.053955078125 +6352 0.02789306640625 +6353 0.048797607421875 +6354 0.05657958984375 +6355 0.157318115234375 +6356 0.071563720703125 +6357 0.212005615234375 +6358 0.074066162109375 +6359 0.218475341796875 +6360 0.078125 +6361 0.23724365234375 +6362 0.092376708984375 +6363 0.30535888671875 +6364 0.1072998046875 +6365 0.38128662109375 +6366 0.1090087890625 +6367 0.404449462890625 +6368 0.102294921875 +6369 0.3944091796875 +6370 0.0960693359375 +6371 0.3885498046875 +6372 0.08502197265625 +6373 0.362640380859375 +6374 0.0594482421875 +6375 0.27362060546875 +6376 0.018585205078125 +6377 0.11712646484375 +6378 -0.0252685546875 +6379 -0.054901123046875 +6380 -0.0599365234375 +6381 -0.19085693359375 +6382 -0.084075927734375 +6383 -0.28570556640625 +6384 -0.097564697265625 +6385 -0.339263916015625 +6386 -0.106414794921875 +6387 -0.3775634765625 +6388 -0.121124267578125 +6389 -0.445709228515625 +6390 -0.139801025390625 +6391 -0.535064697265625 +6392 -0.15875244140625 +6393 -0.629058837890625 +6394 -0.171142578125 +6395 -0.697601318359375 +6396 -0.168670654296875 +6397 -0.70391845703125 +6398 -0.150238037109375 +6399 -0.6424560546875 +6400 -0.111480712890625 +6401 -0.491241455078125 +6402 -0.056365966796875 +6403 -0.265716552734375 +6404 0.002227783203125 +6405 -0.023712158203125 +6406 0.056976318359375 +6407 0.201751708984375 +6408 0.10028076171875 +6409 0.375823974609375 +6410 0.12896728515625 +6411 0.485076904296875 +6412 0.1505126953125 +6413 0.56884765625 +6414 0.166229248046875 +6415 0.634765625 +6416 0.1669921875 +6417 0.63763427734375 +6418 0.150604248046875 +6419 0.5660400390625 +6420 0.127655029296875 +6421 0.4720458984375 +6422 0.10870361328125 +6423 0.40692138671875 +6424 0.095550537109375 +6425 0.3778076171875 +6426 0.087127685546875 +6427 0.376953125 +6428 0.077423095703125 +6429 0.371978759765625 +6430 0.056976318359375 +6431 0.313140869140625 +6432 0.023101806640625 +6433 0.184417724609375 +6434 -0.0186767578125 +6435 0.011199951171875 +6436 -0.060882568359375 +6437 -0.171051025390625 +6438 -0.098236083984375 +6439 -0.33740234375 +6440 -0.127410888671875 +6441 -0.47198486328125 +6442 -0.14544677734375 +6443 -0.560394287109375 +6444 -0.147979736328125 +6445 -0.58056640625 +6446 -0.13812255859375 +6447 -0.54754638671875 +6448 -0.1256103515625 +6449 -0.508575439453125 +6450 -0.109893798828125 +6451 -0.459503173828125 +6452 -0.090118408203125 +6453 -0.394378662109375 +6454 -0.074554443359375 +6455 -0.35260009765625 +6456 -0.059112548828125 +6457 -0.31170654296875 +6458 -0.02935791015625 +6459 -0.197418212890625 +6460 0.014678955078125 +6461 -0.007965087890625 +6462 0.06280517578125 +6463 0.207489013671875 +6464 0.10687255859375 +6465 0.409210205078125 +6466 0.141693115234375 +6467 0.57208251953125 +6468 0.161163330078125 +6469 0.66595458984375 +6470 0.158843994140625 +6471 0.65875244140625 +6472 0.138275146484375 +6473 0.56744384765625 +6474 0.107452392578125 +6475 0.431396484375 +6476 0.075408935546875 +6477 0.29443359375 +6478 0.047607421875 +6479 0.182464599609375 +6480 0.01800537109375 +6481 0.06365966796875 +6482 -0.015838623046875 +6483 -0.075958251953125 +6484 -0.044219970703125 +6485 -0.189422607421875 +6486 -0.06585693359375 +6487 -0.271942138671875 +6488 -0.08428955078125 +6489 -0.342529296875 +6490 -0.091949462890625 +6491 -0.364166259765625 +6492 -0.086761474609375 +6493 -0.327239990234375 +6494 -0.077667236328125 +6495 -0.2769775390625 +6496 -0.072723388671875 +6497 -0.253692626953125 +6498 -0.0692138671875 +6499 -0.24365234375 +6500 -0.05755615234375 +6501 -0.1983642578125 +6502 -0.03759765625 +6503 -0.116241455078125 +6504 -0.0174560546875 +6505 -0.036834716796875 +6506 0.0015869140625 +6507 0.034881591796875 +6508 0.0177001953125 +6509 0.09124755859375 +6510 0.025970458984375 +6511 0.10888671875 +6512 0.03369140625 +6513 0.125518798828125 +6514 0.043914794921875 +6515 0.15771484375 +6516 0.051025390625 +6517 0.17828369140625 +6518 0.0516357421875 +6519 0.17108154296875 +6520 0.044464111328125 +6521 0.129974365234375 +6522 0.034942626953125 +6523 0.082427978515625 +6524 0.022979736328125 +6525 0.027679443359375 +6526 0.00238037109375 +6527 -0.065643310546875 +6528 -0.01904296875 +6529 -0.15936279296875 +6530 -0.033050537109375 +6531 -0.21307373046875 +6532 -0.041046142578125 +6533 -0.234649658203125 +6534 -0.03802490234375 +6535 -0.2001953125 +6536 -0.025665283203125 +6537 -0.119171142578125 +6538 -0.010406494140625 +6539 -0.024749755859375 +6540 0.008453369140625 +6541 0.085784912109375 +6542 0.024200439453125 +6543 0.178131103515625 +6544 0.0296630859375 +6545 0.215576171875 +6546 0.027587890625 +6547 0.211456298828125 +6548 0.01995849609375 +6549 0.17523193359375 +6550 0.011138916015625 +6551 0.128753662109375 +6552 0.007049560546875 +6553 0.1019287109375 +6554 0.003509521484375 +6555 0.0743408203125 +6556 -0.000152587890625 +6557 0.04327392578125 +6558 0.001800537109375 +6559 0.038177490234375 +6560 0.012603759765625 +6561 0.076263427734375 +6562 0.028778076171875 +6563 0.14105224609375 +6564 0.040924072265625 +6565 0.186431884765625 +6566 0.044158935546875 +6567 0.188812255859375 +6568 0.036529541015625 +6569 0.1390380859375 +6570 0.018890380859375 +6571 0.041778564453125 +6572 -0.004150390625 +6573 -0.079437255859375 +6574 -0.031585693359375 +6575 -0.219390869140625 +6576 -0.06134033203125 +6577 -0.367828369140625 +6578 -0.08746337890625 +6579 -0.494873046875 +6580 -0.101043701171875 +6581 -0.556243896484375 +6582 -0.09332275390625 +6583 -0.508697509765625 +6584 -0.068878173828125 +6585 -0.3756103515625 +6586 -0.039947509765625 +6587 -0.218902587890625 +6588 -0.011444091796875 +6589 -0.063751220703125 +6590 0.01702880859375 +6591 0.091552734375 +6592 0.04345703125 +6593 0.23602294921875 +6594 0.062652587890625 +6595 0.342987060546875 +6596 0.0712890625 +6597 0.39520263671875 +6598 0.06878662109375 +6599 0.389373779296875 +6600 0.054962158203125 +6601 0.324249267578125 +6602 0.034698486328125 +6603 0.224090576171875 +6604 0.01507568359375 +6605 0.124267578125 +6606 -0.001495361328125 +6607 0.037078857421875 +6608 -0.009552001953125 +6609 -0.010101318359375 +6610 -0.0096435546875 +6611 -0.019439697265625 +6612 -0.008270263671875 +6613 -0.022796630859375 +6614 -0.0018310546875 +6615 -0.001556396484375 +6616 0.011932373046875 +6617 0.056304931640625 +6618 0.024078369140625 +6619 0.106719970703125 +6620 0.02398681640625 +6621 0.096893310546875 +6622 0.01470947265625 +6623 0.042694091796875 +6624 0.003753662109375 +6625 -0.018035888671875 +6626 -0.00701904296875 +6627 -0.07586669921875 +6628 -0.015380859375 +6629 -0.11944580078125 +6630 -0.023529052734375 +6631 -0.15972900390625 +6632 -0.032623291015625 +6633 -0.202606201171875 +6634 -0.042694091796875 +6635 -0.24859619140625 +6636 -0.05517578125 +6637 -0.30517578125 +6638 -0.0679931640625 +6639 -0.36212158203125 +6640 -0.075469970703125 +6641 -0.39141845703125 +6642 -0.0699462890625 +6643 -0.35528564453125 +6644 -0.050567626953125 +6645 -0.249969482421875 +6646 -0.020751953125 +6647 -0.092864990234375 +6648 0.01416015625 +6649 0.08905029296875 +6650 0.04217529296875 +6651 0.2352294921875 +6652 0.0579833984375 +6653 0.318817138671875 +6654 0.06536865234375 +6655 0.358642578125 +6656 0.063568115234375 +6657 0.347747802734375 +6658 0.053131103515625 +6659 0.28564453125 +6660 0.042999267578125 +6661 0.223175048828125 +6662 0.039031982421875 +6663 0.196746826171875 +6664 0.03656005859375 +6665 0.179840087890625 +6666 0.0325927734375 +6667 0.155548095703125 +6668 0.0316162109375 +6669 0.151214599609375 +6670 0.031951904296875 +6671 0.156951904296875 +6672 0.026702880859375 +6673 0.13177490234375 +6674 0.0201416015625 +6675 0.100799560546875 +6676 0.0162353515625 +6677 0.087127685546875 +6678 0.009063720703125 +6679 0.05487060546875 +6680 -0.00341796875 +6681 -0.009002685546875 +6682 -0.021026611328125 +6683 -0.10400390625 +6684 -0.043548583984375 +6685 -0.229400634765625 +6686 -0.065887451171875 +6687 -0.35552978515625 +6688 -0.081207275390625 +6689 -0.441925048828125 +6690 -0.08697509765625 +6691 -0.473846435546875 +6692 -0.085418701171875 +6693 -0.464813232421875 +6694 -0.0772705078125 +6695 -0.419097900390625 +6696 -0.062164306640625 +6697 -0.334320068359375 +6698 -0.0430908203125 +6699 -0.227935791015625 +6700 -0.024078369140625 +6701 -0.12347412109375 +6702 -0.00634765625 +6703 -0.02764892578125 +6704 0.013031005859375 +6705 0.077667236328125 +6706 0.037445068359375 +6707 0.2132568359375 +6708 0.06842041015625 +6709 0.38885498046875 +6710 0.102294921875 +6711 0.582794189453125 +6712 0.12872314453125 +6713 0.734039306640625 +6714 0.1405029296875 +6715 0.800140380859375 +6716 0.13714599609375 +6717 0.7783203125 +6718 0.118072509765625 +6719 0.6651611328125 +6720 0.083160400390625 +6721 0.45965576171875 +6722 0.038726806640625 +6723 0.199188232421875 +6724 -0.004150390625 +6725 -0.050689697265625 +6726 -0.035858154296875 +6727 -0.23297119140625 +6728 -0.05340576171875 +6729 -0.33013916015625 +6730 -0.06109619140625 +6731 -0.368408203125 +6732 -0.064117431640625 +6733 -0.378936767578125 +6734 -0.064971923828125 +6735 -0.376983642578125 +6736 -0.06646728515625 +6737 -0.37969970703125 +6738 -0.069305419921875 +6739 -0.391510009765625 +6740 -0.068878173828125 +6741 -0.385345458984375 +6742 -0.061920166015625 +6743 -0.3419189453125 +6744 -0.05206298828125 +6745 -0.28289794921875 +6746 -0.046600341796875 +6747 -0.251617431640625 +6748 -0.048583984375 +6749 -0.266143798828125 +6750 -0.049102783203125 +6751 -0.273345947265625 +6752 -0.03875732421875 +6753 -0.216796875 +6754 -0.02288818359375 +6755 -0.128265380859375 +6756 -0.011688232421875 +6757 -0.068145751953125 +6758 -0.006378173828125 +6759 -0.0430908203125 +6760 -0.002166748046875 +6761 -0.024444580078125 +6762 0.006378173828125 +6763 0.020721435546875 +6764 0.024566650390625 +6765 0.124481201171875 +6766 0.047515869140625 +6767 0.25787353515625 +6768 0.06817626953125 +6769 0.379119873046875 +6770 0.08514404296875 +6771 0.47991943359375 +6772 0.093048095703125 +6773 0.5281982421875 +6774 0.0897216796875 +6775 0.511138916015625 +6776 0.079833984375 +6777 0.456207275390625 +6778 0.070831298828125 +6779 0.407470703125 +6780 0.065948486328125 +6781 0.383758544921875 +6782 0.060455322265625 +6783 0.35687255859375 +6784 0.0518798828125 +6785 0.31182861328125 +6786 0.0406494140625 +6787 0.250885009765625 +6788 0.025421142578125 +6789 0.1654052734375 +6790 0.002838134765625 +6791 0.035247802734375 +6792 -0.027435302734375 +6793 -0.142059326171875 +6794 -0.060211181640625 +6795 -0.33563232421875 +6796 -0.0936279296875 +6797 -0.5345458984375 +6798 -0.124847412109375 +6799 -0.72186279296875 +6800 -0.143646240234375 +6801 -0.836669921875 +6802 -0.142303466796875 +6803 -0.8326416015625 +6804 -0.124176025390625 +6805 -0.7296142578125 +6806 -0.09857177734375 +6807 -0.582550048828125 +6808 -0.07373046875 +6809 -0.440093994140625 +6810 -0.053375244140625 +6811 -0.324310302734375 +6812 -0.031890869140625 +6813 -0.20147705078125 +6814 -0.004791259765625 +6815 -0.044647216796875 +6816 0.020751953125 +6817 0.103973388671875 +6818 0.03765869140625 +6819 0.202392578125 +6820 0.048248291015625 +6821 0.264495849609375 +6822 0.0606689453125 +6823 0.338897705078125 +6824 0.0780029296875 +6825 0.443817138671875 +6826 0.09454345703125 +6827 0.545074462890625 +6828 0.106048583984375 +6829 0.6173095703125 +6830 0.111236572265625 +6831 0.6524658203125 +6832 0.1123046875 +6833 0.66339111328125 +6834 0.11029052734375 +6835 0.6561279296875 +6836 0.1011962890625 +6837 0.606781005859375 +6838 0.08270263671875 +6839 0.501190185546875 +6840 0.05712890625 +6841 0.352783203125 +6842 0.027008056640625 +6843 0.176544189453125 +6844 -0.008819580078125 +6845 -0.034820556640625 +6846 -0.046417236328125 +6847 -0.258209228515625 +6848 -0.077239990234375 +6849 -0.44244384765625 +6850 -0.0992431640625 +6851 -0.5753173828125 +6852 -0.11163330078125 +6853 -0.65203857421875 +6854 -0.109283447265625 +6855 -0.641632080078125 +6856 -0.095245361328125 +6857 -0.562164306640625 +6858 -0.077056884765625 +6859 -0.458038330078125 +6860 -0.058319091796875 +6861 -0.350555419921875 +6862 -0.04254150390625 +6863 -0.260528564453125 +6864 -0.03045654296875 +6865 -0.192108154296875 +6866 -0.02154541015625 +6867 -0.141937255859375 +6868 -0.01446533203125 +6869 -0.1021728515625 +6870 -0.007598876953125 +6871 -0.062896728515625 +6872 0.001068115234375 +6873 -0.011932373046875 +6874 0.013580322265625 +6875 0.062835693359375 +6876 0.027801513671875 +6877 0.148712158203125 +6878 0.043060302734375 +6879 0.241729736328125 +6880 0.06060791015625 +6881 0.34912109375 +6882 0.078216552734375 +6883 0.457305908203125 +6884 0.092132568359375 +6885 0.54388427734375 +6886 0.096343994140625 +6887 0.5728759765625 +6888 0.084564208984375 +6889 0.506591796875 +6890 0.057861328125 +6891 0.351226806640625 +6892 0.02294921875 +6893 0.146514892578125 +6894 -0.011322021484375 +6895 -0.05523681640625 +6896 -0.038604736328125 +6897 -0.21624755859375 +6898 -0.058624267578125 +6899 -0.334930419921875 +6900 -0.0699462890625 +6901 -0.402984619140625 +6902 -0.07611083984375 +6903 -0.4412841796875 +6904 -0.084869384765625 +6905 -0.49578857421875 +6906 -0.095184326171875 +6907 -0.5601806640625 +6908 -0.1014404296875 +6909 -0.600738525390625 +6910 -0.09808349609375 +6911 -0.584228515625 +6912 -0.0802001953125 +6913 -0.47930908203125 +6914 -0.04736328125 +6915 -0.27935791015625 +6916 -0.00390625 +6917 -0.0089111328125 +6918 0.04083251953125 +6919 0.268798828125 +6920 0.0765380859375 +6921 0.482818603515625 +6922 0.098724365234375 +6923 0.60369873046875 +6924 0.109588623046875 +6925 0.650421142578125 +6926 0.11444091796875 +6927 0.66400146484375 +6928 0.112762451171875 +6929 0.6414794921875 +6930 0.103118896484375 +6931 0.572540283203125 +6932 0.091156005859375 +6933 0.498138427734375 +6934 0.0799560546875 +6935 0.439453125 +6936 0.066925048828125 +6937 0.375518798828125 +6938 0.048004150390625 +6939 0.274505615234375 +6940 0.019775390625 +6941 0.1087646484375 +6942 -0.01434326171875 +6943 -0.099395751953125 +6944 -0.0496826171875 +6945 -0.3182373046875 +6946 -0.086090087890625 +6947 -0.5489501953125 +6948 -0.120880126953125 +6949 -0.7738037109375 +6950 -0.14666748046875 +6951 -0.86383056640625 +6952 -0.15875244140625 +6953 -0.870391845703125 +6954 -0.15948486328125 +6955 -0.86895751953125 +6956 -0.150665283203125 +6957 -0.861053466796875 +6958 -0.1300048828125 +6959 -0.765869140625 +6960 -0.096099853515625 +6961 -0.5301513671875 +6962 -0.050079345703125 +6963 -0.214691162109375 +6964 0.001983642578125 +6965 0.137359619140625 +6966 0.0528564453125 +6967 0.474822998046875 +6968 0.097442626953125 +6969 0.76239013671875 +6970 0.131805419921875 +6971 0.867462158203125 +6972 0.155731201171875 +6973 0.870361328125 +6974 0.16741943359375 +6975 0.86480712890625 +6976 0.167449951171875 +6977 0.831817626953125 +6978 0.159027099609375 +6979 0.677581787109375 +6980 0.142852783203125 +6981 0.495880126953125 +6982 0.121429443359375 +6983 0.30767822265625 +6984 0.0950927734375 +6985 0.116180419921875 +6986 0.05963134765625 +6987 -0.110748291015625 +6988 0.01422119140625 +6989 -0.381805419921875 +6990 -0.03509521484375 +6991 -0.6572265625 +6992 -0.0799560546875 +6993 -0.857421875 +6994 -0.114349365234375 +6995 -0.870391845703125 +6996 -0.137115478515625 +6997 -0.870391845703125 +6998 -0.1517333984375 +6999 -0.86444091796875 +7000 -0.162872314453125 +7001 -0.85723876953125 +7002 -0.167877197265625 +7003 -0.790008544921875 +7004 -0.15924072265625 +7005 -0.62847900390625 +7006 -0.136474609375 +7007 -0.3956298828125 +7008 -0.10400390625 +7009 -0.126708984375 +7010 -0.06561279296875 +7011 0.150115966796875 +7012 -0.02294921875 +7013 0.424041748046875 +7014 0.020233154296875 +7015 0.670623779296875 +7016 0.058563232421875 +7017 0.854522705078125 +7018 0.089447021484375 +7019 0.866485595703125 +7020 0.11065673828125 +7021 0.86920166015625 +7022 0.124481201171875 +7023 0.8653564453125 +7024 0.132598876953125 +7025 0.857147216796875 +7026 0.13446044921875 +7027 0.766845703125 +7028 0.130645751953125 +7029 0.628509521484375 +7030 0.1201171875 +7031 0.462127685546875 +7032 0.1063232421875 +7033 0.297210693359375 +7034 0.09088134765625 +7035 0.14862060546875 +7036 0.0706787109375 +7037 -0.00537109375 +7038 0.04681396484375 +7039 -0.15753173828125 +7040 0.01885986328125 +7041 -0.31304931640625 +7042 -0.01495361328125 +7043 -0.48876953125 +7044 -0.048126220703125 +7045 -0.6416015625 +7046 -0.077178955078125 +7047 -0.751373291015625 +7048 -0.105133056640625 +7049 -0.84619140625 +7050 -0.129852294921875 +7051 -0.861297607421875 +7052 -0.146697998046875 +7053 -0.863250732421875 +7054 -0.151275634765625 +7055 -0.856597900390625 +7056 -0.1451416015625 +7057 -0.7498779296875 +7058 -0.1361083984375 +7059 -0.624542236328125 +7060 -0.12115478515625 +7061 -0.47808837890625 +7062 -0.092315673828125 +7063 -0.253387451171875 +7064 -0.055816650390625 +7065 0.003692626953125 +7066 -0.021026611328125 +7067 0.2257080078125 +7068 0.013641357421875 +7069 0.427154541015625 +7070 0.052490234375 +7071 0.643218994140625 +7072 0.094085693359375 +7073 0.855926513671875 +7074 0.130462646484375 +7075 0.870361328125 +7076 0.154754638671875 +7077 0.870361328125 +7078 0.167877197265625 +7079 0.862762451171875 +7080 0.16937255859375 +7081 0.79669189453125 +7082 0.157867431640625 +7083 0.595794677734375 +7084 0.137298583984375 +7085 0.362152099609375 +7086 0.111419677734375 +7087 0.1270751953125 +7088 0.083099365234375 +7089 -0.086944580078125 +7090 0.052642822265625 +7091 -0.2784423828125 +7092 0.015350341796875 +7093 -0.484832763671875 +7094 -0.031280517578125 +7095 -0.729583740234375 +7096 -0.080291748046875 +7097 -0.86688232421875 +7098 -0.123016357421875 +7099 -0.870391845703125 +7100 -0.158660888671875 +7101 -0.86859130859375 +7102 -0.186859130859375 +7103 -0.86279296875 +7104 -0.20263671875 +7105 -0.817962646484375 +7106 -0.199737548828125 +7107 -0.6116943359375 +7108 -0.177154541015625 +7109 -0.3128662109375 +7110 -0.139434814453125 +7111 0.039398193359375 +7112 -0.089263916015625 +7113 0.422821044921875 +7114 -0.031158447265625 +7115 0.805145263671875 +7116 0.025543212890625 +7117 0.870361328125 +7118 0.07305908203125 +7119 0.870361328125 +7120 0.1097412109375 +7121 0.860015869140625 +7122 0.134490966796875 +7123 0.727935791015625 +7124 0.146453857421875 +7125 0.48114013671875 +7126 0.148834228515625 +7127 0.2059326171875 +7128 0.14459228515625 +7129 -0.06103515625 +7130 0.135009765625 +7131 -0.29913330078125 +7132 0.1180419921875 +7133 -0.516204833984375 +7134 0.091583251953125 +7135 -0.7252197265625 +7136 0.0589599609375 +7137 -0.85980224609375 +7138 0.02484130859375 +7139 -0.870391845703125 +7140 -0.0067138671875 +7141 -0.870391845703125 +7142 -0.029052734375 +7143 -0.858062744140625 +7144 -0.04150390625 +7145 -0.673004150390625 +7146 -0.051116943359375 +7147 -0.42694091796875 +7148 -0.0638427734375 +7149 -0.2100830078125 +7150 -0.07928466796875 +7151 -0.0362548828125 +7152 -0.093353271484375 +7153 0.10943603515625 +7154 -0.10321044921875 +7155 0.23516845703125 +7156 -0.1031494140625 +7157 0.373687744140625 +7158 -0.093353271484375 +7159 0.517791748046875 +7160 -0.08233642578125 +7161 0.602783203125 +7162 -0.06939697265625 +7163 0.635711669921875 +7164 -0.050018310546875 +7165 0.655181884765625 +7166 -0.02557373046875 +7167 0.65948486328125 +7168 0.002471923828125 +7169 0.651275634765625 +7170 0.030731201171875 +7171 0.61846923828125 +7172 0.05462646484375 +7173 0.53753662109375 +7174 0.071990966796875 +7175 0.404144287109375 +7176 0.08154296875 +7177 0.22186279296875 +7178 0.083282470703125 +7179 0.003997802734375 +7180 0.0789794921875 +7181 -0.22100830078125 +7182 0.070770263671875 +7183 -0.42449951171875 +7184 0.0609130859375 +7185 -0.579833984375 +7186 0.053955078125 +7187 -0.641876220703125 +7188 0.049346923828125 +7189 -0.6177978515625 +7190 0.0406494140625 +7191 -0.575531005859375 +7192 0.027587890625 +7193 -0.526336669921875 +7194 0.015838623046875 +7195 -0.42645263671875 +7196 0.008544921875 +7197 -0.2581787109375 +7198 0.002197265625 +7199 -0.068695068359375 +7200 -0.0068359375 +7201 0.09222412109375 +7202 -0.016387939453125 +7203 0.232147216796875 +7204 -0.025177001953125 +7205 0.3509521484375 +7206 -0.036163330078125 +7207 0.410064697265625 +7208 -0.05230712890625 +7209 0.372955322265625 +7210 -0.071441650390625 +7211 0.2554931640625 +7212 -0.08819580078125 +7213 0.10711669921875 +7214 -0.10064697265625 +7215 -0.052886962890625 +7216 -0.105194091796875 +7217 -0.186279296875 +7218 -0.096282958984375 +7219 -0.23291015625 +7220 -0.076507568359375 +7221 -0.209442138671875 +7222 -0.053009033203125 +7223 -0.174163818359375 +7224 -0.026885986328125 +7225 -0.126739501953125 +7226 0.002593994140625 +7227 -0.048126220703125 +7228 0.03228759765625 +7229 0.0426025390625 +7230 0.057159423828125 +7231 0.10748291015625 +7232 0.07574462890625 +7233 0.1409912109375 +7234 0.0928955078125 +7235 0.19708251953125 +7236 0.107879638671875 +7237 0.273651123046875 +7238 0.114959716796875 +7239 0.31768798828125 +7240 0.1153564453125 +7241 0.341094970703125 +7242 0.11181640625 +7243 0.368011474609375 +7244 0.10211181640625 +7245 0.37249755859375 +7246 0.081298828125 +7247 0.30072021484375 +7248 0.050140380859375 +7249 0.1517333984375 +7250 0.0157470703125 +7251 -0.01470947265625 +7252 -0.019805908203125 +7253 -0.1883544921875 +7254 -0.055938720703125 +7255 -0.372711181640625 +7256 -0.08612060546875 +7257 -0.51397705078125 +7258 -0.105377197265625 +7259 -0.57177734375 +7260 -0.112335205078125 +7261 -0.53948974609375 +7262 -0.1083984375 +7263 -0.43511962890625 +7264 -0.097198486328125 +7265 -0.2962646484375 +7266 -0.0826416015625 +7267 -0.161102294921875 +7268 -0.066314697265625 +7269 -0.0435791015625 +7270 -0.048126220703125 +7271 0.060394287109375 +7272 -0.030029296875 +7273 0.13665771484375 +7274 -0.01422119140625 +7275 0.170135498046875 +7276 -0.0009765625 +7277 0.16552734375 +7278 0.01251220703125 +7279 0.15728759765625 +7280 0.025970458984375 +7281 0.150787353515625 +7282 0.0361328125 +7283 0.12200927734375 +7284 0.043304443359375 +7285 0.080108642578125 +7286 0.049591064453125 +7287 0.05126953125 +7288 0.057403564453125 +7289 0.062896728515625 +7290 0.06414794921875 +7291 0.09271240234375 +7292 0.064727783203125 +7293 0.092987060546875 +7294 0.060760498046875 +7295 0.07855224609375 +7296 0.05401611328125 +7297 0.06427001953125 +7298 0.043243408203125 +7299 0.0347900390625 +7300 0.02874755859375 +7301 -0.01171875 +7302 0.01312255859375 +7303 -0.056060791015625 +7304 0.001434326171875 +7305 -0.055511474609375 +7306 -0.00567626953125 +7307 -0.010467529296875 +7308 -0.013153076171875 +7309 0.02508544921875 +7310 -0.023040771484375 +7311 0.025665283203125 +7312 -0.032135009765625 +7313 0.017333984375 +7314 -0.039825439453125 +7315 0.00189208984375 +7316 -0.047027587890625 +7317 -0.03173828125 +7318 -0.052337646484375 +7319 -0.071502685546875 +7320 -0.05767822265625 +7321 -0.13543701171875 +7322 -0.06280517578125 +7323 -0.219970703125 +7324 -0.065399169921875 +7325 -0.300506591796875 +7326 -0.06573486328125 +7327 -0.376312255859375 +7328 -0.061065673828125 +7329 -0.416107177734375 +7330 -0.04681396484375 +7331 -0.371124267578125 +7332 -0.023651123046875 +7333 -0.242279052734375 +7334 0.003692626953125 +7335 -0.069732666015625 +7336 0.03253173828125 +7337 0.125640869140625 +7338 0.059173583984375 +7339 0.31268310546875 +7340 0.0794677734375 +7341 0.45501708984375 +7342 0.0933837890625 +7343 0.554779052734375 +7344 0.100677490234375 +7345 0.61065673828125 +7346 0.10009765625 +7347 0.610931396484375 +7348 0.0892333984375 +7349 0.531463623046875 +7350 0.0699462890625 +7351 0.3883056640625 +7352 0.048095703125 +7353 0.23468017578125 +7354 0.026641845703125 +7355 0.095245361328125 +7356 0.008697509765625 +7357 -0.00396728515625 +7358 -0.00384521484375 +7359 -0.04852294921875 +7360 -0.01226806640625 +7361 -0.055145263671875 +7362 -0.02154541015625 +7363 -0.0758056640625 +7364 -0.03424072265625 +7365 -0.138702392578125 +7366 -0.046417236328125 +7367 -0.209197998046875 +7368 -0.05804443359375 +7369 -0.289031982421875 +7370 -0.069061279296875 +7371 -0.37884521484375 +7372 -0.07708740234375 +7373 -0.456329345703125 +7374 -0.0816650390625 +7375 -0.51641845703125 +7376 -0.07879638671875 +7377 -0.519287109375 +7378 -0.0679931640625 +7379 -0.458251953125 +7380 -0.054901123046875 +7381 -0.384796142578125 +7382 -0.04241943359375 +7383 -0.323699951171875 +7384 -0.0302734375 +7385 -0.269287109375 +7386 -0.01611328125 +7387 -0.1951904296875 +7388 -0.000152587890625 +7389 -0.100006103515625 +7390 0.014495849609375 +7391 -0.01055908203125 +7392 0.03070068359375 +7393 0.1033935546875 +7394 0.048980712890625 +7395 0.24908447265625 +7396 0.06365966796875 +7397 0.373199462890625 +7398 0.072845458984375 +7399 0.45806884765625 +7400 0.077392578125 +7401 0.511474609375 +7402 0.080718994140625 +7403 0.565399169921875 +7404 0.082061767578125 +7405 0.61138916015625 +7406 0.075439453125 +7407 0.5897216796875 +7408 0.06011962890625 +7409 0.4906005859375 +7410 0.0382080078125 +7411 0.33148193359375 +7412 0.013702392578125 +7413 0.147796630859375 +7414 -0.00872802734375 +7415 -0.01873779296875 +7416 -0.02593994140625 +7417 -0.140289306640625 +7418 -0.03509521484375 +7419 -0.191986083984375 +7420 -0.037109375 +7421 -0.184295654296875 +7422 -0.0364990234375 +7423 -0.161834716796875 +7424 -0.03753662109375 +7425 -0.166595458984375 +7426 -0.039764404296875 +7427 -0.19390869140625 +7428 -0.041229248046875 +7429 -0.22442626953125 +7430 -0.044189453125 +7431 -0.279754638671875 +7432 -0.046722412109375 +7433 -0.3389892578125 +7434 -0.04425048828125 +7435 -0.3543701171875 +7436 -0.039215087890625 +7437 -0.348175048828125 +7438 -0.032440185546875 +7439 -0.32598876953125 +7440 -0.021209716796875 +7441 -0.2581787109375 +7442 -0.005279541015625 +7443 -0.139801025390625 +7444 0.013641357421875 +7445 0.014617919921875 +7446 0.029327392578125 +7447 0.144378662109375 +7448 0.038818359375 +7449 0.221038818359375 +7450 0.044647216796875 +7451 0.27069091796875 +7452 0.046875 +7453 0.294036865234375 +7454 0.047607421875 +7455 0.311767578125 +7456 0.048370361328125 +7457 0.339141845703125 +7458 0.047332763671875 +7459 0.360260009765625 +7460 0.0433349609375 +7461 0.360504150390625 +7462 0.03448486328125 +7463 0.308380126953125 +7464 0.01959228515625 +7465 0.18170166015625 +7466 0.00079345703125 +7467 0.0047607421875 +7468 -0.018096923828125 +7469 -0.17559814453125 +7470 -0.033477783203125 +7471 -0.3143310546875 +7472 -0.041900634765625 +7473 -0.36785888671875 +7474 -0.0450439453125 +7475 -0.36248779296875 +7476 -0.0460205078125 +7477 -0.343536376953125 +7478 -0.0440673828125 +7479 -0.3018798828125 +7480 -0.038726806640625 +7481 -0.231414794921875 +7482 -0.029022216796875 +7483 -0.117645263671875 +7484 -0.017425537109375 +7485 0.007049560546875 +7486 -0.008026123046875 +7487 0.087982177734375 +7488 -3.0517578125e-05 +7489 0.13946533203125 +7490 0.0072021484375 +7491 0.17425537109375 +7492 0.013092041015625 +7493 0.188201904296875 +7494 0.016632080078125 +7495 0.171234130859375 +7496 0.017242431640625 +7497 0.118438720703125 +7498 0.01666259765625 +7499 0.05706787109375 +7500 0.01483154296875 +7501 -0.010711669921875 +7502 0.011138916015625 +7503 -0.0914306640625 +7504 0.007110595703125 +7505 -0.162322998046875 +7506 0.004791259765625 +7507 -0.194549560546875 +7508 0.00701904296875 +7509 -0.1492919921875 +7510 0.01422119140625 +7511 -0.02166748046875 +7512 0.02191162109375 +7513 0.124053955078125 +7514 0.02471923828125 +7515 0.211151123046875 +7516 0.022918701171875 +7517 0.240447998046875 +7518 0.018951416015625 +7519 0.242218017578125 +7520 0.013702392578125 +7521 0.2257080078125 +7522 0.007659912109375 +7523 0.194366455078125 +7524 -0.001312255859375 +7525 0.115509033203125 +7526 -0.011322021484375 +7527 0.0128173828125 +7528 -0.0179443359375 +7529 -0.053802490234375 +7530 -0.02301025390625 +7531 -0.110626220703125 +7532 -0.02947998046875 +7533 -0.199493408203125 +7534 -0.035552978515625 +7535 -0.29437255859375 +7536 -0.036712646484375 +7537 -0.33221435546875 +7538 -0.03070068359375 +7539 -0.27972412109375 +7540 -0.021148681640625 +7541 -0.185333251953125 +7542 -0.013916015625 +7543 -0.128204345703125 +7544 -0.00970458984375 +7545 -0.115692138671875 +7546 -0.006439208984375 +7547 -0.116455078125 +7548 -0.002532958984375 +7549 -0.105926513671875 +7550 0.00396728515625 +7551 -0.053955078125 +7552 0.01361083984375 +7553 0.048797607421875 +7554 0.0230712890625 +7555 0.157318115234375 +7556 0.027984619140625 +7557 0.212005615234375 +7558 0.0286865234375 +7559 0.218475341796875 +7560 0.029541015625 +7561 0.23724365234375 +7562 0.03326416015625 +7563 0.30535888671875 +7564 0.03692626953125 +7565 0.38128662109375 +7566 0.03631591796875 +7567 0.404449462890625 +7568 0.032989501953125 +7569 0.3944091796875 +7570 0.02978515625 +7571 0.3885498046875 +7572 0.025146484375 +7573 0.362640380859375 +7574 0.016082763671875 +7575 0.27362060546875 +7576 0.00244140625 +7577 0.11712646484375 +7578 -0.01190185546875 +7579 -0.054901123046875 +7580 -0.023101806640625 +7581 -0.19085693359375 +7582 -0.03076171875 +7583 -0.28570556640625 +7584 -0.034820556640625 +7585 -0.339263916015625 +7586 -0.037200927734375 +7587 -0.3775634765625 +7588 -0.041168212890625 +7589 -0.445709228515625 +7590 -0.046173095703125 +7591 -0.535064697265625 +7592 -0.05108642578125 +7593 -0.629058837890625 +7594 -0.0538330078125 +7595 -0.697601318359375 +7596 -0.05194091796875 +7597 -0.70391845703125 +7598 -0.045135498046875 +7599 -0.6424560546875 +7600 -0.031982421875 +7601 -0.491241455078125 +7602 -0.013702392578125 +7603 -0.265716552734375 +7604 0.005401611328125 +7605 -0.023712158203125 +7606 0.022857666015625 +7607 0.201751708984375 +7608 0.0361328125 +7609 0.375823974609375 +7610 0.044219970703125 +7611 0.485076904296875 +7612 0.049957275390625 +7613 0.56884765625 +7614 0.053924560546875 +7615 0.634765625 +7616 0.05291748046875 +7617 0.63763427734375 +7618 0.04620361328125 +7619 0.5660400390625 +7620 0.03759765625 +7621 0.4720458984375 +7622 0.030914306640625 +7623 0.40692138671875 +7624 0.02679443359375 +7625 0.3778076171875 +7626 0.0247802734375 +7627 0.376953125 +7628 0.022674560546875 +7629 0.371978759765625 +7630 0.016937255859375 +7631 0.313140869140625 +7632 0.006500244140625 +7633 0.184417724609375 +7634 -0.0067138671875 +7635 0.011199951171875 +7636 -0.02008056640625 +7637 -0.171051025390625 +7638 -0.031829833984375 +7639 -0.33740234375 +7640 -0.040863037109375 +7641 -0.47198486328125 +7642 -0.04620361328125 +7643 -0.560394287109375 +7644 -0.04632568359375 +7645 -0.58056640625 +7646 -0.042388916015625 +7647 -0.54754638671875 +7648 -0.037872314453125 +7649 -0.508575439453125 +7650 -0.0325927734375 +7651 -0.459503173828125 +7652 -0.026214599609375 +7653 -0.394378662109375 +7654 -0.0216064453125 +7655 -0.35260009765625 +7656 -0.017242431640625 +7657 -0.31170654296875 +7658 -0.00787353515625 +7659 -0.197418212890625 +7660 0.00653076171875 +7661 -0.007965087890625 +7662 0.022369384765625 +7663 0.207489013671875 +7664 0.036773681640625 +7665 0.409210205078125 +7666 0.0479736328125 +7667 0.57208251953125 +7668 0.053863525390625 +7669 0.66595458984375 +7670 0.052154541015625 +7671 0.65875244140625 +7672 0.044189453125 +7673 0.56744384765625 +7674 0.032867431640625 +7675 0.431396484375 +7676 0.02142333984375 +7677 0.29443359375 +7678 0.011810302734375 +7679 0.182464599609375 +7680 0.0023193359375 +7681 0.06365966796875 +7682 -0.00787353515625 +7683 -0.075958251953125 +7684 -0.0167236328125 +7685 -0.189422607421875 +7686 -0.02374267578125 +7687 -0.271942138671875 +7688 -0.029449462890625 +7689 -0.342529296875 +7690 -0.032196044921875 +7691 -0.364166259765625 +7692 -0.031494140625 +7693 -0.327239990234375 +7694 -0.029144287109375 +7695 -0.2769775390625 +7696 -0.026824951171875 +7697 -0.253692626953125 +7698 -0.024078369140625 +7699 -0.24365234375 +7700 -0.019134521484375 +7701 -0.1983642578125 +7702 -0.01214599609375 +7703 -0.116241455078125 +7704 -0.004913330078125 +7705 -0.036834716796875 +7706 0.0020751953125 +7707 0.034881591796875 +7708 0.00830078125 +7709 0.09124755859375 +7710 0.01263427734375 +7711 0.10888671875 +7712 0.016387939453125 +7713 0.125518798828125 +7714 0.020050048828125 +7715 0.15771484375 +7716 0.022430419921875 +7717 0.17828369140625 +7718 0.022796630859375 +7719 0.17108154296875 +7720 0.02093505859375 +7721 0.129974365234375 +7722 0.0179443359375 +7723 0.082427978515625 +7724 0.013885498046875 +7725 0.027679443359375 +7726 0.007659912109375 +7727 -0.065643310546875 +7728 0.000946044921875 +7729 -0.15936279296875 +7730 -0.004425048828125 +7731 -0.21307373046875 +7732 -0.008636474609375 +7733 -0.234649658203125 +7734 -0.010528564453125 +7735 -0.2001953125 +7736 -0.01031494140625 +7737 -0.119171142578125 +7738 -0.0091552734375 +7739 -0.024749755859375 +7740 -0.00677490234375 +7741 0.085784912109375 +7742 -0.0045166015625 +7743 0.178131103515625 +7744 -0.003753662109375 +7745 0.215576171875 +7746 -0.003936767578125 +7747 0.211456298828125 +7748 -0.004669189453125 +7749 0.17523193359375 +7750 -0.005157470703125 +7751 0.128753662109375 +7752 -0.004302978515625 +7753 0.1019287109375 +7754 -0.003021240234375 +7755 0.0743408203125 +7756 -0.0015869140625 +7757 0.04327392578125 +7758 0.0009765625 +7759 0.038177490234375 +7760 0.00518798828125 +7761 0.076263427734375 +7762 0.01025390625 +7763 0.14105224609375 +7764 0.014190673828125 +7765 0.186431884765625 +7766 0.0159912109375 +7767 0.188812255859375 +7768 0.01519775390625 +7769 0.1390380859375 +7770 0.011932373046875 +7771 0.041778564453125 +7772 0.00714111328125 +7773 -0.079437255859375 +7774 0.00103759765625 +7775 -0.219390869140625 +7776 -0.005859375 +7777 -0.367828369140625 +7778 -0.012298583984375 +7779 -0.494873046875 +7780 -0.01641845703125 +7781 -0.556243896484375 +7782 -0.01641845703125 +7783 -0.508697509765625 +7784 -0.01312255859375 +7785 -0.3756103515625 +7786 -0.0089111328125 +7787 -0.218902587890625 +7788 -0.004730224609375 +7789 -0.063751220703125 +7790 -0.0003662109375 +7791 0.091552734375 +7792 0.00384521484375 +7793 0.23602294921875 +7794 0.00689697265625 +7795 0.342987060546875 +7796 0.008148193359375 +7797 0.39520263671875 +7798 0.007537841796875 +7799 0.389373779296875 +7800 0.005035400390625 +7801 0.324249267578125 +7802 0.0015869140625 +7803 0.224090576171875 +7804 -0.00140380859375 +7805 0.124267578125 +7806 -0.0035400390625 +7807 0.037078857421875 +7808 -0.003814697265625 +7809 -0.010101318359375 +7810 -0.00238037109375 +7811 -0.019439697265625 +7812 -0.000640869140625 +7813 -0.022796630859375 +7814 0.00201416015625 +7815 -0.001556396484375 +7816 0.005950927734375 +7817 0.056304931640625 +7818 0.00933837890625 +7819 0.106719970703125 +7820 0.009979248046875 +7821 0.096893310546875 +7822 0.00848388671875 +7823 0.042694091796875 +7824 0.006317138671875 +7825 -0.018035888671875 +7826 0.003875732421875 +7827 -0.07586669921875 +7828 0.00164794921875 +7829 -0.11944580078125 +7830 -0.000762939453125 +7831 -0.15972900390625 +7832 -0.0035400390625 +7833 -0.202606201171875 +7834 -0.006591796875 +7835 -0.24859619140625 +7836 -0.010162353515625 +7837 -0.30517578125 +7838 -0.0137939453125 +7839 -0.36212158203125 +7840 -0.016265869140625 +7841 -0.39141845703125 +7842 -0.016021728515625 +7843 -0.35528564453125 +7844 -0.01287841796875 +7845 -0.249969482421875 +7846 -0.0074462890625 +7847 -0.092864990234375 +7848 -0.000762939453125 +7849 0.08905029296875 +7850 0.004730224609375 +7851 0.2352294921875 +7852 0.00799560546875 +7853 0.318817138671875 +7854 0.009796142578125 +7855 0.358642578125 +7856 0.009796142578125 +7857 0.347747802734375 +7858 0.007965087890625 +7859 0.28564453125 +7860 0.00628662109375 +7861 0.223175048828125 +7862 0.00616455078125 +7863 0.196746826171875 +7864 0.0064697265625 +7865 0.179840087890625 +7866 0.006500244140625 +7867 0.155548095703125 +7868 0.00726318359375 +7869 0.151214599609375 +7870 0.00836181640625 +7871 0.156951904296875 +7872 0.008087158203125 +7873 0.13177490234375 +7874 0.007415771484375 +7875 0.100799560546875 +7876 0.007232666015625 +7877 0.087127685546875 +7878 0.006103515625 +7879 0.05487060546875 +7880 0.00347900390625 +7881 -0.009002685546875 +7882 -0.00054931640625 +7883 -0.10400390625 +7884 -0.005950927734375 +7885 -0.229400634765625 +7886 -0.01153564453125 +7887 -0.35552978515625 +7888 -0.015655517578125 +7889 -0.441925048828125 +7890 -0.01763916015625 +7891 -0.473846435546875 +7892 -0.01800537109375 +7893 -0.464813232421875 +7894 -0.016876220703125 +7895 -0.419097900390625 +7896 -0.01416015625 +7897 -0.334320068359375 +7898 -0.010467529296875 +7899 -0.227935791015625 +7900 -0.0067138671875 +7901 -0.12347412109375 +7902 -0.003173828125 +7903 -0.02764892578125 +7904 0.000885009765625 +7905 0.077667236328125 +7906 0.006256103515625 +7907 0.2132568359375 +7908 0.01336669921875 +7909 0.38885498046875 +7910 0.021331787109375 +7911 0.582794189453125 +7912 0.0277099609375 +7913 0.734039306640625 +7914 0.030731201171875 +7915 0.800140380859375 +7916 0.0302734375 +7917 0.7783203125 +7918 0.02618408203125 +7919 0.6651611328125 +7920 0.018402099609375 +7921 0.45965576171875 +7922 0.008453369140625 +7923 0.199188232421875 +7924 -0.00103759765625 +7925 -0.050689697265625 +7926 -0.007843017578125 +7927 -0.23297119140625 +7928 -0.01129150390625 +7929 -0.33013916015625 +7930 -0.012481689453125 +7931 -0.368408203125 +7932 -0.012664794921875 +7933 -0.378936767578125 +7934 -0.01251220703125 +7935 -0.376983642578125 +7936 -0.012603759765625 +7937 -0.37969970703125 +7938 -0.013092041015625 +7939 -0.391510009765625 +7940 -0.013519287109375 +7941 -0.385345458984375 +7942 -0.013458251953125 +7943 -0.3419189453125 +7944 -0.012908935546875 +7945 -0.28289794921875 +7946 -0.0120849609375 +7947 -0.251617431640625 +7948 -0.011077880859375 +7949 -0.266143798828125 +7950 -0.00946044921875 +7951 -0.273345947265625 +7952 -0.006866455078125 +7953 -0.216796875 +7954 -0.003662109375 +7955 -0.128265380859375 +7956 -0.00048828125 +7957 -0.068145751953125 +7958 0.00244140625 +7959 -0.0430908203125 +7960 0.00518798828125 +7961 -0.024444580078125 +7962 0.00787353515625 +7963 0.020721435546875 +7964 0.010589599609375 +7965 0.124481201171875 +7966 0.01300048828125 +7967 0.25787353515625 +7968 0.014678955078125 +7969 0.379119873046875 +7970 0.015533447265625 +7971 0.47991943359375 +7972 0.015350341796875 +7973 0.5281982421875 +7974 0.014068603515625 +7975 0.511138916015625 +7976 0.011962890625 +7977 0.456207275390625 +7978 0.009490966796875 +7979 0.407470703125 +7980 0.00689697265625 +7981 0.383758544921875 +7982 0.00408935546875 +7983 0.35687255859375 +7984 0.001129150390625 +7985 0.31182861328125 +7986 -0.00177001953125 +7987 0.250885009765625 +7988 -0.00457763671875 +7989 0.1654052734375 +7990 -0.00732421875 +7991 0.035247802734375 +7992 -0.00994873046875 +7993 -0.142059326171875 +7994 -0.012176513671875 +7995 -0.33563232421875 +7996 -0.013885498046875 +7997 -0.5345458984375 +7998 -0.014923095703125 +7999 -0.72186279296875 +8000 -0.01483154296875 +8001 -0.836669921875 +8002 -0.0133056640625 +8003 -0.8326416015625 +8004 -0.0106201171875 +8005 -0.7296142578125 +8006 -0.00738525390625 +8007 -0.582550048828125 +8008 -0.00408935546875 +8009 -0.440093994140625 +8010 -0.001007080078125 +8011 -0.324310302734375 +8012 0.001983642578125 +8013 -0.20147705078125 +8014 0.0050048828125 +8015 -0.044647216796875 +8016 0.007598876953125 +8017 0.103973388671875 +8018 0.009368896484375 +8019 0.202392578125 +8020 0.010406494140625 +8021 0.264495849609375 +8022 0.011077880859375 +8023 0.338897705078125 +8024 0.01153564453125 +8025 0.443817138671875 +8026 0.01153564453125 +8027 0.545074462890625 +8028 0.01092529296875 +8029 0.6173095703125 +8030 0.00970458984375 +8031 0.6524658203125 +8032 0.008087158203125 +8033 0.66339111328125 +8034 0.006195068359375 +8035 0.6561279296875 +8036 0.00396728515625 +8037 0.606781005859375 +8038 0.001373291015625 +8039 0.501190185546875 +8040 -0.0013427734375 +8041 0.352783203125 +8042 -0.003997802734375 +8043 0.176544189453125 +8044 -0.006561279296875 +8045 -0.034820556640625 +8046 -0.0087890625 +8047 -0.258209228515625 +8048 -0.01025390625 +8049 -0.44244384765625 +8050 -0.010894775390625 +8051 -0.5753173828125 +8052 -0.010711669921875 +8053 -0.65203857421875 +8054 -0.009521484375 +8055 -0.641632080078125 +8056 -0.007537841796875 +8057 -0.562164306640625 +8058 -0.005218505859375 +8059 -0.458038330078125 +8060 -0.0028076171875 +8061 -0.350555419921875 +8062 -0.00054931640625 +8063 -0.260528564453125 +8064 0.00140380859375 +8065 -0.192108154296875 +8066 0.003021240234375 +8067 -0.141937255859375 +8068 0.0042724609375 +8069 -0.1021728515625 +8070 0.005218505859375 +8071 -0.062896728515625 +8072 0.005950927734375 +8073 -0.011932373046875 +8074 0.00653076171875 +8075 0.062835693359375 +8076 0.00689697265625 +8077 0.148712158203125 +8078 0.00701904296875 +8079 0.241729736328125 +8080 0.006988525390625 +8081 0.34912109375 +8082 0.006744384765625 +8083 0.457305908203125 +8084 0.006195068359375 +8085 0.54388427734375 +8086 0.005126953125 +8087 0.5728759765625 +8088 0.0032958984375 +8089 0.506591796875 +8090 0.000823974609375 +8091 0.351226806640625 +8092 -0.001861572265625 +8093 0.146514892578125 +8094 -0.004302978515625 +8095 -0.05523681640625 +8096 -0.006134033203125 +8097 -0.21624755859375 +8098 -0.007354736328125 +8099 -0.334930419921875 +8100 -0.00787353515625 +8101 -0.402984619140625 +8102 -0.00787353515625 +8103 -0.4412841796875 +8104 -0.00775146484375 +8105 -0.49578857421875 +8106 -0.007476806640625 +8107 -0.5601806640625 +8108 -0.0068359375 +8109 -0.600738525390625 +8110 -0.005645751953125 +8111 -0.584228515625 +8112 -0.003692626953125 +8113 -0.47930908203125 +8114 -0.001007080078125 +8115 -0.27935791015625 +8116 0.00213623046875 +8117 -0.0089111328125 +8118 0.005157470703125 +8119 0.268798828125 +8120 0.0074462890625 +8121 0.482818603515625 +8122 0.008758544921875 +8123 0.60369873046875 +8124 0.009246826171875 +8125 0.650421142578125 +8126 0.009246826171875 +8127 0.66400146484375 +8128 0.008758544921875 +8129 0.6414794921875 +8130 0.007720947265625 +8131 0.572540283203125 +8132 0.006500244140625 +8133 0.498138427734375 +8134 0.005279541015625 +8135 0.439453125 +8136 0.00396728515625 +8137 0.375518798828125 +8138 0.0023193359375 +8139 0.274505615234375 +8140 0.00018310546875 +8141 0.1087646484375 +8142 -0.002197265625 +8143 -0.099395751953125 +8144 -0.004547119140625 +8145 -0.3182373046875 +8146 -0.0068359375 +8147 -0.5489501953125 +8148 -0.008880615234375 +8149 -0.7738037109375 +8150 -0.01025390625 +8151 -0.86383056640625 +8152 -0.010711669921875 +8153 -0.870391845703125 +8154 -0.010406494140625 +8155 -0.86895751953125 +8156 -0.00946044921875 +8157 -0.861053466796875 +8158 -0.007781982421875 +8159 -0.765869140625 +8160 -0.00531005859375 +8161 -0.5301513671875 +8162 -0.00213623046875 +8163 -0.214691162109375 +8164 0.0013427734375 +8165 0.137359619140625 +8166 0.004669189453125 +8167 0.474822998046875 +8168 0.007537841796875 +8169 0.76239013671875 +8170 0.00970458984375 +8171 0.867462158203125 +8172 0.011138916015625 +8173 0.870361328125 +8174 0.01171875 +8175 0.86480712890625 +8176 0.011505126953125 +8177 0.831817626953125 +8178 0.010711669921875 +8179 0.677581787109375 +8180 0.009429931640625 +8181 0.495880126953125 +8182 0.007781982421875 +8183 0.30767822265625 +8184 0.005859375 +8185 0.116180419921875 +8186 0.00341796875 +8187 -0.110748291015625 +8188 0.00042724609375 +8189 -0.381805419921875 +8190 -0.00274658203125 +8191 -0.6572265625 +8192 -0.005462646484375 +8193 -0.857421875 +8194 -0.00732421875 +8195 -0.870391845703125 +8196 -0.00836181640625 +8197 -0.870391845703125 +8198 -0.00921630859375 +8199 -0.86444091796875 +8200 -0.010650634765625 +8201 -0.85723876953125 +8202 -0.012115478515625 +8203 -0.790008544921875 +8204 -0.012176513671875 +8205 -0.62847900390625 +8206 -0.01055908203125 +8207 -0.3956298828125 +8208 -0.007843017578125 +8209 -0.126708984375 +8210 -0.0045166015625 +8211 0.150115966796875 +8212 -0.000640869140625 +8213 0.424041748046875 +8214 0.0032958984375 +8215 0.670623779296875 +8216 0.00653076171875 +8217 0.854522705078125 +8218 0.008819580078125 +8219 0.866485595703125 +8220 0.009918212890625 +8221 0.86920166015625 +8222 0.01031494140625 +8223 0.8653564453125 +8224 0.010406494140625 +8225 0.857147216796875 +8226 0.010162353515625 +8227 0.766845703125 +8228 0.009674072265625 +8229 0.628509521484375 +8230 0.00872802734375 +8231 0.462127685546875 +8232 0.00787353515625 +8233 0.297210693359375 +8234 0.00726318359375 +8235 0.14862060546875 +8236 0.0062255859375 +8237 -0.00537109375 +8238 0.004791259765625 +8239 -0.15753173828125 +8240 0.00274658203125 +8241 -0.31304931640625 +8242 -0.0003662109375 +8243 -0.48876953125 +8244 -0.0035400390625 +8245 -0.6416015625 +8246 -0.006317138671875 +8247 -0.751373291015625 +8248 -0.009307861328125 +8249 -0.84619140625 +8250 -0.01226806640625 +8251 -0.861297607421875 +8252 -0.014404296875 +8253 -0.863250732421875 +8254 -0.014984130859375 +8255 -0.856597900390625 +8256 -0.0142822265625 +8257 -0.7498779296875 +8258 -0.01361083984375 +8259 -0.624542236328125 +8260 -0.012420654296875 +8261 -0.47808837890625 +8262 -0.009185791015625 +8263 -0.253387451171875 +8264 -0.004913330078125 +8265 0.003692626953125 +8266 -0.00115966796875 +8267 0.2257080078125 +8268 0.00250244140625 +8269 0.427154541015625 +8270 0.0069580078125 +8271 0.643218994140625 +8272 0.012054443359375 +8273 0.855926513671875 +8274 0.01654052734375 +8275 0.870361328125 +8276 0.019317626953125 +8277 0.870361328125 +8278 0.020599365234375 +8279 0.862762451171875 +8280 0.020355224609375 +8281 0.79669189453125 +8282 0.018341064453125 +8283 0.595794677734375 +8284 0.015228271484375 +8285 0.362152099609375 +8286 0.011627197265625 +8287 0.1270751953125 +8288 0.00799560546875 +8289 -0.086944580078125 +8290 0.00433349609375 +8291 -0.2784423828125 +8292 -0.000274658203125 +8293 -0.484832763671875 +8294 -0.00640869140625 +8295 -0.729583740234375 +8296 -0.012969970703125 +8297 -0.86688232421875 +8298 -0.018524169921875 +8299 -0.870391845703125 +8300 -0.02301025390625 +8301 -0.86859130859375 +8302 -0.026458740234375 +8303 -0.86279296875 +8304 -0.028106689453125 +8305 -0.817962646484375 +8306 -0.02685546875 +8307 -0.6116943359375 +8308 -0.022613525390625 +8309 -0.3128662109375 +8310 -0.01617431640625 +8311 0.039398193359375 +8312 -0.007965087890625 +8313 0.422821044921875 +8314 0.001220703125 +8315 0.805145263671875 +8316 0.009796142578125 +8317 0.870361328125 +8318 0.0164794921875 +8319 0.870361328125 +8320 0.021087646484375 +8321 0.860015869140625 +8322 0.0235595703125 +8323 0.727935791015625 +8324 0.023834228515625 +8325 0.48114013671875 +8326 0.022552490234375 +8327 0.2059326171875 +8328 0.020355224609375 +8329 -0.06103515625 +8330 0.017547607421875 +8331 -0.29913330078125 +8332 0.0137939453125 +8333 -0.516204833984375 +8334 0.0087890625 +8335 -0.7252197265625 +8336 0.00311279296875 +8337 -0.85980224609375 +8338 -0.00238037109375 +8339 -0.870391845703125 +8340 -0.00701904296875 +8341 -0.870391845703125 +8342 -0.00970458984375 +8343 -0.858062744140625 +8344 -0.010406494140625 +8345 -0.673004150390625 +8346 -0.010498046875 +8347 -0.42694091796875 +8348 -0.011077880859375 +8349 -0.2100830078125 +8350 -0.012176513671875 +8351 -0.0362548828125 +8352 -0.01318359375 +8353 0.10943603515625 +8354 -0.01361083984375 +8355 0.23516845703125 +8356 -0.012542724609375 +8357 0.373687744140625 +8358 -0.01007080078125 +8359 0.517791748046875 +8360 -0.007720947265625 +8361 0.602783203125 +8362 -0.00537109375 +8363 0.635711669921875 +8364 -0.002227783203125 +8365 0.655181884765625 +8366 0.00146484375 +8367 0.65948486328125 +8368 0.0054931640625 +8369 0.651275634765625 +8370 0.009307861328125 +8371 0.61846923828125 +8372 0.012115478515625 +8373 0.53753662109375 +8374 0.0135498046875 +8375 0.404144287109375 +8376 0.013458251953125 +8377 0.22186279296875 +8378 0.011993408203125 +8379 0.003997802734375 +8380 0.009613037109375 +8381 -0.22100830078125 +8382 0.006866455078125 +8383 -0.42449951171875 +8384 0.004302978515625 +8385 -0.579833984375 +8386 0.002960205078125 +8387 -0.641876220703125 +8388 0.002685546875 +8389 -0.6177978515625 +8390 0.001922607421875 +8391 -0.575531005859375 +8392 0.000518798828125 +8393 -0.526336669921875 +8394 -0.00030517578125 +8395 -0.42645263671875 +8396 3.0517578125e-05 +8397 -0.2581787109375 +8398 0.0006103515625 +8399 -0.068695068359375 +8400 0.00048828125 +8401 0.09222412109375 +8402 6.103515625e-05 +8403 0.232147216796875 +8404 -0.000457763671875 +8405 0.3509521484375 +8406 -0.001800537109375 +8407 0.410064697265625 +8408 -0.00469970703125 +8409 0.372955322265625 +8410 -0.008697509765625 +8411 0.2554931640625 +8412 -0.012542724609375 +8413 0.10711669921875 +8414 -0.015777587890625 +8415 -0.052886962890625 +8416 -0.017547607421875 +8417 -0.186279296875 +8418 -0.01654052734375 +8419 -0.23291015625 +8420 -0.0133056640625 +8421 -0.209442138671875 +8422 -0.009368896484375 +8423 -0.174163818359375 +8424 -0.004913330078125 +8425 -0.126739501953125 +8426 0.000274658203125 +8427 -0.048126220703125 +8428 0.00555419921875 +8429 0.0426025390625 +8430 0.0098876953125 +8431 0.10748291015625 +8432 0.012969970703125 +8433 0.1409912109375 +8434 0.0159912109375 +8435 0.19708251953125 +8436 0.018829345703125 +8437 0.273651123046875 +8438 0.020172119140625 +8439 0.31768798828125 +8440 0.02032470703125 +8441 0.341094970703125 +8442 0.019927978515625 +8443 0.368011474609375 +8444 0.0184326171875 +8445 0.37249755859375 +8446 0.0146484375 +8447 0.30072021484375 +8448 0.00885009765625 +8449 0.1517333984375 +8450 0.00274658203125 +8451 -0.01470947265625 +8452 -0.004058837890625 +8453 -0.1883544921875 +8454 -0.011932373046875 +8455 -0.372711181640625 +8456 -0.018310546875 +8457 -0.51397705078125 +8458 -0.021148681640625 +8459 -0.57177734375 +8460 -0.0201416015625 +8461 -0.53948974609375 +8462 -0.01611328125 +8463 -0.43511962890625 +8464 -0.010772705078125 +8465 -0.2962646484375 +8466 -0.00592041015625 +8467 -0.161102294921875 +8468 -0.002105712890625 +8469 -0.0435791015625 +8470 0.00103759765625 +8471 0.060394287109375 +8472 0.002899169921875 +8473 0.13665771484375 +8474 0.00286865234375 +8475 0.170135498046875 +8476 0.00128173828125 +8477 0.16552734375 +8478 -3.0517578125e-05 +8479 0.15728759765625 +8480 -0.000762939453125 +8481 0.150787353515625 +8482 -0.0020751953125 +8483 0.12200927734375 +8484 -0.003570556640625 +8485 0.080108642578125 +8486 -0.00396728515625 +8487 0.05126953125 +8488 -0.001983642578125 +8489 0.062896728515625 +8490 0.00115966796875 +8491 0.09271240234375 +8492 0.002960205078125 +8493 0.092987060546875 +8494 0.004058837890625 +8495 0.07855224609375 +8496 0.005126953125 +8497 0.06427001953125 +8498 0.005279541015625 +8499 0.0347900390625 +8500 0.00433349609375 +8501 -0.01171875 +8502 0.003173828125 +8503 -0.056060791015625 +8504 0.00390625 +8505 -0.055511474609375 +8506 0.0064697265625 +8507 -0.010467529296875 +8508 0.008148193359375 +8509 0.02508544921875 +8510 0.0076904296875 +8511 0.025665283203125 +8512 0.006439208984375 +8513 0.017333984375 +8514 0.004547119140625 +8515 0.00189208984375 +8516 0.001556396484375 +8517 -0.03173828125 +8518 -0.001861572265625 +8519 -0.071502685546875 +8520 -0.006500244140625 +8521 -0.13543701171875 +8522 -0.012115478515625 +8523 -0.219970703125 +8524 -0.01739501953125 +8525 -0.300506591796875 +8526 -0.022216796875 +8527 -0.376312255859375 +8528 -0.02496337890625 +8529 -0.416107177734375 +8530 -0.023193359375 +8531 -0.371124267578125 +8532 -0.016937255859375 +8533 -0.242279052734375 +8534 -0.008209228515625 +8535 -0.069732666015625 +8536 0.00189208984375 +8537 0.125640869140625 +8538 0.011810302734375 +8539 0.31268310546875 +8540 0.0196533203125 +8541 0.45501708984375 +8542 0.025482177734375 +8543 0.554779052734375 +8544 0.029205322265625 +8545 0.61065673828125 +8546 0.030181884765625 +8547 0.610931396484375 +8548 0.02716064453125 +8549 0.531463623046875 +8550 0.020904541015625 +8551 0.3883056640625 +8552 0.014007568359375 +8553 0.23468017578125 +8554 0.0076904296875 +8555 0.095245361328125 +8556 0.003204345703125 +8557 -0.00396728515625 +8558 0.001220703125 +8559 -0.04852294921875 +8560 0.00091552734375 +8561 -0.055145263671875 +8562 -0.000274658203125 +8563 -0.0758056640625 +8564 -0.00372314453125 +8565 -0.138702392578125 +8566 -0.0076904296875 +8567 -0.209197998046875 +8568 -0.01220703125 +8569 -0.289031982421875 +8570 -0.017303466796875 +8571 -0.37884521484375 +8572 -0.0218505859375 +8573 -0.456329345703125 +8574 -0.0255126953125 +8575 -0.51641845703125 +8576 -0.026275634765625 +8577 -0.519287109375 +8578 -0.023773193359375 +8579 -0.458251953125 +8580 -0.020538330078125 +8581 -0.384796142578125 +8582 -0.017822265625 +8583 -0.323699951171875 +8584 -0.015289306640625 +8585 -0.269287109375 +8586 -0.0115966796875 +8587 -0.1951904296875 +8588 -0.0067138671875 +8589 -0.100006103515625 +8590 -0.001983642578125 +8591 -0.01055908203125 +8592 0.0040283203125 +8593 0.1033935546875 +8594 0.01165771484375 +8595 0.24908447265625 +8596 0.018218994140625 +8597 0.373199462890625 +8598 0.0228271484375 +8599 0.45806884765625 +8600 0.025848388671875 +8601 0.511474609375 +8602 0.028900146484375 +8603 0.565399169921875 +8604 0.031494140625 +8605 0.61138916015625 +8606 0.0306396484375 +8607 0.5897216796875 +8608 0.025848388671875 +8609 0.4906005859375 +8610 0.017974853515625 +8611 0.33148193359375 +8612 0.0087890625 +8613 0.147796630859375 +8614 0.000396728515625 +8615 -0.01873779296875 +8616 -0.00579833984375 +8617 -0.140289306640625 +8618 -0.008544921875 +8619 -0.191986083984375 +8620 -0.00836181640625 +8621 -0.184295654296875 +8622 -0.0074462890625 +8623 -0.161834716796875 +8624 -0.007904052734375 +8625 -0.166595458984375 +8626 -0.00946044921875 +8627 -0.19390869140625 +8628 -0.01116943359375 +8629 -0.22442626953125 +8630 -0.01409912109375 +8631 -0.279754638671875 +8632 -0.017181396484375 +8633 -0.3389892578125 +8634 -0.018035888671875 +8635 -0.3543701171875 +8636 -0.01776123046875 +8637 -0.348175048828125 +8638 -0.0166015625 +8639 -0.32598876953125 +8640 -0.01312255859375 +8641 -0.2581787109375 +8642 -0.007080078125 +8643 -0.139801025390625 +8644 0.000762939453125 +8645 0.014617919921875 +8646 0.00732421875 +8647 0.144378662109375 +8648 0.011199951171875 +8649 0.221038818359375 +8650 0.013702392578125 +8651 0.27069091796875 +8652 0.014892578125 +8653 0.294036865234375 +8654 0.01580810546875 +8655 0.311767578125 +8656 0.017242431640625 +8657 0.339141845703125 +8658 0.0184326171875 +8659 0.360260009765625 +8660 0.018646240234375 +8661 0.360504150390625 +8662 0.01605224609375 +8663 0.308380126953125 +8664 0.0093994140625 +8665 0.18170166015625 +8666 3.0517578125e-05 +8667 0.0047607421875 +8668 -0.009490966796875 +8669 -0.17559814453125 +8670 -0.016693115234375 +8671 -0.3143310546875 +8672 -0.019195556640625 +8673 -0.36785888671875 +8674 -0.018463134765625 +8675 -0.36248779296875 +8676 -0.017059326171875 +8677 -0.343536376953125 +8678 -0.014495849609375 +8679 -0.3018798828125 +8680 -0.01043701171875 +8681 -0.231414794921875 +8682 -0.00408935546875 +8683 -0.117645263671875 +8684 0.002685546875 +8685 0.007049560546875 +8686 0.006866455078125 +8687 0.087982177734375 +8688 0.009307861328125 +8689 0.13946533203125 +8690 0.0107421875 +8691 0.17425537109375 +8692 0.010986328125 +8693 0.188201904296875 +8694 0.009490966796875 +8695 0.171234130859375 +8696 0.006011962890625 +8697 0.118438720703125 +8698 0.00213623046875 +8699 0.05706787109375 +8700 -0.001983642578125 +8701 -0.010711669921875 +8702 -0.0067138671875 +8703 -0.0914306640625 +8704 -0.011199951171875 +8705 -0.162322998046875 +8706 -0.013641357421875 +8707 -0.194549560546875 +8708 -0.01031494140625 +8709 -0.1492919921875 +8710 -0.000396728515625 +8711 -0.02166748046875 +8712 0.0107421875 +8713 0.124053955078125 +8714 0.016632080078125 +8715 0.211151123046875 +8716 0.017608642578125 +8717 0.240447998046875 +8718 0.016510009765625 +8719 0.242218017578125 +8720 0.014251708984375 +8721 0.2257080078125 +8722 0.011199951171875 +8723 0.194366455078125 +8724 0.00445556640625 +8725 0.115509033203125 +8726 -0.003875732421875 +8727 0.0128173828125 +8728 -0.00860595703125 +8729 -0.053802490234375 +8730 -0.012176513671875 +8731 -0.110626220703125 +8732 -0.01837158203125 +8733 -0.199493408203125 +8734 -0.0250244140625 +8735 -0.29437255859375 +8736 -0.02667236328125 +8737 -0.33221435546875 +8738 -0.0205078125 +8739 -0.27972412109375 +8740 -0.010894775390625 +8741 -0.185333251953125 +8742 -0.004852294921875 +8743 -0.128204345703125 +8744 -0.00311279296875 +8745 -0.115692138671875 +8746 -0.002899169921875 +8747 -0.116455078125 +8748 -0.0020751953125 +8749 -0.105926513671875 +8750 0.001983642578125 +8751 -0.053955078125 +8752 0.010162353515625 +8753 0.048797607421875 +8754 0.0185546875 +8755 0.157318115234375 +8756 0.02197265625 +8757 0.212005615234375 +8758 0.02099609375 +8759 0.218475341796875 +8760 0.021026611328125 +8761 0.23724365234375 +8762 0.025421142578125 +8763 0.30535888671875 +8764 0.03057861328125 +8765 0.38128662109375 +8766 0.031280517578125 +8767 0.404449462890625 +8768 0.029327392578125 +8769 0.3944091796875 +8770 0.028045654296875 +8771 0.3885498046875 +8772 0.025360107421875 +8773 0.362640380859375 +8774 0.017486572265625 +8775 0.27362060546875 +8776 0.004058837890625 +8777 0.11712646484375 +8778 -0.0103759765625 +8779 -0.054901123046875 +8780 -0.02130126953125 +8781 -0.19085693359375 +8782 -0.02838134765625 +8783 -0.28570556640625 +8784 -0.03167724609375 +8785 -0.339263916015625 +8786 -0.033538818359375 +8787 -0.3775634765625 +8788 -0.03802490234375 +8789 -0.445709228515625 +8790 -0.04443359375 +8791 -0.535064697265625 +8792 -0.051422119140625 +8793 -0.629058837890625 +8794 -0.056365966796875 +8795 -0.697601318359375 +8796 -0.056121826171875 +8797 -0.70391845703125 +8798 -0.050201416015625 +8799 -0.6424560546875 +8800 -0.0367431640625 +8801 -0.491241455078125 +8802 -0.017059326171875 +8803 -0.265716552734375 +8804 0.00372314453125 +8805 -0.023712158203125 +8806 0.022735595703125 +8807 0.201751708984375 +8808 0.036956787109375 +8809 0.375823974609375 +8810 0.0452880859375 +8811 0.485076904296875 +8812 0.05126953125 +8813 0.56884765625 +8814 0.0556640625 +8815 0.634765625 +8816 0.054595947265625 +8817 0.63763427734375 +8818 0.047088623046875 +8819 0.5660400390625 +8820 0.03778076171875 +8821 0.4720458984375 +8822 0.03125 +8823 0.40692138671875 +8824 0.028167724609375 +8825 0.3778076171875 +8826 0.027862548828125 +8827 0.376953125 +8828 0.027496337890625 +8829 0.371978759765625 +8830 0.02264404296875 +8831 0.313140869140625 +8832 0.01190185546875 +8833 0.184417724609375 +8834 -0.00250244140625 +8835 0.011199951171875 +8836 -0.017486572265625 +8837 -0.171051025390625 +8838 -0.03094482421875 +8839 -0.33740234375 +8840 -0.041534423828125 +8841 -0.47198486328125 +8842 -0.048065185546875 +8843 -0.560394287109375 +8844 -0.048675537109375 +8845 -0.58056640625 +8846 -0.04473876953125 +8847 -0.54754638671875 +8848 -0.040496826171875 +8849 -0.508575439453125 +8850 -0.035614013671875 +8851 -0.459503173828125 +8852 -0.029571533203125 +8853 -0.394378662109375 +8854 -0.02581787109375 +8855 -0.35260009765625 +8856 -0.022369384765625 +8857 -0.31170654296875 +8858 -0.0126953125 +8859 -0.197418212890625 +8860 0.00335693359375 +8861 -0.007965087890625 +8862 0.021453857421875 +8863 0.207489013671875 +8864 0.038177490234375 +8865 0.409210205078125 +8866 0.0513916015625 +8867 0.57208251953125 +8868 0.058502197265625 +8869 0.66595458984375 +8870 0.0567626953125 +8871 0.65875244140625 +8872 0.047698974609375 +8873 0.56744384765625 +8874 0.03485107421875 +8875 0.431396484375 +8876 0.022125244140625 +8877 0.29443359375 +8878 0.011810302734375 +8879 0.182464599609375 +8880 0.00115966796875 +8881 0.06365966796875 +8882 -0.01104736328125 +8883 -0.075958251953125 +8884 -0.02069091796875 +8885 -0.189422607421875 +8886 -0.027313232421875 +8887 -0.271942138671875 +8888 -0.032684326171875 +8889 -0.342529296875 +8890 -0.03363037109375 +8891 -0.364166259765625 +8892 -0.02935791015625 +8893 -0.327239990234375 +8894 -0.023895263671875 +8895 -0.2769775390625 +8896 -0.02081298828125 +8897 -0.253692626953125 +8898 -0.01898193359375 +8899 -0.24365234375 +8900 -0.014190673828125 +8901 -0.1983642578125 +8902 -0.006317138671875 +8903 -0.116241455078125 +8904 0.001068115234375 +8905 -0.036834716796875 +8906 0.007537841796875 +8907 0.034881591796875 +8908 0.01239013671875 +8909 0.09124755859375 +8910 0.013580322265625 +8911 0.10888671875 +8912 0.01446533203125 +8913 0.125518798828125 +8914 0.01654052734375 +8915 0.15771484375 +8916 0.017486572265625 +8917 0.17828369140625 +8918 0.015899658203125 +8919 0.17108154296875 +8920 0.011322021484375 +8921 0.129974365234375 +8922 0.006195068359375 +8923 0.082427978515625 +8924 0.000518798828125 +8925 0.027679443359375 +8926 -0.00836181640625 +8927 -0.065643310546875 +8928 -0.017059326171875 +8929 -0.15936279296875 +8930 -0.02203369140625 +8931 -0.21307373046875 +8932 -0.023956298828125 +8933 -0.234649658203125 +8934 -0.020751953125 +8935 -0.2001953125 +8936 -0.013275146484375 +8937 -0.119171142578125 +8938 -0.00445556640625 +8939 -0.024749755859375 +8940 0.005889892578125 +8941 0.085784912109375 +8942 0.014678955078125 +8943 0.178131103515625 +8944 0.018646240234375 +8945 0.215576171875 +8946 0.018951416015625 +8947 0.211456298828125 +8948 0.01641845703125 +8949 0.17523193359375 +8950 0.012939453125 +8951 0.128753662109375 +8952 0.011077880859375 +8953 0.1019287109375 +8954 0.009033203125 +8955 0.0743408203125 +8956 0.006561279296875 +8957 0.04327392578125 +8958 0.006195068359375 +8959 0.038177490234375 +8960 0.010009765625 +8961 0.076263427734375 +8962 0.01702880859375 +8963 0.14105224609375 +8964 0.022308349609375 +8965 0.186431884765625 +8966 0.022857666015625 +8967 0.188812255859375 +8968 0.017425537109375 +8969 0.1390380859375 +8970 0.006439208984375 +8971 0.041778564453125 +8972 -0.007354736328125 +8973 -0.079437255859375 +8974 -0.0234375 +8975 -0.219390869140625 +8976 -0.040618896484375 +8977 -0.367828369140625 +8978 -0.055419921875 +8979 -0.494873046875 +8980 -0.06256103515625 +8981 -0.556243896484375 +8982 -0.056884765625 +8983 -0.508697509765625 +8984 -0.041168212890625 +8985 -0.3756103515625 +8986 -0.022857666015625 +8987 -0.218902587890625 +8988 -0.004913330078125 +8989 -0.063751220703125 +8990 0.012847900390625 +8991 0.091552734375 +8992 0.029205322265625 +8993 0.23602294921875 +8994 0.041015625 +8995 0.342987060546875 +8996 0.0462646484375 +8997 0.39520263671875 +8998 0.04461669921875 +8999 0.389373779296875 +9000 0.0360107421875 +9001 0.324249267578125 +9002 0.023406982421875 +9003 0.224090576171875 +9004 0.011077880859375 +9005 0.124267578125 +9006 0.00048828125 +9007 0.037078857421875 +9008 -0.005035400390625 +9009 -0.010101318359375 +9010 -0.00579833984375 +9011 -0.019439697265625 +9012 -0.005615234375 +9013 -0.022796630859375 +9014 -0.0023193359375 +9015 -0.001556396484375 +9016 0.00543212890625 +9017 0.056304931640625 +9018 0.012298583984375 +9019 0.106719970703125 +9020 0.011962890625 +9021 0.096893310546875 +9022 0.006256103515625 +9023 0.042694091796875 +9024 -0.00030517578125 +9025 -0.018035888671875 +9026 -0.006591796875 +9027 -0.07586669921875 +9028 -0.01129150390625 +9029 -0.11944580078125 +9030 -0.0157470703125 +9031 -0.15972900390625 +9032 -0.020660400390625 +9033 -0.202606201171875 +9034 -0.026123046875 +9035 -0.24859619140625 +9036 -0.032989501953125 +9037 -0.30517578125 +9038 -0.0400390625 +9039 -0.36212158203125 +9040 -0.0439453125 +9041 -0.39141845703125 +9042 -0.040130615234375 +9043 -0.35528564453125 +9044 -0.02813720703125 +9045 -0.249969482421875 +9046 -0.010009765625 +9047 -0.092864990234375 +9048 0.01104736328125 +9049 0.08905029296875 +9050 0.027801513671875 +9051 0.2352294921875 +9052 0.037109375 +9053 0.318817138671875 +9054 0.041259765625 +9055 0.358642578125 +9056 0.0394287109375 +9057 0.347747802734375 +9058 0.031585693359375 +9059 0.28564453125 +9060 0.023834228515625 +9061 0.223175048828125 +9062 0.020599365234375 +9063 0.196746826171875 +9064 0.0186767578125 +9065 0.179840087890625 +9066 0.016021728515625 +9067 0.155548095703125 +9068 0.015899658203125 +9069 0.151214599609375 +9070 0.01708984375 +9071 0.156951904296875 +9072 0.0146484375 +9073 0.13177490234375 +9074 0.011566162109375 +9075 0.100799560546875 +9076 0.010589599609375 +9077 0.087127685546875 +9078 0.007354736328125 +9079 0.05487060546875 +9080 0.000244140625 +9081 -0.009002685546875 +9082 -0.010650634765625 +9083 -0.10400390625 +9084 -0.0252685546875 +9085 -0.229400634765625 +9086 -0.040069580078125 +9087 -0.35552978515625 +9088 -0.05023193359375 +9089 -0.441925048828125 +9090 -0.053985595703125 +9091 -0.473846435546875 +9092 -0.052978515625 +9093 -0.464813232421875 +9094 -0.047698974609375 +9095 -0.419097900390625 +9096 -0.037841796875 +9097 -0.334320068359375 +9098 -0.025482177734375 +9099 -0.227935791015625 +9100 -0.013427734375 +9101 -0.12347412109375 +9102 -0.00244140625 +9103 -0.02764892578125 +9104 0.009674072265625 +9105 0.077667236328125 +9106 0.025421142578125 +9107 0.2132568359375 +9108 0.045989990234375 +9109 0.38885498046875 +9110 0.06878662109375 +9111 0.582794189453125 +9112 0.086517333984375 +9113 0.734039306640625 +9114 0.094085693359375 +9115 0.800140380859375 +9116 0.091217041015625 +9117 0.7783203125 +9118 0.0775146484375 +9119 0.6651611328125 +9120 0.0528564453125 +9121 0.45965576171875 +9122 0.021759033203125 +9123 0.199188232421875 +9124 -0.007904052734375 +9125 -0.050689697265625 +9126 -0.029296875 +9127 -0.23297119140625 +9128 -0.040374755859375 +9129 -0.33013916015625 +9130 -0.044342041015625 +9131 -0.368408203125 +9132 -0.04498291015625 +9133 -0.378936767578125 +9134 -0.044158935546875 +9135 -0.376983642578125 +9136 -0.043975830078125 +9137 -0.37969970703125 +9138 -0.044952392578125 +9139 -0.391510009765625 +9140 -0.043853759765625 +9141 -0.385345458984375 +9142 -0.038421630859375 +9143 -0.3419189453125 +9144 -0.031219482421875 +9145 -0.28289794921875 +9146 -0.0274658203125 +9147 -0.251617431640625 +9148 -0.029327392578125 +9149 -0.266143798828125 +9150 -0.030426025390625 +9151 -0.273345947265625 +9152 -0.023956298828125 +9153 -0.216796875 +9154 -0.01373291015625 +9155 -0.128265380859375 +9156 -0.006927490234375 +9157 -0.068145751953125 +9158 -0.00433349609375 +9159 -0.0430908203125 +9160 -0.00250244140625 +9161 -0.024444580078125 +9162 0.00250244140625 +9163 0.020721435546875 +9164 0.014556884765625 +9165 0.124481201171875 +9166 0.030181884765625 +9167 0.25787353515625 +9168 0.044403076171875 +9169 0.379119873046875 +9170 0.05621337890625 +9171 0.47991943359375 +9172 0.061798095703125 +9173 0.5281982421875 +9174 0.059600830078125 +9175 0.511138916015625 +9176 0.052947998046875 +9177 0.456207275390625 +9178 0.047119140625 +9179 0.407470703125 +9180 0.044403076171875 +9181 0.383758544921875 +9182 0.041351318359375 +9183 0.35687255859375 +9184 0.03619384765625 +9185 0.31182861328125 +9186 0.0291748046875 +9187 0.250885009765625 +9188 0.019256591796875 +9189 0.1654052734375 +9190 0.003997802734375 +9191 0.035247802734375 +9192 -0.016876220703125 +9193 -0.142059326171875 +9194 -0.039703369140625 +9195 -0.33563232421875 +9196 -0.06317138671875 +9197 -0.5345458984375 +9198 -0.08526611328125 +9199 -0.72186279296875 +9200 -0.098663330078125 +9201 -0.836669921875 +9202 -0.097869873046875 +9203 -0.8326416015625 +9204 -0.08526611328125 +9205 -0.7296142578125 +9206 -0.0675048828125 +9207 -0.582550048828125 +9208 -0.0504150390625 +9209 -0.440093994140625 +9210 -0.036651611328125 +9211 -0.324310302734375 +9212 -0.022125244140625 +9213 -0.20147705078125 +9214 -0.003570556640625 +9215 -0.044647216796875 +9216 0.013336181640625 +9217 0.103973388671875 +9218 0.022918701171875 +9219 0.202392578125 +9220 0.02752685546875 +9221 0.264495849609375 +9222 0.034820556640625 +9223 0.338897705078125 +9224 0.04779052734375 +9225 0.443817138671875 +9226 0.061370849609375 +9227 0.545074462890625 +9228 0.07177734375 +9229 0.6173095703125 +9230 0.0777587890625 +9231 0.6524658203125 +9232 0.08123779296875 +9233 0.66339111328125 +9234 0.082977294921875 +9235 0.6561279296875 +9236 0.079132080078125 +9237 0.606781005859375 +9238 0.067352294921875 +9239 0.501190185546875 +9240 0.049407958984375 +9241 0.352783203125 +9242 0.02734375 +9243 0.176544189453125 +9244 -0.000213623046875 +9245 -0.034820556640625 +9246 -0.02996826171875 +9247 -0.258209228515625 +9248 -0.054351806640625 +9249 -0.44244384765625 +9250 -0.071685791015625 +9251 -0.5753173828125 +9252 -0.081390380859375 +9253 -0.65203857421875 +9254 -0.078857421875 +9255 -0.641632080078125 +9256 -0.066864013671875 +9257 -0.562164306640625 +9258 -0.0521240234375 +9259 -0.458038330078125 +9260 -0.037750244140625 +9261 -0.350555419921875 +9262 -0.02679443359375 +9263 -0.260528564453125 +9264 -0.01971435546875 +9265 -0.192108154296875 +9266 -0.01580810546875 +9267 -0.141937255859375 +9268 -0.013671875 +9269 -0.1021728515625 +9270 -0.011566162109375 +9271 -0.062896728515625 +9272 -0.0074462890625 +9273 -0.011932373046875 +9274 0.000701904296875 +9275 0.062835693359375 +9276 0.011138916015625 +9277 0.148712158203125 +9278 0.02337646484375 +9279 0.241729736328125 +9280 0.03857421875 +9281 0.34912109375 +9282 0.0546875 +9283 0.457305908203125 +9284 0.068328857421875 +9285 0.54388427734375 +9286 0.074005126953125 +9287 0.5728759765625 +9288 0.06585693359375 +9289 0.506591796875 +9290 0.044708251953125 +9291 0.351226806640625 +9292 0.016448974609375 +9293 0.146514892578125 +9294 -0.0111083984375 +9295 -0.05523681640625 +9296 -0.032379150390625 +9297 -0.21624755859375 +9298 -0.04730224609375 +9299 -0.334930419921875 +9300 -0.054779052734375 +9301 -0.402984619140625 +9302 -0.058135986328125 +9303 -0.4412841796875 +9304 -0.064483642578125 +9305 -0.49578857421875 +9306 -0.07293701171875 +9307 -0.5601806640625 +9308 -0.078460693359375 +9309 -0.600738525390625 +9310 -0.076019287109375 +9311 -0.584228515625 +9312 -0.060821533203125 +9313 -0.47930908203125 +9314 -0.03179931640625 +9315 -0.27935791015625 +9316 0.00738525390625 +9317 -0.0089111328125 +9318 0.047271728515625 +9319 0.268798828125 +9320 0.077178955078125 +9321 0.482818603515625 +9322 0.092803955078125 +9323 0.60369873046875 +9324 0.09716796875 +9325 0.650421142578125 +9326 0.096649169921875 +9327 0.66400146484375 +9328 0.0909423828125 +9329 0.6414794921875 +9330 0.07861328125 +9331 0.572540283203125 +9332 0.06597900390625 +9333 0.498138427734375 +9334 0.056304931640625 +9335 0.439453125 +9336 0.04644775390625 +9337 0.375518798828125 +9338 0.031524658203125 +9339 0.274505615234375 +9340 0.007293701171875 +9341 0.1087646484375 +9342 -0.022857666015625 +9343 -0.099395751953125 +9344 -0.054229736328125 +9345 -0.3182373046875 +9346 -0.087127685546875 +9347 -0.5489501953125 +9348 -0.11895751953125 +9349 -0.7738037109375 +9350 -0.14178466796875 +9351 -0.86383056640625 +9352 -0.15069580078125 +9353 -0.870391845703125 +9354 -0.148529052734375 +9355 -0.86895751953125 +9356 -0.137420654296875 +9357 -0.861053466796875 +9358 -0.11480712890625 +9359 -0.765869140625 +9360 -0.079010009765625 +9361 -0.5301513671875 +9362 -0.031158447265625 +9363 -0.214691162109375 +9364 0.02215576171875 +9365 0.137359619140625 +9366 0.07318115234375 +9367 0.474822998046875 +9368 0.1165771484375 +9369 0.76239013671875 +9370 0.1483154296875 +9371 0.867462158203125 +9372 0.1685791015625 +9373 0.870361328125 +9374 0.1756591796875 +9375 0.86480712890625 +9376 0.170501708984375 +9377 0.831817626953125 +9378 0.156951904296875 +9379 0.677581787109375 +9380 0.136016845703125 +9381 0.495880126953125 +9382 0.110626220703125 +9383 0.30767822265625 +9384 0.081146240234375 +9385 0.116180419921875 +9386 0.0428466796875 +9387 -0.110748291015625 +9388 -0.0052490234375 +9389 -0.381805419921875 +9390 -0.056671142578125 +9391 -0.6572265625 +9392 -0.102294921875 +9393 -0.857421875 +9394 -0.135650634765625 +9395 -0.870391845703125 +9396 -0.155731201171875 +9397 -0.870391845703125 +9398 -0.16668701171875 +9399 -0.86444091796875 +9400 -0.174041748046875 +9401 -0.85723876953125 +9402 -0.175140380859375 +9403 -0.790008544921875 +9404 -0.161834716796875 +9405 -0.62847900390625 +9406 -0.13372802734375 +9407 -0.3956298828125 +9408 -0.095916748046875 +9409 -0.126708984375 +9410 -0.0526123046875 +9411 0.150115966796875 +9412 -0.005645751953125 +9413 0.424041748046875 +9414 0.040802001953125 +9415 0.670623779296875 +9416 0.08087158203125 +9417 0.854522705078125 +9418 0.11187744140625 +9419 0.866485595703125 +9420 0.131500244140625 +9421 0.86920166015625 +9422 0.142547607421875 +9423 0.8653564453125 +9424 0.14715576171875 +9425 0.857147216796875 +9426 0.14495849609375 +9427 0.766845703125 +9428 0.136810302734375 +9429 0.628509521484375 +9430 0.12176513671875 +9431 0.462127685546875 +9432 0.103851318359375 +9433 0.297210693359375 +9434 0.084991455078125 +9435 0.14862060546875 +9436 0.061767578125 +9437 -0.00537109375 +9438 0.035400390625 +9439 -0.15753173828125 +9440 0.00537109375 +9441 -0.31304931640625 +9442 -0.0303955078125 +9443 -0.48876953125 +9444 -0.064788818359375 +9445 -0.6416015625 +9446 -0.09405517578125 +9447 -0.751373291015625 +9448 -0.121734619140625 +9449 -0.84619140625 +9450 -0.145660400390625 +9451 -0.861297607421875 +9452 -0.160858154296875 +9453 -0.863250732421875 +9454 -0.162567138671875 +9455 -0.856597900390625 +9456 -0.152740478515625 +9457 -0.7498779296875 +9458 -0.1402587890625 +9459 -0.624542236328125 +9460 -0.12188720703125 +9461 -0.47808837890625 +9462 -0.088836669921875 +9463 -0.253387451171875 +9464 -0.048065185546875 +9465 0.003692626953125 +9466 -0.010009765625 +9467 0.2257080078125 +9468 0.027191162109375 +9469 0.427154541015625 +9470 0.0684814453125 +9471 0.643218994140625 +9472 0.11285400390625 +9473 0.855926513671875 +9474 0.151580810546875 +9475 0.870361328125 +9476 0.176483154296875 +9477 0.870361328125 +9478 0.18890380859375 +9479 0.862762451171875 +9480 0.188232421875 +9481 0.79669189453125 +9482 0.17254638671875 +9483 0.595794677734375 +9484 0.14697265625 +9485 0.362152099609375 +9486 0.1163330078125 +9487 0.1270751953125 +9488 0.084136962890625 +9489 -0.086944580078125 +9490 0.050384521484375 +9491 -0.2784423828125 +9492 0.008270263671875 +9493 -0.484832763671875 +9494 -0.046142578125 +9495 -0.729583740234375 +9496 -0.103912353515625 +9497 -0.86688232421875 +9498 -0.153778076171875 +9499 -0.870391845703125 +9500 -0.195037841796875 +9501 -0.86859130859375 +9502 -0.227569580078125 +9503 -0.86279296875 +9504 -0.244903564453125 +9505 -0.817962646484375 +9506 -0.238739013671875 +9507 -0.6116943359375 +9508 -0.207763671875 +9509 -0.3128662109375 +9510 -0.158050537109375 +9511 0.039398193359375 +9512 -0.0931396484375 +9513 0.422821044921875 +9514 -0.0189208984375 +9515 0.805145263671875 +9516 0.052276611328125 +9517 0.870361328125 +9518 0.1102294921875 +9519 0.870361328125 +9520 0.153106689453125 +9521 0.860015869140625 +9522 0.179779052734375 +9523 0.727935791015625 +9524 0.189483642578125 +9525 0.48114013671875 +9526 0.186859130859375 +9527 0.2059326171875 +9528 0.17626953125 +9529 -0.06103515625 +9530 0.15966796875 +9531 -0.29913330078125 +9532 0.134429931640625 +9533 -0.516204833984375 +9534 0.0977783203125 +9535 -0.7252197265625 +9536 0.054229736328125 +9537 -0.85980224609375 +9538 0.010009765625 +9539 -0.870391845703125 +9540 -0.029510498046875 +9541 -0.870391845703125 +9542 -0.055511474609375 +9543 -0.858062744140625 +9544 -0.0673828125 +9545 -0.673004150390625 +9546 -0.07501220703125 +9547 -0.42694091796875 +9548 -0.086700439453125 +9549 -0.2100830078125 +9550 -0.102203369140625 +9551 -0.0362548828125 +9552 -0.11627197265625 +9553 0.10943603515625 +9554 -0.125335693359375 +9555 0.23516845703125 +9556 -0.12188720703125 +9557 0.373687744140625 +9558 -0.106353759765625 +9559 0.517791748046875 +9560 -0.090362548828125 +9561 0.602783203125 +9562 -0.07293701171875 +9563 0.635711669921875 +9564 -0.047943115234375 +9565 0.655181884765625 +9566 -0.01715087890625 +9567 0.65948486328125 +9568 0.018035888671875 +9569 0.651275634765625 +9570 0.053192138671875 +9571 0.61846923828125 +9572 0.08160400390625 +9573 0.53753662109375 +9574 0.10003662109375 +9575 0.404144287109375 +9576 0.1068115234375 +9577 0.22186279296875 +9578 0.102325439453125 +9579 0.003997802734375 +9580 0.0899658203125 +9581 -0.22100830078125 +9582 0.0736083984375 +9583 -0.42449951171875 +9584 0.0572509765625 +9585 -0.579833984375 +9586 0.04876708984375 +9587 -0.641876220703125 +9588 0.04693603515625 +9589 -0.6177978515625 +9590 0.039886474609375 +9591 -0.575531005859375 +9592 0.02655029296875 +9593 -0.526336669921875 +9594 0.016448974609375 +9595 -0.42645263671875 +9596 0.014556884765625 +9597 -0.2581787109375 +9598 0.01409912109375 +9599 -0.068695068359375 +9600 0.0079345703125 +9601 0.09222412109375 +9602 -0.000518798828125 +9603 0.232147216796875 +9604 -0.00946044921875 +9605 0.3509521484375 +9606 -0.0244140625 +9607 0.410064697265625 +9608 -0.050872802734375 +9609 0.372955322265625 +9610 -0.08502197265625 +9611 0.2554931640625 +9612 -0.11724853515625 +9613 0.10711669921875 +9614 -0.143951416015625 +9615 -0.052886962890625 +9616 -0.158477783203125 +9617 -0.186279296875 +9618 -0.150543212890625 +9619 -0.23291015625 +9620 -0.124267578125 +9621 -0.209442138671875 +9622 -0.091766357421875 +9623 -0.174163818359375 +9624 -0.054473876953125 +9625 -0.126739501953125 +9626 -0.010528564453125 +9627 -0.048126220703125 +9628 0.03485107421875 +9629 0.0426025390625 +9630 0.07318115234375 +9631 0.10748291015625 +9632 0.10205078125 +9633 0.1409912109375 +9634 0.1302490234375 +9635 0.19708251953125 +9636 0.15655517578125 +9637 0.273651123046875 +9638 0.17071533203125 +9639 0.31768798828125 +9640 0.1748046875 +9641 0.341094970703125 +9642 0.173431396484375 +9643 0.368011474609375 +9644 0.162353515625 +9645 0.37249755859375 +9646 0.132476806640625 +9647 0.30072021484375 +9648 0.08465576171875 +9649 0.1517333984375 +9650 0.0311279296875 +9651 -0.01470947265625 +9652 -0.024871826171875 +9653 -0.1883544921875 +9654 -0.0826416015625 +9655 -0.372711181640625 +9656 -0.131011962890625 +9657 -0.51397705078125 +9658 -0.161346435546875 +9659 -0.57177734375 +9660 -0.17144775390625 +9661 -0.53948974609375 +9662 -0.16387939453125 +9663 -0.43511962890625 +9664 -0.145050048828125 +9665 -0.2962646484375 +9666 -0.12176513671875 +9667 -0.161102294921875 +9668 -0.096649169921875 +9669 -0.0435791015625 +9670 -0.06927490234375 +9671 0.060394287109375 +9672 -0.042816162109375 +9673 0.13665771484375 +9674 -0.020843505859375 +9675 0.170135498046875 +9676 -0.003448486328125 +9677 0.16552734375 +9678 0.014617919921875 +9679 0.15728759765625 +9680 0.033233642578125 +9681 0.150787353515625 +9682 0.046875 +9683 0.12200927734375 +9684 0.056243896484375 +9685 0.080108642578125 +9686 0.06524658203125 +9687 0.05126953125 +9688 0.0782470703125 +9689 0.062896728515625 +9690 0.09063720703125 +9691 0.09271240234375 +9692 0.093414306640625 +9693 0.092987060546875 +9694 0.089263916015625 +9695 0.07855224609375 +9696 0.08111572265625 +9697 0.06427001953125 +9698 0.066558837890625 +9699 0.0347900390625 +9700 0.04583740234375 +9701 -0.01171875 +9702 0.02325439453125 +9703 -0.056060791015625 +9704 0.00750732421875 +9705 -0.055511474609375 +9706 -0.00054931640625 +9707 -0.010467529296875 +9708 -0.009918212890625 +9709 0.02508544921875 +9710 -0.024444580078125 +9711 0.025665283203125 +9712 -0.038543701171875 +9713 0.017333984375 +9714 -0.051300048828125 +9715 0.00189208984375 +9716 -0.06427001953125 +9717 -0.03173828125 +9718 -0.074951171875 +9719 -0.071502685546875 +9720 -0.086578369140625 +9721 -0.13543701171875 +9722 -0.098602294921875 +9723 -0.219970703125 +9724 -0.106781005859375 +9725 -0.300506591796875 +9726 -0.111419677734375 +9727 -0.376312255859375 +9728 -0.107269287109375 +9729 -0.416107177734375 +9730 -0.08587646484375 +9731 -0.371124267578125 +9732 -0.048187255859375 +9733 -0.242279052734375 +9734 -0.002593994140625 +9735 -0.069732666015625 +9736 0.046295166015625 +9737 0.125640869140625 +9738 0.0919189453125 +9739 0.31268310546875 +9740 0.126708984375 +9741 0.45501708984375 +9742 0.15087890625 +9743 0.554779052734375 +9744 0.1640625 +9745 0.61065673828125 +9746 0.16387939453125 +9747 0.610931396484375 +9748 0.145599365234375 +9749 0.531463623046875 +9750 0.11260986328125 +9751 0.3883056640625 +9752 0.07586669921875 +9753 0.23468017578125 +9754 0.040679931640625 +9755 0.095245361328125 +9756 0.012664794921875 +9757 -0.00396728515625 +9758 -0.004852294921875 +9759 -0.04852294921875 +9760 -0.014739990234375 +9761 -0.055145263671875 +9762 -0.026947021484375 +9763 -0.0758056640625 +9764 -0.046722412109375 +9765 -0.138702392578125 +9766 -0.066741943359375 +9767 -0.209197998046875 +9768 -0.08709716796875 +9769 -0.289031982421875 +9770 -0.107696533203125 +9771 -0.37884521484375 +9772 -0.123992919921875 +9773 -0.456329345703125 +9774 -0.134979248046875 +9775 -0.51641845703125 +9776 -0.1328125 +9777 -0.519287109375 +9778 -0.116363525390625 +9779 -0.458251953125 +9780 -0.09619140625 +9781 -0.384796142578125 +9782 -0.077545166015625 +9783 -0.323699951171875 +9784 -0.0596923828125 +9785 -0.269287109375 +9786 -0.0377197265625 +9787 -0.1951904296875 +9788 -0.01177978515625 +9789 -0.100006103515625 +9790 0.012359619140625 +9791 -0.01055908203125 +9792 0.0404052734375 +9793 0.1033935546875 +9794 0.073577880859375 +9795 0.24908447265625 +9796 0.10101318359375 +9797 0.373199462890625 +9798 0.11907958984375 +9799 0.45806884765625 +9800 0.129302978515625 +9801 0.511474609375 +9802 0.13818359375 +9803 0.565399169921875 +9804 0.144134521484375 +9805 0.61138916015625 +9806 0.13543701171875 +9807 0.5897216796875 +9808 0.11041259765625 +9809 0.4906005859375 +9810 0.0728759765625 +9811 0.33148193359375 +9812 0.030242919921875 +9813 0.147796630859375 +9814 -0.008819580078125 +9815 -0.01873779296875 +9816 -0.038421630859375 +9817 -0.140289306640625 +9818 -0.053314208984375 +9819 -0.191986083984375 +9820 -0.055389404296875 +9821 -0.184295654296875 +9822 -0.053375244140625 +9823 -0.161834716796875 +9824 -0.055572509765625 +9825 -0.166595458984375 +9826 -0.061004638671875 +9827 -0.19390869140625 +9828 -0.065826416015625 +9829 -0.22442626953125 +9830 -0.074493408203125 +9831 -0.279754638671875 +9832 -0.082977294921875 +9833 -0.3389892578125 +9834 -0.081939697265625 +9835 -0.3543701171875 +9836 -0.076080322265625 +9837 -0.348175048828125 +9838 -0.0667724609375 +9839 -0.32598876953125 +9840 -0.04840087890625 +9841 -0.2581787109375 +9842 -0.02020263671875 +9843 -0.139801025390625 +9844 0.014678955078125 +9845 0.014617919921875 +9846 0.043853759765625 +9847 0.144378662109375 +9848 0.061492919921875 +9849 0.221038818359375 +9850 0.072723388671875 +9851 0.27069091796875 +9852 0.07763671875 +9853 0.294036865234375 +9854 0.080413818359375 +9855 0.311767578125 +9856 0.084228515625 +9857 0.339141845703125 +9858 0.086181640625 +9859 0.360260009765625 +9860 0.083465576171875 +9861 0.360504150390625 +9862 0.069366455078125 +9863 0.308380126953125 +9864 0.0391845703125 +9865 0.18170166015625 +9866 -0.001678466796875 +9867 0.0047607421875 +9868 -0.042999267578125 +9869 -0.17559814453125 +9870 -0.074951171875 +9871 -0.3143310546875 +9872 -0.088043212890625 +9873 -0.36785888671875 +9874 -0.087890625 +9875 -0.36248779296875 +9876 -0.084259033203125 +9877 -0.343536376953125 +9878 -0.0751953125 +9879 -0.3018798828125 +9880 -0.05938720703125 +9881 -0.231414794921875 +9882 -0.033721923828125 +9883 -0.117645263671875 +9884 -0.005279541015625 +9885 0.007049560546875 +9886 0.0140380859375 +9887 0.087982177734375 +9888 0.027191162109375 +9889 0.13946533203125 +9890 0.036834716796875 +9891 0.17425537109375 +9892 0.041961669921875 +9893 0.188201904296875 +9894 0.040252685546875 +9895 0.171234130859375 +9896 0.03057861328125 +9897 0.118438720703125 +9898 0.018768310546875 +9899 0.05706787109375 +9900 0.00518798828125 +9901 -0.010711669921875 +9902 -0.0115966796875 +9903 -0.0914306640625 +9904 -0.026702880859375 +9905 -0.162322998046875 +9906 -0.033905029296875 +9907 -0.194549560546875 +9908 -0.0247802734375 +9909 -0.1492919921875 +9910 0.001739501953125 +9911 -0.02166748046875 +9912 0.0318603515625 +9913 0.124053955078125 +9914 0.049041748046875 +9915 0.211151123046875 +9916 0.0535888671875 +9917 0.240447998046875 +9918 0.052154541015625 +9919 0.242218017578125 +9920 0.04681396484375 +9921 0.2257080078125 +9922 0.038421630859375 +9923 0.194366455078125 +9924 0.019989013671875 +9925 0.115509033203125 +9926 -0.003204345703125 +9927 0.0128173828125 +9928 -0.0181884765625 +9929 -0.053802490234375 +9930 -0.0306396484375 +9931 -0.110626220703125 +9932 -0.049591064453125 +9933 -0.199493408203125 +9934 -0.069488525390625 +9935 -0.29437255859375 +9936 -0.076751708984375 +9937 -0.33221435546875 +9938 -0.06427001953125 +9939 -0.27972412109375 +9940 -0.04254150390625 +9941 -0.185333251953125 +9942 -0.028717041015625 +9943 -0.128204345703125 +9944 -0.024505615234375 +9945 -0.115692138671875 +9946 -0.023193359375 +9947 -0.116455078125 +9948 -0.01959228515625 +9949 -0.105926513671875 +9950 -0.007232666015625 +9951 -0.053955078125 +9952 0.01580810546875 +9953 0.048797607421875 +9954 0.039794921875 +9955 0.157318115234375 +9956 0.05181884765625 +9957 0.212005615234375 +9958 0.053070068359375 +9959 0.218475341796875 +9960 0.056671142578125 +9961 0.23724365234375 +9962 0.070648193359375 +9963 0.30535888671875 +9964 0.0860595703125 +9965 0.38128662109375 +9966 0.089874267578125 +9967 0.404449462890625 +9968 0.086395263671875 +9969 0.3944091796875 +9970 0.08380126953125 +9971 0.3885498046875 +9972 0.076934814453125 +9973 0.362640380859375 +9974 0.056549072265625 +9975 0.27362060546875 +9976 0.021759033203125 +9977 0.11712646484375 +9978 -0.01611328125 +9979 -0.054901123046875 +9980 -0.0458984375 +9981 -0.19085693359375 +9982 -0.066497802734375 +9983 -0.28570556640625 +9984 -0.0772705078125 +9985 -0.339263916015625 +9986 -0.0841064453125 +9987 -0.3775634765625 +9988 -0.0982666015625 +9989 -0.445709228515625 +9990 -0.118011474609375 +9991 -0.535064697265625 +9992 -0.13958740234375 +9993 -0.629058837890625 +9994 -0.15576171875 +9995 -0.697601318359375 +9996 -0.15753173828125 +9997 -0.70391845703125 +9998 -0.143524169921875 +9999 -0.6424560546875 +10000 -0.10821533203125 +10001 -0.491241455078125 +10002 -0.0552978515625 +10003 -0.265716552734375 +10004 0.001068115234375 +10005 -0.023712158203125 +10006 0.05291748046875 +10007 0.201751708984375 +10008 0.091888427734375 +10009 0.375823974609375 +10010 0.1148681640625 +10011 0.485076904296875 +10012 0.131866455078125 +10013 0.56884765625 +10014 0.144989013671875 +10015 0.634765625 +10016 0.143218994140625 +10017 0.63763427734375 +10018 0.12384033203125 +10019 0.5660400390625 +10020 0.099853515625 +10021 0.4720458984375 +10022 0.083953857421875 +10023 0.40692138671875 +10024 0.077911376953125 +10025 0.3778076171875 +10026 0.0797119140625 +10027 0.376953125 +10028 0.0811767578125 +10029 0.371978759765625 +10030 0.06982421875 +10031 0.313140869140625 +10032 0.041473388671875 +10033 0.184417724609375 +10034 0.002227783203125 +10035 0.011199951171875 +10036 -0.039276123046875 +10037 -0.171051025390625 +10038 -0.07708740234375 +10039 -0.33740234375 +10040 -0.107452392578125 +10041 -0.47198486328125 +10042 -0.126922607421875 +10043 -0.560394287109375 +10044 -0.13018798828125 +10045 -0.58056640625 +10046 -0.12103271484375 +10047 -0.54754638671875 +10048 -0.111236572265625 +10049 -0.508575439453125 +10050 -0.0997314453125 +10051 -0.459503173828125 +10052 -0.084991455078125 +10053 -0.394378662109375 +10054 -0.07666015625 +10055 -0.35260009765625 +10056 -0.06903076171875 +10057 -0.31170654296875 +10058 -0.04351806640625 +10059 -0.197418212890625 +10060 0.00042724609375 +10061 -0.007965087890625 +10062 0.050750732421875 +10063 0.207489013671875 +10064 0.0977783203125 +10065 0.409210205078125 +10066 0.135467529296875 +10067 0.57208251953125 +10068 0.156463623046875 +10069 0.66595458984375 +10070 0.152923583984375 +10071 0.65875244140625 +10072 0.129119873046875 +10073 0.56744384765625 +10074 0.09490966796875 +10075 0.431396484375 +10076 0.061126708984375 +10077 0.29443359375 +10078 0.034210205078125 +10079 0.182464599609375 +10080 0.00616455078125 +10081 0.06365966796875 +10082 -0.02655029296875 +10083 -0.075958251953125 +10084 -0.052398681640625 +10085 -0.189422607421875 +10086 -0.070281982421875 +10087 -0.271942138671875 +10088 -0.085052490234375 +10089 -0.342529296875 +10090 -0.0877685546875 +10091 -0.364166259765625 +10092 -0.076171875 +10093 -0.327239990234375 +10094 -0.06158447265625 +10095 -0.2769775390625 +10096 -0.054107666015625 +10097 -0.253692626953125 +10098 -0.0504150390625 +10099 -0.24365234375 +10100 -0.03857421875 +10101 -0.1983642578125 +10102 -0.0181884765625 +10103 -0.116241455078125 +10104 0.000946044921875 +10105 -0.036834716796875 +10106 0.01763916015625 +10107 0.034881591796875 +10108 0.030059814453125 +10109 0.09124755859375 +10110 0.032501220703125 +10111 0.10888671875 +10112 0.034423828125 +10113 0.125518798828125 +10114 0.04010009765625 +10115 0.15771484375 +10116 0.042877197265625 +10117 0.17828369140625 +10118 0.038909912109375 +10119 0.17108154296875 +10120 0.02679443359375 +10121 0.129974365234375 +10122 0.013458251953125 +10123 0.082427978515625 +10124 -0.001220703125 +10125 0.027679443359375 +10126 -0.024932861328125 +10127 -0.065643310546875 +10128 -0.0482177734375 +10129 -0.15936279296875 +10130 -0.06109619140625 +10131 -0.21307373046875 +10132 -0.0655517578125 +10133 -0.234649658203125 +10134 -0.05572509765625 +10135 -0.2001953125 +10136 -0.034027099609375 +10137 -0.119171142578125 +10138 -0.008819580078125 +10139 -0.024749755859375 +10140 0.020477294921875 +10141 0.085784912109375 +10142 0.04522705078125 +10143 0.178131103515625 +10144 0.056243896484375 +10145 0.215576171875 +10146 0.056732177734375 +10147 0.211456298828125 +10148 0.04901123046875 +10149 0.17523193359375 +10150 0.038421630859375 +10151 0.128753662109375 +10152 0.032318115234375 +10153 0.1019287109375 +10154 0.025634765625 +10155 0.0743408203125 +10156 0.0177001953125 +10157 0.04327392578125 +10158 0.01580810546875 +10159 0.038177490234375 +10160 0.0242919921875 +10161 0.076263427734375 +10162 0.039093017578125 +10163 0.14105224609375 +10164 0.04888916015625 +10165 0.186431884765625 +10166 0.04791259765625 +10167 0.188812255859375 +10168 0.03399658203125 +10169 0.1390380859375 +10170 0.008392333984375 +10171 0.041778564453125 +10172 -0.02294921875 +10173 -0.079437255859375 +10174 -0.058685302734375 +10175 -0.219390869140625 +10176 -0.096221923828125 +10177 -0.367828369140625 +10178 -0.12811279296875 +10179 -0.494873046875 +10180 -0.14337158203125 +10181 -0.556243896484375 +10182 -0.13128662109375 +10183 -0.508697509765625 +10184 -0.09771728515625 +10185 -0.3756103515625 +10186 -0.05804443359375 +10187 -0.218902587890625 +10188 -0.018585205078125 +10189 -0.063751220703125 +10190 0.02099609375 +10191 0.091552734375 +10192 0.057952880859375 +10193 0.23602294921875 +10194 0.0855712890625 +10195 0.342987060546875 +10196 0.099578857421875 +10197 0.39520263671875 +10198 0.099090576171875 +10199 0.389373779296875 +10200 0.083709716796875 +10201 0.324249267578125 +10202 0.0594482421875 +10203 0.224090576171875 +10204 0.0350341796875 +10205 0.124267578125 +10206 0.0135498046875 +10207 0.037078857421875 +10208 0.001739501953125 +10209 -0.010101318359375 +10210 -0.000885009765625 +10211 -0.019439697265625 +10212 -0.002197265625 +10213 -0.022796630859375 +10214 0.002410888671875 +10215 -0.001556396484375 +10216 0.015960693359375 +10217 0.056304931640625 +10218 0.02752685546875 +10219 0.106719970703125 +10220 0.02410888671875 +10221 0.096893310546875 +10222 0.00970458984375 +10223 0.042694091796875 +10224 -0.0062255859375 +10225 -0.018035888671875 +10226 -0.021270751953125 +10227 -0.07586669921875 +10228 -0.0325927734375 +10229 -0.11944580078125 +10230 -0.04290771484375 +10231 -0.15972900390625 +10232 -0.05364990234375 +10233 -0.202606201171875 +10234 -0.064910888671875 +10235 -0.24859619140625 +10236 -0.078582763671875 +10237 -0.30517578125 +10238 -0.0921630859375 +10239 -0.36212158203125 +10240 -0.0986328125 +10241 -0.39141845703125 +10242 -0.088531494140625 +10243 -0.35528564453125 +10244 -0.06103515625 +10245 -0.249969482421875 +10246 -0.0203857421875 +10247 -0.092864990234375 +10248 0.026458740234375 +10249 0.08905029296875 +10250 0.0631103515625 +10251 0.2352294921875 +10252 0.082489013671875 +10253 0.318817138671875 +10254 0.0902099609375 +10255 0.358642578125 +10256 0.084564208984375 +10257 0.347747802734375 +10258 0.065582275390625 +10259 0.28564453125 +10260 0.04754638671875 +10261 0.223175048828125 +10262 0.0406494140625 +10263 0.196746826171875 +10264 0.037384033203125 +10265 0.179840087890625 +10266 0.032867431640625 +10267 0.155548095703125 +10268 0.034576416015625 +10269 0.151214599609375 +10270 0.03955078125 +10271 0.156951904296875 +10272 0.03607177734375 +10273 0.13177490234375 +10274 0.030975341796875 +10275 0.100799560546875 +10276 0.030487060546875 +10277 0.087127685546875 +10278 0.024383544921875 +10279 0.05487060546875 +10280 0.00885009765625 +10281 -0.009002685546875 +10282 -0.01605224609375 +10283 -0.10400390625 +10284 -0.05023193359375 +10285 -0.229400634765625 +10286 -0.085418701171875 +10287 -0.35552978515625 +10288 -0.110260009765625 +10289 -0.441925048828125 +10290 -0.120574951171875 +10291 -0.473846435546875 +10292 -0.120025634765625 +10293 -0.464813232421875 +10294 -0.10968017578125 +10295 -0.419097900390625 +10296 -0.088714599609375 +10297 -0.334320068359375 +10298 -0.061859130859375 +10299 -0.227935791015625 +10300 -0.035552978515625 +10301 -0.12347412109375 +10302 -0.011505126953125 +10303 -0.02764892578125 +10304 0.015472412109375 +10305 0.077667236328125 +10306 0.05133056640625 +10307 0.2132568359375 +10308 0.098907470703125 +10309 0.38885498046875 +10310 0.1522216796875 +10311 0.582794189453125 +10312 0.194183349609375 +10313 0.734039306640625 +10314 0.212890625 +10315 0.800140380859375 +10316 0.207550048828125 +10317 0.7783203125 +10318 0.177154541015625 +10319 0.6651611328125 +10320 0.12139892578125 +10321 0.45965576171875 +10322 0.050628662109375 +10323 0.199188232421875 +10324 -0.01690673828125 +10325 -0.050689697265625 +10326 -0.065399169921875 +10327 -0.23297119140625 +10328 -0.090087890625 +10329 -0.33013916015625 +10330 -0.098480224609375 +10331 -0.368408203125 +10332 -0.099395751953125 +10333 -0.378936767578125 +10334 -0.09722900390625 +10335 -0.376983642578125 +10336 -0.096893310546875 +10337 -0.37969970703125 +10338 -0.099609375 +10339 -0.391510009765625 +10340 -0.097869873046875 +10341 -0.385345458984375 +10342 -0.086212158203125 +10343 -0.3419189453125 +10344 -0.0706787109375 +10345 -0.28289794921875 +10346 -0.063323974609375 +10347 -0.251617431640625 +10348 -0.069091796875 +10349 -0.266143798828125 +10350 -0.073028564453125 +10351 -0.273345947265625 +10352 -0.059234619140625 +10353 -0.216796875 +10354 -0.0364990234375 +10355 -0.128265380859375 +10356 -0.0216064453125 +10357 -0.068145751953125 +10358 -0.01629638671875 +10359 -0.0430908203125 +10360 -0.012481689453125 +10361 -0.024444580078125 +10362 -0.0008544921875 +10363 0.020721435546875 +10364 0.027587890625 +10365 0.124481201171875 +10366 0.064727783203125 +10367 0.25787353515625 +10368 0.098876953125 +10369 0.379119873046875 +10370 0.127685546875 +10371 0.47991943359375 +10372 0.142120361328125 +10373 0.5281982421875 +10374 0.1385498046875 +10375 0.511138916015625 +10376 0.124603271484375 +10377 0.456207275390625 +10378 0.112518310546875 +10379 0.407470703125 +10380 0.10748291015625 +10381 0.383758544921875 +10382 0.101470947265625 +10383 0.35687255859375 +10384 0.090240478515625 +10385 0.31182861328125 +10386 0.0743408203125 +10387 0.250885009765625 +10388 0.051300048828125 +10389 0.1654052734375 +10390 0.01544189453125 +10391 0.035247802734375 +10392 -0.033935546875 +10393 -0.142059326171875 +10394 -0.088165283203125 +10395 -0.33563232421875 +10396 -0.1441650390625 +10397 -0.5345458984375 +10398 -0.197174072265625 +10399 -0.72186279296875 +10400 -0.230072021484375 +10401 -0.836669921875 +10402 -0.229888916015625 +10403 -0.8326416015625 +10404 -0.202117919921875 +10405 -0.7296142578125 +10406 -0.162109375 +10407 -0.582550048828125 +10408 -0.1234130859375 +10409 -0.440093994140625 +10410 -0.092132568359375 +10411 -0.324310302734375 +10412 -0.058746337890625 +10413 -0.20147705078125 +10414 -0.015655517578125 +10415 -0.044647216796875 +10416 0.02532958984375 +10417 0.103973388671875 +10418 0.052490234375 +10419 0.202392578125 +10420 0.069732666015625 +10421 0.264495849609375 +10422 0.090667724609375 +10423 0.338897705078125 +10424 0.120361328125 +10425 0.443817138671875 +10426 0.14923095703125 +10427 0.545074462890625 +10428 0.170135498046875 +10429 0.6173095703125 +10430 0.1807861328125 +10431 0.6524658203125 +10432 0.18475341796875 +10433 0.66339111328125 +10434 0.18365478515625 +10435 0.6561279296875 +10436 0.170745849609375 +10437 0.606781005859375 +10438 0.141998291015625 +10439 0.501190185546875 +10440 0.10113525390625 +10441 0.352783203125 +10442 0.05230712890625 +10443 0.176544189453125 +10444 -0.0064697265625 +10445 -0.034820556640625 +10446 -0.068756103515625 +10447 -0.258209228515625 +10448 -0.1202392578125 +10449 -0.44244384765625 +10450 -0.15753173828125 +10451 -0.5753173828125 +10452 -0.17926025390625 +10453 -0.65203857421875 +10454 -0.176727294921875 +10455 -0.641632080078125 +10456 -0.154998779296875 +10457 -0.562164306640625 +10458 -0.126495361328125 +10459 -0.458038330078125 +10460 -0.09710693359375 +10461 -0.350555419921875 +10462 -0.072601318359375 +10463 -0.260528564453125 +10464 -0.05413818359375 +10465 -0.192108154296875 +10466 -0.040740966796875 +10467 -0.141937255859375 +10468 -0.030181884765625 +10469 -0.1021728515625 +10470 -0.0196533203125 +10471 -0.062896728515625 +10472 -0.00567626953125 +10473 -0.011932373046875 +10474 0.01507568359375 +10475 0.062835693359375 +10476 0.039093017578125 +10477 0.148712158203125 +10478 0.06524658203125 +10479 0.241729736328125 +10480 0.095550537109375 +10481 0.34912109375 +10482 0.126220703125 +10483 0.457305908203125 +10484 0.15093994140625 +10485 0.54388427734375 +10486 0.15960693359375 +10487 0.5728759765625 +10488 0.141632080078125 +10489 0.506591796875 +10490 0.098724365234375 +10491 0.351226806640625 +10492 0.041961669921875 +10493 0.146514892578125 +10494 -0.0140380859375 +10495 -0.05523681640625 +10496 -0.058990478515625 +10497 -0.21624755859375 +10498 -0.09228515625 +10499 -0.334930419921875 +10500 -0.11077880859375 +10501 -0.402984619140625 +10502 -0.121063232421875 +10503 -0.4412841796875 +10504 -0.13751220703125 +10505 -0.49578857421875 +10506 -0.1580810546875 +10507 -0.5601806640625 +10508 -0.17218017578125 +10509 -0.600738525390625 +10510 -0.1693115234375 +10511 -0.584228515625 +10512 -0.1395263671875 +10513 -0.47930908203125 +10514 -0.08056640625 +10515 -0.27935791015625 +10516 9.1552734375e-05 +10517 -0.0089111328125 +10518 0.082977294921875 +10519 0.268798828125 +10520 0.146148681640625 +10521 0.482818603515625 +10522 0.18060302734375 +10523 0.60369873046875 +10524 0.192413330078125 +10525 0.650421142578125 +10526 0.194549560546875 +10527 0.66400146484375 +10528 0.1861572265625 +10529 0.6414794921875 +10530 0.164093017578125 +10531 0.572540283203125 +10532 0.141143798828125 +10533 0.498138427734375 +10534 0.123870849609375 +10535 0.439453125 +10536 0.10565185546875 +10537 0.375518798828125 +10538 0.07647705078125 +10539 0.274505615234375 +10540 0.02752685546875 +10541 0.1087646484375 +10542 -0.03436279296875 +10543 -0.099395751953125 +10544 -0.099456787109375 +10545 -0.3182373046875 +10546 -0.1683349609375 +10547 -0.5489501953125 +10548 -0.235565185546875 +10549 -0.7738037109375 +10550 -0.284820556640625 +10551 -0.86383056640625 +10552 -0.30584716796875 +10553 -0.870391845703125 +10554 -0.304290771484375 +10555 -0.86895751953125 +10556 -0.2843017578125 +10557 -0.861053466796875 +10558 -0.240509033203125 +10559 -0.765869140625 +10560 -0.16937255859375 +10561 -0.5301513671875 +10562 -0.07305908203125 +10563 -0.214691162109375 +10564 0.035064697265625 +10565 0.137359619140625 +10566 0.13909912109375 +10567 0.474822998046875 +10568 0.22808837890625 +10569 0.76239013671875 +10570 0.29376220703125 +10571 0.867462158203125 +10572 0.336395263671875 +10573 0.870361328125 +10574 0.3525390625 +10575 0.86480712890625 +10576 0.343994140625 +10577 0.831817626953125 +10578 0.3184814453125 +10579 0.677581787109375 +10580 0.277923583984375 +10581 0.495880126953125 +10582 0.2281494140625 +10583 0.30767822265625 +10584 0.169891357421875 +10585 0.116180419921875 +10586 0.09326171875 +10587 -0.110748291015625 +10588 -0.00390625 +10589 -0.381805419921875 +10590 -0.10833740234375 +10591 -0.6572265625 +10592 -0.201385498046875 +10593 -0.857421875 +10594 -0.269805908203125 +10595 -0.870391845703125 +10596 -0.311492919921875 +10597 -0.870391845703125 +10598 -0.3349609375 +10599 -0.86444091796875 +10600 -0.351470947265625 +10601 -0.85723876953125 +10602 -0.35540771484375 +10603 -0.790008544921875 +10604 -0.3299560546875 +10605 -0.62847900390625 +10606 -0.27423095703125 +10607 -0.3956298828125 +10608 -0.198516845703125 +10609 -0.126708984375 +10610 -0.111419677734375 +10611 0.150115966796875 +10612 -0.0166015625 +10613 0.424041748046875 +10614 0.0775146484375 +10615 0.670623779296875 +10616 0.158905029296875 +10617 0.854522705078125 +10618 0.22210693359375 +10619 0.866485595703125 +10620 0.26239013671875 +10621 0.86920166015625 +10622 0.2855224609375 +10623 0.8653564453125 +10624 0.295806884765625 +10625 0.857147216796875 +10626 0.29241943359375 +10627 0.766845703125 +10628 0.277069091796875 +10629 0.628509521484375 +10630 0.24774169921875 +10631 0.462127685546875 +10632 0.21258544921875 +10633 0.297210693359375 +10634 0.17547607421875 +10635 0.14862060546875 +10636 0.129364013671875 +10637 -0.00537109375 +10638 0.07659912109375 +10639 -0.15753173828125 +10640 0.016082763671875 +10641 -0.31304931640625 +10642 -0.056549072265625 +10643 -0.48876953125 +10644 -0.126708984375 +10645 -0.6416015625 +10646 -0.186767578125 +10647 -0.751373291015625 +10648 -0.243988037109375 +10649 -0.84619140625 +10650 -0.293853759765625 +10651 -0.861297607421875 +10652 -0.32611083984375 +10653 -0.863250732421875 +10654 -0.33099365234375 +10655 -0.856597900390625 +10656 -0.312408447265625 +10657 -0.7498779296875 +10658 -0.288482666015625 +10659 -0.624542236328125 +10660 -0.252410888671875 +10661 -0.47808837890625 +10662 -0.186004638671875 +10663 -0.253387451171875 +10664 -0.103546142578125 +10665 0.003692626953125 +10666 -0.0263671875 +10667 0.2257080078125 +10668 0.0494384765625 +10669 0.427154541015625 +10670 0.13397216796875 +10671 0.643218994140625 +10672 0.224273681640625 +10673 0.855926513671875 +10674 0.302337646484375 +10675 0.870361328125 +10676 0.352752685546875 +10677 0.870361328125 +10678 0.3778076171875 +10679 0.862762451171875 +10680 0.37664794921875 +10681 0.79669189453125 +10682 0.346405029296875 +10683 0.595794677734375 +10684 0.2962646484375 +10685 0.362152099609375 +10686 0.23504638671875 +10687 0.1270751953125 +10688 0.169403076171875 +10689 -0.086944580078125 +10690 0.10003662109375 +10691 -0.2784423828125 +10692 0.01611328125 +10693 -0.484832763671875 +10694 -0.08831787109375 +10695 -0.729583740234375 +10696 -0.19744873046875 +10697 -0.86688232421875 +10698 -0.29156494140625 +10699 -0.870391845703125 +10700 -0.369140625 +10701 -0.86859130859375 +10702 -0.429534912109375 +10703 -0.86279296875 +10704 -0.461578369140625 +10705 -0.817962646484375 +10706 -0.451171875 +10707 -0.6116943359375 +10708 -0.3961181640625 +10709 -0.3128662109375 +10710 -0.3070068359375 +10711 0.039398193359375 +10712 -0.190155029296875 +10713 0.422821044921875 +10714 -0.055999755859375 +10715 0.805145263671875 +10716 0.074127197265625 +10717 0.870361328125 +10718 0.182373046875 +10719 0.870361328125 +10720 0.2650146484375 +10721 0.860015869140625 +10722 0.319580078125 +10723 0.727935791015625 +10724 0.344268798828125 +10725 0.48114013671875 +10726 0.34661865234375 +10727 0.2059326171875 +10728 0.3336181640625 +10729 -0.06103515625 +10730 0.308349609375 +10731 -0.29913330078125 +10732 0.266326904296875 +10733 -0.516204833984375 +10734 0.20281982421875 +10735 -0.7252197265625 +10736 0.125640869140625 +10737 -0.85980224609375 +10738 0.045623779296875 +10739 -0.870391845703125 +10740 -0.027862548828125 +10741 -0.870391845703125 +10742 -0.0794677734375 +10743 -0.858062744140625 +10744 -0.10772705078125 +10745 -0.673004150390625 +10746 -0.12884521484375 +10747 -0.42694091796875 +10748 -0.156524658203125 +10749 -0.2100830078125 +10750 -0.189910888671875 +10751 -0.0362548828125 +10752 -0.22015380859375 +10753 0.10943603515625 +10754 -0.24102783203125 +10755 0.23516845703125 +10756 -0.238311767578125 +10757 0.373687744140625 +10758 -0.212554931640625 +10759 0.517791748046875 +10760 -0.185272216796875 +10761 0.602783203125 +10762 -0.154510498046875 +10763 0.635711669921875 +10764 -0.108612060546875 +10765 0.655181884765625 +10766 -0.050872802734375 +10767 0.65948486328125 +10768 0.016082763671875 +10769 0.651275634765625 +10770 0.083892822265625 +10771 0.61846923828125 +10772 0.139892578125 +10773 0.53753662109375 +10774 0.17791748046875 +10775 0.404144287109375 +10776 0.194580078125 +10777 0.22186279296875 +10778 0.1903076171875 +10779 0.003997802734375 +10780 0.1712646484375 +10781 -0.22100830078125 +10782 0.14447021484375 +10783 -0.42449951171875 +10784 0.117156982421875 +10785 -0.579833984375 +10786 0.103912353515625 +10787 -0.641876220703125 +10788 0.10235595703125 +10789 -0.6177978515625 +10790 0.090179443359375 +10791 -0.575531005859375 +10792 0.065460205078125 +10793 -0.526336669921875 +10794 0.045928955078125 +10795 -0.42645263671875 +10796 0.04095458984375 +10797 -0.2581787109375 +10798 0.037994384765625 +10799 -0.068695068359375 +10800 0.023834228515625 +10801 0.09222412109375 +10802 0.004852294921875 +10803 0.232147216796875 +10804 -0.01531982421875 +10805 0.3509521484375 +10806 -0.046844482421875 +10807 0.410064697265625 +10808 -0.099700927734375 +10809 0.372955322265625 +10810 -0.16656494140625 +10811 0.2554931640625 +10812 -0.229400634765625 +10813 0.10711669921875 +10814 -0.281341552734375 +10815 -0.052886962890625 +10816 -0.309814453125 +10817 -0.186279296875 +10818 -0.295501708984375 +10819 -0.23291015625 +10820 -0.246185302734375 +10821 -0.209442138671875 +10822 -0.184478759765625 +10823 -0.174163818359375 +10824 -0.11322021484375 +10825 -0.126739501953125 +10826 -0.029022216796875 +10827 -0.048126220703125 +10828 0.058380126953125 +10829 0.0426025390625 +10830 0.13287353515625 +10831 0.10748291015625 +10832 0.1898193359375 +10833 0.1409912109375 +10834 0.2454833984375 +10835 0.19708251953125 +10836 0.297454833984375 +10837 0.273651123046875 +10838 0.326416015625 +10839 0.31768798828125 +10840 0.336029052734375 +10841 0.341094970703125 +10842 0.33489990234375 +10843 0.368011474609375 +10844 0.31500244140625 +10845 0.37249755859375 +10846 0.259307861328125 +10847 0.30072021484375 +10848 0.16943359375 +10849 0.1517333984375 +10850 0.0682373046875 +10851 -0.01470947265625 +10852 -0.03814697265625 +10853 -0.1883544921875 +10854 -0.148284912109375 +10855 -0.372711181640625 +10856 -0.24114990234375 +10857 -0.51397705078125 +10858 -0.300506591796875 +10859 -0.57177734375 +10860 -0.322052001953125 +10861 -0.53948974609375 +10862 -0.3104248046875 +10863 -0.43511962890625 +10864 -0.2774658203125 +10865 -0.2962646484375 +10866 -0.235748291015625 +10867 -0.161102294921875 +10868 -0.190093994140625 +10869 -0.0435791015625 +10870 -0.13970947265625 +10871 0.060394287109375 +10872 -0.090484619140625 +10873 0.13665771484375 +10874 -0.049102783203125 +10875 0.170135498046875 +10876 -0.015777587890625 +10877 0.16552734375 +10878 0.019256591796875 +10879 0.15728759765625 +10880 0.055694580078125 +10881 0.150787353515625 +10882 0.083160400390625 +10883 0.12200927734375 +10884 0.102813720703125 +10885 0.080108642578125 +10886 0.12188720703125 +10887 0.05126953125 +10888 0.14837646484375 +10889 0.062896728515625 +10890 0.173583984375 +10891 0.09271240234375 +10892 0.18048095703125 +10893 0.092987060546875 +10894 0.17401123046875 +10895 0.07855224609375 +10896 0.159637451171875 +10897 0.06427001953125 +10898 0.1328125 +10899 0.0347900390625 +10900 0.093994140625 +10901 -0.01171875 +10902 0.051239013671875 +10903 -0.056060791015625 +10904 0.0208740234375 +10905 -0.055511474609375 +10906 0.0045166015625 +10907 -0.010467529296875 +10908 -0.014617919921875 +10909 0.02508544921875 +10910 -0.0435791015625 +10911 0.025665283203125 +10912 -0.0718994140625 +10913 0.017333984375 +10914 -0.09765625 +10915 0.00189208984375 +10916 -0.123687744140625 +10917 -0.03173828125 +10918 -0.145263671875 +10919 -0.071502685546875 +10920 -0.1683349609375 +10921 -0.13543701171875 +10922 -0.191802978515625 +10923 -0.219970703125 +10924 -0.207672119140625 +10925 -0.300506591796875 +10926 -0.216552734375 +10927 -0.376312255859375 +10928 -0.208770751953125 +10929 -0.416107177734375 +10930 -0.1688232421875 +10931 -0.371124267578125 +10932 -0.09844970703125 +10933 -0.242279052734375 +10934 -0.012939453125 +10935 -0.069732666015625 +10936 0.07904052734375 +10937 0.125640869140625 +10938 0.16546630859375 +10939 0.31268310546875 +10940 0.232696533203125 +10941 0.45501708984375 +10942 0.280609130859375 +10943 0.554779052734375 +10944 0.308135986328125 +10945 0.61065673828125 +10946 0.310943603515625 +10947 0.610931396484375 +10948 0.28076171875 +10949 0.531463623046875 +10950 0.223419189453125 +10951 0.3883056640625 +10952 0.157806396484375 +10953 0.23468017578125 +10954 0.093292236328125 +10955 0.095245361328125 +10956 0.039794921875 +10957 -0.00396728515625 +10958 0.00341796875 +10959 -0.04852294921875 +10960 -0.0203857421875 +10961 -0.055145263671875 +10962 -0.04833984375 +10963 -0.0758056640625 +10964 -0.0889892578125 +10965 -0.138702392578125 +10966 -0.129425048828125 +10967 -0.209197998046875 +10968 -0.16943359375 +10969 -0.289031982421875 +10970 -0.20867919921875 +10971 -0.37884521484375 +10972 -0.239166259765625 +10973 -0.456329345703125 +10974 -0.259063720703125 +10975 -0.51641845703125 +10976 -0.25482177734375 +10977 -0.519287109375 +10978 -0.22454833984375 +10979 -0.458251953125 +10980 -0.186614990234375 +10981 -0.384796142578125 +10982 -0.150299072265625 +10983 -0.323699951171875 +10984 -0.114532470703125 +10985 -0.269287109375 +10986 -0.071258544921875 +10987 -0.1951904296875 +10988 -0.02099609375 +10989 -0.100006103515625 +10990 0.026031494140625 +10991 -0.01055908203125 +10992 0.07940673828125 +10993 0.1033935546875 +10994 0.140899658203125 +10995 0.24908447265625 +10996 0.191650390625 +10997 0.373199462890625 +10998 0.2252197265625 +10999 0.45806884765625 +11000 0.244140625 +11001 0.511474609375 +11002 0.259490966796875 +11003 0.565399169921875 +11004 0.268646240234375 +11005 0.61138916015625 +11006 0.25152587890625 +11007 0.5897216796875 +11008 0.205291748046875 +11009 0.4906005859375 +11010 0.13653564453125 +11011 0.33148193359375 +11012 0.058380126953125 +11013 0.147796630859375 +11014 -0.013763427734375 +11015 -0.01873779296875 +11016 -0.069366455078125 +11017 -0.140289306640625 +11018 -0.099029541015625 +11019 -0.191986083984375 +11020 -0.1058349609375 +11021 -0.184295654296875 +11022 -0.104888916015625 +11023 -0.161834716796875 +11024 -0.110595703125 +11025 -0.166595458984375 +11026 -0.1212158203125 +11027 -0.19390869140625 +11028 -0.1300048828125 +11029 -0.22442626953125 +11030 -0.144683837890625 +11031 -0.279754638671875 +11032 -0.158294677734375 +11033 -0.3389892578125 +11034 -0.154571533203125 +11035 -0.3543701171875 +11036 -0.141876220703125 +11037 -0.348175048828125 +11038 -0.122772216796875 +11039 -0.32598876953125 +11040 -0.0875244140625 +11041 -0.2581787109375 +11042 -0.035064697265625 +11043 -0.139801025390625 +11044 0.0289306640625 +11045 0.014617919921875 +11046 0.08270263671875 +11047 0.144378662109375 +11048 0.115875244140625 +11049 0.221038818359375 +11050 0.137298583984375 +11051 0.27069091796875 +11052 0.1470947265625 +11053 0.294036865234375 +11054 0.1524658203125 +11055 0.311767578125 +11056 0.15899658203125 +11057 0.339141845703125 +11058 0.161651611328125 +11059 0.360260009765625 +11060 0.155548095703125 +11061 0.360504150390625 +11062 0.129058837890625 +11063 0.308380126953125 +11064 0.07415771484375 +11065 0.18170166015625 +11066 0.0003662109375 +11067 0.0047607421875 +11068 -0.0743408203125 +11069 -0.17559814453125 +11070 -0.132720947265625 +11071 -0.3143310546875 +11072 -0.158111572265625 +11073 -0.36785888671875 +11074 -0.160125732421875 +11075 -0.36248779296875 +11076 -0.1556396484375 +11077 -0.343536376953125 +11078 -0.141143798828125 +11079 -0.3018798828125 +11080 -0.114288330078125 +11081 -0.231414794921875 +11082 -0.0697021484375 +11083 -0.117645263671875 +11084 -0.019683837890625 +11085 0.007049560546875 +11086 0.01495361328125 +11087 0.087982177734375 +11088 0.03936767578125 +11089 0.13946533203125 +11090 0.058074951171875 +11091 0.17425537109375 +11092 0.069183349609375 +11093 0.188201904296875 +11094 0.068572998046875 +11095 0.171234130859375 +11096 0.054107666015625 +11097 0.118438720703125 +11098 0.035736083984375 +11099 0.05706787109375 +11100 0.0140380859375 +11101 -0.010711669921875 +11102 -0.013580322265625 +11103 -0.0914306640625 +11104 -0.0386962890625 +11105 -0.162322998046875 +11106 -0.050537109375 +11107 -0.194549560546875 +11108 -0.03448486328125 +11109 -0.1492919921875 +11110 0.011383056640625 +11111 -0.02166748046875 +11112 0.06304931640625 +11113 0.124053955078125 +11114 0.09185791015625 +11115 0.211151123046875 +11116 0.098358154296875 +11117 0.240447998046875 +11118 0.09417724609375 +11119 0.242218017578125 +11120 0.083099365234375 +11121 0.2257080078125 +11122 0.066680908203125 +11123 0.194366455078125 +11124 0.03289794921875 +11125 0.115509033203125 +11126 -0.00909423828125 +11127 0.0128173828125 +11128 -0.03662109375 +11129 -0.053802490234375 +11130 -0.0594482421875 +11131 -0.110626220703125 +11132 -0.093292236328125 +11133 -0.199493408203125 +11134 -0.128387451171875 +11135 -0.29437255859375 +11136 -0.14105224609375 +11137 -0.33221435546875 +11138 -0.118896484375 +11139 -0.27972412109375 +11140 -0.080291748046875 +11141 -0.185333251953125 +11142 -0.055206298828125 +11143 -0.128204345703125 +11144 -0.04656982421875 +11145 -0.115692138671875 +11146 -0.0428466796875 +11147 -0.116455078125 +11148 -0.0350341796875 +11149 -0.105926513671875 +11150 -0.011993408203125 +11151 -0.053955078125 +11152 0.029571533203125 +11153 0.048797607421875 +11154 0.072601318359375 +11155 0.157318115234375 +11156 0.0946044921875 +11157 0.212005615234375 +11158 0.097625732421875 +11159 0.218475341796875 +11160 0.104400634765625 +11161 0.23724365234375 +11162 0.12890625 +11163 0.30535888671875 +11164 0.155609130859375 +11165 0.38128662109375 +11166 0.161865234375 +11167 0.404449462890625 +11168 0.1551513671875 +11169 0.3944091796875 +11170 0.14971923828125 +11171 0.3885498046875 +11172 0.136627197265625 +11173 0.362640380859375 +11174 0.099884033203125 +11175 0.27362060546875 +11176 0.038055419921875 +11177 0.11712646484375 +11178 -0.0291748046875 +11179 -0.054901123046875 +11180 -0.082275390625 +11181 -0.19085693359375 +11182 -0.1192626953125 +11183 -0.28570556640625 +11184 -0.1400146484375 +11185 -0.339263916015625 +11186 -0.154327392578125 +11187 -0.3775634765625 +11188 -0.179168701171875 +11189 -0.445709228515625 +11190 -0.21136474609375 +11191 -0.535064697265625 +11192 -0.2447509765625 +11193 -0.629058837890625 +11194 -0.26812744140625 +11195 -0.697601318359375 +11196 -0.267852783203125 +11197 -0.70391845703125 +11198 -0.241973876953125 +11199 -0.6424560546875 +11200 -0.182373046875 +11201 -0.491241455078125 +11202 -0.09503173828125 +11203 -0.265716552734375 +11204 -0.0018310546875 +11205 -0.023712158203125 +11206 0.084686279296875 +11207 0.201751708984375 +11208 0.151336669921875 +11209 0.375823974609375 +11210 0.193023681640625 +11211 0.485076904296875 +11212 0.22454833984375 +11213 0.56884765625 +11214 0.248779296875 +11215 0.634765625 +11216 0.248779296875 +11217 0.63763427734375 +11218 0.2203369140625 +11219 0.5660400390625 +11220 0.18310546875 +11221 0.4720458984375 +11222 0.156463623046875 +11223 0.40692138671875 +11224 0.143218994140625 +11225 0.3778076171875 +11226 0.140625 +11227 0.376953125 +11228 0.136627197265625 +11229 0.371978759765625 +11230 0.11260986328125 +11231 0.313140869140625 +11232 0.0626220703125 +11233 0.184417724609375 +11234 -0.003662109375 +11235 0.011199951171875 +11236 -0.07281494140625 +11237 -0.171051025390625 +11238 -0.135467529296875 +11239 -0.33740234375 +11240 -0.1856689453125 +11241 -0.47198486328125 +11242 -0.218048095703125 +11243 -0.560394287109375 +11244 -0.224365234375 +11245 -0.58056640625 +11246 -0.21038818359375 +11247 -0.54754638671875 +11248 -0.1939697265625 +11249 -0.508575439453125 +11250 -0.17364501953125 +11251 -0.459503173828125 +11252 -0.14727783203125 +11253 -0.394378662109375 +11254 -0.1297607421875 +11255 -0.35260009765625 +11256 -0.112762451171875 +11257 -0.31170654296875 +11258 -0.06842041015625 +11259 -0.197418212890625 +11260 0.003814697265625 +11261 -0.007965087890625 +11262 0.08538818359375 +11263 0.207489013671875 +11264 0.161407470703125 +11265 0.409210205078125 +11266 0.2230224609375 +11267 0.57208251953125 +11268 0.25848388671875 +11269 0.66595458984375 +11270 0.254425048828125 +11271 0.65875244140625 +11272 0.2174072265625 +11273 0.56744384765625 +11274 0.1632080078125 +11275 0.431396484375 +11276 0.109405517578125 +11277 0.29443359375 +11278 0.066314697265625 +11279 0.182464599609375 +11280 0.020721435546875 +11281 0.06365966796875 +11282 -0.03326416015625 +11283 -0.075958251953125 +11284 -0.07666015625 +11285 -0.189422607421875 +11286 -0.107696533203125 +11287 -0.271942138671875 +11288 -0.134246826171875 +11289 -0.342529296875 +11290 -0.141326904296875 +11291 -0.364166259765625 +11292 -0.12506103515625 +11293 -0.327239990234375 +11294 -0.10394287109375 +11295 -0.2769775390625 +11296 -0.094390869140625 +11297 -0.253692626953125 +11298 -0.09075927734375 +11299 -0.24365234375 +11300 -0.073211669921875 +11301 -0.1983642578125 +11302 -0.041015625 +11303 -0.116241455078125 +11304 -0.010223388671875 +11305 -0.036834716796875 +11306 0.0172119140625 +11307 0.034881591796875 +11308 0.03826904296875 +11309 0.09124755859375 +11310 0.043548583984375 +11311 0.10888671875 +11312 0.04852294921875 +11313 0.125518798828125 +11314 0.06005859375 +11315 0.15771484375 +11316 0.067138671875 +11317 0.17828369140625 +11318 0.063232421875 +11319 0.17108154296875 +11320 0.0458984375 +11321 0.129974365234375 +11322 0.026336669921875 +11323 0.082427978515625 +11324 0.004241943359375 +11325 0.027679443359375 +11326 -0.033172607421875 +11327 -0.065643310546875 +11328 -0.070404052734375 +11329 -0.15936279296875 +11330 -0.091033935546875 +11331 -0.21307373046875 +11332 -0.09832763671875 +11333 -0.234649658203125 +11334 -0.0826416015625 +11335 -0.2001953125 +11336 -0.047943115234375 +11337 -0.119171142578125 +11338 -0.00787353515625 +11339 -0.024749755859375 +11340 0.038604736328125 +11341 0.085784912109375 +11342 0.077392578125 +11343 0.178131103515625 +11344 0.093505859375 +11345 0.215576171875 +11346 0.09234619140625 +11347 0.211456298828125 +11348 0.0777587890625 +11349 0.17523193359375 +11350 0.05865478515625 +11351 0.128753662109375 +11352 0.0472412109375 +11353 0.1019287109375 +11354 0.035247802734375 +11355 0.0743408203125 +11356 0.021575927734375 +11357 0.04327392578125 +11358 0.018310546875 +11359 0.038177490234375 +11360 0.03253173828125 +11361 0.076263427734375 +11362 0.057586669921875 +11363 0.14105224609375 +11364 0.074737548828125 +11365 0.186431884765625 +11366 0.074432373046875 +11367 0.188812255859375 +11368 0.053009033203125 +11369 0.1390380859375 +11370 0.012451171875 +11371 0.041778564453125 +11372 -0.03759765625 +11373 -0.079437255859375 +11374 -0.095001220703125 +11375 -0.219390869140625 +11376 -0.155517578125 +11377 -0.367828369140625 +11378 -0.20697021484375 +11379 -0.494873046875 +11380 -0.2313232421875 +11381 -0.556243896484375 +11382 -0.21099853515625 +11383 -0.508697509765625 +11384 -0.15557861328125 +11385 -0.3756103515625 +11386 -0.090423583984375 +11387 -0.218902587890625 +11388 -0.025848388671875 +11389 -0.063751220703125 +11390 0.038726806640625 +11391 0.091552734375 +11392 0.0987548828125 +11393 0.23602294921875 +11394 0.143310546875 +11395 0.342987060546875 +11396 0.165313720703125 +11397 0.39520263671875 +11398 0.16339111328125 +11399 0.389373779296875 +11400 0.13702392578125 +11401 0.324249267578125 +11402 0.096099853515625 +11403 0.224090576171875 +11404 0.055084228515625 +11405 0.124267578125 +11406 0.01898193359375 +11407 0.037078857421875 +11408 -0.0009765625 +11409 -0.010101318359375 +11410 -0.005615234375 +11411 -0.019439697265625 +11412 -0.00787353515625 +11413 -0.022796630859375 +11414 -0.000152587890625 +11415 -0.001556396484375 +11416 0.022491455078125 +11417 0.056304931640625 +11418 0.042144775390625 +11419 0.106719970703125 +11420 0.037353515625 +11421 0.096893310546875 +11422 0.014617919921875 +11423 0.042694091796875 +11424 -0.010589599609375 +11425 -0.018035888671875 +11426 -0.034393310546875 +11427 -0.07586669921875 +11428 -0.052154541015625 +11429 -0.11944580078125 +11430 -0.068359375 +11431 -0.15972900390625 +11432 -0.08544921875 +11433 -0.202606201171875 +11434 -0.103607177734375 +11435 -0.24859619140625 +11436 -0.125946044921875 +11437 -0.30517578125 +11438 -0.14837646484375 +11439 -0.36212158203125 +11440 -0.159515380859375 +11441 -0.39141845703125 +11442 -0.143951416015625 +11443 -0.35528564453125 +11444 -0.1002197265625 +11445 -0.249969482421875 +11446 -0.03546142578125 +11447 -0.092864990234375 +11448 0.03924560546875 +11449 0.08905029296875 +11450 0.09918212890625 +11451 0.2352294921875 +11452 0.133392333984375 +11453 0.318817138671875 +11454 0.149566650390625 +11455 0.358642578125 +11456 0.144866943359375 +11457 0.347747802734375 +11458 0.119110107421875 +11459 0.28564453125 +11460 0.09307861328125 +11461 0.223175048828125 +11462 0.0816650390625 +11463 0.196746826171875 +11464 0.0740966796875 +11465 0.179840087890625 +11466 0.0634765625 +11467 0.155548095703125 +11468 0.06103515625 +11469 0.151214599609375 +11470 0.062744140625 +11471 0.156951904296875 +11472 0.051910400390625 +11473 0.13177490234375 +11474 0.038818359375 +11475 0.100799560546875 +11476 0.032928466796875 +11477 0.087127685546875 +11478 0.019622802734375 +11479 0.05487060546875 +11480 -0.00640869140625 +11481 -0.009002685546875 +11482 -0.044952392578125 +11483 -0.10400390625 +11484 -0.095733642578125 +11485 -0.229400634765625 +11486 -0.146728515625 +11487 -0.35552978515625 +11488 -0.181396484375 +11489 -0.441925048828125 +11490 -0.19378662109375 +11491 -0.473846435546875 +11492 -0.189453125 +11493 -0.464813232421875 +11494 -0.170166015625 +11495 -0.419097900390625 +11496 -0.134979248046875 +11497 -0.334320068359375 +11498 -0.091033935546875 +11499 -0.227935791015625 +11500 -0.0479736328125 +11501 -0.12347412109375 +11502 -0.008575439453125 +11503 -0.02764892578125 +11504 0.0345458984375 +11505 0.077667236328125 +11506 0.08984375 +11507 0.2132568359375 +11508 0.161285400390625 +11509 0.38885498046875 +11510 0.240081787109375 +11511 0.582794189453125 +11512 0.30133056640625 +11513 0.734039306640625 +11514 0.3277587890625 +11515 0.800140380859375 +11516 0.3182373046875 +11517 0.7783203125 +11518 0.27142333984375 +11519 0.6651611328125 +11520 0.186492919921875 +11521 0.45965576171875 +11522 0.078155517578125 +11523 0.199188232421875 +11524 -0.025848388671875 +11525 -0.050689697265625 +11526 -0.100555419921875 +11527 -0.23297119140625 +11528 -0.138427734375 +11529 -0.33013916015625 +11530 -0.151123046875 +11531 -0.368408203125 +11532 -0.1524658203125 +11533 -0.378936767578125 +11534 -0.149261474609375 +11535 -0.376983642578125 +11536 -0.149078369140625 +11537 -0.37969970703125 +11538 -0.153900146484375 +11539 -0.391510009765625 +11540 -0.151763916015625 +11541 -0.385345458984375 +11542 -0.134124755859375 +11543 -0.3419189453125 +11544 -0.110382080078125 +11545 -0.28289794921875 +11546 -0.099456787109375 +11547 -0.251617431640625 +11548 -0.109130859375 +11549 -0.266143798828125 +11550 -0.115875244140625 +11551 -0.273345947265625 +11552 -0.09466552734375 +11553 -0.216796875 +11554 -0.05926513671875 +11555 -0.128265380859375 +11556 -0.03607177734375 +11557 -0.068145751953125 +11558 -0.027862548828125 +11559 -0.0430908203125 +11560 -0.021881103515625 +11561 -0.024444580078125 +11562 -0.003509521484375 +11563 0.020721435546875 +11564 0.0413818359375 +11565 0.124481201171875 +11566 0.100067138671875 +11567 0.25787353515625 +11568 0.15411376953125 +11569 0.379119873046875 +11570 0.1998291015625 +11571 0.47991943359375 +11572 0.2230224609375 +11573 0.5281982421875 +11574 0.2178955078125 +11575 0.511138916015625 +11576 0.1964111328125 +11577 0.456207275390625 +11578 0.17779541015625 +11579 0.407470703125 +11580 0.170196533203125 +11581 0.383758544921875 +11582 0.161041259765625 +11583 0.35687255859375 +11584 0.143585205078125 +11585 0.31182861328125 +11586 0.11871337890625 +11587 0.250885009765625 +11588 0.082550048828125 +11589 0.1654052734375 +11590 0.026153564453125 +11591 0.035247802734375 +11592 -0.05157470703125 +11593 -0.142059326171875 +11594 -0.137054443359375 +11595 -0.33563232421875 +11596 -0.225433349609375 +11597 -0.5345458984375 +11598 -0.3092041015625 +11599 -0.72186279296875 +11600 -0.3614501953125 +11601 -0.836669921875 +11602 -0.3616943359375 +11603 -0.8326416015625 +11604 -0.31854248046875 +11605 -0.7296142578125 +11606 -0.256103515625 +11607 -0.582550048828125 +11608 -0.19561767578125 +11609 -0.440093994140625 +11610 -0.14666748046875 +11611 -0.324310302734375 +11612 -0.094329833984375 +11613 -0.20147705078125 +11614 -0.026641845703125 +11615 -0.044647216796875 +11616 0.037841796875 +11617 0.103973388671875 +11618 0.0806884765625 +11619 0.202392578125 +11620 0.1080322265625 +11621 0.264495849609375 +11622 0.1412353515625 +11623 0.338897705078125 +11624 0.188262939453125 +11625 0.443817138671875 +11626 0.234039306640625 +11627 0.545074462890625 +11628 0.267303466796875 +11629 0.6173095703125 +11630 0.284454345703125 +11631 0.6524658203125 +11632 0.291046142578125 +11633 0.66339111328125 +11634 0.28961181640625 +11635 0.6561279296875 +11636 0.269561767578125 +11637 0.606781005859375 +11638 0.224578857421875 +11639 0.501190185546875 +11640 0.16046142578125 +11641 0.352783203125 +11642 0.083770751953125 +11643 0.176544189453125 +11644 -0.00872802734375 +11645 -0.034820556640625 +11646 -0.106842041015625 +11647 -0.258209228515625 +11648 -0.188079833984375 +11649 -0.44244384765625 +11650 -0.247039794921875 +11651 -0.5753173828125 +11652 -0.281585693359375 +11653 -0.65203857421875 +11654 -0.278045654296875 +11655 -0.641632080078125 +11656 -0.24432373046875 +11657 -0.562164306640625 +11658 -0.19989013671875 +11659 -0.458038330078125 +11660 -0.154022216796875 +11661 -0.350555419921875 +11662 -0.11578369140625 +11663 -0.260528564453125 +11664 -0.086944580078125 +11665 -0.192108154296875 +11666 -0.065948486328125 +11667 -0.141937255859375 +11668 -0.049285888671875 +11669 -0.1021728515625 +11670 -0.0325927734375 +11671 -0.062896728515625 +11672 -0.01043701171875 +11673 -0.011932373046875 +11674 0.0224609375 +11675 0.062835693359375 +11676 0.060546875 +11677 0.148712158203125 +11678 0.10205078125 +11679 0.241729736328125 +11680 0.15008544921875 +11681 0.34912109375 +11682 0.198638916015625 +11683 0.457305908203125 +11684 0.237823486328125 +11685 0.54388427734375 +11686 0.251739501953125 +11687 0.5728759765625 +11688 0.223724365234375 +11689 0.506591796875 +11690 0.15643310546875 +11691 0.351226806640625 +11692 0.067291259765625 +11693 0.146514892578125 +11694 -0.02069091796875 +11695 -0.05523681640625 +11696 -0.0909423828125 +11697 -0.21624755859375 +11698 -0.142791748046875 +11699 -0.334930419921875 +11700 -0.172576904296875 +11701 -0.402984619140625 +11702 -0.18951416015625 +11703 -0.4412841796875 +11704 -0.21380615234375 +11705 -0.49578857421875 +11706 -0.242645263671875 +11707 -0.5601806640625 +11708 -0.26116943359375 +11709 -0.600738525390625 +11710 -0.254730224609375 +11711 -0.584228515625 +11712 -0.20947265625 +11713 -0.47930908203125 +11714 -0.1224365234375 +11715 -0.27935791015625 +11716 -0.00439453125 +11717 -0.0089111328125 +11718 0.11688232421875 +11719 0.268798828125 +11720 0.210235595703125 +11721 0.482818603515625 +11722 0.26275634765625 +11723 0.60369873046875 +11724 0.282806396484375 +11725 0.650421142578125 +11726 0.2884521484375 +11727 0.66400146484375 +11728 0.278411865234375 +11729 0.6414794921875 +11730 0.248138427734375 +11731 0.572540283203125 +11732 0.21563720703125 +11733 0.498138427734375 +11734 0.190277099609375 +11735 0.439453125 +11736 0.16278076171875 +11737 0.375518798828125 +11738 0.11907958984375 +11739 0.274505615234375 +11740 0.046966552734375 +11741 0.1087646484375 +11742 -0.04376220703125 +11743 -0.099395751953125 +11744 -0.139190673828125 +11745 -0.3182373046875 +11746 -0.239898681640625 +11747 -0.5489501953125 +11748 -0.338104248046875 +11749 -0.7738037109375 +11750 -0.410552978515625 +11751 -0.86383056640625 +11752 -0.442657470703125 +11753 -0.870391845703125 +11754 -0.442230224609375 +11755 -0.86895751953125 +11756 -0.4150390625 +11757 -0.861053466796875 +11758 -0.353485107421875 +11759 -0.765869140625 +11760 -0.252593994140625 +11761 -0.5301513671875 +11762 -0.115509033203125 +11763 -0.214691162109375 +11764 0.038848876953125 +11765 0.137359619140625 +11766 0.187957763671875 +11767 0.474822998046875 +11768 0.316253662109375 +11769 0.76239013671875 +11770 0.411865234375 +11771 0.867462158203125 +11772 0.47503662109375 +11773 0.870361328125 +11774 0.500701904296875 +11775 0.86480712890625 +11776 0.491455078125 +11777 0.831817626953125 +11778 0.4581298828125 +11779 0.677581787109375 +11780 0.403228759765625 +11781 0.495880126953125 +11782 0.335205078125 +11783 0.30767822265625 +11784 0.254730224609375 +11785 0.116180419921875 +11786 0.1463623046875 +11787 -0.110748291015625 +11788 0.006378173828125 +11789 -0.381805419921875 +11790 -0.145477294921875 +11791 -0.6572265625 +11792 -0.2813720703125 +11793 -0.857421875 +11794 -0.381439208984375 +11795 -0.870391845703125 +11796 -0.442657470703125 +11797 -0.870391845703125 +11798 -0.47796630859375 +11799 -0.86444091796875 +11800 -0.504364013671875 +11801 -0.85723876953125 +11802 -0.51324462890625 +11803 -0.790008544921875 +11804 -0.47894287109375 +11805 -0.62847900390625 +11806 -0.399810791015625 +11807 -0.3956298828125 +11808 -0.2911376953125 +11809 -0.126708984375 +11810 -0.16558837890625 +11811 0.150115966796875 +11812 -0.0283203125 +11813 0.424041748046875 +11814 0.1082763671875 +11815 0.670623779296875 +11816 0.22625732421875 +11817 0.854522705078125 +11818 0.317657470703125 +11819 0.866485595703125 +11820 0.375518798828125 +11821 0.86920166015625 +11822 0.40869140625 +11823 0.8653564453125 +11824 0.423736572265625 +11825 0.857147216796875 +11826 0.419403076171875 +11827 0.766845703125 +11828 0.398223876953125 +11829 0.628509521484375 +11830 0.35699462890625 +11831 0.462127685546875 +11832 0.307830810546875 +11833 0.297210693359375 +11834 0.25640869140625 +11835 0.14862060546875 +11836 0.19171142578125 +11837 -0.00537109375 +11838 0.1170654296875 +11839 -0.15753173828125 +11840 0.03045654296875 +11841 -0.31304931640625 +11842 -0.07501220703125 +11843 -0.48876953125 +11844 -0.177490234375 +11845 -0.6416015625 +11846 -0.26556396484375 +11847 -0.751373291015625 +11848 -0.35040283203125 +11849 -0.84619140625 +11850 -0.42523193359375 +11851 -0.861297607421875 +11852 -0.474517822265625 +11853 -0.863250732421875 +11854 -0.483428955078125 +11855 -0.856597900390625 +11856 -0.457733154296875 +11857 -0.7498779296875 +11858 -0.424713134765625 +11859 -0.624542236328125 +11860 -0.373870849609375 +11861 -0.47808837890625 +11862 -0.2774658203125 +11863 -0.253387451171875 +11864 -0.1568603515625 +11865 0.003692626953125 +11866 -0.044097900390625 +11867 0.2257080078125 +11868 0.066925048828125 +11869 0.427154541015625 +11870 0.19171142578125 +11871 0.643218994140625 +11872 0.325958251953125 +11873 0.855926513671875 +11874 0.4425048828125 +11875 0.870361328125 +11876 0.51806640625 +11877 0.870361328125 +11878 0.556121826171875 +11879 0.862762451171875 +11880 0.555389404296875 +11881 0.79669189453125 +11882 0.511444091796875 +11883 0.595794677734375 +11884 0.43804931640625 +11885 0.362152099609375 +11886 0.348358154296875 +11887 0.1270751953125 +11888 0.252288818359375 +11889 -0.086944580078125 +11890 0.15069580078125 +11891 -0.2784423828125 +11892 0.0269775390625 +11893 -0.484832763671875 +11894 -0.128021240234375 +11895 -0.729583740234375 +11896 -0.29058837890625 +11897 -0.86688232421875 +11898 -0.43096923828125 +11899 -0.870391845703125 +11900 -0.54693603515625 +11901 -0.86859130859375 +11902 -0.637603759765625 +11903 -0.86279296875 +11904 -0.686065673828125 +11905 -0.817962646484375 +11906 -0.67095947265625 +11907 -0.6116943359375 +11908 -0.588958740234375 +11909 -0.3128662109375 +11910 -0.455963134765625 +11911 0.039398193359375 +11912 -0.281402587890625 +11913 0.422821044921875 +11914 -0.0809326171875 +11915 0.805145263671875 +11916 0.113311767578125 +11917 0.870361328125 +11918 0.27447509765625 +11919 0.870361328125 +11920 0.3970947265625 +11921 0.860015869140625 +11922 0.4775390625 +11923 0.727935791015625 +11924 0.51318359375 +11925 0.48114013671875 +11926 0.51544189453125 +11927 0.2059326171875 +11928 0.4949951171875 +11929 -0.06103515625 +11930 0.456573486328125 +11931 -0.29913330078125 +11932 0.393341064453125 +11933 -0.516204833984375 +11934 0.298095703125 +11935 -0.7252197265625 +11936 0.1826171875 +11937 -0.85980224609375 +11938 0.06317138671875 +11939 -0.870391845703125 +11940 -0.046173095703125 +11941 -0.870391845703125 +11942 -0.122283935546875 +11943 -0.858062744140625 +11944 -0.16302490234375 +11945 -0.673004150390625 +11946 -0.193023681640625 +11947 -0.42694091796875 +11948 -0.23309326171875 +11949 -0.2100830078125 +11950 -0.282073974609375 +11951 -0.0362548828125 +11952 -0.32611083984375 +11953 0.10943603515625 +11954 -0.355712890625 +11955 0.23516845703125 +11956 -0.35125732421875 +11957 0.373687744140625 +11958 -0.3135986328125 +11959 0.517791748046875 +11960 -0.272491455078125 +11961 0.602783203125 +11962 -0.225616455078125 +11963 0.635711669921875 +11964 -0.157318115234375 +11965 0.655181884765625 +11966 -0.072418212890625 +11967 0.65948486328125 +11968 0.02508544921875 +11969 0.651275634765625 +11970 0.12347412109375 +11971 0.61846923828125 +11972 0.205047607421875 +11973 0.53753662109375 +11974 0.26104736328125 +11975 0.404144287109375 +11976 0.286712646484375 +11977 0.22186279296875 +11978 0.282470703125 +11979 0.003997802734375 +11980 0.2567138671875 +11981 -0.22100830078125 +11982 0.2191162109375 +11983 -0.42449951171875 +11984 0.179718017578125 +11985 -0.579833984375 +11986 0.158660888671875 +11987 -0.641876220703125 +11988 0.152862548828125 +11989 -0.6177978515625 +11990 0.13189697265625 +11991 -0.575531005859375 +11992 0.0933837890625 +11993 -0.526336669921875 +11994 0.0618896484375 +11995 -0.42645263671875 +11996 0.050567626953125 +11997 -0.2581787109375 +11998 0.042449951171875 +11999 -0.068695068359375 +12000 0.01959228515625 +12001 0.09222412109375 +12002 -0.009033203125 +12003 0.232147216796875 +12004 -0.03839111328125 +12005 0.3509521484375 +12006 -0.082305908203125 +12007 0.410064697265625 +12008 -0.154510498046875 +12009 0.372955322265625 +12010 -0.245025634765625 +12011 0.2554931640625 +12012 -0.32916259765625 +12013 0.10711669921875 +12014 -0.39764404296875 +12015 -0.052886962890625 +12016 -0.43341064453125 +12017 -0.186279296875 +12018 -0.410186767578125 +12019 -0.23291015625 +12020 -0.338775634765625 +12021 -0.209442138671875 +12022 -0.250457763671875 +12023 -0.174163818359375 +12024 -0.149261474609375 +12025 -0.126739501953125 +12026 -0.030731201171875 +12027 -0.048126220703125 +12028 0.09161376953125 +12029 0.0426025390625 +12030 0.195556640625 +12031 0.10748291015625 +12032 0.275177001953125 +12033 0.1409912109375 +12034 0.353485107421875 +12035 0.19708251953125 +12036 0.426361083984375 +12037 0.273651123046875 +12038 0.4659423828125 +12039 0.31768798828125 +12040 0.477813720703125 +12041 0.341094970703125 +12042 0.474609375 +12043 0.368011474609375 +12044 0.444793701171875 +12045 0.37249755859375 +12046 0.363677978515625 +12047 0.30072021484375 +12048 0.233612060546875 +12049 0.1517333984375 +12050 0.087799072265625 +12051 -0.01470947265625 +12052 -0.064971923828125 +12053 -0.1883544921875 +12054 -0.222747802734375 +12055 -0.372711181640625 +12056 -0.355072021484375 +12057 -0.51397705078125 +12058 -0.4384765625 +12059 -0.57177734375 +12060 -0.466888427734375 +12061 -0.53948974609375 +12062 -0.44720458984375 +12063 -0.43511962890625 +12064 -0.39678955078125 +12065 -0.2962646484375 +12066 -0.334075927734375 +12067 -0.161102294921875 +12068 -0.266204833984375 +12069 -0.0435791015625 +12070 -0.192047119140625 +12071 0.060394287109375 +12072 -0.1202392578125 +12073 0.13665771484375 +12074 -0.060455322265625 +12075 0.170135498046875 +12076 -0.012969970703125 +12077 0.16552734375 +12078 0.0364990234375 +12079 0.15728759765625 +12080 0.08758544921875 +12081 0.150787353515625 +12082 0.12530517578125 +12083 0.12200927734375 +12084 0.151458740234375 +12085 0.080108642578125 +12086 0.17669677734375 +12087 0.05126953125 +12088 0.21282958984375 +12089 0.062896728515625 +12090 0.247283935546875 +12091 0.09271240234375 +12092 0.255462646484375 +12093 0.092987060546875 +12094 0.244659423828125 +12095 0.07855224609375 +12096 0.22283935546875 +12097 0.06427001953125 +12098 0.183441162109375 +12099 0.0347900390625 +12100 0.127166748046875 +12101 -0.01171875 +12102 0.065673828125 +12103 -0.056060791015625 +12104 0.022613525390625 +12105 -0.055511474609375 +12106 0.00030517578125 +12107 -0.010467529296875 +12108 -0.025726318359375 +12109 0.02508544921875 +12110 -0.06585693359375 +12111 0.025665283203125 +12112 -0.104949951171875 +12113 0.017333984375 +12114 -0.140380859375 +12115 0.00189208984375 +12116 -0.176361083984375 +12117 -0.03173828125 +12118 -0.20611572265625 +12119 -0.071502685546875 +12120 -0.238372802734375 +12121 -0.13543701171875 +12122 -0.2716064453125 +12123 -0.219970703125 +12124 -0.29425048828125 +12125 -0.300506591796875 +12126 -0.307159423828125 +12127 -0.376312255859375 +12128 -0.296234130859375 +12129 -0.416107177734375 +12130 -0.238983154296875 +12131 -0.371124267578125 +12132 -0.13787841796875 +12133 -0.242279052734375 +12134 -0.015045166015625 +12135 -0.069732666015625 +12136 0.117034912109375 +12137 0.125640869140625 +12138 0.240997314453125 +12139 0.31268310546875 +12140 0.33709716796875 +12141 0.45501708984375 +12142 0.40521240234375 +12143 0.554779052734375 +12144 0.443878173828125 +12145 0.61065673828125 +12146 0.4468994140625 +12147 0.610931396484375 +12148 0.40228271484375 +12149 0.531463623046875 +12150 0.318511962890625 +12151 0.3883056640625 +12152 0.22308349609375 +12153 0.23468017578125 +12154 0.12957763671875 +12155 0.095245361328125 +12156 0.052398681640625 +12157 -0.00396728515625 +12158 0.0003662109375 +12159 -0.04852294921875 +12160 -0.033172607421875 +12161 -0.055145263671875 +12162 -0.07257080078125 +12163 -0.0758056640625 +12164 -0.130340576171875 +12165 -0.138702392578125 +12166 -0.187835693359375 +12167 -0.209197998046875 +12168 -0.24481201171875 +12169 -0.289031982421875 +12170 -0.300811767578125 +12171 -0.37884521484375 +12172 -0.34423828125 +12173 -0.456329345703125 +12174 -0.37249755859375 +12175 -0.51641845703125 +12176 -0.365966796875 +12177 -0.519287109375 +12178 -0.321868896484375 +12179 -0.458251953125 +12180 -0.26690673828125 +12181 -0.384796142578125 +12182 -0.21453857421875 +12183 -0.323699951171875 +12184 -0.163238525390625 +12185 -0.269287109375 +12186 -0.101226806640625 +12187 -0.1951904296875 +12188 -0.0291748046875 +12189 -0.100006103515625 +12190 0.03814697265625 +12191 -0.01055908203125 +12192 0.11468505859375 +12193 0.1033935546875 +12194 0.203094482421875 +12195 0.24908447265625 +12196 0.275970458984375 +12197 0.373199462890625 +12198 0.32403564453125 +12199 0.45806884765625 +12200 0.35101318359375 +12201 0.511474609375 +12202 0.373077392578125 +12203 0.565399169921875 +12204 0.386383056640625 +12205 0.61138916015625 +12206 0.36175537109375 +12207 0.5897216796875 +12208 0.295135498046875 +12209 0.4906005859375 +12210 0.196319580078125 +12211 0.33148193359375 +12212 0.0841064453125 +12213 0.147796630859375 +12214 -0.019500732421875 +12215 -0.01873779296875 +12216 -0.0994873046875 +12217 -0.140289306640625 +12218 -0.14239501953125 +12219 -0.191986083984375 +12220 -0.152587890625 +12221 -0.184295654296875 +12222 -0.15167236328125 +12223 -0.161834716796875 +12224 -0.160186767578125 +12225 -0.166595458984375 +12226 -0.17559814453125 +12227 -0.19390869140625 +12228 -0.188262939453125 +12229 -0.22442626953125 +12230 -0.209259033203125 +12231 -0.279754638671875 +12232 -0.228607177734375 +12233 -0.3389892578125 +12234 -0.223114013671875 +12235 -0.3543701171875 +12236 -0.204681396484375 +12237 -0.348175048828125 +12238 -0.176971435546875 +12239 -0.32598876953125 +12240 -0.12615966796875 +12241 -0.2581787109375 +12242 -0.050689697265625 +12243 -0.139801025390625 +12244 0.041290283203125 +12245 0.014617919921875 +12246 0.11865234375 +12247 0.144378662109375 +12248 0.16656494140625 +12249 0.221038818359375 +12250 0.1976318359375 +12251 0.27069091796875 +12252 0.21197509765625 +12253 0.294036865234375 +12254 0.21990966796875 +12255 0.311767578125 +12256 0.229217529296875 +12257 0.339141845703125 +12258 0.23236083984375 +12259 0.360260009765625 +12260 0.222503662109375 +12261 0.360504150390625 +12262 0.184326171875 +12263 0.308380126953125 +12264 0.10736083984375 +12265 0.18170166015625 +12266 0.004638671875 +12267 0.0047607421875 +12268 -0.099517822265625 +12269 -0.17559814453125 +12270 -0.18170166015625 +12271 -0.3143310546875 +12272 -0.21929931640625 +12273 -0.36785888671875 +12274 -0.225067138671875 +12275 -0.36248779296875 +12276 -0.221435546875 +12277 -0.343536376953125 +12278 -0.20355224609375 +12279 -0.3018798828125 +12280 -0.16827392578125 +12281 -0.231414794921875 +12282 -0.10833740234375 +12283 -0.117645263671875 +12284 -0.040283203125 +12285 0.007049560546875 +12286 0.007965087890625 +12287 0.087982177734375 +12288 0.0430908203125 +12289 0.13946533203125 +12290 0.071014404296875 +12291 0.17425537109375 +12292 0.089080810546875 +12293 0.188201904296875 +12294 0.091156005859375 +12295 0.171234130859375 +12296 0.073883056640625 +12297 0.118438720703125 +12298 0.051177978515625 +12299 0.05706787109375 +12300 0.02362060546875 +12301 -0.010711669921875 +12302 -0.01275634765625 +12303 -0.0914306640625 +12304 -0.04608154296875 +12305 -0.162322998046875 +12306 -0.06109619140625 +12307 -0.194549560546875 +12308 -0.037078857421875 +12309 -0.1492919921875 +12310 0.0286865234375 +12311 -0.02166748046875 +12312 0.10198974609375 +12313 0.124053955078125 +12314 0.14202880859375 +12315 0.211151123046875 +12316 0.149688720703125 +12317 0.240447998046875 +12318 0.141632080078125 +12319 0.242218017578125 +12320 0.123382568359375 +12321 0.2257080078125 +12322 0.0972900390625 +12323 0.194366455078125 +12324 0.046356201171875 +12325 0.115509033203125 +12326 -0.0162353515625 +12327 0.0128173828125 +12328 -0.0579833984375 +12329 -0.053802490234375 +12330 -0.092681884765625 +12331 -0.110626220703125 +12332 -0.142608642578125 +12333 -0.199493408203125 +12334 -0.1937255859375 +12335 -0.29437255859375 +12336 -0.2122802734375 +12337 -0.33221435546875 +12338 -0.180572509765625 +12339 -0.27972412109375 +12340 -0.124847412109375 +12341 -0.185333251953125 +12342 -0.08782958984375 +12343 -0.128204345703125 +12344 -0.0738525390625 +12345 -0.115692138671875 +12346 -0.0665283203125 +12347 -0.116455078125 +12348 -0.053131103515625 +12349 -0.105926513671875 +12350 -0.0179443359375 +12351 -0.053955078125 +12352 0.04364013671875 +12353 0.048797607421875 +12354 0.107177734375 +12355 0.157318115234375 +12356 0.140472412109375 +12357 0.212005615234375 +12358 0.1463623046875 +12359 0.218475341796875 +12360 0.157196044921875 +12361 0.23724365234375 +12362 0.19281005859375 +12363 0.30535888671875 +12364 0.231048583984375 +12365 0.38128662109375 +12366 0.23956298828125 +12367 0.404449462890625 +12368 0.2291259765625 +12369 0.3944091796875 +12370 0.2200927734375 +12371 0.3885498046875 +12372 0.199859619140625 +12373 0.362640380859375 +12374 0.14569091796875 +12375 0.27362060546875 +12376 0.05560302734375 +12377 0.11712646484375 +12378 -0.042236328125 +12379 -0.054901123046875 +12380 -0.119842529296875 +12381 -0.19085693359375 +12382 -0.17431640625 +12383 -0.28570556640625 +12384 -0.20538330078125 +12385 -0.339263916015625 +12386 -0.2269287109375 +12387 -0.3775634765625 +12388 -0.2630615234375 +12389 -0.445709228515625 +12390 -0.309234619140625 +12391 -0.535064697265625 +12392 -0.356719970703125 +12393 -0.629058837890625 +12394 -0.389556884765625 +12395 -0.697601318359375 +12396 -0.3883056640625 +12397 -0.70391845703125 +12398 -0.3502197265625 +12399 -0.6424560546875 +12400 -0.26385498046875 +12401 -0.491241455078125 +12402 -0.13775634765625 +12403 -0.265716552734375 +12404 -0.003204345703125 +12405 -0.023712158203125 +12406 0.121826171875 +12407 0.201751708984375 +12408 0.21844482421875 +12409 0.375823974609375 +12410 0.279327392578125 +12411 0.485076904296875 +12412 0.325439453125 +12413 0.56884765625 +12414 0.360809326171875 +12415 0.634765625 +12416 0.36126708984375 +12417 0.63763427734375 +12418 0.320770263671875 +12419 0.5660400390625 +12420 0.267364501953125 +12421 0.4720458984375 +12422 0.228729248046875 +12423 0.40692138671875 +12424 0.208953857421875 +12425 0.3778076171875 +12426 0.204071044921875 +12427 0.376953125 +12428 0.196990966796875 +12429 0.371978759765625 +12430 0.16131591796875 +12431 0.313140869140625 +12432 0.088653564453125 +12433 0.184417724609375 +12434 -0.007171630859375 +12435 0.011199951171875 +12436 -0.107025146484375 +12437 -0.171051025390625 +12438 -0.197418212890625 +12439 -0.33740234375 +12440 -0.26983642578125 +12441 -0.47198486328125 +12442 -0.316558837890625 +12443 -0.560394287109375 +12444 -0.325836181640625 +12445 -0.58056640625 +12446 -0.30584716796875 +12447 -0.54754638671875 +12448 -0.282073974609375 +12449 -0.508575439453125 +12450 -0.25244140625 +12451 -0.459503173828125 +12452 -0.213958740234375 +12453 -0.394378662109375 +12454 -0.187896728515625 +12455 -0.35260009765625 +12456 -0.162445068359375 +12457 -0.31170654296875 +12458 -0.097991943359375 +12459 -0.197418212890625 +12460 0.0062255859375 +12461 -0.007965087890625 +12462 0.12371826171875 +12463 0.207489013671875 +12464 0.23309326171875 +12465 0.409210205078125 +12466 0.32086181640625 +12467 0.57208251953125 +12468 0.370849609375 +12469 0.66595458984375 +12470 0.36590576171875 +12471 0.65875244140625 +12472 0.315216064453125 +12473 0.56744384765625 +12474 0.239990234375 +12475 0.431396484375 +12476 0.16387939453125 +12477 0.29443359375 +12478 0.100921630859375 +12479 0.182464599609375 +12480 0.034210205078125 +12481 0.06365966796875 +12482 -0.043548583984375 +12483 -0.075958251953125 +12484 -0.107025146484375 +12485 -0.189422607421875 +12486 -0.153533935546875 +12487 -0.271942138671875 +12488 -0.193115234375 +12489 -0.342529296875 +12490 -0.205902099609375 +12491 -0.364166259765625 +12492 -0.186676025390625 +12493 -0.327239990234375 +12494 -0.15966796875 +12495 -0.2769775390625 +12496 -0.146514892578125 +12497 -0.253692626953125 +12498 -0.139862060546875 +12499 -0.24365234375 +12500 -0.113861083984375 +12501 -0.1983642578125 +12502 -0.0677490234375 +12503 -0.116241455078125 +12504 -0.0228271484375 +12505 -0.036834716796875 +12506 0.01806640625 +12507 0.034881591796875 +12508 0.050689697265625 +12509 0.09124755859375 +12510 0.062408447265625 +12511 0.10888671875 +12512 0.07330322265625 +12513 0.125518798828125 +12514 0.0921630859375 +12515 0.15771484375 +12516 0.104339599609375 +12517 0.17828369140625 +12518 0.101104736328125 +12519 0.17108154296875 +12520 0.079193115234375 +12521 0.129974365234375 +12522 0.05328369140625 +12523 0.082427978515625 +12524 0.023040771484375 +12525 0.027679443359375 +12526 -0.02825927734375 +12527 -0.065643310546875 +12528 -0.080108642578125 +12529 -0.15936279296875 +12530 -0.110748291015625 +12531 -0.21307373046875 +12532 -0.124298095703125 +12533 -0.234649658203125 +12534 -0.107818603515625 +12535 -0.2001953125 +12536 -0.0662841796875 +12537 -0.119171142578125 +12538 -0.017364501953125 +12539 -0.024749755859375 +12540 0.04046630859375 +12541 0.085784912109375 +12542 0.088897705078125 +12543 0.178131103515625 +12544 0.1080322265625 +12545 0.215576171875 +12546 0.104949951171875 +12547 0.211456298828125 +12548 0.0845947265625 +12549 0.17523193359375 +12550 0.059326171875 +12551 0.128753662109375 +12552 0.045989990234375 +12553 0.1019287109375 +12554 0.0328369140625 +12555 0.0743408203125 +12556 0.018157958984375 +12557 0.04327392578125 +12558 0.018463134765625 +12559 0.038177490234375 +12560 0.043365478515625 +12561 0.076263427734375 +12562 0.08331298828125 +12563 0.14105224609375 +12564 0.1119384765625 +12565 0.186431884765625 +12566 0.115692138671875 +12567 0.188812255859375 +12568 0.089263916015625 +12569 0.1390380859375 +12570 0.035247802734375 +12571 0.041778564453125 +12572 -0.03302001953125 +12573 -0.079437255859375 +12574 -0.11260986328125 +12575 -0.219390869140625 +12576 -0.1976318359375 +12577 -0.367828369140625 +12578 -0.271087646484375 +12579 -0.494873046875 +12580 -0.307708740234375 +12581 -0.556243896484375 +12582 -0.282867431640625 +12583 -0.508697509765625 +12584 -0.209686279296875 +12585 -0.3756103515625 +12586 -0.12322998046875 +12587 -0.218902587890625 +12588 -0.037628173828125 +12589 -0.063751220703125 +12590 0.048187255859375 +12591 0.091552734375 +12592 0.12811279296875 +12593 0.23602294921875 +12594 0.1871337890625 +12595 0.342987060546875 +12596 0.215545654296875 +12597 0.39520263671875 +12598 0.211517333984375 +12599 0.389373779296875 +12600 0.174346923828125 +12601 0.324249267578125 +12602 0.117828369140625 +12603 0.224090576171875 +12604 0.06201171875 +12605 0.124267578125 +12606 0.0137939453125 +12607 0.037078857421875 +12608 -0.01129150390625 +12609 -0.010101318359375 +12610 -0.014617919921875 +12611 -0.019439697265625 +12612 -0.014373779296875 +12613 -0.022796630859375 +12614 -0.0001220703125 +12615 -0.001556396484375 +12616 0.0347900390625 +12617 0.056304931640625 +12618 0.06524658203125 +12619 0.106719970703125 +12620 0.0611572265625 +12621 0.096893310546875 +12622 0.031494140625 +12623 0.042694091796875 +12624 -0.002288818359375 +12625 -0.018035888671875 +12626 -0.03485107421875 +12627 -0.07586669921875 +12628 -0.05975341796875 +12629 -0.11944580078125 +12630 -0.08319091796875 +12631 -0.15972900390625 +12632 -0.108489990234375 +12633 -0.202606201171875 +12634 -0.1358642578125 +12635 -0.24859619140625 +12636 -0.16949462890625 +12637 -0.30517578125 +12638 -0.2034912109375 +12639 -0.36212158203125 +12640 -0.22186279296875 +12641 -0.39141845703125 +12642 -0.2030029296875 +12643 -0.35528564453125 +12644 -0.14471435546875 +12645 -0.249969482421875 +12646 -0.05682373046875 +12647 -0.092864990234375 +12648 0.04541015625 +12649 0.08905029296875 +12650 0.127655029296875 +12651 0.2352294921875 +12652 0.174713134765625 +12653 0.318817138671875 +12654 0.197265625 +12655 0.358642578125 +12656 0.191375732421875 +12657 0.347747802734375 +12658 0.15673828125 +12659 0.28564453125 +12660 0.1221923828125 +12661 0.223175048828125 +12662 0.10833740234375 +12663 0.196746826171875 +12664 0.10003662109375 +12665 0.179840087890625 +12666 0.087615966796875 +12667 0.155548095703125 +12668 0.0865478515625 +12669 0.151214599609375 +12670 0.09112548828125 +12671 0.156951904296875 +12672 0.0780029296875 +12673 0.13177490234375 +12674 0.061370849609375 +12675 0.100799560546875 +12676 0.054290771484375 +12677 0.087127685546875 +12678 0.036376953125 +12679 0.05487060546875 +12680 0.00018310546875 +12681 -0.009002685546875 +12682 -0.053955078125 +12683 -0.10400390625 +12684 -0.125640869140625 +12685 -0.229400634765625 +12686 -0.197967529296875 +12687 -0.35552978515625 +12688 -0.247894287109375 +12689 -0.441925048828125 +12690 -0.26702880859375 +12691 -0.473846435546875 +12692 -0.262939453125 +12693 -0.464813232421875 +12694 -0.238006591796875 +12695 -0.419097900390625 +12696 -0.19085693359375 +12697 -0.334320068359375 +12698 -0.131317138671875 +12699 -0.227935791015625 +12700 -0.072723388671875 +12701 -0.12347412109375 +12702 -0.018829345703125 +12703 -0.02764892578125 +12704 0.0406494140625 +12705 0.077667236328125 +12706 0.117523193359375 +12707 0.2132568359375 +12708 0.217315673828125 +12709 0.38885498046875 +12710 0.32769775390625 +12711 0.582794189453125 +12712 0.41400146484375 +12713 0.734039306640625 +12714 0.45208740234375 +12715 0.800140380859375 +12716 0.4403076171875 +12717 0.7783203125 +12718 0.376708984375 +12719 0.6651611328125 +12720 0.260711669921875 +12721 0.45965576171875 +12722 0.113525390625 +12723 0.199188232421875 +12724 -0.027679443359375 +12725 -0.050689697265625 +12726 -0.13055419921875 +12727 -0.23297119140625 +12728 -0.185211181640625 +12729 -0.33013916015625 +12730 -0.206512451171875 +12731 -0.368408203125 +12732 -0.21221923828125 +12733 -0.378936767578125 +12734 -0.21099853515625 +12735 -0.376983642578125 +12736 -0.212615966796875 +12737 -0.37969970703125 +12738 -0.21954345703125 +12739 -0.391510009765625 +12740 -0.216400146484375 +12741 -0.385345458984375 +12742 -0.19219970703125 +12743 -0.3419189453125 +12744 -0.15924072265625 +12745 -0.28289794921875 +12746 -0.14208984375 +12747 -0.251617431640625 +12748 -0.150970458984375 +12749 -0.266143798828125 +12750 -0.155670166015625 +12751 -0.273345947265625 +12752 -0.124114990234375 +12753 -0.216796875 +12754 -0.074310302734375 +12755 -0.128265380859375 +12756 -0.040557861328125 +12757 -0.068145751953125 +12758 -0.02655029296875 +12759 -0.0430908203125 +12760 -0.01605224609375 +12761 -0.024444580078125 +12762 0.0096435546875 +12763 0.020721435546875 +12764 0.0687255859375 +12765 0.124481201171875 +12766 0.144744873046875 +12767 0.25787353515625 +12768 0.213958740234375 +12769 0.379119873046875 +12770 0.271636962890625 +12771 0.47991943359375 +12772 0.29949951171875 +12773 0.5281982421875 +12774 0.290283203125 +12775 0.511138916015625 +12776 0.259552001953125 +12777 0.456207275390625 +12778 0.232330322265625 +12779 0.407470703125 +12780 0.21923828125 +12781 0.383758544921875 +12782 0.204254150390625 +12783 0.35687255859375 +12784 0.178863525390625 +12785 0.31182861328125 +12786 0.14434814453125 +12787 0.250885009765625 +12788 0.095794677734375 +12789 0.1654052734375 +12790 0.021759033203125 +12791 0.035247802734375 +12792 -0.079132080078125 +12793 -0.142059326171875 +12794 -0.1893310546875 +12795 -0.33563232421875 +12796 -0.3026123046875 +12797 -0.5345458984375 +12798 -0.409332275390625 +12799 -0.72186279296875 +12800 -0.474395751953125 +12801 -0.836669921875 +12802 -0.470855712890625 +12803 -0.8326416015625 +12804 -0.410552978515625 +12805 -0.7296142578125 +12806 -0.326019287109375 +12807 -0.582550048828125 +12808 -0.24591064453125 +12809 -0.440093994140625 +12810 -0.18292236328125 +12811 -0.324310302734375 +12812 -0.116241455078125 +12813 -0.20147705078125 +12814 -0.029205322265625 +12815 -0.044647216796875 +12816 0.053314208984375 +12817 0.103973388671875 +12818 0.106475830078125 +12819 0.202392578125 +12820 0.138916015625 +12821 0.264495849609375 +12822 0.180084228515625 +12823 0.338897705078125 +12824 0.24102783203125 +12825 0.443817138671875 +12826 0.301300048828125 +12827 0.545074462890625 +12828 0.34564208984375 +12829 0.6173095703125 +12830 0.369140625 +12831 0.6524658203125 +12832 0.379302978515625 +12833 0.66339111328125 +12834 0.3795166015625 +12835 0.6561279296875 +12836 0.355133056640625 +12837 0.606781005859375 +12838 0.29736328125 +12839 0.501190185546875 +12840 0.21392822265625 +12841 0.352783203125 +12842 0.113525390625 +12843 0.176544189453125 +12844 -0.008514404296875 +12845 -0.034820556640625 +12846 -0.1385498046875 +12847 -0.258209228515625 +12848 -0.24609375 +12849 -0.44244384765625 +12850 -0.323944091796875 +12851 -0.5753173828125 +12852 -0.36932373046875 +12853 -0.65203857421875 +12854 -0.3636474609375 +12855 -0.641632080078125 +12856 -0.31768798828125 +12857 -0.562164306640625 +12858 -0.257965087890625 +12859 -0.458038330078125 +12860 -0.197052001953125 +12861 -0.350555419921875 +12862 -0.147216796875 +12863 -0.260528564453125 +12864 -0.110687255859375 +12865 -0.192108154296875 +12866 -0.085235595703125 +12867 -0.141937255859375 +12868 -0.06585693359375 +12869 -0.1021728515625 +12870 -0.04638671875 +12871 -0.062896728515625 +12872 -0.019317626953125 +12873 -0.011932373046875 +12874 0.022796630859375 +12875 0.062835693359375 +12876 0.072479248046875 +12877 0.148712158203125 +12878 0.127410888671875 +12879 0.241729736328125 +12880 0.191925048828125 +12881 0.34912109375 +12882 0.25787353515625 +12883 0.457305908203125 +12884 0.311737060546875 +12885 0.54388427734375 +12886 0.331817626953125 +12887 0.5728759765625 +12888 0.295318603515625 +12889 0.506591796875 +12890 0.20574951171875 +12891 0.351226806640625 +12892 0.08673095703125 +12893 0.146514892578125 +12894 -0.030548095703125 +12895 -0.05523681640625 +12896 -0.123626708984375 +12897 -0.21624755859375 +12898 -0.19171142578125 +12899 -0.334930419921875 +12900 -0.22998046875 +12901 -0.402984619140625 +12902 -0.2510986328125 +12903 -0.4412841796875 +12904 -0.28271484375 +12905 -0.49578857421875 +12906 -0.321075439453125 +12907 -0.5601806640625 +12908 -0.345947265625 +12909 -0.600738525390625 +12910 -0.33734130859375 +12911 -0.584228515625 +12912 -0.2763671875 +12913 -0.47930908203125 +12914 -0.158905029296875 +12915 -0.27935791015625 +12916 0.00042724609375 +12917 -0.0089111328125 +12918 0.16387939453125 +12919 0.268798828125 +12920 0.2890625 +12921 0.482818603515625 +12922 0.358489990234375 +12923 0.60369873046875 +12924 0.383697509765625 +12925 0.650421142578125 +12926 0.38946533203125 +12927 0.66400146484375 +12928 0.3741455078125 +12929 0.6414794921875 +12930 0.33160400390625 +12931 0.572540283203125 +12932 0.286468505859375 +12933 0.498138427734375 +12934 0.25146484375 +12935 0.439453125 +12936 0.213958740234375 +12937 0.375518798828125 +12938 0.154815673828125 +12939 0.274505615234375 +12940 0.057342529296875 +12941 0.1087646484375 +12942 -0.065185546875 +12943 -0.099395751953125 +12944 -0.193878173828125 +12945 -0.3182373046875 +12946 -0.32958984375 +12947 -0.5489501953125 +12948 -0.461822509765625 +12949 -0.7738037109375 +12950 -0.5589599609375 +12951 -0.86383056640625 +12952 -0.601165771484375 +12953 -0.870391845703125 +12954 -0.599212646484375 +12955 -0.86895751953125 +12956 -0.56103515625 +12957 -0.861053466796875 +12958 -0.476318359375 +12959 -0.765869140625 +12960 -0.33831787109375 +12961 -0.5301513671875 +12962 -0.151275634765625 +12963 -0.214691162109375 +12964 0.05902099609375 +12965 0.137359619140625 +12966 0.2618408203125 +12967 0.474822998046875 +12968 0.43597412109375 +12969 0.76239013671875 +12970 0.565338134765625 +12971 0.867462158203125 +12972 0.65032958984375 +12973 0.870361328125 +12974 0.684112548828125 +12975 0.86480712890625 +12976 0.670013427734375 +12977 0.831817626953125 +12978 0.622772216796875 +12979 0.677581787109375 +12980 0.545928955078125 +12981 0.495880126953125 +12982 0.45074462890625 +12983 0.30767822265625 +12984 0.33856201171875 +12985 0.116180419921875 +12986 0.190399169921875 +12987 -0.110748291015625 +12988 0.002105712890625 +12989 -0.381805419921875 +12990 -0.200653076171875 +12991 -0.6572265625 +12992 -0.381988525390625 +12993 -0.857421875 +12994 -0.5162353515625 +12995 -0.870391845703125 +12996 -0.59918212890625 +12997 -0.870391845703125 +12998 -0.647064208984375 +12999 -0.86444091796875 +13000 -0.68133544921875 +13001 -0.85723876953125 +13002 -0.69110107421875 +13003 -0.790008544921875 +13004 -0.643890380859375 +13005 -0.62847900390625 +13006 -0.53790283203125 +13007 -0.3956298828125 +13008 -0.392913818359375 +13009 -0.126708984375 +13010 -0.225433349609375 +13011 0.150115966796875 +13012 -0.042510986328125 +13013 0.424041748046875 +13014 0.1396484375 +13015 0.670623779296875 +13016 0.297821044921875 +13017 0.854522705078125 +13018 0.421417236328125 +13019 0.866485595703125 +13020 0.501220703125 +13021 0.86920166015625 +13022 0.548187255859375 +13023 0.8653564453125 +13024 0.570404052734375 +13025 0.857147216796875 +13026 0.566192626953125 +13027 0.766845703125 +13028 0.5386962890625 +13029 0.628509521484375 +13030 0.483978271484375 +13031 0.462127685546875 +13032 0.417572021484375 +13033 0.297210693359375 +13034 0.346954345703125 +13035 0.14862060546875 +13036 0.258514404296875 +13037 -0.00537109375 +13038 0.156768798828125 +13039 -0.15753173828125 +13040 0.039581298828125 +13041 -0.31304931640625 +13042 -0.101409912109375 +13043 -0.48876953125 +13044 -0.238067626953125 +13045 -0.6416015625 +13046 -0.3555908203125 +13047 -0.751373291015625 +13048 -0.46783447265625 +13049 -0.84619140625 +13050 -0.566009521484375 +13051 -0.861297607421875 +13052 -0.630279541015625 +13053 -0.863250732421875 +13054 -0.6417236328125 +13055 -0.856597900390625 +13056 -0.608306884765625 +13057 -0.7498779296875 +13058 -0.565582275390625 +13059 -0.624542236328125 +13060 -0.49896240234375 +13061 -0.47808837890625 +13062 -0.371246337890625 +13063 -0.253387451171875 +13064 -0.211029052734375 +13065 0.003692626953125 +13066 -0.06121826171875 +13067 0.2257080078125 +13068 0.086456298828125 +13069 0.427154541015625 +13070 0.252777099609375 +13071 0.643218994140625 +13072 0.431976318359375 +13073 0.855926513671875 +13074 0.58770751953125 +13075 0.870361328125 +13076 0.6888427734375 +13077 0.870361328125 +13078 0.74005126953125 +13079 0.862762451171875 +13080 0.739532470703125 +13081 0.79669189453125 +13082 0.68133544921875 +13083 0.595794677734375 +13084 0.583831787109375 +13085 0.362152099609375 +13086 0.464630126953125 +13087 0.1270751953125 +13088 0.336944580078125 +13089 -0.086944580078125 +13090 0.20184326171875 +13091 -0.2784423828125 +13092 0.037109375 +13093 -0.484832763671875 +13094 -0.169586181640625 +13095 -0.729583740234375 +13096 -0.38653564453125 +13097 -0.86688232421875 +13098 -0.573944091796875 +13099 -0.870391845703125 +13100 -0.728851318359375 +13101 -0.86859130859375 +13102 -0.85009765625 +13103 -0.86279296875 +13104 -0.861114501953125 +13105 -0.817962646484375 +13106 -0.85894775390625 +13107 -0.6116943359375 +13108 -0.78582763671875 +13109 -0.3128662109375 +13110 -0.608367919921875 +13111 0.039398193359375 +13112 -0.375335693359375 +13113 0.422821044921875 +13114 -0.107696533203125 +13115 0.805145263671875 +13116 0.151580810546875 +13117 0.870361328125 +13118 0.366607666015625 +13119 0.870361328125 +13120 0.53009033203125 +13121 0.860015869140625 +13122 0.637237548828125 +13123 0.727935791015625 +13124 0.68450927734375 +13125 0.48114013671875 +13126 0.687225341796875 +13127 0.2059326171875 +13128 0.659698486328125 +13129 -0.06103515625 +13130 0.6082763671875 +13131 -0.29913330078125 +13132 0.5238037109375 +13133 -0.516204833984375 +13134 0.396575927734375 +13135 -0.7252197265625 +13136 0.24237060546875 +13137 -0.85980224609375 +13138 0.08294677734375 +13139 -0.870391845703125 +13140 -0.0628662109375 +13141 -0.870391845703125 +13142 -0.164154052734375 +13143 -0.858062744140625 +13144 -0.218109130859375 +13145 -0.673004150390625 +13146 -0.257720947265625 +13147 -0.42694091796875 +13148 -0.31085205078125 +13149 -0.2100830078125 +13150 -0.376007080078125 +13151 -0.0362548828125 +13152 -0.43463134765625 +13153 0.10943603515625 +13154 -0.474029541015625 +13155 0.23516845703125 +13156 -0.467987060546875 +13157 0.373687744140625 +13158 -0.41766357421875 +13159 0.517791748046875 +13160 -0.362884521484375 +13161 0.602783203125 +13162 -0.300445556640625 +13163 0.635711669921875 +13164 -0.209381103515625 +13165 0.655181884765625 +13166 -0.09613037109375 +13167 0.65948486328125 +13168 0.033966064453125 +13169 0.651275634765625 +13170 0.165191650390625 +13171 0.61846923828125 +13172 0.27392578125 +13173 0.53753662109375 +13174 0.3485107421875 +13175 0.404144287109375 +13176 0.382568359375 +13177 0.22186279296875 +13178 0.37664794921875 +13179 0.003997802734375 +13180 0.342010498046875 +13181 -0.22100830078125 +13182 0.291595458984375 +13183 -0.42449951171875 +13184 0.23883056640625 +13185 -0.579833984375 +13186 0.210723876953125 +13187 -0.641876220703125 +13188 0.203125 +13189 -0.6177978515625 +13190 0.17529296875 +13191 -0.575531005859375 +13192 0.123992919921875 +13193 -0.526336669921875 +13194 0.082183837890625 +13195 -0.42645263671875 +13196 0.067413330078125 +13197 -0.2581787109375 +13198 0.056915283203125 +13199 -0.068695068359375 +13200 0.026641845703125 +13201 0.09222412109375 +13202 -0.011322021484375 +13203 0.232147216796875 +13204 -0.05035400390625 +13205 0.3509521484375 +13206 -0.10894775390625 +13207 0.410064697265625 +13208 -0.20550537109375 +13209 0.372955322265625 +13210 -0.32666015625 +13211 0.2554931640625 +13212 -0.439361572265625 +13213 0.10711669921875 +13214 -0.531219482421875 +13215 -0.052886962890625 +13216 -0.579345703125 +13217 -0.186279296875 +13218 -0.548492431640625 +13219 -0.23291015625 +13220 -0.45318603515625 +13221 -0.209442138671875 +13222 -0.335235595703125 +13223 -0.174163818359375 +13224 -0.200042724609375 +13225 -0.126739501953125 +13226 -0.0416259765625 +13227 -0.048126220703125 +13228 0.121917724609375 +13229 0.0426025390625 +13230 0.260894775390625 +13231 0.10748291015625 +13232 0.36669921875 +13233 0.1409912109375 +13234 0.469207763671875 +13235 0.19708251953125 +13236 0.56396484375 +13237 0.273651123046875 +13238 0.615509033203125 +13239 0.31768798828125 +13240 0.630706787109375 +13241 0.341094970703125 +13242 0.62548828125 +13243 0.368011474609375 +13244 0.5853271484375 +13245 0.37249755859375 +13246 0.479156494140625 +13247 0.30072021484375 +13248 0.3101806640625 +13249 0.1517333984375 +13250 0.12060546875 +13251 -0.01470947265625 +13252 -0.078155517578125 +13253 -0.1883544921875 +13254 -0.283355712890625 +13255 -0.372711181640625 +13256 -0.456146240234375 +13257 -0.51397705078125 +13258 -0.56658935546875 +13259 -0.57177734375 +13260 -0.606781005859375 +13261 -0.53948974609375 +13262 -0.585174560546875 +13263 -0.43511962890625 +13264 -0.523590087890625 +13265 -0.2962646484375 +13266 -0.44525146484375 +13267 -0.161102294921875 +13268 -0.359100341796875 +13269 -0.0435791015625 +13270 -0.2637939453125 +13271 0.060394287109375 +13272 -0.17034912109375 +13273 0.13665771484375 +13274 -0.091217041015625 +13275 0.170135498046875 +13276 -0.026947021484375 +13277 0.16552734375 +13278 0.040252685546875 +13279 0.15728759765625 +13280 0.1097412109375 +13281 0.150787353515625 +13282 0.1622314453125 +13283 0.12200927734375 +13284 0.19976806640625 +13285 0.080108642578125 +13286 0.235595703125 +13287 0.05126953125 +13288 0.284393310546875 +13289 0.062896728515625 +13290 0.33013916015625 +13291 0.09271240234375 +13292 0.341644287109375 +13293 0.092987060546875 +13294 0.328094482421875 +13295 0.07855224609375 +13296 0.299591064453125 +13297 0.06427001953125 +13298 0.2479248046875 +13299 0.0347900390625 +13300 0.174072265625 +13301 -0.01171875 +13302 0.09295654296875 +13303 -0.056060791015625 +13304 0.03472900390625 +13305 -0.055511474609375 +13306 0.00250244140625 +13307 -0.010467529296875 +13308 -0.034454345703125 +13309 0.02508544921875 +13310 -0.089019775390625 +13311 0.025665283203125 +13312 -0.14166259765625 +13313 0.017333984375 +13314 -0.18902587890625 +13315 0.00189208984375 +13316 -0.236572265625 +13317 -0.03173828125 +13318 -0.2755126953125 +13319 -0.071502685546875 +13320 -0.3172607421875 +13321 -0.13543701171875 +13322 -0.359954833984375 +13323 -0.219970703125 +13324 -0.38861083984375 +13325 -0.300506591796875 +13326 -0.404388427734375 +13327 -0.376312255859375 +13328 -0.389068603515625 +13329 -0.416107177734375 +13330 -0.31341552734375 +13331 -0.371124267578125 +13332 -0.180694580078125 +13333 -0.242279052734375 +13334 -0.019744873046875 +13335 -0.069732666015625 +13336 0.153167724609375 +13337 0.125640869140625 +13338 0.315399169921875 +13339 0.31268310546875 +13340 0.4412841796875 +13341 0.45501708984375 +13342 0.53057861328125 +13343 0.554779052734375 +13344 0.581390380859375 +13345 0.61065673828125 +13346 0.5855712890625 +13347 0.610931396484375 +13348 0.527557373046875 +13349 0.531463623046875 +13350 0.41839599609375 +13351 0.3883056640625 +13352 0.293853759765625 +13353 0.23468017578125 +13354 0.17156982421875 +13355 0.095245361328125 +13356 0.070343017578125 +13357 -0.00396728515625 +13358 0.001708984375 +13359 -0.04852294921875 +13360 -0.04290771484375 +13361 -0.055145263671875 +13362 -0.095123291015625 +13363 -0.0758056640625 +13364 -0.171173095703125 +13365 -0.138702392578125 +13366 -0.2467041015625 +13367 -0.209197998046875 +13368 -0.321380615234375 +13369 -0.289031982421875 +13370 -0.394622802734375 +13371 -0.37884521484375 +13372 -0.451324462890625 +13373 -0.456329345703125 +13374 -0.48809814453125 +13375 -0.51641845703125 +13376 -0.47943115234375 +13377 -0.519287109375 +13378 -0.421783447265625 +13379 -0.458251953125 +13380 -0.34979248046875 +13381 -0.384796142578125 +13382 -0.281097412109375 +13383 -0.323699951171875 +13384 -0.21368408203125 +13385 -0.269287109375 +13386 -0.132293701171875 +13387 -0.1951904296875 +13388 -0.037841796875 +13389 -0.100006103515625 +13390 0.050445556640625 +13391 -0.01055908203125 +13392 0.150665283203125 +13393 0.1033935546875 +13394 0.2662353515625 +13395 0.24908447265625 +13396 0.361480712890625 +13397 0.373199462890625 +13398 0.42431640625 +13399 0.45806884765625 +13400 0.4595947265625 +13401 0.511474609375 +13402 0.48828125 +13403 0.565399169921875 +13404 0.505401611328125 +13405 0.61138916015625 +13406 0.473052978515625 +13407 0.5897216796875 +13408 0.385986328125 +13409 0.4906005859375 +13410 0.256927490234375 +13411 0.33148193359375 +13412 0.110382080078125 +13413 0.147796630859375 +13414 -0.0250244140625 +13415 -0.01873779296875 +13416 -0.129730224609375 +13417 -0.140289306640625 +13418 -0.1861572265625 +13419 -0.191986083984375 +13420 -0.199981689453125 +13421 -0.184295654296875 +13422 -0.19927978515625 +13423 -0.161834716796875 +13424 -0.210723876953125 +13425 -0.166595458984375 +13426 -0.230987548828125 +13427 -0.19390869140625 +13428 -0.24749755859375 +13429 -0.22442626953125 +13430 -0.274658203125 +13431 -0.279754638671875 +13432 -0.299530029296875 +13433 -0.3389892578125 +13434 -0.2919921875 +13435 -0.3543701171875 +13436 -0.267578125 +13437 -0.348175048828125 +13438 -0.2310791015625 +13439 -0.32598876953125 +13440 -0.164520263671875 +13441 -0.2581787109375 +13442 -0.065887451171875 +13443 -0.139801025390625 +13444 0.05419921875 +13445 0.014617919921875 +13446 0.155242919921875 +13447 0.144378662109375 +13448 0.217926025390625 +13449 0.221038818359375 +13450 0.258636474609375 +13451 0.27069091796875 +13452 0.27752685546875 +13453 0.294036865234375 +13454 0.2879638671875 +13455 0.311767578125 +13456 0.30010986328125 +13457 0.339141845703125 +13458 0.30419921875 +13459 0.360260009765625 +13460 0.2913818359375 +13461 0.360504150390625 +13462 0.241455078125 +13463 0.308380126953125 +13464 0.140533447265625 +13465 0.18170166015625 +13466 0.0057373046875 +13467 0.0047607421875 +13468 -0.13092041015625 +13469 -0.17559814453125 +13470 -0.238677978515625 +13471 -0.3143310546875 +13472 -0.28778076171875 +13473 -0.36785888671875 +13474 -0.295013427734375 +13475 -0.36248779296875 +13476 -0.289947509765625 +13477 -0.343536376953125 +13478 -0.266265869140625 +13479 -0.3018798828125 +13480 -0.219757080078125 +13481 -0.231414794921875 +13482 -0.140899658203125 +13483 -0.117645263671875 +13484 -0.05145263671875 +13485 0.007049560546875 +13486 0.011810302734375 +13487 0.087982177734375 +13488 0.057769775390625 +13489 0.13946533203125 +13490 0.094207763671875 +13491 0.17425537109375 +13492 0.117584228515625 +13493 0.188201904296875 +13494 0.120452880859375 +13495 0.171234130859375 +13496 0.0987548828125 +13497 0.118438720703125 +13498 0.06988525390625 +13499 0.05706787109375 +13500 0.03466796875 +13501 -0.010711669921875 +13502 -0.011688232421875 +13503 -0.0914306640625 +13504 -0.05438232421875 +13505 -0.162322998046875 +13506 -0.074432373046875 +13507 -0.194549560546875 +13508 -0.046051025390625 +13509 -0.1492919921875 +13510 0.034149169921875 +13511 -0.02166748046875 +13512 0.12384033203125 +13513 0.124053955078125 +13514 0.172515869140625 +13515 0.211151123046875 +13516 0.181304931640625 +13517 0.240447998046875 +13518 0.170928955078125 +13519 0.242218017578125 +13520 0.148223876953125 +13521 0.2257080078125 +13522 0.1160888671875 +13523 0.194366455078125 +13524 0.053436279296875 +13525 0.115509033203125 +13526 -0.0234375 +13527 0.0128173828125 +13528 -0.074371337890625 +13529 -0.053802490234375 +13530 -0.116455078125 +13531 -0.110626220703125 +13532 -0.177337646484375 +13533 -0.199493408203125 +13534 -0.239715576171875 +13535 -0.29437255859375 +13536 -0.261810302734375 +13537 -0.33221435546875 +13538 -0.221771240234375 +13539 -0.27972412109375 +13540 -0.152099609375 +13541 -0.185333251953125 +13542 -0.10577392578125 +13543 -0.128204345703125 +13544 -0.088134765625 +13545 -0.115692138671875 +13546 -0.078948974609375 +13547 -0.116455078125 +13548 -0.06243896484375 +13549 -0.105926513671875 +13550 -0.01910400390625 +13551 -0.053955078125 +13552 0.056793212890625 +13553 0.048797607421875 +13554 0.134979248046875 +13555 0.157318115234375 +13556 0.17559814453125 +13557 0.212005615234375 +13558 0.182159423828125 +13559 0.218475341796875 +13560 0.194793701171875 +13561 0.23724365234375 +13562 0.2381591796875 +13563 0.30535888671875 +13564 0.284820556640625 +13565 0.38128662109375 +13566 0.2947998046875 +13567 0.404449462890625 +13568 0.28204345703125 +13569 0.3944091796875 +13570 0.27239990234375 +13571 0.3885498046875 +13572 0.249267578125 +13573 0.362640380859375 +13574 0.18280029296875 +13575 0.27362060546875 +13576 0.070068359375 +13577 0.11712646484375 +13578 -0.052642822265625 +13579 -0.054901123046875 +13580 -0.14935302734375 +13581 -0.19085693359375 +13582 -0.216522216796875 +13583 -0.28570556640625 +13584 -0.253997802734375 +13585 -0.339263916015625 +13586 -0.279937744140625 +13587 -0.3775634765625 +13588 -0.3258056640625 +13589 -0.445709228515625 +13590 -0.38568115234375 +13591 -0.535064697265625 +13592 -0.44818115234375 +13593 -0.629058837890625 +13594 -0.49249267578125 +13595 -0.697601318359375 +13596 -0.49322509765625 +13597 -0.70391845703125 +13598 -0.446746826171875 +13599 -0.6424560546875 +13600 -0.33795166015625 +13601 -0.491241455078125 +13602 -0.177734375 +13603 -0.265716552734375 +13604 -0.00653076171875 +13605 -0.023712158203125 +13606 0.15252685546875 +13607 0.201751708984375 +13608 0.27508544921875 +13609 0.375823974609375 +13610 0.35174560546875 +13611 0.485076904296875 +13612 0.409881591796875 +13613 0.56884765625 +13614 0.454864501953125 +13615 0.634765625 +13616 0.455291748046875 +13617 0.63763427734375 +13618 0.4033203125 +13619 0.5660400390625 +13620 0.3353271484375 +13621 0.4720458984375 +13622 0.287109375 +13623 0.40692138671875 +13624 0.263824462890625 +13625 0.3778076171875 +13626 0.260223388671875 +13627 0.376953125 +13628 0.25396728515625 +13629 0.371978759765625 +13630 0.2105712890625 +13631 0.313140869140625 +13632 0.1190185546875 +13633 0.184417724609375 +13634 -0.002899169921875 +13635 0.011199951171875 +13636 -0.130462646484375 +13637 -0.171051025390625 +13638 -0.246337890625 +13639 -0.33740234375 +13640 -0.339447021484375 +13641 -0.47198486328125 +13642 -0.39984130859375 +13643 -0.560394287109375 +13644 -0.4122314453125 +13645 -0.58056640625 +13646 -0.38720703125 +13647 -0.54754638671875 +13648 -0.357757568359375 +13649 -0.508575439453125 +13650 -0.321136474609375 +13651 -0.459503173828125 +13652 -0.273345947265625 +13653 -0.394378662109375 +13654 -0.241943359375 +13655 -0.35260009765625 +13656 -0.211395263671875 +13657 -0.31170654296875 +13658 -0.130096435546875 +13659 -0.197418212890625 +13660 0.0030517578125 +13661 -0.007965087890625 +13662 0.153778076171875 +13663 0.207489013671875 +13664 0.294403076171875 +13665 0.409210205078125 +13666 0.407470703125 +13667 0.57208251953125 +13668 0.47198486328125 +13669 0.66595458984375 +13670 0.4656982421875 +13671 0.65875244140625 +13672 0.4005126953125 +13673 0.56744384765625 +13674 0.303955078125 +13675 0.431396484375 +13676 0.206634521484375 +13677 0.29443359375 +13678 0.126678466796875 +13679 0.182464599609375 +13680 0.04205322265625 +13681 0.06365966796875 +13682 -0.056884765625 +13683 -0.075958251953125 +13684 -0.137359619140625 +13685 -0.189422607421875 +13686 -0.1959228515625 +13687 -0.271942138671875 +13688 -0.245758056640625 +13689 -0.342529296875 +13690 -0.2611083984375 +13691 -0.364166259765625 +13692 -0.23529052734375 +13693 -0.327239990234375 +13694 -0.19976806640625 +13695 -0.2769775390625 +13696 -0.182647705078125 +13697 -0.253692626953125 +13698 -0.1744384765625 +13699 -0.24365234375 +13700 -0.1414794921875 +13701 -0.1983642578125 +13702 -0.082733154296875 +13703 -0.116241455078125 +13704 -0.025787353515625 +13705 -0.036834716796875 +13706 0.0257568359375 +13707 0.034881591796875 +13708 0.066497802734375 +13709 0.09124755859375 +13710 0.080078125 +13711 0.10888671875 +13712 0.0926513671875 +13713 0.125518798828125 +13714 0.115753173828125 +13715 0.15771484375 +13716 0.13043212890625 +13717 0.17828369140625 +13718 0.12542724609375 +13719 0.17108154296875 +13720 0.09649658203125 +13721 0.129974365234375 +13722 0.062744140625 +13723 0.082427978515625 +13724 0.023712158203125 +13725 0.027679443359375 +13726 -0.0423583984375 +13727 -0.065643310546875 +13728 -0.10882568359375 +13729 -0.15936279296875 +13730 -0.14752197265625 +13731 -0.21307373046875 +13732 -0.163848876953125 +13733 -0.234649658203125 +13734 -0.14111328125 +13735 -0.2001953125 +13736 -0.0858154296875 +13737 -0.119171142578125 +13738 -0.02099609375 +13739 -0.024749755859375 +13740 0.055267333984375 +13741 0.085784912109375 +13742 0.119110107421875 +13743 0.178131103515625 +13744 0.14501953125 +13745 0.215576171875 +13746 0.142242431640625 +13747 0.211456298828125 +13748 0.117401123046875 +13749 0.17523193359375 +13750 0.085662841796875 +13751 0.128753662109375 +13752 0.06781005859375 +13753 0.1019287109375 +13754 0.049591064453125 +13755 0.0743408203125 +13756 0.029052734375 +13757 0.04327392578125 +13758 0.026611328125 +13759 0.038177490234375 +13760 0.054168701171875 +13761 0.076263427734375 +13762 0.100189208984375 +13763 0.14105224609375 +13764 0.132568359375 +13765 0.186431884765625 +13766 0.13482666015625 +13767 0.188812255859375 +13768 0.100555419921875 +13769 0.1390380859375 +13770 0.033050537109375 +13771 0.041778564453125 +13772 -0.05133056640625 +13773 -0.079437255859375 +13774 -0.148956298828125 +13775 -0.219390869140625 +13776 -0.252655029296875 +13777 -0.367828369140625 +13778 -0.34161376953125 +13779 -0.494873046875 +13780 -0.385009765625 +13781 -0.556243896484375 +13782 -0.352691650390625 +13783 -0.508697509765625 +13784 -0.2608642578125 +13785 -0.3756103515625 +13786 -0.152618408203125 +13787 -0.218902587890625 +13788 -0.045379638671875 +13789 -0.063751220703125 +13790 0.06201171875 +13791 0.091552734375 +13792 0.161956787109375 +13793 0.23602294921875 +13794 0.235931396484375 +13795 0.342987060546875 +13796 0.27197265625 +13797 0.39520263671875 +13798 0.267791748046875 +13799 0.389373779296875 +13800 0.2225341796875 +13801 0.324249267578125 +13802 0.153076171875 +13803 0.224090576171875 +13804 0.084014892578125 +13805 0.124267578125 +13806 0.023834228515625 +13807 0.037078857421875 +13808 -0.008392333984375 +13809 -0.010101318359375 +13810 -0.01422119140625 +13811 -0.019439697265625 +13812 -0.015869140625 +13813 -0.022796630859375 +13814 -0.000396728515625 +13815 -0.001556396484375 +13816 0.040496826171875 +13817 0.056304931640625 +13818 0.07611083984375 +13819 0.106719970703125 +13820 0.069671630859375 +13821 0.096893310546875 +13822 0.0322265625 +13823 0.042694091796875 +13824 -0.010223388671875 +13825 -0.018035888671875 +13826 -0.0509033203125 +13827 -0.07586669921875 +13828 -0.081329345703125 +13829 -0.11944580078125 +13830 -0.109619140625 +13831 -0.15972900390625 +13832 -0.140167236328125 +13833 -0.202606201171875 +13834 -0.173370361328125 +13835 -0.24859619140625 +13836 -0.2147216796875 +13837 -0.30517578125 +13838 -0.256805419921875 +13839 -0.36212158203125 +13840 -0.279205322265625 +13841 -0.39141845703125 +13842 -0.254302978515625 +13843 -0.35528564453125 +13844 -0.17926025390625 +13845 -0.249969482421875 +13846 -0.066680908203125 +13847 -0.092864990234375 +13848 0.063934326171875 +13849 0.08905029296875 +13850 0.168609619140625 +13851 0.2352294921875 +13852 0.2279052734375 +13853 0.318817138671875 +13854 0.255615234375 +13855 0.358642578125 +13856 0.246734619140625 +13857 0.347747802734375 +13858 0.200927734375 +13859 0.28564453125 +13860 0.155242919921875 +13861 0.223175048828125 +13862 0.136199951171875 +13863 0.196746826171875 +13864 0.124481201171875 +13865 0.179840087890625 +13866 0.107757568359375 +13867 0.155548095703125 +13868 0.1058349609375 +13869 0.151214599609375 +13870 0.1114501953125 +13871 0.156951904296875 +13872 0.09466552734375 +13873 0.13177490234375 +13874 0.07366943359375 +13875 0.100799560546875 +13876 0.065185546875 +13877 0.087127685546875 +13878 0.04302978515625 +13879 0.05487060546875 +13880 -0.002349853515625 +13881 -0.009002685546875 +13882 -0.07061767578125 +13883 -0.10400390625 +13884 -0.16131591796875 +13885 -0.229400634765625 +13886 -0.252899169921875 +13887 -0.35552978515625 +13888 -0.31585693359375 +13889 -0.441925048828125 +13890 -0.3394775390625 +13891 -0.473846435546875 +13892 -0.33355712890625 +13893 -0.464813232421875 +13894 -0.3011474609375 +13895 -0.419097900390625 +13896 -0.240447998046875 +13897 -0.334320068359375 +13898 -0.16412353515625 +13899 -0.227935791015625 +13900 -0.089263916015625 +13901 -0.12347412109375 +13902 -0.020660400390625 +13903 -0.02764892578125 +13904 0.054931640625 +13905 0.077667236328125 +13906 0.152679443359375 +13907 0.2132568359375 +13908 0.279693603515625 +13909 0.38885498046875 +13910 0.420257568359375 +13911 0.582794189453125 +13912 0.52996826171875 +13913 0.734039306640625 +13914 0.57794189453125 +13915 0.800140380859375 +13916 0.5621337890625 +13917 0.7783203125 +13918 0.480072021484375 +13919 0.6651611328125 +13920 0.331024169921875 +13921 0.45965576171875 +13922 0.14215087890625 +13923 0.199188232421875 +13924 -0.038848876953125 +13925 -0.050689697265625 +13926 -0.170562744140625 +13927 -0.23297119140625 +13928 -0.24029541015625 +13929 -0.33013916015625 +13930 -0.26715087890625 +13931 -0.368408203125 +13932 -0.27386474609375 +13933 -0.378936767578125 +13934 -0.271636962890625 +13935 -0.376983642578125 +13936 -0.27301025390625 +13937 -0.37969970703125 +13938 -0.281219482421875 +13939 -0.391510009765625 +13940 -0.276580810546875 +13941 -0.385345458984375 +13942 -0.245025634765625 +13943 -0.3419189453125 +13944 -0.202301025390625 +13945 -0.28289794921875 +13946 -0.179962158203125 +13947 -0.251617431640625 +13948 -0.19110107421875 +13949 -0.266143798828125 +13950 -0.197052001953125 +13951 -0.273345947265625 +13952 -0.15667724609375 +13953 -0.216796875 +13954 -0.093017578125 +13955 -0.128265380859375 +13956 -0.050018310546875 +13957 -0.068145751953125 +13958 -0.032501220703125 +13959 -0.0430908203125 +13960 -0.019561767578125 +13961 -0.024444580078125 +13962 0.0128173828125 +13963 0.020721435546875 +13964 0.087982177734375 +13965 0.124481201171875 +13966 0.184844970703125 +13967 0.25787353515625 +13968 0.27301025390625 +13969 0.379119873046875 +13970 0.346466064453125 +13971 0.47991943359375 +13972 0.3818359375 +13973 0.5281982421875 +13974 0.369781494140625 +13975 0.511138916015625 +13976 0.330291748046875 +13977 0.456207275390625 +13978 0.29541015625 +13979 0.407470703125 +13980 0.27880859375 +13981 0.383758544921875 +13982 0.259918212890625 +13983 0.35687255859375 +13984 0.227752685546875 +13985 0.31182861328125 +13986 0.1839599609375 +13987 0.250885009765625 +13988 0.1221923828125 +13989 0.1654052734375 +13990 0.027801513671875 +13991 0.035247802734375 +13992 -0.101043701171875 +13993 -0.142059326171875 +13994 -0.241851806640625 +13995 -0.33563232421875 +13996 -0.38665771484375 +13997 -0.5345458984375 +13998 -0.52313232421875 +13999 -0.72186279296875 +14000 -0.606903076171875 +14001 -0.836669921875 +14002 -0.604278564453125 +14003 -0.8326416015625 +14004 -0.5296630859375 +14005 -0.7296142578125 +14006 -0.42303466796875 +14007 -0.582550048828125 +14008 -0.319793701171875 +14009 -0.440093994140625 +14010 -0.235992431640625 +14011 -0.324310302734375 +14012 -0.14703369140625 +14013 -0.20147705078125 +14014 -0.03326416015625 +14015 -0.044647216796875 +14016 0.0745849609375 +14017 0.103973388671875 +14018 0.145965576171875 +14019 0.202392578125 +14020 0.19097900390625 +14021 0.264495849609375 +14022 0.245025634765625 +14023 0.338897705078125 +14024 0.321380615234375 +14025 0.443817138671875 +14026 0.395172119140625 +14027 0.545074462890625 +14028 0.447906494140625 +14029 0.6173095703125 +14030 0.473724365234375 +14031 0.6524658203125 +14032 0.481964111328125 +14033 0.66339111328125 +14034 0.477020263671875 +14035 0.6561279296875 +14036 0.441436767578125 +14037 0.606781005859375 +14038 0.364898681640625 +14039 0.501190185546875 +14040 0.25714111328125 +14041 0.352783203125 +14042 0.12908935546875 +14043 0.176544189453125 +14044 -0.024566650390625 +14045 -0.034820556640625 +14046 -0.18701171875 +14047 -0.258209228515625 +14048 -0.321014404296875 +14049 -0.44244384765625 +14050 -0.417633056640625 +14051 -0.5753173828125 +14052 -0.473419189453125 +14053 -0.65203857421875 +14054 -0.4658203125 +14055 -0.641632080078125 +14056 -0.40802001953125 +14057 -0.562164306640625 +14058 -0.33233642578125 +14059 -0.458038330078125 +14060 -0.254241943359375 +14061 -0.350555419921875 +14062 -0.18890380859375 +14063 -0.260528564453125 +14064 -0.13934326171875 +14065 -0.192108154296875 +14066 -0.103118896484375 +14067 -0.141937255859375 +14068 -0.074493408203125 +14069 -0.1021728515625 +14070 -0.04620361328125 +14071 -0.062896728515625 +14072 -0.009368896484375 +14073 -0.011932373046875 +14074 0.044830322265625 +14075 0.062835693359375 +14076 0.107177734375 +14077 0.148712158203125 +14078 0.1748046875 +14079 0.241729736328125 +14080 0.253265380859375 +14081 0.34912109375 +14082 0.33343505859375 +14083 0.457305908203125 +14084 0.398895263671875 +14085 0.54388427734375 +14086 0.4219970703125 +14087 0.5728759765625 +14088 0.37371826171875 +14089 0.506591796875 +14090 0.258453369140625 +14091 0.351226806640625 +14092 0.106109619140625 +14093 0.146514892578125 +14094 -0.043853759765625 +14095 -0.05523681640625 +14096 -0.1629638671875 +14097 -0.21624755859375 +14098 -0.25018310546875 +14099 -0.334930419921875 +14100 -0.299407958984375 +14101 -0.402984619140625 +14102 -0.326568603515625 +14103 -0.4412841796875 +14104 -0.366668701171875 +14105 -0.49578857421875 +14106 -0.41497802734375 +14107 -0.5601806640625 +14108 -0.445831298828125 +14109 -0.600738525390625 +14110 -0.4339599609375 +14111 -0.584228515625 +14112 -0.355438232421875 +14113 -0.47930908203125 +14114 -0.20513916015625 +14115 -0.27935791015625 +14116 -0.001617431640625 +14117 -0.0089111328125 +14118 0.207183837890625 +14119 0.268798828125 +14120 0.36749267578125 +14121 0.482818603515625 +14122 0.457061767578125 +14123 0.60369873046875 +14124 0.490386962890625 +14125 0.650421142578125 +14126 0.498809814453125 +14127 0.66400146484375 +14128 0.48016357421875 +14129 0.6414794921875 +14130 0.42669677734375 +14131 0.572540283203125 +14132 0.36956787109375 +14133 0.498138427734375 +14134 0.32489013671875 +14135 0.439453125 +14136 0.2767333984375 +14137 0.375518798828125 +14138 0.200836181640625 +14139 0.274505615234375 +14140 0.076141357421875 +14141 0.1087646484375 +14142 -0.080474853515625 +14143 -0.099395751953125 +14144 -0.244964599609375 +14145 -0.3182373046875 +14146 -0.418365478515625 +14147 -0.5489501953125 +14148 -0.5872802734375 +14149 -0.7738037109375 +14150 -0.711578369140625 +14151 -0.86383056640625 +14152 -0.766082763671875 +14153 -0.870391845703125 +14154 -0.76434326171875 +14155 -0.86895751953125 +14156 -0.716400146484375 +14157 -0.861053466796875 +14158 -0.60919189453125 +14159 -0.765869140625 +14160 -0.434173583984375 +14161 -0.5301513671875 +14162 -0.19671630859375 +14163 -0.214691162109375 +14164 0.070465087890625 +14165 0.137359619140625 +14166 0.328399658203125 +14167 0.474822998046875 +14168 0.550140380859375 +14169 0.76239013671875 +14170 0.715240478515625 +14171 0.867462158203125 +14172 0.8240966796875 +14173 0.870361328125 +14174 0.85595703125 +14175 0.86480712890625 +14176 0.851287841796875 +14177 0.831817626953125 +14178 0.792327880859375 +14179 0.677581787109375 +14180 0.695709228515625 +14181 0.495880126953125 +14182 0.5755615234375 +14183 0.30767822265625 +14184 0.433624267578125 +14185 0.116180419921875 +14186 0.245849609375 +14187 -0.110748291015625 +14188 0.0069580078125 +14189 -0.381805419921875 +14190 -0.25048828125 +14191 -0.6572265625 +14192 -0.48101806640625 +14193 -0.857421875 +14194 -0.652008056640625 +14195 -0.870391845703125 +14196 -0.758056640625 +14197 -0.870391845703125 +14198 -0.8197021484375 +14199 -0.86444091796875 +14200 -0.855560302734375 +14201 -0.85723876953125 +14202 -0.85699462890625 +14203 -0.790008544921875 +14204 -0.818389892578125 +14205 -0.62847900390625 +14206 -0.684783935546875 +14207 -0.3956298828125 +14208 -0.5015869140625 +14209 -0.126708984375 +14210 -0.2896728515625 +14211 0.150115966796875 +14212 -0.0579833984375 +14213 0.424041748046875 +14214 0.1729736328125 +14215 0.670623779296875 +14216 0.373748779296875 +14217 0.854522705078125 +14218 0.530914306640625 +14219 0.866485595703125 +14220 0.63275146484375 +14221 0.86920166015625 +14222 0.693084716796875 +14223 0.8653564453125 +14224 0.722137451171875 +14225 0.857147216796875 +14226 0.71771240234375 +14227 0.766845703125 +14228 0.6837158203125 +14229 0.628509521484375 +14230 0.615081787109375 +14231 0.462127685546875 +14232 0.531494140625 +14233 0.297210693359375 +14234 0.442474365234375 +14235 0.14862060546875 +14236 0.3306884765625 +14237 -0.00537109375 +14238 0.201873779296875 +14239 -0.15753173828125 +14240 0.053314208984375 +14241 -0.31304931640625 +14242 -0.125579833984375 +14243 -0.48876953125 +14244 -0.299163818359375 +14245 -0.6416015625 +14246 -0.4486083984375 +14247 -0.751373291015625 +14248 -0.591461181640625 +14249 -0.84619140625 +14250 -0.716552734375 +14251 -0.861297607421875 +14252 -0.7987060546875 +14253 -0.863250732421875 +14254 -0.813934326171875 +14255 -0.856597900390625 +14256 -0.771514892578125 +14257 -0.7498779296875 +14258 -0.7154541015625 +14259 -0.624542236328125 +14260 -0.62908935546875 +14261 -0.47808837890625 +14262 -0.468017578125 +14263 -0.253387451171875 +14264 -0.26702880859375 +14265 0.003692626953125 +14266 -0.078125 +14267 0.2257080078125 +14268 0.108184814453125 +14269 0.427154541015625 +14270 0.316436767578125 +14271 0.643218994140625 +14272 0.539276123046875 +14273 0.855926513671875 +14274 0.73260498046875 +14275 0.870361328125 +14276 0.854949951171875 +14277 0.870361328125 +14278 0.8619384765625 +14279 0.862762451171875 +14280 0.861968994140625 +14281 0.79669189453125 +14282 0.852203369140625 +14283 0.595794677734375 +14284 0.732208251953125 +14285 0.362152099609375 +14286 0.5845947265625 +14287 0.1270751953125 +14288 0.425506591796875 +14289 -0.086944580078125 +14290 0.256561279296875 +14291 -0.2784423828125 +14292 0.051422119140625 +14293 -0.484832763671875 +14294 -0.204376220703125 +14295 -0.729583740234375 +14296 -0.472259521484375 +14297 -0.86688232421875 +14298 -0.704010009765625 +14299 -0.870391845703125 +14300 -0.8590087890625 +14301 -0.86859130859375 +14302 -0.870391845703125 +14303 -0.86279296875 +14304 -0.870391845703125 +14305 -0.817962646484375 +14306 -0.860076904296875 +14307 -0.6116943359375 +14308 -0.714996337890625 +14309 -0.3128662109375 +14310 -0.45672607421875 +14311 0.039398193359375 +14312 -0.14794921875 +14313 0.422821044921875 +14314 0.18505859375 +14315 0.805145263671875 +14316 0.490570068359375 +14317 0.870361328125 +14318 0.726226806640625 +14319 0.870361328125 +14320 0.857818603515625 +14321 0.860015869140625 +14322 0.866363525390625 +14323 0.727935791015625 +14324 0.8660888671875 +14325 0.48114013671875 +14326 0.85931396484375 +14327 0.2059326171875 +14328 0.79827880859375 +14329 -0.06103515625 +14330 0.67071533203125 +14331 -0.29913330078125 +14332 0.508636474609375 +14333 -0.516204833984375 +14334 0.303466796875 +14335 -0.7252197265625 +14336 0.076995849609375 +14337 -0.85980224609375 +14338 -0.14306640625 +14339 -0.870391845703125 +14340 -0.3330078125 +14341 -0.870391845703125 +14342 -0.453765869140625 +14343 -0.858062744140625 +14344 -0.502288818359375 +14345 -0.673004150390625 +14346 -0.52117919921875 +14347 -0.42694091796875 +14348 -0.547210693359375 +14349 -0.2100830078125 +14350 -0.58087158203125 +14351 -0.0362548828125 +14352 -0.60174560546875 +14353 0.10943603515625 +14354 -0.59686279296875 +14355 0.23516845703125 +14356 -0.53631591796875 +14357 0.373687744140625 +14358 -0.4244384765625 +14359 0.517791748046875 +14360 -0.313690185546875 +14361 0.602783203125 +14362 -0.202178955078125 +14363 0.635711669921875 +14364 -0.065216064453125 +14365 0.655181884765625 +14366 0.088134765625 +14367 0.65948486328125 +14368 0.2509765625 +14369 0.651275634765625 +14370 0.403900146484375 +14371 0.61846923828125 +14372 0.51824951171875 +14373 0.53753662109375 +14374 0.580902099609375 +14375 0.404144287109375 +14376 0.585784912109375 +14377 0.22186279296875 +14378 0.535858154296875 +14379 0.003997802734375 +14380 0.44769287109375 +14381 -0.22100830078125 +14382 0.339996337890625 +14383 -0.42449951171875 +14384 0.232025146484375 +14385 -0.579833984375 +14386 0.159820556640625 +14387 -0.641876220703125 +14388 0.12005615234375 +14389 -0.6177978515625 +14390 0.063140869140625 +14391 -0.575531005859375 +14392 -0.01397705078125 +14393 -0.526336669921875 +14394 -0.069610595703125 +14395 -0.42645263671875 +14396 -0.081817626953125 +14397 -0.2581787109375 +14398 -0.0797119140625 +14399 -0.068695068359375 +14400 -0.094573974609375 +14401 0.09222412109375 +14402 -0.112823486328125 +14403 0.232147216796875 +14404 -0.12786865234375 +14405 0.3509521484375 +14406 -0.164886474609375 +14407 0.410064697265625 +14408 -0.248992919921875 +14409 0.372955322265625 +14410 -0.365447998046875 +14411 0.2554931640625 +14412 -0.4747314453125 +14413 0.10711669921875 +14414 -0.562957763671875 +14415 -0.052886962890625 +14416 -0.602813720703125 +14417 -0.186279296875 +14418 -0.551025390625 +14419 -0.23291015625 +14420 -0.42626953125 +14421 -0.209442138671875 +14422 -0.281005859375 +14423 -0.174163818359375 +14424 -0.1217041015625 +14425 -0.126739501953125 +14426 0.059906005859375 +14427 -0.048126220703125 +14428 0.2423095703125 +14429 0.0426025390625 +14430 0.389678955078125 +14431 0.10748291015625 +14432 0.49285888671875 +14433 0.1409912109375 +14434 0.590911865234375 +14435 0.19708251953125 +14436 0.679962158203125 +14437 0.273651123046875 +14438 0.717193603515625 +14439 0.31768798828125 +14440 0.712646484375 +14441 0.341094970703125 +14442 0.687408447265625 +14443 0.368011474609375 +14444 0.6241455078125 +14445 0.37249755859375 +14446 0.484466552734375 +14447 0.30072021484375 +14448 0.2725830078125 +14449 0.1517333984375 +14450 0.041229248046875 +14451 -0.01470947265625 +14452 -0.195831298828125 +14453 -0.1883544921875 +14454 -0.43597412109375 +14455 -0.372711181640625 +14456 -0.631622314453125 +14457 -0.51397705078125 +14458 -0.746490478515625 +14459 -0.57177734375 +14460 -0.772003173828125 +14461 -0.53948974609375 +14462 -0.72015380859375 +14463 -0.43511962890625 +14464 -0.61962890625 +14465 -0.2962646484375 +14466 -0.500762939453125 +14467 -0.161102294921875 +14468 -0.3758544921875 +14469 -0.0435791015625 +14470 -0.24395751953125 +14471 0.060394287109375 +14472 -0.1195068359375 +14473 0.13665771484375 +14474 -0.018310546875 +14475 0.170135498046875 +14476 0.058929443359375 +14477 0.16552734375 +14478 0.1348876953125 +14479 0.15728759765625 +14480 0.209320068359375 +14481 0.150787353515625 +14482 0.2589111328125 +14483 0.12200927734375 +14484 0.28717041015625 +14485 0.080108642578125 +14486 0.311798095703125 +14487 0.05126953125 +14488 0.35235595703125 +14489 0.062896728515625 +14490 0.389923095703125 +14491 0.09271240234375 +14492 0.386444091796875 +14493 0.092987060546875 +14494 0.3543701171875 +14495 0.07855224609375 +14496 0.30706787109375 +14497 0.06427001953125 +14498 0.23480224609375 +14499 0.0347900390625 +14500 0.139129638671875 +14501 -0.01171875 +14502 0.038726806640625 +14503 -0.056060791015625 +14504 -0.028778076171875 +14505 -0.055511474609375 +14506 -0.05987548828125 +14507 -0.010467529296875 +14508 -0.09368896484375 +14509 0.02508544921875 +14510 -0.147186279296875 +14511 0.025665283203125 +14512 -0.197021484375 +14513 0.017333984375 +14514 -0.23974609375 +14515 0.00189208984375 +14516 -0.2828369140625 +14517 -0.03173828125 +14518 -0.3162841796875 +14519 -0.071502685546875 +14520 -0.35467529296875 +14521 -0.13543701171875 +14522 -0.396240234375 +14523 -0.219970703125 +14524 -0.423248291015625 +14525 -0.300506591796875 +14526 -0.437469482421875 +14527 -0.376312255859375 +14528 -0.4168701171875 +14529 -0.416107177734375 +14530 -0.325836181640625 +14531 -0.371124267578125 +14532 -0.168212890625 +14533 -0.242279052734375 +14534 0.021148681640625 +14535 -0.069732666015625 +14536 0.222869873046875 +14537 0.125640869140625 +14538 0.409912109375 +14539 0.31268310546875 +14540 0.55157470703125 +14541 0.45501708984375 +14542 0.648284912109375 +14543 0.554779052734375 +14544 0.698333740234375 +14545 0.61065673828125 +14546 0.692474365234375 +14547 0.610931396484375 +14548 0.612274169921875 +14549 0.531463623046875 +14550 0.471710205078125 +14551 0.3883056640625 +14552 0.314697265625 +14553 0.23468017578125 +14554 0.162933349609375 +14555 0.095245361328125 +14556 0.0394287109375 +14557 -0.00396728515625 +14558 -0.041839599609375 +14559 -0.04852294921875 +14560 -0.091522216796875 +14561 -0.055145263671875 +14562 -0.1484375 +14563 -0.0758056640625 +14564 -0.232818603515625 +14565 -0.138702392578125 +14566 -0.315521240234375 +14567 -0.209197998046875 +14568 -0.39666748046875 +14569 -0.289031982421875 +14570 -0.476043701171875 +14571 -0.37884521484375 +14572 -0.535797119140625 +14573 -0.456329345703125 +14574 -0.57232666015625 +14575 -0.51641845703125 +14576 -0.554962158203125 +14577 -0.519287109375 +14578 -0.479736328125 +14579 -0.458251953125 +14580 -0.389068603515625 +14581 -0.384796142578125 +14582 -0.30450439453125 +14583 -0.323699951171875 +14584 -0.2236328125 +14585 -0.269287109375 +14586 -0.127716064453125 +14587 -0.1951904296875 +14588 -0.01763916015625 +14589 -0.100006103515625 +14590 0.083526611328125 +14591 -0.01055908203125 +14592 0.1983642578125 +14593 0.1033935546875 +14594 0.331390380859375 +14595 0.24908447265625 +14596 0.439300537109375 +14597 0.373199462890625 +14598 0.507781982421875 +14599 0.45806884765625 +14600 0.543304443359375 +14601 0.511474609375 +14602 0.5721435546875 +14603 0.565399169921875 +14604 0.588531494140625 +14605 0.61138916015625 +14606 0.545989990234375 +14607 0.5897216796875 +14608 0.438201904296875 +14609 0.4906005859375 +14610 0.280792236328125 +14611 0.33148193359375 +14612 0.103759765625 +14613 0.147796630859375 +14614 -0.057861328125 +14615 -0.01873779296875 +14616 -0.180328369140625 +14617 -0.140289306640625 +14618 -0.242462158203125 +14619 -0.191986083984375 +14620 -0.251617431640625 +14621 -0.184295654296875 +14622 -0.24285888671875 +14623 -0.161834716796875 +14624 -0.249420166015625 +14625 -0.166595458984375 +14626 -0.267578125 +14627 -0.19390869140625 +14628 -0.282257080078125 +14629 -0.22442626953125 +14630 -0.311431884765625 +14631 -0.279754638671875 +14632 -0.33941650390625 +14633 -0.3389892578125 +14634 -0.32916259765625 +14635 -0.3543701171875 +14636 -0.2998046875 +14637 -0.348175048828125 +14638 -0.257171630859375 +14639 -0.32598876953125 +14640 -0.178955078125 +14641 -0.2581787109375 +14642 -0.062469482421875 +14643 -0.139801025390625 +14644 0.079559326171875 +14645 0.014617919921875 +14646 0.1976318359375 +14647 0.144378662109375 +14648 0.268341064453125 +14649 0.221038818359375 +14650 0.31219482421875 +14651 0.27069091796875 +14652 0.329681396484375 +14653 0.294036865234375 +14654 0.337554931640625 +14655 0.311767578125 +14656 0.348602294921875 +14657 0.339141845703125 +14658 0.351104736328125 +14659 0.360260009765625 +14660 0.334228515625 +14661 0.360504150390625 +14662 0.27288818359375 +14663 0.308380126953125 +14664 0.149749755859375 +14665 0.18170166015625 +14666 -0.014129638671875 +14667 0.0047607421875 +14668 -0.179290771484375 +14669 -0.17559814453125 +14670 -0.30780029296875 +14671 -0.3143310546875 +14672 -0.363067626953125 +14673 -0.36785888671875 +14674 -0.3662109375 +14675 -0.36248779296875 +14676 -0.354278564453125 +14677 -0.343536376953125 +14678 -0.3197021484375 +14679 -0.3018798828125 +14680 -0.257568359375 +14681 -0.231414794921875 +14682 -0.15625 +14683 -0.117645263671875 +14684 -0.04290771484375 +14685 0.007049560546875 +14686 0.036712646484375 +14687 0.087982177734375 +14688 0.093658447265625 +14689 0.13946533203125 +14690 0.137603759765625 +14691 0.17425537109375 +14692 0.16424560546875 +14693 0.188201904296875 +14694 0.164459228515625 +14695 0.171234130859375 +14696 0.13348388671875 +14697 0.118438720703125 +14698 0.0931396484375 +14699 0.05706787109375 +14700 0.044677734375 +14701 -0.010711669921875 +14702 -0.017578125 +14703 -0.0914306640625 +14704 -0.074981689453125 +14705 -0.162322998046875 +14706 -0.103759765625 +14707 -0.194549560546875 +14708 -0.071746826171875 +14709 -0.1492919921875 +14710 0.02545166015625 +14711 -0.02166748046875 +14712 0.13543701171875 +14713 0.124053955078125 +14714 0.19561767578125 +14715 0.211151123046875 +14716 0.20733642578125 +14717 0.240447998046875 +14718 0.196197509765625 +14719 0.242218017578125 +14720 0.170562744140625 +14721 0.2257080078125 +14722 0.1339111328125 +14723 0.194366455078125 +14724 0.059844970703125 +14725 0.115509033203125 +14726 -0.031646728515625 +14727 0.0128173828125 +14728 -0.090911865234375 +14729 -0.053802490234375 +14730 -0.139434814453125 +14731 -0.110626220703125 +14732 -0.211700439453125 +14733 -0.199493408203125 +14734 -0.286376953125 +14735 -0.29437255859375 +14736 -0.311767578125 +14737 -0.33221435546875 +14738 -0.26080322265625 +14739 -0.27972412109375 +14740 -0.17388916015625 +14741 -0.185333251953125 +14742 -0.11676025390625 +14743 -0.128204345703125 +14744 -0.096038818359375 +14745 -0.115692138671875 +14746 -0.086517333984375 +14747 -0.116455078125 +14748 -0.0684814453125 +14749 -0.105926513671875 +14750 -0.017578125 +14751 -0.053955078125 +14752 0.073455810546875 +14753 0.048797607421875 +14754 0.167236328125 +14755 0.157318115234375 +14756 0.214508056640625 +14757 0.212005615234375 +14758 0.219818115234375 +14759 0.218475341796875 +14760 0.23309326171875 +14761 0.23724365234375 +14762 0.2850341796875 +14763 0.30535888671875 +14764 0.341705322265625 +14765 0.38128662109375 +14766 0.35357666015625 +14767 0.404449462890625 +14768 0.337158203125 +14769 0.3944091796875 +14770 0.32373046875 +14771 0.3885498046875 +14772 0.29388427734375 +14773 0.362640380859375 +14774 0.2125244140625 +14775 0.27362060546875 +14776 0.076507568359375 +14777 0.11712646484375 +14778 -0.07098388671875 +14779 -0.054901123046875 +14780 -0.1871337890625 +14781 -0.19085693359375 +14782 -0.26763916015625 +14783 -0.28570556640625 +14784 -0.31231689453125 +14785 -0.339263916015625 +14786 -0.342620849609375 +14787 -0.3775634765625 +14788 -0.395843505859375 +14789 -0.445709228515625 +14790 -0.465057373046875 +14791 -0.535064697265625 +14792 -0.536895751953125 +14793 -0.629058837890625 +14794 -0.586944580078125 +14795 -0.697601318359375 +14796 -0.585235595703125 +14797 -0.70391845703125 +14798 -0.527587890625 +14799 -0.6424560546875 +14800 -0.39630126953125 +14801 -0.491241455078125 +14802 -0.20440673828125 +14803 -0.265716552734375 +14804 9.1552734375e-05 +14805 -0.023712158203125 +14806 0.189727783203125 +14807 0.201751708984375 +14808 0.33563232421875 +14809 0.375823974609375 +14810 0.4266357421875 +14811 0.485076904296875 +14812 0.495147705078125 +14813 0.56884765625 +14814 0.54754638671875 +14815 0.634765625 +14816 0.546722412109375 +14817 0.63763427734375 +14818 0.483428955078125 +14819 0.5660400390625 +14820 0.400848388671875 +14821 0.4720458984375 +14822 0.341552734375 +14823 0.40692138671875 +14824 0.311737060546875 +14825 0.3778076171875 +14826 0.30535888671875 +14827 0.376953125 +14828 0.2960205078125 +14829 0.371978759765625 +14830 0.243011474609375 +14831 0.313140869140625 +14832 0.13336181640625 +14833 0.184417724609375 +14834 -0.01177978515625 +14835 0.011199951171875 +14836 -0.16314697265625 +14837 -0.171051025390625 +14838 -0.3001708984375 +14839 -0.33740234375 +14840 -0.4097900390625 +14841 -0.47198486328125 +14842 -0.480255126953125 +14843 -0.560394287109375 +14844 -0.493560791015625 +14845 -0.58056640625 +14846 -0.462310791015625 +14847 -0.54754638671875 +14848 -0.42578125 +14849 -0.508575439453125 +14850 -0.380584716796875 +14851 -0.459503173828125 +14852 -0.32232666015625 +14853 -0.394378662109375 +14854 -0.284881591796875 +14855 -0.35260009765625 +14856 -0.24908447265625 +14857 -0.31170654296875 +14858 -0.151397705078125 +14859 -0.197418212890625 +14860 0.00970458984375 +14861 -0.007965087890625 +14862 0.19219970703125 +14863 0.207489013671875 +14864 0.3621826171875 +14865 0.409210205078125 +14866 0.498321533203125 +14867 0.57208251953125 +14868 0.574981689453125 +14869 0.66595458984375 +14870 0.56494140625 +14871 0.65875244140625 +14872 0.48291015625 +14873 0.56744384765625 +14874 0.362823486328125 +14875 0.431396484375 +14876 0.242401123046875 +14877 0.29443359375 +14878 0.14398193359375 +14879 0.182464599609375 +14880 0.04046630859375 +14881 0.06365966796875 +14882 -0.080047607421875 +14883 -0.075958251953125 +14884 -0.17730712890625 +14885 -0.189422607421875 +14886 -0.24725341796875 +14887 -0.271942138671875 +14888 -0.306182861328125 +14889 -0.342529296875 +14890 -0.322540283203125 +14891 -0.364166259765625 +14892 -0.288238525390625 +14893 -0.327239990234375 +14894 -0.242156982421875 +14895 -0.2769775390625 +14896 -0.218994140625 +14897 -0.253692626953125 +14898 -0.2071533203125 +14899 -0.24365234375 +14900 -0.165313720703125 +14901 -0.1983642578125 +14902 -0.09228515625 +14903 -0.116241455078125 +14904 -0.02203369140625 +14905 -0.036834716796875 +14906 0.041046142578125 +14907 0.034881591796875 +14908 0.090301513671875 +14909 0.09124755859375 +14910 0.105743408203125 +14911 0.10888671875 +14912 0.11962890625 +14913 0.125518798828125 +14914 0.146209716796875 +14915 0.15771484375 +14916 0.1622314453125 +14917 0.17828369140625 +14918 0.153961181640625 +14919 0.17108154296875 +14920 0.1163330078125 +14921 0.129974365234375 +14922 0.072967529296875 +14923 0.082427978515625 +14924 0.023406982421875 +14925 0.027679443359375 +14926 -0.059051513671875 +14927 -0.065643310546875 +14928 -0.141571044921875 +14929 -0.15936279296875 +14930 -0.189483642578125 +14931 -0.21307373046875 +14932 -0.209442138671875 +14933 -0.234649658203125 +14934 -0.180908203125 +14935 -0.2001953125 +14936 -0.111968994140625 +14937 -0.119171142578125 +14938 -0.031005859375 +14939 -0.024749755859375 +14940 0.06427001953125 +14941 0.085784912109375 +14942 0.14447021484375 +14943 0.178131103515625 +14944 0.1781005859375 +14945 0.215576171875 +14946 0.176422119140625 +14947 0.211456298828125 +14948 0.147430419921875 +14949 0.17523193359375 +14950 0.1097412109375 +14951 0.128753662109375 +14952 0.088836669921875 +14953 0.1019287109375 +14954 0.067169189453125 +14955 0.0743408203125 +14956 0.04229736328125 +14957 0.04327392578125 +14958 0.039337158203125 +14959 0.038177490234375 +14960 0.07293701171875 +14961 0.076263427734375 +14962 0.128936767578125 +14963 0.14105224609375 +14964 0.167877197265625 +14965 0.186431884765625 +14966 0.1695556640625 +14967 0.188812255859375 +14968 0.126129150390625 +14969 0.1390380859375 +14970 0.04168701171875 +14971 0.041778564453125 +14972 -0.06353759765625 +14973 -0.079437255859375 +14974 -0.18499755859375 +14975 -0.219390869140625 +14976 -0.31378173828125 +14977 -0.367828369140625 +14978 -0.42425537109375 +14979 -0.494873046875 +14980 -0.478424072265625 +14981 -0.556243896484375 +14982 -0.439178466796875 +14983 -0.508697509765625 +14984 -0.326446533203125 +14985 -0.3756103515625 +14986 -0.193206787109375 +14987 -0.218902587890625 +14988 -0.060943603515625 +14989 -0.063751220703125 +14990 0.07177734375 +14991 0.091552734375 +14992 0.195587158203125 +14993 0.23602294921875 +14994 0.287628173828125 +14995 0.342987060546875 +14996 0.3331298828125 +14997 0.39520263671875 +14998 0.329193115234375 +14999 0.389373779296875 +15000 0.27471923828125 +15001 0.324249267578125 +15002 0.19036865234375 +15003 0.224090576171875 +15004 0.106353759765625 +15005 0.124267578125 +15006 0.0330810546875 +15007 0.037078857421875 +15008 -0.00604248046875 +15009 -0.010101318359375 +15010 -0.012969970703125 +15011 -0.019439697265625 +15012 -0.014984130859375 +15013 -0.022796630859375 +15014 0.003753662109375 +15015 -0.001556396484375 +15016 0.053558349609375 +15017 0.056304931640625 +15018 0.096710205078125 +15019 0.106719970703125 +15020 0.087982177734375 +15021 0.096893310546875 +15022 0.041015625 +15023 0.042694091796875 +15024 -0.011749267578125 +15025 -0.018035888671875 +15026 -0.06219482421875 +15027 -0.07586669921875 +15028 -0.100555419921875 +15029 -0.11944580078125 +15030 -0.13616943359375 +15031 -0.15972900390625 +15032 -0.17401123046875 +15033 -0.202606201171875 +15034 -0.21441650390625 +15035 -0.24859619140625 +15036 -0.26373291015625 +15037 -0.30517578125 +15038 -0.31317138671875 +15039 -0.36212158203125 +15040 -0.338775634765625 +15041 -0.39141845703125 +15042 -0.308135986328125 +15043 -0.35528564453125 +15044 -0.218048095703125 +15045 -0.249969482421875 +15046 -0.083404541015625 +15047 -0.092864990234375 +15048 0.07269287109375 +15049 0.08905029296875 +15050 0.1983642578125 +15051 0.2352294921875 +15052 0.270599365234375 +15053 0.318817138671875 +15054 0.30548095703125 +15055 0.358642578125 +15056 0.2969970703125 +15057 0.347747802734375 +15058 0.24468994140625 +15059 0.28564453125 +15060 0.192047119140625 +15061 0.223175048828125 +15062 0.170166015625 +15063 0.196746826171875 +15064 0.156341552734375 +15065 0.179840087890625 +15066 0.136077880859375 +15067 0.155548095703125 +15068 0.13275146484375 +15069 0.151214599609375 +15070 0.13787841796875 +15071 0.156951904296875 +15072 0.116302490234375 +15073 0.13177490234375 +15074 0.089569091796875 +15075 0.100799560546875 +15076 0.07745361328125 +15077 0.087127685546875 +15078 0.049285888671875 +15079 0.05487060546875 +15080 -0.00604248046875 +15081 -0.009002685546875 +15082 -0.08807373046875 +15083 -0.10400390625 +15084 -0.196136474609375 +15085 -0.229400634765625 +15086 -0.3048095703125 +15087 -0.35552978515625 +15088 -0.37939453125 +15089 -0.441925048828125 +15090 -0.40728759765625 +15091 -0.473846435546875 +15092 -0.39996337890625 +15093 -0.464813232421875 +15094 -0.361114501953125 +15095 -0.419097900390625 +15096 -0.288665771484375 +15097 -0.334320068359375 +15098 -0.19757080078125 +15099 -0.227935791015625 +15100 -0.10797119140625 +15101 -0.12347412109375 +15102 -0.025634765625 +15103 -0.02764892578125 +15104 0.06488037109375 +15105 0.077667236328125 +15106 0.181610107421875 +15107 0.2132568359375 +15108 0.333648681640625 +15109 0.38885498046875 +15110 0.502349853515625 +15111 0.582794189453125 +15112 0.634002685546875 +15113 0.734039306640625 +15114 0.691253662109375 +15115 0.800140380859375 +15116 0.6717529296875 +15117 0.7783203125 +15118 0.572509765625 +15119 0.6651611328125 +15120 0.392486572265625 +15121 0.45965576171875 +15122 0.16473388671875 +15123 0.199188232421875 +15124 -0.05279541015625 +15125 -0.050689697265625 +15126 -0.20977783203125 +15127 -0.23297119140625 +15128 -0.291015625 +15129 -0.33013916015625 +15130 -0.320098876953125 +15131 -0.368408203125 +15132 -0.324951171875 +15133 -0.378936767578125 +15134 -0.319427490234375 +15135 -0.376983642578125 +15136 -0.319000244140625 +15137 -0.37969970703125 +15138 -0.32769775390625 +15139 -0.391510009765625 +15140 -0.32159423828125 +15141 -0.385345458984375 +15142 -0.283538818359375 +15143 -0.3419189453125 +15144 -0.23272705078125 +15145 -0.28289794921875 +15146 -0.207550048828125 +15147 -0.251617431640625 +15148 -0.223846435546875 +15149 -0.266143798828125 +15150 -0.2342529296875 +15151 -0.273345947265625 +15152 -0.18841552734375 +15153 -0.216796875 +15154 -0.1142578125 +15155 -0.128265380859375 +15156 -0.065185546875 +15157 -0.068145751953125 +15158 -0.046875 +15159 -0.0430908203125 +15160 -0.03369140625 +15161 -0.024444580078125 +15162 0.0037841796875 +15163 0.020721435546875 +15164 0.09417724609375 +15165 0.124481201171875 +15166 0.211822509765625 +15167 0.25787353515625 +15168 0.319610595703125 +15169 0.379119873046875 +15170 0.410186767578125 +15171 0.47991943359375 +15172 0.4549560546875 +15173 0.5281982421875 +15174 0.44244384765625 +15175 0.511138916015625 +15176 0.3968505859375 +15177 0.456207275390625 +15178 0.357147216796875 +15179 0.407470703125 +15180 0.339813232421875 +15181 0.383758544921875 +15182 0.319610595703125 +15183 0.35687255859375 +15184 0.283050537109375 +15185 0.31182861328125 +15186 0.231903076171875 +15187 0.250885009765625 +15188 0.158355712890625 +15189 0.1654052734375 +15190 0.04443359375 +15191 0.035247802734375 +15192 -0.112091064453125 +15193 -0.142059326171875 +15194 -0.283843994140625 +15195 -0.33563232421875 +15196 -0.461090087890625 +15197 -0.5345458984375 +15198 -0.628753662109375 +15199 -0.72186279296875 +15200 -0.732635498046875 +15201 -0.836669921875 +15202 -0.73150634765625 +15203 -0.8326416015625 +15204 -0.642852783203125 +15205 -0.7296142578125 +15206 -0.5152587890625 +15207 -0.582550048828125 +15208 -0.39178466796875 +15209 -0.440093994140625 +15210 -0.2918701171875 +15211 -0.324310302734375 +15212 -0.1854248046875 +15213 -0.20147705078125 +15214 -0.048309326171875 +15215 -0.044647216796875 +15216 0.08203125 +15217 0.103973388671875 +15218 0.168426513671875 +15219 0.202392578125 +15220 0.22320556640625 +15221 0.264495849609375 +15222 0.28955078125 +15223 0.338897705078125 +15224 0.38360595703125 +15225 0.443817138671875 +15226 0.4749755859375 +15227 0.545074462890625 +15228 0.541015625 +15229 0.6173095703125 +15230 0.574493408203125 +15231 0.6524658203125 +15232 0.586639404296875 +15233 0.66339111328125 +15234 0.58270263671875 +15235 0.6561279296875 +15236 0.54132080078125 +15237 0.606781005859375 +15238 0.449798583984375 +15239 0.501190185546875 +15240 0.31988525390625 +15241 0.352783203125 +15242 0.164825439453125 +15243 0.176544189453125 +15244 -0.021881103515625 +15245 -0.034820556640625 +15246 -0.219757080078125 +15247 -0.258209228515625 +15248 -0.3834228515625 +15249 -0.44244384765625 +15250 -0.501953125 +15251 -0.5753173828125 +15252 -0.571075439453125 +15253 -0.65203857421875 +15254 -0.563232421875 +15255 -0.641632080078125 +15256 -0.494384765625 +15257 -0.562164306640625 +15258 -0.40386962890625 +15259 -0.458038330078125 +15260 -0.3104248046875 +15261 -0.350555419921875 +15262 -0.23248291015625 +15263 -0.260528564453125 +15264 -0.173614501953125 +15265 -0.192108154296875 +15266 -0.1307373046875 +15267 -0.141937255859375 +15268 -0.0968017578125 +15269 -0.1021728515625 +15270 -0.06292724609375 +15271 -0.062896728515625 +15272 -0.01824951171875 +15273 -0.011932373046875 +15274 0.048004150390625 +15275 0.062835693359375 +15276 0.12457275390625 +15277 0.148712158203125 +15278 0.207855224609375 +15279 0.241729736328125 +15280 0.30426025390625 +15281 0.34912109375 +15282 0.401641845703125 +15283 0.457305908203125 +15284 0.480010986328125 +15285 0.54388427734375 +15286 0.50738525390625 +15287 0.5728759765625 +15288 0.4501953125 +15289 0.506591796875 +15290 0.3138427734375 +15291 0.351226806640625 +15292 0.133514404296875 +15293 0.146514892578125 +15294 -0.044403076171875 +15295 -0.05523681640625 +15296 -0.1864013671875 +15297 -0.21624755859375 +15298 -0.2911376953125 +15299 -0.334930419921875 +15300 -0.351287841796875 +15301 -0.402984619140625 +15302 -0.3853759765625 +15303 -0.4412841796875 +15304 -0.434173583984375 +15305 -0.49578857421875 +15306 -0.492034912109375 +15307 -0.5601806640625 +15308 -0.52899169921875 +15309 -0.600738525390625 +15310 -0.5155029296875 +15311 -0.584228515625 +15312 -0.42364501953125 +15313 -0.47930908203125 +15314 -0.24749755859375 +15315 -0.27935791015625 +15316 -0.008758544921875 +15317 -0.0089111328125 +15318 0.23651123046875 +15319 0.268798828125 +15320 0.425384521484375 +15321 0.482818603515625 +15322 0.53179931640625 +15323 0.60369873046875 +15324 0.5726318359375 +15325 0.650421142578125 +15326 0.584320068359375 +15327 0.66400146484375 +15328 0.564239501953125 +15329 0.6414794921875 +15330 0.50323486328125 +15331 0.572540283203125 +15332 0.437652587890625 +15333 0.498138427734375 +15334 0.386260986328125 +15335 0.439453125 +15336 0.33038330078125 +15337 0.375518798828125 +15338 0.241729736328125 +15339 0.274505615234375 +15340 0.095672607421875 +15341 0.1087646484375 +15342 -0.088043212890625 +15343 -0.099395751953125 +15344 -0.28125 +15345 -0.3182373046875 +15346 -0.485107421875 +15347 -0.5489501953125 +15348 -0.683929443359375 +15349 -0.7738037109375 +15350 -0.830718994140625 +15351 -0.86383056640625 +15352 -0.859039306640625 +15353 -0.870391845703125 +15354 -0.858978271484375 +15355 -0.86895751953125 +15356 -0.84075927734375 +15357 -0.861053466796875 +15358 -0.716583251953125 +15359 -0.765869140625 +15360 -0.512786865234375 +15361 -0.5301513671875 +15362 -0.23516845703125 +15363 -0.214691162109375 +15364 0.077911376953125 +15365 0.137359619140625 +15366 0.380279541015625 +15367 0.474822998046875 +15368 0.640106201171875 +15369 0.76239013671875 +15370 0.833221435546875 +15371 0.867462158203125 +15372 0.866058349609375 +15373 0.870361328125 +15374 0.870361328125 +15375 0.86480712890625 +15376 0.86700439453125 +15377 0.831817626953125 +15378 0.8585205078125 +15379 0.677581787109375 +15380 0.772491455078125 +15381 0.495880126953125 +15382 0.628936767578125 +15383 0.30767822265625 +15384 0.46282958984375 +15385 0.116180419921875 +15386 0.24456787109375 +15387 -0.110748291015625 +15388 -0.032806396484375 +15389 -0.381805419921875 +15390 -0.330718994140625 +15391 -0.6572265625 +15392 -0.59490966796875 +15393 -0.857421875 +15394 -0.786773681640625 +15395 -0.870391845703125 +15396 -0.859527587890625 +15397 -0.870391845703125 +15398 -0.866241455078125 +15399 -0.86444091796875 +15400 -0.870391845703125 +15401 -0.85723876953125 +15402 -0.870391845703125 +15403 -0.790008544921875 +15404 -0.86126708984375 +15405 -0.62847900390625 +15406 -0.746856689453125 +15407 -0.3956298828125 +15408 -0.522003173828125 +15409 -0.126708984375 +15410 -0.267120361328125 +15411 0.150115966796875 +15412 0.007171630859375 +15413 0.424041748046875 +15414 0.27655029296875 +15415 0.670623779296875 +15416 0.50604248046875 +15417 0.854522705078125 +15418 0.68017578125 +15419 0.866485595703125 +15420 0.785736083984375 +15421 0.86920166015625 +15422 0.840484619140625 +15423 0.8653564453125 +15424 0.854827880859375 +15425 0.857147216796875 +15426 0.835968017578125 +15427 0.766845703125 +15428 0.780670166015625 +15429 0.628509521484375 +15430 0.686431884765625 +15431 0.462127685546875 +15432 0.577606201171875 +15433 0.297210693359375 +15434 0.46600341796875 +15435 0.14862060546875 +15436 0.33074951171875 +15437 -0.00537109375 +15438 0.17864990234375 +15439 -0.15753173828125 +15440 0.006134033203125 +15441 -0.31304931640625 +15442 -0.20013427734375 +15443 -0.48876953125 +15444 -0.397674560546875 +15445 -0.6416015625 +15446 -0.564453125 +15447 -0.751373291015625 +15448 -0.722503662109375 +15449 -0.84619140625 +15450 -0.855010986328125 +15451 -0.861297607421875 +15452 -0.864349365234375 +15453 -0.863250732421875 +15454 -0.865020751953125 +15455 -0.856597900390625 +15456 -0.85833740234375 +15457 -0.7498779296875 +15458 -0.8143310546875 +15459 -0.624542236328125 +15460 -0.70550537109375 +15461 -0.47808837890625 +15462 -0.509429931640625 +15463 -0.253387451171875 +15464 -0.268157958984375 +15465 0.003692626953125 +15466 -0.04443359375 +15467 0.2257080078125 +15468 0.17352294921875 +15469 0.427154541015625 +15470 0.41595458984375 +15471 0.643218994140625 +15472 0.674530029296875 +15473 0.855926513671875 +15474 0.85906982421875 +15475 0.870361328125 +15476 0.870361328125 +15477 0.870361328125 +15478 0.870361328125 +15479 0.862762451171875 +15480 0.862823486328125 +15481 0.79669189453125 +15482 0.7880859375 +15483 0.595794677734375 +15484 0.6007080078125 +15485 0.362152099609375 +15486 0.396636962890625 +15487 0.1270751953125 +15488 0.196319580078125 +15489 -0.086944580078125 +15490 0.001708984375 +15491 -0.2784423828125 +15492 -0.220123291015625 +15493 -0.484832763671875 +15494 -0.4886474609375 +15495 -0.729583740234375 +15496 -0.7598876953125 +15497 -0.86688232421875 +15498 -0.8680419921875 +15499 -0.870391845703125 +15500 -0.870391845703125 +15501 -0.86859130859375 +15502 -0.868377685546875 +15503 -0.86279296875 +15504 -0.85955810546875 +15505 -0.817962646484375 +15506 -0.724853515625 +15507 -0.6116943359375 +15508 -0.45458984375 +15509 -0.3128662109375 +15510 -0.125885009765625 +15511 0.039398193359375 +15512 0.240203857421875 +15513 0.422821044921875 +15514 0.613006591796875 +15515 0.805145263671875 +15516 0.862945556640625 +15517 0.870361328125 +15518 0.870361328125 +15519 0.870361328125 +15520 0.8675537109375 +15521 0.860015869140625 +15522 0.85540771484375 +15523 0.727935791015625 +15524 0.6759033203125 +15525 0.48114013671875 +15526 0.44873046875 +15527 0.2059326171875 +15528 0.2142333984375 +15529 -0.06103515625 +15530 -0.008758544921875 +15531 -0.29913330078125 +15532 -0.226837158203125 +15533 -0.516204833984375 +15534 -0.45050048828125 +15535 -0.7252197265625 +15536 -0.656280517578125 +15537 -0.85980224609375 +15538 -0.815155029296875 +15539 -0.870391845703125 +15540 -0.86004638671875 +15541 -0.870391845703125 +15542 -0.858367919921875 +15543 -0.858062744140625 +15544 -0.77459716796875 +15545 -0.673004150390625 +15546 -0.619171142578125 +15547 -0.42694091796875 +15548 -0.47625732421875 +15549 -0.2100830078125 +15550 -0.355865478515625 +15551 -0.0362548828125 +15552 -0.242645263671875 +15553 0.10943603515625 +15554 -0.128448486328125 +15555 0.23516845703125 +15556 0.016326904296875 +15557 0.373687744140625 +15558 0.18359375 +15559 0.517791748046875 +15560 0.311431884765625 +15561 0.602783203125 +15562 0.403228759765625 +15563 0.635711669921875 +15564 0.490753173828125 +15565 0.655181884765625 +15566 0.56842041015625 +15567 0.65948486328125 +15568 0.634521484375 +15569 0.651275634765625 +15570 0.673919677734375 +15571 0.61846923828125 +15572 0.661346435546875 +15573 0.53753662109375 +15574 0.58966064453125 +15575 0.404144287109375 +15576 0.45965576171875 +15577 0.22186279296875 +15578 0.281890869140625 +15579 0.003997802734375 +15580 0.08172607421875 +15581 -0.22100830078125 +15582 -0.114410400390625 +15583 -0.42449951171875 +15584 -0.281005859375 +15585 -0.579833984375 +15586 -0.374847412109375 +15587 -0.641876220703125 +15588 -0.400177001953125 +15589 -0.6177978515625 +15590 -0.41656494140625 +15591 -0.575531005859375 +15592 -0.431121826171875 +15593 -0.526336669921875 +15594 -0.4002685546875 +15595 -0.42645263671875 +15596 -0.304290771484375 +15597 -0.2581787109375 +15598 -0.183441162109375 +15599 -0.068695068359375 +15600 -0.080718994140625 +15601 0.09222412109375 +15602 0.01300048828125 +15603 0.232147216796875 +15604 0.0992431640625 +15605 0.3509521484375 +15606 0.143402099609375 +15607 0.410064697265625 +15608 0.112091064453125 +15609 0.372955322265625 +15610 0.019378662109375 +15611 0.2554931640625 +15612 -0.0904541015625 +15613 0.10711669921875 +15614 -0.201446533203125 +15615 -0.052886962890625 +15616 -0.28021240234375 +15617 -0.186279296875 +15618 -0.273590087890625 +15619 -0.23291015625 +15620 -0.20050048828125 +15621 -0.209442138671875 +15622 -0.11865234375 +15623 -0.174163818359375 +15624 -0.0299072265625 +15625 -0.126739501953125 +15626 0.081817626953125 +15627 -0.048126220703125 +15628 0.19683837890625 +15629 0.0426025390625 +15630 0.2779541015625 +15631 0.10748291015625 +15632 0.319183349609375 +15633 0.1409912109375 +15634 0.37164306640625 +15635 0.19708251953125 +15636 0.4337158203125 +15637 0.273651123046875 +15638 0.45587158203125 +15639 0.31768798828125 +15640 0.45074462890625 +15641 0.341094970703125 +15642 0.4429931640625 +15643 0.368011474609375 +15644 0.409912109375 +15645 0.37249755859375 +15646 0.302490234375 +15647 0.30072021484375 +15648 0.121978759765625 +15649 0.1517333984375 +15650 -0.07275390625 +15651 -0.01470947265625 +15652 -0.27001953125 +15653 -0.1883544921875 +15654 -0.471588134765625 +15655 -0.372711181640625 +15656 -0.625091552734375 +15657 -0.51397705078125 +15658 -0.691253662109375 +15659 -0.57177734375 +15660 -0.663421630859375 +15661 -0.53948974609375 +15662 -0.558807373046875 +15663 -0.43511962890625 +15664 -0.413665771484375 +15665 -0.2962646484375 +15666 -0.265228271484375 +15667 -0.161102294921875 +15668 -0.12799072265625 +15669 -0.0435791015625 +15670 0.000335693359375 +15671 0.060394287109375 +15672 0.104583740234375 +15673 0.13665771484375 +15674 0.16864013671875 +15675 0.170135498046875 +15676 0.195220947265625 +15677 0.16552734375 +15678 0.21539306640625 +15679 0.15728759765625 +15680 0.232818603515625 +15681 0.150787353515625 +15682 0.2235107421875 +15683 0.12200927734375 +15684 0.195343017578125 +15685 0.080108642578125 +15686 0.172760009765625 +15687 0.05126953125 +15688 0.181732177734375 +15689 0.062896728515625 +15690 0.201385498046875 +15691 0.09271240234375 +15692 0.18707275390625 +15693 0.092987060546875 +15694 0.15380859375 +15695 0.07855224609375 +15696 0.116943359375 +15697 0.06427001953125 +15698 0.063262939453125 +15699 0.0347900390625 +15700 -0.007537841796875 +15701 -0.01171875 +15702 -0.07568359375 +15703 -0.056060791015625 +15704 -0.099212646484375 +15705 -0.055511474609375 +15706 -0.077239990234375 +15707 -0.010467529296875 +15708 -0.059967041015625 +15709 0.02508544921875 +15710 -0.070831298828125 +15711 0.025665283203125 +15712 -0.0845947265625 +15713 0.017333984375 +15714 -0.099395751953125 +15715 0.00189208984375 +15716 -0.125946044921875 +15717 -0.03173828125 +15718 -0.15325927734375 +15719 -0.071502685546875 +15720 -0.199188232421875 +15721 -0.13543701171875 +15722 -0.261260986328125 +15723 -0.219970703125 +15724 -0.317230224609375 +15725 -0.300506591796875 +15726 -0.3675537109375 +15727 -0.376312255859375 +15728 -0.38372802734375 +15729 -0.416107177734375 +15730 -0.320587158203125 +15731 -0.371124267578125 +15732 -0.180084228515625 +15733 -0.242279052734375 +15734 -0.001312255859375 +15735 -0.069732666015625 +15736 0.195159912109375 +15737 0.125640869140625 +15738 0.3792724609375 +15739 0.31268310546875 +15740 0.516265869140625 +15741 0.45501708984375 +15742 0.608184814453125 +15743 0.554779052734375 +15744 0.654083251953125 +15745 0.61065673828125 +15746 0.643341064453125 +15747 0.610931396484375 +15748 0.553741455078125 +15749 0.531463623046875 +15750 0.401397705078125 +15751 0.3883056640625 +15752 0.23779296875 +15753 0.23468017578125 +15754 0.087371826171875 +15755 0.095245361328125 +15756 -0.024139404296875 +15757 -0.00396728515625 +15758 -0.082122802734375 +15759 -0.04852294921875 +15760 -0.10162353515625 +15761 -0.055145263671875 +15762 -0.13140869140625 +15763 -0.0758056640625 +15764 -0.197784423828125 +15765 -0.138702392578125 +15766 -0.267578125 +15767 -0.209197998046875 +15768 -0.3424072265625 +15769 -0.289031982421875 +15770 -0.423065185546875 +15771 -0.37884521484375 +15772 -0.488677978515625 +15773 -0.456329345703125 +15774 -0.535003662109375 +15775 -0.51641845703125 +15776 -0.52484130859375 +15777 -0.519287109375 +15778 -0.452606201171875 +15779 -0.458251953125 +15780 -0.3680419921875 +15781 -0.384796142578125 +15782 -0.29547119140625 +15783 -0.323699951171875 +15784 -0.23028564453125 +15785 -0.269287109375 +15786 -0.148193359375 +15787 -0.1951904296875 +15788 -0.048431396484375 +15789 -0.100006103515625 +15790 0.04302978515625 +15791 -0.01055908203125 +15792 0.1546630859375 +15793 0.1033935546875 +15794 0.293243408203125 +15795 0.24908447265625 +15796 0.408233642578125 +15797 0.373199462890625 +15798 0.48309326171875 +15799 0.45806884765625 +15800 0.525604248046875 +15801 0.511474609375 +15802 0.56671142578125 +15803 0.565399169921875 +15804 0.598968505859375 +15805 0.61138916015625 +15806 0.5662841796875 +15807 0.5897216796875 +15808 0.46002197265625 +15809 0.4906005859375 +15810 0.297454833984375 +15811 0.33148193359375 +15812 0.112823486328125 +15813 0.147796630859375 +15814 -0.053741455078125 +15815 -0.01873779296875 +15816 -0.17535400390625 +15817 -0.140289306640625 +15818 -0.2281494140625 +15819 -0.191986083984375 +15820 -0.221923828125 +15821 -0.184295654296875 +15822 -0.1990966796875 +15823 -0.161834716796875 +15824 -0.199676513671875 +15825 -0.166595458984375 +15826 -0.219512939453125 +15827 -0.19390869140625 +15828 -0.240631103515625 +15829 -0.22442626953125 +15830 -0.284027099609375 +15831 -0.279754638671875 +15832 -0.330413818359375 +15833 -0.3389892578125 +15834 -0.3349609375 +15835 -0.3543701171875 +15836 -0.31939697265625 +15837 -0.348175048828125 +15838 -0.28955078125 +15839 -0.32598876953125 +15840 -0.21771240234375 +15841 -0.2581787109375 +15842 -0.09954833984375 +15843 -0.139801025390625 +15844 0.0509033203125 +15845 0.014617919921875 +15846 0.17578125 +15847 0.144378662109375 +15848 0.248077392578125 +15849 0.221038818359375 +15850 0.292633056640625 +15851 0.27069091796875 +15852 0.31036376953125 +15853 0.294036865234375 +15854 0.321197509765625 +15855 0.311767578125 +15856 0.34002685546875 +15857 0.339141845703125 +15858 0.3521728515625 +15859 0.360260009765625 +15860 0.34423828125 +15861 0.360504150390625 +15862 0.28662109375 +15863 0.308380126953125 +15864 0.15863037109375 +15865 0.18170166015625 +15866 -0.016143798828125 +15867 0.0047607421875 +15868 -0.192840576171875 +15869 -0.17559814453125 +15870 -0.328369140625 +15871 -0.3143310546875 +15872 -0.3807373046875 +15873 -0.36785888671875 +15874 -0.37530517578125 +15875 -0.36248779296875 +15876 -0.35589599609375 +15877 -0.343536376953125 +15878 -0.31341552734375 +15879 -0.3018798828125 +15880 -0.241790771484375 +15881 -0.231414794921875 +15882 -0.126800537109375 +15883 -0.117645263671875 +15884 -0.000396728515625 +15885 0.007049560546875 +15886 0.0833740234375 +15887 0.087982177734375 +15888 0.138397216796875 +15889 0.13946533203125 +15890 0.176971435546875 +15891 0.17425537109375 +15892 0.1947021484375 +15893 0.188201904296875 +15894 0.18145751953125 +15895 0.171234130859375 +15896 0.132232666015625 +15897 0.118438720703125 +15898 0.073699951171875 +15899 0.05706787109375 +15900 0.007843017578125 +15901 -0.010711669921875 +15902 -0.071746826171875 +15903 -0.0914306640625 +15904 -0.142608642578125 +15905 -0.162322998046875 +15906 -0.17633056640625 +15907 -0.194549560546875 +15908 -0.13458251953125 +15909 -0.1492919921875 +15910 -0.01239013671875 +15911 -0.02166748046875 +15912 0.127227783203125 +15913 0.124053955078125 +15914 0.208984375 +15915 0.211151123046875 +15916 0.233917236328125 +15917 0.240447998046875 +15918 0.23199462890625 +15919 0.242218017578125 +15920 0.212554931640625 +15921 0.2257080078125 +15922 0.179107666015625 +15923 0.194366455078125 +15924 0.099639892578125 +15925 0.115509033203125 +15926 -0.002471923828125 +15927 0.0128173828125 +15928 -0.0682373046875 +15929 -0.053802490234375 +15930 -0.123504638671875 +15931 -0.110626220703125 +15932 -0.20953369140625 +15933 -0.199493408203125 +15934 -0.300811767578125 +15935 -0.29437255859375 +15936 -0.335418701171875 +15937 -0.33221435546875 +15938 -0.28076171875 +15939 -0.27972412109375 +15940 -0.184661865234375 +15941 -0.185333251953125 +15942 -0.12518310546875 +15943 -0.128204345703125 +15944 -0.109710693359375 +15945 -0.115692138671875 +15946 -0.10760498046875 +15947 -0.116455078125 +15948 -0.0948486328125 +15949 -0.105926513671875 +15950 -0.04193115234375 +15951 -0.053955078125 +15952 0.060272216796875 +15953 0.048797607421875 +15954 0.16748046875 +15955 0.157318115234375 +15956 0.22100830078125 +15957 0.212005615234375 +15958 0.2264404296875 +15959 0.218475341796875 +15960 0.243377685546875 +15961 0.23724365234375 +15962 0.308380126953125 +15963 0.30535888671875 +15964 0.380706787109375 +15965 0.38128662109375 +15966 0.40087890625 +15967 0.404449462890625 +15968 0.388275146484375 +15969 0.3944091796875 +15970 0.379852294921875 +15971 0.3885498046875 +15972 0.3519287109375 +15973 0.362640380859375 +15974 0.26220703125 +15975 0.27362060546875 +15976 0.106536865234375 +15977 0.11712646484375 +15978 -0.063873291015625 +15979 -0.054901123046875 +15980 -0.198211669921875 +15981 -0.19085693359375 +15982 -0.291534423828125 +15983 -0.28570556640625 +15984 -0.343658447265625 +15985 -0.339263916015625 +15986 -0.3802490234375 +15987 -0.3775634765625 +15988 -0.445770263671875 +15989 -0.445709228515625 +15990 -0.531829833984375 +15991 -0.535064697265625 +15992 -0.6221923828125 +15993 -0.629058837890625 +15994 -0.687408447265625 +15995 -0.697601318359375 +15996 -0.69140625 +15997 -0.70391845703125 +15998 -0.628814697265625 +15999 -0.6424560546875 +16000 -0.4781494140625 +16001 -0.491241455078125 +16002 -0.25469970703125 +16003 -0.265716552734375 +16004 -0.015411376953125 +16005 -0.023712158203125 +16006 0.207122802734375 +16007 0.201751708984375 +16008 0.37860107421875 +16009 0.375823974609375 +16010 0.485809326171875 +16011 0.485076904296875 +16012 0.5675048828125 +16013 0.56884765625 +16014 0.6312255859375 +16015 0.634765625 +16016 0.632568359375 +16017 0.63763427734375 +16018 0.560394287109375 +16019 0.5660400390625 +16020 0.466033935546875 +16021 0.4720458984375 +16022 0.400054931640625 +16023 0.40692138671875 +16024 0.369598388671875 +16025 0.3778076171875 +16026 0.367095947265625 +16027 0.376953125 +16028 0.360809326171875 +16029 0.371978759765625 +16030 0.3018798828125 +16031 0.313140869140625 +16032 0.174530029296875 +16033 0.184417724609375 +16034 0.003814697265625 +16035 0.011199951171875 +16036 -0.1754150390625 +16037 -0.171051025390625 +16038 -0.338623046875 +16039 -0.33740234375 +16040 -0.470184326171875 +16041 -0.47198486328125 +16042 -0.5560302734375 +16043 -0.560394287109375 +16044 -0.574554443359375 +16045 -0.58056640625 +16046 -0.540618896484375 +16047 -0.54754638671875 +16048 -0.500762939453125 +16049 -0.508575439453125 +16050 -0.45098876953125 +16051 -0.459503173828125 +16052 -0.385528564453125 +16053 -0.394378662109375 +16054 -0.343231201171875 +16055 -0.35260009765625 +16056 -0.302032470703125 +16057 -0.31170654296875 +16058 -0.188873291015625 +16059 -0.197418212890625 +16060 -0.002044677734375 +16061 -0.007965087890625 +16062 0.21002197265625 +16063 0.207489013671875 +16064 0.40826416015625 +16065 0.409210205078125 +16066 0.567962646484375 +16067 0.57208251953125 +16068 0.659515380859375 +16069 0.66595458984375 +16070 0.6513671875 +16071 0.65875244140625 +16072 0.560302734375 +16073 0.56744384765625 +16074 0.425140380859375 +16075 0.431396484375 +16076 0.2890625 +16077 0.29443359375 +16078 0.177642822265625 +16079 0.182464599609375 +16080 0.059661865234375 +16081 0.06365966796875 +16082 -0.078582763671875 +16083 -0.075958251953125 +16084 -0.19085693359375 +16085 -0.189422607421875 +16086 -0.27239990234375 +16087 -0.271942138671875 +16088 -0.3419189453125 +16089 -0.342529296875 +16090 -0.363037109375 +16091 -0.364166259765625 +16092 -0.3262939453125 +16093 -0.327239990234375 +16094 -0.276214599609375 +16095 -0.2769775390625 +16096 -0.25250244140625 +16097 -0.253692626953125 +16098 -0.24169921875 +16099 -0.24365234375 +16100 -0.196136474609375 +16101 -0.1983642578125 +16102 -0.11431884765625 +16103 -0.116241455078125 +16104 -0.035186767578125 +16105 -0.036834716796875 +16106 0.036285400390625 +16107 0.034881591796875 +16108 0.092498779296875 +16109 0.09124755859375 +16110 0.110443115234375 +16111 0.10888671875 +16112 0.127197265625 +16113 0.125518798828125 +16114 0.159088134765625 +16115 0.15771484375 +16116 0.1793212890625 +16117 0.17828369140625 +16118 0.1719970703125 +16119 0.17108154296875 +16120 0.131134033203125 +16121 0.129974365234375 +16122 0.083770751953125 +16123 0.082427978515625 +16124 0.02923583984375 +16125 0.027679443359375 +16126 -0.0633544921875 +16127 -0.065643310546875 +16128 -0.15618896484375 +16129 -0.159515380859375 +16130 -0.209686279296875 +16131 -0.21337890625 +16132 -0.23187255859375 +16133 -0.2347412109375 +16134 -0.1986083984375 +16135 -0.200286865234375 +16136 -0.119110107421875 +16137 -0.11956787109375 +16138 -0.0263671875 +16139 -0.025421142578125 +16140 0.082550048828125 +16141 0.084686279296875 +16142 0.173492431640625 +16143 0.1768798828125 +16144 0.20989990234375 +16145 0.21490478515625 +16146 0.205108642578125 +16147 0.211761474609375 +16148 0.16864013671875 +16149 0.176727294921875 +16150 0.12237548828125 +16151 0.13128662109375 +16152 0.096160888671875 +16153 0.1048583984375 +16154 0.069580078125 +16155 0.077423095703125 +16156 0.039794921875 +16157 0.046295166015625 +16158 0.036163330078125 +16159 0.040496826171875 +16160 0.0758056640625 +16161 0.0770263671875 +16162 0.14215087890625 +16163 0.13970947265625 +16164 0.18902587890625 +16165 0.18328857421875 +16166 0.192718505859375 +16167 0.184600830078125 +16168 0.144012451171875 +16169 0.134674072265625 +16170 0.047515869140625 +16171 0.038177490234375 +16172 -0.073272705078125 +16173 -0.08172607421875 +16174 -0.213165283203125 +16175 -0.219879150390625 +16176 -0.361846923828125 +16177 -0.366119384765625 +16178 -0.489471435546875 +16179 -0.4910888671875 +16180 -0.551727294921875 +16181 -0.551239013671875 +16182 -0.505279541015625 +16183 -0.5040283203125 +16184 -0.373443603515625 +16185 -0.3724365234375 +16186 -0.218109130859375 +16187 -0.21746826171875 +16188 -0.0643310546875 +16189 -0.063934326171875 +16190 0.08966064453125 +16191 0.08978271484375 +16192 0.232940673828125 +16193 0.232818603515625 +16194 0.338897705078125 +16195 0.3388671875 +16196 0.390380859375 +16197 0.390960693359375 +16198 0.38409423828125 +16199 0.38580322265625 +16200 0.318817138671875 +16201 0.3221435546875 +16202 0.21881103515625 +16203 0.22381591796875 +16204 0.119415283203125 +16205 0.125640869140625 +16206 0.032867431640625 +16207 0.0396728515625 +16208 -0.013427734375 +16209 -0.007080078125 +16210 -0.021728515625 +16211 -0.016754150390625 +16212 -0.023956298828125 +16213 -0.0206298828125 +16214 -0.001556396484375 +16215 -0.0003662109375 +16216 0.05743408203125 +16217 0.055877685546875 +16218 0.108856201171875 +16219 0.104766845703125 +16220 0.099884033203125 +16221 0.09442138671875 +16222 0.046356201171875 +16223 0.040496826171875 +16224 -0.013916015625 +16225 -0.019744873046875 +16226 -0.071533203125 +16227 -0.076995849609375 +16228 -0.115142822265625 +16229 -0.12005615234375 +16230 -0.15570068359375 +16231 -0.159759521484375 +16232 -0.199066162109375 +16233 -0.201904296875 +16234 -0.2457275390625 +16235 -0.2469482421875 +16236 -0.3031005859375 +16237 -0.302276611328125 +16238 -0.360931396484375 +16239 -0.357879638671875 +16240 -0.39117431640625 +16241 -0.38623046875 +16242 -0.35595703125 +16243 -0.350128173828125 +16244 -0.251495361328125 +16245 -0.245941162109375 +16246 -0.09515380859375 +16247 -0.090850830078125 +16248 0.086151123046875 +16249 0.088623046875 +16250 0.231903076171875 +16251 0.232879638671875 +16252 0.315277099609375 +16253 0.31549072265625 +16254 0.355072021484375 +16255 0.35491943359375 +16256 0.3443603515625 +16257 0.344329833984375 +16258 0.282623291015625 +16259 0.283233642578125 +16260 0.220672607421875 +16261 0.221649169921875 +16262 0.19488525390625 +16263 0.195404052734375 +16264 0.1787109375 +16265 0.178436279296875 +16266 0.15521240234375 +16267 0.154144287109375 +16268 0.15167236328125 +16269 0.149444580078125 +16270 0.158172607421875 +16271 0.154632568359375 +16272 0.1336669921875 +16273 0.12939453125 +16274 0.103240966796875 +16275 0.098480224609375 +16276 0.0899658203125 +16277 0.084625244140625 +16278 0.05792236328125 +16279 0.05255126953125 +16280 -0.005889892578125 +16281 -0.01055908203125 +16282 -0.10101318359375 +16283 -0.104156494140625 +16284 -0.2266845703125 +16285 -0.227569580078125 +16286 -0.353240966796875 +16287 -0.351593017578125 +16288 -0.440155029296875 +16289 -0.4364013671875 +16290 -0.472686767578125 +16291 -0.467559814453125 +16292 -0.46429443359375 +16293 -0.45831298828125 +16294 -0.419219970703125 +16295 -0.41290283203125 +16296 -0.335052490234375 +16297 -0.32904052734375 +16298 -0.229217529296875 +16299 -0.223907470703125 +16300 -0.125213623046875 +16301 -0.120697021484375 +16302 -0.02972412109375 +16303 -0.026031494140625 +16304 0.07537841796875 +16305 0.07794189453125 +16306 0.21087646484375 +16307 0.21160888671875 +16308 0.38653564453125 +16309 0.384521484375 +16310 0.580657958984375 +16311 0.575347900390625 +16312 0.732177734375 +16313 0.72406005859375 +16314 0.79864501953125 +16315 0.788909912109375 +16316 0.777252197265625 +16317 0.76715087890625 +16318 0.664581298828125 +16319 0.65545654296875 +16320 0.459564208984375 +16321 0.452850341796875 +16322 0.1995849609375 +16323 0.196136474609375 +16324 -0.04986572265625 +16325 -0.050140380859375 +16326 -0.231781005859375 +16327 -0.229888916015625 +16328 -0.32867431640625 +16329 -0.325836181640625 +16330 -0.36676025390625 +16331 -0.36376953125 +16332 -0.377197265625 +16333 -0.37432861328125 +16334 -0.375244140625 +16335 -0.372528076171875 +16336 -0.3780517578125 +16337 -0.375244140625 +16338 -0.390045166015625 +16339 -0.386810302734375 +16340 -0.3841552734375 +16341 -0.380615234375 +16342 -0.341064453125 +16343 -0.337677001953125 +16344 -0.28240966796875 +16345 -0.27935791015625 +16346 -0.25152587890625 +16347 -0.248291015625 +16348 -0.266448974609375 +16349 -0.26226806640625 +16350 -0.274017333984375 +16351 -0.26904296875 +16352 -0.2177734375 +16353 -0.21307373046875 +16354 -0.129486083984375 +16355 -0.1256103515625 +16356 -0.069549560546875 +16357 -0.066162109375 +16358 -0.044586181640625 +16359 -0.041259765625 +16360 -0.02593994140625 +16361 -0.022735595703125 +16362 0.019317626953125 +16363 0.021820068359375 +16364 0.12322998046875 +16365 0.12396240234375 +16366 0.2568359375 +16367 0.255157470703125 +16368 0.378326416015625 +16369 0.37432861328125 +16370 0.47943115234375 +16371 0.473358154296875 +16372 0.528045654296875 +16373 0.5206298828125 +16374 0.511322021484375 +16375 0.503570556640625 +16376 0.45672607421875 +16377 0.449249267578125 +16378 0.408294677734375 +16379 0.401031494140625 +16380 0.38482666015625 +16381 0.37744140625 +16382 0.358123779296875 +16383 0.350738525390625 +16384 0.313201904296875 +16385 0.305694580078125 +16386 0.252288818359375 +16387 0.24420166015625 +16388 0.166748046875 +16389 0.158447265625 +16390 0.036468505859375 +16391 0.029754638671875 +16392 -0.141021728515625 +16393 -0.143768310546875 +16394 -0.3348388671875 +16395 -0.33233642578125 +16396 -0.534027099609375 +16397 -0.52520751953125 +16398 -0.721649169921875 +16399 -0.706024169921875 +16400 -0.836761474609375 +16401 -0.816650390625 +16402 -0.833038330078125 +16403 -0.81292724609375 +16404 -0.73028564453125 +16405 -0.713775634765625 +16406 -0.58343505859375 +16407 -0.57159423828125 +16408 -0.441131591796875 +16409 -0.432830810546875 +16410 -0.325439453125 +16411 -0.3187255859375 +16412 -0.20263671875 +16413 -0.19744873046875 +16414 -0.0457763671875 +16415 -0.043548583984375 +16416 0.102935791015625 +16417 0.102508544921875 +16418 0.201507568359375 +16419 0.200469970703125 +16420 0.263824462890625 +16421 0.263336181640625 +16422 0.338470458984375 +16423 0.337188720703125 +16424 0.443634033203125 +16425 0.439178466796875 +16426 0.545135498046875 +16427 0.536712646484375 +16428 0.61761474609375 +16429 0.605621337890625 +16430 0.652984619140625 +16431 0.63824462890625 +16432 0.664093017578125 +16433 0.646881103515625 +16434 0.656951904296875 +16435 0.637420654296875 +16436 0.607696533203125 +16437 0.587249755859375 +16438 0.50213623046875 +16439 0.48309326171875 +16440 0.35369873046875 +16441 0.33795166015625 +16442 0.1773681640625 +16443 0.16632080078125 +16444 -0.034149169921875 +16445 -0.038543701171875 +16446 -0.257720947265625 +16447 -0.25445556640625 +16448 -0.442169189453125 +16449 -0.432525634765625 +16450 -0.57525634765625 +16451 -0.56097412109375 +16452 -0.652191162109375 +16453 -0.63519287109375 +16454 -0.6419677734375 +16455 -0.625640869140625 +16456 -0.562652587890625 +16457 -0.54949951171875 +16458 -0.458648681640625 +16459 -0.449127197265625 +16460 -0.351226806640625 +16461 -0.344879150390625 +16462 -0.26123046875 +16463 -0.256683349609375 +16464 -0.19281005859375 +16465 -0.18865966796875 +16466 -0.142608642578125 +16467 -0.137786865234375 +16468 -0.102783203125 +16469 -0.096771240234375 +16470 -0.06341552734375 +16471 -0.056365966796875 +16472 -0.0123291015625 +16473 -0.005096435546875 +16474 0.062591552734375 +16475 0.06842041015625 +16476 0.148651123046875 +16477 0.1519775390625 +16478 0.241851806640625 +16479 0.24169921875 +16480 0.34942626953125 +16481 0.344451904296875 +16482 0.457794189453125 +16483 0.447296142578125 +16484 0.544525146484375 +16485 0.5289306640625 +16486 0.5736083984375 +16487 0.55517578125 +16488 0.507354736328125 +16489 0.490234375 +16490 0.35198974609375 +16491 0.340118408203125 +16492 0.147247314453125 +16493 0.14276123046875 +16494 -0.0545654296875 +16495 -0.0518798828125 +16496 -0.215667724609375 +16497 -0.20770263671875 +16498 -0.33447265625 +16499 -0.32305908203125 +16500 -0.402679443359375 +16501 -0.389923095703125 +16502 -0.441131591796875 +16503 -0.42803955078125 +16504 -0.49578857421875 +16505 -0.4810791015625 +16506 -0.560333251953125 +16507 -0.542999267578125 +16508 -0.60101318359375 +16509 -0.581695556640625 +16510 -0.584625244140625 +16511 -0.565521240234375 +16512 -0.47979736328125 +16513 -0.46466064453125 +16514 -0.2799072265625 +16515 -0.27288818359375 +16516 -0.009490966796875 +16517 -0.013671875 +16518 0.268218994140625 +16519 0.252655029296875 +16520 0.482269287109375 +16521 0.45849609375 +16522 0.60321044921875 +16523 0.575714111328125 +16524 0.649993896484375 +16525 0.6221923828125 +16526 0.663665771484375 +16527 0.63690185546875 +16528 0.6412353515625 +16529 0.616912841796875 +16530 0.5723876953125 +16531 0.5523681640625 +16532 0.498077392578125 +16533 0.482177734375 +16534 0.439483642578125 +16535 0.426483154296875 +16536 0.375640869140625 +16537 0.365325927734375 +16538 0.274688720703125 +16539 0.268463134765625 +16540 0.1090087890625 +16541 0.109619140625 +16542 -0.09912109375 +16543 -0.08990478515625 +16544 -0.31793212890625 +16545 -0.2998046875 +16546 -0.54864501953125 +16547 -0.521148681640625 +16548 -0.773529052734375 +16549 -0.7369384765625 +16550 -0.863800048828125 +16551 -0.859100341796875 +16552 -0.870391845703125 +16553 -0.866973876953125 +16554 -0.868988037109375 +16555 -0.8670654296875 +16556 -0.861114501953125 +16557 -0.86077880859375 +16558 -0.766510009765625 +16559 -0.779083251953125 +16560 -0.53094482421875 +16561 -0.560455322265625 +16562 -0.215576171875 +16563 -0.262725830078125 +16564 0.13641357421875 +16565 0.0731201171875 +16566 0.473846435546875 +16567 0.398193359375 +16568 0.761444091796875 +16569 0.6785888671875 +16570 0.86737060546875 +16571 0.858184814453125 +16572 0.870361328125 +16573 0.870361328125 +16574 0.864898681640625 +16575 0.870361328125 +16576 0.833465576171875 +16577 0.86273193359375 +16578 0.679901123046875 +16579 0.816436767578125 +16580 0.498748779296875 +16581 0.666229248046875 +16582 0.3109130859375 +16583 0.49859619140625 +16584 0.119598388671875 +16585 0.3162841796875 +16586 -0.107330322265625 +16587 0.08905029296875 +16588 -0.378570556640625 +16589 -0.190460205078125 +16590 -0.654327392578125 +16591 -0.482940673828125 +16592 -0.857147216796875 +16593 -0.733367919921875 +16594 -0.870391845703125 +16595 -0.859832763671875 +16596 -0.870391845703125 +16597 -0.869110107421875 +16598 -0.86444091796875 +16599 -0.870391845703125 +16600 -0.85723876953125 +16601 -0.869659423828125 +16602 -0.790008544921875 +16603 -0.86541748046875 +16604 -0.62847900390625 +16605 -0.834625244140625 +16606 -0.3956298828125 +16607 -0.632965087890625 +16608 -0.126708984375 +16609 -0.38238525390625 +16610 0.150115966796875 +16611 -0.109832763671875 +16612 0.424041748046875 +16613 0.173492431640625 +16614 0.670623779296875 +16615 0.44268798828125 +16616 0.854522705078125 +16617 0.662322998046875 +16618 0.866485595703125 +16619 0.817657470703125 +16620 0.86920166015625 +16621 0.85906982421875 +16622 0.8653564453125 +16623 0.861541748046875 +16624 0.857147216796875 +16625 0.859588623046875 +16626 0.766845703125 +16627 0.84326171875 +16628 0.628509521484375 +16629 0.752777099609375 +16630 0.462127685546875 +16631 0.625946044921875 +16632 0.297210693359375 +16633 0.489471435546875 +16634 0.14862060546875 +16635 0.356658935546875 +16636 -0.00537109375 +16637 0.20672607421875 +16638 -0.15753173828125 +16639 0.047088623046875 +16640 -0.31304931640625 +16641 -0.125640869140625 +16642 -0.48876953125 +16643 -0.32574462890625 +16644 -0.6416015625 +16645 -0.511383056640625 +16646 -0.751373291015625 +16647 -0.661041259765625 +16648 -0.84619140625 +16649 -0.79754638671875 +16650 -0.861297607421875 +16651 -0.860504150390625 +16652 -0.863250732421875 +16653 -0.86688232421875 +16654 -0.856597900390625 +16655 -0.86456298828125 +16656 -0.7498779296875 +16657 -0.85498046875 +16658 -0.624542236328125 +16659 -0.75927734375 +16660 -0.47808837890625 +16661 -0.629669189453125 +16662 -0.253387451171875 +16663 -0.41741943359375 +16664 0.003692626953125 +16665 -0.165313720703125 +16666 0.2257080078125 +16667 0.06341552734375 +16668 0.427154541015625 +16669 0.28045654296875 +16670 0.643218994140625 +16671 0.5162353515625 +16672 0.855926513671875 +16673 0.762908935546875 +16674 0.870361328125 +16675 0.866912841796875 +16676 0.870361328125 +16677 0.870361328125 +16678 0.862762451171875 +16679 0.866241455078125 +16680 0.79669189453125 +16681 0.85491943359375 +16682 0.595794677734375 +16683 0.68603515625 +16684 0.362152099609375 +16685 0.47540283203125 +16686 0.1270751953125 +16687 0.255584716796875 +16688 -0.086944580078125 +16689 0.047637939453125 +16690 -0.2784423828125 +16691 -0.146270751953125 +16692 -0.484832763671875 +16693 -0.359344482421875 +16694 -0.729583740234375 +16695 -0.611785888671875 +16696 -0.86688232421875 +16697 -0.855194091796875 +16698 -0.870391845703125 +16699 -0.870391845703125 +16700 -0.86859130859375 +16701 -0.870391845703125 +16702 -0.86279296875 +16703 -0.866119384765625 +16704 -0.817962646484375 +16705 -0.855224609375 +16706 -0.6116943359375 +16707 -0.6688232421875 +16708 -0.3128662109375 +16709 -0.38580322265625 +16710 0.039398193359375 +16711 -0.0484619140625 +16712 0.422821044921875 +16713 0.32177734375 +16714 0.805145263671875 +16715 0.69415283203125 +16716 0.870361328125 +16717 0.870361328125 +16718 0.870361328125 +16719 0.870361328125 +16720 0.860015869140625 +16721 0.860382080078125 +16722 0.727935791015625 +16723 0.736968994140625 +16724 0.48114013671875 +16725 0.49810791015625 +16726 0.2059326171875 +16727 0.23040771484375 +16728 -0.06103515625 +16729 -0.031494140625 +16730 -0.29913330078125 +16731 -0.267730712890625 +16732 -0.516204833984375 +16733 -0.48455810546875 +16734 -0.7252197265625 +16735 -0.69293212890625 +16736 -0.85980224609375 +16737 -0.85626220703125 +16738 -0.870391845703125 +16739 -0.869354248046875 +16740 -0.870391845703125 +16741 -0.870391845703125 +16742 -0.858062744140625 +16743 -0.85955810546875 +16744 -0.673004150390625 +16745 -0.70391845703125 +16746 -0.42694091796875 +16747 -0.472930908203125 +16748 -0.2100830078125 +16749 -0.26458740234375 +16750 -0.0362548828125 +16751 -0.092193603515625 +16752 0.10943603515625 +16753 0.05712890625 +16754 0.23516845703125 +16755 0.190032958984375 +16756 0.373687744140625 +16757 0.33563232421875 +16758 0.517791748046875 +16759 0.48626708984375 +16760 0.602783203125 +16761 0.581451416015625 +16762 0.635711669921875 +16763 0.626800537109375 +16764 0.655181884765625 +16765 0.65704345703125 +16766 0.65948486328125 +16767 0.670013427734375 +16768 0.651275634765625 +16769 0.667755126953125 +16770 0.61846923828125 +16771 0.638946533203125 +16772 0.53753662109375 +16773 0.56201171875 +16774 0.404144287109375 +16775 0.4332275390625 +16776 0.22186279296875 +16777 0.25628662109375 +16778 0.003997802734375 +16779 0.044036865234375 +16780 -0.22100830078125 +16781 -0.1766357421875 +16782 -0.42449951171875 +16783 -0.37860107421875 +16784 -0.579833984375 +16785 -0.536468505859375 +16786 -0.641876220703125 +16787 -0.60791015625 +16788 -0.6177978515625 +16789 -0.598785400390625 +16790 -0.575531005859375 +16791 -0.570892333984375 +16792 -0.526336669921875 +16793 -0.534027099609375 +16794 -0.42645263671875 +16795 -0.447601318359375 +16796 -0.2581787109375 +16797 -0.295074462890625 +16798 -0.068695068359375 +16799 -0.11981201171875 +16800 0.09222412109375 +16801 0.032257080078125 +16802 0.232147216796875 +16803 0.167755126953125 +16804 0.3509521484375 +16805 0.2861328125 +16806 0.410064697265625 +16807 0.351318359375 +16808 0.372955322265625 +16809 0.329071044921875 +16810 0.2554931640625 +16811 0.23333740234375 +16812 0.10711669921875 +16813 0.10888671875 +16814 -0.052886962890625 +16815 -0.027191162109375 +16816 -0.186279296875 +16817 -0.1402587890625 +16818 -0.23291015625 +16819 -0.17547607421875 +16820 -0.209442138671875 +16821 -0.148529052734375 +16822 -0.174163818359375 +16823 -0.11328125 +16824 -0.126739501953125 +16825 -0.069488525390625 +16826 -0.048126220703125 +16827 0.000396728515625 +16828 0.0426025390625 +16829 0.07904052734375 +16830 0.10748291015625 +16831 0.131866455078125 +16832 0.1409912109375 +16833 0.15423583984375 +16834 0.19708251953125 +16835 0.196258544921875 +16836 0.273651123046875 +16837 0.256591796875 +16838 0.31768798828125 +16839 0.287017822265625 +16840 0.341094970703125 +16841 0.299041748046875 +16842 0.368011474609375 +16843 0.315399169921875 +16844 0.37249755859375 +16845 0.312591552734375 +16846 0.30072021484375 +16847 0.241455078125 +16848 0.1517333984375 +16849 0.101318359375 +16850 -0.01470947265625 +16851 -0.052734375 +16852 -0.1883544921875 +16853 -0.21124267578125 +16854 -0.372711181640625 +16855 -0.3775634765625 +16856 -0.51397705078125 +16857 -0.50244140625 +16858 -0.57177734375 +16859 -0.549072265625 +16860 -0.53948974609375 +16861 -0.511749267578125 +16862 -0.43511962890625 +16863 -0.407501220703125 +16864 -0.2962646484375 +16865 -0.2713623046875 +16866 -0.161102294921875 +16867 -0.138916015625 +16868 -0.0435791015625 +16869 -0.02337646484375 +16870 0.060394287109375 +16871 0.07855224609375 +16872 0.13665771484375 +16873 0.153564453125 +16874 0.170135498046875 +16875 0.18756103515625 +16876 0.16552734375 +16877 0.18475341796875 +16878 0.15728759765625 +16879 0.176788330078125 +16880 0.150787353515625 +16881 0.168701171875 +16882 0.12200927734375 +16883 0.138519287109375 +16884 0.080108642578125 +16885 0.094940185546875 +16886 0.05126953125 +16887 0.062347412109375 +16888 0.062896728515625 +16889 0.06634521484375 +16890 0.09271240234375 +16891 0.086822509765625 +16892 0.092987060546875 +16893 0.08026123046875 +16894 0.07855224609375 +16895 0.060638427734375 +16896 0.06427001953125 +16897 0.0421142578125 +16898 0.0347900390625 +16899 0.010772705078125 +16900 -0.01171875 +16901 -0.03497314453125 +16902 -0.056060791015625 +16903 -0.077484130859375 +16904 -0.055511474609375 +16905 -0.078125 +16906 -0.010467529296875 +16907 -0.037139892578125 +16908 0.02508544921875 +16909 -0.00311279296875 +16910 0.025665283203125 +16911 0.0008544921875 +16912 0.017333984375 +16913 -0.001953125 +16914 0.00189208984375 +16915 -0.01025390625 +16916 -0.03173828125 +16917 -0.034332275390625 +16918 -0.071502685546875 +16919 -0.063751220703125 +16920 -0.13543701171875 +16921 -0.115081787109375 +16922 -0.219970703125 +16923 -0.18548583984375 +16924 -0.300506591796875 +16925 -0.25311279296875 +16926 -0.376312255859375 +16927 -0.317535400390625 +16928 -0.416107177734375 +16929 -0.35076904296875 +16930 -0.371124267578125 +16931 -0.309051513671875 +16932 -0.242279052734375 +16933 -0.1932373046875 +16934 -0.069732666015625 +16935 -0.0394287109375 +16936 0.125640869140625 +16937 0.1336669921875 +16938 0.31268310546875 +16939 0.2982177734375 +16940 0.45501708984375 +16941 0.421722412109375 +16942 0.554779052734375 +16943 0.506378173828125 +16944 0.61065673828125 +16945 0.551300048828125 +16946 0.610931396484375 +16947 0.546234130859375 +16948 0.531463623046875 +16949 0.46978759765625 +16950 0.3883056640625 +16951 0.33660888671875 +16952 0.23468017578125 +16953 0.19482421875 +16954 0.095245361328125 +16955 0.06683349609375 +16956 -0.00396728515625 +16957 -0.02386474609375 +16958 -0.04852294921875 +16959 -0.064239501953125 +16960 -0.055145263671875 +16961 -0.069305419921875 +16962 -0.0758056640625 +16963 -0.085968017578125 +16964 -0.138702392578125 +16965 -0.139739990234375 +16966 -0.209197998046875 +16967 -0.199615478515625 +16968 -0.289031982421875 +16969 -0.26739501953125 +16970 -0.37884521484375 +16971 -0.343902587890625 +16972 -0.456329345703125 +16973 -0.409271240234375 +16974 -0.51641845703125 +16975 -0.45916748046875 +16976 -0.519287109375 +16977 -0.457977294921875 +16978 -0.458251953125 +16979 -0.399871826171875 +16980 -0.384796142578125 +16981 -0.33135986328125 +16982 -0.323699951171875 +16983 -0.27484130859375 +16984 -0.269287109375 +16985 -0.225250244140625 +16986 -0.1951904296875 +16987 -0.158905029296875 +16988 -0.100006103515625 +16989 -0.074462890625 +16990 -0.01055908203125 +16991 0.003997802734375 +16992 0.1033935546875 +16993 0.10382080078125 +16994 0.24908447265625 +16995 0.231689453125 +16996 0.373199462890625 +16997 0.339813232421875 +16998 0.45806884765625 +16999 0.412506103515625 +17000 0.511474609375 +17001 0.456939697265625 +17002 0.565399169921875 +17003 0.50213623046875 +17004 0.61138916015625 +17005 0.540679931640625 +17006 0.5897216796875 +17007 0.5189208984375 +17008 0.4906005859375 +17009 0.42816162109375 +17010 0.33148193359375 +17011 0.284210205078125 +17012 0.147796630859375 +17013 0.118927001953125 +17014 -0.01873779296875 +17015 -0.0301513671875 +17016 -0.140289306640625 +17017 -0.1380615234375 +17018 -0.191986083984375 +17019 -0.182464599609375 +17020 -0.184295654296875 +17021 -0.172943115234375 +17022 -0.161834716796875 +17023 -0.149810791015625 +17024 -0.166595458984375 +17025 -0.151031494140625 +17026 -0.19390869140625 +17027 -0.172576904296875 +17028 -0.22442626953125 +17029 -0.197174072265625 +17030 -0.279754638671875 +17031 -0.244415283203125 +17032 -0.3389892578125 +17033 -0.295623779296875 +17034 -0.3543701171875 +17035 -0.307952880859375 +17036 -0.348175048828125 +17037 -0.301513671875 +17038 -0.32598876953125 +17039 -0.281341552734375 +17040 -0.2581787109375 +17041 -0.220794677734375 +17042 -0.139801025390625 +17043 -0.1153564453125 +17044 0.014617919921875 +17045 0.022003173828125 +17046 0.144378662109375 +17047 0.13671875 +17048 0.221038818359375 +17049 0.203338623046875 +17050 0.27069091796875 +17051 0.2454833984375 +17052 0.294036865234375 +17053 0.263916015625 +17054 0.311767578125 +17055 0.277435302734375 +17056 0.339141845703125 +17057 0.29986572265625 +17058 0.360260009765625 +17059 0.316802978515625 +17060 0.360504150390625 +17061 0.315277099609375 +17062 0.308380126953125 +17063 0.2674560546875 +17064 0.18170166015625 +17065 0.15374755859375 +17066 0.0047607421875 +17067 -0.004150390625 +17068 -0.17559814453125 +17069 -0.16461181640625 +17070 -0.3143310546875 +17071 -0.287628173828125 +17072 -0.36785888671875 +17073 -0.33453369140625 +17074 -0.36248779296875 +17075 -0.32867431640625 +17076 -0.343536376953125 +17077 -0.310394287109375 +17078 -0.3018798828125 +17079 -0.27166748046875 +17080 -0.231414794921875 +17081 -0.207183837890625 +17082 -0.117645263671875 +17083 -0.10418701171875 +17084 0.007049560546875 +17085 0.008453369140625 +17086 0.087982177734375 +17087 0.082061767578125 +17088 0.13946533203125 +17089 0.1292724609375 +17090 0.17425537109375 +17091 0.161346435546875 +17092 0.188201904296875 +17093 0.17449951171875 +17094 0.171234130859375 +17095 0.1597900390625 +17096 0.118438720703125 +17097 0.112823486328125 +17098 0.05706787109375 +17099 0.057830810546875 +17100 -0.010711669921875 +17101 -0.00323486328125 +17102 -0.0914306640625 +17103 -0.07611083984375 +17104 -0.162322998046875 +17105 -0.140472412109375 +17106 -0.194549560546875 +17107 -0.170684814453125 +17108 -0.1492919921875 +17109 -0.132171630859375 +17110 -0.02166748046875 +17111 -0.020477294921875 +17112 0.124053955078125 +17113 0.107391357421875 +17114 0.211151123046875 +17115 0.18341064453125 +17116 0.240447998046875 +17117 0.2083740234375 +17118 0.242218017578125 +17119 0.209197998046875 +17120 0.2257080078125 +17121 0.19415283203125 +17122 0.194366455078125 +17123 0.166290283203125 +17124 0.115509033203125 +17125 0.096588134765625 +17126 0.0128173828125 +17127 0.00604248046875 +17128 -0.053802490234375 +17129 -0.052215576171875 +17130 -0.110626220703125 +17131 -0.101531982421875 +17132 -0.199493408203125 +17133 -0.179168701171875 +17134 -0.29437255859375 +17135 -0.262054443359375 +17136 -0.33221435546875 +17137 -0.294281005859375 +17138 -0.27972412109375 +17139 -0.246368408203125 +17140 -0.185333251953125 +17141 -0.16143798828125 +17142 -0.128204345703125 +17143 -0.109771728515625 +17144 -0.115692138671875 +17145 -0.09796142578125 +17146 -0.116455078125 +17147 -0.09820556640625 +17148 -0.105926513671875 +17149 -0.088714599609375 +17150 -0.053955078125 +17151 -0.042724609375 +17152 0.048797607421875 +17153 0.0478515625 +17154 0.157318115234375 +17155 0.1434326171875 +17156 0.212005615234375 +17157 0.192230224609375 +17158 0.218475341796875 +17159 0.198883056640625 +17160 0.23724365234375 +17161 0.21514892578125 +17162 0.30535888671875 +17163 0.272796630859375 +17164 0.38128662109375 +17165 0.3363037109375 +17166 0.404449462890625 +17167 0.353973388671875 +17168 0.3944091796875 +17169 0.34271240234375 +17170 0.3885498046875 +17171 0.334716796875 +17172 0.362640380859375 +17173 0.309478759765625 +17174 0.27362060546875 +17175 0.230316162109375 +17176 0.11712646484375 +17177 0.09368896484375 +17178 -0.054901123046875 +17179 -0.055816650390625 +17180 -0.19085693359375 +17181 -0.173858642578125 +17182 -0.28570556640625 +17183 -0.256072998046875 +17184 -0.339263916015625 +17185 -0.302276611328125 +17186 -0.3775634765625 +17187 -0.334747314453125 +17188 -0.445709228515625 +17189 -0.392120361328125 +17190 -0.535064697265625 +17191 -0.46710205078125 +17192 -0.629058837890625 +17193 -0.54559326171875 +17194 -0.697601318359375 +17195 -0.601959228515625 +17196 -0.70391845703125 +17197 -0.6048583984375 +17198 -0.6424560546875 +17199 -0.5496826171875 +17200 -0.491241455078125 +17201 -0.417755126953125 +17202 -0.265716552734375 +17203 -0.222412109375 +17204 -0.023712158203125 +17205 -0.0133056640625 +17206 0.201751708984375 +17207 0.181182861328125 +17208 0.375823974609375 +17209 0.3311767578125 +17210 0.485076904296875 +17211 0.425140380859375 +17212 0.56884765625 +17213 0.496734619140625 +17214 0.634765625 +17215 0.552520751953125 +17216 0.63763427734375 +17217 0.553863525390625 +17218 0.5660400390625 +17219 0.491058349609375 +17220 0.4720458984375 +17221 0.40875244140625 +17222 0.40692138671875 +17223 0.3509521484375 +17224 0.3778076171875 +17225 0.323883056640625 +17226 0.376953125 +17227 0.321044921875 +17228 0.371978759765625 +17229 0.3148193359375 +17230 0.313140869140625 +17231 0.26275634765625 +17232 0.184417724609375 +17233 0.151214599609375 +17234 0.011199951171875 +17235 0.001983642578125 +17236 -0.171051025390625 +17237 -0.154510498046875 +17238 -0.33740234375 +17239 -0.29693603515625 +17240 -0.47198486328125 +17241 -0.411712646484375 +17242 -0.560394287109375 +17243 -0.486572265625 +17244 -0.58056640625 +17245 -0.502685546875 +17246 -0.54754638671875 +17247 -0.472991943359375 +17248 -0.508575439453125 +17249 -0.438018798828125 +17250 -0.459503173828125 +17251 -0.394287109375 +17252 -0.394378662109375 +17253 -0.336822509765625 +17254 -0.35260009765625 +17255 -0.2994384765625 +17256 -0.31170654296875 +17257 -0.262969970703125 +17258 -0.197418212890625 +17259 -0.1639404296875 +17260 -0.007965087890625 +17261 -0.0008544921875 +17262 0.207489013671875 +17263 0.18414306640625 +17264 0.409210205078125 +17265 0.35699462890625 +17266 0.57208251953125 +17267 0.4962158203125 +17268 0.66595458984375 +17269 0.57598876953125 +17270 0.65875244140625 +17271 0.56890869140625 +17272 0.56744384765625 +17273 0.48956298828125 +17274 0.431396484375 +17275 0.371734619140625 +17276 0.29443359375 +17277 0.2530517578125 +17278 0.182464599609375 +17279 0.15576171875 +17280 0.06365966796875 +17281 0.05267333984375 +17282 -0.075958251953125 +17283 -0.068084716796875 +17284 -0.189422607421875 +17285 -0.166229248046875 +17286 -0.271942138671875 +17287 -0.23760986328125 +17288 -0.342529296875 +17289 -0.2984619140625 +17290 -0.364166259765625 +17291 -0.317108154296875 +17292 -0.327239990234375 +17293 -0.285369873046875 +17294 -0.2769775390625 +17295 -0.241943359375 +17296 -0.253692626953125 +17297 -0.22137451171875 +17298 -0.24365234375 +17299 -0.2119140625 +17300 -0.1983642578125 +17301 -0.172119140625 +17302 -0.116241455078125 +17303 -0.1007080078125 +17304 -0.036834716796875 +17305 -0.03155517578125 +17306 0.034881591796875 +17307 0.030975341796875 +17308 0.09124755859375 +17309 0.080291748046875 +17310 0.10888671875 +17311 0.0963134765625 +17312 0.125518798828125 +17313 0.11126708984375 +17314 0.15771484375 +17315 0.13934326171875 +17316 0.17828369140625 +17317 0.157196044921875 +17318 0.17108154296875 +17319 0.150970458984375 +17320 0.129974365234375 +17321 0.115478515625 +17322 0.082427978515625 +17323 0.074249267578125 +17324 0.027679443359375 +17325 0.02667236328125 +17326 -0.065643310546875 +17327 -0.054046630859375 +17328 -0.15936279296875 +17329 -0.135162353515625 +17330 -0.21307373046875 +17331 -0.18206787109375 +17332 -0.234649658203125 +17333 -0.201446533203125 +17334 -0.2001953125 +17335 -0.17279052734375 +17336 -0.119171142578125 +17337 -0.10418701171875 +17338 -0.024749755859375 +17339 -0.02398681640625 +17340 0.085784912109375 +17341 0.070159912109375 +17342 0.178131103515625 +17343 0.14892578125 +17344 0.215576171875 +17345 0.180908203125 +17346 0.211456298828125 +17347 0.177490234375 +17348 0.17523193359375 +17349 0.146759033203125 +17350 0.128753662109375 +17351 0.107421875 +17352 0.1019287109375 +17353 0.085052490234375 +17354 0.0743408203125 +17355 0.062164306640625 +17356 0.04327392578125 +17357 0.036376953125 +17358 0.038177490234375 +17359 0.0328369140625 +17360 0.076263427734375 +17361 0.06622314453125 +17362 0.14105224609375 +17363 0.12237548828125 +17364 0.186431884765625 +17365 0.16180419921875 +17366 0.188812255859375 +17367 0.164276123046875 +17368 0.1390380859375 +17369 0.121917724609375 +17370 0.041778564453125 +17371 0.038726806640625 +17372 -0.079437255859375 +17373 -0.06512451171875 +17374 -0.219390869140625 +17375 -0.1851806640625 +17376 -0.367828369140625 +17377 -0.312591552734375 +17378 -0.494873046875 +17379 -0.421783447265625 +17380 -0.556243896484375 +17381 -0.474853515625 +17382 -0.508697509765625 +17383 -0.43475341796875 +17384 -0.3756103515625 +17385 -0.321441650390625 +17386 -0.218902587890625 +17387 -0.187896728515625 +17388 -0.063751220703125 +17389 -0.055633544921875 +17390 0.091552734375 +17391 0.076812744140625 +17392 0.23602294921875 +17393 0.2000732421875 +17394 0.342987060546875 +17395 0.29132080078125 +17396 0.39520263671875 +17397 0.335845947265625 +17398 0.389373779296875 +17399 0.330810546875 +17400 0.324249267578125 +17401 0.275177001953125 +17402 0.224090576171875 +17403 0.189666748046875 +17404 0.124267578125 +17405 0.10455322265625 +17406 0.037078857421875 +17407 0.030303955078125 +17408 -0.010101318359375 +17409 -0.01007080078125 +17410 -0.019439697265625 +17411 -0.01824951171875 +17412 -0.022796630859375 +17413 -0.020843505859375 +17414 -0.001556396484375 +17415 -0.00274658203125 +17416 0.056304931640625 +17417 0.045745849609375 +17418 0.106719970703125 +17419 0.088134765625 +17420 0.096893310546875 +17421 0.080780029296875 +17422 0.042694091796875 +17423 0.03668212890625 +17424 -0.018035888671875 +17425 -0.01300048828125 +17426 -0.07586669921875 +17427 -0.060516357421875 +17428 -0.11944580078125 +17429 -0.09649658203125 +17430 -0.15972900390625 +17431 -0.129974365234375 +17432 -0.202606201171875 +17433 -0.165771484375 +17434 -0.24859619140625 +17435 -0.2042236328125 +17436 -0.30517578125 +17437 -0.251434326171875 +17438 -0.36212158203125 +17439 -0.298980712890625 +17440 -0.39141845703125 +17441 -0.32373046875 +17442 -0.35528564453125 +17443 -0.294464111328125 +17444 -0.249969482421875 +17445 -0.208099365234375 +17446 -0.092864990234375 +17447 -0.07891845703125 +17448 0.08905029296875 +17449 0.07086181640625 +17450 0.2352294921875 +17451 0.191314697265625 +17452 0.318817138671875 +17453 0.260345458984375 +17454 0.358642578125 +17455 0.293426513671875 +17456 0.347747802734375 +17457 0.284820556640625 +17458 0.28564453125 +17459 0.234130859375 +17460 0.223175048828125 +17461 0.183197021484375 +17462 0.196746826171875 +17463 0.161956787109375 +17464 0.179840087890625 +17465 0.1485595703125 +17466 0.155548095703125 +17467 0.129058837890625 +17468 0.151214599609375 +17469 0.1259765625 +17470 0.156951904296875 +17471 0.131103515625 +17472 0.13177490234375 +17473 0.11065673828125 +17474 0.100799560546875 +17475 0.085296630859375 +17476 0.087127685546875 +17477 0.074066162109375 +17478 0.05487060546875 +17479 0.047393798828125 +17480 -0.009002685546875 +17481 -0.00543212890625 +17482 -0.10400390625 +17483 -0.083984375 +17484 -0.229400634765625 +17485 -0.18768310546875 +17486 -0.35552978515625 +17487 -0.29205322265625 +17488 -0.441925048828125 +17489 -0.36370849609375 +17490 -0.473846435546875 +17491 -0.3905029296875 +17492 -0.464813232421875 +17493 -0.383514404296875 +17494 -0.419097900390625 +17495 -0.346221923828125 +17496 -0.334320068359375 +17497 -0.27667236328125 +17498 -0.227935791015625 +17499 -0.189239501953125 +17500 -0.12347412109375 +17501 -0.103302001953125 +17502 -0.02764892578125 +17503 -0.02435302734375 +17504 0.077667236328125 +17505 0.062530517578125 +17506 0.2132568359375 +17507 0.1744384765625 +17508 0.38885498046875 +17509 0.319366455078125 +17510 0.582794189453125 +17511 0.479461669921875 +17512 0.734039306640625 +17513 0.604400634765625 +17514 0.800140380859375 +17515 0.659210205078125 +17516 0.7783203125 +17517 0.64154052734375 +17518 0.6651611328125 +17519 0.548583984375 +17520 0.45965576171875 +17521 0.3795166015625 +17522 0.199188232421875 +17523 0.16510009765625 +17524 -0.050689697265625 +17525 -0.0406494140625 +17526 -0.23297119140625 +17527 -0.190765380859375 +17528 -0.33013916015625 +17529 -0.27081298828125 +17530 -0.368408203125 +17531 -0.3023681640625 +17532 -0.378936767578125 +17533 -0.31109619140625 +17534 -0.376983642578125 +17535 -0.30963134765625 +17536 -0.37969970703125 +17537 -0.31207275390625 +17538 -0.391510009765625 +17539 -0.322052001953125 +17540 -0.385345458984375 +17541 -0.3172607421875 +17542 -0.3419189453125 +17543 -0.281768798828125 +17544 -0.28289794921875 +17545 -0.233428955078125 +17546 -0.251617431640625 +17547 -0.207916259765625 +17548 -0.266143798828125 +17549 -0.2200927734375 +17550 -0.273345947265625 +17551 -0.2261962890625 +17552 -0.216796875 +17553 -0.179718017578125 +17554 -0.128265380859375 +17555 -0.1068115234375 +17556 -0.068145751953125 +17557 -0.0572509765625 +17558 -0.0430908203125 +17559 -0.0364990234375 +17560 -0.024444580078125 +17561 -0.020965576171875 +17562 0.020721435546875 +17563 0.0164794921875 +17564 0.124481201171875 +17565 0.10223388671875 +17566 0.25787353515625 +17567 0.21240234375 +17568 0.379119873046875 +17569 0.31256103515625 +17570 0.47991943359375 +17571 0.3958740234375 +17572 0.5281982421875 +17573 0.435882568359375 +17574 0.511138916015625 +17575 0.4219970703125 +17576 0.456207275390625 +17577 0.376861572265625 +17578 0.407470703125 +17579 0.3367919921875 +17580 0.383758544921875 +17581 0.317291259765625 +17582 0.35687255859375 +17583 0.29510498046875 +17584 0.31182861328125 +17585 0.257904052734375 +17586 0.250885009765625 +17587 0.20751953125 +17588 0.1654052734375 +17589 0.136871337890625 +17590 0.035247802734375 +17591 0.029388427734375 +17592 -0.142059326171875 +17593 -0.116943359375 +17594 -0.33563232421875 +17595 -0.27667236328125 +17596 -0.5345458984375 +17597 -0.440765380859375 +17598 -0.72186279296875 +17599 -0.595245361328125 +17600 -0.836669921875 +17601 -0.68994140625 +17602 -0.8326416015625 +17603 -0.68670654296875 +17604 -0.7296142578125 +17605 -0.60186767578125 +17606 -0.582550048828125 +17607 -0.480712890625 +17608 -0.440093994140625 +17609 -0.363311767578125 +17610 -0.324310302734375 +17611 -0.267852783203125 +17612 -0.20147705078125 +17613 -0.16656494140625 +17614 -0.044647216796875 +17615 -0.0372314453125 +17616 0.103973388671875 +17617 0.085357666015625 +17618 0.202392578125 +17619 0.166595458984375 +17620 0.264495849609375 +17621 0.2178955078125 +17622 0.338897705078125 +17623 0.279327392578125 +17624 0.443817138671875 +17625 0.365875244140625 +17626 0.545074462890625 +17627 0.44940185546875 +17628 0.6173095703125 +17629 0.50897216796875 +17630 0.6524658203125 +17631 0.537994384765625 +17632 0.66339111328125 +17633 0.547027587890625 +17634 0.6561279296875 +17635 0.541046142578125 +17636 0.606781005859375 +17637 0.500335693359375 +17638 0.501190185546875 +17639 0.413238525390625 +17640 0.352783203125 +17641 0.29083251953125 +17642 0.176544189453125 +17643 0.145477294921875 +17644 -0.034820556640625 +17645 -0.02880859375 +17646 -0.258209228515625 +17647 -0.212982177734375 +17648 -0.44244384765625 +17649 -0.364898681640625 +17650 -0.5753173828125 +17651 -0.47442626953125 +17652 -0.65203857421875 +17653 -0.53765869140625 +17654 -0.641632080078125 +17655 -0.529083251953125 +17656 -0.562164306640625 +17657 -0.463592529296875 +17658 -0.458038330078125 +17659 -0.377777099609375 +17660 -0.350555419921875 +17661 -0.289154052734375 +17662 -0.260528564453125 +17663 -0.214874267578125 +17664 -0.192108154296875 +17665 -0.158233642578125 +17666 -0.141937255859375 +17667 -0.11639404296875 +17668 -0.1021728515625 +17669 -0.08319091796875 +17670 -0.062896728515625 +17671 -0.050567626953125 +17672 -0.011932373046875 +17673 -0.00872802734375 +17674 0.062835693359375 +17675 0.05194091796875 +17676 0.148712158203125 +17677 0.121368408203125 +17678 0.241729736328125 +17679 0.19635009765625 +17680 0.34912109375 +17681 0.2825927734375 +17682 0.457305908203125 +17683 0.369293212890625 +17684 0.54388427734375 +17685 0.438629150390625 +17686 0.5728759765625 +17687 0.462066650390625 +17688 0.506591796875 +17689 0.409698486328125 +17690 0.351226806640625 +17691 0.286407470703125 +17692 0.146514892578125 +17693 0.123626708984375 +17694 -0.05523681640625 +17695 -0.037139892578125 +17696 -0.21624755859375 +17697 -0.165924072265625 +17698 -0.334930419921875 +17699 -0.26141357421875 +17700 -0.402984619140625 +17701 -0.31695556640625 +17702 -0.4412841796875 +17703 -0.3489990234375 +17704 -0.49578857421875 +17705 -0.39385986328125 +17706 -0.5601806640625 +17707 -0.4464111328125 +17708 -0.600738525390625 +17709 -0.479888916015625 +17710 -0.584228515625 +17711 -0.4678955078125 +17712 -0.47930908203125 +17713 -0.38555908203125 +17714 -0.27935791015625 +17715 -0.227630615234375 +17716 -0.0089111328125 +17717 -0.013519287109375 +17718 0.268798828125 +17719 0.206695556640625 +17720 0.482818603515625 +17721 0.376800537109375 +17722 0.60369873046875 +17723 0.473419189453125 +17724 0.650421142578125 +17725 0.51153564453125 +17726 0.66400146484375 +17727 0.5235595703125 +17728 0.6414794921875 +17729 0.507080078125 +17730 0.572540283203125 +17731 0.453857421875 +17732 0.498138427734375 +17733 0.396240234375 +17734 0.439453125 +17735 0.3509521484375 +17736 0.375518798828125 +17737 0.301300048828125 +17738 0.274505615234375 +17739 0.222015380859375 +17740 0.1087646484375 +17741 0.0911865234375 +17742 -0.099395751953125 +17743 -0.073516845703125 +17744 -0.3182373046875 +17745 -0.2469482421875 +17746 -0.5489501953125 +17747 -0.4300537109375 +17748 -0.7738037109375 +17749 -0.608734130859375 +17750 -0.86383056640625 +17751 -0.74102783203125 +17752 -0.870391845703125 +17753 -0.800567626953125 +17754 -0.86895751953125 +17755 -0.801300048828125 +17756 -0.861053466796875 +17757 -0.7535400390625 +17758 -0.765869140625 +17759 -0.6435546875 +17760 -0.5301513671875 +17761 -0.462371826171875 +17762 -0.214691162109375 +17763 -0.215576171875 +17764 0.137359619140625 +17765 0.062774658203125 +17766 0.474822998046875 +17767 0.33209228515625 +17768 0.76239013671875 +17769 0.564208984375 +17770 0.867462158203125 +17771 0.737762451171875 +17772 0.870361328125 +17773 0.85308837890625 +17774 0.86480712890625 +17775 0.85955810546875 +17776 0.831817626953125 +17777 0.857879638671875 +17778 0.677581787109375 +17779 0.82666015625 +17780 0.495880126953125 +17781 0.7281494140625 +17782 0.30767822265625 +17783 0.60491943359375 +17784 0.116180419921875 +17785 0.45867919921875 +17786 -0.110748291015625 +17787 0.26422119140625 +17788 -0.381805419921875 +17789 0.016021728515625 +17790 -0.6572265625 +17791 -0.25201416015625 +17792 -0.857421875 +17793 -0.49249267578125 +17794 -0.870391845703125 +17795 -0.67138671875 +17796 -0.870391845703125 +17797 -0.783050537109375 +17798 -0.86444091796875 +17799 -0.8487548828125 +17800 -0.85723876953125 +17801 -0.859130859375 +17802 -0.790008544921875 +17803 -0.86083984375 +17804 -0.62847900390625 +17805 -0.852935791015625 +17806 -0.3956298828125 +17807 -0.715576171875 +17808 -0.126708984375 +17809 -0.5263671875 +17810 0.150115966796875 +17811 -0.30694580078125 +17812 0.424041748046875 +17813 -0.066558837890625 +17814 0.670623779296875 +17815 0.173431396484375 +17816 0.854522705078125 +17817 0.382354736328125 +17818 0.866485595703125 +17819 0.54620361328125 +17820 0.86920166015625 +17821 0.652801513671875 +17822 0.8653564453125 +17823 0.71649169921875 +17824 0.857147216796875 +17825 0.747833251953125 +17826 0.766845703125 +17827 0.7445068359375 +17828 0.628509521484375 +17829 0.710540771484375 +17830 0.462127685546875 +17831 0.64056396484375 +17832 0.297210693359375 +17833 0.555023193359375 +17834 0.14862060546875 +17835 0.46368408203125 +17836 -0.00537109375 +17837 0.348419189453125 +17838 -0.15753173828125 +17839 0.21514892578125 +17840 -0.31304931640625 +17841 0.061004638671875 +17842 -0.48876953125 +17843 -0.125091552734375 +17844 -0.6416015625 +17845 -0.30596923828125 +17846 -0.751373291015625 +17847 -0.4620361328125 +17848 -0.84619140625 +17849 -0.61151123046875 +17850 -0.861297607421875 +17851 -0.74273681640625 +17852 -0.863250732421875 +17853 -0.829376220703125 +17854 -0.856597900390625 +17855 -0.846435546875 +17856 -0.7498779296875 +17857 -0.803497314453125 +17858 -0.624542236328125 +17859 -0.746337890625 +17860 -0.47808837890625 +17861 -0.657501220703125 +17862 -0.253387451171875 +17863 -0.490692138671875 +17864 0.003692626953125 +17865 -0.282073974609375 +17866 0.2257080078125 +17867 -0.085784912109375 +17868 0.427154541015625 +17869 0.1080322265625 +17870 0.643218994140625 +17871 0.32501220703125 +17872 0.855926513671875 +17873 0.55743408203125 +17874 0.870361328125 +17875 0.759368896484375 +17876 0.870361328125 +17877 0.8585205078125 +17878 0.862762451171875 +17879 0.86590576171875 +17880 0.79669189453125 +17881 0.86602783203125 +17882 0.595794677734375 +17883 0.858062744140625 +17884 0.362152099609375 +17885 0.763336181640625 +17886 0.1270751953125 +17887 0.610443115234375 +17888 -0.086944580078125 +17889 0.44549560546875 +17890 -0.2784423828125 +17891 0.270172119140625 +17892 -0.484832763671875 +17893 0.056976318359375 +17894 -0.729583740234375 +17895 -0.209197998046875 +17896 -0.86688232421875 +17897 -0.48822021484375 +17898 -0.870391845703125 +17899 -0.729827880859375 +17900 -0.86859130859375 +17901 -0.86273193359375 +17902 -0.86279296875 +17903 -0.870391845703125 +17904 -0.817962646484375 +17905 -0.870391845703125 +17906 -0.6116943359375 +17907 -0.859893798828125 +17908 -0.3128662109375 +17909 -0.709716796875 +17910 0.039398193359375 +17911 -0.44677734375 +17912 0.422821044921875 +17913 -0.132598876953125 +17914 0.805145263671875 +17915 0.205841064453125 +17916 0.870361328125 +17917 0.515167236328125 +17918 0.870361328125 +17919 0.751739501953125 +17920 0.860015869140625 +17921 0.860382080078125 +17922 0.727935791015625 +17923 0.868499755859375 +17924 0.48114013671875 +17925 0.86761474609375 +17926 0.2059326171875 +17927 0.860137939453125 +17928 -0.06103515625 +17929 0.799102783203125 +17930 -0.29913330078125 +17931 0.664947509765625 +17932 -0.516204833984375 +17933 0.496826171875 +17934 -0.7252197265625 +17935 0.28656005859375 +17936 -0.85980224609375 +17937 0.055999755859375 +17938 -0.870391845703125 +17939 -0.166534423828125 +17940 -0.870391845703125 +17941 -0.357177734375 +17942 -0.858062744140625 +17943 -0.4783935546875 +17944 -0.673004150390625 +17945 -0.527313232421875 +17946 -0.42694091796875 +17947 -0.544921875 +17948 -0.2100830078125 +17949 -0.566802978515625 +17950 -0.0362548828125 +17951 -0.593780517578125 +17952 0.10943603515625 +17953 -0.606658935546875 +17954 0.23516845703125 +17955 -0.593505859375 +17956 0.373687744140625 +17957 -0.526123046875 +17958 0.517791748046875 +17959 -0.40924072265625 +17960 0.602783203125 +17961 -0.293701171875 +17962 0.635711669921875 +17963 -0.17816162109375 +17964 0.655181884765625 +17965 -0.03936767578125 +17966 0.65948486328125 +17967 0.113616943359375 +17968 0.651275634765625 +17969 0.273895263671875 +17970 0.61846923828125 +17971 0.422698974609375 +17972 0.53753662109375 +17973 0.532501220703125 +17974 0.404144287109375 +17975 0.59075927734375 +17976 0.22186279296875 +17977 0.591796875 +17978 0.003997802734375 +17979 0.538726806640625 +17980 -0.22100830078125 +17981 0.447784423828125 +17982 -0.42449951171875 +17983 0.337310791015625 +17984 -0.579833984375 +17985 0.226165771484375 +17986 -0.641876220703125 +17987 0.14935302734375 +17988 -0.6177978515625 +17989 0.104095458984375 +17990 -0.575531005859375 +17991 0.043182373046875 +17992 -0.526336669921875 +17993 -0.035980224609375 +17994 -0.42645263671875 +17995 -0.0931396484375 +17996 -0.2581787109375 +17997 -0.1070556640625 +17998 -0.068695068359375 +17999 -0.105621337890625 +18000 0.09222412109375 +18001 -0.118865966796875 +18002 0.232147216796875 +18003 -0.133819580078125 +18004 0.3509521484375 +18005 -0.144378662109375 +18006 0.410064697265625 +18007 -0.17498779296875 +18008 0.372955322265625 +18009 -0.25 +18010 0.2554931640625 +18011 -0.3555908203125 +18012 0.10711669921875 +18013 -0.454193115234375 +18014 -0.052886962890625 +18015 -0.5328369140625 +18016 -0.186279296875 +18017 -0.56561279296875 +18018 -0.23291015625 +18019 -0.511322021484375 +18020 -0.209442138671875 +18021 -0.38812255859375 +18022 -0.174163818359375 +18023 -0.2464599609375 +18024 -0.126739501953125 +18025 -0.0926513671875 +18026 -0.048126220703125 +18027 0.08123779296875 +18028 0.0426025390625 +18029 0.254638671875 +18030 0.10748291015625 +18031 0.393280029296875 +18032 0.1409912109375 +18033 0.488525390625 +18034 0.19708251953125 +18035 0.578094482421875 +18036 0.273651123046875 +18037 0.658538818359375 +18038 0.31768798828125 +18039 0.689056396484375 +18040 0.341094970703125 +18041 0.679595947265625 +18042 0.368011474609375 +18043 0.65069580078125 +18044 0.37249755859375 +18045 0.5859375 +18046 0.30072021484375 +18047 0.44866943359375 +18048 0.1517333984375 +18049 0.243072509765625 +18050 -0.01470947265625 +18051 0.019866943359375 +18052 -0.1883544921875 +18053 -0.20770263671875 +18054 -0.372711181640625 +18055 -0.4371337890625 +18056 -0.51397705078125 +18057 -0.62286376953125 +18058 -0.57177734375 +18059 -0.730224609375 +18060 -0.53948974609375 +18061 -0.751190185546875 +18062 -0.43511962890625 +18063 -0.697479248046875 +18064 -0.2962646484375 +18065 -0.596832275390625 +18066 -0.161102294921875 +18067 -0.478607177734375 +18068 -0.0435791015625 +18069 -0.35479736328125 +18070 0.060394287109375 +18071 -0.2247314453125 +18072 0.13665771484375 +18073 -0.102386474609375 +18074 0.170135498046875 +18075 -0.003143310546875 +18076 0.16552734375 +18077 0.072265625 +18078 0.15728759765625 +18079 0.14556884765625 +18080 0.150787353515625 +18081 0.21649169921875 +18082 0.12200927734375 +18083 0.26275634765625 +18084 0.080108642578125 +18085 0.287811279296875 +18086 0.05126953125 +18087 0.308807373046875 +18088 0.062896728515625 +18089 0.344635009765625 +18090 0.09271240234375 +18091 0.3773193359375 +18092 0.092987060546875 +18093 0.37054443359375 +18094 0.07855224609375 +18095 0.33642578125 +18096 0.06427001953125 +18097 0.287994384765625 +18098 0.0347900390625 +18099 0.216064453125 +18100 -0.01171875 +18101 0.122222900390625 +18102 -0.056060791015625 +18103 0.024566650390625 +18104 -0.055511474609375 +18105 -0.040802001953125 +18106 -0.010467529296875 +18107 -0.07049560546875 +18108 0.02508544921875 +18109 -0.10211181640625 +18110 0.025665283203125 +18111 -0.1519775390625 +18112 0.017333984375 +18113 -0.197784423828125 +18114 0.00189208984375 +18115 -0.236328125 +18116 -0.03173828125 +18117 -0.274932861328125 +18118 -0.071502685546875 +18119 -0.304168701171875 +18120 -0.13543701171875 +18121 -0.338165283203125 +18122 -0.219970703125 +18123 -0.37542724609375 +18124 -0.300506591796875 +18125 -0.399078369140625 +18126 -0.376312255859375 +18127 -0.410888671875 +18128 -0.416107177734375 +18129 -0.389801025390625 +18130 -0.371124267578125 +18131 -0.301727294921875 +18132 -0.242279052734375 +18133 -0.150360107421875 +18134 -0.069732666015625 +18135 0.030853271484375 +18136 0.125640869140625 +18137 0.223388671875 +18138 0.31268310546875 +18139 0.401336669921875 +18140 0.45501708984375 +18141 0.535369873046875 +18142 0.554779052734375 +18143 0.625946044921875 +18144 0.61065673828125 +18145 0.671600341796875 +18146 0.610931396484375 +18147 0.66357421875 +18148 0.531463623046875 +18149 0.5843505859375 +18150 0.3883056640625 +18151 0.447418212890625 +18152 0.23468017578125 +18153 0.2950439453125 +18154 0.095245361328125 +18155 0.14813232421875 +18156 -0.00396728515625 +18157 0.02880859375 +18158 -0.04852294921875 +18159 -0.0494384765625 +18160 -0.055145263671875 +18161 -0.09686279296875 +18162 -0.0758056640625 +18163 -0.1507568359375 +18164 -0.138702392578125 +18165 -0.230560302734375 +18166 -0.209197998046875 +18167 -0.308380126953125 +18168 -0.289031982421875 +18169 -0.38446044921875 +18170 -0.37884521484375 +18171 -0.458709716796875 +18172 -0.456329345703125 +18173 -0.51409912109375 +18174 -0.51641845703125 +18175 -0.5472412109375 +18176 -0.519287109375 +18177 -0.52899169921875 +18178 -0.458251953125 +18179 -0.45562744140625 +18180 -0.384796142578125 +18181 -0.3675537109375 +18182 -0.323699951171875 +18183 -0.285308837890625 +18184 -0.269287109375 +18185 -0.20672607421875 +18186 -0.1951904296875 +18187 -0.1141357421875 +18188 -0.100006103515625 +18189 -0.008514404296875 +18190 -0.01055908203125 +18191 0.08819580078125 +18192 0.1033935546875 +18193 0.19720458984375 +18194 0.24908447265625 +18195 0.32281494140625 +18196 0.373199462890625 +18197 0.42437744140625 +18198 0.45806884765625 +18199 0.488372802734375 +18200 0.511474609375 +18201 0.520843505859375 +18202 0.565399169921875 +18203 0.546417236328125 +18204 0.61138916015625 +18205 0.559814453125 +18206 0.5897216796875 +18207 0.517547607421875 +18208 0.4906005859375 +18209 0.413818359375 +18210 0.33148193359375 +18211 0.263427734375 +18212 0.147796630859375 +18213 0.09466552734375 +18214 -0.01873779296875 +18215 -0.059478759765625 +18216 -0.140289306640625 +18217 -0.176544189453125 +18218 -0.191986083984375 +18219 -0.236572265625 +18220 -0.184295654296875 +18221 -0.24639892578125 +18222 -0.161834716796875 +18223 -0.238800048828125 +18224 -0.166595458984375 +18225 -0.24493408203125 +18226 -0.19390869140625 +18227 -0.2613525390625 +18228 -0.22442626953125 +18229 -0.27392578125 +18230 -0.279754638671875 +18231 -0.29962158203125 +18232 -0.3389892578125 +18233 -0.32379150390625 +18234 -0.3543701171875 +18235 -0.3118896484375 +18236 -0.348175048828125 +18237 -0.281951904296875 +18238 -0.32598876953125 +18239 -0.239593505859375 +18240 -0.2581787109375 +18241 -0.164031982421875 +18242 -0.139801025390625 +18243 -0.0528564453125 +18244 0.014617919921875 +18245 0.081878662109375 +18246 0.144378662109375 +18247 0.193695068359375 +18248 0.221038818359375 +18249 0.2606201171875 +18250 0.27069091796875 +18251 0.301849365234375 +18252 0.294036865234375 +18253 0.317840576171875 +18254 0.311767578125 +18255 0.324371337890625 +18256 0.339141845703125 +18257 0.33331298828125 +18258 0.360260009765625 +18259 0.333251953125 +18260 0.360504150390625 +18261 0.314300537109375 +18262 0.308380126953125 +18263 0.254730224609375 +18264 0.18170166015625 +18265 0.139739990234375 +18266 0.0047607421875 +18267 -0.011627197265625 +18268 -0.17559814453125 +18269 -0.164031982421875 +18270 -0.3143310546875 +18271 -0.283538818359375 +18272 -0.36785888671875 +18273 -0.337493896484375 +18274 -0.36248779296875 +18275 -0.34429931640625 +18276 -0.343536376953125 +18277 -0.336456298828125 +18278 -0.3018798828125 +18279 -0.307159423828125 +18280 -0.231414794921875 +18281 -0.252044677734375 +18282 -0.117645263671875 +18283 -0.160919189453125 +18284 0.007049560546875 +18285 -0.057952880859375 +18286 0.087982177734375 +18287 0.016265869140625 +18288 0.13946533203125 +18289 0.07122802734375 +18290 0.17425537109375 +18291 0.115203857421875 +18292 0.188201904296875 +18293 0.14410400390625 +18294 0.171234130859375 +18295 0.1495361328125 +18296 0.118438720703125 +18297 0.12701416015625 +18298 0.05706787109375 +18299 0.0955810546875 +18300 -0.010711669921875 +18301 0.056121826171875 +18302 -0.0914306640625 +18303 0.003448486328125 +18304 -0.162322998046875 +18305 -0.0460205078125 +18306 -0.194549560546875 +18307 -0.07135009765625 +18308 -0.1492919921875 +18309 -0.0440673828125 +18310 -0.02166748046875 +18311 0.039794921875 +18312 0.124053955078125 +18313 0.134063720703125 +18314 0.211151123046875 +18315 0.183624267578125 +18316 0.240447998046875 +18317 0.18988037109375 +18318 0.242218017578125 +18319 0.175689697265625 +18320 0.2257080078125 +18321 0.148681640625 +18322 0.194366455078125 +18323 0.1121826171875 +18324 0.115509033203125 +18325 0.043060302734375 +18326 0.0128173828125 +18327 -0.040802001953125 +18328 -0.053802490234375 +18329 -0.095367431640625 +18330 -0.110626220703125 +18331 -0.139556884765625 +18332 -0.199493408203125 +18333 -0.20379638671875 +18334 -0.29437255859375 +18335 -0.26922607421875 +18336 -0.33221435546875 +18337 -0.290252685546875 +18338 -0.27972412109375 +18339 -0.243072509765625 +18340 -0.185333251953125 +18341 -0.16351318359375 +18342 -0.128204345703125 +18343 -0.10980224609375 +18344 -0.115692138671875 +18345 -0.087982177734375 +18346 -0.116455078125 +18347 -0.07598876953125 +18348 -0.105926513671875 +18349 -0.056610107421875 +18350 -0.053955078125 +18351 -0.008544921875 +18352 0.048797607421875 +18353 0.07452392578125 +18354 0.157318115234375 +18355 0.159423828125 +18356 0.212005615234375 +18357 0.2025146484375 +18358 0.218475341796875 +18359 0.207794189453125 +18360 0.23724365234375 +18361 0.219329833984375 +18362 0.30535888671875 +18363 0.264312744140625 +18364 0.38128662109375 +18365 0.31280517578125 +18366 0.404449462890625 +18367 0.321136474609375 +18368 0.3944091796875 +18369 0.3040771484375 +18370 0.3885498046875 +18371 0.289398193359375 +18372 0.362640380859375 +18373 0.26007080078125 +18374 0.27362060546875 +18375 0.185302734375 +18376 0.11712646484375 +18377 0.06243896484375 +18378 -0.054901123046875 +18379 -0.070220947265625 +18380 -0.19085693359375 +18381 -0.174713134765625 +18382 -0.28570556640625 +18383 -0.247161865234375 +18384 -0.339263916015625 +18385 -0.287322998046875 +18386 -0.3775634765625 +18387 -0.314117431640625 +18388 -0.445709228515625 +18389 -0.36053466796875 +18390 -0.535064697265625 +18391 -0.4205322265625 +18392 -0.629058837890625 +18393 -0.48236083984375 +18394 -0.697601318359375 +18395 -0.524505615234375 +18396 -0.70391845703125 +18397 -0.520660400390625 +18398 -0.6424560546875 +18399 -0.467254638671875 +18400 -0.491241455078125 +18401 -0.348785400390625 +18402 -0.265716552734375 +18403 -0.176910400390625 +18404 -0.023712158203125 +18405 0.00579833984375 +18406 0.201751708984375 +18407 0.17498779296875 +18408 0.375823974609375 +18409 0.305084228515625 +18410 0.485076904296875 +18411 0.386199951171875 +18412 0.56884765625 +18413 0.4468994140625 +18414 0.634765625 +18415 0.492828369140625 +18416 0.63763427734375 +18417 0.49127197265625 +18418 0.5660400390625 +18419 0.434112548828125 +18420 0.4720458984375 +18421 0.35955810546875 +18422 0.40692138671875 +18423 0.305328369140625 +18424 0.3778076171875 +18425 0.277008056640625 +18426 0.376953125 +18427 0.26934814453125 +18428 0.371978759765625 +18429 0.2591552734375 +18430 0.313140869140625 +18431 0.2105712890625 +18432 0.184417724609375 +18433 0.112457275390625 +18434 0.011199951171875 +18435 -0.016204833984375 +18436 -0.171051025390625 +18437 -0.14971923828125 +18438 -0.33740234375 +18439 -0.2703857421875 +18440 -0.47198486328125 +18441 -0.36688232421875 +18442 -0.560394287109375 +18443 -0.429046630859375 +18444 -0.58056640625 +18445 -0.441558837890625 +18446 -0.54754638671875 +18447 -0.415008544921875 +18448 -0.508575439453125 +18449 -0.382537841796875 +18450 -0.459503173828125 +18451 -0.34161376953125 +18452 -0.394378662109375 +18453 -0.288482666015625 +18454 -0.35260009765625 +18455 -0.25103759765625 +18456 -0.31170654296875 +18457 -0.214080810546875 +18458 -0.197418212890625 +18459 -0.12640380859375 +18460 -0.007965087890625 +18461 0.012786865234375 +18462 0.207489013671875 +18463 0.16888427734375 +18464 0.409210205078125 +18465 0.31390380859375 +18466 0.57208251953125 +18467 0.430145263671875 +18468 0.66595458984375 +18469 0.496551513671875 +18470 0.65875244140625 +18471 0.490753173828125 +18472 0.56744384765625 +18473 0.4246826171875 +18474 0.431396484375 +18475 0.325897216796875 +18476 0.29443359375 +18477 0.2252197265625 +18478 0.182464599609375 +18479 0.140960693359375 +18480 0.06365966796875 +18481 0.0513916015625 +18482 -0.075958251953125 +18483 -0.0528564453125 +18484 -0.189422607421875 +18485 -0.138671875 +18486 -0.271942138671875 +18487 -0.202362060546875 +18488 -0.342529296875 +18489 -0.2568359375 +18490 -0.364166259765625 +18491 -0.276092529296875 +18492 -0.327239990234375 +18493 -0.25323486328125 +18494 -0.2769775390625 +18495 -0.219635009765625 +18496 -0.253692626953125 +18497 -0.20330810546875 +18498 -0.24365234375 +18499 -0.194732666015625 +18500 -0.1983642578125 +18501 -0.160308837890625 +18502 -0.116241455078125 +18503 -0.09912109375 +18504 -0.036834716796875 +18505 -0.038909912109375 +18506 0.034881591796875 +18507 0.01654052734375 +18508 0.09124755859375 +18509 0.06158447265625 +18510 0.10888671875 +18511 0.079620361328125 +18512 0.125518798828125 +18513 0.0965576171875 +18514 0.15771484375 +18515 0.1236572265625 +18516 0.17828369140625 +18517 0.14178466796875 +18518 0.17108154296875 +18519 0.139495849609375 +18520 0.129974365234375 +18521 0.1124267578125 +18522 0.082427978515625 +18523 0.079620361328125 +18524 0.027679443359375 +18525 0.04058837890625 +18526 -0.065643310546875 +18527 -0.026397705078125 +18528 -0.15936279296875 +18529 -0.0946044921875 +18530 -0.21307373046875 +18531 -0.135772705078125 +18532 -0.234649658203125 +18533 -0.1551513671875 +18534 -0.2001953125 +18535 -0.135833740234375 +18536 -0.119171142578125 +18537 -0.08416748046875 +18538 -0.024749755859375 +18539 -0.02294921875 +18540 0.085784912109375 +18541 0.0499267578125 +18542 0.178131103515625 +18543 0.11077880859375 +18544 0.215576171875 +18545 0.134246826171875 +18546 0.211456298828125 +18547 0.12969970703125 +18548 0.17523193359375 +18549 0.10382080078125 +18550 0.128753662109375 +18551 0.071807861328125 +18552 0.1019287109375 +18553 0.054443359375 +18554 0.0743408203125 +18555 0.037445068359375 +18556 0.04327392578125 +18557 0.01873779296875 +18558 0.038177490234375 +18559 0.018646240234375 +18560 0.076263427734375 +18561 0.048919677734375 +18562 0.14105224609375 +18563 0.097869873046875 +18564 0.186431884765625 +18565 0.13323974609375 +18566 0.188812255859375 +18567 0.13836669921875 +18568 0.1390380859375 +18569 0.106689453125 +18570 0.041778564453125 +18571 0.041351318359375 +18572 -0.079437255859375 +18573 -0.0413818359375 +18574 -0.219390869140625 +18575 -0.137969970703125 +18576 -0.367828369140625 +18577 -0.24127197265625 +18578 -0.494873046875 +18579 -0.330474853515625 +18580 -0.556243896484375 +18581 -0.374725341796875 +18582 -0.508697509765625 +18583 -0.343780517578125 +18584 -0.3756103515625 +18585 -0.2537841796875 +18586 -0.218902587890625 +18587 -0.147705078125 +18588 -0.063751220703125 +18589 -0.0428466796875 +18590 0.091552734375 +18591 0.062103271484375 +18592 0.23602294921875 +18593 0.15966796875 +18594 0.342987060546875 +18595 0.2314453125 +18596 0.39520263671875 +18597 0.265625 +18598 0.389373779296875 +18599 0.259979248046875 +18600 0.324249267578125 +18601 0.213714599609375 +18602 0.224090576171875 +18603 0.14373779296875 +18604 0.124267578125 +18605 0.074676513671875 +18606 0.037078857421875 +18607 0.0150146484375 +18608 -0.010101318359375 +18609 -0.016204833984375 +18610 -0.019439697265625 +18611 -0.0206298828125 +18612 -0.022796630859375 +18613 -0.02056884765625 +18614 -0.001556396484375 +18615 -0.003204345703125 +18616 0.056304931640625 +18617 0.0396728515625 +18618 0.106719970703125 +18619 0.0772705078125 +18620 0.096893310546875 +18621 0.07269287109375 +18622 0.042694091796875 +18623 0.036895751953125 +18624 -0.018035888671875 +18625 -0.003875732421875 +18626 -0.07586669921875 +18627 -0.04315185546875 +18628 -0.11944580078125 +18629 -0.07305908203125 +18630 -0.15972900390625 +18631 -0.101226806640625 +18632 -0.202606201171875 +18633 -0.1317138671875 +18634 -0.24859619140625 +18635 -0.164825439453125 +18636 -0.30517578125 +18637 -0.2056884765625 +18638 -0.36212158203125 +18639 -0.24713134765625 +18640 -0.39141845703125 +18641 -0.269561767578125 +18642 -0.35528564453125 +18643 -0.246551513671875 +18644 -0.249969482421875 +18645 -0.175384521484375 +18646 -0.092864990234375 +18647 -0.06805419921875 +18648 0.08905029296875 +18649 0.056793212890625 +18650 0.2352294921875 +18651 0.1571044921875 +18652 0.318817138671875 +18653 0.214263916015625 +18654 0.358642578125 +18655 0.24139404296875 +18656 0.347747802734375 +18657 0.233673095703125 +18658 0.28564453125 +18659 0.190765380859375 +18660 0.223175048828125 +18661 0.148040771484375 +18662 0.196746826171875 +18663 0.13079833984375 +18664 0.179840087890625 +18665 0.1204833984375 +18666 0.155548095703125 +18667 0.105255126953125 +18668 0.151214599609375 +18669 0.104034423828125 +18670 0.156951904296875 +18671 0.10986328125 +18672 0.13177490234375 +18673 0.094085693359375 +18674 0.100799560546875 +18675 0.0740966796875 +18676 0.087127685546875 +18677 0.06585693359375 +18678 0.05487060546875 +18679 0.04437255859375 +18680 -0.009002685546875 +18681 0.000518798828125 +18682 -0.10400390625 +18683 -0.06536865234375 +18684 -0.229400634765625 +18685 -0.15283203125 +18686 -0.35552978515625 +18687 -0.24114990234375 +18688 -0.441925048828125 +18689 -0.301910400390625 +18690 -0.473846435546875 +18691 -0.32452392578125 +18692 -0.464813232421875 +18693 -0.318206787109375 +18694 -0.419097900390625 +18695 -0.286285400390625 +18696 -0.334320068359375 +18697 -0.227691650390625 +18698 -0.227935791015625 +18699 -0.154388427734375 +18700 -0.12347412109375 +18701 -0.082366943359375 +18702 -0.02764892578125 +18703 -0.01629638671875 +18704 0.077667236328125 +18705 0.055694580078125 +18706 0.2132568359375 +18707 0.14727783203125 +18708 0.38885498046875 +18709 0.264801025390625 +18710 0.582794189453125 +18711 0.3939208984375 +18712 0.734039306640625 +18713 0.494110107421875 +18714 0.800140380859375 +18715 0.537261962890625 +18716 0.7783203125 +18717 0.5216064453125 +18718 0.6651611328125 +18719 0.444976806640625 +18720 0.45965576171875 +18721 0.30682373046875 +18722 0.199188232421875 +18723 0.13214111328125 +18724 -0.050689697265625 +18725 -0.035430908203125 +18726 -0.23297119140625 +18727 -0.157958984375 +18728 -0.33013916015625 +18729 -0.2237548828125 +18730 -0.368408203125 +18731 -0.2501220703125 +18732 -0.378936767578125 +18733 -0.2576904296875 +18734 -0.376983642578125 +18735 -0.256591796875 +18736 -0.37969970703125 +18737 -0.25823974609375 +18738 -0.391510009765625 +18739 -0.265594482421875 +18740 -0.385345458984375 +18741 -0.260711669921875 +18742 -0.3419189453125 +18743 -0.2308349609375 +18744 -0.28289794921875 +18745 -0.1904296875 +18746 -0.251617431640625 +18747 -0.168304443359375 +18748 -0.266143798828125 +18749 -0.176544189453125 +18750 -0.273345947265625 +18751 -0.179962158203125 +18752 -0.216796875 +18753 -0.14117431640625 +18754 -0.128265380859375 +18755 -0.081298828125 +18756 -0.068145751953125 +18757 -0.04052734375 +18758 -0.0430908203125 +18759 -0.0233154296875 +18760 -0.024444580078125 +18761 -0.010650634765625 +18762 0.020721435546875 +18763 0.019317626953125 +18764 0.124481201171875 +18765 0.087890625 +18766 0.25787353515625 +18767 0.175872802734375 +18768 0.379119873046875 +18769 0.25555419921875 +18770 0.47991943359375 +18771 0.32147216796875 +18772 0.5281982421875 +18773 0.352386474609375 +18774 0.511138916015625 +18775 0.339874267578125 +18776 0.456207275390625 +18777 0.302215576171875 +18778 0.407470703125 +18779 0.26873779296875 +18780 0.383758544921875 +18781 0.25201416015625 +18782 0.35687255859375 +18783 0.233367919921875 +18784 0.31182861328125 +18785 0.202880859375 +18786 0.250885009765625 +18787 0.16204833984375 +18788 0.1654052734375 +18789 0.10516357421875 +18790 0.035247802734375 +18791 0.01885986328125 +18792 -0.142059326171875 +18793 -0.0985107421875 +18794 -0.33563232421875 +18795 -0.2264404296875 +18796 -0.5345458984375 +18797 -0.357696533203125 +18798 -0.72186279296875 +18799 -0.481109619140625 +18800 -0.836669921875 +18801 -0.5562744140625 +18802 -0.8326416015625 +18803 -0.552520751953125 +18804 -0.7296142578125 +18805 -0.483062744140625 +18806 -0.582550048828125 +18807 -0.38446044921875 +18808 -0.440093994140625 +18809 -0.2890625 +18810 -0.324310302734375 +18811 -0.2115478515625 +18812 -0.20147705078125 +18813 -0.12957763671875 +18814 -0.044647216796875 +18815 -0.025238037109375 +18816 0.103973388671875 +18817 0.07342529296875 +18818 0.202392578125 +18819 0.13848876953125 +18820 0.264495849609375 +18821 0.179229736328125 +18822 0.338897705078125 +18823 0.22796630859375 +18824 0.443817138671875 +18825 0.29681396484375 +18826 0.545074462890625 +18827 0.363128662109375 +18828 0.6173095703125 +18829 0.410125732421875 +18830 0.6524658203125 +18831 0.432525634765625 +18832 0.66339111328125 +18833 0.43890380859375 +18834 0.6561279296875 +18835 0.433319091796875 +18836 0.606781005859375 +18837 0.399932861328125 +18838 0.501190185546875 +18839 0.329376220703125 +18840 0.352783203125 +18841 0.2305908203125 +18842 0.176544189453125 +18843 0.113525390625 +18844 -0.034820556640625 +18845 -0.026641845703125 +18846 -0.258209228515625 +18847 -0.174591064453125 +18848 -0.44244384765625 +18849 -0.296356201171875 +18850 -0.5753173828125 +18851 -0.383880615234375 +18852 -0.65203857421875 +18853 -0.43402099609375 +18854 -0.641632080078125 +18855 -0.42626953125 +18856 -0.562164306640625 +18857 -0.3726806640625 +18858 -0.458038330078125 +18859 -0.30279541015625 +18860 -0.350555419921875 +18861 -0.230743408203125 +18862 -0.260528564453125 +18863 -0.17041015625 +18864 -0.192108154296875 +18865 -0.12457275390625 +18866 -0.141937255859375 +18867 -0.091033935546875 +18868 -0.1021728515625 +18869 -0.0645751953125 +18870 -0.062896728515625 +18871 -0.038604736328125 +18872 -0.011932373046875 +18873 -0.005035400390625 +18874 0.062835693359375 +18875 0.044189453125 +18876 0.148712158203125 +18877 0.100677490234375 +18878 0.241729736328125 +18879 0.16180419921875 +18880 0.34912109375 +18881 0.232421875 +18882 0.457305908203125 +18883 0.303558349609375 +18884 0.54388427734375 +18885 0.360382080078125 +18886 0.5728759765625 +18887 0.379058837890625 +18888 0.506591796875 +18889 0.334564208984375 +18890 0.351226806640625 +18891 0.231048583984375 +18892 0.146514892578125 +18893 0.094879150390625 +18894 -0.05523681640625 +18895 -0.039154052734375 +18896 -0.21624755859375 +18897 -0.14599609375 +18898 -0.334930419921875 +18899 -0.224578857421875 +18900 -0.402984619140625 +18901 -0.269439697265625 +18902 -0.4412841796875 +18903 -0.29443359375 +18904 -0.49578857421875 +18905 -0.330108642578125 +18906 -0.5601806640625 +18907 -0.372314453125 +18908 -0.600738525390625 +18909 -0.398681640625 +18910 -0.584228515625 +18911 -0.38714599609375 +18912 -0.47930908203125 +18913 -0.31695556640625 +18914 -0.27935791015625 +18915 -0.183746337890625 +18916 -0.0089111328125 +18917 -0.003814697265625 +18918 0.268798828125 +18919 0.1807861328125 +18920 0.482818603515625 +18921 0.322967529296875 +18922 0.60369873046875 +18923 0.403167724609375 +18924 0.650421142578125 +18925 0.433990478515625 +18926 0.66400146484375 +18927 0.442718505859375 +18928 0.6414794921875 +18929 0.427398681640625 +18930 0.572540283203125 +18931 0.381195068359375 +18932 0.498138427734375 +18933 0.331329345703125 +18934 0.439453125 +18935 0.291900634765625 +18936 0.375518798828125 +18937 0.248992919921875 +18938 0.274505615234375 +18939 0.181488037109375 +18940 0.1087646484375 +18941 0.071044921875 +18942 -0.099395751953125 +18943 -0.0675048828125 +18944 -0.3182373046875 +18945 -0.2125244140625 +18946 -0.5489501953125 +18947 -0.364013671875 +18948 -0.7738037109375 +18949 -0.5103759765625 +18950 -0.86383056640625 +18951 -0.61798095703125 +18952 -0.870391845703125 +18953 -0.665740966796875 +18954 -0.86895751953125 +18955 -0.664886474609375 +18956 -0.861053466796875 +18957 -0.62384033203125 +18958 -0.765869140625 +18959 -0.5318603515625 +18960 -0.5301513671875 +18961 -0.382110595703125 +18962 -0.214691162109375 +18963 -0.17938232421875 +18964 0.137359619140625 +18965 0.04876708984375 +18966 0.474822998046875 +18967 0.26959228515625 +18968 0.76239013671875 +18969 0.4603271484375 +18970 0.867462158203125 +18971 0.603607177734375 +18972 0.870361328125 +18973 0.699462890625 +18974 0.86480712890625 +18975 0.74041748046875 +18976 0.831817626953125 +18977 0.729705810546875 +18978 0.677581787109375 +18979 0.682647705078125 +18980 0.495880126953125 +18981 0.602874755859375 +18982 0.30767822265625 +18983 0.502197265625 +18984 0.116180419921875 +18985 0.38214111328125 +18986 -0.110748291015625 +18987 0.22283935546875 +18988 -0.381805419921875 +18989 0.020111083984375 +18990 -0.6572265625 +18991 -0.198699951171875 +18992 -0.857421875 +18993 -0.3955078125 +18994 -0.870391845703125 +18995 -0.542877197265625 +18996 -0.870391845703125 +18997 -0.636077880859375 +18998 -0.86444091796875 +18999 -0.69189453125 +19000 -0.85723876953125 +19001 -0.732696533203125 +19002 -0.790008544921875 +19003 -0.746734619140625 +19004 -0.62847900390625 +19005 -0.69964599609375 +19006 -0.3956298828125 +19007 -0.58941650390625 +19008 -0.126708984375 +19009 -0.43682861328125 +19010 0.150115966796875 +19011 -0.25927734375 +19012 0.424041748046875 +19013 -0.064300537109375 +19014 0.670623779296875 +19015 0.130859375 +19016 0.854522705078125 +19017 0.301544189453125 +19018 0.866485595703125 +19019 0.43634033203125 +19020 0.86920166015625 +19021 0.525299072265625 +19022 0.8653564453125 +19023 0.57965087890625 +19024 0.857147216796875 +19025 0.607666015625 +19026 0.766845703125 +19027 0.607330322265625 +19028 0.628509521484375 +19029 0.581756591796875 +19030 0.462127685546875 +19031 0.526611328125 +19032 0.297210693359375 +19033 0.458160400390625 +19034 0.14862060546875 +19035 0.384246826171875 +19036 -0.00537109375 +19037 0.290496826171875 +19038 -0.15753173828125 +19039 0.1817626953125 +19040 -0.31304931640625 +19041 0.055908203125 +19042 -0.48876953125 +19043 -0.095733642578125 +19044 -0.6416015625 +19045 -0.24334716796875 +19046 -0.751373291015625 +19047 -0.371124267578125 +19048 -0.84619140625 +19049 -0.493438720703125 +19050 -0.861297607421875 +19051 -0.60076904296875 +19052 -0.863250732421875 +19053 -0.672027587890625 +19054 -0.856597900390625 +19055 -0.687103271484375 +19056 -0.7498779296875 +19057 -0.653594970703125 +19058 -0.624542236328125 +19059 -0.6080322265625 +19060 -0.47808837890625 +19061 -0.5364990234375 +19062 -0.253387451171875 +19063 -0.402130126953125 +19064 0.003692626953125 +19065 -0.233856201171875 +19066 0.2257080078125 +19067 -0.07501220703125 +19068 0.427154541015625 +19069 0.082183837890625 +19070 0.643218994140625 +19071 0.25799560546875 +19072 0.855926513671875 +19073 0.446136474609375 +19074 0.870361328125 +19075 0.609771728515625 +19076 0.870361328125 +19077 0.717376708984375 +19078 0.862762451171875 +19079 0.7733154296875 +19080 0.79669189453125 +19081 0.775604248046875 +19082 0.595794677734375 +19083 0.718170166015625 +19084 0.362152099609375 +19085 0.61944580078125 +19086 0.1270751953125 +19087 0.49713134765625 +19088 -0.086944580078125 +19089 0.364654541015625 +19090 -0.2784423828125 +19091 0.223419189453125 +19092 -0.484832763671875 +19093 0.05157470703125 +19094 -0.729583740234375 +19095 -0.162841796875 +19096 -0.86688232421875 +19097 -0.38763427734375 +19098 -0.870391845703125 +19099 -0.582611083984375 +19100 -0.86859130859375 +19101 -0.744415283203125 +19102 -0.86279296875 +19103 -0.856353759765625 +19104 -0.817962646484375 +19105 -0.86395263671875 +19106 -0.6116943359375 +19107 -0.862091064453125 +19108 -0.3128662109375 +19109 -0.816009521484375 +19110 0.039398193359375 +19111 -0.638153076171875 +19112 0.422821044921875 +19113 -0.40313720703125 +19114 0.805145263671875 +19115 -0.132049560546875 +19116 0.870361328125 +19117 0.131927490234375 +19118 0.870361328125 +19119 0.35260009765625 +19120 0.860015869140625 +19121 0.522308349609375 +19122 0.727935791015625 +19123 0.63592529296875 +19124 0.48114013671875 +19125 0.689544677734375 +19126 0.2059326171875 +19127 0.698150634765625 +19128 -0.06103515625 +19129 0.675750732421875 +19130 -0.29913330078125 +19131 0.628448486328125 +19132 -0.516204833984375 +19133 0.546875 +19134 -0.7252197265625 +19135 0.42120361328125 +19136 -0.85980224609375 +19137 0.267181396484375 +19138 -0.870391845703125 +19139 0.106597900390625 +19140 -0.870391845703125 +19141 -0.0416259765625 +19142 -0.858062744140625 +19143 -0.14642333984375 +19144 -0.673004150390625 +19145 -0.204742431640625 +19146 -0.42694091796875 +19147 -0.24932861328125 +19148 -0.2100830078125 +19149 -0.307769775390625 +19150 -0.0362548828125 +19151 -0.37823486328125 +19152 0.10943603515625 +19153 -0.441925048828125 +19154 0.23516845703125 +19155 -0.48583984375 +19156 0.373687744140625 +19157 -0.4835205078125 +19158 0.517791748046875 +19159 -0.435943603515625 +19160 0.602783203125 +19161 -0.382843017578125 +19162 0.635711669921875 +19163 -0.320953369140625 +19164 0.655181884765625 +19165 -0.22930908203125 +19166 0.65948486328125 +19167 -0.114410400390625 +19168 0.651275634765625 +19169 0.018280029296875 +19170 0.61846923828125 +19171 0.15289306640625 +19172 0.53753662109375 +19173 0.26556396484375 +19174 0.404144287109375 +19175 0.34442138671875 +19176 0.22186279296875 +19177 0.382843017578125 +19178 0.003997802734375 +19179 0.381134033203125 +19180 -0.22100830078125 +19181 0.350341796875 +19182 -0.42449951171875 +19183 0.30322265625 +19184 -0.579833984375 +19185 0.2530517578125 +19186 -0.641876220703125 +19187 0.2266845703125 +19188 -0.6177978515625 +19189 0.21990966796875 +19190 -0.575531005859375 +19191 0.191986083984375 +19192 -0.526336669921875 +19193 0.139678955078125 +19194 -0.42645263671875 +19195 0.096038818359375 +19196 -0.2581787109375 +19197 0.0787353515625 +19198 -0.068695068359375 +19199 0.065185546875 +19200 0.09222412109375 +19201 0.031005859375 +19202 0.232147216796875 +19203 -0.01214599609375 +19204 0.3509521484375 +19205 -0.056854248046875 +19206 0.410064697265625 +19207 -0.11993408203125 +19208 0.372955322265625 +19209 -0.21820068359375 +19210 0.2554931640625 +19211 -0.33843994140625 +19212 0.10711669921875 +19213 -0.44891357421875 +19214 -0.052886962890625 +19215 -0.53765869140625 +19216 -0.186279296875 +19217 -0.5828857421875 +19218 -0.23291015625 +19219 -0.55120849609375 +19220 -0.209442138671875 +19221 -0.45660400390625 +19222 -0.174163818359375 +19223 -0.339019775390625 +19224 -0.126739501953125 +19225 -0.2039794921875 +19226 -0.048126220703125 +19227 -0.04620361328125 +19228 0.0426025390625 +19229 0.116668701171875 +19230 0.10748291015625 +19231 0.2559814453125 +19232 0.1409912109375 +19233 0.3631591796875 +19234 0.19708251953125 +19235 0.466217041015625 +19236 0.273651123046875 +19237 0.560638427734375 +19238 0.31768798828125 +19239 0.612518310546875 +19240 0.341094970703125 +19241 0.6282958984375 +19242 0.368011474609375 +19243 0.623046875 +19244 0.37249755859375 +19245 0.5830078125 +19246 0.30072021484375 +19247 0.478851318359375 +19248 0.1517333984375 +19249 0.3138427734375 +19250 -0.01470947265625 +19251 0.128326416015625 +19252 -0.1883544921875 +19253 -0.066497802734375 +19254 -0.372711181640625 +19255 -0.267669677734375 +19256 -0.51397705078125 +19257 -0.437957763671875 +19258 -0.57177734375 +19259 -0.54864501953125 +19260 -0.53948974609375 +19261 -0.591888427734375 +19262 -0.43511962890625 +19263 -0.575469970703125 +19264 -0.2962646484375 +19265 -0.5198974609375 +19266 -0.161102294921875 +19267 -0.44708251953125 +19268 -0.0435791015625 +19269 -0.365478515625 +19270 0.060394287109375 +19271 -0.2738037109375 +19272 0.13665771484375 +19273 -0.182647705078125 +19274 0.170135498046875 +19275 -0.10400390625 +19276 0.16552734375 +19277 -0.03863525390625 +19278 0.15728759765625 +19279 0.03009033203125 +19280 0.150787353515625 +19281 0.101287841796875 +19282 0.12200927734375 +19283 0.1563720703125 +19284 0.080108642578125 +19285 0.19696044921875 +19286 0.05126953125 +19287 0.235382080078125 +19288 0.062896728515625 +19289 0.28533935546875 +19290 0.09271240234375 +19291 0.33148193359375 +19292 0.092987060546875 +19293 0.34405517578125 +19294 0.07855224609375 +19295 0.33172607421875 +19296 0.06427001953125 +19297 0.304107666015625 +19298 0.0347900390625 +19299 0.253448486328125 +19300 -0.01171875 +19301 0.180816650390625 +19302 -0.056060791015625 +19303 0.100494384765625 +19304 -0.055511474609375 +19305 0.04132080078125 +19306 -0.010467529296875 +19307 0.0064697265625 +19308 0.02508544921875 +19309 -0.032958984375 +19310 0.025665283203125 +19311 -0.088958740234375 +19312 0.017333984375 +19313 -0.1429443359375 +19314 0.00189208984375 +19315 -0.19140625 +19316 -0.03173828125 +19317 -0.2391357421875 +19318 -0.071502685546875 +19319 -0.27777099609375 +19320 -0.13543701171875 +19321 -0.31768798828125 +19322 -0.219970703125 +19323 -0.357025146484375 +19324 -0.300506591796875 +19325 -0.381988525390625 +19326 -0.376312255859375 +19327 -0.393768310546875 +19328 -0.416107177734375 +19329 -0.375701904296875 +19330 -0.371124267578125 +19331 -0.30108642578125 +19332 -0.242279052734375 +19333 -0.1732177734375 +19334 -0.069732666015625 +19335 -0.01904296875 +19336 0.125640869140625 +19337 0.1461181640625 +19338 0.31268310546875 +19339 0.301025390625 +19340 0.45501708984375 +19341 0.42169189453125 +19342 0.554779052734375 +19343 0.5076904296875 +19344 0.61065673828125 +19345 0.55706787109375 +19346 0.610931396484375 +19347 0.562225341796875 +19348 0.531463623046875 +19349 0.50872802734375 +19350 0.3883056640625 +19351 0.4068603515625 +19352 0.23468017578125 +19353 0.289703369140625 +19354 0.095245361328125 +19355 0.1737060546875 +19356 -0.00396728515625 +19357 0.076416015625 +19358 -0.04852294921875 +19359 0.0086669921875 +19360 -0.055145263671875 +19361 -0.03717041015625 +19362 -0.0758056640625 +19363 -0.09002685546875 +19364 -0.138702392578125 +19365 -0.164642333984375 +19366 -0.209197998046875 +19367 -0.23828125 +19368 -0.289031982421875 +19369 -0.310455322265625 +19370 -0.37884521484375 +19371 -0.380462646484375 +19372 -0.456329345703125 +19373 -0.434234619140625 +19374 -0.51641845703125 +19375 -0.468597412109375 +19376 -0.519287109375 +19377 -0.46002197265625 +19378 -0.458251953125 +19379 -0.405303955078125 +19380 -0.384796142578125 +19381 -0.3365478515625 +19382 -0.323699951171875 +19383 -0.2701416015625 +19384 -0.269287109375 +19385 -0.20440673828125 +19386 -0.1951904296875 +19387 -0.12548828125 +19388 -0.100006103515625 +19389 -0.034423828125 +19390 -0.01055908203125 +19391 0.05084228515625 +19392 0.1033935546875 +19393 0.146759033203125 +19394 0.24908447265625 +19395 0.256317138671875 +19396 0.373199462890625 +19397 0.346466064453125 +19398 0.45806884765625 +19399 0.405914306640625 +19400 0.511474609375 +19401 0.4390869140625 +19402 0.565399169921875 +19403 0.46533203125 +19404 0.61138916015625 +19405 0.4801025390625 +19406 0.5897216796875 +19407 0.448455810546875 +19408 0.4906005859375 +19409 0.36572265625 +19410 0.33148193359375 +19411 0.2437744140625 +19412 0.147796630859375 +19413 0.105377197265625 +19414 -0.01873779296875 +19415 -0.0228271484375 +19416 -0.140289306640625 +19417 -0.12255859375 +19418 -0.191986083984375 +19419 -0.177490234375 +19420 -0.184295654296875 +19421 -0.19268798828125 +19422 -0.161834716796875 +19423 -0.1939697265625 +19424 -0.166595458984375 +19425 -0.20587158203125 +19426 -0.19390869140625 +19427 -0.225250244140625 +19428 -0.22442626953125 +19429 -0.240509033203125 +19430 -0.279754638671875 +19431 -0.26495361328125 +19432 -0.3389892578125 +19433 -0.28668212890625 +19434 -0.3543701171875 +19435 -0.2779541015625 +19436 -0.348175048828125 +19437 -0.25323486328125 +19438 -0.32598876953125 +19439 -0.217071533203125 +19440 -0.2581787109375 +19441 -0.15301513671875 +19442 -0.139801025390625 +19443 -0.05938720703125 +19444 0.014617919921875 +19445 0.05389404296875 +19446 0.144378662109375 +19447 0.1492919921875 +19448 0.221038818359375 +19449 0.208892822265625 +19450 0.27069091796875 +19451 0.24774169921875 +19452 0.294036865234375 +19453 0.26593017578125 +19454 0.311767578125 +19455 0.2757568359375 +19456 0.339141845703125 +19457 0.286468505859375 +19458 0.360260009765625 +19459 0.288543701171875 +19460 0.360504150390625 +19461 0.2740478515625 +19462 0.308380126953125 +19463 0.226165771484375 +19464 0.18170166015625 +19465 0.13348388671875 +19466 0.0047607421875 +19467 0.011138916015625 +19468 -0.17559814453125 +19469 -0.11297607421875 +19470 -0.3143310546875 +19471 -0.21209716796875 +19472 -0.36785888671875 +19473 -0.2603759765625 +19474 -0.36248779296875 +19475 -0.271820068359375 +19476 -0.343536376953125 +19477 -0.271453857421875 +19478 -0.3018798828125 +19479 -0.253692626953125 +19480 -0.231414794921875 +19481 -0.214874267578125 +19482 -0.117645263671875 +19483 -0.14678955078125 +19484 0.007049560546875 +19485 -0.068206787109375 +19486 0.087982177734375 +19487 -0.010711669921875 +19488 0.13946533203125 +19489 0.033050537109375 +19490 0.17425537109375 +19491 0.0694580078125 +19492 0.188201904296875 +19493 0.09515380859375 +19494 0.171234130859375 +19495 0.103424072265625 +19496 0.118438720703125 +19497 0.09051513671875 +19498 0.05706787109375 +19499 0.07098388671875 +19500 -0.010711669921875 +19501 0.04522705078125 +19502 -0.0914306640625 +19503 0.008941650390625 +19504 -0.162322998046875 +19505 -0.02532958984375 +19506 -0.194549560546875 +19507 -0.04144287109375 +19508 -0.1492919921875 +19509 -0.017364501953125 +19510 -0.02166748046875 +19511 0.049835205078125 +19512 0.124053955078125 +19513 0.12408447265625 +19514 0.211151123046875 +19515 0.162353515625 +19516 0.240447998046875 +19517 0.165802001953125 +19518 0.242218017578125 +19519 0.152374267578125 +19520 0.2257080078125 +19521 0.128173828125 +19522 0.194366455078125 +19523 0.095977783203125 +19524 0.115509033203125 +19525 0.0379638671875 +19526 0.0128173828125 +19527 -0.03167724609375 +19528 -0.053802490234375 +19529 -0.078369140625 +19530 -0.110626220703125 +19531 -0.116607666015625 +19532 -0.199493408203125 +19533 -0.169921875 +19534 -0.29437255859375 +19535 -0.223480224609375 +19536 -0.33221435546875 +19537 -0.2415771484375 +19538 -0.27972412109375 +19539 -0.205596923828125 +19540 -0.185333251953125 +19541 -0.143463134765625 +19542 -0.128204345703125 +19543 -0.100616455078125 +19544 -0.115692138671875 +19545 -0.081878662109375 +19546 -0.116455078125 +19547 -0.070098876953125 +19548 -0.105926513671875 +19549 -0.052001953125 +19550 -0.053955078125 +19551 -0.011138916015625 +19552 0.048797607421875 +19553 0.057159423828125 +19554 0.157318115234375 +19555 0.126861572265625 +19556 0.212005615234375 +19557 0.1636962890625 +19558 0.218475341796875 +19559 0.170623779296875 +19560 0.23724365234375 +19561 0.181915283203125 +19562 0.30535888671875 +19563 0.218658447265625 +19564 0.38128662109375 +19565 0.257415771484375 +19566 0.404449462890625 +19567 0.264068603515625 +19568 0.3944091796875 +19569 0.25018310546875 +19570 0.3885498046875 +19571 0.23748779296875 +19572 0.362640380859375 +19573 0.2127685546875 +19574 0.27362060546875 +19575 0.152130126953125 +19576 0.11712646484375 +19577 0.05364990234375 +19578 -0.054901123046875 +19579 -0.05267333984375 +19580 -0.19085693359375 +19581 -0.137054443359375 +19582 -0.28570556640625 +19583 -0.1962890625 +19584 -0.339263916015625 +19585 -0.230072021484375 +19586 -0.3775634765625 +19587 -0.2530517578125 +19588 -0.445709228515625 +19589 -0.29083251953125 +19590 -0.535064697265625 +19591 -0.338623046875 +19592 -0.629058837890625 +19593 -0.387237548828125 +19594 -0.697601318359375 +19595 -0.41986083984375 +19596 -0.70391845703125 +19597 -0.415985107421875 +19598 -0.6424560546875 +19599 -0.3729248046875 +19600 -0.491241455078125 +19601 -0.2786865234375 +19602 -0.265716552734375 +19603 -0.142486572265625 +19604 -0.023712158203125 +19605 0.00238037109375 +19606 0.201751708984375 +19607 0.136749267578125 +19608 0.375823974609375 +19609 0.240509033203125 +19610 0.485076904296875 +19611 0.30584716796875 +19612 0.56884765625 +19613 0.35498046875 +19614 0.634765625 +19615 0.392181396484375 +19616 0.63763427734375 +19617 0.391876220703125 +19618 0.5660400390625 +19619 0.34771728515625 +19620 0.4720458984375 +19621 0.28948974609375 +19622 0.40692138671875 +19623 0.246612548828125 +19624 0.3778076171875 +19625 0.2235107421875 +19626 0.376953125 +19627 0.216156005859375 +19628 0.371978759765625 +19629 0.20654296875 +19630 0.313140869140625 +19631 0.166778564453125 +19632 0.184417724609375 +19633 0.088104248046875 +19634 0.011199951171875 +19635 -0.0147705078125 +19636 -0.171051025390625 +19637 -0.121490478515625 +19638 -0.33740234375 +19639 -0.217742919921875 +19640 -0.47198486328125 +19641 -0.294464111328125 +19642 -0.560394287109375 +19643 -0.343505859375 +19644 -0.58056640625 +19645 -0.352447509765625 +19646 -0.54754638671875 +19647 -0.329986572265625 +19648 -0.508575439453125 +19649 -0.303192138671875 +19650 -0.459503173828125 +19651 -0.269989013671875 +19652 -0.394378662109375 +19653 -0.227325439453125 +19654 -0.35260009765625 +19655 -0.1978759765625 +19656 -0.31170654296875 +19657 -0.169189453125 +19658 -0.197418212890625 +19659 -0.099395751953125 +19660 -0.007965087890625 +19661 0.01226806640625 +19662 0.207489013671875 +19663 0.13763427734375 +19664 0.409210205078125 +19665 0.2540283203125 +19666 0.57208251953125 +19667 0.34710693359375 +19668 0.66595458984375 +19669 0.399749755859375 +19670 0.65875244140625 +19671 0.393829345703125 +19672 0.56744384765625 +19673 0.339111328125 +19674 0.431396484375 +19675 0.258148193359375 +19676 0.29443359375 +19677 0.176055908203125 +19678 0.182464599609375 +19679 0.107818603515625 +19680 0.06365966796875 +19681 0.035614013671875 +19682 -0.075958251953125 +19683 -0.0482177734375 +19684 -0.189422607421875 +19685 -0.116790771484375 +19686 -0.271942138671875 +19687 -0.1671142578125 +19688 -0.342529296875 +19689 -0.2098388671875 +19690 -0.364166259765625 +19691 -0.223846435546875 +19692 -0.327239990234375 +19693 -0.20361328125 +19694 -0.2769775390625 +19695 -0.174835205078125 +19696 -0.253692626953125 +19697 -0.160430908203125 +19698 -0.24365234375 +19699 -0.152679443359375 +19700 -0.1983642578125 +19701 -0.124176025390625 +19702 -0.116241455078125 +19703 -0.074188232421875 +19704 -0.036834716796875 +19705 -0.025360107421875 +19706 0.034881591796875 +19707 0.01922607421875 +19708 0.09124755859375 +19709 0.055023193359375 +19710 0.10888671875 +19711 0.06854248046875 +19712 0.125518798828125 +19713 0.08062744140625 +19714 0.15771484375 +19715 0.100433349609375 +19716 0.17828369140625 +19717 0.112884521484375 +19718 0.17108154296875 +19719 0.109405517578125 +19720 0.129974365234375 +19721 0.086822509765625 +19722 0.082427978515625 +19723 0.059967041015625 +19724 0.027679443359375 +19725 0.028564453125 +19726 -0.065643310546875 +19727 -0.0240478515625 +19728 -0.15936279296875 +19729 -0.077239990234375 +19730 -0.21307373046875 +19731 -0.109222412109375 +19732 -0.234649658203125 +19733 -0.124053955078125 +19734 -0.2001953125 +19735 -0.1087646484375 +19736 -0.119171142578125 +19737 -0.068267822265625 +19738 -0.024749755859375 +19739 -0.020233154296875 +19740 0.085784912109375 +19741 0.036895751953125 +19742 0.178131103515625 +19743 0.0848388671875 +19744 0.215576171875 +19745 0.10400390625 +19746 0.211456298828125 +19747 0.101531982421875 +19748 0.17523193359375 +19749 0.082489013671875 +19750 0.128753662109375 +19751 0.058563232421875 +19752 0.1019287109375 +19753 0.04571533203125 +19754 0.0743408203125 +19755 0.03289794921875 +19756 0.04327392578125 +19757 0.018524169921875 +19758 0.038177490234375 +19759 0.01824951171875 +19760 0.076263427734375 +19761 0.041168212890625 +19762 0.14105224609375 +19763 0.07830810546875 +19764 0.186431884765625 +19765 0.104827880859375 +19766 0.188812255859375 +19767 0.10797119140625 +19768 0.1390380859375 +19769 0.082733154296875 +19770 0.041778564453125 +19771 0.03155517578125 +19772 -0.079437255859375 +19773 -0.032958984375 +19774 -0.219390869140625 +19775 -0.108062744140625 +19776 -0.367828369140625 +19777 -0.188201904296875 +19778 -0.494873046875 +19779 -0.25732421875 +19780 -0.556243896484375 +19781 -0.2916259765625 +19782 -0.508697509765625 +19783 -0.26788330078125 +19784 -0.3756103515625 +19785 -0.198486328125 +19786 -0.218902587890625 +19787 -0.11651611328125 +19788 -0.063751220703125 +19789 -0.035369873046875 +19790 0.091552734375 +19791 0.04595947265625 +19792 0.23602294921875 +19793 0.1217041015625 +19794 0.342987060546875 +19795 0.177642822265625 +19796 0.39520263671875 +19797 0.204620361328125 +19798 0.389373779296875 +19799 0.200927734375 +19800 0.324249267578125 +19801 0.1658935546875 +19802 0.224090576171875 +19803 0.112518310546875 +19804 0.124267578125 +19805 0.059722900390625 +19806 0.037078857421875 +19807 0.014068603515625 +19808 -0.010101318359375 +19809 -0.00982666015625 +19810 -0.019439697265625 +19811 -0.01324462890625 +19812 -0.022796630859375 +19813 -0.013336181640625 +19814 -0.001556396484375 +19815 -0.000213623046875 +19816 0.056304931640625 +19817 0.032440185546875 +19818 0.106719970703125 +19819 0.0609130859375 +19820 0.096893310546875 +19821 0.056854248046875 +19822 0.042694091796875 +19823 0.028717041015625 +19824 -0.018035888671875 +19825 -0.003265380859375 +19826 -0.07586669921875 +19827 -0.034027099609375 +19828 -0.11944580078125 +19829 -0.057525634765625 +19830 -0.15972900390625 +19831 -0.079620361328125 +19832 -0.202606201171875 +19833 -0.103424072265625 +19834 -0.24859619140625 +19835 -0.129119873046875 +19836 -0.30517578125 +19837 -0.160614013671875 +19838 -0.36212158203125 +19839 -0.192413330078125 +19840 -0.39141845703125 +19841 -0.209442138671875 +19842 -0.35528564453125 +19843 -0.191375732421875 +19844 -0.249969482421875 +19845 -0.136138916015625 +19846 -0.092864990234375 +19847 -0.053009033203125 +19848 0.08905029296875 +19849 0.04364013671875 +19850 0.2352294921875 +19851 0.121368408203125 +19852 0.318817138671875 +19853 0.16583251953125 +19854 0.358642578125 +19855 0.187103271484375 +19856 0.347747802734375 +19857 0.181488037109375 +19858 0.28564453125 +19859 0.148681640625 +19860 0.223175048828125 +19861 0.11590576171875 +19862 0.196746826171875 +19863 0.102630615234375 +19864 0.179840087890625 +19865 0.0946044921875 +19866 0.155548095703125 +19867 0.08270263671875 +19868 0.151214599609375 +19869 0.081512451171875 +19870 0.156951904296875 +19871 0.085662841796875 +19872 0.13177490234375 +19873 0.073089599609375 +19874 0.100799560546875 +19875 0.0572509765625 +19876 0.087127685546875 +19877 0.05047607421875 +19878 0.05487060546875 +19879 0.033538818359375 +19880 -0.009002685546875 +19881 -0.000579833984375 +19882 -0.10400390625 +19883 -0.051605224609375 +19884 -0.229400634765625 +19885 -0.119110107421875 +19886 -0.35552978515625 +19887 -0.18719482421875 +19888 -0.441925048828125 +19889 -0.234130859375 +19890 -0.473846435546875 +19891 -0.25201416015625 +19892 -0.464813232421875 +19893 -0.248016357421875 +19894 -0.419097900390625 +19895 -0.224365234375 +19896 -0.334320068359375 +19897 -0.17974853515625 +19898 -0.227935791015625 +19899 -0.12347412109375 +19900 -0.12347412109375 +19901 -0.068145751953125 +19902 -0.02764892578125 +19903 -0.017303466796875 +19904 0.077667236328125 +19905 0.038787841796875 +19906 0.2132568359375 +19907 0.11126708984375 +19908 0.38885498046875 +19909 0.205352783203125 +19910 0.582794189453125 +19911 0.3094482421875 +19912 0.734039306640625 +19913 0.39080810546875 +19914 0.800140380859375 +19915 0.426666259765625 +19916 0.7783203125 +19917 0.415496826171875 +19918 0.6651611328125 +19919 0.355438232421875 +19920 0.45965576171875 +19921 0.245941162109375 +19922 0.199188232421875 +19923 0.10699462890625 +19924 -0.050689697265625 +19925 -0.026275634765625 +19926 -0.23297119140625 +19927 -0.123382568359375 +19928 -0.33013916015625 +19929 -0.174957275390625 +19930 -0.368408203125 +19931 -0.195068359375 +19932 -0.378936767578125 +19933 -0.200439453125 +19934 -0.376983642578125 +19935 -0.19927978515625 +19936 -0.37969970703125 +19937 -0.200775146484375 +19938 -0.391510009765625 +19939 -0.207275390625 +19940 -0.385345458984375 +19941 -0.20428466796875 +19942 -0.3419189453125 +19943 -0.181427001953125 +19944 -0.28289794921875 +19945 -0.150299072265625 +19946 -0.251617431640625 +19947 -0.134063720703125 +19948 -0.266143798828125 +19949 -0.142364501953125 +19950 -0.273345947265625 +19951 -0.146728515625 +19952 -0.216796875 +19953 -0.11688232421875 +19954 -0.128265380859375 +19955 -0.069793701171875 +19956 -0.068145751953125 +19957 -0.037841796875 +19958 -0.0430908203125 +19959 -0.02459716796875 +19960 -0.024444580078125 +19961 -0.014678955078125 +19962 0.020721435546875 +19963 0.009552001953125 +19964 0.124481201171875 +19965 0.065277099609375 +19966 0.25787353515625 +19967 0.136962890625 +19968 0.379119873046875 +19969 0.201629638671875 +19970 0.47991943359375 +19971 0.255035400390625 +19972 0.5281982421875 +19973 0.28131103515625 +19974 0.511138916015625 +19975 0.2738037109375 +19976 0.456207275390625 +19977 0.246246337890625 +19978 0.407470703125 +19979 0.2208251953125 +19980 0.383758544921875 +19981 0.20709228515625 +19982 0.35687255859375 +19983 0.190948486328125 +19984 0.31182861328125 +19985 0.165008544921875 +19986 0.250885009765625 +19987 0.130615234375 +19988 0.1654052734375 +19989 0.0836181640625 +19990 0.035247802734375 +19991 0.014129638671875 +19992 -0.142059326171875 +19993 -0.078857421875 +19994 -0.33563232421875 +19995 -0.1795654296875 +19996 -0.5345458984375 +19997 -0.282318115234375 +19998 -0.72186279296875 +19999 -0.378448486328125 +20000 -0.836669921875 +20001 -0.437164306640625 +20002 -0.8326416015625 +20003 -0.435089111328125 +20004 -0.7296142578125 +20005 -0.382232666015625 +20006 -0.582550048828125 +20007 -0.306427001953125 +20008 -0.440093994140625 +20009 -0.232269287109375 +20010 -0.324310302734375 +20011 -0.171051025390625 +20012 -0.20147705078125 +20013 -0.105926513671875 +20014 -0.044647216796875 +20015 -0.02349853515625 +20016 0.103973388671875 +20017 0.05474853515625 +20018 0.202392578125 +20019 0.10748291015625 +20020 0.264495849609375 +20021 0.141510009765625 +20022 0.338897705078125 +20023 0.18121337890625 +20024 0.443817138671875 +20025 0.23565673828125 +20026 0.545074462890625 +20027 0.287567138671875 +20028 0.6173095703125 +20029 0.324127197265625 +20030 0.6524658203125 +20031 0.341278076171875 +20032 0.66339111328125 +20033 0.3455810546875 +20034 0.6561279296875 +20035 0.340118408203125 +20036 0.606781005859375 +20037 0.31298828125 +20038 0.501190185546875 +20039 0.257171630859375 +20040 0.352783203125 +20041 0.1795654296875 +20042 0.176544189453125 +20043 0.087921142578125 +20044 -0.034820556640625 +20045 -0.021270751953125 +20046 -0.258209228515625 +20047 -0.136199951171875 +20048 -0.44244384765625 +20049 -0.23095703125 +20050 -0.5753173828125 +20051 -0.29931640625 +20052 -0.65203857421875 +20053 -0.33880615234375 +20054 -0.641632080078125 +20055 -0.33380126953125 +20056 -0.562164306640625 +20057 -0.293426513671875 +20058 -0.458038330078125 +20059 -0.240081787109375 +20060 -0.350555419921875 +20061 -0.184539794921875 +20062 -0.260528564453125 +20063 -0.13739013671875 +20064 -0.192108154296875 +20065 -0.100830078125 +20066 -0.141937255859375 +20067 -0.07330322265625 +20068 -0.1021728515625 +20069 -0.05096435546875 +20070 -0.062896728515625 +20071 -0.028961181640625 +20072 -0.011932373046875 +20073 -0.00128173828125 +20074 0.062835693359375 +20075 0.0380859375 +20076 0.148712158203125 +20077 0.082672119140625 +20078 0.241729736328125 +20079 0.130401611328125 +20080 0.34912109375 +20081 0.18487548828125 +20082 0.457305908203125 +20083 0.2392578125 +20084 0.54388427734375 +20085 0.282257080078125 +20086 0.5728759765625 +20087 0.295806884765625 +20088 0.506591796875 +20089 0.260986328125 +20090 0.351226806640625 +20091 0.1810302734375 +20092 0.146514892578125 +20093 0.076019287109375 +20094 -0.05523681640625 +20095 -0.02752685546875 +20096 -0.21624755859375 +20097 -0.110504150390625 +20098 -0.334930419921875 +20099 -0.1719970703125 +20100 -0.402984619140625 +20101 -0.207733154296875 +20102 -0.4412841796875 +20103 -0.2281494140625 +20104 -0.49578857421875 +20105 -0.256378173828125 +20106 -0.5601806640625 +20107 -0.2891845703125 +20108 -0.600738525390625 +20109 -0.3095703125 +20110 -0.584228515625 +20111 -0.300811767578125 +20112 -0.47930908203125 +20113 -0.24713134765625 +20114 -0.27935791015625 +20115 -0.145263671875 +20116 -0.0089111328125 +20117 -0.00762939453125 +20118 0.268798828125 +20119 0.1337890625 +20120 0.482818603515625 +20121 0.243133544921875 +20122 0.60369873046875 +20123 0.305511474609375 +20124 0.650421142578125 +20125 0.330413818359375 +20126 0.66400146484375 +20127 0.33843994140625 +20128 0.6414794921875 +20129 0.328033447265625 +20130 0.572540283203125 +20131 0.2939453125 +20132 0.498138427734375 +20133 0.256805419921875 +20134 0.439453125 +20135 0.227264404296875 +20136 0.375518798828125 +20137 0.19476318359375 +20138 0.274505615234375 +20139 0.14324951171875 +20140 0.1087646484375 +20141 0.058868408203125 +20142 -0.099395751953125 +20143 -0.04705810546875 +20144 -0.3182373046875 +20145 -0.158477783203125 +20146 -0.5489501953125 +20147 -0.27593994140625 +20148 -0.7738037109375 +20149 -0.390411376953125 +20150 -0.86383056640625 +20151 -0.475189208984375 +20152 -0.870391845703125 +20153 -0.513427734375 +20154 -0.86895751953125 +20155 -0.514007568359375 +20156 -0.861053466796875 +20157 -0.4835205078125 +20158 -0.765869140625 +20159 -0.4132080078125 +20160 -0.5301513671875 +20161 -0.297393798828125 +20162 -0.214691162109375 +20163 -0.1396484375 +20164 0.137359619140625 +20165 0.038299560546875 +20166 0.474822998046875 +20167 0.2105712890625 +20168 0.76239013671875 +20169 0.35919189453125 +20170 0.867462158203125 +20171 0.470489501953125 +20172 0.870361328125 +20173 0.544677734375 +20174 0.86480712890625 +20175 0.57586669921875 +20176 0.831817626953125 +20177 0.566680908203125 +20178 0.677581787109375 +20179 0.52935791015625 +20180 0.495880126953125 +20181 0.466766357421875 +20182 0.30767822265625 +20183 0.38824462890625 +20184 0.116180419921875 +20185 0.294921875 +20186 -0.110748291015625 +20187 0.1707763671875 +20188 -0.381805419921875 +20189 0.0123291015625 +20190 -0.6572265625 +20191 -0.158843994140625 +20192 -0.857421875 +20193 -0.312530517578125 +20194 -0.870391845703125 +20195 -0.42706298828125 +20196 -0.870391845703125 +20197 -0.498809814453125 +20198 -0.86444091796875 +20199 -0.541259765625 +20200 -0.85723876953125 +20201 -0.572357177734375 +20202 -0.790008544921875 +20203 -0.58282470703125 +20204 -0.62847900390625 +20205 -0.545257568359375 +20206 -0.3956298828125 +20207 -0.4580078125 +20208 -0.126708984375 +20209 -0.33758544921875 +20210 0.150115966796875 +20211 -0.19781494140625 +20212 0.424041748046875 +20213 -0.044586181640625 +20214 0.670623779296875 +20215 0.1085205078125 +20216 0.854522705078125 +20217 0.241943359375 +20218 0.866485595703125 +20219 0.34674072265625 +20220 0.86920166015625 +20221 0.415130615234375 +20222 0.8653564453125 +20223 0.456207275390625 +20224 0.857147216796875 +20225 0.4769287109375 +20226 0.766845703125 +20227 0.47552490234375 +20228 0.628509521484375 +20229 0.454193115234375 +20230 0.462127685546875 +20231 0.4097900390625 +20232 0.297210693359375 +20233 0.354644775390625 +20234 0.14862060546875 +20235 0.2947998046875 +20236 -0.00537109375 +20237 0.219818115234375 +20238 -0.15753173828125 +20239 0.133575439453125 +20240 -0.31304931640625 +20241 0.0347900390625 +20242 -0.48876953125 +20243 -0.082794189453125 +20244 -0.6416015625 +20245 -0.1966552734375 +20246 -0.751373291015625 +20247 -0.294769287109375 +20248 -0.84619140625 +20249 -0.387786865234375 +20250 -0.861297607421875 +20251 -0.468536376953125 +20252 -0.863250732421875 +20253 -0.521240234375 +20254 -0.856597900390625 +20255 -0.53094482421875 +20256 -0.7498779296875 +20257 -0.503448486328125 +20258 -0.624542236328125 +20259 -0.4661865234375 +20260 -0.47808837890625 +20261 -0.408966064453125 +20262 -0.253387451171875 +20263 -0.304473876953125 +20264 0.003692626953125 +20265 -0.174530029296875 +20266 0.2257080078125 +20267 -0.051727294921875 +20268 0.427154541015625 +20269 0.069488525390625 +20270 0.643218994140625 +20271 0.20404052734375 +20272 0.855926513671875 +20273 0.34710693359375 +20274 0.870361328125 +20275 0.4710693359375 +20276 0.870361328125 +20277 0.552276611328125 +20278 0.862762451171875 +20279 0.593963623046875 +20280 0.79669189453125 +20281 0.594696044921875 +20282 0.595794677734375 +20283 0.550018310546875 +20284 0.362152099609375 +20285 0.473785400390625 +20286 0.1270751953125 +20287 0.37939453125 +20288 -0.086944580078125 +20289 0.277069091796875 +20290 -0.2784423828125 +20291 0.16802978515625 +20292 -0.484832763671875 +20293 0.0361328125 +20294 -0.729583740234375 +20295 -0.1273193359375 +20296 -0.86688232421875 +20297 -0.298126220703125 +20298 -0.870391845703125 +20299 -0.446075439453125 +20300 -0.86859130859375 +20301 -0.568572998046875 +20302 -0.86279296875 +20303 -0.664398193359375 +20304 -0.817962646484375 +20305 -0.7164306640625 +20306 -0.6116943359375 +20307 -0.703155517578125 +20308 -0.3128662109375 +20309 -0.621185302734375 +20310 0.039398193359375 +20311 -0.486480712890625 +20312 0.422821044921875 +20313 -0.30859375 +20314 0.805145263671875 +20315 -0.103424072265625 +20316 0.870361328125 +20317 0.09661865234375 +20318 0.870361328125 +20319 0.264312744140625 +20320 0.860015869140625 +20321 0.393829345703125 +20322 0.727935791015625 +20323 0.481170654296875 +20324 0.48114013671875 +20325 0.5233154296875 +20326 0.2059326171875 +20327 0.531341552734375 +20328 -0.06103515625 +20329 0.515625 +20330 -0.29913330078125 +20331 0.480682373046875 +20332 -0.516204833984375 +20333 0.41949462890625 +20334 -0.7252197265625 +20335 0.324798583984375 +20336 -0.85980224609375 +20337 0.2083740234375 +20338 -0.870391845703125 +20339 0.08660888671875 +20340 -0.870391845703125 +20341 -0.0262451171875 +20342 -0.858062744140625 +20343 -0.10687255859375 +20344 -0.673004150390625 +20345 -0.15283203125 +20346 -0.42694091796875 +20347 -0.188446044921875 +20348 -0.2100830078125 +20349 -0.234222412109375 +20350 -0.0362548828125 +20351 -0.2886962890625 +20352 0.10943603515625 +20353 -0.33770751953125 +20354 0.23516845703125 +20355 -0.371490478515625 +20356 0.373687744140625 +20357 -0.3702392578125 +20358 0.517791748046875 +20359 -0.33465576171875 +20360 0.602783203125 +20361 -0.29443359375 +20362 0.635711669921875 +20363 -0.247222900390625 +20364 0.655181884765625 +20365 -0.17742919921875 +20366 0.65948486328125 +20367 -0.0899658203125 +20368 0.651275634765625 +20369 0.010986328125 +20370 0.61846923828125 +20371 0.113494873046875 +20372 0.53753662109375 +20373 0.199615478515625 +20374 0.404144287109375 +20375 0.260345458984375 +20376 0.22186279296875 +20377 0.290618896484375 +20378 0.003997802734375 +20379 0.290618896484375 +20380 -0.22100830078125 +20381 0.2685546875 +20382 -0.42449951171875 +20383 0.233917236328125 +20384 -0.579833984375 +20385 0.196563720703125 +20386 -0.641876220703125 +20387 0.17657470703125 +20388 -0.6177978515625 +20389 0.17083740234375 +20390 -0.575531005859375 +20391 0.148956298828125 +20392 -0.526336669921875 +20393 0.108612060546875 +20394 -0.42645263671875 +20395 0.07452392578125 +20396 -0.2581787109375 +20397 0.05999755859375 +20398 -0.068695068359375 +20399 0.048248291015625 +20400 0.09222412109375 +20401 0.02154541015625 +20402 0.232147216796875 +20403 -0.010894775390625 +20404 0.3509521484375 +20405 -0.043853759765625 +20406 0.410064697265625 +20407 -0.090972900390625 +20408 0.372955322265625 +20409 -0.165802001953125 +20410 0.2554931640625 +20411 -0.25823974609375 +20412 0.10711669921875 +20413 -0.343536376953125 +20414 -0.052886962890625 +20415 -0.412384033203125 +20416 -0.186279296875 +20417 -0.44769287109375 +20418 -0.23291015625 +20419 -0.423248291015625 +20420 -0.209442138671875 +20421 -0.349945068359375 +20422 -0.174163818359375 +20423 -0.2591552734375 +20424 -0.126739501953125 +20425 -0.15509033203125 +20426 -0.048126220703125 +20427 -0.033447265625 +20428 0.0426025390625 +20429 0.092071533203125 +20430 0.10748291015625 +20431 0.1990966796875 +20432 0.1409912109375 +20433 0.281036376953125 +20434 0.19708251953125 +20435 0.360015869140625 +20436 0.273651123046875 +20437 0.4326171875 +20438 0.31768798828125 +20439 0.4722900390625 +20440 0.341094970703125 +20441 0.484100341796875 +20442 0.368011474609375 +20443 0.47991943359375 +20444 0.37249755859375 +20445 0.448944091796875 +20446 0.30072021484375 +20447 0.3680419921875 +20448 0.1517333984375 +20449 0.239715576171875 +20450 -0.01470947265625 +20451 0.09564208984375 +20452 -0.1883544921875 +20453 -0.0555419921875 +20454 -0.372711181640625 +20455 -0.211578369140625 +20456 -0.51397705078125 +20457 -0.343353271484375 +20458 -0.57177734375 +20459 -0.4283447265625 +20460 -0.53948974609375 +20461 -0.460479736328125 +20462 -0.43511962890625 +20463 -0.446014404296875 +20464 -0.2962646484375 +20465 -0.401123046875 +20466 -0.161102294921875 +20467 -0.3431396484375 +20468 -0.0435791015625 +20469 -0.27874755859375 +20470 0.060394287109375 +20471 -0.2069091796875 +20472 0.13665771484375 +20473 -0.135955810546875 +20474 0.170135498046875 +20475 -0.075225830078125 +20476 0.16552734375 +20477 -0.025238037109375 +20478 0.15728759765625 +20479 0.02716064453125 +20480 0.150787353515625 +20481 0.081512451171875 +20482 0.12200927734375 +20483 0.12335205078125 +20484 0.080108642578125 +20485 0.15374755859375 +20486 0.05126953125 +20487 0.182098388671875 +20488 0.062896728515625 +20489 0.218841552734375 +20490 0.09271240234375 +20491 0.2525634765625 +20492 0.092987060546875 +20493 0.26104736328125 +20494 0.07855224609375 +20495 0.2508544921875 +20496 0.06427001953125 +20497 0.229217529296875 +20498 0.0347900390625 +20499 0.19036865234375 +20500 -0.01171875 +20501 0.1351318359375 +20502 -0.056060791015625 +20503 0.074249267578125 +20504 -0.055511474609375 +20505 0.02935791015625 +20506 -0.010467529296875 +20507 0.00286865234375 +20508 0.02508544921875 +20509 -0.02691650390625 +20510 0.025665283203125 +20511 -0.0689697265625 +20512 0.017333984375 +20513 -0.109375 +20514 0.00189208984375 +20515 -0.1455078125 +20516 -0.03173828125 +20517 -0.18096923828125 +20518 -0.071502685546875 +20519 -0.20953369140625 +20520 -0.13543701171875 +20521 -0.239013671875 +20522 -0.219970703125 +20523 -0.268035888671875 +20524 -0.300506591796875 +20525 -0.28631591796875 +20526 -0.376312255859375 +20527 -0.294708251953125 +20528 -0.416107177734375 +20529 -0.28076171875 +20530 -0.371124267578125 +20531 -0.224456787109375 +20532 -0.242279052734375 +20533 -0.128326416015625 +20534 -0.069732666015625 +20535 -0.0125732421875 +20536 0.125640869140625 +20537 0.111297607421875 +20538 0.31268310546875 +20539 0.2274169921875 +20540 0.45501708984375 +20541 0.317779541015625 +20542 0.554779052734375 +20543 0.382049560546875 +20544 0.61065673828125 +20545 0.418792724609375 +20546 0.610931396484375 +20547 0.422332763671875 +20548 0.531463623046875 +20549 0.381866455078125 +20550 0.3883056640625 +20551 0.30511474609375 +20552 0.23468017578125 +20553 0.2169189453125 +20554 0.095245361328125 +20555 0.129608154296875 +20556 -0.00396728515625 +20557 0.056365966796875 +20558 -0.04852294921875 +20559 0.005340576171875 +20560 -0.055145263671875 +20561 -0.029205322265625 +20562 -0.0758056640625 +20563 -0.06890869140625 +20564 -0.138702392578125 +20565 -0.124847412109375 +20566 -0.209197998046875 +20567 -0.17999267578125 +20568 -0.289031982421875 +20569 -0.23394775390625 +20570 -0.37884521484375 +20571 -0.286224365234375 +20572 -0.456329345703125 +20573 -0.326263427734375 +20574 -0.51641845703125 +20575 -0.35174560546875 +20576 -0.519287109375 +20577 -0.345001220703125 +20578 -0.458251953125 +20579 -0.303619384765625 +20580 -0.384796142578125 +20581 -0.251708984375 +20582 -0.323699951171875 +20583 -0.20159912109375 +20584 -0.269287109375 +20585 -0.152069091796875 +20586 -0.1951904296875 +20587 -0.09271240234375 +20588 -0.100006103515625 +20589 -0.024322509765625 +20590 -0.01055908203125 +20591 0.03961181640625 +20592 0.1033935546875 +20593 0.1114501953125 +20594 0.24908447265625 +20595 0.19342041015625 +20596 0.373199462890625 +20597 0.260772705078125 +20598 0.45806884765625 +20599 0.305084228515625 +20600 0.511474609375 +20601 0.32965087890625 +20602 0.565399169921875 +20603 0.3489990234375 +20604 0.61138916015625 +20605 0.359771728515625 +20606 0.5897216796875 +20607 0.33575439453125 +20608 0.4906005859375 +20609 0.273468017578125 +20610 0.33148193359375 +20611 0.18182373046875 +20612 0.147796630859375 +20613 0.077911376953125 +20614 -0.01873779296875 +20615 -0.018310546875 +20616 -0.140289306640625 +20617 -0.093109130859375 +20618 -0.191986083984375 +20619 -0.134246826171875 +20620 -0.184295654296875 +20621 -0.1455078125 +20622 -0.161834716796875 +20623 -0.146270751953125 +20624 -0.166595458984375 +20625 -0.154937744140625 +20626 -0.19390869140625 +20627 -0.169219970703125 +20628 -0.22442626953125 +20629 -0.180389404296875 +20630 -0.279754638671875 +20631 -0.19842529296875 +20632 -0.3389892578125 +20633 -0.214447021484375 +20634 -0.3543701171875 +20635 -0.207672119140625 +20636 -0.348175048828125 +20637 -0.188934326171875 +20638 -0.32598876953125 +20639 -0.16168212890625 +20640 -0.2581787109375 +20641 -0.11358642578125 +20642 -0.139801025390625 +20643 -0.043365478515625 +20644 0.014617919921875 +20645 0.041534423828125 +20646 0.144378662109375 +20647 0.11297607421875 +20648 0.221038818359375 +20649 0.15753173828125 +20650 0.27069091796875 +20651 0.18646240234375 +20652 0.294036865234375 +20653 0.199859619140625 +20654 0.311767578125 +20655 0.207000732421875 +20656 0.339141845703125 +20657 0.21484375 +20658 0.360260009765625 +20659 0.2164306640625 +20660 0.360504150390625 +20661 0.205780029296875 +20662 0.308380126953125 +20663 0.169708251953125 +20664 0.18170166015625 +20665 0.099273681640625 +20666 0.0047607421875 +20667 0.006072998046875 +20668 -0.17559814453125 +20669 -0.08837890625 +20670 -0.3143310546875 +20671 -0.1634521484375 +20672 -0.36785888671875 +20673 -0.199249267578125 +20674 -0.36248779296875 +20675 -0.206695556640625 +20676 -0.343536376953125 +20677 -0.20526123046875 +20678 -0.3018798828125 +20679 -0.190704345703125 +20680 -0.231414794921875 +20681 -0.160186767578125 +20682 -0.117645263671875 +20683 -0.107391357421875 +20684 0.007049560546875 +20685 -0.04681396484375 +20686 0.087982177734375 +20687 -0.002899169921875 +20688 0.13946533203125 +20689 0.03009033203125 +20690 0.17425537109375 +20691 0.057159423828125 +20692 0.188201904296875 +20693 0.075775146484375 +20694 0.171234130859375 +20695 0.080810546875 +20696 0.118438720703125 +20697 0.069427490234375 +20698 0.05706787109375 +20699 0.053009033203125 +20700 -0.010711669921875 +20701 0.031951904296875 +20702 -0.0914306640625 +20703 0.0029296875 +20704 -0.162322998046875 +20705 -0.0242919921875 +20706 -0.194549560546875 +20707 -0.03717041015625 +20708 -0.1492919921875 +20709 -0.018646240234375 +20710 -0.02166748046875 +20711 0.033599853515625 +20712 0.124053955078125 +20713 0.091552734375 +20714 0.211151123046875 +20715 0.121856689453125 +20716 0.240447998046875 +20717 0.125396728515625 +20718 0.242218017578125 +20719 0.115997314453125 +20720 0.2257080078125 +20721 0.098358154296875 +20722 0.194366455078125 +20723 0.074554443359375 +20724 0.115509033203125 +20725 0.030731201171875 +20726 0.0128173828125 +20727 -0.022186279296875 +20728 -0.053802490234375 +20729 -0.057464599609375 +20730 -0.110626220703125 +20731 -0.086395263671875 +20732 -0.199493408203125 +20733 -0.12725830078125 +20734 -0.29437255859375 +20735 -0.168548583984375 +20736 -0.33221435546875 +20737 -0.1829833984375 +20738 -0.27972412109375 +20739 -0.156829833984375 +20740 -0.185333251953125 +20741 -0.11065673828125 +20742 -0.128204345703125 +20743 -0.077545166015625 +20744 -0.115692138671875 +20745 -0.061309814453125 +20746 -0.116455078125 +20747 -0.049957275390625 +20748 -0.105926513671875 +20749 -0.03424072265625 +20750 -0.053955078125 +20751 -0.002532958984375 +20752 0.048797607421875 +20753 0.048370361328125 +20754 0.157318115234375 +20755 0.09967041015625 +20756 0.212005615234375 +20757 0.126708984375 +20758 0.218475341796875 +20759 0.131622314453125 +20760 0.23724365234375 +20761 0.139068603515625 +20762 0.30535888671875 +20763 0.164276123046875 +20764 0.38128662109375 +20765 0.190521240234375 +20766 0.404449462890625 +20767 0.19342041015625 +20768 0.3944091796875 +20769 0.181365966796875 +20770 0.3885498046875 +20771 0.17010498046875 +20772 0.362640380859375 +20773 0.1502685546875 +20774 0.27362060546875 +20775 0.104827880859375 +20776 0.11712646484375 +20777 0.032501220703125 +20778 -0.054901123046875 +20779 -0.0450439453125 +20780 -0.19085693359375 +20781 -0.10638427734375 +20782 -0.28570556640625 +20783 -0.149200439453125 +20784 -0.339263916015625 +20785 -0.173248291015625 +20786 -0.3775634765625 +20787 -0.1890869140625 +20788 -0.445709228515625 +20789 -0.215179443359375 +20790 -0.535064697265625 +20791 -0.248138427734375 +20792 -0.629058837890625 +20793 -0.28143310546875 +20794 -0.697601318359375 +20795 -0.3031005859375 +20796 -0.70391845703125 +20797 -0.29852294921875 +20798 -0.6424560546875 +20799 -0.265869140625 +20800 -0.491241455078125 +20801 -0.19659423828125 +20802 -0.265716552734375 +20803 -0.097412109375 +20804 -0.023712158203125 +20805 0.007659912109375 +20806 0.201751708984375 +20807 0.1048583984375 +20808 0.375823974609375 +20809 0.1796875 +20810 0.485076904296875 +20811 0.226531982421875 +20812 0.56884765625 +20813 0.2613525390625 +20814 0.634765625 +20815 0.287261962890625 +20816 0.63763427734375 +20817 0.28594970703125 +20818 0.5660400390625 +20819 0.2529296875 +20820 0.4720458984375 +20821 0.209686279296875 +20822 0.40692138671875 +20823 0.177398681640625 +20824 0.3778076171875 +20825 0.159332275390625 +20826 0.376953125 +20827 0.152679443359375 +20828 0.371978759765625 +20829 0.14459228515625 +20830 0.313140869140625 +20831 0.115081787109375 +20832 0.184417724609375 +20833 0.057891845703125 +20834 0.011199951171875 +20835 -0.016357421875 +20836 -0.171051025390625 +20837 -0.093017578125 +20838 -0.33740234375 +20839 -0.161834716796875 +20840 -0.47198486328125 +20841 -0.21630859375 +20842 -0.560394287109375 +20843 -0.250640869140625 +20844 -0.58056640625 +20845 -0.2559814453125 +20846 -0.54754638671875 +20847 -0.2386474609375 +20848 -0.508575439453125 +20849 -0.218170166015625 +20850 -0.459503173828125 +20851 -0.193115234375 +20852 -0.394378662109375 +20853 -0.161346435546875 +20854 -0.35260009765625 +20855 -0.139190673828125 +20856 -0.31170654296875 +20857 -0.117767333984375 +20858 -0.197418212890625 +20859 -0.0670166015625 +20860 -0.007965087890625 +20861 0.0135498046875 +20862 0.207489013671875 +20863 0.10369873046875 +20864 0.409210205078125 +20865 0.187103271484375 +20866 0.57208251953125 +20867 0.253509521484375 +20868 0.66595458984375 +20869 0.2906494140625 +20870 0.65875244140625 +20871 0.285552978515625 +20872 0.56744384765625 +20873 0.24530029296875 +20874 0.431396484375 +20875 0.186126708984375 +20876 0.29443359375 +20877 0.126129150390625 +20878 0.182464599609375 +20879 0.07611083984375 +20880 0.06365966796875 +20881 0.023345947265625 +20882 -0.075958251953125 +20883 -0.037628173828125 +20884 -0.189422607421875 +20885 -0.087432861328125 +20886 -0.271942138671875 +20887 -0.123931884765625 +20888 -0.342529296875 +20889 -0.15472412109375 +20890 -0.364166259765625 +20891 -0.1646728515625 +20892 -0.327239990234375 +20893 -0.149810791015625 +20894 -0.2769775390625 +20895 -0.12860107421875 +20896 -0.253692626953125 +20897 -0.1175537109375 +20898 -0.24365234375 +20899 -0.111175537109375 +20900 -0.1983642578125 +20901 -0.089813232421875 +20902 -0.116241455078125 +20903 -0.053009033203125 +20904 -0.036834716796875 +20905 -0.017059326171875 +20906 0.034881591796875 +20907 0.0157470703125 +20908 0.09124755859375 +20909 0.042083740234375 +20910 0.10888671875 +20911 0.05224609375 +20912 0.125518798828125 +20913 0.061492919921875 +20914 0.15771484375 +20915 0.07647705078125 +20916 0.17828369140625 +20917 0.08599853515625 +20918 0.17108154296875 +20919 0.08343505859375 +20920 0.129974365234375 +20921 0.0662841796875 +20922 0.082427978515625 +20923 0.0457763671875 +20924 0.027679443359375 +20925 0.021697998046875 +20926 -0.065643310546875 +20927 -0.018585205078125 +20928 -0.15936279296875 +20929 -0.059356689453125 +20930 -0.21307373046875 +20931 -0.084014892578125 +20932 -0.234649658203125 +20933 -0.09564208984375 +20934 -0.2001953125 +20935 -0.084320068359375 +20936 -0.119171142578125 +20937 -0.05377197265625 +20938 -0.024749755859375 +20939 -0.01739501953125 +20940 0.085784912109375 +20941 0.0260009765625 +20942 0.178131103515625 +20943 0.0625 +20944 0.215576171875 +20945 0.077178955078125 +20946 0.211456298828125 +20947 0.07550048828125 +20948 0.17523193359375 +20949 0.06134033203125 +20950 0.128753662109375 +20951 0.04351806640625 +20952 0.1019287109375 +20953 0.0341796875 +20954 0.0743408203125 +20955 0.02490234375 +20956 0.04327392578125 +20957 0.014434814453125 +20958 0.038177490234375 +20959 0.014678955078125 +20960 0.076263427734375 +20961 0.032501220703125 +20962 0.14105224609375 +20963 0.061065673828125 +20964 0.186431884765625 +20965 0.081451416015625 +20966 0.188812255859375 +20967 0.08392333984375 +20968 0.1390380859375 +20969 0.064697265625 +20970 0.041778564453125 +20971 0.025634765625 +20972 -0.079437255859375 +20973 -0.023681640625 +20974 -0.219390869140625 +20975 -0.08111572265625 +20976 -0.367828369140625 +20977 -0.142425537109375 +20978 -0.494873046875 +20979 -0.19537353515625 +20980 -0.556243896484375 +20981 -0.221832275390625 +20982 -0.508697509765625 +20983 -0.204071044921875 +20984 -0.3756103515625 +20985 -0.151519775390625 +20986 -0.218902587890625 +20987 -0.08935546875 +20988 -0.063751220703125 +20989 -0.027740478515625 +20990 0.091552734375 +20991 0.0340576171875 +20992 0.23602294921875 +20993 0.091583251953125 +20994 0.342987060546875 +20995 0.134033203125 +20996 0.39520263671875 +20997 0.15472412109375 +20998 0.389373779296875 +20999 0.152679443359375 +21000 0.324249267578125 +21001 0.127655029296875 +21002 0.224090576171875 +21003 0.0889892578125 +21004 0.124267578125 +21005 0.0501708984375 +21006 0.037078857421875 +21007 0.0159912109375 +21008 -0.010101318359375 +21009 -0.00311279296875 +21010 -0.019439697265625 +21011 -0.007843017578125 +21012 -0.022796630859375 +21013 -0.0101318359375 +21014 -0.001556396484375 +21015 -0.0029296875 +21016 0.056304931640625 +21017 0.018280029296875 +21018 0.106719970703125 +21019 0.03692626953125 +21020 0.096893310546875 +21021 0.03314208984375 +21022 0.042694091796875 +21023 0.012908935546875 +21024 -0.018035888671875 +21025 -0.009552001953125 +21026 -0.07586669921875 +21027 -0.030731201171875 +21028 -0.11944580078125 +21029 -0.046417236328125 +21030 -0.15972900390625 +21031 -0.060791015625 +21032 -0.202606201171875 +21033 -0.076080322265625 +21034 -0.24859619140625 +21035 -0.092529296875 +21036 -0.30517578125 +21037 -0.113006591796875 +21038 -0.36212158203125 +21039 -0.133697509765625 +21040 -0.39141845703125 +21041 -0.144134521484375 +21042 -0.35528564453125 +21043 -0.130157470703125 +21044 -0.249969482421875 +21045 -0.090362548828125 +21046 -0.092864990234375 +21047 -0.03131103515625 +21048 0.08905029296875 +21049 0.036865234375 +21050 0.2352294921875 +21051 0.0914306640625 +21052 0.318817138671875 +21053 0.122314453125 +21054 0.358642578125 +21055 0.136627197265625 +21056 0.347747802734375 +21057 0.13177490234375 +21058 0.28564453125 +21059 0.107635498046875 +21060 0.223175048828125 +21061 0.0833740234375 +21062 0.196746826171875 +21063 0.072723388671875 +21064 0.179840087890625 +21065 0.06573486328125 +21066 0.155548095703125 +21067 0.056121826171875 +21068 0.151214599609375 +21069 0.054168701171875 +21070 0.156951904296875 +21071 0.056182861328125 +21072 0.13177490234375 +21073 0.046722412109375 +21074 0.100799560546875 +21075 0.03521728515625 +21076 0.087127685546875 +21077 0.03033447265625 +21078 0.05487060546875 +21079 0.01861572265625 +21080 -0.009002685546875 +21081 -0.0048828125 +21082 -0.10400390625 +21083 -0.03997802734375 +21084 -0.229400634765625 +21085 -0.086456298828125 +21086 -0.35552978515625 +21087 -0.133209228515625 +21088 -0.441925048828125 +21089 -0.1650390625 +21090 -0.473846435546875 +21091 -0.176483154296875 +21092 -0.464813232421875 +21093 -0.172607421875 +21094 -0.419097900390625 +21095 -0.155029296875 +21096 -0.334320068359375 +21097 -0.1229248046875 +21098 -0.227935791015625 +21099 -0.082855224609375 +21100 -0.12347412109375 +21101 -0.043670654296875 +21102 -0.02764892578125 +21103 -0.007843017578125 +21104 0.077667236328125 +21105 0.031463623046875 +21106 0.2132568359375 +21107 0.082061767578125 +21108 0.38885498046875 +21109 0.1475830078125 +21110 0.582794189453125 +21111 0.219940185546875 +21112 0.734039306640625 +21113 0.276214599609375 +21114 0.800140380859375 +21115 0.30047607421875 +21116 0.7783203125 +21117 0.291717529296875 +21118 0.6651611328125 +21119 0.248687744140625 +21120 0.45965576171875 +21121 0.1710205078125 +21122 0.199188232421875 +21123 0.072784423828125 +21124 -0.050689697265625 +21125 -0.02130126953125 +21126 -0.23297119140625 +21127 -0.08984375 +21128 -0.33013916015625 +21129 -0.126251220703125 +21130 -0.368408203125 +21131 -0.140380859375 +21132 -0.378936767578125 +21133 -0.143951416015625 +21134 -0.376983642578125 +21135 -0.14276123046875 +21136 -0.37969970703125 +21137 -0.143280029296875 +21138 -0.391510009765625 +21139 -0.147186279296875 +21140 -0.385345458984375 +21141 -0.14434814453125 +21142 -0.3419189453125 +21143 -0.127532958984375 +21144 -0.28289794921875 +21145 -0.104888916015625 +21146 -0.251617431640625 +21147 -0.092742919921875 +21148 -0.266143798828125 +21149 -0.097900390625 +21150 -0.273345947265625 +21151 -0.100433349609375 +21152 -0.216796875 +21153 -0.0791015625 +21154 -0.128265380859375 +21155 -0.045867919921875 +21156 -0.068145751953125 +21157 -0.023406982421875 +21158 -0.0430908203125 +21159 -0.014190673828125 +21160 -0.024444580078125 +21161 -0.0074462890625 +21162 0.020721435546875 +21163 0.009185791015625 +21164 0.124481201171875 +21165 0.047760009765625 +21166 0.25787353515625 +21167 0.097412109375 +21168 0.379119873046875 +21169 0.1424560546875 +21170 0.47991943359375 +21171 0.179840087890625 +21172 0.5281982421875 +21173 0.197509765625 +21174 0.511138916015625 +21175 0.190673828125 +21176 0.456207275390625 +21177 0.169708251953125 +21178 0.407470703125 +21179 0.15118408203125 +21180 0.383758544921875 +21181 0.142181396484375 +21182 0.35687255859375 +21183 0.132110595703125 +21184 0.31182861328125 +21185 0.11529541015625 +21186 0.250885009765625 +21187 0.09259033203125 +21188 0.1654052734375 +21189 0.06072998046875 +21190 0.035247802734375 +21191 0.01214599609375 +21192 -0.142059326171875 +21193 -0.054107666015625 +21194 -0.33563232421875 +21195 -0.126434326171875 +21196 -0.5345458984375 +21197 -0.20074462890625 +21198 -0.72186279296875 +21199 -0.27069091796875 +21200 -0.836669921875 +21201 -0.313385009765625 +21202 -0.8326416015625 +21203 -0.31146240234375 +21204 -0.7296142578125 +21205 -0.27239990234375 +21206 -0.582550048828125 +21207 -0.216888427734375 +21208 -0.440093994140625 +21209 -0.163238525390625 +21210 -0.324310302734375 +21211 -0.119720458984375 +21212 -0.20147705078125 +21213 -0.07366943359375 +21214 -0.044647216796875 +21215 -0.014892578125 +21216 0.103973388671875 +21217 0.040679931640625 +21218 0.202392578125 +21219 0.077301025390625 +21220 0.264495849609375 +21221 0.100189208984375 +21222 0.338897705078125 +21223 0.127655029296875 +21224 0.443817138671875 +21225 0.166595458984375 +21226 0.545074462890625 +21227 0.204193115234375 +21228 0.6173095703125 +21229 0.230926513671875 +21230 0.6524658203125 +21231 0.243804931640625 +21232 0.66339111328125 +21233 0.247650146484375 +21234 0.6561279296875 +21235 0.244781494140625 +21236 0.606781005859375 +21237 0.2261962890625 +21238 0.501190185546875 +21239 0.186553955078125 +21240 0.352783203125 +21241 0.130889892578125 +21242 0.176544189453125 +21243 0.064849853515625 +21244 -0.034820556640625 +21245 -0.014312744140625 +21246 -0.258209228515625 +21247 -0.097900390625 +21248 -0.44244384765625 +21249 -0.1668701171875 +21250 -0.5753173828125 +21251 -0.216522216796875 +21252 -0.65203857421875 +21253 -0.2452392578125 +21254 -0.641632080078125 +21255 -0.242431640625 +21256 -0.562164306640625 +21257 -0.2144775390625 +21258 -0.458038330078125 +21259 -0.176788330078125 +21260 -0.350555419921875 +21261 -0.13690185546875 +21262 -0.260528564453125 +21263 -0.102203369140625 +21264 -0.192108154296875 +21265 -0.07440185546875 +21266 -0.141937255859375 +21267 -0.0526123046875 +21268 -0.1021728515625 +21269 -0.03436279296875 +21270 -0.062896728515625 +21271 -0.0164794921875 +21272 -0.011932373046875 +21273 0.004974365234375 +21274 0.062835693359375 +21275 0.033966064453125 +21276 0.148712158203125 +21277 0.06597900390625 +21278 0.241729736328125 +21279 0.099517822265625 +21280 0.34912109375 +21281 0.137054443359375 +21282 0.457305908203125 +21283 0.17388916015625 +21284 0.54388427734375 +21285 0.202392578125 +21286 0.5728759765625 +21287 0.210296630859375 +21288 0.506591796875 +21289 0.18475341796875 +21290 0.351226806640625 +21291 0.12811279296875 +21292 0.146514892578125 +21293 0.05419921875 +21294 -0.05523681640625 +21295 -0.018768310546875 +21296 -0.21624755859375 +21297 -0.077606201171875 +21298 -0.334930419921875 +21299 -0.121551513671875 +21300 -0.402984619140625 +21301 -0.147613525390625 +21302 -0.4412841796875 +21303 -0.162841796875 +21304 -0.49578857421875 +21305 -0.182952880859375 +21306 -0.5601806640625 +21307 -0.205718994140625 +21308 -0.600738525390625 +21309 -0.21954345703125 +21310 -0.584228515625 +21311 -0.2130126953125 +21312 -0.47930908203125 +21313 -0.1754150390625 +21314 -0.27935791015625 +21315 -0.104583740234375 +21316 -0.0089111328125 +21317 -0.00909423828125 +21318 0.268798828125 +21319 0.089141845703125 +21320 0.482818603515625 +21321 0.16558837890625 +21322 0.60369873046875 +21323 0.209930419921875 +21324 0.650421142578125 +21325 0.22857666015625 +21326 0.66400146484375 +21327 0.2354736328125 +21328 0.6414794921875 +21329 0.229522705078125 +21330 0.572540283203125 +21331 0.20709228515625 +21332 0.498138427734375 +21333 0.18218994140625 +21334 0.439453125 +21335 0.162078857421875 +21336 0.375518798828125 +21337 0.13958740234375 +21338 0.274505615234375 +21339 0.103790283203125 +21340 0.1087646484375 +21341 0.04522705078125 +21342 -0.099395751953125 +21343 -0.028289794921875 +21344 -0.3182373046875 +21345 -0.105712890625 +21346 -0.5489501953125 +21347 -0.187347412109375 +21348 -0.7738037109375 +21349 -0.266937255859375 +21350 -0.86383056640625 +21351 -0.326171875 +21352 -0.870391845703125 +21353 -0.353485107421875 +21354 -0.86895751953125 +21355 -0.354888916015625 +21356 -0.861053466796875 +21357 -0.3348388671875 +21358 -0.765869140625 +21359 -0.287322998046875 +21360 -0.5301513671875 +21361 -0.20843505859375 +21362 -0.214691162109375 +21363 -0.10064697265625 +21364 0.137359619140625 +21365 0.021209716796875 +21366 0.474822998046875 +21367 0.139404296875 +21368 0.76239013671875 +21369 0.241668701171875 +21370 0.867462158203125 +21371 0.318634033203125 +21372 0.870361328125 +21373 0.370361328125 +21374 0.86480712890625 +21375 0.39276123046875 +21376 0.831817626953125 +21377 0.387603759765625 +21378 0.677581787109375 +21379 0.3631591796875 +21380 0.495880126953125 +21381 0.32135009765625 +21382 0.30767822265625 +21383 0.26849365234375 +21384 0.116180419921875 +21385 0.205322265625 +21386 -0.110748291015625 +21387 0.120880126953125 +21388 -0.381805419921875 +21389 0.01275634765625 +21390 -0.6572265625 +21391 -0.104248046875 +21392 -0.857421875 +21393 -0.209503173828125 +21394 -0.870391845703125 +21395 -0.2882080078125 +21396 -0.870391845703125 +21397 -0.337860107421875 +21398 -0.86444091796875 +21399 -0.367645263671875 +21400 -0.85723876953125 +21401 -0.389739990234375 +21402 -0.790008544921875 +21403 -0.39776611328125 +21404 -0.62847900390625 +21405 -0.37298583984375 +21406 -0.3956298828125 +21407 -0.314239501953125 +21408 -0.126708984375 +21409 -0.232757568359375 +21410 0.150115966796875 +21411 -0.137908935546875 +21412 0.424041748046875 +21413 -0.033660888671875 +21414 0.670623779296875 +21415 0.0706787109375 +21416 0.854522705078125 +21417 0.16180419921875 +21418 0.866485595703125 +21419 0.23358154296875 +21420 0.86920166015625 +21421 0.280670166015625 +21422 0.8653564453125 +21423 0.30926513671875 +21424 0.857147216796875 +21425 0.323883056640625 +21426 0.766845703125 +21427 0.323455810546875 +21428 0.628509521484375 +21429 0.3096923828125 +21430 0.462127685546875 +21431 0.28021240234375 +21432 0.297210693359375 +21433 0.24383544921875 +21434 0.14862060546875 +21435 0.204742431640625 +21436 -0.00537109375 +21437 0.155059814453125 +21438 -0.15753173828125 +21439 0.09735107421875 +21440 -0.31304931640625 +21441 0.0303955078125 +21442 -0.48876953125 +21443 -0.050628662109375 +21444 -0.6416015625 +21445 -0.129547119140625 +21446 -0.751373291015625 +21447 -0.197845458984375 +21448 -0.84619140625 +21449 -0.263427734375 +21450 -0.861297607421875 +21451 -0.3211669921875 +21452 -0.863250732421875 +21453 -0.359588623046875 +21454 -0.856597900390625 +21455 -0.367767333984375 +21456 -0.7498779296875 +21457 -0.349822998046875 +21458 -0.624542236328125 +21459 -0.325592041015625 +21460 -0.47808837890625 +21461 -0.287506103515625 +21462 -0.253387451171875 +21463 -0.215423583984375 +21464 0.003692626953125 +21465 -0.125030517578125 +21466 0.2257080078125 +21467 -0.03985595703125 +21468 0.427154541015625 +21469 0.044403076171875 +21470 0.643218994140625 +21471 0.13885498046875 +21472 0.855926513671875 +21473 0.240142822265625 +21474 0.870361328125 +21475 0.3282470703125 +21476 0.870361328125 +21477 0.386077880859375 +21478 0.862762451171875 +21479 0.416046142578125 +21480 0.79669189453125 +21481 0.4171142578125 +21482 0.595794677734375 +21483 0.385955810546875 +21484 0.362152099609375 +21485 0.33258056640625 +21486 0.1270751953125 +21487 0.2666015625 +21488 -0.086944580078125 +21489 0.195281982421875 +21490 -0.2784423828125 +21491 0.119354248046875 +21492 -0.484832763671875 +21493 0.026885986328125 +21494 -0.729583740234375 +21495 -0.08868408203125 +21496 -0.86688232421875 +21497 -0.209930419921875 +21498 -0.870391845703125 +21499 -0.315032958984375 +21500 -0.86859130859375 +21501 -0.402191162109375 +21502 -0.86279296875 +21503 -0.47064208984375 +21504 -0.817962646484375 +21505 -0.50787353515625 +21506 -0.6116943359375 +21507 -0.49853515625 +21508 -0.3128662109375 +21509 -0.4404296875 +21510 0.039398193359375 +21511 -0.344879150390625 +21512 0.422821044921875 +21513 -0.21905517578125 +21514 0.805145263671875 +21515 -0.07427978515625 +21516 0.870361328125 +21517 0.06719970703125 +21518 0.870361328125 +21519 0.186767578125 +21520 0.860015869140625 +21521 0.280029296875 +21522 0.727935791015625 +21523 0.343902587890625 +21524 0.48114013671875 +21525 0.3760986328125 +21526 0.2059326171875 +21527 0.3837890625 +21528 -0.06103515625 +21529 0.373748779296875 +21530 -0.29913330078125 +21531 0.349029541015625 +21532 -0.516204833984375 +21533 0.305206298828125 +21534 -0.7252197265625 +21535 0.23773193359375 +21536 -0.85980224609375 +21537 0.15472412109375 +21538 -0.870391845703125 +21539 0.0673828125 +21540 -0.870391845703125 +21541 -0.014434814453125 +21542 -0.858062744140625 +21543 -0.07489013671875 +21544 -0.673004150390625 +21545 -0.11199951171875 +21546 -0.42694091796875 +21547 -0.1414794921875 +21548 -0.2100830078125 +21549 -0.176544189453125 +21550 -0.0362548828125 +21551 -0.21600341796875 +21552 0.10943603515625 +21553 -0.2503662109375 +21554 0.23516845703125 +21555 -0.273101806640625 +21556 0.373687744140625 +21557 -0.2711181640625 +21558 0.517791748046875 +21559 -0.245025634765625 +21560 0.602783203125 +21561 -0.214630126953125 +21562 0.635711669921875 +21563 -0.1785888671875 +21564 0.655181884765625 +21565 -0.12689208984375 +21566 0.65948486328125 +21567 -0.063140869140625 +21568 0.651275634765625 +21569 0.009552001953125 +21570 0.61846923828125 +21571 0.08294677734375 +21572 0.53753662109375 +21573 0.1448974609375 +21574 0.404144287109375 +21575 0.189178466796875 +21576 0.22186279296875 +21577 0.2122802734375 +21578 0.003997802734375 +21579 0.214202880859375 +21580 -0.22100830078125 +21581 0.2003173828125 +21582 -0.42449951171875 +21583 0.17681884765625 +21584 -0.579833984375 +21585 0.15032958984375 +21586 -0.641876220703125 +21587 0.13427734375 +21588 -0.6177978515625 +21589 0.12677001953125 +21590 -0.575531005859375 +21591 0.107940673828125 +21592 -0.526336669921875 +21593 0.076507568359375 +21594 -0.42645263671875 +21595 0.049102783203125 +21596 -0.2581787109375 +21597 0.034759521484375 +21598 -0.068695068359375 +21599 0.02264404296875 +21600 0.09222412109375 +21601 0.00128173828125 +21602 0.232147216796875 +21603 -0.023040771484375 +21604 0.3509521484375 +21605 -0.046783447265625 +21606 0.410064697265625 +21607 -0.078857421875 +21608 0.372955322265625 +21609 -0.128204345703125 +21610 0.2554931640625 +21611 -0.18817138671875 +21612 0.10711669921875 +21613 -0.24249267578125 +21614 -0.052886962890625 +21615 -0.285125732421875 +21616 -0.186279296875 +21617 -0.304962158203125 +21618 -0.23291015625 +21619 -0.284881591796875 +21620 -0.209442138671875 +21621 -0.232330322265625 +21622 -0.174163818359375 +21623 -0.16827392578125 +21624 -0.126739501953125 +21625 -0.095733642578125 +21626 -0.048126220703125 +21627 -0.012054443359375 +21628 0.0426025390625 +21629 0.073516845703125 +21630 0.10748291015625 +21631 0.146087646484375 +21632 0.1409912109375 +21633 0.20123291015625 +21634 0.19708251953125 +21635 0.253509521484375 +21636 0.273651123046875 +21637 0.300689697265625 +21638 0.31768798828125 +21639 0.3253173828125 +21640 0.341094970703125 +21641 0.330841064453125 +21642 0.368011474609375 +21643 0.325286865234375 +21644 0.37249755859375 +21645 0.301666259765625 +21646 0.30072021484375 +21647 0.244873046875 +21648 0.1517333984375 +21649 0.156768798828125 +21650 -0.01470947265625 +21651 0.058441162109375 +21652 -0.1883544921875 +21653 -0.044189453125 +21654 -0.372711181640625 +21655 -0.1495361328125 +21656 -0.51397705078125 +21657 -0.238250732421875 +21658 -0.57177734375 +21659 -0.295379638671875 +21660 -0.53948974609375 +21661 -0.31689453125 +21662 -0.43511962890625 +21663 -0.306915283203125 +21664 -0.2962646484375 +21665 -0.276153564453125 +21666 -0.161102294921875 +21667 -0.23614501953125 +21668 -0.0435791015625 +21669 -0.19140625 +21670 0.060394287109375 +21671 -0.14141845703125 +21672 0.13665771484375 +21673 -0.091796875 +21674 0.170135498046875 +21675 -0.04888916015625 +21676 0.16552734375 +21677 -0.013214111328125 +21678 0.15728759765625 +21679 0.023773193359375 +21680 0.150787353515625 +21681 0.061553955078125 +21682 0.12200927734375 +21683 0.0904541015625 +21684 0.080108642578125 +21685 0.111297607421875 +21686 0.05126953125 +21687 0.13055419921875 +21688 0.062896728515625 +21689 0.1553955078125 +21690 0.09271240234375 +21691 0.17791748046875 +21692 0.092987060546875 +21693 0.1827392578125 +21694 0.07855224609375 +21695 0.174468994140625 +21696 0.06427001953125 +21697 0.158172607421875 +21698 0.0347900390625 +21699 0.129913330078125 +21700 -0.01171875 +21701 0.09039306640625 +21702 -0.056060791015625 +21703 0.047149658203125 +21704 -0.055511474609375 +21705 0.015228271484375 +21706 -0.010467529296875 +21707 -0.003631591796875 +21708 0.02508544921875 +21709 -0.024444580078125 +21710 0.025665283203125 +21711 -0.053466796875 +21712 0.017333984375 +21713 -0.0810546875 +21714 0.00189208984375 +21715 -0.105377197265625 +21716 -0.03173828125 +21717 -0.128997802734375 +21718 -0.071502685546875 +21719 -0.14764404296875 +21720 -0.13543701171875 +21721 -0.166778564453125 +21722 -0.219970703125 +21723 -0.185546875 +21724 -0.300506591796875 +21725 -0.196868896484375 +21726 -0.376312255859375 +21727 -0.20147705078125 +21728 -0.416107177734375 +21729 -0.1907958984375 +21730 -0.371124267578125 +21731 -0.150970458984375 +21732 -0.242279052734375 +21733 -0.08380126953125 +21734 -0.069732666015625 +21735 -0.003326416015625 +21736 0.125640869140625 +21737 0.082489013671875 +21738 0.31268310546875 +21739 0.162628173828125 +21740 0.45501708984375 +21741 0.224639892578125 +21742 0.554779052734375 +21743 0.268310546875 +21744 0.61065673828125 +21745 0.292755126953125 +21746 0.610931396484375 +21747 0.2940673828125 +21748 0.531463623046875 +21749 0.26483154296875 +21750 0.3883056640625 +21751 0.21044921875 +21752 0.23468017578125 +21753 0.148193359375 +21754 0.095245361328125 +21755 0.086700439453125 +21756 -0.00396728515625 +21757 0.035186767578125 +21758 -0.04852294921875 +21759 -0.000640869140625 +21760 -0.055145263671875 +21761 -0.024993896484375 +21762 -0.0758056640625 +21763 -0.052734375 +21764 -0.138702392578125 +21765 -0.09124755859375 +21766 -0.209197998046875 +21767 -0.1290283203125 +21768 -0.289031982421875 +21769 -0.1656494140625 +21770 -0.37884521484375 +21771 -0.20068359375 +21772 -0.456329345703125 +21773 -0.22705078125 +21774 -0.51641845703125 +21775 -0.2431640625 +21776 -0.519287109375 +21777 -0.2373046875 +21778 -0.458251953125 +21779 -0.207977294921875 +21780 -0.384796142578125 +21781 -0.17132568359375 +21782 -0.323699951171875 +21783 -0.13568115234375 +21784 -0.269287109375 +21785 -0.100341796875 +21786 -0.1951904296875 +21787 -0.05853271484375 +21788 -0.100006103515625 +21789 -0.010894775390625 +21790 -0.01055908203125 +21791 0.033447265625 +21792 0.1033935546875 +21793 0.0826416015625 +21794 0.24908447265625 +21795 0.13812255859375 +21796 0.373199462890625 +21797 0.183349609375 +21798 0.45806884765625 +21799 0.212677001953125 +21800 0.511474609375 +21801 0.228363037109375 +21802 0.565399169921875 +21803 0.240142822265625 +21804 0.61138916015625 +21805 0.245819091796875 +21806 0.5897216796875 +21807 0.22802734375 +21808 0.4906005859375 +21809 0.184539794921875 +21810 0.33148193359375 +21811 0.12139892578125 +21812 0.147796630859375 +21813 0.050140380859375 +21814 -0.01873779296875 +21815 -0.01580810546875 +21816 -0.140289306640625 +21817 -0.0672607421875 +21818 -0.191986083984375 +21819 -0.095947265625 +21820 -0.184295654296875 +21821 -0.104339599609375 +21822 -0.161834716796875 +21823 -0.10528564453125 +21824 -0.166595458984375 +21825 -0.111053466796875 +21826 -0.19390869140625 +21827 -0.120086669921875 +21828 -0.22442626953125 +21829 -0.12664794921875 +21830 -0.279754638671875 +21831 -0.137481689453125 +21832 -0.3389892578125 +21833 -0.146697998046875 +21834 -0.3543701171875 +21835 -0.140533447265625 +21836 -0.348175048828125 +21837 -0.126312255859375 +21838 -0.32598876953125 +21839 -0.1064453125 +21840 -0.2581787109375 +21841 -0.072784423828125 +21842 -0.139801025390625 +21843 -0.02459716796875 +21844 0.014617919921875 +21845 0.033111572265625 +21846 0.144378662109375 +21847 0.081512451171875 +21848 0.221038818359375 +21849 0.11163330078125 +21850 0.27069091796875 +21851 0.1309814453125 +21852 0.294036865234375 +21853 0.139617919921875 +21854 0.311767578125 +21855 0.143707275390625 +21856 0.339141845703125 +21857 0.14794921875 +21858 0.360260009765625 +21859 0.1475830078125 +21860 0.360504150390625 +21861 0.13873291015625 +21862 0.308380126953125 +21863 0.11322021484375 +21864 0.18170166015625 +21865 0.065582275390625 +21866 0.0047607421875 +21867 0.00335693359375 +21868 -0.17559814453125 +21869 -0.059539794921875 +21870 -0.3143310546875 +21871 -0.109832763671875 +21872 -0.36785888671875 +21873 -0.13470458984375 +21874 -0.36248779296875 +21875 -0.141021728515625 +21876 -0.343536376953125 +21877 -0.14111328125 +21878 -0.3018798828125 +21879 -0.1322021484375 +21880 -0.231414794921875 +21881 -0.11248779296875 +21882 -0.117645263671875 +21883 -0.0780029296875 +21884 0.007049560546875 +21885 -0.038055419921875 +21886 0.087982177734375 +21887 -0.008270263671875 +21888 0.13946533203125 +21889 0.014892578125 +21890 0.17425537109375 +21891 0.034454345703125 +21892 0.188201904296875 +21893 0.0487060546875 +21894 0.171234130859375 +21895 0.054229736328125 +21896 0.118438720703125 +21897 0.049072265625 +21898 0.05706787109375 +21899 0.040374755859375 +21900 -0.010711669921875 +21901 0.028289794921875 +21902 -0.0914306640625 +21903 0.01068115234375 +21904 -0.162322998046875 +21905 -0.006256103515625 +21906 -0.194549560546875 +21907 -0.014556884765625 +21908 -0.1492919921875 +21909 -0.00335693359375 +21910 -0.02166748046875 +21911 0.028839111328125 +21912 0.124053955078125 +21913 0.064300537109375 +21914 0.211151123046875 +21915 0.08184814453125 +21916 0.240447998046875 +21917 0.082183837890625 +21918 0.242218017578125 +21919 0.07421875 +21920 0.2257080078125 +21921 0.06103515625 +21922 0.194366455078125 +21923 0.0440673828125 +21924 0.115509033203125 +21925 0.01458740234375 +21926 0.0128173828125 +21927 -0.020355224609375 +21928 -0.053802490234375 +21929 -0.043701171875 +21930 -0.110626220703125 +21931 -0.06256103515625 +21932 -0.199493408203125 +21933 -0.08856201171875 +21934 -0.29437255859375 +21935 -0.114410400390625 +21936 -0.33221435546875 +21937 -0.122528076171875 +21938 -0.27972412109375 +21939 -0.103790283203125 +21940 -0.185333251953125 +21941 -0.072021484375 +21942 -0.128204345703125 +21943 -0.049713134765625 +21944 -0.115692138671875 +21945 -0.039306640625 +21946 -0.116455078125 +21947 -0.032379150390625 +21948 -0.105926513671875 +21949 -0.022491455078125 +21950 -0.053955078125 +21951 -0.0015869140625 +21952 0.048797607421875 +21953 0.0325927734375 +21954 0.157318115234375 +21955 0.06719970703125 +21956 0.212005615234375 +21957 0.085357666015625 +21958 0.218475341796875 +21959 0.088531494140625 +21960 0.23724365234375 +21961 0.093597412109375 +21962 0.30535888671875 +21963 0.110992431640625 +21964 0.38128662109375 +21965 0.12921142578125 +21966 0.404449462890625 +21967 0.131500244140625 +21968 0.3944091796875 +21969 0.123626708984375 +21970 0.3885498046875 +21971 0.116363525390625 +21972 0.362640380859375 +21973 0.103240966796875 +21974 0.27362060546875 +21975 0.072540283203125 +21976 0.11712646484375 +21977 0.023345947265625 +21978 -0.054901123046875 +21979 -0.029510498046875 +21980 -0.19085693359375 +21981 -0.071319580078125 +21982 -0.28570556640625 +21983 -0.100494384765625 +21984 -0.339263916015625 +21985 -0.11688232421875 +21986 -0.3775634765625 +21987 -0.12774658203125 +21988 -0.445709228515625 +21989 -0.145751953125 +21990 -0.535064697265625 +21991 -0.1685791015625 +21992 -0.629058837890625 +21993 -0.19171142578125 +21994 -0.697601318359375 +21995 -0.206939697265625 +21996 -0.70391845703125 +21997 -0.204193115234375 +21998 -0.6424560546875 +21999 -0.18218994140625 +22000 -0.491241455078125 +22001 -0.135040283203125 +22002 -0.265716552734375 +22003 -0.067352294921875 +22004 -0.023712158203125 +22005 0.004425048828125 +22006 0.201751708984375 +22007 0.070831298828125 +22008 0.375823974609375 +22009 0.121978759765625 +22010 0.485076904296875 +22011 0.15399169921875 +22012 0.56884765625 +22013 0.177825927734375 +22014 0.634765625 +22015 0.195648193359375 +22016 0.63763427734375 +22017 0.195343017578125 +22018 0.5660400390625 +22019 0.174591064453125 +22020 0.4720458984375 +22021 0.14703369140625 +22022 0.40692138671875 +22023 0.125457763671875 +22024 0.3778076171875 +22025 0.11181640625 +22026 0.376953125 +22027 0.104461669921875 +22028 0.371978759765625 +22029 0.095733642578125 +22030 0.313140869140625 +22031 0.0736083984375 +22032 0.184417724609375 +22033 0.034515380859375 +22034 0.011199951171875 +22035 -0.01483154296875 +22036 -0.171051025390625 +22037 -0.0653076171875 +22038 -0.33740234375 +22039 -0.1104736328125 +22040 -0.47198486328125 +22041 -0.146209716796875 +22042 -0.560394287109375 +22043 -0.168853759765625 +22044 -0.58056640625 +22045 -0.172943115234375 +22046 -0.54754638671875 +22047 -0.16229248046875 +22048 -0.508575439453125 +22049 -0.148834228515625 +22050 -0.459503173828125 +22051 -0.131744384765625 +22052 -0.394378662109375 +22053 -0.10986328125 +22054 -0.35260009765625 +22055 -0.093231201171875 +22056 -0.31170654296875 +22057 -0.07666015625 +22058 -0.197418212890625 +22059 -0.04205322265625 +22060 -0.007965087890625 +22061 0.010650634765625 +22062 0.207489013671875 +22063 0.06890869140625 +22064 0.409210205078125 +22065 0.122650146484375 +22066 0.57208251953125 +22067 0.165496826171875 +22068 0.66595458984375 +22069 0.18988037109375 +22070 0.65875244140625 +22071 0.18780517578125 +22072 0.56744384765625 +22073 0.16357421875 +22074 0.431396484375 +22075 0.127044677734375 +22076 0.29443359375 +22077 0.08929443359375 +22078 0.182464599609375 +22079 0.05694580078125 +22080 0.06365966796875 +22081 0.02239990234375 +22082 -0.075958251953125 +22083 -0.01751708984375 +22084 -0.189422607421875 +22085 -0.05084228515625 +22086 -0.271942138671875 +22087 -0.076080322265625 +22088 -0.342529296875 +22089 -0.097686767578125 +22090 -0.364166259765625 +22091 -0.106353759765625 +22092 -0.327239990234375 +22093 -0.099517822265625 +22094 -0.2769775390625 +22095 -0.088287353515625 +22096 -0.253692626953125 +22097 -0.082611083984375 +22098 -0.24365234375 +22099 -0.079132080078125 +22100 -0.1983642578125 +22101 -0.06591796875 +22102 -0.116241455078125 +22103 -0.042694091796875 +22104 -0.036834716796875 +22105 -0.019439697265625 +22106 0.034881591796875 +22107 0.00238037109375 +22108 0.09124755859375 +22109 0.0206298828125 +22110 0.10888671875 +22111 0.02923583984375 +22112 0.125518798828125 +22113 0.037322998046875 +22114 0.15771484375 +22115 0.048828125 +22116 0.17828369140625 +22117 0.056793212890625 +22118 0.17108154296875 +22119 0.057098388671875 +22120 0.129974365234375 +22121 0.048126220703125 +22122 0.082427978515625 +22123 0.03668212890625 +22124 0.027679443359375 +22125 0.022552490234375 +22126 -0.065643310546875 +22127 -0.001922607421875 +22128 -0.15936279296875 +22129 -0.027191162109375 +22130 -0.21307373046875 +22131 -0.043121337890625 +22132 -0.234649658203125 +22133 -0.051513671875 +22134 -0.2001953125 +22135 -0.0462646484375 +22136 -0.119171142578125 +22137 -0.029541015625 +22138 -0.024749755859375 +22139 -0.0093994140625 +22140 0.085784912109375 +22141 0.0150146484375 +22142 0.178131103515625 +22143 0.03533935546875 +22144 0.215576171875 +22145 0.0426025390625 +22146 0.211456298828125 +22147 0.040191650390625 +22148 0.17523193359375 +22149 0.030548095703125 +22150 0.128753662109375 +22151 0.01910400390625 +22152 0.1019287109375 +22153 0.01324462890625 +22154 0.0743408203125 +22155 0.007843017578125 +22156 0.04327392578125 +22157 0.002105712890625 +22158 0.038177490234375 +22159 0.003204345703125 +22160 0.076263427734375 +22161 0.015289306640625 +22162 0.14105224609375 +22163 0.034088134765625 +22164 0.186431884765625 +22165 0.04803466796875 +22166 0.188812255859375 +22167 0.051116943359375 +22168 0.1390380859375 +22169 0.040985107421875 +22170 0.041778564453125 +22171 0.0186767578125 +22172 -0.079437255859375 +22173 -0.010040283203125 +22174 -0.219390869140625 +22175 -0.0439453125 +22176 -0.367828369140625 +22177 -0.08050537109375 +22178 -0.494873046875 +22179 -0.1123046875 +22180 -0.556243896484375 +22181 -0.12835693359375 +22182 -0.508697509765625 +22183 -0.117889404296875 +22184 -0.3756103515625 +22185 -0.08660888671875 +22186 -0.218902587890625 +22187 -0.04974365234375 +22188 -0.063751220703125 +22189 -0.013458251953125 +22190 0.091552734375 +22191 0.02276611328125 +22192 0.23602294921875 +22193 0.056365966796875 +22194 0.342987060546875 +22195 0.080810546875 +22196 0.39520263671875 +22197 0.09197998046875 +22198 0.389373779296875 +22199 0.089141845703125 +22200 0.324249267578125 +22201 0.072021484375 +22202 0.224090576171875 +22203 0.046722412109375 +22204 0.124267578125 +22205 0.022003173828125 +22206 0.037078857421875 +22207 0.00091552734375 +22208 -0.010101318359375 +22209 -0.009796142578125 +22210 -0.019439697265625 +22211 -0.0107421875 +22212 -0.022796630859375 +22213 -0.0098876953125 +22214 -0.001556396484375 +22215 -0.00274658203125 +22216 0.056304931640625 +22217 0.0135498046875 +22218 0.106719970703125 +22219 0.027923583984375 +22220 0.096893310546875 +22221 0.0272216796875 +22222 0.042694091796875 +22223 0.015289306640625 +22224 -0.018035888671875 +22225 0.00140380859375 +22226 -0.07586669921875 +22227 -0.0120849609375 +22228 -0.11944580078125 +22229 -0.02239990234375 +22230 -0.15972900390625 +22231 -0.03228759765625 +22232 -0.202606201171875 +22233 -0.043182373046875 +22234 -0.24859619140625 +22235 -0.05517578125 +22236 -0.30517578125 +22237 -0.070098876953125 +22238 -0.36212158203125 +22239 -0.085357666015625 +22240 -0.39141845703125 +22241 -0.093963623046875 +22242 -0.35528564453125 +22243 -0.086456298828125 +22244 -0.249969482421875 +22245 -0.061798095703125 +22246 -0.092864990234375 +22247 -0.02423095703125 +22248 0.08905029296875 +22249 0.01959228515625 +22250 0.2352294921875 +22251 0.054718017578125 +22252 0.318817138671875 +22253 0.074554443359375 +22254 0.358642578125 +22255 0.08380126953125 +22256 0.347747802734375 +22257 0.080780029296875 +22258 0.28564453125 +22259 0.06536865234375 +22260 0.223175048828125 +22261 0.0501708984375 +22262 0.196746826171875 +22263 0.044189453125 +22264 0.179840087890625 +22265 0.040802001953125 +22266 0.155548095703125 +22267 0.0357666015625 +22268 0.151214599609375 +22269 0.035797119140625 +22270 0.156951904296875 +22271 0.03839111328125 +22272 0.13177490234375 +22273 0.033447265625 +22274 0.100799560546875 +22275 0.026702880859375 +22276 0.087127685546875 +22277 0.023681640625 +22278 0.05487060546875 +22279 0.016448974609375 +22280 -0.009002685546875 +22281 0.00213623046875 +22282 -0.10400390625 +22283 -0.0191650390625 +22284 -0.229400634765625 +22285 -0.047332763671875 +22286 -0.35552978515625 +22287 -0.07586669921875 +22288 -0.441925048828125 +22289 -0.095947265625 +22290 -0.473846435546875 +22291 -0.10430908203125 +22292 -0.464813232421875 +22293 -0.103790283203125 +22294 -0.419097900390625 +22295 -0.095184326171875 +22296 -0.334320068359375 +22297 -0.077911376953125 +22298 -0.227935791015625 +22299 -0.055633544921875 +22300 -0.12347412109375 +22301 -0.033416748046875 +22302 -0.02764892578125 +22303 -0.0126953125 +22304 0.077667236328125 +22305 0.01043701171875 +22306 0.2132568359375 +22307 0.040435791015625 +22308 0.38885498046875 +22309 0.079345703125 +22310 0.582794189453125 +22311 0.122467041015625 +22312 0.734039306640625 +22313 0.156524658203125 +22314 0.800140380859375 +22315 0.172271728515625 +22316 0.7783203125 +22317 0.16900634765625 +22318 0.6651611328125 +22319 0.145904541015625 +22320 0.45965576171875 +22321 0.10272216796875 +22322 0.199188232421875 +22323 0.0474853515625 +22324 -0.050689697265625 +22325 -0.005706787109375 +22326 -0.23297119140625 +22327 -0.0445556640625 +22328 -0.33013916015625 +22329 -0.0653076171875 +22330 -0.368408203125 +22331 -0.07366943359375 +22332 -0.378936767578125 +22333 -0.076324462890625 +22334 -0.376983642578125 +22335 -0.076568603515625 +22336 -0.37969970703125 +22337 -0.07806396484375 +22338 -0.391510009765625 +22339 -0.081695556640625 +22340 -0.385345458984375 +22341 -0.081573486328125 +22342 -0.3419189453125 +22343 -0.073455810546875 +22344 -0.28289794921875 +22345 -0.061920166015625 +22346 -0.251617431640625 +22347 -0.0562744140625 +22348 -0.266143798828125 +22349 -0.06036376953125 +22350 -0.273345947265625 +22351 -0.062652587890625 +22352 -0.216796875 +22353 -0.050933837890625 +22354 -0.128265380859375 +22355 -0.03204345703125 +22356 -0.068145751953125 +22357 -0.01898193359375 +22358 -0.0430908203125 +22359 -0.013214111328125 +22360 -0.024444580078125 +22361 -0.00860595703125 +22362 0.020721435546875 +22363 0.00189208984375 +22364 0.124481201171875 +22365 0.025146484375 +22366 0.25787353515625 +22367 0.05487060546875 +22368 0.379119873046875 +22369 0.08197021484375 +22370 0.47991943359375 +22371 0.1046142578125 +22372 0.5281982421875 +22373 0.1158447265625 +22374 0.511138916015625 +22375 0.11285400390625 +22376 0.456207275390625 +22377 0.10150146484375 +22378 0.407470703125 +22379 0.09130859375 +22380 0.383758544921875 +22381 0.086334228515625 +22382 0.35687255859375 +22383 0.0804443359375 +22384 0.31182861328125 +22385 0.0704345703125 +22386 0.250885009765625 +22387 0.05682373046875 +22388 0.1654052734375 +22389 0.03778076171875 +22390 0.035247802734375 +22391 0.009002685546875 +22392 -0.142059326171875 +22393 -0.02996826171875 +22394 -0.33563232421875 +22395 -0.07244873046875 +22396 -0.5345458984375 +22397 -0.11602783203125 +22398 -0.72186279296875 +22399 -0.157012939453125 +22400 -0.836669921875 +22401 -0.182220458984375 +22402 -0.8326416015625 +22403 -0.181640625 +22404 -0.7296142578125 +22405 -0.1595458984375 +22406 -0.582550048828125 +22407 -0.1278076171875 +22408 -0.440093994140625 +22409 -0.096954345703125 +22410 -0.324310302734375 +22411 -0.071746826171875 +22412 -0.20147705078125 +22413 -0.044891357421875 +22414 -0.044647216796875 +22415 -0.010589599609375 +22416 0.103973388671875 +22417 0.02197265625 +22418 0.202392578125 +22419 0.043701171875 +22420 0.264495849609375 +22421 0.05755615234375 +22422 0.338897705078125 +22423 0.07403564453125 +22424 0.443817138671875 +22425 0.0970458984375 +22426 0.545074462890625 +22427 0.119171142578125 +22428 0.6173095703125 +22429 0.13494873046875 +22430 0.6524658203125 +22431 0.142608642578125 +22432 0.66339111328125 +22433 0.14495849609375 +22434 0.6561279296875 +22435 0.143280029296875 +22436 0.606781005859375 +22437 0.132415771484375 +22438 0.501190185546875 +22439 0.10931396484375 +22440 0.352783203125 +22441 0.076904296875 +22442 0.176544189453125 +22443 0.0384521484375 +22444 -0.034820556640625 +22445 -0.007568359375 +22446 -0.258209228515625 +22447 -0.056121826171875 +22448 -0.44244384765625 +22449 -0.09613037109375 +22450 -0.5753173828125 +22451 -0.124969482421875 +22452 -0.65203857421875 +22453 -0.1416015625 +22454 -0.641632080078125 +22455 -0.13934326171875 +22456 -0.562164306640625 +22457 -0.12213134765625 +22458 -0.458038330078125 +22459 -0.099517822265625 +22460 -0.350555419921875 +22461 -0.076141357421875 +22462 -0.260528564453125 +22463 -0.056488037109375 +22464 -0.192108154296875 +22465 -0.041473388671875 +22466 -0.141937255859375 +22467 -0.0303955078125 +22468 -0.1021728515625 +22469 -0.021575927734375 +22470 -0.062896728515625 +22471 -0.01287841796875 +22472 -0.011932373046875 +22473 -0.001678466796875 +22474 0.062835693359375 +22475 0.014617919921875 +22476 0.148712158203125 +22477 0.03326416015625 +22478 0.241729736328125 +22479 0.053375244140625 +22480 0.34912109375 +22481 0.0765380859375 +22482 0.457305908203125 +22483 0.099822998046875 +22484 0.54388427734375 +22485 0.118377685546875 +22486 0.5728759765625 +22487 0.12445068359375 +22488 0.506591796875 +22489 0.109893798828125 +22490 0.351226806640625 +22491 0.076080322265625 +22492 0.146514892578125 +22493 0.031585693359375 +22494 -0.05523681640625 +22495 -0.012237548828125 +22496 -0.21624755859375 +22497 -0.047210693359375 +22498 -0.334930419921875 +22499 -0.072967529296875 +22500 -0.402984619140625 +22501 -0.08770751953125 +22502 -0.4412841796875 +22503 -0.095947265625 +22504 -0.49578857421875 +22505 -0.10760498046875 +22506 -0.5601806640625 +22507 -0.121337890625 +22508 -0.600738525390625 +22509 -0.129913330078125 +22510 -0.584228515625 +22511 -0.12615966796875 +22512 -0.47930908203125 +22513 -0.103302001953125 +22514 -0.27935791015625 +22515 -0.0599365234375 +22516 -0.0089111328125 +22517 -0.0013427734375 +22518 0.268798828125 +22519 0.05877685546875 +22520 0.482818603515625 +22521 0.105072021484375 +22522 0.60369873046875 +22523 0.131195068359375 +22524 0.650421142578125 +22525 0.141265869140625 +22526 0.66400146484375 +22527 0.144134521484375 +22528 0.6414794921875 +22529 0.139404296875 +22530 0.572540283203125 +22531 0.124786376953125 +22532 0.498138427734375 +22533 0.10797119140625 +22534 0.439453125 +22535 0.093170166015625 +22536 0.375518798828125 +22537 0.07684326171875 +22538 0.274505615234375 +22539 0.05340576171875 +22540 0.1087646484375 +22541 0.018096923828125 +22542 -0.099395751953125 +22543 -0.02471923828125 +22544 -0.3182373046875 +22545 -0.068939208984375 +22546 -0.5489501953125 +22547 -0.114593505859375 +22548 -0.7738037109375 +22549 -0.158233642578125 +22550 -0.86383056640625 +22551 -0.190032958984375 +22552 -0.870391845703125 +22553 -0.203857421875 +22554 -0.86895751953125 +22555 -0.2030029296875 +22556 -0.861053466796875 +22557 -0.18994140625 +22558 -0.765869140625 +22559 -0.161651611328125 +22560 -0.5301513671875 +22561 -0.1162109375 +22562 -0.214691162109375 +22563 -0.05511474609375 +22564 0.137359619140625 +22565 0.013458251953125 +22566 0.474822998046875 +22567 0.079864501953125 +22568 0.76239013671875 +22569 0.137359619140625 +22570 0.867462158203125 +22571 0.180816650390625 +22572 0.870361328125 +22573 0.21014404296875 +22574 0.86480712890625 +22575 0.223052978515625 +22576 0.831817626953125 +22577 0.220458984375 +22578 0.677581787109375 +22579 0.20684814453125 +22580 0.495880126953125 +22581 0.18328857421875 +22582 0.30767822265625 +22583 0.153228759765625 +22584 0.116180419921875 +22585 0.117156982421875 +22586 -0.110748291015625 +22587 0.06939697265625 +22588 -0.381805419921875 +22589 0.0087890625 +22590 -0.6572265625 +22591 -0.05657958984375 +22592 -0.857421875 +22593 -0.115509033203125 +22594 -0.870391845703125 +22595 -0.159942626953125 +22596 -0.870391845703125 +22597 -0.188446044921875 +22598 -0.86444091796875 +22599 -0.205841064453125 +22600 -0.85723876953125 +22601 -0.21856689453125 +22602 -0.790008544921875 +22603 -0.223175048828125 +22604 -0.62847900390625 +22605 -0.20965576171875 +22606 -0.3956298828125 +22607 -0.177398681640625 +22608 -0.126708984375 +22609 -0.132476806640625 +22610 0.150115966796875 +22611 -0.079986572265625 +22612 0.424041748046875 +22613 -0.022186279296875 +22614 0.670623779296875 +22615 0.035858154296875 +22616 0.854522705078125 +22617 0.086883544921875 +22618 0.866485595703125 +22619 0.127471923828125 +22620 0.86920166015625 +22621 0.1546630859375 +22622 0.8653564453125 +22623 0.171630859375 +22624 0.857147216796875 +22625 0.180755615234375 +22626 0.766845703125 +22627 0.181396484375 +22628 0.628509521484375 +22629 0.174407958984375 +22630 0.462127685546875 +22631 0.15850830078125 +22632 0.297210693359375 +22633 0.138458251953125 +22634 0.14862060546875 +22635 0.11651611328125 +22636 -0.00537109375 +22637 0.08856201171875 +22638 -0.15753173828125 +22639 0.056060791015625 +22640 -0.31304931640625 +22641 0.0184326171875 +22642 -0.48876953125 +22643 -0.026763916015625 +22644 -0.6416015625 +22645 -0.07080078125 +22646 -0.751373291015625 +22647 -0.1090087890625 +22648 -0.84619140625 +22649 -0.1455078125 +22650 -0.861297607421875 +22651 -0.177520751953125 +22652 -0.863250732421875 +22653 -0.198822021484375 +22654 -0.856597900390625 +22655 -0.20355224609375 +22656 -0.7498779296875 +22657 -0.19390869140625 +22658 -0.624542236328125 +22659 -0.1805419921875 +22660 -0.47808837890625 +22661 -0.159423828125 +22662 -0.253387451171875 +22663 -0.11981201171875 +22664 0.003692626953125 +22665 -0.0701904296875 +22666 0.2257080078125 +22667 -0.023193359375 +22668 0.427154541015625 +22669 0.02337646484375 +22670 0.643218994140625 +22671 0.07537841796875 +22672 0.855926513671875 +22673 0.13092041015625 +22674 0.870361328125 +22675 0.17919921875 +22676 0.870361328125 +22677 0.211029052734375 +22678 0.862762451171875 +22679 0.227691650390625 +22680 0.79669189453125 +22681 0.22857666015625 +22682 0.595794677734375 +22683 0.2119140625 +22684 0.362152099609375 +22685 0.183074951171875 +22686 0.1270751953125 +22687 0.147216796875 +22688 -0.086944580078125 +22689 0.1082763671875 +22690 -0.2784423828125 +22691 0.066680908203125 +22692 -0.484832763671875 +22693 0.01611328125 +22694 -0.729583740234375 +22695 -0.046875 +22696 -0.86688232421875 +22697 -0.112884521484375 +22698 -0.870391845703125 +22699 -0.170166015625 +22700 -0.86859130859375 +22701 -0.21771240234375 +22702 -0.86279296875 +22703 -0.255035400390625 +22704 -0.817962646484375 +22705 -0.275482177734375 +22706 -0.6116943359375 +22707 -0.2706298828125 +22708 -0.3128662109375 +22709 -0.2391357421875 +22710 0.039398193359375 +22711 -0.18719482421875 +22712 0.422821044921875 +22713 -0.1185302734375 +22714 0.805145263671875 +22715 -0.039306640625 +22716 0.870361328125 +22717 0.037841796875 +22718 0.870361328125 +22719 0.102386474609375 +22720 0.860015869140625 +22721 0.152069091796875 +22722 0.727935791015625 +22723 0.1854248046875 +22724 0.48114013671875 +22725 0.2012939453125 +22726 0.2059326171875 +22727 0.204010009765625 +22728 -0.06103515625 +22729 0.197662353515625 +22730 -0.29913330078125 +22731 0.18402099609375 +22732 -0.516204833984375 +22733 0.16033935546875 +22734 -0.7252197265625 +22735 0.123779296875 +22736 -0.85980224609375 +22737 0.07891845703125 +22738 -0.870391845703125 +22739 0.032073974609375 +22740 -0.870391845703125 +22741 -0.011199951171875 +22742 -0.858062744140625 +22743 -0.041839599609375 +22744 -0.673004150390625 +22745 -0.0589599609375 +22746 -0.42694091796875 +22747 -0.0721435546875 +22748 -0.2100830078125 +22749 -0.089385986328125 +22750 -0.0362548828125 +22751 -0.110137939453125 +22752 0.10943603515625 +22753 -0.128875732421875 +22754 0.23516845703125 +22755 -0.14178466796875 +22756 0.373687744140625 +22757 -0.14117431640625 +22758 0.517791748046875 +22759 -0.127349853515625 +22760 0.602783203125 +22761 -0.11187744140625 +22762 0.635711669921875 +22763 -0.093780517578125 +22764 0.655181884765625 +22765 -0.066986083984375 +22766 0.65948486328125 +22767 -0.03338623046875 +22768 0.651275634765625 +22769 0.005401611328125 +22770 0.61846923828125 +22771 0.04473876953125 +22772 0.53753662109375 +22773 0.077667236328125 +22774 0.404144287109375 +22775 0.1007080078125 +22776 0.22186279296875 +22777 0.1119384765625 +22778 0.003997802734375 +22779 0.111480712890625 +22780 -0.22100830078125 +22781 0.1025390625 +22782 -0.42449951171875 +22783 0.088836669921875 +22784 -0.579833984375 +22785 0.073883056640625 +22786 -0.641876220703125 +22787 0.0648193359375 +22788 -0.6177978515625 +22789 0.06103515625 +22790 -0.575531005859375 +22791 0.05242919921875 +22792 -0.526336669921875 +22793 0.03802490234375 +22794 -0.42645263671875 +22795 0.025634765625 +22796 -0.2581787109375 +22797 0.01947021484375 +22798 -0.068695068359375 +22799 0.01409912109375 +22800 0.09222412109375 +22801 0.003875732421875 +22802 0.232147216796875 +22803 -0.008148193359375 +22804 0.3509521484375 +22805 -0.020172119140625 +22806 0.410064697265625 +22807 -0.036529541015625 +22808 0.372955322265625 +22809 -0.061492919921875 +22810 0.2554931640625 +22811 -0.091766357421875 +22812 0.10711669921875 +22813 -0.11932373046875 +22814 -0.052886962890625 +22815 -0.14111328125 +22816 -0.186279296875 +22817 -0.15167236328125 +22818 -0.23291015625 +22819 -0.142608642578125 +22820 -0.209442138671875 +22821 -0.11749267578125 +22822 -0.174163818359375 +22823 -0.086517333984375 +22824 -0.126739501953125 +22825 -0.051116943359375 +22826 -0.048126220703125 +22827 -0.010040283203125 +22828 0.0426025390625 +22829 0.032196044921875 +22830 0.10748291015625 +22831 0.06829833984375 +22832 0.1409912109375 +22833 0.096038818359375 +22834 0.19708251953125 +22835 0.122467041015625 +22836 0.273651123046875 +22837 0.146453857421875 +22838 0.31768798828125 +22839 0.159423828125 +22840 0.341094970703125 +22841 0.162994384765625 +22842 0.368011474609375 +22843 0.161041259765625 +22844 0.37249755859375 +22845 0.150115966796875 +22846 0.30072021484375 +22847 0.122833251953125 +22848 0.1517333984375 +22849 0.080078125 +22850 -0.01470947265625 +22851 0.032135009765625 +22852 -0.1883544921875 +22853 -0.01806640625 +22854 -0.372711181640625 +22855 -0.06976318359375 +22856 -0.51397705078125 +22857 -0.11346435546875 +22858 -0.57177734375 +22859 -0.14190673828125 +22860 -0.53948974609375 +22861 -0.153076171875 +22862 -0.43511962890625 +22863 -0.14892578125 +22864 -0.2962646484375 +22865 -0.1346435546875 +22866 -0.161102294921875 +22867 -0.115814208984375 +22868 -0.0435791015625 +22869 -0.094635009765625 +22870 0.060394287109375 +22871 -0.070770263671875 +22872 0.13665771484375 +22873 -0.046966552734375 +22874 0.170135498046875 +22875 -0.02630615234375 +22876 0.16552734375 +22877 -0.009033203125 +22878 0.15728759765625 +22879 0.009033203125 +22880 0.150787353515625 +22881 0.027618408203125 +22882 0.12200927734375 +22883 0.0419921875 +22884 0.080108642578125 +22885 0.05255126953125 +22886 0.05126953125 +22887 0.062408447265625 +22888 0.062896728515625 +22889 0.075042724609375 +22890 0.09271240234375 +22891 0.0865478515625 +22892 0.092987060546875 +22893 0.08941650390625 +22894 0.07855224609375 +22895 0.08587646484375 +22896 0.06427001953125 +22897 0.078338623046875 +22898 0.0347900390625 +22899 0.064910888671875 +22900 -0.01171875 +22901 0.0458984375 +22902 -0.056060791015625 +22903 0.02496337890625 +22904 -0.055511474609375 +22905 0.009429931640625 +22906 -0.010467529296875 +22907 0.0001220703125 +22908 0.02508544921875 +22909 -0.010223388671875 +22910 0.025665283203125 +22911 -0.024627685546875 +22912 0.017333984375 +22913 -0.038360595703125 +22914 0.00189208984375 +22915 -0.050567626953125 +22916 -0.03173828125 +22917 -0.062469482421875 +22918 -0.071502685546875 +22919 -0.071929931640625 +22920 -0.13543701171875 +22921 -0.08160400390625 +22922 -0.219970703125 +22923 -0.091064453125 +22924 -0.300506591796875 +22925 -0.096832275390625 +22926 -0.376312255859375 +22927 -0.0992431640625 +22928 -0.416107177734375 +22929 -0.094085693359375 +22930 -0.371124267578125 +22931 -0.074676513671875 +22932 -0.242279052734375 +22933 -0.0418701171875 +22934 -0.069732666015625 +22935 -0.00250244140625 +22936 0.125640869140625 +22937 0.039520263671875 +22938 0.31268310546875 +22939 0.07879638671875 +22940 0.45501708984375 +22941 0.109222412109375 +22942 0.554779052734375 +22943 0.130706787109375 +22944 0.61065673828125 +22945 0.142791748046875 +22946 0.610931396484375 +22947 0.14361572265625 +22948 0.531463623046875 +22949 0.1295166015625 +22950 0.3883056640625 +22951 0.103118896484375 +22952 0.23468017578125 +22953 0.0728759765625 +22954 0.095245361328125 +22955 0.042999267578125 +22956 -0.00396728515625 +22957 0.0179443359375 +22958 -0.04852294921875 +22959 0.000457763671875 +22960 -0.055145263671875 +22961 -0.0113525390625 +22962 -0.0758056640625 +22963 -0.024810791015625 +22964 -0.138702392578125 +22965 -0.04364013671875 +22966 -0.209197998046875 +22967 -0.062103271484375 +22968 -0.289031982421875 +22969 -0.080078125 +22970 -0.37884521484375 +22971 -0.097412109375 +22972 -0.456329345703125 +22973 -0.110565185546875 +22974 -0.51641845703125 +22975 -0.1187744140625 +22976 -0.519287109375 +22977 -0.1160888671875 +22978 -0.458251953125 +22979 -0.101715087890625 +22980 -0.384796142578125 +22981 -0.08380126953125 +22982 -0.323699951171875 +22983 -0.066558837890625 +22984 -0.269287109375 +22985 -0.049560546875 +22986 -0.1951904296875 +22987 -0.029296875 +22988 -0.100006103515625 +22989 -0.006072998046875 +22990 -0.01055908203125 +22991 0.0155029296875 +22992 0.1033935546875 +22993 0.039642333984375 +22994 0.24908447265625 +22995 0.067108154296875 +22996 0.373199462890625 +22997 0.08953857421875 +22998 0.45806884765625 +22999 0.104095458984375 +23000 0.511474609375 +23001 0.1119384765625 +23002 0.565399169921875 +23003 0.11798095703125 +23004 0.61138916015625 +23005 0.121124267578125 +23006 0.5897216796875 +23007 0.112548828125 +23008 0.4906005859375 +23009 0.091094970703125 +23010 0.33148193359375 +23011 0.059814453125 +23012 0.147796630859375 +23013 0.02447509765625 +23014 -0.01873779296875 +23015 -0.00811767578125 +23016 -0.140289306640625 +23017 -0.0333251953125 +23018 -0.191986083984375 +23019 -0.047027587890625 +23020 -0.184295654296875 +23021 -0.050537109375 +23022 -0.161834716796875 +23023 -0.0504150390625 +23024 -0.166595458984375 +23025 -0.05291748046875 +23026 -0.19390869140625 +23027 -0.057281494140625 +23028 -0.22442626953125 +23029 -0.060577392578125 +23030 -0.279754638671875 +23031 -0.066192626953125 +23032 -0.3389892578125 +23033 -0.0711669921875 +23034 -0.3543701171875 +23035 -0.068511962890625 +23036 -0.348175048828125 +23037 -0.0618896484375 +23038 -0.32598876953125 +23039 -0.052459716796875 +23040 -0.2581787109375 +23041 -0.036102294921875 +23042 -0.139801025390625 +23043 -0.01239013671875 +23044 0.014617919921875 +23045 0.016082763671875 +23046 0.144378662109375 +23047 0.0399169921875 +23048 0.221038818359375 +23049 0.05462646484375 +23050 0.27069091796875 +23051 0.063995361328125 +23052 0.294036865234375 +23053 0.068084716796875 +23054 0.311767578125 +23055 0.07000732421875 +23056 0.339141845703125 +23057 0.072021484375 +23058 0.360260009765625 +23059 0.071533203125 +23060 0.360504150390625 +23061 0.066680908203125 +23062 0.308380126953125 +23063 0.054107666015625 +23064 0.18170166015625 +23065 0.03167724609375 +23066 0.0047607421875 +23067 0.0028076171875 +23068 -0.17559814453125 +23069 -0.0263671875 +23070 -0.3143310546875 +23071 -0.04998779296875 +23072 -0.36785888671875 +23073 -0.062469482421875 +23074 -0.36248779296875 +23075 -0.066650390625 +23076 -0.343536376953125 +23077 -0.067718505859375 +23078 -0.3018798828125 +23079 -0.064453125 +23080 -0.231414794921875 +23081 -0.05609130859375 +23082 -0.117645263671875 +23083 -0.040924072265625 +23084 0.007049560546875 +23085 -0.02301025390625 +23086 0.087982177734375 +23087 -0.009063720703125 +23088 0.13946533203125 +23089 0.0023193359375 +23090 0.17425537109375 +23091 0.012359619140625 +23092 0.188201904296875 +23093 0.02020263671875 +23094 0.171234130859375 +23095 0.0242919921875 +23096 0.118438720703125 +23097 0.023712158203125 +23098 0.05706787109375 +23099 0.021453857421875 +23100 -0.010711669921875 +23101 0.017486572265625 +23102 -0.0914306640625 +23103 0.010833740234375 +23104 -0.162322998046875 +23105 0.00408935546875 +23106 -0.194549560546875 +23107 0.000640869140625 +23108 -0.1492919921875 +23109 0.00518798828125 +23110 -0.02166748046875 +23111 0.01837158203125 +23112 0.124053955078125 +23113 0.032623291015625 +23114 0.211151123046875 +23115 0.0389404296875 +23116 0.240447998046875 +23117 0.03765869140625 +23118 0.242218017578125 +23119 0.03271484375 +23120 0.2257080078125 +23121 0.025543212890625 +23122 0.194366455078125 +23123 0.016815185546875 +23124 0.115509033203125 +23125 0.00286865234375 +23126 0.0128173828125 +23127 -0.013153076171875 +23128 -0.053802490234375 +23129 -0.023895263671875 +23130 -0.110626220703125 +23131 -0.03240966796875 +23132 -0.199493408203125 +23133 -0.043670654296875 +23134 -0.29437255859375 +23135 -0.054534912109375 +23136 -0.33221435546875 +23137 -0.0574951171875 +23138 -0.27972412109375 +23139 -0.048675537109375 +23140 -0.185333251953125 +23141 -0.034088134765625 +23142 -0.128204345703125 +23143 -0.023406982421875 +23144 -0.115692138671875 +23145 -0.017730712890625 +23146 -0.116455078125 +23147 -0.013519287109375 +23148 -0.105926513671875 +23149 -0.008056640625 +23150 -0.053955078125 +23151 0.001983642578125 +23152 0.048797607421875 +23153 0.017547607421875 +23154 0.157318115234375 +23155 0.0330810546875 +23156 0.212005615234375 +23157 0.041290283203125 +23158 0.218475341796875 +23159 0.042816162109375 +23160 0.23724365234375 +23161 0.044891357421875 +23162 0.30535888671875 +23163 0.052001953125 +23164 0.38128662109375 +23165 0.059234619140625 +23166 0.404449462890625 +23167 0.059417724609375 +23168 0.3944091796875 +23169 0.055084228515625 +23170 0.3885498046875 +23171 0.050933837890625 +23172 0.362640380859375 +23173 0.04425048828125 +23174 0.27362060546875 +23175 0.030059814453125 +23176 0.11712646484375 +23177 0.008026123046875 +23178 -0.054901123046875 +23179 -0.015411376953125 +23180 -0.19085693359375 +23181 -0.033935546875 +23182 -0.28570556640625 +23183 -0.046844482421875 +23184 -0.339263916015625 +23185 -0.054046630859375 +23186 -0.3775634765625 +23187 -0.058624267578125 +23188 -0.445709228515625 +23189 -0.066009521484375 +23190 -0.535064697265625 +23191 -0.07525634765625 +23192 -0.629058837890625 +23193 -0.08447265625 +23194 -0.697601318359375 +23195 -0.09014892578125 +23196 -0.70391845703125 +23197 -0.088043212890625 +23198 -0.6424560546875 +23199 -0.077667236328125 +23200 -0.491241455078125 +23201 -0.056549072265625 +23202 -0.265716552734375 +23203 -0.026702880859375 +23204 -0.023712158203125 +23205 0.0047607421875 +23206 0.201751708984375 +23207 0.03375244140625 +23208 0.375823974609375 +23209 0.05596923828125 +23210 0.485076904296875 +23211 0.069793701171875 +23212 0.56884765625 +23213 0.07989501953125 +23214 0.634765625 +23215 0.08721923828125 +23216 0.63763427734375 +23217 0.086395263671875 +23218 0.5660400390625 +23219 0.07611083984375 +23220 0.4720458984375 +23221 0.062744140625 +23222 0.40692138671875 +23223 0.052581787109375 +23224 0.3778076171875 +23225 0.046600341796875 +23226 0.376953125 +23227 0.04400634765625 +23228 0.371978759765625 +23229 0.041046142578125 +23230 0.313140869140625 +23231 0.0318603515625 +23232 0.184417724609375 +23233 0.0146484375 +23234 0.011199951171875 +23235 -0.0074462890625 +23236 -0.171051025390625 +23237 -0.030029296875 +23238 -0.33740234375 +23239 -0.05010986328125 +23240 -0.47198486328125 +23241 -0.065826416015625 +23242 -0.560394287109375 +23243 -0.075469970703125 +23244 -0.58056640625 +23245 -0.07647705078125 +23246 -0.54754638671875 +23247 -0.07073974609375 +23248 -0.508575439453125 +23249 -0.064056396484375 +23250 -0.459503173828125 +23251 -0.0560302734375 +23252 -0.394378662109375 +23253 -0.04608154296875 +23254 -0.35260009765625 +23255 -0.03900146484375 +23256 -0.31170654296875 +23257 -0.0322265625 +23258 -0.197418212890625 +23259 -0.016937255859375 +23260 -0.007965087890625 +23261 0.006927490234375 +23262 0.207489013671875 +23263 0.033416748046875 +23264 0.409210205078125 +23265 0.057769775390625 +23266 0.57208251953125 +23267 0.07696533203125 +23268 0.66595458984375 +23269 0.087432861328125 +23270 0.65875244140625 +23271 0.08538818359375 +23272 0.56744384765625 +23273 0.072967529296875 +23274 0.431396484375 +23275 0.054962158203125 +23276 0.29443359375 +23277 0.0367431640625 +23278 0.182464599609375 +23279 0.021484375 +23280 0.06365966796875 +23281 0.005462646484375 +23282 -0.075958251953125 +23283 -0.012847900390625 +23284 -0.189422607421875 +23285 -0.027740478515625 +23286 -0.271942138671875 +23287 -0.038543701171875 +23288 -0.342529296875 +23289 -0.047515869140625 +23290 -0.364166259765625 +23291 -0.05023193359375 +23292 -0.327239990234375 +23293 -0.045562744140625 +23294 -0.2769775390625 +23295 -0.0389404296875 +23296 -0.253692626953125 +23297 -0.03497314453125 +23298 -0.24365234375 +23299 -0.03228759765625 +23300 -0.1983642578125 +23301 -0.0262451171875 +23302 -0.116241455078125 +23303 -0.016693115234375 +23304 -0.036834716796875 +23305 -0.00714111328125 +23306 0.034881591796875 +23307 0.00189208984375 +23308 0.09124755859375 +23309 0.009613037109375 +23310 0.10888671875 +23311 0.01385498046875 +23312 0.125518798828125 +23313 0.017791748046875 +23314 0.15771484375 +23315 0.02276611328125 +23316 0.17828369140625 +23317 0.026275634765625 +23318 0.17108154296875 +23319 0.02679443359375 +23320 0.129974365234375 +23321 0.023712158203125 +23322 0.082427978515625 +23323 0.019439697265625 +23324 0.027679443359375 +23325 0.013916015625 +23326 -0.065643310546875 +23327 0.00445556640625 +23328 -0.15936279296875 +23329 -0.005523681640625 +23330 -0.21307373046875 +23331 -0.012359619140625 +23332 -0.234649658203125 +23333 -0.016632080078125 +23334 -0.2001953125 +23335 -0.016082763671875 +23336 -0.119171142578125 +23337 -0.011444091796875 +23338 -0.024749755859375 +23339 -0.0054931640625 +23340 0.085784912109375 +23341 0.00213623046875 +23342 0.178131103515625 +23343 0.00848388671875 +23344 0.215576171875 +23345 0.010406494140625 +23346 0.211456298828125 +23347 0.0091552734375 +23348 0.17523193359375 +23349 0.005645751953125 +23350 0.128753662109375 +23351 0.00177001953125 +23352 0.1019287109375 +23353 0.000152587890625 +23354 0.0743408203125 +23355 -0.00103759765625 +23356 0.04327392578125 +23357 -0.00213623046875 +23358 0.038177490234375 +23359 -0.000640869140625 +23360 0.076263427734375 +23361 0.00482177734375 +23362 0.14105224609375 +23363 0.012664794921875 +23364 0.186431884765625 +23365 0.018707275390625 +23366 0.188812255859375 +23367 0.020782470703125 +23368 0.1390380859375 +23369 0.017974853515625 +23370 0.041778564453125 +23371 0.010650634765625 +23372 -0.079437255859375 +23373 0.00079345703125 +23374 -0.219390869140625 +23375 -0.011138916015625 +23376 -0.367828369140625 +23377 -0.024200439453125 +23378 -0.494873046875 +23379 -0.0357666015625 +23380 -0.556243896484375 +23381 -0.04193115234375 +23382 -0.508697509765625 +23383 -0.038848876953125 +23384 -0.3756103515625 +23385 -0.02850341796875 +23386 -0.218902587890625 +23387 -0.016265869140625 +23388 -0.063751220703125 +23389 -0.0042724609375 +23390 0.091552734375 +23391 0.007659912109375 +23392 0.23602294921875 +23393 0.018707275390625 +23394 0.342987060546875 +23395 0.026611328125 +23396 0.39520263671875 +23397 0.029937744140625 +23398 0.389373779296875 +23399 0.0284423828125 +23400 0.324249267578125 +23401 0.0220947265625 +23402 0.224090576171875 +23403 0.0130615234375 +23404 0.124267578125 +23405 0.004425048828125 +23406 0.037078857421875 +23407 -0.002716064453125 +23408 -0.010101318359375 +23409 -0.0059814453125 +23410 -0.019439697265625 +23411 -0.005645751953125 +23412 -0.022796630859375 +23413 -0.00457763671875 +23414 -0.001556396484375 +23415 -0.001220703125 +23416 0.056304931640625 +23417 0.005340576171875 +23418 0.106719970703125 +23419 0.01116943359375 +23420 0.096893310546875 +23421 0.011566162109375 +23422 0.042694091796875 +23423 0.007843017578125 +23424 -0.018035888671875 +23425 0.0032958984375 +23426 -0.07586669921875 +23427 -0.00128173828125 +23428 -0.11944580078125 +23429 -0.0048828125 +23430 -0.15972900390625 +23431 -0.00848388671875 +23432 -0.202606201171875 +23433 -0.0125732421875 +23434 -0.24859619140625 +23435 -0.01715087890625 +23436 -0.30517578125 +23437 -0.022857666015625 +23438 -0.36212158203125 +23439 -0.02874755859375 +23440 -0.39141845703125 +23441 -0.032318115234375 +23442 -0.35528564453125 +23443 -0.030181884765625 +23444 -0.249969482421875 +23445 -0.021942138671875 +23446 -0.092864990234375 +23447 -0.00909423828125 +23448 0.08905029296875 +23449 0.006011962890625 +23450 0.2352294921875 +23451 0.01806640625 +23452 0.318817138671875 +23453 0.0247802734375 +23454 0.358642578125 +23455 0.02783203125 +23456 0.347747802734375 +23457 0.026641845703125 +23458 0.28564453125 +23459 0.021148681640625 +23460 0.223175048828125 +23461 0.01580810546875 +23462 0.196746826171875 +23463 0.013824462890625 +23464 0.179840087890625 +23465 0.01287841796875 +23466 0.155548095703125 +23467 0.011444091796875 +23468 0.151214599609375 +23469 0.011871337890625 +23470 0.156951904296875 +23471 0.01324462890625 +23472 0.13177490234375 +23473 0.01190185546875 +23474 0.100799560546875 +23475 0.010009765625 +23476 0.087127685546875 +23477 0.009552001953125 +23478 0.05487060546875 +23479 0.007354736328125 +23480 -0.009002685546875 +23481 0.002227783203125 +23482 -0.10400390625 +23483 -0.005767822265625 +23484 -0.229400634765625 +23485 -0.0166015625 +23486 -0.35552978515625 +23487 -0.027679443359375 +23488 -0.441925048828125 +23489 -0.035430908203125 +23490 -0.473846435546875 +23491 -0.03857421875 +23492 -0.464813232421875 +23493 -0.038238525390625 +23494 -0.419097900390625 +23495 -0.0347900390625 +23496 -0.334320068359375 +23497 -0.027984619140625 +23498 -0.227935791015625 +23499 -0.019317626953125 +23500 -0.12347412109375 +23501 -0.01080322265625 +23502 -0.02764892578125 +23503 -0.003021240234375 +23504 0.077667236328125 +23505 0.005645751953125 +23506 0.2132568359375 +23507 0.017059326171875 +23508 0.38885498046875 +23509 0.0321044921875 +23510 0.582794189453125 +23511 0.04888916015625 +23512 0.734039306640625 +23513 0.062042236328125 +23514 0.800140380859375 +23515 0.06781005859375 +23516 0.7783203125 +23517 0.06597900390625 +23518 0.6651611328125 +23519 0.056243896484375 +23520 0.45965576171875 +23521 0.03851318359375 +23522 0.199188232421875 +23523 0.016082763671875 +23524 -0.050689697265625 +23525 -0.00531005859375 +23526 -0.23297119140625 +23527 -0.02069091796875 +23528 -0.33013916015625 +23529 -0.028564453125 +23530 -0.368408203125 +23531 -0.031280517578125 +23532 -0.378936767578125 +23533 -0.031585693359375 +23534 -0.376983642578125 +23535 -0.030914306640625 +23536 -0.37969970703125 +23537 -0.03076171875 +23538 -0.391510009765625 +23539 -0.03155517578125 +23540 -0.385345458984375 +23541 -0.030914306640625 +23542 -0.3419189453125 +23543 -0.02716064453125 +23544 -0.28289794921875 +23545 -0.02215576171875 +23546 -0.251617431640625 +23547 -0.01971435546875 +23548 -0.266143798828125 +23549 -0.021392822265625 +23550 -0.273345947265625 +23551 -0.02252197265625 +23552 -0.216796875 +23553 -0.018218994140625 +23554 -0.128265380859375 +23555 -0.010986328125 +23556 -0.068145751953125 +23557 -0.005096435546875 +23558 -0.0430908203125 +23559 -0.0010986328125 +23560 -0.024444580078125 +23561 0.002471923828125 +23562 0.020721435546875 +23563 0.007293701171875 +23564 0.124481201171875 +23565 0.0150146484375 +23566 0.25787353515625 +23567 0.023895263671875 +23568 0.379119873046875 +23569 0.03155517578125 +23570 0.47991943359375 +23571 0.0374755859375 +23572 0.5281982421875 +23573 0.039886474609375 +23574 0.511138916015625 +23575 0.0380859375 +23576 0.456207275390625 +23577 0.033660888671875 +23578 0.407470703125 +23579 0.0291748046875 +23580 0.383758544921875 +23581 0.025787353515625 +23582 0.35687255859375 +23583 0.022003173828125 +23584 0.31182861328125 +23585 0.01715087890625 +23586 0.250885009765625 +23587 0.011474609375 +23588 0.1654052734375 +23589 0.004638671875 +23590 0.035247802734375 +23591 -0.004364013671875 +23592 -0.142059326171875 +23593 -0.01556396484375 +23594 -0.33563232421875 +23595 -0.027191162109375 +23596 -0.5345458984375 +23597 -0.038604736328125 +23598 -0.72186279296875 +23599 -0.048828125 +23600 -0.836669921875 +23601 -0.054473876953125 +23602 -0.8326416015625 +23603 -0.05303955078125 +23604 -0.7296142578125 +23605 -0.045684814453125 +23606 -0.582550048828125 +23607 -0.03564453125 +23608 -0.440093994140625 +23609 -0.025726318359375 +23610 -0.324310302734375 +23611 -0.017303466796875 +23612 -0.20147705078125 +23613 -0.008544921875 +23614 -0.044647216796875 +23615 0.001922607421875 +23616 0.103973388671875 +23617 0.01165771484375 +23618 0.202392578125 +23619 0.018218994140625 +23620 0.264495849609375 +23621 0.022308349609375 +23622 0.338897705078125 +23623 0.02667236328125 +23624 0.443817138671875 +23625 0.032318115234375 +23626 0.545074462890625 +23627 0.037353515625 +23628 0.6173095703125 +23629 0.0404052734375 +23630 0.6524658203125 +23631 0.04107666015625 +23632 0.66339111328125 +23633 0.0401611328125 +23634 0.6561279296875 +23635 0.038116455078125 +23636 0.606781005859375 +23637 0.033660888671875 +23638 0.501190185546875 +23639 0.026092529296875 +23640 0.352783203125 +23641 0.01629638671875 +23642 0.176544189453125 +23643 0.005157470703125 +23644 -0.034820556640625 +23645 -0.00762939453125 +23646 -0.258209228515625 +23647 -0.020660400390625 +23648 -0.44244384765625 +23649 -0.031097412109375 +23650 -0.5753173828125 +23651 -0.03826904296875 +23652 -0.65203857421875 +23653 -0.04193115234375 +23654 -0.641632080078125 +23655 -0.0404052734375 +23656 -0.562164306640625 +23657 -0.0347900390625 +23658 -0.458038330078125 +23659 -0.02764892578125 +23660 -0.350555419921875 +23661 -0.020233154296875 +23662 -0.260528564453125 +23663 -0.013763427734375 +23664 -0.192108154296875 +23665 -0.008575439453125 +23666 -0.141937255859375 +23667 -0.0045166015625 +23668 -0.1021728515625 +23669 -0.001251220703125 +23670 -0.062896728515625 +23671 0.001708984375 +23672 -0.011932373046875 +23673 0.005035400390625 +23674 0.062835693359375 +23675 0.0093994140625 +23676 0.148712158203125 +23677 0.0140380859375 +23678 0.241729736328125 +23679 0.018768310546875 +23680 0.34912109375 +23681 0.024017333984375 +23682 0.457305908203125 +23683 0.02911376953125 +23684 0.54388427734375 +23685 0.0328369140625 +23686 0.5728759765625 +23687 0.033233642578125 +23688 0.506591796875 +23689 0.028289794921875 +23690 0.351226806640625 +23691 0.018402099609375 +23692 0.146514892578125 +23693 0.005859375 +23694 -0.05523681640625 +23695 -0.00634765625 +23696 -0.21624755859375 +23697 -0.01605224609375 +23698 -0.334930419921875 +23699 -0.02313232421875 +23700 -0.402984619140625 +23701 -0.027099609375 +23702 -0.4412841796875 +23703 -0.029083251953125 +23704 -0.49578857421875 +23705 -0.031707763671875 +23706 -0.5601806640625 +23707 -0.03466796875 +23708 -0.600738525390625 +23709 -0.036102294921875 +23710 -0.584228515625 +23711 -0.034210205078125 +23712 -0.47930908203125 +23713 -0.027313232421875 +23714 -0.27935791015625 +23715 -0.01507568359375 +23716 -0.0089111328125 +23717 0.00103759765625 +23718 0.268798828125 +23719 0.017425537109375 +23720 0.482818603515625 +23721 0.03009033203125 +23722 0.60369873046875 +23723 0.037353515625 +23724 0.650421142578125 +23725 0.04022216796875 +23726 0.66400146484375 +23727 0.041015625 +23728 0.6414794921875 +23729 0.039581298828125 +23730 0.572540283203125 +23731 0.03533935546875 +23732 0.498138427734375 +23733 0.0306396484375 +23734 0.439453125 +23735 0.026702880859375 +23736 0.375518798828125 +23737 0.022369384765625 +23738 0.274505615234375 +23739 0.01593017578125 +23740 0.1087646484375 +23741 0.005859375 +23742 -0.099395751953125 +23743 -0.00653076171875 +23744 -0.3182373046875 +23745 -0.0194091796875 +23746 -0.5489501953125 +23747 -0.032806396484375 +23748 -0.7738037109375 +23749 -0.045684814453125 +23750 -0.86383056640625 +23751 -0.055084228515625 +23752 -0.870391845703125 +23753 -0.059173583984375 +23754 -0.86895751953125 +23755 -0.058929443359375 +23756 -0.861053466796875 +23757 -0.05511474609375 +23758 -0.765869140625 +23759 -0.046783447265625 +23760 -0.5301513671875 +23761 -0.033355712890625 +23762 -0.214691162109375 +23763 -0.0152587890625 +23764 0.137359619140625 +23765 0.005035400390625 +23766 0.474822998046875 +23767 0.024658203125 +23768 0.76239013671875 +23769 0.04156494140625 +23770 0.867462158203125 +23771 0.05419921875 +23772 0.870361328125 +23773 0.062591552734375 +23774 0.86480712890625 +23775 0.066070556640625 +23776 0.831817626953125 +23777 0.06494140625 +23778 0.677581787109375 +23779 0.060577392578125 +23780 0.495880126953125 +23781 0.053314208984375 +23782 0.30767822265625 +23783 0.044219970703125 +23784 0.116180419921875 +23785 0.033447265625 +23786 -0.110748291015625 +23787 0.01922607421875 +23788 -0.381805419921875 +23789 0.001190185546875 +23790 -0.6572265625 +23791 -0.0181884765625 +23792 -0.857421875 +23793 -0.0355224609375 +23794 -0.870391845703125 +23795 -0.04840087890625 +23796 -0.870391845703125 +23797 -0.056427001953125 +23798 -0.86444091796875 +23799 -0.061126708984375 +23800 -0.85723876953125 +23801 -0.064483642578125 +23802 -0.790008544921875 +23803 -0.065460205078125 +23804 -0.62847900390625 +23805 -0.061065673828125 +23806 -0.3956298828125 +23807 -0.05108642578125 +23808 -0.126708984375 +23809 -0.037445068359375 +23810 0.150115966796875 +23811 -0.02166748046875 +23812 0.424041748046875 +23813 -0.0047607421875 +23814 0.670623779296875 +23815 0.011962890625 +23816 0.854522705078125 +23817 0.0269775390625 +23818 0.866485595703125 +23819 0.03936767578125 +23820 0.86920166015625 +23821 0.04840087890625 +23822 0.8653564453125 +23823 0.054229736328125 +23824 0.857147216796875 +23825 0.05706787109375 +23826 0.766845703125 +23827 0.056793212890625 +23828 0.628509521484375 +23829 0.05364990234375 +23830 0.462127685546875 +23831 0.047637939453125 +23832 0.297210693359375 +23833 0.039642333984375 +23834 0.14862060546875 +23835 0.03033447265625 +23836 -0.00537109375 +23837 0.01959228515625 +23838 -0.15753173828125 +23839 0.00799560546875 +23840 -0.31304931640625 +23841 -0.004058837890625 +23842 -0.48876953125 +23843 -0.016510009765625 +23844 -0.6416015625 +23845 -0.02789306640625 +23846 -0.751373291015625 +23847 -0.03729248046875 +23848 -0.84619140625 +23849 -0.0450439453125 +23850 -0.861297607421875 +23851 -0.0506591796875 +23852 -0.863250732421875 +23853 -0.053314208984375 +23854 -0.856597900390625 +23855 -0.052276611328125 +23856 -0.7498779296875 +23857 -0.047943115234375 +23858 -0.624542236328125 +23859 -0.04193115234375 +23860 -0.47808837890625 +23861 -0.034027099609375 +23862 -0.253387451171875 +23863 -0.023101806640625 +23864 0.003692626953125 +23865 -0.0106201171875 +23866 0.2257080078125 +23867 0.00140380859375 +23868 0.427154541015625 +23869 0.012939453125 +23870 0.643218994140625 +23871 0.02447509765625 +23872 0.855926513671875 +23873 0.035491943359375 +23874 0.870361328125 +23875 0.04443359375 +23876 0.870361328125 +23877 0.050018310546875 +23878 0.862762451171875 +23879 0.0523681640625 +23880 0.79669189453125 +23881 0.05145263671875 +23882 0.595794677734375 +23883 0.047119140625 +23884 0.362152099609375 +23885 0.040191650390625 +23886 0.1270751953125 +23887 0.031524658203125 +23888 -0.086944580078125 +23889 0.021881103515625 +23890 -0.2784423828125 +23891 0.011627197265625 +23892 -0.484832763671875 +23893 0.000213623046875 +23894 -0.729583740234375 +23895 -0.012542724609375 +23896 -0.86688232421875 +23897 -0.02520751953125 +23898 -0.870391845703125 +23899 -0.0360107421875 +23900 -0.86859130859375 +23901 -0.04461669921875 +23902 -0.86279296875 +23903 -0.0509033203125 +23904 -0.817962646484375 +23905 -0.053955078125 +23906 -0.6116943359375 +23907 -0.05267333984375 +23908 -0.3128662109375 +23909 -0.0469970703125 +23910 0.039398193359375 +23911 -0.037811279296875 +23912 0.422821044921875 +23913 -0.0257568359375 +23914 0.805145263671875 +23915 -0.0118408203125 +23916 0.870361328125 +23917 0.002044677734375 +23918 0.870361328125 +23919 0.014312744140625 +23920 0.860015869140625 +23921 0.02447509765625 +23922 0.727935791015625 +23923 0.03216552734375 +23924 0.48114013671875 +23925 0.03704833984375 +23926 0.2059326171875 +23927 0.039520263671875 +23928 -0.06103515625 +23929 0.0400390625 +23930 -0.29913330078125 +23931 0.038818359375 +23932 -0.516204833984375 +23933 0.03546142578125 +23934 -0.7252197265625 +23935 0.0296630859375 +23936 -0.85980224609375 +23937 0.0220947265625 +23938 -0.870391845703125 +23939 0.013702392578125 +23940 -0.870391845703125 +23941 0.005340576171875 +23942 -0.858062744140625 +23943 -0.00164794921875 +23944 -0.673004150390625 +23945 -0.006988525390625 +23946 -0.42694091796875 +23947 -0.011749267578125 +23948 -0.2100830078125 +23949 -0.01678466796875 +23950 -0.0362548828125 +23951 -0.021881103515625 +23952 0.10943603515625 +23953 -0.0262451171875 +23954 0.23516845703125 +23955 -0.02923583984375 +23956 0.373687744140625 +23957 -0.029815673828125 +23958 0.517791748046875 +23959 -0.02801513671875 +23960 0.602783203125 +23961 -0.02532958984375 +23962 0.635711669921875 +23963 -0.021697998046875 +23964 0.655181884765625 +23965 -0.01641845703125 +23966 0.65948486328125 +23967 -0.009857177734375 +23968 0.651275634765625 +23969 -0.00238037109375 +23970 0.61846923828125 +23971 0.005218505859375 +23972 0.53753662109375 +23973 0.011932373046875 +23974 0.404144287109375 +23975 0.017181396484375 +23976 0.22186279296875 +23977 0.020599365234375 +23978 0.003997802734375 +23979 0.02215576171875 +23980 -0.22100830078125 +23981 0.02215576171875 +23982 -0.42449951171875 +23983 0.021026611328125 +23984 -0.579833984375 +23985 0.019256591796875 +23986 -0.641876220703125 +23987 0.01788330078125 +23988 -0.6177978515625 +23989 0.016754150390625 +23990 -0.575531005859375 +23991 0.014373779296875 +23992 -0.526336669921875 +23993 0.010711669921875 +23994 -0.42645263671875 +23995 0.007110595703125 +23996 -0.2581787109375 +23997 0.004364013671875 +23998 -0.068695068359375 +23999 0.001739501953125 +24000 0.09222412109375 +24001 -0.00152587890625 +24002 0.232147216796875 +24003 -0.004852294921875 +24004 0.3509521484375 +24005 -0.007904052734375 +24006 0.410064697265625 +24007 -0.01129150390625 +24008 0.372955322265625 +24009 -0.015655517578125 +24010 0.2554931640625 +24011 -0.020477294921875 +24012 0.10711669921875 +24013 -0.02447509765625 +24014 -0.052886962890625 +24015 -0.027191162109375 +24016 -0.186279296875 +24017 -0.02783203125 +24018 -0.23291015625 +24019 -0.025146484375 +24020 -0.209442138671875 +24021 -0.019805908203125 +24022 -0.174163818359375 +24023 -0.01348876953125 +24024 -0.126739501953125 +24025 -0.006500244140625 +24026 -0.048126220703125 +24027 0.001220703125 +24028 0.0426025390625 +24029 0.0089111328125 +24030 0.10748291015625 +24031 0.015380859375 +24032 0.1409912109375 +24033 0.020233154296875 +24034 0.19708251953125 +24035 0.02459716796875 +24036 0.273651123046875 +24037 0.02825927734375 +24038 0.31768798828125 +24039 0.029876708984375 +24040 0.341094970703125 +24041 0.029754638671875 +24042 0.368011474609375 +24043 0.028564453125 +24044 0.37249755859375 +24045 0.02581787109375 +24046 0.30072021484375 +24047 0.020416259765625 +24048 0.1517333984375 +24049 0.0125732421875 +24050 -0.01470947265625 +24051 0.003936767578125 +24052 -0.1883544921875 +24053 -0.00494384765625 +24054 -0.372711181640625 +24055 -0.013885498046875 +24056 -0.51397705078125 +24057 -0.0213623046875 +24058 -0.57177734375 +24059 -0.02618408203125 +24060 -0.53948974609375 +24061 -0.028045654296875 +24062 -0.43511962890625 +24063 -0.027252197265625 +24064 -0.2962646484375 +24065 -0.024932861328125 +24066 -0.161102294921875 +24067 -0.0220947265625 +24068 -0.0435791015625 +24069 -0.0189208984375 +24070 0.060394287109375 +24071 -0.01531982421875 +24072 0.13665771484375 +24073 -0.01129150390625 +24074 0.170135498046875 +24075 -0.006866455078125 +24076 0.16552734375 +24077 -0.002197265625 +24078 0.15728759765625 +24079 0.002471923828125 +24080 0.150787353515625 +24081 0.0069580078125 +24082 0.12200927734375 +24083 0.01104736328125 +24084 0.080108642578125 +24085 0.014556884765625 +24086 0.05126953125 +24087 0.017303466796875 +24088 0.062896728515625 +24089 0.019134521484375 +24090 0.09271240234375 +24091 0.019989013671875 +24092 0.092987060546875 +24093 0.019805908203125 +24094 0.07855224609375 +24095 0.01861572265625 +24096 0.06427001953125 +24097 0.0164794921875 +24098 0.0347900390625 +24099 0.01348876953125 +24100 -0.01171875 +24101 0.009857177734375 +24102 -0.056060791015625 +24103 0.00579833984375 +24104 -0.055511474609375 +24105 0.001495361328125 +24106 -0.010467529296875 +24107 -0.00274658203125 +24108 0.02508544921875 +24109 -0.006683349609375 +24110 0.025665283203125 +24111 -0.010101318359375 +24112 0.017333984375 +24113 -0.012847900390625 +24114 0.00189208984375 +24115 -0.0147705078125 +24116 -0.03173828125 +24117 -0.01580810546875 +24118 -0.071502685546875 +24119 -0.01593017578125 +24120 -0.13543701171875 +24121 -0.01513671875 +24122 -0.219970703125 +24123 -0.013519287109375 +24124 -0.300506591796875 +24125 -0.01116943359375 +24126 -0.376312255859375 +24127 -0.00823974609375 +24128 -0.416107177734375 +24129 -0.004913330078125 +24130 -0.371124267578125 +24131 -0.001373291015625 +24132 -0.242279052734375 +24133 0.00213623046875 +24134 -0.069732666015625 +24135 0.00543212890625 +24136 0.125640869140625 +24137 0.008331298828125 +24138 0.31268310546875 +24139 0.01068115234375 +24140 0.45501708984375 +24141 0.01239013671875 +24142 0.554779052734375 +24143 0.01336669921875 +24144 0.61065673828125 +24145 0.013580322265625 +24146 0.610931396484375 +24147 0.0130615234375 +24148 0.531463623046875 +24149 0.0118408203125 +24150 0.3883056640625 +24151 0.010009765625 +24152 0.23468017578125 +24153 0.0076904296875 +24154 0.095245361328125 +24155 0.0050048828125 +24156 -0.00396728515625 +24157 0.00213623046875 +24158 -0.04852294921875 +24159 -0.000732421875 +24160 -0.055145263671875 +24161 -0.003448486328125 +24162 -0.0758056640625 +24163 -0.005859375 +24164 -0.138702392578125 +24165 -0.007843017578125 +24166 -0.209197998046875 +24167 -0.009307861328125 +24168 -0.289031982421875 +24169 -0.01019287109375 +24170 -0.37884521484375 +24171 -0.010467529296875 +24172 -0.456329345703125 +24173 -0.0101318359375 +24174 -0.51641845703125 +24175 -0.00921630859375 +24176 -0.519287109375 +24177 -0.007781982421875 +24178 -0.458251953125 +24179 -0.00592041015625 +24180 -0.384796142578125 +24181 -0.003753662109375 +24182 -0.323699951171875 +24183 -0.00140380859375 +24184 -0.269287109375 +24185 0.000946044921875 +24186 -0.1951904296875 +24187 0.003173828125 +24188 -0.100006103515625 +24189 0.005157470703125 +24190 -0.01055908203125 +24191 0.006805419921875 +24192 0.1033935546875 +24193 0.008026123046875 +24194 0.24908447265625 +24195 0.0087890625 +24196 0.373199462890625 +24197 0.009063720703125 +24198 0.45806884765625 +24199 0.00885009765625 +24200 0.511474609375 +24201 0.008148193359375 +24202 0.565399169921875 +24203 0.00701904296875 +24204 0.61138916015625 +24205 0.00555419921875 +24206 0.5897216796875 +24207 0.003814697265625 +24208 0.4906005859375 +24209 0.001922607421875 +24210 0.33148193359375 +24211 0.0 +24212 0.147796630859375 +24213 -0.0018310546875 +24214 -0.01873779296875 +24215 -0.00347900390625 +24216 -0.140289306640625 +24217 -0.004852294921875 +24218 -0.191986083984375 +24219 -0.005889892578125 +24220 -0.184295654296875 +24221 -0.006561279296875 +24222 -0.161834716796875 +24223 -0.0068359375 +24224 -0.166595458984375 +24225 -0.0067138671875 +24226 -0.19390869140625 +24227 -0.006195068359375 +24228 -0.22442626953125 +24229 -0.00531005859375 +24230 -0.279754638671875 +24231 -0.004119873046875 +24232 -0.3389892578125 +24233 -0.002716064453125 +24234 -0.3543701171875 +24235 -0.00115966796875 +24236 -0.348175048828125 +24237 0.00042724609375 +24238 -0.32598876953125 +24239 0.001953125 +24240 -0.2581787109375 +24241 0.003326416015625 +24242 -0.139801025390625 +24243 0.004486083984375 +24244 0.014617919921875 +24245 0.00537109375 +24246 0.144378662109375 +24247 0.005950927734375 +24248 0.221038818359375 +24249 0.006195068359375 +24250 0.27069091796875 +24251 0.006103515625 +24252 0.294036865234375 +24253 0.00567626953125 +24254 0.311767578125 +24255 0.00494384765625 +24256 0.339141845703125 +24257 0.003997802734375 +24258 0.360260009765625 +24259 0.00299072265625 +24260 0.360504150390625 +24261 0.001953125 +24262 0.308380126953125 +24263 0.00067138671875 +24264 0.18170166015625 +24265 -0.001007080078125 +24266 0.0047607421875 +24267 -0.002838134765625 +24268 -0.17559814453125 +24269 -0.00445556640625 +24270 -0.3143310546875 +24271 -0.00555419921875 +24272 -0.36785888671875 +24273 -0.00579833984375 +24274 -0.36248779296875 +24275 -0.00543212890625 +24276 -0.343536376953125 +24277 -0.00482177734375 +24278 -0.3018798828125 +24279 -0.00390625 +24280 -0.231414794921875 +24281 -0.002685546875 +24282 -0.117645263671875 +24283 -0.001129150390625 +24284 0.007049560546875 +24285 0.00048828125 +24286 0.087982177734375 +24287 0.001708984375 +24288 0.13946533203125 +24289 0.002593994140625 +24290 0.17425537109375 +24291 0.003265380859375 +24292 0.188201904296875 +24293 0.003662109375 +24294 0.171234130859375 +24295 0.003692626953125 +24296 0.118438720703125 +24297 0.003326416015625 +24298 0.05706787109375 +24299 0.002777099609375 +24300 -0.010711669921875 +24301 0.002105712890625 +24302 -0.0914306640625 +24303 0.001220703125 +24304 -0.162322998046875 +24305 0.000335693359375 +24306 -0.194549560546875 +24307 -0.000274658203125 +24308 -0.1492919921875 +24309 -0.00030517578125 +24310 -0.02166748046875 +24311 0.000274658203125 +24312 0.124053955078125 +24313 0.0009765625 +24314 0.211151123046875 +24315 0.001190185546875 +24316 0.240447998046875 +24317 0.0009765625 +24318 0.242218017578125 +24319 0.0006103515625 +24320 0.2257080078125 +24321 0.000732421875 +24322 0.194366455078125 +24323 0.001068115234375 +24324 0.115509033203125 +24325 -0.00030517578125 +24326 0.0128173828125 +24327 -0.00250244140625 +24328 -0.053802490234375 +24329 -0.00323486328125 +24330 -0.110626220703125 +24331 -0.003631591796875 +24332 -0.199493408203125 +24333 -0.005462646484375 +24334 -0.29437255859375 +24335 -0.00775146484375 +24336 -0.33221435546875 +24337 -0.008026123046875 +24338 -0.27972412109375 +24339 -0.0050048828125 +24340 -0.185333251953125 +24341 -0.00067138671875 +24342 -0.128204345703125 +24343 0.00177001953125 +24344 -0.115692138671875 +24345 0.002044677734375 +24346 -0.116455078125 +24347 0.001434326171875 +24348 -0.105926513671875 +24349 0.0009765625 +24350 -0.053955078125 +24351 0.001922607421875 +24352 0.048797607421875 +24353 0.00469970703125 +24354 0.157318115234375 +24355 0.00762939453125 +24356 0.212005615234375 +24357 0.00836181640625 +24358 0.218475341796875 +24359 0.007232666015625 +24360 0.23724365234375 +24361 0.0067138671875 +24362 0.30535888671875 +24363 0.00836181640625 +24364 0.38128662109375 +24365 0.010528564453125 +24366 0.404449462890625 +24367 0.010833740234375 +24368 0.3944091796875 +24369 0.0101318359375 +24370 0.3885498046875 +24371 0.009918212890625 +24372 0.362640380859375 +24373 0.00921630859375 +24374 0.27362060546875 +24375 0.00628662109375 +24376 0.11712646484375 +24377 0.00091552734375 +24378 -0.054901123046875 +24379 -0.004852294921875 +24380 -0.19085693359375 +24381 -0.009033203125 +24382 -0.28570556640625 +24383 -0.011505126953125 +24384 -0.339263916015625 +24385 -0.0123291015625 +24386 -0.3775634765625 +24387 -0.01263427734375 +24388 -0.445709228515625 +24389 -0.014251708984375 +24390 -0.535064697265625 +24391 -0.01690673828125 +24392 -0.629058837890625 +24393 -0.019989013671875 +24394 -0.697601318359375 +24395 -0.022308349609375 +24396 -0.70391845703125 +24397 -0.02239990234375 +24398 -0.6424560546875 +24399 -0.020050048828125 +24400 -0.491241455078125 +24401 -0.014404296875 +24402 -0.265716552734375 +24403 -0.00604248046875 +24404 -0.023712158203125 +24405 0.00274658203125 +24406 0.201751708984375 +24407 0.01068115234375 +24408 0.375823974609375 +24409 0.01641845703125 +24410 0.485076904296875 +24411 0.01953125 +24412 0.56884765625 +24413 0.021636962890625 +24414 0.634765625 +24415 0.02313232421875 +24416 0.63763427734375 +24417 0.022247314453125 +24418 0.5660400390625 +24419 0.01861572265625 +24420 0.4720458984375 +24421 0.01434326171875 +24422 0.40692138671875 +24423 0.011474609375 +24424 0.3778076171875 +24425 0.01031494140625 +24426 0.376953125 +24427 0.01055908203125 +24428 0.371978759765625 +24429 0.0108642578125 +24430 0.313140869140625 +24431 0.009185791015625 +24432 0.184417724609375 +24433 0.004852294921875 +24434 0.011199951171875 +24435 -0.001129150390625 +24436 -0.171051025390625 +24437 -0.007354736328125 +24438 -0.33740234375 +24439 -0.012908935546875 +24440 -0.47198486328125 +24441 -0.0172119140625 +24442 -0.560394287109375 +24443 -0.019744873046875 +24444 -0.58056640625 +24445 -0.01971435546875 +24446 -0.54754638671875 +24447 -0.01776123046875 +24448 -0.508575439453125 +24449 -0.01580810546875 +24450 -0.459503173828125 +24451 -0.013671875 +24452 -0.394378662109375 +24453 -0.0111083984375 +24454 -0.35260009765625 +24455 -0.009674072265625 +24456 -0.31170654296875 +24457 -0.008453369140625 +24458 -0.197418212890625 +24459 -0.00445556640625 +24460 -0.007965087890625 +24461 0.00238037109375 +24462 0.207489013671875 +24463 0.010101318359375 +24464 0.409210205078125 +24465 0.017181396484375 +24466 0.57208251953125 +24467 0.022674560546875 +24468 0.66595458984375 +24469 0.02545166015625 +24470 0.65875244140625 +24471 0.024261474609375 +24472 0.56744384765625 +24473 0.019866943359375 +24474 0.431396484375 +24475 0.01385498046875 +24476 0.29443359375 +24477 0.008026123046875 +24478 0.182464599609375 +24479 0.00341796875 +24480 0.06365966796875 +24481 -0.001220703125 +24482 -0.075958251953125 +24483 -0.0064697265625 +24484 -0.189422607421875 +24485 -0.01043701171875 +24486 -0.271942138671875 +24487 -0.012969970703125 +24488 -0.342529296875 +24489 -0.014862060546875 +24490 -0.364166259765625 +24491 -0.0147705078125 +24492 -0.327239990234375 +24493 -0.0123291015625 +24494 -0.2769775390625 +24495 -0.0093994140625 +24496 -0.253692626953125 +24497 -0.00762939453125 +24498 -0.24365234375 +24499 -0.00653076171875 +24500 -0.1983642578125 +24501 -0.004180908203125 +24502 -0.116241455078125 +24503 -0.00054931640625 +24504 -0.036834716796875 +24505 0.00274658203125 +24506 0.034881591796875 +24507 0.0054931640625 +24508 0.09124755859375 +24509 0.00738525390625 +24510 0.10888671875 +24511 0.007537841796875 +24512 0.125518798828125 +24513 0.007476806640625 +24514 0.15771484375 +24515 0.0079345703125 +24516 0.17828369140625 +24517 0.007843017578125 +24518 0.17108154296875 +24519 0.006622314453125 +24520 0.129974365234375 +24521 0.00408935546875 +24522 0.082427978515625 +24523 0.001373291015625 +24524 0.027679443359375 +24525 -0.00146484375 +24526 -0.065643310546875 +24527 -0.005615234375 +24528 -0.15936279296875 +24529 -0.009552001953125 +24530 -0.21307373046875 +24531 -0.01165771484375 +24532 -0.234649658203125 +24533 -0.012298583984375 +24534 -0.2001953125 +24535 -0.010528564453125 +24536 -0.119171142578125 +24537 -0.006744384765625 +24538 -0.024749755859375 +24539 -0.0023193359375 +24540 0.085784912109375 +24541 0.0028076171875 +24542 0.178131103515625 +24543 0.0072021484375 +24544 0.215576171875 +24545 0.009368896484375 +24546 0.211456298828125 +24547 0.009796142578125 +24548 0.17523193359375 +24549 0.008880615234375 +24550 0.128753662109375 +24551 0.0074462890625 +24552 0.1019287109375 +24553 0.00665283203125 +24554 0.0743408203125 +24555 0.005706787109375 +24556 0.04327392578125 +24557 0.004486083984375 +24558 0.038177490234375 +24559 0.004150390625 +24560 0.076263427734375 +24561 0.00537109375 +24562 0.14105224609375 +24563 0.00750732421875 +24564 0.186431884765625 +24565 0.008758544921875 +24566 0.188812255859375 +24567 0.00823974609375 +24568 0.1390380859375 +24569 0.005615234375 +24570 0.041778564453125 +24571 0.0010986328125 +24572 -0.079437255859375 +24573 -0.004302978515625 +24574 -0.219390869140625 +24575 -0.010345458984375 +24576 -0.367828369140625 +24577 -0.01690673828125 +24578 -0.494873046875 +24579 -0.023223876953125 +24580 -0.556243896484375 +24581 -0.026580810546875 +24582 -0.508697509765625 +24583 -0.023590087890625 +24584 -0.3756103515625 +24585 -0.015655517578125 +24586 -0.218902587890625 +24587 -0.006927490234375 +24588 -0.063751220703125 +24589 0.001068115234375 +24590 0.091552734375 +24591 0.0087890625 +24592 0.23602294921875 +24593 0.01568603515625 +24594 0.342987060546875 +24595 0.020111083984375 +24596 0.39520263671875 +24597 0.021026611328125 +24598 0.389373779296875 +24599 0.018341064453125 +24600 0.324249267578125 +24601 0.0120849609375 +24602 0.224090576171875 +24603 0.00408935546875 +24604 0.124267578125 +24605 -0.003082275390625 +24606 0.037078857421875 +24607 -0.00860595703125 +24608 -0.010101318359375 +24609 -0.010589599609375 +24610 -0.019439697265625 +24611 -0.009307861328125 +24612 -0.022796630859375 +24613 -0.007171630859375 +24614 -0.001556396484375 +24615 -0.00299072265625 +24616 0.056304931640625 +24617 0.003875732421875 +24618 0.106719970703125 +24619 0.0101318359375 +24620 0.096893310546875 +24621 0.0118408203125 +24622 0.042694091796875 +24623 0.010040283203125 +24624 -0.018035888671875 +24625 0.00732421875 +24626 -0.07586669921875 +24627 0.0042724609375 +24628 -0.11944580078125 +24629 0.001708984375 +24630 -0.15972900390625 +24631 -0.00115966796875 +24632 -0.202606201171875 +24633 -0.004730224609375 +24634 -0.24859619140625 +24635 -0.009002685546875 +24636 -0.30517578125 +24637 -0.014434814453125 +24638 -0.36212158203125 +24639 -0.020233154296875 +24640 -0.39141845703125 +24641 -0.0242919921875 +24642 -0.35528564453125 +24643 -0.023773193359375 +24644 -0.249969482421875 +24645 -0.018280029296875 +24646 -0.092864990234375 +24647 -0.00897216796875 +24648 0.08905029296875 +24649 0.002288818359375 +24650 0.2352294921875 +24651 0.011260986328125 +24652 0.318817138671875 +24653 0.016082763671875 +24654 0.358642578125 +24655 0.018157958984375 +24656 0.347747802734375 +24657 0.01702880859375 +24658 0.28564453125 +24659 0.012664794921875 +24660 0.223175048828125 +24661 0.00872802734375 +24662 0.196746826171875 +24663 0.00775146484375 +24664 0.179840087890625 +24665 0.007781982421875 +24666 0.155548095703125 +24667 0.007537841796875 +24668 0.151214599609375 +24669 0.008880615234375 +24670 0.156951904296875 +24671 0.011016845703125 +24672 0.13177490234375 +24673 0.010894775390625 +24674 0.100799560546875 +24675 0.01025390625 +24676 0.087127685546875 +24677 0.010650634765625 +24678 0.05487060546875 +24679 0.00946044921875 +24680 -0.009002685546875 +24681 0.005645751953125 +24682 -0.10400390625 +24683 -0.000732421875 +24684 -0.229400634765625 +24685 -0.0096435546875 +24686 -0.35552978515625 +24687 -0.018951416015625 +24688 -0.441925048828125 +24689 -0.025726318359375 +24690 -0.473846435546875 +24691 -0.028900146484375 +24692 -0.464813232421875 +24693 -0.02935791015625 +24694 -0.419097900390625 +24695 -0.02734375 +24696 -0.334320068359375 +24697 -0.0225830078125 +24698 -0.227935791015625 +24699 -0.01629638671875 +24700 -0.12347412109375 +24701 -0.010101318359375 +24702 -0.02764892578125 +24703 -0.00439453125 +24704 0.077667236328125 +24705 0.002166748046875 +24706 0.2132568359375 +24707 0.0111083984375 +24708 0.38885498046875 +24709 0.023193359375 +24710 0.582794189453125 +24711 0.036865234375 +24712 0.734039306640625 +24713 0.047760009765625 +24714 0.800140380859375 +24715 0.052764892578125 +24716 0.7783203125 +24717 0.05169677734375 +24718 0.6651611328125 +24719 0.044281005859375 +24720 0.45965576171875 +24721 0.0303955078125 +24722 0.199188232421875 +24723 0.0126953125 +24724 -0.050689697265625 +24725 -0.004150390625 +24726 -0.23297119140625 +24727 -0.01611328125 +24728 -0.33013916015625 +24729 -0.022003173828125 +24730 -0.368408203125 +24731 -0.02374267578125 +24732 -0.378936767578125 +24733 -0.02362060546875 +24734 -0.376983642578125 +24735 -0.0228271484375 +24736 -0.37969970703125 +24737 -0.022613525390625 +24738 -0.391510009765625 +24739 -0.0233154296875 +24740 -0.385345458984375 +24741 -0.02294921875 +24742 -0.3419189453125 +24743 -0.020111083984375 +24744 -0.28289794921875 +24745 -0.016357421875 +24746 -0.251617431640625 +24747 -0.014801025390625 +24748 -0.266143798828125 +24749 -0.01666259765625 +24750 -0.273345947265625 +24751 -0.01806640625 +24752 -0.216796875 +24753 -0.014923095703125 +24754 -0.128265380859375 +24755 -0.00946044921875 +24756 -0.068145751953125 +24757 -0.005950927734375 +24758 -0.0430908203125 +24759 -0.00482177734375 +24760 -0.024444580078125 +24761 -0.003997802734375 +24762 0.020721435546875 +24763 -0.0010986328125 +24764 0.124481201171875 +24765 0.00616455078125 +24766 0.25787353515625 +24767 0.015716552734375 +24768 0.379119873046875 +24769 0.024566650390625 +24770 0.47991943359375 +24771 0.0321044921875 +24772 0.5281982421875 +24773 0.035980224609375 +24774 0.511138916015625 +24775 0.035247802734375 +24776 0.456207275390625 +24777 0.031829833984375 +24778 0.407470703125 +24779 0.02886962890625 +24780 0.383758544921875 +24781 0.0277099609375 +24782 0.35687255859375 +24783 0.026275634765625 +24784 0.31182861328125 +24785 0.023468017578125 +24786 0.250885009765625 +24787 0.019439697265625 +24788 0.1654052734375 +24789 0.0135498046875 +24790 0.035247802734375 +24791 0.004364013671875 +24792 -0.142059326171875 +24793 -0.008270263671875 +24794 -0.33563232421875 +24795 -0.022125244140625 +24796 -0.5345458984375 +24797 -0.03643798828125 +24798 -0.72186279296875 +24799 -0.04998779296875 +24800 -0.836669921875 +24801 -0.058380126953125 +24802 -0.8326416015625 +24803 -0.05828857421875 +24804 -0.7296142578125 +24805 -0.051116943359375 +24806 -0.582550048828125 +24807 -0.040863037109375 +24808 -0.440093994140625 +24809 -0.030975341796875 +24810 -0.324310302734375 +24811 -0.02301025390625 +24812 -0.20147705078125 +24813 -0.014495849609375 +24814 -0.044647216796875 +24815 -0.00347900390625 +24816 0.103973388671875 +24817 0.0069580078125 +24818 0.202392578125 +24819 0.0137939453125 +24820 0.264495849609375 +24821 0.01806640625 +24822 0.338897705078125 +24823 0.023284912109375 +24824 0.443817138671875 +24825 0.03076171875 +24826 0.545074462890625 +24827 0.03802490234375 +24828 0.6173095703125 +24829 0.04327392578125 +24830 0.6524658203125 +24831 0.0458984375 +24832 0.66339111328125 +24833 0.04718017578125 +24834 0.6561279296875 +24835 0.047698974609375 +24836 0.606781005859375 +24837 0.045074462890625 +24838 0.501190185546875 +24839 0.03765869140625 +24840 0.352783203125 +24841 0.026611328125 +24842 0.176544189453125 +24843 0.01324462890625 +24844 -0.034820556640625 +24845 -0.00347900390625 +24846 -0.258209228515625 +24847 -0.021453857421875 +24848 -0.44244384765625 +24849 -0.035675048828125 +24850 -0.5753173828125 +24851 -0.045166015625 +24852 -0.65203857421875 +24853 -0.049652099609375 +24854 -0.641632080078125 +24855 -0.046112060546875 +24856 -0.562164306640625 +24857 -0.03656005859375 +24858 -0.458038330078125 +24859 -0.025665283203125 +24860 -0.350555419921875 +24861 -0.015625 +24862 -0.260528564453125 +24863 -0.00848388671875 +24864 -0.192108154296875 +24865 -0.0045166015625 +24866 -0.141937255859375 +24867 -0.003173828125 +24868 -0.1021728515625 +24869 -0.00341796875 +24870 -0.062896728515625 +24871 -0.003936767578125 +24872 -0.011932373046875 +24873 -0.003204345703125 +24874 0.062835693359375 +24875 0.000244140625 +24876 0.148712158203125 +24877 0.005340576171875 +24878 0.241729736328125 +24879 0.0118408203125 +24880 0.34912109375 +24881 0.020660400390625 +24882 0.457305908203125 +24883 0.030487060546875 +24884 0.54388427734375 +24885 0.0390625 +24886 0.5728759765625 +24887 0.042633056640625 +24888 0.506591796875 +24889 0.037200927734375 +24890 0.351226806640625 +24891 0.0233154296875 +24892 0.146514892578125 +24893 0.00494384765625 +24894 -0.05523681640625 +24895 -0.012603759765625 +24896 -0.21624755859375 +24897 -0.025604248046875 +24898 -0.334930419921875 +24899 -0.03411865234375 +24900 -0.402984619140625 +24901 -0.0374755859375 +24902 -0.4412841796875 +24903 -0.03802490234375 +24904 -0.49578857421875 +24905 -0.040771484375 +24906 -0.5601806640625 +24907 -0.045196533203125 +24908 -0.600738525390625 +24909 -0.047882080078125 +24910 -0.584228515625 +24911 -0.045440673828125 +24912 -0.47930908203125 +24913 -0.03466796875 +24914 -0.27935791015625 +24915 -0.014801025390625 +24916 -0.0089111328125 +24917 0.011627197265625 +24918 0.268798828125 +24919 0.038177490234375 +24920 0.482818603515625 +24921 0.057586669921875 +24922 0.60369873046875 +24923 0.066986083984375 +24924 0.650421142578125 +24925 0.068511962890625 +24926 0.66400146484375 +24927 0.066650390625 +24928 0.6414794921875 +24929 0.061279296875 +24930 0.572540283203125 +24931 0.051483154296875 +24932 0.498138427734375 +24933 0.0416259765625 +24934 0.439453125 +24935 0.034027099609375 +24936 0.375518798828125 +24937 0.026580810546875 +24938 0.274505615234375 +24939 0.0159912109375 +24940 0.1087646484375 +24941 -0.0006103515625 +24942 -0.099395751953125 +24943 -0.020965576171875 +24944 -0.3182373046875 +24945 -0.041839599609375 +24946 -0.5489501953125 +24947 -0.0634765625 +24948 -0.7738037109375 +24949 -0.08416748046875 +24950 -0.86383056640625 +24951 -0.09857177734375 +24952 -0.870391845703125 +24953 -0.1033935546875 +24954 -0.86895751953125 +24955 -0.10064697265625 +24956 -0.861053466796875 +24957 -0.091827392578125 +24958 -0.765869140625 +24959 -0.075286865234375 +24960 -0.5301513671875 +24961 -0.049957275390625 +24962 -0.214691162109375 +24963 -0.0166015625 +24964 0.137359619140625 +24965 0.020233154296875 +24966 0.474822998046875 +24967 0.055206298828125 +24968 0.76239013671875 +24969 0.084686279296875 +24970 0.867462158203125 +24971 0.105926513671875 +24972 0.870361328125 +24973 0.119049072265625 +24974 0.86480712890625 +24975 0.122955322265625 +24976 0.831817626953125 +24977 0.11834716796875 +24978 0.677581787109375 +24979 0.10791015625 +24980 0.495880126953125 +24981 0.092437744140625 +24982 0.30767822265625 +24983 0.073974609375 +24984 0.116180419921875 +24985 0.0528564453125 +24986 -0.110748291015625 +24987 0.02587890625 +24988 -0.381805419921875 +24989 -0.007598876953125 +24990 -0.6572265625 +24991 -0.0430908203125 +24992 -0.857421875 +24993 -0.0743408203125 +24994 -0.870391845703125 +24995 -0.096954345703125 +24996 -0.870391845703125 +24997 -0.110260009765625 +24998 -0.86444091796875 +24999 -0.117156982421875 +25000 -0.85723876953125 +25001 -0.121429443359375 +25002 -0.790008544921875 +25003 -0.121307373046875 +25004 -0.62847900390625 +25005 -0.11126708984375 +25006 -0.3956298828125 +25007 -0.091094970703125 +25008 -0.126708984375 +25009 -0.064300537109375 +25010 0.150115966796875 +25011 -0.0338134765625 +25012 0.424041748046875 +25013 -0.0009765625 +25014 0.670623779296875 +25015 0.031341552734375 +25016 0.854522705078125 +25017 0.059051513671875 +25018 0.866485595703125 +25019 0.080352783203125 +25020 0.86920166015625 +25021 0.093658447265625 +25022 0.8653564453125 +25023 0.100921630859375 +25024 0.857147216796875 +25025 0.103607177734375 +25026 0.766845703125 +25027 0.10150146484375 +25028 0.628509521484375 +25029 0.09521484375 +25030 0.462127685546875 +25031 0.08416748046875 +25032 0.297210693359375 +25033 0.071136474609375 +25034 0.14862060546875 +25035 0.057464599609375 +25036 -0.00537109375 +25037 0.040863037109375 +25038 -0.15753173828125 +25039 0.022186279296875 +25040 -0.31304931640625 +25041 0.00115966796875 +25042 -0.48876953125 +25043 -0.02362060546875 +25044 -0.6416015625 +25045 -0.04730224609375 +25046 -0.751373291015625 +25047 -0.06732177734375 +25048 -0.84619140625 +25049 -0.086090087890625 +25050 -0.861297607421875 +25051 -0.102142333984375 +25052 -0.863250732421875 +25053 -0.112091064453125 +25054 -0.856597900390625 +25055 -0.112701416015625 +25056 -0.7498779296875 +25057 -0.1053466796875 +25058 -0.624542236328125 +25059 -0.09613037109375 +25060 -0.47808837890625 +25061 -0.0828857421875 +25062 -0.253387451171875 +25063 -0.059600830078125 +25064 0.003692626953125 +25065 -0.031097412109375 +25066 0.2257080078125 +25067 -0.00457763671875 +25068 0.427154541015625 +25069 0.021209716796875 +25070 0.643218994140625 +25071 0.049652099609375 +25072 0.855926513671875 +25073 0.0797119140625 +25074 0.870361328125 +25075 0.105438232421875 +25076 0.870361328125 +25077 0.121673583984375 +25078 0.862762451171875 +25079 0.1292724609375 +25080 0.79669189453125 +25081 0.127960205078125 +25082 0.595794677734375 +25083 0.116851806640625 +25084 0.362152099609375 +25085 0.09906005859375 +25086 0.1270751953125 +25087 0.077606201171875 +25088 -0.086944580078125 +25089 0.0552978515625 +25090 -0.2784423828125 +25091 0.03271484375 +25092 -0.484832763671875 +25093 0.0048828125 +25094 -0.729583740234375 +25095 -0.0316162109375 +25096 -0.86688232421875 +25097 -0.07061767578125 +25098 -0.870391845703125 +25099 -0.104156494140625 +25100 -0.86859130859375 +25101 -0.131988525390625 +25102 -0.86279296875 +25103 -0.154205322265625 +25104 -0.817962646484375 +25105 -0.1661376953125 +25106 -0.6116943359375 +25107 -0.161712646484375 +25108 -0.3128662109375 +25109 -0.139892578125 +25110 0.039398193359375 +25111 -0.105072021484375 +25112 0.422821044921875 +25113 -0.059722900390625 +25114 0.805145263671875 +25115 -0.008026123046875 +25116 0.870361328125 +25117 0.041107177734375 +25118 0.870361328125 +25119 0.08038330078125 +25120 0.860015869140625 +25121 0.108673095703125 +25122 0.727935791015625 +25123 0.12530517578125 +25124 0.48114013671875 +25125 0.1298828125 +25126 0.2059326171875 +25127 0.126007080078125 +25128 -0.06103515625 +25129 0.116943359375 +25130 -0.29913330078125 +25131 0.10418701171875 +25132 -0.516204833984375 +25133 0.0858154296875 +25134 -0.7252197265625 +25135 0.05975341796875 +25136 -0.85980224609375 +25137 0.029266357421875 +25138 -0.870391845703125 +25139 -0.0010986328125 +25140 -0.870391845703125 +25141 -0.027587890625 +25142 -0.858062744140625 +25143 -0.0438232421875 +25144 -0.673004150390625 +25145 -0.049560546875 +25146 -0.42694091796875 +25147 -0.05224609375 +25148 -0.2100830078125 +25149 -0.05816650390625 +25150 -0.0362548828125 +25151 -0.067291259765625 +25152 0.10943603515625 +25153 -0.07586669921875 +25154 0.23516845703125 +25155 -0.081329345703125 +25156 0.373687744140625 +25157 -0.07818603515625 +25158 0.517791748046875 +25159 -0.066741943359375 +25160 0.602783203125 +25161 -0.055572509765625 +25162 0.635711669921875 +25163 -0.0439453125 +25164 0.655181884765625 +25165 -0.0272216796875 +25166 0.65948486328125 +25167 -0.006591796875 +25168 0.651275634765625 +25169 0.016998291015625 +25170 0.61846923828125 +25171 0.0404052734375 +25172 0.53753662109375 +25173 0.058837890625 +25174 0.404144287109375 +25175 0.070037841796875 +25176 0.22186279296875 +25177 0.072906494140625 +25178 0.003997802734375 +25179 0.067840576171875 +25180 -0.22100830078125 +25181 0.05743408203125 +25182 -0.42449951171875 +25183 0.04461669921875 +25184 -0.579833984375 +25185 0.0323486328125 +25186 -0.641876220703125 +25187 0.026458740234375 +25188 -0.6177978515625 +25189 0.0260009765625 +25190 -0.575531005859375 +25191 0.022125244140625 +25192 -0.526336669921875 +25193 0.01397705078125 +25194 -0.42645263671875 +25195 0.00848388671875 +25196 -0.2581787109375 +25197 0.009185791015625 +25198 -0.068695068359375 +25199 0.010955810546875 +25200 0.09222412109375 +25201 0.0084228515625 +25202 0.232147216796875 +25203 0.00396728515625 +25204 0.3509521484375 +25205 -0.001129150390625 +25206 0.410064697265625 +25207 -0.011016845703125 +25208 0.372955322265625 +25209 -0.029815673828125 +25210 0.2554931640625 +25211 -0.054718017578125 +25212 0.10711669921875 +25213 -0.078643798828125 +25214 -0.052886962890625 +25215 -0.098907470703125 +25216 -0.186279296875 +25217 -0.110565185546875 +25218 -0.23291015625 +25219 -0.105926513671875 +25220 -0.209442138671875 +25221 -0.087982177734375 +25222 -0.174163818359375 +25223 -0.065582275390625 +25224 -0.126739501953125 +25225 -0.03973388671875 +25226 -0.048126220703125 +25227 -0.00897216796875 +25228 0.0426025390625 +25229 0.02301025390625 +25230 0.10748291015625 +25231 0.049957275390625 +25232 0.1409912109375 +25233 0.070159912109375 +25234 0.19708251953125 +25235 0.090179443359375 +25236 0.273651123046875 +25237 0.109161376953125 +25238 0.31768798828125 +25239 0.119537353515625 +25240 0.341094970703125 +25241 0.122833251953125 +25242 0.368011474609375 +25243 0.1224365234375 +25244 0.37249755859375 +25245 0.11517333984375 +25246 0.30072021484375 +25247 0.09423828125 +25248 0.1517333984375 +25249 0.060211181640625 +25250 -0.01470947265625 +25251 0.02203369140625 +25252 -0.1883544921875 +25253 -0.0179443359375 +25254 -0.372711181640625 +25255 -0.059295654296875 +25256 -0.51397705078125 +25257 -0.09381103515625 +25258 -0.57177734375 +25259 -0.115203857421875 +25260 -0.53948974609375 +25261 -0.12188720703125 +25262 -0.43511962890625 +25263 -0.11578369140625 +25264 -0.2962646484375 +25265 -0.101654052734375 +25266 -0.161102294921875 +25267 -0.08453369140625 +25268 -0.0435791015625 +25269 -0.066314697265625 +25270 0.060394287109375 +25271 -0.046661376953125 +25272 0.13665771484375 +25273 -0.02789306640625 +25274 0.170135498046875 +25275 -0.01263427734375 +25276 0.16552734375 +25277 -0.000885009765625 +25278 0.15728759765625 +25279 0.01129150390625 +25280 0.150787353515625 +25281 0.02386474609375 +25282 0.12200927734375 +25283 0.0328369140625 +25284 0.080108642578125 +25285 0.03875732421875 +25286 0.05126953125 +25287 0.04461669921875 +25288 0.062896728515625 +25289 0.05364990234375 +25290 0.09271240234375 +25291 0.062469482421875 +25292 0.092987060546875 +25293 0.064422607421875 +25294 0.07855224609375 +25295 0.061492919921875 +25296 0.06427001953125 +25297 0.055816650390625 +25298 0.0347900390625 +25299 0.04559326171875 +25300 -0.01171875 +25301 0.031005859375 +25302 -0.056060791015625 +25303 0.015167236328125 +25304 -0.055511474609375 +25305 0.004486083984375 +25306 -0.010467529296875 +25307 -0.000457763671875 +25308 0.02508544921875 +25309 -0.006378173828125 +25310 0.025665283203125 +25311 -0.01617431640625 +25312 0.017333984375 +25313 -0.02581787109375 +25314 0.00189208984375 +25315 -0.03460693359375 +25316 -0.03173828125 +25317 -0.04376220703125 +25318 -0.071502685546875 +25319 -0.05145263671875 +25320 -0.13543701171875 +25321 -0.06005859375 +25322 -0.219970703125 +25323 -0.069183349609375 +25324 -0.300506591796875 +25325 -0.075653076171875 +25326 -0.376312255859375 +25327 -0.079681396484375 +25328 -0.416107177734375 +25329 -0.077423095703125 +25330 -0.371124267578125 +25331 -0.06268310546875 +25332 -0.242279052734375 +25333 -0.036102294921875 +25334 -0.069732666015625 +25335 -0.003631591796875 +25336 0.125640869140625 +25337 0.0313720703125 +25338 0.31268310546875 +25339 0.064208984375 +25340 0.45501708984375 +25341 0.08953857421875 +25342 0.554779052734375 +25343 0.107391357421875 +25344 0.61065673828125 +25345 0.11761474609375 +25346 0.610931396484375 +25347 0.118408203125 +25348 0.531463623046875 +25349 0.105865478515625 +25350 0.3883056640625 +25351 0.08245849609375 +25352 0.23468017578125 +25353 0.0562744140625 +25354 0.095245361328125 +25355 0.03118896484375 +25356 -0.00396728515625 +25357 0.011322021484375 +25358 -0.04852294921875 +25359 -0.000885009765625 +25360 -0.055145263671875 +25361 -0.007598876953125 +25362 -0.0758056640625 +25363 -0.016326904296875 +25364 -0.138702392578125 +25365 -0.030975341796875 +25366 -0.209197998046875 +25367 -0.046051025390625 +25368 -0.289031982421875 +25369 -0.06158447265625 +25370 -0.37884521484375 +25371 -0.077484130859375 +25372 -0.456329345703125 +25373 -0.090301513671875 +25374 -0.51641845703125 +25375 -0.0992431640625 +25376 -0.519287109375 +25377 -0.098388671875 +25378 -0.458251953125 +25379 -0.08685302734375 +25380 -0.384796142578125 +25381 -0.072509765625 +25382 -0.323699951171875 +25383 -0.059295654296875 +25384 -0.269287109375 +25385 -0.046539306640625 +25386 -0.1951904296875 +25387 -0.03057861328125 +25388 -0.100006103515625 +25389 -0.011474609375 +25390 -0.01055908203125 +25391 0.006439208984375 +25392 0.1033935546875 +25393 0.027435302734375 +25394 0.24908447265625 +25395 0.05242919921875 +25396 0.373199462890625 +25397 0.073272705078125 +25398 0.45806884765625 +25399 0.08721923828125 +25400 0.511474609375 +25401 0.09539794921875 +25402 0.565399169921875 +25403 0.102630615234375 +25404 0.61138916015625 +25405 0.10772705078125 +25406 0.5897216796875 +25407 0.101837158203125 +25408 0.4906005859375 +25409 0.08367919921875 +25410 0.33148193359375 +25411 0.056060791015625 +25412 0.147796630859375 +25413 0.024505615234375 +25414 -0.01873779296875 +25415 -0.004486083984375 +25416 -0.140289306640625 +25417 -0.0264892578125 +25418 -0.191986083984375 +25419 -0.037567138671875 +25420 -0.184295654296875 +25421 -0.03912353515625 +25422 -0.161834716796875 +25423 -0.0377197265625 +25424 -0.166595458984375 +25425 -0.039581298828125 +25426 -0.19390869140625 +25427 -0.043975830078125 +25428 -0.22442626953125 +25429 -0.048004150390625 +25430 -0.279754638671875 +25431 -0.054962158203125 +25432 -0.3389892578125 +25433 -0.061798095703125 +25434 -0.3543701171875 +25435 -0.0615234375 +25436 -0.348175048828125 +25437 -0.0576171875 +25438 -0.32598876953125 +25439 -0.051055908203125 +25440 -0.2581787109375 +25441 -0.03759765625 +25442 -0.139801025390625 +25443 -0.016693115234375 +25444 0.014617919921875 +25445 0.009307861328125 +25446 0.144378662109375 +25447 0.0311279296875 +25448 0.221038818359375 +25449 0.044403076171875 +25450 0.27069091796875 +25451 0.052947998046875 +25452 0.294036865234375 +25453 0.056854248046875 +25454 0.311767578125 +25455 0.0592041015625 +25456 0.339141845703125 +25457 0.0623779296875 +25458 0.360260009765625 +25459 0.064300537109375 +25460 0.360504150390625 +25461 0.06280517578125 +25462 0.308380126953125 +25463 0.052581787109375 +25464 0.18170166015625 +25465 0.029937744140625 +25466 0.0047607421875 +25467 -0.000946044921875 +25468 -0.17559814453125 +25469 -0.032196044921875 +25470 -0.3143310546875 +25471 -0.056243896484375 +25472 -0.36785888671875 +25473 -0.065765380859375 +25474 -0.36248779296875 +25475 -0.06512451171875 +25476 -0.343536376953125 +25477 -0.06195068359375 +25478 -0.3018798828125 +25479 -0.05474853515625 +25480 -0.231414794921875 +25481 -0.042510986328125 +25482 -0.117645263671875 +25483 -0.0228271484375 +25484 0.007049560546875 +25485 -0.001190185546875 +25486 0.087982177734375 +25487 0.01318359375 +25488 0.13946533203125 +25489 0.02264404296875 +25490 0.17425537109375 +25491 0.029327392578125 +25492 0.188201904296875 +25493 0.032470703125 +25494 0.171234130859375 +25495 0.03033447265625 +25496 0.118438720703125 +25497 0.0220947265625 +25498 0.05706787109375 +25499 0.012298583984375 +25500 -0.010711669921875 +25501 0.00128173828125 +25502 -0.0914306640625 +25503 -0.01202392578125 +25504 -0.162322998046875 +25505 -0.023834228515625 +25506 -0.194549560546875 +25507 -0.029327392578125 +25508 -0.1492919921875 +25509 -0.02197265625 +25510 -0.02166748046875 +25511 -0.000946044921875 +25512 0.124053955078125 +25513 0.02301025390625 +25514 0.211151123046875 +25515 0.0369873046875 +25516 0.240447998046875 +25517 0.041168212890625 +25518 0.242218017578125 +25519 0.04071044921875 +25520 0.2257080078125 +25521 0.037200927734375 +25522 0.194366455078125 +25523 0.03125 +25524 0.115509033203125 +25525 0.017425537109375 +25526 0.0128173828125 +25527 -0.000244140625 +25528 -0.053802490234375 +25529 -0.01165771484375 +25530 -0.110626220703125 +25531 -0.021240234375 +25532 -0.199493408203125 +25533 -0.036041259765625 +25534 -0.29437255859375 +25535 -0.05169677734375 +25536 -0.33221435546875 +25537 -0.0576171875 +25538 -0.27972412109375 +25539 -0.04827880859375 +25540 -0.185333251953125 +25541 -0.031829833984375 +25542 -0.128204345703125 +25543 -0.0216064453125 +25544 -0.115692138671875 +25545 -0.01885986328125 +25546 -0.116455078125 +25547 -0.01837158203125 +25548 -0.105926513671875 +25549 -0.016021728515625 +25550 -0.053955078125 +25551 -0.006805419921875 +25552 0.048797607421875 +25553 0.01080322265625 +25554 0.157318115234375 +25555 0.02923583984375 +25556 0.212005615234375 +25557 0.0384521484375 +25558 0.218475341796875 +25559 0.039398193359375 +25560 0.23724365234375 +25561 0.042266845703125 +25562 0.30535888671875 +25563 0.053314208984375 +25564 0.38128662109375 +25565 0.065582275390625 +25566 0.404449462890625 +25567 0.068878173828125 +25568 0.3944091796875 +25569 0.066558837890625 +25570 0.3885498046875 +25571 0.06494140625 +25572 0.362640380859375 +25573 0.059967041015625 +25574 0.27362060546875 +25575 0.044464111328125 +25576 0.11712646484375 +25577 0.017730712890625 +25578 -0.054901123046875 +25579 -0.011444091796875 +25580 -0.19085693359375 +25581 -0.034393310546875 +25582 -0.28570556640625 +25583 -0.050262451171875 +25584 -0.339263916015625 +25585 -0.059051513671875 +25586 -0.3775634765625 +25587 -0.065155029296875 +25588 -0.445709228515625 +25589 -0.076171875 +25590 -0.535064697265625 +25591 -0.090667724609375 +25592 -0.629058837890625 +25593 -0.10589599609375 +25594 -0.697601318359375 +25595 -0.1168212890625 +25596 -0.70391845703125 +25597 -0.117279052734375 +25598 -0.6424560546875 +25599 -0.10638427734375 +25600 -0.491241455078125 +25601 -0.080047607421875 +25602 -0.265716552734375 +25603 -0.04071044921875 +25604 -0.023712158203125 +25605 0.0010986328125 +25606 0.201751708984375 +25607 0.039276123046875 +25608 0.375823974609375 +25609 0.0673828125 +25610 0.485076904296875 +25611 0.083221435546875 +25612 0.56884765625 +25613 0.095001220703125 +25614 0.634765625 +25615 0.1044921875 +25616 0.63763427734375 +25617 0.102813720703125 +25618 0.5660400390625 +25619 0.0877685546875 +25620 0.4720458984375 +25621 0.069732666015625 +25622 0.40692138671875 +25623 0.058868408203125 +25624 0.3778076171875 +25625 0.056427001953125 +25626 0.376953125 +25627 0.06060791015625 +25628 0.371978759765625 +25629 0.064697265625 +25630 0.313140869140625 +25631 0.05841064453125 +25632 0.184417724609375 +25633 0.0382080078125 +25634 0.011199951171875 +25635 0.008880615234375 +25636 -0.171051025390625 +25637 -0.022735595703125 +25638 -0.33740234375 +25639 -0.051910400390625 +25640 -0.47198486328125 +25641 -0.075653076171875 +25642 -0.560394287109375 +25643 -0.09124755859375 +25644 -0.58056640625 +25645 -0.0943603515625 +25646 -0.54754638671875 +25647 -0.0880126953125 +25648 -0.508575439453125 +25649 -0.081634521484375 +25650 -0.459503173828125 +25651 -0.07427978515625 +25652 -0.394378662109375 +25653 -0.064605712890625 +25654 -0.35260009765625 +25655 -0.06024169921875 +25656 -0.31170654296875 +25657 -0.05645751953125 +25658 -0.197418212890625 +25659 -0.038177490234375 +25660 -0.007965087890625 +25661 -0.004791259765625 +25662 0.207489013671875 +25663 0.0340576171875 +25664 0.409210205078125 +25665 0.0706787109375 +25666 0.57208251953125 +25667 0.1002197265625 +25668 0.66595458984375 +25669 0.1168212890625 +25670 0.65875244140625 +25671 0.1141357421875 +25672 0.56744384765625 +25673 0.09564208984375 +25674 0.431396484375 +25675 0.069183349609375 +25676 0.29443359375 +25677 0.04345703125 +25678 0.182464599609375 +25679 0.023529052734375 +25680 0.06365966796875 +25681 0.002899169921875 +25682 -0.075958251953125 +25683 -0.02142333984375 +25684 -0.189422607421875 +25685 -0.040252685546875 +25686 -0.271942138671875 +25687 -0.052825927734375 +25688 -0.342529296875 +25689 -0.06317138671875 +25690 -0.364166259765625 +25691 -0.064117431640625 +25692 -0.327239990234375 +25693 -0.053924560546875 +25694 -0.2769775390625 +25695 -0.041778564453125 +25696 -0.253692626953125 +25697 -0.035797119140625 +25698 -0.24365234375 +25699 -0.033294677734375 +25700 -0.1983642578125 +25701 -0.024566650390625 +25702 -0.116241455078125 +25703 -0.00927734375 +25704 -0.036834716796875 +25705 0.004730224609375 +25706 0.034881591796875 +25707 0.0166015625 +25708 0.09124755859375 +25709 0.024932861328125 +25710 0.10888671875 +25711 0.025238037109375 +25712 0.125518798828125 +25713 0.025238037109375 +25714 0.15771484375 +25715 0.0284423828125 +25716 0.17828369140625 +25717 0.02960205078125 +25718 0.17108154296875 +25719 0.025604248046875 +25720 0.129974365234375 +25721 0.015380859375 +25722 0.082427978515625 +25723 0.0045166015625 +25724 0.027679443359375 +25725 -0.007049560546875 +25726 -0.065643310546875 +25727 -0.02557373046875 +25728 -0.15936279296875 +25729 -0.04345703125 +25730 -0.21307373046875 +25731 -0.052703857421875 +25732 -0.234649658203125 +25733 -0.05499267578125 +25734 -0.2001953125 +25735 -0.045684814453125 +25736 -0.119171142578125 +25737 -0.026824951171875 +25738 -0.024749755859375 +25739 -0.00518798828125 +25740 0.085784912109375 +25741 0.01959228515625 +25742 0.178131103515625 +25743 0.040496826171875 +25744 0.215576171875 +25745 0.050079345703125 +25746 0.211456298828125 +25747 0.0509033203125 +25748 0.17523193359375 +25749 0.0447998046875 +25750 0.128753662109375 +25751 0.036102294921875 +25752 0.1019287109375 +25753 0.03076171875 +25754 0.0743408203125 +25755 0.02471923828125 +25756 0.04327392578125 +25757 0.0174560546875 +25758 0.038177490234375 +25759 0.01495361328125 +25760 0.076263427734375 +25761 0.020721435546875 +25762 0.14105224609375 +25763 0.031585693359375 +25764 0.186431884765625 +25765 0.038421630859375 +25766 0.188812255859375 +25767 0.036651611328125 +25768 0.1390380859375 +25769 0.024566650390625 +25770 0.041778564453125 +25771 0.00323486328125 +25772 -0.079437255859375 +25773 -0.02252197265625 +25774 -0.219390869140625 +25775 -0.051605224609375 +25776 -0.367828369140625 +25777 -0.081878662109375 +25778 -0.494873046875 +25779 -0.107391357421875 +25780 -0.556243896484375 +25781 -0.119293212890625 +25782 -0.508697509765625 +25783 -0.10894775390625 +25784 -0.3756103515625 +25785 -0.081085205078125 +25786 -0.218902587890625 +25787 -0.048187255859375 +25788 -0.063751220703125 +25789 -0.015380859375 +25790 0.091552734375 +25791 0.017486572265625 +25792 0.23602294921875 +25793 0.04815673828125 +25794 0.342987060546875 +25795 0.07122802734375 +25796 0.39520263671875 +25797 0.083160400390625 +25798 0.389373779296875 +25799 0.083221435546875 +25800 0.324249267578125 +25801 0.07110595703125 +25802 0.224090576171875 +25803 0.0516357421875 +25804 0.124267578125 +25805 0.0318603515625 +25806 0.037078857421875 +25807 0.01422119140625 +25808 -0.010101318359375 +25809 0.004241943359375 +25810 -0.019439697265625 +25811 0.001495361328125 +25812 -0.022796630859375 +25813 -0.00030517578125 +25814 -0.001556396484375 +25815 0.002593994140625 +25816 0.056304931640625 +25817 0.0126953125 +25818 0.106719970703125 +25819 0.021240234375 +25820 0.096893310546875 +25821 0.017791748046875 +25822 0.042694091796875 +25823 0.005584716796875 +25824 -0.018035888671875 +25825 -0.0076904296875 +25826 -0.07586669921875 +25827 -0.020111083984375 +25828 -0.11944580078125 +25829 -0.02935791015625 +25830 -0.15972900390625 +25831 -0.03759765625 +25832 -0.202606201171875 +25833 -0.0460205078125 +25834 -0.24859619140625 +25835 -0.054718017578125 +25836 -0.30517578125 +25837 -0.065216064453125 +25838 -0.36212158203125 +25839 -0.0755615234375 +25840 -0.39141845703125 +25841 -0.0802001953125 +25842 -0.35528564453125 +25843 -0.0716552734375 +25844 -0.249969482421875 +25845 -0.04925537109375 +25846 -0.092864990234375 +25847 -0.016571044921875 +25848 0.08905029296875 +25849 0.020904541015625 +25850 0.2352294921875 +25851 0.051025390625 +25852 0.318817138671875 +25853 0.068389892578125 +25854 0.358642578125 +25855 0.07672119140625 +25856 0.347747802734375 +25857 0.07403564453125 +25858 0.28564453125 +25859 0.0595703125 +25860 0.223175048828125 +25861 0.04473876953125 +25862 0.196746826171875 +25863 0.0382080078125 +25864 0.179840087890625 +25865 0.034088134765625 +25866 0.155548095703125 +25867 0.028594970703125 +25868 0.151214599609375 +25869 0.02813720703125 +25870 0.156951904296875 +25871 0.030426025390625 +25872 0.13177490234375 +25873 0.025909423828125 +25874 0.100799560546875 +25875 0.0203857421875 +25876 0.087127685546875 +25877 0.01910400390625 +25878 0.05487060546875 +25879 0.01361083984375 +25880 -0.009002685546875 +25881 0.000762939453125 +25882 -0.10400390625 +25883 -0.0194091796875 +25884 -0.229400634765625 +25885 -0.046875 +25886 -0.35552978515625 +25887 -0.074859619140625 +25888 -0.441925048828125 +25889 -0.094024658203125 +25890 -0.473846435546875 +25891 -0.10101318359375 +25892 -0.464813232421875 +25893 -0.098968505859375 +25894 -0.419097900390625 +25895 -0.0888671875 +25896 -0.334320068359375 +25897 -0.07012939453125 +25898 -0.227935791015625 +25899 -0.0467529296875 +25900 -0.12347412109375 +25901 -0.02410888671875 +25902 -0.02764892578125 +25903 -0.003631591796875 +25904 0.077667236328125 +25905 0.018951416015625 +25906 0.2132568359375 +25907 0.048553466796875 +25908 0.38885498046875 +25909 0.0875244140625 +25910 0.582794189453125 +25911 0.130950927734375 +25912 0.734039306640625 +25913 0.16473388671875 +25914 0.800140380859375 +25915 0.1790771484375 +25916 0.7783203125 +25917 0.17340087890625 +25918 0.6651611328125 +25919 0.146942138671875 +25920 0.45965576171875 +25921 0.0994873046875 +25922 0.199188232421875 +25923 0.039703369140625 +25924 -0.050689697265625 +25925 -0.01727294921875 +25926 -0.23297119140625 +25927 -0.058258056640625 +25928 -0.33013916015625 +25929 -0.07928466796875 +25930 -0.368408203125 +25931 -0.086517333984375 +25932 -0.378936767578125 +25933 -0.0872802734375 +25934 -0.376983642578125 +25935 -0.085235595703125 +25936 -0.37969970703125 +25937 -0.084442138671875 +25938 -0.391510009765625 +25939 -0.085968017578125 +25940 -0.385345458984375 +25941 -0.083587646484375 +25942 -0.3419189453125 +25943 -0.072906494140625 +25944 -0.28289794921875 +25945 -0.0589599609375 +25946 -0.251617431640625 +25947 -0.051788330078125 +25948 -0.266143798828125 +25949 -0.0555419921875 +25950 -0.273345947265625 +25951 -0.05792236328125 +25952 -0.216796875 +25953 -0.0457763671875 +25954 -0.128265380859375 +25955 -0.0263671875 +25956 -0.068145751953125 +25957 -0.013671875 +25958 -0.0430908203125 +25959 -0.009124755859375 +25960 -0.024444580078125 +25961 -0.00604248046875 +25962 0.020721435546875 +25963 0.00323486328125 +25964 0.124481201171875 +25965 0.026214599609375 +25966 0.25787353515625 +25967 0.056243896484375 +25968 0.379119873046875 +25969 0.08367919921875 +25970 0.47991943359375 +25971 0.10662841796875 +25972 0.5281982421875 +25973 0.117645263671875 +25974 0.511138916015625 +25975 0.11376953125 +25976 0.456207275390625 +25977 0.101348876953125 +25978 0.407470703125 +25979 0.090606689453125 +25980 0.383758544921875 +25981 0.085845947265625 +25982 0.35687255859375 +25983 0.080474853515625 +25984 0.31182861328125 +25985 0.07098388671875 +25986 0.250885009765625 +25987 0.057830810546875 +25988 0.1654052734375 +25989 0.038970947265625 +25990 0.035247802734375 +25991 0.009674072265625 +25992 -0.142059326171875 +25993 -0.0306396484375 +25994 -0.33563232421875 +25995 -0.074859619140625 +25996 -0.5345458984375 +25997 -0.120452880859375 +25998 -0.72186279296875 +25999 -0.163543701171875 +26000 -0.836669921875 +26001 -0.189971923828125 +26002 -0.8326416015625 +26003 -0.18902587890625 +26004 -0.7296142578125 +26005 -0.165313720703125 +26006 -0.582550048828125 +26007 -0.131591796875 +26008 -0.440093994140625 +26009 -0.09912109375 +26010 -0.324310302734375 +26011 -0.07293701171875 +26012 -0.20147705078125 +26013 -0.045196533203125 +26014 -0.044647216796875 +26015 -0.00958251953125 +26016 0.103973388671875 +26017 0.02410888671875 +26018 0.202392578125 +26019 0.046173095703125 +26020 0.264495849609375 +26021 0.05987548828125 +26022 0.338897705078125 +26023 0.0765380859375 +26024 0.443817138671875 +26025 0.10040283203125 +26026 0.545074462890625 +26027 0.123565673828125 +26028 0.6173095703125 +26029 0.140167236328125 +26030 0.6524658203125 +26031 0.1483154296875 +26032 0.66339111328125 +26033 0.1510009765625 +26034 0.6561279296875 +26035 0.149627685546875 +26036 0.606781005859375 +26037 0.13861083984375 +26038 0.501190185546875 +26039 0.1146240234375 +26040 0.352783203125 +26041 0.080780029296875 +26042 0.176544189453125 +26043 0.040496826171875 +26044 -0.034820556640625 +26045 -0.007904052734375 +26046 -0.258209228515625 +26047 -0.059051513671875 +26048 -0.44244384765625 +26049 -0.10113525390625 +26050 -0.5753173828125 +26051 -0.131378173828125 +26052 -0.65203857421875 +26053 -0.148681640625 +26054 -0.641632080078125 +26055 -0.145904541015625 +26056 -0.562164306640625 +26057 -0.127288818359375 +26058 -0.458038330078125 +26059 -0.103118896484375 +26060 -0.350555419921875 +26061 -0.078338623046875 +26062 -0.260528564453125 +26063 -0.0577392578125 +26064 -0.192108154296875 +26065 -0.042266845703125 +26066 -0.141937255859375 +26067 -0.031097412109375 +26068 -0.1021728515625 +26069 -0.02239990234375 +26070 -0.062896728515625 +26071 -0.01385498046875 +26072 -0.011932373046875 +26073 -0.0025634765625 +26074 0.062835693359375 +26075 0.0142822265625 +26076 0.148712158203125 +26077 0.033721923828125 +26078 0.241729736328125 +26079 0.05487060546875 +26080 0.34912109375 +26081 0.079437255859375 +26082 0.457305908203125 +26083 0.104278564453125 +26084 0.54388427734375 +26085 0.12420654296875 +26086 0.5728759765625 +26087 0.130889892578125 +26088 0.506591796875 +26089 0.1156005859375 +26090 0.351226806640625 +26091 0.07977294921875 +26092 0.146514892578125 +26093 0.0325927734375 +26094 -0.05523681640625 +26095 -0.0137939453125 +26096 -0.21624755859375 +26097 -0.050689697265625 +26098 -0.334930419921875 +26099 -0.07769775390625 +26100 -0.402984619140625 +26101 -0.092926025390625 +26102 -0.4412841796875 +26103 -0.10125732421875 +26104 -0.49578857421875 +26105 -0.1134033203125 +26106 -0.5601806640625 +26107 -0.1279296875 +26108 -0.600738525390625 +26109 -0.13702392578125 +26110 -0.584228515625 +26111 -0.133026123046875 +26112 -0.47930908203125 +26113 -0.10833740234375 +26114 -0.27935791015625 +26115 -0.06072998046875 +26116 -0.0089111328125 +26117 0.004241943359375 +26118 0.268798828125 +26119 0.070587158203125 +26120 0.482818603515625 +26121 0.1202392578125 +26122 0.60369873046875 +26123 0.145965576171875 +26124 0.650421142578125 +26125 0.153167724609375 +26126 0.66400146484375 +26127 0.15301513671875 +26128 0.6414794921875 +26129 0.144866943359375 +26130 0.572540283203125 +26131 0.1260986328125 +26132 0.498138427734375 +26133 0.107452392578125 +26134 0.439453125 +26135 0.09442138671875 +26136 0.375518798828125 +26137 0.08123779296875 +26138 0.274505615234375 +26139 0.059234619140625 +26140 0.1087646484375 +26141 0.02081298828125 +26142 -0.099395751953125 +26143 -0.028472900390625 +26144 -0.3182373046875 +26145 -0.080535888671875 +26146 -0.5489501953125 +26147 -0.13604736328125 +26148 -0.7738037109375 +26149 -0.190582275390625 +26150 -0.86383056640625 +26151 -0.23046875 +26152 -0.870391845703125 +26153 -0.247100830078125 +26154 -0.86895751953125 +26155 -0.24530029296875 +26156 -0.861053466796875 +26157 -0.22857666015625 +26158 -0.765869140625 +26159 -0.192352294921875 +26160 -0.5301513671875 +26161 -0.13360595703125 +26162 -0.214691162109375 +26163 -0.054046630859375 +26164 0.137359619140625 +26165 0.03509521484375 +26166 0.474822998046875 +26167 0.12054443359375 +26168 0.76239013671875 +26169 0.19317626953125 +26170 0.867462158203125 +26171 0.24615478515625 +26172 0.870361328125 +26173 0.279876708984375 +26174 0.86480712890625 +26175 0.29150390625 +26176 0.831817626953125 +26177 0.28265380859375 +26178 0.677581787109375 +26179 0.259918212890625 +26180 0.495880126953125 +26181 0.225006103515625 +26182 0.30767822265625 +26183 0.182861328125 +26184 0.116180419921875 +26185 0.13409423828125 +26186 -0.110748291015625 +26187 0.070281982421875 +26188 -0.381805419921875 +26189 -0.01043701171875 +26190 -0.6572265625 +26191 -0.096923828125 +26192 -0.857421875 +26193 -0.173553466796875 +26194 -0.870391845703125 +26195 -0.229217529296875 +26196 -0.870391845703125 +26197 -0.26226806640625 +26198 -0.86444091796875 +26199 -0.280029296875 +26200 -0.85723876953125 +26201 -0.29217529296875 +26202 -0.790008544921875 +26203 -0.29400634765625 +26204 -0.62847900390625 +26205 -0.271392822265625 +26206 -0.3956298828125 +26207 -0.223602294921875 +26208 -0.126708984375 +26209 -0.159393310546875 +26210 0.150115966796875 +26211 -0.08599853515625 +26212 0.424041748046875 +26213 -0.006500244140625 +26214 0.670623779296875 +26215 0.072021484375 +26216 0.854522705078125 +26217 0.139434814453125 +26218 0.866485595703125 +26219 0.19122314453125 +26220 0.86920166015625 +26221 0.2235107421875 +26222 0.8653564453125 +26223 0.24127197265625 +26224 0.857147216796875 +26225 0.24822998046875 +26226 0.766845703125 +26227 0.243804931640625 +26228 0.628509521484375 +26229 0.229522705078125 +26230 0.462127685546875 +26231 0.203704833984375 +26232 0.297210693359375 +26233 0.173309326171875 +26234 0.14862060546875 +26235 0.141632080078125 +26236 -0.00537109375 +26237 0.102691650390625 +26238 -0.15753173828125 +26239 0.058502197265625 +26240 -0.31304931640625 +26241 0.008087158203125 +26242 -0.48876953125 +26243 -0.05230712890625 +26244 -0.6416015625 +26245 -0.11041259765625 +26246 -0.751373291015625 +26247 -0.159820556640625 +26248 -0.84619140625 +26249 -0.206787109375 +26250 -0.861297607421875 +26251 -0.24755859375 +26252 -0.863250732421875 +26253 -0.2735595703125 +26254 -0.856597900390625 +26255 -0.276580810546875 +26256 -0.7498779296875 +26257 -0.259918212890625 +26258 -0.624542236328125 +26259 -0.239013671875 +26260 -0.47808837890625 +26261 -0.208099365234375 +26262 -0.253387451171875 +26263 -0.15179443359375 +26264 0.003692626953125 +26265 -0.082183837890625 +26266 0.2257080078125 +26267 -0.017333984375 +26268 0.427154541015625 +26269 0.04608154296875 +26270 0.643218994140625 +26271 0.11669921875 +26272 0.855926513671875 +26273 0.192047119140625 +26274 0.870361328125 +26275 0.256927490234375 +26276 0.870361328125 +26277 0.298370361328125 +26278 0.862762451171875 +26279 0.31842041015625 +26280 0.79669189453125 +26281 0.31640625 +26282 0.595794677734375 +26283 0.289947509765625 +26284 0.362152099609375 +26285 0.246856689453125 +26286 0.1270751953125 +26287 0.194610595703125 +26288 -0.086944580078125 +26289 0.13885498046875 +26290 -0.2784423828125 +26291 0.0802001953125 +26292 -0.484832763671875 +26293 0.009490966796875 +26294 -0.729583740234375 +26295 -0.078338623046875 +26296 -0.86688232421875 +26297 -0.169952392578125 +26298 -0.870391845703125 +26299 -0.24871826171875 +26300 -0.86859130859375 +26301 -0.313385009765625 +26302 -0.86279296875 +26303 -0.36346435546875 +26304 -0.817962646484375 +26305 -0.38958740234375 +26306 -0.6116943359375 +26307 -0.379852294921875 +26308 -0.3128662109375 +26309 -0.332489013671875 +26310 0.039398193359375 +26311 -0.2564697265625 +26312 0.422821044921875 +26313 -0.15716552734375 +26314 0.805145263671875 +26315 -0.043426513671875 +26316 0.870361328125 +26317 0.066680908203125 +26318 0.870361328125 +26319 0.158050537109375 +26320 0.860015869140625 +26321 0.227569580078125 +26322 0.727935791015625 +26323 0.273162841796875 +26324 0.48114013671875 +26325 0.293365478515625 +26326 0.2059326171875 +26327 0.294525146484375 +26328 -0.06103515625 +26329 0.28265380859375 +26330 -0.29913330078125 +26331 0.26043701171875 +26332 -0.516204833984375 +26333 0.224090576171875 +26334 -0.7252197265625 +26335 0.169647216796875 +26336 -0.85980224609375 +26337 0.103759765625 +26338 -0.870391845703125 +26339 0.035614013671875 +26340 -0.870391845703125 +26341 -0.02685546875 +26342 -0.858062744140625 +26343 -0.070648193359375 +26344 -0.673004150390625 +26345 -0.094512939453125 +26346 -0.42694091796875 +26347 -0.112152099609375 +26348 -0.2100830078125 +26349 -0.135162353515625 +26350 -0.0362548828125 +26351 -0.162872314453125 +26352 0.10943603515625 +26353 -0.187530517578125 +26354 0.23516845703125 +26355 -0.203765869140625 +26356 0.373687744140625 +26357 -0.20068359375 +26358 0.517791748046875 +26359 -0.178802490234375 +26360 0.602783203125 +26361 -0.15484619140625 +26362 0.635711669921875 +26363 -0.127532958984375 +26364 0.655181884765625 +26365 -0.088165283203125 +26366 0.65948486328125 +26367 -0.039520263671875 +26368 0.651275634765625 +26369 0.016387939453125 +26370 0.61846923828125 +26371 0.0728759765625 +26372 0.53753662109375 +26373 0.11944580078125 +26374 0.404144287109375 +26375 0.15081787109375 +26376 0.22186279296875 +26377 0.164154052734375 +26378 0.003997802734375 +26379 0.1597900390625 +26380 -0.22100830078125 +26381 0.143035888671875 +26382 -0.42449951171875 +26383 0.119903564453125 +26384 -0.579833984375 +26385 0.09661865234375 +26386 -0.641876220703125 +26387 0.085662841796875 +26388 -0.6177978515625 +26389 0.084991455078125 +26390 -0.575531005859375 +26391 0.0753173828125 +26392 -0.526336669921875 +26393 0.054901123046875 +26394 -0.42645263671875 +26395 0.03900146484375 +26396 -0.2581787109375 +26397 0.035614013671875 +26398 -0.068695068359375 +26399 0.03387451171875 +26400 0.09222412109375 +26401 0.02239990234375 +26402 0.232147216796875 +26403 0.00665283203125 +26404 0.3509521484375 +26405 -0.010284423828125 +26406 0.410064697265625 +26407 -0.037139892578125 +26408 0.372955322265625 +26409 -0.08251953125 +26410 0.2554931640625 +26411 -0.14013671875 +26412 0.10711669921875 +26413 -0.1944580078125 +26414 -0.052886962890625 +26415 -0.23956298828125 +26416 -0.186279296875 +26417 -0.264617919921875 +26418 -0.23291015625 +26419 -0.252960205078125 +26420 -0.209442138671875 +26421 -0.21124267578125 +26422 -0.174163818359375 +26423 -0.158843994140625 +26424 -0.126739501953125 +26425 -0.09820556640625 +26426 -0.048126220703125 +26427 -0.0263671875 +26428 0.0426025390625 +26429 0.048309326171875 +26430 0.10748291015625 +26431 0.11199951171875 +26432 0.1409912109375 +26433 0.1607666015625 +26434 0.19708251953125 +26435 0.208587646484375 +26436 0.273651123046875 +26437 0.253387451171875 +26438 0.31768798828125 +26439 0.278533935546875 +26440 0.341094970703125 +26441 0.287139892578125 +26442 0.368011474609375 +26443 0.28662109375 +26444 0.37249755859375 +26445 0.27001953125 +26446 0.30072021484375 +26447 0.22265625 +26448 0.1517333984375 +26449 0.1458740234375 +26450 -0.01470947265625 +26451 0.059326171875 +26452 -0.1883544921875 +26453 -0.031707763671875 +26454 -0.372711181640625 +26455 -0.12603759765625 +26456 -0.51397705078125 +26457 -0.205596923828125 +26458 -0.57177734375 +26459 -0.25640869140625 +26460 -0.53948974609375 +26461 -0.274810791015625 +26462 -0.43511962890625 +26463 -0.2647705078125 +26464 -0.2962646484375 +26465 -0.236480712890625 +26466 -0.161102294921875 +26467 -0.2008056640625 +26468 -0.0435791015625 +26469 -0.161865234375 +26470 0.060394287109375 +26471 -0.118896484375 +26472 0.13665771484375 +26473 -0.076995849609375 +26474 0.170135498046875 +26475 -0.041900634765625 +26476 0.16552734375 +26477 -0.01373291015625 +26478 0.15728759765625 +26479 0.015899658203125 +26480 0.150787353515625 +26481 0.04681396484375 +26482 0.12200927734375 +26483 0.070068359375 +26484 0.080108642578125 +26485 0.086669921875 +26486 0.05126953125 +26487 0.102874755859375 +26488 0.062896728515625 +26489 0.125579833984375 +26490 0.09271240234375 +26491 0.14727783203125 +26492 0.092987060546875 +26493 0.1533203125 +26494 0.07855224609375 +26495 0.147979736328125 +26496 0.06427001953125 +26497 0.13592529296875 +26498 0.0347900390625 +26499 0.11322021484375 +26500 -0.01171875 +26501 0.08026123046875 +26502 -0.056060791015625 +26503 0.0439453125 +26504 -0.055511474609375 +26505 0.018280029296875 +26506 -0.010467529296875 +26507 0.004638671875 +26508 0.02508544921875 +26509 -0.01141357421875 +26510 0.025665283203125 +26511 -0.035980224609375 +26512 0.017333984375 +26513 -0.060089111328125 +26514 0.00189208984375 +26515 -0.08209228515625 +26516 -0.03173828125 +26517 -0.104461669921875 +26518 -0.071502685546875 +26519 -0.12310791015625 +26520 -0.13543701171875 +26521 -0.14312744140625 +26522 -0.219970703125 +26523 -0.16357421875 +26524 -0.300506591796875 +26525 -0.17755126953125 +26526 -0.376312255859375 +26527 -0.185546875 +26528 -0.416107177734375 +26529 -0.179229736328125 +26530 -0.371124267578125 +26531 -0.145263671875 +26532 -0.242279052734375 +26533 -0.085113525390625 +26534 -0.069732666015625 +26535 -0.01190185546875 +26536 0.125640869140625 +26537 0.06695556640625 +26538 0.31268310546875 +26539 0.141082763671875 +26540 0.45501708984375 +26541 0.198760986328125 +26542 0.554779052734375 +26543 0.239898681640625 +26544 0.61065673828125 +26545 0.263580322265625 +26546 0.610931396484375 +26547 0.266082763671875 +26548 0.531463623046875 +26549 0.240264892578125 +26550 0.3883056640625 +26551 0.191162109375 +26552 0.23468017578125 +26553 0.135009765625 +26554 0.095245361328125 +26555 0.079803466796875 +26556 -0.00396728515625 +26557 0.034088134765625 +26558 -0.04852294921875 +26559 0.003082275390625 +26560 -0.055145263671875 +26561 -0.017120361328125 +26562 -0.0758056640625 +26563 -0.0408935546875 +26564 -0.138702392578125 +26565 -0.07562255859375 +26566 -0.209197998046875 +26567 -0.110260009765625 +26568 -0.289031982421875 +26569 -0.14459228515625 +26570 -0.37884521484375 +26571 -0.1783447265625 +26572 -0.456329345703125 +26573 -0.204620361328125 +26574 -0.51641845703125 +26575 -0.221832275390625 +26576 -0.519287109375 +26577 -0.21832275390625 +26578 -0.458251953125 +26579 -0.192474365234375 +26580 -0.384796142578125 +26581 -0.160064697265625 +26582 -0.323699951171875 +26583 -0.12908935546875 +26584 -0.269287109375 +26585 -0.098602294921875 +26586 -0.1951904296875 +26587 -0.061614990234375 +26588 -0.100006103515625 +26589 -0.018585205078125 +26590 -0.01055908203125 +26591 0.021728515625 +26592 0.1033935546875 +26593 0.067535400390625 +26594 0.24908447265625 +26595 0.120361328125 +26596 0.373199462890625 +26597 0.163970947265625 +26598 0.45806884765625 +26599 0.192840576171875 +26600 0.511474609375 +26601 0.20916748046875 +26602 0.565399169921875 +26603 0.222503662109375 +26604 0.61138916015625 +26605 0.230560302734375 +26606 0.5897216796875 +26607 0.216033935546875 +26608 0.4906005859375 +26609 0.176544189453125 +26610 0.33148193359375 +26611 0.117889404296875 +26612 0.147796630859375 +26613 0.05120849609375 +26614 -0.01873779296875 +26615 -0.01043701171875 +26616 -0.140289306640625 +26617 -0.05810546875 +26618 -0.191986083984375 +26619 -0.0838623046875 +26620 -0.184295654296875 +26621 -0.090240478515625 +26622 -0.161834716796875 +26623 -0.09002685546875 +26624 -0.166595458984375 +26625 -0.095367431640625 +26626 -0.19390869140625 +26627 -0.104766845703125 +26628 -0.22442626953125 +26629 -0.11248779296875 +26630 -0.279754638671875 +26631 -0.125152587890625 +26632 -0.3389892578125 +26633 -0.136810302734375 +26634 -0.3543701171875 +26635 -0.133514404296875 +26636 -0.348175048828125 +26637 -0.122467041015625 +26638 -0.32598876953125 +26639 -0.105865478515625 +26640 -0.2581787109375 +26641 -0.075408935546875 +26642 -0.139801025390625 +26643 -0.030181884765625 +26644 0.014617919921875 +26645 0.024932861328125 +26646 0.144378662109375 +26647 0.071258544921875 +26648 0.221038818359375 +26649 0.09991455078125 +26650 0.27069091796875 +26651 0.118438720703125 +26652 0.294036865234375 +26653 0.126953125 +26654 0.311767578125 +26655 0.131622314453125 +26656 0.339141845703125 +26657 0.137237548828125 +26658 0.360260009765625 +26659 0.1395263671875 +26660 0.360504150390625 +26661 0.134307861328125 +26662 0.308380126953125 +26663 0.1114501953125 +26664 0.18170166015625 +26665 0.063934326171875 +26666 0.0047607421875 +26667 0.0 +26668 -0.17559814453125 +26669 -0.064727783203125 +26670 -0.3143310546875 +26671 -0.115234375 +26672 -0.36785888671875 +26673 -0.136993408203125 +26674 -0.36248779296875 +26675 -0.138427734375 +26676 -0.343536376953125 +26677 -0.13427734375 +26678 -0.3018798828125 +26679 -0.1214599609375 +26680 -0.231414794921875 +26681 -0.09796142578125 +26682 -0.117645263671875 +26683 -0.05908203125 +26684 0.007049560546875 +26685 -0.01556396484375 +26686 0.087982177734375 +26687 0.01446533203125 +26688 0.13946533203125 +26689 0.0355224609375 +26690 0.17425537109375 +26691 0.051544189453125 +26692 0.188201904296875 +26693 0.060882568359375 +26694 0.171234130859375 +26695 0.05999755859375 +26696 0.118438720703125 +26697 0.0469970703125 +26698 0.05706787109375 +26699 0.0306396484375 +26700 -0.010711669921875 +26701 0.01141357421875 +26702 -0.0914306640625 +26703 -0.012908935546875 +26704 -0.162322998046875 +26705 -0.03497314453125 +26706 -0.194549560546875 +26707 -0.045379638671875 +26708 -0.1492919921875 +26709 -0.0313720703125 +26710 -0.02166748046875 +26711 0.00872802734375 +26712 0.124053955078125 +26713 0.053955078125 +26714 0.211151123046875 +26715 0.07928466796875 +26716 0.240447998046875 +26717 0.085205078125 +26718 0.242218017578125 +26719 0.081817626953125 +26720 0.2257080078125 +26721 0.07244873046875 +26722 0.194366455078125 +26723 0.05841064453125 +26724 0.115509033203125 +26725 0.0291748046875 +26726 0.0128173828125 +26727 -0.007232666015625 +26728 -0.053802490234375 +26729 -0.03106689453125 +26730 -0.110626220703125 +26731 -0.050872802734375 +26732 -0.199493408203125 +26733 -0.080352783203125 +26734 -0.29437255859375 +26735 -0.1109619140625 +26736 -0.33221435546875 +26737 -0.1220703125 +26738 -0.27972412109375 +26739 -0.10284423828125 +26740 -0.185333251953125 +26741 -0.069305419921875 +26742 -0.128204345703125 +26743 -0.047576904296875 +26744 -0.115692138671875 +26745 -0.040252685546875 +26746 -0.116455078125 +26747 -0.0372314453125 +26748 -0.105926513671875 +26749 -0.0306396484375 +26750 -0.053955078125 +26751 -0.010772705078125 +26752 0.048797607421875 +26753 0.0252685546875 +26754 0.157318115234375 +26755 0.0626220703125 +26756 0.212005615234375 +26757 0.0816650390625 +26758 0.218475341796875 +26759 0.084197998046875 +26760 0.23724365234375 +26761 0.090087890625 +26762 0.30535888671875 +26763 0.11151123046875 +26764 0.38128662109375 +26765 0.134918212890625 +26766 0.404449462890625 +26767 0.140472412109375 +26768 0.3944091796875 +26769 0.134765625 +26770 0.3885498046875 +26771 0.13018798828125 +26772 0.362640380859375 +26773 0.11895751953125 +26774 0.27362060546875 +26775 0.087127685546875 +26776 0.11712646484375 +26777 0.03338623046875 +26778 -0.054901123046875 +26779 -0.02508544921875 +26780 -0.19085693359375 +26781 -0.071258544921875 +26782 -0.28570556640625 +26783 -0.103424072265625 +26784 -0.339263916015625 +26785 -0.1214599609375 +26786 -0.3775634765625 +26787 -0.1339111328125 +26788 -0.445709228515625 +26789 -0.15557861328125 +26790 -0.535064697265625 +26791 -0.183685302734375 +26792 -0.629058837890625 +26793 -0.212860107421875 +26794 -0.697601318359375 +26795 -0.233367919921875 +26796 -0.70391845703125 +26797 -0.233245849609375 +26798 -0.6424560546875 +26799 -0.2108154296875 +26800 -0.491241455078125 +26801 -0.15899658203125 +26802 -0.265716552734375 +26803 -0.08294677734375 +26804 -0.023712158203125 +26805 -0.00177001953125 +26806 0.201751708984375 +26807 0.073577880859375 +26808 0.375823974609375 +26809 0.131622314453125 +26810 0.485076904296875 +26811 0.16790771484375 +26812 0.56884765625 +26813 0.195343017578125 +26814 0.634765625 +26815 0.2164306640625 +26816 0.63763427734375 +26817 0.2164306640625 +26818 0.5660400390625 +26819 0.191650390625 +26820 0.4720458984375 +26821 0.159210205078125 +26822 0.40692138671875 +26823 0.13604736328125 +26824 0.3778076171875 +26825 0.124603271484375 +26826 0.376953125 +26827 0.1224365234375 +26828 0.371978759765625 +26829 0.1190185546875 +26830 0.313140869140625 +26831 0.098114013671875 +26832 0.184417724609375 +26833 0.0545654296875 +26834 0.011199951171875 +26835 -0.003204345703125 +26836 -0.171051025390625 +26837 -0.063507080078125 +26838 -0.33740234375 +26839 -0.118133544921875 +26840 -0.47198486328125 +26841 -0.161895751953125 +26842 -0.560394287109375 +26843 -0.19012451171875 +26844 -0.58056640625 +26845 -0.195648193359375 +26846 -0.54754638671875 +26847 -0.1834716796875 +26848 -0.508575439453125 +26849 -0.169189453125 +26850 -0.459503173828125 +26851 -0.1514892578125 +26852 -0.394378662109375 +26853 -0.128509521484375 +26854 -0.35260009765625 +26855 -0.113250732421875 +26856 -0.31170654296875 +26857 -0.098419189453125 +26858 -0.197418212890625 +26859 -0.059722900390625 +26860 -0.007965087890625 +26861 0.0032958984375 +26862 0.207489013671875 +26863 0.074462890625 +26864 0.409210205078125 +26865 0.1407470703125 +26866 0.57208251953125 +26867 0.19390869140625 +26868 0.66595458984375 +26869 0.22412109375 +26870 0.65875244140625 +26871 0.22088623046875 +26872 0.56744384765625 +26873 0.1898193359375 +26874 0.431396484375 +26875 0.143890380859375 +26876 0.29443359375 +26877 0.097564697265625 +26878 0.182464599609375 +26879 0.059417724609375 +26880 0.06365966796875 +26881 0.018585205078125 +26882 -0.075958251953125 +26883 -0.029449462890625 +26884 -0.189422607421875 +26885 -0.067840576171875 +26886 -0.271942138671875 +26887 -0.0950927734375 +26888 -0.342529296875 +26889 -0.118255615234375 +26890 -0.364166259765625 +26891 -0.124176025390625 +26892 -0.327239990234375 +26893 -0.1094970703125 +26894 -0.2769775390625 +26895 -0.090545654296875 +26896 -0.253692626953125 +26897 -0.081878662109375 +26898 -0.24365234375 +26899 -0.078521728515625 +26900 -0.1983642578125 +26901 -0.06298828125 +26902 -0.116241455078125 +26903 -0.034637451171875 +26904 -0.036834716796875 +26905 -0.00762939453125 +26906 0.034881591796875 +26907 0.016326904296875 +26908 0.09124755859375 +26909 0.034576416015625 +26910 0.10888671875 +26911 0.038848876953125 +26912 0.125518798828125 +26913 0.0428466796875 +26914 0.15771484375 +26915 0.052642822265625 +26916 0.17828369140625 +26917 0.058502197265625 +26918 0.17108154296875 +26919 0.054718017578125 +26920 0.129974365234375 +26921 0.039154052734375 +26922 0.082427978515625 +26923 0.021728515625 +26924 0.027679443359375 +26925 0.002166748046875 +26926 -0.065643310546875 +26927 -0.03082275390625 +26928 -0.15936279296875 +26929 -0.063568115234375 +26930 -0.21307373046875 +26931 -0.081573486328125 +26932 -0.234649658203125 +26933 -0.0877685546875 +26934 -0.2001953125 +26935 -0.073638916015625 +26936 -0.119171142578125 +26937 -0.042694091796875 +26938 -0.024749755859375 +26939 -0.0069580078125 +26940 0.085784912109375 +26941 0.034423828125 +26942 0.178131103515625 +26943 0.069000244140625 +26944 0.215576171875 +26945 0.08349609375 +26946 0.211456298828125 +26947 0.082672119140625 +26948 0.17523193359375 +26949 0.069915771484375 +26950 0.128753662109375 +26951 0.0531005859375 +26952 0.1019287109375 +26953 0.042999267578125 +26954 0.0743408203125 +26955 0.03228759765625 +26956 0.04327392578125 +26957 0.02008056640625 +26958 0.038177490234375 +26959 0.016998291015625 +26960 0.076263427734375 +26961 0.029296875 +26962 0.14105224609375 +26963 0.051116943359375 +26964 0.186431884765625 +26965 0.065948486328125 +26966 0.188812255859375 +26967 0.065399169921875 +26968 0.1390380859375 +26969 0.0462646484375 +26970 0.041778564453125 +26971 0.010284423828125 +26972 -0.079437255859375 +26973 -0.03399658203125 +26974 -0.219390869140625 +26975 -0.084716796875 +26976 -0.367828369140625 +26977 -0.138153076171875 +26978 -0.494873046875 +26979 -0.18353271484375 +26980 -0.556243896484375 +26981 -0.2049560546875 +26982 -0.508697509765625 +26983 -0.186920166015625 +26984 -0.3756103515625 +26985 -0.13787841796875 +26986 -0.218902587890625 +26987 -0.0802001953125 +26988 -0.063751220703125 +26989 -0.023040771484375 +26990 0.091552734375 +26991 0.03411865234375 +26992 0.23602294921875 +26993 0.0872802734375 +26994 0.342987060546875 +26995 0.12677001953125 +26996 0.39520263671875 +26997 0.1463623046875 +26998 0.389373779296875 +26999 0.144805908203125 +27000 0.324249267578125 +27001 0.12164306640625 +27002 0.224090576171875 +27003 0.085601806640625 +27004 0.124267578125 +27005 0.0494384765625 +27006 0.037078857421875 +27007 0.017578125 +27008 -0.010101318359375 +27009 -9.1552734375e-05 +27010 -0.019439697265625 +27011 -0.0042724609375 +27012 -0.022796630859375 +27013 -0.00640869140625 +27014 -0.001556396484375 +27015 0.000244140625 +27016 0.056304931640625 +27017 0.020050048828125 +27018 0.106719970703125 +27019 0.03717041015625 +27020 0.096893310546875 +27021 0.032684326171875 +27022 0.042694091796875 +27023 0.012359619140625 +27024 -0.018035888671875 +27025 -0.010101318359375 +27026 -0.07586669921875 +27027 -0.031280517578125 +27028 -0.11944580078125 +27029 -0.047088623046875 +27030 -0.15972900390625 +27031 -0.06146240234375 +27032 -0.202606201171875 +27033 -0.076507568359375 +27034 -0.24859619140625 +27035 -0.092437744140625 +27036 -0.30517578125 +27037 -0.111968994140625 +27038 -0.36212158203125 +27039 -0.131500244140625 +27040 -0.39141845703125 +27041 -0.14105224609375 +27042 -0.35528564453125 +27043 -0.1270751953125 +27044 -0.249969482421875 +27045 -0.088226318359375 +27046 -0.092864990234375 +27047 -0.030853271484375 +27048 0.08905029296875 +27049 0.0352783203125 +27050 0.2352294921875 +27051 0.08831787109375 +27052 0.318817138671875 +27053 0.118621826171875 +27054 0.358642578125 +27055 0.132965087890625 +27056 0.347747802734375 +27057 0.128814697265625 +27058 0.28564453125 +27059 0.106048583984375 +27060 0.223175048828125 +27061 0.0830078125 +27062 0.196746826171875 +27063 0.07281494140625 +27064 0.179840087890625 +27065 0.06597900390625 +27066 0.155548095703125 +27067 0.056427001953125 +27068 0.151214599609375 +27069 0.0540771484375 +27070 0.156951904296875 +27071 0.055419921875 +27072 0.13177490234375 +27073 0.045684814453125 +27074 0.100799560546875 +27075 0.033966064453125 +27076 0.087127685546875 +27077 0.028594970703125 +27078 0.05487060546875 +27079 0.016693115234375 +27080 -0.009002685546875 +27081 -0.00640869140625 +27082 -0.10400390625 +27083 -0.040496826171875 +27084 -0.229400634765625 +27085 -0.0853271484375 +27086 -0.35552978515625 +27087 -0.130279541015625 +27088 -0.441925048828125 +27089 -0.160797119140625 +27090 -0.473846435546875 +27091 -0.171600341796875 +27092 -0.464813232421875 +27093 -0.1676025390625 +27094 -0.419097900390625 +27095 -0.150390625 +27096 -0.334320068359375 +27097 -0.119140625 +27098 -0.227935791015625 +27099 -0.080169677734375 +27100 -0.12347412109375 +27101 -0.0419921875 +27102 -0.02764892578125 +27103 -0.007049560546875 +27104 0.077667236328125 +27105 0.0311279296875 +27106 0.2132568359375 +27107 0.08001708984375 +27108 0.38885498046875 +27109 0.14312744140625 +27110 0.582794189453125 +27111 0.212677001953125 +27112 0.734039306640625 +27113 0.2667236328125 +27114 0.800140380859375 +27115 0.28997802734375 +27116 0.7783203125 +27117 0.281494140625 +27118 0.6651611328125 +27119 0.240081787109375 +27120 0.45965576171875 +27121 0.165435791015625 +27122 0.199188232421875 +27123 0.071044921875 +27124 -0.050689697265625 +27125 -0.01947021484375 +27126 -0.23297119140625 +27127 -0.085540771484375 +27128 -0.33013916015625 +27129 -0.120880126953125 +27130 -0.368408203125 +27131 -0.1348876953125 +27132 -0.378936767578125 +27133 -0.13873291015625 +27134 -0.376983642578125 +27135 -0.137969970703125 +27136 -0.37969970703125 +27137 -0.13885498046875 +27138 -0.391510009765625 +27139 -0.1429443359375 +27140 -0.385345458984375 +27141 -0.139923095703125 +27142 -0.3419189453125 +27143 -0.122467041015625 +27144 -0.28289794921875 +27145 -0.099273681640625 +27146 -0.251617431640625 +27147 -0.087432861328125 +27148 -0.266143798828125 +27149 -0.094085693359375 +27150 -0.273345947265625 +27151 -0.098419189453125 +27152 -0.216796875 +27153 -0.0782470703125 +27154 -0.128265380859375 +27155 -0.0458984375 +27156 -0.068145751953125 +27157 -0.02490234375 +27158 -0.0430908203125 +27159 -0.017730712890625 +27160 -0.024444580078125 +27161 -0.01300048828125 +27162 0.020721435546875 +27163 0.0023193359375 +27164 0.124481201171875 +27165 0.040924072265625 +27166 0.25787353515625 +27167 0.091583251953125 +27168 0.379119873046875 +27169 0.138031005859375 +27170 0.47991943359375 +27171 0.177032470703125 +27172 0.5281982421875 +27173 0.196044921875 +27174 0.511138916015625 +27175 0.190032958984375 +27176 0.456207275390625 +27177 0.169708251953125 +27178 0.407470703125 +27179 0.15228271484375 +27180 0.383758544921875 +27181 0.14501953125 +27182 0.35687255859375 +27183 0.136749267578125 +27184 0.31182861328125 +27185 0.1214599609375 +27186 0.250885009765625 +27187 0.09991455078125 +27188 0.1654052734375 +27189 0.068572998046875 +27190 0.035247802734375 +27191 0.01947021484375 +27192 -0.142059326171875 +27193 -0.0484619140625 +27194 -0.33563232421875 +27195 -0.123199462890625 +27196 -0.5345458984375 +27197 -0.20050048828125 +27198 -0.72186279296875 +27199 -0.27374267578125 +27200 -0.836669921875 +27201 -0.31903076171875 +27202 -0.8326416015625 +27203 -0.31817626953125 +27204 -0.7296142578125 +27205 -0.278900146484375 +27206 -0.582550048828125 +27207 -0.22271728515625 +27208 -0.440093994140625 +27209 -0.1685791015625 +27210 -0.324310302734375 +27211 -0.12506103515625 +27212 -0.20147705078125 +27213 -0.078826904296875 +27214 -0.044647216796875 +27215 -0.019195556640625 +27216 0.103973388671875 +27217 0.037353515625 +27218 0.202392578125 +27219 0.074462890625 +27220 0.264495849609375 +27221 0.097625732421875 +27222 0.338897705078125 +27223 0.125946044921875 +27224 0.443817138671875 +27225 0.1666259765625 +27226 0.545074462890625 +27227 0.206268310546875 +27228 0.6173095703125 +27229 0.23492431640625 +27230 0.6524658203125 +27231 0.249420166015625 +27232 0.66339111328125 +27233 0.254730224609375 +27234 0.6561279296875 +27235 0.253173828125 +27236 0.606781005859375 +27237 0.23529052734375 +27238 0.501190185546875 +27239 0.195465087890625 +27240 0.352783203125 +27241 0.13885498046875 +27242 0.176544189453125 +27243 0.071258544921875 +27244 -0.034820556640625 +27245 -0.01025390625 +27246 -0.258209228515625 +27247 -0.0966796875 +27248 -0.44244384765625 +27249 -0.16802978515625 +27250 -0.5753173828125 +27251 -0.21954345703125 +27252 -0.65203857421875 +27253 -0.249359130859375 +27254 -0.641632080078125 +27255 -0.245330810546875 +27256 -0.562164306640625 +27257 -0.21453857421875 +27258 -0.458038330078125 +27259 -0.17437744140625 +27260 -0.350555419921875 +27261 -0.133148193359375 +27262 -0.260528564453125 +27263 -0.098968505859375 +27264 -0.192108154296875 +27265 -0.073394775390625 +27266 -0.141937255859375 +27267 -0.055023193359375 +27268 -0.1021728515625 +27269 -0.04071044921875 +27270 -0.062896728515625 +27271 -0.0264892578125 +27272 -0.011932373046875 +27273 -0.007537841796875 +27274 0.062835693359375 +27275 0.02093505859375 +27276 0.148712158203125 +27277 0.05401611328125 +27278 0.241729736328125 +27279 0.09014892578125 +27280 0.34912109375 +27281 0.132171630859375 +27282 0.457305908203125 +27283 0.174774169921875 +27284 0.54388427734375 +27285 0.209136962890625 +27286 0.5728759765625 +27287 0.22113037109375 +27288 0.506591796875 +27289 0.195953369140625 +27290 0.351226806640625 +27291 0.135955810546875 +27292 0.146514892578125 +27293 0.056671142578125 +27294 -0.05523681640625 +27295 -0.021392822265625 +27296 -0.21624755859375 +27297 -0.083526611328125 +27298 -0.334930419921875 +27299 -0.129150390625 +27300 -0.402984619140625 +27301 -0.155029296875 +27302 -0.4412841796875 +27303 -0.16937255859375 +27304 -0.49578857421875 +27305 -0.190277099609375 +27306 -0.5601806640625 +27307 -0.21527099609375 +27308 -0.600738525390625 +27309 -0.23114013671875 +27310 -0.584228515625 +27311 -0.224884033203125 +27312 -0.47930908203125 +27313 -0.18414306640625 +27314 -0.27935791015625 +27315 -0.1063232421875 +27316 -0.0089111328125 +27317 -0.00103759765625 +27318 0.268798828125 +27319 0.106964111328125 +27320 0.482818603515625 +27321 0.189910888671875 +27322 0.60369873046875 +27323 0.236328125 +27324 0.650421142578125 +27325 0.253692626953125 +27326 0.66400146484375 +27327 0.258148193359375 +27328 0.6414794921875 +27329 0.24859619140625 +27330 0.572540283203125 +27331 0.221038818359375 +27332 0.498138427734375 +27333 0.1915283203125 +27334 0.439453125 +27335 0.16839599609375 +27336 0.375518798828125 +27337 0.1434326171875 +27338 0.274505615234375 +27339 0.104156494140625 +27340 0.1087646484375 +27341 0.0396728515625 +27342 -0.099395751953125 +27343 -0.041290283203125 +27344 -0.3182373046875 +27345 -0.126312255859375 +27346 -0.5489501953125 +27347 -0.21588134765625 +27348 -0.7738037109375 +27349 -0.3031005859375 +27350 -0.86383056640625 +27351 -0.367279052734375 +27352 -0.870391845703125 +27353 -0.39544677734375 +27354 -0.86895751953125 +27355 -0.394561767578125 +27356 -0.861053466796875 +27357 -0.36981201171875 +27358 -0.765869140625 +27359 -0.314453125 +27360 -0.5301513671875 +27361 -0.22412109375 +27362 -0.214691162109375 +27363 -0.101593017578125 +27364 0.137359619140625 +27365 0.036285400390625 +27366 0.474822998046875 +27367 0.16937255859375 +27368 0.76239013671875 +27369 0.2838134765625 +27370 0.867462158203125 +27371 0.3690185546875 +27372 0.870361328125 +27373 0.42523193359375 +27374 0.86480712890625 +27375 0.44793701171875 +27376 0.831817626953125 +27377 0.439300537109375 +27378 0.677581787109375 +27379 0.408905029296875 +27380 0.495880126953125 +27381 0.359039306640625 +27382 0.30767822265625 +27383 0.297027587890625 +27384 0.116180419921875 +27385 0.223785400390625 +27386 -0.110748291015625 +27387 0.12689208984375 +27388 -0.381805419921875 +27389 0.003662109375 +27390 -0.6572265625 +27391 -0.129119873046875 +27392 -0.857421875 +27393 -0.247833251953125 +27394 -0.870391845703125 +27395 -0.335540771484375 +27396 -0.870391845703125 +27397 -0.389617919921875 +27398 -0.86444091796875 +27399 -0.4215087890625 +27400 -0.85723876953125 +27401 -0.446197509765625 +27402 -0.790008544921875 +27403 -0.4556884765625 +27404 -0.62847900390625 +27405 -0.4267578125 +27406 -0.3956298828125 +27407 -0.35772705078125 +27408 -0.126708984375 +27409 -0.262176513671875 +27410 0.150115966796875 +27411 -0.151275634765625 +27412 0.424041748046875 +27413 -0.02960205078125 +27414 0.670623779296875 +27415 0.091827392578125 +27416 0.854522705078125 +27417 0.19696044921875 +27418 0.866485595703125 +27419 0.278656005859375 +27420 0.86920166015625 +27421 0.3306884765625 +27422 0.8653564453125 +27423 0.3609619140625 +27424 0.857147216796875 +27425 0.37530517578125 +27426 0.766845703125 +27427 0.37255859375 +27428 0.628509521484375 +27429 0.3548583984375 +27430 0.462127685546875 +27431 0.31927490234375 +27432 0.297210693359375 +27433 0.276580810546875 +27434 0.14862060546875 +27435 0.231781005859375 +27436 -0.00537109375 +27437 0.174957275390625 +27438 -0.15753173828125 +27439 0.108978271484375 +27440 -0.31304931640625 +27441 0.032012939453125 +27442 -0.48876953125 +27443 -0.062164306640625 +27444 -0.6416015625 +27445 -0.153961181640625 +27446 -0.751373291015625 +27447 -0.233123779296875 +27448 -0.84619140625 +27449 -0.30963134765625 +27450 -0.861297607421875 +27451 -0.377410888671875 +27452 -0.863250732421875 +27453 -0.4224853515625 +27454 -0.856597900390625 +27455 -0.43145751953125 +27456 -0.7498779296875 +27457 -0.40948486328125 +27458 -0.624542236328125 +27459 -0.3809814453125 +27460 -0.47808837890625 +27461 -0.336456298828125 +27462 -0.253387451171875 +27463 -0.250946044921875 +27464 0.003692626953125 +27465 -0.1435546875 +27466 0.2257080078125 +27467 -0.043060302734375 +27468 0.427154541015625 +27469 0.05609130859375 +27470 0.643218994140625 +27471 0.1678466796875 +27472 0.855926513671875 +27473 0.288330078125 +27474 0.870361328125 +27475 0.39312744140625 +27476 0.870361328125 +27477 0.461334228515625 +27478 0.862762451171875 +27479 0.49609375 +27480 0.79669189453125 +27481 0.49615478515625 +27482 0.595794677734375 +27483 0.45751953125 +27484 0.362152099609375 +27485 0.39251708984375 +27486 0.1270751953125 +27487 0.312896728515625 +27488 -0.086944580078125 +27489 0.227508544921875 +27490 -0.2784423828125 +27491 0.1370849609375 +27492 -0.484832763671875 +27493 0.02667236328125 +27494 -0.729583740234375 +27495 -0.111968994140625 +27496 -0.86688232421875 +27497 -0.257568359375 +27498 -0.870391845703125 +27499 -0.3834228515625 +27500 -0.86859130859375 +27501 -0.487548828125 +27502 -0.86279296875 +27503 -0.569122314453125 +27504 -0.817962646484375 +27505 -0.613006591796875 +27506 -0.6116943359375 +27507 -0.599945068359375 +27508 -0.3128662109375 +27509 -0.526947021484375 +27510 0.039398193359375 +27511 -0.408233642578125 +27512 0.422821044921875 +27513 -0.252227783203125 +27514 0.805145263671875 +27515 -0.072967529296875 +27516 0.870361328125 +27517 0.100738525390625 +27518 0.870361328125 +27519 0.24481201171875 +27520 0.860015869140625 +27521 0.354339599609375 +27522 0.727935791015625 +27523 0.426116943359375 +27524 0.48114013671875 +27525 0.45782470703125 +27526 0.2059326171875 +27527 0.459716796875 +27528 -0.06103515625 +27529 0.441375732421875 +27530 -0.29913330078125 +27531 0.407073974609375 +27532 -0.516204833984375 +27533 0.35064697265625 +27534 -0.7252197265625 +27535 0.26556396484375 +27536 -0.85980224609375 +27537 0.162445068359375 +27538 -0.870391845703125 +27539 0.05584716796875 +27540 -0.870391845703125 +27541 -0.0416259765625 +27542 -0.858062744140625 +27543 -0.1092529296875 +27544 -0.673004150390625 +27545 -0.145172119140625 +27546 -0.42694091796875 +27547 -0.171539306640625 +27548 -0.2100830078125 +27549 -0.20709228515625 +27550 -0.0362548828125 +27551 -0.250762939453125 +27552 0.10943603515625 +27553 -0.290130615234375 +27554 0.23516845703125 +27555 -0.316680908203125 +27556 0.373687744140625 +27557 -0.312774658203125 +27558 0.517791748046875 +27559 -0.279205322265625 +27560 0.602783203125 +27561 -0.242706298828125 +27562 0.635711669921875 +27563 -0.201080322265625 +27564 0.655181884765625 +27565 -0.140289306640625 +27566 0.65948486328125 +27567 -0.064605712890625 +27568 0.651275634765625 +27569 0.02239990234375 +27570 0.61846923828125 +27571 0.110198974609375 +27572 0.53753662109375 +27573 0.182952880859375 +27574 0.404144287109375 +27575 0.232818603515625 +27576 0.22186279296875 +27577 0.255523681640625 +27578 0.003997802734375 +27579 0.251495361328125 +27580 -0.22100830078125 +27581 0.228302001953125 +27582 -0.42449951171875 +27583 0.194580078125 +27584 -0.579833984375 +27585 0.15936279296875 +27586 -0.641876220703125 +27587 0.1407470703125 +27588 -0.6177978515625 +27589 0.13592529296875 +27590 -0.575531005859375 +27591 0.1175537109375 +27592 -0.526336669921875 +27593 0.08343505859375 +27594 -0.42645263671875 +27595 0.0556640625 +27596 -0.2581787109375 +27597 0.045989990234375 +27598 -0.068695068359375 +27599 0.039154052734375 +27600 0.09222412109375 +27601 0.01898193359375 +27602 0.232147216796875 +27603 -0.00640869140625 +27604 0.3509521484375 +27605 -0.032562255859375 +27606 0.410064697265625 +27607 -0.0718994140625 +27608 0.372955322265625 +27609 -0.136749267578125 +27610 0.2554931640625 +27611 -0.2181396484375 +27612 0.10711669921875 +27613 -0.293914794921875 +27614 -0.052886962890625 +27615 -0.355743408203125 +27616 -0.186279296875 +27617 -0.38824462890625 +27618 -0.23291015625 +27619 -0.367767333984375 +27620 -0.209442138671875 +27621 -0.304046630859375 +27622 -0.174163818359375 +27623 -0.22509765625 +27624 -0.126739501953125 +27625 -0.13458251953125 +27626 -0.048126220703125 +27627 -0.028472900390625 +27628 0.0426025390625 +27629 0.08111572265625 +27630 0.10748291015625 +27631 0.17425537109375 +27632 0.1409912109375 +27633 0.245208740234375 +27634 0.19708251953125 +27635 0.31396484375 +27636 0.273651123046875 +27637 0.377532958984375 +27638 0.31768798828125 +27639 0.41217041015625 +27640 0.341094970703125 +27641 0.4224853515625 +27642 0.368011474609375 +27643 0.41912841796875 +27644 0.37249755859375 +27645 0.392333984375 +27646 0.30072021484375 +27647 0.321258544921875 +27648 0.1517333984375 +27649 0.208221435546875 +27650 -0.01470947265625 +27651 0.081695556640625 +27652 -0.1883544921875 +27653 -0.051513671875 +27654 -0.372711181640625 +27655 -0.189971923828125 +27656 -0.51397705078125 +27657 -0.306488037109375 +27658 -0.57177734375 +27659 -0.38006591796875 +27660 -0.53948974609375 +27661 -0.4052734375 +27662 -0.43511962890625 +27663 -0.388275146484375 +27664 -0.2962646484375 +27665 -0.344573974609375 +27666 -0.161102294921875 +27667 -0.290618896484375 +27668 -0.0435791015625 +27669 -0.232574462890625 +27670 0.060394287109375 +27671 -0.169219970703125 +27672 0.13665771484375 +27673 -0.10809326171875 +27674 0.170135498046875 +27675 -0.0577392578125 +27676 0.16552734375 +27677 -0.018218994140625 +27678 0.15728759765625 +27679 0.023529052734375 +27680 0.150787353515625 +27681 0.06732177734375 +27682 0.12200927734375 +27683 0.099761962890625 +27684 0.080108642578125 +27685 0.12255859375 +27686 0.05126953125 +27687 0.14532470703125 +27688 0.062896728515625 +27689 0.17864990234375 +27690 0.09271240234375 +27691 0.211151123046875 +27692 0.092987060546875 +27693 0.2205810546875 +27694 0.07855224609375 +27695 0.21337890625 +27696 0.06427001953125 +27697 0.196563720703125 +27698 0.0347900390625 +27699 0.164093017578125 +27700 -0.01171875 +27701 0.11639404296875 +27702 -0.056060791015625 +27703 0.063812255859375 +27704 -0.055511474609375 +27705 0.027496337890625 +27706 -0.010467529296875 +27707 0.009368896484375 +27708 0.02508544921875 +27709 -0.012664794921875 +27710 0.025665283203125 +27711 -0.048004150390625 +27712 0.017333984375 +27713 -0.08306884765625 +27714 0.00189208984375 +27715 -0.115447998046875 +27716 -0.03173828125 +27717 -0.14892578125 +27718 -0.071502685546875 +27719 -0.17730712890625 +27720 -0.13543701171875 +27721 -0.208343505859375 +27722 -0.219970703125 +27723 -0.24053955078125 +27724 -0.300506591796875 +27725 -0.26336669921875 +27726 -0.376312255859375 +27727 -0.277435302734375 +27728 -0.416107177734375 +27729 -0.269927978515625 +27730 -0.371124267578125 +27731 -0.220489501953125 +27732 -0.242279052734375 +27733 -0.131195068359375 +27734 -0.069732666015625 +27735 -0.02191162109375 +27736 0.125640869140625 +27737 0.09619140625 +27738 0.31268310546875 +27739 0.207489013671875 +27740 0.45501708984375 +27741 0.29425048828125 +27742 0.554779052734375 +27743 0.3563232421875 +27744 0.61065673828125 +27745 0.392364501953125 +27746 0.610931396484375 +27747 0.39666748046875 +27748 0.531463623046875 +27749 0.35833740234375 +27750 0.3883056640625 +27751 0.284912109375 +27752 0.23468017578125 +27753 0.201019287109375 +27754 0.095245361328125 +27755 0.118743896484375 +27756 -0.00396728515625 +27757 0.050994873046875 +27758 -0.04852294921875 +27759 0.005615234375 +27760 -0.055145263671875 +27761 -0.023468017578125 +27762 -0.0758056640625 +27763 -0.05816650390625 +27764 -0.138702392578125 +27765 -0.109832763671875 +27766 -0.209197998046875 +27767 -0.161651611328125 +27768 -0.289031982421875 +27769 -0.213409423828125 +27770 -0.37884521484375 +27771 -0.264617919921875 +27772 -0.456329345703125 +27773 -0.3048095703125 +27774 -0.51641845703125 +27775 -0.33160400390625 +27776 -0.519287109375 +27777 -0.327239990234375 +27778 -0.458251953125 +27779 -0.289154052734375 +27780 -0.384796142578125 +27781 -0.241241455078125 +27782 -0.323699951171875 +27783 -0.195587158203125 +27784 -0.269287109375 +27785 -0.15069580078125 +27786 -0.1951904296875 +27787 -0.095916748046875 +27788 -0.100006103515625 +27789 -0.03179931640625 +27790 -0.01055908203125 +27791 0.02838134765625 +27792 0.1033935546875 +27793 0.09716796875 +27794 0.24908447265625 +27795 0.17694091796875 +27796 0.373199462890625 +27797 0.243072509765625 +27798 0.45806884765625 +27799 0.28717041015625 +27800 0.511474609375 +27801 0.3125 +27802 0.565399169921875 +27803 0.333526611328125 +27804 0.61138916015625 +27805 0.346771240234375 +27806 0.5897216796875 +27807 0.32586669921875 +27808 0.4906005859375 +27809 0.267120361328125 +27810 0.33148193359375 +27811 0.17926025390625 +27812 0.147796630859375 +27813 0.07916259765625 +27814 -0.01873779296875 +27815 -0.013397216796875 +27816 -0.140289306640625 +27817 -0.08489990234375 +27818 -0.191986083984375 +27819 -0.123291015625 +27820 -0.184295654296875 +27821 -0.13250732421875 +27822 -0.161834716796875 +27823 -0.13201904296875 +27824 -0.166595458984375 +27825 -0.1402587890625 +27826 -0.19390869140625 +27827 -0.1549072265625 +27828 -0.22442626953125 +27829 -0.167205810546875 +27830 -0.279754638671875 +27831 -0.18707275390625 +27832 -0.3389892578125 +27833 -0.205474853515625 +27834 -0.3543701171875 +27835 -0.201507568359375 +27836 -0.348175048828125 +27837 -0.18585205078125 +27838 -0.32598876953125 +27839 -0.161773681640625 +27840 -0.2581787109375 +27841 -0.11676025390625 +27842 -0.139801025390625 +27843 -0.049346923828125 +27844 0.014617919921875 +27845 0.03314208984375 +27846 0.144378662109375 +27847 0.102691650390625 +27848 0.221038818359375 +27849 0.145965576171875 +27850 0.27069091796875 +27851 0.174285888671875 +27852 0.294036865234375 +27853 0.187744140625 +27854 0.311767578125 +27855 0.195587158203125 +27856 0.339141845703125 +27857 0.204803466796875 +27858 0.360260009765625 +27859 0.20855712890625 +27860 0.360504150390625 +27861 0.20062255859375 +27862 0.308380126953125 +27863 0.1671142578125 +27864 0.18170166015625 +27865 0.098480224609375 +27866 0.0047607421875 +27867 0.006439208984375 +27868 -0.17559814453125 +27869 -0.087005615234375 +27870 -0.3143310546875 +27871 -0.1607666015625 +27872 -0.36785888671875 +27873 -0.194427490234375 +27874 -0.36248779296875 +27875 -0.199493408203125 +27876 -0.343536376953125 +27877 -0.196258544921875 +27878 -0.3018798828125 +27879 -0.18035888671875 +27880 -0.231414794921875 +27881 -0.148895263671875 +27882 -0.117645263671875 +27883 -0.095306396484375 +27884 0.007049560546875 +27885 -0.034515380859375 +27886 0.087982177734375 +27887 0.008270263671875 +27888 0.13946533203125 +27889 0.0391845703125 +27890 0.17425537109375 +27891 0.0635986328125 +27892 0.188201904296875 +27893 0.079132080078125 +27894 0.171234130859375 +27895 0.080657958984375 +27896 0.118438720703125 +27897 0.065460205078125 +27898 0.05706787109375 +27899 0.045501708984375 +27900 -0.010711669921875 +27901 0.021331787109375 +27902 -0.0914306640625 +27903 -0.0103759765625 +27904 -0.162322998046875 +27905 -0.03985595703125 +27906 -0.194549560546875 +27907 -0.053924560546875 +27908 -0.1492919921875 +27909 -0.033355712890625 +27910 -0.02166748046875 +27911 0.02471923828125 +27912 0.124053955078125 +27913 0.08953857421875 +27914 0.211151123046875 +27915 0.124237060546875 +27916 0.240447998046875 +27917 0.12982177734375 +27918 0.242218017578125 +27919 0.121612548828125 +27920 0.2257080078125 +27921 0.104736328125 +27922 0.194366455078125 +27923 0.081329345703125 +27924 0.115509033203125 +27925 0.035858154296875 +27926 0.0128173828125 +27927 -0.01971435546875 +27928 -0.053802490234375 +27929 -0.05596923828125 +27930 -0.110626220703125 +27931 -0.0855712890625 +27932 -0.199493408203125 +27933 -0.128936767578125 +27934 -0.29437255859375 +27935 -0.1734619140625 +27936 -0.33221435546875 +27937 -0.18853759765625 +27938 -0.27972412109375 +27939 -0.158172607421875 +27940 -0.185333251953125 +27941 -0.106292724609375 +27942 -0.128204345703125 +27943 -0.071868896484375 +27944 -0.115692138671875 +27945 -0.058868408203125 +27946 -0.116455078125 +27947 -0.0523681640625 +27948 -0.105926513671875 +27949 -0.040802001953125 +27950 -0.053955078125 +27951 -0.009765625 +27952 0.048797607421875 +27953 0.04498291015625 +27954 0.157318115234375 +27955 0.10125732421875 +27956 0.212005615234375 +27957 0.129852294921875 +27958 0.218475341796875 +27959 0.133392333984375 +27960 0.23724365234375 +27961 0.141448974609375 +27962 0.30535888671875 +27963 0.172210693359375 +27964 0.38128662109375 +27965 0.20556640625 +27966 0.404449462890625 +27967 0.212188720703125 +27968 0.3944091796875 +27969 0.201934814453125 +27970 0.3885498046875 +27971 0.193359375 +27972 0.362640380859375 +27973 0.174957275390625 +27974 0.27362060546875 +27975 0.12603759765625 +27976 0.11712646484375 +27977 0.04473876953125 +27978 -0.054901123046875 +27979 -0.04327392578125 +27980 -0.19085693359375 +27981 -0.112640380859375 +27982 -0.28570556640625 +27983 -0.1607666015625 +27984 -0.339263916015625 +27985 -0.187530517578125 +27986 -0.3775634765625 +27987 -0.20562744140625 +27988 -0.445709228515625 +27989 -0.23712158203125 +27990 -0.535064697265625 +27991 -0.277923583984375 +27992 -0.629058837890625 +27993 -0.320159912109375 +27994 -0.697601318359375 +27995 -0.349334716796875 +27996 -0.70391845703125 +27997 -0.347747802734375 +27998 -0.6424560546875 +27999 -0.31298828125 +28000 -0.491241455078125 +28001 -0.234588623046875 +28002 -0.265716552734375 +28003 -0.120330810546875 +28004 -0.023712158203125 +28005 0.001312255859375 +28006 0.201751708984375 +28007 0.11407470703125 +28008 0.375823974609375 +28009 0.200836181640625 +28010 0.485076904296875 +28011 0.254974365234375 +28012 0.56884765625 +28013 0.295654296875 +28014 0.634765625 +28015 0.326629638671875 +28016 0.63763427734375 +28017 0.325958251953125 +28018 0.5660400390625 +28019 0.2882080078125 +28020 0.4720458984375 +28021 0.23895263671875 +28022 0.40692138671875 +28023 0.203399658203125 +28024 0.3778076171875 +28025 0.18524169921875 +28026 0.376953125 +28027 0.180938720703125 +28028 0.371978759765625 +28029 0.174896240234375 +28030 0.313140869140625 +28031 0.143035888671875 +28032 0.184417724609375 +28033 0.07769775390625 +28034 0.011199951171875 +28035 -0.00860595703125 +28036 -0.171051025390625 +28037 -0.09844970703125 +28038 -0.33740234375 +28039 -0.179656982421875 +28040 -0.47198486328125 +28041 -0.244537353515625 +28042 -0.560394287109375 +28043 -0.2861328125 +28044 -0.58056640625 +28045 -0.293792724609375 +28046 -0.54754638671875 +28047 -0.27496337890625 +28048 -0.508575439453125 +28049 -0.252899169921875 +28050 -0.459503173828125 +28051 -0.2257080078125 +28052 -0.394378662109375 +28053 -0.190704345703125 +28054 -0.35260009765625 +28055 -0.167266845703125 +28056 -0.31170654296875 +28057 -0.14459228515625 +28058 -0.197418212890625 +28059 -0.086578369140625 +28060 -0.007965087890625 +28061 0.007537841796875 +28062 0.207489013671875 +28063 0.113677978515625 +28064 0.409210205078125 +28065 0.212371826171875 +28066 0.57208251953125 +28067 0.291412353515625 +28068 0.66595458984375 +28069 0.33612060546875 +28070 0.65875244140625 +28071 0.3309326171875 +28072 0.56744384765625 +28073 0.284210205078125 +28074 0.431396484375 +28075 0.21533203125 +28076 0.29443359375 +28077 0.145843505859375 +28078 0.182464599609375 +28079 0.0885009765625 +28080 0.06365966796875 +28081 0.027923583984375 +28082 -0.075958251953125 +28083 -0.04254150390625 +28084 -0.189422607421875 +28085 -0.099853515625 +28086 -0.271942138671875 +28087 -0.141571044921875 +28088 -0.342529296875 +28089 -0.176910400390625 +28090 -0.364166259765625 +28091 -0.18780517578125 +28092 -0.327239990234375 +28093 -0.169586181640625 +28094 -0.2769775390625 +28095 -0.144317626953125 +28096 -0.253692626953125 +28097 -0.1317138671875 +28098 -0.24365234375 +28099 -0.12518310546875 +28100 -0.1983642578125 +28101 -0.101165771484375 +28102 -0.116241455078125 +28103 -0.058990478515625 +28104 -0.036834716796875 +28105 -0.018035888671875 +28106 0.034881591796875 +28107 0.01910400390625 +28108 0.09124755859375 +28109 0.048583984375 +28110 0.10888671875 +28111 0.05889892578125 +28112 0.125518798828125 +28113 0.068328857421875 +28114 0.15771484375 +28115 0.084930419921875 +28116 0.17828369140625 +28117 0.09539794921875 +28118 0.17108154296875 +28119 0.09185791015625 +28120 0.129974365234375 +28121 0.071319580078125 +28122 0.082427978515625 +28123 0.047210693359375 +28124 0.027679443359375 +28125 0.01922607421875 +28126 -0.065643310546875 +28127 -0.027801513671875 +28128 -0.15936279296875 +28129 -0.075164794921875 +28130 -0.21307373046875 +28131 -0.10308837890625 +28132 -0.234649658203125 +28133 -0.11529541015625 +28134 -0.2001953125 +28135 -0.10003662109375 +28136 -0.119171142578125 +28137 -0.061859130859375 +28138 -0.024749755859375 +28139 -0.01690673828125 +28140 0.085784912109375 +28141 0.03619384765625 +28142 0.178131103515625 +28143 0.080718994140625 +28144 0.215576171875 +28145 0.098785400390625 +28146 0.211456298828125 +28147 0.096923828125 +28148 0.17523193359375 +28149 0.079742431640625 +28150 0.128753662109375 +28151 0.057861328125 +28152 0.1019287109375 +28153 0.04583740234375 +28154 0.0743408203125 +28155 0.033660888671875 +28156 0.04327392578125 +28157 0.0198974609375 +28158 0.038177490234375 +28159 0.018829345703125 +28160 0.076263427734375 +28161 0.039337158203125 +28162 0.14105224609375 +28163 0.073760986328125 +28164 0.186431884765625 +28165 0.0986328125 +28166 0.188812255859375 +28167 0.1014404296875 +28168 0.1390380859375 +28169 0.07720947265625 +28170 0.041778564453125 +28171 0.0281982421875 +28172 -0.079437255859375 +28173 -0.03350830078125 +28174 -0.219390869140625 +28175 -0.1053466796875 +28176 -0.367828369140625 +28177 -0.182037353515625 +28178 -0.494873046875 +28179 -0.24810791015625 +28180 -0.556243896484375 +28181 -0.280548095703125 +28182 -0.508697509765625 +28183 -0.256866455078125 +28184 -0.3756103515625 +28185 -0.189117431640625 +28186 -0.218902587890625 +28187 -0.109405517578125 +28188 -0.063751220703125 +28189 -0.03070068359375 +28190 0.091552734375 +28191 0.047943115234375 +28192 0.23602294921875 +28193 0.1209716796875 +28194 0.342987060546875 +28195 0.17462158203125 +28196 0.39520263671875 +28197 0.200042724609375 +28198 0.389373779296875 +28199 0.19561767578125 +28200 0.324249267578125 +28201 0.1607666015625 +28202 0.224090576171875 +28203 0.108154296875 +28204 0.124267578125 +28205 0.05621337890625 +28206 0.037078857421875 +28207 0.01129150390625 +28208 -0.010101318359375 +28209 -0.01239013671875 +28210 -0.019439697265625 +28211 -0.016021728515625 +28212 -0.022796630859375 +28213 -0.0162353515625 +28214 -0.001556396484375 +28215 -0.00341796875 +28216 0.056304931640625 +28217 0.028533935546875 +28218 0.106719970703125 +28219 0.05657958984375 +28220 0.096893310546875 +28221 0.053192138671875 +28222 0.042694091796875 +28223 0.026519775390625 +28224 -0.018035888671875 +28225 -0.003814697265625 +28226 -0.07586669921875 +28227 -0.032958984375 +28228 -0.11944580078125 +28229 -0.0550537109375 +28230 -0.15972900390625 +28231 -0.075836181640625 +28232 -0.202606201171875 +28233 -0.098358154296875 +28234 -0.24859619140625 +28235 -0.12286376953125 +28236 -0.30517578125 +28237 -0.153167724609375 +28238 -0.36212158203125 +28239 -0.183929443359375 +28240 -0.39141845703125 +28241 -0.20050048828125 +28242 -0.35528564453125 +28243 -0.183135986328125 +28244 -0.249969482421875 +28245 -0.129852294921875 +28246 -0.092864990234375 +28247 -0.049591064453125 +28248 0.08905029296875 +28249 0.043670654296875 +28250 0.2352294921875 +28251 0.1185302734375 +28252 0.318817138671875 +28253 0.16107177734375 +28254 0.358642578125 +28255 0.181121826171875 +28256 0.347747802734375 +28257 0.17510986328125 +28258 0.28564453125 +28259 0.142791748046875 +28260 0.223175048828125 +28261 0.110595703125 +28262 0.196746826171875 +28263 0.097442626953125 +28264 0.179840087890625 +28265 0.089508056640625 +28266 0.155548095703125 +28267 0.07794189453125 +28268 0.151214599609375 +28269 0.076873779296875 +28270 0.156951904296875 +28271 0.08111572265625 +28272 0.13177490234375 +28273 0.069244384765625 +28274 0.100799560546875 +28275 0.05426025390625 +28276 0.087127685546875 +28277 0.04815673828125 +28278 0.05487060546875 +28279 0.0322265625 +28280 -0.009002685546875 +28281 -0.0003662109375 +28282 -0.10400390625 +28283 -0.04937744140625 +28284 -0.229400634765625 +28285 -0.11444091796875 +28286 -0.35552978515625 +28287 -0.180145263671875 +28288 -0.441925048828125 +28289 -0.22540283203125 +28290 -0.473846435546875 +28291 -0.2425537109375 +28292 -0.464813232421875 +28293 -0.238555908203125 +28294 -0.419097900390625 +28295 -0.215606689453125 +28296 -0.334320068359375 +28297 -0.17242431640625 +28298 -0.227935791015625 +28299 -0.118011474609375 +28300 -0.12347412109375 +28301 -0.064605712890625 +28302 -0.02764892578125 +28303 -0.015655517578125 +28304 0.077667236328125 +28305 0.038330078125 +28306 0.2132568359375 +28307 0.108184814453125 +28308 0.38885498046875 +28309 0.199005126953125 +28310 0.582794189453125 +28311 0.299560546875 +28312 0.734039306640625 +28313 0.37811279296875 +28314 0.800140380859375 +28315 0.41259765625 +28316 0.7783203125 +28317 0.401519775390625 +28318 0.6651611328125 +28319 0.343109130859375 +28320 0.45965576171875 +28321 0.23681640625 +28322 0.199188232421875 +28323 0.10205078125 +28324 -0.050689697265625 +28325 -0.027099609375 +28326 -0.23297119140625 +28327 -0.121063232421875 +28328 -0.33013916015625 +28329 -0.1707763671875 +28330 -0.368408203125 +28331 -0.18994140625 +28332 -0.378936767578125 +28333 -0.19476318359375 +28334 -0.376983642578125 +28335 -0.1932373046875 +28336 -0.37969970703125 +28337 -0.194305419921875 +28338 -0.391510009765625 +28339 -0.20025634765625 +28340 -0.385345458984375 +28341 -0.197052001953125 +28342 -0.3419189453125 +28343 -0.17462158203125 +28344 -0.28289794921875 +28345 -0.14422607421875 +28346 -0.251617431640625 +28347 -0.128387451171875 +28348 -0.266143798828125 +28349 -0.136474609375 +28350 -0.273345947265625 +28351 -0.140838623046875 +28352 -0.216796875 +28353 -0.112091064453125 +28354 -0.128265380859375 +28355 -0.06671142578125 +28356 -0.068145751953125 +28357 -0.036041259765625 +28358 -0.0430908203125 +28359 -0.02349853515625 +28360 -0.024444580078125 +28361 -0.014190673828125 +28362 0.020721435546875 +28363 0.009002685546875 +28364 0.124481201171875 +28365 0.062744140625 +28366 0.25787353515625 +28367 0.131988525390625 +28368 0.379119873046875 +28369 0.19500732421875 +28370 0.47991943359375 +28371 0.247528076171875 +28372 0.5281982421875 +28373 0.272857666015625 +28374 0.511138916015625 +28375 0.2642822265625 +28376 0.456207275390625 +28377 0.236083984375 +28378 0.407470703125 +28379 0.211151123046875 +28380 0.383758544921875 +28381 0.19927978515625 +28382 0.35687255859375 +28383 0.185760498046875 +28384 0.31182861328125 +28385 0.16278076171875 +28386 0.250885009765625 +28387 0.1314697265625 +28388 0.1654052734375 +28389 0.087310791015625 +28390 0.035247802734375 +28391 0.01983642578125 +28392 -0.142059326171875 +28393 -0.072235107421875 +28394 -0.33563232421875 +28395 -0.1728515625 +28396 -0.5345458984375 +28397 -0.27630615234375 +28398 -0.72186279296875 +28399 -0.373779296875 +28400 -0.836669921875 +28401 -0.43359375 +28402 -0.8326416015625 +28403 -0.431671142578125 +28404 -0.7296142578125 +28405 -0.378326416015625 +28406 -0.582550048828125 +28407 -0.3021240234375 +28408 -0.440093994140625 +28409 -0.22833251953125 +28410 -0.324310302734375 +28411 -0.168426513671875 +28412 -0.20147705078125 +28413 -0.1048583984375 +28414 -0.044647216796875 +28415 -0.023590087890625 +28416 0.103973388671875 +28417 0.052886962890625 +28418 0.202392578125 +28419 0.102081298828125 +28420 0.264495849609375 +28421 0.131866455078125 +28422 0.338897705078125 +28423 0.169342041015625 +28424 0.443817138671875 +28425 0.2247314453125 +28426 0.545074462890625 +28427 0.279296875 +28428 0.6173095703125 +28429 0.319061279296875 +28430 0.6524658203125 +28431 0.33953857421875 +28432 0.66339111328125 +28433 0.347747802734375 +28434 0.6561279296875 +28435 0.346893310546875 +28436 0.606781005859375 +28437 0.32354736328125 +28438 0.501190185546875 +28439 0.2696533203125 +28440 0.352783203125 +28441 0.1923828125 +28442 0.176544189453125 +28443 0.099761962890625 +28444 -0.034820556640625 +28445 -0.012481689453125 +28446 -0.258209228515625 +28447 -0.1318359375 +28448 -0.44244384765625 +28449 -0.230255126953125 +28450 -0.5753173828125 +28451 -0.301116943359375 +28452 -0.65203857421875 +28453 -0.3419189453125 +28454 -0.641632080078125 +28455 -0.335662841796875 +28456 -0.562164306640625 +28457 -0.29229736328125 +28458 -0.458038330078125 +28459 -0.236297607421875 +28460 -0.350555419921875 +28461 -0.179290771484375 +28462 -0.260528564453125 +28463 -0.132598876953125 +28464 -0.192108154296875 +28465 -0.098358154296875 +28466 -0.141937255859375 +28467 -0.07452392578125 +28468 -0.1021728515625 +28469 -0.0565185546875 +28470 -0.062896728515625 +28471 -0.038665771484375 +28472 -0.011932373046875 +28473 -0.0140380859375 +28474 0.062835693359375 +28475 0.02423095703125 +28476 0.148712158203125 +28477 0.069305419921875 +28478 0.241729736328125 +28479 0.11907958984375 +28480 0.34912109375 +28481 0.177642822265625 +28482 0.457305908203125 +28483 0.23748779296875 +28484 0.54388427734375 +28485 0.28619384765625 +28486 0.5728759765625 +28487 0.303863525390625 +28488 0.506591796875 +28489 0.269561767578125 +28490 0.351226806640625 +28491 0.18658447265625 +28492 0.146514892578125 +28493 0.076690673828125 +28494 -0.05523681640625 +28495 -0.031402587890625 +28496 -0.21624755859375 +28497 -0.1170654296875 +28498 -0.334930419921875 +28499 -0.1795654296875 +28500 -0.402984619140625 +28501 -0.2144775390625 +28502 -0.4412841796875 +28503 -0.23345947265625 +28504 -0.49578857421875 +28505 -0.261993408203125 +28506 -0.5601806640625 +28507 -0.296630859375 +28508 -0.600738525390625 +28509 -0.318817138671875 +28510 -0.584228515625 +28511 -0.310211181640625 +28512 -0.47930908203125 +28513 -0.253448486328125 +28514 -0.27935791015625 +28515 -0.144775390625 +28516 -0.0089111328125 +28517 0.002349853515625 +28518 0.268798828125 +28519 0.15313720703125 +28520 0.482818603515625 +28521 0.268585205078125 +28522 0.60369873046875 +28523 0.33258056640625 +28524 0.650421142578125 +28525 0.355712890625 +28526 0.66400146484375 +28527 0.360809326171875 +28528 0.6414794921875 +28529 0.346343994140625 +28530 0.572540283203125 +28531 0.306732177734375 +28532 0.498138427734375 +28533 0.2646484375 +28534 0.439453125 +28535 0.231842041015625 +28536 0.375518798828125 +28537 0.19671630859375 +28538 0.274505615234375 +28539 0.141693115234375 +28540 0.1087646484375 +28541 0.05145263671875 +28542 -0.099395751953125 +28543 -0.061767578125 +28544 -0.3182373046875 +28545 -0.1805419921875 +28546 -0.5489501953125 +28547 -0.3056640625 +28548 -0.7738037109375 +28549 -0.42742919921875 +28550 -0.86383056640625 +28551 -0.516754150390625 +28552 -0.870391845703125 +28553 -0.555419921875 +28554 -0.86895751953125 +28555 -0.553314208984375 +28556 -0.861053466796875 +28557 -0.517791748046875 +28558 -0.765869140625 +28559 -0.439361572265625 +28560 -0.5301513671875 +28561 -0.311859130859375 +28562 -0.214691162109375 +28563 -0.13922119140625 +28564 0.137359619140625 +28565 0.054779052734375 +28566 0.474822998046875 +28567 0.24188232421875 +28568 0.76239013671875 +28569 0.402496337890625 +28570 0.867462158203125 +28571 0.521820068359375 +28572 0.870361328125 +28573 0.600189208984375 +28574 0.86480712890625 +28575 0.63134765625 +28576 0.831817626953125 +28577 0.618316650390625 +28578 0.677581787109375 +28579 0.574676513671875 +28580 0.495880126953125 +28581 0.503753662109375 +28582 0.30767822265625 +28583 0.415863037109375 +28584 0.116180419921875 +28585 0.312286376953125 +28586 -0.110748291015625 +28587 0.175567626953125 +28588 -0.381805419921875 +28589 0.001922607421875 +28590 -0.6572265625 +28591 -0.185028076171875 +28592 -0.857421875 +28593 -0.352203369140625 +28594 -0.870391845703125 +28595 -0.475982666015625 +28596 -0.870391845703125 +28597 -0.552490234375 +28598 -0.86444091796875 +28599 -0.596649169921875 +28600 -0.85723876953125 +28601 -0.62823486328125 +28602 -0.790008544921875 +28603 -0.63720703125 +28604 -0.62847900390625 +28605 -0.59368896484375 +28606 -0.3956298828125 +28607 -0.496002197265625 +28608 -0.126708984375 +28609 -0.36236572265625 +28610 0.150115966796875 +28611 -0.207977294921875 +28612 0.424041748046875 +28613 -0.03936767578125 +28614 0.670623779296875 +28615 0.128570556640625 +28616 0.854522705078125 +28617 0.2744140625 +28618 0.866485595703125 +28619 0.388427734375 +28620 0.86920166015625 +28621 0.46209716796875 +28622 0.8653564453125 +28623 0.505462646484375 +28624 0.857147216796875 +28625 0.5260009765625 +28626 0.766845703125 +28627 0.522186279296875 +28628 0.628509521484375 +28629 0.49688720703125 +28630 0.462127685546875 +28631 0.446441650390625 +28632 0.297210693359375 +28633 0.38519287109375 +28634 0.14862060546875 +28635 0.32000732421875 +28636 -0.00537109375 +28637 0.238372802734375 +28638 -0.15753173828125 +28639 0.144500732421875 +28640 -0.31304931640625 +28641 0.03643798828125 +28642 -0.48876953125 +28643 -0.093536376953125 +28644 -0.6416015625 +28645 -0.219512939453125 +28646 -0.751373291015625 +28647 -0.32781982421875 +28648 -0.84619140625 +28649 -0.43121337890625 +28650 -0.861297607421875 +28651 -0.521636962890625 +28652 -0.863250732421875 +28653 -0.580780029296875 +28654 -0.856597900390625 +28655 -0.591278076171875 +28656 -0.7498779296875 +28657 -0.559906005859375 +28658 -0.624542236328125 +28659 -0.5186767578125 +28660 -0.47808837890625 +28661 -0.45550537109375 +28662 -0.253387451171875 +28663 -0.338165283203125 +28664 0.003692626953125 +28665 -0.191925048828125 +28666 0.2257080078125 +28667 -0.0545654296875 +28668 0.427154541015625 +28669 0.080780029296875 +28670 0.643218994140625 +28671 0.231964111328125 +28672 0.855926513671875 +28673 0.39410400390625 +28674 0.870361328125 +28675 0.53521728515625 +28676 0.870361328125 +28677 0.627197265625 +28678 0.862762451171875 +28679 0.674224853515625 +28680 0.79669189453125 +28681 0.674468994140625 +28682 0.595794677734375 +28683 0.622161865234375 +28684 0.362152099609375 +28685 0.534088134765625 +28686 0.1270751953125 +28687 0.42626953125 +28688 -0.086944580078125 +28689 0.310699462890625 +28690 -0.2784423828125 +28691 0.188232421875 +28692 -0.484832763671875 +28693 0.0382080078125 +28694 -0.729583740234375 +28695 -0.15093994140625 +28696 -0.86688232421875 +28697 -0.3499755859375 +28698 -0.870391845703125 +28699 -0.522186279296875 +28700 -0.86859130859375 +28701 -0.664886474609375 +28702 -0.86279296875 +28703 -0.777008056640625 +28704 -0.817962646484375 +28705 -0.837615966796875 +28706 -0.6116943359375 +28707 -0.820220947265625 +28708 -0.3128662109375 +28709 -0.7205810546875 +28710 0.039398193359375 +28711 -0.558258056640625 +28712 0.422821044921875 +28713 -0.34478759765625 +28714 0.805145263671875 +28715 -0.099395751953125 +28716 0.870361328125 +28717 0.138336181640625 +28718 0.870361328125 +28719 0.3353271484375 +28720 0.860015869140625 +28721 0.48492431640625 +28722 0.727935791015625 +28723 0.582763671875 +28724 0.48114013671875 +28725 0.625640869140625 +28726 0.2059326171875 +28727 0.62774658203125 +28728 -0.06103515625 +28729 0.602294921875 +28730 -0.29913330078125 +28731 0.555145263671875 +28732 -0.516204833984375 +28733 0.477813720703125 +28734 -0.7252197265625 +28735 0.361297607421875 +28736 -0.85980224609375 +28737 0.2200927734375 +28738 -0.870391845703125 +28739 0.07427978515625 +28740 -0.870391845703125 +28741 -0.058837890625 +28742 -0.858062744140625 +28743 -0.15081787109375 +28744 -0.673004150390625 +28745 -0.19915771484375 +28746 -0.42694091796875 +28747 -0.234405517578125 +28748 -0.2100830078125 +28749 -0.28240966796875 +28750 -0.0362548828125 +28751 -0.341796875 +28752 0.10943603515625 +28753 -0.3955078125 +28754 0.23516845703125 +28755 -0.43182373046875 +28756 0.373687744140625 +28757 -0.426483154296875 +28758 0.517791748046875 +28759 -0.38055419921875 +28760 0.602783203125 +28761 -0.330780029296875 +28762 0.635711669921875 +28763 -0.274169921875 +28764 0.655181884765625 +28765 -0.1912841796875 +28766 0.65948486328125 +28767 -0.0880126953125 +28768 0.651275634765625 +28769 0.030853271484375 +28770 0.61846923828125 +28771 0.15081787109375 +28772 0.53753662109375 +28773 0.2501220703125 +28774 0.404144287109375 +28775 0.31805419921875 +28776 0.22186279296875 +28777 0.348785400390625 +28778 0.003997802734375 +28779 0.342864990234375 +28780 -0.22100830078125 +28781 0.31072998046875 +28782 -0.42449951171875 +28783 0.264312744140625 +28784 -0.579833984375 +28785 0.21600341796875 +28786 -0.641876220703125 +28787 0.190704345703125 +28788 -0.6177978515625 +28789 0.184539794921875 +28790 -0.575531005859375 +28791 0.159820556640625 +28792 -0.526336669921875 +28793 0.113525390625 +28794 -0.42645263671875 +28795 0.076019287109375 +28796 -0.2581787109375 +28797 0.063446044921875 +28798 -0.068695068359375 +28799 0.05474853515625 +28800 0.09222412109375 +28801 0.02764892578125 +28802 0.232147216796875 +28803 -0.00677490234375 +28804 0.3509521484375 +28805 -0.042388916015625 +28806 0.410064697265625 +28807 -0.0963134765625 +28808 0.372955322265625 +28809 -0.185577392578125 +28810 0.2554931640625 +28811 -0.29779052734375 +28812 0.10711669921875 +28813 -0.40240478515625 +28814 -0.052886962890625 +28815 -0.4879150390625 +28816 -0.186279296875 +28817 -0.533172607421875 +28818 -0.23291015625 +28819 -0.50555419921875 +28820 -0.209442138671875 +28821 -0.418426513671875 +28822 -0.174163818359375 +28823 -0.31036376953125 +28824 -0.126739501953125 +28825 -0.18634033203125 +28826 -0.048126220703125 +28827 -0.040740966796875 +28828 0.0426025390625 +28829 0.1097412109375 +28830 0.10748291015625 +28831 0.237701416015625 +28832 0.1409912109375 +28833 0.335205078125 +28834 0.19708251953125 +28835 0.42987060546875 +28836 0.273651123046875 +28837 0.517547607421875 +28838 0.31768798828125 +28839 0.56549072265625 +28840 0.341094970703125 +28841 0.580047607421875 +28842 0.368011474609375 +28843 0.575897216796875 +28844 0.37249755859375 +28845 0.539520263671875 +28846 0.30072021484375 +28847 0.442169189453125 +28848 0.1517333984375 +28849 0.286773681640625 +28850 -0.01470947265625 +28851 0.1123046875 +28852 -0.1883544921875 +28853 -0.070709228515625 +28854 -0.372711181640625 +28855 -0.259765625 +28856 -0.51397705078125 +28857 -0.419036865234375 +28858 -0.57177734375 +28859 -0.520843505859375 +28860 -0.53948974609375 +28861 -0.557861328125 +28862 -0.43511962890625 +28863 -0.537933349609375 +28864 -0.2962646484375 +28865 -0.481231689453125 +28866 -0.161102294921875 +28867 -0.4091796875 +28868 -0.0435791015625 +28869 -0.33001708984375 +28870 0.060394287109375 +28871 -0.242431640625 +28872 0.13665771484375 +28873 -0.156646728515625 +28874 0.170135498046875 +28875 -0.0841064453125 +28876 0.16552734375 +28877 -0.025299072265625 +28878 0.15728759765625 +28879 0.036285400390625 +28880 0.150787353515625 +28881 0.100006103515625 +28882 0.12200927734375 +28883 0.148101806640625 +28884 0.080108642578125 +28885 0.182464599609375 +28886 0.05126953125 +28887 0.21539306640625 +28888 0.062896728515625 +28889 0.26043701171875 +28890 0.09271240234375 +28891 0.30279541015625 +28892 0.092987060546875 +28893 0.313629150390625 +28894 0.07855224609375 +28895 0.301422119140625 +28896 0.06427001953125 +28897 0.2755126953125 +28898 0.0347900390625 +28899 0.228240966796875 +28900 -0.01171875 +28901 0.160552978515625 +28902 -0.056060791015625 +28903 0.086151123046875 +28904 -0.055511474609375 +28905 0.032867431640625 +28906 -0.010467529296875 +28907 0.003570556640625 +28908 0.02508544921875 +28909 -0.0301513671875 +28910 0.025665283203125 +28911 -0.08026123046875 +28912 0.017333984375 +28913 -0.12890625 +28914 0.00189208984375 +28915 -0.1728515625 +28916 -0.03173828125 +28917 -0.2169189453125 +28918 -0.071502685546875 +28919 -0.2530517578125 +28920 -0.13543701171875 +28921 -0.291412353515625 +28922 -0.219970703125 +28923 -0.3302001953125 +28924 -0.300506591796875 +28925 -0.355926513671875 +28926 -0.376312255859375 +28927 -0.36962890625 +28928 -0.416107177734375 +28929 -0.354888916015625 +28930 -0.371124267578125 +28931 -0.28533935546875 +28932 -0.242279052734375 +28933 -0.164031982421875 +28934 -0.069732666015625 +28935 -0.017242431640625 +28936 0.125640869140625 +28937 0.14031982421875 +28938 0.31268310546875 +28939 0.28802490234375 +28940 0.45501708984375 +28941 0.402374267578125 +28942 0.554779052734375 +28943 0.48333740234375 +28944 0.61065673828125 +28945 0.52923583984375 +28946 0.610931396484375 +28947 0.53265380859375 +28948 0.531463623046875 +28949 0.479217529296875 +28950 0.3883056640625 +28951 0.37908935546875 +28952 0.23468017578125 +28953 0.26519775390625 +28954 0.095245361328125 +28955 0.153778076171875 +28956 -0.00396728515625 +28957 0.06207275390625 +28958 -0.04852294921875 +28959 0.000579833984375 +28960 -0.055145263671875 +28961 -0.0386962890625 +28962 -0.0758056640625 +28963 -0.085052490234375 +28964 -0.138702392578125 +28965 -0.153594970703125 +28966 -0.209197998046875 +28967 -0.221954345703125 +28968 -0.289031982421875 +28969 -0.289886474609375 +28970 -0.37884521484375 +28971 -0.356903076171875 +28972 -0.456329345703125 +28973 -0.409027099609375 +28974 -0.51641845703125 +28975 -0.44317626953125 +28976 -0.519287109375 +28977 -0.435791015625 +28978 -0.458251953125 +28979 -0.383544921875 +28980 -0.384796142578125 +28981 -0.318359375 +28982 -0.323699951171875 +28983 -0.25640869140625 +28984 -0.269287109375 +28985 -0.19580078125 +28986 -0.1951904296875 +28987 -0.122314453125 +28988 -0.100006103515625 +28989 -0.036712646484375 +28990 -0.01055908203125 +28991 0.0433349609375 +28992 0.1033935546875 +28993 0.134613037109375 +28994 0.24908447265625 +28995 0.240325927734375 +28996 0.373199462890625 +28997 0.327606201171875 +28998 0.45806884765625 +28999 0.385284423828125 +29000 0.511474609375 +29001 0.4178466796875 +29002 0.565399169921875 +29003 0.444671630859375 +29004 0.61138916015625 +29005 0.461151123046875 +29006 0.5897216796875 +29007 0.432220458984375 +29008 0.4906005859375 +29009 0.352996826171875 +29010 0.33148193359375 +29011 0.23516845703125 +29012 0.147796630859375 +29013 0.101226806640625 +29014 -0.01873779296875 +29015 -0.022430419921875 +29016 -0.140289306640625 +29017 -0.117767333984375 +29018 -0.191986083984375 +29019 -0.168701171875 +29020 -0.184295654296875 +29021 -0.18048095703125 +29022 -0.161834716796875 +29023 -0.179107666015625 +29024 -0.166595458984375 +29025 -0.189239501953125 +29026 -0.19390869140625 +29027 -0.207794189453125 +29028 -0.22442626953125 +29029 -0.22320556640625 +29030 -0.279754638671875 +29031 -0.24871826171875 +29032 -0.3389892578125 +29033 -0.272369384765625 +29034 -0.3543701171875 +29035 -0.26629638671875 +29036 -0.348175048828125 +29037 -0.244781494140625 +29038 -0.32598876953125 +29039 -0.212188720703125 +29040 -0.2581787109375 +29041 -0.151885986328125 +29042 -0.139801025390625 +29043 -0.06195068359375 +29044 0.014617919921875 +29045 0.047882080078125 +29046 0.144378662109375 +29047 0.1402587890625 +29048 0.221038818359375 +29049 0.197418212890625 +29050 0.27069091796875 +29051 0.234527587890625 +29052 0.294036865234375 +29053 0.251739501953125 +29054 0.311767578125 +29055 0.261383056640625 +29056 0.339141845703125 +29057 0.272857666015625 +29058 0.360260009765625 +29059 0.277191162109375 +29060 0.360504150390625 +29061 0.266143798828125 +29062 0.308380126953125 +29063 0.22088623046875 +29064 0.18170166015625 +29065 0.12847900390625 +29066 0.0047607421875 +29067 0.00469970703125 +29068 -0.17559814453125 +29069 -0.120819091796875 +29070 -0.3143310546875 +29071 -0.2196044921875 +29072 -0.36785888671875 +29073 -0.26409912109375 +29074 -0.36248779296875 +29075 -0.269927978515625 +29076 -0.343536376953125 +29077 -0.264617919921875 +29078 -0.3018798828125 +29079 -0.242279052734375 +29080 -0.231414794921875 +29081 -0.19903564453125 +29082 -0.117645263671875 +29083 -0.12603759765625 +29084 0.007049560546875 +29085 -0.043487548828125 +29086 0.087982177734375 +29087 0.0145263671875 +29088 0.13946533203125 +29089 0.056304931640625 +29090 0.17425537109375 +29091 0.089141845703125 +29092 0.188201904296875 +29093 0.10980224609375 +29094 0.171234130859375 +29095 0.11138916015625 +29096 0.118438720703125 +29097 0.090240478515625 +29098 0.05706787109375 +29099 0.06256103515625 +29100 -0.010711669921875 +29101 0.02911376953125 +29102 -0.0914306640625 +29103 -0.01446533203125 +29104 -0.162322998046875 +29105 -0.054412841796875 +29106 -0.194549560546875 +29107 -0.073150634765625 +29108 -0.1492919921875 +29109 -0.0467529296875 +29110 -0.02166748046875 +29111 0.0279541015625 +29112 0.124053955078125 +29113 0.1116943359375 +29114 0.211151123046875 +29115 0.157562255859375 +29116 0.240447998046875 +29117 0.16656494140625 +29118 0.242218017578125 +29119 0.1578369140625 +29120 0.2257080078125 +29121 0.137664794921875 +29122 0.194366455078125 +29123 0.108734130859375 +29124 0.115509033203125 +29125 0.0513916015625 +29126 0.0128173828125 +29127 -0.019256591796875 +29128 -0.053802490234375 +29129 -0.06597900390625 +29130 -0.110626220703125 +29131 -0.104705810546875 +29132 -0.199493408203125 +29133 -0.161041259765625 +29134 -0.29437255859375 +29135 -0.218963623046875 +29136 -0.33221435546875 +29137 -0.239715576171875 +29138 -0.27972412109375 +29139 -0.2030029296875 +29140 -0.185333251953125 +29141 -0.138916015625 +29142 -0.128204345703125 +29143 -0.0965576171875 +29144 -0.115692138671875 +29145 -0.08087158203125 +29146 -0.116455078125 +29147 -0.07305908203125 +29148 -0.105926513671875 +29149 -0.0584716796875 +29150 -0.053955078125 +29151 -0.018951416015625 +29152 0.048797607421875 +29153 0.05084228515625 +29154 0.157318115234375 +29155 0.122894287109375 +29156 0.212005615234375 +29157 0.16021728515625 +29158 0.218475341796875 +29159 0.166107177734375 +29160 0.23724365234375 +29161 0.17779541015625 +29162 0.30535888671875 +29163 0.218170166015625 +29164 0.38128662109375 +29165 0.261749267578125 +29166 0.404449462890625 +29167 0.27142333984375 +29168 0.3944091796875 +29169 0.259552001953125 +29170 0.3885498046875 +29171 0.24951171875 +29172 0.362640380859375 +29173 0.22674560546875 +29174 0.27362060546875 +29175 0.165130615234375 +29176 0.11712646484375 +29177 0.06231689453125 +29178 -0.054901123046875 +29179 -0.04931640625 +29180 -0.19085693359375 +29181 -0.1376953125 +29182 -0.28570556640625 +29183 -0.19952392578125 +29184 -0.339263916015625 +29185 -0.233917236328125 +29186 -0.3775634765625 +29187 -0.257110595703125 +29188 -0.445709228515625 +29189 -0.29833984375 +29190 -0.535064697265625 +29191 -0.352508544921875 +29192 -0.629058837890625 +29193 -0.409271240234375 +29194 -0.697601318359375 +29195 -0.449554443359375 +29196 -0.70391845703125 +29197 -0.4498291015625 +29198 -0.6424560546875 +29199 -0.406768798828125 +29200 -0.491241455078125 +29201 -0.306304931640625 +29202 -0.265716552734375 +29203 -0.1585693359375 +29204 -0.023712158203125 +29205 -0.001068115234375 +29206 0.201751708984375 +29207 0.144775390625 +29208 0.375823974609375 +29209 0.256439208984375 +29210 0.485076904296875 +29211 0.325347900390625 +29212 0.56884765625 +29213 0.37713623046875 +29214 0.634765625 +29215 0.416900634765625 +29216 0.63763427734375 +29217 0.415557861328125 +29218 0.5660400390625 +29219 0.36590576171875 +29220 0.4720458984375 +29221 0.301849365234375 +29222 0.40692138671875 +29223 0.256805419921875 +29224 0.3778076171875 +29225 0.23553466796875 +29226 0.376953125 +29227 0.233154296875 +29228 0.371978759765625 +29229 0.228790283203125 +29230 0.313140869140625 +29231 0.190216064453125 +29232 0.184417724609375 +29233 0.1070556640625 +29234 0.011199951171875 +29235 -0.004241943359375 +29236 -0.171051025390625 +29237 -0.120758056640625 +29238 -0.33740234375 +29239 -0.2264404296875 +29240 -0.47198486328125 +29241 -0.311126708984375 +29242 -0.560394287109375 +29243 -0.365692138671875 +29244 -0.58056640625 +29245 -0.3759765625 +29246 -0.54754638671875 +29247 -0.351898193359375 +29248 -0.508575439453125 +29249 -0.324188232421875 +29250 -0.459503173828125 +29251 -0.290283203125 +29252 -0.394378662109375 +29253 -0.2464599609375 +29254 -0.35260009765625 +29255 -0.218292236328125 +29256 -0.31170654296875 +29257 -0.191253662109375 +29258 -0.197418212890625 +29259 -0.11724853515625 +29260 -0.007965087890625 +29261 0.004852294921875 +29262 0.207489013671875 +29263 0.14324951171875 +29264 0.409210205078125 +29265 0.27227783203125 +29266 0.57208251953125 +29267 0.37579345703125 +29268 0.66595458984375 +29269 0.434356689453125 +29270 0.65875244140625 +29271 0.427337646484375 +29272 0.56744384765625 +29273 0.3658447265625 +29274 0.431396484375 +29275 0.2755126953125 +29276 0.29443359375 +29277 0.18487548828125 +29278 0.182464599609375 +29279 0.11077880859375 +29280 0.06365966796875 +29281 0.03271484375 +29282 -0.075958251953125 +29283 -0.058319091796875 +29284 -0.189422607421875 +29285 -0.131866455078125 +29286 -0.271942138671875 +29287 -0.184844970703125 +29288 -0.342529296875 +29289 -0.2296142578125 +29290 -0.364166259765625 +29291 -0.242279052734375 +29292 -0.327239990234375 +29293 -0.216705322265625 +29294 -0.2769775390625 +29295 -0.182281494140625 +29296 -0.253692626953125 +29297 -0.165252685546875 +29298 -0.24365234375 +29299 -0.15679931640625 +29300 -0.1983642578125 +29301 -0.125640869140625 +29302 -0.116241455078125 +29303 -0.070831298828125 +29304 -0.036834716796875 +29305 -0.018035888671875 +29306 0.034881591796875 +29307 0.0294189453125 +29308 0.09124755859375 +29309 0.0665283203125 +29310 0.10888671875 +29311 0.078155517578125 +29312 0.125518798828125 +29313 0.08868408203125 +29314 0.15771484375 +29315 0.108917236328125 +29316 0.17828369140625 +29317 0.12127685546875 +29318 0.17108154296875 +29319 0.115325927734375 +29320 0.129974365234375 +29321 0.08721923828125 +29322 0.082427978515625 +29323 0.0548095703125 +29324 0.027679443359375 +29325 0.017730712890625 +29326 -0.065643310546875 +29327 -0.04425048828125 +29328 -0.15936279296875 +29329 -0.1063232421875 +29330 -0.21307373046875 +29331 -0.142242431640625 +29332 -0.234649658203125 +29333 -0.1571044921875 +29334 -0.2001953125 +29335 -0.135345458984375 +29336 -0.119171142578125 +29337 -0.08306884765625 +29338 -0.024749755859375 +29339 -0.02178955078125 +29340 0.085784912109375 +29341 0.050262451171875 +29342 0.178131103515625 +29343 0.110809326171875 +29344 0.215576171875 +29345 0.136016845703125 +29346 0.211456298828125 +29347 0.13446044921875 +29348 0.17523193359375 +29349 0.112213134765625 +29350 0.128753662109375 +29351 0.0833740234375 +29352 0.1019287109375 +29353 0.067230224609375 +29354 0.0743408203125 +29355 0.050506591796875 +29356 0.04327392578125 +29357 0.0313720703125 +29358 0.038177490234375 +29359 0.028839111328125 +29360 0.076263427734375 +29361 0.054046630859375 +29362 0.14105224609375 +29363 0.096282958984375 +29364 0.186431884765625 +29365 0.12567138671875 +29366 0.188812255859375 +29367 0.126922607421875 +29368 0.1390380859375 +29369 0.094146728515625 +29370 0.041778564453125 +29371 0.0303955078125 +29372 -0.079437255859375 +29373 -0.04901123046875 +29374 -0.219390869140625 +29375 -0.140655517578125 +29376 -0.367828369140625 +29377 -0.237823486328125 +29378 -0.494873046875 +29379 -0.32110595703125 +29380 -0.556243896484375 +29381 -0.36175537109375 +29382 -0.508697509765625 +29383 -0.33172607421875 +29384 -0.3756103515625 +29385 -0.246124267578125 +29386 -0.218902587890625 +29387 -0.145050048828125 +29388 -0.063751220703125 +29389 -0.0447998046875 +29390 0.091552734375 +29391 0.05572509765625 +29392 0.23602294921875 +29393 0.149444580078125 +29394 0.342987060546875 +29395 0.219024658203125 +29396 0.39520263671875 +29397 0.2532958984375 +29398 0.389373779296875 +29399 0.2501220703125 +29400 0.324249267578125 +29401 0.208648681640625 +29402 0.224090576171875 +29403 0.14453125 +29404 0.124267578125 +29405 0.08062744140625 +29406 0.037078857421875 +29407 0.024871826171875 +29408 -0.010101318359375 +29409 -0.0050048828125 +29410 -0.019439697265625 +29411 -0.010467529296875 +29412 -0.022796630859375 +29413 -0.012176513671875 +29414 -0.001556396484375 +29415 0.001861572265625 +29416 0.056304931640625 +29417 0.039459228515625 +29418 0.106719970703125 +29419 0.072052001953125 +29420 0.096893310546875 +29421 0.065460205078125 +29422 0.042694091796875 +29423 0.02996826171875 +29424 -0.018035888671875 +29425 -0.0098876953125 +29426 -0.07586669921875 +29427 -0.047943115234375 +29428 -0.11944580078125 +29429 -0.0767822265625 +29430 -0.15972900390625 +29431 -0.103515625 +29432 -0.202606201171875 +29433 -0.13189697265625 +29434 -0.24859619140625 +29435 -0.162200927734375 +29436 -0.30517578125 +29437 -0.199249267578125 +29438 -0.36212158203125 +29439 -0.236419677734375 +29440 -0.39141845703125 +29441 -0.255462646484375 +29442 -0.35528564453125 +29443 -0.231719970703125 +29444 -0.249969482421875 +29445 -0.162872314453125 +29446 -0.092864990234375 +29447 -0.060028076171875 +29448 0.08905029296875 +29449 0.05908203125 +29450 0.2352294921875 +29451 0.15386962890625 +29452 0.318817138671875 +29453 0.206512451171875 +29454 0.358642578125 +29455 0.23016357421875 +29456 0.347747802734375 +29457 0.220367431640625 +29458 0.28564453125 +29459 0.176910400390625 +29460 0.223175048828125 +29461 0.1343994140625 +29462 0.196746826171875 +29463 0.1175537109375 +29464 0.179840087890625 +29465 0.10821533203125 +29466 0.155548095703125 +29467 0.094696044921875 +29468 0.151214599609375 +29469 0.09539794921875 +29470 0.156951904296875 +29471 0.10333251953125 +29472 0.13177490234375 +29473 0.090362548828125 +29474 0.100799560546875 +29475 0.073333740234375 +29476 0.087127685546875 +29477 0.06768798828125 +29478 0.05487060546875 +29479 0.048858642578125 +29480 -0.009002685546875 +29481 0.0078125 +29482 -0.10400390625 +29483 -0.05523681640625 +29484 -0.229400634765625 +29485 -0.139862060546875 +29486 -0.35552978515625 +29487 -0.22589111328125 +29488 -0.441925048828125 +29489 -0.285736083984375 +29490 -0.473846435546875 +29491 -0.309326171875 +29492 -0.464813232421875 +29493 -0.305694580078125 +29494 -0.419097900390625 +29495 -0.277618408203125 +29496 -0.334320068359375 +29497 -0.223297119140625 +29498 -0.227935791015625 +29499 -0.154388427734375 +29500 -0.12347412109375 +29501 -0.08673095703125 +29502 -0.02764892578125 +29503 -0.024688720703125 +29504 0.077667236328125 +29505 0.044219970703125 +29506 0.2132568359375 +29507 0.134246826171875 +29508 0.38885498046875 +29509 0.252105712890625 +29510 0.582794189453125 +29511 0.383148193359375 +29512 0.734039306640625 +29513 0.48590087890625 +29514 0.800140380859375 +29515 0.531494140625 +29516 0.7783203125 +29517 0.5179443359375 +29518 0.6651611328125 +29519 0.442840576171875 +29520 0.45965576171875 +29521 0.305419921875 +29522 0.199188232421875 +29523 0.1309814453125 +29524 -0.050689697265625 +29525 -0.03607177734375 +29526 -0.23297119140625 +29527 -0.157135009765625 +29528 -0.33013916015625 +29529 -0.220458984375 +29530 -0.368408203125 +29531 -0.2440185546875 +29532 -0.378936767578125 +29533 -0.249114990234375 +29534 -0.376983642578125 +29535 -0.246246337890625 +29536 -0.37969970703125 +29537 -0.247161865234375 +29538 -0.391510009765625 +29539 -0.254913330078125 +29540 -0.385345458984375 +29541 -0.251068115234375 +29542 -0.3419189453125 +29543 -0.22247314453125 +29544 -0.28289794921875 +29545 -0.183807373046875 +29546 -0.251617431640625 +29547 -0.1644287109375 +29548 -0.266143798828125 +29549 -0.176483154296875 +29550 -0.273345947265625 +29551 -0.183746337890625 +29552 -0.216796875 +29553 -0.147674560546875 +29554 -0.128265380859375 +29555 -0.0897216796875 +29556 -0.068145751953125 +29557 -0.050872802734375 +29558 -0.0430908203125 +29559 -0.035552978515625 +29560 -0.024444580078125 +29561 -0.024200439453125 +29562 0.020721435546875 +29563 0.005645751953125 +29564 0.124481201171875 +29565 0.075836181640625 +29566 0.25787353515625 +29567 0.1666259765625 +29568 0.379119873046875 +29569 0.249603271484375 +29570 0.47991943359375 +29571 0.319122314453125 +29572 0.5281982421875 +29573 0.353302001953125 +29574 0.511138916015625 +29575 0.34332275390625 +29576 0.456207275390625 +29577 0.307769775390625 +29578 0.407470703125 +29579 0.276519775390625 +29580 0.383758544921875 +29581 0.26226806640625 +29582 0.35687255859375 +29583 0.2457275390625 +29584 0.31182861328125 +29585 0.21661376953125 +29586 0.250885009765625 +29587 0.1763916015625 +29588 0.1654052734375 +29589 0.119140625 +29590 0.035247802734375 +29591 0.031097412109375 +29592 -0.142059326171875 +29593 -0.089385986328125 +29594 -0.33563232421875 +29595 -0.2213134765625 +29596 -0.5345458984375 +29597 -0.357208251953125 +29598 -0.72186279296875 +29599 -0.48553466796875 +29600 -0.836669921875 +29601 -0.564788818359375 +29602 -0.8326416015625 +29603 -0.56341552734375 +29604 -0.7296142578125 +29605 -0.49481201171875 +29606 -0.582550048828125 +29607 -0.396270751953125 +29608 -0.440093994140625 +29609 -0.30078125 +29610 -0.324310302734375 +29611 -0.22332763671875 +29612 -0.20147705078125 +29613 -0.140869140625 +29614 -0.044647216796875 +29615 -0.0350341796875 +29616 0.103973388671875 +29617 0.065521240234375 +29618 0.202392578125 +29619 0.132232666015625 +29620 0.264495849609375 +29621 0.174530029296875 +29622 0.338897705078125 +29623 0.2254638671875 +29624 0.443817138671875 +29625 0.29742431640625 +29626 0.545074462890625 +29627 0.36712646484375 +29628 0.6173095703125 +29629 0.417236328125 +29630 0.6524658203125 +29631 0.4422607421875 +29632 0.66339111328125 +29633 0.45086669921875 +29634 0.6561279296875 +29635 0.44708251953125 +29636 0.606781005859375 +29637 0.41455078125 +29638 0.501190185546875 +29639 0.3436279296875 +29640 0.352783203125 +29641 0.243377685546875 +29642 0.176544189453125 +29643 0.123992919921875 +29644 -0.034820556640625 +29645 -0.01947021484375 +29646 -0.258209228515625 +29647 -0.17132568359375 +29648 -0.44244384765625 +29649 -0.296783447265625 +29650 -0.5753173828125 +29651 -0.38751220703125 +29652 -0.65203857421875 +29653 -0.440216064453125 +29654 -0.641632080078125 +29655 -0.433807373046875 +29656 -0.562164306640625 +29657 -0.38055419921875 +29658 -0.458038330078125 +29659 -0.31060791015625 +29660 -0.350555419921875 +29661 -0.238372802734375 +29662 -0.260528564453125 +29663 -0.177978515625 +29664 -0.192108154296875 +29665 -0.1322021484375 +29666 -0.141937255859375 +29667 -0.098724365234375 +29668 -0.1021728515625 +29669 -0.07220458984375 +29670 -0.062896728515625 +29671 -0.04583740234375 +29672 -0.011932373046875 +29673 -0.011322021484375 +29674 0.062835693359375 +29675 0.03955078125 +29676 0.148712158203125 +29677 0.098175048828125 +29678 0.241729736328125 +29679 0.16180419921875 +29680 0.34912109375 +29681 0.2353515625 +29682 0.457305908203125 +29683 0.309539794921875 +29684 0.54388427734375 +29685 0.369110107421875 +29686 0.5728759765625 +29687 0.389556884765625 +29688 0.506591796875 +29689 0.345184326171875 +29690 0.351226806640625 +29691 0.240203857421875 +29692 0.146514892578125 +29693 0.1015625 +29694 -0.05523681640625 +29695 -0.03515625 +29696 -0.21624755859375 +29697 -0.144622802734375 +29698 -0.334930419921875 +29699 -0.225555419921875 +29700 -0.402984619140625 +29701 -0.271484375 +29702 -0.4412841796875 +29703 -0.297332763671875 +29704 -0.49578857421875 +29705 -0.335845947265625 +29706 -0.5601806640625 +29707 -0.382476806640625 +29708 -0.600738525390625 +29709 -0.4130859375 +29710 -0.584228515625 +29711 -0.40386962890625 +29712 -0.47930908203125 +29713 -0.332305908203125 +29714 -0.27935791015625 +29715 -0.193511962890625 +29716 -0.0089111328125 +29717 -0.00469970703125 +29718 0.268798828125 +29719 0.189300537109375 +29720 0.482818603515625 +29721 0.33819580078125 +29722 0.60369873046875 +29723 0.421173095703125 +29724 0.650421142578125 +29725 0.451904296875 +29726 0.66400146484375 +29727 0.459716796875 +29728 0.6414794921875 +29729 0.442596435546875 +29730 0.572540283203125 +29731 0.39324951171875 +29732 0.498138427734375 +29733 0.340789794921875 +29734 0.439453125 +29735 0.300262451171875 +29736 0.375518798828125 +29737 0.25665283203125 +29738 0.274505615234375 +29739 0.187164306640625 +29740 0.1087646484375 +29741 0.07196044921875 +29742 -0.099395751953125 +29743 -0.073211669921875 +29744 -0.3182373046875 +29745 -0.225921630859375 +29746 -0.5489501953125 +29747 -0.38720703125 +29748 -0.7738037109375 +29749 -0.544586181640625 +29750 -0.86383056640625 +29751 -0.6605224609375 +29752 -0.870391845703125 +29753 -0.71142578125 +29754 -0.86895751953125 +29755 -0.71002197265625 +29756 -0.861053466796875 +29757 -0.665679931640625 +29758 -0.765869140625 +29759 -0.56610107421875 +29760 -0.5301513671875 +29761 -0.403228759765625 +29762 -0.214691162109375 +29763 -0.182037353515625 +29764 0.137359619140625 +29765 0.06689453125 +29766 0.474822998046875 +29767 0.30712890625 +29768 0.76239013671875 +29769 0.513519287109375 +29770 0.867462158203125 +29771 0.666961669921875 +29772 0.870361328125 +29773 0.767913818359375 +29774 0.86480712890625 +29775 0.808319091796875 +29776 0.831817626953125 +29777 0.792083740234375 +29778 0.677581787109375 +29779 0.736663818359375 +29780 0.495880126953125 +29781 0.646270751953125 +29782 0.30767822265625 +29783 0.534149169921875 +29784 0.116180419921875 +29785 0.401885986328125 +29786 -0.110748291015625 +29787 0.226898193359375 +29788 -0.381805419921875 +29789 0.00421142578125 +29790 -0.6572265625 +29791 -0.23577880859375 +29792 -0.857421875 +29793 -0.450531005859375 +29794 -0.870391845703125 +29795 -0.60955810546875 +29796 -0.870391845703125 +29797 -0.707855224609375 +29798 -0.86444091796875 +29799 -0.76470947265625 +29800 -0.85723876953125 +29801 -0.805633544921875 +29802 -0.790008544921875 +29803 -0.817626953125 +29804 -0.62847900390625 +29805 -0.762176513671875 +29806 -0.3956298828125 +29807 -0.6370849609375 +29808 -0.126708984375 +29809 -0.46575927734375 +29810 0.150115966796875 +29811 -0.2677001953125 +29812 0.424041748046875 +29813 -0.05126953125 +29814 0.670623779296875 +29815 0.164306640625 +29816 0.854522705078125 +29817 0.35150146484375 +29818 0.866485595703125 +29819 0.497772216796875 +29820 0.86920166015625 +29821 0.59222412109375 +29822 0.8653564453125 +29823 0.6478271484375 +29824 0.857147216796875 +29825 0.6741943359375 +29826 0.766845703125 +29827 0.669342041015625 +29828 0.628509521484375 +29829 0.63702392578125 +29830 0.462127685546875 +29831 0.572479248046875 +29832 0.297210693359375 +29833 0.494171142578125 +29834 0.14862060546875 +29835 0.41094970703125 +29836 -0.00537109375 +29837 0.30657958984375 +29838 -0.15753173828125 +29839 0.186431884765625 +29840 -0.31304931640625 +29841 0.04791259765625 +29842 -0.48876953125 +29843 -0.118927001953125 +29844 -0.6416015625 +29845 -0.28076171875 +29846 -0.751373291015625 +29847 -0.41998291015625 +29848 -0.84619140625 +29849 -0.553070068359375 +29850 -0.861297607421875 +29851 -0.669586181640625 +29852 -0.863250732421875 +29853 -0.746002197265625 +29854 -0.856597900390625 +29855 -0.759857177734375 +29856 -0.7498779296875 +29857 -0.7198486328125 +29858 -0.624542236328125 +29859 -0.667205810546875 +29860 -0.47808837890625 +29861 -0.586334228515625 +29862 -0.253387451171875 +29863 -0.4356689453125 +29864 0.003692626953125 +29865 -0.24774169921875 +29866 0.2257080078125 +29867 -0.071258544921875 +29868 0.427154541015625 +29869 0.102691650390625 +29870 0.643218994140625 +29871 0.297119140625 +29872 0.855926513671875 +29873 0.50518798828125 +29874 0.870361328125 +29875 0.685638427734375 +29876 0.870361328125 +29877 0.80316162109375 +29878 0.862762451171875 +29879 0.85540771484375 +29880 0.79669189453125 +29881 0.855377197265625 +29882 0.595794677734375 +29883 0.795928955078125 +29884 0.362152099609375 +29885 0.683380126953125 +29886 0.1270751953125 +29887 0.54510498046875 +29888 -0.086944580078125 +29889 0.396209716796875 +29890 -0.2784423828125 +29891 0.238250732421875 +29892 -0.484832763671875 +29893 0.0465087890625 +29894 -0.729583740234375 +29895 -0.192626953125 +29896 -0.86688232421875 +29897 -0.44305419921875 +29898 -0.870391845703125 +29899 -0.65960693359375 +29900 -0.86859130859375 +29901 -0.8387451171875 +29902 -0.86279296875 +29903 -0.868072509765625 +29904 -0.817962646484375 +29905 -0.870391845703125 +29906 -0.6116943359375 +29907 -0.86260986328125 +29908 -0.3128662109375 +29909 -0.76226806640625 +29910 0.039398193359375 +29911 -0.527099609375 +29912 0.422821044921875 +29913 -0.238983154296875 +29914 0.805145263671875 +29915 0.07733154296875 +29916 0.870361328125 +29917 0.373016357421875 +29918 0.870361328125 +29919 0.60772705078125 +29920 0.860015869140625 +29921 0.77392578125 +29922 0.727935791015625 +29923 0.85589599609375 +29924 0.48114013671875 +29925 0.857940673828125 +29926 0.2059326171875 +29927 0.849639892578125 +29928 -0.06103515625 +29929 0.775909423828125 +29930 -0.29913330078125 +29931 0.6746826171875 +29932 -0.516204833984375 +29933 0.538055419921875 +29934 -0.7252197265625 +29935 0.357269287109375 +29936 -0.85980224609375 +29937 0.15203857421875 +29938 -0.870391845703125 +29939 -0.051513671875 +29940 -0.870391845703125 +29941 -0.231170654296875 +29942 -0.858062744140625 +29943 -0.351470947265625 +29944 -0.673004150390625 +29945 -0.409210205078125 +29946 -0.42694091796875 +29947 -0.441986083984375 +29948 -0.2100830078125 +29949 -0.4820556640625 +29950 -0.0362548828125 +29951 -0.529052734375 +29952 0.10943603515625 +29953 -0.564056396484375 +29954 0.23516845703125 +29955 -0.57476806640625 +29956 0.373687744140625 +29957 -0.5323486328125 +29958 0.517791748046875 +29959 -0.440032958984375 +29960 0.602783203125 +29961 -0.346405029296875 +29962 0.635711669921875 +29963 -0.249114990234375 +29964 0.655181884765625 +29965 -0.124603271484375 +29966 0.65948486328125 +29967 0.018798828125 +29968 0.651275634765625 +29969 0.174560546875 +29970 0.61846923828125 +29971 0.324249267578125 +29972 0.53753662109375 +29973 0.4405517578125 +29974 0.404144287109375 +29975 0.510528564453125 +29976 0.22186279296875 +29977 0.527862548828125 +29978 0.003997802734375 +29979 0.49456787109375 +29980 -0.22100830078125 +29981 0.425445556640625 +29982 -0.42449951171875 +29983 0.33734130859375 +29984 -0.579833984375 +29985 0.24761962890625 +29986 -0.641876220703125 +29987 0.189544677734375 +29988 -0.6177978515625 +29989 0.159515380859375 +29990 -0.575531005859375 +29991 0.110626220703125 +29992 -0.526336669921875 +29993 0.039825439453125 +29994 -0.42645263671875 +29995 -0.013702392578125 +29996 -0.2581787109375 +29997 -0.029205322265625 +29998 -0.068695068359375 +29999 -0.03375244140625 +30000 0.09222412109375 +30001 -0.056304931640625 +30002 0.232147216796875 +30003 -0.083526611328125 +30004 0.3509521484375 +30005 -0.108673095703125 +30006 0.410064697265625 +30007 -0.15478515625 +30008 0.372955322265625 +30009 -0.24481201171875 +30010 0.2554931640625 +30011 -0.36431884765625 +30012 0.10711669921875 +30013 -0.47564697265625 +30014 -0.052886962890625 +30015 -0.565338134765625 +30016 -0.186279296875 +30017 -0.60736083984375 +30018 -0.23291015625 +30019 -0.560943603515625 +30020 -0.209442138671875 +30021 -0.443572998046875 +30022 -0.174163818359375 +30023 -0.304595947265625 +30024 -0.126739501953125 +30025 -0.1502685546875 +30026 -0.048126220703125 +30027 0.02685546875 +30028 0.0426025390625 +30029 0.2061767578125 +30030 0.10748291015625 +30031 0.353546142578125 +30032 0.1409912109375 +30033 0.459808349609375 +30034 0.19708251953125 +30035 0.561187744140625 +30036 0.273651123046875 +30037 0.65350341796875 +30038 0.31768798828125 +30039 0.69610595703125 +30040 0.341094970703125 +30041 0.697998046875 +30042 0.368011474609375 +30043 0.678741455078125 +30044 0.37249755859375 +30045 0.621856689453125 +30046 0.30072021484375 +30047 0.49114990234375 +30048 0.1517333984375 +30049 0.290618896484375 +30050 -0.01470947265625 +30051 0.0699462890625 +30052 -0.1883544921875 +30053 -0.157684326171875 +30054 -0.372711181640625 +30055 -0.389495849609375 +30056 -0.51397705078125 +30057 -0.58038330078125 +30058 -0.57177734375 +30059 -0.695892333984375 +30060 -0.53948974609375 +30061 -0.727569580078125 +30062 -0.43511962890625 +30063 -0.68621826171875 +30064 -0.2962646484375 +30065 -0.598388671875 +30066 -0.161102294921875 +30067 -0.49224853515625 +30068 -0.0435791015625 +30069 -0.379058837890625 +30070 0.060394287109375 +30071 -0.257781982421875 +30072 0.13665771484375 +30073 -0.141876220703125 +30074 0.170135498046875 +30075 -0.04620361328125 +30076 0.16552734375 +30077 0.028533935546875 +30078 0.15728759765625 +30079 0.103485107421875 +30080 0.150787353515625 +30081 0.17816162109375 +30082 0.12200927734375 +30083 0.230377197265625 +30084 0.080108642578125 +30085 0.263092041015625 +30086 0.05126953125 +30087 0.2926025390625 +30088 0.062896728515625 +30089 0.3369140625 +30090 0.09271240234375 +30091 0.377899169921875 +30092 0.092987060546875 +30093 0.379547119140625 +30094 0.07855224609375 +30095 0.353271484375 +30096 0.06427001953125 +30097 0.311492919921875 +30098 0.0347900390625 +30099 0.244903564453125 +30100 -0.01171875 +30101 0.154937744140625 +30102 -0.056060791015625 +30103 0.059234619140625 +30104 -0.055511474609375 +30105 -0.006744384765625 +30106 -0.010467529296875 +30107 -0.039581298828125 +30108 0.02508544921875 +30109 -0.075775146484375 +30110 0.025665283203125 +30111 -0.1309814453125 +30112 0.017333984375 +30113 -0.183013916015625 +30114 0.00189208984375 +30115 -0.22833251953125 +30116 -0.03173828125 +30117 -0.273681640625 +30118 -0.071502685546875 +30119 -0.30938720703125 +30120 -0.13543701171875 +30121 -0.348907470703125 +30122 -0.219970703125 +30123 -0.390472412109375 +30124 -0.300506591796875 +30125 -0.41729736328125 +30126 -0.376312255859375 +30127 -0.430999755859375 +30128 -0.416107177734375 +30129 -0.410888671875 +30130 -0.371124267578125 +30131 -0.3236083984375 +30132 -0.242279052734375 +30133 -0.172882080078125 +30134 -0.069732666015625 +30135 0.008392333984375 +30136 0.125640869140625 +30137 0.20184326171875 +30138 0.31268310546875 +30139 0.38177490234375 +30140 0.45501708984375 +30141 0.519134521484375 +30142 0.554779052734375 +30143 0.61407470703125 +30144 0.61065673828125 +30145 0.664794921875 +30146 0.610931396484375 +30147 0.662384033203125 +30148 0.531463623046875 +30149 0.58941650390625 +30150 0.3883056640625 +30151 0.458892822265625 +30152 0.23468017578125 +30153 0.31201171875 +30154 0.095245361328125 +30155 0.16912841796875 +30156 -0.00396728515625 +30157 0.051910400390625 +30158 -0.04852294921875 +30159 -0.026397705078125 +30160 -0.055145263671875 +30161 -0.075714111328125 +30162 -0.0758056640625 +30163 -0.132293701171875 +30164 -0.138702392578125 +30165 -0.214996337890625 +30166 -0.209197998046875 +30167 -0.29620361328125 +30168 -0.289031982421875 +30169 -0.375885009765625 +30170 -0.37884521484375 +30171 -0.453643798828125 +30172 -0.456329345703125 +30173 -0.51251220703125 +30174 -0.51641845703125 +30175 -0.5489501953125 +30176 -0.519287109375 +30177 -0.534088134765625 +30178 -0.458251953125 +30179 -0.464111328125 +30180 -0.384796142578125 +30181 -0.37884521484375 +30182 -0.323699951171875 +30183 -0.298614501953125 +30184 -0.269287109375 +30185 -0.221160888671875 +30186 -0.1951904296875 +30187 -0.128997802734375 +30188 -0.100006103515625 +30189 -0.0230712890625 +30190 -0.01055908203125 +30191 0.074737548828125 +30192 0.1033935546875 +30193 0.18536376953125 +30194 0.24908447265625 +30195 0.31292724609375 +30196 0.373199462890625 +30197 0.416961669921875 +30198 0.45806884765625 +30199 0.483856201171875 +30200 0.511474609375 +30201 0.519439697265625 +30202 0.565399169921875 +30203 0.5479736328125 +30204 0.61138916015625 +30205 0.563995361328125 +30206 0.5897216796875 +30207 0.524261474609375 +30208 0.4906005859375 +30209 0.42279052734375 +30210 0.33148193359375 +30211 0.274078369140625 +30212 0.147796630859375 +30213 0.1063232421875 +30214 -0.01873779296875 +30215 -0.047515869140625 +30216 -0.140289306640625 +30217 -0.16497802734375 +30218 -0.191986083984375 +30219 -0.22601318359375 +30220 -0.184295654296875 +30221 -0.237396240234375 +30222 -0.161834716796875 +30223 -0.2318115234375 +30224 -0.166595458984375 +30225 -0.240264892578125 +30226 -0.19390869140625 +30227 -0.2591552734375 +30228 -0.22442626953125 +30229 -0.274261474609375 +30230 -0.279754638671875 +30231 -0.302398681640625 +30232 -0.3389892578125 +30233 -0.32879638671875 +30234 -0.3543701171875 +30235 -0.318756103515625 +30236 -0.348175048828125 +30237 -0.290252685546875 +30238 -0.32598876953125 +30239 -0.248809814453125 +30240 -0.2581787109375 +30241 -0.17364501953125 +30242 -0.139801025390625 +30243 -0.062347412109375 +30244 0.014617919921875 +30245 0.073028564453125 +30246 0.144378662109375 +30247 0.185943603515625 +30248 0.221038818359375 +30249 0.254364013671875 +30250 0.27069091796875 +30251 0.29736328125 +30252 0.294036865234375 +30253 0.31536865234375 +30254 0.311767578125 +30255 0.323974609375 +30256 0.339141845703125 +30257 0.335113525390625 +30258 0.360260009765625 +30259 0.33782958984375 +30260 0.360504150390625 +30261 0.321929931640625 +30262 0.308380126953125 +30263 0.2637939453125 +30264 0.18170166015625 +30265 0.147125244140625 +30266 0.0047607421875 +30267 -0.008209228515625 +30268 -0.17559814453125 +30269 -0.16497802734375 +30270 -0.3143310546875 +30271 -0.287384033203125 +30272 -0.36785888671875 +30273 -0.34088134765625 +30274 -0.36248779296875 +30275 -0.3453369140625 +30276 -0.343536376953125 +30277 -0.335540771484375 +30278 -0.3018798828125 +30279 -0.30426025390625 +30280 -0.231414794921875 +30281 -0.246826171875 +30282 -0.117645263671875 +30283 -0.1522216796875 +30284 0.007049560546875 +30285 -0.0460205078125 +30286 0.087982177734375 +30287 0.02874755859375 +30288 0.13946533203125 +30289 0.082489013671875 +30290 0.17425537109375 +30291 0.124298095703125 +30292 0.188201904296875 +30293 0.15008544921875 +30294 0.171234130859375 +30295 0.15118408203125 +30296 0.118438720703125 +30297 0.123077392578125 +30298 0.05706787109375 +30299 0.08624267578125 +30300 -0.010711669921875 +30301 0.04180908203125 +30302 -0.0914306640625 +30303 -0.015625 +30304 -0.162322998046875 +30305 -0.068603515625 +30306 -0.194549560546875 +30307 -0.09478759765625 +30308 -0.1492919921875 +30309 -0.063873291015625 +30310 -0.02166748046875 +30311 0.028228759765625 +30312 0.124053955078125 +30313 0.13214111328125 +30314 0.211151123046875 +30315 0.188873291015625 +30316 0.240447998046875 +30317 0.19970703125 +30318 0.242218017578125 +30319 0.18878173828125 +30320 0.2257080078125 +30321 0.16400146484375 +30322 0.194366455078125 +30323 0.128692626953125 +30324 0.115509033203125 +30325 0.058013916015625 +30326 0.0128173828125 +30327 -0.029144287109375 +30328 -0.053802490234375 +30329 -0.085968017578125 +30330 -0.110626220703125 +30331 -0.13262939453125 +30332 -0.199493408203125 +30333 -0.2015380859375 +30334 -0.29437255859375 +30335 -0.2725830078125 +30336 -0.33221435546875 +30337 -0.2969970703125 +30338 -0.27972412109375 +30339 -0.24932861328125 +30340 -0.185333251953125 +30341 -0.167572021484375 +30342 -0.128204345703125 +30343 -0.113677978515625 +30344 -0.115692138671875 +30345 -0.0938720703125 +30346 -0.116455078125 +30347 -0.08441162109375 +30348 -0.105926513671875 +30349 -0.066802978515625 +30350 -0.053955078125 +30351 -0.01812744140625 +30352 0.048797607421875 +30353 0.06842041015625 +30354 0.157318115234375 +30355 0.1575927734375 +30356 0.212005615234375 +30357 0.202911376953125 +30358 0.218475341796875 +30359 0.208648681640625 +30360 0.23724365234375 +30361 0.221771240234375 +30362 0.30535888671875 +30363 0.27117919921875 +30364 0.38128662109375 +30365 0.324859619140625 +30366 0.404449462890625 +30367 0.336151123046875 +30368 0.3944091796875 +30369 0.320648193359375 +30370 0.3885498046875 +30371 0.30780029296875 +30372 0.362640380859375 +30373 0.279327392578125 +30374 0.27362060546875 +30375 0.202239990234375 +30376 0.11712646484375 +30377 0.073577880859375 +30378 -0.054901123046875 +30379 -0.065948486328125 +30380 -0.19085693359375 +30381 -0.176025390625 +30382 -0.28570556640625 +30383 -0.252532958984375 +30384 -0.339263916015625 +30385 -0.295257568359375 +30386 -0.3775634765625 +30387 -0.3243408203125 +30388 -0.445709228515625 +30389 -0.3748779296875 +30390 -0.535064697265625 +30391 -0.44036865234375 +30392 -0.629058837890625 +30393 -0.5081787109375 +30394 -0.697601318359375 +30395 -0.5552978515625 +30396 -0.70391845703125 +30397 -0.55352783203125 +30398 -0.6424560546875 +30399 -0.498931884765625 +30400 -0.491241455078125 +30401 -0.3748779296875 +30402 -0.265716552734375 +30403 -0.19366455078125 +30404 -0.023712158203125 +30405 -0.000518798828125 +30406 0.201751708984375 +30407 0.17864990234375 +30408 0.375823974609375 +30409 0.316619873046875 +30410 0.485076904296875 +30411 0.40283203125 +30412 0.56884765625 +30413 0.4677734375 +30414 0.634765625 +30415 0.517425537109375 +30416 0.63763427734375 +30417 0.516845703125 +30418 0.5660400390625 +30419 0.457366943359375 +30420 0.4720458984375 +30421 0.379638671875 +30422 0.40692138671875 +30423 0.323699951171875 +30424 0.3778076171875 +30425 0.295440673828125 +30426 0.376953125 +30427 0.289154052734375 +30428 0.371978759765625 +30429 0.280029296875 +30430 0.313140869140625 +30431 0.229736328125 +30432 0.184417724609375 +30433 0.126068115234375 +30434 0.011199951171875 +30435 -0.011077880859375 +30436 -0.171051025390625 +30437 -0.154083251953125 +30438 -0.33740234375 +30439 -0.283538818359375 +30440 -0.47198486328125 +30441 -0.387115478515625 +30442 -0.560394287109375 +30443 -0.4537353515625 +30444 -0.58056640625 +30445 -0.466461181640625 +30446 -0.54754638671875 +30447 -0.437103271484375 +30448 -0.508575439453125 +30449 -0.402587890625 +30450 -0.459503173828125 +30451 -0.359893798828125 +30452 -0.394378662109375 +30453 -0.304718017578125 +30454 -0.35260009765625 +30455 -0.267852783203125 +30456 -0.31170654296875 +30457 -0.232086181640625 +30458 -0.197418212890625 +30459 -0.139984130859375 +30460 -0.007965087890625 +30461 0.009613037109375 +30462 0.207489013671875 +30463 0.178436279296875 +30464 0.409210205078125 +30465 0.33563232421875 +30466 0.57208251953125 +30467 0.462310791015625 +30468 0.66595458984375 +30469 0.534698486328125 +30470 0.65875244140625 +30471 0.526580810546875 +30472 0.56744384765625 +30473 0.451416015625 +30474 0.431396484375 +30475 0.340850830078125 +30476 0.29443359375 +30477 0.2301025390625 +30478 0.182464599609375 +30479 0.13995361328125 +30480 0.06365966796875 +30481 0.044586181640625 +30482 -0.075958251953125 +30483 -0.0673828125 +30484 -0.189422607421875 +30485 -0.158050537109375 +30486 -0.271942138671875 +30487 -0.223602294921875 +30488 -0.342529296875 +30489 -0.27947998046875 +30490 -0.364166259765625 +30491 -0.29583740234375 +30492 -0.327239990234375 +30493 -0.264923095703125 +30494 -0.2769775390625 +30495 -0.22332763671875 +30496 -0.253692626953125 +30497 -0.203643798828125 +30498 -0.24365234375 +30499 -0.194793701171875 +30500 -0.1983642578125 +30501 -0.157623291015625 +30502 -0.116241455078125 +30503 -0.090850830078125 +30504 -0.036834716796875 +30505 -0.02642822265625 +30506 0.034881591796875 +30507 0.031585693359375 +30508 0.09124755859375 +30509 0.076995849609375 +30510 0.10888671875 +30511 0.090972900390625 +30512 0.125518798828125 +30513 0.103973388671875 +30514 0.15771484375 +30515 0.129425048828125 +30516 0.17828369140625 +30517 0.145355224609375 +30518 0.17108154296875 +30519 0.1387939453125 +30520 0.129974365234375 +30521 0.104827880859375 +30522 0.082427978515625 +30523 0.065673828125 +30524 0.027679443359375 +30525 0.02081298828125 +30526 -0.065643310546875 +30527 -0.055084228515625 +30528 -0.15936279296875 +30529 -0.131134033203125 +30530 -0.21307373046875 +30531 -0.174713134765625 +30532 -0.234649658203125 +30533 -0.192169189453125 +30534 -0.2001953125 +30535 -0.164215087890625 +30536 -0.119171142578125 +30537 -0.0985107421875 +30538 -0.024749755859375 +30539 -0.021881103515625 +30540 0.085784912109375 +30541 0.06787109375 +30542 0.178131103515625 +30543 0.14300537109375 +30544 0.215576171875 +30545 0.173828125 +30546 0.211456298828125 +30547 0.171051025390625 +30548 0.17523193359375 +30549 0.142303466796875 +30550 0.128753662109375 +30551 0.105194091796875 +30552 0.1019287109375 +30553 0.083892822265625 +30554 0.0743408203125 +30555 0.0618896484375 +30556 0.04327392578125 +30557 0.036956787109375 +30558 0.038177490234375 +30559 0.03289794921875 +30560 0.076263427734375 +30561 0.063629150390625 +30562 0.14105224609375 +30563 0.1158447265625 +30564 0.186431884765625 +30565 0.15228271484375 +30566 0.188812255859375 +30567 0.153900146484375 +30568 0.1390380859375 +30569 0.11328125 +30570 0.041778564453125 +30571 0.03424072265625 +30572 -0.079437255859375 +30573 -0.06414794921875 +30574 -0.219390869140625 +30575 -0.17767333984375 +30576 -0.367828369140625 +30577 -0.298004150390625 +30578 -0.494873046875 +30579 -0.4010009765625 +30580 -0.556243896484375 +30581 -0.450836181640625 +30582 -0.508697509765625 +30583 -0.412567138671875 +30584 -0.3756103515625 +30585 -0.305084228515625 +30586 -0.218902587890625 +30587 -0.178436279296875 +30588 -0.063751220703125 +30589 -0.052978515625 +30590 0.091552734375 +30591 0.072662353515625 +30592 0.23602294921875 +30593 0.189605712890625 +30594 0.342987060546875 +30595 0.27630615234375 +30596 0.39520263671875 +30597 0.318817138671875 +30598 0.389373779296875 +30599 0.314453125 +30600 0.324249267578125 +30601 0.26220703125 +30602 0.224090576171875 +30603 0.181640625 +30604 0.124267578125 +30605 0.101287841796875 +30606 0.037078857421875 +30607 0.03106689453125 +30608 -0.010101318359375 +30609 -0.006866455078125 +30610 -0.019439697265625 +30611 -0.014312744140625 +30612 -0.022796630859375 +30613 -0.016998291015625 +30614 -0.001556396484375 +30615 9.1552734375e-05 +30616 0.056304931640625 +30617 0.04669189453125 +30618 0.106719970703125 +30619 0.08721923828125 +30620 0.096893310546875 +30621 0.079010009765625 +30622 0.042694091796875 +30623 0.034942626953125 +30624 -0.018035888671875 +30625 -0.014434814453125 +30626 -0.07586669921875 +30627 -0.06146240234375 +30628 -0.11944580078125 +30629 -0.096954345703125 +30630 -0.15972900390625 +30631 -0.1297607421875 +30632 -0.202606201171875 +30633 -0.16461181640625 +30634 -0.24859619140625 +30635 -0.201904296875 +30636 -0.30517578125 +30637 -0.2476806640625 +30638 -0.36212158203125 +30639 -0.293670654296875 +30640 -0.39141845703125 +30641 -0.317291259765625 +30642 -0.35528564453125 +30643 -0.2879638671875 +30644 -0.249969482421875 +30645 -0.20269775390625 +30646 -0.092864990234375 +30647 -0.0755615234375 +30648 0.08905029296875 +30649 0.0716552734375 +30650 0.2352294921875 +30651 0.19000244140625 +30652 0.318817138671875 +30653 0.257781982421875 +30654 0.358642578125 +30655 0.290191650390625 +30656 0.347747802734375 +30657 0.281585693359375 +30658 0.28564453125 +30659 0.2315673828125 +30660 0.223175048828125 +30661 0.18121337890625 +30662 0.196746826171875 +30663 0.159942626953125 +30664 0.179840087890625 +30665 0.146331787109375 +30666 0.155548095703125 +30667 0.126678466796875 +30668 0.151214599609375 +30669 0.12310791015625 +30670 0.156951904296875 +30671 0.12762451171875 +30672 0.13177490234375 +30673 0.10711669921875 +30674 0.100799560546875 +30675 0.0819091796875 +30676 0.087127685546875 +30677 0.070648193359375 +30678 0.05487060546875 +30679 0.044342041015625 +30680 -0.009002685546875 +30681 -0.00750732421875 +30682 -0.10400390625 +30683 -0.08447265625 +30684 -0.229400634765625 +30685 -0.18597412109375 +30686 -0.35552978515625 +30687 -0.28802490234375 +30688 -0.441925048828125 +30689 -0.357879638671875 +30690 -0.473846435546875 +30691 -0.383697509765625 +30692 -0.464813232421875 +30693 -0.3763427734375 +30694 -0.419097900390625 +30695 -0.33929443359375 +30696 -0.334320068359375 +30697 -0.2706298828125 +30698 -0.227935791015625 +30699 -0.1844482421875 +30700 -0.12347412109375 +30701 -0.099822998046875 +30702 -0.02764892578125 +30703 -0.022186279296875 +30704 0.077667236328125 +30705 0.063140869140625 +30706 0.2132568359375 +30707 0.17291259765625 +30708 0.38885498046875 +30709 0.314971923828125 +30710 0.582794189453125 +30711 0.4718017578125 +30712 0.734039306640625 +30713 0.594085693359375 +30714 0.800140380859375 +30715 0.64752197265625 +30716 0.7783203125 +30717 0.629852294921875 +30718 0.6651611328125 +30719 0.538299560546875 +30720 0.45965576171875 +30721 0.371612548828125 +30722 0.199188232421875 +30723 0.159454345703125 +30724 -0.050689697265625 +30725 -0.044219970703125 +30726 -0.23297119140625 +30727 -0.19171142578125 +30728 -0.33013916015625 +30729 -0.2684326171875 +30730 -0.368408203125 +30731 -0.2965087890625 +30732 -0.378936767578125 +30733 -0.302215576171875 +30734 -0.376983642578125 +30735 -0.2984619140625 +30736 -0.37969970703125 +30737 -0.29974365234375 +30738 -0.391510009765625 +30739 -0.309722900390625 +30740 -0.385345458984375 +30741 -0.30560302734375 +30742 -0.3419189453125 +30743 -0.271087646484375 +30744 -0.28289794921875 +30745 -0.2242431640625 +30746 -0.251617431640625 +30747 -0.2012939453125 +30748 -0.266143798828125 +30749 -0.21722412109375 +30750 -0.273345947265625 +30751 -0.227203369140625 +30752 -0.216796875 +30753 -0.18359375 +30754 -0.128265380859375 +30755 -0.112884521484375 +30756 -0.068145751953125 +30757 -0.065643310546875 +30758 -0.0430908203125 +30759 -0.04730224609375 +30760 -0.024444580078125 +30761 -0.03363037109375 +30762 0.020721435546875 +30763 0.00311279296875 +30764 0.124481201171875 +30765 0.08990478515625 +30766 0.25787353515625 +30767 0.202392578125 +30768 0.379119873046875 +30769 0.305389404296875 +30770 0.47991943359375 +30771 0.39190673828125 +30772 0.5281982421875 +30773 0.434844970703125 +30774 0.511138916015625 +30775 0.423309326171875 +30776 0.456207275390625 +30777 0.380218505859375 +30778 0.407470703125 +30779 0.3424072265625 +30780 0.383758544921875 +30781 0.325531005859375 +30782 0.35687255859375 +30783 0.30572509765625 +30784 0.31182861328125 +30785 0.270263671875 +30786 0.250885009765625 +30787 0.220916748046875 +30788 0.1654052734375 +30789 0.150360107421875 +30790 0.035247802734375 +30791 0.0416259765625 +30792 -0.142059326171875 +30793 -0.10736083984375 +30794 -0.33563232421875 +30795 -0.270660400390625 +30796 -0.5345458984375 +30797 -0.43902587890625 +30798 -0.72186279296875 +30799 -0.59814453125 +30800 -0.836669921875 +30801 -0.696746826171875 +30802 -0.8326416015625 +30803 -0.69580078125 +30804 -0.7296142578125 +30805 -0.611846923828125 +30806 -0.582550048828125 +30807 -0.490875244140625 +30808 -0.440093994140625 +30809 -0.37359619140625 +30810 -0.324310302734375 +30811 -0.2784423828125 +30812 -0.20147705078125 +30813 -0.177001953125 +30814 -0.044647216796875 +30815 -0.0465087890625 +30816 0.103973388671875 +30817 0.07763671875 +30818 0.202392578125 +30819 0.16015625 +30820 0.264495849609375 +30821 0.21270751953125 +30822 0.338897705078125 +30823 0.276092529296875 +30824 0.443817138671875 +30825 0.36553955078125 +30826 0.545074462890625 +30827 0.452239990234375 +30828 0.6173095703125 +30829 0.514801025390625 +30830 0.6524658203125 +30831 0.54638671875 +30832 0.66339111328125 +30833 0.557647705078125 +30834 0.6561279296875 +30835 0.553558349609375 +30836 0.606781005859375 +30837 0.513916015625 +30838 0.501190185546875 +30839 0.426727294921875 +30840 0.352783203125 +30841 0.30322265625 +30842 0.176544189453125 +30843 0.155914306640625 +30844 -0.034820556640625 +30845 -0.02130126953125 +30846 -0.258209228515625 +30847 -0.20904541015625 +30848 -0.44244384765625 +30849 -0.36431884765625 +30850 -0.5753173828125 +30851 -0.476806640625 +30852 -0.65203857421875 +30853 -0.542449951171875 +30854 -0.641632080078125 +30855 -0.535125732421875 +30856 -0.562164306640625 +30857 -0.469940185546875 +30858 -0.458038330078125 +30859 -0.384124755859375 +30860 -0.350555419921875 +30861 -0.29547119140625 +30862 -0.260528564453125 +30863 -0.221343994140625 +30864 -0.192108154296875 +30865 -0.165191650390625 +30866 -0.141937255859375 +30867 -0.1241455078125 +30868 -0.1021728515625 +30869 -0.091552734375 +30870 -0.062896728515625 +30871 -0.05902099609375 +30872 -0.011932373046875 +30873 -0.01629638671875 +30874 0.062835693359375 +30875 0.046783447265625 +30876 0.148712158203125 +30877 0.119537353515625 +30878 0.241729736328125 +30879 0.19854736328125 +30880 0.34912109375 +30881 0.28985595703125 +30882 0.457305908203125 +30883 0.381988525390625 +30884 0.54388427734375 +30885 0.4560546875 +30886 0.5728759765625 +30887 0.481781005859375 +30888 0.506591796875 +30889 0.427398681640625 +30890 0.351226806640625 +30891 0.298065185546875 +30892 0.146514892578125 +30893 0.127105712890625 +30894 -0.05523681640625 +30895 -0.041595458984375 +30896 -0.21624755859375 +30897 -0.176361083984375 +30898 -0.334930419921875 +30899 -0.27587890625 +30900 -0.402984619140625 +30901 -0.333160400390625 +30902 -0.4412841796875 +30903 -0.36572265625 +30904 -0.49578857421875 +30905 -0.412139892578125 +30906 -0.5601806640625 +30907 -0.467071533203125 +30908 -0.600738525390625 +30909 -0.50213623046875 +30910 -0.584228515625 +30911 -0.489349365234375 +30912 -0.47930908203125 +30913 -0.402313232421875 +30914 -0.27935791015625 +30915 -0.235443115234375 +30916 -0.0089111328125 +30917 -0.00927734375 +30918 0.268798828125 +30919 0.22308349609375 +30920 0.482818603515625 +30921 0.402130126953125 +30922 0.60369873046875 +30923 0.503143310546875 +30924 0.650421142578125 +30925 0.542083740234375 +30926 0.66400146484375 +30927 0.553436279296875 +30928 0.6414794921875 +30929 0.53466796875 +30930 0.572540283203125 +30931 0.47711181640625 +30932 0.498138427734375 +30933 0.4151611328125 +30934 0.439453125 +30935 0.3665771484375 +30936 0.375518798828125 +30937 0.313690185546875 +30938 0.274505615234375 +30939 0.229705810546875 +30940 0.1087646484375 +30941 0.09136962890625 +30942 -0.099395751953125 +30943 -0.0826416015625 +30944 -0.3182373046875 +30945 -0.265655517578125 +30946 -0.5489501953125 +30947 -0.458770751953125 +30948 -0.7738037109375 +30949 -0.647064208984375 +30950 -0.86383056640625 +30951 -0.7861328125 +30952 -0.870391845703125 +30953 -0.848052978515625 +30954 -0.86895751953125 +30955 -0.847686767578125 +30956 -0.861053466796875 +30957 -0.79608154296875 +30958 -0.765869140625 +30959 -0.678680419921875 +30960 -0.5301513671875 +30961 -0.485992431640625 +30962 -0.214691162109375 +30963 -0.223968505859375 +30964 0.137359619140625 +30965 0.071258544921875 +30966 0.474822998046875 +30967 0.35662841796875 +30968 0.76239013671875 +30969 0.602325439453125 +30970 0.867462158203125 +30971 0.78570556640625 +30972 0.870361328125 +30973 0.8602294921875 +30974 0.86480712890625 +30975 0.86566162109375 +30976 0.831817626953125 +30977 0.863800048828125 +30978 0.677581787109375 +30979 0.856903076171875 +30980 0.495880126953125 +30981 0.77191162109375 +30982 0.30767822265625 +30983 0.64141845703125 +30984 0.116180419921875 +30985 0.48681640625 +30986 -0.110748291015625 +30987 0.27996826171875 +30988 -0.381805419921875 +30989 0.014312744140625 +30990 -0.6572265625 +30991 -0.273223876953125 +30992 -0.857421875 +30993 -0.5308837890625 +30994 -0.870391845703125 +30995 -0.72161865234375 +30996 -0.870391845703125 +30997 -0.8394775390625 +30998 -0.86444091796875 +30999 -0.8603515625 +31000 -0.85723876953125 +31001 -0.86590576171875 +31002 -0.790008544921875 +31003 -0.86773681640625 +31004 -0.62847900390625 +31005 -0.8607177734375 +31006 -0.3956298828125 +31007 -0.762725830078125 +31008 -0.126708984375 +31009 -0.558319091796875 +31010 0.150115966796875 +31011 -0.321685791015625 +31012 0.424041748046875 +31013 -0.062744140625 +31014 0.670623779296875 +31015 0.195343017578125 +31016 0.854522705078125 +31017 0.419158935546875 +31018 0.866485595703125 +31019 0.5936279296875 +31020 0.86920166015625 +31021 0.70562744140625 +31022 0.8653564453125 +31023 0.771270751953125 +31024 0.857147216796875 +31025 0.80242919921875 +31026 0.766845703125 +31027 0.796661376953125 +31028 0.628509521484375 +31029 0.758453369140625 +31030 0.462127685546875 +31031 0.68194580078125 +31032 0.297210693359375 +31033 0.58953857421875 +31034 0.14862060546875 +31035 0.491851806640625 +31036 -0.00537109375 +31037 0.3687744140625 +31038 -0.15753173828125 +31039 0.226593017578125 +31040 -0.31304931640625 +31041 0.0618896484375 +31042 -0.48876953125 +31043 -0.137847900390625 +31044 -0.6416015625 +31045 -0.332000732421875 +31046 -0.751373291015625 +31047 -0.499237060546875 +31048 -0.84619140625 +31049 -0.659881591796875 +31050 -0.861297607421875 +31051 -0.80126953125 +31052 -0.863250732421875 +31053 -0.85888671875 +31054 -0.856597900390625 +31055 -0.860809326171875 +31056 -0.7498779296875 +31057 -0.855682373046875 +31058 -0.624542236328125 +31059 -0.8033447265625 +31060 -0.47808837890625 +31061 -0.7076416015625 +31062 -0.253387451171875 +31063 -0.526947021484375 +31064 0.003692626953125 +31065 -0.300872802734375 +31066 0.2257080078125 +31067 -0.08880615234375 +31068 0.427154541015625 +31069 0.120361328125 +31070 0.643218994140625 +31071 0.35504150390625 +31072 0.855926513671875 +31073 0.607025146484375 +31074 0.870361328125 +31075 0.825927734375 +31076 0.870361328125 +31077 0.866912841796875 +31078 0.862762451171875 +31079 0.870361328125 +31080 0.79669189453125 +31081 0.866241455078125 +31082 0.595794677734375 +31083 0.849365234375 +31084 0.362152099609375 +31085 0.688079833984375 +31086 0.1270751953125 +31087 0.5040283203125 +31088 -0.086944580078125 +31089 0.316253662109375 +31090 -0.2784423828125 +31091 0.126708984375 +31092 -0.484832763671875 +31093 -0.095306396484375 +31094 -0.729583740234375 +31095 -0.367431640625 +31096 -0.86688232421875 +31097 -0.646820068359375 +31098 -0.870391845703125 +31099 -0.857269287109375 +31100 -0.86859130859375 +31101 -0.870391845703125 +31102 -0.86279296875 +31103 -0.870391845703125 +31104 -0.817962646484375 +31105 -0.86346435546875 +31106 -0.6116943359375 +31107 -0.778167724609375 +31108 -0.3128662109375 +31109 -0.52508544921875 +31110 0.039398193359375 +31111 -0.211395263671875 +31112 0.422821044921875 +31113 0.142669677734375 +31114 0.805145263671875 +31115 0.50750732421875 +31116 0.870361328125 +31117 0.8251953125 +31118 0.870361328125 +31119 0.870361328125 +31120 0.860015869140625 +31121 0.870361328125 +31122 0.727935791015625 +31123 0.860992431640625 +31124 0.48114013671875 +31125 0.75042724609375 +31126 0.2059326171875 +31127 0.542449951171875 +31128 -0.06103515625 +31129 0.320953369140625 +31130 -0.29913330078125 +31131 0.1038818359375 +31132 -0.516204833984375 +31133 -0.114471435546875 +31134 -0.7252197265625 +31135 -0.343231201171875 +31136 -0.85980224609375 +31137 -0.55914306640625 +31138 -0.870391845703125 +31139 -0.733428955078125 +31140 -0.870391845703125 +31141 -0.844024658203125 +31142 -0.858062744140625 +31143 -0.8544921875 +31144 -0.673004150390625 +31145 -0.769134521484375 +31146 -0.42694091796875 +31147 -0.64306640625 +31148 -0.2100830078125 +31149 -0.525177001953125 +31150 -0.0362548828125 +31151 -0.424102783203125 +31152 0.10943603515625 +31153 -0.32470703125 +31154 0.23516845703125 +31155 -0.219024658203125 +31156 0.373687744140625 +31157 -0.07891845703125 +31158 0.517791748046875 +31159 0.0875244140625 +31160 0.602783203125 +31161 0.221099853515625 +31162 0.635711669921875 +31163 0.324188232421875 +31164 0.655181884765625 +31165 0.425933837890625 +31166 0.65948486328125 +31167 0.519927978515625 +31168 0.651275634765625 +31169 0.603424072265625 +31170 0.61846923828125 +31171 0.660919189453125 +31172 0.53753662109375 +31173 0.667327880859375 +31174 0.404144287109375 +31175 0.614959716796875 +31176 0.22186279296875 +31177 0.503814697265625 +31178 0.003997802734375 +31179 0.3433837890625 +31180 -0.22100830078125 +31181 0.1573486328125 +31182 -0.42449951171875 +31183 -0.029296875 +31184 -0.579833984375 +31185 -0.1922607421875 +31186 -0.641876220703125 +31187 -0.2901611328125 +31188 -0.6177978515625 +31189 -0.326385498046875 +31190 -0.575531005859375 +31191 -0.356689453125 +31192 -0.526336669921875 +31193 -0.386932373046875 +31194 -0.42645263671875 +31195 -0.374847412109375 +31196 -0.2581787109375 +31197 -0.30078125 +31198 -0.068695068359375 +31199 -0.20196533203125 +31200 0.09222412109375 +31201 -0.11834716796875 +31202 0.232147216796875 +31203 -0.04052734375 +31204 0.3509521484375 +31205 0.03338623046875 +31206 0.410064697265625 +31207 0.070953369140625 +31208 0.372955322265625 +31209 0.0406494140625 +31210 0.2554931640625 +31211 -0.044219970703125 +31212 0.10711669921875 +31213 -0.141998291015625 +31214 -0.052886962890625 +31215 -0.238006591796875 +31216 -0.186279296875 +31217 -0.30157470703125 +31218 -0.23291015625 +31219 -0.283416748046875 +31220 -0.209442138671875 +31221 -0.201446533203125 +31222 -0.174163818359375 +31223 -0.109893798828125 +31224 -0.126739501953125 +31225 -0.01177978515625 +31226 -0.048126220703125 +31227 0.106475830078125 +31228 0.0426025390625 +31229 0.22576904296875 +31230 0.10748291015625 +31231 0.31109619140625 +31232 0.1409912109375 +31233 0.35687255859375 +31234 0.19708251953125 +31235 0.410369873046875 +31236 0.273651123046875 +31237 0.469207763671875 +31238 0.31768798828125 +31239 0.4866943359375 +31240 0.341094970703125 +31241 0.47515869140625 +31242 0.368011474609375 +31243 0.458465576171875 +31244 0.37249755859375 +31245 0.415771484375 +31246 0.30072021484375 +31247 0.3013916015625 +31248 0.1517333984375 +31249 0.117279052734375 +31250 -0.01470947265625 +31251 -0.080047607421875 +31252 -0.1883544921875 +31253 -0.278839111328125 +31254 -0.372711181640625 +31255 -0.480072021484375 +31256 -0.51397705078125 +31257 -0.63360595703125 +31258 -0.57177734375 +31259 -0.701873779296875 +31260 -0.53948974609375 +31261 -0.678375244140625 +31262 -0.43511962890625 +31263 -0.579315185546875 +31264 -0.2962646484375 +31265 -0.439117431640625 +31266 -0.161102294921875 +31267 -0.29327392578125 +31268 -0.0435791015625 +31269 -0.1558837890625 +31270 0.060394287109375 +31271 -0.025238037109375 +31272 0.13665771484375 +31273 0.083740234375 +31274 0.170135498046875 +31275 0.15521240234375 +31276 0.16552734375 +31277 0.191131591796875 +31278 0.15728759765625 +31279 0.2203369140625 +31280 0.150787353515625 +31281 0.24578857421875 +31282 0.12200927734375 +31283 0.244293212890625 +31284 0.080108642578125 +31285 0.222930908203125 +31286 0.05126953125 +31287 0.204620361328125 +31288 0.062896728515625 +31289 0.213897705078125 +31290 0.09271240234375 +31291 0.230987548828125 +31292 0.092987060546875 +31293 0.2137451171875 +31294 0.07855224609375 +31295 0.176666259765625 +31296 0.06427001953125 +31297 0.1346435546875 +31298 0.0347900390625 +31299 0.075592041015625 +31300 -0.01171875 +31301 -0.000274658203125 +31302 -0.056060791015625 +31303 -0.073760986328125 +31304 -0.055511474609375 +31305 -0.1046142578125 +31306 -0.010467529296875 +31307 -0.091522216796875 +31308 0.02508544921875 +31309 -0.081695556640625 +31310 0.025665283203125 +31311 -0.09698486328125 +31312 0.017333984375 +31313 -0.113250732421875 +31314 0.00189208984375 +31315 -0.12860107421875 +31316 -0.03173828125 +31317 -0.15313720703125 +31318 -0.071502685546875 +31319 -0.176605224609375 +31320 -0.13543701171875 +31321 -0.216064453125 +31322 -0.219970703125 +31323 -0.26947021484375 +31324 -0.300506591796875 +31325 -0.3160400390625 +31326 -0.376312255859375 +31327 -0.356597900390625 +31328 -0.416107177734375 +31329 -0.364532470703125 +31330 -0.371124267578125 +31331 -0.2974853515625 +31332 -0.242279052734375 +31333 -0.15771484375 +31334 -0.069732666015625 +31335 0.01739501953125 +31336 0.125640869140625 +31337 0.208099365234375 +31338 0.31268310546875 +31339 0.385650634765625 +31340 0.45501708984375 +31341 0.51702880859375 +31342 0.554779052734375 +31343 0.6041259765625 +31344 0.61065673828125 +31345 0.646087646484375 +31346 0.610931396484375 +31347 0.63299560546875 +31348 0.531463623046875 +31349 0.54400634765625 +31350 0.3883056640625 +31351 0.394622802734375 +31352 0.23468017578125 +31353 0.23394775390625 +31354 0.095245361328125 +31355 0.08544921875 +31356 -0.00396728515625 +31357 -0.02618408203125 +31358 -0.04852294921875 +31359 -0.086761474609375 +31360 -0.055145263671875 +31361 -0.1102294921875 +31362 -0.0758056640625 +31363 -0.14251708984375 +31364 -0.138702392578125 +31365 -0.2083740234375 +31366 -0.209197998046875 +31367 -0.2762451171875 +31368 -0.289031982421875 +31369 -0.347625732421875 +31370 -0.37884521484375 +31371 -0.423248291015625 +31372 -0.456329345703125 +31373 -0.483428955078125 +31374 -0.51641845703125 +31375 -0.524261474609375 +31376 -0.519287109375 +31377 -0.5107421875 +31378 -0.458251953125 +31379 -0.43780517578125 +31380 -0.384796142578125 +31381 -0.35284423828125 +31382 -0.323699951171875 +31383 -0.2791748046875 +31384 -0.269287109375 +31385 -0.21270751953125 +31386 -0.1951904296875 +31387 -0.130645751953125 +31388 -0.100006103515625 +31389 -0.032501220703125 +31390 -0.01055908203125 +31391 0.056976318359375 +31392 0.1033935546875 +31393 0.16461181640625 +31394 0.24908447265625 +31395 0.2967529296875 +31396 0.373199462890625 +31397 0.405487060546875 +31398 0.45806884765625 +31399 0.4752197265625 +31400 0.511474609375 +31401 0.51336669921875 +31402 0.565399169921875 +31403 0.54937744140625 +31404 0.61138916015625 +31405 0.576416015625 +31406 0.5897216796875 +31407 0.541534423828125 +31408 0.4906005859375 +31409 0.436798095703125 +31410 0.33148193359375 +31411 0.278778076171875 +31412 0.147796630859375 +31413 0.100128173828125 +31414 -0.01873779296875 +31415 -0.0609130859375 +31416 -0.140289306640625 +31417 -0.178741455078125 +31418 -0.191986083984375 +31419 -0.230560302734375 +31420 -0.184295654296875 +31421 -0.225616455078125 +31422 -0.161834716796875 +31423 -0.204071044921875 +31424 -0.166595458984375 +31425 -0.203887939453125 +31426 -0.19390869140625 +31427 -0.22119140625 +31428 -0.22442626953125 +31429 -0.239013671875 +31430 -0.279754638671875 +31431 -0.27740478515625 +31432 -0.3389892578125 +31433 -0.3182373046875 +31434 -0.3543701171875 +31435 -0.319244384765625 +31436 -0.348175048828125 +31437 -0.301177978515625 +31438 -0.32598876953125 +31439 -0.269744873046875 +31440 -0.2581787109375 +31441 -0.198883056640625 +31442 -0.139801025390625 +31443 -0.084625244140625 +31444 0.014617919921875 +31445 0.05963134765625 +31446 0.144378662109375 +31447 0.178985595703125 +31448 0.221038818359375 +31449 0.247802734375 +31450 0.27069091796875 +31451 0.289642333984375 +31452 0.294036865234375 +31453 0.305389404296875 +31454 0.311767578125 +31455 0.31402587890625 +31456 0.339141845703125 +31457 0.329742431640625 +31458 0.360260009765625 +31459 0.33880615234375 +31460 0.360504150390625 +31461 0.328643798828125 +31462 0.308380126953125 +31463 0.27130126953125 +31464 0.18170166015625 +31465 0.14727783203125 +31466 0.0047607421875 +31467 -0.02093505859375 +31468 -0.17559814453125 +31469 -0.190582275390625 +31470 -0.3143310546875 +31471 -0.3206787109375 +31472 -0.36785888671875 +31473 -0.37164306640625 +31474 -0.36248779296875 +31475 -0.367156982421875 +31476 -0.343536376953125 +31477 -0.348236083984375 +31478 -0.3018798828125 +31479 -0.30682373046875 +31480 -0.231414794921875 +31481 -0.23760986328125 +31482 -0.117645263671875 +31483 -0.127838134765625 +31484 0.007049560546875 +31485 -0.0072021484375 +31486 0.087982177734375 +31487 0.074371337890625 +31488 0.13946533203125 +31489 0.12933349609375 +31490 0.17425537109375 +31491 0.168792724609375 +31492 0.188201904296875 +31493 0.1885986328125 +31494 0.171234130859375 +31495 0.178802490234375 +31496 0.118438720703125 +31497 0.134429931640625 +31498 0.05706787109375 +31499 0.08062744140625 +31500 -0.010711669921875 +31501 0.0191650390625 +31502 -0.0914306640625 +31503 -0.05609130859375 +31504 -0.162322998046875 +31505 -0.123809814453125 +31506 -0.194549560546875 +31507 -0.15692138671875 +31508 -0.1492919921875 +31509 -0.118865966796875 +31510 -0.02166748046875 +31511 -0.004791259765625 +31512 0.124053955078125 +31513 0.12548828125 +31514 0.211151123046875 +31515 0.20050048828125 +31516 0.240447998046875 +31517 0.221435546875 +31518 0.242218017578125 +31519 0.216949462890625 +31520 0.2257080078125 +31521 0.196075439453125 +31522 0.194366455078125 +31523 0.16229248046875 +31524 0.115509033203125 +31525 0.085205078125 +31526 0.0128173828125 +31527 -0.0128173828125 +31528 -0.053802490234375 +31529 -0.07568359375 +31530 -0.110626220703125 +31531 -0.127960205078125 +31532 -0.199493408203125 +31533 -0.20892333984375 +31534 -0.29437255859375 +31535 -0.29437255859375 +31536 -0.33221435546875 +31537 -0.325469970703125 +31538 -0.27972412109375 +31539 -0.2713623046875 +31540 -0.185333251953125 +31541 -0.17767333984375 +31542 -0.128204345703125 +31543 -0.1187744140625 +31544 -0.115692138671875 +31545 -0.101806640625 +31546 -0.116455078125 +31547 -0.097747802734375 +31548 -0.105926513671875 +31549 -0.0838623046875 +31550 -0.053955078125 +31551 -0.032135009765625 +31552 0.048797607421875 +31553 0.066009521484375 +31554 0.157318115234375 +31555 0.16839599609375 +31556 0.212005615234375 +31557 0.219207763671875 +31558 0.218475341796875 +31559 0.223785400390625 +31560 0.23724365234375 +31561 0.2388916015625 +31562 0.30535888671875 +31563 0.299346923828125 +31564 0.38128662109375 +31565 0.366455078125 +31566 0.404449462890625 +31567 0.383758544921875 +31568 0.3944091796875 +31569 0.36981201171875 +31570 0.3885498046875 +31571 0.35986328125 +31572 0.362640380859375 +31573 0.331512451171875 +31574 0.27362060546875 +31575 0.24462890625 +31576 0.11712646484375 +31577 0.095306396484375 +31578 -0.054901123046875 +31579 -0.06768798828125 +31580 -0.19085693359375 +31581 -0.195953369140625 +31582 -0.28570556640625 +31583 -0.284759521484375 +31584 -0.339263916015625 +31585 -0.333984375 +31586 -0.3775634765625 +31587 -0.3680419921875 +31588 -0.445709228515625 +31589 -0.429290771484375 +31590 -0.535064697265625 +31591 -0.50982666015625 +31592 -0.629058837890625 +31593 -0.59429931640625 +31594 -0.697601318359375 +31595 -0.654754638671875 +31596 -0.70391845703125 +31597 -0.656951904296875 +31598 -0.6424560546875 +31599 -0.595916748046875 +31600 -0.491241455078125 +31601 -0.451263427734375 +31602 -0.265716552734375 +31603 -0.23760986328125 +31604 -0.023712158203125 +31605 -0.009185791015625 +31606 0.201751708984375 +31607 0.202972412109375 +31608 0.375823974609375 +31609 0.366241455078125 +31610 0.485076904296875 +31611 0.468048095703125 +31612 0.56884765625 +31613 0.545257568359375 +31614 0.634765625 +31615 0.6051025390625 +31616 0.63763427734375 +31617 0.60540771484375 +31618 0.5660400390625 +31619 0.535614013671875 +31620 0.4720458984375 +31621 0.444610595703125 +31622 0.40692138671875 +31623 0.38055419921875 +31624 0.3778076171875 +31625 0.350311279296875 +31626 0.376953125 +31627 0.3468017578125 +31628 0.371978759765625 +31629 0.33984375 +31630 0.313140869140625 +31631 0.282989501953125 +31632 0.184417724609375 +31633 0.16131591796875 +31634 0.011199951171875 +31635 -0.0013427734375 +31636 -0.171051025390625 +31637 -0.17181396484375 +31638 -0.33740234375 +31639 -0.3267822265625 +31640 -0.47198486328125 +31641 -0.451416015625 +31642 -0.560394287109375 +31643 -0.5323486328125 +31644 -0.58056640625 +31645 -0.549072265625 +31646 -0.54754638671875 +31647 -0.5157470703125 +31648 -0.508575439453125 +31649 -0.47674560546875 +31650 -0.459503173828125 +31651 -0.4283447265625 +31652 -0.394378662109375 +31653 -0.3651123046875 +31654 -0.35260009765625 +31655 -0.324005126953125 +31656 -0.31170654296875 +31657 -0.284088134765625 +31658 -0.197418212890625 +31659 -0.175933837890625 +31660 -0.007965087890625 +31661 0.0020751953125 +31662 0.207489013671875 +31663 0.203857421875 +31664 0.409210205078125 +31665 0.392242431640625 +31666 0.57208251953125 +31667 0.54376220703125 +31668 0.66595458984375 +31669 0.6302490234375 +31670 0.65875244140625 +31671 0.621795654296875 +31672 0.56744384765625 +31673 0.53436279296875 +31674 0.431396484375 +31675 0.404937744140625 +31676 0.29443359375 +31677 0.274658203125 +31678 0.182464599609375 +31679 0.167877197265625 +31680 0.06365966796875 +31681 0.054931640625 +31682 -0.075958251953125 +31683 -0.077178955078125 +31684 -0.189422607421875 +31685 -0.1844482421875 +31686 -0.271942138671875 +31687 -0.2623291015625 +31688 -0.342529296875 +31689 -0.328582763671875 +31690 -0.364166259765625 +31691 -0.348602294921875 +31692 -0.327239990234375 +31693 -0.31341552734375 +31694 -0.2769775390625 +31695 -0.265380859375 +31696 -0.253692626953125 +31697 -0.242279052734375 +31698 -0.24365234375 +31699 -0.231353759765625 +31700 -0.1983642578125 +31701 -0.18731689453125 +31702 -0.116241455078125 +31703 -0.1087646484375 +31704 -0.036834716796875 +31705 -0.03277587890625 +31706 0.034881591796875 +31707 0.035858154296875 +31708 0.09124755859375 +31709 0.08990478515625 +31710 0.10888671875 +31711 0.107452392578125 +31712 0.125518798828125 +31713 0.12371826171875 +31714 0.15771484375 +31715 0.1541748046875 +31716 0.17828369140625 +31717 0.173370361328125 +31718 0.17108154296875 +31719 0.166229248046875 +31720 0.129974365234375 +31721 0.127044677734375 +31722 0.082427978515625 +31723 0.08154296875 +31724 0.027679443359375 +31725 0.02911376953125 +31726 -0.065643310546875 +31727 -0.059539794921875 +31728 -0.15936279296875 +31729 -0.148590087890625 +31730 -0.21307373046875 +31731 -0.200164794921875 +31732 -0.234649658203125 +31733 -0.221588134765625 +31734 -0.2001953125 +31735 -0.1904296875 +31736 -0.119171142578125 +31737 -0.115478515625 +31738 -0.024749755859375 +31739 -0.027740478515625 +31740 0.085784912109375 +31741 0.07537841796875 +31742 0.178131103515625 +31743 0.1617431640625 +31744 0.215576171875 +31745 0.196807861328125 +31746 0.211456298828125 +31747 0.192840576171875 +31748 0.17523193359375 +31749 0.1585693359375 +31750 0.128753662109375 +31751 0.115020751953125 +31752 0.1019287109375 +31753 0.09100341796875 +31754 0.0743408203125 +31755 0.066650390625 +31756 0.04327392578125 +31757 0.039154052734375 +31758 0.038177490234375 +31759 0.036834716796875 +31760 0.076263427734375 +31761 0.07623291015625 +31762 0.14105224609375 +31763 0.141265869140625 +31764 0.186431884765625 +31765 0.1871337890625 +31766 0.188812255859375 +31767 0.19091796875 +31768 0.1390380859375 +31769 0.1436767578125 +31770 0.041778564453125 +31771 0.0499267578125 +31772 -0.079437255859375 +31773 -0.067535400390625 +31774 -0.219390869140625 +31775 -0.20367431640625 +31776 -0.367828369140625 +31777 -0.348480224609375 +31778 -0.494873046875 +31779 -0.47296142578125 +31780 -0.556243896484375 +31781 -0.5341796875 +31782 -0.508697509765625 +31783 -0.490142822265625 +31784 -0.3756103515625 +31785 -0.363372802734375 +31786 -0.218902587890625 +31787 -0.213714599609375 +31788 -0.063751220703125 +31789 -0.065399169921875 +31790 0.091552734375 +31791 0.08331298828125 +31792 0.23602294921875 +31793 0.22186279296875 +31794 0.342987060546875 +31795 0.32452392578125 +31796 0.39520263671875 +31797 0.3746337890625 +31798 0.389373779296875 +31799 0.3690185546875 +31800 0.324249267578125 +31801 0.306427001953125 +31802 0.224090576171875 +31803 0.210296630859375 +31804 0.124267578125 +31805 0.114837646484375 +31806 0.037078857421875 +31807 0.0318603515625 +31808 -0.010101318359375 +31809 -0.01220703125 +31810 -0.019439697265625 +31811 -0.019561767578125 +31812 -0.022796630859375 +31813 -0.0211181640625 +31814 -0.001556396484375 +31815 0.001007080078125 +31816 0.056304931640625 +31817 0.058380126953125 +31818 0.106719970703125 +31819 0.1082763671875 +31820 0.096893310546875 +31821 0.09954833984375 +31822 0.042694091796875 +31823 0.04754638671875 +31824 -0.018035888671875 +31825 -0.01116943359375 +31826 -0.07586669921875 +31827 -0.067413330078125 +31828 -0.11944580078125 +31829 -0.11016845703125 +31830 -0.15972900390625 +31831 -0.150054931640625 +31832 -0.202606201171875 +31833 -0.19268798828125 +31834 -0.24859619140625 +31835 -0.23846435546875 +31836 -0.30517578125 +31837 -0.2945556640625 +31838 -0.36212158203125 +31839 -0.35101318359375 +31840 -0.39141845703125 +31841 -0.380645751953125 +31842 -0.35528564453125 +31843 -0.3468017578125 +31844 -0.249969482421875 +31845 -0.245819091796875 +31846 -0.092864990234375 +31847 -0.094482421875 +31848 0.08905029296875 +31849 0.081146240234375 +31850 0.2352294921875 +31851 0.22247314453125 +31852 0.318817138671875 +31853 0.303497314453125 +31854 0.358642578125 +31855 0.342437744140625 +31856 0.347747802734375 +31857 0.33251953125 +31858 0.28564453125 +31859 0.273223876953125 +31860 0.223175048828125 +31861 0.2137451171875 +31862 0.196746826171875 +31863 0.189239501953125 +31864 0.179840087890625 +31865 0.17401123046875 +31866 0.155548095703125 +31867 0.151611328125 +31868 0.151214599609375 +31869 0.1484375 +31870 0.156951904296875 +31871 0.154876708984375 +31872 0.13177490234375 +31873 0.131195068359375 +31874 0.100799560546875 +31875 0.1016845703125 +31876 0.087127685546875 +31877 0.088653564453125 +31878 0.05487060546875 +31879 0.057403564453125 +31880 -0.009002685546875 +31881 -0.004669189453125 +31882 -0.10400390625 +31883 -0.0970458984375 +31884 -0.229400634765625 +31885 -0.21905517578125 +31886 -0.35552978515625 +31887 -0.3419189453125 +31888 -0.441925048828125 +31889 -0.4263916015625 +31890 -0.473846435546875 +31891 -0.458221435546875 +31892 -0.464813232421875 +31893 -0.45037841796875 +31894 -0.419097900390625 +31895 -0.406951904296875 +31896 -0.334320068359375 +31897 -0.32562255859375 +31898 -0.227935791015625 +31899 -0.223236083984375 +31900 -0.12347412109375 +31901 -0.12255859375 +31902 -0.02764892578125 +31903 -0.030059814453125 +31904 0.077667236328125 +31905 0.07183837890625 +31906 0.2132568359375 +31907 0.203216552734375 +31908 0.38885498046875 +31909 0.37347412109375 +31910 0.582794189453125 +31911 0.5616455078125 +31912 0.734039306640625 +31913 0.7086181640625 +31914 0.800140380859375 +31915 0.77325439453125 +31916 0.7783203125 +31917 0.752838134765625 +31918 0.6651611328125 +31919 0.644012451171875 +31920 0.45965576171875 +31921 0.445770263671875 +31922 0.199188232421875 +31923 0.194244384765625 +31924 -0.050689697265625 +31925 -0.047149658203125 +31926 -0.23297119140625 +31927 -0.223236083984375 +31928 -0.33013916015625 +31929 -0.31707763671875 +31930 -0.368408203125 +31931 -0.354034423828125 +31932 -0.378936767578125 +31933 -0.3642578125 +31934 -0.376983642578125 +31935 -0.362548828125 +31936 -0.37969970703125 +31937 -0.365509033203125 +31938 -0.391510009765625 +31939 -0.377349853515625 +31940 -0.385345458984375 +31941 -0.37188720703125 +31942 -0.3419189453125 +31943 -0.330413818359375 +31944 -0.28289794921875 +31945 -0.27386474609375 +31946 -0.251617431640625 +31947 -0.244140625 +31948 -0.266143798828125 +31949 -0.258697509765625 +31950 -0.273345947265625 +31951 -0.266082763671875 +31952 -0.216796875 +31953 -0.211669921875 +31954 -0.128265380859375 +31955 -0.12615966796875 +31956 -0.068145751953125 +31957 -0.06805419921875 +31958 -0.0430908203125 +31959 -0.04376220703125 +31960 -0.024444580078125 +31961 -0.025543212890625 +31962 0.020721435546875 +31963 0.018463134765625 +31964 0.124481201171875 +31965 0.1192626953125 +31966 0.25787353515625 +31967 0.248779296875 +31968 0.379119873046875 +31969 0.3665771484375 +31970 0.47991943359375 +31971 0.464599609375 +31972 0.5281982421875 +31973 0.511749267578125 +31974 0.511138916015625 +31975 0.495635986328125 +31976 0.456207275390625 +31977 0.44281005859375 +31978 0.407470703125 +31979 0.39593505859375 +31980 0.383758544921875 +31981 0.373199462890625 +31982 0.35687255859375 +31983 0.3472900390625 +31984 0.31182861328125 +31985 0.3037109375 +31986 0.250885009765625 +31987 0.24462890625 +31988 0.1654052734375 +31989 0.16168212890625 +31990 0.035247802734375 +31991 0.035400390625 +31992 -0.142059326171875 +31993 -0.1365966796875 +31994 -0.33563232421875 +31995 -0.32440185546875 +31996 -0.5345458984375 +31997 -0.517364501953125 +31998 -0.72186279296875 +31999 -0.699066162109375 +32000 -0.836669921875 +32001 -0.81005859375 +32002 -0.8326416015625 +32003 -0.804901123046875 +32004 -0.7296142578125 +32005 -0.703369140625 +32006 -0.582550048828125 +32007 -0.5599365234375 +32008 -0.440093994140625 +32009 -0.422698974609375 +32010 -0.324310302734375 +32011 -0.313232421875 +32012 -0.20147705078125 +32013 -0.197296142578125 +32014 -0.044647216796875 +32015 -0.047393798828125 +32016 0.103973388671875 +32017 0.094696044921875 +32018 0.202392578125 +32019 0.1873779296875 +32020 0.264495849609375 +32021 0.24481201171875 +32022 0.338897705078125 +32023 0.315887451171875 +32024 0.443817138671875 +32025 0.4189453125 +32026 0.545074462890625 +32027 0.519866943359375 +32028 0.6173095703125 +32029 0.59320068359375 +32030 0.6524658203125 +32031 0.63079833984375 +32032 0.66339111328125 +32033 0.64532470703125 +32034 0.6561279296875 +32035 0.642578125 +32036 0.606781005859375 +32037 0.598358154296875 +32038 0.501190185546875 +32039 0.498199462890625 +32040 0.352783203125 +32041 0.355224609375 +32042 0.176544189453125 +32043 0.184112548828125 +32044 -0.034820556640625 +32045 -0.022674560546875 +32046 -0.258209228515625 +32047 -0.242279052734375 +32048 -0.44244384765625 +32049 -0.4237060546875 +32050 -0.5753173828125 +32051 -0.55487060546875 +32052 -0.65203857421875 +32053 -0.63104248046875 +32054 -0.641632080078125 +32055 -0.621246337890625 +32056 -0.562164306640625 +32057 -0.543487548828125 +32058 -0.458038330078125 +32059 -0.442047119140625 +32060 -0.350555419921875 +32061 -0.338043212890625 +32062 -0.260528564453125 +32063 -0.2520751953125 +32064 -0.192108154296875 +32065 -0.188079833984375 +32066 -0.141937255859375 +32067 -0.1424560546875 +32068 -0.1021728515625 +32069 -0.107086181640625 +32070 -0.062896728515625 +32071 -0.07183837890625 +32072 -0.011932373046875 +32073 -0.0242919921875 +32074 0.062835693359375 +32075 0.047821044921875 +32076 0.148712158203125 +32077 0.131988525390625 +32078 0.241729736328125 +32079 0.2242431640625 +32080 0.34912109375 +32081 0.33184814453125 +32082 0.457305908203125 +32083 0.441192626953125 +32084 0.54388427734375 +32085 0.52978515625 +32086 0.5728759765625 +32087 0.561492919921875 +32088 0.506591796875 +32089 0.49847412109375 +32090 0.351226806640625 +32091 0.34674072265625 +32092 0.146514892578125 +32093 0.145782470703125 +32094 -0.05523681640625 +32095 -0.052276611328125 +32096 -0.21624755859375 +32097 -0.2098388671875 +32098 -0.334930419921875 +32099 -0.325469970703125 +32100 -0.402984619140625 +32101 -0.391082763671875 +32102 -0.4412841796875 +32103 -0.427642822265625 +32104 -0.49578857421875 +32105 -0.481201171875 +32106 -0.5601806640625 +32107 -0.54547119140625 +32108 -0.600738525390625 +32109 -0.586700439453125 +32110 -0.584228515625 +32111 -0.571624755859375 +32112 -0.47930908203125 +32113 -0.468780517578125 +32114 -0.27935791015625 +32115 -0.27142333984375 +32116 -0.0089111328125 +32117 -0.00390625 +32118 0.268798828125 +32119 0.270660400390625 +32120 0.482818603515625 +32121 0.4815673828125 +32122 0.60369873046875 +32123 0.5994873046875 +32124 0.650421142578125 +32125 0.6435546875 +32126 0.66400146484375 +32127 0.654937744140625 +32128 0.6414794921875 +32129 0.630767822265625 +32130 0.572540283203125 +32131 0.560821533203125 +32132 0.498138427734375 +32133 0.486053466796875 +32134 0.439453125 +32135 0.42767333984375 +32136 0.375518798828125 +32137 0.36468505859375 +32138 0.274505615234375 +32139 0.265167236328125 +32140 0.1087646484375 +32141 0.10137939453125 +32142 -0.099395751953125 +32143 -0.1044921875 +32144 -0.3182373046875 +32145 -0.320831298828125 +32146 -0.5489501953125 +32147 -0.548980712890625 +32148 -0.7738037109375 +32149 -0.771331787109375 +32150 -0.86383056640625 +32151 -0.863311767578125 +32152 -0.870391845703125 +32153 -0.870391845703125 +32154 -0.86895751953125 +32155 -0.869476318359375 +32156 -0.861053466796875 +32157 -0.862030029296875 +32158 -0.765869140625 +32159 -0.77838134765625 +32160 -0.5301513671875 +32161 -0.5455322265625 +32162 -0.214691162109375 +32163 -0.232025146484375 +32164 0.137359619140625 +32165 0.119049072265625 +32166 0.474822998046875 +32167 0.45654296875 +32168 0.76239013671875 +32169 0.7451171875 +32170 0.867462158203125 +32171 0.86578369140625 +32172 0.870361328125 +32173 0.870361328125 +32174 0.86480712890625 +32175 0.866424560546875 +32176 0.831817626953125 +32177 0.855133056640625 +32178 0.677581787109375 +32179 0.7178955078125 +32180 0.495880126953125 +32181 0.545379638671875 +32182 0.30767822265625 +32183 0.3634033203125 +32184 0.116180419921875 +32185 0.1749267578125 +32186 -0.110748291015625 +32187 -0.05224609375 +32188 -0.381805419921875 +32189 -0.32672119140625 +32190 -0.6572265625 +32191 -0.60845947265625 +32192 -0.857421875 +32193 -0.841217041015625 +32194 -0.870391845703125 +32195 -0.868896484375 +32196 -0.870391845703125 +32197 -0.870391845703125 +32198 -0.86444091796875 +32199 -0.865875244140625 +32200 -0.85723876953125 +32201 -0.860015869140625 +32202 -0.790008544921875 +32203 -0.825897216796875 +32204 -0.62847900390625 +32205 -0.67254638671875 +32206 -0.3956298828125 +32207 -0.445220947265625 +32208 -0.126708984375 +32209 -0.178955078125 +32210 0.150115966796875 +32211 0.09814453125 +32212 0.424041748046875 +32213 0.375152587890625 +32214 0.670623779296875 +32215 0.627410888671875 +32216 0.854522705078125 +32217 0.819610595703125 +32218 0.866485595703125 +32219 0.8636474609375 +32220 0.86920166015625 +32221 0.8675537109375 +32222 0.8653564453125 +32223 0.86492919921875 +32224 0.857147216796875 +32225 0.857940673828125 +32226 0.766845703125 +32227 0.784393310546875 +32228 0.628509521484375 +32229 0.655181884765625 +32230 0.462127685546875 +32231 0.4962158203125 +32232 0.297210693359375 +32233 0.336639404296875 +32234 0.14862060546875 +32235 0.19110107421875 +32236 -0.00537109375 +32237 0.0377197265625 +32238 -0.15753173828125 +32239 -0.116180419921875 +32240 -0.31304931640625 +32241 -0.275634765625 +32242 -0.48876953125 +32243 -0.45721435546875 +32244 -0.6416015625 +32245 -0.617462158203125 +32246 -0.751373291015625 +32247 -0.735748291015625 +32248 -0.84619140625 +32249 -0.839691162109375 +32250 -0.861297607421875 +32251 -0.861572265625 +32252 -0.863250732421875 +32253 -0.864501953125 +32254 -0.856597900390625 +32255 -0.85870361328125 +32256 -0.749298095703125 +32257 -0.775909423828125 +32258 -0.62200927734375 +32259 -0.655609130859375 +32260 -0.473663330078125 +32261 -0.512359619140625 +32262 -0.249298095703125 +32263 -0.288909912109375 +32264 0.00634765625 +32265 -0.03106689453125 +32266 0.227630615234375 +32267 0.193603515625 +32268 0.42828369140625 +32269 0.39935302734375 +32270 0.642120361328125 +32271 0.621124267578125 +32272 0.85540771484375 +32273 0.8524169921875 +32274 0.870361328125 +32275 0.870361328125 +32276 0.870361328125 +32277 0.870361328125 +32278 0.862823486328125 +32279 0.862762451171875 +32280 0.798126220703125 +32281 0.79669189453125 +32282 0.598968505859375 +32283 0.595794677734375 +32284 0.3670654296875 +32285 0.362152099609375 +32286 0.133056640625 +32287 0.1270751953125 +32288 -0.080902099609375 +32289 -0.086944580078125 +32290 -0.2730712890625 +32291 -0.2784423828125 +32292 -0.479248046875 +32293 -0.484832763671875 +32294 -0.72186279296875 +32295 -0.729583740234375 +32296 -0.86572265625 +32297 -0.86688232421875 +32298 -0.870391845703125 +32299 -0.870391845703125 +32300 -0.86968994140625 +32301 -0.86859130859375 +32302 -0.8648681640625 +32303 -0.86279296875 +32304 -0.8447265625 +32305 -0.817962646484375 +32306 -0.64630126953125 +32307 -0.6116943359375 +32308 -0.35528564453125 +32309 -0.3128662109375 +32310 -0.00970458984375 +32311 0.039398193359375 +32312 0.3685302734375 +32313 0.422821044921875 +32314 0.747711181640625 +32315 0.805145263671875 +32316 0.870361328125 +32317 0.870361328125 +32318 0.870361328125 +32319 0.870361328125 +32320 0.86016845703125 +32321 0.860015869140625 +32322 0.7315673828125 +32323 0.727935791015625 +32324 0.48797607421875 +32325 0.48114013671875 +32326 0.215789794921875 +32327 0.2059326171875 +32328 -0.049163818359375 +32329 -0.06103515625 +32330 -0.28656005859375 +32331 -0.29913330078125 +32332 -0.50360107421875 +32333 -0.516204833984375 +32334 -0.71240234375 +32335 -0.7252197265625 +32336 -0.8583984375 +32337 -0.85980224609375 +32338 -0.870391845703125 +32339 -0.870391845703125 +32340 -0.870391845703125 +32341 -0.870391845703125 +32342 -0.8582763671875 +32343 -0.858062744140625 +32344 -0.6783447265625 +32345 -0.673004150390625 +32346 -0.435394287109375 +32347 -0.42694091796875 +32348 -0.219696044921875 +32349 -0.2100830078125 +32350 -0.044921875 +32351 -0.0362548828125 +32352 0.10296630859375 +32353 0.10943603515625 +32354 0.23150634765625 +32355 0.23516845703125 +32356 0.37200927734375 +32357 0.373687744140625 +32358 0.51715087890625 +32359 0.517791748046875 +32360 0.604034423828125 +32361 0.602783203125 +32362 0.639312744140625 +32363 0.635711669921875 +32364 0.66015625 +32365 0.655181884765625 +32366 0.66485595703125 +32367 0.65948486328125 +32368 0.655975341796875 +32369 0.651275634765625 +32370 0.62188720703125 +32371 0.61846923828125 +32372 0.540008544921875 +32373 0.53753662109375 +32374 0.4063720703125 +32375 0.404144287109375 +32376 0.224700927734375 +32377 0.22186279296875 +32378 0.008209228515625 +32379 0.003997802734375 +32380 -0.21527099609375 +32381 -0.22100830078125 +32382 -0.417724609375 +32383 -0.42449951171875 +32384 -0.573028564453125 +32385 -0.579833984375 +32386 -0.637237548828125 +32387 -0.641876220703125 +32388 -0.617095947265625 +32389 -0.6177978515625 +32390 -0.578216552734375 +32391 -0.575531005859375 +32392 -0.53143310546875 +32393 -0.526336669921875 +32394 -0.43438720703125 +32395 -0.42645263671875 +32396 -0.269927978515625 +32397 -0.2581787109375 +32398 -0.083892822265625 +32399 -0.068695068359375 +32400 0.07537841796875 +32401 0.09222412109375 +32402 0.2149658203125 +32403 0.232147216796875 +32404 0.33453369140625 +32405 0.3509521484375 +32406 0.396453857421875 +32407 0.410064697265625 +32408 0.3651123046875 +32409 0.372955322265625 +32410 0.255645751953125 +32411 0.2554931640625 +32412 0.115692138671875 +32413 0.10711669921875 +32414 -0.036285400390625 +32415 -0.052886962890625 +32416 -0.163360595703125 +32417 -0.186279296875 +32418 -0.20745849609375 +32419 -0.23291015625 +32420 -0.1846923828125 +32421 -0.209442138671875 +32422 -0.151458740234375 +32423 -0.174163818359375 +32424 -0.107391357421875 +32425 -0.126739501953125 +32426 -0.033935546875 +32427 -0.048126220703125 +32428 0.050628662109375 +32429 0.0426025390625 +32430 0.109771728515625 +32431 0.10748291015625 +32432 0.138336181640625 +32433 0.1409912109375 +32434 0.188751220703125 +32435 0.19708251953125 +32436 0.25921630859375 +32437 0.273651123046875 +32438 0.298614501953125 +32439 0.31768798828125 +32440 0.318603515625 +32441 0.341094970703125 +32442 0.34271240234375 +32443 0.368011474609375 +32444 0.34588623046875 +32445 0.37249755859375 +32446 0.27606201171875 +32447 0.30072021484375 +32448 0.132293701171875 +32449 0.1517333984375 +32450 -0.027618408203125 +32451 -0.01470947265625 +32452 -0.193817138671875 +32453 -0.1883544921875 +32454 -0.36981201171875 +32455 -0.372711181640625 +32456 -0.503692626953125 +32457 -0.51397705078125 +32458 -0.556488037109375 +32459 -0.57177734375 +32460 -0.522003173828125 +32461 -0.53948974609375 +32462 -0.4178466796875 +32463 -0.43511962890625 +32464 -0.280609130859375 +32465 -0.2962646484375 +32466 -0.147369384765625 +32467 -0.161102294921875 +32468 -0.031707763671875 +32469 -0.0435791015625 +32470 0.0701904296875 +32471 0.060394287109375 +32472 0.144561767578125 +32473 0.13665771484375 +32474 0.176849365234375 +32475 0.170135498046875 +32476 0.171630859375 +32477 0.16552734375 +32478 0.16229248046875 +32479 0.15728759765625 +32480 0.154144287109375 +32481 0.150787353515625 +32482 0.1240234375 +32483 0.12200927734375 +32484 0.0809326171875 +32485 0.080108642578125 +32486 0.05035400390625 +32487 0.05126953125 +32488 0.05902099609375 +32489 0.062896728515625 +32490 0.08544921875 +32491 0.09271240234375 +32492 0.0836181640625 +32493 0.092987060546875 +32494 0.067962646484375 +32495 0.07855224609375 +32496 0.052947998046875 +32497 0.06427001953125 +32498 0.02374267578125 +32499 0.0347900390625 +32500 -0.021392822265625 +32501 -0.01171875 +32502 -0.06390380859375 +32503 -0.056060791015625 +32504 -0.06243896484375 +32505 -0.055511474609375 +32506 -0.0174560546875 +32507 -0.010467529296875 +32508 0.01873779296875 +32509 0.02508544921875 +32510 0.0213623046875 +32511 0.025665283203125 +32512 0.015289306640625 +32513 0.017333984375 +32514 0.00225830078125 +32515 0.00189208984375 +32516 -0.028289794921875 +32517 -0.03173828125 +32518 -0.06494140625 +32519 -0.071502685546875 +32520 -0.124755859375 +32521 -0.13543701171875 +32522 -0.204345703125 +32523 -0.219970703125 +32524 -0.28033447265625 +32525 -0.300506591796875 +32526 -0.352020263671875 +32527 -0.376312255859375 +32528 -0.38970947265625 +32529 -0.416107177734375 +32530 -0.347076416015625 +32531 -0.371124267578125 +32532 -0.2249755859375 +32533 -0.242279052734375 +32534 -0.061553955078125 +32535 -0.069732666015625 +32536 0.12335205078125 +32537 0.125640869140625 +32538 0.3001708984375 +32539 0.31268310546875 +32540 0.43438720703125 +32541 0.45501708984375 +32542 0.528076171875 +32543 0.554779052734375 +32544 0.580047607421875 +32545 0.61065673828125 +32546 0.579254150390625 +32547 0.610931396484375 +32548 0.502838134765625 +32549 0.531463623046875 +32550 0.366058349609375 +32551 0.3883056640625 +32552 0.219482421875 +32553 0.23468017578125 +32554 0.08660888671875 +32555 0.095245361328125 +32556 -0.007843017578125 +32557 -0.00396728515625 +32558 -0.050140380859375 +32559 -0.04852294921875 +32560 -0.05615234375 +32561 -0.055145263671875 +32562 -0.075347900390625 +32563 -0.0758056640625 +32564 -0.134490966796875 +32565 -0.138702392578125 +32566 -0.200714111328125 +32567 -0.209197998046875 +32568 -0.275726318359375 +32569 -0.289031982421875 +32570 -0.360198974609375 +32571 -0.37884521484375 +32572 -0.432952880859375 +32573 -0.456329345703125 +32574 -0.4892578125 +32575 -0.51641845703125 +32576 -0.491302490234375 +32577 -0.519287109375 +32578 -0.432769775390625 +32579 -0.458251953125 +32580 -0.36260986328125 +32581 -0.384796142578125 +32582 -0.304351806640625 +32583 -0.323699951171875 +32584 -0.252593994140625 +32585 -0.269287109375 +32586 -0.18231201171875 +32587 -0.1951904296875 +32588 -0.0921630859375 +32589 -0.100006103515625 +32590 -0.00762939453125 +32591 -0.01055908203125 +32592 0.10003662109375 +32593 0.1033935546875 +32594 0.237762451171875 +32595 0.24908447265625 +32596 0.354949951171875 +32597 0.373199462890625 +32598 0.43487548828125 +32599 0.45806884765625 +32600 0.48492431640625 +32601 0.511474609375 +32602 0.535552978515625 +32603 0.565399169921875 +32604 0.5787353515625 +32605 0.61138916015625 +32606 0.557769775390625 +32607 0.5897216796875 +32608 0.463348388671875 +32609 0.4906005859375 +32610 0.312103271484375 +32611 0.33148193359375 +32612 0.137664794921875 +32613 0.147796630859375 +32614 -0.020355224609375 +32615 -0.01873779296875 +32616 -0.135498046875 +32617 -0.140289306640625 +32618 -0.184173583984375 +32619 -0.191986083984375 +32620 -0.17633056640625 +32621 -0.184295654296875 +32622 -0.1544189453125 +32623 -0.161834716796875 +32624 -0.1583251953125 +32625 -0.166595458984375 +32626 -0.18365478515625 +32627 -0.19390869140625 +32628 -0.212066650390625 +32629 -0.22442626953125 +32630 -0.26409912109375 +32631 -0.279754638671875 +32632 -0.319976806640625 +32633 -0.3389892578125 +32634 -0.334320068359375 +32635 -0.3543701171875 +32636 -0.32830810546875 +32637 -0.348175048828125 +32638 -0.3072509765625 +32639 -0.32598876953125 +32640 -0.24298095703125 +32641 -0.2581787109375 +32642 -0.13079833984375 +32643 -0.139801025390625 +32644 0.015533447265625 +32645 0.014617919921875 +32646 0.138336181640625 +32647 0.144378662109375 +32648 0.21063232421875 +32649 0.221038818359375 +32650 0.257232666015625 +32651 0.27069091796875 +32652 0.278900146484375 +32653 0.294036865234375 +32654 0.2952880859375 +32655 0.311767578125 +32656 0.320892333984375 +32657 0.339141845703125 +32658 0.34039306640625 +32659 0.360260009765625 +32660 0.339996337890625 +32661 0.360504150390625 +32662 0.290313720703125 +32663 0.308380126953125 +32664 0.17071533203125 +32665 0.18170166015625 +32666 0.004058837890625 +32667 0.0047607421875 +32668 -0.165740966796875 +32669 -0.17559814453125 +32670 -0.2965087890625 +32671 -0.3143310546875 +32672 -0.347381591796875 +32673 -0.36785888671875 +32674 -0.3428955078125 +32675 -0.36248779296875 +32676 -0.325439453125 +32677 -0.343536376953125 +32678 -0.2864990234375 +32679 -0.3018798828125 +32680 -0.220367431640625 +32681 -0.231414794921875 +32682 -0.11346435546875 +32683 -0.117645263671875 +32684 0.00384521484375 +32685 0.007049560546875 +32686 0.080352783203125 +32687 0.087982177734375 +32688 0.12939453125 +32689 0.13946533203125 +32690 0.162872314453125 +32691 0.17425537109375 +32692 0.17681884765625 +32693 0.188201904296875 +32694 0.1617431640625 +32695 0.171234130859375 +32696 0.113006591796875 +32697 0.118438720703125 +32698 0.05609130859375 +32699 0.05706787109375 +32700 -0.006988525390625 +32701 -0.010711669921875 +32702 -0.082366943359375 +32703 -0.0914306640625 +32704 -0.148712158203125 +32705 -0.162322998046875 +32706 -0.179046630859375 +32707 -0.194549560546875 +32708 -0.137054443359375 +32709 -0.1492919921875 +32710 -0.01806640625 +32711 -0.02166748046875 +32712 0.117767333984375 +32713 0.124053955078125 +32714 0.19866943359375 +32715 0.211151123046875 +32716 0.2254638671875 +32717 0.240447998046875 +32718 0.226470947265625 +32719 0.242218017578125 +32720 0.210418701171875 +32721 0.2257080078125 +32722 0.1805419921875 +32723 0.194366455078125 +32724 0.10626220703125 +32725 0.115509033203125 +32726 0.009765625 +32727 0.0128173828125 +32728 -0.052825927734375 +32729 -0.053802490234375 +32730 -0.1060791015625 +32731 -0.110626220703125 +32732 -0.189208984375 +32733 -0.199493408203125 +32734 -0.277801513671875 +32735 -0.29437255859375 +32736 -0.3128662109375 +32737 -0.33221435546875 +32738 -0.2633056640625 +32739 -0.27972412109375 +32740 -0.174468994140625 +32741 -0.185333251953125 +32742 -0.120452880859375 +32743 -0.128204345703125 +32744 -0.108154296875 +32745 -0.115692138671875 +32746 -0.1082763671875 +32747 -0.116455078125 +32748 -0.097900390625 +32749 -0.105926513671875 +32750 -0.048797607421875 +32751 -0.053955078125 +32752 0.0477294921875 +32753 0.048797607421875 +32754 0.1495361328125 +32755 0.157318115234375 +32756 0.2008056640625 +32757 0.212005615234375 +32758 0.206817626953125 +32759 0.218475341796875 +32760 0.2242431640625 +32761 0.23724365234375 +32762 0.287750244140625 +32763 0.30535888671875 +32764 0.35845947265625 +32765 0.38128662109375 +32766 0.37969970703125 +32767 0.404449462890625 +32768 0.36920166015625 +32769 0.3944091796875 +32770 0.361358642578125 +32771 0.3885498046875 +32772 0.334503173828125 +32773 0.362640380859375 +32774 0.25006103515625 +32775 0.27362060546875 +32776 0.10443115234375 +32777 0.11712646484375 +32778 -0.055084228515625 +32779 -0.054901123046875 +32780 -0.181549072265625 +32781 -0.19085693359375 +32782 -0.270233154296875 +32783 -0.28570556640625 +32784 -0.320831298828125 +32785 -0.339263916015625 +32786 -0.35675048828125 +32787 -0.3775634765625 +32788 -0.418701171875 +32789 -0.445709228515625 +32790 -0.4989013671875 +32791 -0.535064697265625 +32792 -0.582427978515625 +32793 -0.629058837890625 +32794 -0.642181396484375 +32795 -0.697601318359375 +32796 -0.64508056640625 +32797 -0.70391845703125 +32798 -0.5863037109375 +32799 -0.6424560546875 +32800 -0.4461669921875 +32801 -0.491241455078125 +32802 -0.238800048828125 +32803 -0.265716552734375 +32804 -0.016693115234375 +32805 -0.023712158203125 +32806 0.190093994140625 +32807 0.201751708984375 +32808 0.34991455078125 +32809 0.375823974609375 +32810 0.45050048828125 +32811 0.485076904296875 +32812 0.52734375 +32813 0.56884765625 +32814 0.58734130859375 +32815 0.634765625 +32816 0.589599609375 +32817 0.63763427734375 +32818 0.523834228515625 +32819 0.5660400390625 +32820 0.437164306640625 +32821 0.4720458984375 +32822 0.376068115234375 +32823 0.40692138671875 +32824 0.347137451171875 +32825 0.3778076171875 +32826 0.343505859375 +32827 0.376953125 +32828 0.3360595703125 +32829 0.371978759765625 +32830 0.280029296875 +32831 0.313140869140625 +32832 0.16107177734375 +32833 0.184417724609375 +32834 0.002288818359375 +32835 0.011199951171875 +32836 -0.1641845703125 +32837 -0.171051025390625 +32838 -0.315704345703125 +32839 -0.33740234375 +32840 -0.437896728515625 +32841 -0.47198486328125 +32842 -0.517730712890625 +32843 -0.560394287109375 +32844 -0.5352783203125 +32845 -0.58056640625 +32846 -0.504180908203125 +32847 -0.54754638671875 +32848 -0.46722412109375 +32849 -0.508575439453125 +32850 -0.4207763671875 +32851 -0.459503173828125 +32852 -0.359588623046875 +32853 -0.394378662109375 +32854 -0.319427490234375 +32855 -0.35260009765625 +32856 -0.28009033203125 +32857 -0.31170654296875 +32858 -0.174560546875 +32859 -0.197418212890625 +32860 -0.001312255859375 +32861 -0.007965087890625 +32862 0.195068359375 +32863 0.207489013671875 +32864 0.3785400390625 +32865 0.409210205078125 +32866 0.5263671875 +32867 0.57208251953125 +32868 0.611297607421875 +32869 0.66595458984375 +32870 0.604339599609375 +32871 0.65875244140625 +32872 0.5208740234375 +32873 0.56744384765625 +32874 0.39654541015625 +32875 0.431396484375 +32876 0.271087646484375 +32877 0.29443359375 +32878 0.167999267578125 +32879 0.182464599609375 +32880 0.058624267578125 +32881 0.06365966796875 +32882 -0.069549560546875 +32883 -0.075958251953125 +32884 -0.1739501953125 +32885 -0.189422607421875 +32886 -0.25018310546875 +32887 -0.271942138671875 +32888 -0.315338134765625 +32889 -0.342529296875 +32890 -0.335906982421875 +32891 -0.364166259765625 +32892 -0.30316162109375 +32893 -0.327239990234375 +32894 -0.2579345703125 +32895 -0.2769775390625 +32896 -0.236663818359375 +32897 -0.253692626953125 +32898 -0.226959228515625 +32899 -0.24365234375 +32900 -0.18505859375 +32901 -0.1983642578125 +32902 -0.10955810546875 +32903 -0.116241455078125 +32904 -0.036285400390625 +32905 -0.036834716796875 +32906 0.0301513671875 +32907 0.034881591796875 +32908 0.082733154296875 +32909 0.09124755859375 +32910 0.100250244140625 +32911 0.10888671875 +32912 0.11669921875 +32913 0.125518798828125 +32914 0.147003173828125 +32915 0.15771484375 +32916 0.16650390625 +32917 0.17828369140625 +32918 0.160552978515625 +32919 0.17108154296875 +32920 0.123626708984375 +32921 0.129974365234375 +32922 0.080535888671875 +32923 0.082427978515625 +32924 0.0306396484375 +32925 0.027679443359375 +32926 -0.054412841796875 +32927 -0.065643310546875 +32928 -0.140045166015625 +32929 -0.15936279296875 +32930 -0.189727783203125 +32931 -0.21307373046875 +32932 -0.210479736328125 +32933 -0.234649658203125 +32934 -0.180633544921875 +32935 -0.2001953125 +32936 -0.108673095703125 +32937 -0.119171142578125 +32938 -0.024505615234375 +32939 -0.024749755859375 +32940 0.074371337890625 +32941 0.085784912109375 +32942 0.157012939453125 +32943 0.178131103515625 +32944 0.190277099609375 +32945 0.215576171875 +32946 0.18621826171875 +32947 0.211456298828125 +32948 0.153411865234375 +32949 0.17523193359375 +32950 0.111602783203125 +32951 0.128753662109375 +32952 0.087799072265625 +32953 0.1019287109375 +32954 0.06353759765625 +32955 0.0743408203125 +32956 0.03631591796875 +32957 0.04327392578125 +32958 0.032684326171875 +32959 0.038177490234375 +32960 0.06817626953125 +32961 0.076263427734375 +32962 0.127838134765625 +32963 0.14105224609375 +32964 0.169921875 +32965 0.186431884765625 +32966 0.17303466796875 +32967 0.188812255859375 +32968 0.12884521484375 +32969 0.1390380859375 +32970 0.04156494140625 +32971 0.041778564453125 +32972 -0.06756591796875 +32973 -0.079437255859375 +32974 -0.19390869140625 +32975 -0.219390869140625 +32976 -0.328155517578125 +32977 -0.367828369140625 +32978 -0.44329833984375 +32979 -0.494873046875 +32980 -0.499298095703125 +32981 -0.556243896484375 +32982 -0.45703125 +32983 -0.508697509765625 +32984 -0.337554931640625 +32985 -0.3756103515625 +32986 -0.196807861328125 +32987 -0.218902587890625 +32988 -0.0574951171875 +32989 -0.063751220703125 +32990 0.08197021484375 +32991 0.091552734375 +32992 0.211700439453125 +32993 0.23602294921875 +32994 0.3076171875 +32995 0.342987060546875 +32996 0.354217529296875 +32997 0.39520263671875 +32998 0.348541259765625 +32999 0.389373779296875 +33000 0.289459228515625 +33001 0.324249267578125 +33002 0.198883056640625 +33003 0.224090576171875 +33004 0.10882568359375 +33005 0.124267578125 +33006 0.03033447265625 +33007 0.037078857421875 +33008 -0.0118408203125 +33009 -0.010101318359375 +33010 -0.019683837890625 +33011 -0.019439697265625 +33012 -0.022003173828125 +33013 -0.022796630859375 +33014 -0.00201416015625 +33015 -0.001556396484375 +33016 0.05108642578125 +33017 0.056304931640625 +33018 0.097412109375 +33019 0.106719970703125 +33020 0.089202880859375 +33021 0.096893310546875 +33022 0.040802001953125 +33023 0.042694091796875 +33024 -0.01336669921875 +33025 -0.018035888671875 +33026 -0.06494140625 +33027 -0.07586669921875 +33028 -0.104248046875 +33029 -0.11944580078125 +33030 -0.140716552734375 +33031 -0.15972900390625 +33032 -0.179351806640625 +33033 -0.202606201171875 +33034 -0.220489501953125 +33035 -0.24859619140625 +33036 -0.270538330078125 +33037 -0.30517578125 +33038 -0.320587158203125 +33039 -0.36212158203125 +33040 -0.34619140625 +33041 -0.39141845703125 +33042 -0.31439208984375 +33043 -0.35528564453125 +33044 -0.22198486328125 +33045 -0.249969482421875 +33046 -0.084197998046875 +33047 -0.092864990234375 +33048 0.075408935546875 +33049 0.08905029296875 +33050 0.2039794921875 +33051 0.2352294921875 +33052 0.27801513671875 +33053 0.318817138671875 +33054 0.313873291015625 +33055 0.358642578125 +33056 0.305419921875 +33057 0.347747802734375 +33058 0.252166748046875 +33059 0.28564453125 +33060 0.198394775390625 +33061 0.223175048828125 +33062 0.175811767578125 +33063 0.196746826171875 +33064 0.16131591796875 +33065 0.179840087890625 +33066 0.14013671875 +33067 0.155548095703125 +33068 0.1361083984375 +33069 0.151214599609375 +33070 0.140625 +33071 0.156951904296875 +33072 0.11798095703125 +33073 0.13177490234375 +33074 0.090118408203125 +33075 0.100799560546875 +33076 0.07720947265625 +33077 0.087127685546875 +33078 0.048065185546875 +33079 0.05487060546875 +33080 -0.008636474609375 +33081 -0.009002685546875 +33082 -0.092376708984375 +33083 -0.10400390625 +33084 -0.2025146484375 +33085 -0.229400634765625 +33086 -0.3131103515625 +33087 -0.35552978515625 +33088 -0.38885498046875 +33089 -0.441925048828125 +33090 -0.41693115234375 +33091 -0.473846435546875 +33092 -0.4090576171875 +33093 -0.464813232421875 +33094 -0.36895751953125 +33095 -0.419097900390625 +33096 -0.29461669921875 +33097 -0.334320068359375 +33098 -0.20123291015625 +33099 -0.227935791015625 +33100 -0.109405517578125 +33101 -0.12347412109375 +33102 -0.0250244140625 +33103 -0.02764892578125 +33104 0.06768798828125 +33105 0.077667236328125 +33106 0.186767578125 +33107 0.2132568359375 +33108 0.340667724609375 +33109 0.38885498046875 +33110 0.51043701171875 +33111 0.582794189453125 +33112 0.642822265625 +33113 0.734039306640625 +33114 0.7008056640625 +33115 0.800140380859375 +33116 0.68194580078125 +33117 0.7783203125 +33118 0.583282470703125 +33119 0.6651611328125 +33120 0.4039306640625 +33121 0.45965576171875 +33122 0.176483154296875 +33123 0.199188232421875 +33124 -0.0418701171875 +33125 -0.050689697265625 +33126 -0.201385498046875 +33127 -0.23297119140625 +33128 -0.286773681640625 +33129 -0.33013916015625 +33130 -0.32086181640625 +33131 -0.368408203125 +33132 -0.33074951171875 +33133 -0.378936767578125 +33134 -0.3297119140625 +33135 -0.376983642578125 +33136 -0.332672119140625 +33137 -0.37969970703125 +33138 -0.34344482421875 +33139 -0.391510009765625 +33140 -0.338409423828125 +33141 -0.385345458984375 +33142 -0.300750732421875 +33143 -0.3419189453125 +33144 -0.249359130859375 +33145 -0.28289794921875 +33146 -0.22198486328125 +33147 -0.251617431640625 +33148 -0.234405517578125 +33149 -0.266143798828125 +33150 -0.24029541015625 +33151 -0.273345947265625 +33152 -0.19049072265625 +33153 -0.216796875 +33154 -0.112701416015625 +33155 -0.128265380859375 +33156 -0.0596923828125 +33157 -0.068145751953125 +33158 -0.037261962890625 +33159 -0.0430908203125 +33160 -0.02044677734375 +33161 -0.024444580078125 +33162 0.01947021484375 +33163 0.020721435546875 +33164 0.11041259765625 +33165 0.124481201171875 +33166 0.22705078125 +33167 0.25787353515625 +33168 0.33294677734375 +33169 0.379119873046875 +33170 0.4208984375 +33171 0.47991943359375 +33172 0.462921142578125 +33173 0.5281982421875 +33174 0.447845458984375 +33175 0.511138916015625 +33176 0.399627685546875 +33177 0.456207275390625 +33178 0.356719970703125 +33179 0.407470703125 +33180 0.335601806640625 +33181 0.383758544921875 +33182 0.311676025390625 +33183 0.35687255859375 +33184 0.271881103515625 +33185 0.31182861328125 +33186 0.218231201171875 +33187 0.250885009765625 +33188 0.143218994140625 +33189 0.1654052734375 +33190 0.029327392578125 +33191 0.035247802734375 +33192 -0.125579833984375 +33193 -0.142059326171875 +33194 -0.294586181640625 +33195 -0.33563232421875 +33196 -0.4681396484375 +33197 -0.5345458984375 +33198 -0.631439208984375 +33199 -0.72186279296875 +33200 -0.73138427734375 +33201 -0.836669921875 +33202 -0.72760009765625 +33203 -0.8326416015625 +33204 -0.637420654296875 +33205 -0.7296142578125 +33206 -0.508758544921875 +33207 -0.582550048828125 +33208 -0.384063720703125 +33209 -0.440093994140625 +33210 -0.282623291015625 +33211 -0.324310302734375 +33212 -0.175079345703125 +33213 -0.20147705078125 +33214 -0.03790283203125 +33215 -0.044647216796875 +33216 0.092071533203125 +33217 0.103973388671875 +33218 0.17816162109375 +33219 0.202392578125 +33220 0.23248291015625 +33221 0.264495849609375 +33222 0.29742431640625 +33223 0.338897705078125 +33224 0.38885498046875 +33225 0.443817138671875 +33226 0.47698974609375 +33227 0.545074462890625 +33228 0.539703369140625 +33229 0.6173095703125 +33230 0.57000732421875 +33231 0.6524658203125 +33232 0.579132080078125 +33233 0.66339111328125 +33234 0.572357177734375 +33235 0.6561279296875 +33236 0.528900146484375 +33237 0.606781005859375 +33238 0.436431884765625 +33239 0.501190185546875 +33240 0.306671142578125 +33241 0.352783203125 +33242 0.152679443359375 +33243 0.176544189453125 +33244 -0.031829833984375 +33245 -0.034820556640625 +33246 -0.22674560546875 +33247 -0.258209228515625 +33248 -0.387451171875 +33249 -0.44244384765625 +33250 -0.503265380859375 +33251 -0.5753173828125 +33252 -0.57000732421875 +33253 -0.65203857421875 +33254 -0.560699462890625 +33255 -0.641632080078125 +33256 -0.491119384765625 +33257 -0.562164306640625 +33258 -0.399993896484375 +33259 -0.458038330078125 +33260 -0.305877685546875 +33261 -0.350555419921875 +33262 -0.22698974609375 +33263 -0.260528564453125 +33264 -0.166961669921875 +33265 -0.192108154296875 +33266 -0.1229248046875 +33267 -0.141937255859375 +33268 -0.0880126953125 +33269 -0.1021728515625 +33270 -0.0535888671875 +33271 -0.062896728515625 +33272 -0.009033203125 +33273 -0.011932373046875 +33274 0.05621337890625 +33275 0.062835693359375 +33276 0.131072998046875 +33277 0.148712158203125 +33278 0.212066650390625 +33279 0.241729736328125 +33280 0.305206298828125 +33281 0.34912109375 +33282 0.397918701171875 +33283 0.457305908203125 +33284 0.47076416015625 +33285 0.54388427734375 +33286 0.493896484375 +33287 0.5728759765625 +33288 0.436004638671875 +33289 0.506591796875 +33290 0.302642822265625 +33291 0.351226806640625 +33292 0.127471923828125 +33293 0.146514892578125 +33294 -0.0452880859375 +33295 -0.05523681640625 +33296 -0.183685302734375 +33297 -0.21624755859375 +33298 -0.286163330078125 +33299 -0.334930419921875 +33300 -0.345611572265625 +33301 -0.402984619140625 +33302 -0.37945556640625 +33303 -0.4412841796875 +33304 -0.42626953125 +33305 -0.49578857421875 +33306 -0.480712890625 +33307 -0.5601806640625 +33308 -0.51446533203125 +33309 -0.600738525390625 +33310 -0.49969482421875 +33311 -0.584228515625 +33312 -0.410125732421875 +33313 -0.47930908203125 +33314 -0.2403564453125 +33315 -0.27935791015625 +33316 -0.0111083984375 +33317 -0.0089111328125 +33318 0.224365234375 +33319 0.268798828125 +33320 0.4063720703125 +33321 0.482818603515625 +33322 0.510040283203125 +33323 0.60369873046875 +33324 0.551177978515625 +33325 0.650421142578125 +33326 0.56414794921875 +33327 0.66400146484375 +33328 0.54638671875 +33329 0.6414794921875 +33330 0.489166259765625 +33331 0.572540283203125 +33332 0.4268798828125 +33333 0.498138427734375 +33334 0.3773193359375 +33335 0.439453125 +33336 0.322906494140625 +33337 0.375518798828125 +33338 0.2369384765625 +33339 0.274505615234375 +33340 0.096282958984375 +33341 0.1087646484375 +33342 -0.080230712890625 +33343 -0.099395751953125 +33344 -0.265838623046875 +33345 -0.3182373046875 +33346 -0.461456298828125 +33347 -0.5489501953125 +33348 -0.65203857421875 +33349 -0.7738037109375 +33350 -0.793060302734375 +33351 -0.86383056640625 +33352 -0.854736328125 +33353 -0.870391845703125 +33354 -0.85479736328125 +33355 -0.86895751953125 +33356 -0.806060791015625 +33357 -0.861053466796875 +33358 -0.6885986328125 +33359 -0.765869140625 +33360 -0.495330810546875 +33361 -0.5301513671875 +33362 -0.23223876953125 +33363 -0.214691162109375 +33364 0.064453125 +33365 0.137359619140625 +33366 0.351593017578125 +33367 0.474822998046875 +33368 0.599273681640625 +33369 0.76239013671875 +33370 0.784759521484375 +33371 0.867462158203125 +33372 0.8603515625 +33373 0.870361328125 +33374 0.865997314453125 +33375 0.86480712890625 +33376 0.86431884765625 +33377 0.831817626953125 +33378 0.8575439453125 +33379 0.677581787109375 +33380 0.778106689453125 +33381 0.495880126953125 +33382 0.647186279296875 +33383 0.30767822265625 +33384 0.491546630859375 +33385 0.116180419921875 +33386 0.284515380859375 +33387 -0.110748291015625 +33388 0.020294189453125 +33389 -0.381805419921875 +33390 -0.26513671875 +33391 -0.6572265625 +33392 -0.52142333984375 +33393 -0.857421875 +33394 -0.712432861328125 +33395 -0.870391845703125 +33396 -0.83209228515625 +33397 -0.870391845703125 +33398 -0.85980224609375 +33399 -0.86444091796875 +33400 -0.865447998046875 +33401 -0.85723876953125 +33402 -0.867340087890625 +33403 -0.790008544921875 +33404 -0.860504150390625 +33405 -0.62847900390625 +33406 -0.76409912109375 +33407 -0.3956298828125 +33408 -0.563323974609375 +33409 -0.126708984375 +33410 -0.33026123046875 +33411 0.150115966796875 +33412 -0.074737548828125 +33413 0.424041748046875 +33414 0.180572509765625 +33415 0.670623779296875 +33416 0.403106689453125 +33417 0.854522705078125 +33418 0.577972412109375 +33419 0.866485595703125 +33420 0.692138671875 +33421 0.86920166015625 +33422 0.760772705078125 +33423 0.8653564453125 +33424 0.7950439453125 +33425 0.857147216796875 +33426 0.79241943359375 +33427 0.766845703125 +33428 0.757110595703125 +33429 0.628509521484375 +33430 0.683380126953125 +33431 0.462127685546875 +33432 0.5928955078125 +33433 0.297210693359375 +33434 0.49603271484375 +33435 0.14862060546875 +33436 0.37359619140625 +33437 -0.00537109375 +33438 0.231842041015625 +33439 -0.15753173828125 +33440 0.067779541015625 +33441 -0.31304931640625 +33442 -0.13031005859375 +33443 -0.48876953125 +33444 -0.322998046875 +33445 -0.6416015625 +33446 -0.48944091796875 +33447 -0.751373291015625 +33448 -0.64892578125 +33449 -0.84619140625 +33450 -0.788970947265625 +33451 -0.861297607421875 +33452 -0.85748291015625 +33453 -0.863250732421875 +33454 -0.859527587890625 +33455 -0.856597900390625 +33456 -0.854583740234375 +33457 -0.7498779296875 +33458 -0.794952392578125 +33459 -0.624542236328125 +33460 -0.700836181640625 +33461 -0.47808837890625 +33462 -0.52386474609375 +33463 -0.253387451171875 +33464 -0.3023681640625 +33465 0.003692626953125 +33466 -0.09381103515625 +33467 0.2257080078125 +33468 0.112274169921875 +33469 0.427154541015625 +33470 0.343017578125 +33471 0.643218994140625 +33472 0.590240478515625 +33473 0.855926513671875 +33474 0.805145263671875 +33475 0.870361328125 +33476 0.86444091796875 +33477 0.870361328125 +33478 0.870361328125 +33479 0.862762451171875 +33480 0.868682861328125 +33481 0.79669189453125 +33482 0.85870361328125 +33483 0.595794677734375 +33484 0.75067138671875 +33485 0.362152099609375 +33486 0.580963134765625 +33487 0.1270751953125 +33488 0.40228271484375 +33489 -0.086944580078125 +33490 0.216522216796875 +33491 -0.2784423828125 +33492 -0.005584716796875 +33493 -0.484832763671875 +33494 -0.280426025390625 +33495 -0.729583740234375 +33496 -0.56591796875 +33497 -0.86688232421875 +33498 -0.80938720703125 +33499 -0.870391845703125 +33500 -0.870391845703125 +33501 -0.86859130859375 +33502 -0.870391845703125 +33503 -0.86279296875 +33504 -0.863494873046875 +33505 -0.817962646484375 +33506 -0.780487060546875 +33507 -0.6116943359375 +33508 -0.531280517578125 +33509 -0.3128662109375 +33510 -0.22247314453125 +33511 0.039398193359375 +33512 0.126068115234375 +33513 0.422821044921875 +33514 0.48541259765625 +33515 0.805145263671875 +33516 0.79931640625 +33517 0.870361328125 +33518 0.870361328125 +33519 0.870361328125 +33520 0.870361328125 +33521 0.860015869140625 +33522 0.861114501953125 +33523 0.727935791015625 +33524 0.75372314453125 +33525 0.48114013671875 +33526 0.5479736328125 +33527 0.2059326171875 +33528 0.327972412109375 +33529 -0.06103515625 +33530 0.111358642578125 +33531 -0.29913330078125 +33532 -0.10687255859375 +33533 -0.516204833984375 +33534 -0.335113525390625 +33535 -0.7252197265625 +33536 -0.550689697265625 +33537 -0.85980224609375 +33538 -0.72503662109375 +33539 -0.870391845703125 +33540 -0.836578369140625 +33541 -0.870391845703125 +33542 -0.8514404296875 +33543 -0.858062744140625 +33544 -0.773651123046875 +33545 -0.673004150390625 +33546 -0.654541015625 +33547 -0.42694091796875 +33548 -0.539764404296875 +33549 -0.2100830078125 +33550 -0.43780517578125 +33551 -0.0362548828125 +33552 -0.33526611328125 +33553 0.10943603515625 +33554 -0.225372314453125 +33555 0.23516845703125 +33556 -0.08282470703125 +33557 0.373687744140625 +33558 0.084197998046875 +33559 0.517791748046875 +33560 0.220123291015625 +33561 0.602783203125 +33562 0.3265380859375 +33563 0.635711669921875 +33564 0.429931640625 +33565 0.655181884765625 +33566 0.52392578125 +33567 0.65948486328125 +33568 0.60565185546875 +33569 0.651275634765625 +33570 0.66058349609375 +33571 0.61846923828125 +33572 0.66546630859375 +33573 0.53753662109375 +33574 0.613311767578125 +33575 0.404144287109375 +33576 0.504425048828125 +33577 0.22186279296875 +33578 0.347991943359375 +33579 0.003997802734375 +33580 0.166412353515625 +33581 -0.22100830078125 +33582 -0.0166015625 +33583 -0.42449951171875 +33584 -0.17791748046875 +33585 -0.579833984375 +33586 -0.278656005859375 +33587 -0.641876220703125 +33588 -0.321441650390625 +33589 -0.6177978515625 +33590 -0.357421875 +33591 -0.575531005859375 +33592 -0.391632080078125 +33593 -0.526336669921875 +33594 -0.384613037109375 +33595 -0.42645263671875 +33596 -0.3179931640625 +33597 -0.2581787109375 +33598 -0.22625732421875 +33599 -0.068695068359375 +33600 -0.146484375 +33601 0.09222412109375 +33602 -0.070159912109375 +33603 0.232147216796875 +33604 0.00421142578125 +33605 0.3509521484375 +33606 0.046173095703125 +33607 0.410064697265625 +33608 0.026123046875 +33609 0.372955322265625 +33610 -0.0440673828125 +33611 0.2554931640625 +33612 -0.12628173828125 +33613 0.10711669921875 +33614 -0.207366943359375 +33615 -0.052886962890625 +33616 -0.25933837890625 +33617 -0.186279296875 +33618 -0.23687744140625 +33619 -0.23291015625 +33620 -0.1568603515625 +33621 -0.209442138671875 +33622 -0.069732666015625 +33623 -0.174163818359375 +33624 0.021636962890625 +33625 -0.126739501953125 +33626 0.129913330078125 +33627 -0.048126220703125 +33628 0.23748779296875 +33629 0.0426025390625 +33630 0.3121337890625 +33631 0.10748291015625 +33632 0.3485107421875 +33633 0.1409912109375 +33634 0.390045166015625 +33635 0.19708251953125 +33636 0.4356689453125 +33637 0.273651123046875 +33638 0.44378662109375 +33639 0.31768798828125 +33640 0.425811767578125 +33641 0.341094970703125 +33642 0.403564453125 +33643 0.368011474609375 +33644 0.358673095703125 +33645 0.37249755859375 +33646 0.250396728515625 +33647 0.30072021484375 +33648 0.08074951171875 +33649 0.1517333984375 +33650 -0.09930419921875 +33651 -0.01470947265625 +33652 -0.279083251953125 +33653 -0.1883544921875 +33654 -0.45947265625 +33655 -0.372711181640625 +33656 -0.59552001953125 +33657 -0.51397705078125 +33658 -0.653656005859375 +33659 -0.57177734375 +33660 -0.62823486328125 +33661 -0.53948974609375 +33662 -0.5340576171875 +33663 -0.43511962890625 +33664 -0.40234375 +33665 -0.2962646484375 +33666 -0.265289306640625 +33667 -0.161102294921875 +33668 -0.135894775390625 +33669 -0.0435791015625 +33670 -0.012939453125 +33671 0.060394287109375 +33672 0.08984375 +33673 0.13665771484375 +33674 0.15802001953125 +33675 0.170135498046875 +33676 0.193115234375 +33677 0.16552734375 +33678 0.220916748046875 +33679 0.15728759765625 +33680 0.244049072265625 +33681 0.150787353515625 +33682 0.24169921875 +33683 0.12200927734375 +33684 0.2203369140625 +33685 0.080108642578125 +33686 0.20068359375 +33687 0.05126953125 +33688 0.204986572265625 +33689 0.062896728515625 +33690 0.215728759765625 +33691 0.09271240234375 +33692 0.1953125 +33693 0.092987060546875 +33694 0.15704345703125 +33695 0.07855224609375 +33696 0.11456298828125 +33697 0.06427001953125 +33698 0.057281494140625 +33699 0.0347900390625 +33700 -0.014404296875 +33701 -0.01171875 +33702 -0.083099365234375 +33703 -0.056060791015625 +33704 -0.112518310546875 +33705 -0.055511474609375 +33706 -0.101409912109375 +33707 -0.010467529296875 +33708 -0.092132568359375 +33709 0.02508544921875 +33710 -0.104400634765625 +33711 0.025665283203125 +33712 -0.116607666015625 +33713 0.017333984375 +33714 -0.127288818359375 +33715 0.00189208984375 +33716 -0.14569091796875 +33717 -0.03173828125 +33718 -0.16278076171875 +33719 -0.071502685546875 +33720 -0.194091796875 +33721 -0.13543701171875 +33722 -0.238006591796875 +33723 -0.219970703125 +33724 -0.276123046875 +33725 -0.300506591796875 +33726 -0.309356689453125 +33727 -0.376312255859375 +33728 -0.31396484375 +33729 -0.416107177734375 +33730 -0.252044677734375 +33731 -0.371124267578125 +33732 -0.12567138671875 +33733 -0.242279052734375 +33734 0.03155517578125 +33735 -0.069732666015625 +33736 0.201873779296875 +33737 0.125640869140625 +33738 0.359619140625 +33739 0.31268310546875 +33740 0.4752197265625 +33741 0.45501708984375 +33742 0.550537109375 +33743 0.554779052734375 +33744 0.5849609375 +33745 0.61065673828125 +33746 0.569793701171875 +33747 0.610931396484375 +33748 0.48651123046875 +33749 0.531463623046875 +33750 0.349212646484375 +33751 0.3883056640625 +33752 0.2021484375 +33753 0.23468017578125 +33754 0.0665283203125 +33755 0.095245361328125 +33756 -0.035369873046875 +33757 -0.00396728515625 +33758 -0.090728759765625 +33759 -0.04852294921875 +33760 -0.112060546875 +33761 -0.055145263671875 +33762 -0.140594482421875 +33763 -0.0758056640625 +33764 -0.198577880859375 +33765 -0.138702392578125 +33766 -0.25775146484375 +33767 -0.209197998046875 +33768 -0.319580078125 +33769 -0.289031982421875 +33770 -0.3848876953125 +33771 -0.37884521484375 +33772 -0.436126708984375 +33773 -0.456329345703125 +33774 -0.469970703125 +33775 -0.51641845703125 +33776 -0.45513916015625 +33777 -0.519287109375 +33778 -0.38720703125 +33779 -0.458251953125 +33780 -0.308837890625 +33781 -0.384796142578125 +33782 -0.2410888671875 +33783 -0.323699951171875 +33784 -0.18035888671875 +33785 -0.269287109375 +33786 -0.106231689453125 +33787 -0.1951904296875 +33788 -0.018280029296875 +33789 -0.100006103515625 +33790 0.061279296875 +33791 -0.01055908203125 +33792 0.156463623046875 +33793 0.1033935546875 +33794 0.27313232421875 +33795 0.24908447265625 +33796 0.368682861328125 +33797 0.373199462890625 +33798 0.429229736328125 +33799 0.45806884765625 +33800 0.461456298828125 +33801 0.511474609375 +33802 0.4915771484375 +33803 0.565399169921875 +33804 0.5135498046875 +33805 0.61138916015625 +33806 0.48046875 +33807 0.5897216796875 +33808 0.385345458984375 +33809 0.4906005859375 +33810 0.2430419921875 +33811 0.33148193359375 +33812 0.08270263671875 +33813 0.147796630859375 +33814 -0.061614990234375 +33815 -0.01873779296875 +33816 -0.1671142578125 +33817 -0.140289306640625 +33818 -0.2135009765625 +33819 -0.191986083984375 +33820 -0.208984375 +33821 -0.184295654296875 +33822 -0.18927001953125 +33823 -0.161834716796875 +33824 -0.188140869140625 +33825 -0.166595458984375 +33826 -0.20220947265625 +33827 -0.19390869140625 +33828 -0.21649169921875 +33829 -0.22442626953125 +33830 -0.248870849609375 +33831 -0.279754638671875 +33832 -0.2833251953125 +33833 -0.3389892578125 +33834 -0.28240966796875 +33835 -0.3543701171875 +33836 -0.264678955078125 +33837 -0.348175048828125 +33838 -0.235260009765625 +33839 -0.32598876953125 +33840 -0.17108154296875 +33841 -0.2581787109375 +33842 -0.06866455078125 +33843 -0.139801025390625 +33844 0.060028076171875 +33845 0.014617919921875 +33846 0.166168212890625 +33847 0.144378662109375 +33848 0.227020263671875 +33849 0.221038818359375 +33850 0.2635498046875 +33851 0.27069091796875 +33852 0.276580810546875 +33853 0.294036865234375 +33854 0.28302001953125 +33855 0.311767578125 +33856 0.295501708984375 +33857 0.339141845703125 +33858 0.30157470703125 +33859 0.360260009765625 +33860 0.29022216796875 +33861 0.360504150390625 +33862 0.237762451171875 +33863 0.308380126953125 +33864 0.127716064453125 +33865 0.18170166015625 +33866 -0.020294189453125 +33867 0.0047607421875 +33868 -0.169342041015625 +33869 -0.17559814453125 +33870 -0.284027099609375 +33871 -0.3143310546875 +33872 -0.330169677734375 +33873 -0.36785888671875 +33874 -0.3280029296875 +33875 -0.36248779296875 +33876 -0.312652587890625 +33877 -0.343536376953125 +33878 -0.27716064453125 +33879 -0.3018798828125 +33880 -0.217010498046875 +33881 -0.231414794921875 +33882 -0.121337890625 +33883 -0.117645263671875 +33884 -0.015716552734375 +33885 0.007049560546875 +33886 0.056884765625 +33887 0.087982177734375 +33888 0.10699462890625 +33889 0.13946533203125 +33890 0.143951416015625 +33891 0.17425537109375 +33892 0.163970947265625 +33893 0.188201904296875 +33894 0.15875244140625 +33895 0.171234130859375 +33896 0.12408447265625 +33897 0.118438720703125 +33898 0.080841064453125 +33899 0.05706787109375 +33900 0.03045654296875 +33901 -0.010711669921875 +33902 -0.032135009765625 +33903 -0.0914306640625 +33904 -0.08917236328125 +33905 -0.162322998046875 +33906 -0.1181640625 +33907 -0.194549560546875 +33908 -0.088714599609375 +33909 -0.1492919921875 +33910 0.003326416015625 +33911 -0.02166748046875 +33912 0.108489990234375 +33913 0.124053955078125 +33914 0.167724609375 +33915 0.211151123046875 +33916 0.182159423828125 +33917 0.240447998046875 +33918 0.175689697265625 +33919 0.242218017578125 +33920 0.15594482421875 +33921 0.2257080078125 +33922 0.125946044921875 +33923 0.194366455078125 +33924 0.060577392578125 +33925 0.115509033203125 +33926 -0.02154541015625 +33927 0.0128173828125 +33928 -0.073883056640625 +33929 -0.053802490234375 +33930 -0.1168212890625 +33931 -0.110626220703125 +33932 -0.1829833984375 +33933 -0.199493408203125 +33934 -0.25238037109375 +33935 -0.29437255859375 +33936 -0.27630615234375 +33937 -0.33221435546875 +33938 -0.22930908203125 +33939 -0.27972412109375 +33940 -0.149322509765625 +33941 -0.185333251953125 +33942 -0.098114013671875 +33943 -0.128204345703125 +33944 -0.081756591796875 +33945 -0.115692138671875 +33946 -0.0762939453125 +33947 -0.116455078125 +33948 -0.06298828125 +33949 -0.105926513671875 +33950 -0.018707275390625 +33951 -0.053955078125 +33952 0.0635986328125 +33953 0.048797607421875 +33954 0.14892578125 +33955 0.157318115234375 +33956 0.19097900390625 +33957 0.212005615234375 +33958 0.194183349609375 +33959 0.218475341796875 +33960 0.20562744140625 +33961 0.23724365234375 +33962 0.2542724609375 +33963 0.30535888671875 +33964 0.308135986328125 +33965 0.38128662109375 +33966 0.320526123046875 +33967 0.404449462890625 +33968 0.30694580078125 +33969 0.3944091796875 +33970 0.296722412109375 +33971 0.3885498046875 +33972 0.271392822265625 +33973 0.362640380859375 +33974 0.197784423828125 +33975 0.27362060546875 +33976 0.072723388671875 +33977 0.11712646484375 +33978 -0.063262939453125 +33979 -0.054901123046875 +33980 -0.1700439453125 +33981 -0.19085693359375 +33982 -0.243682861328125 +33983 -0.28570556640625 +33984 -0.284088134765625 +33985 -0.339263916015625 +33986 -0.3115234375 +33987 -0.3775634765625 +33988 -0.36114501953125 +33989 -0.445709228515625 +33990 -0.426513671875 +33991 -0.535064697265625 +33992 -0.494964599609375 +33993 -0.629058837890625 +33994 -0.543426513671875 +33995 -0.697601318359375 +33996 -0.543609619140625 +33997 -0.70391845703125 +33998 -0.491455078125 +33999 -0.6424560546875 +34000 -0.37017822265625 +34001 -0.491241455078125 +34002 -0.191925048828125 +34003 -0.265716552734375 +34004 -0.001739501953125 +34005 -0.023712158203125 +34006 0.17462158203125 +34007 0.201751708984375 +34008 0.310089111328125 +34009 0.375823974609375 +34010 0.39422607421875 +34011 0.485076904296875 +34012 0.4576416015625 +34013 0.56884765625 +34014 0.506378173828125 +34015 0.634765625 +34016 0.5054931640625 +34017 0.63763427734375 +34018 0.446319580078125 +34019 0.5660400390625 +34020 0.369476318359375 +34021 0.4720458984375 +34022 0.314971923828125 +34023 0.40692138671875 +34024 0.28857421875 +34025 0.3778076171875 +34026 0.284454345703125 +34027 0.376953125 +34028 0.277679443359375 +34029 0.371978759765625 +34030 0.22979736328125 +34031 0.313140869140625 +34032 0.12847900390625 +34033 0.184417724609375 +34034 -0.006500244140625 +34035 0.011199951171875 +34036 -0.14764404296875 +34037 -0.171051025390625 +34038 -0.275634765625 +34039 -0.33740234375 +34040 -0.378204345703125 +34041 -0.47198486328125 +34042 -0.4443359375 +34043 -0.560394287109375 +34044 -0.45709228515625 +34045 -0.58056640625 +34046 -0.42828369140625 +34047 -0.54754638671875 +34048 -0.3946533203125 +34049 -0.508575439453125 +34050 -0.353363037109375 +34051 -0.459503173828125 +34052 -0.299774169921875 +34053 -0.394378662109375 +34054 -0.263458251953125 +34055 -0.35260009765625 +34056 -0.227935791015625 +34057 -0.31170654296875 +34058 -0.13818359375 +34059 -0.197418212890625 +34060 0.006866455078125 +34061 -0.007965087890625 +34062 0.17041015625 +34063 0.207489013671875 +34064 0.32275390625 +34065 0.409210205078125 +34066 0.44512939453125 +34067 0.57208251953125 +34068 0.515106201171875 +34069 0.66595458984375 +34070 0.5087890625 +34071 0.65875244140625 +34072 0.43890380859375 +34073 0.56744384765625 +34074 0.334869384765625 +34075 0.431396484375 +34076 0.229522705078125 +34077 0.29443359375 +34078 0.142303466796875 +34079 0.182464599609375 +34080 0.049774169921875 +34081 0.06365966796875 +34082 -0.0582275390625 +34083 -0.075958251953125 +34084 -0.14654541015625 +34085 -0.189422607421875 +34086 -0.211395263671875 +34087 -0.271942138671875 +34088 -0.26678466796875 +34089 -0.342529296875 +34090 -0.2850341796875 +34091 -0.364166259765625 +34092 -0.258880615234375 +34093 -0.327239990234375 +34094 -0.221923828125 +34095 -0.2769775390625 +34096 -0.20416259765625 +34097 -0.253692626953125 +34098 -0.1954345703125 +34099 -0.24365234375 +34100 -0.159759521484375 +34101 -0.1983642578125 +34102 -0.096099853515625 +34103 -0.116241455078125 +34104 -0.03399658203125 +34105 -0.036834716796875 +34106 0.02264404296875 +34107 0.034881591796875 +34108 0.067962646484375 +34109 0.09124755859375 +34110 0.084381103515625 +34111 0.10888671875 +34112 0.099761962890625 +34113 0.125518798828125 +34114 0.12628173828125 +34115 0.15771484375 +34116 0.143585205078125 +34117 0.17828369140625 +34118 0.139556884765625 +34119 0.17108154296875 +34120 0.109619140625 +34121 0.129974365234375 +34122 0.07415771484375 +34123 0.082427978515625 +34124 0.03265380859375 +34125 0.027679443359375 +34126 -0.03814697265625 +34127 -0.065643310546875 +34128 -0.1097412109375 +34129 -0.15936279296875 +34130 -0.152008056640625 +34131 -0.21307373046875 +34132 -0.170654296875 +34133 -0.234649658203125 +34134 -0.147735595703125 +34135 -0.2001953125 +34136 -0.09014892578125 +34137 -0.119171142578125 +34138 -0.0224609375 +34139 -0.024749755859375 +34140 0.057525634765625 +34141 0.085784912109375 +34142 0.1243896484375 +34143 0.178131103515625 +34144 0.150909423828125 +34145 0.215576171875 +34146 0.14703369140625 +34147 0.211456298828125 +34148 0.119873046875 +34149 0.17523193359375 +34150 0.085662841796875 +34151 0.128753662109375 +34152 0.066619873046875 +34153 0.1019287109375 +34154 0.047515869140625 +34155 0.0743408203125 +34156 0.026214599609375 +34157 0.04327392578125 +34158 0.024505615234375 +34159 0.038177490234375 +34160 0.0550537109375 +34161 0.076263427734375 +34162 0.10546875 +34163 0.14105224609375 +34164 0.141357421875 +34165 0.186431884765625 +34166 0.145050048828125 +34167 0.188812255859375 +34168 0.109619140625 +34169 0.1390380859375 +34170 0.038482666015625 +34171 0.041778564453125 +34172 -0.0509033203125 +34173 -0.079437255859375 +34174 -0.154693603515625 +34175 -0.219390869140625 +34176 -0.2652587890625 +34177 -0.367828369140625 +34178 -0.3603515625 +34179 -0.494873046875 +34180 -0.406982421875 +34181 -0.556243896484375 +34182 -0.3729248046875 +34183 -0.508697509765625 +34184 -0.27545166015625 +34185 -0.3756103515625 +34186 -0.16058349609375 +34187 -0.218902587890625 +34188 -0.04693603515625 +34189 -0.063751220703125 +34190 0.066802978515625 +34191 0.091552734375 +34192 0.172576904296875 +34193 0.23602294921875 +34194 0.250640869140625 +34195 0.342987060546875 +34196 0.28826904296875 +34197 0.39520263671875 +34198 0.2830810546875 +34199 0.389373779296875 +34200 0.234161376953125 +34201 0.324249267578125 +34202 0.159576416015625 +34203 0.224090576171875 +34204 0.085601806640625 +34205 0.124267578125 +34206 0.0213623046875 +34207 0.037078857421875 +34208 -0.01275634765625 +34209 -0.010101318359375 +34210 -0.018463134765625 +34211 -0.019439697265625 +34212 -0.01953125 +34213 -0.022796630859375 +34214 -0.002166748046875 +34215 -0.001556396484375 +34216 0.04241943359375 +34217 0.056304931640625 +34218 0.081390380859375 +34219 0.106719970703125 +34220 0.07537841796875 +34221 0.096893310546875 +34222 0.036163330078125 +34223 0.042694091796875 +34224 -0.008209228515625 +34225 -0.018035888671875 +34226 -0.05072021484375 +34227 -0.07586669921875 +34228 -0.08294677734375 +34229 -0.11944580078125 +34230 -0.113037109375 +34231 -0.15972900390625 +34232 -0.145355224609375 +34233 -0.202606201171875 +34234 -0.18023681640625 +34235 -0.24859619140625 +34236 -0.22320556640625 +34237 -0.30517578125 +34238 -0.266632080078125 +34239 -0.36212158203125 +34240 -0.28961181640625 +34241 -0.39141845703125 +34242 -0.263946533203125 +34243 -0.35528564453125 +34244 -0.186767578125 +34245 -0.249969482421875 +34246 -0.071014404296875 +34247 -0.092864990234375 +34248 0.063323974609375 +34249 0.08905029296875 +34250 0.1712646484375 +34251 0.2352294921875 +34252 0.232879638671875 +34253 0.318817138671875 +34254 0.262176513671875 +34255 0.358642578125 +34256 0.253997802734375 +34257 0.347747802734375 +34258 0.207977294921875 +34259 0.28564453125 +34260 0.161956787109375 +34261 0.223175048828125 +34262 0.1429443359375 +34263 0.196746826171875 +34264 0.131195068359375 +34265 0.179840087890625 +34266 0.114105224609375 +34267 0.155548095703125 +34268 0.1119384765625 +34269 0.151214599609375 +34270 0.117279052734375 +34271 0.156951904296875 +34272 0.099517822265625 +34273 0.13177490234375 +34274 0.07733154296875 +34275 0.100799560546875 +34276 0.06787109375 +34277 0.087127685546875 +34278 0.044403076171875 +34279 0.05487060546875 +34280 -0.002777099609375 +34281 -0.009002685546875 +34282 -0.07330322265625 +34283 -0.10400390625 +34284 -0.166656494140625 +34285 -0.229400634765625 +34286 -0.260772705078125 +34287 -0.35552978515625 +34288 -0.32550048828125 +34289 -0.441925048828125 +34290 -0.349884033203125 +34291 -0.473846435546875 +34292 -0.343902587890625 +34293 -0.464813232421875 +34294 -0.3106689453125 +34295 -0.419097900390625 +34296 -0.248382568359375 +34297 -0.334320068359375 +34298 -0.170013427734375 +34299 -0.227935791015625 +34300 -0.093017578125 +34301 -0.12347412109375 +34302 -0.0223388671875 +34303 -0.02764892578125 +34304 0.055572509765625 +34305 0.077667236328125 +34306 0.15594482421875 +34307 0.2132568359375 +34308 0.28521728515625 +34309 0.38885498046875 +34310 0.42730712890625 +34311 0.582794189453125 +34312 0.53826904296875 +34313 0.734039306640625 +34314 0.587554931640625 +34315 0.800140380859375 +34316 0.572967529296875 +34317 0.7783203125 +34318 0.49200439453125 +34319 0.6651611328125 +34320 0.344024658203125 +34321 0.45965576171875 +34322 0.15576171875 +34323 0.199188232421875 +34324 -0.02587890625 +34325 -0.050689697265625 +34326 -0.1600341796875 +34327 -0.23297119140625 +34328 -0.233978271484375 +34329 -0.33013916015625 +34330 -0.266021728515625 +34331 -0.368408203125 +34332 -0.278045654296875 +34333 -0.378936767578125 +34334 -0.2806396484375 +34335 -0.376983642578125 +34336 -0.285797119140625 +34337 -0.37969970703125 +34338 -0.2965087890625 +34339 -0.391510009765625 +34340 -0.29339599609375 +34341 -0.385345458984375 +34342 -0.262664794921875 +34343 -0.3419189453125 +34344 -0.21978759765625 +34345 -0.28289794921875 +34346 -0.1956787109375 +34347 -0.251617431640625 +34348 -0.20330810546875 +34349 -0.266143798828125 +34350 -0.205047607421875 +34351 -0.273345947265625 +34352 -0.160888671875 +34353 -0.216796875 +34354 -0.093658447265625 +34355 -0.128265380859375 +34356 -0.046630859375 +34357 -0.068145751953125 +34358 -0.0247802734375 +34359 -0.0430908203125 +34360 -0.007904052734375 +34361 -0.024444580078125 +34362 0.027252197265625 +34363 0.020721435546875 +34364 0.10333251953125 +34365 0.124481201171875 +34366 0.199615478515625 +34367 0.25787353515625 +34368 0.28631591796875 +34369 0.379119873046875 +34370 0.357574462890625 +34371 0.47991943359375 +34372 0.390594482421875 +34373 0.5281982421875 +34374 0.3763427734375 +34375 0.511138916015625 +34376 0.334503173828125 +34377 0.456207275390625 +34378 0.296630859375 +34379 0.407470703125 +34380 0.27630615234375 +34381 0.383758544921875 +34382 0.253631591796875 +34383 0.35687255859375 +34384 0.2181396484375 +34385 0.31182861328125 +34386 0.171630859375 +34387 0.250885009765625 +34388 0.108123779296875 +34389 0.1654052734375 +34390 0.013397216796875 +34391 0.035247802734375 +34392 -0.11419677734375 +34393 -0.142059326171875 +34394 -0.252593994140625 +34395 -0.33563232421875 +34396 -0.394012451171875 +34397 -0.5345458984375 +34398 -0.52642822265625 +34399 -0.72186279296875 +34400 -0.606536865234375 +34401 -0.836669921875 +34402 -0.601470947265625 +34403 -0.8326416015625 +34404 -0.5255126953125 +34405 -0.7296142578125 +34406 -0.41796875 +34407 -0.582550048828125 +34408 -0.3135986328125 +34409 -0.440093994140625 +34410 -0.228302001953125 +34411 -0.324310302734375 +34412 -0.138214111328125 +34413 -0.20147705078125 +34414 -0.024261474609375 +34415 -0.044647216796875 +34416 0.0833740234375 +34417 0.103973388671875 +34418 0.15472412109375 +34419 0.202392578125 +34420 0.199615478515625 +34421 0.264495849609375 +34422 0.25262451171875 +34423 0.338897705078125 +34424 0.32672119140625 +34425 0.443817138671875 +34426 0.39764404296875 +34427 0.545074462890625 +34428 0.447418212890625 +34429 0.6173095703125 +34430 0.47039794921875 +34431 0.6524658203125 +34432 0.475860595703125 +34433 0.66339111328125 +34434 0.46826171875 +34435 0.6561279296875 +34436 0.430694580078125 +34437 0.606781005859375 +34438 0.353240966796875 +34439 0.501190185546875 +34440 0.245574951171875 +34441 0.352783203125 +34442 0.118438720703125 +34443 0.176544189453125 +34444 -0.03326416015625 +34445 -0.034820556640625 +34446 -0.1929931640625 +34447 -0.258209228515625 +34448 -0.324310302734375 +34449 -0.44244384765625 +34450 -0.41851806640625 +34451 -0.5753173828125 +34452 -0.4722900390625 +34453 -0.65203857421875 +34454 -0.463592529296875 +34455 -0.641632080078125 +34456 -0.4053955078125 +34457 -0.562164306640625 +34458 -0.32940673828125 +34459 -0.458038330078125 +34460 -0.250885009765625 +34461 -0.350555419921875 +34462 -0.184783935546875 +34463 -0.260528564453125 +34464 -0.1341552734375 +34465 -0.192108154296875 +34466 -0.096710205078125 +34467 -0.141937255859375 +34468 -0.06695556640625 +34469 -0.1021728515625 +34470 -0.037872314453125 +34471 -0.062896728515625 +34472 -0.0008544921875 +34473 -0.011932373046875 +34474 0.05267333984375 +34475 0.062835693359375 +34476 0.113677978515625 +34477 0.148712158203125 +34478 0.179351806640625 +34479 0.241729736328125 +34480 0.254852294921875 +34481 0.34912109375 +34482 0.330596923828125 +34483 0.457305908203125 +34484 0.3907470703125 +34485 0.54388427734375 +34486 0.409759521484375 +34487 0.5728759765625 +34488 0.360870361328125 +34489 0.506591796875 +34490 0.24859619140625 +34491 0.351226806640625 +34492 0.101318359375 +34493 0.146514892578125 +34494 -0.04364013671875 +34495 -0.05523681640625 +34496 -0.1593017578125 +34497 -0.21624755859375 +34498 -0.244476318359375 +34499 -0.334930419921875 +34500 -0.29327392578125 +34501 -0.402984619140625 +34502 -0.32049560546875 +34503 -0.4412841796875 +34504 -0.35888671875 +34505 -0.49578857421875 +34506 -0.40399169921875 +34507 -0.5601806640625 +34508 -0.431854248046875 +34509 -0.600738525390625 +34510 -0.41888427734375 +34511 -0.584228515625 +34512 -0.34283447265625 +34513 -0.47930908203125 +34514 -0.199066162109375 +34515 -0.27935791015625 +34516 -0.005126953125 +34517 -0.0089111328125 +34518 0.19384765625 +34519 0.268798828125 +34520 0.347320556640625 +34521 0.482818603515625 +34522 0.43426513671875 +34523 0.60369873046875 +34524 0.4681396484375 +34525 0.650421142578125 +34526 0.478118896484375 +34527 0.66400146484375 +34528 0.462066650390625 +34529 0.6414794921875 +34530 0.41265869140625 +34531 0.572540283203125 +34532 0.359100341796875 +34533 0.498138427734375 +34534 0.3165283203125 +34535 0.439453125 +34536 0.270050048828125 +34537 0.375518798828125 +34538 0.197052001953125 +34539 0.274505615234375 +34540 0.077911376953125 +34541 0.1087646484375 +34542 -0.0714111328125 +34543 -0.099395751953125 +34544 -0.228240966796875 +34545 -0.3182373046875 +34546 -0.3934326171875 +34547 -0.5489501953125 +34548 -0.55426025390625 +34549 -0.7738037109375 +34550 -0.673004150390625 +34551 -0.86383056640625 +34552 -0.7259521484375 +34553 -0.870391845703125 +34554 -0.7257080078125 +34555 -0.86895751953125 +34556 -0.681640625 +34557 -0.861053466796875 +34558 -0.581451416015625 +34559 -0.765869140625 +34560 -0.417205810546875 +34561 -0.5301513671875 +34562 -0.19451904296875 +34563 -0.214691162109375 +34564 0.05609130859375 +34565 0.137359619140625 +34566 0.2987060546875 +34567 0.474822998046875 +34568 0.508270263671875 +34569 0.76239013671875 +34570 0.665740966796875 +34571 0.867462158203125 +34572 0.770904541015625 +34573 0.870361328125 +34574 0.81561279296875 +34575 0.86480712890625 +34576 0.8033447265625 +34577 0.831817626953125 +34578 0.750701904296875 +34579 0.677581787109375 +34580 0.66180419921875 +34581 0.495880126953125 +34582 0.549591064453125 +34583 0.30767822265625 +34584 0.415985107421875 +34585 0.116180419921875 +34586 0.2398681640625 +34587 -0.110748291015625 +34588 0.01708984375 +34589 -0.381805419921875 +34590 -0.222686767578125 +34591 -0.6572265625 +34592 -0.43817138671875 +34593 -0.857421875 +34594 -0.599700927734375 +34595 -0.870391845703125 +34596 -0.701995849609375 +34597 -0.870391845703125 +34598 -0.763031005859375 +34599 -0.86444091796875 +34600 -0.806854248046875 +34601 -0.85723876953125 +34602 -0.82086181640625 +34603 -0.790008544921875 +34604 -0.7681884765625 +34605 -0.62847900390625 +34606 -0.646759033203125 +34607 -0.3956298828125 +34608 -0.4791259765625 +34609 -0.126708984375 +34610 -0.28424072265625 +34611 0.150115966796875 +34612 -0.0704345703125 +34613 0.424041748046875 +34614 0.1435546875 +34615 0.670623779296875 +34616 0.3309326171875 +34617 0.854522705078125 +34618 0.479217529296875 +34619 0.866485595703125 +34620 0.577545166015625 +34621 0.86920166015625 +34622 0.637908935546875 +34623 0.8653564453125 +34624 0.66912841796875 +34625 0.857147216796875 +34626 0.668975830078125 +34627 0.766845703125 +34628 0.64080810546875 +34629 0.628509521484375 +34630 0.580047607421875 +34631 0.462127685546875 +34632 0.5042724609375 +34633 0.297210693359375 +34634 0.42205810546875 +34635 0.14862060546875 +34636 0.318145751953125 +34637 -0.00537109375 +34638 0.1978759765625 +34639 -0.15753173828125 +34640 0.05914306640625 +34641 -0.31304931640625 +34642 -0.107177734375 +34643 -0.48876953125 +34644 -0.268829345703125 +34645 -0.6416015625 +34646 -0.408660888671875 +34647 -0.751373291015625 +34648 -0.542022705078125 +34649 -0.84619140625 +34650 -0.65863037109375 +34651 -0.861297607421875 +34652 -0.7357177734375 +34653 -0.863250732421875 +34654 -0.751678466796875 +34655 -0.856597900390625 +34656 -0.714691162109375 +34657 -0.7498779296875 +34658 -0.66412353515625 +34659 -0.624542236328125 +34660 -0.58514404296875 +34661 -0.47808837890625 +34662 -0.43817138671875 +34663 -0.253387451171875 +34664 -0.254486083984375 +34665 0.003692626953125 +34666 -0.08087158203125 +34667 0.2257080078125 +34668 0.09088134765625 +34669 0.427154541015625 +34670 0.282470703125 +34671 0.643218994140625 +34672 0.486968994140625 +34673 0.855926513671875 +34674 0.6646728515625 +34675 0.870361328125 +34676 0.781585693359375 +34677 0.870361328125 +34678 0.84234619140625 +34679 0.862762451171875 +34680 0.84478759765625 +34681 0.79669189453125 +34682 0.78240966796875 +34683 0.595794677734375 +34684 0.675079345703125 +34685 0.362152099609375 +34686 0.54193115234375 +34687 0.1270751953125 +34688 0.397491455078125 +34689 -0.086944580078125 +34690 0.243408203125 +34691 -0.2784423828125 +34692 0.0562744140625 +34693 -0.484832763671875 +34694 -0.1766357421875 +34695 -0.729583740234375 +34696 -0.420562744140625 +34697 -0.86688232421875 +34698 -0.63214111328125 +34699 -0.870391845703125 +34700 -0.80767822265625 +34701 -0.86859130859375 +34702 -0.86444091796875 +34703 -0.86279296875 +34704 -0.870391845703125 +34705 -0.817962646484375 +34706 -0.8663330078125 +34707 -0.6116943359375 +34708 -0.829803466796875 +34709 -0.3128662109375 +34710 -0.62481689453125 +34711 0.039398193359375 +34712 -0.362091064453125 +34713 0.422821044921875 +34714 -0.06475830078125 +34715 0.805145263671875 +34716 0.220550537109375 +34717 0.870361328125 +34718 0.454925537109375 +34719 0.870361328125 +34720 0.630401611328125 +34721 0.860015869140625 +34722 0.741973876953125 +34723 0.727935791015625 +34724 0.786163330078125 +34725 0.48114013671875 +34726 0.7799072265625 +34727 0.2059326171875 +34728 0.739166259765625 +34729 -0.06103515625 +34730 0.67144775390625 +34731 -0.29913330078125 +34732 0.567596435546875 +34733 -0.516204833984375 +34734 0.41790771484375 +34735 -0.7252197265625 +34736 0.24005126953125 +34737 -0.85980224609375 +34738 0.05804443359375 +34739 -0.870391845703125 +34740 -0.107330322265625 +34741 -0.870391845703125 +34742 -0.222381591796875 +34743 -0.858062744140625 +34744 -0.2838134765625 +34745 -0.673004150390625 +34746 -0.3270263671875 +34747 -0.42694091796875 +34748 -0.382080078125 +34749 -0.2100830078125 +34750 -0.447540283203125 +34751 -0.0362548828125 +34752 -0.5037841796875 +34753 0.10943603515625 +34754 -0.537567138671875 +34755 0.23516845703125 +34756 -0.52117919921875 +34757 0.373687744140625 +34758 -0.45648193359375 +34759 0.517791748046875 +34760 -0.38690185546875 +34761 0.602783203125 +34762 -0.309600830078125 +34763 0.635711669921875 +34764 -0.20257568359375 +34765 0.655181884765625 +34766 -0.073211669921875 +34767 0.65948486328125 +34768 0.072418212890625 +34769 0.651275634765625 +34770 0.2171630859375 +34771 0.61846923828125 +34772 0.335479736328125 +34773 0.53753662109375 +34774 0.414794921875 +34775 0.404144287109375 +34776 0.448333740234375 +34777 0.22186279296875 +34778 0.43695068359375 +34779 0.003997802734375 +34780 0.393096923828125 +34781 -0.22100830078125 +34782 0.331085205078125 +34783 -0.42449951171875 +34784 0.265838623046875 +34785 -0.579833984375 +34786 0.22686767578125 +34787 -0.641876220703125 +34788 0.210205078125 +34789 -0.6177978515625 +34790 0.1724853515625 +34791 -0.575531005859375 +34792 0.110626220703125 +34793 -0.526336669921875 +34794 0.060394287109375 +34795 -0.42645263671875 +34796 0.04095458984375 +34797 -0.2581787109375 +34798 0.0279541015625 +34799 -0.068695068359375 +34800 -0.004425048828125 +34801 0.09222412109375 +34802 -0.043304443359375 +34803 0.232147216796875 +34804 -0.0816650390625 +34805 0.3509521484375 +34806 -0.139678955078125 +34807 0.410064697265625 +34808 -0.237457275390625 +34809 0.372955322265625 +34810 -0.360992431640625 +34811 0.2554931640625 +34812 -0.475128173828125 +34813 0.10711669921875 +34814 -0.566925048828125 +34815 -0.052886962890625 +34816 -0.612579345703125 +34817 -0.186279296875 +34818 -0.574951171875 +34819 -0.23291015625 +34820 -0.46905517578125 +34821 -0.209442138671875 +34822 -0.3388671875 +34823 -0.174163818359375 +34824 -0.19085693359375 +34825 -0.126739501953125 +34826 -0.0196533203125 +34827 -0.048126220703125 +34828 0.155517578125 +34829 0.0426025390625 +34830 0.3035888671875 +34831 0.10748291015625 +34832 0.4154052734375 +34833 0.1409912109375 +34834 0.521514892578125 +34835 0.19708251953125 +34836 0.617340087890625 +34837 0.273651123046875 +34838 0.66656494140625 +34839 0.31768798828125 +34840 0.676544189453125 +34841 0.341094970703125 +34842 0.66400146484375 +34843 0.368011474609375 +34844 0.614471435546875 +34845 0.37249755859375 +34846 0.496490478515625 +34847 0.30072021484375 +34848 0.313873291015625 +34849 0.1517333984375 +34850 0.110595703125 +34851 -0.01470947265625 +34852 -0.1011962890625 +34853 -0.1883544921875 +34854 -0.318267822265625 +34855 -0.372711181640625 +34856 -0.500396728515625 +34857 -0.51397705078125 +34858 -0.6165771484375 +34859 -0.57177734375 +34860 -0.6585693359375 +34861 -0.53948974609375 +34862 -0.635101318359375 +34863 -0.43511962890625 +34864 -0.5687255859375 +34865 -0.2962646484375 +34866 -0.4835205078125 +34867 -0.161102294921875 +34868 -0.389007568359375 +34869 -0.0435791015625 +34870 -0.284149169921875 +34871 0.060394287109375 +34872 -0.180694580078125 +34873 0.13665771484375 +34874 -0.091888427734375 +34875 0.170135498046875 +34876 -0.018707275390625 +34877 0.16552734375 +34878 0.056793212890625 +34879 0.15728759765625 +34880 0.133575439453125 +34881 0.150787353515625 +34882 0.191619873046875 +34883 0.12200927734375 +34884 0.2327880859375 +34885 0.080108642578125 +34886 0.2706298828125 +34887 0.05126953125 +34888 0.32025146484375 +34889 0.062896728515625 +34890 0.365264892578125 +34891 0.09271240234375 +34892 0.373748779296875 +34893 0.092987060546875 +34894 0.3553466796875 +34895 0.07855224609375 +34896 0.320709228515625 +34897 0.06427001953125 +34898 0.261688232421875 +34899 0.0347900390625 +34900 0.1796875 +34901 -0.01171875 +34902 0.09033203125 +34903 -0.056060791015625 +34904 0.02496337890625 +34905 -0.055511474609375 +34906 -0.012908935546875 +34907 -0.010467529296875 +34908 -0.054656982421875 +34909 0.02508544921875 +34910 -0.11334228515625 +34911 0.025665283203125 +34912 -0.16900634765625 +34913 0.017333984375 +34914 -0.217987060546875 +34915 0.00189208984375 +34916 -0.26568603515625 +34917 -0.03173828125 +34918 -0.30328369140625 +34919 -0.071502685546875 +34920 -0.342254638671875 +34921 -0.13543701171875 +34922 -0.380828857421875 +34923 -0.219970703125 +34924 -0.404266357421875 +34925 -0.300506591796875 +34926 -0.4140625 +34927 -0.376312255859375 +34928 -0.392303466796875 +34929 -0.416107177734375 +34930 -0.310150146484375 +34931 -0.371124267578125 +34932 -0.171234130859375 +34933 -0.242279052734375 +34934 -0.004730224609375 +34935 -0.069732666015625 +34936 0.172821044921875 +34937 0.125640869140625 +34938 0.338531494140625 +34939 0.31268310546875 +34940 0.466552734375 +34941 0.45501708984375 +34942 0.55657958984375 +34943 0.554779052734375 +34944 0.606689453125 +34945 0.61065673828125 +34946 0.60882568359375 +34947 0.610931396484375 +34948 0.54754638671875 +34949 0.531463623046875 +34950 0.434112548828125 +34951 0.3883056640625 +34952 0.304534912109375 +34953 0.23468017578125 +34954 0.1767578125 +34955 0.095245361328125 +34956 0.069915771484375 +34957 -0.00396728515625 +34958 -0.004150390625 +34959 -0.04852294921875 +34960 -0.053741455078125 +34961 -0.055145263671875 +34962 -0.110198974609375 +34963 -0.0758056640625 +34964 -0.189544677734375 +34965 -0.138702392578125 +34966 -0.26727294921875 +34967 -0.209197998046875 +34968 -0.342987060546875 +34969 -0.289031982421875 +34970 -0.416046142578125 +34971 -0.37884521484375 +34972 -0.471405029296875 +34973 -0.456329345703125 +34974 -0.505767822265625 +34975 -0.51641845703125 +34976 -0.493804931640625 +34977 -0.519287109375 +34978 -0.432159423828125 +34979 -0.458251953125 +34980 -0.355743408203125 +34981 -0.384796142578125 +34982 -0.28240966796875 +34983 -0.323699951171875 +34984 -0.210418701171875 +34985 -0.269287109375 +34986 -0.124755859375 +34987 -0.1951904296875 +34988 -0.026580810546875 +34989 -0.100006103515625 +34990 0.064697265625 +34991 -0.01055908203125 +34992 0.167022705078125 +34993 0.1033935546875 +34994 0.283721923828125 +34995 0.24908447265625 +34996 0.379119873046875 +34997 0.373199462890625 +34998 0.441162109375 +34999 0.45806884765625 +35000 0.4747314453125 +35001 0.511474609375 +35002 0.50091552734375 +35003 0.565399169921875 +35004 0.514923095703125 +35005 0.61138916015625 +35006 0.47900390625 +35007 0.5897216796875 +35008 0.388153076171875 +35009 0.4906005859375 +35010 0.25531005859375 +35011 0.33148193359375 +35012 0.10516357421875 +35013 0.147796630859375 +35014 -0.033447265625 +35015 -0.01873779296875 +35016 -0.140777587890625 +35017 -0.140289306640625 +35018 -0.19915771484375 +35019 -0.191986083984375 +35020 -0.21417236328125 +35021 -0.184295654296875 +35022 -0.213836669921875 +35023 -0.161834716796875 +35024 -0.224853515625 +35025 -0.166595458984375 +35026 -0.243927001953125 +35027 -0.19390869140625 +35028 -0.258575439453125 +35029 -0.22442626953125 +35030 -0.2833251953125 +35031 -0.279754638671875 +35032 -0.305389404296875 +35033 -0.3389892578125 +35034 -0.2947998046875 +35035 -0.3543701171875 +35036 -0.267242431640625 +35037 -0.348175048828125 +35038 -0.22772216796875 +35039 -0.32598876953125 +35040 -0.158416748046875 +35041 -0.2581787109375 +35042 -0.057464599609375 +35043 -0.139801025390625 +35044 0.064422607421875 +35045 0.014617919921875 +35046 0.166656494140625 +35047 0.144378662109375 +35048 0.229888916015625 +35049 0.221038818359375 +35050 0.270477294921875 +35051 0.27069091796875 +35052 0.288604736328125 +35053 0.294036865234375 +35054 0.297698974609375 +35055 0.311767578125 +35056 0.307952880859375 +35057 0.339141845703125 +35058 0.309539794921875 +35059 0.360260009765625 +35060 0.293792724609375 +35061 0.360504150390625 +35062 0.241241455078125 +35063 0.308380126953125 +35064 0.138641357421875 +35065 0.18170166015625 +35066 0.002960205078125 +35067 0.0047607421875 +35068 -0.13427734375 +35069 -0.17559814453125 +35070 -0.242828369140625 +35071 -0.3143310546875 +35072 -0.29388427734375 +35073 -0.36785888671875 +35074 -0.30328369140625 +35075 -0.36248779296875 +35076 -0.2991943359375 +35077 -0.343536376953125 +35078 -0.27593994140625 +35079 -0.3018798828125 +35080 -0.229888916015625 +35081 -0.231414794921875 +35082 -0.15252685546875 +35083 -0.117645263671875 +35084 -0.06439208984375 +35085 0.007049560546875 +35086 6.103515625e-05 +35087 0.087982177734375 +35088 0.04876708984375 +35089 0.13946533203125 +35090 0.088592529296875 +35091 0.17425537109375 +35092 0.115936279296875 +35093 0.188201904296875 +35094 0.12359619140625 +35095 0.171234130859375 +35096 0.10760498046875 +35097 0.118438720703125 +35098 0.08392333984375 +35099 0.05706787109375 +35100 0.05316162109375 +35101 -0.010711669921875 +35102 0.01080322265625 +35103 -0.0914306640625 +35104 -0.029388427734375 +35105 -0.162322998046875 +35106 -0.04974365234375 +35107 -0.194549560546875 +35108 -0.02618408203125 +35109 -0.1492919921875 +35110 0.044647216796875 +35111 -0.02166748046875 +35112 0.123687744140625 +35113 0.124053955078125 +35114 0.164337158203125 +35115 0.211151123046875 +35116 0.16790771484375 +35117 0.240447998046875 +35118 0.15386962890625 +35119 0.242218017578125 +35120 0.128753662109375 +35121 0.2257080078125 +35122 0.095489501953125 +35123 0.194366455078125 +35124 0.034698486328125 +35125 0.115509033203125 +35126 -0.03839111328125 +35127 0.0128173828125 +35128 -0.08642578125 +35129 -0.053802490234375 +35130 -0.125274658203125 +35131 -0.110626220703125 +35132 -0.180633544921875 +35133 -0.199493408203125 +35134 -0.23651123046875 +35135 -0.29437255859375 +35136 -0.254302978515625 +35137 -0.33221435546875 +35138 -0.213897705078125 +35139 -0.27972412109375 +35140 -0.1456298828125 +35141 -0.185333251953125 +35142 -0.098876953125 +35143 -0.128204345703125 +35144 -0.078826904296875 +35145 -0.115692138671875 +35146 -0.066864013671875 +35147 -0.116455078125 +35148 -0.048583984375 +35149 -0.105926513671875 +35150 -0.006011962890625 +35151 -0.053955078125 +35152 0.0660400390625 +35153 0.048797607421875 +35154 0.13946533203125 +35155 0.157318115234375 +35156 0.177215576171875 +35157 0.212005615234375 +35158 0.182586669921875 +35159 0.218475341796875 +35160 0.19287109375 +35161 0.23724365234375 +35162 0.231048583984375 +35163 0.30535888671875 +35164 0.27178955078125 +35165 0.38128662109375 +35166 0.278167724609375 +35167 0.404449462890625 +35168 0.262725830078125 +35169 0.3944091796875 +35170 0.2490234375 +35171 0.3885498046875 +35172 0.22271728515625 +35173 0.362640380859375 +35174 0.157867431640625 +35175 0.27362060546875 +35176 0.052337646484375 +35177 0.11712646484375 +35178 -0.061370849609375 +35179 -0.054901123046875 +35180 -0.151123046875 +35181 -0.19085693359375 +35182 -0.213531494140625 +35183 -0.28570556640625 +35184 -0.248321533203125 +35185 -0.339263916015625 +35186 -0.271484375 +35187 -0.3775634765625 +35188 -0.3109130859375 +35189 -0.445709228515625 +35190 -0.361480712890625 +35191 -0.535064697265625 +35192 -0.413299560546875 +35193 -0.629058837890625 +35194 -0.44818115234375 +35195 -0.697601318359375 +35196 -0.443939208984375 +35197 -0.70391845703125 +35198 -0.3975830078125 +35199 -0.6424560546875 +35200 -0.296051025390625 +35201 -0.491241455078125 +35202 -0.149322509765625 +35203 -0.265716552734375 +35204 0.00653076171875 +35205 -0.023712158203125 +35206 0.150848388671875 +35207 0.201751708984375 +35208 0.261871337890625 +35209 0.375823974609375 +35210 0.331207275390625 +35211 0.485076904296875 +35212 0.383026123046875 +35213 0.56884765625 +35214 0.42205810546875 +35215 0.634765625 +35216 0.420623779296875 +35217 0.63763427734375 +35218 0.37188720703125 +35219 0.5660400390625 +35220 0.308197021484375 +35221 0.4720458984375 +35222 0.261505126953125 +35223 0.40692138671875 +35224 0.236602783203125 +35225 0.3778076171875 +35226 0.229095458984375 +35227 0.376953125 +35228 0.219390869140625 +35229 0.371978759765625 +35230 0.17724609375 +35231 0.313140869140625 +35232 0.09307861328125 +35233 0.184417724609375 +35234 -0.0172119140625 +35235 0.011199951171875 +35236 -0.13165283203125 +35237 -0.171051025390625 +35238 -0.23480224609375 +35239 -0.33740234375 +35240 -0.316864013671875 +35241 -0.47198486328125 +35242 -0.369049072265625 +35243 -0.560394287109375 +35244 -0.377960205078125 +35245 -0.58056640625 +35246 -0.353118896484375 +35247 -0.54754638671875 +35248 -0.3238525390625 +35249 -0.508575439453125 +35250 -0.2879638671875 +35251 -0.459503173828125 +35252 -0.2420654296875 +35253 -0.394378662109375 +35254 -0.21075439453125 +35255 -0.35260009765625 +35256 -0.18048095703125 +35257 -0.31170654296875 +35258 -0.10577392578125 +35259 -0.197418212890625 +35260 0.014251708984375 +35261 -0.007965087890625 +35262 0.149139404296875 +35263 0.207489013671875 +35264 0.274322509765625 +35265 0.409210205078125 +35266 0.374298095703125 +35267 0.57208251953125 +35268 0.430572509765625 +35269 0.66595458984375 +35270 0.42352294921875 +35271 0.65875244140625 +35272 0.36376953125 +35273 0.56744384765625 +35274 0.2757568359375 +35275 0.431396484375 +35276 0.186737060546875 +35277 0.29443359375 +35278 0.11297607421875 +35279 0.182464599609375 +35280 0.035125732421875 +35281 0.06365966796875 +35282 -0.05517578125 +35283 -0.075958251953125 +35284 -0.1287841796875 +35285 -0.189422607421875 +35286 -0.182525634765625 +35287 -0.271942138671875 +35288 -0.22796630859375 +35289 -0.342529296875 +35290 -0.242279052734375 +35291 -0.364166259765625 +35292 -0.219512939453125 +35293 -0.327239990234375 +35294 -0.187530517578125 +35295 -0.2769775390625 +35296 -0.171295166015625 +35297 -0.253692626953125 +35298 -0.162445068359375 +35299 -0.24365234375 +35300 -0.13128662109375 +35301 -0.1983642578125 +35302 -0.0770263671875 +35303 -0.116241455078125 +35304 -0.02423095703125 +35305 -0.036834716796875 +35306 0.0238037109375 +35307 0.034881591796875 +35308 0.0621337890625 +35309 0.09124755859375 +35310 0.076171875 +35311 0.10888671875 +35312 0.0889892578125 +35313 0.125518798828125 +35314 0.1107177734375 +35315 0.15771484375 +35316 0.124481201171875 +35317 0.17828369140625 +35318 0.12030029296875 +35319 0.17108154296875 +35320 0.09442138671875 +35321 0.129974365234375 +35322 0.063812255859375 +35323 0.082427978515625 +35324 0.028106689453125 +35325 0.027679443359375 +35326 -0.031890869140625 +35327 -0.065643310546875 +35328 -0.092864990234375 +35329 -0.15936279296875 +35330 -0.129364013671875 +35331 -0.21307373046875 +35332 -0.145416259765625 +35333 -0.234649658203125 +35334 -0.12725830078125 +35335 -0.2001953125 +35336 -0.0806884765625 +35337 -0.119171142578125 +35338 -0.02532958984375 +35339 -0.024749755859375 +35340 0.0401611328125 +35341 0.085784912109375 +35342 0.095550537109375 +35343 0.178131103515625 +35344 0.119232177734375 +35345 0.215576171875 +35346 0.11883544921875 +35347 0.211456298828125 +35348 0.099761962890625 +35349 0.17523193359375 +35350 0.07464599609375 +35351 0.128753662109375 +35352 0.06085205078125 +35353 0.1019287109375 +35354 0.04638671875 +35355 0.0743408203125 +35356 0.02960205078125 +35357 0.04327392578125 +35358 0.027618408203125 +35359 0.038177490234375 +35360 0.05047607421875 +35361 0.076263427734375 +35362 0.08856201171875 +35363 0.14105224609375 +35364 0.11492919921875 +35365 0.186431884765625 +35366 0.115814208984375 +35367 0.188812255859375 +35368 0.0859375 +35369 0.1390380859375 +35370 0.028106689453125 +35371 0.041778564453125 +35372 -0.043853759765625 +35373 -0.079437255859375 +35374 -0.1268310546875 +35375 -0.219390869140625 +35376 -0.21478271484375 +35377 -0.367828369140625 +35378 -0.290191650390625 +35379 -0.494873046875 +35380 -0.327117919921875 +35381 -0.556243896484375 +35382 -0.300262451171875 +35383 -0.508697509765625 +35384 -0.223236083984375 +35385 -0.3756103515625 +35386 -0.1322021484375 +35387 -0.218902587890625 +35388 -0.04180908203125 +35389 -0.063751220703125 +35390 0.04888916015625 +35391 0.091552734375 +35392 0.133514404296875 +35393 0.23602294921875 +35394 0.196441650390625 +35395 0.342987060546875 +35396 0.22760009765625 +35397 0.39520263671875 +35398 0.225006103515625 +35399 0.389373779296875 +35400 0.187896728515625 +35401 0.324249267578125 +35402 0.130401611328125 +35403 0.224090576171875 +35404 0.0731201171875 +35405 0.124267578125 +35406 0.02313232421875 +35407 0.037078857421875 +35408 -0.003570556640625 +35409 -0.010101318359375 +35410 -0.008331298828125 +35411 -0.019439697265625 +35412 -0.009765625 +35413 -0.022796630859375 +35414 0.0029296875 +35415 -0.001556396484375 +35416 0.036773681640625 +35417 0.056304931640625 +35418 0.0660400390625 +35419 0.106719970703125 +35420 0.0599365234375 +35421 0.096893310546875 +35422 0.027740478515625 +35423 0.042694091796875 +35424 -0.008392333984375 +35425 -0.018035888671875 +35426 -0.04290771484375 +35427 -0.07586669921875 +35428 -0.06915283203125 +35429 -0.11944580078125 +35430 -0.093475341796875 +35431 -0.15972900390625 +35432 -0.1192626953125 +35433 -0.202606201171875 +35434 -0.146728515625 +35435 -0.24859619140625 +35436 -0.18023681640625 +35437 -0.30517578125 +35438 -0.21380615234375 +35439 -0.36212158203125 +35440 -0.231109619140625 +35441 -0.39141845703125 +35442 -0.210052490234375 +35443 -0.35528564453125 +35444 -0.148468017578125 +35445 -0.249969482421875 +35446 -0.056488037109375 +35447 -0.092864990234375 +35448 0.050079345703125 +35449 0.08905029296875 +35450 0.1358642578125 +35451 0.2352294921875 +35452 0.1851806640625 +35453 0.318817138671875 +35454 0.208953857421875 +35455 0.358642578125 +35456 0.203125 +35457 0.347747802734375 +35458 0.167388916015625 +35459 0.28564453125 +35460 0.131378173828125 +35461 0.223175048828125 +35462 0.1163330078125 +35463 0.196746826171875 +35464 0.106781005859375 +35465 0.179840087890625 +35466 0.092803955078125 +35467 0.155548095703125 +35468 0.090362548828125 +35469 0.151214599609375 +35470 0.09368896484375 +35471 0.156951904296875 +35472 0.078857421875 +35473 0.13177490234375 +35474 0.060546875 +35475 0.100799560546875 +35476 0.05224609375 +35477 0.087127685546875 +35478 0.03302001953125 +35479 0.05487060546875 +35480 -0.00469970703125 +35481 -0.009002685546875 +35482 -0.06060791015625 +35483 -0.10400390625 +35484 -0.13427734375 +35485 -0.229400634765625 +35486 -0.20831298828125 +35487 -0.35552978515625 +35488 -0.259063720703125 +35489 -0.441925048828125 +35490 -0.2779541015625 +35491 -0.473846435546875 +35492 -0.2728271484375 +35493 -0.464813232421875 +35494 -0.246185302734375 +35495 -0.419097900390625 +35496 -0.1966552734375 +35497 -0.334320068359375 +35498 -0.1343994140625 +35499 -0.227935791015625 +35500 -0.07318115234375 +35501 -0.12347412109375 +35502 -0.016937255859375 +35503 -0.02764892578125 +35504 0.044921875 +35505 0.077667236328125 +35506 0.124481201171875 +35507 0.2132568359375 +35508 0.227386474609375 +35509 0.38885498046875 +35510 0.340972900390625 +35511 0.582794189453125 +35512 0.4295654296875 +35513 0.734039306640625 +35514 0.4683837890625 +35515 0.800140380859375 +35516 0.455780029296875 +35517 0.7783203125 +35518 0.389739990234375 +35519 0.6651611328125 +35520 0.26971435546875 +35521 0.45965576171875 +35522 0.117523193359375 +35523 0.199188232421875 +35524 -0.02850341796875 +35525 -0.050689697265625 +35526 -0.135101318359375 +35527 -0.23297119140625 +35528 -0.1920166015625 +35529 -0.33013916015625 +35530 -0.21453857421875 +35531 -0.368408203125 +35532 -0.220855712890625 +35533 -0.378936767578125 +35534 -0.21990966796875 +35535 -0.376983642578125 +35536 -0.221710205078125 +35537 -0.37969970703125 +35538 -0.22882080078125 +35539 -0.391510009765625 +35540 -0.225433349609375 +35541 -0.385345458984375 +35542 -0.20025634765625 +35543 -0.3419189453125 +35544 -0.165924072265625 +35545 -0.28289794921875 +35546 -0.147735595703125 +35547 -0.251617431640625 +35548 -0.156219482421875 +35549 -0.266143798828125 +35550 -0.160369873046875 +35551 -0.273345947265625 +35552 -0.12725830078125 +35553 -0.216796875 +35554 -0.075408935546875 +35555 -0.128265380859375 +35556 -0.04010009765625 +35557 -0.068145751953125 +35558 -0.02520751953125 +35559 -0.0430908203125 +35560 -0.0140380859375 +35561 -0.024444580078125 +35562 0.012603759765625 +35563 0.020721435546875 +35564 0.07342529296875 +35565 0.124481201171875 +35566 0.1514892578125 +35567 0.25787353515625 +35568 0.222381591796875 +35569 0.379119873046875 +35570 0.281280517578125 +35571 0.47991943359375 +35572 0.3094482421875 +35573 0.5281982421875 +35574 0.299407958984375 +35575 0.511138916015625 +35576 0.2672119140625 +35577 0.456207275390625 +35578 0.238616943359375 +35579 0.407470703125 +35580 0.224609375 +35581 0.383758544921875 +35582 0.208740234375 +35583 0.35687255859375 +35584 0.181732177734375 +35585 0.31182861328125 +35586 0.14459228515625 +35587 0.250885009765625 +35588 0.09295654296875 +35589 0.1654052734375 +35590 0.0162353515625 +35591 0.035247802734375 +35592 -0.08648681640625 +35593 -0.142059326171875 +35594 -0.19775390625 +35595 -0.33563232421875 +35596 -0.311187744140625 +35597 -0.5345458984375 +35598 -0.41717529296875 +35599 -0.72186279296875 +35600 -0.481964111328125 +35601 -0.836669921875 +35602 -0.47991943359375 +35603 -0.8326416015625 +35604 -0.4219970703125 +35605 -0.7296142578125 +35606 -0.338653564453125 +35607 -0.582550048828125 +35608 -0.25689697265625 +35609 -0.440093994140625 +35610 -0.189117431640625 +35611 -0.324310302734375 +35612 -0.116912841796875 +35613 -0.20147705078125 +35614 -0.02569580078125 +35615 -0.044647216796875 +35616 0.060943603515625 +35617 0.103973388671875 +35618 0.11956787109375 +35619 0.202392578125 +35620 0.1575927734375 +35621 0.264495849609375 +35622 0.201690673828125 +35623 0.338897705078125 +35624 0.261749267578125 +35625 0.443817138671875 +35626 0.318817138671875 +35627 0.545074462890625 +35628 0.358856201171875 +35629 0.6173095703125 +35630 0.37744140625 +35631 0.6524658203125 +35632 0.3817138671875 +35633 0.66339111328125 +35634 0.375152587890625 +35635 0.6561279296875 +35636 0.3447265625 +35637 0.606781005859375 +35638 0.282806396484375 +35639 0.501190185546875 +35640 0.196990966796875 +35641 0.352783203125 +35642 0.095794677734375 +35643 0.176544189453125 +35644 -0.024566650390625 +35645 -0.034820556640625 +35646 -0.151123046875 +35647 -0.258209228515625 +35648 -0.2554931640625 +35649 -0.44244384765625 +35650 -0.330810546875 +35651 -0.5753173828125 +35652 -0.37432861328125 +35653 -0.65203857421875 +35654 -0.368927001953125 +35655 -0.641632080078125 +35656 -0.3245849609375 +35657 -0.562164306640625 +35658 -0.265869140625 +35659 -0.458038330078125 +35660 -0.204620361328125 +35661 -0.350555419921875 +35662 -0.152435302734375 +35663 -0.260528564453125 +35664 -0.111785888671875 +35665 -0.192108154296875 +35666 -0.080963134765625 +35667 -0.141937255859375 +35668 -0.055816650390625 +35669 -0.1021728515625 +35670 -0.03106689453125 +35671 -0.062896728515625 +35672 -0.0001220703125 +35673 -0.011932373046875 +35674 0.04351806640625 +35675 0.062835693359375 +35676 0.092742919921875 +35677 0.148712158203125 +35678 0.145263671875 +35679 0.241729736328125 +35680 0.205047607421875 +35681 0.34912109375 +35682 0.26458740234375 +35683 0.457305908203125 +35684 0.3115234375 +35685 0.54388427734375 +35686 0.326080322265625 +35687 0.5728759765625 +35688 0.287567138671875 +35689 0.506591796875 +35690 0.199493408203125 +35691 0.351226806640625 +35692 0.083953857421875 +35693 0.146514892578125 +35694 -0.030029296875 +35695 -0.05523681640625 +35696 -0.121490478515625 +35697 -0.21624755859375 +35698 -0.189361572265625 +35699 -0.334930419921875 +35700 -0.22894287109375 +35701 -0.402984619140625 +35702 -0.251678466796875 +35703 -0.4412841796875 +35704 -0.282867431640625 +35705 -0.49578857421875 +35706 -0.318939208984375 +35707 -0.5601806640625 +35708 -0.34130859375 +35709 -0.600738525390625 +35710 -0.331634521484375 +35711 -0.584228515625 +35712 -0.27264404296875 +35713 -0.47930908203125 +35714 -0.1607666015625 +35715 -0.27935791015625 +35716 -0.0096435546875 +35717 -0.0089111328125 +35718 0.145660400390625 +35719 0.268798828125 +35720 0.265899658203125 +35721 0.482818603515625 +35722 0.334686279296875 +35723 0.60369873046875 +35724 0.36236572265625 +35725 0.650421142578125 +35726 0.37152099609375 +35727 0.66400146484375 +35728 0.360443115234375 +35729 0.6414794921875 +35730 0.3233642578125 +35731 0.572540283203125 +35732 0.2828369140625 +35733 0.498138427734375 +35734 0.25054931640625 +35735 0.439453125 +35736 0.21490478515625 +35737 0.375518798828125 +35738 0.15838623046875 +35739 0.274505615234375 +35740 0.0657958984375 +35741 0.1087646484375 +35742 -0.05047607421875 +35743 -0.099395751953125 +35744 -0.172821044921875 +35745 -0.3182373046875 +35746 -0.301849365234375 +35747 -0.5489501953125 +35748 -0.4276123046875 +35749 -0.7738037109375 +35750 -0.52081298828125 +35751 -0.86383056640625 +35752 -0.563018798828125 +35753 -0.870391845703125 +35754 -0.563934326171875 +35755 -0.86895751953125 +35756 -0.53076171875 +35757 -0.861053466796875 +35758 -0.45391845703125 +35759 -0.765869140625 +35760 -0.3271484375 +35761 -0.5301513671875 +35762 -0.154388427734375 +35763 -0.214691162109375 +35764 0.040557861328125 +35765 0.137359619140625 +35766 0.2293701171875 +35767 0.474822998046875 +35768 0.392333984375 +35769 0.76239013671875 +35770 0.514495849609375 +35771 0.867462158203125 +35772 0.596038818359375 +35773 0.870361328125 +35774 0.6304931640625 +35775 0.86480712890625 +35776 0.6207275390625 +35777 0.831817626953125 +35778 0.58013916015625 +35779 0.677581787109375 +35780 0.511871337890625 +35781 0.495880126953125 +35782 0.426116943359375 +35783 0.30767822265625 +35784 0.32403564453125 +35785 0.116180419921875 +35786 0.1881103515625 +35787 -0.110748291015625 +35788 0.014556884765625 +35789 -0.381805419921875 +35790 -0.1729736328125 +35791 -0.6572265625 +35792 -0.34136962890625 +35793 -0.857421875 +35794 -0.4669189453125 +35795 -0.870391845703125 +35796 -0.545654296875 +35797 -0.870391845703125 +35798 -0.59234619140625 +35799 -0.86444091796875 +35800 -0.626617431640625 +35801 -0.85723876953125 +35802 -0.6383056640625 +35803 -0.790008544921875 +35804 -0.59735107421875 +35805 -0.62847900390625 +35806 -0.501953125 +35807 -0.3956298828125 +35808 -0.370208740234375 +35809 -0.126708984375 +35810 -0.21722412109375 +35811 0.150115966796875 +35812 -0.049468994140625 +35813 0.424041748046875 +35814 0.1181640625 +35815 0.670623779296875 +35816 0.2642822265625 +35817 0.854522705078125 +35818 0.37908935546875 +35819 0.866485595703125 +35820 0.45404052734375 +35821 0.86920166015625 +35822 0.49908447265625 +35823 0.8653564453125 +35824 0.5216064453125 +35825 0.857147216796875 +35826 0.51995849609375 +35827 0.766845703125 +35828 0.496856689453125 +35829 0.628509521484375 +35830 0.44854736328125 +35831 0.462127685546875 +35832 0.389251708984375 +35833 0.297210693359375 +35834 0.32574462890625 +35835 0.14862060546875 +35836 0.24542236328125 +35837 -0.00537109375 +35838 0.152435302734375 +35839 -0.15753173828125 +35840 0.04522705078125 +35841 -0.31304931640625 +35842 -0.083831787109375 +35843 -0.48876953125 +35844 -0.210174560546875 +35845 -0.6416015625 +35846 -0.320098876953125 +35847 -0.751373291015625 +35848 -0.4249267578125 +35849 -0.84619140625 +35850 -0.51641845703125 +35851 -0.861297607421875 +35852 -0.576934814453125 +35853 -0.863250732421875 +35854 -0.58978271484375 +35855 -0.856597900390625 +35856 -0.5611572265625 +35857 -0.7498779296875 +35858 -0.52117919921875 +35859 -0.624542236328125 +35860 -0.458587646484375 +35861 -0.47808837890625 +35862 -0.34332275390625 +35863 -0.253387451171875 +35864 -0.199493408203125 +35865 0.003692626953125 +35866 -0.063079833984375 +35867 0.2257080078125 +35868 0.07196044921875 +35869 0.427154541015625 +35870 0.22198486328125 +35871 0.643218994140625 +35872 0.381500244140625 +35873 0.855926513671875 +35874 0.51995849609375 +35875 0.870361328125 +35876 0.611236572265625 +35877 0.870361328125 +35878 0.6588134765625 +35879 0.862762451171875 +35880 0.66094970703125 +35881 0.79669189453125 +35882 0.612701416015625 +35883 0.595794677734375 +35884 0.529296875 +35885 0.362152099609375 +35886 0.425445556640625 +35887 0.1270751953125 +35888 0.312408447265625 +35889 -0.086944580078125 +35890 0.191619873046875 +35891 -0.2784423828125 +35892 0.04534912109375 +35893 -0.484832763671875 +35894 -0.135955810546875 +35895 -0.729583740234375 +35896 -0.325592041015625 +35897 -0.86688232421875 +35898 -0.490203857421875 +35899 -0.870391845703125 +35900 -0.626800537109375 +35901 -0.86859130859375 +35902 -0.733978271484375 +35903 -0.86279296875 +35904 -0.792724609375 +35905 -0.817962646484375 +35906 -0.779266357421875 +35907 -0.6116943359375 +35908 -0.689849853515625 +35909 -0.3128662109375 +35910 -0.5419921875 +35911 0.039398193359375 +35912 -0.346221923828125 +35913 0.422821044921875 +35914 -0.120025634765625 +35915 0.805145263671875 +35916 0.100830078125 +35917 0.870361328125 +35918 0.286346435546875 +35919 0.870361328125 +35920 0.42999267578125 +35921 0.860015869140625 +35922 0.52734375 +35923 0.727935791015625 +35924 0.57501220703125 +35925 0.48114013671875 +35926 0.58514404296875 +35927 0.2059326171875 +35928 0.569091796875 +35929 -0.06103515625 +35930 0.531768798828125 +35931 -0.29913330078125 +35932 0.46539306640625 +35933 -0.516204833984375 +35934 0.36187744140625 +35935 -0.7252197265625 +35936 0.23419189453125 +35937 -0.85980224609375 +35938 0.100341796875 +35939 -0.870391845703125 +35940 -0.02398681640625 +35941 -0.870391845703125 +35942 -0.11309814453125 +35943 -0.858062744140625 +35944 -0.164306640625 +35945 -0.673004150390625 +35946 -0.204345703125 +35947 -0.42694091796875 +35948 -0.255706787109375 +35949 -0.2100830078125 +35950 -0.31671142578125 +35951 -0.0362548828125 +35952 -0.37176513671875 +35953 0.10943603515625 +35954 -0.4100341796875 +35955 0.23516845703125 +35956 -0.409637451171875 +35957 0.373687744140625 +35958 -0.371307373046875 +35959 0.517791748046875 +35960 -0.327728271484375 +35961 0.602783203125 +35962 -0.27618408203125 +35963 0.635711669921875 +35964 -0.19952392578125 +35965 0.655181884765625 +35966 -0.103179931640625 +35967 0.65948486328125 +35968 0.008270263671875 +35969 0.651275634765625 +35970 0.12158203125 +35971 0.61846923828125 +35972 0.217010498046875 +35973 0.53753662109375 +35974 0.28460693359375 +35975 0.404144287109375 +35976 0.31878662109375 +35977 0.22186279296875 +35978 0.3197021484375 +35979 0.003997802734375 +35980 0.29632568359375 +35981 -0.22100830078125 +35982 0.259002685546875 +35983 -0.42449951171875 +35984 0.21856689453125 +35985 -0.579833984375 +35986 0.1971435546875 +35987 -0.641876220703125 +35988 0.19122314453125 +35989 -0.6177978515625 +35990 0.167327880859375 +35991 -0.575531005859375 +35992 0.122894287109375 +35993 -0.526336669921875 +35994 0.085174560546875 +35995 -0.42645263671875 +35996 0.06884765625 +35997 -0.2581787109375 +35998 0.05548095703125 +35999 -0.068695068359375 +36000 0.0255126953125 +36001 0.09222412109375 +36002 -0.0108642578125 +36003 0.232147216796875 +36004 -0.0478515625 +36005 0.3509521484375 +36006 -0.1004638671875 +36007 0.410064697265625 +36008 -0.18359375 +36009 0.372955322265625 +36010 -0.286041259765625 +36011 0.2554931640625 +36012 -0.380523681640625 +36013 0.10711669921875 +36014 -0.456756591796875 +36015 -0.052886962890625 +36016 -0.49591064453125 +36017 -0.186279296875 +36018 -0.46905517578125 +36019 -0.23291015625 +36020 -0.38824462890625 +36021 -0.209442138671875 +36022 -0.28802490234375 +36023 -0.174163818359375 +36024 -0.173065185546875 +36025 -0.126739501953125 +36026 -0.038665771484375 +36027 -0.048126220703125 +36028 0.10009765625 +36029 0.0426025390625 +36030 0.218536376953125 +36031 0.10748291015625 +36032 0.309356689453125 +36033 0.1409912109375 +36034 0.396942138671875 +36035 0.19708251953125 +36036 0.4774169921875 +36037 0.273651123046875 +36038 0.52154541015625 +36039 0.31768798828125 +36040 0.534912109375 +36041 0.341094970703125 +36042 0.530609130859375 +36043 0.368011474609375 +36044 0.496673583984375 +36045 0.37249755859375 +36046 0.4075927734375 +36047 0.30072021484375 +36048 0.26617431640625 +36049 0.1517333984375 +36050 0.107269287109375 +36051 -0.01470947265625 +36052 -0.059539794921875 +36053 -0.1883544921875 +36054 -0.2318115234375 +36055 -0.372711181640625 +36056 -0.37738037109375 +36057 -0.51397705078125 +36058 -0.471435546875 +36059 -0.57177734375 +36060 -0.50732421875 +36061 -0.53948974609375 +36062 -0.491851806640625 +36063 -0.43511962890625 +36064 -0.442840576171875 +36065 -0.2962646484375 +36066 -0.379364013671875 +36067 -0.161102294921875 +36068 -0.3087158203125 +36069 -0.0435791015625 +36070 -0.229766845703125 +36071 0.060394287109375 +36072 -0.151702880859375 +36073 0.13665771484375 +36074 -0.084808349609375 +36075 0.170135498046875 +36076 -0.0296630859375 +36077 0.16552734375 +36078 0.028228759765625 +36079 0.15728759765625 +36080 0.088165283203125 +36081 0.150787353515625 +36082 0.134185791015625 +36083 0.12200927734375 +36084 0.167755126953125 +36085 0.080108642578125 +36086 0.19964599609375 +36087 0.05126953125 +36088 0.2418212890625 +36089 0.062896728515625 +36090 0.281036376953125 +36091 0.09271240234375 +36092 0.291534423828125 +36093 0.092987060546875 +36094 0.28082275390625 +36095 0.07855224609375 +36096 0.25732421875 +36097 0.06427001953125 +36098 0.21429443359375 +36099 0.0347900390625 +36100 0.15252685546875 +36101 -0.01171875 +36102 0.084136962890625 +36103 -0.056060791015625 +36104 0.0333251953125 +36105 -0.055511474609375 +36106 0.002899169921875 +36107 -0.010467529296875 +36108 -0.0311279296875 +36109 0.02508544921875 +36110 -0.07867431640625 +36111 0.025665283203125 +36112 -0.124176025390625 +36113 0.017333984375 +36114 -0.16473388671875 +36115 0.00189208984375 +36116 -0.204315185546875 +36117 -0.03173828125 +36118 -0.235992431640625 +36119 -0.071502685546875 +36120 -0.2684326171875 +36121 -0.13543701171875 +36122 -0.3001708984375 +36123 -0.219970703125 +36124 -0.31976318359375 +36125 -0.300506591796875 +36126 -0.32830810546875 +36127 -0.376312255859375 +36128 -0.31201171875 +36129 -0.416107177734375 +36130 -0.248687744140625 +36131 -0.371124267578125 +36132 -0.141143798828125 +36133 -0.242279052734375 +36134 -0.011871337890625 +36135 -0.069732666015625 +36136 0.126312255859375 +36137 0.125640869140625 +36138 0.25567626953125 +36139 0.31268310546875 +36140 0.356231689453125 +36141 0.45501708984375 +36142 0.427642822265625 +36143 0.554779052734375 +36144 0.468292236328125 +36145 0.61065673828125 +36146 0.471893310546875 +36147 0.610931396484375 +36148 0.426483154296875 +36149 0.531463623046875 +36150 0.340606689453125 +36151 0.3883056640625 +36152 0.241912841796875 +36153 0.23468017578125 +36154 0.1441650390625 +36155 0.095245361328125 +36156 0.06207275390625 +36157 -0.00396728515625 +36158 0.00469970703125 +36159 -0.04852294921875 +36160 -0.03424072265625 +36161 -0.055145263671875 +36162 -0.07879638671875 +36163 -0.0758056640625 +36164 -0.1412353515625 +36165 -0.138702392578125 +36166 -0.202667236328125 +36167 -0.209197998046875 +36168 -0.262664794921875 +36169 -0.289031982421875 +36170 -0.32061767578125 +36171 -0.37884521484375 +36172 -0.3648681640625 +36173 -0.456329345703125 +36174 -0.392791748046875 +36175 -0.51641845703125 +36176 -0.38482666015625 +36177 -0.519287109375 +36178 -0.33831787109375 +36179 -0.458251953125 +36180 -0.28009033203125 +36181 -0.384796142578125 +36182 -0.223846435546875 +36183 -0.323699951171875 +36184 -0.16827392578125 +36185 -0.269287109375 +36186 -0.101837158203125 +36187 -0.1951904296875 +36188 -0.02545166015625 +36189 -0.100006103515625 +36190 0.0458984375 +36191 -0.01055908203125 +36192 0.12591552734375 +36193 0.1033935546875 +36194 0.21710205078125 +36195 0.24908447265625 +36196 0.291900634765625 +36197 0.373199462890625 +36198 0.340972900390625 +36199 0.45806884765625 +36200 0.368011474609375 +36201 0.511474609375 +36202 0.389190673828125 +36203 0.565399169921875 +36204 0.4007568359375 +36205 0.61138916015625 +36206 0.3736572265625 +36207 0.5897216796875 +36208 0.303985595703125 +36209 0.4906005859375 +36210 0.20172119140625 +36211 0.33148193359375 +36212 0.085845947265625 +36213 0.147796630859375 +36214 -0.021392822265625 +36215 -0.01873779296875 +36216 -0.10479736328125 +36217 -0.140289306640625 +36218 -0.150726318359375 +36219 -0.191986083984375 +36220 -0.16339111328125 +36221 -0.184295654296875 +36222 -0.164276123046875 +36223 -0.161834716796875 +36224 -0.173858642578125 +36225 -0.166595458984375 +36226 -0.189544677734375 +36227 -0.19390869140625 +36228 -0.20172119140625 +36229 -0.22442626953125 +36230 -0.22149658203125 +36231 -0.279754638671875 +36232 -0.238983154296875 +36233 -0.3389892578125 +36234 -0.231109619140625 +36235 -0.3543701171875 +36236 -0.209930419921875 +36237 -0.348175048828125 +36238 -0.179290771484375 +36239 -0.32598876953125 +36240 -0.125518798828125 +36241 -0.2581787109375 +36242 -0.047210693359375 +36243 -0.139801025390625 +36244 0.04736328125 +36245 0.014617919921875 +36246 0.126922607421875 +36247 0.144378662109375 +36248 0.176513671875 +36249 0.221038818359375 +36250 0.20867919921875 +36251 0.27069091796875 +36252 0.223480224609375 +36253 0.294036865234375 +36254 0.231231689453125 +36255 0.311767578125 +36256 0.239715576171875 +36257 0.339141845703125 +36258 0.2412109375 +36259 0.360260009765625 +36260 0.22906494140625 +36261 0.360504150390625 +36262 0.188690185546875 +36263 0.308380126953125 +36264 0.110198974609375 +36265 0.18170166015625 +36266 0.006439208984375 +36267 0.0047607421875 +36268 -0.09869384765625 +36269 -0.17559814453125 +36270 -0.18231201171875 +36271 -0.3143310546875 +36272 -0.2222900390625 +36273 -0.36785888671875 +36274 -0.230743408203125 +36275 -0.36248779296875 +36276 -0.229278564453125 +36277 -0.343536376953125 +36278 -0.213134765625 +36279 -0.3018798828125 +36280 -0.17919921875 +36281 -0.231414794921875 +36282 -0.120452880859375 +36283 -0.117645263671875 +36284 -0.053009033203125 +36285 0.007049560546875 +36286 -0.0040283203125 +36287 0.087982177734375 +36288 0.032867431640625 +36289 0.13946533203125 +36290 0.063201904296875 +36291 0.17425537109375 +36292 0.08416748046875 +36293 0.188201904296875 +36294 0.09002685546875 +36295 0.171234130859375 +36296 0.07763671875 +36297 0.118438720703125 +36298 0.05963134765625 +36299 0.05706787109375 +36300 0.03643798828125 +36301 -0.010711669921875 +36302 0.004364013671875 +36303 -0.0914306640625 +36304 -0.025787353515625 +36305 -0.162322998046875 +36306 -0.04010009765625 +36307 -0.194549560546875 +36308 -0.019622802734375 +36309 -0.1492919921875 +36310 0.038177490234375 +36311 -0.02166748046875 +36312 0.102264404296875 +36313 0.124053955078125 +36314 0.135650634765625 +36315 0.211151123046875 +36316 0.139312744140625 +36317 0.240447998046875 +36318 0.128631591796875 +36319 0.242218017578125 +36320 0.10882568359375 +36321 0.2257080078125 +36322 0.08221435546875 +36323 0.194366455078125 +36324 0.033447265625 +36325 0.115509033203125 +36326 -0.025390625 +36327 0.0128173828125 +36328 -0.06463623046875 +36329 -0.053802490234375 +36330 -0.0968017578125 +36331 -0.110626220703125 +36332 -0.142120361328125 +36333 -0.199493408203125 +36334 -0.187835693359375 +36335 -0.29437255859375 +36336 -0.20330810546875 +36337 -0.33221435546875 +36338 -0.17254638671875 +36339 -0.27972412109375 +36340 -0.1195068359375 +36341 -0.185333251953125 +36342 -0.083251953125 +36343 -0.128204345703125 +36344 -0.067840576171875 +36345 -0.115692138671875 +36346 -0.058502197265625 +36347 -0.116455078125 +36348 -0.0438232421875 +36349 -0.105926513671875 +36350 -0.009613037109375 +36351 -0.053955078125 +36352 0.048004150390625 +36353 0.048797607421875 +36354 0.10699462890625 +36355 0.157318115234375 +36356 0.139068603515625 +36357 0.212005615234375 +36358 0.14642333984375 +36359 0.218475341796875 +36360 0.156463623046875 +36361 0.23724365234375 +36362 0.186126708984375 +36363 0.30535888671875 +36364 0.216644287109375 +36365 0.38128662109375 +36366 0.220703125 +36367 0.404449462890625 +36368 0.20770263671875 +36369 0.3944091796875 +36370 0.195220947265625 +36371 0.3885498046875 +36372 0.172821044921875 +36373 0.362640380859375 +36374 0.121490478515625 +36375 0.27362060546875 +36376 0.03985595703125 +36377 0.11712646484375 +36378 -0.047821044921875 +36379 -0.054901123046875 +36380 -0.117523193359375 +36381 -0.19085693359375 +36382 -0.16656494140625 +36383 -0.28570556640625 +36384 -0.194610595703125 +36385 -0.339263916015625 +36386 -0.21337890625 +36387 -0.3775634765625 +36388 -0.243438720703125 +36389 -0.445709228515625 +36390 -0.281005859375 +36391 -0.535064697265625 +36392 -0.3187255859375 +36393 -0.629058837890625 +36394 -0.34320068359375 +36395 -0.697601318359375 +36396 -0.338104248046875 +36397 -0.70391845703125 +36398 -0.301361083984375 +36399 -0.6424560546875 +36400 -0.223480224609375 +36401 -0.491241455078125 +36402 -0.111968994140625 +36403 -0.265716552734375 +36404 0.00628662109375 +36405 -0.023712158203125 +36406 0.115814208984375 +36407 0.201751708984375 +36408 0.200408935546875 +36409 0.375823974609375 +36410 0.253692626953125 +36411 0.485076904296875 +36412 0.293487548828125 +36413 0.56884765625 +36414 0.323272705078125 +36415 0.634765625 +36416 0.322479248046875 +36417 0.63763427734375 +36418 0.28607177734375 +36419 0.5660400390625 +36420 0.238037109375 +36421 0.4720458984375 +36422 0.202056884765625 +36423 0.40692138671875 +36424 0.181793212890625 +36425 0.3778076171875 +36426 0.174102783203125 +36427 0.376953125 +36428 0.16461181640625 +36429 0.371978759765625 +36430 0.13104248046875 +36431 0.313140869140625 +36432 0.06640625 +36433 0.184417724609375 +36434 -0.017364501953125 +36435 0.011199951171875 +36436 -0.103851318359375 +36437 -0.171051025390625 +36438 -0.181549072265625 +36439 -0.33740234375 +36440 -0.2431640625 +36441 -0.47198486328125 +36442 -0.28216552734375 +36443 -0.560394287109375 +36444 -0.28863525390625 +36445 -0.58056640625 +36446 -0.26959228515625 +36447 -0.54754638671875 +36448 -0.24688720703125 +36449 -0.508575439453125 +36450 -0.2188720703125 +36451 -0.459503173828125 +36452 -0.18316650390625 +36453 -0.394378662109375 +36454 -0.1580810546875 +36455 -0.35260009765625 +36456 -0.133697509765625 +36457 -0.31170654296875 +36458 -0.076446533203125 +36459 -0.197418212890625 +36460 0.014190673828125 +36461 -0.007965087890625 +36462 0.115570068359375 +36463 0.207489013671875 +36464 0.20941162109375 +36465 0.409210205078125 +36466 0.28424072265625 +36467 0.57208251953125 +36468 0.326324462890625 +36469 0.66595458984375 +36470 0.321075439453125 +36471 0.65875244140625 +36472 0.276397705078125 +36473 0.56744384765625 +36474 0.210418701171875 +36475 0.431396484375 +36476 0.143402099609375 +36477 0.29443359375 +36478 0.08740234375 +36479 0.182464599609375 +36480 0.028228759765625 +36481 0.06365966796875 +36482 -0.040252685546875 +36483 -0.075958251953125 +36484 -0.096343994140625 +36485 -0.189422607421875 +36486 -0.13763427734375 +36487 -0.271942138671875 +36488 -0.172607421875 +36489 -0.342529296875 +36490 -0.18426513671875 +36491 -0.364166259765625 +36492 -0.16815185546875 +36493 -0.327239990234375 +36494 -0.1448974609375 +36495 -0.2769775390625 +36496 -0.1329345703125 +36497 -0.253692626953125 +36498 -0.1260986328125 +36499 -0.24365234375 +36500 -0.102447509765625 +36501 -0.1983642578125 +36502 -0.061431884765625 +36503 -0.116241455078125 +36504 -0.021270751953125 +36505 -0.036834716796875 +36506 0.0155029296875 +36507 0.034881591796875 +36508 0.045166015625 +36509 0.09124755859375 +36510 0.056884765625 +36511 0.10888671875 +36512 0.067657470703125 +36513 0.125518798828125 +36514 0.084869384765625 +36515 0.15771484375 +36516 0.095977783203125 +36517 0.17828369140625 +36518 0.09356689453125 +36519 0.17108154296875 +36520 0.0748291015625 +36521 0.129974365234375 +36522 0.05230712890625 +36523 0.082427978515625 +36524 0.025726318359375 +36525 0.027679443359375 +36526 -0.019073486328125 +36527 -0.065643310546875 +36528 -0.064544677734375 +36529 -0.15936279296875 +36530 -0.09210205078125 +36531 -0.21307373046875 +36532 -0.105194091796875 +36533 -0.234649658203125 +36534 -0.092742919921875 +36535 -0.2001953125 +36536 -0.058868408203125 +36537 -0.119171142578125 +36538 -0.0185546875 +36539 -0.024749755859375 +36540 0.029571533203125 +36541 0.085784912109375 +36542 0.069976806640625 +36543 0.178131103515625 +36544 0.08599853515625 +36545 0.215576171875 +36546 0.083770751953125 +36547 0.211456298828125 +36548 0.067596435546875 +36549 0.17523193359375 +36550 0.047393798828125 +36551 0.128753662109375 +36552 0.0367431640625 +36553 0.1019287109375 +36554 0.0262451171875 +36555 0.0743408203125 +36556 0.0145263671875 +36557 0.04327392578125 +36558 0.014862060546875 +36559 0.038177490234375 +36560 0.034942626953125 +36561 0.076263427734375 +36562 0.067108154296875 +36563 0.14105224609375 +36564 0.090179443359375 +36565 0.186431884765625 +36566 0.093292236328125 +36567 0.188812255859375 +36568 0.0721435546875 +36569 0.1390380859375 +36570 0.028839111328125 +36571 0.041778564453125 +36572 -0.025909423828125 +36573 -0.079437255859375 +36574 -0.08978271484375 +36575 -0.219390869140625 +36576 -0.158050537109375 +36577 -0.367828369140625 +36578 -0.217041015625 +36579 -0.494873046875 +36580 -0.246490478515625 +36581 -0.556243896484375 +36582 -0.226593017578125 +36583 -0.508697509765625 +36584 -0.16790771484375 +36585 -0.3756103515625 +36586 -0.09857177734375 +36587 -0.218902587890625 +36588 -0.029937744140625 +36589 -0.063751220703125 +36590 0.038848876953125 +36591 0.091552734375 +36592 0.102874755859375 +36593 0.23602294921875 +36594 0.150115966796875 +36595 0.342987060546875 +36596 0.17279052734375 +36597 0.39520263671875 +36598 0.16943359375 +36599 0.389373779296875 +36600 0.1395263671875 +36601 0.324249267578125 +36602 0.0941162109375 +36603 0.224090576171875 +36604 0.04931640625 +36605 0.124267578125 +36606 0.010650634765625 +36607 0.037078857421875 +36608 -0.0098876953125 +36609 -0.010101318359375 +36610 -0.013153076171875 +36611 -0.019439697265625 +36612 -0.01312255859375 +36613 -0.022796630859375 +36614 -0.002197265625 +36615 -0.001556396484375 +36616 0.024444580078125 +36617 0.056304931640625 +36618 0.047821044921875 +36619 0.106719970703125 +36620 0.04541015625 +36621 0.096893310546875 +36622 0.0238037109375 +36623 0.042694091796875 +36624 -0.00103759765625 +36625 -0.018035888671875 +36626 -0.025146484375 +36627 -0.07586669921875 +36628 -0.043701171875 +36629 -0.11944580078125 +36630 -0.06134033203125 +36631 -0.15972900390625 +36632 -0.080474853515625 +36633 -0.202606201171875 +36634 -0.1011962890625 +36635 -0.24859619140625 +36636 -0.126617431640625 +36637 -0.30517578125 +36638 -0.152313232421875 +36639 -0.36212158203125 +36640 -0.16632080078125 +36641 -0.39141845703125 +36642 -0.15252685546875 +36643 -0.35528564453125 +36644 -0.1092529296875 +36645 -0.249969482421875 +36646 -0.043792724609375 +36647 -0.092864990234375 +36648 0.032470703125 +36649 0.08905029296875 +36650 0.093902587890625 +36651 0.2352294921875 +36652 0.129150390625 +36653 0.318817138671875 +36654 0.14617919921875 +36655 0.358642578125 +36656 0.14202880859375 +36657 0.347747802734375 +36658 0.116424560546875 +36659 0.28564453125 +36660 0.090911865234375 +36661 0.223175048828125 +36662 0.080841064453125 +36663 0.196746826171875 +36664 0.074920654296875 +36665 0.179840087890625 +36666 0.06591796875 +36667 0.155548095703125 +36668 0.065338134765625 +36669 0.151214599609375 +36670 0.068939208984375 +36671 0.156951904296875 +36672 0.05926513671875 +36673 0.13177490234375 +36674 0.046905517578125 +36675 0.100799560546875 +36676 0.0416259765625 +36677 0.087127685546875 +36678 0.0281982421875 +36679 0.05487060546875 +36680 0.001068115234375 +36681 -0.009002685546875 +36682 -0.03948974609375 +36683 -0.10400390625 +36684 -0.093170166015625 +36685 -0.229400634765625 +36686 -0.1473388671875 +36687 -0.35552978515625 +36688 -0.184783935546875 +36689 -0.441925048828125 +36690 -0.199249267578125 +36691 -0.473846435546875 +36692 -0.1964111328125 +36693 -0.464813232421875 +36694 -0.178009033203125 +36695 -0.419097900390625 +36696 -0.142974853515625 +36697 -0.334320068359375 +36698 -0.098663330078125 +36699 -0.227935791015625 +36700 -0.055023193359375 +36701 -0.12347412109375 +36702 -0.014862060546875 +36703 -0.02764892578125 +36704 0.029541015625 +36705 0.077667236328125 +36706 0.08697509765625 +36707 0.2132568359375 +36708 0.16156005859375 +36709 0.38885498046875 +36710 0.24407958984375 +36711 0.582794189453125 +36712 0.30865478515625 +36713 0.734039306640625 +36714 0.337249755859375 +36715 0.800140380859375 +36716 0.328643798828125 +36717 0.7783203125 +36718 0.2813720703125 +36719 0.6651611328125 +36720 0.194976806640625 +36721 0.45965576171875 +36722 0.08526611328125 +36723 0.199188232421875 +36724 -0.019989013671875 +36725 -0.050689697265625 +36726 -0.096649169921875 +36727 -0.23297119140625 +36728 -0.1373291015625 +36729 -0.33013916015625 +36730 -0.1531982421875 +36731 -0.368408203125 +36732 -0.157440185546875 +36733 -0.378936767578125 +36734 -0.15655517578125 +36735 -0.376983642578125 +36736 -0.1578369140625 +36737 -0.37969970703125 +36738 -0.16314697265625 +36739 -0.391510009765625 +36740 -0.160980224609375 +36741 -0.385345458984375 +36742 -0.143096923828125 +36743 -0.3419189453125 +36744 -0.118682861328125 +36745 -0.28289794921875 +36746 -0.1060791015625 +36747 -0.251617431640625 +36748 -0.112884521484375 +36749 -0.266143798828125 +36750 -0.116546630859375 +36751 -0.273345947265625 +36752 -0.093109130859375 +36753 -0.216796875 +36754 -0.055999755859375 +36755 -0.128265380859375 +36756 -0.03082275390625 +36757 -0.068145751953125 +36758 -0.0203857421875 +36759 -0.0430908203125 +36760 -0.01251220703125 +36761 -0.024444580078125 +36762 0.006744384765625 +36763 0.020721435546875 +36764 0.050933837890625 +36765 0.124481201171875 +36766 0.1077880859375 +36767 0.25787353515625 +36768 0.159576416015625 +36769 0.379119873046875 +36770 0.2027587890625 +36771 0.47991943359375 +36772 0.22369384765625 +36773 0.5281982421875 +36774 0.2169189453125 +36775 0.511138916015625 +36776 0.194061279296875 +36777 0.456207275390625 +36778 0.17376708984375 +36779 0.407470703125 +36780 0.16400146484375 +36781 0.383758544921875 +36782 0.152801513671875 +36783 0.35687255859375 +36784 0.1337890625 +36785 0.31182861328125 +36786 0.107940673828125 +36787 0.250885009765625 +36788 0.071624755859375 +36789 0.1654052734375 +36790 0.016265869140625 +36791 0.035247802734375 +36792 -0.059112548828125 +36793 -0.142059326171875 +36794 -0.141448974609375 +36795 -0.33563232421875 +36796 -0.226043701171875 +36797 -0.5345458984375 +36798 -0.30572509765625 +36799 -0.72186279296875 +36800 -0.3546142578125 +36801 -0.836669921875 +36802 -0.353118896484375 +36803 -0.8326416015625 +36804 -0.309600830078125 +36805 -0.7296142578125 +36806 -0.247406005859375 +36807 -0.582550048828125 +36808 -0.1871337890625 +36809 -0.440093994140625 +36810 -0.13812255859375 +36811 -0.324310302734375 +36812 -0.0860595703125 +36813 -0.20147705078125 +36814 -0.01953125 +36815 -0.044647216796875 +36816 0.0435791015625 +36817 0.103973388671875 +36818 0.085418701171875 +36819 0.202392578125 +36820 0.11187744140625 +36821 0.264495849609375 +36822 0.1435546875 +36823 0.338897705078125 +36824 0.18817138671875 +36825 0.443817138671875 +36826 0.231231689453125 +36827 0.545074462890625 +36828 0.261962890625 +36829 0.6173095703125 +36830 0.2769775390625 +36831 0.6524658203125 +36832 0.28167724609375 +36833 0.66339111328125 +36834 0.27862548828125 +36835 0.6561279296875 +36836 0.2576904296875 +36837 0.606781005859375 +36838 0.212860107421875 +36839 0.501190185546875 +36840 0.14984130859375 +36841 0.352783203125 +36842 0.07501220703125 +36843 0.176544189453125 +36844 -0.014678955078125 +36845 -0.034820556640625 +36846 -0.10943603515625 +36847 -0.258209228515625 +36848 -0.18756103515625 +36849 -0.44244384765625 +36850 -0.243865966796875 +36851 -0.5753173828125 +36852 -0.2763671875 +36853 -0.65203857421875 +36854 -0.271942138671875 +36855 -0.641632080078125 +36856 -0.23822021484375 +36857 -0.562164306640625 +36858 -0.194061279296875 +36859 -0.458038330078125 +36860 -0.148468017578125 +36861 -0.350555419921875 +36862 -0.110260009765625 +36863 -0.260528564453125 +36864 -0.081024169921875 +36865 -0.192108154296875 +36866 -0.059295654296875 +36867 -0.141937255859375 +36868 -0.042022705078125 +36869 -0.1021728515625 +36870 -0.025115966796875 +36871 -0.062896728515625 +36872 -0.00372314453125 +36873 -0.011932373046875 +36874 0.026947021484375 +36875 0.062835693359375 +36876 0.06195068359375 +36877 0.148712158203125 +36878 0.099700927734375 +36879 0.241729736328125 +36880 0.1429443359375 +36881 0.34912109375 +36882 0.186309814453125 +36883 0.457305908203125 +36884 0.220947265625 +36885 0.54388427734375 +36886 0.23272705078125 +36887 0.5728759765625 +36888 0.206787109375 +36889 0.506591796875 +36890 0.14556884765625 +36891 0.351226806640625 +36892 0.06463623046875 +36893 0.146514892578125 +36894 -0.01544189453125 +36895 -0.05523681640625 +36896 -0.079833984375 +36897 -0.21624755859375 +36898 -0.1278076171875 +36899 -0.334930419921875 +36900 -0.156036376953125 +36901 -0.402984619140625 +36902 -0.172637939453125 +36903 -0.4412841796875 +36904 -0.195556640625 +36905 -0.49578857421875 +36906 -0.22222900390625 +36907 -0.5601806640625 +36908 -0.2393798828125 +36909 -0.600738525390625 +36910 -0.233917236328125 +36911 -0.584228515625 +36912 -0.1934814453125 +36913 -0.47930908203125 +36914 -0.115478515625 +36915 -0.27935791015625 +36916 -0.009490966796875 +36917 -0.0089111328125 +36918 0.09967041015625 +36919 0.268798828125 +36920 0.18414306640625 +36921 0.482818603515625 +36922 0.23236083984375 +36923 0.60369873046875 +36924 0.251708984375 +36925 0.650421142578125 +36926 0.258209228515625 +36927 0.66400146484375 +36928 0.250640869140625 +36929 0.6414794921875 +36930 0.224884033203125 +36931 0.572540283203125 +36932 0.196929931640625 +36933 0.498138427734375 +36934 0.175018310546875 +36935 0.439453125 +36936 0.15087890625 +36937 0.375518798828125 +36938 0.11199951171875 +36939 0.274505615234375 +36940 0.0474853515625 +36941 0.1087646484375 +36942 -0.033935546875 +36943 -0.099395751953125 +36944 -0.11981201171875 +36945 -0.3182373046875 +36946 -0.210601806640625 +36947 -0.5489501953125 +36948 -0.299285888671875 +36949 -0.7738037109375 +36950 -0.365081787109375 +36951 -0.86383056640625 +36952 -0.394927978515625 +36953 -0.870391845703125 +36954 -0.395721435546875 +36955 -0.86895751953125 +36956 -0.37255859375 +36957 -0.861053466796875 +36958 -0.318603515625 +36959 -0.765869140625 +36960 -0.229400634765625 +36961 -0.5301513671875 +36962 -0.107666015625 +36963 -0.214691162109375 +36964 0.029754638671875 +36965 0.137359619140625 +36966 0.162750244140625 +36967 0.474822998046875 +36968 0.277435302734375 +36969 0.76239013671875 +36970 0.36322021484375 +36971 0.867462158203125 +36972 0.420318603515625 +36973 0.870361328125 +36974 0.44415283203125 +36975 0.86480712890625 +36976 0.436798095703125 +36977 0.831817626953125 +36978 0.40777587890625 +36979 0.677581787109375 +36980 0.35931396484375 +36981 0.495880126953125 +36982 0.29864501953125 +36983 0.30767822265625 +36984 0.22662353515625 +36985 0.116180419921875 +36986 0.130767822265625 +36987 -0.110748291015625 +36988 0.008331298828125 +36989 -0.381805419921875 +36990 -0.123931884765625 +36991 -0.6572265625 +36992 -0.242584228515625 +36993 -0.857421875 +36994 -0.330810546875 +36995 -0.870391845703125 +36996 -0.385833740234375 +36997 -0.870391845703125 +36998 -0.418182373046875 +36999 -0.86444091796875 +37000 -0.441864013671875 +37001 -0.85723876953125 +37002 -0.449676513671875 +37003 -0.790008544921875 +37004 -0.420318603515625 +37005 -0.62847900390625 +37006 -0.352508544921875 +37007 -0.3956298828125 +37008 -0.25909423828125 +37009 -0.126708984375 +37010 -0.150787353515625 +37011 0.150115966796875 +37012 -0.03216552734375 +37013 0.424041748046875 +37014 0.086212158203125 +37015 0.670623779296875 +37016 0.189178466796875 +37017 0.854522705078125 +37018 0.26983642578125 +37019 0.866485595703125 +37020 0.32220458984375 +37021 0.86920166015625 +37022 0.3533935546875 +37023 0.8653564453125 +37024 0.36865234375 +37025 0.857147216796875 +37026 0.366851806640625 +37027 0.766845703125 +37028 0.3499755859375 +37029 0.628509521484375 +37030 0.31536865234375 +37031 0.462127685546875 +37032 0.27313232421875 +37033 0.297210693359375 +37034 0.228118896484375 +37035 0.14862060546875 +37036 0.171356201171875 +37037 -0.00537109375 +37038 0.105712890625 +37039 -0.15753173828125 +37040 0.02978515625 +37041 -0.31304931640625 +37042 -0.061920166015625 +37043 -0.48876953125 +37044 -0.151031494140625 +37045 -0.6416015625 +37046 -0.227874755859375 +37047 -0.751373291015625 +37048 -0.301513671875 +37049 -0.84619140625 +37050 -0.366180419921875 +37051 -0.861297607421875 +37052 -0.408843994140625 +37053 -0.863250732421875 +37054 -0.4171142578125 +37055 -0.856597900390625 +37056 -0.395751953125 +37057 -0.7498779296875 +37058 -0.367431640625 +37059 -0.624542236328125 +37060 -0.32354736328125 +37061 -0.47808837890625 +37062 -0.24114990234375 +37063 -0.253387451171875 +37064 -0.13812255859375 +37065 0.003692626953125 +37066 -0.041259765625 +37067 0.2257080078125 +37068 0.0543212890625 +37069 0.427154541015625 +37070 0.16131591796875 +37071 0.643218994140625 +37072 0.27593994140625 +37073 0.855926513671875 +37074 0.375457763671875 +37075 0.870361328125 +37076 0.440399169921875 +37077 0.870361328125 +37078 0.473602294921875 +37079 0.862762451171875 +37080 0.473907470703125 +37081 0.79669189453125 +37082 0.437591552734375 +37083 0.595794677734375 +37084 0.376129150390625 +37085 0.362152099609375 +37086 0.300506591796875 +37087 0.1270751953125 +37088 0.218994140625 +37089 -0.086944580078125 +37090 0.132415771484375 +37091 -0.2784423828125 +37092 0.02716064453125 +37093 -0.484832763671875 +37094 -0.104248046875 +37095 -0.729583740234375 +37096 -0.241943359375 +37097 -0.86688232421875 +37098 -0.361114501953125 +37099 -0.870391845703125 +37100 -0.459747314453125 +37101 -0.86859130859375 +37102 -0.537017822265625 +37103 -0.86279296875 +37104 -0.578765869140625 +37105 -0.817962646484375 +37106 -0.567169189453125 +37107 -0.6116943359375 +37108 -0.49945068359375 +37109 -0.3128662109375 +37110 -0.3887939453125 +37111 0.039398193359375 +37112 -0.243072509765625 +37113 0.422821044921875 +37114 -0.075347900390625 +37115 0.805145263671875 +37116 0.087615966796875 +37117 0.870361328125 +37118 0.223419189453125 +37119 0.870361328125 +37120 0.327178955078125 +37121 0.860015869140625 +37122 0.396270751953125 +37123 0.727935791015625 +37124 0.428741455078125 +37125 0.48114013671875 +37126 0.43328857421875 +37127 0.2059326171875 +37128 0.41815185546875 +37129 -0.06103515625 +37130 0.387054443359375 +37131 -0.29913330078125 +37132 0.335052490234375 +37133 -0.516204833984375 +37134 0.256927490234375 +37135 -0.7252197265625 +37136 0.16204833984375 +37137 -0.85980224609375 +37138 0.063232421875 +37139 -0.870391845703125 +37140 -0.0283203125 +37141 -0.870391845703125 +37142 -0.094573974609375 +37143 -0.858062744140625 +37144 -0.13348388671875 +37145 -0.673004150390625 +37146 -0.163421630859375 +37147 -0.42694091796875 +37148 -0.19989013671875 +37149 -0.2100830078125 +37150 -0.241729736328125 +37151 -0.0362548828125 +37152 -0.278167724609375 +37153 0.10943603515625 +37154 -0.3018798828125 +37155 0.23516845703125 +37156 -0.297882080078125 +37157 0.373687744140625 +37158 -0.2669677734375 +37159 0.517791748046875 +37160 -0.23199462890625 +37161 0.602783203125 +37162 -0.191375732421875 +37163 0.635711669921875 +37164 -0.133514404296875 +37165 0.655181884765625 +37166 -0.062408447265625 +37167 0.65948486328125 +37168 0.018524169921875 +37169 0.651275634765625 +37170 0.099945068359375 +37171 0.61846923828125 +37172 0.16802978515625 +37173 0.53753662109375 +37174 0.2158203125 +37175 0.404144287109375 +37176 0.239410400390625 +37177 0.22186279296875 +37178 0.23895263671875 +37179 0.003997802734375 +37180 0.220733642578125 +37181 -0.22100830078125 +37182 0.19207763671875 +37183 -0.42449951171875 +37184 0.160675048828125 +37185 -0.579833984375 +37186 0.141998291015625 +37187 -0.641876220703125 +37188 0.133880615234375 +37189 -0.6177978515625 +37190 0.113372802734375 +37191 -0.575531005859375 +37192 0.078887939453125 +37193 -0.526336669921875 +37194 0.049530029296875 +37195 -0.42645263671875 +37196 0.03558349609375 +37197 -0.2581787109375 +37198 0.0244140625 +37199 -0.068695068359375 +37200 0.0025634765625 +37201 0.09222412109375 +37202 -0.022857666015625 +37203 0.232147216796875 +37204 -0.047882080078125 +37205 0.3509521484375 +37206 -0.082916259765625 +37207 0.410064697265625 +37208 -0.138397216796875 +37209 0.372955322265625 +37210 -0.206695556640625 +37211 0.2554931640625 +37212 -0.269073486328125 +37213 0.10711669921875 +37214 -0.31854248046875 +37215 -0.052886962890625 +37216 -0.34228515625 +37217 -0.186279296875 +37218 -0.320465087890625 +37219 -0.23291015625 +37220 -0.2615966796875 +37221 -0.209442138671875 +37222 -0.18975830078125 +37223 -0.174163818359375 +37224 -0.108306884765625 +37225 -0.126739501953125 +37226 -0.014068603515625 +37227 -0.048126220703125 +37228 0.082427978515625 +37229 0.0426025390625 +37230 0.16412353515625 +37231 0.10748291015625 +37232 0.22601318359375 +37233 0.1409912109375 +37234 0.285003662109375 +37235 0.19708251953125 +37236 0.33856201171875 +37237 0.273651123046875 +37238 0.3665771484375 +37239 0.31768798828125 +37240 0.373077392578125 +37241 0.341094970703125 +37242 0.367279052734375 +37243 0.368011474609375 +37244 0.341064453125 +37245 0.37249755859375 +37246 0.276885986328125 +37247 0.30072021484375 +37248 0.17681884765625 +37249 0.1517333984375 +37250 0.06512451171875 +37251 -0.01470947265625 +37252 -0.051483154296875 +37253 -0.1883544921875 +37254 -0.171234130859375 +37255 -0.372711181640625 +37256 -0.27191162109375 +37257 -0.51397705078125 +37258 -0.336334228515625 +37259 -0.57177734375 +37260 -0.35992431640625 +37261 -0.53948974609375 +37262 -0.347503662109375 +37263 -0.43511962890625 +37264 -0.311553955078125 +37265 -0.2962646484375 +37266 -0.265350341796875 +37267 -0.161102294921875 +37268 -0.214080810546875 +37269 -0.0435791015625 +37270 -0.1571044921875 +37271 0.060394287109375 +37272 -0.10089111328125 +37273 0.13665771484375 +37274 -0.052703857421875 +37275 0.170135498046875 +37276 -0.013031005859375 +37277 0.16552734375 +37278 0.028106689453125 +37279 0.15728759765625 +37280 0.070159912109375 +37281 0.150787353515625 +37282 0.10205078125 +37283 0.12200927734375 +37284 0.124847412109375 +37285 0.080108642578125 +37286 0.146026611328125 +37287 0.05126953125 +37288 0.173919677734375 +37289 0.062896728515625 +37290 0.199432373046875 +37291 0.09271240234375 +37292 0.204864501953125 +37293 0.092987060546875 +37294 0.19549560546875 +37295 0.07855224609375 +37296 0.17718505859375 +37297 0.06427001953125 +37298 0.1453857421875 +37299 0.0347900390625 +37300 0.100799560546875 +37301 -0.01171875 +37302 0.05206298828125 +37303 -0.056060791015625 +37304 0.0164794921875 +37305 -0.055511474609375 +37306 -0.003997802734375 +37307 -0.010467529296875 +37308 -0.02679443359375 +37309 0.02508544921875 +37310 -0.059173583984375 +37311 0.025665283203125 +37312 -0.090057373046875 +37313 0.017333984375 +37314 -0.117431640625 +37315 0.00189208984375 +37316 -0.144256591796875 +37317 -0.03173828125 +37318 -0.165618896484375 +37319 -0.071502685546875 +37320 -0.187835693359375 +37321 -0.13543701171875 +37322 -0.20989990234375 +37323 -0.219970703125 +37324 -0.223602294921875 +37325 -0.300506591796875 +37326 -0.229736328125 +37327 -0.376312255859375 +37328 -0.21832275390625 +37329 -0.416107177734375 +37330 -0.173370361328125 +37331 -0.371124267578125 +37332 -0.09686279296875 +37333 -0.242279052734375 +37334 -0.00494384765625 +37335 -0.069732666015625 +37336 0.09320068359375 +37337 0.125640869140625 +37338 0.1849365234375 +37339 0.31268310546875 +37340 0.25592041015625 +37341 0.45501708984375 +37342 0.30596923828125 +37343 0.554779052734375 +37344 0.334014892578125 +37345 0.61065673828125 +37346 0.335601806640625 +37347 0.610931396484375 +37348 0.302154541015625 +37349 0.531463623046875 +37350 0.2398681640625 +37351 0.3883056640625 +37352 0.168670654296875 +37353 0.23468017578125 +37354 0.098480224609375 +37355 0.095245361328125 +37356 0.039825439453125 +37357 -0.00396728515625 +37358 -0.000732421875 +37359 -0.04852294921875 +37360 -0.027801513671875 +37361 -0.055145263671875 +37362 -0.05877685546875 +37363 -0.0758056640625 +37364 -0.1025390625 +37365 -0.138702392578125 +37366 -0.145538330078125 +37367 -0.209197998046875 +37368 -0.18756103515625 +37369 -0.289031982421875 +37370 -0.228240966796875 +37371 -0.37884521484375 +37372 -0.259185791015625 +37373 -0.456329345703125 +37374 -0.278594970703125 +37375 -0.51641845703125 +37376 -0.272552490234375 +37377 -0.519287109375 +37378 -0.23919677734375 +37379 -0.458251953125 +37380 -0.19744873046875 +37381 -0.384796142578125 +37382 -0.156951904296875 +37383 -0.323699951171875 +37384 -0.116851806640625 +37385 -0.269287109375 +37386 -0.06915283203125 +37387 -0.1951904296875 +37388 -0.014617919921875 +37389 -0.100006103515625 +37390 0.03619384765625 +37391 -0.01055908203125 +37392 0.092864990234375 +37393 0.1033935546875 +37394 0.15704345703125 +37395 0.24908447265625 +37396 0.20947265625 +37397 0.373199462890625 +37398 0.243621826171875 +37399 0.45806884765625 +37400 0.2620849609375 +37401 0.511474609375 +37402 0.276214599609375 +37403 0.565399169921875 +37404 0.283416748046875 +37405 0.61138916015625 +37406 0.263397216796875 +37407 0.5897216796875 +37408 0.213531494140625 +37409 0.4906005859375 +37410 0.140838623046875 +37411 0.33148193359375 +37412 0.058685302734375 +37413 0.147796630859375 +37414 -0.017333984375 +37415 -0.01873779296875 +37416 -0.07647705078125 +37417 -0.140289306640625 +37418 -0.10919189453125 +37419 -0.191986083984375 +37420 -0.118408203125 +37421 -0.184295654296875 +37422 -0.119140625 +37423 -0.161834716796875 +37424 -0.125732421875 +37425 -0.166595458984375 +37426 -0.136383056640625 +37427 -0.19390869140625 +37428 -0.144378662109375 +37429 -0.22442626953125 +37430 -0.15753173828125 +37431 -0.279754638671875 +37432 -0.1689453125 +37433 -0.3389892578125 +37434 -0.162506103515625 +37435 -0.3543701171875 +37436 -0.146728515625 +37437 -0.348175048828125 +37438 -0.124359130859375 +37439 -0.32598876953125 +37440 -0.085845947265625 +37441 -0.2581787109375 +37442 -0.030303955078125 +37443 -0.139801025390625 +37444 0.03643798828125 +37445 0.014617919921875 +37446 0.09246826171875 +37447 0.144378662109375 +37448 0.1273193359375 +37449 0.221038818359375 +37450 0.149749755859375 +37451 0.27069091796875 +37452 0.159820556640625 +37453 0.294036865234375 +37454 0.164764404296875 +37455 0.311767578125 +37456 0.170013427734375 +37457 0.339141845703125 +37458 0.1700439453125 +37459 0.360260009765625 +37460 0.16033935546875 +37461 0.360504150390625 +37462 0.131256103515625 +37463 0.308380126953125 +37464 0.076263427734375 +37465 0.18170166015625 +37466 0.00421142578125 +37467 0.0047607421875 +37468 -0.068695068359375 +37469 -0.17559814453125 +37470 -0.126922607421875 +37471 -0.3143310546875 +37472 -0.155487060546875 +37473 -0.36785888671875 +37474 -0.1624755859375 +37475 -0.36248779296875 +37476 -0.162322998046875 +37477 -0.343536376953125 +37478 -0.15179443359375 +37479 -0.3018798828125 +37480 -0.1287841796875 +37481 -0.231414794921875 +37482 -0.088653564453125 +37483 -0.117645263671875 +37484 -0.042266845703125 +37485 0.007049560546875 +37486 -0.0079345703125 +37487 0.087982177734375 +37488 0.018524169921875 +37489 0.13946533203125 +37490 0.04071044921875 +37491 0.17425537109375 +37492 0.056671142578125 +37493 0.188201904296875 +37494 0.06243896484375 +37495 0.171234130859375 +37496 0.0557861328125 +37497 0.118438720703125 +37498 0.045135498046875 +37499 0.05706787109375 +37500 0.030670166015625 +37501 -0.010711669921875 +37502 0.0098876953125 +37503 -0.0914306640625 +37504 -0.010009765625 +37505 -0.162322998046875 +37506 -0.019683837890625 +37507 -0.194549560546875 +37508 -0.00634765625 +37509 -0.1492919921875 +37510 0.031707763671875 +37511 -0.02166748046875 +37512 0.07366943359375 +37513 0.124053955078125 +37514 0.094757080078125 +37515 0.211151123046875 +37516 0.095703125 +37517 0.240447998046875 +37518 0.0869140625 +37519 0.242218017578125 +37520 0.072021484375 +37521 0.2257080078125 +37522 0.052642822265625 +37523 0.194366455078125 +37524 0.0185546875 +37525 0.115509033203125 +37526 -0.02203369140625 +37527 0.0128173828125 +37528 -0.04913330078125 +37529 -0.053802490234375 +37530 -0.07110595703125 +37531 -0.110626220703125 +37532 -0.101593017578125 +37533 -0.199493408203125 +37534 -0.13201904296875 +37535 -0.29437255859375 +37536 -0.14178466796875 +37537 -0.33221435546875 +37538 -0.120208740234375 +37539 -0.27972412109375 +37540 -0.08343505859375 +37541 -0.185333251953125 +37542 -0.05780029296875 +37543 -0.128204345703125 +37544 -0.046112060546875 +37545 -0.115692138671875 +37546 -0.038543701171875 +37547 -0.116455078125 +37548 -0.0274658203125 +37549 -0.105926513671875 +37550 -0.003387451171875 +37551 -0.053955078125 +37552 0.036346435546875 +37553 0.048797607421875 +37554 0.076690673828125 +37555 0.157318115234375 +37556 0.097869873046875 +37557 0.212005615234375 +37558 0.101593017578125 +37559 0.218475341796875 +37560 0.107696533203125 +37561 0.23724365234375 +37562 0.12835693359375 +37563 0.30535888671875 +37564 0.15008544921875 +37565 0.38128662109375 +37566 0.1531982421875 +37567 0.404449462890625 +37568 0.144439697265625 +37569 0.3944091796875 +37570 0.1363525390625 +37571 0.3885498046875 +37572 0.12139892578125 +37573 0.362640380859375 +37574 0.0858154296875 +37575 0.27362060546875 +37576 0.02850341796875 +37577 0.11712646484375 +37578 -0.033172607421875 +37579 -0.054901123046875 +37580 -0.082000732421875 +37581 -0.19085693359375 +37582 -0.11614990234375 +37583 -0.28570556640625 +37584 -0.13543701171875 +37585 -0.339263916015625 +37586 -0.148345947265625 +37587 -0.3775634765625 +37588 -0.169677734375 +37589 -0.445709228515625 +37590 -0.196685791015625 +37591 -0.535064697265625 +37592 -0.224090576171875 +37593 -0.629058837890625 +37594 -0.24224853515625 +37595 -0.697601318359375 +37596 -0.239349365234375 +37597 -0.70391845703125 +37598 -0.2138671875 +37599 -0.6424560546875 +37600 -0.158905029296875 +37601 -0.491241455078125 +37602 -0.079803466796875 +37603 -0.265716552734375 +37604 0.004119873046875 +37605 -0.023712158203125 +37606 0.081817626953125 +37607 0.201751708984375 +37608 0.141693115234375 +37609 0.375823974609375 +37610 0.179229736328125 +37611 0.485076904296875 +37612 0.207244873046875 +37613 0.56884765625 +37614 0.228271484375 +37615 0.634765625 +37616 0.227569580078125 +37617 0.63763427734375 +37618 0.201507568359375 +37619 0.5660400390625 +37620 0.16729736328125 +37621 0.4720458984375 +37622 0.1419677734375 +37623 0.40692138671875 +37624 0.12811279296875 +37625 0.3778076171875 +37626 0.1234130859375 +37627 0.376953125 +37628 0.11749267578125 +37629 0.371978759765625 +37630 0.09423828125 +37631 0.313140869140625 +37632 0.048828125 +37633 0.184417724609375 +37634 -0.009918212890625 +37635 0.011199951171875 +37636 -0.07049560546875 +37637 -0.171051025390625 +37638 -0.1251220703125 +37639 -0.33740234375 +37640 -0.168792724609375 +37641 -0.47198486328125 +37642 -0.19708251953125 +37643 -0.560394287109375 +37644 -0.203369140625 +37645 -0.58056640625 +37646 -0.192138671875 +37647 -0.54754638671875 +37648 -0.177490234375 +37649 -0.508575439453125 +37650 -0.158416748046875 +37651 -0.459503173828125 +37652 -0.133453369140625 +37653 -0.394378662109375 +37654 -0.114593505859375 +37655 -0.35260009765625 +37656 -0.0955810546875 +37657 -0.31170654296875 +37658 -0.0548095703125 +37659 -0.197418212890625 +37660 0.007843017578125 +37661 -0.007965087890625 +37662 0.077423095703125 +37663 0.207489013671875 +37664 0.141876220703125 +37665 0.409210205078125 +37666 0.193572998046875 +37667 0.57208251953125 +37668 0.223419189453125 +37669 0.66595458984375 +37670 0.22186279296875 +37671 0.65875244140625 +37672 0.193939208984375 +37673 0.56744384765625 +37674 0.1513671875 +37675 0.431396484375 +37676 0.1072998046875 +37677 0.29443359375 +37678 0.069610595703125 +37679 0.182464599609375 +37680 0.0291748046875 +37681 0.06365966796875 +37682 -0.017791748046875 +37683 -0.075958251953125 +37684 -0.057098388671875 +37685 -0.189422607421875 +37686 -0.087005615234375 +37687 -0.271942138671875 +37688 -0.112823486328125 +37689 -0.342529296875 +37690 -0.123382568359375 +37691 -0.364166259765625 +37692 -0.115631103515625 +37693 -0.327239990234375 +37694 -0.102813720703125 +37695 -0.2769775390625 +37696 -0.096771240234375 +37697 -0.253692626953125 +37698 -0.09344482421875 +37699 -0.24365234375 +37700 -0.0784912109375 +37701 -0.1983642578125 +37702 -0.051605224609375 +37703 -0.116241455078125 +37704 -0.02459716796875 +37705 -0.036834716796875 +37706 0.00079345703125 +37707 0.034881591796875 +37708 0.02203369140625 +37709 0.09124755859375 +37710 0.031982421875 +37711 0.10888671875 +37712 0.04150390625 +37713 0.125518798828125 +37714 0.055267333984375 +37715 0.15771484375 +37716 0.06500244140625 +37717 0.17828369140625 +37718 0.06573486328125 +37719 0.17108154296875 +37720 0.0555419921875 +37721 0.129974365234375 +37722 0.042449951171875 +37723 0.082427978515625 +37724 0.026214599609375 +37725 0.027679443359375 +37726 -0.00238037109375 +37727 -0.065643310546875 +37728 -0.031951904296875 +37729 -0.15936279296875 +37730 -0.0504150390625 +37731 -0.21307373046875 +37732 -0.059967041015625 +37733 -0.234649658203125 +37734 -0.0533447265625 +37735 -0.2001953125 +37736 -0.03314208984375 +37737 -0.119171142578125 +37738 -0.00897216796875 +37739 -0.024749755859375 +37740 0.0201416015625 +37741 0.085784912109375 +37742 0.04425048828125 +37743 0.178131103515625 +37744 0.052642822265625 +37745 0.215576171875 +37746 0.049407958984375 +37747 0.211456298828125 +37748 0.0374755859375 +37749 0.17523193359375 +37750 0.023345947265625 +37751 0.128753662109375 +37752 0.015869140625 +37753 0.1019287109375 +37754 0.00897216796875 +37755 0.0743408203125 +37756 0.001739501953125 +37757 0.04327392578125 +37758 0.002716064453125 +37759 0.038177490234375 +37760 0.016876220703125 +37761 0.076263427734375 +37762 0.039154052734375 +37763 0.14105224609375 +37764 0.05572509765625 +37765 0.186431884765625 +37766 0.0594482421875 +37767 0.188812255859375 +37768 0.047454833984375 +37769 0.1390380859375 +37770 0.02099609375 +37771 0.041778564453125 +37772 -0.0130615234375 +37773 -0.079437255859375 +37774 -0.053253173828125 +37775 -0.219390869140625 +37776 -0.0965576171875 +37777 -0.367828369140625 +37778 -0.134185791015625 +37779 -0.494873046875 +37780 -0.15301513671875 +37781 -0.556243896484375 +37782 -0.14019775390625 +37783 -0.508697509765625 +37784 -0.102569580078125 +37785 -0.3756103515625 +37786 -0.058349609375 +37787 -0.218902587890625 +37788 -0.014862060546875 +37789 -0.063751220703125 +37790 0.028472900390625 +37791 0.091552734375 +37792 0.068603515625 +37793 0.23602294921875 +37794 0.097747802734375 +37795 0.342987060546875 +37796 0.1109619140625 +37797 0.39520263671875 +37798 0.107391357421875 +37799 0.389373779296875 +37800 0.08673095703125 +37801 0.324249267578125 +37802 0.0562744140625 +37803 0.224090576171875 +37804 0.0264892578125 +37805 0.124267578125 +37806 0.001007080078125 +37807 0.037078857421875 +37808 -0.0120849609375 +37809 -0.010101318359375 +37810 -0.01348876953125 +37811 -0.019439697265625 +37812 -0.012725830078125 +37813 -0.022796630859375 +37814 -0.004364013671875 +37815 -0.001556396484375 +37816 0.014984130859375 +37817 0.056304931640625 +37818 0.032135009765625 +37819 0.106719970703125 +37820 0.031341552734375 +37821 0.096893310546875 +37822 0.017242431640625 +37823 0.042694091796875 +37824 0.000885009765625 +37825 -0.018035888671875 +37826 -0.01495361328125 +37827 -0.07586669921875 +37828 -0.027008056640625 +37829 -0.11944580078125 +37830 -0.038543701171875 +37831 -0.15972900390625 +37832 -0.05133056640625 +37833 -0.202606201171875 +37834 -0.065460205078125 +37835 -0.24859619140625 +37836 -0.083099365234375 +37837 -0.30517578125 +37838 -0.1011962890625 +37839 -0.36212158203125 +37840 -0.11138916015625 +37841 -0.39141845703125 +37842 -0.102386474609375 +37843 -0.35528564453125 +37844 -0.072998046875 +37845 -0.249969482421875 +37846 -0.028289794921875 +37847 -0.092864990234375 +37848 0.02386474609375 +37849 0.08905029296875 +37850 0.06561279296875 +37851 0.2352294921875 +37852 0.089080810546875 +37853 0.318817138671875 +37854 0.099945068359375 +37855 0.358642578125 +37856 0.096160888671875 +37857 0.347747802734375 +37858 0.077606201171875 +37859 0.28564453125 +37860 0.059326171875 +37861 0.223175048828125 +37862 0.05206298828125 +37863 0.196746826171875 +37864 0.047943115234375 +37865 0.179840087890625 +37866 0.041900634765625 +37867 0.155548095703125 +37868 0.041961669921875 +37869 0.151214599609375 +37870 0.045135498046875 +37871 0.156951904296875 +37872 0.0391845703125 +37873 0.13177490234375 +37874 0.031463623046875 +37875 0.100799560546875 +37876 0.028717041015625 +37877 0.087127685546875 +37878 0.020263671875 +37879 0.05487060546875 +37880 0.002197265625 +37881 -0.009002685546875 +37882 -0.025360107421875 +37883 -0.10400390625 +37884 -0.06219482421875 +37885 -0.229400634765625 +37886 -0.099517822265625 +37887 -0.35552978515625 +37888 -0.12518310546875 +37889 -0.441925048828125 +37890 -0.13446044921875 +37891 -0.473846435546875 +37892 -0.1312255859375 +37893 -0.464813232421875 +37894 -0.117156982421875 +37895 -0.419097900390625 +37896 -0.092132568359375 +37897 -0.334320068359375 +37898 -0.061126708984375 +37899 -0.227935791015625 +37900 -0.030731201171875 +37901 -0.12347412109375 +37902 -0.0029296875 +37903 -0.02764892578125 +37904 0.02685546875 +37905 0.077667236328125 +37906 0.06396484375 +37907 0.2132568359375 +37908 0.110931396484375 +37909 0.38885498046875 +37910 0.16204833984375 +37911 0.582794189453125 +37912 0.201263427734375 +37913 0.734039306640625 +37914 0.21746826171875 +37915 0.800140380859375 +37916 0.210052490234375 +37917 0.7783203125 +37918 0.17822265625 +37919 0.6651611328125 +37920 0.12188720703125 +37921 0.45965576171875 +37922 0.051055908203125 +37923 0.199188232421875 +37924 -0.016815185546875 +37925 -0.050689697265625 +37926 -0.066558837890625 +37927 -0.23297119140625 +37928 -0.093475341796875 +37929 -0.33013916015625 +37930 -0.10443115234375 +37931 -0.368408203125 +37932 -0.10760498046875 +37933 -0.378936767578125 +37934 -0.1070556640625 +37935 -0.376983642578125 +37936 -0.1072998046875 +37937 -0.37969970703125 +37938 -0.10955810546875 +37939 -0.391510009765625 +37940 -0.106719970703125 +37941 -0.385345458984375 +37942 -0.093780517578125 +37943 -0.3419189453125 +37944 -0.0765380859375 +37945 -0.28289794921875 +37946 -0.0665283203125 +37947 -0.251617431640625 +37948 -0.068634033203125 +37949 -0.266143798828125 +37950 -0.068939208984375 +37951 -0.273345947265625 +37952 -0.0526123046875 +37953 -0.216796875 +37954 -0.028106689453125 +37955 -0.128265380859375 +37956 -0.01141357421875 +37957 -0.068145751953125 +37958 -0.00433349609375 +37959 -0.0430908203125 +37960 0.000640869140625 +37961 -0.024444580078125 +37962 0.012237548828125 +37963 0.020721435546875 +37964 0.0389404296875 +37965 0.124481201171875 +37966 0.073150634765625 +37967 0.25787353515625 +37968 0.103912353515625 +37969 0.379119873046875 +37970 0.129119873046875 +37971 0.47991943359375 +37972 0.140380859375 +37973 0.5281982421875 +37974 0.134368896484375 +37975 0.511138916015625 +37976 0.118438720703125 +37977 0.456207275390625 +37978 0.10430908203125 +37979 0.407470703125 +37980 0.097015380859375 +37981 0.383758544921875 +37982 0.089111328125 +37983 0.35687255859375 +37984 0.076690673828125 +37985 0.31182861328125 +37986 0.060394287109375 +37987 0.250885009765625 +37988 0.037933349609375 +37989 0.1654052734375 +37990 0.003997802734375 +37991 0.035247802734375 +37992 -0.042083740234375 +37993 -0.142059326171875 +37994 -0.092193603515625 +37995 -0.33563232421875 +37996 -0.143524169921875 +37997 -0.5345458984375 +37998 -0.191680908203125 +37999 -0.72186279296875 +38000 -0.220611572265625 +38001 -0.836669921875 +38002 -0.218170166015625 +38003 -0.8326416015625 +38004 -0.189697265625 +38005 -0.7296142578125 +38006 -0.149810791015625 +38007 -0.582550048828125 +38008 -0.11138916015625 +38009 -0.440093994140625 +38010 -0.080291748046875 +38011 -0.324310302734375 +38012 -0.047607421875 +38013 -0.20147705078125 +38014 -0.006195068359375 +38015 -0.044647216796875 +38016 0.03277587890625 +38017 0.103973388671875 +38018 0.0582275390625 +38019 0.202392578125 +38020 0.0738525390625 +38021 0.264495849609375 +38022 0.092498779296875 +38023 0.338897705078125 +38024 0.11907958984375 +38025 0.443817138671875 +38026 0.14459228515625 +38027 0.545074462890625 +38028 0.162445068359375 +38029 0.6173095703125 +38030 0.170562744140625 +38031 0.6524658203125 +38032 0.17242431640625 +38033 0.66339111328125 +38034 0.169677734375 +38035 0.6561279296875 +38036 0.156005859375 +38037 0.606781005859375 +38038 0.127685546875 +38039 0.501190185546875 +38040 0.08831787109375 +38041 0.352783203125 +38042 0.0418701171875 +38043 0.176544189453125 +38044 -0.0135498046875 +38045 -0.034820556640625 +38046 -0.071868896484375 +38047 -0.258209228515625 +38048 -0.11962890625 +38049 -0.44244384765625 +38050 -0.1536865234375 +38051 -0.5753173828125 +38052 -0.1728515625 +38053 -0.65203857421875 +38054 -0.16900634765625 +38055 -0.641632080078125 +38056 -0.14697265625 +38057 -0.562164306640625 +38058 -0.118499755859375 +38059 -0.458038330078125 +38060 -0.08929443359375 +38061 -0.350555419921875 +38062 -0.06488037109375 +38063 -0.260528564453125 +38064 -0.04638671875 +38065 -0.192108154296875 +38066 -0.032928466796875 +38067 -0.141937255859375 +38068 -0.0224609375 +38069 -0.1021728515625 +38070 -0.012359619140625 +38071 -0.062896728515625 +38072 0.0006103515625 +38073 -0.011932373046875 +38074 0.019683837890625 +38075 0.062835693359375 +38076 0.04156494140625 +38077 0.148712158203125 +38078 0.06524658203125 +38079 0.241729736328125 +38080 0.092681884765625 +38081 0.34912109375 +38082 0.120330810546875 +38083 0.457305908203125 +38084 0.142303466796875 +38085 0.54388427734375 +38086 0.149169921875 +38087 0.5728759765625 +38088 0.131011962890625 +38089 0.506591796875 +38090 0.089508056640625 +38091 0.351226806640625 +38092 0.035186767578125 +38093 0.146514892578125 +38094 -0.01812744140625 +38095 -0.05523681640625 +38096 -0.060455322265625 +38097 -0.21624755859375 +38098 -0.0914306640625 +38099 -0.334930419921875 +38100 -0.108856201171875 +38101 -0.402984619140625 +38102 -0.1182861328125 +38103 -0.4412841796875 +38104 -0.13189697265625 +38105 -0.49578857421875 +38106 -0.148040771484375 +38107 -0.5601806640625 +38108 -0.157867431640625 +38109 -0.600738525390625 +38110 -0.152679443359375 +38111 -0.584228515625 +38112 -0.124237060546875 +38113 -0.47930908203125 +38114 -0.070831298828125 +38115 -0.27935791015625 +38116 0.0009765625 +38117 -0.0089111328125 +38118 0.074493408203125 +38119 0.268798828125 +38120 0.1309814453125 +38121 0.482818603515625 +38122 0.162689208984375 +38123 0.60369873046875 +38124 0.17462158203125 +38125 0.650421142578125 +38126 0.17767333984375 +38127 0.66400146484375 +38128 0.17108154296875 +38129 0.6414794921875 +38130 0.15216064453125 +38131 0.572540283203125 +38132 0.13177490234375 +38133 0.498138427734375 +38134 0.115570068359375 +38135 0.439453125 +38136 0.098052978515625 +38137 0.375518798828125 +38138 0.070831298828125 +38139 0.274505615234375 +38140 0.026611328125 +38141 0.1087646484375 +38142 -0.0286865234375 +38143 -0.099395751953125 +38144 -0.08612060546875 +38145 -0.3182373046875 +38146 -0.14520263671875 +38147 -0.5489501953125 +38148 -0.201446533203125 +38149 -0.7738037109375 +38150 -0.242431640625 +38151 -0.86383056640625 +38152 -0.2603759765625 +38153 -0.870391845703125 +38154 -0.25946044921875 +38155 -0.86895751953125 +38156 -0.24285888671875 +38157 -0.861053466796875 +38158 -0.206756591796875 +38159 -0.765869140625 +38160 -0.1488037109375 +38161 -0.5301513671875 +38162 -0.070953369140625 +38163 -0.214691162109375 +38164 0.01641845703125 +38165 0.137359619140625 +38166 0.101104736328125 +38167 0.474822998046875 +38168 0.174530029296875 +38169 0.76239013671875 +38170 0.230133056640625 +38171 0.867462158203125 +38172 0.26776123046875 +38173 0.870361328125 +38174 0.284515380859375 +38175 0.86480712890625 +38176 0.28155517578125 +38177 0.831817626953125 +38178 0.26446533203125 +38179 0.677581787109375 +38180 0.234619140625 +38181 0.495880126953125 +38182 0.196380615234375 +38183 0.30767822265625 +38184 0.150390625 +38185 0.116180419921875 +38186 0.0894775390625 +38187 -0.110748291015625 +38188 0.01226806640625 +38189 -0.381805419921875 +38190 -0.071014404296875 +38191 -0.6572265625 +38192 -0.14617919921875 +38193 -0.857421875 +38194 -0.203033447265625 +38195 -0.870391845703125 +38196 -0.23968505859375 +38197 -0.870391845703125 +38198 -0.26214599609375 +38199 -0.86444091796875 +38200 -0.278564453125 +38201 -0.85723876953125 +38202 -0.284576416015625 +38203 -0.790008544921875 +38204 -0.267547607421875 +38205 -0.62847900390625 +38206 -0.226715087890625 +38207 -0.3956298828125 +38208 -0.169769287109375 +38209 -0.126708984375 +38210 -0.1031494140625 +38211 0.150115966796875 +38212 -0.02972412109375 +38213 0.424041748046875 +38214 0.0440673828125 +38215 0.670623779296875 +38216 0.1090087890625 +38217 0.854522705078125 +38218 0.160797119140625 +38219 0.866485595703125 +38220 0.195648193359375 +38221 0.86920166015625 +38222 0.21759033203125 +38223 0.8653564453125 +38224 0.22955322265625 +38225 0.857147216796875 +38226 0.230712890625 +38227 0.766845703125 +38228 0.222137451171875 +38229 0.628509521484375 +38230 0.20220947265625 +38231 0.462127685546875 +38232 0.176910400390625 +38233 0.297210693359375 +38234 0.14910888671875 +38235 0.14862060546875 +38236 0.11358642578125 +38237 -0.00537109375 +38238 0.07220458984375 +38239 -0.15753173828125 +38240 0.024322509765625 +38241 -0.31304931640625 +38242 -0.03314208984375 +38243 -0.48876953125 +38244 -0.08917236328125 +38245 -0.6416015625 +38246 -0.137847900390625 +38247 -0.751373291015625 +38248 -0.184356689453125 +38249 -0.84619140625 +38250 -0.22515869140625 +38251 -0.861297607421875 +38252 -0.252410888671875 +38253 -0.863250732421875 +38254 -0.2586669921875 +38255 -0.856597900390625 +38256 -0.2467041015625 +38257 -0.7498779296875 +38258 -0.22991943359375 +38259 -0.624542236328125 +38260 -0.203216552734375 +38261 -0.47808837890625 +38262 -0.153106689453125 +38263 -0.253387451171875 +38264 -0.090240478515625 +38265 0.003692626953125 +38266 -0.030609130859375 +38267 0.2257080078125 +38268 0.028533935546875 +38269 0.427154541015625 +38270 0.09454345703125 +38271 0.643218994140625 +38272 0.1650390625 +38273 0.855926513671875 +38274 0.226409912109375 +38275 0.870361328125 +38276 0.26702880859375 +38277 0.870361328125 +38278 0.288421630859375 +38279 0.862762451171875 +38280 0.28985595703125 +38281 0.79669189453125 +38282 0.269073486328125 +38283 0.595794677734375 +38284 0.232818603515625 +38285 0.362152099609375 +38286 0.1876220703125 +38287 0.1270751953125 +38288 0.138427734375 +38289 -0.086944580078125 +38290 0.085784912109375 +38291 -0.2784423828125 +38292 0.021728515625 +38293 -0.484832763671875 +38294 -0.05804443359375 +38295 -0.729583740234375 +38296 -0.14166259765625 +38297 -0.86688232421875 +38298 -0.214324951171875 +38299 -0.870391845703125 +38300 -0.27471923828125 +38301 -0.86859130859375 +38302 -0.322235107421875 +38303 -0.86279296875 +38304 -0.34844970703125 +38305 -0.817962646484375 +38306 -0.34271240234375 +38307 -0.6116943359375 +38308 -0.3033447265625 +38309 -0.3128662109375 +38310 -0.23809814453125 +38311 0.039398193359375 +38312 -0.151641845703125 +38313 0.422821044921875 +38314 -0.0517578125 +38315 0.805145263671875 +38316 0.045684814453125 +38317 0.870361328125 +38318 0.127349853515625 +38319 0.870361328125 +38320 0.190399169921875 +38321 0.860015869140625 +38322 0.232879638671875 +38323 0.727935791015625 +38324 0.25335693359375 +38325 0.48114013671875 +38326 0.257293701171875 +38327 0.2059326171875 +38328 0.249755859375 +38329 -0.06103515625 +38330 0.23297119140625 +38331 -0.29913330078125 +38332 0.203460693359375 +38333 -0.516204833984375 +38334 0.157623291015625 +38335 -0.7252197265625 +38336 0.101226806640625 +38337 -0.85980224609375 +38338 0.042236328125 +38339 -0.870391845703125 +38340 -0.01239013671875 +38341 -0.870391845703125 +38342 -0.051177978515625 +38343 -0.858062744140625 +38344 -0.072998046875 +38345 -0.673004150390625 +38346 -0.089874267578125 +38347 -0.42694091796875 +38348 -0.111907958984375 +38349 -0.2100830078125 +38350 -0.138397216796875 +38351 -0.0362548828125 +38352 -0.162384033203125 +38353 0.10943603515625 +38354 -0.179046630859375 +38355 0.23516845703125 +38356 -0.17864990234375 +38357 0.373687744140625 +38358 -0.16156005859375 +38359 0.517791748046875 +38360 -0.142333984375 +38361 0.602783203125 +38362 -0.1197509765625 +38363 0.635711669921875 +38364 -0.08612060546875 +38365 0.655181884765625 +38366 -0.0438232421875 +38367 0.65948486328125 +38368 0.00506591796875 +38369 0.651275634765625 +38370 0.05474853515625 +38371 0.61846923828125 +38372 0.096435546875 +38373 0.53753662109375 +38374 0.125732421875 +38375 0.404144287109375 +38376 0.140228271484375 +38377 0.22186279296875 +38378 0.1400146484375 +38379 0.003997802734375 +38380 0.129119873046875 +38381 -0.22100830078125 +38382 0.112213134765625 +38383 -0.42449951171875 +38384 0.0941162109375 +38385 -0.579833984375 +38386 0.084686279296875 +38387 -0.641876220703125 +38388 0.082366943359375 +38389 -0.6177978515625 +38390 0.072174072265625 +38391 -0.575531005859375 +38392 0.052947998046875 +38393 -0.526336669921875 +38394 0.036773681640625 +38395 -0.42645263671875 +38396 0.0301513671875 +38397 -0.2581787109375 +38398 0.02484130859375 +38399 -0.068695068359375 +38400 0.0115966796875 +38401 0.09222412109375 +38402 -0.005615234375 +38403 0.232147216796875 +38404 -0.023712158203125 +38405 0.3509521484375 +38406 -0.047882080078125 +38407 0.410064697265625 +38408 -0.083404541015625 +38409 0.372955322265625 +38410 -0.125640869140625 +38411 0.2554931640625 +38412 -0.163818359375 +38413 0.10711669921875 +38414 -0.193817138671875 +38415 -0.052886962890625 +38416 -0.208343505859375 +38417 -0.186279296875 +38418 -0.19635009765625 +38419 -0.23291015625 +38420 -0.16259765625 +38421 -0.209442138671875 +38422 -0.120574951171875 +38423 -0.174163818359375 +38424 -0.07232666015625 +38425 -0.126739501953125 +38426 -0.016265869140625 +38427 -0.048126220703125 +38428 0.041473388671875 +38429 0.0426025390625 +38430 0.091156005859375 +38431 0.10748291015625 +38432 0.129730224609375 +38433 0.1409912109375 +38434 0.166351318359375 +38435 0.19708251953125 +38436 0.19940185546875 +38437 0.273651123046875 +38438 0.217559814453125 +38439 0.31768798828125 +38440 0.222930908203125 +38441 0.341094970703125 +38442 0.220550537109375 +38443 0.368011474609375 +38444 0.205902099609375 +38445 0.37249755859375 +38446 0.1693115234375 +38447 0.30072021484375 +38448 0.111968994140625 +38449 0.1517333984375 +38450 0.0474853515625 +38451 -0.01470947265625 +38452 -0.020263671875 +38453 -0.1883544921875 +38454 -0.090118408203125 +38455 -0.372711181640625 +38456 -0.149566650390625 +38457 -0.51397705078125 +38458 -0.188873291015625 +38459 -0.57177734375 +38460 -0.20526123046875 +38461 -0.53948974609375 +38462 -0.20123291015625 +38463 -0.43511962890625 +38464 -0.183563232421875 +38465 -0.2962646484375 +38466 -0.1595458984375 +38467 -0.161102294921875 +38468 -0.131988525390625 +38469 -0.0435791015625 +38470 -0.10052490234375 +38471 0.060394287109375 +38472 -0.0687255859375 +38473 0.13665771484375 +38474 -0.040679931640625 +38475 0.170135498046875 +38476 -0.01678466796875 +38477 0.16552734375 +38478 0.00836181640625 +38479 0.15728759765625 +38480 0.034332275390625 +38481 0.150787353515625 +38482 0.054840087890625 +38483 0.12200927734375 +38484 0.0703125 +38485 0.080108642578125 +38486 0.084747314453125 +38487 0.05126953125 +38488 0.102630615234375 +38489 0.062896728515625 +38490 0.118804931640625 +38491 0.09271240234375 +38492 0.123321533203125 +38493 0.092987060546875 +38494 0.119049072265625 +38495 0.07855224609375 +38496 0.109222412109375 +38497 0.06427001953125 +38498 0.09130859375 +38499 0.0347900390625 +38500 0.06573486328125 +38501 -0.01171875 +38502 0.037353515625 +38503 -0.056060791015625 +38504 0.015869140625 +38505 -0.055511474609375 +38506 0.00244140625 +38507 -0.010467529296875 +38508 -0.012451171875 +38509 0.02508544921875 +38510 -0.032745361328125 +38511 0.025665283203125 +38512 -0.052154541015625 +38513 0.017333984375 +38514 -0.06939697265625 +38515 0.00189208984375 +38516 -0.086029052734375 +38517 -0.03173828125 +38518 -0.0992431640625 +38519 -0.071502685546875 +38520 -0.11248779296875 +38521 -0.13543701171875 +38522 -0.125152587890625 +38523 -0.219970703125 +38524 -0.1326904296875 +38525 -0.300506591796875 +38526 -0.135528564453125 +38527 -0.376312255859375 +38528 -0.128204345703125 +38529 -0.416107177734375 +38530 -0.10186767578125 +38531 -0.371124267578125 +38532 -0.0577392578125 +38533 -0.242279052734375 +38534 -0.0048828125 +38535 -0.069732666015625 +38536 0.051483154296875 +38537 0.125640869140625 +38538 0.104248046875 +38539 0.31268310546875 +38540 0.14532470703125 +38541 0.45501708984375 +38542 0.174530029296875 +38543 0.554779052734375 +38544 0.19122314453125 +38545 0.61065673828125 +38546 0.19287109375 +38547 0.610931396484375 +38548 0.1746826171875 +38549 0.531463623046875 +38550 0.140106201171875 +38551 0.3883056640625 +38552 0.1002197265625 +38553 0.23468017578125 +38554 0.060546875 +38555 0.095245361328125 +38556 0.027008056640625 +38557 -0.00396728515625 +38558 0.003265380859375 +38559 -0.04852294921875 +38560 -0.013153076171875 +38561 -0.055145263671875 +38562 -0.031829833984375 +38563 -0.0758056640625 +38564 -0.0576171875 +38565 -0.138702392578125 +38566 -0.0828857421875 +38567 -0.209197998046875 +38568 -0.107452392578125 +38569 -0.289031982421875 +38570 -0.13104248046875 +38571 -0.37884521484375 +38572 -0.148956298828125 +38573 -0.456329345703125 +38574 -0.16015625 +38575 -0.51641845703125 +38576 -0.156829833984375 +38577 -0.519287109375 +38578 -0.137939453125 +38579 -0.458251953125 +38580 -0.11419677734375 +38581 -0.384796142578125 +38582 -0.09112548828125 +38583 -0.323699951171875 +38584 -0.0682373046875 +38585 -0.269287109375 +38586 -0.040924072265625 +38587 -0.1951904296875 +38588 -0.009613037109375 +38589 -0.100006103515625 +38590 0.019622802734375 +38591 -0.01055908203125 +38592 0.052215576171875 +38593 0.1033935546875 +38594 0.089141845703125 +38595 0.24908447265625 +38596 0.119384765625 +38597 0.373199462890625 +38598 0.13916015625 +38599 0.45806884765625 +38600 0.14996337890625 +38601 0.511474609375 +38602 0.15826416015625 +38603 0.565399169921875 +38604 0.162567138671875 +38605 0.61138916015625 +38606 0.151275634765625 +38607 0.5897216796875 +38608 0.12286376953125 +38609 0.4906005859375 +38610 0.08135986328125 +38611 0.33148193359375 +38612 0.034423828125 +38613 0.147796630859375 +38614 -0.009033203125 +38615 -0.01873779296875 +38616 -0.042877197265625 +38617 -0.140289306640625 +38618 -0.0616455078125 +38619 -0.191986083984375 +38620 -0.0670166015625 +38621 -0.184295654296875 +38622 -0.06756591796875 +38623 -0.161834716796875 +38624 -0.07147216796875 +38625 -0.166595458984375 +38626 -0.07769775390625 +38627 -0.19390869140625 +38628 -0.0823974609375 +38629 -0.22442626953125 +38630 -0.09002685546875 +38631 -0.279754638671875 +38632 -0.096649169921875 +38633 -0.3389892578125 +38634 -0.09307861328125 +38635 -0.3543701171875 +38636 -0.084136962890625 +38637 -0.348175048828125 +38638 -0.0714111328125 +38639 -0.32598876953125 +38640 -0.049468994140625 +38641 -0.2581787109375 +38642 -0.01776123046875 +38643 -0.139801025390625 +38644 0.0203857421875 +38645 0.014617919921875 +38646 0.052398681640625 +38647 0.144378662109375 +38648 0.07232666015625 +38649 0.221038818359375 +38650 0.085174560546875 +38651 0.27069091796875 +38652 0.09100341796875 +38653 0.294036865234375 +38654 0.09393310546875 +38655 0.311767578125 +38656 0.09698486328125 +38657 0.339141845703125 +38658 0.096771240234375 +38659 0.360260009765625 +38660 0.09075927734375 +38661 0.360504150390625 +38662 0.074188232421875 +38663 0.308380126953125 +38664 0.043914794921875 +38665 0.18170166015625 +38666 0.004608154296875 +38667 0.0047607421875 +38668 -0.035186767578125 +38669 -0.17559814453125 +38670 -0.0673828125 +38671 -0.3143310546875 +38672 -0.084136962890625 +38673 -0.36785888671875 +38674 -0.0894775390625 +38675 -0.36248779296875 +38676 -0.090728759765625 +38677 -0.343536376953125 +38678 -0.086181640625 +38679 -0.3018798828125 +38680 -0.074737548828125 +38681 -0.231414794921875 +38682 -0.053985595703125 +38683 -0.117645263671875 +38684 -0.029541015625 +38685 0.007049560546875 +38686 -0.010833740234375 +38687 0.087982177734375 +38688 0.004180908203125 +38689 0.13946533203125 +38690 0.01727294921875 +38691 0.17425537109375 +38692 0.027313232421875 +38693 0.188201904296875 +38694 0.03216552734375 +38695 0.171234130859375 +38696 0.03057861328125 +38697 0.118438720703125 +38698 0.02679443359375 +38699 0.05706787109375 +38700 0.02081298828125 +38701 -0.010711669921875 +38702 0.011260986328125 +38703 -0.0914306640625 +38704 0.001800537109375 +38705 -0.162322998046875 +38706 -0.0028076171875 +38707 -0.194549560546875 +38708 0.003936767578125 +38709 -0.1492919921875 +38710 0.02294921875 +38711 -0.02166748046875 +38712 0.04364013671875 +38713 0.124053955078125 +38714 0.053314208984375 +38715 0.211151123046875 +38716 0.05242919921875 +38717 0.240447998046875 +38718 0.046417236328125 +38719 0.242218017578125 +38720 0.0372314453125 +38721 0.2257080078125 +38722 0.025787353515625 +38723 0.194366455078125 +38724 0.006927490234375 +38725 0.115509033203125 +38726 -0.015045166015625 +38727 0.0128173828125 +38728 -0.02984619140625 +38729 -0.053802490234375 +38730 -0.041748046875 +38731 -0.110626220703125 +38732 -0.05767822265625 +38733 -0.199493408203125 +38734 -0.0732421875 +38735 -0.29437255859375 +38736 -0.077911376953125 +38737 -0.33221435546875 +38738 -0.066253662109375 +38739 -0.27972412109375 +38740 -0.04656982421875 +38741 -0.185333251953125 +38742 -0.032379150390625 +38743 -0.128204345703125 +38744 -0.02520751953125 +38745 -0.115692138671875 +38746 -0.02008056640625 +38747 -0.116455078125 +38748 -0.013153076171875 +38749 -0.105926513671875 +38750 0.00030517578125 +38751 -0.053955078125 +38752 0.021636962890625 +38753 0.048797607421875 +38754 0.0430908203125 +38755 0.157318115234375 +38756 0.05450439453125 +38757 0.212005615234375 +38758 0.05670166015625 +38759 0.218475341796875 +38760 0.059844970703125 +38761 0.23724365234375 +38762 0.0701904296875 +38763 0.30535888671875 +38764 0.08087158203125 +38765 0.38128662109375 +38766 0.081787109375 +38767 0.404449462890625 +38768 0.076446533203125 +38769 0.3944091796875 +38770 0.07135009765625 +38771 0.3885498046875 +38772 0.062652587890625 +38773 0.362640380859375 +38774 0.043365478515625 +38775 0.27362060546875 +38776 0.01300048828125 +38777 0.11712646484375 +38778 -0.01947021484375 +38779 -0.054901123046875 +38780 -0.045166015625 +38781 -0.19085693359375 +38782 -0.0631103515625 +38783 -0.28570556640625 +38784 -0.073211669921875 +38785 -0.339263916015625 +38786 -0.079803466796875 +38787 -0.3775634765625 +38788 -0.090484619140625 +38789 -0.445709228515625 +38790 -0.1038818359375 +38791 -0.535064697265625 +38792 -0.1173095703125 +38793 -0.629058837890625 +38794 -0.1258544921875 +38795 -0.697601318359375 +38796 -0.123504638671875 +38797 -0.70391845703125 +38798 -0.109527587890625 +38799 -0.6424560546875 +38800 -0.0804443359375 +38801 -0.491241455078125 +38802 -0.039093017578125 +38803 -0.265716552734375 +38804 0.004608154296875 +38805 -0.023712158203125 +38806 0.044952392578125 +38807 0.201751708984375 +38808 0.07598876953125 +38809 0.375823974609375 +38810 0.095367431640625 +38811 0.485076904296875 +38812 0.10968017578125 +38813 0.56884765625 +38814 0.120208740234375 +38815 0.634765625 +38816 0.11944580078125 +38817 0.63763427734375 +38818 0.10552978515625 +38819 0.5660400390625 +38820 0.08734130859375 +38821 0.4720458984375 +38822 0.073638916015625 +38823 0.40692138671875 +38824 0.065765380859375 +38825 0.3778076171875 +38826 0.062591552734375 +38827 0.376953125 +38828 0.058868408203125 +38829 0.371978759765625 +38830 0.046356201171875 +38831 0.313140869140625 +38832 0.02252197265625 +38833 0.184417724609375 +38834 -0.00823974609375 +38835 0.011199951171875 +38836 -0.039886474609375 +38837 -0.171051025390625 +38838 -0.06817626953125 +38839 -0.33740234375 +38840 -0.0904541015625 +38841 -0.47198486328125 +38842 -0.104339599609375 +38843 -0.560394287109375 +38844 -0.106201171875 +38845 -0.58056640625 +38846 -0.09869384765625 +38847 -0.54754638671875 +38848 -0.089874267578125 +38849 -0.508575439453125 +38850 -0.07916259765625 +38851 -0.459503173828125 +38852 -0.065704345703125 +38853 -0.394378662109375 +38854 -0.056243896484375 +38855 -0.35260009765625 +38856 -0.047088623046875 +38857 -0.31170654296875 +38858 -0.02593994140625 +38859 -0.197418212890625 +38860 0.007415771484375 +38861 -0.007965087890625 +38862 0.044586181640625 +38863 0.207489013671875 +38864 0.078887939453125 +38865 0.409210205078125 +38866 0.1060791015625 +38867 0.57208251953125 +38868 0.121124267578125 +38869 0.66595458984375 +38870 0.118682861328125 +38871 0.65875244140625 +38872 0.101715087890625 +38873 0.56744384765625 +38874 0.076934814453125 +38875 0.431396484375 +38876 0.05181884765625 +38877 0.29443359375 +38878 0.03082275390625 +38879 0.182464599609375 +38880 0.008758544921875 +38881 0.06365966796875 +38882 -0.016632080078125 +38883 -0.075958251953125 +38884 -0.037322998046875 +38885 -0.189422607421875 +38886 -0.05242919921875 +38887 -0.271942138671875 +38888 -0.0650634765625 +38889 -0.342529296875 +38890 -0.06903076171875 +38891 -0.364166259765625 +38892 -0.062713623046875 +38893 -0.327239990234375 +38894 -0.0537109375 +38895 -0.2769775390625 +38896 -0.048828125 +38897 -0.253692626953125 +38898 -0.04583740234375 +38899 -0.24365234375 +38900 -0.03668212890625 +38901 -0.1983642578125 +38902 -0.02117919921875 +38903 -0.116241455078125 +38904 -0.006072998046875 +38905 -0.036834716796875 +38906 0.0076904296875 +38907 0.034881591796875 +38908 0.01873779296875 +38909 0.09124755859375 +38910 0.023040771484375 +38911 0.10888671875 +38912 0.0264892578125 +38913 0.125518798828125 +38914 0.031707763671875 +38915 0.15771484375 +38916 0.03460693359375 +38917 0.17828369140625 +38918 0.03314208984375 +38919 0.17108154296875 +38920 0.026580810546875 +38921 0.129974365234375 +38922 0.018798828125 +38923 0.082427978515625 +38924 0.009765625 +38925 0.027679443359375 +38926 -0.004608154296875 +38927 -0.065643310546875 +38928 -0.019073486328125 +38929 -0.15936279296875 +38930 -0.028045654296875 +38931 -0.21307373046875 +38932 -0.03253173828125 +38933 -0.234649658203125 +38934 -0.02923583984375 +38935 -0.2001953125 +38936 -0.0194091796875 +38937 -0.119171142578125 +38938 -0.00750732421875 +38939 -0.024749755859375 +38940 0.006866455078125 +38941 0.085784912109375 +38942 0.01904296875 +38943 0.178131103515625 +38944 0.0240478515625 +38945 0.215576171875 +38946 0.023681640625 +38947 0.211456298828125 +38948 0.019256591796875 +38949 0.17523193359375 +38950 0.013671875 +38951 0.128753662109375 +38952 0.010955810546875 +38953 0.1019287109375 +38954 0.008270263671875 +38955 0.0743408203125 +38956 0.00518798828125 +38957 0.04327392578125 +38958 0.005615234375 +38959 0.038177490234375 +38960 0.011871337890625 +38961 0.076263427734375 +38962 0.0216064453125 +38963 0.14105224609375 +38964 0.028533935546875 +38965 0.186431884765625 +38966 0.0294189453125 +38967 0.188812255859375 +38968 0.02301025390625 +38969 0.1390380859375 +38970 0.009918212890625 +38971 0.041778564453125 +38972 -0.006622314453125 +38973 -0.079437255859375 +38974 -0.025909423828125 +38975 -0.219390869140625 +38976 -0.046478271484375 +38977 -0.367828369140625 +38978 -0.06427001953125 +38979 -0.494873046875 +38980 -0.0732421875 +38981 -0.556243896484375 +38982 -0.0675048828125 +38983 -0.508697509765625 +38984 -0.0501708984375 +38985 -0.3756103515625 +38986 -0.0296630859375 +38987 -0.218902587890625 +38988 -0.009307861328125 +38989 -0.063751220703125 +38990 0.011077880859375 +38991 0.091552734375 +38992 0.030059814453125 +38993 0.23602294921875 +38994 0.0440673828125 +38995 0.342987060546875 +38996 0.05078125 +38997 0.39520263671875 +38998 0.04974365234375 +38999 0.389373779296875 +39000 0.04083251953125 +39001 0.324249267578125 +39002 0.027374267578125 +39003 0.224090576171875 +39004 0.01416015625 +39005 0.124267578125 +39006 0.0028076171875 +39007 0.037078857421875 +39008 -0.002960205078125 +39009 -0.010101318359375 +39010 -0.003509521484375 +39011 -0.019439697265625 +39012 -0.003204345703125 +39013 -0.022796630859375 +39014 0.00042724609375 +39015 -0.001556396484375 +39016 0.008941650390625 +39017 0.056304931640625 +39018 0.016326904296875 +39019 0.106719970703125 +39020 0.015411376953125 +39021 0.096893310546875 +39022 0.00830078125 +39023 0.042694091796875 +39024 0.00018310546875 +39025 -0.018035888671875 +39026 -0.007659912109375 +39027 -0.07586669921875 +39028 -0.013671875 +39029 -0.11944580078125 +39030 -0.01934814453125 +39031 -0.15972900390625 +39032 -0.025482177734375 +39033 -0.202606201171875 +39034 -0.0321044921875 +39035 -0.24859619140625 +39036 -0.040191650390625 +39037 -0.30517578125 +39038 -0.04833984375 +39039 -0.36212158203125 +39040 -0.052764892578125 +39041 -0.39141845703125 +39042 -0.04827880859375 +39043 -0.35528564453125 +39044 -0.034332275390625 +39045 -0.249969482421875 +39046 -0.0133056640625 +39047 -0.092864990234375 +39048 0.011138916015625 +39049 0.08905029296875 +39050 0.030792236328125 +39051 0.2352294921875 +39052 0.0419921875 +39053 0.318817138671875 +39054 0.047332763671875 +39055 0.358642578125 +39056 0.04583740234375 +39057 0.347747802734375 +39058 0.0374755859375 +39059 0.28564453125 +39060 0.02911376953125 +39061 0.223175048828125 +39062 0.025726318359375 +39063 0.196746826171875 +39064 0.023681640625 +39065 0.179840087890625 +39066 0.020660400390625 +39067 0.155548095703125 +39068 0.020355224609375 +39069 0.151214599609375 +39070 0.02142333984375 +39071 0.156951904296875 +39072 0.018280029296875 +39073 0.13177490234375 +39074 0.014312744140625 +39075 0.100799560546875 +39076 0.01263427734375 +39077 0.087127685546875 +39078 0.008392333984375 +39079 0.05487060546875 +39080 -0.000152587890625 +39081 -0.009002685546875 +39082 -0.012939453125 +39083 -0.10400390625 +39084 -0.0299072265625 +39085 -0.229400634765625 +39086 -0.047027587890625 +39087 -0.35552978515625 +39088 -0.05877685546875 +39089 -0.441925048828125 +39090 -0.063140869140625 +39091 -0.473846435546875 +39092 -0.061981201171875 +39093 -0.464813232421875 +39094 -0.055877685546875 +39095 -0.419097900390625 +39096 -0.04449462890625 +39097 -0.334320068359375 +39098 -0.03021240234375 +39099 -0.227935791015625 +39100 -0.016204833984375 +39101 -0.12347412109375 +39102 -0.003387451171875 +39103 -0.02764892578125 +39104 0.010711669921875 +39105 0.077667236328125 +39106 0.0289306640625 +39107 0.2132568359375 +39108 0.0526123046875 +39109 0.38885498046875 +39110 0.07879638671875 +39111 0.582794189453125 +39112 0.099212646484375 +39113 0.734039306640625 +39114 0.108062744140625 +39115 0.800140380859375 +39116 0.10498046875 +39117 0.7783203125 +39118 0.08953857421875 +39119 0.6651611328125 +39120 0.06158447265625 +39121 0.45965576171875 +39122 0.0262451171875 +39123 0.199188232421875 +39124 -0.007568359375 +39125 -0.050689697265625 +39126 -0.032135009765625 +39127 -0.23297119140625 +39128 -0.045074462890625 +39129 -0.33013916015625 +39130 -0.049957275390625 +39131 -0.368408203125 +39132 -0.051055908203125 +39133 -0.378936767578125 +39134 -0.050506591796875 +39135 -0.376983642578125 +39136 -0.050628662109375 +39137 -0.37969970703125 +39138 -0.052032470703125 +39139 -0.391510009765625 +39140 -0.051025390625 +39141 -0.385345458984375 +39142 -0.045013427734375 +39143 -0.3419189453125 +39144 -0.036956787109375 +39145 -0.28289794921875 +39146 -0.03271484375 +39147 -0.251617431640625 +39148 -0.034759521484375 +39149 -0.266143798828125 +39150 -0.035858154296875 +39151 -0.273345947265625 +39152 -0.0283203125 +39153 -0.216796875 +39154 -0.016448974609375 +39155 -0.128265380859375 +39156 -0.0084228515625 +39157 -0.068145751953125 +39158 -0.005157470703125 +39159 -0.0430908203125 +39160 -0.002777099609375 +39161 -0.024444580078125 +39162 0.003173828125 +39163 0.020721435546875 +39164 0.01708984375 +39165 0.124481201171875 +39166 0.035003662109375 +39167 0.25787353515625 +39168 0.050689697265625 +39169 0.379119873046875 +39170 0.063262939453125 +39171 0.47991943359375 +39172 0.0697021484375 +39173 0.5281982421875 +39174 0.06854248046875 +39175 0.511138916015625 +39176 0.062530517578125 +39177 0.456207275390625 +39178 0.056243896484375 +39179 0.407470703125 +39180 0.051727294921875 +39181 0.383758544921875 +39182 0.046142578125 +39183 0.35687255859375 +39184 0.038116455078125 +39185 0.31182861328125 +39186 0.02813720703125 +39187 0.250885009765625 +39188 0.0155029296875 +39189 0.1654052734375 +39190 -0.001617431640625 +39191 0.035247802734375 +39192 -0.02325439453125 +39193 -0.142059326171875 +39194 -0.0460205078125 +39195 -0.33563232421875 +39196 -0.068634033203125 +39197 -0.5345458984375 +39198 -0.089263916015625 +39199 -0.72186279296875 +39200 -0.10150146484375 +39201 -0.836669921875 +39202 -0.10052490234375 +39203 -0.8326416015625 +39204 -0.0885009765625 +39205 -0.7296142578125 +39206 -0.07122802734375 +39207 -0.582550048828125 +39208 -0.05389404296875 +39209 -0.440093994140625 +39210 -0.0389404296875 +39211 -0.324310302734375 +39212 -0.02301025390625 +39213 -0.20147705078125 +39214 -0.00347900390625 +39215 -0.044647216796875 +39216 0.015045166015625 +39217 0.103973388671875 +39218 0.028045654296875 +39219 0.202392578125 +39220 0.03680419921875 +39221 0.264495849609375 +39222 0.0462646484375 +39223 0.338897705078125 +39224 0.0582275390625 +39225 0.443817138671875 +39226 0.069091796875 +39227 0.545074462890625 +39228 0.076263427734375 +39229 0.6173095703125 +39230 0.07891845703125 +39231 0.6524658203125 +39232 0.078460693359375 +39233 0.66339111328125 +39234 0.075653076171875 +39235 0.6561279296875 +39236 0.068084716796875 +39237 0.606781005859375 +39238 0.054443359375 +39239 0.501190185546875 +39240 0.036285400390625 +39241 0.352783203125 +39242 0.015350341796875 +39243 0.176544189453125 +39244 -0.00897216796875 +39245 -0.034820556640625 +39246 -0.03411865234375 +39247 -0.258209228515625 +39248 -0.0546875 +39249 -0.44244384765625 +39250 -0.069366455078125 +39251 -0.5753173828125 +39252 -0.077606201171875 +39253 -0.65203857421875 +39254 -0.076202392578125 +39255 -0.641632080078125 +39256 -0.067108154296875 +39257 -0.562164306640625 +39258 -0.05499267578125 +39259 -0.458038330078125 +39260 -0.042144775390625 +39261 -0.350555419921875 +39262 -0.03082275390625 +39263 -0.260528564453125 +39264 -0.021575927734375 +39265 -0.192108154296875 +39266 -0.014190673828125 +39267 -0.141937255859375 +39268 -0.007965087890625 +39269 -0.1021728515625 +39270 -0.001953125 +39271 -0.062896728515625 +39272 0.004974365234375 +39273 -0.011932373046875 +39274 0.014007568359375 +39275 0.062835693359375 +39276 0.023773193359375 +39277 0.148712158203125 +39278 0.0338134765625 +39279 0.241729736328125 +39280 0.04486083984375 +39281 0.34912109375 +39282 0.055511474609375 +39283 0.457305908203125 +39284 0.063507080078125 +39285 0.54388427734375 +39286 0.065185546875 +39287 0.5728759765625 +39288 0.056671142578125 +39289 0.506591796875 +39290 0.038726806640625 +39291 0.351226806640625 +39292 0.01556396484375 +39293 0.146514892578125 +39294 -0.007232666015625 +39295 -0.05523681640625 +39296 -0.025634765625 +39297 -0.21624755859375 +39298 -0.03936767578125 +39299 -0.334930419921875 +39300 -0.047515869140625 +39301 -0.402984619140625 +39302 -0.05218505859375 +39303 -0.4412841796875 +39304 -0.058135986328125 +39305 -0.49578857421875 +39306 -0.064727783203125 +39307 -0.5601806640625 +39308 -0.068450927734375 +39309 -0.600738525390625 +39310 -0.065887451171875 +39311 -0.584228515625 +39312 -0.0538330078125 +39313 -0.47930908203125 +39314 -0.031707763671875 +39315 -0.27935791015625 +39316 -0.002105712890625 +39317 -0.0089111328125 +39318 0.02825927734375 +39319 0.268798828125 +39320 0.051910400390625 +39321 0.482818603515625 +39322 0.065704345703125 +39323 0.60369873046875 +39324 0.071563720703125 +39325 0.650421142578125 +39326 0.07373046875 +39327 0.66400146484375 +39328 0.071868896484375 +39329 0.6414794921875 +39330 0.064910888671875 +39331 0.572540283203125 +39332 0.05706787109375 +39333 0.498138427734375 +39334 0.050567626953125 +39335 0.439453125 +39336 0.04327392578125 +39337 0.375518798828125 +39338 0.031890869140625 +39339 0.274505615234375 +39340 0.013641357421875 +39341 0.1087646484375 +39342 -0.00909423828125 +39343 -0.099395751953125 +39344 -0.032928466796875 +39345 -0.3182373046875 +39346 -0.05792236328125 +39347 -0.5489501953125 +39348 -0.082183837890625 +39349 -0.7738037109375 +39350 -0.10015869140625 +39351 -0.86383056640625 +39352 -0.1083984375 +39353 -0.870391845703125 +39354 -0.108673095703125 +39355 -0.86895751953125 +39356 -0.10235595703125 +39357 -0.861053466796875 +39358 -0.087677001953125 +39359 -0.765869140625 +39360 -0.0634765625 +39361 -0.5301513671875 +39362 -0.030487060546875 +39363 -0.214691162109375 +39364 0.006744384765625 +39365 0.137359619140625 +39366 0.0428466796875 +39367 0.474822998046875 +39368 0.0740966796875 +39369 0.76239013671875 +39370 0.097625732421875 +39371 0.867462158203125 +39372 0.113433837890625 +39373 0.870361328125 +39374 0.120269775390625 +39375 0.86480712890625 +39376 0.11865234375 +39377 0.831817626953125 +39378 0.111114501953125 +39379 0.677581787109375 +39380 0.0982666015625 +39381 0.495880126953125 +39382 0.08203125 +39383 0.30767822265625 +39384 0.062652587890625 +39385 0.116180419921875 +39386 0.036834716796875 +39387 -0.110748291015625 +39388 0.00384521484375 +39389 -0.381805419921875 +39390 -0.03179931640625 +39391 -0.6572265625 +39392 -0.063812255859375 +39393 -0.857421875 +39394 -0.087738037109375 +39395 -0.870391845703125 +39396 -0.102813720703125 +39397 -0.870391845703125 +39398 -0.11181640625 +39399 -0.86444091796875 +39400 -0.118438720703125 +39401 -0.85723876953125 +39402 -0.120758056640625 +39403 -0.790008544921875 +39404 -0.11309814453125 +39405 -0.62847900390625 +39406 -0.095123291015625 +39407 -0.3956298828125 +39408 -0.07025146484375 +39409 -0.126708984375 +39410 -0.04132080078125 +39411 0.150115966796875 +39412 -0.00958251953125 +39413 0.424041748046875 +39414 0.02215576171875 +39415 0.670623779296875 +39416 0.0498046875 +39417 0.854522705078125 +39418 0.071533203125 +39419 0.866485595703125 +39420 0.08575439453125 +39421 0.86920166015625 +39422 0.094329833984375 +39423 0.8653564453125 +39424 0.098907470703125 +39425 0.857147216796875 +39426 0.098907470703125 +39427 0.766845703125 +39428 0.094482421875 +39429 0.628509521484375 +39430 0.085205078125 +39431 0.462127685546875 +39432 0.0731201171875 +39433 0.297210693359375 +39434 0.059326171875 +39435 0.14862060546875 +39436 0.042510986328125 +39437 -0.00537109375 +39438 0.023590087890625 +39439 -0.15753173828125 +39440 0.002716064453125 +39441 -0.31304931640625 +39442 -0.02069091796875 +39443 -0.48876953125 +39444 -0.04290771484375 +39445 -0.6416015625 +39446 -0.0618896484375 +39447 -0.751373291015625 +39448 -0.07904052734375 +39449 -0.84619140625 +39450 -0.0931396484375 +39451 -0.861297607421875 +39452 -0.1016845703125 +39453 -0.863250732421875 +39454 -0.102386474609375 +39455 -0.856597900390625 +39456 -0.09625244140625 +39457 -0.7498779296875 +39458 -0.08758544921875 +39459 -0.624542236328125 +39460 -0.07501220703125 +39461 -0.47808837890625 +39462 -0.05462646484375 +39463 -0.253387451171875 +39464 -0.030029296875 +39465 0.003692626953125 +39466 -0.0064697265625 +39467 0.2257080078125 +39468 0.016632080078125 +39469 0.427154541015625 +39470 0.04132080078125 +39471 0.643218994140625 +39472 0.066619873046875 +39473 0.855926513671875 +39474 0.088165283203125 +39475 0.870361328125 +39476 0.102203369140625 +39477 0.870361328125 +39478 0.109161376953125 +39479 0.862762451171875 +39480 0.108856201171875 +39481 0.79669189453125 +39482 0.100677490234375 +39483 0.595794677734375 +39484 0.0867919921875 +39485 0.362152099609375 +39486 0.069427490234375 +39487 0.1270751953125 +39488 0.050323486328125 +39489 -0.086944580078125 +39490 0.02984619140625 +39491 -0.2784423828125 +39492 0.005767822265625 +39493 -0.484832763671875 +39494 -0.02301025390625 +39495 -0.729583740234375 +39496 -0.052581787109375 +39497 -0.86688232421875 +39498 -0.078125 +39499 -0.870391845703125 +39500 -0.099090576171875 +39501 -0.86859130859375 +39502 -0.115203857421875 +39503 -0.86279296875 +39504 -0.123809814453125 +39505 -0.817962646484375 +39506 -0.121612548828125 +39507 -0.6116943359375 +39508 -0.108123779296875 +39509 -0.3128662109375 +39510 -0.08587646484375 +39511 0.039398193359375 +39512 -0.05645751953125 +39513 0.422821044921875 +39514 -0.022430419921875 +39515 0.805145263671875 +39516 0.011077880859375 +39517 0.870361328125 +39518 0.039764404296875 +39519 0.870361328125 +39520 0.06256103515625 +39521 0.860015869140625 +39522 0.07867431640625 +39523 0.727935791015625 +39524 0.0875244140625 +39525 0.48114013671875 +39526 0.0906982421875 +39527 0.2059326171875 +39528 0.08966064453125 +39529 -0.06103515625 +39530 0.0850830078125 +39531 -0.29913330078125 +39532 0.075836181640625 +39533 -0.516204833984375 +39534 0.06085205078125 +39535 -0.7252197265625 +39536 0.041961669921875 +39537 -0.85980224609375 +39538 0.021728515625 +39539 -0.870391845703125 +39540 0.00244140625 +39541 -0.870391845703125 +39542 -0.012176513671875 +39543 -0.858062744140625 +39544 -0.021636962890625 +39545 -0.673004150390625 +39546 -0.029541015625 +39547 -0.42694091796875 +39548 -0.03887939453125 +39549 -0.2100830078125 +39550 -0.04925537109375 +39551 -0.0362548828125 +39552 -0.058441162109375 +39553 0.10943603515625 +39554 -0.0648193359375 +39555 0.23516845703125 +39556 -0.065338134765625 +39557 0.373687744140625 +39558 -0.060089111328125 +39559 0.517791748046875 +39560 -0.053619384765625 +39561 0.602783203125 +39562 -0.045562744140625 +39563 0.635711669921875 +39564 -0.03363037109375 +39565 0.655181884765625 +39566 -0.0186767578125 +39567 0.65948486328125 +39568 -0.00140380859375 +39569 0.651275634765625 +39570 0.016204833984375 +39571 0.61846923828125 +39572 0.03131103515625 +39573 0.53753662109375 +39574 0.04241943359375 +39575 0.404144287109375 +39576 0.048675537109375 +39577 0.22186279296875 +39578 0.050048828125 +39579 0.003997802734375 +39580 0.0477294921875 +39581 -0.22100830078125 +39582 0.043121337890625 +39583 -0.42449951171875 +39584 0.03765869140625 +39585 -0.579833984375 +39586 0.034423828125 +39587 -0.641876220703125 +39588 0.032958984375 +39589 -0.6177978515625 +39590 0.0286865234375 +39591 -0.575531005859375 +39592 0.021270751953125 +39593 -0.526336669921875 +39594 0.01458740234375 +39595 -0.42645263671875 +39596 0.010711669921875 +39597 -0.2581787109375 +39598 0.007232666015625 +39599 -0.068695068359375 +39600 0.001495361328125 +39601 0.09222412109375 +39602 -0.00494384765625 +39603 0.232147216796875 +39604 -0.01123046875 +39605 0.3509521484375 +39606 -0.019378662109375 +39607 0.410064697265625 +39608 -0.031402587890625 +39609 0.372955322265625 +39610 -0.04571533203125 +39611 0.2554931640625 +39612 -0.058563232421875 +39613 0.10711669921875 +39614 -0.068511962890625 +39615 -0.052886962890625 +39616 -0.073028564453125 +39617 -0.186279296875 +39618 -0.068145751953125 +39619 -0.23291015625 +39620 -0.055633544921875 +39621 -0.209442138671875 +39622 -0.04034423828125 +39623 -0.174163818359375 +39624 -0.02301025390625 +39625 -0.126739501953125 +39626 -0.0030517578125 +39627 -0.048126220703125 +39628 0.017333984375 +39629 0.0426025390625 +39630 0.03466796875 +39631 0.10748291015625 +39632 0.047882080078125 +39633 0.1409912109375 +39634 0.060333251953125 +39635 0.19708251953125 +39636 0.07147216796875 +39637 0.273651123046875 +39638 0.0772705078125 +39639 0.31768798828125 +39640 0.07855224609375 +39641 0.341094970703125 +39642 0.077178955078125 +39643 0.368011474609375 +39644 0.071533203125 +39645 0.37249755859375 +39646 0.058135986328125 +39647 0.30072021484375 +39648 0.037445068359375 +39649 0.1517333984375 +39650 0.01434326171875 +39651 -0.01470947265625 +39652 -0.009765625 +39653 -0.1883544921875 +39654 -0.03448486328125 +39655 -0.372711181640625 +39656 -0.0552978515625 +39657 -0.51397705078125 +39658 -0.068756103515625 +39659 -0.57177734375 +39660 -0.07391357421875 +39661 -0.53948974609375 +39662 -0.071746826171875 +39663 -0.43511962890625 +39664 -0.064727783203125 +39665 -0.2962646484375 +39666 -0.05548095703125 +39667 -0.161102294921875 +39668 -0.045074462890625 +39669 -0.0435791015625 +39670 -0.033355712890625 +39671 0.060394287109375 +39672 -0.02166748046875 +39673 0.13665771484375 +39674 -0.011505126953125 +39675 0.170135498046875 +39676 -0.002960205078125 +39677 0.16552734375 +39678 0.005889892578125 +39679 0.15728759765625 +39680 0.015045166015625 +39681 0.150787353515625 +39682 0.022308349609375 +39683 0.12200927734375 +39684 0.027557373046875 +39685 0.080108642578125 +39686 0.0318603515625 +39687 0.05126953125 +39688 0.03643798828125 +39689 0.062896728515625 +39690 0.040069580078125 +39691 0.09271240234375 +39692 0.04034423828125 +39693 0.092987060546875 +39694 0.038055419921875 +39695 0.07855224609375 +39696 0.034088134765625 +39697 0.06427001953125 +39698 0.02789306640625 +39699 0.0347900390625 +39700 0.0196533203125 +39701 -0.01171875 +39702 0.01068115234375 +39703 -0.056060791015625 +39704 0.003448486328125 +39705 -0.055511474609375 +39706 -0.0015869140625 +39707 -0.010467529296875 +39708 -0.00677490234375 +39709 0.02508544921875 +39710 -0.013031005859375 +39711 0.025665283203125 +39712 -0.01873779296875 +39713 0.017333984375 +39714 -0.0235595703125 +39715 0.00189208984375 +39716 -0.027862548828125 +39717 -0.03173828125 +39718 -0.03094482421875 +39719 -0.071502685546875 +39720 -0.03369140625 +39721 -0.13543701171875 +39722 -0.035980224609375 +39723 -0.219970703125 +39724 -0.036712646484375 +39725 -0.300506591796875 +39726 -0.03607177734375 +39727 -0.376312255859375 +39728 -0.032806396484375 +39729 -0.416107177734375 +39730 -0.0247802734375 +39731 -0.371124267578125 +39732 -0.012359619140625 +39733 -0.242279052734375 +39734 0.0020751953125 +39735 -0.069732666015625 +39736 0.017181396484375 +39737 0.125640869140625 +39738 0.0311279296875 +39739 0.31268310546875 +39740 0.041839599609375 +39741 0.45501708984375 +39742 0.04925537109375 +39743 0.554779052734375 +39744 0.053253173828125 +39745 0.61065673828125 +39746 0.053192138671875 +39747 0.610931396484375 +39748 0.04791259765625 +39749 0.531463623046875 +39750 0.038330078125 +39751 0.3883056640625 +39752 0.027252197265625 +39753 0.23468017578125 +39754 0.01617431640625 +39755 0.095245361328125 +39756 0.006622314453125 +39757 -0.00396728515625 +39758 -0.00042724609375 +39759 -0.04852294921875 +39760 -0.005523681640625 +39761 -0.055145263671875 +39762 -0.011016845703125 +39763 -0.0758056640625 +39764 -0.01806640625 +39765 -0.138702392578125 +39766 -0.024749755859375 +39767 -0.209197998046875 +39768 -0.030975341796875 +39769 -0.289031982421875 +39770 -0.036712646484375 +39771 -0.37884521484375 +39772 -0.040802001953125 +39773 -0.456329345703125 +39774 -0.04302978515625 +39775 -0.51641845703125 +39776 -0.04144287109375 +39777 -0.519287109375 +39778 -0.03582763671875 +39779 -0.458251953125 +39780 -0.0289306640625 +39781 -0.384796142578125 +39782 -0.022186279296875 +39783 -0.323699951171875 +39784 -0.0155029296875 +39785 -0.269287109375 +39786 -0.007781982421875 +39787 -0.1951904296875 +39788 0.000762939453125 +39789 -0.100006103515625 +39790 0.00860595703125 +39791 -0.01055908203125 +39792 0.017059326171875 +39793 0.1033935546875 +39794 0.0263671875 +39795 0.24908447265625 +39796 0.033782958984375 +39797 0.373199462890625 +39798 0.038360595703125 +39799 0.45806884765625 +39800 0.040496826171875 +39801 0.511474609375 +39802 0.041839599609375 +39803 0.565399169921875 +39804 0.042083740234375 +39805 0.61138916015625 +39806 0.038360595703125 +39807 0.5897216796875 +39808 0.03033447265625 +39809 0.4906005859375 +39810 0.019073486328125 +39811 0.33148193359375 +39812 0.006561279296875 +39813 0.147796630859375 +39814 -0.004913330078125 +39815 -0.01873779296875 +39816 -0.0137939453125 +39817 -0.140289306640625 +39818 -0.018707275390625 +39819 -0.191986083984375 +39820 -0.02008056640625 +39821 -0.184295654296875 +39822 -0.020050048828125 +39823 -0.161834716796875 +39824 -0.02069091796875 +39825 -0.166595458984375 +39826 -0.021728515625 +39827 -0.19390869140625 +39828 -0.02227783203125 +39829 -0.22442626953125 +39830 -0.023468017578125 +39831 -0.279754638671875 +39832 -0.02435302734375 +39833 -0.3389892578125 +39834 -0.022674560546875 +39835 -0.3543701171875 +39836 -0.019683837890625 +39837 -0.348175048828125 +39838 -0.01580810546875 +39839 -0.32598876953125 +39840 -0.009735107421875 +39841 -0.2581787109375 +39842 -0.0013427734375 +39843 -0.139801025390625 +39844 0.00848388671875 +39845 0.014617919921875 +39846 0.016571044921875 +39847 0.144378662109375 +39848 0.02142333984375 +39849 0.221038818359375 +39850 0.024322509765625 +39851 0.27069091796875 +39852 0.025299072265625 +39853 0.294036865234375 +39854 0.025421142578125 +39855 0.311767578125 +39856 0.025482177734375 +39857 0.339141845703125 +39858 0.024658203125 +39859 0.360260009765625 +39860 0.022369384765625 +39861 0.360504150390625 +39862 0.017547607421875 +39863 0.308380126953125 +39864 0.00946044921875 +39865 0.18170166015625 +39866 -0.00067138671875 +39867 0.0047607421875 +39868 -0.010772705078125 +39869 -0.17559814453125 +39870 -0.01885986328125 +39871 -0.3143310546875 +39872 -0.0230712890625 +39873 -0.36785888671875 +39874 -0.02435302734375 +39875 -0.36248779296875 +39876 -0.02447509765625 +39877 -0.343536376953125 +39878 -0.023040771484375 +39879 -0.3018798828125 +39880 -0.01983642578125 +39881 -0.231414794921875 +39882 -0.014312744140625 +39883 -0.117645263671875 +39884 -0.007843017578125 +39885 0.007049560546875 +39886 -0.002716064453125 +39887 0.087982177734375 +39888 0.00152587890625 +39889 0.13946533203125 +39890 0.005279541015625 +39891 0.17425537109375 +39892 0.008209228515625 +39893 0.188201904296875 +39894 0.009796142578125 +39895 0.171234130859375 +39896 0.009735107421875 +39897 0.118438720703125 +39898 0.009033203125 +39899 0.05706787109375 +39900 0.0076904296875 +39901 -0.010711669921875 +39902 0.00537109375 +39903 -0.0914306640625 +39904 0.0029296875 +39905 -0.162322998046875 +39906 0.00152587890625 +39907 -0.194549560546875 +39908 0.002716064453125 +39909 -0.1492919921875 +39910 0.0067138671875 +39911 -0.02166748046875 +39912 0.011016845703125 +39913 0.124053955078125 +39914 0.012664794921875 +39915 0.211151123046875 +39916 0.011810302734375 +39917 0.240447998046875 +39918 0.009765625 +39919 0.242218017578125 +39920 0.007049560546875 +39921 0.2257080078125 +39922 0.00390625 +39923 0.194366455078125 +39924 -0.0008544921875 +39925 0.115509033203125 +39926 -0.006134033203125 +39927 0.0128173828125 +39928 -0.009521484375 +39929 -0.053802490234375 +39930 -0.012054443359375 +39931 -0.110626220703125 +39932 -0.015411376953125 +39933 -0.199493408203125 +39934 -0.018585205078125 +39935 -0.29437255859375 +39936 -0.01947021484375 +39937 -0.33221435546875 +39938 -0.01751708984375 +39939 -0.27972412109375 +39940 -0.013671875 +39941 -0.185333251953125 +39942 -0.00909423828125 +39943 -0.128204345703125 +39944 -0.004302978515625 +39945 -0.115692138671875 +39946 0.000457763671875 +39947 -0.116455078125 +39948 0.005035400390625 +39949 -0.105926513671875 +39950 0.0093994140625 +39951 -0.053955078125 +39952 0.01336669921875 +39953 0.048797607421875 +39954 0.01641845703125 +39955 0.157318115234375 +39956 0.01800537109375 +39957 0.212005615234375 +39958 0.018157958984375 +39959 0.218475341796875 +39960 0.01739501953125 +39961 0.23724365234375 +39962 0.01611328125 +39963 0.30535888671875 +39964 0.01409912109375 +39965 0.38128662109375 +39966 0.011077880859375 +39967 0.404449462890625 +39968 0.007415771484375 +39969 0.3944091796875 +39970 0.003631591796875 +39971 0.3885498046875 +39972 -0.000213623046875 +39973 0.362640380859375 +39974 -0.0042724609375 +39975 0.27362060546875 +39976 -0.008392333984375 +39977 0.11712646484375 +39978 -0.011993408203125 +39979 -0.054901123046875 +39980 -0.014556884765625 +39981 -0.19085693359375 +39982 -0.0159912109375 +39983 -0.28570556640625 +39984 -0.01629638671875 +39985 -0.339263916015625 +39986 -0.015716552734375 +39987 -0.3775634765625 +39988 -0.014678955078125 +39989 -0.445709228515625 +39990 -0.01318359375 +39991 -0.535064697265625 +39992 -0.01129150390625 +39993 -0.629058837890625 +39994 -0.008880615234375 +39995 -0.697601318359375 +39996 -0.005828857421875 +39997 -0.70391845703125 +39998 -0.002288818359375 +39999 -0.6424560546875 +40000 0.001708984375 +40001 -0.491241455078125 +40002 0.00592041015625 +40003 -0.265716552734375 +40004 0.009735107421875 +40005 -0.023712158203125 +40006 0.012786865234375 +40007 0.201751708984375 +40008 0.0147705078125 +40009 0.375823974609375 +40010 0.015594482421875 +40011 0.485076904296875 +40012 0.015594482421875 +40013 0.56884765625 +40014 0.014862060546875 +40015 0.634765625 +40016 0.01312255859375 +40017 0.63763427734375 +40018 0.010406494140625 +40019 0.5660400390625 +40020 0.00726318359375 +40021 0.4720458984375 +40022 0.004241943359375 +40023 0.40692138671875 +40024 0.00152587890625 +40025 0.3778076171875 +40026 -0.000823974609375 +40027 0.376953125 +40028 -0.0029296875 +40029 0.371978759765625 +40030 -0.005096435546875 +40031 0.313140869140625 +40032 -0.00732421875 +40033 0.184417724609375 +40034 -0.009368896484375 +40035 0.011199951171875 +40036 -0.010894775390625 +40037 -0.171051025390625 +40038 -0.01171875 +40039 -0.33740234375 +40040 -0.011749267578125 +40041 -0.47198486328125 +40042 -0.010955810546875 +40043 -0.560394287109375 +40044 -0.009246826171875 +40045 -0.58056640625 +40046 -0.00689697265625 +40047 -0.54754638671875 +40048 -0.004425048828125 +40049 -0.508575439453125 +40050 -0.00189208984375 +40051 -0.459503173828125 +40052 0.0006103515625 +40053 -0.394378662109375 +40054 0.002685546875 +40055 -0.35260009765625 +40056 0.00439453125 +40057 -0.31170654296875 +40058 0.00628662109375 +40059 -0.197418212890625 +40060 0.00830078125 +40061 -0.007965087890625 +40062 0.010040283203125 +40063 0.207489013671875 +40064 0.01116943359375 +40065 0.409210205078125 +40066 0.011566162109375 +40067 0.57208251953125 +40068 0.01104736328125 +40069 0.66595458984375 +40070 0.00946044921875 +40071 0.65875244140625 +40072 0.00701904296875 +40073 0.56744384765625 +40074 0.004150390625 +40075 0.431396484375 +40076 0.00128173828125 +40077 0.29443359375 +40078 -0.001251220703125 +40079 0.182464599609375 +40080 -0.00360107421875 +40081 0.06365966796875 +40082 -0.005828857421875 +40083 -0.075958251953125 +40084 -0.00750732421875 +40085 -0.189422607421875 +40086 -0.008544921875 +40087 -0.271942138671875 +40088 -0.009063720703125 +40089 -0.342529296875 +40090 -0.00885009765625 +40091 -0.364166259765625 +40092 -0.007843017578125 +40093 -0.327239990234375 +40094 -0.006439208984375 +40095 -0.2769775390625 +40096 -0.005035400390625 +40097 -0.253692626953125 +40098 -0.00360107421875 +40099 -0.24365234375 +40100 -0.001800537109375 +40101 -0.1983642578125 +40102 0.000244140625 +40103 -0.116241455078125 +40104 0.002166748046875 +40105 -0.036834716796875 +40106 0.00384521484375 +40107 0.034881591796875 +40108 0.00518798828125 +40109 0.09124755859375 +40110 0.0059814453125 +40111 0.10888671875 +40112 0.006500244140625 +40113 0.125518798828125 +40114 0.0068359375 +40115 0.15771484375 +40116 0.00677490234375 +40117 0.17828369140625 +40118 0.006195068359375 +40119 0.17108154296875 +40120 0.005126953125 +40121 0.129974365234375 +40122 0.003814697265625 +40123 0.082427978515625 +40124 0.002288818359375 +40125 0.027679443359375 +40126 0.000396728515625 +40127 -0.065643310546875 +40128 -0.00146484375 +40129 -0.15936279296875 +40130 -0.0029296875 +40131 -0.21307373046875 +40132 -0.0040283203125 +40133 -0.234649658203125 +40134 -0.0045166015625 +40135 -0.2001953125 +40136 -0.004425048828125 +40137 -0.119171142578125 +40138 -0.003997802734375 +40139 -0.024749755859375 +40140 -0.003173828125 +40141 0.085784912109375 +40142 -0.002288818359375 +40143 0.178131103515625 +40144 -0.001617431640625 +40145 0.215576171875 +40146 -0.0010986328125 +40147 0.211456298828125 +40148 -0.00067138671875 +40149 0.17523193359375 +40150 -0.00018310546875 +40151 0.128753662109375 +40152 0.00054931640625 +40153 0.1019287109375 +40154 0.001251220703125 +40155 0.0743408203125 +40156 0.001861572265625 +40157 0.04327392578125 +40158 0.002593994140625 +40159 0.038177490234375 +40160 0.00347900390625 +40161 0.076263427734375 +40162 0.00439453125 +40163 0.14105224609375 +40164 0.00494384765625 +40165 0.186431884765625 +40166 0.00494384765625 +40167 0.188812255859375 +40168 0.00433349609375 +40169 0.1390380859375 +40170 0.003173828125 +40171 0.041778564453125 +40172 0.001708984375 +40173 -0.079437255859375 +40174 0.0 +40175 -0.219390869140625 +40176 -0.001800537109375 +40177 -0.367828369140625 +40178 -0.00341796875 +40179 -0.494873046875 +40180 -0.004486083984375 +40181 -0.556243896484375 +40182 -0.004638671875 +40183 -0.508697509765625 +40184 -0.0040283203125 +40185 -0.3756103515625 +40186 -0.00311279296875 +40187 -0.218902587890625 +40188 -0.00213623046875 +40189 -0.063751220703125 +40190 -0.001068115234375 +40191 0.091552734375 +40192 3.0517578125e-05 +40193 0.23602294921875 +40194 0.000946044921875 +40195 0.342987060546875 +40196 0.00140380859375 +40197 0.39520263671875 +40198 0.001251220703125 +40199 0.389373779296875 +40200 0.000335693359375 +40201 0.324249267578125 +40202 -0.000885009765625 +40203 0.224090576171875 +40204 -0.001739501953125 +40205 0.124267578125 +40206 -0.002044677734375 +40207 0.037078857421875 +40208 -0.00128173828125 +40209 -0.010101318359375 +40210 0.000335693359375 +40211 -0.019439697265625 +40212 0.001953125 +40213 -0.022796630859375 +40214 0.003936767578125 +40215 -0.001556396484375 +40216 0.006439208984375 +40217 0.056304931640625 +40218 0.008392333984375 +40219 0.106719970703125 +40220 0.008514404296875 +40221 0.096893310546875 +40222 0.0072021484375 +40223 0.042694091796875 +40224 0.005401611328125 +40225 -0.018035888671875 +40226 0.00335693359375 +40227 -0.07586669921875 +40228 0.00140380859375 +40229 -0.11944580078125 +40230 -0.00067138671875 +40231 -0.15972900390625 +40232 -0.0029296875 +40233 -0.202606201171875 +40234 -0.0052490234375 +40235 -0.24859619140625 +40236 -0.007781982421875 +40237 -0.30517578125 +40238 -0.010223388671875 +40239 -0.36212158203125 +40240 -0.011871337890625 +40241 -0.39141845703125 +40242 -0.011749267578125 +40243 -0.35528564453125 +40244 -0.009735107421875 +40245 -0.249969482421875 +40246 -0.0062255859375 +40247 -0.092864990234375 +40248 -0.00189208984375 +40249 0.08905029296875 +40250 0.001800537109375 +40251 0.2352294921875 +40252 0.004180908203125 +40253 0.318817138671875 +40254 0.005706787109375 +40255 0.358642578125 +40256 0.00616455078125 +40257 0.347747802734375 +40258 0.005462646484375 +40259 0.28564453125 +40260 0.00482177734375 +40261 0.223175048828125 +40262 0.005035400390625 +40263 0.196746826171875 +40264 0.00543212890625 +40265 0.179840087890625 +40266 0.005584716796875 +40267 0.155548095703125 +40268 0.006072998046875 +40269 0.151214599609375 +40270 0.00665283203125 +40271 0.156951904296875 +40272 0.006317138671875 +40273 0.13177490234375 +40274 0.005645751953125 +40275 0.100799560546875 +40276 0.005218505859375 +40277 0.087127685546875 +40278 0.004180908203125 +40279 0.05487060546875 +40280 0.002227783203125 +40281 -0.009002685546875 +40282 -0.00054931640625 +40283 -0.10400390625 +40284 -0.004150390625 +40285 -0.229400634765625 +40286 -0.0078125 +40287 -0.35552978515625 +40288 -0.010498046875 +40289 -0.441925048828125 +40290 -0.011810302734375 +40291 -0.473846435546875 +40292 -0.0120849609375 +40293 -0.464813232421875 +40294 -0.011383056640625 +40295 -0.419097900390625 +40296 -0.0096435546875 +40297 -0.334320068359375 +40298 -0.00726318359375 +40299 -0.227935791015625 +40300 -0.004791259765625 +40301 -0.12347412109375 +40302 -0.00238037109375 +40303 -0.02764892578125 +40304 0.0003662109375 +40305 0.077667236328125 +40306 0.00390625 +40307 0.2132568359375 +40308 0.008453369140625 +40309 0.38885498046875 +40310 0.01348876953125 +40311 0.582794189453125 +40312 0.01751708984375 +40313 0.734039306640625 +40314 0.01947021484375 +40315 0.800140380859375 +40316 0.019256591796875 +40317 0.7783203125 +40318 0.016815185546875 +40319 0.6651611328125 +40320 0.012115478515625 +40321 0.45965576171875 +40322 0.006072998046875 +40323 0.199188232421875 +40324 0.000244140625 +40325 -0.050689697265625 +40326 -0.003997802734375 +40327 -0.23297119140625 +40328 -0.006256103515625 +40329 -0.33013916015625 +40330 -0.007171630859375 +40331 -0.368408203125 +40332 -0.007476806640625 +40333 -0.378936767578125 +40334 -0.007568359375 +40335 -0.376983642578125 +40336 -0.007843017578125 +40337 -0.37969970703125 +40338 -0.00836181640625 +40339 -0.391510009765625 +40340 -0.008453369140625 +40341 -0.385345458984375 +40342 -0.007659912109375 +40343 -0.3419189453125 +40344 -0.0064697265625 +40345 -0.28289794921875 +40346 -0.00592041015625 +40347 -0.251617431640625 +40348 -0.006439208984375 +40349 -0.266143798828125 +40350 -0.006744384765625 +40351 -0.273345947265625 +40352 -0.0054931640625 +40353 -0.216796875 +40354 -0.003448486328125 +40355 -0.128265380859375 +40356 -0.00201416015625 +40357 -0.068145751953125 +40358 -0.0013427734375 +40359 -0.0430908203125 +40360 -0.000762939453125 +40361 -0.024444580078125 +40362 0.000457763671875 +40363 0.020721435546875 +40364 0.003082275390625 +40365 0.124481201171875 +40366 0.00640869140625 +40367 0.25787353515625 +40368 0.0093994140625 +40369 0.379119873046875 +40370 0.011871337890625 +40371 0.47991943359375 +40372 0.0130615234375 +40373 0.5281982421875 +40374 0.01263427734375 +40375 0.511138916015625 +40376 0.01129150390625 +40377 0.456207275390625 +40378 0.01007080078125 +40379 0.407470703125 +40380 0.009429931640625 +40381 0.383758544921875 +40382 0.008636474609375 +40383 0.35687255859375 +40384 0.00738525390625 +40385 0.31182861328125 +40386 0.0057373046875 +40387 0.250885009765625 +40388 0.0035400390625 +40389 0.1654052734375 +40390 0.00030517578125 +40391 0.035247802734375 +40392 -0.00396728515625 +40393 -0.142059326171875 +40394 -0.008544921875 +40395 -0.33563232421875 +40396 -0.01318359375 +40397 -0.5345458984375 +40398 -0.01751708984375 +40399 -0.72186279296875 +40400 -0.02001953125 +40401 -0.836669921875 +40402 -0.019622802734375 +40403 -0.8326416015625 +40404 -0.016845703125 +40405 -0.7296142578125 +40406 -0.0130615234375 +40407 -0.582550048828125 +40408 -0.009429931640625 +40409 -0.440093994140625 +40410 -0.006500244140625 +40411 -0.324310302734375 +40412 -0.00341796875 +40413 -0.20147705078125 +40414 0.00042724609375 +40415 -0.044647216796875 +40416 0.003997802734375 +40417 0.103973388671875 +40418 0.006256103515625 +40419 0.202392578125 +40420 0.007568359375 +40421 0.264495849609375 +40422 0.009124755859375 +40423 0.338897705078125 +40424 0.0113525390625 +40425 0.443817138671875 +40426 0.013458251953125 +40427 0.545074462890625 +40428 0.014862060546875 +40429 0.6173095703125 +40430 0.015380859375 +40431 0.6524658203125 +40432 0.01531982421875 +40433 0.66339111328125 +40434 0.014862060546875 +40435 0.6561279296875 +40436 0.013427734375 +40437 0.606781005859375 +40438 0.01068115234375 +40439 0.501190185546875 +40440 0.006988525390625 +40441 0.352783203125 +40442 0.002685546875 +40443 0.176544189453125 +40444 -0.0023193359375 +40445 -0.034820556640625 +40446 -0.007476806640625 +40447 -0.258209228515625 +40448 -0.011383056640625 +40449 -0.44244384765625 +40450 -0.013946533203125 +40451 -0.5753173828125 +40452 -0.01495361328125 +40453 -0.65203857421875 +40454 -0.0126953125 +40455 -0.641632080078125 +40456 -0.008056640625 +40457 -0.562164306640625 +40458 -0.00341796875 +40459 -0.458038330078125 +40460 0.000213623046875 +40461 -0.350555419921875 +40462 0.00189208984375 +40463 -0.260528564453125 +40464 0.001617431640625 +40465 -0.192108154296875 +40466 -0.0001220703125 +40467 -0.141937255859375 +40468 -0.00262451171875 +40469 -0.1021728515625 +40470 -0.005096435546875 +40471 -0.062896728515625 +40472 -0.006591796875 +40473 -0.011932373046875 +40474 -0.0062255859375 +40475 0.062835693359375 +40476 -0.0045166015625 +40477 0.148712158203125 +40478 -0.0015869140625 +40479 0.241729736328125 +40480 0.0030517578125 +40481 0.34912109375 +40482 0.0086669921875 +40483 0.457305908203125 +40484 0.014007568359375 +40485 0.54388427734375 +40486 0.016998291015625 +40487 0.5728759765625 +40488 0.01544189453125 +40489 0.506591796875 +40490 0.009552001953125 +40491 0.351226806640625 +40492 0.001373291015625 +40493 0.146514892578125 +40494 -0.00634765625 +40495 -0.05523681640625 +40496 -0.011688232421875 +40497 -0.21624755859375 +40498 -0.014739990234375 +40499 -0.334930419921875 +40500 -0.01519775390625 +40501 -0.402984619140625 +40502 -0.01446533203125 +40503 -0.4412841796875 +40504 -0.0152587890625 +40505 -0.49578857421875 +40506 -0.017333984375 +40507 -0.5601806640625 +40508 -0.01885986328125 +40509 -0.600738525390625 +40510 -0.01800537109375 +40511 -0.584228515625 +40512 -0.012969970703125 +40513 -0.47930908203125 +40514 -0.003326416015625 +40515 -0.27935791015625 +40516 0.0096435546875 +40517 -0.0089111328125 +40518 0.02252197265625 +40519 0.268798828125 +40520 0.031494140625 +40521 0.482818603515625 +40522 0.03509521484375 +40523 0.60369873046875 +40524 0.0345458984375 +40525 0.650421142578125 +40526 0.0323486328125 +40527 0.66400146484375 +40528 0.028472900390625 +40529 0.6414794921875 +40530 0.0224609375 +40531 0.572540283203125 +40532 0.0167236328125 +40533 0.498138427734375 +40534 0.01251220703125 +40535 0.439453125 +40536 0.008697509765625 +40537 0.375518798828125 +40538 0.003509521484375 +40539 0.274505615234375 +40540 -0.004638671875 +40541 0.1087646484375 +40542 -0.01458740234375 +40543 -0.099395751953125 +40544 -0.024658203125 +40545 -0.3182373046875 +40546 -0.035064697265625 +40547 -0.5489501953125 +40548 -0.044921875 +40549 -0.7738037109375 +40550 -0.051422119140625 +40551 -0.86383056640625 +40552 -0.052886962890625 +40553 -0.870391845703125 +40554 -0.050445556640625 +40555 -0.86895751953125 +40556 -0.044952392578125 +40557 -0.861053466796875 +40558 -0.0355224609375 +40559 -0.765869140625 +40560 -0.021636962890625 +40561 -0.5301513671875 +40562 -0.00372314453125 +40563 -0.214691162109375 +40564 0.015777587890625 +40565 0.137359619140625 +40566 0.034027099609375 +40567 0.474822998046875 +40568 0.049102783203125 +40569 0.76239013671875 +40570 0.0595703125 +40571 0.867462158203125 +40572 0.065582275390625 +40573 0.870361328125 +40574 0.066558837890625 +40575 0.86480712890625 +40576 0.062957763671875 +40577 0.831817626953125 +40578 0.056304931640625 +40579 0.677581787109375 +40580 0.047027587890625 +40581 0.495880126953125 +40582 0.03631591796875 +40583 0.30767822265625 +40584 0.0244140625 +40585 0.116180419921875 +40586 0.00958251953125 +40587 -0.110748291015625 +40588 -0.00848388671875 +40589 -0.381805419921875 +40590 -0.027374267578125 +40591 -0.6572265625 +40592 -0.043731689453125 +40593 -0.857421875 +40594 -0.055206298828125 +40595 -0.870391845703125 +40596 -0.061492919921875 +40597 -0.870391845703125 +40598 -0.064208984375 +40599 -0.86444091796875 +40600 -0.06549072265625 +40601 -0.85723876953125 +40602 -0.064422607421875 +40603 -0.790008544921875 +40604 -0.05810546875 +40605 -0.62847900390625 +40606 -0.046417236328125 +40607 -0.3956298828125 +40608 -0.03131103515625 +40609 -0.126708984375 +40610 -0.014434814453125 +40611 0.150115966796875 +40612 0.00347900390625 +40613 0.424041748046875 +40614 0.020904541015625 +40615 0.670623779296875 +40616 0.03564453125 +40617 0.854522705078125 +40618 0.046722412109375 +40619 0.866485595703125 +40620 0.053314208984375 +40621 0.86920166015625 +40622 0.0565185546875 +40623 0.8653564453125 +40624 0.05712890625 +40625 0.857147216796875 +40626 0.05511474609375 +40627 0.766845703125 +40628 0.050872802734375 +40629 0.628509521484375 +40630 0.044097900390625 +40631 0.462127685546875 +40632 0.03631591796875 +40633 0.297210693359375 +40634 0.028289794921875 +40635 0.14862060546875 +40636 0.01885986328125 +40637 -0.00537109375 +40638 0.00848388671875 +40639 -0.15753173828125 +40640 -0.002960205078125 +40641 -0.31304931640625 +40642 -0.016204833984375 +40643 -0.48876953125 +40644 -0.02862548828125 +40645 -0.6416015625 +40646 -0.03887939453125 +40647 -0.751373291015625 +40648 -0.048309326171875 +40649 -0.84619140625 +40650 -0.056182861328125 +40651 -0.861297607421875 +40652 -0.060699462890625 +40653 -0.863250732421875 +40654 -0.0601806640625 +40655 -0.856597900390625 +40656 -0.055419921875 +40657 -0.7498779296875 +40658 -0.04974365234375 +40659 -0.624542236328125 +40660 -0.042022705078125 +40661 -0.47808837890625 +40662 -0.029052734375 +40663 -0.253387451171875 +40664 -0.013458251953125 +40665 0.003692626953125 +40666 0.000885009765625 +40667 0.2257080078125 +40668 0.014678955078125 +40669 0.427154541015625 +40670 0.029693603515625 +40671 0.643218994140625 +40672 0.04541015625 +40673 0.855926513671875 +40674 0.05865478515625 +40675 0.870361328125 +40676 0.06671142578125 +40677 0.870361328125 +40678 0.070068359375 +40679 0.862762451171875 +40680 0.068634033203125 +40681 0.79669189453125 +40682 0.06195068359375 +40683 0.595794677734375 +40684 0.0517578125 +40685 0.362152099609375 +40686 0.039703369140625 +40687 0.1270751953125 +40688 0.027008056640625 +40689 -0.086944580078125 +40690 0.01385498046875 +40691 -0.2784423828125 +40692 -0.001617431640625 +40693 -0.484832763671875 +40694 -0.020477294921875 +40695 -0.729583740234375 +40696 -0.0399169921875 +40697 -0.86688232421875 +40698 -0.056396484375 +40699 -0.870391845703125 +40700 -0.06964111328125 +40701 -0.86859130859375 +40702 -0.07958984375 +40703 -0.86279296875 +40704 -0.084381103515625 +40705 -0.817962646484375 +40706 -0.081207275390625 +40707 -0.6116943359375 +40708 -0.069488525390625 +40709 -0.3128662109375 +40710 -0.051361083984375 +40711 0.039398193359375 +40712 -0.0277099609375 +40713 0.422821044921875 +40714 -0.000640869140625 +40715 0.805145263671875 +40716 0.024688720703125 +40717 0.870361328125 +40718 0.044036865234375 +40719 0.870361328125 +40720 0.057037353515625 +40721 0.860015869140625 +40722 0.0635986328125 +40723 0.727935791015625 +40724 0.06365966796875 +40725 0.48114013671875 +40726 0.05963134765625 +40727 0.2059326171875 +40728 0.053680419921875 +40729 -0.06103515625 +40730 0.04669189453125 +40731 -0.29913330078125 +40732 0.03729248046875 +40733 -0.516204833984375 +40734 0.02392578125 +40735 -0.7252197265625 +40736 0.00848388671875 +40737 -0.85980224609375 +40738 -0.00640869140625 +40739 -0.870391845703125 +40740 -0.0185546875 +40741 -0.870391845703125 +40742 -0.024169921875 +40743 -0.858062744140625 +40744 -0.023345947265625 +40745 -0.673004150390625 +40746 -0.021148681640625 +40747 -0.42694091796875 +40748 -0.0218505859375 +40749 -0.2100830078125 +40750 -0.02557373046875 +40751 -0.0362548828125 +40752 -0.029998779296875 +40753 0.10943603515625 +40754 -0.033447265625 +40755 0.23516845703125 +40756 -0.0323486328125 +40757 0.373687744140625 +40758 -0.02685546875 +40759 0.517791748046875 +40760 -0.022369384765625 +40761 0.602783203125 +40762 -0.01824951171875 +40763 0.635711669921875 +40764 -0.01129150390625 +40765 0.655181884765625 +40766 -0.00201416015625 +40767 0.65948486328125 +40768 0.009185791015625 +40769 0.651275634765625 +40770 0.020477294921875 +40771 0.61846923828125 +40772 0.0289306640625 +40773 0.53753662109375 +40774 0.033294677734375 +40775 0.404144287109375 +40776 0.03302001953125 +40777 0.22186279296875 +40778 0.0284423828125 +40779 0.003997802734375 +40780 0.021331787109375 +40781 -0.22100830078125 +40782 0.013519287109375 +40783 -0.42449951171875 +40784 0.00689697265625 +40785 -0.579833984375 +40786 0.005126953125 +40787 -0.641876220703125 +40788 0.0074462890625 +40789 -0.6177978515625 +40790 0.00799560546875 +40791 -0.575531005859375 +40792 0.00604248046875 +40793 -0.526336669921875 +40794 0.005859375 +40795 -0.42645263671875 +40796 0.009552001953125 +40797 -0.2581787109375 +40798 0.013641357421875 +40799 -0.068695068359375 +40800 0.014495849609375 +40801 0.09222412109375 +40802 0.013519287109375 +40803 0.232147216796875 +40804 0.011444091796875 +40805 0.3509521484375 +40806 0.00555419921875 +40807 0.410064697265625 +40808 -0.00677490234375 +40809 0.372955322265625 +40810 -0.023712158203125 +40811 0.2554931640625 +40812 -0.040618896484375 +40813 0.10711669921875 +40814 -0.055633544921875 +40815 -0.052886962890625 +40816 -0.065460205078125 +40817 -0.186279296875 +40818 -0.06500244140625 +40819 -0.23291015625 +40820 -0.0560302734375 +40821 -0.209442138671875 +40822 -0.04412841796875 +40823 -0.174163818359375 +40824 -0.029815673828125 +40825 -0.126739501953125 +40826 -0.01202392578125 +40827 -0.048126220703125 +40828 0.0069580078125 +40829 0.0426025390625 +40830 0.023162841796875 +40831 0.10748291015625 +40832 0.0355224609375 +40833 0.1409912109375 +40834 0.04827880859375 +40835 0.19708251953125 +40836 0.0609130859375 +40837 0.273651123046875 +40838 0.068511962890625 +40839 0.31768798828125 +40840 0.071990966796875 +40841 0.341094970703125 +40842 0.073455810546875 +40843 0.368011474609375 +40844 0.07073974609375 +40845 0.37249755859375 +40846 0.059356689453125 +40847 0.30072021484375 +40848 0.039520263671875 +40849 0.1517333984375 +40850 0.01690673828125 +40851 -0.01470947265625 +40852 -0.007080078125 +40853 -0.1883544921875 +40854 -0.032257080078125 +40855 -0.372711181640625 +40856 -0.053375244140625 +40857 -0.51397705078125 +40858 -0.06640625 +40859 -0.57177734375 +40860 -0.07037353515625 +40861 -0.53948974609375 +40862 -0.0665283203125 +40863 -0.43511962890625 +40864 -0.05792236328125 +40865 -0.2962646484375 +40866 -0.047760009765625 +40867 -0.161102294921875 +40868 -0.0372314453125 +40869 -0.0435791015625 +40870 -0.026031494140625 +40871 0.060394287109375 +40872 -0.01556396484375 +40873 0.13665771484375 +40874 -0.007415771484375 +40875 0.170135498046875 +40876 -0.00152587890625 +40877 0.16552734375 +40878 0.0047607421875 +40879 0.15728759765625 +40880 0.011505126953125 +40881 0.150787353515625 +40882 0.016143798828125 +40883 0.12200927734375 +40884 0.01910400390625 +40885 0.080108642578125 +40886 0.022369384765625 +40887 0.05126953125 +40888 0.028045654296875 +40889 0.062896728515625 +40890 0.033966064453125 +40891 0.09271240234375 +40892 0.035797119140625 +40893 0.092987060546875 +40894 0.0347900390625 +40895 0.07855224609375 +40896 0.032257080078125 +40897 0.06427001953125 +40898 0.0269775390625 +40899 0.0347900390625 +40900 0.018951416015625 +40901 -0.01171875 +40902 0.010162353515625 +40903 -0.056060791015625 +40904 0.004638671875 +40905 -0.055511474609375 +40906 0.002655029296875 +40907 -0.010467529296875 +40908 -0.000152587890625 +40909 0.02508544921875 +40910 -0.005706787109375 +40911 0.025665283203125 +40912 -0.01141357421875 +40913 0.017333984375 +40914 -0.016876220703125 +40915 0.00189208984375 +40916 -0.022857666015625 +40917 -0.03173828125 +40918 -0.028167724609375 +40919 -0.071502685546875 +40920 -0.034332275390625 +40921 -0.13543701171875 +40922 -0.041015625 +40923 -0.219970703125 +40924 -0.046142578125 +40925 -0.300506591796875 +40926 -0.0498046875 +40927 -0.376312255859375 +40928 -0.0494384765625 +40929 -0.416107177734375 +40930 -0.041015625 +40931 -0.371124267578125 +40932 -0.024871826171875 +40933 -0.242279052734375 +40934 -0.00482177734375 +40935 -0.069732666015625 +40936 0.01702880859375 +40937 0.125640869140625 +40938 0.037689208984375 +40939 0.31268310546875 +40940 0.0537109375 +40941 0.45501708984375 +40942 0.06512451171875 +40943 0.554779052734375 +40944 0.07171630859375 +40945 0.61065673828125 +40946 0.072357177734375 +40947 0.610931396484375 +40948 0.06494140625 +40949 0.531463623046875 +40950 0.05096435546875 +40951 0.3883056640625 +40952 0.03521728515625 +40953 0.23468017578125 +40954 0.02001953125 +40955 0.095245361328125 +40956 0.0078125 +40957 -0.00396728515625 +40958 3.0517578125e-05 +40959 -0.04852294921875 +40960 -0.004302978515625 +40961 -0.055145263671875 +40962 -0.009674072265625 +40963 -0.0758056640625 +40964 -0.018646240234375 +40965 -0.138702392578125 +40966 -0.027740478515625 +40967 -0.209197998046875 +40968 -0.037139892578125 +40969 -0.289031982421875 +40970 -0.04693603515625 +40971 -0.37884521484375 +40972 -0.054931640625 +40973 -0.456329345703125 +40974 -0.060638427734375 +40975 -0.51641845703125 +40976 -0.060150146484375 +40977 -0.519287109375 +40978 -0.0528564453125 +40979 -0.458251953125 +40980 -0.043975830078125 +40981 -0.384796142578125 +40982 -0.036102294921875 +40983 -0.323699951171875 +40984 -0.028717041015625 +40985 -0.269287109375 +40986 -0.019317626953125 +40987 -0.1951904296875 +40988 -0.00787353515625 +40989 -0.100006103515625 +40990 0.0028076171875 +40991 -0.01055908203125 +40992 0.015625 +40993 0.1033935546875 +40994 0.03125 +40995 0.24908447265625 +40996 0.044342041015625 +40997 0.373199462890625 +40998 0.0531005859375 +40999 0.45806884765625 +41000 0.05828857421875 +41001 0.511474609375 +41002 0.063140869140625 +41003 0.565399169921875 +41004 0.06683349609375 +41005 0.61138916015625 +41006 0.0634765625 +41007 0.5897216796875 +41008 0.052154541015625 +41009 0.4906005859375 +41010 0.034698486328125 +41011 0.33148193359375 +41012 0.0147705078125 +41013 0.147796630859375 +41014 -0.00335693359375 +41015 -0.01873779296875 +41016 -0.016845703125 +41017 -0.140289306640625 +41018 -0.02313232421875 +41019 -0.191986083984375 +41020 -0.023223876953125 +41021 -0.184295654296875 +41022 -0.021514892578125 +41023 -0.161834716796875 +41024 -0.022216796875 +41025 -0.166595458984375 +41026 -0.02484130859375 +41027 -0.19390869140625 +41028 -0.0274658203125 +41029 -0.22442626953125 +41030 -0.03228759765625 +41031 -0.279754638671875 +41032 -0.037261962890625 +41033 -0.3389892578125 +41034 -0.03765869140625 +41035 -0.3543701171875 +41036 -0.035797119140625 +41037 -0.348175048828125 +41038 -0.032318115234375 +41039 -0.32598876953125 +41040 -0.0242919921875 +41041 -0.2581787109375 +41042 -0.01129150390625 +41043 -0.139801025390625 +41044 0.005126953125 +41045 0.014617919921875 +41046 0.018829345703125 +41047 0.144378662109375 +41048 0.026947021484375 +41049 0.221038818359375 +41050 0.032073974609375 +41051 0.27069091796875 +41052 0.034271240234375 +41053 0.294036865234375 +41054 0.03564453125 +41055 0.311767578125 +41056 0.037811279296875 +41057 0.339141845703125 +41058 0.03948974609375 +41059 0.360260009765625 +41060 0.0391845703125 +41061 0.360504150390625 +41062 0.03302001953125 +41063 0.308380126953125 +41064 0.018218994140625 +41065 0.18170166015625 +41066 -0.002288818359375 +41067 0.0047607421875 +41068 -0.02301025390625 +41069 -0.17559814453125 +41070 -0.038604736328125 +41071 -0.3143310546875 +41072 -0.043975830078125 +41073 -0.36785888671875 +41074 -0.042327880859375 +41075 -0.36248779296875 +41076 -0.039154052734375 +41077 -0.343536376953125 +41078 -0.033416748046875 +41079 -0.3018798828125 +41080 -0.0244140625 +41081 -0.231414794921875 +41082 -0.01043701171875 +41083 -0.117645263671875 +41084 0.004608154296875 +41085 0.007049560546875 +41086 0.01416015625 +41087 0.087982177734375 +41088 0.01995849609375 +41089 0.13946533203125 +41090 0.023590087890625 +41091 0.17425537109375 +41092 0.02459716796875 +41093 0.188201904296875 +41094 0.02178955078125 +41095 0.171234130859375 +41096 0.0146484375 +41097 0.118438720703125 +41098 0.00653076171875 +41099 0.05706787109375 +41100 -0.00225830078125 +41101 -0.010711669921875 +41102 -0.012481689453125 +41103 -0.0914306640625 +41104 -0.021392822265625 +41105 -0.162322998046875 +41106 -0.025543212890625 +41107 -0.194549560546875 +41108 -0.020233154296875 +41109 -0.1492919921875 +41110 -0.0048828125 +41111 -0.02166748046875 +41112 0.01275634765625 +41113 0.124053955078125 +41114 0.0234375 +41115 0.211151123046875 +41116 0.027252197265625 +41117 0.240447998046875 +41118 0.02783203125 +41119 0.242218017578125 +41120 0.026275634765625 +41121 0.2257080078125 +41122 0.022979736328125 +41123 0.194366455078125 +41124 0.01397705078125 +41125 0.115509033203125 +41126 0.00213623046875 +41127 0.0128173828125 +41128 -0.00537109375 +41129 -0.053802490234375 +41130 -0.011749267578125 +41131 -0.110626220703125 +41132 -0.02203369140625 +41133 -0.199493408203125 +41134 -0.03314208984375 +41135 -0.29437255859375 +41136 -0.037506103515625 +41137 -0.33221435546875 +41138 -0.031158447265625 +41139 -0.27972412109375 +41140 -0.0198974609375 +41141 -0.185333251953125 +41142 -0.013214111328125 +41143 -0.128204345703125 +41144 -0.011962890625 +41145 -0.115692138671875 +41146 -0.01239013671875 +41147 -0.116455078125 +41148 -0.011505126953125 +41149 -0.105926513671875 +41150 -0.00567626953125 +41151 -0.053955078125 +41152 0.0062255859375 +41153 0.048797607421875 +41154 0.018798828125 +41155 0.157318115234375 +41156 0.02490234375 +41157 0.212005615234375 +41158 0.0252685546875 +41159 0.218475341796875 +41160 0.027191162109375 +41161 0.23724365234375 +41162 0.035125732421875 +41163 0.30535888671875 +41164 0.044097900390625 +41165 0.38128662109375 +41166 0.046783447265625 +41167 0.404449462890625 +41168 0.045562744140625 +41169 0.3944091796875 +41170 0.044952392578125 +41171 0.3885498046875 +41172 0.042022705078125 +41173 0.362640380859375 +41174 0.0316162109375 +41175 0.27362060546875 +41176 0.01318359375 +41177 0.11712646484375 +41178 -0.007049560546875 +41179 -0.054901123046875 +41180 -0.022918701171875 +41181 -0.19085693359375 +41182 -0.033843994140625 +41183 -0.28570556640625 +41184 -0.039825439453125 +41185 -0.339263916015625 +41186 -0.04400634765625 +41187 -0.3775634765625 +41188 -0.05181884765625 +41189 -0.445709228515625 +41190 -0.062255859375 +41191 -0.535064697265625 +41192 -0.073333740234375 +41193 -0.629058837890625 +41194 -0.0814208984375 +41195 -0.697601318359375 +41196 -0.082122802734375 +41197 -0.70391845703125 +41198 -0.074798583984375 +41199 -0.6424560546875 +41200 -0.05682373046875 +41201 -0.491241455078125 +41202 -0.029998779296875 +41203 -0.265716552734375 +41204 -0.00128173828125 +41205 -0.023712158203125 +41206 0.025360107421875 +41207 0.201751708984375 +41208 0.045745849609375 +41209 0.375823974609375 +41210 0.058349609375 +41211 0.485076904296875 +41212 0.06787109375 +41213 0.56884765625 +41214 0.075286865234375 +41215 0.634765625 +41216 0.07470703125 +41217 0.63763427734375 +41218 0.064056396484375 +41219 0.5660400390625 +41220 0.0506591796875 +41221 0.4720458984375 +41222 0.04241943359375 +41223 0.40692138671875 +41224 0.04046630859375 +41225 0.3778076171875 +41226 0.043548583984375 +41227 0.376953125 +41228 0.046630859375 +41229 0.371978759765625 +41230 0.0419921875 +41231 0.313140869140625 +41232 0.026947021484375 +41233 0.184417724609375 +41234 0.005126953125 +41235 0.011199951171875 +41236 -0.01824951171875 +41237 -0.171051025390625 +41238 -0.039642333984375 +41239 -0.33740234375 +41240 -0.056854248046875 +41241 -0.47198486328125 +41242 -0.06787109375 +41243 -0.560394287109375 +41244 -0.0694580078125 +41245 -0.58056640625 +41246 -0.06396484375 +41247 -0.54754638671875 +41248 -0.058624267578125 +41249 -0.508575439453125 +41250 -0.052703857421875 +41251 -0.459503173828125 +41252 -0.045196533203125 +41253 -0.394378662109375 +41254 -0.041900634765625 +41255 -0.35260009765625 +41256 -0.039276123046875 +41257 -0.31170654296875 +41258 -0.02581787109375 +41259 -0.197418212890625 +41260 -0.001007080078125 +41261 -0.007965087890625 +41262 0.02783203125 +41263 0.207489013671875 +41264 0.054901123046875 +41265 0.409210205078125 +41266 0.0765380859375 +41267 0.57208251953125 +41268 0.088348388671875 +41269 0.66595458984375 +41270 0.0855712890625 +41271 0.65875244140625 +41272 0.07086181640625 +41273 0.56744384765625 +41274 0.05023193359375 +41275 0.431396484375 +41276 0.030303955078125 +41277 0.29443359375 +41278 0.014923095703125 +41279 0.182464599609375 +41280 -0.00079345703125 +41281 0.06365966796875 +41282 -0.019134521484375 +41283 -0.075958251953125 +41284 -0.03314208984375 +41285 -0.189422607421875 +41286 -0.042266845703125 +41287 -0.271942138671875 +41288 -0.049591064453125 +41289 -0.342529296875 +41290 -0.049713134765625 +41291 -0.364166259765625 +41292 -0.04132080078125 +41293 -0.327239990234375 +41294 -0.03143310546875 +41295 -0.2769775390625 +41296 -0.026275634765625 +41297 -0.253692626953125 +41298 -0.0238037109375 +41299 -0.24365234375 +41300 -0.016693115234375 +41301 -0.1983642578125 +41302 -0.00469970703125 +41303 -0.116241455078125 +41304 0.00616455078125 +41305 -0.036834716796875 +41306 0.0152587890625 +41307 0.034881591796875 +41308 0.02154541015625 +41309 0.09124755859375 +41310 0.021575927734375 +41311 0.10888671875 +41312 0.021270751953125 +41313 0.125518798828125 +41314 0.0233154296875 +41315 0.15771484375 +41316 0.023712158203125 +41317 0.17828369140625 +41318 0.0201416015625 +41319 0.17108154296875 +41320 0.011810302734375 +41321 0.129974365234375 +41322 0.00299072265625 +41323 0.082427978515625 +41324 -0.00628662109375 +41325 0.027679443359375 +41326 -0.020782470703125 +41327 -0.065643310546875 +41328 -0.034698486328125 +41329 -0.15936279296875 +41330 -0.04193115234375 +41331 -0.21307373046875 +41332 -0.04376220703125 +41333 -0.234649658203125 +41334 -0.036651611328125 +41335 -0.2001953125 +41336 -0.02215576171875 +41337 -0.119171142578125 +41338 -0.00543212890625 +41339 -0.024749755859375 +41340 0.01373291015625 +41341 0.085784912109375 +41342 0.029998779296875 +41343 0.178131103515625 +41344 0.037689208984375 +41345 0.215576171875 +41346 0.038726806640625 +41347 0.211456298828125 +41348 0.034515380859375 +41349 0.17523193359375 +41350 0.0283203125 +41351 0.128753662109375 +41352 0.024627685546875 +41353 0.1019287109375 +41354 0.02032470703125 +41355 0.0743408203125 +41356 0.0150146484375 +41357 0.04327392578125 +41358 0.01318359375 +41359 0.038177490234375 +41360 0.017547607421875 +41361 0.076263427734375 +41362 0.025665283203125 +41363 0.14105224609375 +41364 0.0306396484375 +41365 0.186431884765625 +41366 0.02899169921875 +41367 0.188812255859375 +41368 0.01947021484375 +41369 0.1390380859375 +41370 0.00286865234375 +41371 0.041778564453125 +41372 -0.01708984375 +41373 -0.079437255859375 +41374 -0.03955078125 +41375 -0.219390869140625 +41376 -0.062896728515625 +41377 -0.367828369140625 +41378 -0.08251953125 +41379 -0.494873046875 +41380 -0.091705322265625 +41381 -0.556243896484375 +41382 -0.083953857421875 +41383 -0.508697509765625 +41384 -0.062835693359375 +41385 -0.3756103515625 +41386 -0.037841796875 +41387 -0.218902587890625 +41388 -0.012847900390625 +41389 -0.063751220703125 +41390 0.01226806640625 +41391 0.091552734375 +41392 0.0357666015625 +41393 0.23602294921875 +41394 0.05352783203125 +41395 0.342987060546875 +41396 0.062835693359375 +41397 0.39520263671875 +41398 0.063140869140625 +41399 0.389373779296875 +41400 0.054168701171875 +41401 0.324249267578125 +41402 0.039581298828125 +41403 0.224090576171875 +41404 0.024749755859375 +41405 0.124267578125 +41406 0.011505126953125 +41407 0.037078857421875 +41408 0.0040283203125 +41409 -0.010101318359375 +41410 0.00201416015625 +41411 -0.019439697265625 +41412 0.000640869140625 +41413 -0.022796630859375 +41414 0.0028076171875 +41415 -0.001556396484375 +41416 0.0103759765625 +41417 0.056304931640625 +41418 0.016754150390625 +41419 0.106719970703125 +41420 0.01397705078125 +41421 0.096893310546875 +41422 0.0045166015625 +41423 0.042694091796875 +41424 -0.005767822265625 +41425 -0.018035888671875 +41426 -0.015380859375 +41427 -0.07586669921875 +41428 -0.022552490234375 +41429 -0.11944580078125 +41430 -0.0289306640625 +41431 -0.15972900390625 +41432 -0.035430908203125 +41433 -0.202606201171875 +41434 -0.042083740234375 +41435 -0.24859619140625 +41436 -0.050079345703125 +41437 -0.30517578125 +41438 -0.057891845703125 +41439 -0.36212158203125 +41440 -0.06134033203125 +41441 -0.39141845703125 +41442 -0.05474853515625 +41443 -0.35528564453125 +41444 -0.037628173828125 +41445 -0.249969482421875 +41446 -0.012664794921875 +41447 -0.092864990234375 +41448 0.015960693359375 +41449 0.08905029296875 +41450 0.03900146484375 +41451 0.2352294921875 +41452 0.05230712890625 +41453 0.318817138671875 +41454 0.058746337890625 +41455 0.358642578125 +41456 0.057220458984375 +41457 0.347747802734375 +41458 0.04766845703125 +41459 0.28564453125 +41460 0.037841796875 +41461 0.223175048828125 +41462 0.033294677734375 +41463 0.196746826171875 +41464 0.030029296875 +41465 0.179840087890625 +41466 0.025482177734375 +41467 0.155548095703125 +41468 0.023895263671875 +41469 0.151214599609375 +41470 0.0238037109375 +41471 0.156951904296875 +41472 0.018890380859375 +41473 0.13177490234375 +41474 0.013458251953125 +41475 0.100799560546875 +41476 0.011260986328125 +41477 0.087127685546875 +41478 0.005828857421875 +41479 0.05487060546875 +41480 -0.005126953125 +41481 -0.009002685546875 +41482 -0.021514892578125 +41483 -0.10400390625 +41484 -0.043243408203125 +41485 -0.229400634765625 +41486 -0.064910888671875 +41487 -0.35552978515625 +41488 -0.07916259765625 +41489 -0.441925048828125 +41490 -0.083404541015625 +41491 -0.473846435546875 +41492 -0.080230712890625 +41493 -0.464813232421875 +41494 -0.070526123046875 +41495 -0.419097900390625 +41496 -0.053924560546875 +41497 -0.334320068359375 +41498 -0.033721923828125 +41499 -0.227935791015625 +41500 -0.0142822265625 +41501 -0.12347412109375 +41502 0.00311279296875 +41503 -0.02764892578125 +41504 0.021820068359375 +41505 0.077667236328125 +41506 0.045684814453125 +41507 0.2132568359375 +41508 0.076568603515625 +41509 0.38885498046875 +41510 0.110565185546875 +41511 0.582794189453125 +41512 0.136566162109375 +41513 0.734039306640625 +41514 0.1468505859375 +41515 0.800140380859375 +41516 0.1409912109375 +41517 0.7783203125 +41518 0.118499755859375 +41519 0.6651611328125 +41520 0.07928466796875 +41521 0.45965576171875 +41522 0.03033447265625 +41523 0.199188232421875 +41524 -0.0162353515625 +41525 -0.050689697265625 +41526 -0.049957275390625 +41527 -0.23297119140625 +41528 -0.067626953125 +41529 -0.33013916015625 +41530 -0.074066162109375 +41531 -0.368408203125 +41532 -0.075042724609375 +41533 -0.378936767578125 +41534 -0.073486328125 +41535 -0.376983642578125 +41536 -0.072601318359375 +41537 -0.37969970703125 +41538 -0.0732421875 +41539 -0.391510009765625 +41540 -0.070526123046875 +41541 -0.385345458984375 +41542 -0.06097412109375 +41543 -0.3419189453125 +41544 -0.048675537109375 +41545 -0.28289794921875 +41546 -0.04168701171875 +41547 -0.251617431640625 +41548 -0.04339599609375 +41549 -0.266143798828125 +41550 -0.0440673828125 +41551 -0.273345947265625 +41552 -0.0333251953125 +41553 -0.216796875 +41554 -0.01702880859375 +41555 -0.128265380859375 +41556 -0.006256103515625 +41557 -0.068145751953125 +41558 -0.002227783203125 +41559 -0.0430908203125 +41560 0.000335693359375 +41561 -0.024444580078125 +41562 0.007568359375 +41563 0.020721435546875 +41564 0.025390625 +41565 0.124481201171875 +41566 0.048553466796875 +41567 0.25787353515625 +41568 0.0694580078125 +41569 0.379119873046875 +41570 0.086669921875 +41571 0.47991943359375 +41572 0.094329833984375 +41573 0.5281982421875 +41574 0.09014892578125 +41575 0.511138916015625 +41576 0.079254150390625 +41577 0.456207275390625 +41578 0.069793701171875 +41579 0.407470703125 +41580 0.065216064453125 +41581 0.383758544921875 +41582 0.060333251953125 +41583 0.35687255859375 +41584 0.052398681640625 +41585 0.31182861328125 +41586 0.041778564453125 +41587 0.250885009765625 +41588 0.026885986328125 +41589 0.1654052734375 +41590 0.00396728515625 +41591 0.035247802734375 +41592 -0.027496337890625 +41593 -0.142059326171875 +41594 -0.0618896484375 +41595 -0.33563232421875 +41596 -0.097259521484375 +41597 -0.5345458984375 +41598 -0.13055419921875 +41599 -0.72186279296875 +41600 -0.150604248046875 +41601 -0.836669921875 +41602 -0.148956298828125 +41603 -0.8326416015625 +41604 -0.12933349609375 +41605 -0.7296142578125 +41606 -0.101898193359375 +41607 -0.582550048828125 +41608 -0.075592041015625 +41609 -0.440093994140625 +41610 -0.054473876953125 +41611 -0.324310302734375 +41612 -0.03228759765625 +41613 -0.20147705078125 +41614 -0.004058837890625 +41615 -0.044647216796875 +41616 0.022491455078125 +41617 0.103973388671875 +41618 0.039642333984375 +41619 0.202392578125 +41620 0.050018310546875 +41621 0.264495849609375 +41622 0.0626220703125 +41623 0.338897705078125 +41624 0.080841064453125 +41625 0.443817138671875 +41626 0.09844970703125 +41627 0.545074462890625 +41628 0.11083984375 +41629 0.6173095703125 +41630 0.1165771484375 +41631 0.6524658203125 +41632 0.1180419921875 +41633 0.66339111328125 +41634 0.11639404296875 +41635 0.6561279296875 +41636 0.107208251953125 +41637 0.606781005859375 +41638 0.087890625 +41639 0.501190185546875 +41640 0.0609130859375 +41641 0.352783203125 +41642 0.029022216796875 +41643 0.176544189453125 +41644 -0.009124755859375 +41645 -0.034820556640625 +41646 -0.049285888671875 +41647 -0.258209228515625 +41648 -0.082122802734375 +41649 -0.44244384765625 +41650 -0.105438232421875 +41651 -0.5753173828125 +41652 -0.118438720703125 +41653 -0.65203857421875 +41654 -0.115478515625 +41655 -0.641632080078125 +41656 -0.0999755859375 +41657 -0.562164306640625 +41658 -0.08013916015625 +41659 -0.458038330078125 +41660 -0.059906005859375 +41661 -0.350555419921875 +41662 -0.043121337890625 +41663 -0.260528564453125 +41664 -0.030548095703125 +41665 -0.192108154296875 +41666 -0.021575927734375 +41667 -0.141937255859375 +41668 -0.01470947265625 +41669 -0.1021728515625 +41670 -0.00811767578125 +41671 -0.062896728515625 +41672 0.000457763671875 +41673 -0.011932373046875 +41674 0.0133056640625 +41675 0.062835693359375 +41676 0.02813720703125 +41677 0.148712158203125 +41678 0.044281005859375 +41679 0.241729736328125 +41680 0.063079833984375 +41681 0.34912109375 +41682 0.082122802734375 +41683 0.457305908203125 +41684 0.097320556640625 +41685 0.54388427734375 +41686 0.10211181640625 +41687 0.5728759765625 +41688 0.089569091796875 +41689 0.506591796875 +41690 0.06085205078125 +41691 0.351226806640625 +41692 0.02325439453125 +41693 0.146514892578125 +41694 -0.013580322265625 +41695 -0.05523681640625 +41696 -0.042724609375 +41697 -0.21624755859375 +41698 -0.06390380859375 +41699 -0.334930419921875 +41700 -0.07562255859375 +41701 -0.402984619140625 +41702 -0.081787109375 +41703 -0.4412841796875 +41704 -0.09088134765625 +41705 -0.49578857421875 +41706 -0.101806640625 +41707 -0.5601806640625 +41708 -0.1083984375 +41709 -0.600738525390625 +41710 -0.1046142578125 +41711 -0.584228515625 +41712 -0.084747314453125 +41713 -0.47930908203125 +41714 -0.047576904296875 +41715 -0.27935791015625 +41716 0.0023193359375 +41717 -0.0089111328125 +41718 0.053314208984375 +41719 0.268798828125 +41720 0.09234619140625 +41721 0.482818603515625 +41722 0.114044189453125 +41723 0.60369873046875 +41724 0.121917724609375 +41725 0.650421142578125 +41726 0.12359619140625 +41727 0.66400146484375 +41728 0.11834716796875 +41729 0.6414794921875 +41730 0.104400634765625 +41731 0.572540283203125 +41732 0.09051513671875 +41733 0.498138427734375 +41734 0.08099365234375 +41735 0.439453125 +41736 0.071044921875 +41737 0.375518798828125 +41738 0.05352783203125 +41739 0.274505615234375 +41740 0.022186279296875 +41741 0.1087646484375 +41742 -0.018402099609375 +41743 -0.099395751953125 +41744 -0.061614990234375 +41745 -0.3182373046875 +41746 -0.107940673828125 +41747 -0.5489501953125 +41748 -0.1536865234375 +41749 -0.7738037109375 +41750 -0.187530517578125 +41751 -0.86383056640625 +41752 -0.202362060546875 +41753 -0.870391845703125 +41754 -0.20208740234375 +41755 -0.86895751953125 +41756 -0.189483642578125 +41757 -0.861053466796875 +41758 -0.1607666015625 +41759 -0.765869140625 +41760 -0.1134033203125 +41761 -0.5301513671875 +41762 -0.04876708984375 +41763 -0.214691162109375 +41764 0.02398681640625 +41765 0.137359619140625 +41766 0.093994140625 +41767 0.474822998046875 +41768 0.15374755859375 +41769 0.76239013671875 +41770 0.197662353515625 +41771 0.867462158203125 +41772 0.225982666015625 +41773 0.870361328125 +41774 0.236358642578125 +41775 0.86480712890625 +41776 0.230072021484375 +41777 0.831817626953125 +41778 0.212493896484375 +41779 0.677581787109375 +41780 0.184906005859375 +41781 0.495880126953125 +41782 0.1513671875 +41783 0.30767822265625 +41784 0.1123046875 +41785 0.116180419921875 +41786 0.060760498046875 +41787 -0.110748291015625 +41788 -0.00482177734375 +41789 -0.381805419921875 +41790 -0.075347900390625 +41791 -0.6572265625 +41792 -0.138031005859375 +41793 -0.857421875 +41794 -0.18377685546875 +41795 -0.870391845703125 +41796 -0.211212158203125 +41797 -0.870391845703125 +41798 -0.226318359375 +41799 -0.86444091796875 +41800 -0.2369384765625 +41801 -0.85723876953125 +41802 -0.239227294921875 +41803 -0.790008544921875 +41804 -0.2215576171875 +41805 -0.62847900390625 +41806 -0.183258056640625 +41807 -0.3956298828125 +41808 -0.1314697265625 +41809 -0.126708984375 +41810 -0.072113037109375 +41811 0.150115966796875 +41812 -0.00762939453125 +41813 0.424041748046875 +41814 0.056182861328125 +41815 0.670623779296875 +41816 0.111083984375 +41817 0.854522705078125 +41818 0.15338134765625 +41819 0.866485595703125 +41820 0.17987060546875 +41821 0.86920166015625 +41822 0.19464111328125 +41823 0.8653564453125 +41824 0.200714111328125 +41825 0.857147216796875 +41826 0.19757080078125 +41827 0.766845703125 +41828 0.18646240234375 +41829 0.628509521484375 +41830 0.165985107421875 +41831 0.462127685546875 +41832 0.141754150390625 +41833 0.297210693359375 +41834 0.116455078125 +41835 0.14862060546875 +41836 0.085174560546875 +41837 -0.00537109375 +41838 0.049530029296875 +41839 -0.15753173828125 +41840 0.0086669921875 +41841 -0.31304931640625 +41842 -0.040496826171875 +41843 -0.48876953125 +41844 -0.087921142578125 +41845 -0.6416015625 +41846 -0.12835693359375 +41847 -0.751373291015625 +41848 -0.16693115234375 +41849 -0.84619140625 +41850 -0.2005615234375 +41851 -0.861297607421875 +41852 -0.22216796875 +41853 -0.863250732421875 +41854 -0.22503662109375 +41855 -0.856597900390625 +41856 -0.211883544921875 +41857 -0.7498779296875 +41858 -0.195281982421875 +41859 -0.624542236328125 +41860 -0.170501708984375 +41861 -0.47808837890625 +41862 -0.124908447265625 +41863 -0.253387451171875 +41864 -0.068389892578125 +41865 0.003692626953125 +41866 -0.015655517578125 +41867 0.2257080078125 +41868 0.0360107421875 +41869 0.427154541015625 +41870 0.093658447265625 +41871 0.643218994140625 +41872 0.1552734375 +41873 0.855926513671875 +41874 0.20843505859375 +41875 0.870361328125 +41876 0.24249267578125 +41877 0.870361328125 +41878 0.25909423828125 +41879 0.862762451171875 +41880 0.257720947265625 +41881 0.79669189453125 +41882 0.236419677734375 +41883 0.595794677734375 +41884 0.2015380859375 +41885 0.362152099609375 +41886 0.1591796875 +41887 0.1270751953125 +41888 0.11395263671875 +41889 -0.086944580078125 +41890 0.066314697265625 +41891 -0.2784423828125 +41892 0.008758544921875 +41893 -0.484832763671875 +41894 -0.0628662109375 +41895 -0.729583740234375 +41896 -0.137664794921875 +41897 -0.86688232421875 +41898 -0.201995849609375 +41899 -0.870391845703125 +41900 -0.254852294921875 +41901 -0.86859130859375 +41902 -0.295867919921875 +41903 -0.86279296875 +41904 -0.317352294921875 +41905 -0.817962646484375 +41906 -0.3095703125 +41907 -0.6116943359375 +41908 -0.27105712890625 +41909 -0.3128662109375 +41910 -0.209136962890625 +41911 0.039398193359375 +41912 -0.128204345703125 +41913 0.422821044921875 +41914 -0.035491943359375 +41915 0.805145263671875 +41916 0.054229736328125 +41917 0.870361328125 +41918 0.128662109375 +41919 0.870361328125 +41920 0.18524169921875 +41921 0.860015869140625 +41922 0.222320556640625 +41923 0.727935791015625 +41924 0.238677978515625 +41925 0.48114013671875 +41926 0.239532470703125 +41927 0.2059326171875 +41928 0.22979736328125 +41929 -0.06103515625 +41930 0.211669921875 +41931 -0.29913330078125 +41932 0.18206787109375 +41933 -0.516204833984375 +41934 0.137725830078125 +41935 -0.7252197265625 +41936 0.0841064453125 +41937 -0.85980224609375 +41938 0.028656005859375 +41939 -0.870391845703125 +41940 -0.0220947265625 +41941 -0.870391845703125 +41942 -0.05755615234375 +41943 -0.858062744140625 +41944 -0.07672119140625 +41945 -0.673004150390625 +41946 -0.090850830078125 +41947 -0.42694091796875 +41948 -0.109405517578125 +41949 -0.2100830078125 +41950 -0.131866455078125 +41951 -0.0362548828125 +41952 -0.151885986328125 +41953 0.10943603515625 +41954 -0.165130615234375 +41955 0.23516845703125 +41956 -0.16265869140625 +41957 0.373687744140625 +41958 -0.1448974609375 +41959 0.517791748046875 +41960 -0.125457763671875 +41961 0.602783203125 +41962 -0.10333251953125 +41963 0.635711669921875 +41964 -0.0714111328125 +41965 0.655181884765625 +41966 -0.031951904296875 +41967 0.65948486328125 +41968 0.01318359375 +41969 0.651275634765625 +41970 0.058624267578125 +41971 0.61846923828125 +41972 0.096221923828125 +41973 0.53753662109375 +41974 0.121978759765625 +41975 0.404144287109375 +41976 0.133697509765625 +41977 0.22186279296875 +41978 0.131622314453125 +41979 0.003997802734375 +41980 0.119598388671875 +41981 -0.22100830078125 +41982 0.10205078125 +41983 -0.42449951171875 +41984 0.08392333984375 +41985 -0.579833984375 +41986 0.07513427734375 +41987 -0.641876220703125 +41988 0.073699951171875 +41989 -0.6177978515625 +41990 0.06396484375 +41991 -0.575531005859375 +41992 0.044891357421875 +41993 -0.526336669921875 +41994 0.029541015625 +41995 -0.42645263671875 +41996 0.02490234375 +41997 -0.2581787109375 +41998 0.0220947265625 +41999 -0.068695068359375 +42000 0.01165771484375 +42001 0.09222412109375 +42002 -0.001739501953125 +42003 0.232147216796875 +42004 -0.015533447265625 +42005 0.3509521484375 +42006 -0.037109375 +42007 0.410064697265625 +42008 -0.073760986328125 +42009 0.372955322265625 +42010 -0.120361328125 +42011 0.2554931640625 +42012 -0.16400146484375 +42013 0.10711669921875 +42014 -0.1998291015625 +42015 -0.052886962890625 +42016 -0.218902587890625 +42017 -0.186279296875 +42018 -0.2073974609375 +42019 -0.23291015625 +42020 -0.170989990234375 +42021 -0.209442138671875 +42022 -0.126007080078125 +42023 -0.174163818359375 +42024 -0.07452392578125 +42025 -0.126739501953125 +42026 -0.014068603515625 +42027 -0.048126220703125 +42028 0.048309326171875 +42029 0.0426025390625 +42030 0.101043701171875 +42031 0.10748291015625 +42032 0.140869140625 +42033 0.1409912109375 +42034 0.179595947265625 +42035 0.19708251953125 +42036 0.215545654296875 +42037 0.273651123046875 +42038 0.23486328125 +42039 0.31768798828125 +42040 0.240325927734375 +42041 0.341094970703125 +42042 0.2381591796875 +42043 0.368011474609375 +42044 0.222686767578125 +42045 0.37249755859375 +42046 0.181671142578125 +42047 0.30072021484375 +42048 0.116363525390625 +42049 0.1517333984375 +42050 0.043243408203125 +42051 -0.01470947265625 +42052 -0.03326416015625 +42053 -0.1883544921875 +42054 -0.112152099609375 +42055 -0.372711181640625 +42056 -0.178314208984375 +42057 -0.51397705078125 +42058 -0.220062255859375 +42059 -0.57177734375 +42060 -0.234375 +42061 -0.53948974609375 +42062 -0.22467041015625 +42063 -0.43511962890625 +42064 -0.199554443359375 +42065 -0.2962646484375 +42066 -0.168212890625 +42067 -0.161102294921875 +42068 -0.1341552734375 +42069 -0.0435791015625 +42070 -0.09686279296875 +42071 0.060394287109375 +42072 -0.060638427734375 +42073 0.13665771484375 +42074 -0.03033447265625 +42075 0.170135498046875 +42076 -0.006134033203125 +42077 0.16552734375 +42078 0.019012451171875 +42079 0.15728759765625 +42080 0.044891357421875 +42081 0.150787353515625 +42082 0.064056396484375 +42083 0.12200927734375 +42084 0.077362060546875 +42085 0.080108642578125 +42086 0.090087890625 +42087 0.05126953125 +42088 0.108062744140625 +42089 0.062896728515625 +42090 0.12506103515625 +42091 0.09271240234375 +42092 0.12890625 +42093 0.092987060546875 +42094 0.123199462890625 +42095 0.07855224609375 +42096 0.1119384765625 +42097 0.06427001953125 +42098 0.091888427734375 +42099 0.0347900390625 +42100 0.06341552734375 +42101 -0.01171875 +42102 0.0323486328125 +42103 -0.056060791015625 +42104 0.010467529296875 +42105 -0.055511474609375 +42106 -0.00103759765625 +42107 -0.010467529296875 +42108 -0.0142822265625 +42109 0.02508544921875 +42110 -0.034423828125 +42111 0.025665283203125 +42112 -0.053955078125 +42113 0.017333984375 +42114 -0.071533203125 +42115 0.00189208984375 +42116 -0.089263916015625 +42117 -0.03173828125 +42118 -0.103790283203125 +42119 -0.071502685546875 +42120 -0.11944580078125 +42121 -0.13543701171875 +42122 -0.135528564453125 +42123 -0.219970703125 +42124 -0.14630126953125 +42125 -0.300506591796875 +42126 -0.152191162109375 +42127 -0.376312255859375 +42128 -0.14630126953125 +42129 -0.416107177734375 +42130 -0.117462158203125 +42131 -0.371124267578125 +42132 -0.066925048828125 +42133 -0.242279052734375 +42134 -0.00567626953125 +42135 -0.069732666015625 +42136 0.06005859375 +42137 0.125640869140625 +42138 0.12164306640625 +42139 0.31268310546875 +42140 0.169281005859375 +42141 0.45501708984375 +42142 0.202911376953125 +42143 0.554779052734375 +42144 0.221832275390625 +42145 0.61065673828125 +42146 0.222991943359375 +42147 0.610931396484375 +42148 0.200439453125 +42149 0.531463623046875 +42150 0.158447265625 +42151 0.3883056640625 +42152 0.11065673828125 +42153 0.23468017578125 +42154 0.063812255859375 +42155 0.095245361328125 +42156 0.02508544921875 +42157 -0.00396728515625 +42158 -0.001068115234375 +42159 -0.04852294921875 +42160 -0.0179443359375 +42161 -0.055145263671875 +42162 -0.037628173828125 +42163 -0.0758056640625 +42164 -0.066314697265625 +42165 -0.138702392578125 +42166 -0.094757080078125 +42167 -0.209197998046875 +42168 -0.122833251953125 +42169 -0.289031982421875 +42170 -0.150360107421875 +42171 -0.37884521484375 +42172 -0.17156982421875 +42173 -0.456329345703125 +42174 -0.1851806640625 +42175 -0.51641845703125 +42176 -0.1815185546875 +42177 -0.519287109375 +42178 -0.15924072265625 +42179 -0.458251953125 +42180 -0.131561279296875 +42181 -0.384796142578125 +42182 -0.105224609375 +42183 -0.323699951171875 +42184 -0.0794677734375 +42185 -0.269287109375 +42186 -0.0484619140625 +42187 -0.1951904296875 +42188 -0.0125732421875 +42189 -0.100006103515625 +42190 0.0208740234375 +42191 -0.01055908203125 +42192 0.05877685546875 +42193 0.1033935546875 +42194 0.102447509765625 +42195 0.24908447265625 +42196 0.138336181640625 +42197 0.373199462890625 +42198 0.161865234375 +42199 0.45806884765625 +42200 0.17486572265625 +42201 0.511474609375 +42202 0.18536376953125 +42203 0.565399169921875 +42204 0.191497802734375 +42205 0.61138916015625 +42206 0.1788330078125 +42207 0.5897216796875 +42208 0.1453857421875 +42209 0.4906005859375 +42210 0.096038818359375 +42211 0.33148193359375 +42212 0.040130615234375 +42213 0.147796630859375 +42214 -0.01141357421875 +42215 -0.01873779296875 +42216 -0.051116943359375 +42217 -0.140289306640625 +42218 -0.072296142578125 +42219 -0.191986083984375 +42220 -0.0771484375 +42221 -0.184295654296875 +42222 -0.076416015625 +42223 -0.161834716796875 +42224 -0.080291748046875 +42225 -0.166595458984375 +42226 -0.0875244140625 +42227 -0.19390869140625 +42228 -0.093353271484375 +42229 -0.22442626953125 +42230 -0.103302001953125 +42231 -0.279754638671875 +42232 -0.112457275390625 +42233 -0.3389892578125 +42234 -0.10931396484375 +42235 -0.3543701171875 +42236 -0.099822998046875 +42237 -0.348175048828125 +42238 -0.085845947265625 +42239 -0.32598876953125 +42240 -0.06048583984375 +42241 -0.2581787109375 +42242 -0.02294921875 +42243 -0.139801025390625 +42244 0.022705078125 +42245 0.014617919921875 +42246 0.0609130859375 +42247 0.144378662109375 +42248 0.084320068359375 +42249 0.221038818359375 +42250 0.099273681640625 +42251 0.27069091796875 +42252 0.105865478515625 +42253 0.294036865234375 +42254 0.109283447265625 +42255 0.311767578125 +42256 0.113525390625 +42257 0.339141845703125 +42258 0.115203857421875 +42259 0.360260009765625 +42260 0.11077880859375 +42261 0.360504150390625 +42262 0.091583251953125 +42263 0.308380126953125 +42264 0.051544189453125 +42265 0.18170166015625 +42266 -0.0023193359375 +42267 0.0047607421875 +42268 -0.056732177734375 +42269 -0.17559814453125 +42270 -0.09893798828125 +42271 -0.3143310546875 +42272 -0.1165771484375 +42273 -0.36785888671875 +42274 -0.116943359375 +42275 -0.36248779296875 +42276 -0.112640380859375 +42277 -0.343536376953125 +42278 -0.101104736328125 +42279 -0.3018798828125 +42280 -0.08062744140625 +42281 -0.231414794921875 +42282 -0.047210693359375 +42283 -0.117645263671875 +42284 -0.010009765625 +42285 0.007049560546875 +42286 0.015472412109375 +42287 0.087982177734375 +42288 0.033111572265625 +42289 0.13946533203125 +42290 0.046295166015625 +42291 0.17425537109375 +42292 0.053680419921875 +42293 0.188201904296875 +42294 0.05224609375 +42295 0.171234130859375 +42296 0.040435791015625 +42297 0.118438720703125 +42298 0.025787353515625 +42299 0.05706787109375 +42300 0.00872802734375 +42301 -0.010711669921875 +42302 -0.012603759765625 +42303 -0.0914306640625 +42304 -0.031890869140625 +42305 -0.162322998046875 +42306 -0.04107666015625 +42307 -0.194549560546875 +42308 -0.029266357421875 +42309 -0.1492919921875 +42310 0.004913330078125 +42311 -0.02166748046875 +42312 0.043609619140625 +42313 0.124053955078125 +42314 0.0654296875 +42315 0.211151123046875 +42316 0.070770263671875 +42317 0.240447998046875 +42318 0.068267822265625 +42319 0.242218017578125 +42320 0.06072998046875 +42321 0.2257080078125 +42322 0.04925537109375 +42323 0.194366455078125 +42324 0.02484130859375 +42325 0.115509033203125 +42326 -0.005706787109375 +42327 0.0128173828125 +42328 -0.025543212890625 +42329 -0.053802490234375 +42330 -0.0419921875 +42331 -0.110626220703125 +42332 -0.0667724609375 +42333 -0.199493408203125 +42334 -0.092620849609375 +42335 -0.29437255859375 +42336 -0.1019287109375 +42337 -0.33221435546875 +42338 -0.085479736328125 +42339 -0.27972412109375 +42340 -0.05694580078125 +42341 -0.185333251953125 +42342 -0.038604736328125 +42343 -0.128204345703125 +42344 -0.03265380859375 +42345 -0.115692138671875 +42346 -0.03045654296875 +42347 -0.116455078125 +42348 -0.0252685546875 +42349 -0.105926513671875 +42350 -0.008758544921875 +42351 -0.053955078125 +42352 0.021575927734375 +42353 0.048797607421875 +42354 0.05303955078125 +42355 0.157318115234375 +42356 0.06890869140625 +42357 0.212005615234375 +42358 0.07073974609375 +42359 0.218475341796875 +42360 0.07550048828125 +42361 0.23724365234375 +42362 0.093597412109375 +42363 0.30535888671875 +42364 0.11346435546875 +42365 0.38128662109375 +42366 0.11822509765625 +42367 0.404449462890625 +42368 0.11346435546875 +42369 0.3944091796875 +42370 0.109771728515625 +42371 0.3885498046875 +42372 0.1004638671875 +42373 0.362640380859375 +42374 0.0736083984375 +42375 0.27362060546875 +42376 0.028076171875 +42377 0.11712646484375 +42378 -0.021484375 +42379 -0.054901123046875 +42380 -0.060516357421875 +42381 -0.19085693359375 +42382 -0.08758544921875 +42383 -0.28570556640625 +42384 -0.1026611328125 +42385 -0.339263916015625 +42386 -0.113006591796875 +42387 -0.3775634765625 +42388 -0.131317138671875 +42389 -0.445709228515625 +42390 -0.15521240234375 +42391 -0.535064697265625 +42392 -0.18011474609375 +42393 -0.629058837890625 +42394 -0.197662353515625 +42395 -0.697601318359375 +42396 -0.197662353515625 +42397 -0.70391845703125 +42398 -0.1787109375 +42399 -0.6424560546875 +42400 -0.134735107421875 +42401 -0.491241455078125 +42402 -0.07012939453125 +42403 -0.265716552734375 +42404 -0.00115966796875 +42405 -0.023712158203125 +42406 0.062835693359375 +42407 0.201751708984375 +42408 0.112060546875 +42409 0.375823974609375 +42410 0.14276123046875 +42411 0.485076904296875 +42412 0.165924072265625 +42413 0.56884765625 +42414 0.183746337890625 +42415 0.634765625 +42416 0.18359375 +42417 0.63763427734375 +42418 0.162353515625 +42419 0.5660400390625 +42420 0.1346435546875 +42421 0.4720458984375 +42422 0.114898681640625 +42423 0.40692138671875 +42424 0.105255126953125 +42425 0.3778076171875 +42426 0.10357666015625 +42427 0.376953125 +42428 0.10089111328125 +42429 0.371978759765625 +42430 0.08331298828125 +42431 0.313140869140625 +42432 0.046417236328125 +42433 0.184417724609375 +42434 -0.002593994140625 +42435 0.011199951171875 +42436 -0.05377197265625 +42437 -0.171051025390625 +42438 -0.100128173828125 +42439 -0.33740234375 +42440 -0.13726806640625 +42441 -0.47198486328125 +42442 -0.16119384765625 +42443 -0.560394287109375 +42444 -0.165802001953125 +42445 -0.58056640625 +42446 -0.15533447265625 +42447 -0.54754638671875 +42448 -0.14312744140625 +42449 -0.508575439453125 +42450 -0.128082275390625 +42451 -0.459503173828125 +42452 -0.10858154296875 +42453 -0.394378662109375 +42454 -0.095703125 +42455 -0.35260009765625 +42456 -0.083221435546875 +42457 -0.31170654296875 +42458 -0.0504150390625 +42459 -0.197418212890625 +42460 0.003143310546875 +42461 -0.007965087890625 +42462 0.06365966796875 +42463 0.207489013671875 +42464 0.1199951171875 +42465 0.409210205078125 +42466 0.165130615234375 +42467 0.57208251953125 +42468 0.190673828125 +42469 0.66595458984375 +42470 0.187713623046875 +42471 0.65875244140625 +42472 0.161041259765625 +42473 0.56744384765625 +42474 0.12176513671875 +42475 0.431396484375 +42476 0.082244873046875 +42477 0.29443359375 +42478 0.049774169921875 +42479 0.182464599609375 +42480 0.0155029296875 +42481 0.06365966796875 +42482 -0.0244140625 +42483 -0.075958251953125 +42484 -0.056793212890625 +42485 -0.189422607421875 +42486 -0.08026123046875 +42487 -0.271942138671875 +42488 -0.10009765625 +42489 -0.342529296875 +42490 -0.105987548828125 +42491 -0.364166259765625 +42492 -0.095245361328125 +42493 -0.327239990234375 +42494 -0.08056640625 +42495 -0.2769775390625 +42496 -0.07354736328125 +42497 -0.253692626953125 +42498 -0.070159912109375 +42499 -0.24365234375 +42500 -0.0557861328125 +42501 -0.1983642578125 +42502 -0.030059814453125 +42503 -0.116241455078125 +42504 -0.00543212890625 +42505 -0.036834716796875 +42506 0.016448974609375 +42507 0.034881591796875 +42508 0.033172607421875 +42509 0.09124755859375 +42510 0.037506103515625 +42511 0.10888671875 +42512 0.041259765625 +42513 0.125518798828125 +42514 0.049713134765625 +42515 0.15771484375 +42516 0.054473876953125 +42517 0.17828369140625 +42518 0.050567626953125 +42519 0.17108154296875 +42520 0.0362548828125 +42521 0.129974365234375 +42522 0.020172119140625 +42523 0.082427978515625 +42524 0.00213623046875 +42525 0.027679443359375 +42526 -0.02752685546875 +42527 -0.065643310546875 +42528 -0.056884765625 +42529 -0.15936279296875 +42530 -0.073333740234375 +42531 -0.21307373046875 +42532 -0.079376220703125 +42533 -0.234649658203125 +42534 -0.067596435546875 +42535 -0.2001953125 +42536 -0.041015625 +42537 -0.119171142578125 +42538 -0.01007080078125 +42539 -0.024749755859375 +42540 0.0260009765625 +42541 0.085784912109375 +42542 0.056396484375 +42543 0.178131103515625 +42544 0.069549560546875 +42545 0.215576171875 +42546 0.069549560546875 +42547 0.211456298828125 +42548 0.059326171875 +42549 0.17523193359375 +42550 0.045623779296875 +42551 0.128753662109375 +42552 0.037750244140625 +42553 0.1019287109375 +42554 0.029327392578125 +42555 0.0743408203125 +42556 0.019500732421875 +42557 0.04327392578125 +42558 0.017425537109375 +42559 0.038177490234375 +42560 0.028564453125 +42561 0.076263427734375 +42562 0.047760009765625 +42563 0.14105224609375 +42564 0.06072998046875 +42565 0.186431884765625 +42566 0.0601806640625 +42567 0.188812255859375 +42568 0.043304443359375 +42569 0.1390380859375 +42570 0.011688232421875 +42571 0.041778564453125 +42572 -0.027252197265625 +42573 -0.079437255859375 +42574 -0.071868896484375 +42575 -0.219390869140625 +42576 -0.118865966796875 +42577 -0.367828369140625 +42578 -0.158905029296875 +42579 -0.494873046875 +42580 -0.178192138671875 +42581 -0.556243896484375 +42582 -0.1632080078125 +42583 -0.508697509765625 +42584 -0.12127685546875 +42585 -0.3756103515625 +42586 -0.071746826171875 +42587 -0.218902587890625 +42588 -0.02252197265625 +42589 -0.063751220703125 +42590 0.02685546875 +42591 0.091552734375 +42592 0.072906494140625 +42593 0.23602294921875 +42594 0.10723876953125 +42595 0.342987060546875 +42596 0.12445068359375 +42597 0.39520263671875 +42598 0.12347412109375 +42599 0.389373779296875 +42600 0.1038818359375 +42601 0.324249267578125 +42602 0.073211669921875 +42603 0.224090576171875 +42604 0.042449951171875 +42605 0.124267578125 +42606 0.015411376953125 +42607 0.037078857421875 +42608 0.000640869140625 +42609 -0.010101318359375 +42610 -0.00250244140625 +42611 -0.019439697265625 +42612 -0.003936767578125 +42613 -0.022796630859375 +42614 0.00213623046875 +42615 -0.001556396484375 +42616 0.019500732421875 +42617 0.056304931640625 +42618 0.034454345703125 +42619 0.106719970703125 +42620 0.030548095703125 +42621 0.096893310546875 +42622 0.0128173828125 +42623 0.042694091796875 +42624 -0.00689697265625 +42625 -0.018035888671875 +42626 -0.025604248046875 +42627 -0.07586669921875 +42628 -0.039703369140625 +42629 -0.11944580078125 +42630 -0.0526123046875 +42631 -0.15972900390625 +42632 -0.066131591796875 +42633 -0.202606201171875 +42634 -0.080413818359375 +42635 -0.24859619140625 +42636 -0.0977783203125 +42637 -0.30517578125 +42638 -0.115081787109375 +42639 -0.36212158203125 +42640 -0.1236572265625 +42641 -0.39141845703125 +42642 -0.111724853515625 +42643 -0.35528564453125 +42644 -0.07818603515625 +42645 -0.249969482421875 +42646 -0.02850341796875 +42647 -0.092864990234375 +42648 0.02886962890625 +42649 0.08905029296875 +42650 0.07501220703125 +42651 0.2352294921875 +42652 0.101531982421875 +42653 0.318817138671875 +42654 0.114288330078125 +42655 0.358642578125 +42656 0.111083984375 +42657 0.347747802734375 +42658 0.09173583984375 +42659 0.28564453125 +42660 0.0721435546875 +42661 0.223175048828125 +42662 0.06365966796875 +42663 0.196746826171875 +42664 0.05804443359375 +42665 0.179840087890625 +42666 0.050048828125 +42667 0.155548095703125 +42668 0.0482177734375 +42669 0.151214599609375 +42670 0.049468994140625 +42671 0.156951904296875 +42672 0.041046142578125 +42673 0.13177490234375 +42674 0.030853271484375 +42675 0.100799560546875 +42676 0.026092529296875 +42677 0.087127685546875 +42678 0.015594482421875 +42679 0.05487060546875 +42680 -0.004638671875 +42681 -0.009002685546875 +42682 -0.034454345703125 +42683 -0.10400390625 +42684 -0.073638916015625 +42685 -0.229400634765625 +42686 -0.1129150390625 +42687 -0.35552978515625 +42688 -0.1396484375 +42689 -0.441925048828125 +42690 -0.149261474609375 +42691 -0.473846435546875 +42692 -0.14599609375 +42693 -0.464813232421875 +42694 -0.1312255859375 +42695 -0.419097900390625 +42696 -0.104248046875 +42697 -0.334320068359375 +42698 -0.070526123046875 +42699 -0.227935791015625 +42700 -0.037445068359375 +42701 -0.12347412109375 +42702 -0.007110595703125 +42703 -0.02764892578125 +42704 0.026092529296875 +42705 0.077667236328125 +42706 0.068634033203125 +42707 0.2132568359375 +42708 0.12353515625 +42709 0.38885498046875 +42710 0.184051513671875 +42711 0.582794189453125 +42712 0.231109619140625 +42713 0.734039306640625 +42714 0.25146484375 +42715 0.800140380859375 +42716 0.244293212890625 +42717 0.7783203125 +42718 0.20855712890625 +42719 0.6651611328125 +42720 0.144012451171875 +42721 0.45965576171875 +42722 0.06231689453125 +42723 0.199188232421875 +42724 -0.016021728515625 +42725 -0.050689697265625 +42726 -0.0732421875 +42727 -0.23297119140625 +42728 -0.103851318359375 +42729 -0.33013916015625 +42730 -0.11602783203125 +42731 -0.368408203125 +42732 -0.11944580078125 +42733 -0.378936767578125 +42734 -0.118927001953125 +42735 -0.376983642578125 +42736 -0.11981201171875 +42737 -0.37969970703125 +42738 -0.1234130859375 +42739 -0.391510009765625 +42740 -0.121307373046875 +42741 -0.385345458984375 +42742 -0.107513427734375 +42743 -0.3419189453125 +42744 -0.08880615234375 +42745 -0.28289794921875 +42746 -0.078704833984375 +42747 -0.251617431640625 +42748 -0.082855224609375 +42749 -0.266143798828125 +42750 -0.084716796875 +42751 -0.273345947265625 +42752 -0.066558837890625 +42753 -0.216796875 +42754 -0.038604736328125 +42755 -0.128265380859375 +42756 -0.02069091796875 +42757 -0.068145751953125 +42758 -0.014923095703125 +42759 -0.0430908203125 +42760 -0.01129150390625 +42761 -0.024444580078125 +42762 0.001678466796875 +42763 0.020721435546875 +42764 0.03515625 +42765 0.124481201171875 +42766 0.07928466796875 +42767 0.25787353515625 +42768 0.1197509765625 +42769 0.379119873046875 +42770 0.15380859375 +42771 0.47991943359375 +42772 0.17041015625 +42773 0.5281982421875 +42774 0.165130615234375 +42775 0.511138916015625 +42776 0.147369384765625 +42777 0.456207275390625 +42778 0.132232666015625 +42779 0.407470703125 +42780 0.1260986328125 +42781 0.383758544921875 +42782 0.119110107421875 +42783 0.35687255859375 +42784 0.10601806640625 +42785 0.31182861328125 +42786 0.087432861328125 +42787 0.250885009765625 +42788 0.060272216796875 +42789 0.1654052734375 +42790 0.017486572265625 +42791 0.035247802734375 +42792 -0.041839599609375 +42793 -0.142059326171875 +42794 -0.107147216796875 +42795 -0.33563232421875 +42796 -0.174774169921875 +42797 -0.5345458984375 +42798 -0.2388916015625 +42799 -0.72186279296875 +42800 -0.278564453125 +42801 -0.836669921875 +42802 -0.27783203125 +42803 -0.8326416015625 +42804 -0.24346923828125 +42805 -0.7296142578125 +42806 -0.1943359375 +42807 -0.582550048828125 +42808 -0.147064208984375 +42809 -0.440093994140625 +42810 -0.109161376953125 +42811 -0.324310302734375 +42812 -0.068878173828125 +42813 -0.20147705078125 +42814 -0.016845703125 +42815 -0.044647216796875 +42816 0.032501220703125 +42817 0.103973388671875 +42818 0.0648193359375 +42819 0.202392578125 +42820 0.0849609375 +42821 0.264495849609375 +42822 0.10968017578125 +42823 0.338897705078125 +42824 0.145294189453125 +42825 0.443817138671875 +42826 0.1800537109375 +42827 0.545074462890625 +42828 0.205230712890625 +42829 0.6173095703125 +42830 0.218017578125 +42831 0.6524658203125 +42832 0.222808837890625 +42833 0.66339111328125 +42834 0.22161865234375 +42835 0.6561279296875 +42836 0.20611572265625 +42837 0.606781005859375 +42838 0.17132568359375 +42839 0.501190185546875 +42840 0.121826171875 +42841 0.352783203125 +42842 0.06268310546875 +42843 0.176544189453125 +42844 -0.0086669921875 +42845 -0.034820556640625 +42846 -0.084320068359375 +42847 -0.258209228515625 +42848 -0.146759033203125 +42849 -0.44244384765625 +42850 -0.191802978515625 +42851 -0.5753173828125 +42852 -0.217864990234375 +42853 -0.65203857421875 +42854 -0.21429443359375 +42855 -0.641632080078125 +42856 -0.18731689453125 +42857 -0.562164306640625 +42858 -0.152191162109375 +42859 -0.458038330078125 +42860 -0.11614990234375 +42861 -0.350555419921875 +42862 -0.086334228515625 +42863 -0.260528564453125 +42864 -0.0640869140625 +42865 -0.192108154296875 +42866 -0.048187255859375 +42867 -0.141937255859375 +42868 -0.035858154296875 +42869 -0.1021728515625 +42870 -0.023590087890625 +42871 -0.062896728515625 +42872 -0.00714111328125 +42873 -0.011932373046875 +42874 0.0177001953125 +42875 0.062835693359375 +42876 0.046630859375 +42877 0.148712158203125 +42878 0.078277587890625 +42879 0.241729736328125 +42880 0.11517333984375 +42881 0.34912109375 +42882 0.152618408203125 +42883 0.457305908203125 +42884 0.182891845703125 +42885 0.54388427734375 +42886 0.193572998046875 +42887 0.5728759765625 +42888 0.171661376953125 +42889 0.506591796875 +42890 0.119232177734375 +42891 0.351226806640625 +42892 0.049896240234375 +42893 0.146514892578125 +42894 -0.018402099609375 +42895 -0.05523681640625 +42896 -0.072723388671875 +42897 -0.21624755859375 +42898 -0.112579345703125 +42899 -0.334930419921875 +42900 -0.135162353515625 +42901 -0.402984619140625 +42902 -0.147674560546875 +42903 -0.4412841796875 +42904 -0.165985107421875 +42905 -0.49578857421875 +42906 -0.187957763671875 +42907 -0.5601806640625 +42908 -0.20196533203125 +42909 -0.600738525390625 +42910 -0.19659423828125 +42911 -0.584228515625 +42912 -0.1610107421875 +42913 -0.47930908203125 +42914 -0.092926025390625 +42915 -0.27935791015625 +42916 -0.000732421875 +42917 -0.0089111328125 +42918 0.093841552734375 +42919 0.268798828125 +42920 0.166473388671875 +42921 0.482818603515625 +42922 0.207061767578125 +42923 0.60369873046875 +42924 0.222198486328125 +42925 0.650421142578125 +42926 0.226043701171875 +42927 0.66400146484375 +42928 0.21759033203125 +42929 0.6414794921875 +42930 0.193359375 +42931 0.572540283203125 +42932 0.16748046875 +42933 0.498138427734375 +42934 0.147216796875 +42935 0.439453125 +42936 0.125396728515625 +42937 0.375518798828125 +42938 0.091033935546875 +42939 0.274505615234375 +42940 0.034576416015625 +42941 0.1087646484375 +42942 -0.03631591796875 +42943 -0.099395751953125 +42944 -0.110748291015625 +42945 -0.3182373046875 +42946 -0.189208984375 +42947 -0.5489501953125 +42948 -0.265594482421875 +42949 -0.7738037109375 +42950 -0.32177734375 +42951 -0.86383056640625 +42952 -0.34637451171875 +42953 -0.870391845703125 +42954 -0.345550537109375 +42955 -0.86895751953125 +42956 -0.323822021484375 +42957 -0.861053466796875 +42958 -0.2752685546875 +42959 -0.765869140625 +42960 -0.196014404296875 +42961 -0.5301513671875 +42962 -0.088531494140625 +42963 -0.214691162109375 +42964 0.032379150390625 +42965 0.137359619140625 +42966 0.1490478515625 +42967 0.474822998046875 +42968 0.24932861328125 +42969 0.76239013671875 +42970 0.323944091796875 +42971 0.867462158203125 +42972 0.37310791015625 +42973 0.870361328125 +42974 0.39288330078125 +42975 0.86480712890625 +42976 0.385162353515625 +42977 0.831817626953125 +42978 0.358367919921875 +42979 0.677581787109375 +42980 0.314544677734375 +42981 0.495880126953125 +42982 0.260101318359375 +42983 0.30767822265625 +42984 0.195831298828125 +42985 0.116180419921875 +42986 0.11083984375 +42987 -0.110748291015625 +42988 0.002716064453125 +42989 -0.381805419921875 +42990 -0.113739013671875 +42991 -0.6572265625 +42992 -0.21795654296875 +42993 -0.857421875 +42994 -0.295196533203125 +42995 -0.870391845703125 +42996 -0.343017578125 +42997 -0.870391845703125 +42998 -0.3707275390625 +42999 -0.86444091796875 +43000 -0.390625 +43001 -0.85723876953125 +43002 -0.396453857421875 +43003 -0.790008544921875 +43004 -0.36962890625 +43005 -0.62847900390625 +43006 -0.30908203125 +43007 -0.3956298828125 +43008 -0.22607421875 +43009 -0.126708984375 +43010 -0.130035400390625 +43011 0.150115966796875 +43012 -0.024749755859375 +43013 0.424041748046875 +43014 0.080291748046875 +43015 0.670623779296875 +43016 0.171051025390625 +43017 0.854522705078125 +43018 0.24139404296875 +43019 0.866485595703125 +43020 0.285919189453125 +43021 0.86920166015625 +43022 0.31170654296875 +43023 0.8653564453125 +43024 0.323974609375 +43025 0.857147216796875 +43026 0.321685791015625 +43027 0.766845703125 +43028 0.30670166015625 +43029 0.628509521484375 +43030 0.276336669921875 +43031 0.462127685546875 +43032 0.24005126953125 +43033 0.297210693359375 +43034 0.202178955078125 +43035 0.14862060546875 +43036 0.153778076171875 +43037 -0.00537109375 +43038 0.0972900390625 +43039 -0.15753173828125 +43040 0.030975341796875 +43041 -0.31304931640625 +43042 -0.05078125 +43043 -0.48876953125 +43044 -0.130706787109375 +43045 -0.6416015625 +43046 -0.199798583984375 +43047 -0.751373291015625 +43048 -0.2669677734375 +43049 -0.84619140625 +43050 -0.32684326171875 +43051 -0.861297607421875 +43052 -0.367034912109375 +43053 -0.863250732421875 +43054 -0.3756103515625 +43055 -0.856597900390625 +43056 -0.357086181640625 +43057 -0.7498779296875 +43058 -0.33306884765625 +43059 -0.624542236328125 +43060 -0.2950439453125 +43061 -0.47808837890625 +43062 -0.220794677734375 +43063 -0.253387451171875 +43064 -0.127197265625 +43065 0.003692626953125 +43066 -0.0396728515625 +43067 0.2257080078125 +43068 0.046783447265625 +43069 0.427154541015625 +43070 0.1446533203125 +43071 0.643218994140625 +43072 0.250518798828125 +43073 0.855926513671875 +43074 0.342803955078125 +43075 0.870361328125 +43076 0.402984619140625 +43077 0.870361328125 +43078 0.433837890625 +43079 0.862762451171875 +43080 0.43426513671875 +43081 0.79669189453125 +43082 0.400665283203125 +43083 0.595794677734375 +43084 0.34393310546875 +43085 0.362152099609375 +43086 0.274444580078125 +43087 0.1270751953125 +43088 0.199981689453125 +43089 -0.086944580078125 +43090 0.121124267578125 +43091 -0.2784423828125 +43092 0.0245361328125 +43093 -0.484832763671875 +43094 -0.097198486328125 +43095 -0.729583740234375 +43096 -0.225250244140625 +43097 -0.86688232421875 +43098 -0.335968017578125 +43099 -0.870391845703125 +43100 -0.427642822265625 +43101 -0.86859130859375 +43102 -0.4996337890625 +43103 -0.86279296875 +43104 -0.5384521484375 +43105 -0.817962646484375 +43106 -0.52703857421875 +43107 -0.6116943359375 +43108 -0.46270751953125 +43109 -0.3128662109375 +43110 -0.358062744140625 +43111 0.039398193359375 +43112 -0.220550537109375 +43113 0.422821044921875 +43114 -0.06256103515625 +43115 0.805145263671875 +43116 0.090423583984375 +43117 0.870361328125 +43118 0.217071533203125 +43119 0.870361328125 +43120 0.313140869140625 +43121 0.860015869140625 +43122 0.3758544921875 +43123 0.727935791015625 +43124 0.403167724609375 +43125 0.48114013671875 +43126 0.404205322265625 +43127 0.2059326171875 +43128 0.38751220703125 +43129 -0.06103515625 +43130 0.35687255859375 +43131 -0.29913330078125 +43132 0.306854248046875 +43133 -0.516204833984375 +43134 0.231658935546875 +43135 -0.7252197265625 +43136 0.140625 +43137 -0.85980224609375 +43138 0.04669189453125 +43139 -0.870391845703125 +43140 -0.03900146484375 +43141 -0.870391845703125 +43142 -0.09814453125 +43143 -0.858062744140625 +43144 -0.129119873046875 +43145 -0.673004150390625 +43146 -0.151641845703125 +43147 -0.42694091796875 +43148 -0.182342529296875 +43149 -0.2100830078125 +43150 -0.2203369140625 +43151 -0.0362548828125 +43152 -0.254638671875 +43153 0.10943603515625 +43154 -0.2777099609375 +43155 0.23516845703125 +43156 -0.273956298828125 +43157 0.373687744140625 +43158 -0.244110107421875 +43159 0.517791748046875 +43160 -0.21185302734375 +43161 0.602783203125 +43162 -0.17523193359375 +43163 0.635711669921875 +43164 -0.121734619140625 +43165 0.655181884765625 +43166 -0.05517578125 +43167 0.65948486328125 +43168 0.021331787109375 +43169 0.651275634765625 +43170 0.098480224609375 +43171 0.61846923828125 +43172 0.162261962890625 +43173 0.53753662109375 +43174 0.20574951171875 +43175 0.404144287109375 +43176 0.2252197265625 +43177 0.22186279296875 +43178 0.2210693359375 +43179 0.003997802734375 +43180 0.200042724609375 +43181 -0.22100830078125 +43182 0.16986083984375 +43183 -0.42449951171875 +43184 0.13848876953125 +43185 -0.579833984375 +43186 0.121978759765625 +43187 -0.641876220703125 +43188 0.117828369140625 +43189 -0.6177978515625 +43190 0.101806640625 +43191 -0.575531005859375 +43192 0.07196044921875 +43193 -0.526336669921875 +43194 0.047821044921875 +43195 -0.42645263671875 +43196 0.039794921875 +43197 -0.2581787109375 +43198 0.0343017578125 +43199 -0.068695068359375 +43200 0.0169677734375 +43201 0.09222412109375 +43202 -0.005035400390625 +43203 0.232147216796875 +43204 -0.02777099609375 +43205 0.3509521484375 +43206 -0.062286376953125 +43207 0.410064697265625 +43208 -0.1195068359375 +43209 0.372955322265625 +43210 -0.191497802734375 +43211 0.2554931640625 +43212 -0.25860595703125 +43213 0.10711669921875 +43214 -0.31341552734375 +43215 -0.052886962890625 +43216 -0.342315673828125 +43217 -0.186279296875 +43218 -0.3243408203125 +43219 -0.23291015625 +43220 -0.268096923828125 +43221 -0.209442138671875 +43222 -0.19842529296875 +43223 -0.174163818359375 +43224 -0.1185302734375 +43225 -0.126739501953125 +43226 -0.02484130859375 +43227 -0.048126220703125 +43228 0.071929931640625 +43229 0.0426025390625 +43230 0.154144287109375 +43231 0.10748291015625 +43232 0.216705322265625 +43233 0.1409912109375 +43234 0.277374267578125 +43235 0.19708251953125 +43236 0.333526611328125 +43237 0.273651123046875 +43238 0.36407470703125 +43239 0.31768798828125 +43240 0.373138427734375 +43241 0.341094970703125 +43242 0.37017822265625 +43243 0.368011474609375 +43244 0.346527099609375 +43245 0.37249755859375 +43246 0.283660888671875 +43247 0.30072021484375 +43248 0.183502197265625 +43249 0.1517333984375 +43250 0.071136474609375 +43251 -0.01470947265625 +43252 -0.046661376953125 +43253 -0.1883544921875 +43254 -0.168304443359375 +43255 -0.372711181640625 +43256 -0.27069091796875 +43257 -0.51397705078125 +43258 -0.336029052734375 +43259 -0.57177734375 +43260 -0.359619140625 +43261 -0.53948974609375 +43262 -0.346527099609375 +43263 -0.43511962890625 +43264 -0.3094482421875 +43265 -0.2962646484375 +43266 -0.2620849609375 +43267 -0.161102294921875 +43268 -0.209930419921875 +43269 -0.0435791015625 +43270 -0.15228271484375 +43271 0.060394287109375 +43272 -0.096221923828125 +43273 0.13665771484375 +43274 -0.049591064453125 +43275 0.170135498046875 +43276 -0.012664794921875 +43277 0.16552734375 +43278 0.02593994140625 +43279 0.15728759765625 +43280 0.065948486328125 +43281 0.150787353515625 +43282 0.09539794921875 +43283 0.12200927734375 +43284 0.115753173828125 +43285 0.080108642578125 +43286 0.135589599609375 +43287 0.05126953125 +43288 0.164337158203125 +43289 0.062896728515625 +43290 0.191986083984375 +43291 0.09271240234375 +43292 0.1988525390625 +43293 0.092987060546875 +43294 0.190765380859375 +43295 0.07855224609375 +43296 0.174072265625 +43297 0.06427001953125 +43298 0.14349365234375 +43299 0.0347900390625 +43300 0.099578857421875 +43301 -0.01171875 +43302 0.051544189453125 +43303 -0.056060791015625 +43304 0.018310546875 +43305 -0.055511474609375 +43306 0.001617431640625 +43307 -0.010467529296875 +43308 -0.018157958984375 +43309 0.02508544921875 +43310 -0.04937744140625 +43311 0.025665283203125 +43312 -0.0799560546875 +43313 0.017333984375 +43314 -0.107818603515625 +43315 0.00189208984375 +43316 -0.136383056640625 +43317 -0.03173828125 +43318 -0.16021728515625 +43319 -0.071502685546875 +43320 -0.186279296875 +43321 -0.13543701171875 +43322 -0.21337890625 +43323 -0.219970703125 +43324 -0.232177734375 +43325 -0.300506591796875 +43326 -0.243316650390625 +43327 -0.376312255859375 +43328 -0.23553466796875 +43329 -0.416107177734375 +43330 -0.190765380859375 +43331 -0.371124267578125 +43332 -0.11090087890625 +43333 -0.242279052734375 +43334 -0.013580322265625 +43335 -0.069732666015625 +43336 0.091278076171875 +43337 0.125640869140625 +43338 0.189788818359375 +43339 0.31268310546875 +43340 0.266204833984375 +43341 0.45501708984375 +43342 0.3204345703125 +43343 0.554779052734375 +43344 0.351348876953125 +43345 0.61065673828125 +43346 0.35394287109375 +43347 0.610931396484375 +43348 0.318603515625 +43349 0.531463623046875 +43350 0.252105712890625 +43351 0.3883056640625 +43352 0.176422119140625 +43353 0.23468017578125 +43354 0.10235595703125 +43355 0.095245361328125 +43356 0.041412353515625 +43357 -0.00396728515625 +43358 0.000579833984375 +43359 -0.04852294921875 +43360 -0.025482177734375 +43361 -0.055145263671875 +43362 -0.0562744140625 +43363 -0.0758056640625 +43364 -0.101898193359375 +43365 -0.138702392578125 +43366 -0.147430419921875 +43367 -0.209197998046875 +43368 -0.19268798828125 +43369 -0.289031982421875 +43370 -0.23736572265625 +43371 -0.37884521484375 +43372 -0.27215576171875 +43373 -0.456329345703125 +43374 -0.29498291015625 +43375 -0.51641845703125 +43376 -0.290130615234375 +43377 -0.519287109375 +43378 -0.25537109375 +43379 -0.458251953125 +43380 -0.212005615234375 +43381 -0.384796142578125 +43382 -0.1707763671875 +43383 -0.323699951171875 +43384 -0.130401611328125 +43385 -0.269287109375 +43386 -0.081451416015625 +43387 -0.1951904296875 +43388 -0.0244140625 +43389 -0.100006103515625 +43390 0.0289306640625 +43391 -0.01055908203125 +43392 0.089752197265625 +43393 0.1033935546875 +43394 0.160186767578125 +43395 0.24908447265625 +43396 0.21832275390625 +43397 0.373199462890625 +43398 0.256744384765625 +43399 0.45806884765625 +43400 0.2784423828125 +43401 0.511474609375 +43402 0.296295166015625 +43403 0.565399169921875 +43404 0.307281494140625 +43405 0.61138916015625 +43406 0.287994384765625 +43407 0.5897216796875 +43408 0.23516845703125 +43409 0.4906005859375 +43410 0.156585693359375 +43411 0.33148193359375 +43412 0.067291259765625 +43413 0.147796630859375 +43414 -0.015106201171875 +43415 -0.01873779296875 +43416 -0.07861328125 +43417 -0.140289306640625 +43418 -0.112518310546875 +43419 -0.191986083984375 +43420 -0.120330810546875 +43421 -0.184295654296875 +43422 -0.119354248046875 +43423 -0.161834716796875 +43424 -0.126007080078125 +43425 -0.166595458984375 +43426 -0.1383056640625 +43427 -0.19390869140625 +43428 -0.14849853515625 +43429 -0.22442626953125 +43430 -0.165435791015625 +43431 -0.279754638671875 +43432 -0.18115234375 +43433 -0.3389892578125 +43434 -0.177093505859375 +43435 -0.3543701171875 +43436 -0.162750244140625 +43437 -0.348175048828125 +43438 -0.14105224609375 +43439 -0.32598876953125 +43440 -0.10089111328125 +43441 -0.2581787109375 +43442 -0.040985107421875 +43443 -0.139801025390625 +43444 0.03216552734375 +43445 0.014617919921875 +43446 0.093658447265625 +43447 0.144378662109375 +43448 0.131683349609375 +43449 0.221038818359375 +43450 0.156341552734375 +43451 0.27069091796875 +43452 0.167724609375 +43453 0.294036865234375 +43454 0.174072265625 +43455 0.311767578125 +43456 0.181640625 +43457 0.339141845703125 +43458 0.184417724609375 +43459 0.360260009765625 +43460 0.176910400390625 +43461 0.360504150390625 +43462 0.146728515625 +43463 0.308380126953125 +43464 0.085296630859375 +43465 0.18170166015625 +43466 0.003082275390625 +43467 0.0047607421875 +43468 -0.08026123046875 +43469 -0.17559814453125 +43470 -0.145843505859375 +43471 -0.3143310546875 +43472 -0.175445556640625 +43473 -0.36785888671875 +43474 -0.179412841796875 +43475 -0.36248779296875 +43476 -0.175933837890625 +43477 -0.343536376953125 +43478 -0.1611328125 +43479 -0.3018798828125 +43480 -0.132415771484375 +43481 -0.231414794921875 +43482 -0.083953857421875 +43483 -0.117645263671875 +43484 -0.029144287109375 +43485 0.007049560546875 +43486 0.009429931640625 +43487 0.087982177734375 +43488 0.037261962890625 +43489 0.13946533203125 +43490 0.059173583984375 +43491 0.17425537109375 +43492 0.073028564453125 +43493 0.188201904296875 +43494 0.07421875 +43495 0.171234130859375 +43496 0.060333251953125 +43497 0.118438720703125 +43498 0.0421142578125 +43499 0.05706787109375 +43500 0.020050048828125 +43501 -0.010711669921875 +43502 -0.0087890625 +43503 -0.0914306640625 +43504 -0.035247802734375 +43505 -0.162322998046875 +43506 -0.047698974609375 +43507 -0.194549560546875 +43508 -0.0302734375 +43509 -0.1492919921875 +43510 0.01910400390625 +43511 -0.02166748046875 +43512 0.074432373046875 +43513 0.124053955078125 +43514 0.104644775390625 +43515 0.211151123046875 +43516 0.11041259765625 +43517 0.240447998046875 +43518 0.104461669921875 +43519 0.242218017578125 +43520 0.091461181640625 +43521 0.2257080078125 +43522 0.07293701171875 +43523 0.194366455078125 +43524 0.034149169921875 +43525 0.115509033203125 +43526 -0.014190673828125 +43527 0.0128173828125 +43528 -0.04559326171875 +43529 -0.053802490234375 +43530 -0.071502685546875 +43531 -0.110626220703125 +43532 -0.11029052734375 +43533 -0.199493408203125 +43534 -0.150543212890625 +43535 -0.29437255859375 +43536 -0.16461181640625 +43537 -0.33221435546875 +43538 -0.13800048828125 +43539 -0.27972412109375 +43540 -0.092254638671875 +43541 -0.185333251953125 +43542 -0.06243896484375 +43543 -0.128204345703125 +43544 -0.052032470703125 +43545 -0.115692138671875 +43546 -0.047515869140625 +43547 -0.116455078125 +43548 -0.038330078125 +43549 -0.105926513671875 +43550 -0.011474609375 +43551 -0.053955078125 +43552 0.036956787109375 +43553 0.048797607421875 +43554 0.087005615234375 +43555 0.157318115234375 +43556 0.112335205078125 +43557 0.212005615234375 +43558 0.115386962890625 +43559 0.218475341796875 +43560 0.122802734375 +43561 0.23724365234375 +43562 0.150970458984375 +43563 0.30535888671875 +43564 0.18170166015625 +43565 0.38128662109375 +43566 0.188507080078125 +43567 0.404449462890625 +43568 0.180206298828125 +43569 0.3944091796875 +43570 0.1734619140625 +43571 0.3885498046875 +43572 0.157867431640625 +43573 0.362640380859375 +43574 0.114715576171875 +43575 0.27362060546875 +43576 0.042327880859375 +43577 0.11712646484375 +43578 -0.0362548828125 +43579 -0.054901123046875 +43580 -0.09820556640625 +43581 -0.19085693359375 +43582 -0.141204833984375 +43583 -0.28570556640625 +43584 -0.165130615234375 +43585 -0.339263916015625 +43586 -0.18145751953125 +43587 -0.3775634765625 +43588 -0.210052490234375 +43589 -0.445709228515625 +43590 -0.24725341796875 +43591 -0.535064697265625 +43592 -0.285888671875 +43593 -0.629058837890625 +43594 -0.3128662109375 +43595 -0.697601318359375 +43596 -0.31219482421875 +43597 -0.70391845703125 +43598 -0.281646728515625 +43599 -0.6424560546875 +43600 -0.21173095703125 +43601 -0.491241455078125 +43602 -0.10943603515625 +43603 -0.265716552734375 +43604 -0.0003662109375 +43605 -0.023712158203125 +43606 0.10076904296875 +43607 0.201751708984375 +43608 0.1785888671875 +43609 0.375823974609375 +43610 0.227142333984375 +43611 0.485076904296875 +43612 0.26373291015625 +43613 0.56884765625 +43614 0.291748046875 +43615 0.634765625 +43616 0.2913818359375 +43617 0.63763427734375 +43618 0.2576904296875 +43619 0.5660400390625 +43620 0.213714599609375 +43621 0.4720458984375 +43622 0.182159423828125 +43623 0.40692138671875 +43624 0.166351318359375 +43625 0.3778076171875 +43626 0.163055419921875 +43627 0.376953125 +43628 0.158172607421875 +43629 0.371978759765625 +43630 0.129974365234375 +43631 0.313140869140625 +43632 0.071502685546875 +43633 0.184417724609375 +43634 -0.005950927734375 +43635 0.011199951171875 +43636 -0.08673095703125 +43637 -0.171051025390625 +43638 -0.15985107421875 +43639 -0.33740234375 +43640 -0.21832275390625 +43641 -0.47198486328125 +43642 -0.25592041015625 +43643 -0.560394287109375 +43644 -0.26300048828125 +43645 -0.58056640625 +43646 -0.24627685546875 +43647 -0.54754638671875 +43648 -0.226715087890625 +43649 -0.508575439453125 +43650 -0.20263671875 +43651 -0.459503173828125 +43652 -0.171539306640625 +43653 -0.394378662109375 +43654 -0.150848388671875 +43655 -0.35260009765625 +43656 -0.13079833984375 +43657 -0.31170654296875 +43658 -0.078826904296875 +43659 -0.197418212890625 +43660 0.0057373046875 +43661 -0.007965087890625 +43662 0.101165771484375 +43663 0.207489013671875 +43664 0.189971923828125 +43665 0.409210205078125 +43666 0.2611083984375 +43667 0.57208251953125 +43668 0.301361083984375 +43669 0.66595458984375 +43670 0.296722412109375 +43671 0.65875244140625 +43672 0.254730224609375 +43673 0.56744384765625 +43674 0.192840576171875 +43675 0.431396484375 +43676 0.130462646484375 +43677 0.29443359375 +43678 0.079071044921875 +43679 0.182464599609375 +43680 0.024810791015625 +43681 0.06365966796875 +43682 -0.038360595703125 +43683 -0.075958251953125 +43684 -0.089691162109375 +43685 -0.189422607421875 +43686 -0.126983642578125 +43687 -0.271942138671875 +43688 -0.1585693359375 +43689 -0.342529296875 +43690 -0.168182373046875 +43691 -0.364166259765625 +43692 -0.151580810546875 +43693 -0.327239990234375 +43694 -0.128692626953125 +43695 -0.2769775390625 +43696 -0.117340087890625 +43697 -0.253692626953125 +43698 -0.11151123046875 +43699 -0.24365234375 +43700 -0.089996337890625 +43701 -0.1983642578125 +43702 -0.052154541015625 +43703 -0.116241455078125 +43704 -0.015472412109375 +43705 -0.036834716796875 +43706 0.017730712890625 +43707 0.034881591796875 +43708 0.04400634765625 +43709 0.09124755859375 +43710 0.053009033203125 +43711 0.10888671875 +43712 0.061248779296875 +43713 0.125518798828125 +43714 0.07598876953125 +43715 0.15771484375 +43716 0.085235595703125 +43717 0.17828369140625 +43718 0.08184814453125 +43719 0.17108154296875 +43720 0.063201904296875 +43721 0.129974365234375 +43722 0.041412353515625 +43723 0.082427978515625 +43724 0.016204833984375 +43725 0.027679443359375 +43726 -0.026123046875 +43727 -0.065643310546875 +43728 -0.0687255859375 +43729 -0.15936279296875 +43730 -0.09375 +43731 -0.21307373046875 +43732 -0.104583740234375 +43733 -0.234649658203125 +43734 -0.09063720703125 +43735 -0.2001953125 +43736 -0.055999755859375 +43737 -0.119171142578125 +43738 -0.015228271484375 +43739 -0.024749755859375 +43740 0.03289794921875 +43741 0.085784912109375 +43742 0.073272705078125 +43743 0.178131103515625 +43744 0.08978271484375 +43745 0.215576171875 +43746 0.0882568359375 +43747 0.211456298828125 +43748 0.072845458984375 +43749 0.17523193359375 +43750 0.053131103515625 +43751 0.128753662109375 +43752 0.042236328125 +43753 0.1019287109375 +43754 0.0311279296875 +43755 0.0743408203125 +43756 0.0185546875 +43757 0.04327392578125 +43758 0.01739501953125 +43759 0.038177490234375 +43760 0.03515625 +43761 0.076263427734375 +43762 0.064544677734375 +43763 0.14105224609375 +43764 0.085235595703125 +43765 0.186431884765625 +43766 0.0867919921875 +43767 0.188812255859375 +43768 0.065185546875 +43769 0.1390380859375 +43770 0.0224609375 +43771 0.041778564453125 +43772 -0.031005859375 +43773 -0.079437255859375 +43774 -0.0928955078125 +43775 -0.219390869140625 +43776 -0.15899658203125 +43777 -0.367828369140625 +43778 -0.21661376953125 +43779 -0.494873046875 +43780 -0.2452392578125 +43781 -0.556243896484375 +43782 -0.224151611328125 +43783 -0.508697509765625 +43784 -0.164031982421875 +43785 -0.3756103515625 +43786 -0.093719482421875 +43787 -0.218902587890625 +43788 -0.0247802734375 +43789 -0.063751220703125 +43790 0.043975830078125 +43791 0.091552734375 +43792 0.107696533203125 +43793 0.23602294921875 +43794 0.15411376953125 +43795 0.342987060546875 +43796 0.17535400390625 +43797 0.39520263671875 +43798 0.16998291015625 +43799 0.389373779296875 +43800 0.137542724609375 +43801 0.324249267578125 +43802 0.08953857421875 +43803 0.224090576171875 +43804 0.042694091796875 +43805 0.124267578125 +43806 0.002716064453125 +43807 0.037078857421875 +43808 -0.017547607421875 +43809 -0.010101318359375 +43810 -0.019287109375 +43811 -0.019439697265625 +43812 -0.0177001953125 +43813 -0.022796630859375 +43814 -0.004180908203125 +43815 -0.001556396484375 +43816 0.026702880859375 +43817 0.056304931640625 +43818 0.053924560546875 +43819 0.106719970703125 +43820 0.05242919921875 +43821 0.096893310546875 +43822 0.029541015625 +43823 0.042694091796875 +43824 0.002960205078125 +43825 -0.018035888671875 +43826 -0.022918701171875 +43827 -0.07586669921875 +43828 -0.04278564453125 +43829 -0.11944580078125 +43830 -0.061859130859375 +43831 -0.15972900390625 +43832 -0.0828857421875 +43833 -0.202606201171875 +43834 -0.10601806640625 +43835 -0.24859619140625 +43836 -0.134674072265625 +43837 -0.30517578125 +43838 -0.1639404296875 +43839 -0.36212158203125 +43840 -0.180450439453125 +43841 -0.39141845703125 +43842 -0.16619873046875 +43843 -0.35528564453125 +43844 -0.1192626953125 +43845 -0.249969482421875 +43846 -0.0477294921875 +43847 -0.092864990234375 +43848 0.035797119140625 +43849 0.08905029296875 +43850 0.102874755859375 +43851 0.2352294921875 +43852 0.140899658203125 +43853 0.318817138671875 +43854 0.1588134765625 +43855 0.358642578125 +43856 0.15338134765625 +43857 0.347747802734375 +43858 0.1243896484375 +43859 0.28564453125 +43860 0.09576416015625 +43861 0.223175048828125 +43862 0.084625244140625 +43863 0.196746826171875 +43864 0.078399658203125 +43865 0.179840087890625 +43866 0.069000244140625 +43867 0.155548095703125 +43868 0.069183349609375 +43869 0.151214599609375 +43870 0.074188232421875 +43871 0.156951904296875 +43872 0.06451416015625 +43873 0.13177490234375 +43874 0.051910400390625 +43875 0.100799560546875 +43876 0.04718017578125 +43877 0.087127685546875 +43878 0.0333251953125 +43879 0.05487060546875 +43880 0.004119873046875 +43881 -0.009002685546875 +43882 -0.040252685546875 +43883 -0.10400390625 +43884 -0.099456787109375 +43885 -0.229400634765625 +43886 -0.159454345703125 +43887 -0.35552978515625 +43888 -0.20111083984375 +43889 -0.441925048828125 +43890 -0.217437744140625 +43891 -0.473846435546875 +43892 -0.2147216796875 +43893 -0.464813232421875 +43894 -0.19488525390625 +43895 -0.419097900390625 +43896 -0.156707763671875 +43897 -0.334320068359375 +43898 -0.1082763671875 +43899 -0.227935791015625 +43900 -0.060638427734375 +43901 -0.12347412109375 +43902 -0.01690673828125 +43903 -0.02764892578125 +43904 0.03155517578125 +43905 0.077667236328125 +43906 0.0946044921875 +43907 0.2132568359375 +43908 0.1768798828125 +43909 0.38885498046875 +43910 0.2681884765625 +43911 0.582794189453125 +43912 0.3397216796875 +43913 0.734039306640625 +43914 0.371429443359375 +43915 0.800140380859375 +43916 0.361968994140625 +43917 0.7783203125 +43918 0.309661865234375 +43919 0.6651611328125 +43920 0.2139892578125 +43921 0.45965576171875 +43922 0.092529296875 +43923 0.199188232421875 +43924 -0.02386474609375 +43925 -0.050689697265625 +43926 -0.108367919921875 +43927 -0.23297119140625 +43928 -0.15283203125 +43929 -0.33013916015625 +43930 -0.169677734375 +43931 -0.368408203125 +43932 -0.173675537109375 +43933 -0.378936767578125 +43934 -0.172088623046875 +43935 -0.376983642578125 +43936 -0.173065185546875 +43937 -0.37969970703125 +43938 -0.178680419921875 +43939 -0.391510009765625 +43940 -0.176116943359375 +43941 -0.385345458984375 +43942 -0.15625 +43943 -0.3419189453125 +43944 -0.1292724609375 +43945 -0.28289794921875 +43946 -0.115570068359375 +43947 -0.251617431640625 +43948 -0.12359619140625 +43949 -0.266143798828125 +43950 -0.12823486328125 +43951 -0.273345947265625 +43952 -0.102752685546875 +43953 -0.216796875 +43954 -0.06207275390625 +43955 -0.128265380859375 +43956 -0.03466796875 +43957 -0.068145751953125 +43958 -0.02362060546875 +43959 -0.0430908203125 +43960 -0.015380859375 +43961 -0.024444580078125 +43962 0.005615234375 +43963 0.020721435546875 +43964 0.05450439453125 +43965 0.124481201171875 +43966 0.117584228515625 +43967 0.25787353515625 +43968 0.175140380859375 +43969 0.379119873046875 +43970 0.223236083984375 +43971 0.47991943359375 +43972 0.2467041015625 +43973 0.5281982421875 +43974 0.239471435546875 +43975 0.511138916015625 +43976 0.214447021484375 +43977 0.456207275390625 +43978 0.192352294921875 +43979 0.407470703125 +43980 0.182037353515625 +43981 0.383758544921875 +43982 0.170135498046875 +43983 0.35687255859375 +43984 0.1495361328125 +43985 0.31182861328125 +43986 0.121246337890625 +43987 0.250885009765625 +43988 0.081207275390625 +43989 0.1654052734375 +43990 0.019927978515625 +43991 0.035247802734375 +43992 -0.063751220703125 +43993 -0.142059326171875 +43994 -0.155242919921875 +43995 -0.33563232421875 +43996 -0.249420166015625 +43997 -0.5345458984375 +43998 -0.3382568359375 +43999 -0.72186279296875 +44000 -0.392974853515625 +44001 -0.836669921875 +44002 -0.391693115234375 +44003 -0.8326416015625 +44004 -0.343719482421875 +44005 -0.7296142578125 +44006 -0.27496337890625 +44007 -0.582550048828125 +44008 -0.208343505859375 +44009 -0.440093994140625 +44010 -0.154266357421875 +44011 -0.324310302734375 +44012 -0.09674072265625 +44013 -0.20147705078125 +44014 -0.02301025390625 +44015 -0.044647216796875 +44016 0.04693603515625 +44017 0.103973388671875 +44018 0.093292236328125 +44019 0.202392578125 +44020 0.122650146484375 +44021 0.264495849609375 +44022 0.157928466796875 +44023 0.338897705078125 +44024 0.20770263671875 +44025 0.443817138671875 +44026 0.255859375 +44027 0.545074462890625 +44028 0.290374755859375 +44029 0.6173095703125 +44030 0.30743408203125 +44031 0.6524658203125 +44032 0.31341552734375 +44033 0.66339111328125 +44034 0.311309814453125 +44035 0.6561279296875 +44036 0.289154052734375 +44037 0.606781005859375 +44038 0.239654541015625 +44039 0.501190185546875 +44040 0.169342041015625 +44041 0.352783203125 +44042 0.085479736328125 +44043 0.176544189453125 +44044 -0.015899658203125 +44045 -0.034820556640625 +44046 -0.123443603515625 +44047 -0.258209228515625 +44048 -0.211669921875 +44049 -0.44244384765625 +44050 -0.274658203125 +44051 -0.5753173828125 +44052 -0.31024169921875 +44053 -0.65203857421875 +44054 -0.302978515625 +44055 -0.641632080078125 +44056 -0.262054443359375 +44057 -0.562164306640625 +44058 -0.20989990234375 +44059 -0.458038330078125 +44060 -0.15716552734375 +44061 -0.350555419921875 +44062 -0.114227294921875 +44063 -0.260528564453125 +44064 -0.083038330078125 +44065 -0.192108154296875 +44066 -0.06170654296875 +44067 -0.141937255859375 +44068 -0.046051025390625 +44069 -0.1021728515625 +44070 -0.030792236328125 +44071 -0.062896728515625 +44072 -0.009552001953125 +44073 -0.011932373046875 +44074 0.02398681640625 +44075 0.062835693359375 +44076 0.063690185546875 +44077 0.148712158203125 +44078 0.107696533203125 +44079 0.241729736328125 +44080 0.159820556640625 +44081 0.34912109375 +44082 0.2132568359375 +44083 0.457305908203125 +44084 0.25677490234375 +44085 0.54388427734375 +44086 0.272216796875 +44087 0.5728759765625 +44088 0.240509033203125 +44089 0.506591796875 +44090 0.1646728515625 +44091 0.351226806640625 +44092 0.0645751953125 +44093 0.146514892578125 +44094 -0.033599853515625 +44095 -0.05523681640625 +44096 -0.11102294921875 +44097 -0.21624755859375 +44098 -0.167083740234375 +44099 -0.334930419921875 +44100 -0.19781494140625 +44101 -0.402984619140625 +44102 -0.21392822265625 +44103 -0.4412841796875 +44104 -0.238739013671875 +44105 -0.49578857421875 +44106 -0.269195556640625 +44107 -0.5601806640625 +44108 -0.288360595703125 +44109 -0.600738525390625 +44110 -0.279571533203125 +44111 -0.584228515625 +44112 -0.227020263671875 +44113 -0.47930908203125 +44114 -0.127349853515625 +44115 -0.27935791015625 +44116 0.007110595703125 +44117 -0.0089111328125 +44118 0.1446533203125 +44119 0.268798828125 +44120 0.249664306640625 +44121 0.482818603515625 +44122 0.307464599609375 +44123 0.60369873046875 +44124 0.3277587890625 +44125 0.650421142578125 +44126 0.331451416015625 +44127 0.66400146484375 +44128 0.31719970703125 +44129 0.6414794921875 +44130 0.279998779296875 +44131 0.572540283203125 +44132 0.2406005859375 +44133 0.498138427734375 +44134 0.209747314453125 +44135 0.439453125 +44136 0.176910400390625 +44137 0.375518798828125 +44138 0.126068115234375 +44139 0.274505615234375 +44140 0.04327392578125 +44141 0.1087646484375 +44142 -0.060272216796875 +44143 -0.099395751953125 +44144 -0.16864013671875 +44145 -0.3182373046875 +44146 -0.2825927734375 +44147 -0.5489501953125 +44148 -0.393280029296875 +44149 -0.7738037109375 +44150 -0.474212646484375 +44151 -0.86383056640625 +44152 -0.5087890625 +44153 -0.870391845703125 +44154 -0.506072998046875 +44155 -0.86895751953125 +44156 -0.472808837890625 +44157 -0.861053466796875 +44158 -0.400390625 +44159 -0.765869140625 +44160 -0.283203125 +44161 -0.5301513671875 +44162 -0.124908447265625 +44163 -0.214691162109375 +44164 0.052764892578125 +44165 0.137359619140625 +44166 0.223968505859375 +44167 0.474822998046875 +44168 0.370819091796875 +44169 0.76239013671875 +44170 0.479766845703125 +44171 0.867462158203125 +44172 0.5511474609375 +44173 0.870361328125 +44174 0.579254150390625 +44175 0.86480712890625 +44176 0.56689453125 +44177 0.831817626953125 +44178 0.5264892578125 +44179 0.677581787109375 +44180 0.4610595703125 +44181 0.495880126953125 +44182 0.380096435546875 +44183 0.30767822265625 +44184 0.28485107421875 +44185 0.116180419921875 +44186 0.15936279296875 +44187 -0.110748291015625 +44188 0.000213623046875 +44189 -0.381805419921875 +44190 -0.170989990234375 +44191 -0.6572265625 +44192 -0.32403564453125 +44193 -0.857421875 +44194 -0.43731689453125 +44195 -0.870391845703125 +44196 -0.50726318359375 +44197 -0.870391845703125 +44198 -0.5474853515625 +44199 -0.86444091796875 +44200 -0.576080322265625 +44201 -0.85723876953125 +44202 -0.583892822265625 +44203 -0.790008544921875 +44204 -0.543701171875 +44205 -0.62847900390625 +44206 -0.454010009765625 +44207 -0.3956298828125 +44208 -0.331451416015625 +44209 -0.126708984375 +44210 -0.18994140625 +44211 0.150115966796875 +44212 -0.035430908203125 +44213 0.424041748046875 +44214 0.118408203125 +44215 0.670623779296875 +44216 0.251983642578125 +44217 0.854522705078125 +44218 0.35638427734375 +44219 0.866485595703125 +44220 0.423858642578125 +44221 0.86920166015625 +44222 0.46356201171875 +44223 0.8653564453125 +44224 0.482330322265625 +44225 0.857147216796875 +44226 0.478729248046875 +44227 0.766845703125 +44228 0.455413818359375 +44229 0.628509521484375 +44230 0.409088134765625 +44231 0.462127685546875 +44232 0.352813720703125 +44233 0.297210693359375 +44234 0.292938232421875 +44235 0.14862060546875 +44236 0.218017578125 +44237 -0.00537109375 +44238 0.13189697265625 +44239 -0.15753173828125 +44240 0.032806396484375 +44241 -0.31304931640625 +44242 -0.08624267578125 +44243 -0.48876953125 +44244 -0.20159912109375 +44245 -0.6416015625 +44246 -0.300750732421875 +44247 -0.751373291015625 +44248 -0.395355224609375 +44249 -0.84619140625 +44250 -0.477996826171875 +44251 -0.861297607421875 +44252 -0.532012939453125 +44253 -0.863250732421875 +44254 -0.54150390625 +44255 -0.856597900390625 +44256 -0.512664794921875 +44257 -0.7498779296875 +44258 -0.4747314453125 +44259 -0.624542236328125 +44260 -0.41668701171875 +44261 -0.47808837890625 +44262 -0.30914306640625 +44263 -0.253387451171875 +44264 -0.175201416015625 +44265 0.003692626953125 +44266 -0.04937744140625 +44267 0.2257080078125 +44268 0.074554443359375 +44269 0.427154541015625 +44270 0.212860107421875 +44271 0.643218994140625 +44272 0.36065673828125 +44273 0.855926513671875 +44274 0.488739013671875 +44275 0.870361328125 +44276 0.57208251953125 +44277 0.870361328125 +44278 0.614288330078125 +44279 0.862762451171875 +44280 0.6138916015625 +44281 0.79669189453125 +44282 0.566192626953125 +44283 0.595794677734375 +44284 0.4859619140625 +44285 0.362152099609375 +44286 0.38739013671875 +44287 0.1270751953125 +44288 0.281768798828125 +44289 -0.086944580078125 +44290 0.17059326171875 +44291 -0.2784423828125 +44292 0.034942626953125 +44293 -0.484832763671875 +44294 -0.136199951171875 +44295 -0.729583740234375 +44296 -0.316375732421875 +44297 -0.86688232421875 +44298 -0.47222900390625 +44299 -0.870391845703125 +44300 -0.60150146484375 +44301 -0.86859130859375 +44302 -0.703338623046875 +44303 -0.86279296875 +44304 -0.75860595703125 +44305 -0.817962646484375 +44306 -0.74298095703125 +44307 -0.6116943359375 +44308 -0.65252685546875 +44309 -0.3128662109375 +44310 -0.505126953125 +44311 0.039398193359375 +44312 -0.31121826171875 +44313 0.422821044921875 +44314 -0.08831787109375 +44315 0.805145263671875 +44316 0.12738037109375 +44317 0.870361328125 +44318 0.3056640625 +44319 0.870361328125 +44320 0.440582275390625 +44321 0.860015869140625 +44322 0.528289794921875 +44323 0.727935791015625 +44324 0.565948486328125 +44325 0.48114013671875 +44326 0.566680908203125 +44327 0.2059326171875 +44328 0.542694091796875 +44329 -0.06103515625 +44330 0.499359130859375 +44331 -0.29913330078125 +44332 0.42889404296875 +44333 -0.516204833984375 +44334 0.322998046875 +44335 -0.7252197265625 +44336 0.19488525390625 +44337 -0.85980224609375 +44338 0.0628662109375 +44339 -0.870391845703125 +44340 -0.057281494140625 +44341 -0.870391845703125 +44342 -0.1395263671875 +44343 -0.858062744140625 +44344 -0.18170166015625 +44345 -0.673004150390625 +44346 -0.21197509765625 +44347 -0.42694091796875 +44348 -0.254180908203125 +44349 -0.2100830078125 +44350 -0.30718994140625 +44351 -0.0362548828125 +44352 -0.355377197265625 +44353 0.10943603515625 +44354 -0.388031005859375 +44355 0.23516845703125 +44356 -0.382904052734375 +44357 0.373687744140625 +44358 -0.340972900390625 +44359 0.517791748046875 +44360 -0.29595947265625 +44361 0.602783203125 +44362 -0.24505615234375 +44363 0.635711669921875 +44364 -0.17034912109375 +44365 0.655181884765625 +44366 -0.077178955078125 +44367 0.65948486328125 +44368 0.030120849609375 +44369 0.651275634765625 +44370 0.138427734375 +44371 0.61846923828125 +44372 0.22784423828125 +44373 0.53753662109375 +44374 0.288604736328125 +44375 0.404144287109375 +44376 0.3154296875 +44377 0.22186279296875 +44378 0.30889892578125 +44379 0.003997802734375 +44380 0.278656005859375 +44381 -0.22100830078125 +44382 0.235687255859375 +44383 -0.42449951171875 +44384 0.191375732421875 +44385 -0.579833984375 +44386 0.168548583984375 +44387 -0.641876220703125 +44388 0.16363525390625 +44389 -0.6177978515625 +44390 0.141998291015625 +44391 -0.575531005859375 +44392 0.100799560546875 +44393 -0.526336669921875 +44394 0.06781005859375 +44395 -0.42645263671875 +44396 0.05780029296875 +44397 -0.2581787109375 +44398 0.05133056640625 +44399 -0.068695068359375 +44400 0.027862548828125 +44401 0.09222412109375 +44402 -0.00250244140625 +44403 0.232147216796875 +44404 -0.034210205078125 +44405 0.3509521484375 +44406 -0.083038330078125 +44407 0.410064697265625 +44408 -0.164581298828125 +44409 0.372955322265625 +44410 -0.26751708984375 +44411 0.2554931640625 +44412 -0.363800048828125 +44413 0.10711669921875 +44414 -0.44287109375 +44415 -0.052886962890625 +44416 -0.4852294921875 +44417 -0.186279296875 +44418 -0.46087646484375 +44419 -0.23291015625 +44420 -0.382049560546875 +44421 -0.209442138671875 +44422 -0.2840576171875 +44423 -0.174163818359375 +44424 -0.171417236328125 +44425 -0.126739501953125 +44426 -0.0389404296875 +44427 -0.048126220703125 +44428 0.09814453125 +44429 0.0426025390625 +44430 0.2147216796875 +44431 0.10748291015625 +44432 0.303558349609375 +44433 0.1409912109375 +44434 0.3900146484375 +44435 0.19708251953125 +44436 0.470306396484375 +44437 0.273651123046875 +44438 0.514404296875 +44439 0.31768798828125 +44440 0.528106689453125 +44441 0.341094970703125 +44442 0.52484130859375 +44443 0.368011474609375 +44444 0.4921875 +44445 0.37249755859375 +44446 0.403717041015625 +44447 0.30072021484375 +44448 0.2620849609375 +44449 0.1517333984375 +44450 0.102996826171875 +44451 -0.01470947265625 +44452 -0.06396484375 +44453 -0.1883544921875 +44454 -0.236541748046875 +44455 -0.372711181640625 +44456 -0.38189697265625 +44457 -0.51397705078125 +44458 -0.474700927734375 +44459 -0.57177734375 +44460 -0.508270263671875 +44461 -0.53948974609375 +44462 -0.489776611328125 +44463 -0.43511962890625 +44464 -0.437744140625 +44465 -0.2962646484375 +44466 -0.371826171875 +44467 -0.161102294921875 +44468 -0.299591064453125 +44469 -0.0435791015625 +44470 -0.219818115234375 +44471 0.060394287109375 +44472 -0.141815185546875 +44473 0.13665771484375 +44474 -0.0760498046875 +44475 0.170135498046875 +44476 -0.022918701171875 +44477 0.16552734375 +44478 0.032745361328125 +44479 0.15728759765625 +44480 0.0904541015625 +44481 0.150787353515625 +44482 0.133941650390625 +44483 0.12200927734375 +44484 0.164947509765625 +44485 0.080108642578125 +44486 0.19476318359375 +44487 0.05126953125 +44488 0.235870361328125 +44489 0.062896728515625 +44490 0.274688720703125 +44491 0.09271240234375 +44492 0.284759521484375 +44493 0.092987060546875 +44494 0.27386474609375 +44495 0.07855224609375 +44496 0.250518798828125 +44497 0.06427001953125 +44498 0.20770263671875 +44499 0.0347900390625 +44500 0.146209716796875 +44501 -0.01171875 +44502 0.07861328125 +44503 -0.056060791015625 +44504 0.030426025390625 +44505 -0.055511474609375 +44506 0.004180908203125 +44507 -0.010467529296875 +44508 -0.02618408203125 +44509 0.02508544921875 +44510 -0.0716552734375 +44511 0.025665283203125 +44512 -0.11590576171875 +44513 0.017333984375 +44514 -0.155975341796875 +44515 0.00189208984375 +44516 -0.1962890625 +44517 -0.03173828125 +44518 -0.2294921875 +44519 -0.071502685546875 +44520 -0.264862060546875 +44521 -0.13543701171875 +44522 -0.30078125 +44523 -0.219970703125 +44524 -0.3248291015625 +44525 -0.300506591796875 +44526 -0.33795166015625 +44527 -0.376312255859375 +44528 -0.325103759765625 +44529 -0.416107177734375 +44530 -0.26220703125 +44531 -0.371124267578125 +44532 -0.15203857421875 +44533 -0.242279052734375 +44534 -0.01837158203125 +44535 -0.069732666015625 +44536 0.12530517578125 +44537 0.125640869140625 +44538 0.260223388671875 +44539 0.31268310546875 +44540 0.3651123046875 +44541 0.45501708984375 +44542 0.439727783203125 +44543 0.554779052734375 +44544 0.482666015625 +44545 0.61065673828125 +44546 0.487060546875 +44547 0.610931396484375 +44548 0.43939208984375 +44549 0.531463623046875 +44550 0.348846435546875 +44551 0.3883056640625 +44552 0.24554443359375 +44553 0.23468017578125 +44554 0.144287109375 +44555 0.095245361328125 +44556 0.060821533203125 +44557 -0.00396728515625 +44558 0.0047607421875 +44559 -0.04852294921875 +44560 -0.03125 +44561 -0.055145263671875 +44562 -0.07403564453125 +44563 -0.0758056640625 +44564 -0.13739013671875 +44565 -0.138702392578125 +44566 -0.200775146484375 +44567 -0.209197998046875 +44568 -0.263916015625 +44569 -0.289031982421875 +44570 -0.3262939453125 +44571 -0.37884521484375 +44572 -0.375091552734375 +44573 -0.456329345703125 +44574 -0.407379150390625 +44575 -0.51641845703125 +44576 -0.4014892578125 +44577 -0.519287109375 +44578 -0.354339599609375 +44579 -0.458251953125 +44580 -0.295166015625 +44581 -0.384796142578125 +44582 -0.238739013671875 +44583 -0.323699951171875 +44584 -0.18328857421875 +44585 -0.269287109375 +44586 -0.11578369140625 +44587 -0.1951904296875 +44588 -0.036956787109375 +44589 -0.100006103515625 +44590 0.036956787109375 +44591 -0.01055908203125 +44592 0.121307373046875 +44593 0.1033935546875 +44594 0.218963623046875 +44595 0.24908447265625 +44596 0.299774169921875 +44597 0.373199462890625 +44598 0.353515625 +44599 0.45806884765625 +44600 0.384185791015625 +44601 0.511474609375 +44602 0.40948486328125 +44603 0.565399169921875 +44604 0.4251708984375 +44605 0.61138916015625 +44606 0.399078369140625 +44607 0.5897216796875 +44608 0.32672119140625 +44609 0.4906005859375 +44610 0.21875 +44611 0.33148193359375 +44612 0.095855712890625 +44613 0.147796630859375 +44614 -0.01776123046875 +44615 -0.01873779296875 +44616 -0.1055908203125 +44617 -0.140289306640625 +44618 -0.15283203125 +44619 -0.191986083984375 +44620 -0.164276123046875 +44621 -0.184295654296875 +44622 -0.1636962890625 +44623 -0.161834716796875 +44624 -0.173675537109375 +44625 -0.166595458984375 +44626 -0.19134521484375 +44627 -0.19390869140625 +44628 -0.2060546875 +44629 -0.22442626953125 +44630 -0.22991943359375 +44631 -0.279754638671875 +44632 -0.251983642578125 +44633 -0.3389892578125 +44634 -0.24664306640625 +44635 -0.3543701171875 +44636 -0.22698974609375 +44637 -0.348175048828125 +44638 -0.197052001953125 +44639 -0.32598876953125 +44640 -0.141571044921875 +44641 -0.2581787109375 +44642 -0.058807373046875 +44643 -0.139801025390625 +44644 0.04229736328125 +44645 0.014617919921875 +44646 0.127471923828125 +44647 0.144378662109375 +44648 0.180450439453125 +44649 0.221038818359375 +44650 0.21502685546875 +44651 0.27069091796875 +44652 0.231353759765625 +44653 0.294036865234375 +44654 0.24072265625 +44655 0.311767578125 +44656 0.251708984375 +44657 0.339141845703125 +44658 0.256103515625 +44659 0.360260009765625 +44660 0.246307373046875 +44661 0.360504150390625 +44662 0.2049560546875 +44663 0.308380126953125 +44664 0.120086669921875 +44665 0.18170166015625 +44666 0.006195068359375 +44667 0.0047607421875 +44668 -0.109375 +44669 -0.17559814453125 +44670 -0.20037841796875 +44671 -0.3143310546875 +44672 -0.241455078125 +44673 -0.36785888671875 +44674 -0.24700927734375 +44675 -0.36248779296875 +44676 -0.24237060546875 +44677 -0.343536376953125 +44678 -0.222137451171875 +44679 -0.3018798828125 +44680 -0.18267822265625 +44681 -0.231414794921875 +44682 -0.115814208984375 +44683 -0.117645263671875 +44684 -0.040130615234375 +44685 0.007049560546875 +44686 0.012969970703125 +44687 0.087982177734375 +44688 0.0511474609375 +44689 0.13946533203125 +44690 0.08111572265625 +44691 0.17425537109375 +44692 0.09991455078125 +44693 0.188201904296875 +44694 0.101226806640625 +44695 0.171234130859375 +44696 0.081634521484375 +44697 0.118438720703125 +44698 0.056121826171875 +44699 0.05706787109375 +44700 0.025421142578125 +44701 -0.010711669921875 +44702 -0.014556884765625 +44703 -0.0914306640625 +44704 -0.0511474609375 +44705 -0.162322998046875 +44706 -0.068115234375 +44707 -0.194549560546875 +44708 -0.04345703125 +44709 -0.1492919921875 +44710 0.0257568359375 +44711 -0.02166748046875 +44712 0.103271484375 +44713 0.124053955078125 +44714 0.145843505859375 +44715 0.211151123046875 +44716 0.15435791015625 +44717 0.240447998046875 +44718 0.146484375 +44719 0.242218017578125 +44720 0.12799072265625 +44721 0.2257080078125 +44722 0.101348876953125 +44723 0.194366455078125 +44724 0.0484619140625 +44725 0.115509033203125 +44726 -0.016754150390625 +44727 0.0128173828125 +44728 -0.059967041015625 +44729 -0.053802490234375 +44730 -0.0958251953125 +44731 -0.110626220703125 +44732 -0.147979736328125 +44733 -0.199493408203125 +44734 -0.20159912109375 +44735 -0.29437255859375 +44736 -0.220947265625 +44737 -0.33221435546875 +44738 -0.187286376953125 +44739 -0.27972412109375 +44740 -0.128387451171875 +44741 -0.185333251953125 +44742 -0.089508056640625 +44743 -0.128204345703125 +44744 -0.075225830078125 +44745 -0.115692138671875 +44746 -0.068145751953125 +44747 -0.116455078125 +44748 -0.054718017578125 +44749 -0.105926513671875 +44750 -0.01824951171875 +44751 -0.053955078125 +44752 0.046173095703125 +44753 0.048797607421875 +44754 0.112701416015625 +44755 0.157318115234375 +44756 0.147247314453125 +44757 0.212005615234375 +44758 0.15283203125 +44759 0.218475341796875 +44760 0.163787841796875 +44761 0.23724365234375 +44762 0.201202392578125 +44763 0.30535888671875 +44764 0.241546630859375 +44765 0.38128662109375 +44766 0.2506103515625 +44767 0.404449462890625 +44768 0.239776611328125 +44769 0.3944091796875 +44770 0.2305908203125 +44771 0.3885498046875 +44772 0.20965576171875 +44773 0.362640380859375 +44774 0.152862548828125 +44775 0.27362060546875 +44776 0.058074951171875 +44777 0.11712646484375 +44778 -0.044891357421875 +44779 -0.054901123046875 +44780 -0.126434326171875 +44781 -0.19085693359375 +44782 -0.183502197265625 +44783 -0.28570556640625 +44784 -0.21588134765625 +44785 -0.339263916015625 +44786 -0.23828125 +44787 -0.3775634765625 +44788 -0.27630615234375 +44789 -0.445709228515625 +44790 -0.325103759765625 +44791 -0.535064697265625 +44792 -0.37542724609375 +44793 -0.629058837890625 +44794 -0.410369873046875 +44795 -0.697601318359375 +44796 -0.409271240234375 +44797 -0.70391845703125 +44798 -0.369293212890625 +44799 -0.6424560546875 +44800 -0.27777099609375 +44801 -0.491241455078125 +44802 -0.143585205078125 +44803 -0.265716552734375 +44804 -0.0006103515625 +44805 -0.023712158203125 +44806 0.131622314453125 +44807 0.201751708984375 +44808 0.232513427734375 +44809 0.375823974609375 +44810 0.294281005859375 +44811 0.485076904296875 +44812 0.340789794921875 +44813 0.56884765625 +44814 0.376861572265625 +44815 0.634765625 +44816 0.37554931640625 +44817 0.63763427734375 +44818 0.33013916015625 +44819 0.5660400390625 +44820 0.27197265625 +44821 0.4720458984375 +44822 0.23187255859375 +44823 0.40692138671875 +44824 0.214141845703125 +44825 0.3778076171875 +44826 0.214080810546875 +44827 0.376953125 +44828 0.21221923828125 +44829 0.371978759765625 +44830 0.178619384765625 +44831 0.313140869140625 +44832 0.103546142578125 +44833 0.184417724609375 +44834 0.002105712890625 +44835 0.011199951171875 +44836 -0.10455322265625 +44837 -0.171051025390625 +44838 -0.20166015625 +44839 -0.33740234375 +44840 -0.279815673828125 +44841 -0.47198486328125 +44842 -0.33050537109375 +44843 -0.560394287109375 +44844 -0.34063720703125 +44845 -0.58056640625 +44846 -0.3193359375 +44847 -0.54754638671875 +44848 -0.295013427734375 +44849 -0.508575439453125 +44850 -0.265228271484375 +44851 -0.459503173828125 +44852 -0.226409912109375 +44853 -0.394378662109375 +44854 -0.202117919921875 +44855 -0.35260009765625 +44856 -0.1788330078125 +44857 -0.31170654296875 +44858 -0.111907958984375 +44859 -0.197418212890625 +44860 -0.000152587890625 +44861 -0.007965087890625 +44862 0.126983642578125 +44863 0.207489013671875 +44864 0.24578857421875 +44865 0.409210205078125 +44866 0.34130859375 +44867 0.57208251953125 +44868 0.395599365234375 +44869 0.66595458984375 +44870 0.389495849609375 +44871 0.65875244140625 +44872 0.333282470703125 +44873 0.56744384765625 +44874 0.25067138671875 +44875 0.431396484375 +44876 0.16796875 +44877 0.29443359375 +44878 0.10076904296875 +44879 0.182464599609375 +44880 0.029937744140625 +44881 0.06365966796875 +44882 -0.05291748046875 +44883 -0.075958251953125 +44884 -0.119720458984375 +44885 -0.189422607421875 +44886 -0.167633056640625 +44887 -0.271942138671875 +44888 -0.208160400390625 +44889 -0.342529296875 +44890 -0.21923828125 +44891 -0.364166259765625 +44892 -0.1951904296875 +44893 -0.327239990234375 +44894 -0.163238525390625 +44895 -0.2769775390625 +44896 -0.147705078125 +44897 -0.253692626953125 +44898 -0.140380859375 +44899 -0.24365234375 +44900 -0.112274169921875 +44901 -0.1983642578125 +44902 -0.06243896484375 +44903 -0.116241455078125 +44904 -0.0146484375 +44905 -0.036834716796875 +44906 0.028106689453125 +44907 0.034881591796875 +44908 0.061279296875 +44909 0.09124755859375 +44910 0.07086181640625 +44911 0.10888671875 +44912 0.079559326171875 +44913 0.125518798828125 +44914 0.097412109375 +44915 0.15771484375 +44916 0.108154296875 +44917 0.17828369140625 +44918 0.102203369140625 +44919 0.17108154296875 +44920 0.07598876953125 +44921 0.129974365234375 +44922 0.046051025390625 +44923 0.082427978515625 +44924 0.01202392578125 +44925 0.027679443359375 +44926 -0.04486083984375 +44927 -0.065643310546875 +44928 -0.101654052734375 +44929 -0.15936279296875 +44930 -0.134063720703125 +44931 -0.21307373046875 +44932 -0.1468505859375 +44933 -0.234649658203125 +44934 -0.12567138671875 +44935 -0.2001953125 +44936 -0.076263427734375 +44937 -0.119171142578125 +44938 -0.0185546875 +44939 -0.024749755859375 +44940 0.048980712890625 +44941 0.085784912109375 +44942 0.105712890625 +44943 0.178131103515625 +44944 0.129547119140625 +44945 0.215576171875 +44946 0.12835693359375 +44947 0.211456298828125 +44948 0.1077880859375 +44949 0.17523193359375 +44950 0.080902099609375 +44951 0.128753662109375 +44952 0.065582275390625 +44953 0.1019287109375 +44954 0.049560546875 +44955 0.0743408203125 +44956 0.03118896484375 +44957 0.04327392578125 +44958 0.028106689453125 +44959 0.038177490234375 +44960 0.0506591796875 +44961 0.076263427734375 +44962 0.088958740234375 +44963 0.14105224609375 +44964 0.115386962890625 +44965 0.186431884765625 +44966 0.1158447265625 +44967 0.188812255859375 +44968 0.084869384765625 +44969 0.1390380859375 +44970 0.025360107421875 +44971 0.041778564453125 +44972 -0.0484619140625 +44973 -0.079437255859375 +44974 -0.133453369140625 +44975 -0.219390869140625 +44976 -0.223358154296875 +44977 -0.367828369140625 +44978 -0.300262451171875 +44979 -0.494873046875 +44980 -0.337554931640625 +44981 -0.556243896484375 +44982 -0.309234619140625 +44983 -0.508697509765625 +44984 -0.229339599609375 +44985 -0.3756103515625 +44986 -0.135040283203125 +44987 -0.218902587890625 +44988 -0.041473388671875 +44989 -0.063751220703125 +44990 0.05230712890625 +44991 0.091552734375 +44992 0.13970947265625 +44993 0.23602294921875 +44994 0.204681396484375 +44995 0.342987060546875 +44996 0.236846923828125 +44997 0.39520263671875 +44998 0.234161376953125 +44999 0.389373779296875 +45000 0.19586181640625 +45001 0.324249267578125 +45002 0.136444091796875 +45003 0.224090576171875 +45004 0.077117919921875 +45005 0.124267578125 +45006 0.02520751953125 +45007 0.037078857421875 +45008 -0.002838134765625 +45009 -0.010101318359375 +45010 -0.00836181640625 +45011 -0.019439697265625 +45012 -0.01043701171875 +45013 -0.022796630859375 +45014 0.0020751953125 +45015 -0.001556396484375 +45016 0.036407470703125 +45017 0.056304931640625 +45018 0.066131591796875 +45019 0.106719970703125 +45020 0.059600830078125 +45021 0.096893310546875 +45022 0.026397705078125 +45023 0.042694091796875 +45024 -0.010772705078125 +45025 -0.018035888671875 +45026 -0.046173095703125 +45027 -0.07586669921875 +45028 -0.07293701171875 +45029 -0.11944580078125 +45030 -0.09765625 +45031 -0.15972900390625 +45032 -0.123809814453125 +45033 -0.202606201171875 +45034 -0.15167236328125 +45035 -0.24859619140625 +45036 -0.185699462890625 +45037 -0.30517578125 +45038 -0.21978759765625 +45039 -0.36212158203125 +45040 -0.237152099609375 +45041 -0.39141845703125 +45042 -0.215087890625 +45043 -0.35528564453125 +45044 -0.151397705078125 +45045 -0.249969482421875 +45046 -0.05657958984375 +45047 -0.092864990234375 +45048 0.053131103515625 +45049 0.08905029296875 +45050 0.141387939453125 +45051 0.2352294921875 +45052 0.192047119140625 +45053 0.318817138671875 +45054 0.21636962890625 +45055 0.358642578125 +45056 0.2095947265625 +45057 0.347747802734375 +45058 0.170745849609375 +45059 0.28564453125 +45060 0.13153076171875 +45061 0.223175048828125 +45062 0.11517333984375 +45063 0.196746826171875 +45064 0.1051025390625 +45065 0.179840087890625 +45066 0.090728759765625 +45067 0.155548095703125 +45068 0.08935546875 +45069 0.151214599609375 +45070 0.0947265625 +45071 0.156951904296875 +45072 0.080841064453125 +45073 0.13177490234375 +45074 0.0634765625 +45075 0.100799560546875 +45076 0.057098388671875 +45077 0.087127685546875 +45078 0.038909912109375 +45079 0.05487060546875 +45080 0.000518798828125 +45081 -0.009002685546875 +45082 -0.057861328125 +45083 -0.10400390625 +45084 -0.1358642578125 +45085 -0.229400634765625 +45086 -0.214813232421875 +45087 -0.35552978515625 +45088 -0.2691650390625 +45089 -0.441925048828125 +45090 -0.28961181640625 +45091 -0.473846435546875 +45092 -0.284698486328125 +45093 -0.464813232421875 +45094 -0.257049560546875 +45095 -0.419097900390625 +45096 -0.205078125 +45097 -0.334320068359375 +45098 -0.139739990234375 +45099 -0.227935791015625 +45100 -0.0758056640625 +45101 -0.12347412109375 +45102 -0.017364501953125 +45103 -0.02764892578125 +45104 0.047149658203125 +45105 0.077667236328125 +45106 0.130950927734375 +45107 0.2132568359375 +45108 0.24029541015625 +45109 0.38885498046875 +45110 0.361541748046875 +45111 0.582794189453125 +45112 0.456207275390625 +45113 0.734039306640625 +45114 0.49749755859375 +45115 0.800140380859375 +45116 0.483673095703125 +45117 0.7783203125 +45118 0.412567138671875 +45119 0.6651611328125 +45120 0.283538818359375 +45121 0.45965576171875 +45122 0.120147705078125 +45123 0.199188232421875 +45124 -0.0362548828125 +45125 -0.050689697265625 +45126 -0.149749755859375 +45127 -0.23297119140625 +45128 -0.209381103515625 +45129 -0.33013916015625 +45130 -0.231781005859375 +45131 -0.368408203125 +45132 -0.23675537109375 +45133 -0.378936767578125 +45134 -0.2340087890625 +45135 -0.376983642578125 +45136 -0.2344970703125 +45137 -0.37969970703125 +45138 -0.241058349609375 +45139 -0.391510009765625 +45140 -0.23663330078125 +45141 -0.385345458984375 +45142 -0.20904541015625 +45143 -0.3419189453125 +45144 -0.1719970703125 +45145 -0.28289794921875 +45146 -0.15283203125 +45147 -0.251617431640625 +45148 -0.16290283203125 +45149 -0.266143798828125 +45150 -0.1685791015625 +45151 -0.273345947265625 +45152 -0.1341552734375 +45153 -0.216796875 +45154 -0.079620361328125 +45155 -0.128265380859375 +45156 -0.0430908203125 +45157 -0.068145751953125 +45158 -0.02862548828125 +45159 -0.0430908203125 +45160 -0.018096923828125 +45161 -0.024444580078125 +45162 0.009368896484375 +45163 0.020721435546875 +45164 0.0740966796875 +45165 0.124481201171875 +45166 0.157806396484375 +45167 0.25787353515625 +45168 0.234130859375 +45169 0.379119873046875 +45170 0.2978515625 +45171 0.47991943359375 +45172 0.32867431640625 +45173 0.5281982421875 +45174 0.3184814453125 +45175 0.511138916015625 +45176 0.284576416015625 +45177 0.456207275390625 +45178 0.2547607421875 +45179 0.407470703125 +45180 0.240875244140625 +45181 0.383758544921875 +45182 0.22503662109375 +45183 0.35687255859375 +45184 0.197723388671875 +45185 0.31182861328125 +45186 0.160308837890625 +45187 0.250885009765625 +45188 0.10723876953125 +45189 0.1654052734375 +45190 0.0257568359375 +45191 0.035247802734375 +45192 -0.085723876953125 +45193 -0.142059326171875 +45194 -0.20770263671875 +45195 -0.33563232421875 +45196 -0.333282470703125 +45197 -0.5345458984375 +45198 -0.4517822265625 +45199 -0.72186279296875 +45200 -0.524658203125 +45201 -0.836669921875 +45202 -0.52264404296875 +45203 -0.8326416015625 +45204 -0.458221435546875 +45205 -0.7296142578125 +45206 -0.366119384765625 +45207 -0.582550048828125 +45208 -0.277008056640625 +45209 -0.440093994140625 +45210 -0.20477294921875 +45211 -0.324310302734375 +45212 -0.1280517578125 +45213 -0.20147705078125 +45214 -0.029754638671875 +45215 -0.044647216796875 +45216 0.0634765625 +45217 0.103973388671875 +45218 0.1251220703125 +45219 0.202392578125 +45220 0.163970947265625 +45221 0.264495849609375 +45222 0.210784912109375 +45223 0.338897705078125 +45224 0.277069091796875 +45225 0.443817138671875 +45226 0.34124755859375 +45227 0.545074462890625 +45228 0.387237548828125 +45229 0.6173095703125 +45230 0.409942626953125 +45231 0.6524658203125 +45232 0.417449951171875 +45233 0.66339111328125 +45234 0.413543701171875 +45235 0.6561279296875 +45236 0.383056640625 +45237 0.606781005859375 +45238 0.3170166015625 +45239 0.501190185546875 +45240 0.223846435546875 +45241 0.352783203125 +45242 0.113037109375 +45243 0.176544189453125 +45244 -0.020050048828125 +45245 -0.034820556640625 +45246 -0.16082763671875 +45247 -0.258209228515625 +45248 -0.2769775390625 +45249 -0.44244384765625 +45250 -0.360809326171875 +45251 -0.5753173828125 +45252 -0.4093017578125 +45253 -0.65203857421875 +45254 -0.402862548828125 +45255 -0.641632080078125 +45256 -0.3529052734375 +45257 -0.562164306640625 +45258 -0.287506103515625 +45259 -0.458038330078125 +45260 -0.220062255859375 +45261 -0.350555419921875 +45262 -0.163726806640625 +45263 -0.260528564453125 +45264 -0.121063232421875 +45265 -0.192108154296875 +45266 -0.089935302734375 +45267 -0.141937255859375 +45268 -0.065338134765625 +45269 -0.1021728515625 +45270 -0.040985107421875 +45271 -0.062896728515625 +45272 -0.009124755859375 +45273 -0.011932373046875 +45274 0.037872314453125 +45275 0.062835693359375 +45276 0.092010498046875 +45277 0.148712158203125 +45278 0.1507568359375 +45279 0.241729736328125 +45280 0.21868896484375 +45281 0.34912109375 +45282 0.2872314453125 +45283 0.457305908203125 +45284 0.342193603515625 +45285 0.54388427734375 +45286 0.36083984375 +45287 0.5728759765625 +45288 0.3193359375 +45289 0.506591796875 +45290 0.2215576171875 +45291 0.351226806640625 +45292 0.092620849609375 +45293 0.146514892578125 +45294 -0.034454345703125 +45295 -0.05523681640625 +45296 -0.13580322265625 +45297 -0.21624755859375 +45298 -0.210418701171875 +45299 -0.334930419921875 +45300 -0.253082275390625 +45301 -0.402984619140625 +45302 -0.277008056640625 +45303 -0.4412841796875 +45304 -0.311279296875 +45305 -0.49578857421875 +45306 -0.351898193359375 +45307 -0.5601806640625 +45308 -0.3775634765625 +45309 -0.600738525390625 +45310 -0.36724853515625 +45311 -0.584228515625 +45312 -0.30084228515625 +45313 -0.47930908203125 +45314 -0.173492431640625 +45315 -0.27935791015625 +45316 -0.000518798828125 +45317 -0.0089111328125 +45318 0.17681884765625 +45319 0.268798828125 +45320 0.31207275390625 +45321 0.482818603515625 +45322 0.386199951171875 +45323 0.60369873046875 +45324 0.412200927734375 +45325 0.650421142578125 +45326 0.417633056640625 +45327 0.66400146484375 +45328 0.400665283203125 +45329 0.6414794921875 +45330 0.35455322265625 +45331 0.572540283203125 +45332 0.306427001953125 +45333 0.498138427734375 +45334 0.270172119140625 +45335 0.439453125 +45336 0.231689453125 +45337 0.375518798828125 +45338 0.169525146484375 +45339 0.274505615234375 +45340 0.065032958984375 +45341 0.1087646484375 +45342 -0.067352294921875 +45343 -0.099395751953125 +45344 -0.206878662109375 +45345 -0.3182373046875 +45346 -0.35467529296875 +45347 -0.5489501953125 +45348 -0.499237060546875 +45349 -0.7738037109375 +45350 -0.60565185546875 +45351 -0.86383056640625 +45352 -0.65203857421875 +45353 -0.870391845703125 +45354 -0.6502685546875 +45355 -0.86895751953125 +45356 -0.609130859375 +45357 -0.861053466796875 +45358 -0.51708984375 +45359 -0.765869140625 +45360 -0.3665771484375 +45361 -0.5301513671875 +45362 -0.16217041015625 +45363 -0.214691162109375 +45364 0.0677490234375 +45365 0.137359619140625 +45366 0.28936767578125 +45367 0.474822998046875 +45368 0.479339599609375 +45369 0.76239013671875 +45370 0.6199951171875 +45371 0.867462158203125 +45372 0.7119140625 +45373 0.870361328125 +45374 0.747650146484375 +45375 0.86480712890625 +45376 0.73095703125 +45377 0.831817626953125 +45378 0.67816162109375 +45379 0.677581787109375 +45380 0.593231201171875 +45381 0.495880126953125 +45382 0.48858642578125 +45383 0.30767822265625 +45384 0.365692138671875 +45385 0.116180419921875 +45386 0.20343017578125 +45387 -0.110748291015625 +45388 -0.002899169921875 +45389 -0.381805419921875 +45390 -0.225006103515625 +45391 -0.6572265625 +45392 -0.42333984375 +45393 -0.857421875 +45394 -0.569580078125 +45395 -0.870391845703125 +45396 -0.6591796875 +45397 -0.870391845703125 +45398 -0.710205078125 +45399 -0.86444091796875 +45400 -0.74658203125 +45401 -0.85723876953125 +45402 -0.75628662109375 +45403 -0.790008544921875 +45404 -0.703460693359375 +45405 -0.62847900390625 +45406 -0.586090087890625 +45407 -0.3956298828125 +45408 -0.426055908203125 +45409 -0.126708984375 +45410 -0.2415771484375 +45411 0.150115966796875 +45412 -0.0404052734375 +45413 0.424041748046875 +45414 0.159576416015625 +45415 0.670623779296875 +45416 0.332763671875 +45417 0.854522705078125 +45418 0.467559814453125 +45419 0.866485595703125 +45420 0.55389404296875 +45421 0.86920166015625 +45422 0.603973388671875 +45423 0.8653564453125 +45424 0.626861572265625 +45425 0.857147216796875 +45426 0.620758056640625 +45427 0.766845703125 +45428 0.5892333984375 +45429 0.628509521484375 +45430 0.5279541015625 +45431 0.462127685546875 +45432 0.454193115234375 +45433 0.297210693359375 +45434 0.376251220703125 +45435 0.14862060546875 +45436 0.278961181640625 +45437 -0.00537109375 +45438 0.167327880859375 +45439 -0.15753173828125 +45440 0.038909912109375 +45441 -0.31304931640625 +45442 -0.115631103515625 +45443 -0.48876953125 +45444 -0.2652587890625 +45445 -0.6416015625 +45446 -0.3936767578125 +45447 -0.751373291015625 +45448 -0.51629638671875 +45449 -0.84619140625 +45450 -0.62347412109375 +45451 -0.861297607421875 +45452 -0.693328857421875 +45453 -0.863250732421875 +45454 -0.70501708984375 +45455 -0.856597900390625 +45456 -0.66668701171875 +45457 -0.7498779296875 +45458 -0.61688232421875 +45459 -0.624542236328125 +45460 -0.541046142578125 +45461 -0.47808837890625 +45462 -0.400421142578125 +45463 -0.253387451171875 +45464 -0.225372314453125 +45465 0.003692626953125 +45466 -0.061279296875 +45467 0.2257080078125 +45468 0.10015869140625 +45469 0.427154541015625 +45470 0.280517578125 +45471 0.643218994140625 +45472 0.47344970703125 +45473 0.855926513671875 +45474 0.6405029296875 +45475 0.870361328125 +45476 0.74884033203125 +45477 0.870361328125 +45478 0.803314208984375 +45479 0.862762451171875 +45480 0.80206298828125 +45481 0.79669189453125 +45482 0.7388916015625 +45483 0.595794677734375 +45484 0.63323974609375 +45485 0.362152099609375 +45486 0.503814697265625 +45487 0.1270751953125 +45488 0.36474609375 +45489 -0.086944580078125 +45490 0.21746826171875 +45491 -0.2784423828125 +45492 0.038909912109375 +45493 -0.484832763671875 +45494 -0.18359375 +45495 -0.729583740234375 +45496 -0.416412353515625 +45497 -0.86688232421875 +45498 -0.617462158203125 +45499 -0.870391845703125 +45500 -0.78350830078125 +45501 -0.86859130859375 +45502 -0.86090087890625 +45503 -0.86279296875 +45504 -0.86846923828125 +45505 -0.817962646484375 +45506 -0.866180419921875 +45507 -0.6116943359375 +45508 -0.845306396484375 +45509 -0.3128662109375 +45510 -0.65655517578125 +45511 0.039398193359375 +45512 -0.408538818359375 +45513 0.422821044921875 +45514 -0.123504638671875 +45515 0.805145263671875 +45516 0.153228759765625 +45517 0.870361328125 +45518 0.3836669921875 +45519 0.870361328125 +45520 0.55987548828125 +45521 0.860015869140625 +45522 0.676605224609375 +45523 0.727935791015625 +45524 0.72991943359375 +45525 0.48114013671875 +45526 0.73577880859375 +45527 0.2059326171875 +45528 0.70904541015625 +45529 -0.06103515625 +45530 0.656280517578125 +45531 -0.29913330078125 +45532 0.56781005859375 +45533 -0.516204833984375 +45534 0.4334716796875 +45535 -0.7252197265625 +45536 0.269866943359375 +45537 -0.85980224609375 +45538 0.100006103515625 +45539 -0.870391845703125 +45540 -0.056182861328125 +45541 -0.870391845703125 +45542 -0.166046142578125 +45543 -0.858062744140625 +45544 -0.226409912109375 +45545 -0.673004150390625 +45546 -0.271759033203125 +45547 -0.42694091796875 +45548 -0.331146240234375 +45549 -0.2100830078125 +45550 -0.402801513671875 +45551 -0.0362548828125 +45552 -0.46710205078125 +45553 0.10943603515625 +45554 -0.51055908203125 +45555 0.23516845703125 +45556 -0.505523681640625 +45557 0.373687744140625 +45558 -0.45318603515625 +45559 0.517791748046875 +45560 -0.3953857421875 +45561 0.602783203125 +45562 -0.32879638671875 +45563 0.635711669921875 +45564 -0.231475830078125 +45565 0.655181884765625 +45566 -0.11029052734375 +45567 0.65948486328125 +45568 0.02935791015625 +45569 0.651275634765625 +45570 0.170745849609375 +45571 0.61846923828125 +45572 0.288299560546875 +45573 0.53753662109375 +45574 0.369232177734375 +45575 0.404144287109375 +45576 0.406524658203125 +45577 0.22186279296875 +45578 0.4007568359375 +45579 0.003997802734375 +45580 0.36419677734375 +45581 -0.22100830078125 +45582 0.31097412109375 +45583 -0.42449951171875 +45584 0.25567626953125 +45585 -0.579833984375 +45586 0.227874755859375 +45587 -0.641876220703125 +45588 0.2227783203125 +45589 -0.6177978515625 +45590 0.19537353515625 +45591 -0.575531005859375 +45592 0.14190673828125 +45593 -0.526336669921875 +45594 0.0985107421875 +45595 -0.42645263671875 +45596 0.084381103515625 +45597 -0.2581787109375 +45598 0.074371337890625 +45599 -0.068695068359375 +45600 0.0418701171875 +45601 0.09222412109375 +45602 0.0001220703125 +45603 0.232147216796875 +45604 -0.043487548828125 +45605 0.3509521484375 +45606 -0.10931396484375 +45607 0.410064697265625 +45608 -0.217498779296875 +45609 0.372955322265625 +45610 -0.35321044921875 +45611 0.2554931640625 +45612 -0.47991943359375 +45613 0.10711669921875 +45614 -0.58380126953125 +45615 -0.052886962890625 +45616 -0.6395263671875 +45617 -0.186279296875 +45618 -0.608154296875 +45619 -0.23291015625 +45620 -0.5054931640625 +45621 -0.209442138671875 +45622 -0.377471923828125 +45623 -0.174163818359375 +45624 -0.230010986328125 +45625 -0.126739501953125 +45626 -0.056396484375 +45627 -0.048126220703125 +45628 0.123504638671875 +45629 0.0426025390625 +45630 0.276947021484375 +45631 0.10748291015625 +45632 0.3944091796875 +45633 0.1409912109375 +45634 0.508697509765625 +45635 0.19708251953125 +45636 0.614837646484375 +45637 0.273651123046875 +45638 0.673675537109375 +45639 0.31768798828125 +45640 0.69268798828125 +45641 0.341094970703125 +45642 0.68927001953125 +45643 0.368011474609375 +45644 0.647247314453125 +45645 0.37249755859375 +45646 0.53228759765625 +45647 0.30072021484375 +45648 0.34783935546875 +45649 0.1517333984375 +45650 0.14031982421875 +45651 -0.01470947265625 +45652 -0.0777587890625 +45653 -0.1883544921875 +45654 -0.30340576171875 +45655 -0.372711181640625 +45656 -0.493865966796875 +45657 -0.51397705078125 +45658 -0.616119384765625 +45659 -0.57177734375 +45660 -0.661407470703125 +45661 -0.53948974609375 +45662 -0.639007568359375 +45663 -0.43511962890625 +45664 -0.57281494140625 +45665 -0.2962646484375 +45666 -0.488311767578125 +45667 -0.161102294921875 +45668 -0.395294189453125 +45669 -0.0435791015625 +45670 -0.292144775390625 +45671 0.060394287109375 +45672 -0.190948486328125 +45673 0.13665771484375 +45674 -0.10528564453125 +45675 0.170135498046875 +45676 -0.03570556640625 +45677 0.16552734375 +45678 0.037506103515625 +45679 0.15728759765625 +45680 0.11358642578125 +45681 0.150787353515625 +45682 0.17138671875 +45683 0.12200927734375 +45684 0.213104248046875 +45685 0.080108642578125 +45686 0.253265380859375 +45687 0.05126953125 +45688 0.308013916015625 +45689 0.062896728515625 +45690 0.35968017578125 +45691 0.09271240234375 +45692 0.373809814453125 +45693 0.092987060546875 +45694 0.360443115234375 +45695 0.07855224609375 +45696 0.33062744140625 +45697 0.06427001953125 +45698 0.27520751953125 +45699 0.0347900390625 +45700 0.195220947265625 +45701 -0.01171875 +45702 0.10699462890625 +45703 -0.056060791015625 +45704 0.043670654296875 +45705 -0.055511474609375 +45706 0.008636474609375 +45707 -0.010467529296875 +45708 -0.031951904296875 +45709 0.02508544921875 +45710 -0.092254638671875 +45711 0.025665283203125 +45712 -0.150970458984375 +45713 0.017333984375 +45714 -0.2042236328125 +45715 0.00189208984375 +45716 -0.2576904296875 +45717 -0.03173828125 +45718 -0.301727294921875 +45719 -0.071502685546875 +45720 -0.348388671875 +45721 -0.13543701171875 +45722 -0.39544677734375 +45723 -0.219970703125 +45724 -0.426849365234375 +45725 -0.300506591796875 +45726 -0.44378662109375 +45727 -0.376312255859375 +45728 -0.4267578125 +45729 -0.416107177734375 +45730 -0.34454345703125 +45731 -0.371124267578125 +45732 -0.200714111328125 +45733 -0.242279052734375 +45734 -0.0262451171875 +45735 -0.069732666015625 +45736 0.16131591796875 +45737 0.125640869140625 +45738 0.337554931640625 +45739 0.31268310546875 +45740 0.474822998046875 +45741 0.45501708984375 +45742 0.57275390625 +45743 0.554779052734375 +45744 0.629180908203125 +45745 0.61065673828125 +45746 0.635284423828125 +45747 0.610931396484375 +45748 0.57427978515625 +45749 0.531463623046875 +45750 0.457977294921875 +45751 0.3883056640625 +45752 0.324615478515625 +45753 0.23468017578125 +45754 0.193115234375 +45755 0.095245361328125 +45756 0.08367919921875 +45757 -0.00396728515625 +45758 0.00872802734375 +45759 -0.04852294921875 +45760 -0.040863037109375 +45761 -0.055145263671875 +45762 -0.098785400390625 +45763 -0.0758056640625 +45764 -0.182342529296875 +45765 -0.138702392578125 +45766 -0.265350341796875 +45767 -0.209197998046875 +45768 -0.34735107421875 +45769 -0.289031982421875 +45770 -0.427581787109375 +45771 -0.37884521484375 +45772 -0.489776611328125 +45773 -0.456329345703125 +45774 -0.53021240234375 +45775 -0.51641845703125 +45776 -0.52154541015625 +45777 -0.519287109375 +45778 -0.4599609375 +45779 -0.458251953125 +45780 -0.382568359375 +45781 -0.384796142578125 +45782 -0.308258056640625 +45783 -0.323699951171875 +45784 -0.2349853515625 +45785 -0.269287109375 +45786 -0.146453857421875 +45787 -0.1951904296875 +45788 -0.043701171875 +45789 -0.100006103515625 +45790 0.052581787109375 +45791 -0.01055908203125 +45792 0.161651611328125 +45793 0.1033935546875 +45794 0.28704833984375 +45795 0.24908447265625 +45796 0.39056396484375 +45797 0.373199462890625 +45798 0.459136962890625 +45799 0.45806884765625 +45800 0.49786376953125 +45801 0.511474609375 +45802 0.5291748046875 +45803 0.565399169921875 +45804 0.547760009765625 +45805 0.61138916015625 +45806 0.512969970703125 +45807 0.5897216796875 +45808 0.41925048828125 +45809 0.4906005859375 +45810 0.280242919921875 +45811 0.33148193359375 +45812 0.12225341796875 +45813 0.147796630859375 +45814 -0.02398681640625 +45815 -0.01873779296875 +45816 -0.137451171875 +45817 -0.140289306640625 +45818 -0.19927978515625 +45819 -0.191986083984375 +45820 -0.2154541015625 +45821 -0.184295654296875 +45822 -0.215972900390625 +45823 -0.161834716796875 +45824 -0.229339599609375 +45825 -0.166595458984375 +45826 -0.251953125 +45827 -0.19390869140625 +45828 -0.270294189453125 +45829 -0.22442626953125 +45830 -0.29986572265625 +45831 -0.279754638671875 +45832 -0.32672119140625 +45833 -0.3389892578125 +45834 -0.318389892578125 +45835 -0.3543701171875 +45836 -0.2916259765625 +45837 -0.348175048828125 +45838 -0.251678466796875 +45839 -0.32598876953125 +45840 -0.179229736328125 +45841 -0.2581787109375 +45842 -0.072174072265625 +45843 -0.139801025390625 +45844 0.058013916015625 +45845 0.014617919921875 +45846 0.167694091796875 +45847 0.144378662109375 +45848 0.236053466796875 +45849 0.221038818359375 +45850 0.2806396484375 +45851 0.27069091796875 +45852 0.301544189453125 +45853 0.294036865234375 +45854 0.31317138671875 +45855 0.311767578125 +45856 0.326507568359375 +45857 0.339141845703125 +45858 0.331207275390625 +45859 0.360260009765625 +45860 0.317626953125 +45861 0.360504150390625 +45862 0.263580322265625 +45863 0.308380126953125 +45864 0.15374755859375 +45865 0.18170166015625 +45866 0.00677490234375 +45867 0.0047607421875 +45868 -0.14227294921875 +45869 -0.17559814453125 +45870 -0.259735107421875 +45871 -0.3143310546875 +45872 -0.313018798828125 +45873 -0.36785888671875 +45874 -0.320556640625 +45875 -0.36248779296875 +45876 -0.3148193359375 +45877 -0.343536376953125 +45878 -0.288848876953125 +45879 -0.3018798828125 +45880 -0.238067626953125 +45881 -0.231414794921875 +45882 -0.1519775390625 +45883 -0.117645263671875 +45884 -0.054412841796875 +45885 0.007049560546875 +45886 0.01434326171875 +45887 0.087982177734375 +45888 0.0640869140625 +45889 0.13946533203125 +45890 0.103363037109375 +45891 0.17425537109375 +45892 0.128326416015625 +45893 0.188201904296875 +45894 0.13079833984375 +45895 0.171234130859375 +45896 0.1064453125 +45897 0.118438720703125 +45898 0.0743408203125 +45899 0.05706787109375 +45900 0.035400390625 +45901 -0.010711669921875 +45902 -0.015625 +45903 -0.0914306640625 +45904 -0.0625 +45905 -0.162322998046875 +45906 -0.084381103515625 +45907 -0.194549560546875 +45908 -0.05303955078125 +45909 -0.1492919921875 +45910 0.035247802734375 +45911 -0.02166748046875 +45912 0.134063720703125 +45913 0.124053955078125 +45914 0.188018798828125 +45915 0.211151123046875 +45916 0.19830322265625 +45917 0.240447998046875 +45918 0.18756103515625 +45919 0.242218017578125 +45920 0.16326904296875 +45921 0.2257080078125 +45922 0.128570556640625 +45923 0.194366455078125 +45924 0.060333251953125 +45925 0.115509033203125 +45926 -0.02362060546875 +45927 0.0128173828125 +45928 -0.079254150390625 +45929 -0.053802490234375 +45930 -0.125335693359375 +45931 -0.110626220703125 +45932 -0.192169189453125 +45933 -0.199493408203125 +45934 -0.2607421875 +45935 -0.29437255859375 +45936 -0.285247802734375 +45937 -0.33221435546875 +45938 -0.24169921875 +45939 -0.27972412109375 +45940 -0.165740966796875 +45941 -0.185333251953125 +45942 -0.11541748046875 +45943 -0.128204345703125 +45944 -0.096588134765625 +45945 -0.115692138671875 +45946 -0.087005615234375 +45947 -0.116455078125 +45948 -0.069366455078125 +45949 -0.105926513671875 +45950 -0.02227783203125 +45951 -0.053955078125 +45952 0.060577392578125 +45953 0.048797607421875 +45954 0.146026611328125 +45955 0.157318115234375 +45956 0.190399169921875 +45957 0.212005615234375 +45958 0.19757080078125 +45959 0.218475341796875 +45960 0.211517333984375 +45961 0.23724365234375 +45962 0.25927734375 +45963 0.30535888671875 +45964 0.310760498046875 +45965 0.38128662109375 +45966 0.322113037109375 +45967 0.404449462890625 +45968 0.30792236328125 +45969 0.3944091796875 +45970 0.29583740234375 +45971 0.3885498046875 +45972 0.2686767578125 +45973 0.362640380859375 +45974 0.195556640625 +45975 0.27362060546875 +45976 0.07373046875 +45977 0.11712646484375 +45978 -0.05853271484375 +45979 -0.054901123046875 +45980 -0.16326904296875 +45981 -0.19085693359375 +45982 -0.236572265625 +45983 -0.28570556640625 +45984 -0.27813720703125 +45985 -0.339263916015625 +45986 -0.306793212890625 +45987 -0.3775634765625 +45988 -0.35540771484375 +45989 -0.445709228515625 +45990 -0.417816162109375 +45991 -0.535064697265625 +45992 -0.48211669921875 +45993 -0.629058837890625 +45994 -0.52667236328125 +45995 -0.697601318359375 +45996 -0.525054931640625 +45997 -0.70391845703125 +45998 -0.47357177734375 +45999 -0.6424560546875 +46000 -0.356597900390625 +46001 -0.491241455078125 +46002 -0.185791015625 +46003 -0.265716552734375 +46004 -0.003570556640625 +46005 -0.023712158203125 +46006 0.1656494140625 +46007 0.201751708984375 +46008 0.296295166015625 +46009 0.375823974609375 +46010 0.37841796875 +46011 0.485076904296875 +46012 0.440521240234375 +46013 0.56884765625 +46014 0.4881591796875 +46015 0.634765625 +46016 0.488494873046875 +46017 0.63763427734375 +46018 0.433349609375 +46019 0.5660400390625 +46020 0.36083984375 +46021 0.4720458984375 +46022 0.308502197265625 +46023 0.40692138671875 +46024 0.2818603515625 +46025 0.3778076171875 +46026 0.27557373046875 +46027 0.376953125 +46028 0.266387939453125 +46029 0.371978759765625 +46030 0.218414306640625 +46031 0.313140869140625 +46032 0.1202392578125 +46033 0.184417724609375 +46034 -0.0093994140625 +46035 0.011199951171875 +46036 -0.144561767578125 +46037 -0.171051025390625 +46038 -0.2669677734375 +46039 -0.33740234375 +46040 -0.365020751953125 +46041 -0.47198486328125 +46042 -0.42828369140625 +46043 -0.560394287109375 +46044 -0.440826416015625 +46045 -0.58056640625 +46046 -0.4136962890625 +46047 -0.54754638671875 +46048 -0.381500244140625 +46049 -0.508575439453125 +46050 -0.341461181640625 +46051 -0.459503173828125 +46052 -0.28948974609375 +46053 -0.394378662109375 +46054 -0.254486083984375 +46055 -0.35260009765625 +46056 -0.2203369140625 +46057 -0.31170654296875 +46058 -0.13323974609375 +46059 -0.197418212890625 +46060 0.00787353515625 +46061 -0.007965087890625 +46062 0.167083740234375 +46063 0.207489013671875 +46064 0.315338134765625 +46065 0.409210205078125 +46066 0.434295654296875 +46067 0.57208251953125 +46068 0.502044677734375 +46069 0.66595458984375 +46070 0.495269775390625 +46071 0.65875244140625 +46072 0.42645263671875 +46073 0.56744384765625 +46074 0.324371337890625 +46075 0.431396484375 +46076 0.221160888671875 +46077 0.29443359375 +46078 0.135894775390625 +46079 0.182464599609375 +46080 0.04510498046875 +46081 0.06365966796875 +46082 -0.06121826171875 +46083 -0.075958251953125 +46084 -0.1473388671875 +46085 -0.189422607421875 +46086 -0.209686279296875 +46087 -0.271942138671875 +46088 -0.262786865234375 +46089 -0.342529296875 +46090 -0.278594970703125 +46091 -0.364166259765625 +46092 -0.2498779296875 +46093 -0.327239990234375 +46094 -0.211029052734375 +46095 -0.2769775390625 +46096 -0.1927490234375 +46097 -0.253692626953125 +46098 -0.184600830078125 +46099 -0.24365234375 +46100 -0.149749755859375 +46101 -0.1983642578125 +46102 -0.087005615234375 +46103 -0.116241455078125 +46104 -0.026397705078125 +46105 -0.036834716796875 +46106 0.028228759765625 +46107 0.034881591796875 +46108 0.071075439453125 +46109 0.09124755859375 +46110 0.08441162109375 +46111 0.10888671875 +46112 0.096893310546875 +46113 0.125518798828125 +46114 0.121124267578125 +46115 0.15771484375 +46116 0.136444091796875 +46117 0.17828369140625 +46118 0.130584716796875 +46119 0.17108154296875 +46120 0.098968505859375 +46121 0.129974365234375 +46122 0.06243896484375 +46123 0.082427978515625 +46124 0.020477294921875 +46125 0.027679443359375 +46126 -0.05072021484375 +46127 -0.065643310546875 +46128 -0.122161865234375 +46129 -0.15936279296875 +46130 -0.163116455078125 +46131 -0.21307373046875 +46132 -0.179595947265625 +46133 -0.234649658203125 +46134 -0.153411865234375 +46135 -0.2001953125 +46136 -0.091766357421875 +46137 -0.119171142578125 +46138 -0.019866943359375 +46139 -0.024749755859375 +46140 0.0643310546875 +46141 0.085784912109375 +46142 0.134735107421875 +46143 0.178131103515625 +46144 0.1634521484375 +46145 0.215576171875 +46146 0.16058349609375 +46147 0.211456298828125 +46148 0.133331298828125 +46149 0.17523193359375 +46150 0.0982666015625 +46151 0.128753662109375 +46152 0.078094482421875 +46153 0.1019287109375 +46154 0.057342529296875 +46155 0.0743408203125 +46156 0.033905029296875 +46157 0.04327392578125 +46158 0.0301513671875 +46159 0.038177490234375 +46160 0.05914306640625 +46161 0.076263427734375 +46162 0.10833740234375 +46163 0.14105224609375 +46164 0.1427001953125 +46165 0.186431884765625 +46166 0.144317626953125 +46167 0.188812255859375 +46168 0.10626220703125 +46169 0.1390380859375 +46170 0.0321044921875 +46171 0.041778564453125 +46172 -0.06024169921875 +46173 -0.079437255859375 +46174 -0.16680908203125 +46175 -0.219390869140625 +46176 -0.27978515625 +46177 -0.367828369140625 +46178 -0.376495361328125 +46179 -0.494873046875 +46180 -0.42327880859375 +46181 -0.556243896484375 +46182 -0.38726806640625 +46183 -0.508697509765625 +46184 -0.28619384765625 +46185 -0.3756103515625 +46186 -0.1671142578125 +46187 -0.218902587890625 +46188 -0.049163818359375 +46189 -0.063751220703125 +46190 0.06890869140625 +46191 0.091552734375 +46192 0.178802490234375 +46193 0.23602294921875 +46194 0.260223388671875 +46195 0.342987060546875 +46196 0.300048828125 +46197 0.39520263671875 +46198 0.2957763671875 +46199 0.389373779296875 +46200 0.246429443359375 +46201 0.324249267578125 +46202 0.170440673828125 +46203 0.224090576171875 +46204 0.094696044921875 +46205 0.124267578125 +46206 0.02850341796875 +46207 0.037078857421875 +46208 -0.007293701171875 +46209 -0.010101318359375 +46210 -0.01434326171875 +46211 -0.019439697265625 +46212 -0.016845703125 +46213 -0.022796630859375 +46214 -0.00067138671875 +46215 -0.001556396484375 +46216 0.04327392578125 +46217 0.056304931640625 +46218 0.081512451171875 +46219 0.106719970703125 +46220 0.073944091796875 +46221 0.096893310546875 +46222 0.03265380859375 +46223 0.042694091796875 +46224 -0.01361083984375 +46225 -0.018035888671875 +46226 -0.057647705078125 +46227 -0.07586669921875 +46228 -0.090850830078125 +46229 -0.11944580078125 +46230 -0.121551513671875 +46231 -0.15972900390625 +46232 -0.154205322265625 +46233 -0.202606201171875 +46234 -0.189178466796875 +46235 -0.24859619140625 +46236 -0.232147216796875 +46237 -0.30517578125 +46238 -0.275360107421875 +46239 -0.36212158203125 +46240 -0.297576904296875 +46241 -0.39141845703125 +46242 -0.270050048828125 +46243 -0.35528564453125 +46244 -0.18994140625 +46245 -0.249969482421875 +46246 -0.07049560546875 +46247 -0.092864990234375 +46248 0.067779541015625 +46249 0.08905029296875 +46250 0.17889404296875 +46251 0.2352294921875 +46252 0.242462158203125 +46253 0.318817138671875 +46254 0.272735595703125 +46255 0.358642578125 +46256 0.26446533203125 +46257 0.347747802734375 +46258 0.21728515625 +46259 0.28564453125 +46260 0.169830322265625 +46261 0.223175048828125 +46262 0.14971923828125 +46263 0.196746826171875 +46264 0.1368408203125 +46265 0.179840087890625 +46266 0.118377685546875 +46267 0.155548095703125 +46268 0.115081787109375 +46269 0.151214599609375 +46270 0.11944580078125 +46271 0.156951904296875 +46272 0.10028076171875 +46273 0.13177490234375 +46274 0.07672119140625 +46275 0.100799560546875 +46276 0.0662841796875 +46277 0.087127685546875 +46278 0.041717529296875 +46279 0.05487060546875 +46280 -0.006866455078125 +46281 -0.009002685546875 +46282 -0.079071044921875 +46283 -0.10400390625 +46284 -0.17437744140625 +46285 -0.229400634765625 +46286 -0.270233154296875 +46287 -0.35552978515625 +46288 -0.33587646484375 +46289 -0.441925048828125 +46290 -0.360137939453125 +46291 -0.473846435546875 +46292 -0.353240966796875 +46293 -0.464813232421875 +46294 -0.318450927734375 +46295 -0.419097900390625 +46296 -0.25396728515625 +46297 -0.334320068359375 +46298 -0.173065185546875 +46299 -0.227935791015625 +46300 -0.093658447265625 +46301 -0.12347412109375 +46302 -0.02081298828125 +46303 -0.02764892578125 +46304 0.05926513671875 +46305 0.077667236328125 +46306 0.162322998046875 +46307 0.2132568359375 +46308 0.295745849609375 +46309 0.38885498046875 +46310 0.443084716796875 +46311 0.582794189453125 +46312 0.5579833984375 +46313 0.734039306640625 +46314 0.608184814453125 +46315 0.800140380859375 +46316 0.591552734375 +46317 0.7783203125 +46318 0.505523681640625 +46319 0.6651611328125 +46320 0.349334716796875 +46321 0.45965576171875 +46322 0.1513671875 +46323 0.199188232421875 +46324 -0.038543701171875 +46325 -0.050689697265625 +46326 -0.17706298828125 +46327 -0.23297119140625 +46328 -0.250885009765625 +46329 -0.33013916015625 +46330 -0.279937744140625 +46331 -0.368408203125 +46332 -0.28790283203125 +46333 -0.378936767578125 +46334 -0.286376953125 +46335 -0.376983642578125 +46336 -0.28851318359375 +46337 -0.37969970703125 +46338 -0.297607421875 +46339 -0.391510009765625 +46340 -0.292510986328125 +46341 -0.385345458984375 +46342 -0.2581787109375 +46343 -0.3419189453125 +46344 -0.2119140625 +46345 -0.28289794921875 +46346 -0.188140869140625 +46347 -0.251617431640625 +46348 -0.201202392578125 +46349 -0.266143798828125 +46350 -0.208984375 +46351 -0.273345947265625 +46352 -0.166717529296875 +46353 -0.216796875 +46354 -0.099365234375 +46355 -0.128265380859375 +46356 -0.054656982421875 +46357 -0.068145751953125 +46358 -0.037689208984375 +46359 -0.0430908203125 +46360 -0.02557373046875 +46361 -0.024444580078125 +46362 0.007904052734375 +46363 0.020721435546875 +46364 0.088287353515625 +46365 0.124481201171875 +46366 0.19268798828125 +46367 0.25787353515625 +46368 0.2880859375 +46369 0.379119873046875 +46370 0.36798095703125 +46371 0.47991943359375 +46372 0.40692138671875 +46373 0.5281982421875 +46374 0.39471435546875 +46375 0.511138916015625 +46376 0.352996826171875 +46377 0.456207275390625 +46378 0.31658935546875 +46379 0.407470703125 +46380 0.30029296875 +46381 0.383758544921875 +46382 0.2816162109375 +46383 0.35687255859375 +46384 0.24853515625 +46385 0.31182861328125 +46386 0.202667236328125 +46387 0.250885009765625 +46388 0.1370849609375 +46389 0.1654052734375 +46390 0.035736083984375 +46391 0.035247802734375 +46392 -0.103424072265625 +46393 -0.142059326171875 +46394 -0.256011962890625 +46395 -0.33563232421875 +46396 -0.413360595703125 +46397 -0.5345458984375 +46398 -0.562042236328125 +46399 -0.72186279296875 +46400 -0.65380859375 +46401 -0.836669921875 +46402 -0.65191650390625 +46403 -0.8326416015625 +46404 -0.571990966796875 +46405 -0.7296142578125 +46406 -0.45745849609375 +46407 -0.582550048828125 +46408 -0.346710205078125 +46409 -0.440093994140625 +46410 -0.257110595703125 +46411 -0.324310302734375 +46412 -0.161865234375 +46413 -0.20147705078125 +46414 -0.03948974609375 +46415 -0.044647216796875 +46416 0.076690673828125 +46417 0.103973388671875 +46418 0.153472900390625 +46419 0.202392578125 +46420 0.201873779296875 +46421 0.264495849609375 +46422 0.260467529296875 +46423 0.338897705078125 +46424 0.343658447265625 +46425 0.443817138671875 +46426 0.424346923828125 +46427 0.545074462890625 +46428 0.482452392578125 +46429 0.6173095703125 +46430 0.51153564453125 +46431 0.6524658203125 +46432 0.52166748046875 +46433 0.66339111328125 +46434 0.517547607421875 +46435 0.6561279296875 +46436 0.480133056640625 +46437 0.606781005859375 +46438 0.39813232421875 +46439 0.501190185546875 +46440 0.2821044921875 +46441 0.352783203125 +46442 0.143829345703125 +46443 0.176544189453125 +46444 -0.022491455078125 +46445 -0.034820556640625 +46446 -0.1986083984375 +46447 -0.258209228515625 +46448 -0.34405517578125 +46449 -0.44244384765625 +46450 -0.44915771484375 +46451 -0.5753173828125 +46452 -0.5101318359375 +46453 -0.65203857421875 +46454 -0.502410888671875 +46455 -0.641632080078125 +46456 -0.4403076171875 +46457 -0.562164306640625 +46458 -0.358917236328125 +46459 -0.458038330078125 +46460 -0.275054931640625 +46461 -0.350555419921875 +46462 -0.205108642578125 +46463 -0.260528564453125 +46464 -0.152313232421875 +46465 -0.192108154296875 +46466 -0.113922119140625 +46467 -0.141937255859375 +46468 -0.083648681640625 +46469 -0.1021728515625 +46470 -0.0535888671875 +46471 -0.062896728515625 +46472 -0.014007568359375 +46473 -0.011932373046875 +46474 0.044708251953125 +46475 0.062835693359375 +46476 0.112518310546875 +46477 0.148712158203125 +46478 0.186248779296875 +46479 0.241729736328125 +46480 0.271636962890625 +46481 0.34912109375 +46482 0.35791015625 +46483 0.457305908203125 +46484 0.427276611328125 +46485 0.54388427734375 +46486 0.451202392578125 +46487 0.5728759765625 +46488 0.3997802734375 +46489 0.506591796875 +46490 0.277862548828125 +46491 0.351226806640625 +46492 0.1168212890625 +46493 0.146514892578125 +46494 -0.04193115234375 +46495 -0.05523681640625 +46496 -0.168548583984375 +46497 -0.21624755859375 +46498 -0.261810302734375 +46499 -0.334930419921875 +46500 -0.315185546875 +46501 -0.402984619140625 +46502 -0.345184326171875 +46503 -0.4412841796875 +46504 -0.38824462890625 +46505 -0.49578857421875 +46506 -0.439361572265625 +46507 -0.5601806640625 +46508 -0.471832275390625 +46509 -0.600738525390625 +46510 -0.45928955078125 +46511 -0.584228515625 +46512 -0.37689208984375 +46513 -0.47930908203125 +46514 -0.2193603515625 +46515 -0.27935791015625 +46516 -0.006072998046875 +46517 -0.0089111328125 +46518 0.212921142578125 +46519 0.268798828125 +46520 0.381500244140625 +46521 0.482818603515625 +46522 0.47637939453125 +46523 0.60369873046875 +46524 0.51263427734375 +46525 0.650421142578125 +46526 0.522796630859375 +46527 0.66400146484375 +46528 0.5045166015625 +46529 0.6414794921875 +46530 0.449676513671875 +46531 0.572540283203125 +46532 0.390716552734375 +46533 0.498138427734375 +46534 0.34442138671875 +46535 0.439453125 +46536 0.294158935546875 +46537 0.375518798828125 +46538 0.2147216796875 +46539 0.274505615234375 +46540 0.08416748046875 +46541 0.1087646484375 +46542 -0.079925537109375 +46543 -0.099395751953125 +46544 -0.252410888671875 +46545 -0.3182373046875 +46546 -0.434295654296875 +46547 -0.5489501953125 +46548 -0.611572265625 +46549 -0.7738037109375 +46550 -0.742340087890625 +46551 -0.86383056640625 +46552 -0.800323486328125 +46553 -0.870391845703125 +46554 -0.799560546875 +46555 -0.86895751953125 +46556 -0.75048828125 +46557 -0.861053466796875 +46558 -0.639404296875 +46559 -0.765869140625 +46560 -0.457366943359375 +46561 -0.5301513671875 +46562 -0.209991455078125 +46563 -0.214691162109375 +46564 0.068603515625 +46565 0.137359619140625 +46566 0.33782958984375 +46567 0.474822998046875 +46568 0.569549560546875 +46569 0.76239013671875 +46570 0.742431640625 +46571 0.867462158203125 +46572 0.854736328125 +46573 0.870361328125 +46574 0.85986328125 +46575 0.86480712890625 +46576 0.858062744140625 +46577 0.831817626953125 +46578 0.826934814453125 +46579 0.677581787109375 +46580 0.7271728515625 +46581 0.495880126953125 +46582 0.602783203125 +46583 0.30767822265625 +46584 0.45550537109375 +46585 0.116180419921875 +46586 0.260223388671875 +46587 -0.110748291015625 +46588 0.011444091796875 +46589 -0.381805419921875 +46590 -0.25689697265625 +46591 -0.6572265625 +46592 -0.49725341796875 +46593 -0.857421875 +46594 -0.67547607421875 +46595 -0.870391845703125 +46596 -0.7861328125 +46597 -0.870391845703125 +46598 -0.851348876953125 +46599 -0.86444091796875 +46600 -0.859527587890625 +46601 -0.85723876953125 +46602 -0.861419677734375 +46603 -0.790008544921875 +46604 -0.85498046875 +46605 -0.62847900390625 +46606 -0.72039794921875 +46607 -0.3956298828125 +46608 -0.52911376953125 +46609 -0.126708984375 +46610 -0.30718994140625 +46611 0.150115966796875 +46612 -0.063873291015625 +46613 0.424041748046875 +46614 0.17901611328125 +46615 0.670623779296875 +46616 0.389923095703125 +46617 0.854522705078125 +46618 0.55462646484375 +46619 0.866485595703125 +46620 0.660736083984375 +46621 0.86920166015625 +46622 0.723388671875 +46623 0.8653564453125 +46624 0.7537841796875 +46625 0.857147216796875 +46626 0.74951171875 +46627 0.766845703125 +46628 0.71478271484375 +46629 0.628509521484375 +46630 0.643890380859375 +46631 0.462127685546875 +46632 0.5579833984375 +46633 0.297210693359375 +46634 0.467010498046875 +46635 0.14862060546875 +46636 0.351898193359375 +46637 -0.00537109375 +46638 0.218505859375 +46639 -0.15753173828125 +46640 0.063568115234375 +46641 -0.31304931640625 +46642 -0.124755859375 +46643 -0.48876953125 +46644 -0.30810546875 +46645 -0.6416015625 +46646 -0.466339111328125 +46647 -0.751373291015625 +46648 -0.618621826171875 +46649 -0.84619140625 +46650 -0.75299072265625 +46651 -0.861297607421875 +46652 -0.842132568359375 +46653 -0.863250732421875 +46654 -0.8551025390625 +46655 -0.856597900390625 +46656 -0.81658935546875 +46657 -0.7498779296875 +46658 -0.7593994140625 +46659 -0.624542236328125 +46660 -0.670135498046875 +46661 -0.47808837890625 +46662 -0.50042724609375 +46663 -0.253387451171875 +46664 -0.287628173828125 +46665 0.003692626953125 +46666 -0.087860107421875 +46667 0.2257080078125 +46668 0.109405517578125 +46669 0.427154541015625 +46670 0.3310546875 +46671 0.643218994140625 +46672 0.56927490234375 +46673 0.855926513671875 +46674 0.77642822265625 +46675 0.870361328125 +46676 0.8607177734375 +46677 0.870361328125 +46678 0.8682861328125 +46679 0.862762451171875 +46680 0.868408203125 +46681 0.79669189453125 +46682 0.860198974609375 +46683 0.595794677734375 +46684 0.779296875 +46685 0.362152099609375 +46686 0.62255859375 +46687 0.1270751953125 +46688 0.453857421875 +46689 -0.086944580078125 +46690 0.274810791015625 +46691 -0.2784423828125 +46692 0.05657958984375 +46693 -0.484832763671875 +46694 -0.21673583984375 +46695 -0.729583740234375 +46696 -0.5035400390625 +46697 -0.86688232421875 +46698 -0.751739501953125 +46699 -0.870391845703125 +46700 -0.86572265625 +46701 -0.86859130859375 +46702 -0.870391845703125 +46703 -0.86279296875 +46704 -0.8680419921875 +46705 -0.817962646484375 +46706 -0.855224609375 +46707 -0.6116943359375 +46708 -0.646514892578125 +46709 -0.3128662109375 +46710 -0.365692138671875 +46711 0.039398193359375 +46712 -0.03717041015625 +46713 0.422821044921875 +46714 0.311065673828125 +46715 0.805145263671875 +46716 0.62384033203125 +46717 0.870361328125 +46718 0.85467529296875 +46719 0.870361328125 +46720 0.870361328125 +46721 0.860015869140625 +46722 0.870361328125 +46723 0.727935791015625 +46724 0.86126708984375 +46725 0.48114013671875 +46726 0.778228759765625 +46727 0.2059326171875 +46728 0.610809326171875 +46729 -0.06103515625 +46730 0.429595947265625 +46731 -0.29913330078125 +46732 0.228363037109375 +46733 -0.516204833984375 +46734 -0.001220703125 +46735 -0.7252197265625 +46736 -0.235870361328125 +46737 -0.85980224609375 +46738 -0.44622802734375 +46739 -0.870391845703125 +46740 -0.608551025390625 +46741 -0.870391845703125 +46742 -0.684906005859375 +46743 -0.858062744140625 +46744 -0.675445556640625 +46745 -0.673004150390625 +46746 -0.628265380859375 +46747 -0.42694091796875 +46748 -0.58563232421875 +46749 -0.2100830078125 +46750 -0.55206298828125 +46751 -0.0362548828125 +46752 -0.510040283203125 +46753 0.10943603515625 +46754 -0.449493408203125 +46755 0.23516845703125 +46756 -0.34210205078125 +46757 0.373687744140625 +46758 -0.1944580078125 +46759 0.517791748046875 +46760 -0.062469482421875 +46761 0.602783203125 +46762 0.055328369140625 +46763 0.635711669921875 +46764 0.184967041015625 +46765 0.655181884765625 +46766 0.31817626953125 +46767 0.65948486328125 +46768 0.449615478515625 +46769 0.651275634765625 +46770 0.561553955078125 +46771 0.61846923828125 +46772 0.62701416015625 +46773 0.53753662109375 +46774 0.635406494140625 +46775 0.404144287109375 +46776 0.583648681640625 +46777 0.22186279296875 +46778 0.4779052734375 +46779 0.003997802734375 +46780 0.3382568359375 +46781 -0.22100830078125 +46782 0.186614990234375 +46783 -0.42449951171875 +46784 0.044952392578125 +46785 -0.579833984375 +46786 -0.047943115234375 +46787 -0.641876220703125 +46788 -0.094879150390625 +46789 -0.6177978515625 +46790 -0.147491455078125 +46791 -0.575531005859375 +46792 -0.209686279296875 +46793 -0.526336669921875 +46794 -0.2393798828125 +46795 -0.42645263671875 +46796 -0.215606689453125 +46797 -0.2581787109375 +46798 -0.1708984375 +46799 -0.068695068359375 +46800 -0.1402587890625 +46801 0.09222412109375 +46802 -0.1121826171875 +46803 0.232147216796875 +46804 -0.082427978515625 +46805 0.3509521484375 +46806 -0.079620361328125 +46807 0.410064697265625 +46808 -0.131988525390625 +46809 0.372955322265625 +46810 -0.2259521484375 +46811 0.2554931640625 +46812 -0.321624755859375 +46813 0.10711669921875 +46814 -0.405303955078125 +46815 -0.052886962890625 +46816 -0.448699951171875 +46817 -0.186279296875 +46818 -0.40643310546875 +46819 -0.23291015625 +46820 -0.297027587890625 +46821 -0.209442138671875 +46822 -0.173675537109375 +46823 -0.174163818359375 +46824 -0.0413818359375 +46825 -0.126739501953125 +46826 0.110443115234375 +46827 -0.048126220703125 +46828 0.261566162109375 +46829 0.0426025390625 +46830 0.376861572265625 +46831 0.10748291015625 +46832 0.448822021484375 +46833 0.1409912109375 +46834 0.51995849609375 +46835 0.19708251953125 +46836 0.587799072265625 +46837 0.273651123046875 +46838 0.60894775390625 +46839 0.31768798828125 +46840 0.5946044921875 +46841 0.341094970703125 +46842 0.567047119140625 +46843 0.368011474609375 +46844 0.508056640625 +46845 0.37249755859375 +46846 0.377044677734375 +46847 0.30072021484375 +46848 0.17755126953125 +46849 0.1517333984375 +46850 -0.03668212890625 +46851 -0.01470947265625 +46852 -0.2537841796875 +46853 -0.1883544921875 +46854 -0.473114013671875 +46855 -0.372711181640625 +46856 -0.645751953125 +46857 -0.51397705078125 +46858 -0.73480224609375 +46859 -0.57177734375 +46860 -0.732818603515625 +46861 -0.53948974609375 +46862 -0.65411376953125 +46863 -0.43511962890625 +46864 -0.530517578125 +46865 -0.2962646484375 +46866 -0.395172119140625 +46867 -0.161102294921875 +46868 -0.26141357421875 +46869 -0.0435791015625 +46870 -0.127960205078125 +46871 0.060394287109375 +46872 -0.00958251953125 +46873 0.13665771484375 +46874 0.077728271484375 +46875 0.170135498046875 +46876 0.134613037109375 +46877 0.16552734375 +46878 0.186981201171875 +46879 0.15728759765625 +46880 0.236236572265625 +46881 0.150787353515625 +46882 0.25909423828125 +46883 0.12200927734375 +46884 0.260955810546875 +46885 0.080108642578125 +46886 0.2623291015625 +46887 0.05126953125 +46888 0.28546142578125 +46889 0.062896728515625 +46890 0.31103515625 +46891 0.09271240234375 +46892 0.298858642578125 +46893 0.092987060546875 +46894 0.262542724609375 +46895 0.07855224609375 +46896 0.216400146484375 +46897 0.06427001953125 +46898 0.149505615234375 +46899 0.0347900390625 +46900 0.062774658203125 +46901 -0.01171875 +46902 -0.02471923828125 +46903 -0.056060791015625 +46904 -0.073883056640625 +46905 -0.055511474609375 +46906 -0.08233642578125 +46907 -0.010467529296875 +46908 -0.093475341796875 +46909 0.02508544921875 +46910 -0.126861572265625 +46911 0.025665283203125 +46912 -0.15869140625 +46913 0.017333984375 +46914 -0.186370849609375 +46915 0.00189208984375 +46916 -0.21881103515625 +46917 -0.03173828125 +46918 -0.245941162109375 +46919 -0.071502685546875 +46920 -0.283721923828125 +46921 -0.13543701171875 +46922 -0.330291748046875 +46923 -0.219970703125 +46924 -0.366363525390625 +46925 -0.300506591796875 +46926 -0.393280029296875 +46927 -0.376312255859375 +46928 -0.38665771484375 +46929 -0.416107177734375 +46930 -0.30731201171875 +46931 -0.371124267578125 +46932 -0.158294677734375 +46933 -0.242279052734375 +46934 0.02410888671875 +46935 -0.069732666015625 +46936 0.220306396484375 +46937 0.125640869140625 +46938 0.402374267578125 +46939 0.31268310546875 +46940 0.538360595703125 +46941 0.45501708984375 +46942 0.62945556640625 +46943 0.554779052734375 +46944 0.674468994140625 +46945 0.61065673828125 +46946 0.663848876953125 +46947 0.610931396484375 +46948 0.577911376953125 +46949 0.531463623046875 +46950 0.431488037109375 +46951 0.3883056640625 +46952 0.271331787109375 +46953 0.23468017578125 +46954 0.12017822265625 +46955 0.095245361328125 +46956 0.00201416015625 +46957 -0.00396728515625 +46958 -0.06903076171875 +46959 -0.04852294921875 +46960 -0.1053466796875 +46961 -0.055145263671875 +46962 -0.1495361328125 +46963 -0.0758056640625 +46964 -0.2242431640625 +46965 -0.138702392578125 +46966 -0.29901123046875 +46967 -0.209197998046875 +46968 -0.374664306640625 +46969 -0.289031982421875 +46970 -0.4515380859375 +46971 -0.37884521484375 +46972 -0.510833740234375 +46973 -0.456329345703125 +46974 -0.548828125 +46975 -0.51641845703125 +46976 -0.532562255859375 +46977 -0.519287109375 +46978 -0.457550048828125 +46979 -0.458251953125 +46980 -0.36895751953125 +46981 -0.384796142578125 +46982 -0.289306640625 +46983 -0.323699951171875 +46984 -0.21533203125 +46985 -0.269287109375 +46986 -0.12615966796875 +46987 -0.1951904296875 +46988 -0.02197265625 +46989 -0.100006103515625 +46990 0.073211669921875 +46991 -0.01055908203125 +46992 0.184173583984375 +46993 0.1033935546875 +46994 0.316436767578125 +46995 0.24908447265625 +46996 0.424407958984375 +46997 0.373199462890625 +46998 0.49310302734375 +46999 0.45806884765625 +47000 0.52947998046875 +47001 0.511474609375 +47002 0.5614013671875 +47003 0.565399169921875 +47004 0.58258056640625 +47005 0.61138916015625 +47006 0.5433349609375 +47007 0.5897216796875 +47008 0.436553955078125 +47009 0.4906005859375 +47010 0.27838134765625 +47011 0.33148193359375 +47012 0.10015869140625 +47013 0.147796630859375 +47014 -0.06146240234375 +47015 -0.01873779296875 +47016 -0.181793212890625 +47017 -0.140289306640625 +47018 -0.23883056640625 +47019 -0.191986083984375 +47020 -0.24090576171875 +47021 -0.184295654296875 +47022 -0.225616455078125 +47023 -0.161834716796875 +47024 -0.228546142578125 +47025 -0.166595458984375 +47026 -0.24591064453125 +47027 -0.19390869140625 +47028 -0.261749267578125 +47029 -0.22442626953125 +47030 -0.295074462890625 +47031 -0.279754638671875 +47032 -0.3289794921875 +47033 -0.3389892578125 +47034 -0.3238525390625 +47035 -0.3543701171875 +47036 -0.2996826171875 +47037 -0.348175048828125 +47038 -0.262237548828125 +47039 -0.32598876953125 +47040 -0.1873779296875 +47041 -0.2581787109375 +47042 -0.07177734375 +47043 -0.139801025390625 +47044 0.07147216796875 +47045 0.014617919921875 +47046 0.190185546875 +47047 0.144378662109375 +47048 0.259857177734375 +47049 0.221038818359375 +47050 0.302490234375 +47051 0.27069091796875 +47052 0.318817138671875 +47053 0.294036865234375 +47054 0.32672119140625 +47055 0.311767578125 +47056 0.339691162109375 +47057 0.339141845703125 +47058 0.344940185546875 +47059 0.360260009765625 +47060 0.330780029296875 +47061 0.360504150390625 +47062 0.27105712890625 +47063 0.308380126953125 +47064 0.1475830078125 +47065 0.18170166015625 +47066 -0.017974853515625 +47067 0.0047607421875 +47068 -0.184814453125 +47069 -0.17559814453125 +47070 -0.31378173828125 +47071 -0.3143310546875 +47072 -0.367095947265625 +47073 -0.36785888671875 +47074 -0.366912841796875 +47075 -0.36248779296875 +47076 -0.351898193359375 +47077 -0.343536376953125 +47078 -0.314300537109375 +47079 -0.3018798828125 +47080 -0.249053955078125 +47081 -0.231414794921875 +47082 -0.14410400390625 +47083 -0.117645263671875 +47084 -0.02764892578125 +47085 0.007049560546875 +47086 0.05291748046875 +47087 0.087982177734375 +47088 0.10919189453125 +47089 0.13946533203125 +47090 0.151397705078125 +47091 0.17425537109375 +47092 0.175262451171875 +47093 0.188201904296875 +47094 0.171539306640625 +47095 0.171234130859375 +47096 0.135467529296875 +47097 0.118438720703125 +47098 0.089935302734375 +47099 0.05706787109375 +47100 0.03643798828125 +47101 -0.010711669921875 +47102 -0.03076171875 +47103 -0.0914306640625 +47104 -0.09259033203125 +47105 -0.162322998046875 +47106 -0.12408447265625 +47107 -0.194549560546875 +47108 -0.090240478515625 +47109 -0.1492919921875 +47110 0.0140380859375 +47111 -0.02166748046875 +47112 0.132537841796875 +47113 0.124053955078125 +47114 0.197967529296875 +47115 0.211151123046875 +47116 0.211883544921875 +47117 0.240447998046875 +47118 0.201873779296875 +47119 0.242218017578125 +47120 0.176849365234375 +47121 0.2257080078125 +47122 0.140411376953125 +47123 0.194366455078125 +47124 0.063934326171875 +47125 0.115509033203125 +47126 -0.03125 +47127 0.0128173828125 +47128 -0.091827392578125 +47129 -0.053802490234375 +47130 -0.141143798828125 +47131 -0.110626220703125 +47132 -0.216552734375 +47133 -0.199493408203125 +47134 -0.295196533203125 +47135 -0.29437255859375 +47136 -0.32147216796875 +47137 -0.33221435546875 +47138 -0.26629638671875 +47139 -0.27972412109375 +47140 -0.173187255859375 +47141 -0.185333251953125 +47142 -0.112945556640625 +47143 -0.128204345703125 +47144 -0.092620849609375 +47145 -0.115692138671875 +47146 -0.084869384765625 +47147 -0.116455078125 +47148 -0.068359375 +47149 -0.105926513671875 +47150 -0.01666259765625 +47151 -0.053955078125 +47152 0.0782470703125 +47153 0.048797607421875 +47154 0.17626953125 +47155 0.157318115234375 +47156 0.22442626953125 +47157 0.212005615234375 +47158 0.227783203125 +47159 0.218475341796875 +47160 0.24029541015625 +47161 0.23724365234375 +47162 0.295135498046875 +47163 0.30535888671875 +47164 0.355743408203125 +47165 0.38128662109375 +47166 0.368743896484375 +47167 0.404449462890625 +47168 0.3519287109375 +47169 0.3944091796875 +47170 0.338958740234375 +47171 0.3885498046875 +47172 0.308746337890625 +47173 0.362640380859375 +47174 0.223419189453125 +47175 0.27362060546875 +47176 0.07940673828125 +47177 0.11712646484375 +47178 -0.076873779296875 +47179 -0.054901123046875 +47180 -0.199432373046875 +47181 -0.19085693359375 +47182 -0.283782958984375 +47183 -0.28570556640625 +47184 -0.329833984375 +47185 -0.339263916015625 +47186 -0.36083984375 +47187 -0.3775634765625 +47188 -0.417022705078125 +47189 -0.445709228515625 +47190 -0.49102783203125 +47191 -0.535064697265625 +47192 -0.568450927734375 +47193 -0.629058837890625 +47194 -0.622894287109375 +47195 -0.697601318359375 +47196 -0.6220703125 +47197 -0.70391845703125 +47198 -0.5614013671875 +47199 -0.6424560546875 +47200 -0.421722412109375 +47201 -0.491241455078125 +47202 -0.21697998046875 +47203 -0.265716552734375 +47204 0.001220703125 +47205 -0.023712158203125 +47206 0.203399658203125 +47207 0.201751708984375 +47208 0.358551025390625 +47209 0.375823974609375 +47210 0.45477294921875 +47211 0.485076904296875 +47212 0.527099609375 +47213 0.56884765625 +47214 0.582427978515625 +47215 0.634765625 +47216 0.580841064453125 +47217 0.63763427734375 +47218 0.512420654296875 +47219 0.5660400390625 +47220 0.4237060546875 +47221 0.4720458984375 +47222 0.360504150390625 +47223 0.40692138671875 +47224 0.329498291015625 +47225 0.3778076171875 +47226 0.324066162109375 +47227 0.376953125 +47228 0.315704345703125 +47229 0.371978759765625 +47230 0.26043701171875 +47231 0.313140869140625 +47232 0.1441650390625 +47233 0.184417724609375 +47234 -0.010467529296875 +47235 0.011199951171875 +47236 -0.171966552734375 +47237 -0.171051025390625 +47238 -0.318267822265625 +47239 -0.33740234375 +47240 -0.43536376953125 +47241 -0.47198486328125 +47242 -0.510650634765625 +47243 -0.560394287109375 +47244 -0.52471923828125 +47245 -0.58056640625 +47246 -0.491180419921875 +47247 -0.54754638671875 +47248 -0.45220947265625 +47249 -0.508575439453125 +47250 -0.40435791015625 +47251 -0.459503173828125 +47252 -0.34259033203125 +47253 -0.394378662109375 +47254 -0.30206298828125 +47255 -0.35260009765625 +47256 -0.26300048828125 +47257 -0.31170654296875 +47258 -0.159576416015625 +47259 -0.197418212890625 +47260 0.009674072265625 +47261 -0.007965087890625 +47262 0.2010498046875 +47263 0.207489013671875 +47264 0.3792724609375 +47265 0.409210205078125 +47266 0.52215576171875 +47267 0.57208251953125 +47268 0.60302734375 +47269 0.66595458984375 +47270 0.59356689453125 +47271 0.65875244140625 +47272 0.509033203125 +47273 0.56744384765625 +47274 0.38458251953125 +47275 0.431396484375 +47276 0.259368896484375 +47277 0.29443359375 +47278 0.156585693359375 +47279 0.182464599609375 +47280 0.048126220703125 +47281 0.06365966796875 +47282 -0.0782470703125 +47283 -0.075958251953125 +47284 -0.180755615234375 +47285 -0.189422607421875 +47286 -0.255035400390625 +47287 -0.271942138671875 +47288 -0.31793212890625 +47289 -0.342529296875 +47290 -0.336639404296875 +47291 -0.364166259765625 +47292 -0.302642822265625 +47293 -0.327239990234375 +47294 -0.256195068359375 +47295 -0.2769775390625 +47296 -0.233184814453125 +47297 -0.253692626953125 +47298 -0.2215576171875 +47299 -0.24365234375 +47300 -0.178436279296875 +47301 -0.1983642578125 +47302 -0.102569580078125 +47303 -0.116241455078125 +47304 -0.029205322265625 +47305 -0.036834716796875 +47306 0.03704833984375 +47307 0.034881591796875 +47308 0.089263916015625 +47309 0.09124755859375 +47310 0.1065673828125 +47311 0.10888671875 +47312 0.12237548828125 +47313 0.125518798828125 +47314 0.1513671875 +47315 0.15771484375 +47316 0.169403076171875 +47317 0.17828369140625 +47318 0.16217041015625 +47319 0.17108154296875 +47320 0.12432861328125 +47321 0.129974365234375 +47322 0.080322265625 +47323 0.082427978515625 +47324 0.02960205078125 +47325 0.027679443359375 +47326 -0.05560302734375 +47327 -0.065643310546875 +47328 -0.1412353515625 +47329 -0.15936279296875 +47330 -0.1912841796875 +47331 -0.21307373046875 +47332 -0.212615966796875 +47333 -0.234649658203125 +47334 -0.18389892578125 +47335 -0.2001953125 +47336 -0.113433837890625 +47337 -0.119171142578125 +47338 -0.030609130859375 +47339 -0.024749755859375 +47340 0.0670166015625 +47341 0.085784912109375 +47342 0.149017333984375 +47343 0.178131103515625 +47344 0.182769775390625 +47345 0.215576171875 +47346 0.1800537109375 +47347 0.211456298828125 +47348 0.149200439453125 +47349 0.17523193359375 +47350 0.10955810546875 +47351 0.128753662109375 +47352 0.08758544921875 +47353 0.1019287109375 +47354 0.0650634765625 +47355 0.0743408203125 +47356 0.039459228515625 +47357 0.04327392578125 +47358 0.03680419921875 +47359 0.038177490234375 +47360 0.072845458984375 +47361 0.076263427734375 +47362 0.13330078125 +47363 0.14105224609375 +47364 0.17626953125 +47365 0.186431884765625 +47366 0.1798095703125 +47367 0.188812255859375 +47368 0.135284423828125 +47369 0.1390380859375 +47370 0.046875 +47371 0.041778564453125 +47372 -0.06390380859375 +47373 -0.079437255859375 +47374 -0.192413330078125 +47375 -0.219390869140625 +47376 -0.3292236328125 +47377 -0.367828369140625 +47378 -0.446868896484375 +47379 -0.494873046875 +47380 -0.504547119140625 +47381 -0.556243896484375 +47382 -0.462432861328125 +47383 -0.508697509765625 +47384 -0.3419189453125 +47385 -0.3756103515625 +47386 -0.19989013671875 +47387 -0.218902587890625 +47388 -0.059356689453125 +47389 -0.063751220703125 +47390 0.08135986328125 +47391 0.091552734375 +47392 0.212310791015625 +47393 0.23602294921875 +47394 0.309051513671875 +47395 0.342987060546875 +47396 0.355804443359375 +47397 0.39520263671875 +47398 0.349609375 +47399 0.389373779296875 +47400 0.28936767578125 +47401 0.324249267578125 +47402 0.1973876953125 +47403 0.224090576171875 +47404 0.106201171875 +47405 0.124267578125 +47406 0.02703857421875 +47407 0.037078857421875 +47408 -0.01495361328125 +47409 -0.010101318359375 +47410 -0.0218505859375 +47411 -0.019439697265625 +47412 -0.023040771484375 +47413 -0.022796630859375 +47414 -0.00152587890625 +47415 -0.001556396484375 +47416 0.053619384765625 +47417 0.056304931640625 +47418 0.10174560546875 +47419 0.106719970703125 +47420 0.094207763671875 +47421 0.096893310546875 +47422 0.0455322265625 +47423 0.042694091796875 +47424 -0.009552001953125 +47425 -0.018035888671875 +47426 -0.062347412109375 +47427 -0.07586669921875 +47428 -0.102447509765625 +47429 -0.11944580078125 +47430 -0.139923095703125 +47431 -0.15972900390625 +47432 -0.18017578125 +47433 -0.202606201171875 +47434 -0.223602294921875 +47435 -0.24859619140625 +47436 -0.277008056640625 +47437 -0.30517578125 +47438 -0.3309326171875 +47439 -0.36212158203125 +47440 -0.3594970703125 +47441 -0.39141845703125 +47442 -0.32781982421875 +47443 -0.35528564453125 +47444 -0.23236083984375 +47445 -0.249969482421875 +47446 -0.089111328125 +47447 -0.092864990234375 +47448 0.077178955078125 +47449 0.08905029296875 +47450 0.210906982421875 +47451 0.2352294921875 +47452 0.287384033203125 +47453 0.318817138671875 +47454 0.323944091796875 +47455 0.358642578125 +47456 0.314178466796875 +47457 0.347747802734375 +47458 0.25762939453125 +47459 0.28564453125 +47460 0.201019287109375 +47461 0.223175048828125 +47462 0.177734375 +47463 0.196746826171875 +47464 0.163360595703125 +47465 0.179840087890625 +47466 0.14227294921875 +47467 0.155548095703125 +47468 0.139556884765625 +47469 0.151214599609375 +47470 0.14605712890625 +47471 0.156951904296875 +47472 0.123992919921875 +47473 0.13177490234375 +47474 0.096405029296875 +47475 0.100799560546875 +47476 0.084503173828125 +47477 0.087127685546875 +47478 0.055267333984375 +47479 0.05487060546875 +47480 -0.0032958984375 +47481 -0.009002685546875 +47482 -0.09075927734375 +47483 -0.10400390625 +47484 -0.20648193359375 +47485 -0.229400634765625 +47486 -0.3231201171875 +47487 -0.35552978515625 +47488 -0.40338134765625 +47489 -0.441925048828125 +47490 -0.433685302734375 +47491 -0.473846435546875 +47492 -0.4263916015625 +47493 -0.464813232421875 +47494 -0.3853759765625 +47495 -0.419097900390625 +47496 -0.308380126953125 +47497 -0.334320068359375 +47498 -0.211395263671875 +47499 -0.227935791015625 +47500 -0.1160888671875 +47501 -0.12347412109375 +47502 -0.028564453125 +47503 -0.02764892578125 +47504 0.067901611328125 +47505 0.077667236328125 +47506 0.19244384765625 +47507 0.2132568359375 +47508 0.35400390625 +47509 0.38885498046875 +47510 0.532623291015625 +47511 0.582794189453125 +47512 0.672149658203125 +47513 0.734039306640625 +47514 0.7335205078125 +47515 0.800140380859375 +47516 0.714111328125 +47517 0.7783203125 +47518 0.610748291015625 +47519 0.6651611328125 +47520 0.4224853515625 +47521 0.45965576171875 +47522 0.18365478515625 +47523 0.199188232421875 +47524 -0.04547119140625 +47525 -0.050689697265625 +47526 -0.212493896484375 +47527 -0.23297119140625 +47528 -0.30133056640625 +47529 -0.33013916015625 +47530 -0.33612060546875 +47531 -0.368408203125 +47532 -0.345550537109375 +47533 -0.378936767578125 +47534 -0.34368896484375 +47535 -0.376983642578125 +47536 -0.3463134765625 +47537 -0.37969970703125 +47538 -0.357452392578125 +47539 -0.391510009765625 +47540 -0.352203369140625 +47541 -0.385345458984375 +47542 -0.312774658203125 +47543 -0.3419189453125 +47544 -0.25909423828125 +47545 -0.28289794921875 +47546 -0.230987548828125 +47547 -0.251617431640625 +47548 -0.2449951171875 +47549 -0.266143798828125 +47550 -0.25225830078125 +47551 -0.273345947265625 +47552 -0.2008056640625 +47553 -0.216796875 +47554 -0.11981201171875 +47555 -0.128265380859375 +47556 -0.06488037109375 +47557 -0.068145751953125 +47558 -0.042083740234375 +47559 -0.0430908203125 +47560 -0.0250244140625 +47561 -0.024444580078125 +47562 0.016571044921875 +47563 0.020721435546875 +47564 0.112213134765625 +47565 0.124481201171875 +47566 0.2352294921875 +47567 0.25787353515625 +47568 0.34716796875 +47569 0.379119873046875 +47570 0.44036865234375 +47571 0.47991943359375 +47572 0.48529052734375 +47573 0.5281982421875 +47574 0.470123291015625 +47575 0.511138916015625 +47576 0.42010498046875 +47577 0.456207275390625 +47578 0.375762939453125 +47579 0.407470703125 +47580 0.354400634765625 +47581 0.383758544921875 +47582 0.33001708984375 +47583 0.35687255859375 +47584 0.288818359375 +47585 0.31182861328125 +47586 0.23284912109375 +47587 0.250885009765625 +47588 0.154205322265625 +47589 0.1654052734375 +47590 0.03436279296875 +47591 0.035247802734375 +47592 -0.128936767578125 +47593 -0.142059326171875 +47594 -0.30731201171875 +47595 -0.33563232421875 +47596 -0.49066162109375 +47597 -0.5345458984375 +47598 -0.663360595703125 +47599 -0.72186279296875 +47600 -0.769378662109375 +47601 -0.836669921875 +47602 -0.766082763671875 +47603 -0.8326416015625 +47604 -0.67169189453125 +47605 -0.7296142578125 +47606 -0.5367431640625 +47607 -0.582550048828125 +47608 -0.405975341796875 +47609 -0.440093994140625 +47610 -0.299713134765625 +47611 -0.324310302734375 +47612 -0.1868896484375 +47613 -0.20147705078125 +47614 -0.042694091796875 +47615 -0.044647216796875 +47616 0.093475341796875 +47617 0.103973388671875 +47618 0.18231201171875 +47619 0.202392578125 +47620 0.23724365234375 +47621 0.264495849609375 +47622 0.3048095703125 +47623 0.338897705078125 +47624 0.402496337890625 +47625 0.443817138671875 +47626 0.49786376953125 +47627 0.545074462890625 +47628 0.5667724609375 +47629 0.6173095703125 +47630 0.601531982421875 +47631 0.6524658203125 +47632 0.614288330078125 +47633 0.66339111328125 +47634 0.610626220703125 +47635 0.6561279296875 +47636 0.567596435546875 +47637 0.606781005859375 +47638 0.471466064453125 +47639 0.501190185546875 +47640 0.334747314453125 +47641 0.352783203125 +47642 0.17144775390625 +47643 0.176544189453125 +47644 -0.025604248046875 +47645 -0.034820556640625 +47646 -0.234649658203125 +47647 -0.258209228515625 +47648 -0.407135009765625 +47649 -0.44244384765625 +47650 -0.53155517578125 +47651 -0.5753173828125 +47652 -0.60345458984375 +47653 -0.65203857421875 +47654 -0.5933837890625 +47655 -0.641632080078125 +47656 -0.518524169921875 +47657 -0.562164306640625 +47658 -0.42108154296875 +47659 -0.458038330078125 +47660 -0.321197509765625 +47661 -0.350555419921875 +47662 -0.238555908203125 +47663 -0.260528564453125 +47664 -0.176910400390625 +47665 -0.192108154296875 +47666 -0.13287353515625 +47667 -0.141937255859375 +47668 -0.0987548828125 +47669 -0.1021728515625 +47670 -0.06494140625 +47671 -0.062896728515625 +47672 -0.01959228515625 +47673 -0.011932373046875 +47674 0.0489501953125 +47675 0.062835693359375 +47676 0.128753662109375 +47677 0.148712158203125 +47678 0.216094970703125 +47679 0.241729736328125 +47680 0.317901611328125 +47681 0.34912109375 +47682 0.421295166015625 +47683 0.457305908203125 +47684 0.5048828125 +47685 0.54388427734375 +47686 0.534332275390625 +47687 0.5728759765625 +47688 0.4736328125 +47689 0.506591796875 +47690 0.32855224609375 +47691 0.351226806640625 +47692 0.13671875 +47693 0.146514892578125 +47694 -0.052215576171875 +47695 -0.05523681640625 +47696 -0.202484130859375 +47697 -0.21624755859375 +47698 -0.312713623046875 +47699 -0.334930419921875 +47700 -0.37518310546875 +47701 -0.402984619140625 +47702 -0.409820556640625 +47703 -0.4412841796875 +47704 -0.460479736328125 +47705 -0.49578857421875 +47706 -0.521209716796875 +47707 -0.5601806640625 +47708 -0.5599365234375 +47709 -0.600738525390625 +47710 -0.54498291015625 +47711 -0.584228515625 +47712 -0.446441650390625 +47713 -0.47930908203125 +47714 -0.2579345703125 +47715 -0.27935791015625 +47716 -0.002685546875 +47717 -0.0089111328125 +47718 0.259185791015625 +47719 0.268798828125 +47720 0.4603271484375 +47721 0.482818603515625 +47722 0.5728759765625 +47723 0.60369873046875 +47724 0.614990234375 +47725 0.650421142578125 +47726 0.6258544921875 +47727 0.66400146484375 +47728 0.60272216796875 +47729 0.6414794921875 +47730 0.535888671875 +47731 0.572540283203125 +47732 0.46435546875 +47733 0.498138427734375 +47734 0.4083251953125 +47735 0.439453125 +47736 0.34783935546875 +47737 0.375518798828125 +47738 0.2525634765625 +47739 0.274505615234375 +47740 0.09613037109375 +47741 0.1087646484375 +47742 -0.100311279296875 +47743 -0.099395751953125 +47744 -0.306640625 +47745 -0.3182373046875 +47746 -0.524139404296875 +47747 -0.5489501953125 +47748 -0.73602294921875 +47749 -0.7738037109375 +47750 -0.858612060546875 +47751 -0.86383056640625 +47752 -0.8660888671875 +47753 -0.870391845703125 +47754 -0.865875244140625 +47755 -0.86895751953125 +47756 -0.859344482421875 +47757 -0.861053466796875 +47758 -0.764617919921875 +47759 -0.765869140625 +47760 -0.54541015625 +47761 -0.5301513671875 +47762 -0.247955322265625 +47763 -0.214691162109375 +47764 0.086822509765625 +47765 0.137359619140625 +47766 0.41009521484375 +47767 0.474822998046875 +47768 0.688079833984375 +47769 0.76239013671875 +47770 0.858917236328125 +47771 0.867462158203125 +47772 0.870361328125 +47773 0.870361328125 +47774 0.870361328125 +47775 0.86480712890625 +47776 0.86273193359375 +47777 0.831817626953125 +47778 0.816436767578125 +47779 0.677581787109375 +47780 0.666229248046875 +47781 0.495880126953125 +47782 0.49859619140625 +47783 0.30767822265625 +47784 0.3162841796875 +47785 0.116180419921875 +47786 0.08905029296875 +47787 -0.110748291015625 +47788 -0.190460205078125 +47789 -0.381805419921875 +47790 -0.482940673828125 +47791 -0.6572265625 +47792 -0.733367919921875 +47793 -0.857421875 +47794 -0.859832763671875 +47795 -0.870391845703125 +47796 -0.869110107421875 +47797 -0.870391845703125 +47798 -0.870391845703125 +47799 -0.86444091796875 +47800 -0.869659423828125 +47801 -0.85723876953125 +47802 -0.86541748046875 +47803 -0.790008544921875 +47804 -0.834625244140625 +47805 -0.62847900390625 +47806 -0.632965087890625 +47807 -0.3956298828125 +47808 -0.38238525390625 +47809 -0.126708984375 +47810 -0.109832763671875 +47811 0.150115966796875 +47812 0.173492431640625 +47813 0.424041748046875 +47814 0.44268798828125 +47815 0.670623779296875 +47816 0.662322998046875 +47817 0.854522705078125 +47818 0.817657470703125 +47819 0.866485595703125 +47820 0.85906982421875 +47821 0.86920166015625 +47822 0.861541748046875 +47823 0.8653564453125 +47824 0.859588623046875 +47825 0.857147216796875 +47826 0.84326171875 +47827 0.766845703125 +47828 0.752777099609375 +47829 0.628509521484375 +47830 0.625946044921875 +47831 0.462127685546875 +47832 0.489471435546875 +47833 0.297210693359375 +47834 0.356658935546875 +47835 0.14862060546875 +47836 0.20672607421875 +47837 -0.00537109375 +47838 0.047088623046875 +47839 -0.15753173828125 +47840 -0.126068115234375 +47841 -0.31304931640625 +47842 -0.32708740234375 +47843 -0.48876953125 +47844 -0.51287841796875 +47845 -0.6416015625 +47846 -0.661834716796875 +47847 -0.751373291015625 +47848 -0.7982177734375 +47849 -0.84619140625 +47850 -0.860626220703125 +47851 -0.861297607421875 +47852 -0.8670654296875 +47853 -0.863250732421875 +47854 -0.86468505859375 +47855 -0.856597900390625 +47856 -0.85498046875 +47857 -0.7498779296875 +47858 -0.759735107421875 +47859 -0.624542236328125 +47860 -0.630950927734375 +47861 -0.47808837890625 +47862 -0.41778564453125 +47863 -0.253387451171875 +47864 -0.164093017578125 +47865 0.003692626953125 +47866 0.065093994140625 +47867 0.2257080078125 +47868 0.2823486328125 +47869 0.427154541015625 +47870 0.519561767578125 +47871 0.643218994140625 +47872 0.769500732421875 +47873 0.855926513671875 +47874 0.8680419921875 +47875 0.870361328125 +47876 0.870361328125 +47877 0.870361328125 +47878 0.8651123046875 +47879 0.862762451171875 +47880 0.83843994140625 +47881 0.79669189453125 +47882 0.655731201171875 +47883 0.595794677734375 +47884 0.436767578125 +47885 0.362152099609375 +47886 0.2117919921875 +47887 0.1270751953125 +47888 0.00262451171875 +47889 -0.086944580078125 +47890 -0.189300537109375 +47891 -0.2784423828125 +47892 -0.400421142578125 +47893 -0.484832763671875 +47894 -0.6533203125 +47895 -0.729583740234375 +47896 -0.85980224609375 +47897 -0.86688232421875 +47898 -0.870391845703125 +47899 -0.870391845703125 +47900 -0.870391845703125 +47901 -0.86859130859375 +47902 -0.866241455078125 +47903 -0.86279296875 +47904 -0.855377197265625 +47905 -0.817962646484375 +47906 -0.667388916015625 +47907 -0.6116943359375 +47908 -0.37738037109375 +47909 -0.3128662109375 +47910 -0.0308837890625 +47911 0.039398193359375 +47912 0.35009765625 +47913 0.422821044921875 +47914 0.73345947265625 +47915 0.805145263671875 +47916 0.870361328125 +47917 0.870361328125 +47918 0.870361328125 +47919 0.870361328125 +47920 0.860076904296875 +47921 0.860015869140625 +47922 0.729766845703125 +47923 0.727935791015625 +47924 0.48455810546875 +47925 0.48114013671875 +47926 0.210845947265625 +47927 0.2059326171875 +47928 -0.05511474609375 +47929 -0.06103515625 +47930 -0.292877197265625 +47931 -0.29913330078125 +47932 -0.50994873046875 +47933 -0.516204833984375 +47934 -0.7188720703125 +47935 -0.7252197265625 +47936 -0.859100341796875 +47937 -0.85980224609375 +47938 -0.870391845703125 +47939 -0.870391845703125 +47940 -0.870391845703125 +47941 -0.870391845703125 +47942 -0.858184814453125 +47943 -0.858062744140625 +47944 -0.675689697265625 +47945 -0.673004150390625 +47946 -0.43121337890625 +47947 -0.42694091796875 +47948 -0.2149658203125 +47949 -0.2100830078125 +47950 -0.040679931640625 +47951 -0.0362548828125 +47952 0.1060791015625 +47953 0.10943603515625 +47954 0.233184814453125 +47955 0.23516845703125 +47956 0.3726806640625 +47957 0.373687744140625 +47958 0.517303466796875 +47959 0.517791748046875 +47960 0.603271484375 +47961 0.602783203125 +47962 0.63739013671875 +47963 0.635711669921875 +47964 0.657562255859375 +47965 0.655181884765625 +47966 0.662078857421875 +47967 0.65948486328125 +47968 0.653533935546875 +47969 0.651275634765625 +47970 0.620086669921875 +47971 0.61846923828125 +47972 0.538665771484375 +47973 0.53753662109375 +47974 0.4051513671875 +47975 0.404144287109375 +47976 0.22320556640625 +47977 0.22186279296875 +47978 0.00604248046875 +47979 0.003997802734375 +47980 -0.21820068359375 +47981 -0.22100830078125 +47982 -0.421173095703125 +47983 -0.42449951171875 +47984 -0.57647705078125 +47985 -0.579833984375 +47986 -0.63958740234375 +47987 -0.641876220703125 +47988 -0.617462158203125 +47989 -0.6177978515625 +47990 -0.576873779296875 +47991 -0.575531005859375 +47992 -0.52886962890625 +47993 -0.526336669921875 +47994 -0.430389404296875 +47995 -0.42645263671875 +47996 -0.264007568359375 +47997 -0.2581787109375 +47998 -0.076202392578125 +47999 -0.068695068359375 +48000 0.083953857421875 +48001 0.09222412109375 +48002 0.2237548828125 +48003 0.232147216796875 +48004 0.34295654296875 +48005 0.3509521484375 +48006 0.403472900390625 +48007 0.410064697265625 +48008 0.369232177734375 +48009 0.372955322265625 +48010 0.2557373046875 +48011 0.2554931640625 +48012 0.11151123046875 +48013 0.10711669921875 +48014 -0.0445556640625 +48015 -0.052886962890625 +48016 -0.17486572265625 +48017 -0.186279296875 +48018 -0.22027587890625 +48019 -0.23291015625 +48020 -0.19720458984375 +48021 -0.209442138671875 +48022 -0.162994384765625 +48023 -0.174163818359375 +48024 -0.11724853515625 +48025 -0.126739501953125 +48026 -0.04119873046875 +48027 -0.048126220703125 +48028 0.046478271484375 +48029 0.0426025390625 +48030 0.1085205078125 +48031 0.10748291015625 +48032 0.13958740234375 +48033 0.1409912109375 +48034 0.19287109375 +48035 0.19708251953125 +48036 0.266448974609375 +48037 0.273651123046875 +48038 0.3082275390625 +48039 0.31768798828125 +48040 0.329986572265625 +48041 0.341094970703125 +48042 0.355560302734375 +48043 0.368011474609375 +48044 0.35943603515625 +48045 0.37249755859375 +48046 0.288665771484375 +48047 0.30072021484375 +48048 0.14227294921875 +48049 0.1517333984375 +48050 -0.02093505859375 +48051 -0.01470947265625 +48052 -0.190887451171875 +48053 -0.1883544921875 +48054 -0.37109375 +48055 -0.372711181640625 +48056 -0.50872802734375 +48057 -0.51397705078125 +48058 -0.564117431640625 +48059 -0.57177734375 +48060 -0.53082275390625 +48061 -0.53948974609375 +48062 -0.426666259765625 +48063 -0.43511962890625 +48064 -0.2886962890625 +48065 -0.2962646484375 +48066 -0.154541015625 +48067 -0.161102294921875 +48068 -0.0379638671875 +48069 -0.0435791015625 +48070 0.06494140625 +48071 0.060394287109375 +48072 0.1402587890625 +48073 0.13665771484375 +48074 0.17315673828125 +48075 0.170135498046875 +48076 0.16827392578125 +48077 0.16552734375 +48078 0.1595458984375 +48079 0.15728759765625 +48080 0.152313232421875 +48081 0.150787353515625 +48082 0.12298583984375 +48083 0.12200927734375 +48084 0.08062744140625 +48085 0.080108642578125 +48086 0.051055908203125 +48087 0.05126953125 +48088 0.06134033203125 +48089 0.062896728515625 +48090 0.089569091796875 +48091 0.09271240234375 +48092 0.088836669921875 +48093 0.092987060546875 +48094 0.07379150390625 +48095 0.07855224609375 +48096 0.059112548828125 +48097 0.06427001953125 +48098 0.029693603515625 +48099 0.0347900390625 +48100 -0.016265869140625 +48101 -0.01171875 +48102 -0.059814453125 +48103 -0.056060791015625 +48104 -0.058929443359375 +48105 -0.055511474609375 +48106 -0.014007568359375 +48107 -0.010467529296875 +48108 0.02178955078125 +48109 0.02508544921875 +48110 0.0233154296875 +48111 0.025665283203125 +48112 0.01617431640625 +48113 0.017333984375 +48114 0.002044677734375 +48115 0.00189208984375 +48116 -0.029998779296875 +48117 -0.03173828125 +48118 -0.068206787109375 +48119 -0.071502685546875 +48120 -0.130340576171875 +48121 -0.13543701171875 +48122 -0.212921142578125 +48123 -0.219970703125 +48124 -0.291778564453125 +48125 -0.300506591796875 +48126 -0.3662109375 +48127 -0.376312255859375 +48128 -0.40533447265625 +48129 -0.416107177734375 +48130 -0.360992431640625 +48131 -0.371124267578125 +48132 -0.23406982421875 +48133 -0.242279052734375 +48134 -0.0643310546875 +48135 -0.069732666015625 +48136 0.127716064453125 +48137 0.125640869140625 +48138 0.311248779296875 +48139 0.31268310546875 +48140 0.450225830078125 +48141 0.45501708984375 +48142 0.547027587890625 +48143 0.554779052734375 +48144 0.600555419921875 +48145 0.61065673828125 +48146 0.599212646484375 +48147 0.610931396484375 +48148 0.518951416015625 +48149 0.531463623046875 +48150 0.37579345703125 +48151 0.3883056640625 +48152 0.222930908203125 +48153 0.23468017578125 +48154 0.0849609375 +48155 0.095245361328125 +48156 -0.01220703125 +48157 -0.00396728515625 +48158 -0.05426025390625 +48159 -0.04852294921875 +48160 -0.05810546875 +48161 -0.055145263671875 +48162 -0.075897216796875 +48163 -0.0758056640625 +48164 -0.136016845703125 +48165 -0.138702392578125 +48166 -0.203948974609375 +48167 -0.209197998046875 +48168 -0.281585693359375 +48169 -0.289031982421875 +48170 -0.36968994140625 +48171 -0.37884521484375 +48172 -0.446014404296875 +48173 -0.456329345703125 +48174 -0.505523681640625 +48175 -0.51641845703125 +48176 -0.5084228515625 +48177 -0.519287109375 +48178 -0.448028564453125 +48179 -0.458251953125 +48180 -0.37579345703125 +48181 -0.384796142578125 +48182 -0.31634521484375 +48183 -0.323699951171875 +48184 -0.263946533203125 +48185 -0.269287109375 +48186 -0.192108154296875 +48187 -0.1951904296875 +48188 -0.099273681640625 +48189 -0.100006103515625 +48190 -0.012115478515625 +48191 -0.01055908203125 +48192 0.09967041015625 +48193 0.1033935546875 +48194 0.24346923828125 +48195 0.24908447265625 +48196 0.366058349609375 +48197 0.373199462890625 +48198 0.4498291015625 +48199 0.45806884765625 +48200 0.502593994140625 +48201 0.511474609375 +48202 0.556396484375 +48203 0.565399169921875 +48204 0.602783203125 +48205 0.61138916015625 +48206 0.58197021484375 +48207 0.5897216796875 +48208 0.484100341796875 +48209 0.4906005859375 +48210 0.326568603515625 +48211 0.33148193359375 +48212 0.144683837890625 +48213 0.147796630859375 +48214 -0.01995849609375 +48215 -0.01873779296875 +48216 -0.139617919921875 +48217 -0.140289306640625 +48218 -0.18951416015625 +48219 -0.191986083984375 +48220 -0.180206298828125 +48221 -0.184295654296875 +48222 -0.1563720703125 +48223 -0.161834716796875 +48224 -0.16009521484375 +48225 -0.166595458984375 +48226 -0.186737060546875 +48227 -0.19390869140625 +48228 -0.217010498046875 +48229 -0.22442626953125 +48230 -0.272491455078125 +48231 -0.279754638671875 +48232 -0.332244873046875 +48233 -0.3389892578125 +48234 -0.348541259765625 +48235 -0.3543701171875 +48236 -0.34356689453125 +48237 -0.348175048828125 +48238 -0.322784423828125 +48239 -0.32598876953125 +48240 -0.25653076171875 +48241 -0.2581787109375 +48242 -0.139739990234375 +48243 -0.139801025390625 +48244 0.013153076171875 +48245 0.014617919921875 +48246 0.141510009765625 +48247 0.144378662109375 +48248 0.21697998046875 +48249 0.221038818359375 +48250 0.26568603515625 +48251 0.27069091796875 +48252 0.28839111328125 +48253 0.294036865234375 +48254 0.305816650390625 +48255 0.311767578125 +48256 0.333251953125 +48257 0.339111328125 +48258 0.354766845703125 +48259 0.35992431640625 +48260 0.355712890625 +48261 0.35968017578125 +48262 0.30450439453125 +48263 0.3074951171875 +48264 0.17889404296875 +48265 0.181640625 +48266 0.003173828125 +48267 0.00616455078125 +48268 -0.1759033203125 +48269 -0.1727294921875 +48270 -0.3133544921875 +48271 -0.310638427734375 +48272 -0.365692138671875 +48273 -0.364593505859375 +48274 -0.359283447265625 +48275 -0.3603515625 +48276 -0.3394775390625 +48277 -0.342498779296875 +48278 -0.297210693359375 +48279 -0.302032470703125 +48280 -0.226409912109375 +48281 -0.232879638671875 +48282 -0.112579345703125 +48283 -0.120819091796875 +48284 0.01190185546875 +48285 0.00225830078125 +48286 0.092376708984375 +48287 0.082550048828125 +48288 0.143157958984375 +48289 0.13409423828125 +48290 0.177093505859375 +48291 0.169403076171875 +48292 0.190032958984375 +48293 0.184295654296875 +48294 0.17193603515625 +48295 0.16876220703125 +48296 0.118011474609375 +48297 0.117919921875 +48298 0.0555419921875 +48299 0.05853271484375 +48300 -0.01324462890625 +48301 -0.00732421875 +48302 -0.094818115234375 +48303 -0.08612060546875 +48304 -0.166351318359375 +48305 -0.15545654296875 +48306 -0.198974609375 +48307 -0.18701171875 +48308 -0.15386962890625 +48309 -0.142608642578125 +48310 -0.026153564453125 +48311 -0.01739501953125 +48312 0.119903564453125 +48313 0.12542724609375 +48314 0.207550048828125 +48315 0.210418701171875 +48316 0.237579345703125 +48317 0.238433837890625 +48318 0.240203857421875 +48319 0.2392578125 +48320 0.224639892578125 +48321 0.222076416015625 +48322 0.19427490234375 +48323 0.190338134765625 +48324 0.116363525390625 +48325 0.111907958984375 +48326 0.0145263671875 +48327 0.010101318359375 +48328 -0.051361083984375 +48329 -0.056060791015625 +48330 -0.10760498046875 +48331 -0.11236572265625 +48332 -0.196075439453125 +48333 -0.20001220703125 +48334 -0.290771484375 +48335 -0.293365478515625 +48336 -0.32861328125 +48337 -0.330352783203125 +48338 -0.27630615234375 +48339 -0.278289794921875 +48340 -0.182281494140625 +48341 -0.18487548828125 +48342 -0.12567138671875 +48343 -0.12799072265625 +48344 -0.113800048828125 +48345 -0.1148681640625 +48346 -0.11529541015625 +48347 -0.11474609375 +48348 -0.10552978515625 +48349 -0.103546142578125 +48350 -0.0543212890625 +48351 -0.051666259765625 +48352 0.047698974609375 +48353 0.050079345703125 +48354 0.15557861328125 +48355 0.157379150390625 +48356 0.209716796875 +48357 0.2115478515625 +48358 0.215789794921875 +48359 0.218109130859375 +48360 0.23431396484375 +48361 0.236602783203125 +48362 0.3023681640625 +48363 0.303497314453125 +48364 0.378387451171875 +48365 0.377899169921875 +48366 0.40179443359375 +48367 0.400238037109375 +48368 0.392120361328125 +48369 0.3897705078125 +48370 0.386749267578125 +48371 0.383331298828125 +48372 0.361419677734375 +48373 0.357147216796875 +48374 0.273040771484375 +48375 0.26885986328125 +48376 0.1171875 +48377 0.114227294921875 +48378 -0.054229736328125 +48379 -0.05560302734375 +48380 -0.189605712890625 +48381 -0.189788818359375 +48382 -0.283935546875 +48383 -0.283416748046875 +48384 -0.33709716796875 +48385 -0.3369140625 +48386 -0.375152587890625 +48387 -0.375579833984375 +48388 -0.443206787109375 +48389 -0.4423828125 +48390 -0.532623291015625 +48391 -0.528717041015625 +48392 -0.626800537109375 +48393 -0.618560791015625 +48394 -0.695648193359375 +48395 -0.68310546875 +48396 -0.702392578125 +48397 -0.68731689453125 +48398 -0.641448974609375 +48399 -0.6259765625 +48400 -0.49078369140625 +48401 -0.478363037109375 +48402 -0.26580810546875 +48403 -0.25933837890625 +48404 -0.024322509765625 +48405 -0.02423095703125 +48406 0.200653076171875 +48407 0.195220947265625 +48408 0.37432861328125 +48409 0.36553955078125 +48410 0.4832763671875 +48411 0.47369384765625 +48412 0.56683349609375 +48413 0.556884765625 +48414 0.632659912109375 +48415 0.6221923828125 +48416 0.63555908203125 +48417 0.62646484375 +48418 0.564117431640625 +48419 0.558746337890625 +48420 0.470367431640625 +48421 0.468597412109375 +48422 0.405548095703125 +48423 0.404876708984375 +48424 0.376800537109375 +48425 0.374542236328125 +48426 0.3763427734375 +48427 0.370361328125 +48428 0.371795654296875 +48429 0.361724853515625 +48430 0.313385009765625 +48431 0.301513671875 +48432 0.18505859375 +48433 0.1746826171875 +48434 0.012176513671875 +48435 0.00567626953125 +48436 -0.1697998046875 +48437 -0.171539306640625 +48438 -0.335968017578125 +48439 -0.333038330078125 +48440 -0.470428466796875 +48441 -0.46356201171875 +48442 -0.558807373046875 +48443 -0.54931640625 +48444 -0.57904052734375 +48445 -0.569244384765625 +48446 -0.546142578125 +48447 -0.53759765625 +48448 -0.50738525390625 +48449 -0.4993896484375 +48450 -0.458587646484375 +48451 -0.45074462890625 +48452 -0.393798828125 +48453 -0.38616943359375 +48454 -0.352386474609375 +48455 -0.343292236328125 +48456 -0.311859130859375 +48457 -0.3009033203125 +48458 -0.197906494140625 +48459 -0.188507080078125 +48460 -0.008758544921875 +48461 -0.004608154296875 +48462 0.2064208984375 +48463 0.203765869140625 +48464 0.407928466796875 +48465 0.398590087890625 +48466 0.5706787109375 +48467 0.55584716796875 +48468 0.664520263671875 +48469 0.646728515625 +48470 0.6573486328125 +48471 0.640625 +48472 0.566131591796875 +48473 0.5537109375 +48474 0.43023681640625 +48475 0.4234619140625 +48476 0.293487548828125 +48477 0.291656494140625 +48478 0.181793212890625 +48479 0.183074951171875 +48480 0.06329345703125 +48481 0.067535400390625 +48482 -0.076019287109375 +48483 -0.068115234375 +48484 -0.189178466796875 +48485 -0.179046630859375 +48486 -0.27142333984375 +48487 -0.260498046875 +48488 -0.341766357421875 +48489 -0.33038330078125 +48490 -0.36322021484375 +48491 -0.353363037109375 +48492 -0.326171875 +48493 -0.320159912109375 +48494 -0.275848388671875 +48495 -0.27374267578125 +48496 -0.2525634765625 +48497 -0.252410888671875 +48498 -0.242584228515625 +48499 -0.243072509765625 +48500 -0.197418212890625 +48501 -0.1995849609375 +48502 -0.115478515625 +48503 -0.120452880859375 +48504 -0.036285400390625 +48505 -0.04339599609375 +48506 0.035186767578125 +48507 0.0267333984375 +48508 0.091278076171875 +48509 0.08251953125 +48510 0.108642578125 +48511 0.101654052734375 +48512 0.125 +48513 0.119842529296875 +48514 0.156982421875 +48515 0.15277099609375 +48516 0.1773681640625 +48517 0.174407958984375 +48518 0.170013427734375 +48519 0.169281005859375 +48520 0.128814697265625 +48521 0.131500244140625 +48522 0.08123779296875 +48523 0.087127685546875 +48524 0.026519775390625 +48525 0.035430908203125 +48526 -0.06671142578125 +48527 -0.053497314453125 +48528 -0.1602783203125 +48529 -0.143280029296875 +48530 -0.21380615234375 +48531 -0.195404052734375 +48532 -0.235137939453125 +48533 -0.217315673828125 +48534 -0.200408935546875 +48535 -0.1861572265625 +48536 -0.119110107421875 +48537 -0.110870361328125 +48538 -0.0244140625 +48539 -0.02294921875 +48540 0.08636474609375 +48541 0.080352783203125 +48542 0.178924560546875 +48543 0.166473388671875 +48544 0.216522216796875 +48545 0.200592041015625 +48546 0.212493896484375 +48547 0.195404052734375 +48548 0.176300048828125 +48549 0.160003662109375 +48550 0.129791259765625 +48551 0.115234375 +48552 0.102874755859375 +48553 0.089599609375 +48554 0.075164794921875 +48555 0.063690185546875 +48556 0.0439453125 +48557 0.03485107421875 +48558 0.038665771484375 +48559 0.03106689453125 +48560 0.0765380859375 +48561 0.06866455078125 +48562 0.141082763671875 +48563 0.131866455078125 +48564 0.18621826171875 +48565 0.17669677734375 +48566 0.1883544921875 +48567 0.180572509765625 +48568 0.13836669921875 +48569 0.134674072265625 +48570 0.04095458984375 +48571 0.043426513671875 +48572 -0.080352783203125 +48573 -0.07086181640625 +48574 -0.2203369140625 +48575 -0.20330810546875 +48576 -0.3687744140625 +48577 -0.344146728515625 +48578 -0.49578857421875 +48579 -0.4649658203125 +48580 -0.557098388671875 +48581 -0.52362060546875 +48582 -0.50946044921875 +48583 -0.4788818359375 +48584 -0.376251220703125 +48585 -0.352996826171875 +48586 -0.219390869140625 +48587 -0.204864501953125 +48588 -0.064056396484375 +48589 -0.058349609375 +48590 0.0914306640625 +48591 0.08819580078125 +48592 0.236083984375 +48593 0.22442626953125 +48594 0.34320068359375 +48595 0.32501220703125 +48596 0.395538330078125 +48597 0.37359619140625 +48598 0.389801025390625 +48599 0.367095947265625 +48600 0.324737548828125 +48601 0.30438232421875 +48602 0.224609375 +48603 0.20855712890625 +48604 0.124786376953125 +48605 0.113311767578125 +48606 0.037567138671875 +48607 0.030364990234375 +48608 -0.009674072265625 +48609 -0.01422119140625 +48610 -0.01910400390625 +48611 -0.022552490234375 +48612 -0.022552490234375 +48613 -0.02496337890625 +48614 -0.00140380859375 +48615 -0.003814697265625 +48616 0.056365966796875 +48617 0.05230712890625 +48618 0.106658935546875 +48619 0.10137939453125 +48620 0.096710205078125 +48621 0.09307861328125 +48622 0.04241943359375 +48623 0.04248046875 +48624 -0.01837158203125 +48625 -0.01446533203125 +48626 -0.07623291015625 +48627 -0.068817138671875 +48628 -0.11981201171875 +48629 -0.109832763671875 +48630 -0.16009521484375 +48631 -0.14794921875 +48632 -0.20294189453125 +48633 -0.18878173828125 +48634 -0.2489013671875 +48635 -0.232818603515625 +48636 -0.305419921875 +48637 -0.287109375 +48638 -0.3623046875 +48639 -0.3419189453125 +48640 -0.39154052734375 +48641 -0.370697021484375 +48642 -0.3553466796875 +48643 -0.337493896484375 +48644 -0.249969482421875 +48645 -0.2386474609375 +48646 -0.092803955078125 +48647 -0.090850830078125 +48648 0.08917236328125 +48649 0.08050537109375 +48650 0.23541259765625 +48651 0.21917724609375 +48652 0.319061279296875 +48653 0.300048828125 +48654 0.358917236328125 +48655 0.340057373046875 +48656 0.348052978515625 +48657 0.33258056640625 +48658 0.285980224609375 +48659 0.27703857421875 +48660 0.2235107421875 +48661 0.220123291015625 +48662 0.197052001953125 +48663 0.195343017578125 +48664 0.18011474609375 +48665 0.178375244140625 +48666 0.155792236328125 +48667 0.15380859375 +48668 0.15142822265625 +48669 0.14697265625 +48670 0.157135009765625 +48671 0.14898681640625 +48672 0.13189697265625 +48673 0.122344970703125 +48674 0.100860595703125 +48675 0.09033203125 +48676 0.087127685546875 +48677 0.074432373046875 +48678 0.0548095703125 +48679 0.041839599609375 +48680 -0.00909423828125 +48681 -0.019256591796875 +48682 -0.1041259765625 +48683 -0.108306884765625 +48684 -0.22955322265625 +48685 -0.224578857421875 +48686 -0.355712890625 +48687 -0.34075927734375 +48688 -0.442108154296875 +48689 -0.41961669921875 +48690 -0.474029541015625 +48691 -0.447662353515625 +48692 -0.4649658203125 +48693 -0.437408447265625 +48694 -0.419219970703125 +48695 -0.392913818359375 +48696 -0.334381103515625 +48697 -0.3121337890625 +48698 -0.227935791015625 +48699 -0.211273193359375 +48700 -0.1234130859375 +48701 -0.112152099609375 +48702 -0.02752685546875 +48703 -0.021148681640625 +48704 0.077850341796875 +48705 0.078277587890625 +48706 0.2135009765625 +48707 0.205108642578125 +48708 0.38916015625 +48709 0.368194580078125 +48710 0.583160400390625 +48711 0.547515869140625 +48712 0.73443603515625 +48713 0.686920166015625 +48714 0.800537109375 +48715 0.747344970703125 +48716 0.7786865234375 +48717 0.72625732421875 +48718 0.665496826171875 +48719 0.62060546875 +48720 0.459930419921875 +48721 0.429595947265625 +48722 0.19940185546875 +48723 0.187713623046875 +48724 -0.050567626953125 +48725 -0.044586181640625 +48726 -0.232940673828125 +48727 -0.2147216796875 +48728 -0.3302001953125 +48729 -0.30645751953125 +48730 -0.3685302734375 +48731 -0.343780517578125 +48732 -0.379119873046875 +48733 -0.355224609375 +48734 -0.377227783203125 +48735 -0.354766845703125 +48736 -0.379974365234375 +48737 -0.358154296875 +48738 -0.391815185546875 +48739 -0.369384765625 +48740 -0.38568115234375 +48741 -0.36358642578125 +48742 -0.34228515625 +48743 -0.322998046875 +48744 -0.28326416015625 +48745 -0.267608642578125 +48746 -0.251983642578125 +48747 -0.23736572265625 +48748 -0.2664794921875 +48749 -0.248992919921875 +48750 -0.27362060546875 +48751 -0.25372314453125 +48752 -0.217010498046875 +48753 -0.199737548828125 +48754 -0.128387451171875 +48755 -0.1163330078125 +48756 -0.06817626953125 +48757 -0.059234619140625 +48758 -0.04302978515625 +48759 -0.034637451171875 +48760 -0.0242919921875 +48761 -0.0162353515625 +48762 0.020965576171875 +48763 0.02618408203125 +48764 0.12481689453125 +48765 0.122100830078125 +48766 0.258270263671875 +48767 0.244842529296875 +48768 0.379547119140625 +48769 0.355987548828125 +48770 0.480377197265625 +48771 0.44793701171875 +48772 0.528656005859375 +48773 0.491241455078125 +48774 0.5115966796875 +48775 0.474151611328125 +48776 0.456634521484375 +48777 0.422027587890625 +48778 0.4078369140625 +48779 0.37554931640625 +48780 0.384033203125 +48781 0.35211181640625 +48782 0.357025146484375 +48783 0.325836181640625 +48784 0.311859130859375 +48785 0.28302001953125 +48786 0.25079345703125 +48787 0.225799560546875 +48788 0.165191650390625 +48789 0.14630126953125 +48790 0.034912109375 +48791 0.026031494140625 +48792 -0.14251708984375 +48793 -0.137237548828125 +48794 -0.336181640625 +48795 -0.31512451171875 +48796 -0.53515625 +48797 -0.49755859375 +48798 -0.722503662109375 +48799 -0.668975830078125 +48800 -0.8372802734375 +48801 -0.7734375 +48802 -0.83319091796875 +48803 -0.768402099609375 +48804 -0.730072021484375 +48805 -0.672210693359375 +48806 -0.5828857421875 +48807 -0.535491943359375 +48808 -0.440277099609375 +48809 -0.403045654296875 +48810 -0.3243408203125 +48811 -0.2952880859375 +48812 -0.20135498046875 +48813 -0.1812744140625 +48814 -0.04437255859375 +48815 -0.036224365234375 +48816 0.1043701171875 +48817 0.100982666015625 +48818 0.202911376953125 +48819 0.191680908203125 +48820 0.265106201171875 +48821 0.2486572265625 +48822 0.339569091796875 +48823 0.316680908203125 +48824 0.444488525390625 +48825 0.412506103515625 +48826 0.545684814453125 +48827 0.504791259765625 +48828 0.617828369140625 +48829 0.570220947265625 +48830 0.652862548828125 +48831 0.6014404296875 +48832 0.66363525390625 +48833 0.6103515625 +48834 0.65618896484375 +48835 0.602569580078125 +48836 0.606658935546875 +48837 0.55615234375 +48838 0.500885009765625 +48839 0.4581298828125 +48840 0.352325439453125 +48841 0.32086181640625 +48842 0.17596435546875 +48843 0.158203125 +48844 -0.035491943359375 +48845 -0.036529541015625 +48846 -0.258941650390625 +48847 -0.2420654296875 +48848 -0.443206787109375 +48849 -0.41131591796875 +48850 -0.5760498046875 +48851 -0.5330810546875 +48852 -0.6527099609375 +48853 -0.602996826171875 +48854 -0.6422119140625 +48855 -0.59259033203125 +48856 -0.5626220703125 +48857 -0.518524169921875 +48858 -0.4583740234375 +48859 -0.4217529296875 +48860 -0.350738525390625 +48861 -0.3218994140625 +48862 -0.26055908203125 +48863 -0.2381591796875 +48864 -0.191986083984375 +48865 -0.174407958984375 +48866 -0.141693115234375 +48867 -0.12762451171875 +48868 -0.101837158203125 +48869 -0.090606689453125 +48870 -0.062469482421875 +48871 -0.054229736328125 +48872 -0.011444091796875 +48873 -0.007293701171875 +48874 0.0633544921875 +48875 0.06134033203125 +48876 0.149261474609375 +48877 0.1400146484375 +48878 0.242279052734375 +48879 0.225067138671875 +48880 0.349639892578125 +48881 0.323211669921875 +48882 0.457794189453125 +48883 0.4219970703125 +48884 0.5443115234375 +48885 0.5008544921875 +48886 0.573211669921875 +48887 0.5267333984375 +48888 0.506805419921875 +48889 0.464996337890625 +48890 0.351318359375 +48891 0.321380615234375 +48892 0.146484375 +48893 0.132476806640625 +48894 -0.055389404296875 +48895 -0.053558349609375 +48896 -0.21649169921875 +48897 -0.201629638671875 +48898 -0.335235595703125 +48899 -0.310455322265625 +48900 -0.403350830078125 +48901 -0.373291015625 +48902 -0.441680908203125 +48903 -0.408538818359375 +48904 -0.496185302734375 +48905 -0.457061767578125 +48906 -0.560546875 +48907 -0.5133056640625 +48908 -0.601043701171875 +48909 -0.547454833984375 +48910 -0.58447265625 +48911 -0.5301513671875 +48912 -0.479461669921875 +48913 -0.433746337890625 +48914 -0.2794189453125 +48915 -0.252593994140625 +48916 -0.008880615234375 +48917 -0.0086669921875 +48918 0.268890380859375 +48919 0.24163818359375 +48920 0.48297119140625 +48921 0.43511962890625 +48922 0.603912353515625 +48923 0.545440673828125 +48924 0.650665283203125 +48925 0.58929443359375 +48926 0.66424560546875 +48927 0.602996826171875 +48928 0.641693115234375 +48929 0.5838623046875 +48930 0.572723388671875 +48931 0.522705078125 +48932 0.498291015625 +48933 0.455902099609375 +48934 0.4395751953125 +48935 0.402313232421875 +48936 0.3756103515625 +48937 0.34344482421875 +48938 0.274566650390625 +48939 0.251129150390625 +48940 0.108795166015625 +48941 0.100982666015625 +48942 -0.099395751953125 +48943 -0.08697509765625 +48944 -0.318267822265625 +48945 -0.28436279296875 +48946 -0.54901123046875 +48947 -0.492095947265625 +48948 -0.773895263671875 +48949 -0.694305419921875 +48950 -0.86383056640625 +48951 -0.843841552734375 +48952 -0.870391845703125 +48953 -0.860687255859375 +48954 -0.86895751953125 +48955 -0.860748291015625 +48956 -0.86102294921875 +48957 -0.85479736328125 +48958 -0.765625 +48959 -0.732086181640625 +48960 -0.529876708984375 +48961 -0.52679443359375 +48962 -0.21441650390625 +48963 -0.247528076171875 +48964 0.137603759765625 +48965 0.067352294921875 +48966 0.475006103515625 +48967 0.372161865234375 +48968 0.76251220703125 +48969 0.63519287109375 +48970 0.867462158203125 +48971 0.83233642578125 +48972 0.870361328125 +48973 0.866424560546875 +48974 0.864776611328125 +48975 0.870361328125 +48976 0.831695556640625 +48977 0.866668701171875 +48978 0.677398681640625 +48979 0.85784912109375 +48980 0.49566650390625 +48981 0.762847900390625 +48982 0.30743408203125 +48983 0.615936279296875 +48984 0.115936279296875 +48985 0.44683837890625 +48986 -0.1109619140625 +48987 0.227508544921875 +48988 -0.381988525390625 +48989 -0.048248291015625 +48990 -0.6573486328125 +48991 -0.34271240234375 +48992 -0.857421875 +48993 -0.603179931640625 +48994 -0.870391845703125 +48995 -0.7921142578125 +48996 -0.870391845703125 +48997 -0.859893798828125 +48998 -0.86444091796875 +48999 -0.866363525390625 +49000 -0.85723876953125 +49001 -0.870391845703125 +49002 -0.790008544921875 +49003 -0.870391845703125 +49004 -0.62847900390625 +49005 -0.861358642578125 +49006 -0.3956298828125 +49007 -0.75006103515625 +49008 -0.126708984375 +49009 -0.527862548828125 +49010 0.150115966796875 +49011 -0.2755126953125 +49012 0.424041748046875 +49013 -0.003631591796875 +49014 0.670623779296875 +49015 0.26385498046875 +49016 0.854522705078125 +49017 0.492767333984375 +49018 0.866485595703125 +49019 0.667816162109375 +49020 0.86920166015625 +49021 0.775909423828125 +49022 0.8653564453125 +49023 0.83380126953125 +49024 0.857147216796875 +49025 0.854156494140625 +49026 0.766845703125 +49027 0.835235595703125 +49028 0.628509521484375 +49029 0.782379150390625 +49030 0.462127685546875 +49031 0.69036865234375 +49032 0.297210693359375 +49033 0.582794189453125 +49034 0.14862060546875 +49035 0.47119140625 +49036 -0.00537109375 +49037 0.335693359375 +49038 -0.15753173828125 +49039 0.183197021484375 +49040 -0.31304931640625 +49041 0.010589599609375 +49042 -0.48876953125 +49043 -0.194671630859375 +49044 -0.6416015625 +49045 -0.3912353515625 +49046 -0.751373291015625 +49047 -0.557525634765625 +49048 -0.84619140625 +49049 -0.71453857421875 +49050 -0.861297607421875 +49051 -0.849822998046875 +49052 -0.863250732421875 +49053 -0.863250732421875 +49054 -0.856597900390625 +49055 -0.863983154296875 +49056 -0.7498779296875 +49057 -0.85748291015625 +49058 -0.624542236328125 +49059 -0.80743408203125 +49060 -0.47808837890625 +49061 -0.699554443359375 +49062 -0.253387451171875 +49063 -0.50653076171875 +49064 0.003692626953125 +49065 -0.269195556640625 +49066 0.2257080078125 +49067 -0.048370361328125 +49068 0.427154541015625 +49069 0.16705322265625 +49070 0.643218994140625 +49071 0.405975341796875 +49072 0.855926513671875 +49073 0.660064697265625 +49074 0.870361328125 +49075 0.857086181640625 +49076 0.870361328125 +49077 0.870361328125 +49078 0.862762451171875 +49079 0.870361328125 +49080 0.79669189453125 +49081 0.862884521484375 +49082 0.595794677734375 +49083 0.789947509765625 +49084 0.362152099609375 +49085 0.60394287109375 +49086 0.1270751953125 +49087 0.400665283203125 +49088 -0.086944580078125 +49089 0.200225830078125 +49090 -0.2784423828125 +49091 0.004913330078125 +49092 -0.484832763671875 +49093 -0.21661376953125 +49094 -0.729583740234375 +49095 -0.482757568359375 +49096 -0.86688232421875 +49097 -0.750701904296875 +49098 -0.870391845703125 +49099 -0.86676025390625 +49100 -0.86859130859375 +49101 -0.870391845703125 +49102 -0.86279296875 +49103 -0.86956787109375 +49104 -0.817962646484375 +49105 -0.86187744140625 +49106 -0.6116943359375 +49107 -0.756622314453125 +49108 -0.3128662109375 +49109 -0.496978759765625 +49110 0.039398193359375 +49111 -0.177703857421875 +49112 0.422821044921875 +49113 0.1806640625 +49114 0.805145263671875 +49115 0.548126220703125 +49116 0.870361328125 +49117 0.855743408203125 +49118 0.870361328125 +49119 0.870361328125 +49120 0.860015869140625 +49121 0.870361328125 +49122 0.727935791015625 +49123 0.86090087890625 +49124 0.48114013671875 +49125 0.74871826171875 +49126 0.2059326171875 +49127 0.539642333984375 +49128 -0.06103515625 +49129 0.317413330078125 +49130 -0.29913330078125 +49131 0.100067138671875 +49132 -0.516204833984375 +49133 -0.118377685546875 +49134 -0.7252197265625 +49135 -0.34747314453125 +49136 -0.85980224609375 +49137 -0.563720703125 +49138 -0.870391845703125 +49139 -0.73797607421875 +49140 -0.870391845703125 +49141 -0.84796142578125 +49142 -0.858062744140625 +49143 -0.854736328125 +49144 -0.673004150390625 +49145 -0.768707275390625 +49146 -0.42694091796875 +49147 -0.640045166015625 +49148 -0.2100830078125 +49149 -0.520538330078125 +49150 -0.0362548828125 +49151 -0.418914794921875 +49152 0.10943603515625 +49153 -0.319366455078125 +49154 0.23516845703125 +49155 -0.213470458984375 +49156 0.373687744140625 +49157 -0.073699951171875 +49158 0.517791748046875 +49159 0.091888427734375 +49160 0.602783203125 +49161 0.224945068359375 +49162 0.635711669921875 +49163 0.32769775390625 +49164 0.655181884765625 +49165 0.42864990234375 +49166 0.65948486328125 +49167 0.52142333984375 +49168 0.651275634765625 +49169 0.603271484375 +49170 0.61846923828125 +49171 0.65899658203125 +49172 0.53753662109375 +49173 0.664031982421875 +49174 0.404144287109375 +49175 0.61090087890625 +49176 0.22186279296875 +49177 0.49969482421875 +49178 0.003997802734375 +49179 0.339874267578125 +49180 -0.22100830078125 +49181 0.15478515625 +49182 -0.42449951171875 +49183 -0.030853271484375 +49184 -0.579833984375 +49185 -0.19305419921875 +49186 -0.641876220703125 +49187 -0.29107666015625 +49188 -0.6177978515625 +49189 -0.328155517578125 +49190 -0.575531005859375 +49191 -0.35894775390625 +49192 -0.526336669921875 +49193 -0.389190673828125 +49194 -0.42645263671875 +49195 -0.3773193359375 +49196 -0.2581787109375 +49197 -0.304107666015625 +49198 -0.068695068359375 +49199 -0.2061767578125 +49200 0.09222412109375 +49201 -0.12274169921875 +49202 0.232147216796875 +49203 -0.044677734375 +49204 0.3509521484375 +49205 0.02978515625 +49206 0.410064697265625 +49207 0.06866455078125 +49208 0.372955322265625 +49209 0.040924072265625 +49210 0.2554931640625 +49211 -0.040496826171875 +49212 0.10711669921875 +49213 -0.134796142578125 +49214 -0.052886962890625 +49215 -0.227630615234375 +49216 -0.186279296875 +49217 -0.288970947265625 +49218 -0.23291015625 +49219 -0.2705078125 +49220 -0.209442138671875 +49221 -0.1898193359375 +49222 -0.174163818359375 +49223 -0.100189208984375 +49224 -0.126739501953125 +49225 -0.0045166015625 +49226 -0.048126220703125 +49227 0.110565185546875 +49228 0.0426025390625 +49229 0.22637939453125 +49230 0.10748291015625 +49231 0.308624267578125 +49232 0.1409912109375 +49233 0.351409912109375 +49234 0.19708251953125 +49235 0.400543212890625 +49236 0.273651123046875 +49237 0.454559326171875 +49238 0.31768798828125 +49239 0.46905517578125 +49240 0.341094970703125 +49241 0.455810546875 +49242 0.368011474609375 +49243 0.4376220703125 +49244 0.37249755859375 +49245 0.394744873046875 +49246 0.30072021484375 +49247 0.28375244140625 +49248 0.1517333984375 +49249 0.10662841796875 +49250 -0.01470947265625 +49251 -0.082763671875 +49252 -0.1883544921875 +49253 -0.27313232421875 +49254 -0.372711181640625 +49255 -0.465362548828125 +49256 -0.51397705078125 +49257 -0.61175537109375 +49258 -0.57177734375 +49259 -0.67657470703125 +49260 -0.53948974609375 +49261 -0.653656005859375 +49262 -0.43511962890625 +49263 -0.558441162109375 +49264 -0.2962646484375 +49265 -0.423736572265625 +49266 -0.161102294921875 +49267 -0.283355712890625 +49268 -0.0435791015625 +49269 -0.15081787109375 +49270 0.060394287109375 +49271 -0.024627685546875 +49272 0.13665771484375 +49273 0.0809326171875 +49274 0.170135498046875 +49275 0.150665283203125 +49276 0.16552734375 +49277 0.18634033203125 +49278 0.15728759765625 +49279 0.21533203125 +49280 0.150787353515625 +49281 0.24041748046875 +49282 0.12200927734375 +49283 0.239471435546875 +49284 0.080108642578125 +49285 0.21923828125 +49286 0.05126953125 +49287 0.201507568359375 +49288 0.062896728515625 +49289 0.20965576171875 +49290 0.09271240234375 +49291 0.22491455078125 +49292 0.092987060546875 +49293 0.207275390625 +49294 0.07855224609375 +49295 0.17059326171875 +49296 0.06427001953125 +49297 0.12908935546875 +49298 0.0347900390625 +49299 0.071380615234375 +49300 -0.01171875 +49301 -0.00225830078125 +49302 -0.056060791015625 +49303 -0.073486328125 +49304 -0.055511474609375 +49305 -0.10394287109375 +49306 -0.010467529296875 +49307 -0.092315673828125 +49308 0.02508544921875 +49309 -0.083465576171875 +49310 0.025665283203125 +49311 -0.098175048828125 +49312 0.017333984375 +49313 -0.113494873046875 +49314 0.00189208984375 +49315 -0.127655029296875 +49316 -0.03173828125 +49317 -0.1502685546875 +49318 -0.071502685546875 +49319 -0.171600341796875 +49320 -0.13543701171875 +49321 -0.207977294921875 +49322 -0.219970703125 +49323 -0.25750732421875 +49324 -0.300506591796875 +49325 -0.30047607421875 +49326 -0.376312255859375 +49327 -0.337799072265625 +49328 -0.416107177734375 +49329 -0.344207763671875 +49330 -0.371124267578125 +49331 -0.27947998046875 +49332 -0.242279052734375 +49333 -0.145782470703125 +49334 -0.069732666015625 +49335 0.021270751953125 +49336 0.125640869140625 +49337 0.202850341796875 +49338 0.31268310546875 +49339 0.371673583984375 +49340 0.45501708984375 +49341 0.496307373046875 +49342 0.554779052734375 +49343 0.57861328125 +49344 0.61065673828125 +49345 0.6177978515625 +49346 0.610931396484375 +49347 0.60443115234375 +49348 0.531463623046875 +49349 0.518768310546875 +49350 0.3883056640625 +49351 0.3756103515625 +49352 0.23468017578125 +49353 0.22174072265625 +49354 0.095245361328125 +49355 0.079559326171875 +49356 -0.00396728515625 +49357 -0.027435302734375 +49358 -0.04852294921875 +49359 -0.085693359375 +49360 -0.055145263671875 +49361 -0.108489990234375 +49362 -0.0758056640625 +49363 -0.139495849609375 +49364 -0.138702392578125 +49365 -0.20220947265625 +49366 -0.209197998046875 +49367 -0.2666015625 +49368 -0.289031982421875 +49369 -0.3341064453125 +49370 -0.37884521484375 +49371 -0.40545654296875 +49372 -0.456329345703125 +49373 -0.46197509765625 +49374 -0.51641845703125 +49375 -0.5 +49376 -0.519287109375 +49377 -0.48626708984375 +49378 -0.458251953125 +49379 -0.416015625 +49380 -0.384796142578125 +49381 -0.3343505859375 +49382 -0.323699951171875 +49383 -0.2635498046875 +49384 -0.269287109375 +49385 -0.19970703125 +49386 -0.1951904296875 +49387 -0.1212158203125 +49388 -0.100006103515625 +49389 -0.027587890625 +49390 -0.01055908203125 +49391 0.057586669921875 +49392 0.1033935546875 +49393 0.15985107421875 +49394 0.24908447265625 +49395 0.285247802734375 +49396 0.373199462890625 +49397 0.38824462890625 +49398 0.45806884765625 +49399 0.4539794921875 +49400 0.511474609375 +49401 0.489593505859375 +49402 0.565399169921875 +49403 0.52313232421875 +49404 0.61138916015625 +49405 0.548095703125 +49406 0.5897216796875 +49407 0.514190673828125 +49408 0.4906005859375 +49409 0.41400146484375 +49410 0.33148193359375 +49411 0.26348876953125 +49412 0.147796630859375 +49413 0.09356689453125 +49414 -0.01873779296875 +49415 -0.059600830078125 +49416 -0.140289306640625 +49417 -0.171783447265625 +49418 -0.191986083984375 +49419 -0.221435546875 +49420 -0.184295654296875 +49421 -0.21728515625 +49422 -0.161834716796875 +49423 -0.19720458984375 +49424 -0.166595458984375 +49425 -0.197021484375 +49426 -0.19390869140625 +49427 -0.213134765625 +49428 -0.22442626953125 +49429 -0.229522705078125 +49430 -0.279754638671875 +49431 -0.26513671875 +49432 -0.3389892578125 +49433 -0.30291748046875 +49434 -0.3543701171875 +49435 -0.302978515625 +49436 -0.348175048828125 +49437 -0.28497314453125 +49438 -0.32598876953125 +49439 -0.254364013671875 +49440 -0.2581787109375 +49441 -0.186553955078125 +49442 -0.139801025390625 +49443 -0.077850341796875 +49444 0.014617919921875 +49445 0.05902099609375 +49446 0.144378662109375 +49447 0.172210693359375 +49448 0.221038818359375 +49449 0.23748779296875 +49450 0.27069091796875 +49451 0.277130126953125 +49452 0.294036865234375 +49453 0.29193115234375 +49454 0.311767578125 +49455 0.299835205078125 +49456 0.339141845703125 +49457 0.314178466796875 +49458 0.360260009765625 +49459 0.321624755859375 +49460 0.360504150390625 +49461 0.310455322265625 +49462 0.308380126953125 +49463 0.2554931640625 +49464 0.18170166015625 +49465 0.13922119140625 +49466 0.0047607421875 +49467 -0.017578125 +49468 -0.17559814453125 +49469 -0.17572021484375 +49470 -0.3143310546875 +49471 -0.297607421875 +49472 -0.36785888671875 +49473 -0.346923828125 +49474 -0.36248779296875 +49475 -0.345123291015625 +49476 -0.343536376953125 +49477 -0.3294677734375 +49478 -0.3018798828125 +49479 -0.29254150390625 +49480 -0.231414794921875 +49481 -0.229522705078125 +49482 -0.117645263671875 +49483 -0.128814697265625 +49484 0.007049560546875 +49485 -0.017547607421875 +49486 0.087982177734375 +49487 0.0587158203125 +49488 0.13946533203125 +49489 0.111236572265625 +49490 0.17425537109375 +49491 0.149932861328125 +49492 0.188201904296875 +49493 0.17083740234375 +49494 0.171234130859375 +49495 0.165130615234375 +49496 0.118438720703125 +49497 0.128326416015625 +49498 0.05706787109375 +49499 0.08258056640625 +49500 -0.010711669921875 +49501 0.029449462890625 +49502 -0.0914306640625 +49503 -0.0364990234375 +49504 -0.162322998046875 +49505 -0.096466064453125 +49506 -0.194549560546875 +49507 -0.1265869140625 +49508 -0.1492919921875 +49509 -0.094635009765625 +49510 -0.02166748046875 +49511 0.003753662109375 +49512 0.124053955078125 +49513 0.1160888671875 +49514 0.211151123046875 +49515 0.179595947265625 +49516 0.240447998046875 +49517 0.195404052734375 +49518 0.242218017578125 +49519 0.18890380859375 +49520 0.2257080078125 +49521 0.168182373046875 +49522 0.194366455078125 +49523 0.13641357421875 +49524 0.115509033203125 +49525 0.06695556640625 +49526 0.0128173828125 +49527 -0.02044677734375 +49528 -0.053802490234375 +49529 -0.076324462890625 +49530 -0.110626220703125 +49531 -0.122344970703125 +49532 -0.199493408203125 +49533 -0.193115234375 +49534 -0.29437255859375 +49535 -0.267333984375 +49536 -0.33221435546875 +49537 -0.293304443359375 +49538 -0.27972412109375 +49539 -0.243927001953125 +49540 -0.185333251953125 +49541 -0.15948486328125 +49542 -0.128204345703125 +49543 -0.105560302734375 +49544 -0.115692138671875 +49545 -0.08856201171875 +49546 -0.116455078125 +49547 -0.08306884765625 +49548 -0.105926513671875 +49549 -0.069122314453125 +49550 -0.053955078125 +49551 -0.02215576171875 +49552 0.048797607421875 +49553 0.0653076171875 +49554 0.157318115234375 +49555 0.15606689453125 +49556 0.212005615234375 +49557 0.201019287109375 +49558 0.218475341796875 +49559 0.204803466796875 +49560 0.23724365234375 +49561 0.2174072265625 +49562 0.30535888671875 +49563 0.269561767578125 +49564 0.38128662109375 +49565 0.3272705078125 +49566 0.404449462890625 +49567 0.340911865234375 +49568 0.3944091796875 +49569 0.326904296875 +49570 0.3885498046875 +49571 0.31640625 +49572 0.362640380859375 +49573 0.289794921875 +49574 0.27362060546875 +49575 0.211822509765625 +49576 0.11712646484375 +49577 0.079132080078125 +49578 -0.054901123046875 +49579 -0.065277099609375 +49580 -0.19085693359375 +49581 -0.178741455078125 +49582 -0.28570556640625 +49583 -0.257110595703125 +49584 -0.339263916015625 +49585 -0.30029296875 +49586 -0.3775634765625 +49587 -0.32977294921875 +49588 -0.445709228515625 +49589 -0.38287353515625 +49590 -0.535064697265625 +49591 -0.452667236328125 +49592 -0.629058837890625 +49593 -0.5257568359375 +49594 -0.697601318359375 +49595 -0.577606201171875 +49596 -0.70391845703125 +49597 -0.578155517578125 +49598 -0.6424560546875 +49599 -0.523101806640625 +49600 -0.491241455078125 +49601 -0.394561767578125 +49602 -0.265716552734375 +49603 -0.2054443359375 +49604 -0.023712158203125 +49605 -0.003570556640625 +49606 0.201751708984375 +49607 0.1837158203125 +49608 0.375823974609375 +49609 0.327667236328125 +49610 0.485076904296875 +49611 0.417205810546875 +49612 0.56884765625 +49613 0.48480224609375 +49614 0.634765625 +49615 0.536865234375 +49616 0.63763427734375 +49617 0.53631591796875 +49618 0.5660400390625 +49619 0.473876953125 +49620 0.4720458984375 +49621 0.392669677734375 +49622 0.40692138671875 +49623 0.33514404296875 +49624 0.3778076171875 +49625 0.307403564453125 +49626 0.376953125 +49627 0.30328369140625 +49628 0.371978759765625 +49629 0.2962646484375 +49630 0.313140869140625 +49631 0.245513916015625 +49632 0.184417724609375 +49633 0.137939453125 +49634 0.011199951171875 +49635 -0.00543212890625 +49636 -0.171051025390625 +49637 -0.155426025390625 +49638 -0.33740234375 +49639 -0.291534423828125 +49640 -0.47198486328125 +49641 -0.4007568359375 +49642 -0.560394287109375 +49643 -0.4713134765625 +49644 -0.58056640625 +49645 -0.485198974609375 +49646 -0.54754638671875 +49647 -0.454986572265625 +49648 -0.508575439453125 +49649 -0.41973876953125 +49650 -0.459503173828125 +49651 -0.376220703125 +49652 -0.394378662109375 +49653 -0.3197021484375 +49654 -0.35260009765625 +49655 -0.282806396484375 +49656 -0.31170654296875 +49657 -0.24713134765625 +49658 -0.197418212890625 +49659 -0.15155029296875 +49660 -0.007965087890625 +49661 0.00531005859375 +49662 0.207489013671875 +49663 0.18292236328125 +49664 0.409210205078125 +49665 0.348480224609375 +49666 0.57208251953125 +49667 0.48077392578125 +49668 0.66595458984375 +49669 0.5555419921875 +49670 0.65875244140625 +49671 0.54779052734375 +49672 0.56744384765625 +49673 0.47149658203125 +49674 0.431396484375 +49675 0.358367919921875 +49676 0.29443359375 +49677 0.24365234375 +49678 0.182464599609375 +49679 0.148345947265625 +49680 0.06365966796875 +49681 0.0477294921875 +49682 -0.075958251953125 +49683 -0.068878173828125 +49684 -0.189422607421875 +49685 -0.163970947265625 +49686 -0.271942138671875 +49687 -0.233489990234375 +49688 -0.342529296875 +49689 -0.29229736328125 +49690 -0.364166259765625 +49691 -0.311004638671875 +49692 -0.327239990234375 +49693 -0.281951904296875 +49694 -0.2769775390625 +49695 -0.240997314453125 +49696 -0.253692626953125 +49697 -0.22021484375 +49698 -0.24365234375 +49699 -0.208892822265625 +49700 -0.1983642578125 +49701 -0.168853759765625 +49702 -0.116241455078125 +49703 -0.09912109375 +49704 -0.036834716796875 +49705 -0.031280517578125 +49706 0.034881591796875 +49707 0.030426025390625 +49708 0.09124755859375 +49709 0.079681396484375 +49710 0.10888671875 +49711 0.097747802734375 +49712 0.125518798828125 +49713 0.114227294921875 +49714 0.15771484375 +49715 0.142120361328125 +49716 0.17828369140625 +49717 0.159759521484375 +49718 0.17108154296875 +49719 0.154327392578125 +49720 0.129974365234375 +49721 0.12103271484375 +49722 0.082427978515625 +49723 0.0816650390625 +49724 0.027679443359375 +49725 0.0357666015625 +49726 -0.065643310546875 +49727 -0.041351318359375 +49728 -0.15936279296875 +49729 -0.1192626953125 +49730 -0.21307373046875 +49731 -0.165771484375 +49732 -0.234649658203125 +49733 -0.1868896484375 +49734 -0.2001953125 +49735 -0.1634521484375 +49736 -0.119171142578125 +49737 -0.10272216796875 +49738 -0.024749755859375 +49739 -0.03082275390625 +49740 0.085784912109375 +49741 0.054534912109375 +49742 0.178131103515625 +49743 0.12628173828125 +49744 0.215576171875 +49745 0.1553955078125 +49746 0.211456298828125 +49747 0.152435302734375 +49748 0.17523193359375 +49749 0.124847412109375 +49750 0.128753662109375 +49751 0.089874267578125 +49752 0.1019287109375 +49753 0.07110595703125 +49754 0.0743408203125 +49755 0.052215576171875 +49756 0.04327392578125 +49757 0.030853271484375 +49758 0.038177490234375 +49759 0.0301513671875 +49760 0.076263427734375 +49761 0.063568115234375 +49762 0.14105224609375 +49763 0.11785888671875 +49764 0.186431884765625 +49765 0.1563720703125 +49766 0.188812255859375 +49767 0.1602783203125 +49768 0.1390380859375 +49769 0.122222900390625 +49770 0.041778564453125 +49771 0.045867919921875 +49772 -0.079437255859375 +49773 -0.0501708984375 +49774 -0.219390869140625 +49775 -0.1617431640625 +49776 -0.367828369140625 +49777 -0.280670166015625 +49778 -0.494873046875 +49779 -0.3831787109375 +49780 -0.556243896484375 +49781 -0.43408203125 +49782 -0.508697509765625 +49783 -0.399017333984375 +49784 -0.3756103515625 +49785 -0.29632568359375 +49786 -0.218902587890625 +49787 -0.1749267578125 +49788 -0.063751220703125 +49789 -0.0545654296875 +49790 0.091552734375 +49791 0.066192626953125 +49792 0.23602294921875 +49793 0.17877197265625 +49794 0.342987060546875 +49795 0.26214599609375 +49796 0.39520263671875 +49797 0.302703857421875 +49798 0.389373779296875 +49799 0.297882080078125 +49800 0.324249267578125 +49801 0.246673583984375 +49802 0.224090576171875 +49803 0.168243408203125 +49804 0.124267578125 +49805 0.090545654296875 +49806 0.037078857421875 +49807 0.023223876953125 +49808 -0.010101318359375 +49809 -0.012115478515625 +49810 -0.019439697265625 +49811 -0.017333984375 +49812 -0.022796630859375 +49813 -0.017730712890625 +49814 -0.001556396484375 +49815 0.001251220703125 +49816 0.056304931640625 +49817 0.049041748046875 +49818 0.106719970703125 +49819 0.090606689453125 +49820 0.096893310546875 +49821 0.0841064453125 +49822 0.042694091796875 +49823 0.042022705078125 +49824 -0.018035888671875 +49825 -0.005706787109375 +49826 -0.07586669921875 +49827 -0.051605224609375 +49828 -0.11944580078125 +49829 -0.086669921875 +49830 -0.15972900390625 +49831 -0.11956787109375 +49832 -0.202606201171875 +49833 -0.154876708984375 +49834 -0.24859619140625 +49835 -0.192901611328125 +49836 -0.30517578125 +49837 -0.239471435546875 +49838 -0.36212158203125 +49839 -0.286376953125 +49840 -0.39141845703125 +49841 -0.311370849609375 +49842 -0.35528564453125 +49843 -0.284393310546875 +49844 -0.249969482421875 +49845 -0.202392578125 +49846 -0.092864990234375 +49847 -0.0791015625 +49848 0.08905029296875 +49849 0.064178466796875 +49850 0.2352294921875 +49851 0.179534912109375 +49852 0.318817138671875 +49853 0.2457275390625 +49854 0.358642578125 +49855 0.277618408203125 +49856 0.347747802734375 +49857 0.269683837890625 +49858 0.28564453125 +49859 0.221466064453125 +49860 0.223175048828125 +49861 0.173187255859375 +49862 0.196746826171875 +49863 0.15362548828125 +49864 0.179840087890625 +49865 0.141693115234375 +49866 0.155548095703125 +49867 0.123931884765625 +49868 0.151214599609375 +49869 0.121917724609375 +49870 0.156951904296875 +49871 0.12774658203125 +49872 0.13177490234375 +49873 0.10882568359375 +49874 0.100799560546875 +49875 0.08502197265625 +49876 0.087127685546875 +49877 0.0745849609375 +49878 0.05487060546875 +49879 0.049102783203125 +49880 -0.009002685546875 +49881 -0.001708984375 +49882 -0.10400390625 +49883 -0.077423095703125 +49884 -0.229400634765625 +49885 -0.177459716796875 +49886 -0.35552978515625 +49887 -0.278289794921875 +49888 -0.441925048828125 +49889 -0.347747802734375 +49890 -0.473846435546875 +49891 -0.374176025390625 +49892 -0.464813232421875 +49893 -0.3681640625 +49894 -0.419097900390625 +49895 -0.333038330078125 +49896 -0.334320068359375 +49897 -0.266876220703125 +49898 -0.227935791015625 +49899 -0.183441162109375 +49900 -0.12347412109375 +49901 -0.101348876953125 +49902 -0.02764892578125 +49903 -0.02587890625 +49904 0.077667236328125 +49905 0.057342529296875 +49906 0.2132568359375 +49907 0.164764404296875 +49908 0.38885498046875 +49909 0.3040771484375 +49910 0.582794189453125 +49911 0.4581298828125 +49912 0.734039306640625 +49913 0.578521728515625 +49914 0.800140380859375 +49915 0.631622314453125 +49916 0.7783203125 +49917 0.61517333984375 +49918 0.6651611328125 +49919 0.52642822265625 +49920 0.45965576171875 +49921 0.36505126953125 +49922 0.199188232421875 +49923 0.161163330078125 +49924 -0.050689697265625 +49925 -0.03436279296875 +49926 -0.23297119140625 +49927 -0.178070068359375 +49928 -0.33013916015625 +49929 -0.25653076171875 +49930 -0.368408203125 +49931 -0.289520263671875 +49932 -0.378936767578125 +49933 -0.3006591796875 +49934 -0.376983642578125 +49935 -0.30145263671875 +49936 -0.37969970703125 +49937 -0.304901123046875 +49938 -0.391510009765625 +49939 -0.314361572265625 +49940 -0.385345458984375 +49941 -0.30926513671875 +49942 -0.3419189453125 +49943 -0.274993896484375 +49944 -0.28289794921875 +49945 -0.2281494140625 +49946 -0.251617431640625 +49947 -0.2017822265625 +49948 -0.266143798828125 +49949 -0.209747314453125 +49950 -0.273345947265625 +49951 -0.21185302734375 +49952 -0.216796875 +49953 -0.1654052734375 +49954 -0.128265380859375 +49955 -0.094696044921875 +49956 -0.068145751953125 +49957 -0.045867919921875 +49958 -0.0430908203125 +49959 -0.024078369140625 +49960 -0.024444580078125 +49961 -0.007720947265625 +49962 0.020721435546875 +49963 0.02813720703125 +49964 0.124481201171875 +49965 0.1077880859375 +49966 0.25787353515625 +49967 0.209197998046875 +49968 0.379119873046875 +49969 0.3006591796875 +49970 0.47991943359375 +49971 0.37591552734375 +49972 0.5281982421875 +49973 0.41070556640625 +49974 0.511138916015625 +49975 0.3953857421875 +49976 0.456207275390625 +49977 0.350982666015625 +49978 0.407470703125 +49979 0.3111572265625 +49980 0.383758544921875 +49981 0.290374755859375 +49982 0.35687255859375 +49983 0.267333984375 +49984 0.31182861328125 +49985 0.23077392578125 +49986 0.250885009765625 +49987 0.1824951171875 +49988 0.1654052734375 +49989 0.116058349609375 +49990 0.035247802734375 +49991 0.0162353515625 +49992 -0.142059326171875 +49993 -0.11883544921875 +49994 -0.33563232421875 +49995 -0.265655517578125 +49996 -0.5345458984375 +49997 -0.415924072265625 +49998 -0.72186279296875 +49999 -0.556854248046875 +50000 -0.836669921875 +50001 -0.64227294921875 +50002 -0.8326416015625 +50003 -0.6370849609375 +50004 -0.7296142578125 +50005 -0.5565185546875 +50006 -0.582550048828125 +50007 -0.44244384765625 +50008 -0.440093994140625 +50009 -0.331939697265625 +50010 -0.324310302734375 +50011 -0.241912841796875 +50012 -0.20147705078125 +50013 -0.146820068359375 +50014 -0.044647216796875 +50015 -0.0262451171875 +50016 0.103973388671875 +50017 0.087646484375 +50018 0.202392578125 +50019 0.16290283203125 +50020 0.264495849609375 +50021 0.21002197265625 +50022 0.338897705078125 +50023 0.2659912109375 +50024 0.443817138671875 +50025 0.3447265625 +50026 0.545074462890625 +50027 0.4202880859375 +50028 0.6173095703125 +50029 0.4735107421875 +50030 0.6524658203125 +50031 0.49835205078125 +50032 0.66339111328125 +50033 0.50469970703125 +50034 0.6561279296875 +50035 0.49725341796875 +50036 0.606781005859375 +50037 0.457977294921875 +50038 0.501190185546875 +50039 0.376190185546875 +50040 0.352783203125 +50041 0.262115478515625 +50042 0.176544189453125 +50043 0.12725830078125 +50044 -0.034820556640625 +50045 -0.03387451171875 +50046 -0.258209228515625 +50047 -0.203704833984375 +50048 -0.44244384765625 +50049 -0.3433837890625 +50050 -0.5753173828125 +50051 -0.443603515625 +50052 -0.65203857421875 +50053 -0.50079345703125 +50054 -0.641632080078125 +50055 -0.49151611328125 +50056 -0.562164306640625 +50057 -0.429595947265625 +50058 -0.458038330078125 +50059 -0.348846435546875 +50060 -0.350555419921875 +50061 -0.265533447265625 +50062 -0.260528564453125 +50063 -0.195556640625 +50064 -0.192108154296875 +50065 -0.142181396484375 +50066 -0.141937255859375 +50067 -0.1029052734375 +50068 -0.1021728515625 +50069 -0.07183837890625 +50070 -0.062896728515625 +50071 -0.04150390625 +50072 -0.011932373046875 +50073 -0.00262451171875 +50074 0.062835693359375 +50075 0.053985595703125 +50076 0.148712158203125 +50077 0.11871337890625 +50078 0.241729736328125 +50079 0.188568115234375 +50080 0.34912109375 +50081 0.26910400390625 +50082 0.457305908203125 +50083 0.35009765625 +50084 0.54388427734375 +50085 0.414581298828125 +50086 0.5728759765625 +50087 0.435272216796875 +50088 0.506591796875 +50089 0.38360595703125 +50090 0.351226806640625 +50091 0.264373779296875 +50092 0.146514892578125 +50093 0.107818603515625 +50094 -0.05523681640625 +50095 -0.0462646484375 +50096 -0.21624755859375 +50097 -0.16912841796875 +50098 -0.334930419921875 +50099 -0.259521484375 +50100 -0.402984619140625 +50101 -0.3111572265625 +50102 -0.4412841796875 +50103 -0.33990478515625 +50104 -0.49578857421875 +50105 -0.380706787109375 +50106 -0.5601806640625 +50107 -0.4288330078125 +50108 -0.600738525390625 +50109 -0.45867919921875 +50110 -0.584228515625 +50111 -0.445037841796875 +50112 -0.47930908203125 +50113 -0.364166259765625 +50114 -0.27935791015625 +50115 -0.21112060546875 +50116 -0.0089111328125 +50117 -0.004608154296875 +50118 0.268798828125 +50119 0.207244873046875 +50120 0.482818603515625 +50121 0.37054443359375 +50122 0.60369873046875 +50123 0.462860107421875 +50124 0.650421142578125 +50125 0.498565673828125 +50126 0.66400146484375 +50127 0.508819580078125 +50128 0.6414794921875 +50129 0.49139404296875 +50130 0.572540283203125 +50131 0.4384765625 +50132 0.498138427734375 +50133 0.381256103515625 +50134 0.439453125 +50135 0.335845947265625 +50136 0.375518798828125 +50137 0.286376953125 +50138 0.274505615234375 +50139 0.20867919921875 +50140 0.1087646484375 +50141 0.081817626953125 +50142 -0.099395751953125 +50143 -0.07720947265625 +50144 -0.3182373046875 +50145 -0.244232177734375 +50146 -0.5489501953125 +50147 -0.42010498046875 +50148 -0.7738037109375 +50149 -0.591339111328125 +50150 -0.86383056640625 +50151 -0.717681884765625 +50152 -0.870391845703125 +50153 -0.77386474609375 +50154 -0.86895751953125 +50155 -0.773345947265625 +50156 -0.861053466796875 +50157 -0.726104736328125 +50158 -0.765869140625 +50159 -0.619049072265625 +50160 -0.5301513671875 +50161 -0.443634033203125 +50162 -0.214691162109375 +50163 -0.205291748046875 +50164 0.137359619140625 +50165 0.063201904296875 +50166 0.474822998046875 +50167 0.322784423828125 +50168 0.76239013671875 +50169 0.546417236328125 +50170 0.867462158203125 +50171 0.71356201171875 +50172 0.870361328125 +50173 0.824493408203125 +50174 0.86480712890625 +50175 0.856231689453125 +50176 0.831817626953125 +50177 0.85455322265625 +50178 0.677581787109375 +50179 0.797454833984375 +50180 0.495880126953125 +50181 0.701385498046875 +50182 0.30767822265625 +50183 0.5809326171875 +50184 0.116180419921875 +50185 0.438140869140625 +50186 -0.110748291015625 +50187 0.2503662109375 +50188 -0.381805419921875 +50189 0.0130615234375 +50190 -0.6572265625 +50191 -0.24212646484375 +50192 -0.857421875 +50193 -0.47113037109375 +50194 -0.870391845703125 +50195 -0.64227294921875 +50196 -0.870391845703125 +50197 -0.75006103515625 +50198 -0.86444091796875 +50199 -0.813812255859375 +50200 -0.85723876953125 +50201 -0.85504150390625 +50202 -0.790008544921875 +50203 -0.8565673828125 +50204 -0.62847900390625 +50205 -0.816131591796875 +50206 -0.3956298828125 +50207 -0.685791015625 +50208 -0.126708984375 +50209 -0.50634765625 +50210 0.150115966796875 +50211 -0.298095703125 +50212 0.424041748046875 +50213 -0.069915771484375 +50214 0.670623779296875 +50215 0.158172607421875 +50216 0.854522705078125 +50217 0.3575439453125 +50218 0.866485595703125 +50219 0.514923095703125 +50220 0.86920166015625 +50221 0.6187744140625 +50222 0.8653564453125 +50223 0.6820068359375 +50224 0.857147216796875 +50225 0.714111328125 +50226 0.766845703125 +50227 0.7127685546875 +50228 0.628509521484375 +50229 0.681671142578125 +50230 0.462127685546875 +50231 0.61590576171875 +50232 0.297210693359375 +50233 0.534393310546875 +50234 0.14862060546875 +50235 0.4462890625 +50236 -0.00537109375 +50237 0.335235595703125 +50238 -0.15753173828125 +50239 0.20697021484375 +50240 -0.31304931640625 +50241 0.0592041015625 +50242 -0.48876953125 +50243 -0.117919921875 +50244 -0.6416015625 +50245 -0.2899169921875 +50246 -0.751373291015625 +50247 -0.438446044921875 +50248 -0.84619140625 +50249 -0.580047607421875 +50250 -0.861297607421875 +50251 -0.703765869140625 +50252 -0.863250732421875 +50253 -0.7852783203125 +50254 -0.856597900390625 +50255 -0.801513671875 +50256 -0.7498779296875 +50257 -0.76129150390625 +50258 -0.624542236328125 +50259 -0.706787109375 +50260 -0.47808837890625 +50261 -0.62213134765625 +50262 -0.253387451171875 +50263 -0.46490478515625 +50264 0.003692626953125 +50265 -0.26861572265625 +50266 0.2257080078125 +50267 -0.083282470703125 +50268 0.427154541015625 +50269 0.099884033203125 +50270 0.643218994140625 +50271 0.30413818359375 +50272 0.855926513671875 +50273 0.52215576171875 +50274 0.870361328125 +50275 0.71148681640625 +50276 0.870361328125 +50277 0.83575439453125 +50278 0.862762451171875 +50279 0.85943603515625 +50280 0.79669189453125 +50281 0.859649658203125 +50282 0.595794677734375 +50283 0.83465576171875 +50284 0.362152099609375 +50285 0.71942138671875 +50286 0.1270751953125 +50287 0.57672119140625 +50288 -0.086944580078125 +50289 0.422149658203125 +50290 -0.2784423828125 +50291 0.257415771484375 +50292 -0.484832763671875 +50293 0.0574951171875 +50294 -0.729583740234375 +50295 -0.191314697265625 +50296 -0.86688232421875 +50297 -0.45184326171875 +50298 -0.870391845703125 +50299 -0.67767333984375 +50300 -0.86859130859375 +50301 -0.85565185546875 +50302 -0.86279296875 +50303 -0.870391845703125 +50304 -0.817962646484375 +50305 -0.870391845703125 +50306 -0.6116943359375 +50307 -0.860260009765625 +50308 -0.3128662109375 +50309 -0.7203369140625 +50310 0.039398193359375 +50311 -0.46673583984375 +50312 0.422821044921875 +50313 -0.163330078125 +50314 0.805145263671875 +50315 0.16424560546875 +50316 0.870361328125 +50317 0.4659423828125 +50318 0.870361328125 +50319 0.700714111328125 +50320 0.860015869140625 +50321 0.855224609375 +50322 0.727935791015625 +50323 0.8642578125 +50324 0.48114013671875 +50325 0.8646240234375 +50326 0.2059326171875 +50327 0.858642578125 +50328 -0.06103515625 +50329 0.79901123046875 +50330 -0.29913330078125 +50331 0.677520751953125 +50332 -0.516204833984375 +50333 0.521026611328125 +50334 -0.7252197265625 +50335 0.32147216796875 +50336 -0.85980224609375 +50337 0.099761962890625 +50338 -0.870391845703125 +50339 -0.11688232421875 +50340 -0.870391845703125 +50341 -0.305328369140625 +50342 -0.858062744140625 +50343 -0.42919921875 +50344 -0.673004150390625 +50345 -0.4852294921875 +50346 -0.42694091796875 +50347 -0.512176513671875 +50348 -0.2100830078125 +50349 -0.54351806640625 +50350 -0.0362548828125 +50351 -0.5794677734375 +50352 0.10943603515625 +50353 -0.60107421875 +50354 0.23516845703125 +50355 -0.596405029296875 +50356 0.373687744140625 +50357 -0.538055419921875 +50358 0.517791748046875 +50359 -0.430267333984375 +50360 0.602783203125 +50361 -0.321563720703125 +50362 0.635711669921875 +50363 -0.21063232421875 +50364 0.655181884765625 +50365 -0.07525634765625 +50366 0.65948486328125 +50367 0.07568359375 +50368 0.651275634765625 +50369 0.235321044921875 +50370 0.61846923828125 +50371 0.385284423828125 +50372 0.53753662109375 +50373 0.498748779296875 +50374 0.404144287109375 +50375 0.563232421875 +50376 0.22186279296875 +50377 0.57281494140625 +50378 0.003997802734375 +50379 0.529998779296875 +50380 -0.22100830078125 +50381 0.449920654296875 +50382 -0.42449951171875 +50383 0.349761962890625 +50384 -0.579833984375 +50385 0.247344970703125 +50386 -0.641876220703125 +50387 0.176055908203125 +50388 -0.6177978515625 +50389 0.13311767578125 +50390 -0.575531005859375 +50391 0.0733642578125 +50392 -0.526336669921875 +50393 -0.005584716796875 +50394 -0.42645263671875 +50395 -0.06494140625 +50396 -0.2581787109375 +50397 -0.084075927734375 +50398 -0.068695068359375 +50399 -0.08935546875 +50400 0.09222412109375 +50401 -0.109100341796875 +50402 0.232147216796875 +50403 -0.13055419921875 +50404 0.3509521484375 +50405 -0.147491455078125 +50406 0.410064697265625 +50407 -0.182891845703125 +50408 0.372955322265625 +50409 -0.25982666015625 +50410 0.2554931640625 +50411 -0.364837646484375 +50412 0.10711669921875 +50413 -0.461761474609375 +50414 -0.052886962890625 +50415 -0.53802490234375 +50416 -0.186279296875 +50417 -0.56878662109375 +50418 -0.23291015625 +50419 -0.514678955078125 +50420 -0.209442138671875 +50421 -0.39324951171875 +50422 -0.174163818359375 +50423 -0.25311279296875 +50424 -0.126739501953125 +50425 -0.10052490234375 +50426 -0.048126220703125 +50427 0.07177734375 +50428 0.0426025390625 +50429 0.2437744140625 +50430 0.10748291015625 +50431 0.38232421875 +50432 0.1409912109375 +50433 0.478363037109375 +50434 0.19708251953125 +50435 0.567047119140625 +50436 0.273651123046875 +50437 0.645599365234375 +50438 0.31768798828125 +50439 0.6761474609375 +50440 0.341094970703125 +50441 0.667694091796875 +50442 0.368011474609375 +50443 0.639129638671875 +50444 0.37249755859375 +50445 0.575469970703125 +50446 0.30072021484375 +50447 0.44317626953125 +50448 0.1517333984375 +50449 0.2464599609375 +50450 -0.01470947265625 +50451 0.032470703125 +50452 -0.1883544921875 +50453 -0.18609619140625 +50454 -0.372711181640625 +50455 -0.40643310546875 +50456 -0.51397705078125 +50457 -0.586090087890625 +50458 -0.57177734375 +50459 -0.692657470703125 +50460 -0.53948974609375 +50461 -0.71832275390625 +50462 -0.43511962890625 +50463 -0.673614501953125 +50464 -0.2962646484375 +50465 -0.583831787109375 +50466 -0.161102294921875 +50467 -0.475921630859375 +50468 -0.0435791015625 +50469 -0.360931396484375 +50470 0.060394287109375 +50471 -0.238372802734375 +50472 0.13665771484375 +50473 -0.121307373046875 +50474 0.170135498046875 +50475 -0.024169921875 +50476 0.16552734375 +50477 0.052032470703125 +50478 0.15728759765625 +50479 0.12689208984375 +50480 0.150787353515625 +50481 0.19976806640625 +50482 0.12200927734375 +50483 0.24969482421875 +50484 0.080108642578125 +50485 0.27947998046875 +50486 0.05126953125 +50487 0.304534912109375 +50488 0.062896728515625 +50489 0.34197998046875 +50490 0.09271240234375 +50491 0.37506103515625 +50492 0.092987060546875 +50493 0.37017822265625 +50494 0.07855224609375 +50495 0.3385009765625 +50496 0.06427001953125 +50497 0.292083740234375 +50498 0.0347900390625 +50499 0.22259521484375 +50500 -0.01171875 +50501 0.131744384765625 +50502 -0.056060791015625 +50503 0.03643798828125 +50504 -0.055511474609375 +50505 -0.029693603515625 +50506 -0.010467529296875 +50507 -0.063232421875 +50508 0.02508544921875 +50509 -0.09844970703125 +50510 0.025665283203125 +50511 -0.150054931640625 +50512 0.017333984375 +50513 -0.197235107421875 +50514 0.00189208984375 +50515 -0.23675537109375 +50516 -0.03173828125 +50517 -0.27520751953125 +50518 -0.071502685546875 +50519 -0.30377197265625 +50520 -0.13543701171875 +50521 -0.33538818359375 +50522 -0.219970703125 +50523 -0.368682861328125 +50524 -0.300506591796875 +50525 -0.38818359375 +50526 -0.376312255859375 +50527 -0.395721435546875 +50528 -0.416107177734375 +50529 -0.37213134765625 +50530 -0.371124267578125 +50531 -0.2862548828125 +50532 -0.242279052734375 +50533 -0.14178466796875 +50534 -0.069732666015625 +50535 0.030181884765625 +50536 0.125640869140625 +50537 0.212310791015625 +50538 0.31268310546875 +50539 0.380523681640625 +50540 0.45501708984375 +50541 0.507568359375 +50542 0.554779052734375 +50543 0.593719482421875 +50544 0.61065673828125 +50545 0.63751220703125 +50546 0.610931396484375 +50547 0.630828857421875 +50548 0.531463623046875 +50549 0.557464599609375 +50550 0.3883056640625 +50551 0.429931640625 +50552 0.23468017578125 +50553 0.2872314453125 +50554 0.095245361328125 +50555 0.148773193359375 +50556 -0.00396728515625 +50557 0.03515625 +50558 -0.04852294921875 +50559 -0.041015625 +50560 -0.055145263671875 +50561 -0.08892822265625 +50562 -0.0758056640625 +50563 -0.1427001953125 +50564 -0.138702392578125 +50565 -0.22003173828125 +50566 -0.209197998046875 +50567 -0.295013427734375 +50568 -0.289031982421875 +50569 -0.367706298828125 +50570 -0.37884521484375 +50571 -0.4378662109375 +50572 -0.456329345703125 +50573 -0.48974609375 +50574 -0.51641845703125 +50575 -0.520233154296875 +50576 -0.519287109375 +50577 -0.5023193359375 +50578 -0.458251953125 +50579 -0.432647705078125 +50580 -0.384796142578125 +50581 -0.348968505859375 +50582 -0.323699951171875 +50583 -0.2705078125 +50584 -0.269287109375 +50585 -0.195343017578125 +50586 -0.1951904296875 +50587 -0.107086181640625 +50588 -0.100006103515625 +50589 -0.0067138671875 +50590 -0.01055908203125 +50591 0.085205078125 +50592 0.1033935546875 +50593 0.188385009765625 +50594 0.24908447265625 +50595 0.306793212890625 +50596 0.373199462890625 +50597 0.40240478515625 +50598 0.45806884765625 +50599 0.46258544921875 +50600 0.511474609375 +50601 0.49298095703125 +50602 0.565399169921875 +50603 0.516571044921875 +50604 0.61138916015625 +50605 0.528411865234375 +50606 0.5897216796875 +50607 0.488006591796875 +50608 0.4906005859375 +50609 0.389984130859375 +50610 0.33148193359375 +50611 0.248291015625 +50612 0.147796630859375 +50613 0.08935546875 +50614 -0.01873779296875 +50615 -0.055938720703125 +50616 -0.140289306640625 +50617 -0.16656494140625 +50618 -0.191986083984375 +50619 -0.22381591796875 +50620 -0.184295654296875 +50621 -0.2340087890625 +50622 -0.161834716796875 +50623 -0.227691650390625 +50624 -0.166595458984375 +50625 -0.233917236328125 +50626 -0.19390869140625 +50627 -0.249420166015625 +50628 -0.22442626953125 +50629 -0.26104736328125 +50630 -0.279754638671875 +50631 -0.28466796875 +50632 -0.3389892578125 +50633 -0.306610107421875 +50634 -0.3543701171875 +50635 -0.294647216796875 +50636 -0.348175048828125 +50637 -0.26568603515625 +50638 -0.32598876953125 +50639 -0.22503662109375 +50640 -0.2581787109375 +50641 -0.153350830078125 +50642 -0.139801025390625 +50643 -0.048431396484375 +50644 0.014617919921875 +50645 0.07843017578125 +50646 0.144378662109375 +50647 0.183746337890625 +50648 0.221038818359375 +50649 0.246978759765625 +50650 0.27069091796875 +50651 0.2860107421875 +50652 0.294036865234375 +50653 0.301239013671875 +50654 0.311767578125 +50655 0.307373046875 +50656 0.339141845703125 +50657 0.3155517578125 +50658 0.360260009765625 +50659 0.315338134765625 +50660 0.360504150390625 +50661 0.297454833984375 +50662 0.308380126953125 +50663 0.241058349609375 +50664 0.18170166015625 +50665 0.131866455078125 +50666 0.0047607421875 +50667 -0.011962890625 +50668 -0.17559814453125 +50669 -0.15673828125 +50670 -0.3143310546875 +50671 -0.270111083984375 +50672 -0.36785888671875 +50673 -0.320892333984375 +50674 -0.36248779296875 +50675 -0.32672119140625 +50676 -0.343536376953125 +50677 -0.318756103515625 +50678 -0.3018798828125 +50679 -0.290496826171875 +50680 -0.231414794921875 +50681 -0.237762451171875 +50682 -0.117645263671875 +50683 -0.150787353515625 +50684 0.007049560546875 +50685 -0.05267333984375 +50686 0.087982177734375 +50687 0.017822265625 +50688 0.13946533203125 +50689 0.069793701171875 +50690 0.17425537109375 +50691 0.1112060546875 +50692 0.188201904296875 +50693 0.13812255859375 +50694 0.171234130859375 +50695 0.143035888671875 +50696 0.118438720703125 +50697 0.121978759765625 +50698 0.05706787109375 +50699 0.092437744140625 +50700 -0.010711669921875 +50701 0.055328369140625 +50702 -0.0914306640625 +50703 0.006011962890625 +50704 -0.162322998046875 +50705 -0.04046630859375 +50706 -0.194549560546875 +50707 -0.06488037109375 +50708 -0.1492919921875 +50709 -0.04119873046875 +50710 -0.02166748046875 +50711 0.03424072265625 +50712 0.124053955078125 +50713 0.119384765625 +50714 0.211151123046875 +50715 0.1639404296875 +50716 0.240447998046875 +50717 0.16925048828125 +50718 0.242218017578125 +50719 0.15618896484375 +50720 0.2257080078125 +50721 0.131683349609375 +50722 0.194366455078125 +50723 0.098724365234375 +50724 0.115509033203125 +50725 0.03619384765625 +50726 0.0128173828125 +50727 -0.03961181640625 +50728 -0.053802490234375 +50729 -0.088623046875 +50730 -0.110626220703125 +50731 -0.128082275390625 +50732 -0.199493408203125 +50733 -0.185791015625 +50734 -0.29437255859375 +50735 -0.24462890625 +50736 -0.33221435546875 +50737 -0.263031005859375 +50738 -0.27972412109375 +50739 -0.219329833984375 +50740 -0.185333251953125 +50741 -0.146240234375 +50742 -0.128204345703125 +50743 -0.096923828125 +50744 -0.115692138671875 +50745 -0.076904296875 +50746 -0.116455078125 +50747 -0.066009521484375 +50748 -0.105926513671875 +50749 -0.04852294921875 +50750 -0.053955078125 +50751 -0.0050048828125 +50752 0.048797607421875 +50753 0.070281982421875 +50754 0.157318115234375 +50755 0.14715576171875 +50756 0.212005615234375 +50757 0.185791015625 +50758 0.218475341796875 +50759 0.18988037109375 +50760 0.23724365234375 +50761 0.19970703125 +50762 0.30535888671875 +50763 0.2401123046875 +50764 0.38128662109375 +50765 0.2838134765625 +50766 0.404449462890625 +50767 0.290985107421875 +50768 0.3944091796875 +50769 0.275115966796875 +50770 0.3885498046875 +50771 0.261566162109375 +50772 0.362640380859375 +50773 0.23480224609375 +50774 0.27362060546875 +50775 0.166717529296875 +50776 0.11712646484375 +50777 0.054901123046875 +50778 -0.054901123046875 +50779 -0.06573486328125 +50780 -0.19085693359375 +50781 -0.160614013671875 +50782 -0.28570556640625 +50783 -0.2261962890625 +50784 -0.339263916015625 +50785 -0.262298583984375 +50786 -0.3775634765625 +50787 -0.286224365234375 +50788 -0.445709228515625 +50789 -0.32806396484375 +50790 -0.535064697265625 +50791 -0.38232421875 +50792 -0.629058837890625 +50793 -0.438323974609375 +50794 -0.697601318359375 +50795 -0.476470947265625 +50796 -0.70391845703125 +50797 -0.4727783203125 +50798 -0.6424560546875 +50799 -0.423980712890625 +50800 -0.491241455078125 +50801 -0.315948486328125 +50802 -0.265716552734375 +50803 -0.159332275390625 +50804 -0.023712158203125 +50805 0.007080078125 +50806 0.201751708984375 +50807 0.16107177734375 +50808 0.375823974609375 +50809 0.27935791015625 +50810 0.485076904296875 +50811 0.352874755859375 +50812 0.56884765625 +50813 0.40777587890625 +50814 0.634765625 +50815 0.449188232421875 +50816 0.63763427734375 +50817 0.447296142578125 +50818 0.5660400390625 +50819 0.394775390625 +50820 0.4720458984375 +50821 0.326507568359375 +50822 0.40692138671875 +50823 0.27685546875 +50824 0.3778076171875 +50825 0.25091552734375 +50826 0.376953125 +50827 0.243896484375 +50828 0.371978759765625 +50829 0.23468017578125 +50830 0.313140869140625 +50831 0.1905517578125 +50832 0.184417724609375 +50833 0.101104736328125 +50834 0.011199951171875 +50835 -0.016571044921875 +50836 -0.171051025390625 +50837 -0.138824462890625 +50838 -0.33740234375 +50839 -0.249114990234375 +50840 -0.47198486328125 +50841 -0.336944580078125 +50842 -0.560394287109375 +50843 -0.39288330078125 +50844 -0.58056640625 +50845 -0.4024658203125 +50846 -0.54754638671875 +50847 -0.375885009765625 +50848 -0.508575439453125 +50849 -0.344818115234375 +50850 -0.459503173828125 +50851 -0.306793212890625 +50852 -0.394378662109375 +50853 -0.2581787109375 +50854 -0.35260009765625 +50855 -0.22540283203125 +50856 -0.31170654296875 +50857 -0.19378662109375 +50858 -0.197418212890625 +50859 -0.114288330078125 +50860 -0.007965087890625 +50861 0.01409912109375 +50862 0.207489013671875 +50863 0.158599853515625 +50864 0.409210205078125 +50865 0.292755126953125 +50866 0.57208251953125 +50867 0.399932861328125 +50868 0.66595458984375 +50869 0.460205078125 +50870 0.65875244140625 +50871 0.45245361328125 +50872 0.56744384765625 +50873 0.388092041015625 +50874 0.431396484375 +50875 0.29351806640625 +50876 0.29443359375 +50877 0.198089599609375 +50878 0.182464599609375 +50879 0.1192626953125 +50880 0.06365966796875 +50881 0.0361328125 +50882 -0.075958251953125 +50883 -0.060333251953125 +50884 -0.189422607421875 +50885 -0.1387939453125 +50886 -0.271942138671875 +50887 -0.195892333984375 +50888 -0.342529296875 +50889 -0.244140625 +50890 -0.364166259765625 +50891 -0.258941650390625 +50892 -0.327239990234375 +50893 -0.233917236328125 +50894 -0.2769775390625 +50895 -0.19915771484375 +50896 -0.253692626953125 +50897 -0.1815185546875 +50898 -0.24365234375 +50899 -0.1719970703125 +50900 -0.1983642578125 +50901 -0.13861083984375 +50902 -0.116241455078125 +50903 -0.080474853515625 +50904 -0.036834716796875 +50905 -0.0240478515625 +50906 0.034881591796875 +50907 0.027130126953125 +50908 0.09124755859375 +50909 0.067779541015625 +50910 0.10888671875 +50911 0.082244873046875 +50912 0.125518798828125 +50913 0.095428466796875 +50914 0.15771484375 +50915 0.118255615234375 +50916 0.17828369140625 +50917 0.132568359375 +50918 0.17108154296875 +50919 0.127655029296875 +50920 0.129974365234375 +50921 0.099456787109375 +50922 0.082427978515625 +50923 0.0662841796875 +50924 0.027679443359375 +50925 0.027740478515625 +50926 -0.065643310546875 +50927 -0.036834716796875 +50928 -0.15936279296875 +50929 -0.1019287109375 +50930 -0.21307373046875 +50931 -0.140594482421875 +50932 -0.234649658203125 +50933 -0.157867431640625 +50934 -0.2001953125 +50935 -0.1376953125 +50936 -0.119171142578125 +50937 -0.086273193359375 +50938 -0.024749755859375 +50939 -0.025482177734375 +50940 0.085784912109375 +50941 0.046539306640625 +50942 0.178131103515625 +50943 0.107086181640625 +50944 0.215576171875 +50945 0.13201904296875 +50946 0.211456298828125 +50947 0.13031005859375 +50948 0.17523193359375 +50949 0.108306884765625 +50950 0.128753662109375 +50951 0.079833984375 +50952 0.1019287109375 +50953 0.063812255859375 +50954 0.0743408203125 +50955 0.047332763671875 +50956 0.04327392578125 +50957 0.02862548828125 +50958 0.038177490234375 +50959 0.0262451171875 +50960 0.076263427734375 +50961 0.051025390625 +50962 0.14105224609375 +50963 0.092498779296875 +50964 0.186431884765625 +50965 0.121551513671875 +50966 0.188812255859375 +50967 0.12322998046875 +50968 0.1390380859375 +50969 0.09173583984375 +50970 0.041778564453125 +50971 0.030029296875 +50972 -0.079437255859375 +50973 -0.046966552734375 +50974 -0.219390869140625 +50975 -0.135986328125 +50976 -0.367828369140625 +50977 -0.23046875 +50978 -0.494873046875 +50979 -0.3115234375 +50980 -0.556243896484375 +50981 -0.351104736328125 +50982 -0.508697509765625 +50983 -0.32183837890625 +50984 -0.3756103515625 +50985 -0.238433837890625 +50986 -0.218902587890625 +50987 -0.1400146484375 +50988 -0.063751220703125 +50989 -0.042449951171875 +50990 0.091552734375 +50991 0.0552978515625 +50992 0.23602294921875 +50993 0.146331787109375 +50994 0.342987060546875 +50995 0.21380615234375 +50996 0.39520263671875 +50997 0.246856689453125 +50998 0.389373779296875 +50999 0.243377685546875 +51000 0.324249267578125 +51001 0.20257568359375 +51002 0.224090576171875 +51003 0.139739990234375 +51004 0.124267578125 +51005 0.07720947265625 +51006 0.037078857421875 +51007 0.022705078125 +51008 -0.010101318359375 +51009 -0.0064697265625 +51010 -0.019439697265625 +51011 -0.01171875 +51012 -0.022796630859375 +51013 -0.01324462890625 +51014 -0.001556396484375 +51015 0.00067138671875 +51016 0.056304931640625 +51017 0.037628173828125 +51018 0.106719970703125 +51019 0.06976318359375 +51020 0.096893310546875 +51021 0.063690185546875 +51022 0.042694091796875 +51023 0.0294189453125 +51024 -0.018035888671875 +51025 -0.009124755859375 +51026 -0.07586669921875 +51027 -0.04595947265625 +51028 -0.11944580078125 +51029 -0.0738525390625 +51030 -0.15972900390625 +51031 -0.0997314453125 +51032 -0.202606201171875 +51033 -0.127288818359375 +51034 -0.24859619140625 +51035 -0.156829833984375 +51036 -0.30517578125 +51037 -0.193023681640625 +51038 -0.36212158203125 +51039 -0.229400634765625 +51040 -0.39141845703125 +51041 -0.248291015625 +51042 -0.35528564453125 +51043 -0.225738525390625 +51044 -0.249969482421875 +51045 -0.15936279296875 +51046 -0.092864990234375 +51047 -0.0601806640625 +51048 0.08905029296875 +51049 0.054779052734375 +51050 0.2352294921875 +51051 0.147216796875 +51052 0.318817138671875 +51053 0.200164794921875 +51054 0.358642578125 +51055 0.22552490234375 +51056 0.347747802734375 +51057 0.2188720703125 +51058 0.28564453125 +51059 0.179901123046875 +51060 0.223175048828125 +51061 0.1407470703125 +51062 0.196746826171875 +51063 0.124359130859375 +51064 0.179840087890625 +51065 0.113983154296875 +51066 0.155548095703125 +51067 0.098907470703125 +51068 0.151214599609375 +51069 0.096405029296875 +51070 0.156951904296875 +51071 0.100250244140625 +51072 0.13177490234375 +51073 0.084503173828125 +51074 0.100799560546875 +51075 0.065032958984375 +51076 0.087127685546875 +51077 0.056396484375 +51078 0.05487060546875 +51079 0.03594970703125 +51080 -0.009002685546875 +51081 -0.004547119140625 +51082 -0.10400390625 +51083 -0.06475830078125 +51084 -0.229400634765625 +51085 -0.14422607421875 +51086 -0.35552978515625 +51087 -0.22418212890625 +51088 -0.441925048828125 +51089 -0.279022216796875 +51090 -0.473846435546875 +51091 -0.299407958984375 +51092 -0.464813232421875 +51093 -0.29388427734375 +51094 -0.419097900390625 +51095 -0.26513671875 +51096 -0.334320068359375 +51097 -0.211669921875 +51098 -0.227935791015625 +51099 -0.144500732421875 +51100 -0.12347412109375 +51101 -0.0784912109375 +51102 -0.02764892578125 +51103 -0.01788330078125 +51104 0.077667236328125 +51105 0.04876708984375 +51106 0.2132568359375 +51107 0.134552001953125 +51108 0.38885498046875 +51109 0.245635986328125 +51110 0.582794189453125 +51111 0.3682861328125 +51112 0.734039306640625 +51113 0.463958740234375 +51114 0.800140380859375 +51115 0.505828857421875 +51116 0.7783203125 +51117 0.492095947265625 +51118 0.6651611328125 +51119 0.420623779296875 +51120 0.45965576171875 +51121 0.290771484375 +51122 0.199188232421875 +51123 0.12615966796875 +51124 -0.050689697265625 +51125 -0.031768798828125 +51126 -0.23297119140625 +51127 -0.147003173828125 +51128 -0.33013916015625 +51129 -0.208465576171875 +51130 -0.368408203125 +51131 -0.232666015625 +51132 -0.378936767578125 +51133 -0.23931884765625 +51134 -0.376983642578125 +51135 -0.23809814453125 +51136 -0.37969970703125 +51137 -0.239837646484375 +51138 -0.391510009765625 +51139 -0.247314453125 +51140 -0.385345458984375 +51141 -0.243408203125 +51142 -0.3419189453125 +51143 -0.2159423828125 +51144 -0.28289794921875 +51145 -0.178619384765625 +51146 -0.251617431640625 +51147 -0.158843994140625 +51148 -0.266143798828125 +51149 -0.167999267578125 +51150 -0.273345947265625 +51151 -0.17254638671875 +51152 -0.216796875 +51153 -0.136810302734375 +51154 -0.128265380859375 +51155 -0.080841064453125 +51156 -0.068145751953125 +51157 -0.0428466796875 +51158 -0.0430908203125 +51159 -0.027008056640625 +51160 -0.024444580078125 +51161 -0.015228271484375 +51162 0.020721435546875 +51163 0.013336181640625 +51164 0.124481201171875 +51165 0.07891845703125 +51166 0.25787353515625 +51167 0.1632080078125 +51168 0.379119873046875 +51169 0.23980712890625 +51170 0.47991943359375 +51171 0.303466796875 +51172 0.5281982421875 +51173 0.33392333984375 +51174 0.511138916015625 +51175 0.323089599609375 +51176 0.456207275390625 +51177 0.288299560546875 +51178 0.407470703125 +51179 0.257415771484375 +51180 0.383758544921875 +51181 0.242340087890625 +51182 0.35687255859375 +51183 0.225250244140625 +51184 0.31182861328125 +51185 0.196685791015625 +51186 0.250885009765625 +51187 0.158111572265625 +51188 0.1654052734375 +51189 0.104034423828125 +51190 0.035247802734375 +51191 0.021759033203125 +51192 -0.142059326171875 +51193 -0.09027099609375 +51194 -0.33563232421875 +51195 -0.2125244140625 +51196 -0.5345458984375 +51197 -0.338104248046875 +51198 -0.72186279296875 +51199 -0.456329345703125 +51200 -0.836669921875 +51201 -0.5291748046875 +51202 -0.8326416015625 +51203 -0.528045654296875 +51204 -0.7296142578125 +51205 -0.46484375 +51206 -0.582550048828125 +51207 -0.373016357421875 +51208 -0.440093994140625 +51209 -0.28228759765625 +51210 -0.324310302734375 +51211 -0.206451416015625 +51212 -0.20147705078125 +51213 -0.12579345703125 +51214 -0.044647216796875 +51215 -0.02459716796875 +51216 0.103973388671875 +51217 0.0712890625 +51218 0.202392578125 +51219 0.136260986328125 +51220 0.264495849609375 +51221 0.1783447265625 +51222 0.338897705078125 +51223 0.22650146484375 +51224 0.443817138671875 +51225 0.291473388671875 +51226 0.545074462890625 +51227 0.35272216796875 +51228 0.6173095703125 +51229 0.39508056640625 +51230 0.6524658203125 +51231 0.413787841796875 +51232 0.66339111328125 +51233 0.416748046875 +51234 0.6561279296875 +51235 0.4078369140625 +51236 0.606781005859375 +51237 0.373016357421875 +51238 0.501190185546875 +51239 0.304107666015625 +51240 0.352783203125 +51241 0.209442138671875 +51242 0.176544189453125 +51243 0.098358154296875 +51244 -0.034820556640625 +51245 -0.033233642578125 +51246 -0.258209228515625 +51247 -0.171173095703125 +51248 -0.44244384765625 +51249 -0.28460693359375 +51250 -0.5753173828125 +51251 -0.366058349609375 +51252 -0.65203857421875 +51253 -0.41259765625 +51254 -0.641632080078125 +51255 -0.405670166015625 +51256 -0.562164306640625 +51257 -0.356170654296875 +51258 -0.458038330078125 +51259 -0.2908935546875 +51260 -0.350555419921875 +51261 -0.2227783203125 +51262 -0.260528564453125 +51263 -0.164520263671875 +51264 -0.192108154296875 +51265 -0.118865966796875 +51266 -0.141937255859375 +51267 -0.0841064453125 +51268 -0.1021728515625 +51269 -0.055755615234375 +51270 -0.062896728515625 +51271 -0.028106689453125 +51272 -0.011932373046875 +51273 0.005889892578125 +51274 0.062835693359375 +51275 0.0533447265625 +51276 0.148712158203125 +51277 0.106536865234375 +51278 0.241729736328125 +51279 0.16302490234375 +51280 0.34912109375 +51281 0.22711181640625 +51282 0.457305908203125 +51283 0.290740966796875 +51284 0.54388427734375 +51285 0.340545654296875 +51286 0.5728759765625 +51287 0.3551025390625 +51288 0.506591796875 +51289 0.311981201171875 +51290 0.351226806640625 +51291 0.215057373046875 +51292 0.146514892578125 +51293 0.088409423828125 +51294 -0.05523681640625 +51295 -0.036376953125 +51296 -0.21624755859375 +51297 -0.136444091796875 +51298 -0.334930419921875 +51299 -0.21063232421875 +51300 -0.402984619140625 +51301 -0.2537841796875 +51302 -0.4412841796875 +51303 -0.2783203125 +51304 -0.49578857421875 +51305 -0.311767578125 +51306 -0.5601806640625 +51307 -0.350341796875 +51308 -0.600738525390625 +51309 -0.37384033203125 +51310 -0.584228515625 +51311 -0.36236572265625 +51312 -0.47930908203125 +51313 -0.2972412109375 +51314 -0.27935791015625 +51315 -0.17462158203125 +51316 -0.0089111328125 +51317 -0.0093994140625 +51318 0.268798828125 +51319 0.160308837890625 +51320 0.482818603515625 +51321 0.291748046875 +51322 0.60369873046875 +51323 0.367095947265625 +51324 0.650421142578125 +51325 0.3975830078125 +51326 0.66400146484375 +51327 0.40771484375 +51328 0.6414794921875 +51329 0.3956298828125 +51330 0.572540283203125 +51331 0.355072021484375 +51332 0.498138427734375 +51333 0.31060791015625 +51334 0.439453125 +51335 0.274932861328125 +51336 0.375518798828125 +51337 0.235504150390625 +51338 0.274505615234375 +51339 0.173309326171875 +51340 0.1087646484375 +51341 0.071868896484375 +51342 -0.099395751953125 +51343 -0.055328369140625 +51344 -0.3182373046875 +51345 -0.1890869140625 +51346 -0.5489501953125 +51347 -0.329986572265625 +51348 -0.7738037109375 +51349 -0.467254638671875 +51350 -0.86383056640625 +51351 -0.569000244140625 +51352 -0.870391845703125 +51353 -0.615142822265625 +51354 -0.86895751953125 +51355 -0.616241455078125 +51356 -0.861053466796875 +51357 -0.580078125 +51358 -0.765869140625 +51359 -0.49627685546875 +51360 -0.5301513671875 +51361 -0.358062744140625 +51362 -0.214691162109375 +51363 -0.16973876953125 +51364 0.137359619140625 +51365 0.042816162109375 +51366 0.474822998046875 +51367 0.24871826171875 +51368 0.76239013671875 +51369 0.426544189453125 +51370 0.867462158203125 +51371 0.55999755859375 +51372 0.870361328125 +51373 0.64923095703125 +51374 0.86480712890625 +51375 0.68719482421875 +51376 0.831817626953125 +51377 0.677001953125 +51378 0.677581787109375 +51379 0.6331787109375 +51380 0.495880126953125 +51381 0.559112548828125 +51382 0.30767822265625 +51383 0.46588134765625 +51384 0.116180419921875 +51385 0.354766845703125 +51386 -0.110748291015625 +51387 0.206756591796875 +51388 -0.381805419921875 +51389 0.0177001953125 +51390 -0.6572265625 +51391 -0.1866455078125 +51392 -0.857421875 +51393 -0.37030029296875 +51394 -0.870391845703125 +51395 -0.507415771484375 +51396 -0.870391845703125 +51397 -0.5936279296875 +51398 -0.86444091796875 +51399 -0.644989013671875 +51400 -0.85723876953125 +51401 -0.682769775390625 +51402 -0.790008544921875 +51403 -0.69586181640625 +51404 -0.62847900390625 +51405 -0.651641845703125 +51406 -0.3956298828125 +51407 -0.548126220703125 +51408 -0.126708984375 +51409 -0.40496826171875 +51410 0.150115966796875 +51411 -0.23858642578125 +51412 0.424041748046875 +51413 -0.055999755859375 +51414 0.670623779296875 +51415 0.126556396484375 +51416 0.854522705078125 +51417 0.28582763671875 +51418 0.866485595703125 +51419 0.411163330078125 +51420 0.86920166015625 +51421 0.49322509765625 +51422 0.8653564453125 +51423 0.542816162109375 +51424 0.857147216796875 +51425 0.56787109375 +51426 0.766845703125 +51427 0.566558837890625 +51428 0.628509521484375 +51429 0.541839599609375 +51430 0.462127685546875 +51431 0.4896240234375 +51432 0.297210693359375 +51433 0.425323486328125 +51434 0.14862060546875 +51435 0.3563232421875 +51436 -0.00537109375 +51437 0.2689208984375 +51438 -0.15753173828125 +51439 0.167633056640625 +51440 -0.31304931640625 +51441 0.05029296875 +51442 -0.48876953125 +51443 -0.0914306640625 +51444 -0.6416015625 +51445 -0.229339599609375 +51446 -0.751373291015625 +51447 -0.34857177734375 +51448 -0.84619140625 +51449 -0.462860107421875 +51450 -0.861297607421875 +51451 -0.56329345703125 +51452 -0.863250732421875 +51453 -0.629913330078125 +51454 -0.856597900390625 +51455 -0.6436767578125 +51456 -0.7498779296875 +51457 -0.611236572265625 +51458 -0.624542236328125 +51459 -0.566436767578125 +51460 -0.47808837890625 +51461 -0.497528076171875 +51462 -0.253387451171875 +51463 -0.371551513671875 +51464 0.003692626953125 +51465 -0.21478271484375 +51466 0.2257080078125 +51467 -0.066436767578125 +51468 0.427154541015625 +51469 0.080169677734375 +51470 0.643218994140625 +51471 0.24298095703125 +51472 0.855926513671875 +51473 0.416107177734375 +51474 0.870361328125 +51475 0.5662841796875 +51476 0.870361328125 +51477 0.665008544921875 +51478 0.862762451171875 +51479 0.716156005859375 +51480 0.79669189453125 +51481 0.717926025390625 +51482 0.595794677734375 +51483 0.6649169921875 +51484 0.362152099609375 +51485 0.573760986328125 +51486 0.1270751953125 +51487 0.4605712890625 +51488 -0.086944580078125 +51489 0.33758544921875 +51490 -0.2784423828125 +51491 0.206329345703125 +51492 -0.484832763671875 +51493 0.047393798828125 +51494 -0.729583740234375 +51495 -0.14971923828125 +51496 -0.86688232421875 +51497 -0.3558349609375 +51498 -0.870391845703125 +51499 -0.53460693359375 +51500 -0.86859130859375 +51501 -0.682861328125 +51502 -0.86279296875 +51503 -0.799102783203125 +51504 -0.817962646484375 +51505 -0.85540771484375 +51506 -0.6116943359375 +51507 -0.847564697265625 +51508 -0.3128662109375 +51509 -0.749664306640625 +51510 0.039398193359375 +51511 -0.588134765625 +51512 0.422821044921875 +51513 -0.374481201171875 +51514 0.805145263671875 +51515 -0.1278076171875 +51516 0.870361328125 +51517 0.11285400390625 +51518 0.870361328125 +51519 0.314788818359375 +51520 0.860015869140625 +51521 0.470916748046875 +51522 0.727935791015625 +51523 0.576446533203125 +51524 0.48114013671875 +51525 0.627716064453125 +51526 0.2059326171875 +51527 0.63800048828125 +51528 -0.06103515625 +51529 0.619781494140625 +51530 -0.29913330078125 +51531 0.57843017578125 +51532 -0.516204833984375 +51533 0.505523681640625 +51534 -0.7252197265625 +51535 0.3922119140625 +51536 -0.85980224609375 +51537 0.252685546875 +51538 -0.870391845703125 +51539 0.106597900390625 +51540 -0.870391845703125 +51541 -0.028900146484375 +51542 -0.858062744140625 +51543 -0.125762939453125 +51544 -0.673004150390625 +51545 -0.18109130859375 +51546 -0.42694091796875 +51547 -0.22412109375 +51548 -0.2100830078125 +51549 -0.279510498046875 +51550 -0.0362548828125 +51551 -0.345458984375 +51552 0.10943603515625 +51553 -0.4049072265625 +51554 0.23516845703125 +51555 -0.446136474609375 +51556 0.373687744140625 +51557 -0.44525146484375 +51558 0.517791748046875 +51559 -0.403106689453125 +51560 0.602783203125 +51561 -0.3553466796875 +51562 0.635711669921875 +51563 -0.299072265625 +51564 0.655181884765625 +51565 -0.21551513671875 +51566 0.65948486328125 +51567 -0.110595703125 +51568 0.651275634765625 +51569 0.010711669921875 +51570 0.61846923828125 +51571 0.134002685546875 +51572 0.53753662109375 +51573 0.237701416015625 +51574 0.404144287109375 +51575 0.31097412109375 +51576 0.22186279296875 +51577 0.347747802734375 +51578 0.003997802734375 +51579 0.34820556640625 +51580 -0.22100830078125 +51581 0.322174072265625 +51582 -0.42449951171875 +51583 0.281036376953125 +51584 -0.579833984375 +51585 0.23663330078125 +51586 -0.641876220703125 +51587 0.213104248046875 +51588 -0.6177978515625 +51589 0.206634521484375 +51590 -0.575531005859375 +51591 0.1806640625 +51592 -0.526336669921875 +51593 0.13238525390625 +51594 -0.42645263671875 +51595 0.091552734375 +51596 -0.2581787109375 +51597 0.07415771484375 +51598 -0.068695068359375 +51599 0.05999755859375 +51600 0.09222412109375 +51601 0.0277099609375 +51602 0.232147216796875 +51603 -0.011566162109375 +51604 0.3509521484375 +51605 -0.05157470703125 +51606 0.410064697265625 +51607 -0.108673095703125 +51608 0.372955322265625 +51609 -0.19915771484375 +51610 0.2554931640625 +51611 -0.31085205078125 +51612 0.10711669921875 +51613 -0.4139404296875 +51614 -0.052886962890625 +51615 -0.4971923828125 +51616 -0.186279296875 +51617 -0.540069580078125 +51618 -0.23291015625 +51619 -0.51092529296875 +51620 -0.209442138671875 +51621 -0.42291259765625 +51622 -0.174163818359375 +51623 -0.313751220703125 +51624 -0.126739501953125 +51625 -0.18853759765625 +51626 -0.048126220703125 +51627 -0.042083740234375 +51628 0.0426025390625 +51629 0.109130859375 +51630 0.10748291015625 +51631 0.2381591796875 +51632 0.1409912109375 +51633 0.337066650390625 +51634 0.19708251953125 +51635 0.4324951171875 +51636 0.273651123046875 +51637 0.520263671875 +51638 0.31768798828125 +51639 0.568389892578125 +51640 0.341094970703125 +51641 0.5830078125 +51642 0.368011474609375 +51643 0.578369140625 +51644 0.37249755859375 +51645 0.541412353515625 +51646 0.30072021484375 +51647 0.444305419921875 +51648 0.1517333984375 +51649 0.2900390625 +51650 -0.01470947265625 +51651 0.11669921875 +51652 -0.1883544921875 +51653 -0.06524658203125 +51654 -0.372711181640625 +51655 -0.253143310546875 +51656 -0.51397705078125 +51657 -0.411895751953125 +51658 -0.57177734375 +51659 -0.514404296875 +51660 -0.53948974609375 +51661 -0.553375244140625 +51662 -0.43511962890625 +51663 -0.536285400390625 +51664 -0.2962646484375 +51665 -0.482635498046875 +51666 -0.161102294921875 +51667 -0.4132080078125 +51668 -0.0435791015625 +51669 -0.336029052734375 +51670 0.060394287109375 +51671 -0.249847412109375 +51672 0.13665771484375 +51673 -0.1646728515625 +51674 0.170135498046875 +51675 -0.091766357421875 +51676 0.16552734375 +51677 -0.03173828125 +51678 0.15728759765625 +51679 0.03125 +51680 0.150787353515625 +51681 0.096435546875 +51682 0.12200927734375 +51683 0.146392822265625 +51684 0.080108642578125 +51685 0.18280029296875 +51686 0.05126953125 +51687 0.2174072265625 +51688 0.062896728515625 +51689 0.263275146484375 +51690 0.09271240234375 +51691 0.305938720703125 +51692 0.092987060546875 +51693 0.317291259765625 +51694 0.07855224609375 +51695 0.3055419921875 +51696 0.06427001953125 +51697 0.279754638671875 +51698 0.0347900390625 +51699 0.232574462890625 +51700 -0.01171875 +51701 0.16497802734375 +51702 -0.056060791015625 +51703 0.0904541015625 +51704 -0.055511474609375 +51705 0.036163330078125 +51706 -0.010467529296875 +51707 0.005035400390625 +51708 0.02508544921875 +51709 -0.0303955078125 +51710 0.025665283203125 +51711 -0.081634521484375 +51712 0.017333984375 +51713 -0.131378173828125 +51714 0.00189208984375 +51715 -0.176239013671875 +51716 -0.03173828125 +51717 -0.220550537109375 +51718 -0.071502685546875 +51719 -0.25653076171875 +51720 -0.13543701171875 +51721 -0.293548583984375 +51722 -0.219970703125 +51723 -0.329833984375 +51724 -0.300506591796875 +51725 -0.35272216796875 +51726 -0.376312255859375 +51727 -0.36328125 +51728 -0.416107177734375 +51729 -0.346282958984375 +51730 -0.371124267578125 +51731 -0.27728271484375 +51732 -0.242279052734375 +51733 -0.15936279296875 +51734 -0.069732666015625 +51735 -0.01727294921875 +51736 0.125640869140625 +51737 0.134918212890625 +51738 0.31268310546875 +51739 0.277679443359375 +51740 0.45501708984375 +51741 0.388946533203125 +51742 0.554779052734375 +51743 0.46832275390625 +51744 0.61065673828125 +51745 0.51397705078125 +51746 0.610931396484375 +51747 0.5189208984375 +51748 0.531463623046875 +51749 0.46990966796875 +51750 0.3883056640625 +51751 0.3763427734375 +51752 0.23468017578125 +51753 0.268585205078125 +51754 0.095245361328125 +51755 0.161712646484375 +51756 -0.00396728515625 +51757 0.07183837890625 +51758 -0.04852294921875 +51759 0.009002685546875 +51760 -0.055145263671875 +51761 -0.0338134765625 +51762 -0.0758056640625 +51763 -0.083038330078125 +51764 -0.138702392578125 +51765 -0.152130126953125 +51766 -0.209197998046875 +51767 -0.22027587890625 +51768 -0.289031982421875 +51769 -0.286956787109375 +51770 -0.37884521484375 +51771 -0.351470947265625 +51772 -0.456329345703125 +51773 -0.40093994140625 +51774 -0.51641845703125 +51775 -0.432464599609375 +51776 -0.519287109375 +51777 -0.424468994140625 +51778 -0.458251953125 +51779 -0.3740234375 +51780 -0.384796142578125 +51781 -0.310577392578125 +51782 -0.323699951171875 +51783 -0.249176025390625 +51784 -0.269287109375 +51785 -0.188323974609375 +51786 -0.1951904296875 +51787 -0.115325927734375 +51788 -0.100006103515625 +51789 -0.03118896484375 +51790 -0.01055908203125 +51791 0.047576904296875 +51792 0.1033935546875 +51793 0.136016845703125 +51794 0.24908447265625 +51795 0.236846923828125 +51796 0.373199462890625 +51797 0.31976318359375 +51798 0.45806884765625 +51799 0.37445068359375 +51800 0.511474609375 +51801 0.4049072265625 +51802 0.565399169921875 +51803 0.42889404296875 +51804 0.61138916015625 +51805 0.4422607421875 +51806 0.5897216796875 +51807 0.412994384765625 +51808 0.4906005859375 +51809 0.3367919921875 +51810 0.33148193359375 +51811 0.224578857421875 +51812 0.147796630859375 +51813 0.097259521484375 +51814 -0.01873779296875 +51815 -0.020751953125 +51816 -0.140289306640625 +51817 -0.1126708984375 +51818 -0.191986083984375 +51819 -0.163482666015625 +51820 -0.184295654296875 +51821 -0.177825927734375 +51822 -0.161834716796875 +51823 -0.1793212890625 +51824 -0.166595458984375 +51825 -0.190460205078125 +51826 -0.19390869140625 +51827 -0.2083740234375 +51828 -0.22442626953125 +51829 -0.222381591796875 +51830 -0.279754638671875 +51831 -0.244720458984375 +51832 -0.3389892578125 +51833 -0.26446533203125 +51834 -0.3543701171875 +51835 -0.256195068359375 +51836 -0.348175048828125 +51837 -0.233184814453125 +51838 -0.32598876953125 +51839 -0.19964599609375 +51840 -0.2581787109375 +51841 -0.140533447265625 +51842 -0.139801025390625 +51843 -0.0543212890625 +51844 0.014617919921875 +51845 0.04986572265625 +51846 0.144378662109375 +51847 0.13763427734375 +51848 0.221038818359375 +51849 0.19256591796875 +51850 0.27069091796875 +51851 0.2283935546875 +51852 0.294036865234375 +51853 0.245208740234375 +51854 0.311767578125 +51855 0.2542724609375 +51856 0.339141845703125 +51857 0.26409912109375 +51858 0.360260009765625 +51859 0.26617431640625 +51860 0.360504150390625 +51861 0.253173828125 +51862 0.308380126953125 +51863 0.209075927734375 +51864 0.18170166015625 +51865 0.123016357421875 +51866 0.0047607421875 +51867 0.009124755859375 +51868 -0.17559814453125 +51869 -0.106414794921875 +51870 -0.3143310546875 +51871 -0.19842529296875 +51872 -0.36785888671875 +51873 -0.242584228515625 +51874 -0.36248779296875 +51875 -0.252227783203125 +51876 -0.343536376953125 +51877 -0.25103759765625 +51878 -0.3018798828125 +51879 -0.233734130859375 +51880 -0.231414794921875 +51881 -0.1968994140625 +51882 -0.117645263671875 +51883 -0.132843017578125 +51884 0.007049560546875 +51885 -0.059173583984375 +51886 0.087982177734375 +51887 -0.005706787109375 +51888 0.13946533203125 +51889 0.034576416015625 +51890 0.17425537109375 +51891 0.0677490234375 +51892 0.188201904296875 +51893 0.090728759765625 +51894 0.171234130859375 +51895 0.097259521484375 +51896 0.118438720703125 +51897 0.083831787109375 +51898 0.05706787109375 +51899 0.064300537109375 +51900 -0.010711669921875 +51901 0.039093017578125 +51902 -0.0914306640625 +51903 0.004180908203125 +51904 -0.162322998046875 +51905 -0.028594970703125 +51906 -0.194549560546875 +51907 -0.043975830078125 +51908 -0.1492919921875 +51909 -0.02117919921875 +51910 -0.02166748046875 +51911 0.042572021484375 +51912 0.124053955078125 +51913 0.11322021484375 +51914 0.211151123046875 +51915 0.15008544921875 +51916 0.240447998046875 +51917 0.15423583984375 +51918 0.242218017578125 +51919 0.142547607421875 +51920 0.2257080078125 +51921 0.120758056640625 +51922 0.194366455078125 +51923 0.091400146484375 +51924 0.115509033203125 +51925 0.037628173828125 +51926 0.0128173828125 +51927 -0.027252197265625 +51928 -0.053802490234375 +51929 -0.07061767578125 +51930 -0.110626220703125 +51931 -0.106201171875 +51932 -0.199493408203125 +51933 -0.15625 +51934 -0.29437255859375 +51935 -0.206756591796875 +51936 -0.33221435546875 +51937 -0.2239990234375 +51938 -0.27972412109375 +51939 -0.1904296875 +51940 -0.185333251953125 +51941 -0.132354736328125 +51942 -0.128204345703125 +51943 -0.0926513671875 +51944 -0.115692138671875 +51945 -0.0758056640625 +51946 -0.116455078125 +51947 -0.06561279296875 +51948 -0.105926513671875 +51949 -0.04949951171875 +51950 -0.053955078125 +51951 -0.011871337890625 +51952 0.048797607421875 +51953 0.0517578125 +51954 0.157318115234375 +51955 0.116851806640625 +51956 0.212005615234375 +51957 0.151123046875 +51958 0.218475341796875 +51959 0.157379150390625 +51960 0.23724365234375 +51961 0.167938232421875 +51962 0.30535888671875 +51963 0.20269775390625 +51964 0.38128662109375 +51965 0.23956298828125 +51966 0.404449462890625 +51967 0.246337890625 +51968 0.3944091796875 +51969 0.2332763671875 +51970 0.3885498046875 +51971 0.220184326171875 +51972 0.362640380859375 +51973 0.195556640625 +51974 0.27362060546875 +51975 0.13848876953125 +51976 0.11712646484375 +51977 0.047607421875 +51978 -0.054901123046875 +51979 -0.0501708984375 +51980 -0.19085693359375 +51981 -0.128204345703125 +51982 -0.28570556640625 +51983 -0.183441162109375 +51984 -0.339263916015625 +51985 -0.215423583984375 +51986 -0.3775634765625 +51987 -0.237091064453125 +51988 -0.445709228515625 +51989 -0.2711181640625 +51990 -0.535064697265625 +51991 -0.313232421875 +51992 -0.629058837890625 +51993 -0.355316162109375 +51994 -0.697601318359375 +51995 -0.382537841796875 +51996 -0.70391845703125 +51997 -0.376861572265625 +51998 -0.6424560546875 +51999 -0.336029052734375 +52000 -0.491241455078125 +52001 -0.249542236328125 +52002 -0.265716552734375 +52003 -0.125762939453125 +52004 -0.023712158203125 +52005 0.005584716796875 +52006 0.201751708984375 +52007 0.12738037109375 +52008 0.375823974609375 +52009 0.22161865234375 +52010 0.485076904296875 +52011 0.281219482421875 +52012 0.56884765625 +52013 0.32586669921875 +52014 0.634765625 +52015 0.35931396484375 +52016 0.63763427734375 +52017 0.35882568359375 +52018 0.5660400390625 +52019 0.318817138671875 +52020 0.4720458984375 +52021 0.265777587890625 +52022 0.40692138671875 +52023 0.225921630859375 +52024 0.3778076171875 +52025 0.203277587890625 +52026 0.376953125 +52027 0.194427490234375 +52028 0.371978759765625 +52029 0.183502197265625 +52030 0.313140869140625 +52031 0.145904541015625 +52032 0.184417724609375 +52033 0.073944091796875 +52034 0.011199951171875 +52035 -0.0191650390625 +52036 -0.171051025390625 +52037 -0.11529541015625 +52038 -0.33740234375 +52039 -0.20166015625 +52040 -0.47198486328125 +52041 -0.27020263671875 +52042 -0.560394287109375 +52043 -0.313690185546875 +52044 -0.58056640625 +52045 -0.32110595703125 +52046 -0.54754638671875 +52047 -0.300201416015625 +52048 -0.508575439453125 +52049 -0.275115966796875 +52050 -0.459503173828125 +52051 -0.244049072265625 +52052 -0.394378662109375 +52053 -0.20440673828125 +52054 -0.35260009765625 +52055 -0.176422119140625 +52056 -0.31170654296875 +52057 -0.14910888671875 +52058 -0.197418212890625 +52059 -0.085418701171875 +52060 -0.007965087890625 +52061 0.01519775390625 +52062 0.207489013671875 +52063 0.127685546875 +52064 0.409210205078125 +52065 0.23187255859375 +52066 0.57208251953125 +52067 0.31500244140625 +52068 0.66595458984375 +52069 0.36187744140625 +52070 0.65875244140625 +52071 0.35638427734375 +52072 0.56744384765625 +52073 0.3072509765625 +52074 0.431396484375 +52075 0.2344970703125 +52076 0.29443359375 +52077 0.160491943359375 +52078 0.182464599609375 +52079 0.098541259765625 +52080 0.06365966796875 +52081 0.032928466796875 +52082 -0.075958251953125 +52083 -0.04302978515625 +52084 -0.189422607421875 +52085 -0.1053466796875 +52086 -0.271942138671875 +52087 -0.151336669921875 +52088 -0.342529296875 +52089 -0.19036865234375 +52090 -0.364166259765625 +52091 -0.20367431640625 +52092 -0.327239990234375 +52093 -0.186309814453125 +52094 -0.2769775390625 +52095 -0.161041259765625 +52096 -0.253692626953125 +52097 -0.148193359375 +52098 -0.24365234375 +52099 -0.14093017578125 +52100 -0.1983642578125 +52101 -0.114990234375 +52102 -0.116241455078125 +52103 -0.069732666015625 +52104 -0.036834716796875 +52105 -0.02532958984375 +52106 0.034881591796875 +52107 0.01544189453125 +52108 0.09124755859375 +52109 0.0484619140625 +52110 0.10888671875 +52111 0.06170654296875 +52112 0.125518798828125 +52113 0.073944091796875 +52114 0.15771484375 +52115 0.09332275390625 +52116 0.17828369140625 +52117 0.105987548828125 +52118 0.17108154296875 +52119 0.10369873046875 +52120 0.129974365234375 +52121 0.0833740234375 +52122 0.082427978515625 +52123 0.058807373046875 +52124 0.027679443359375 +52125 0.029693603515625 +52126 -0.065643310546875 +52127 -0.019622802734375 +52128 -0.15936279296875 +52129 -0.06976318359375 +52130 -0.21307373046875 +52131 -0.1002197265625 +52132 -0.234649658203125 +52133 -0.114776611328125 +52134 -0.2001953125 +52135 -0.10113525390625 +52136 -0.119171142578125 +52137 -0.06390380859375 +52138 -0.024749755859375 +52139 -0.01959228515625 +52140 0.085784912109375 +52141 0.0333251953125 +52142 0.178131103515625 +52143 0.077667236328125 +52144 0.215576171875 +52145 0.095062255859375 +52146 0.211456298828125 +52147 0.09228515625 +52148 0.17523193359375 +52149 0.07415771484375 +52150 0.128753662109375 +52151 0.0516357421875 +52152 0.1019287109375 +52153 0.03973388671875 +52154 0.0743408203125 +52155 0.028045654296875 +52156 0.04327392578125 +52157 0.015045166015625 +52158 0.038177490234375 +52159 0.015411376953125 +52160 0.076263427734375 +52161 0.03765869140625 +52162 0.14105224609375 +52163 0.07330322265625 +52164 0.186431884765625 +52165 0.09893798828125 +52166 0.188812255859375 +52167 0.1025390625 +52168 0.1390380859375 +52169 0.079376220703125 +52170 0.041778564453125 +52171 0.03173828125 +52172 -0.079437255859375 +52173 -0.028533935546875 +52174 -0.219390869140625 +52175 -0.098907470703125 +52176 -0.367828369140625 +52177 -0.17413330078125 +52178 -0.494873046875 +52179 -0.239166259765625 +52180 -0.556243896484375 +52181 -0.2716064453125 +52182 -0.508697509765625 +52183 -0.24957275390625 +52184 -0.3756103515625 +52185 -0.184722900390625 +52186 -0.218902587890625 +52187 -0.108154296875 +52188 -0.063751220703125 +52189 -0.03240966796875 +52190 0.091552734375 +52191 0.04345703125 +52192 0.23602294921875 +52193 0.11407470703125 +52194 0.342987060546875 +52195 0.166107177734375 +52196 0.39520263671875 +52197 0.19097900390625 +52198 0.389373779296875 +52199 0.187103271484375 +52200 0.324249267578125 +52201 0.15386962890625 +52202 0.224090576171875 +52203 0.103546142578125 +52204 0.124267578125 +52205 0.05389404296875 +52206 0.037078857421875 +52207 0.011077880859375 +52208 -0.010101318359375 +52209 -0.01116943359375 +52210 -0.019439697265625 +52211 -0.0140380859375 +52212 -0.022796630859375 +52213 -0.013702392578125 +52214 -0.001556396484375 +52215 -0.000885009765625 +52216 0.056304931640625 +52217 0.030303955078125 +52218 0.106719970703125 +52219 0.057586669921875 +52220 0.096893310546875 +52221 0.05426025390625 +52222 0.042694091796875 +52223 0.028228759765625 +52224 -0.018035888671875 +52225 -0.00115966796875 +52226 -0.07586669921875 +52227 -0.029388427734375 +52228 -0.11944580078125 +52229 -0.051361083984375 +52230 -0.15972900390625 +52231 -0.07208251953125 +52232 -0.202606201171875 +52233 -0.094146728515625 +52234 -0.24859619140625 +52235 -0.117645263671875 +52236 -0.30517578125 +52237 -0.145965576171875 +52238 -0.36212158203125 +52239 -0.174224853515625 +52240 -0.39141845703125 +52241 -0.18914794921875 +52242 -0.35528564453125 +52243 -0.172821044921875 +52244 -0.249969482421875 +52245 -0.12347412109375 +52246 -0.092864990234375 +52247 -0.049346923828125 +52248 0.08905029296875 +52249 0.036834716796875 +52250 0.2352294921875 +52251 0.106475830078125 +52252 0.318817138671875 +52253 0.1468505859375 +52254 0.358642578125 +52255 0.166717529296875 +52256 0.347747802734375 +52257 0.162750244140625 +52258 0.28564453125 +52259 0.134674072265625 +52260 0.223175048828125 +52261 0.10638427734375 +52262 0.196746826171875 +52263 0.095001220703125 +52264 0.179840087890625 +52265 0.087982177734375 +52266 0.155548095703125 +52267 0.077301025390625 +52268 0.151214599609375 +52269 0.075836181640625 +52270 0.156951904296875 +52271 0.078857421875 +52272 0.13177490234375 +52273 0.0670166015625 +52274 0.100799560546875 +52275 0.052154541015625 +52276 0.087127685546875 +52277 0.045196533203125 +52278 0.05487060546875 +52279 0.029266357421875 +52280 -0.009002685546875 +52281 -0.001739501953125 +52282 -0.10400390625 +52283 -0.04754638671875 +52284 -0.229400634765625 +52285 -0.107757568359375 +52286 -0.35552978515625 +52287 -0.168304443359375 +52288 -0.441925048828125 +52289 -0.21002197265625 +52290 -0.473846435546875 +52291 -0.225921630859375 +52292 -0.464813232421875 +52293 -0.222320556640625 +52294 -0.419097900390625 +52295 -0.201202392578125 +52296 -0.334320068359375 +52297 -0.16143798828125 +52298 -0.227935791015625 +52299 -0.111236572265625 +52300 -0.12347412109375 +52301 -0.06170654296875 +52302 -0.02764892578125 +52303 -0.016082763671875 +52304 0.077667236328125 +52305 0.0341796875 +52306 0.2132568359375 +52307 0.098846435546875 +52308 0.38885498046875 +52309 0.182464599609375 +52310 0.582794189453125 +52311 0.2747802734375 +52312 0.734039306640625 +52313 0.346954345703125 +52314 0.800140380859375 +52315 0.37890625 +52316 0.7783203125 +52317 0.3692626953125 +52318 0.6651611328125 +52319 0.316375732421875 +52320 0.45965576171875 +52321 0.219757080078125 +52322 0.199188232421875 +52323 0.0970458984375 +52324 -0.050689697265625 +52325 -0.02081298828125 +52326 -0.23297119140625 +52327 -0.106903076171875 +52328 -0.33013916015625 +52329 -0.152984619140625 +52330 -0.368408203125 +52331 -0.17138671875 +52332 -0.378936767578125 +52333 -0.176788330078125 +52334 -0.376983642578125 +52335 -0.1763916015625 +52336 -0.37969970703125 +52337 -0.17828369140625 +52338 -0.391510009765625 +52339 -0.18450927734375 +52340 -0.385345458984375 +52341 -0.182220458984375 +52342 -0.3419189453125 +52343 -0.16229248046875 +52344 -0.28289794921875 +52345 -0.134918212890625 +52346 -0.251617431640625 +52347 -0.120513916015625 +52348 -0.266143798828125 +52349 -0.127593994140625 +52350 -0.273345947265625 +52351 -0.131103515625 +52352 -0.216796875 +52353 -0.1043701171875 +52354 -0.128265380859375 +52355 -0.062408447265625 +52356 -0.068145751953125 +52357 -0.033721923828125 +52358 -0.0430908203125 +52359 -0.021484375 +52360 -0.024444580078125 +52361 -0.01220703125 +52362 0.020721435546875 +52363 0.0096435546875 +52364 0.124481201171875 +52365 0.05914306640625 +52366 0.25787353515625 +52367 0.12255859375 +52368 0.379119873046875 +52369 0.18017578125 +52370 0.47991943359375 +52371 0.228057861328125 +52372 0.5281982421875 +52373 0.25103759765625 +52374 0.511138916015625 +52375 0.24310302734375 +52376 0.456207275390625 +52377 0.217193603515625 +52378 0.407470703125 +52379 0.194091796875 +52380 0.383758544921875 +52381 0.182708740234375 +52382 0.35687255859375 +52383 0.16973876953125 +52384 0.31182861328125 +52385 0.14813232421875 +52386 0.250885009765625 +52387 0.11895751953125 +52388 0.1654052734375 +52389 0.07818603515625 +52390 0.035247802734375 +52391 0.016357421875 +52392 -0.142059326171875 +52393 -0.067657470703125 +52394 -0.33563232421875 +52395 -0.159271240234375 +52396 -0.5345458984375 +52397 -0.253326416015625 +52398 -0.72186279296875 +52399 -0.341827392578125 +52400 -0.836669921875 +52401 -0.396026611328125 +52402 -0.8326416015625 +52403 -0.394073486328125 +52404 -0.7296142578125 +52405 -0.345306396484375 +52406 -0.582550048828125 +52407 -0.27569580078125 +52408 -0.440093994140625 +52409 -0.208221435546875 +52410 -0.324310302734375 +52411 -0.1533203125 +52412 -0.20147705078125 +52413 -0.095062255859375 +52414 -0.044647216796875 +52415 -0.020721435546875 +52416 0.103973388671875 +52417 0.049713134765625 +52418 0.202392578125 +52419 0.096405029296875 +52420 0.264495849609375 +52421 0.12591552734375 +52422 0.338897705078125 +52423 0.161163330078125 +52424 0.443817138671875 +52425 0.210723876953125 +52426 0.545074462890625 +52427 0.258514404296875 +52428 0.6173095703125 +52429 0.29254150390625 +52430 0.6524658203125 +52431 0.308990478515625 +52432 0.66339111328125 +52433 0.313934326171875 +52434 0.6561279296875 +52435 0.310272216796875 +52436 0.606781005859375 +52437 0.286712646484375 +52438 0.501190185546875 +52439 0.236572265625 +52440 0.352783203125 +52441 0.166229248046875 +52442 0.176544189453125 +52443 0.082763671875 +52444 -0.034820556640625 +52445 -0.017242431640625 +52446 -0.258209228515625 +52447 -0.122833251953125 +52448 -0.44244384765625 +52449 -0.2098388671875 +52450 -0.5753173828125 +52451 -0.27252197265625 +52452 -0.65203857421875 +52453 -0.30865478515625 +52454 -0.641632080078125 +52455 -0.3035888671875 +52456 -0.562164306640625 +52457 -0.265899658203125 +52458 -0.458038330078125 +52459 -0.216552734375 +52460 -0.350555419921875 +52461 -0.16558837890625 +52462 -0.260528564453125 +52463 -0.122833251953125 +52464 -0.192108154296875 +52465 -0.09027099609375 +52466 -0.141937255859375 +52467 -0.06634521484375 +52468 -0.1021728515625 +52469 -0.04736328125 +52470 -0.062896728515625 +52471 -0.028656005859375 +52472 -0.011932373046875 +52473 -0.004486083984375 +52474 0.062835693359375 +52475 0.030853271484375 +52476 0.148712158203125 +52477 0.071380615234375 +52478 0.241729736328125 +52479 0.11517333984375 +52480 0.34912109375 +52481 0.165374755859375 +52482 0.457305908203125 +52483 0.21484375 +52484 0.54388427734375 +52485 0.25311279296875 +52486 0.5728759765625 +52487 0.264739990234375 +52488 0.506591796875 +52489 0.23345947265625 +52490 0.351226806640625 +52491 0.162322998046875 +52492 0.146514892578125 +52493 0.069091796875 +52494 -0.05523681640625 +52495 -0.022918701171875 +52496 -0.21624755859375 +52497 -0.096832275390625 +52498 -0.334930419921875 +52499 -0.151763916015625 +52500 -0.402984619140625 +52501 -0.183929443359375 +52502 -0.4412841796875 +52503 -0.202423095703125 +52504 -0.49578857421875 +52505 -0.2274169921875 +52506 -0.5601806640625 +52507 -0.256072998046875 +52508 -0.600738525390625 +52509 -0.27362060546875 +52510 -0.584228515625 +52511 -0.265472412109375 +52512 -0.47930908203125 +52513 -0.217926025390625 +52514 -0.27935791015625 +52515 -0.128173828125 +52516 -0.0089111328125 +52517 -0.007171630859375 +52518 0.268798828125 +52519 0.11712646484375 +52520 0.482818603515625 +52521 0.213409423828125 +52522 0.60369873046875 +52523 0.268585205078125 +52524 0.650421142578125 +52525 0.2908935546875 +52526 0.66400146484375 +52527 0.298309326171875 +52528 0.6414794921875 +52529 0.289459228515625 +52530 0.572540283203125 +52531 0.259735107421875 +52532 0.498138427734375 +52533 0.227142333984375 +52534 0.439453125 +52535 0.201019287109375 +52536 0.375518798828125 +52537 0.17218017578125 +52538 0.274505615234375 +52539 0.12664794921875 +52540 0.1087646484375 +52541 0.052337646484375 +52542 -0.099395751953125 +52543 -0.040802001953125 +52544 -0.3182373046875 +52545 -0.13873291015625 +52546 -0.5489501953125 +52547 -0.24188232421875 +52548 -0.7738037109375 +52549 -0.34234619140625 +52550 -0.86383056640625 +52551 -0.416748046875 +52552 -0.870391845703125 +52553 -0.45037841796875 +52554 -0.86895751953125 +52555 -0.451019287109375 +52556 -0.861053466796875 +52557 -0.424407958984375 +52558 -0.765869140625 +52559 -0.3629150390625 +52560 -0.5301513671875 +52561 -0.261566162109375 +52562 -0.214691162109375 +52563 -0.12353515625 +52564 0.137359619140625 +52565 0.032196044921875 +52566 0.474822998046875 +52567 0.183013916015625 +52568 0.76239013671875 +52569 0.313232421875 +52570 0.867462158203125 +52571 0.410888671875 +52572 0.870361328125 +52573 0.476104736328125 +52574 0.86480712890625 +52575 0.503692626953125 +52576 0.831817626953125 +52577 0.4959716796875 +52578 0.677581787109375 +52579 0.463592529296875 +52580 0.495880126953125 +52581 0.409088134765625 +52582 0.30767822265625 +52583 0.340576171875 +52584 0.116180419921875 +52585 0.259033203125 +52586 -0.110748291015625 +52587 0.150482177734375 +52588 -0.381805419921875 +52589 0.01190185546875 +52590 -0.6572265625 +52591 -0.1378173828125 +52592 -0.857421875 +52593 -0.27227783203125 +52594 -0.870391845703125 +52595 -0.372589111328125 +52596 -0.870391845703125 +52597 -0.435516357421875 +52598 -0.86444091796875 +52599 -0.472869873046875 +52600 -0.85723876953125 +52601 -0.500274658203125 +52602 -0.790008544921875 +52603 -0.509613037109375 +52604 -0.62847900390625 +52605 -0.476959228515625 +52606 -0.3956298828125 +52607 -0.40087890625 +52608 -0.126708984375 +52609 -0.2957763671875 +52610 0.150115966796875 +52611 -0.173675537109375 +52612 0.424041748046875 +52613 -0.039764404296875 +52614 0.670623779296875 +52615 0.09405517578125 +52616 0.854522705078125 +52617 0.210723876953125 +52618 0.866485595703125 +52619 0.30242919921875 +52620 0.86920166015625 +52621 0.362335205078125 +52622 0.8653564453125 +52623 0.398406982421875 +52624 0.857147216796875 +52625 0.416473388671875 +52626 0.766845703125 +52627 0.41522216796875 +52628 0.628509521484375 +52629 0.3968505859375 +52630 0.462127685546875 +52631 0.358367919921875 +52632 0.297210693359375 +52633 0.311065673828125 +52634 0.14862060546875 +52635 0.260345458984375 +52636 -0.00537109375 +52637 0.1961669921875 +52638 -0.15753173828125 +52639 0.121856689453125 +52640 -0.31304931640625 +52641 0.035858154296875 +52642 -0.48876953125 +52643 -0.0679931640625 +52644 -0.6416015625 +52645 -0.16900634765625 +52646 -0.751373291015625 +52647 -0.256256103515625 +52648 -0.84619140625 +52649 -0.33984375 +52650 -0.861297607421875 +52651 -0.413238525390625 +52652 -0.863250732421875 +52653 -0.461822509765625 +52654 -0.856597900390625 +52655 -0.471649169921875 +52656 -0.7498779296875 +52657 -0.447998046875 +52658 -0.624542236328125 +52659 -0.41632080078125 +52660 -0.47808837890625 +52661 -0.366943359375 +52662 -0.253387451171875 +52663 -0.274169921875 +52664 0.003692626953125 +52665 -0.158050537109375 +52666 0.2257080078125 +52667 -0.048736572265625 +52668 0.427154541015625 +52669 0.05926513671875 +52670 0.643218994140625 +52671 0.180145263671875 +52672 0.855926513671875 +52673 0.30963134765625 +52674 0.870361328125 +52675 0.422149658203125 +52676 0.870361328125 +52677 0.495819091796875 +52678 0.862762451171875 +52679 0.53375244140625 +52680 0.79669189453125 +52681 0.53460693359375 +52682 0.595794677734375 +52683 0.49420166015625 +52684 0.362152099609375 +52685 0.425384521484375 +52686 0.1270751953125 +52687 0.3404541015625 +52688 -0.086944580078125 +52689 0.248748779296875 +52690 -0.2784423828125 +52691 0.151214599609375 +52692 -0.484832763671875 +52693 0.032562255859375 +52694 -0.729583740234375 +52695 -0.115570068359375 +52696 -0.86688232421875 +52697 -0.27081298828125 +52698 -0.870391845703125 +52699 -0.4052734375 +52700 -0.86859130859375 +52701 -0.516693115234375 +52702 -0.86279296875 +52703 -0.60406494140625 +52704 -0.817962646484375 +52705 -0.6514892578125 +52706 -0.6116943359375 +52707 -0.638916015625 +52708 -0.3128662109375 +52709 -0.563201904296875 +52710 0.039398193359375 +52711 -0.43914794921875 +52712 0.422821044921875 +52713 -0.27557373046875 +52714 0.805145263671875 +52715 -0.087188720703125 +52716 0.870361328125 +52717 0.09600830078125 +52718 0.870361328125 +52719 0.24884033203125 +52720 0.860015869140625 +52721 0.36602783203125 +52722 0.727935791015625 +52723 0.444061279296875 +52724 0.48114013671875 +52725 0.48028564453125 +52726 0.2059326171875 +52727 0.485198974609375 +52728 -0.06103515625 +52729 0.4686279296875 +52730 -0.29913330078125 +52731 0.434814453125 +52732 -0.516204833984375 +52733 0.3773193359375 +52734 -0.7252197265625 +52735 0.289337158203125 +52736 -0.85980224609375 +52737 0.181640625 +52738 -0.870391845703125 +52739 0.069854736328125 +52740 -0.870391845703125 +52741 -0.032806396484375 +52742 -0.858062744140625 +52743 -0.106201171875 +52744 -0.673004150390625 +52745 -0.148345947265625 +52746 -0.42694091796875 +52747 -0.18035888671875 +52748 -0.2100830078125 +52749 -0.22003173828125 +52750 -0.0362548828125 +52751 -0.2662353515625 +52752 0.10943603515625 +52753 -0.306854248046875 +52754 0.23516845703125 +52755 -0.3336181640625 +52756 0.373687744140625 +52757 -0.329559326171875 +52758 0.517791748046875 +52759 -0.2955322265625 +52760 0.602783203125 +52761 -0.257354736328125 +52762 0.635711669921875 +52763 -0.213165283203125 +52764 0.655181884765625 +52765 -0.149627685546875 +52766 0.65948486328125 +52767 -0.071197509765625 +52768 0.651275634765625 +52769 0.018402099609375 +52770 0.61846923828125 +52771 0.108734130859375 +52772 0.53753662109375 +52773 0.18426513671875 +52774 0.404144287109375 +52775 0.2371826171875 +52776 0.22186279296875 +52777 0.263092041015625 +52778 0.003997802734375 +52779 0.26220703125 +52780 -0.22100830078125 +52781 0.24169921875 +52782 -0.42449951171875 +52783 0.2098388671875 +52784 -0.579833984375 +52785 0.17529296875 +52786 -0.641876220703125 +52787 0.155548095703125 +52788 -0.6177978515625 +52789 0.14801025390625 +52790 -0.575531005859375 +52791 0.1265869140625 +52792 -0.526336669921875 +52793 0.089385986328125 +52794 -0.42645263671875 +52795 0.057891845703125 +52796 -0.2581787109375 +52797 0.043731689453125 +52798 -0.068695068359375 +52799 0.032470703125 +52800 0.09222412109375 +52801 0.008819580078125 +52802 0.232147216796875 +52803 -0.01922607421875 +52804 0.3509521484375 +52805 -0.047210693359375 +52806 0.410064697265625 +52807 -0.0869140625 +52808 0.372955322265625 +52809 -0.150146484375 +52810 0.2554931640625 +52811 -0.228271484375 +52812 0.10711669921875 +52813 -0.29998779296875 +52814 -0.052886962890625 +52815 -0.35736083984375 +52816 -0.186279296875 +52817 -0.385772705078125 +52818 -0.23291015625 +52819 -0.362640380859375 +52820 -0.209442138671875 +52821 -0.297515869140625 +52822 -0.174163818359375 +52823 -0.21759033203125 +52824 -0.126739501953125 +52825 -0.1265869140625 +52826 -0.048126220703125 +52827 -0.02081298828125 +52828 0.0426025390625 +52829 0.087860107421875 +52830 0.10748291015625 +52831 0.180084228515625 +52832 0.1409912109375 +52833 0.25018310546875 +52834 0.19708251953125 +52835 0.317352294921875 +52836 0.273651123046875 +52837 0.378662109375 +52838 0.31768798828125 +52839 0.411285400390625 +52840 0.341094970703125 +52841 0.419708251953125 +52842 0.368011474609375 +52843 0.414337158203125 +52844 0.37249755859375 +52845 0.385894775390625 +52846 0.30072021484375 +52847 0.314453125 +52848 0.1517333984375 +52849 0.2022705078125 +52850 -0.01470947265625 +52851 0.076751708984375 +52852 -0.1883544921875 +52853 -0.054534912109375 +52854 -0.372711181640625 +52855 -0.18963623046875 +52856 -0.51397705078125 +52857 -0.303375244140625 +52858 -0.57177734375 +52859 -0.376312255859375 +52860 -0.53948974609375 +52861 -0.40325927734375 +52862 -0.43511962890625 +52863 -0.3896484375 +52864 -0.2962646484375 +52865 -0.34954833984375 +52866 -0.161102294921875 +52867 -0.2979736328125 +52868 -0.0435791015625 +52869 -0.240814208984375 +52870 0.060394287109375 +52871 -0.177276611328125 +52872 0.13665771484375 +52873 -0.1146240234375 +52874 0.170135498046875 +52875 -0.061004638671875 +52876 0.16552734375 +52877 -0.016937255859375 +52878 0.15728759765625 +52879 0.0289306640625 +52880 0.150787353515625 +52881 0.076019287109375 +52882 0.12200927734375 +52883 0.111785888671875 +52884 0.080108642578125 +52885 0.137451171875 +52886 0.05126953125 +52887 0.1614990234375 +52888 0.062896728515625 +52889 0.193359375 +52890 0.09271240234375 +52891 0.22271728515625 +52892 0.092987060546875 +52893 0.229461669921875 +52894 0.07855224609375 +52895 0.219573974609375 +52896 0.06427001953125 +52897 0.199676513671875 +52898 0.0347900390625 +52899 0.164520263671875 +52900 -0.01171875 +52901 0.1148681640625 +52902 -0.056060791015625 +52903 0.060455322265625 +52904 -0.055511474609375 +52905 0.020843505859375 +52906 -0.010467529296875 +52907 -0.001800537109375 +52908 0.02508544921875 +52909 -0.0272216796875 +52910 0.025665283203125 +52911 -0.063690185546875 +52912 0.017333984375 +52913 -0.098663330078125 +52914 0.00189208984375 +52915 -0.12982177734375 +52916 -0.03173828125 +52917 -0.160552978515625 +52918 -0.071502685546875 +52919 -0.185272216796875 +52920 -0.13543701171875 +52921 -0.211090087890625 +52922 -0.219970703125 +52923 -0.23681640625 +52924 -0.300506591796875 +52925 -0.25311279296875 +52926 -0.376312255859375 +52927 -0.26080322265625 +52928 -0.416107177734375 +52929 -0.24859619140625 +52930 -0.371124267578125 +52931 -0.19830322265625 +52932 -0.242279052734375 +52933 -0.11212158203125 +52934 -0.069732666015625 +52935 -0.008331298828125 +52936 0.125640869140625 +52937 0.102691650390625 +52938 0.31268310546875 +52939 0.20660400390625 +52940 0.45501708984375 +52941 0.28717041015625 +52942 0.554779052734375 +52943 0.34417724609375 +52944 0.61065673828125 +52945 0.37640380859375 +52946 0.610931396484375 +52947 0.37872314453125 +52948 0.531463623046875 +52949 0.341400146484375 +52950 0.3883056640625 +52951 0.271453857421875 +52952 0.23468017578125 +52953 0.19140625 +52954 0.095245361328125 +52955 0.112457275390625 +52956 -0.00396728515625 +52957 0.04656982421875 +52958 -0.04852294921875 +52959 0.001068115234375 +52960 -0.055145263671875 +52961 -0.029296875 +52962 -0.0758056640625 +52963 -0.064208984375 +52964 -0.138702392578125 +52965 -0.113739013671875 +52966 -0.209197998046875 +52967 -0.162567138671875 +52968 -0.289031982421875 +52969 -0.21038818359375 +52970 -0.37884521484375 +52971 -0.25677490234375 +52972 -0.456329345703125 +52973 -0.292266845703125 +52974 -0.51641845703125 +52975 -0.31475830078125 +52976 -0.519287109375 +52977 -0.308258056640625 +52978 -0.458251953125 +52979 -0.2706298828125 +52980 -0.384796142578125 +52981 -0.223724365234375 +52982 -0.323699951171875 +52983 -0.1787109375 +52984 -0.269287109375 +52985 -0.134429931640625 +52986 -0.1951904296875 +52987 -0.081390380859375 +52988 -0.100006103515625 +52989 -0.020263671875 +52990 -0.01055908203125 +52991 0.036773681640625 +52992 0.1033935546875 +52993 0.100830078125 +52994 0.24908447265625 +52995 0.17401123046875 +52996 0.373199462890625 +52997 0.234283447265625 +52998 0.45806884765625 +52999 0.2740478515625 +53000 0.511474609375 +53001 0.296142578125 +53002 0.565399169921875 +53003 0.313446044921875 +53004 0.61138916015625 +53005 0.32293701171875 +53006 0.5897216796875 +53007 0.30133056640625 +53008 0.4906005859375 +53009 0.245513916015625 +53010 0.33148193359375 +53011 0.1634521484375 +53012 0.147796630859375 +53013 0.07037353515625 +53014 -0.01873779296875 +53015 -0.015899658203125 +53016 -0.140289306640625 +53017 -0.083160400390625 +53018 -0.191986083984375 +53019 -0.120452880859375 +53020 -0.184295654296875 +53021 -0.131134033203125 +53022 -0.161834716796875 +53023 -0.13238525390625 +53024 -0.166595458984375 +53025 -0.140533447265625 +53026 -0.19390869140625 +53027 -0.153472900390625 +53028 -0.22442626953125 +53029 -0.163482666015625 +53030 -0.279754638671875 +53031 -0.179412841796875 +53032 -0.3389892578125 +53033 -0.193389892578125 +53034 -0.3543701171875 +53035 -0.186920166015625 +53036 -0.348175048828125 +53037 -0.169708251953125 +53038 -0.32598876953125 +53039 -0.14483642578125 +53040 -0.2581787109375 +53041 -0.10137939453125 +53042 -0.139801025390625 +53043 -0.038238525390625 +53044 0.014617919921875 +53045 0.03790283203125 +53046 0.144378662109375 +53047 0.10198974609375 +53048 0.221038818359375 +53049 0.14208984375 +53050 0.27069091796875 +53051 0.168182373046875 +53052 0.294036865234375 +53053 0.180328369140625 +53054 0.311767578125 +53055 0.18670654296875 +53056 0.339141845703125 +53057 0.193511962890625 +53058 0.360260009765625 +53059 0.19439697265625 +53060 0.360504150390625 +53061 0.18408203125 +53062 0.308380126953125 +53063 0.151519775390625 +53064 0.18170166015625 +53065 0.089202880859375 +53066 0.0047607421875 +53067 0.007232666015625 +53068 -0.17559814453125 +53069 -0.07586669921875 +53070 -0.3143310546875 +53071 -0.142333984375 +53072 -0.36785888671875 +53073 -0.175018310546875 +53074 -0.36248779296875 +53075 -0.183135986328125 +53076 -0.343536376953125 +53077 -0.183258056640625 +53078 -0.3018798828125 +53079 -0.171630859375 +53080 -0.231414794921875 +53081 -0.14581298828125 +53082 -0.117645263671875 +53083 -0.100433349609375 +53084 0.007049560546875 +53085 -0.04791259765625 +53086 0.087982177734375 +53087 -0.00921630859375 +53088 0.13946533203125 +53089 0.020477294921875 +53090 0.17425537109375 +53091 0.04534912109375 +53092 0.188201904296875 +53093 0.063140869140625 +53094 0.171234130859375 +53095 0.069366455078125 +53096 0.118438720703125 +53097 0.061492919921875 +53098 0.05706787109375 +53099 0.049163818359375 +53100 -0.010711669921875 +53101 0.032623291015625 +53102 -0.0914306640625 +53103 0.008941650390625 +53104 -0.162322998046875 +53105 -0.0135498046875 +53106 -0.194549560546875 +53107 -0.024200439453125 +53108 -0.1492919921875 +53109 -0.0084228515625 +53110 -0.02166748046875 +53111 0.035736083984375 +53112 0.124053955078125 +53113 0.08441162109375 +53114 0.211151123046875 +53115 0.109130859375 +53116 0.240447998046875 +53117 0.1107177734375 +53118 0.242218017578125 +53119 0.101104736328125 +53120 0.2257080078125 +53121 0.084381103515625 +53122 0.194366455078125 +53123 0.062408447265625 +53124 0.115509033203125 +53125 0.023468017578125 +53126 0.0128173828125 +53127 -0.023040771484375 +53128 -0.053802490234375 +53129 -0.05419921875 +53130 -0.110626220703125 +53131 -0.079620361328125 +53132 -0.199493408203125 +53133 -0.114898681640625 +53134 -0.29437255859375 +53135 -0.15020751953125 +53136 -0.33221435546875 +53137 -0.161895751953125 +53138 -0.27972412109375 +53139 -0.137664794921875 +53140 -0.185333251953125 +53141 -0.096038818359375 +53142 -0.128204345703125 +53143 -0.067169189453125 +53144 -0.115692138671875 +53145 -0.05419921875 +53146 -0.116455078125 +53147 -0.045867919921875 +53148 -0.105926513671875 +53149 -0.033416748046875 +53150 -0.053955078125 +53151 -0.0059814453125 +53152 0.048797607421875 +53153 0.039520263671875 +53154 0.157318115234375 +53155 0.085845947265625 +53156 0.212005615234375 +53157 0.110321044921875 +53158 0.218475341796875 +53159 0.1148681640625 +53160 0.23724365234375 +53161 0.1221923828125 +53162 0.30535888671875 +53163 0.146270751953125 +53164 0.38128662109375 +53165 0.171630859375 +53166 0.404449462890625 +53167 0.175689697265625 +53168 0.3944091796875 +53169 0.16607666015625 +53170 0.3885498046875 +53171 0.1572265625 +53172 0.362640380859375 +53173 0.140411376953125 +53174 0.27362060546875 +53175 0.099853515625 +53176 0.11712646484375 +53177 0.0343017578125 +53178 -0.054901123046875 +53179 -0.036346435546875 +53180 -0.19085693359375 +53181 -0.092376708984375 +53182 -0.28570556640625 +53183 -0.13165283203125 +53184 -0.339263916015625 +53185 -0.153961181640625 +53186 -0.3775634765625 +53187 -0.16900634765625 +53188 -0.445709228515625 +53189 -0.193756103515625 +53190 -0.535064697265625 +53191 -0.225067138671875 +53192 -0.629058837890625 +53193 -0.256866455078125 +53194 -0.697601318359375 +53195 -0.278045654296875 +53196 -0.70391845703125 +53197 -0.27508544921875 +53198 -0.6424560546875 +53199 -0.2462158203125 +53200 -0.491241455078125 +53201 -0.1834716796875 +53202 -0.265716552734375 +53203 -0.093017578125 +53204 -0.023712158203125 +53205 0.003082275390625 +53206 0.201751708984375 +53207 0.0921630859375 +53208 0.375823974609375 +53209 0.160919189453125 +53210 0.485076904296875 +53211 0.204132080078125 +53212 0.56884765625 +53213 0.23651123046875 +53214 0.634765625 +53215 0.26092529296875 +53216 0.63763427734375 +53217 0.26043701171875 +53218 0.5660400390625 +53219 0.230865478515625 +53220 0.4720458984375 +53221 0.19195556640625 +53222 0.40692138671875 +53223 0.1632080078125 +53224 0.3778076171875 +53225 0.147552490234375 +53226 0.376953125 +53227 0.142364501953125 +53228 0.371978759765625 +53229 0.1357421875 +53230 0.313140869140625 +53231 0.109222412109375 +53232 0.184417724609375 +53233 0.056976318359375 +53234 0.011199951171875 +53235 -0.011199951171875 +53236 -0.171051025390625 +53237 -0.081787109375 +53238 -0.33740234375 +53239 -0.145355224609375 +53240 -0.47198486328125 +53241 -0.1959228515625 +53242 -0.560394287109375 +53243 -0.22808837890625 +53244 -0.58056640625 +53245 -0.233673095703125 +53246 -0.54754638671875 +53247 -0.218475341796875 +53248 -0.508575439453125 +53249 -0.2003173828125 +53250 -0.459503173828125 +53251 -0.17803955078125 +53252 -0.394378662109375 +53253 -0.1494140625 +53254 -0.35260009765625 +53255 -0.1282958984375 +53256 -0.31170654296875 +53257 -0.107330322265625 +53258 -0.197418212890625 +53259 -0.06134033203125 +53260 -0.007965087890625 +53261 0.009918212890625 +53262 0.207489013671875 +53263 0.0892333984375 +53264 0.409210205078125 +53265 0.162689208984375 +53266 0.57208251953125 +53267 0.22149658203125 +53268 0.66595458984375 +53269 0.255157470703125 +53270 0.65875244140625 +53271 0.25262451171875 +53272 0.56744384765625 +53273 0.219757080078125 +53274 0.431396484375 +53275 0.17022705078125 +53276 0.29443359375 +53277 0.1192626953125 +53278 0.182464599609375 +53279 0.0760498046875 +53280 0.06365966796875 +53281 0.0299072265625 +53282 -0.075958251953125 +53283 -0.023651123046875 +53284 -0.189422607421875 +53285 -0.068145751953125 +53286 -0.271942138671875 +53287 -0.10162353515625 +53288 -0.342529296875 +53289 -0.13037109375 +53290 -0.364166259765625 +53291 -0.141448974609375 +53292 -0.327239990234375 +53293 -0.131378173828125 +53294 -0.2769775390625 +53295 -0.115631103515625 +53296 -0.253692626953125 +53297 -0.108001708984375 +53298 -0.24365234375 +53299 -0.103790283203125 +53300 -0.1983642578125 +53301 -0.08636474609375 +53302 -0.116241455078125 +53303 -0.055328369140625 +53304 -0.036834716796875 +53305 -0.0244140625 +53306 0.034881591796875 +53307 0.00439453125 +53308 0.09124755859375 +53309 0.028228759765625 +53310 0.10888671875 +53311 0.038787841796875 +53312 0.125518798828125 +53313 0.048797607421875 +53314 0.15771484375 +53315 0.063720703125 +53316 0.17828369140625 +53317 0.074005126953125 +53318 0.17108154296875 +53319 0.073944091796875 +53320 0.129974365234375 +53321 0.06134033203125 +53322 0.082427978515625 +53323 0.045562744140625 +53324 0.027679443359375 +53325 0.0263671875 +53326 -0.065643310546875 +53327 -0.0069580078125 +53328 -0.15936279296875 +53329 -0.04119873046875 +53330 -0.21307373046875 +53331 -0.06231689453125 +53332 -0.234649658203125 +53333 -0.0728759765625 +53334 -0.2001953125 +53335 -0.064483642578125 +53336 -0.119171142578125 +53337 -0.04022216796875 +53338 -0.024749755859375 +53339 -0.01129150390625 +53340 0.085784912109375 +53341 0.0234375 +53342 0.178131103515625 +53343 0.05230712890625 +53344 0.215576171875 +53345 0.0628662109375 +53346 0.211456298828125 +53347 0.059783935546875 +53348 0.17523193359375 +53349 0.04644775390625 +53350 0.128753662109375 +53351 0.030364990234375 +53352 0.1019287109375 +53353 0.021820068359375 +53354 0.0743408203125 +53355 0.01373291015625 +53356 0.04327392578125 +53357 0.005035400390625 +53358 0.038177490234375 +53359 0.0057373046875 +53360 0.076263427734375 +53361 0.0216064453125 +53362 0.14105224609375 +53363 0.04681396484375 +53364 0.186431884765625 +53365 0.06536865234375 +53366 0.188812255859375 +53367 0.0689697265625 +53368 0.1390380859375 +53369 0.0543212890625 +53370 0.041778564453125 +53371 0.022918701171875 +53372 -0.079437255859375 +53373 -0.0172119140625 +53374 -0.219390869140625 +53375 -0.064361572265625 +53376 -0.367828369140625 +53377 -0.115020751953125 +53378 -0.494873046875 +53379 -0.158935546875 +53380 -0.556243896484375 +53381 -0.18084716796875 +53382 -0.508697509765625 +53383 -0.165802001953125 +53384 -0.3756103515625 +53385 -0.12176513671875 +53386 -0.218902587890625 +53387 -0.0699462890625 +53388 -0.063751220703125 +53389 -0.018890380859375 +53390 0.091552734375 +53391 0.032073974609375 +53392 0.23602294921875 +53393 0.079345703125 +53394 0.342987060546875 +53395 0.113861083984375 +53396 0.39520263671875 +53397 0.129852294921875 +53398 0.389373779296875 +53399 0.126251220703125 +53400 0.324249267578125 +53401 0.10272216796875 +53402 0.224090576171875 +53403 0.067657470703125 +53404 0.124267578125 +53405 0.03326416015625 +53406 0.037078857421875 +53407 0.003753662109375 +53408 -0.010101318359375 +53409 -0.011505126953125 +53410 -0.019439697265625 +53411 -0.013336181640625 +53412 -0.022796630859375 +53413 -0.012786865234375 +53414 -0.001556396484375 +53415 -0.0035400390625 +53416 0.056304931640625 +53417 0.018402099609375 +53418 0.106719970703125 +53419 0.037750244140625 +53420 0.096893310546875 +53421 0.036285400390625 +53422 0.042694091796875 +53423 0.01934814453125 +53424 -0.018035888671875 +53425 -0.0001220703125 +53426 -0.07586669921875 +53427 -0.018951416015625 +53428 -0.11944580078125 +53429 -0.03326416015625 +53430 -0.15972900390625 +53431 -0.046875 +53432 -0.202606201171875 +53433 -0.061798095703125 +53434 -0.24859619140625 +53435 -0.07818603515625 +53436 -0.30517578125 +53437 -0.09857177734375 +53438 -0.36212158203125 +53439 -0.119384765625 +53440 -0.39141845703125 +53441 -0.13092041015625 +53442 -0.35528564453125 +53443 -0.120086669921875 +53444 -0.249969482421875 +53445 -0.08551025390625 +53446 -0.092864990234375 +53447 -0.0330810546875 +53448 0.08905029296875 +53449 0.027984619140625 +53450 0.2352294921875 +53451 0.07696533203125 +53452 0.318817138671875 +53453 0.10467529296875 +53454 0.358642578125 +53455 0.11761474609375 +53456 0.347747802734375 +53457 0.11346435546875 +53458 0.28564453125 +53459 0.092041015625 +53460 0.223175048828125 +53461 0.070831298828125 +53462 0.196746826171875 +53463 0.062347412109375 +53464 0.179840087890625 +53465 0.057403564453125 +53466 0.155548095703125 +53467 0.0501708984375 +53468 0.151214599609375 +53469 0.049957275390625 +53470 0.156951904296875 +53471 0.05328369140625 +53472 0.13177490234375 +53473 0.04595947265625 +53474 0.100799560546875 +53475 0.03656005859375 +53476 0.087127685546875 +53477 0.032989501953125 +53478 0.05487060546875 +53479 0.0228271484375 +53480 -0.009002685546875 +53481 0.00152587890625 +53482 -0.10400390625 +53483 -0.030731201171875 +53484 -0.229400634765625 +53485 -0.07373046875 +53486 -0.35552978515625 +53487 -0.11724853515625 +53488 -0.441925048828125 +53489 -0.1473388671875 +53490 -0.473846435546875 +53491 -0.158905029296875 +53492 -0.464813232421875 +53493 -0.15655517578125 +53494 -0.419097900390625 +53495 -0.1417236328125 +53496 -0.334320068359375 +53497 -0.113525390625 +53498 -0.227935791015625 +53499 -0.07794189453125 +53500 -0.12347412109375 +53501 -0.04296875 +53502 -0.02764892578125 +53503 -0.010894775390625 +53504 0.077667236328125 +53505 0.02459716796875 +53506 0.2132568359375 +53507 0.0704345703125 +53508 0.38885498046875 +53509 0.129180908203125 +53510 0.582794189453125 +53511 0.1934814453125 +53512 0.734039306640625 +53513 0.243743896484375 +53514 0.800140380859375 +53515 0.26641845703125 +53516 0.7783203125 +53517 0.260467529296875 +53518 0.6651611328125 +53519 0.2247314453125 +53520 0.45965576171875 +53521 0.158966064453125 +53522 0.199188232421875 +53523 0.074981689453125 +53524 -0.050689697265625 +53525 -0.00653076171875 +53526 -0.23297119140625 +53527 -0.067535400390625 +53528 -0.33013916015625 +53529 -0.102264404296875 +53530 -0.368408203125 +53531 -0.11865234375 +53532 -0.378936767578125 +53533 -0.1260986328125 +53534 -0.376983642578125 +53535 -0.129150390625 +53536 -0.37969970703125 +53537 -0.132965087890625 +53538 -0.391510009765625 +53539 -0.13873291015625 +53540 -0.385345458984375 +53541 -0.137908935546875 +53542 -0.3419189453125 +53543 -0.124420166015625 +53544 -0.28289794921875 +53545 -0.105072021484375 +53546 -0.251617431640625 +53547 -0.09344482421875 +53548 -0.266143798828125 +53549 -0.095306396484375 +53550 -0.273345947265625 +53551 -0.094268798828125 +53552 -0.216796875 +53553 -0.072906494140625 +53554 -0.128265380859375 +53555 -0.04132080078125 +53556 -0.068145751953125 +53557 -0.018585205078125 +53558 -0.0430908203125 +53559 -0.006988525390625 +53560 -0.024444580078125 +53561 0.00213623046875 +53562 0.020721435546875 +53563 0.0189208984375 +53564 0.124481201171875 +53565 0.05322265625 +53566 0.25787353515625 +53567 0.095916748046875 +53568 0.379119873046875 +53569 0.133941650390625 +53570 0.47991943359375 +53571 0.16473388671875 +53572 0.5281982421875 +53573 0.1783447265625 +53574 0.511138916015625 +53575 0.170867919921875 +53576 0.456207275390625 +53577 0.1510009765625 +53578 0.407470703125 +53579 0.132659912109375 +53580 0.383758544921875 +53581 0.121917724609375 +53582 0.35687255859375 +53583 0.110137939453125 +53584 0.31182861328125 +53585 0.09283447265625 +53586 0.250885009765625 +53587 0.0709228515625 +53588 0.1654052734375 +53589 0.0418701171875 +53590 0.035247802734375 +53591 -0.00048828125 +53592 -0.142059326171875 +53593 -0.056854248046875 +53594 -0.33563232421875 +53595 -0.1175537109375 +53596 -0.5345458984375 +53597 -0.179168701171875 +53598 -0.72186279296875 +53599 -0.236480712890625 +53600 -0.836669921875 +53601 -0.27056884765625 +53602 -0.8326416015625 +53603 -0.267059326171875 +53604 -0.7296142578125 +53605 -0.2322998046875 +53606 -0.582550048828125 +53607 -0.183624267578125 +53608 -0.440093994140625 +53609 -0.1363525390625 +53610 -0.324310302734375 +53611 -0.097503662109375 +53612 -0.20147705078125 +53613 -0.05670166015625 +53614 -0.044647216796875 +53615 -0.00567626953125 +53616 0.103973388671875 +53617 0.04229736328125 +53618 0.202392578125 +53619 0.07403564453125 +53620 0.264495849609375 +53621 0.093841552734375 +53622 0.338897705078125 +53623 0.116851806640625 +53624 0.443817138671875 +53625 0.148773193359375 +53626 0.545074462890625 +53627 0.178985595703125 +53628 0.6173095703125 +53629 0.199676513671875 +53630 0.6524658203125 +53631 0.208465576171875 +53632 0.66339111328125 +53633 0.209503173828125 +53634 0.6561279296875 +53635 0.204803466796875 +53636 0.606781005859375 +53637 0.187042236328125 +53638 0.501190185546875 +53639 0.15191650390625 +53640 0.352783203125 +53641 0.10369873046875 +53642 0.176544189453125 +53643 0.047210693359375 +53644 -0.034820556640625 +53645 -0.019744873046875 +53646 -0.258209228515625 +53647 -0.08990478515625 +53648 -0.44244384765625 +53649 -0.14727783203125 +53650 -0.5753173828125 +53651 -0.188079833984375 +53652 -0.65203857421875 +53653 -0.210906982421875 +53654 -0.641632080078125 +53655 -0.206146240234375 +53656 -0.562164306640625 +53657 -0.179534912109375 +53658 -0.458038330078125 +53659 -0.145050048828125 +53660 -0.350555419921875 +53661 -0.10943603515625 +53662 -0.260528564453125 +53663 -0.07928466796875 +53664 -0.192108154296875 +53665 -0.0560302734375 +53666 -0.141937255859375 +53667 -0.038726806640625 +53668 -0.1021728515625 +53669 -0.024993896484375 +53670 -0.062896728515625 +53671 -0.011810302734375 +53672 -0.011932373046875 +53673 0.00457763671875 +53674 0.062835693359375 +53675 0.027923583984375 +53676 0.148712158203125 +53677 0.054290771484375 +53678 0.241729736328125 +53679 0.082489013671875 +53680 0.34912109375 +53681 0.11480712890625 +53682 0.457305908203125 +53683 0.1470947265625 +53684 0.54388427734375 +53685 0.172454833984375 +53686 0.5728759765625 +53687 0.17974853515625 +53688 0.506591796875 +53689 0.157318115234375 +53690 0.351226806640625 +53691 0.107208251953125 +53692 0.146514892578125 +53693 0.0418701171875 +53694 -0.05523681640625 +53695 -0.02227783203125 +53696 -0.21624755859375 +53697 -0.0733642578125 +53698 -0.334930419921875 +53699 -0.110870361328125 +53700 -0.402984619140625 +53701 -0.132171630859375 +53702 -0.4412841796875 +53703 -0.143798828125 +53704 -0.49578857421875 +53705 -0.160125732421875 +53706 -0.5601806640625 +53707 -0.179229736328125 +53708 -0.600738525390625 +53709 -0.190673828125 +53710 -0.584228515625 +53711 -0.18414306640625 +53712 -0.47930908203125 +53713 -0.149932861328125 +53714 -0.27935791015625 +53715 -0.086090087890625 +53716 -0.0089111328125 +53717 -0.000335693359375 +53718 0.268798828125 +53719 0.087493896484375 +53720 0.482818603515625 +53721 0.15521240234375 +53722 0.60369873046875 +53723 0.193603515625 +53724 0.650421142578125 +53725 0.208526611328125 +53726 0.66400146484375 +53727 0.2127685546875 +53728 0.6414794921875 +53729 0.2054443359375 +53730 0.572540283203125 +53731 0.183380126953125 +53732 0.498138427734375 +53733 0.15936279296875 +53734 0.439453125 +53735 0.14007568359375 +53736 0.375518798828125 +53737 0.1190185546875 +53738 0.274505615234375 +53739 0.086334228515625 +53740 0.1087646484375 +53741 0.033447265625 +53742 -0.099395751953125 +53743 -0.0325927734375 +53744 -0.3182373046875 +53745 -0.101806640625 +53746 -0.5489501953125 +53747 -0.174560546875 +53748 -0.7738037109375 +53749 -0.245269775390625 +53750 -0.86383056640625 +53751 -0.29736328125 +53752 -0.870391845703125 +53753 -0.320465087890625 +53754 -0.86895751953125 +53755 -0.32012939453125 +53756 -0.861053466796875 +53757 -0.300445556640625 +53758 -0.765869140625 +53759 -0.25604248046875 +53760 -0.5301513671875 +53761 -0.183563232421875 +53762 -0.214691162109375 +53763 -0.085784912109375 +53764 0.137359619140625 +53765 0.02398681640625 +53766 0.474822998046875 +53767 0.13037109375 +53768 0.76239013671875 +53769 0.2225341796875 +53770 0.867462158203125 +53771 0.292205810546875 +53772 0.870361328125 +53773 0.339019775390625 +53774 0.86480712890625 +53775 0.35943603515625 +53776 0.831817626953125 +53777 0.354827880859375 +53778 0.677581787109375 +53779 0.33209228515625 +53780 0.495880126953125 +53781 0.293060302734375 +53782 0.30767822265625 +53783 0.243255615234375 +53784 0.116180419921875 +53785 0.1837158203125 +53786 -0.110748291015625 +53787 0.106048583984375 +53788 -0.381805419921875 +53789 0.008880615234375 +53790 -0.6572265625 +53791 -0.095245361328125 +53792 -0.857421875 +53793 -0.188995361328125 +53794 -0.870391845703125 +53795 -0.2598876953125 +53796 -0.870391845703125 +53797 -0.3055419921875 +53798 -0.86444091796875 +53799 -0.33319091796875 +53800 -0.85723876953125 +53801 -0.352630615234375 +53802 -0.790008544921875 +53803 -0.358612060546875 +53804 -0.62847900390625 +53805 -0.335968017578125 +53806 -0.3956298828125 +53807 -0.283935546875 +53808 -0.126708984375 +53809 -0.211944580078125 +53810 0.150115966796875 +53811 -0.128021240234375 +53812 0.424041748046875 +53813 -0.035797119140625 +53814 0.670623779296875 +53815 0.056732177734375 +53816 0.854522705078125 +53817 0.1383056640625 +53818 0.866485595703125 +53819 0.20355224609375 +53820 0.86920166015625 +53821 0.247772216796875 +53822 0.8653564453125 +53823 0.27569580078125 +53824 0.857147216796875 +53825 0.290802001953125 +53826 0.766845703125 +53827 0.2921142578125 +53828 0.628509521484375 +53829 0.28094482421875 +53830 0.462127685546875 +53831 0.255401611328125 +53832 0.297210693359375 +53833 0.2227783203125 +53834 0.14862060546875 +53835 0.186737060546875 +53836 -0.00537109375 +53837 0.141082763671875 +53838 -0.15753173828125 +53839 0.088226318359375 +53840 -0.31304931640625 +53841 0.027496337890625 +53842 -0.48876953125 +53843 -0.044647216796875 +53844 -0.6416015625 +53845 -0.114715576171875 +53846 -0.751373291015625 +53847 -0.175445556640625 +53848 -0.84619140625 +53849 -0.233001708984375 +53850 -0.861297607421875 +53851 -0.28302001953125 +53852 -0.863250732421875 +53853 -0.316070556640625 +53854 -0.856597900390625 +53855 -0.32318115234375 +53856 -0.7498779296875 +53857 -0.307708740234375 +53858 -0.624542236328125 +53859 -0.285919189453125 +53860 -0.47808837890625 +53861 -0.251739501953125 +53862 -0.253387451171875 +53863 -0.188995361328125 +53864 0.003692626953125 +53865 -0.1107177734375 +53866 0.2257080078125 +53867 -0.03631591796875 +53868 0.427154541015625 +53869 0.037384033203125 +53870 0.643218994140625 +53871 0.119140625 +53872 0.855926513671875 +53873 0.205963134765625 +53874 0.870361328125 +53875 0.2813720703125 +53876 0.870361328125 +53877 0.33123779296875 +53878 0.862762451171875 +53879 0.357421875 +53880 0.79669189453125 +53881 0.358978271484375 +53882 0.595794677734375 +53883 0.333251953125 +53884 0.362152099609375 +53885 0.288421630859375 +53886 0.1270751953125 +53887 0.232421875 +53888 -0.086944580078125 +53889 0.171295166015625 +53890 -0.2784423828125 +53891 0.1058349609375 +53892 -0.484832763671875 +53893 0.026519775390625 +53894 -0.729583740234375 +53895 -0.07171630859375 +53896 -0.86688232421875 +53897 -0.174468994140625 +53898 -0.870391845703125 +53899 -0.263763427734375 +53900 -0.86859130859375 +53901 -0.33795166015625 +53902 -0.86279296875 +53903 -0.396209716796875 +53904 -0.817962646484375 +53905 -0.428314208984375 +53906 -0.6116943359375 +53907 -0.42144775390625 +53908 -0.3128662109375 +53909 -0.37353515625 +53910 0.039398193359375 +53911 -0.294036865234375 +53912 0.422821044921875 +53913 -0.1885986328125 +53914 0.805145263671875 +53915 -0.066650390625 +53916 0.870361328125 +53917 0.052520751953125 +53918 0.870361328125 +53919 0.152740478515625 +53920 0.860015869140625 +53921 0.23046875 +53922 0.727935791015625 +53923 0.2833251953125 +53924 0.48114013671875 +53925 0.3094482421875 +53926 0.2059326171875 +53927 0.315338134765625 +53928 -0.06103515625 +53929 0.307098388671875 +53930 -0.29913330078125 +53931 0.287384033203125 +53932 -0.516204833984375 +53933 0.251983642578125 +53934 -0.7252197265625 +53935 0.196502685546875 +53936 -0.85980224609375 +53937 0.1279296875 +53938 -0.870391845703125 +53939 0.055938720703125 +53940 -0.870391845703125 +53941 -0.011016845703125 +53942 -0.858062744140625 +53943 -0.05908203125 +53944 -0.673004150390625 +53945 -0.086822509765625 +53946 -0.42694091796875 +53947 -0.108642578125 +53948 -0.2100830078125 +53949 -0.136627197265625 +53950 -0.0362548828125 +53951 -0.16986083984375 +53952 0.10943603515625 +53953 -0.19989013671875 +53954 0.23516845703125 +53955 -0.220855712890625 +53956 0.373687744140625 +53957 -0.220977783203125 +53958 0.517791748046875 +53959 -0.20062255859375 +53960 0.602783203125 +53961 -0.1773681640625 +53962 0.635711669921875 +53963 -0.1497802734375 +53964 0.655181884765625 +53965 -0.10858154296875 +53966 0.65948486328125 +53967 -0.05670166015625 +53968 0.651275634765625 +53969 0.00335693359375 +53970 0.61846923828125 +53971 0.064483642578125 +53972 0.53753662109375 +53973 0.115997314453125 +53974 0.404144287109375 +53975 0.152557373046875 +53976 0.22186279296875 +53977 0.171142578125 +53978 0.003997802734375 +53979 0.171844482421875 +53980 -0.22100830078125 +53981 0.15948486328125 +53982 -0.42449951171875 +53983 0.139617919921875 +53984 -0.579833984375 +53985 0.118072509765625 +53986 -0.641876220703125 +53987 0.106719970703125 +53988 -0.6177978515625 +53989 0.103668212890625 +53990 -0.575531005859375 +53991 0.090911865234375 +53992 -0.526336669921875 +53993 0.067047119140625 +53994 -0.42645263671875 +53995 0.046783447265625 +53996 -0.2581787109375 +53997 0.0379638671875 +53998 -0.068695068359375 +53999 0.030670166015625 +54000 0.09222412109375 +54001 0.014373779296875 +54002 0.232147216796875 +54003 -0.00537109375 +54004 0.3509521484375 +54005 -0.025482177734375 +54006 0.410064697265625 +54007 -0.053985595703125 +54008 0.372955322265625 +54009 -0.098907470703125 +54010 0.2554931640625 +54011 -0.154205322265625 +54012 0.10711669921875 +54013 -0.205169677734375 +54014 -0.052886962890625 +54015 -0.24627685546875 +54016 -0.186279296875 +54017 -0.267791748046875 +54018 -0.23291015625 +54019 -0.254608154296875 +54020 -0.209442138671875 +54021 -0.21234130859375 +54022 -0.174163818359375 +54023 -0.158355712890625 +54024 -0.126739501953125 +54025 -0.09564208984375 +54026 -0.048126220703125 +54027 -0.022705078125 +54028 0.0426025390625 +54029 0.052490234375 +54030 0.10748291015625 +54031 0.117431640625 +54032 0.1409912109375 +54033 0.1680908203125 +54034 0.19708251953125 +54035 0.215789794921875 +54036 0.273651123046875 +54037 0.25836181640625 +54038 0.31768798828125 +54039 0.281585693359375 +54040 0.341094970703125 +54041 0.288116455078125 +54042 0.368011474609375 +54043 0.284332275390625 +54044 0.37249755859375 +54045 0.2646484375 +54046 0.30072021484375 +54047 0.217041015625 +54048 0.1517333984375 +54049 0.1431884765625 +54050 -0.01470947265625 +54051 0.06024169921875 +54052 -0.1883544921875 +54053 -0.02679443359375 +54054 -0.372711181640625 +54055 -0.116363525390625 +54056 -0.51397705078125 +54057 -0.192626953125 +54058 -0.57177734375 +54059 -0.243316650390625 +54060 -0.53948974609375 +54061 -0.264923095703125 +54062 -0.43511962890625 +54063 -0.26055908203125 +54064 -0.2962646484375 +54065 -0.2386474609375 +54066 -0.161102294921875 +54067 -0.208282470703125 +54068 -0.0435791015625 +54069 -0.17303466796875 +54070 0.060394287109375 +54071 -0.132476806640625 +54072 0.13665771484375 +54073 -0.0911865234375 +54074 0.170135498046875 +54075 -0.054351806640625 +54076 0.16552734375 +54077 -0.02252197265625 +54078 0.15728759765625 +54079 0.01092529296875 +54080 0.150787353515625 +54081 0.04534912109375 +54082 0.12200927734375 +54083 0.07275390625 +54084 0.080108642578125 +54085 0.093597412109375 +54086 0.05126953125 +54087 0.11279296875 +54088 0.062896728515625 +54089 0.135894775390625 +54090 0.09271240234375 +54091 0.156402587890625 +54092 0.092987060546875 +54093 0.161895751953125 +54094 0.07855224609375 +54095 0.156005859375 +54096 0.06427001953125 +54097 0.142791748046875 +54098 0.0347900390625 +54099 0.119110107421875 +54100 -0.01171875 +54101 0.085601806640625 +54102 -0.056060791015625 +54103 0.048431396484375 +54104 -0.055511474609375 +54105 0.01983642578125 +54106 -0.010467529296875 +54107 0.0013427734375 +54108 0.02508544921875 +54109 -0.01885986328125 +54110 0.025665283203125 +54111 -0.045562744140625 +54112 0.017333984375 +54113 -0.07086181640625 +54114 0.00189208984375 +54115 -0.0931396484375 +54116 -0.03173828125 +54117 -0.114288330078125 +54118 -0.071502685546875 +54119 -0.13079833984375 +54120 -0.13543701171875 +54121 -0.14697265625 +54122 -0.219970703125 +54123 -0.162109375 +54124 -0.300506591796875 +54125 -0.1705322265625 +54126 -0.376312255859375 +54127 -0.1728515625 +54128 -0.416107177734375 +54129 -0.162322998046875 +54130 -0.371124267578125 +54131 -0.12799072265625 +54132 -0.242279052734375 +54133 -0.0714111328125 +54134 -0.069732666015625 +54135 -0.003997802734375 +54136 0.125640869140625 +54137 0.06768798828125 +54138 0.31268310546875 +54139 0.1346435546875 +54140 0.45501708984375 +54141 0.186737060546875 +54142 0.554779052734375 +54143 0.223724365234375 +54144 0.61065673828125 +54145 0.2447509765625 +54146 0.610931396484375 +54147 0.246673583984375 +54148 0.531463623046875 +54149 0.2235107421875 +54150 0.3883056640625 +54151 0.1795654296875 +54152 0.23468017578125 +54153 0.128753662109375 +54154 0.095245361328125 +54155 0.07806396484375 +54156 -0.00396728515625 +54157 0.034942626953125 +54158 -0.04852294921875 +54159 0.0040283203125 +54160 -0.055145263671875 +54161 -0.0177001953125 +54162 -0.0758056640625 +54163 -0.042144775390625 +54164 -0.138702392578125 +54165 -0.0753173828125 +54166 -0.209197998046875 +54167 -0.107635498046875 +54168 -0.289031982421875 +54169 -0.138824462890625 +54170 -0.37884521484375 +54171 -0.16851806640625 +54172 -0.456329345703125 +54173 -0.190887451171875 +54174 -0.51641845703125 +54175 -0.204620361328125 +54176 -0.519287109375 +54177 -0.199951171875 +54178 -0.458251953125 +54179 -0.17559814453125 +54180 -0.384796142578125 +54181 -0.145050048828125 +54182 -0.323699951171875 +54183 -0.115234375 +54184 -0.269287109375 +54185 -0.085601806640625 +54186 -0.1951904296875 +54187 -0.050506591796875 +54188 -0.100006103515625 +54189 -0.010498046875 +54190 -0.01055908203125 +54191 0.02679443359375 +54192 0.1033935546875 +54193 0.06817626953125 +54194 0.24908447265625 +54195 0.11480712890625 +54196 0.373199462890625 +54197 0.15289306640625 +54198 0.45806884765625 +54199 0.177734375 +54200 0.511474609375 +54201 0.191131591796875 +54202 0.565399169921875 +54203 0.201202392578125 +54204 0.61138916015625 +54205 0.20611572265625 +54206 0.5897216796875 +54207 0.19140625 +54208 0.4906005859375 +54209 0.15521240234375 +54210 0.33148193359375 +54211 0.102569580078125 +54212 0.147796630859375 +54213 0.043060302734375 +54214 -0.01873779296875 +54215 -0.0120849609375 +54216 -0.140289306640625 +54217 -0.05517578125 +54218 -0.191986083984375 +54219 -0.079315185546875 +54220 -0.184295654296875 +54221 -0.086578369140625 +54222 -0.161834716796875 +54223 -0.087677001953125 +54224 -0.166595458984375 +54225 -0.0927734375 +54226 -0.19390869140625 +54227 -0.1005859375 +54228 -0.22442626953125 +54229 -0.1063232421875 +54230 -0.279754638671875 +54231 -0.115570068359375 +54232 -0.3389892578125 +54233 -0.1234130859375 +54234 -0.3543701171875 +54235 -0.118377685546875 +54236 -0.348175048828125 +54237 -0.1065673828125 +54238 -0.32598876953125 +54239 -0.0899658203125 +54240 -0.2581787109375 +54241 -0.061798095703125 +54242 -0.139801025390625 +54243 -0.02142333984375 +54244 0.014617919921875 +54245 0.02691650390625 +54246 0.144378662109375 +54247 0.067535400390625 +54248 0.221038818359375 +54249 0.092926025390625 +54250 0.27069091796875 +54251 0.10931396484375 +54252 0.294036865234375 +54253 0.11676025390625 +54254 0.311767578125 +54255 0.12042236328125 +54256 0.339141845703125 +54257 0.12420654296875 +54258 0.360260009765625 +54259 0.12432861328125 +54260 0.360504150390625 +54261 0.11749267578125 +54262 0.308380126953125 +54263 0.0963134765625 +54264 0.18170166015625 +54265 0.0557861328125 +54266 0.0047607421875 +54267 0.00250244140625 +54268 -0.17559814453125 +54269 -0.0513916015625 +54270 -0.3143310546875 +54271 -0.09423828125 +54272 -0.36785888671875 +54273 -0.11517333984375 +54274 -0.36248779296875 +54275 -0.119964599609375 +54276 -0.343536376953125 +54277 -0.11895751953125 +54278 -0.3018798828125 +54279 -0.110321044921875 +54280 -0.231414794921875 +54281 -0.092926025390625 +54282 -0.117645263671875 +54283 -0.063934326171875 +54284 0.007049560546875 +54285 -0.030731201171875 +54286 0.087982177734375 +54287 -0.005523681640625 +54288 0.13946533203125 +54289 0.0142822265625 +54290 0.17425537109375 +54291 0.03094482421875 +54292 0.188201904296875 +54293 0.0430908203125 +54294 0.171234130859375 +54295 0.048065185546875 +54296 0.118438720703125 +54297 0.04437255859375 +54298 0.05706787109375 +54299 0.037567138671875 +54300 -0.010711669921875 +54301 0.02777099609375 +54302 -0.0914306640625 +54303 0.01336669921875 +54304 -0.162322998046875 +54305 -0.00079345703125 +54306 -0.194549560546875 +54307 -0.008514404296875 +54308 -0.1492919921875 +54309 -0.00128173828125 +54310 -0.02166748046875 +54311 0.022125244140625 +54312 0.124053955078125 +54313 0.048095703125 +54314 0.211151123046875 +54315 0.06036376953125 +54316 0.240447998046875 +54317 0.059539794921875 +54318 0.242218017578125 +54319 0.05255126953125 +54320 0.2257080078125 +54321 0.04180908203125 +54322 0.194366455078125 +54323 0.0284423828125 +54324 0.115509033203125 +54325 0.0057373046875 +54326 0.0128173828125 +54327 -0.020843505859375 +54328 -0.053802490234375 +54329 -0.038177490234375 +54330 -0.110626220703125 +54331 -0.05181884765625 +54332 -0.199493408203125 +54333 -0.070770263671875 +54334 -0.29437255859375 +54335 -0.089508056640625 +54336 -0.33221435546875 +54337 -0.09454345703125 +54338 -0.27972412109375 +54339 -0.07891845703125 +54340 -0.185333251953125 +54341 -0.053314208984375 +54342 -0.128204345703125 +54343 -0.03515625 +54344 -0.115692138671875 +54345 -0.0263671875 +54346 -0.116455078125 +54347 -0.0205078125 +54348 -0.105926513671875 +54349 -0.01263427734375 +54350 -0.053955078125 +54351 0.003448486328125 +54352 0.048797607421875 +54353 0.029541015625 +54354 0.157318115234375 +54355 0.05572509765625 +54356 0.212005615234375 +54357 0.069000244140625 +54358 0.218475341796875 +54359 0.070556640625 +54360 0.23724365234375 +54361 0.073516845703125 +54362 0.30535888671875 +54363 0.085968017578125 +54364 0.38128662109375 +54365 0.09906005859375 +54366 0.404449462890625 +54367 0.09991455078125 +54368 0.3944091796875 +54369 0.093017578125 +54370 0.3885498046875 +54371 0.086700439453125 +54372 0.362640380859375 +54373 0.0760498046875 +54374 0.27362060546875 +54375 0.052032470703125 +54376 0.11712646484375 +54377 0.01397705078125 +54378 -0.054901123046875 +54379 -0.026641845703125 +54380 -0.19085693359375 +54381 -0.05853271484375 +54382 -0.28570556640625 +54383 -0.08050537109375 +54384 -0.339263916015625 +54385 -0.092437744140625 +54386 -0.3775634765625 +54387 -0.100006103515625 +54388 -0.445709228515625 +54389 -0.113006591796875 +54390 -0.535064697265625 +54391 -0.12969970703125 +54392 -0.629058837890625 +54393 -0.14666748046875 +54394 -0.697601318359375 +54395 -0.1575927734375 +54396 -0.70391845703125 +54397 -0.15478515625 +54398 -0.6424560546875 +54399 -0.13726806640625 +54400 -0.491241455078125 +54401 -0.100555419921875 +54402 -0.265716552734375 +54403 -0.0482177734375 +54404 -0.023712158203125 +54405 0.007049560546875 +54406 0.201751708984375 +54407 0.058013916015625 +54408 0.375823974609375 +54409 0.097015380859375 +54410 0.485076904296875 +54411 0.12109375 +54412 0.56884765625 +54413 0.138763427734375 +54414 0.634765625 +54415 0.151702880859375 +54416 0.63763427734375 +54417 0.1502685546875 +54418 0.5660400390625 +54419 0.132110595703125 +54420 0.4720458984375 +54421 0.108642578125 +54422 0.40692138671875 +54423 0.091156005859375 +54424 0.3778076171875 +54425 0.08135986328125 +54426 0.376953125 +54427 0.0777587890625 +54428 0.371978759765625 +54429 0.07354736328125 +54430 0.313140869140625 +54431 0.05816650390625 +54432 0.184417724609375 +54433 0.028289794921875 +54434 0.011199951171875 +54435 -0.010498046875 +54436 -0.171051025390625 +54437 -0.050445556640625 +54438 -0.33740234375 +54439 -0.086181640625 +54440 -0.47198486328125 +54441 -0.114288330078125 +54442 -0.560394287109375 +54443 -0.131744384765625 +54444 -0.58056640625 +54445 -0.133880615234375 +54446 -0.54754638671875 +54447 -0.124114990234375 +54448 -0.508575439453125 +54449 -0.112823486328125 +54450 -0.459503173828125 +54451 -0.099273681640625 +54452 -0.394378662109375 +54453 -0.08233642578125 +54454 -0.35260009765625 +54455 -0.07061767578125 +54456 -0.31170654296875 +54457 -0.0594482421875 +54458 -0.197418212890625 +54459 -0.03289794921875 +54460 -0.007965087890625 +54461 0.009307861328125 +54462 0.207489013671875 +54463 0.05645751953125 +54464 0.409210205078125 +54465 0.0999755859375 +54466 0.57208251953125 +54467 0.134490966796875 +54468 0.66595458984375 +54469 0.153533935546875 +54470 0.65875244140625 +54471 0.150238037109375 +54472 0.56744384765625 +54473 0.12841796875 +54474 0.431396484375 +54475 0.0966796875 +54476 0.29443359375 +54477 0.064605712890625 +54478 0.182464599609375 +54479 0.037933349609375 +54480 0.06365966796875 +54481 0.009918212890625 +54482 -0.075958251953125 +54483 -0.02227783203125 +54484 -0.189422607421875 +54485 -0.048431396484375 +54486 -0.271942138671875 +54487 -0.0673828125 +54488 -0.342529296875 +54489 -0.083221435546875 +54490 -0.364166259765625 +54491 -0.08795166015625 +54492 -0.327239990234375 +54493 -0.079498291015625 +54494 -0.2769775390625 +54495 -0.06768798828125 +54496 -0.253692626953125 +54497 -0.061279296875 +54498 -0.24365234375 +54499 -0.057373046875 +54500 -0.1983642578125 +54501 -0.045654296875 +54502 -0.116241455078125 +54503 -0.025848388671875 +54504 -0.036834716796875 +54505 -0.006622314453125 +54506 0.034881591796875 +54507 0.01080322265625 +54508 0.09124755859375 +54509 0.024688720703125 +54510 0.10888671875 +54511 0.029876708984375 +54512 0.125518798828125 +54513 0.03448486328125 +54514 0.15771484375 +54515 0.042022705078125 +54516 0.17828369140625 +54517 0.046600341796875 +54518 0.17108154296875 +54519 0.04473876953125 +54520 0.129974365234375 +54521 0.035125732421875 +54522 0.082427978515625 +54523 0.02374267578125 +54524 0.027679443359375 +54525 0.010498046875 +54526 -0.065643310546875 +54527 -0.01123046875 +54528 -0.15936279296875 +54529 -0.033477783203125 +54530 -0.21307373046875 +54531 -0.047027587890625 +54532 -0.234649658203125 +54533 -0.0528564453125 +54534 -0.2001953125 +54535 -0.046875 +54536 -0.119171142578125 +54537 -0.03118896484375 +54538 -0.024749755859375 +54539 -0.01220703125 +54540 0.085784912109375 +54541 0.01025390625 +54542 0.178131103515625 +54543 0.029571533203125 +54544 0.215576171875 +54545 0.038818359375 +54546 0.211456298828125 +54547 0.040252685546875 +54548 0.17523193359375 +54549 0.0355224609375 +54550 0.128753662109375 +54551 0.028533935546875 +54552 0.1019287109375 +54553 0.02471923828125 +54554 0.0743408203125 +54555 0.020294189453125 +54556 0.04327392578125 +54557 0.0147705078125 +54558 0.038177490234375 +54559 0.0135498046875 +54560 0.076263427734375 +54561 0.019866943359375 +54562 0.14105224609375 +54563 0.030731201171875 +54564 0.186431884765625 +54565 0.03778076171875 +54566 0.188812255859375 +54567 0.0367431640625 +54568 0.1390380859375 +54569 0.026031494140625 +54570 0.041778564453125 +54571 0.006622314453125 +54572 -0.079437255859375 +54573 -0.017059326171875 +54574 -0.219390869140625 +54575 -0.04400634765625 +54576 -0.367828369140625 +54577 -0.072235107421875 +54578 -0.494873046875 +54579 -0.09619140625 +54580 -0.556243896484375 +54581 -0.10772705078125 +54582 -0.508697509765625 +54583 -0.098876953125 +54584 -0.3756103515625 +54585 -0.073974609375 +54586 -0.218902587890625 +54587 -0.044464111328125 +54588 -0.063751220703125 +54589 -0.0150146484375 +54590 0.091552734375 +54591 0.01458740234375 +54592 0.23602294921875 +54593 0.042236328125 +54594 0.342987060546875 +54595 0.06298828125 +54596 0.39520263671875 +54597 0.07366943359375 +54598 0.389373779296875 +54599 0.073577880859375 +54600 0.324249267578125 +54601 0.06243896484375 +54602 0.224090576171875 +54603 0.044708251953125 +54604 0.124267578125 +54605 0.026824951171875 +54606 0.037078857421875 +54607 0.01104736328125 +54608 -0.010101318359375 +54609 0.00238037109375 +54610 -0.019439697265625 +54611 0.000457763671875 +54612 -0.022796630859375 +54613 -0.00054931640625 +54614 -0.001556396484375 +54615 0.002777099609375 +54616 0.056304931640625 +54617 0.012664794921875 +54618 0.106719970703125 +54619 0.02105712890625 +54620 0.096893310546875 +54621 0.018310546875 +54622 0.042694091796875 +54623 0.007415771484375 +54624 -0.018035888671875 +54625 -0.004608154296875 +54626 -0.07586669921875 +54627 -0.015960693359375 +54628 -0.11944580078125 +54629 -0.024505615234375 +54630 -0.15972900390625 +54631 -0.032257080078125 +54632 -0.202606201171875 +54633 -0.040283203125 +54634 -0.24859619140625 +54635 -0.048675537109375 +54636 -0.30517578125 +54637 -0.058807373046875 +54638 -0.36212158203125 +54639 -0.06884765625 +54640 -0.39141845703125 +54641 -0.07366943359375 +54642 -0.35528564453125 +54643 -0.06634521484375 +54644 -0.249969482421875 +54645 -0.046234130859375 +54646 -0.092864990234375 +54647 -0.016571044921875 +54648 0.08905029296875 +54649 0.017578125 +54650 0.2352294921875 +54651 0.045074462890625 +54652 0.318817138671875 +54653 0.060943603515625 +54654 0.358642578125 +54655 0.068603515625 +54656 0.347747802734375 +54657 0.0667724609375 +54658 0.28564453125 +54659 0.05535888671875 +54660 0.223175048828125 +54661 0.043731689453125 +54662 0.196746826171875 +54663 0.038604736328125 +54664 0.179840087890625 +54665 0.035125732421875 +54666 0.155548095703125 +54667 0.030181884765625 +54668 0.151214599609375 +54669 0.028839111328125 +54670 0.156951904296875 +54671 0.029327392578125 +54672 0.13177490234375 +54673 0.02410888671875 +54674 0.100799560546875 +54675 0.017852783203125 +54676 0.087127685546875 +54677 0.01483154296875 +54678 0.05487060546875 +54679 0.00848388671875 +54680 -0.009002685546875 +54681 -0.003570556640625 +54682 -0.10400390625 +54683 -0.02117919921875 +54684 -0.229400634765625 +54685 -0.04425048828125 +54686 -0.35552978515625 +54687 -0.06732177734375 +54688 -0.441925048828125 +54689 -0.08294677734375 +54690 -0.473846435546875 +54691 -0.08843994140625 +54692 -0.464813232421875 +54693 -0.0863037109375 +54694 -0.419097900390625 +54695 -0.077362060546875 +54696 -0.334320068359375 +54697 -0.06121826171875 +54698 -0.227935791015625 +54699 -0.041107177734375 +54700 -0.12347412109375 +54701 -0.021392822265625 +54702 -0.02764892578125 +54703 -0.003326416015625 +54704 0.077667236328125 +54705 0.016387939453125 +54706 0.2132568359375 +54707 0.04156494140625 +54708 0.38885498046875 +54709 0.073944091796875 +54710 0.582794189453125 +54711 0.10955810546875 +54712 0.734039306640625 +54713 0.13720703125 +54714 0.800140380859375 +54715 0.1490478515625 +54716 0.7783203125 +54717 0.144622802734375 +54718 0.6651611328125 +54719 0.123291015625 +54720 0.45965576171875 +54721 0.084930419921875 +54722 0.199188232421875 +54723 0.0364990234375 +54724 -0.050689697265625 +54725 -0.009918212890625 +54726 -0.23297119140625 +54727 -0.0438232421875 +54728 -0.33013916015625 +54729 -0.06195068359375 +54730 -0.368408203125 +54731 -0.06915283203125 +54732 -0.378936767578125 +54733 -0.0711669921875 +54734 -0.376983642578125 +54735 -0.07080078125 +54736 -0.37969970703125 +54737 -0.07122802734375 +54738 -0.391510009765625 +54739 -0.073211669921875 +54740 -0.385345458984375 +54741 -0.071807861328125 +54742 -0.3419189453125 +54743 -0.0634765625 +54744 -0.28289794921875 +54745 -0.052215576171875 +54746 -0.251617431640625 +54747 -0.0460205078125 +54748 -0.266143798828125 +54749 -0.048248291015625 +54750 -0.273345947265625 +54751 -0.04913330078125 +54752 -0.216796875 +54753 -0.038360595703125 +54754 -0.128265380859375 +54755 -0.021759033203125 +54756 -0.068145751953125 +54757 -0.01043701171875 +54758 -0.0430908203125 +54759 -0.005645751953125 +54760 -0.024444580078125 +54761 -0.00213623046875 +54762 0.020721435546875 +54763 0.006103515625 +54764 0.124481201171875 +54765 0.024993896484375 +54766 0.25787353515625 +54767 0.049224853515625 +54768 0.379119873046875 +54769 0.071136474609375 +54770 0.47991943359375 +54771 0.0892333984375 +54772 0.5281982421875 +54773 0.097625732421875 +54774 0.511138916015625 +54775 0.093994140625 +54776 0.456207275390625 +54777 0.083404541015625 +54778 0.407470703125 +54779 0.074005126953125 +54780 0.383758544921875 +54781 0.06927490234375 +54782 0.35687255859375 +54783 0.06402587890625 +54784 0.31182861328125 +54785 0.05499267578125 +54786 0.250885009765625 +54787 0.042327880859375 +54788 0.1654052734375 +54789 0.02508544921875 +54790 0.035247802734375 +54791 0.000701904296875 +54792 -0.142059326171875 +54793 -0.030731201171875 +54794 -0.33563232421875 +54795 -0.064117431640625 +54796 -0.5345458984375 +54797 -0.097503662109375 +54798 -0.72186279296875 +54799 -0.128082275390625 +54800 -0.836669921875 +54801 -0.146484375 +54802 -0.8326416015625 +54803 -0.145599365234375 +54804 -0.7296142578125 +54805 -0.1285400390625 +54806 -0.582550048828125 +54807 -0.103790283203125 +54808 -0.440093994140625 +54809 -0.078857421875 +54810 -0.324310302734375 +54811 -0.057342529296875 +54812 -0.20147705078125 +54813 -0.034332275390625 +54814 -0.044647216796875 +54815 -0.0059814453125 +54816 0.103973388671875 +54817 0.02099609375 +54818 0.202392578125 +54819 0.03997802734375 +54820 0.264495849609375 +54821 0.052825927734375 +54822 0.338897705078125 +54823 0.066741943359375 +54824 0.443817138671875 +54825 0.084381103515625 +54826 0.545074462890625 +54827 0.100494384765625 +54828 0.6173095703125 +54829 0.1112060546875 +54830 0.6524658203125 +54831 0.1153564453125 +54832 0.66339111328125 +54833 0.114959716796875 +54834 0.6561279296875 +54835 0.111053466796875 +54836 0.606781005859375 +54837 0.10015869140625 +54838 0.501190185546875 +54839 0.080352783203125 +54840 0.352783203125 +54841 0.053924560546875 +54842 0.176544189453125 +54843 0.023345947265625 +54844 -0.034820556640625 +54845 -0.01226806640625 +54846 -0.258209228515625 +54847 -0.0491943359375 +54848 -0.44244384765625 +54849 -0.079498291015625 +54850 -0.5753173828125 +54851 -0.101226806640625 +54852 -0.65203857421875 +54853 -0.11358642578125 +54854 -0.641632080078125 +54855 -0.11187744140625 +54856 -0.562164306640625 +54857 -0.098907470703125 +54858 -0.458038330078125 +54859 -0.08148193359375 +54860 -0.350555419921875 +54861 -0.062896728515625 +54862 -0.260528564453125 +54863 -0.046478271484375 +54864 -0.192108154296875 +54865 -0.03302001953125 +54866 -0.141937255859375 +54867 -0.022186279296875 +54868 -0.1021728515625 +54869 -0.012969970703125 +54870 -0.062896728515625 +54871 -0.0040283203125 +54872 -0.011932373046875 +54873 0.00628662109375 +54874 0.062835693359375 +54875 0.01971435546875 +54876 0.148712158203125 +54877 0.03424072265625 +54878 0.241729736328125 +54879 0.0491943359375 +54880 0.34912109375 +54881 0.065643310546875 +54882 0.457305908203125 +54883 0.081512451171875 +54884 0.54388427734375 +54885 0.093475341796875 +54886 0.5728759765625 +54887 0.09613037109375 +54888 0.506591796875 +54889 0.0838623046875 +54890 0.351226806640625 +54891 0.0577392578125 +54892 0.146514892578125 +54893 0.02392578125 +54894 -0.05523681640625 +54895 -0.009429931640625 +54896 -0.21624755859375 +54897 -0.036407470703125 +54898 -0.334930419921875 +54899 -0.056640625 +54900 -0.402984619140625 +54901 -0.068756103515625 +54902 -0.4412841796875 +54903 -0.07586669921875 +54904 -0.49578857421875 +54905 -0.08489990234375 +54906 -0.5601806640625 +54907 -0.0948486328125 +54908 -0.600738525390625 +54909 -0.100616455078125 +54910 -0.584228515625 +54911 -0.097198486328125 +54912 -0.47930908203125 +54913 -0.07989501953125 +54914 -0.27935791015625 +54915 -0.04779052734375 +54916 -0.0089111328125 +54917 -0.004730224609375 +54918 0.268798828125 +54919 0.039581298828125 +54920 0.482818603515625 +54921 0.074188232421875 +54922 0.60369873046875 +54923 0.09454345703125 +54924 0.650421142578125 +54925 0.1033935546875 +54926 0.66400146484375 +54927 0.10687255859375 +54928 0.6414794921875 +54929 0.1044921875 +54930 0.572540283203125 +54931 0.094635009765625 +54932 0.498138427734375 +54933 0.083526611328125 +54934 0.439453125 +54935 0.074371337890625 +54936 0.375518798828125 +54937 0.06402587890625 +54938 0.274505615234375 +54939 0.04766845703125 +54940 0.1087646484375 +54941 0.02117919921875 +54942 -0.099395751953125 +54943 -0.011932373046875 +54944 -0.3182373046875 +54945 -0.0467529296875 +54946 -0.5489501953125 +54947 -0.083404541015625 +54948 -0.7738037109375 +54949 -0.11907958984375 +54950 -0.86383056640625 +54951 -0.1456298828125 +54952 -0.870391845703125 +54953 -0.157958984375 +54954 -0.86895751953125 +54955 -0.158721923828125 +54956 -0.861053466796875 +54957 -0.14990234375 +54958 -0.765869140625 +54959 -0.12884521484375 +54960 -0.5301513671875 +54961 -0.09381103515625 +54962 -0.214691162109375 +54963 -0.0458984375 +54964 0.137359619140625 +54965 0.008270263671875 +54966 0.474822998046875 +54967 0.060882568359375 +54968 0.76239013671875 +54969 0.10650634765625 +54970 0.867462158203125 +54971 0.140960693359375 +54972 0.870361328125 +54973 0.16424560546875 +54974 0.86480712890625 +54975 0.17449951171875 +54976 0.831817626953125 +54977 0.1724853515625 +54978 0.677581787109375 +54979 0.161865234375 +54980 0.495880126953125 +54981 0.14349365234375 +54982 0.30767822265625 +54983 0.12017822265625 +54984 0.116180419921875 +54985 0.092193603515625 +54986 -0.110748291015625 +54987 0.05474853515625 +54988 -0.381805419921875 +54989 0.006805419921875 +54990 -0.6572265625 +54991 -0.04510498046875 +54992 -0.857421875 +54993 -0.09185791015625 +54994 -0.870391845703125 +54995 -0.12689208984375 +54996 -0.870391845703125 +54997 -0.149078369140625 +54998 -0.86444091796875 +54999 -0.162445068359375 +55000 -0.85723876953125 +55001 -0.172393798828125 +55002 -0.790008544921875 +55003 -0.17608642578125 +55004 -0.62847900390625 +55005 -0.165252685546875 +55006 -0.3956298828125 +55007 -0.139373779296875 +55008 -0.126708984375 +55009 -0.1033935546875 +55010 0.150115966796875 +55011 -0.061431884765625 +55012 0.424041748046875 +55013 -0.015289306640625 +55014 0.670623779296875 +55015 0.0308837890625 +55016 0.854522705078125 +55017 0.07122802734375 +55018 0.866485595703125 +55019 0.10302734375 +55020 0.86920166015625 +55021 0.1239013671875 +55022 0.8653564453125 +55023 0.1365966796875 +55024 0.857147216796875 +55025 0.143157958984375 +55026 0.766845703125 +55027 0.14306640625 +55028 0.628509521484375 +55029 0.1370849609375 +55030 0.462127685546875 +55031 0.1241455078125 +55032 0.297210693359375 +55033 0.108123779296875 +55034 0.14862060546875 +55035 0.09088134765625 +55036 -0.00537109375 +55037 0.06890869140625 +55038 -0.15753173828125 +55039 0.043365478515625 +55040 -0.31304931640625 +55041 0.01416015625 +55042 -0.48876953125 +55043 -0.020721435546875 +55044 -0.6416015625 +55045 -0.05548095703125 +55046 -0.751373291015625 +55047 -0.08636474609375 +55048 -0.84619140625 +55049 -0.115478515625 +55050 -0.861297607421875 +55051 -0.1405029296875 +55052 -0.863250732421875 +55053 -0.1571044921875 +55054 -0.856597900390625 +55055 -0.161224365234375 +55056 -0.7498779296875 +55057 -0.15423583984375 +55058 -0.624542236328125 +55059 -0.143096923828125 +55060 -0.47808837890625 +55061 -0.125396728515625 +55062 -0.253387451171875 +55063 -0.094390869140625 +55064 0.003692626953125 +55065 -0.05596923828125 +55066 0.2257080078125 +55067 -0.018768310546875 +55068 0.427154541015625 +55069 0.01824951171875 +55070 0.643218994140625 +55071 0.058502197265625 +55072 0.855926513671875 +55073 0.100433349609375 +55074 0.870361328125 +55075 0.13665771484375 +55076 0.870361328125 +55077 0.16094970703125 +55078 0.862762451171875 +55079 0.1739501953125 +55080 0.79669189453125 +55081 0.17523193359375 +55082 0.595794677734375 +55083 0.16363525390625 +55084 0.362152099609375 +55085 0.1427001953125 +55086 0.1270751953125 +55087 0.115997314453125 +55088 -0.086944580078125 +55089 0.0863037109375 +55090 -0.2784423828125 +55091 0.05413818359375 +55092 -0.484832763671875 +55093 0.01568603515625 +55094 -0.729583740234375 +55095 -0.030975341796875 +55096 -0.86688232421875 +55097 -0.07940673828125 +55098 -0.870391845703125 +55099 -0.121673583984375 +55100 -0.86859130859375 +55101 -0.156829833984375 +55102 -0.86279296875 +55103 -0.18438720703125 +55104 -0.817962646484375 +55105 -0.199859619140625 +55106 -0.6116943359375 +55107 -0.197662353515625 +55108 -0.3128662109375 +55109 -0.176910400390625 +55110 0.039398193359375 +55111 -0.141693115234375 +55112 0.422821044921875 +55113 -0.09454345703125 +55114 0.805145263671875 +55115 -0.03961181640625 +55116 0.870361328125 +55117 0.014617919921875 +55118 0.870361328125 +55119 0.061065673828125 +55120 0.860015869140625 +55121 0.0980224609375 +55122 0.727935791015625 +55123 0.124267578125 +55124 0.48114013671875 +55125 0.1387939453125 +55126 0.2059326171875 +55127 0.144195556640625 +55128 -0.06103515625 +55129 0.142974853515625 +55130 -0.29913330078125 +55131 0.136138916015625 +55132 -0.516204833984375 +55133 0.121856689453125 +55134 -0.7252197265625 +55135 0.098236083984375 +55136 -0.85980224609375 +55137 0.0682373046875 +55138 -0.870391845703125 +55139 0.03607177734375 +55140 -0.870391845703125 +55141 0.005401611328125 +55142 -0.858062744140625 +55143 -0.01763916015625 +55144 -0.673004150390625 +55145 -0.03228759765625 +55146 -0.42694091796875 +55147 -0.04461669921875 +55148 -0.2100830078125 +55149 -0.05963134765625 +55150 -0.0362548828125 +55151 -0.07672119140625 +55152 0.10943603515625 +55153 -0.092132568359375 +55154 0.23516845703125 +55155 -0.10321044921875 +55156 0.373687744140625 +55157 -0.10479736328125 +55158 0.517791748046875 +55159 -0.097015380859375 +55160 0.602783203125 +55161 -0.08734130859375 +55162 0.635711669921875 +55163 -0.075164794921875 +55164 0.655181884765625 +55165 -0.056549072265625 +55166 0.65948486328125 +55167 -0.0328369140625 +55168 0.651275634765625 +55169 -0.005157470703125 +55170 0.61846923828125 +55171 0.023284912109375 +55172 0.53753662109375 +55173 0.047760009765625 +55174 0.404144287109375 +55175 0.065887451171875 +55176 0.22186279296875 +55177 0.07623291015625 +55178 0.003997802734375 +55179 0.07867431640625 +55180 -0.22100830078125 +55181 0.0751953125 +55182 -0.42449951171875 +55183 0.068084716796875 +55184 -0.579833984375 +55185 0.059783935546875 +55186 -0.641876220703125 +55187 0.055328369140625 +55188 -0.6177978515625 +55189 0.053924560546875 +55190 -0.575531005859375 +55191 0.0478515625 +55192 -0.526336669921875 +55193 0.03656005859375 +55194 -0.42645263671875 +55195 0.026397705078125 +55196 -0.2581787109375 +55197 0.02081298828125 +55198 -0.068695068359375 +55199 0.01568603515625 +55200 0.09222412109375 +55201 0.006622314453125 +55202 0.232147216796875 +55203 -0.003875732421875 +55204 0.3509521484375 +55205 -0.014373779296875 +55206 0.410064697265625 +55207 -0.0281982421875 +55208 0.372955322265625 +55209 -0.0487060546875 +55210 0.2554931640625 +55211 -0.073272705078125 +55212 0.10711669921875 +55213 -0.095550537109375 +55214 -0.052886962890625 +55215 -0.11309814453125 +55216 -0.186279296875 +55217 -0.12164306640625 +55218 -0.23291015625 +55219 -0.114532470703125 +55220 -0.209442138671875 +55221 -0.0946044921875 +55222 -0.174163818359375 +55223 -0.0699462890625 +55224 -0.126739501953125 +55225 -0.041748046875 +55226 -0.048126220703125 +55227 -0.009002685546875 +55228 0.0426025390625 +55229 0.024688720703125 +55230 0.10748291015625 +55231 0.053558349609375 +55232 0.1409912109375 +55233 0.075836181640625 +55234 0.19708251953125 +55235 0.097076416015625 +55236 0.273651123046875 +55237 0.1163330078125 +55238 0.31768798828125 +55239 0.126861572265625 +55240 0.341094970703125 +55241 0.12994384765625 +55242 0.368011474609375 +55243 0.128570556640625 +55244 0.37249755859375 +55245 0.120025634765625 +55246 0.30072021484375 +55247 0.098480224609375 +55248 0.1517333984375 +55249 0.06463623046875 +55250 -0.01470947265625 +55251 0.026641845703125 +55252 -0.1883544921875 +55253 -0.013214111328125 +55254 -0.372711181640625 +55255 -0.054290771484375 +55256 -0.51397705078125 +55257 -0.089080810546875 +55258 -0.57177734375 +55259 -0.11181640625 +55260 -0.53948974609375 +55261 -0.120880126953125 +55262 -0.43511962890625 +55263 -0.11785888671875 +55264 -0.2962646484375 +55265 -0.106842041015625 +55266 -0.161102294921875 +55267 -0.092193603515625 +55268 -0.0435791015625 +55269 -0.07562255859375 +55270 0.060394287109375 +55271 -0.056884765625 +55272 0.13665771484375 +55273 -0.03814697265625 +55274 0.170135498046875 +55275 -0.021820068359375 +55276 0.16552734375 +55277 -0.008056640625 +55278 0.15728759765625 +55279 0.006378173828125 +55280 0.150787353515625 +55281 0.021270751953125 +55282 0.12200927734375 +55283 0.03289794921875 +55284 0.080108642578125 +55285 0.04150390625 +55286 0.05126953125 +55287 0.049560546875 +55288 0.062896728515625 +55289 0.059783935546875 +55290 0.09271240234375 +55291 0.069091796875 +55292 0.092987060546875 +55293 0.071533203125 +55294 0.07855224609375 +55295 0.06884765625 +55296 0.06427001953125 +55297 0.0631103515625 +55298 0.0347900390625 +55299 0.052764892578125 +55300 -0.01171875 +55301 0.037933349609375 +55302 -0.056060791015625 +55303 0.02130126953125 +55304 -0.055511474609375 +55305 0.007965087890625 +55306 -0.010467529296875 +55307 -0.001251220703125 +55308 0.02508544921875 +55309 -0.01092529296875 +55310 0.025665283203125 +55311 -0.02288818359375 +55312 0.017333984375 +55313 -0.033905029296875 +55314 0.00189208984375 +55315 -0.043304443359375 +55316 -0.03173828125 +55317 -0.05181884765625 +55318 -0.071502685546875 +55319 -0.058074951171875 +55320 -0.13543701171875 +55321 -0.0638427734375 +55322 -0.219970703125 +55323 -0.06890869140625 +55324 -0.300506591796875 +55325 -0.071014404296875 +55326 -0.376312255859375 +55327 -0.070526123046875 +55328 -0.416107177734375 +55329 -0.064849853515625 +55330 -0.371124267578125 +55331 -0.049652099609375 +55332 -0.242279052734375 +55333 -0.025665283203125 +55334 -0.069732666015625 +55335 0.00244140625 +55336 0.125640869140625 +55337 0.031982421875 +55338 0.31268310546875 +55339 0.059356689453125 +55340 0.45501708984375 +55341 0.0804443359375 +55342 0.554779052734375 +55343 0.09515380859375 +55344 0.61065673828125 +55345 0.1031494140625 +55346 0.610931396484375 +55347 0.10321044921875 +55348 0.531463623046875 +55349 0.093017578125 +55350 0.3883056640625 +55351 0.0743408203125 +55352 0.23468017578125 +55353 0.05279541015625 +55354 0.095245361328125 +55355 0.031280517578125 +55356 -0.00396728515625 +55357 0.012847900390625 +55358 -0.04852294921875 +55359 -0.000579833984375 +55360 -0.055145263671875 +55361 -0.01019287109375 +55362 -0.0758056640625 +55363 -0.020660400390625 +55364 -0.138702392578125 +55365 -0.03436279296875 +55366 -0.209197998046875 +55367 -0.047454833984375 +55368 -0.289031982421875 +55369 -0.059844970703125 +55370 -0.37884521484375 +55371 -0.0714111328125 +55372 -0.456329345703125 +55373 -0.079833984375 +55374 -0.51641845703125 +55375 -0.084625244140625 +55376 -0.519287109375 +55377 -0.0819091796875 +55378 -0.458251953125 +55379 -0.07122802734375 +55380 -0.384796142578125 +55381 -0.05804443359375 +55382 -0.323699951171875 +55383 -0.045166015625 +55384 -0.269287109375 +55385 -0.032379150390625 +55386 -0.1951904296875 +55387 -0.017486572265625 +55388 -0.100006103515625 +55389 -0.00079345703125 +55390 -0.01055908203125 +55391 0.014617919921875 +55392 0.1033935546875 +55393 0.03143310546875 +55394 0.24908447265625 +55395 0.05010986328125 +55396 0.373199462890625 +55397 0.06512451171875 +55398 0.45806884765625 +55399 0.074615478515625 +55400 0.511474609375 +55401 0.079345703125 +55402 0.565399169921875 +55403 0.08258056640625 +55404 0.61138916015625 +55405 0.083648681640625 +55406 0.5897216796875 +55407 0.07684326171875 +55408 0.4906005859375 +55409 0.06146240234375 +55410 0.33148193359375 +55411 0.03955078125 +55412 0.147796630859375 +55413 0.0150146484375 +55414 -0.01873779296875 +55415 -0.00762939453125 +55416 -0.140289306640625 +55417 -0.0252685546875 +55418 -0.191986083984375 +55419 -0.035125732421875 +55420 -0.184295654296875 +55421 -0.03802490234375 +55422 -0.161834716796875 +55423 -0.03826904296875 +55424 -0.166595458984375 +55425 -0.0399169921875 +55426 -0.19390869140625 +55427 -0.04248046875 +55428 -0.22442626953125 +55429 -0.0440673828125 +55430 -0.279754638671875 +55431 -0.046966552734375 +55432 -0.3389892578125 +55433 -0.04925537109375 +55434 -0.3543701171875 +55435 -0.04638671875 +55436 -0.348175048828125 +55437 -0.040863037109375 +55438 -0.32598876953125 +55439 -0.033538818359375 +55440 -0.2581787109375 +55441 -0.021728515625 +55442 -0.139801025390625 +55443 -0.00518798828125 +55444 0.014617919921875 +55445 0.01434326171875 +55446 0.144378662109375 +55447 0.03057861328125 +55448 0.221038818359375 +55449 0.04052734375 +55450 0.27069091796875 +55451 0.04669189453125 +55452 0.294036865234375 +55453 0.049102783203125 +55454 0.311767578125 +55455 0.04986572265625 +55456 0.339141845703125 +55457 0.05059814453125 +55458 0.360260009765625 +55459 0.0496826171875 +55460 0.360504150390625 +55461 0.045867919921875 +55462 0.308380126953125 +55463 0.036651611328125 +55464 0.18170166015625 +55465 0.020416259765625 +55466 0.0047607421875 +55467 -0.000335693359375 +55468 -0.17559814453125 +55469 -0.021148681640625 +55470 -0.3143310546875 +55471 -0.037811279296875 +55472 -0.36785888671875 +55473 -0.0462646484375 +55474 -0.36248779296875 +55475 -0.04864501953125 +55476 -0.343536376953125 +55477 -0.04876708984375 +55478 -0.3018798828125 +55479 -0.0457763671875 +55480 -0.231414794921875 +55481 -0.039154052734375 +55482 -0.117645263671875 +55483 -0.027679443359375 +55484 0.007049560546875 +55485 -0.01434326171875 +55486 0.087982177734375 +55487 -0.00408935546875 +55488 0.13946533203125 +55489 0.004119873046875 +55490 0.17425537109375 +55491 0.01123046875 +55492 0.188201904296875 +55493 0.0166015625 +55494 0.171234130859375 +55495 0.019134521484375 +55496 0.118438720703125 +55497 0.0181884765625 +55498 0.05706787109375 +55499 0.0159912109375 +55500 -0.010711669921875 +55501 0.0125732421875 +55502 -0.0914306640625 +55503 0.0072021484375 +55504 -0.162322998046875 +55505 0.0018310546875 +55506 -0.194549560546875 +55507 -0.001007080078125 +55508 -0.1492919921875 +55509 0.002105712890625 +55510 -0.02166748046875 +55511 0.01165771484375 +55512 0.124053955078125 +55513 0.0220947265625 +55514 0.211151123046875 +55515 0.02679443359375 +55516 0.240447998046875 +55517 0.0260009765625 +55518 0.242218017578125 +55519 0.0225830078125 +55520 0.2257080078125 +55521 0.017578125 +55522 0.194366455078125 +55523 0.011505126953125 +55524 0.115509033203125 +55525 0.00164794921875 +55526 0.0128173828125 +55527 -0.009674072265625 +55528 -0.053802490234375 +55529 -0.017120361328125 +55530 -0.110626220703125 +55531 -0.02294921875 +55532 -0.199493408203125 +55533 -0.03082275390625 +55534 -0.29437255859375 +55535 -0.038482666015625 +55536 -0.33221435546875 +55537 -0.0404052734375 +55538 -0.27972412109375 +55539 -0.033782958984375 +55540 -0.185333251953125 +55541 -0.02301025390625 +55542 -0.128204345703125 +55543 -0.01519775390625 +55544 -0.115692138671875 +55545 -0.011138916015625 +55546 -0.116455078125 +55547 -0.00823974609375 +55548 -0.105926513671875 +55549 -0.0045166015625 +55550 -0.053955078125 +55551 0.00250244140625 +55552 0.048797607421875 +55553 0.0133056640625 +55554 0.157318115234375 +55555 0.024169921875 +55556 0.212005615234375 +55557 0.0308837890625 +55558 0.218475341796875 +55559 0.033538818359375 +55560 0.23724365234375 +55561 0.035430908203125 +55562 0.30535888671875 +55563 0.03863525390625 +55564 0.38128662109375 +55565 0.0408935546875 +55566 0.404449462890625 +55567 0.039031982421875 +55568 0.3944091796875 +55569 0.034393310546875 +55570 0.3885498046875 +55571 0.02935791015625 +55572 0.362640380859375 +55573 0.022857666015625 +55574 0.27362060546875 +55575 0.012786865234375 +55576 0.11712646484375 +55577 -0.000762939453125 +55578 -0.054901123046875 +55579 -0.014617919921875 +55580 -0.19085693359375 +55581 -0.025665283203125 +55582 -0.28570556640625 +55583 -0.033447265625 +55584 -0.339263916015625 +55585 -0.037841796875 +55586 -0.3775634765625 +55587 -0.040283203125 +55588 -0.445709228515625 +55589 -0.043304443359375 +55590 -0.535064697265625 +55591 -0.046478271484375 +55592 -0.629058837890625 +55593 -0.04901123046875 +55594 -0.697601318359375 +55595 -0.04937744140625 +55596 -0.70391845703125 +55597 -0.045745849609375 +55598 -0.6424560546875 +55599 -0.038055419921875 +55600 -0.491241455078125 +55601 -0.025299072265625 +55602 -0.265716552734375 +55603 -0.00860595703125 +55604 -0.023712158203125 +55605 0.008544921875 +55606 0.201751708984375 +55607 0.02410888671875 +55608 0.375823974609375 +55609 0.0360107421875 +55610 0.485076904296875 +55611 0.04339599609375 +55612 0.56884765625 +55613 0.04840087890625 +55614 0.634765625 +55615 0.051483154296875 +55616 0.63763427734375 +55617 0.050201416015625 +55618 0.5660400390625 +55619 0.04400634765625 +55620 0.4720458984375 +55621 0.03594970703125 +55622 0.40692138671875 +55623 0.029083251953125 +55624 0.3778076171875 +55625 0.02398681640625 +55626 0.376953125 +55627 0.020416259765625 +55628 0.371978759765625 +55629 0.016754150390625 +55630 0.313140869140625 +55631 0.0103759765625 +55632 0.184417724609375 +55633 0.00054931640625 +55634 0.011199951171875 +55635 -0.011138916015625 +55636 -0.171051025390625 +55637 -0.0225830078125 +55638 -0.33740234375 +55639 -0.0323486328125 +55640 -0.47198486328125 +55641 -0.03955078125 +55642 -0.560394287109375 +55643 -0.043426513671875 +55644 -0.58056640625 +55645 -0.042816162109375 +55646 -0.54754638671875 +55647 -0.038665771484375 +55648 -0.508575439453125 +55649 -0.033843994140625 +55650 -0.459503173828125 +55651 -0.028228759765625 +55652 -0.394378662109375 +55653 -0.021636962890625 +55654 -0.35260009765625 +55655 -0.016387939453125 +55656 -0.31170654296875 +55657 -0.01141357421875 +55658 -0.197418212890625 +55659 -0.002685546875 +55660 -0.007965087890625 +55661 0.009735107421875 +55662 0.207489013671875 +55663 0.022979736328125 +55664 0.409210205078125 +55665 0.0347900390625 +55666 0.57208251953125 +55667 0.043731689453125 +55668 0.66595458984375 +55669 0.04815673828125 +55670 0.65875244140625 +55671 0.046356201171875 +55672 0.56744384765625 +55673 0.03936767578125 +55674 0.431396484375 +55675 0.029510498046875 +55676 0.29443359375 +55677 0.019378662109375 +55678 0.182464599609375 +55679 0.01055908203125 +55680 0.06365966796875 +55681 0.00140380859375 +55682 -0.075958251953125 +55683 -0.008697509765625 +55684 -0.189422607421875 +55685 -0.016998291015625 +55686 -0.271942138671875 +55687 -0.023101806640625 +55688 -0.342529296875 +55689 -0.02801513671875 +55690 -0.364166259765625 +55691 -0.0296630859375 +55692 -0.327239990234375 +55693 -0.027496337890625 +55694 -0.2769775390625 +55695 -0.024078369140625 +55696 -0.253692626953125 +55697 -0.021697998046875 +55698 -0.24365234375 +55699 -0.0196533203125 +55700 -0.1983642578125 +55701 -0.01531982421875 +55702 -0.116241455078125 +55703 -0.00872802734375 +55704 -0.036834716796875 +55705 -0.002197265625 +55706 0.034881591796875 +55707 0.00384521484375 +55708 0.09124755859375 +55709 0.008880615234375 +55710 0.10888671875 +55711 0.011474609375 +55712 0.125518798828125 +55713 0.013671875 +55714 0.15771484375 +55715 0.016357421875 +55716 0.17828369140625 +55717 0.0179443359375 +55718 0.17108154296875 +55719 0.01751708984375 +55720 0.129974365234375 +55721 0.014739990234375 +55722 0.082427978515625 +55723 0.011199951171875 +55724 0.027679443359375 +55725 0.0069580078125 +55726 -0.065643310546875 +55727 0.000335693359375 +55728 -0.15936279296875 +55729 -0.006439208984375 +55730 -0.21307373046875 +55731 -0.01104736328125 +55732 -0.234649658203125 +55733 -0.013824462890625 +55734 -0.2001953125 +55735 -0.01336669921875 +55736 -0.119171142578125 +55737 -0.010101318359375 +55738 -0.024749755859375 +55739 -0.005859375 +55740 0.085784912109375 +55741 -0.000396728515625 +55742 0.178131103515625 +55743 0.004302978515625 +55744 0.215576171875 +55745 0.0062255859375 +55746 0.211456298828125 +55747 0.006134033203125 +55748 0.17523193359375 +55749 0.00457763671875 +55750 0.128753662109375 +55751 0.002716064453125 +55752 0.1019287109375 +55753 0.002197265625 +55754 0.0743408203125 +55755 0.001800537109375 +55756 0.04327392578125 +55757 0.001312255859375 +55758 0.038177490234375 +55759 0.0023193359375 +55760 0.076263427734375 +55761 0.005706787109375 +55762 0.14105224609375 +55763 0.01043701171875 +55764 0.186431884765625 +55765 0.013885498046875 +55766 0.188812255859375 +55767 0.01470947265625 +55768 0.1390380859375 +55769 0.012359619140625 +55770 0.041778564453125 +55771 0.007080078125 +55772 -0.079437255859375 +55773 0.000213623046875 +55774 -0.219390869140625 +55775 -0.0079345703125 +55776 -0.367828369140625 +55777 -0.0167236328125 +55778 -0.494873046875 +55779 -0.02447509765625 +55780 -0.556243896484375 +55781 -0.028656005859375 +55782 -0.508697509765625 +55783 -0.026824951171875 +55784 -0.3756103515625 +55785 -0.020233154296875 +55786 -0.218902587890625 +55787 -0.012298583984375 +55788 -0.063751220703125 +55789 -0.004425048828125 +55790 0.091552734375 +55791 0.00347900390625 +55792 0.23602294921875 +55793 0.0108642578125 +55794 0.342987060546875 +55795 0.01629638671875 +55796 0.39520263671875 +55797 0.01885986328125 +55798 0.389373779296875 +55799 0.01837158203125 +55800 0.324249267578125 +55801 0.0147705078125 +55802 0.224090576171875 +55803 0.0093994140625 +55804 0.124267578125 +55805 0.004241943359375 +55806 0.037078857421875 +55807 -6.103515625e-05 +55808 -0.010101318359375 +55809 -0.00244140625 +55810 -0.019439697265625 +55811 -0.002838134765625 +55812 -0.022796630859375 +55813 -0.002410888671875 +55814 -0.001556396484375 +55815 -0.0009765625 +55816 0.056304931640625 +55817 0.001495361328125 +55818 0.106719970703125 +55819 0.0037841796875 +55820 0.096893310546875 +55821 0.004425048828125 +55822 0.042694091796875 +55823 0.003753662109375 +55824 -0.018035888671875 +55825 0.00262451171875 +55826 -0.07586669921875 +55827 0.001251220703125 +55828 -0.11944580078125 +55829 -3.0517578125e-05 +55830 -0.15972900390625 +55831 -0.001434326171875 +55832 -0.202606201171875 +55833 -0.003082275390625 +55834 -0.24859619140625 +55835 -0.0048828125 +55836 -0.30517578125 +55837 -0.006988525390625 +55838 -0.36212158203125 +55839 -0.00909423828125 +55840 -0.39141845703125 +55841 -0.010467529296875 +55842 -0.35528564453125 +55843 -0.01019287109375 +55844 -0.249969482421875 +55845 -0.00811767578125 +55846 -0.092864990234375 +55847 -0.004638671875 +55848 0.08905029296875 +55849 -0.000396728515625 +55850 0.2352294921875 +55851 0.00311279296875 +55852 0.318817138671875 +55853 0.0052490234375 +55854 0.358642578125 +55855 0.0064697265625 +55856 0.347747802734375 +55857 0.006561279296875 +55858 0.28564453125 +55859 0.005523681640625 +55860 0.223175048828125 +55861 0.004547119140625 +55862 0.196746826171875 +55863 0.00445556640625 +55864 0.179840087890625 +55865 0.004608154296875 +55866 0.155548095703125 +55867 0.00457763671875 +55868 0.151214599609375 +55869 0.00494384765625 +55870 0.156951904296875 +55871 0.005462646484375 +55872 0.13177490234375 +55873 0.005126953125 +55874 0.100799560546875 +55875 0.0045166015625 +55876 0.087127685546875 +55877 0.00421142578125 +55878 0.05487060546875 +55879 0.00335693359375 +55880 -0.009002685546875 +55881 0.001617431640625 +55882 -0.10400390625 +55883 -0.00091552734375 +55884 -0.229400634765625 +55885 -0.004241943359375 +55886 -0.35552978515625 +55887 -0.00762939453125 +55888 -0.441925048828125 +55889 -0.01007080078125 +55890 -0.473846435546875 +55891 -0.01116943359375 +55892 -0.464813232421875 +55893 -0.011260986328125 +55894 -0.419097900390625 +55895 -0.01043701171875 +55896 -0.334320068359375 +55897 -0.008636474609375 +55898 -0.227935791015625 +55899 -0.0062255859375 +55900 -0.12347412109375 +55901 -0.0037841796875 +55902 -0.02764892578125 +55903 -0.00146484375 +55904 0.077667236328125 +55905 0.001129150390625 +55906 0.2132568359375 +55907 0.004486083984375 +55908 0.38885498046875 +55909 0.00885009765625 +55910 0.582794189453125 +55911 0.013671875 +55912 0.734039306640625 +55913 0.017486572265625 +55914 0.800140380859375 +55915 0.01922607421875 +55916 0.7783203125 +55917 0.018829345703125 +55918 0.6651611328125 +55919 0.0162353515625 +55920 0.45965576171875 +55921 0.01141357421875 +55922 0.199188232421875 +55923 0.005279541015625 +55924 -0.050689697265625 +55925 -0.000579833984375 +55926 -0.23297119140625 +55927 -0.00482177734375 +55928 -0.33013916015625 +55929 -0.007049560546875 +55930 -0.368408203125 +55931 -0.00787353515625 +55932 -0.378936767578125 +55933 -0.008056640625 +55934 -0.376983642578125 +55935 -0.00799560546875 +55936 -0.37969970703125 +55937 -0.008087158203125 +55938 -0.391510009765625 +55939 -0.0084228515625 +55940 -0.385345458984375 +55941 -0.00836181640625 +55942 -0.3419189453125 +55943 -0.007415771484375 +55944 -0.28289794921875 +55945 -0.006103515625 +55946 -0.251617431640625 +55947 -0.00543212890625 +55948 -0.266143798828125 +55949 -0.005859375 +55950 -0.273345947265625 +55951 -0.006103515625 +55952 -0.216796875 +55953 -0.00482177734375 +55954 -0.128265380859375 +55955 -0.002777099609375 +55956 -0.068145751953125 +55957 -0.001373291015625 +55958 -0.0430908203125 +55959 -0.000762939453125 +55960 -0.024444580078125 +55961 -0.000274658203125 +55962 0.020721435546875 +55963 0.000823974609375 +55964 0.124481201171875 +55965 0.0032958984375 +55966 0.25787353515625 +55967 0.0064697265625 +55968 0.379119873046875 +55969 0.009307861328125 +55970 0.47991943359375 +55971 0.01165771484375 +55972 0.5281982421875 +55973 0.01275634765625 +55974 0.511138916015625 +55975 0.01226806640625 +55976 0.456207275390625 +55977 0.010894775390625 +55978 0.407470703125 +55979 0.009674072265625 +55980 0.383758544921875 +55981 0.009063720703125 +55982 0.35687255859375 +55983 0.008331298828125 +55984 0.31182861328125 +55985 0.007171630859375 +55986 0.250885009765625 +55987 0.005615234375 +55988 0.1654052734375 +55989 0.003509521484375 +55990 0.035247802734375 +55991 0.0003662109375 +55992 -0.142059326171875 +55993 -0.00384521484375 +55994 -0.33563232421875 +55995 -0.008392333984375 +55996 -0.5345458984375 +55997 -0.01300048828125 +55998 -0.72186279296875 +55999 -0.017303466796875 +56000 -0.836669921875 +56001 -0.019805908203125 +56002 -0.8326416015625 +56003 -0.019439697265625 +56004 -0.7296142578125 +56005 -0.016693115234375 +56006 -0.582550048828125 +56007 -0.012939453125 +56008 -0.440093994140625 +56009 -0.009368896484375 +56010 -0.324310302734375 +56011 -0.006500244140625 +56012 -0.20147705078125 +56013 -0.00347900390625 +56014 -0.044647216796875 +56015 0.00030517578125 +56016 0.103973388671875 +56017 0.003814697265625 +56018 0.202392578125 +56019 0.00604248046875 +56020 0.264495849609375 +56021 0.007354736328125 +56022 0.338897705078125 +56023 0.0089111328125 +56024 0.443817138671875 +56025 0.011138916015625 +56026 0.545074462890625 +56027 0.01324462890625 +56028 0.6173095703125 +56029 0.0146484375 +56030 0.6524658203125 +56031 0.01519775390625 +56032 0.66339111328125 +56033 0.015167236328125 +56034 0.6561279296875 +56035 0.0147705078125 +56036 0.606781005859375 +56037 0.013397216796875 +56038 0.501190185546875 +56039 0.010711669921875 +56040 0.352783203125 +56041 0.007080078125 +56042 0.176544189453125 +56043 0.002838134765625 +56044 -0.034820556640625 +56045 -0.002105712890625 +56046 -0.258209228515625 +56047 -0.0072021484375 +56048 -0.44244384765625 +56049 -0.011260986328125 +56050 -0.5753173828125 +56051 -0.0140380859375 +56052 -0.65203857421875 +56053 -0.01544189453125 +56054 -0.641632080078125 +56055 -0.014739990234375 +56056 -0.562164306640625 +56057 -0.012420654296875 +56058 -0.458038330078125 +56059 -0.00958251953125 +56060 -0.350555419921875 +56061 -0.0067138671875 +56062 -0.260528564453125 +56063 -0.00433349609375 +56064 -0.192108154296875 +56065 -0.002471923828125 +56066 -0.141937255859375 +56067 -0.00103759765625 +56068 -0.1021728515625 +56069 3.0517578125e-05 +56070 -0.062896728515625 +56071 0.000885009765625 +56072 -0.011932373046875 +56073 0.001708984375 +56074 0.062835693359375 +56075 0.002655029296875 +56076 0.148712158203125 +56077 0.003631591796875 +56078 0.241729736328125 +56079 0.00457763671875 +56080 0.34912109375 +56081 0.005584716796875 +56082 0.457305908203125 +56083 0.00653076171875 +56084 0.54388427734375 +56085 0.007232666015625 +56086 0.5728759765625 +56087 0.007415771484375 +56088 0.506591796875 +56089 0.006744384765625 +56090 0.351226806640625 +56091 0.0052490234375 +56092 0.146514892578125 +56093 0.003265380859375 +56094 -0.05523681640625 +56095 0.001220703125 +56096 -0.21624755859375 +56097 -0.00054931640625 +56098 -0.334930419921875 +56099 -0.001983642578125 +56100 -0.402984619140625 +56101 -0.00299072265625 +56102 -0.4412841796875 +56103 -0.00372314453125 +56104 -0.49578857421875 +56105 -0.0045166015625 +56106 -0.5601806640625 +56107 -0.005340576171875 +56108 -0.600738525390625 +56109 -0.00592041015625 +56110 -0.584228515625 +56111 -0.005950927734375 +56112 -0.47930908203125 +56113 -0.00518798828125 +56114 -0.27935791015625 +56115 -0.003570556640625 +56116 -0.0089111328125 +56117 -0.001312255859375 +56118 0.268798828125 +56119 0.00103759765625 +56120 0.482818603515625 +56121 0.002899169921875 +56122 0.60369873046875 +56123 0.004058837890625 +56124 0.650421142578125 +56125 0.004669189453125 +56126 0.66400146484375 +56127 0.005035400390625 +56128 0.6414794921875 +56129 0.005126953125 +56130 0.572540283203125 +56131 0.004852294921875 +56132 0.498138427734375 +56133 0.0045166015625 +56134 0.439453125 +56135 0.0042724609375 +56136 0.375518798828125 +56137 0.003936767578125 +56138 0.274505615234375 +56139 0.00323486328125 +56140 0.1087646484375 +56141 0.001953125 +56142 -0.099395751953125 +56143 0.000274658203125 +56144 -0.3182373046875 +56145 -0.00152587890625 +56146 -0.5489501953125 +56147 -0.00341796875 +56148 -0.7738037109375 +56149 -0.0052490234375 +56150 -0.86383056640625 +56151 -0.006622314453125 +56152 -0.870391845703125 +56153 -0.00726318359375 +56154 -0.86895751953125 +56155 -0.00732421875 +56156 -0.861053466796875 +56157 -0.006927490234375 +56158 -0.765869140625 +56159 -0.00592041015625 +56160 -0.5301513671875 +56161 -0.00421142578125 +56162 -0.214691162109375 +56163 -0.001861572265625 +56164 0.137359619140625 +56165 0.00079345703125 +56166 0.474822998046875 +56167 0.00335693359375 +56168 0.76239013671875 +56169 0.00555419921875 +56170 0.867462158203125 +56171 0.007171630859375 +56172 0.870361328125 +56173 0.008209228515625 +56174 0.86480712890625 +56175 0.008575439453125 +56176 0.831817626953125 +56177 0.00830078125 +56178 0.677581787109375 +56179 0.007598876953125 +56180 0.495880126953125 +56181 0.006561279296875 +56182 0.30767822265625 +56183 0.00531005859375 +56184 0.116180419921875 +56185 0.00390625 +56186 -0.110748291015625 +56187 0.0020751953125 +56188 -0.381805419921875 +56189 -0.000244140625 +56190 -0.6572265625 +56191 -0.002716064453125 +56192 -0.857421875 +56193 -0.004852294921875 +56194 -0.870391845703125 +56195 -0.00634765625 +56196 -0.870391845703125 +56197 -0.007171630859375 +56198 -0.86444091796875 +56199 -0.007537841796875 +56200 -0.85723876953125 +56201 -0.00775146484375 +56202 -0.790008544921875 +56203 -0.0076904296875 +56204 -0.62847900390625 +56205 -0.0069580078125 +56206 -0.3956298828125 +56207 -0.005523681640625 +56208 -0.126708984375 +56209 -0.003631591796875 +56210 0.150115966796875 +56211 -0.001495361328125 +56212 0.424041748046875 +56213 0.000762939453125 +56214 0.670623779296875 +56215 0.0029296875 +56216 0.854522705078125 +56217 0.00469970703125 +56218 0.866485595703125 +56219 0.005950927734375 +56220 0.86920166015625 +56221 0.006622314453125 +56222 0.8653564453125 +56223 0.00689697265625 +56224 0.857147216796875 +56225 0.006866455078125 +56226 0.766845703125 +56227 0.006561279296875 +56228 0.628509521484375 +56229 0.0059814453125 +56230 0.462127685546875 +56231 0.005126953125 +56232 0.297210693359375 +56233 0.004180908203125 +56234 0.14862060546875 +56235 0.00323486328125 +56236 -0.00537109375 +56237 0.002105712890625 +56238 -0.15753173828125 +56239 0.0008544921875 +56240 -0.31304931640625 +56241 -0.000518798828125 +56242 -0.48876953125 +56243 -0.002105712890625 +56244 -0.6416015625 +56245 -0.003570556640625 +56246 -0.751373291015625 +56247 -0.004730224609375 +56248 -0.84619140625 +56249 -0.00579833984375 +56250 -0.861297607421875 +56251 -0.00665283203125 +56252 -0.863250732421875 +56253 -0.007080078125 +56254 -0.856597900390625 +56255 -0.006805419921875 +56256 -0.7498779296875 +56257 -0.0059814453125 +56258 -0.624542236328125 +56259 -0.005096435546875 +56260 -0.47808837890625 +56261 -0.003997802734375 +56262 -0.253387451171875 +56263 -0.002227783203125 +56264 0.003692626953125 +56265 -0.000152587890625 +56266 0.2257080078125 +56267 0.00164794921875 +56268 0.427154541015625 +56269 0.003265380859375 +56270 0.643218994140625 +56271 0.004974365234375 +56272 0.855926513671875 +56273 0.0067138671875 +56274 0.870361328125 +56275 0.008087158203125 +56276 0.870361328125 +56277 0.00872802734375 +56278 0.862762451171875 +56279 0.008758544921875 +56280 0.79669189453125 +56281 0.0081787109375 +56282 0.595794677734375 +56283 0.0069580078125 +56284 0.362152099609375 +56285 0.005340576171875 +56286 0.1270751953125 +56287 0.003570556640625 +56288 -0.086944580078125 +56289 0.0018310546875 +56290 -0.2784423828125 +56291 0.0001220703125 +56292 -0.484832763671875 +56293 -0.00177001953125 +56294 -0.729583740234375 +56295 -0.004058837890625 +56296 -0.86688232421875 +56297 -0.006317138671875 +56298 -0.870391845703125 +56299 -0.00811767578125 +56300 -0.86859130859375 +56301 -0.009429931640625 +56302 -0.86279296875 +56303 -0.010284423828125 +56304 -0.817962646484375 +56305 -0.01043701171875 +56306 -0.6116943359375 +56307 -0.00958251953125 +56308 -0.3128662109375 +56309 -0.007659912109375 +56310 0.039398193359375 +56311 -0.004974365234375 +56312 0.422821044921875 +56313 -0.001739501953125 +56314 0.805145263671875 +56315 0.001708984375 +56316 0.870361328125 +56317 0.0048828125 +56318 0.870361328125 +56319 0.00732421875 +56320 0.860015869140625 +56321 0.0091552734375 +56322 0.727935791015625 +56323 0.0098876953125 +56324 0.48114013671875 +56325 0.0091552734375 +56326 0.2059326171875 +56327 0.00787353515625 +56328 -0.06103515625 +56329 0.006805419921875 +56330 -0.29913330078125 +56331 0.006103515625 +56332 -0.516204833984375 +56333 0.00494384765625 +56334 -0.7252197265625 +56335 0.00238037109375 +56336 -0.85980224609375 +56337 -0.00091552734375 +56338 -0.870391845703125 +56339 -0.003936767578125 +56340 -0.870391845703125 +56341 -0.005889892578125 +56342 -0.858062744140625 +56343 -0.005218505859375 +56344 -0.673004150390625 +56345 -0.0020751953125 +56346 -0.42694091796875 +56347 0.00103759765625 +56348 -0.2100830078125 +56349 0.00213623046875 +56350 -0.0362548828125 +56351 0.0010986328125 +56352 0.10943603515625 +56353 -0.0009765625 +56354 0.23516845703125 +56355 -0.003265380859375 +56356 0.373687744140625 +56357 -0.00408935546875 +56358 0.517791748046875 +56359 -0.00341796875 +56360 0.602783203125 +56361 -0.003631591796875 +56362 0.635711669921875 +56363 -0.004302978515625 +56364 0.655181884765625 +56365 -0.003814697265625 +56366 0.65948486328125 +56367 -0.002227783203125 +56368 0.651275634765625 +56369 0.000396728515625 +56370 0.61846923828125 +56371 0.0032958984375 +56372 0.53753662109375 +56373 0.00531005859375 +56374 0.404144287109375 +56375 0.005950927734375 +56376 0.22186279296875 +56377 0.005035400390625 +56378 0.003997802734375 +56379 0.00274658203125 +56380 -0.22100830078125 +56381 -9.1552734375e-05 +56382 -0.42449951171875 +56383 -0.002655029296875 +56384 -0.579833984375 +56385 -0.00421142578125 +56386 -0.641876220703125 +56387 -0.003173828125 +56388 -0.6177978515625 +56389 0.0 +56390 -0.575531005859375 +56391 0.00250244140625 +56392 -0.526336669921875 +56393 0.003875732421875 +56394 -0.42645263671875 +56395 0.00592041015625 +56396 -0.2581787109375 +56397 0.009490966796875 +56398 -0.068695068359375 +56399 0.01287841796875 +56400 0.09222412109375 +56401 0.014404296875 +56402 0.232147216796875 +56403 0.014617919921875 +56404 0.3509521484375 +56405 0.01385498046875 +56406 0.410064697265625 +56407 0.0108642578125 +56408 0.372955322265625 +56409 0.004486083984375 +56410 0.2554931640625 +56411 -0.004364013671875 +56412 0.10711669921875 +56413 -0.01348876953125 +56414 -0.052886962890625 +56415 -0.021942138671875 +56416 -0.186279296875 +56417 -0.028167724609375 +56418 -0.23291015625 +56419 -0.02972412109375 +56420 -0.209442138671875 +56421 -0.027374267578125 +56422 -0.174163818359375 +56423 -0.023529052734375 +56424 -0.126739501953125 +56425 -0.018341064453125 +56426 -0.048126220703125 +56427 -0.011260986328125 +56428 0.0426025390625 +56429 -0.003265380859375 +56430 0.10748291015625 +56431 0.00384521484375 +56432 0.1409912109375 +56433 0.00958251953125 +56434 0.19708251953125 +56435 0.015838623046875 +56436 0.273651123046875 +56437 0.0223388671875 +56438 0.31768798828125 +56439 0.026824951171875 +56440 0.341094970703125 +56441 0.029632568359375 +56442 0.368011474609375 +56443 0.03167724609375 +56444 0.37249755859375 +56445 0.031890869140625 +56446 0.30072021484375 +56447 0.02813720703125 +56448 0.1517333984375 +56449 0.020477294921875 +56450 -0.01470947265625 +56451 0.011383056640625 +56452 -0.1883544921875 +56453 0.001434326171875 +56454 -0.372711181640625 +56455 -0.009307861328125 +56456 -0.51397705078125 +56457 -0.018524169921875 +56458 -0.57177734375 +56459 -0.024383544921875 +56460 -0.53948974609375 +56461 -0.02642822265625 +56462 -0.43511962890625 +56463 -0.02520751953125 +56464 -0.2962646484375 +56465 -0.022064208984375 +56466 -0.161102294921875 +56467 -0.018402099609375 +56468 -0.0435791015625 +56469 -0.01470947265625 +56470 0.060394287109375 +56471 -0.01080322265625 +56472 0.13665771484375 +56473 -0.00726318359375 +56474 0.170135498046875 +56475 -0.004730224609375 +56476 0.16552734375 +56477 -0.00311279296875 +56478 0.15728759765625 +56479 -0.001129150390625 +56480 0.150787353515625 +56481 0.00128173828125 +56482 0.12200927734375 +56483 0.00299072265625 +56484 0.080108642578125 +56485 0.004180908203125 +56486 0.05126953125 +56487 0.005767822265625 +56488 0.062896728515625 +56489 0.008697509765625 +56490 0.09271240234375 +56491 0.011962890625 +56492 0.092987060546875 +56493 0.013519287109375 +56494 0.07855224609375 +56495 0.013916015625 +56496 0.06427001953125 +56497 0.013702392578125 +56498 0.0347900390625 +56499 0.01226806640625 +56500 -0.01171875 +56501 0.009552001953125 +56502 -0.056060791015625 +56503 0.006378173828125 +56504 -0.055511474609375 +56505 0.00457763671875 +56506 -0.010467529296875 +56507 0.004241943359375 +56508 0.02508544921875 +56509 0.003326416015625 +56510 0.025665283203125 +56511 0.000946044921875 +56512 0.017333984375 +56513 -0.001678466796875 +56514 0.00189208984375 +56515 -0.00433349609375 +56516 -0.03173828125 +56517 -0.00738525390625 +56518 -0.071502685546875 +56519 -0.010284423828125 +56520 -0.13543701171875 +56521 -0.013671875 +56522 -0.219970703125 +56523 -0.017364501953125 +56524 -0.300506591796875 +56525 -0.020355224609375 +56526 -0.376312255859375 +56527 -0.022674560546875 +56528 -0.416107177734375 +56529 -0.02313232421875 +56530 -0.371124267578125 +56531 -0.019866943359375 +56532 -0.242279052734375 +56533 -0.01300048828125 +56534 -0.069732666015625 +56535 -0.004241943359375 +56536 0.125640869140625 +56537 0.00543212890625 +56538 0.31268310546875 +56539 0.014678955078125 +56540 0.45501708984375 +56541 0.021942138671875 +56542 0.554779052734375 +56543 0.027252197265625 +56544 0.61065673828125 +56545 0.030487060546875 +56546 0.610931396484375 +56547 0.0311279296875 +56548 0.531463623046875 +56549 0.028228759765625 +56550 0.3883056640625 +56551 0.02239990234375 +56552 0.23468017578125 +56553 0.015777587890625 +56554 0.095245361328125 +56555 0.009429931640625 +56556 -0.00396728515625 +56557 0.004425048828125 +56558 -0.04852294921875 +56559 0.001373291015625 +56560 -0.055145263671875 +56561 -0.000274658203125 +56562 -0.0758056640625 +56563 -0.002532958984375 +56564 -0.138702392578125 +56565 -0.006439208984375 +56566 -0.209197998046875 +56567 -0.010528564453125 +56568 -0.289031982421875 +56569 -0.014801025390625 +56570 -0.37884521484375 +56571 -0.01922607421875 +56572 -0.456329345703125 +56573 -0.02288818359375 +56574 -0.51641845703125 +56575 -0.025543212890625 +56576 -0.519287109375 +56577 -0.025421142578125 +56578 -0.458251953125 +56579 -0.02227783203125 +56580 -0.384796142578125 +56581 -0.01861572265625 +56582 -0.323699951171875 +56583 -0.015655517578125 +56584 -0.269287109375 +56585 -0.0130615234375 +56586 -0.1951904296875 +56587 -0.009490966796875 +56588 -0.100006103515625 +56589 -0.0048828125 +56590 -0.01055908203125 +56591 -0.00054931640625 +56592 0.1033935546875 +56593 0.0050048828125 +56594 0.24908447265625 +56595 0.01214599609375 +56596 0.373199462890625 +56597 0.01824951171875 +56598 0.45806884765625 +56599 0.02239990234375 +56600 0.511474609375 +56601 0.024993896484375 +56602 0.565399169921875 +56603 0.02764892578125 +56604 0.61138916015625 +56605 0.029937744140625 +56606 0.5897216796875 +56607 0.028900146484375 +56608 0.4906005859375 +56609 0.0240478515625 +56610 0.33148193359375 +56611 0.016204833984375 +56612 0.147796630859375 +56613 0.00714111328125 +56614 -0.01873779296875 +56615 -0.001007080078125 +56616 -0.140289306640625 +56617 -0.006866455078125 +56618 -0.191986083984375 +56619 -0.00921630859375 +56620 -0.184295654296875 +56621 -0.008636474609375 +56622 -0.161834716796875 +56623 -0.00732421875 +56624 -0.166595458984375 +56625 -0.00738525390625 +56626 -0.19390869140625 +56627 -0.008575439453125 +56628 -0.22442626953125 +56629 -0.009979248046875 +56630 -0.279754638671875 +56631 -0.012664794921875 +56632 -0.3389892578125 +56633 -0.015594482421875 +56634 -0.3543701171875 +56635 -0.016387939453125 +56636 -0.348175048828125 +56637 -0.016143798828125 +56638 -0.32598876953125 +56639 -0.015106201171875 +56640 -0.2581787109375 +56641 -0.011810302734375 +56642 -0.139801025390625 +56643 -0.006011962890625 +56644 0.014617919921875 +56645 0.001556396484375 +56646 0.144378662109375 +56647 0.0078125 +56648 0.221038818359375 +56649 0.0113525390625 +56650 0.27069091796875 +56651 0.013519287109375 +56652 0.294036865234375 +56653 0.014373779296875 +56654 0.311767578125 +56655 0.014984130859375 +56656 0.339141845703125 +56657 0.01617431640625 +56658 0.360260009765625 +56659 0.0174560546875 +56660 0.360504150390625 +56661 0.01800537109375 +56662 0.308380126953125 +56663 0.015411376953125 +56664 0.18170166015625 +56665 0.0079345703125 +56666 0.0047607421875 +56667 -0.0028076171875 +56668 -0.17559814453125 +56669 -0.01361083984375 +56670 -0.3143310546875 +56671 -0.0213623046875 +56672 -0.36785888671875 +56673 -0.023101806640625 +56674 -0.36248779296875 +56675 -0.0208740234375 +56676 -0.343536376953125 +56677 -0.01800537109375 +56678 -0.3018798828125 +56679 -0.013946533203125 +56680 -0.231414794921875 +56681 -0.008270263671875 +56682 -0.117645263671875 +56683 0.0 +56684 0.007049560546875 +56685 0.008544921875 +56686 0.087982177734375 +56687 0.013458251953125 +56688 0.13946533203125 +56689 0.015869140625 +56690 0.17425537109375 +56691 0.01678466796875 +56692 0.188201904296875 +56693 0.016021728515625 +56694 0.171234130859375 +56695 0.012939453125 +56696 0.118438720703125 +56697 0.00732421875 +56698 0.05706787109375 +56699 0.001251220703125 +56700 -0.010711669921875 +56701 -0.005035400390625 +56702 -0.0914306640625 +56703 -0.011932373046875 +56704 -0.162322998046875 +56705 -0.01776123046875 +56706 -0.194549560546875 +56707 -0.02044677734375 +56708 -0.1492919921875 +56709 -0.01715087890625 +56710 -0.02166748046875 +56711 -0.007568359375 +56712 0.124053955078125 +56713 0.003631591796875 +56714 0.211151123046875 +56715 0.010833740234375 +56716 0.240447998046875 +56717 0.014068603515625 +56718 0.242218017578125 +56719 0.015472412109375 +56720 0.2257080078125 +56721 0.015625 +56722 0.194366455078125 +56723 0.01470947265625 +56724 0.115509033203125 +56725 0.010284423828125 +56726 0.0128173828125 +56727 0.0040283203125 +56728 -0.053802490234375 +56729 0.000152587890625 +56730 -0.110626220703125 +56731 -0.00323486328125 +56732 -0.199493408203125 +56733 -0.0091552734375 +56734 -0.29437255859375 +56735 -0.015777587890625 +56736 -0.33221435546875 +56737 -0.0185546875 +56738 -0.27972412109375 +56739 -0.015106201171875 +56740 -0.185333251953125 +56741 -0.008880615234375 +56742 -0.128204345703125 +56743 -0.005523681640625 +56744 -0.115692138671875 +56745 -0.005523681640625 +56746 -0.116455078125 +56747 -0.006591796875 +56748 -0.105926513671875 +56749 -0.00689697265625 +56750 -0.053955078125 +56751 -0.00421142578125 +56752 0.048797607421875 +56753 0.002166748046875 +56754 0.157318115234375 +56755 0.009033203125 +56756 0.212005615234375 +56757 0.012176513671875 +56758 0.218475341796875 +56759 0.012054443359375 +56760 0.23724365234375 +56761 0.013031005859375 +56762 0.30535888671875 +56763 0.017791748046875 +56764 0.38128662109375 +56765 0.0233154296875 +56766 0.404449462890625 +56767 0.025238037109375 +56768 0.3944091796875 +56769 0.024993896484375 +56770 0.3885498046875 +56771 0.025238037109375 +56772 0.362640380859375 +56773 0.024200439453125 +56774 0.27362060546875 +56775 0.018707275390625 +56776 0.11712646484375 +56777 0.00836181640625 +56778 -0.054901123046875 +56779 -0.003082275390625 +56780 -0.19085693359375 +56781 -0.011962890625 +56782 -0.28570556640625 +56783 -0.017974853515625 +56784 -0.339263916015625 +56785 -0.021148681640625 +56786 -0.3775634765625 +56787 -0.023406982421875 +56788 -0.445709228515625 +56789 -0.02801513671875 +56790 -0.535064697265625 +56791 -0.034332275390625 +56792 -0.629058837890625 +56793 -0.041168212890625 +56794 -0.697601318359375 +56795 -0.04632568359375 +56796 -0.70391845703125 +56797 -0.04718017578125 +56798 -0.6424560546875 +56799 -0.043304443359375 +56800 -0.491241455078125 +56801 -0.0330810546875 +56802 -0.265716552734375 +56803 -0.017578125 +56804 -0.023712158203125 +56805 -0.000946044921875 +56806 0.201751708984375 +56807 0.01446533203125 +56808 0.375823974609375 +56809 0.026214599609375 +56810 0.485076904296875 +56811 0.033355712890625 +56812 0.56884765625 +56813 0.03875732421875 +56814 0.634765625 +56815 0.04302978515625 +56816 0.63763427734375 +56817 0.04290771484375 +56818 0.5660400390625 +56819 0.03759765625 +56820 0.4720458984375 +56821 0.03082275390625 +56822 0.40692138671875 +56823 0.02630615234375 +56824 0.3778076171875 +56825 0.0245361328125 +56826 0.376953125 +56827 0.024932861328125 +56828 0.371978759765625 +56829 0.025146484375 +56830 0.313140869140625 +56831 0.021514892578125 +56832 0.184417724609375 +56833 0.01263427734375 +56834 0.011199951171875 +56835 6.103515625e-05 +56836 -0.171051025390625 +56837 -0.013336181640625 +56838 -0.33740234375 +56839 -0.025360107421875 +56840 -0.47198486328125 +56841 -0.03466796875 +56842 -0.560394287109375 +56843 -0.040069580078125 +56844 -0.58056640625 +56845 -0.03948974609375 +56846 -0.54754638671875 +56847 -0.03460693359375 +56848 -0.508575439453125 +56849 -0.030364990234375 +56850 -0.459503173828125 +56851 -0.026336669921875 +56852 -0.394378662109375 +56853 -0.02178955078125 +56854 -0.35260009765625 +56855 -0.0206298828125 +56856 -0.31170654296875 +56857 -0.02032470703125 +56858 -0.197418212890625 +56859 -0.012908935546875 +56860 -0.007965087890625 +56861 0.00201416015625 +56862 0.207489013671875 +56863 0.01959228515625 +56864 0.409210205078125 +56865 0.03594970703125 +56866 0.57208251953125 +56867 0.048736572265625 +56868 0.66595458984375 +56869 0.0550537109375 +56870 0.65875244140625 +56871 0.051727294921875 +56872 0.56744384765625 +56873 0.040618896484375 +56874 0.431396484375 +56875 0.025909423828125 +56876 0.29443359375 +56877 0.012176513671875 +56878 0.182464599609375 +56879 0.002044677734375 +56880 0.06365966796875 +56881 -0.00787353515625 +56882 -0.075958251953125 +56883 -0.01922607421875 +56884 -0.189422607421875 +56885 -0.027313232421875 +56886 -0.271942138671875 +56887 -0.03179931640625 +56888 -0.342529296875 +56889 -0.034912109375 +56890 -0.364166259765625 +56891 -0.0330810546875 +56892 -0.327239990234375 +56893 -0.0255126953125 +56894 -0.2769775390625 +56895 -0.01708984375 +56896 -0.253692626953125 +56897 -0.012176513671875 +56898 -0.24365234375 +56899 -0.00946044921875 +56900 -0.1983642578125 +56901 -0.00396728515625 +56902 -0.116241455078125 +56903 0.004425048828125 +56904 -0.036834716796875 +56905 0.01165771484375 +56906 0.034881591796875 +56907 0.01727294921875 +56908 0.09124755859375 +56909 0.020599365234375 +56910 0.10888671875 +56911 0.01934814453125 +56912 0.125518798828125 +56913 0.01763916015625 +56914 0.15771484375 +56915 0.01739501953125 +56916 0.17828369140625 +56917 0.0159912109375 +56918 0.17108154296875 +56919 0.011932373046875 +56920 0.129974365234375 +56921 0.0047607421875 +56922 0.082427978515625 +56923 -0.00250244140625 +56924 0.027679443359375 +56925 -0.009796142578125 +56926 -0.065643310546875 +56927 -0.02032470703125 +56928 -0.15936279296875 +56929 -0.03009033203125 +56930 -0.21307373046875 +56931 -0.034912109375 +56932 -0.234649658203125 +56933 -0.03570556640625 +56934 -0.2001953125 +56935 -0.03009033203125 +56936 -0.119171142578125 +56937 -0.0191650390625 +56938 -0.024749755859375 +56939 -0.00653076171875 +56940 0.085784912109375 +56941 0.007904052734375 +56942 0.178131103515625 +56943 0.0203857421875 +56944 0.215576171875 +56945 0.026947021484375 +56946 0.211456298828125 +56947 0.02886962890625 +56948 0.17523193359375 +56949 0.02703857421875 +56950 0.128753662109375 +56951 0.023651123046875 +56952 0.1019287109375 +56953 0.021697998046875 +56954 0.0743408203125 +56955 0.019073486328125 +56956 0.04327392578125 +56957 0.01544189453125 +56958 0.038177490234375 +56959 0.013916015625 +56960 0.076263427734375 +56961 0.016357421875 +56962 0.14105224609375 +56963 0.0211181640625 +56964 0.186431884765625 +56965 0.0235595703125 +56966 0.188812255859375 +56967 0.0213623046875 +56968 0.1390380859375 +56969 0.01373291015625 +56970 0.041778564453125 +56971 0.00128173828125 +56972 -0.079437255859375 +56973 -0.013397216796875 +56974 -0.219390869140625 +56975 -0.0296630859375 +56976 -0.367828369140625 +56977 -0.04632568359375 +56978 -0.494873046875 +56979 -0.06024169921875 +56980 -0.556243896484375 +56981 -0.066802978515625 +56982 -0.508697509765625 +56983 -0.061492919921875 +56984 -0.3756103515625 +56985 -0.046783447265625 +56986 -0.218902587890625 +56987 -0.029205322265625 +56988 -0.063751220703125 +56989 -0.011444091796875 +56990 0.091552734375 +56991 0.00653076171875 +56992 0.23602294921875 +56993 0.023468017578125 +56994 0.342987060546875 +56995 0.0364990234375 +56996 0.39520263671875 +56997 0.043731689453125 +56998 0.389373779296875 +56999 0.04473876953125 +57000 0.324249267578125 +57001 0.039306640625 +57002 0.224090576171875 +57003 0.029937744140625 +57004 0.124267578125 +57005 0.020233154296875 +57006 0.037078857421875 +57007 0.01141357421875 +57008 -0.010101318359375 +57009 0.00634765625 +57010 -0.019439697265625 +57011 0.00482177734375 +57012 -0.022796630859375 +57013 0.0035400390625 +57014 -0.001556396484375 +57015 0.0045166015625 +57016 0.056304931640625 +57017 0.009033203125 +57018 0.106719970703125 +57019 0.01263427734375 +57020 0.096893310546875 +57021 0.009918212890625 +57022 0.042694091796875 +57023 0.002655029296875 +57024 -0.018035888671875 +57025 -0.005126953125 +57026 -0.07586669921875 +57027 -0.012359619140625 +57028 -0.11944580078125 +57029 -0.017791748046875 +57030 -0.15972900390625 +57031 -0.022552490234375 +57032 -0.202606201171875 +57033 -0.0272216796875 +57034 -0.24859619140625 +57035 -0.03179931640625 +57036 -0.30517578125 +57037 -0.037109375 +57038 -0.36212158203125 +57039 -0.042144775390625 +57040 -0.39141845703125 +57041 -0.0440673828125 +57042 -0.35528564453125 +57043 -0.03900146484375 +57044 -0.249969482421875 +57045 -0.026641845703125 +57046 -0.092864990234375 +57047 -0.008880615234375 +57048 0.08905029296875 +57049 0.011383056640625 +57050 0.2352294921875 +57051 0.02777099609375 +57052 0.318817138671875 +57053 0.03741455078125 +57054 0.358642578125 +57055 0.042236328125 +57056 0.347747802734375 +57057 0.041473388671875 +57058 0.28564453125 +57059 0.03509521484375 +57060 0.223175048828125 +57061 0.02838134765625 +57062 0.196746826171875 +57063 0.025115966796875 +57064 0.179840087890625 +57065 0.0225830078125 +57066 0.155548095703125 +57067 0.01910400390625 +57068 0.151214599609375 +57069 0.017547607421875 +57070 0.156951904296875 +57071 0.0169677734375 +57072 0.13177490234375 +57073 0.013153076171875 +57074 0.100799560546875 +57075 0.008819580078125 +57076 0.087127685546875 +57077 0.00640869140625 +57078 0.05487060546875 +57079 0.002227783203125 +57080 -0.009002685546875 +57081 -0.0050048828125 +57082 -0.10400390625 +57083 -0.01519775390625 +57084 -0.229400634765625 +57085 -0.02825927734375 +57086 -0.35552978515625 +57087 -0.0411376953125 +57088 -0.441925048828125 +57089 -0.049835205078125 +57090 -0.473846435546875 +57091 -0.05316162109375 +57092 -0.464813232421875 +57093 -0.052703857421875 +57094 -0.419097900390625 +57095 -0.048492431640625 +57096 -0.334320068359375 +57097 -0.039703369140625 +57098 -0.227935791015625 +57099 -0.02825927734375 +57100 -0.12347412109375 +57101 -0.01702880859375 +57102 -0.02764892578125 +57103 -0.006683349609375 +57104 0.077667236328125 +57105 0.00543212890625 +57106 0.2132568359375 +57107 0.022247314453125 +57108 0.38885498046875 +57109 0.045166015625 +57110 0.582794189453125 +57111 0.071258544921875 +57112 0.734039306640625 +57113 0.0921630859375 +57114 0.800140380859375 +57115 0.102020263671875 +57116 0.7783203125 +57117 0.100372314453125 +57118 0.6651611328125 +57119 0.086639404296875 +57120 0.45965576171875 +57121 0.06060791015625 +57122 0.199188232421875 +57123 0.027191162109375 +57124 -0.050689697265625 +57125 -0.004791259765625 +57126 -0.23297119140625 +57127 -0.027740478515625 +57128 -0.33013916015625 +57129 -0.039337158203125 +57130 -0.368408203125 +57131 -0.04327392578125 +57132 -0.378936767578125 +57133 -0.0438232421875 +57134 -0.376983642578125 +57135 -0.04315185546875 +57136 -0.37969970703125 +57137 -0.043548583984375 +57138 -0.391510009765625 +57139 -0.045623779296875 +57140 -0.385345458984375 +57141 -0.045623779296875 +57142 -0.3419189453125 +57143 -0.0408935546875 +57144 -0.28289794921875 +57145 -0.0343017578125 +57146 -0.251617431640625 +57147 -0.031646728515625 +57148 -0.266143798828125 +57149 -0.0352783203125 +57150 -0.273345947265625 +57151 -0.03790283203125 +57152 -0.216796875 +57153 -0.03173828125 +57154 -0.128265380859375 +57155 -0.021026611328125 +57156 -0.068145751953125 +57157 -0.01385498046875 +57158 -0.0430908203125 +57159 -0.0111083984375 +57160 -0.024444580078125 +57161 -0.0089111328125 +57162 0.020721435546875 +57163 -0.00274658203125 +57164 0.124481201171875 +57165 0.011688232421875 +57166 0.25787353515625 +57167 0.030426025390625 +57168 0.379119873046875 +57169 0.0477294921875 +57170 0.47991943359375 +57171 0.06243896484375 +57172 0.5281982421875 +57173 0.07012939453125 +57174 0.511138916015625 +57175 0.069000244140625 +57176 0.456207275390625 +57177 0.06268310546875 +57178 0.407470703125 +57179 0.05712890625 +57180 0.383758544921875 +57181 0.054840087890625 +57182 0.35687255859375 +57183 0.051910400390625 +57184 0.31182861328125 +57185 0.046295166015625 +57186 0.250885009765625 +57187 0.038299560546875 +57188 0.1654052734375 +57189 0.0267333984375 +57190 0.035247802734375 +57191 0.008880615234375 +57192 -0.142059326171875 +57193 -0.01556396484375 +57194 -0.33563232421875 +57195 -0.042388916015625 +57196 -0.5345458984375 +57197 -0.070068359375 +57198 -0.72186279296875 +57199 -0.09625244140625 +57200 -0.836669921875 +57201 -0.11260986328125 +57202 -0.8326416015625 +57203 -0.11279296875 +57204 -0.7296142578125 +57205 -0.099456787109375 +57206 -0.582550048828125 +57207 -0.080108642578125 +57208 -0.440093994140625 +57209 -0.061309814453125 +57210 -0.324310302734375 +57211 -0.0460205078125 +57212 -0.20147705078125 +57213 -0.02960205078125 +57214 -0.044647216796875 +57215 -0.008392333984375 +57216 0.103973388671875 +57217 0.0118408203125 +57218 0.202392578125 +57219 0.025390625 +57220 0.264495849609375 +57221 0.03411865234375 +57222 0.338897705078125 +57223 0.044586181640625 +57224 0.443817138671875 +57225 0.05926513671875 +57226 0.545074462890625 +57227 0.073486328125 +57228 0.6173095703125 +57229 0.083770751953125 +57230 0.6524658203125 +57231 0.089019775390625 +57232 0.66339111328125 +57233 0.0909423828125 +57234 0.6561279296875 +57235 0.09033203125 +57236 0.606781005859375 +57237 0.083892822265625 +57238 0.501190185546875 +57239 0.0697021484375 +57240 0.352783203125 +57241 0.049591064453125 +57242 0.176544189453125 +57243 0.025604248046875 +57244 -0.034820556640625 +57245 -0.003204345703125 +57246 -0.258209228515625 +57247 -0.03369140625 +57248 -0.44244384765625 +57249 -0.05889892578125 +57250 -0.5753173828125 +57251 -0.0771484375 +57252 -0.65203857421875 +57253 -0.087799072265625 +57254 -0.641632080078125 +57255 -0.08660888671875 +57256 -0.562164306640625 +57257 -0.0760498046875 +57258 -0.458038330078125 +57259 -0.062164306640625 +57260 -0.350555419921875 +57261 -0.047821044921875 +57262 -0.260528564453125 +57263 -0.035797119140625 +57264 -0.192108154296875 +57265 -0.026641845703125 +57266 -0.141937255859375 +57267 -0.019927978515625 +57268 -0.1021728515625 +57269 -0.01458740234375 +57270 -0.062896728515625 +57271 -0.00921630859375 +57272 -0.011932373046875 +57273 -0.002197265625 +57274 0.062835693359375 +57275 0.008087158203125 +57276 0.148712158203125 +57277 0.0198974609375 +57278 0.241729736328125 +57279 0.032684326171875 +57280 0.34912109375 +57281 0.047454833984375 +57282 0.457305908203125 +57283 0.06231689453125 +57284 0.54388427734375 +57285 0.074249267578125 +57286 0.5728759765625 +57287 0.07830810546875 +57288 0.506591796875 +57289 0.06939697265625 +57290 0.351226806640625 +57291 0.048370361328125 +57292 0.146514892578125 +57293 0.020599365234375 +57294 -0.05523681640625 +57295 -0.00677490234375 +57296 -0.21624755859375 +57297 -0.02862548828125 +57298 -0.334930419921875 +57299 -0.04473876953125 +57300 -0.402984619140625 +57301 -0.053985595703125 +57302 -0.4412841796875 +57303 -0.0592041015625 +57304 -0.49578857421875 +57305 -0.066650390625 +57306 -0.5601806640625 +57307 -0.075439453125 +57308 -0.600738525390625 +57309 -0.081024169921875 +57310 -0.584228515625 +57311 -0.078857421875 +57312 -0.47930908203125 +57313 -0.064666748046875 +57314 -0.27935791015625 +57315 -0.037567138671875 +57316 -0.0089111328125 +57317 -0.0008544921875 +57318 0.268798828125 +57319 0.036834716796875 +57320 0.482818603515625 +57321 0.065826416015625 +57322 0.60369873046875 +57323 0.082122802734375 +57324 0.650421142578125 +57325 0.08831787109375 +57326 0.66400146484375 +57327 0.09002685546875 +57328 0.6414794921875 +57329 0.08685302734375 +57330 0.572540283203125 +57331 0.077392578125 +57332 0.498138427734375 +57333 0.067230224609375 +57334 0.439453125 +57335 0.059234619140625 +57336 0.375518798828125 +57337 0.050567626953125 +57338 0.274505615234375 +57339 0.036895751953125 +57340 0.1087646484375 +57341 0.01446533203125 +57342 -0.099395751953125 +57343 -0.013671875 +57344 -0.3182373046875 +57345 -0.04376220703125 +57346 -0.5489501953125 +57347 -0.0767822265625 +57348 -0.7738037109375 +57349 -0.110107421875 +57350 -0.86383056640625 +57351 -0.135009765625 +57352 -0.870391845703125 +57353 -0.14599609375 +57354 -0.86895751953125 +57355 -0.146026611328125 +57356 -0.861053466796875 +57357 -0.137237548828125 +57358 -0.765869140625 +57359 -0.116546630859375 +57360 -0.5301513671875 +57361 -0.08184814453125 +57362 -0.214691162109375 +57363 -0.034027099609375 +57364 0.137359619140625 +57365 0.019927978515625 +57366 0.474822998046875 +57367 0.07171630859375 +57368 0.76239013671875 +57369 0.115692138671875 +57370 0.867462158203125 +57371 0.147613525390625 +57372 0.870361328125 +57373 0.167816162109375 +57374 0.86480712890625 +57375 0.174560546875 +57376 0.831817626953125 +57377 0.16888427734375 +57378 0.677581787109375 +57379 0.154998779296875 +57380 0.495880126953125 +57381 0.1339111328125 +57382 0.30767822265625 +57383 0.108734130859375 +57384 0.116180419921875 +57385 0.0797119140625 +57386 -0.110748291015625 +57387 0.0413818359375 +57388 -0.381805419921875 +57389 -0.007598876953125 +57390 -0.6572265625 +57391 -0.060272216796875 +57392 -0.857421875 +57393 -0.106781005859375 +57394 -0.870391845703125 +57395 -0.14019775390625 +57396 -0.870391845703125 +57397 -0.159576416015625 +57398 -0.86444091796875 +57399 -0.169677734375 +57400 -0.85723876953125 +57401 -0.176666259765625 +57402 -0.790008544921875 +57403 -0.1776123046875 +57404 -0.62847900390625 +57405 -0.16351318359375 +57406 -0.3956298828125 +57407 -0.133880615234375 +57408 -0.126708984375 +57409 -0.094207763671875 +57410 0.150115966796875 +57411 -0.049041748046875 +57412 0.424041748046875 +57413 -0.000244140625 +57414 0.670623779296875 +57415 0.047760009765625 +57416 0.854522705078125 +57417 0.088653564453125 +57418 0.866485595703125 +57419 0.119659423828125 +57420 0.86920166015625 +57421 0.138427734375 +57422 0.8653564453125 +57423 0.148193359375 +57424 0.857147216796875 +57425 0.151397705078125 +57426 0.766845703125 +57427 0.147735595703125 +57428 0.628509521484375 +57429 0.13824462890625 +57430 0.462127685546875 +57431 0.12188720703125 +57432 0.297210693359375 +57433 0.10302734375 +57434 0.14862060546875 +57435 0.083709716796875 +57436 -0.00537109375 +57437 0.06011962890625 +57438 -0.15753173828125 +57439 0.033416748046875 +57440 -0.31304931640625 +57441 0.0029296875 +57442 -0.48876953125 +57443 -0.033843994140625 +57444 -0.6416015625 +57445 -0.069183349609375 +57446 -0.751373291015625 +57447 -0.099090576171875 +57448 -0.84619140625 +57449 -0.127593994140625 +57450 -0.861297607421875 +57451 -0.152374267578125 +57452 -0.863250732421875 +57453 -0.168060302734375 +57454 -0.856597900390625 +57455 -0.16943359375 +57456 -0.7498779296875 +57457 -0.158660888671875 +57458 -0.624542236328125 +57459 -0.1455078125 +57460 -0.47808837890625 +57461 -0.1263427734375 +57462 -0.253387451171875 +57463 -0.091339111328125 +57464 0.003692626953125 +57465 -0.048126220703125 +57466 0.2257080078125 +57467 -0.00811767578125 +57468 0.427154541015625 +57469 0.030853271484375 +57470 0.643218994140625 +57471 0.0743408203125 +57472 0.855926513671875 +57473 0.120849609375 +57474 0.870361328125 +57475 0.160797119140625 +57476 0.870361328125 +57477 0.18603515625 +57478 0.862762451171875 +57479 0.1978759765625 +57480 0.79669189453125 +57481 0.195953369140625 +57482 0.595794677734375 +57483 0.178802490234375 +57484 0.362152099609375 +57485 0.151397705078125 +57486 0.1270751953125 +57487 0.118499755859375 +57488 -0.086944580078125 +57489 0.083648681640625 +57490 -0.2784423828125 +57491 0.047210693359375 +57492 -0.484832763671875 +57493 0.003265380859375 +57494 -0.729583740234375 +57495 -0.051422119140625 +57496 -0.86688232421875 +57497 -0.10845947265625 +57498 -0.870391845703125 +57499 -0.157318115234375 +57500 -0.86859130859375 +57501 -0.197265625 +57502 -0.86279296875 +57503 -0.228057861328125 +57504 -0.817962646484375 +57505 -0.243804931640625 +57506 -0.6116943359375 +57507 -0.236968994140625 +57508 -0.3128662109375 +57509 -0.2064208984375 +57510 0.039398193359375 +57511 -0.157928466796875 +57512 0.422821044921875 +57513 -0.094879150390625 +57514 0.805145263671875 +57515 -0.022918701171875 +57516 0.870361328125 +57517 0.046478271484375 +57518 0.870361328125 +57519 0.103759765625 +57520 0.860015869140625 +57521 0.14697265625 +57522 0.727935791015625 +57523 0.17486572265625 +57524 0.48114013671875 +57525 0.186553955078125 +57526 0.2059326171875 +57527 0.186187744140625 +57528 -0.06103515625 +57529 0.1776123046875 +57530 -0.29913330078125 +57531 0.16259765625 +57532 -0.516204833984375 +57533 0.1387939453125 +57534 -0.7252197265625 +57535 0.103729248046875 +57536 -0.85980224609375 +57537 0.0616455078125 +57538 -0.870391845703125 +57539 0.01837158203125 +57540 -0.870391845703125 +57541 -0.021026611328125 +57542 -0.858062744140625 +57543 -0.048309326171875 +57544 -0.673004150390625 +57545 -0.062713623046875 +57546 -0.42694091796875 +57547 -0.07305908203125 +57548 -0.2100830078125 +57549 -0.086761474609375 +57550 -0.0362548828125 +57551 -0.103424072265625 +57552 0.10943603515625 +57553 -0.118194580078125 +57554 0.23516845703125 +57555 -0.127685546875 +57556 0.373687744140625 +57557 -0.125 +57558 0.517791748046875 +57559 -0.110504150390625 +57560 0.602783203125 +57561 -0.0948486328125 +57562 0.635711669921875 +57563 -0.0772705078125 +57564 0.655181884765625 +57565 -0.05224609375 +57566 0.65948486328125 +57567 -0.02154541015625 +57568 0.651275634765625 +57569 0.013397216796875 +57570 0.61846923828125 +57571 0.048370361328125 +57572 0.53753662109375 +57573 0.07708740234375 +57574 0.404144287109375 +57575 0.096466064453125 +57576 0.22186279296875 +57577 0.1048583984375 +57578 0.003997802734375 +57579 0.102508544921875 +57580 -0.22100830078125 +57581 0.092437744140625 +57582 -0.42449951171875 +57583 0.078125 +57584 -0.579833984375 +57585 0.063201904296875 +57586 -0.641876220703125 +57587 0.05487060546875 +57588 -0.6177978515625 +57589 0.05206298828125 +57590 -0.575531005859375 +57591 0.04400634765625 +57592 -0.526336669921875 +57593 0.029876708984375 +57594 -0.42645263671875 +57595 0.0184326171875 +57596 -0.2581787109375 +57597 0.01434326171875 +57598 -0.068695068359375 +57599 0.011566162109375 +57600 0.09222412109375 +57601 0.00421142578125 +57602 0.232147216796875 +57603 -0.003936767578125 +57604 0.3509521484375 +57605 -0.01165771484375 +57606 0.410064697265625 +57607 -0.025390625 +57608 0.372955322265625 +57609 -0.05145263671875 +57610 0.2554931640625 +57611 -0.086029052734375 +57612 0.10711669921875 +57613 -0.118988037109375 +57614 -0.052886962890625 +57615 -0.146575927734375 +57616 -0.186279296875 +57617 -0.161651611328125 +57618 -0.23291015625 +57619 -0.153076171875 +57620 -0.209442138671875 +57621 -0.125335693359375 +57622 -0.174163818359375 +57623 -0.091461181640625 +57624 -0.126739501953125 +57625 -0.05291748046875 +57626 -0.048126220703125 +57627 -0.007568359375 +57628 0.0426025390625 +57629 0.039154052734375 +57630 0.10748291015625 +57631 0.078155517578125 +57632 0.1409912109375 +57633 0.10699462890625 +57634 0.19708251953125 +57635 0.1353759765625 +57636 0.273651123046875 +57637 0.162109375 +57638 0.31768798828125 +57639 0.1761474609375 +57640 0.341094970703125 +57641 0.179779052734375 +57642 0.368011474609375 +57643 0.178070068359375 +57644 0.37249755859375 +57645 0.1663818359375 +57646 0.30072021484375 +57647 0.134796142578125 +57648 0.1517333984375 +57649 0.084197998046875 +57650 -0.01470947265625 +57651 0.027801513671875 +57652 -0.1883544921875 +57653 -0.031005859375 +57654 -0.372711181640625 +57655 -0.091583251953125 +57656 -0.51397705078125 +57657 -0.14190673828125 +57658 -0.57177734375 +57659 -0.172760009765625 +57660 -0.53948974609375 +57661 -0.18182373046875 +57662 -0.43511962890625 +57663 -0.171966552734375 +57664 -0.2962646484375 +57665 -0.150238037109375 +57666 -0.161102294921875 +57667 -0.12408447265625 +57668 -0.0435791015625 +57669 -0.096405029296875 +57670 0.060394287109375 +57671 -0.0667724609375 +57672 0.13665771484375 +57673 -0.038604736328125 +57674 0.170135498046875 +57675 -0.0157470703125 +57676 0.16552734375 +57677 0.001739501953125 +57678 0.15728759765625 +57679 0.019683837890625 +57680 0.150787353515625 +57681 0.038055419921875 +57682 0.12200927734375 +57683 0.05096435546875 +57684 0.080108642578125 +57685 0.05926513671875 +57686 0.05126953125 +57687 0.06732177734375 +57688 0.062896728515625 +57689 0.0799560546875 +57690 0.09271240234375 +57691 0.092254638671875 +57692 0.092987060546875 +57693 0.094451904296875 +57694 0.07855224609375 +57695 0.089508056640625 +57696 0.06427001953125 +57697 0.080657958984375 +57698 0.0347900390625 +57699 0.06524658203125 +57700 -0.01171875 +57701 0.04351806640625 +57702 -0.056060791015625 +57703 0.02008056640625 +57704 -0.055511474609375 +57705 0.004364013671875 +57706 -0.010467529296875 +57707 -0.0028076171875 +57708 0.02508544921875 +57709 -0.0113525390625 +57710 0.025665283203125 +57711 -0.025543212890625 +57712 0.017333984375 +57713 -0.0394287109375 +57714 0.00189208984375 +57715 -0.052001953125 +57716 -0.03173828125 +57717 -0.0650634765625 +57718 -0.071502685546875 +57719 -0.075958251953125 +57720 -0.13543701171875 +57721 -0.088226318359375 +57722 -0.219970703125 +57723 -0.10125732421875 +57724 -0.300506591796875 +57725 -0.110443115234375 +57726 -0.376312255859375 +57727 -0.1160888671875 +57728 -0.416107177734375 +57729 -0.112548828125 +57730 -0.371124267578125 +57731 -0.09075927734375 +57732 -0.242279052734375 +57733 -0.051666259765625 +57734 -0.069732666015625 +57735 -0.0040283203125 +57736 0.125640869140625 +57737 0.0472412109375 +57738 0.31268310546875 +57739 0.095306396484375 +57740 0.45501708984375 +57741 0.13232421875 +57742 0.554779052734375 +57743 0.158294677734375 +57744 0.61065673828125 +57745 0.1727294921875 +57746 0.610931396484375 +57747 0.173187255859375 +57748 0.531463623046875 +57749 0.1549072265625 +57750 0.3883056640625 +57751 0.121337890625 +57752 0.23468017578125 +57753 0.083465576171875 +57754 0.095245361328125 +57755 0.046661376953125 +57756 -0.00396728515625 +57757 0.01666259765625 +57758 -0.04852294921875 +57759 -0.0030517578125 +57760 -0.055145263671875 +57761 -0.01519775390625 +57762 -0.0758056640625 +57763 -0.02960205078125 +57764 -0.138702392578125 +57765 -0.051361083984375 +57766 -0.209197998046875 +57767 -0.07305908203125 +57768 -0.289031982421875 +57769 -0.094696044921875 +57770 -0.37884521484375 +57771 -0.116119384765625 +57772 -0.456329345703125 +57773 -0.132720947265625 +57774 -0.51641845703125 +57775 -0.1435546875 +57776 -0.519287109375 +57777 -0.140777587890625 +57778 -0.458251953125 +57779 -0.123291015625 +57780 -0.384796142578125 +57781 -0.101715087890625 +57782 -0.323699951171875 +57783 -0.0814208984375 +57784 -0.269287109375 +57785 -0.061737060546875 +57786 -0.1951904296875 +57787 -0.03790283203125 +57788 -0.100006103515625 +57789 -0.0101318359375 +57790 -0.01055908203125 +57791 0.015716552734375 +57792 0.1033935546875 +57793 0.045257568359375 +57794 0.24908447265625 +57795 0.079620361328125 +57796 0.373199462890625 +57797 0.107879638671875 +57798 0.45806884765625 +57799 0.126373291015625 +57800 0.511474609375 +57801 0.136627197265625 +57802 0.565399169921875 +57803 0.1451416015625 +57804 0.61138916015625 +57805 0.150360107421875 +57806 0.5897216796875 +57807 0.140625 +57808 0.4906005859375 +57809 0.11431884765625 +57810 0.33148193359375 +57811 0.0753173828125 +57812 0.147796630859375 +57813 0.0311279296875 +57814 -0.01873779296875 +57815 -0.009490966796875 +57816 -0.140289306640625 +57817 -0.040557861328125 +57818 -0.191986083984375 +57819 -0.056732177734375 +57820 -0.184295654296875 +57821 -0.059844970703125 +57822 -0.161834716796875 +57823 -0.05859375 +57824 -0.166595458984375 +57825 -0.061248779296875 +57826 -0.19390869140625 +57827 -0.066802978515625 +57828 -0.22442626953125 +57829 -0.071441650390625 +57830 -0.279754638671875 +57831 -0.079620361328125 +57832 -0.3389892578125 +57833 -0.08734130859375 +57834 -0.3543701171875 +57835 -0.0853271484375 +57836 -0.348175048828125 +57837 -0.078338623046875 +57838 -0.32598876953125 +57839 -0.06781005859375 +57840 -0.2581787109375 +57841 -0.048187255859375 +57842 -0.139801025390625 +57843 -0.018798828125 +57844 0.014617919921875 +57845 0.01715087890625 +57846 0.144378662109375 +57847 0.047210693359375 +57848 0.221038818359375 +57849 0.065521240234375 +57850 0.27069091796875 +57851 0.077178955078125 +57852 0.294036865234375 +57853 0.082275390625 +57854 0.311767578125 +57855 0.0849609375 +57856 0.339141845703125 +57857 0.088470458984375 +57858 0.360260009765625 +57859 0.090179443359375 +57860 0.360504150390625 +57861 0.08721923828125 +57862 0.308380126953125 +57863 0.072296142578125 +57864 0.18170166015625 +57865 0.040313720703125 +57866 0.0047607421875 +57867 -0.002960205078125 +57868 -0.17559814453125 +57869 -0.046661376953125 +57870 -0.3143310546875 +57871 -0.080291748046875 +57872 -0.36785888671875 +57873 -0.093719482421875 +57874 -0.36248779296875 +57875 -0.093017578125 +57876 -0.343536376953125 +57877 -0.08868408203125 +57878 -0.3018798828125 +57879 -0.078643798828125 +57880 -0.231414794921875 +57881 -0.061492919921875 +57882 -0.117645263671875 +57883 -0.033905029296875 +57884 0.007049560546875 +57885 -0.00347900390625 +57886 0.087982177734375 +57887 0.016998291015625 +57888 0.13946533203125 +57889 0.03076171875 +57890 0.17425537109375 +57891 0.040679931640625 +57892 0.188201904296875 +57893 0.045684814453125 +57894 0.171234130859375 +57895 0.0433349609375 +57896 0.118438720703125 +57897 0.032440185546875 +57898 0.05706787109375 +57899 0.019256591796875 +57900 -0.010711669921875 +57901 0.004241943359375 +57902 -0.0914306640625 +57903 -0.014129638671875 +57904 -0.162322998046875 +57905 -0.03057861328125 +57906 -0.194549560546875 +57907 -0.038421630859375 +57908 -0.1492919921875 +57909 -0.02862548828125 +57910 -0.02166748046875 +57911 -3.0517578125e-05 +57912 0.124053955078125 +57913 0.03253173828125 +57914 0.211151123046875 +57915 0.051300048828125 +57916 0.240447998046875 +57917 0.056549072265625 +57918 0.242218017578125 +57919 0.055389404296875 +57920 0.2257080078125 +57921 0.050079345703125 +57922 0.194366455078125 +57923 0.04150390625 +57924 0.115509033203125 +57925 0.022125244140625 +57926 0.0128173828125 +57927 -0.00244140625 +57928 -0.053802490234375 +57929 -0.018280029296875 +57930 -0.110626220703125 +57931 -0.031494140625 +57932 -0.199493408203125 +57933 -0.05181884765625 +57934 -0.29437255859375 +57935 -0.073211669921875 +57936 -0.33221435546875 +57937 -0.081085205078125 +57938 -0.27972412109375 +57939 -0.067779541015625 +57940 -0.185333251953125 +57941 -0.04461669921875 +57942 -0.128204345703125 +57943 -0.030029296875 +57944 -0.115692138671875 +57945 -0.025787353515625 +57946 -0.116455078125 +57947 -0.024688720703125 +57948 -0.105926513671875 +57949 -0.0211181640625 +57950 -0.053955078125 +57951 -0.00811767578125 +57952 0.048797607421875 +57953 0.016387939453125 +57954 0.157318115234375 +57955 0.04193115234375 +57956 0.212005615234375 +57957 0.054656982421875 +57958 0.218475341796875 +57959 0.055877685546875 +57960 0.23724365234375 +57961 0.0596923828125 +57962 0.30535888671875 +57963 0.07470703125 +57964 0.38128662109375 +57965 0.091339111328125 +57966 0.404449462890625 +57967 0.0955810546875 +57968 0.3944091796875 +57969 0.092071533203125 +57970 0.3885498046875 +57971 0.089508056640625 +57972 0.362640380859375 +57973 0.082366943359375 +57974 0.27362060546875 +57975 0.060699462890625 +57976 0.11712646484375 +57977 0.0235595703125 +57978 -0.054901123046875 +57979 -0.01690673828125 +57980 -0.19085693359375 +57981 -0.0487060546875 +57982 -0.28570556640625 +57983 -0.070709228515625 +57984 -0.339263916015625 +57985 -0.082855224609375 +57986 -0.3775634765625 +57987 -0.091217041015625 +57988 -0.445709228515625 +57989 -0.106292724609375 +57990 -0.535064697265625 +57991 -0.12615966796875 +57992 -0.629058837890625 +57993 -0.147003173828125 +57994 -0.697601318359375 +57995 -0.161865234375 +57996 -0.70391845703125 +57997 -0.16229248046875 +57998 -0.6424560546875 +57999 -0.14703369140625 +58000 -0.491241455078125 +58001 -0.111053466796875 +58002 -0.265716552734375 +58003 -0.058013916015625 +58004 -0.023712158203125 +58005 -0.0013427734375 +58006 0.201751708984375 +58007 0.051239013671875 +58008 0.375823974609375 +58009 0.09161376953125 +58010 0.485076904296875 +58011 0.11669921875 +58012 0.56884765625 +58013 0.135650634765625 +58014 0.634765625 +58015 0.1502685546875 +58016 0.63763427734375 +58017 0.150115966796875 +58018 0.5660400390625 +58019 0.132598876953125 +58020 0.4720458984375 +58021 0.109832763671875 +58022 0.40692138671875 +58023 0.093780517578125 +58024 0.3778076171875 +58025 0.08612060546875 +58026 0.376953125 +58027 0.085113525390625 +58028 0.371978759765625 +58029 0.083282470703125 +58030 0.313140869140625 +58031 0.069122314453125 +58032 0.184417724609375 +58033 0.0389404296875 +58034 0.011199951171875 +58035 -0.001312255859375 +58036 -0.171051025390625 +58037 -0.04339599609375 +58038 -0.33740234375 +58039 -0.08154296875 +58040 -0.47198486328125 +58041 -0.11212158203125 +58042 -0.560394287109375 +58043 -0.1318359375 +58044 -0.58056640625 +58045 -0.135650634765625 +58046 -0.54754638671875 +58047 -0.1270751953125 +58048 -0.508575439453125 +58049 -0.117156982421875 +58050 -0.459503173828125 +58051 -0.104949951171875 +58052 -0.394378662109375 +58053 -0.089111328125 +58054 -0.35260009765625 +58055 -0.078765869140625 +58056 -0.31170654296875 +58057 -0.06878662109375 +58058 -0.197418212890625 +58059 -0.04193115234375 +58060 -0.007965087890625 +58061 0.00213623046875 +58062 0.207489013671875 +58063 0.052001953125 +58064 0.409210205078125 +58065 0.09844970703125 +58066 0.57208251953125 +58067 0.135711669921875 +58068 0.66595458984375 +58069 0.156829833984375 +58070 0.65875244140625 +58071 0.154388427734375 +58072 0.56744384765625 +58073 0.132354736328125 +58074 0.431396484375 +58075 0.099945068359375 +58076 0.29443359375 +58077 0.067352294921875 +58078 0.182464599609375 +58079 0.040618896484375 +58080 0.06365966796875 +58081 0.012420654296875 +58082 -0.075958251953125 +58083 -0.020416259765625 +58084 -0.189422607421875 +58085 -0.0469970703125 +58086 -0.271942138671875 +58087 -0.066192626953125 +58088 -0.342529296875 +58089 -0.082427978515625 +58090 -0.364166259765625 +58091 -0.087158203125 +58092 -0.327239990234375 +58093 -0.078155517578125 +58094 -0.2769775390625 +58095 -0.06591796875 +58096 -0.253692626953125 +58097 -0.059844970703125 +58098 -0.24365234375 +58099 -0.056793212890625 +58100 -0.1983642578125 +58101 -0.0455322265625 +58102 -0.116241455078125 +58103 -0.025726318359375 +58104 -0.036834716796875 +58105 -0.006591796875 +58106 0.034881591796875 +58107 0.0106201171875 +58108 0.09124755859375 +58109 0.02410888671875 +58110 0.10888671875 +58111 0.028411865234375 +58112 0.125518798828125 +58113 0.032684326171875 +58114 0.15771484375 +58115 0.0408935546875 +58116 0.17828369140625 +58117 0.046234130859375 +58118 0.17108154296875 +58119 0.044342041015625 +58120 0.129974365234375 +58121 0.03350830078125 +58122 0.082427978515625 +58123 0.02093505859375 +58124 0.027679443359375 +58125 0.00640869140625 +58126 -0.065643310546875 +58127 -0.018341064453125 +58128 -0.15936279296875 +58129 -0.043212890625 +58130 -0.21307373046875 +58131 -0.057525634765625 +58132 -0.234649658203125 +58133 -0.063323974609375 +58134 -0.2001953125 +58135 -0.054290771484375 +58136 -0.119171142578125 +58137 -0.032928466796875 +58138 -0.024749755859375 +58139 -0.00799560546875 +58140 0.085784912109375 +58141 0.021240234375 +58142 0.178131103515625 +58143 0.04571533203125 +58144 0.215576171875 +58145 0.055755615234375 +58146 0.211456298828125 +58147 0.05487060546875 +58148 0.17523193359375 +58149 0.045562744140625 +58150 0.128753662109375 +58151 0.033599853515625 +58152 0.1019287109375 +58153 0.02685546875 +58154 0.0743408203125 +58155 0.0198974609375 +58156 0.04327392578125 +58157 0.011993408203125 +58158 0.038177490234375 +58159 0.010894775390625 +58160 0.076263427734375 +58161 0.021148681640625 +58162 0.14105224609375 +58163 0.03839111328125 +58164 0.186431884765625 +58165 0.050445556640625 +58166 0.188812255859375 +58167 0.051055908203125 +58168 0.1390380859375 +58169 0.037841796875 +58170 0.041778564453125 +58171 0.012054443359375 +58172 -0.079437255859375 +58173 -0.02008056640625 +58174 -0.219390869140625 +58175 -0.05718994140625 +58176 -0.367828369140625 +58177 -0.096527099609375 +58178 -0.494873046875 +58179 -0.130218505859375 +58180 -0.556243896484375 +58181 -0.14654541015625 +58182 -0.508697509765625 +58183 -0.13409423828125 +58184 -0.3756103515625 +58185 -0.09906005859375 +58186 -0.218902587890625 +58187 -0.057769775390625 +58188 -0.063751220703125 +58189 -0.016845703125 +58190 0.091552734375 +58191 0.024078369140625 +58192 0.23602294921875 +58193 0.0621337890625 +58194 0.342987060546875 +58195 0.09027099609375 +58196 0.39520263671875 +58197 0.103973388671875 +58198 0.389373779296875 +58199 0.10235595703125 +58200 0.324249267578125 +58201 0.085113525390625 +58202 0.224090576171875 +58203 0.05865478515625 +58204 0.124267578125 +58205 0.0323486328125 +58206 0.037078857421875 +58207 0.0093994140625 +58208 -0.010101318359375 +58209 -0.0029296875 +58210 -0.019439697265625 +58211 -0.0052490234375 +58212 -0.022796630859375 +58213 -0.0059814453125 +58214 -0.001556396484375 +58215 -0.00018310546875 +58216 0.056304931640625 +58217 0.0152587890625 +58218 0.106719970703125 +58219 0.0286865234375 +58220 0.096893310546875 +58221 0.026153564453125 +58222 0.042694091796875 +58223 0.011871337890625 +58224 -0.018035888671875 +58225 -0.004150390625 +58226 -0.07586669921875 +58227 -0.0194091796875 +58228 -0.11944580078125 +58229 -0.030914306640625 +58230 -0.15972900390625 +58231 -0.04156494140625 +58232 -0.202606201171875 +58233 -0.05291748046875 +58234 -0.24859619140625 +58235 -0.0650634765625 +58236 -0.30517578125 +58237 -0.079986572265625 +58238 -0.36212158203125 +58239 -0.095001220703125 +58240 -0.39141845703125 +58241 -0.102752685546875 +58242 -0.35528564453125 +58243 -0.093231201171875 +58244 -0.249969482421875 +58245 -0.065460205078125 +58246 -0.092864990234375 +58247 -0.024017333984375 +58248 0.08905029296875 +58249 0.02392578125 +58250 0.2352294921875 +58251 0.062408447265625 +58252 0.318817138671875 +58253 0.084381103515625 +58254 0.358642578125 +58255 0.09478759765625 +58256 0.347747802734375 +58257 0.091796875 +58258 0.28564453125 +58259 0.075286865234375 +58260 0.223175048828125 +58261 0.058685302734375 +58262 0.196746826171875 +58263 0.051605224609375 +58264 0.179840087890625 +58265 0.047088623046875 +58266 0.155548095703125 +58267 0.0406494140625 +58268 0.151214599609375 +58269 0.039520263671875 +58270 0.156951904296875 +58271 0.04107666015625 +58272 0.13177490234375 +58273 0.03448486328125 +58274 0.100799560546875 +58275 0.026397705078125 +58276 0.087127685546875 +58277 0.02288818359375 +58278 0.05487060546875 +58279 0.01446533203125 +58280 -0.009002685546875 +58281 -0.002288818359375 +58282 -0.10400390625 +58283 -0.027252197265625 +58284 -0.229400634765625 +58285 -0.06024169921875 +58286 -0.35552978515625 +58287 -0.093414306640625 +58288 -0.441925048828125 +58289 -0.1160888671875 +58290 -0.473846435546875 +58291 -0.124420166015625 +58292 -0.464813232421875 +58293 -0.1219482421875 +58294 -0.419097900390625 +58295 -0.10980224609375 +58296 -0.334320068359375 +58297 -0.087371826171875 +58298 -0.227935791015625 +58299 -0.059234619140625 +58300 -0.12347412109375 +58301 -0.031646728515625 +58302 -0.02764892578125 +58303 -0.00634765625 +58304 0.077667236328125 +58305 0.021392822265625 +58306 0.2132568359375 +58307 0.05706787109375 +58308 0.38885498046875 +58309 0.103271484375 +58310 0.582794189453125 +58311 0.154296875 +58312 0.734039306640625 +58313 0.19403076171875 +58314 0.800140380859375 +58315 0.21124267578125 +58316 0.7783203125 +58317 0.205230712890625 +58318 0.6651611328125 +58319 0.17510986328125 +58320 0.45965576171875 +58321 0.12066650390625 +58322 0.199188232421875 +58323 0.051788330078125 +58324 -0.050689697265625 +58325 -0.01422119140625 +58326 -0.23297119140625 +58327 -0.06231689453125 +58328 -0.33013916015625 +58329 -0.087890625 +58330 -0.368408203125 +58331 -0.09783935546875 +58332 -0.378936767578125 +58333 -0.10040283203125 +58334 -0.376983642578125 +58335 -0.099639892578125 +58336 -0.37969970703125 +58337 -0.10009765625 +58338 -0.391510009765625 +58339 -0.102935791015625 +58340 -0.385345458984375 +58341 -0.101043701171875 +58342 -0.3419189453125 +58343 -0.089324951171875 +58344 -0.28289794921875 +58345 -0.073516845703125 +58346 -0.251617431640625 +58347 -0.0650634765625 +58348 -0.266143798828125 +58349 -0.068756103515625 +58350 -0.273345947265625 +58351 -0.070587158203125 +58352 -0.216796875 +58353 -0.055633544921875 +58354 -0.128265380859375 +58355 -0.03228759765625 +58356 -0.068145751953125 +58357 -0.0164794921875 +58358 -0.0430908203125 +58359 -0.009979248046875 +58360 -0.024444580078125 +58361 -0.005218505859375 +58362 0.020721435546875 +58363 0.0064697265625 +58364 0.124481201171875 +58365 0.0335693359375 +58366 0.25787353515625 +58367 0.068450927734375 +58368 0.379119873046875 +58369 0.100677490234375 +58370 0.47991943359375 +58371 0.127899169921875 +58372 0.5281982421875 +58373 0.140289306640625 +58374 0.511138916015625 +58375 0.134246826171875 +58376 0.456207275390625 +58377 0.118011474609375 +58378 0.407470703125 +58379 0.104644775390625 +58380 0.383758544921875 +58381 0.099639892578125 +58382 0.35687255859375 +58383 0.094482421875 +58384 0.31182861328125 +58385 0.0845947265625 +58386 0.250885009765625 +58387 0.070404052734375 +58388 0.1654052734375 +58389 0.04913330078125 +58390 0.035247802734375 +58391 0.01458740234375 +58392 -0.142059326171875 +58393 -0.0341796875 +58394 -0.33563232421875 +58395 -0.0882568359375 +58396 -0.5345458984375 +58397 -0.14453125 +58398 -0.72186279296875 +58399 -0.198150634765625 +58400 -0.836669921875 +58401 -0.23114013671875 +58402 -0.8326416015625 +58403 -0.2298583984375 +58404 -0.7296142578125 +58405 -0.200164794921875 +58406 -0.582550048828125 +58407 -0.15826416015625 +58408 -0.440093994140625 +58409 -0.118438720703125 +58410 -0.324310302734375 +58411 -0.08709716796875 +58412 -0.20147705078125 +58413 -0.054046630859375 +58414 -0.044647216796875 +58415 -0.0111083984375 +58416 0.103973388671875 +58417 0.029388427734375 +58418 0.202392578125 +58419 0.055206298828125 +58420 0.264495849609375 +58421 0.07061767578125 +58422 0.338897705078125 +58423 0.09014892578125 +58424 0.443817138671875 +58425 0.11932373046875 +58426 0.545074462890625 +58427 0.14813232421875 +58428 0.6173095703125 +58429 0.169097900390625 +58430 0.6524658203125 +58431 0.179840087890625 +58432 0.66339111328125 +58433 0.184112548828125 +58434 0.6561279296875 +58435 0.183624267578125 +58436 0.606781005859375 +58437 0.171173095703125 +58438 0.501190185546875 +58439 0.1424560546875 +58440 0.352783203125 +58441 0.101318359375 +58442 0.176544189453125 +58443 0.052001953125 +58444 -0.034820556640625 +58445 -0.00775146484375 +58446 -0.258209228515625 +58447 -0.07122802734375 +58448 -0.44244384765625 +58449 -0.1234130859375 +58450 -0.5753173828125 +58451 -0.160858154296875 +58452 -0.65203857421875 +58453 -0.182220458984375 +58454 -0.641632080078125 +58455 -0.178375244140625 +58456 -0.562164306640625 +58457 -0.154754638671875 +58458 -0.458038330078125 +58459 -0.124481201171875 +58460 -0.350555419921875 +58461 -0.093780517578125 +58462 -0.260528564453125 +58463 -0.0687255859375 +58464 -0.192108154296875 +58465 -0.05047607421875 +58466 -0.141937255859375 +58467 -0.03790283203125 +58468 -0.1021728515625 +58469 -0.028564453125 +58470 -0.062896728515625 +58471 -0.01934814453125 +58472 -0.011932373046875 +58473 -0.006561279296875 +58474 0.062835693359375 +58475 0.013519287109375 +58476 0.148712158203125 +58477 0.0372314453125 +58478 0.241729736328125 +58479 0.0634765625 +58480 0.34912109375 +58481 0.09442138671875 +58482 0.457305908203125 +58483 0.126129150390625 +58484 0.54388427734375 +58485 0.151947021484375 +58486 0.5728759765625 +58487 0.16119384765625 +58488 0.506591796875 +58489 0.142669677734375 +58490 0.351226806640625 +58491 0.09814453125 +58492 0.146514892578125 +58493 0.039276123046875 +58494 -0.05523681640625 +58495 -0.01849365234375 +58496 -0.21624755859375 +58497 -0.064117431640625 +58498 -0.334930419921875 +58499 -0.09722900390625 +58500 -0.402984619140625 +58501 -0.115478515625 +58502 -0.4412841796875 +58503 -0.1251220703125 +58504 -0.49578857421875 +58505 -0.139892578125 +58506 -0.5601806640625 +58507 -0.157958984375 +58508 -0.600738525390625 +58509 -0.169403076171875 +58510 -0.584228515625 +58511 -0.164398193359375 +58512 -0.47930908203125 +58513 -0.1336669921875 +58514 -0.27935791015625 +58515 -0.075225830078125 +58516 -0.0089111328125 +58517 0.003662109375 +58518 0.268798828125 +58519 0.0843505859375 +58520 0.482818603515625 +58521 0.145965576171875 +58522 0.60369873046875 +58523 0.17987060546875 +58524 0.650421142578125 +58525 0.191802978515625 +58526 0.66400146484375 +58527 0.194000244140625 +58528 0.6414794921875 +58529 0.185699462890625 +58530 0.572540283203125 +58531 0.1639404296875 +58532 0.498138427734375 +58533 0.140899658203125 +58534 0.439453125 +58535 0.1229248046875 +58536 0.375518798828125 +58537 0.10382080078125 +58538 0.274505615234375 +58539 0.07415771484375 +58540 0.1087646484375 +58541 0.025726318359375 +58542 -0.099395751953125 +58543 -0.034912109375 +58544 -0.3182373046875 +58545 -0.098388671875 +58546 -0.5489501953125 +58547 -0.165191650390625 +58548 -0.7738037109375 +58549 -0.2301025390625 +58550 -0.86383056640625 +58551 -0.277557373046875 +58552 -0.870391845703125 +58553 -0.297821044921875 +58554 -0.86895751953125 +58555 -0.296234130859375 +58556 -0.861053466796875 +58557 -0.276763916015625 +58558 -0.765869140625 +58559 -0.234344482421875 +58560 -0.5301513671875 +58561 -0.165679931640625 +58562 -0.214691162109375 +58563 -0.072906494140625 +58564 0.137359619140625 +58565 0.031219482421875 +58566 0.474822998046875 +58567 0.13153076171875 +58568 0.76239013671875 +58569 0.217559814453125 +58570 0.867462158203125 +58571 0.281341552734375 +58572 0.870361328125 +58573 0.323089599609375 +58574 0.86480712890625 +58575 0.339447021484375 +58576 0.831817626953125 +58577 0.332061767578125 +58578 0.677581787109375 +58579 0.308258056640625 +58580 0.495880126953125 +58581 0.269805908203125 +58582 0.30767822265625 +58583 0.2222900390625 +58584 0.116180419921875 +58585 0.166412353515625 +58586 -0.110748291015625 +58587 0.09283447265625 +58588 -0.381805419921875 +58589 -0.000457763671875 +58590 -0.6572265625 +58591 -0.10076904296875 +58592 -0.857421875 +58593 -0.19036865234375 +58594 -0.870391845703125 +58595 -0.256591796875 +58596 -0.870391845703125 +58597 -0.29736328125 +58598 -0.86444091796875 +58599 -0.320709228515625 +58600 -0.85723876953125 +58601 -0.337249755859375 +58602 -0.790008544921875 +58603 -0.341644287109375 +58604 -0.62847900390625 +58605 -0.31787109375 +58606 -0.3956298828125 +58607 -0.26507568359375 +58608 -0.126708984375 +58609 -0.19305419921875 +58610 0.150115966796875 +58611 -0.109954833984375 +58612 0.424041748046875 +58613 -0.019317626953125 +58614 0.670623779296875 +58615 0.070831298828125 +58616 0.854522705078125 +58617 0.149017333984375 +58618 0.866485595703125 +58619 0.21002197265625 +58620 0.86920166015625 +58621 0.249298095703125 +58622 0.8653564453125 +58623 0.272247314453125 +58624 0.857147216796875 +58625 0.282623291015625 +58626 0.766845703125 +58627 0.2799072265625 +58628 0.628509521484375 +58629 0.266021728515625 +58630 0.462127685546875 +58631 0.23870849609375 +58632 0.297210693359375 +58633 0.20635986328125 +58634 0.14862060546875 +58635 0.17279052734375 +58636 -0.00537109375 +58637 0.130279541015625 +58638 -0.15753173828125 +58639 0.080963134765625 +58640 -0.31304931640625 +58641 0.023345947265625 +58642 -0.48876953125 +58643 -0.04754638671875 +58644 -0.6416015625 +58645 -0.11663818359375 +58646 -0.751373291015625 +58647 -0.176116943359375 +58648 -0.84619140625 +58649 -0.233795166015625 +58650 -0.861297607421875 +58651 -0.285064697265625 +58652 -0.863250732421875 +58653 -0.319183349609375 +58654 -0.856597900390625 +58655 -0.3258056640625 +58656 -0.7498779296875 +58657 -0.30889892578125 +58658 -0.624542236328125 +58659 -0.287353515625 +58660 -0.47808837890625 +58661 -0.2537841796875 +58662 -0.253387451171875 +58663 -0.1888427734375 +58664 0.003692626953125 +58665 -0.10723876953125 +58666 0.2257080078125 +58667 -0.0311279296875 +58668 0.427154541015625 +58669 0.04388427734375 +58670 0.643218994140625 +58671 0.128662109375 +58672 0.855926513671875 +58673 0.220306396484375 +58674 0.870361328125 +58675 0.300018310546875 +58676 0.870361328125 +58677 0.3516845703125 +58678 0.862762451171875 +58679 0.377777099609375 +58680 0.79669189453125 +58681 0.37738037109375 +58682 0.595794677734375 +58683 0.347412109375 +58684 0.362152099609375 +58685 0.29742431640625 +58686 0.1270751953125 +58687 0.2364501953125 +58688 -0.086944580078125 +58689 0.171295166015625 +58690 -0.2784423828125 +58691 0.10247802734375 +58692 -0.484832763671875 +58693 0.018402099609375 +58694 -0.729583740234375 +58695 -0.087432861328125 +58696 -0.86688232421875 +58697 -0.19866943359375 +58698 -0.870391845703125 +58699 -0.294708251953125 +58700 -0.86859130859375 +58701 -0.37408447265625 +58702 -0.86279296875 +58703 -0.43621826171875 +58704 -0.817962646484375 +58705 -0.46942138671875 +58706 -0.6116943359375 +58707 -0.4588623046875 +58708 -0.3128662109375 +58709 -0.402191162109375 +58710 0.039398193359375 +58711 -0.310455322265625 +58712 0.422821044921875 +58713 -0.190155029296875 +58714 0.805145263671875 +58715 -0.0521240234375 +58716 0.870361328125 +58717 0.081390380859375 +58718 0.870361328125 +58719 0.191802978515625 +58720 0.860015869140625 +58721 0.275421142578125 +58722 0.727935791015625 +58723 0.329803466796875 +58724 0.48114013671875 +58725 0.353179931640625 +58726 0.2059326171875 +58727 0.35357666015625 +58728 -0.06103515625 +58729 0.3385009765625 +58730 -0.29913330078125 +58731 0.311248779296875 +58732 -0.516204833984375 +58733 0.26708984375 +58734 -0.7252197265625 +58735 0.2010498046875 +58736 -0.85980224609375 +58737 0.12127685546875 +58738 -0.870391845703125 +58739 0.0390625 +58740 -0.870391845703125 +58741 -0.035858154296875 +58742 -0.858062744140625 +58743 -0.087493896484375 +58744 -0.673004150390625 +58745 -0.11444091796875 +58746 -0.42694091796875 +58747 -0.133941650390625 +58748 -0.2100830078125 +58749 -0.16046142578125 +58750 -0.0362548828125 +58751 -0.193267822265625 +58752 0.10943603515625 +58753 -0.222808837890625 +58754 0.23516845703125 +58755 -0.242523193359375 +58756 0.373687744140625 +58757 -0.23883056640625 +58758 0.517791748046875 +58759 -0.212371826171875 +58760 0.602783203125 +58761 -0.183807373046875 +58762 0.635711669921875 +58763 -0.1514892578125 +58764 0.655181884765625 +58765 -0.10455322265625 +58766 0.65948486328125 +58767 -0.04632568359375 +58768 0.651275634765625 +58769 0.020477294921875 +58770 0.61846923828125 +58771 0.087738037109375 +58772 0.53753662109375 +58773 0.143218994140625 +58774 0.404144287109375 +58775 0.180938720703125 +58776 0.22186279296875 +58777 0.1976318359375 +58778 0.003997802734375 +58779 0.19366455078125 +58780 -0.22100830078125 +58781 0.1749267578125 +58782 -0.42449951171875 +58783 0.148162841796875 +58784 -0.579833984375 +58785 0.120391845703125 +58786 -0.641876220703125 +58787 0.105621337890625 +58788 -0.6177978515625 +58789 0.1016845703125 +58790 -0.575531005859375 +58791 0.08746337890625 +58792 -0.526336669921875 +58793 0.061248779296875 +58794 -0.42645263671875 +58795 0.04010009765625 +58796 -0.2581787109375 +58797 0.0330810546875 +58798 -0.068695068359375 +58799 0.02838134765625 +58800 0.09222412109375 +58801 0.013458251953125 +58802 0.232147216796875 +58803 -0.0054931640625 +58804 0.3509521484375 +58805 -0.0250244140625 +58806 0.410064697265625 +58807 -0.0548095703125 +58808 0.372955322265625 +58809 -0.1043701171875 +58810 0.2554931640625 +58811 -0.16680908203125 +58812 0.10711669921875 +58813 -0.225006103515625 +58814 -0.052886962890625 +58815 -0.27252197265625 +58816 -0.186279296875 +58817 -0.2974853515625 +58818 -0.23291015625 +58819 -0.2816162109375 +58820 -0.209442138671875 +58821 -0.232452392578125 +58822 -0.174163818359375 +58823 -0.171630859375 +58824 -0.126739501953125 +58825 -0.10198974609375 +58826 -0.048126220703125 +58827 -0.020355224609375 +58828 0.0426025390625 +58829 0.063873291015625 +58830 0.10748291015625 +58831 0.135345458984375 +58832 0.1409912109375 +58833 0.189605712890625 +58834 0.19708251953125 +58835 0.2421875 +58836 0.273651123046875 +58837 0.29083251953125 +58838 0.31768798828125 +58839 0.317169189453125 +58840 0.341094970703125 +58841 0.32476806640625 +58842 0.368011474609375 +58843 0.321929931640625 +58844 0.37249755859375 +58845 0.301116943359375 +58846 0.30072021484375 +58847 0.246185302734375 +58848 0.1517333984375 +58849 0.15875244140625 +58850 -0.01470947265625 +58851 0.060760498046875 +58852 -0.1883544921875 +58853 -0.041900634765625 +58854 -0.372711181640625 +58855 -0.147796630859375 +58856 -0.51397705078125 +58857 -0.236846923828125 +58858 -0.57177734375 +58859 -0.293548583984375 +58860 -0.53948974609375 +58861 -0.313812255859375 +58862 -0.43511962890625 +58863 -0.30206298828125 +58864 -0.2962646484375 +58865 -0.2696533203125 +58866 -0.161102294921875 +58867 -0.228668212890625 +58868 -0.0435791015625 +58869 -0.183746337890625 +58870 0.060394287109375 +58871 -0.134185791015625 +58872 0.13665771484375 +58873 -0.08575439453125 +58874 0.170135498046875 +58875 -0.04486083984375 +58876 0.16552734375 +58877 -0.01177978515625 +58878 0.15728759765625 +58879 0.022705078125 +58880 0.150787353515625 +58881 0.058074951171875 +58882 0.12200927734375 +58883 0.0843505859375 +58884 0.080108642578125 +58885 0.10296630859375 +58886 0.05126953125 +58887 0.121185302734375 +58888 0.062896728515625 +58889 0.147125244140625 +58890 0.09271240234375 +58891 0.171905517578125 +58892 0.092987060546875 +58893 0.17822265625 +58894 0.07855224609375 +58895 0.171142578125 +58896 0.06427001953125 +58897 0.15625 +58898 0.0347900390625 +58899 0.12890625 +58900 -0.01171875 +58901 0.089630126953125 +58902 -0.056060791015625 +58903 0.04656982421875 +58904 -0.055511474609375 +58905 0.016326904296875 +58906 -0.010467529296875 +58907 0.00054931640625 +58908 0.02508544921875 +58909 -0.017852783203125 +58910 0.025665283203125 +58911 -0.046142578125 +58912 0.017333984375 +58913 -0.073699951171875 +58914 0.00189208984375 +58915 -0.098663330078125 +58916 -0.03173828125 +58917 -0.123992919921875 +58918 -0.071502685546875 +58919 -0.144927978515625 +58920 -0.13543701171875 +58921 -0.16754150390625 +58922 -0.219970703125 +58923 -0.1907958984375 +58924 -0.300506591796875 +58925 -0.20660400390625 +58926 -0.376312255859375 +58927 -0.21551513671875 +58928 -0.416107177734375 +58929 -0.207733154296875 +58930 -0.371124267578125 +58931 -0.16748046875 +58932 -0.242279052734375 +58933 -0.09649658203125 +58934 -0.069732666015625 +58935 -0.01031494140625 +58936 0.125640869140625 +58937 0.082305908203125 +58938 0.31268310546875 +58939 0.169219970703125 +58940 0.45501708984375 +58941 0.236572265625 +58942 0.554779052734375 +58943 0.2843017578125 +58944 0.61065673828125 +58945 0.3114013671875 +58946 0.610931396484375 +58947 0.313507080078125 +58948 0.531463623046875 +58949 0.282196044921875 +58950 0.3883056640625 +58951 0.223480224609375 +58952 0.23468017578125 +58953 0.15655517578125 +58954 0.095245361328125 +58955 0.0909423828125 +58956 -0.00396728515625 +58957 0.036773681640625 +58958 -0.04852294921875 +58959 0.00018310546875 +58960 -0.055145263671875 +58961 -0.0234375 +58962 -0.0758056640625 +58963 -0.051116943359375 +58964 -0.138702392578125 +58965 -0.091644287109375 +58966 -0.209197998046875 +58967 -0.131927490234375 +58968 -0.289031982421875 +58969 -0.17181396484375 +58970 -0.37884521484375 +58971 -0.210968017578125 +58972 -0.456329345703125 +58973 -0.241302490234375 +58974 -0.51641845703125 +58975 -0.260986328125 +58976 -0.519287109375 +58977 -0.256256103515625 +58978 -0.458251953125 +58979 -0.225250244140625 +58980 -0.384796142578125 +58981 -0.186614990234375 +58982 -0.323699951171875 +58983 -0.14984130859375 +58984 -0.269287109375 +58985 -0.11383056640625 +58986 -0.1951904296875 +58987 -0.0703125 +58988 -0.100006103515625 +58989 -0.019805908203125 +58990 -0.01055908203125 +58991 0.027374267578125 +58992 0.1033935546875 +58993 0.080963134765625 +58994 0.24908447265625 +58995 0.142852783203125 +58996 0.373199462890625 +58997 0.19384765625 +58998 0.45806884765625 +58999 0.227447509765625 +59000 0.511474609375 +59001 0.24627685546875 +59002 0.565399169921875 +59003 0.261627197265625 +59004 0.61138916015625 +59005 0.27081298828125 +59006 0.5897216796875 +59007 0.25341796875 +59008 0.4906005859375 +59009 0.20660400390625 +59010 0.33148193359375 +59011 0.137237548828125 +59012 0.147796630859375 +59013 0.058502197265625 +59014 -0.01873779296875 +59015 -0.01416015625 +59016 -0.140289306640625 +59017 -0.070220947265625 +59018 -0.191986083984375 +59019 -0.10028076171875 +59020 -0.184295654296875 +59021 -0.107391357421875 +59022 -0.161834716796875 +59023 -0.106689453125 +59024 -0.166595458984375 +59025 -0.112548828125 +59026 -0.19390869140625 +59027 -0.123199462890625 +59028 -0.22442626953125 +59029 -0.13189697265625 +59030 -0.279754638671875 +59031 -0.146392822265625 +59032 -0.3389892578125 +59033 -0.15972900390625 +59034 -0.3543701171875 +59035 -0.155670166015625 +59036 -0.348175048828125 +59037 -0.142578125 +59038 -0.32598876953125 +59039 -0.123077392578125 +59040 -0.2581787109375 +59041 -0.08746337890625 +59042 -0.139801025390625 +59043 -0.034637451171875 +59044 0.014617919921875 +59045 0.02972412109375 +59046 0.144378662109375 +59047 0.08380126953125 +59048 0.221038818359375 +59049 0.117218017578125 +59050 0.27069091796875 +59051 0.1387939453125 +59052 0.294036865234375 +59053 0.148651123046875 +59054 0.311767578125 +59055 0.154022216796875 +59056 0.339141845703125 +59057 0.160400390625 +59058 0.360260009765625 +59059 0.162567138671875 +59060 0.360504150390625 +59061 0.155731201171875 +59062 0.308380126953125 +59063 0.128936767578125 +59064 0.18170166015625 +59065 0.074615478515625 +59066 0.0047607421875 +59067 0.00201416015625 +59068 -0.17559814453125 +59069 -0.071502685546875 +59070 -0.3143310546875 +59071 -0.129302978515625 +59072 -0.36785888671875 +59073 -0.155303955078125 +59074 -0.36248779296875 +59075 -0.15869140625 +59076 -0.343536376953125 +59077 -0.155487060546875 +59078 -0.3018798828125 +59079 -0.142303466796875 +59080 -0.231414794921875 +59081 -0.11688232421875 +59082 -0.117645263671875 +59083 -0.07403564453125 +59084 0.007049560546875 +59085 -0.02557373046875 +59086 0.087982177734375 +59087 0.008575439453125 +59088 0.13946533203125 +59089 0.033233642578125 +59090 0.17425537109375 +59091 0.052642822265625 +59092 0.188201904296875 +59093 0.06488037109375 +59094 0.171234130859375 +59095 0.06591796875 +59096 0.118438720703125 +59097 0.0535888671875 +59098 0.05706787109375 +59099 0.03741455078125 +59100 -0.010711669921875 +59101 0.017822265625 +59102 -0.0914306640625 +59103 -0.007720947265625 +59104 -0.162322998046875 +59105 -0.03118896484375 +59106 -0.194549560546875 +59107 -0.042266845703125 +59108 -0.1492919921875 +59109 -0.026947021484375 +59110 -0.02166748046875 +59111 0.016571044921875 +59112 0.124053955078125 +59113 0.065338134765625 +59114 0.211151123046875 +59115 0.091949462890625 +59116 0.240447998046875 +59117 0.097015380859375 +59118 0.242218017578125 +59119 0.091766357421875 +59120 0.2257080078125 +59121 0.079864501953125 +59122 0.194366455078125 +59123 0.062896728515625 +59124 0.115509033203125 +59125 0.02935791015625 +59126 0.0128173828125 +59127 -0.01190185546875 +59128 -0.053802490234375 +59129 -0.039093017578125 +59130 -0.110626220703125 +59131 -0.061553955078125 +59132 -0.199493408203125 +59133 -0.094268798828125 +59134 -0.29437255859375 +59135 -0.12786865234375 +59136 -0.33221435546875 +59137 -0.139373779296875 +59138 -0.27972412109375 +59139 -0.116180419921875 +59140 -0.185333251953125 +59141 -0.076995849609375 +59142 -0.128204345703125 +59143 -0.052642822265625 +59144 -0.115692138671875 +59145 -0.0458984375 +59146 -0.116455078125 +59147 -0.044403076171875 +59148 -0.105926513671875 +59149 -0.038543701171875 +59150 -0.053955078125 +59151 -0.016510009765625 +59152 0.048797607421875 +59153 0.025238037109375 +59154 0.157318115234375 +59155 0.06903076171875 +59156 0.212005615234375 +59157 0.0914306640625 +59158 0.218475341796875 +59159 0.0946044921875 +59160 0.23724365234375 +59161 0.102203369140625 +59162 0.30535888671875 +59163 0.12872314453125 +59164 0.38128662109375 +59165 0.157867431640625 +59166 0.404449462890625 +59167 0.165924072265625 +59168 0.3944091796875 +59169 0.160614013671875 +59170 0.3885498046875 +59171 0.15667724609375 +59172 0.362640380859375 +59173 0.144683837890625 +59174 0.27362060546875 +59175 0.10784912109375 +59176 0.11712646484375 +59177 0.044586181640625 +59178 -0.054901123046875 +59179 -0.024627685546875 +59180 -0.19085693359375 +59181 -0.079437255859375 +59182 -0.28570556640625 +59183 -0.1177978515625 +59184 -0.339263916015625 +59185 -0.139617919921875 +59186 -0.3775634765625 +59187 -0.155029296875 +59188 -0.445709228515625 +59189 -0.1817626953125 +59190 -0.535064697265625 +59191 -0.2164306640625 +59192 -0.629058837890625 +59193 -0.252532958984375 +59194 -0.697601318359375 +59195 -0.2783203125 +59196 -0.70391845703125 +59197 -0.279449462890625 +59198 -0.6424560546875 +59199 -0.25384521484375 +59200 -0.491241455078125 +59201 -0.1929931640625 +59202 -0.265716552734375 +59203 -0.10302734375 +59204 -0.023712158203125 +59205 -0.006683349609375 +59206 0.201751708984375 +59207 0.082977294921875 +59208 0.375823974609375 +59209 0.152252197265625 +59210 0.485076904296875 +59211 0.19580078125 +59212 0.56884765625 +59213 0.229034423828125 +59214 0.634765625 +59215 0.25494384765625 +59216 0.63763427734375 +59217 0.25579833984375 +59218 0.5660400390625 +59219 0.227142333984375 +59220 0.4720458984375 +59221 0.189422607421875 +59222 0.40692138671875 +59223 0.16278076171875 +59224 0.3778076171875 +59225 0.150115966796875 +59226 0.376953125 +59227 0.1484375 +59228 0.371978759765625 +59229 0.1451416015625 +59230 0.313140869140625 +59231 0.12078857421875 +59232 0.184417724609375 +59233 0.06915283203125 +59234 0.011199951171875 +59235 0.000274658203125 +59236 -0.171051025390625 +59237 -0.071868896484375 +59238 -0.33740234375 +59239 -0.137451171875 +59240 -0.47198486328125 +59241 -0.19024658203125 +59242 -0.560394287109375 +59243 -0.224639892578125 +59244 -0.58056640625 +59245 -0.23199462890625 +59246 -0.54754638671875 +59247 -0.21826171875 +59248 -0.508575439453125 +59249 -0.2020263671875 +59250 -0.459503173828125 +59251 -0.18170166015625 +59252 -0.394378662109375 +59253 -0.155029296875 +59254 -0.35260009765625 +59255 -0.137481689453125 +59256 -0.31170654296875 +59257 -0.120330810546875 +59258 -0.197418212890625 +59259 -0.07452392578125 +59260 -0.007965087890625 +59261 0.00054931640625 +59262 0.207489013671875 +59263 0.0855712890625 +59264 0.409210205078125 +59265 0.164947509765625 +59266 0.57208251953125 +59267 0.228851318359375 +59268 0.66595458984375 +59269 0.26544189453125 +59270 0.65875244140625 +59271 0.262176513671875 +59272 0.56744384765625 +59273 0.22576904296875 +59274 0.431396484375 +59275 0.171661376953125 +59276 0.29443359375 +59277 0.1170654296875 +59278 0.182464599609375 +59279 0.07220458984375 +59280 0.06365966796875 +59281 0.024658203125 +59282 -0.075958251953125 +59283 -0.030975341796875 +59284 -0.189422607421875 +59285 -0.076263427734375 +59286 -0.271942138671875 +59287 -0.1092529296875 +59288 -0.342529296875 +59289 -0.13739013671875 +59290 -0.364166259765625 +59291 -0.14617919921875 +59292 -0.327239990234375 +59293 -0.131805419921875 +59294 -0.2769775390625 +59295 -0.11199951171875 +59296 -0.253692626953125 +59297 -0.10260009765625 +59298 -0.24365234375 +59299 -0.09820556640625 +59300 -0.1983642578125 +59301 -0.079833984375 +59302 -0.116241455078125 +59303 -0.04693603515625 +59304 -0.036834716796875 +59305 -0.0150146484375 +59306 0.034881591796875 +59307 0.013885498046875 +59308 0.09124755859375 +59309 0.036712646484375 +59310 0.10888671875 +59311 0.0443115234375 +59312 0.125518798828125 +59313 0.051422119140625 +59314 0.15771484375 +59315 0.064483642578125 +59316 0.17828369140625 +59317 0.07281494140625 +59318 0.17108154296875 +59319 0.070068359375 +59320 0.129974365234375 +59321 0.05389404296875 +59322 0.082427978515625 +59323 0.0350341796875 +59324 0.027679443359375 +59325 0.013214111328125 +59326 -0.065643310546875 +59327 -0.0238037109375 +59328 -0.15936279296875 +59329 -0.06103515625 +59330 -0.21307373046875 +59331 -0.082611083984375 +59332 -0.234649658203125 +59333 -0.09161376953125 +59334 -0.2001953125 +59335 -0.078643798828125 +59336 -0.119171142578125 +59337 -0.04736328125 +59338 -0.024749755859375 +59339 -0.010772705078125 +59340 0.085784912109375 +59341 0.032196044921875 +59342 0.178131103515625 +59343 0.068115234375 +59344 0.215576171875 +59345 0.082611083984375 +59346 0.211456298828125 +59347 0.08087158203125 +59348 0.17523193359375 +59349 0.066680908203125 +59350 0.128753662109375 +59351 0.048583984375 +59352 0.1019287109375 +59353 0.038299560546875 +59354 0.0743408203125 +59355 0.02783203125 +59356 0.04327392578125 +59357 0.01605224609375 +59358 0.038177490234375 +59359 0.01446533203125 +59360 0.076263427734375 +59361 0.029815673828125 +59362 0.14105224609375 +59363 0.05560302734375 +59364 0.186431884765625 +59365 0.073760986328125 +59366 0.188812255859375 +59367 0.07501220703125 +59368 0.1390380859375 +59369 0.055755615234375 +59370 0.041778564453125 +59371 0.017822265625 +59372 -0.079437255859375 +59373 -0.029571533203125 +59374 -0.219390869140625 +59375 -0.084381103515625 +59376 -0.367828369140625 +59377 -0.142578125 +59378 -0.494873046875 +59379 -0.19244384765625 +59380 -0.556243896484375 +59381 -0.21661376953125 +59382 -0.508697509765625 +59383 -0.198150634765625 +59384 -0.3756103515625 +59385 -0.14617919921875 +59386 -0.218902587890625 +59387 -0.084991455078125 +59388 -0.063751220703125 +59389 -0.0244140625 +59390 0.091552734375 +59391 0.036163330078125 +59392 0.23602294921875 +59393 0.092529296875 +59394 0.342987060546875 +59395 0.13421630859375 +59396 0.39520263671875 +59397 0.15423583984375 +59398 0.389373779296875 +59399 0.1510009765625 +59400 0.324249267578125 +59401 0.123748779296875 +59402 0.224090576171875 +59403 0.08258056640625 +59404 0.124267578125 +59405 0.042236328125 +59406 0.037078857421875 +59407 0.007720947265625 +59408 -0.010101318359375 +59409 -0.009521484375 +59410 -0.019439697265625 +59411 -0.010589599609375 +59412 -0.022796630859375 +59413 -0.0091552734375 +59414 -0.001556396484375 +59415 0.002471923828125 +59416 0.056304931640625 +59417 0.029266357421875 +59418 0.106719970703125 +59419 0.052459716796875 +59420 0.096893310546875 +59421 0.049591064453125 +59422 0.042694091796875 +59423 0.027374267578125 +59424 -0.018035888671875 +59425 0.001800537109375 +59426 -0.07586669921875 +59427 -0.0230712890625 +59428 -0.11944580078125 +59429 -0.042388916015625 +59430 -0.15972900390625 +59431 -0.06072998046875 +59432 -0.202606201171875 +59433 -0.080474853515625 +59434 -0.24859619140625 +59435 -0.10174560546875 +59436 -0.30517578125 +59437 -0.12762451171875 +59438 -0.36212158203125 +59439 -0.153656005859375 +59440 -0.39141845703125 +59441 -0.167877197265625 +59442 -0.35528564453125 +59443 -0.1541748046875 +59444 -0.249969482421875 +59445 -0.11090087890625 +59446 -0.092864990234375 +59447 -0.04534912109375 +59448 0.08905029296875 +59449 0.03106689453125 +59450 0.2352294921875 +59451 0.09271240234375 +59452 0.318817138671875 +59453 0.12823486328125 +59454 0.358642578125 +59455 0.14556884765625 +59456 0.347747802734375 +59457 0.141754150390625 +59458 0.28564453125 +59459 0.116546630859375 +59460 0.223175048828125 +59461 0.091400146484375 +59462 0.196746826171875 +59463 0.0816650390625 +59464 0.179840087890625 +59465 0.076019287109375 +59466 0.155548095703125 +59467 0.067230224609375 +59468 0.151214599609375 +59469 0.0667724609375 +59470 0.156951904296875 +59471 0.070404052734375 +59472 0.13177490234375 +59473 0.0606689453125 +59474 0.100799560546875 +59475 0.048187255859375 +59476 0.087127685546875 +59477 0.042724609375 +59478 0.05487060546875 +59479 0.029083251953125 +59480 -0.009002685546875 +59481 0.001708984375 +59482 -0.10400390625 +59483 -0.03912353515625 +59484 -0.229400634765625 +59485 -0.09307861328125 +59486 -0.35552978515625 +59487 -0.14752197265625 +59488 -0.441925048828125 +59489 -0.18524169921875 +59490 -0.473846435546875 +59491 -0.199951171875 +59492 -0.464813232421875 +59493 -0.19732666015625 +59494 -0.419097900390625 +59495 -0.1790771484375 +59496 -0.334320068359375 +59497 -0.144134521484375 +59498 -0.227935791015625 +59499 -0.099853515625 +59500 -0.12347412109375 +59501 -0.056182861328125 +59502 -0.02764892578125 +59503 -0.01593017578125 +59504 0.077667236328125 +59505 0.028594970703125 +59506 0.2132568359375 +59507 0.086181640625 +59508 0.38885498046875 +59509 0.16094970703125 +59510 0.582794189453125 +59511 0.243682861328125 +59512 0.734039306640625 +59513 0.3084716796875 +59514 0.800140380859375 +59515 0.3372802734375 +59516 0.7783203125 +59517 0.328857421875 +59518 0.6651611328125 +59519 0.28173828125 +59520 0.45965576171875 +59521 0.195465087890625 +59522 0.199188232421875 +59523 0.085845947265625 +59524 -0.050689697265625 +59525 -0.019378662109375 +59526 -0.23297119140625 +59527 -0.096038818359375 +59528 -0.33013916015625 +59529 -0.136749267578125 +59530 -0.368408203125 +59531 -0.152679443359375 +59532 -0.378936767578125 +59533 -0.157012939453125 +59534 -0.376983642578125 +59535 -0.15625 +59536 -0.37969970703125 +59537 -0.157684326171875 +59538 -0.391510009765625 +59539 -0.16314697265625 +59540 -0.385345458984375 +59541 -0.1611328125 +59542 -0.3419189453125 +59543 -0.143402099609375 +59544 -0.28289794921875 +59545 -0.119110107421875 +59546 -0.251617431640625 +59547 -0.106597900390625 +59548 -0.266143798828125 +59549 -0.11346435546875 +59550 -0.273345947265625 +59551 -0.117156982421875 +59552 -0.216796875 +59553 -0.093719482421875 +59554 -0.128265380859375 +59555 -0.056549072265625 +59556 -0.068145751953125 +59557 -0.031280517578125 +59558 -0.0430908203125 +59559 -0.020721435546875 +59560 -0.024444580078125 +59561 -0.012725830078125 +59562 0.020721435546875 +59563 0.00665283203125 +59564 0.124481201171875 +59565 0.050994873046875 +59566 0.25787353515625 +59567 0.10797119140625 +59568 0.379119873046875 +59569 0.15985107421875 +59570 0.47991943359375 +59571 0.203094482421875 +59572 0.5281982421875 +59573 0.22406005859375 +59574 0.511138916015625 +59575 0.21728515625 +59576 0.456207275390625 +59577 0.194427490234375 +59578 0.407470703125 +59579 0.17413330078125 +59580 0.383758544921875 +59581 0.16436767578125 +59582 0.35687255859375 +59583 0.153167724609375 +59584 0.31182861328125 +59585 0.1341552734375 +59586 0.250885009765625 +59587 0.1082763671875 +59588 0.1654052734375 +59589 0.0718994140625 +59590 0.035247802734375 +59591 0.0164794921875 +59592 -0.142059326171875 +59593 -0.058990478515625 +59594 -0.33563232421875 +59595 -0.14141845703125 +59596 -0.5345458984375 +59597 -0.226104736328125 +59598 -0.72186279296875 +59599 -0.305877685546875 +59600 -0.836669921875 +59601 -0.3548583984375 +59602 -0.8326416015625 +59603 -0.353424072265625 +59604 -0.7296142578125 +59605 -0.309967041015625 +59606 -0.582550048828125 +59607 -0.247802734375 +59608 -0.440093994140625 +59609 -0.187530517578125 +59610 -0.324310302734375 +59611 -0.13848876953125 +59612 -0.20147705078125 +59613 -0.08636474609375 +59614 -0.044647216796875 +59615 -0.019744873046875 +59616 0.103973388671875 +59617 0.04345703125 +59618 0.202392578125 +59619 0.08538818359375 +59620 0.264495849609375 +59621 0.1119384765625 +59622 0.338897705078125 +59623 0.143707275390625 +59624 0.443817138671875 +59625 0.18841552734375 +59626 0.545074462890625 +59627 0.231536865234375 +59628 0.6173095703125 +59629 0.2623291015625 +59630 0.6524658203125 +59631 0.277374267578125 +59632 0.66339111328125 +59633 0.2821044921875 +59634 0.6561279296875 +59635 0.279052734375 +59636 0.606781005859375 +59637 0.258087158203125 +59638 0.501190185546875 +59639 0.213226318359375 +59640 0.352783203125 +59641 0.150177001953125 +59642 0.176544189453125 +59643 0.075286865234375 +59644 -0.034820556640625 +59645 -0.014495849609375 +59646 -0.258209228515625 +59647 -0.109375 +59648 -0.44244384765625 +59649 -0.18743896484375 +59650 -0.5753173828125 +59651 -0.24365234375 +59652 -0.65203857421875 +59653 -0.275848388671875 +59654 -0.641632080078125 +59655 -0.269866943359375 +59656 -0.562164306640625 +59657 -0.233856201171875 +59658 -0.458038330078125 +59659 -0.18792724609375 +59660 -0.350555419921875 +59661 -0.141571044921875 +59662 -0.260528564453125 +59663 -0.10406494140625 +59664 -0.192108154296875 +59665 -0.077056884765625 +59666 -0.141937255859375 +59667 -0.058746337890625 +59668 -0.1021728515625 +59669 -0.0452880859375 +59670 -0.062896728515625 +59671 -0.03192138671875 +59672 -0.011932373046875 +59673 -0.012847900390625 +59674 0.062835693359375 +59675 0.017669677734375 +59676 0.148712158203125 +59677 0.053985595703125 +59678 0.241729736328125 +59679 0.09442138671875 +59680 0.34912109375 +59681 0.142364501953125 +59682 0.457305908203125 +59683 0.191650390625 +59684 0.54388427734375 +59685 0.23199462890625 +59686 0.5728759765625 +59687 0.246917724609375 +59688 0.506591796875 +59689 0.2191162109375 +59690 0.351226806640625 +59691 0.151275634765625 +59692 0.146514892578125 +59693 0.06134033203125 +59694 -0.05523681640625 +59695 -0.027008056640625 +59696 -0.21624755859375 +59697 -0.09674072265625 +59698 -0.334930419921875 +59699 -0.147369384765625 +59700 -0.402984619140625 +59701 -0.17529296875 +59702 -0.4412841796875 +59703 -0.190155029296875 +59704 -0.49578857421875 +59705 -0.21307373046875 +59706 -0.5601806640625 +59707 -0.241241455078125 +59708 -0.600738525390625 +59709 -0.25933837890625 +59710 -0.584228515625 +59711 -0.252227783203125 +59712 -0.47930908203125 +59713 -0.20556640625 +59714 -0.27935791015625 +59715 -0.11627197265625 +59716 -0.0089111328125 +59717 0.00457763671875 +59718 0.268798828125 +59719 0.128326416015625 +59720 0.482818603515625 +59721 0.222808837890625 +59722 0.60369873046875 +59723 0.2747802734375 +59724 0.650421142578125 +59725 0.293060302734375 +59726 0.66400146484375 +59727 0.2965087890625 +59728 0.6414794921875 +59729 0.283905029296875 +59730 0.572540283203125 +59731 0.25067138671875 +59732 0.498138427734375 +59733 0.215545654296875 +59734 0.439453125 +59735 0.188262939453125 +59736 0.375518798828125 +59737 0.159271240234375 +59738 0.274505615234375 +59739 0.114044189453125 +59740 0.1087646484375 +59741 0.039886474609375 +59742 -0.099395751953125 +59743 -0.053131103515625 +59744 -0.3182373046875 +59745 -0.150634765625 +59746 -0.5489501953125 +59747 -0.2532958984375 +59748 -0.7738037109375 +59749 -0.353179931640625 +59750 -0.86383056640625 +59751 -0.42626953125 +59752 -0.870391845703125 +59753 -0.457550048828125 +59754 -0.86895751953125 +59755 -0.455230712890625 +59756 -0.861053466796875 +59757 -0.4254150390625 +59758 -0.765869140625 +59759 -0.36029052734375 +59760 -0.5301513671875 +59761 -0.2547607421875 +59762 -0.214691162109375 +59763 -0.112091064453125 +59764 0.137359619140625 +59765 0.048065185546875 +59766 0.474822998046875 +59767 0.202362060546875 +59768 0.76239013671875 +59769 0.33465576171875 +59770 0.867462158203125 +59771 0.432708740234375 +59772 0.870361328125 +59773 0.496856689453125 +59774 0.86480712890625 +59775 0.52197265625 +59776 0.831817626953125 +59777 0.510589599609375 +59778 0.677581787109375 +59779 0.473968505859375 +59780 0.495880126953125 +59781 0.41485595703125 +59782 0.30767822265625 +59783 0.341827392578125 +59784 0.116180419921875 +59785 0.255950927734375 +59786 -0.110748291015625 +59787 0.142822265625 +59788 -0.381805419921875 +59789 -0.000640869140625 +59790 -0.6572265625 +59791 -0.15496826171875 +59792 -0.857421875 +59793 -0.2928466796875 +59794 -0.870391845703125 +59795 -0.394775390625 +59796 -0.870391845703125 +59797 -0.45758056640625 +59798 -0.86444091796875 +59799 -0.493621826171875 +59800 -0.85723876953125 +59801 -0.519256591796875 +59802 -0.790008544921875 +59803 -0.526214599609375 +59804 -0.62847900390625 +59805 -0.489837646484375 +59806 -0.3956298828125 +59807 -0.40875244140625 +59808 -0.126708984375 +59809 -0.298004150390625 +59810 0.150115966796875 +59811 -0.170196533203125 +59812 0.424041748046875 +59813 -0.030731201171875 +59814 0.670623779296875 +59815 0.108062744140625 +59816 0.854522705078125 +59817 0.228485107421875 +59818 0.866485595703125 +59819 0.322479248046875 +59820 0.86920166015625 +59821 0.383087158203125 +59822 0.8653564453125 +59823 0.418609619140625 +59824 0.857147216796875 +59825 0.435211181640625 +59826 0.766845703125 +59827 0.431640625 +59828 0.628509521484375 +59829 0.410308837890625 +59830 0.462127685546875 +59831 0.36822509765625 +59832 0.297210693359375 +59833 0.3172607421875 +59834 0.14862060546875 +59835 0.26312255859375 +59836 -0.00537109375 +59837 0.195465087890625 +59838 -0.15753173828125 +59839 0.117767333984375 +59840 -0.31304931640625 +59841 0.0284423828125 +59842 -0.48876953125 +59843 -0.078887939453125 +59844 -0.6416015625 +59845 -0.182830810546875 +59846 -0.751373291015625 +59847 -0.2720947265625 +59848 -0.84619140625 +59849 -0.35723876953125 +59850 -0.861297607421875 +59851 -0.43157958984375 +59852 -0.863250732421875 +59853 -0.480072021484375 +59854 -0.856597900390625 +59855 -0.488372802734375 +59856 -0.7498779296875 +59857 -0.462066650390625 +59858 -0.624542236328125 +59859 -0.427642822265625 +59860 -0.47808837890625 +59861 -0.375152587890625 +59862 -0.253387451171875 +59863 -0.277984619140625 +59864 0.003692626953125 +59865 -0.157012939453125 +59866 0.2257080078125 +59867 -0.04345703125 +59868 0.427154541015625 +59869 0.068359375 +59870 0.643218994140625 +59871 0.193145751953125 +59872 0.855926513671875 +59873 0.326507568359375 +59874 0.870361328125 +59875 0.4420166015625 +59876 0.870361328125 +59877 0.51702880859375 +59878 0.862762451171875 +59879 0.55487060546875 +59880 0.79669189453125 +59881 0.554229736328125 +59882 0.595794677734375 +59883 0.5108642578125 +59884 0.362152099609375 +59885 0.438140869140625 +59886 0.1270751953125 +59887 0.34893798828125 +59888 -0.086944580078125 +59889 0.252960205078125 +59890 -0.2784423828125 +59891 0.151214599609375 +59892 -0.484832763671875 +59893 0.027923583984375 +59894 -0.729583740234375 +59895 -0.125579833984375 +59896 -0.86688232421875 +59897 -0.286163330078125 +59898 -0.870391845703125 +59899 -0.424896240234375 +59900 -0.86859130859375 +59901 -0.53948974609375 +59902 -0.86279296875 +59903 -0.62896728515625 +59904 -0.817962646484375 +59905 -0.677001953125 +59906 -0.6116943359375 +59907 -0.66253662109375 +59908 -0.3128662109375 +59909 -0.58209228515625 +59910 0.039398193359375 +59911 -0.4512939453125 +59912 0.422821044921875 +59913 -0.279052734375 +59914 0.805145263671875 +59915 -0.080780029296875 +59916 0.870361328125 +59917 0.111053466796875 +59918 0.870361328125 +59919 0.26934814453125 +59920 0.860015869140625 +59921 0.388946533203125 +59922 0.727935791015625 +59923 0.466552734375 +59924 0.48114013671875 +59925 0.499664306640625 +59926 0.2059326171875 +59927 0.500244140625 +59928 -0.06103515625 +59929 0.479339599609375 +59930 -0.29913330078125 +59931 0.4417724609375 +59932 -0.516204833984375 +59933 0.380279541015625 +59934 -0.7252197265625 +59935 0.287109375 +59936 -0.85980224609375 +59937 0.174072265625 +59938 -0.870391845703125 +59939 0.0576171875 +59940 -0.870391845703125 +59941 -0.048126220703125 +59942 -0.858062744140625 +59943 -0.11968994140625 +59944 -0.673004150390625 +59945 -0.1552734375 +59946 -0.42694091796875 +59947 -0.180694580078125 +59948 -0.2100830078125 +59949 -0.21771240234375 +59950 -0.0362548828125 +59951 -0.265350341796875 +59952 0.10943603515625 +59953 -0.309417724609375 +59954 0.23516845703125 +59955 -0.340087890625 +59956 0.373687744140625 +59957 -0.3370361328125 +59958 0.517791748046875 +59959 -0.30108642578125 +59960 0.602783203125 +59961 -0.262786865234375 +59962 0.635711669921875 +59963 -0.21942138671875 +59964 0.655181884765625 +59965 -0.154510498046875 +59966 0.65948486328125 +59967 -0.072723388671875 +59968 0.651275634765625 +59969 0.02215576171875 +59970 0.61846923828125 +59971 0.1182861328125 +59972 0.53753662109375 +59973 0.19769287109375 +59974 0.404144287109375 +59975 0.251617431640625 +59976 0.22186279296875 +59977 0.275299072265625 +59978 0.003997802734375 +59979 0.269287109375 +59980 -0.22100830078125 +59981 0.242340087890625 +59982 -0.42449951171875 +59983 0.204376220703125 +59984 -0.579833984375 +59985 0.16571044921875 +59986 -0.641876220703125 +59987 0.14703369140625 +59988 -0.6177978515625 +59989 0.144927978515625 +59990 -0.575531005859375 +59991 0.12774658203125 +59992 -0.526336669921875 +59993 0.092742919921875 +59994 -0.42645263671875 +59995 0.065093994140625 +59996 -0.2581787109375 +59997 0.05810546875 +59998 -0.068695068359375 +59999 0.053985595703125 +60000 0.09222412109375 +60001 0.033935546875 +60002 0.232147216796875 +60003 0.007080078125 +60004 0.3509521484375 +60005 -0.021514892578125 +60006 0.410064697265625 +60007 -0.06622314453125 +60008 0.372955322265625 +60009 -0.1412353515625 +60010 0.2554931640625 +60011 -0.23614501953125 +60012 0.10711669921875 +60013 -0.32537841796875 +60014 -0.052886962890625 +60015 -0.399169921875 +60016 -0.186279296875 +60017 -0.439697265625 +60018 -0.23291015625 +60019 -0.4195556640625 +60020 -0.209442138671875 +60021 -0.349761962890625 +60022 -0.174163818359375 +60023 -0.262359619140625 +60024 -0.126739501953125 +60025 -0.161346435546875 +60026 -0.048126220703125 +60027 -0.04193115234375 +60028 0.0426025390625 +60029 0.082061767578125 +60030 0.10748291015625 +60031 0.18780517578125 +60032 0.1409912109375 +60033 0.268707275390625 +60034 0.19708251953125 +60035 0.347869873046875 +60036 0.273651123046875 +60037 0.42181396484375 +60038 0.31768798828125 +60039 0.463104248046875 +60040 0.341094970703125 +60041 0.47698974609375 +60042 0.368011474609375 +60043 0.4755859375 +60044 0.37249755859375 +60045 0.447540283203125 +60046 0.30072021484375 +60047 0.368682861328125 +60048 0.1517333984375 +60049 0.241302490234375 +60050 -0.01470947265625 +60051 0.09783935546875 +60052 -0.1883544921875 +60053 -0.053070068359375 +60054 -0.372711181640625 +60055 -0.20941162109375 +60056 -0.51397705078125 +60057 -0.34130859375 +60058 -0.57177734375 +60059 -0.425689697265625 +60060 -0.53948974609375 +60061 -0.456512451171875 +60062 -0.43511962890625 +60063 -0.440277099609375 +60064 -0.2962646484375 +60065 -0.393768310546875 +60066 -0.161102294921875 +60067 -0.3348388671875 +60068 -0.0435791015625 +60069 -0.270294189453125 +60070 0.060394287109375 +60071 -0.198974609375 +60072 0.13665771484375 +60073 -0.1292724609375 +60074 0.170135498046875 +60075 -0.0706787109375 +60076 0.16552734375 +60077 -0.023468017578125 +60078 0.15728759765625 +60079 0.026214599609375 +60080 0.150787353515625 +60081 0.077972412109375 +60082 0.12200927734375 +60083 0.117034912109375 +60084 0.080108642578125 +60085 0.14501953125 +60086 0.05126953125 +60087 0.172210693359375 +60088 0.062896728515625 +60089 0.2099609375 +60090 0.09271240234375 +60091 0.245880126953125 +60092 0.092987060546875 +60093 0.255828857421875 +60094 0.07855224609375 +60095 0.246856689453125 +60096 0.06427001953125 +60097 0.226654052734375 +60098 0.0347900390625 +60099 0.18878173828125 +60100 -0.01171875 +60101 0.133880615234375 +60102 -0.056060791015625 +60103 0.073333740234375 +60104 -0.055511474609375 +60105 0.030303955078125 +60106 -0.010467529296875 +60107 0.007080078125 +60108 0.02508544921875 +60109 -0.020111083984375 +60110 0.025665283203125 +60111 -0.061309814453125 +60112 0.017333984375 +60113 -0.101593017578125 +60114 0.00189208984375 +60115 -0.138275146484375 +60116 -0.03173828125 +60117 -0.175384521484375 +60118 -0.071502685546875 +60119 -0.2061767578125 +60120 -0.13543701171875 +60121 -0.23907470703125 +60122 -0.219970703125 +60123 -0.27252197265625 +60124 -0.300506591796875 +60125 -0.295196533203125 +60126 -0.376312255859375 +60127 -0.30792236328125 +60128 -0.416107177734375 +60129 -0.296966552734375 +60130 -0.371124267578125 +60131 -0.240386962890625 +60132 -0.242279052734375 +60133 -0.140655517578125 +60134 -0.069732666015625 +60135 -0.0194091796875 +60136 0.125640869140625 +60137 0.111114501953125 +60138 0.31268310546875 +60139 0.233856201171875 +60140 0.45501708984375 +60141 0.329437255859375 +60142 0.554779052734375 +60143 0.39764404296875 +60144 0.61065673828125 +60145 0.43695068359375 +60146 0.610931396484375 +60147 0.441192626953125 +60148 0.531463623046875 +60149 0.398590087890625 +60150 0.3883056640625 +60151 0.317413330078125 +60152 0.23468017578125 +60153 0.2244873046875 +60154 0.095245361328125 +60155 0.133026123046875 +60156 -0.00396728515625 +60157 0.057159423828125 +60158 -0.04852294921875 +60159 0.005523681640625 +60160 -0.055145263671875 +60161 -0.028106689453125 +60162 -0.0758056640625 +60163 -0.067535400390625 +60164 -0.138702392578125 +60165 -0.125244140625 +60166 -0.209197998046875 +60167 -0.182647705078125 +60168 -0.289031982421875 +60169 -0.2396240234375 +60170 -0.37884521484375 +60171 -0.295806884765625 +60172 -0.456329345703125 +60173 -0.339630126953125 +60174 -0.51641845703125 +60175 -0.3685302734375 +60176 -0.519287109375 +60177 -0.36285400390625 +60178 -0.458251953125 +60179 -0.31982421875 +60180 -0.384796142578125 +60181 -0.266021728515625 +60182 -0.323699951171875 +60183 -0.21490478515625 +60184 -0.269287109375 +60185 -0.16485595703125 +60186 -0.1951904296875 +60187 -0.10400390625 +60188 -0.100006103515625 +60189 -0.032928466796875 +60190 -0.01055908203125 +60191 0.03363037109375 +60192 0.1033935546875 +60193 0.109649658203125 +60194 0.24908447265625 +60195 0.197784423828125 +60196 0.373199462890625 +60197 0.27069091796875 +60198 0.45806884765625 +60199 0.319091796875 +60200 0.511474609375 +60201 0.3466796875 +60202 0.565399169921875 +60203 0.36956787109375 +60204 0.61138916015625 +60205 0.383880615234375 +60206 0.5897216796875 +60207 0.3603515625 +60208 0.4906005859375 +60209 0.29486083984375 +60210 0.33148193359375 +60211 0.1971435546875 +60212 0.147796630859375 +60213 0.0859375 +60214 -0.01873779296875 +60215 -0.01678466796875 +60216 -0.140289306640625 +60217 -0.096038818359375 +60218 -0.191986083984375 +60219 -0.138397216796875 +60220 -0.184295654296875 +60221 -0.14825439453125 +60222 -0.161834716796875 +60223 -0.147247314453125 +60224 -0.166595458984375 +60225 -0.155914306640625 +60226 -0.19390869140625 +60227 -0.17169189453125 +60228 -0.22442626953125 +60229 -0.1849365234375 +60230 -0.279754638671875 +60231 -0.206634521484375 +60232 -0.3389892578125 +60233 -0.226806640625 +60234 -0.3543701171875 +60235 -0.222198486328125 +60236 -0.348175048828125 +60237 -0.204681396484375 +60238 -0.32598876953125 +60239 -0.17791748046875 +60240 -0.2581787109375 +60241 -0.12799072265625 +60242 -0.139801025390625 +60243 -0.05328369140625 +60244 0.014617919921875 +60245 0.038116455078125 +60246 0.144378662109375 +60247 0.115081787109375 +60248 0.221038818359375 +60249 0.162811279296875 +60250 0.27069091796875 +60251 0.19390869140625 +60252 0.294036865234375 +60253 0.208465576171875 +60254 0.311767578125 +60255 0.216796875 +60256 0.339141845703125 +60257 0.226715087890625 +60258 0.360260009765625 +60259 0.230804443359375 +60260 0.360504150390625 +60261 0.222137451171875 +60262 0.308380126953125 +60263 0.184783935546875 +60264 0.18170166015625 +60265 0.107757568359375 +60266 0.0047607421875 +60267 0.004302978515625 +60268 -0.17559814453125 +60269 -0.10064697265625 +60270 -0.3143310546875 +60271 -0.18310546875 +60272 -0.36785888671875 +60273 -0.21990966796875 +60274 -0.36248779296875 +60275 -0.224273681640625 +60276 -0.343536376953125 +60277 -0.21942138671875 +60278 -0.3018798828125 +60279 -0.200439453125 +60280 -0.231414794921875 +60281 -0.164031982421875 +60282 -0.117645263671875 +60283 -0.10272216796875 +60284 0.007049560546875 +60285 -0.033538818359375 +60286 0.087982177734375 +60287 0.0147705078125 +60288 0.13946533203125 +60289 0.04925537109375 +60290 0.17425537109375 +60291 0.07611083984375 +60292 0.188201904296875 +60293 0.0926513671875 +60294 0.171234130859375 +60295 0.093109130859375 +60296 0.118438720703125 +60297 0.074432373046875 +60298 0.05706787109375 +60299 0.05035400390625 +60300 -0.010711669921875 +60301 0.021575927734375 +60302 -0.0914306640625 +60303 -0.015594482421875 +60304 -0.162322998046875 +60305 -0.04949951171875 +60306 -0.194549560546875 +60307 -0.065277099609375 +60308 -0.1492919921875 +60309 -0.042755126953125 +60310 -0.02166748046875 +60311 0.020721435546875 +60312 0.124053955078125 +60313 0.091949462890625 +60314 0.211151123046875 +60315 0.131317138671875 +60316 0.240447998046875 +60317 0.1396484375 +60318 0.242218017578125 +60319 0.133026123046875 +60320 0.2257080078125 +60321 0.116729736328125 +60322 0.194366455078125 +60323 0.092987060546875 +60324 0.115509033203125 +60325 0.045196533203125 +60326 0.0128173828125 +60327 -0.013946533203125 +60328 -0.053802490234375 +60329 -0.05303955078125 +60330 -0.110626220703125 +60331 -0.08551025390625 +60332 -0.199493408203125 +60333 -0.133026123046875 +60334 -0.29437255859375 +60335 -0.182037353515625 +60336 -0.33221435546875 +60337 -0.199798583984375 +60338 -0.27972412109375 +60339 -0.169158935546875 +60340 -0.185333251953125 +60341 -0.115509033203125 +60342 -0.128204345703125 +60343 -0.080291748046875 +60344 -0.115692138671875 +60345 -0.067657470703125 +60346 -0.116455078125 +60347 -0.061676025390625 +60348 -0.105926513671875 +60349 -0.0499267578125 +60350 -0.053955078125 +60351 -0.017059326171875 +60352 0.048797607421875 +60353 0.04144287109375 +60354 0.157318115234375 +60355 0.101898193359375 +60356 0.212005615234375 +60357 0.133148193359375 +60358 0.218475341796875 +60359 0.13800048828125 +60360 0.23724365234375 +60361 0.147857666015625 +60362 0.30535888671875 +60363 0.182037353515625 +60364 0.38128662109375 +60365 0.21905517578125 +60366 0.404449462890625 +60367 0.227569580078125 +60368 0.3944091796875 +60369 0.217987060546875 +60370 0.3885498046875 +60371 0.209991455078125 +60372 0.362640380859375 +60373 0.1912841796875 +60374 0.27362060546875 +60375 0.1397705078125 +60376 0.11712646484375 +60377 0.053466796875 +60378 -0.054901123046875 +60379 -0.04034423828125 +60380 -0.19085693359375 +60381 -0.1146240234375 +60382 -0.28570556640625 +60383 -0.166595458984375 +60384 -0.339263916015625 +60385 -0.196044921875 +60386 -0.3775634765625 +60387 -0.2164306640625 +60388 -0.445709228515625 +60389 -0.251190185546875 +60390 -0.535064697265625 +60391 -0.295928955078125 +60392 -0.629058837890625 +60393 -0.3421630859375 +60394 -0.697601318359375 +60395 -0.3743896484375 +60396 -0.70391845703125 +60397 -0.373687744140625 +60398 -0.6424560546875 +60399 -0.337432861328125 +60400 -0.491241455078125 +60401 -0.254425048828125 +60402 -0.265716552734375 +60403 -0.1329345703125 +60404 -0.023712158203125 +60405 -0.003265380859375 +60406 0.201751708984375 +60407 0.1171875 +60408 0.375823974609375 +60409 0.21014404296875 +60410 0.485076904296875 +60411 0.26849365234375 +60412 0.56884765625 +60413 0.31268310546875 +60414 0.634765625 +60415 0.346649169921875 +60416 0.63763427734375 +60417 0.346435546875 +60418 0.5660400390625 +60419 0.305450439453125 +60420 0.4720458984375 +60421 0.251983642578125 +60422 0.40692138671875 +60423 0.214599609375 +60424 0.3778076171875 +60425 0.197479248046875 +60426 0.376953125 +60427 0.196502685546875 +60428 0.371978759765625 +60429 0.19390869140625 +60430 0.313140869140625 +60431 0.1622314453125 +60432 0.184417724609375 +60433 0.092559814453125 +60434 0.011199951171875 +60435 -0.0010986328125 +60436 -0.171051025390625 +60437 -0.09930419921875 +60438 -0.33740234375 +60439 -0.188446044921875 +60440 -0.47198486328125 +60441 -0.259918212890625 +60442 -0.560394287109375 +60443 -0.305938720703125 +60444 -0.58056640625 +60445 -0.31451416015625 +60446 -0.54754638671875 +60447 -0.2940673828125 +60448 -0.508575439453125 +60449 -0.270843505859375 +60450 -0.459503173828125 +60451 -0.24261474609375 +60452 -0.394378662109375 +60453 -0.206146240234375 +60454 -0.35260009765625 +60455 -0.183197021484375 +60456 -0.31170654296875 +60457 -0.161346435546875 +60458 -0.197418212890625 +60459 -0.099517822265625 +60460 -0.007965087890625 +60461 0.0032958984375 +60462 0.207489013671875 +60463 0.120086669921875 +60464 0.409210205078125 +60465 0.229034423828125 +60466 0.57208251953125 +60467 0.316436767578125 +60468 0.66595458984375 +60469 0.36578369140625 +60470 0.65875244140625 +60471 0.3594970703125 +60472 0.56744384765625 +60473 0.30706787109375 +60474 0.431396484375 +60475 0.230316162109375 +60476 0.29443359375 +60477 0.153533935546875 +60478 0.182464599609375 +60479 0.091094970703125 +60480 0.06365966796875 +60481 0.025421142578125 +60482 -0.075958251953125 +60483 -0.051177978515625 +60484 -0.189422607421875 +60485 -0.11285400390625 +60486 -0.271942138671875 +60487 -0.156982421875 +60488 -0.342529296875 +60489 -0.19415283203125 +60490 -0.364166259765625 +60491 -0.204071044921875 +60492 -0.327239990234375 +60493 -0.181549072265625 +60494 -0.2769775390625 +60495 -0.15167236328125 +60496 -0.253692626953125 +60497 -0.136810302734375 +60498 -0.24365234375 +60499 -0.129486083984375 +60500 -0.1983642578125 +60501 -0.10302734375 +60502 -0.116241455078125 +60503 -0.056610107421875 +60504 -0.036834716796875 +60505 -0.012115478515625 +60506 0.034881591796875 +60507 0.02764892578125 +60508 0.09124755859375 +60509 0.0584716796875 +60510 0.10888671875 +60511 0.0675048828125 +60512 0.125518798828125 +60513 0.075592041015625 +60514 0.15771484375 +60515 0.091949462890625 +60516 0.17828369140625 +60517 0.10162353515625 +60518 0.17108154296875 +60519 0.0958251953125 +60520 0.129974365234375 +60521 0.0712890625 +60522 0.082427978515625 +60523 0.04327392578125 +60524 0.027679443359375 +60525 0.011474609375 +60526 -0.065643310546875 +60527 -0.04132080078125 +60528 -0.15936279296875 +60529 -0.093994140625 +60530 -0.21307373046875 +60531 -0.12420654296875 +60532 -0.234649658203125 +60533 -0.13629150390625 +60534 -0.2001953125 +60535 -0.117034912109375 +60536 -0.119171142578125 +60537 -0.07171630859375 +60538 -0.024749755859375 +60539 -0.0186767578125 +60540 0.085784912109375 +60541 0.043487548828125 +60542 0.178131103515625 +60543 0.09576416015625 +60544 0.215576171875 +60545 0.11785888671875 +60546 0.211456298828125 +60547 0.117034912109375 +60548 0.17523193359375 +60549 0.09844970703125 +60550 0.128753662109375 +60551 0.0740966796875 +60552 0.1019287109375 +60553 0.06036376953125 +60554 0.0743408203125 +60555 0.04595947265625 +60556 0.04327392578125 +60557 0.02935791015625 +60558 0.038177490234375 +60559 0.02679443359375 +60560 0.076263427734375 +60561 0.047760009765625 +60562 0.14105224609375 +60563 0.0831298828125 +60564 0.186431884765625 +60565 0.10748291015625 +60566 0.188812255859375 +60567 0.10784912109375 +60568 0.1390380859375 +60569 0.079254150390625 +60570 0.041778564453125 +60571 0.02435302734375 +60572 -0.079437255859375 +60573 -0.04376220703125 +60574 -0.219390869140625 +60575 -0.1221923828125 +60576 -0.367828369140625 +60577 -0.205169677734375 +60578 -0.494873046875 +60579 -0.27618408203125 +60580 -0.556243896484375 +60581 -0.31072998046875 +60582 -0.508697509765625 +60583 -0.284912109375 +60584 -0.3756103515625 +60585 -0.211639404296875 +60586 -0.218902587890625 +60587 -0.125091552734375 +60588 -0.063751220703125 +60589 -0.039154052734375 +60590 0.091552734375 +60591 0.047027587890625 +60592 0.23602294921875 +60593 0.127410888671875 +60594 0.342987060546875 +60595 0.187225341796875 +60596 0.39520263671875 +60597 0.2169189453125 +60598 0.389373779296875 +60599 0.214630126953125 +60600 0.324249267578125 +60601 0.179595947265625 +60602 0.224090576171875 +60603 0.125152587890625 +60604 0.124267578125 +60605 0.07080078125 +60606 0.037078857421875 +60607 0.023284912109375 +60608 -0.010101318359375 +60609 -0.002288818359375 +60610 -0.019439697265625 +60611 -0.00714111328125 +60612 -0.022796630859375 +60613 -0.008880615234375 +60614 -0.001556396484375 +60615 0.002716064453125 +60616 0.056304931640625 +60617 0.034332275390625 +60618 0.106719970703125 +60619 0.0616455078125 +60620 0.096893310546875 +60621 0.055572509765625 +60622 0.042694091796875 +60623 0.024932861328125 +60624 -0.018035888671875 +60625 -0.009368896484375 +60626 -0.07586669921875 +60627 -0.04205322265625 +60628 -0.11944580078125 +60629 -0.06683349609375 +60630 -0.15972900390625 +60631 -0.0897216796875 +60632 -0.202606201171875 +60633 -0.11395263671875 +60634 -0.24859619140625 +60635 -0.139739990234375 +60636 -0.30517578125 +60637 -0.17120361328125 +60638 -0.36212158203125 +60639 -0.20269775390625 +60640 -0.39141845703125 +60641 -0.21875 +60642 -0.35528564453125 +60643 -0.19854736328125 +60644 -0.249969482421875 +60645 -0.1400146484375 +60646 -0.092864990234375 +60647 -0.05279541015625 +60648 0.08905029296875 +60649 0.048187255859375 +60650 0.2352294921875 +60651 0.12945556640625 +60652 0.318817138671875 +60653 0.176177978515625 +60654 0.358642578125 +60655 0.19873046875 +60656 0.347747802734375 +60657 0.1932373046875 +60658 0.28564453125 +60659 0.159393310546875 +60660 0.223175048828125 +60661 0.125244140625 +60662 0.196746826171875 +60663 0.11083984375 +60664 0.179840087890625 +60665 0.101593017578125 +60666 0.155548095703125 +60667 0.088134765625 +60668 0.151214599609375 +60669 0.0855712890625 +60670 0.156951904296875 +60671 0.088470458984375 +60672 0.13177490234375 +60673 0.07403564453125 +60674 0.100799560546875 +60675 0.056610107421875 +60676 0.087127685546875 +60677 0.04913330078125 +60678 0.05487060546875 +60679 0.030792236328125 +60680 -0.009002685546875 +60681 -0.005889892578125 +60682 -0.10400390625 +60683 -0.06060791015625 +60684 -0.229400634765625 +60685 -0.132965087890625 +60686 -0.35552978515625 +60687 -0.205657958984375 +60688 -0.441925048828125 +60689 -0.255096435546875 +60690 -0.473846435546875 +60691 -0.27276611328125 +60692 -0.464813232421875 +60693 -0.266632080078125 +60694 -0.419097900390625 +60695 -0.2392578125 +60696 -0.334320068359375 +60697 -0.1893310546875 +60698 -0.227935791015625 +60699 -0.127044677734375 +60700 -0.12347412109375 +60701 -0.066162109375 +60702 -0.02764892578125 +60703 -0.010589599609375 +60704 0.077667236328125 +60705 0.050262451171875 +60706 0.2132568359375 +60707 0.1285400390625 +60708 0.38885498046875 +60709 0.22998046875 +60710 0.582794189453125 +60711 0.34197998046875 +60712 0.734039306640625 +60713 0.428985595703125 +60714 0.800140380859375 +60715 0.466278076171875 +60716 0.7783203125 +60717 0.452301025390625 +60718 0.6651611328125 +60719 0.3851318359375 +60720 0.45965576171875 +60721 0.264251708984375 +60722 0.199188232421875 +60723 0.111541748046875 +60724 -0.050689697265625 +60725 -0.03466796875 +60726 -0.23297119140625 +60727 -0.14111328125 +60728 -0.33013916015625 +60729 -0.19757080078125 +60730 -0.368408203125 +60731 -0.2193603515625 +60732 -0.378936767578125 +60733 -0.224700927734375 +60734 -0.376983642578125 +60735 -0.22259521484375 +60736 -0.37969970703125 +60737 -0.22314453125 +60738 -0.391510009765625 +60739 -0.228973388671875 +60740 -0.385345458984375 +60741 -0.224334716796875 +60742 -0.3419189453125 +60743 -0.197998046875 +60744 -0.28289794921875 +60745 -0.16265869140625 +60746 -0.251617431640625 +60747 -0.1436767578125 +60748 -0.266143798828125 +60749 -0.151611328125 +60750 -0.273345947265625 +60751 -0.155487060546875 +60752 -0.216796875 +60753 -0.122344970703125 +60754 -0.128265380859375 +60755 -0.07073974609375 +60756 -0.068145751953125 +60757 -0.035919189453125 +60758 -0.0430908203125 +60759 -0.021728515625 +60760 -0.024444580078125 +60761 -0.011444091796875 +60762 0.020721435546875 +60763 0.01422119140625 +60764 0.124481201171875 +60765 0.074005126953125 +60766 0.25787353515625 +60767 0.151031494140625 +60768 0.379119873046875 +60769 0.220947265625 +60770 0.47991943359375 +60771 0.27899169921875 +60772 0.5281982421875 +60773 0.30645751953125 +60774 0.511138916015625 +60775 0.2958984375 +60776 0.456207275390625 +60777 0.26336669921875 +60778 0.407470703125 +60779 0.234649658203125 +60780 0.383758544921875 +60781 0.220733642578125 +60782 0.35687255859375 +60783 0.20513916015625 +60784 0.31182861328125 +60785 0.179107666015625 +60786 0.250885009765625 +60787 0.1439208984375 +60788 0.1654052734375 +60789 0.09454345703125 +60790 0.035247802734375 +60791 0.019195556640625 +60792 -0.142059326171875 +60793 -0.0836181640625 +60794 -0.33563232421875 +60795 -0.195892333984375 +60796 -0.5345458984375 +60797 -0.311279296875 +60798 -0.72186279296875 +60799 -0.419952392578125 +60800 -0.836669921875 +60801 -0.486358642578125 +60802 -0.8326416015625 +60803 -0.483489990234375 +60804 -0.7296142578125 +60805 -0.4229736328125 +60806 -0.582550048828125 +60807 -0.336944580078125 +60808 -0.440093994140625 +60809 -0.2537841796875 +60810 -0.324310302734375 +60811 -0.186370849609375 +60812 -0.20147705078125 +60813 -0.114990234375 +60814 -0.044647216796875 +60815 -0.02386474609375 +60816 0.103973388671875 +60817 0.062347412109375 +60818 0.202392578125 +60819 0.119171142578125 +60820 0.264495849609375 +60821 0.154754638671875 +60822 0.338897705078125 +60823 0.197509765625 +60824 0.443817138671875 +60825 0.25811767578125 +60826 0.545074462890625 +60827 0.316680908203125 +60828 0.6173095703125 +60829 0.3583984375 +60830 0.6524658203125 +60831 0.378570556640625 +60832 0.66339111328125 +60833 0.384735107421875 +60834 0.6561279296875 +60835 0.38043212890625 +60836 0.606781005859375 +60837 0.3516845703125 +60838 0.501190185546875 +60839 0.29022216796875 +60840 0.352783203125 +60841 0.203857421875 +60842 0.176544189453125 +60843 0.101318359375 +60844 -0.034820556640625 +60845 -0.021636962890625 +60846 -0.258209228515625 +60847 -0.151519775390625 +60848 -0.44244384765625 +60849 -0.25848388671875 +60850 -0.5753173828125 +60851 -0.33544921875 +60852 -0.65203857421875 +60853 -0.379669189453125 +60854 -0.641632080078125 +60855 -0.373046875 +60856 -0.562164306640625 +60857 -0.326202392578125 +60858 -0.458038330078125 +60859 -0.265106201171875 +60860 -0.350555419921875 +60861 -0.202178955078125 +60862 -0.260528564453125 +60863 -0.149566650390625 +60864 -0.192108154296875 +60865 -0.109710693359375 +60866 -0.141937255859375 +60867 -0.08062744140625 +60868 -0.1021728515625 +60869 -0.057708740234375 +60870 -0.062896728515625 +60871 -0.03515625 +60872 -0.011932373046875 +60873 -0.005859375 +60874 0.062835693359375 +60875 0.03729248046875 +60876 0.148712158203125 +60877 0.0869140625 +60878 0.241729736328125 +60879 0.14068603515625 +60880 0.34912109375 +60881 0.202880859375 +60882 0.457305908203125 +60883 0.265594482421875 +60884 0.54388427734375 +60885 0.3157958984375 +60886 0.5728759765625 +60887 0.332489013671875 +60888 0.506591796875 +60889 0.293670654296875 +60890 0.351226806640625 +60891 0.202972412109375 +60892 0.146514892578125 +60893 0.08355712890625 +60894 -0.05523681640625 +60895 -0.034027099609375 +60896 -0.21624755859375 +60897 -0.127716064453125 +60898 -0.334930419921875 +60899 -0.19659423828125 +60900 -0.402984619140625 +60901 -0.23583984375 +60902 -0.4412841796875 +60903 -0.257659912109375 +60904 -0.49578857421875 +60905 -0.288909912109375 +60906 -0.5601806640625 +60907 -0.325958251953125 +60908 -0.600738525390625 +60909 -0.349151611328125 +60910 -0.584228515625 +60911 -0.339111328125 +60912 -0.47930908203125 +60913 -0.27752685546875 +60914 -0.27935791015625 +60915 -0.16058349609375 +60916 -0.0089111328125 +60917 -0.00262451171875 +60918 0.268798828125 +60919 0.159423828125 +60920 0.482818603515625 +60921 0.284149169921875 +60922 0.60369873046875 +60923 0.3543701171875 +60924 0.650421142578125 +60925 0.38116455078125 +60926 0.66400146484375 +60927 0.3885498046875 +60928 0.6414794921875 +60929 0.37457275390625 +60930 0.572540283203125 +60931 0.333343505859375 +60932 0.498138427734375 +60933 0.2899169921875 +60934 0.439453125 +60935 0.257110595703125 +60936 0.375518798828125 +60937 0.221771240234375 +60938 0.274505615234375 +60939 0.163970947265625 +60940 0.1087646484375 +60941 0.06640625 +60942 -0.099395751953125 +60943 -0.05743408203125 +60944 -0.3182373046875 +60945 -0.188201904296875 +60946 -0.5489501953125 +60947 -0.326873779296875 +60948 -0.7738037109375 +60949 -0.462677001953125 +60950 -0.86383056640625 +60951 -0.563140869140625 +60952 -0.870391845703125 +60953 -0.607818603515625 +60954 -0.86895751953125 +60955 -0.607635498046875 +60956 -0.861053466796875 +60957 -0.570648193359375 +60958 -0.765869140625 +60959 -0.486114501953125 +60960 -0.5301513671875 +60961 -0.34698486328125 +60962 -0.214691162109375 +60963 -0.157470703125 +60964 0.137359619140625 +60965 0.05609130859375 +60966 0.474822998046875 +60967 0.262298583984375 +60968 0.76239013671875 +60969 0.439453125 +60970 0.867462158203125 +60971 0.571136474609375 +60972 0.870361328125 +60973 0.65777587890625 +60974 0.86480712890625 +60975 0.692413330078125 +60976 0.831817626953125 +60977 0.678436279296875 +60978 0.677581787109375 +60979 0.630950927734375 +60980 0.495880126953125 +60981 0.55352783203125 +60982 0.30767822265625 +60983 0.45758056640625 +60984 0.116180419921875 +60985 0.34442138671875 +60986 -0.110748291015625 +60987 0.194427490234375 +60988 -0.381805419921875 +60989 0.003204345703125 +60990 -0.6572265625 +60991 -0.202972412109375 +60992 -0.857421875 +60993 -0.38739013671875 +60994 -0.870391845703125 +60995 -0.52374267578125 +60996 -0.870391845703125 +60997 -0.6077880859375 +60998 -0.86444091796875 +60999 -0.65625 +61000 -0.85723876953125 +61001 -0.69122314453125 +61002 -0.790008544921875 +61003 -0.701507568359375 +61004 -0.62847900390625 +61005 -0.65374755859375 +61006 -0.3956298828125 +61007 -0.5460205078125 +61008 -0.126708984375 +61009 -0.398529052734375 +61010 0.150115966796875 +61011 -0.2281494140625 +61012 0.424041748046875 +61013 -0.04205322265625 +61014 0.670623779296875 +61015 0.143218994140625 +61016 0.854522705078125 +61017 0.303924560546875 +61018 0.866485595703125 +61019 0.42926025390625 +61020 0.86920166015625 +61021 0.5098876953125 +61022 0.8653564453125 +61023 0.557098388671875 +61024 0.857147216796875 +61025 0.5792236328125 +61026 0.766845703125 +61027 0.574615478515625 +61028 0.628509521484375 +61029 0.546478271484375 +61030 0.462127685546875 +61031 0.49072265625 +61032 0.297210693359375 +61033 0.42327880859375 +61034 0.14862060546875 +61035 0.351776123046875 +61036 -0.00537109375 +61037 0.262176513671875 +61038 -0.15753173828125 +61039 0.1590576171875 +61040 -0.31304931640625 +61041 0.0401611328125 +61042 -0.48876953125 +61043 -0.10321044921875 +61044 -0.6416015625 +61045 -0.24224853515625 +61046 -0.751373291015625 +61047 -0.36181640625 +61048 -0.84619140625 +61049 -0.476165771484375 +61050 -0.861297607421875 +61051 -0.57635498046875 +61052 -0.863250732421875 +61053 -0.64202880859375 +61054 -0.856597900390625 +61055 -0.653778076171875 +61056 -0.7498779296875 +61057 -0.619140625 +61058 -0.624542236328125 +61059 -0.57379150390625 +61060 -0.47808837890625 +61061 -0.504180908203125 +61062 -0.253387451171875 +61063 -0.37432861328125 +61064 0.003692626953125 +61065 -0.21234130859375 +61066 0.2257080078125 +61067 -0.060302734375 +61068 0.427154541015625 +61069 0.089508056640625 +61070 0.643218994140625 +61071 0.257049560546875 +61072 0.855926513671875 +61073 0.4364013671875 +61074 0.870361328125 +61075 0.5919189453125 +61076 0.870361328125 +61077 0.69305419921875 +61078 0.862762451171875 +61079 0.744293212890625 +61080 0.79669189453125 +61081 0.74383544921875 +61082 0.595794677734375 +61083 0.6859130859375 +61084 0.362152099609375 +61085 0.58856201171875 +61086 0.1270751953125 +61087 0.469085693359375 +61088 -0.086944580078125 +61089 0.340545654296875 +61090 -0.2784423828125 +61091 0.204254150390625 +61092 -0.484832763671875 +61093 0.038818359375 +61094 -0.729583740234375 +61095 -0.16754150390625 +61096 -0.86688232421875 +61097 -0.38360595703125 +61098 -0.870391845703125 +61099 -0.57037353515625 +61100 -0.86859130859375 +61101 -0.72479248046875 +61102 -0.86279296875 +61103 -0.84552001953125 +61104 -0.817962646484375 +61105 -0.860595703125 +61106 -0.6116943359375 +61107 -0.8585205078125 +61108 -0.3128662109375 +61109 -0.78424072265625 +61110 0.039398193359375 +61111 -0.60968017578125 +61112 0.422821044921875 +61113 -0.380126953125 +61114 0.805145263671875 +61115 -0.116119384765625 +61116 0.870361328125 +61117 0.140289306640625 +61118 0.870361328125 +61119 0.353851318359375 +61120 0.860015869140625 +61121 0.5172119140625 +61122 0.727935791015625 +61123 0.62548828125 +61124 0.48114013671875 +61125 0.675079345703125 +61126 0.2059326171875 +61127 0.68072509765625 +61128 -0.06103515625 +61129 0.656219482421875 +61130 -0.29913330078125 +61131 0.607635498046875 +61132 -0.516204833984375 +61133 0.5260009765625 +61134 -0.7252197265625 +61135 0.401824951171875 +61136 -0.85980224609375 +61137 0.25054931640625 +61138 -0.870391845703125 +61139 0.09344482421875 +61140 -0.870391845703125 +61141 -0.051025390625 +61142 -0.858062744140625 +61143 -0.152587890625 +61144 -0.673004150390625 +61145 -0.20831298828125 +61146 -0.42694091796875 +61147 -0.250213623046875 +61148 -0.2100830078125 +61149 -0.30523681640625 +61150 -0.0362548828125 +61151 -0.37176513671875 +61152 0.10943603515625 +61153 -0.43157958984375 +61154 0.23516845703125 +61155 -0.472137451171875 +61156 0.373687744140625 +61157 -0.4677734375 +61158 0.517791748046875 +61159 -0.4195556640625 +61160 0.602783203125 +61161 -0.366302490234375 +61162 0.635711669921875 +61163 -0.304901123046875 +61164 0.655181884765625 +61165 -0.2149658203125 +61166 0.65948486328125 +61167 -0.102874755859375 +61168 0.651275634765625 +61169 0.026123046875 +61170 0.61846923828125 +61171 0.15655517578125 +61172 0.53753662109375 +61173 0.26519775390625 +61174 0.404144287109375 +61175 0.340576171875 +61176 0.22186279296875 +61177 0.3763427734375 +61178 0.003997802734375 +61179 0.372894287109375 +61180 -0.22100830078125 +61181 0.341064453125 +61182 -0.42449951171875 +61183 0.293365478515625 +61184 -0.579833984375 +61185 0.2431640625 +61186 -0.641876220703125 +61187 0.217437744140625 +61188 -0.6177978515625 +61189 0.211517333984375 +61190 -0.575531005859375 +61191 0.183990478515625 +61192 -0.526336669921875 +61193 0.131805419921875 +61194 -0.42645263671875 +61195 0.08892822265625 +61196 -0.2581787109375 +61197 0.073516845703125 +61198 -0.068695068359375 +61199 0.062408447265625 +61200 0.09222412109375 +61201 0.030975341796875 +61202 0.232147216796875 +61203 -0.008392333984375 +61204 0.3509521484375 +61205 -0.048858642578125 +61206 0.410064697265625 +61207 -0.109375 +61208 0.372955322265625 +61209 -0.208770751953125 +61210 0.2554931640625 +61211 -0.333343505859375 +61212 0.10711669921875 +61213 -0.449249267578125 +61214 -0.052886962890625 +61215 -0.54376220703125 +61216 -0.186279296875 +61217 -0.59344482421875 +61218 -0.23291015625 +61219 -0.562164306640625 +61220 -0.209442138671875 +61221 -0.46478271484375 +61222 -0.174163818359375 +61223 -0.344146728515625 +61224 -0.126739501953125 +61225 -0.205841064453125 +61226 -0.048126220703125 +61227 -0.043670654296875 +61228 0.0426025390625 +61229 0.123809814453125 +61230 0.10748291015625 +61231 0.26617431640625 +61232 0.1409912109375 +61233 0.374603271484375 +61234 0.19708251953125 +61235 0.479705810546875 +61236 0.273651123046875 +61237 0.576904296875 +61238 0.31768798828125 +61239 0.629852294921875 +61240 0.341094970703125 +61241 0.645599365234375 +61242 0.368011474609375 +61243 0.640472412109375 +61244 0.37249755859375 +61245 0.59954833984375 +61246 0.30072021484375 +61247 0.490936279296875 +61248 0.1517333984375 +61249 0.31793212890625 +61250 -0.01470947265625 +61251 0.123809814453125 +61252 -0.1883544921875 +61253 -0.079742431640625 +61254 -0.372711181640625 +61255 -0.2899169921875 +61256 -0.51397705078125 +61257 -0.4669189453125 +61258 -0.57177734375 +61259 -0.580047607421875 +61260 -0.53948974609375 +61261 -0.6212158203125 +61262 -0.43511962890625 +61263 -0.59906005859375 +61264 -0.2962646484375 +61265 -0.53594970703125 +61266 -0.161102294921875 +61267 -0.455718994140625 +61268 -0.0435791015625 +61269 -0.367523193359375 +61270 0.060394287109375 +61271 -0.26995849609375 +61272 0.13665771484375 +61273 -0.174346923828125 +61274 0.170135498046875 +61275 -0.093414306640625 +61276 0.16552734375 +61277 -0.027740478515625 +61278 0.15728759765625 +61279 0.04095458984375 +61280 0.150787353515625 +61281 0.11199951171875 +61282 0.12200927734375 +61283 0.165679931640625 +61284 0.080108642578125 +61285 0.20404052734375 +61286 0.05126953125 +61287 0.24066162109375 +61288 0.062896728515625 +61289 0.2906494140625 +61290 0.09271240234375 +61291 0.337554931640625 +61292 0.092987060546875 +61293 0.349395751953125 +61294 0.07855224609375 +61295 0.33563232421875 +61296 0.06427001953125 +61297 0.30657958984375 +61298 0.0347900390625 +61299 0.253814697265625 +61300 -0.01171875 +61301 0.1783447265625 +61302 -0.056060791015625 +61303 0.095428466796875 +61304 -0.055511474609375 +61305 0.03594970703125 +61306 -0.010467529296875 +61307 0.003082275390625 +61308 0.02508544921875 +61309 -0.034637451171875 +61310 0.025665283203125 +61311 -0.0904541015625 +61312 0.017333984375 +61313 -0.144561767578125 +61314 0.00189208984375 +61315 -0.193359375 +61316 -0.03173828125 +61317 -0.242218017578125 +61318 -0.071502685546875 +61319 -0.282196044921875 +61320 -0.13543701171875 +61321 -0.3245849609375 +61322 -0.219970703125 +61323 -0.36737060546875 +61324 -0.300506591796875 +61325 -0.3956298828125 +61326 -0.376312255859375 +61327 -0.4105224609375 +61328 -0.416107177734375 +61329 -0.393951416015625 +61330 -0.371124267578125 +61331 -0.316864013671875 +61332 -0.242279052734375 +61333 -0.1826171875 +61334 -0.069732666015625 +61335 -0.020111083984375 +61336 0.125640869140625 +61337 0.154327392578125 +61338 0.31268310546875 +61339 0.318023681640625 +61340 0.45501708984375 +61341 0.445220947265625 +61342 0.554779052734375 +61343 0.535614013671875 +61344 0.61065673828125 +61345 0.58721923828125 +61346 0.610931396484375 +61347 0.5919189453125 +61348 0.531463623046875 +61349 0.534149169921875 +61350 0.3883056640625 +61351 0.424957275390625 +61352 0.23468017578125 +61353 0.29998779296875 +61354 0.095245361328125 +61355 0.176910400390625 +61356 -0.00396728515625 +61357 0.074554443359375 +61358 -0.04852294921875 +61359 0.004486083984375 +61360 -0.055145263671875 +61361 -0.041748046875 +61362 -0.0758056640625 +61363 -0.095550537109375 +61364 -0.138702392578125 +61365 -0.17303466796875 +61366 -0.209197998046875 +61367 -0.249847412109375 +61368 -0.289031982421875 +61369 -0.325592041015625 +61370 -0.37884521484375 +61371 -0.399566650390625 +61372 -0.456329345703125 +61373 -0.4566650390625 +61374 -0.51641845703125 +61375 -0.493499755859375 +61376 -0.519287109375 +61377 -0.484649658203125 +61378 -0.458251953125 +61379 -0.4266357421875 +61380 -0.384796142578125 +61381 -0.354034423828125 +61382 -0.323699951171875 +61383 -0.284423828125 +61384 -0.269287109375 +61385 -0.215911865234375 +61386 -0.1951904296875 +61387 -0.133331298828125 +61388 -0.100006103515625 +61389 -0.037689208984375 +61390 -0.01055908203125 +61391 0.0517578125 +61392 0.1033935546875 +61393 0.1529541015625 +61394 0.24908447265625 +61395 0.269256591796875 +61396 0.373199462890625 +61397 0.365081787109375 +61398 0.45806884765625 +61399 0.428314208984375 +61400 0.511474609375 +61401 0.463714599609375 +61402 0.565399169921875 +61403 0.492218017578125 +61404 0.61138916015625 +61405 0.5089111328125 +61406 0.5897216796875 +61407 0.475982666015625 +61408 0.4906005859375 +61409 0.388275146484375 +61410 0.33148193359375 +61411 0.258544921875 +61412 0.147796630859375 +61413 0.11126708984375 +61414 -0.01873779296875 +61415 -0.024932861328125 +61416 -0.140289306640625 +61417 -0.130462646484375 +61418 -0.191986083984375 +61419 -0.187774658203125 +61420 -0.184295654296875 +61421 -0.20245361328125 +61422 -0.161834716796875 +61423 -0.20245361328125 +61424 -0.166595458984375 +61425 -0.21435546875 +61426 -0.19390869140625 +61427 -0.23480224609375 +61428 -0.22442626953125 +61429 -0.251251220703125 +61430 -0.279754638671875 +61431 -0.278106689453125 +61432 -0.3389892578125 +61433 -0.302459716796875 +61434 -0.3543701171875 +61435 -0.294281005859375 +61436 -0.348175048828125 +61437 -0.26910400390625 +61438 -0.32598876953125 +61439 -0.231781005859375 +61440 -0.2581787109375 +61441 -0.1644287109375 +61442 -0.139801025390625 +61443 -0.065093994140625 +61444 0.014617919921875 +61445 0.055633544921875 +61446 0.144378662109375 +61447 0.1572265625 +61448 0.221038818359375 +61449 0.220367431640625 +61450 0.27069091796875 +61451 0.261383056640625 +61452 0.294036865234375 +61453 0.280426025390625 +61454 0.311767578125 +61455 0.29083251953125 +61456 0.339141845703125 +61457 0.3028564453125 +61458 0.360260009765625 +61459 0.30694580078125 +61460 0.360504150390625 +61461 0.294189453125 +61462 0.308380126953125 +61463 0.2437744140625 +61464 0.18170166015625 +61465 0.14141845703125 +61466 0.0047607421875 +61467 0.0045166015625 +61468 -0.17559814453125 +61469 -0.134246826171875 +61470 -0.3143310546875 +61471 -0.243438720703125 +61472 -0.36785888671875 +61473 -0.29266357421875 +61474 -0.36248779296875 +61475 -0.2991943359375 +61476 -0.343536376953125 +61477 -0.2933349609375 +61478 -0.3018798828125 +61479 -0.26861572265625 +61480 -0.231414794921875 +61481 -0.220794677734375 +61482 -0.117645263671875 +61483 -0.140106201171875 +61484 0.007049560546875 +61485 -0.048828125 +61486 0.087982177734375 +61487 0.015411376953125 +61488 0.13946533203125 +61489 0.061767578125 +61490 0.17425537109375 +61491 0.0982666015625 +61492 0.188201904296875 +61493 0.121307373046875 +61494 0.171234130859375 +61495 0.123291015625 +61496 0.118438720703125 +61497 0.100128173828125 +61498 0.05706787109375 +61499 0.0697021484375 +61500 -0.010711669921875 +61501 0.032867431640625 +61502 -0.0914306640625 +61503 -0.015228271484375 +61504 -0.162322998046875 +61505 -0.059356689453125 +61506 -0.194549560546875 +61507 -0.080078125 +61508 -0.1492919921875 +61509 -0.050994873046875 +61510 -0.02166748046875 +61511 0.031341552734375 +61512 0.124053955078125 +61513 0.12359619140625 +61514 0.211151123046875 +61515 0.174041748046875 +61516 0.240447998046875 +61517 0.183807373046875 +61518 0.242218017578125 +61519 0.17401123046875 +61520 0.2257080078125 +61521 0.151611328125 +61522 0.194366455078125 +61523 0.119537353515625 +61524 0.115509033203125 +61525 0.05615234375 +61526 0.0128173828125 +61527 -0.02191162109375 +61528 -0.053802490234375 +61529 -0.073516845703125 +61530 -0.110626220703125 +61531 -0.116241455078125 +61532 -0.199493408203125 +61533 -0.17840576171875 +61534 -0.29437255859375 +61535 -0.242279052734375 +61536 -0.33221435546875 +61537 -0.26507568359375 +61538 -0.27972412109375 +61539 -0.22442626953125 +61540 -0.185333251953125 +61541 -0.153533935546875 +61542 -0.128204345703125 +61543 -0.106658935546875 +61544 -0.115692138671875 +61545 -0.089263916015625 +61546 -0.116455078125 +61547 -0.08056640625 +61548 -0.105926513671875 +61549 -0.064361572265625 +61550 -0.053955078125 +61551 -0.020660400390625 +61552 0.048797607421875 +61553 0.056427001953125 +61554 0.157318115234375 +61555 0.135955810546875 +61556 0.212005615234375 +61557 0.1771240234375 +61558 0.218475341796875 +61559 0.18359375 +61560 0.23724365234375 +61561 0.196441650390625 +61562 0.30535888671875 +61563 0.240966796875 +61564 0.38128662109375 +61565 0.289031982421875 +61566 0.404449462890625 +61567 0.2996826171875 +61568 0.3944091796875 +61569 0.286529541015625 +61570 0.3885498046875 +61571 0.275390625 +61572 0.362640380859375 +61573 0.250244140625 +61574 0.27362060546875 +61575 0.18218994140625 +61576 0.11712646484375 +61577 0.068695068359375 +61578 -0.054901123046875 +61579 -0.054534912109375 +61580 -0.19085693359375 +61581 -0.152099609375 +61582 -0.28570556640625 +61583 -0.2203369140625 +61584 -0.339263916015625 +61585 -0.25897216796875 +61586 -0.3775634765625 +61587 -0.285614013671875 +61588 -0.445709228515625 +61589 -0.330963134765625 +61590 -0.535064697265625 +61591 -0.389251708984375 +61592 -0.629058837890625 +61593 -0.449371337890625 +61594 -0.697601318359375 +61595 -0.4910888671875 +61596 -0.70391845703125 +61597 -0.489715576171875 +61598 -0.6424560546875 +61599 -0.441802978515625 +61600 -0.491241455078125 +61601 -0.332733154296875 +61602 -0.265716552734375 +61603 -0.173370361328125 +61604 -0.023712158203125 +61605 -0.00335693359375 +61606 0.201751708984375 +61607 0.154541015625 +61608 0.375823974609375 +61609 0.276397705078125 +61610 0.485076904296875 +61611 0.352935791015625 +61612 0.56884765625 +61613 0.41082763671875 +61614 0.634765625 +61615 0.45526123046875 +61616 0.63763427734375 +61617 0.45556640625 +61618 0.5660400390625 +61619 0.404083251953125 +61620 0.4720458984375 +61621 0.336395263671875 +61622 0.40692138671875 +61623 0.28759765625 +61624 0.3778076171875 +61625 0.2628173828125 +61626 0.376953125 +61627 0.257080078125 +61628 0.371978759765625 +61629 0.2486572265625 +61630 0.313140869140625 +61631 0.204010009765625 +61632 0.184417724609375 +61633 0.112457275390625 +61634 0.011199951171875 +61635 -0.008514404296875 +61636 -0.171051025390625 +61637 -0.1346435546875 +61638 -0.33740234375 +61639 -0.2489013671875 +61640 -0.47198486328125 +61641 -0.340423583984375 +61642 -0.560394287109375 +61643 -0.39947509765625 +61644 -0.58056640625 +61645 -0.411163330078125 +61646 -0.54754638671875 +61647 -0.385833740234375 +61648 -0.508575439453125 +61649 -0.355804443359375 +61650 -0.459503173828125 +61651 -0.318450927734375 +61652 -0.394378662109375 +61653 -0.269989013671875 +61654 -0.35260009765625 +61655 -0.237396240234375 +61656 -0.31170654296875 +61657 -0.20562744140625 +61658 -0.197418212890625 +61659 -0.124420166015625 +61660 -0.007965087890625 +61661 0.007232666015625 +61662 0.207489013671875 +61663 0.155792236328125 +61664 0.409210205078125 +61665 0.29412841796875 +61666 0.57208251953125 +61667 0.405120849609375 +61668 0.66595458984375 +61669 0.468292236328125 +61670 0.65875244140625 +61671 0.4619140625 +61672 0.56744384765625 +61673 0.397613525390625 +61674 0.431396484375 +61675 0.302337646484375 +61676 0.29443359375 +61677 0.2060546875 +61678 0.182464599609375 +61679 0.126556396484375 +61680 0.06365966796875 +61681 0.0423583984375 +61682 -0.075958251953125 +61683 -0.055816650390625 +61684 -0.189422607421875 +61685 -0.1358642578125 +61686 -0.271942138671875 +61687 -0.19439697265625 +61688 -0.342529296875 +61689 -0.24420166015625 +61690 -0.364166259765625 +61691 -0.26007080078125 +61692 -0.327239990234375 +61693 -0.23541259765625 +61694 -0.2769775390625 +61695 -0.20098876953125 +61696 -0.253692626953125 +61697 -0.184478759765625 +61698 -0.24365234375 +61699 -0.176361083984375 +61700 -0.1983642578125 +61701 -0.1427001953125 +61702 -0.116241455078125 +61703 -0.08258056640625 +61704 -0.036834716796875 +61705 -0.024383544921875 +61706 0.034881591796875 +61707 0.028167724609375 +61708 0.09124755859375 +61709 0.06951904296875 +61710 0.10888671875 +61711 0.082916259765625 +61712 0.125518798828125 +61713 0.095184326171875 +61714 0.15771484375 +61715 0.118133544921875 +61716 0.17828369140625 +61717 0.13238525390625 +61718 0.17108154296875 +61719 0.126495361328125 +61720 0.129974365234375 +61721 0.09619140625 +61722 0.082427978515625 +61723 0.06109619140625 +61724 0.027679443359375 +61725 0.020751953125 +61726 -0.065643310546875 +61727 -0.047088623046875 +61728 -0.15936279296875 +61729 -0.115142822265625 +61730 -0.21307373046875 +61731 -0.154571533203125 +61732 -0.234649658203125 +61733 -0.1708984375 +61734 -0.2001953125 +61735 -0.1470947265625 +61736 -0.119171142578125 +61737 -0.08984375 +61738 -0.024749755859375 +61739 -0.02276611328125 +61740 0.085784912109375 +61741 0.056060791015625 +61742 0.178131103515625 +61743 0.122222900390625 +61744 0.215576171875 +61745 0.1495361328125 +61746 0.211456298828125 +61747 0.1474609375 +61748 0.17523193359375 +61749 0.1226806640625 +61750 0.128753662109375 +61751 0.090667724609375 +61752 0.1019287109375 +61753 0.072662353515625 +61754 0.0743408203125 +61755 0.054107666015625 +61756 0.04327392578125 +61757 0.032989501953125 +61758 0.038177490234375 +61759 0.03021240234375 +61760 0.076263427734375 +61761 0.0579833984375 +61762 0.14105224609375 +61763 0.10455322265625 +61764 0.186431884765625 +61765 0.137054443359375 +61766 0.188812255859375 +61767 0.138702392578125 +61768 0.1390380859375 +61769 0.102996826171875 +61770 0.041778564453125 +61771 0.03326416015625 +61772 -0.079437255859375 +61773 -0.05364990234375 +61774 -0.219390869140625 +61775 -0.154052734375 +61776 -0.367828369140625 +61777 -0.260589599609375 +61778 -0.494873046875 +61779 -0.3519287109375 +61780 -0.556243896484375 +61781 -0.396514892578125 +61782 -0.508697509765625 +61783 -0.363494873046875 +61784 -0.3756103515625 +61785 -0.26947021484375 +61786 -0.218902587890625 +61787 -0.15850830078125 +61788 -0.063751220703125 +61789 -0.0484619140625 +61790 0.091552734375 +61791 0.061859130859375 +61792 0.23602294921875 +61793 0.164642333984375 +61794 0.342987060546875 +61795 0.24090576171875 +61796 0.39520263671875 +61797 0.278350830078125 +61798 0.389373779296875 +61799 0.274627685546875 +61800 0.324249267578125 +61801 0.22882080078125 +61802 0.224090576171875 +61803 0.158172607421875 +61804 0.124267578125 +61805 0.08782958984375 +61806 0.037078857421875 +61807 0.026458740234375 +61808 -0.010101318359375 +61809 -0.006439208984375 +61810 -0.019439697265625 +61811 -0.012451171875 +61812 -0.022796630859375 +61813 -0.0142822265625 +61814 -0.001556396484375 +61815 0.00128173828125 +61816 0.056304931640625 +61817 0.042755126953125 +61818 0.106719970703125 +61819 0.0787353515625 +61820 0.096893310546875 +61821 0.071685791015625 +61822 0.042694091796875 +61823 0.03289794921875 +61824 -0.018035888671875 +61825 -0.010650634765625 +61826 -0.07586669921875 +61827 -0.05224609375 +61828 -0.11944580078125 +61829 -0.083740234375 +61830 -0.15972900390625 +61831 -0.11297607421875 +61832 -0.202606201171875 +61833 -0.144073486328125 +61834 -0.24859619140625 +61835 -0.177337646484375 +61836 -0.30517578125 +61837 -0.21807861328125 +61838 -0.36212158203125 +61839 -0.259033203125 +61840 -0.39141845703125 +61841 -0.280242919921875 +61842 -0.35528564453125 +61843 -0.254730224609375 +61844 -0.249969482421875 +61845 -0.179840087890625 +61846 -0.092864990234375 +61847 -0.0679931640625 +61848 0.08905029296875 +61849 0.061614990234375 +61850 0.2352294921875 +61851 0.165863037109375 +61852 0.318817138671875 +61853 0.225616455078125 +61854 0.358642578125 +61855 0.2542724609375 +61856 0.347747802734375 +61857 0.246856689453125 +61858 0.28564453125 +61859 0.2030029296875 +61860 0.223175048828125 +61861 0.158905029296875 +61862 0.196746826171875 +61863 0.140472412109375 +61864 0.179840087890625 +61865 0.128814697265625 +61866 0.155548095703125 +61867 0.111846923828125 +61868 0.151214599609375 +61869 0.109039306640625 +61870 0.156951904296875 +61871 0.11334228515625 +61872 0.13177490234375 +61873 0.09552001953125 +61874 0.100799560546875 +61875 0.073486328125 +61876 0.087127685546875 +61877 0.06365966796875 +61878 0.05487060546875 +61879 0.040496826171875 +61880 -0.009002685546875 +61881 -0.0052490234375 +61882 -0.10400390625 +61883 -0.07318115234375 +61884 -0.229400634765625 +61885 -0.16278076171875 +61886 -0.35552978515625 +61887 -0.252899169921875 +61888 -0.441925048828125 +61889 -0.314697265625 +61890 -0.473846435546875 +61891 -0.33770751953125 +61892 -0.464813232421875 +61893 -0.331512451171875 +61894 -0.419097900390625 +61895 -0.29913330078125 +61896 -0.334320068359375 +61897 -0.2388916015625 +61898 -0.227935791015625 +61899 -0.1632080078125 +61900 -0.12347412109375 +61901 -0.088836669921875 +61902 -0.02764892578125 +61903 -0.020538330078125 +61904 0.077667236328125 +61905 0.0545654296875 +61906 0.2132568359375 +61907 0.151275634765625 +61908 0.38885498046875 +61909 0.2764892578125 +61910 0.582794189453125 +61911 0.414794921875 +61912 0.734039306640625 +61913 0.522705078125 +61914 0.800140380859375 +61915 0.569976806640625 +61916 0.7783203125 +61917 0.554595947265625 +61918 0.6651611328125 +61919 0.474151611328125 +61920 0.45965576171875 +61921 0.32794189453125 +61922 0.199188232421875 +61923 0.142547607421875 +61924 -0.050689697265625 +61925 -0.03533935546875 +61926 -0.23297119140625 +61927 -0.165130615234375 +61928 -0.33013916015625 +61929 -0.234375 +61930 -0.368408203125 +61931 -0.26171875 +61932 -0.378936767578125 +61933 -0.269317626953125 +61934 -0.376983642578125 +61935 -0.268035888671875 +61936 -0.37969970703125 +61937 -0.270111083984375 +61938 -0.391510009765625 +61939 -0.278656005859375 +61940 -0.385345458984375 +61941 -0.2744140625 +61942 -0.3419189453125 +61943 -0.243621826171875 +61944 -0.28289794921875 +61945 -0.20172119140625 +61946 -0.251617431640625 +61947 -0.179534912109375 +61948 -0.266143798828125 +61949 -0.189910888671875 +61950 -0.273345947265625 +61951 -0.195037841796875 +61952 -0.216796875 +61953 -0.154632568359375 +61954 -0.128265380859375 +61955 -0.091522216796875 +61956 -0.068145751953125 +61957 -0.04974365234375 +61958 -0.0430908203125 +61959 -0.034027099609375 +61960 -0.024444580078125 +61961 -0.022918701171875 +61962 0.020721435546875 +61963 0.008270263671875 +61964 0.124481201171875 +61965 0.083465576171875 +61966 0.25787353515625 +61967 0.181243896484375 +61968 0.379119873046875 +61969 0.27056884765625 +61970 0.47991943359375 +61971 0.3453369140625 +61972 0.5281982421875 +61973 0.38165283203125 +61974 0.511138916015625 +61975 0.369964599609375 +61976 0.456207275390625 +61977 0.330657958984375 +61978 0.407470703125 +61979 0.296417236328125 +61980 0.383758544921875 +61981 0.281097412109375 +61982 0.35687255859375 +61983 0.263580322265625 +61984 0.31182861328125 +61985 0.232574462890625 +61986 0.250885009765625 +61987 0.18963623046875 +61988 0.1654052734375 +61989 0.128173828125 +61990 0.035247802734375 +61991 0.03314208984375 +61992 -0.142059326171875 +61993 -0.097381591796875 +61994 -0.33563232421875 +61995 -0.240478515625 +61996 -0.5345458984375 +61997 -0.388031005859375 +61998 -0.72186279296875 +61999 -0.527496337890625 +62000 -0.836669921875 +62001 -0.613525390625 +62002 -0.8326416015625 +62003 -0.611602783203125 +62004 -0.7296142578125 +62005 -0.536407470703125 +62006 -0.582550048828125 +62007 -0.428741455078125 +62008 -0.440093994140625 +62009 -0.32470703125 +62010 -0.324310302734375 +62011 -0.2406005859375 +62012 -0.20147705078125 +62013 -0.151214599609375 +62014 -0.044647216796875 +62015 -0.036376953125 +62016 0.103973388671875 +62017 0.07257080078125 +62018 0.202392578125 +62019 0.14447021484375 +62020 0.264495849609375 +62021 0.189727783203125 +62022 0.338897705078125 +62023 0.24456787109375 +62024 0.443817138671875 +62025 0.322540283203125 +62026 0.545074462890625 +62027 0.398193359375 +62028 0.6173095703125 +62029 0.45263671875 +62030 0.6524658203125 +62031 0.479827880859375 +62032 0.66339111328125 +62033 0.4892578125 +62034 0.6561279296875 +62035 0.4853515625 +62036 0.606781005859375 +62037 0.450225830078125 +62038 0.501190185546875 +62039 0.373260498046875 +62040 0.352783203125 +62041 0.264373779296875 +62042 0.176544189453125 +62043 0.134613037109375 +62044 -0.034820556640625 +62045 -0.021484375 +62046 -0.258209228515625 +62047 -0.186798095703125 +62048 -0.44244384765625 +62049 -0.32330322265625 +62050 -0.5753173828125 +62051 -0.421905517578125 +62052 -0.65203857421875 +62053 -0.47906494140625 +62054 -0.641632080078125 +62055 -0.471710205078125 +62056 -0.562164306640625 +62057 -0.413299560546875 +62058 -0.458038330078125 +62059 -0.3367919921875 +62060 -0.350555419921875 +62061 -0.257965087890625 +62062 -0.260528564453125 +62063 -0.192230224609375 +62064 -0.192108154296875 +62065 -0.142608642578125 +62066 -0.141937255859375 +62067 -0.106536865234375 +62068 -0.1021728515625 +62069 -0.078094482421875 +62070 -0.062896728515625 +62071 -0.04986572265625 +62072 -0.011932373046875 +62073 -0.012725830078125 +62074 0.062835693359375 +62075 0.0423583984375 +62076 0.148712158203125 +62077 0.105987548828125 +62078 0.241729736328125 +62079 0.1751708984375 +62080 0.34912109375 +62081 0.25531005859375 +62082 0.457305908203125 +62083 0.336273193359375 +62084 0.54388427734375 +62085 0.4013671875 +62086 0.5728759765625 +62087 0.42376708984375 +62088 0.506591796875 +62089 0.375396728515625 +62090 0.351226806640625 +62091 0.26080322265625 +62092 0.146514892578125 +62093 0.109466552734375 +62094 -0.05523681640625 +62095 -0.03973388671875 +62096 -0.21624755859375 +62097 -0.158721923828125 +62098 -0.334930419921875 +62099 -0.246337890625 +62100 -0.402984619140625 +62101 -0.29644775390625 +62102 -0.4412841796875 +62103 -0.3245849609375 +62104 -0.49578857421875 +62105 -0.364990234375 +62106 -0.5601806640625 +62107 -0.412933349609375 +62108 -0.600738525390625 +62109 -0.443328857421875 +62110 -0.584228515625 +62111 -0.43145751953125 +62112 -0.47930908203125 +62113 -0.35394287109375 +62114 -0.27935791015625 +62115 -0.20587158203125 +62116 -0.0089111328125 +62117 -0.00543212890625 +62118 0.268798828125 +62119 0.200347900390625 +62120 0.482818603515625 +62121 0.3587646484375 +62122 0.60369873046875 +62123 0.447967529296875 +62124 0.650421142578125 +62125 0.4820556640625 +62126 0.66400146484375 +62127 0.4915771484375 +62128 0.6414794921875 +62129 0.474395751953125 +62130 0.572540283203125 +62131 0.422821044921875 +62132 0.498138427734375 +62133 0.36737060546875 +62134 0.439453125 +62135 0.32379150390625 +62136 0.375518798828125 +62137 0.2764892578125 +62138 0.274505615234375 +62139 0.201751708984375 +62140 0.1087646484375 +62141 0.0789794921875 +62142 -0.099395751953125 +62143 -0.075286865234375 +62144 -0.3182373046875 +62145 -0.2374267578125 +62146 -0.5489501953125 +62147 -0.408355712890625 +62148 -0.7738037109375 +62149 -0.574920654296875 +62150 -0.86383056640625 +62151 -0.697784423828125 +62152 -0.870391845703125 +62153 -0.752227783203125 +62154 -0.86895751953125 +62155 -0.751495361328125 +62156 -0.861053466796875 +62157 -0.705322265625 +62158 -0.765869140625 +62159 -0.600860595703125 +62160 -0.5301513671875 +62161 -0.42974853515625 +62162 -0.214691162109375 +62163 -0.197296142578125 +62164 0.137359619140625 +62165 0.064483642578125 +62166 0.474822998046875 +62167 0.31744384765625 +62168 0.76239013671875 +62169 0.535186767578125 +62170 0.867462158203125 +62171 0.6976318359375 +62172 0.870361328125 +62173 0.80517578125 +62174 0.86480712890625 +62175 0.849212646484375 +62176 0.831817626953125 +62177 0.833770751953125 +62178 0.677581787109375 +62179 0.777008056640625 +62180 0.495880126953125 +62181 0.683258056640625 +62182 0.30767822265625 +62183 0.56634521484375 +62184 0.116180419921875 +62185 0.427947998046875 +62186 -0.110748291015625 +62187 0.24444580078125 +62188 -0.381805419921875 +62189 0.010711669921875 +62190 -0.6572265625 +62191 -0.241424560546875 +62192 -0.857421875 +62193 -0.4674072265625 +62194 -0.870391845703125 +62195 -0.635284423828125 +62196 -0.870391845703125 +62197 -0.739776611328125 +62198 -0.86444091796875 +62199 -0.8009033203125 +62200 -0.85723876953125 +62201 -0.84521484375 +62202 -0.790008544921875 +62203 -0.855010986328125 +62204 -0.62847900390625 +62205 -0.802215576171875 +62206 -0.3956298828125 +62207 -0.67218017578125 +62208 -0.126708984375 +62209 -0.493408203125 +62210 0.150115966796875 +62211 -0.28631591796875 +62212 0.424041748046875 +62213 -0.059326171875 +62214 0.670623779296875 +62215 0.167266845703125 +62216 0.854522705078125 +62217 0.3638916015625 +62218 0.866485595703125 +62219 0.517333984375 +62220 0.86920166015625 +62221 0.615997314453125 +62222 0.8653564453125 +62223 0.674224853515625 +62224 0.857147216796875 +62225 0.70257568359375 +62226 0.766845703125 +62227 0.69879150390625 +62228 0.628509521484375 +62229 0.666778564453125 +62230 0.462127685546875 +62231 0.60113525390625 +62232 0.297210693359375 +62233 0.521636962890625 +62234 0.14862060546875 +62235 0.43756103515625 +62236 -0.00537109375 +62237 0.330841064453125 +62238 -0.15753173828125 +62239 0.2069091796875 +62240 -0.31304931640625 +62241 0.06256103515625 +62242 -0.48876953125 +62243 -0.1134033203125 +62244 -0.6416015625 +62245 -0.284942626953125 +62246 -0.751373291015625 +62247 -0.433135986328125 +62248 -0.84619140625 +62249 -0.57611083984375 +62250 -0.861297607421875 +62251 -0.70257568359375 +62252 -0.863250732421875 +62253 -0.78680419921875 +62254 -0.856597900390625 +62255 -0.80426025390625 +62256 -0.7498779296875 +62257 -0.7642822265625 +62258 -0.624542236328125 +62259 -0.7115478515625 +62260 -0.47808837890625 +62261 -0.6287841796875 +62262 -0.253387451171875 +62263 -0.4703369140625 +62264 0.003692626953125 +62265 -0.271331787109375 +62266 0.2257080078125 +62267 -0.084564208984375 +62268 0.427154541015625 +62269 0.0999755859375 +62270 0.643218994140625 +62271 0.30767822265625 +62272 0.855926513671875 +62273 0.531219482421875 +62274 0.870361328125 +62275 0.725830078125 +62276 0.870361328125 +62277 0.853057861328125 +62278 0.862762451171875 +62279 0.8614501953125 +62280 0.79669189453125 +62281 0.861602783203125 +62282 0.595794677734375 +62283 0.849761962890625 +62284 0.362152099609375 +62285 0.73065185546875 +62286 0.1270751953125 +62287 0.58416748046875 +62288 -0.086944580078125 +62289 0.426513671875 +62290 -0.2784423828125 +62291 0.259124755859375 +62292 -0.484832763671875 +62293 0.0548095703125 +62294 -0.729583740234375 +62295 -0.201507568359375 +62296 -0.86688232421875 +62297 -0.470703125 +62298 -0.870391845703125 +62299 -0.703765869140625 +62300 -0.86859130859375 +62301 -0.859130859375 +62302 -0.86279296875 +62303 -0.870391845703125 +62304 -0.817962646484375 +62305 -0.870391845703125 +62306 -0.6116943359375 +62307 -0.8599853515625 +62308 -0.3128662109375 +62309 -0.712371826171875 +62310 0.039398193359375 +62311 -0.4517822265625 +62312 0.422821044921875 +62313 -0.140289306640625 +62314 0.805145263671875 +62315 0.195465087890625 +62316 0.870361328125 +62317 0.5029296875 +62318 0.870361328125 +62319 0.739105224609375 +62320 0.860015869140625 +62321 0.859100341796875 +62322 0.727935791015625 +62323 0.867462158203125 +62324 0.48114013671875 +62325 0.8668212890625 +62326 0.2059326171875 +62327 0.85968017578125 +62328 -0.06103515625 +62329 0.798126220703125 +62330 -0.29913330078125 +62331 0.66748046875 +62332 -0.516204833984375 +62333 0.502532958984375 +62334 -0.7252197265625 +62335 0.29449462890625 +62336 -0.85980224609375 +62337 0.0653076171875 +62338 -0.870391845703125 +62339 -0.15643310546875 +62340 -0.870391845703125 +62341 -0.34661865234375 +62342 -0.858062744140625 +62343 -0.467132568359375 +62344 -0.673004150390625 +62345 -0.515167236328125 +62346 -0.42694091796875 +62347 -0.53265380859375 +62348 -0.2100830078125 +62349 -0.55584716796875 +62350 -0.0362548828125 +62351 -0.58551025390625 +62352 0.10943603515625 +62353 -0.60186767578125 +62354 0.23516845703125 +62355 -0.592529296875 +62356 0.373687744140625 +62357 -0.528472900390625 +62358 0.517791748046875 +62359 -0.4141845703125 +62360 0.602783203125 +62361 -0.30133056640625 +62362 0.635711669921875 +62363 -0.188262939453125 +62364 0.655181884765625 +62365 -0.05096435546875 +62366 0.65948486328125 +62367 0.101531982421875 +62368 0.651275634765625 +62369 0.26239013671875 +62370 0.61846923828125 +62371 0.41259765625 +62372 0.53753662109375 +62373 0.524078369140625 +62374 0.404144287109375 +62375 0.584014892578125 +62376 0.22186279296875 +62377 0.586578369140625 +62378 0.003997802734375 +62379 0.534820556640625 +62380 -0.22100830078125 +62381 0.44512939453125 +62382 -0.42449951171875 +62383 0.336029052734375 +62384 -0.579833984375 +62385 0.22662353515625 +62386 -0.641876220703125 +62387 0.15240478515625 +62388 -0.6177978515625 +62389 0.11029052734375 +62390 -0.575531005859375 +62391 0.0518798828125 +62392 -0.526336669921875 +62393 -0.02569580078125 +62394 -0.42645263671875 +62395 -0.08148193359375 +62396 -0.2581787109375 +62397 -0.093963623046875 +62398 -0.068695068359375 +62399 -0.091644287109375 +62400 0.09222412109375 +62401 -0.105194091796875 +62402 0.232147216796875 +62403 -0.12139892578125 +62404 0.3509521484375 +62405 -0.133941650390625 +62406 0.410064697265625 +62407 -0.167633056640625 +62408 0.372955322265625 +62409 -0.247161865234375 +62410 0.2554931640625 +62411 -0.3582763671875 +62412 0.10711669921875 +62413 -0.46246337890625 +62414 -0.052886962890625 +62415 -0.5462646484375 +62416 -0.186279296875 +62417 -0.5830078125 +62418 -0.23291015625 +62419 -0.530426025390625 +62420 -0.209442138671875 +62421 -0.40692138671875 +62422 -0.174163818359375 +62423 -0.263946533203125 +62424 -0.126739501953125 +62425 -0.10784912109375 +62426 -0.048126220703125 +62427 0.06951904296875 +62428 0.0426025390625 +62429 0.247100830078125 +62430 0.10748291015625 +62431 0.389892578125 +62432 0.1409912109375 +62433 0.48895263671875 +62434 0.19708251953125 +62435 0.582733154296875 +62436 0.273651123046875 +62437 0.66754150390625 +62438 0.31768798828125 +62439 0.701568603515625 +62440 0.341094970703125 +62441 0.694793701171875 +62442 0.368011474609375 +62443 0.66802978515625 +62444 0.37249755859375 +62445 0.6043701171875 +62446 0.30072021484375 +62447 0.466278076171875 +62448 0.1517333984375 +62449 0.2579345703125 +62450 -0.01470947265625 +62451 0.031036376953125 +62452 -0.1883544921875 +62453 -0.200958251953125 +62454 -0.372711181640625 +62455 -0.43548583984375 +62456 -0.51397705078125 +62457 -0.6259765625 +62458 -0.57177734375 +62459 -0.736968994140625 +62460 -0.53948974609375 +62461 -0.760162353515625 +62462 -0.43511962890625 +62463 -0.707427978515625 +62464 -0.2962646484375 +62465 -0.606689453125 +62466 -0.161102294921875 +62467 -0.487640380859375 +62468 -0.0435791015625 +62469 -0.362579345703125 +62470 0.060394287109375 +62471 -0.2308349609375 +62472 0.13665771484375 +62473 -0.107086181640625 +62474 0.170135498046875 +62475 -0.00738525390625 +62476 0.16552734375 +62477 0.067626953125 +62478 0.15728759765625 +62479 0.14093017578125 +62480 0.150787353515625 +62481 0.21240234375 +62482 0.12200927734375 +62483 0.25872802734375 +62484 0.080108642578125 +62485 0.283660888671875 +62486 0.05126953125 +62487 0.3052978515625 +62488 0.062896728515625 +62489 0.343536376953125 +62490 0.09271240234375 +62491 0.379425048828125 +62492 0.092987060546875 +62493 0.3746337890625 +62494 0.07855224609375 +62495 0.341796875 +62496 0.06427001953125 +62497 0.29443359375 +62498 0.0347900390625 +62499 0.22265625 +62500 -0.01171875 +62501 0.127960205078125 +62502 -0.056060791015625 +62503 0.029144287109375 +62504 -0.055511474609375 +62505 -0.035980224609375 +62506 -0.010467529296875 +62507 -0.064056396484375 +62508 0.02508544921875 +62509 -0.094818115234375 +62510 0.025665283203125 +62511 -0.145538330078125 +62512 0.017333984375 +62513 -0.19281005859375 +62514 0.00189208984375 +62515 -0.233306884765625 +62516 -0.03173828125 +62517 -0.27471923828125 +62518 -0.071502685546875 +62519 -0.30706787109375 +62520 -0.13543701171875 +62521 -0.3450927734375 +62522 -0.219970703125 +62523 -0.387054443359375 +62524 -0.300506591796875 +62525 -0.4150390625 +62526 -0.376312255859375 +62527 -0.430755615234375 +62528 -0.416107177734375 +62529 -0.411865234375 +62530 -0.371124267578125 +62531 -0.322296142578125 +62532 -0.242279052734375 +62533 -0.165771484375 +62534 -0.069732666015625 +62535 0.02264404296875 +62536 0.125640869140625 +62537 0.22357177734375 +62538 0.31268310546875 +62539 0.409820556640625 +62540 0.45501708984375 +62541 0.550537109375 +62542 0.554779052734375 +62543 0.646270751953125 +62544 0.61065673828125 +62545 0.695404052734375 +62546 0.610931396484375 +62547 0.688629150390625 +62548 0.531463623046875 +62549 0.60736083984375 +62550 0.3883056640625 +62551 0.465728759765625 +62552 0.23468017578125 +62553 0.308074951171875 +62554 0.095245361328125 +62555 0.156219482421875 +62556 -0.00396728515625 +62557 0.0333251953125 +62558 -0.04852294921875 +62559 -0.046600341796875 +62560 -0.055145263671875 +62561 -0.094451904296875 +62562 -0.0758056640625 +62563 -0.149566650390625 +62564 -0.138702392578125 +62565 -0.232513427734375 +62566 -0.209197998046875 +62567 -0.31396484375 +62568 -0.289031982421875 +62569 -0.394195556640625 +62570 -0.37884521484375 +62571 -0.473052978515625 +62572 -0.456329345703125 +62573 -0.532562255859375 +62574 -0.51641845703125 +62575 -0.569091796875 +62576 -0.519287109375 +62577 -0.551666259765625 +62578 -0.458251953125 +62579 -0.47625732421875 +62580 -0.384796142578125 +62581 -0.38568115234375 +62582 -0.323699951171875 +62583 -0.301666259765625 +62584 -0.269287109375 +62585 -0.221649169921875 +62586 -0.1951904296875 +62587 -0.1265869140625 +62588 -0.100006103515625 +62589 -0.01727294921875 +62590 -0.01055908203125 +62591 0.083038330078125 +62592 0.1033935546875 +62593 0.197113037109375 +62594 0.24908447265625 +62595 0.329681396484375 +62596 0.373199462890625 +62597 0.437408447265625 +62598 0.45806884765625 +62599 0.50592041015625 +62600 0.511474609375 +62601 0.5416259765625 +62602 0.565399169921875 +62603 0.570770263671875 +62604 0.61138916015625 +62605 0.5875244140625 +62606 0.5897216796875 +62607 0.545379638671875 +62608 0.4906005859375 +62609 0.43792724609375 +62610 0.33148193359375 +62611 0.280792236328125 +62612 0.147796630859375 +62613 0.10400390625 +62614 -0.01873779296875 +62615 -0.05743408203125 +62616 -0.140289306640625 +62617 -0.17974853515625 +62618 -0.191986083984375 +62619 -0.241790771484375 +62620 -0.184295654296875 +62621 -0.25091552734375 +62622 -0.161834716796875 +62623 -0.242156982421875 +62624 -0.166595458984375 +62625 -0.248748779296875 +62626 -0.19390869140625 +62627 -0.2669677734375 +62628 -0.22442626953125 +62629 -0.28173828125 +62630 -0.279754638671875 +62631 -0.31103515625 +62632 -0.3389892578125 +62633 -0.339111328125 +62634 -0.3543701171875 +62635 -0.3289794921875 +62636 -0.348175048828125 +62637 -0.29974365234375 +62638 -0.32598876953125 +62639 -0.257232666015625 +62640 -0.2581787109375 +62641 -0.17913818359375 +62642 -0.139801025390625 +62643 -0.062774658203125 +62644 0.014617919921875 +62645 0.07916259765625 +62646 0.144378662109375 +62647 0.1971435546875 +62648 0.221038818359375 +62649 0.267791748046875 +62650 0.27069091796875 +62651 0.311614990234375 +62652 0.294036865234375 +62653 0.3291015625 +62654 0.311767578125 +62655 0.337005615234375 +62656 0.339141845703125 +62657 0.34808349609375 +62658 0.360260009765625 +62659 0.35040283203125 +62660 0.360504150390625 +62661 0.333160400390625 +62662 0.308380126953125 +62663 0.271881103515625 +62664 0.18170166015625 +62665 0.14971923828125 +62666 0.0047607421875 +62667 -0.0125732421875 +62668 -0.17559814453125 +62669 -0.1761474609375 +62670 -0.3143310546875 +62671 -0.3037109375 +62672 -0.36785888671875 +62673 -0.359283447265625 +62674 -0.36248779296875 +62675 -0.363494873046875 +62676 -0.343536376953125 +62677 -0.352630615234375 +62678 -0.3018798828125 +62679 -0.319244384765625 +62680 -0.231414794921875 +62681 -0.258453369140625 +62682 -0.117645263671875 +62683 -0.158905029296875 +62684 0.007049560546875 +62685 -0.047271728515625 +62686 0.087982177734375 +62687 0.031585693359375 +62688 0.13946533203125 +62689 0.088409423828125 +62690 0.17425537109375 +62691 0.13262939453125 +62692 0.188201904296875 +62693 0.15997314453125 +62694 0.171234130859375 +62695 0.16143798828125 +62696 0.118438720703125 +62697 0.13226318359375 +62698 0.05706787109375 +62699 0.093780517578125 +62700 -0.010711669921875 +62701 0.04718017578125 +62702 -0.0914306640625 +62703 -0.013153076171875 +62704 -0.162322998046875 +62705 -0.0689697265625 +62706 -0.194549560546875 +62707 -0.09698486328125 +62708 -0.1492919921875 +62709 -0.06561279296875 +62710 -0.02166748046875 +62711 0.029449462890625 +62712 0.124053955078125 +62713 0.136810302734375 +62714 0.211151123046875 +62715 0.195098876953125 +62716 0.240447998046875 +62717 0.205718994140625 +62718 0.242218017578125 +62719 0.19384765625 +62720 0.2257080078125 +62721 0.168243408203125 +62722 0.194366455078125 +62723 0.132080078125 +62724 0.115509033203125 +62725 0.05780029296875 +62726 0.0128173828125 +62727 -0.03424072265625 +62728 -0.053802490234375 +62729 -0.093475341796875 +62730 -0.110626220703125 +62731 -0.141845703125 +62732 -0.199493408203125 +62733 -0.21453857421875 +62734 -0.29437255859375 +62735 -0.289825439453125 +62736 -0.33221435546875 +62737 -0.315032958984375 +62738 -0.27972412109375 +62739 -0.26263427734375 +62740 -0.185333251953125 +62741 -0.17376708984375 +62742 -0.128204345703125 +62743 -0.115478515625 +62744 -0.115692138671875 +62745 -0.094512939453125 +62746 -0.116455078125 +62747 -0.08514404296875 +62748 -0.105926513671875 +62749 -0.0672607421875 +62750 -0.053955078125 +62751 -0.016021728515625 +62752 0.048797607421875 +62753 0.0760498046875 +62754 0.157318115234375 +62755 0.1708984375 +62756 0.212005615234375 +62757 0.21832275390625 +62758 0.218475341796875 +62759 0.222991943359375 +62760 0.23724365234375 +62761 0.235870361328125 +62762 0.30535888671875 +62763 0.288299560546875 +62764 0.38128662109375 +62765 0.345703125 +62766 0.404449462890625 +62767 0.3575439453125 +62768 0.3944091796875 +62769 0.34075927734375 +62770 0.3885498046875 +62771 0.32720947265625 +62772 0.362640380859375 +62773 0.297027587890625 +62774 0.27362060546875 +62775 0.2144775390625 +62776 0.11712646484375 +62777 0.0762939453125 +62778 -0.054901123046875 +62779 -0.073486328125 +62780 -0.19085693359375 +62781 -0.1912841796875 +62782 -0.28570556640625 +62783 -0.27276611328125 +62784 -0.339263916015625 +62785 -0.317718505859375 +62786 -0.3775634765625 +62787 -0.34808349609375 +62788 -0.445709228515625 +62789 -0.401885986328125 +62790 -0.535064697265625 +62791 -0.47210693359375 +62792 -0.629058837890625 +62793 -0.54510498046875 +62794 -0.697601318359375 +62795 -0.59600830078125 +62796 -0.70391845703125 +62797 -0.594268798828125 +62798 -0.6424560546875 +62799 -0.535614013671875 +62800 -0.491241455078125 +62801 -0.4019775390625 +62802 -0.265716552734375 +62803 -0.206695556640625 +62804 -0.023712158203125 +62805 0.001373291015625 +62806 0.201751708984375 +62807 0.1942138671875 +62808 0.375823974609375 +62809 0.3424072265625 +62810 0.485076904296875 +62811 0.43463134765625 +62812 0.56884765625 +62813 0.503997802734375 +62814 0.634765625 +62815 0.556976318359375 +62816 0.63763427734375 +62817 0.555755615234375 +62818 0.5660400390625 +62819 0.490966796875 +62820 0.4720458984375 +62821 0.406646728515625 +62822 0.40692138671875 +62823 0.346160888671875 +62824 0.3778076171875 +62825 0.31585693359375 +62826 0.376953125 +62827 0.309539794921875 +62828 0.371978759765625 +62829 0.30029296875 +62830 0.313140869140625 +62831 0.246612548828125 +62832 0.184417724609375 +62833 0.135223388671875 +62834 0.011199951171875 +62835 -0.0123291015625 +62836 -0.171051025390625 +62837 -0.16619873046875 +62838 -0.33740234375 +62839 -0.305450439453125 +62840 -0.47198486328125 +62841 -0.41680908203125 +62842 -0.560394287109375 +62843 -0.48834228515625 +62844 -0.58056640625 +62845 -0.501678466796875 +62846 -0.54754638671875 +62847 -0.46966552734375 +62848 -0.508575439453125 +62849 -0.4322509765625 +62850 -0.459503173828125 +62851 -0.386199951171875 +62852 -0.394378662109375 +62853 -0.326812744140625 +62854 -0.35260009765625 +62855 -0.28741455078125 +62856 -0.31170654296875 +62857 -0.249359130859375 +62858 -0.197418212890625 +62859 -0.150421142578125 +62860 -0.007965087890625 +62861 0.0107421875 +62862 0.207489013671875 +62863 0.192718505859375 +62864 0.409210205078125 +62865 0.362091064453125 +62866 0.57208251953125 +62867 0.497802734375 +62868 0.66595458984375 +62869 0.57464599609375 +62870 0.65875244140625 +62871 0.5657958984375 +62872 0.56744384765625 +62873 0.485687255859375 +62874 0.431396484375 +62875 0.36761474609375 +62876 0.29443359375 +62877 0.24859619140625 +62878 0.182464599609375 +62879 0.150634765625 +62880 0.06365966796875 +62881 0.04718017578125 +62882 -0.075958251953125 +62883 -0.07330322265625 +62884 -0.189422607421875 +62885 -0.17120361328125 +62886 -0.271942138671875 +62887 -0.24237060546875 +62888 -0.342529296875 +62889 -0.30267333984375 +62890 -0.364166259765625 +62891 -0.321014404296875 +62892 -0.327239990234375 +62893 -0.28936767578125 +62894 -0.2769775390625 +62895 -0.245758056640625 +62896 -0.253692626953125 +62897 -0.224151611328125 +62898 -0.24365234375 +62899 -0.213104248046875 +62900 -0.1983642578125 +62901 -0.172088623046875 +62902 -0.116241455078125 +62903 -0.09991455078125 +62904 -0.036834716796875 +62905 -0.029937744140625 +62906 0.034881591796875 +62907 0.033416748046875 +62908 0.09124755859375 +62909 0.083526611328125 +62910 0.10888671875 +62911 0.100677490234375 +62912 0.125518798828125 +62913 0.116424560546875 +62914 0.15771484375 +62915 0.14459228515625 +62916 0.17828369140625 +62917 0.16229248046875 +62918 0.17108154296875 +62919 0.15594482421875 +62920 0.129974365234375 +62921 0.120452880859375 +62922 0.082427978515625 +62923 0.0789794921875 +62924 0.027679443359375 +62925 0.030975341796875 +62926 -0.065643310546875 +62927 -0.049774169921875 +62928 -0.15936279296875 +62929 -0.131072998046875 +62930 -0.21307373046875 +62931 -0.1788330078125 +62932 -0.234649658203125 +62933 -0.19952392578125 +62934 -0.2001953125 +62935 -0.172943115234375 +62936 -0.119171142578125 +62937 -0.106903076171875 +62938 -0.024749755859375 +62939 -0.0291748046875 +62940 0.085784912109375 +62941 0.062591552734375 +62942 0.178131103515625 +62943 0.139617919921875 +62944 0.215576171875 +62945 0.171112060546875 +62946 0.211456298828125 +62947 0.168212890625 +62948 0.17523193359375 +62949 0.13885498046875 +62950 0.128753662109375 +62951 0.101318359375 +62952 0.1019287109375 +62953 0.080596923828125 +62954 0.0743408203125 +62955 0.059478759765625 +62956 0.04327392578125 +62957 0.035552978515625 +62958 0.038177490234375 +62959 0.033416748046875 +62960 0.076263427734375 +62961 0.067413330078125 +62962 0.14105224609375 +62963 0.12359619140625 +62964 0.186431884765625 +62965 0.16314697265625 +62966 0.188812255859375 +62967 0.166168212890625 +62968 0.1390380859375 +62969 0.124908447265625 +62970 0.041778564453125 +62971 0.043304443359375 +62972 -0.079437255859375 +62973 -0.058837890625 +62974 -0.219390869140625 +62975 -0.177154541015625 +62976 -0.367828369140625 +62977 -0.303253173828125 +62978 -0.494873046875 +62979 -0.412445068359375 +62980 -0.556243896484375 +62981 -0.466522216796875 +62982 -0.508697509765625 +62983 -0.427398681640625 +62984 -0.3756103515625 +62985 -0.315032958984375 +62986 -0.218902587890625 +62987 -0.1829833984375 +62988 -0.063751220703125 +62989 -0.05279541015625 +62990 0.091552734375 +62991 0.07745361328125 +62992 0.23602294921875 +62993 0.19854736328125 +62994 0.342987060546875 +62995 0.28753662109375 +62996 0.39520263671875 +62997 0.329620361328125 +62998 0.389373779296875 +62999 0.322113037109375 +63000 0.324249267578125 +63001 0.264007568359375 +63002 0.224090576171875 +63003 0.176483154296875 +63004 0.124267578125 +63005 0.090362548828125 +63006 0.037078857421875 +63007 0.0162353515625 +63008 -0.010101318359375 +63009 -0.022125244140625 +63010 -0.019439697265625 +63011 -0.026824951171875 +63012 -0.022796630859375 +63013 -0.02581787109375 +63014 -0.001556396484375 +63015 -0.003143310546875 +63016 0.056304931640625 +63017 0.05145263671875 +63018 0.106719970703125 +63019 0.09930419921875 +63020 0.096893310546875 +63021 0.09417724609375 +63022 0.042694091796875 +63023 0.04974365234375 +63024 -0.018035888671875 +63025 -0.00115966796875 +63026 -0.07586669921875 +63027 -0.05035400390625 +63028 -0.11944580078125 +63029 -0.0880126953125 +63030 -0.15972900390625 +63031 -0.12371826171875 +63032 -0.202606201171875 +63033 -0.16253662109375 +63034 -0.24859619140625 +63035 -0.20477294921875 +63036 -0.30517578125 +63037 -0.256805419921875 +63038 -0.36212158203125 +63039 -0.3095703125 +63040 -0.39141845703125 +63041 -0.338470458984375 +63042 -0.35528564453125 +63043 -0.31036376953125 +63044 -0.249969482421875 +63045 -0.2218017578125 +63046 -0.092864990234375 +63047 -0.08782958984375 +63048 0.08905029296875 +63049 0.0682373046875 +63050 0.2352294921875 +63051 0.1937255859375 +63052 0.318817138671875 +63053 0.26531982421875 +63054 0.358642578125 +63055 0.299468994140625 +63056 0.347747802734375 +63057 0.290130615234375 +63058 0.28564453125 +63059 0.23687744140625 +63060 0.223175048828125 +63061 0.183929443359375 +63062 0.196746826171875 +63063 0.162933349609375 +63064 0.179840087890625 +63065 0.150665283203125 +63066 0.155548095703125 +63067 0.132232666015625 +63068 0.151214599609375 +63069 0.131317138671875 +63070 0.156951904296875 +63071 0.13916015625 +63072 0.13177490234375 +63073 0.119842529296875 +63074 0.100799560546875 +63075 0.095123291015625 +63076 0.087127685546875 +63077 0.08502197265625 +63078 0.05487060546875 +63079 0.05816650390625 +63080 -0.009002685546875 +63081 0.00311279296875 +63082 -0.10400390625 +63083 -0.079681396484375 +63084 -0.229400634765625 +63085 -0.1895751953125 +63086 -0.35552978515625 +63087 -0.3006591796875 +63088 -0.441925048828125 +63089 -0.3775634765625 +63090 -0.473846435546875 +63091 -0.4073486328125 +63092 -0.464813232421875 +63093 -0.40167236328125 +63094 -0.419097900390625 +63095 -0.3641357421875 +63096 -0.334320068359375 +63097 -0.29254150390625 +63098 -0.227935791015625 +63099 -0.201934814453125 +63100 -0.12347412109375 +63101 -0.112762451171875 +63102 -0.02764892578125 +63103 -0.030792236328125 +63104 0.077667236328125 +63105 0.05987548828125 +63106 0.2132568359375 +63107 0.177398681640625 +63108 0.38885498046875 +63109 0.330291748046875 +63110 0.582794189453125 +63111 0.499664306640625 +63112 0.734039306640625 +63113 0.63226318359375 +63114 0.800140380859375 +63115 0.6910400390625 +63116 0.7783203125 +63117 0.6734619140625 +63118 0.6651611328125 +63119 0.57647705078125 +63120 0.45965576171875 +63121 0.399139404296875 +63122 0.199188232421875 +63123 0.173919677734375 +63124 -0.050689697265625 +63125 -0.042144775390625 +63126 -0.23297119140625 +63127 -0.19940185546875 +63128 -0.33013916015625 +63129 -0.28271484375 +63130 -0.368408203125 +63131 -0.31500244140625 +63132 -0.378936767578125 +63133 -0.323455810546875 +63134 -0.376983642578125 +63135 -0.3214111328125 +63136 -0.37969970703125 +63137 -0.3238525390625 +63138 -0.391510009765625 +63139 -0.3345947265625 +63140 -0.385345458984375 +63141 -0.33001708984375 +63142 -0.3419189453125 +63143 -0.29327392578125 +63144 -0.28289794921875 +63145 -0.2431640625 +63146 -0.251617431640625 +63147 -0.217376708984375 +63148 -0.266143798828125 +63149 -0.231597900390625 +63150 -0.273345947265625 +63151 -0.239410400390625 +63152 -0.216796875 +63153 -0.1915283203125 +63154 -0.128265380859375 +63155 -0.11553955078125 +63156 -0.068145751953125 +63157 -0.064117431640625 +63158 -0.0430908203125 +63159 -0.04296875 +63160 -0.024444580078125 +63161 -0.027069091796875 +63162 0.020721435546875 +63163 0.012298583984375 +63164 0.124481201171875 +63165 0.10308837890625 +63166 0.25787353515625 +63167 0.219970703125 +63168 0.379119873046875 +63169 0.32647705078125 +63170 0.47991943359375 +63171 0.415374755859375 +63172 0.5281982421875 +63173 0.4586181640625 +63174 0.511138916015625 +63175 0.4449462890625 +63176 0.456207275390625 +63177 0.39825439453125 +63178 0.407470703125 +63179 0.356903076171875 +63180 0.383758544921875 +63181 0.3372802734375 +63182 0.35687255859375 +63183 0.314727783203125 +63184 0.31182861328125 +63185 0.276123046875 +63186 0.250885009765625 +63187 0.223388671875 +63188 0.1654052734375 +63189 0.14898681640625 +63190 0.035247802734375 +63191 0.035369873046875 +63192 -0.142059326171875 +63193 -0.119598388671875 +63194 -0.33563232421875 +63195 -0.28900146484375 +63196 -0.5345458984375 +63197 -0.463226318359375 +63198 -0.72186279296875 +63199 -0.627471923828125 +63200 -0.836669921875 +63201 -0.728546142578125 +63202 -0.8326416015625 +63203 -0.72601318359375 +63204 -0.7296142578125 +63205 -0.63714599609375 +63206 -0.582550048828125 +63207 -0.509796142578125 +63208 -0.440093994140625 +63209 -0.386322021484375 +63210 -0.324310302734375 +63211 -0.28594970703125 +63212 -0.20147705078125 +63213 -0.17926025390625 +63214 -0.044647216796875 +63215 -0.042694091796875 +63216 0.103973388671875 +63217 0.086944580078125 +63218 0.202392578125 +63219 0.173004150390625 +63220 0.264495849609375 +63221 0.22760009765625 +63222 0.338897705078125 +63223 0.2930908203125 +63224 0.443817138671875 +63225 0.385284423828125 +63226 0.545074462890625 +63227 0.474365234375 +63228 0.6173095703125 +63229 0.53814697265625 +63230 0.6524658203125 +63231 0.569580078125 +63232 0.66339111328125 +63233 0.5802001953125 +63234 0.6561279296875 +63235 0.57537841796875 +63236 0.606781005859375 +63237 0.5335693359375 +63238 0.501190185546875 +63239 0.441802978515625 +63240 0.352783203125 +63241 0.311981201171875 +63242 0.176544189453125 +63243 0.15740966796875 +63244 -0.034820556640625 +63245 -0.02880859375 +63246 -0.258209228515625 +63247 -0.22607421875 +63248 -0.44244384765625 +63249 -0.388397216796875 +63250 -0.5753173828125 +63251 -0.504974365234375 +63252 -0.65203857421875 +63253 -0.571685791015625 +63254 -0.641632080078125 +63255 -0.560638427734375 +63256 -0.562164306640625 +63257 -0.488250732421875 +63258 -0.458038330078125 +63259 -0.394683837890625 +63260 -0.350555419921875 +63261 -0.299102783203125 +63262 -0.260528564453125 +63263 -0.22021484375 +63264 -0.192108154296875 +63265 -0.16162109375 +63266 -0.141937255859375 +63267 -0.1201171875 +63268 -0.1021728515625 +63269 -0.08837890625 +63270 -0.062896728515625 +63271 -0.057159423828125 +63272 -0.011932373046875 +63273 -0.01519775390625 +63274 0.062835693359375 +63275 0.048614501953125 +63276 0.148712158203125 +63277 0.123046875 +63278 0.241729736328125 +63279 0.204620361328125 +63280 0.34912109375 +63281 0.300018310546875 +63282 0.457305908203125 +63283 0.397064208984375 +63284 0.54388427734375 +63285 0.475494384765625 +63286 0.5728759765625 +63287 0.50274658203125 +63288 0.506591796875 +63289 0.444671630859375 +63290 0.351226806640625 +63291 0.306732177734375 +63292 0.146514892578125 +63293 0.124664306640625 +63294 -0.05523681640625 +63295 -0.05438232421875 +63296 -0.21624755859375 +63297 -0.19647216796875 +63298 -0.334930419921875 +63299 -0.300323486328125 +63300 -0.402984619140625 +63301 -0.358642578125 +63302 -0.4412841796875 +63303 -0.39044189453125 +63304 -0.49578857421875 +63305 -0.437408447265625 +63306 -0.5601806640625 +63307 -0.49395751953125 +63308 -0.600738525390625 +63309 -0.5296630859375 +63310 -0.584228515625 +63311 -0.5145263671875 +63312 -0.47930908203125 +63313 -0.42022705078125 +63314 -0.27935791015625 +63315 -0.24072265625 +63316 -0.0089111328125 +63317 0.001861572265625 +63318 0.268798828125 +63319 0.250518798828125 +63320 0.482818603515625 +63321 0.441253662109375 +63322 0.60369873046875 +63323 0.547637939453125 +63324 0.650421142578125 +63325 0.586944580078125 +63326 0.66400146484375 +63327 0.596435546875 +63328 0.6414794921875 +63329 0.57354736328125 +63330 0.572540283203125 +63331 0.50909423828125 +63332 0.498138427734375 +63333 0.440216064453125 +63334 0.439453125 +63335 0.386138916015625 +63336 0.375518798828125 +63337 0.327972412109375 +63338 0.274505615234375 +63339 0.2369384765625 +63340 0.1087646484375 +63341 0.087982177734375 +63342 -0.099395751953125 +63343 -0.09881591796875 +63344 -0.3182373046875 +63345 -0.2947998046875 +63346 -0.5489501953125 +63347 -0.501190185546875 +63348 -0.7738037109375 +63349 -0.702056884765625 +63350 -0.86383056640625 +63351 -0.84967041015625 +63352 -0.870391845703125 +63353 -0.86102294921875 +63354 -0.86895751953125 +63355 -0.860748291015625 +63356 -0.861053466796875 +63357 -0.85394287109375 +63358 -0.765869140625 +63359 -0.725738525390625 +63360 -0.5301513671875 +63361 -0.516815185546875 +63362 -0.214691162109375 +63363 -0.233642578125 +63364 0.137359619140625 +63365 0.084808349609375 +63366 0.474822998046875 +63367 0.392181396484375 +63368 0.76239013671875 +63369 0.6563720703125 +63370 0.867462158203125 +63371 0.853057861328125 +63372 0.870361328125 +63373 0.86846923828125 +63374 0.86480712890625 +63375 0.870361328125 +63376 0.831817626953125 +63377 0.864654541015625 +63378 0.677581787109375 +63379 0.849761962890625 +63380 0.495880126953125 +63381 0.71282958984375 +63382 0.30767822265625 +63383 0.554840087890625 +63384 0.116180419921875 +63385 0.37847900390625 +63386 -0.110748291015625 +63387 0.1552734375 +63388 -0.381805419921875 +63389 -0.1212158203125 +63390 -0.6572265625 +63391 -0.4129638671875 +63392 -0.857421875 +63393 -0.666839599609375 +63394 -0.870391845703125 +63395 -0.8453369140625 +63396 -0.870391845703125 +63397 -0.864227294921875 +63398 -0.86444091796875 +63399 -0.8690185546875 +63400 -0.85723876953125 +63401 -0.870391845703125 +63402 -0.790008544921875 +63403 -0.868011474609375 +63404 -0.62847900390625 +63405 -0.856781005859375 +63406 -0.3956298828125 +63407 -0.689697265625 +63408 -0.126708984375 +63409 -0.4527587890625 +63410 0.150115966796875 +63411 -0.190032958984375 +63412 0.424041748046875 +63413 0.08746337890625 +63414 0.670623779296875 +63415 0.355499267578125 +63416 0.854522705078125 +63417 0.579681396484375 +63418 0.866485595703125 +63419 0.745025634765625 +63420 0.86920166015625 +63421 0.8389892578125 +63422 0.8653564453125 +63423 0.857208251953125 +63424 0.857147216796875 +63425 0.85736083984375 +63426 0.766845703125 +63427 0.842193603515625 +63428 0.628509521484375 +63429 0.7698974609375 +63430 0.462127685546875 +63431 0.659698486328125 +63432 0.297210693359375 +63433 0.5364990234375 +63434 0.14862060546875 +63435 0.412689208984375 +63436 -0.00537109375 +63437 0.268524169921875 +63438 -0.15753173828125 +63439 0.111236572265625 +63440 -0.31304931640625 +63441 -0.062347412109375 +63442 -0.48876953125 +63443 -0.265289306640625 +63444 -0.6416015625 +63445 -0.455902099609375 +63446 -0.751373291015625 +63447 -0.61285400390625 +63448 -0.84619140625 +63449 -0.758270263671875 +63450 -0.861297607421875 +63451 -0.857330322265625 +63452 -0.863250732421875 +63453 -0.864990234375 +63454 -0.856597900390625 +63455 -0.864044189453125 +63456 -0.7498779296875 +63457 -0.8558349609375 +63458 -0.624542236328125 +63459 -0.779022216796875 +63460 -0.47808837890625 +63461 -0.659759521484375 +63462 -0.253387451171875 +63463 -0.45697021484375 +63464 0.003692626953125 +63465 -0.212432861328125 +63466 0.2257080078125 +63467 0.0118408203125 +63468 0.427154541015625 +63469 0.227294921875 +63470 0.643218994140625 +63471 0.463653564453125 +63472 0.855926513671875 +63473 0.712921142578125 +63474 0.870361328125 +63475 0.862030029296875 +63476 0.870361328125 +63477 0.870361328125 +63478 0.862762451171875 +63479 0.870361328125 +63480 0.79669189453125 +63481 0.86285400390625 +63482 0.595794677734375 +63483 0.78900146484375 +63484 0.362152099609375 +63485 0.602325439453125 +63486 0.1270751953125 +63487 0.398681640625 +63488 -0.086944580078125 +63489 0.19891357421875 +63490 -0.2784423828125 +63491 0.00543212890625 +63492 -0.484832763671875 +63493 -0.215362548828125 +63494 -0.729583740234375 +63495 -0.48388671875 +63496 -0.86688232421875 +63497 -0.755859375 +63498 -0.870391845703125 +63499 -0.867706298828125 +63500 -0.86859130859375 +63501 -0.870391845703125 +63502 -0.86279296875 +63503 -0.868743896484375 +63504 -0.817962646484375 +63505 -0.86029052734375 +63506 -0.6116943359375 +63507 -0.73370361328125 +63508 -0.3128662109375 +63509 -0.464111328125 +63510 0.039398193359375 +63511 -0.134979248046875 +63512 0.422821044921875 +63513 0.23260498046875 +63514 0.805145263671875 +63515 0.607666015625 +63516 0.870361328125 +63517 0.86260986328125 +63518 0.870361328125 +63519 0.870361328125 +63520 0.860015869140625 +63521 0.8677978515625 +63522 0.727935791015625 +63523 0.8558349609375 +63524 0.48114013671875 +63525 0.680572509765625 +63526 0.2059326171875 +63527 0.4537353515625 +63528 -0.06103515625 +63529 0.219512939453125 +63530 -0.29913330078125 +63531 -0.00323486328125 +63532 -0.516204833984375 +63533 -0.221405029296875 +63534 -0.7252197265625 +63535 -0.44586181640625 +63536 -0.85980224609375 +63537 -0.652923583984375 +63538 -0.870391845703125 +63539 -0.8131103515625 +63540 -0.870391845703125 +63541 -0.859954833984375 +63542 -0.858062744140625 +63543 -0.8582763671875 +63544 -0.673004150390625 +63545 -0.7730712890625 +63546 -0.42694091796875 +63547 -0.617034912109375 +63548 -0.2100830078125 +63549 -0.474365234375 +63550 -0.0362548828125 +63551 -0.3551025390625 +63552 0.10943603515625 +63553 -0.243408203125 +63554 0.23516845703125 +63555 -0.13079833984375 +63556 0.373687744140625 +63557 0.0130615234375 +63558 0.517791748046875 +63559 0.180084228515625 +63560 0.602783203125 +63561 0.307464599609375 +63562 0.635711669921875 +63563 0.39874267578125 +63564 0.655181884765625 +63565 0.486358642578125 +63566 0.65948486328125 +63567 0.564697265625 +63568 0.651275634765625 +63569 0.632049560546875 +63570 0.61846923828125 +63571 0.6729736328125 +63572 0.53753662109375 +63573 0.661651611328125 +63574 0.404144287109375 +63575 0.590728759765625 +63576 0.22186279296875 +63577 0.460906982421875 +63578 0.003997802734375 +63579 0.282806396484375 +63580 -0.22100830078125 +63581 0.08203125 +63582 -0.42449951171875 +63583 -0.114654541015625 +63584 -0.579833984375 +63585 -0.281494140625 +63586 -0.641876220703125 +63587 -0.374603271484375 +63588 -0.6177978515625 +63589 -0.3984375 +63590 -0.575531005859375 +63591 -0.413726806640625 +63592 -0.526336669921875 +63593 -0.427764892578125 +63594 -0.42645263671875 +63595 -0.39617919921875 +63596 -0.2581787109375 +63597 -0.2989501953125 +63598 -0.068695068359375 +63599 -0.176971435546875 +63600 0.09222412109375 +63601 -0.073944091796875 +63602 0.232147216796875 +63603 0.01953125 +63604 0.3509521484375 +63605 0.1051025390625 +63606 0.410064697265625 +63607 0.147705078125 +63608 0.372955322265625 +63609 0.11346435546875 +63610 0.2554931640625 +63611 0.016845703125 +63612 0.10711669921875 +63613 -0.096923828125 +63614 -0.052886962890625 +63615 -0.2115478515625 +63616 -0.186279296875 +63617 -0.293426513671875 +63618 -0.23291015625 +63619 -0.288848876953125 +63620 -0.209442138671875 +63621 -0.2161865234375 +63622 -0.174163818359375 +63623 -0.1328125 +63624 -0.126739501953125 +63625 -0.0411376953125 +63626 -0.048126220703125 +63627 0.0740966796875 +63628 0.0426025390625 +63629 0.192962646484375 +63630 0.10748291015625 +63631 0.2783203125 +63632 0.1409912109375 +63633 0.32391357421875 +63634 0.19708251953125 +63635 0.3797607421875 +63636 0.273651123046875 +63637 0.444061279296875 +63638 0.31768798828125 +63639 0.4678955078125 +63640 0.341094970703125 +63641 0.463623046875 +63642 0.368011474609375 +63643 0.455535888671875 +63644 0.37249755859375 +63645 0.421356201171875 +63646 0.30072021484375 +63647 0.31292724609375 +63648 0.1517333984375 +63649 0.13165283203125 +63650 -0.01470947265625 +63651 -0.064208984375 +63652 -0.1883544921875 +63653 -0.262908935546875 +63654 -0.372711181640625 +63655 -0.46588134765625 +63656 -0.51397705078125 +63657 -0.62127685546875 +63658 -0.57177734375 +63659 -0.690216064453125 +63660 -0.53948974609375 +63661 -0.66595458984375 +63662 -0.43511962890625 +63663 -0.565277099609375 +63664 -0.2962646484375 +63665 -0.423828125 +63666 -0.161102294921875 +63667 -0.278167724609375 +63668 -0.0435791015625 +63669 -0.142608642578125 +63670 0.060394287109375 +63671 -0.014892578125 +63672 0.13665771484375 +63673 0.08990478515625 +63674 0.170135498046875 +63675 0.155792236328125 +63676 0.16552734375 +63677 0.18524169921875 +63678 0.15728759765625 +63679 0.208648681640625 +63680 0.150787353515625 +63681 0.229461669921875 +63682 0.12200927734375 +63683 0.223846435546875 +63684 0.080108642578125 +63685 0.199371337890625 +63686 0.05126953125 +63687 0.179901123046875 +63688 0.062896728515625 +63689 0.19091796875 +63690 0.09271240234375 +63691 0.21173095703125 +63692 0.092987060546875 +63693 0.19830322265625 +63694 0.07855224609375 +63695 0.165435791015625 +63696 0.06427001953125 +63697 0.128265380859375 +63698 0.0347900390625 +63699 0.07379150390625 +63700 -0.01171875 +63701 0.001861572265625 +63702 -0.056060791015625 +63703 -0.06793212890625 +63704 -0.055511474609375 +63705 -0.09405517578125 +63706 -0.010467529296875 +63707 -0.075439453125 +63708 0.02508544921875 +63709 -0.0614013671875 +63710 0.025665283203125 +63711 -0.074859619140625 +63712 0.017333984375 +63713 -0.0908203125 +63714 0.00189208984375 +63715 -0.107330322265625 +63716 -0.03173828125 +63717 -0.134857177734375 +63718 -0.071502685546875 +63719 -0.16253662109375 +63720 -0.13543701171875 +63721 -0.2078857421875 +63722 -0.219970703125 +63723 -0.268524169921875 +63724 -0.300506591796875 +63725 -0.322540283203125 +63726 -0.376312255859375 +63727 -0.370513916015625 +63728 -0.416107177734375 +63729 -0.384429931640625 +63730 -0.371124267578125 +63731 -0.319915771484375 +63732 -0.242279052734375 +63733 -0.17901611328125 +63734 -0.069732666015625 +63735 -0.000396728515625 +63736 0.125640869140625 +63737 0.195526123046875 +63738 0.31268310546875 +63739 0.3790283203125 +63740 0.45501708984375 +63741 0.5157470703125 +63742 0.554779052734375 +63743 0.60760498046875 +63744 0.61065673828125 +63745 0.653839111328125 +63746 0.610931396484375 +63747 0.643829345703125 +63748 0.531463623046875 +63749 0.5550537109375 +63750 0.3883056640625 +63751 0.403472900390625 +63752 0.23468017578125 +63753 0.24053955078125 +63754 0.095245361328125 +63755 0.09063720703125 +63756 -0.00396728515625 +63757 -0.02056884765625 +63758 -0.04852294921875 +63759 -0.0784912109375 +63760 -0.055145263671875 +63761 -0.098175048828125 +63762 -0.0758056640625 +63763 -0.128387451171875 +63764 -0.138702392578125 +63765 -0.19537353515625 +63766 -0.209197998046875 +63767 -0.26593017578125 +63768 -0.289031982421875 +63769 -0.34161376953125 +63770 -0.37884521484375 +63771 -0.42315673828125 +63772 -0.456329345703125 +63773 -0.489654541015625 +63774 -0.51641845703125 +63775 -0.536773681640625 +63776 -0.519287109375 +63777 -0.527313232421875 +63778 -0.458251953125 +63779 -0.45562744140625 +63780 -0.384796142578125 +63781 -0.371429443359375 +63782 -0.323699951171875 +63783 -0.299072265625 +63784 -0.269287109375 +63785 -0.233917236328125 +63786 -0.1951904296875 +63787 -0.151641845703125 +63788 -0.100006103515625 +63789 -0.051513671875 +63790 -0.01055908203125 +63791 0.040496826171875 +63792 0.1033935546875 +63793 0.152801513671875 +63794 0.24908447265625 +63795 0.292144775390625 +63796 0.373199462890625 +63797 0.407958984375 +63798 0.45806884765625 +63799 0.483642578125 +63800 0.511474609375 +63801 0.52691650390625 +63802 0.565399169921875 +63803 0.56866455078125 +63804 0.61138916015625 +63805 0.601409912109375 +63806 0.5897216796875 +63807 0.569091796875 +63808 0.4906005859375 +63809 0.4630126953125 +63810 0.33148193359375 +63811 0.300445556640625 +63812 0.147796630859375 +63813 0.11566162109375 +63814 -0.01873779296875 +63815 -0.05120849609375 +63816 -0.140289306640625 +63817 -0.173248291015625 +63818 -0.191986083984375 +63819 -0.2265625 +63820 -0.184295654296875 +63821 -0.220916748046875 +63822 -0.161834716796875 +63823 -0.198699951171875 +63824 -0.166595458984375 +63825 -0.19989013671875 +63826 -0.19390869140625 +63827 -0.220306396484375 +63828 -0.22442626953125 +63829 -0.241943359375 +63830 -0.279754638671875 +63831 -0.2857666015625 +63832 -0.3389892578125 +63833 -0.332489013671875 +63834 -0.3543701171875 +63835 -0.337249755859375 +63836 -0.348175048828125 +63837 -0.32177734375 +63838 -0.32598876953125 +63839 -0.2918701171875 +63840 -0.2581787109375 +63841 -0.2198486328125 +63842 -0.139801025390625 +63843 -0.101409912109375 +63844 0.014617919921875 +63845 0.049407958984375 +63846 0.144378662109375 +63847 0.174713134765625 +63848 0.221038818359375 +63849 0.247467041015625 +63850 0.27069091796875 +63851 0.292510986328125 +63852 0.294036865234375 +63853 0.31072998046875 +63854 0.311767578125 +63855 0.322021484375 +63856 0.339141845703125 +63857 0.34130859375 +63858 0.360260009765625 +63859 0.35406494140625 +63860 0.360504150390625 +63861 0.3468017578125 +63862 0.308380126953125 +63863 0.289337158203125 +63864 0.18170166015625 +63865 0.160491943359375 +63866 0.0047607421875 +63867 -0.015869140625 +63868 -0.17559814453125 +63869 -0.194244384765625 +63870 -0.3143310546875 +63871 -0.33087158203125 +63872 -0.36785888671875 +63873 -0.383544921875 +63874 -0.36248779296875 +63875 -0.377685546875 +63876 -0.343536376953125 +63877 -0.35723876953125 +63878 -0.3018798828125 +63879 -0.313568115234375 +63880 -0.231414794921875 +63881 -0.240966796875 +63882 -0.117645263671875 +63883 -0.12567138671875 +63884 0.007049560546875 +63885 0.00067138671875 +63886 0.087982177734375 +63887 0.084808349609375 +63888 0.13946533203125 +63889 0.14031982421875 +63890 0.17425537109375 +63891 0.179229736328125 +63892 0.188201904296875 +63893 0.197235107421875 +63894 0.171234130859375 +63895 0.184326171875 +63896 0.118438720703125 +63897 0.135650634765625 +63898 0.05706787109375 +63899 0.07745361328125 +63900 -0.010711669921875 +63901 0.011749267578125 +63902 -0.0914306640625 +63903 -0.067718505859375 +63904 -0.162322998046875 +63905 -0.13873291015625 +63906 -0.194549560546875 +63907 -0.173248291015625 +63908 -0.1492919921875 +63909 -0.133514404296875 +63910 -0.02166748046875 +63911 -0.0145263671875 +63912 0.124053955078125 +63913 0.12176513671875 +63914 0.211151123046875 +63915 0.201385498046875 +63916 0.240447998046875 +63917 0.225372314453125 +63918 0.242218017578125 +63919 0.22320556640625 +63920 0.2257080078125 +63921 0.2041015625 +63922 0.194366455078125 +63923 0.1715087890625 +63924 0.115509033203125 +63925 0.0938720703125 +63926 0.0128173828125 +63927 -0.00579833984375 +63928 -0.053802490234375 +63929 -0.069580078125 +63930 -0.110626220703125 +63931 -0.1229248046875 +63932 -0.199493408203125 +63933 -0.20648193359375 +63934 -0.29437255859375 +63935 -0.29522705078125 +63936 -0.33221435546875 +63937 -0.328277587890625 +63938 -0.27972412109375 +63939 -0.27362060546875 +63940 -0.185333251953125 +63941 -0.1783447265625 +63942 -0.128204345703125 +63943 -0.119293212890625 +63944 -0.115692138671875 +63945 -0.103759765625 +63946 -0.116455078125 +63947 -0.10162353515625 +63948 -0.105926513671875 +63949 -0.0892333984375 +63950 -0.053955078125 +63951 -0.03753662109375 +63952 0.048797607421875 +63953 0.06243896484375 +63954 0.157318115234375 +63955 0.16717529296875 +63956 0.212005615234375 +63957 0.218994140625 +63958 0.218475341796875 +63959 0.223388671875 +63960 0.23724365234375 +63961 0.239105224609375 +63962 0.30535888671875 +63963 0.302154541015625 +63964 0.38128662109375 +63965 0.372467041015625 +63966 0.404449462890625 +63967 0.3916015625 +63968 0.3944091796875 +63969 0.378662109375 +63970 0.3885498046875 +63971 0.370025634765625 +63972 0.362640380859375 +63973 0.3424072265625 +63974 0.27362060546875 +63975 0.2542724609375 +63976 0.11712646484375 +63977 0.101470947265625 +63978 -0.054901123046875 +63979 -0.065673828125 +63980 -0.19085693359375 +63981 -0.197174072265625 +63982 -0.28570556640625 +63983 -0.2882080078125 +63984 -0.339263916015625 +63985 -0.33868408203125 +63986 -0.3775634765625 +63987 -0.37384033203125 +63988 -0.445709228515625 +63989 -0.437469482421875 +63990 -0.535064697265625 +63991 -0.521392822265625 +63992 -0.629058837890625 +63993 -0.609710693359375 +63994 -0.697601318359375 +63995 -0.673431396484375 +63996 -0.70391845703125 +63997 -0.6771240234375 +63998 -0.6424560546875 +63999 -0.615509033203125 +64000 -0.491241455078125 +64001 -0.466949462890625 +64002 -0.265716552734375 +64003 -0.246307373046875 +64004 -0.023712158203125 +64005 -0.010406494140625 +64006 0.201751708984375 +64007 0.208251953125 +64008 0.375823974609375 +64009 0.37530517578125 +64010 0.485076904296875 +64011 0.477813720703125 +64012 0.56884765625 +64013 0.555511474609375 +64014 0.634765625 +64015 0.61639404296875 +64016 0.63763427734375 +64017 0.615509033203125 +64018 0.5660400390625 +64019 0.54156494140625 +64020 0.4720458984375 +64021 0.44671630859375 +64022 0.40692138671875 +64023 0.382232666015625 +64024 0.3778076171875 +64025 0.35516357421875 +64026 0.376953125 +64027 0.357574462890625 +64028 0.371978759765625 +64029 0.35687255859375 +64030 0.313140869140625 +64031 0.30303955078125 +64032 0.184417724609375 +64033 0.17974853515625 +64034 0.011199951171875 +64035 0.012054443359375 +64036 -0.171051025390625 +64037 -0.164886474609375 +64038 -0.33740234375 +64039 -0.326416015625 +64040 -0.47198486328125 +64041 -0.456939697265625 +64042 -0.560394287109375 +64043 -0.542236328125 +64044 -0.58056640625 +64045 -0.560394287109375 +64046 -0.54754638671875 +64047 -0.526519775390625 +64048 -0.508575439453125 +64049 -0.48785400390625 +64050 -0.459503173828125 +64051 -0.440216064453125 +64052 -0.394378662109375 +64053 -0.377532958984375 +64054 -0.35260009765625 +64055 -0.33905029296875 +64056 -0.31170654296875 +64057 -0.302093505859375 +64058 -0.197418212890625 +64059 -0.192169189453125 +64060 -0.007965087890625 +64061 -0.007232666015625 +64062 0.207489013671875 +64063 0.203765869140625 +64064 0.409210205078125 +64065 0.4013671875 +64066 0.57208251953125 +64067 0.560638427734375 +64068 0.66595458984375 +64069 0.651641845703125 +64070 0.65875244140625 +64071 0.642425537109375 +64072 0.56744384765625 +64073 0.550048828125 +64074 0.431396484375 +64075 0.413909912109375 +64076 0.29443359375 +64077 0.27783203125 +64078 0.182464599609375 +64079 0.167633056640625 +64080 0.06365966796875 +64081 0.051361083984375 +64082 -0.075958251953125 +64083 -0.08514404296875 +64084 -0.189422607421875 +64085 -0.195068359375 +64086 -0.271942138671875 +64087 -0.273834228515625 +64088 -0.342529296875 +64089 -0.340667724609375 +64090 -0.364166259765625 +64091 -0.3587646484375 +64092 -0.327239990234375 +64093 -0.3187255859375 +64094 -0.2769775390625 +64095 -0.265899658203125 +64096 -0.253692626953125 +64097 -0.240753173828125 +64098 -0.24365234375 +64099 -0.2296142578125 +64100 -0.1983642578125 +64101 -0.184051513671875 +64102 -0.116241455078125 +64103 -0.102447509765625 +64104 -0.036834716796875 +64105 -0.0242919921875 +64106 0.034881591796875 +64107 0.0455322265625 +64108 0.09124755859375 +64109 0.099456787109375 +64110 0.10888671875 +64111 0.114288330078125 +64112 0.125518798828125 +64113 0.127899169921875 +64114 0.15771484375 +64115 0.15704345703125 +64116 0.17828369140625 +64117 0.1746826171875 +64118 0.17108154296875 +64119 0.164825439453125 +64120 0.129974365234375 +64121 0.121490478515625 +64122 0.082427978515625 +64123 0.07220458984375 +64124 0.027679443359375 +64125 0.016326904296875 +64126 -0.065643310546875 +64127 -0.07745361328125 +64128 -0.15936279296875 +64129 -0.17095947265625 +64130 -0.21307373046875 +64131 -0.22381591796875 +64132 -0.234649658203125 +64133 -0.24395751953125 +64134 -0.2001953125 +64135 -0.20758056640625 +64136 -0.119171142578125 +64137 -0.124298095703125 +64138 -0.024749755859375 +64139 -0.02740478515625 +64140 0.085784912109375 +64141 0.085662841796875 +64142 0.178131103515625 +64143 0.18048095703125 +64144 0.215576171875 +64145 0.220184326171875 +64146 0.211456298828125 +64147 0.217987060546875 +64148 0.17523193359375 +64149 0.183258056640625 +64150 0.128753662109375 +64151 0.137786865234375 +64152 0.1019287109375 +64153 0.1114501953125 +64154 0.0743408203125 +64155 0.083831787109375 +64156 0.04327392578125 +64157 0.05224609375 +64158 0.038177490234375 +64159 0.046173095703125 +64160 0.076263427734375 +64161 0.0828857421875 +64162 0.14105224609375 +64163 0.145965576171875 +64164 0.186431884765625 +64165 0.189422607421875 +64166 0.188812255859375 +64167 0.18975830078125 +64168 0.1390380859375 +64169 0.137939453125 +64170 0.041778564453125 +64171 0.03875732421875 +64172 -0.079437255859375 +64173 -0.08416748046875 +64174 -0.219390869140625 +64175 -0.22552490234375 +64176 -0.367828369140625 +64177 -0.375 +64178 -0.494873046875 +64179 -0.502685546875 +64180 -0.556243896484375 +64181 -0.56427001953125 +64182 -0.508697509765625 +64183 -0.516510009765625 +64184 -0.3756103515625 +64185 -0.382781982421875 +64186 -0.218902587890625 +64187 -0.225067138671875 +64188 -0.063751220703125 +64189 -0.068603515625 +64190 0.091552734375 +64191 0.088226318359375 +64192 0.23602294921875 +64193 0.234375 +64194 0.342987060546875 +64195 0.343048095703125 +64196 0.39520263671875 +64197 0.39691162109375 +64198 0.389373779296875 +64199 0.392578125 +64200 0.324249267578125 +64201 0.3287353515625 +64202 0.224090576171875 +64203 0.229583740234375 +64204 0.124267578125 +64205 0.13043212890625 +64206 0.037078857421875 +64207 0.043548583984375 +64208 -0.010101318359375 +64209 -0.003692626953125 +64210 -0.019439697265625 +64211 -0.013458251953125 +64212 -0.022796630859375 +64213 -0.017547607421875 +64214 -0.001556396484375 +64215 0.002655029296875 +64216 0.056304931640625 +64217 0.05926513671875 +64218 0.106719970703125 +64219 0.1082763671875 +64220 0.096893310546875 +64221 0.09698486328125 +64222 0.042694091796875 +64223 0.041351318359375 +64224 -0.018035888671875 +64225 -0.02069091796875 +64226 -0.07586669921875 +64227 -0.07965087890625 +64228 -0.11944580078125 +64229 -0.124114990234375 +64230 -0.15972900390625 +64231 -0.165008544921875 +64232 -0.202606201171875 +64233 -0.20819091796875 +64234 -0.24859619140625 +64235 -0.254180908203125 +64236 -0.30517578125 +64237 -0.310455322265625 +64238 -0.36212158203125 +64239 -0.3668212890625 +64240 -0.39141845703125 +64241 -0.395294189453125 +64242 -0.35528564453125 +64243 -0.358154296875 +64244 -0.249969482421875 +64245 -0.251708984375 +64246 -0.092864990234375 +64247 -0.093414306640625 +64248 0.08905029296875 +64249 0.089691162109375 +64250 0.2352294921875 +64251 0.23699951171875 +64252 0.318817138671875 +64253 0.32159423828125 +64254 0.358642578125 +64255 0.36224365234375 +64256 0.348358154296875 +64257 0.351959228515625 +64258 0.288116455078125 +64259 0.29022216796875 +64260 0.227569580078125 +64261 0.22784423828125 +64262 0.201690673828125 +64263 0.20123291015625 +64264 0.184661865234375 +64265 0.183929443359375 +64266 0.1600341796875 +64267 0.159027099609375 +64268 0.15423583984375 +64269 0.1539306640625 +64270 0.157745361328125 +64271 0.158782958984375 +64272 0.1309814453125 +64273 0.13262939453125 +64274 0.098358154296875 +64275 0.10064697265625 +64276 0.082366943359375 +64277 0.08599853515625 +64278 0.0484619140625 +64279 0.0528564453125 +64280 -0.015777587890625 +64281 -0.011749267578125 +64282 -0.1097412109375 +64283 -0.1072998046875 +64284 -0.232635498046875 +64285 -0.233062744140625 +64286 -0.355682373046875 +64287 -0.359344482421875 +64288 -0.439605712890625 +64289 -0.4456787109375 +64290 -0.470184326171875 +64291 -0.47735595703125 +64292 -0.46051025390625 +64293 -0.4678955078125 +64294 -0.414764404296875 +64295 -0.421600341796875 +64296 -0.33074951171875 +64297 -0.33612060546875 +64298 -0.2254638671875 +64299 -0.22894287109375 +64300 -0.121856689453125 +64301 -0.1236572265625 +64302 -0.02655029296875 +64303 -0.027008056640625 +64304 0.077880859375 +64305 0.0791015625 +64306 0.21142578125 +64307 0.21539306640625 +64308 0.383331298828125 +64309 0.391571044921875 +64310 0.57257080078125 +64311 0.5859375 +64312 0.719970703125 +64313 0.7374267578125 +64314 0.784423828125 +64315 0.8035888671875 +64316 0.763214111328125 +64317 0.781646728515625 +64318 0.653045654296875 +64319 0.668182373046875 +64320 0.453033447265625 +64321 0.46221923828125 +64322 0.19940185546875 +64323 0.201171875 +64324 -0.0443115234375 +64325 -0.04937744140625 +64326 -0.222808837890625 +64327 -0.232391357421875 +64328 -0.319000244140625 +64329 -0.330322265625 +64330 -0.358123779296875 +64331 -0.36932373046875 +64332 -0.3702392578125 +64333 -0.380523681640625 +64334 -0.370025634765625 +64335 -0.379150390625 +64336 -0.3740234375 +64337 -0.382293701171875 +64338 -0.38641357421875 +64339 -0.394378662109375 +64340 -0.3809814453125 +64341 -0.388336181640625 +64342 -0.33905029296875 +64343 -0.344879150390625 +64344 -0.281585693359375 +64345 -0.28564453125 +64346 -0.25054931640625 +64347 -0.2540283203125 +64348 -0.263458251953125 +64349 -0.268096923828125 +64350 -0.26898193359375 +64351 -0.274749755859375 +64352 -0.212615966796875 +64353 -0.21759033203125 +64354 -0.125152587890625 +64355 -0.12841796875 +64356 -0.065216064453125 +64357 -0.06768798828125 +64358 -0.039306640625 +64359 -0.04205322265625 +64360 -0.019775390625 +64361 -0.02288818359375 +64362 0.02520751953125 +64363 0.022705078125 +64364 0.1265869140625 +64365 0.12677001953125 +64366 0.25628662109375 +64367 0.260345458984375 +64368 0.37384033203125 +64369 0.381622314453125 +64370 0.471221923828125 +64371 0.482330322265625 +64372 0.51739501953125 +64373 0.5303955078125 +64374 0.500030517578125 +64375 0.513031005859375 +64376 0.44573974609375 +64377 0.45770263671875 +64378 0.39727783203125 +64379 0.40850830078125 +64380 0.3729248046875 +64381 0.384307861328125 +64382 0.345458984375 +64383 0.356903076171875 +64384 0.300445556640625 +64385 0.311370849609375 +64386 0.240142822265625 +64387 0.249969482421875 +64388 0.15625 +64389 0.164093017578125 +64390 0.02935791015625 +64391 0.03363037109375 +64392 -0.14288330078125 +64393 -0.143890380859375 +64394 -0.33056640625 +64395 -0.33758544921875 +64396 -0.5230712890625 +64397 -0.5364990234375 +64398 -0.704010009765625 +64399 -0.723724365234375 +64400 -0.81451416015625 +64401 -0.83831787109375 +64402 -0.80975341796875 +64403 -0.834014892578125 +64404 -0.708984375 +64405 -0.73065185546875 +64406 -0.565460205078125 +64407 -0.58319091796875 +64408 -0.42633056640625 +64409 -0.4403076171875 +64410 -0.31304931640625 +64411 -0.3240966796875 +64412 -0.19305419921875 +64413 -0.20086669921875 +64414 -0.040252685546875 +64415 -0.043670654296875 +64416 0.10443115234375 +64417 0.105255126953125 +64418 0.200286865234375 +64419 0.20391845703125 +64420 0.2607421875 +64421 0.26617431640625 +64422 0.332855224609375 +64423 0.34063720703125 +64424 0.434234619140625 +64425 0.44549560546875 +64426 0.531829833984375 +64427 0.546600341796875 +64428 0.601104736328125 +64429 0.61859130859375 +64430 0.63433837890625 +64431 0.6534423828125 +64432 0.64398193359375 +64433 0.664031982421875 +64434 0.635955810546875 +64435 0.656402587890625 +64436 0.587158203125 +64437 0.606689453125 +64438 0.48394775390625 +64439 0.500732421875 +64440 0.339385986328125 +64441 0.35198974609375 +64442 0.16802978515625 +64443 0.17547607421875 +64444 -0.037139892578125 +64445 -0.036102294921875 +64446 -0.253753662109375 +64447 -0.259613037109375 +64448 -0.4322509765625 +64449 -0.443878173828125 +64450 -0.560791015625 +64451 -0.576690673828125 +64452 -0.634765625 +64453 -0.653289794921875 +64454 -0.624237060546875 +64455 -0.6427001953125 +64456 -0.54669189453125 +64457 -0.563018798828125 +64458 -0.445159912109375 +64459 -0.458648681640625 +64460 -0.34027099609375 +64461 -0.35089111328125 +64462 -0.25225830078125 +64463 -0.26055908203125 +64464 -0.1851806640625 +64465 -0.191864013671875 +64466 -0.135833740234375 +64467 -0.141448974609375 +64468 -0.0966796875 +64469 -0.101470947265625 +64470 -0.058135986328125 +64471 -0.06201171875 +64472 -0.0084228515625 +64473 -0.010894775390625 +64474 0.06414794921875 +64475 0.06396484375 +64476 0.147308349609375 +64477 0.149871826171875 +64478 0.2371826171875 +64479 0.24285888671875 +64480 0.340789794921875 +64481 0.35015869140625 +64482 0.445037841796875 +64483 0.458221435546875 +64484 0.52825927734375 +64485 0.54461669921875 +64486 0.5556640625 +64487 0.573394775390625 +64488 0.49078369140625 +64489 0.506866455078125 +64490 0.339691162109375 +64491 0.35125732421875 +64492 0.140869140625 +64493 0.146331787109375 +64494 -0.05499267578125 +64495 -0.05560302734375 +64496 -0.211334228515625 +64497 -0.216766357421875 +64498 -0.326568603515625 +64499 -0.3355712890625 +64500 -0.392669677734375 +64501 -0.403717041015625 +64502 -0.4298095703125 +64503 -0.442047119140625 +64504 -0.482513427734375 +64505 -0.49652099609375 +64506 -0.54461669921875 +64507 -0.560821533203125 +64508 -0.583526611328125 +64509 -0.60125732421875 +64510 -0.56707763671875 +64511 -0.584625244140625 +64512 -0.46527099609375 +64513 -0.47955322265625 +64514 -0.272430419921875 +64515 -0.279449462890625 +64516 -0.012481689453125 +64517 -0.00885009765625 +64518 0.254608154296875 +64519 0.26898193359375 +64520 0.461822509765625 +64521 0.483123779296875 +64522 0.581085205078125 +64523 0.6041259765625 +64524 0.62969970703125 +64525 0.65093994140625 +64526 0.645782470703125 +64527 0.664581298828125 +64528 0.62640380859375 +64529 0.64208984375 +64530 0.5618896484375 +64531 0.573150634765625 +64532 0.490631103515625 +64533 0.49871826171875 +64534 0.4326171875 +64535 0.439971923828125 +64536 0.36846923828125 +64537 0.375946044921875 +64538 0.268707275390625 +64539 0.274810791015625 +64540 0.1077880859375 +64541 0.10894775390625 +64542 -0.09307861328125 +64543 -0.099365234375 +64544 -0.30377197265625 +64545 -0.318359375 +64546 -0.525115966796875 +64547 -0.549224853515625 +64548 -0.74017333984375 +64549 -0.77423095703125 +64550 -0.859375 +64551 -0.8638916015625 +64552 -0.8671875 +64553 -0.870391845703125 +64554 -0.867279052734375 +64555 -0.868896484375 +64556 -0.8609619140625 +64557 -0.860931396484375 +64558 -0.780975341796875 +64559 -0.764373779296875 +64560 -0.563140869140625 +64561 -0.528350830078125 +64562 -0.2669677734375 +64563 -0.21270751953125 +64564 0.0670166015625 +64565 0.139404296875 +64566 0.39056396484375 +64567 0.476806640625 +64568 0.670135498046875 +64569 0.764190673828125 +64570 0.857269287109375 +64571 0.86761474609375 +64572 0.870361328125 +64573 0.870361328125 +64574 0.870361328125 +64575 0.8646240234375 +64576 0.862762451171875 +64577 0.828948974609375 +64578 0.81683349609375 +64579 0.673553466796875 +64580 0.66668701171875 +64581 0.490966796875 +64582 0.49884033203125 +64583 0.30218505859375 +64584 0.316192626953125 +64585 0.11041259765625 +64586 0.08917236328125 +64587 -0.116455078125 +64588 -0.189239501953125 +64589 -0.38714599609375 +64590 -0.480194091796875 +64591 -0.66192626953125 +64592 -0.729400634765625 +64593 -0.85784912109375 +64594 -0.859344482421875 +64595 -0.870391845703125 +64596 -0.868682861328125 +64597 -0.870391845703125 +64598 -0.870391845703125 +64599 -0.86444091796875 +64600 -0.870025634765625 +64601 -0.85723876953125 +64602 -0.8660888671875 +64603 -0.790008544921875 +64604 -0.84332275390625 +64605 -0.62847900390625 +64606 -0.644500732421875 +64607 -0.3956298828125 +64608 -0.39642333984375 +64609 -0.126708984375 +64610 -0.12567138671875 +64611 0.150115966796875 +64612 0.15655517578125 +64613 0.424041748046875 +64614 0.425537109375 +64615 0.670623779296875 +64616 0.64617919921875 +64617 0.854522705078125 +64618 0.8037109375 +64619 0.866485595703125 +64620 0.85791015625 +64621 0.86920166015625 +64622 0.860809326171875 +64623 0.8653564453125 +64624 0.85931396484375 +64625 0.857147216796875 +64626 0.84466552734375 +64627 0.766845703125 +64628 0.7576904296875 +64629 0.628509521484375 +64630 0.634002685546875 +64631 0.462127685546875 +64632 0.499786376953125 +64633 0.297210693359375 +64634 0.3681640625 +64635 0.14862060546875 +64636 0.218780517578125 +64637 -0.00537109375 +64638 0.05902099609375 +64639 -0.15753173828125 +64640 -0.114654541015625 +64641 -0.31304931640625 +64642 -0.316162109375 +64643 -0.48876953125 +64644 -0.50286865234375 +64645 -0.6416015625 +64646 -0.6533203125 +64647 -0.751373291015625 +64648 -0.7911376953125 +64649 -0.84619140625 +64650 -0.8599853515625 +64651 -0.861297607421875 +64652 -0.866607666015625 +64653 -0.863250732421875 +64654 -0.864501953125 +64655 -0.856597900390625 +64656 -0.855072021484375 +64657 -0.7498779296875 +64658 -0.76239013671875 +64659 -0.624542236328125 +64660 -0.6351318359375 +64661 -0.47808837890625 +64662 -0.424102783203125 +64663 -0.253387451171875 +64664 -0.17254638671875 +64665 0.003692626953125 +64666 0.05548095703125 +64667 0.2257080078125 +64668 0.27215576171875 +64669 0.427154541015625 +64670 0.5086669921875 +64671 0.643218994140625 +64672 0.757232666015625 +64673 0.855926513671875 +64674 0.866546630859375 +64675 0.870361328125 +64676 0.870361328125 +64677 0.870361328125 +64678 0.8665771484375 +64679 0.862762451171875 +64680 0.855560302734375 +64681 0.79669189453125 +64682 0.693359375 +64683 0.595794677734375 +64684 0.483917236328125 +64685 0.362152099609375 +64686 0.264984130859375 +64687 0.1270751953125 +64688 0.0577392578125 +64689 -0.086944580078125 +64690 -0.13580322265625 +64691 -0.2784423828125 +64692 -0.34967041015625 +64693 -0.484832763671875 +64694 -0.60455322265625 +64695 -0.729583740234375 +64696 -0.854766845703125 +64697 -0.86688232421875 +64698 -0.870391845703125 +64699 -0.870391845703125 +64700 -0.870391845703125 +64701 -0.86859130859375 +64702 -0.86614990234375 +64703 -0.86279296875 +64704 -0.855255126953125 +64705 -0.817962646484375 +64706 -0.668487548828125 +64707 -0.6116943359375 +64708 -0.38372802734375 +64709 -0.3128662109375 +64710 -0.044097900390625 +64711 0.039398193359375 +64712 0.328857421875 +64713 0.422821044921875 +64714 0.704010009765625 +64715 0.805145263671875 +64716 0.870361328125 +64717 0.870361328125 +64718 0.870361328125 +64719 0.870361328125 +64720 0.86029052734375 +64721 0.860015869140625 +64722 0.73516845703125 +64723 0.727935791015625 +64724 0.494720458984375 +64725 0.48114013671875 +64726 0.22552490234375 +64727 0.2059326171875 +64728 -0.037384033203125 +64729 -0.06103515625 +64730 -0.27398681640625 +64731 -0.29913330078125 +64732 -0.490875244140625 +64733 -0.516204833984375 +64734 -0.69940185546875 +64735 -0.7252197265625 +64736 -0.85699462890625 +64737 -0.85980224609375 +64738 -0.870025634765625 +64739 -0.870391845703125 +64740 -0.870391845703125 +64741 -0.870391845703125 +64742 -0.85882568359375 +64743 -0.858062744140625 +64744 -0.6898193359375 +64745 -0.673004150390625 +64746 -0.45257568359375 +64747 -0.42694091796875 +64748 -0.240020751953125 +64749 -0.2100830078125 +64750 -0.065643310546875 +64751 -0.0362548828125 +64752 0.083770751953125 +64753 0.10943603515625 +64754 0.21514892578125 +64755 0.23516845703125 +64756 0.358367919921875 +64757 0.373687744140625 +64758 0.505950927734375 +64759 0.517791748046875 +64760 0.5966796875 +64761 0.602783203125 +64762 0.6365966796875 +64763 0.635711669921875 +64764 0.661376953125 +64765 0.655181884765625 +64766 0.669158935546875 +64767 0.65948486328125 +64768 0.6619873046875 +64769 0.651275634765625 +64770 0.628631591796875 +64771 0.61846923828125 +64772 0.547821044921875 +64773 0.53753662109375 +64774 0.416229248046875 +64775 0.404144287109375 +64776 0.237823486328125 +64777 0.22186279296875 +64778 0.025482177734375 +64779 0.003997802734375 +64780 -0.19415283203125 +64781 -0.22100830078125 +64782 -0.394256591796875 +64783 -0.42449951171875 +64784 -0.5498046875 +64785 -0.579833984375 +64786 -0.61920166015625 +64787 -0.641876220703125 +64788 -0.608245849609375 +64789 -0.6177978515625 +64790 -0.57781982421875 +64791 -0.575531005859375 +64792 -0.53778076171875 +64793 -0.526336669921875 +64794 -0.44842529296875 +64795 -0.42645263671875 +64796 -0.29376220703125 +64797 -0.2581787109375 +64798 -0.116668701171875 +64799 -0.068695068359375 +64800 0.03741455078125 +64801 0.09222412109375 +64802 0.174774169921875 +64803 0.232147216796875 +64804 0.294677734375 +64805 0.3509521484375 +64806 0.361480712890625 +64807 0.410064697265625 +64808 0.3414306640625 +64809 0.372955322265625 +64810 0.248138427734375 +64811 0.2554931640625 +64812 0.1256103515625 +64813 0.10711669921875 +64814 -0.009307861328125 +64815 -0.052886962890625 +64816 -0.122528076171875 +64817 -0.186279296875 +64818 -0.1600341796875 +64819 -0.23291015625 +64820 -0.137054443359375 +64821 -0.209442138671875 +64822 -0.1063232421875 +64823 -0.174163818359375 +64824 -0.067352294921875 +64825 -0.126739501953125 +64826 -0.002655029296875 +64827 -0.048126220703125 +64828 0.070953369140625 +64829 0.0426025390625 +64830 0.119659423828125 +64831 0.10748291015625 +64832 0.139068603515625 +64833 0.1409912109375 +64834 0.178558349609375 +64835 0.19708251953125 +64836 0.23687744140625 +64837 0.273651123046875 +64838 0.266693115234375 +64839 0.31768798828125 +64840 0.279266357421875 +64841 0.341094970703125 +64842 0.296844482421875 +64843 0.368011474609375 +64844 0.2962646484375 +64845 0.37249755859375 +64846 0.229095458984375 +64847 0.30072021484375 +64848 0.094482421875 +64849 0.1517333984375 +64850 -0.0535888671875 +64851 -0.01470947265625 +64852 -0.206024169921875 +64853 -0.1883544921875 +64854 -0.366302490234375 +64855 -0.372711181640625 +64856 -0.486236572265625 +64857 -0.51397705078125 +64858 -0.529754638671875 +64859 -0.57177734375 +64860 -0.49139404296875 +64861 -0.53948974609375 +64862 -0.387969970703125 +64863 -0.43511962890625 +64864 -0.25390625 +64865 -0.2962646484375 +64866 -0.124176025390625 +64867 -0.161102294921875 +64868 -0.011749267578125 +64869 -0.0435791015625 +64870 0.086700439453125 +64871 0.060394287109375 +64872 0.158203125 +64873 0.13665771484375 +64874 0.1890869140625 +64875 0.170135498046875 +64876 0.18365478515625 +64877 0.16552734375 +64878 0.173095703125 +64879 0.15728759765625 +64880 0.16253662109375 +64881 0.150787353515625 +64882 0.13055419921875 +64883 0.12200927734375 +64884 0.085784912109375 +64885 0.080108642578125 +64886 0.052276611328125 +64887 0.05126953125 +64888 0.055267333984375 +64889 0.062896728515625 +64890 0.07501220703125 +64891 0.09271240234375 +64892 0.068756103515625 +64893 0.092987060546875 +64894 0.050201416015625 +64895 0.07855224609375 +64896 0.0330810546875 +64897 0.06427001953125 +64898 0.003692626953125 +64899 0.0347900390625 +64900 -0.039520263671875 +64901 -0.01171875 +64902 -0.07916259765625 +64903 -0.056060791015625 +64904 -0.076690673828125 +64905 -0.055511474609375 +64906 -0.0325927734375 +64907 -0.010467529296875 +64908 0.00408935546875 +64909 0.02508544921875 +64910 0.01007080078125 +64911 0.025665283203125 +64912 0.008575439453125 +64913 0.017333984375 +64914 0.0008544921875 +64915 0.00189208984375 +64916 -0.0234375 +64917 -0.03173828125 +64918 -0.05377197265625 +64919 -0.071502685546875 +64920 -0.106719970703125 +64921 -0.13543701171875 +64922 -0.17926025390625 +64923 -0.219970703125 +64924 -0.249359130859375 +64925 -0.300506591796875 +64926 -0.316497802734375 +64927 -0.376312255859375 +64928 -0.352386474609375 +64929 -0.416107177734375 +64930 -0.31292724609375 +64931 -0.371124267578125 +64932 -0.198822021484375 +64933 -0.242279052734375 +64934 -0.046234130859375 +64935 -0.069732666015625 +64936 0.12615966796875 +64937 0.125640869140625 +64938 0.290435791015625 +64939 0.31268310546875 +64940 0.414031982421875 +64941 0.45501708984375 +64942 0.4991455078125 +64943 0.554779052734375 +64944 0.54486083984375 +64945 0.61065673828125 +64946 0.54083251953125 +64947 0.610931396484375 +64948 0.465484619140625 +64949 0.531463623046875 +64950 0.333465576171875 +64951 0.3883056640625 +64952 0.1929931640625 +64953 0.23468017578125 +64954 0.066436767578125 +64955 0.095245361328125 +64956 -0.022674560546875 +64957 -0.00396728515625 +64958 -0.061370849609375 +64959 -0.04852294921875 +64960 -0.064849853515625 +64961 -0.055145263671875 +64962 -0.08026123046875 +64963 -0.0758056640625 +64964 -0.13330078125 +64965 -0.138702392578125 +64966 -0.192901611328125 +64967 -0.209197998046875 +64968 -0.260833740234375 +64969 -0.289031982421875 +64970 -0.337921142578125 +64971 -0.37884521484375 +64972 -0.404205322265625 +64973 -0.456329345703125 +64974 -0.455322265625 +64975 -0.51641845703125 +64976 -0.4554443359375 +64977 -0.519287109375 +64978 -0.39862060546875 +64979 -0.458251953125 +64980 -0.331451416015625 +64981 -0.384796142578125 +64982 -0.276397705078125 +64983 -0.323699951171875 +64984 -0.228240966796875 +64985 -0.269287109375 +64986 -0.1630859375 +64987 -0.1951904296875 +64988 -0.07952880859375 +64989 -0.100006103515625 +64990 -0.001678466796875 +64991 -0.01055908203125 +64992 0.09796142578125 +64993 0.1033935546875 +64994 0.22613525390625 +64995 0.24908447265625 +64996 0.334869384765625 +64997 0.373199462890625 +64998 0.40838623046875 +64999 0.45806884765625 +65000 0.453826904296875 +65001 0.511474609375 +65002 0.500274658203125 +65003 0.565399169921875 +65004 0.54022216796875 +65005 0.61138916015625 +65006 0.519744873046875 +65007 0.5897216796875 +65008 0.429962158203125 +65009 0.4906005859375 +65010 0.286712646484375 +65011 0.33148193359375 +65012 0.1219482421875 +65013 0.147796630859375 +65014 -0.026702880859375 +65015 -0.01873779296875 +65016 -0.134185791015625 +65017 -0.140289306640625 +65018 -0.178192138671875 +65019 -0.191986083984375 +65020 -0.1683349609375 +65021 -0.184295654296875 +65022 -0.145111083984375 +65023 -0.161834716796875 +65024 -0.1466064453125 +65025 -0.166595458984375 +65026 -0.16876220703125 +65027 -0.19390869140625 +65028 -0.1942138671875 +65029 -0.22442626953125 +65030 -0.242523193359375 +65031 -0.279754638671875 +65032 -0.294952392578125 +65033 -0.3389892578125 +65034 -0.30853271484375 +65035 -0.3543701171875 +65036 -0.30328369140625 +65037 -0.348175048828125 +65038 -0.2841796875 +65039 -0.32598876953125 +65040 -0.2244873046875 +65041 -0.2581787109375 +65042 -0.11968994140625 +65043 -0.139801025390625 +65044 0.01727294921875 +65045 0.014617919921875 +65046 0.131866455078125 +65047 0.144378662109375 +65048 0.19866943359375 +65049 0.221038818359375 +65050 0.241241455078125 +65051 0.27069091796875 +65052 0.260345458984375 +65053 0.294036865234375 +65054 0.27471923828125 +65055 0.311767578125 +65056 0.298065185546875 +65057 0.339141845703125 +65058 0.315765380859375 +65059 0.360260009765625 +65060 0.3148193359375 +65061 0.360504150390625 +65062 0.2679443359375 +65063 0.308380126953125 +65064 0.155975341796875 +65065 0.18170166015625 +65066 0.000274658203125 +65067 0.0047607421875 +65068 -0.158172607421875 +65069 -0.17559814453125 +65070 -0.279998779296875 +65071 -0.3143310546875 +65072 -0.327178955078125 +65073 -0.36785888671875 +65074 -0.32257080078125 +65075 -0.36248779296875 +65076 -0.30572509765625 +65077 -0.343536376953125 +65078 -0.268707275390625 +65079 -0.3018798828125 +65080 -0.20623779296875 +65081 -0.231414794921875 +65082 -0.105743408203125 +65083 -0.117645263671875 +65084 0.004425048828125 +65085 0.007049560546875 +65086 0.0765380859375 +65087 0.087982177734375 +65088 0.12298583984375 +65089 0.13946533203125 +65090 0.15478515625 +65091 0.17425537109375 +65092 0.168212890625 +65093 0.188201904296875 +65094 0.1544189453125 +65095 0.171234130859375 +65096 0.10906982421875 +65097 0.118438720703125 +65098 0.055908203125 +65099 0.05706787109375 +65100 -0.003204345703125 +65101 -0.010711669921875 +65102 -0.073974609375 +65103 -0.0914306640625 +65104 -0.136474609375 +65105 -0.162322998046875 +65106 -0.16552734375 +65107 -0.194549560546875 +65108 -0.127227783203125 +65109 -0.1492919921875 +65110 -0.0172119140625 +65111 -0.02166748046875 +65112 0.1085205078125 +65113 0.124053955078125 +65114 0.18316650390625 +65115 0.211151123046875 +65116 0.20751953125 +65117 0.240447998046875 +65118 0.2080078125 +65119 0.242218017578125 +65120 0.192779541015625 +65121 0.2257080078125 +65122 0.16485595703125 +65123 0.194366455078125 +65124 0.09576416015625 +65125 0.115509033203125 +65126 0.00616455078125 +65127 0.0128173828125 +65128 -0.05169677734375 +65129 -0.053802490234375 +65130 -0.100738525390625 +65131 -0.110626220703125 +65132 -0.177520751953125 +65133 -0.199493408203125 +65134 -0.259368896484375 +65135 -0.29437255859375 +65136 -0.291351318359375 +65137 -0.33221435546875 +65138 -0.2445068359375 +65139 -0.27972412109375 +65140 -0.161102294921875 +65141 -0.185333251953125 +65142 -0.1102294921875 +65143 -0.128204345703125 +65144 -0.098358154296875 +65145 -0.115692138671875 +65146 -0.09820556640625 +65147 -0.116455078125 +65148 -0.088409423828125 +65149 -0.105926513671875 +65150 -0.042724609375 +65151 -0.053955078125 +65152 0.046966552734375 +65153 0.048797607421875 +65154 0.141448974609375 +65155 0.157318115234375 +65156 0.188751220703125 +65157 0.212005615234375 +65158 0.19378662109375 +65159 0.218475341796875 +65160 0.209381103515625 +65161 0.23724365234375 +65162 0.267913818359375 +65163 0.30535888671875 +65164 0.333160400390625 +65165 0.38128662109375 +65166 0.35235595703125 +65167 0.404449462890625 +65168 0.342620849609375 +65169 0.3944091796875 +65170 0.33660888671875 +65171 0.3885498046875 +65172 0.31329345703125 +65173 0.362640380859375 +65174 0.235137939453125 +65175 0.27362060546875 +65176 0.098358154296875 +65177 0.11712646484375 +65178 -0.051727294921875 +65179 -0.054901123046875 +65180 -0.170135498046875 +65181 -0.19085693359375 +65182 -0.25250244140625 +65183 -0.28570556640625 +65184 -0.2987060546875 +65185 -0.339263916015625 +65186 -0.331451416015625 +65187 -0.3775634765625 +65188 -0.390106201171875 +65189 -0.445709228515625 +65190 -0.46722412109375 +65191 -0.535064697265625 +65192 -0.548370361328125 +65193 -0.629058837890625 +65194 -0.60736083984375 +65195 -0.697601318359375 +65196 -0.612152099609375 +65197 -0.70391845703125 +65198 -0.557952880859375 +65199 -0.6424560546875 +65200 -0.425628662109375 +65201 -0.491241455078125 +65202 -0.2286376953125 +65203 -0.265716552734375 +65204 -0.0174560546875 +65205 -0.023712158203125 +65206 0.179107666015625 +65207 0.201751708984375 +65208 0.3306884765625 +65209 0.375823974609375 +65210 0.42559814453125 +65211 0.485076904296875 +65212 0.498138427734375 +65213 0.56884765625 +65214 0.55499267578125 +65215 0.634765625 +65216 0.55682373046875 +65217 0.63763427734375 +65218 0.49371337890625 +65219 0.5660400390625 +65220 0.41107177734375 +65221 0.4720458984375 +65222 0.3536376953125 +65223 0.40692138671875 +65224 0.327667236328125 +65225 0.3778076171875 +65226 0.326446533203125 +65227 0.376953125 +65228 0.32177734375 +65229 0.371978759765625 +65230 0.27032470703125 +65231 0.313140869140625 +65232 0.158111572265625 +65233 0.184417724609375 +65234 0.00726318359375 +65235 0.011199951171875 +65236 -0.151336669921875 +65237 -0.171051025390625 +65238 -0.29595947265625 +65239 -0.33740234375 +65240 -0.41278076171875 +65241 -0.47198486328125 +65242 -0.489288330078125 +65243 -0.560394287109375 +65244 -0.50628662109375 +65245 -0.58056640625 +65246 -0.476898193359375 +65247 -0.54754638671875 +65248 -0.4423828125 +65249 -0.508575439453125 +65250 -0.399139404296875 +65251 -0.459503173828125 +65252 -0.342010498046875 +65253 -0.394378662109375 +65254 -0.30535888671875 +65255 -0.35260009765625 +65256 -0.26959228515625 +65257 -0.31170654296875 +65258 -0.169952392578125 +65259 -0.197418212890625 +65260 -0.0048828125 +65261 -0.007965087890625 +65262 0.1827392578125 +65263 0.207489013671875 +65264 0.3582763671875 +65265 0.409210205078125 +65266 0.499847412109375 +65267 0.57208251953125 +65268 0.581207275390625 +65269 0.66595458984375 +65270 0.57440185546875 +65271 0.65875244140625 +65272 0.4942626953125 +65273 0.56744384765625 +65274 0.375152587890625 +65275 0.431396484375 +65276 0.255340576171875 +65277 0.29443359375 +65278 0.15740966796875 +65279 0.182464599609375 +65280 0.05413818359375 +65281 0.06365966796875 +65282 -0.066650390625 +65283 -0.075958251953125 +65284 -0.16534423828125 +65285 -0.189422607421875 +65286 -0.237640380859375 +65287 -0.271942138671875 +65288 -0.29931640625 +65289 -0.342529296875 +65290 -0.31915283203125 +65291 -0.364166259765625 +65292 -0.28900146484375 +65293 -0.327239990234375 +65294 -0.246826171875 +65295 -0.2769775390625 +65296 -0.22650146484375 +65297 -0.253692626953125 +65298 -0.216522216796875 +65299 -0.24365234375 +65300 -0.176300048828125 +65301 -0.1983642578125 +65302 -0.104644775390625 +65303 -0.116241455078125 +65304 -0.034912109375 +65305 -0.036834716796875 +65306 0.02850341796875 +65307 0.034881591796875 +65308 0.0789794921875 +65309 0.09124755859375 +65310 0.09674072265625 +65311 0.10888671875 +65312 0.11328125 +65313 0.125518798828125 +65314 0.14239501953125 +65315 0.15771484375 +65316 0.1611328125 +65317 0.17828369140625 +65318 0.155853271484375 +65319 0.17108154296875 +65320 0.121429443359375 +65321 0.129974365234375 +65322 0.0809326171875 +65323 0.082427978515625 +65324 0.033782958984375 +65325 0.027679443359375 +65326 -0.046295166015625 +65327 -0.065643310546875 +65328 -0.12713623046875 +65329 -0.15936279296875 +65330 -0.174652099609375 +65331 -0.21307373046875 +65332 -0.195343017578125 +65333 -0.234649658203125 +65334 -0.168975830078125 +65335 -0.2001953125 +65336 -0.103363037109375 +65337 -0.119171142578125 +65338 -0.0262451171875 +65339 -0.024749755859375 +65340 0.06475830078125 +65341 0.085784912109375 +65342 0.14093017578125 +65343 0.178131103515625 +65344 0.1715087890625 +65345 0.215576171875 +65346 0.167694091796875 +65347 0.211456298828125 +65348 0.137451171875 +65349 0.17523193359375 +65350 0.099090576171875 +65351 0.128753662109375 +65352 0.077728271484375 +65353 0.1019287109375 +65354 0.05615234375 +65355 0.0743408203125 +65356 0.031951904296875 +65357 0.04327392578125 +65358 0.029754638671875 +65359 0.038177490234375 +65360 0.063873291015625 +65361 0.076263427734375 +65362 0.120361328125 +65363 0.14105224609375 +65364 0.160400390625 +65365 0.186431884765625 +65366 0.1640625 +65367 0.188812255859375 +65368 0.123565673828125 +65369 0.1390380859375 +65370 0.04278564453125 +65371 0.041778564453125 +65372 -0.058563232421875 +65373 -0.079437255859375 +65374 -0.176116943359375 +65375 -0.219390869140625 +65376 -0.30120849609375 +65377 -0.367828369140625 +65378 -0.40875244140625 +65379 -0.494873046875 +65380 -0.461456298828125 +65381 -0.556243896484375 +65382 -0.422943115234375 +65383 -0.508697509765625 +65384 -0.312774658203125 +65385 -0.3756103515625 +65386 -0.182891845703125 +65387 -0.218902587890625 +65388 -0.0543212890625 +65389 -0.063751220703125 +65390 0.074432373046875 +65391 0.091552734375 +65392 0.19427490234375 +65393 0.23602294921875 +65394 0.282867431640625 +65395 0.342987060546875 +65396 0.3258056640625 +65397 0.39520263671875 +65398 0.320343017578125 +65399 0.389373779296875 +65400 0.26544189453125 +65401 0.324249267578125 +65402 0.181488037109375 +65403 0.224090576171875 +65404 0.098175048828125 +65405 0.124267578125 +65406 0.025787353515625 +65407 0.037078857421875 +65408 -0.012725830078125 +65409 -0.010101318359375 +65410 -0.019256591796875 +65411 -0.019439697265625 +65412 -0.0206298828125 +65413 -0.022796630859375 +65414 -0.00128173828125 +65415 -0.001556396484375 +65416 0.048797607421875 +65417 0.056304931640625 +65418 0.092498779296875 +65419 0.106719970703125 +65420 0.085418701171875 +65421 0.096893310546875 +65422 0.04083251953125 +65423 0.042694091796875 +65424 -0.009521484375 +65425 -0.018035888671875 +65426 -0.057769775390625 +65427 -0.07586669921875 +65428 -0.0943603515625 +65429 -0.11944580078125 +65430 -0.128509521484375 +65431 -0.15972900390625 +65432 -0.165130615234375 +65433 -0.202606201171875 +65434 -0.204620361328125 +65435 -0.24859619140625 +65436 -0.253173828125 +65437 -0.30517578125 +65438 -0.30218505859375 +65439 -0.36212158203125 +65440 -0.32806396484375 +65441 -0.39141845703125 +65442 -0.298980712890625 +65443 -0.35528564453125 +65444 -0.211700439453125 +65445 -0.249969482421875 +65446 -0.080810546875 +65447 -0.092864990234375 +65448 0.07110595703125 +65449 0.08905029296875 +65450 0.1932373046875 +65451 0.2352294921875 +65452 0.2630615234375 +65453 0.318817138671875 +65454 0.29638671875 +65455 0.358642578125 +65456 0.287384033203125 +65457 0.347747802734375 +65458 0.235626220703125 +65459 0.28564453125 +65460 0.18377685546875 +65461 0.223175048828125 +65462 0.162353515625 +65463 0.196746826171875 +65464 0.149078369140625 +65465 0.179840087890625 +65466 0.129669189453125 +65467 0.155548095703125 +65468 0.1270751953125 +65469 0.151214599609375 +65470 0.132904052734375 +65471 0.156951904296875 +65472 0.1126708984375 +65473 0.13177490234375 +65474 0.087432861328125 +65475 0.100799560546875 +65476 0.076507568359375 +65477 0.087127685546875 +65478 0.049774169921875 +65479 0.05487060546875 +65480 -0.003692626953125 +65481 -0.009002685546875 +65482 -0.08349609375 +65483 -0.10400390625 +65484 -0.189056396484375 +65485 -0.229400634765625 +65486 -0.29541015625 +65487 -0.35552978515625 +65488 -0.368499755859375 +65489 -0.441925048828125 +65490 -0.39599609375 +65491 -0.473846435546875 +65492 -0.38916015625 +65493 -0.464813232421875 +65494 -0.351531982421875 +65495 -0.419097900390625 +65496 -0.281097412109375 +65497 -0.334320068359375 +65498 -0.192474365234375 +65499 -0.227935791015625 +65500 -0.105377197265625 +65501 -0.12347412109375 +65502 -0.025421142578125 +65503 -0.02764892578125 +65504 0.062652587890625 +65505 0.077667236328125 +65506 0.17633056640625 +65507 0.2132568359375 +65508 0.323760986328125 +65509 0.38885498046875 +65510 0.48675537109375 +65511 0.582794189453125 +65512 0.614044189453125 +65513 0.734039306640625 +65514 0.669952392578125 +65515 0.800140380859375 +65516 0.652099609375 +65517 0.7783203125 +65518 0.557586669921875 +65519 0.6651611328125 +65520 0.385528564453125 +65521 0.45965576171875 +65522 0.167327880859375 +65523 0.199188232421875 +65524 -0.0419921875 +65525 -0.050689697265625 +65526 -0.194549560546875 +65527 -0.23297119140625 +65528 -0.27569580078125 +65529 -0.33013916015625 +65530 -0.307464599609375 +65531 -0.368408203125 +65532 -0.3160400390625 +65533 -0.378936767578125 +65534 -0.31427001953125 +65535 -0.376983642578125 +65536 -0.316497802734375 +65537 -0.37969970703125 +65538 -0.326416015625 +65539 -0.391510009765625 +65540 -0.321868896484375 +65541 -0.385345458984375 +65542 -0.28704833984375 +65543 -0.3419189453125 +65544 -0.239288330078125 +65545 -0.28289794921875 +65546 -0.213470458984375 +65547 -0.251617431640625 +65548 -0.22412109375 +65549 -0.266143798828125 +65550 -0.228363037109375 +65551 -0.273345947265625 +65552 -0.1806640625 +65553 -0.216796875 +65554 -0.10675048828125 +65555 -0.128265380859375 +65556 -0.05560302734375 +65557 -0.068145751953125 +65558 -0.032745361328125 +65559 -0.0430908203125 +65560 -0.015167236328125 +65561 -0.024444580078125 +65562 0.023590087890625 +65563 0.020721435546875 +65564 0.10931396484375 +65565 0.124481201171875 +65566 0.218475341796875 +65567 0.25787353515625 +65568 0.3172607421875 +65569 0.379119873046875 +65570 0.398956298828125 +65571 0.47991943359375 +65572 0.437591552734375 +65573 0.5281982421875 +65574 0.4228515625 +65575 0.511138916015625 +65576 0.37701416015625 +65577 0.456207275390625 +65578 0.33575439453125 +65579 0.407470703125 +65580 0.31439208984375 +65581 0.383758544921875 +65582 0.290313720703125 +65583 0.35687255859375 +65584 0.25152587890625 +65585 0.31182861328125 +65586 0.199951171875 +65587 0.250885009765625 +65588 0.128753662109375 +65589 0.1654052734375 +65590 0.02178955078125 +65591 0.035247802734375 +65592 -0.12286376953125 +65593 -0.142059326171875 +65594 -0.2801513671875 +65595 -0.33563232421875 +65596 -0.441192626953125 +65597 -0.5345458984375 +65598 -0.59234619140625 +65599 -0.72186279296875 +65600 -0.684417724609375 +65601 -0.836669921875 +65602 -0.680023193359375 +65603 -0.8326416015625 +65604 -0.595306396484375 +65605 -0.7296142578125 +65606 -0.4747314453125 +65607 -0.582550048828125 +65608 -0.357696533203125 +65609 -0.440093994140625 +65610 -0.26214599609375 +65611 -0.324310302734375 +65612 -0.16094970703125 +65613 -0.20147705078125 +65614 -0.03240966796875 +65615 -0.044647216796875 +65616 0.089263916015625 +65617 0.103973388671875 +65618 0.1700439453125 +65619 0.202392578125 +65620 0.2210693359375 +65621 0.264495849609375 +65622 0.2816162109375 +65623 0.338897705078125 +65624 0.366363525390625 +65625 0.443817138671875 +65626 0.44775390625 +65627 0.545074462890625 +65628 0.50531005859375 +65629 0.6173095703125 +65630 0.532562255859375 +65631 0.6524658203125 +65632 0.53997802734375 +65633 0.66339111328125 +65634 0.53253173828125 +65635 0.6561279296875 +65636 0.490997314453125 +65637 0.606781005859375 +65638 0.40399169921875 +65639 0.501190185546875 +65640 0.282470703125 +65641 0.352783203125 +65642 0.138641357421875 +65643 0.176544189453125 +65644 -0.033294677734375 +65645 -0.034820556640625 +65646 -0.214599609375 +65647 -0.258209228515625 +65648 -0.363922119140625 +65649 -0.44244384765625 +65650 -0.471343994140625 +65651 -0.5753173828125 +65652 -0.53302001953125 +65653 -0.65203857421875 +65654 -0.52398681640625 +65655 -0.641632080078125 +65656 -0.4588623046875 +65657 -0.562164306640625 +65658 -0.37359619140625 +65659 -0.458038330078125 +65660 -0.285430908203125 +65661 -0.350555419921875 +65662 -0.211273193359375 +65663 -0.260528564453125 +65664 -0.154571533203125 +65665 -0.192108154296875 +65666 -0.112701416015625 +65667 -0.141937255859375 +65668 -0.07940673828125 +65669 -0.1021728515625 +65670 -0.04669189453125 +65671 -0.062896728515625 +65672 -0.004791259765625 +65673 -0.011932373046875 +65674 0.056060791015625 +65675 0.062835693359375 +65676 0.1256103515625 +65677 0.148712158203125 +65678 0.20062255859375 +65679 0.241729736328125 +65680 0.286956787109375 +65681 0.34912109375 +65682 0.373687744140625 +65683 0.457305908203125 +65684 0.4427490234375 +65685 0.54388427734375 +65686 0.46514892578125 +65687 0.5728759765625 +65688 0.41046142578125 +65689 0.506591796875 +65690 0.283782958984375 +65691 0.351226806640625 +65692 0.117279052734375 +65693 0.146514892578125 +65694 -0.0467529296875 +65695 -0.05523681640625 +65696 -0.177703857421875 +65697 -0.21624755859375 +65698 -0.27423095703125 +65699 -0.334930419921875 +65700 -0.329620361328125 +65701 -0.402984619140625 +65702 -0.3607177734375 +65703 -0.4412841796875 +65704 -0.404693603515625 +65705 -0.49578857421875 +65706 -0.4564208984375 +65707 -0.5601806640625 +65708 -0.488677978515625 +65709 -0.600738525390625 +65710 -0.474639892578125 +65711 -0.584228515625 +65712 -0.3890380859375 +65713 -0.47930908203125 +65714 -0.2265625 +65715 -0.27935791015625 +65716 -0.007110595703125 +65717 -0.0089111328125 +65718 0.218170166015625 +65719 0.268798828125 +65720 0.39190673828125 +65721 0.482818603515625 +65722 0.49029541015625 +65723 0.60369873046875 +65724 0.528564453125 +65725 0.650421142578125 +65726 0.539886474609375 +65727 0.66400146484375 +65728 0.5218505859375 +65729 0.6414794921875 +65730 0.466094970703125 +65731 0.572540283203125 +65732 0.405731201171875 +65733 0.498138427734375 +65734 0.357879638671875 +65735 0.439453125 +65736 0.3056640625 +65737 0.375518798828125 +65738 0.223358154296875 +65739 0.274505615234375 +65740 0.088714599609375 +65741 0.1087646484375 +65742 -0.080230712890625 +65743 -0.099395751953125 +65744 -0.257781982421875 +65745 -0.3182373046875 +65746 -0.444854736328125 +65747 -0.5489501953125 +65748 -0.627105712890625 +65749 -0.7738037109375 +65750 -0.76171875 +65751 -0.86383056640625 +65752 -0.82177734375 +65753 -0.870391845703125 +65754 -0.82159423828125 +65755 -0.86895751953125 +65756 -0.771759033203125 +65757 -0.861053466796875 +65758 -0.6583251953125 +65759 -0.765869140625 +65760 -0.47216796875 +65761 -0.5301513671875 +65762 -0.219085693359375 +65763 -0.214691162109375 +65764 0.066070556640625 +65765 0.137359619140625 +65766 0.341827392578125 +65767 0.474822998046875 +65768 0.5794677734375 +65769 0.76239013671875 +65770 0.75714111328125 +65771 0.867462158203125 +65772 0.856719970703125 +65773 0.870361328125 +65774 0.862091064453125 +65775 0.86480712890625 +65776 0.8603515625 +65777 0.831817626953125 +65778 0.84765625 +65779 0.677581787109375 +65780 0.7464599609375 +65781 0.495880126953125 +65782 0.619842529296875 +65783 0.30767822265625 +65784 0.4696044921875 +65785 0.116180419921875 +65786 0.2701416015625 +65787 -0.110748291015625 +65788 0.015869140625 +65789 -0.381805419921875 +65790 -0.25860595703125 +65791 -0.6572265625 +65792 -0.504974365234375 +65793 -0.857421875 +65794 -0.68865966796875 +65795 -0.870391845703125 +65796 -0.803680419921875 +65797 -0.870391845703125 +65798 -0.856292724609375 +65799 -0.86444091796875 +65800 -0.8614501953125 +65801 -0.85723876953125 +65802 -0.8629150390625 +65803 -0.790008544921875 +65804 -0.8560791015625 +65805 -0.62847900390625 +65806 -0.72833251953125 +65807 -0.3956298828125 +65808 -0.53570556640625 +65809 -0.126708984375 +65810 -0.31268310546875 +65811 0.150115966796875 +65812 -0.06878662109375 +65813 0.424041748046875 +65814 0.174591064453125 +65815 0.670623779296875 +65816 0.386962890625 +65817 0.854522705078125 +65818 0.55419921875 +65819 0.866485595703125 +65820 0.664031982421875 +65821 0.86920166015625 +65822 0.73028564453125 +65823 0.8653564453125 +65824 0.763153076171875 +65825 0.857147216796875 +65826 0.76031494140625 +65827 0.766845703125 +65828 0.72576904296875 +65829 0.628509521484375 +65830 0.65435791015625 +65831 0.462127685546875 +65832 0.566314697265625 +65833 0.297210693359375 +65834 0.47149658203125 +65835 0.14862060546875 +65836 0.352447509765625 +65837 -0.00537109375 +65838 0.215362548828125 +65839 -0.15753173828125 +65840 0.057769775390625 +65841 -0.31304931640625 +65842 -0.13079833984375 +65843 -0.48876953125 +65844 -0.313629150390625 +65845 -0.6416015625 +65846 -0.471221923828125 +65847 -0.751373291015625 +65848 -0.621246337890625 +65849 -0.84619140625 +65850 -0.752044677734375 +65851 -0.861297607421875 +65852 -0.837799072265625 +65853 -0.863250732421875 +65854 -0.853973388671875 +65855 -0.856597900390625 +65856 -0.810028076171875 +65857 -0.7498779296875 +65858 -0.750946044921875 +65859 -0.624542236328125 +65860 -0.65985107421875 +65861 -0.47808837890625 +65862 -0.49163818359375 +65863 -0.253387451171875 +65864 -0.282012939453125 +65865 0.003692626953125 +65866 -0.0843505859375 +65867 0.2257080078125 +65868 0.110748291015625 +65869 0.427154541015625 +65870 0.328094482421875 +65871 0.643218994140625 +65872 0.5599365234375 +65873 0.855926513671875 +65874 0.761016845703125 +65875 0.870361328125 +65876 0.858642578125 +65877 0.870361328125 +65878 0.865997314453125 +65879 0.862762451171875 +65880 0.866119384765625 +65881 0.79669189453125 +65882 0.85821533203125 +65883 0.595794677734375 +65884 0.764984130859375 +65885 0.362152099609375 +65886 0.612213134765625 +65887 0.1270751953125 +65888 0.446929931640625 +65889 -0.086944580078125 +65890 0.271026611328125 +65891 -0.2784423828125 +65892 0.057769775390625 +65893 -0.484832763671875 +65894 -0.2073974609375 +65895 -0.729583740234375 +65896 -0.484893798828125 +65897 -0.86688232421875 +65898 -0.725250244140625 +65899 -0.870391845703125 +65900 -0.86212158203125 +65901 -0.86859130859375 +65902 -0.870391845703125 +65903 -0.86279296875 +65904 -0.870391845703125 +65905 -0.817962646484375 +65906 -0.8599853515625 +65907 -0.6116943359375 +65908 -0.712371826171875 +65909 -0.3128662109375 +65910 -0.4517822265625 +65911 0.039398193359375 +65912 -0.140289306640625 +65913 0.422821044921875 +65914 0.195465087890625 +65915 0.805145263671875 +65916 0.502899169921875 +65917 0.870361328125 +65918 0.739044189453125 +65919 0.870361328125 +65920 0.859100341796875 +65921 0.860015869140625 +65922 0.867462158203125 +65923 0.727935791015625 +65924 0.8668212890625 +65925 0.48114013671875 +65926 0.85968017578125 +65927 0.2059326171875 +65928 0.798187255859375 +65929 -0.06103515625 +65930 0.667572021484375 +65931 -0.29913330078125 +65932 0.50262451171875 +65933 -0.516204833984375 +65934 0.294586181640625 +65935 -0.7252197265625 +65936 0.065399169921875 +65937 -0.85980224609375 +65938 -0.156341552734375 +65939 -0.870391845703125 +65940 -0.346527099609375 +65941 -0.870391845703125 +65942 -0.467071533203125 +65943 -0.858062744140625 +65944 -0.51513671875 +65945 -0.673004150390625 +65946 -0.53265380859375 +65947 -0.42694091796875 +65948 -0.555877685546875 +65949 -0.2100830078125 +65950 -0.5855712890625 +65951 -0.0362548828125 +65952 -0.601959228515625 +65953 0.10943603515625 +65954 -0.5926513671875 +65955 0.23516845703125 +65956 -0.52862548828125 +65957 0.373687744140625 +65958 -0.41436767578125 +65959 0.517791748046875 +65960 -0.301544189453125 +65961 0.602783203125 +65962 -0.1884765625 +65963 0.635711669921875 +65964 -0.051177978515625 +65965 0.655181884765625 +65966 0.101348876953125 +65967 0.65948486328125 +65968 0.262237548828125 +65969 0.651275634765625 +65970 0.4124755859375 +65971 0.61846923828125 +65972 0.52398681640625 +65973 0.53753662109375 +65974 0.583953857421875 +65975 0.404144287109375 +65976 0.5865478515625 +65977 0.22186279296875 +65978 0.534820556640625 +65979 0.003997802734375 +65980 0.445159912109375 +65981 -0.22100830078125 +65982 0.336090087890625 +65983 -0.42449951171875 +65984 0.226715087890625 +65985 -0.579833984375 +65986 0.152496337890625 +65987 -0.641876220703125 +65988 0.110382080078125 +65989 -0.6177978515625 +65990 0.051971435546875 +65991 -0.575531005859375 +65992 -0.025604248046875 +65993 -0.526336669921875 +65994 -0.081390380859375 +65995 -0.42645263671875 +65996 -0.0938720703125 +65997 -0.2581787109375 +65998 -0.091552734375 +65999 -0.068695068359375 +66000 -0.1051025390625 +66001 0.09222412109375 +66002 -0.121307373046875 +66003 0.232147216796875 +66004 -0.13385009765625 +66005 0.3509521484375 +66006 -0.16754150390625 +66007 0.410064697265625 +66008 -0.2470703125 +66009 0.372955322265625 +66010 -0.358184814453125 +66011 0.2554931640625 +66012 -0.462371826171875 +66013 0.10711669921875 +66014 -0.546173095703125 +66015 -0.052886962890625 +66016 -0.58294677734375 +66017 -0.186279296875 +66018 -0.5303955078125 +66019 -0.23291015625 +66020 -0.40692138671875 +66021 -0.209442138671875 +66022 -0.26397705078125 +66023 -0.174163818359375 +66024 -0.10791015625 +66025 -0.126739501953125 +66026 0.069427490234375 +66027 -0.048126220703125 +66028 0.246978759765625 +66029 0.0426025390625 +66030 0.389739990234375 +66031 0.10748291015625 +66032 0.488800048828125 +66033 0.1409912109375 +66034 0.58258056640625 +66035 0.19708251953125 +66036 0.667388916015625 +66037 0.273651123046875 +66038 0.701416015625 +66039 0.31768798828125 +66040 0.694671630859375 +66041 0.341094970703125 +66042 0.667938232421875 +66043 0.368011474609375 +66044 0.60430908203125 +66045 0.37249755859375 +66046 0.46624755859375 +66047 0.30072021484375 +66048 0.25775146484375 +66049 0.1517333984375 +66050 0.0303955078125 +66051 -0.01470947265625 +66052 -0.201507568359375 +66053 -0.1883544921875 +66054 -0.43499755859375 +66055 -0.372711181640625 +66056 -0.62469482421875 +66057 -0.51397705078125 +66058 -0.73602294921875 +66059 -0.57177734375 +66060 -0.76080322265625 +66061 -0.53948974609375 +66062 -0.710479736328125 +66063 -0.43511962890625 +66064 -0.61236572265625 +66065 -0.2962646484375 +66066 -0.49542236328125 +66067 -0.161102294921875 +66068 -0.371612548828125 +66069 -0.0435791015625 +66070 -0.24041748046875 +66071 0.060394287109375 +66072 -0.115875244140625 +66073 0.13665771484375 +66074 -0.013397216796875 +66075 0.170135498046875 +66076 0.066009521484375 +66077 0.16552734375 +66078 0.143463134765625 +66079 0.15728759765625 +66080 0.218414306640625 +66081 0.150787353515625 +66082 0.26861572265625 +66083 0.12200927734375 +66084 0.2972412109375 +66085 0.080108642578125 +66086 0.321014404296875 +66087 0.05126953125 +66088 0.358428955078125 +66089 0.062896728515625 +66090 0.391693115234375 +66091 0.09271240234375 +66092 0.38494873046875 +66093 0.092987060546875 +66094 0.350189208984375 +66095 0.07855224609375 +66096 0.30035400390625 +66097 0.06427001953125 +66098 0.226470947265625 +66099 0.0347900390625 +66100 0.13031005859375 +66101 -0.01171875 +66102 0.029937744140625 +66103 -0.056060791015625 +66104 -0.03875732421875 +66105 -0.055511474609375 +66106 -0.072235107421875 +66107 -0.010467529296875 +66108 -0.107330322265625 +66109 0.02508544921875 +66110 -0.159942626953125 +66111 0.025665283203125 +66112 -0.207916259765625 +66113 0.017333984375 +66114 -0.247955322265625 +66115 0.00189208984375 +66116 -0.287200927734375 +66117 -0.03173828125 +66118 -0.3162841796875 +66119 -0.071502685546875 +66120 -0.34918212890625 +66121 -0.13543701171875 +66122 -0.38446044921875 +66123 -0.219970703125 +66124 -0.40557861328125 +66125 -0.300506591796875 +66126 -0.414459228515625 +66127 -0.376312255859375 +66128 -0.3905029296875 +66129 -0.416107177734375 +66130 -0.300201416015625 +66131 -0.371124267578125 +66132 -0.147430419921875 +66133 -0.242279052734375 +66134 0.03460693359375 +66135 -0.069732666015625 +66136 0.227508544921875 +66137 0.125640869140625 +66138 0.405548095703125 +66139 0.31268310546875 +66140 0.539642333984375 +66141 0.45501708984375 +66142 0.630218505859375 +66143 0.554779052734375 +66144 0.67578125 +66145 0.61065673828125 +66146 0.66766357421875 +66147 0.610931396484375 +66148 0.588592529296875 +66149 0.531463623046875 +66150 0.451934814453125 +66151 0.3883056640625 +66152 0.29949951171875 +66153 0.23468017578125 +66154 0.152069091796875 +66155 0.095245361328125 +66156 0.031646728515625 +66157 -0.00396728515625 +66158 -0.048370361328125 +66159 -0.04852294921875 +66160 -0.097930908203125 +66161 -0.055145263671875 +66162 -0.153656005859375 +66163 -0.0758056640625 +66164 -0.234619140625 +66165 -0.138702392578125 +66166 -0.31317138671875 +66167 -0.209197998046875 +66168 -0.38946533203125 +66169 -0.289031982421875 +66170 -0.46337890625 +66171 -0.37884521484375 +66172 -0.518035888671875 +66173 -0.456329345703125 +66174 -0.5501708984375 +66175 -0.51641845703125 +66176 -0.530914306640625 +66177 -0.519287109375 +66178 -0.45660400390625 +66179 -0.458251953125 +66180 -0.367645263671875 +66181 -0.384796142578125 +66182 -0.28460693359375 +66183 -0.323699951171875 +66184 -0.205352783203125 +66185 -0.269287109375 +66186 -0.112274169921875 +66187 -0.1951904296875 +66188 -0.00628662109375 +66189 -0.100006103515625 +66190 0.09063720703125 +66191 -0.01055908203125 +66192 0.199676513671875 +66193 0.1033935546875 +66194 0.3251953125 +66195 0.24908447265625 +66196 0.426513671875 +66197 0.373199462890625 +66198 0.49017333984375 +66199 0.45806884765625 +66200 0.522247314453125 +66201 0.511474609375 +66202 0.547393798828125 +66203 0.565399169921875 +66204 0.560302734375 +66205 0.61138916015625 +66206 0.517547607421875 +66207 0.5897216796875 +66208 0.413360595703125 +66209 0.4906005859375 +66210 0.262603759765625 +66211 0.33148193359375 +66212 0.09356689453125 +66213 0.147796630859375 +66214 -0.060791015625 +66215 -0.01873779296875 +66216 -0.178009033203125 +66217 -0.140289306640625 +66218 -0.23809814453125 +66219 -0.191986083984375 +66220 -0.247894287109375 +66221 -0.184295654296875 +66222 -0.24017333984375 +66223 -0.161834716796875 +66224 -0.24609375 +66225 -0.166595458984375 +66226 -0.262237548828125 +66227 -0.19390869140625 +66228 -0.2745361328125 +66229 -0.22442626953125 +66230 -0.2999267578125 +66231 -0.279754638671875 +66232 -0.32379150390625 +66233 -0.3389892578125 +66234 -0.31158447265625 +66235 -0.3543701171875 +66236 -0.2813720703125 +66237 -0.348175048828125 +66238 -0.23876953125 +66239 -0.32598876953125 +66240 -0.16302490234375 +66241 -0.2581787109375 +66242 -0.051727294921875 +66243 -0.139801025390625 +66244 0.08306884765625 +66245 0.014617919921875 +66246 0.194854736328125 +66247 0.144378662109375 +66248 0.261688232421875 +66249 0.221038818359375 +66250 0.302764892578125 +66251 0.27069091796875 +66252 0.318572998046875 +66253 0.294036865234375 +66254 0.32489013671875 +66255 0.311767578125 +66256 0.33367919921875 +66257 0.339141845703125 +66258 0.333709716796875 +66259 0.360260009765625 +66260 0.31500244140625 +66261 0.360504150390625 +66262 0.2552490234375 +66263 0.308380126953125 +66264 0.139190673828125 +66265 0.18170166015625 +66266 -0.0137939453125 +66267 0.0047607421875 +66268 -0.167755126953125 +66269 -0.17559814453125 +66270 -0.28814697265625 +66271 -0.3143310546875 +66272 -0.3416748046875 +66273 -0.36785888671875 +66274 -0.347259521484375 +66275 -0.36248779296875 +66276 -0.338226318359375 +66277 -0.343536376953125 +66278 -0.3076171875 +66279 -0.3018798828125 +66280 -0.25103759765625 +66281 -0.231414794921875 +66282 -0.15802001953125 +66283 -0.117645263671875 +66284 -0.053253173828125 +66285 0.007049560546875 +66286 0.02178955078125 +66287 0.087982177734375 +66288 0.076873779296875 +66289 0.13946533203125 +66290 0.12054443359375 +66291 0.17425537109375 +66292 0.148681640625 +66293 0.188201904296875 +66294 0.15283203125 +66295 0.171234130859375 +66296 0.128448486328125 +66297 0.118438720703125 +66298 0.095062255859375 +66299 0.05706787109375 +66300 0.05364990234375 +66301 -0.010711669921875 +66302 -0.001007080078125 +66303 -0.0914306640625 +66304 -0.051727294921875 +66305 -0.162322998046875 +66306 -0.07720947265625 +66307 -0.194549560546875 +66308 -0.0499267578125 +66309 -0.1492919921875 +66310 0.033599853515625 +66311 -0.02166748046875 +66312 0.127838134765625 +66313 0.124053955078125 +66314 0.178558349609375 +66315 0.211151123046875 +66316 0.186920166015625 +66317 0.240447998046875 +66318 0.175048828125 +66319 0.242218017578125 +66320 0.1502685546875 +66321 0.2257080078125 +66322 0.11572265625 +66323 0.194366455078125 +66324 0.048736572265625 +66325 0.115509033203125 +66326 -0.033203125 +66327 0.0128173828125 +66328 -0.087005615234375 +66329 -0.053802490234375 +66330 -0.131072998046875 +66331 -0.110626220703125 +66332 -0.195098876953125 +66333 -0.199493408203125 +66334 -0.26055908203125 +66335 -0.29437255859375 +66336 -0.28271484375 +66337 -0.33221435546875 +66338 -0.23822021484375 +66339 -0.27972412109375 +66340 -0.161956787109375 +66341 -0.185333251953125 +66342 -0.110809326171875 +66343 -0.128204345703125 +66344 -0.09063720703125 +66345 -0.115692138671875 +66346 -0.07977294921875 +66347 -0.116455078125 +66348 -0.061370849609375 +66349 -0.105926513671875 +66350 -0.014556884765625 +66351 -0.053955078125 +66352 0.06683349609375 +66353 0.048797607421875 +66354 0.150360107421875 +66355 0.157318115234375 +66356 0.19329833984375 +66357 0.212005615234375 +66358 0.199493408203125 +66359 0.218475341796875 +66360 0.212005615234375 +66361 0.23724365234375 +66362 0.25732421875 +66363 0.30535888671875 +66364 0.306121826171875 +66365 0.38128662109375 +66366 0.315582275390625 +66367 0.404449462890625 +66368 0.300079345703125 +66369 0.3944091796875 +66370 0.2867431640625 +66371 0.3885498046875 +66372 0.25885009765625 +66373 0.362640380859375 +66374 0.186248779296875 +66375 0.27362060546875 +66376 0.06634521484375 +66377 0.11712646484375 +66378 -0.063446044921875 +66379 -0.054901123046875 +66380 -0.165985107421875 +66381 -0.19085693359375 +66382 -0.2374267578125 +66383 -0.28570556640625 +66384 -0.277496337890625 +66385 -0.339263916015625 +66386 -0.3046875 +66387 -0.3775634765625 +66388 -0.3511962890625 +66389 -0.445709228515625 +66390 -0.4110107421875 +66391 -0.535064697265625 +66392 -0.47259521484375 +66393 -0.629058837890625 +66394 -0.51483154296875 +66395 -0.697601318359375 +66396 -0.511962890625 +66397 -0.70391845703125 +66398 -0.46044921875 +66399 -0.6424560546875 +66400 -0.3450927734375 +66401 -0.491241455078125 +66402 -0.177276611328125 +66403 -0.265716552734375 +66404 0.00140380859375 +66405 -0.023712158203125 +66406 0.167144775390625 +66407 0.201751708984375 +66408 0.29486083984375 +66409 0.375823974609375 +66410 0.374847412109375 +66411 0.485076904296875 +66412 0.43499755859375 +66413 0.56884765625 +66414 0.48077392578125 +66415 0.634765625 +66416 0.480133056640625 +66417 0.63763427734375 +66418 0.42510986328125 +66419 0.5660400390625 +66420 0.35302734375 +66421 0.4720458984375 +66422 0.30072021484375 +66423 0.40692138671875 +66424 0.273651123046875 +66425 0.3778076171875 +66426 0.266632080078125 +66427 0.376953125 +66428 0.2569580078125 +66429 0.371978759765625 +66430 0.20953369140625 +66431 0.313140869140625 +66432 0.11322021484375 +66433 0.184417724609375 +66434 -0.01361083984375 +66435 0.011199951171875 +66436 -0.14556884765625 +66437 -0.171051025390625 +66438 -0.264862060546875 +66439 -0.33740234375 +66440 -0.360137939453125 +66441 -0.47198486328125 +66442 -0.421234130859375 +66443 -0.560394287109375 +66444 -0.432586669921875 +66445 -0.58056640625 +66446 -0.40509033203125 +66447 -0.54754638671875 +66448 -0.372650146484375 +66449 -0.508575439453125 +66450 -0.33258056640625 +66451 -0.459503173828125 +66452 -0.28094482421875 +66453 -0.394378662109375 +66454 -0.246063232421875 +66455 -0.35260009765625 +66456 -0.21221923828125 +66457 -0.31170654296875 +66458 -0.12677001953125 +66459 -0.197418212890625 +66460 0.01129150390625 +66461 -0.007965087890625 +66462 0.166839599609375 +66463 0.207489013671875 +66464 0.311492919921875 +66465 0.409210205078125 +66466 0.4273681640625 +66467 0.57208251953125 +66468 0.4930419921875 +66469 0.66595458984375 +66470 0.485748291015625 +66471 0.65875244140625 +66472 0.417724609375 +66473 0.56744384765625 +66474 0.317169189453125 +66475 0.431396484375 +66476 0.215545654296875 +66477 0.29443359375 +66478 0.131500244140625 +66479 0.182464599609375 +66480 0.042633056640625 +66481 0.06365966796875 +66482 -0.060760498046875 +66483 -0.075958251953125 +66484 -0.145050048828125 +66485 -0.189422607421875 +66486 -0.20660400390625 +66487 -0.271942138671875 +66488 -0.25885009765625 +66489 -0.342529296875 +66490 -0.275360107421875 +66491 -0.364166259765625 +66492 -0.249267578125 +66493 -0.327239990234375 +66494 -0.2127685546875 +66495 -0.2769775390625 +66496 -0.19464111328125 +66497 -0.253692626953125 +66498 -0.185211181640625 +66499 -0.24365234375 +66500 -0.150115966796875 +66501 -0.1983642578125 +66502 -0.08837890625 +66503 -0.116241455078125 +66504 -0.028350830078125 +66505 -0.036834716796875 +66506 0.026214599609375 +66507 0.034881591796875 +66508 0.06964111328125 +66509 0.09124755859375 +66510 0.08514404296875 +66511 0.10888671875 +66512 0.099456787109375 +66513 0.125518798828125 +66514 0.124237060546875 +66515 0.15771484375 +66516 0.1400146484375 +66517 0.17828369140625 +66518 0.13525390625 +66519 0.17108154296875 +66520 0.105621337890625 +66521 0.129974365234375 +66522 0.070709228515625 +66523 0.082427978515625 +66524 0.030059814453125 +66525 0.027679443359375 +66526 -0.038543701171875 +66527 -0.065643310546875 +66528 -0.1077880859375 +66529 -0.15936279296875 +66530 -0.148773193359375 +66531 -0.21307373046875 +66532 -0.166961669921875 +66533 -0.234649658203125 +66534 -0.1451416015625 +66535 -0.2001953125 +66536 -0.089935302734375 +66537 -0.119171142578125 +66538 -0.02484130859375 +66539 -0.024749755859375 +66540 0.052154541015625 +66541 0.085784912109375 +66542 0.116729736328125 +66543 0.178131103515625 +66544 0.142791748046875 +66545 0.215576171875 +66546 0.139862060546875 +66547 0.211456298828125 +66548 0.114654541015625 +66549 0.17523193359375 +66550 0.082672119140625 +66551 0.128753662109375 +66552 0.06512451171875 +66553 0.1019287109375 +66554 0.047454833984375 +66555 0.0743408203125 +66556 0.027557373046875 +66557 0.04327392578125 +66558 0.0262451171875 +66559 0.038177490234375 +66560 0.05511474609375 +66561 0.076263427734375 +66562 0.10186767578125 +66563 0.14105224609375 +66564 0.13446044921875 +66565 0.186431884765625 +66566 0.13690185546875 +66567 0.188812255859375 +66568 0.103057861328125 +66569 0.1390380859375 +66570 0.036224365234375 +66571 0.041778564453125 +66572 -0.04742431640625 +66573 -0.079437255859375 +66574 -0.144195556640625 +66575 -0.219390869140625 +66576 -0.2469482421875 +66577 -0.367828369140625 +66578 -0.335235595703125 +66579 -0.494873046875 +66580 -0.37884521484375 +66581 -0.556243896484375 +66582 -0.3482666015625 +66583 -0.508697509765625 +66584 -0.259307861328125 +66585 -0.3756103515625 +66586 -0.15399169921875 +66587 -0.218902587890625 +66588 -0.04937744140625 +66589 -0.063751220703125 +66590 0.055694580078125 +66591 0.091552734375 +66592 0.153778076171875 +66593 0.23602294921875 +66594 0.22674560546875 +66595 0.342987060546875 +66596 0.262847900390625 +66597 0.39520263671875 +66598 0.259796142578125 +66599 0.389373779296875 +66600 0.2166748046875 +66601 0.324249267578125 +66602 0.149932861328125 +66603 0.224090576171875 +66604 0.083526611328125 +66605 0.124267578125 +66606 0.02569580078125 +66607 0.037078857421875 +66608 -0.004974365234375 +66609 -0.010101318359375 +66610 -0.01007080078125 +66611 -0.019439697265625 +66612 -0.01129150390625 +66613 -0.022796630859375 +66614 0.003936767578125 +66615 -0.001556396484375 +66616 0.04376220703125 +66617 0.056304931640625 +66618 0.07818603515625 +66619 0.106719970703125 +66620 0.071319580078125 +66621 0.096893310546875 +66622 0.03399658203125 +66623 0.042694091796875 +66624 -0.008026123046875 +66625 -0.018035888671875 +66626 -0.04827880859375 +66627 -0.07586669921875 +66628 -0.078948974609375 +66629 -0.11944580078125 +66630 -0.10748291015625 +66631 -0.15972900390625 +66632 -0.137786865234375 +66633 -0.202606201171875 +66634 -0.170135498046875 +66635 -0.24859619140625 +66636 -0.209564208984375 +66637 -0.30517578125 +66638 -0.249114990234375 +66639 -0.36212158203125 +66640 -0.269683837890625 +66641 -0.39141845703125 +66642 -0.24554443359375 +66643 -0.35528564453125 +66644 -0.17413330078125 +66645 -0.249969482421875 +66646 -0.0672607421875 +66647 -0.092864990234375 +66648 0.05670166015625 +66649 0.08905029296875 +66650 0.156585693359375 +66651 0.2352294921875 +66652 0.214080810546875 +66653 0.318817138671875 +66654 0.241943359375 +66655 0.358642578125 +66656 0.23541259765625 +66657 0.347747802734375 +66658 0.194091796875 +66659 0.28564453125 +66660 0.152496337890625 +66661 0.223175048828125 +66662 0.135345458984375 +66663 0.196746826171875 +66664 0.12457275390625 +66665 0.179840087890625 +66666 0.108642578125 +66667 0.155548095703125 +66668 0.106109619140625 +66669 0.151214599609375 +66670 0.1102294921875 +66671 0.156951904296875 +66672 0.0931396484375 +66673 0.13177490234375 +66674 0.0718994140625 +66675 0.100799560546875 +66676 0.062225341796875 +66677 0.087127685546875 +66678 0.039764404296875 +66679 0.05487060546875 +66680 -0.004302978515625 +66681 -0.009002685546875 +66682 -0.069610595703125 +66683 -0.10400390625 +66684 -0.155609130859375 +66685 -0.229400634765625 +66686 -0.242095947265625 +66687 -0.35552978515625 +66688 -0.301513671875 +66689 -0.441925048828125 +66690 -0.323822021484375 +66691 -0.473846435546875 +66692 -0.318145751953125 +66693 -0.464813232421875 +66694 -0.287353515625 +66695 -0.419097900390625 +66696 -0.2298583984375 +66697 -0.334320068359375 +66698 -0.157501220703125 +66699 -0.227935791015625 +66700 -0.0863037109375 +66701 -0.12347412109375 +66702 -0.0208740234375 +66703 -0.02764892578125 +66704 0.051116943359375 +66705 0.077667236328125 +66706 0.143768310546875 +66707 0.2132568359375 +66708 0.263702392578125 +66709 0.38885498046875 +66710 0.396148681640625 +66711 0.582794189453125 +66712 0.499542236328125 +66713 0.734039306640625 +66714 0.545013427734375 +66715 0.800140380859375 +66716 0.5306396484375 +66717 0.7783203125 +66718 0.454071044921875 +66719 0.6651611328125 +66720 0.314605712890625 +66721 0.45965576171875 +66722 0.13763427734375 +66723 0.199188232421875 +66724 -0.032257080078125 +66725 -0.050689697265625 +66726 -0.156280517578125 +66727 -0.23297119140625 +66728 -0.2225341796875 +66729 -0.33013916015625 +66730 -0.248809814453125 +66731 -0.368408203125 +66732 -0.25628662109375 +66733 -0.378936767578125 +66734 -0.25537109375 +66735 -0.376983642578125 +66736 -0.2576904296875 +66737 -0.37969970703125 +66738 -0.26617431640625 +66739 -0.391510009765625 +66740 -0.262420654296875 +66741 -0.385345458984375 +66742 -0.2332763671875 +66743 -0.3419189453125 +66744 -0.1934814453125 +66745 -0.28289794921875 +66746 -0.172454833984375 +66747 -0.251617431640625 +66748 -0.182464599609375 +66749 -0.266143798828125 +66750 -0.187408447265625 +66751 -0.273345947265625 +66752 -0.148895263671875 +66753 -0.216796875 +66754 -0.0885009765625 +66755 -0.128265380859375 +66756 -0.04736328125 +66757 -0.068145751953125 +66758 -0.029998779296875 +66759 -0.0430908203125 +66760 -0.0169677734375 +66761 -0.024444580078125 +66762 0.014129638671875 +66763 0.020721435546875 +66764 0.085052490234375 +66765 0.124481201171875 +66766 0.176055908203125 +66767 0.25787353515625 +66768 0.25872802734375 +66769 0.379119873046875 +66770 0.32745361328125 +66771 0.47991943359375 +66772 0.36041259765625 +66773 0.5281982421875 +66774 0.348876953125 +66775 0.511138916015625 +66776 0.3115234375 +66777 0.456207275390625 +66778 0.2783203125 +66779 0.407470703125 +66780 0.2620849609375 +66781 0.383758544921875 +66782 0.243621826171875 +66783 0.35687255859375 +66784 0.2127685546875 +66785 0.31182861328125 +66786 0.171051025390625 +66787 0.250885009765625 +66788 0.112640380859375 +66789 0.1654052734375 +66790 0.023834228515625 +66791 0.035247802734375 +66792 -0.097015380859375 +66793 -0.142059326171875 +66794 -0.2288818359375 +66795 -0.33563232421875 +66796 -0.364288330078125 +66797 -0.5345458984375 +66798 -0.491729736328125 +66799 -0.72186279296875 +66800 -0.56982421875 +66801 -0.836669921875 +66802 -0.56707763671875 +66803 -0.8326416015625 +66804 -0.4969482421875 +66805 -0.7296142578125 +66806 -0.396820068359375 +66807 -0.582550048828125 +66808 -0.299774169921875 +66809 -0.440093994140625 +66810 -0.220855712890625 +66811 -0.324310302734375 +66812 -0.137115478515625 +66813 -0.20147705078125 +66814 -0.030242919921875 +66815 -0.044647216796875 +66816 0.071624755859375 +66817 0.103973388671875 +66818 0.14056396484375 +66819 0.202392578125 +66820 0.185333251953125 +66821 0.264495849609375 +66822 0.2371826171875 +66823 0.338897705078125 +66824 0.307708740234375 +66825 0.443817138671875 +66826 0.37469482421875 +66827 0.545074462890625 +66828 0.421630859375 +66829 0.6173095703125 +66830 0.443359375 +66831 0.6524658203125 +66832 0.448272705078125 +66833 0.66339111328125 +66834 0.440460205078125 +66835 0.6561279296875 +66836 0.40460205078125 +66837 0.606781005859375 +66838 0.331756591796875 +66839 0.501190185546875 +66840 0.230865478515625 +66841 0.352783203125 +66842 0.111968994140625 +66843 0.176544189453125 +66844 -0.029388427734375 +66845 -0.034820556640625 +66846 -0.178009033203125 +66847 -0.258209228515625 +66848 -0.300537109375 +66849 -0.44244384765625 +66850 -0.388916015625 +66851 -0.5753173828125 +66852 -0.439971923828125 +66853 -0.65203857421875 +66854 -0.433563232421875 +66855 -0.641632080078125 +66856 -0.381439208984375 +66857 -0.562164306640625 +66858 -0.31243896484375 +66859 -0.458038330078125 +66860 -0.24041748046875 +66861 -0.350555419921875 +66862 -0.17901611328125 +66863 -0.260528564453125 +66864 -0.131134033203125 +66865 -0.192108154296875 +66866 -0.0948486328125 +66867 -0.141937255859375 +66868 -0.06524658203125 +66869 -0.1021728515625 +66870 -0.036102294921875 +66871 -0.062896728515625 +66872 0.000244140625 +66873 -0.011932373046875 +66874 0.051483154296875 +66875 0.062835693359375 +66876 0.1092529296875 +66877 0.148712158203125 +66878 0.170867919921875 +66879 0.241729736328125 +66880 0.240966796875 +66881 0.34912109375 +66882 0.310760498046875 +66883 0.457305908203125 +66884 0.365753173828125 +66885 0.54388427734375 +66886 0.38275146484375 +66887 0.5728759765625 +66888 0.337432861328125 +66889 0.506591796875 +66890 0.233978271484375 +66891 0.351226806640625 +66892 0.098297119140625 +66893 0.146514892578125 +66894 -0.035552978515625 +66895 -0.05523681640625 +66896 -0.142913818359375 +66897 -0.21624755859375 +66898 -0.22259521484375 +66899 -0.334930419921875 +66900 -0.269073486328125 +66901 -0.402984619140625 +66902 -0.29571533203125 +66903 -0.4412841796875 +66904 -0.332244873046875 +66905 -0.49578857421875 +66906 -0.374542236328125 +66907 -0.5601806640625 +66908 -0.400726318359375 +66909 -0.600738525390625 +66910 -0.389312744140625 +66911 -0.584228515625 +66912 -0.320037841796875 +66913 -0.47930908203125 +66914 -0.188690185546875 +66915 -0.27935791015625 +66916 -0.01129150390625 +66917 -0.0089111328125 +66918 0.1710205078125 +66919 0.268798828125 +66920 0.312164306640625 +66921 0.482818603515625 +66922 0.3929443359375 +66923 0.60369873046875 +66924 0.42547607421875 +66925 0.650421142578125 +66926 0.436248779296875 +66927 0.66400146484375 +66928 0.4232177734375 +66929 0.6414794921875 +66930 0.379669189453125 +66931 0.572540283203125 +66932 0.332061767578125 +66933 0.498138427734375 +66934 0.29412841796875 +66935 0.439453125 +66936 0.252288818359375 +66937 0.375518798828125 +66938 0.185943603515625 +66939 0.274505615234375 +66940 0.07720947265625 +66941 0.1087646484375 +66942 -0.059326171875 +66943 -0.099395751953125 +66944 -0.202972412109375 +66945 -0.3182373046875 +66946 -0.35443115234375 +66947 -0.5489501953125 +66948 -0.502105712890625 +66949 -0.7738037109375 +66950 -0.611541748046875 +66951 -0.86383056640625 +66952 -0.6611328125 +66953 -0.870391845703125 +66954 -0.662261962890625 +66955 -0.86895751953125 +66956 -0.623382568359375 +66957 -0.861053466796875 +66958 -0.533203125 +66959 -0.765869140625 +66960 -0.3843994140625 +66961 -0.5301513671875 +66962 -0.181610107421875 +66963 -0.214691162109375 +66964 0.047271728515625 +66965 0.137359619140625 +66966 0.2689208984375 +66967 0.474822998046875 +66968 0.46026611328125 +66969 0.76239013671875 +66970 0.603729248046875 +66971 0.867462158203125 +66972 0.699493408203125 +66973 0.870361328125 +66974 0.739990234375 +66975 0.86480712890625 +66976 0.728607177734375 +66977 0.831817626953125 +66978 0.6810302734375 +66979 0.677581787109375 +66980 0.6009521484375 +66981 0.495880126953125 +66982 0.500335693359375 +66983 0.30767822265625 +66984 0.380584716796875 +66985 0.116180419921875 +66986 0.221099853515625 +66987 -0.110748291015625 +66988 0.01739501953125 +66989 -0.381805419921875 +66990 -0.2027587890625 +66991 -0.6572265625 +66992 -0.4005126953125 +66993 -0.857421875 +66994 -0.548004150390625 +66995 -0.870391845703125 +66996 -0.6405029296875 +66997 -0.870391845703125 +66998 -0.695404052734375 +66999 -0.86444091796875 +67000 -0.735748291015625 +67001 -0.85723876953125 +67002 -0.749542236328125 +67003 -0.790008544921875 +67004 -0.701568603515625 +67005 -0.62847900390625 +67006 -0.589691162109375 +67007 -0.3956298828125 +67008 -0.435150146484375 +67009 -0.126708984375 +67010 -0.255645751953125 +67011 0.150115966796875 +67012 -0.058746337890625 +67013 0.424041748046875 +67014 0.138031005859375 +67015 0.670623779296875 +67016 0.309600830078125 +67017 0.854522705078125 +67018 0.4444580078125 +67019 0.866485595703125 +67020 0.5325927734375 +67021 0.86920166015625 +67022 0.585662841796875 +67023 0.8653564453125 +67024 0.612274169921875 +67025 0.857147216796875 +67026 0.6104736328125 +67027 0.766845703125 +67028 0.583526611328125 +67029 0.628509521484375 +67030 0.5269775390625 +67031 0.462127685546875 +67032 0.457489013671875 +67033 0.297210693359375 +67034 0.383026123046875 +67035 0.14862060546875 +67036 0.288787841796875 +67037 -0.00537109375 +67038 0.179656982421875 +67039 -0.15753173828125 +67040 0.05328369140625 +67041 -0.31304931640625 +67042 -0.099395751953125 +67043 -0.48876953125 +67044 -0.247955322265625 +67045 -0.6416015625 +67046 -0.376312255859375 +67047 -0.751373291015625 +67048 -0.499359130859375 +67049 -0.84619140625 +67050 -0.60748291015625 +67051 -0.861297607421875 +67052 -0.679107666015625 +67053 -0.863250732421875 +67054 -0.693756103515625 +67055 -0.856597900390625 +67056 -0.659210205078125 +67057 -0.7498779296875 +67058 -0.612884521484375 +67059 -0.624542236328125 +67060 -0.540496826171875 +67061 -0.47808837890625 +67062 -0.404144287109375 +67063 -0.253387451171875 +67064 -0.233428955078125 +67065 0.003692626953125 +67066 -0.072662353515625 +67067 0.2257080078125 +67068 0.086212158203125 +67069 0.427154541015625 +67070 0.264129638671875 +67071 0.643218994140625 +67072 0.45428466796875 +67073 0.855926513671875 +67074 0.619049072265625 +67075 0.870361328125 +67076 0.726898193359375 +67077 0.870361328125 +67078 0.78216552734375 +67079 0.862762451171875 +67080 0.783111572265625 +67081 0.79669189453125 +67082 0.72412109375 +67083 0.595794677734375 +67084 0.62347412109375 +67085 0.362152099609375 +67086 0.498809814453125 +67087 0.1270751953125 +67088 0.36358642578125 +67089 -0.086944580078125 +67090 0.2196044921875 +67091 -0.2784423828125 +67092 0.045928955078125 +67093 -0.484832763671875 +67094 -0.16876220703125 +67095 -0.729583740234375 +67096 -0.392822265625 +67097 -0.86688232421875 +67098 -0.5867919921875 +67099 -0.870391845703125 +67100 -0.747222900390625 +67101 -0.86859130859375 +67102 -0.856475830078125 +67103 -0.86279296875 +67104 -0.863861083984375 +67105 -0.817962646484375 +67106 -0.8619384765625 +67107 -0.6116943359375 +67108 -0.81488037109375 +67109 -0.3128662109375 +67110 -0.63812255859375 +67111 0.039398193359375 +67112 -0.404876708984375 +67113 0.422821044921875 +67114 -0.135955810546875 +67115 0.805145263671875 +67116 0.126312255859375 +67117 0.870361328125 +67118 0.346343994140625 +67119 0.870361328125 +67120 0.516387939453125 +67121 0.860015869140625 +67122 0.631195068359375 +67123 0.727935791015625 +67124 0.68682861328125 +67125 0.48114013671875 +67126 0.69769287109375 +67127 0.2059326171875 +67128 0.677337646484375 +67129 -0.06103515625 +67130 0.631622314453125 +67131 -0.29913330078125 +67132 0.55145263671875 +67133 -0.516204833984375 +67134 0.42730712890625 +67135 -0.7252197265625 +67136 0.274658203125 +67137 -0.85980224609375 +67138 0.114898681640625 +67139 -0.870391845703125 +67140 -0.0333251953125 +67141 -0.870391845703125 +67142 -0.139495849609375 +67143 -0.858062744140625 +67144 -0.200408935546875 +67145 -0.673004150390625 +67146 -0.24774169921875 +67147 -0.42694091796875 +67148 -0.308197021484375 +67149 -0.2100830078125 +67150 -0.37982177734375 +67151 -0.0362548828125 +67152 -0.44415283203125 +67153 0.10943603515625 +67154 -0.4884033203125 +67155 0.23516845703125 +67156 -0.48675537109375 +67157 0.373687744140625 +67158 -0.440185546875 +67159 0.517791748046875 +67160 -0.38739013671875 +67161 0.602783203125 +67162 -0.325286865234375 +67163 0.635711669921875 +67164 -0.233551025390625 +67165 0.655181884765625 +67166 -0.11871337890625 +67167 0.65948486328125 +67168 0.0137939453125 +67169 0.651275634765625 +67170 0.148284912109375 +67171 0.61846923828125 +67172 0.261322021484375 +67173 0.53753662109375 +67174 0.3411865234375 +67175 0.404144287109375 +67176 0.3812255859375 +67177 0.22186279296875 +67178 0.38165283203125 +67179 0.003997802734375 +67180 0.3531494140625 +67181 -0.22100830078125 +67182 0.308013916015625 +67183 -0.42449951171875 +67184 0.259185791015625 +67185 -0.579833984375 +67186 0.232879638671875 +67187 -0.641876220703125 +67188 0.225006103515625 +67189 -0.6177978515625 +67190 0.195953369140625 +67191 -0.575531005859375 +67192 0.142730712890625 +67193 -0.526336669921875 +67194 0.09765625 +67195 -0.42645263671875 +67196 0.078094482421875 +67197 -0.2581787109375 +67198 0.06219482421875 +67199 -0.068695068359375 +67200 0.02679443359375 +67201 0.09222412109375 +67202 -0.0159912109375 +67203 0.232147216796875 +67204 -0.05938720703125 +67205 0.3509521484375 +67206 -0.12115478515625 +67207 0.410064697265625 +67208 -0.218963623046875 +67209 0.372955322265625 +67210 -0.339599609375 +67211 0.2554931640625 +67212 -0.450775146484375 +67213 0.10711669921875 +67214 -0.54034423828125 +67215 -0.052886962890625 +67216 -0.586090087890625 +67217 -0.186279296875 +67218 -0.553741455078125 +67219 -0.23291015625 +67220 -0.45758056640625 +67221 -0.209442138671875 +67222 -0.33856201171875 +67223 -0.174163818359375 +67224 -0.202239990234375 +67225 -0.126739501953125 +67226 -0.042999267578125 +67227 -0.048126220703125 +67228 0.121246337890625 +67229 0.0426025390625 +67230 0.261260986328125 +67231 0.10748291015625 +67232 0.368438720703125 +67233 0.1409912109375 +67234 0.4716796875 +67235 0.19708251953125 +67236 0.56646728515625 +67237 0.273651123046875 +67238 0.6181640625 +67239 0.31768798828125 +67240 0.633392333984375 +67241 0.341094970703125 +67242 0.627685546875 +67243 0.368011474609375 +67244 0.586944580078125 +67245 0.37249755859375 +67246 0.48095703125 +67247 0.30072021484375 +67248 0.31304931640625 +67249 0.1517333984375 +67250 0.124603271484375 +67251 -0.01470947265625 +67252 -0.073089599609375 +67253 -0.1883544921875 +67254 -0.277099609375 +67255 -0.372711181640625 +67256 -0.449371337890625 +67257 -0.51397705078125 +67258 -0.560516357421875 +67259 -0.57177734375 +67260 -0.602630615234375 +67261 -0.53948974609375 +67262 -0.58380126953125 +67263 -0.43511962890625 +67264 -0.52520751953125 +67265 -0.2962646484375 +67266 -0.44940185546875 +67267 -0.161102294921875 +67268 -0.365142822265625 +67269 -0.0435791015625 +67270 -0.2711181640625 +67271 0.060394287109375 +67272 -0.178192138671875 +67273 0.13665771484375 +67274 -0.098602294921875 +67275 0.170135498046875 +67276 -0.03302001953125 +67277 0.16552734375 +67278 0.03570556640625 +67279 0.15728759765625 +67280 0.106719970703125 +67281 0.150787353515625 +67282 0.161102294921875 +67283 0.12200927734375 +67284 0.200653076171875 +67285 0.080108642578125 +67286 0.238128662109375 +67287 0.05126953125 +67288 0.2877197265625 +67289 0.062896728515625 +67290 0.333709716796875 +67291 0.09271240234375 +67292 0.34564208984375 +67293 0.092987060546875 +67294 0.33245849609375 +67295 0.07855224609375 +67296 0.303985595703125 +67297 0.06427001953125 +67298 0.252288818359375 +67299 0.0347900390625 +67300 0.178436279296875 +67301 -0.01171875 +67302 0.09710693359375 +67303 -0.056060791015625 +67304 0.037811279296875 +67305 -0.055511474609375 +67306 0.003692626953125 +67307 -0.010467529296875 +67308 -0.035003662109375 +67309 0.02508544921875 +67310 -0.0906982421875 +67311 0.025665283203125 +67312 -0.1444091796875 +67313 0.017333984375 +67314 -0.192626953125 +67315 0.00189208984375 +67316 -0.2403564453125 +67317 -0.03173828125 +67318 -0.279052734375 +67319 -0.071502685546875 +67320 -0.31939697265625 +67321 -0.13543701171875 +67322 -0.359527587890625 +67323 -0.219970703125 +67324 -0.38531494140625 +67325 -0.300506591796875 +67326 -0.397918701171875 +67327 -0.376312255859375 +67328 -0.380340576171875 +67329 -0.416107177734375 +67330 -0.30523681640625 +67331 -0.371124267578125 +67332 -0.1759033203125 +67333 -0.242279052734375 +67334 -0.0196533203125 +67335 -0.069732666015625 +67336 0.147857666015625 +67337 0.125640869140625 +67338 0.30511474609375 +67339 0.31268310546875 +67340 0.427886962890625 +67341 0.45501708984375 +67342 0.515533447265625 +67343 0.554779052734375 +67344 0.566009521484375 +67345 0.61065673828125 +67346 0.5716552734375 +67347 0.610931396484375 +67348 0.51800537109375 +67349 0.531463623046875 +67350 0.41534423828125 +67351 0.3883056640625 +67352 0.296844482421875 +67353 0.23468017578125 +67354 0.1790771484375 +67355 0.095245361328125 +67356 0.0797119140625 +67357 -0.00396728515625 +67358 0.009735107421875 +67359 -0.04852294921875 +67360 -0.03839111328125 +67361 -0.055145263671875 +67362 -0.093414306640625 +67363 -0.0758056640625 +67364 -0.169952392578125 +67365 -0.138702392578125 +67366 -0.245208740234375 +67367 -0.209197998046875 +67368 -0.318572998046875 +67369 -0.289031982421875 +67370 -0.389251708984375 +67371 -0.37884521484375 +67372 -0.44317626953125 +67373 -0.456329345703125 +67374 -0.477203369140625 +67375 -0.51641845703125 +67376 -0.467803955078125 +67377 -0.519287109375 +67378 -0.411865234375 +67379 -0.458251953125 +67380 -0.341552734375 +67381 -0.384796142578125 +67382 -0.27337646484375 +67383 -0.323699951171875 +67384 -0.20574951171875 +67385 -0.269287109375 +67386 -0.124908447265625 +67387 -0.1951904296875 +67388 -0.032012939453125 +67389 -0.100006103515625 +67390 0.05487060546875 +67391 -0.01055908203125 +67392 0.15216064453125 +67393 0.1033935546875 +67394 0.26275634765625 +67395 0.24908447265625 +67396 0.35357666015625 +67397 0.373199462890625 +67398 0.413299560546875 +67399 0.45806884765625 +67400 0.446319580078125 +67401 0.511474609375 +67402 0.4720458984375 +67403 0.565399169921875 +67404 0.4859619140625 +67405 0.61138916015625 +67406 0.45318603515625 +67407 0.5897216796875 +67408 0.369110107421875 +67409 0.4906005859375 +67410 0.24566650390625 +67411 0.33148193359375 +67412 0.105712890625 +67413 0.147796630859375 +67414 -0.024017333984375 +67415 -0.01873779296875 +67416 -0.12518310546875 +67417 -0.140289306640625 +67418 -0.181365966796875 +67419 -0.191986083984375 +67420 -0.19757080078125 +67421 -0.184295654296875 +67422 -0.1995849609375 +67423 -0.161834716796875 +67424 -0.211883544921875 +67425 -0.166595458984375 +67426 -0.2313232421875 +67427 -0.19390869140625 +67428 -0.246307373046875 +67429 -0.22442626953125 +67430 -0.2701416015625 +67431 -0.279754638671875 +67432 -0.290985107421875 +67433 -0.3389892578125 +67434 -0.281158447265625 +67435 -0.3543701171875 +67436 -0.25518798828125 +67437 -0.348175048828125 +67438 -0.21771240234375 +67439 -0.32598876953125 +67440 -0.15234375 +67441 -0.2581787109375 +67442 -0.057464599609375 +67443 -0.139801025390625 +67444 0.056915283203125 +67445 0.014617919921875 +67446 0.153228759765625 +67447 0.144378662109375 +67448 0.2135009765625 +67449 0.221038818359375 +67450 0.25274658203125 +67451 0.27069091796875 +67452 0.271026611328125 +67453 0.294036865234375 +67454 0.2806396484375 +67455 0.311767578125 +67456 0.290924072265625 +67457 0.339141845703125 +67458 0.292633056640625 +67459 0.360260009765625 +67460 0.27777099609375 +67461 0.360504150390625 +67462 0.22894287109375 +67463 0.308380126953125 +67464 0.13433837890625 +67465 0.18170166015625 +67466 0.0093994140625 +67467 0.0047607421875 +67468 -0.117279052734375 +67469 -0.17559814453125 +67470 -0.218231201171875 +67471 -0.3143310546875 +67472 -0.26690673828125 +67473 -0.36785888671875 +67474 -0.277801513671875 +67475 -0.36248779296875 +67476 -0.2767333984375 +67477 -0.343536376953125 +67478 -0.2579345703125 +67479 -0.3018798828125 +67480 -0.2176513671875 +67481 -0.231414794921875 +67482 -0.14752197265625 +67483 -0.117645263671875 +67484 -0.066802978515625 +67485 0.007049560546875 +67486 -0.007965087890625 +67487 0.087982177734375 +67488 0.036590576171875 +67489 0.13946533203125 +67490 0.073455810546875 +67491 0.17425537109375 +67492 0.0992431640625 +67493 0.188201904296875 +67494 0.1070556640625 +67495 0.171234130859375 +67496 0.093048095703125 +67497 0.118438720703125 +67498 0.072265625 +67499 0.05706787109375 +67500 0.045135498046875 +67501 -0.010711669921875 +67502 0.007293701171875 +67503 -0.0914306640625 +67504 -0.02838134765625 +67505 -0.162322998046875 +67506 -0.045257568359375 +67507 -0.194549560546875 +67508 -0.020660400390625 +67509 -0.1492919921875 +67510 0.048431396484375 +67511 -0.02166748046875 +67512 0.124908447265625 +67513 0.124053955078125 +67514 0.164520263671875 +67515 0.211151123046875 +67516 0.16845703125 +67517 0.240447998046875 +67518 0.1551513671875 +67519 0.242218017578125 +67520 0.130859375 +67521 0.2257080078125 +67522 0.098388671875 +67523 0.194366455078125 +67524 0.039398193359375 +67525 0.115509033203125 +67526 -0.031585693359375 +67527 0.0128173828125 +67528 -0.079010009765625 +67529 -0.053802490234375 +67530 -0.11785888671875 +67531 -0.110626220703125 +67532 -0.172332763671875 +67533 -0.199493408203125 +67534 -0.227203369140625 +67535 -0.29437255859375 +67536 -0.245758056640625 +67537 -0.33221435546875 +67538 -0.208831787109375 +67539 -0.27972412109375 +67540 -0.1451416015625 +67541 -0.185333251953125 +67542 -0.1014404296875 +67543 -0.128204345703125 +67544 -0.08258056640625 +67545 -0.115692138671875 +67546 -0.07098388671875 +67547 -0.116455078125 +67548 -0.052978515625 +67549 -0.105926513671875 +67550 -0.0115966796875 +67551 -0.053955078125 +67552 0.05804443359375 +67553 0.048797607421875 +67554 0.129180908203125 +67555 0.157318115234375 +67556 0.166656494140625 +67557 0.212005615234375 +67558 0.1734619140625 +67559 0.218475341796875 +67560 0.184844970703125 +67561 0.23724365234375 +67562 0.2225341796875 +67563 0.30535888671875 +67564 0.262420654296875 +67565 0.38128662109375 +67566 0.269439697265625 +67567 0.404449462890625 +67568 0.25543212890625 +67569 0.3944091796875 +67570 0.242706298828125 +67571 0.3885498046875 +67572 0.21771240234375 +67573 0.362640380859375 +67574 0.15582275390625 +67575 0.27362060546875 +67576 0.055023193359375 +67577 0.11712646484375 +67578 -0.0538330078125 +67579 -0.054901123046875 +67580 -0.140167236328125 +67581 -0.19085693359375 +67582 -0.200714111328125 +67583 -0.28570556640625 +67584 -0.235748291015625 +67585 -0.339263916015625 +67586 -0.26007080078125 +67587 -0.3775634765625 +67588 -0.298583984375 +67589 -0.445709228515625 +67590 -0.346282958984375 +67591 -0.535064697265625 +67592 -0.39398193359375 +67593 -0.629058837890625 +67594 -0.425201416015625 +67595 -0.697601318359375 +67596 -0.41998291015625 +67597 -0.70391845703125 +67598 -0.375732421875 +67599 -0.6424560546875 +67600 -0.280914306640625 +67601 -0.491241455078125 +67602 -0.144683837890625 +67603 -0.265716552734375 +67604 0.0003662109375 +67605 -0.023712158203125 +67606 0.135345458984375 +67607 0.201751708984375 +67608 0.240447998046875 +67609 0.375823974609375 +67610 0.30780029296875 +67611 0.485076904296875 +67612 0.3587646484375 +67613 0.56884765625 +67614 0.3973388671875 +67615 0.634765625 +67616 0.398529052734375 +67617 0.63763427734375 +67618 0.3560791015625 +67619 0.5660400390625 +67620 0.298980712890625 +67621 0.4720458984375 +67622 0.255859375 +67623 0.40692138671875 +67624 0.231109619140625 +67625 0.3778076171875 +67626 0.220977783203125 +67627 0.376953125 +67628 0.2081298828125 +67629 0.371978759765625 +67630 0.165679931640625 +67631 0.313140869140625 +67632 0.0853271484375 +67633 0.184417724609375 +67634 -0.018402099609375 +67635 0.011199951171875 +67636 -0.125518798828125 +67637 -0.171051025390625 +67638 -0.221954345703125 +67639 -0.33740234375 +67640 -0.298736572265625 +67641 -0.47198486328125 +67642 -0.347869873046875 +67643 -0.560394287109375 +67644 -0.35723876953125 +67645 -0.58056640625 +67646 -0.335296630859375 +67647 -0.54754638671875 +67648 -0.308380126953125 +67649 -0.508575439453125 +67650 -0.2745361328125 +67651 -0.459503173828125 +67652 -0.23089599609375 +67653 -0.394378662109375 +67654 -0.199615478515625 +67655 -0.35260009765625 +67656 -0.16876220703125 +67657 -0.31170654296875 +67658 -0.097808837890625 +67659 -0.197418212890625 +67660 0.013824462890625 +67661 -0.007965087890625 +67662 0.13861083984375 +67663 0.207489013671875 +67664 0.254302978515625 +67665 0.409210205078125 +67666 0.34686279296875 +67667 0.57208251953125 +67668 0.3995361328125 +67669 0.66595458984375 +67670 0.3946533203125 +67671 0.65875244140625 +67672 0.3416748046875 +67673 0.56744384765625 +67674 0.26251220703125 +67675 0.431396484375 +67676 0.181640625 +67677 0.29443359375 +67678 0.113677978515625 +67679 0.182464599609375 +67680 0.041412353515625 +67681 0.06365966796875 +67682 -0.04248046875 +67683 -0.075958251953125 +67684 -0.1116943359375 +67685 -0.189422607421875 +67686 -0.1632080078125 +67687 -0.271942138671875 +67688 -0.20721435546875 +67689 -0.342529296875 +67690 -0.223052978515625 +67691 -0.364166259765625 +67692 -0.205291748046875 +67693 -0.327239990234375 +67694 -0.178741455078125 +67695 -0.2769775390625 +67696 -0.1656494140625 +67697 -0.253692626953125 +67698 -0.158447265625 +67699 -0.24365234375 +67700 -0.130523681640625 +67701 -0.1983642578125 +67702 -0.0811767578125 +67703 -0.116241455078125 +67704 -0.032501220703125 +67705 -0.036834716796875 +67706 0.012451171875 +67707 0.034881591796875 +67708 0.04913330078125 +67709 0.09124755859375 +67710 0.064361572265625 +67711 0.10888671875 +67712 0.078643798828125 +67713 0.125518798828125 +67714 0.100860595703125 +67715 0.15771484375 +67716 0.11578369140625 +67717 0.17828369140625 +67718 0.11431884765625 +67719 0.17108154296875 +67720 0.092987060546875 +67721 0.129974365234375 +67722 0.06689453125 +67723 0.082427978515625 +67724 0.03564453125 +67725 0.027679443359375 +67726 -0.0179443359375 +67727 -0.065643310546875 +67728 -0.072662353515625 +67729 -0.15936279296875 +67730 -0.106048583984375 +67731 -0.21307373046875 +67732 -0.122222900390625 +67733 -0.234649658203125 +67734 -0.10772705078125 +67735 -0.2001953125 +67736 -0.067535400390625 +67737 -0.119171142578125 +67738 -0.01971435546875 +67739 -0.024749755859375 +67740 0.037445068359375 +67741 0.085784912109375 +67742 0.085205078125 +67743 0.178131103515625 +67744 0.103485107421875 +67745 0.215576171875 +67746 0.0997314453125 +67747 0.211456298828125 +67748 0.0792236328125 +67749 0.17523193359375 +67750 0.05401611328125 +67751 0.128753662109375 +67752 0.04058837890625 +67753 0.1019287109375 +67754 0.027557373046875 +67755 0.0743408203125 +67756 0.013275146484375 +67757 0.04327392578125 +67758 0.013824462890625 +67759 0.038177490234375 +67760 0.03851318359375 +67761 0.076263427734375 +67762 0.0780029296875 +67763 0.14105224609375 +67764 0.106658935546875 +67765 0.186431884765625 +67766 0.11126708984375 +67767 0.188812255859375 +67768 0.08660888671875 +67769 0.1390380859375 +67770 0.035125732421875 +67771 0.041778564453125 +67772 -0.030303955078125 +67773 -0.079437255859375 +67774 -0.106842041015625 +67775 -0.219390869140625 +67776 -0.188812255859375 +67777 -0.367828369140625 +67778 -0.25970458984375 +67779 -0.494873046875 +67780 -0.2950439453125 +67781 -0.556243896484375 +67782 -0.2708740234375 +67783 -0.508697509765625 +67784 -0.199951171875 +67785 -0.3756103515625 +67786 -0.116302490234375 +67787 -0.218902587890625 +67788 -0.033660888671875 +67789 -0.063751220703125 +67790 0.049041748046875 +67791 0.091552734375 +67792 0.12591552734375 +67793 0.23602294921875 +67794 0.182373046875 +67795 0.342987060546875 +67796 0.20904541015625 +67797 0.39520263671875 +67798 0.204254150390625 +67799 0.389373779296875 +67800 0.167388916015625 +67801 0.324249267578125 +67802 0.111846923828125 +67803 0.224090576171875 +67804 0.057159423828125 +67805 0.124267578125 +67806 0.01007080078125 +67807 0.037078857421875 +67808 -0.014373779296875 +67809 -0.010101318359375 +67810 -0.017486572265625 +67811 -0.019439697265625 +67812 -0.0169677734375 +67813 -0.022796630859375 +67814 -0.002685546875 +67815 -0.001556396484375 +67816 0.031829833984375 +67817 0.056304931640625 +67818 0.062103271484375 +67819 0.106719970703125 +67820 0.058868408203125 +67821 0.096893310546875 +67822 0.030792236328125 +67823 0.042694091796875 +67824 -0.0013427734375 +67825 -0.018035888671875 +67826 -0.0323486328125 +67827 -0.07586669921875 +67828 -0.055999755859375 +67829 -0.11944580078125 +67830 -0.078369140625 +67831 -0.15972900390625 +67832 -0.102691650390625 +67833 -0.202606201171875 +67834 -0.129180908203125 +67835 -0.24859619140625 +67836 -0.161895751953125 +67837 -0.30517578125 +67838 -0.195098876953125 +67839 -0.36212158203125 +67840 -0.21337890625 +67841 -0.39141845703125 +67842 -0.19586181640625 +67843 -0.35528564453125 +67844 -0.14031982421875 +67845 -0.249969482421875 +67846 -0.056396484375 +67847 -0.092864990234375 +67848 0.04132080078125 +67849 0.08905029296875 +67850 0.120880126953125 +67851 0.2352294921875 +67852 0.16790771484375 +67853 0.318817138671875 +67854 0.191864013671875 +67855 0.358642578125 +67856 0.18890380859375 +67857 0.347747802734375 +67858 0.158599853515625 +67859 0.28564453125 +67860 0.12725830078125 +67861 0.223175048828125 +67862 0.113800048828125 +67863 0.196746826171875 +67864 0.1044921875 +67865 0.179840087890625 +67866 0.09063720703125 +67867 0.155548095703125 +67868 0.0865478515625 +67869 0.151214599609375 +67870 0.087249755859375 +67871 0.156951904296875 +67872 0.071563720703125 +67873 0.13177490234375 +67874 0.052734375 +67875 0.100799560546875 +67876 0.042938232421875 +67877 0.087127685546875 +67878 0.023681640625 +67879 0.05487060546875 +67880 -0.011688232421875 +67881 -0.009002685546875 +67882 -0.062744140625 +67883 -0.10400390625 +67884 -0.12908935546875 +67885 -0.229400634765625 +67886 -0.195220947265625 +67887 -0.35552978515625 +67888 -0.240081787109375 +67889 -0.441925048828125 +67890 -0.25604248046875 +67891 -0.473846435546875 +67892 -0.250152587890625 +67893 -0.464813232421875 +67894 -0.2247314453125 +67895 -0.419097900390625 +67896 -0.17864990234375 +67897 -0.334320068359375 +67898 -0.12109375 +67899 -0.227935791015625 +67900 -0.064422607421875 +67901 -0.12347412109375 +67902 -0.01226806640625 +67903 -0.02764892578125 +67904 0.044647216796875 +67905 0.077667236328125 +67906 0.11700439453125 +67907 0.2132568359375 +67908 0.20977783203125 +67909 0.38885498046875 +67910 0.311614990234375 +67911 0.582794189453125 +67912 0.3907470703125 +67913 0.734039306640625 +67914 0.425079345703125 +67915 0.800140380859375 +67916 0.413177490234375 +67917 0.7783203125 +67918 0.353363037109375 +67919 0.6651611328125 +67920 0.245147705078125 +67921 0.45965576171875 +67922 0.10809326171875 +67923 0.199188232421875 +67924 -0.023651123046875 +67925 -0.050689697265625 +67926 -0.120330810546875 +67927 -0.23297119140625 +67928 -0.1727294921875 +67929 -0.33013916015625 +67930 -0.19439697265625 +67931 -0.368408203125 +67932 -0.201416015625 +67933 -0.378936767578125 +67934 -0.20166015625 +67935 -0.376983642578125 +67936 -0.2039794921875 +67937 -0.37969970703125 +67938 -0.21063232421875 +67939 -0.391510009765625 +67940 -0.207550048828125 +67941 -0.385345458984375 +67942 -0.184661865234375 +67943 -0.3419189453125 +67944 -0.153289794921875 +67945 -0.28289794921875 +67946 -0.136016845703125 +67947 -0.251617431640625 +67948 -0.142303466796875 +67949 -0.266143798828125 +67950 -0.14459228515625 +67951 -0.273345947265625 +67952 -0.113616943359375 +67953 -0.216796875 +67954 -0.06597900390625 +67955 -0.128265380859375 +67956 -0.033172607421875 +67957 -0.068145751953125 +67958 -0.018707275390625 +67959 -0.0430908203125 +67960 -0.007781982421875 +67961 -0.024444580078125 +67962 0.016632080078125 +67963 0.020721435546875 +67964 0.071136474609375 +67965 0.124481201171875 +67966 0.140655517578125 +67967 0.25787353515625 +67968 0.2034912109375 +67969 0.379119873046875 +67970 0.25537109375 +67971 0.47991943359375 +67972 0.2796630859375 +67973 0.5281982421875 +67974 0.26971435546875 +67975 0.511138916015625 +67976 0.239898681640625 +67977 0.456207275390625 +67978 0.21319580078125 +67979 0.407470703125 +67980 0.199493408203125 +67981 0.383758544921875 +67982 0.184173583984375 +67983 0.35687255859375 +67984 0.159515380859375 +67985 0.31182861328125 +67986 0.126739501953125 +67987 0.250885009765625 +67988 0.0814208984375 +67989 0.1654052734375 +67990 0.013153076171875 +67991 0.035247802734375 +67992 -0.079315185546875 +67993 -0.142059326171875 +67994 -0.179931640625 +67995 -0.33563232421875 +67996 -0.28302001953125 +67997 -0.5345458984375 +67998 -0.3797607421875 +67999 -0.72186279296875 +68000 -0.43853759765625 +68001 -0.836669921875 +68002 -0.435333251953125 +68003 -0.8326416015625 +68004 -0.38055419921875 +68005 -0.7296142578125 +68006 -0.302825927734375 +68007 -0.582550048828125 +68008 -0.2275390625 +68009 -0.440093994140625 +68010 -0.166229248046875 +68011 -0.324310302734375 +68012 -0.101409912109375 +68013 -0.20147705078125 +68014 -0.01910400390625 +68015 -0.044647216796875 +68016 0.0587158203125 +68017 0.103973388671875 +68018 0.11016845703125 +68019 0.202392578125 +68020 0.1424560546875 +68021 0.264495849609375 +68022 0.180877685546875 +68023 0.338897705078125 +68024 0.23492431640625 +68025 0.443817138671875 +68026 0.286865234375 +68027 0.545074462890625 +68028 0.32354736328125 +68029 0.6173095703125 +68030 0.3408203125 +68031 0.6524658203125 +68032 0.345428466796875 +68033 0.66339111328125 +68034 0.340576171875 +68035 0.6561279296875 +68036 0.31390380859375 +68037 0.606781005859375 +68038 0.25811767578125 +68039 0.501190185546875 +68040 0.18023681640625 +68041 0.352783203125 +68042 0.08807373046875 +68043 0.176544189453125 +68044 -0.0220947265625 +68045 -0.034820556640625 +68046 -0.138275146484375 +68047 -0.258209228515625 +68048 -0.233856201171875 +68049 -0.44244384765625 +68050 -0.302490234375 +68051 -0.5753173828125 +68052 -0.34173583984375 +68053 -0.65203857421875 +68054 -0.335540771484375 +68055 -0.641632080078125 +68056 -0.2933349609375 +68057 -0.562164306640625 +68058 -0.23828125 +68059 -0.458038330078125 +68060 -0.181488037109375 +68061 -0.350555419921875 +68062 -0.133819580078125 +68063 -0.260528564453125 +68064 -0.097503662109375 +68065 -0.192108154296875 +68066 -0.070831298828125 +68067 -0.141937255859375 +68068 -0.04974365234375 +68069 -0.1021728515625 +68070 -0.029083251953125 +68071 -0.062896728515625 +68072 -0.002532958984375 +68073 -0.011932373046875 +68074 0.03619384765625 +68075 0.062835693359375 +68076 0.080535888671875 +68077 0.148712158203125 +68078 0.12841796875 +68079 0.241729736328125 +68080 0.18365478515625 +68081 0.34912109375 +68082 0.239227294921875 +68083 0.457305908203125 +68084 0.28350830078125 +68085 0.54388427734375 +68086 0.297821044921875 +68087 0.5728759765625 +68088 0.262603759765625 +68089 0.506591796875 +68090 0.18115234375 +68091 0.351226806640625 +68092 0.074127197265625 +68093 0.146514892578125 +68094 -0.031219482421875 +68095 -0.05523681640625 +68096 -0.114898681640625 +68097 -0.21624755859375 +68098 -0.17626953125 +68099 -0.334930419921875 +68100 -0.211883544921875 +68101 -0.402984619140625 +68102 -0.231842041015625 +68103 -0.4412841796875 +68104 -0.258575439453125 +68105 -0.49578857421875 +68106 -0.2890625 +68107 -0.5601806640625 +68108 -0.306976318359375 +68109 -0.600738525390625 +68110 -0.296234130859375 +68111 -0.584228515625 +68112 -0.24176025390625 +68113 -0.47930908203125 +68114 -0.14056396484375 +68115 -0.27935791015625 +68116 -0.00482177734375 +68117 -0.0089111328125 +68118 0.134368896484375 +68119 0.268798828125 +68120 0.2421875 +68121 0.482818603515625 +68122 0.304107666015625 +68123 0.60369873046875 +68124 0.3292236328125 +68125 0.650421142578125 +68126 0.337432861328125 +68127 0.66400146484375 +68128 0.32720947265625 +68129 0.6414794921875 +68130 0.293548583984375 +68131 0.572540283203125 +68132 0.256439208984375 +68133 0.498138427734375 +68134 0.226287841796875 +68135 0.439453125 +68136 0.192962646484375 +68137 0.375518798828125 +68138 0.14105224609375 +68139 0.274505615234375 +68140 0.0572509765625 +68141 0.1087646484375 +68142 -0.047393798828125 +68143 -0.099395751953125 +68144 -0.157196044921875 +68145 -0.3182373046875 +68146 -0.2725830078125 +68147 -0.5489501953125 +68148 -0.384735107421875 +68149 -0.7738037109375 +68150 -0.46771240234375 +68151 -0.86383056640625 +68152 -0.50518798828125 +68153 -0.870391845703125 +68154 -0.5057373046875 +68155 -0.86895751953125 +68156 -0.47576904296875 +68157 -0.861053466796875 +68158 -0.406829833984375 +68159 -0.765869140625 +68160 -0.293487548828125 +68161 -0.5301513671875 +68162 -0.1392822265625 +68163 -0.214691162109375 +68164 0.034637451171875 +68165 0.137359619140625 +68166 0.203125 +68167 0.474822998046875 +68168 0.34869384765625 +68169 0.76239013671875 +68170 0.458038330078125 +68171 0.867462158203125 +68172 0.53125 +68173 0.870361328125 +68174 0.56256103515625 +68175 0.86480712890625 +68176 0.554473876953125 +68177 0.831817626953125 +68178 0.518798828125 +68179 0.677581787109375 +68180 0.458343505859375 +68181 0.495880126953125 +68182 0.382110595703125 +68183 0.30767822265625 +68184 0.29119873046875 +68185 0.116180419921875 +68186 0.170135498046875 +68187 -0.110748291015625 +68188 0.015594482421875 +68189 -0.381805419921875 +68190 -0.15142822265625 +68191 -0.6572265625 +68192 -0.301605224609375 +68193 -0.857421875 +68194 -0.41387939453125 +68195 -0.870391845703125 +68196 -0.484649658203125 +68197 -0.870391845703125 +68198 -0.526947021484375 +68199 -0.86444091796875 +68200 -0.55804443359375 +68201 -0.85723876953125 +68202 -0.568878173828125 +68203 -0.790008544921875 +68204 -0.532928466796875 +68205 -0.62847900390625 +68206 -0.448577880859375 +68207 -0.3956298828125 +68208 -0.33184814453125 +68209 -0.126708984375 +68210 -0.19610595703125 +68211 0.150115966796875 +68212 -0.047088623046875 +68213 0.424041748046875 +68214 0.10198974609375 +68215 0.670623779296875 +68216 0.232147216796875 +68217 0.854522705078125 +68218 0.33465576171875 +68219 0.866485595703125 +68220 0.401947021484375 +68221 0.86920166015625 +68222 0.4427490234375 +68223 0.8653564453125 +68224 0.463531494140625 +68225 0.857147216796875 +68226 0.4627685546875 +68227 0.766845703125 +68228 0.442901611328125 +68229 0.628509521484375 +68230 0.400543212890625 +68231 0.462127685546875 +68232 0.348236083984375 +68233 0.297210693359375 +68234 0.2919921875 +68235 0.14862060546875 +68236 0.220672607421875 +68237 -0.00537109375 +68238 0.137939453125 +68239 -0.15753173828125 +68240 0.042083740234375 +68241 -0.31304931640625 +68242 -0.07366943359375 +68243 -0.48876953125 +68244 -0.18634033203125 +68245 -0.6416015625 +68246 -0.2838134765625 +68247 -0.751373291015625 +68248 -0.377227783203125 +68249 -0.84619140625 +68250 -0.459320068359375 +68251 -0.861297607421875 +68252 -0.513824462890625 +68253 -0.863250732421875 +68254 -0.525238037109375 +68255 -0.856597900390625 +68256 -0.499420166015625 +68257 -0.7498779296875 +68258 -0.464569091796875 +68259 -0.624542236328125 +68260 -0.409942626953125 +68261 -0.47808837890625 +68262 -0.3070068359375 +68263 -0.253387451171875 +68264 -0.17803955078125 +68265 0.003692626953125 +68266 -0.05645751953125 +68267 0.2257080078125 +68268 0.06378173828125 +68269 0.427154541015625 +68270 0.19842529296875 +68271 0.643218994140625 +68272 0.3426513671875 +68273 0.855926513671875 +68274 0.46807861328125 +68275 0.870361328125 +68276 0.5504150390625 +68277 0.870361328125 +68278 0.593048095703125 +68279 0.862762451171875 +68280 0.594512939453125 +68281 0.79669189453125 +68282 0.55010986328125 +68283 0.595794677734375 +68284 0.474029541015625 +68285 0.362152099609375 +68286 0.379974365234375 +68287 0.1270751953125 +68288 0.27825927734375 +68289 -0.086944580078125 +68290 0.169952392578125 +68291 -0.2784423828125 +68292 0.03814697265625 +68293 -0.484832763671875 +68294 -0.12646484375 +68295 -0.729583740234375 +68296 -0.299102783203125 +68297 -0.86688232421875 +68298 -0.44873046875 +68299 -0.870391845703125 +68300 -0.572845458984375 +68301 -0.86859130859375 +68302 -0.6702880859375 +68303 -0.86279296875 +68304 -0.723419189453125 +68305 -0.817962646484375 +68306 -0.7099609375 +68307 -0.6116943359375 +68308 -0.62640380859375 +68309 -0.3128662109375 +68310 -0.4891357421875 +68311 0.039398193359375 +68312 -0.30792236328125 +68313 0.422821044921875 +68314 -0.099029541015625 +68315 0.805145263671875 +68316 0.104217529296875 +68317 0.870361328125 +68318 0.273895263671875 +68319 0.870361328125 +68320 0.404144287109375 +68321 0.860015869140625 +68322 0.49102783203125 +68323 0.727935791015625 +68324 0.5316162109375 +68325 0.48114013671875 +68326 0.53753662109375 +68327 0.2059326171875 +68328 0.519622802734375 +68329 -0.06103515625 +68330 0.48260498046875 +68331 -0.29913330078125 +68332 0.4193115234375 +68333 -0.516204833984375 +68334 0.3221435546875 +68335 -0.7252197265625 +68336 0.2032470703125 +68337 -0.85980224609375 +68338 0.079437255859375 +68339 -0.870391845703125 +68340 -0.03466796875 +68341 -0.870391845703125 +68342 -0.115081787109375 +68343 -0.858062744140625 +68344 -0.159515380859375 +68345 -0.673004150390625 +68346 -0.193267822265625 +68347 -0.42694091796875 +68348 -0.2376708984375 +68349 -0.2100830078125 +68350 -0.2913818359375 +68351 -0.0362548828125 +68352 -0.339599609375 +68353 0.10943603515625 +68354 -0.372161865234375 +68355 0.23516845703125 +68356 -0.369873046875 +68357 0.373687744140625 +68358 -0.3336181640625 +68359 0.517791748046875 +68360 -0.292236328125 +68361 0.602783203125 +68362 -0.243621826171875 +68363 0.635711669921875 +68364 -0.172943115234375 +68365 0.655181884765625 +68366 -0.085205078125 +68367 0.65948486328125 +68368 0.015380859375 +68369 0.651275634765625 +68370 0.117095947265625 +68371 0.61846923828125 +68372 0.202484130859375 +68373 0.53753662109375 +68374 0.262725830078125 +68375 0.404144287109375 +68376 0.292877197265625 +68377 0.22186279296875 +68378 0.2930908203125 +68379 0.003997802734375 +68380 0.27130126953125 +68381 -0.22100830078125 +68382 0.2366943359375 +68383 -0.42449951171875 +68384 0.19891357421875 +68385 -0.579833984375 +68386 0.177459716796875 +68387 -0.641876220703125 +68388 0.16943359375 +68389 -0.6177978515625 +68390 0.1456298828125 +68391 -0.575531005859375 +68392 0.103973388671875 +68393 -0.526336669921875 +68394 0.068511962890625 +68395 -0.42645263671875 +68396 0.05218505859375 +68397 -0.2581787109375 +68398 0.0389404296875 +68399 -0.068695068359375 +68400 0.011688232421875 +68401 0.09222412109375 +68402 -0.020538330078125 +68403 0.232147216796875 +68404 -0.052703857421875 +68405 0.3509521484375 +68406 -0.097991943359375 +68407 0.410064697265625 +68408 -0.16949462890625 +68409 0.372955322265625 +68410 -0.257537841796875 +68411 0.2554931640625 +68412 -0.3382568359375 +68413 0.10711669921875 +68414 -0.402801513671875 +68415 -0.052886962890625 +68416 -0.434783935546875 +68417 -0.186279296875 +68418 -0.408935546875 +68419 -0.23291015625 +68420 -0.335968017578125 +68421 -0.209442138671875 +68422 -0.24627685546875 +68423 -0.174163818359375 +68424 -0.14404296875 +68425 -0.126739501953125 +68426 -0.02520751953125 +68427 -0.048126220703125 +68428 0.096954345703125 +68429 0.0426025390625 +68430 0.200775146484375 +68431 0.10748291015625 +68432 0.279876708984375 +68433 0.1409912109375 +68434 0.355682373046875 +68435 0.19708251953125 +68436 0.424896240234375 +68437 0.273651123046875 +68438 0.461944580078125 +68439 0.31768798828125 +68440 0.4718017578125 +68441 0.341094970703125 +68442 0.466033935546875 +68443 0.368011474609375 +68444 0.434326171875 +68445 0.37249755859375 +68446 0.354400634765625 +68447 0.30072021484375 +68448 0.228759765625 +68449 0.1517333984375 +68450 0.08807373046875 +68451 -0.01470947265625 +68452 -0.059173583984375 +68453 -0.1883544921875 +68454 -0.210784912109375 +68455 -0.372711181640625 +68456 -0.33856201171875 +68457 -0.51397705078125 +68458 -0.420745849609375 +68459 -0.57177734375 +68460 -0.451507568359375 +68461 -0.53948974609375 +68462 -0.436859130859375 +68463 -0.43511962890625 +68464 -0.392547607421875 +68465 -0.2962646484375 +68466 -0.3353271484375 +68467 -0.161102294921875 +68468 -0.271697998046875 +68469 -0.0435791015625 +68470 -0.200775146484375 +68471 0.060394287109375 +68472 -0.130706787109375 +68473 0.13665771484375 +68474 -0.070587158203125 +68475 0.170135498046875 +68476 -0.021026611328125 +68477 0.16552734375 +68478 0.0306396484375 +68479 0.15728759765625 +68480 0.083740234375 +68481 0.150787353515625 +68482 0.124237060546875 +68483 0.12200927734375 +68484 0.153472900390625 +68485 0.080108642578125 +68486 0.180908203125 +68487 0.05126953125 +68488 0.217071533203125 +68489 0.062896728515625 +68490 0.2503662109375 +68491 0.09271240234375 +68492 0.25830078125 +68493 0.092987060546875 +68494 0.247528076171875 +68495 0.07855224609375 +68496 0.22540283203125 +68497 0.06427001953125 +68498 0.18609619140625 +68499 0.0347900390625 +68500 0.130462646484375 +68501 -0.01171875 +68502 0.06939697265625 +68503 -0.056060791015625 +68504 0.0247802734375 +68505 -0.055511474609375 +68506 -0.000946044921875 +68507 -0.010467529296875 +68508 -0.02984619140625 +68509 0.02508544921875 +68510 -0.071136474609375 +68511 0.025665283203125 +68512 -0.110748291015625 +68513 0.017333984375 +68514 -0.14605712890625 +68515 0.00189208984375 +68516 -0.180816650390625 +68517 -0.03173828125 +68518 -0.208770751953125 +68519 -0.071502685546875 +68520 -0.237823486328125 +68521 -0.13543701171875 +68522 -0.26666259765625 +68523 -0.219970703125 +68524 -0.28485107421875 +68525 -0.300506591796875 +68526 -0.2933349609375 +68527 -0.376312255859375 +68528 -0.27947998046875 +68529 -0.416107177734375 +68530 -0.22296142578125 +68531 -0.371124267578125 +68532 -0.126312255859375 +68533 -0.242279052734375 +68534 -0.00994873046875 +68535 -0.069732666015625 +68536 0.114532470703125 +68537 0.125640869140625 +68538 0.231048583984375 +68539 0.31268310546875 +68540 0.321441650390625 +68541 0.45501708984375 +68542 0.385498046875 +68543 0.554779052734375 +68544 0.421783447265625 +68545 0.61065673828125 +68546 0.424591064453125 +68547 0.610931396484375 +68548 0.383026123046875 +68549 0.531463623046875 +68550 0.304901123046875 +68551 0.3883056640625 +68552 0.21539306640625 +68553 0.23468017578125 +68554 0.127044677734375 +68555 0.095245361328125 +68556 0.053192138671875 +68557 -0.00396728515625 +68558 0.002044677734375 +68559 -0.04852294921875 +68560 -0.0322265625 +68561 -0.055145263671875 +68562 -0.071624755859375 +68563 -0.0758056640625 +68564 -0.12738037109375 +68565 -0.138702392578125 +68566 -0.18231201171875 +68567 -0.209197998046875 +68568 -0.236083984375 +68569 -0.289031982421875 +68570 -0.2882080078125 +68571 -0.37884521484375 +68572 -0.328094482421875 +68573 -0.456329345703125 +68574 -0.353363037109375 +68575 -0.51641845703125 +68576 -0.346160888671875 +68577 -0.519287109375 +68578 -0.3040771484375 +68579 -0.458251953125 +68580 -0.251556396484375 +68581 -0.384796142578125 +68582 -0.2010498046875 +68583 -0.323699951171875 +68584 -0.15130615234375 +68585 -0.269287109375 +68586 -0.091705322265625 +68587 -0.1951904296875 +68588 -0.0230712890625 +68589 -0.100006103515625 +68590 0.040985107421875 +68591 -0.01055908203125 +68592 0.113037109375 +68593 0.1033935546875 +68594 0.195404052734375 +68595 0.24908447265625 +68596 0.26300048828125 +68597 0.373199462890625 +68598 0.30731201171875 +68599 0.45806884765625 +68600 0.33172607421875 +68601 0.511474609375 +68602 0.35101318359375 +68603 0.565399169921875 +68604 0.36175537109375 +68605 0.61138916015625 +68606 0.33740234375 +68607 0.5897216796875 +68608 0.274505615234375 +68609 0.4906005859375 +68610 0.182220458984375 +68611 0.33148193359375 +68612 0.077728271484375 +68613 0.147796630859375 +68614 -0.01898193359375 +68615 -0.01873779296875 +68616 -0.094207763671875 +68617 -0.140289306640625 +68618 -0.135711669921875 +68619 -0.191986083984375 +68620 -0.14727783203125 +68621 -0.184295654296875 +68622 -0.14825439453125 +68623 -0.161834716796875 +68624 -0.157012939453125 +68625 -0.166595458984375 +68626 -0.1712646484375 +68627 -0.19390869140625 +68628 -0.182281494140625 +68629 -0.22442626953125 +68630 -0.200103759765625 +68631 -0.279754638671875 +68632 -0.2158203125 +68633 -0.3389892578125 +68634 -0.20867919921875 +68635 -0.3543701171875 +68636 -0.189544677734375 +68637 -0.348175048828125 +68638 -0.161865234375 +68639 -0.32598876953125 +68640 -0.11334228515625 +68641 -0.2581787109375 +68642 -0.042755126953125 +68643 -0.139801025390625 +68644 0.042449951171875 +68645 0.014617919921875 +68646 0.1141357421875 +68647 0.144378662109375 +68648 0.158843994140625 +68649 0.221038818359375 +68650 0.1878662109375 +68651 0.27069091796875 +68652 0.201263427734375 +68653 0.294036865234375 +68654 0.208282470703125 +68655 0.311767578125 +68656 0.215911865234375 +68657 0.339141845703125 +68658 0.217010498046875 +68659 0.360260009765625 +68660 0.205657958984375 +68661 0.360504150390625 +68662 0.1693115234375 +68663 0.308380126953125 +68664 0.099517822265625 +68665 0.18170166015625 +68666 0.007598876953125 +68667 0.0047607421875 +68668 -0.085601806640625 +68669 -0.17559814453125 +68670 -0.160064697265625 +68671 -0.3143310546875 +68672 -0.19647216796875 +68673 -0.36785888671875 +68674 -0.20526123046875 +68675 -0.36248779296875 +68676 -0.205108642578125 +68677 -0.343536376953125 +68678 -0.19183349609375 +68679 -0.3018798828125 +68680 -0.16265869140625 +68681 -0.231414794921875 +68682 -0.11151123046875 +68683 -0.117645263671875 +68684 -0.05242919921875 +68685 0.007049560546875 +68686 -0.009002685546875 +68687 0.087982177734375 +68688 0.024200439453125 +68689 0.13946533203125 +68690 0.051910400390625 +68691 0.17425537109375 +68692 0.07159423828125 +68693 0.188201904296875 +68694 0.078216552734375 +68695 0.171234130859375 +68696 0.0689697265625 +68697 0.118438720703125 +68698 0.054718017578125 +68699 0.05706787109375 +68700 0.035736083984375 +68701 -0.010711669921875 +68702 0.008758544921875 +68703 -0.0914306640625 +68704 -0.016815185546875 +68705 -0.162322998046875 +68706 -0.028961181640625 +68707 -0.194549560546875 +68708 -0.011199951171875 +68709 -0.1492919921875 +68710 0.038665771484375 +68711 -0.02166748046875 +68712 0.093719482421875 +68713 0.124053955078125 +68714 0.121856689453125 +68715 0.211151123046875 +68716 0.12396240234375 +68717 0.240447998046875 +68718 0.11346435546875 +68719 0.242218017578125 +68720 0.094970703125 +68721 0.2257080078125 +68722 0.070556640625 +68723 0.194366455078125 +68724 0.026947021484375 +68725 0.115509033203125 +68726 -0.02520751953125 +68727 0.0128173828125 +68728 -0.06011962890625 +68729 -0.053802490234375 +68730 -0.088623046875 +68731 -0.110626220703125 +68732 -0.1282958984375 +68733 -0.199493408203125 +68734 -0.1680908203125 +68735 -0.29437255859375 +68736 -0.18133544921875 +68737 -0.33221435546875 +68738 -0.154144287109375 +68739 -0.27972412109375 +68740 -0.10736083984375 +68741 -0.185333251953125 +68742 -0.074981689453125 +68743 -0.128204345703125 +68744 -0.06060791015625 +68745 -0.115692138671875 +68746 -0.051483154296875 +68747 -0.116455078125 +68748 -0.0377197265625 +68749 -0.105926513671875 +68750 -0.007049560546875 +68751 -0.053955078125 +68752 0.044036865234375 +68753 0.048797607421875 +68754 0.0960693359375 +68755 0.157318115234375 +68756 0.123504638671875 +68757 0.212005615234375 +68758 0.1285400390625 +68759 0.218475341796875 +68760 0.13677978515625 +68761 0.23724365234375 +68762 0.163970947265625 +68763 0.30535888671875 +68764 0.192626953125 +68765 0.38128662109375 +68766 0.197296142578125 +68767 0.404449462890625 +68768 0.186614990234375 +68769 0.3944091796875 +68770 0.176849365234375 +68771 0.3885498046875 +68772 0.15814208984375 +68773 0.362640380859375 +68774 0.1126708984375 +68775 0.27362060546875 +68776 0.03900146484375 +68777 0.11712646484375 +68778 -0.040435791015625 +68779 -0.054901123046875 +68780 -0.103424072265625 +68781 -0.19085693359375 +68782 -0.1475830078125 +68783 -0.28570556640625 +68784 -0.17266845703125 +68785 -0.339263916015625 +68786 -0.189605712890625 +68787 -0.3775634765625 +68788 -0.217559814453125 +68789 -0.445709228515625 +68790 -0.252960205078125 +68791 -0.535064697265625 +68792 -0.2889404296875 +68793 -0.629058837890625 +68794 -0.31298828125 +68795 -0.697601318359375 +68796 -0.309814453125 +68797 -0.70391845703125 +68798 -0.27740478515625 +68799 -0.6424560546875 +68800 -0.20684814453125 +68801 -0.491241455078125 +68802 -0.10504150390625 +68803 -0.265716552734375 +68804 0.003143310546875 +68805 -0.023712158203125 +68806 0.103424072265625 +68807 0.201751708984375 +68808 0.1807861328125 +68809 0.375823974609375 +68810 0.2293701171875 +68811 0.485076904296875 +68812 0.26580810546875 +68813 0.56884765625 +68814 0.293304443359375 +68815 0.634765625 +68816 0.292755126953125 +68817 0.63763427734375 +68818 0.259490966796875 +68819 0.5660400390625 +68820 0.215728759765625 +68821 0.4720458984375 +68822 0.183441162109375 +68823 0.40692138671875 +68824 0.16595458984375 +68825 0.3778076171875 +68826 0.1602783203125 +68827 0.376953125 +68828 0.15301513671875 +68829 0.371978759765625 +68830 0.123321533203125 +68831 0.313140869140625 +68832 0.06463623046875 +68833 0.184417724609375 +68834 -0.01202392578125 +68835 0.011199951171875 +68836 -0.09149169921875 +68837 -0.171051025390625 +68838 -0.1630859375 +68839 -0.33740234375 +68840 -0.220062255859375 +68841 -0.47198486328125 +68842 -0.25634765625 +68843 -0.560394287109375 +68844 -0.2626953125 +68845 -0.58056640625 +68846 -0.245635986328125 +68847 -0.54754638671875 +68848 -0.22540283203125 +68849 -0.508575439453125 +68850 -0.200469970703125 +68851 -0.459503173828125 +68852 -0.16851806640625 +68853 -0.394378662109375 +68854 -0.146514892578125 +68855 -0.35260009765625 +68856 -0.1251220703125 +68857 -0.31170654296875 +68858 -0.073089599609375 +68859 -0.197418212890625 +68860 0.010101318359375 +68861 -0.007965087890625 +68862 0.103485107421875 +68863 0.207489013671875 +68864 0.1900634765625 +68865 0.409210205078125 +68866 0.25860595703125 +68867 0.57208251953125 +68868 0.296783447265625 +68869 0.66595458984375 +68870 0.29248046875 +68871 0.65875244140625 +68872 0.252838134765625 +68873 0.56744384765625 +68874 0.19378662109375 +68875 0.431396484375 +68876 0.133087158203125 +68877 0.29443359375 +68878 0.081451416015625 +68879 0.182464599609375 +68880 0.02691650390625 +68881 0.06365966796875 +68882 -0.035491943359375 +68883 -0.075958251953125 +68884 -0.086944580078125 +68885 -0.189422607421875 +68886 -0.12518310546875 +68887 -0.271942138671875 +68888 -0.157379150390625 +68889 -0.342529296875 +68890 -0.168853759765625 +68891 -0.364166259765625 +68892 -0.15576171875 +68893 -0.327239990234375 +68894 -0.135833740234375 +68895 -0.2769775390625 +68896 -0.12493896484375 +68897 -0.253692626953125 +68898 -0.117828369140625 +68899 -0.24365234375 +68900 -0.095733642578125 +68901 -0.1983642578125 +68902 -0.058319091796875 +68903 -0.116241455078125 +68904 -0.021392822265625 +68905 -0.036834716796875 +68906 0.012725830078125 +68907 0.034881591796875 +68908 0.040679931640625 +68909 0.09124755859375 +68910 0.053009033203125 +68911 0.10888671875 +68912 0.064239501953125 +68913 0.125518798828125 +68914 0.080596923828125 +68915 0.15771484375 +68916 0.09124755859375 +68917 0.17828369140625 +68918 0.089752197265625 +68919 0.17108154296875 +68920 0.07366943359375 +68921 0.129974365234375 +68922 0.0538330078125 +68923 0.082427978515625 +68924 0.030029296875 +68925 0.027679443359375 +68926 -0.00982666015625 +68927 -0.065643310546875 +68928 -0.050567626953125 +68929 -0.15936279296875 +68930 -0.076141357421875 +68931 -0.21307373046875 +68932 -0.089385986328125 +68933 -0.234649658203125 +68934 -0.080657958984375 +68935 -0.2001953125 +68936 -0.05340576171875 +68937 -0.119171142578125 +68938 -0.020416259765625 +68939 -0.024749755859375 +68940 0.01959228515625 +68941 0.085784912109375 +68942 0.053314208984375 +68943 0.178131103515625 +68944 0.06646728515625 +68945 0.215576171875 +68946 0.064361572265625 +68947 0.211456298828125 +68948 0.05072021484375 +68949 0.17523193359375 +68950 0.034027099609375 +68951 0.128753662109375 +68952 0.025909423828125 +68953 0.1019287109375 +68954 0.018218994140625 +68955 0.0743408203125 +68956 0.009674072265625 +68957 0.04327392578125 +68958 0.0115966796875 +68959 0.038177490234375 +68960 0.030517578125 +68961 0.076263427734375 +68962 0.05975341796875 +68963 0.14105224609375 +68964 0.081024169921875 +68965 0.186431884765625 +68966 0.08489990234375 +68967 0.188812255859375 +68968 0.067657470703125 +68969 0.1390380859375 +68970 0.031036376953125 +68971 0.041778564453125 +68972 -0.01580810546875 +68973 -0.079437255859375 +68974 -0.070831298828125 +68975 -0.219390869140625 +68976 -0.129974365234375 +68977 -0.367828369140625 +68978 -0.18145751953125 +68979 -0.494873046875 +68980 -0.207794189453125 +68981 -0.556243896484375 +68982 -0.19189453125 +68983 -0.508697509765625 +68984 -0.14276123046875 +68985 -0.3756103515625 +68986 -0.08453369140625 +68987 -0.218902587890625 +68988 -0.026885986328125 +68989 -0.063751220703125 +68990 0.030975341796875 +68991 0.091552734375 +68992 0.084930419921875 +68993 0.23602294921875 +68994 0.124664306640625 +68995 0.342987060546875 +68996 0.143524169921875 +68997 0.39520263671875 +68998 0.14031982421875 +68999 0.389373779296875 +69000 0.11456298828125 +69001 0.324249267578125 +69002 0.075775146484375 +69003 0.224090576171875 +69004 0.03778076171875 +69005 0.124267578125 +69006 0.005279541015625 +69007 0.037078857421875 +69008 -0.01104736328125 +69009 -0.010101318359375 +69010 -0.01220703125 +69011 -0.019439697265625 +69012 -0.01080322265625 +69013 -0.022796630859375 +69014 0.000244140625 +69015 -0.001556396484375 +69016 0.025482177734375 +69017 0.056304931640625 +69018 0.04754638671875 +69019 0.106719970703125 +69020 0.045623779296875 +69021 0.096893310546875 +69022 0.025848388671875 +69023 0.042694091796875 +69024 0.002960205078125 +69025 -0.018035888671875 +69026 -0.01934814453125 +69027 -0.07586669921875 +69028 -0.036651611328125 +69029 -0.11944580078125 +69030 -0.05322265625 +69031 -0.15972900390625 +69032 -0.0712890625 +69033 -0.202606201171875 +69034 -0.0909423828125 +69035 -0.24859619140625 +69036 -0.115020751953125 +69037 -0.30517578125 +69038 -0.139404296875 +69039 -0.36212158203125 +69040 -0.15301513671875 +69041 -0.39141845703125 +69042 -0.140899658203125 +69043 -0.35528564453125 +69044 -0.10150146484375 +69045 -0.249969482421875 +69046 -0.04156494140625 +69047 -0.092864990234375 +69048 0.0284423828125 +69049 0.08905029296875 +69050 0.0848388671875 +69051 0.2352294921875 +69052 0.11712646484375 +69053 0.318817138671875 +69054 0.1326904296875 +69055 0.358642578125 +69056 0.128814697265625 +69057 0.347747802734375 +69058 0.105255126953125 +69059 0.28564453125 +69060 0.081878662109375 +69061 0.223175048828125 +69062 0.072906494140625 +69063 0.196746826171875 +69064 0.06787109375 +69065 0.179840087890625 +69066 0.060028076171875 +69067 0.155548095703125 +69068 0.060028076171875 +69069 0.151214599609375 +69070 0.063873291015625 +69071 0.156951904296875 +69072 0.055419921875 +69073 0.13177490234375 +69074 0.044464111328125 +69075 0.100799560546875 +69076 0.03997802734375 +69077 0.087127685546875 +69078 0.027862548828125 +69079 0.05487060546875 +69080 0.00299072265625 +69081 -0.009002685546875 +69082 -0.034393310546875 +69083 -0.10400390625 +69084 -0.084014892578125 +69085 -0.229400634765625 +69086 -0.13421630859375 +69087 -0.35552978515625 +69088 -0.1690673828125 +69089 -0.441925048828125 +69090 -0.1827392578125 +69091 -0.473846435546875 +69092 -0.18048095703125 +69093 -0.464813232421875 +69094 -0.16387939453125 +69095 -0.419097900390625 +69096 -0.131927490234375 +69097 -0.334320068359375 +69098 -0.091400146484375 +69099 -0.227935791015625 +69100 -0.051483154296875 +69101 -0.12347412109375 +69102 -0.014739990234375 +69103 -0.02764892578125 +69104 0.025970458984375 +69105 0.077667236328125 +69106 0.078826904296875 +69107 0.2132568359375 +69108 0.14764404296875 +69109 0.38885498046875 +69110 0.223907470703125 +69111 0.582794189453125 +69112 0.283660888671875 +69113 0.734039306640625 +69114 0.31024169921875 +69115 0.800140380859375 +69116 0.302520751953125 +69117 0.7783203125 +69118 0.25909423828125 +69119 0.6651611328125 +69120 0.180023193359375 +69121 0.45965576171875 +69122 0.080474853515625 +69123 0.199188232421875 +69124 -0.01483154296875 +69125 -0.050689697265625 +69126 -0.085296630859375 +69127 -0.23297119140625 +69128 -0.12451171875 +69129 -0.33013916015625 +69130 -0.141845703125 +69131 -0.368408203125 +69132 -0.1484375 +69133 -0.378936767578125 +69134 -0.149749755859375 +69135 -0.376983642578125 +69136 -0.15191650390625 +69137 -0.37969970703125 +69138 -0.156494140625 +69139 -0.391510009765625 +69140 -0.153778076171875 +69141 -0.385345458984375 +69142 -0.136871337890625 +69143 -0.3419189453125 +69144 -0.113677978515625 +69145 -0.28289794921875 +69146 -0.09991455078125 +69147 -0.251617431640625 +69148 -0.10223388671875 +69149 -0.266143798828125 +69150 -0.1016845703125 +69151 -0.273345947265625 +69152 -0.078094482421875 +69153 -0.216796875 +69154 -0.043060302734375 +69155 -0.128265380859375 +69156 -0.01849365234375 +69157 -0.068145751953125 +69158 -0.006927490234375 +69159 -0.0430908203125 +69160 0.00177001953125 +69161 -0.024444580078125 +69162 0.0194091796875 +69163 0.020721435546875 +69164 0.05743408203125 +69165 0.124481201171875 +69166 0.10540771484375 +69167 0.25787353515625 +69168 0.1483154296875 +69169 0.379119873046875 +69170 0.1832275390625 +69171 0.47991943359375 +69172 0.198699951171875 +69173 0.5281982421875 +69174 0.19024658203125 +69175 0.511138916015625 +69176 0.16790771484375 +69177 0.456207275390625 +69178 0.147674560546875 +69179 0.407470703125 +69180 0.136474609375 +69181 0.383758544921875 +69182 0.124298095703125 +69183 0.35687255859375 +69184 0.105865478515625 +69185 0.31182861328125 +69186 0.08209228515625 +69187 0.250885009765625 +69188 0.04998779296875 +69189 0.1654052734375 +69190 0.002349853515625 +69191 0.035247802734375 +69192 -0.0616455078125 +69193 -0.142059326171875 +69194 -0.130889892578125 +69195 -0.33563232421875 +69196 -0.201507568359375 +69197 -0.5345458984375 +69198 -0.2674560546875 +69199 -0.72186279296875 +69200 -0.306915283203125 +69201 -0.836669921875 +69202 -0.30328369140625 +69203 -0.8326416015625 +69204 -0.26385498046875 +69205 -0.7296142578125 +69206 -0.20855712890625 +69207 -0.582550048828125 +69208 -0.155059814453125 +69209 -0.440093994140625 +69210 -0.111419677734375 +69211 -0.324310302734375 +69212 -0.0655517578125 +69213 -0.20147705078125 +69214 -0.007843017578125 +69215 -0.044647216796875 +69216 0.04644775390625 +69217 0.103973388671875 +69218 0.0821533203125 +69219 0.202392578125 +69220 0.104248046875 +69221 0.264495849609375 +69222 0.130279541015625 +69223 0.338897705078125 +69224 0.1668701171875 +69225 0.443817138671875 +69226 0.201812744140625 +69227 0.545074462890625 +69228 0.226043701171875 +69229 0.6173095703125 +69230 0.236785888671875 +69231 0.6524658203125 +69232 0.23876953125 +69233 0.66339111328125 +69234 0.234283447265625 +69235 0.6561279296875 +69236 0.21478271484375 +69237 0.606781005859375 +69238 0.175262451171875 +69239 0.501190185546875 +69240 0.120635986328125 +69241 0.352783203125 +69242 0.056365966796875 +69243 0.176544189453125 +69244 -0.020111083984375 +69245 -0.034820556640625 +69246 -0.1004638671875 +69247 -0.258209228515625 +69248 -0.166290283203125 +69249 -0.44244384765625 +69250 -0.21319580078125 +69251 -0.5753173828125 +69252 -0.23956298828125 +69253 -0.65203857421875 +69254 -0.23431396484375 +69255 -0.641632080078125 +69256 -0.204071044921875 +69257 -0.562164306640625 +69258 -0.164886474609375 +69259 -0.458038330078125 +69260 -0.12451171875 +69261 -0.350555419921875 +69262 -0.090545654296875 +69263 -0.260528564453125 +69264 -0.064544677734375 +69265 -0.192108154296875 +69266 -0.045379638671875 +69267 -0.141937255859375 +69268 -0.0302734375 +69269 -0.1021728515625 +69270 -0.015716552734375 +69271 -0.062896728515625 +69272 0.002655029296875 +69273 -0.011932373046875 +69274 0.02923583984375 +69275 0.062835693359375 +69276 0.059478759765625 +69277 0.148712158203125 +69278 0.09197998046875 +69279 0.241729736328125 +69280 0.12939453125 +69281 0.34912109375 +69282 0.16693115234375 +69283 0.457305908203125 +69284 0.19659423828125 +69285 0.54388427734375 +69286 0.205535888671875 +69287 0.5728759765625 +69288 0.180267333984375 +69289 0.506591796875 +69290 0.123077392578125 +69291 0.351226806640625 +69292 0.04833984375 +69293 0.146514892578125 +69294 -0.025054931640625 +69295 -0.05523681640625 +69296 -0.08343505859375 +69297 -0.21624755859375 +69298 -0.126251220703125 +69299 -0.334930419921875 +69300 -0.150482177734375 +69301 -0.402984619140625 +69302 -0.163665771484375 +69303 -0.4412841796875 +69304 -0.182403564453125 +69305 -0.49578857421875 +69306 -0.2044677734375 +69307 -0.5601806640625 +69308 -0.217803955078125 +69309 -0.600738525390625 +69310 -0.210540771484375 +69311 -0.584228515625 +69312 -0.17144775390625 +69313 -0.47930908203125 +69314 -0.098236083984375 +69315 -0.27935791015625 +69316 0.00018310546875 +69317 -0.0089111328125 +69318 0.100982666015625 +69319 0.268798828125 +69320 0.1785888671875 +69321 0.482818603515625 +69322 0.222381591796875 +69323 0.60369873046875 +69324 0.239166259765625 +69325 0.650421142578125 +69326 0.243743896484375 +69327 0.66400146484375 +69328 0.235076904296875 +69329 0.6414794921875 +69330 0.20947265625 +69331 0.572540283203125 +69332 0.1817626953125 +69333 0.498138427734375 +69334 0.159637451171875 +69335 0.439453125 +69336 0.135589599609375 +69337 0.375518798828125 +69338 0.09820556640625 +69339 0.274505615234375 +69340 0.03759765625 +69341 0.1087646484375 +69342 -0.03814697265625 +69343 -0.099395751953125 +69344 -0.1175537109375 +69345 -0.3182373046875 +69346 -0.2010498046875 +69347 -0.5489501953125 +69348 -0.282196044921875 +69349 -0.7738037109375 +69350 -0.341949462890625 +69351 -0.86383056640625 +69352 -0.36834716796875 +69353 -0.870391845703125 +69354 -0.367767333984375 +69355 -0.86895751953125 +69356 -0.345001220703125 +69357 -0.861053466796875 +69358 -0.293853759765625 +69359 -0.765869140625 +69360 -0.210296630859375 +69361 -0.5301513671875 +69362 -0.096923828125 +69363 -0.214691162109375 +69364 0.03070068359375 +69365 0.137359619140625 +69366 0.154052734375 +69367 0.474822998046875 +69368 0.26031494140625 +69369 0.76239013671875 +69370 0.3397216796875 +69371 0.867462158203125 +69372 0.392425537109375 +69373 0.870361328125 +69374 0.414215087890625 +69375 0.86480712890625 +69376 0.4068603515625 +69377 0.831817626953125 +69378 0.3790283203125 +69379 0.677581787109375 +69380 0.332916259765625 +69381 0.495880126953125 +69382 0.27496337890625 +69383 0.30767822265625 +69384 0.206329345703125 +69385 0.116180419921875 +69386 0.1170654296875 +69387 -0.110748291015625 +69388 0.005401611328125 +69389 -0.381805419921875 +69390 -0.114105224609375 +69391 -0.6572265625 +69392 -0.22137451171875 +69393 -0.857421875 +69394 -0.301910400390625 +69395 -0.870391845703125 +69396 -0.35308837890625 +69397 -0.870391845703125 +69398 -0.383514404296875 +69399 -0.86444091796875 +69400 -0.40472412109375 +69401 -0.85723876953125 +69402 -0.41070556640625 +69403 -0.790008544921875 +69404 -0.38372802734375 +69405 -0.62847900390625 +69406 -0.322906494140625 +69407 -0.3956298828125 +69408 -0.2392578125 +69409 -0.126708984375 +69410 -0.14208984375 +69411 0.150115966796875 +69412 -0.035614013671875 +69413 0.424041748046875 +69414 0.0709228515625 +69415 0.670623779296875 +69416 0.1644287109375 +69417 0.854522705078125 +69418 0.238739013671875 +69419 0.866485595703125 +69420 0.288482666015625 +69421 0.86920166015625 +69422 0.319305419921875 +69423 0.8653564453125 +69424 0.33538818359375 +69425 0.857147216796875 +69426 0.33563232421875 +69427 0.766845703125 +69428 0.3216552734375 +69429 0.628509521484375 +69430 0.291259765625 +69431 0.462127685546875 +69432 0.2530517578125 +69433 0.297210693359375 +69434 0.21124267578125 +69435 0.14862060546875 +69436 0.158599853515625 +69437 -0.00537109375 +69438 0.097869873046875 +69439 -0.15753173828125 +69440 0.028167724609375 +69441 -0.31304931640625 +69442 -0.05474853515625 +69443 -0.48876953125 +69444 -0.135162353515625 +69445 -0.6416015625 +69446 -0.20465087890625 +69447 -0.751373291015625 +69448 -0.270538330078125 +69449 -0.84619140625 +69450 -0.3277587890625 +69451 -0.861297607421875 +69452 -0.365325927734375 +69453 -0.863250732421875 +69454 -0.372802734375 +69455 -0.856597900390625 +69456 -0.354156494140625 +69457 -0.7498779296875 +69458 -0.328460693359375 +69459 -0.624542236328125 +69460 -0.28863525390625 +69461 -0.47808837890625 +69462 -0.2156982421875 +69463 -0.253387451171875 +69464 -0.124847412109375 +69465 0.003692626953125 +69466 -0.038787841796875 +69467 0.2257080078125 +69468 0.046295166015625 +69469 0.427154541015625 +69470 0.1407470703125 +69471 0.643218994140625 +69472 0.241119384765625 +69473 0.855926513671875 +69474 0.328155517578125 +69475 0.870361328125 +69476 0.385406494140625 +69477 0.870361328125 +69478 0.415069580078125 +69479 0.862762451171875 +69480 0.4161376953125 +69481 0.79669189453125 +69482 0.385467529296875 +69483 0.595794677734375 +69484 0.332672119140625 +69485 0.362152099609375 +69486 0.26708984375 +69487 0.1270751953125 +69488 0.19580078125 +69489 -0.086944580078125 +69490 0.11968994140625 +69491 -0.2784423828125 +69492 0.027587890625 +69493 -0.484832763671875 +69494 -0.0865478515625 +69495 -0.729583740234375 +69496 -0.205902099609375 +69497 -0.86688232421875 +69498 -0.309417724609375 +69499 -0.870391845703125 +69500 -0.395263671875 +69501 -0.86859130859375 +69502 -0.4625244140625 +69503 -0.86279296875 +69504 -0.499298095703125 +69505 -0.817962646484375 +69506 -0.490570068359375 +69507 -0.6116943359375 +69508 -0.4339599609375 +69509 -0.3128662109375 +69510 -0.340545654296875 +69511 0.039398193359375 +69512 -0.21697998046875 +69513 0.422821044921875 +69514 -0.074310302734375 +69515 0.805145263671875 +69516 0.06494140625 +69517 0.870361328125 +69518 0.18182373046875 +69519 0.870361328125 +69520 0.27227783203125 +69521 0.860015869140625 +69522 0.33349609375 +69523 0.727935791015625 +69524 0.363311767578125 +69525 0.48114013671875 +69526 0.369415283203125 +69527 0.2059326171875 +69528 0.3590087890625 +69529 -0.06103515625 +69530 0.335174560546875 +69531 -0.29913330078125 +69532 0.29302978515625 +69533 -0.516204833984375 +69534 0.227508544921875 +69535 -0.7252197265625 +69536 0.14678955078125 +69537 -0.85980224609375 +69538 0.062255859375 +69539 -0.870391845703125 +69540 -0.01617431640625 +69541 -0.870391845703125 +69542 -0.072296142578125 +69543 -0.858062744140625 +69544 -0.10443115234375 +69545 -0.673004150390625 +69546 -0.1295166015625 +69547 -0.42694091796875 +69548 -0.161712646484375 +69549 -0.2100830078125 +69550 -0.199981689453125 +69551 -0.0362548828125 +69552 -0.234466552734375 +69553 0.10943603515625 +69554 -0.25836181640625 +69555 0.23516845703125 +69556 -0.25787353515625 +69557 0.373687744140625 +69558 -0.233489990234375 +69559 0.517791748046875 +69560 -0.205810546875 +69561 0.602783203125 +69562 -0.17315673828125 +69563 0.635711669921875 +69564 -0.12469482421875 +69565 0.655181884765625 +69566 -0.063873291015625 +69567 0.65948486328125 +69568 0.00640869140625 +69569 0.651275634765625 +69570 0.07781982421875 +69571 0.61846923828125 +69572 0.13787841796875 +69573 0.53753662109375 +69574 0.180328369140625 +69575 0.404144287109375 +69576 0.201629638671875 +69577 0.22186279296875 +69578 0.201934814453125 +69579 0.003997802734375 +69580 0.1868896484375 +69581 -0.22100830078125 +69582 0.1630859375 +69583 -0.42449951171875 +69584 0.137359619140625 +69585 -0.579833984375 +69586 0.123626708984375 +69587 -0.641876220703125 +69588 0.1197509765625 +69589 -0.6177978515625 +69590 0.104583740234375 +69591 -0.575531005859375 +69592 0.0765380859375 +69593 -0.526336669921875 +69594 0.05279541015625 +69595 -0.42645263671875 +69596 0.042572021484375 +69597 -0.2581787109375 +69598 0.03424072265625 +69599 -0.068695068359375 +69600 0.015472412109375 +69601 0.09222412109375 +69602 -0.00732421875 +69603 0.232147216796875 +69604 -0.030487060546875 +69605 0.3509521484375 +69606 -0.0634765625 +69607 0.410064697265625 +69608 -0.11566162109375 +69609 0.372955322265625 +69610 -0.180023193359375 +69611 0.2554931640625 +69612 -0.2393798828125 +69613 0.10711669921875 +69614 -0.2872314453125 +69615 -0.052886962890625 +69616 -0.311737060546875 +69617 -0.186279296875 +69618 -0.294647216796875 +69619 -0.23291015625 +69620 -0.24359130859375 +69621 -0.209442138671875 +69622 -0.180328369140625 +69623 -0.174163818359375 +69624 -0.10784912109375 +69625 -0.126739501953125 +69626 -0.023162841796875 +69627 -0.048126220703125 +69628 0.064178466796875 +69629 0.0426025390625 +69630 0.138671875 +69631 0.10748291015625 +69632 0.195220947265625 +69633 0.1409912109375 +69634 0.24847412109375 +69635 0.19708251953125 +69636 0.29681396484375 +69637 0.273651123046875 +69638 0.32318115234375 +69639 0.31768798828125 +69640 0.330718994140625 +69641 0.341094970703125 +69642 0.326934814453125 +69643 0.368011474609375 +69644 0.30499267578125 +69645 0.37249755859375 +69646 0.250335693359375 +69647 0.30072021484375 +69648 0.16473388671875 +69649 0.1517333984375 +69650 0.06854248046875 +69651 -0.01470947265625 +69652 -0.032470703125 +69653 -0.1883544921875 +69654 -0.136627197265625 +69655 -0.372711181640625 +69656 -0.225128173828125 +69657 -0.51397705078125 +69658 -0.28338623046875 +69659 -0.57177734375 +69660 -0.307342529296875 +69661 -0.53948974609375 +69662 -0.30078125 +69663 -0.43511962890625 +69664 -0.27386474609375 +69665 -0.2962646484375 +69666 -0.237548828125 +69667 -0.161102294921875 +69668 -0.196075439453125 +69669 -0.0435791015625 +69670 -0.148834228515625 +69671 0.060394287109375 +69672 -0.10125732421875 +69673 0.13665771484375 +69674 -0.0594482421875 +69675 0.170135498046875 +69676 -0.023895263671875 +69677 0.16552734375 +69678 0.013519287109375 +69679 0.15728759765625 +69680 0.052154541015625 +69681 0.150787353515625 +69682 0.082550048828125 +69683 0.12200927734375 +69684 0.105377197265625 +69685 0.080108642578125 +69686 0.126678466796875 +69687 0.05126953125 +69688 0.153228759765625 +69689 0.062896728515625 +69690 0.17724609375 +69691 0.09271240234375 +69692 0.183807373046875 +69693 0.092987060546875 +69694 0.177276611328125 +69695 0.07855224609375 +69696 0.1624755859375 +69697 0.06427001953125 +69698 0.135589599609375 +69699 0.0347900390625 +69700 0.0972900390625 +69701 -0.01171875 +69702 0.054840087890625 +69703 -0.056060791015625 +69704 0.022796630859375 +69705 -0.055511474609375 +69706 0.00286865234375 +69707 -0.010467529296875 +69708 -0.01922607421875 +69709 0.02508544921875 +69710 -0.04937744140625 +69711 0.025665283203125 +69712 -0.07818603515625 +69713 0.017333984375 +69714 -0.103790283203125 +69715 0.00189208984375 +69716 -0.1285400390625 +69717 -0.03173828125 +69718 -0.148223876953125 +69719 -0.071502685546875 +69720 -0.167999267578125 +69721 -0.13543701171875 +69722 -0.186981201171875 +69723 -0.219970703125 +69724 -0.19830322265625 +69725 -0.300506591796875 +69726 -0.20263671875 +69727 -0.376312255859375 +69728 -0.1917724609375 +69729 -0.416107177734375 +69730 -0.152435302734375 +69731 -0.371124267578125 +69732 -0.08642578125 +69733 -0.242279052734375 +69734 -0.007293701171875 +69735 -0.069732666015625 +69736 0.0771484375 +69737 0.125640869140625 +69738 0.15618896484375 +69739 0.31268310546875 +69740 0.217742919921875 +69741 0.45501708984375 +69742 0.26153564453125 +69743 0.554779052734375 +69744 0.286590576171875 +69745 0.61065673828125 +69746 0.2890625 +69747 0.610931396484375 +69748 0.261810302734375 +69749 0.531463623046875 +69750 0.209991455078125 +69751 0.3883056640625 +69752 0.15020751953125 +69753 0.23468017578125 +69754 0.09075927734375 +69755 0.095245361328125 +69756 0.040496826171875 +69757 -0.00396728515625 +69758 0.004913330078125 +69759 -0.04852294921875 +69760 -0.01971435546875 +69761 -0.055145263671875 +69762 -0.0477294921875 +69763 -0.0758056640625 +69764 -0.086395263671875 +69765 -0.138702392578125 +69766 -0.12432861328125 +69767 -0.209197998046875 +69768 -0.16119384765625 +69769 -0.289031982421875 +69770 -0.196624755859375 +69771 -0.37884521484375 +69772 -0.223541259765625 +69773 -0.456329345703125 +69774 -0.24041748046875 +69775 -0.51641845703125 +69776 -0.2354736328125 +69777 -0.519287109375 +69778 -0.2071533203125 +69779 -0.458251953125 +69780 -0.17156982421875 +69781 -0.384796142578125 +69782 -0.136993408203125 +69783 -0.323699951171875 +69784 -0.102691650390625 +69785 -0.269287109375 +69786 -0.061767578125 +69787 -0.1951904296875 +69788 -0.014862060546875 +69789 -0.100006103515625 +69790 0.028961181640625 +69791 -0.01055908203125 +69792 0.077911376953125 +69793 0.1033935546875 +69794 0.133392333984375 +69795 0.24908447265625 +69796 0.178863525390625 +69797 0.373199462890625 +69798 0.20867919921875 +69799 0.45806884765625 +69800 0.225006103515625 +69801 0.511474609375 +69802 0.237579345703125 +69803 0.565399169921875 +69804 0.244171142578125 +69805 0.61138916015625 +69806 0.22735595703125 +69807 0.5897216796875 +69808 0.184844970703125 +69809 0.4906005859375 +69810 0.122650146484375 +69811 0.33148193359375 +69812 0.05224609375 +69813 0.147796630859375 +69814 -0.01300048828125 +69815 -0.01873779296875 +69816 -0.063873291015625 +69817 -0.140289306640625 +69818 -0.092193603515625 +69819 -0.191986083984375 +69820 -0.100433349609375 +69821 -0.184295654296875 +69822 -0.101470947265625 +69823 -0.161834716796875 +69824 -0.1075439453125 +69825 -0.166595458984375 +69826 -0.1170654296875 +69827 -0.19390869140625 +69828 -0.124298095703125 +69829 -0.22442626953125 +69830 -0.1358642578125 +69831 -0.279754638671875 +69832 -0.145904541015625 +69833 -0.3389892578125 +69834 -0.140594482421875 +69835 -0.3543701171875 +69836 -0.127197265625 +69837 -0.348175048828125 +69838 -0.10809326171875 +69839 -0.32598876953125 +69840 -0.0750732421875 +69841 -0.2581787109375 +69842 -0.027374267578125 +69843 -0.139801025390625 +69844 0.029998779296875 +69845 0.014617919921875 +69846 0.0782470703125 +69847 0.144378662109375 +69848 0.1083984375 +69849 0.221038818359375 +69850 0.127960205078125 +69851 0.27069091796875 +69852 0.136962890625 +69853 0.294036865234375 +69854 0.141571044921875 +69855 0.311767578125 +69856 0.146453857421875 +69857 0.339141845703125 +69858 0.147064208984375 +69859 0.360260009765625 +69860 0.139404296875 +69861 0.360504150390625 +69862 0.1146240234375 +69863 0.308380126953125 +69864 0.066741943359375 +69865 0.18170166015625 +69866 0.00360107421875 +69867 0.0047607421875 +69868 -0.060333251953125 +69869 -0.17559814453125 +69870 -0.11114501953125 +69871 -0.3143310546875 +69872 -0.13543701171875 +69873 -0.36785888671875 +69874 -0.140594482421875 +69875 -0.36248779296875 +69876 -0.139678955078125 +69877 -0.343536376953125 +69878 -0.12982177734375 +69879 -0.3018798828125 +69880 -0.109130859375 +69881 -0.231414794921875 +69882 -0.073394775390625 +69883 -0.117645263671875 +69884 -0.032379150390625 +69885 0.007049560546875 +69886 -0.0025634765625 +69887 0.087982177734375 +69888 0.01995849609375 +69889 0.13946533203125 +69890 0.03851318359375 +69891 0.17425537109375 +69892 0.051361083984375 +69893 0.188201904296875 +69894 0.055450439453125 +69895 0.171234130859375 +69896 0.049163818359375 +69897 0.118438720703125 +69898 0.039398193359375 +69899 0.05706787109375 +69900 0.02642822265625 +69901 -0.010711669921875 +69902 0.00836181640625 +69903 -0.0914306640625 +69904 -0.008880615234375 +69905 -0.162322998046875 +69906 -0.017730712890625 +69907 -0.194549560546875 +69908 -0.00787353515625 +69909 -0.1492919921875 +69910 0.022125244140625 +69911 -0.02166748046875 +69912 0.0555419921875 +69913 0.124053955078125 +69914 0.0723876953125 +69915 0.211151123046875 +69916 0.073272705078125 +69917 0.240447998046875 +69918 0.06658935546875 +69919 0.242218017578125 +69920 0.05517578125 +69921 0.2257080078125 +69922 0.040313720703125 +69923 0.194366455078125 +69924 0.013671875 +69925 0.115509033203125 +69926 -0.018096923828125 +69927 0.0128173828125 +69928 -0.03900146484375 +69929 -0.053802490234375 +69930 -0.05584716796875 +69931 -0.110626220703125 +69932 -0.079620361328125 +69933 -0.199493408203125 +69934 -0.103485107421875 +69935 -0.29437255859375 +69936 -0.11090087890625 +69937 -0.33221435546875 +69938 -0.093292236328125 +69939 -0.27972412109375 +69940 -0.06365966796875 +69941 -0.185333251953125 +69942 -0.043182373046875 +69943 -0.128204345703125 +69944 -0.034088134765625 +69945 -0.115692138671875 +69946 -0.0284423828125 +69947 -0.116455078125 +69948 -0.020111083984375 +69949 -0.105926513671875 +69950 -0.00140380859375 +69951 -0.053955078125 +69952 0.029876708984375 +69953 0.048797607421875 +69954 0.061614990234375 +69955 0.157318115234375 +69956 0.077972412109375 +69957 0.212005615234375 +69958 0.080322265625 +69959 0.218475341796875 +69960 0.08465576171875 +69961 0.23724365234375 +69962 0.100830078125 +69963 0.30535888671875 +69964 0.118011474609375 +69965 0.38128662109375 +69966 0.120361328125 +69967 0.404449462890625 +69968 0.11328125 +69969 0.3944091796875 +69970 0.10693359375 +69971 0.3885498046875 +69972 0.09521484375 +69973 0.362640380859375 +69974 0.0670166015625 +69975 0.27362060546875 +69976 0.021453857421875 +69977 0.11712646484375 +69978 -0.027557373046875 +69979 -0.054901123046875 +69980 -0.06622314453125 +69981 -0.19085693359375 +69982 -0.093048095703125 +69983 -0.28570556640625 +69984 -0.107940673828125 +69985 -0.339263916015625 +69986 -0.11773681640625 +69987 -0.3775634765625 +69988 -0.134429931640625 +69989 -0.445709228515625 +69990 -0.15582275390625 +69991 -0.535064697265625 +69992 -0.177703857421875 +69993 -0.629058837890625 +69994 -0.1922607421875 +69995 -0.697601318359375 +69996 -0.19000244140625 +69997 -0.70391845703125 +69998 -0.169708251953125 +69999 -0.6424560546875 +70000 -0.12579345703125 +70001 -0.491241455078125 +70002 -0.06256103515625 +70003 -0.265716552734375 +70004 0.004486083984375 +70005 -0.023712158203125 +70006 0.066497802734375 +70007 0.201751708984375 +70008 0.1141357421875 +70009 0.375823974609375 +70010 0.143798828125 +70011 0.485076904296875 +70012 0.16583251953125 +70013 0.56884765625 +70014 0.182281494140625 +70015 0.634765625 +70016 0.181304931640625 +70017 0.63763427734375 +70018 0.160003662109375 +70019 0.5660400390625 +70020 0.132293701171875 +70021 0.4720458984375 +70022 0.11187744140625 +70023 0.40692138671875 +70024 0.100799560546875 +70025 0.3778076171875 +70026 0.09722900390625 +70027 0.376953125 +70028 0.092803955078125 +70029 0.371978759765625 +70030 0.07452392578125 +70031 0.313140869140625 +70032 0.038330078125 +70033 0.184417724609375 +70034 -0.00897216796875 +70035 0.011199951171875 +70036 -0.05792236328125 +70037 -0.171051025390625 +70038 -0.1019287109375 +70039 -0.33740234375 +70040 -0.136810302734375 +70041 -0.47198486328125 +70042 -0.1588134765625 +70043 -0.560394287109375 +70044 -0.1622314453125 +70045 -0.58056640625 +70046 -0.151153564453125 +70047 -0.54754638671875 +70048 -0.138214111328125 +70049 -0.508575439453125 +70050 -0.1224365234375 +70051 -0.459503173828125 +70052 -0.1024169921875 +70053 -0.394378662109375 +70054 -0.08868408203125 +70055 -0.35260009765625 +70056 -0.075469970703125 +70057 -0.31170654296875 +70058 -0.043304443359375 +70059 -0.197418212890625 +70060 0.008148193359375 +70061 -0.007965087890625 +70062 0.065826416015625 +70063 0.207489013671875 +70064 0.119232177734375 +70065 0.409210205078125 +70066 0.1617431640625 +70067 0.57208251953125 +70068 0.185455322265625 +70069 0.66595458984375 +70070 0.1820068359375 +70071 0.65875244140625 +70072 0.15594482421875 +70073 0.56744384765625 +70074 0.1177978515625 +70075 0.431396484375 +70076 0.07928466796875 +70077 0.29443359375 +70078 0.047332763671875 +70079 0.182464599609375 +70080 0.013702392578125 +70081 0.06365966796875 +70082 -0.025177001953125 +70083 -0.075958251953125 +70084 -0.056793212890625 +70085 -0.189422607421875 +70086 -0.07977294921875 +70087 -0.271942138671875 +70088 -0.099090576171875 +70089 -0.342529296875 +70090 -0.105010986328125 +70091 -0.364166259765625 +70092 -0.094970703125 +70093 -0.327239990234375 +70094 -0.0809326171875 +70095 -0.2769775390625 +70096 -0.0736083984375 +70097 -0.253692626953125 +70098 -0.069427490234375 +70099 -0.24365234375 +70100 -0.055694580078125 +70101 -0.1983642578125 +70102 -0.032073974609375 +70103 -0.116241455078125 +70104 -0.009124755859375 +70105 -0.036834716796875 +70106 0.011688232421875 +70107 0.034881591796875 +70108 0.02825927734375 +70109 0.09124755859375 +70110 0.034332275390625 +70111 0.10888671875 +70112 0.039794921875 +70113 0.125518798828125 +70114 0.048980712890625 +70115 0.15771484375 +70116 0.054656982421875 +70117 0.17828369140625 +70118 0.052581787109375 +70119 0.17108154296875 +70120 0.041168212890625 +70121 0.129974365234375 +70122 0.027679443359375 +70123 0.082427978515625 +70124 0.011993408203125 +70125 0.027679443359375 +70126 -0.014068603515625 +70127 -0.065643310546875 +70128 -0.04034423828125 +70129 -0.15936279296875 +70130 -0.056060791015625 +70131 -0.21307373046875 +70132 -0.063262939453125 +70133 -0.234649658203125 +70134 -0.0555419921875 +70135 -0.2001953125 +70136 -0.035308837890625 +70137 -0.119171142578125 +70138 -0.01129150390625 +70139 -0.024749755859375 +70140 0.01727294921875 +70141 0.085784912109375 +70142 0.04132080078125 +70143 0.178131103515625 +70144 0.0513916015625 +70145 0.215576171875 +70146 0.0511474609375 +70147 0.211456298828125 +70148 0.043212890625 +70149 0.17523193359375 +70150 0.032684326171875 +70151 0.128753662109375 +70152 0.026519775390625 +70153 0.1019287109375 +70154 0.020050048828125 +70155 0.0743408203125 +70156 0.01263427734375 +70157 0.04327392578125 +70158 0.0111083984375 +70159 0.038177490234375 +70160 0.01953125 +70161 0.076263427734375 +70162 0.0340576171875 +70163 0.14105224609375 +70164 0.044036865234375 +70165 0.186431884765625 +70166 0.044036865234375 +70167 0.188812255859375 +70168 0.03192138671875 +70169 0.1390380859375 +70170 0.00885009765625 +70171 0.041778564453125 +70172 -0.019683837890625 +70173 -0.079437255859375 +70174 -0.052459716796875 +70175 -0.219390869140625 +70176 -0.0870361328125 +70177 -0.367828369140625 +70178 -0.116485595703125 +70179 -0.494873046875 +70180 -0.130584716796875 +70181 -0.556243896484375 +70182 -0.11932373046875 +70183 -0.508697509765625 +70184 -0.088104248046875 +70185 -0.3756103515625 +70186 -0.051361083984375 +70187 -0.218902587890625 +70188 -0.01495361328125 +70189 -0.063751220703125 +70190 0.021453857421875 +70191 0.091552734375 +70192 0.055328369140625 +70193 0.23602294921875 +70194 0.0804443359375 +70195 0.342987060546875 +70196 0.092803955078125 +70197 0.39520263671875 +70198 0.09161376953125 +70199 0.389373779296875 +70200 0.07659912109375 +70201 0.324249267578125 +70202 0.05340576171875 +70203 0.224090576171875 +70204 0.03021240234375 +70205 0.124267578125 +70206 0.0098876953125 +70207 0.037078857421875 +70208 -0.001190185546875 +70209 -0.010101318359375 +70210 -0.003509521484375 +70211 -0.019439697265625 +70212 -0.004486083984375 +70213 -0.022796630859375 +70214 0.000213623046875 +70215 -0.001556396484375 +70216 0.01336669921875 +70217 0.056304931640625 +70218 0.024749755859375 +70219 0.106719970703125 +70220 0.02215576171875 +70221 0.096893310546875 +70222 0.00927734375 +70223 0.042694091796875 +70224 -0.005035400390625 +70225 -0.018035888671875 +70226 -0.01861572265625 +70227 -0.07586669921875 +70228 -0.02880859375 +70229 -0.11944580078125 +70230 -0.03814697265625 +70231 -0.15972900390625 +70232 -0.048004150390625 +70233 -0.202606201171875 +70234 -0.0584716796875 +70235 -0.24859619140625 +70236 -0.071319580078125 +70237 -0.30517578125 +70238 -0.084197998046875 +70239 -0.36212158203125 +70240 -0.09063720703125 +70241 -0.39141845703125 +70242 -0.081878662109375 +70243 -0.35528564453125 +70244 -0.057098388671875 +70245 -0.249969482421875 +70246 -0.02032470703125 +70247 -0.092864990234375 +70248 0.0220947265625 +70249 0.08905029296875 +70250 0.056121826171875 +70251 0.2352294921875 +70252 0.0755615234375 +70253 0.318817138671875 +70254 0.084747314453125 +70255 0.358642578125 +70256 0.08209228515625 +70257 0.347747802734375 +70258 0.0675048828125 +70259 0.28564453125 +70260 0.052764892578125 +70261 0.223175048828125 +70262 0.046356201171875 +70263 0.196746826171875 +70264 0.0421142578125 +70265 0.179840087890625 +70266 0.0361328125 +70267 0.155548095703125 +70268 0.0347900390625 +70269 0.151214599609375 +70270 0.035797119140625 +70271 0.156951904296875 +70272 0.0296630859375 +70273 0.13177490234375 +70274 0.022247314453125 +70275 0.100799560546875 +70276 0.0189208984375 +70277 0.087127685546875 +70278 0.0113525390625 +70279 0.05487060546875 +70280 -0.003448486328125 +70281 -0.009002685546875 +70282 -0.025390625 +70283 -0.10400390625 +70284 -0.054290771484375 +70285 -0.229400634765625 +70286 -0.083282470703125 +70287 -0.35552978515625 +70288 -0.102996826171875 +70289 -0.441925048828125 +70290 -0.110015869140625 +70291 -0.473846435546875 +70292 -0.107513427734375 +70293 -0.464813232421875 +70294 -0.096527099609375 +70295 -0.419097900390625 +70296 -0.076507568359375 +70297 -0.334320068359375 +70298 -0.051513671875 +70299 -0.227935791015625 +70300 -0.02703857421875 +70301 -0.12347412109375 +70302 -0.004638671875 +70303 -0.02764892578125 +70304 0.019866943359375 +70305 0.077667236328125 +70306 0.051300048828125 +70307 0.2132568359375 +70308 0.0919189453125 +70309 0.38885498046875 +70310 0.13671875 +70311 0.582794189453125 +70312 0.171539306640625 +70313 0.734039306640625 +70314 0.1865234375 +70315 0.800140380859375 +70316 0.181060791015625 +70317 0.7783203125 +70318 0.154388427734375 +70319 0.6651611328125 +70320 0.1063232421875 +70321 0.45965576171875 +70322 0.0455322265625 +70323 0.199188232421875 +70324 -0.012725830078125 +70325 -0.050689697265625 +70326 -0.055206298828125 +70327 -0.23297119140625 +70328 -0.077850341796875 +70329 -0.33013916015625 +70330 -0.08673095703125 +70331 -0.368408203125 +70332 -0.089080810546875 +70333 -0.378936767578125 +70334 -0.088470458984375 +70335 -0.376983642578125 +70336 -0.0888671875 +70337 -0.37969970703125 +70338 -0.09130859375 +70339 -0.391510009765625 +70340 -0.089569091796875 +70341 -0.385345458984375 +70342 -0.07916259765625 +70343 -0.3419189453125 +70344 -0.06512451171875 +70345 -0.28289794921875 +70346 -0.057525634765625 +70347 -0.251617431640625 +70348 -0.060577392578125 +70349 -0.266143798828125 +70350 -0.061981201171875 +70351 -0.273345947265625 +70352 -0.048675537109375 +70353 -0.216796875 +70354 -0.027984619140625 +70355 -0.128265380859375 +70356 -0.013946533203125 +70357 -0.068145751953125 +70358 -0.008087158203125 +70359 -0.0430908203125 +70360 -0.0037841796875 +70361 -0.024444580078125 +70362 0.006561279296875 +70363 0.020721435546875 +70364 0.0303955078125 +70365 0.124481201171875 +70366 0.06103515625 +70367 0.25787353515625 +70368 0.08880615234375 +70369 0.379119873046875 +70370 0.111785888671875 +70371 0.47991943359375 +70372 0.12255859375 +70373 0.5281982421875 +70374 0.118194580078125 +70375 0.511138916015625 +70376 0.105072021484375 +70377 0.456207275390625 +70378 0.093414306640625 +70379 0.407470703125 +70380 0.087615966796875 +70381 0.383758544921875 +70382 0.081146240234375 +70383 0.35687255859375 +70384 0.070556640625 +70385 0.31182861328125 +70386 0.056365966796875 +70387 0.250885009765625 +70388 0.03656005859375 +70389 0.1654052734375 +70390 0.006500244140625 +70391 0.035247802734375 +70392 -0.034393310546875 +70393 -0.142059326171875 +70394 -0.0789794921875 +70395 -0.33563232421875 +70396 -0.124725341796875 +70397 -0.5345458984375 +70398 -0.167724609375 +70399 -0.72186279296875 +70400 -0.1943359375 +70401 -0.836669921875 +70402 -0.194488525390625 +70403 -0.8326416015625 +70404 -0.172210693359375 +70405 -0.7296142578125 +70406 -0.138946533203125 +70407 -0.582550048828125 +70408 -0.105010986328125 +70409 -0.440093994140625 +70410 -0.0753173828125 +70411 -0.324310302734375 +70412 -0.043670654296875 +70413 -0.20147705078125 +70414 -0.00518798828125 +70415 -0.044647216796875 +70416 0.03118896484375 +70417 0.103973388671875 +70418 0.056671142578125 +70419 0.202392578125 +70420 0.073699951171875 +70421 0.264495849609375 +70422 0.091796875 +70423 0.338897705078125 +70424 0.114471435546875 +70425 0.443817138671875 +70426 0.134857177734375 +70427 0.545074462890625 +70428 0.14794921875 +70429 0.6173095703125 +70430 0.15228271484375 +70431 0.6524658203125 +70432 0.150604248046875 +70433 0.66339111328125 +70434 0.144378662109375 +70435 0.6561279296875 +70436 0.12908935546875 +70437 0.606781005859375 +70438 0.102264404296875 +70439 0.501190185546875 +70440 0.066925048828125 +70441 0.352783203125 +70442 0.0263671875 +70443 0.176544189453125 +70444 -0.020538330078125 +70445 -0.034820556640625 +70446 -0.06890869140625 +70447 -0.258209228515625 +70448 -0.108367919921875 +70449 -0.44244384765625 +70450 -0.1363525390625 +70451 -0.5753173828125 +70452 -0.15185546875 +70453 -0.65203857421875 +70454 -0.148712158203125 +70455 -0.641632080078125 +70456 -0.13067626953125 +70457 -0.562164306640625 +70458 -0.106781005859375 +70459 -0.458038330078125 +70460 -0.081451416015625 +70461 -0.350555419921875 +70462 -0.05908203125 +70463 -0.260528564453125 +70464 -0.040740966796875 +70465 -0.192108154296875 +70466 -0.026031494140625 +70467 -0.141937255859375 +70468 -0.013641357421875 +70469 -0.1021728515625 +70470 -0.001800537109375 +70471 -0.062896728515625 +70472 0.01165771484375 +70473 -0.011932373046875 +70474 0.029022216796875 +70475 0.062835693359375 +70476 0.04766845703125 +70477 0.148712158203125 +70478 0.066741943359375 +70479 0.241729736328125 +70480 0.087677001953125 +70481 0.34912109375 +70482 0.1077880859375 +70483 0.457305908203125 +70484 0.122711181640625 +70485 0.54388427734375 +70486 0.125457763671875 +70487 0.5728759765625 +70488 0.108642578125 +70489 0.506591796875 +70490 0.07373046875 +70491 0.351226806640625 +70492 0.02886962890625 +70493 0.146514892578125 +70494 -0.015228271484375 +70495 -0.05523681640625 +70496 -0.050811767578125 +70497 -0.21624755859375 +70498 -0.077392578125 +70499 -0.334930419921875 +70500 -0.0931396484375 +70501 -0.402984619140625 +70502 -0.102142333984375 +70503 -0.4412841796875 +70504 -0.113555908203125 +70505 -0.49578857421875 +70506 -0.126129150390625 +70507 -0.5601806640625 +70508 -0.133148193359375 +70509 -0.600738525390625 +70510 -0.1280517578125 +70511 -0.584228515625 +70512 -0.104705810546875 +70513 -0.47930908203125 +70514 -0.061920166015625 +70515 -0.27935791015625 +70516 -0.0047607421875 +70517 -0.0089111328125 +70518 0.053924560546875 +70519 0.268798828125 +70520 0.0997314453125 +70521 0.482818603515625 +70522 0.12664794921875 +70523 0.60369873046875 +70524 0.138336181640625 +70525 0.650421142578125 +70526 0.142852783203125 +70527 0.66400146484375 +70528 0.139556884765625 +70529 0.6414794921875 +70530 0.1263427734375 +70531 0.572540283203125 +70532 0.111358642578125 +70533 0.498138427734375 +70534 0.098907470703125 +70535 0.439453125 +70536 0.0848388671875 +70537 0.375518798828125 +70538 0.0628662109375 +70539 0.274505615234375 +70540 0.027557373046875 +70541 0.1087646484375 +70542 -0.016448974609375 +70543 -0.099395751953125 +70544 -0.06268310546875 +70545 -0.3182373046875 +70546 -0.11126708984375 +70547 -0.5489501953125 +70548 -0.158477783203125 +70549 -0.7738037109375 +70550 -0.193603515625 +70551 -0.86383056640625 +70552 -0.209930419921875 +70553 -0.870391845703125 +70554 -0.2109375 +70555 -0.86895751953125 +70556 -0.199188232421875 +70557 -0.861053466796875 +70558 -0.171234130859375 +70559 -0.765869140625 +70560 -0.12481689453125 +70561 -0.5301513671875 +70562 -0.0614013671875 +70563 -0.214691162109375 +70564 0.010345458984375 +70565 0.137359619140625 +70566 0.080047607421875 +70567 0.474822998046875 +70568 0.1405029296875 +70569 0.76239013671875 +70570 0.18621826171875 +70571 0.867462158203125 +70572 0.2171630859375 +70573 0.870361328125 +70574 0.230926513671875 +70575 0.86480712890625 +70576 0.228485107421875 +70577 0.831817626953125 +70578 0.214630126953125 +70579 0.677581787109375 +70580 0.19049072265625 +70581 0.495880126953125 +70582 0.15972900390625 +70583 0.30767822265625 +70584 0.122772216796875 +70585 0.116180419921875 +70586 0.073272705078125 +70587 -0.110748291015625 +70588 0.009857177734375 +70589 -0.381805419921875 +70590 -0.058837890625 +70591 -0.6572265625 +70592 -0.120758056640625 +70593 -0.857421875 +70594 -0.167266845703125 +70595 -0.870391845703125 +70596 -0.196868896484375 +70597 -0.870391845703125 +70598 -0.21484375 +70599 -0.86444091796875 +70600 -0.228271484375 +70601 -0.85723876953125 +70602 -0.2333984375 +70603 -0.790008544921875 +70604 -0.21929931640625 +70605 -0.62847900390625 +70606 -0.185272216796875 +70607 -0.3956298828125 +70608 -0.13787841796875 +70609 -0.126708984375 +70610 -0.082550048828125 +70611 0.150115966796875 +70612 -0.021636962890625 +70613 0.424041748046875 +70614 0.039459228515625 +70615 0.670623779296875 +70616 0.092926025390625 +70617 0.854522705078125 +70618 0.13519287109375 +70619 0.866485595703125 +70620 0.163116455078125 +70621 0.86920166015625 +70622 0.180267333984375 +70623 0.8653564453125 +70624 0.18927001953125 +70625 0.857147216796875 +70626 0.189453125 +70627 0.766845703125 +70628 0.181793212890625 +70629 0.628509521484375 +70630 0.164886474609375 +70631 0.462127685546875 +70632 0.143829345703125 +70633 0.297210693359375 +70634 0.12109375 +70635 0.14862060546875 +70636 0.092071533203125 +70637 -0.00537109375 +70638 0.058258056640625 +70639 -0.15753173828125 +70640 0.01898193359375 +70641 -0.31304931640625 +70642 -0.028533935546875 +70643 -0.48876953125 +70644 -0.074859619140625 +70645 -0.6416015625 +70646 -0.114990234375 +70647 -0.751373291015625 +70648 -0.15350341796875 +70649 -0.84619140625 +70650 -0.187408447265625 +70651 -0.861297607421875 +70652 -0.209991455078125 +70653 -0.863250732421875 +70654 -0.21490478515625 +70655 -0.856597900390625 +70656 -0.203948974609375 +70657 -0.7498779296875 +70658 -0.187896728515625 +70659 -0.624542236328125 +70660 -0.163787841796875 +70661 -0.47808837890625 +70662 -0.1220703125 +70663 -0.253387451171875 +70664 -0.070770263671875 +70665 0.003692626953125 +70666 -0.021728515625 +70667 0.2257080078125 +70668 0.0267333984375 +70669 0.427154541015625 +70670 0.079681396484375 +70671 0.643218994140625 +70672 0.135101318359375 +70673 0.855926513671875 +70674 0.182952880859375 +70675 0.870361328125 +70676 0.21466064453125 +70677 0.870361328125 +70678 0.23126220703125 +70679 0.862762451171875 +70680 0.232177734375 +70681 0.79669189453125 +70682 0.2158203125 +70683 0.595794677734375 +70684 0.187164306640625 +70685 0.362152099609375 +70686 0.151092529296875 +70687 0.1270751953125 +70688 0.111419677734375 +70689 -0.086944580078125 +70690 0.068756103515625 +70691 -0.2784423828125 +70692 0.017608642578125 +70693 -0.484832763671875 +70694 -0.044891357421875 +70695 -0.729583740234375 +70696 -0.109893798828125 +70697 -0.86688232421875 +70698 -0.166412353515625 +70699 -0.870391845703125 +70700 -0.21331787109375 +70701 -0.86859130859375 +70702 -0.25 +70703 -0.86279296875 +70704 -0.270294189453125 +70705 -0.817962646484375 +70706 -0.26641845703125 +70707 -0.6116943359375 +70708 -0.237152099609375 +70709 -0.3128662109375 +70710 -0.188232421875 +70711 0.039398193359375 +70712 -0.123138427734375 +70713 0.422821044921875 +70714 -0.04766845703125 +70715 0.805145263671875 +70716 0.0264892578125 +70717 0.870361328125 +70718 0.0894775390625 +70719 0.870361328125 +70720 0.139007568359375 +70721 0.860015869140625 +70722 0.173492431640625 +70723 0.727935791015625 +70724 0.191650390625 +70725 0.48114013671875 +70726 0.197296142578125 +70727 0.2059326171875 +70728 0.193939208984375 +70729 -0.06103515625 +70730 0.18310546875 +70731 -0.29913330078125 +70732 0.162261962890625 +70733 -0.516204833984375 +70734 0.1287841796875 +70735 -0.7252197265625 +70736 0.086883544921875 +70737 -0.85980224609375 +70738 0.042388916015625 +70739 -0.870391845703125 +70740 0.000457763671875 +70741 -0.870391845703125 +70742 -0.03045654296875 +70743 -0.858062744140625 +70744 -0.049346923828125 +70745 -0.673004150390625 +70746 -0.06475830078125 +70747 -0.42694091796875 +70748 -0.083831787109375 +70749 -0.2100830078125 +70750 -0.10589599609375 +70751 -0.0362548828125 +70752 -0.125762939453125 +70753 0.10943603515625 +70754 -0.139801025390625 +70755 0.23516845703125 +70756 -0.140869140625 +70757 0.373687744140625 +70758 -0.129150390625 +70759 0.517791748046875 +70760 -0.11517333984375 +70761 0.602783203125 +70762 -0.098114013671875 +70763 0.635711669921875 +70764 -0.07244873046875 +70765 0.655181884765625 +70766 -0.040008544921875 +70767 0.65948486328125 +70768 -0.002349853515625 +70769 0.651275634765625 +70770 0.0361328125 +70771 0.61846923828125 +70772 0.068939208984375 +70773 0.53753662109375 +70774 0.092742919921875 +70775 0.404144287109375 +70776 0.10565185546875 +70777 0.22186279296875 +70778 0.107666015625 +70779 0.003997802734375 +70780 0.1015625 +70781 -0.22100830078125 +70782 0.090606689453125 +70783 -0.42449951171875 +70784 0.0782470703125 +70785 -0.579833984375 +70786 0.07159423828125 +70787 -0.641876220703125 +70788 0.06951904296875 +70789 -0.6177978515625 +70790 0.06121826171875 +70791 -0.575531005859375 +70792 0.0458984375 +70793 -0.526336669921875 +70794 0.032440185546875 +70795 -0.42645263671875 +70796 0.025634765625 +70797 -0.2581787109375 +70798 0.019622802734375 +70799 -0.068695068359375 +70800 0.008209228515625 +70801 0.09222412109375 +70802 -0.005218505859375 +70803 0.232147216796875 +70804 -0.0186767578125 +70805 0.3509521484375 +70806 -0.03692626953125 +70807 0.410064697265625 +70808 -0.064697265625 +70809 0.372955322265625 +70810 -0.098388671875 +70811 0.2554931640625 +70812 -0.129119873046875 +70813 0.10711669921875 +70814 -0.153564453125 +70815 -0.052886962890625 +70816 -0.165679931640625 +70817 -0.186279296875 +70818 -0.156158447265625 +70819 -0.23291015625 +70820 -0.12896728515625 +70821 -0.209442138671875 +70822 -0.095306396484375 +70823 -0.174163818359375 +70824 -0.056793212890625 +70825 -0.126739501953125 +70826 -0.011962890625 +70827 -0.048126220703125 +70828 0.034210205078125 +70829 0.0426025390625 +70830 0.07366943359375 +70831 0.10748291015625 +70832 0.10400390625 +70833 0.1409912109375 +70834 0.133026123046875 +70835 0.19708251953125 +70836 0.159454345703125 +70837 0.273651123046875 +70838 0.173858642578125 +70839 0.31768798828125 +70840 0.178009033203125 +70841 0.341094970703125 +70842 0.176177978515625 +70843 0.368011474609375 +70844 0.164520263671875 +70845 0.37249755859375 +70846 0.134857177734375 +70847 0.30072021484375 +70848 0.088134765625 +70849 0.1517333984375 +70850 0.03570556640625 +70851 -0.01470947265625 +70852 -0.019256591796875 +70853 -0.1883544921875 +70854 -0.075927734375 +70855 -0.372711181640625 +70856 -0.123870849609375 +70857 -0.51397705078125 +70858 -0.155029296875 +70859 -0.57177734375 +70860 -0.167205810546875 +70861 -0.53948974609375 +70862 -0.162567138671875 +70863 -0.43511962890625 +70864 -0.1468505859375 +70865 -0.2962646484375 +70866 -0.126220703125 +70867 -0.161102294921875 +70868 -0.103057861328125 +70869 -0.0435791015625 +70870 -0.0770263671875 +70871 0.060394287109375 +70872 -0.0511474609375 +70873 0.13665771484375 +70874 -0.028778076171875 +70875 0.170135498046875 +70876 -0.010101318359375 +70877 0.16552734375 +70878 0.009490966796875 +70879 0.15728759765625 +70880 0.029693603515625 +70881 0.150787353515625 +70882 0.0452880859375 +70883 0.12200927734375 +70884 0.0567626953125 +70885 0.080108642578125 +70886 0.067535400390625 +70887 0.05126953125 +70888 0.0814208984375 +70889 0.062896728515625 +70890 0.094146728515625 +70891 0.09271240234375 +70892 0.097442626953125 +70893 0.092987060546875 +70894 0.093719482421875 +70895 0.07855224609375 +70896 0.085662841796875 +70897 0.06427001953125 +70898 0.07110595703125 +70899 0.0347900390625 +70900 0.050384521484375 +70901 -0.01171875 +70902 0.02752685546875 +70903 -0.056060791015625 +70904 0.0106201171875 +70905 -0.055511474609375 +70906 0.000579833984375 +70907 -0.010467529296875 +70908 -0.0106201171875 +70909 0.02508544921875 +70910 -0.026336669921875 +70911 0.025665283203125 +70912 -0.041595458984375 +70913 0.017333984375 +70914 -0.055267333984375 +70915 0.00189208984375 +70916 -0.068511962890625 +70917 -0.03173828125 +70918 -0.07904052734375 +70919 -0.071502685546875 +70920 -0.089324951171875 +70921 -0.13543701171875 +70922 -0.098846435546875 +70923 -0.219970703125 +70924 -0.104156494140625 +70925 -0.300506591796875 +70926 -0.1055908203125 +70927 -0.376312255859375 +70928 -0.09912109375 +70929 -0.416107177734375 +70930 -0.07818603515625 +70931 -0.371124267578125 +70932 -0.04376220703125 +70933 -0.242279052734375 +70934 -0.00274658203125 +70935 -0.069732666015625 +70936 0.040863037109375 +70937 0.125640869140625 +70938 0.081634521484375 +70939 0.31268310546875 +70940 0.113433837890625 +70941 0.45501708984375 +70942 0.136077880859375 +70943 0.554779052734375 +70944 0.1490478515625 +70945 0.61065673828125 +70946 0.150421142578125 +70947 0.610931396484375 +70948 0.136627197265625 +70949 0.531463623046875 +70950 0.1102294921875 +70951 0.3883056640625 +70952 0.079559326171875 +70953 0.23468017578125 +70954 0.048858642578125 +70955 0.095245361328125 +70956 0.022613525390625 +70957 -0.00396728515625 +70958 0.00360107421875 +70959 -0.04852294921875 +70960 -0.00994873046875 +70961 -0.055145263671875 +70962 -0.025146484375 +70963 -0.0758056640625 +70964 -0.0455322265625 +70965 -0.138702392578125 +70966 -0.06536865234375 +70967 -0.209197998046875 +70968 -0.084442138671875 +70969 -0.289031982421875 +70970 -0.1025390625 +70971 -0.37884521484375 +70972 -0.116119384765625 +70973 -0.456329345703125 +70974 -0.1243896484375 +70975 -0.51641845703125 +70976 -0.12152099609375 +70977 -0.519287109375 +70978 -0.106781005859375 +70979 -0.458251953125 +70980 -0.0882568359375 +70981 -0.384796142578125 +70982 -0.070098876953125 +70983 -0.323699951171875 +70984 -0.051971435546875 +70985 -0.269287109375 +70986 -0.030487060546875 +70987 -0.1951904296875 +70988 -0.00604248046875 +70989 -0.100006103515625 +70990 0.016754150390625 +70991 -0.01055908203125 +70992 0.04193115234375 +70993 0.1033935546875 +70994 0.0701904296875 +70995 0.24908447265625 +70996 0.09326171875 +70997 0.373199462890625 +70998 0.1082763671875 +70999 0.45806884765625 +71000 0.1163330078125 +71001 0.511474609375 +71002 0.122283935546875 +71003 0.565399169921875 +71004 0.125091552734375 +71005 0.61138916015625 +71006 0.116058349609375 +71007 0.5897216796875 +71008 0.094085693359375 +71009 0.4906005859375 +71010 0.06219482421875 +71011 0.33148193359375 +71012 0.02618408203125 +71013 0.147796630859375 +71014 -0.007232666015625 +71015 -0.01873779296875 +71016 -0.03338623046875 +71017 -0.140289306640625 +71018 -0.048126220703125 +71019 -0.191986083984375 +71020 -0.05267333984375 +71021 -0.184295654296875 +71022 -0.053436279296875 +71023 -0.161834716796875 +71024 -0.056549072265625 +71025 -0.166595458984375 +71026 -0.061248779296875 +71027 -0.19390869140625 +71028 -0.06463623046875 +71029 -0.22442626953125 +71030 -0.070068359375 +71031 -0.279754638671875 +71032 -0.074615478515625 +71033 -0.3389892578125 +71034 -0.0714111328125 +71035 -0.3543701171875 +71036 -0.064117431640625 +71037 -0.348175048828125 +71038 -0.053924560546875 +71039 -0.32598876953125 +71040 -0.036773681640625 +71041 -0.2581787109375 +71042 -0.0123291015625 +71043 -0.139801025390625 +71044 0.016845703125 +71045 0.014617919921875 +71046 0.04132080078125 +71047 0.144378662109375 +71048 0.056610107421875 +71049 0.221038818359375 +71050 0.066436767578125 +71051 0.27069091796875 +71052 0.07086181640625 +71053 0.294036865234375 +71054 0.072967529296875 +71055 0.311767578125 +71056 0.0750732421875 +71057 0.339141845703125 +71058 0.07476806640625 +71059 0.360260009765625 +71060 0.07012939453125 +71061 0.360504150390625 +71062 0.057220458984375 +71063 0.308380126953125 +71064 0.033416748046875 +71065 0.18170166015625 +71066 0.002471923828125 +71067 0.0047607421875 +71068 -0.02880859375 +71069 -0.17559814453125 +71070 -0.053955078125 +71071 -0.3143310546875 +71072 -0.066680908203125 +71073 -0.36785888671875 +71074 -0.070281982421875 +71075 -0.36248779296875 +71076 -0.070709228515625 +71077 -0.343536376953125 +71078 -0.066619873046875 +71079 -0.3018798828125 +71080 -0.057159423828125 +71081 -0.231414794921875 +71082 -0.040374755859375 +71083 -0.117645263671875 +71084 -0.02081298828125 +71085 0.007049560546875 +71086 -0.00604248046875 +71087 0.087982177734375 +71088 0.005615234375 +71089 0.13946533203125 +71090 0.015594482421875 +71091 0.17425537109375 +71092 0.023040771484375 +71093 0.188201904296875 +71094 0.0262451171875 +71095 0.171234130859375 +71096 0.0242919921875 +71097 0.118438720703125 +71098 0.020599365234375 +71099 0.05706787109375 +71100 0.01519775390625 +71101 -0.010711669921875 +71102 0.00701904296875 +71103 -0.0914306640625 +71104 -0.00091552734375 +71105 -0.162322998046875 +71106 -0.0047607421875 +71107 -0.194549560546875 +71108 0.000732421875 +71109 -0.1492919921875 +71110 0.01629638671875 +71111 -0.02166748046875 +71112 0.0333251953125 +71113 0.124053955078125 +71114 0.04156494140625 +71115 0.211151123046875 +71116 0.041351318359375 +71117 0.240447998046875 +71118 0.037017822265625 +71119 0.242218017578125 +71120 0.030120849609375 +71121 0.2257080078125 +71122 0.0213623046875 +71123 0.194366455078125 +71124 0.006561279296875 +71125 0.115509033203125 +71126 -0.01080322265625 +71127 0.0128173828125 +71128 -0.0224609375 +71129 -0.053802490234375 +71130 -0.0318603515625 +71131 -0.110626220703125 +71132 -0.04461669921875 +71133 -0.199493408203125 +71134 -0.05718994140625 +71135 -0.29437255859375 +71136 -0.061065673828125 +71137 -0.33221435546875 +71138 -0.051788330078125 +71139 -0.27972412109375 +71140 -0.036102294921875 +71141 -0.185333251953125 +71142 -0.02496337890625 +71143 -0.128204345703125 +71144 -0.01953125 +71145 -0.115692138671875 +71146 -0.01580810546875 +71147 -0.116455078125 +71148 -0.010650634765625 +71149 -0.105926513671875 +71150 -0.0001220703125 +71151 -0.053955078125 +71152 0.016815185546875 +71153 0.048797607421875 +71154 0.033905029296875 +71155 0.157318115234375 +71156 0.042938232421875 +71157 0.212005615234375 +71158 0.044586181640625 +71159 0.218475341796875 +71160 0.047088623046875 +71161 0.23724365234375 +71162 0.05548095703125 +71163 0.30535888671875 +71164 0.064208984375 +71165 0.38128662109375 +71166 0.065093994140625 +71167 0.404449462890625 +71168 0.06036376953125 +71169 0.3944091796875 +71170 0.054656982421875 +71171 0.3885498046875 +71172 0.04583740234375 +71173 0.362640380859375 +71174 0.029937744140625 +71175 0.27362060546875 +71176 0.006988525390625 +71177 0.11712646484375 +71178 -0.017120361328125 +71179 -0.054901123046875 +71180 -0.036651611328125 +71181 -0.19085693359375 +71182 -0.05078125 +71183 -0.28570556640625 +71184 -0.05926513671875 +71185 -0.339263916015625 +71186 -0.064697265625 +71187 -0.3775634765625 +71188 -0.071685791015625 +71189 -0.445709228515625 +71190 -0.07940673828125 +71191 -0.535064697265625 +71192 -0.086273193359375 +71193 -0.629058837890625 +71194 -0.089324951171875 +71195 -0.697601318359375 +71196 -0.085052490234375 +71197 -0.70391845703125 +71198 -0.073150634765625 +71199 -0.6424560546875 +71200 -0.05169677734375 +71201 -0.491241455078125 +71202 -0.022613525390625 +71203 -0.265716552734375 +71204 0.00775146484375 +71205 -0.023712158203125 +71206 0.03570556640625 +71207 0.201751708984375 +71208 0.057373046875 +71209 0.375823974609375 +71210 0.071197509765625 +71211 0.485076904296875 +71212 0.081146240234375 +71213 0.56884765625 +71214 0.087982177734375 +71215 0.634765625 +71216 0.087066650390625 +71217 0.63763427734375 +71218 0.077301025390625 +71219 0.5660400390625 +71220 0.06427001953125 +71221 0.4720458984375 +71222 0.053466796875 +71223 0.40692138671875 +71224 0.0458984375 +71225 0.3778076171875 +71226 0.041015625 +71227 0.376953125 +71228 0.0357666015625 +71229 0.371978759765625 +71230 0.025177001953125 +71231 0.313140869140625 +71232 0.007843017578125 +71233 0.184417724609375 +71234 -0.01336669921875 +71235 0.011199951171875 +71236 -0.034576416015625 +71237 -0.171051025390625 +71238 -0.0531005859375 +71239 -0.33740234375 +71240 -0.067291259765625 +71241 -0.47198486328125 +71242 -0.075653076171875 +71243 -0.560394287109375 +71244 -0.075958251953125 +71245 -0.58056640625 +71246 -0.06988525390625 +71247 -0.54754638671875 +71248 -0.06256103515625 +71249 -0.508575439453125 +71250 -0.05377197265625 +71251 -0.459503173828125 +71252 -0.043060302734375 +71253 -0.394378662109375 +71254 -0.03472900390625 +71255 -0.35260009765625 +71256 -0.02667236328125 +71257 -0.31170654296875 +71258 -0.011383056640625 +71259 -0.197418212890625 +71260 0.011138916015625 +71261 -0.007965087890625 +71262 0.035614013671875 +71263 0.207489013671875 +71264 0.057830810546875 +71265 0.409210205078125 +71266 0.07513427734375 +71267 0.57208251953125 +71268 0.084381103515625 +71269 0.66595458984375 +71270 0.082305908203125 +71271 0.65875244140625 +71272 0.07080078125 +71273 0.56744384765625 +71274 0.054046630859375 +71275 0.431396484375 +71276 0.036773681640625 +71277 0.29443359375 +71278 0.0218505859375 +71279 0.182464599609375 +71280 0.00616455078125 +71281 0.06365966796875 +71282 -0.01153564453125 +71283 -0.075958251953125 +71284 -0.02618408203125 +71285 -0.189422607421875 +71286 -0.037109375 +71287 -0.271942138671875 +71288 -0.04620361328125 +71289 -0.342529296875 +71290 -0.049591064453125 +71291 -0.364166259765625 +71292 -0.04620361328125 +71293 -0.327239990234375 +71294 -0.04071044921875 +71295 -0.2769775390625 +71296 -0.037353515625 +71297 -0.253692626953125 +71298 -0.0347900390625 +71299 -0.24365234375 +71300 -0.028045654296875 +71301 -0.1983642578125 +71302 -0.01708984375 +71303 -0.116241455078125 +71304 -0.00616455078125 +71305 -0.036834716796875 +71306 0.003997802734375 +71307 0.034881591796875 +71308 0.012451171875 +71309 0.09124755859375 +71310 0.016632080078125 +71311 0.10888671875 +71312 0.020355224609375 +71313 0.125518798828125 +71314 0.025238037109375 +71315 0.15771484375 +71316 0.028411865234375 +71317 0.17828369140625 +71318 0.02813720703125 +71319 0.17108154296875 +71320 0.02374267578125 +71321 0.129974365234375 +71322 0.01812744140625 +71323 0.082427978515625 +71324 0.011260986328125 +71325 0.027679443359375 +71326 0.0 +71327 -0.065643310546875 +71328 -0.0115966796875 +71329 -0.15936279296875 +71330 -0.019195556640625 +71331 -0.21307373046875 +71332 -0.023529052734375 +71333 -0.234649658203125 +71334 -0.022003173828125 +71335 -0.2001953125 +71336 -0.0155029296875 +71337 -0.119171142578125 +71338 -0.007354736328125 +71339 -0.024749755859375 +71340 0.002777099609375 +71341 0.085784912109375 +71342 0.011383056640625 +71343 0.178131103515625 +71344 0.014678955078125 +71345 0.215576171875 +71346 0.01409912109375 +71347 0.211456298828125 +71348 0.0106201171875 +71349 0.17523193359375 +71350 0.006500244140625 +71351 0.128753662109375 +71352 0.004791259765625 +71353 0.1019287109375 +71354 0.003326416015625 +71355 0.0743408203125 +71356 0.001678466796875 +71357 0.04327392578125 +71358 0.002838134765625 +71359 0.038177490234375 +71360 0.00848388671875 +71361 0.076263427734375 +71362 0.01678466796875 +71363 0.14105224609375 +71364 0.02288818359375 +71365 0.186431884765625 +71366 0.024261474609375 +71367 0.188812255859375 +71368 0.019927978515625 +71369 0.1390380859375 +71370 0.010345458984375 +71371 0.041778564453125 +71372 -0.002044677734375 +71373 -0.079437255859375 +71374 -0.016693115234375 +71375 -0.219390869140625 +71376 -0.032501220703125 +71377 -0.367828369140625 +71378 -0.046356201171875 +71379 -0.494873046875 +71380 -0.053619384765625 +71381 -0.556243896484375 +71382 -0.049713134765625 +71383 -0.508697509765625 +71384 -0.037017822265625 +71385 -0.3756103515625 +71386 -0.021942138671875 +71387 -0.218902587890625 +71388 -0.00701904296875 +71389 -0.063751220703125 +71390 0.0079345703125 +71391 0.091552734375 +71392 0.0218505859375 +71393 0.23602294921875 +71394 0.03204345703125 +71395 0.342987060546875 +71396 0.0367431640625 +71397 0.39520263671875 +71398 0.03564453125 +71399 0.389373779296875 +71400 0.028656005859375 +71401 0.324249267578125 +71402 0.018341064453125 +71403 0.224090576171875 +71404 0.00836181640625 +71405 0.124267578125 +71406 -3.0517578125e-05 +71407 0.037078857421875 +71408 -0.0040283203125 +71409 -0.010101318359375 +71410 -0.003936767578125 +71411 -0.019439697265625 +71412 -0.00311279296875 +71413 -0.022796630859375 +71414 0.000274658203125 +71415 -0.001556396484375 +71416 0.00738525390625 +71417 0.056304931640625 +71418 0.013580322265625 +71419 0.106719970703125 +71420 0.013336181640625 +71421 0.096893310546875 +71422 0.008270263671875 +71423 0.042694091796875 +71424 0.002593994140625 +71425 -0.018035888671875 +71426 -0.00286865234375 +71427 -0.07586669921875 +71428 -0.007537841796875 +71429 -0.11944580078125 +71430 -0.01202392578125 +71431 -0.15972900390625 +71432 -0.0166015625 +71433 -0.202606201171875 +71434 -0.02117919921875 +71435 -0.24859619140625 +71436 -0.02618408203125 +71437 -0.30517578125 +71438 -0.030853271484375 +71439 -0.36212158203125 +71440 -0.033172607421875 +71441 -0.39141845703125 +71442 -0.030426025390625 +71443 -0.35528564453125 +71444 -0.022369384765625 +71445 -0.249969482421875 +71446 -0.010284423828125 +71447 -0.092864990234375 +71448 0.0037841796875 +71449 0.08905029296875 +71450 0.015411376953125 +71451 0.2352294921875 +71452 0.022613525390625 +71453 0.318817138671875 +71454 0.026641845703125 +71455 0.358642578125 +71456 0.026947021484375 +71457 0.347747802734375 +71458 0.0234375 +71459 0.28564453125 +71460 0.01971435546875 +71461 0.223175048828125 +71462 0.018341064453125 +71463 0.196746826171875 +71464 0.01739501953125 +71465 0.179840087890625 +71466 0.01568603515625 +71467 0.155548095703125 +71468 0.015167236328125 +71469 0.151214599609375 +71470 0.01513671875 +71471 0.156951904296875 +71472 0.0126953125 +71473 0.13177490234375 +71474 0.00970458984375 +71475 0.100799560546875 +71476 0.007843017578125 +71477 0.087127685546875 +71478 0.004608154296875 +71479 0.05487060546875 +71480 -0.000885009765625 +71481 -0.009002685546875 +71482 -0.008544921875 +71483 -0.10400390625 +71484 -0.018280029296875 +71485 -0.229400634765625 +71486 -0.027923583984375 +71487 -0.35552978515625 +71488 -0.034515380859375 +71489 -0.441925048828125 +71490 -0.037017822265625 +71491 -0.473846435546875 +71492 -0.036376953125 +71493 -0.464813232421875 +71494 -0.03289794921875 +71495 -0.419097900390625 +71496 -0.02642822265625 +71497 -0.334320068359375 +71498 -0.01824951171875 +71499 -0.227935791015625 +71500 -0.010101318359375 +71501 -0.12347412109375 +71502 -0.00250244140625 +71503 -0.02764892578125 +71504 0.00579833984375 +71505 0.077667236328125 +71506 0.0162353515625 +71507 0.2132568359375 +71508 0.02947998046875 +71509 0.38885498046875 +71510 0.0439453125 +71511 0.582794189453125 +71512 0.055206298828125 +71513 0.734039306640625 +71514 0.0601806640625 +71515 0.800140380859375 +71516 0.058685302734375 +71517 0.7783203125 +71518 0.05047607421875 +71519 0.6651611328125 +71520 0.035491943359375 +71521 0.45965576171875 +71522 0.016448974609375 +71523 0.199188232421875 +71524 -0.00189208984375 +71525 -0.050689697265625 +71526 -0.015411376953125 +71527 -0.23297119140625 +71528 -0.0228271484375 +71529 -0.33013916015625 +71530 -0.0260009765625 +71531 -0.368408203125 +71532 -0.02716064453125 +71533 -0.378936767578125 +71534 -0.027435302734375 +71535 -0.376983642578125 +71536 -0.02801513671875 +71537 -0.37969970703125 +71538 -0.0291748046875 +71539 -0.391510009765625 +71540 -0.028961181640625 +71541 -0.385345458984375 +71542 -0.025970458984375 +71543 -0.3419189453125 +71544 -0.021728515625 +71545 -0.28289794921875 +71546 -0.019378662109375 +71547 -0.251617431640625 +71548 -0.020233154296875 +71549 -0.266143798828125 +71550 -0.020477294921875 +71551 -0.273345947265625 +71552 -0.016082763671875 +71553 -0.216796875 +71554 -0.00933837890625 +71555 -0.128265380859375 +71556 -0.00457763671875 +71557 -0.068145751953125 +71558 -0.0023193359375 +71559 -0.0430908203125 +71560 -0.000518798828125 +71561 -0.024444580078125 +71562 0.00311279296875 +71563 0.020721435546875 +71564 0.0108642578125 +71565 0.124481201171875 +71566 0.0206298828125 +71567 0.25787353515625 +71568 0.0294189453125 +71569 0.379119873046875 +71570 0.03662109375 +71571 0.47991943359375 +71572 0.0399169921875 +71573 0.5281982421875 +71574 0.03839111328125 +71575 0.511138916015625 +71576 0.0340576171875 +71577 0.456207275390625 +71578 0.03009033203125 +71579 0.407470703125 +71580 0.02789306640625 +71581 0.383758544921875 +71582 0.02545166015625 +71583 0.35687255859375 +71584 0.021728515625 +71585 0.31182861328125 +71586 0.01690673828125 +71587 0.250885009765625 +71588 0.0103759765625 +71589 0.1654052734375 +71590 0.000732421875 +71591 0.035247802734375 +71592 -0.01214599609375 +71593 -0.142059326171875 +71594 -0.026031494140625 +71595 -0.33563232421875 +71596 -0.0401611328125 +71597 -0.5345458984375 +71598 -0.053314208984375 +71599 -0.72186279296875 +71600 -0.061126708984375 +71601 -0.836669921875 +71602 -0.060302734375 +71603 -0.8326416015625 +71604 -0.05230712890625 +71605 -0.7296142578125 +71606 -0.04119873046875 +71607 -0.582550048828125 +71608 -0.030487060546875 +71609 -0.440093994140625 +71610 -0.021728515625 +71611 -0.324310302734375 +71612 -0.01251220703125 +71613 -0.20147705078125 +71614 -0.00091552734375 +71615 -0.044647216796875 +71616 0.00994873046875 +71617 0.103973388671875 +71618 0.017059326171875 +71619 0.202392578125 +71620 0.02142333984375 +71621 0.264495849609375 +71622 0.02655029296875 +71623 0.338897705078125 +71624 0.03375244140625 +71625 0.443817138671875 +71626 0.04058837890625 +71627 0.545074462890625 +71628 0.0452880859375 +71629 0.6173095703125 +71630 0.047271728515625 +71631 0.6524658203125 +71632 0.047515869140625 +71633 0.66339111328125 +71634 0.046478271484375 +71635 0.6561279296875 +71636 0.04241943359375 +71637 0.606781005859375 +71638 0.034393310546875 +71639 0.501190185546875 +71640 0.02337646484375 +71641 0.352783203125 +71642 0.010467529296875 +71643 0.176544189453125 +71644 -0.004791259765625 +71645 -0.034820556640625 +71646 -0.020751953125 +71647 -0.258209228515625 +71648 -0.033721923828125 +71649 -0.44244384765625 +71650 -0.0428466796875 +71651 -0.5753173828125 +71652 -0.047821044921875 +71653 -0.65203857421875 +71654 -0.04644775390625 +71655 -0.641632080078125 +71656 -0.040130615234375 +71657 -0.562164306640625 +71658 -0.032073974609375 +71659 -0.458038330078125 +71660 -0.023834228515625 +71661 -0.350555419921875 +71662 -0.01690673828125 +71663 -0.260528564453125 +71664 -0.011627197265625 +71665 -0.192108154296875 +71666 -0.00775146484375 +71667 -0.141937255859375 +71668 -0.004730224609375 +71669 -0.1021728515625 +71670 -0.001861572265625 +71671 -0.062896728515625 +71672 0.001708984375 +71673 -0.011932373046875 +71674 0.006866455078125 +71675 0.062835693359375 +71676 0.012725830078125 +71677 0.148712158203125 +71678 0.019012451171875 +71679 0.241729736328125 +71680 0.02593994140625 +71681 0.34912109375 +71682 0.031829833984375 +71683 0.457305908203125 +71684 0.03515625 +71685 0.54388427734375 +71686 0.034881591796875 +71687 0.5728759765625 +71688 0.02984619140625 +71689 0.506591796875 +71690 0.020660400390625 +71691 0.351226806640625 +71692 0.00921630859375 +71693 0.146514892578125 +71694 -0.002105712890625 +71695 -0.05523681640625 +71696 -0.011566162109375 +71697 -0.21624755859375 +71698 -0.018951416015625 +71699 -0.334930419921875 +71700 -0.02374267578125 +71701 -0.402984619140625 +71702 -0.02667236328125 +71703 -0.4412841796875 +71704 -0.029541015625 +71705 -0.49578857421875 +71706 -0.032135009765625 +71707 -0.5601806640625 +71708 -0.03314208984375 +71709 -0.600738525390625 +71710 -0.03131103515625 +71711 -0.584228515625 +71712 -0.025482177734375 +71713 -0.47930908203125 +71714 -0.0155029296875 +71715 -0.27935791015625 +71716 -0.00250244140625 +71717 -0.0089111328125 +71718 0.0108642578125 +71719 0.268798828125 +71720 0.021575927734375 +71721 0.482818603515625 +71722 0.02838134765625 +71723 0.60369873046875 +71724 0.031890869140625 +71725 0.650421142578125 +71726 0.033721923828125 +71727 0.66400146484375 +71728 0.033660888671875 +71729 0.6414794921875 +71730 0.031280517578125 +71731 0.572540283203125 +71732 0.0281982421875 +71733 0.498138427734375 +71734 0.025299072265625 +71735 0.439453125 +71736 0.02178955078125 +71737 0.375518798828125 +71738 0.016448974609375 +71739 0.274505615234375 +71740 0.008270263671875 +71741 0.1087646484375 +71742 -0.001739501953125 +71743 -0.099395751953125 +71744 -0.012237548828125 +71745 -0.3182373046875 +71746 -0.023162841796875 +71747 -0.5489501953125 +71748 -0.033660888671875 +71749 -0.7738037109375 +71750 -0.04156494140625 +71751 -0.86383056640625 +71752 -0.045501708984375 +71753 -0.870391845703125 +71754 -0.046142578125 +71755 -0.86895751953125 +71756 -0.043975830078125 +71757 -0.861053466796875 +71758 -0.038330078125 +71759 -0.765869140625 +71760 -0.02874755859375 +71761 -0.5301513671875 +71762 -0.01556396484375 +71763 -0.214691162109375 +71764 -0.000518798828125 +71765 0.137359619140625 +71766 0.014251708984375 +71767 0.474822998046875 +71768 0.0272216796875 +71769 0.76239013671875 +71770 0.037261962890625 +71771 0.867462158203125 +71772 0.0443115234375 +71773 0.870361328125 +71774 0.047821044921875 +71775 0.86480712890625 +71776 0.0479736328125 +71777 0.831817626953125 +71778 0.045684814453125 +71779 0.677581787109375 +71780 0.041168212890625 +71781 0.495880126953125 +71782 0.03515625 +71783 0.30767822265625 +71784 0.027740478515625 +71785 0.116180419921875 +71786 0.017669677734375 +71787 -0.110748291015625 +71788 0.004669189453125 +71789 -0.381805419921875 +71790 -0.009490966796875 +71791 -0.6572265625 +71792 -0.022369384765625 +71793 -0.857421875 +71794 -0.032196044921875 +71795 -0.870391845703125 +71796 -0.03863525390625 +71797 -0.870391845703125 +71798 -0.042755126953125 +71799 -0.86444091796875 +71800 -0.045928955078125 +71801 -0.85723876953125 +71802 -0.047393798828125 +71803 -0.790008544921875 +71804 -0.044952392578125 +71805 -0.62847900390625 +71806 -0.0384521484375 +71807 -0.3956298828125 +71808 -0.0291748046875 +71809 -0.126708984375 +71810 -0.0181884765625 +71811 0.150115966796875 +71812 -0.005950927734375 +71813 0.424041748046875 +71814 0.00640869140625 +71815 0.670623779296875 +71816 0.017303466796875 +71817 0.854522705078125 +71818 0.026031494140625 +71819 0.866485595703125 +71820 0.03192138671875 +71821 0.86920166015625 +71822 0.03570556640625 +71823 0.8653564453125 +71824 0.037872314453125 +71825 0.857147216796875 +71826 0.03826904296875 +71827 0.766845703125 +71828 0.037078857421875 +71829 0.628509521484375 +71830 0.03399658203125 +71831 0.462127685546875 +71832 0.029998779296875 +71833 0.297210693359375 +71834 0.025543212890625 +71835 0.14862060546875 +71836 0.019744873046875 +71837 -0.00537109375 +71838 0.012908935546875 +71839 -0.15753173828125 +71840 0.004913330078125 +71841 -0.31304931640625 +71842 -0.0047607421875 +71843 -0.48876953125 +71844 -0.01422119140625 +71845 -0.6416015625 +71846 -0.0224609375 +71847 -0.751373291015625 +71848 -0.030364990234375 +71849 -0.84619140625 +71850 -0.03729248046875 +71851 -0.861297607421875 +71852 -0.04193115234375 +71853 -0.863250732421875 +71854 -0.042999267578125 +71855 -0.856597900390625 +71856 -0.040985107421875 +71857 -0.7498779296875 +71858 -0.038177490234375 +71859 -0.624542236328125 +71860 -0.03369140625 +71861 -0.47808837890625 +71862 -0.02520751953125 +71863 -0.253387451171875 +71864 -0.014556884765625 +71865 0.003692626953125 +71866 -0.004486083984375 +71867 0.2257080078125 +71868 0.005462646484375 +71869 0.427154541015625 +71870 0.01654052734375 +71871 0.643218994140625 +71872 0.028350830078125 +71873 0.855926513671875 +71874 0.03857421875 +71875 0.870361328125 +71876 0.045257568359375 +71877 0.870361328125 +71878 0.048675537109375 +71879 0.862762451171875 +71880 0.0487060546875 +71881 0.79669189453125 +71882 0.04498291015625 +71883 0.595794677734375 +71884 0.038665771484375 +71885 0.362152099609375 +71886 0.0308837890625 +71887 0.1270751953125 +71888 0.022491455078125 +71889 -0.086944580078125 +71890 0.013580322265625 +71891 -0.2784423828125 +71892 0.00274658203125 +71893 -0.484832763671875 +71894 -0.010711669921875 +71895 -0.729583740234375 +71896 -0.0247802734375 +71897 -0.86688232421875 +71898 -0.036956787109375 +71899 -0.870391845703125 +71900 -0.046966552734375 +71901 -0.86859130859375 +71902 -0.05474853515625 +71903 -0.86279296875 +71904 -0.058868408203125 +71905 -0.817962646484375 +71906 -0.057525634765625 +71907 -0.6116943359375 +71908 -0.050445556640625 +71909 -0.3128662109375 +71910 -0.03900146484375 +71911 0.039398193359375 +71912 -0.024017333984375 +71913 0.422821044921875 +71914 -0.006805419921875 +71915 0.805145263671875 +71916 0.00982666015625 +71917 0.870361328125 +71918 0.02362060546875 +71919 0.870361328125 +71920 0.034088134765625 +71921 0.860015869140625 +71922 0.04095458984375 +71923 0.727935791015625 +71924 0.04400634765625 +71925 0.48114013671875 +71926 0.044219970703125 +71927 0.2059326171875 +71928 0.04248046875 +71929 -0.06103515625 +71930 0.0391845703125 +71931 -0.29913330078125 +71932 0.03375244140625 +71933 -0.516204833984375 +71934 0.025634765625 +71935 -0.7252197265625 +71936 0.015625 +71937 -0.85980224609375 +71938 0.005523681640625 +71939 -0.870391845703125 +71940 -0.003387451171875 +71941 -0.870391845703125 +71942 -0.010711669921875 +71943 -0.858062744140625 +71944 -0.016326904296875 +71945 -0.673004150390625 +71946 -0.020599365234375 +71947 -0.42694091796875 +71948 -0.02386474609375 +71949 -0.2100830078125 +71950 -0.026092529296875 +71951 -0.0362548828125 +71952 -0.02703857421875 +71953 0.10943603515625 +71954 -0.026641845703125 +71955 0.23516845703125 +71956 -0.024658203125 +71957 0.373687744140625 +71958 -0.021209716796875 +71959 0.517791748046875 +71960 -0.016998291015625 +71961 0.602783203125 +71962 -0.01214599609375 +71963 0.635711669921875 +71964 -0.00665283203125 +71965 0.655181884765625 +71966 -0.00079345703125 +71967 0.65948486328125 +71968 0.00506591796875 +71969 0.651275634765625 +71970 0.010498046875 +71971 0.61846923828125 +71972 0.015045166015625 +71973 0.53753662109375 +71974 0.0184326171875 +71975 0.404144287109375 +71976 0.02044677734375 +71977 0.22186279296875 +71978 0.0211181640625 +71979 0.003997802734375 +71980 0.020538330078125 +71981 -0.22100830078125 +71982 0.018890380859375 +71983 -0.42449951171875 +71984 0.016448974609375 +71985 -0.579833984375 +71986 0.013641357421875 +71987 -0.641876220703125 +71988 0.01055908203125 +71989 -0.6177978515625 +71990 0.006866455078125 +71991 -0.575531005859375 +71992 0.002716064453125 +71993 -0.526336669921875 +71994 -0.00128173828125 +71995 -0.42645263671875 +71996 -0.00469970703125 +71997 -0.2581787109375 +71998 -0.00762939453125 +71999 -0.068695068359375 +72000 -0.010223388671875 +72001 0.09222412109375 +72002 -0.012237548828125 +72003 0.232147216796875 +72004 -0.013519287109375 +72005 0.3509521484375 +72006 -0.0142822265625 +72007 0.410064697265625 +72008 -0.0147705078125 +72009 0.372955322265625 +72010 -0.014892578125 +72011 0.2554931640625 +72012 -0.014312744140625 +72013 0.10711669921875 +72014 -0.01300048828125 +72015 -0.052886962890625 +72016 -0.01080322265625 +72017 -0.186279296875 +72018 -0.0074462890625 +72019 -0.23291015625 +72020 -0.0032958984375 +72021 -0.209442138671875 +72022 0.00091552734375 +72023 -0.174163818359375 +72024 0.004974365234375 +72025 -0.126739501953125 +72026 0.008819580078125 +72027 -0.048126220703125 +72028 0.01214599609375 +72029 0.0426025390625 +72030 0.014495849609375 +72031 0.10748291015625 +72032 0.015777587890625 +72033 0.1409912109375 +72034 0.016387939453125 +72035 0.19708251953125 +72036 0.016357421875 +72037 0.273651123046875 +72038 0.01531982421875 +72039 0.31768798828125 +72040 0.01348876953125 +72041 0.341094970703125 +72042 0.01116943359375 +72043 0.368011474609375 +72044 0.00830078125 +72045 0.37249755859375 +72046 0.004608154296875 +72047 0.30072021484375 +72048 0.000274658203125 +72049 0.1517333984375 +72050 -0.003997802734375 +72051 -0.01470947265625 +72052 -0.00799560546875 +72053 -0.1883544921875 +72054 -0.011627197265625 +72055 -0.372711181640625 +72056 -0.01434326171875 +72057 -0.51397705078125 +72058 -0.015777587890625 +72059 -0.57177734375 +72060 -0.015838623046875 +72061 -0.53948974609375 +72062 -0.0146484375 +72063 -0.43511962890625 +72064 -0.012542724609375 +72065 -0.2962646484375 +72066 -0.0098876953125 +72067 -0.161102294921875 +72068 -0.006927490234375 +72069 -0.0435791015625 +72070 -0.003753662109375 +72071 0.060394287109375 +72072 -0.0006103515625 +72073 0.13665771484375 +72074 0.002197265625 +72075 0.170135498046875 +72076 0.004608154296875 +72077 0.16552734375 +72078 0.0067138671875 +72079 0.15728759765625 +72080 0.00848388671875 +72081 0.150787353515625 +72082 0.009613037109375 +72083 0.12200927734375 +72084 0.0101318359375 +72085 0.080108642578125 +72086 0.010223388671875 +72087 0.05126953125 +72088 0.01007080078125 +72089 0.062896728515625 +72090 0.009552001953125 +72091 0.09271240234375 +72092 0.00836181640625 +72093 0.092987060546875 +72094 0.00665283203125 +72095 0.07855224609375 +72096 0.004669189453125 +72097 0.06427001953125 +72098 0.002410888671875 +72099 0.0347900390625 +72100 0.0 +72101 -0.01171875 +72102 -0.0023193359375 +72103 -0.056060791015625 +72104 -0.00408935546875 +72105 -0.055511474609375 +72106 -0.005218505859375 +72107 -0.010467529296875 +72108 -0.006103515625 +72109 0.02508544921875 +72110 -0.006866455078125 +72111 0.025665283203125 +72112 -0.00726318359375 +72113 0.017333984375 +72114 -0.007293701171875 +72115 0.00189208984375 +72116 -0.007049560546875 +72117 -0.03173828125 +72118 -0.0064697265625 +72119 -0.071502685546875 +72120 -0.005767822265625 +72121 -0.13543701171875 +72122 -0.004974365234375 +72123 -0.219970703125 +72124 -0.00396728515625 +72125 -0.300506591796875 +72126 -0.002838134765625 +72127 -0.376312255859375 +72128 -0.001434326171875 +72129 -0.416107177734375 +72130 0.000518798828125 +72131 -0.371124267578125 +72132 0.002899169921875 +72133 -0.242279052734375 +72134 0.00531005859375 +72135 -0.069732666015625 +72136 0.007537841796875 +72137 0.125640869140625 +72138 0.009307861328125 +72139 0.31268310546875 +72140 0.01031494140625 +72141 0.45501708984375 +72142 0.0106201171875 +72143 0.554779052734375 +72144 0.01025390625 +72145 0.61065673828125 +72146 0.0091552734375 +72147 0.610931396484375 +72148 0.0072021484375 +72149 0.531463623046875 +72150 0.004608154296875 +72151 0.3883056640625 +72152 0.00189208984375 +72153 0.23468017578125 +72154 -0.0006103515625 +72155 0.095245361328125 +72156 -0.00262451171875 +72157 -0.00396728515625 +72158 -0.0040283203125 +72159 -0.04852294921875 +72160 -0.0048828125 +72161 -0.055145263671875 +72162 -0.00555419921875 +72163 -0.0758056640625 +72164 -0.0062255859375 +72165 -0.138702392578125 +72166 -0.00665283203125 +72167 -0.209197998046875 +72168 -0.006866455078125 +72169 -0.289031982421875 +72170 -0.006866455078125 +72171 -0.37884521484375 +72172 -0.006561279296875 +72173 -0.456329345703125 +72174 -0.005950927734375 +72175 -0.51641845703125 +72176 -0.0047607421875 +72177 -0.519287109375 +72178 -0.003021240234375 +72179 -0.458251953125 +72180 -0.001220703125 +72181 -0.384796142578125 +72182 0.000335693359375 +72183 -0.323699951171875 +72184 0.001678466796875 +72185 -0.269287109375 +72186 0.002960205078125 +72187 -0.1951904296875 +72188 0.004150390625 +72189 -0.100006103515625 +72190 0.005035400390625 +72191 -0.01055908203125 +72192 0.00567626953125 +72193 0.1033935546875 +72194 0.006195068359375 +72195 0.24908447265625 +72196 0.00653076171875 +72197 0.373199462890625 +72198 0.006591796875 +72199 0.45806884765625 +72200 0.00634765625 +72201 0.511474609375 +72202 0.005767822265625 +72203 0.565399169921875 +72204 0.004852294921875 +72205 0.61138916015625 +72206 0.003662109375 +72207 0.5897216796875 +72208 0.00225830078125 +72209 0.4906005859375 +72210 0.000701904296875 +72211 0.33148193359375 +72212 -0.0008544921875 +72213 0.147796630859375 +72214 -0.0023193359375 +72215 -0.01873779296875 +72216 -0.00360107421875 +72217 -0.140289306640625 +72218 -0.004608154296875 +72219 -0.191986083984375 +72220 -0.00531005859375 +72221 -0.184295654296875 +72222 -0.00567626953125 +72223 -0.161834716796875 +72224 -0.005706787109375 +72225 -0.166595458984375 +72226 -0.005401611328125 +72227 -0.19390869140625 +72228 -0.004791259765625 +72229 -0.22442626953125 +72230 -0.00390625 +72231 -0.279754638671875 +72232 -0.0028076171875 +72233 -0.3389892578125 +72234 -0.001556396484375 +72235 -0.3543701171875 +72236 -0.000213623046875 +72237 -0.348175048828125 +72238 0.0010986328125 +72239 -0.32598876953125 +72240 0.0023193359375 +72241 -0.2581787109375 +72242 0.003387451171875 +72243 -0.139801025390625 +72244 0.004241943359375 +72245 0.014617919921875 +72246 0.004852294921875 +72247 0.144378662109375 +72248 0.00518798828125 +72249 0.221038818359375 +72250 0.005218505859375 +72251 0.27069091796875 +72252 0.004974365234375 +72253 0.294036865234375 +72254 0.00445556640625 +72255 0.311767578125 +72256 0.003753662109375 +72257 0.339141845703125 +72258 0.00323486328125 +72259 0.360260009765625 +72260 0.002838134765625 +72261 0.360504150390625 +72262 0.001739501953125 +72263 0.308380126953125 +72264 -0.00067138671875 +72265 0.18170166015625 +72266 -0.003875732421875 +72267 0.0047607421875 +72268 -0.00689697265625 +72269 -0.17559814453125 +72270 -0.008758544921875 +72271 -0.3143310546875 +72272 -0.008544921875 +72273 -0.36785888671875 +72274 -0.006988525390625 +72275 -0.36248779296875 +72276 -0.0052490234375 +72277 -0.343536376953125 +72278 -0.003173828125 +72279 -0.3018798828125 +72280 -0.00067138671875 +72281 -0.231414794921875 +72282 0.002532958984375 +72283 -0.117645263671875 +72284 0.005615234375 +72285 0.007049560546875 +72286 0.00732421875 +72287 0.087982177734375 +72288 0.008026123046875 +72289 0.13946533203125 +72290 0.008056640625 +72291 0.17425537109375 +72292 0.007415771484375 +72293 0.188201904296875 +72294 0.00592041015625 +72295 0.171234130859375 +72296 0.00347900390625 +72297 0.118438720703125 +72298 0.0008544921875 +72299 0.05706787109375 +72300 -0.001800537109375 +72301 -0.010711669921875 +72302 -0.004608154296875 +72303 -0.0914306640625 +72304 -0.006988525390625 +72305 -0.162322998046875 +72306 -0.00823974609375 +72307 -0.194549560546875 +72308 -0.007415771484375 +72309 -0.1492919921875 +72310 -0.004364013671875 +72311 -0.02166748046875 +72312 -0.00067138671875 +72313 0.124053955078125 +72314 0.001800537109375 +72315 0.211151123046875 +72316 0.003021240234375 +72317 0.240447998046875 +72318 0.00372314453125 +72319 0.242218017578125 +72320 0.00408935546875 +72321 0.2257080078125 +72322 0.004119873046875 +72323 0.194366455078125 +72324 0.003021240234375 +72325 0.115509033203125 +72326 0.0013427734375 +72327 0.0128173828125 +72328 0.000457763671875 +72329 -0.053802490234375 +72330 -0.000274658203125 +72331 -0.110626220703125 +72332 -0.00189208984375 +72333 -0.199493408203125 +72334 -0.003814697265625 +72335 -0.29437255859375 +72336 -0.0045166015625 +72337 -0.33221435546875 +72338 -0.00323486328125 +72339 -0.27972412109375 +72340 -0.0010986328125 +72341 -0.185333251953125 +72342 0.0 +72343 -0.128204345703125 +72344 -9.1552734375e-05 +72345 -0.115692138671875 +72346 -0.0006103515625 +72347 -0.116455078125 +72348 -0.000946044921875 +72349 -0.105926513671875 +72350 -0.000335693359375 +72351 -0.053955078125 +72352 0.00146484375 +72353 0.048797607421875 +72354 0.003387451171875 +72355 0.157318115234375 +72356 0.004058837890625 +72357 0.212005615234375 +72358 0.003631591796875 +72359 0.218475341796875 +72360 0.003570556640625 +72361 0.23724365234375 +72362 0.00482177734375 +72363 0.30535888671875 +72364 0.006378173828125 +72365 0.38128662109375 +72366 0.0068359375 +72367 0.404449462890625 +72368 0.00665283203125 +72369 0.3944091796875 +72370 0.006744384765625 +72371 0.3885498046875 +72372 0.006500244140625 +72373 0.362640380859375 +72374 0.0048828125 +72375 0.27362060546875 +72376 0.001739501953125 +72377 0.11712646484375 +72378 -0.001708984375 +72379 -0.054901123046875 +72380 -0.004241943359375 +72381 -0.19085693359375 +72382 -0.005828857421875 +72383 -0.28570556640625 +72384 -0.0064697265625 +72385 -0.339263916015625 +72386 -0.0068359375 +72387 -0.3775634765625 +72388 -0.008026123046875 +72389 -0.445709228515625 +72390 -0.00982666015625 +72391 -0.535064697265625 +72392 -0.011871337890625 +72393 -0.629058837890625 +72394 -0.013427734375 +72395 -0.697601318359375 +72396 -0.013641357421875 +72397 -0.70391845703125 +72398 -0.012359619140625 +72399 -0.6424560546875 +72400 -0.009033203125 +72401 -0.491241455078125 +72402 -0.0040283203125 +72403 -0.265716552734375 +72404 0.001220703125 +72405 -0.023712158203125 +72406 0.0059814453125 +72407 0.201751708984375 +72408 0.009429931640625 +72409 0.375823974609375 +72410 0.011322021484375 +72411 0.485076904296875 +72412 0.012664794921875 +72413 0.56884765625 +72414 0.013671875 +72415 0.634765625 +72416 0.01324462890625 +72417 0.63763427734375 +72418 0.01116943359375 +72419 0.5660400390625 +72420 0.008697509765625 +72421 0.4720458984375 +72422 0.007080078125 +72423 0.40692138671875 +72424 0.006500244140625 +72425 0.3778076171875 +72426 0.006744384765625 +72427 0.376953125 +72428 0.006988525390625 +72429 0.371978759765625 +72430 0.006011962890625 +72431 0.313140869140625 +72432 0.003387451171875 +72433 0.184417724609375 +72434 -0.000244140625 +72435 0.011199951171875 +72436 -0.0040283203125 +72437 -0.171051025390625 +72438 -0.00738525390625 +72439 -0.33740234375 +72440 -0.010009765625 +72441 -0.47198486328125 +72442 -0.0115966796875 +72443 -0.560394287109375 +72444 -0.01165771484375 +72445 -0.58056640625 +72446 -0.01055908203125 +72447 -0.54754638671875 +72448 -0.00958251953125 +72449 -0.508575439453125 +72450 -0.008392333984375 +72451 -0.459503173828125 +72452 -0.007049560546875 +72453 -0.394378662109375 +72454 -0.00762939453125 +72455 -0.35260009765625 +72456 -0.00872802734375 +72457 -0.31170654296875 +72458 -0.006011962890625 +72459 -0.197418212890625 +72460 0.00079345703125 +72461 -0.007965087890625 +72462 0.00909423828125 +72463 0.207489013671875 +72464 0.016845703125 +72465 0.409210205078125 +72466 0.0228271484375 +72467 0.57208251953125 +72468 0.0255126953125 +72469 0.66595458984375 +72470 0.023223876953125 +72471 0.65875244140625 +72472 0.016998291015625 +72473 0.56744384765625 +72474 0.00909423828125 +72475 0.431396484375 +72476 0.001953125 +72477 0.29443359375 +72478 -0.00299072265625 +72479 0.182464599609375 +72480 -0.00762939453125 +72481 0.06365966796875 +72482 -0.012847900390625 +72483 -0.075958251953125 +72484 -0.01617431640625 +72485 -0.189422607421875 +72486 -0.017486572265625 +72487 -0.271942138671875 +72488 -0.01806640625 +72489 -0.342529296875 +72490 -0.01605224609375 +72491 -0.364166259765625 +72492 -0.011077880859375 +72493 -0.327239990234375 +72494 -0.005828857421875 +72495 -0.2769775390625 +72496 -0.002655029296875 +72497 -0.253692626953125 +72498 -0.000885009765625 +72499 -0.24365234375 +72500 0.00213623046875 +72501 -0.1983642578125 +72502 0.006500244140625 +72503 -0.116241455078125 +72504 0.010009765625 +72505 -0.036834716796875 +72506 0.012451171875 +72507 0.034881591796875 +72508 0.013519287109375 +72509 0.09124755859375 +72510 0.012054443359375 +72511 0.10888671875 +72512 0.010284423828125 +72513 0.125518798828125 +72514 0.00927734375 +72515 0.15771484375 +72516 0.007659912109375 +72517 0.17828369140625 +72518 0.00469970703125 +72519 0.17108154296875 +72520 0.00018310546875 +72521 0.129974365234375 +72522 -0.00421142578125 +72523 0.082427978515625 +72524 -0.0084228515625 +72525 0.027679443359375 +72526 -0.01416015625 +72527 -0.065643310546875 +72528 -0.019287109375 +72529 -0.15936279296875 +72530 -0.021575927734375 +72531 -0.21307373046875 +72532 -0.021514892578125 +72533 -0.234649658203125 +72534 -0.01788330078125 +72535 -0.2001953125 +72536 -0.01129150390625 +72537 -0.119171142578125 +72538 -0.003753662109375 +72539 -0.024749755859375 +72540 0.0047607421875 +72541 0.085784912109375 +72542 0.01214599609375 +72543 0.178131103515625 +72544 0.016265869140625 +72545 0.215576171875 +72546 0.01776123046875 +72547 0.211456298828125 +72548 0.017120361328125 +72549 0.17523193359375 +72550 0.015472412109375 +72551 0.128753662109375 +72552 0.01446533203125 +72553 0.1019287109375 +72554 0.012939453125 +72555 0.0743408203125 +72556 0.0107421875 +72557 0.04327392578125 +72558 0.009552001953125 +72559 0.038177490234375 +72560 0.010406494140625 +72561 0.076263427734375 +72562 0.012420654296875 +72563 0.14105224609375 +72564 0.01312255859375 +72565 0.186431884765625 +72566 0.011322021484375 +72567 0.188812255859375 +72568 0.006622314453125 +72569 0.1390380859375 +72570 -0.000579833984375 +72571 0.041778564453125 +72572 -0.008880615234375 +72573 -0.079437255859375 +72574 -0.017913818359375 +72575 -0.219390869140625 +72576 -0.027008056640625 +72577 -0.367828369140625 +72578 -0.03448486328125 +72579 -0.494873046875 +72580 -0.037841796875 +72581 -0.556243896484375 +72582 -0.034698486328125 +72583 -0.508697509765625 +72584 -0.026397705078125 +72585 -0.3756103515625 +72586 -0.0164794921875 +72587 -0.218902587890625 +72588 -0.006439208984375 +72589 -0.063751220703125 +72590 0.003692626953125 +72591 0.091552734375 +72592 0.01324462890625 +72593 0.23602294921875 +72594 0.0206298828125 +72595 0.342987060546875 +72596 0.02484130859375 +72597 0.39520263671875 +72598 0.025634765625 +72599 0.389373779296875 +72600 0.022857666015625 +72601 0.324249267578125 +72602 0.017852783203125 +72603 0.224090576171875 +72604 0.0125732421875 +72605 0.124267578125 +72606 0.007720947265625 +72607 0.037078857421875 +72608 0.004791259765625 +72609 -0.010101318359375 +72610 0.003692626953125 +72611 -0.019439697265625 +72612 0.002685546875 +72613 -0.022796630859375 +72614 0.00286865234375 +72615 -0.001556396484375 +72616 0.00494384765625 +72617 0.056304931640625 +72618 0.006500244140625 +72619 0.106719970703125 +72620 0.004669189453125 +72621 0.096893310546875 +72622 0.00042724609375 +72623 0.042694091796875 +72624 -0.003997802734375 +72625 -0.018035888671875 +72626 -0.008056640625 +72627 -0.07586669921875 +72628 -0.01104736328125 +72629 -0.11944580078125 +72630 -0.0135498046875 +72631 -0.15972900390625 +72632 -0.015899658203125 +72633 -0.202606201171875 +72634 -0.01812744140625 +72635 -0.24859619140625 +72636 -0.02069091796875 +72637 -0.30517578125 +72638 -0.0230712890625 +72639 -0.36212158203125 +72640 -0.02374267578125 +72641 -0.39141845703125 +72642 -0.020660400390625 +72643 -0.35528564453125 +72644 -0.013671875 +72645 -0.249969482421875 +72646 -0.0037841796875 +72647 -0.092864990234375 +72648 0.007354736328125 +72649 0.08905029296875 +72650 0.016357421875 +72651 0.2352294921875 +72652 0.02166748046875 +72653 0.318817138671875 +72654 0.0242919921875 +72655 0.358642578125 +72656 0.023834228515625 +72657 0.347747802734375 +72658 0.020294189453125 +72659 0.28564453125 +72660 0.0164794921875 +72661 0.223175048828125 +72662 0.014495849609375 +72663 0.196746826171875 +72664 0.01287841796875 +72665 0.179840087890625 +72666 0.01068115234375 +72667 0.155548095703125 +72668 0.009521484375 +72669 0.151214599609375 +72670 0.008880615234375 +72671 0.156951904296875 +72672 0.00653076171875 +72673 0.13177490234375 +72674 0.00396728515625 +72675 0.100799560546875 +72676 0.002471923828125 +72677 0.087127685546875 +72678 9.1552734375e-05 +72679 0.05487060546875 +72680 -0.00384521484375 +72681 -0.009002685546875 +72682 -0.009307861328125 +72683 -0.10400390625 +72684 -0.0162353515625 +72685 -0.229400634765625 +72686 -0.02301025390625 +72687 -0.35552978515625 +72688 -0.02734375 +72689 -0.441925048828125 +72690 -0.028472900390625 +72691 -0.473846435546875 +72692 -0.027191162109375 +72693 -0.464813232421875 +72694 -0.023773193359375 +72695 -0.419097900390625 +72696 -0.018157958984375 +72697 -0.334320068359375 +72698 -0.0113525390625 +72699 -0.227935791015625 +72700 -0.004730224609375 +72701 -0.12347412109375 +72702 0.001251220703125 +72703 -0.02764892578125 +72704 0.007537841796875 +72705 0.077667236328125 +72706 0.015533447265625 +72707 0.2132568359375 +72708 0.026580810546875 +72709 0.38885498046875 +72710 0.039459228515625 +72711 0.582794189453125 +72712 0.04925537109375 +72713 0.734039306640625 +72714 0.0526123046875 +72715 0.800140380859375 +72716 0.04949951171875 +72717 0.7783203125 +72718 0.039703369140625 +72719 0.6651611328125 +72720 0.023101806640625 +72721 0.45965576171875 +72722 0.002899169921875 +72723 0.199188232421875 +72724 -0.015380859375 +72725 -0.050689697265625 +72726 -0.0269775390625 +72727 -0.23297119140625 +72728 -0.030670166015625 +72729 -0.33013916015625 +72730 -0.029083251953125 +72731 -0.368408203125 +72732 -0.025238037109375 +72733 -0.378936767578125 +72734 -0.02081298828125 +72735 -0.376983642578125 +72736 -0.017547607421875 +72737 -0.37969970703125 +72738 -0.016021728515625 +72739 -0.391510009765625 +72740 -0.01397705078125 +72741 -0.385345458984375 +72742 -0.009765625 +72743 -0.3419189453125 +72744 -0.005279541015625 +72745 -0.28289794921875 +72746 -0.004241943359375 +72747 -0.251617431640625 +72748 -0.008148193359375 +72749 -0.266143798828125 +72750 -0.01214599609375 +72751 -0.273345947265625 +72752 -0.011077880859375 +72753 -0.216796875 +72754 -0.00750732421875 +72755 -0.128265380859375 +72756 -0.0064697265625 +72757 -0.068145751953125 +72758 -0.008331298828125 +72759 -0.0430908203125 +72760 -0.0103759765625 +72761 -0.024444580078125 +72762 -0.009521484375 +72763 0.020721435546875 +72764 -0.002777099609375 +72765 0.124481201171875 +72766 0.00738525390625 +72767 0.25787353515625 +72768 0.017364501953125 +72769 0.379119873046875 +72770 0.02642822265625 +72771 0.47991943359375 +72772 0.031707763671875 +72773 0.5281982421875 +72774 0.032012939453125 +72775 0.511138916015625 +72776 0.029632568359375 +72777 0.456207275390625 +72778 0.028289794921875 +72779 0.407470703125 +72780 0.02947998046875 +72781 0.383758544921875 +72782 0.030517578125 +72783 0.35687255859375 +72784 0.029876708984375 +72785 0.31182861328125 +72786 0.027587890625 +72787 0.250885009765625 +72788 0.022735595703125 +72789 0.1654052734375 +72790 0.013427734375 +72791 0.035247802734375 +72792 -0.0006103515625 +72793 -0.142059326171875 +72794 -0.0167236328125 +72795 -0.33563232421875 +72796 -0.034027099609375 +72797 -0.5345458984375 +72798 -0.050994873046875 +72799 -0.72186279296875 +72800 -0.062164306640625 +72801 -0.836669921875 +72802 -0.06341552734375 +72803 -0.8326416015625 +72804 -0.056396484375 +72805 -0.7296142578125 +72806 -0.045867919921875 +72807 -0.582550048828125 +72808 -0.03594970703125 +72809 -0.440093994140625 +72810 -0.0284423828125 +72811 -0.324310302734375 +72812 -0.02020263671875 +72813 -0.20147705078125 +72814 -0.00872802734375 +72815 -0.044647216796875 +72816 0.002349853515625 +72817 0.103973388671875 +72818 0.00946044921875 +72819 0.202392578125 +72820 0.013885498046875 +72821 0.264495849609375 +72822 0.019927978515625 +72823 0.338897705078125 +72824 0.029205322265625 +72825 0.443817138671875 +72826 0.0386962890625 +72827 0.545074462890625 +72828 0.046112060546875 +72829 0.6173095703125 +72830 0.050689697265625 +72831 0.6524658203125 +72832 0.053436279296875 +72833 0.66339111328125 +72834 0.054779052734375 +72835 0.6561279296875 +72836 0.052490234375 +72837 0.606781005859375 +72838 0.045196533203125 +72839 0.501190185546875 +72840 0.034027099609375 +72841 0.352783203125 +72842 0.02020263671875 +72843 0.176544189453125 +72844 0.002960205078125 +72845 -0.034820556640625 +72846 -0.015625 +72847 -0.258209228515625 +72848 -0.0311279296875 +72849 -0.44244384765625 +72850 -0.04254150390625 +72851 -0.5753173828125 +72852 -0.0494384765625 +72853 -0.65203857421875 +72854 -0.049041748046875 +72855 -0.641632080078125 +72856 -0.04296875 +72857 -0.562164306640625 +72858 -0.035064697265625 +72859 -0.458038330078125 +72860 -0.027069091796875 +72861 -0.350555419921875 +72862 -0.020721435546875 +72863 -0.260528564453125 +72864 -0.016326904296875 +72865 -0.192108154296875 +72866 -0.013519287109375 +72867 -0.141937255859375 +72868 -0.011474609375 +72869 -0.1021728515625 +72870 -0.00927734375 +72871 -0.062896728515625 +72872 -0.005767822265625 +72873 -0.011932373046875 +72874 0.0001220703125 +72875 0.062835693359375 +72876 0.00732421875 +72877 0.148712158203125 +72878 0.0155029296875 +72879 0.241729736328125 +72880 0.0252685546875 +72881 0.34912109375 +72882 0.035400390625 +72883 0.457305908203125 +72884 0.04388427734375 +72885 0.54388427734375 +72886 0.0474853515625 +72887 0.5728759765625 +72888 0.0428466796875 +72889 0.506591796875 +72890 0.030426025390625 +72891 0.351226806640625 +72892 0.013641357421875 +72893 0.146514892578125 +72894 -0.0029296875 +72895 -0.05523681640625 +72896 -0.016021728515625 +72897 -0.21624755859375 +72898 -0.025543212890625 +72899 -0.334930419921875 +72900 -0.03082275390625 +72901 -0.402984619140625 +72902 -0.03369140625 +72903 -0.4412841796875 +72904 -0.03826904296875 +72905 -0.49578857421875 +72906 -0.043975830078125 +72907 -0.5601806640625 +72908 -0.0478515625 +72909 -0.600738525390625 +72910 -0.04693603515625 +72911 -0.584228515625 +72912 -0.0384521484375 +72913 -0.47930908203125 +72914 -0.021759033203125 +72915 -0.27935791015625 +72916 0.0009765625 +72917 -0.0089111328125 +72918 0.0242919921875 +72919 0.268798828125 +72920 0.041961669921875 +72921 0.482818603515625 +72922 0.051483154296875 +72923 0.60369873046875 +72924 0.054595947265625 +72925 0.650421142578125 +72926 0.054962158203125 +72927 0.66400146484375 +72928 0.052337646484375 +72929 0.6414794921875 +72930 0.045867919921875 +72931 0.572540283203125 +72932 0.0391845703125 +72933 0.498138427734375 +72934 0.034149169921875 +72935 0.439453125 +72936 0.028900146484375 +72937 0.375518798828125 +72938 0.020599365234375 +72939 0.274505615234375 +72940 0.00677490234375 +72941 0.1087646484375 +72942 -0.0106201171875 +72943 -0.099395751953125 +72944 -0.02886962890625 +72945 -0.3182373046875 +72946 -0.048095703125 +72947 -0.5489501953125 +72948 -0.0667724609375 +72949 -0.7738037109375 +72950 -0.080352783203125 +72951 -0.86383056640625 +72952 -0.085968017578125 +72953 -0.870391845703125 +72954 -0.085235595703125 +72955 -0.86895751953125 +72956 -0.079315185546875 +72957 -0.861053466796875 +72958 -0.06671142578125 +72959 -0.765869140625 +72960 -0.04638671875 +72961 -0.5301513671875 +72962 -0.0184326171875 +72963 -0.214691162109375 +72964 0.013153076171875 +72965 0.137359619140625 +72966 0.043243408203125 +72967 0.474822998046875 +72968 0.068450927734375 +72969 0.76239013671875 +72970 0.086212158203125 +72971 0.867462158203125 +72972 0.097076416015625 +72973 0.870361328125 +72974 0.10003662109375 +72975 0.86480712890625 +72976 0.095855712890625 +72977 0.831817626953125 +72978 0.087493896484375 +72979 0.677581787109375 +72980 0.075469970703125 +72981 0.495880126953125 +72982 0.061737060546875 +72983 0.30767822265625 +72984 0.04620361328125 +72985 0.116180419921875 +72986 0.024566650390625 +72987 -0.110748291015625 +72988 -0.00445556640625 +72989 -0.381805419921875 +72990 -0.036285400390625 +72991 -0.6572265625 +72992 -0.064208984375 +72993 -0.857421875 +72994 -0.08355712890625 +72995 -0.870391845703125 +72996 -0.093902587890625 +72997 -0.870391845703125 +72998 -0.09881591796875 +72999 -0.86444091796875 +73000 -0.102813720703125 +73001 -0.85723876953125 +73002 -0.10382080078125 +73003 -0.790008544921875 +73004 -0.0953369140625 +73005 -0.62847900390625 +73006 -0.076873779296875 +73007 -0.3956298828125 +73008 -0.05218505859375 +73009 -0.126708984375 +73010 -0.0242919921875 +73011 0.150115966796875 +73012 0.005706787109375 +73013 0.424041748046875 +73014 0.034942626953125 +73015 0.670623779296875 +73016 0.0592041015625 +73017 0.854522705078125 +73018 0.0767822265625 +73019 0.866485595703125 +73020 0.086212158203125 +73021 0.86920166015625 +73022 0.09002685546875 +73023 0.8653564453125 +73024 0.090118408203125 +73025 0.857147216796875 +73026 0.08636474609375 +73027 0.766845703125 +73028 0.079498291015625 +73029 0.628509521484375 +73030 0.068756103515625 +73031 0.462127685546875 +73032 0.05718994140625 +73033 0.297210693359375 +73034 0.046173095703125 +73035 0.14862060546875 +73036 0.032745361328125 +73037 -0.00537109375 +73038 0.017547607421875 +73039 -0.15753173828125 +73040 -9.1552734375e-05 +73041 -0.31304931640625 +73042 -0.022216796875 +73043 -0.48876953125 +73044 -0.04351806640625 +73045 -0.6416015625 +73046 -0.061370849609375 +73047 -0.751373291015625 +73048 -0.078826904296875 +73049 -0.84619140625 +73050 -0.094390869140625 +73051 -0.861297607421875 +73052 -0.104278564453125 +73053 -0.863250732421875 +73054 -0.104827880859375 +73055 -0.856597900390625 +73056 -0.097564697265625 +73057 -0.7498779296875 +73058 -0.0894775390625 +73059 -0.624542236328125 +73060 -0.077850341796875 +73061 -0.47808837890625 +73062 -0.055511474609375 +73063 -0.253387451171875 +73064 -0.02777099609375 +73065 0.003692626953125 +73066 -0.0025634765625 +73067 0.2257080078125 +73068 0.021820068359375 +73069 0.427154541015625 +73070 0.049530029296875 +73071 0.643218994140625 +73072 0.079681396484375 +73073 0.855926513671875 +73074 0.1055908203125 +73075 0.870361328125 +73076 0.121551513671875 +73077 0.870361328125 +73078 0.128631591796875 +73079 0.862762451171875 +73080 0.126617431640625 +73081 0.79669189453125 +73082 0.114471435546875 +73083 0.595794677734375 +73084 0.095733642578125 +73085 0.362152099609375 +73086 0.073699951171875 +73087 0.1270751953125 +73088 0.05084228515625 +73089 -0.086944580078125 +73090 0.027252197265625 +73091 -0.2784423828125 +73092 -0.001373291015625 +73093 -0.484832763671875 +73094 -0.037567138671875 +73095 -0.729583740234375 +73096 -0.075439453125 +73097 -0.86688232421875 +73098 -0.107666015625 +73099 -0.870391845703125 +73100 -0.13385009765625 +73101 -0.86859130859375 +73102 -0.1539306640625 +73103 -0.86279296875 +73104 -0.163787841796875 +73105 -0.817962646484375 +73106 -0.158111572265625 +73107 -0.6116943359375 +73108 -0.136138916015625 +73109 -0.3128662109375 +73110 -0.101959228515625 +73111 0.039398193359375 +73112 -0.057952880859375 +73113 0.422821044921875 +73114 -0.008087158203125 +73115 0.805145263671875 +73116 0.039520263671875 +73117 0.870361328125 +73118 0.07818603515625 +73119 0.870361328125 +73120 0.10662841796875 +73121 0.860015869140625 +73122 0.124114990234375 +73123 0.727935791015625 +73124 0.130157470703125 +73125 0.48114013671875 +73126 0.1278076171875 +73127 0.2059326171875 +73128 0.119964599609375 +73129 -0.06103515625 +73130 0.107940673828125 +73131 -0.29913330078125 +73132 0.090118408203125 +73133 -0.516204833984375 +73134 0.064788818359375 +73135 -0.7252197265625 +73136 0.03497314453125 +73137 -0.85980224609375 +73138 0.004791259765625 +73139 -0.870391845703125 +73140 -0.022186279296875 +73141 -0.870391845703125 +73142 -0.0401611328125 +73143 -0.858062744140625 +73144 -0.048675537109375 +73145 -0.673004150390625 +73146 -0.05413818359375 +73147 -0.42694091796875 +73148 -0.06195068359375 +73149 -0.2100830078125 +73150 -0.071929931640625 +73151 -0.0362548828125 +73152 -0.0806884765625 +73153 0.10943603515625 +73154 -0.0859375 +73155 0.23516845703125 +73156 -0.082794189453125 +73157 0.373687744140625 +73158 -0.07159423828125 +73159 0.517791748046875 +73160 -0.05999755859375 +73161 0.602783203125 +73162 -0.04742431640625 +73163 0.635711669921875 +73164 -0.02996826171875 +73165 0.655181884765625 +73166 -0.008819580078125 +73167 0.65948486328125 +73168 0.0150146484375 +73169 0.651275634765625 +73170 0.03863525390625 +73171 0.61846923828125 +73172 0.0576171875 +73173 0.53753662109375 +73174 0.069854736328125 +73175 0.404144287109375 +73176 0.074249267578125 +73177 0.22186279296875 +73178 0.071044921875 +73179 0.003997802734375 +73180 0.0625 +73181 -0.22100830078125 +73182 0.0511474609375 +73183 -0.42449951171875 +73184 0.039642333984375 +73185 -0.579833984375 +73186 0.033172607421875 +73187 -0.641876220703125 +73188 0.031005859375 +73189 -0.6177978515625 +73190 0.025421142578125 +73191 -0.575531005859375 +73192 0.015838623046875 +73193 -0.526336669921875 +73194 0.008453369140625 +73195 -0.42645263671875 +73196 0.00653076171875 +73197 -0.2581787109375 +73198 0.0057373046875 +73199 -0.068695068359375 +73200 0.001434326171875 +73201 0.09222412109375 +73202 -0.004150390625 +73203 0.232147216796875 +73204 -0.009857177734375 +73205 0.3509521484375 +73206 -0.019287109375 +73207 0.410064697265625 +73208 -0.036041259765625 +73209 0.372955322265625 +73210 -0.0576171875 +73211 0.2554931640625 +73212 -0.077850341796875 +73213 0.10711669921875 +73214 -0.09442138671875 +73215 -0.052886962890625 +73216 -0.10260009765625 +73217 -0.186279296875 +73218 -0.09527587890625 +73219 -0.23291015625 +73220 -0.0760498046875 +73221 -0.209442138671875 +73222 -0.054107666015625 +73223 -0.174163818359375 +73224 -0.02996826171875 +73225 -0.126739501953125 +73226 -0.00140380859375 +73227 -0.048126220703125 +73228 0.027984619140625 +73229 0.0426025390625 +73230 0.051788330078125 +73231 0.10748291015625 +73232 0.068572998046875 +73233 0.1409912109375 +73234 0.085968017578125 +73235 0.19708251953125 +73236 0.103271484375 +73237 0.273651123046875 +73238 0.1123046875 +73239 0.31768798828125 +73240 0.11480712890625 +73241 0.341094970703125 +73242 0.114532470703125 +73243 0.368011474609375 +73244 0.10791015625 +73245 0.37249755859375 +73246 0.087310791015625 +73247 0.30072021484375 +73248 0.053192138671875 +73249 0.1517333984375 +73250 0.015167236328125 +73251 -0.01470947265625 +73252 -0.024444580078125 +73253 -0.1883544921875 +73254 -0.0654296875 +73255 -0.372711181640625 +73256 -0.0989990234375 +73257 -0.51397705078125 +73258 -0.11846923828125 +73259 -0.57177734375 +73260 -0.122314453125 +73261 -0.53948974609375 +73262 -0.112823486328125 +73263 -0.43511962890625 +73264 -0.095367431640625 +73265 -0.2962646484375 +73266 -0.075592041015625 +73267 -0.161102294921875 +73268 -0.05560302734375 +73269 -0.0435791015625 +73270 -0.0350341796875 +73271 0.060394287109375 +73272 -0.016326904296875 +73273 0.13665771484375 +73274 -0.002227783203125 +73275 0.170135498046875 +73276 0.007415771484375 +73277 0.16552734375 +73278 0.017181396484375 +73279 0.15728759765625 +73280 0.027252197265625 +73281 0.150787353515625 +73282 0.033416748046875 +73283 0.12200927734375 +73284 0.0364990234375 +73285 0.080108642578125 +73286 0.039947509765625 +73287 0.05126953125 +73288 0.0474853515625 +73289 0.062896728515625 +73290 0.055511474609375 +73291 0.09271240234375 +73292 0.0567626953125 +73293 0.092987060546875 +73294 0.053436279296875 +73295 0.07855224609375 +73296 0.047882080078125 +73297 0.06427001953125 +73298 0.038055419921875 +73299 0.0347900390625 +73300 0.0240478515625 +73301 -0.01171875 +73302 0.0091552734375 +73303 -0.056060791015625 +73304 0.000274658203125 +73305 -0.055511474609375 +73306 -0.002105712890625 +73307 -0.010467529296875 +73308 -0.005584716796875 +73309 0.02508544921875 +73310 -0.013519287109375 +73311 0.025665283203125 +73312 -0.021575927734375 +73313 0.017333984375 +73314 -0.0291748046875 +73315 0.00189208984375 +73316 -0.0377197265625 +73317 -0.03173828125 +73318 -0.045257568359375 +73319 -0.071502685546875 +73320 -0.054473876953125 +73321 -0.13543701171875 +73322 -0.06488037109375 +73323 -0.219970703125 +73324 -0.072967529296875 +73325 -0.300506591796875 +73326 -0.078887939453125 +73327 -0.376312255859375 +73328 -0.07830810546875 +73329 -0.416107177734375 +73330 -0.064300537109375 +73331 -0.371124267578125 +73332 -0.03741455078125 +73333 -0.242279052734375 +73334 -0.00408935546875 +73335 -0.069732666015625 +73336 0.0321044921875 +73337 0.125640869140625 +73338 0.066131591796875 +73339 0.31268310546875 +73340 0.092193603515625 +73341 0.45501708984375 +73342 0.11041259765625 +73343 0.554779052734375 +73344 0.120452880859375 +73345 0.61065673828125 +73346 0.120513916015625 +73347 0.610931396484375 +73348 0.1070556640625 +73349 0.531463623046875 +73350 0.082611083984375 +73351 0.3883056640625 +73352 0.05535888671875 +73353 0.23468017578125 +73354 0.029296875 +73355 0.095245361328125 +73356 0.00860595703125 +73357 -0.00396728515625 +73358 -0.00421142578125 +73359 -0.04852294921875 +73360 -0.01129150390625 +73361 -0.055145263671875 +73362 -0.020111083984375 +73363 -0.0758056640625 +73364 -0.03460693359375 +73365 -0.138702392578125 +73366 -0.04931640625 +73367 -0.209197998046875 +73368 -0.064300537109375 +73369 -0.289031982421875 +73370 -0.07952880859375 +73371 -0.37884521484375 +73372 -0.091583251953125 +73373 -0.456329345703125 +73374 -0.0997314453125 +73375 -0.51641845703125 +73376 -0.09808349609375 +73377 -0.519287109375 +73378 -0.085784912109375 +73379 -0.458251953125 +73380 -0.070770263671875 +73381 -0.384796142578125 +73382 -0.056976318359375 +73383 -0.323699951171875 +73384 -0.043792724609375 +73385 -0.269287109375 +73386 -0.027557373046875 +73387 -0.1951904296875 +73388 -0.00836181640625 +73389 -0.100006103515625 +73390 0.00946044921875 +73391 -0.01055908203125 +73392 0.03021240234375 +73393 0.1033935546875 +73394 0.0548095703125 +73395 0.24908447265625 +73396 0.07513427734375 +73397 0.373199462890625 +73398 0.088470458984375 +73399 0.45806884765625 +73400 0.095977783203125 +73401 0.511474609375 +73402 0.102508544921875 +73403 0.565399169921875 +73404 0.10693359375 +73405 0.61138916015625 +73406 0.1004638671875 +73407 0.5897216796875 +73408 0.081817626953125 +73409 0.4906005859375 +73410 0.0538330078125 +73411 0.33148193359375 +73412 0.022064208984375 +73413 0.147796630859375 +73414 -0.006988525390625 +73415 -0.01873779296875 +73416 -0.0289306640625 +73417 -0.140289306640625 +73418 -0.039825439453125 +73419 -0.191986083984375 +73420 -0.04107666015625 +73421 -0.184295654296875 +73422 -0.039276123046875 +73423 -0.161834716796875 +73424 -0.040679931640625 +73425 -0.166595458984375 +73426 -0.044586181640625 +73427 -0.19390869140625 +73428 -0.048126220703125 +73429 -0.22442626953125 +73430 -0.054595947265625 +73431 -0.279754638671875 +73432 -0.06097412109375 +73433 -0.3389892578125 +73434 -0.060272216796875 +73435 -0.3543701171875 +73436 -0.055999755859375 +73437 -0.348175048828125 +73438 -0.0491943359375 +73439 -0.32598876953125 +73440 -0.035614013671875 +73441 -0.2581787109375 +73442 -0.01470947265625 +73443 -0.139801025390625 +73444 0.01116943359375 +73445 0.014617919921875 +73446 0.032745361328125 +73447 0.144378662109375 +73448 0.045684814453125 +73449 0.221038818359375 +73450 0.0538330078125 +73451 0.27069091796875 +73452 0.05731201171875 +73453 0.294036865234375 +73454 0.059234619140625 +73455 0.311767578125 +73456 0.061981201171875 +73457 0.339141845703125 +73458 0.063262939453125 +73459 0.360260009765625 +73460 0.061004638671875 +73461 0.360504150390625 +73462 0.050537109375 +73463 0.308380126953125 +73464 0.02862548828125 +73465 0.18170166015625 +73466 -0.000823974609375 +73467 0.0047607421875 +73468 -0.030609130859375 +73469 -0.17559814453125 +73470 -0.053741455078125 +73471 -0.3143310546875 +73472 -0.063140869140625 +73473 -0.36785888671875 +73474 -0.063140869140625 +73475 -0.36248779296875 +73476 -0.061187744140625 +73477 -0.343536376953125 +73478 -0.0552978515625 +73479 -0.3018798828125 +73480 -0.044097900390625 +73481 -0.231414794921875 +73482 -0.02471923828125 +73483 -0.117645263671875 +73484 -0.003021240234375 +73485 0.007049560546875 +73486 0.011016845703125 +73487 0.087982177734375 +73488 0.02008056640625 +73489 0.13946533203125 +73490 0.02655029296875 +73491 0.17425537109375 +73492 0.02960205078125 +73493 0.188201904296875 +73494 0.02734375 +73495 0.171234130859375 +73496 0.018768310546875 +73497 0.118438720703125 +73498 0.008819580078125 +73499 0.05706787109375 +73500 -0.002166748046875 +73501 -0.010711669921875 +73502 -0.0155029296875 +73503 -0.0914306640625 +73504 -0.027099609375 +73505 -0.162322998046875 +73506 -0.03173828125 +73507 -0.194549560546875 +73508 -0.0223388671875 +73509 -0.1492919921875 +73510 0.00189208984375 +73511 -0.02166748046875 +73512 0.029083251953125 +73513 0.124053955078125 +73514 0.04510498046875 +73515 0.211151123046875 +73516 0.050140380859375 +73517 0.240447998046875 +73518 0.049774169921875 +73519 0.242218017578125 +73520 0.0457763671875 +73521 0.2257080078125 +73522 0.038848876953125 +73523 0.194366455078125 +73524 0.0230712890625 +73525 0.115509033203125 +73526 0.00286865234375 +73527 0.0128173828125 +73528 -0.010650634765625 +73529 -0.053802490234375 +73530 -0.022247314453125 +73531 -0.110626220703125 +73532 -0.039581298828125 +73533 -0.199493408203125 +73534 -0.057830810546875 +73535 -0.29437255859375 +73536 -0.065338134765625 +73537 -0.33221435546875 +73538 -0.05596923828125 +73539 -0.27972412109375 +73540 -0.03863525390625 +73541 -0.185333251953125 +73542 -0.02789306640625 +73543 -0.128204345703125 +73544 -0.025115966796875 +73545 -0.115692138671875 +73546 -0.0245361328125 +73547 -0.116455078125 +73548 -0.021728515625 +73549 -0.105926513671875 +73550 -0.01116943359375 +73551 -0.053955078125 +73552 0.008758544921875 +73553 0.048797607421875 +73554 0.029754638671875 +73555 0.157318115234375 +73556 0.040740966796875 +73557 0.212005615234375 +73558 0.042724609375 +73559 0.218475341796875 +73560 0.04681396484375 +73561 0.23724365234375 +73562 0.059814453125 +73563 0.30535888671875 +73564 0.07403564453125 +73565 0.38128662109375 +73566 0.07830810546875 +73567 0.404449462890625 +73568 0.076263427734375 +73569 0.3944091796875 +73570 0.07476806640625 +73571 0.3885498046875 +73572 0.069427490234375 +73573 0.362640380859375 +73574 0.0523681640625 +73575 0.27362060546875 +73576 0.022796630859375 +73577 0.11712646484375 +73578 -0.009674072265625 +73579 -0.054901123046875 +73580 -0.03546142578125 +73581 -0.19085693359375 +73582 -0.053619384765625 +73583 -0.28570556640625 +73584 -0.064056396484375 +73585 -0.339263916015625 +73586 -0.071563720703125 +73587 -0.3775634765625 +73588 -0.084381103515625 +73589 -0.445709228515625 +73590 -0.1009521484375 +73591 -0.535064697265625 +73592 -0.11822509765625 +73593 -0.629058837890625 +73594 -0.130645751953125 +73595 -0.697601318359375 +73596 -0.131439208984375 +73597 -0.70391845703125 +73598 -0.119659423828125 +73599 -0.6424560546875 +73600 -0.091278076171875 +73601 -0.491241455078125 +73602 -0.049163818359375 +73603 -0.265716552734375 +73604 -0.003997802734375 +73605 -0.023712158203125 +73606 0.0380859375 +73607 0.201751708984375 +73608 0.070648193359375 +73609 0.375823974609375 +73610 0.0911865234375 +73611 0.485076904296875 +73612 0.106903076171875 +73613 0.56884765625 +73614 0.11920166015625 +73615 0.634765625 +73616 0.1197509765625 +73617 0.63763427734375 +73618 0.106475830078125 +73619 0.5660400390625 +73620 0.088958740234375 +73621 0.4720458984375 +73622 0.07666015625 +73623 0.40692138671875 +73624 0.070892333984375 +73625 0.3778076171875 +73626 0.070281982421875 +73627 0.376953125 +73628 0.068878173828125 +73629 0.371978759765625 +73630 0.057525634765625 +73631 0.313140869140625 +73632 0.033294677734375 +73633 0.184417724609375 +73634 0.00091552734375 +73635 0.011199951171875 +73636 -0.03302001953125 +73637 -0.171051025390625 +73638 -0.063873291015625 +73639 -0.33740234375 +73640 -0.088714599609375 +73641 -0.47198486328125 +73642 -0.10491943359375 +73643 -0.560394287109375 +73644 -0.10845947265625 +73645 -0.58056640625 +73646 -0.10211181640625 +73647 -0.54754638671875 +73648 -0.0946044921875 +73649 -0.508575439453125 +73650 -0.085174560546875 +73651 -0.459503173828125 +73652 -0.07275390625 +73653 -0.394378662109375 +73654 -0.0645751953125 +73655 -0.35260009765625 +73656 -0.056549072265625 +73657 -0.31170654296875 +73658 -0.035064697265625 +73659 -0.197418212890625 +73660 0.00018310546875 +73661 -0.007965087890625 +73662 0.04010009765625 +73663 0.207489013671875 +73664 0.077362060546875 +73665 0.409210205078125 +73666 0.10736083984375 +73667 0.57208251953125 +73668 0.124542236328125 +73669 0.66595458984375 +73670 0.123016357421875 +73671 0.65875244140625 +73672 0.105926513671875 +73673 0.56744384765625 +73674 0.080535888671875 +73675 0.431396484375 +73676 0.054931640625 +73677 0.29443359375 +73678 0.033905029296875 +73679 0.182464599609375 +73680 0.011627197265625 +73681 0.06365966796875 +73682 -0.014434814453125 +73683 -0.075958251953125 +73684 -0.035614013671875 +73685 -0.189422607421875 +73686 -0.05096435546875 +73687 -0.271942138671875 +73688 -0.06402587890625 +73689 -0.342529296875 +73690 -0.068023681640625 +73691 -0.364166259765625 +73692 -0.061187744140625 +73693 -0.327239990234375 +73694 -0.051849365234375 +73695 -0.2769775390625 +73696 -0.047393798828125 +73697 -0.253692626953125 +73698 -0.045318603515625 +73699 -0.24365234375 +73700 -0.0367431640625 +73701 -0.1983642578125 +73702 -0.0213623046875 +73703 -0.116241455078125 +73704 -0.006439208984375 +73705 -0.036834716796875 +73706 0.007049560546875 +73707 0.034881591796875 +73708 0.017669677734375 +73709 0.09124755859375 +73710 0.0211181640625 +73711 0.10888671875 +73712 0.024322509765625 +73713 0.125518798828125 +73714 0.03033447265625 +73715 0.15771484375 +73716 0.03411865234375 +73717 0.17828369140625 +73718 0.03271484375 +73719 0.17108154296875 +73720 0.024993896484375 +73721 0.129974365234375 +73722 0.01605224609375 +73723 0.082427978515625 +73724 0.0057373046875 +73725 0.027679443359375 +73726 -0.01165771484375 +73727 -0.065643310546875 +73728 -0.02874755859375 +73729 -0.15936279296875 +73730 -0.038482666015625 +73731 -0.21307373046875 +73732 -0.04296875 +73733 -0.234649658203125 +73734 -0.036651611328125 +73735 -0.2001953125 +73736 -0.021148681640625 +73737 -0.119171142578125 +73738 -0.00323486328125 +73739 -0.024749755859375 +73740 0.017974853515625 +73741 0.085784912109375 +73742 0.035308837890625 +73743 0.178131103515625 +73744 0.04107666015625 +73745 0.215576171875 +73746 0.038330078125 +73747 0.211456298828125 +73748 0.029266357421875 +73749 0.17523193359375 +73750 0.01861572265625 +73751 0.128753662109375 +73752 0.01287841796875 +73753 0.1019287109375 +73754 0.007598876953125 +73755 0.0743408203125 +73756 0.002105712890625 +73757 0.04327392578125 +73758 0.002655029296875 +73759 0.038177490234375 +73760 0.012847900390625 +73761 0.076263427734375 +73762 0.028961181640625 +73763 0.14105224609375 +73764 0.040924072265625 +73765 0.186431884765625 +73766 0.04351806640625 +73767 0.188812255859375 +73768 0.034637451171875 +73769 0.1390380859375 +73770 0.01519775390625 +73771 0.041778564453125 +73772 -0.009796142578125 +73773 -0.079437255859375 +73774 -0.039276123046875 +73775 -0.219390869140625 +73776 -0.07098388671875 +73777 -0.367828369140625 +73778 -0.0985107421875 +73779 -0.494873046875 +73780 -0.112274169921875 +73781 -0.556243896484375 +73782 -0.1029052734375 +73783 -0.508697509765625 +73784 -0.075408935546875 +73785 -0.3756103515625 +73786 -0.0430908203125 +73787 -0.218902587890625 +73788 -0.01129150390625 +73789 -0.063751220703125 +73790 0.02044677734375 +73791 0.091552734375 +73792 0.049835205078125 +73793 0.23602294921875 +73794 0.07122802734375 +73795 0.342987060546875 +73796 0.08099365234375 +73797 0.39520263671875 +73798 0.0784912109375 +73799 0.389373779296875 +73800 0.06353759765625 +73801 0.324249267578125 +73802 0.041412353515625 +73803 0.224090576171875 +73804 0.019775390625 +73805 0.124267578125 +73806 0.001251220703125 +73807 0.037078857421875 +73808 -0.00823974609375 +73809 -0.010101318359375 +73810 -0.009246826171875 +73811 -0.019439697265625 +73812 -0.0086669921875 +73813 -0.022796630859375 +73814 -0.002593994140625 +73815 -0.001556396484375 +73816 0.01141357421875 +73817 0.056304931640625 +73818 0.0238037109375 +73819 0.106719970703125 +73820 0.023101806640625 +73821 0.096893310546875 +73822 0.01263427734375 +73823 0.042694091796875 +73824 0.000518798828125 +73825 -0.018035888671875 +73826 -0.01123046875 +73827 -0.07586669921875 +73828 -0.02020263671875 +73829 -0.11944580078125 +73830 -0.028778076171875 +73831 -0.15972900390625 +73832 -0.0382080078125 +73833 -0.202606201171875 +73834 -0.048553466796875 +73835 -0.24859619140625 +73836 -0.0614013671875 +73837 -0.30517578125 +73838 -0.074493408203125 +73839 -0.36212158203125 +73840 -0.081756591796875 +73841 -0.39141845703125 +73842 -0.074981689453125 +73843 -0.35528564453125 +73844 -0.053314208984375 +73845 -0.249969482421875 +73846 -0.020477294921875 +73847 -0.092864990234375 +73848 0.01776123046875 +73849 0.08905029296875 +73850 0.04840087890625 +73851 0.2352294921875 +73852 0.065673828125 +73853 0.318817138671875 +73854 0.07366943359375 +73855 0.358642578125 +73856 0.0709228515625 +73857 0.347747802734375 +73858 0.057373046875 +73859 0.28564453125 +73860 0.04400634765625 +73861 0.223175048828125 +73862 0.038665771484375 +73863 0.196746826171875 +73864 0.03558349609375 +73865 0.179840087890625 +73866 0.03106689453125 +73867 0.155548095703125 +73868 0.030975341796875 +73869 0.151214599609375 +73870 0.033111572265625 +73871 0.156951904296875 +73872 0.028564453125 +73873 0.13177490234375 +73874 0.022735595703125 +73875 0.100799560546875 +73876 0.020538330078125 +73877 0.087127685546875 +73878 0.014190673828125 +73879 0.05487060546875 +73880 0.000885009765625 +73881 -0.009002685546875 +73882 -0.019287109375 +73883 -0.10400390625 +73884 -0.04620361328125 +73885 -0.229400634765625 +73886 -0.073455810546875 +73887 -0.35552978515625 +73888 -0.092254638671875 +73889 -0.441925048828125 +73890 -0.09942626953125 +73891 -0.473846435546875 +73892 -0.09783935546875 +73893 -0.464813232421875 +73894 -0.08843994140625 +73895 -0.419097900390625 +73896 -0.0706787109375 +73897 -0.334320068359375 +73898 -0.048309326171875 +73899 -0.227935791015625 +73900 -0.026336669921875 +73901 -0.12347412109375 +73902 -0.006195068359375 +73903 -0.02764892578125 +73904 0.016021728515625 +73905 0.077667236328125 +73906 0.044830322265625 +73907 0.2132568359375 +73908 0.082366943359375 +73909 0.38885498046875 +73910 0.123992919921875 +73911 0.582794189453125 +73912 0.156494140625 +73913 0.734039306640625 +73914 0.170684814453125 +73915 0.800140380859375 +73916 0.165985107421875 +73917 0.7783203125 +73918 0.14166259765625 +73919 0.6651611328125 +73920 0.09747314453125 +73921 0.45965576171875 +73922 0.041534423828125 +73923 0.199188232421875 +73924 -0.011993408203125 +73925 -0.050689697265625 +73926 -0.05084228515625 +73927 -0.23297119140625 +73928 -0.071258544921875 +73929 -0.33013916015625 +73930 -0.07891845703125 +73931 -0.368408203125 +73932 -0.080596923828125 +73933 -0.378936767578125 +73934 -0.079681396484375 +73935 -0.376983642578125 +73936 -0.079864501953125 +73937 -0.37969970703125 +73938 -0.082122802734375 +73939 -0.391510009765625 +73940 -0.080596923828125 +73941 -0.385345458984375 +73942 -0.0711669921875 +73943 -0.3419189453125 +73944 -0.0584716796875 +73945 -0.28289794921875 +73946 -0.0518798828125 +73947 -0.251617431640625 +73948 -0.0552978515625 +73949 -0.266143798828125 +73950 -0.057220458984375 +73951 -0.273345947265625 +73952 -0.045440673828125 +73953 -0.216796875 +73954 -0.026763916015625 +73955 -0.128265380859375 +73956 -0.01422119140625 +73957 -0.068145751953125 +73958 -0.00921630859375 +73959 -0.0430908203125 +73960 -0.00555419921875 +73961 -0.024444580078125 +73962 0.00384521484375 +73963 0.020721435546875 +73964 0.02593994140625 +73965 0.124481201171875 +73966 0.05450439453125 +73967 0.25787353515625 +73968 0.08050537109375 +73969 0.379119873046875 +73970 0.1021728515625 +73971 0.47991943359375 +73972 0.112579345703125 +73973 0.5281982421875 +73974 0.10894775390625 +73975 0.511138916015625 +73976 0.097198486328125 +73977 0.456207275390625 +73978 0.08685302734375 +73979 0.407470703125 +73980 0.08197021484375 +73981 0.383758544921875 +73982 0.076416015625 +73983 0.35687255859375 +73984 0.067474365234375 +73985 0.31182861328125 +73986 0.055908203125 +73987 0.250885009765625 +73988 0.0391845703125 +73989 0.1654052734375 +73990 0.0118408203125 +73991 0.035247802734375 +73992 -0.027191162109375 +73993 -0.142059326171875 +73994 -0.070648193359375 +73995 -0.33563232421875 +73996 -0.11614990234375 +73997 -0.5345458984375 +73998 -0.159759521484375 +73999 -0.72186279296875 +74000 -0.186553955078125 +74001 -0.836669921875 +74002 -0.18511962890625 +74003 -0.8326416015625 +74004 -0.160369873046875 +74005 -0.7296142578125 +74006 -0.125885009765625 +74007 -0.582550048828125 +74008 -0.09356689453125 +74009 -0.440093994140625 +74010 -0.06866455078125 +74011 -0.324310302734375 +74012 -0.042572021484375 +74013 -0.20147705078125 +74014 -0.008331298828125 +74015 -0.044647216796875 +74016 0.023834228515625 +74017 0.103973388671875 +74018 0.043792724609375 +74019 0.202392578125 +74020 0.055206298828125 +74021 0.264495849609375 +74022 0.070343017578125 +74023 0.338897705078125 +74024 0.0938720703125 +74025 0.443817138671875 +74026 0.117431640625 +74027 0.545074462890625 +74028 0.134796142578125 +74029 0.6173095703125 +74030 0.143951416015625 +74031 0.6524658203125 +74032 0.148040771484375 +74033 0.66339111328125 +74034 0.148468017578125 +74035 0.6561279296875 +74036 0.13916015625 +74037 0.606781005859375 +74038 0.116424560546875 +74039 0.501190185546875 +74040 0.083404541015625 +74041 0.352783203125 +74042 0.0435791015625 +74043 0.176544189453125 +74044 -0.0050048828125 +74045 -0.034820556640625 +74046 -0.05682373046875 +74047 -0.258209228515625 +74048 -0.099395751953125 +74049 -0.44244384765625 +74050 -0.129852294921875 +74051 -0.5753173828125 +74052 -0.147125244140625 +74053 -0.65203857421875 +74054 -0.14361572265625 +74055 -0.641632080078125 +74056 -0.123870849609375 +74057 -0.562164306640625 +74058 -0.098846435546875 +74059 -0.458038330078125 +74060 -0.073760986328125 +74061 -0.350555419921875 +74062 -0.05364990234375 +74063 -0.260528564453125 +74064 -0.039398193359375 +74065 -0.192108154296875 +74066 -0.030029296875 +74067 -0.141937255859375 +74068 -0.023406982421875 +74069 -0.1021728515625 +74070 -0.016876220703125 +74071 -0.062896728515625 +74072 -0.007232666015625 +74073 -0.011932373046875 +74074 0.008636474609375 +74075 0.062835693359375 +74076 0.027740478515625 +74077 0.148712158203125 +74078 0.049163818359375 +74079 0.241729736328125 +74080 0.07476806640625 +74081 0.34912109375 +74082 0.10125732421875 +74083 0.457305908203125 +74084 0.123077392578125 +74085 0.54388427734375 +74086 0.131256103515625 +74087 0.5728759765625 +74088 0.11639404296875 +74089 0.506591796875 +74090 0.07989501953125 +74091 0.351226806640625 +74092 0.031494140625 +74093 0.146514892578125 +74094 -0.015960693359375 +74095 -0.05523681640625 +74096 -0.05322265625 +74097 -0.21624755859375 +74098 -0.080047607421875 +74099 -0.334930419921875 +74100 -0.094512939453125 +74101 -0.402984619140625 +74102 -0.1019287109375 +74103 -0.4412841796875 +74104 -0.113800048828125 +74105 -0.49578857421875 +74106 -0.128662109375 +74107 -0.5601806640625 +74108 -0.13818359375 +74109 -0.600738525390625 +74110 -0.1341552734375 +74111 -0.584228515625 +74112 -0.1087646484375 +74113 -0.47930908203125 +74114 -0.060302734375 +74115 -0.27935791015625 +74116 0.00518798828125 +74117 -0.0089111328125 +74118 0.072113037109375 +74119 0.268798828125 +74120 0.12298583984375 +74121 0.482818603515625 +74122 0.150665283203125 +74123 0.60369873046875 +74124 0.15997314453125 +74125 0.650421142578125 +74126 0.16119384765625 +74127 0.66400146484375 +74128 0.153717041015625 +74129 0.6414794921875 +74130 0.13507080078125 +74131 0.572540283203125 +74132 0.115509033203125 +74133 0.498138427734375 +74134 0.100311279296875 +74135 0.439453125 +74136 0.08428955078125 +74137 0.375518798828125 +74138 0.0595703125 +74139 0.274505615234375 +74140 0.019256591796875 +74141 0.1087646484375 +74142 -0.031158447265625 +74143 -0.099395751953125 +74144 -0.0838623046875 +74145 -0.3182373046875 +74146 -0.139251708984375 +74147 -0.5489501953125 +74148 -0.193023681640625 +74149 -0.7738037109375 +74150 -0.232177734375 +74151 -0.86383056640625 +74152 -0.24859619140625 +74153 -0.870391845703125 +74154 -0.246734619140625 +74155 -0.86895751953125 +74156 -0.229949951171875 +74157 -0.861053466796875 +74158 -0.194061279296875 +74159 -0.765869140625 +74160 -0.136322021484375 +74161 -0.5301513671875 +74162 -0.058502197265625 +74163 -0.214691162109375 +74164 0.028656005859375 +74165 0.137359619140625 +74166 0.11248779296875 +74167 0.474822998046875 +74168 0.184234619140625 +74169 0.76239013671875 +74170 0.237274169921875 +74171 0.867462158203125 +74172 0.271759033203125 +74173 0.870361328125 +74174 0.284912109375 +74175 0.86480712890625 +74176 0.278167724609375 +74177 0.831817626953125 +74178 0.257659912109375 +74179 0.677581787109375 +74180 0.224945068359375 +74181 0.495880126953125 +74182 0.1846923828125 +74183 0.30767822265625 +74184 0.137542724609375 +74185 0.116180419921875 +74186 0.07568359375 +74187 -0.110748291015625 +74188 -0.0025634765625 +74189 -0.381805419921875 +74190 -0.0865478515625 +74191 -0.6572265625 +74192 -0.16143798828125 +74193 -0.857421875 +74194 -0.21661376953125 +74195 -0.870391845703125 +74196 -0.250396728515625 +74197 -0.870391845703125 +74198 -0.26953125 +74199 -0.86444091796875 +74200 -0.282958984375 +74201 -0.85723876953125 +74202 -0.28619384765625 +74203 -0.790008544921875 +74204 -0.265869140625 +74205 -0.62847900390625 +74206 -0.221282958984375 +74207 -0.3956298828125 +74208 -0.16064453125 +74209 -0.126708984375 +74210 -0.090789794921875 +74211 0.150115966796875 +74212 -0.014678955078125 +74213 0.424041748046875 +74214 0.060943603515625 +74215 0.670623779296875 +74216 0.12646484375 +74217 0.854522705078125 +74218 0.177490234375 +74219 0.866485595703125 +74220 0.210235595703125 +74221 0.86920166015625 +74222 0.229248046875 +74223 0.8653564453125 +74224 0.237884521484375 +74225 0.857147216796875 +74226 0.235504150390625 +74227 0.766845703125 +74228 0.22344970703125 +74229 0.628509521484375 +74230 0.20013427734375 +74231 0.462127685546875 +74232 0.1719970703125 +74233 0.297210693359375 +74234 0.14215087890625 +74235 0.14862060546875 +74236 0.105010986328125 +74237 -0.00537109375 +74238 0.0625 +74239 -0.15753173828125 +74240 0.0133056640625 +74241 -0.31304931640625 +74242 -0.04608154296875 +74243 -0.48876953125 +74244 -0.102691650390625 +74245 -0.6416015625 +74246 -0.150390625 +74247 -0.751373291015625 +74248 -0.1962890625 +74249 -0.84619140625 +74250 -0.236846923828125 +74251 -0.861297607421875 +74252 -0.263214111328125 +74253 -0.863250732421875 +74254 -0.266754150390625 +74255 -0.856597900390625 +74256 -0.25103759765625 +74257 -0.7498779296875 +74258 -0.232269287109375 +74259 -0.624542236328125 +74260 -0.204132080078125 +74261 -0.47808837890625 +74262 -0.1500244140625 +74263 -0.253387451171875 +74264 -0.082366943359375 +74265 0.003692626953125 +74266 -0.019927978515625 +74267 0.2257080078125 +74268 0.041168212890625 +74269 0.427154541015625 +74270 0.11041259765625 +74271 0.643218994140625 +74272 0.185516357421875 +74273 0.855926513671875 +74274 0.250640869140625 +74275 0.870361328125 +74276 0.292205810546875 +74277 0.870361328125 +74278 0.312469482421875 +74279 0.862762451171875 +74280 0.310760498046875 +74281 0.79669189453125 +74282 0.28448486328125 +74283 0.595794677734375 +74284 0.24176025390625 +74285 0.362152099609375 +74286 0.190338134765625 +74287 0.1270751953125 +74288 0.135986328125 +74289 -0.086944580078125 +74290 0.079010009765625 +74291 -0.2784423828125 +74292 0.0093994140625 +74293 -0.484832763671875 +74294 -0.0784912109375 +74295 -0.729583740234375 +74296 -0.170806884765625 +74297 -0.86688232421875 +74298 -0.250152587890625 +74299 -0.870391845703125 +74300 -0.3154296875 +74301 -0.86859130859375 +74302 -0.36627197265625 +74303 -0.86279296875 +74304 -0.392822265625 +74305 -0.817962646484375 +74306 -0.382476806640625 +74307 -0.6116943359375 +74308 -0.33331298828125 +74309 -0.3128662109375 +74310 -0.254791259765625 +74311 0.039398193359375 +74312 -0.152435302734375 +74313 0.422821044921875 +74314 -0.03546142578125 +74315 0.805145263671875 +74316 0.077178955078125 +74317 0.870361328125 +74318 0.169708251953125 +74319 0.870361328125 +74320 0.239044189453125 +74321 0.860015869140625 +74322 0.28326416015625 +74323 0.727935791015625 +74324 0.301025390625 +74325 0.48114013671875 +74326 0.29925537109375 +74327 0.2059326171875 +74328 0.284454345703125 +74329 -0.06103515625 +74330 0.25958251953125 +74331 -0.29913330078125 +74332 0.220672607421875 +74333 -0.516204833984375 +74334 0.163482666015625 +74335 -0.7252197265625 +74336 0.095062255859375 +74337 -0.85980224609375 +74338 0.024993896484375 +74339 -0.870391845703125 +74340 -0.03839111328125 +74341 -0.870391845703125 +74342 -0.08148193359375 +74343 -0.858062744140625 +74344 -0.103179931640625 +74345 -0.673004150390625 +74346 -0.118255615234375 +74347 -0.42694091796875 +74348 -0.139190673828125 +74349 -0.2100830078125 +74350 -0.165435791015625 +74351 -0.0362548828125 +74352 -0.18890380859375 +74353 0.10943603515625 +74354 -0.2041015625 +74355 0.23516845703125 +74356 -0.19952392578125 +74357 0.373687744140625 +74358 -0.17578125 +74359 0.517791748046875 +74360 -0.15057373046875 +74361 0.602783203125 +74362 -0.122528076171875 +74363 0.635711669921875 +74364 -0.082366943359375 +74365 0.655181884765625 +74366 -0.032928466796875 +74367 0.65948486328125 +74368 0.023468017578125 +74369 0.651275634765625 +74370 0.079925537109375 +74371 0.61846923828125 +74372 0.126068115234375 +74373 0.53753662109375 +74374 0.1568603515625 +74375 0.404144287109375 +74376 0.16961669921875 +74377 0.22186279296875 +74378 0.164764404296875 +74379 0.003997802734375 +74380 0.14739990234375 +74381 -0.22100830078125 +74382 0.123321533203125 +74383 -0.42449951171875 +74384 0.09857177734375 +74385 -0.579833984375 +74386 0.085174560546875 +74387 -0.641876220703125 +74388 0.081329345703125 +74389 -0.6177978515625 +74390 0.069000244140625 +74391 -0.575531005859375 +74392 0.0467529296875 +74393 -0.526336669921875 +74394 0.029144287109375 +74395 -0.42645263671875 +74396 0.02386474609375 +74397 -0.2581787109375 +74398 0.020782470703125 +74399 -0.068695068359375 +74400 0.009124755859375 +74401 0.09222412109375 +74402 -0.005828857421875 +74403 0.232147216796875 +74404 -0.021240234375 +74405 0.3509521484375 +74406 -0.04541015625 +74407 0.410064697265625 +74408 -0.086578369140625 +74409 0.372955322265625 +74410 -0.138916015625 +74411 0.2554931640625 +74412 -0.187835693359375 +74413 0.10711669921875 +74414 -0.2279052734375 +74415 -0.052886962890625 +74416 -0.248992919921875 +74417 -0.186279296875 +74418 -0.235504150390625 +74419 -0.23291015625 +74420 -0.19384765625 +74421 -0.209442138671875 +74422 -0.142486572265625 +74423 -0.174163818359375 +74424 -0.08380126953125 +74425 -0.126739501953125 +74426 -0.015045166015625 +74427 -0.048126220703125 +74428 0.05584716796875 +74429 0.0426025390625 +74430 0.11578369140625 +74431 0.10748291015625 +74432 0.16107177734375 +74433 0.1409912109375 +74434 0.204986572265625 +74435 0.19708251953125 +74436 0.245635986328125 +74437 0.273651123046875 +74438 0.26739501953125 +74439 0.31768798828125 +74440 0.27337646484375 +74441 0.341094970703125 +74442 0.270660400390625 +74443 0.368011474609375 +74444 0.2528076171875 +74445 0.37249755859375 +74446 0.2060546875 +74447 0.30072021484375 +74448 0.1318359375 +74449 0.1517333984375 +74450 0.048797607421875 +74451 -0.01470947265625 +74452 -0.0380859375 +74453 -0.1883544921875 +74454 -0.12762451171875 +74455 -0.372711181640625 +74456 -0.20269775390625 +74457 -0.51397705078125 +74458 -0.250152587890625 +74459 -0.57177734375 +74460 -0.266571044921875 +74461 -0.53948974609375 +74462 -0.255767822265625 +74463 -0.43511962890625 +74464 -0.227447509765625 +74465 -0.2962646484375 +74466 -0.19195556640625 +74467 -0.161102294921875 +74468 -0.1533203125 +74469 -0.0435791015625 +74470 -0.11090087890625 +74471 0.060394287109375 +74472 -0.069610595703125 +74473 0.13665771484375 +74474 -0.03497314453125 +74475 0.170135498046875 +74476 -0.0072021484375 +74477 0.16552734375 +74478 0.021636962890625 +74479 0.15728759765625 +74480 0.05126953125 +74481 0.150787353515625 +74482 0.073272705078125 +74483 0.12200927734375 +74484 0.088592529296875 +74485 0.080108642578125 +74486 0.103179931640625 +74487 0.05126953125 +74488 0.123626708984375 +74489 0.062896728515625 +74490 0.14288330078125 +74491 0.09271240234375 +74492 0.147186279296875 +74493 0.092987060546875 +74494 0.140655517578125 +74495 0.07855224609375 +74496 0.12762451171875 +74497 0.06427001953125 +74498 0.104522705078125 +74499 0.0347900390625 +74500 0.071868896484375 +74501 -0.01171875 +74502 0.03643798828125 +74503 -0.056060791015625 +74504 0.012298583984375 +74505 -0.055511474609375 +74506 0.000640869140625 +74507 -0.010467529296875 +74508 -0.01336669921875 +74509 0.02508544921875 +74510 -0.036041259765625 +74511 0.025665283203125 +74512 -0.058380126953125 +74513 0.017333984375 +74514 -0.078887939453125 +74515 0.00189208984375 +74516 -0.100128173828125 +74517 -0.03173828125 +74518 -0.118011474609375 +74519 -0.071502685546875 +74520 -0.137725830078125 +74521 -0.13543701171875 +74522 -0.1583251953125 +74523 -0.219970703125 +74524 -0.172821044921875 +74525 -0.300506591796875 +74526 -0.181671142578125 +74527 -0.376312255859375 +74528 -0.176361083984375 +74529 -0.416107177734375 +74530 -0.143280029296875 +74531 -0.371124267578125 +74532 -0.0838623046875 +74533 -0.242279052734375 +74534 -0.011322021484375 +74535 -0.069732666015625 +74536 0.066925048828125 +74537 0.125640869140625 +74538 0.140533447265625 +74539 0.31268310546875 +74540 0.197662353515625 +74541 0.45501708984375 +74542 0.238250732421875 +74543 0.554779052734375 +74544 0.261444091796875 +74545 0.61065673828125 +74546 0.263519287109375 +74547 0.610931396484375 +74548 0.23724365234375 +74549 0.531463623046875 +74550 0.18768310546875 +74551 0.3883056640625 +74552 0.131317138671875 +74553 0.23468017578125 +74554 0.076202392578125 +74555 0.095245361328125 +74556 0.03094482421875 +74557 -0.00396728515625 +74558 0.000762939453125 +74559 -0.04852294921875 +74560 -0.018402099609375 +74561 -0.055145263671875 +74562 -0.041168212890625 +74563 -0.0758056640625 +74564 -0.075103759765625 +74565 -0.138702392578125 +74566 -0.109039306640625 +74567 -0.209197998046875 +74568 -0.14288330078125 +74569 -0.289031982421875 +74570 -0.176361083984375 +74571 -0.37884521484375 +74572 -0.202484130859375 +74573 -0.456329345703125 +74574 -0.219696044921875 +74575 -0.51641845703125 +74576 -0.216217041015625 +74577 -0.519287109375 +74578 -0.19036865234375 +74579 -0.458251953125 +74580 -0.1580810546875 +74581 -0.384796142578125 +74582 -0.12744140625 +74583 -0.323699951171875 +74584 -0.097442626953125 +74585 -0.269287109375 +74586 -0.061004638671875 +74587 -0.1951904296875 +74588 -0.01849365234375 +74589 -0.100006103515625 +74590 0.021240234375 +74591 -0.01055908203125 +74592 0.066619873046875 +74593 0.1033935546875 +74594 0.1192626953125 +74595 0.24908447265625 +74596 0.162750244140625 +74597 0.373199462890625 +74598 0.1915283203125 +74599 0.45806884765625 +74600 0.20782470703125 +74601 0.511474609375 +74602 0.221282958984375 +74603 0.565399169921875 +74604 0.2296142578125 +74605 0.61138916015625 +74606 0.21527099609375 +74607 0.5897216796875 +74608 0.175811767578125 +74609 0.4906005859375 +74610 0.1170654296875 +74611 0.33148193359375 +74612 0.05029296875 +74613 0.147796630859375 +74614 -0.01129150390625 +74615 -0.01873779296875 +74616 -0.0587158203125 +74617 -0.140289306640625 +74618 -0.083953857421875 +74619 -0.191986083984375 +74620 -0.08966064453125 +74621 -0.184295654296875 +74622 -0.088836669921875 +74623 -0.161834716796875 +74624 -0.093780517578125 +74625 -0.166595458984375 +74626 -0.10296630859375 +74627 -0.19390869140625 +74628 -0.110626220703125 +74629 -0.22442626953125 +74630 -0.12335205078125 +74631 -0.279754638671875 +74632 -0.13519287109375 +74633 -0.3389892578125 +74634 -0.1322021484375 +74635 -0.3543701171875 +74636 -0.12152099609375 +74637 -0.348175048828125 +74638 -0.1053466796875 +74639 -0.32598876953125 +74640 -0.0753173828125 +74641 -0.2581787109375 +74642 -0.030517578125 +74643 -0.139801025390625 +74644 0.024200439453125 +74645 0.014617919921875 +74646 0.0701904296875 +74647 0.144378662109375 +74648 0.09857177734375 +74649 0.221038818359375 +74650 0.116943359375 +74651 0.27069091796875 +74652 0.125396728515625 +74653 0.294036865234375 +74654 0.130096435546875 +74655 0.311767578125 +74656 0.1357421875 +74657 0.339141845703125 +74658 0.137908935546875 +74659 0.360260009765625 +74660 0.132476806640625 +74661 0.360504150390625 +74662 0.109893798828125 +74663 0.308380126953125 +74664 0.06353759765625 +74665 0.18170166015625 +74666 0.00140380859375 +74667 0.0047607421875 +74668 -0.061553955078125 +74669 -0.17559814453125 +74670 -0.1109619140625 +74671 -0.3143310546875 +74672 -0.132904052734375 +74673 -0.36785888671875 +74674 -0.13531494140625 +74675 -0.36248779296875 +74676 -0.13214111328125 +74677 -0.343536376953125 +74678 -0.120452880859375 +74679 -0.3018798828125 +74680 -0.09832763671875 +74681 -0.231414794921875 +74682 -0.061279296875 +74683 -0.117645263671875 +74684 -0.01953125 +74685 0.007049560546875 +74686 0.0096435546875 +74687 0.087982177734375 +74688 0.030487060546875 +74689 0.13946533203125 +74690 0.04669189453125 +74691 0.17425537109375 +74692 0.056640625 +74693 0.188201904296875 +74694 0.056884765625 +74695 0.171234130859375 +74696 0.04559326171875 +74697 0.118438720703125 +74698 0.031005859375 +74699 0.05706787109375 +74700 0.013580322265625 +74701 -0.010711669921875 +74702 -0.008880615234375 +74703 -0.0914306640625 +74704 -0.029388427734375 +74705 -0.162322998046875 +74706 -0.039031982421875 +74707 -0.194549560546875 +74708 -0.02569580078125 +74709 -0.1492919921875 +74710 0.01220703125 +74711 -0.02166748046875 +74712 0.05474853515625 +74713 0.124053955078125 +74714 0.07818603515625 +74715 0.211151123046875 +74716 0.0830078125 +74717 0.240447998046875 +74718 0.07891845703125 +74719 0.242218017578125 +74720 0.069091796875 +74721 0.2257080078125 +74722 0.05487060546875 +74723 0.194366455078125 +74724 0.026275634765625 +74725 0.115509033203125 +74726 -0.009063720703125 +74727 0.0128173828125 +74728 -0.03228759765625 +74729 -0.053802490234375 +74730 -0.051513671875 +74731 -0.110626220703125 +74732 -0.079742431640625 +74733 -0.199493408203125 +74734 -0.108856201171875 +74735 -0.29437255859375 +74736 -0.119232177734375 +74737 -0.33221435546875 +74738 -0.1005859375 +74739 -0.27972412109375 +74740 -0.068206787109375 +74741 -0.185333251953125 +74742 -0.04693603515625 +74743 -0.128204345703125 +74744 -0.03924560546875 +74745 -0.115692138671875 +74746 -0.035614013671875 +74747 -0.116455078125 +74748 -0.028594970703125 +74749 -0.105926513671875 +74750 -0.00897216796875 +74751 -0.053955078125 +74752 0.02618408203125 +74753 0.048797607421875 +74754 0.0623779296875 +74755 0.157318115234375 +74756 0.079803466796875 +74757 0.212005615234375 +74758 0.08050537109375 +74759 0.218475341796875 +74760 0.085418701171875 +74761 0.23724365234375 +74762 0.10736083984375 +74763 0.30535888671875 +74764 0.132110595703125 +74765 0.38128662109375 +74766 0.138824462890625 +74767 0.404449462890625 +74768 0.13427734375 +74769 0.3944091796875 +74770 0.131378173828125 +74771 0.3885498046875 +74772 0.121826171875 +74773 0.362640380859375 +74774 0.090789794921875 +74775 0.27362060546875 +74776 0.036773681640625 +74777 0.11712646484375 +74778 -0.0223388671875 +74779 -0.054901123046875 +74780 -0.06884765625 +74781 -0.19085693359375 +74782 -0.101043701171875 +74783 -0.28570556640625 +74784 -0.118896484375 +74785 -0.339263916015625 +74786 -0.131378173828125 +74787 -0.3775634765625 +74788 -0.154052734375 +74789 -0.445709228515625 +74790 -0.183990478515625 +74791 -0.535064697265625 +74792 -0.21551513671875 +74793 -0.629058837890625 +74794 -0.238311767578125 +74795 -0.697601318359375 +74796 -0.239776611328125 +74797 -0.70391845703125 +74798 -0.218048095703125 +74799 -0.6424560546875 +74800 -0.16558837890625 +74801 -0.491241455078125 +74802 -0.087738037109375 +74803 -0.265716552734375 +74804 -0.00439453125 +74805 -0.023712158203125 +74806 0.073028564453125 +74807 0.201751708984375 +74808 0.132568359375 +74809 0.375823974609375 +74810 0.169647216796875 +74811 0.485076904296875 +74812 0.19781494140625 +74813 0.56884765625 +74814 0.2197265625 +74815 0.634765625 +74816 0.21990966796875 +74817 0.63763427734375 +74818 0.1944580078125 +74819 0.5660400390625 +74820 0.161346435546875 +74821 0.4720458984375 +74822 0.13824462890625 +74823 0.40692138671875 +74824 0.127655029296875 +74825 0.3778076171875 +74826 0.126922607421875 +74827 0.376953125 +74828 0.12493896484375 +74829 0.371978759765625 +74830 0.104583740234375 +74831 0.313140869140625 +74832 0.06036376953125 +74833 0.184417724609375 +74834 0.001007080078125 +74835 0.011199951171875 +74836 -0.061279296875 +74837 -0.171051025390625 +74838 -0.117950439453125 +74839 -0.33740234375 +74840 -0.16357421875 +74841 -0.47198486328125 +74842 -0.1932373046875 +74843 -0.560394287109375 +74844 -0.19940185546875 +74845 -0.58056640625 +74846 -0.18731689453125 +74847 -0.54754638671875 +74848 -0.173248291015625 +74849 -0.508575439453125 +74850 -0.155792236328125 +74851 -0.459503173828125 +74852 -0.132965087890625 +74853 -0.394378662109375 +74854 -0.1182861328125 +74855 -0.35260009765625 +74856 -0.104034423828125 +74857 -0.31170654296875 +74858 -0.064666748046875 +74859 -0.197418212890625 +74860 0.0003662109375 +74861 -0.007965087890625 +74862 0.07415771484375 +74863 0.207489013671875 +74864 0.14306640625 +74865 0.409210205078125 +74866 0.198486328125 +74867 0.57208251953125 +74868 0.2301025390625 +74869 0.66595458984375 +74870 0.226898193359375 +74871 0.65875244140625 +74872 0.19476318359375 +74873 0.56744384765625 +74874 0.14727783203125 +74875 0.431396484375 +74876 0.099578857421875 +74877 0.29443359375 +74878 0.060577392578125 +74879 0.182464599609375 +74880 0.019378662109375 +74881 0.06365966796875 +74882 -0.02880859375 +74883 -0.075958251953125 +74884 -0.06781005859375 +74885 -0.189422607421875 +74886 -0.095977783203125 +74887 -0.271942138671875 +74888 -0.119873046875 +74889 -0.342529296875 +74890 -0.126861572265625 +74891 -0.364166259765625 +74892 -0.113616943359375 +74893 -0.327239990234375 +74894 -0.095733642578125 +74895 -0.2769775390625 +74896 -0.087127685546875 +74897 -0.253692626953125 +74898 -0.08306884765625 +74899 -0.24365234375 +74900 -0.066925048828125 +74901 -0.1983642578125 +74902 -0.0382080078125 +74903 -0.116241455078125 +74904 -0.010498046875 +74905 -0.036834716796875 +74906 0.014434814453125 +74907 0.034881591796875 +74908 0.033935546875 +74909 0.09124755859375 +74910 0.03997802734375 +74911 0.10888671875 +74912 0.0455322265625 +74913 0.125518798828125 +74914 0.056304931640625 +74915 0.15771484375 +74916 0.062957763671875 +74917 0.17828369140625 +74918 0.059967041015625 +74919 0.17108154296875 +74920 0.0452880859375 +74921 0.129974365234375 +74922 0.02838134765625 +74923 0.082427978515625 +74924 0.009033203125 +74925 0.027679443359375 +74926 -0.02349853515625 +74927 -0.065643310546875 +74928 -0.056060791015625 +74929 -0.15936279296875 +74930 -0.074737548828125 +74931 -0.21307373046875 +74932 -0.082244873046875 +74933 -0.234649658203125 +74934 -0.07037353515625 +74935 -0.2001953125 +74936 -0.042388916015625 +74937 -0.119171142578125 +74938 -0.00970458984375 +74939 -0.024749755859375 +74940 0.028564453125 +74941 0.085784912109375 +74942 0.060577392578125 +74943 0.178131103515625 +74944 0.07373046875 +74945 0.215576171875 +74946 0.07257080078125 +74947 0.211456298828125 +74948 0.060394287109375 +74949 0.17523193359375 +74950 0.044677734375 +74951 0.128753662109375 +74952 0.03570556640625 +74953 0.1019287109375 +74954 0.02642822265625 +74955 0.0743408203125 +74956 0.015899658203125 +74957 0.04327392578125 +74958 0.014251708984375 +74959 0.038177490234375 +74960 0.027374267578125 +74961 0.076263427734375 +74962 0.049591064453125 +74963 0.14105224609375 +74964 0.065093994140625 +74965 0.186431884765625 +74966 0.06573486328125 +74967 0.188812255859375 +74968 0.048370361328125 +74969 0.1390380859375 +74970 0.0146484375 +74971 0.041778564453125 +74972 -0.027313232421875 +74973 -0.079437255859375 +74974 -0.07568359375 +74975 -0.219390869140625 +74976 -0.12689208984375 +74977 -0.367828369140625 +74978 -0.170684814453125 +74979 -0.494873046875 +74980 -0.19183349609375 +74981 -0.556243896484375 +74982 -0.175445556640625 +74983 -0.508697509765625 +74984 -0.12957763671875 +74985 -0.3756103515625 +74986 -0.0755615234375 +74987 -0.218902587890625 +74988 -0.022064208984375 +74989 -0.063751220703125 +74990 0.031463623046875 +74991 0.091552734375 +74992 0.081268310546875 +74993 0.23602294921875 +74994 0.1181640625 +74995 0.342987060546875 +74996 0.13623046875 +74997 0.39520263671875 +74998 0.134307861328125 +74999 0.389373779296875 +75000 0.111968994140625 +75001 0.324249267578125 +75002 0.077545166015625 +75003 0.224090576171875 +75004 0.043243408203125 +75005 0.124267578125 +75006 0.013275146484375 +75007 0.037078857421875 +75008 -0.00250244140625 +75009 -0.010101318359375 +75010 -0.00506591796875 +75011 -0.019439697265625 +75012 -0.00604248046875 +75013 -0.022796630859375 +75014 0.00177001953125 +75015 -0.001556396484375 +75016 0.023040771484375 +75017 0.056304931640625 +75018 0.0413818359375 +75019 0.106719970703125 +75020 0.037078857421875 +75021 0.096893310546875 +75022 0.016204833984375 +75023 0.042694091796875 +75024 -0.0069580078125 +75025 -0.018035888671875 +75026 -0.02886962890625 +75027 -0.07586669921875 +75028 -0.045257568359375 +75029 -0.11944580078125 +75030 -0.060272216796875 +75031 -0.15972900390625 +75032 -0.076171875 +75033 -0.202606201171875 +75034 -0.0931396484375 +75035 -0.24859619140625 +75036 -0.114044189453125 +75037 -0.30517578125 +75038 -0.13507080078125 +75039 -0.36212158203125 +75040 -0.145721435546875 +75041 -0.39141845703125 +75042 -0.1318359375 +75043 -0.35528564453125 +75044 -0.092041015625 +75045 -0.249969482421875 +75046 -0.03289794921875 +75047 -0.092864990234375 +75048 0.03546142578125 +75049 0.08905029296875 +75050 0.09027099609375 +75051 0.2352294921875 +75052 0.121429443359375 +75053 0.318817138671875 +75054 0.13604736328125 +75055 0.358642578125 +75056 0.13153076171875 +75057 0.347747802734375 +75058 0.10772705078125 +75059 0.28564453125 +75060 0.083770751953125 +75061 0.223175048828125 +75062 0.073394775390625 +75063 0.196746826171875 +75064 0.066650390625 +75065 0.179840087890625 +75066 0.05718994140625 +75067 0.155548095703125 +75068 0.055328369140625 +75069 0.151214599609375 +75070 0.057342529296875 +75071 0.156951904296875 +75072 0.047821044921875 +75073 0.13177490234375 +75074 0.03619384765625 +75075 0.100799560546875 +75076 0.03118896484375 +75077 0.087127685546875 +75078 0.019287109375 +75079 0.05487060546875 +75080 -0.004425048828125 +75081 -0.009002685546875 +75082 -0.039764404296875 +75083 -0.10400390625 +75084 -0.08648681640625 +75085 -0.229400634765625 +75086 -0.133453369140625 +75087 -0.35552978515625 +75088 -0.16546630859375 +75089 -0.441925048828125 +75090 -0.17706298828125 +75091 -0.473846435546875 +75092 -0.173309326171875 +75093 -0.464813232421875 +75094 -0.15582275390625 +75095 -0.419097900390625 +75096 -0.123748779296875 +75097 -0.334320068359375 +75098 -0.083648681640625 +75099 -0.227935791015625 +75100 -0.04437255859375 +75101 -0.12347412109375 +75102 -0.0084228515625 +75103 -0.02764892578125 +75104 0.031036376953125 +75105 0.077667236328125 +75106 0.081787109375 +75107 0.2132568359375 +75108 0.147491455078125 +75109 0.38885498046875 +75110 0.22003173828125 +75111 0.582794189453125 +75112 0.2764892578125 +75113 0.734039306640625 +75114 0.300933837890625 +75115 0.800140380859375 +75116 0.292327880859375 +75117 0.7783203125 +75118 0.249420166015625 +75119 0.6651611328125 +75120 0.171844482421875 +75121 0.45965576171875 +75122 0.07366943359375 +75123 0.199188232421875 +75124 -0.020416259765625 +75125 -0.050689697265625 +75126 -0.0889892578125 +75127 -0.23297119140625 +75128 -0.125457763671875 +75129 -0.33013916015625 +75130 -0.139678955078125 +75131 -0.368408203125 +75132 -0.14337158203125 +75133 -0.378936767578125 +75134 -0.142303466796875 +75135 -0.376983642578125 +75136 -0.142974853515625 +75137 -0.37969970703125 +75138 -0.14703369140625 +75139 -0.391510009765625 +75140 -0.14434814453125 +75141 -0.385345458984375 +75142 -0.127685546875 +75143 -0.3419189453125 +75144 -0.105194091796875 +75145 -0.28289794921875 +75146 -0.09320068359375 +75147 -0.251617431640625 +75148 -0.098480224609375 +75149 -0.266143798828125 +75150 -0.10107421875 +75151 -0.273345947265625 +75152 -0.079742431640625 +75153 -0.216796875 +75154 -0.04644775390625 +75155 -0.128265380859375 +75156 -0.023895263671875 +75157 -0.068145751953125 +75158 -0.014556884765625 +75159 -0.0430908203125 +75160 -0.0076904296875 +75161 -0.024444580078125 +75162 0.009063720703125 +75163 0.020721435546875 +75164 0.047760009765625 +75165 0.124481201171875 +75166 0.0975341796875 +75167 0.25787353515625 +75168 0.1427001953125 +75169 0.379119873046875 +75170 0.18017578125 +75171 0.47991943359375 +75172 0.197906494140625 +75173 0.5281982421875 +75174 0.19110107421875 +75175 0.511138916015625 +75176 0.170135498046875 +75177 0.456207275390625 +75178 0.151580810546875 +75179 0.407470703125 +75180 0.142547607421875 +75181 0.383758544921875 +75182 0.132415771484375 +75183 0.35687255859375 +75184 0.11553955078125 +75185 0.31182861328125 +75186 0.0927734375 +75187 0.250885009765625 +75188 0.06085205078125 +75189 0.1654052734375 +75190 0.01220703125 +75191 0.035247802734375 +75192 -0.054107666015625 +75193 -0.142059326171875 +75194 -0.126495361328125 +75195 -0.33563232421875 +75196 -0.20086669921875 +75197 -0.5345458984375 +75198 -0.2708740234375 +75199 -0.72186279296875 +75200 -0.3135986328125 +75201 -0.836669921875 +75202 -0.311676025390625 +75203 -0.8326416015625 +75204 -0.2725830078125 +75205 -0.7296142578125 +75206 -0.217041015625 +75207 -0.582550048828125 +75208 -0.163330078125 +75209 -0.440093994140625 +75210 -0.1197509765625 +75211 -0.324310302734375 +75212 -0.073638916015625 +75213 -0.20147705078125 +75214 -0.014801025390625 +75215 -0.044647216796875 +75216 0.04083251953125 +75217 0.103973388671875 +75218 0.0775146484375 +75219 0.202392578125 +75220 0.1004638671875 +75221 0.264495849609375 +75222 0.12799072265625 +75223 0.338897705078125 +75224 0.166961669921875 +75225 0.443817138671875 +75226 0.204559326171875 +75227 0.545074462890625 +75228 0.23126220703125 +75229 0.6173095703125 +75230 0.24407958984375 +75231 0.6524658203125 +75232 0.24786376953125 +75233 0.66339111328125 +75234 0.244903564453125 +75235 0.6561279296875 +75236 0.226226806640625 +75237 0.606781005859375 +75238 0.186492919921875 +75239 0.501190185546875 +75240 0.1307373046875 +75241 0.352783203125 +75242 0.06463623046875 +75243 0.176544189453125 +75244 -0.014556884765625 +75245 -0.034820556640625 +75246 -0.09814453125 +75247 -0.258209228515625 +75248 -0.16693115234375 +75249 -0.44244384765625 +75250 -0.21636962890625 +75251 -0.5753173828125 +75252 -0.244659423828125 +75253 -0.65203857421875 +75254 -0.240203857421875 +75255 -0.641632080078125 +75256 -0.2098388671875 +75257 -0.562164306640625 +75258 -0.170318603515625 +75259 -0.458038330078125 +75260 -0.129638671875 +75261 -0.350555419921875 +75262 -0.09564208984375 +75263 -0.260528564453125 +75264 -0.070037841796875 +75265 -0.192108154296875 +75266 -0.0516357421875 +75267 -0.141937255859375 +75268 -0.037200927734375 +75269 -0.1021728515625 +75270 -0.022857666015625 +75271 -0.062896728515625 +75272 -0.00372314453125 +75273 -0.011932373046875 +75274 0.025054931640625 +75275 0.062835693359375 +75276 0.058319091796875 +75277 0.148712158203125 +75278 0.094512939453125 +75279 0.241729736328125 +75280 0.136688232421875 +75281 0.34912109375 +75282 0.179351806640625 +75283 0.457305908203125 +75284 0.213470458984375 +75285 0.54388427734375 +75286 0.224456787109375 +75287 0.5728759765625 +75288 0.196990966796875 +75289 0.506591796875 +75290 0.133636474609375 +75291 0.351226806640625 +75292 0.05059814453125 +75293 0.146514892578125 +75294 -0.03076171875 +75295 -0.05523681640625 +75296 -0.0950927734375 +75297 -0.21624755859375 +75298 -0.141815185546875 +75299 -0.334930419921875 +75300 -0.1676025390625 +75301 -0.402984619140625 +75302 -0.181121826171875 +75303 -0.4412841796875 +75304 -0.20123291015625 +75305 -0.49578857421875 +75306 -0.2254638671875 +75307 -0.5601806640625 +75308 -0.24017333984375 +75309 -0.600738525390625 +75310 -0.231903076171875 +75311 -0.584228515625 +75312 -0.187896728515625 +75313 -0.47930908203125 +75314 -0.10552978515625 +75315 -0.27935791015625 +75316 0.005096435546875 +75317 -0.0089111328125 +75318 0.1181640625 +75319 0.268798828125 +75320 0.20477294921875 +75321 0.482818603515625 +75322 0.252960205078125 +75323 0.60369873046875 +75324 0.270538330078125 +75325 0.650421142578125 +75326 0.27435302734375 +75327 0.66400146484375 +75328 0.2633056640625 +75329 0.6414794921875 +75330 0.233306884765625 +75331 0.572540283203125 +75332 0.201141357421875 +75333 0.498138427734375 +75334 0.175537109375 +75335 0.439453125 +75336 0.148040771484375 +75337 0.375518798828125 +75338 0.105743408203125 +75339 0.274505615234375 +75340 0.03741455078125 +75341 0.1087646484375 +75342 -0.047821044921875 +75343 -0.099395751953125 +75344 -0.136993408203125 +75345 -0.3182373046875 +75346 -0.230621337890625 +75347 -0.5489501953125 +75348 -0.32147216796875 +75349 -0.7738037109375 +75350 -0.38800048828125 +75351 -0.86383056640625 +75352 -0.416717529296875 +75353 -0.870391845703125 +75354 -0.414947509765625 +75355 -0.86895751953125 +75356 -0.388153076171875 +75357 -0.861053466796875 +75358 -0.329376220703125 +75359 -0.765869140625 +75360 -0.234100341796875 +75361 -0.5301513671875 +75362 -0.10528564453125 +75363 -0.214691162109375 +75364 0.0394287109375 +75365 0.137359619140625 +75366 0.179046630859375 +75367 0.474822998046875 +75368 0.299041748046875 +75369 0.76239013671875 +75370 0.388397216796875 +75371 0.867462158203125 +75372 0.447296142578125 +75373 0.870361328125 +75374 0.471038818359375 +75375 0.86480712890625 +75376 0.461883544921875 +75377 0.831817626953125 +75378 0.429840087890625 +75379 0.677581787109375 +75380 0.377349853515625 +75381 0.495880126953125 +75382 0.31207275390625 +75383 0.30767822265625 +75384 0.2349853515625 +75385 0.116180419921875 +75386 0.1331787109375 +75387 -0.110748291015625 +75388 0.00390625 +75389 -0.381805419921875 +75390 -0.13531494140625 +75391 -0.6572265625 +75392 -0.259979248046875 +75393 -0.857421875 +75394 -0.3525390625 +75395 -0.870391845703125 +75396 -0.41009521484375 +75397 -0.870391845703125 +75398 -0.443572998046875 +75399 -0.86444091796875 +75400 -0.467559814453125 +75401 -0.85723876953125 +75402 -0.474639892578125 +75403 -0.790008544921875 +75404 -0.442718505859375 +75405 -0.62847900390625 +75406 -0.37054443359375 +75407 -0.3956298828125 +75408 -0.271575927734375 +75409 -0.126708984375 +75410 -0.157073974609375 +75411 0.150115966796875 +75412 -0.0318603515625 +75413 0.424041748046875 +75414 0.092987060546875 +75415 0.670623779296875 +75416 0.20159912109375 +75417 0.854522705078125 +75418 0.286712646484375 +75419 0.866485595703125 +75420 0.342010498046875 +75421 0.86920166015625 +75422 0.3748779296875 +75423 0.8653564453125 +75424 0.390777587890625 +75425 0.857147216796875 +75426 0.3885498046875 +75427 0.766845703125 +75428 0.370269775390625 +75429 0.628509521484375 +75430 0.333221435546875 +75431 0.462127685546875 +75432 0.287994384765625 +75433 0.297210693359375 +75434 0.239715576171875 +75435 0.14862060546875 +75436 0.179107666015625 +75437 -0.00537109375 +75438 0.1092529296875 +75439 -0.15753173828125 +75440 0.028778076171875 +75441 -0.31304931640625 +75442 -0.067962646484375 +75443 -0.48876953125 +75444 -0.161773681640625 +75445 -0.6416015625 +75446 -0.242523193359375 +75447 -0.751373291015625 +75448 -0.31964111328125 +75449 -0.84619140625 +75450 -0.3870849609375 +75451 -0.861297607421875 +75452 -0.431304931640625 +75453 -0.863250732421875 +75454 -0.439453125 +75455 -0.856597900390625 +75456 -0.416473388671875 +75457 -0.7498779296875 +75458 -0.386016845703125 +75459 -0.624542236328125 +75460 -0.339202880859375 +75461 -0.47808837890625 +75462 -0.252227783203125 +75463 -0.253387451171875 +75464 -0.143768310546875 +75465 0.003692626953125 +75466 -0.041778564453125 +75467 0.2257080078125 +75468 0.05877685546875 +75469 0.427154541015625 +75470 0.17108154296875 +75471 0.643218994140625 +75472 0.2911376953125 +75473 0.855926513671875 +75474 0.395263671875 +75475 0.870361328125 +75476 0.463165283203125 +75477 0.870361328125 +75478 0.497772216796875 +75479 0.862762451171875 +75480 0.49786376953125 +75481 0.79669189453125 +75482 0.4595947265625 +75483 0.595794677734375 +75484 0.3948974609375 +75485 0.362152099609375 +75486 0.315277099609375 +75487 0.1270751953125 +75488 0.229400634765625 +75489 -0.086944580078125 +75490 0.138214111328125 +75491 -0.2784423828125 +75492 0.027618408203125 +75493 -0.484832763671875 +75494 -0.110137939453125 +75495 -0.729583740234375 +75496 -0.25433349609375 +75497 -0.86688232421875 +75498 -0.379058837890625 +75499 -0.870391845703125 +75500 -0.48223876953125 +75501 -0.86859130859375 +75502 -0.56292724609375 +75503 -0.86279296875 +75504 -0.606414794921875 +75505 -0.817962646484375 +75506 -0.59417724609375 +75507 -0.6116943359375 +75508 -0.523284912109375 +75509 -0.3128662109375 +75510 -0.40753173828125 +75511 0.039398193359375 +75512 -0.255126953125 +75513 0.422821044921875 +75514 -0.079742431640625 +75515 0.805145263671875 +75516 0.090728759765625 +75517 0.870361328125 +75518 0.23291015625 +75519 0.870361328125 +75520 0.342071533203125 +75521 0.860015869140625 +75522 0.41448974609375 +75523 0.727935791015625 +75524 0.447357177734375 +75525 0.48114013671875 +75526 0.451080322265625 +75527 0.2059326171875 +75528 0.435302734375 +75529 -0.06103515625 +75530 0.404083251953125 +75531 -0.29913330078125 +75532 0.350738525390625 +75533 -0.516204833984375 +75534 0.26812744140625 +75535 -0.7252197265625 +75536 0.1668701171875 +75537 -0.85980224609375 +75538 0.061798095703125 +75539 -0.870391845703125 +75540 -0.0343017578125 +75541 -0.870391845703125 +75542 -0.10015869140625 +75543 -0.858062744140625 +75544 -0.134033203125 +75545 -0.673004150390625 +75546 -0.1590576171875 +75547 -0.42694091796875 +75548 -0.1947021484375 +75549 -0.2100830078125 +75550 -0.239990234375 +75551 -0.0362548828125 +75552 -0.281951904296875 +75553 0.10943603515625 +75554 -0.311614990234375 +75555 0.23516845703125 +75556 -0.310546875 +75557 0.373687744140625 +75558 -0.279388427734375 +75559 0.517791748046875 +75560 -0.245635986328125 +75561 0.602783203125 +75562 -0.206787109375 +75563 0.635711669921875 +75564 -0.14801025390625 +75565 0.655181884765625 +75566 -0.07354736328125 +75567 0.65948486328125 +75568 0.013153076171875 +75569 0.651275634765625 +75570 0.101318359375 +75571 0.61846923828125 +75572 0.174652099609375 +75573 0.53753662109375 +75574 0.22515869140625 +75575 0.404144287109375 +75576 0.2484130859375 +75577 0.22186279296875 +75578 0.24481201171875 +75579 0.003997802734375 +75580 0.22216796875 +75581 -0.22100830078125 +75582 0.189361572265625 +75583 -0.42449951171875 +75584 0.155609130859375 +75585 -0.579833984375 +75586 0.1395263671875 +75587 -0.641876220703125 +75588 0.138031005859375 +75589 -0.6177978515625 +75590 0.122528076171875 +75591 -0.575531005859375 +75592 0.090545654296875 +75593 -0.526336669921875 +75594 0.0648193359375 +75595 -0.42645263671875 +75596 0.057403564453125 +75597 -0.2581787109375 +75598 0.05230712890625 +75599 -0.068695068359375 +75600 0.032684326171875 +75601 0.09222412109375 +75602 0.006866455078125 +75603 0.232147216796875 +75604 -0.0205078125 +75605 0.3509521484375 +75606 -0.062286376953125 +75607 0.410064697265625 +75608 -0.131195068359375 +75609 0.372955322265625 +75610 -0.21783447265625 +75611 0.2554931640625 +75612 -0.299041748046875 +75613 0.10711669921875 +75614 -0.365997314453125 +75615 -0.052886962890625 +75616 -0.402618408203125 +75617 -0.186279296875 +75618 -0.38421630859375 +75619 -0.23291015625 +75620 -0.320709228515625 +75621 -0.209442138671875 +75622 -0.24102783203125 +75623 -0.174163818359375 +75624 -0.14886474609375 +75625 -0.126739501953125 +75626 -0.039947509765625 +75627 -0.048126220703125 +75628 0.07318115234375 +75629 0.0426025390625 +75630 0.169830322265625 +75631 0.10748291015625 +75632 0.2440185546875 +75633 0.1409912109375 +75634 0.316497802734375 +75635 0.19708251953125 +75636 0.38409423828125 +75637 0.273651123046875 +75638 0.422027587890625 +75639 0.31768798828125 +75640 0.4349365234375 +75641 0.341094970703125 +75642 0.43377685546875 +75643 0.368011474609375 +75644 0.4083251953125 +75645 0.37249755859375 +75646 0.3367919921875 +75647 0.30072021484375 +75648 0.221282958984375 +75649 0.1517333984375 +75650 0.091094970703125 +75651 -0.01470947265625 +75652 -0.045928955078125 +75653 -0.1883544921875 +75654 -0.18792724609375 +75655 -0.372711181640625 +75656 -0.307891845703125 +75657 -0.51397705078125 +75658 -0.384979248046875 +75659 -0.57177734375 +75660 -0.413665771484375 +75661 -0.53948974609375 +75662 -0.3997802734375 +75663 -0.43511962890625 +75664 -0.358428955078125 +75665 -0.2962646484375 +75666 -0.3056640625 +75667 -0.161102294921875 +75668 -0.247650146484375 +75669 -0.0435791015625 +75670 -0.18328857421875 +75671 0.060394287109375 +75672 -0.120208740234375 +75673 0.13665771484375 +75674 -0.066925048828125 +75675 0.170135498046875 +75676 -0.02374267578125 +75677 0.16552734375 +75678 0.02178955078125 +75679 0.15728759765625 +75680 0.06927490234375 +75681 0.150787353515625 +75682 0.105316162109375 +75683 0.12200927734375 +75684 0.131378173828125 +75685 0.080108642578125 +75686 0.156646728515625 +75687 0.05126953125 +75688 0.19134521484375 +75689 0.062896728515625 +75690 0.224273681640625 +75691 0.09271240234375 +75692 0.233642578125 +75693 0.092987060546875 +75694 0.22576904296875 +75695 0.07855224609375 +75696 0.20758056640625 +75697 0.06427001953125 +75698 0.173248291015625 +75699 0.0347900390625 +75700 0.1234130859375 +75701 -0.01171875 +75702 0.068328857421875 +75703 -0.056060791015625 +75704 0.0289306640625 +75705 -0.055511474609375 +75706 0.007354736328125 +75707 -0.010467529296875 +75708 -0.017822265625 +75709 0.02508544921875 +75710 -0.05560302734375 +75711 0.025665283203125 +75712 -0.092529296875 +75713 0.017333984375 +75714 -0.126129150390625 +75715 0.00189208984375 +75716 -0.160003662109375 +75717 -0.03173828125 +75718 -0.18804931640625 +75719 -0.071502685546875 +75720 -0.2178955078125 +75721 -0.13543701171875 +75722 -0.24810791015625 +75723 -0.219970703125 +75724 -0.268463134765625 +75725 -0.300506591796875 +75726 -0.27972412109375 +75727 -0.376312255859375 +75728 -0.269500732421875 +75729 -0.416107177734375 +75730 -0.218048095703125 +75731 -0.371124267578125 +75732 -0.127593994140625 +75733 -0.242279052734375 +75734 -0.0177001953125 +75735 -0.069732666015625 +75736 0.10052490234375 +75737 0.125640869140625 +75738 0.211639404296875 +75739 0.31268310546875 +75740 0.2982177734375 +75741 0.45501708984375 +75742 0.36004638671875 +75743 0.554779052734375 +75744 0.395721435546875 +75745 0.61065673828125 +75746 0.399688720703125 +75747 0.610931396484375 +75748 0.361328125 +75749 0.531463623046875 +75750 0.2880859375 +75751 0.3883056640625 +75752 0.20416259765625 +75753 0.23468017578125 +75754 0.121490478515625 +75755 0.095245361328125 +75756 0.05279541015625 +75757 -0.00396728515625 +75758 0.005859375 +75759 -0.04852294921875 +75760 -0.025054931640625 +75761 -0.055145263671875 +75762 -0.061279296875 +75763 -0.0758056640625 +75764 -0.11376953125 +75765 -0.138702392578125 +75766 -0.165985107421875 +75767 -0.209197998046875 +75768 -0.2176513671875 +75769 -0.289031982421875 +75770 -0.268280029296875 +75771 -0.37884521484375 +75772 -0.3076171875 +75773 -0.456329345703125 +75774 -0.33331298828125 +75775 -0.51641845703125 +75776 -0.327911376953125 +75777 -0.519287109375 +75778 -0.2889404296875 +75779 -0.458251953125 +75780 -0.240264892578125 +75781 -0.384796142578125 +75782 -0.194000244140625 +75783 -0.323699951171875 +75784 -0.148651123046875 +75785 -0.269287109375 +75786 -0.09356689453125 +75787 -0.1951904296875 +75788 -0.029296875 +75789 -0.100006103515625 +75790 0.0308837890625 +75791 -0.01055908203125 +75792 0.09954833984375 +75793 0.1033935546875 +75794 0.1790771484375 +75795 0.24908447265625 +75796 0.244842529296875 +75797 0.373199462890625 +75798 0.2884521484375 +75799 0.45806884765625 +75800 0.313262939453125 +75801 0.511474609375 +75802 0.333740234375 +75803 0.565399169921875 +75804 0.346435546875 +75805 0.61138916015625 +75806 0.32501220703125 +75807 0.5897216796875 +75808 0.26580810546875 +75809 0.4906005859375 +75810 0.17755126953125 +75811 0.33148193359375 +75812 0.077178955078125 +75813 0.147796630859375 +75814 -0.015533447265625 +75815 -0.01873779296875 +75816 -0.087066650390625 +75817 -0.140289306640625 +75818 -0.1253662109375 +75819 -0.191986083984375 +75820 -0.134368896484375 +75821 -0.184295654296875 +75822 -0.133575439453125 +75823 -0.161834716796875 +75824 -0.14141845703125 +75825 -0.166595458984375 +75826 -0.155609130859375 +75827 -0.19390869140625 +75828 -0.167449951171875 +75829 -0.22442626953125 +75830 -0.1868896484375 +75831 -0.279754638671875 +75832 -0.20489501953125 +75833 -0.3389892578125 +75834 -0.2005615234375 +75835 -0.3543701171875 +75836 -0.184600830078125 +75837 -0.348175048828125 +75838 -0.1602783203125 +75839 -0.32598876953125 +75840 -0.1151123046875 +75841 -0.2581787109375 +75842 -0.047637939453125 +75843 -0.139801025390625 +75844 0.034820556640625 +75845 0.014617919921875 +75846 0.104248046875 +75847 0.144378662109375 +75848 0.147308349609375 +75849 0.221038818359375 +75850 0.17535400390625 +75851 0.27069091796875 +75852 0.188507080078125 +75853 0.294036865234375 +75854 0.196014404296875 +75855 0.311767578125 +75856 0.20489501953125 +75857 0.339141845703125 +75858 0.20855712890625 +75859 0.360260009765625 +75860 0.200775146484375 +75861 0.360504150390625 +75862 0.167022705078125 +75863 0.308380126953125 +75864 0.097320556640625 +75865 0.18170166015625 +75866 0.003631591796875 +75867 0.0047607421875 +75868 -0.091400146484375 +75869 -0.17559814453125 +75870 -0.166015625 +75871 -0.3143310546875 +75872 -0.19921875 +75873 -0.36785888671875 +75874 -0.2030029296875 +75875 -0.36248779296875 +75876 -0.198486328125 +75877 -0.343536376953125 +75878 -0.181182861328125 +75879 -0.3018798828125 +75880 -0.14813232421875 +75881 -0.231414794921875 +75882 -0.092529296875 +75883 -0.117645263671875 +75884 -0.029815673828125 +75885 0.007049560546875 +75886 0.013916015625 +75887 0.087982177734375 +75888 0.045074462890625 +75889 0.13946533203125 +75890 0.06927490234375 +75891 0.17425537109375 +75892 0.0841064453125 +75893 0.188201904296875 +75894 0.084381103515625 +75895 0.171234130859375 +75896 0.06732177734375 +75897 0.118438720703125 +75898 0.045379638671875 +75899 0.05706787109375 +75900 0.019195556640625 +75901 -0.010711669921875 +75902 -0.01458740234375 +75903 -0.0914306640625 +75904 -0.045379638671875 +75905 -0.162322998046875 +75906 -0.0596923828125 +75907 -0.194549560546875 +75908 -0.039215087890625 +75909 -0.1492919921875 +75910 0.0184326171875 +75911 -0.02166748046875 +75912 0.083160400390625 +75913 0.124053955078125 +75914 0.118988037109375 +75915 0.211151123046875 +75916 0.126617431640625 +75917 0.240447998046875 +75918 0.120697021484375 +75919 0.242218017578125 +75920 0.105987548828125 +75921 0.2257080078125 +75922 0.08453369140625 +75923 0.194366455078125 +75924 0.041229248046875 +75925 0.115509033203125 +75926 -0.01239013671875 +75927 0.0128173828125 +75928 -0.04779052734375 +75929 -0.053802490234375 +75930 -0.077178955078125 +75931 -0.110626220703125 +75932 -0.1202392578125 +75933 -0.199493408203125 +75934 -0.1646728515625 +75935 -0.29437255859375 +75936 -0.1807861328125 +75937 -0.33221435546875 +75938 -0.15301513671875 +75939 -0.27972412109375 +75940 -0.1043701171875 +75941 -0.185333251953125 +75942 -0.072479248046875 +75943 -0.128204345703125 +75944 -0.06109619140625 +75945 -0.115692138671875 +75946 -0.055755615234375 +75947 -0.116455078125 +75948 -0.045196533203125 +75949 -0.105926513671875 +75950 -0.0155029296875 +75951 -0.053955078125 +75952 0.0374755859375 +75953 0.048797607421875 +75954 0.092254638671875 +75955 0.157318115234375 +75956 0.120513916015625 +75957 0.212005615234375 +75958 0.12481689453125 +75959 0.218475341796875 +75960 0.133697509765625 +75961 0.23724365234375 +75962 0.164703369140625 +75963 0.30535888671875 +75964 0.19830322265625 +75965 0.38128662109375 +75966 0.206024169921875 +75967 0.404449462890625 +75968 0.19732666015625 +75969 0.3944091796875 +75970 0.190093994140625 +75971 0.3885498046875 +75972 0.17315673828125 +75973 0.362640380859375 +75974 0.12646484375 +75975 0.27362060546875 +75976 0.0482177734375 +75977 0.11712646484375 +75978 -0.03680419921875 +75979 -0.054901123046875 +75980 -0.10406494140625 +75981 -0.19085693359375 +75982 -0.15106201171875 +75983 -0.28570556640625 +75984 -0.1776123046875 +75985 -0.339263916015625 +75986 -0.195953369140625 +75987 -0.3775634765625 +75988 -0.227386474609375 +75989 -0.445709228515625 +75990 -0.267913818359375 +75991 -0.535064697265625 +75992 -0.309814453125 +75993 -0.629058837890625 +75994 -0.33905029296875 +75995 -0.697601318359375 +75996 -0.338470458984375 +75997 -0.70391845703125 +75998 -0.305633544921875 +75999 -0.6424560546875 +76000 -0.230377197265625 +76001 -0.491241455078125 +76002 -0.120208740234375 +76003 -0.265716552734375 +76004 -0.002655029296875 +76005 -0.023712158203125 +76006 0.106536865234375 +76007 0.201751708984375 +76008 0.190765380859375 +76009 0.375823974609375 +76010 0.24359130859375 +76011 0.485076904296875 +76012 0.283538818359375 +76013 0.56884765625 +76014 0.314239501953125 +76015 0.634765625 +76016 0.314422607421875 +76017 0.63763427734375 +76018 0.27874755859375 +76019 0.5660400390625 +76020 0.231903076171875 +76021 0.4720458984375 +76022 0.1982421875 +76023 0.40692138671875 +76024 0.18133544921875 +76025 0.3778076171875 +76026 0.177703857421875 +76027 0.376953125 +76028 0.1722412109375 +76029 0.371978759765625 +76030 0.141632080078125 +76031 0.313140869140625 +76032 0.078216552734375 +76033 0.184417724609375 +76034 -0.006103515625 +76035 0.011199951171875 +76036 -0.09423828125 +76037 -0.171051025390625 +76038 -0.173919677734375 +76039 -0.33740234375 +76040 -0.2374267578125 +76041 -0.47198486328125 +76042 -0.277801513671875 +76043 -0.560394287109375 +76044 -0.284149169921875 +76045 -0.58056640625 +76046 -0.2642822265625 +76047 -0.54754638671875 +76048 -0.2421875 +76049 -0.508575439453125 +76050 -0.215850830078125 +76051 -0.459503173828125 +76052 -0.182373046875 +76053 -0.394378662109375 +76054 -0.16156005859375 +76055 -0.35260009765625 +76056 -0.142059326171875 +76057 -0.31170654296875 +76058 -0.08636474609375 +76059 -0.197418212890625 +76060 0.00653076171875 +76061 -0.007965087890625 +76062 0.11199951171875 +76063 0.207489013671875 +76064 0.210235595703125 +76065 0.409210205078125 +76066 0.28875732421875 +76067 0.57208251953125 +76068 0.33258056640625 +76069 0.66595458984375 +76070 0.325714111328125 +76071 0.65875244140625 +76072 0.27691650390625 +76073 0.56744384765625 +76074 0.206146240234375 +76075 0.431396484375 +76076 0.1356201171875 +76077 0.29443359375 +76078 0.07843017578125 +76079 0.182464599609375 +76080 0.0185546875 +76081 0.06365966796875 +76082 -0.051055908203125 +76083 -0.075958251953125 +76084 -0.1068115234375 +76085 -0.189422607421875 +76086 -0.1463623046875 +76087 -0.271942138671875 +76088 -0.179412841796875 +76089 -0.342529296875 +76090 -0.1875 +76091 -0.364166259765625 +76092 -0.16595458984375 +76093 -0.327239990234375 +76094 -0.1376953125 +76095 -0.2769775390625 +76096 -0.123199462890625 +76097 -0.253692626953125 +76098 -0.115692138671875 +76099 -0.24365234375 +76100 -0.090850830078125 +76101 -0.1983642578125 +76102 -0.048004150390625 +76103 -0.116241455078125 +76104 -0.00714111328125 +76105 -0.036834716796875 +76106 0.029205322265625 +76107 0.034881591796875 +76108 0.05718994140625 +76109 0.09124755859375 +76110 0.065093994140625 +76111 0.10888671875 +76112 0.07196044921875 +76113 0.125518798828125 +76114 0.08624267578125 +76115 0.15771484375 +76116 0.094329833984375 +76117 0.17828369140625 +76118 0.088226318359375 +76119 0.17108154296875 +76120 0.06500244140625 +76121 0.129974365234375 +76122 0.03863525390625 +76123 0.082427978515625 +76124 0.008880615234375 +76125 0.027679443359375 +76126 -0.039947509765625 +76127 -0.065643310546875 +76128 -0.0885009765625 +76129 -0.15936279296875 +76130 -0.11639404296875 +76131 -0.21307373046875 +76132 -0.1275634765625 +76133 -0.234649658203125 +76134 -0.109954833984375 +76135 -0.2001953125 +76136 -0.068389892578125 +76137 -0.119171142578125 +76138 -0.019622802734375 +76139 -0.024749755859375 +76140 0.037628173828125 +76141 0.085784912109375 +76142 0.0859375 +76143 0.178131103515625 +76144 0.106719970703125 +76145 0.215576171875 +76146 0.106597900390625 +76147 0.211456298828125 +76148 0.09027099609375 +76149 0.17523193359375 +76150 0.068634033203125 +76151 0.128753662109375 +76152 0.056671142578125 +76153 0.1019287109375 +76154 0.04400634765625 +76155 0.0743408203125 +76156 0.0291748046875 +76157 0.04327392578125 +76158 0.027008056640625 +76159 0.038177490234375 +76160 0.046142578125 +76161 0.076263427734375 +76162 0.078277587890625 +76163 0.14105224609375 +76164 0.100250244140625 +76165 0.186431884765625 +76166 0.1002197265625 +76167 0.188812255859375 +76168 0.07366943359375 +76169 0.1390380859375 +76170 0.023040771484375 +76171 0.041778564453125 +76172 -0.0396728515625 +76173 -0.079437255859375 +76174 -0.111785888671875 +76175 -0.219390869140625 +76176 -0.188018798828125 +76177 -0.367828369140625 +76178 -0.253265380859375 +76179 -0.494873046875 +76180 -0.28515625 +76181 -0.556243896484375 +76182 -0.2618408203125 +76183 -0.508697509765625 +76184 -0.195068359375 +76185 -0.3756103515625 +76186 -0.1160888671875 +76187 -0.218902587890625 +76188 -0.037567138671875 +76189 -0.063751220703125 +76190 0.041290283203125 +76191 0.091552734375 +76192 0.11492919921875 +76193 0.23602294921875 +76194 0.16986083984375 +76195 0.342987060546875 +76196 0.19732666015625 +76197 0.39520263671875 +76198 0.19561767578125 +76199 0.389373779296875 +76200 0.16400146484375 +76201 0.324249267578125 +76202 0.11468505859375 +76203 0.224090576171875 +76204 0.065399169921875 +76205 0.124267578125 +76206 0.022308349609375 +76207 0.037078857421875 +76208 -0.000823974609375 +76209 -0.010101318359375 +76210 -0.005126953125 +76211 -0.019439697265625 +76212 -0.006683349609375 +76213 -0.022796630859375 +76214 0.003875732421875 +76215 -0.001556396484375 +76216 0.032623291015625 +76217 0.056304931640625 +76218 0.057403564453125 +76219 0.106719970703125 +76220 0.0516357421875 +76221 0.096893310546875 +76222 0.02337646484375 +76223 0.042694091796875 +76224 -0.00823974609375 +76225 -0.018035888671875 +76226 -0.03839111328125 +76227 -0.07586669921875 +76228 -0.061309814453125 +76229 -0.11944580078125 +76230 -0.082489013671875 +76231 -0.15972900390625 +76232 -0.104827880859375 +76233 -0.202606201171875 +76234 -0.128509521484375 +76235 -0.24859619140625 +76236 -0.15728759765625 +76237 -0.30517578125 +76238 -0.18603515625 +76239 -0.36212158203125 +76240 -0.20068359375 +76241 -0.39141845703125 +76242 -0.18212890625 +76243 -0.35528564453125 +76244 -0.1285400390625 +76245 -0.249969482421875 +76246 -0.0487060546875 +76247 -0.092864990234375 +76248 0.043701171875 +76249 0.08905029296875 +76250 0.118133544921875 +76251 0.2352294921875 +76252 0.161041259765625 +76253 0.318817138671875 +76254 0.18182373046875 +76255 0.358642578125 +76256 0.176971435546875 +76257 0.347747802734375 +76258 0.14617919921875 +76259 0.28564453125 +76260 0.115081787109375 +76261 0.223175048828125 +76262 0.10198974609375 +76263 0.196746826171875 +76264 0.093536376953125 +76265 0.179840087890625 +76266 0.081207275390625 +76267 0.155548095703125 +76268 0.07879638671875 +76269 0.151214599609375 +76270 0.081329345703125 +76271 0.156951904296875 +76272 0.06817626953125 +76273 0.13177490234375 +76274 0.052001953125 +76275 0.100799560546875 +76276 0.04449462890625 +76277 0.087127685546875 +76278 0.027587890625 +76279 0.05487060546875 +76280 -0.005218505859375 +76281 -0.009002685546875 +76282 -0.053619384765625 +76283 -0.10400390625 +76284 -0.11724853515625 +76285 -0.229400634765625 +76286 -0.18115234375 +76287 -0.35552978515625 +76288 -0.225067138671875 +76289 -0.441925048828125 +76290 -0.241912841796875 +76291 -0.473846435546875 +76292 -0.238616943359375 +76293 -0.464813232421875 +76294 -0.21685791015625 +76295 -0.419097900390625 +76296 -0.174835205078125 +76297 -0.334320068359375 +76298 -0.121429443359375 +76299 -0.227935791015625 +76300 -0.06890869140625 +76301 -0.12347412109375 +76302 -0.02056884765625 +76303 -0.02764892578125 +76304 0.03350830078125 +76305 0.077667236328125 +76306 0.10455322265625 +76307 0.2132568359375 +76308 0.197845458984375 +76309 0.38885498046875 +76310 0.3017578125 +76311 0.582794189453125 +76312 0.383544921875 +76313 0.734039306640625 +76314 0.42034912109375 +76315 0.800140380859375 +76316 0.410552978515625 +76317 0.7783203125 +76318 0.3521728515625 +76319 0.6651611328125 +76320 0.244537353515625 +76321 0.45965576171875 +76322 0.107513427734375 +76323 0.199188232421875 +76324 -0.023895263671875 +76325 -0.050689697265625 +76326 -0.11932373046875 +76327 -0.23297119140625 +76328 -0.16949462890625 +76329 -0.33013916015625 +76330 -0.18853759765625 +76331 -0.368408203125 +76332 -0.1932373046875 +76333 -0.378936767578125 +76334 -0.19183349609375 +76335 -0.376983642578125 +76336 -0.193511962890625 +76337 -0.37969970703125 +76338 -0.200592041015625 +76339 -0.391510009765625 +76340 -0.198516845703125 +76341 -0.385345458984375 +76342 -0.1768798828125 +76343 -0.3419189453125 +76344 -0.147186279296875 +76345 -0.28289794921875 +76346 -0.132537841796875 +76347 -0.251617431640625 +76348 -0.14251708984375 +76349 -0.266143798828125 +76350 -0.14849853515625 +76351 -0.273345947265625 +76352 -0.1201171875 +76353 -0.216796875 +76354 -0.07427978515625 +76355 -0.128265380859375 +76356 -0.043304443359375 +76357 -0.068145751953125 +76358 -0.03070068359375 +76359 -0.0430908203125 +76360 -0.021087646484375 +76361 -0.024444580078125 +76362 0.003204345703125 +76363 0.020721435546875 +76364 0.059356689453125 +76365 0.124481201171875 +76366 0.13177490234375 +76367 0.25787353515625 +76368 0.197998046875 +76369 0.379119873046875 +76370 0.253509521484375 +76371 0.47991943359375 +76372 0.281036376953125 +76373 0.5281982421875 +76374 0.273590087890625 +76375 0.511138916015625 +76376 0.245819091796875 +76377 0.456207275390625 +76378 0.22125244140625 +76379 0.407470703125 +76380 0.20989990234375 +76381 0.383758544921875 +76382 0.196563720703125 +76383 0.35687255859375 +76384 0.17315673828125 +76385 0.31182861328125 +76386 0.140869140625 +76387 0.250885009765625 +76388 0.095062255859375 +76389 0.1654052734375 +76390 0.024993896484375 +76391 0.035247802734375 +76392 -0.070648193359375 +76393 -0.142059326171875 +76394 -0.175262451171875 +76395 -0.33563232421875 +76396 -0.282958984375 +76397 -0.5345458984375 +76398 -0.384552001953125 +76399 -0.72186279296875 +76400 -0.447357177734375 +76401 -0.836669921875 +76402 -0.44647216796875 +76403 -0.8326416015625 +76404 -0.392486572265625 +76405 -0.7296142578125 +76406 -0.31475830078125 +76407 -0.582550048828125 +76408 -0.23931884765625 +76409 -0.440093994140625 +76410 -0.177947998046875 +76411 -0.324310302734375 +76412 -0.112548828125 +76413 -0.20147705078125 +76414 -0.02862548828125 +76415 -0.044647216796875 +76416 0.0511474609375 +76417 0.103973388671875 +76418 0.104248046875 +76419 0.202392578125 +76420 0.138092041015625 +76421 0.264495849609375 +76422 0.1787109375 +76423 0.338897705078125 +76424 0.23583984375 +76425 0.443817138671875 +76426 0.29107666015625 +76427 0.545074462890625 +76428 0.330780029296875 +76429 0.6173095703125 +76430 0.3505859375 +76431 0.6524658203125 +76432 0.357330322265625 +76433 0.66339111328125 +76434 0.35418701171875 +76435 0.6561279296875 +76436 0.32830810546875 +76437 0.606781005859375 +76438 0.2720947265625 +76439 0.501190185546875 +76440 0.192718505859375 +76441 0.352783203125 +76442 0.09820556640625 +76443 0.176544189453125 +76444 -0.01531982421875 +76445 -0.034820556640625 +76446 -0.13543701171875 +76447 -0.258209228515625 +76448 -0.23468017578125 +76449 -0.44244384765625 +76450 -0.30645751953125 +76451 -0.5753173828125 +76452 -0.348236083984375 +76453 -0.65203857421875 +76454 -0.343353271484375 +76455 -0.641632080078125 +76456 -0.301483154296875 +76457 -0.562164306640625 +76458 -0.246368408203125 +76459 -0.458038330078125 +76460 -0.18939208984375 +76461 -0.350555419921875 +76462 -0.14166259765625 +76463 -0.260528564453125 +76464 -0.105377197265625 +76465 -0.192108154296875 +76466 -0.0787353515625 +76467 -0.141937255859375 +76468 -0.0574951171875 +76469 -0.1021728515625 +76470 -0.036346435546875 +76471 -0.062896728515625 +76472 -0.008758544921875 +76473 -0.011932373046875 +76474 0.031707763671875 +76475 0.062835693359375 +76476 0.0782470703125 +76477 0.148712158203125 +76478 0.128662109375 +76479 0.241729736328125 +76480 0.186798095703125 +76481 0.34912109375 +76482 0.245361328125 +76483 0.457305908203125 +76484 0.29229736328125 +76485 0.54388427734375 +76486 0.30828857421875 +76487 0.5728759765625 +76488 0.27313232421875 +76489 0.506591796875 +76490 0.19012451171875 +76491 0.351226806640625 +76492 0.08056640625 +76493 0.146514892578125 +76494 -0.027496337890625 +76495 -0.05523681640625 +76496 -0.113800048828125 +76497 -0.21624755859375 +76498 -0.177520751953125 +76499 -0.334930419921875 +76500 -0.214202880859375 +76501 -0.402984619140625 +76502 -0.235015869140625 +76503 -0.4412841796875 +76504 -0.26458740234375 +76505 -0.49578857421875 +76506 -0.299468994140625 +76507 -0.5601806640625 +76508 -0.32159423828125 +76509 -0.600738525390625 +76510 -0.3131103515625 +76511 -0.584228515625 +76512 -0.2572021484375 +76513 -0.47930908203125 +76514 -0.15032958984375 +76515 -0.27935791015625 +76516 -0.005615234375 +76517 -0.0089111328125 +76518 0.14300537109375 +76519 0.268798828125 +76520 0.257537841796875 +76521 0.482818603515625 +76522 0.322235107421875 +76523 0.60369873046875 +76524 0.347259521484375 +76525 0.650421142578125 +76526 0.354583740234375 +76527 0.66400146484375 +76528 0.3426513671875 +76529 0.6414794921875 +76530 0.305877685546875 +76531 0.572540283203125 +76532 0.266204833984375 +76533 0.498138427734375 +76534 0.2349853515625 +76535 0.439453125 +76536 0.20098876953125 +76537 0.375518798828125 +76538 0.147125244140625 +76539 0.274505615234375 +76540 0.058563232421875 +76541 0.1087646484375 +76542 -0.052734375 +76543 -0.099395751953125 +76544 -0.170257568359375 +76545 -0.3182373046875 +76546 -0.2955322265625 +76547 -0.5489501953125 +76548 -0.418792724609375 +76549 -0.7738037109375 +76550 -0.510162353515625 +76551 -0.86383056640625 +76552 -0.550872802734375 +76553 -0.870391845703125 +76554 -0.550933837890625 +76555 -0.86895751953125 +76556 -0.5177001953125 +76557 -0.861053466796875 +76558 -0.441192626953125 +76559 -0.765869140625 +76560 -0.314727783203125 +76561 -0.5301513671875 +76562 -0.14208984375 +76563 -0.214691162109375 +76564 0.052581787109375 +76565 0.137359619140625 +76566 0.240447998046875 +76567 0.474822998046875 +76568 0.40167236328125 +76569 0.76239013671875 +76570 0.521209716796875 +76571 0.867462158203125 +76572 0.59954833984375 +76573 0.870361328125 +76574 0.630340576171875 +76575 0.86480712890625 +76576 0.616790771484375 +76577 0.831817626953125 +76578 0.572845458984375 +76579 0.677581787109375 +76580 0.5018310546875 +76581 0.495880126953125 +76582 0.414215087890625 +76583 0.30767822265625 +76584 0.311126708984375 +76585 0.116180419921875 +76586 0.174407958984375 +76587 -0.110748291015625 +76588 -6.103515625e-05 +76589 -0.381805419921875 +76590 -0.188232421875 +76591 -0.6572265625 +76592 -0.3563232421875 +76593 -0.857421875 +76594 -0.480194091796875 +76595 -0.870391845703125 +76596 -0.5560302734375 +76597 -0.870391845703125 +76598 -0.599334716796875 +76599 -0.86444091796875 +76600 -0.63055419921875 +76601 -0.85723876953125 +76602 -0.639404296875 +76603 -0.790008544921875 +76604 -0.595184326171875 +76605 -0.62847900390625 +76606 -0.49609375 +76607 -0.3956298828125 +76608 -0.36077880859375 +76609 -0.126708984375 +76610 -0.2047119140625 +76611 0.150115966796875 +76612 -0.034393310546875 +76613 0.424041748046875 +76614 0.134979248046875 +76615 0.670623779296875 +76616 0.28155517578125 +76617 0.854522705078125 +76618 0.395477294921875 +76619 0.866485595703125 +76620 0.468231201171875 +76621 0.86920166015625 +76622 0.51031494140625 +76623 0.8653564453125 +76624 0.529510498046875 +76625 0.857147216796875 +76626 0.524322509765625 +76627 0.766845703125 +76628 0.497772216796875 +76629 0.628509521484375 +76630 0.44610595703125 +76631 0.462127685546875 +76632 0.384002685546875 +76633 0.297210693359375 +76634 0.318511962890625 +76635 0.14862060546875 +76636 0.23663330078125 +76637 -0.00537109375 +76638 0.142547607421875 +76639 -0.15753173828125 +76640 0.03411865234375 +76641 -0.31304931640625 +76642 -0.09674072265625 +76643 -0.48876953125 +76644 -0.2235107421875 +76645 -0.6416015625 +76646 -0.332305908203125 +76647 -0.751373291015625 +76648 -0.4364013671875 +76649 -0.84619140625 +76650 -0.527587890625 +76651 -0.861297607421875 +76652 -0.587158203125 +76653 -0.863250732421875 +76654 -0.5972900390625 +76655 -0.856597900390625 +76656 -0.564971923828125 +76657 -0.7498779296875 +76658 -0.523101806640625 +76659 -0.624542236328125 +76660 -0.459197998046875 +76661 -0.47808837890625 +76662 -0.340057373046875 +76663 -0.253387451171875 +76664 -0.1915283203125 +76665 0.003692626953125 +76666 -0.052398681640625 +76667 0.2257080078125 +76668 0.084503173828125 +76669 0.427154541015625 +76670 0.237701416015625 +76671 0.643218994140625 +76672 0.40179443359375 +76673 0.855926513671875 +76674 0.543975830078125 +76675 0.870361328125 +76676 0.63616943359375 +76677 0.870361328125 +76678 0.682525634765625 +76679 0.862762451171875 +76680 0.68145751953125 +76681 0.79669189453125 +76682 0.627685546875 +76683 0.595794677734375 +76684 0.537811279296875 +76685 0.362152099609375 +76686 0.42779541015625 +76687 0.1270751953125 +76688 0.3096923828125 +76689 -0.086944580078125 +76690 0.1846923828125 +76691 -0.2784423828125 +76692 0.032989501953125 +76693 -0.484832763671875 +76694 -0.15631103515625 +76695 -0.729583740234375 +76696 -0.3544921875 +76697 -0.86688232421875 +76698 -0.525634765625 +76699 -0.870391845703125 +76700 -0.666961669921875 +76701 -0.86859130859375 +76702 -0.77734375 +76703 -0.86279296875 +76704 -0.83636474609375 +76705 -0.817962646484375 +76706 -0.818267822265625 +76707 -0.6116943359375 +76708 -0.71905517578125 +76709 -0.3128662109375 +76710 -0.55792236328125 +76711 0.039398193359375 +76712 -0.3463134765625 +76713 0.422821044921875 +76714 -0.103179931640625 +76715 0.805145263671875 +76716 0.132720947265625 +76717 0.870361328125 +76718 0.328948974609375 +76719 0.870361328125 +76720 0.478759765625 +76721 0.860015869140625 +76722 0.577728271484375 +76723 0.727935791015625 +76724 0.62255859375 +76725 0.48114013671875 +76726 0.62689208984375 +76727 0.2059326171875 +76728 0.603485107421875 +76729 -0.06103515625 +76730 0.5579833984375 +76731 -0.29913330078125 +76732 0.482147216796875 +76733 -0.516204833984375 +76734 0.36724853515625 +76735 -0.7252197265625 +76736 0.2275390625 +76737 -0.85980224609375 +76738 0.0826416015625 +76739 -0.870391845703125 +76740 -0.0504150390625 +76741 -0.870391845703125 +76742 -0.14373779296875 +76743 -0.858062744140625 +76744 -0.19464111328125 +76745 -0.673004150390625 +76746 -0.232635498046875 +76747 -0.42694091796875 +76748 -0.28265380859375 +76749 -0.2100830078125 +76750 -0.343231201171875 +76751 -0.0362548828125 +76752 -0.3975830078125 +76753 0.10943603515625 +76754 -0.4342041015625 +76755 0.23516845703125 +76756 -0.42950439453125 +76757 0.373687744140625 +76758 -0.384490966796875 +76759 0.517791748046875 +76760 -0.3349609375 +76761 0.602783203125 +76762 -0.278076171875 +76763 0.635711669921875 +76764 -0.195068359375 +76765 0.655181884765625 +76766 -0.091796875 +76767 0.65948486328125 +76768 0.026885986328125 +76769 0.651275634765625 +76770 0.146728515625 +76771 0.61846923828125 +76772 0.246368408203125 +76773 0.53753662109375 +76774 0.31524658203125 +76775 0.404144287109375 +76776 0.3475341796875 +76777 0.22186279296875 +76778 0.3436279296875 +76779 0.003997802734375 +76780 0.3135986328125 +76781 -0.22100830078125 +76782 0.26904296875 +76783 -0.42449951171875 +76784 0.221954345703125 +76785 -0.579833984375 +76786 0.19659423828125 +76787 -0.641876220703125 +76788 0.18927001953125 +76789 -0.6177978515625 +76790 0.163421630859375 +76791 -0.575531005859375 +76792 0.116180419921875 +76793 -0.526336669921875 +76794 0.077239990234375 +76795 -0.42645263671875 +76796 0.062469482421875 +76797 -0.2581787109375 +76798 0.051513671875 +76799 -0.068695068359375 +76800 0.0233154296875 +76801 0.09222412109375 +76802 -0.010650634765625 +76803 0.232147216796875 +76804 -0.044830322265625 +76805 0.3509521484375 +76806 -0.097320556640625 +76807 0.410064697265625 +76808 -0.186004638671875 +76809 0.372955322265625 +76810 -0.29852294921875 +76811 0.2554931640625 +76812 -0.40374755859375 +76813 0.10711669921875 +76814 -0.49005126953125 +76815 -0.052886962890625 +76816 -0.535797119140625 +76817 -0.186279296875 +76818 -0.50750732421875 +76819 -0.23291015625 +76820 -0.41888427734375 +76821 -0.209442138671875 +76822 -0.309478759765625 +76823 -0.174163818359375 +76824 -0.18426513671875 +76825 -0.126739501953125 +76826 -0.037322998046875 +76827 -0.048126220703125 +76828 0.114410400390625 +76829 0.0426025390625 +76830 0.242950439453125 +76831 0.10748291015625 +76832 0.340301513671875 +76833 0.1409912109375 +76834 0.435028076171875 +76835 0.19708251953125 +76836 0.52301025390625 +76837 0.273651123046875 +76838 0.570709228515625 +76839 0.31768798828125 +76840 0.584716796875 +76841 0.341094970703125 +76842 0.580108642578125 +76843 0.368011474609375 +76844 0.543060302734375 +76845 0.37249755859375 +76846 0.4439697265625 +76847 0.30072021484375 +76848 0.285797119140625 +76849 0.1517333984375 +76850 0.108489990234375 +76851 -0.01470947265625 +76852 -0.077301025390625 +76853 -0.1883544921875 +76854 -0.269073486328125 +76855 -0.372711181640625 +76856 -0.43017578125 +76857 -0.51397705078125 +76858 -0.5323486328125 +76859 -0.57177734375 +76860 -0.56817626953125 +76861 -0.53948974609375 +76862 -0.54583740234375 +76863 -0.43511962890625 +76864 -0.486114501953125 +76865 -0.2962646484375 +76866 -0.411102294921875 +76867 -0.161102294921875 +76868 -0.329345703125 +76869 -0.0435791015625 +76870 -0.239501953125 +76871 0.060394287109375 +76872 -0.152008056640625 +76873 0.13665771484375 +76874 -0.078582763671875 +76875 0.170135498046875 +76876 -0.0196533203125 +76877 0.16552734375 +76878 0.041778564453125 +76879 0.15728759765625 +76880 0.105224609375 +76881 0.150787353515625 +76882 0.152557373046875 +76883 0.12200927734375 +76884 0.18585205078125 +76885 0.080108642578125 +76886 0.2177734375 +76887 0.05126953125 +76888 0.26239013671875 +76889 0.062896728515625 +76890 0.304595947265625 +76891 0.09271240234375 +76892 0.3148193359375 +76893 0.092987060546875 +76894 0.301788330078125 +76895 0.07855224609375 +76896 0.275115966796875 +76897 0.06427001953125 +76898 0.226959228515625 +76899 0.0347900390625 +76900 0.158203125 +76901 -0.01171875 +76902 0.0828857421875 +76903 -0.056060791015625 +76904 0.029541015625 +76905 -0.055511474609375 +76906 0.001007080078125 +76907 -0.010467529296875 +76908 -0.031982421875 +76909 0.02508544921875 +76910 -0.081787109375 +76911 0.025665283203125 +76912 -0.130157470703125 +76913 0.017333984375 +76914 -0.173858642578125 +76915 0.00189208984375 +76916 -0.217926025390625 +76917 -0.03173828125 +76918 -0.254150390625 +76919 -0.071502685546875 +76920 -0.292999267578125 +76921 -0.13543701171875 +76922 -0.3326416015625 +76923 -0.219970703125 +76924 -0.3592529296875 +76925 -0.300506591796875 +76926 -0.373870849609375 +76927 -0.376312255859375 +76928 -0.35968017578125 +76929 -0.416107177734375 +76930 -0.289703369140625 +76931 -0.371124267578125 +76932 -0.166961669921875 +76933 -0.242279052734375 +76934 -0.01812744140625 +76935 -0.069732666015625 +76936 0.141815185546875 +76937 0.125640869140625 +76938 0.291900634765625 +76939 0.31268310546875 +76940 0.40838623046875 +76941 0.45501708984375 +76942 0.491058349609375 +76943 0.554779052734375 +76944 0.538116455078125 +76945 0.61065673828125 +76946 0.54205322265625 +76947 0.610931396484375 +76948 0.48846435546875 +76949 0.531463623046875 +76950 0.387603759765625 +76951 0.3883056640625 +76952 0.2724609375 +76953 0.23468017578125 +76954 0.159332275390625 +76955 0.095245361328125 +76956 0.06561279296875 +76957 -0.00396728515625 +76958 0.001953125 +76959 -0.04852294921875 +76960 -0.039581298828125 +76961 -0.055145263671875 +76962 -0.08807373046875 +76963 -0.0758056640625 +76964 -0.1585693359375 +76965 -0.138702392578125 +76966 -0.228546142578125 +76967 -0.209197998046875 +76968 -0.297698974609375 +76969 -0.289031982421875 +76970 -0.365447998046875 +76971 -0.37884521484375 +76972 -0.417816162109375 +76973 -0.456329345703125 +76974 -0.45172119140625 +76975 -0.51641845703125 +76976 -0.443634033203125 +76977 -0.519287109375 +76978 -0.3902587890625 +76979 -0.458251953125 +76980 -0.3236083984375 +76981 -0.384796142578125 +76982 -0.25994873046875 +76983 -0.323699951171875 +76984 -0.19744873046875 +76985 -0.269287109375 +76986 -0.122039794921875 +76987 -0.1951904296875 +76988 -0.034576416015625 +76989 -0.100006103515625 +76990 0.04718017578125 +76991 -0.01055908203125 +76992 0.139892578125 +76993 0.1033935546875 +76994 0.2467041015625 +76995 0.24908447265625 +76996 0.334716796875 +76997 0.373199462890625 +76998 0.392730712890625 +76999 0.45806884765625 +77000 0.42523193359375 +77001 0.511474609375 +77002 0.451568603515625 +77003 0.565399169921875 +77004 0.467193603515625 +77005 0.61138916015625 +77006 0.437103271484375 +77007 0.5897216796875 +77008 0.35650634765625 +77009 0.4906005859375 +77010 0.237152099609375 +77011 0.33148193359375 +77012 0.10162353515625 +77013 0.147796630859375 +77014 -0.023590087890625 +77015 -0.01873779296875 +77016 -0.120391845703125 +77017 -0.140289306640625 +77018 -0.172607421875 +77019 -0.191986083984375 +77020 -0.1854248046875 +77021 -0.184295654296875 +77022 -0.184783935546875 +77023 -0.161834716796875 +77024 -0.1953125 +77025 -0.166595458984375 +77026 -0.21392822265625 +77027 -0.19390869140625 +77028 -0.22906494140625 +77029 -0.22442626953125 +77030 -0.253997802734375 +77031 -0.279754638671875 +77032 -0.27679443359375 +77033 -0.3389892578125 +77034 -0.2696533203125 +77035 -0.3543701171875 +77036 -0.246917724609375 +77037 -0.348175048828125 +77038 -0.213043212890625 +77039 -0.32598876953125 +77040 -0.15142822265625 +77041 -0.2581787109375 +77042 -0.06024169921875 +77043 -0.139801025390625 +77044 0.05072021484375 +77045 0.014617919921875 +77046 0.14404296875 +77047 0.144378662109375 +77048 0.201904296875 +77049 0.221038818359375 +77050 0.23944091796875 +77051 0.27069091796875 +77052 0.256805419921875 +77053 0.294036865234375 +77054 0.266326904296875 +77055 0.311767578125 +77056 0.2774658203125 +77057 0.339141845703125 +77058 0.281463623046875 +77059 0.360260009765625 +77060 0.270050048828125 +77061 0.360504150390625 +77062 0.223876953125 +77063 0.308380126953125 +77064 0.12957763671875 +77065 0.18170166015625 +77066 0.00323486328125 +77067 0.0047607421875 +77068 -0.12481689453125 +77069 -0.17559814453125 +77070 -0.225372314453125 +77071 -0.3143310546875 +77072 -0.270294189453125 +77073 -0.36785888671875 +77074 -0.275634765625 +77075 -0.36248779296875 +77076 -0.2696533203125 +77077 -0.343536376953125 +77078 -0.246337890625 +77079 -0.3018798828125 +77080 -0.201751708984375 +77081 -0.231414794921875 +77082 -0.12677001953125 +77083 -0.117645263671875 +77084 -0.042144775390625 +77085 0.007049560546875 +77086 0.01715087890625 +77087 0.087982177734375 +77088 0.0596923828125 +77089 0.13946533203125 +77090 0.09295654296875 +77091 0.17425537109375 +77092 0.1136474609375 +77093 0.188201904296875 +77094 0.11474609375 +77095 0.171234130859375 +77096 0.092498779296875 +77097 0.118438720703125 +77098 0.063568115234375 +77099 0.05706787109375 +77100 0.028778076171875 +77101 -0.010711669921875 +77102 -0.016326904296875 +77103 -0.0914306640625 +77104 -0.057647705078125 +77105 -0.162322998046875 +77106 -0.07708740234375 +77107 -0.194549560546875 +77108 -0.050079345703125 +77109 -0.1492919921875 +77110 0.026611328125 +77111 -0.02166748046875 +77112 0.112640380859375 +77113 0.124053955078125 +77114 0.159912109375 +77115 0.211151123046875 +77116 0.16943359375 +77117 0.240447998046875 +77118 0.160858154296875 +77119 0.242218017578125 +77120 0.140625 +77121 0.2257080078125 +77122 0.111419677734375 +77123 0.194366455078125 +77124 0.053070068359375 +77125 0.115509033203125 +77126 -0.01898193359375 +77127 0.0128173828125 +77128 -0.0665283203125 +77129 -0.053802490234375 +77130 -0.10589599609375 +77131 -0.110626220703125 +77132 -0.1634521484375 +77133 -0.199493408203125 +77134 -0.22271728515625 +77135 -0.29437255859375 +77136 -0.243927001953125 +77137 -0.33221435546875 +77138 -0.206298828125 +77139 -0.27972412109375 +77140 -0.140716552734375 +77141 -0.185333251953125 +77142 -0.097564697265625 +77143 -0.128204345703125 +77144 -0.081878662109375 +77145 -0.115692138671875 +77146 -0.074310302734375 +77147 -0.116455078125 +77148 -0.059783935546875 +77149 -0.105926513671875 +77150 -0.019683837890625 +77151 -0.053955078125 +77152 0.051513671875 +77153 0.048797607421875 +77154 0.125030517578125 +77155 0.157318115234375 +77156 0.162994384765625 +77157 0.212005615234375 +77158 0.168792724609375 +77159 0.218475341796875 +77160 0.1806640625 +77161 0.23724365234375 +77162 0.222076416015625 +77163 0.30535888671875 +77164 0.266876220703125 +77165 0.38128662109375 +77166 0.2769775390625 +77167 0.404449462890625 +77168 0.265045166015625 +77169 0.3944091796875 +77170 0.25506591796875 +77171 0.3885498046875 +77172 0.232086181640625 +77173 0.362640380859375 +77174 0.16925048828125 +77175 0.27362060546875 +77176 0.064178466796875 +77177 0.11712646484375 +77178 -0.04998779296875 +77179 -0.054901123046875 +77180 -0.14031982421875 +77181 -0.19085693359375 +77182 -0.20343017578125 +77183 -0.28570556640625 +77184 -0.239105224609375 +77185 -0.339263916015625 +77186 -0.26373291015625 +77187 -0.3775634765625 +77188 -0.30584716796875 +77189 -0.445709228515625 +77190 -0.360076904296875 +77191 -0.535064697265625 +77192 -0.416107177734375 +77193 -0.629058837890625 +77194 -0.455108642578125 +77195 -0.697601318359375 +77196 -0.454132080078125 +77197 -0.70391845703125 +77198 -0.409942626953125 +77199 -0.6424560546875 +77200 -0.3089599609375 +77201 -0.491241455078125 +77202 -0.161224365234375 +77203 -0.265716552734375 +77204 -0.003570556640625 +77205 -0.023712158203125 +77206 0.142852783203125 +77207 0.201751708984375 +77208 0.255828857421875 +77209 0.375823974609375 +77210 0.326751708984375 +77211 0.485076904296875 +77212 0.38043212890625 +77213 0.56884765625 +77214 0.42169189453125 +77215 0.634765625 +77216 0.4219970703125 +77217 0.63763427734375 +77218 0.374237060546875 +77219 0.5660400390625 +77220 0.311492919921875 +77221 0.4720458984375 +77222 0.266357421875 +77223 0.40692138671875 +77224 0.24359130859375 +77225 0.3778076171875 +77226 0.238555908203125 +77227 0.376953125 +77228 0.23101806640625 +77229 0.371978759765625 +77230 0.189788818359375 +77231 0.313140869140625 +77232 0.104949951171875 +77233 0.184417724609375 +77234 -0.00726318359375 +77235 0.011199951171875 +77236 -0.124298095703125 +77237 -0.171051025390625 +77238 -0.2303466796875 +77239 -0.33740234375 +77240 -0.315338134765625 +77241 -0.47198486328125 +77242 -0.370208740234375 +77243 -0.560394287109375 +77244 -0.381103515625 +77245 -0.58056640625 +77246 -0.357666015625 +77247 -0.54754638671875 +77248 -0.329925537109375 +77249 -0.508575439453125 +77250 -0.295440673828125 +77251 -0.459503173828125 +77252 -0.250640869140625 +77253 -0.394378662109375 +77254 -0.220611572265625 +77255 -0.35260009765625 +77256 -0.19134521484375 +77257 -0.31170654296875 +77258 -0.116058349609375 +77259 -0.197418212890625 +77260 0.00616455078125 +77261 -0.007965087890625 +77262 0.14410400390625 +77263 0.207489013671875 +77264 0.2725830078125 +77265 0.409210205078125 +77266 0.375701904296875 +77267 0.57208251953125 +77268 0.434417724609375 +77269 0.66595458984375 +77270 0.42852783203125 +77271 0.65875244140625 +77272 0.36883544921875 +77273 0.56744384765625 +77274 0.280364990234375 +77275 0.431396484375 +77276 0.190948486328125 +77277 0.29443359375 +77278 0.117156982421875 +77279 0.182464599609375 +77280 0.039031982421875 +77281 0.06365966796875 +77282 -0.052093505859375 +77283 -0.075958251953125 +77284 -0.126373291015625 +77285 -0.189422607421875 +77286 -0.180633544921875 +77287 -0.271942138671875 +77288 -0.226776123046875 +77289 -0.342529296875 +77290 -0.241363525390625 +77291 -0.364166259765625 +77292 -0.21832275390625 +77293 -0.327239990234375 +77294 -0.18621826171875 +77295 -0.2769775390625 +77296 -0.170562744140625 +77297 -0.253692626953125 +77298 -0.1627197265625 +77299 -0.24365234375 +77300 -0.132171630859375 +77301 -0.1983642578125 +77302 -0.078033447265625 +77303 -0.116241455078125 +77304 -0.025390625 +77305 -0.036834716796875 +77306 0.022430419921875 +77307 0.034881591796875 +77308 0.060455322265625 +77309 0.09124755859375 +77310 0.07379150390625 +77311 0.10888671875 +77312 0.086517333984375 +77313 0.125518798828125 +77314 0.109161376953125 +77315 0.15771484375 +77316 0.12396240234375 +77317 0.17828369140625 +77318 0.1199951171875 +77319 0.17108154296875 +77320 0.093109130859375 +77321 0.129974365234375 +77322 0.06146240234375 +77323 0.082427978515625 +77324 0.024566650390625 +77325 0.027679443359375 +77326 -0.03839111328125 +77327 -0.065643310546875 +77328 -0.101959228515625 +77329 -0.15936279296875 +77330 -0.13922119140625 +77331 -0.21307373046875 +77332 -0.155303955078125 +77333 -0.234649658203125 +77334 -0.13421630859375 +77335 -0.2001953125 +77336 -0.082122802734375 +77337 -0.119171142578125 +77338 -0.020965576171875 +77339 -0.024749755859375 +77340 0.0511474609375 +77341 0.085784912109375 +77342 0.11151123046875 +77343 0.178131103515625 +77344 0.135833740234375 +77345 0.215576171875 +77346 0.132965087890625 +77347 0.211456298828125 +77348 0.10919189453125 +77349 0.17523193359375 +77350 0.0789794921875 +77351 0.128753662109375 +77352 0.062164306640625 +77353 0.1019287109375 +77354 0.045135498046875 +77355 0.0743408203125 +77356 0.0260009765625 +77357 0.04327392578125 +77358 0.024200439453125 +77359 0.038177490234375 +77360 0.05108642578125 +77361 0.076263427734375 +77362 0.095611572265625 +77363 0.14105224609375 +77364 0.127105712890625 +77365 0.186431884765625 +77366 0.12982177734375 +77367 0.188812255859375 +77368 0.09765625 +77369 0.1390380859375 +77370 0.033660888671875 +77371 0.041778564453125 +77372 -0.04656982421875 +77373 -0.079437255859375 +77374 -0.13958740234375 +77375 -0.219390869140625 +77376 -0.238555908203125 +77377 -0.367828369140625 +77378 -0.3236083984375 +77379 -0.494873046875 +77380 -0.36529541015625 +77381 -0.556243896484375 +77382 -0.3348388671875 +77383 -0.508697509765625 +77384 -0.247711181640625 +77385 -0.3756103515625 +77386 -0.14495849609375 +77387 -0.218902587890625 +77388 -0.043212890625 +77389 -0.063751220703125 +77390 0.058685302734375 +77391 0.091552734375 +77392 0.153533935546875 +77393 0.23602294921875 +77394 0.223663330078125 +77395 0.342987060546875 +77396 0.2576904296875 +77397 0.39520263671875 +77398 0.25347900390625 +77399 0.389373779296875 +77400 0.210174560546875 +77401 0.324249267578125 +77402 0.143890380859375 +77403 0.224090576171875 +77404 0.078094482421875 +77405 0.124267578125 +77406 0.0208740234375 +77407 0.037078857421875 +77408 -0.00958251953125 +77409 -0.010101318359375 +77410 -0.014801025390625 +77411 -0.019439697265625 +77412 -0.01593017578125 +77413 -0.022796630859375 +77414 -0.000701904296875 +77415 -0.001556396484375 +77416 0.038787841796875 +77417 0.056304931640625 +77418 0.073211669921875 +77419 0.106719970703125 +77420 0.067474365234375 +77421 0.096893310546875 +77422 0.0321044921875 +77423 0.042694091796875 +77424 -0.0078125 +77425 -0.018035888671875 +77426 -0.046051025390625 +77427 -0.07586669921875 +77428 -0.075042724609375 +77429 -0.11944580078125 +77430 -0.102081298828125 +77431 -0.15972900390625 +77432 -0.13104248046875 +77433 -0.202606201171875 +77434 -0.162200927734375 +77435 -0.24859619140625 +77436 -0.20050048828125 +77437 -0.30517578125 +77438 -0.239105224609375 +77439 -0.36212158203125 +77440 -0.2593994140625 +77441 -0.39141845703125 +77442 -0.236236572265625 +77443 -0.35528564453125 +77444 -0.1671142578125 +77445 -0.249969482421875 +77446 -0.06353759765625 +77447 -0.092864990234375 +77448 0.056640625 +77449 0.08905029296875 +77450 0.15325927734375 +77451 0.2352294921875 +77452 0.20849609375 +77453 0.318817138671875 +77454 0.23486328125 +77455 0.358642578125 +77456 0.227752685546875 +77457 0.347747802734375 +77458 0.186798095703125 +77459 0.28564453125 +77460 0.145751953125 +77461 0.223175048828125 +77462 0.12872314453125 +77463 0.196746826171875 +77464 0.11810302734375 +77465 0.179840087890625 +77466 0.102630615234375 +77467 0.155548095703125 +77468 0.100433349609375 +77469 0.151214599609375 +77470 0.10491943359375 +77471 0.156951904296875 +77472 0.08880615234375 +77473 0.13177490234375 +77474 0.0687255859375 +77475 0.100799560546875 +77476 0.060028076171875 +77477 0.087127685546875 +77478 0.038848876953125 +77479 0.05487060546875 +77480 -0.003448486328125 +77481 -0.009002685546875 +77482 -0.0665283203125 +77483 -0.10400390625 +77484 -0.14990234375 +77485 -0.229400634765625 +77486 -0.23388671875 +77487 -0.35552978515625 +77488 -0.29156494140625 +77489 -0.441925048828125 +77490 -0.31317138671875 +77491 -0.473846435546875 +77492 -0.307647705078125 +77493 -0.464813232421875 +77494 -0.277801513671875 +77495 -0.419097900390625 +77496 -0.222015380859375 +77497 -0.334320068359375 +77498 -0.151824951171875 +77499 -0.227935791015625 +77500 -0.0828857421875 +77501 -0.12347412109375 +77502 -0.01959228515625 +77503 -0.02764892578125 +77504 0.050079345703125 +77505 0.077667236328125 +77506 0.13995361328125 +77507 0.2132568359375 +77508 0.256500244140625 +77509 0.38885498046875 +77510 0.38531494140625 +77511 0.582794189453125 +77512 0.485870361328125 +77513 0.734039306640625 +77514 0.529937744140625 +77515 0.800140380859375 +77516 0.51568603515625 +77517 0.7783203125 +77518 0.440826416015625 +77519 0.6651611328125 +77520 0.3046875 +77521 0.45965576171875 +77522 0.132080078125 +77523 0.199188232421875 +77524 -0.033477783203125 +77525 -0.050689697265625 +77526 -0.154144287109375 +77527 -0.23297119140625 +77528 -0.218353271484375 +77529 -0.33013916015625 +77530 -0.24346923828125 +77531 -0.368408203125 +77532 -0.250213623046875 +77533 -0.378936767578125 +77534 -0.248748779296875 +77535 -0.376983642578125 +77536 -0.250457763671875 +77537 -0.37969970703125 +77538 -0.258270263671875 +77539 -0.391510009765625 +77540 -0.254241943359375 +77541 -0.385345458984375 +77542 -0.225555419921875 +77543 -0.3419189453125 +77544 -0.18658447265625 +77545 -0.28289794921875 +77546 -0.166107177734375 +77547 -0.251617431640625 +77548 -0.176055908203125 +77549 -0.266143798828125 +77550 -0.18115234375 +77551 -0.273345947265625 +77552 -0.1439208984375 +77553 -0.216796875 +77554 -0.085418701171875 +77555 -0.128265380859375 +77556 -0.0457763671875 +77557 -0.068145751953125 +77558 -0.029327392578125 +77559 -0.0430908203125 +77560 -0.01708984375 +77561 -0.024444580078125 +77562 0.0128173828125 +77563 0.020721435546875 +77564 0.081695556640625 +77565 0.124481201171875 +77566 0.1702880859375 +77567 0.25787353515625 +77568 0.25140380859375 +77569 0.379119873046875 +77570 0.31939697265625 +77571 0.47991943359375 +77572 0.351531982421875 +77573 0.5281982421875 +77574 0.339080810546875 +77575 0.511138916015625 +77576 0.301239013671875 +77577 0.456207275390625 +77578 0.2686767578125 +77579 0.407470703125 +77580 0.25445556640625 +77581 0.383758544921875 +77582 0.23876953125 +77583 0.35687255859375 +77584 0.21099853515625 +77585 0.31182861328125 +77586 0.172454833984375 +77587 0.250885009765625 +77588 0.116912841796875 +77589 0.1654052734375 +77590 0.030120849609375 +77591 0.035247802734375 +77592 -0.08984375 +77593 -0.142059326171875 +77594 -0.2216796875 +77595 -0.33563232421875 +77596 -0.357940673828125 +77597 -0.5345458984375 +77598 -0.486907958984375 +77599 -0.72186279296875 +77600 -0.566253662109375 +77601 -0.836669921875 +77602 -0.56378173828125 +77603 -0.8326416015625 +77604 -0.4932861328125 +77605 -0.7296142578125 +77606 -0.39288330078125 +77607 -0.582550048828125 +77608 -0.29632568359375 +77609 -0.440093994140625 +77610 -0.21881103515625 +77611 -0.324310302734375 +77612 -0.13665771484375 +77613 -0.20147705078125 +77614 -0.030914306640625 +77615 -0.044647216796875 +77616 0.0692138671875 +77617 0.103973388671875 +77618 0.134674072265625 +77619 0.202392578125 +77620 0.17529296875 +77621 0.264495849609375 +77622 0.22503662109375 +77623 0.338897705078125 +77624 0.296661376953125 +77625 0.443817138671875 +77626 0.366424560546875 +77627 0.545074462890625 +77628 0.416717529296875 +77629 0.6173095703125 +77630 0.44189453125 +77631 0.6524658203125 +77632 0.450836181640625 +77633 0.66339111328125 +77634 0.447662353515625 +77635 0.6561279296875 +77636 0.415618896484375 +77637 0.606781005859375 +77638 0.3447265625 +77639 0.501190185546875 +77640 0.244171142578125 +77641 0.352783203125 +77642 0.124237060546875 +77643 0.176544189453125 +77644 -0.020294189453125 +77645 -0.034820556640625 +77646 -0.173431396484375 +77647 -0.258209228515625 +77648 -0.299713134765625 +77649 -0.44244384765625 +77650 -0.390716552734375 +77651 -0.5753173828125 +77652 -0.443206787109375 +77653 -0.65203857421875 +77654 -0.435638427734375 +77655 -0.641632080078125 +77656 -0.380615234375 +77657 -0.562164306640625 +77658 -0.30902099609375 +77659 -0.458038330078125 +77660 -0.235565185546875 +77661 -0.350555419921875 +77662 -0.1746826171875 +77663 -0.260528564453125 +77664 -0.129150390625 +77665 -0.192108154296875 +77666 -0.096527099609375 +77667 -0.141937255859375 +77668 -0.071197509765625 +77669 -0.1021728515625 +77670 -0.046142578125 +77671 -0.062896728515625 +77672 -0.012725830078125 +77673 -0.011932373046875 +77674 0.037567138671875 +77675 0.062835693359375 +77676 0.095977783203125 +77677 0.148712158203125 +77678 0.159820556640625 +77679 0.241729736328125 +77680 0.234130859375 +77681 0.34912109375 +77682 0.30950927734375 +77683 0.457305908203125 +77684 0.370330810546875 +77685 0.54388427734375 +77686 0.39154052734375 +77687 0.5728759765625 +77688 0.3468017578125 +77689 0.506591796875 +77690 0.240325927734375 +77691 0.351226806640625 +77692 0.099700927734375 +77693 0.146514892578125 +77694 -0.038787841796875 +77695 -0.05523681640625 +77696 -0.14892578125 +77697 -0.21624755859375 +77698 -0.229705810546875 +77699 -0.334930419921875 +77700 -0.275482177734375 +77701 -0.402984619140625 +77702 -0.300872802734375 +77703 -0.4412841796875 +77704 -0.337921142578125 +77705 -0.49578857421875 +77706 -0.382232666015625 +77707 -0.5601806640625 +77708 -0.410400390625 +77709 -0.600738525390625 +77710 -0.3992919921875 +77711 -0.584228515625 +77712 -0.3270263671875 +77713 -0.47930908203125 +77714 -0.18896484375 +77715 -0.27935791015625 +77716 -0.0020751953125 +77717 -0.0089111328125 +77718 0.189666748046875 +77719 0.268798828125 +77720 0.337005615234375 +77721 0.482818603515625 +77722 0.419525146484375 +77723 0.60369873046875 +77724 0.45050048828125 +77725 0.650421142578125 +77726 0.458587646484375 +77727 0.66400146484375 +77728 0.4417724609375 +77729 0.6414794921875 +77730 0.3929443359375 +77731 0.572540283203125 +77732 0.34063720703125 +77733 0.498138427734375 +77734 0.29962158203125 +77735 0.439453125 +77736 0.255279541015625 +77737 0.375518798828125 +77738 0.185455322265625 +77739 0.274505615234375 +77740 0.070892333984375 +77741 0.1087646484375 +77742 -0.072967529296875 +77743 -0.099395751953125 +77744 -0.22406005859375 +77745 -0.3182373046875 +77746 -0.38330078125 +77747 -0.5489501953125 +77748 -0.538421630859375 +77749 -0.7738037109375 +77750 -0.65264892578125 +77751 -0.86383056640625 +77752 -0.702911376953125 +77753 -0.870391845703125 +77754 -0.70159912109375 +77755 -0.86895751953125 +77756 -0.65789794921875 +77757 -0.861053466796875 +77758 -0.559783935546875 +77759 -0.765869140625 +77760 -0.399444580078125 +77761 -0.5301513671875 +77762 -0.18182373046875 +77763 -0.214691162109375 +77764 0.063079833984375 +77765 0.137359619140625 +77766 0.299591064453125 +77767 0.474822998046875 +77768 0.503021240234375 +77769 0.76239013671875 +77770 0.654632568359375 +77771 0.867462158203125 +77772 0.7547607421875 +77773 0.870361328125 +77774 0.79541015625 +77775 0.86480712890625 +77776 0.7803955078125 +77777 0.831817626953125 +77778 0.726715087890625 +77779 0.677581787109375 +77780 0.638458251953125 +77781 0.495880126953125 +77782 0.528594970703125 +77783 0.30767822265625 +77784 0.398681640625 +77785 0.116180419921875 +77786 0.2266845703125 +77787 -0.110748291015625 +77788 0.007781982421875 +77789 -0.381805419921875 +77790 -0.228179931640625 +77791 -0.6572265625 +77792 -0.43951416015625 +77793 -0.857421875 +77794 -0.59637451171875 +77795 -0.870391845703125 +77796 -0.693817138671875 +77797 -0.870391845703125 +77798 -0.750579833984375 +77799 -0.86444091796875 +77800 -0.79156494140625 +77801 -0.85723876953125 +77802 -0.804046630859375 +77803 -0.790008544921875 +77804 -0.75030517578125 +77805 -0.62847900390625 +77806 -0.628173828125 +77807 -0.3956298828125 +77808 -0.460540771484375 +77809 -0.126708984375 +77810 -0.26654052734375 +77811 0.150115966796875 +77812 -0.0543212890625 +77813 0.424041748046875 +77814 0.15728759765625 +77815 0.670623779296875 +77816 0.34130859375 +77817 0.854522705078125 +77818 0.48541259765625 +77819 0.866485595703125 +77820 0.578887939453125 +77821 0.86920166015625 +77822 0.634368896484375 +77823 0.8653564453125 +77824 0.66094970703125 +77825 0.857147216796875 +77826 0.656890869140625 +77827 0.766845703125 +77828 0.6260986328125 +77829 0.628509521484375 +77830 0.563629150390625 +77831 0.462127685546875 +77832 0.4881591796875 +77833 0.297210693359375 +77834 0.408477783203125 +77835 0.14862060546875 +77836 0.307708740234375 +77837 -0.00537109375 +77838 0.19097900390625 +77839 -0.15753173828125 +77840 0.055328369140625 +77841 -0.31304931640625 +77842 -0.109771728515625 +77843 -0.48876953125 +77844 -0.2705078125 +77845 -0.6416015625 +77846 -0.409149169921875 +77847 -0.751373291015625 +77848 -0.542724609375 +77849 -0.84619140625 +77850 -0.66064453125 +77851 -0.861297607421875 +77852 -0.738861083984375 +77853 -0.863250732421875 +77854 -0.754425048828125 +77855 -0.856597900390625 +77856 -0.71612548828125 +77857 -0.7498779296875 +77858 -0.665924072265625 +77859 -0.624542236328125 +77860 -0.587646484375 +77861 -0.47808837890625 +77862 -0.438507080078125 +77863 -0.253387451171875 +77864 -0.251495361328125 +77865 0.003692626953125 +77866 -0.07611083984375 +77867 0.2257080078125 +77868 0.09698486328125 +77869 0.427154541015625 +77870 0.2916259765625 +77871 0.643218994140625 +77872 0.501007080078125 +77873 0.855926513671875 +77874 0.68310546875 +77875 0.870361328125 +77876 0.8018798828125 +77877 0.870361328125 +77878 0.855377197265625 +77879 0.862762451171875 +77880 0.855438232421875 +77881 0.79669189453125 +77882 0.7967529296875 +77883 0.595794677734375 +77884 0.684356689453125 +77885 0.362152099609375 +77886 0.54632568359375 +77887 0.1270751953125 +77888 0.397918701171875 +77889 -0.086944580078125 +77890 0.240509033203125 +77891 -0.2784423828125 +77892 0.048614501953125 +77893 -0.484832763671875 +77894 -0.191925048828125 +77895 -0.729583740234375 +77896 -0.44439697265625 +77897 -0.86688232421875 +77898 -0.662811279296875 +77899 -0.870391845703125 +77900 -0.843658447265625 +77901 -0.86859130859375 +77902 -0.868804931640625 +77903 -0.86279296875 +77904 -0.870391845703125 +77905 -0.817962646484375 +77906 -0.86181640625 +77907 -0.6116943359375 +77908 -0.7474365234375 +77909 -0.3128662109375 +77910 -0.504974365234375 +77911 0.039398193359375 +77912 -0.210296630859375 +77913 0.422821044921875 +77914 0.111358642578125 +77915 0.805145263671875 +77916 0.410186767578125 +77917 0.870361328125 +77918 0.64520263671875 +77919 0.870361328125 +77920 0.809051513671875 +77921 0.860015869140625 +77922 0.859222412109375 +77923 0.727935791015625 +77924 0.860504150390625 +77925 0.48114013671875 +77926 0.855621337890625 +77927 0.2059326171875 +77928 0.78277587890625 +77929 -0.06103515625 +77930 0.673187255859375 +77931 -0.29913330078125 +77932 0.528472900390625 +77933 -0.516204833984375 +77934 0.3399658203125 +77935 -0.7252197265625 +77936 0.1279296875 +77937 -0.85980224609375 +77938 -0.080841064453125 +77939 -0.870391845703125 +77940 -0.26361083984375 +77941 -0.870391845703125 +77942 -0.384246826171875 +77943 -0.858062744140625 +77944 -0.439605712890625 +77945 -0.673004150390625 +77946 -0.4683837890625 +77947 -0.42694091796875 +77948 -0.503875732421875 +77949 -0.2100830078125 +77950 -0.545989990234375 +77951 -0.0362548828125 +77952 -0.575408935546875 +77953 0.10943603515625 +77954 -0.579742431640625 +77955 0.23516845703125 +77956 -0.53106689453125 +77957 0.373687744140625 +77958 -0.43304443359375 +77959 0.517791748046875 +77960 -0.33367919921875 +77961 0.602783203125 +77962 -0.23114013671875 +77963 0.635711669921875 +77964 -0.102813720703125 +77965 0.655181884765625 +77966 0.04278564453125 +77967 0.65948486328125 +77968 0.199005126953125 +77969 0.651275634765625 +77970 0.347625732421875 +77971 0.61846923828125 +77972 0.46185302734375 +77973 0.53753662109375 +77974 0.529083251953125 +77975 0.404144287109375 +77976 0.543182373046875 +77977 0.22186279296875 +77978 0.50634765625 +77979 0.003997802734375 +77980 0.433349609375 +77981 -0.22100830078125 +77982 0.34100341796875 +77983 -0.42449951171875 +77984 0.246673583984375 +77985 -0.579833984375 +77986 0.1832275390625 +77987 -0.641876220703125 +77988 0.14752197265625 +77989 -0.6177978515625 +77990 0.093994140625 +77991 -0.575531005859375 +77992 0.01995849609375 +77993 -0.526336669921875 +77994 -0.0360107421875 +77995 -0.42645263671875 +77996 -0.053436279296875 +77997 -0.2581787109375 +77998 -0.0587158203125 +77999 -0.068695068359375 +78000 -0.08013916015625 +78001 0.09222412109375 +78002 -0.10479736328125 +78003 0.232147216796875 +78004 -0.126251220703125 +78005 0.3509521484375 +78006 -0.167205810546875 +78007 0.410064697265625 +78008 -0.2503662109375 +78009 0.372955322265625 +78010 -0.3619384765625 +78011 0.2554931640625 +78012 -0.46539306640625 +78013 0.10711669921875 +78014 -0.547821044921875 +78015 -0.052886962890625 +78016 -0.58404541015625 +78017 -0.186279296875 +78018 -0.534423828125 +78019 -0.23291015625 +78020 -0.416290283203125 +78021 -0.209442138671875 +78022 -0.278076171875 +78023 -0.174163818359375 +78024 -0.126007080078125 +78025 -0.126739501953125 +78026 0.04718017578125 +78027 -0.048126220703125 +78028 0.22137451171875 +78029 0.0426025390625 +78030 0.36328125 +78031 0.10748291015625 +78032 0.464080810546875 +78033 0.1409912109375 +78034 0.559417724609375 +78035 0.19708251953125 +78036 0.645416259765625 +78037 0.273651123046875 +78038 0.68255615234375 +78039 0.31768798828125 +78040 0.679931640625 +78041 0.341094970703125 +78042 0.65692138671875 +78043 0.368011474609375 +78044 0.59759521484375 +78045 0.37249755859375 +78046 0.466766357421875 +78047 0.30072021484375 +78048 0.268463134765625 +78049 0.1517333984375 +78050 0.051361083984375 +78051 -0.01470947265625 +78052 -0.171600341796875 +78053 -0.1883544921875 +78054 -0.397705078125 +78055 -0.372711181640625 +78056 -0.582916259765625 +78057 -0.51397705078125 +78058 -0.693603515625 +78059 -0.57177734375 +78060 -0.72161865234375 +78061 -0.53948974609375 +78062 -0.677764892578125 +78063 -0.43511962890625 +78064 -0.588165283203125 +78065 -0.2962646484375 +78066 -0.480621337890625 +78067 -0.161102294921875 +78068 -0.366363525390625 +78069 -0.0435791015625 +78070 -0.244537353515625 +78071 0.060394287109375 +78072 -0.12847900390625 +78073 0.13665771484375 +78074 -0.0328369140625 +78075 0.170135498046875 +78076 0.041595458984375 +78077 0.16552734375 +78078 0.115447998046875 +78079 0.15728759765625 +78080 0.18804931640625 +78081 0.150787353515625 +78082 0.23773193359375 +78083 0.12200927734375 +78084 0.26776123046875 +78085 0.080108642578125 +78086 0.294586181640625 +78087 0.05126953125 +78088 0.336395263671875 +78089 0.062896728515625 +78090 0.375030517578125 +78091 0.09271240234375 +78092 0.374298095703125 +78093 0.092987060546875 +78094 0.3458251953125 +78095 0.07855224609375 +78096 0.302215576171875 +78097 0.06427001953125 +78098 0.23419189453125 +78099 0.0347900390625 +78100 0.14324951171875 +78101 -0.01171875 +78102 0.04718017578125 +78103 -0.056060791015625 +78104 -0.018341064453125 +78105 -0.055511474609375 +78106 -0.049896240234375 +78107 -0.010467529296875 +78108 -0.08441162109375 +78109 0.02508544921875 +78110 -0.13775634765625 +78111 0.025665283203125 +78112 -0.187652587890625 +78113 0.017333984375 +78114 -0.23065185546875 +78115 0.00189208984375 +78116 -0.27374267578125 +78117 -0.03173828125 +78118 -0.30731201171875 +78119 -0.071502685546875 +78120 -0.345062255859375 +78121 -0.13543701171875 +78122 -0.385284423828125 +78123 -0.219970703125 +78124 -0.411163330078125 +78125 -0.300506591796875 +78126 -0.42431640625 +78127 -0.376312255859375 +78128 -0.4039306640625 +78129 -0.416107177734375 +78130 -0.316375732421875 +78131 -0.371124267578125 +78132 -0.165374755859375 +78133 -0.242279052734375 +78134 0.01593017578125 +78135 -0.069732666015625 +78136 0.209136962890625 +78137 0.125640869140625 +78138 0.38848876953125 +78139 0.31268310546875 +78140 0.5247802734375 +78141 0.45501708984375 +78142 0.6182861328125 +78143 0.554779052734375 +78144 0.667327880859375 +78145 0.61065673828125 +78146 0.663055419921875 +78147 0.610931396484375 +78148 0.587982177734375 +78149 0.531463623046875 +78150 0.45526123046875 +78151 0.3883056640625 +78152 0.30645751953125 +78153 0.23468017578125 +78154 0.16217041015625 +78155 0.095245361328125 +78156 0.04425048828125 +78157 -0.00396728515625 +78158 -0.03399658203125 +78159 -0.04852294921875 +78160 -0.082611083984375 +78161 -0.055145263671875 +78162 -0.138275146484375 +78163 -0.0758056640625 +78164 -0.220001220703125 +78165 -0.138702392578125 +78166 -0.30010986328125 +78167 -0.209197998046875 +78168 -0.378631591796875 +78169 -0.289031982421875 +78170 -0.455291748046875 +78171 -0.37884521484375 +78172 -0.513092041015625 +78173 -0.456329345703125 +78174 -0.54852294921875 +78175 -0.51641845703125 +78176 -0.532501220703125 +78177 -0.519287109375 +78178 -0.46124267578125 +78179 -0.458251953125 +78180 -0.375 +78181 -0.384796142578125 +78182 -0.294189453125 +78183 -0.323699951171875 +78184 -0.216583251953125 +78185 -0.269287109375 +78186 -0.124481201171875 +78187 -0.1951904296875 +78188 -0.018768310546875 +78189 -0.100006103515625 +78190 0.078582763671875 +78191 -0.01055908203125 +78192 0.188690185546875 +78193 0.1033935546875 +78194 0.315826416015625 +78195 0.24908447265625 +78196 0.419219970703125 +78197 0.373199462890625 +78198 0.48529052734375 +78199 0.45806884765625 +78200 0.51995849609375 +78201 0.511474609375 +78202 0.547760009765625 +78203 0.565399169921875 +78204 0.563232421875 +78205 0.61138916015625 +78206 0.522796630859375 +78207 0.5897216796875 +78208 0.420562744140625 +78209 0.4906005859375 +78210 0.27130126953125 +78211 0.33148193359375 +78212 0.10321044921875 +78213 0.147796630859375 +78214 -0.05072021484375 +78215 -0.01873779296875 +78216 -0.1680908203125 +78217 -0.140289306640625 +78218 -0.2288818359375 +78219 -0.191986083984375 +78220 -0.2398681640625 +78221 -0.184295654296875 +78222 -0.2337646484375 +78223 -0.161834716796875 +78224 -0.241607666015625 +78225 -0.166595458984375 +78226 -0.2598876953125 +78227 -0.19390869140625 +78228 -0.274383544921875 +78229 -0.22442626953125 +78230 -0.301910400390625 +78231 -0.279754638671875 +78232 -0.327728271484375 +78233 -0.3389892578125 +78234 -0.31719970703125 +78235 -0.3543701171875 +78236 -0.288330078125 +78237 -0.348175048828125 +78238 -0.24664306640625 +78239 -0.32598876953125 +78240 -0.171356201171875 +78241 -0.2581787109375 +78242 -0.06005859375 +78243 -0.139801025390625 +78244 0.0751953125 +78245 0.014617919921875 +78246 0.1878662109375 +78247 0.144378662109375 +78248 0.255950927734375 +78249 0.221038818359375 +78250 0.298553466796875 +78251 0.27069091796875 +78252 0.316070556640625 +78253 0.294036865234375 +78254 0.324188232421875 +78255 0.311767578125 +78256 0.334808349609375 +78257 0.339141845703125 +78258 0.3367919921875 +78259 0.360260009765625 +78260 0.320037841796875 +78261 0.360504150390625 +78262 0.26153564453125 +78263 0.308380126953125 +78264 0.145477294921875 +78265 0.18170166015625 +78266 -0.008544921875 +78267 0.0047607421875 +78268 -0.163909912109375 +78269 -0.17559814453125 +78270 -0.28546142578125 +78271 -0.3143310546875 +78272 -0.3392333984375 +78273 -0.36785888671875 +78274 -0.3446044921875 +78275 -0.36248779296875 +78276 -0.33563232421875 +78277 -0.343536376953125 +78278 -0.305206298828125 +78279 -0.3018798828125 +78280 -0.24871826171875 +78281 -0.231414794921875 +78282 -0.155426025390625 +78283 -0.117645263671875 +78284 -0.0504150390625 +78285 0.007049560546875 +78286 0.024078369140625 +78287 0.087982177734375 +78288 0.078155517578125 +78289 0.13946533203125 +78290 0.12066650390625 +78291 0.17425537109375 +78292 0.14752197265625 +78293 0.188201904296875 +78294 0.150146484375 +78295 0.171234130859375 +78296 0.1240234375 +78297 0.118438720703125 +78298 0.089141845703125 +78299 0.05706787109375 +78300 0.0465087890625 +78301 -0.010711669921875 +78302 -0.00921630859375 +78303 -0.0914306640625 +78304 -0.0609130859375 +78305 -0.162322998046875 +78306 -0.086669921875 +78307 -0.194549560546875 +78308 -0.056854248046875 +78309 -0.1492919921875 +78310 0.032562255859375 +78311 -0.02166748046875 +78312 0.13330078125 +78313 0.124053955078125 +78314 0.1876220703125 +78315 0.211151123046875 +78316 0.1968994140625 +78317 0.240447998046875 +78318 0.184814453125 +78319 0.242218017578125 +78320 0.159210205078125 +78321 0.2257080078125 +78322 0.123382568359375 +78323 0.194366455078125 +78324 0.0531005859375 +78325 0.115509033203125 +78326 -0.033050537109375 +78327 0.0128173828125 +78328 -0.089202880859375 +78329 -0.053802490234375 +78330 -0.135101318359375 +78331 -0.110626220703125 +78332 -0.2025146484375 +78333 -0.199493408203125 +78334 -0.271728515625 +78335 -0.29437255859375 +78336 -0.294677734375 +78337 -0.33221435546875 +78338 -0.2457275390625 +78339 -0.27972412109375 +78340 -0.163177490234375 +78341 -0.185333251953125 +78342 -0.10986328125 +78343 -0.128204345703125 +78344 -0.091827392578125 +78345 -0.115692138671875 +78346 -0.084564208984375 +78347 -0.116455078125 +78348 -0.068939208984375 +78349 -0.105926513671875 +78350 -0.021392822265625 +78351 -0.053955078125 +78352 0.065185546875 +78353 0.048797607421875 +78354 0.1549072265625 +78355 0.157318115234375 +78356 0.20037841796875 +78357 0.212005615234375 +78358 0.205963134765625 +78359 0.218475341796875 +78360 0.2196044921875 +78361 0.23724365234375 +78362 0.270721435546875 +78363 0.30535888671875 +78364 0.32659912109375 +78365 0.38128662109375 +78366 0.3394775390625 +78367 0.404449462890625 +78368 0.3251953125 +78369 0.3944091796875 +78370 0.313720703125 +78371 0.3885498046875 +78372 0.286285400390625 +78373 0.362640380859375 +78374 0.2091064453125 +78375 0.27362060546875 +78376 0.079071044921875 +78377 0.11712646484375 +78378 -0.062347412109375 +78379 -0.054901123046875 +78380 -0.17401123046875 +78381 -0.19085693359375 +78382 -0.251739501953125 +78383 -0.28570556640625 +78384 -0.295318603515625 +78385 -0.339263916015625 +78386 -0.3253173828125 +78387 -0.3775634765625 +78388 -0.377532958984375 +78389 -0.445709228515625 +78390 -0.44525146484375 +78391 -0.535064697265625 +78392 -0.51556396484375 +78393 -0.629058837890625 +78394 -0.56488037109375 +78395 -0.697601318359375 +78396 -0.564361572265625 +78397 -0.70391845703125 +78398 -0.50994873046875 +78399 -0.6424560546875 +78400 -0.384552001953125 +78401 -0.491241455078125 +78402 -0.20068359375 +78403 -0.265716552734375 +78404 -0.004425048828125 +78405 -0.023712158203125 +78406 0.17779541015625 +78407 0.201751708984375 +78408 0.318206787109375 +78409 0.375823974609375 +78410 0.406097412109375 +78411 0.485076904296875 +78412 0.472564697265625 +78413 0.56884765625 +78414 0.523712158203125 +78415 0.634765625 +78416 0.5238037109375 +78417 0.63763427734375 +78418 0.46392822265625 +78419 0.5660400390625 +78420 0.385528564453125 +78421 0.4720458984375 +78422 0.3294677734375 +78423 0.40692138671875 +78424 0.301666259765625 +78425 0.3778076171875 +78426 0.2962646484375 +78427 0.376953125 +78428 0.287872314453125 +78429 0.371978759765625 +78430 0.237335205078125 +78431 0.313140869140625 +78432 0.132110595703125 +78433 0.184417724609375 +78434 -0.007476806640625 +78435 0.011199951171875 +78436 -0.153228759765625 +78437 -0.171051025390625 +78438 -0.285369873046875 +78439 -0.33740234375 +78440 -0.391326904296875 +78441 -0.47198486328125 +78442 -0.459808349609375 +78443 -0.560394287109375 +78444 -0.473419189453125 +78445 -0.58056640625 +78446 -0.4442138671875 +78447 -0.54754638671875 +78448 -0.409820556640625 +78449 -0.508575439453125 +78450 -0.36712646484375 +78451 -0.459503173828125 +78452 -0.311676025390625 +78453 -0.394378662109375 +78454 -0.27484130859375 +78455 -0.35260009765625 +78456 -0.239044189453125 +78457 -0.31170654296875 +78458 -0.1456298828125 +78459 -0.197418212890625 +78460 0.00665283203125 +78461 -0.007965087890625 +78462 0.17877197265625 +78463 0.207489013671875 +78464 0.33917236328125 +78465 0.409210205078125 +78466 0.46795654296875 +78467 0.57208251953125 +78468 0.541290283203125 +78469 0.66595458984375 +78470 0.533843994140625 +78471 0.65875244140625 +78472 0.45916748046875 +78473 0.56744384765625 +78474 0.34857177734375 +78475 0.431396484375 +78476 0.236968994140625 +78477 0.29443359375 +78478 0.145050048828125 +78479 0.182464599609375 +78480 0.04779052734375 +78481 0.06365966796875 +78482 -0.065704345703125 +78483 -0.075958251953125 +78484 -0.1580810546875 +78485 -0.189422607421875 +78486 -0.225433349609375 +78487 -0.271942138671875 +78488 -0.28271484375 +78489 -0.342529296875 +78490 -0.300567626953125 +78491 -0.364166259765625 +78492 -0.2713623046875 +78493 -0.327239990234375 +78494 -0.230926513671875 +78495 -0.2769775390625 +78496 -0.21124267578125 +78497 -0.253692626953125 +78498 -0.201507568359375 +78499 -0.24365234375 +78500 -0.1634521484375 +78501 -0.1983642578125 +78502 -0.095916748046875 +78503 -0.116241455078125 +78504 -0.030364990234375 +78505 -0.036834716796875 +78506 0.029083251953125 +78507 0.034881591796875 +78508 0.076202392578125 +78509 0.09124755859375 +78510 0.092376708984375 +78511 0.10888671875 +78512 0.10736083984375 +78513 0.125518798828125 +78514 0.134185791015625 +78515 0.15771484375 +78516 0.1512451171875 +78517 0.17828369140625 +78518 0.145721435546875 +78519 0.17108154296875 +78520 0.11279296875 +78521 0.129974365234375 +78522 0.07421875 +78523 0.082427978515625 +78524 0.029510498046875 +78525 0.027679443359375 +78526 -0.046112060546875 +78527 -0.065643310546875 +78528 -0.122283935546875 +78529 -0.15936279296875 +78530 -0.166900634765625 +78531 -0.21307373046875 +78532 -0.18609619140625 +78533 -0.234649658203125 +78534 -0.16082763671875 +78535 -0.2001953125 +78536 -0.0985107421875 +78537 -0.119171142578125 +78538 -0.02532958984375 +78539 -0.024749755859375 +78540 0.06097412109375 +78541 0.085784912109375 +78542 0.13330078125 +78543 0.178131103515625 +78544 0.16259765625 +78545 0.215576171875 +78546 0.159393310546875 +78547 0.211456298828125 +78548 0.131195068359375 +78549 0.17523193359375 +78550 0.095306396484375 +78551 0.128753662109375 +78552 0.075347900390625 +78553 0.1019287109375 +78554 0.0550537109375 +78555 0.0743408203125 +78556 0.03216552734375 +78557 0.04327392578125 +78558 0.0299072265625 +78559 0.038177490234375 +78560 0.06182861328125 +78561 0.076263427734375 +78562 0.114776611328125 +78563 0.14105224609375 +78564 0.152130126953125 +78565 0.186431884765625 +78566 0.1551513671875 +78567 0.188812255859375 +78568 0.11651611328125 +78569 0.1390380859375 +78570 0.0399169921875 +78571 0.041778564453125 +78572 -0.0560302734375 +78573 -0.079437255859375 +78574 -0.167205810546875 +78575 -0.219390869140625 +78576 -0.285430908203125 +78577 -0.367828369140625 +78578 -0.38702392578125 +78579 -0.494873046875 +78580 -0.43682861328125 +78581 -0.556243896484375 +78582 -0.400543212890625 +78583 -0.508697509765625 +78584 -0.296600341796875 +78585 -0.3756103515625 +78586 -0.1739501953125 +78587 -0.218902587890625 +78588 -0.05242919921875 +78589 -0.063751220703125 +78590 0.0693359375 +78591 0.091552734375 +78592 0.182769775390625 +78593 0.23602294921875 +78594 0.26678466796875 +78595 0.342987060546875 +78596 0.3074951171875 +78597 0.39520263671875 +78598 0.302001953125 +78599 0.389373779296875 +78600 0.249053955078125 +78601 0.324249267578125 +78602 0.168365478515625 +78603 0.224090576171875 +78604 0.0888671875 +78605 0.124267578125 +78606 0.0203857421875 +78607 0.037078857421875 +78608 -0.014739990234375 +78609 -0.010101318359375 +78610 -0.0185546875 +78611 -0.019439697265625 +78612 -0.01751708984375 +78613 -0.022796630859375 +78614 0.00347900390625 +78615 -0.001556396484375 +78616 0.054168701171875 +78617 0.056304931640625 +78618 0.09814453125 +78619 0.106719970703125 +78620 0.091796875 +78621 0.096893310546875 +78622 0.04815673828125 +78623 0.042694091796875 +78624 -0.001617431640625 +78625 -0.018035888671875 +78626 -0.04974365234375 +78627 -0.07586669921875 +78628 -0.0867919921875 +78629 -0.11944580078125 +78630 -0.12176513671875 +78631 -0.15972900390625 +78632 -0.15936279296875 +78633 -0.202606201171875 +78634 -0.199859619140625 +78635 -0.24859619140625 +78636 -0.249237060546875 +78637 -0.30517578125 +78638 -0.2989501953125 +78639 -0.36212158203125 +78640 -0.3258056640625 +78641 -0.39141845703125 +78642 -0.2984619140625 +78643 -0.35528564453125 +78644 -0.213714599609375 +78645 -0.249969482421875 +78646 -0.0858154296875 +78647 -0.092864990234375 +78648 0.063079833984375 +78649 0.08905029296875 +78650 0.18310546875 +78651 0.2352294921875 +78652 0.25213623046875 +78653 0.318817138671875 +78654 0.28564453125 +78655 0.358642578125 +78656 0.27789306640625 +78657 0.347747802734375 +78658 0.2283935546875 +78659 0.28564453125 +78660 0.178924560546875 +78661 0.223175048828125 +78662 0.15936279296875 +78663 0.196746826171875 +78664 0.147735595703125 +78665 0.179840087890625 +78666 0.1300048828125 +78667 0.155548095703125 +78668 0.1285400390625 +78669 0.151214599609375 +78670 0.135101318359375 +78671 0.156951904296875 +78672 0.115814208984375 +78673 0.13177490234375 +78674 0.09130859375 +78675 0.100799560546875 +78676 0.08056640625 +78677 0.087127685546875 +78678 0.05401611328125 +78679 0.05487060546875 +78680 0.00091552734375 +78681 -0.009002685546875 +78682 -0.0782470703125 +78683 -0.10400390625 +78684 -0.182830810546875 +78685 -0.229400634765625 +78686 -0.288330078125 +78687 -0.35552978515625 +78688 -0.36126708984375 +78689 -0.441925048828125 +78690 -0.389434814453125 +78691 -0.473846435546875 +78692 -0.38385009765625 +78693 -0.464813232421875 +78694 -0.347900390625 +78695 -0.419097900390625 +78696 -0.279571533203125 +78697 -0.334320068359375 +78698 -0.193145751953125 +78699 -0.227935791015625 +78700 -0.10797119140625 +78701 -0.12347412109375 +78702 -0.029510498046875 +78703 -0.02764892578125 +78704 0.05718994140625 +78705 0.077667236328125 +78706 0.169189453125 +78707 0.2132568359375 +78708 0.314483642578125 +78709 0.38885498046875 +78710 0.475189208984375 +78711 0.582794189453125 +78712 0.6009521484375 +78713 0.734039306640625 +78714 0.65673828125 +78715 0.800140380859375 +78716 0.640167236328125 +78717 0.7783203125 +78718 0.548370361328125 +78719 0.6651611328125 +78720 0.38043212890625 +78721 0.45965576171875 +78722 0.167083740234375 +78723 0.199188232421875 +78724 -0.0377197265625 +78725 -0.050689697265625 +78726 -0.18707275390625 +78727 -0.23297119140625 +78728 -0.2666015625 +78729 -0.33013916015625 +78730 -0.297882080078125 +78731 -0.368408203125 +78732 -0.306610107421875 +78733 -0.378936767578125 +78734 -0.30535888671875 +78735 -0.376983642578125 +78736 -0.3082275390625 +78737 -0.37969970703125 +78738 -0.318817138671875 +78739 -0.391510009765625 +78740 -0.314788818359375 +78741 -0.385345458984375 +78742 -0.280181884765625 +78743 -0.3419189453125 +78744 -0.2327880859375 +78745 -0.28289794921875 +78746 -0.208221435546875 +78747 -0.251617431640625 +78748 -0.2213134765625 +78749 -0.266143798828125 +78750 -0.228240966796875 +78751 -0.273345947265625 +78752 -0.182464599609375 +78753 -0.216796875 +78754 -0.110076904296875 +78755 -0.128265380859375 +78756 -0.06085205078125 +78757 -0.068145751953125 +78758 -0.04022216796875 +78759 -0.0430908203125 +78760 -0.02459716796875 +78761 -0.024444580078125 +78762 0.01312255859375 +78763 0.020721435546875 +78764 0.099334716796875 +78765 0.124481201171875 +78766 0.210113525390625 +78767 0.25787353515625 +78768 0.31097412109375 +78769 0.379119873046875 +78770 0.395050048828125 +78771 0.47991943359375 +78772 0.43585205078125 +78773 0.5281982421875 +78774 0.422760009765625 +78775 0.511138916015625 +78776 0.37835693359375 +78777 0.456207275390625 +78778 0.338897705078125 +78779 0.407470703125 +78780 0.319854736328125 +78781 0.383758544921875 +78782 0.2979736328125 +78783 0.35687255859375 +78784 0.26092529296875 +78785 0.31182861328125 +78786 0.210540771484375 +78787 0.250885009765625 +78788 0.139739990234375 +78789 0.1654052734375 +78790 0.031951904296875 +78791 0.035247802734375 +78792 -0.114837646484375 +78793 -0.142059326171875 +78794 -0.275115966796875 +78795 -0.33563232421875 +78796 -0.4398193359375 +78797 -0.5345458984375 +78798 -0.594940185546875 +78799 -0.72186279296875 +78800 -0.690277099609375 +78801 -0.836669921875 +78802 -0.687652587890625 +78803 -0.8326416015625 +78804 -0.603363037109375 +78805 -0.7296142578125 +78806 -0.482635498046875 +78807 -0.582550048828125 +78808 -0.36553955078125 +78809 -0.440093994140625 +78810 -0.270263671875 +78811 -0.324310302734375 +78812 -0.16900634765625 +78813 -0.20147705078125 +78814 -0.03955078125 +78815 -0.044647216796875 +78816 0.083282470703125 +78817 0.103973388671875 +78818 0.164886474609375 +78819 0.202392578125 +78820 0.216644287109375 +78821 0.264495849609375 +78822 0.278594970703125 +78823 0.338897705078125 +78824 0.365692138671875 +78825 0.443817138671875 +78826 0.44976806640625 +78827 0.545074462890625 +78828 0.509857177734375 +78829 0.6173095703125 +78830 0.539337158203125 +78831 0.6524658203125 +78832 0.548736572265625 +78833 0.66339111328125 +78834 0.54302978515625 +78835 0.6561279296875 +78836 0.50250244140625 +78837 0.606781005859375 +78838 0.41546630859375 +78839 0.501190185546875 +78840 0.292999267578125 +78841 0.352783203125 +78842 0.1474609375 +78843 0.176544189453125 +78844 -0.027130126953125 +78845 -0.034820556640625 +78846 -0.211700439453125 +78847 -0.258209228515625 +78848 -0.3638916015625 +78849 -0.44244384765625 +78850 -0.47369384765625 +78851 -0.5753173828125 +78852 -0.53704833984375 +78853 -0.65203857421875 +78854 -0.527374267578125 +78855 -0.641632080078125 +78856 -0.459991455078125 +78857 -0.562164306640625 +78858 -0.37274169921875 +78859 -0.458038330078125 +78860 -0.28363037109375 +78861 -0.350555419921875 +78862 -0.21026611328125 +78863 -0.260528564453125 +78864 -0.15594482421875 +78865 -0.192108154296875 +78866 -0.117523193359375 +78867 -0.141937255859375 +78868 -0.088043212890625 +78869 -0.1021728515625 +78870 -0.058746337890625 +78871 -0.062896728515625 +78872 -0.018951416015625 +78873 -0.011932373046875 +78874 0.041839599609375 +78875 0.062835693359375 +78876 0.1129150390625 +78877 0.148712158203125 +78878 0.19097900390625 +78879 0.241729736328125 +78880 0.28228759765625 +78881 0.34912109375 +78882 0.375213623046875 +78883 0.457305908203125 +78884 0.450531005859375 +78885 0.54388427734375 +78886 0.47735595703125 +78887 0.5728759765625 +78888 0.42327880859375 +78889 0.506591796875 +78890 0.29345703125 +78891 0.351226806640625 +78892 0.121673583984375 +78893 0.146514892578125 +78894 -0.047454833984375 +78895 -0.05523681640625 +78896 -0.181793212890625 +78897 -0.21624755859375 +78898 -0.280181884765625 +78899 -0.334930419921875 +78900 -0.335662841796875 +78901 -0.402984619140625 +78902 -0.366241455078125 +78903 -0.4412841796875 +78904 -0.411407470703125 +78905 -0.49578857421875 +78906 -0.465789794921875 +78907 -0.5601806640625 +78908 -0.50054931640625 +78909 -0.600738525390625 +78910 -0.487213134765625 +78911 -0.584228515625 +78912 -0.398834228515625 +78913 -0.47930908203125 +78914 -0.229705810546875 +78915 -0.27935791015625 +78916 -0.00067138671875 +78917 -0.0089111328125 +78918 0.2342529296875 +78919 0.268798828125 +78920 0.41455078125 +78921 0.482818603515625 +78922 0.515167236328125 +78923 0.60369873046875 +78924 0.552459716796875 +78925 0.650421142578125 +78926 0.561676025390625 +78927 0.66400146484375 +78928 0.5404052734375 +78929 0.6414794921875 +78930 0.479949951171875 +78931 0.572540283203125 +78932 0.4154052734375 +78933 0.498138427734375 +78934 0.36492919921875 +78935 0.439453125 +78936 0.310577392578125 +78937 0.375518798828125 +78938 0.225067138671875 +78939 0.274505615234375 +78940 0.08465576171875 +78941 0.1087646484375 +78942 -0.0916748046875 +78943 -0.099395751953125 +78944 -0.27679443359375 +78945 -0.3182373046875 +78946 -0.471923828125 +78947 -0.5489501953125 +78948 -0.6619873046875 +78949 -0.7738037109375 +78950 -0.801788330078125 +78951 -0.86383056640625 +78952 -0.855438232421875 +78953 -0.870391845703125 +78954 -0.855194091796875 +78955 -0.86895751953125 +78956 -0.80670166015625 +78957 -0.861053466796875 +78958 -0.685821533203125 +78959 -0.765869140625 +78960 -0.48858642578125 +78961 -0.5301513671875 +78962 -0.2210693359375 +78963 -0.214691162109375 +78964 0.07989501953125 +78965 0.137359619140625 +78966 0.37042236328125 +78967 0.474822998046875 +78968 0.620147705078125 +78969 0.76239013671875 +78970 0.806060791015625 +78971 0.867462158203125 +78972 0.862579345703125 +78973 0.870361328125 +78974 0.867950439453125 +78975 0.86480712890625 +78976 0.865875244140625 +78977 0.831817626953125 +78978 0.858642578125 +78979 0.677581787109375 +78980 0.783599853515625 +78981 0.495880126953125 +78982 0.648193359375 +78983 0.30767822265625 +78984 0.488250732421875 +78985 0.116180419921875 +78986 0.27667236328125 +78987 -0.110748291015625 +78988 0.007568359375 +78989 -0.381805419921875 +78990 -0.28240966796875 +78991 -0.6572265625 +78992 -0.54205322265625 +78993 -0.857421875 +78994 -0.734649658203125 +78995 -0.870391845703125 +78996 -0.854095458984375 +78997 -0.870391845703125 +78998 -0.862030029296875 +78999 -0.86444091796875 +79000 -0.86749267578125 +79001 -0.85723876953125 +79002 -0.869140625 +79003 -0.790008544921875 +79004 -0.86187744140625 +79005 -0.62847900390625 +79006 -0.771575927734375 +79007 -0.3956298828125 +79008 -0.565185546875 +79009 -0.126708984375 +79010 -0.326446533203125 +79011 0.150115966796875 +79012 -0.065399169921875 +79013 0.424041748046875 +79014 0.19482421875 +79015 0.670623779296875 +79016 0.421051025390625 +79017 0.854522705078125 +79018 0.59814453125 +79019 0.866485595703125 +79020 0.712890625 +79021 0.86920166015625 +79022 0.7808837890625 +79023 0.8653564453125 +79024 0.813629150390625 +79025 0.857147216796875 +79026 0.80865478515625 +79027 0.766845703125 +79028 0.7703857421875 +79029 0.628509521484375 +79030 0.693084716796875 +79031 0.462127685546875 +79032 0.59893798828125 +79033 0.297210693359375 +79034 0.498626708984375 +79035 0.14862060546875 +79036 0.372650146484375 +79037 -0.00537109375 +79038 0.22747802734375 +79039 -0.15753173828125 +79040 0.060089111328125 +79041 -0.31304931640625 +79042 -0.1414794921875 +79043 -0.48876953125 +79044 -0.337066650390625 +79045 -0.6416015625 +79046 -0.505462646484375 +79047 -0.751373291015625 +79048 -0.66644287109375 +79049 -0.84619140625 +79050 -0.807373046875 +79051 -0.861297607421875 +79052 -0.859466552734375 +79053 -0.863250732421875 +79054 -0.861328125 +79055 -0.856597900390625 +79056 -0.85614013671875 +79057 -0.7498779296875 +79058 -0.80621337890625 +79059 -0.624542236328125 +79060 -0.70892333984375 +79061 -0.47808837890625 +79062 -0.527496337890625 +79063 -0.253387451171875 +79064 -0.301055908203125 +79065 0.003692626953125 +79066 -0.08819580078125 +79067 0.2257080078125 +79068 0.12176513671875 +79069 0.427154541015625 +79070 0.356475830078125 +79071 0.643218994140625 +79072 0.60760498046875 +79073 0.855926513671875 +79074 0.82550048828125 +79075 0.870361328125 +79076 0.8668212890625 +79077 0.870361328125 +79078 0.870361328125 +79079 0.862762451171875 +79080 0.866363525390625 +79081 0.79669189453125 +79082 0.852020263671875 +79083 0.595794677734375 +79084 0.692138671875 +79085 0.362152099609375 +79086 0.509063720703125 +79087 0.1270751953125 +79088 0.3216552734375 +79089 -0.086944580078125 +79090 0.131988525390625 +79091 -0.2784423828125 +79092 -0.089874267578125 +79093 -0.484832763671875 +79094 -0.36102294921875 +79095 -0.729583740234375 +79096 -0.639129638671875 +79097 -0.86688232421875 +79098 -0.856353759765625 +79099 -0.870391845703125 +79100 -0.870391845703125 +79101 -0.86859130859375 +79102 -0.870391845703125 +79103 -0.86279296875 +79104 -0.863494873046875 +79105 -0.817962646484375 +79106 -0.77923583984375 +79107 -0.6116943359375 +79108 -0.52740478515625 +79109 -0.3128662109375 +79110 -0.21514892578125 +79111 0.039398193359375 +79112 0.1378173828125 +79113 0.422821044921875 +79114 0.5020751953125 +79115 0.805145263671875 +79116 0.81927490234375 +79117 0.870361328125 +79118 0.870361328125 +79119 0.870361328125 +79120 0.870361328125 +79121 0.860015869140625 +79122 0.860931396484375 +79123 0.727935791015625 +79124 0.74932861328125 +79125 0.48114013671875 +79126 0.540802001953125 +79127 0.2059326171875 +79128 0.319244384765625 +79129 -0.06103515625 +79130 0.10260009765625 +79131 -0.29913330078125 +79132 -0.115203857421875 +79133 -0.516204833984375 +79134 -0.343719482421875 +79135 -0.7252197265625 +79136 -0.55950927734375 +79137 -0.85980224609375 +79138 -0.7335205078125 +79139 -0.870391845703125 +79140 -0.843505859375 +79141 -0.870391845703125 +79142 -0.852508544921875 +79143 -0.858062744140625 +79144 -0.764923095703125 +79145 -0.673004150390625 +79146 -0.636871337890625 +79147 -0.42694091796875 +79148 -0.51812744140625 +79149 -0.2100830078125 +79150 -0.41741943359375 +79151 -0.0362548828125 +79152 -0.31915283203125 +79153 0.10943603515625 +79154 -0.214996337890625 +79155 0.23516845703125 +79156 -0.076141357421875 +79157 0.373687744140625 +79158 0.08941650390625 +79159 0.517791748046875 +79160 0.221588134765625 +79161 0.602783203125 +79162 0.323028564453125 +79163 0.635711669921875 +79164 0.423614501953125 +79165 0.655181884765625 +79166 0.516937255859375 +79167 0.65948486328125 +79168 0.600311279296875 +79169 0.651275634765625 +79170 0.657989501953125 +79171 0.61846923828125 +79172 0.66448974609375 +79173 0.53753662109375 +79174 0.6119384765625 +79175 0.404144287109375 +79176 0.500274658203125 +79177 0.22186279296875 +79178 0.33905029296875 +79179 0.003997802734375 +79180 0.152252197265625 +79181 -0.22100830078125 +79182 -0.034820556640625 +79183 -0.42449951171875 +79184 -0.19757080078125 +79185 -0.579833984375 +79186 -0.2940673828125 +79187 -0.641876220703125 +79188 -0.327911376953125 +79189 -0.6177978515625 +79190 -0.356048583984375 +79191 -0.575531005859375 +79192 -0.38458251953125 +79193 -0.526336669921875 +79194 -0.370574951171875 +79195 -0.42645263671875 +79196 -0.29412841796875 +79197 -0.2581787109375 +79198 -0.193206787109375 +79199 -0.068695068359375 +79200 -0.108489990234375 +79201 0.09222412109375 +79202 -0.030364990234375 +79203 0.232147216796875 +79204 0.043243408203125 +79205 0.3509521484375 +79206 0.079376220703125 +79207 0.410064697265625 +79208 0.046051025390625 +79209 0.372955322265625 +79210 -0.04302978515625 +79211 0.2554931640625 +79212 -0.145263671875 +79213 0.10711669921875 +79214 -0.245574951171875 +79215 -0.052886962890625 +79216 -0.312591552734375 +79217 -0.186279296875 +79218 -0.2960205078125 +79219 -0.23291015625 +79220 -0.214019775390625 +79221 -0.209442138671875 +79222 -0.12176513671875 +79223 -0.174163818359375 +79224 -0.022247314453125 +79225 -0.126739501953125 +79226 0.098358154296875 +79227 -0.048126220703125 +79228 0.2205810546875 +79229 0.0426025390625 +79230 0.308685302734375 +79231 0.10748291015625 +79232 0.3564453125 +79233 0.1409912109375 +79234 0.4111328125 +79235 0.19708251953125 +79236 0.47100830078125 +79237 0.273651123046875 +79238 0.48980712890625 +79239 0.31768798828125 +79240 0.479522705078125 +79241 0.341094970703125 +79242 0.463623046875 +79243 0.368011474609375 +79244 0.421478271484375 +79245 0.37249755859375 +79246 0.3079833984375 +79247 0.30072021484375 +79248 0.125091552734375 +79249 0.1517333984375 +79250 -0.071319580078125 +79251 -0.01470947265625 +79252 -0.26953125 +79253 -0.1883544921875 +79254 -0.47039794921875 +79255 -0.372711181640625 +79256 -0.62432861328125 +79257 -0.51397705078125 +79258 -0.69415283203125 +79259 -0.57177734375 +79260 -0.67327880859375 +79261 -0.53948974609375 +79262 -0.577606201171875 +79263 -0.43511962890625 +79264 -0.44097900390625 +79265 -0.2962646484375 +79266 -0.298309326171875 +79267 -0.161102294921875 +79268 -0.1634521484375 +79269 -0.0435791015625 +79270 -0.034698486328125 +79271 0.060394287109375 +79272 0.07318115234375 +79273 0.13665771484375 +79274 0.144561767578125 +79275 0.170135498046875 +79276 0.181304931640625 +79277 0.16552734375 +79278 0.211761474609375 +79279 0.15728759765625 +79280 0.23876953125 +79281 0.150787353515625 +79282 0.239349365234375 +79283 0.12200927734375 +79284 0.220367431640625 +79285 0.080108642578125 +79286 0.204345703125 +79287 0.05126953125 +79288 0.21533203125 +79289 0.062896728515625 +79290 0.2337646484375 +79291 0.09271240234375 +79292 0.21795654296875 +79293 0.092987060546875 +79294 0.182159423828125 +79295 0.07855224609375 +79296 0.14105224609375 +79297 0.06427001953125 +79298 0.082672119140625 +79299 0.0347900390625 +79300 0.007232666015625 +79301 -0.01171875 +79302 -0.066253662109375 +79303 -0.056060791015625 +79304 -0.097991943359375 +79305 -0.055511474609375 +79306 -0.08660888671875 +79307 -0.010467529296875 +79308 -0.078582763671875 +79309 0.02508544921875 +79310 -0.095367431640625 +79311 0.025665283203125 +79312 -0.11309814453125 +79313 0.017333984375 +79314 -0.12982177734375 +79315 0.00189208984375 +79316 -0.155426025390625 +79317 -0.03173828125 +79318 -0.1796875 +79319 -0.071502685546875 +79320 -0.219390869140625 +79321 -0.13543701171875 +79322 -0.272491455078125 +79323 -0.219970703125 +79324 -0.3184814453125 +79325 -0.300506591796875 +79326 -0.358184814453125 +79327 -0.376312255859375 +79328 -0.3653564453125 +79329 -0.416107177734375 +79330 -0.29827880859375 +79331 -0.371124267578125 +79332 -0.159210205078125 +79333 -0.242279052734375 +79334 0.014892578125 +79335 -0.069732666015625 +79336 0.2044677734375 +79337 0.125640869140625 +79338 0.381103515625 +79339 0.31268310546875 +79340 0.512115478515625 +79341 0.45501708984375 +79342 0.599273681640625 +79343 0.554779052734375 +79344 0.6417236328125 +79345 0.61065673828125 +79346 0.62957763671875 +79347 0.610931396484375 +79348 0.542266845703125 +79349 0.531463623046875 +79350 0.395050048828125 +79351 0.3883056640625 +79352 0.23638916015625 +79353 0.23468017578125 +79354 0.089447021484375 +79355 0.095245361328125 +79356 -0.0213623046875 +79357 -0.00396728515625 +79358 -0.08203125 +79359 -0.04852294921875 +79360 -0.1060791015625 +79361 -0.055145263671875 +79362 -0.138885498046875 +79363 -0.0758056640625 +79364 -0.205078125 +79365 -0.138702392578125 +79366 -0.273162841796875 +79367 -0.209197998046875 +79368 -0.3447265625 +79369 -0.289031982421875 +79370 -0.420562744140625 +79371 -0.37884521484375 +79372 -0.48101806640625 +79373 -0.456329345703125 +79374 -0.52227783203125 +79375 -0.51641845703125 +79376 -0.509307861328125 +79377 -0.519287109375 +79378 -0.43701171875 +79379 -0.458251953125 +79380 -0.35272216796875 +79381 -0.384796142578125 +79382 -0.27978515625 +79383 -0.323699951171875 +79384 -0.21405029296875 +79385 -0.269287109375 +79386 -0.132659912109375 +79387 -0.1951904296875 +79388 -0.035064697265625 +79389 -0.100006103515625 +79390 0.053985595703125 +79391 -0.01055908203125 +79392 0.16131591796875 +79393 0.1033935546875 +79394 0.2933349609375 +79395 0.24908447265625 +79396 0.402130126953125 +79397 0.373199462890625 +79398 0.472076416015625 +79399 0.45806884765625 +79400 0.5106201171875 +79401 0.511474609375 +79402 0.54718017578125 +79403 0.565399169921875 +79404 0.57489013671875 +79405 0.61138916015625 +79406 0.540740966796875 +79407 0.5897216796875 +79408 0.436737060546875 +79409 0.4906005859375 +79410 0.279449462890625 +79411 0.33148193359375 +79412 0.10150146484375 +79413 0.147796630859375 +79414 -0.058929443359375 +79415 -0.01873779296875 +79416 -0.176300048828125 +79417 -0.140289306640625 +79418 -0.227813720703125 +79419 -0.191986083984375 +79420 -0.222747802734375 +79421 -0.184295654296875 +79422 -0.20123291015625 +79423 -0.161834716796875 +79424 -0.20123291015625 +79425 -0.166595458984375 +79426 -0.2188720703125 +79427 -0.19390869140625 +79428 -0.237152099609375 +79429 -0.22442626953125 +79430 -0.276092529296875 +79431 -0.279754638671875 +79432 -0.317535400390625 +79433 -0.3389892578125 +79434 -0.319183349609375 +79435 -0.3543701171875 +79436 -0.3017578125 +79437 -0.348175048828125 +79438 -0.270904541015625 +79439 -0.32598876953125 +79440 -0.2005615234375 +79441 -0.2581787109375 +79442 -0.08673095703125 +79443 -0.139801025390625 +79444 0.057220458984375 +79445 0.014617919921875 +79446 0.176422119140625 +79447 0.144378662109375 +79448 0.245269775390625 +79449 0.221038818359375 +79450 0.28729248046875 +79451 0.27069091796875 +79452 0.3033447265625 +79453 0.294036865234375 +79454 0.312408447265625 +79455 0.311767578125 +79456 0.32867431640625 +79457 0.339141845703125 +79458 0.338592529296875 +79459 0.360260009765625 +79460 0.3294677734375 +79461 0.360504150390625 +79462 0.272705078125 +79463 0.308380126953125 +79464 0.1483154296875 +79465 0.18170166015625 +79466 -0.020965576171875 +79467 0.0047607421875 +79468 -0.1917724609375 +79469 -0.17559814453125 +79470 -0.322509765625 +79471 -0.3143310546875 +79472 -0.372955322265625 +79473 -0.36785888671875 +79474 -0.367340087890625 +79475 -0.36248779296875 +79476 -0.347442626953125 +79477 -0.343536376953125 +79478 -0.3050537109375 +79479 -0.3018798828125 +79480 -0.234832763671875 +79481 -0.231414794921875 +79482 -0.123748779296875 +79483 -0.117645263671875 +79484 -0.001922607421875 +79485 0.007049560546875 +79486 0.079864501953125 +79487 0.087982177734375 +79488 0.134429931640625 +79489 0.13946533203125 +79490 0.173095703125 +79491 0.17425537109375 +79492 0.191680908203125 +79493 0.188201904296875 +79494 0.180633544921875 +79495 0.171234130859375 +79496 0.135223388671875 +79497 0.118438720703125 +79498 0.08038330078125 +79499 0.05706787109375 +79500 0.01806640625 +79501 -0.010711669921875 +79502 -0.05767822265625 +79503 -0.0914306640625 +79504 -0.125762939453125 +79505 -0.162322998046875 +79506 -0.15948486328125 +79507 -0.194549560546875 +79508 -0.122894287109375 +79509 -0.1492919921875 +79510 -0.01116943359375 +79511 -0.02166748046875 +79512 0.116912841796875 +79513 0.124053955078125 +79514 0.19110107421875 +79515 0.211151123046875 +79516 0.21246337890625 +79517 0.240447998046875 +79518 0.2091064453125 +79519 0.242218017578125 +79520 0.189849853515625 +79521 0.2257080078125 +79522 0.158050537109375 +79523 0.194366455078125 +79524 0.083740234375 +79525 0.115509033203125 +79526 -0.011199951171875 +79527 0.0128173828125 +79528 -0.071685791015625 +79529 -0.053802490234375 +79530 -0.1219482421875 +79531 -0.110626220703125 +79532 -0.200653076171875 +79533 -0.199493408203125 +79534 -0.284027099609375 +79535 -0.29437255859375 +79536 -0.314300537109375 +79537 -0.33221435546875 +79538 -0.261138916015625 +79539 -0.27972412109375 +79540 -0.16937255859375 +79541 -0.185333251953125 +79542 -0.112091064453125 +79543 -0.128204345703125 +79544 -0.09625244140625 +79545 -0.115692138671875 +79546 -0.093292236328125 +79547 -0.116455078125 +79548 -0.080780029296875 +79549 -0.105926513671875 +79550 -0.031158447265625 +79551 -0.053955078125 +79552 0.064117431640625 +79553 0.048797607421875 +79554 0.16363525390625 +79555 0.157318115234375 +79556 0.212615966796875 +79557 0.212005615234375 +79558 0.21630859375 +79559 0.218475341796875 +79560 0.23052978515625 +79561 0.23724365234375 +79562 0.289581298828125 +79563 0.30535888671875 +79564 0.35540771484375 +79565 0.38128662109375 +79566 0.372528076171875 +79567 0.404449462890625 +79568 0.35919189453125 +79569 0.3944091796875 +79570 0.35003662109375 +79571 0.3885498046875 +79572 0.322967529296875 +79573 0.362640380859375 +79574 0.238525390625 +79575 0.27362060546875 +79576 0.0927734375 +79577 0.11712646484375 +79578 -0.06640625 +79579 -0.054901123046875 +79580 -0.19146728515625 +79581 -0.19085693359375 +79582 -0.27783203125 +79583 -0.28570556640625 +79584 -0.325439453125 +79585 -0.339263916015625 +79586 -0.35833740234375 +79587 -0.3775634765625 +79588 -0.41815185546875 +79589 -0.445709228515625 +79590 -0.49713134765625 +79591 -0.535064697265625 +79592 -0.5802001953125 +79593 -0.629058837890625 +79594 -0.639892578125 +79595 -0.697601318359375 +79596 -0.642547607421875 +79597 -0.70391845703125 +79598 -0.58319091796875 +79599 -0.6424560546875 +79600 -0.4417724609375 +79601 -0.491241455078125 +79602 -0.232574462890625 +79603 -0.265716552734375 +79604 -0.0089111328125 +79605 -0.023712158203125 +79606 0.19879150390625 +79607 0.201751708984375 +79608 0.358489990234375 +79609 0.375823974609375 +79610 0.457855224609375 +79611 0.485076904296875 +79612 0.533172607421875 +79613 0.56884765625 +79614 0.591583251953125 +79615 0.634765625 +79616 0.591156005859375 +79617 0.63763427734375 +79618 0.520782470703125 +79619 0.5660400390625 +79620 0.429595947265625 +79621 0.4720458984375 +79622 0.366668701171875 +79623 0.40692138671875 +79624 0.3389892578125 +79625 0.3778076171875 +79626 0.3392333984375 +79627 0.376953125 +79628 0.336578369140625 +79629 0.371978759765625 +79630 0.283599853515625 +79631 0.313140869140625 +79632 0.164825439453125 +79633 0.184417724609375 +79634 0.004241943359375 +79635 0.011199951171875 +79636 -0.164642333984375 +79637 -0.171051025390625 +79638 -0.318359375 +79639 -0.33740234375 +79640 -0.4420166015625 +79641 -0.47198486328125 +79642 -0.522186279296875 +79643 -0.560394287109375 +79644 -0.5380859375 +79645 -0.58056640625 +79646 -0.50421142578125 +79647 -0.54754638671875 +79648 -0.465667724609375 +79649 -0.508575439453125 +79650 -0.418548583984375 +79651 -0.459503173828125 +79652 -0.357177734375 +79653 -0.394378662109375 +79654 -0.319000244140625 +79655 -0.35260009765625 +79656 -0.282501220703125 +79657 -0.31170654296875 +79658 -0.17681884765625 +79659 -0.197418212890625 +79660 -9.1552734375e-05 +79661 -0.007965087890625 +79662 0.201080322265625 +79663 0.207489013671875 +79664 0.389068603515625 +79665 0.409210205078125 +79666 0.54022216796875 +79667 0.57208251953125 +79668 0.62603759765625 +79669 0.66595458984375 +79670 0.61614990234375 +79671 0.65875244140625 +79672 0.52685546875 +79673 0.56744384765625 +79674 0.395782470703125 +79675 0.431396484375 +79676 0.26470947265625 +79677 0.29443359375 +79678 0.158294677734375 +79679 0.182464599609375 +79680 0.046234130859375 +79681 0.06365966796875 +79682 -0.084869384765625 +79683 -0.075958251953125 +79684 -0.190460205078125 +79685 -0.189422607421875 +79686 -0.26611328125 +79687 -0.271942138671875 +79688 -0.330078125 +79689 -0.342529296875 +79690 -0.34735107421875 +79691 -0.364166259765625 +79692 -0.3089599609375 +79693 -0.327239990234375 +79694 -0.258087158203125 +79695 -0.2769775390625 +79696 -0.233306884765625 +79697 -0.253692626953125 +79698 -0.221649169921875 +79699 -0.24365234375 +79700 -0.177093505859375 +79701 -0.1983642578125 +79702 -0.09814453125 +79703 -0.116241455078125 +79704 -0.0224609375 +79705 -0.036834716796875 +79706 0.045196533203125 +79707 0.034881591796875 +79708 0.09759521484375 +79709 0.09124755859375 +79710 0.11260986328125 +79711 0.10888671875 +79712 0.126220703125 +79713 0.125518798828125 +79714 0.15435791015625 +79715 0.15771484375 +79716 0.1712646484375 +79717 0.17828369140625 +79718 0.161712646484375 +79719 0.17108154296875 +79720 0.120025634765625 +79721 0.129974365234375 +79722 0.072479248046875 +79723 0.082427978515625 +79724 0.01849365234375 +79725 0.027679443359375 +79726 -0.07171630859375 +79727 -0.065643310546875 +79728 -0.1617431640625 +79729 -0.15936279296875 +79730 -0.213104248046875 +79731 -0.21307373046875 +79732 -0.233306884765625 +79733 -0.234649658203125 +79734 -0.199615478515625 +79735 -0.2001953125 +79736 -0.121124267578125 +79737 -0.119171142578125 +79738 -0.029541015625 +79739 -0.024749755859375 +79740 0.077667236328125 +79741 0.085784912109375 +79742 0.167724609375 +79743 0.178131103515625 +79744 0.20556640625 +79745 0.215576171875 +79746 0.2037353515625 +79747 0.211456298828125 +79748 0.171142578125 +79749 0.17523193359375 +79750 0.128509521484375 +79751 0.128753662109375 +79752 0.104217529296875 +79753 0.1019287109375 +79754 0.07879638671875 +79755 0.0743408203125 +79756 0.049591064453125 +79757 0.04327392578125 +79758 0.044647216796875 +79759 0.038177490234375 +79760 0.080352783203125 +79761 0.076263427734375 +79762 0.141082763671875 +79763 0.14105224609375 +79764 0.183013916015625 +79765 0.186431884765625 +79766 0.183746337890625 +79767 0.188812255859375 +79768 0.1346435546875 +79769 0.1390380859375 +79770 0.040283203125 +79771 0.041778564453125 +79772 -0.07684326171875 +79773 -0.079437255859375 +79774 -0.21173095703125 +79775 -0.219390869140625 +79776 -0.3544921875 +79777 -0.367828369140625 +79778 -0.47662353515625 +79779 -0.494873046875 +79780 -0.535919189453125 +79781 -0.556243896484375 +79782 -0.49114990234375 +79783 -0.508697509765625 +79784 -0.36456298828125 +79785 -0.3756103515625 +79786 -0.215118408203125 +79787 -0.218902587890625 +79788 -0.0667724609375 +79789 -0.063751220703125 +79790 0.08203125 +79791 0.091552734375 +79792 0.22076416015625 +79793 0.23602294921875 +79794 0.323974609375 +79795 0.342987060546875 +79796 0.37518310546875 +79797 0.39520263671875 +79798 0.37115478515625 +79799 0.389373779296875 +79800 0.31060791015625 +79801 0.324249267578125 +79802 0.216552734375 +79803 0.224090576171875 +79804 0.122589111328125 +79805 0.124267578125 +79806 0.040374755859375 +79807 0.037078857421875 +79808 -0.004058837890625 +79809 -0.010101318359375 +79810 -0.012786865234375 +79811 -0.019439697265625 +79812 -0.01611328125 +79813 -0.022796630859375 +79814 0.003631591796875 +79815 -0.001556396484375 +79816 0.0579833984375 +79817 0.056304931640625 +79818 0.10504150390625 +79819 0.106719970703125 +79820 0.0946044921875 +79821 0.096893310546875 +79822 0.041839599609375 +79823 0.042694091796875 +79824 -0.017181396484375 +79825 -0.018035888671875 +79826 -0.073394775390625 +79827 -0.07586669921875 +79828 -0.115966796875 +79829 -0.11944580078125 +79830 -0.1552734375 +79831 -0.15972900390625 +79832 -0.19683837890625 +79833 -0.202606201171875 +79834 -0.241119384765625 +79835 -0.24859619140625 +79836 -0.295196533203125 +79837 -0.30517578125 +79838 -0.349365234375 +79839 -0.36212158203125 +79840 -0.376983642578125 +79841 -0.39141845703125 +79842 -0.342041015625 +79843 -0.35528564453125 +79844 -0.24102783203125 +79845 -0.249969482421875 +79846 -0.090576171875 +79847 -0.092864990234375 +79848 0.08355712890625 +79849 0.08905029296875 +79850 0.223724365234375 +79851 0.2352294921875 +79852 0.304290771484375 +79853 0.318817138671875 +79854 0.343109130859375 +79855 0.358642578125 +79856 0.333526611328125 +79857 0.347747802734375 +79858 0.275054931640625 +79859 0.28564453125 +79860 0.216033935546875 +79861 0.223175048828125 +79862 0.19110107421875 +79863 0.196746826171875 +79864 0.175018310546875 +79865 0.179840087890625 +79866 0.151702880859375 +79867 0.155548095703125 +79868 0.147186279296875 +79869 0.151214599609375 +79870 0.152099609375 +79871 0.156951904296875 +79872 0.127288818359375 +79873 0.13177490234375 +79874 0.097137451171875 +79875 0.100799560546875 +79876 0.0838623046875 +79877 0.087127685546875 +79878 0.05230712890625 +79879 0.05487060546875 +79880 -0.010223388671875 +79881 -0.009002685546875 +79882 -0.10321044921875 +79883 -0.10400390625 +79884 -0.2259521484375 +79885 -0.229400634765625 +79886 -0.349273681640625 +79887 -0.35552978515625 +79888 -0.433349609375 +79889 -0.441925048828125 +79890 -0.46380615234375 +79891 -0.473846435546875 +79892 -0.454010009765625 +79893 -0.464813232421875 +79894 -0.408233642578125 +79895 -0.419097900390625 +79896 -0.324188232421875 +79897 -0.334320068359375 +79898 -0.219085693359375 +79899 -0.227935791015625 +79900 -0.11614990234375 +79901 -0.12347412109375 +79902 -0.02197265625 +79903 -0.02764892578125 +79904 0.081298828125 +79905 0.077667236328125 +79906 0.214111328125 +79907 0.2132568359375 +79908 0.38604736328125 +79909 0.38885498046875 +79910 0.575836181640625 +79911 0.582794189453125 +79912 0.7235107421875 +79913 0.734039306640625 +79914 0.787384033203125 +79915 0.800140380859375 +79916 0.764739990234375 +79917 0.7783203125 +79918 0.65228271484375 +79919 0.6651611328125 +79920 0.4490966796875 +79921 0.45965576171875 +79922 0.192047119140625 +79923 0.199188232421875 +79924 -0.054351806640625 +79925 -0.050689697265625 +79926 -0.233978271484375 +79927 -0.23297119140625 +79928 -0.32958984375 +79929 -0.33013916015625 +79930 -0.366973876953125 +79931 -0.368408203125 +79932 -0.376800537109375 +79933 -0.378936767578125 +79934 -0.3741455078125 +79935 -0.376983642578125 +79936 -0.375946044921875 +79937 -0.37969970703125 +79938 -0.386566162109375 +79939 -0.391510009765625 +79940 -0.37945556640625 +79941 -0.385345458984375 +79942 -0.335693359375 +79943 -0.3419189453125 +79944 -0.27667236328125 +79945 -0.28289794921875 +79946 -0.24505615234375 +79947 -0.251617431640625 +79948 -0.2586669921875 +79949 -0.266143798828125 +79950 -0.265289306640625 +79951 -0.273345947265625 +79952 -0.20941162109375 +79953 -0.216796875 +79954 -0.12225341796875 +79955 -0.128265380859375 +79956 -0.06329345703125 +79957 -0.068145751953125 +79958 -0.03900146484375 +79959 -0.0430908203125 +79960 -0.021209716796875 +79961 -0.024444580078125 +79962 0.022552490234375 +79963 0.020721435546875 +79964 0.123870849609375 +79965 0.124481201171875 +79966 0.2542724609375 +79967 0.25787353515625 +79968 0.372711181640625 +79969 0.379119873046875 +79970 0.471099853515625 +79971 0.47991943359375 +79972 0.51788330078125 +79973 0.5281982421875 +79974 0.500518798828125 +79975 0.511138916015625 +79976 0.446044921875 +79977 0.456207275390625 +79978 0.3978271484375 +79979 0.407470703125 +79980 0.3743896484375 +79981 0.383758544921875 +79982 0.3480224609375 +79983 0.35687255859375 +79984 0.303985595703125 +79985 0.31182861328125 +79986 0.24444580078125 +79987 0.250885009765625 +79988 0.160858154296875 +79989 0.1654052734375 +79990 0.033416748046875 +79991 0.035247802734375 +79992 -0.140350341796875 +79993 -0.142059326171875 +79994 -0.33013916015625 +79995 -0.33563232421875 +79996 -0.52520751953125 +79997 -0.5345458984375 +79998 -0.70892333984375 +79999 -0.72186279296875 +80000 -0.821380615234375 +80001 -0.836669921875 +80002 -0.817047119140625 +80003 -0.8326416015625 +80004 -0.7154541015625 +80005 -0.7296142578125 +80006 -0.5706787109375 +80007 -0.582550048828125 +80008 -0.4305419921875 +80009 -0.440093994140625 +80010 -0.316802978515625 +80011 -0.324310302734375 +80012 -0.1962890625 +80013 -0.20147705078125 +80014 -0.04241943359375 +80015 -0.044647216796875 +80016 0.10333251953125 +80017 0.103973388671875 +80018 0.19964599609375 +80019 0.202392578125 +80020 0.260223388671875 +80021 0.264495849609375 +80022 0.33294677734375 +80023 0.338897705078125 +80024 0.43572998046875 +80025 0.443817138671875 +80026 0.53497314453125 +80027 0.545074462890625 +80028 0.605743408203125 +80029 0.6173095703125 +80030 0.64013671875 +80031 0.6524658203125 +80032 0.650787353515625 +80033 0.66339111328125 +80034 0.6436767578125 +80035 0.6561279296875 +80036 0.595245361328125 +80037 0.606781005859375 +80038 0.491546630859375 +80039 0.501190185546875 +80040 0.34576416015625 +80041 0.352783203125 +80042 0.17266845703125 +80043 0.176544189453125 +80044 -0.034942626953125 +80045 -0.034820556640625 +80046 -0.25433349609375 +80047 -0.258209228515625 +80048 -0.4351806640625 +80049 -0.44244384765625 +80050 -0.56549072265625 +80051 -0.5753173828125 +80052 -0.640625 +80053 -0.65203857421875 +80054 -0.630096435546875 +80055 -0.641632080078125 +80056 -0.551666259765625 +80057 -0.562164306640625 +80058 -0.449066162109375 +80059 -0.458038330078125 +80060 -0.343231201171875 +80061 -0.350555419921875 +80062 -0.254669189453125 +80063 -0.260528564453125 +80064 -0.187469482421875 +80065 -0.192108154296875 +80066 -0.138336181640625 +80067 -0.141937255859375 +80068 -0.099517822265625 +80069 -0.1021728515625 +80070 -0.06121826171875 +80071 -0.062896728515625 +80072 -0.011444091796875 +80073 -0.011932373046875 +80074 0.061767578125 +80075 0.062835693359375 +80076 0.145965576171875 +80077 0.148712158203125 +80078 0.2371826171875 +80079 0.241729736328125 +80080 0.34259033203125 +80081 0.34912109375 +80082 0.448822021484375 +80083 0.457305908203125 +80084 0.533843994140625 +80085 0.54388427734375 +80086 0.56231689453125 +80087 0.5728759765625 +80088 0.497100830078125 +80089 0.506591796875 +80090 0.344329833984375 +80091 0.351226806640625 +80092 0.14306640625 +80093 0.146514892578125 +80094 -0.05523681640625 +80095 -0.05523681640625 +80096 -0.213409423828125 +80097 -0.21624755859375 +80098 -0.32989501953125 +80099 -0.334930419921875 +80100 -0.39654541015625 +80101 -0.402984619140625 +80102 -0.43389892578125 +80103 -0.4412841796875 +80104 -0.487213134765625 +80105 -0.49578857421875 +80106 -0.55029296875 +80107 -0.5601806640625 +80108 -0.589996337890625 +80109 -0.600738525390625 +80110 -0.5736083984375 +80111 -0.584228515625 +80112 -0.47027587890625 +80113 -0.47930908203125 +80114 -0.273529052734375 +80115 -0.27935791015625 +80116 -0.007476806640625 +80117 -0.0089111328125 +80118 0.265625 +80119 0.268798828125 +80120 0.47601318359375 +80121 0.482818603515625 +80122 0.5947265625 +80123 0.60369873046875 +80124 0.640411376953125 +80125 0.650421142578125 +80126 0.653472900390625 +80127 0.66400146484375 +80128 0.630859375 +80129 0.6416015625 +80130 0.562530517578125 +80131 0.5728759765625 +80132 0.489349365234375 +80133 0.498199462890625 +80134 0.432342529296875 +80135 0.43853759765625 +80136 0.37042236328125 +80137 0.3734130859375 +80138 0.271636962890625 +80139 0.271636962890625 +80140 0.108184814453125 +80141 0.106170654296875 +80142 -0.097747802734375 +80143 -0.100921630859375 +80144 -0.314544677734375 +80145 -0.3182373046875 +80146 -0.54351806640625 +80147 -0.546875 +80148 -0.766998291015625 +80149 -0.769287109375 +80150 -0.86297607421875 +80151 -0.863128662109375 +80152 -0.870391845703125 +80153 -0.870391845703125 +80154 -0.869781494140625 +80155 -0.86968994140625 +80156 -0.862640380859375 +80157 -0.8624267578125 +80158 -0.786224365234375 +80159 -0.784149169921875 +80160 -0.55517578125 +80161 -0.553741455078125 +80162 -0.242889404296875 +80163 -0.24310302734375 +80164 0.10760498046875 +80165 0.105255126953125 +80166 0.445159912109375 +80167 0.4407958984375 +80168 0.73443603515625 +80169 0.72857666015625 +80170 0.86474609375 +80171 0.864044189453125 +80172 0.870361328125 +80173 0.870361328125 +80174 0.867431640625 +80175 0.8681640625 +80176 0.857025146484375 +80177 0.85845947265625 +80178 0.742645263671875 +80179 0.7611083984375 +80180 0.575775146484375 +80181 0.598388671875 +80182 0.397613525390625 +80183 0.42279052734375 +80184 0.210968017578125 +80185 0.237152099609375 +80186 -0.016387939453125 +80187 0.009857177734375 +80188 -0.292999267578125 +80189 -0.2672119140625 +80190 -0.578643798828125 +80191 -0.554168701171875 +80192 -0.81683349609375 +80193 -0.795074462890625 +80194 -0.866943359375 +80195 -0.86505126953125 +80196 -0.870391845703125 +80197 -0.870391845703125 +80198 -0.867767333984375 +80199 -0.869598388671875 +80200 -0.863616943359375 +80201 -0.8670654296875 +80202 -0.856475830078125 +80203 -0.861297607421875 +80204 -0.729736328125 +80205 -0.7840576171875 +80206 -0.509613037109375 +80207 -0.57147216796875 +80208 -0.246826171875 +80209 -0.312957763671875 +80210 0.03057861328125 +80211 -0.03619384765625 +80212 0.31158447265625 +80213 0.24761962890625 +80214 0.5711669921875 +80215 0.51336669921875 +80216 0.7735595703125 +80217 0.725189208984375 +80218 0.8599853515625 +80219 0.856048583984375 +80220 0.865386962890625 +80221 0.863006591796875 +80222 0.8643798828125 +80223 0.8636474609375 +80224 0.85894775390625 +80225 0.859832763671875 +80226 0.807159423828125 +80227 0.82916259765625 +80228 0.689849853515625 +80229 0.72393798828125 +80230 0.54052734375 +80231 0.584442138671875 +80232 0.387908935546875 +80233 0.438629150390625 +80234 0.246337890625 +80235 0.3004150390625 +80236 0.09381103515625 +80237 0.148223876953125 +80238 -0.06231689453125 +80239 -0.010498046875 +80240 -0.22686767578125 +80241 -0.180145263671875 +80242 -0.41607666015625 +80243 -0.376190185546875 +80244 -0.58599853515625 +80245 -0.55474853515625 +80246 -0.71539306640625 +80247 -0.694305419921875 +80248 -0.83123779296875 +80249 -0.820709228515625 +80250 -0.861968994140625 +80251 -0.861968994140625 +80252 -0.86614990234375 +80253 -0.86724853515625 +80254 -0.861480712890625 +80255 -0.8636474609375 +80256 -0.80999755859375 +80257 -0.8385009765625 +80258 -0.696258544921875 +80259 -0.731048583984375 +80260 -0.557159423828125 +80261 -0.59600830078125 +80262 -0.335296630859375 +80263 -0.376861572265625 +80264 -0.07647705078125 +80265 -0.118804931640625 +80266 0.151611328125 +80267 0.11126708984375 +80268 0.36297607421875 +80269 0.3267822265625 +80270 0.5921630859375 +80271 0.561309814453125 +80272 0.832244873046875 +80273 0.80743408203125 +80274 0.870361328125 +80275 0.870361328125 +80276 0.870361328125 +80277 0.870361328125 +80278 0.862762451171875 +80279 0.86279296875 +80280 0.79669189453125 +80281 0.797332763671875 +80282 0.595794677734375 +80283 0.597259521484375 +80284 0.362152099609375 +80285 0.36444091796875 +80286 0.1270751953125 +80287 0.1298828125 +80288 -0.086944580078125 +80289 -0.0841064453125 +80290 -0.2784423828125 +80291 -0.27593994140625 +80292 -0.484832763671875 +80293 -0.48223876953125 +80294 -0.729583740234375 +80295 -0.725921630859375 +80296 -0.86688232421875 +80297 -0.866302490234375 +80298 -0.870391845703125 +80299 -0.870391845703125 +80300 -0.86859130859375 +80301 -0.869110107421875 +80302 -0.86279296875 +80303 -0.86376953125 +80304 -0.817962646484375 +80305 -0.83087158203125 +80306 -0.6116943359375 +80307 -0.62841796875 +80308 -0.3128662109375 +80309 -0.33343505859375 +80310 0.039398193359375 +80311 0.0155029296875 +80312 0.422821044921875 +80313 0.39630126953125 +80314 0.805145263671875 +80315 0.7769775390625 +80316 0.870361328125 +80317 0.870361328125 +80318 0.870361328125 +80319 0.870361328125 +80320 0.860015869140625 +80321 0.860076904296875 +80322 0.727935791015625 +80323 0.729766845703125 +80324 0.48114013671875 +80325 0.484588623046875 +80326 0.2059326171875 +80327 0.21087646484375 +80328 -0.06103515625 +80329 -0.055084228515625 +80330 -0.29913330078125 +80331 -0.2928466796875 +80332 -0.516204833984375 +80333 -0.509918212890625 +80334 -0.7252197265625 +80335 -0.718841552734375 +80336 -0.85980224609375 +80337 -0.859100341796875 +80338 -0.870391845703125 +80339 -0.870391845703125 +80340 -0.870391845703125 +80341 -0.870391845703125 +80342 -0.858062744140625 +80343 -0.858184814453125 +80344 -0.673004150390625 +80345 -0.675689697265625 +80346 -0.42694091796875 +80347 -0.43121337890625 +80348 -0.2100830078125 +80349 -0.2149658203125 +80350 -0.0362548828125 +80351 -0.040679931640625 +80352 0.10943603515625 +80353 0.1060791015625 +80354 0.23516845703125 +80355 0.233184814453125 +80356 0.373687744140625 +80357 0.3726806640625 +80358 0.517791748046875 +80359 0.517303466796875 +80360 0.602783203125 +80361 0.603271484375 +80362 0.635711669921875 +80363 0.63739013671875 +80364 0.655181884765625 +80365 0.657562255859375 +80366 0.65948486328125 +80367 0.662078857421875 +80368 0.651275634765625 +80369 0.653533935546875 +80370 0.61846923828125 +80371 0.620086669921875 +80372 0.53753662109375 +80373 0.538665771484375 +80374 0.404144287109375 +80375 0.4051513671875 +80376 0.22186279296875 +80377 0.22320556640625 +80378 0.003997802734375 +80379 0.00604248046875 +80380 -0.22100830078125 +80381 -0.21820068359375 +80382 -0.42449951171875 +80383 -0.421173095703125 +80384 -0.579833984375 +80385 -0.576812744140625 +80386 -0.641876220703125 +80387 -0.641265869140625 +80388 -0.6177978515625 +80389 -0.620880126953125 +80390 -0.575531005859375 +80391 -0.58062744140625 +80392 -0.526336669921875 +80393 -0.5316162109375 +80394 -0.42645263671875 +80395 -0.432647705078125 +80396 -0.2581787109375 +80397 -0.2672119140625 +80398 -0.068695068359375 +80399 -0.080657958984375 +80400 0.09222412109375 +80401 0.079193115234375 +80402 0.232147216796875 +80403 0.219146728515625 +80404 0.3509521484375 +80405 0.3387451171875 +80406 0.410064697265625 +80407 0.40093994140625 +80408 0.372955322265625 +80409 0.370635986328125 +80410 0.2554931640625 +80411 0.262725830078125 +80412 0.10711669921875 +80413 0.1241455078125 +80414 -0.052886962890625 +80415 -0.02685546875 +80416 -0.186279296875 +80417 -0.15386962890625 +80418 -0.23291015625 +80419 -0.199615478515625 +80420 -0.209442138671875 +80421 -0.1798095703125 +80422 -0.174163818359375 +80423 -0.149749755859375 +80424 -0.126739501953125 +80425 -0.10888671875 +80426 -0.048126220703125 +80427 -0.038848876953125 +80428 0.0426025390625 +80429 0.04248046875 +80430 0.10748291015625 +80431 0.0992431640625 +80432 0.1409912109375 +80433 0.12646484375 +80434 0.19708251953125 +80435 0.17572021484375 +80436 0.273651123046875 +80437 0.2452392578125 +80438 0.31768798828125 +80439 0.28472900390625 +80440 0.341094970703125 +80441 0.30560302734375 +80442 0.368011474609375 +80443 0.3309326171875 +80444 0.37249755859375 +80445 0.335968017578125 +80446 0.30072021484375 +80447 0.269378662109375 +80448 0.1517333984375 +80449 0.130126953125 +80450 -0.01470947265625 +80451 -0.0250244140625 +80452 -0.1883544921875 +80453 -0.1865234375 +80454 -0.372711181640625 +80455 -0.35797119140625 +80456 -0.51397705078125 +80457 -0.48834228515625 +80458 -0.57177734375 +80459 -0.539398193359375 +80460 -0.53948974609375 +80461 -0.50506591796875 +80462 -0.43511962890625 +80463 -0.4027099609375 +80464 -0.2962646484375 +80465 -0.26824951171875 +80466 -0.161102294921875 +80467 -0.13812255859375 +80468 -0.0435791015625 +80469 -0.025634765625 +80470 0.060394287109375 +80471 0.07305908203125 +80472 0.13665771484375 +80473 0.14453125 +80474 0.170135498046875 +80475 0.174530029296875 +80476 0.16552734375 +80477 0.16766357421875 +80478 0.15728759765625 +80479 0.1568603515625 +80480 0.150787353515625 +80481 0.147430419921875 +80482 0.12200927734375 +80483 0.116668701171875 +80484 0.080108642578125 +80485 0.073486328125 +80486 0.05126953125 +80487 0.04296875 +80488 0.062896728515625 +80489 0.051422119140625 +80490 0.09271240234375 +80491 0.07769775390625 +80492 0.092987060546875 +80493 0.076507568359375 +80494 0.07855224609375 +80495 0.06201171875 +80496 0.06427001953125 +80497 0.04840087890625 +80498 0.0347900390625 +80499 0.02099609375 +80500 -0.01171875 +80501 -0.02197265625 +80502 -0.056060791015625 +80503 -0.062347412109375 +80504 -0.055511474609375 +80505 -0.059539794921875 +80506 -0.010467529296875 +80507 -0.014068603515625 +80508 0.02508544921875 +80509 0.02252197265625 +80510 0.025665283203125 +80511 0.02581787109375 +80512 0.017333984375 +80513 0.020477294921875 +80514 0.00189208984375 +80515 0.008087158203125 +80516 -0.03173828125 +80517 -0.022003173828125 +80518 -0.071502685546875 +80519 -0.0584716796875 +80520 -0.13543701171875 +80521 -0.118499755859375 +80522 -0.219970703125 +80523 -0.19873046875 +80524 -0.300506591796875 +80525 -0.2757568359375 +80526 -0.376312255859375 +80527 -0.34881591796875 +80528 -0.416107177734375 +80529 -0.3880615234375 +80530 -0.371124267578125 +80531 -0.34698486328125 +80532 -0.242279052734375 +80533 -0.226348876953125 +80534 -0.069732666015625 +80535 -0.06427001953125 +80536 0.125640869140625 +80537 0.119476318359375 +80538 0.31268310546875 +80539 0.29534912109375 +80540 0.45501708984375 +80541 0.428863525390625 +80542 0.554779052734375 +80543 0.52215576171875 +80544 0.61065673828125 +80545 0.574066162109375 +80546 0.610931396484375 +80547 0.573455810546875 +80548 0.531463623046875 +80549 0.497406005859375 +80550 0.3883056640625 +80551 0.3612060546875 +80552 0.23468017578125 +80553 0.215484619140625 +80554 0.095245361328125 +80555 0.083709716796875 +80556 -0.00396728515625 +80557 -0.009429931640625 +80558 -0.04852294921875 +80559 -0.05029296875 +80560 -0.055145263671875 +80561 -0.054840087890625 +80562 -0.0758056640625 +80563 -0.07269287109375 +80564 -0.138702392578125 +80565 -0.130767822265625 +80566 -0.209197998046875 +80567 -0.196197509765625 +80568 -0.289031982421875 +80569 -0.270751953125 +80570 -0.37884521484375 +80571 -0.3551025390625 +80572 -0.456329345703125 +80573 -0.42803955078125 +80574 -0.51641845703125 +80575 -0.484771728515625 +80576 -0.519287109375 +80577 -0.487396240234375 +80578 -0.458251953125 +80579 -0.4295654296875 +80580 -0.384796142578125 +80581 -0.360260009765625 +80582 -0.323699951171875 +80583 -0.30303955078125 +80584 -0.269287109375 +80585 -0.252410888671875 +80586 -0.1951904296875 +80587 -0.1832275390625 +80588 -0.100006103515625 +80589 -0.09405517578125 +80590 -0.01055908203125 +80591 -0.010345458984375 +80592 0.1033935546875 +80593 0.09674072265625 +80594 0.24908447265625 +80595 0.234161376953125 +80596 0.373199462890625 +80597 0.351226806640625 +80598 0.45806884765625 +80599 0.431182861328125 +80600 0.511474609375 +80601 0.4814453125 +80602 0.565399169921875 +80603 0.53253173828125 +80604 0.61138916015625 +80605 0.576385498046875 +80606 0.5897216796875 +80607 0.556121826171875 +80608 0.4906005859375 +80609 0.462371826171875 +80610 0.33148193359375 +80611 0.311767578125 +80612 0.147796630859375 +80613 0.137939453125 +80614 -0.01873779296875 +80615 -0.019439697265625 +80616 -0.140289306640625 +80617 -0.133941650390625 +80618 -0.191986083984375 +80619 -0.18194580078125 +80620 -0.184295654296875 +80621 -0.173492431640625 +80622 -0.161834716796875 +80623 -0.151123046875 +80624 -0.166595458984375 +80625 -0.15484619140625 +80626 -0.19390869140625 +80627 -0.18023681640625 +80628 -0.22442626953125 +80629 -0.20892333984375 +80630 -0.279754638671875 +80631 -0.261505126953125 +80632 -0.3389892578125 +80633 -0.318084716796875 +80634 -0.3543701171875 +80635 -0.333160400390625 +80636 -0.348175048828125 +80637 -0.327911376953125 +80638 -0.32598876953125 +80639 -0.3076171875 +80640 -0.2581787109375 +80641 -0.2440185546875 +80642 -0.139801025390625 +80643 -0.132354736328125 +80644 0.014617919921875 +80645 0.013580322265625 +80646 0.144378662109375 +80647 0.1361083984375 +80648 0.221038818359375 +80649 0.208282470703125 +80650 0.27069091796875 +80651 0.2548828125 +80652 0.294036865234375 +80653 0.276641845703125 +80654 0.311767578125 +80655 0.293212890625 +80656 0.339141845703125 +80657 0.31903076171875 +80658 0.360260009765625 +80659 0.338623046875 +80660 0.360504150390625 +80661 0.338226318359375 +80662 0.308380126953125 +80663 0.28900146484375 +80664 0.18170166015625 +80665 0.170745849609375 +80666 0.0047607421875 +80667 0.00604248046875 +80668 -0.17559814453125 +80669 -0.161865234375 +80670 -0.3143310546875 +80671 -0.291412353515625 +80672 -0.36785888671875 +80673 -0.342376708984375 +80674 -0.36248779296875 +80675 -0.338836669921875 +80676 -0.343536376953125 +80677 -0.322418212890625 +80678 -0.3018798828125 +80679 -0.284698486328125 +80680 -0.231414794921875 +80681 -0.22003173828125 +80682 -0.117645263671875 +80683 -0.11505126953125 +80684 0.007049560546875 +80685 0.0003662109375 +80686 0.087982177734375 +80687 0.07586669921875 +80688 0.13946533203125 +80689 0.12457275390625 +80690 0.17425537109375 +80691 0.158111572265625 +80692 0.188201904296875 +80693 0.17254638671875 +80694 0.171234130859375 +80695 0.15850830078125 +80696 0.118438720703125 +80697 0.111419677734375 +80698 0.05706787109375 +80699 0.0562744140625 +80700 -0.010711669921875 +80701 -0.0050048828125 +80702 -0.0914306640625 +80703 -0.078521728515625 +80704 -0.162322998046875 +80705 -0.143310546875 +80706 -0.194549560546875 +80707 -0.172882080078125 +80708 -0.1492919921875 +80709 -0.13153076171875 +80710 -0.02166748046875 +80711 -0.014678955078125 +80712 0.124053955078125 +80713 0.1185302734375 +80714 0.211151123046875 +80715 0.197601318359375 +80716 0.240447998046875 +80717 0.223358154296875 +80718 0.242218017578125 +80719 0.22369384765625 +80720 0.2257080078125 +80721 0.20721435546875 +80722 0.194366455078125 +80723 0.177154541015625 +80724 0.115509033203125 +80725 0.103515625 +80726 0.0128173828125 +80727 0.00811767578125 +80728 -0.053802490234375 +80729 -0.053863525390625 +80730 -0.110626220703125 +80731 -0.1065673828125 +80732 -0.199493408203125 +80733 -0.1884765625 +80734 -0.29437255859375 +80735 -0.275634765625 +80736 -0.33221435546875 +80737 -0.31005859375 +80738 -0.27972412109375 +80739 -0.261138916015625 +80740 -0.185333251953125 +80741 -0.173492431640625 +80742 -0.128204345703125 +80743 -0.1199951171875 +80744 -0.115692138671875 +80745 -0.107421875 +80746 -0.116455078125 +80747 -0.107025146484375 +80748 -0.105926513671875 +80749 -0.09625244140625 +80750 -0.053955078125 +80751 -0.047454833984375 +80752 0.048797607421875 +80753 0.04791259765625 +80754 0.157318115234375 +80755 0.148406982421875 +80756 0.212005615234375 +80757 0.19915771484375 +80758 0.218475341796875 +80759 0.205291748046875 +80760 0.23724365234375 +80761 0.222503662109375 +80762 0.30535888671875 +80763 0.284912109375 +80764 0.38128662109375 +80765 0.354278564453125 +80766 0.404449462890625 +80767 0.374908447265625 +80768 0.3944091796875 +80769 0.364837646484375 +80770 0.3885498046875 +80771 0.358551025390625 +80772 0.362640380859375 +80773 0.333831787109375 +80774 0.27362060546875 +80775 0.251068115234375 +80776 0.11712646484375 +80777 0.10626220703125 +80778 -0.054901123046875 +80779 -0.052734375 +80780 -0.19085693359375 +80781 -0.178375244140625 +80782 -0.28570556640625 +80783 -0.266021728515625 +80784 -0.339263916015625 +80785 -0.31549072265625 +80786 -0.3775634765625 +80787 -0.350738525390625 +80788 -0.445709228515625 +80789 -0.41326904296875 +80790 -0.535064697265625 +80791 -0.495147705078125 +80792 -0.629058837890625 +80793 -0.581146240234375 +80794 -0.697601318359375 +80795 -0.64361572265625 +80796 -0.70391845703125 +80797 -0.648773193359375 +80798 -0.6424560546875 +80799 -0.591522216796875 +80800 -0.491241455078125 +80801 -0.451690673828125 +80802 -0.265716552734375 +80803 -0.243499755859375 +80804 -0.023712158203125 +80805 -0.02020263671875 +80806 0.201751708984375 +80807 0.187744140625 +80808 0.375823974609375 +80809 0.3482666015625 +80810 0.485076904296875 +80811 0.449005126953125 +80812 0.56884765625 +80813 0.526153564453125 +80814 0.634765625 +80815 0.58673095703125 +80816 0.63763427734375 +80817 0.58917236328125 +80818 0.5660400390625 +80819 0.522979736328125 +80820 0.4720458984375 +80821 0.436065673828125 +80822 0.40692138671875 +80823 0.375579833984375 +80824 0.3778076171875 +80825 0.34820556640625 +80826 0.376953125 +80827 0.3468017578125 +80828 0.371978759765625 +80829 0.34161376953125 +80830 0.313140869140625 +80831 0.28692626953125 +80832 0.184417724609375 +80833 0.167999267578125 +80834 0.011199951171875 +80835 0.00823974609375 +80836 -0.171051025390625 +80837 -0.15972900390625 +80838 -0.33740234375 +80839 -0.31292724609375 +80840 -0.47198486328125 +80841 -0.436737060546875 +80842 -0.560394287109375 +80843 -0.5179443359375 +80844 -0.58056640625 +80845 -0.5362548828125 +80846 -0.54754638671875 +80847 -0.505523681640625 +80848 -0.508575439453125 +80849 -0.46923828125 +80850 -0.459503173828125 +80851 -0.423583984375 +80852 -0.394378662109375 +80853 -0.3631591796875 +80854 -0.35260009765625 +80855 -0.32421875 +80856 -0.31170654296875 +80857 -0.286102294921875 +80858 -0.197418212890625 +80859 -0.180511474609375 +80860 -0.007965087890625 +80861 -0.005828857421875 +80862 0.207489013671875 +80863 0.19268798828125 +80864 0.409210205078125 +80865 0.37847900390625 +80866 0.57208251953125 +80867 0.52838134765625 +80868 0.66595458984375 +80869 0.61468505859375 +80870 0.65875244140625 +80871 0.60791015625 +80872 0.56744384765625 +80873 0.523651123046875 +80874 0.431396484375 +80875 0.39813232421875 +80876 0.29443359375 +80877 0.271728515625 +80878 0.182464599609375 +80879 0.16827392578125 +80880 0.06365966796875 +80881 0.05853271484375 +80882 -0.075958251953125 +80883 -0.070343017578125 +80884 -0.189422607421875 +80885 -0.175140380859375 +80886 -0.271942138671875 +80887 -0.25140380859375 +80888 -0.342529296875 +80889 -0.316619873046875 +80890 -0.364166259765625 +80891 -0.336761474609375 +80892 -0.327239990234375 +80893 -0.302947998046875 +80894 -0.2769775390625 +80895 -0.25677490234375 +80896 -0.253692626953125 +80897 -0.235076904296875 +80898 -0.24365234375 +80899 -0.22540283203125 +80900 -0.1983642578125 +80901 -0.184295654296875 +80902 -0.116241455078125 +80903 -0.1102294921875 +80904 -0.036834716796875 +80905 -0.038238525390625 +80906 0.034881591796875 +80907 0.027191162109375 +80908 0.09124755859375 +80909 0.079193115234375 +80910 0.10888671875 +80911 0.096954345703125 +80912 0.125518798828125 +80913 0.11383056640625 +80914 0.15771484375 +80915 0.1444091796875 +80916 0.17828369140625 +80917 0.1644287109375 +80918 0.17108154296875 +80919 0.159454345703125 +80920 0.129974365234375 +80921 0.123992919921875 +80922 0.082427978515625 +80923 0.08233642578125 +80924 0.027679443359375 +80925 0.0338134765625 +80926 -0.065643310546875 +80927 -0.0494384765625 +80928 -0.15936279296875 +80929 -0.13348388671875 +80930 -0.21307373046875 +80931 -0.182373046875 +80932 -0.234649658203125 +80933 -0.20306396484375 +80934 -0.2001953125 +80935 -0.174224853515625 +80936 -0.119171142578125 +80937 -0.10418701171875 +80938 -0.024749755859375 +80939 -0.022308349609375 +80940 0.085784912109375 +80941 0.073944091796875 +80942 0.178131103515625 +80943 0.154205322265625 +80944 0.215576171875 +80945 0.186004638671875 +80946 0.211456298828125 +80947 0.18121337890625 +80948 0.17523193359375 +80949 0.148284912109375 +80950 0.128753662109375 +80951 0.106689453125 +80952 0.1019287109375 +80953 0.082977294921875 +80954 0.0743408203125 +80955 0.05902099609375 +80956 0.04327392578125 +80957 0.0323486328125 +80958 0.038177490234375 +80959 0.029022216796875 +80960 0.076263427734375 +80961 0.064300537109375 +80962 0.14105224609375 +80963 0.1234130859375 +80964 0.186431884765625 +80965 0.16534423828125 +80966 0.188812255859375 +80967 0.169036865234375 +80968 0.1390380859375 +80969 0.126251220703125 +80970 0.041778564453125 +80971 0.041107177734375 +80972 -0.079437255859375 +80973 -0.0655517578125 +80974 -0.219390869140625 +80975 -0.18914794921875 +80976 -0.367828369140625 +80977 -0.320587158203125 +80978 -0.494873046875 +80979 -0.433349609375 +80980 -0.556243896484375 +80981 -0.488128662109375 +80982 -0.508697509765625 +80983 -0.446502685546875 +80984 -0.3756103515625 +80985 -0.32916259765625 +80986 -0.218902587890625 +80987 -0.191070556640625 +80988 -0.063751220703125 +80989 -0.05450439453125 +80990 0.091552734375 +80991 0.08209228515625 +80992 0.23602294921875 +80993 0.209075927734375 +80994 0.342987060546875 +80995 0.30279541015625 +80996 0.39520263671875 +80997 0.3480224609375 +80998 0.389373779296875 +80999 0.3419189453125 +81000 0.324249267578125 +81001 0.28338623046875 +81002 0.224090576171875 +81003 0.194000244140625 +81004 0.124267578125 +81005 0.105224609375 +81006 0.037078857421875 +81007 0.027923583984375 +81008 -0.010101318359375 +81009 -0.013580322265625 +81010 -0.019439697265625 +81011 -0.021270751953125 +81012 -0.022796630859375 +81013 -0.0234375 +81014 -0.001556396484375 +81015 -0.003570556640625 +81016 0.056304931640625 +81017 0.048919677734375 +81018 0.106719970703125 +81019 0.09478759765625 +81020 0.096893310546875 +81021 0.087127685546875 +81022 0.042694091796875 +81023 0.040008544921875 +81024 -0.018035888671875 +81025 -0.0130615234375 +81026 -0.07586669921875 +81027 -0.063720703125 +81028 -0.11944580078125 +81029 -0.1019287109375 +81030 -0.15972900390625 +81031 -0.137451171875 +81032 -0.202606201171875 +81033 -0.175537109375 +81034 -0.24859619140625 +81035 -0.216644287109375 +81036 -0.30517578125 +81037 -0.267333984375 +81038 -0.36212158203125 +81039 -0.31854248046875 +81040 -0.39141845703125 +81041 -0.345367431640625 +81042 -0.35528564453125 +81043 -0.314178466796875 +81044 -0.249969482421875 +81045 -0.22161865234375 +81046 -0.092864990234375 +81047 -0.083099365234375 +81048 0.08905029296875 +81049 0.0775146484375 +81050 0.2352294921875 +81051 0.206512451171875 +81052 0.318817138671875 +81053 0.28009033203125 +81054 0.358642578125 +81055 0.31500244140625 +81056 0.347747802734375 +81057 0.305084228515625 +81058 0.28564453125 +81059 0.249908447265625 +81060 0.223175048828125 +81061 0.19464111328125 +81062 0.196746826171875 +81063 0.17156982421875 +81064 0.179840087890625 +81065 0.1571044921875 +81066 0.155548095703125 +81067 0.13623046875 +81068 0.151214599609375 +81069 0.133148193359375 +81070 0.156951904296875 +81071 0.139068603515625 +81072 0.13177490234375 +81073 0.117523193359375 +81074 0.100799560546875 +81075 0.09075927734375 +81076 0.087127685546875 +81077 0.079254150390625 +81078 0.05487060546875 +81079 0.051116943359375 +81080 -0.009002685546875 +81081 -0.0052490234375 +81082 -0.10400390625 +81083 -0.089385986328125 +81084 -0.229400634765625 +81085 -0.200653076171875 +81086 -0.35552978515625 +81087 -0.312713623046875 +81088 -0.441925048828125 +81089 -0.3896484375 +81090 -0.473846435546875 +81091 -0.41839599609375 +81092 -0.464813232421875 +81093 -0.410858154296875 +81094 -0.419097900390625 +81095 -0.370819091796875 +81096 -0.334320068359375 +81097 -0.296173095703125 +81098 -0.227935791015625 +81099 -0.20233154296875 +81100 -0.12347412109375 +81101 -0.11016845703125 +81102 -0.02764892578125 +81103 -0.025604248046875 +81104 0.077667236328125 +81105 0.06744384765625 +81106 0.2132568359375 +81107 0.187469482421875 +81108 0.38885498046875 +81109 0.3431396484375 +81110 0.582794189453125 +81111 0.51519775390625 +81112 0.734039306640625 +81113 0.649444580078125 +81114 0.800140380859375 +81115 0.708221435546875 +81116 0.7783203125 +81117 0.68902587890625 +81118 0.6651611328125 +81119 0.588836669921875 +81120 0.45965576171875 +81121 0.40673828125 +81122 0.199188232421875 +81123 0.1759033203125 +81124 -0.050689697265625 +81125 -0.04547119140625 +81126 -0.23297119140625 +81127 -0.206817626953125 +81128 -0.33013916015625 +81129 -0.292633056640625 +81130 -0.368408203125 +81131 -0.326171875 +81132 -0.378936767578125 +81133 -0.335113525390625 +81134 -0.376983642578125 +81135 -0.333038330078125 +81136 -0.37969970703125 +81137 -0.335205078125 +81138 -0.391510009765625 +81139 -0.345550537109375 +81140 -0.385345458984375 +81141 -0.340057373046875 +81142 -0.3419189453125 +81143 -0.301605224609375 +81144 -0.28289794921875 +81145 -0.249420166015625 +81146 -0.251617431640625 +81147 -0.221954345703125 +81148 -0.266143798828125 +81149 -0.235198974609375 +81150 -0.273345947265625 +81151 -0.24200439453125 +81152 -0.216796875 +81153 -0.192352294921875 +81154 -0.128265380859375 +81155 -0.114166259765625 +81156 -0.068145751953125 +81157 -0.060089111328125 +81158 -0.0430908203125 +81159 -0.03594970703125 +81160 -0.024444580078125 +81161 -0.01739501953125 +81162 0.020721435546875 +81163 0.023651123046875 +81164 0.124481201171875 +81165 0.114501953125 +81166 0.25787353515625 +81167 0.230224609375 +81168 0.379119873046875 +81169 0.334991455078125 +81170 0.47991943359375 +81171 0.421661376953125 +81172 0.5281982421875 +81173 0.4627685546875 +81174 0.511138916015625 +81175 0.447357177734375 +81176 0.456207275390625 +81177 0.399017333984375 +81178 0.407470703125 +81179 0.355560302734375 +81180 0.383758544921875 +81181 0.333221435546875 +81182 0.35687255859375 +81183 0.307952880859375 +81184 0.31182861328125 +81185 0.267059326171875 +81186 0.250885009765625 +81187 0.212615966796875 +81188 0.1654052734375 +81189 0.137359619140625 +81190 0.035247802734375 +81191 0.024139404296875 +81192 -0.142059326171875 +81193 -0.129058837890625 +81194 -0.33563232421875 +81195 -0.295745849609375 +81196 -0.5345458984375 +81197 -0.46649169921875 +81198 -0.72186279296875 +81199 -0.62677001953125 +81200 -0.836669921875 +81201 -0.7244873046875 +81202 -0.8326416015625 +81203 -0.72003173828125 +81204 -0.7296142578125 +81205 -0.6304931640625 +81206 -0.582550048828125 +81207 -0.502960205078125 +81208 -0.440093994140625 +81209 -0.379180908203125 +81210 -0.324310302734375 +81211 -0.278167724609375 +81212 -0.20147705078125 +81213 -0.171142578125 +81214 -0.044647216796875 +81215 -0.035125732421875 +81216 0.103973388671875 +81217 0.093658447265625 +81218 0.202392578125 +81219 0.179168701171875 +81220 0.264495849609375 +81221 0.233245849609375 +81222 0.338897705078125 +81223 0.2974853515625 +81224 0.443817138671875 +81225 0.387420654296875 +81226 0.545074462890625 +81227 0.47381591796875 +81228 0.6173095703125 +81229 0.53497314453125 +81230 0.6524658203125 +81231 0.564056396484375 +81232 0.66339111328125 +81233 0.572113037109375 +81234 0.6561279296875 +81235 0.56439208984375 +81236 0.606781005859375 +81237 0.520538330078125 +81238 0.501190185546875 +81239 0.42852783203125 +81240 0.352783203125 +81241 0.2999267578125 +81242 0.176544189453125 +81243 0.147674560546875 +81244 -0.034820556640625 +81245 -0.034423828125 +81246 -0.258209228515625 +81247 -0.226531982421875 +81248 -0.44244384765625 +81249 -0.384765625 +81250 -0.5753173828125 +81251 -0.4986572265625 +81252 -0.65203857421875 +81253 -0.56414794921875 +81254 -0.641632080078125 +81255 -0.55474853515625 +81256 -0.562164306640625 +81257 -0.485931396484375 +81258 -0.458038330078125 +81259 -0.395782470703125 +81260 -0.350555419921875 +81261 -0.302581787109375 +81262 -0.260528564453125 +81263 -0.224212646484375 +81264 -0.192108154296875 +81265 -0.164306640625 +81266 -0.141937255859375 +81267 -0.120086669921875 +81268 -0.1021728515625 +81269 -0.08489990234375 +81270 -0.062896728515625 +81271 -0.050323486328125 +81272 -0.011932373046875 +81273 -0.005950927734375 +81274 0.062835693359375 +81275 0.058563232421875 +81276 0.148712158203125 +81277 0.13232421875 +81278 0.241729736328125 +81279 0.2119140625 +81280 0.34912109375 +81281 0.30352783203125 +81282 0.457305908203125 +81283 0.395599365234375 +81284 0.54388427734375 +81285 0.46893310546875 +81286 0.5728759765625 +81287 0.492828369140625 +81288 0.506591796875 +81289 0.43505859375 +81290 0.351226806640625 +81291 0.300994873046875 +81292 0.146514892578125 +81293 0.12469482421875 +81294 -0.05523681640625 +81295 -0.048980712890625 +81296 -0.21624755859375 +81297 -0.18768310546875 +81298 -0.334930419921875 +81299 -0.289947509765625 +81300 -0.402984619140625 +81301 -0.348663330078125 +81302 -0.4412841796875 +81303 -0.381683349609375 +81304 -0.49578857421875 +81305 -0.428375244140625 +81306 -0.5601806640625 +81307 -0.483306884765625 +81308 -0.600738525390625 +81309 -0.51763916015625 +81310 -0.584228515625 +81311 -0.502960205078125 +81312 -0.47930908203125 +81313 -0.41241455078125 +81314 -0.27935791015625 +81315 -0.240447998046875 +81316 -0.0089111328125 +81317 -0.008087158203125 +81318 0.268798828125 +81319 0.23046875 +81320 0.482818603515625 +81321 0.41448974609375 +81322 0.60369873046875 +81323 0.518707275390625 +81324 0.650421142578125 +81325 0.559295654296875 +81326 0.66400146484375 +81327 0.57135009765625 +81328 0.6414794921875 +81329 0.55230712890625 +81330 0.572540283203125 +81331 0.49334716796875 +81332 0.498138427734375 +81333 0.429534912109375 +81334 0.439453125 +81335 0.378997802734375 +81336 0.375518798828125 +81337 0.323822021484375 +81338 0.274505615234375 +81339 0.236785888671875 +81340 0.1087646484375 +81341 0.09423828125 +81342 -0.099395751953125 +81343 -0.084686279296875 +81344 -0.3182373046875 +81345 -0.272735595703125 +81346 -0.5489501953125 +81347 -0.470916748046875 +81348 -0.7738037109375 +81349 -0.663970947265625 +81350 -0.86383056640625 +81351 -0.806549072265625 +81352 -0.870391845703125 +81353 -0.856231689453125 +81354 -0.86895751953125 +81355 -0.856201171875 +81356 -0.861053466796875 +81357 -0.81732177734375 +81358 -0.765869140625 +81359 -0.697235107421875 +81360 -0.5301513671875 +81361 -0.5001220703125 +81362 -0.214691162109375 +81363 -0.23211669921875 +81364 0.137359619140625 +81365 0.069915771484375 +81366 0.474822998046875 +81367 0.36199951171875 +81368 0.76239013671875 +81369 0.613677978515625 +81370 0.867462158203125 +81371 0.801849365234375 +81372 0.870361328125 +81373 0.86236572265625 +81374 0.86480712890625 +81375 0.8680419921875 +81376 0.831817626953125 +81377 0.8662109375 +81378 0.677581787109375 +81379 0.85919189453125 +81380 0.495880126953125 +81381 0.790435791015625 +81382 0.30767822265625 +81383 0.6563720703125 +81384 0.116180419921875 +81385 0.497283935546875 +81386 -0.110748291015625 +81387 0.286041259765625 +81388 -0.381805419921875 +81389 0.016754150390625 +81390 -0.6572265625 +81391 -0.27392578125 +81392 -0.857421875 +81393 -0.534698486328125 +81394 -0.870391845703125 +81395 -0.728790283203125 +81396 -0.870391845703125 +81397 -0.850006103515625 +81398 -0.86444091796875 +81399 -0.86181640625 +81400 -0.85723876953125 +81401 -0.86749267578125 +81402 -0.790008544921875 +81403 -0.86932373046875 +81404 -0.62847900390625 +81405 -0.862274169921875 +81406 -0.3956298828125 +81407 -0.776763916015625 +81408 -0.126708984375 +81409 -0.5716552734375 +81410 0.150115966796875 +81411 -0.333831787109375 +81412 0.424041748046875 +81413 -0.073638916015625 +81414 0.670623779296875 +81415 0.186065673828125 +81416 0.854522705078125 +81417 0.4127197265625 +81418 0.866485595703125 +81419 0.59124755859375 +81420 0.86920166015625 +81421 0.708526611328125 +81422 0.8653564453125 +81423 0.779205322265625 +81424 0.857147216796875 +81425 0.81414794921875 +81426 0.766845703125 +81427 0.81085205078125 +81428 0.628509521484375 +81429 0.773590087890625 +81430 0.462127685546875 +81431 0.696990966796875 +81432 0.297210693359375 +81433 0.602569580078125 +81434 0.14862060546875 +81435 0.5008544921875 +81436 -0.00537109375 +81437 0.373443603515625 +81438 -0.15753173828125 +81439 0.2269287109375 +81440 -0.31304931640625 +81441 0.05877685546875 +81442 -0.48876953125 +81443 -0.142120361328125 +81444 -0.6416015625 +81445 -0.33673095703125 +81446 -0.751373291015625 +81447 -0.50433349609375 +81448 -0.84619140625 +81449 -0.663665771484375 +81450 -0.861297607421875 +81451 -0.802398681640625 +81452 -0.863250732421875 +81453 -0.858734130859375 +81454 -0.856597900390625 +81455 -0.86053466796875 +81456 -0.7498779296875 +81457 -0.855377197265625 +81458 -0.624542236328125 +81459 -0.798858642578125 +81460 -0.47808837890625 +81461 -0.701324462890625 +81462 -0.253387451171875 +81463 -0.521881103515625 +81464 0.003692626953125 +81465 -0.2984619140625 +81466 0.2257080078125 +81467 -0.087799072265625 +81468 0.427154541015625 +81469 0.12005615234375 +81470 0.643218994140625 +81471 0.351409912109375 +81472 0.855926513671875 +81473 0.59796142578125 +81474 0.870361328125 +81475 0.8116455078125 +81476 0.870361328125 +81477 0.86505126953125 +81478 0.862762451171875 +81479 0.870361328125 +81480 0.79669189453125 +81481 0.868133544921875 +81482 0.595794677734375 +81483 0.857696533203125 +81484 0.362152099609375 +81485 0.737945556640625 +81486 0.1270751953125 +81487 0.56536865234375 +81488 -0.086944580078125 +81489 0.3843994140625 +81490 -0.2784423828125 +81491 0.197235107421875 +81492 -0.484832763671875 +81493 -0.024627685546875 +81494 -0.729583740234375 +81495 -0.297027587890625 +81496 -0.86688232421875 +81497 -0.578582763671875 +81498 -0.870391845703125 +81499 -0.817596435546875 +81500 -0.86859130859375 +81501 -0.870391845703125 +81502 -0.86279296875 +81503 -0.870391845703125 +81504 -0.817962646484375 +81505 -0.863525390625 +81506 -0.6116943359375 +81507 -0.78167724609375 +81508 -0.3128662109375 +81509 -0.534423828125 +81510 0.039398193359375 +81511 -0.228057861328125 +81512 0.422821044921875 +81513 0.11773681640625 +81514 0.805145263671875 +81515 0.47430419921875 +81516 0.870361328125 +81517 0.786285400390625 +81518 0.870361328125 +81519 0.870361328125 +81520 0.860015869140625 +81521 0.870361328125 +81522 0.727935791015625 +81523 0.861175537109375 +81524 0.48114013671875 +81525 0.755401611328125 +81526 0.2059326171875 +81527 0.55078125 +81528 -0.06103515625 +81529 0.33154296875 +81530 -0.29913330078125 +81531 0.115203857421875 +81532 -0.516204833984375 +81533 -0.10296630859375 +81534 -0.7252197265625 +81535 -0.3309326171875 +81536 -0.85980224609375 +81537 -0.546051025390625 +81538 -0.870391845703125 +81539 -0.72052001953125 +81540 -0.870391845703125 +81541 -0.833038330078125 +81542 -0.858062744140625 +81543 -0.848785400390625 +81544 -0.673004150390625 +81545 -0.77154541015625 +81546 -0.42694091796875 +81547 -0.653289794921875 +81548 -0.2100830078125 +81549 -0.540252685546875 +81550 -0.0362548828125 +81551 -0.440765380859375 +81552 0.10943603515625 +81553 -0.340789794921875 +81554 0.23516845703125 +81555 -0.233184814453125 +81556 0.373687744140625 +81557 -0.091888427734375 +81558 0.517791748046875 +81559 0.07501220703125 +81560 0.602783203125 +81561 0.21099853515625 +81562 0.635711669921875 +81563 0.317779541015625 +81564 0.655181884765625 +81565 0.42242431640625 +81566 0.65948486328125 +81567 0.5184326171875 +81568 0.651275634765625 +81569 0.602813720703125 +81570 0.61846923828125 +81571 0.66070556640625 +81572 0.53753662109375 +81573 0.668243408203125 +81574 0.404144287109375 +81575 0.618133544921875 +81576 0.22186279296875 +81577 0.510498046875 +81578 0.003997802734375 +81579 0.354461669921875 +81580 -0.22100830078125 +81581 0.172698974609375 +81582 -0.42449951171875 +81583 -0.010772705078125 +81584 -0.579833984375 +81585 -0.172576904296875 +81586 -0.641876220703125 +81587 -0.273193359375 +81588 -0.6177978515625 +81589 -0.315338134765625 +81590 -0.575531005859375 +81591 -0.35125732421875 +81592 -0.526336669921875 +81593 -0.386138916015625 +81594 -0.42645263671875 +81595 -0.37969970703125 +81596 -0.2581787109375 +81597 -0.31317138671875 +81598 -0.068695068359375 +81599 -0.22161865234375 +81600 0.09222412109375 +81601 -0.142730712890625 +81602 0.232147216796875 +81603 -0.067657470703125 +81604 0.3509521484375 +81605 0.005279541015625 +81606 0.410064697265625 +81607 0.045196533203125 +81608 0.372955322265625 +81609 0.02203369140625 +81610 0.2554931640625 +81611 -0.05194091796875 +81612 0.10711669921875 +81613 -0.1376953125 +81614 -0.052886962890625 +81615 -0.221771240234375 +81616 -0.186279296875 +81617 -0.27557373046875 +81618 -0.23291015625 +81619 -0.25286865234375 +81620 -0.209442138671875 +81621 -0.17083740234375 +81622 -0.174163818359375 +81623 -0.080963134765625 +81624 -0.126739501953125 +81625 0.01373291015625 +81626 -0.048126220703125 +81627 0.12603759765625 +81628 0.0426025390625 +81629 0.2379150390625 +81630 0.10748291015625 +81631 0.316375732421875 +81632 0.1409912109375 +81633 0.3558349609375 +81634 0.19708251953125 +81635 0.400482177734375 +81636 0.273651123046875 +81637 0.4490966796875 +81638 0.31768798828125 +81639 0.459136962890625 +81640 0.341094970703125 +81641 0.442169189453125 +81642 0.368011474609375 +81643 0.42034912109375 +81644 0.37249755859375 +81645 0.37493896484375 +81646 0.30072021484375 +81647 0.264373779296875 +81648 0.1517333984375 +81649 0.09075927734375 +81650 -0.01470947265625 +81651 -0.09393310546875 +81652 -0.1883544921875 +81653 -0.27874755859375 +81654 -0.372711181640625 +81655 -0.464447021484375 +81656 -0.51397705078125 +81657 -0.6051025390625 +81658 -0.57177734375 +81659 -0.666351318359375 +81660 -0.53948974609375 +81661 -0.642333984375 +81662 -0.43511962890625 +81663 -0.548065185546875 +81664 -0.2962646484375 +81665 -0.415557861328125 +81666 -0.161102294921875 +81667 -0.277679443359375 +81668 -0.0435791015625 +81669 -0.1474609375 +81670 0.060394287109375 +81671 -0.0235595703125 +81672 0.13665771484375 +81673 0.080596923828125 +81674 0.170135498046875 +81675 0.150726318359375 +81676 0.16552734375 +81677 0.188323974609375 +81678 0.15728759765625 +81679 0.218841552734375 +81680 0.150787353515625 +81681 0.244720458984375 +81682 0.12200927734375 +81683 0.2452392578125 +81684 0.080108642578125 +81685 0.226654052734375 +81686 0.05126953125 +81687 0.209320068359375 +81688 0.062896728515625 +81689 0.21514892578125 +81690 0.09271240234375 +81691 0.226715087890625 +81692 0.092987060546875 +81693 0.206756591796875 +81694 0.07855224609375 +81695 0.16845703125 +81696 0.06427001953125 +81697 0.125335693359375 +81698 0.0347900390625 +81699 0.06695556640625 +81700 -0.01171875 +81701 -0.006195068359375 +81702 -0.056060791015625 +81703 -0.07672119140625 +81704 -0.055511474609375 +81705 -0.108551025390625 +81706 -0.010467529296875 +81707 -0.100341796875 +81708 0.02508544921875 +81709 -0.0938720703125 +81710 0.025665283203125 +81711 -0.1085205078125 +81712 0.017333984375 +81713 -0.122802734375 +81714 0.00189208984375 +81715 -0.135101318359375 +81716 -0.03173828125 +81717 -0.15447998046875 +81718 -0.071502685546875 +81719 -0.171966552734375 +81720 -0.13543701171875 +81721 -0.20294189453125 +81722 -0.219970703125 +81723 -0.245819091796875 +81724 -0.300506591796875 +81725 -0.28240966796875 +81726 -0.376312255859375 +81727 -0.313720703125 +81728 -0.416107177734375 +81729 -0.31634521484375 +81730 -0.371124267578125 +81731 -0.25286865234375 +81732 -0.242279052734375 +81733 -0.125457763671875 +81734 -0.069732666015625 +81735 0.032470703125 +81736 0.125640869140625 +81737 0.2032470703125 +81738 0.31268310546875 +81739 0.361328125 +81740 0.45501708984375 +81741 0.47735595703125 +81742 0.554779052734375 +81743 0.553070068359375 +81744 0.61065673828125 +81745 0.58782958984375 +81746 0.610931396484375 +81747 0.572967529296875 +81748 0.531463623046875 +81749 0.49017333984375 +81750 0.3883056640625 +81751 0.353424072265625 +81752 0.23468017578125 +81753 0.206634521484375 +81754 0.095245361328125 +81755 0.07086181640625 +81756 -0.00396728515625 +81757 -0.03173828125 +81758 -0.04852294921875 +81759 -0.088409423828125 +81760 -0.055145263671875 +81761 -0.11138916015625 +81762 -0.0758056640625 +81763 -0.14141845703125 +81764 -0.138702392578125 +81765 -0.200439453125 +81766 -0.209197998046875 +81767 -0.260406494140625 +81768 -0.289031982421875 +81769 -0.322662353515625 +81770 -0.37884521484375 +81771 -0.387969970703125 +81772 -0.456329345703125 +81773 -0.43896484375 +81774 -0.51641845703125 +81775 -0.472320556640625 +81776 -0.519287109375 +81777 -0.45709228515625 +81778 -0.458251953125 +81779 -0.38897705078125 +81780 -0.384796142578125 +81781 -0.31024169921875 +81782 -0.323699951171875 +81783 -0.241851806640625 +81784 -0.269287109375 +81785 -0.180267333984375 +81786 -0.1951904296875 +81787 -0.105377197265625 +81788 -0.100006103515625 +81789 -0.016815185546875 +81790 -0.01055908203125 +81791 0.063323974609375 +81792 0.1033935546875 +81793 0.158905029296875 +81794 0.24908447265625 +81795 0.275604248046875 +81796 0.373199462890625 +81797 0.370880126953125 +81798 0.45806884765625 +81799 0.430938720703125 +81800 0.511474609375 +81801 0.4625244140625 +81802 0.565399169921875 +81803 0.491973876953125 +81804 0.61138916015625 +81805 0.5133056640625 +81806 0.5897216796875 +81807 0.479644775390625 +81808 0.4906005859375 +81809 0.384033203125 +81810 0.33148193359375 +81811 0.241363525390625 +81812 0.147796630859375 +81813 0.080780029296875 +81814 -0.01873779296875 +81815 -0.06365966796875 +81816 -0.140289306640625 +81817 -0.169158935546875 +81818 -0.191986083984375 +81819 -0.215423583984375 +81820 -0.184295654296875 +81821 -0.210662841796875 +81822 -0.161834716796875 +81823 -0.19061279296875 +81824 -0.166595458984375 +81825 -0.189056396484375 +81826 -0.19390869140625 +81827 -0.20263671875 +81828 -0.22442626953125 +81829 -0.216400146484375 +81830 -0.279754638671875 +81831 -0.248291015625 +81832 -0.3389892578125 +81833 -0.282318115234375 +81834 -0.3543701171875 +81835 -0.28106689453125 +81836 -0.348175048828125 +81837 -0.2630615234375 +81838 -0.32598876953125 +81839 -0.23345947265625 +81840 -0.2581787109375 +81841 -0.169189453125 +81842 -0.139801025390625 +81843 -0.066802978515625 +81844 0.014617919921875 +81845 0.061767578125 +81846 0.144378662109375 +81847 0.167694091796875 +81848 0.221038818359375 +81849 0.228240966796875 +81850 0.27069091796875 +81851 0.264404296875 +81852 0.294036865234375 +81853 0.277008056640625 +81854 0.311767578125 +81855 0.28302001953125 +81856 0.339141845703125 +81857 0.295135498046875 +81858 0.360260009765625 +81859 0.301116943359375 +81860 0.360504150390625 +81861 0.2899169921875 +81862 0.308380126953125 +81863 0.23724365234375 +81864 0.18170166015625 +81865 0.12615966796875 +81866 0.0047607421875 +81867 -0.0234375 +81868 -0.17559814453125 +81869 -0.173980712890625 +81870 -0.3143310546875 +81871 -0.289398193359375 +81872 -0.36785888671875 +81873 -0.3349609375 +81874 -0.36248779296875 +81875 -0.331390380859375 +81876 -0.343536376953125 +81877 -0.314605712890625 +81878 -0.3018798828125 +81879 -0.277557373046875 +81880 -0.231414794921875 +81881 -0.2156982421875 +81882 -0.117645263671875 +81883 -0.117919921875 +81884 0.007049560546875 +81885 -0.01031494140625 +81886 0.087982177734375 +81887 0.063262939453125 +81888 0.13946533203125 +81889 0.11358642578125 +81890 0.17425537109375 +81891 0.150238037109375 +81892 0.188201904296875 +81893 0.169464111328125 +81894 0.171234130859375 +81895 0.162841796875 +81896 0.118438720703125 +81897 0.126190185546875 +81898 0.05706787109375 +81899 0.080841064453125 +81900 -0.010711669921875 +81901 0.0283203125 +81902 -0.0914306640625 +81903 -0.036468505859375 +81904 -0.162322998046875 +81905 -0.09539794921875 +81906 -0.194549560546875 +81907 -0.125457763671875 +81908 -0.1492919921875 +81909 -0.095611572265625 +81910 -0.02166748046875 +81911 -0.0015869140625 +81912 0.124053955078125 +81913 0.106109619140625 +81914 0.211151123046875 +81915 0.16717529296875 +81916 0.240447998046875 +81917 0.182708740234375 +81918 0.242218017578125 +81919 0.17706298828125 +81920 0.2257080078125 +81921 0.157440185546875 +81922 0.194366455078125 +81923 0.12713623046875 +81924 0.115509033203125 +81925 0.062164306640625 +81926 0.0128173828125 +81927 -0.01922607421875 +81928 -0.053802490234375 +81929 -0.071380615234375 +81930 -0.110626220703125 +81931 -0.1142578125 +81932 -0.199493408203125 +81933 -0.179779052734375 +81934 -0.29437255859375 +81935 -0.248321533203125 +81936 -0.33221435546875 +81937 -0.272216796875 +81938 -0.27972412109375 +81939 -0.22650146484375 +81940 -0.185333251953125 +81941 -0.148345947265625 +81942 -0.128204345703125 +81943 -0.0982666015625 +81944 -0.115692138671875 +81945 -0.08221435546875 +81946 -0.116455078125 +81947 -0.07672119140625 +81948 -0.105926513671875 +81949 -0.0634765625 +81950 -0.053955078125 +81951 -0.01983642578125 +81952 0.048797607421875 +81953 0.06109619140625 +81954 0.157318115234375 +81955 0.145050048828125 +81956 0.212005615234375 +81957 0.1866455078125 +81958 0.218475341796875 +81959 0.190185546875 +81960 0.23724365234375 +81961 0.201812744140625 +81962 0.30535888671875 +81963 0.2498779296875 +81964 0.38128662109375 +81965 0.303009033203125 +81966 0.404449462890625 +81967 0.315399169921875 +81968 0.3944091796875 +81969 0.302276611328125 +81970 0.3885498046875 +81971 0.292327880859375 +81972 0.362640380859375 +81973 0.2674560546875 +81974 0.27362060546875 +81975 0.195220947265625 +81976 0.11712646484375 +81977 0.072540283203125 +81978 -0.054901123046875 +81979 -0.0609130859375 +81980 -0.19085693359375 +81981 -0.165802001953125 +81982 -0.28570556640625 +81983 -0.238250732421875 +81984 -0.339263916015625 +81985 -0.278167724609375 +81986 -0.3775634765625 +81987 -0.305389404296875 +81988 -0.445709228515625 +81989 -0.354339599609375 +81990 -0.535064697265625 +81991 -0.41864013671875 +81992 -0.629058837890625 +81993 -0.48590087890625 +81994 -0.697601318359375 +81995 -0.53350830078125 +81996 -0.70391845703125 +81997 -0.53375244140625 +81998 -0.6424560546875 +81999 -0.482666015625 +82000 -0.491241455078125 +82001 -0.36376953125 +82002 -0.265716552734375 +82003 -0.188995361328125 +82004 -0.023712158203125 +82005 -0.002471923828125 +82006 0.201751708984375 +82007 0.170562744140625 +82008 0.375823974609375 +82009 0.303558349609375 +82010 0.485076904296875 +82011 0.38629150390625 +82012 0.56884765625 +82013 0.448699951171875 +82014 0.634765625 +82015 0.496673583984375 +82016 0.63763427734375 +82017 0.49603271484375 +82018 0.5660400390625 +82019 0.438232421875 +82020 0.4720458984375 +82021 0.363037109375 +82022 0.40692138671875 +82023 0.30963134765625 +82024 0.3778076171875 +82025 0.28369140625 +82026 0.376953125 +82027 0.279510498046875 +82028 0.371978759765625 +82029 0.272674560546875 +82030 0.313140869140625 +82031 0.225555419921875 +82032 0.184417724609375 +82033 0.126068115234375 +82034 0.011199951171875 +82035 -0.006378173828125 +82036 -0.171051025390625 +82037 -0.14483642578125 +82038 -0.33740234375 +82039 -0.2703857421875 +82040 -0.47198486328125 +82041 -0.37103271484375 +82042 -0.560394287109375 +82043 -0.43597412109375 +82044 -0.58056640625 +82045 -0.448577880859375 +82046 -0.54754638671875 +82047 -0.420440673828125 +82048 -0.508575439453125 +82049 -0.38763427734375 +82050 -0.459503173828125 +82051 -0.34716796875 +82052 -0.394378662109375 +82053 -0.294708251953125 +82054 -0.35260009765625 +82055 -0.260345458984375 +82056 -0.31170654296875 +82057 -0.227142333984375 +82058 -0.197418212890625 +82059 -0.13873291015625 +82060 -0.007965087890625 +82061 0.006134033203125 +82062 0.207489013671875 +82063 0.1700439453125 +82064 0.409210205078125 +82065 0.32281494140625 +82066 0.57208251953125 +82067 0.4454345703125 +82068 0.66595458984375 +82069 0.51507568359375 +82070 0.65875244140625 +82071 0.5074462890625 +82072 0.56744384765625 +82073 0.435577392578125 +82074 0.431396484375 +82075 0.32952880859375 +82076 0.29443359375 +82077 0.2227783203125 +82078 0.182464599609375 +82079 0.135162353515625 +82080 0.06365966796875 +82081 0.0426025390625 +82082 -0.075958251953125 +82083 -0.06536865234375 +82084 -0.189422607421875 +82085 -0.152984619140625 +82086 -0.271942138671875 +82087 -0.216552734375 +82088 -0.342529296875 +82089 -0.270477294921875 +82090 -0.364166259765625 +82091 -0.286651611328125 +82092 -0.327239990234375 +82093 -0.257781982421875 +82094 -0.2769775390625 +82095 -0.218292236328125 +82096 -0.253692626953125 +82097 -0.19891357421875 +82098 -0.24365234375 +82099 -0.189300537109375 +82100 -0.1983642578125 +82101 -0.152740478515625 +82102 -0.116241455078125 +82103 -0.088134765625 +82104 -0.036834716796875 +82105 -0.025634765625 +82106 0.034881591796875 +82107 0.03082275390625 +82108 0.09124755859375 +82109 0.0753173828125 +82110 0.10888671875 +82111 0.089996337890625 +82112 0.125518798828125 +82113 0.10345458984375 +82114 0.15771484375 +82115 0.1282958984375 +82116 0.17828369140625 +82117 0.143829345703125 +82118 0.17108154296875 +82119 0.137786865234375 +82120 0.129974365234375 +82121 0.105560302734375 +82122 0.082427978515625 +82123 0.068084716796875 +82124 0.027679443359375 +82125 0.02490234375 +82126 -0.065643310546875 +82127 -0.0477294921875 +82128 -0.15936279296875 +82129 -0.1207275390625 +82130 -0.21307373046875 +82131 -0.16326904296875 +82132 -0.234649658203125 +82133 -0.1812744140625 +82134 -0.2001953125 +82135 -0.156463623046875 +82136 -0.119171142578125 +82137 -0.095977783203125 +82138 -0.024749755859375 +82139 -0.024993896484375 +82140 0.085784912109375 +82141 0.05859375 +82142 0.178131103515625 +82143 0.12872314453125 +82144 0.215576171875 +82145 0.157501220703125 +82146 0.211456298828125 +82147 0.154998779296875 +82148 0.17523193359375 +82149 0.128387451171875 +82150 0.128753662109375 +82151 0.094207763671875 +82152 0.1019287109375 +82153 0.07513427734375 +82154 0.0743408203125 +82155 0.05560302734375 +82156 0.04327392578125 +82157 0.033416748046875 +82158 0.038177490234375 +82159 0.030914306640625 +82160 0.076263427734375 +82161 0.06109619140625 +82162 0.14105224609375 +82163 0.11138916015625 +82164 0.186431884765625 +82165 0.14666748046875 +82166 0.188812255859375 +82167 0.148956298828125 +82168 0.1390380859375 +82169 0.111297607421875 +82170 0.041778564453125 +82171 0.0372314453125 +82172 -0.079437255859375 +82173 -0.0552978515625 +82174 -0.219390869140625 +82175 -0.162322998046875 +82176 -0.367828369140625 +82177 -0.275665283203125 +82178 -0.494873046875 +82179 -0.372161865234375 +82180 -0.556243896484375 +82181 -0.41900634765625 +82182 -0.508697509765625 +82183 -0.38494873046875 +82184 -0.3756103515625 +82185 -0.287261962890625 +82186 -0.218902587890625 +82187 -0.17132568359375 +82188 -0.063751220703125 +82189 -0.05572509765625 +82190 0.091552734375 +82191 0.060455322265625 +82192 0.23602294921875 +82193 0.168975830078125 +82194 0.342987060546875 +82195 0.25018310546875 +82196 0.39520263671875 +82197 0.29132080078125 +82198 0.389373779296875 +82199 0.289825439453125 +82200 0.324249267578125 +82201 0.244659423828125 +82202 0.224090576171875 +82203 0.173370361328125 +82204 0.124267578125 +82205 0.101654052734375 +82206 0.037078857421875 +82207 0.038421630859375 +82208 -0.010101318359375 +82209 0.003631591796875 +82210 -0.019439697265625 +82211 -0.00421142578125 +82212 -0.022796630859375 +82213 -0.008209228515625 +82214 -0.001556396484375 +82215 0.0052490234375 +82216 0.056304931640625 +82217 0.0450439453125 +82218 0.106719970703125 +82219 0.079254150390625 +82220 0.096893310546875 +82221 0.069610595703125 +82222 0.042694091796875 +82223 0.027801513671875 +82224 -0.018035888671875 +82225 -0.01849365234375 +82226 -0.07586669921875 +82227 -0.06231689453125 +82228 -0.11944580078125 +82229 -0.095306396484375 +82230 -0.15972900390625 +82231 -0.12542724609375 +82232 -0.202606201171875 +82233 -0.15692138671875 +82234 -0.24859619140625 +82235 -0.19012451171875 +82236 -0.30517578125 +82237 -0.23052978515625 +82238 -0.36212158203125 +82239 -0.270751953125 +82240 -0.39141845703125 +82241 -0.290496826171875 +82242 -0.35528564453125 +82243 -0.2623291015625 +82244 -0.249969482421875 +82245 -0.18365478515625 +82246 -0.092864990234375 +82247 -0.067230224609375 +82248 0.08905029296875 +82249 0.067169189453125 +82250 0.2352294921875 +82251 0.175384521484375 +82252 0.318817138671875 +82253 0.237762451171875 +82254 0.358642578125 +82255 0.267913818359375 +82256 0.347747802734375 +82257 0.2607421875 +82258 0.28564453125 +82259 0.215850830078125 +82260 0.223175048828125 +82261 0.170257568359375 +82262 0.196746826171875 +82263 0.15045166015625 +82264 0.179840087890625 +82265 0.137237548828125 +82266 0.155548095703125 +82267 0.118316650390625 +82268 0.151214599609375 +82269 0.11370849609375 +82270 0.156951904296875 +82271 0.116302490234375 +82272 0.13177490234375 +82273 0.0963134765625 +82274 0.100799560546875 +82275 0.0721435546875 +82276 0.087127685546875 +82277 0.060638427734375 +82278 0.05487060546875 +82279 0.035797119140625 +82280 -0.009002685546875 +82281 -0.01177978515625 +82282 -0.10400390625 +82283 -0.081695556640625 +82284 -0.229400634765625 +82285 -0.173370361328125 +82286 -0.35552978515625 +82287 -0.26519775390625 +82288 -0.441925048828125 +82289 -0.327728271484375 +82290 -0.473846435546875 +82291 -0.350311279296875 +82292 -0.464813232421875 +82293 -0.342803955078125 +82294 -0.419097900390625 +82295 -0.308349609375 +82296 -0.334320068359375 +82297 -0.245269775390625 +82298 -0.227935791015625 +82299 -0.1663818359375 +82300 -0.12347412109375 +82301 -0.088897705078125 +82302 -0.02764892578125 +82303 -0.01776123046875 +82304 0.077667236328125 +82305 0.060150146484375 +82306 0.2132568359375 +82307 0.159881591796875 +82308 0.38885498046875 +82309 0.2884521484375 +82310 0.582794189453125 +82311 0.4300537109375 +82312 0.734039306640625 +82313 0.54022216796875 +82314 0.800140380859375 +82315 0.58807373046875 +82316 0.7783203125 +82317 0.57159423828125 +82318 0.6651611328125 +82319 0.488372802734375 +82320 0.45965576171875 +82321 0.337738037109375 +82322 0.199188232421875 +82323 0.146942138671875 +82324 -0.050689697265625 +82325 -0.03619384765625 +82326 -0.23297119140625 +82327 -0.17010498046875 +82328 -0.33013916015625 +82329 -0.24200439453125 +82330 -0.368408203125 +82331 -0.2708740234375 +82332 -0.378936767578125 +82333 -0.279327392578125 +82334 -0.376983642578125 +82335 -0.278472900390625 +82336 -0.37969970703125 +82337 -0.280792236328125 +82338 -0.391510009765625 +82339 -0.28948974609375 +82340 -0.385345458984375 +82341 -0.28485107421875 +82342 -0.3419189453125 +82343 -0.252838134765625 +82344 -0.28289794921875 +82345 -0.209228515625 +82346 -0.251617431640625 +82347 -0.185638427734375 +82348 -0.266143798828125 +82349 -0.195281982421875 +82350 -0.273345947265625 +82351 -0.199554443359375 +82352 -0.216796875 +82353 -0.15740966796875 +82354 -0.128265380859375 +82355 -0.092010498046875 +82356 -0.068145751953125 +82357 -0.047393798828125 +82358 -0.0430908203125 +82359 -0.0284423828125 +82360 -0.024444580078125 +82361 -0.014312744140625 +82362 0.020721435546875 +82363 0.018951416015625 +82364 0.124481201171875 +82365 0.094635009765625 +82366 0.25787353515625 +82367 0.191650390625 +82368 0.379119873046875 +82369 0.27960205078125 +82370 0.47991943359375 +82371 0.35247802734375 +82372 0.5281982421875 +82373 0.386962890625 +82374 0.511138916015625 +82375 0.373779296875 +82376 0.456207275390625 +82377 0.332977294921875 +82378 0.407470703125 +82379 0.29669189453125 +82380 0.383758544921875 +82381 0.278656005859375 +82382 0.35687255859375 +82383 0.258392333984375 +82384 0.31182861328125 +82385 0.2249755859375 +82386 0.250885009765625 +82387 0.18011474609375 +82388 0.1654052734375 +82389 0.117523193359375 +82390 0.035247802734375 +82391 0.0225830078125 +82392 -0.142059326171875 +82393 -0.10650634765625 +82394 -0.33563232421875 +82395 -0.24725341796875 +82396 -0.5345458984375 +82397 -0.3917236328125 +82398 -0.72186279296875 +82399 -0.527587890625 +82400 -0.836669921875 +82401 -0.61053466796875 +82402 -0.8326416015625 +82403 -0.606903076171875 +82404 -0.7296142578125 +82405 -0.531158447265625 +82406 -0.582550048828125 +82407 -0.423370361328125 +82408 -0.440093994140625 +82409 -0.3189697265625 +82410 -0.324310302734375 +82411 -0.234100341796875 +82412 -0.20147705078125 +82413 -0.14422607421875 +82414 -0.044647216796875 +82415 -0.02972412109375 +82416 0.103973388671875 +82417 0.078643798828125 +82418 0.202392578125 +82419 0.150299072265625 +82420 0.264495849609375 +82421 0.195343017578125 +82422 0.338897705078125 +82423 0.249176025390625 +82424 0.443817138671875 +82425 0.3250732421875 +82426 0.545074462890625 +82427 0.398223876953125 +82428 0.6173095703125 +82429 0.4501953125 +82430 0.6524658203125 +82431 0.47515869140625 +82432 0.66339111328125 +82433 0.482147216796875 +82434 0.6561279296875 +82435 0.47540283203125 +82436 0.606781005859375 +82437 0.438232421875 +82438 0.501190185546875 +82439 0.3609619140625 +82440 0.352783203125 +82441 0.253143310546875 +82442 0.176544189453125 +82443 0.125518798828125 +82444 -0.034820556640625 +82445 -0.02667236328125 +82446 -0.258209228515625 +82447 -0.187042236328125 +82448 -0.44244384765625 +82449 -0.3197021484375 +82450 -0.5753173828125 +82451 -0.415863037109375 +82452 -0.65203857421875 +82453 -0.47198486328125 +82454 -0.641632080078125 +82455 -0.4664306640625 +82456 -0.562164306640625 +82457 -0.41168212890625 +82458 -0.458038330078125 +82459 -0.338653564453125 +82460 -0.350555419921875 +82461 -0.26220703125 +82462 -0.260528564453125 +82463 -0.19696044921875 +82464 -0.192108154296875 +82465 -0.145965576171875 +82466 -0.141937255859375 +82467 -0.107086181640625 +82468 -0.1021728515625 +82469 -0.075103759765625 +82470 -0.062896728515625 +82471 -0.0433349609375 +82472 -0.011932373046875 +82473 -0.003570556640625 +82474 0.062835693359375 +82475 0.052398681640625 +82476 0.148712158203125 +82477 0.11553955078125 +82478 0.241729736328125 +82479 0.182861328125 +82480 0.34912109375 +82481 0.259307861328125 +82482 0.457305908203125 +82483 0.33538818359375 +82484 0.54388427734375 +82485 0.395477294921875 +82486 0.5728759765625 +82487 0.41461181640625 +82488 0.506591796875 +82489 0.366607666015625 +82490 0.351226806640625 +82491 0.255889892578125 +82492 0.146514892578125 +82493 0.11029052734375 +82494 -0.05523681640625 +82495 -0.033599853515625 +82496 -0.21624755859375 +82497 -0.1492919921875 +82498 -0.334930419921875 +82499 -0.235443115234375 +82500 -0.402984619140625 +82501 -0.286102294921875 +82502 -0.4412841796875 +82503 -0.315643310546875 +82504 -0.49578857421875 +82505 -0.35589599609375 +82506 -0.5601806640625 +82507 -0.402374267578125 +82508 -0.600738525390625 +82509 -0.4315185546875 +82510 -0.584228515625 +82511 -0.420196533203125 +82512 -0.47930908203125 +82513 -0.3465576171875 +82514 -0.27935791015625 +82515 -0.206085205078125 +82516 -0.0089111328125 +82517 -0.01593017578125 +82518 0.268798828125 +82519 0.17974853515625 +82520 0.482818603515625 +82521 0.331451416015625 +82522 0.60369873046875 +82523 0.41851806640625 +82524 0.650421142578125 +82525 0.453948974609375 +82526 0.66400146484375 +82527 0.466156005859375 +82528 0.6414794921875 +82529 0.45294189453125 +82530 0.572540283203125 +82531 0.406982421875 +82532 0.498138427734375 +82533 0.356689453125 +82534 0.439453125 +82535 0.316741943359375 +82536 0.375518798828125 +82537 0.27252197265625 +82538 0.274505615234375 +82539 0.201873779296875 +82540 0.1087646484375 +82541 0.085601806640625 +82542 -0.099395751953125 +82543 -0.060699462890625 +82544 -0.3182373046875 +82545 -0.214813232421875 +82546 -0.5489501953125 +82547 -0.37750244140625 +82548 -0.7738037109375 +82549 -0.536285400390625 +82550 -0.86383056640625 +82551 -0.6541748046875 +82552 -0.870391845703125 +82553 -0.707916259765625 +82554 -0.86895751953125 +82555 -0.709716796875 +82556 -0.861053466796875 +82557 -0.6685791015625 +82558 -0.765869140625 +82559 -0.5723876953125 +82560 -0.5301513671875 +82561 -0.413238525390625 +82562 -0.214691162109375 +82563 -0.196014404296875 +82564 0.137359619140625 +82565 0.04925537109375 +82566 0.474822998046875 +82567 0.286865234375 +82568 0.76239013671875 +82569 0.492034912109375 +82570 0.867462158203125 +82571 0.64593505859375 +82572 0.870361328125 +82573 0.748748779296875 +82574 0.86480712890625 +82575 0.792327880859375 +82576 0.831817626953125 +82577 0.780303955078125 +82578 0.677581787109375 +82579 0.729522705078125 +82580 0.495880126953125 +82581 0.643951416015625 +82582 0.30767822265625 +82583 0.536376953125 +82584 0.116180419921875 +82585 0.40826416015625 +82586 -0.110748291015625 +82587 0.23748779296875 +82588 -0.381805419921875 +82589 0.019195556640625 +82590 -0.6572265625 +82591 -0.216796875 +82592 -0.857421875 +82593 -0.428802490234375 +82594 -0.870391845703125 +82595 -0.586883544921875 +82596 -0.870391845703125 +82597 -0.68603515625 +82598 -0.86444091796875 +82599 -0.744873046875 +82600 -0.85723876953125 +82601 -0.788177490234375 +82602 -0.790008544921875 +82603 -0.803070068359375 +82604 -0.62847900390625 +82605 -0.751708984375 +82606 -0.3956298828125 +82607 -0.631805419921875 +82608 -0.126708984375 +82609 -0.46612548828125 +82610 0.150115966796875 +82611 -0.273712158203125 +82612 0.424041748046875 +82613 -0.062652587890625 +82614 0.670623779296875 +82615 0.148284912109375 +82616 0.854522705078125 +82617 0.3321533203125 +82618 0.866485595703125 +82619 0.47662353515625 +82620 0.86920166015625 +82621 0.570953369140625 +82622 0.8653564453125 +82623 0.627685546875 +82624 0.857147216796875 +82625 0.65606689453125 +82626 0.766845703125 +82627 0.654022216796875 +82628 0.628509521484375 +82629 0.62506103515625 +82630 0.462127685546875 +82631 0.564422607421875 +82632 0.297210693359375 +82633 0.489990234375 +82634 0.14862060546875 +82635 0.41033935546875 +82636 -0.00537109375 +82637 0.309478759765625 +82638 -0.15753173828125 +82639 0.192626953125 +82640 -0.31304931640625 +82641 0.0572509765625 +82642 -0.48876953125 +82643 -0.10638427734375 +82644 -0.6416015625 +82645 -0.265625 +82646 -0.751373291015625 +82647 -0.4031982421875 +82648 -0.84619140625 +82649 -0.535125732421875 +82650 -0.861297607421875 +82651 -0.651092529296875 +82652 -0.863250732421875 +82653 -0.72796630859375 +82654 -0.856597900390625 +82655 -0.74371337890625 +82656 -0.7498779296875 +82657 -0.706695556640625 +82658 -0.624542236328125 +82659 -0.6571044921875 +82660 -0.47808837890625 +82661 -0.579620361328125 +82662 -0.253387451171875 +82663 -0.433502197265625 +82664 0.003692626953125 +82665 -0.250518798828125 +82666 0.2257080078125 +82667 -0.0782470703125 +82668 0.427154541015625 +82669 0.092041015625 +82670 0.643218994140625 +82671 0.2828369140625 +82672 0.855926513671875 +82673 0.487335205078125 +82674 0.870361328125 +82675 0.665191650390625 +82676 0.870361328125 +82677 0.78173828125 +82678 0.862762451171875 +82679 0.8419189453125 +82680 0.79669189453125 +82681 0.843597412109375 +82682 0.595794677734375 +82683 0.780120849609375 +82684 0.362152099609375 +82685 0.671722412109375 +82686 0.1270751953125 +82687 0.53790283203125 +82688 -0.086944580078125 +82689 0.392822265625 +82690 -0.2784423828125 +82691 0.237640380859375 +82692 -0.484832763671875 +82693 0.04962158203125 +82694 -0.729583740234375 +82695 -0.18304443359375 +82696 -0.86688232421875 +82697 -0.425933837890625 +82698 -0.870391845703125 +82699 -0.63629150390625 +82700 -0.86859130859375 +82701 -0.810211181640625 +82702 -0.86279296875 +82703 -0.864471435546875 +82704 -0.817962646484375 +82705 -0.870391845703125 +82706 -0.6116943359375 +82707 -0.866363525390625 +82708 -0.3128662109375 +82709 -0.83123779296875 +82710 0.039398193359375 +82711 -0.62786865234375 +82712 0.422821044921875 +82713 -0.367095947265625 +82714 0.805145263671875 +82715 -0.07183837890625 +82716 0.870361328125 +82717 0.21209716796875 +82718 0.870361328125 +82719 0.446380615234375 +82720 0.860015869140625 +82721 0.6229248046875 +82722 0.727935791015625 +82723 0.736541748046875 +82724 0.48114013671875 +82725 0.7835693359375 +82726 0.2059326171875 +82727 0.780364990234375 +82728 -0.06103515625 +82729 0.74237060546875 +82730 -0.29913330078125 +82731 0.676849365234375 +82732 -0.516204833984375 +82733 0.574859619140625 +82734 -0.7252197265625 +82735 0.427001953125 +82736 -0.85980224609375 +82737 0.250640869140625 +82738 -0.870391845703125 +82739 0.0694580078125 +82740 -0.870391845703125 +82741 -0.0960693359375 +82742 -0.858062744140625 +82743 -0.21282958984375 +82744 -0.673004150390625 +82745 -0.277374267578125 +82746 -0.42694091796875 +82747 -0.324005126953125 +82748 -0.2100830078125 +82749 -0.381805419921875 +82750 -0.0362548828125 +82751 -0.44915771484375 +82752 0.10943603515625 +82753 -0.50677490234375 +82754 0.23516845703125 +82755 -0.54156494140625 +82756 0.373687744140625 +82757 -0.526397705078125 +82758 0.517791748046875 +82759 -0.46307373046875 +82760 0.602783203125 +82761 -0.394073486328125 +82762 0.635711669921875 +82763 -0.316680908203125 +82764 0.655181884765625 +82765 -0.20953369140625 +82766 0.65948486328125 +82767 -0.079986572265625 +82768 0.651275634765625 +82769 0.065826416015625 +82770 0.61846923828125 +82771 0.210906982421875 +82772 0.53753662109375 +82773 0.330108642578125 +82774 0.404144287109375 +82775 0.41094970703125 +82776 0.22186279296875 +82777 0.446685791015625 +82778 0.003997802734375 +82779 0.43798828125 +82780 -0.22100830078125 +82781 0.39691162109375 +82782 -0.42449951171875 +82783 0.33734130859375 +82784 -0.579833984375 +82785 0.2738037109375 +82786 -0.641876220703125 +82787 0.235137939453125 +82788 -0.6177978515625 +82789 0.217529296875 +82790 -0.575531005859375 +82791 0.1787109375 +82792 -0.526336669921875 +82793 0.1158447265625 +82794 -0.42645263671875 +82795 0.063995361328125 +82796 -0.2581787109375 +82797 0.0419921875 +82798 -0.068695068359375 +82799 0.0262451171875 +82800 0.09222412109375 +82801 -0.008270263671875 +82802 0.232147216796875 +82803 -0.048858642578125 +82804 0.3509521484375 +82805 -0.088531494140625 +82806 0.410064697265625 +82807 -0.1468505859375 +82808 0.372955322265625 +82809 -0.243377685546875 +82810 0.2554931640625 +82811 -0.3643798828125 +82812 0.10711669921875 +82813 -0.47552490234375 +82814 -0.052886962890625 +82815 -0.564239501953125 +82816 -0.186279296875 +82817 -0.60693359375 +82818 -0.23291015625 +82819 -0.566986083984375 +82820 -0.209442138671875 +82821 -0.46002197265625 +82822 -0.174163818359375 +82823 -0.330352783203125 +82824 -0.126739501953125 +82825 -0.1839599609375 +82826 -0.048126220703125 +82827 -0.01470947265625 +82828 0.0426025390625 +82829 0.158294677734375 +82830 0.10748291015625 +82831 0.303802490234375 +82832 0.1409912109375 +82833 0.412841796875 +82834 0.19708251953125 +82835 0.5169677734375 +82836 0.273651123046875 +82837 0.611724853515625 +82838 0.31768798828125 +82839 0.660186767578125 +82840 0.341094970703125 +82841 0.669891357421875 +82842 0.368011474609375 +82843 0.657928466796875 +82844 0.37249755859375 +82845 0.609375 +82846 0.30072021484375 +82847 0.491912841796875 +82848 0.1517333984375 +82849 0.309234619140625 +82850 -0.01470947265625 +82851 0.105987548828125 +82852 -0.1883544921875 +82853 -0.10565185546875 +82854 -0.372711181640625 +82855 -0.32269287109375 +82856 -0.51397705078125 +82857 -0.504302978515625 +82858 -0.57177734375 +82859 -0.619049072265625 +82860 -0.53948974609375 +82861 -0.658721923828125 +82862 -0.43511962890625 +82863 -0.63238525390625 +82864 -0.2962646484375 +82865 -0.56317138671875 +82866 -0.161102294921875 +82867 -0.475799560546875 +82868 -0.0435791015625 +82869 -0.37994384765625 +82870 0.060394287109375 +82871 -0.274444580078125 +82872 0.13665771484375 +82873 -0.171234130859375 +82874 0.170135498046875 +82875 -0.0836181640625 +82876 0.16552734375 +82877 -0.012420654296875 +82878 0.15728759765625 +82879 0.0609130859375 +82880 0.150787353515625 +82881 0.135528564453125 +82882 0.12200927734375 +82883 0.191131591796875 +82884 0.080108642578125 +82885 0.2298583984375 +82886 0.05126953125 +82887 0.265716552734375 +82888 0.062896728515625 +82889 0.31427001953125 +82890 0.09271240234375 +82891 0.358856201171875 +82892 0.092987060546875 +82893 0.366943359375 +82894 0.07855224609375 +82895 0.348388671875 +82896 0.06427001953125 +82897 0.314056396484375 +82898 0.0347900390625 +82899 0.25555419921875 +82900 -0.01171875 +82901 0.174163818359375 +82902 -0.056060791015625 +82903 0.085723876953125 +82904 -0.055511474609375 +82905 0.0220947265625 +82906 -0.010467529296875 +82907 -0.01336669921875 +82908 0.02508544921875 +82909 -0.0528564453125 +82910 0.025665283203125 +82911 -0.109893798828125 +82912 0.017333984375 +82913 -0.164215087890625 +82914 0.00189208984375 +82915 -0.2122802734375 +82916 -0.03173828125 +82917 -0.259674072265625 +82918 -0.071502685546875 +82919 -0.29742431640625 +82920 -0.13543701171875 +82921 -0.3372802734375 +82922 -0.219970703125 +82923 -0.37738037109375 +82924 -0.300506591796875 +82925 -0.402679443359375 +82926 -0.376312255859375 +82927 -0.41455078125 +82928 -0.416107177734375 +82929 -0.394622802734375 +82930 -0.371124267578125 +82931 -0.313262939453125 +82932 -0.242279052734375 +82933 -0.174041748046875 +82934 -0.069732666015625 +82935 -0.006622314453125 +82936 0.125640869140625 +82937 0.1722412109375 +82938 0.31268310546875 +82939 0.33929443359375 +82940 0.45501708984375 +82941 0.46826171875 +82942 0.554779052734375 +82943 0.558929443359375 +82944 0.61065673828125 +82945 0.609161376953125 +82946 0.610931396484375 +82947 0.61090087890625 +82948 0.531463623046875 +82949 0.54901123046875 +82950 0.3883056640625 +82951 0.434844970703125 +82952 0.23468017578125 +82953 0.30450439453125 +82954 0.095245361328125 +82955 0.175994873046875 +82956 -0.00396728515625 +82957 0.0684814453125 +82958 -0.04852294921875 +82959 -0.006134033203125 +82960 -0.055145263671875 +82961 -0.056121826171875 +82962 -0.0758056640625 +82963 -0.11279296875 +82964 -0.138702392578125 +82965 -0.192169189453125 +82966 -0.209197998046875 +82967 -0.269775390625 +82968 -0.289031982421875 +82969 -0.345184326171875 +82970 -0.37884521484375 +82971 -0.41778564453125 +82972 -0.456329345703125 +82973 -0.47259521484375 +82974 -0.51641845703125 +82975 -0.50634765625 +82976 -0.519287109375 +82977 -0.493743896484375 +82978 -0.458251953125 +82979 -0.431488037109375 +82980 -0.384796142578125 +82981 -0.3544921875 +82982 -0.323699951171875 +82983 -0.280670166015625 +82984 -0.269287109375 +82985 -0.20831298828125 +82986 -0.1951904296875 +82987 -0.122406005859375 +82988 -0.100006103515625 +82989 -0.02410888671875 +82990 -0.01055908203125 +82991 0.067169189453125 +82992 0.1033935546875 +82993 0.16937255859375 +82994 0.24908447265625 +82995 0.28582763671875 +82996 0.373199462890625 +82997 0.380859375 +82998 0.45806884765625 +82999 0.44244384765625 +83000 0.511474609375 +83001 0.475494384765625 +83002 0.565399169921875 +83003 0.501129150390625 +83004 0.61138916015625 +83005 0.51458740234375 +83006 0.5897216796875 +83007 0.478179931640625 +83008 0.4906005859375 +83009 0.38690185546875 +83010 0.33148193359375 +83011 0.253692626953125 +83012 0.147796630859375 +83013 0.103271484375 +83014 -0.01873779296875 +83015 -0.0355224609375 +83016 -0.140289306640625 +83017 -0.1429443359375 +83018 -0.191986083984375 +83019 -0.2012939453125 +83020 -0.184295654296875 +83021 -0.216156005859375 +83022 -0.161834716796875 +83023 -0.215576171875 +83024 -0.166595458984375 +83025 -0.22625732421875 +83026 -0.19390869140625 +83027 -0.24493408203125 +83028 -0.22442626953125 +83029 -0.2591552734375 +83030 -0.279754638671875 +83031 -0.283447265625 +83032 -0.3389892578125 +83033 -0.3050537109375 +83034 -0.3543701171875 +83035 -0.294036865234375 +83036 -0.348175048828125 +83037 -0.26611328125 +83038 -0.32598876953125 +83039 -0.226287841796875 +83040 -0.2581787109375 +83041 -0.156768798828125 +83042 -0.139801025390625 +83043 -0.055694580078125 +83044 0.014617919921875 +83045 0.06622314453125 +83046 0.144378662109375 +83047 0.16839599609375 +83048 0.221038818359375 +83049 0.2314453125 +83050 0.27069091796875 +83051 0.271759033203125 +83052 0.294036865234375 +83053 0.28955078125 +83054 0.311767578125 +83055 0.298248291015625 +83056 0.339141845703125 +83057 0.30804443359375 +83058 0.360260009765625 +83059 0.3089599609375 +83060 0.360504150390625 +83061 0.292388916015625 +83062 0.308380126953125 +83063 0.239501953125 +83064 0.18170166015625 +83065 0.13751220703125 +83066 0.0047607421875 +83067 0.00311279296875 +83068 -0.17559814453125 +83069 -0.1328125 +83070 -0.3143310546875 +83071 -0.2406005859375 +83072 -0.36785888671875 +83073 -0.291656494140625 +83074 -0.36248779296875 +83075 -0.30169677734375 +83076 -0.343536376953125 +83077 -0.29876708984375 +83078 -0.3018798828125 +83079 -0.276763916015625 +83080 -0.231414794921875 +83081 -0.231689453125 +83082 -0.117645263671875 +83083 -0.154571533203125 +83084 0.007049560546875 +83085 -0.0662841796875 +83086 0.087982177734375 +83087 -0.00201416015625 +83088 0.13946533203125 +83089 0.046417236328125 +83090 0.17425537109375 +83091 0.08612060546875 +83092 0.188201904296875 +83093 0.113433837890625 +83094 0.171234130859375 +83095 0.1209716796875 +83096 0.118438720703125 +83097 0.104644775390625 +83098 0.05706787109375 +83099 0.080810546875 +83100 -0.010711669921875 +83101 0.050048828125 +83102 -0.0914306640625 +83103 0.00762939453125 +83104 -0.162322998046875 +83105 -0.0323486328125 +83106 -0.194549560546875 +83107 -0.051849365234375 +83108 -0.1492919921875 +83109 -0.026275634765625 +83110 -0.02166748046875 +83111 0.047698974609375 +83112 0.124053955078125 +83113 0.12994384765625 +83114 0.211151123046875 +83115 0.172607421875 +83116 0.240447998046875 +83117 0.176971435546875 +83118 0.242218017578125 +83119 0.1629638671875 +83120 0.2257080078125 +83121 0.1373291015625 +83122 0.194366455078125 +83123 0.103057861328125 +83124 0.115509033203125 +83125 0.040252685546875 +83126 0.0128173828125 +83127 -0.035430908203125 +83128 -0.053802490234375 +83129 -0.08563232421875 +83130 -0.110626220703125 +83131 -0.126556396484375 +83132 -0.199493408203125 +83133 -0.18450927734375 +83134 -0.29437255859375 +83135 -0.243011474609375 +83136 -0.33221435546875 +83137 -0.26239013671875 +83138 -0.27972412109375 +83139 -0.221954345703125 +83140 -0.185333251953125 +83141 -0.15277099609375 +83142 -0.128204345703125 +83143 -0.10546875 +83144 -0.115692138671875 +83145 -0.085296630859375 +83146 -0.116455078125 +83147 -0.07318115234375 +83148 -0.105926513671875 +83149 -0.0543212890625 +83150 -0.053955078125 +83151 -0.01031494140625 +83152 0.048797607421875 +83153 0.064178466796875 +83154 0.157318115234375 +83155 0.140228271484375 +83156 0.212005615234375 +83157 0.1798095703125 +83158 0.218475341796875 +83159 0.186279296875 +83160 0.23724365234375 +83161 0.197845458984375 +83162 0.30535888671875 +83163 0.238006591796875 +83164 0.38128662109375 +83165 0.28070068359375 +83166 0.404449462890625 +83167 0.287994384765625 +83168 0.3944091796875 +83169 0.272735595703125 +83170 0.3885498046875 +83171 0.25909423828125 +83172 0.362640380859375 +83173 0.232330322265625 +83174 0.27362060546875 +83175 0.165802001953125 +83176 0.11712646484375 +83177 0.05731201171875 +83178 -0.054901123046875 +83179 -0.059783935546875 +83180 -0.19085693359375 +83181 -0.152435302734375 +83182 -0.28570556640625 +83183 -0.2171630859375 +83184 -0.339263916015625 +83185 -0.253662109375 +83186 -0.3775634765625 +83187 -0.278289794921875 +83188 -0.445709228515625 +83189 -0.319610595703125 +83190 -0.535064697265625 +83191 -0.372314453125 +83192 -0.629058837890625 +83193 -0.42620849609375 +83194 -0.697601318359375 +83195 -0.46258544921875 +83196 -0.70391845703125 +83197 -0.458648681640625 +83198 -0.6424560546875 +83199 -0.411346435546875 +83200 -0.491241455078125 +83201 -0.3077392578125 +83202 -0.265716552734375 +83203 -0.158172607421875 +83204 -0.023712158203125 +83205 0.0010986328125 +83206 0.201751708984375 +83207 0.14935302734375 +83208 0.375823974609375 +83209 0.264892578125 +83210 0.485076904296875 +83211 0.339019775390625 +83212 0.56884765625 +83213 0.394866943359375 +83214 0.634765625 +83215 0.436798095703125 +83216 0.63763427734375 +83217 0.43768310546875 +83218 0.5660400390625 +83219 0.390777587890625 +83220 0.4720458984375 +83221 0.327667236328125 +83222 0.40692138671875 +83223 0.279541015625 +83224 0.3778076171875 +83225 0.25128173828125 +83226 0.376953125 +83227 0.2388916015625 +83228 0.371978759765625 +83229 0.2236328125 +83230 0.313140869140625 +83231 0.176361083984375 +83232 0.184417724609375 +83233 0.088104248046875 +83234 0.011199951171875 +83235 -0.025299072265625 +83236 -0.171051025390625 +83237 -0.142059326171875 +83238 -0.33740234375 +83239 -0.24688720703125 +83240 -0.47198486328125 +83241 -0.330047607421875 +83242 -0.560394287109375 +83243 -0.38287353515625 +83244 -0.58056640625 +83245 -0.3922119140625 +83246 -0.54754638671875 +83247 -0.367340087890625 +83248 -0.508575439453125 +83249 -0.3369140625 +83250 -0.459503173828125 +83251 -0.298919677734375 +83252 -0.394378662109375 +83253 -0.250274658203125 +83254 -0.35260009765625 +83255 -0.215118408203125 +83256 -0.31170654296875 +83257 -0.180572509765625 +83258 -0.197418212890625 +83259 -0.102630615234375 +83260 -0.007965087890625 +83261 0.019287109375 +83262 0.207489013671875 +83263 0.155242919921875 +83264 0.409210205078125 +83265 0.281097412109375 +83266 0.57208251953125 +83267 0.38153076171875 +83268 0.66595458984375 +83269 0.43841552734375 +83270 0.65875244140625 +83271 0.4324951171875 +83272 0.56744384765625 +83273 0.374114990234375 +83274 0.431396484375 +83275 0.28717041015625 +83276 0.29443359375 +83277 0.198272705078125 +83278 0.182464599609375 +83279 0.1234130859375 +83280 0.06365966796875 +83281 0.043914794921875 +83282 -0.075958251953125 +83283 -0.048126220703125 +83284 -0.189422607421875 +83285 -0.124114990234375 +83286 -0.271942138671875 +83287 -0.18072509765625 +83288 -0.342529296875 +83289 -0.22900390625 +83290 -0.364166259765625 +83291 -0.2464599609375 +83292 -0.327239990234375 +83293 -0.22711181640625 +83294 -0.2769775390625 +83295 -0.197998046875 +83296 -0.253692626953125 +83297 -0.183319091796875 +83298 -0.24365234375 +83299 -0.174896240234375 +83300 -0.1983642578125 +83301 -0.143829345703125 +83302 -0.116241455078125 +83303 -0.08941650390625 +83304 -0.036834716796875 +83305 -0.03570556640625 +83306 0.034881591796875 +83307 0.013946533203125 +83308 0.09124755859375 +83309 0.054595947265625 +83310 0.10888671875 +83311 0.071807861328125 +83312 0.125518798828125 +83313 0.087860107421875 +83314 0.15771484375 +83315 0.112396240234375 +83316 0.17828369140625 +83317 0.128814697265625 +83318 0.17108154296875 +83319 0.12725830078125 +83320 0.129974365234375 +83321 0.10394287109375 +83322 0.082427978515625 +83323 0.0753173828125 +83324 0.027679443359375 +83325 0.040985107421875 +83326 -0.065643310546875 +83327 -0.01776123046875 +83328 -0.15936279296875 +83329 -0.07781982421875 +83330 -0.21307373046875 +83331 -0.114715576171875 +83332 -0.234649658203125 +83333 -0.132904052734375 +83334 -0.2001953125 +83335 -0.11773681640625 +83336 -0.119171142578125 +83337 -0.074615478515625 +83338 -0.024749755859375 +83339 -0.023101806640625 +83340 0.085784912109375 +83341 0.038665771484375 +83342 0.178131103515625 +83343 0.090362548828125 +83344 0.215576171875 +83345 0.110137939453125 +83346 0.211456298828125 +83347 0.1060791015625 +83348 0.17523193359375 +83349 0.08392333984375 +83350 0.128753662109375 +83351 0.056793212890625 +83352 0.1019287109375 +83353 0.04254150390625 +83354 0.0743408203125 +83355 0.02880859375 +83356 0.04327392578125 +83357 0.0137939453125 +83358 0.038177490234375 +83359 0.014923095703125 +83360 0.076263427734375 +83361 0.04229736328125 +83362 0.14105224609375 +83363 0.08575439453125 +83364 0.186431884765625 +83365 0.117340087890625 +83366 0.188812255859375 +83367 0.1226806640625 +83368 0.1390380859375 +83369 0.0960693359375 +83370 0.041778564453125 +83371 0.040191650390625 +83372 -0.079437255859375 +83373 -0.030914306640625 +83374 -0.219390869140625 +83375 -0.114227294921875 +83376 -0.367828369140625 +83377 -0.20355224609375 +83378 -0.494873046875 +83379 -0.280975341796875 +83380 -0.556243896484375 +83381 -0.31982421875 +83382 -0.508697509765625 +83383 -0.29400634765625 +83384 -0.3756103515625 +83385 -0.217376708984375 +83386 -0.218902587890625 +83387 -0.126922607421875 +83388 -0.063751220703125 +83389 -0.03753662109375 +83390 0.091552734375 +83391 0.051971435546875 +83392 0.23602294921875 +83393 0.13525390625 +83394 0.342987060546875 +83395 0.19647216796875 +83396 0.39520263671875 +83397 0.225433349609375 +83398 0.389373779296875 +83399 0.22027587890625 +83400 0.324249267578125 +83401 0.180328369140625 +83402 0.224090576171875 +83403 0.120147705078125 +83404 0.124267578125 +83405 0.06097412109375 +83406 0.037078857421875 +83407 0.010101318359375 +83408 -0.010101318359375 +83409 -0.01611328125 +83410 -0.019439697265625 +83411 -0.019134521484375 +83412 -0.022796630859375 +83413 -0.018218994140625 +83414 -0.001556396484375 +83415 -0.002349853515625 +83416 0.056304931640625 +83417 0.03546142578125 +83418 0.106719970703125 +83419 0.068634033203125 +83420 0.096893310546875 +83421 0.0653076171875 +83422 0.042694091796875 +83423 0.034912109375 +83424 -0.018035888671875 +83425 0.0 +83426 -0.07586669921875 +83427 -0.033782958984375 +83428 -0.11944580078125 +83429 -0.059661865234375 +83430 -0.15972900390625 +83431 -0.084259033203125 +83432 -0.202606201171875 +83433 -0.11102294921875 +83434 -0.24859619140625 +83435 -0.140167236328125 +83436 -0.30517578125 +83437 -0.17608642578125 +83438 -0.36212158203125 +83439 -0.2125244140625 +83440 -0.39141845703125 +83441 -0.232574462890625 +83442 -0.35528564453125 +83443 -0.21337890625 +83444 -0.249969482421875 +83445 -0.152587890625 +83446 -0.092864990234375 +83447 -0.060516357421875 +83448 0.08905029296875 +83449 0.0467529296875 +83450 0.2352294921875 +83451 0.13299560546875 +83452 0.318817138671875 +83453 0.182159423828125 +83454 0.358642578125 +83455 0.20556640625 +83456 0.347747802734375 +83457 0.199676513671875 +83458 0.28564453125 +83459 0.164825439453125 +83460 0.223175048828125 +83461 0.130279541015625 +83462 0.196746826171875 +83463 0.116424560546875 +83464 0.179840087890625 +83465 0.107940673828125 +83466 0.155548095703125 +83467 0.095001220703125 +83468 0.151214599609375 +83469 0.093017578125 +83470 0.156951904296875 +83471 0.096282958984375 +83472 0.13177490234375 +83473 0.08148193359375 +83474 0.100799560546875 +83475 0.06292724609375 +83476 0.087127685546875 +83477 0.053802490234375 +83478 0.05487060546875 +83479 0.0338134765625 +83480 -0.009002685546875 +83481 -0.004302978515625 +83482 -0.10400390625 +83483 -0.06011962890625 +83484 -0.229400634765625 +83485 -0.133148193359375 +83486 -0.35552978515625 +83487 -0.2064208984375 +83488 -0.441925048828125 +83489 -0.2568359375 +83490 -0.473846435546875 +83491 -0.275970458984375 +83492 -0.464813232421875 +83493 -0.27142333984375 +83494 -0.419097900390625 +83495 -0.245574951171875 +83496 -0.334320068359375 +83497 -0.197113037109375 +83498 -0.227935791015625 +83499 -0.135955810546875 +83500 -0.12347412109375 +83501 -0.075531005859375 +83502 -0.02764892578125 +83503 -0.01971435546875 +83504 0.077667236328125 +83505 0.04168701171875 +83506 0.2132568359375 +83507 0.120361328125 +83508 0.38885498046875 +83509 0.22174072265625 +83510 0.582794189453125 +83511 0.333465576171875 +83512 0.734039306640625 +83513 0.420745849609375 +83514 0.800140380859375 +83515 0.45941162109375 +83516 0.7783203125 +83517 0.44781494140625 +83518 0.6651611328125 +83519 0.384002685546875 +83520 0.45965576171875 +83521 0.26739501953125 +83522 0.199188232421875 +83523 0.119232177734375 +83524 -0.050689697265625 +83525 -0.023223876953125 +83526 -0.23297119140625 +83527 -0.1275634765625 +83528 -0.33013916015625 +83529 -0.183807373046875 +83530 -0.368408203125 +83531 -0.20672607421875 +83532 -0.378936767578125 +83533 -0.2139892578125 +83534 -0.376983642578125 +83535 -0.21417236328125 +83536 -0.37969970703125 +83537 -0.21697998046875 +83538 -0.391510009765625 +83539 -0.224822998046875 +83540 -0.385345458984375 +83541 -0.2222900390625 +83542 -0.3419189453125 +83543 -0.1983642578125 +83544 -0.28289794921875 +83545 -0.165313720703125 +83546 -0.251617431640625 +83547 -0.147735595703125 +83548 -0.266143798828125 +83549 -0.1558837890625 +83550 -0.273345947265625 +83551 -0.15960693359375 +83552 -0.216796875 +83553 -0.12689208984375 +83554 -0.128265380859375 +83555 -0.0758056640625 +83556 -0.068145751953125 +83557 -0.04071044921875 +83558 -0.0430908203125 +83559 -0.025390625 +83560 -0.024444580078125 +83561 -0.013702392578125 +83562 0.020721435546875 +83563 0.013031005859375 +83564 0.124481201171875 +83565 0.07293701171875 +83566 0.25787353515625 +83567 0.149505615234375 +83568 0.379119873046875 +83569 0.218994140625 +83570 0.47991943359375 +83571 0.27667236328125 +83572 0.5281982421875 +83573 0.30426025390625 +83574 0.511138916015625 +83575 0.29449462890625 +83576 0.456207275390625 +83577 0.26300048828125 +83578 0.407470703125 +83579 0.234832763671875 +83580 0.383758544921875 +83581 0.220703125 +83582 0.35687255859375 +83583 0.204620361328125 +83584 0.31182861328125 +83585 0.178131103515625 +83586 0.250885009765625 +83587 0.142578125 +83588 0.1654052734375 +83589 0.093109130859375 +83590 0.035247802734375 +83591 0.018341064453125 +83592 -0.142059326171875 +83593 -0.08306884765625 +83594 -0.33563232421875 +83595 -0.193572998046875 +83596 -0.5345458984375 +83597 -0.306915283203125 +83598 -0.72186279296875 +83599 -0.413482666015625 +83600 -0.836669921875 +83601 -0.4786376953125 +83602 -0.8326416015625 +83603 -0.47607421875 +83604 -0.7296142578125 +83605 -0.4171142578125 +83606 -0.582550048828125 +83607 -0.332977294921875 +83608 -0.440093994140625 +83609 -0.2513427734375 +83610 -0.324310302734375 +83611 -0.184814453125 +83612 -0.20147705078125 +83613 -0.1142578125 +83614 -0.044647216796875 +83615 -0.0244140625 +83616 0.103973388671875 +83617 0.060699462890625 +83618 0.202392578125 +83619 0.1171875 +83620 0.264495849609375 +83621 0.152923583984375 +83622 0.338897705078125 +83623 0.195465087890625 +83624 0.443817138671875 +83625 0.25518798828125 +83626 0.545074462890625 +83627 0.312652587890625 +83628 0.6173095703125 +83629 0.35345458984375 +83630 0.6524658203125 +83631 0.373046875 +83632 0.66339111328125 +83633 0.378753662109375 +83634 0.6561279296875 +83635 0.3740234375 +83636 0.606781005859375 +83637 0.345306396484375 +83638 0.501190185546875 +83639 0.284637451171875 +83640 0.352783203125 +83641 0.199676513671875 +83642 0.176544189453125 +83643 0.09893798828125 +83644 -0.034820556640625 +83645 -0.0216064453125 +83646 -0.258209228515625 +83647 -0.148834228515625 +83648 -0.44244384765625 +83649 -0.253662109375 +83650 -0.5753173828125 +83651 -0.32916259765625 +83652 -0.65203857421875 +83653 -0.37261962890625 +83654 -0.641632080078125 +83655 -0.366455078125 +83656 -0.562164306640625 +83657 -0.320953369140625 +83658 -0.458038330078125 +83659 -0.261383056640625 +83660 -0.350555419921875 +83661 -0.1998291015625 +83662 -0.260528564453125 +83663 -0.14813232421875 +83664 -0.192108154296875 +83665 -0.10870361328125 +83666 -0.141937255859375 +83667 -0.079681396484375 +83668 -0.1021728515625 +83669 -0.056610107421875 +83670 -0.062896728515625 +83671 -0.033905029296875 +83672 -0.011932373046875 +83673 -0.004638671875 +83674 0.062835693359375 +83675 0.037994384765625 +83676 0.148712158203125 +83677 0.086822509765625 +83678 0.241729736328125 +83679 0.139556884765625 +83680 0.34912109375 +83681 0.200347900390625 +83682 0.457305908203125 +83683 0.261505126953125 +83684 0.54388427734375 +83685 0.310302734375 +83686 0.5728759765625 +83687 0.326324462890625 +83688 0.506591796875 +83689 0.2882080078125 +83690 0.351226806640625 +83691 0.199493408203125 +83692 0.146514892578125 +83693 0.082763671875 +83694 -0.05523681640625 +83695 -0.0322265625 +83696 -0.21624755859375 +83697 -0.123992919921875 +83698 -0.334930419921875 +83699 -0.191619873046875 +83700 -0.402984619140625 +83701 -0.23040771484375 +83702 -0.4412841796875 +83703 -0.252197265625 +83704 -0.49578857421875 +83705 -0.2830810546875 +83706 -0.5601806640625 +83707 -0.319488525390625 +83708 -0.600738525390625 +83709 -0.342254638671875 +83710 -0.584228515625 +83711 -0.33258056640625 +83712 -0.47930908203125 +83713 -0.27294921875 +83714 -0.27935791015625 +83715 -0.160308837890625 +83716 -0.0089111328125 +83717 -0.008758544921875 +83718 0.268798828125 +83719 0.14703369140625 +83720 0.482818603515625 +83721 0.268402099609375 +83722 0.60369873046875 +83723 0.339080810546875 +83724 0.650421142578125 +83725 0.368804931640625 +83726 0.66400146484375 +83727 0.37933349609375 +83728 0.6414794921875 +83729 0.368896484375 +83730 0.572540283203125 +83731 0.331939697265625 +83732 0.498138427734375 +83733 0.290496826171875 +83734 0.439453125 +83735 0.256072998046875 +83736 0.375518798828125 +83737 0.217681884765625 +83738 0.274505615234375 +83739 0.1585693359375 +83740 0.1087646484375 +83741 0.064208984375 +83742 -0.099395751953125 +83743 -0.0531005859375 +83744 -0.3182373046875 +83745 -0.175994873046875 +83746 -0.5489501953125 +83747 -0.3048095703125 +83748 -0.7738037109375 +83749 -0.429718017578125 +83750 -0.86383056640625 +83751 -0.52215576171875 +83752 -0.870391845703125 +83753 -0.5640869140625 +83754 -0.86895751953125 +83755 -0.56494140625 +83756 -0.861053466796875 +83757 -0.53173828125 +83758 -0.765869140625 +83759 -0.45526123046875 +83760 -0.5301513671875 +83761 -0.329559326171875 +83762 -0.214691162109375 +83763 -0.15863037109375 +83764 0.137359619140625 +83765 0.034210205078125 +83766 0.474822998046875 +83767 0.22125244140625 +83768 0.76239013671875 +83769 0.3831787109375 +83770 0.867462158203125 +83771 0.505279541015625 +83772 0.870361328125 +83773 0.5875244140625 +83774 0.86480712890625 +83775 0.62347412109375 +83776 0.831817626953125 +83777 0.615814208984375 +83778 0.677581787109375 +83779 0.57745361328125 +83780 0.495880126953125 +83781 0.51141357421875 +83782 0.30767822265625 +83783 0.4276123046875 +83784 0.116180419921875 +83785 0.327239990234375 +83786 -0.110748291015625 +83787 0.193389892578125 +83788 -0.381805419921875 +83789 0.022430419921875 +83790 -0.6572265625 +83791 -0.1624755859375 +83792 -0.857421875 +83793 -0.329071044921875 +83794 -0.870391845703125 +83795 -0.4541015625 +83796 -0.870391845703125 +83797 -0.53350830078125 +83798 -0.86444091796875 +83799 -0.581512451171875 +83800 -0.85723876953125 +83801 -0.6170654296875 +83802 -0.790008544921875 +83803 -0.630126953125 +83804 -0.62847900390625 +83805 -0.59149169921875 +83806 -0.3956298828125 +83807 -0.499359130859375 +83808 -0.126708984375 +83809 -0.37127685546875 +83810 0.150115966796875 +83811 -0.221923828125 +83812 0.424041748046875 +83813 -0.057647705078125 +83814 0.670623779296875 +83815 0.10699462890625 +83816 0.854522705078125 +83817 0.2510986328125 +83818 0.866485595703125 +83819 0.365020751953125 +83820 0.86920166015625 +83821 0.440338134765625 +83822 0.8653564453125 +83823 0.486572265625 +83824 0.857147216796875 +83825 0.5107421875 +83826 0.766845703125 +83827 0.511138916015625 +83828 0.628509521484375 +83829 0.490325927734375 +83830 0.462127685546875 +83831 0.444580078125 +83832 0.297210693359375 +83833 0.38763427734375 +83834 0.14862060546875 +83835 0.3260498046875 +83836 -0.00537109375 +83837 0.247589111328125 +83838 -0.15753173828125 +83839 0.15631103515625 +83840 -0.31304931640625 +83841 0.050384521484375 +83842 -0.48876953125 +83843 -0.077606201171875 +83844 -0.6416015625 +83845 -0.202362060546875 +83846 -0.751373291015625 +83847 -0.31048583984375 +83848 -0.84619140625 +83849 -0.4141845703125 +83850 -0.861297607421875 +83851 -0.50543212890625 +83852 -0.863250732421875 +83853 -0.566314697265625 +83854 -0.856597900390625 +83855 -0.5797119140625 +83856 -0.7498779296875 +83857 -0.55206298828125 +83858 -0.624542236328125 +83859 -0.5142822265625 +83860 -0.47808837890625 +83861 -0.45452880859375 +83862 -0.253387451171875 +83863 -0.341461181640625 +83864 0.003692626953125 +83865 -0.1995849609375 +83866 0.2257080078125 +83867 -0.06561279296875 +83868 0.427154541015625 +83869 0.06707763671875 +83870 0.643218994140625 +83871 0.2156982421875 +83872 0.855926513671875 +83873 0.374969482421875 +83874 0.870361328125 +83875 0.513641357421875 +83876 0.870361328125 +83877 0.60498046875 +83878 0.862762451171875 +83879 0.652679443359375 +83880 0.79669189453125 +83881 0.655029296875 +83882 0.595794677734375 +83883 0.606903076171875 +83884 0.362152099609375 +83885 0.523834228515625 +83886 0.1270751953125 +83887 0.42083740234375 +83888 -0.086944580078125 +83889 0.30926513671875 +83890 -0.2784423828125 +83891 0.19024658203125 +83892 -0.484832763671875 +83893 0.045196533203125 +83894 -0.729583740234375 +83895 -0.13604736328125 +83896 -0.86688232421875 +83897 -0.32623291015625 +83898 -0.870391845703125 +83899 -0.49127197265625 +83900 -0.86859130859375 +83901 -0.628326416015625 +83902 -0.86279296875 +83903 -0.736114501953125 +83904 -0.817962646484375 +83905 -0.795196533203125 +83906 -0.6116943359375 +83907 -0.781097412109375 +83908 -0.3128662109375 +83909 -0.689910888671875 +83910 0.039398193359375 +83911 -0.539581298828125 +83912 0.422821044921875 +83913 -0.340850830078125 +83914 0.805145263671875 +83915 -0.111572265625 +83916 0.870361328125 +83917 0.111663818359375 +83918 0.870361328125 +83919 0.298187255859375 +83920 0.860015869140625 +83921 0.441558837890625 +83922 0.727935791015625 +83923 0.53741455078125 +83924 0.48114013671875 +83925 0.58251953125 +83926 0.2059326171875 +83927 0.589599609375 +83928 -0.06103515625 +83929 0.570526123046875 +83930 -0.29913330078125 +83931 0.53045654296875 +83932 -0.516204833984375 +83933 0.461456298828125 +83934 -0.7252197265625 +83935 0.35516357421875 +83936 -0.85980224609375 +83937 0.22491455078125 +83938 -0.870391845703125 +83939 0.08917236328125 +83940 -0.870391845703125 +83941 -0.0360107421875 +83942 -0.858062744140625 +83943 -0.12432861328125 +83944 -0.673004150390625 +83945 -0.1732177734375 +83946 -0.42694091796875 +83947 -0.21051025390625 +83948 -0.2100830078125 +83949 -0.259613037109375 +83950 -0.0362548828125 +83951 -0.319000244140625 +83952 0.10943603515625 +83953 -0.37274169921875 +83954 0.23516845703125 +83955 -0.40985107421875 +83956 0.373687744140625 +83957 -0.407867431640625 +83958 0.517791748046875 +83959 -0.367645263671875 +83960 0.602783203125 +83961 -0.322845458984375 +83962 0.635711669921875 +83963 -0.27069091796875 +83964 0.655181884765625 +83965 -0.193389892578125 +83966 0.65948486328125 +83967 -0.096435546875 +83968 0.651275634765625 +83969 0.01531982421875 +83970 0.61846923828125 +83971 0.128448486328125 +83972 0.53753662109375 +83973 0.22332763671875 +83974 0.404144287109375 +83975 0.290252685546875 +83976 0.22186279296875 +83977 0.32379150390625 +83978 0.003997802734375 +83979 0.324127197265625 +83980 -0.22100830078125 +83981 0.300018310546875 +83982 -0.42449951171875 +83983 0.261688232421875 +83984 -0.579833984375 +83985 0.219818115234375 +83986 -0.641876220703125 +83987 0.19598388671875 +83988 -0.6177978515625 +83989 0.186981201171875 +83990 -0.575531005859375 +83991 0.16058349609375 +83992 -0.526336669921875 +83993 0.114471435546875 +83994 -0.42645263671875 +83995 0.075225830078125 +83996 -0.2581787109375 +83997 0.057220458984375 +83998 -0.068695068359375 +83999 0.042633056640625 +84000 0.09222412109375 +84001 0.012603759765625 +84002 0.232147216796875 +84003 -0.022918701171875 +84004 0.3509521484375 +84005 -0.058380126953125 +84006 0.410064697265625 +84007 -0.10833740234375 +84008 0.372955322265625 +84009 -0.187286376953125 +84010 0.2554931640625 +84011 -0.28448486328125 +84012 0.10711669921875 +84013 -0.37359619140625 +84014 -0.052886962890625 +84015 -0.44482421875 +84016 -0.186279296875 +84017 -0.4801025390625 +84018 -0.23291015625 +84019 -0.451507568359375 +84020 -0.209442138671875 +84021 -0.370849609375 +84022 -0.174163818359375 +84023 -0.271728515625 +84024 -0.126739501953125 +84025 -0.1588134765625 +84026 -0.048126220703125 +84027 -0.027557373046875 +84028 0.0426025390625 +84029 0.107330322265625 +84030 0.10748291015625 +84031 0.221954345703125 +84032 0.1409912109375 +84033 0.30926513671875 +84034 0.19708251953125 +84035 0.3929443359375 +84036 0.273651123046875 +84037 0.4693603515625 +84038 0.31768798828125 +84039 0.510223388671875 +84040 0.341094970703125 +84041 0.52105712890625 +84042 0.368011474609375 +84043 0.5146484375 +84044 0.37249755859375 +84045 0.47955322265625 +84046 0.30072021484375 +84047 0.39117431640625 +84048 0.1517333984375 +84049 0.252288818359375 +84050 -0.01470947265625 +84051 0.096832275390625 +84052 -0.1883544921875 +84053 -0.06585693359375 +84054 -0.372711181640625 +84055 -0.233367919921875 +84056 -0.51397705078125 +84057 -0.374542236328125 +84058 -0.57177734375 +84059 -0.46533203125 +84060 -0.53948974609375 +84061 -0.499267578125 +84062 -0.43511962890625 +84063 -0.483001708984375 +84064 -0.2962646484375 +84065 -0.433929443359375 +84066 -0.161102294921875 +84067 -0.37060546875 +84068 -0.0435791015625 +84069 -0.30023193359375 +84070 0.060394287109375 +84071 -0.2218017578125 +84072 0.13665771484375 +84073 -0.144317626953125 +84074 0.170135498046875 +84075 -0.077880859375 +84076 0.16552734375 +84077 -0.0230712890625 +84078 0.15728759765625 +84079 0.0340576171875 +84080 0.150787353515625 +84081 0.0927734375 +84082 0.12200927734375 +84083 0.1375732421875 +84084 0.080108642578125 +84085 0.169891357421875 +84086 0.05126953125 +84087 0.200164794921875 +84088 0.062896728515625 +84089 0.240081787109375 +84090 0.09271240234375 +84091 0.276824951171875 +84092 0.092987060546875 +84093 0.2855224609375 +84094 0.07855224609375 +84095 0.273529052734375 +84096 0.06427001953125 +84097 0.248992919921875 +84098 0.0347900390625 +84099 0.205474853515625 +84100 -0.01171875 +84101 0.143951416015625 +84102 -0.056060791015625 +84103 0.076446533203125 +84104 -0.055511474609375 +84105 0.02716064453125 +84106 -0.010467529296875 +84107 -0.00128173828125 +84108 0.02508544921875 +84109 -0.033233642578125 +84110 0.025665283203125 +84111 -0.078826904296875 +84112 0.017333984375 +84113 -0.12255859375 +84114 0.00189208984375 +84115 -0.16156005859375 +84116 -0.03173828125 +84117 -0.199951171875 +84118 -0.071502685546875 +84119 -0.230804443359375 +84120 -0.13543701171875 +84121 -0.26287841796875 +84122 -0.219970703125 +84123 -0.294708251953125 +84124 -0.300506591796875 +84125 -0.314788818359375 +84126 -0.376312255859375 +84127 -0.32415771484375 +84128 -0.416107177734375 +84129 -0.308837890625 +84130 -0.371124267578125 +84131 -0.24639892578125 +84132 -0.242279052734375 +84133 -0.139556884765625 +84134 -0.069732666015625 +84135 -0.01092529296875 +84136 0.125640869140625 +84137 0.126678466796875 +84138 0.31268310546875 +84139 0.2554931640625 +84140 0.45501708984375 +84141 0.355438232421875 +84142 0.554779052734375 +84143 0.426239013671875 +84144 0.61065673828125 +84145 0.466339111328125 +84146 0.610931396484375 +84147 0.46942138671875 +84148 0.531463623046875 +84149 0.423431396484375 +84150 0.3883056640625 +84151 0.3370361328125 +84152 0.23468017578125 +84153 0.238067626953125 +84154 0.095245361328125 +84155 0.140350341796875 +84156 -0.00396728515625 +84157 0.058685302734375 +84158 -0.04852294921875 +84159 0.00213623046875 +84160 -0.055145263671875 +84161 -0.035736083984375 +84162 -0.0758056640625 +84163 -0.079254150390625 +84164 -0.138702392578125 +84165 -0.140869140625 +84166 -0.209197998046875 +84167 -0.2015380859375 +84168 -0.289031982421875 +84169 -0.26092529296875 +84170 -0.37884521484375 +84171 -0.318511962890625 +84172 -0.456329345703125 +84173 -0.362548828125 +84174 -0.51641845703125 +84175 -0.39044189453125 +84176 -0.519287109375 +84177 -0.3824462890625 +84178 -0.458251953125 +84179 -0.335906982421875 +84180 -0.384796142578125 +84181 -0.27783203125 +84182 -0.323699951171875 +84183 -0.22198486328125 +84184 -0.269287109375 +84185 -0.166961669921875 +84186 -0.1951904296875 +84187 -0.101104736328125 +84188 -0.100006103515625 +84189 -0.0252685546875 +84190 -0.01055908203125 +84191 0.045501708984375 +84192 0.1033935546875 +84193 0.1251220703125 +84194 0.24908447265625 +84195 0.216094970703125 +84196 0.373199462890625 +84197 0.290740966796875 +84198 0.45806884765625 +84199 0.33966064453125 +84200 0.511474609375 +84201 0.366607666015625 +84202 0.565399169921875 +84203 0.387908935546875 +84204 0.61138916015625 +84205 0.3997802734375 +84206 0.5897216796875 +84207 0.372894287109375 +84208 0.4906005859375 +84209 0.30328369140625 +84210 0.33148193359375 +84211 0.200958251953125 +84212 0.147796630859375 +84213 0.08502197265625 +84214 -0.01873779296875 +84215 -0.02215576171875 +84216 -0.140289306640625 +84217 -0.10528564453125 +84218 -0.191986083984375 +84219 -0.150665283203125 +84220 -0.184295654296875 +84221 -0.162628173828125 +84222 -0.161834716796875 +84223 -0.16290283203125 +84224 -0.166595458984375 +84225 -0.172088623046875 +84226 -0.19390869140625 +84227 -0.187591552734375 +84228 -0.22442626953125 +84229 -0.199737548828125 +84230 -0.279754638671875 +84231 -0.219635009765625 +84232 -0.3389892578125 +84233 -0.23736572265625 +84234 -0.3543701171875 +84235 -0.22979736328125 +84236 -0.348175048828125 +84237 -0.208984375 +84238 -0.32598876953125 +84239 -0.17877197265625 +84240 -0.2581787109375 +84241 -0.125457763671875 +84242 -0.139801025390625 +84243 -0.047607421875 +84244 0.014617919921875 +84245 0.046539306640625 +84246 0.144378662109375 +84247 0.125701904296875 +84248 0.221038818359375 +84249 0.17498779296875 +84250 0.27069091796875 +84251 0.206939697265625 +84252 0.294036865234375 +84253 0.221649169921875 +84254 0.311767578125 +84255 0.229400634765625 +84256 0.339141845703125 +84257 0.2379150390625 +84258 0.360260009765625 +84259 0.239288330078125 +84260 0.360504150390625 +84261 0.226898193359375 +84262 0.308380126953125 +84263 0.186798095703125 +84264 0.18170166015625 +84265 0.10955810546875 +84266 0.0047607421875 +84267 0.00775146484375 +84268 -0.17559814453125 +84269 -0.095458984375 +84270 -0.3143310546875 +84271 -0.17779541015625 +84272 -0.36785888671875 +84273 -0.2177734375 +84274 -0.36248779296875 +84275 -0.227081298828125 +84276 -0.343536376953125 +84277 -0.226531982421875 +84278 -0.3018798828125 +84279 -0.211456298828125 +84280 -0.231414794921875 +84281 -0.178863525390625 +84282 -0.117645263671875 +84283 -0.1219482421875 +84284 0.007049560546875 +84285 -0.056304931640625 +84286 0.087982177734375 +84287 -0.00823974609375 +84288 0.13946533203125 +84289 0.028350830078125 +84290 0.17425537109375 +84291 0.05877685546875 +84292 0.188201904296875 +84293 0.08026123046875 +84294 0.171234130859375 +84295 0.087188720703125 +84296 0.118438720703125 +84297 0.076446533203125 +84298 0.05706787109375 +84299 0.06011962890625 +84300 -0.010711669921875 +84301 0.03857421875 +84302 -0.0914306640625 +84303 0.008209228515625 +84304 -0.162322998046875 +84305 -0.0205078125 +84306 -0.194549560546875 +84307 -0.0341796875 +84308 -0.1492919921875 +84309 -0.01446533203125 +84310 -0.02166748046875 +84311 0.041107177734375 +84312 0.124053955078125 +84313 0.102569580078125 +84314 0.211151123046875 +84315 0.1341552734375 +84316 0.240447998046875 +84317 0.1368408203125 +84318 0.242218017578125 +84319 0.12554931640625 +84320 0.2257080078125 +84321 0.10540771484375 +84322 0.194366455078125 +84323 0.07867431640625 +84324 0.115509033203125 +84325 0.030548095703125 +84326 0.0128173828125 +84327 -0.02716064453125 +84328 -0.053802490234375 +84329 -0.06573486328125 +84330 -0.110626220703125 +84331 -0.09722900390625 +84332 -0.199493408203125 +84333 -0.1412353515625 +84334 -0.29437255859375 +84335 -0.185455322265625 +84336 -0.33221435546875 +84337 -0.2001953125 +84338 -0.27972412109375 +84339 -0.170013427734375 +84340 -0.185333251953125 +84341 -0.118133544921875 +84342 -0.128204345703125 +84343 -0.082366943359375 +84344 -0.115692138671875 +84345 -0.066680908203125 +84346 -0.116455078125 +84347 -0.056854248046875 +84348 -0.105926513671875 +84349 -0.0418701171875 +84350 -0.053955078125 +84351 -0.008056640625 +84352 0.048797607421875 +84353 0.048492431640625 +84354 0.157318115234375 +84355 0.10614013671875 +84356 0.212005615234375 +84357 0.136474609375 +84358 0.218475341796875 +84359 0.14190673828125 +84360 0.23724365234375 +84361 0.150970458984375 +84362 0.30535888671875 +84363 0.18121337890625 +84364 0.38128662109375 +84365 0.213165283203125 +84366 0.404449462890625 +84367 0.218475341796875 +84368 0.3944091796875 +84369 0.206756591796875 +84370 0.3885498046875 +84371 0.196075439453125 +84372 0.362640380859375 +84373 0.175445556640625 +84374 0.27362060546875 +84375 0.12506103515625 +84376 0.11712646484375 +84377 0.043304443359375 +84378 -0.054901123046875 +84379 -0.04486083984375 +84380 -0.19085693359375 +84381 -0.114715576171875 +84382 -0.28570556640625 +84383 -0.16363525390625 +84384 -0.339263916015625 +84385 -0.191375732421875 +84386 -0.3775634765625 +84387 -0.210113525390625 +84388 -0.445709228515625 +84389 -0.24114990234375 +84390 -0.535064697265625 +84391 -0.280548095703125 +84392 -0.629058837890625 +84393 -0.3206787109375 +84394 -0.697601318359375 +84395 -0.34759521484375 +84396 -0.70391845703125 +84397 -0.344268798828125 +84398 -0.6424560546875 +84399 -0.3084716796875 +84400 -0.491241455078125 +84401 -0.230194091796875 +84402 -0.265716552734375 +84403 -0.11712646484375 +84404 -0.023712158203125 +84405 0.0030517578125 +84406 0.201751708984375 +84407 0.114471435546875 +84408 0.375823974609375 +84409 0.200439453125 +84410 0.485076904296875 +84411 0.25445556640625 +84412 0.56884765625 +84413 0.29498291015625 +84414 0.634765625 +84415 0.32562255859375 +84416 0.63763427734375 +84417 0.325103759765625 +84418 0.5660400390625 +84419 0.288177490234375 +84420 0.4720458984375 +84421 0.239593505859375 +84422 0.40692138671875 +84423 0.203826904296875 +84424 0.3778076171875 +84425 0.1845703125 +84426 0.376953125 +84427 0.178466796875 +84428 0.371978759765625 +84429 0.170562744140625 +84430 0.313140869140625 +84431 0.137664794921875 +84432 0.184417724609375 +84433 0.072479248046875 +84434 0.011199951171875 +84435 -0.01275634765625 +84436 -0.171051025390625 +84437 -0.10113525390625 +84438 -0.33740234375 +84439 -0.180816650390625 +84440 -0.47198486328125 +84441 -0.244293212890625 +84442 -0.560394287109375 +84443 -0.2847900390625 +84444 -0.58056640625 +84445 -0.2919921875 +84446 -0.54754638671875 +84447 -0.273162841796875 +84448 -0.508575439453125 +84449 -0.250823974609375 +84450 -0.459503173828125 +84451 -0.223236083984375 +84452 -0.394378662109375 +84453 -0.1878662109375 +84454 -0.35260009765625 +84455 -0.163543701171875 +84456 -0.31170654296875 +84457 -0.139892578125 +84458 -0.197418212890625 +84459 -0.08209228515625 +84460 -0.007965087890625 +84461 0.010467529296875 +84462 0.207489013671875 +84463 0.114410400390625 +84464 0.409210205078125 +84465 0.21087646484375 +84466 0.57208251953125 +84467 0.287994384765625 +84468 0.66595458984375 +84469 0.331573486328125 +84470 0.65875244140625 +84471 0.326507568359375 +84472 0.56744384765625 +84473 0.28094482421875 +84474 0.431396484375 +84475 0.213623046875 +84476 0.29443359375 +84477 0.1453857421875 +84478 0.182464599609375 +84479 0.088714599609375 +84480 0.06365966796875 +84481 0.029266357421875 +84482 -0.075958251953125 +84483 -0.039276123046875 +84484 -0.189422607421875 +84485 -0.095916748046875 +84486 -0.271942138671875 +84487 -0.138092041015625 +84488 -0.342529296875 +84489 -0.173797607421875 +84490 -0.364166259765625 +84491 -0.186553955078125 +84492 -0.327239990234375 +84493 -0.171966552734375 +84494 -0.2769775390625 +84495 -0.149871826171875 +84496 -0.253692626953125 +84497 -0.1380615234375 +84498 -0.24365234375 +84499 -0.130615234375 +84500 -0.1983642578125 +84501 -0.106414794921875 +84502 -0.116241455078125 +84503 -0.065032958984375 +84504 -0.036834716796875 +84505 -0.024169921875 +84506 0.034881591796875 +84507 0.013580322265625 +84508 0.09124755859375 +84509 0.044525146484375 +84510 0.10888671875 +84511 0.05804443359375 +84512 0.125518798828125 +84513 0.070404052734375 +84514 0.15771484375 +84515 0.088623046875 +84516 0.17828369140625 +84517 0.100555419921875 +84518 0.17108154296875 +84519 0.09893798828125 +84520 0.129974365234375 +84521 0.081085205078125 +84522 0.082427978515625 +84523 0.05908203125 +84524 0.027679443359375 +84525 0.03271484375 +84526 -0.065643310546875 +84527 -0.01165771484375 +84528 -0.15936279296875 +84529 -0.057037353515625 +84530 -0.21307373046875 +84531 -0.08538818359375 +84532 -0.234649658203125 +84533 -0.09991455078125 +84534 -0.2001953125 +84535 -0.08978271484375 +84536 -0.119171142578125 +84537 -0.05889892578125 +84538 -0.024749755859375 +84539 -0.021636962890625 +84540 0.085784912109375 +84541 0.023406982421875 +84542 0.178131103515625 +84543 0.061309814453125 +84544 0.215576171875 +84545 0.0760498046875 +84546 0.211456298828125 +84547 0.07354736328125 +84548 0.17523193359375 +84549 0.058013916015625 +84550 0.128753662109375 +84551 0.03900146484375 +84552 0.1019287109375 +84553 0.029571533203125 +84554 0.0743408203125 +84555 0.02056884765625 +84556 0.04327392578125 +84557 0.0106201171875 +84558 0.038177490234375 +84559 0.012451171875 +84560 0.076263427734375 +84561 0.03338623046875 +84562 0.14105224609375 +84563 0.065948486328125 +84564 0.186431884765625 +84565 0.08966064453125 +84566 0.188812255859375 +84567 0.09393310546875 +84568 0.1390380859375 +84569 0.074554443359375 +84570 0.041778564453125 +84571 0.033477783203125 +84572 -0.079437255859375 +84573 -0.01898193359375 +84574 -0.219390869140625 +84575 -0.08056640625 +84576 -0.367828369140625 +84577 -0.146728515625 +84578 -0.494873046875 +84579 -0.204254150390625 +84580 -0.556243896484375 +84581 -0.233551025390625 +84582 -0.508697509765625 +84583 -0.2154541015625 +84584 -0.3756103515625 +84585 -0.16009521484375 +84586 -0.218902587890625 +84587 -0.094512939453125 +84588 -0.063751220703125 +84589 -0.02960205078125 +84590 0.091552734375 +84591 0.0355224609375 +84592 0.23602294921875 +84593 0.096221923828125 +84594 0.342987060546875 +84595 0.140899658203125 +84596 0.39520263671875 +84597 0.162109375 +84598 0.389373779296875 +84599 0.158477783203125 +84600 0.324249267578125 +84601 0.129486083984375 +84602 0.224090576171875 +84603 0.0858154296875 +84604 0.124267578125 +84605 0.042999267578125 +84606 0.037078857421875 +84607 0.00634765625 +84608 -0.010101318359375 +84609 -0.012176513671875 +84610 -0.019439697265625 +84611 -0.013702392578125 +84612 -0.022796630859375 +84613 -0.012359619140625 +84614 -0.001556396484375 +84615 -0.0001220703125 +84616 0.056304931640625 +84617 0.028076171875 +84618 0.106719970703125 +84619 0.052703857421875 +84620 0.096893310546875 +84621 0.050445556640625 +84622 0.042694091796875 +84623 0.028167724609375 +84624 -0.018035888671875 +84625 0.00244140625 +84626 -0.07586669921875 +84627 -0.0225830078125 +84628 -0.11944580078125 +84629 -0.04193115234375 +84630 -0.15972900390625 +84631 -0.060394287109375 +84632 -0.202606201171875 +84633 -0.08050537109375 +84634 -0.24859619140625 +84635 -0.102386474609375 +84636 -0.30517578125 +84637 -0.12921142578125 +84638 -0.36212158203125 +84639 -0.1563720703125 +84640 -0.39141845703125 +84641 -0.171478271484375 +84642 -0.35528564453125 +84643 -0.157745361328125 +84644 -0.249969482421875 +84645 -0.1134033203125 +84646 -0.092864990234375 +84647 -0.0460205078125 +84648 0.08905029296875 +84649 0.0325927734375 +84650 0.2352294921875 +84651 0.095855712890625 +84652 0.318817138671875 +84653 0.13201904296875 +84654 0.358642578125 +84655 0.149383544921875 +84656 0.347747802734375 +84657 0.1448974609375 +84658 0.28564453125 +84659 0.118316650390625 +84660 0.223175048828125 +84661 0.091949462890625 +84662 0.196746826171875 +84663 0.08172607421875 +84664 0.179840087890625 +84665 0.075927734375 +84666 0.155548095703125 +84667 0.0670166015625 +84668 0.151214599609375 +84669 0.06689453125 +84670 0.156951904296875 +84671 0.071136474609375 +84672 0.13177490234375 +84673 0.06158447265625 +84674 0.100799560546875 +84675 0.04925537109375 +84676 0.087127685546875 +84677 0.04425048828125 +84678 0.05487060546875 +84679 0.030731201171875 +84680 -0.009002685546875 +84681 0.002899169921875 +84682 -0.10400390625 +84683 -0.03900146484375 +84684 -0.229400634765625 +84685 -0.094635009765625 +84686 -0.35552978515625 +84687 -0.15087890625 +84688 -0.441925048828125 +84689 -0.18988037109375 +84690 -0.473846435546875 +84691 -0.20513916015625 +84692 -0.464813232421875 +84693 -0.2025146484375 +84694 -0.419097900390625 +84695 -0.18377685546875 +84696 -0.334320068359375 +84697 -0.1478271484375 +84698 -0.227935791015625 +84699 -0.102264404296875 +84700 -0.12347412109375 +84701 -0.057373046875 +84702 -0.02764892578125 +84703 -0.01605224609375 +84704 0.077667236328125 +84705 0.0296630859375 +84706 0.2132568359375 +84707 0.0889892578125 +84708 0.38885498046875 +84709 0.166168212890625 +84710 0.582794189453125 +84711 0.251678466796875 +84712 0.734039306640625 +84713 0.31866455078125 +84714 0.800140380859375 +84715 0.348388671875 +84716 0.7783203125 +84717 0.339599609375 +84718 0.6651611328125 +84719 0.290740966796875 +84720 0.45965576171875 +84721 0.201324462890625 +84722 0.199188232421875 +84723 0.0877685546875 +84724 -0.050689697265625 +84725 -0.021148681640625 +84726 -0.23297119140625 +84727 -0.100372314453125 +84728 -0.33013916015625 +84729 -0.14227294921875 +84730 -0.368408203125 +84731 -0.158416748046875 +84732 -0.378936767578125 +84733 -0.162567138671875 +84734 -0.376983642578125 +84735 -0.161468505859375 +84736 -0.37969970703125 +84737 -0.16259765625 +84738 -0.391510009765625 +84739 -0.167877197265625 +84740 -0.385345458984375 +84741 -0.165985107421875 +84742 -0.3419189453125 +84743 -0.1488037109375 +84744 -0.28289794921875 +84745 -0.124969482421875 +84746 -0.251617431640625 +84747 -0.112030029296875 +84748 -0.266143798828125 +84749 -0.117279052734375 +84750 -0.273345947265625 +84751 -0.119049072265625 +84752 -0.216796875 +84753 -0.0943603515625 +84754 -0.128265380859375 +84755 -0.05621337890625 +84756 -0.068145751953125 +84757 -0.02935791015625 +84758 -0.0430908203125 +84759 -0.01666259765625 +84760 -0.024444580078125 +84761 -0.006591796875 +84762 0.020721435546875 +84763 0.01409912109375 +84764 0.124481201171875 +84765 0.058380126953125 +84766 0.25787353515625 +84767 0.11431884765625 +84768 0.379119873046875 +84769 0.164764404296875 +84770 0.47991943359375 +84771 0.206329345703125 +84772 0.5281982421875 +84773 0.225860595703125 +84774 0.511138916015625 +84775 0.218170166015625 +84776 0.456207275390625 +84777 0.19451904296875 +84778 0.407470703125 +84779 0.173004150390625 +84780 0.383758544921875 +84781 0.161376953125 +84782 0.35687255859375 +84783 0.148223876953125 +84784 0.31182861328125 +84785 0.1275634765625 +84786 0.250885009765625 +84787 0.1004638671875 +84788 0.1654052734375 +84789 0.063507080078125 +84790 0.035247802734375 +84791 0.00860595703125 +84792 -0.142059326171875 +84793 -0.065155029296875 +84794 -0.33563232421875 +84795 -0.14508056640625 +84796 -0.5345458984375 +84797 -0.2266845703125 +84798 -0.72186279296875 +84799 -0.30303955078125 +84800 -0.836669921875 +84801 -0.34930419921875 +84802 -0.8326416015625 +84803 -0.34661865234375 +84804 -0.7296142578125 +84805 -0.303192138671875 +84806 -0.582550048828125 +84807 -0.241546630859375 +84808 -0.440093994140625 +84809 -0.18157958984375 +84810 -0.324310302734375 +84811 -0.132415771484375 +84812 -0.20147705078125 +84813 -0.080413818359375 +84814 -0.044647216796875 +84815 -0.014678955078125 +84816 0.103973388671875 +84817 0.0474853515625 +84818 0.202392578125 +84819 0.088836669921875 +84820 0.264495849609375 +84821 0.114990234375 +84822 0.338897705078125 +84823 0.145751953125 +84824 0.443817138671875 +84825 0.18853759765625 +84826 0.545074462890625 +84827 0.22943115234375 +84828 0.6173095703125 +84829 0.258087158203125 +84830 0.6524658203125 +84831 0.27130126953125 +84832 0.66339111328125 +84833 0.274383544921875 +84834 0.6561279296875 +84835 0.269866943359375 +84836 0.606781005859375 +84837 0.24810791015625 +84838 0.501190185546875 +84839 0.203399658203125 +84840 0.352783203125 +84841 0.141326904296875 +84842 0.176544189453125 +84843 0.068084716796875 +84844 -0.034820556640625 +84845 -0.01922607421875 +84846 -0.258209228515625 +84847 -0.111114501953125 +84848 -0.44244384765625 +84849 -0.1866455078125 +84850 -0.5753173828125 +84851 -0.2408447265625 +84852 -0.65203857421875 +84853 -0.27178955078125 +84854 -0.641632080078125 +84855 -0.266845703125 +84856 -0.562164306640625 +84857 -0.23345947265625 +84858 -0.458038330078125 +84859 -0.1898193359375 +84860 -0.350555419921875 +84861 -0.1446533203125 +84862 -0.260528564453125 +84863 -0.106536865234375 +84864 -0.192108154296875 +84865 -0.0772705078125 +84866 -0.141937255859375 +84867 -0.055511474609375 +84868 -0.1021728515625 +84869 -0.03814697265625 +84870 -0.062896728515625 +84871 -0.02117919921875 +84872 -0.011932373046875 +84873 0.000274658203125 +84874 0.062835693359375 +84875 0.031158447265625 +84876 0.148712158203125 +84877 0.0662841796875 +84878 0.241729736328125 +84879 0.10400390625 +84880 0.34912109375 +84881 0.147308349609375 +84882 0.457305908203125 +84883 0.190673828125 +84884 0.54388427734375 +84885 0.22503662109375 +84886 0.5728759765625 +84887 0.235748291015625 +84888 0.506591796875 +84889 0.20751953125 +84890 0.351226806640625 +84891 0.1429443359375 +84892 0.146514892578125 +84893 0.05828857421875 +84894 -0.05523681640625 +84895 -0.0250244140625 +84896 -0.21624755859375 +84897 -0.091522216796875 +84898 -0.334930419921875 +84899 -0.140533447265625 +84900 -0.402984619140625 +84901 -0.16864013671875 +84902 -0.4412841796875 +84903 -0.184326171875 +84904 -0.49578857421875 +84905 -0.20635986328125 +84906 -0.5601806640625 +84907 -0.232208251953125 +84908 -0.600738525390625 +84909 -0.248138427734375 +84910 -0.584228515625 +84911 -0.240631103515625 +84912 -0.47930908203125 +84913 -0.196929931640625 +84914 -0.27935791015625 +84915 -0.1143798828125 +84916 -0.0089111328125 +84917 -0.0030517578125 +84918 0.268798828125 +84919 0.11114501953125 +84920 0.482818603515625 +84921 0.199249267578125 +84922 0.60369873046875 +84923 0.24920654296875 +84924 0.650421142578125 +84925 0.268707275390625 +84926 0.66400146484375 +84927 0.27447509765625 +84928 0.6414794921875 +84929 0.26531982421875 +84930 0.572540283203125 +84931 0.237030029296875 +84932 0.498138427734375 +84933 0.206329345703125 +84934 0.439453125 +84935 0.181884765625 +84936 0.375518798828125 +84937 0.155181884765625 +84938 0.274505615234375 +84939 0.113250732421875 +84940 0.1087646484375 +84941 0.04486083984375 +84942 -0.099395751953125 +84943 -0.04083251953125 +84944 -0.3182373046875 +84945 -0.130828857421875 +84946 -0.5489501953125 +84947 -0.2255859375 +84948 -0.7738037109375 +84949 -0.31781005859375 +84950 -0.86383056640625 +84951 -0.3858642578125 +84952 -0.870391845703125 +84953 -0.41619873046875 +84954 -0.86895751953125 +84955 -0.416015625 +84956 -0.861053466796875 +84957 -0.39068603515625 +84958 -0.765869140625 +84959 -0.33319091796875 +84960 -0.5301513671875 +84961 -0.23895263671875 +84962 -0.214691162109375 +84963 -0.110870361328125 +84964 0.137359619140625 +84965 0.033416748046875 +84966 0.474822998046875 +84967 0.172943115234375 +84968 0.76239013671875 +84969 0.293182373046875 +84970 0.867462158203125 +84971 0.383087158203125 +84972 0.870361328125 +84973 0.44281005859375 +84974 0.86480712890625 +84975 0.46759033203125 +84976 0.831817626953125 +84977 0.459625244140625 +84978 0.677581787109375 +84979 0.428863525390625 +84980 0.495880126953125 +84981 0.377655029296875 +84982 0.30767822265625 +84983 0.3135986328125 +84984 0.116180419921875 +84985 0.237579345703125 +84986 -0.110748291015625 +84987 0.136688232421875 +84988 -0.381805419921875 +84989 0.00811767578125 +84990 -0.6572265625 +84991 -0.130615234375 +84992 -0.857421875 +84993 -0.25518798828125 +84994 -0.870391845703125 +84995 -0.34820556640625 +84996 -0.870391845703125 +84997 -0.406585693359375 +84998 -0.86444091796875 +84999 -0.440460205078125 +85000 -0.85723876953125 +85001 -0.46337890625 +85002 -0.790008544921875 +85003 -0.46868896484375 +85004 -0.62847900390625 +85005 -0.436279296875 +85006 -0.3956298828125 +85007 -0.36529541015625 +85008 -0.126708984375 +85009 -0.26849365234375 +85010 0.150115966796875 +85011 -0.1566162109375 +85012 0.424041748046875 +85013 -0.03448486328125 +85014 0.670623779296875 +85015 0.0872802734375 +85016 0.854522705078125 +85017 0.193695068359375 +85018 0.866485595703125 +85019 0.27777099609375 +85020 0.86920166015625 +85021 0.333404541015625 +85022 0.8653564453125 +85023 0.3671875 +85024 0.857147216796875 +85025 0.384033203125 +85026 0.766845703125 +85027 0.38275146484375 +85028 0.628509521484375 +85029 0.36529541015625 +85030 0.462127685546875 +85031 0.3292236328125 +85032 0.297210693359375 +85033 0.284454345703125 +85034 0.14862060546875 +85035 0.23590087890625 +85036 -0.00537109375 +85037 0.175262451171875 +85038 -0.15753173828125 +85039 0.105712890625 +85040 -0.31304931640625 +85041 0.0262451171875 +85042 -0.48876953125 +85043 -0.068023681640625 +85044 -0.6416015625 +85045 -0.159149169921875 +85046 -0.751373291015625 +85047 -0.237548828125 +85048 -0.84619140625 +85049 -0.31170654296875 +85050 -0.861297607421875 +85051 -0.37591552734375 +85052 -0.863250732421875 +85053 -0.417633056640625 +85054 -0.856597900390625 +85055 -0.424957275390625 +85056 -0.7498779296875 +85057 -0.40252685546875 +85058 -0.624542236328125 +85059 -0.372222900390625 +85060 -0.47808837890625 +85061 -0.325958251953125 +85062 -0.253387451171875 +85063 -0.242034912109375 +85064 0.003692626953125 +85065 -0.137908935546875 +85066 0.2257080078125 +85067 -0.03955078125 +85068 0.427154541015625 +85069 0.05743408203125 +85070 0.643218994140625 +85071 0.164947509765625 +85072 0.855926513671875 +85073 0.279083251953125 +85074 0.870361328125 +85075 0.377838134765625 +85076 0.870361328125 +85077 0.4423828125 +85078 0.862762451171875 +85079 0.475311279296875 +85080 0.79669189453125 +85081 0.475494384765625 +85082 0.595794677734375 +85083 0.43939208984375 +85084 0.362152099609375 +85085 0.37811279296875 +85086 0.1270751953125 +85087 0.302337646484375 +85088 -0.086944580078125 +85089 0.220245361328125 +85090 -0.2784423828125 +85091 0.13287353515625 +85092 -0.484832763671875 +85093 0.027374267578125 +85094 -0.729583740234375 +85095 -0.103179931640625 +85096 -0.86688232421875 +85097 -0.239471435546875 +85098 -0.870391845703125 +85099 -0.357421875 +85100 -0.86859130859375 +85101 -0.4549560546875 +85102 -0.86279296875 +85103 -0.531158447265625 +85104 -0.817962646484375 +85105 -0.572357177734375 +85106 -0.6116943359375 +85107 -0.5614013671875 +85108 -0.3128662109375 +85109 -0.49566650390625 +85110 0.039398193359375 +85111 -0.38787841796875 +85112 0.422821044921875 +85113 -0.245697021484375 +85114 0.805145263671875 +85115 -0.081817626953125 +85116 0.870361328125 +85117 0.077911376953125 +85118 0.870361328125 +85119 0.2117919921875 +85120 0.860015869140625 +85121 0.315185546875 +85122 0.727935791015625 +85123 0.3848876953125 +85124 0.48114013671875 +85125 0.418487548828125 +85126 0.2059326171875 +85127 0.4248046875 +85128 -0.06103515625 +85129 0.412109375 +85130 -0.29913330078125 +85131 0.384033203125 +85132 -0.516204833984375 +85133 0.33502197265625 +85134 -0.7252197265625 +85135 0.25927734375 +85136 -0.85980224609375 +85137 0.16619873046875 +85138 -0.870391845703125 +85139 0.068878173828125 +85140 -0.870391845703125 +85141 -0.021331787109375 +85142 -0.858062744140625 +85143 -0.085845947265625 +85144 -0.673004150390625 +85145 -0.122711181640625 +85146 -0.42694091796875 +85147 -0.15130615234375 +85148 -0.2100830078125 +85149 -0.18792724609375 +85150 -0.0362548828125 +85151 -0.23138427734375 +85152 0.10943603515625 +85153 -0.2703857421875 +85154 0.23516845703125 +85155 -0.29718017578125 +85156 0.373687744140625 +85157 -0.29595947265625 +85158 0.517791748046875 +85159 -0.267364501953125 +85160 0.602783203125 +85161 -0.23504638671875 +85162 0.635711669921875 +85163 -0.197113037109375 +85164 0.655181884765625 +85165 -0.14117431640625 +85166 0.65948486328125 +85167 -0.071197509765625 +85168 0.651275634765625 +85169 0.009490966796875 +85170 0.61846923828125 +85171 0.091339111328125 +85172 0.53753662109375 +85173 0.160064697265625 +85174 0.404144287109375 +85175 0.208465576171875 +85176 0.22186279296875 +85177 0.232574462890625 +85178 0.003997802734375 +85179 0.232513427734375 +85180 -0.22100830078125 +85181 0.214813232421875 +85182 -0.42449951171875 +85183 0.187042236328125 +85184 -0.579833984375 +85185 0.157073974609375 +85186 -0.641876220703125 +85187 0.140899658203125 +85188 -0.6177978515625 +85189 0.13604736328125 +85190 -0.575531005859375 +85191 0.11834716796875 +85192 -0.526336669921875 +85193 0.085968017578125 +85194 -0.42645263671875 +85195 0.058624267578125 +85196 -0.2581787109375 +85197 0.046905517578125 +85198 -0.068695068359375 +85199 0.037445068359375 +85200 0.09222412109375 +85201 0.01611328125 +85202 0.232147216796875 +85203 -0.009735107421875 +85204 0.3509521484375 +85205 -0.03594970703125 +85206 0.410064697265625 +85207 -0.073394775390625 +85208 0.372955322265625 +85209 -0.132843017578125 +85210 0.2554931640625 +85211 -0.206268310546875 +85212 0.10711669921875 +85213 -0.273956298828125 +85214 -0.052886962890625 +85215 -0.3284912109375 +85216 -0.186279296875 +85217 -0.3563232421875 +85218 -0.23291015625 +85219 -0.3365478515625 +85220 -0.209442138671875 +85221 -0.277862548828125 +85222 -0.174163818359375 +85223 -0.205291748046875 +85224 -0.126739501953125 +85225 -0.122222900390625 +85226 -0.048126220703125 +85227 -0.025238037109375 +85228 0.0426025390625 +85229 0.07476806640625 +85230 0.10748291015625 +85231 0.15997314453125 +85232 0.1409912109375 +85233 0.22509765625 +85234 0.19708251953125 +85235 0.287811279296875 +85236 0.273651123046875 +85237 0.345367431640625 +85238 0.31768798828125 +85239 0.376617431640625 +85240 0.341094970703125 +85241 0.38568115234375 +85242 0.368011474609375 +85243 0.38201904296875 +85244 0.37249755859375 +85245 0.3570556640625 +85246 0.30072021484375 +85247 0.2923583984375 +85248 0.1517333984375 +85249 0.18975830078125 +85250 -0.01470947265625 +85251 0.074371337890625 +85252 -0.1883544921875 +85253 -0.046051025390625 +85254 -0.372711181640625 +85255 -0.169342041015625 +85256 -0.51397705078125 +85257 -0.2734375 +85258 -0.57177734375 +85259 -0.341339111328125 +85260 -0.53948974609375 +85261 -0.368377685546875 +85262 -0.43511962890625 +85263 -0.359039306640625 +85264 -0.2962646484375 +85265 -0.325347900390625 +85266 -0.161102294921875 +85267 -0.2802734375 +85268 -0.0435791015625 +85269 -0.228973388671875 +85270 0.060394287109375 +85271 -0.17095947265625 +85272 0.13665771484375 +85273 -0.112701416015625 +85274 0.170135498046875 +85275 -0.0615234375 +85276 0.16552734375 +85277 -0.018157958984375 +85278 0.15728759765625 +85279 0.02679443359375 +85280 0.150787353515625 +85281 0.072509765625 +85282 0.12200927734375 +85283 0.10797119140625 +85284 0.080108642578125 +85285 0.13397216796875 +85286 0.05126953125 +85287 0.1575927734375 +85288 0.062896728515625 +85289 0.186767578125 +85290 0.09271240234375 +85291 0.212615966796875 +85292 0.092987060546875 +85293 0.217864990234375 +85294 0.07855224609375 +85295 0.20770263671875 +85296 0.06427001953125 +85297 0.187896728515625 +85298 0.0347900390625 +85299 0.1541748046875 +85300 -0.01171875 +85301 0.107421875 +85302 -0.056060791015625 +85303 0.05621337890625 +85304 -0.055511474609375 +85305 0.017578125 +85306 -0.010467529296875 +85307 -0.006378173828125 +85308 0.02508544921875 +85309 -0.032318115234375 +85310 0.025665283203125 +85311 -0.067108154296875 +85312 0.017333984375 +85313 -0.099822998046875 +85314 0.00189208984375 +85315 -0.128387451171875 +85316 -0.03173828125 +85317 -0.155609130859375 +85318 -0.071502685546875 +85319 -0.176666259765625 +85320 -0.13543701171875 +85321 -0.19769287109375 +85322 -0.219970703125 +85323 -0.217742919921875 +85324 -0.300506591796875 +85325 -0.22894287109375 +85326 -0.376312255859375 +85327 -0.232208251953125 +85328 -0.416107177734375 +85329 -0.218048095703125 +85330 -0.371124267578125 +85331 -0.171051025390625 +85332 -0.242279052734375 +85333 -0.09332275390625 +85334 -0.069732666015625 +85335 -0.000762939453125 +85336 0.125640869140625 +85337 0.097564697265625 +85338 0.31268310546875 +85339 0.189178466796875 +85340 0.45501708984375 +85341 0.260009765625 +85342 0.554779052734375 +85343 0.309814453125 +85344 0.61065673828125 +85345 0.3375244140625 +85346 0.610931396484375 +85347 0.33880615234375 +85348 0.531463623046875 +85349 0.305328369140625 +85350 0.3883056640625 +85351 0.24322509765625 +85352 0.23468017578125 +85353 0.17193603515625 +85354 0.095245361328125 +85355 0.10125732421875 +85356 -0.00396728515625 +85357 0.041595458984375 +85358 -0.04852294921875 +85359 -0.00054931640625 +85360 -0.055145263671875 +85361 -0.029541015625 +85362 -0.0758056640625 +85363 -0.062103271484375 +85364 -0.138702392578125 +85365 -0.106781005859375 +85366 -0.209197998046875 +85367 -0.1502685546875 +85368 -0.289031982421875 +85369 -0.1922607421875 +85370 -0.37884521484375 +85371 -0.23236083984375 +85372 -0.456329345703125 +85373 -0.262451171875 +85374 -0.51641845703125 +85375 -0.28076171875 +85376 -0.519287109375 +85377 -0.27362060546875 +85378 -0.458251953125 +85379 -0.23931884765625 +85380 -0.384796142578125 +85381 -0.19671630859375 +85382 -0.323699951171875 +85383 -0.155517578125 +85384 -0.269287109375 +85385 -0.114898681640625 +85386 -0.1951904296875 +85387 -0.06683349609375 +85388 -0.100006103515625 +85389 -0.0120849609375 +85390 -0.01055908203125 +85391 0.038787841796875 +85392 0.1033935546875 +85393 0.0953369140625 +85394 0.24908447265625 +85395 0.1593017578125 +85396 0.373199462890625 +85397 0.21142578125 +85398 0.45806884765625 +85399 0.245147705078125 +85400 0.511474609375 +85401 0.26312255859375 +85402 0.565399169921875 +85403 0.276702880859375 +85404 0.61138916015625 +85405 0.283355712890625 +85406 0.5897216796875 +85407 0.2628173828125 +85408 0.4906005859375 +85409 0.212432861328125 +85410 0.33148193359375 +85411 0.1392822265625 +85412 0.147796630859375 +85413 0.0567626953125 +85414 -0.01873779296875 +85415 -0.01947021484375 +85416 -0.140289306640625 +85417 -0.078704833984375 +85418 -0.191986083984375 +85419 -0.11138916015625 +85420 -0.184295654296875 +85421 -0.120452880859375 +85422 -0.161834716796875 +85423 -0.120941162109375 +85424 -0.166595458984375 +85425 -0.127197265625 +85426 -0.19390869140625 +85427 -0.137420654296875 +85428 -0.22442626953125 +85429 -0.144927978515625 +85430 -0.279754638671875 +85431 -0.157562255859375 +85432 -0.3389892578125 +85433 -0.168487548828125 +85434 -0.3543701171875 +85435 -0.16162109375 +85436 -0.348175048828125 +85437 -0.145477294921875 +85438 -0.32598876953125 +85439 -0.122833251953125 +85440 -0.2581787109375 +85441 -0.08416748046875 +85442 -0.139801025390625 +85443 -0.028564453125 +85444 0.014617919921875 +85445 0.03814697265625 +85446 0.144378662109375 +85447 0.094024658203125 +85448 0.221038818359375 +85449 0.128631591796875 +85450 0.27069091796875 +85451 0.1507568359375 +85452 0.294036865234375 +85453 0.160491943359375 +85454 0.311767578125 +85455 0.16510009765625 +85456 0.339141845703125 +85457 0.170074462890625 +85458 0.360260009765625 +85459 0.17010498046875 +85460 0.360504150390625 +85461 0.16058349609375 +85462 0.308380126953125 +85463 0.13128662109375 +85464 0.18170166015625 +85465 0.07525634765625 +85466 0.0047607421875 +85467 0.001617431640625 +85468 -0.17559814453125 +85469 -0.07281494140625 +85470 -0.3143310546875 +85471 -0.13189697265625 +85472 -0.36785888671875 +85473 -0.1600341796875 +85474 -0.36248779296875 +85475 -0.165802001953125 +85476 -0.343536376953125 +85477 -0.164398193359375 +85478 -0.3018798828125 +85479 -0.152496337890625 +85480 -0.231414794921875 +85481 -0.1279296875 +85482 -0.117645263671875 +85483 -0.0858154296875 +85484 0.007049560546875 +85485 -0.037567138671875 +85486 0.087982177734375 +85487 -0.002288818359375 +85488 0.13946533203125 +85489 0.0244140625 +85490 0.17425537109375 +85491 0.046417236328125 +85492 0.188201904296875 +85493 0.06170654296875 +85494 0.171234130859375 +85495 0.06622314453125 +85496 0.118438720703125 +85497 0.057708740234375 +85498 0.05706787109375 +85499 0.045074462890625 +85500 -0.010711669921875 +85501 0.028594970703125 +85502 -0.0914306640625 +85503 0.005706787109375 +85504 -0.162322998046875 +85505 -0.0155029296875 +85506 -0.194549560546875 +85507 -0.025421142578125 +85508 -0.1492919921875 +85509 -0.012176513671875 +85510 -0.02166748046875 +85511 0.025482177734375 +85512 0.124053955078125 +85513 0.0673828125 +85514 0.211151123046875 +85515 0.089630126953125 +85516 0.240447998046875 +85517 0.0926513671875 +85518 0.242218017578125 +85519 0.086181640625 +85520 0.2257080078125 +85521 0.073516845703125 +85522 0.194366455078125 +85523 0.056121826171875 +85524 0.115509033203125 +85525 0.024200439453125 +85526 0.0128173828125 +85527 -0.014404296875 +85528 -0.053802490234375 +85529 -0.0406494140625 +85530 -0.110626220703125 +85531 -0.06243896484375 +85532 -0.199493408203125 +85533 -0.0926513671875 +85534 -0.29437255859375 +85535 -0.123046875 +85536 -0.33221435546875 +85537 -0.133941650390625 +85538 -0.27972412109375 +85539 -0.11505126953125 +85540 -0.185333251953125 +85541 -0.0816650390625 +85542 -0.128204345703125 +85543 -0.058685302734375 +85544 -0.115692138671875 +85545 -0.0487060546875 +85546 -0.116455078125 +85547 -0.042327880859375 +85548 -0.105926513671875 +85549 -0.032257080078125 +85550 -0.053955078125 +85551 -0.00946044921875 +85552 0.048797607421875 +85553 0.028564453125 +85554 0.157318115234375 +85555 0.0675048828125 +85556 0.212005615234375 +85557 0.0885009765625 +85558 0.218475341796875 +85559 0.0931396484375 +85560 0.23724365234375 +85561 0.100189208984375 +85562 0.30535888671875 +85563 0.121185302734375 +85564 0.38128662109375 +85565 0.1431884765625 +85566 0.404449462890625 +85567 0.147430419921875 +85568 0.3944091796875 +85569 0.140228271484375 +85570 0.3885498046875 +85571 0.133514404296875 +85572 0.362640380859375 +85573 0.120025634765625 +85574 0.27362060546875 +85575 0.08660888671875 +85576 0.11712646484375 +85577 0.032257080078125 +85578 -0.054901123046875 +85579 -0.0264892578125 +85580 -0.19085693359375 +85581 -0.07330322265625 +85582 -0.28570556640625 +85583 -0.10638427734375 +85584 -0.339263916015625 +85585 -0.12554931640625 +85586 -0.3775634765625 +85587 -0.138763427734375 +85588 -0.445709228515625 +85589 -0.16009521484375 +85590 -0.535064697265625 +85591 -0.1868896484375 +85592 -0.629058837890625 +85593 -0.21405029296875 +85594 -0.697601318359375 +85595 -0.232330322265625 +85596 -0.70391845703125 +85597 -0.230438232421875 +85598 -0.6424560546875 +85599 -0.2069091796875 +85600 -0.491241455078125 +85601 -0.155120849609375 +85602 -0.265716552734375 +85603 -0.08013916015625 +85604 -0.023712158203125 +85605 -0.000274658203125 +85606 0.201751708984375 +85607 0.073883056640625 +85608 0.375823974609375 +85609 0.13128662109375 +85610 0.485076904296875 +85611 0.1676025390625 +85612 0.56884765625 +85613 0.19500732421875 +85614 0.634765625 +85615 0.215850830078125 +85616 0.63763427734375 +85617 0.216064453125 +85618 0.5660400390625 +85619 0.192138671875 +85620 0.4720458984375 +85621 0.160430908203125 +85622 0.40692138671875 +85623 0.137054443359375 +85624 0.3778076171875 +85625 0.12445068359375 +85626 0.376953125 +85627 0.12042236328125 +85628 0.371978759765625 +85629 0.11505126953125 +85630 0.313140869140625 +85631 0.093048095703125 +85632 0.184417724609375 +85633 0.049591064453125 +85634 0.011199951171875 +85635 -0.007171630859375 +85636 -0.171051025390625 +85637 -0.066070556640625 +85638 -0.33740234375 +85639 -0.119232177734375 +85640 -0.47198486328125 +85641 -0.161651611328125 +85642 -0.560394287109375 +85643 -0.1888427734375 +85644 -0.58056640625 +85645 -0.1939697265625 +85646 -0.54754638671875 +85647 -0.18182373046875 +85648 -0.508575439453125 +85649 -0.167266845703125 +85650 -0.459503173828125 +85651 -0.149139404296875 +85652 -0.394378662109375 +85653 -0.125732421875 +85654 -0.35260009765625 +85655 -0.109527587890625 +85656 -0.31170654296875 +85657 -0.09368896484375 +85658 -0.197418212890625 +85659 -0.055206298828125 +85660 -0.007965087890625 +85661 0.00628662109375 +85662 0.207489013671875 +85663 0.075347900390625 +85664 0.409210205078125 +85665 0.13946533203125 +85666 0.57208251953125 +85667 0.190765380859375 +85668 0.66595458984375 +85669 0.2198486328125 +85670 0.65875244140625 +85671 0.21673583984375 +85672 0.56744384765625 +85673 0.186798095703125 +85674 0.431396484375 +85675 0.142425537109375 +85676 0.29443359375 +85677 0.097412109375 +85678 0.182464599609375 +85679 0.0599365234375 +85680 0.06365966796875 +85681 0.020233154296875 +85682 -0.075958251953125 +85683 -0.025909423828125 +85684 -0.189422607421875 +85685 -0.063690185546875 +85686 -0.271942138671875 +85687 -0.091461181640625 +85688 -0.342529296875 +85689 -0.11505126953125 +85690 -0.364166259765625 +85691 -0.122894287109375 +85692 -0.327239990234375 +85693 -0.111907958984375 +85694 -0.2769775390625 +85695 -0.09619140625 +85696 -0.253692626953125 +85697 -0.088348388671875 +85698 -0.24365234375 +85699 -0.0841064453125 +85700 -0.1983642578125 +85701 -0.06842041015625 +85702 -0.116241455078125 +85703 -0.040924072265625 +85704 -0.036834716796875 +85705 -0.014068603515625 +85706 0.034881591796875 +85707 0.010467529296875 +85708 0.09124755859375 +85709 0.0301513671875 +85710 0.10888671875 +85711 0.03759765625 +85712 0.125518798828125 +85713 0.044464111328125 +85714 0.15771484375 +85715 0.05584716796875 +85716 0.17828369140625 +85717 0.063201904296875 +85718 0.17108154296875 +85719 0.061431884765625 +85720 0.129974365234375 +85721 0.04864501953125 +85722 0.082427978515625 +85723 0.03338623046875 +85724 0.027679443359375 +85725 0.0155029296875 +85726 -0.065643310546875 +85727 -0.01470947265625 +85728 -0.15936279296875 +85729 -0.0452880859375 +85730 -0.21307373046875 +85731 -0.063568115234375 +85732 -0.234649658203125 +85733 -0.071929931640625 +85734 -0.2001953125 +85735 -0.06280517578125 +85736 -0.119171142578125 +85737 -0.0390625 +85738 -0.024749755859375 +85739 -0.010986328125 +85740 0.085784912109375 +85741 0.0223388671875 +85742 0.178131103515625 +85743 0.05023193359375 +85744 0.215576171875 +85745 0.061309814453125 +85746 0.211456298828125 +85747 0.059783935546875 +85748 0.17523193359375 +85749 0.048614501953125 +85750 0.128753662109375 +85751 0.034576416015625 +85752 0.1019287109375 +85753 0.0269775390625 +85754 0.0743408203125 +85755 0.019378662109375 +85756 0.04327392578125 +85757 0.010894775390625 +85758 0.038177490234375 +85759 0.010589599609375 +85760 0.076263427734375 +85761 0.02325439453125 +85762 0.14105224609375 +85763 0.043182373046875 +85764 0.186431884765625 +85765 0.05682373046875 +85766 0.188812255859375 +85767 0.05767822265625 +85768 0.1390380859375 +85769 0.0433349609375 +85770 0.041778564453125 +85771 0.0152587890625 +85772 -0.079437255859375 +85773 -0.019775390625 +85774 -0.219390869140625 +85775 -0.060211181640625 +85776 -0.367828369140625 +85777 -0.10302734375 +85778 -0.494873046875 +85779 -0.1397705078125 +85780 -0.556243896484375 +85781 -0.157989501953125 +85782 -0.508697509765625 +85783 -0.1455078125 +85784 -0.3756103515625 +85785 -0.10882568359375 +85786 -0.218902587890625 +85787 -0.06524658203125 +85788 -0.063751220703125 +85789 -0.021820068359375 +85790 0.091552734375 +85791 0.021881103515625 +85792 0.23602294921875 +85793 0.062744140625 +85794 0.342987060546875 +85795 0.093292236328125 +85796 0.39520263671875 +85797 0.108642578125 +85798 0.389373779296875 +85799 0.10784912109375 +85800 0.324249267578125 +85801 0.09051513671875 +85802 0.224090576171875 +85803 0.063385009765625 +85804 0.124267578125 +85805 0.03631591796875 +85806 0.037078857421875 +85807 0.012664794921875 +85808 -0.010101318359375 +85809 6.103515625e-05 +85810 -0.019439697265625 +85811 -0.002105712890625 +85812 -0.022796630859375 +85813 -0.00274658203125 +85814 -0.001556396484375 +85815 0.003265380859375 +85816 0.056304931640625 +85817 0.019287109375 +85818 0.106719970703125 +85819 0.03302001953125 +85820 0.096893310546875 +85821 0.02972412109375 +85822 0.042694091796875 +85823 0.01385498046875 +85824 -0.018035888671875 +85825 -0.00390625 +85826 -0.07586669921875 +85827 -0.0208740234375 +85828 -0.11944580078125 +85829 -0.0338134765625 +85830 -0.15972900390625 +85831 -0.045745849609375 +85832 -0.202606201171875 +85833 -0.058319091796875 +85834 -0.24859619140625 +85835 -0.071624755859375 +85836 -0.30517578125 +85837 -0.087738037109375 +85838 -0.36212158203125 +85839 -0.103790283203125 +85840 -0.39141845703125 +85841 -0.1119384765625 +85842 -0.35528564453125 +85843 -0.10162353515625 +85844 -0.249969482421875 +85845 -0.071807861328125 +85846 -0.092864990234375 +85847 -0.02740478515625 +85848 0.08905029296875 +85849 0.024017333984375 +85850 0.2352294921875 +85851 0.065460205078125 +85852 0.318817138671875 +85853 0.089385986328125 +85854 0.358642578125 +85855 0.10101318359375 +85856 0.347747802734375 +85857 0.098388671875 +85858 0.28564453125 +85859 0.08135986328125 +85860 0.223175048828125 +85861 0.064117431640625 +85862 0.196746826171875 +85863 0.056884765625 +85864 0.179840087890625 +85865 0.052215576171875 +85866 0.155548095703125 +85867 0.045379638671875 +85868 0.151214599609375 +85869 0.044036865234375 +85870 0.156951904296875 +85871 0.045440673828125 +85872 0.13177490234375 +85873 0.0380859375 +85874 0.100799560546875 +85875 0.029052734375 +85876 0.087127685546875 +85877 0.024810791015625 +85878 0.05487060546875 +85879 0.015350341796875 +85880 -0.009002685546875 +85881 -0.0029296875 +85882 -0.10400390625 +85883 -0.029876708984375 +85884 -0.229400634765625 +85885 -0.065277099609375 +85886 -0.35552978515625 +85887 -0.100799560546875 +85888 -0.441925048828125 +85889 -0.125091552734375 +85890 -0.473846435546875 +85891 -0.134033203125 +85892 -0.464813232421875 +85893 -0.13140869140625 +85894 -0.419097900390625 +85895 -0.118438720703125 +85896 -0.334320068359375 +85897 -0.094451904296875 +85898 -0.227935791015625 +85899 -0.0643310546875 +85900 -0.12347412109375 +85901 -0.034698486328125 +85902 -0.02764892578125 +85903 -0.007476806640625 +85904 0.077667236328125 +85905 0.022369384765625 +85906 0.2132568359375 +85907 0.060638427734375 +85908 0.38885498046875 +85909 0.11004638671875 +85910 0.582794189453125 +85911 0.164520263671875 +85912 0.734039306640625 +85913 0.206939697265625 +85914 0.800140380859375 +85915 0.22540283203125 +85916 0.7783203125 +85917 0.219146728515625 +85918 0.6651611328125 +85919 0.187286376953125 +85920 0.45965576171875 +85921 0.129547119140625 +85922 0.199188232421875 +85923 0.056365966796875 +85924 -0.050689697265625 +85925 -0.013824462890625 +85926 -0.23297119140625 +85927 -0.0650634765625 +85928 -0.33013916015625 +85929 -0.092437744140625 +85930 -0.368408203125 +85931 -0.103302001953125 +85932 -0.378936767578125 +85933 -0.106353759765625 +85934 -0.376983642578125 +85935 -0.10589599609375 +85936 -0.37969970703125 +85937 -0.10675048828125 +85938 -0.391510009765625 +85939 -0.110107421875 +85940 -0.385345458984375 +85941 -0.1083984375 +85942 -0.3419189453125 +85943 -0.09619140625 +85944 -0.28289794921875 +85945 -0.079559326171875 +85946 -0.251617431640625 +85947 -0.0706787109375 +85948 -0.266143798828125 +85949 -0.0745849609375 +85950 -0.273345947265625 +85951 -0.076416015625 +85952 -0.216796875 +85953 -0.060394287109375 +85954 -0.128265380859375 +85955 -0.035400390625 +85956 -0.068145751953125 +85957 -0.01837158203125 +85958 -0.0430908203125 +85959 -0.011138916015625 +85960 -0.024444580078125 +85961 -0.0057373046875 +85962 0.020721435546875 +85963 0.00701904296875 +85964 0.124481201171875 +85965 0.036102294921875 +85966 0.25787353515625 +85967 0.07342529296875 +85968 0.379119873046875 +85969 0.107269287109375 +85970 0.47991943359375 +85971 0.135345458984375 +85972 0.5281982421875 +85973 0.148651123046875 +85974 0.511138916015625 +85975 0.14361572265625 +85976 0.456207275390625 +85977 0.1279296875 +85978 0.407470703125 +85979 0.113983154296875 +85980 0.383758544921875 +85981 0.107025146484375 +85982 0.35687255859375 +85983 0.099212646484375 +85984 0.31182861328125 +85985 0.08636474609375 +85986 0.250885009765625 +85987 0.069122314453125 +85988 0.1654052734375 +85989 0.045074462890625 +85990 0.035247802734375 +85991 0.008575439453125 +85992 -0.142059326171875 +85993 -0.041046142578125 +85994 -0.33563232421875 +85995 -0.095123291015625 +85996 -0.5345458984375 +85997 -0.150604248046875 +85998 -0.72186279296875 +85999 -0.202789306640625 +86000 -0.836669921875 +86001 -0.234588623046875 +86002 -0.8326416015625 +86003 -0.23309326171875 +86004 -0.7296142578125 +86005 -0.203857421875 +86006 -0.582550048828125 +86007 -0.16229248046875 +86008 -0.440093994140625 +86009 -0.1220703125 +86010 -0.324310302734375 +86011 -0.089385986328125 +86012 -0.20147705078125 +86013 -0.054779052734375 +86014 -0.044647216796875 +86015 -0.010711669921875 +86016 0.103973388671875 +86017 0.03155517578125 +86018 0.202392578125 +86019 0.060882568359375 +86020 0.264495849609375 +86021 0.08050537109375 +86022 0.338897705078125 +86023 0.10223388671875 +86024 0.443817138671875 +86025 0.13043212890625 +86026 0.545074462890625 +86027 0.156524658203125 +86028 0.6173095703125 +86029 0.1741943359375 +86030 0.6524658203125 +86031 0.1815185546875 +86032 0.66339111328125 +86033 0.1817626953125 +86034 0.6561279296875 +86035 0.176605224609375 +86036 0.606781005859375 +86037 0.160308837890625 +86038 0.501190185546875 +86039 0.129638671875 +86040 0.352783203125 +86041 0.088165283203125 +86042 0.176544189453125 +86043 0.039886474609375 +86044 -0.034820556640625 +86045 -0.0167236328125 +86046 -0.258209228515625 +86047 -0.07568359375 +86048 -0.44244384765625 +86049 -0.124176025390625 +86050 -0.5753173828125 +86051 -0.159027099609375 +86052 -0.65203857421875 +86053 -0.178985595703125 +86054 -0.641632080078125 +86055 -0.176361083984375 +86056 -0.562164306640625 +86057 -0.155670166015625 +86058 -0.458038330078125 +86059 -0.128021240234375 +86060 -0.350555419921875 +86061 -0.098785400390625 +86062 -0.260528564453125 +86063 -0.073272705078125 +86064 -0.192108154296875 +86065 -0.052703857421875 +86066 -0.141937255859375 +86067 -0.036468505859375 +86068 -0.1021728515625 +86069 -0.0228271484375 +86070 -0.062896728515625 +86071 -0.009521484375 +86072 -0.011932373046875 +86073 0.006256103515625 +86074 0.062835693359375 +86075 0.02734375 +86076 0.148712158203125 +86077 0.05047607421875 +86078 0.241729736328125 +86079 0.0745849609375 +86080 0.34912109375 +86081 0.101409912109375 +86082 0.457305908203125 +86083 0.12762451171875 +86084 0.54388427734375 +86085 0.147735595703125 +86086 0.5728759765625 +86087 0.15289306640625 +86088 0.506591796875 +86089 0.1339111328125 +86090 0.351226806640625 +86091 0.092437744140625 +86092 0.146514892578125 +86093 0.03851318359375 +86094 -0.05523681640625 +86095 -0.014678955078125 +86096 -0.21624755859375 +86097 -0.057586669921875 +86098 -0.334930419921875 +86099 -0.08966064453125 +86100 -0.402984619140625 +86101 -0.10870361328125 +86102 -0.4412841796875 +86103 -0.119781494140625 +86104 -0.49578857421875 +86105 -0.134246826171875 +86106 -0.5601806640625 +86107 -0.1505126953125 +86108 -0.600738525390625 +86109 -0.160186767578125 +86110 -0.584228515625 +86111 -0.15509033203125 +86112 -0.47930908203125 +86113 -0.12750244140625 +86114 -0.27935791015625 +86115 -0.075897216796875 +86116 -0.0089111328125 +86117 -0.006500244140625 +86118 0.268798828125 +86119 0.064849853515625 +86120 0.482818603515625 +86121 0.12042236328125 +86122 0.60369873046875 +86123 0.152801513671875 +86124 0.650421142578125 +86125 0.166534423828125 +86126 0.66400146484375 +86127 0.17169189453125 +86128 0.6414794921875 +86129 0.167449951171875 +86130 0.572540283203125 +86131 0.151214599609375 +86132 0.498138427734375 +86133 0.13311767578125 +86134 0.439453125 +86135 0.118377685546875 +86136 0.375518798828125 +86137 0.101806640625 +86138 0.274505615234375 +86139 0.075592041015625 +86140 0.1087646484375 +86141 0.032958984375 +86142 -0.099395751953125 +86143 -0.02044677734375 +86144 -0.3182373046875 +86145 -0.076629638671875 +86146 -0.5489501953125 +86147 -0.13580322265625 +86148 -0.7738037109375 +86149 -0.193450927734375 +86150 -0.86383056640625 +86151 -0.236358642578125 +86152 -0.870391845703125 +86153 -0.256195068359375 +86154 -0.86895751953125 +86155 -0.25726318359375 +86156 -0.861053466796875 +86157 -0.242767333984375 +86158 -0.765869140625 +86159 -0.208404541015625 +86160 -0.5301513671875 +86161 -0.1513671875 +86162 -0.214691162109375 +86163 -0.07342529296875 +86164 0.137359619140625 +86165 0.014678955078125 +86166 0.474822998046875 +86167 0.100189208984375 +86168 0.76239013671875 +86169 0.174224853515625 +86170 0.867462158203125 +86171 0.230010986328125 +86172 0.870361328125 +86173 0.267578125 +86174 0.86480712890625 +86175 0.283966064453125 +86176 0.831817626953125 +86177 0.280426025390625 +86178 0.677581787109375 +86179 0.262908935546875 +86180 0.495880126953125 +86181 0.232818603515625 +86182 0.30767822265625 +86183 0.1947021484375 +86184 0.116180419921875 +86185 0.149078369140625 +86186 -0.110748291015625 +86187 0.08807373046875 +86188 -0.381805419921875 +86189 0.00994873046875 +86190 -0.6572265625 +86191 -0.074615478515625 +86192 -0.857421875 +86193 -0.150726318359375 +86194 -0.870391845703125 +86195 -0.207672119140625 +86196 -0.870391845703125 +86197 -0.24365234375 +86198 -0.86444091796875 +86199 -0.265289306640625 +86200 -0.85723876953125 +86201 -0.2813720703125 +86202 -0.790008544921875 +86203 -0.28729248046875 +86204 -0.62847900390625 +86205 -0.26953125 +86206 -0.3956298828125 +86207 -0.227203369140625 +86208 -0.126708984375 +86209 -0.168426513671875 +86210 0.150115966796875 +86211 -0.0999755859375 +86212 0.424041748046875 +86213 -0.024749755859375 +86214 0.670623779296875 +86215 0.050567626953125 +86216 0.854522705078125 +86217 0.116363525390625 +86218 0.866485595703125 +86219 0.168243408203125 +86220 0.86920166015625 +86221 0.202301025390625 +86222 0.8653564453125 +86223 0.2230224609375 +86224 0.857147216796875 +86225 0.233673095703125 +86226 0.766845703125 +86227 0.233489990234375 +86228 0.628509521484375 +86229 0.223663330078125 +86230 0.462127685546875 +86231 0.202484130859375 +86232 0.297210693359375 +86233 0.176300048828125 +86234 0.14862060546875 +86235 0.148101806640625 +86236 -0.00537109375 +86237 0.112213134765625 +86238 -0.15753173828125 +86239 0.070526123046875 +86240 -0.31304931640625 +86241 0.022125244140625 +86242 -0.48876953125 +86243 -0.036407470703125 +86244 -0.6416015625 +86245 -0.09344482421875 +86246 -0.751373291015625 +86247 -0.142791748046875 +86248 -0.84619140625 +86249 -0.190155029296875 +86250 -0.861297607421875 +86251 -0.2318115234375 +86252 -0.863250732421875 +86253 -0.259521484375 +86254 -0.856597900390625 +86255 -0.265380859375 +86256 -0.7498779296875 +86257 -0.25238037109375 +86258 -0.624542236328125 +86259 -0.234832763671875 +86260 -0.47808837890625 +86261 -0.207275390625 +86262 -0.253387451171875 +86263 -0.15521240234375 +86264 0.003692626953125 +86265 -0.0899658203125 +86266 0.2257080078125 +86267 -0.028472900390625 +86268 0.427154541015625 +86269 0.032318115234375 +86270 0.643218994140625 +86271 0.100433349609375 +86272 0.855926513671875 +86273 0.1729736328125 +86274 0.870361328125 +86275 0.2354736328125 +86276 0.870361328125 +86277 0.27630615234375 +86278 0.862762451171875 +86279 0.29705810546875 +86280 0.79669189453125 +86281 0.29718017578125 +86282 0.595794677734375 +86283 0.274871826171875 +86284 0.362152099609375 +86285 0.23675537109375 +86286 0.1270751953125 +86287 0.18927001953125 +86288 -0.086944580078125 +86289 0.13739013671875 +86290 -0.2784423828125 +86291 0.082061767578125 +86292 -0.484832763671875 +86293 0.0162353515625 +86294 -0.729583740234375 +86295 -0.06378173828125 +86296 -0.86688232421875 +86297 -0.146636962890625 +86298 -0.870391845703125 +86299 -0.21826171875 +86300 -0.86859130859375 +86301 -0.277252197265625 +86302 -0.86279296875 +86303 -0.322967529296875 +86304 -0.817962646484375 +86305 -0.347503662109375 +86306 -0.6116943359375 +86307 -0.34100341796875 +86308 -0.3128662109375 +86309 -0.302001953125 +86310 0.039398193359375 +86311 -0.237884521484375 +86312 0.422821044921875 +86313 -0.153228759765625 +86314 0.805145263671875 +86315 -0.055511474609375 +86316 0.870361328125 +86317 0.0401611328125 +86318 0.870361328125 +86319 0.121124267578125 +86320 0.860015869140625 +86321 0.184478759765625 +86322 0.727935791015625 +86323 0.228179931640625 +86324 0.48114013671875 +86325 0.250640869140625 +86326 0.2059326171875 +86327 0.25677490234375 +86328 -0.06103515625 +86329 0.251220703125 +86330 -0.29913330078125 +86331 0.235992431640625 +86332 -0.516204833984375 +86333 0.207855224609375 +86334 -0.7252197265625 +86335 0.163543701171875 +86336 -0.85980224609375 +86337 0.1085205078125 +86338 -0.870391845703125 +86339 0.0504150390625 +86340 -0.870391845703125 +86341 -0.004119873046875 +86342 -0.858062744140625 +86343 -0.044219970703125 +86344 -0.673004150390625 +86345 -0.068634033203125 +86346 -0.42694091796875 +86347 -0.08831787109375 +86348 -0.2100830078125 +86349 -0.1124267578125 +86350 -0.0362548828125 +86351 -0.14013671875 +86352 0.10943603515625 +86353 -0.164794921875 +86354 0.23516845703125 +86355 -0.181793212890625 +86356 0.373687744140625 +86357 -0.182037353515625 +86358 0.517791748046875 +86359 -0.165863037109375 +86360 0.602783203125 +86361 -0.1468505859375 +86362 0.635711669921875 +86363 -0.12396240234375 +86364 0.655181884765625 +86365 -0.090179443359375 +86366 0.65948486328125 +86367 -0.0478515625 +86368 0.651275634765625 +86369 0.000946044921875 +86370 0.61846923828125 +86371 0.050567626953125 +86372 0.53753662109375 +86373 0.0926513671875 +86374 0.404144287109375 +86375 0.122955322265625 +86376 0.22186279296875 +86377 0.1390380859375 +86378 0.003997802734375 +86379 0.140899658203125 +86380 -0.22100830078125 +86381 0.132171630859375 +86382 -0.42449951171875 +86383 0.117156982421875 +86384 -0.579833984375 +86385 0.100341796875 +86386 -0.641876220703125 +86387 0.090911865234375 +86388 -0.6177978515625 +86389 0.08746337890625 +86390 -0.575531005859375 +86391 0.076141357421875 +86392 -0.526336669921875 +86393 0.055938720703125 +86394 -0.42645263671875 +86395 0.038299560546875 +86396 -0.2581787109375 +86397 0.0294189453125 +86398 -0.068695068359375 +86399 0.021728515625 +86400 0.09222412109375 +86401 0.00726318359375 +86402 0.232147216796875 +86403 -0.009613037109375 +86404 0.3509521484375 +86405 -0.026397705078125 +86406 0.410064697265625 +86407 -0.04925537109375 +86408 0.372955322265625 +86409 -0.084320068359375 +86410 0.2554931640625 +86411 -0.126922607421875 +86412 0.10711669921875 +86413 -0.165740966796875 +86414 -0.052886962890625 +86415 -0.196533203125 +86416 -0.186279296875 +86417 -0.2115478515625 +86418 -0.23291015625 +86419 -0.1988525390625 +86420 -0.209442138671875 +86421 -0.163543701171875 +86422 -0.174163818359375 +86423 -0.120086669921875 +86424 -0.126739501953125 +86425 -0.070526123046875 +86426 -0.048126220703125 +86427 -0.01300048828125 +86428 0.0426025390625 +86429 0.046142578125 +86430 0.10748291015625 +86431 0.0965576171875 +86432 0.1409912109375 +86433 0.1351318359375 +86434 0.19708251953125 +86435 0.171966552734375 +86436 0.273651123046875 +86437 0.2054443359375 +86438 0.31768798828125 +86439 0.223419189453125 +86440 0.341094970703125 +86441 0.228240966796875 +86442 0.368011474609375 +86443 0.22540283203125 +86444 0.37249755859375 +86445 0.209991455078125 +86446 0.30072021484375 +86447 0.171539306640625 +86448 0.1517333984375 +86449 0.11126708984375 +86450 -0.01470947265625 +86451 0.04376220703125 +86452 -0.1883544921875 +86453 -0.02691650390625 +86454 -0.372711181640625 +86455 -0.09967041015625 +86456 -0.51397705078125 +86457 -0.161102294921875 +86458 -0.57177734375 +86459 -0.20086669921875 +86460 -0.53948974609375 +86461 -0.21612548828125 +86462 -0.43511962890625 +86463 -0.209747314453125 +86464 -0.2962646484375 +86465 -0.189117431640625 +86466 -0.161102294921875 +86467 -0.162139892578125 +86468 -0.0435791015625 +86469 -0.131927490234375 +86470 0.060394287109375 +86471 -0.09808349609375 +86472 0.13665771484375 +86473 -0.064453125 +86474 0.170135498046875 +86475 -0.035400390625 +86476 0.16552734375 +86477 -0.011260986328125 +86478 0.15728759765625 +86479 0.013916015625 +86480 0.150787353515625 +86481 0.039794921875 +86482 0.12200927734375 +86483 0.059661865234375 +86484 0.080108642578125 +86485 0.074127197265625 +86486 0.05126953125 +86487 0.087646484375 +86488 0.062896728515625 +86489 0.105194091796875 +86490 0.09271240234375 +86491 0.121246337890625 +86492 0.092987060546875 +86493 0.1251220703125 +86494 0.07855224609375 +86495 0.1199951171875 +86496 0.06427001953125 +86497 0.109344482421875 +86498 0.0347900390625 +86499 0.090423583984375 +86500 -0.01171875 +86501 0.06365966796875 +86502 -0.056060791015625 +86503 0.034210205078125 +86504 -0.055511474609375 +86505 0.012481689453125 +86506 -0.010467529296875 +86507 -0.00030517578125 +86508 0.02508544921875 +86509 -0.01458740234375 +86510 0.025665283203125 +86511 -0.03466796875 +86512 0.017333984375 +86513 -0.053863525390625 +86514 0.00189208984375 +86515 -0.0709228515625 +86516 -0.03173828125 +86517 -0.087615966796875 +86518 -0.071502685546875 +86519 -0.100921630859375 +86520 -0.13543701171875 +86521 -0.1146240234375 +86522 -0.219970703125 +86523 -0.128082275390625 +86524 -0.300506591796875 +86525 -0.1363525390625 +86526 -0.376312255859375 +86527 -0.13995361328125 +86528 -0.416107177734375 +86529 -0.13299560546875 +86530 -0.371124267578125 +86531 -0.106048583984375 +86532 -0.242279052734375 +86533 -0.060333251953125 +86534 -0.069732666015625 +86535 -0.005279541015625 +86536 0.125640869140625 +86537 0.0535888671875 +86538 0.31268310546875 +86539 0.108795166015625 +86540 0.45501708984375 +86541 0.15203857421875 +86542 0.554779052734375 +86543 0.182952880859375 +86544 0.61065673828125 +86545 0.20074462890625 +86546 0.610931396484375 +86547 0.20281982421875 +86548 0.531463623046875 +86549 0.18438720703125 +86550 0.3883056640625 +86551 0.14892578125 +86552 0.23468017578125 +86553 0.107574462890625 +86554 0.095245361328125 +86555 0.0660400390625 +86556 -0.00396728515625 +86557 0.03033447265625 +86558 -0.04852294921875 +86559 0.004241943359375 +86560 -0.055145263671875 +86561 -0.0145263671875 +86562 -0.0758056640625 +86563 -0.035400390625 +86564 -0.138702392578125 +86565 -0.063140869140625 +86566 -0.209197998046875 +86567 -0.09002685546875 +86568 -0.289031982421875 +86569 -0.115753173828125 +86570 -0.37884521484375 +86571 -0.1400146484375 +86572 -0.456329345703125 +86573 -0.1580810546875 +86574 -0.51641845703125 +86575 -0.1689453125 +86576 -0.519287109375 +86577 -0.164794921875 +86578 -0.458251953125 +86579 -0.144622802734375 +86580 -0.384796142578125 +86581 -0.119293212890625 +86582 -0.323699951171875 +86583 -0.09442138671875 +86584 -0.269287109375 +86585 -0.069580078125 +86586 -0.1951904296875 +86587 -0.040283203125 +86588 -0.100006103515625 +86589 -0.007080078125 +86590 -0.01055908203125 +86591 0.02386474609375 +86592 0.1033935546875 +86593 0.057891845703125 +86594 0.24908447265625 +86595 0.095916748046875 +86596 0.373199462890625 +86597 0.126861572265625 +86598 0.45806884765625 +86599 0.14691162109375 +86600 0.511474609375 +86601 0.157562255859375 +86602 0.565399169921875 +86603 0.165313720703125 +86604 0.61138916015625 +86605 0.168701171875 +86606 0.5897216796875 +86607 0.15618896484375 +86608 0.4906005859375 +86609 0.1263427734375 +86610 0.33148193359375 +86611 0.083251953125 +86612 0.147796630859375 +86613 0.03466796875 +86614 -0.01873779296875 +86615 -0.010406494140625 +86616 -0.140289306640625 +86617 -0.045745849609375 +86618 -0.191986083984375 +86619 -0.0657958984375 +86620 -0.184295654296875 +86621 -0.072174072265625 +86622 -0.161834716796875 +86623 -0.07342529296875 +86624 -0.166595458984375 +86625 -0.07769775390625 +86626 -0.19390869140625 +86627 -0.08392333984375 +86628 -0.22442626953125 +86629 -0.0882568359375 +86630 -0.279754638671875 +86631 -0.09521484375 +86632 -0.3389892578125 +86633 -0.10089111328125 +86634 -0.3543701171875 +86635 -0.096160888671875 +86636 -0.348175048828125 +86637 -0.0859375 +86638 -0.32598876953125 +86639 -0.071868896484375 +86640 -0.2581787109375 +86641 -0.048583984375 +86642 -0.139801025390625 +86643 -0.015594482421875 +86644 0.014617919921875 +86645 0.023681640625 +86646 0.144378662109375 +86647 0.056610107421875 +86648 0.221038818359375 +86649 0.07720947265625 +86650 0.27069091796875 +86651 0.0904541015625 +86652 0.294036865234375 +86653 0.09637451171875 +86654 0.311767578125 +86655 0.099090576171875 +86656 0.339141845703125 +86657 0.1016845703125 +86658 0.360260009765625 +86659 0.10101318359375 +86660 0.360504150390625 +86661 0.09454345703125 +86662 0.308380126953125 +86663 0.07696533203125 +86664 0.18170166015625 +86665 0.044708251953125 +86666 0.0047607421875 +86667 0.0028076171875 +86668 -0.17559814453125 +86669 -0.039520263671875 +86670 -0.3143310546875 +86671 -0.073516845703125 +86672 -0.36785888671875 +86673 -0.0906982421875 +86674 -0.36248779296875 +86675 -0.09552001953125 +86676 -0.343536376953125 +86677 -0.0960693359375 +86678 -0.3018798828125 +86679 -0.09051513671875 +86680 -0.231414794921875 +86681 -0.07763671875 +86682 -0.117645263671875 +86683 -0.054840087890625 +86684 0.007049560546875 +86685 -0.02825927734375 +86686 0.087982177734375 +86687 -0.008209228515625 +86688 0.13946533203125 +86689 0.00762939453125 +86690 0.17425537109375 +86691 0.021209716796875 +86692 0.188201904296875 +86693 0.031341552734375 +86694 0.171234130859375 +86695 0.035736083984375 +86696 0.118438720703125 +86697 0.033111572265625 +86698 0.05706787109375 +86699 0.028106689453125 +86700 -0.010711669921875 +86701 0.020782470703125 +86702 -0.0914306640625 +86703 0.009674072265625 +86704 -0.162322998046875 +86705 -0.001129150390625 +86706 -0.194549560546875 +86707 -0.006439208984375 +86708 -0.1492919921875 +86709 0.000885009765625 +86710 -0.02166748046875 +86711 0.021820068359375 +86712 0.124053955078125 +86713 0.04473876953125 +86714 0.211151123046875 +86715 0.055755615234375 +86716 0.240447998046875 +86717 0.05535888671875 +86718 0.242218017578125 +86719 0.049468994140625 +86720 0.2257080078125 +86721 0.040130615234375 +86722 0.194366455078125 +86723 0.0283203125 +86724 0.115509033203125 +86725 0.008331298828125 +86726 0.0128173828125 +86727 -0.01513671875 +86728 -0.053802490234375 +86729 -0.030853271484375 +86730 -0.110626220703125 +86731 -0.043487548828125 +86732 -0.199493408203125 +86733 -0.0606689453125 +86734 -0.29437255859375 +86735 -0.07757568359375 +86736 -0.33221435546875 +86737 -0.08270263671875 +86738 -0.27972412109375 +86739 -0.070068359375 +86740 -0.185333251953125 +86741 -0.048797607421875 +86742 -0.128204345703125 +86743 -0.033660888671875 +86744 -0.115692138671875 +86745 -0.026275634765625 +86746 -0.116455078125 +86747 -0.021209716796875 +86748 -0.105926513671875 +86749 -0.01422119140625 +86750 -0.053955078125 +86751 0.0 +86752 0.048797607421875 +86753 0.02288818359375 +86754 0.157318115234375 +86755 0.04595947265625 +86756 0.212005615234375 +86757 0.058135986328125 +86758 0.218475341796875 +86759 0.060333251953125 +86760 0.23724365234375 +86761 0.06365966796875 +86762 0.30535888671875 +86763 0.074981689453125 +86764 0.38128662109375 +86765 0.086761474609375 +86766 0.404449462890625 +86767 0.08795166015625 +86768 0.3944091796875 +86769 0.082366943359375 +86770 0.3885498046875 +86771 0.077117919921875 +86772 0.362640380859375 +86773 0.0679931640625 +86774 0.27362060546875 +86775 0.047332763671875 +86776 0.11712646484375 +86777 0.014556884765625 +86778 -0.054901123046875 +86779 -0.020538330078125 +86780 -0.19085693359375 +86781 -0.04827880859375 +86782 -0.28570556640625 +86783 -0.067626953125 +86784 -0.339263916015625 +86785 -0.079071044921875 +86786 -0.3775634765625 +86787 -0.087127685546875 +86788 -0.445709228515625 +86789 -0.098663330078125 +86790 -0.535064697265625 +86791 -0.112060546875 +86792 -0.629058837890625 +86793 -0.1246337890625 +86794 -0.697601318359375 +86795 -0.131805419921875 +86796 -0.70391845703125 +86797 -0.128082275390625 +86798 -0.6424560546875 +86799 -0.11285400390625 +86800 -0.491241455078125 +86801 -0.0831298828125 +86802 -0.265716552734375 +86803 -0.041656494140625 +86804 -0.023712158203125 +86805 0.0023193359375 +86806 0.201751708984375 +86807 0.043365478515625 +86808 0.375823974609375 +86809 0.075836181640625 +86810 0.485076904296875 +86811 0.09735107421875 +86812 0.56884765625 +86813 0.113616943359375 +86814 0.634765625 +86815 0.1256103515625 +86816 0.63763427734375 +86817 0.12640380859375 +86818 0.5660400390625 +86819 0.1142578125 +86820 0.4720458984375 +86821 0.097198486328125 +86822 0.40692138671875 +86823 0.083221435546875 +86824 0.3778076171875 +86825 0.07366943359375 +86826 0.376953125 +86827 0.06768798828125 +86828 0.371978759765625 +86829 0.060638427734375 +86830 0.313140869140625 +86831 0.045318603515625 +86832 0.184417724609375 +86833 0.0196533203125 +86834 0.011199951171875 +86835 -0.012115478515625 +86836 -0.171051025390625 +86837 -0.0443115234375 +86838 -0.33740234375 +86839 -0.07293701171875 +86840 -0.47198486328125 +86841 -0.095428466796875 +86842 -0.560394287109375 +86843 -0.109527587890625 +86844 -0.58056640625 +86845 -0.11187744140625 +86846 -0.54754638671875 +86847 -0.1048583984375 +86848 -0.508575439453125 +86849 -0.095794677734375 +86850 -0.459503173828125 +86851 -0.084259033203125 +86852 -0.394378662109375 +86853 -0.069580078125 +86854 -0.35260009765625 +86855 -0.058013916015625 +86856 -0.31170654296875 +86857 -0.046478271484375 +86858 -0.197418212890625 +86859 -0.023956298828125 +86860 -0.007965087890625 +86861 0.009521484375 +86862 0.207489013671875 +86863 0.04620361328125 +86864 0.409210205078125 +86865 0.079864501953125 +86866 0.57208251953125 +86867 0.1065673828125 +86868 0.66595458984375 +86869 0.12164306640625 +86870 0.65875244140625 +86871 0.120208740234375 +86872 0.56744384765625 +86873 0.10491943359375 +86874 0.431396484375 +86875 0.08184814453125 +86876 0.29443359375 +86877 0.057830810546875 +86878 0.182464599609375 +86879 0.0369873046875 +86880 0.06365966796875 +86881 0.014739990234375 +86882 -0.075958251953125 +86883 -0.010772705078125 +86884 -0.189422607421875 +86885 -0.032196044921875 +86886 -0.271942138671875 +86887 -0.048553466796875 +86888 -0.342529296875 +86889 -0.06256103515625 +86890 -0.364166259765625 +86891 -0.068450927734375 +86892 -0.327239990234375 +86893 -0.064666748046875 +86894 -0.2769775390625 +86895 -0.0579833984375 +86896 -0.253692626953125 +86897 -0.05450439453125 +86898 -0.24365234375 +86899 -0.0521240234375 +86900 -0.1983642578125 +86901 -0.043548583984375 +86902 -0.116241455078125 +86903 -0.028656005859375 +86904 -0.036834716796875 +86905 -0.013641357421875 +86906 0.034881591796875 +86907 0.00054931640625 +86908 0.09124755859375 +86909 0.0125732421875 +86910 0.10888671875 +86911 0.0186767578125 +86912 0.125518798828125 +86913 0.0244140625 +86914 0.15771484375 +86915 0.032135009765625 +86916 0.17828369140625 +86917 0.037567138671875 +86918 0.17108154296875 +86919 0.03814697265625 +86920 0.129974365234375 +86921 0.032867431640625 +86922 0.082427978515625 +86923 0.025848388671875 +86924 0.027679443359375 +86925 0.01702880859375 +86926 -0.065643310546875 +86927 0.001678466796875 +86928 -0.15936279296875 +86929 -0.014312744140625 +86930 -0.21307373046875 +86931 -0.024658203125 +86932 -0.234649658203125 +86933 -0.03045654296875 +86934 -0.2001953125 +86935 -0.027923583984375 +86936 -0.119171142578125 +86937 -0.01837158203125 +86938 -0.024749755859375 +86939 -0.00665283203125 +86940 0.085784912109375 +86941 0.007720947265625 +86942 0.178131103515625 +86943 0.0196533203125 +86944 0.215576171875 +86945 0.023712158203125 +86946 0.211456298828125 +86947 0.02197265625 +86948 0.17523193359375 +86949 0.015960693359375 +86950 0.128753662109375 +86951 0.009002685546875 +86952 0.1019287109375 +86953 0.005615234375 +86954 0.0743408203125 +86955 0.002655029296875 +86956 0.04327392578125 +86957 -0.0003662109375 +86958 0.038177490234375 +86959 0.000885009765625 +86960 0.076263427734375 +86961 0.0089111328125 +86962 0.14105224609375 +86963 0.02105712890625 +86964 0.186431884765625 +86965 0.030181884765625 +86966 0.188812255859375 +86967 0.0325927734375 +86968 0.1390380859375 +86969 0.02679443359375 +86970 0.041778564453125 +86971 0.013427734375 +86972 -0.079437255859375 +86973 -0.00396728515625 +86974 -0.219390869140625 +86975 -0.024658203125 +86976 -0.367828369140625 +86977 -0.047088623046875 +86978 -0.494873046875 +86979 -0.066680908203125 +86980 -0.556243896484375 +86981 -0.076690673828125 +86982 -0.508697509765625 +86983 -0.070556640625 +86984 -0.3756103515625 +86985 -0.051727294921875 +86986 -0.218902587890625 +86987 -0.029541015625 +86988 -0.063751220703125 +86989 -0.007720947265625 +86990 0.091552734375 +86991 0.0140380859375 +86992 0.23602294921875 +86993 0.0341796875 +86994 0.342987060546875 +86995 0.04876708984375 +86996 0.39520263671875 +86997 0.055267333984375 +86998 0.389373779296875 +86999 0.053253173828125 +87000 0.324249267578125 +87001 0.042572021484375 +87002 0.224090576171875 +87003 0.0269775390625 +87004 0.124267578125 +87005 0.0118408203125 +87006 0.037078857421875 +87007 -0.000946044921875 +87008 -0.010101318359375 +87009 -0.00726318359375 +87010 -0.019439697265625 +87011 -0.00750732421875 +87012 -0.022796630859375 +87013 -0.006622314453125 +87014 -0.001556396484375 +87015 -0.0018310546875 +87016 0.056304931640625 +87017 0.008514404296875 +87018 0.106719970703125 +87019 0.017669677734375 +87020 0.096893310546875 +87021 0.01751708984375 +87022 0.042694091796875 +87023 0.010406494140625 +87024 -0.018035888671875 +87025 0.002044677734375 +87026 -0.07586669921875 +87027 -0.006134033203125 +87028 -0.11944580078125 +87029 -0.012420654296875 +87030 -0.15972900390625 +87031 -0.01849365234375 +87032 -0.202606201171875 +87033 -0.025238037109375 +87034 -0.24859619140625 +87035 -0.032684326171875 +87036 -0.30517578125 +87037 -0.041961669921875 +87038 -0.36212158203125 +87039 -0.051483154296875 +87040 -0.39141845703125 +87041 -0.05706787109375 +87042 -0.35528564453125 +87043 -0.053070068359375 +87044 -0.249969482421875 +87045 -0.03875732421875 +87046 -0.092864990234375 +87047 -0.016876220703125 +87048 0.08905029296875 +87049 0.00872802734375 +87050 0.2352294921875 +87051 0.0302734375 +87052 0.318817138671875 +87053 0.04412841796875 +87054 0.358642578125 +87055 0.05218505859375 +87056 0.347747802734375 +87057 0.053375244140625 +87058 0.28564453125 +87059 0.0474853515625 +87060 0.223175048828125 +87061 0.040557861328125 +87062 0.196746826171875 +87063 0.0369873046875 +87064 0.179840087890625 +87065 0.033660888671875 +87066 0.155548095703125 +87067 0.028656005859375 +87068 0.151214599609375 +87069 0.02545166015625 +87070 0.156951904296875 +87071 0.0230712890625 +87072 0.13177490234375 +87073 0.01678466796875 +87074 0.100799560546875 +87075 0.009796142578125 +87076 0.087127685546875 +87077 0.005096435546875 +87078 0.05487060546875 +87079 -0.001434326171875 +87080 -0.009002685546875 +87081 -0.01123046875 +87082 -0.10400390625 +87083 -0.02410888671875 +87084 -0.229400634765625 +87085 -0.0399169921875 +87086 -0.35552978515625 +87087 -0.055084228515625 +87088 -0.441925048828125 +87089 -0.06475830078125 +87090 -0.473846435546875 +87091 -0.067230224609375 +87092 -0.464813232421875 +87093 -0.064239501953125 +87094 -0.419097900390625 +87095 -0.056396484375 +87096 -0.334320068359375 +87097 -0.0435791015625 +87098 -0.227935791015625 +87099 -0.02801513671875 +87100 -0.12347412109375 +87101 -0.0126953125 +87102 -0.02764892578125 +87103 0.00140380859375 +87104 0.077667236328125 +87105 0.016326904296875 +87106 0.2132568359375 +87107 0.034454345703125 +87108 0.38885498046875 +87109 0.05682373046875 +87110 0.582794189453125 +87111 0.080780029296875 +87112 0.734039306640625 +87113 0.0989990234375 +87114 0.800140380859375 +87115 0.106414794921875 +87116 0.7783203125 +87117 0.10272216796875 +87118 0.6651611328125 +87119 0.08758544921875 +87120 0.45965576171875 +87121 0.061004638671875 +87122 0.199188232421875 +87123 0.027587890625 +87124 -0.050689697265625 +87125 -0.004638671875 +87126 -0.23297119140625 +87127 -0.028717041015625 +87128 -0.33013916015625 +87129 -0.042449951171875 +87130 -0.368408203125 +87131 -0.04888916015625 +87132 -0.378936767578125 +87133 -0.051666259765625 +87134 -0.376983642578125 +87135 -0.05255126953125 +87136 -0.37969970703125 +87137 -0.053558349609375 +87138 -0.391510009765625 +87139 -0.05517578125 +87140 -0.385345458984375 +87141 -0.054168701171875 +87142 -0.3419189453125 +87143 -0.048248291015625 +87144 -0.28289794921875 +87145 -0.0400390625 +87146 -0.251617431640625 +87147 -0.03485107421875 +87148 -0.266143798828125 +87149 -0.034912109375 +87150 -0.273345947265625 +87151 -0.033966064453125 +87152 -0.216796875 +87153 -0.02532958984375 +87154 -0.128265380859375 +87155 -0.012908935546875 +87156 -0.068145751953125 +87157 -0.0040283203125 +87158 -0.0430908203125 +87159 0.000396728515625 +87160 -0.024444580078125 +87161 0.00372314453125 +87162 0.020721435546875 +87163 0.00982666015625 +87164 0.124481201171875 +87165 0.022552490234375 +87166 0.25787353515625 +87167 0.03839111328125 +87168 0.379119873046875 +87169 0.0523681640625 +87170 0.47991943359375 +87171 0.063507080078125 +87172 0.5281982421875 +87173 0.06805419921875 +87174 0.511138916015625 +87175 0.06451416015625 +87176 0.456207275390625 +87177 0.0562744140625 +87178 0.407470703125 +87179 0.048736572265625 +87180 0.383758544921875 +87181 0.044281005859375 +87182 0.35687255859375 +87183 0.03955078125 +87184 0.31182861328125 +87185 0.032867431640625 +87186 0.250885009765625 +87187 0.024566650390625 +87188 0.1654052734375 +87189 0.013641357421875 +87190 0.035247802734375 +87191 -0.00225830078125 +87192 -0.142059326171875 +87193 -0.023406982421875 +87194 -0.33563232421875 +87195 -0.046142578125 +87196 -0.5345458984375 +87197 -0.069183349609375 +87198 -0.72186279296875 +87199 -0.090545654296875 +87200 -0.836669921875 +87201 -0.102935791015625 +87202 -0.8326416015625 +87203 -0.100921630859375 +87204 -0.7296142578125 +87205 -0.08697509765625 +87206 -0.582550048828125 +87207 -0.067840576171875 +87208 -0.440093994140625 +87209 -0.04937744140625 +87210 -0.324310302734375 +87211 -0.034332275390625 +87212 -0.20147705078125 +87213 -0.0186767578125 +87214 -0.044647216796875 +87215 0.000762939453125 +87216 0.103973388671875 +87217 0.01885986328125 +87218 0.202392578125 +87219 0.03057861328125 +87220 0.264495849609375 +87221 0.03759765625 +87222 0.338897705078125 +87223 0.0457763671875 +87224 0.443817138671875 +87225 0.057373046875 +87226 0.545074462890625 +87227 0.068328857421875 +87228 0.6173095703125 +87229 0.075653076171875 +87230 0.6524658203125 +87231 0.078460693359375 +87232 0.66339111328125 +87233 0.078399658203125 +87234 0.6561279296875 +87235 0.076263427734375 +87236 0.606781005859375 +87237 0.069244384765625 +87238 0.501190185546875 +87239 0.055694580078125 +87240 0.352783203125 +87241 0.037261962890625 +87242 0.176544189453125 +87243 0.015777587890625 +87244 -0.034820556640625 +87245 -0.00958251953125 +87246 -0.258209228515625 +87247 -0.036041259765625 +87248 -0.44244384765625 +87249 -0.0574951171875 +87250 -0.5753173828125 +87251 -0.072540283203125 +87252 -0.65203857421875 +87253 -0.080657958984375 +87254 -0.641632080078125 +87255 -0.078216552734375 +87256 -0.562164306640625 +87257 -0.06744384765625 +87258 -0.458038330078125 +87259 -0.053741455078125 +87260 -0.350555419921875 +87261 -0.039703369140625 +87262 -0.260528564453125 +87263 -0.027923583984375 +87264 -0.192108154296875 +87265 -0.0189208984375 +87266 -0.141937255859375 +87267 -0.0123291015625 +87268 -0.1021728515625 +87269 -0.007232666015625 +87270 -0.062896728515625 +87271 -0.00244140625 +87272 -0.011932373046875 +87273 0.00347900390625 +87274 0.062835693359375 +87275 0.011993408203125 +87276 0.148712158203125 +87277 0.021636962890625 +87278 0.241729736328125 +87279 0.031951904296875 +87280 0.34912109375 +87281 0.043853759765625 +87282 0.457305908203125 +87283 0.0557861328125 +87284 0.54388427734375 +87285 0.065093994140625 +87286 0.5728759765625 +87287 0.067535400390625 +87288 0.506591796875 +87289 0.058624267578125 +87290 0.351226806640625 +87291 0.0391845703125 +87292 0.146514892578125 +87293 0.014007568359375 +87294 -0.05523681640625 +87295 -0.010589599609375 +87296 -0.21624755859375 +87297 -0.02972412109375 +87298 -0.334930419921875 +87299 -0.043426513671875 +87300 -0.402984619140625 +87301 -0.051513671875 +87302 -0.4412841796875 +87303 -0.0557861328125 +87304 -0.49578857421875 +87305 -0.060333251953125 +87306 -0.5601806640625 +87307 -0.064697265625 +87308 -0.600738525390625 +87309 -0.0660400390625 +87310 -0.584228515625 +87311 -0.061614990234375 +87312 -0.47930908203125 +87313 -0.04888916015625 +87314 -0.27935791015625 +87315 -0.027496337890625 +87316 -0.0089111328125 +87317 0.000152587890625 +87318 0.268798828125 +87319 0.02825927734375 +87320 0.482818603515625 +87321 0.050384521484375 +87322 0.60369873046875 +87323 0.063751220703125 +87324 0.650421142578125 +87325 0.069915771484375 +87326 0.66400146484375 +87327 0.0723876953125 +87328 0.6414794921875 +87329 0.07086181640625 +87330 0.572540283203125 +87331 0.064453125 +87332 0.498138427734375 +87333 0.05682373046875 +87334 0.439453125 +87335 0.049896240234375 +87336 0.375518798828125 +87337 0.041961669921875 +87338 0.274505615234375 +87339 0.03033447265625 +87340 0.1087646484375 +87341 0.01275634765625 +87342 -0.099395751953125 +87343 -0.00860595703125 +87344 -0.3182373046875 +87345 -0.030792236328125 +87346 -0.5489501953125 +87347 -0.05377197265625 +87348 -0.7738037109375 +87349 -0.0758056640625 +87350 -0.86383056640625 +87351 -0.0921630859375 +87352 -0.870391845703125 +87353 -0.099822998046875 +87354 -0.86895751953125 +87355 -0.100311279296875 +87356 -0.861053466796875 +87357 -0.094757080078125 +87358 -0.765869140625 +87359 -0.0816650390625 +87360 -0.5301513671875 +87361 -0.06011962890625 +87362 -0.214691162109375 +87363 -0.030853271484375 +87364 0.137359619140625 +87365 0.00225830078125 +87366 0.474822998046875 +87367 0.034576416015625 +87368 0.76239013671875 +87369 0.06280517578125 +87370 0.867462158203125 +87371 0.084442138671875 +87372 0.870361328125 +87373 0.099395751953125 +87374 0.86480712890625 +87375 0.10650634765625 +87376 0.831817626953125 +87377 0.106170654296875 +87378 0.677581787109375 +87379 0.1004638671875 +87380 0.495880126953125 +87381 0.08990478515625 +87382 0.30767822265625 +87383 0.076080322265625 +87384 0.116180419921875 +87385 0.0592041015625 +87386 -0.110748291015625 +87387 0.03656005859375 +87388 -0.381805419921875 +87389 0.007598876953125 +87390 -0.6572265625 +87391 -0.0238037109375 +87392 -0.857421875 +87393 -0.052276611328125 +87394 -0.870391845703125 +87395 -0.073944091796875 +87396 -0.870391845703125 +87397 -0.088104248046875 +87398 -0.86444091796875 +87399 -0.097015380859375 +87400 -0.85723876953125 +87401 -0.103729248046875 +87402 -0.790008544921875 +87403 -0.1065673828125 +87404 -0.62847900390625 +87405 -0.1007080078125 +87406 -0.3956298828125 +87407 -0.085845947265625 +87408 -0.126708984375 +87409 -0.0648193359375 +87410 0.150115966796875 +87411 -0.040069580078125 +87412 0.424041748046875 +87413 -0.012664794921875 +87414 0.670623779296875 +87415 0.014984130859375 +87416 0.854522705078125 +87417 0.039398193359375 +87418 0.866485595703125 +87419 0.058929443359375 +87420 0.86920166015625 +87421 0.0721435546875 +87422 0.8653564453125 +87423 0.08056640625 +87424 0.857147216796875 +87425 0.085296630859375 +87426 0.766845703125 +87427 0.08599853515625 +87428 0.628509521484375 +87429 0.083099365234375 +87430 0.462127685546875 +87431 0.075958251953125 +87432 0.297210693359375 +87433 0.066802978515625 +87434 0.14862060546875 +87435 0.056671142578125 +87436 -0.00537109375 +87437 0.0435791015625 +87438 -0.15753173828125 +87439 0.028228759765625 +87440 -0.31304931640625 +87441 0.010345458984375 +87442 -0.48876953125 +87443 -0.01123046875 +87444 -0.6416015625 +87445 -0.032318115234375 +87446 -0.751373291015625 +87447 -0.050689697265625 +87448 -0.84619140625 +87449 -0.06829833984375 +87450 -0.861297607421875 +87451 -0.083770751953125 +87452 -0.863250732421875 +87453 -0.09417724609375 +87454 -0.856597900390625 +87455 -0.096649169921875 +87456 -0.7498779296875 +87457 -0.09222412109375 +87458 -0.624542236328125 +87459 -0.08599853515625 +87460 -0.47808837890625 +87461 -0.0760498046875 +87462 -0.253387451171875 +87463 -0.0572509765625 +87464 0.003692626953125 +87465 -0.033660888671875 +87466 0.2257080078125 +87467 -0.011322021484375 +87468 0.427154541015625 +87469 0.01080322265625 +87470 0.643218994140625 +87471 0.0355224609375 +87472 0.855926513671875 +87473 0.06195068359375 +87474 0.870361328125 +87475 0.0849609375 +87476 0.870361328125 +87477 0.10015869140625 +87478 0.862762451171875 +87479 0.108123779296875 +87480 0.79669189453125 +87481 0.108612060546875 +87482 0.595794677734375 +87483 0.10076904296875 +87484 0.362152099609375 +87485 0.087127685546875 +87486 0.1270751953125 +87487 0.070159912109375 +87488 -0.086944580078125 +87489 0.051727294921875 +87490 -0.2784423828125 +87491 0.032012939453125 +87492 -0.484832763671875 +87493 0.00799560546875 +87494 -0.729583740234375 +87495 -0.02197265625 +87496 -0.86688232421875 +87497 -0.053375244140625 +87498 -0.870391845703125 +87499 -0.08062744140625 +87500 -0.86859130859375 +87501 -0.103240966796875 +87502 -0.86279296875 +87503 -0.121002197265625 +87504 -0.817962646484375 +87505 -0.130706787109375 +87506 -0.6116943359375 +87507 -0.128387451171875 +87508 -0.3128662109375 +87509 -0.113372802734375 +87510 0.039398193359375 +87511 -0.088623046875 +87512 0.422821044921875 +87513 -0.055908203125 +87514 0.805145263671875 +87515 -0.0181884765625 +87516 0.870361328125 +87517 0.018524169921875 +87518 0.870361328125 +87519 0.049163818359375 +87520 0.860015869140625 +87521 0.072723388671875 +87522 0.727935791015625 +87523 0.088470458984375 +87524 0.48114013671875 +87525 0.095855712890625 +87526 0.2059326171875 +87527 0.097015380859375 +87528 -0.06103515625 +87529 0.0938720703125 +87530 -0.29913330078125 +87531 0.0872802734375 +87532 -0.516204833984375 +87533 0.075927734375 +87534 -0.7252197265625 +87535 0.0584716796875 +87536 -0.85980224609375 +87537 0.037078857421875 +87538 -0.870391845703125 +87539 0.0147705078125 +87540 -0.870391845703125 +87541 -0.005767822265625 +87542 -0.858062744140625 +87543 -0.020233154296875 +87544 -0.673004150390625 +87545 -0.028228759765625 +87546 -0.42694091796875 +87547 -0.034332275390625 +87548 -0.2100830078125 +87549 -0.0423583984375 +87550 -0.0362548828125 +87551 -0.052093505859375 +87552 0.10943603515625 +87553 -0.060577392578125 +87554 0.23516845703125 +87555 -0.065826416015625 +87556 0.373687744140625 +87557 -0.065399169921875 +87558 0.517791748046875 +87559 -0.05950927734375 +87560 0.602783203125 +87561 -0.051849365234375 +87562 0.635711669921875 +87563 -0.042388916015625 +87564 0.655181884765625 +87565 -0.029541015625 +87566 0.65948486328125 +87567 -0.014190673828125 +87568 0.651275634765625 +87569 0.002838134765625 +87570 0.61846923828125 +87571 0.019805908203125 +87572 0.53753662109375 +87573 0.0343017578125 +87574 0.404144287109375 +87575 0.0450439453125 +87576 0.22186279296875 +87577 0.05126953125 +87578 0.003997802734375 +87579 0.05291748046875 +87580 -0.22100830078125 +87581 0.0509033203125 +87582 -0.42449951171875 +87583 0.04632568359375 +87584 -0.579833984375 +87585 0.040435791015625 +87586 -0.641876220703125 +87587 0.03570556640625 +87588 -0.6177978515625 +87589 0.03192138671875 +87590 -0.575531005859375 +87591 0.025665283203125 +87592 -0.526336669921875 +87593 0.016876220703125 +87594 -0.42645263671875 +87595 0.00872802734375 +87596 -0.2581787109375 +87597 0.00299072265625 +87598 -0.068695068359375 +87599 -0.0020751953125 +87600 0.09222412109375 +87601 -0.00836181640625 +87602 0.232147216796875 +87603 -0.014617919921875 +87604 0.3509521484375 +87605 -0.020111083984375 +87606 0.410064697265625 +87607 -0.026397705078125 +87608 0.372955322265625 +87609 -0.035064697265625 +87610 0.2554931640625 +87611 -0.044952392578125 +87612 0.10711669921875 +87613 -0.053192138671875 +87614 -0.052886962890625 +87615 -0.058807373046875 +87616 -0.186279296875 +87617 -0.059967041015625 +87618 -0.23291015625 +87619 -0.0537109375 +87620 -0.209442138671875 +87621 -0.041534423828125 +87622 -0.174163818359375 +87623 -0.02734375 +87624 -0.126739501953125 +87625 -0.011871337890625 +87626 -0.048126220703125 +87627 0.005218505859375 +87628 0.0426025390625 +87629 0.022186279296875 +87630 0.10748291015625 +87631 0.036285400390625 +87632 0.1409912109375 +87633 0.046661376953125 +87634 0.19708251953125 +87635 0.055908203125 +87636 0.273651123046875 +87637 0.063690185546875 +87638 0.31768798828125 +87639 0.066925048828125 +87640 0.341094970703125 +87641 0.066314697265625 +87642 0.368011474609375 +87643 0.063385009765625 +87644 0.37249755859375 +87645 0.0570068359375 +87646 0.30072021484375 +87647 0.044586181640625 +87648 0.1517333984375 +87649 0.026580810546875 +87650 -0.01470947265625 +87651 0.00689697265625 +87652 -0.1883544921875 +87653 -0.013275146484375 +87654 -0.372711181640625 +87655 -0.0335693359375 +87656 -0.51397705078125 +87657 -0.050445556640625 +87658 -0.57177734375 +87659 -0.061187744140625 +87660 -0.53948974609375 +87661 -0.0650634765625 +87662 -0.43511962890625 +87663 -0.06280517578125 +87664 -0.2962646484375 +87665 -0.056396484375 +87666 -0.161102294921875 +87667 -0.047943115234375 +87668 -0.0435791015625 +87669 -0.038360595703125 +87670 0.060394287109375 +87671 -0.02764892578125 +87672 0.13665771484375 +87673 -0.01690673828125 +87674 0.170135498046875 +87675 -0.00738525390625 +87676 0.16552734375 +87677 0.000732421875 +87678 0.15728759765625 +87679 0.008880615234375 +87680 0.150787353515625 +87681 0.016876220703125 +87682 0.12200927734375 +87683 0.022918701171875 +87684 0.080108642578125 +87685 0.027130126953125 +87686 0.05126953125 +87687 0.030670166015625 +87688 0.062896728515625 +87689 0.034820556640625 +87690 0.09271240234375 +87691 0.038177490234375 +87692 0.092987060546875 +87693 0.038055419921875 +87694 0.07855224609375 +87695 0.03533935546875 +87696 0.06427001953125 +87697 0.031005859375 +87698 0.0347900390625 +87699 0.0244140625 +87700 -0.01171875 +87701 0.015777587890625 +87702 -0.056060791015625 +87703 0.00653076171875 +87704 -0.055511474609375 +87705 -0.000518798828125 +87706 -0.010467529296875 +87707 -0.0050048828125 +87708 0.02508544921875 +87709 -0.009521484375 +87710 0.025665283203125 +87711 -0.01519775390625 +87712 0.017333984375 +87713 -0.020263671875 +87714 0.00189208984375 +87715 -0.0244140625 +87716 -0.03173828125 +87717 -0.02813720703125 +87718 -0.071502685546875 +87719 -0.03070068359375 +87720 -0.13543701171875 +87721 -0.033111572265625 +87722 -0.219970703125 +87723 -0.0352783203125 +87724 -0.300506591796875 +87725 -0.035980224609375 +87726 -0.376312255859375 +87727 -0.035430908203125 +87728 -0.416107177734375 +87729 -0.03216552734375 +87730 -0.371124267578125 +87731 -0.0238037109375 +87732 -0.242279052734375 +87733 -0.0107421875 +87734 -0.069732666015625 +87735 0.004425048828125 +87736 0.125640869140625 +87737 0.020263671875 +87738 0.31268310546875 +87739 0.0347900390625 +87740 0.45501708984375 +87741 0.04571533203125 +87742 0.554779052734375 +87743 0.05303955078125 +87744 0.61065673828125 +87745 0.056640625 +87746 0.610931396484375 +87747 0.055908203125 +87748 0.531463623046875 +87749 0.049560546875 +87750 0.3883056640625 +87751 0.038604736328125 +87752 0.23468017578125 +87753 0.0262451171875 +87754 0.095245361328125 +87755 0.014129638671875 +87756 -0.00396728515625 +87757 0.003936767578125 +87758 -0.04852294921875 +87759 -0.0032958984375 +87760 -0.055145263671875 +87761 -0.008209228515625 +87762 -0.0758056640625 +87763 -0.01348876953125 +87764 -0.138702392578125 +87765 -0.020477294921875 +87766 -0.209197998046875 +87767 -0.027069091796875 +87768 -0.289031982421875 +87769 -0.033233642578125 +87770 -0.37884521484375 +87771 -0.0389404296875 +87772 -0.456329345703125 +87773 -0.04296875 +87774 -0.51641845703125 +87775 -0.0450439453125 +87776 -0.519287109375 +87777 -0.04302978515625 +87778 -0.458251953125 +87779 -0.036712646484375 +87780 -0.384796142578125 +87781 -0.029144287109375 +87782 -0.323699951171875 +87783 -0.02191162109375 +87784 -0.269287109375 +87785 -0.014923095703125 +87786 -0.1951904296875 +87787 -0.00689697265625 +87788 -0.100006103515625 +87789 0.001983642578125 +87790 -0.01055908203125 +87791 0.010040283203125 +87792 0.1033935546875 +87793 0.018798828125 +87794 0.24908447265625 +87795 0.028533935546875 +87796 0.373199462890625 +87797 0.03619384765625 +87798 0.45806884765625 +87799 0.040802001953125 +87800 0.511474609375 +87801 0.042816162109375 +87802 0.565399169921875 +87803 0.044097900390625 +87804 0.61138916015625 +87805 0.0443115234375 +87806 0.5897216796875 +87807 0.040252685546875 +87808 0.4906005859375 +87809 0.031646728515625 +87810 0.33148193359375 +87811 0.019775390625 +87812 0.147796630859375 +87813 0.006683349609375 +87814 -0.01873779296875 +87815 -0.005340576171875 +87816 -0.140289306640625 +87817 -0.014739990234375 +87818 -0.191986083984375 +87819 -0.020111083984375 +87820 -0.184295654296875 +87821 -0.021820068359375 +87822 -0.161834716796875 +87823 -0.02203369140625 +87824 -0.166595458984375 +87825 -0.022796630859375 +87826 -0.19390869140625 +87827 -0.02386474609375 +87828 -0.22442626953125 +87829 -0.024322509765625 +87830 -0.279754638671875 +87831 -0.025299072265625 +87832 -0.3389892578125 +87833 -0.025909423828125 +87834 -0.3543701171875 +87835 -0.02386474609375 +87836 -0.348175048828125 +87837 -0.02044677734375 +87838 -0.32598876953125 +87839 -0.016143798828125 +87840 -0.2581787109375 +87841 -0.0096435546875 +87842 -0.139801025390625 +87843 -0.000885009765625 +87844 0.014617919921875 +87845 0.00927734375 +87846 0.144378662109375 +87847 0.01763916015625 +87848 0.221038818359375 +87849 0.022735595703125 +87850 0.27069091796875 +87851 0.025787353515625 +87852 0.294036865234375 +87853 0.02685546875 +87854 0.311767578125 +87855 0.0269775390625 +87856 0.339141845703125 +87857 0.026885986328125 +87858 0.360260009765625 +87859 0.02557373046875 +87860 0.360504150390625 +87861 0.022552490234375 +87862 0.308380126953125 +87863 0.01739501953125 +87864 0.18170166015625 +87865 0.009857177734375 +87866 0.0047607421875 +87867 0.000885009765625 +87868 -0.17559814453125 +87869 -0.008056640625 +87870 -0.3143310546875 +87871 -0.015625 +87872 -0.36785888671875 +87873 -0.0205078125 +87874 -0.36248779296875 +87875 -0.023162841796875 +87876 -0.343536376953125 +87877 -0.024566650390625 +87878 -0.3018798828125 +87879 -0.0244140625 +87880 -0.231414794921875 +87881 -0.022552490234375 +87882 -0.117645263671875 +87883 -0.0186767578125 +87884 0.007049560546875 +87885 -0.013671875 +87886 0.087982177734375 +87887 -0.00897216796875 +87888 0.13946533203125 +87889 -0.004425048828125 +87890 0.17425537109375 +87891 6.103515625e-05 +87892 0.188201904296875 +87893 0.004180908203125 +87894 0.171234130859375 +87895 0.007476806640625 +87896 0.118438720703125 +87897 0.0096435546875 +87898 0.05706787109375 +87899 0.01116943359375 +87900 -0.010711669921875 +87901 0.011962890625 +87902 -0.0914306640625 +87903 0.01171875 +87904 -0.162322998046875 +87905 0.010894775390625 +87906 -0.194549560546875 +87907 0.010162353515625 +87908 -0.1492919921875 +87909 0.010467529296875 +87910 -0.02166748046875 +87911 0.011993408203125 +87912 0.124053955078125 +87913 0.0133056640625 +87914 0.211151123046875 +87915 0.012664794921875 +87916 0.240447998046875 +87917 0.010284423828125 +87918 0.242218017578125 +87919 0.007049560546875 +87920 0.2257080078125 +87921 0.00341796875 +87922 0.194366455078125 +87923 -0.000335693359375 +87924 0.115509033203125 +87925 -0.00482177734375 +87926 0.0128173828125 +87927 -0.00933837890625 +87928 -0.053802490234375 +87929 -0.012359619140625 +87930 -0.110626220703125 +87931 -0.01446533203125 +87932 -0.199493408203125 +87933 -0.016632080078125 +87934 -0.29437255859375 +87935 -0.018280029296875 +87936 -0.33221435546875 +87937 -0.0179443359375 +87938 -0.27972412109375 +87939 -0.014923095703125 +87940 -0.185333251953125 +87941 -0.010467529296875 +87942 -0.128204345703125 +87943 -0.006591796875 +87944 -0.115692138671875 +87945 -0.003631591796875 +87946 -0.116455078125 +87947 -0.001007080078125 +87948 -0.105926513671875 +87949 0.001708984375 +87950 -0.053955078125 +87951 0.005126953125 +87952 0.048797607421875 +87953 0.009368896484375 +87954 0.157318115234375 +87955 0.01324462890625 +87956 0.212005615234375 +87957 0.015289306640625 +87958 0.218475341796875 +87959 0.015594482421875 +87960 0.23724365234375 +87961 0.015594482421875 +87962 0.30535888671875 +87963 0.016265869140625 +87964 0.38128662109375 +87965 0.016632080078125 +87966 0.404449462890625 +87967 0.015380859375 +87968 0.3944091796875 +87969 0.0130615234375 +87970 0.3885498046875 +87971 0.010711669921875 +87972 0.362640380859375 +87973 0.00787353515625 +87974 0.27362060546875 +87975 0.003662109375 +87976 0.11712646484375 +87977 -0.00189208984375 +87978 -0.054901123046875 +87979 -0.007476806640625 +87980 -0.19085693359375 +87981 -0.01177978515625 +87982 -0.28570556640625 +87983 -0.014678955078125 +87984 -0.339263916015625 +87985 -0.01611328125 +87986 -0.3775634765625 +87987 -0.0167236328125 +87988 -0.445709228515625 +87989 -0.017608642578125 +87990 -0.535064697265625 +87991 -0.01861572265625 +87992 -0.629058837890625 +87993 -0.0194091796875 +87994 -0.697601318359375 +87995 -0.019317626953125 +87996 -0.70391845703125 +87997 -0.017608642578125 +87998 -0.6424560546875 +87999 -0.014251708984375 +88000 -0.491241455078125 +88001 -0.008819580078125 +88002 -0.265716552734375 +88003 -0.001800537109375 +88004 -0.023712158203125 +88005 0.005279541015625 +88006 0.201751708984375 +88007 0.0115966796875 +88008 0.375823974609375 +88009 0.0162353515625 +88010 0.485076904296875 +88011 0.0189208984375 +88012 0.56884765625 +88013 0.0206298828125 +88014 0.634765625 +88015 0.02154541015625 +88016 0.63763427734375 +88017 0.020599365234375 +88018 0.5660400390625 +88019 0.017608642578125 +88020 0.4720458984375 +88021 0.013885498046875 +88022 0.40692138671875 +88023 0.010772705078125 +88024 0.3778076171875 +88025 0.008514404296875 +88026 0.376953125 +88027 0.00701904296875 +88028 0.371978759765625 +88029 0.005584716796875 +88030 0.313140869140625 +88031 0.0030517578125 +88032 0.184417724609375 +88033 -0.000885009765625 +88034 0.011199951171875 +88035 -0.00555419921875 +88036 -0.171051025390625 +88037 -0.010040283203125 +88038 -0.33740234375 +88039 -0.013763427734375 +88040 -0.47198486328125 +88041 -0.016387939453125 +88042 -0.560394287109375 +88043 -0.01763916015625 +88044 -0.58056640625 +88045 -0.01702880859375 +88046 -0.54754638671875 +88047 -0.014984130859375 +88048 -0.508575439453125 +88049 -0.012725830078125 +88050 -0.459503173828125 +88051 -0.010223388671875 +88052 -0.394378662109375 +88053 -0.00738525390625 +88054 -0.35260009765625 +88055 -0.005218505859375 +88056 -0.31170654296875 +88057 -0.00323486328125 +88058 -0.197418212890625 +88059 0.000274658203125 +88060 -0.007965087890625 +88061 0.00531005859375 +88062 0.207489013671875 +88063 0.0106201171875 +88064 0.409210205078125 +88065 0.0152587890625 +88066 0.57208251953125 +88067 0.018341064453125 +88068 0.66595458984375 +88069 0.0194091796875 +88070 0.65875244140625 +88071 0.0184326171875 +88072 0.56744384765625 +88073 0.015838623046875 +88074 0.431396484375 +88075 0.012176513671875 +88076 0.29443359375 +88077 0.008056640625 +88078 0.182464599609375 +88079 0.00390625 +88080 0.06365966796875 +88081 -0.000244140625 +88082 -0.075958251953125 +88083 -0.00433349609375 +88084 -0.189422607421875 +88085 -0.0078125 +88086 -0.271942138671875 +88087 -0.010528564453125 +88088 -0.342529296875 +88089 -0.012542724609375 +88090 -0.364166259765625 +88091 -0.01348876953125 +88092 -0.327239990234375 +88093 -0.013275146484375 +88094 -0.2769775390625 +88095 -0.012298583984375 +88096 -0.253692626953125 +88097 -0.010955810546875 +88098 -0.24365234375 +88099 -0.009246826171875 +88100 -0.1983642578125 +88101 -0.0068359375 +88102 -0.116241455078125 +88103 -0.003875732421875 +88104 -0.036834716796875 +88105 -0.000823974609375 +88106 0.034881591796875 +88107 0.00213623046875 +88108 0.09124755859375 +88109 0.004791259765625 +88110 0.10888671875 +88111 0.006866455078125 +88112 0.125518798828125 +88113 0.008544921875 +88114 0.15771484375 +88115 0.0098876953125 +88116 0.17828369140625 +88117 0.010650634765625 +88118 0.17108154296875 +88119 0.010650634765625 +88120 0.129974365234375 +88121 0.009857177734375 +88122 0.082427978515625 +88123 0.008544921875 +88124 0.027679443359375 +88125 0.00677490234375 +88126 -0.065643310546875 +88127 0.004425048828125 +88128 -0.15936279296875 +88129 0.001861572265625 +88130 -0.21307373046875 +88131 -0.000457763671875 +88132 -0.234649658203125 +88133 -0.00250244140625 +88134 -0.2001953125 +88135 -0.003997802734375 +88136 -0.119171142578125 +88137 -0.00494384765625 +88138 -0.024749755859375 +88139 -0.0054931640625 +88140 0.085784912109375 +88141 -0.005615234375 +88142 0.178131103515625 +88143 -0.0054931640625 +88144 0.215576171875 +88145 -0.005401611328125 +88146 0.211456298828125 +88147 -0.005218505859375 +88148 0.17523193359375 +88149 -0.004913330078125 +88150 0.128753662109375 +88151 -0.004302978515625 +88152 0.1019287109375 +88153 -0.003204345703125 +88154 0.0743408203125 +88155 -0.001861572265625 +88156 0.04327392578125 +88157 -0.00042724609375 +88158 0.038177490234375 +88159 0.001190185546875 +88160 0.076263427734375 +88161 0.003021240234375 +88162 0.14105224609375 +88163 0.0048828125 +88164 0.186431884765625 +88165 0.00634765625 +88166 0.188812255859375 +88167 0.007171630859375 +88168 0.1390380859375 +88169 0.00726318359375 +88170 0.041778564453125 +88171 0.006622314453125 +88172 -0.079437255859375 +88173 0.005462646484375 +88174 -0.219390869140625 +88175 0.00384521484375 +88176 -0.367828369140625 +88177 0.00189208984375 +88178 -0.494873046875 +88179 -9.1552734375e-05 +88180 -0.556243896484375 +88181 -0.001678466796875 +88182 -0.508697509765625 +88183 -0.002471923828125 +88184 -0.3756103515625 +88185 -0.002593994140625 +88186 -0.218902587890625 +88187 -0.002471923828125 +88188 -0.063751220703125 +88189 -0.0023193359375 +88190 0.091552734375 +88191 -0.002044677734375 +88192 0.23602294921875 +88193 -0.001678466796875 +88194 0.342987060546875 +88195 -0.001373291015625 +88196 0.39520263671875 +88197 -0.001251220703125 +88198 0.389373779296875 +88199 -0.001312255859375 +88200 0.324249267578125 +88201 -0.001556396484375 +88202 0.224090576171875 +88203 -0.001800537109375 +88204 0.124267578125 +88205 -0.001800537109375 +88206 0.037078857421875 +88207 -0.00152587890625 +88208 -0.010101318359375 +88209 -0.000823974609375 +88210 -0.019439697265625 +88211 0.00018310546875 +88212 -0.022796630859375 +88213 0.001190185546875 +88214 -0.001556396484375 +88215 0.002288818359375 +88216 0.056304931640625 +88217 0.003509521484375 +88218 0.106719970703125 +88219 0.004486083984375 +88220 0.096893310546875 +88221 0.004730224609375 +88222 0.042694091796875 +88223 0.00439453125 +88224 -0.018035888671875 +88225 0.0037841796875 +88226 -0.07586669921875 +88227 0.00299072265625 +88228 -0.11944580078125 +88229 0.002105712890625 +88230 -0.15972900390625 +88231 0.0010986328125 +88232 -0.202606201171875 +88233 0.0 +88234 -0.24859619140625 +88235 -0.001129150390625 +88236 -0.30517578125 +88237 -0.0023193359375 +88238 -0.36212158203125 +88239 -0.00347900390625 +88240 -0.39141845703125 +88241 -0.00433349609375 +88242 -0.35528564453125 +88243 -0.00457763671875 +88244 -0.249969482421875 +88245 -0.004119873046875 +88246 -0.092864990234375 +88247 -0.003082275390625 +88248 0.08905029296875 +88249 -0.001708984375 +88250 0.2352294921875 +88251 -0.000457763671875 +88252 0.318817138671875 +88253 0.00042724609375 +88254 0.358642578125 +88255 0.001068115234375 +88256 0.347747802734375 +88257 0.00140380859375 +88258 0.28564453125 +88259 0.001373291015625 +88260 0.223175048828125 +88261 0.0013427734375 +88262 0.196746826171875 +88263 0.0015869140625 +88264 0.179840087890625 +88265 0.001922607421875 +88266 0.155548095703125 +88267 0.002166748046875 +88268 0.151214599609375 +88269 0.00250244140625 +88270 0.156951904296875 +88271 0.002838134765625 +88272 0.13177490234375 +88273 0.002838134765625 +88274 0.100799560546875 +88275 0.002685546875 +88276 0.087127685546875 +88277 0.0025634765625 +88278 0.05487060546875 +88279 0.002197265625 +88280 -0.009002685546875 +88281 0.001495361328125 +88282 -0.10400390625 +88283 0.000457763671875 +88284 -0.229400634765625 +88285 -0.0008544921875 +88286 -0.35552978515625 +88287 -0.002197265625 +88288 -0.441925048828125 +88289 -0.003204345703125 +88290 -0.473846435546875 +88291 -0.0037841796875 +88292 -0.464813232421875 +88293 -0.003997802734375 +88294 -0.419097900390625 +88295 -0.003875732421875 +88296 -0.334320068359375 +88297 -0.00335693359375 +88298 -0.227935791015625 +88299 -0.002593994140625 +88300 -0.12347412109375 +88301 -0.00177001953125 +88302 -0.02764892578125 +88303 -0.000946044921875 +88304 0.077667236328125 +88305 0.0 +88306 0.2132568359375 +88307 0.001220703125 +88308 0.38885498046875 +88309 0.002777099609375 +88310 0.582794189453125 +88311 0.004486083984375 +88312 0.734039306640625 +88313 0.005828857421875 +88314 0.800140380859375 +88315 0.0064697265625 +88316 0.7783203125 +88317 0.006378173828125 +88318 0.6651611328125 +88319 0.00555419921875 +88320 0.45965576171875 +88321 0.003509521484375 +88322 0.199188232421875 +88323 0.0 +88324 -0.050689697265625 +88325 -0.00347900390625 +88326 -0.23297119140625 +88327 -0.00482177734375 +88328 -0.33013916015625 +88329 -0.003509521484375 +88330 -0.368408203125 +88331 -0.000732421875 +88332 -0.378936767578125 +88333 0.002105712890625 +88334 -0.376983642578125 +88335 0.00433349609375 +88336 -0.37969970703125 +88337 0.005218505859375 +88338 -0.391510009765625 +88339 0.004608154296875 +88340 -0.385345458984375 +88341 0.003662109375 +88342 -0.3419189453125 +88343 0.003265380859375 +88344 -0.28289794921875 +88345 0.002716064453125 +88346 -0.251617431640625 +88347 0.00042724609375 +88348 -0.266143798828125 +88349 -0.004058837890625 +88350 -0.273345947265625 +88351 -0.0084228515625 +88352 -0.216796875 +88353 -0.010223388671875 +88354 -0.128265380859375 +88355 -0.010498046875 +88356 -0.068145751953125 +88357 -0.011444091796875 +88358 -0.0430908203125 +88359 -0.013153076171875 +88360 -0.024444580078125 +88361 -0.014373779296875 +88362 0.020721435546875 +88363 -0.013702392578125 +88364 0.124481201171875 +88365 -0.00982666015625 +88366 0.25787353515625 +88367 -0.003936767578125 +88368 0.379119873046875 +88369 0.002197265625 +88370 0.47991943359375 +88371 0.0081787109375 +88372 0.5281982421875 +88373 0.012603759765625 +88374 0.511138916015625 +88375 0.01483154296875 +88376 0.456207275390625 +88377 0.0157470703125 +88378 0.407470703125 +88379 0.0169677734375 +88380 0.383758544921875 +88381 0.019073486328125 +88382 0.35687255859375 +88383 0.020721435546875 +88384 0.31182861328125 +88385 0.02117919921875 +88386 0.250885009765625 +88387 0.02044677734375 +88388 0.1654052734375 +88389 0.01812744140625 +88390 0.035247802734375 +88391 0.013336181640625 +88392 -0.142059326171875 +88393 0.006011962890625 +88394 -0.33563232421875 +88395 -0.0025634765625 +88396 -0.5345458984375 +88397 -0.011871337890625 +88398 -0.72186279296875 +88399 -0.021148681640625 +88400 -0.836669921875 +88401 -0.02783203125 +88402 -0.8326416015625 +88403 -0.02996826171875 +88404 -0.7296142578125 +88405 -0.028228759765625 +88406 -0.582550048828125 +88407 -0.024688720703125 +88408 -0.440093994140625 +88409 -0.02117919921875 +88410 -0.324310302734375 +88411 -0.018463134765625 +88412 -0.20147705078125 +88413 -0.01507568359375 +88414 -0.044647216796875 +88415 -0.009857177734375 +88416 0.103973388671875 +88417 -0.00445556640625 +88418 0.202392578125 +88419 -0.00054931640625 +88420 0.264495849609375 +88421 0.00238037109375 +88422 0.338897705078125 +88423 0.0062255859375 +88424 0.443817138671875 +88425 0.01165771484375 +88426 0.545074462890625 +88427 0.0172119140625 +88428 0.6173095703125 +88429 0.021820068359375 +88430 0.6524658203125 +88431 0.025054931640625 +88432 0.66339111328125 +88433 0.027313232421875 +88434 0.6561279296875 +88435 0.02874755859375 +88436 0.606781005859375 +88437 0.028289794921875 +88438 0.501190185546875 +88439 0.025299072265625 +88440 0.352783203125 +88441 0.020263671875 +88442 0.176544189453125 +88443 0.013763427734375 +88444 -0.034820556640625 +88445 0.0054931640625 +88446 -0.258209228515625 +88447 -0.003570556640625 +88448 -0.44244384765625 +88449 -0.011383056640625 +88450 -0.5753173828125 +88451 -0.017425537109375 +88452 -0.65203857421875 +88453 -0.021484375 +88454 -0.641632080078125 +88455 -0.022247314453125 +88456 -0.562164306640625 +88457 -0.020416259765625 +88458 -0.458038330078125 +88459 -0.017669677734375 +88460 -0.350555419921875 +88461 -0.014739990234375 +88462 -0.260528564453125 +88463 -0.01239013671875 +88464 -0.192108154296875 +88465 -0.0107421875 +88466 -0.141937255859375 +88467 -0.00958251953125 +88468 -0.1021728515625 +88469 -0.008544921875 +88470 -0.062896728515625 +88471 -0.00726318359375 +88472 -0.011932373046875 +88473 -0.005218505859375 +88474 0.062835693359375 +88475 -0.001953125 +88476 0.148712158203125 +88477 0.00201416015625 +88478 0.241729736328125 +88479 0.0064697265625 +88480 0.34912109375 +88481 0.01165771484375 +88482 0.457305908203125 +88483 0.0169677734375 +88484 0.54388427734375 +88485 0.02142333984375 +88486 0.5728759765625 +88487 0.0235595703125 +88488 0.506591796875 +88489 0.021820068359375 +88490 0.351226806640625 +88491 0.016387939453125 +88492 0.146514892578125 +88493 0.008819580078125 +88494 -0.05523681640625 +88495 0.001190185546875 +88496 -0.21624755859375 +88497 -0.004974365234375 +88498 -0.334930419921875 +88499 -0.009613037109375 +88500 -0.402984619140625 +88501 -0.01239013671875 +88502 -0.4412841796875 +88503 -0.014129638671875 +88504 -0.49578857421875 +88505 -0.016693115234375 +88506 -0.5601806640625 +88507 -0.019775390625 +88508 -0.600738525390625 +88509 -0.02197265625 +88510 -0.584228515625 +88511 -0.02197265625 +88512 -0.47930908203125 +88513 -0.018463134765625 +88514 -0.27935791015625 +88515 -0.01116943359375 +88516 -0.0089111328125 +88517 -0.001007080078125 +88518 0.268798828125 +88519 0.009490966796875 +88520 0.482818603515625 +88521 0.01751708984375 +88522 0.60369873046875 +88523 0.021881103515625 +88524 0.650421142578125 +88525 0.023406982421875 +88526 0.66400146484375 +88527 0.023773193359375 +88528 0.6414794921875 +88529 0.022857666015625 +88530 0.572540283203125 +88531 0.020233154296875 +88532 0.498138427734375 +88533 0.01751708984375 +88534 0.439453125 +88535 0.01556396484375 +88536 0.375518798828125 +88537 0.01348876953125 +88538 0.274505615234375 +88539 0.010009765625 +88540 0.1087646484375 +88541 0.00396728515625 +88542 -0.099395751953125 +88543 -0.00372314453125 +88544 -0.3182373046875 +88545 -0.0118408203125 +88546 -0.5489501953125 +88547 -0.020477294921875 +88548 -0.7738037109375 +88549 -0.028900146484375 +88550 -0.86383056640625 +88551 -0.035064697265625 +88552 -0.870391845703125 +88553 -0.03765869140625 +88554 -0.86895751953125 +88555 -0.03741455078125 +88556 -0.861053466796875 +88557 -0.034881591796875 +88558 -0.765869140625 +88559 -0.02935791015625 +88560 -0.5301513671875 +88561 -0.020416259765625 +88562 -0.214691162109375 +88563 -0.00830078125 +88564 0.137359619140625 +88565 0.005279541015625 +88566 0.474822998046875 +88567 0.018310546875 +88568 0.76239013671875 +88569 0.0294189453125 +88570 0.867462158203125 +88571 0.03753662109375 +88572 0.870361328125 +88573 0.042724609375 +88574 0.86480712890625 +88575 0.044525146484375 +88576 0.831817626953125 +88577 0.0433349609375 +88578 0.677581787109375 +88579 0.040252685546875 +88580 0.495880126953125 +88581 0.035491943359375 +88582 0.30767822265625 +88583 0.03009033203125 +88584 0.116180419921875 +88585 0.023834228515625 +88586 -0.110748291015625 +88587 0.014007568359375 +88588 -0.381805419921875 +88589 -0.000335693359375 +88590 -0.6572265625 +88591 -0.0166015625 +88592 -0.857421875 +88593 -0.030914306640625 +88594 -0.870391845703125 +88595 -0.04058837890625 +88596 -0.870391845703125 +88597 -0.045440673828125 +88598 -0.86444091796875 +88599 -0.047637939453125 +88600 -0.85723876953125 +88601 -0.0499267578125 +88602 -0.790008544921875 +88603 -0.051055908203125 +88604 -0.62847900390625 +88605 -0.04705810546875 +88606 -0.3956298828125 +88607 -0.03759765625 +88608 -0.126708984375 +88609 -0.024810791015625 +88610 0.150115966796875 +88611 -0.0103759765625 +88612 0.424041748046875 +88613 0.005157470703125 +88614 0.670623779296875 +88615 0.02020263671875 +88616 0.854522705078125 +88617 0.032379150390625 +88618 0.866485595703125 +88619 0.040771484375 +88620 0.86920166015625 +88621 0.04461669921875 +88622 0.8653564453125 +88623 0.0455322265625 +88624 0.857147216796875 +88625 0.044708251953125 +88626 0.766845703125 +88627 0.0421142578125 +88628 0.628509521484375 +88629 0.038177490234375 +88630 0.462127685546875 +88631 0.03240966796875 +88632 0.297210693359375 +88633 0.026611328125 +88634 0.14862060546875 +88635 0.021514892578125 +88636 -0.00537109375 +88637 0.0152587890625 +88638 -0.15753173828125 +88639 0.008148193359375 +88640 -0.31304931640625 +88641 -0.0003662109375 +88642 -0.48876953125 +88643 -0.0115966796875 +88644 -0.6416015625 +88645 -0.0224609375 +88646 -0.751373291015625 +88647 -0.031494140625 +88648 -0.84619140625 +88649 -0.040618896484375 +88650 -0.861297607421875 +88651 -0.048980712890625 +88652 -0.863250732421875 +88653 -0.05438232421875 +88654 -0.856597900390625 +88655 -0.05462646484375 +88656 -0.7498779296875 +88657 -0.050628662109375 +88658 -0.624542236328125 +88659 -0.046539306640625 +88660 -0.47808837890625 +88661 -0.0406494140625 +88662 -0.253387451171875 +88663 -0.02862548828125 +88664 0.003692626953125 +88665 -0.013580322265625 +88666 0.2257080078125 +88667 -0.00018310546875 +88668 0.427154541015625 +88669 0.0126953125 +88670 0.643218994140625 +88671 0.02764892578125 +88672 0.855926513671875 +88673 0.044219970703125 +88674 0.870361328125 +88675 0.058502197265625 +88676 0.870361328125 +88677 0.067108154296875 +88678 0.862762451171875 +88679 0.070709228515625 +88680 0.79669189453125 +88681 0.0692138671875 +88682 0.595794677734375 +88683 0.062042236328125 +88684 0.362152099609375 +88685 0.051239013671875 +88686 0.1270751953125 +88687 0.038818359375 +88688 -0.086944580078125 +88689 0.02618408203125 +88690 -0.2784423828125 +88691 0.0133056640625 +88692 -0.484832763671875 +88693 -0.00244140625 +88694 -0.729583740234375 +88695 -0.022674560546875 +88696 -0.86688232421875 +88697 -0.043975830078125 +88698 -0.870391845703125 +88699 -0.061981201171875 +88700 -0.86859130859375 +88701 -0.076507568359375 +88702 -0.86279296875 +88703 -0.087615966796875 +88704 -0.817962646484375 +88705 -0.092864990234375 +88706 -0.6116943359375 +88707 -0.089111328125 +88708 -0.3128662109375 +88709 -0.075897216796875 +88710 0.039398193359375 +88711 -0.0556640625 +88712 0.422821044921875 +88713 -0.02984619140625 +88714 0.805145263671875 +88715 -0.000762939453125 +88716 0.870361328125 +88717 0.026763916015625 +88718 0.870361328125 +88719 0.04876708984375 +88720 0.860015869140625 +88721 0.0645751953125 +88722 0.727935791015625 +88723 0.07379150390625 +88724 0.48114013671875 +88725 0.076202392578125 +88726 0.2059326171875 +88727 0.07373046875 +88728 -0.06103515625 +88729 0.068145751953125 +88730 -0.29913330078125 +88731 0.060302734375 +88732 -0.516204833984375 +88733 0.04925537109375 +88734 -0.7252197265625 +88735 0.033966064453125 +88736 -0.85980224609375 +88737 0.016265869140625 +88738 -0.870391845703125 +88739 -0.001373291015625 +88740 -0.870391845703125 +88741 -0.016845703125 +88742 -0.858062744140625 +88743 -0.026702880859375 +88744 -0.673004150390625 +88745 -0.03076171875 +88746 -0.42694091796875 +88747 -0.032928466796875 +88748 -0.2100830078125 +88749 -0.0364990234375 +88750 -0.0362548828125 +88751 -0.041412353515625 +88752 0.10943603515625 +88753 -0.04571533203125 +88754 0.23516845703125 +88755 -0.048065185546875 +88756 0.373687744140625 +88757 -0.04559326171875 +88758 0.517791748046875 +88759 -0.03851318359375 +88760 0.602783203125 +88761 -0.03143310546875 +88762 0.635711669921875 +88763 -0.02398681640625 +88764 0.655181884765625 +88765 -0.013824462890625 +88766 0.65948486328125 +88767 -0.00164794921875 +88768 0.651275634765625 +88769 0.011962890625 +88770 0.61846923828125 +88771 0.0252685546875 +88772 0.53753662109375 +88773 0.035675048828125 +88774 0.404144287109375 +88775 0.041961669921875 +88776 0.22186279296875 +88777 0.043548583984375 +88778 0.003997802734375 +88779 0.040679931640625 +88780 -0.22100830078125 +88781 0.034759521484375 +88782 -0.42449951171875 +88783 0.02734375 +88784 -0.579833984375 +88785 0.02001953125 +88786 -0.641876220703125 +88787 0.01593017578125 +88788 -0.6177978515625 +88789 0.0146484375 +88790 -0.575531005859375 +88791 0.01153564453125 +88792 -0.526336669921875 +88793 0.006195068359375 +88794 -0.42645263671875 +88795 0.002349853515625 +88796 -0.2581787109375 +88797 0.00189208984375 +88798 -0.068695068359375 +88799 0.002197265625 +88800 0.09222412109375 +88801 0.00042724609375 +88802 0.232147216796875 +88803 -0.0020751953125 +88804 0.3509521484375 +88805 -0.00469970703125 +88806 0.410064697265625 +88807 -0.0096435546875 +88808 0.372955322265625 +88809 -0.019073486328125 +88810 0.2554931640625 +88811 -0.03155517578125 +88812 0.10711669921875 +88813 -0.04339599609375 +88814 -0.052886962890625 +88815 -0.053192138671875 +88816 -0.186279296875 +88817 -0.058380126953125 +88818 -0.23291015625 +88819 -0.054962158203125 +88820 -0.209442138671875 +88821 -0.044586181640625 +88822 -0.174163818359375 +88823 -0.031982421875 +88824 -0.126739501953125 +88825 -0.0177001953125 +88826 -0.048126220703125 +88827 -0.001007080078125 +88828 0.0426025390625 +88829 0.016082763671875 +88830 0.10748291015625 +88831 0.030303955078125 +88832 0.1409912109375 +88833 0.04119873046875 +88834 0.19708251953125 +88835 0.05303955078125 +88836 0.273651123046875 +88837 0.0645751953125 +88838 0.31768798828125 +88839 0.070465087890625 +88840 0.341094970703125 +88841 0.071990966796875 +88842 0.368011474609375 +88843 0.071746826171875 +88844 0.37249755859375 +88845 0.0673828125 +88846 0.30072021484375 +88847 0.05389404296875 +88848 0.1517333984375 +88849 0.031585693359375 +88850 -0.01470947265625 +88851 0.006866455078125 +88852 -0.1883544921875 +88853 -0.01873779296875 +88854 -0.372711181640625 +88855 -0.04510498046875 +88856 -0.51397705078125 +88857 -0.066436767578125 +88858 -0.57177734375 +88859 -0.078338623046875 +88860 -0.53948974609375 +88861 -0.079833984375 +88862 -0.43511962890625 +88863 -0.072509765625 +88864 -0.2962646484375 +88865 -0.060028076171875 +88866 -0.161102294921875 +88867 -0.046173095703125 +88868 -0.0435791015625 +88869 -0.03240966796875 +88870 0.060394287109375 +88871 -0.01849365234375 +88872 0.13665771484375 +88873 -0.006103515625 +88874 0.170135498046875 +88875 0.0029296875 +88876 0.16552734375 +88877 0.008758544921875 +88878 0.15728759765625 +88879 0.01446533203125 +88880 0.150787353515625 +88881 0.020233154296875 +88882 0.12200927734375 +88883 0.0233154296875 +88884 0.080108642578125 +88885 0.0242919921875 +88886 0.05126953125 +88887 0.025543212890625 +88888 0.062896728515625 +88889 0.02960205078125 +88890 0.09271240234375 +88891 0.03411865234375 +88892 0.092987060546875 +88893 0.0343017578125 +88894 0.07855224609375 +88895 0.031646728515625 +88896 0.06427001953125 +88897 0.027740478515625 +88898 0.0347900390625 +88899 0.021209716796875 +88900 -0.01171875 +88901 0.012115478515625 +88902 -0.056060791015625 +88903 0.002655029296875 +88904 -0.055511474609375 +88905 -0.002593994140625 +88906 -0.010467529296875 +88907 -0.003387451171875 +88908 0.02508544921875 +88909 -0.00482177734375 +88910 0.025665283203125 +88911 -0.009185791015625 +88912 0.017333984375 +88913 -0.013641357421875 +88914 0.00189208984375 +88915 -0.017822265625 +88916 -0.03173828125 +88917 -0.022735595703125 +88918 -0.071502685546875 +88919 -0.027130126953125 +88920 -0.13543701171875 +88921 -0.0328369140625 +88922 -0.219970703125 +88923 -0.03955078125 +88924 -0.300506591796875 +88925 -0.044891357421875 +88926 -0.376312255859375 +88927 -0.048980712890625 +88928 -0.416107177734375 +88929 -0.048919677734375 +88930 -0.371124267578125 +88931 -0.0400390625 +88932 -0.242279052734375 +88933 -0.022705078125 +88934 -0.069732666015625 +88935 -0.001190185546875 +88936 0.125640869140625 +88937 0.02215576171875 +88938 0.31268310546875 +88939 0.044036865234375 +88940 0.45501708984375 +88941 0.060638427734375 +88942 0.554779052734375 +88943 0.072052001953125 +88944 0.61065673828125 +88945 0.078125 +88946 0.610931396484375 +88947 0.07769775390625 +88948 0.531463623046875 +88949 0.068389892578125 +88950 0.3883056640625 +88951 0.051910400390625 +88952 0.23468017578125 +88953 0.03375244140625 +88954 0.095245361328125 +88955 0.016571044921875 +88956 -0.00396728515625 +88957 0.003143310546875 +88958 -0.04852294921875 +88959 -0.0048828125 +88960 -0.055145263671875 +88961 -0.009002685546875 +88962 -0.0758056640625 +88963 -0.014190673828125 +88964 -0.138702392578125 +88965 -0.023101806640625 +88966 -0.209197998046875 +88967 -0.03216552734375 +88968 -0.289031982421875 +88969 -0.041473388671875 +88970 -0.37884521484375 +88971 -0.051055908203125 +88972 -0.456329345703125 +88973 -0.05865478515625 +88974 -0.51641845703125 +88975 -0.06378173828125 +88976 -0.519287109375 +88977 -0.062530517578125 +88978 -0.458251953125 +88979 -0.0543212890625 +88980 -0.384796142578125 +88981 -0.044464111328125 +88982 -0.323699951171875 +88983 -0.035552978515625 +88984 -0.269287109375 +88985 -0.02716064453125 +88986 -0.1951904296875 +88987 -0.016815185546875 +88988 -0.100006103515625 +88989 -0.00457763671875 +88990 -0.01055908203125 +88991 0.0067138671875 +88992 0.1033935546875 +88993 0.01995849609375 +88994 0.24908447265625 +88995 0.035797119140625 +88996 0.373199462890625 +88997 0.048858642578125 +88998 0.45806884765625 +88999 0.057342529296875 +89000 0.511474609375 +89001 0.062042236328125 +89002 0.565399169921875 +89003 0.066192626953125 +89004 0.61138916015625 +89005 0.069061279296875 +89006 0.5897216796875 +89007 0.064788818359375 +89008 0.4906005859375 +89009 0.052520751953125 +89010 0.33148193359375 +89011 0.03411865234375 +89012 0.147796630859375 +89013 0.013275146484375 +89014 -0.01873779296875 +89015 -0.00567626953125 +89016 -0.140289306640625 +89017 -0.01983642578125 +89018 -0.191986083984375 +89019 -0.026611328125 +89020 -0.184295654296875 +89021 -0.027008056640625 +89022 -0.161834716796875 +89023 -0.025421142578125 +89024 -0.166595458984375 +89025 -0.0260009765625 +89026 -0.19390869140625 +89027 -0.028289794921875 +89028 -0.22442626953125 +89029 -0.0303955078125 +89030 -0.279754638671875 +89031 -0.0345458984375 +89032 -0.3389892578125 +89033 -0.038726806640625 +89034 -0.3543701171875 +89035 -0.03826904296875 +89036 -0.348175048828125 +89037 -0.0355224609375 +89038 -0.32598876953125 +89039 -0.03118896484375 +89040 -0.2581787109375 +89041 -0.02239990234375 +89042 -0.139801025390625 +89043 -0.008758544921875 +89044 0.014617919921875 +89045 0.008148193359375 +89046 0.144378662109375 +89047 0.02215576171875 +89048 0.221038818359375 +89049 0.0303955078125 +89050 0.27069091796875 +89051 0.03546142578125 +89052 0.294036865234375 +89053 0.03741455078125 +89054 0.311767578125 +89055 0.038360595703125 +89056 0.339141845703125 +89057 0.0399169921875 +89058 0.360260009765625 +89059 0.040618896484375 +89060 0.360504150390625 +89061 0.039093017578125 +89062 0.308380126953125 +89063 0.032135009765625 +89064 0.18170166015625 +89065 0.01751708984375 +89066 0.0047607421875 +89067 -0.00213623046875 +89068 -0.17559814453125 +89069 -0.02191162109375 +89070 -0.3143310546875 +89071 -0.037109375 +89072 -0.36785888671875 +89073 -0.04315185546875 +89074 -0.36248779296875 +89075 -0.042755126953125 +89076 -0.343536376953125 +89077 -0.0406494140625 +89078 -0.3018798828125 +89079 -0.035919189453125 +89080 -0.231414794921875 +89081 -0.0279541015625 +89082 -0.117645263671875 +89083 -0.015289306640625 +89084 0.007049560546875 +89085 -0.0013427734375 +89086 0.087982177734375 +89087 0.00811767578125 +89088 0.13946533203125 +89089 0.014495849609375 +89090 0.17425537109375 +89091 0.01910400390625 +89092 0.188201904296875 +89093 0.021514892578125 +89094 0.171234130859375 +89095 0.020172119140625 +89096 0.118438720703125 +89097 0.014251708984375 +89098 0.05706787109375 +89099 0.00732421875 +89100 -0.010711669921875 +89101 -0.00048828125 +89102 -0.0914306640625 +89103 -0.010162353515625 +89104 -0.162322998046875 +89105 -0.018707275390625 +89106 -0.194549560546875 +89107 -0.022247314453125 +89108 -0.1492919921875 +89109 -0.01556396484375 +89110 -0.02166748046875 +89111 0.001983642578125 +89112 0.124053955078125 +89113 0.021636962890625 +89114 0.211151123046875 +89115 0.032989501953125 +89116 0.240447998046875 +89117 0.036224365234375 +89118 0.242218017578125 +89119 0.0355224609375 +89120 0.2257080078125 +89121 0.032196044921875 +89122 0.194366455078125 +89123 0.02679443359375 +89124 0.115509033203125 +89125 0.01495361328125 +89126 0.0128173828125 +89127 0.0 +89128 -0.053802490234375 +89129 -0.009857177734375 +89130 -0.110626220703125 +89131 -0.0181884765625 +89132 -0.199493408203125 +89133 -0.030670166015625 +89134 -0.29437255859375 +89135 -0.043731689453125 +89136 -0.33221435546875 +89137 -0.048797607421875 +89138 -0.27972412109375 +89139 -0.041351318359375 +89140 -0.185333251953125 +89141 -0.02801513671875 +89142 -0.128204345703125 +89143 -0.01959228515625 +89144 -0.115692138671875 +89145 -0.017120361328125 +89146 -0.116455078125 +89147 -0.016387939453125 +89148 -0.105926513671875 +89149 -0.01409912109375 +89150 -0.053955078125 +89151 -0.006195068359375 +89152 0.048797607421875 +89153 0.008514404296875 +89154 0.157318115234375 +89155 0.023895263671875 +89156 0.212005615234375 +89157 0.03179931640625 +89158 0.218475341796875 +89159 0.032958984375 +89160 0.23724365234375 +89161 0.035614013671875 +89162 0.30535888671875 +89163 0.0447998046875 +89164 0.38128662109375 +89165 0.05487060546875 +89166 0.404449462890625 +89167 0.05755615234375 +89168 0.3944091796875 +89169 0.055572509765625 +89170 0.3885498046875 +89171 0.054046630859375 +89172 0.362640380859375 +89173 0.049774169921875 +89174 0.27362060546875 +89175 0.03692626953125 +89176 0.11712646484375 +89177 0.01495361328125 +89178 -0.054901123046875 +89179 -0.009002685546875 +89180 -0.19085693359375 +89181 -0.027923583984375 +89182 -0.28570556640625 +89183 -0.041107177734375 +89184 -0.339263916015625 +89185 -0.04852294921875 +89186 -0.3775634765625 +89187 -0.0537109375 +89188 -0.445709228515625 +89189 -0.06280517578125 +89190 -0.535064697265625 +89191 -0.074615478515625 +89192 -0.629058837890625 +89193 -0.086944580078125 +89194 -0.697601318359375 +89195 -0.095703125 +89196 -0.70391845703125 +89197 -0.095947265625 +89198 -0.6424560546875 +89199 -0.086944580078125 +89200 -0.491241455078125 +89201 -0.06573486328125 +89202 -0.265716552734375 +89203 -0.03448486328125 +89204 -0.023712158203125 +89205 -0.001068115234375 +89206 0.201751708984375 +89207 0.02996826171875 +89208 0.375823974609375 +89209 0.053863525390625 +89210 0.485076904296875 +89211 0.06878662109375 +89212 0.56884765625 +89213 0.080078125 +89214 0.634765625 +89215 0.088775634765625 +89216 0.63763427734375 +89217 0.088775634765625 +89218 0.5660400390625 +89219 0.07855224609375 +89220 0.4720458984375 +89221 0.06524658203125 +89222 0.40692138671875 +89223 0.055816650390625 +89224 0.3778076171875 +89225 0.05126953125 +89226 0.376953125 +89227 0.05059814453125 +89228 0.371978759765625 +89229 0.049407958984375 +89230 0.313140869140625 +89231 0.04095458984375 +89232 0.184417724609375 +89233 0.0230712890625 +89234 0.011199951171875 +89235 -0.000701904296875 +89236 -0.171051025390625 +89237 -0.025543212890625 +89238 -0.33740234375 +89239 -0.04803466796875 +89240 -0.47198486328125 +89241 -0.0660400390625 +89242 -0.560394287109375 +89243 -0.07763671875 +89244 -0.58056640625 +89245 -0.079864501953125 +89246 -0.54754638671875 +89247 -0.074798583984375 +89248 -0.508575439453125 +89249 -0.06890869140625 +89250 -0.459503173828125 +89251 -0.061676025390625 +89252 -0.394378662109375 +89253 -0.05230712890625 +89254 -0.35260009765625 +89255 -0.046173095703125 +89256 -0.31170654296875 +89257 -0.04022216796875 +89258 -0.197418212890625 +89259 -0.024383544921875 +89260 -0.007965087890625 +89261 0.00152587890625 +89262 0.207489013671875 +89263 0.03082275390625 +89264 0.409210205078125 +89265 0.05810546875 +89266 0.57208251953125 +89267 0.0799560546875 +89268 0.66595458984375 +89269 0.092315673828125 +89270 0.65875244140625 +89271 0.090850830078125 +89272 0.56744384765625 +89273 0.077880859375 +89274 0.431396484375 +89275 0.058807373046875 +89276 0.29443359375 +89277 0.039642333984375 +89278 0.182464599609375 +89279 0.023895263671875 +89280 0.06365966796875 +89281 0.007293701171875 +89282 -0.075958251953125 +89283 -0.01202392578125 +89284 -0.189422607421875 +89285 -0.027679443359375 +89286 -0.271942138671875 +89287 -0.038970947265625 +89288 -0.342529296875 +89289 -0.048492431640625 +89290 -0.364166259765625 +89291 -0.051239013671875 +89292 -0.327239990234375 +89293 -0.045928955078125 +89294 -0.2769775390625 +89295 -0.038726806640625 +89296 -0.253692626953125 +89297 -0.035125732421875 +89298 -0.24365234375 +89299 -0.03326416015625 +89300 -0.1983642578125 +89301 -0.026580810546875 +89302 -0.116241455078125 +89303 -0.014892578125 +89304 -0.036834716796875 +89305 -0.003631591796875 +89306 0.034881591796875 +89307 0.006500244140625 +89308 0.09124755859375 +89309 0.014434814453125 +89310 0.10888671875 +89311 0.016998291015625 +89312 0.125518798828125 +89313 0.019287109375 +89314 0.15771484375 +89315 0.0235595703125 +89316 0.17828369140625 +89317 0.026123046875 +89318 0.17108154296875 +89319 0.024810791015625 +89320 0.129974365234375 +89321 0.018798828125 +89322 0.082427978515625 +89323 0.011871337890625 +89324 0.027679443359375 +89325 0.003936767578125 +89326 -0.065643310546875 +89327 -0.009185791015625 +89328 -0.15936279296875 +89329 -0.02227783203125 +89330 -0.21307373046875 +89331 -0.029876708984375 +89332 -0.234649658203125 +89333 -0.03302001953125 +89334 -0.2001953125 +89335 -0.028472900390625 +89336 -0.119171142578125 +89337 -0.017486572265625 +89338 -0.024749755859375 +89339 -0.00457763671875 +89340 0.085784912109375 +89341 0.010589599609375 +89342 0.178131103515625 +89343 0.0233154296875 +89344 0.215576171875 +89345 0.02838134765625 +89346 0.211456298828125 +89347 0.0274658203125 +89348 0.17523193359375 +89349 0.021759033203125 +89350 0.128753662109375 +89351 0.01483154296875 +89352 0.1019287109375 +89353 0.0115966796875 +89354 0.0743408203125 +89355 0.008544921875 +89356 0.04327392578125 +89357 0.005096435546875 +89358 0.038177490234375 +89359 0.006072998046875 +89360 0.076263427734375 +89361 0.014251708984375 +89362 0.14105224609375 +89363 0.0267333984375 +89364 0.186431884765625 +89365 0.035675048828125 +89366 0.188812255859375 +89367 0.037078857421875 +89368 0.1390380859375 +89369 0.029388427734375 +89370 0.041778564453125 +89371 0.013336181640625 +89372 -0.079437255859375 +89373 -0.007080078125 +89374 -0.219390869140625 +89375 -0.030975341796875 +89376 -0.367828369140625 +89377 -0.0565185546875 +89378 -0.494873046875 +89379 -0.078704833984375 +89380 -0.556243896484375 +89381 -0.090057373046875 +89382 -0.508697509765625 +89383 -0.083251953125 +89384 -0.3756103515625 +89385 -0.0621337890625 +89386 -0.218902587890625 +89387 -0.03704833984375 +89388 -0.063751220703125 +89389 -0.01214599609375 +89390 0.091552734375 +89391 0.01287841796875 +89392 0.23602294921875 +89393 0.0362548828125 +89394 0.342987060546875 +89395 0.053497314453125 +89396 0.39520263671875 +89397 0.061767578125 +89398 0.389373779296875 +89399 0.060546875 +89400 0.324249267578125 +89401 0.049652099609375 +89402 0.224090576171875 +89403 0.033172607421875 +89404 0.124267578125 +89405 0.016998291015625 +89406 0.037078857421875 +89407 0.003143310546875 +89408 -0.010101318359375 +89409 -0.003814697265625 +89410 -0.019439697265625 +89411 -0.004302978515625 +89412 -0.022796630859375 +89413 -0.003753662109375 +89414 -0.001556396484375 +89415 0.000885009765625 +89416 0.056304931640625 +89417 0.01153564453125 +89418 0.106719970703125 +89419 0.020782470703125 +89420 0.096893310546875 +89421 0.019744873046875 +89422 0.042694091796875 +89423 0.01104736328125 +89424 -0.018035888671875 +89425 0.001007080078125 +89426 -0.07586669921875 +89427 -0.00872802734375 +89428 -0.11944580078125 +89429 -0.016265869140625 +89430 -0.15972900390625 +89431 -0.023406982421875 +89432 -0.202606201171875 +89433 -0.0311279296875 +89434 -0.24859619140625 +89435 -0.039459228515625 +89436 -0.30517578125 +89437 -0.049652099609375 +89438 -0.36212158203125 +89439 -0.0599365234375 +89440 -0.39141845703125 +89441 -0.065582275390625 +89442 -0.35528564453125 +89443 -0.0601806640625 +89444 -0.249969482421875 +89445 -0.0430908203125 +89446 -0.092864990234375 +89447 -0.0172119140625 +89448 0.08905029296875 +89449 0.012939453125 +89450 0.2352294921875 +89451 0.037200927734375 +89452 0.318817138671875 +89453 0.05108642578125 +89454 0.358642578125 +89455 0.057769775390625 +89456 0.347747802734375 +89457 0.056060791015625 +89458 0.28564453125 +89459 0.045867919921875 +89460 0.223175048828125 +89461 0.035736083984375 +89462 0.196746826171875 +89463 0.03173828125 +89464 0.179840087890625 +89465 0.029388427734375 +89466 0.155548095703125 +89467 0.02581787109375 +89468 0.151214599609375 +89469 0.025604248046875 +89470 0.156951904296875 +89471 0.027069091796875 +89472 0.13177490234375 +89473 0.023284912109375 +89474 0.100799560546875 +89475 0.018463134765625 +89476 0.087127685546875 +89477 0.016448974609375 +89478 0.05487060546875 +89479 0.011199951171875 +89480 -0.009002685546875 +89481 0.00054931640625 +89482 -0.10400390625 +89483 -0.01544189453125 +89484 -0.229400634765625 +89485 -0.03662109375 +89486 -0.35552978515625 +89487 -0.0579833984375 +89488 -0.441925048828125 +89489 -0.072723388671875 +89490 -0.473846435546875 +89491 -0.078369140625 +89492 -0.464813232421875 +89493 -0.077178955078125 +89494 -0.419097900390625 +89495 -0.069854736328125 +89496 -0.334320068359375 +89497 -0.05596923828125 +89498 -0.227935791015625 +89499 -0.038421630859375 +89500 -0.12347412109375 +89501 -0.021148681640625 +89502 -0.02764892578125 +89503 -0.0052490234375 +89504 0.077667236328125 +89505 0.01226806640625 +89506 0.2132568359375 +89507 0.034912109375 +89508 0.38885498046875 +89509 0.0643310546875 +89510 0.582794189453125 +89511 0.096893310546875 +89512 0.734039306640625 +89513 0.122344970703125 +89514 0.800140380859375 +89515 0.133514404296875 +89516 0.7783203125 +89517 0.129974365234375 +89518 0.6651611328125 +89519 0.111114501953125 +89520 0.45965576171875 +89521 0.0767822265625 +89522 0.199188232421875 +89523 0.03326416015625 +89524 -0.050689697265625 +89525 -0.008453369140625 +89526 -0.23297119140625 +89527 -0.038787841796875 +89528 -0.33013916015625 +89529 -0.054840087890625 +89530 -0.368408203125 +89531 -0.061004638671875 +89532 -0.378936767578125 +89533 -0.062530517578125 +89534 -0.376983642578125 +89535 -0.062042236328125 +89536 -0.37969970703125 +89537 -0.062408447265625 +89538 -0.391510009765625 +89539 -0.064361572265625 +89540 -0.385345458984375 +89541 -0.0633544921875 +89542 -0.3419189453125 +89543 -0.056121826171875 +89544 -0.28289794921875 +89545 -0.046295166015625 +89546 -0.251617431640625 +89547 -0.041168212890625 +89548 -0.266143798828125 +89549 -0.04376220703125 +89550 -0.273345947265625 +89551 -0.045135498046875 +89552 -0.216796875 +89553 -0.03582763671875 +89554 -0.128265380859375 +89555 -0.0211181640625 +89556 -0.068145751953125 +89557 -0.011138916015625 +89558 -0.0430908203125 +89559 -0.007049560546875 +89560 -0.024444580078125 +89561 -0.003997802734375 +89562 0.020721435546875 +89563 0.003509521484375 +89564 0.124481201171875 +89565 0.020843505859375 +89566 0.25787353515625 +89567 0.04315185546875 +89568 0.379119873046875 +89569 0.06341552734375 +89570 0.47991943359375 +89571 0.08026123046875 +89572 0.5281982421875 +89573 0.08831787109375 +89574 0.511138916015625 +89575 0.08538818359375 +89576 0.456207275390625 +89577 0.07611083984375 +89578 0.407470703125 +89579 0.067901611328125 +89580 0.383758544921875 +89581 0.063934326171875 +89582 0.35687255859375 +89583 0.0594482421875 +89584 0.31182861328125 +89585 0.051910400390625 +89586 0.250885009765625 +89587 0.04168701171875 +89588 0.1654052734375 +89589 0.027374267578125 +89590 0.035247802734375 +89591 0.005584716796875 +89592 -0.142059326171875 +89593 -0.024078369140625 +89594 -0.33563232421875 +89595 -0.056427001953125 +89596 -0.5345458984375 +89597 -0.089630126953125 +89598 -0.72186279296875 +89599 -0.120849609375 +89600 -0.836669921875 +89601 -0.139404296875 +89602 -0.8326416015625 +89603 -0.13690185546875 +89604 -0.7296142578125 +89605 -0.117279052734375 +89606 -0.582550048828125 +89607 -0.09112548828125 +89608 -0.440093994140625 +89609 -0.067657470703125 +89610 -0.324310302734375 +89611 -0.050750732421875 +89612 -0.20147705078125 +89613 -0.033111572265625 +89614 -0.044647216796875 +89615 -0.00885009765625 +89616 0.103973388671875 +89617 0.0140380859375 +89618 0.202392578125 +89619 0.027557373046875 +89620 0.264495849609375 +89621 0.0347900390625 +89622 0.338897705078125 +89623 0.045745849609375 +89624 0.443817138671875 +89625 0.064208984375 +89626 0.545074462890625 +89627 0.08343505859375 +89628 0.6173095703125 +89629 0.09832763671875 +89630 0.6524658203125 +89631 0.10723876953125 +89632 0.66339111328125 +89633 0.112548828125 +89634 0.6561279296875 +89635 0.115264892578125 +89636 0.606781005859375 +89637 0.110321044921875 +89638 0.501190185546875 +89639 0.094573974609375 +89640 0.352783203125 +89641 0.070404052734375 +89642 0.176544189453125 +89643 0.04052734375 +89644 -0.034820556640625 +89645 0.003204345703125 +89646 -0.258209228515625 +89647 -0.03717041015625 +89648 -0.44244384765625 +89649 -0.070587158203125 +89650 -0.5753173828125 +89651 -0.09478759765625 +89652 -0.65203857421875 +89653 -0.108917236328125 +89654 -0.641632080078125 +89655 -0.106781005859375 +89656 -0.562164306640625 +89657 -0.092010498046875 +89658 -0.458038330078125 +89659 -0.073394775390625 +89660 -0.350555419921875 +89661 -0.055023193359375 +89662 -0.260528564453125 +89663 -0.040863037109375 +89664 -0.192108154296875 +89665 -0.031524658203125 +89666 -0.141937255859375 +89667 -0.02606201171875 +89668 -0.1021728515625 +89669 -0.02264404296875 +89670 -0.062896728515625 +89671 -0.01904296875 +89672 -0.011932373046875 +89673 -0.012603759765625 +89674 0.062835693359375 +89675 -0.000701904296875 +89676 0.148712158203125 +89677 0.014251708984375 +89678 0.241729736328125 +89679 0.031524658203125 +89680 0.34912109375 +89681 0.052642822265625 +89682 0.457305908203125 +89683 0.07489013671875 +89684 0.54388427734375 +89685 0.09368896484375 +89686 0.5728759765625 +89687 0.101776123046875 +89688 0.506591796875 +89689 0.0914306640625 +89690 0.351226806640625 +89691 0.063720703125 +89692 0.146514892578125 +89693 0.026397705078125 +89694 -0.05523681640625 +89695 -0.01025390625 +89696 -0.21624755859375 +89697 -0.03887939453125 +89698 -0.334930419921875 +89699 -0.059356689453125 +89700 -0.402984619140625 +89701 -0.070159912109375 +89702 -0.4412841796875 +89703 -0.07562255859375 +89704 -0.49578857421875 +89705 -0.085052490234375 +89706 -0.5601806640625 +89707 -0.097259521484375 +89708 -0.600738525390625 +89709 -0.105499267578125 +89710 -0.584228515625 +89711 -0.10308837890625 +89712 -0.47930908203125 +89713 -0.083709716796875 +89714 -0.27935791015625 +89715 -0.045928955078125 +89716 -0.0089111328125 +89717 0.005462646484375 +89718 0.268798828125 +89719 0.0579833984375 +89720 0.482818603515625 +89721 0.09759521484375 +89722 0.60369873046875 +89723 0.118621826171875 +89724 0.650421142578125 +89725 0.125 +89726 0.66400146484375 +89727 0.125091552734375 +89728 0.6414794921875 +89729 0.118438720703125 +89730 0.572540283203125 +89731 0.103118896484375 +89732 0.498138427734375 +89733 0.087371826171875 +89734 0.439453125 +89735 0.075469970703125 +89736 0.375518798828125 +89737 0.063201904296875 +89738 0.274505615234375 +89739 0.044158935546875 +89740 0.1087646484375 +89741 0.012725830078125 +89742 -0.099395751953125 +89743 -0.026702880859375 +89744 -0.3182373046875 +89745 -0.06793212890625 +89746 -0.5489501953125 +89747 -0.111358642578125 +89748 -0.7738037109375 +89749 -0.153533935546875 +89750 -0.86383056640625 +89751 -0.184051513671875 +89752 -0.870391845703125 +89753 -0.1964111328125 +89754 -0.86895751953125 +89755 -0.194305419921875 +89756 -0.861053466796875 +89757 -0.180450439453125 +89758 -0.765869140625 +89759 -0.151458740234375 +89760 -0.5301513671875 +89761 -0.1051025390625 +89762 -0.214691162109375 +89763 -0.042816162109375 +89764 0.137359619140625 +89765 0.02679443359375 +89766 0.474822998046875 +89767 0.093536376953125 +89768 0.76239013671875 +89769 0.150390625 +89770 0.867462158203125 +89771 0.19207763671875 +89772 0.870361328125 +89773 0.21881103515625 +89774 0.86480712890625 +89775 0.2283935546875 +89776 0.831817626953125 +89777 0.222015380859375 +89778 0.677581787109375 +89779 0.2047119140625 +89780 0.495880126953125 +89781 0.177764892578125 +89782 0.30767822265625 +89783 0.14495849609375 +89784 0.116180419921875 +89785 0.1068115234375 +89786 -0.110748291015625 +89787 0.057037353515625 +89788 -0.381805419921875 +89789 -0.005706787109375 +89790 -0.6572265625 +89791 -0.072906494140625 +89792 -0.857421875 +89793 -0.132598876953125 +89794 -0.870391845703125 +89795 -0.176300048828125 +89796 -0.870391845703125 +89797 -0.202667236328125 +89798 -0.86444091796875 +89799 -0.217193603515625 +89800 -0.85723876953125 +89801 -0.227142333984375 +89802 -0.790008544921875 +89803 -0.228973388671875 +89804 -0.62847900390625 +89805 -0.2119140625 +89806 -0.3956298828125 +89807 -0.1754150390625 +89808 -0.126708984375 +89809 -0.12615966796875 +89810 0.150115966796875 +89811 -0.069671630859375 +89812 0.424041748046875 +89813 -0.008331298828125 +89814 0.670623779296875 +89815 0.05242919921875 +89816 0.854522705078125 +89817 0.1048583984375 +89818 0.866485595703125 +89819 0.145477294921875 +89820 0.86920166015625 +89821 0.171234130859375 +89822 0.8653564453125 +89823 0.18585205078125 +89824 0.857147216796875 +89825 0.19207763671875 +89826 0.766845703125 +89827 0.18939208984375 +89828 0.628509521484375 +89829 0.178955078125 +89830 0.462127685546875 +89831 0.159515380859375 +89832 0.297210693359375 +89833 0.13629150390625 +89834 0.14862060546875 +89835 0.111846923828125 +89836 -0.00537109375 +89837 0.081695556640625 +89838 -0.15753173828125 +89839 0.04736328125 +89840 -0.31304931640625 +89841 0.0081787109375 +89842 -0.48876953125 +89843 -0.038665771484375 +89844 -0.6416015625 +89845 -0.083770751953125 +89846 -0.751373291015625 +89847 -0.12225341796875 +89848 -0.84619140625 +89849 -0.158782958984375 +89850 -0.861297607421875 +89851 -0.190460205078125 +89852 -0.863250732421875 +89853 -0.210723876953125 +89854 -0.856597900390625 +89855 -0.213348388671875 +89856 -0.7498779296875 +89857 -0.201446533203125 +89858 -0.624542236328125 +89859 -0.187469482421875 +89860 -0.47808837890625 +89861 -0.165618896484375 +89862 -0.253387451171875 +89863 -0.122100830078125 +89864 0.003692626953125 +89865 -0.067230224609375 +89866 0.2257080078125 +89867 -0.016571044921875 +89868 0.427154541015625 +89869 0.033111572265625 +89870 0.643218994140625 +89871 0.0897216796875 +89872 0.855926513671875 +89873 0.1513671875 +89874 0.870361328125 +89875 0.20489501953125 +89876 0.870361328125 +89877 0.239044189453125 +89878 0.862762451171875 +89879 0.25567626953125 +89880 0.79669189453125 +89881 0.254241943359375 +89882 0.595794677734375 +89883 0.232574462890625 +89884 0.362152099609375 +89885 0.19744873046875 +89886 0.1270751953125 +89887 0.1552734375 +89888 -0.086944580078125 +89889 0.11077880859375 +89890 -0.2784423828125 +89891 0.064178466796875 +89892 -0.484832763671875 +89893 0.007171630859375 +89894 -0.729583740234375 +89895 -0.06500244140625 +89896 -0.86688232421875 +89897 -0.140869140625 +89898 -0.870391845703125 +89899 -0.2060546875 +89900 -0.86859130859375 +89901 -0.259613037109375 +89902 -0.86279296875 +89903 -0.301300048828125 +89904 -0.817962646484375 +89905 -0.322967529296875 +89906 -0.6116943359375 +89907 -0.314208984375 +89908 -0.3128662109375 +89909 -0.2734375 +89910 0.039398193359375 +89911 -0.20849609375 +89912 0.422821044921875 +89913 -0.123931884765625 +89914 0.805145263671875 +89915 -0.027374267578125 +89916 0.870361328125 +89917 0.06549072265625 +89918 0.870361328125 +89919 0.1416015625 +89920 0.860015869140625 +89921 0.198486328125 +89922 0.727935791015625 +89923 0.23455810546875 +89924 0.48114013671875 +89925 0.24871826171875 +89926 0.2059326171875 +89927 0.24676513671875 +89928 -0.06103515625 +89929 0.234100341796875 +89930 -0.29913330078125 +89931 0.21319580078125 +89932 -0.516204833984375 +89933 0.180755615234375 +89934 -0.7252197265625 +89935 0.13330078125 +89936 -0.85980224609375 +89937 0.07666015625 +89938 -0.870391845703125 +89939 0.018768310546875 +89940 -0.870391845703125 +89941 -0.03350830078125 +89942 -0.858062744140625 +89943 -0.06890869140625 +89944 -0.673004150390625 +89945 -0.08648681640625 +89946 -0.42694091796875 +89947 -0.0985107421875 +89948 -0.2100830078125 +89949 -0.1153564453125 +89950 -0.0362548828125 +89951 -0.136627197265625 +89952 0.10943603515625 +89953 -0.155609130859375 +89954 0.23516845703125 +89955 -0.16778564453125 +89956 0.373687744140625 +89957 -0.16363525390625 +89958 0.517791748046875 +89959 -0.143707275390625 +89960 0.602783203125 +89961 -0.1226806640625 +89962 0.635711669921875 +89963 -0.09942626953125 +89964 0.655181884765625 +89965 -0.066253662109375 +89966 0.65948486328125 +89967 -0.0255126953125 +89968 0.651275634765625 +89969 0.020904541015625 +89970 0.61846923828125 +89971 0.06732177734375 +89972 0.53753662109375 +89973 0.105133056640625 +89974 0.404144287109375 +89975 0.13018798828125 +89976 0.22186279296875 +89977 0.14031982421875 +89978 0.003997802734375 +89979 0.1358642578125 +89980 -0.22100830078125 +89981 0.121063232421875 +89982 -0.42449951171875 +89983 0.10076904296875 +89984 -0.579833984375 +89985 0.08001708984375 +89986 -0.641876220703125 +89987 0.068756103515625 +89988 -0.6177978515625 +89989 0.065521240234375 +89990 -0.575531005859375 +89991 0.05535888671875 +89992 -0.526336669921875 +89993 0.037078857421875 +89994 -0.42645263671875 +89995 0.022735595703125 +89996 -0.2581787109375 +89997 0.0186767578125 +89998 -0.068695068359375 +89999 0.0164794921875 +90000 0.09222412109375 +90001 0.0072021484375 +90002 0.232147216796875 +90003 -0.00482177734375 +90004 0.3509521484375 +90005 -0.017242431640625 +90006 0.410064697265625 +90007 -0.036956787109375 +90008 0.372955322265625 +90009 -0.07080078125 +90010 0.2554931640625 +90011 -0.113922119140625 +90012 0.10711669921875 +90013 -0.154296875 +90014 -0.052886962890625 +90015 -0.1873779296875 +90016 -0.186279296875 +90017 -0.204803466796875 +90018 -0.23291015625 +90019 -0.19366455078125 +90020 -0.209442138671875 +90021 -0.159271240234375 +90022 -0.174163818359375 +90023 -0.116912841796875 +90024 -0.126739501953125 +90025 -0.068511962890625 +90026 -0.048126220703125 +90027 -0.011810302734375 +90028 0.0426025390625 +90029 0.046630859375 +90030 0.10748291015625 +90031 0.095977783203125 +90032 0.1409912109375 +90033 0.1331787109375 +90034 0.19708251953125 +90035 0.16925048828125 +90036 0.273651123046875 +90037 0.202667236328125 +90038 0.31768798828125 +90039 0.220489501953125 +90040 0.341094970703125 +90041 0.225311279296875 +90042 0.368011474609375 +90043 0.222991943359375 +90044 0.37249755859375 +90045 0.208221435546875 +90046 0.30072021484375 +90047 0.169586181640625 +90048 0.1517333984375 +90049 0.10821533203125 +90050 -0.01470947265625 +90051 0.039581298828125 +90052 -0.1883544921875 +90053 -0.03216552734375 +90054 -0.372711181640625 +90055 -0.1060791015625 +90056 -0.51397705078125 +90057 -0.16802978515625 +90058 -0.57177734375 +90059 -0.20709228515625 +90060 -0.53948974609375 +90061 -0.220428466796875 +90062 -0.43511962890625 +90063 -0.211212158203125 +90064 -0.2962646484375 +90065 -0.187530517578125 +90066 -0.161102294921875 +90067 -0.157958984375 +90068 -0.0435791015625 +90069 -0.125823974609375 +90070 0.060394287109375 +90071 -0.09063720703125 +90072 0.13665771484375 +90073 -0.056488037109375 +90074 0.170135498046875 +90075 -0.02789306640625 +90076 0.16552734375 +90077 -0.005035400390625 +90078 0.15728759765625 +90079 0.018646240234375 +90080 0.150787353515625 +90081 0.04296875 +90082 0.12200927734375 +90083 0.060943603515625 +90084 0.080108642578125 +90085 0.073394775390625 +90086 0.05126953125 +90087 0.08526611328125 +90088 0.062896728515625 +90089 0.10198974609375 +90090 0.09271240234375 +90091 0.11773681640625 +90092 0.092987060546875 +90093 0.121124267578125 +90094 0.07855224609375 +90095 0.1156005859375 +90096 0.06427001953125 +90097 0.104888916015625 +90098 0.0347900390625 +90099 0.0859375 +90100 -0.01171875 +90101 0.05914306640625 +90102 -0.056060791015625 +90103 0.029937744140625 +90104 -0.055511474609375 +90105 0.00933837890625 +90106 -0.010467529296875 +90107 -0.00152587890625 +90108 0.02508544921875 +90109 -0.01397705078125 +90110 0.025665283203125 +90111 -0.0328369140625 +90112 0.017333984375 +90113 -0.050872802734375 +90114 0.00189208984375 +90115 -0.066986083984375 +90116 -0.03173828125 +90117 -0.083404541015625 +90118 -0.071502685546875 +90119 -0.096923828125 +90120 -0.13543701171875 +90121 -0.112030029296875 +90122 -0.219970703125 +90123 -0.128082275390625 +90124 -0.300506591796875 +90125 -0.139312744140625 +90126 -0.376312255859375 +90127 -0.146148681640625 +90128 -0.416107177734375 +90129 -0.141571044921875 +90130 -0.371124267578125 +90131 -0.114227294921875 +90132 -0.242279052734375 +90133 -0.06524658203125 +90134 -0.069732666015625 +90135 -0.005615234375 +90136 0.125640869140625 +90137 0.05853271484375 +90138 0.31268310546875 +90139 0.118621826171875 +90140 0.45501708984375 +90141 0.1649169921875 +90142 0.554779052734375 +90143 0.197418212890625 +90144 0.61065673828125 +90145 0.21551513671875 +90146 0.610931396484375 +90147 0.216156005859375 +90148 0.531463623046875 +90149 0.193389892578125 +90150 0.3883056640625 +90151 0.1514892578125 +90152 0.23468017578125 +90153 0.10418701171875 +90154 0.095245361328125 +90155 0.0582275390625 +90156 -0.00396728515625 +90157 0.02081298828125 +90158 -0.04852294921875 +90159 -0.003753662109375 +90160 -0.055145263671875 +90161 -0.018890380859375 +90162 -0.0758056640625 +90163 -0.036865234375 +90164 -0.138702392578125 +90165 -0.06402587890625 +90166 -0.209197998046875 +90167 -0.09112548828125 +90168 -0.289031982421875 +90169 -0.118133544921875 +90170 -0.37884521484375 +90171 -0.1448974609375 +90172 -0.456329345703125 +90173 -0.165679931640625 +90174 -0.51641845703125 +90175 -0.179229736328125 +90176 -0.519287109375 +90177 -0.17578125 +90178 -0.458251953125 +90179 -0.153961181640625 +90180 -0.384796142578125 +90181 -0.127044677734375 +90182 -0.323699951171875 +90183 -0.10174560546875 +90184 -0.269287109375 +90185 -0.07720947265625 +90186 -0.1951904296875 +90187 -0.047515869140625 +90188 -0.100006103515625 +90189 -0.012908935546875 +90190 -0.01055908203125 +90191 0.019287109375 +90192 0.1033935546875 +90193 0.056121826171875 +90194 0.24908447265625 +90195 0.0989990234375 +90196 0.373199462890625 +90197 0.13427734375 +90198 0.45806884765625 +90199 0.15740966796875 +90200 0.511474609375 +90201 0.170257568359375 +90202 0.565399169921875 +90203 0.180938720703125 +90204 0.61138916015625 +90205 0.18756103515625 +90206 0.5897216796875 +90207 0.175537109375 +90208 0.4906005859375 +90209 0.142791748046875 +90210 0.33148193359375 +90211 0.09417724609375 +90212 0.147796630859375 +90213 0.0390625 +90214 -0.01873779296875 +90215 -0.0115966796875 +90216 -0.140289306640625 +90217 -0.05035400390625 +90218 -0.191986083984375 +90219 -0.070526123046875 +90220 -0.184295654296875 +90221 -0.07440185546875 +90222 -0.161834716796875 +90223 -0.0728759765625 +90224 -0.166595458984375 +90225 -0.07623291015625 +90226 -0.19390869140625 +90227 -0.083251953125 +90228 -0.22442626953125 +90229 -0.089141845703125 +90230 -0.279754638671875 +90231 -0.099456787109375 +90232 -0.3389892578125 +90233 -0.109222412109375 +90234 -0.3543701171875 +90235 -0.1068115234375 +90236 -0.348175048828125 +90237 -0.098175048828125 +90238 -0.32598876953125 +90239 -0.085113525390625 +90240 -0.2581787109375 +90241 -0.060638427734375 +90242 -0.139801025390625 +90243 -0.02392578125 +90244 0.014617919921875 +90245 0.02099609375 +90246 0.144378662109375 +90247 0.058624267578125 +90248 0.221038818359375 +90249 0.08160400390625 +90250 0.27069091796875 +90251 0.096282958984375 +90252 0.294036865234375 +90253 0.102783203125 +90254 0.311767578125 +90255 0.106292724609375 +90256 0.339141845703125 +90257 0.1107177734375 +90258 0.360260009765625 +90259 0.112457275390625 +90260 0.360504150390625 +90261 0.1080322265625 +90262 0.308380126953125 +90263 0.089324951171875 +90264 0.18170166015625 +90265 0.050750732421875 +90266 0.0047607421875 +90267 -0.0009765625 +90268 -0.17559814453125 +90269 -0.05328369140625 +90270 -0.3143310546875 +90271 -0.09405517578125 +90272 -0.36785888671875 +90273 -0.111602783203125 +90274 -0.36248779296875 +90275 -0.112701416015625 +90276 -0.343536376953125 +90277 -0.109222412109375 +90278 -0.3018798828125 +90279 -0.09869384765625 +90280 -0.231414794921875 +90281 -0.079498291015625 +90282 -0.117645263671875 +90283 -0.047882080078125 +90284 0.007049560546875 +90285 -0.01251220703125 +90286 0.087982177734375 +90287 0.011993408203125 +90288 0.13946533203125 +90289 0.02923583984375 +90290 0.17425537109375 +90291 0.0423583984375 +90292 0.188201904296875 +90293 0.050079345703125 +90294 0.171234130859375 +90295 0.04949951171875 +90296 0.118438720703125 +90297 0.03912353515625 +90298 0.05706787109375 +90299 0.025970458984375 +90300 -0.010711669921875 +90301 0.01043701171875 +90302 -0.0914306640625 +90303 -0.00927734375 +90304 -0.162322998046875 +90305 -0.0272216796875 +90306 -0.194549560546875 +90307 -0.035797119140625 +90308 -0.1492919921875 +90309 -0.02471923828125 +90310 -0.02166748046875 +90311 0.00732421875 +90312 0.124053955078125 +90313 0.043487548828125 +90314 0.211151123046875 +90315 0.063629150390625 +90316 0.240447998046875 +90317 0.068145751953125 +90318 0.242218017578125 +90319 0.065185546875 +90320 0.2257080078125 +90321 0.05743408203125 +90322 0.194366455078125 +90323 0.045989990234375 +90324 0.115509033203125 +90325 0.022369384765625 +90326 0.0128173828125 +90327 -0.0069580078125 +90328 -0.053802490234375 +90329 -0.026092529296875 +90330 -0.110626220703125 +90331 -0.04193115234375 +90332 -0.199493408203125 +90333 -0.065460205078125 +90334 -0.29437255859375 +90335 -0.08984375 +90336 -0.33221435546875 +90337 -0.0985107421875 +90338 -0.27972412109375 +90339 -0.082794189453125 +90340 -0.185333251953125 +90341 -0.055572509765625 +90342 -0.128204345703125 +90343 -0.037872314453125 +90344 -0.115692138671875 +90345 -0.031768798828125 +90346 -0.116455078125 +90347 -0.029144287109375 +90348 -0.105926513671875 +90349 -0.023712158203125 +90350 -0.053955078125 +90351 -0.00762939453125 +90352 0.048797607421875 +90353 0.02142333984375 +90354 0.157318115234375 +90355 0.051483154296875 +90356 0.212005615234375 +90357 0.066741943359375 +90358 0.218475341796875 +90359 0.068634033203125 +90360 0.23724365234375 +90361 0.07318115234375 +90362 0.30535888671875 +90363 0.090179443359375 +90364 0.38128662109375 +90365 0.108734130859375 +90366 0.404449462890625 +90367 0.112945556640625 +90368 0.3944091796875 +90369 0.10870361328125 +90370 0.3885498046875 +90371 0.10662841796875 +90372 0.362640380859375 +90373 0.0994873046875 +90374 0.27362060546875 +90375 0.0743408203125 +90376 0.11712646484375 +90377 0.029693603515625 +90378 -0.054901123046875 +90379 -0.01922607421875 +90380 -0.19085693359375 +90381 -0.05731201171875 +90382 -0.28570556640625 +90383 -0.083251953125 +90384 -0.339263916015625 +90385 -0.097137451171875 +90386 -0.3775634765625 +90387 -0.106781005859375 +90388 -0.445709228515625 +90389 -0.1256103515625 +90390 -0.535064697265625 +90391 -0.151153564453125 +90392 -0.629058837890625 +90393 -0.17852783203125 +90394 -0.697601318359375 +90395 -0.19879150390625 +90396 -0.70391845703125 +90397 -0.2010498046875 +90398 -0.6424560546875 +90399 -0.183624267578125 +90400 -0.491241455078125 +90401 -0.13995361328125 +90402 -0.265716552734375 +90403 -0.074554443359375 +90404 -0.023712158203125 +90405 -0.00445556640625 +90406 0.201751708984375 +90407 0.060638427734375 +90408 0.375823974609375 +90409 0.110504150390625 +90410 0.485076904296875 +90411 0.141265869140625 +90412 0.56884765625 +90413 0.1646728515625 +90414 0.634765625 +90415 0.18304443359375 +90416 0.63763427734375 +90417 0.18304443359375 +90418 0.5660400390625 +90419 0.161346435546875 +90420 0.4720458984375 +90421 0.133392333984375 +90422 0.40692138671875 +90423 0.11431884765625 +90424 0.3778076171875 +90425 0.106231689453125 +90426 0.376953125 +90427 0.1068115234375 +90428 0.371978759765625 +90429 0.106414794921875 +90430 0.313140869140625 +90431 0.090240478515625 +90432 0.184417724609375 +90433 0.053436279296875 +90434 0.011199951171875 +90435 0.00347900390625 +90436 -0.171051025390625 +90437 -0.04913330078125 +90438 -0.33740234375 +90439 -0.09710693359375 +90440 -0.47198486328125 +90441 -0.135833740234375 +90442 -0.560394287109375 +90443 -0.1611328125 +90444 -0.58056640625 +90445 -0.16650390625 +90446 -0.54754638671875 +90447 -0.156402587890625 +90448 -0.508575439453125 +90449 -0.144866943359375 +90450 -0.459503173828125 +90451 -0.130645751953125 +90452 -0.394378662109375 +90453 -0.1119384765625 +90454 -0.35260009765625 +90455 -0.100341796875 +90456 -0.31170654296875 +90457 -0.08917236328125 +90458 -0.197418212890625 +90459 -0.056365966796875 +90460 -0.007965087890625 +90461 -0.001373291015625 +90462 0.207489013671875 +90463 0.061279296875 +90464 0.409210205078125 +90465 0.119873046875 +90466 0.57208251953125 +90467 0.16705322265625 +90468 0.66595458984375 +90469 0.193939208984375 +90470 0.65875244140625 +90471 0.191131591796875 +90472 0.56744384765625 +90473 0.163665771484375 +90474 0.431396484375 +90475 0.123199462890625 +90476 0.29443359375 +90477 0.082733154296875 +90478 0.182464599609375 +90479 0.0499267578125 +90480 0.06365966796875 +90481 0.01531982421875 +90482 -0.075958251953125 +90483 -0.025238037109375 +90484 -0.189422607421875 +90485 -0.05792236328125 +90486 -0.271942138671875 +90487 -0.081329345703125 +90488 -0.342529296875 +90489 -0.101165771484375 +90490 -0.364166259765625 +90491 -0.1065673828125 +90492 -0.327239990234375 +90493 -0.0947265625 +90494 -0.2769775390625 +90495 -0.079071044921875 +90496 -0.253692626953125 +90497 -0.071563720703125 +90498 -0.24365234375 +90499 -0.068145751953125 +90500 -0.1983642578125 +90501 -0.05450439453125 +90502 -0.116241455078125 +90503 -0.030181884765625 +90504 -0.036834716796875 +90505 -0.006866455078125 +90506 0.034881591796875 +90507 0.013946533203125 +90508 0.09124755859375 +90509 0.030029296875 +90510 0.10888671875 +90511 0.034515380859375 +90512 0.125518798828125 +90513 0.038604736328125 +90514 0.15771484375 +90515 0.047271728515625 +90516 0.17828369140625 +90517 0.052490234375 +90518 0.17108154296875 +90519 0.04949951171875 +90520 0.129974365234375 +90521 0.03656005859375 +90522 0.082427978515625 +90523 0.021820068359375 +90524 0.027679443359375 +90525 0.005126953125 +90526 -0.065643310546875 +90527 -0.02276611328125 +90528 -0.15936279296875 +90529 -0.050537109375 +90530 -0.21307373046875 +90531 -0.0662841796875 +90532 -0.234649658203125 +90533 -0.07232666015625 +90534 -0.2001953125 +90535 -0.061614990234375 +90536 -0.119171142578125 +90537 -0.0369873046875 +90538 -0.024749755859375 +90539 -0.00830078125 +90540 0.085784912109375 +90541 0.025177001953125 +90542 0.178131103515625 +90543 0.05322265625 +90544 0.215576171875 +90545 0.06494140625 +90546 0.211456298828125 +90547 0.06427001953125 +90548 0.17523193359375 +90549 0.05401611328125 +90550 0.128753662109375 +90551 0.040618896484375 +90552 0.1019287109375 +90553 0.03289794921875 +90554 0.0743408203125 +90555 0.024810791015625 +90556 0.04327392578125 +90557 0.015533447265625 +90558 0.038177490234375 +90559 0.0137939453125 +90560 0.076263427734375 +90561 0.024688720703125 +90562 0.14105224609375 +90563 0.043365478515625 +90564 0.186431884765625 +90565 0.05621337890625 +90566 0.188812255859375 +90567 0.0562744140625 +90568 0.1390380859375 +90569 0.0408935546875 +90570 0.041778564453125 +90571 0.011505126953125 +90572 -0.079437255859375 +90573 -0.02490234375 +90574 -0.219390869140625 +90575 -0.066741943359375 +90576 -0.367828369140625 +90577 -0.1109619140625 +90578 -0.494873046875 +90579 -0.148681640625 +90580 -0.556243896484375 +90581 -0.16680908203125 +90582 -0.508697509765625 +90583 -0.152557373046875 +90584 -0.3756103515625 +90585 -0.11285400390625 +90586 -0.218902587890625 +90587 -0.066070556640625 +90588 -0.063751220703125 +90589 -0.019683837890625 +90590 0.091552734375 +90591 0.026763916015625 +90592 0.23602294921875 +90593 0.07000732421875 +90594 0.342987060546875 +90595 0.10211181640625 +90596 0.39520263671875 +90597 0.11798095703125 +90598 0.389373779296875 +90599 0.116607666015625 +90600 0.324249267578125 +90601 0.097625732421875 +90602 0.224090576171875 +90603 0.068206787109375 +90604 0.124267578125 +90605 0.038787841796875 +90606 0.037078857421875 +90607 0.01300048828125 +90608 -0.010101318359375 +90609 -0.00103759765625 +90610 -0.019439697265625 +90611 -0.00396728515625 +90612 -0.022796630859375 +90613 -0.00518798828125 +90614 -0.001556396484375 +90615 0.000762939453125 +90616 0.056304931640625 +90617 0.017486572265625 +90618 0.106719970703125 +90619 0.031951904296875 +90620 0.096893310546875 +90621 0.028564453125 +90622 0.042694091796875 +90623 0.012054443359375 +90624 -0.018035888671875 +90625 -0.006622314453125 +90626 -0.07586669921875 +90627 -0.02447509765625 +90628 -0.11944580078125 +90629 -0.037506103515625 +90630 -0.15972900390625 +90631 -0.049468994140625 +90632 -0.202606201171875 +90633 -0.062469482421875 +90634 -0.24859619140625 +90635 -0.076690673828125 +90636 -0.30517578125 +90637 -0.094696044921875 +90638 -0.36212158203125 +90639 -0.1131591796875 +90640 -0.39141845703125 +90641 -0.122894287109375 +90642 -0.35528564453125 +90643 -0.11151123046875 +90644 -0.249969482421875 +90645 -0.077728271484375 +90646 -0.092864990234375 +90647 -0.0272216796875 +90648 0.08905029296875 +90649 0.03125 +90650 0.2352294921875 +90651 0.077911376953125 +90652 0.318817138671875 +90653 0.104034423828125 +90654 0.358642578125 +90655 0.1158447265625 +90656 0.347747802734375 +90657 0.11114501953125 +90658 0.28564453125 +90659 0.08984375 +90660 0.223175048828125 +90661 0.06866455078125 +90662 0.196746826171875 +90663 0.0595703125 +90664 0.179840087890625 +90665 0.053863525390625 +90666 0.155548095703125 +90667 0.0460205078125 +90668 0.151214599609375 +90669 0.045013427734375 +90670 0.156951904296875 +90671 0.04754638671875 +90672 0.13177490234375 +90673 0.040130615234375 +90674 0.100799560546875 +90675 0.03094482421875 +90676 0.087127685546875 +90677 0.02752685546875 +90678 0.05487060546875 +90679 0.01806640625 +90680 -0.009002685546875 +90681 -0.00177001953125 +90682 -0.10400390625 +90683 -0.031890869140625 +90684 -0.229400634765625 +90685 -0.072113037109375 +90686 -0.35552978515625 +90687 -0.112762451171875 +90688 -0.441925048828125 +90689 -0.14056396484375 +90690 -0.473846435546875 +90691 -0.150726318359375 +90692 -0.464813232421875 +90693 -0.147674560546875 +90694 -0.419097900390625 +90695 -0.132843017578125 +90696 -0.334320068359375 +90697 -0.105438232421875 +90698 -0.227935791015625 +90699 -0.071136474609375 +90700 -0.12347412109375 +90701 -0.037628173828125 +90702 -0.02764892578125 +90703 -0.007049560546875 +90704 0.077667236328125 +90705 0.026580810546875 +90706 0.2132568359375 +90707 0.070098876953125 +90708 0.38885498046875 +90709 0.12677001953125 +90710 0.582794189453125 +90711 0.18951416015625 +90712 0.734039306640625 +90713 0.238372802734375 +90714 0.800140380859375 +90715 0.259429931640625 +90716 0.7783203125 +90717 0.2518310546875 +90718 0.6651611328125 +90719 0.2144775390625 +90720 0.45965576171875 +90721 0.14703369140625 +90722 0.199188232421875 +90723 0.061767578125 +90724 -0.050689697265625 +90725 -0.019805908203125 +90726 -0.23297119140625 +90727 -0.079010009765625 +90728 -0.33013916015625 +90729 -0.11016845703125 +90730 -0.368408203125 +90731 -0.121917724609375 +90732 -0.378936767578125 +90733 -0.124481201171875 +90734 -0.376983642578125 +90735 -0.12298583984375 +90736 -0.37969970703125 +90737 -0.123077392578125 +90738 -0.391510009765625 +90739 -0.126251220703125 +90740 -0.385345458984375 +90741 -0.123626708984375 +90742 -0.3419189453125 +90743 -0.10894775390625 +90744 -0.28289794921875 +90745 -0.089324951171875 +90746 -0.251617431640625 +90747 -0.078948974609375 +90748 -0.266143798828125 +90749 -0.083770751953125 +90750 -0.273345947265625 +90751 -0.086395263671875 +90752 -0.216796875 +90753 -0.0682373046875 +90754 -0.128265380859375 +90755 -0.039703369140625 +90756 -0.068145751953125 +90757 -0.02056884765625 +90758 -0.0430908203125 +90759 -0.01300048828125 +90760 -0.024444580078125 +90761 -0.007537841796875 +90762 0.020721435546875 +90763 0.006622314453125 +90764 0.124481201171875 +90765 0.040008544921875 +90766 0.25787353515625 +90767 0.083160400390625 +90768 0.379119873046875 +90769 0.122406005859375 +90770 0.47991943359375 +90771 0.155059814453125 +90772 0.5281982421875 +90773 0.170654296875 +90774 0.511138916015625 +90775 0.164947509765625 +90776 0.456207275390625 +90777 0.14697265625 +90778 0.407470703125 +90779 0.13116455078125 +90780 0.383758544921875 +90781 0.123687744140625 +90782 0.35687255859375 +90783 0.115264892578125 +90784 0.31182861328125 +90785 0.1009521484375 +90786 0.250885009765625 +90787 0.081451416015625 +90788 0.1654052734375 +90789 0.053924560546875 +90790 0.035247802734375 +90791 0.011749267578125 +90792 -0.142059326171875 +90793 -0.045867919921875 +90794 -0.33563232421875 +90795 -0.108856201171875 +90796 -0.5345458984375 +90797 -0.17364501953125 +90798 -0.72186279296875 +90799 -0.234710693359375 +90800 -0.836669921875 +90801 -0.272064208984375 +90802 -0.8326416015625 +90803 -0.27056884765625 +90804 -0.7296142578125 +90805 -0.236724853515625 +90806 -0.582550048828125 +90807 -0.188568115234375 +90808 -0.440093994140625 +90809 -0.142059326171875 +90810 -0.324310302734375 +90811 -0.10443115234375 +90812 -0.20147705078125 +90813 -0.0645751953125 +90814 -0.044647216796875 +90815 -0.013580322265625 +90816 0.103973388671875 +90817 0.034698486328125 +90818 0.202392578125 +90819 0.066497802734375 +90820 0.264495849609375 +90821 0.08636474609375 +90822 0.338897705078125 +90823 0.11029052734375 +90824 0.443817138671875 +90825 0.144287109375 +90826 0.545074462890625 +90827 0.177154541015625 +90828 0.6173095703125 +90829 0.20062255859375 +90830 0.6524658203125 +90831 0.2120361328125 +90832 0.66339111328125 +90833 0.215606689453125 +90834 0.6561279296875 +90835 0.21331787109375 +90836 0.606781005859375 +90837 0.197296142578125 +90838 0.501190185546875 +90839 0.16290283203125 +90840 0.352783203125 +90841 0.114532470703125 +90842 0.176544189453125 +90843 0.05706787109375 +90844 -0.034820556640625 +90845 -0.0118408203125 +90846 -0.258209228515625 +90847 -0.08465576171875 +90848 -0.44244384765625 +90849 -0.14459228515625 +90850 -0.5753173828125 +90851 -0.18768310546875 +90852 -0.65203857421875 +90853 -0.21240234375 +90854 -0.641632080078125 +90855 -0.2086181640625 +90856 -0.562164306640625 +90857 -0.18231201171875 +90858 -0.458038330078125 +90859 -0.148040771484375 +90860 -0.350555419921875 +90861 -0.112762451171875 +90862 -0.260528564453125 +90863 -0.083343505859375 +90864 -0.192108154296875 +90865 -0.061126708984375 +90866 -0.141937255859375 +90867 -0.04498291015625 +90868 -0.1021728515625 +90869 -0.032318115234375 +90870 -0.062896728515625 +90871 -0.019866943359375 +90872 -0.011932373046875 +90873 -0.003570556640625 +90874 0.062835693359375 +90875 0.020538330078125 +90876 0.148712158203125 +90877 0.048309326171875 +90878 0.241729736328125 +90879 0.078460693359375 +90880 0.34912109375 +90881 0.113677978515625 +90882 0.457305908203125 +90883 0.150299072265625 +90884 0.54388427734375 +90885 0.180877685546875 +90886 0.5728759765625 +90887 0.192138671875 +90888 0.506591796875 +90889 0.170196533203125 +90890 0.351226806640625 +90891 0.116943359375 +90892 0.146514892578125 +90893 0.04638671875 +90894 -0.05523681640625 +90895 -0.02288818359375 +90896 -0.21624755859375 +90897 -0.0775146484375 +90898 -0.334930419921875 +90899 -0.11712646484375 +90900 -0.402984619140625 +90901 -0.138885498046875 +90902 -0.4412841796875 +90903 -0.15045166015625 +90904 -0.49578857421875 +90905 -0.16845703125 +90906 -0.5601806640625 +90907 -0.190704345703125 +90908 -0.600738525390625 +90909 -0.205047607421875 +90910 -0.584228515625 +90911 -0.199493408203125 +90912 -0.47930908203125 +90913 -0.162689208984375 +90914 -0.27935791015625 +90915 -0.092193603515625 +90916 -0.0089111328125 +90917 0.00323486328125 +90918 0.268798828125 +90919 0.1009521484375 +90920 0.482818603515625 +90921 0.175567626953125 +90922 0.60369873046875 +90923 0.216644287109375 +90924 0.650421142578125 +90925 0.231109619140625 +90926 0.66400146484375 +90927 0.23388671875 +90928 0.6414794921875 +90929 0.2239990234375 +90930 0.572540283203125 +90931 0.19781494140625 +90932 0.498138427734375 +90933 0.170166015625 +90934 0.439453125 +90935 0.148712158203125 +90936 0.375518798828125 +90937 0.12591552734375 +90938 0.274505615234375 +90939 0.09027099609375 +90940 0.1087646484375 +90941 0.031768798828125 +90942 -0.099395751953125 +90943 -0.0416259765625 +90944 -0.3182373046875 +90945 -0.118560791015625 +90946 -0.5489501953125 +90947 -0.199615478515625 +90948 -0.7738037109375 +90949 -0.278472900390625 +90950 -0.86383056640625 +90951 -0.336212158203125 +90952 -0.870391845703125 +90953 -0.3609619140625 +90954 -0.86895751953125 +90955 -0.35919189453125 +90956 -0.861053466796875 +90957 -0.335723876953125 +90958 -0.765869140625 +90959 -0.284393310546875 +90960 -0.5301513671875 +90961 -0.201171875 +90962 -0.214691162109375 +90963 -0.088592529296875 +90964 0.137359619140625 +90965 0.037811279296875 +90966 0.474822998046875 +90967 0.15960693359375 +90968 0.76239013671875 +90969 0.2640380859375 +90970 0.867462158203125 +90971 0.341461181640625 +90972 0.870361328125 +90973 0.39215087890625 +90974 0.86480712890625 +90975 0.4119873046875 +90976 0.831817626953125 +90977 0.40301513671875 +90978 0.677581787109375 +90979 0.374114990234375 +90980 0.495880126953125 +90981 0.32745361328125 +90982 0.30767822265625 +90983 0.269805908203125 +90984 0.116180419921875 +90985 0.2020263671875 +90986 -0.110748291015625 +90987 0.11273193359375 +90988 -0.381805419921875 +90989 -0.000518798828125 +90990 -0.6572265625 +90991 -0.122314453125 +90992 -0.857421875 +90993 -0.231109619140625 +90994 -0.870391845703125 +90995 -0.3115234375 +90996 -0.870391845703125 +90997 -0.361053466796875 +90998 -0.86444091796875 +90999 -0.389434814453125 +91000 -0.85723876953125 +91001 -0.40960693359375 +91002 -0.790008544921875 +91003 -0.4150390625 +91004 -0.62847900390625 +91005 -0.38629150390625 +91006 -0.3956298828125 +91007 -0.322265625 +91008 -0.126708984375 +91009 -0.23486328125 +91010 0.150115966796875 +91011 -0.134002685546875 +91012 0.424041748046875 +91013 -0.023956298828125 +91014 0.670623779296875 +91015 0.085540771484375 +91016 0.854522705078125 +91017 0.180511474609375 +91018 0.866485595703125 +91019 0.254638671875 +91020 0.86920166015625 +91021 0.302398681640625 +91022 0.8653564453125 +91023 0.33038330078125 +91024 0.857147216796875 +91025 0.34344482421875 +91026 0.766845703125 +91027 0.340576171875 +91028 0.628509521484375 +91029 0.323699951171875 +91030 0.462127685546875 +91031 0.29046630859375 +91032 0.297210693359375 +91033 0.250213623046875 +91034 0.14862060546875 +91035 0.20745849609375 +91036 -0.00537109375 +91037 0.154022216796875 +91038 -0.15753173828125 +91039 0.092681884765625 +91040 -0.31304931640625 +91041 0.022186279296875 +91042 -0.48876953125 +91043 -0.0625 +91044 -0.6416015625 +91045 -0.144500732421875 +91046 -0.751373291015625 +91047 -0.21490478515625 +91048 -0.84619140625 +91049 -0.28204345703125 +91050 -0.861297607421875 +91051 -0.340667724609375 +91052 -0.863250732421875 +91053 -0.378875732421875 +91054 -0.856597900390625 +91055 -0.385345458984375 +91056 -0.7498779296875 +91057 -0.364501953125 +91058 -0.624542236328125 +91059 -0.33721923828125 +91060 -0.47808837890625 +91061 -0.295684814453125 +91062 -0.253387451171875 +91063 -0.218902587890625 +91064 0.003692626953125 +91065 -0.12335205078125 +91066 0.2257080078125 +91067 -0.03369140625 +91068 0.427154541015625 +91069 0.054534912109375 +91070 0.643218994140625 +91071 0.152984619140625 +91072 0.855926513671875 +91073 0.2581787109375 +91074 0.870361328125 +91075 0.3492431640625 +91076 0.870361328125 +91077 0.4083251953125 +91078 0.862762451171875 +91079 0.43804931640625 +91080 0.79669189453125 +91081 0.437408447265625 +91082 0.595794677734375 +91083 0.403076171875 +91084 0.362152099609375 +91085 0.3455810546875 +91086 0.1270751953125 +91087 0.27508544921875 +91088 -0.086944580078125 +91089 0.19927978515625 +91090 -0.2784423828125 +91091 0.118927001953125 +91092 -0.484832763671875 +91093 0.021575927734375 +91094 -0.729583740234375 +91095 -0.099609375 +91096 -0.86688232421875 +91097 -0.226348876953125 +91098 -0.870391845703125 +91099 -0.3358154296875 +91100 -0.86859130859375 +91101 -0.426177978515625 +91102 -0.86279296875 +91103 -0.496673583984375 +91104 -0.817962646484375 +91105 -0.534393310546875 +91106 -0.6116943359375 +91107 -0.52301025390625 +91108 -0.3128662109375 +91109 -0.459991455078125 +91110 0.039398193359375 +91111 -0.35748291015625 +91112 0.422821044921875 +91113 -0.2227783203125 +91114 0.805145263671875 +91115 -0.067901611328125 +91116 0.870361328125 +91117 0.082489013671875 +91118 0.870361328125 +91119 0.207794189453125 +91120 0.860015869140625 +91121 0.303680419921875 +91122 0.727935791015625 +91123 0.367279052734375 +91124 0.48114013671875 +91125 0.396453857421875 +91126 0.2059326171875 +91127 0.39984130859375 +91128 -0.06103515625 +91129 0.385498046875 +91130 -0.29913330078125 +91131 0.35699462890625 +91132 -0.516204833984375 +91133 0.30908203125 +91134 -0.7252197265625 +91135 0.236236572265625 +91136 -0.85980224609375 +91137 0.147674560546875 +91138 -0.870391845703125 +91139 0.055419921875 +91140 -0.870391845703125 +91141 -0.029754638671875 +91142 -0.858062744140625 +91143 -0.088653564453125 +91144 -0.673004150390625 +91145 -0.11944580078125 +91146 -0.42694091796875 +91147 -0.142547607421875 +91148 -0.2100830078125 +91149 -0.175140380859375 +91150 -0.0362548828125 +91151 -0.2161865234375 +91152 0.10943603515625 +91153 -0.254058837890625 +91154 0.23516845703125 +91155 -0.28070068359375 +91156 0.373687744140625 +91157 -0.2796630859375 +91158 0.517791748046875 +91159 -0.251556396484375 +91160 0.602783203125 +91161 -0.22088623046875 +91162 0.635711669921875 +91163 -0.18548583984375 +91164 0.655181884765625 +91165 -0.1322021484375 +91166 0.65948486328125 +91167 -0.06488037109375 +91168 0.651275634765625 +91169 0.0133056640625 +91170 0.61846923828125 +91171 0.092742919921875 +91172 0.53753662109375 +91173 0.1588134765625 +91174 0.404144287109375 +91175 0.204345703125 +91176 0.22186279296875 +91177 0.22540283203125 +91178 0.003997802734375 +91179 0.222320556640625 +91180 -0.22100830078125 +91181 0.202056884765625 +91182 -0.42449951171875 +91183 0.172515869140625 +91184 -0.579833984375 +91185 0.141937255859375 +91186 -0.641876220703125 +91187 0.12689208984375 +91188 -0.6177978515625 +91189 0.12469482421875 +91190 -0.575531005859375 +91191 0.109954833984375 +91192 -0.526336669921875 +91193 0.08050537109375 +91194 -0.42645263671875 +91195 0.056640625 +91196 -0.2581787109375 +91197 0.0491943359375 +91198 -0.068695068359375 +91199 0.043975830078125 +91200 0.09222412109375 +91201 0.025970458984375 +91202 0.232147216796875 +91203 0.00262451171875 +91204 0.3509521484375 +91205 -0.021881103515625 +91206 0.410064697265625 +91207 -0.05902099609375 +91208 0.372955322265625 +91209 -0.1201171875 +91210 0.2554931640625 +91211 -0.196807861328125 +91212 0.10711669921875 +91213 -0.268524169921875 +91214 -0.052886962890625 +91215 -0.32745361328125 +91216 -0.186279296875 +91217 -0.35931396484375 +91218 -0.23291015625 +91219 -0.34210205078125 +91220 -0.209442138671875 +91221 -0.284759521484375 +91222 -0.174163818359375 +91223 -0.213104248046875 +91224 -0.126739501953125 +91225 -0.13043212890625 +91226 -0.048126220703125 +91227 -0.032958984375 +91228 0.0426025390625 +91229 0.068115234375 +91230 0.10748291015625 +91231 0.15435791015625 +91232 0.1409912109375 +91233 0.220428466796875 +91234 0.19708251953125 +91235 0.284820556640625 +91236 0.273651123046875 +91237 0.344696044921875 +91238 0.31768798828125 +91239 0.3780517578125 +91240 0.341094970703125 +91241 0.3890380859375 +91242 0.368011474609375 +91243 0.387420654296875 +91244 0.37249755859375 +91245 0.364105224609375 +91246 0.30072021484375 +91247 0.299713134765625 +91248 0.1517333984375 +91249 0.1961669921875 +91250 -0.01470947265625 +91251 0.079620361328125 +91252 -0.1883544921875 +91253 -0.04290771484375 +91254 -0.372711181640625 +91255 -0.16973876953125 +91256 -0.51397705078125 +91257 -0.276824951171875 +91258 -0.57177734375 +91259 -0.3455810546875 +91260 -0.53948974609375 +91261 -0.37103271484375 +91262 -0.43511962890625 +91263 -0.358428955078125 +91264 -0.2962646484375 +91265 -0.32122802734375 +91266 -0.161102294921875 +91267 -0.2738037109375 +91268 -0.0435791015625 +91269 -0.22161865234375 +91270 0.060394287109375 +91271 -0.16375732421875 +91272 0.13665771484375 +91273 -0.10699462890625 +91274 0.170135498046875 +91275 -0.058990478515625 +91276 0.16552734375 +91277 -0.020050048828125 +91278 0.15728759765625 +91279 0.02093505859375 +91280 0.150787353515625 +91281 0.063568115234375 +91282 0.12200927734375 +91283 0.095916748046875 +91284 0.080108642578125 +91285 0.119232177734375 +91286 0.05126953125 +91287 0.1417236328125 +91288 0.062896728515625 +91289 0.1724853515625 +91290 0.09271240234375 +91291 0.201568603515625 +91292 0.092987060546875 +91293 0.209564208984375 +91294 0.07855224609375 +91295 0.2021484375 +91296 0.06427001953125 +91297 0.18548583984375 +91298 0.0347900390625 +91299 0.154449462890625 +91300 -0.01171875 +91301 0.109588623046875 +91302 -0.056060791015625 +91303 0.060089111328125 +91304 -0.055511474609375 +91305 0.024627685546875 +91306 -0.010467529296875 +91307 0.005096435546875 +91308 0.02508544921875 +91309 -0.017547607421875 +91310 0.025665283203125 +91311 -0.051300048828125 +91312 0.017333984375 +91313 -0.084197998046875 +91314 0.00189208984375 +91315 -0.114044189453125 +91316 -0.03173828125 +91317 -0.14404296875 +91318 -0.071502685546875 +91319 -0.16876220703125 +91320 -0.13543701171875 +91321 -0.195037841796875 +91322 -0.219970703125 +91323 -0.221588134765625 +91324 -0.300506591796875 +91325 -0.239349365234375 +91326 -0.376312255859375 +91327 -0.2490234375 +91328 -0.416107177734375 +91329 -0.239593505859375 +91330 -0.371124267578125 +91331 -0.193450927734375 +91332 -0.242279052734375 +91333 -0.11260986328125 +91334 -0.069732666015625 +91335 -0.0145263671875 +91336 0.125640869140625 +91337 0.0909423828125 +91338 0.31268310546875 +91339 0.190032958984375 +91340 0.45501708984375 +91341 0.267181396484375 +91342 0.554779052734375 +91343 0.322174072265625 +91344 0.61065673828125 +91345 0.353790283203125 +91346 0.610931396484375 +91347 0.357086181640625 +91348 0.531463623046875 +91349 0.3226318359375 +91350 0.3883056640625 +91351 0.257080078125 +91352 0.23468017578125 +91353 0.181976318359375 +91354 0.095245361328125 +91355 0.10797119140625 +91356 -0.00396728515625 +91357 0.04644775390625 +91358 -0.04852294921875 +91359 0.004364013671875 +91360 -0.055145263671875 +91361 -0.023406982421875 +91362 -0.0758056640625 +91363 -0.055877685546875 +91364 -0.138702392578125 +91365 -0.102752685546875 +91366 -0.209197998046875 +91367 -0.1492919921875 +91368 -0.289031982421875 +91369 -0.19525146484375 +91370 -0.37884521484375 +91371 -0.240234375 +91372 -0.456329345703125 +91373 -0.27508544921875 +91374 -0.51641845703125 +91375 -0.2977294921875 +91376 -0.519287109375 +91377 -0.292755126953125 +91378 -0.458251953125 +91379 -0.258026123046875 +91380 -0.384796142578125 +91381 -0.214447021484375 +91382 -0.323699951171875 +91383 -0.17266845703125 +91384 -0.269287109375 +91385 -0.131500244140625 +91386 -0.1951904296875 +91387 -0.08172607421875 +91388 -0.100006103515625 +91389 -0.02398681640625 +91390 -0.01055908203125 +91391 0.03009033203125 +91392 0.1033935546875 +91393 0.09149169921875 +91394 0.24908447265625 +91395 0.162200927734375 +91396 0.373199462890625 +91397 0.220306396484375 +91398 0.45806884765625 +91399 0.25848388671875 +91400 0.511474609375 +91401 0.27978515625 +91402 0.565399169921875 +91403 0.29718017578125 +91404 0.61138916015625 +91405 0.30767822265625 +91406 0.5897216796875 +91407 0.287933349609375 +91408 0.4906005859375 +91409 0.234710693359375 +91410 0.33148193359375 +91411 0.15582275390625 +91412 0.147796630859375 +91413 0.066314697265625 +91414 -0.01873779296875 +91415 -0.0162353515625 +91416 -0.140289306640625 +91417 -0.079833984375 +91418 -0.191986083984375 +91419 -0.113739013671875 +91420 -0.184295654296875 +91421 -0.1214599609375 +91422 -0.161834716796875 +91423 -0.120330810546875 +91424 -0.166595458984375 +91425 -0.126800537109375 +91426 -0.19390869140625 +91427 -0.13885498046875 +91428 -0.22442626953125 +91429 -0.1488037109375 +91430 -0.279754638671875 +91431 -0.16552734375 +91432 -0.3389892578125 +91433 -0.1810302734375 +91434 -0.3543701171875 +91435 -0.176727294921875 +91436 -0.348175048828125 +91437 -0.16217041015625 +91438 -0.32598876953125 +91439 -0.140289306640625 +91440 -0.2581787109375 +91441 -0.100006103515625 +91442 -0.139801025390625 +91443 -0.0400390625 +91444 0.014617919921875 +91445 0.033111572265625 +91446 0.144378662109375 +91447 0.09454345703125 +91448 0.221038818359375 +91449 0.132476806640625 +91450 0.27069091796875 +91451 0.156982421875 +91452 0.294036865234375 +91453 0.168182373046875 +91454 0.311767578125 +91455 0.17431640625 +91456 0.339141845703125 +91457 0.181732177734375 +91458 0.360260009765625 +91459 0.184600830078125 +91460 0.360504150390625 +91461 0.177398681640625 +91462 0.308380126953125 +91463 0.1470947265625 +91464 0.18170166015625 +91465 0.08465576171875 +91466 0.0047607421875 +91467 0.0008544921875 +91468 -0.17559814453125 +91469 -0.084014892578125 +91470 -0.3143310546875 +91471 -0.15045166015625 +91472 -0.36785888671875 +91473 -0.179595947265625 +91474 -0.36248779296875 +91475 -0.18231201171875 +91476 -0.343536376953125 +91477 -0.177581787109375 +91478 -0.3018798828125 +91479 -0.16143798828125 +91480 -0.231414794921875 +91481 -0.1312255859375 +91482 -0.117645263671875 +91483 -0.08087158203125 +91484 0.007049560546875 +91485 -0.024261474609375 +91486 0.087982177734375 +91487 0.01513671875 +91488 0.13946533203125 +91489 0.0430908203125 +91490 0.17425537109375 +91491 0.064666748046875 +91492 0.188201904296875 +91493 0.07769775390625 +91494 0.171234130859375 +91495 0.0775146484375 +91496 0.118438720703125 +91497 0.061676025390625 +91498 0.05706787109375 +91499 0.041412353515625 +91500 -0.010711669921875 +91501 0.017333984375 +91502 -0.0914306640625 +91503 -0.0135498046875 +91504 -0.162322998046875 +91505 -0.041717529296875 +91506 -0.194549560546875 +91507 -0.055023193359375 +91508 -0.1492919921875 +91509 -0.036956787109375 +91510 -0.02166748046875 +91511 0.014617919921875 +91512 0.124053955078125 +91513 0.0726318359375 +91514 0.211151123046875 +91515 0.10479736328125 +91516 0.240447998046875 +91517 0.11175537109375 +91518 0.242218017578125 +91519 0.10662841796875 +91520 0.2257080078125 +91521 0.093719482421875 +91522 0.194366455078125 +91523 0.074798583984375 +91524 0.115509033203125 +91525 0.036285400390625 +91526 0.0128173828125 +91527 -0.011444091796875 +91528 -0.053802490234375 +91529 -0.042816162109375 +91530 -0.110626220703125 +91531 -0.068817138671875 +91532 -0.199493408203125 +91533 -0.107147216796875 +91534 -0.29437255859375 +91535 -0.14678955078125 +91536 -0.33221435546875 +91537 -0.161041259765625 +91538 -0.27972412109375 +91539 -0.13592529296875 +91540 -0.185333251953125 +91541 -0.0921630859375 +91542 -0.128204345703125 +91543 -0.063568115234375 +91544 -0.115692138671875 +91545 -0.053466796875 +91546 -0.116455078125 +91547 -0.048858642578125 +91548 -0.105926513671875 +91549 -0.03961181640625 +91550 -0.053955078125 +91551 -0.013214111328125 +91552 0.048797607421875 +91553 0.0340576171875 +91554 0.157318115234375 +91555 0.082916259765625 +91556 0.212005615234375 +91557 0.108001708984375 +91558 0.218475341796875 +91559 0.111602783203125 +91560 0.23724365234375 +91561 0.119384765625 +91562 0.30535888671875 +91563 0.147064208984375 +91564 0.38128662109375 +91565 0.1771240234375 +91566 0.404449462890625 +91567 0.183990478515625 +91568 0.3944091796875 +91569 0.176177978515625 +91570 0.3885498046875 +91571 0.16973876953125 +91572 0.362640380859375 +91573 0.154632568359375 +91574 0.27362060546875 +91575 0.11285400390625 +91576 0.11712646484375 +91577 0.042755126953125 +91578 -0.054901123046875 +91579 -0.033416748046875 +91580 -0.19085693359375 +91581 -0.0936279296875 +91582 -0.28570556640625 +91583 -0.1356201171875 +91584 -0.339263916015625 +91585 -0.159271240234375 +91586 -0.3775634765625 +91587 -0.175537109375 +91588 -0.445709228515625 +91589 -0.20361328125 +91590 -0.535064697265625 +91591 -0.239898681640625 +91592 -0.629058837890625 +91593 -0.2774658203125 +91594 -0.697601318359375 +91595 -0.303680419921875 +91596 -0.70391845703125 +91597 -0.303131103515625 +91598 -0.6424560546875 +91599 -0.273651123046875 +91600 -0.491241455078125 +91601 -0.206146240234375 +91602 -0.265716552734375 +91603 -0.107330322265625 +91604 -0.023712158203125 +91605 -0.00189208984375 +91606 0.201751708984375 +91607 0.095977783203125 +91608 0.375823974609375 +91609 0.171417236328125 +91610 0.485076904296875 +91611 0.218658447265625 +91612 0.56884765625 +91613 0.254364013671875 +91614 0.634765625 +91615 0.281768798828125 +91616 0.63763427734375 +91617 0.281768798828125 +91618 0.5660400390625 +91619 0.2496337890625 +91620 0.4720458984375 +91621 0.20751953125 +91622 0.40692138671875 +91623 0.177276611328125 +91624 0.3778076171875 +91625 0.162109375 +91626 0.376953125 +91627 0.158905029296875 +91628 0.371978759765625 +91629 0.15411376953125 +91630 0.313140869140625 +91631 0.12677001953125 +91632 0.184417724609375 +91633 0.070159912109375 +91634 0.011199951171875 +91635 -0.004791259765625 +91636 -0.171051025390625 +91637 -0.082977294921875 +91638 -0.33740234375 +91639 -0.15380859375 +91640 -0.47198486328125 +91641 -0.210540771484375 +91642 -0.560394287109375 +91643 -0.247100830078125 +91644 -0.58056640625 +91645 -0.25421142578125 +91646 -0.54754638671875 +91647 -0.238372802734375 +91648 -0.508575439453125 +91649 -0.2198486328125 +91650 -0.459503173828125 +91651 -0.19677734375 +91652 -0.394378662109375 +91653 -0.166961669921875 +91654 -0.35260009765625 +91655 -0.14837646484375 +91656 -0.31170654296875 +91657 -0.1307373046875 +91658 -0.197418212890625 +91659 -0.080169677734375 +91660 -0.007965087890625 +91661 0.004180908203125 +91662 0.207489013671875 +91663 0.100006103515625 +91664 0.409210205078125 +91665 0.189300537109375 +91666 0.57208251953125 +91667 0.260772705078125 +91668 0.66595458984375 +91669 0.30084228515625 +91670 0.65875244140625 +91671 0.2950439453125 +91672 0.56744384765625 +91673 0.251251220703125 +91674 0.431396484375 +91675 0.1875 +91676 0.29443359375 +91677 0.123870849609375 +91678 0.182464599609375 +91679 0.072265625 +91680 0.06365966796875 +91681 0.018157958984375 +91682 -0.075958251953125 +91683 -0.044830322265625 +91684 -0.189422607421875 +91685 -0.0953369140625 +91686 -0.271942138671875 +91687 -0.131256103515625 +91688 -0.342529296875 +91689 -0.161346435546875 +91690 -0.364166259765625 +91691 -0.168914794921875 +91692 -0.327239990234375 +91693 -0.149688720703125 +91694 -0.2769775390625 +91695 -0.124420166015625 +91696 -0.253692626953125 +91697 -0.111602783203125 +91698 -0.24365234375 +91699 -0.105072021484375 +91700 -0.1983642578125 +91701 -0.082855224609375 +91702 -0.116241455078125 +91703 -0.0443115234375 +91704 -0.036834716796875 +91705 -0.007476806640625 +91706 0.034881591796875 +91707 0.02532958984375 +91708 0.09124755859375 +91709 0.050628662109375 +91710 0.10888671875 +91711 0.05780029296875 +91712 0.125518798828125 +91713 0.0640869140625 +91714 0.15771484375 +91715 0.0771484375 +91716 0.17828369140625 +91717 0.084686279296875 +91718 0.17108154296875 +91719 0.07940673828125 +91720 0.129974365234375 +91721 0.05865478515625 +91722 0.082427978515625 +91723 0.035064697265625 +91724 0.027679443359375 +91725 0.008392333984375 +91726 -0.065643310546875 +91727 -0.035552978515625 +91728 -0.15936279296875 +91729 -0.07928466796875 +91730 -0.21307373046875 +91731 -0.104339599609375 +91732 -0.234649658203125 +91733 -0.11431884765625 +91734 -0.2001953125 +91735 -0.098358154296875 +91736 -0.119171142578125 +91737 -0.060760498046875 +91738 -0.024749755859375 +91739 -0.0167236328125 +91740 0.085784912109375 +91741 0.034912109375 +91742 0.178131103515625 +91743 0.07843017578125 +91744 0.215576171875 +91745 0.097015380859375 +91746 0.211456298828125 +91747 0.0966796875 +91748 0.17523193359375 +91749 0.0816650390625 +91750 0.128753662109375 +91751 0.06182861328125 +91752 0.1019287109375 +91753 0.050750732421875 +91754 0.0743408203125 +91755 0.0390625 +91756 0.04327392578125 +91757 0.025482177734375 +91758 0.038177490234375 +91759 0.0234375 +91760 0.076263427734375 +91761 0.040740966796875 +91762 0.14105224609375 +91763 0.06988525390625 +91764 0.186431884765625 +91765 0.089874267578125 +91766 0.188812255859375 +91767 0.089996337890625 +91768 0.1390380859375 +91769 0.066131591796875 +91770 0.041778564453125 +91771 0.0205078125 +91772 -0.079437255859375 +91773 -0.036041259765625 +91774 -0.219390869140625 +91775 -0.101104736328125 +91776 -0.367828369140625 +91777 -0.169921875 +91778 -0.494873046875 +91779 -0.228790283203125 +91780 -0.556243896484375 +91781 -0.257476806640625 +91782 -0.508697509765625 +91783 -0.236236572265625 +91784 -0.3756103515625 +91785 -0.17572021484375 +91786 -0.218902587890625 +91787 -0.10418701171875 +91788 -0.063751220703125 +91789 -0.033111572265625 +91790 0.091552734375 +91791 0.038238525390625 +91792 0.23602294921875 +91793 0.10479736328125 +91794 0.342987060546875 +91795 0.154388427734375 +91796 0.39520263671875 +91797 0.179107666015625 +91798 0.389373779296875 +91799 0.177398681640625 +91800 0.324249267578125 +91801 0.148651123046875 +91802 0.224090576171875 +91803 0.1038818359375 +91804 0.124267578125 +91805 0.05914306640625 +91806 0.037078857421875 +91807 0.019989013671875 +91808 -0.010101318359375 +91809 -0.0010986328125 +91810 -0.019439697265625 +91811 -0.005157470703125 +91812 -0.022796630859375 +91813 -0.006683349609375 +91814 -0.001556396484375 +91815 0.002777099609375 +91816 0.056304931640625 +91817 0.02874755859375 +91818 0.106719970703125 +91819 0.0511474609375 +91820 0.096893310546875 +91821 0.045928955078125 +91822 0.042694091796875 +91823 0.020416259765625 +91824 -0.018035888671875 +91825 -0.008087158203125 +91826 -0.07586669921875 +91827 -0.035247802734375 +91828 -0.11944580078125 +91829 -0.055816650390625 +91830 -0.15972900390625 +91831 -0.07476806640625 +91832 -0.202606201171875 +91833 -0.094757080078125 +91834 -0.24859619140625 +91835 -0.115966796875 +91836 -0.30517578125 +91837 -0.141815185546875 +91838 -0.36212158203125 +91839 -0.16766357421875 +91840 -0.39141845703125 +91841 -0.1807861328125 +91842 -0.35528564453125 +91843 -0.1639404296875 +91844 -0.249969482421875 +91845 -0.115447998046875 +91846 -0.092864990234375 +91847 -0.04327392578125 +91848 0.08905029296875 +91849 0.040252685546875 +91850 0.2352294921875 +91851 0.107513427734375 +91852 0.318817138671875 +91853 0.146209716796875 +91854 0.358642578125 +91855 0.164886474609375 +91856 0.347747802734375 +91857 0.16033935546875 +91858 0.28564453125 +91859 0.13232421875 +91860 0.223175048828125 +91861 0.10400390625 +91862 0.196746826171875 +91863 0.09197998046875 +91864 0.179840087890625 +91865 0.084197998046875 +91866 0.155548095703125 +91867 0.07293701171875 +91868 0.151214599609375 +91869 0.0706787109375 +91870 0.156951904296875 +91871 0.07293701171875 +91872 0.13177490234375 +91873 0.061004638671875 +91874 0.100799560546875 +91875 0.04638671875 +91876 0.087127685546875 +91877 0.039642333984375 +91878 0.05487060546875 +91879 0.02447509765625 +91880 -0.009002685546875 +91881 -0.00506591796875 +91882 -0.10400390625 +91883 -0.0487060546875 +91884 -0.229400634765625 +91885 -0.106109619140625 +91886 -0.35552978515625 +91887 -0.16375732421875 +91888 -0.441925048828125 +91889 -0.203155517578125 +91890 -0.473846435546875 +91891 -0.217620849609375 +91892 -0.464813232421875 +91893 -0.21331787109375 +91894 -0.419097900390625 +91895 -0.19219970703125 +91896 -0.334320068359375 +91897 -0.1531982421875 +91898 -0.227935791015625 +91899 -0.104278564453125 +91900 -0.12347412109375 +91901 -0.05621337890625 +91902 -0.02764892578125 +91903 -0.0120849609375 +91904 0.077667236328125 +91905 0.036285400390625 +91906 0.2132568359375 +91907 0.098602294921875 +91908 0.38885498046875 +91909 0.18011474609375 +91910 0.582794189453125 +91911 0.2708740234375 +91912 0.734039306640625 +91913 0.341583251953125 +91914 0.800140380859375 +91915 0.371856689453125 +91916 0.7783203125 +91917 0.36053466796875 +91918 0.6651611328125 +91919 0.30596923828125 +91920 0.45965576171875 +91921 0.207611083984375 +91922 0.199188232421875 +91923 0.083587646484375 +91924 -0.050689697265625 +91925 -0.034332275390625 +91926 -0.23297119140625 +91927 -0.118621826171875 +91928 -0.33013916015625 +91929 -0.16107177734375 +91930 -0.368408203125 +91931 -0.174774169921875 +91932 -0.378936767578125 +91933 -0.17523193359375 +91934 -0.376983642578125 +91935 -0.17022705078125 +91936 -0.37969970703125 +91937 -0.1683349609375 +91938 -0.391510009765625 +91939 -0.171844482421875 +91940 -0.385345458984375 +91941 -0.167694091796875 +91942 -0.3419189453125 +91943 -0.146484375 +91944 -0.28289794921875 +91945 -0.118804931640625 +91946 -0.251617431640625 +91947 -0.105682373046875 +91948 -0.266143798828125 +91949 -0.11578369140625 +91950 -0.273345947265625 +91951 -0.12298583984375 +91952 -0.216796875 +91953 -0.099517822265625 +91954 -0.128265380859375 +91955 -0.060638427734375 +91956 -0.068145751953125 +91957 -0.03558349609375 +91958 -0.0430908203125 +91959 -0.027374267578125 +91960 -0.024444580078125 +91961 -0.021820068359375 +91962 0.020721435546875 +91963 -0.00262451171875 +91964 0.124481201171875 +91965 0.04595947265625 +91966 0.25787353515625 +91967 0.10986328125 +91968 0.379119873046875 +91969 0.168731689453125 +91970 0.47991943359375 +91971 0.218536376953125 +91972 0.5281982421875 +91973 0.2435302734375 +91974 0.511138916015625 +91975 0.23736572265625 +91976 0.456207275390625 +91977 0.21331787109375 +91978 0.407470703125 +91979 0.192718505859375 +91980 0.383758544921875 +91981 0.1845703125 +91982 0.35687255859375 +91983 0.1749267578125 +91984 0.31182861328125 +91985 0.156280517578125 +91986 0.250885009765625 +91987 0.1295166015625 +91988 0.1654052734375 +91989 0.090301513671875 +91990 0.035247802734375 +91991 0.0286865234375 +91992 -0.142059326171875 +91993 -0.056610107421875 +91994 -0.33563232421875 +91995 -0.150543212890625 +91996 -0.5345458984375 +91997 -0.247772216796875 +91998 -0.72186279296875 +91999 -0.34002685546875 +92000 -0.836669921875 +92001 -0.39752197265625 +92002 -0.8326416015625 +92003 -0.397552490234375 +92004 -0.7296142578125 +92005 -0.34967041015625 +92006 -0.582550048828125 +92007 -0.28057861328125 +92008 -0.440093994140625 +92009 -0.213836669921875 +92010 -0.324310302734375 +92011 -0.160064697265625 +92012 -0.20147705078125 +92013 -0.102630615234375 +92014 -0.044647216796875 +92015 -0.02825927734375 +92016 0.103973388671875 +92017 0.042510986328125 +92018 0.202392578125 +92019 0.089263916015625 +92020 0.264495849609375 +92021 0.118865966796875 +92022 0.338897705078125 +92023 0.155059814453125 +92024 0.443817138671875 +92025 0.206695556640625 +92026 0.545074462890625 +92027 0.257049560546875 +92028 0.6173095703125 +92029 0.293701171875 +92030 0.6524658203125 +92031 0.312652587890625 +92032 0.66339111328125 +92033 0.320037841796875 +92034 0.6561279296875 +92035 0.31866455078125 +92036 0.606781005859375 +92037 0.2967529296875 +92038 0.501190185546875 +92039 0.247283935546875 +92040 0.352783203125 +92041 0.17669677734375 +92042 0.176544189453125 +92043 0.09222412109375 +92044 -0.034820556640625 +92045 -0.009735107421875 +92046 -0.258209228515625 +92047 -0.117950439453125 +92048 -0.44244384765625 +92049 -0.207489013671875 +92050 -0.5753173828125 +92051 -0.27239990234375 +92052 -0.65203857421875 +92053 -0.310333251953125 +92054 -0.641632080078125 +92055 -0.30615234375 +92056 -0.562164306640625 +92057 -0.268646240234375 +92058 -0.458038330078125 +92059 -0.219390869140625 +92060 -0.350555419921875 +92061 -0.168670654296875 +92062 -0.260528564453125 +92063 -0.12652587890625 +92064 -0.192108154296875 +92065 -0.09490966796875 +92066 -0.141937255859375 +92067 -0.072052001953125 +92068 -0.1021728515625 +92069 -0.054046630859375 +92070 -0.062896728515625 +92071 -0.035980224609375 +92072 -0.011932373046875 +92073 -0.011871337890625 +92074 0.062835693359375 +92075 0.024200439453125 +92076 0.148712158203125 +92077 0.066070556640625 +92078 0.241729736328125 +92079 0.11175537109375 +92080 0.34912109375 +92081 0.164764404296875 +92082 0.457305908203125 +92083 0.21844482421875 +92084 0.54388427734375 +92085 0.261810302734375 +92086 0.5728759765625 +92087 0.277252197265625 +92088 0.506591796875 +92089 0.246307373046875 +92090 0.351226806640625 +92091 0.171905517578125 +92092 0.146514892578125 +92093 0.0733642578125 +92094 -0.05523681640625 +92095 -0.02386474609375 +92096 -0.21624755859375 +92097 -0.1014404296875 +92098 -0.334930419921875 +92099 -0.158599853515625 +92100 -0.402984619140625 +92101 -0.191314697265625 +92102 -0.4412841796875 +92103 -0.20977783203125 +92104 -0.49578857421875 +92105 -0.2364501953125 +92106 -0.5601806640625 +92107 -0.268218994140625 +92108 -0.600738525390625 +92109 -0.288604736328125 +92110 -0.584228515625 +92111 -0.2813720703125 +92112 -0.47930908203125 +92113 -0.23114013671875 +92114 -0.27935791015625 +92115 -0.1346435546875 +92116 -0.0089111328125 +92117 -0.0037841796875 +92118 0.268798828125 +92119 0.130615234375 +92120 0.482818603515625 +92121 0.2340087890625 +92122 0.60369873046875 +92123 0.292083740234375 +92124 0.650421142578125 +92125 0.314117431640625 +92126 0.66400146484375 +92127 0.3201904296875 +92128 0.6414794921875 +92129 0.308868408203125 +92130 0.572540283203125 +92131 0.275146484375 +92132 0.498138427734375 +92133 0.23895263671875 +92134 0.439453125 +92135 0.210662841796875 +92136 0.375518798828125 +92137 0.180023193359375 +92138 0.274505615234375 +92139 0.1314697265625 +92140 0.1087646484375 +92141 0.05145263671875 +92142 -0.099395751953125 +92143 -0.049224853515625 +92144 -0.3182373046875 +92145 -0.155059814453125 +92146 -0.5489501953125 +92147 -0.2667236328125 +92148 -0.7738037109375 +92149 -0.375579833984375 +92150 -0.86383056640625 +92151 -0.455841064453125 +92152 -0.870391845703125 +92153 -0.4913330078125 +92154 -0.86895751953125 +92155 -0.49072265625 +92156 -0.861053466796875 +92157 -0.46044921875 +92158 -0.765869140625 +92159 -0.392059326171875 +92160 -0.5301513671875 +92161 -0.27996826171875 +92162 -0.214691162109375 +92163 -0.127105712890625 +92164 0.137359619140625 +92165 0.045318603515625 +92166 0.474822998046875 +92167 0.211639404296875 +92168 0.76239013671875 +92169 0.354217529296875 +92170 0.867462158203125 +92171 0.459747314453125 +92172 0.870361328125 +92173 0.5289306640625 +92174 0.86480712890625 +92175 0.55609130859375 +92176 0.831817626953125 +92177 0.544158935546875 +92178 0.677581787109375 +92179 0.50579833984375 +92180 0.495880126953125 +92181 0.44384765625 +92182 0.30767822265625 +92183 0.36767578125 +92184 0.116180419921875 +92185 0.278045654296875 +92186 -0.110748291015625 +92187 0.157989501953125 +92188 -0.381805419921875 +92189 0.00335693359375 +92190 -0.6572265625 +92191 -0.164093017578125 +92192 -0.857421875 +92193 -0.313720703125 +92194 -0.870391845703125 +92195 -0.42364501953125 +92196 -0.870391845703125 +92197 -0.490570068359375 +92198 -0.86444091796875 +92199 -0.52880859375 +92200 -0.85723876953125 +92201 -0.55712890625 +92202 -0.790008544921875 +92203 -0.56610107421875 +92204 -0.62847900390625 +92205 -0.52752685546875 +92206 -0.3956298828125 +92207 -0.439605712890625 +92208 -0.126708984375 +92209 -0.3192138671875 +92210 0.150115966796875 +92211 -0.180328369140625 +92212 0.424041748046875 +92213 -0.0286865234375 +92214 0.670623779296875 +92215 0.1220703125 +92216 0.854522705078125 +92217 0.252166748046875 +92218 0.866485595703125 +92219 0.352783203125 +92220 0.86920166015625 +92221 0.41632080078125 +92222 0.8653564453125 +92223 0.4525146484375 +92224 0.857147216796875 +92225 0.468597412109375 +92226 0.766845703125 +92227 0.463287353515625 +92228 0.628509521484375 +92229 0.439361572265625 +92230 0.462127685546875 +92231 0.393341064453125 +92232 0.297210693359375 +92233 0.33856201171875 +92234 0.14862060546875 +92235 0.281341552734375 +92236 -0.00537109375 +92237 0.2095947265625 +92238 -0.15753173828125 +92239 0.126983642578125 +92240 -0.31304931640625 +92241 0.03131103515625 +92242 -0.48876953125 +92243 -0.084991455078125 +92244 -0.6416015625 +92245 -0.1978759765625 +92246 -0.751373291015625 +92247 -0.294769287109375 +92248 -0.84619140625 +92249 -0.387969970703125 +92250 -0.861297607421875 +92251 -0.47003173828125 +92252 -0.863250732421875 +92253 -0.523895263671875 +92254 -0.856597900390625 +92255 -0.533233642578125 +92256 -0.7498779296875 +92257 -0.504425048828125 +92258 -0.624542236328125 +92259 -0.467559814453125 +92260 -0.47808837890625 +92261 -0.411102294921875 +92262 -0.253387451171875 +92263 -0.304534912109375 +92264 0.003692626953125 +92265 -0.17138671875 +92266 0.2257080078125 +92267 -0.0469970703125 +92268 0.427154541015625 +92269 0.075408935546875 +92270 0.643218994140625 +92271 0.212921142578125 +92272 0.855926513671875 +92273 0.360748291015625 +92274 0.870361328125 +92275 0.48895263671875 +92276 0.870361328125 +92277 0.571929931640625 +92278 0.862762451171875 +92279 0.61358642578125 +92280 0.79669189453125 +92281 0.612457275390625 +92282 0.595794677734375 +92283 0.563690185546875 +92284 0.362152099609375 +92285 0.482452392578125 +92286 0.1270751953125 +92287 0.383270263671875 +92288 -0.086944580078125 +92289 0.277069091796875 +92290 -0.2784423828125 +92291 0.164825439453125 +92292 -0.484832763671875 +92293 0.0283203125 +92294 -0.729583740234375 +92295 -0.142547607421875 +92296 -0.86688232421875 +92297 -0.3216552734375 +92298 -0.870391845703125 +92299 -0.47625732421875 +92300 -0.86859130859375 +92301 -0.603912353515625 +92302 -0.86279296875 +92303 -0.70361328125 +92304 -0.817962646484375 +92305 -0.75677490234375 +92306 -0.6116943359375 +92307 -0.7398681640625 +92308 -0.3128662109375 +92309 -0.64923095703125 +92310 0.039398193359375 +92311 -0.502410888671875 +92312 0.422821044921875 +92313 -0.309783935546875 +92314 0.805145263671875 +92315 -0.088623046875 +92316 0.870361328125 +92317 0.125640869140625 +92318 0.870361328125 +92319 0.30340576171875 +92320 0.860015869140625 +92321 0.4385986328125 +92322 0.727935791015625 +92323 0.52728271484375 +92324 0.48114013671875 +92325 0.566558837890625 +92326 0.2059326171875 +92327 0.569000244140625 +92328 -0.06103515625 +92329 0.546356201171875 +92330 -0.29913330078125 +92331 0.503875732421875 +92332 -0.516204833984375 +92333 0.43402099609375 +92334 -0.7252197265625 +92335 0.328857421875 +92336 -0.85980224609375 +92337 0.201385498046875 +92338 -0.870391845703125 +92339 0.069549560546875 +92340 -0.870391845703125 +92341 -0.051116943359375 +92342 -0.858062744140625 +92343 -0.13519287109375 +92344 -0.673004150390625 +92345 -0.1802978515625 +92346 -0.42694091796875 +92347 -0.213531494140625 +92348 -0.2100830078125 +92349 -0.257781982421875 +92350 -0.0362548828125 +92351 -0.311767578125 +92352 0.10943603515625 +92353 -0.360260009765625 +92354 0.23516845703125 +92355 -0.392791748046875 +92356 0.373687744140625 +92357 -0.38775634765625 +92358 0.517791748046875 +92359 -0.34613037109375 +92360 0.602783203125 +92361 -0.30072021484375 +92362 0.635711669921875 +92363 -0.248870849609375 +92364 0.655181884765625 +92365 -0.17340087890625 +92366 0.65948486328125 +92367 -0.07965087890625 +92368 0.651275634765625 +92369 0.027984619140625 +92370 0.61846923828125 +92371 0.136505126953125 +92372 0.53753662109375 +92373 0.226470947265625 +92374 0.404144287109375 +92375 0.288238525390625 +92376 0.22186279296875 +92377 0.316558837890625 +92378 0.003997802734375 +92379 0.3118896484375 +92380 -0.22100830078125 +92381 0.28350830078125 +92382 -0.42449951171875 +92383 0.242034912109375 +92384 -0.579833984375 +92385 0.198516845703125 +92386 -0.641876220703125 +92387 0.1751708984375 +92388 -0.6177978515625 +92389 0.1685791015625 +92390 -0.575531005859375 +92391 0.145263671875 +92392 -0.526336669921875 +92393 0.10260009765625 +92394 -0.42645263671875 +92395 0.067718505859375 +92396 -0.2581787109375 +92397 0.055084228515625 +92398 -0.068695068359375 +92399 0.046051025390625 +92400 0.09222412109375 +92401 0.020782470703125 +92402 0.232147216796875 +92403 -0.010772705078125 +92404 0.3509521484375 +92405 -0.0430908203125 +92406 0.410064697265625 +92407 -0.0914306640625 +92408 0.372955322265625 +92409 -0.1708984375 +92410 0.2554931640625 +92411 -0.270477294921875 +92412 0.10711669921875 +92413 -0.363006591796875 +92414 -0.052886962890625 +92415 -0.43829345703125 +92416 -0.186279296875 +92417 -0.47711181640625 +92418 -0.23291015625 +92419 -0.450042724609375 +92420 -0.209442138671875 +92421 -0.369903564453125 +92422 -0.174163818359375 +92423 -0.27239990234375 +92424 -0.126739501953125 +92425 -0.1614990234375 +92426 -0.048126220703125 +92427 -0.031280517578125 +92428 0.0426025390625 +92429 0.103179931640625 +92430 0.10748291015625 +92431 0.21661376953125 +92432 0.1409912109375 +92433 0.302032470703125 +92434 0.19708251953125 +92435 0.3858642578125 +92436 0.273651123046875 +92437 0.464508056640625 +92438 0.31768798828125 +92439 0.50726318359375 +92440 0.341094970703125 +92441 0.520172119140625 +92442 0.368011474609375 +92443 0.51702880859375 +92444 0.37249755859375 +92445 0.48504638671875 +92446 0.30072021484375 +92447 0.396942138671875 +92448 0.1517333984375 +92449 0.25518798828125 +92450 -0.01470947265625 +92451 0.096221923828125 +92452 -0.1883544921875 +92453 -0.070404052734375 +92454 -0.372711181640625 +92455 -0.242645263671875 +92456 -0.51397705078125 +92457 -0.387115478515625 +92458 -0.57177734375 +92459 -0.47802734375 +92460 -0.53948974609375 +92461 -0.508758544921875 +92462 -0.43511962890625 +92463 -0.48687744140625 +92464 -0.2962646484375 +92465 -0.4315185546875 +92466 -0.161102294921875 +92467 -0.362945556640625 +92468 -0.0435791015625 +92469 -0.2889404296875 +92470 0.060394287109375 +92471 -0.20819091796875 +92472 0.13665771484375 +92473 -0.130157470703125 +92474 0.170135498046875 +92475 -0.065460205078125 +92476 0.16552734375 +92477 -0.01434326171875 +92478 0.15728759765625 +92479 0.038970947265625 +92480 0.150787353515625 +92481 0.09417724609375 +92482 0.12200927734375 +92483 0.13482666015625 +92484 0.080108642578125 +92485 0.1629638671875 +92486 0.05126953125 +92487 0.190338134765625 +92488 0.062896728515625 +92489 0.229888916015625 +92490 0.09271240234375 +92491 0.267852783203125 +92492 0.092987060546875 +92493 0.277130126953125 +92494 0.07855224609375 +92495 0.2657470703125 +92496 0.06427001953125 +92497 0.242431640625 +92498 0.0347900390625 +92499 0.19989013671875 +92500 -0.01171875 +92501 0.13885498046875 +92502 -0.056060791015625 +92503 0.07208251953125 +92504 -0.055511474609375 +92505 0.025604248046875 +92506 -0.010467529296875 +92507 0.001861572265625 +92508 0.02508544921875 +92509 -0.026092529296875 +92510 0.025665283203125 +92511 -0.0697021484375 +92512 0.017333984375 +92513 -0.11236572265625 +92514 0.00189208984375 +92515 -0.15118408203125 +92516 -0.03173828125 +92517 -0.190826416015625 +92518 -0.071502685546875 +92519 -0.223785400390625 +92520 -0.13543701171875 +92521 -0.2596435546875 +92522 -0.219970703125 +92523 -0.29669189453125 +92524 -0.300506591796875 +92525 -0.32220458984375 +92526 -0.376312255859375 +92527 -0.337066650390625 +92528 -0.416107177734375 +92529 -0.325775146484375 +92530 -0.371124267578125 +92531 -0.263519287109375 +92532 -0.242279052734375 +92533 -0.152984619140625 +92534 -0.069732666015625 +92535 -0.0184326171875 +92536 0.125640869140625 +92537 0.126434326171875 +92538 0.31268310546875 +92539 0.26251220703125 +92540 0.45501708984375 +92541 0.368133544921875 +92542 0.554779052734375 +92543 0.443115234375 +92544 0.61065673828125 +92545 0.485870361328125 +92546 0.610931396484375 +92547 0.489532470703125 +92548 0.531463623046875 +92549 0.44085693359375 +92550 0.3883056640625 +92551 0.349212646484375 +92552 0.23468017578125 +92553 0.244781494140625 +92554 0.095245361328125 +92555 0.142425537109375 +92556 -0.00396728515625 +92557 0.05804443359375 +92558 -0.04852294921875 +92559 0.00128173828125 +92560 -0.055145263671875 +92561 -0.035186767578125 +92562 -0.0758056640625 +92563 -0.07818603515625 +92564 -0.138702392578125 +92565 -0.141510009765625 +92566 -0.209197998046875 +92567 -0.204620361328125 +92568 -0.289031982421875 +92569 -0.26727294921875 +92570 -0.37884521484375 +92571 -0.328948974609375 +92572 -0.456329345703125 +92573 -0.37689208984375 +92574 -0.51641845703125 +92575 -0.40826416015625 +92576 -0.519287109375 +92577 -0.40142822265625 +92578 -0.458251953125 +92579 -0.353363037109375 +92580 -0.384796142578125 +92581 -0.293365478515625 +92582 -0.323699951171875 +92583 -0.236236572265625 +92584 -0.269287109375 +92585 -0.18023681640625 +92586 -0.1951904296875 +92587 -0.112396240234375 +92588 -0.100006103515625 +92589 -0.033447265625 +92590 -0.01055908203125 +92591 0.0404052734375 +92592 0.1033935546875 +92593 0.12451171875 +92594 0.24908447265625 +92595 0.22174072265625 +92596 0.373199462890625 +92597 0.301971435546875 +92598 0.45806884765625 +92599 0.35498046875 +92600 0.511474609375 +92601 0.384857177734375 +92602 0.565399169921875 +92603 0.40936279296875 +92604 0.61138916015625 +92605 0.424285888671875 +92606 0.5897216796875 +92607 0.397491455078125 +92608 0.4906005859375 +92609 0.32452392578125 +92610 0.33148193359375 +92611 0.21612548828125 +92612 0.147796630859375 +92613 0.09295654296875 +92614 -0.01873779296875 +92615 -0.020751953125 +92616 -0.140289306640625 +92617 -0.108489990234375 +92618 -0.191986083984375 +92619 -0.155487060546875 +92620 -0.184295654296875 +92621 -0.166534423828125 +92622 -0.161834716796875 +92623 -0.16546630859375 +92624 -0.166595458984375 +92625 -0.17486572265625 +92626 -0.19390869140625 +92627 -0.191925048828125 +92628 -0.22442626953125 +92629 -0.206024169921875 +92630 -0.279754638671875 +92631 -0.229339599609375 +92632 -0.3389892578125 +92633 -0.250885009765625 +92634 -0.3543701171875 +92635 -0.2451171875 +92636 -0.348175048828125 +92637 -0.22515869140625 +92638 -0.32598876953125 +92639 -0.19500732421875 +92640 -0.2581787109375 +92641 -0.139434814453125 +92642 -0.139801025390625 +92643 -0.05670166015625 +92644 0.014617919921875 +92645 0.04425048828125 +92646 0.144378662109375 +92647 0.129180908203125 +92648 0.221038818359375 +92649 0.18182373046875 +92650 0.27069091796875 +92651 0.21600341796875 +92652 0.294036865234375 +92653 0.23187255859375 +92654 0.311767578125 +92655 0.240753173828125 +92656 0.339141845703125 +92657 0.251220703125 +92658 0.360260009765625 +92659 0.2548828125 +92660 0.360504150390625 +92661 0.2442626953125 +92662 0.308380126953125 +92663 0.202606201171875 +92664 0.18170166015625 +92665 0.118408203125 +92666 0.0047607421875 +92667 0.00592041015625 +92668 -0.17559814453125 +92669 -0.108184814453125 +92670 -0.3143310546875 +92671 -0.198272705078125 +92672 -0.36785888671875 +92673 -0.23919677734375 +92674 -0.36248779296875 +92675 -0.245269775390625 +92676 -0.343536376953125 +92677 -0.24169921875 +92678 -0.3018798828125 +92679 -0.222625732421875 +92680 -0.231414794921875 +92681 -0.18408203125 +92682 -0.117645263671875 +92683 -0.117462158203125 +92684 0.007049560546875 +92685 -0.04168701171875 +92686 0.087982177734375 +92687 0.011077880859375 +92688 0.13946533203125 +92689 0.048858642578125 +92690 0.17425537109375 +92691 0.078582763671875 +92692 0.188201904296875 +92693 0.09722900390625 +92694 0.171234130859375 +92695 0.09832763671875 +92696 0.118438720703125 +92697 0.078369140625 +92698 0.05706787109375 +92699 0.05267333984375 +92700 -0.010711669921875 +92701 0.02191162109375 +92702 -0.0914306640625 +92703 -0.0181884765625 +92704 -0.162322998046875 +92705 -0.05462646484375 +92706 -0.194549560546875 +92707 -0.07080078125 +92708 -0.1492919921875 +92709 -0.04412841796875 +92710 -0.02166748046875 +92711 0.02825927734375 +92712 0.124053955078125 +92713 0.109039306640625 +92714 0.211151123046875 +92715 0.1536865234375 +92716 0.240447998046875 +92717 0.163116455078125 +92718 0.242218017578125 +92719 0.155426025390625 +92720 0.2257080078125 +92721 0.13653564453125 +92722 0.194366455078125 +92723 0.1090087890625 +92724 0.115509033203125 +92725 0.054229736328125 +92726 0.0128173828125 +92727 -0.013427734375 +92728 -0.053802490234375 +92729 -0.05865478515625 +92730 -0.110626220703125 +92731 -0.096466064453125 +92732 -0.199493408203125 +92733 -0.151092529296875 +92734 -0.29437255859375 +92735 -0.207275390625 +92736 -0.33221435546875 +92737 -0.228179931640625 +92738 -0.27972412109375 +92739 -0.194488525390625 +92740 -0.185333251953125 +92741 -0.134735107421875 +92742 -0.128204345703125 +92743 -0.095428466796875 +92744 -0.115692138671875 +92745 -0.0811767578125 +92746 -0.116455078125 +92747 -0.074127197265625 +92748 -0.105926513671875 +92749 -0.06036376953125 +92750 -0.053955078125 +92751 -0.022705078125 +92752 0.048797607421875 +92753 0.043914794921875 +92754 0.157318115234375 +92755 0.112884521484375 +92756 0.212005615234375 +92757 0.149139404296875 +92758 0.218475341796875 +92759 0.155731201171875 +92760 0.23724365234375 +92761 0.167877197265625 +92762 0.30535888671875 +92763 0.20721435546875 +92764 0.38128662109375 +92765 0.24951171875 +92766 0.404449462890625 +92767 0.25958251953125 +92768 0.3944091796875 +92769 0.24908447265625 +92770 0.3885498046875 +92771 0.240142822265625 +92772 0.362640380859375 +92773 0.21893310546875 +92774 0.27362060546875 +92775 0.16064453125 +92776 0.11712646484375 +92777 0.063079833984375 +92778 -0.054901123046875 +92779 -0.043060302734375 +92780 -0.19085693359375 +92781 -0.127349853515625 +92782 -0.28570556640625 +92783 -0.186614990234375 +92784 -0.339263916015625 +92785 -0.2205810546875 +92786 -0.3775634765625 +92787 -0.24432373046875 +92788 -0.445709228515625 +92789 -0.284149169921875 +92790 -0.535064697265625 +92791 -0.335052490234375 +92792 -0.629058837890625 +92793 -0.387451171875 +92794 -0.697601318359375 +92795 -0.423919677734375 +92796 -0.70391845703125 +92797 -0.423248291015625 +92798 -0.6424560546875 +92799 -0.3824462890625 +92800 -0.491241455078125 +92801 -0.288970947265625 +92802 -0.265716552734375 +92803 -0.152099609375 +92804 -0.023712158203125 +92805 -0.00592041015625 +92806 0.201751708984375 +92807 0.130035400390625 +92808 0.375823974609375 +92809 0.23516845703125 +92810 0.485076904296875 +92811 0.301513671875 +92812 0.56884765625 +92813 0.351898193359375 +92814 0.634765625 +92815 0.3907470703125 +92816 0.63763427734375 +92817 0.391693115234375 +92818 0.5660400390625 +92819 0.34808349609375 +92820 0.4720458984375 +92821 0.290496826171875 +92822 0.40692138671875 +92823 0.2490234375 +92824 0.3778076171875 +92825 0.228057861328125 +92826 0.376953125 +92827 0.223297119140625 +92828 0.371978759765625 +92829 0.216094970703125 +92830 0.313140869140625 +92831 0.1776123046875 +92832 0.184417724609375 +92833 0.09869384765625 +92834 0.011199951171875 +92835 -0.005584716796875 +92836 -0.171051025390625 +92837 -0.114349365234375 +92838 -0.33740234375 +92839 -0.21295166015625 +92840 -0.47198486328125 +92841 -0.29205322265625 +92842 -0.560394287109375 +92843 -0.34326171875 +92844 -0.58056640625 +92845 -0.353759765625 +92846 -0.54754638671875 +92847 -0.332427978515625 +92848 -0.508575439453125 +92849 -0.3070068359375 +92850 -0.459503173828125 +92851 -0.275238037109375 +92852 -0.394378662109375 +92853 -0.233795166015625 +92854 -0.35260009765625 +92855 -0.205902099609375 +92856 -0.31170654296875 +92857 -0.1785888671875 +92858 -0.197418212890625 +92859 -0.108673095703125 +92860 -0.007965087890625 +92861 0.00469970703125 +92862 0.207489013671875 +92863 0.132659912109375 +92864 0.409210205078125 +92865 0.25189208984375 +92866 0.57208251953125 +92867 0.347686767578125 +92868 0.66595458984375 +92869 0.402435302734375 +92870 0.65875244140625 +92871 0.39739990234375 +92872 0.56744384765625 +92873 0.34259033203125 +92874 0.431396484375 +92875 0.2611083984375 +92876 0.29443359375 +92877 0.17864990234375 +92878 0.182464599609375 +92879 0.1104736328125 +92880 0.06365966796875 +92881 0.038177490234375 +92882 -0.075958251953125 +92883 -0.046234130859375 +92884 -0.189422607421875 +92885 -0.11517333984375 +92886 -0.271942138671875 +92887 -0.165679931640625 +92888 -0.342529296875 +92889 -0.208770751953125 +92890 -0.364166259765625 +92891 -0.222747802734375 +92892 -0.327239990234375 +92893 -0.201934814453125 +92894 -0.2769775390625 +92895 -0.1727294921875 +92896 -0.253692626953125 +92897 -0.15869140625 +92898 -0.24365234375 +92899 -0.15179443359375 +92900 -0.1983642578125 +92901 -0.123809814453125 +92902 -0.116241455078125 +92903 -0.07391357421875 +92904 -0.036834716796875 +92905 -0.025299072265625 +92906 0.034881591796875 +92907 0.018951416015625 +92908 0.09124755859375 +92909 0.05426025390625 +92910 0.10888671875 +92911 0.06683349609375 +92912 0.125518798828125 +92913 0.078582763671875 +92914 0.15771484375 +92915 0.099090576171875 +92916 0.17828369140625 +92917 0.11236572265625 +92918 0.17108154296875 +92919 0.108917236328125 +92920 0.129974365234375 +92921 0.08514404296875 +92922 0.082427978515625 +92923 0.057098388671875 +92924 0.027679443359375 +92925 0.024383544921875 +92926 -0.065643310546875 +92927 -0.03125 +92928 -0.15936279296875 +92929 -0.0870361328125 +92930 -0.21307373046875 +92931 -0.1197509765625 +92932 -0.234649658203125 +92933 -0.134552001953125 +92934 -0.2001953125 +92935 -0.1162109375 +92936 -0.119171142578125 +92937 -0.070037841796875 +92938 -0.024749755859375 +92939 -0.016021728515625 +92940 0.085784912109375 +92941 0.047943115234375 +92942 0.178131103515625 +92943 0.101043701171875 +92944 0.215576171875 +92945 0.1209716796875 +92946 0.211456298828125 +92947 0.116119384765625 +92948 0.17523193359375 +92949 0.09246826171875 +92950 0.128753662109375 +92951 0.06353759765625 +92952 0.1019287109375 +92953 0.0477294921875 +92954 0.0743408203125 +92955 0.032379150390625 +92956 0.04327392578125 +92957 0.01568603515625 +92958 0.038177490234375 +92959 0.015594482421875 +92960 0.076263427734375 +92961 0.042510986328125 +92962 0.14105224609375 +92963 0.086029052734375 +92964 0.186431884765625 +92965 0.1175537109375 +92966 0.188812255859375 +92967 0.122344970703125 +92968 0.1390380859375 +92969 0.094573974609375 +92970 0.041778564453125 +92971 0.0369873046875 +92972 -0.079437255859375 +92973 -0.0360107421875 +92974 -0.219390869140625 +92975 -0.121307373046875 +92976 -0.367828369140625 +92977 -0.21258544921875 +92978 -0.494873046875 +92979 -0.291473388671875 +92980 -0.556243896484375 +92981 -0.330596923828125 +92982 -0.508697509765625 +92983 -0.30322265625 +92984 -0.3756103515625 +92985 -0.223663330078125 +92986 -0.218902587890625 +92987 -0.129913330078125 +92988 -0.063751220703125 +92989 -0.03729248046875 +92990 0.091552734375 +92991 0.055389404296875 +92992 0.23602294921875 +92993 0.14154052734375 +92994 0.342987060546875 +92995 0.204864501953125 +92996 0.39520263671875 +92997 0.234893798828125 +92998 0.389373779296875 +92999 0.229705810546875 +93000 0.324249267578125 +93001 0.1885986328125 +93002 0.224090576171875 +93003 0.126556396484375 +93004 0.124267578125 +93005 0.06536865234375 +93006 0.037078857421875 +93007 0.012542724609375 +93008 -0.010101318359375 +93009 -0.015106201171875 +93010 -0.019439697265625 +93011 -0.019012451171875 +93012 -0.022796630859375 +93013 -0.018890380859375 +93014 -0.001556396484375 +93015 -0.00341796875 +93016 0.056304931640625 +93017 0.03466796875 +93018 0.106719970703125 +93019 0.068115234375 +93020 0.096893310546875 +93021 0.06427001953125 +93022 0.042694091796875 +93023 0.032806396484375 +93024 -0.018035888671875 +93025 -0.00311279296875 +93026 -0.07586669921875 +93027 -0.0377197265625 +93028 -0.11944580078125 +93029 -0.064056396484375 +93030 -0.15972900390625 +93031 -0.088897705078125 +93032 -0.202606201171875 +93033 -0.1158447265625 +93034 -0.24859619140625 +93035 -0.145172119140625 +93036 -0.30517578125 +93037 -0.181365966796875 +93038 -0.36212158203125 +93039 -0.218109130859375 +93040 -0.39141845703125 +93041 -0.238037109375 +93042 -0.35528564453125 +93043 -0.217742919921875 +93044 -0.249969482421875 +93045 -0.15484619140625 +93046 -0.092864990234375 +93047 -0.0599365234375 +93048 0.08905029296875 +93049 0.05047607421875 +93050 0.2352294921875 +93051 0.13916015625 +93052 0.318817138671875 +93053 0.18963623046875 +93054 0.358642578125 +93055 0.21356201171875 +93056 0.347747802734375 +93057 0.2066650390625 +93058 0.28564453125 +93059 0.16864013671875 +93060 0.223175048828125 +93061 0.13079833984375 +93062 0.196746826171875 +93063 0.115478515625 +93064 0.179840087890625 +93065 0.1063232421875 +93066 0.155548095703125 +93067 0.09283447265625 +93068 0.151214599609375 +93069 0.091766357421875 +93070 0.156951904296875 +93071 0.096923828125 +93072 0.13177490234375 +93073 0.08294677734375 +93074 0.100799560546875 +93075 0.06524658203125 +93076 0.087127685546875 +93077 0.058013916015625 +93078 0.05487060546875 +93079 0.039093017578125 +93080 -0.009002685546875 +93081 0.0003662109375 +93082 -0.10400390625 +93083 -0.057861328125 +93084 -0.229400634765625 +93085 -0.135162353515625 +93086 -0.35552978515625 +93087 -0.2132568359375 +93088 -0.441925048828125 +93089 -0.26715087890625 +93090 -0.473846435546875 +93091 -0.287750244140625 +93092 -0.464813232421875 +93093 -0.283294677734375 +93094 -0.419097900390625 +93095 -0.25634765625 +93096 -0.334320068359375 +93097 -0.20538330078125 +93098 -0.227935791015625 +93099 -0.141082763671875 +93100 -0.12347412109375 +93101 -0.077880859375 +93102 -0.02764892578125 +93103 -0.01983642578125 +93104 0.077667236328125 +93105 0.04425048828125 +93106 0.2132568359375 +93107 0.127197265625 +93108 0.38885498046875 +93109 0.23504638671875 +93110 0.582794189453125 +93111 0.35443115234375 +93112 0.734039306640625 +93113 0.447784423828125 +93114 0.800140380859375 +93115 0.4888916015625 +93116 0.7783203125 +93117 0.476043701171875 +93118 0.6651611328125 +93119 0.4071044921875 +93120 0.45965576171875 +93121 0.281402587890625 +93122 0.199188232421875 +93123 0.1219482421875 +93124 -0.050689697265625 +93125 -0.030975341796875 +93126 -0.23297119140625 +93127 -0.14227294921875 +93128 -0.33013916015625 +93129 -0.20123291015625 +93130 -0.368408203125 +93131 -0.224029541015625 +93132 -0.378936767578125 +93133 -0.229888916015625 +93134 -0.376983642578125 +93135 -0.228271484375 +93136 -0.37969970703125 +93137 -0.229766845703125 +93138 -0.391510009765625 +93139 -0.237091064453125 +93140 -0.385345458984375 +93141 -0.23358154296875 +93142 -0.3419189453125 +93143 -0.20733642578125 +93144 -0.28289794921875 +93145 -0.171630859375 +93146 -0.251617431640625 +93147 -0.153106689453125 +93148 -0.266143798828125 +93149 -0.162841796875 +93150 -0.273345947265625 +93151 -0.168121337890625 +93152 -0.216796875 +93153 -0.13409423828125 +93154 -0.128265380859375 +93155 -0.080291748046875 +93156 -0.068145751953125 +93157 -0.04388427734375 +93158 -0.0430908203125 +93159 -0.028900146484375 +93160 -0.024444580078125 +93161 -0.0177001953125 +93162 0.020721435546875 +93163 0.009979248046875 +93164 0.124481201171875 +93165 0.07391357421875 +93166 0.25787353515625 +93167 0.15625 +93168 0.379119873046875 +93169 0.231201171875 +93170 0.47991943359375 +93171 0.293670654296875 +93172 0.5281982421875 +93173 0.3238525390625 +93174 0.511138916015625 +93175 0.313873291015625 +93176 0.456207275390625 +93177 0.280609130859375 +93178 0.407470703125 +93179 0.251190185546875 +93180 0.383758544921875 +93181 0.237152099609375 +93182 0.35687255859375 +93183 0.221099853515625 +93184 0.31182861328125 +93185 0.19427490234375 +93186 0.250885009765625 +93187 0.158355712890625 +93188 0.1654052734375 +93189 0.10736083984375 +93190 0.035247802734375 +93191 0.02777099609375 +93192 -0.142059326171875 +93193 -0.08245849609375 +93194 -0.33563232421875 +93195 -0.203704833984375 +93196 -0.5345458984375 +93197 -0.329193115234375 +93198 -0.72186279296875 +93199 -0.448211669921875 +93200 -0.836669921875 +93201 -0.52142333984375 +93202 -0.8326416015625 +93203 -0.51885986328125 +93204 -0.7296142578125 +93205 -0.453369140625 +93206 -0.582550048828125 +93207 -0.360443115234375 +93208 -0.440093994140625 +93209 -0.27142333984375 +93210 -0.324310302734375 +93211 -0.200439453125 +93212 -0.20147705078125 +93213 -0.125335693359375 +93214 -0.044647216796875 +93215 -0.02838134765625 +93216 0.103973388671875 +93217 0.063323974609375 +93218 0.202392578125 +93219 0.122833251953125 +93220 0.264495849609375 +93221 0.15936279296875 +93222 0.338897705078125 +93223 0.204620361328125 +93224 0.443817138671875 +93225 0.27056884765625 +93226 0.545074462890625 +93227 0.335113525390625 +93228 0.6173095703125 +93229 0.381866455078125 +93230 0.6524658203125 +93231 0.405609130859375 +93232 0.66339111328125 +93233 0.414581298828125 +93234 0.6561279296875 +93235 0.41253662109375 +93236 0.606781005859375 +93237 0.383819580078125 +93238 0.501190185546875 +93239 0.319061279296875 +93240 0.352783203125 +93241 0.22674560546875 +93242 0.176544189453125 +93243 0.11639404296875 +93244 -0.034820556640625 +93245 -0.01690673828125 +93246 -0.258209228515625 +93247 -0.15838623046875 +93248 -0.44244384765625 +93249 -0.275054931640625 +93250 -0.5753173828125 +93251 -0.359130859375 +93252 -0.65203857421875 +93253 -0.4075927734375 +93254 -0.641632080078125 +93255 -0.40045166015625 +93256 -0.562164306640625 +93257 -0.34942626953125 +93258 -0.458038330078125 +93259 -0.283233642578125 +93260 -0.350555419921875 +93261 -0.215545654296875 +93262 -0.260528564453125 +93263 -0.15972900390625 +93264 -0.192108154296875 +93265 -0.118316650390625 +93266 -0.141937255859375 +93267 -0.088958740234375 +93268 -0.1021728515625 +93269 -0.06640625 +93270 -0.062896728515625 +93271 -0.0440673828125 +93272 -0.011932373046875 +93273 -0.01385498046875 +93274 0.062835693359375 +93275 0.032196044921875 +93276 0.148712158203125 +93277 0.08599853515625 +93278 0.241729736328125 +93279 0.14501953125 +93280 0.34912109375 +93281 0.214019775390625 +93282 0.457305908203125 +93283 0.28424072265625 +93284 0.54388427734375 +93285 0.341094970703125 +93286 0.5728759765625 +93287 0.36126708984375 +93288 0.506591796875 +93289 0.3201904296875 +93290 0.351226806640625 +93291 0.221771240234375 +93292 0.146514892578125 +93293 0.091644287109375 +93294 -0.05523681640625 +93295 -0.03643798828125 +93296 -0.21624755859375 +93297 -0.138153076171875 +93298 -0.334930419921875 +93299 -0.21258544921875 +93300 -0.402984619140625 +93301 -0.2545166015625 +93302 -0.4412841796875 +93303 -0.277557373046875 +93304 -0.49578857421875 +93305 -0.31158447265625 +93306 -0.5601806640625 +93307 -0.352569580078125 +93308 -0.600738525390625 +93309 -0.378662109375 +93310 -0.584228515625 +93311 -0.36834716796875 +93312 -0.47930908203125 +93313 -0.301300048828125 +93314 -0.27935791015625 +93315 -0.17315673828125 +93316 -0.0089111328125 +93317 0.000244140625 +93318 0.268798828125 +93319 0.17803955078125 +93320 0.482818603515625 +93321 0.314422607421875 +93322 0.60369873046875 +93323 0.39044189453125 +93324 0.650421142578125 +93325 0.418487548828125 +93326 0.66400146484375 +93327 0.42529296875 +93328 0.6414794921875 +93329 0.409027099609375 +93330 0.572540283203125 +93331 0.36309814453125 +93332 0.498138427734375 +93333 0.3140869140625 +93334 0.439453125 +93335 0.2757568359375 +93336 0.375518798828125 +93337 0.234527587890625 +93338 0.274505615234375 +93339 0.16973876953125 +93340 0.1087646484375 +93341 0.06341552734375 +93342 -0.099395751953125 +93343 -0.070037841796875 +93344 -0.3182373046875 +93345 -0.210113525390625 +93346 -0.5489501953125 +93347 -0.35772705078125 +93348 -0.7738037109375 +93349 -0.50146484375 +93350 -0.86383056640625 +93351 -0.60711669921875 +93352 -0.870391845703125 +93353 -0.65325927734375 +93354 -0.86895751953125 +93355 -0.651458740234375 +93356 -0.861053466796875 +93357 -0.610321044921875 +93358 -0.765869140625 +93359 -0.5186767578125 +93360 -0.5301513671875 +93361 -0.369232177734375 +93362 -0.214691162109375 +93363 -0.1666259765625 +93364 0.137359619140625 +93365 0.061248779296875 +93366 0.474822998046875 +93367 0.281158447265625 +93368 0.76239013671875 +93369 0.47015380859375 +93370 0.867462158203125 +93371 0.610809326171875 +93372 0.870361328125 +93373 0.703460693359375 +93374 0.86480712890625 +93375 0.74072265625 +93376 0.831817626953125 +93377 0.726165771484375 +93378 0.677581787109375 +93379 0.6756591796875 +93380 0.495880126953125 +93381 0.593048095703125 +93382 0.30767822265625 +93383 0.490386962890625 +93384 0.116180419921875 +93385 0.36920166015625 +93386 -0.110748291015625 +93387 0.208953857421875 +93388 -0.381805419921875 +93389 0.005157470703125 +93390 -0.6572265625 +93391 -0.21441650390625 +93392 -0.857421875 +93393 -0.410980224609375 +93394 -0.870391845703125 +93395 -0.556732177734375 +93396 -0.870391845703125 +93397 -0.647064208984375 +93398 -0.86444091796875 +93399 -0.699493408203125 +93400 -0.85723876953125 +93401 -0.737213134765625 +93402 -0.790008544921875 +93403 -0.748382568359375 +93404 -0.62847900390625 +93405 -0.697906494140625 +93406 -0.3956298828125 +93407 -0.583770751953125 +93408 -0.126708984375 +93409 -0.4273681640625 +93410 0.150115966796875 +93411 -0.2464599609375 +93412 0.424041748046875 +93413 -0.0487060546875 +93414 0.670623779296875 +93415 0.14837646484375 +93416 0.854522705078125 +93417 0.319671630859375 +93418 0.866485595703125 +93419 0.453704833984375 +93420 0.86920166015625 +93421 0.54052734375 +93422 0.8653564453125 +93423 0.591888427734375 +93424 0.857147216796875 +93425 0.61651611328125 +93426 0.766845703125 +93427 0.612548828125 +93428 0.628509521484375 +93429 0.5833740234375 +93430 0.462127685546875 +93431 0.524658203125 +93432 0.297210693359375 +93433 0.45318603515625 +93434 0.14862060546875 +93435 0.377044677734375 +93436 -0.00537109375 +93437 0.281494140625 +93438 -0.15753173828125 +93439 0.171478271484375 +93440 -0.31304931640625 +93441 0.04425048828125 +93442 -0.48876953125 +93443 -0.10931396484375 +93444 -0.6416015625 +93445 -0.25750732421875 +93446 -0.751373291015625 +93447 -0.384246826171875 +93448 -0.84619140625 +93449 -0.505889892578125 +93450 -0.861297607421875 +93451 -0.6129150390625 +93452 -0.863250732421875 +93453 -0.683197021484375 +93454 -0.856597900390625 +93455 -0.69549560546875 +93456 -0.7498779296875 +93457 -0.658172607421875 +93458 -0.624542236328125 +93459 -0.61053466796875 +93460 -0.47808837890625 +93461 -0.5374755859375 +93462 -0.253387451171875 +93463 -0.39898681640625 +93464 0.003692626953125 +93465 -0.225799560546875 +93466 0.2257080078125 +93467 -0.064056396484375 +93468 0.427154541015625 +93469 0.09515380859375 +93470 0.643218994140625 +93471 0.27423095703125 +93472 0.855926513671875 +93473 0.467010498046875 +93474 0.870361328125 +93475 0.6343994140625 +93476 0.870361328125 +93477 0.742919921875 +93478 0.862762451171875 +93479 0.797637939453125 +93480 0.79669189453125 +93481 0.796661376953125 +93482 0.595794677734375 +93483 0.733612060546875 +93484 0.362152099609375 +93485 0.6282958984375 +93486 0.1270751953125 +93487 0.499664306640625 +93488 -0.086944580078125 +93489 0.361907958984375 +93490 -0.2784423828125 +93491 0.216278076171875 +93492 -0.484832763671875 +93493 0.038848876953125 +93494 -0.729583740234375 +93495 -0.183685302734375 +93496 -0.86688232421875 +93497 -0.41717529296875 +93498 -0.870391845703125 +93499 -0.618804931640625 +93500 -0.86859130859375 +93501 -0.785430908203125 +93502 -0.86279296875 +93503 -0.8612060546875 +93504 -0.817962646484375 +93505 -0.868804931640625 +93506 -0.6116943359375 +93507 -0.866455078125 +93508 -0.3128662109375 +93509 -0.84600830078125 +93510 0.039398193359375 +93511 -0.65478515625 +93512 0.422821044921875 +93513 -0.403778076171875 +93514 0.805145263671875 +93515 -0.11553955078125 +93516 0.870361328125 +93517 0.1636962890625 +93518 0.870361328125 +93519 0.395294189453125 +93520 0.860015869140625 +93521 0.57135009765625 +93522 0.727935791015625 +93523 0.68670654296875 +93524 0.48114013671875 +93525 0.737579345703125 +93526 0.2059326171875 +93527 0.740478515625 +93528 -0.06103515625 +93529 0.710784912109375 +93530 -0.29913330078125 +93531 0.65533447265625 +93532 -0.516204833984375 +93533 0.56427001953125 +93534 -0.7252197265625 +93535 0.42718505859375 +93536 -0.85980224609375 +93537 0.26104736328125 +93538 -0.870391845703125 +93539 0.08929443359375 +93540 -0.870391845703125 +93541 -0.06781005859375 +93542 -0.858062744140625 +93543 -0.176971435546875 +93544 -0.673004150390625 +93545 -0.23516845703125 +93546 -0.42694091796875 +93547 -0.27789306640625 +93548 -0.2100830078125 +93549 -0.33514404296875 +93550 -0.0362548828125 +93551 -0.405303955078125 +93552 0.10943603515625 +93553 -0.468414306640625 +93554 0.23516845703125 +93555 -0.51080322265625 +93556 0.373687744140625 +93557 -0.504241943359375 +93558 0.517791748046875 +93559 -0.45001220703125 +93560 0.602783203125 +93561 -0.390960693359375 +93562 0.635711669921875 +93563 -0.32366943359375 +93564 0.655181884765625 +93565 -0.2255859375 +93566 0.65948486328125 +93567 -0.103668212890625 +93568 0.651275634765625 +93569 0.036376953125 +93570 0.61846923828125 +93571 0.177642822265625 +93572 0.53753662109375 +93573 0.29473876953125 +93574 0.404144287109375 +93575 0.375091552734375 +93576 0.22186279296875 +93577 0.41180419921875 +93578 0.003997802734375 +93579 0.405487060546875 +93580 -0.22100830078125 +93581 0.368255615234375 +93582 -0.42449951171875 +93583 0.314056396484375 +93584 -0.579833984375 +93585 0.25732421875 +93586 -0.641876220703125 +93587 0.227081298828125 +93588 -0.6177978515625 +93589 0.2188720703125 +93590 -0.575531005859375 +93591 0.188873291015625 +93592 -0.526336669921875 +93593 0.13360595703125 +93594 -0.42645263671875 +93595 0.088531494140625 +93596 -0.2581787109375 +93597 0.07257080078125 +93598 -0.068695068359375 +93599 0.061248779296875 +93600 0.09222412109375 +93601 0.028656005859375 +93602 0.232147216796875 +93603 -0.012237548828125 +93604 0.3509521484375 +93605 -0.05426025390625 +93606 0.410064697265625 +93607 -0.117340087890625 +93608 0.372955322265625 +93609 -0.22125244140625 +93610 0.2554931640625 +93611 -0.35162353515625 +93612 0.10711669921875 +93613 -0.472900390625 +93614 -0.052886962890625 +93615 -0.571746826171875 +93616 -0.186279296875 +93617 -0.62353515625 +93618 -0.23291015625 +93619 -0.590362548828125 +93620 -0.209442138671875 +93621 -0.48785400390625 +93622 -0.174163818359375 +93623 -0.3609619140625 +93624 -0.126739501953125 +93625 -0.215545654296875 +93626 -0.048126220703125 +93627 -0.04510498046875 +93628 0.0426025390625 +93629 0.130889892578125 +93630 0.10748291015625 +93631 0.280487060546875 +93632 0.1409912109375 +93633 0.3944091796875 +93634 0.19708251953125 +93635 0.5047607421875 +93636 0.273651123046875 +93637 0.60675048828125 +93638 0.31768798828125 +93639 0.662261962890625 +93640 0.341094970703125 +93641 0.678680419921875 +93642 0.368011474609375 +93643 0.673126220703125 +93644 0.37249755859375 +93645 0.62994384765625 +93646 0.30072021484375 +93647 0.51568603515625 +93648 0.1517333984375 +93649 0.333831787109375 +93650 -0.01470947265625 +93651 0.12982177734375 +93652 -0.1883544921875 +93653 -0.0841064453125 +93654 -0.372711181640625 +93655 -0.304962158203125 +93656 -0.51397705078125 +93657 -0.490966796875 +93658 -0.57177734375 +93659 -0.609893798828125 +93660 -0.53948974609375 +93661 -0.6531982421875 +93662 -0.43511962890625 +93663 -0.6300048828125 +93664 -0.2962646484375 +93665 -0.56378173828125 +93666 -0.161102294921875 +93667 -0.4794921875 +93668 -0.0435791015625 +93669 -0.38677978515625 +93670 0.060394287109375 +93671 -0.2841796875 +93672 0.13665771484375 +93673 -0.18359375 +93674 0.170135498046875 +93675 -0.098388671875 +93676 0.16552734375 +93677 -0.0291748046875 +93678 0.15728759765625 +93679 0.043182373046875 +93680 0.150787353515625 +93681 0.11798095703125 +93682 0.12200927734375 +93683 0.17449951171875 +93684 0.080108642578125 +93685 0.214935302734375 +93686 0.05126953125 +93687 0.253509521484375 +93688 0.062896728515625 +93689 0.3060302734375 +93690 0.09271240234375 +93691 0.35528564453125 +93692 0.092987060546875 +93693 0.367706298828125 +93694 0.07855224609375 +93695 0.353179931640625 +93696 0.06427001953125 +93697 0.322418212890625 +93698 0.0347900390625 +93699 0.2666015625 +93700 -0.01171875 +93701 0.18695068359375 +93702 -0.056060791015625 +93703 0.099700927734375 +93704 -0.055511474609375 +93705 0.0379638671875 +93706 -0.010467529296875 +93707 0.004974365234375 +93708 0.02508544921875 +93709 -0.033477783203125 +93710 0.025665283203125 +93711 -0.09185791015625 +93712 0.017333984375 +93713 -0.148834228515625 +93714 0.00189208984375 +93715 -0.200592041015625 +93716 -0.03173828125 +93717 -0.252960205078125 +93718 -0.071502685546875 +93719 -0.296295166015625 +93720 -0.13543701171875 +93721 -0.34271240234375 +93722 -0.219970703125 +93723 -0.390045166015625 +93724 -0.300506591796875 +93725 -0.42205810546875 +93726 -0.376312255859375 +93727 -0.43994140625 +93728 -0.416107177734375 +93729 -0.423980712890625 +93730 -0.371124267578125 +93731 -0.342681884765625 +93732 -0.242279052734375 +93733 -0.199554443359375 +93734 -0.069732666015625 +93735 -0.025726318359375 +93736 0.125640869140625 +93737 0.161285400390625 +93738 0.31268310546875 +93739 0.337005615234375 +93740 0.45501708984375 +93741 0.47369384765625 +93742 0.554779052734375 +93743 0.571044921875 +93744 0.61065673828125 +93745 0.626922607421875 +93746 0.610931396484375 +93747 0.632537841796875 +93748 0.531463623046875 +93749 0.571044921875 +93750 0.3883056640625 +93751 0.45428466796875 +93752 0.23468017578125 +93753 0.320709228515625 +93754 0.095245361328125 +93755 0.189300537109375 +93756 -0.00396728515625 +93757 0.080322265625 +93758 -0.04852294921875 +93759 0.00616455078125 +93760 -0.055145263671875 +93761 -0.042388916015625 +93762 -0.0758056640625 +93763 -0.09930419921875 +93764 -0.138702392578125 +93765 -0.182037353515625 +93766 -0.209197998046875 +93767 -0.26434326171875 +93768 -0.289031982421875 +93769 -0.345794677734375 +93770 -0.37884521484375 +93771 -0.4256591796875 +93772 -0.456329345703125 +93773 -0.48760986328125 +93774 -0.51641845703125 +93775 -0.527984619140625 +93776 -0.519287109375 +93777 -0.519256591796875 +93778 -0.458251953125 +93779 -0.45758056640625 +93780 -0.384796142578125 +93781 -0.38031005859375 +93782 -0.323699951171875 +93783 -0.306365966796875 +93784 -0.269287109375 +93785 -0.233642578125 +93786 -0.1951904296875 +93787 -0.14569091796875 +93788 -0.100006103515625 +93789 -0.04351806640625 +93790 -0.01055908203125 +93791 0.052154541015625 +93792 0.1033935546875 +93793 0.1607666015625 +93794 0.24908447265625 +93795 0.28594970703125 +93796 0.373199462890625 +93797 0.3892822265625 +93798 0.45806884765625 +93799 0.45770263671875 +93800 0.511474609375 +93801 0.496337890625 +93802 0.565399169921875 +93803 0.527740478515625 +93804 0.61138916015625 +93805 0.546600341796875 +93806 0.5897216796875 +93807 0.51202392578125 +93808 0.4906005859375 +93809 0.41839599609375 +93810 0.33148193359375 +93811 0.279388427734375 +93812 0.147796630859375 +93813 0.121368408203125 +93814 -0.01873779296875 +93815 -0.0247802734375 +93816 -0.140289306640625 +93817 -0.137939453125 +93818 -0.191986083984375 +93819 -0.19921875 +93820 -0.184295654296875 +93821 -0.214691162109375 +93822 -0.161834716796875 +93823 -0.21453857421875 +93824 -0.166595458984375 +93825 -0.227447509765625 +93826 -0.19390869140625 +93827 -0.24981689453125 +93828 -0.22442626953125 +93829 -0.268096923828125 +93830 -0.279754638671875 +93831 -0.29779052734375 +93832 -0.3389892578125 +93833 -0.32489013671875 +93834 -0.3543701171875 +93835 -0.31695556640625 +93836 -0.348175048828125 +93837 -0.290679931640625 +93838 -0.32598876953125 +93839 -0.25128173828125 +93840 -0.2581787109375 +93841 -0.17938232421875 +93842 -0.139801025390625 +93843 -0.072845458984375 +93844 0.014617919921875 +93845 0.056915283203125 +93846 0.144378662109375 +93847 0.166229248046875 +93848 0.221038818359375 +93849 0.23431396484375 +93850 0.27069091796875 +93851 0.27874755859375 +93852 0.294036865234375 +93853 0.29962158203125 +93854 0.311767578125 +93855 0.31134033203125 +93856 0.339141845703125 +93857 0.324798583984375 +93858 0.360260009765625 +93859 0.329437255859375 +93860 0.360504150390625 +93861 0.315704345703125 +93862 0.308380126953125 +93863 0.261962890625 +93864 0.18170166015625 +93865 0.153350830078125 +93866 0.0047607421875 +93867 0.00823974609375 +93868 -0.17559814453125 +93869 -0.138946533203125 +93870 -0.3143310546875 +93871 -0.25518798828125 +93872 -0.36785888671875 +93873 -0.308563232421875 +93874 -0.36248779296875 +93875 -0.317047119140625 +93876 -0.343536376953125 +93877 -0.31231689453125 +93878 -0.3018798828125 +93879 -0.287506103515625 +93880 -0.231414794921875 +93881 -0.23809814453125 +93882 -0.117645263671875 +93883 -0.153839111328125 +93884 0.007049560546875 +93885 -0.058074951171875 +93886 0.087982177734375 +93887 0.009735107421875 +93888 0.13946533203125 +93889 0.059173583984375 +93890 0.17425537109375 +93891 0.09857177734375 +93892 0.188201904296875 +93893 0.12408447265625 +93894 0.171234130859375 +93895 0.127685546875 +93896 0.118438720703125 +93897 0.105010986328125 +93898 0.05706787109375 +93899 0.074676513671875 +93900 -0.010711669921875 +93901 0.03753662109375 +93902 -0.0914306640625 +93903 -0.0115966796875 +93904 -0.162322998046875 +93905 -0.056884765625 +93906 -0.194549560546875 +93907 -0.0780029296875 +93908 -0.1492919921875 +93909 -0.04730224609375 +93910 -0.02166748046875 +93911 0.038848876953125 +93912 0.124053955078125 +93913 0.13507080078125 +93914 0.211151123046875 +93915 0.18719482421875 +93916 0.240447998046875 +93917 0.196441650390625 +93918 0.242218017578125 +93919 0.18505859375 +93920 0.2257080078125 +93921 0.160369873046875 +93922 0.194366455078125 +93923 0.125518798828125 +93924 0.115509033203125 +93925 0.057891845703125 +93926 0.0128173828125 +93927 -0.024993896484375 +93928 -0.053802490234375 +93929 -0.080047607421875 +93930 -0.110626220703125 +93931 -0.1256103515625 +93932 -0.199493408203125 +93933 -0.1912841796875 +93934 -0.29437255859375 +93935 -0.258453369140625 +93936 -0.33221435546875 +93937 -0.2823486328125 +93938 -0.27972412109375 +93939 -0.239532470703125 +93940 -0.185333251953125 +93941 -0.164825439453125 +93942 -0.128204345703125 +93943 -0.115081787109375 +93944 -0.115692138671875 +93945 -0.096038818359375 +93946 -0.116455078125 +93947 -0.085968017578125 +93948 -0.105926513671875 +93949 -0.0679931640625 +93950 -0.053955078125 +93951 -0.021209716796875 +93952 0.048797607421875 +93953 0.06072998046875 +93954 0.157318115234375 +93955 0.145050048828125 +93956 0.212005615234375 +93957 0.1878662109375 +93958 0.218475341796875 +93959 0.193328857421875 +93960 0.23724365234375 +93961 0.206451416015625 +93962 0.30535888671875 +93963 0.254913330078125 +93964 0.38128662109375 +93965 0.30792236328125 +93966 0.404449462890625 +93967 0.320587158203125 +93968 0.3944091796875 +93969 0.3077392578125 +93970 0.3885498046875 +93971 0.297454833984375 +93972 0.362640380859375 +93973 0.272064208984375 +93974 0.27362060546875 +93975 0.1998291015625 +93976 0.11712646484375 +93977 0.07781982421875 +93978 -0.054901123046875 +93979 -0.0550537109375 +93980 -0.19085693359375 +93981 -0.160125732421875 +93982 -0.28570556640625 +93983 -0.2335205078125 +93984 -0.339263916015625 +93985 -0.274993896484375 +93986 -0.3775634765625 +93987 -0.3038330078125 +93988 -0.445709228515625 +93989 -0.353607177734375 +93990 -0.535064697265625 +93991 -0.417999267578125 +93992 -0.629058837890625 +93993 -0.48480224609375 +93994 -0.697601318359375 +93995 -0.531829833984375 +93996 -0.70391845703125 +93997 -0.531951904296875 +93998 -0.6424560546875 +93999 -0.4813232421875 +94000 -0.491241455078125 +94001 -0.3638916015625 +94002 -0.265716552734375 +94003 -0.19140625 +94004 -0.023712158203125 +94005 -0.007110595703125 +94006 0.201751708984375 +94007 0.1641845703125 +94008 0.375823974609375 +94009 0.296356201171875 +94010 0.485076904296875 +94011 0.37933349609375 +94012 0.56884765625 +94013 0.442291259765625 +94014 0.634765625 +94015 0.49090576171875 +94016 0.63763427734375 +94017 0.491607666015625 +94018 0.5660400390625 +94019 0.436004638671875 +94020 0.4720458984375 +94021 0.36297607421875 +94022 0.40692138671875 +94023 0.31085205078125 +94024 0.3778076171875 +94025 0.285186767578125 +94026 0.376953125 +94027 0.280426025390625 +94028 0.371978759765625 +94029 0.272705078125 +94030 0.313140869140625 +94031 0.225250244140625 +94032 0.184417724609375 +94033 0.1263427734375 +94034 0.011199951171875 +94035 -0.004974365234375 +94036 -0.171051025390625 +94037 -0.1422119140625 +94038 -0.33740234375 +94039 -0.266754150390625 +94040 -0.47198486328125 +94041 -0.36676025390625 +94042 -0.560394287109375 +94043 -0.431549072265625 +94044 -0.58056640625 +94045 -0.444793701171875 +94046 -0.54754638671875 +94047 -0.417816162109375 +94048 -0.508575439453125 +94049 -0.385894775390625 +94050 -0.459503173828125 +94051 -0.34613037109375 +94052 -0.394378662109375 +94053 -0.294281005859375 +94054 -0.35260009765625 +94055 -0.259857177734375 +94056 -0.31170654296875 +94057 -0.226287841796875 +94058 -0.197418212890625 +94059 -0.13848876953125 +94060 -0.007965087890625 +94061 0.004669189453125 +94062 0.207489013671875 +94063 0.16650390625 +94064 0.409210205078125 +94065 0.3173828125 +94066 0.57208251953125 +94067 0.4385986328125 +94068 0.66595458984375 +94069 0.507781982421875 +94070 0.65875244140625 +94071 0.5010986328125 +94072 0.56744384765625 +94073 0.4312744140625 +94074 0.431396484375 +94075 0.327728271484375 +94076 0.29443359375 +94077 0.22320556640625 +94078 0.182464599609375 +94079 0.137115478515625 +94080 0.06365966796875 +94081 0.045928955078125 +94082 -0.075958251953125 +94083 -0.060577392578125 +94084 -0.189422607421875 +94085 -0.147308349609375 +94086 -0.271942138671875 +94087 -0.2105712890625 +94088 -0.342529296875 +94089 -0.264434814453125 +94090 -0.364166259765625 +94091 -0.281341552734375 +94092 -0.327239990234375 +94093 -0.25408935546875 +94094 -0.2769775390625 +94095 -0.21630859375 +94096 -0.253692626953125 +94097 -0.19805908203125 +94098 -0.24365234375 +94099 -0.189178466796875 +94100 -0.1983642578125 +94101 -0.1536865234375 +94102 -0.116241455078125 +94103 -0.09051513671875 +94104 -0.036834716796875 +94105 -0.0291748046875 +94106 0.034881591796875 +94107 0.026458740234375 +94108 0.09124755859375 +94109 0.070587158203125 +94110 0.10888671875 +94111 0.085723876953125 +94112 0.125518798828125 +94113 0.09979248046875 +94114 0.15771484375 +94115 0.125030517578125 +94116 0.17828369140625 +94117 0.141143798828125 +94118 0.17108154296875 +94119 0.1361083984375 +94120 0.129974365234375 +94121 0.105377197265625 +94122 0.082427978515625 +94123 0.069366455078125 +94124 0.027679443359375 +94125 0.027587890625 +94126 -0.065643310546875 +94127 -0.043243408203125 +94128 -0.15936279296875 +94129 -0.114593505859375 +94130 -0.21307373046875 +94131 -0.15631103515625 +94132 -0.234649658203125 +94133 -0.1741943359375 +94134 -0.2001953125 +94135 -0.150360107421875 +94136 -0.119171142578125 +94137 -0.09173583984375 +94138 -0.024749755859375 +94139 -0.02294921875 +94140 0.085784912109375 +94141 0.058135986328125 +94142 0.178131103515625 +94143 0.12603759765625 +94144 0.215576171875 +94145 0.153472900390625 +94146 0.211456298828125 +94147 0.150360107421875 +94148 0.17523193359375 +94149 0.123748779296875 +94150 0.128753662109375 +94151 0.08984375 +94152 0.1019287109375 +94153 0.07086181640625 +94154 0.0743408203125 +94155 0.051605224609375 +94156 0.04327392578125 +94157 0.0299072265625 +94158 0.038177490234375 +94159 0.027618408203125 +94160 0.076263427734375 +94161 0.057464599609375 +94162 0.14105224609375 +94163 0.107086181640625 +94164 0.186431884765625 +94165 0.142120361328125 +94166 0.188812255859375 +94167 0.144927978515625 +94168 0.1390380859375 +94169 0.108642578125 +94170 0.041778564453125 +94171 0.0367431640625 +94172 -0.079437255859375 +94173 -0.05328369140625 +94174 -0.219390869140625 +94175 -0.157562255859375 +94176 -0.367828369140625 +94177 -0.2684326171875 +94178 -0.494873046875 +94179 -0.3636474609375 +94180 -0.556243896484375 +94181 -0.41021728515625 +94182 -0.508697509765625 +94183 -0.37591552734375 +94184 -0.3756103515625 +94185 -0.278045654296875 +94186 -0.218902587890625 +94187 -0.162628173828125 +94188 -0.063751220703125 +94189 -0.04833984375 +94190 0.091552734375 +94191 0.06610107421875 +94192 0.23602294921875 +94193 0.172607421875 +94194 0.342987060546875 +94195 0.25140380859375 +94196 0.39520263671875 +94197 0.289703369140625 +94198 0.389373779296875 +94199 0.28509521484375 +94200 0.324249267578125 +94201 0.23663330078125 +94202 0.224090576171875 +94203 0.162353515625 +94204 0.124267578125 +94205 0.088531494140625 +94206 0.037078857421875 +94207 0.0242919921875 +94208 -0.010101318359375 +94209 -0.00958251953125 +94210 -0.019439697265625 +94211 -0.01495361328125 +94212 -0.022796630859375 +94213 -0.0162353515625 +94214 -0.001556396484375 +94215 0.00115966796875 +94216 0.056304931640625 +94217 0.046661376953125 +94218 0.106719970703125 +94219 0.086181640625 +94220 0.096893310546875 +94221 0.078826904296875 +94222 0.042694091796875 +94223 0.036956787109375 +94224 -0.018035888671875 +94225 -0.01007080078125 +94226 -0.07586669921875 +94227 -0.054931640625 +94228 -0.11944580078125 +94229 -0.088836669921875 +94230 -0.15972900390625 +94231 -0.12030029296875 +94232 -0.202606201171875 +94233 -0.15386962890625 +94234 -0.24859619140625 +94235 -0.18994140625 +94236 -0.30517578125 +94237 -0.234283447265625 +94238 -0.36212158203125 +94239 -0.27899169921875 +94240 -0.39141845703125 +94241 -0.302337646484375 +94242 -0.35528564453125 +94243 -0.274932861328125 +94244 -0.249969482421875 +94245 -0.19384765625 +94246 -0.092864990234375 +94247 -0.07257080078125 +94248 0.08905029296875 +94249 0.0679931640625 +94250 0.2352294921875 +94251 0.180877685546875 +94252 0.318817138671875 +94253 0.24530029296875 +94254 0.358642578125 +94255 0.27587890625 +94256 0.347747802734375 +94257 0.267242431640625 +94258 0.28564453125 +94259 0.219024658203125 +94260 0.223175048828125 +94261 0.170684814453125 +94262 0.196746826171875 +94263 0.150421142578125 +94264 0.179840087890625 +94265 0.137664794921875 +94266 0.155548095703125 +94267 0.119293212890625 +94268 0.151214599609375 +94269 0.116485595703125 +94270 0.156951904296875 +94271 0.121551513671875 +94272 0.13177490234375 +94273 0.10260009765625 +94274 0.100799560546875 +94275 0.0791015625 +94276 0.087127685546875 +94277 0.068939208984375 +94278 0.05487060546875 +94279 0.044281005859375 +94280 -0.009002685546875 +94281 -0.0050048828125 +94282 -0.10400390625 +94283 -0.07855224609375 +94284 -0.229400634765625 +94285 -0.175811767578125 +94286 -0.35552978515625 +94287 -0.27374267578125 +94288 -0.441925048828125 +94289 -0.3409423828125 +94290 -0.473846435546875 +94291 -0.365997314453125 +94292 -0.464813232421875 +94293 -0.359344482421875 +94294 -0.419097900390625 +94295 -0.32427978515625 +94296 -0.334320068359375 +94297 -0.2589111328125 +94298 -0.227935791015625 +94299 -0.1767578125 +94300 -0.12347412109375 +94301 -0.0960693359375 +94302 -0.02764892578125 +94303 -0.022064208984375 +94304 0.077667236328125 +94305 0.059356689453125 +94306 0.2132568359375 +94307 0.164337158203125 +94308 0.38885498046875 +94309 0.3004150390625 +94310 0.582794189453125 +94311 0.4508056640625 +94312 0.734039306640625 +94313 0.568115234375 +94314 0.800140380859375 +94315 0.61944580078125 +94316 0.7783203125 +94317 0.60260009765625 +94318 0.6651611328125 +94319 0.51495361328125 +94320 0.45965576171875 +94321 0.355712890625 +94322 0.199188232421875 +94323 0.15386962890625 +94324 -0.050689697265625 +94325 -0.039703369140625 +94326 -0.23297119140625 +94327 -0.180816650390625 +94328 -0.33013916015625 +94329 -0.255889892578125 +94330 -0.368408203125 +94331 -0.2852783203125 +94332 -0.378936767578125 +94333 -0.293182373046875 +94334 -0.376983642578125 +94335 -0.291473388671875 +94336 -0.37969970703125 +94337 -0.29345703125 +94338 -0.391510009765625 +94339 -0.30255126953125 +94340 -0.385345458984375 +94341 -0.297760009765625 +94342 -0.3419189453125 +94343 -0.264129638671875 +94344 -0.28289794921875 +94345 -0.218475341796875 +94346 -0.251617431640625 +94347 -0.19439697265625 +94348 -0.266143798828125 +94349 -0.205902099609375 +94350 -0.273345947265625 +94351 -0.211761474609375 +94352 -0.216796875 +94353 -0.16815185546875 +94354 -0.128265380859375 +94355 -0.099700927734375 +94356 -0.068145751953125 +94357 -0.053253173828125 +94358 -0.0430908203125 +94359 -0.033966064453125 +94360 -0.024444580078125 +94361 -0.019622802734375 +94362 0.020721435546875 +94363 0.015350341796875 +94364 0.124481201171875 +94365 0.095855712890625 +94366 0.25787353515625 +94367 0.199371337890625 +94368 0.379119873046875 +94369 0.293487548828125 +94370 0.47991943359375 +94371 0.371795654296875 +94372 0.5281982421875 +94373 0.40936279296875 +94374 0.511138916015625 +94375 0.396240234375 +94376 0.456207275390625 +94377 0.353729248046875 +94378 0.407470703125 +94379 0.3160400390625 +94380 0.383758544921875 +94381 0.29779052734375 +94382 0.35687255859375 +94383 0.277069091796875 +94384 0.31182861328125 +94385 0.24224853515625 +94386 0.250885009765625 +94387 0.195037841796875 +94388 0.1654052734375 +94389 0.128753662109375 +94390 0.035247802734375 +94391 0.02777099609375 +94392 -0.142059326171875 +94393 -0.109832763671875 +94394 -0.33563232421875 +94395 -0.26007080078125 +94396 -0.5345458984375 +94397 -0.414459228515625 +94398 -0.72186279296875 +94399 -0.559814453125 +94400 -0.836669921875 +94401 -0.64892578125 +94402 -0.8326416015625 +94403 -0.64581298828125 +94404 -0.7296142578125 +94405 -0.56591796875 +94406 -0.582550048828125 +94407 -0.451873779296875 +94408 -0.440093994140625 +94409 -0.341400146484375 +94410 -0.324310302734375 +94411 -0.251617431640625 +94412 -0.20147705078125 +94413 -0.1563720703125 +94414 -0.044647216796875 +94415 -0.03472900390625 +94416 0.103973388671875 +94417 0.08056640625 +94418 0.202392578125 +94419 0.15692138671875 +94420 0.264495849609375 +94421 0.205078125 +94422 0.338897705078125 +94423 0.2628173828125 +94424 0.443817138671875 +94425 0.34423828125 +94426 0.545074462890625 +94427 0.422821044921875 +94428 0.6173095703125 +94429 0.478851318359375 +94430 0.6524658203125 +94431 0.506103515625 +94432 0.66339111328125 +94433 0.514556884765625 +94434 0.6561279296875 +94435 0.5089111328125 +94436 0.606781005859375 +94437 0.470611572265625 +94438 0.501190185546875 +94439 0.388671875 +94440 0.352783203125 +94441 0.273529052734375 +94442 0.176544189453125 +94443 0.13677978515625 +94444 -0.034820556640625 +94445 -0.027191162109375 +94446 -0.258209228515625 +94447 -0.200439453125 +94448 -0.44244384765625 +94449 -0.343292236328125 +94450 -0.5753173828125 +94451 -0.446258544921875 +94452 -0.65203857421875 +94453 -0.505645751953125 +94454 -0.641632080078125 +94455 -0.4974365234375 +94456 -0.562164306640625 +94457 -0.4356689453125 +94458 -0.458038330078125 +94459 -0.35479736328125 +94460 -0.350555419921875 +94461 -0.271331787109375 +94462 -0.260528564453125 +94463 -0.201446533203125 +94464 -0.192108154296875 +94465 -0.1485595703125 +94466 -0.141937255859375 +94467 -0.110107421875 +94468 -0.1021728515625 +94469 -0.0797119140625 +94470 -0.062896728515625 +94471 -0.049530029296875 +94472 -0.011932373046875 +94473 -0.00982666015625 +94474 0.062835693359375 +94475 0.049102783203125 +94476 0.148712158203125 +94477 0.11700439453125 +94478 0.241729736328125 +94479 0.190704345703125 +94480 0.34912109375 +94481 0.276123046875 +94482 0.457305908203125 +94483 0.362396240234375 +94484 0.54388427734375 +94485 0.431488037109375 +94486 0.5728759765625 +94487 0.45440673828125 +94488 0.506591796875 +94489 0.400726318359375 +94490 0.351226806640625 +94491 0.275482177734375 +94492 0.146514892578125 +94493 0.110748291015625 +94494 -0.05523681640625 +94495 -0.051239013671875 +94496 -0.21624755859375 +94497 -0.17999267578125 +94498 -0.334930419921875 +94499 -0.2742919921875 +94500 -0.402984619140625 +94501 -0.3275146484375 +94502 -0.4412841796875 +94503 -0.35662841796875 +94504 -0.49578857421875 +94505 -0.39886474609375 +94506 -0.5601806640625 +94507 -0.449188232421875 +94508 -0.600738525390625 +94509 -0.480499267578125 +94510 -0.584228515625 +94511 -0.46600341796875 +94512 -0.47930908203125 +94513 -0.380401611328125 +94514 -0.27935791015625 +94515 -0.218414306640625 +94516 -0.0089111328125 +94517 9.1552734375e-05 +94518 0.268798828125 +94519 0.22406005859375 +94520 0.482818603515625 +94521 0.396209716796875 +94522 0.60369873046875 +94523 0.4927978515625 +94524 0.650421142578125 +94525 0.529205322265625 +94526 0.66400146484375 +94527 0.5386962890625 +94528 0.6414794921875 +94529 0.5189208984375 +94530 0.572540283203125 +94531 0.461669921875 +94532 0.498138427734375 +94533 0.40008544921875 +94534 0.439453125 +94535 0.351348876953125 +94536 0.375518798828125 +94537 0.298614501953125 +94538 0.274505615234375 +94539 0.2161865234375 +94540 0.1087646484375 +94541 0.081787109375 +94542 -0.099395751953125 +94543 -0.0865478515625 +94544 -0.3182373046875 +94545 -0.26312255859375 +94546 -0.5489501953125 +94547 -0.448974609375 +94548 -0.7738037109375 +94549 -0.62982177734375 +94550 -0.86383056640625 +94551 -0.762908935546875 +94552 -0.870391845703125 +94553 -0.8214111328125 +94554 -0.86895751953125 +94555 -0.819732666015625 +94556 -0.861053466796875 +94557 -0.7685546875 +94558 -0.765869140625 +94559 -0.65399169921875 +94560 -0.5301513671875 +94561 -0.46697998046875 +94562 -0.214691162109375 +94563 -0.213348388671875 +94564 0.137359619140625 +94565 0.07208251953125 +94566 0.474822998046875 +94567 0.3477783203125 +94568 0.76239013671875 +94569 0.584991455078125 +94570 0.867462158203125 +94571 0.761932373046875 +94572 0.870361328125 +94573 0.857147216796875 +94574 0.86480712890625 +94575 0.86236572265625 +94576 0.831817626953125 +94577 0.860504150390625 +94578 0.677581787109375 +94579 0.847625732421875 +94580 0.495880126953125 +94581 0.745147705078125 +94582 0.30767822265625 +94583 0.61737060546875 +94584 0.116180419921875 +94585 0.466156005859375 +94586 -0.110748291015625 +94587 0.26593017578125 +94588 -0.381805419921875 +94589 0.011138916015625 +94590 -0.6572265625 +94591 -0.263580322265625 +94592 -0.857421875 +94593 -0.509765625 +94594 -0.870391845703125 +94595 -0.692718505859375 +94596 -0.870391845703125 +94597 -0.806640625 +94598 -0.86444091796875 +94599 -0.8565673828125 +94600 -0.85723876953125 +94601 -0.86181640625 +94602 -0.790008544921875 +94603 -0.863433837890625 +94604 -0.62847900390625 +94605 -0.856658935546875 +94606 -0.3956298828125 +94607 -0.732574462890625 +94608 -0.126708984375 +94609 -0.537872314453125 +94610 0.150115966796875 +94611 -0.312347412109375 +94612 0.424041748046875 +94613 -0.0655517578125 +94614 0.670623779296875 +94615 0.1806640625 +94616 0.854522705078125 +94617 0.394927978515625 +94618 0.866485595703125 +94619 0.562896728515625 +94620 0.86920166015625 +94621 0.672088623046875 +94622 0.8653564453125 +94623 0.737152099609375 +94624 0.857147216796875 +94625 0.7689208984375 +94626 0.766845703125 +94627 0.7650146484375 +94628 0.628509521484375 +94629 0.729583740234375 +94630 0.462127685546875 +94631 0.657196044921875 +94632 0.297210693359375 +94633 0.5687255859375 +94634 0.14862060546875 +94635 0.474212646484375 +94636 -0.00537109375 +94637 0.35528564453125 +94638 -0.15753173828125 +94639 0.218048095703125 +94640 -0.31304931640625 +94641 0.059661865234375 +94642 -0.48876953125 +94643 -0.13116455078125 +94644 -0.6416015625 +94645 -0.316436767578125 +94646 -0.751373291015625 +94647 -0.47613525390625 +94648 -0.84619140625 +94649 -0.62884521484375 +94650 -0.861297607421875 +94651 -0.76263427734375 +94652 -0.863250732421875 +94653 -0.850677490234375 +94654 -0.856597900390625 +94655 -0.855926513671875 +94656 -0.7498779296875 +94657 -0.8228759765625 +94658 -0.624542236328125 +94659 -0.76361083984375 +94660 -0.47808837890625 +94661 -0.671966552734375 +94662 -0.253387451171875 +94663 -0.500732421875 +94664 0.003692626953125 +94665 -0.286865234375 +94666 0.2257080078125 +94667 -0.085662841796875 +94668 0.427154541015625 +94669 0.112884521484375 +94670 0.643218994140625 +94671 0.334869384765625 +94672 0.855926513671875 +94673 0.572418212890625 +94674 0.870361328125 +94675 0.778656005859375 +94676 0.870361328125 +94677 0.86090087890625 +94678 0.862762451171875 +94679 0.868438720703125 +94680 0.79669189453125 +94681 0.8685302734375 +94682 0.595794677734375 +94683 0.860321044921875 +94684 0.362152099609375 +94685 0.780853271484375 +94686 0.1270751953125 +94687 0.624053955078125 +94688 -0.086944580078125 +94689 0.45489501953125 +94690 -0.2784423828125 +94691 0.275177001953125 +94692 -0.484832763671875 +94693 0.056854248046875 +94694 -0.729583740234375 +94695 -0.215423583984375 +94696 -0.86688232421875 +94697 -0.500640869140625 +94698 -0.870391845703125 +94699 -0.747528076171875 +94700 -0.86859130859375 +94701 -0.865142822265625 +94702 -0.86279296875 +94703 -0.870391845703125 +94704 -0.817962646484375 +94705 -0.868621826171875 +94706 -0.6116943359375 +94707 -0.8564453125 +94708 -0.3128662109375 +94709 -0.663543701171875 +94710 0.039398193359375 +94711 -0.38836669921875 +94712 0.422821044921875 +94713 -0.064788818359375 +94714 0.805145263671875 +94715 0.279632568359375 +94716 0.870361328125 +94717 0.590606689453125 +94718 0.870361328125 +94719 0.823974609375 +94720 0.860015869140625 +94721 0.867462158203125 +94722 0.727935791015625 +94723 0.870361328125 +94724 0.48114013671875 +94725 0.86407470703125 +94726 0.2059326171875 +94727 0.827606201171875 +94728 -0.06103515625 +94729 0.6807861328125 +94730 -0.29913330078125 +94731 0.516021728515625 +94732 -0.516204833984375 +94733 0.325958251953125 +94734 -0.7252197265625 +94735 0.10137939453125 +94736 -0.85980224609375 +94737 -0.134368896484375 +94738 -0.870391845703125 +94739 -0.351348876953125 +94740 -0.870391845703125 +94741 -0.525054931640625 +94742 -0.858062744140625 +94743 -0.6162109375 +94744 -0.673004150390625 +94745 -0.624114990234375 +94746 -0.42694091796875 +94747 -0.596649169921875 +94748 -0.2100830078125 +94749 -0.575653076171875 +94750 -0.0362548828125 +94751 -0.564422607421875 +94752 0.10943603515625 +94753 -0.54388427734375 +94754 0.23516845703125 +94755 -0.50250244140625 +94756 0.373687744140625 +94757 -0.410369873046875 +94758 0.517791748046875 +94759 -0.273345947265625 +94760 0.602783203125 +94761 -0.147796630859375 +94762 0.635711669921875 +94763 -0.031829833984375 +94764 0.655181884765625 +94765 0.10113525390625 +94766 0.65948486328125 +94767 0.242462158203125 +94768 0.651275634765625 +94769 0.38629150390625 +94770 0.61846923828125 +94771 0.51385498046875 +94772 0.53753662109375 +94773 0.596832275390625 +94774 0.404144287109375 +94775 0.623504638671875 +94776 0.22186279296875 +94777 0.58966064453125 +94778 0.003997802734375 +94779 0.500518798828125 +94780 -0.22100830078125 +94781 0.375579833984375 +94782 -0.42449951171875 +94783 0.23626708984375 +94784 -0.579833984375 +94785 0.104156494140625 +94786 -0.641876220703125 +94787 0.0181884765625 +94788 -0.6177978515625 +94789 -0.024810791015625 +94790 -0.575531005859375 +94791 -0.07763671875 +94792 -0.526336669921875 +94793 -0.14422607421875 +94794 -0.42645263671875 +94795 -0.181396484375 +94796 -0.2581787109375 +94797 -0.167266845703125 +94798 -0.068695068359375 +94799 -0.13433837890625 +94800 0.09222412109375 +94801 -0.1175537109375 +94802 0.232147216796875 +94803 -0.104339599609375 +94804 0.3509521484375 +94805 -0.089508056640625 +94806 0.410064697265625 +94807 -0.101409912109375 +94808 0.372955322265625 +94809 -0.16802978515625 +94810 0.2554931640625 +94811 -0.27484130859375 +94812 0.10711669921875 +94813 -0.380706787109375 +94814 -0.052886962890625 +94815 -0.471221923828125 +94816 -0.186279296875 +94817 -0.517333984375 +94818 -0.23291015625 +94819 -0.4727783203125 +94820 -0.209442138671875 +94821 -0.356658935546875 +94822 -0.174163818359375 +94823 -0.223541259765625 +94824 -0.126739501953125 +94825 -0.0789794921875 +94826 -0.048126220703125 +94827 0.087249755859375 +94828 0.0426025390625 +94829 0.253814697265625 +94830 0.10748291015625 +94831 0.384185791015625 +94832 0.1409912109375 +94833 0.470001220703125 +94834 0.19708251953125 +94835 0.553955078125 +94836 0.273651123046875 +94837 0.63287353515625 +94838 0.31768798828125 +94839 0.66204833984375 +94840 0.341094970703125 +94841 0.652587890625 +94842 0.368011474609375 +94843 0.626953125 +94844 0.37249755859375 +94845 0.5665283203125 +94846 0.30072021484375 +94847 0.4300537109375 +94848 0.1517333984375 +94849 0.221221923828125 +94850 -0.01470947265625 +94851 -0.004974365234375 +94852 -0.1883544921875 +94853 -0.235137939453125 +94854 -0.372711181640625 +94855 -0.467681884765625 +94856 -0.51397705078125 +94857 -0.65338134765625 +94858 -0.57177734375 +94859 -0.75494384765625 +94860 -0.53948974609375 +94861 -0.764312744140625 +94862 -0.43511962890625 +94863 -0.69512939453125 +94864 -0.2962646484375 +94865 -0.5784912109375 +94866 -0.161102294921875 +94867 -0.446990966796875 +94868 -0.0435791015625 +94869 -0.313812255859375 +94870 0.060394287109375 +94871 -0.177886962890625 +94872 0.13665771484375 +94873 -0.054168701171875 +94874 0.170135498046875 +94875 0.041107177734375 +94876 0.16552734375 +94877 0.108062744140625 +94878 0.15728759765625 +94879 0.171600341796875 +94880 0.150787353515625 +94881 0.232421875 +94882 0.12200927734375 +94883 0.266876220703125 +94884 0.080108642578125 +94885 0.2796630859375 +94886 0.05126953125 +94887 0.290435791015625 +94888 0.062896728515625 +94889 0.32073974609375 +94890 0.09271240234375 +94891 0.351104736328125 +94892 0.092987060546875 +94893 0.341644287109375 +94894 0.07855224609375 +94895 0.30572509765625 +94896 0.06427001953125 +94897 0.257537841796875 +94898 0.0347900390625 +94899 0.1865234375 +94900 -0.01171875 +94901 0.093902587890625 +94902 -0.056060791015625 +94903 -0.001007080078125 +94904 -0.055511474609375 +94905 -0.059051513671875 +94906 -0.010467529296875 +94907 -0.077362060546875 +94908 0.02508544921875 +94909 -0.0982666015625 +94910 0.025665283203125 +94911 -0.140533447265625 +94912 0.017333984375 +94913 -0.18017578125 +94914 0.00189208984375 +94915 -0.214202880859375 +94916 -0.03173828125 +94917 -0.251129150390625 +94918 -0.071502685546875 +94919 -0.280731201171875 +94920 -0.13543701171875 +94921 -0.3187255859375 +94922 -0.219970703125 +94923 -0.36328125 +94924 -0.300506591796875 +94925 -0.3955078125 +94926 -0.376312255859375 +94927 -0.416961669921875 +94928 -0.416107177734375 +94929 -0.40386962890625 +94930 -0.371124267578125 +94931 -0.31793212890625 +94932 -0.242279052734375 +94933 -0.162567138671875 +94934 -0.069732666015625 +94935 0.02587890625 +94936 0.125640869140625 +94937 0.22760009765625 +94938 0.31268310546875 +94939 0.41455078125 +94940 0.45501708984375 +94941 0.5548095703125 +94942 0.554779052734375 +94943 0.649322509765625 +94944 0.61065673828125 +94945 0.696685791015625 +94946 0.610931396484375 +94947 0.68731689453125 +94948 0.531463623046875 +94949 0.601776123046875 +94950 0.3883056640625 +94951 0.454803466796875 +94952 0.23468017578125 +94953 0.29278564453125 +94954 0.095245361328125 +94955 0.138458251953125 +94956 -0.00396728515625 +94957 0.015777587890625 +94958 -0.04852294921875 +94959 -0.060882568359375 +94960 -0.055145263671875 +94961 -0.103424072265625 +94962 -0.0758056640625 +94963 -0.15362548828125 +94964 -0.138702392578125 +94965 -0.23345947265625 +94966 -0.209197998046875 +94967 -0.312530517578125 +94968 -0.289031982421875 +94969 -0.391387939453125 +94970 -0.37884521484375 +94971 -0.47021484375 +94972 -0.456329345703125 +94973 -0.5302734375 +94974 -0.51641845703125 +94975 -0.56787109375 +94976 -0.519287109375 +94977 -0.55029296875 +94978 -0.458251953125 +94979 -0.47320556640625 +94980 -0.384796142578125 +94981 -0.381805419921875 +94982 -0.323699951171875 +94983 -0.298797607421875 +94984 -0.269287109375 +94985 -0.221099853515625 +94986 -0.1951904296875 +94987 -0.128021240234375 +94988 -0.100006103515625 +94989 -0.01995849609375 +94990 -0.01055908203125 +94991 0.078857421875 +94992 0.1033935546875 +94993 0.193023681640625 +94994 0.24908447265625 +94995 0.327911376953125 +94996 0.373199462890625 +94997 0.43780517578125 +94998 0.45806884765625 +94999 0.50762939453125 +95000 0.511474609375 +95001 0.5443115234375 +95002 0.565399169921875 +95003 0.575714111328125 +95004 0.61138916015625 +95005 0.59564208984375 +95006 0.5897216796875 +95007 0.554473876953125 +95008 0.4906005859375 +95009 0.4451904296875 +95010 0.33148193359375 +95011 0.28411865234375 +95012 0.147796630859375 +95013 0.102752685546875 +95014 -0.01873779296875 +95015 -0.062042236328125 +95016 -0.140289306640625 +95017 -0.1854248046875 +95018 -0.191986083984375 +95019 -0.2452392578125 +95020 -0.184295654296875 +95021 -0.2496337890625 +95022 -0.161834716796875 +95023 -0.236083984375 +95024 -0.166595458984375 +95025 -0.240142822265625 +95026 -0.19390869140625 +95027 -0.25799560546875 +95028 -0.22442626953125 +95029 -0.273651123046875 +95030 -0.279754638671875 +95031 -0.30615234375 +95032 -0.3389892578125 +95033 -0.338653564453125 +95034 -0.3543701171875 +95035 -0.331634521484375 +95036 -0.348175048828125 +95037 -0.305206298828125 +95038 -0.32598876953125 +95039 -0.2652587890625 +95040 -0.2581787109375 +95041 -0.18780517578125 +95042 -0.139801025390625 +95043 -0.06964111328125 +95044 0.014617919921875 +95045 0.07598876953125 +95046 0.144378662109375 +95047 0.19677734375 +95048 0.221038818359375 +95049 0.268096923828125 +95050 0.27069091796875 +95051 0.3118896484375 +95052 0.294036865234375 +95053 0.328826904296875 +95054 0.311767578125 +95055 0.3367919921875 +95056 0.339141845703125 +95057 0.349334716796875 +95058 0.360260009765625 +95059 0.3538818359375 +95060 0.360504150390625 +95061 0.338775634765625 +95062 0.308380126953125 +95063 0.277313232421875 +95064 0.18170166015625 +95065 0.15093994140625 +95066 0.0047607421875 +95067 -0.01824951171875 +95068 -0.17559814453125 +95069 -0.188720703125 +95070 -0.3143310546875 +95071 -0.320587158203125 +95072 -0.36785888671875 +95073 -0.375335693359375 +95074 -0.36248779296875 +95075 -0.37554931640625 +95076 -0.343536376953125 +95077 -0.360565185546875 +95078 -0.3018798828125 +95079 -0.322479248046875 +95080 -0.231414794921875 +95081 -0.256134033203125 +95082 -0.117645263671875 +95083 -0.149200439453125 +95084 0.007049560546875 +95085 -0.030426025390625 +95086 0.087982177734375 +95087 0.0518798828125 +95088 0.13946533203125 +95089 0.1094970703125 +95090 0.17425537109375 +95091 0.152862548828125 +95092 0.188201904296875 +95093 0.1776123046875 +95094 0.171234130859375 +95095 0.174285888671875 +95096 0.118438720703125 +95097 0.138031005859375 +95098 0.05706787109375 +95099 0.092132568359375 +95100 -0.010711669921875 +95101 0.0380859375 +95102 -0.0914306640625 +95103 -0.02996826171875 +95104 -0.162322998046875 +95105 -0.09222412109375 +95106 -0.194549560546875 +95107 -0.123443603515625 +95108 -0.1492919921875 +95109 -0.08953857421875 +95110 -0.02166748046875 +95111 0.01409912109375 +95112 0.124053955078125 +95113 0.131927490234375 +95114 0.211151123046875 +95115 0.1976318359375 +95116 0.240447998046875 +95117 0.2125244140625 +95118 0.242218017578125 +95119 0.20355224609375 +95120 0.2257080078125 +95121 0.17938232421875 +95122 0.194366455078125 +95123 0.143524169921875 +95124 0.115509033203125 +95125 0.067901611328125 +95126 0.0128173828125 +95127 -0.0264892578125 +95128 -0.053802490234375 +95129 -0.087249755859375 +95130 -0.110626220703125 +95131 -0.137176513671875 +95132 -0.199493408203125 +95133 -0.21282958984375 +95134 -0.29437255859375 +95135 -0.291656494140625 +95136 -0.33221435546875 +95137 -0.31890869140625 +95138 -0.27972412109375 +95139 -0.265960693359375 +95140 -0.185333251953125 +95141 -0.175506591796875 +95142 -0.128204345703125 +95143 -0.11700439453125 +95144 -0.115692138671875 +95145 -0.09735107421875 +95146 -0.116455078125 +95147 -0.0897216796875 +95148 -0.105926513671875 +95149 -0.0731201171875 +95150 -0.053955078125 +95151 -0.021636962890625 +95152 0.048797607421875 +95153 0.07257080078125 +95154 0.157318115234375 +95155 0.1700439453125 +95156 0.212005615234375 +95157 0.21868896484375 +95158 0.218475341796875 +95159 0.223419189453125 +95160 0.23724365234375 +95161 0.23712158203125 +95162 0.30535888671875 +95163 0.29229736328125 +95164 0.38128662109375 +95165 0.35296630859375 +95166 0.404449462890625 +95167 0.36663818359375 +95168 0.3944091796875 +95169 0.35076904296875 +95170 0.3885498046875 +95171 0.338348388671875 +95172 0.362640380859375 +95173 0.308685302734375 +95174 0.27362060546875 +95175 0.224609375 +95176 0.11712646484375 +95177 0.0826416015625 +95178 -0.054901123046875 +95179 -0.071624755859375 +95180 -0.19085693359375 +95181 -0.1929931640625 +95182 -0.28570556640625 +95183 -0.2769775390625 +95184 -0.339263916015625 +95185 -0.32342529296875 +95186 -0.3775634765625 +95187 -0.355072021484375 +95188 -0.445709228515625 +95189 -0.411376953125 +95190 -0.535064697265625 +95191 -0.485015869140625 +95192 -0.629058837890625 +95193 -0.56182861328125 +95194 -0.697601318359375 +95195 -0.615875244140625 +95196 -0.70391845703125 +95197 -0.615386962890625 +95198 -0.6424560546875 +95199 -0.555877685546875 +95200 -0.491241455078125 +95201 -0.41851806640625 +95202 -0.265716552734375 +95203 -0.217010498046875 +95204 -0.023712158203125 +95205 -0.0020751953125 +95206 0.201751708984375 +95207 0.197296142578125 +95208 0.375823974609375 +95209 0.350616455078125 +95210 0.485076904296875 +95211 0.446136474609375 +95212 0.56884765625 +95213 0.518157958984375 +95214 0.634765625 +95215 0.57342529296875 +95216 0.63763427734375 +95217 0.572723388671875 +95218 0.5660400390625 +95219 0.50628662109375 +95220 0.4720458984375 +95221 0.419708251953125 +95222 0.40692138671875 +95223 0.35797119140625 +95224 0.3778076171875 +95225 0.327606201171875 +95226 0.376953125 +95227 0.322113037109375 +95228 0.371978759765625 +95229 0.31353759765625 +95230 0.313140869140625 +95231 0.25872802734375 +95232 0.184417724609375 +95233 0.143646240234375 +95234 0.011199951171875 +95235 -0.009674072265625 +95236 -0.171051025390625 +95237 -0.1700439453125 +95238 -0.33740234375 +95239 -0.31524658203125 +95240 -0.47198486328125 +95241 -0.4312744140625 +95242 -0.560394287109375 +95243 -0.505462646484375 +95244 -0.58056640625 +95245 -0.518218994140625 +95246 -0.54754638671875 +95247 -0.483428955078125 +95248 -0.508575439453125 +95249 -0.444091796875 +95250 -0.459503173828125 +95251 -0.396636962890625 +95252 -0.394378662109375 +95253 -0.3358154296875 +95254 -0.35260009765625 +95255 -0.297332763671875 +95256 -0.31170654296875 +95257 -0.260833740234375 +95258 -0.197418212890625 +95259 -0.159149169921875 +95260 -0.007965087890625 +95261 0.00946044921875 +95262 0.207489013671875 +95263 0.20074462890625 +95264 0.409210205078125 +95265 0.37896728515625 +95266 0.57208251953125 +95267 0.52166748046875 +95268 0.66595458984375 +95269 0.60186767578125 +95270 0.65875244140625 +95271 0.5908203125 +95272 0.56744384765625 +95273 0.504119873046875 +95274 0.431396484375 +95275 0.3775634765625 +95276 0.29443359375 +95277 0.2509765625 +95278 0.182464599609375 +95279 0.14788818359375 +95280 0.06365966796875 +95281 0.03961181640625 +95282 -0.075958251953125 +95283 -0.086456298828125 +95284 -0.189422607421875 +95285 -0.18792724609375 +95286 -0.271942138671875 +95287 -0.26055908203125 +95288 -0.342529296875 +95289 -0.3216552734375 +95290 -0.364166259765625 +95291 -0.337921142578125 +95292 -0.327239990234375 +95293 -0.3009033203125 +95294 -0.2769775390625 +95295 -0.251678466796875 +95296 -0.253692626953125 +95297 -0.22686767578125 +95298 -0.24365234375 +95299 -0.214263916015625 +95300 -0.1983642578125 +95301 -0.17022705078125 +95302 -0.116241455078125 +95303 -0.093505859375 +95304 -0.036834716796875 +95305 -0.019927978515625 +95306 0.034881591796875 +95307 0.0458984375 +95308 0.09124755859375 +95309 0.0970458984375 +95310 0.10888671875 +95311 0.1124267578125 +95312 0.125518798828125 +95313 0.126129150390625 +95314 0.15771484375 +95315 0.15325927734375 +95316 0.17828369140625 +95317 0.1693115234375 +95318 0.17108154296875 +95319 0.15985107421875 +95320 0.129974365234375 +95321 0.11956787109375 +95322 0.082427978515625 +95323 0.073455810546875 +95324 0.027679443359375 +95325 0.02099609375 +95326 -0.065643310546875 +95327 -0.066009521484375 +95328 -0.15936279296875 +95329 -0.15289306640625 +95330 -0.21307373046875 +95331 -0.20306396484375 +95332 -0.234649658203125 +95333 -0.22357177734375 +95334 -0.2001953125 +95335 -0.192779541015625 +95336 -0.119171142578125 +95337 -0.119232177734375 +95338 -0.024749755859375 +95339 -0.032958984375 +95340 0.085784912109375 +95341 0.06842041015625 +95342 0.178131103515625 +95343 0.15380859375 +95344 0.215576171875 +95345 0.189910888671875 +95346 0.211456298828125 +95347 0.188629150390625 +95348 0.17523193359375 +95349 0.15838623046875 +95350 0.128753662109375 +95351 0.118804931640625 +95352 0.1019287109375 +95353 0.0968017578125 +95354 0.0743408203125 +95355 0.07379150390625 +95356 0.04327392578125 +95357 0.047210693359375 +95358 0.038177490234375 +95359 0.043609619140625 +95360 0.076263427734375 +95361 0.078521728515625 +95362 0.14105224609375 +95363 0.137054443359375 +95364 0.186431884765625 +95365 0.177520751953125 +95366 0.188812255859375 +95367 0.17864990234375 +95368 0.1390380859375 +95369 0.1322021484375 +95370 0.041778564453125 +95371 0.04254150390625 +95372 -0.079437255859375 +95373 -0.0689697265625 +95374 -0.219390869140625 +95375 -0.197509765625 +95376 -0.367828369140625 +95377 -0.33367919921875 +95378 -0.494873046875 +95379 -0.450408935546875 +95380 -0.556243896484375 +95381 -0.507537841796875 +95382 -0.508697509765625 +95383 -0.465911865234375 +95384 -0.3756103515625 +95385 -0.3465576171875 +95386 -0.218902587890625 +95387 -0.2054443359375 +95388 -0.063751220703125 +95389 -0.0653076171875 +95390 0.091552734375 +95391 0.07537841796875 +95392 0.23602294921875 +95393 0.2066650390625 +95394 0.342987060546875 +95395 0.30438232421875 +95396 0.39520263671875 +95397 0.352874755859375 +95398 0.389373779296875 +95399 0.34912109375 +95400 0.324249267578125 +95401 0.291900634765625 +95402 0.224090576171875 +95403 0.203033447265625 +95404 0.124267578125 +95405 0.114410400390625 +95406 0.037078857421875 +95407 0.037017822265625 +95408 -0.010101318359375 +95409 -0.00445556640625 +95410 -0.019439697265625 +95411 -0.011993408203125 +95412 -0.022796630859375 +95413 -0.014434814453125 +95414 -0.001556396484375 +95415 0.004974365234375 +95416 0.056304931640625 +95417 0.05712890625 +95418 0.106719970703125 +95419 0.102203369140625 +95420 0.096893310546875 +95421 0.092529296875 +95422 0.042694091796875 +95423 0.04248046875 +95424 -0.018035888671875 +95425 -0.013671875 +95426 -0.07586669921875 +95427 -0.067291259765625 +95428 -0.11944580078125 +95429 -0.108062744140625 +95430 -0.15972900390625 +95431 -0.145843505859375 +95432 -0.202606201171875 +95433 -0.18585205078125 +95434 -0.24859619140625 +95435 -0.228485107421875 +95436 -0.30517578125 +95437 -0.280426025390625 +95438 -0.36212158203125 +95439 -0.332427978515625 +95440 -0.39141845703125 +95441 -0.359130859375 +95442 -0.35528564453125 +95443 -0.32635498046875 +95444 -0.249969482421875 +95445 -0.230743408203125 +95446 -0.092864990234375 +95447 -0.088104248046875 +95448 0.08905029296875 +95449 0.077178955078125 +95450 0.2352294921875 +95451 0.2103271484375 +95452 0.318817138671875 +95453 0.287017822265625 +95454 0.358642578125 +95455 0.32415771484375 +95456 0.347747802734375 +95457 0.3154296875 +95458 0.28564453125 +95459 0.260345458984375 +95460 0.223175048828125 +95461 0.204803466796875 +95462 0.196746826171875 +95463 0.181640625 +95464 0.179840087890625 +95465 0.1668701171875 +95466 0.155548095703125 +95467 0.145172119140625 +95468 0.151214599609375 +95469 0.141265869140625 +95470 0.156951904296875 +95471 0.146209716796875 +95472 0.13177490234375 +95473 0.122955322265625 +95474 0.100799560546875 +95475 0.094268798828125 +95476 0.087127685546875 +95477 0.0810546875 +95478 0.05487060546875 +95479 0.050933837890625 +95480 -0.009002685546875 +95481 -0.007781982421875 +95482 -0.10400390625 +95483 -0.0946044921875 +95484 -0.229400634765625 +95485 -0.2088623046875 +95486 -0.35552978515625 +95487 -0.32366943359375 +95488 -0.441925048828125 +95489 -0.402587890625 +95490 -0.473846435546875 +95491 -0.4326171875 +95492 -0.464813232421875 +95493 -0.426055908203125 +95494 -0.419097900390625 +95495 -0.386260986328125 +95496 -0.334320068359375 +95497 -0.31048583984375 +95498 -0.227935791015625 +95499 -0.214569091796875 +95500 -0.12347412109375 +95501 -0.120208740234375 +95502 -0.02764892578125 +95503 -0.03338623046875 +95504 0.077667236328125 +95505 0.063079833984375 +95506 0.2132568359375 +95507 0.188720703125 +95508 0.38885498046875 +95509 0.352691650390625 +95510 0.582794189453125 +95511 0.53466796875 +95512 0.734039306640625 +95513 0.677398681640625 +95514 0.800140380859375 +95515 0.7410888671875 +95516 0.7783203125 +95517 0.72296142578125 +95518 0.6651611328125 +95519 0.619659423828125 +95520 0.45965576171875 +95521 0.4300537109375 +95522 0.199188232421875 +95523 0.18896484375 +95524 -0.050689697265625 +95525 -0.04241943359375 +95526 -0.23297119140625 +95527 -0.21087646484375 +95528 -0.33013916015625 +95529 -0.300140380859375 +95530 -0.368408203125 +95531 -0.33477783203125 +95532 -0.378936767578125 +95533 -0.344024658203125 +95534 -0.376983642578125 +95535 -0.342193603515625 +95536 -0.37969970703125 +95537 -0.345306396484375 +95538 -0.391510009765625 +95539 -0.357452392578125 +95540 -0.385345458984375 +95541 -0.353271484375 +95542 -0.3419189453125 +95543 -0.314605712890625 +95544 -0.28289794921875 +95545 -0.2615966796875 +95546 -0.251617431640625 +95547 -0.234649658203125 +95548 -0.266143798828125 +95549 -0.25054931640625 +95550 -0.273345947265625 +95551 -0.25946044921875 +95552 -0.216796875 +95553 -0.20843505859375 +95554 -0.128265380859375 +95555 -0.127105712890625 +95556 -0.068145751953125 +95557 -0.07196044921875 +95558 -0.0430908203125 +95559 -0.049163818359375 +95560 -0.024444580078125 +95561 -0.0318603515625 +95562 0.020721435546875 +95563 0.010772705078125 +95564 0.124481201171875 +95565 0.108734130859375 +95566 0.25787353515625 +95567 0.23480224609375 +95568 0.379119873046875 +95569 0.349822998046875 +95570 0.47991943359375 +95571 0.445953369140625 +95572 0.5281982421875 +95573 0.4930419921875 +95574 0.511138916015625 +95575 0.47900390625 +95576 0.456207275390625 +95577 0.429443359375 +95578 0.407470703125 +95579 0.385498046875 +95580 0.383758544921875 +95581 0.36468505859375 +95582 0.35687255859375 +95583 0.340576171875 +95584 0.31182861328125 +95585 0.299102783203125 +95586 0.250885009765625 +95587 0.2423095703125 +95588 0.1654052734375 +95589 0.162139892578125 +95590 0.035247802734375 +95591 0.03973388671875 +95592 -0.142059326171875 +95593 -0.127166748046875 +95594 -0.33563232421875 +95595 -0.3095703125 +95596 -0.5345458984375 +95597 -0.4971923828125 +95598 -0.72186279296875 +95599 -0.674072265625 +95600 -0.836669921875 +95601 -0.783111572265625 +95602 -0.8326416015625 +95603 -0.7808837890625 +95604 -0.7296142578125 +95605 -0.685882568359375 +95606 -0.582550048828125 +95607 -0.549468994140625 +95608 -0.440093994140625 +95609 -0.417083740234375 +95610 -0.324310302734375 +95611 -0.30938720703125 +95612 -0.20147705078125 +95613 -0.194732666015625 +95614 -0.044647216796875 +95615 -0.04791259765625 +95616 0.103973388671875 +95617 0.091583251953125 +95618 0.202392578125 +95619 0.18438720703125 +95620 0.264495849609375 +95621 0.243438720703125 +95622 0.338897705078125 +95623 0.314239501953125 +95624 0.443817138671875 +95625 0.413726806640625 +95626 0.545074462890625 +95627 0.509857177734375 +95628 0.6173095703125 +95629 0.57879638671875 +95630 0.6524658203125 +95631 0.612945556640625 +95632 0.66339111328125 +95633 0.624237060546875 +95634 0.6561279296875 +95635 0.6182861328125 +95636 0.606781005859375 +95637 0.572662353515625 +95638 0.501190185546875 +95639 0.47412109375 +95640 0.352783203125 +95641 0.335174560546875 +95642 0.176544189453125 +95643 0.169921875 +95644 -0.034820556640625 +95645 -0.0284423828125 +95646 -0.258209228515625 +95647 -0.23828125 +95648 -0.44244384765625 +95649 -0.411651611328125 +95650 -0.5753173828125 +95651 -0.53704833984375 +95652 -0.65203857421875 +95653 -0.60992431640625 +95654 -0.641632080078125 +95655 -0.601226806640625 +95656 -0.562164306640625 +95657 -0.52783203125 +95658 -0.458038330078125 +95659 -0.431243896484375 +95660 -0.350555419921875 +95661 -0.331329345703125 +95662 -0.260528564453125 +95663 -0.24755859375 +95664 -0.192108154296875 +95665 -0.183807373046875 +95666 -0.141937255859375 +95667 -0.13690185546875 +95668 -0.1021728515625 +95669 -0.099517822265625 +95670 -0.062896728515625 +95671 -0.0623779296875 +95672 -0.011932373046875 +95673 -0.01409912109375 +95674 0.062835693359375 +95675 0.056610107421875 +95676 0.148712158203125 +95677 0.137847900390625 +95678 0.241729736328125 +95679 0.225799560546875 +95680 0.34912109375 +95681 0.32720947265625 +95682 0.457305908203125 +95683 0.4293212890625 +95684 0.54388427734375 +95685 0.5111083984375 +95686 0.5728759765625 +95687 0.53887939453125 +95688 0.506591796875 +95689 0.477294921875 +95690 0.351226806640625 +95691 0.3321533203125 +95692 0.146514892578125 +95693 0.140625 +95694 -0.05523681640625 +95695 -0.048309326171875 +95696 -0.21624755859375 +95697 -0.19927978515625 +95698 -0.334930419921875 +95699 -0.310760498046875 +95700 -0.402984619140625 +95701 -0.375 +95702 -0.4412841796875 +95703 -0.4114990234375 +95704 -0.49578857421875 +95705 -0.463226318359375 +95706 -0.5601806640625 +95707 -0.52423095703125 +95708 -0.600738525390625 +95709 -0.56292724609375 +95710 -0.584228515625 +95711 -0.548126220703125 +95712 -0.47930908203125 +95713 -0.450469970703125 +95714 -0.27935791015625 +95715 -0.263763427734375 +95716 -0.0089111328125 +95717 -0.01092529296875 +95718 0.268798828125 +95719 0.24884033203125 +95720 0.482818603515625 +95721 0.44915771484375 +95722 0.60369873046875 +95723 0.562469482421875 +95724 0.650421142578125 +95725 0.60650634765625 +95726 0.66400146484375 +95727 0.61962890625 +95728 0.6414794921875 +95729 0.599029541015625 +95730 0.572540283203125 +95731 0.5350341796875 +95732 0.498138427734375 +95733 0.465972900390625 +95734 0.439453125 +95735 0.41162109375 +95736 0.375518798828125 +95737 0.352325439453125 +95738 0.274505615234375 +95739 0.258270263671875 +95740 0.1087646484375 +95741 0.103546142578125 +95742 -0.099395751953125 +95743 -0.09100341796875 +95744 -0.3182373046875 +95745 -0.296142578125 +95746 -0.5489501953125 +95747 -0.51385498046875 +95748 -0.7738037109375 +95749 -0.727325439453125 +95750 -0.86383056640625 +95751 -0.857879638671875 +95752 -0.870391845703125 +95753 -0.8656005859375 +95754 -0.86895751953125 +95755 -0.865631103515625 +95756 -0.861053466796875 +95757 -0.859344482421875 +95758 -0.765869140625 +95759 -0.7667236328125 +95760 -0.5301513671875 +95761 -0.548583984375 +95762 -0.214691162109375 +95763 -0.251129150390625 +95764 0.137359619140625 +95765 0.084320068359375 +95766 0.474822998046875 +95767 0.408416748046875 +95768 0.76239013671875 +95769 0.68707275390625 +95770 0.867462158203125 +95771 0.85882568359375 +95772 0.870361328125 +95773 0.870361328125 +95774 0.86480712890625 +95775 0.870361328125 +95776 0.831817626953125 +95777 0.862701416015625 +95778 0.677581787109375 +95779 0.816070556640625 +95780 0.495880126953125 +95781 0.665863037109375 +95782 0.30767822265625 +95783 0.498504638671875 +95784 0.116180419921875 +95785 0.316619873046875 +95786 -0.110748291015625 +95787 0.089202880859375 +95788 -0.381805419921875 +95789 -0.19140625 +95790 -0.6572265625 +95791 -0.485443115234375 +95792 -0.857421875 +95793 -0.737091064453125 +95794 -0.870391845703125 +95795 -0.860260009765625 +95796 -0.870391845703125 +95797 -0.869537353515625 +95798 -0.86444091796875 +95799 -0.870391845703125 +95800 -0.85723876953125 +95801 -0.86932373046875 +95802 -0.790008544921875 +95803 -0.864837646484375 +95804 -0.62847900390625 +95805 -0.826568603515625 +95806 -0.3956298828125 +95807 -0.622161865234375 +95808 -0.126708984375 +95809 -0.369171142578125 +95810 0.150115966796875 +95811 -0.0948486328125 +95812 0.424041748046875 +95813 0.1895751953125 +95814 0.670623779296875 +95815 0.459014892578125 +95816 0.854522705078125 +95817 0.677703857421875 +95818 0.866485595703125 +95819 0.830902099609375 +95820 0.86920166015625 +95821 0.86016845703125 +95822 0.8653564453125 +95823 0.862213134765625 +95824 0.857147216796875 +95825 0.85986328125 +95826 0.766845703125 +95827 0.84197998046875 +95828 0.628509521484375 +95829 0.748138427734375 +95830 0.462127685546875 +95831 0.61834716796875 +95832 0.297210693359375 +95833 0.479736328125 +95834 0.14862060546875 +95835 0.3458251953125 +95836 -0.00537109375 +95837 0.19537353515625 +95838 -0.15753173828125 +95839 0.0357666015625 +95840 -0.31304931640625 +95841 -0.136993408203125 +95842 -0.48876953125 +95843 -0.337738037109375 +95844 -0.6416015625 +95845 -0.5228271484375 +95846 -0.751373291015625 +95847 -0.67047119140625 +95848 -0.84619140625 +95849 -0.805572509765625 +95850 -0.861297607421875 +95851 -0.86126708984375 +95852 -0.863250732421875 +95853 -0.8675537109375 +95854 -0.856597900390625 +95855 -0.86492919921875 +95856 -0.7498779296875 +95857 -0.854949951171875 +95858 -0.624542236328125 +95859 -0.757598876953125 +95860 -0.47808837890625 +95861 -0.627227783203125 +95862 -0.253387451171875 +95863 -0.41180419921875 +95864 0.003692626953125 +95865 -0.155853271484375 +95866 0.2257080078125 +95867 0.07464599609375 +95868 0.427154541015625 +95869 0.2926025390625 +95870 0.643218994140625 +95871 0.5306396484375 +95872 0.855926513671875 +95873 0.78106689453125 +95874 0.870361328125 +95875 0.869232177734375 +95876 0.870361328125 +95877 0.870361328125 +95878 0.862762451171875 +95879 0.8638916015625 +95880 0.79669189453125 +95881 0.817047119140625 +95882 0.595794677734375 +95883 0.6256103515625 +95884 0.362152099609375 +95885 0.39971923828125 +95886 0.1270751953125 +95887 0.169769287109375 +95888 -0.086944580078125 +95889 -0.042266845703125 +95890 -0.2784423828125 +95891 -0.23468017578125 +95892 -0.484832763671875 +95893 -0.443206787109375 +95894 -0.729583740234375 +95895 -0.6900634765625 +95896 -0.86688232421875 +95897 -0.862884521484375 +95898 -0.870391845703125 +95899 -0.870391845703125 +95900 -0.86859130859375 +95901 -0.870391845703125 +95902 -0.86279296875 +95903 -0.8662109375 +95904 -0.817962646484375 +95905 -0.8553466796875 +95906 -0.6116943359375 +95907 -0.667633056640625 +95908 -0.3128662109375 +95909 -0.379302978515625 +95910 0.039398193359375 +95911 -0.0350341796875 +95912 0.422821044921875 +95913 0.34332275390625 +95914 0.805145263671875 +95915 0.723968505859375 +95916 0.870361328125 +95917 0.870361328125 +95918 0.870361328125 +95919 0.870361328125 +95920 0.860015869140625 +95921 0.86016845703125 +95922 0.727935791015625 +95923 0.7315673828125 +95924 0.48114013671875 +95925 0.48797607421875 +95926 0.2059326171875 +95927 0.215789794921875 +95928 -0.06103515625 +95929 -0.04913330078125 +95930 -0.29913330078125 +95931 -0.2864990234375 +95932 -0.516204833984375 +95933 -0.503509521484375 +95934 -0.7252197265625 +95935 -0.712310791015625 +95936 -0.85980224609375 +95937 -0.8583984375 +95938 -0.870391845703125 +95939 -0.870391845703125 +95940 -0.870391845703125 +95941 -0.870391845703125 +95942 -0.858062744140625 +95943 -0.8582763671875 +95944 -0.673004150390625 +95945 -0.6783447265625 +95946 -0.42694091796875 +95947 -0.435394287109375 +95948 -0.2100830078125 +95949 -0.219696044921875 +95950 -0.0362548828125 +95951 -0.044921875 +95952 0.10943603515625 +95953 0.10296630859375 +95954 0.23516845703125 +95955 0.23150634765625 +95956 0.373687744140625 +95957 0.37200927734375 +95958 0.517791748046875 +95959 0.51715087890625 +95960 0.602783203125 +95961 0.604034423828125 +95962 0.635711669921875 +95963 0.639312744140625 +95964 0.655181884765625 +95965 0.66015625 +95966 0.65948486328125 +95967 0.66485595703125 +95968 0.651275634765625 +95969 0.655975341796875 +95970 0.61846923828125 +95971 0.62188720703125 +95972 0.53753662109375 +95973 0.540008544921875 +95974 0.404144287109375 +95975 0.4063720703125 +95976 0.22186279296875 +95977 0.224700927734375 +95978 0.003997802734375 +95979 0.008209228515625 +95980 -0.22100830078125 +95981 -0.21527099609375 +95982 -0.42449951171875 +95983 -0.417724609375 +95984 -0.579833984375 +95985 -0.57305908203125 +95986 -0.641876220703125 +95987 -0.637298583984375 +95988 -0.6177978515625 +95989 -0.617156982421875 +95990 -0.575531005859375 +95991 -0.578277587890625 +95992 -0.526336669921875 +95993 -0.531463623046875 +95994 -0.42645263671875 +95995 -0.43438720703125 +95996 -0.2581787109375 +95997 -0.2698974609375 +95998 -0.068695068359375 +95999 -0.083831787109375 +96000 0.09222412109375 +96001 0.075958251953125 +96002 0.232147216796875 +96003 0.2171630859375 +96004 0.3509521484375 +96005 0.3388671875 +96006 0.410064697265625 +96007 0.401947021484375 +96008 0.372955322265625 +96009 0.369384765625 +96010 0.2554931640625 +96011 0.256622314453125 +96012 0.10711669921875 +96013 0.11273193359375 +96014 -0.052886962890625 +96015 -0.0433349609375 +96016 -0.186279296875 +96017 -0.173553466796875 +96018 -0.23291015625 +96019 -0.21795654296875 +96020 -0.209442138671875 +96021 -0.19329833984375 +96022 -0.174163818359375 +96023 -0.15789794921875 +96024 -0.126739501953125 +96025 -0.111358642578125 +96026 -0.048126220703125 +96027 -0.0345458984375 +96028 0.0426025390625 +96029 0.0535888671875 +96030 0.10748291015625 +96031 0.11529541015625 +96032 0.1409912109375 +96033 0.145233154296875 +96034 0.19708251953125 +96035 0.197601318359375 +96036 0.273651123046875 +96037 0.270538330078125 +96038 0.31768798828125 +96039 0.311248779296875 +96040 0.341094970703125 +96041 0.331787109375 +96042 0.368011474609375 +96043 0.356414794921875 +96044 0.37249755859375 +96045 0.359283447265625 +96046 0.30072021484375 +96047 0.286651611328125 +96048 0.1517333984375 +96049 0.1375732421875 +96050 -0.01470947265625 +96051 -0.0281982421875 +96052 -0.1883544921875 +96053 -0.200439453125 +96054 -0.372711181640625 +96055 -0.38275146484375 +96056 -0.51397705078125 +96057 -0.521484375 +96058 -0.57177734375 +96059 -0.576416015625 +96060 -0.53948974609375 +96061 -0.541107177734375 +96062 -0.43511962890625 +96063 -0.4337158203125 +96064 -0.2962646484375 +96065 -0.292022705078125 +96066 -0.161102294921875 +96067 -0.154327392578125 +96068 -0.0435791015625 +96069 -0.034698486328125 +96070 0.060394287109375 +96071 0.070831298828125 +96072 0.13665771484375 +96073 0.148040771484375 +96074 0.170135498046875 +96075 0.18182373046875 +96076 0.16552734375 +96077 0.1768798828125 +96078 0.15728759765625 +96079 0.16766357421875 +96080 0.150787353515625 +96081 0.15966796875 +96082 0.12200927734375 +96083 0.12896728515625 +96084 0.080108642578125 +96085 0.084808349609375 +96086 0.05126953125 +96087 0.05352783203125 +96088 0.062896728515625 +96089 0.06268310546875 +96090 0.09271240234375 +96091 0.090118408203125 +96092 0.092987060546875 +96093 0.088226318359375 +96094 0.07855224609375 +96095 0.071929931640625 +96096 0.06427001953125 +96097 0.05621337890625 +96098 0.0347900390625 +96099 0.025787353515625 +96100 -0.01171875 +96101 -0.021148681640625 +96102 -0.056060791015625 +96103 -0.06536865234375 +96104 -0.055511474609375 +96105 -0.064208984375 +96106 -0.010467529296875 +96107 -0.018096923828125 +96108 0.02508544921875 +96109 0.0189208984375 +96110 0.025665283203125 +96111 0.021270751953125 +96112 0.017333984375 +96113 0.014923095703125 +96114 0.00189208984375 +96115 0.00152587890625 +96116 -0.03173828125 +96117 -0.03009033203125 +96118 -0.071502685546875 +96119 -0.0679931640625 +96120 -0.13543701171875 +96121 -0.13031005859375 +96122 -0.219970703125 +96123 -0.21356201171875 +96124 -0.300506591796875 +96125 -0.293182373046875 +96126 -0.376312255859375 +96127 -0.368499755859375 +96128 -0.416107177734375 +96129 -0.408233642578125 +96130 -0.371124267578125 +96131 -0.363616943359375 +96132 -0.242279052734375 +96133 -0.23553466796875 +96134 -0.069732666015625 +96135 -0.0640869140625 +96136 0.125640869140625 +96137 0.129913330078125 +96138 0.31268310546875 +96139 0.31536865234375 +96140 0.45501708984375 +96141 0.456024169921875 +96142 0.554779052734375 +96143 0.554107666015625 +96144 0.61065673828125 +96145 0.6083984375 +96146 0.610931396484375 +96147 0.607269287109375 +96148 0.531463623046875 +96149 0.526641845703125 +96150 0.3883056640625 +96151 0.382598876953125 +96152 0.23468017578125 +96153 0.228424072265625 +96154 0.095245361328125 +96155 0.08880615234375 +96156 -0.00396728515625 +96157 -0.010223388671875 +96158 -0.04852294921875 +96159 -0.05426025390625 +96160 -0.055145263671875 +96161 -0.06005859375 +96162 -0.0758056640625 +96163 -0.07965087890625 +96164 -0.138702392578125 +96165 -0.14129638671875 +96166 -0.209197998046875 +96167 -0.21044921875 +96168 -0.289031982421875 +96169 -0.288909912109375 +96170 -0.37884521484375 +96171 -0.377410888671875 +96172 -0.456329345703125 +96173 -0.45367431640625 +96174 -0.51641845703125 +96175 -0.512725830078125 +96176 -0.519287109375 +96177 -0.514801025390625 +96178 -0.458251953125 +96179 -0.4532470703125 +96180 -0.384796142578125 +96181 -0.379547119140625 +96182 -0.323699951171875 +96183 -0.3184814453125 +96184 -0.269287109375 +96185 -0.264373779296875 +96186 -0.1951904296875 +96187 -0.19085693359375 +96188 -0.100006103515625 +96189 -0.096466064453125 +96190 -0.01055908203125 +96191 -0.007965087890625 +96192 0.1033935546875 +96193 0.10491943359375 +96194 0.24908447265625 +96195 0.249481201171875 +96196 0.373199462890625 +96197 0.372467041015625 +96198 0.45806884765625 +96199 0.456298828125 +96200 0.511474609375 +96201 0.5087890625 +96202 0.565399169921875 +96203 0.561981201171875 +96204 0.61138916015625 +96205 0.607452392578125 +96206 0.5897216796875 +96207 0.58551025390625 +96208 0.4906005859375 +96209 0.486328125 +96210 0.33148193359375 +96211 0.327392578125 +96212 0.147796630859375 +96213 0.14410400390625 +96214 -0.01873779296875 +96215 -0.0218505859375 +96216 -0.140289306640625 +96217 -0.142669677734375 +96218 -0.191986083984375 +96219 -0.193511962890625 +96220 -0.184295654296875 +96221 -0.184906005859375 +96222 -0.161834716796875 +96223 -0.1614990234375 +96224 -0.166595458984375 +96225 -0.16534423828125 +96226 -0.19390869140625 +96227 -0.19183349609375 +96228 -0.22442626953125 +96229 -0.2216796875 +96230 -0.279754638671875 +96231 -0.2764892578125 +96232 -0.3389892578125 +96233 -0.33538818359375 +96234 -0.3543701171875 +96235 -0.35064697265625 +96236 -0.348175048828125 +96237 -0.34454345703125 +96238 -0.32598876953125 +96239 -0.322662353515625 +96240 -0.2581787109375 +96241 -0.255340576171875 +96242 -0.139801025390625 +96243 -0.137603759765625 +96244 0.014617919921875 +96245 0.016082763671875 +96246 0.144378662109375 +96247 0.145050048828125 +96248 0.221038818359375 +96249 0.220916748046875 +96250 0.27069091796875 +96251 0.269805908203125 +96252 0.294036865234375 +96253 0.29248046875 +96254 0.311767578125 +96255 0.309661865234375 +96256 0.33905029296875 +96257 0.33660888671875 +96258 0.359588623046875 +96259 0.357452392578125 +96260 0.35888671875 +96261 0.357574462890625 +96262 0.306671142578125 +96263 0.30548095703125 +96264 0.18170166015625 +96265 0.178985595703125 +96266 0.00775146484375 +96267 0.00238037109375 +96268 -0.16961669921875 +96269 -0.177520751953125 +96270 -0.306640625 +96271 -0.315704345703125 +96272 -0.3609619140625 +96273 -0.368621826171875 +96274 -0.357879638671875 +96275 -0.36260986328125 +96276 -0.341156005859375 +96277 -0.343017578125 +96278 -0.3018798828125 +96279 -0.30078125 +96280 -0.234100341796875 +96281 -0.22979736328125 +96282 -0.123809814453125 +96283 -0.1156005859375 +96284 -0.002349853515625 +96285 0.0093994140625 +96286 0.0772705078125 +96287 0.09051513671875 +96288 0.1287841796875 +96289 0.14202880859375 +96290 0.164459228515625 +96291 0.176727294921875 +96292 0.18011474609375 +96293 0.1904296875 +96294 0.1658935546875 +96295 0.173095703125 +96296 0.116943359375 +96297 0.119842529296875 +96298 0.05950927734375 +96299 0.057952880859375 +96300 -0.004425048828125 +96301 -0.0103759765625 +96302 -0.081298828125 +96303 -0.091644287109375 +96304 -0.149078369140625 +96305 -0.163055419921875 +96306 -0.179901123046875 +96307 -0.19573974609375 +96308 -0.13623046875 +96309 -0.15087890625 +96310 -0.0133056640625 +96311 -0.0235595703125 +96312 0.126739501953125 +96313 0.121978759765625 +96314 0.209686279296875 +96315 0.209014892578125 +96316 0.2364501953125 +96317 0.238372802734375 +96318 0.23638916015625 +96319 0.24029541015625 +96320 0.218597412109375 +96321 0.22406005859375 +96322 0.186492919921875 +96323 0.193084716796875 +96324 0.108551025390625 +96325 0.114654541015625 +96326 0.00775146484375 +96327 0.012420654296875 +96328 -0.057830810546875 +96329 -0.053741455078125 +96330 -0.113555908203125 +96331 -0.110107421875 +96332 -0.199951171875 +96333 -0.198577880859375 +96334 -0.29180908203125 +96335 -0.293121337890625 +96336 -0.32806396484375 +96337 -0.3306884765625 +96338 -0.27655029296875 +96339 -0.27801513671875 +96340 -0.184173583984375 +96341 -0.18353271484375 +96342 -0.12762451171875 +96343 -0.12640380859375 +96344 -0.11407470703125 +96345 -0.113983154296875 +96346 -0.11328125 +96347 -0.11492919921875 +96348 -0.1015625 +96349 -0.104644775390625 +96350 -0.049835205078125 +96351 -0.052978515625 +96352 0.05084228515625 +96353 0.0494384765625 +96354 0.156890869140625 +96355 0.157623291015625 +96356 0.2105712890625 +96357 0.21197509765625 +96358 0.217254638671875 +96359 0.218109130859375 +96360 0.23553466796875 +96361 0.236572265625 +96362 0.30126953125 +96363 0.304443359375 +96364 0.374237060546875 +96365 0.380157470703125 +96366 0.395843505859375 +96367 0.403167724609375 +96368 0.38507080078125 +96369 0.393035888671875 +96370 0.378173828125 +96371 0.38714599609375 +96372 0.351806640625 +96373 0.361297607421875 +96374 0.264373779296875 +96375 0.27239990234375 +96376 0.1116943359375 +96377 0.1160888671875 +96378 -0.055877685546875 +96379 -0.055694580078125 +96380 -0.188323974609375 +96381 -0.19134521484375 +96382 -0.28076171875 +96383 -0.285858154296875 +96384 -0.3330078125 +96385 -0.339080810546875 +96386 -0.370208740234375 +96387 -0.3770751953125 +96388 -0.43603515625 +96389 -0.4449462890625 +96390 -0.52215576171875 +96391 -0.534088134765625 +96392 -0.612548828125 +96393 -0.6279296875 +96394 -0.678131103515625 +96395 -0.696380615234375 +96396 -0.683349609375 +96397 -0.70269775390625 +96398 -0.62286376953125 +96399 -0.64129638671875 +96400 -0.4754638671875 +96401 -0.490203857421875 +96402 -0.25616455078125 +96403 -0.264862060546875 +96404 -0.02099609375 +96405 -0.0230712890625 +96406 0.198028564453125 +96407 0.2021484375 +96408 0.36712646484375 +96409 0.3759765625 +96410 0.473297119140625 +96411 0.4849853515625 +96412 0.554595947265625 +96413 0.568511962890625 +96414 0.618408203125 +96415 0.63421630859375 +96416 0.6209716796875 +96417 0.636932373046875 +96418 0.551239013671875 +96419 0.565216064453125 +96420 0.45965576171875 +96421 0.47113037109375 +96422 0.3958740234375 +96423 0.40594482421875 +96424 0.36688232421875 +96425 0.376800537109375 +96426 0.36517333984375 +96427 0.375946044921875 +96428 0.3594970703125 +96429 0.37103271484375 +96430 0.3017578125 +96431 0.31231689453125 +96432 0.17645263671875 +96433 0.183746337890625 +96434 0.008209228515625 +96435 0.010711669921875 +96436 -0.168609619140625 +96437 -0.17132568359375 +96438 -0.329864501953125 +96439 -0.33746337890625 +96440 -0.460174560546875 +96441 -0.471832275390625 +96442 -0.54559326171875 +96443 -0.560028076171875 +96444 -0.5648193359375 +96445 -0.58001708984375 +96446 -0.53240966796875 +96447 -0.546844482421875 +96448 -0.494140625 +96449 -0.507781982421875 +96450 -0.44598388671875 +96451 -0.458648681640625 +96452 -0.38226318359375 +96453 -0.393524169921875 +96454 -0.34112548828125 +96455 -0.351806640625 +96456 -0.30084228515625 +96457 -0.311004638671875 +96458 -0.1895751953125 +96459 -0.19683837890625 +96460 -0.005645751953125 +96461 -0.007537841796875 +96462 0.203338623046875 +96463 0.207733154296875 +96464 0.398834228515625 +96465 0.409271240234375 +96466 0.556549072265625 +96467 0.57196044921875 +96468 0.647308349609375 +96469 0.6656494140625 +96470 0.64007568359375 +96471 0.65826416015625 +96472 0.551300048828125 +96473 0.566802978515625 +96474 0.41912841796875 +96475 0.430633544921875 +96476 0.2860107421875 +96477 0.2935791015625 +96478 0.17706298828125 +96479 0.18157958984375 +96480 0.061492919921875 +96481 0.062774658203125 +96482 -0.074188232421875 +96483 -0.076812744140625 +96484 -0.18450927734375 +96485 -0.190185546875 +96486 -0.2647705078125 +96487 -0.2725830078125 +96488 -0.3333740234375 +96489 -0.343017578125 +96490 -0.354522705078125 +96491 -0.364501953125 +96492 -0.31890869140625 +96493 -0.327423095703125 +96494 -0.270263671875 +96495 -0.277008056640625 +96496 -0.24761962890625 +96497 -0.253570556640625 +96498 -0.2376708984375 +96499 -0.243377685546875 +96500 -0.19354248046875 +96501 -0.197967529296875 +96502 -0.11370849609375 +96503 -0.115753173828125 +96504 -0.036407470703125 +96505 -0.036285400390625 +96506 0.033477783203125 +96507 0.03546142578125 +96508 0.0885009765625 +96509 0.091827392578125 +96510 0.10601806640625 +96511 0.10943603515625 +96512 0.12213134765625 +96513 0.126007080078125 +96514 0.152740478515625 +96515 0.15814208984375 +96516 0.1719970703125 +96517 0.178619384765625 +96518 0.1649169921875 +96519 0.171295166015625 +96520 0.12591552734375 +96521 0.13006591796875 +96522 0.080780029296875 +96523 0.0823974609375 +96524 0.02886962890625 +96525 0.02752685546875 +96526 -0.059173583984375 +96527 -0.06591796875 +96528 -0.147552490234375 +96529 -0.15972900390625 +96530 -0.198455810546875 +96531 -0.2135009765625 +96532 -0.219207763671875 +96533 -0.235107421875 +96534 -0.18743896484375 +96535 -0.200653076171875 +96536 -0.11199951171875 +96537 -0.119598388671875 +96538 -0.023956298828125 +96539 -0.025115966796875 +96540 0.0792236328125 +96541 0.085479736328125 +96542 0.16546630859375 +96543 0.17791748046875 +96544 0.200408935546875 +96545 0.2154541015625 +96546 0.196533203125 +96547 0.21142578125 +96548 0.16265869140625 +96549 0.17529296875 +96550 0.1192626953125 +96551 0.12890625 +96552 0.094329833984375 +96553 0.1021728515625 +96554 0.068756103515625 +96555 0.074676513671875 +96556 0.03997802734375 +96557 0.043701171875 +96558 0.0355224609375 +96559 0.038665771484375 +96560 0.071502685546875 +96561 0.0767822265625 +96562 0.1324462890625 +96563 0.141571044921875 +96564 0.175201416015625 +96565 0.186920166015625 +96566 0.17767333984375 +96567 0.189239501953125 +96568 0.131256103515625 +96569 0.139373779296875 +96570 0.04034423828125 +96571 0.042022705078125 +96572 -0.07305908203125 +96573 -0.07928466796875 +96574 -0.204071044921875 +96575 -0.219329833984375 +96576 -0.343109130859375 +96577 -0.36785888671875 +96578 -0.462188720703125 +96579 -0.4949951171875 +96580 -0.51983642578125 +96581 -0.55645751953125 +96582 -0.4755859375 +96583 -0.509002685546875 +96584 -0.351287841796875 +96585 -0.3759765625 +96586 -0.20489501953125 +96587 -0.21929931640625 +96588 -0.059967041015625 +96589 -0.06414794921875 +96590 0.085113525390625 +96591 0.091156005859375 +96592 0.2200927734375 +96593 0.23565673828125 +96594 0.32000732421875 +96595 0.3426513671875 +96596 0.368743896484375 +96597 0.3948974609375 +96598 0.36322021484375 +96599 0.38909912109375 +96600 0.302276611328125 +96601 0.324005126953125 +96602 0.208587646484375 +96603 0.223907470703125 +96604 0.115264892578125 +96605 0.1241455078125 +96606 0.0338134765625 +96607 0.037017822265625 +96608 -0.0101318359375 +96609 -0.010101318359375 +96610 -0.018646240234375 +96611 -0.019378662109375 +96612 -0.02154541015625 +96613 -0.022674560546875 +96614 -0.00140380859375 +96615 -0.001373291015625 +96616 0.053009033203125 +96617 0.0565185546875 +96618 0.10040283203125 +96619 0.10693359375 +96620 0.091400146484375 +96621 0.097076416015625 +96622 0.04083251953125 +96623 0.0428466796875 +96624 -0.015899658203125 +96625 -0.017913818359375 +96626 -0.069976806640625 +96627 -0.075775146484375 +96628 -0.11077880859375 +96629 -0.119384765625 +96630 -0.148590087890625 +96631 -0.159698486328125 +96632 -0.188873291015625 +96633 -0.202606201171875 +96634 -0.232086181640625 +96635 -0.248626708984375 +96636 -0.285186767578125 +96637 -0.305206298828125 +96638 -0.338653564453125 +96639 -0.362152099609375 +96640 -0.36627197265625 +96641 -0.391448974609375 +96642 -0.3326416015625 +96643 -0.355316162109375 +96644 -0.234222412109375 +96645 -0.25 +96646 -0.087310791015625 +96647 -0.0928955078125 +96648 0.08282470703125 +96649 0.089019775390625 +96650 0.219573974609375 +96651 0.235198974609375 +96652 0.297760009765625 +96653 0.31878662109375 +96654 0.33502197265625 +96655 0.358612060546875 +96656 0.3248291015625 +96657 0.34771728515625 +96658 0.2667236328125 +96659 0.285614013671875 +96660 0.20831298828125 +96661 0.22314453125 +96662 0.18365478515625 +96663 0.19671630859375 +96664 0.167938232421875 +96665 0.1798095703125 +96666 0.14532470703125 +96667 0.155517578125 +96668 0.141448974609375 +96669 0.15118408203125 +96670 0.147003173828125 +96671 0.15692138671875 +96672 0.12359619140625 +96673 0.131744384765625 +96674 0.0947265625 +96675 0.10076904296875 +96676 0.082000732421875 +96677 0.08709716796875 +96678 0.051849365234375 +96679 0.054840087890625 +96680 -0.007904052734375 +96681 -0.009033203125 +96682 -0.0968017578125 +96683 -0.104034423828125 +96684 -0.214202880859375 +96685 -0.22943115234375 +96686 -0.33233642578125 +96687 -0.355560302734375 +96688 -0.41326904296875 +96689 -0.44195556640625 +96690 -0.4432373046875 +96691 -0.473876953125 +96692 -0.43487548828125 +96693 -0.46484375 +96694 -0.392181396484375 +96695 -0.41912841796875 +96696 -0.31292724609375 +96697 -0.3343505859375 +96698 -0.213409423828125 +96699 -0.22796630859375 +96700 -0.115692138671875 +96701 -0.123504638671875 +96702 -0.026031494140625 +96703 -0.027679443359375 +96704 0.072540283203125 +96705 0.07763671875 +96706 0.199462890625 +96707 0.213226318359375 +96708 0.363861083984375 +96709 0.388824462890625 +96710 0.54541015625 +96711 0.582763671875 +96712 0.68701171875 +96713 0.7340087890625 +96714 0.748931884765625 +96715 0.80010986328125 +96716 0.72857666015625 +96717 0.778289794921875 +96718 0.622711181640625 +96719 0.665130615234375 +96720 0.430419921875 +96721 0.459625244140625 +96722 0.186676025390625 +96723 0.199188232421875 +96724 -0.04718017578125 +96725 -0.0506591796875 +96726 -0.2177734375 +96727 -0.23291015625 +96728 -0.3087158203125 +96729 -0.330078125 +96730 -0.344512939453125 +96731 -0.36834716796875 +96732 -0.3543701171875 +96733 -0.378875732421875 +96734 -0.3525390625 +96735 -0.376922607421875 +96736 -0.355133056640625 +96737 -0.379638671875 +96738 -0.366241455078125 +96739 -0.391448974609375 +96740 -0.36053466796875 +96741 -0.385284423828125 +96742 -0.3199462890625 +96743 -0.34185791015625 +96744 -0.2647705078125 +96745 -0.2828369140625 +96746 -0.235565185546875 +96747 -0.251556396484375 +96748 -0.24920654296875 +96749 -0.266082763671875 +96750 -0.2559814453125 +96751 -0.273284912109375 +96752 -0.20306396484375 +96753 -0.21673583984375 +96754 -0.12017822265625 +96755 -0.128204345703125 +96756 -0.063873291015625 +96757 -0.068084716796875 +96758 -0.040374755859375 +96759 -0.04302978515625 +96760 -0.02288818359375 +96761 -0.024383544921875 +96762 0.019439697265625 +96763 0.020782470703125 +96764 0.116607666015625 +96765 0.124542236328125 +96766 0.24151611328125 +96767 0.2579345703125 +96768 0.3544921875 +96769 0.379150390625 +96770 0.447967529296875 +96771 0.47991943359375 +96772 0.4932861328125 +96773 0.528167724609375 +96774 0.4786376953125 +96775 0.5111083984375 +96776 0.42877197265625 +96777 0.4561767578125 +96778 0.383544921875 +96779 0.407440185546875 +96780 0.36004638671875 +96781 0.38372802734375 +96782 0.332916259765625 +96783 0.356842041015625 +96784 0.288787841796875 +96785 0.311798095703125 +96786 0.229888916015625 +96787 0.2508544921875 +96788 0.148681640625 +96789 0.165374755859375 +96790 0.027191162109375 +96791 0.03521728515625 +96792 -0.1365966796875 +96793 -0.14208984375 +96794 -0.3145751953125 +96795 -0.335662841796875 +96796 -0.4967041015625 +96797 -0.534576416015625 +96798 -0.667572021484375 +96799 -0.721893310546875 +96800 -0.772003173828125 +96801 -0.836669921875 +96802 -0.76812744140625 +96803 -0.8326416015625 +96804 -0.6739501953125 +96805 -0.7296142578125 +96806 -0.5391845703125 +96807 -0.582550048828125 +96808 -0.407958984375 +96809 -0.440093994140625 +96810 -0.30035400390625 +96811 -0.324310302734375 +96812 -0.18609619140625 +96813 -0.20147705078125 +96814 -0.04095458984375 +96815 -0.044647216796875 +96816 0.096710205078125 +96817 0.103973388671875 +96818 0.188751220703125 +96819 0.202392578125 +96820 0.24755859375 +96821 0.264495849609375 +96822 0.31695556640625 +96823 0.338897705078125 +96824 0.41326904296875 +96825 0.443817138671875 +96826 0.505584716796875 +96827 0.545074462890625 +96828 0.5709228515625 +96829 0.6173095703125 +96830 0.60205078125 +96831 0.6524658203125 +96832 0.610626220703125 +96833 0.66339111328125 +96834 0.602203369140625 +96835 0.6561279296875 +96836 0.555267333984375 +96837 0.606781005859375 +96838 0.457183837890625 +96839 0.501190185546875 +96840 0.32025146484375 +96841 0.352783203125 +96842 0.15814208984375 +96843 0.176544189453125 +96844 -0.035552978515625 +96845 -0.034820556640625 +96846 -0.23980712890625 +96847 -0.258209228515625 +96848 -0.40826416015625 +96849 -0.44244384765625 +96850 -0.529754638671875 +96851 -0.5753173828125 +96852 -0.59991455078125 +96853 -0.65203857421875 +96854 -0.590728759765625 +96855 -0.641632080078125 +96856 -0.518524169921875 +96857 -0.562164306640625 +96858 -0.423492431640625 +96859 -0.458038330078125 +96860 -0.32489013671875 +96861 -0.350555419921875 +96862 -0.24163818359375 +96863 -0.260528564453125 +96864 -0.177642822265625 +96865 -0.192108154296875 +96866 -0.1300048828125 +96867 -0.141937255859375 +96868 -0.091766357421875 +96869 -0.1021728515625 +96870 -0.0540771484375 +96871 -0.062896728515625 +96872 -0.006011962890625 +96873 -0.011932373046875 +96874 0.063262939453125 +96875 0.062835693359375 +96876 0.142181396484375 +96877 0.148712158203125 +96878 0.227081298828125 +96879 0.241729736328125 +96880 0.324493408203125 +96881 0.34912109375 +96882 0.422119140625 +96883 0.457305908203125 +96884 0.499725341796875 +96885 0.54388427734375 +96886 0.524871826171875 +96887 0.5728759765625 +96888 0.463531494140625 +96889 0.506591796875 +96890 0.321441650390625 +96891 0.351226806640625 +96892 0.13458251953125 +96893 0.146514892578125 +96894 -0.0496826171875 +96895 -0.05523681640625 +96896 -0.19708251953125 +96897 -0.21624755859375 +96898 -0.3060302734375 +96899 -0.334930419921875 +96900 -0.368988037109375 +96901 -0.402984619140625 +96902 -0.404754638671875 +96903 -0.4412841796875 +96904 -0.454803466796875 +96905 -0.49578857421875 +96906 -0.513397216796875 +96907 -0.5601806640625 +96908 -0.550018310546875 +96909 -0.600738525390625 +96910 -0.53466796875 +96911 -0.584228515625 +96912 -0.43902587890625 +96913 -0.47930908203125 +96914 -0.2572021484375 +96915 -0.27935791015625 +96916 -0.011444091796875 +96917 -0.0089111328125 +96918 0.240997314453125 +96919 0.268798828125 +96920 0.435943603515625 +96921 0.482818603515625 +96922 0.54669189453125 +96923 0.60369873046875 +96924 0.59027099609375 +96925 0.650421142578125 +96926 0.603729248046875 +96927 0.66400146484375 +96928 0.584320068359375 +96929 0.6414794921875 +96930 0.522705078125 +96931 0.572540283203125 +96932 0.455841064453125 +96933 0.498138427734375 +96934 0.402862548828125 +96935 0.439453125 +96936 0.3448486328125 +96937 0.375518798828125 +96938 0.253021240234375 +96939 0.274505615234375 +96940 0.1024169921875 +96941 0.1087646484375 +96942 -0.086761474609375 +96943 -0.099395751953125 +96944 -0.28570556640625 +96945 -0.3182373046875 +96946 -0.495452880859375 +96947 -0.5489501953125 +96948 -0.69989013671875 +96949 -0.7738037109375 +96950 -0.851104736328125 +96951 -0.86383056640625 +96952 -0.861541748046875 +96953 -0.870391845703125 +96954 -0.861602783203125 +96955 -0.86895751953125 +96956 -0.8555908203125 +96957 -0.861053466796875 +96958 -0.738067626953125 +96959 -0.765869140625 +96960 -0.53033447265625 +96961 -0.5301513671875 +96962 -0.247589111328125 +96963 -0.214691162109375 +96964 0.071197509765625 +96965 0.137359619140625 +96966 0.379638671875 +96967 0.474822998046875 +96968 0.64556884765625 +96969 0.76239013671875 +96970 0.844512939453125 +96971 0.867462158203125 +96972 0.867828369140625 +96973 0.870361328125 +96974 0.870361328125 +96975 0.86480712890625 +96976 0.865264892578125 +96977 0.831817626953125 +96978 0.85516357421875 +96979 0.677581787109375 +96980 0.7283935546875 +96981 0.495880126953125 +96982 0.573974609375 +96983 0.30767822265625 +96984 0.4000244140625 +96985 0.116180419921875 +96986 0.177978515625 +96987 -0.110748291015625 +96988 -0.098602294921875 +96989 -0.381805419921875 +96990 -0.39166259765625 +96991 -0.6572265625 +96992 -0.647979736328125 +96993 -0.857421875 +96994 -0.829864501953125 +96995 -0.870391845703125 +96996 -0.86297607421875 +96997 -0.870391845703125 +96998 -0.8682861328125 +96999 -0.86444091796875 +97000 -0.870391845703125 +97001 -0.85723876953125 +97002 -0.86871337890625 +97003 -0.790008544921875 +97004 -0.858123779296875 +97005 -0.62847900390625 +97006 -0.7071533203125 +97007 -0.3956298828125 +97008 -0.474212646484375 +97009 -0.126708984375 +97010 -0.214202880859375 +97011 0.150115966796875 +97012 0.061981201171875 +97013 0.424041748046875 +97014 0.33013916015625 +97015 0.670623779296875 +97016 0.555816650390625 +97017 0.854522705078125 +97018 0.723907470703125 +97019 0.866485595703125 +97020 0.821685791015625 +97021 0.86920166015625 +97022 0.8558349609375 +97023 0.8653564453125 +97024 0.8565673828125 +97025 0.857147216796875 +97026 0.840728759765625 +97027 0.766845703125 +97028 0.77374267578125 +97029 0.628509521484375 +97030 0.66845703125 +97031 0.462127685546875 +97032 0.548797607421875 +97033 0.297210693359375 +97034 0.4268798828125 +97035 0.14862060546875 +97036 0.283782958984375 +97037 -0.00537109375 +97038 0.126739501953125 +97039 -0.15753173828125 +97040 -0.046966552734375 +97041 -0.31304931640625 +97042 -0.249542236328125 +97043 -0.48876953125 +97044 -0.440399169921875 +97045 -0.6416015625 +97046 -0.59857177734375 +97047 -0.751373291015625 +97048 -0.745025634765625 +97049 -0.84619140625 +97050 -0.855987548828125 +97051 -0.861297607421875 +97052 -0.863800048828125 +97053 -0.863250732421875 +97054 -0.863189697265625 +97055 -0.856597900390625 +97056 -0.855438232421875 +97057 -0.7498779296875 +97058 -0.778289794921875 +97059 -0.624542236328125 +97060 -0.661590576171875 +97061 -0.47808837890625 +97062 -0.462982177734375 +97063 -0.253387451171875 +97064 -0.222991943359375 +97065 0.003692626953125 +97066 -0.00164794921875 +97067 0.2257080078125 +97068 0.2117919921875 +97069 0.427154541015625 +97070 0.445648193359375 +97071 0.643218994140625 +97072 0.691864013671875 +97073 0.855926513671875 +97074 0.8594970703125 +97075 0.870361328125 +97076 0.870361328125 +97077 0.870361328125 +97078 0.870361328125 +97079 0.862762451171875 +97080 0.8629150390625 +97081 0.79669189453125 +97082 0.790863037109375 +97083 0.595794677734375 +97084 0.6055908203125 +97085 0.362152099609375 +97086 0.402740478515625 +97087 0.1270751953125 +97088 0.2022705078125 +97089 -0.086944580078125 +97090 0.006622314453125 +97091 -0.2784423828125 +97092 -0.214813232421875 +97093 -0.484832763671875 +97094 -0.4798583984375 +97095 -0.729583740234375 +97096 -0.7462158203125 +97097 -0.86688232421875 +97098 -0.86614990234375 +97099 -0.870391845703125 +97100 -0.870391845703125 +97101 -0.86859130859375 +97102 -0.870147705078125 +97103 -0.86279296875 +97104 -0.863006591796875 +97105 -0.817962646484375 +97106 -0.77215576171875 +97107 -0.6116943359375 +97108 -0.5177001953125 +97109 -0.3128662109375 +97110 -0.203094482421875 +97111 0.039398193359375 +97112 0.15142822265625 +97113 0.422821044921875 +97114 0.5162353515625 +97115 0.805145263671875 +97116 0.83343505859375 +97117 0.870361328125 +97118 0.870361328125 +97119 0.870361328125 +97120 0.870361328125 +97121 0.860015869140625 +97122 0.860992431640625 +97123 0.727935791015625 +97124 0.75042724609375 +97125 0.48114013671875 +97126 0.542449951171875 +97127 0.2059326171875 +97128 0.320953369140625 +97129 -0.06103515625 +97130 0.1038818359375 +97131 -0.29913330078125 +97132 -0.114471435546875 +97133 -0.516204833984375 +97134 -0.343231201171875 +97135 -0.7252197265625 +97136 -0.55914306640625 +97137 -0.85980224609375 +97138 -0.733428955078125 +97139 -0.870391845703125 +97140 -0.844024658203125 +97141 -0.870391845703125 +97142 -0.8544921875 +97143 -0.858062744140625 +97144 -0.769134521484375 +97145 -0.673004150390625 +97146 -0.64306640625 +97147 -0.42694091796875 +97148 -0.52520751953125 +97149 -0.2100830078125 +97150 -0.424163818359375 +97151 -0.0362548828125 +97152 -0.324798583984375 +97153 0.10943603515625 +97154 -0.219085693359375 +97155 0.23516845703125 +97156 -0.078948974609375 +97157 0.373687744140625 +97158 0.087554931640625 +97159 0.517791748046875 +97160 0.221160888671875 +97161 0.602783203125 +97162 0.32427978515625 +97163 0.635711669921875 +97164 0.42608642578125 +97165 0.655181884765625 +97166 0.5201416015625 +97167 0.65948486328125 +97168 0.603668212890625 +97169 0.651275634765625 +97170 0.661163330078125 +97171 0.61846923828125 +97172 0.667572021484375 +97173 0.53753662109375 +97174 0.615203857421875 +97175 0.404144287109375 +97176 0.5040283203125 +97177 0.22186279296875 +97178 0.343505859375 +97179 0.003997802734375 +97180 0.157379150390625 +97181 -0.22100830078125 +97182 -0.02935791015625 +97183 -0.42449951171875 +97184 -0.192413330078125 +97185 -0.579833984375 +97186 -0.2904052734375 +97187 -0.641876220703125 +97188 -0.326690673828125 +97189 -0.6177978515625 +97190 -0.357025146484375 +97191 -0.575531005859375 +97192 -0.387298583984375 +97193 -0.526336669921875 +97194 -0.37518310546875 +97195 -0.42645263671875 +97196 -0.30108642578125 +97197 -0.2581787109375 +97198 -0.202239990234375 +97199 -0.068695068359375 +97200 -0.11859130859375 +97201 0.09222412109375 +97202 -0.040740966796875 +97203 0.232147216796875 +97204 0.033233642578125 +97205 0.3509521484375 +97206 0.07086181640625 +97207 0.410064697265625 +97208 0.040618896484375 +97209 0.372955322265625 +97210 -0.044189453125 +97211 0.2554931640625 +97212 -0.14190673828125 +97213 0.10711669921875 +97214 -0.23785400390625 +97215 -0.052886962890625 +97216 -0.3013916015625 +97217 -0.186279296875 +97218 -0.283233642578125 +97219 -0.23291015625 +97220 -0.20123291015625 +97221 -0.209442138671875 +97222 -0.10968017578125 +97223 -0.174163818359375 +97224 -0.011566162109375 +97225 -0.126739501953125 +97226 0.106658935546875 +97227 -0.048126220703125 +97228 0.225921630859375 +97229 0.0426025390625 +97230 0.311187744140625 +97231 0.10748291015625 +97232 0.35638427734375 +97233 0.1409912109375 +97234 0.4080810546875 +97235 0.19708251953125 +97236 0.464691162109375 +97237 0.273651123046875 +97238 0.48089599609375 +97239 0.31768798828125 +97240 0.4686279296875 +97241 0.341094970703125 +97242 0.4510498046875 +97243 0.368011474609375 +97244 0.407989501953125 +97245 0.37249755859375 +97246 0.29522705078125 +97247 0.30072021484375 +97248 0.11474609375 +97249 0.1517333984375 +97250 -0.07855224609375 +97251 -0.01470947265625 +97252 -0.27313232421875 +97253 -0.1883544921875 +97254 -0.469879150390625 +97255 -0.372711181640625 +97256 -0.620147705078125 +97257 -0.51397705078125 +97258 -0.687469482421875 +97259 -0.57177734375 +97260 -0.66546630859375 +97261 -0.53948974609375 +97262 -0.569793701171875 +97263 -0.43511962890625 +97264 -0.433807373046875 +97265 -0.2962646484375 +97266 -0.2918701171875 +97267 -0.161102294921875 +97268 -0.15771484375 +97269 -0.0435791015625 +97270 -0.029754638671875 +97271 0.060394287109375 +97272 0.07745361328125 +97273 0.13665771484375 +97274 0.148468017578125 +97275 0.170135498046875 +97276 0.185089111328125 +97277 0.16552734375 +97278 0.21514892578125 +97279 0.15728759765625 +97280 0.241607666015625 +97281 0.150787353515625 +97282 0.241943359375 +97283 0.12200927734375 +97284 0.222625732421875 +97285 0.080108642578125 +97286 0.205413818359375 +97287 0.05126953125 +97288 0.213592529296875 +97289 0.062896728515625 +97290 0.2286376953125 +97291 0.09271240234375 +97292 0.2108154296875 +97293 0.092987060546875 +97294 0.1739501953125 +97295 0.07855224609375 +97296 0.132232666015625 +97297 0.06427001953125 +97298 0.0743408203125 +97299 0.0347900390625 +97300 0.000518798828125 +97301 -0.01171875 +97302 -0.070953369140625 +97303 -0.056060791015625 +97304 -0.10198974609375 +97305 -0.055511474609375 +97306 -0.09124755859375 +97307 -0.010467529296875 +97308 -0.083221435546875 +97309 0.02508544921875 +97310 -0.0985107421875 +97311 0.025665283203125 +97312 -0.11431884765625 +97313 0.017333984375 +97314 -0.128875732421875 +97315 0.00189208984375 +97316 -0.151702880859375 +97317 -0.03173828125 +97318 -0.17315673828125 +97319 -0.071502685546875 +97320 -0.209381103515625 +97321 -0.13543701171875 +97322 -0.25848388671875 +97323 -0.219970703125 +97324 -0.30096435546875 +97325 -0.300506591796875 +97326 -0.337677001953125 +97327 -0.376312255859375 +97328 -0.343597412109375 +97329 -0.416107177734375 +97330 -0.278778076171875 +97331 -0.371124267578125 +97332 -0.145416259765625 +97333 -0.242279052734375 +97334 0.021087646484375 +97335 -0.069732666015625 +97336 0.201995849609375 +97337 0.125640869140625 +97338 0.370208740234375 +97339 0.31268310546875 +97340 0.494476318359375 +97341 0.45501708984375 +97342 0.57659912109375 +97343 0.554779052734375 +97344 0.615753173828125 +97345 0.61065673828125 +97346 0.602630615234375 +97347 0.610931396484375 +97348 0.517578125 +97349 0.531463623046875 +97350 0.37530517578125 +97351 0.3883056640625 +97352 0.22222900390625 +97353 0.23468017578125 +97354 0.08062744140625 +97355 0.095245361328125 +97356 -0.026092529296875 +97357 -0.00396728515625 +97358 -0.08447265625 +97359 -0.04852294921875 +97360 -0.107635498046875 +97361 -0.055145263671875 +97362 -0.138916015625 +97363 -0.0758056640625 +97364 -0.20166015625 +97365 -0.138702392578125 +97366 -0.266021728515625 +97367 -0.209197998046875 +97368 -0.3333740234375 +97369 -0.289031982421875 +97370 -0.404449462890625 +97371 -0.37884521484375 +97372 -0.460662841796875 +97373 -0.456329345703125 +97374 -0.4984130859375 +97375 -0.51641845703125 +97376 -0.484649658203125 +97377 -0.519287109375 +97378 -0.4146728515625 +97379 -0.458251953125 +97380 -0.33331298828125 +97381 -0.384796142578125 +97382 -0.26263427734375 +97383 -0.323699951171875 +97384 -0.198822021484375 +97385 -0.269287109375 +97386 -0.12042236328125 +97387 -0.1951904296875 +97388 -0.027008056640625 +97389 -0.100006103515625 +97390 0.0579833984375 +97391 -0.01055908203125 +97392 0.159881591796875 +97393 0.1033935546875 +97394 0.28466796875 +97395 0.24908447265625 +97396 0.387115478515625 +97397 0.373199462890625 +97398 0.452484130859375 +97399 0.45806884765625 +97400 0.48785400390625 +97401 0.511474609375 +97402 0.52105712890625 +97403 0.565399169921875 +97404 0.545684814453125 +97405 0.61138916015625 +97406 0.511810302734375 +97407 0.5897216796875 +97408 0.411956787109375 +97409 0.4906005859375 +97410 0.2618408203125 +97411 0.33148193359375 +97412 0.09234619140625 +97413 0.147796630859375 +97414 -0.06036376953125 +97415 -0.01873779296875 +97416 -0.172088623046875 +97417 -0.140289306640625 +97418 -0.221282958984375 +97419 -0.191986083984375 +97420 -0.2166748046875 +97421 -0.184295654296875 +97422 -0.196197509765625 +97423 -0.161834716796875 +97424 -0.1956787109375 +97425 -0.166595458984375 +97426 -0.21148681640625 +97427 -0.19390869140625 +97428 -0.227691650390625 +97429 -0.22442626953125 +97430 -0.26324462890625 +97431 -0.279754638671875 +97432 -0.301055908203125 +97433 -0.3389892578125 +97434 -0.30126953125 +97435 -0.3543701171875 +97436 -0.28350830078125 +97437 -0.348175048828125 +97438 -0.253173828125 +97439 -0.32598876953125 +97440 -0.185699462890625 +97441 -0.2581787109375 +97442 -0.077362060546875 +97443 -0.139801025390625 +97444 0.05914306640625 +97445 0.014617919921875 +97446 0.171966552734375 +97447 0.144378662109375 +97448 0.236907958984375 +97449 0.221038818359375 +97450 0.276214599609375 +97451 0.27069091796875 +97452 0.290740966796875 +97453 0.294036865234375 +97454 0.298431396484375 +97455 0.311767578125 +97456 0.31268310546875 +97457 0.339141845703125 +97458 0.320404052734375 +97459 0.360260009765625 +97460 0.309783935546875 +97461 0.360504150390625 +97462 0.2550048828125 +97463 0.308380126953125 +97464 0.1380615234375 +97465 0.18170166015625 +97466 -0.019989013671875 +97467 0.0047607421875 +97468 -0.1793212890625 +97469 -0.17559814453125 +97470 -0.301727294921875 +97471 -0.3143310546875 +97472 -0.350311279296875 +97473 -0.36785888671875 +97474 -0.3470458984375 +97475 -0.36248779296875 +97476 -0.329986572265625 +97477 -0.343536376953125 +97478 -0.2916259765625 +97479 -0.3018798828125 +97480 -0.227081298828125 +97481 -0.231414794921875 +97482 -0.12451171875 +97483 -0.117645263671875 +97484 -0.011505126953125 +97485 0.007049560546875 +97486 0.06549072265625 +97487 0.087982177734375 +97488 0.117950439453125 +97489 0.13946533203125 +97490 0.156097412109375 +97491 0.17425537109375 +97492 0.175933837890625 +97493 0.188201904296875 +97494 0.1685791015625 +97495 0.171234130859375 +97496 0.12957763671875 +97497 0.118438720703125 +97498 0.081573486328125 +97499 0.05706787109375 +97500 0.026214599609375 +97501 -0.010711669921875 +97502 -0.041961669921875 +97503 -0.0914306640625 +97504 -0.103759765625 +97505 -0.162322998046875 +97506 -0.134796142578125 +97507 -0.194549560546875 +97508 -0.102203369140625 +97509 -0.1492919921875 +97510 -0.00152587890625 +97511 -0.02166748046875 +97512 0.1136474609375 +97513 0.124053955078125 +97514 0.17926025390625 +97515 0.211151123046875 +97516 0.196441650390625 +97517 0.240447998046875 +97518 0.191009521484375 +97519 0.242218017578125 +97520 0.171112060546875 +97521 0.2257080078125 +97522 0.139923095703125 +97523 0.194366455078125 +97524 0.070220947265625 +97525 0.115509033203125 +97526 -0.017913818359375 +97527 0.0128173828125 +97528 -0.074127197265625 +97529 -0.053802490234375 +97530 -0.12054443359375 +97531 -0.110626220703125 +97532 -0.192413330078125 +97533 -0.199493408203125 +97534 -0.26806640625 +97535 -0.29437255859375 +97536 -0.295135498046875 +97537 -0.33221435546875 +97538 -0.246734619140625 +97539 -0.27972412109375 +97540 -0.162811279296875 +97541 -0.185333251953125 +97542 -0.108062744140625 +97543 -0.128204345703125 +97544 -0.089111328125 +97545 -0.115692138671875 +97546 -0.081298828125 +97547 -0.116455078125 +97548 -0.06536865234375 +97549 -0.105926513671875 +97550 -0.017364501953125 +97551 -0.053955078125 +97552 0.06988525390625 +97553 0.048797607421875 +97554 0.159881591796875 +97555 0.157318115234375 +97556 0.204376220703125 +97557 0.212005615234375 +97558 0.207977294921875 +97559 0.218475341796875 +97560 0.219757080078125 +97561 0.23724365234375 +97562 0.2698974609375 +97563 0.30535888671875 +97564 0.32513427734375 +97565 0.38128662109375 +97566 0.3369140625 +97567 0.404449462890625 +97568 0.32147216796875 +97569 0.3944091796875 +97570 0.3094482421875 +97571 0.3885498046875 +97572 0.281707763671875 +97573 0.362640380859375 +97574 0.203765869140625 +97575 0.27362060546875 +97576 0.072418212890625 +97577 0.11712646484375 +97578 -0.070098876953125 +97579 -0.054901123046875 +97580 -0.181915283203125 +97581 -0.19085693359375 +97582 -0.258941650390625 +97583 -0.28570556640625 +97584 -0.30108642578125 +97585 -0.339263916015625 +97586 -0.329437255859375 +97587 -0.3775634765625 +97588 -0.380645751953125 +97589 -0.445709228515625 +97590 -0.447998046875 +97591 -0.535064697265625 +97592 -0.51837158203125 +97593 -0.629058837890625 +97594 -0.567779541015625 +97595 -0.697601318359375 +97596 -0.56683349609375 +97597 -0.70391845703125 +97598 -0.51141357421875 +97599 -0.6424560546875 +97600 -0.384063720703125 +97601 -0.491241455078125 +97602 -0.197479248046875 +97603 -0.265716552734375 +97604 0.0013427734375 +97605 -0.023712158203125 +97606 0.185577392578125 +97607 0.201751708984375 +97608 0.326995849609375 +97609 0.375823974609375 +97610 0.414764404296875 +97611 0.485076904296875 +97612 0.480712890625 +97613 0.56884765625 +97614 0.5311279296875 +97615 0.634765625 +97616 0.529693603515625 +97617 0.63763427734375 +97618 0.4674072265625 +97619 0.5660400390625 +97620 0.3865966796875 +97621 0.4720458984375 +97622 0.328948974609375 +97623 0.40692138671875 +97624 0.300537109375 +97625 0.3778076171875 +97626 0.29534912109375 +97627 0.376953125 +97628 0.287445068359375 +97629 0.371978759765625 +97630 0.236846923828125 +97631 0.313140869140625 +97632 0.1307373046875 +97633 0.184417724609375 +97634 -0.010223388671875 +97635 0.011199951171875 +97636 -0.157379150390625 +97637 -0.171051025390625 +97638 -0.290618896484375 +97639 -0.33740234375 +97640 -0.397216796875 +97641 -0.47198486328125 +97642 -0.465728759765625 +97643 -0.560394287109375 +97644 -0.478485107421875 +97645 -0.58056640625 +97646 -0.447845458984375 +97647 -0.54754638671875 +97648 -0.412200927734375 +97649 -0.508575439453125 +97650 -0.368438720703125 +97651 -0.459503173828125 +97652 -0.311981201171875 +97653 -0.394378662109375 +97654 -0.27484130859375 +97655 -0.35260009765625 +97656 -0.239044189453125 +97657 -0.31170654296875 +97658 -0.14471435546875 +97659 -0.197418212890625 +97660 0.00946044921875 +97661 -0.007965087890625 +97662 0.1837158203125 +97663 0.207489013671875 +97664 0.345977783203125 +97665 0.409210205078125 +97666 0.47601318359375 +97667 0.57208251953125 +97668 0.549560546875 +97669 0.66595458984375 +97670 0.540863037109375 +97671 0.65875244140625 +97672 0.463836669921875 +97673 0.56744384765625 +97674 0.3504638671875 +97675 0.431396484375 +97676 0.236358642578125 +97677 0.29443359375 +97678 0.14263916015625 +97679 0.182464599609375 +97680 0.04376220703125 +97681 0.06365966796875 +97682 -0.0714111328125 +97683 -0.075958251953125 +97684 -0.16485595703125 +97685 -0.189422607421875 +97686 -0.23260498046875 +97687 -0.271942138671875 +97688 -0.28997802734375 +97689 -0.342529296875 +97690 -0.307098388671875 +97691 -0.364166259765625 +97692 -0.276214599609375 +97693 -0.327239990234375 +97694 -0.233917236328125 +97695 -0.2769775390625 +97696 -0.212921142578125 +97697 -0.253692626953125 +97698 -0.20220947265625 +97699 -0.24365234375 +97700 -0.162811279296875 +97701 -0.1983642578125 +97702 -0.093597412109375 +97703 -0.116241455078125 +97704 -0.026641845703125 +97705 -0.036834716796875 +97706 0.033843994140625 +97707 0.034881591796875 +97708 0.08154296875 +97709 0.09124755859375 +97710 0.09747314453125 +97711 0.10888671875 +97712 0.112030029296875 +97713 0.125518798828125 +97714 0.1385498046875 +97715 0.15771484375 +97716 0.155029296875 +97717 0.17828369140625 +97718 0.148468017578125 +97719 0.17108154296875 +97720 0.113983154296875 +97721 0.129974365234375 +97722 0.073822021484375 +97723 0.082427978515625 +97724 0.02752685546875 +97725 0.027679443359375 +97726 -0.050140380859375 +97727 -0.065643310546875 +97728 -0.128173828125 +97729 -0.15936279296875 +97730 -0.173828125 +97731 -0.21307373046875 +97732 -0.193359375 +97733 -0.234649658203125 +97734 -0.1673583984375 +97735 -0.2001953125 +97736 -0.103363037109375 +97737 -0.119171142578125 +97738 -0.02813720703125 +97739 -0.024749755859375 +97740 0.060577392578125 +97741 0.085784912109375 +97742 0.135101318359375 +97743 0.178131103515625 +97744 0.165771484375 +97745 0.215576171875 +97746 0.163299560546875 +97747 0.211456298828125 +97748 0.13525390625 +97749 0.17523193359375 +97750 0.099212646484375 +97751 0.128753662109375 +97752 0.079254150390625 +97753 0.1019287109375 +97754 0.058807373046875 +97755 0.0743408203125 +97756 0.035552978515625 +97757 0.04327392578125 +97758 0.033203125 +97759 0.038177490234375 +97760 0.065582275390625 +97761 0.076263427734375 +97762 0.119293212890625 +97763 0.14105224609375 +97764 0.157012939453125 +97765 0.186431884765625 +97766 0.15960693359375 +97767 0.188812255859375 +97768 0.11962890625 +97769 0.1390380859375 +97770 0.040863037109375 +97771 0.041778564453125 +97772 -0.0576171875 +97773 -0.079437255859375 +97774 -0.17156982421875 +97775 -0.219390869140625 +97776 -0.29266357421875 +97777 -0.367828369140625 +97778 -0.396697998046875 +97779 -0.494873046875 +97780 -0.447784423828125 +97781 -0.556243896484375 +97782 -0.410919189453125 +97783 -0.508697509765625 +97784 -0.304901123046875 +97785 -0.3756103515625 +97786 -0.179656982421875 +97787 -0.218902587890625 +97788 -0.05548095703125 +97789 -0.063751220703125 +97790 0.06903076171875 +97791 0.091552734375 +97792 0.18499755859375 +97793 0.23602294921875 +97794 0.27093505859375 +97795 0.342987060546875 +97796 0.313232421875 +97797 0.39520263671875 +97798 0.309539794921875 +97799 0.389373779296875 +97800 0.259063720703125 +97801 0.324249267578125 +97802 0.180816650390625 +97803 0.224090576171875 +97804 0.1024169921875 +97805 0.124267578125 +97806 0.033538818359375 +97807 0.037078857421875 +97808 -0.004425048828125 +97809 -0.010101318359375 +97810 -0.013092041015625 +97811 -0.019439697265625 +97812 -0.017059326171875 +97813 -0.022796630859375 +97814 -0.0018310546875 +97815 -0.001556396484375 +97816 0.0419921875 +97817 0.056304931640625 +97818 0.080230712890625 +97819 0.106719970703125 +97820 0.07196044921875 +97821 0.096893310546875 +97822 0.029510498046875 +97823 0.042694091796875 +97824 -0.017791748046875 +97825 -0.018035888671875 +97826 -0.062591552734375 +97827 -0.07586669921875 +97828 -0.096099853515625 +97829 -0.11944580078125 +97830 -0.12689208984375 +97831 -0.15972900390625 +97832 -0.1595458984375 +97833 -0.202606201171875 +97834 -0.194488525390625 +97835 -0.24859619140625 +97836 -0.237548828125 +97837 -0.30517578125 +97838 -0.280853271484375 +97839 -0.36212158203125 +97840 -0.302734375 +97841 -0.39141845703125 +97842 -0.273895263671875 +97843 -0.35528564453125 +97844 -0.191497802734375 +97845 -0.249969482421875 +97846 -0.069091796875 +97847 -0.092864990234375 +97848 0.0723876953125 +97849 0.08905029296875 +97850 0.185943603515625 +97851 0.2352294921875 +97852 0.250732421875 +97853 0.318817138671875 +97854 0.2813720703125 +97855 0.358642578125 +97856 0.272491455078125 +97857 0.347747802734375 +97858 0.2237548828125 +97859 0.28564453125 +97860 0.174652099609375 +97861 0.223175048828125 +97862 0.1534423828125 +97863 0.196746826171875 +97864 0.139617919921875 +97865 0.179840087890625 +97866 0.120086669921875 +97867 0.155548095703125 +97868 0.116119384765625 +97869 0.151214599609375 +97870 0.12005615234375 +97871 0.156951904296875 +97872 0.10009765625 +97873 0.13177490234375 +97874 0.075775146484375 +97875 0.100799560546875 +97876 0.06500244140625 +97877 0.087127685546875 +97878 0.03997802734375 +97879 0.05487060546875 +97880 -0.009429931640625 +97881 -0.009002685546875 +97882 -0.08282470703125 +97883 -0.10400390625 +97884 -0.1796875 +97885 -0.229400634765625 +97886 -0.27703857421875 +97887 -0.35552978515625 +97888 -0.343505859375 +97889 -0.441925048828125 +97890 -0.367706298828125 +97891 -0.473846435546875 +97892 -0.360137939453125 +97893 -0.464813232421875 +97894 -0.324127197265625 +97895 -0.419097900390625 +97896 -0.25787353515625 +97897 -0.334320068359375 +97898 -0.1749267578125 +97899 -0.227935791015625 +97900 -0.093597412109375 +97901 -0.12347412109375 +97902 -0.019073486328125 +97903 -0.02764892578125 +97904 0.06268310546875 +97905 0.077667236328125 +97906 0.167816162109375 +97907 0.2132568359375 +97908 0.303863525390625 +97909 0.38885498046875 +97910 0.45404052734375 +97911 0.582794189453125 +97912 0.57098388671875 +97913 0.734039306640625 +97914 0.621795654296875 +97915 0.800140380859375 +97916 0.604339599609375 +97917 0.7783203125 +97918 0.5159912109375 +97919 0.6651611328125 +97920 0.35601806640625 +97921 0.45965576171875 +97922 0.1534423828125 +97923 0.199188232421875 +97924 -0.040802001953125 +97925 -0.050689697265625 +97926 -0.1824951171875 +97927 -0.23297119140625 +97928 -0.258056640625 +97929 -0.33013916015625 +97930 -0.287811279296875 +97931 -0.368408203125 +97932 -0.295928955078125 +97933 -0.378936767578125 +97934 -0.294281005859375 +97935 -0.376983642578125 +97936 -0.296173095703125 +97937 -0.37969970703125 +97938 -0.305023193359375 +97939 -0.391510009765625 +97940 -0.29986572265625 +97941 -0.385345458984375 +97942 -0.2657470703125 +97943 -0.3419189453125 +97944 -0.219512939453125 +97945 -0.28289794921875 +97946 -0.194793701171875 +97947 -0.251617431640625 +97948 -0.205657958984375 +97949 -0.266143798828125 +97950 -0.210906982421875 +97951 -0.273345947265625 +97952 -0.166748046875 +97953 -0.216796875 +97954 -0.09783935546875 +97955 -0.128265380859375 +97956 -0.051055908203125 +97957 -0.068145751953125 +97958 -0.031585693359375 +97959 -0.0430908203125 +97960 -0.017181396484375 +97961 -0.024444580078125 +97962 0.0177001953125 +97963 0.020721435546875 +97964 0.097991943359375 +97965 0.124481201171875 +97966 0.201202392578125 +97967 0.25787353515625 +97968 0.294921875 +97969 0.379119873046875 +97970 0.37274169921875 +97971 0.47991943359375 +97972 0.4097900390625 +97973 0.5281982421875 +97974 0.396148681640625 +97975 0.511138916015625 +97976 0.3531494140625 +97977 0.456207275390625 +97978 0.31500244140625 +97979 0.407470703125 +97980 0.296356201171875 +97981 0.383758544921875 +97982 0.27532958984375 +97983 0.35687255859375 +97984 0.240325927734375 +97985 0.31182861328125 +97986 0.19305419921875 +97987 0.250885009765625 +97988 0.1268310546875 +97989 0.1654052734375 +97990 0.026031494140625 +97991 0.035247802734375 +97992 -0.111297607421875 +97993 -0.142059326171875 +97994 -0.261199951171875 +97995 -0.33563232421875 +97996 -0.415191650390625 +97997 -0.5345458984375 +97998 -0.56011962890625 +97999 -0.72186279296875 +98000 -0.648773193359375 +98001 -0.836669921875 +98002 -0.645233154296875 +98003 -0.8326416015625 +98004 -0.56494140625 +98005 -0.7296142578125 +98006 -0.4505615234375 +98007 -0.582550048828125 +98008 -0.339813232421875 +98009 -0.440093994140625 +98010 -0.249847412109375 +98011 -0.324310302734375 +98012 -0.154510498046875 +98013 -0.20147705078125 +98014 -0.032867431640625 +98015 -0.044647216796875 +98016 0.08233642578125 +98017 0.103973388671875 +98018 0.15850830078125 +98019 0.202392578125 +98020 0.2064208984375 +98021 0.264495849609375 +98022 0.263824462890625 +98023 0.338897705078125 +98024 0.3448486328125 +98025 0.443817138671875 +98026 0.42303466796875 +98027 0.545074462890625 +98028 0.478668212890625 +98029 0.6173095703125 +98030 0.50555419921875 +98031 0.6524658203125 +98032 0.513702392578125 +98033 0.66339111328125 +98034 0.5078125 +98035 0.6561279296875 +98036 0.469329833984375 +98037 0.606781005859375 +98038 0.38726806640625 +98039 0.501190185546875 +98040 0.272064208984375 +98041 0.352783203125 +98042 0.135345458984375 +98043 0.176544189453125 +98044 -0.028533935546875 +98045 -0.034820556640625 +98046 -0.201629638671875 +98047 -0.258209228515625 +98048 -0.344451904296875 +98049 -0.44244384765625 +98050 -0.4473876953125 +98051 -0.5753173828125 +98052 -0.50689697265625 +98053 -0.65203857421875 +98054 -0.5 +98055 -0.641632080078125 +98056 -0.440277099609375 +98057 -0.562164306640625 +98058 -0.36090087890625 +98059 -0.458038330078125 +98060 -0.277923583984375 +98061 -0.350555419921875 +98062 -0.20709228515625 +98063 -0.260528564453125 +98064 -0.15179443359375 +98065 -0.192108154296875 +98066 -0.109771728515625 +98067 -0.141937255859375 +98068 -0.075469970703125 +98069 -0.1021728515625 +98070 -0.041748046875 +98071 -0.062896728515625 +98072 0.00018310546875 +98073 -0.011932373046875 +98074 0.059173583984375 +98075 0.062835693359375 +98076 0.125640869140625 +98077 0.148712158203125 +98078 0.19647216796875 +98079 0.241729736328125 +98080 0.277008056640625 +98081 0.34912109375 +98082 0.357177734375 +98083 0.457305908203125 +98084 0.42034912109375 +98085 0.54388427734375 +98086 0.439849853515625 +98087 0.5728759765625 +98088 0.387786865234375 +98089 0.506591796875 +98090 0.268951416015625 +98091 0.351226806640625 +98092 0.11309814453125 +98093 0.146514892578125 +98094 -0.040679931640625 +98095 -0.05523681640625 +98096 -0.1640625 +98097 -0.21624755859375 +98098 -0.255645751953125 +98099 -0.334930419921875 +98100 -0.30908203125 +98101 -0.402984619140625 +98102 -0.33978271484375 +98103 -0.4412841796875 +98104 -0.3818359375 +98105 -0.49578857421875 +98106 -0.43048095703125 +98107 -0.5601806640625 +98108 -0.460601806640625 +98109 -0.600738525390625 +98110 -0.447509765625 +98111 -0.584228515625 +98112 -0.367950439453125 +98113 -0.47930908203125 +98114 -0.21710205078125 +98115 -0.27935791015625 +98116 -0.01336669921875 +98117 -0.0089111328125 +98118 0.196044921875 +98119 0.268798828125 +98120 0.35821533203125 +98121 0.482818603515625 +98122 0.451080322265625 +98123 0.60369873046875 +98124 0.488555908203125 +98125 0.650421142578125 +98126 0.50103759765625 +98127 0.66400146484375 +98128 0.486175537109375 +98129 0.6414794921875 +98130 0.436248779296875 +98131 0.572540283203125 +98132 0.38165283203125 +98133 0.498138427734375 +98134 0.338104248046875 +98135 0.439453125 +98136 0.2900390625 +98137 0.375518798828125 +98138 0.21380615234375 +98139 0.274505615234375 +98140 0.08892822265625 +98141 0.1087646484375 +98142 -0.067901611328125 +98143 -0.099395751953125 +98144 -0.232940673828125 +98145 -0.3182373046875 +98146 -0.406982421875 +98147 -0.5489501953125 +98148 -0.57666015625 +98149 -0.7738037109375 +98150 -0.702423095703125 +98151 -0.86383056640625 +98152 -0.759429931640625 +98153 -0.870391845703125 +98154 -0.760772705078125 +98155 -0.86895751953125 +98156 -0.716156005859375 +98157 -0.861053466796875 +98158 -0.612640380859375 +98159 -0.765869140625 +98160 -0.441802978515625 +98161 -0.5301513671875 +98162 -0.208953857421875 +98163 -0.214691162109375 +98164 0.0538330078125 +98165 0.137359619140625 +98166 0.308349609375 +98167 0.474822998046875 +98168 0.528106689453125 +98169 0.76239013671875 +98170 0.692901611328125 +98171 0.867462158203125 +98172 0.802978515625 +98173 0.870361328125 +98174 0.849609375 +98175 0.86480712890625 +98176 0.836669921875 +98177 0.831817626953125 +98178 0.78216552734375 +98179 0.677581787109375 +98180 0.690338134765625 +98181 0.495880126953125 +98182 0.574920654296875 +98183 0.30767822265625 +98184 0.4375 +98185 0.116180419921875 +98186 0.254425048828125 +98187 -0.110748291015625 +98188 0.02056884765625 +98189 -0.381805419921875 +98190 -0.232208251953125 +98191 -0.6572265625 +98192 -0.459320068359375 +98193 -0.857421875 +98194 -0.62872314453125 +98195 -0.870391845703125 +98196 -0.73504638671875 +98197 -0.870391845703125 +98198 -0.7982177734375 +98199 -0.86444091796875 +98200 -0.84466552734375 +98201 -0.85723876953125 +98202 -0.855194091796875 +98203 -0.790008544921875 +98204 -0.80572509765625 +98205 -0.62847900390625 +98206 -0.677398681640625 +98207 -0.3956298828125 +98208 -0.50006103515625 +98209 -0.126708984375 +98210 -0.294036865234375 +98211 0.150115966796875 +98212 -0.068023681640625 +98213 0.424041748046875 +98214 0.15789794921875 +98215 0.670623779296875 +98216 0.354888916015625 +98217 0.854522705078125 +98218 0.509765625 +98219 0.866485595703125 +98220 0.610992431640625 +98221 0.86920166015625 +98222 0.6719970703125 +98223 0.8653564453125 +98224 0.702667236328125 +98225 0.857147216796875 +98226 0.700714111328125 +98227 0.766845703125 +98228 0.669891357421875 +98229 0.628509521484375 +98230 0.605072021484375 +98231 0.462127685546875 +98232 0.525390625 +98233 0.297210693359375 +98234 0.44000244140625 +98235 0.14862060546875 +98236 0.3319091796875 +98237 -0.00537109375 +98238 0.2066650390625 +98239 -0.15753173828125 +98240 0.06158447265625 +98241 -0.31304931640625 +98242 -0.11370849609375 +98243 -0.48876953125 +98244 -0.2843017578125 +98245 -0.6416015625 +98246 -0.431732177734375 +98247 -0.751373291015625 +98248 -0.573089599609375 +98249 -0.84619140625 +98250 -0.69732666015625 +98251 -0.861297607421875 +98252 -0.779693603515625 +98253 -0.863250732421875 +98254 -0.796600341796875 +98255 -0.856597900390625 +98256 -0.75701904296875 +98257 -0.7498779296875 +98258 -0.703948974609375 +98259 -0.624542236328125 +98260 -0.620941162109375 +98261 -0.47808837890625 +98262 -0.464508056640625 +98263 -0.253387451171875 +98264 -0.268585205078125 +98265 0.003692626953125 +98266 -0.08404541015625 +98267 0.2257080078125 +98268 0.098358154296875 +98269 0.427154541015625 +98270 0.30267333984375 +98271 0.643218994140625 +98272 0.5216064453125 +98273 0.855926513671875 +98274 0.71197509765625 +98275 0.870361328125 +98276 0.836761474609375 +98277 0.870361328125 +98278 0.859588623046875 +98279 0.862762451171875 +98280 0.859771728515625 +98281 0.79669189453125 +98282 0.835174560546875 +98283 0.595794677734375 +98284 0.719207763671875 +98285 0.362152099609375 +98286 0.57598876953125 +98287 0.1270751953125 +98288 0.4212646484375 +98289 -0.086944580078125 +98290 0.256622314453125 +98291 -0.2784423828125 +98292 0.056243896484375 +98293 -0.484832763671875 +98294 -0.19403076171875 +98295 -0.729583740234375 +98296 -0.45648193359375 +98297 -0.86688232421875 +98298 -0.68389892578125 +98299 -0.870391845703125 +98300 -0.856475830078125 +98301 -0.86859130859375 +98302 -0.870391845703125 +98303 -0.86279296875 +98304 -0.870391845703125 +98305 -0.817962646484375 +98306 -0.860198974609375 +98307 -0.6116943359375 +98308 -0.718719482421875 +98309 -0.3128662109375 +98310 -0.463897705078125 +98311 0.039398193359375 +98312 -0.159515380859375 +98313 0.422821044921875 +98314 0.1685791015625 +98315 0.805145263671875 +98316 0.470794677734375 +98317 0.870361328125 +98318 0.706451416015625 +98319 0.870361328125 +98320 0.85595703125 +98321 0.860015869140625 +98322 0.8651123046875 +98323 0.727935791015625 +98324 0.8656005859375 +98325 0.48114013671875 +98326 0.859619140625 +98327 0.2059326171875 +98328 0.8074951171875 +98329 -0.06103515625 +98330 0.684539794921875 +98331 -0.29913330078125 +98332 0.526153564453125 +98333 -0.516204833984375 +98334 0.324798583984375 +98335 -0.7252197265625 +98336 0.101287841796875 +98337 -0.85980224609375 +98338 -0.1173095703125 +98339 -0.870391845703125 +98340 -0.3079833984375 +98341 -0.870391845703125 +98342 -0.434814453125 +98343 -0.858062744140625 +98344 -0.494354248046875 +98345 -0.673004150390625 +98346 -0.52423095703125 +98347 -0.42694091796875 +98348 -0.5570068359375 +98349 -0.2100830078125 +98350 -0.592803955078125 +98351 -0.0362548828125 +98352 -0.613128662109375 +98353 0.10943603515625 +98354 -0.60638427734375 +98355 0.23516845703125 +98356 -0.54595947265625 +98357 0.373687744140625 +98358 -0.4361572265625 +98359 0.517791748046875 +98360 -0.324737548828125 +98361 0.602783203125 +98362 -0.210723876953125 +98363 0.635711669921875 +98364 -0.072723388671875 +98365 0.655181884765625 +98366 0.080322265625 +98367 0.65948486328125 +98368 0.241363525390625 +98369 0.651275634765625 +98370 0.3922119140625 +98371 0.61846923828125 +98372 0.50640869140625 +98373 0.53753662109375 +98374 0.571563720703125 +98375 0.404144287109375 +98376 0.581817626953125 +98377 0.22186279296875 +98378 0.53961181640625 +98379 0.003997802734375 +98380 0.459808349609375 +98381 -0.22100830078125 +98382 0.359344482421875 +98383 -0.42449951171875 +98384 0.255828857421875 +98385 -0.579833984375 +98386 0.18206787109375 +98387 -0.641876220703125 +98388 0.1356201171875 +98389 -0.6177978515625 +98390 0.07257080078125 +98391 -0.575531005859375 +98392 -0.0091552734375 +98393 -0.526336669921875 +98394 -0.071380615234375 +98395 -0.42645263671875 +98396 -0.093719482421875 +98397 -0.2581787109375 +98398 -0.101776123046875 +98399 -0.068695068359375 +98400 -0.123138427734375 +98401 0.09222412109375 +98402 -0.145233154296875 +98403 0.232147216796875 +98404 -0.161895751953125 +98405 0.3509521484375 +98406 -0.1956787109375 +98407 0.410064697265625 +98408 -0.2691650390625 +98409 0.372955322265625 +98410 -0.36932373046875 +98411 0.2554931640625 +98412 -0.4609375 +98413 0.10711669921875 +98414 -0.531951904296875 +98415 -0.052886962890625 +98416 -0.55828857421875 +98417 -0.186279296875 +98418 -0.501617431640625 +98419 -0.23291015625 +98420 -0.379302978515625 +98421 -0.209442138671875 +98422 -0.239044189453125 +98423 -0.174163818359375 +98424 -0.087188720703125 +98425 -0.126739501953125 +98426 0.083282470703125 +98427 -0.048126220703125 +98428 0.252685546875 +98429 0.0426025390625 +98430 0.3885498046875 +98431 0.10748291015625 +98432 0.48248291015625 +98433 0.1409912109375 +98434 0.56964111328125 +98435 0.19708251953125 +98436 0.646636962890625 +98437 0.273651123046875 +98438 0.675201416015625 +98439 0.31768798828125 +98440 0.6646728515625 +98441 0.341094970703125 +98442 0.634429931640625 +98443 0.368011474609375 +98444 0.569305419921875 +98445 0.37249755859375 +98446 0.435272216796875 +98447 0.30072021484375 +98448 0.236572265625 +98449 0.1517333984375 +98450 0.02105712890625 +98451 -0.01470947265625 +98452 -0.198486328125 +98453 -0.1883544921875 +98454 -0.41937255859375 +98455 -0.372711181640625 +98456 -0.598602294921875 +98457 -0.51397705078125 +98458 -0.703460693359375 +98459 -0.57177734375 +98460 -0.726165771484375 +98461 -0.53948974609375 +98462 -0.677581787109375 +98463 -0.43511962890625 +98464 -0.583648681640625 +98465 -0.2962646484375 +98466 -0.471893310546875 +98467 -0.161102294921875 +98468 -0.353668212890625 +98469 -0.0435791015625 +98470 -0.228515625 +98471 0.060394287109375 +98472 -0.1097412109375 +98473 0.13665771484375 +98474 -0.011962890625 +98475 0.170135498046875 +98476 0.0638427734375 +98477 0.16552734375 +98478 0.137725830078125 +98479 0.15728759765625 +98480 0.209136962890625 +98481 0.150787353515625 +98482 0.2569580078125 +98483 0.12200927734375 +98484 0.284210205078125 +98485 0.080108642578125 +98486 0.3067626953125 +98487 0.05126953125 +98488 0.3421630859375 +98489 0.062896728515625 +98490 0.37353515625 +98491 0.09271240234375 +98492 0.3668212890625 +98493 0.092987060546875 +98494 0.333465576171875 +98495 0.07855224609375 +98496 0.2857666015625 +98497 0.06427001953125 +98498 0.215240478515625 +98499 0.0347900390625 +98500 0.12359619140625 +98501 -0.01171875 +98502 0.0279541015625 +98503 -0.056060791015625 +98504 -0.037567138671875 +98505 -0.055511474609375 +98506 -0.069580078125 +98507 -0.010467529296875 +98508 -0.10308837890625 +98509 0.02508544921875 +98510 -0.153167724609375 +98511 0.025665283203125 +98512 -0.198760986328125 +98513 0.017333984375 +98514 -0.23675537109375 +98515 0.00189208984375 +98516 -0.27392578125 +98517 -0.03173828125 +98518 -0.3013916015625 +98519 -0.071502685546875 +98520 -0.332427978515625 +98521 -0.13543701171875 +98522 -0.36566162109375 +98523 -0.219970703125 +98524 -0.38543701171875 +98525 -0.300506591796875 +98526 -0.393585205078125 +98527 -0.376312255859375 +98528 -0.370513916015625 +98529 -0.416107177734375 +98530 -0.284515380859375 +98531 -0.371124267578125 +98532 -0.13922119140625 +98533 -0.242279052734375 +98534 0.033843994140625 +98535 -0.069732666015625 +98536 0.2171630859375 +98537 0.125640869140625 +98538 0.38629150390625 +98539 0.31268310546875 +98540 0.513641357421875 +98541 0.45501708984375 +98542 0.599578857421875 +98543 0.554779052734375 +98544 0.6427001953125 +98545 0.61065673828125 +98546 0.634796142578125 +98547 0.610931396484375 +98548 0.559478759765625 +98549 0.531463623046875 +98550 0.42950439453125 +98551 0.3883056640625 +98552 0.2845458984375 +98553 0.23468017578125 +98554 0.144317626953125 +98555 0.095245361328125 +98556 0.02972412109375 +98557 -0.00396728515625 +98558 -0.046478271484375 +98559 -0.04852294921875 +98560 -0.09393310546875 +98561 -0.055145263671875 +98562 -0.14727783203125 +98563 -0.0758056640625 +98564 -0.22430419921875 +98565 -0.138702392578125 +98566 -0.299041748046875 +98567 -0.209197998046875 +98568 -0.37139892578125 +98569 -0.289031982421875 +98570 -0.441131591796875 +98571 -0.37884521484375 +98572 -0.492462158203125 +98573 -0.456329345703125 +98574 -0.52227783203125 +98575 -0.51641845703125 +98576 -0.50360107421875 +98577 -0.519287109375 +98578 -0.43310546875 +98579 -0.458251953125 +98580 -0.348541259765625 +98581 -0.384796142578125 +98582 -0.269195556640625 +98583 -0.323699951171875 +98584 -0.19317626953125 +98585 -0.269287109375 +98586 -0.104156494140625 +98587 -0.1951904296875 +98588 -0.003173828125 +98589 -0.100006103515625 +98590 0.08917236328125 +98591 -0.01055908203125 +98592 0.192535400390625 +98593 0.1033935546875 +98594 0.310882568359375 +98595 0.24908447265625 +98596 0.406219482421875 +98597 0.373199462890625 +98598 0.4659423828125 +98599 0.45806884765625 +98600 0.495697021484375 +98601 0.511474609375 +98602 0.518524169921875 +98603 0.565399169921875 +98604 0.529541015625 +98605 0.61138916015625 +98606 0.48828125 +98607 0.5897216796875 +98608 0.389404296875 +98609 0.4906005859375 +98610 0.24688720703125 +98611 0.33148193359375 +98612 0.087249755859375 +98613 0.147796630859375 +98614 -0.05859375 +98615 -0.01873779296875 +98616 -0.16961669921875 +98617 -0.140289306640625 +98618 -0.227081298828125 +98619 -0.191986083984375 +98620 -0.2373046875 +98621 -0.184295654296875 +98622 -0.2308349609375 +98623 -0.161834716796875 +98624 -0.236724853515625 +98625 -0.166595458984375 +98626 -0.25177001953125 +98627 -0.19390869140625 +98628 -0.262847900390625 +98629 -0.22442626953125 +98630 -0.285797119140625 +98631 -0.279754638671875 +98632 -0.307037353515625 +98633 -0.3389892578125 +98634 -0.29437255859375 +98635 -0.3543701171875 +98636 -0.264739990234375 +98637 -0.348175048828125 +98638 -0.223480224609375 +98639 -0.32598876953125 +98640 -0.151275634765625 +98641 -0.2581787109375 +98642 -0.04595947265625 +98643 -0.139801025390625 +98644 0.081146240234375 +98645 0.014617919921875 +98646 0.186553955078125 +98647 0.144378662109375 +98648 0.249725341796875 +98649 0.221038818359375 +98650 0.288543701171875 +98651 0.27069091796875 +98652 0.303436279296875 +98653 0.294036865234375 +98654 0.30914306640625 +98655 0.311767578125 +98656 0.316802978515625 +98657 0.339141845703125 +98658 0.315765380859375 +98659 0.360260009765625 +98660 0.296875 +98661 0.360504150390625 +98662 0.239898681640625 +98663 0.308380126953125 +98664 0.131072998046875 +98665 0.18170166015625 +98666 -0.011688232421875 +98667 0.0047607421875 +98668 -0.155303955078125 +98669 -0.17559814453125 +98670 -0.268035888671875 +98671 -0.3143310546875 +98672 -0.319305419921875 +98673 -0.36785888671875 +98674 -0.326263427734375 +98675 -0.36248779296875 +98676 -0.319305419921875 +98677 -0.343536376953125 +98678 -0.29205322265625 +98679 -0.3018798828125 +98680 -0.24041748046875 +98681 -0.231414794921875 +98682 -0.154876708984375 +98683 -0.117645263671875 +98684 -0.058013916015625 +98685 0.007049560546875 +98686 0.012176513671875 +98687 0.087982177734375 +98688 0.06451416015625 +98689 0.13946533203125 +98690 0.106658935546875 +98691 0.17425537109375 +98692 0.134735107421875 +98693 0.188201904296875 +98694 0.140869140625 +98695 0.171234130859375 +98696 0.120819091796875 +98697 0.118438720703125 +98698 0.09228515625 +98699 0.05706787109375 +98700 0.056060791015625 +98701 -0.010711669921875 +98702 0.00726318359375 +98703 -0.0914306640625 +98704 -0.038787841796875 +98705 -0.162322998046875 +98706 -0.0625 +98707 -0.194549560546875 +98708 -0.03729248046875 +98709 -0.1492919921875 +98710 0.04058837890625 +98711 -0.02166748046875 +98712 0.128021240234375 +98713 0.124053955078125 +98714 0.173553466796875 +98715 0.211151123046875 +98716 0.17852783203125 +98717 0.240447998046875 +98718 0.16436767578125 +98719 0.242218017578125 +98720 0.13824462890625 +98721 0.2257080078125 +98722 0.103302001953125 +98723 0.194366455078125 +98724 0.03802490234375 +98725 0.115509033203125 +98726 -0.0408935546875 +98727 0.0128173828125 +98728 -0.09228515625 +98729 -0.053802490234375 +98730 -0.1337890625 +98731 -0.110626220703125 +98732 -0.19378662109375 +98733 -0.199493408203125 +98734 -0.254730224609375 +98735 -0.29437255859375 +98736 -0.27398681640625 +98737 -0.33221435546875 +98738 -0.229400634765625 +98739 -0.27972412109375 +98740 -0.154449462890625 +98741 -0.185333251953125 +98742 -0.10357666015625 +98743 -0.128204345703125 +98744 -0.08245849609375 +98745 -0.115692138671875 +98746 -0.07049560546875 +98747 -0.116455078125 +98748 -0.051666259765625 +98749 -0.105926513671875 +98750 -0.006072998046875 +98751 -0.053955078125 +98752 0.07208251953125 +98753 0.048797607421875 +98754 0.15179443359375 +98755 0.157318115234375 +98756 0.192291259765625 +98757 0.212005615234375 +98758 0.197265625 +98759 0.218475341796875 +98760 0.207916259765625 +98761 0.23724365234375 +98762 0.2496337890625 +98763 0.30535888671875 +98764 0.29449462890625 +98765 0.38128662109375 +98766 0.301727294921875 +98767 0.404449462890625 +98768 0.28515625 +98769 0.3944091796875 +98770 0.270782470703125 +98771 0.3885498046875 +98772 0.24273681640625 +98773 0.362640380859375 +98774 0.172271728515625 +98775 0.27362060546875 +98776 0.056976318359375 +98777 0.11712646484375 +98778 -0.0673828125 +98779 -0.054901123046875 +98780 -0.16534423828125 +98781 -0.19085693359375 +98782 -0.233245849609375 +98783 -0.28570556640625 +98784 -0.270843505859375 +98785 -0.339263916015625 +98786 -0.29583740234375 +98787 -0.3775634765625 +98788 -0.339019775390625 +98789 -0.445709228515625 +98790 -0.394775390625 +98791 -0.535064697265625 +98792 -0.452117919921875 +98793 -0.629058837890625 +98794 -0.490997314453125 +98795 -0.697601318359375 +98796 -0.48687744140625 +98797 -0.70391845703125 +98798 -0.43646240234375 +98799 -0.6424560546875 +98800 -0.32525634765625 +98801 -0.491241455078125 +98802 -0.164215087890625 +98803 -0.265716552734375 +98804 0.00689697265625 +98805 -0.023712158203125 +98806 0.165313720703125 +98807 0.201751708984375 +98808 0.287078857421875 +98809 0.375823974609375 +98810 0.362945556640625 +98811 0.485076904296875 +98812 0.419647216796875 +98813 0.56884765625 +98814 0.462432861328125 +98815 0.634765625 +98816 0.461212158203125 +98817 0.63763427734375 +98818 0.409210205078125 +98819 0.5660400390625 +98820 0.341064453125 +98821 0.4720458984375 +98822 0.290252685546875 +98823 0.40692138671875 +98824 0.26177978515625 +98825 0.3778076171875 +98826 0.251068115234375 +98827 0.376953125 +98828 0.237640380859375 +98829 0.371978759765625 +98830 0.18975830078125 +98831 0.313140869140625 +98832 0.0975341796875 +98833 0.184417724609375 +98834 -0.022125244140625 +98835 0.011199951171875 +98836 -0.1458740234375 +98837 -0.171051025390625 +98838 -0.257293701171875 +98839 -0.33740234375 +98840 -0.345977783203125 +98841 -0.47198486328125 +98842 -0.402557373046875 +98843 -0.560394287109375 +98844 -0.412841796875 +98845 -0.58056640625 +98846 -0.38677978515625 +98847 -0.54754638671875 +98848 -0.35528564453125 +98849 -0.508575439453125 +98850 -0.3160400390625 +98851 -0.459503173828125 +98852 -0.265625 +98853 -0.394378662109375 +98854 -0.230010986328125 +98855 -0.35260009765625 +98856 -0.195098876953125 +98857 -0.31170654296875 +98858 -0.113250732421875 +98859 -0.197418212890625 +98860 0.016265869140625 +98861 -0.007965087890625 +98862 0.1612548828125 +98863 0.207489013671875 +98864 0.29571533203125 +98865 0.409210205078125 +98866 0.403228759765625 +98867 0.57208251953125 +98868 0.4642333984375 +98869 0.66595458984375 +98870 0.45794677734375 +98871 0.65875244140625 +98872 0.3955078125 +98873 0.56744384765625 +98874 0.302642822265625 +98875 0.431396484375 +98876 0.208038330078125 +98877 0.29443359375 +98878 0.128875732421875 +98879 0.182464599609375 +98880 0.044891357421875 +98881 0.06365966796875 +98882 -0.05255126953125 +98883 -0.075958251953125 +98884 -0.132659912109375 +98885 -0.189422607421875 +98886 -0.19195556640625 +98887 -0.271942138671875 +98888 -0.242462158203125 +98889 -0.342529296875 +98890 -0.260009765625 +98891 -0.364166259765625 +98892 -0.238189697265625 +98893 -0.327239990234375 +98894 -0.20623779296875 +98895 -0.2769775390625 +98896 -0.1903076171875 +98897 -0.253692626953125 +98898 -0.181549072265625 +98899 -0.24365234375 +98900 -0.14874267578125 +98901 -0.1983642578125 +98902 -0.091064453125 +98903 -0.116241455078125 +98904 -0.034393310546875 +98905 -0.036834716796875 +98906 0.0177001953125 +98907 0.034881591796875 +98908 0.0599365234375 +98909 0.09124755859375 +98910 0.076904296875 +98911 0.10888671875 +98912 0.092681884765625 +98913 0.125518798828125 +98914 0.117767333984375 +98915 0.15771484375 +98916 0.13433837890625 +98917 0.17828369140625 +98918 0.13177490234375 +98919 0.17108154296875 +98920 0.106048583984375 +98921 0.129974365234375 +98922 0.074920654296875 +98923 0.082427978515625 +98924 0.037994384765625 +98925 0.027679443359375 +98926 -0.024932861328125 +98927 -0.065643310546875 +98928 -0.0889892578125 +98929 -0.15936279296875 +98930 -0.127777099609375 +98931 -0.21307373046875 +98932 -0.14617919921875 +98933 -0.234649658203125 +98934 -0.12847900390625 +98935 -0.2001953125 +98936 -0.08050537109375 +98937 -0.119171142578125 +98938 -0.0235595703125 +98939 -0.024749755859375 +98940 0.04437255859375 +98941 0.085784912109375 +98942 0.101226806640625 +98943 0.178131103515625 +98944 0.123382568359375 +98945 0.215576171875 +98946 0.119537353515625 +98947 0.211456298828125 +98948 0.09588623046875 +98949 0.17523193359375 +98950 0.066558837890625 +98951 0.128753662109375 +98952 0.05084228515625 +98953 0.1019287109375 +98954 0.035430908203125 +98955 0.0743408203125 +98956 0.01837158203125 +98957 0.04327392578125 +98958 0.01861572265625 +98959 0.038177490234375 +98960 0.047088623046875 +98961 0.076263427734375 +98962 0.0928955078125 +98963 0.14105224609375 +98964 0.12591552734375 +98965 0.186431884765625 +98966 0.13067626953125 +98967 0.188812255859375 +98968 0.101104736328125 +98969 0.1390380859375 +98970 0.040069580078125 +98971 0.041778564453125 +98972 -0.0372314453125 +98973 -0.079437255859375 +98974 -0.12750244140625 +98975 -0.219390869140625 +98976 -0.224029541015625 +98977 -0.367828369140625 +98978 -0.30743408203125 +98979 -0.494873046875 +98980 -0.348968505859375 +98981 -0.556243896484375 +98982 -0.32049560546875 +98983 -0.508697509765625 +98984 -0.23699951171875 +98985 -0.3756103515625 +98986 -0.13848876953125 +98987 -0.218902587890625 +98988 -0.04107666015625 +98989 -0.063751220703125 +98990 0.056488037109375 +98991 0.091552734375 +98992 0.14727783203125 +98993 0.23602294921875 +98994 0.214141845703125 +98995 0.342987060546875 +98996 0.246063232421875 +98997 0.39520263671875 +98998 0.240997314453125 +98999 0.389373779296875 +99000 0.19818115234375 +99001 0.324249267578125 +99002 0.133331298828125 +99003 0.224090576171875 +99004 0.0693359375 +99005 0.124267578125 +99006 0.01409912109375 +99007 0.037078857421875 +99008 -0.014678955078125 +99009 -0.010101318359375 +99010 -0.0185546875 +99011 -0.019439697265625 +99012 -0.018280029296875 +99013 -0.022796630859375 +99014 -0.001953125 +99015 -0.001556396484375 +99016 0.038055419921875 +99017 0.056304931640625 +99018 0.07305908203125 +99019 0.106719970703125 +99020 0.068756103515625 +99021 0.096893310546875 +99022 0.035308837890625 +99023 0.042694091796875 +99024 -0.002838134765625 +99025 -0.018035888671875 +99026 -0.03961181640625 +99027 -0.07586669921875 +99028 -0.06768798828125 +99029 -0.11944580078125 +99030 -0.094146728515625 +99031 -0.15972900390625 +99032 -0.122772216796875 +99033 -0.202606201171875 +99034 -0.15380859375 +99035 -0.24859619140625 +99036 -0.1920166015625 +99037 -0.30517578125 +99038 -0.230743408203125 +99039 -0.36212158203125 +99040 -0.251708984375 +99041 -0.39141845703125 +99042 -0.23028564453125 +99043 -0.35528564453125 +99044 -0.163970947265625 +99045 -0.249969482421875 +99046 -0.06396484375 +99047 -0.092864990234375 +99048 0.0523681640625 +99049 0.08905029296875 +99050 0.145904541015625 +99051 0.2352294921875 +99052 0.199249267578125 +99053 0.318817138671875 +99054 0.22467041015625 +99055 0.358642578125 +99056 0.2176513671875 +99057 0.347747802734375 +99058 0.1778564453125 +99059 0.28564453125 +99060 0.138214111328125 +99061 0.223175048828125 +99062 0.122222900390625 +99063 0.196746826171875 +99064 0.1126708984375 +99065 0.179840087890625 +99066 0.0985107421875 +99067 0.155548095703125 +99068 0.097381591796875 +99069 0.151214599609375 +99070 0.102783203125 +99071 0.156951904296875 +99072 0.08819580078125 +99073 0.13177490234375 +99074 0.069366455078125 +99075 0.100799560546875 +99076 0.06103515625 +99077 0.087127685546875 +99078 0.040924072265625 +99079 0.05487060546875 +99080 0.000885009765625 +99081 -0.009002685546875 +99082 -0.0587158203125 +99083 -0.10400390625 +99084 -0.137420654296875 +99085 -0.229400634765625 +99086 -0.216888427734375 +99087 -0.35552978515625 +99088 -0.272064208984375 +99089 -0.441925048828125 +99090 -0.293792724609375 +99091 -0.473846435546875 +99092 -0.29022216796875 +99093 -0.464813232421875 +99094 -0.26385498046875 +99095 -0.419097900390625 +99096 -0.213104248046875 +99097 -0.334320068359375 +99098 -0.14862060546875 +99099 -0.227935791015625 +99100 -0.084869384765625 +99101 -0.12347412109375 +99102 -0.02593994140625 +99103 -0.02764892578125 +99104 0.039337158203125 +99105 0.077667236328125 +99106 0.12371826171875 +99107 0.2132568359375 +99108 0.233154296875 +99109 0.38885498046875 +99110 0.354217529296875 +99111 0.582794189453125 +99112 0.44921875 +99113 0.734039306640625 +99114 0.49188232421875 +99115 0.800140380859375 +99116 0.480377197265625 +99117 0.7783203125 +99118 0.412506103515625 +99119 0.6651611328125 +99120 0.287567138671875 +99121 0.45965576171875 +99122 0.128509521484375 +99123 0.199188232421875 +99124 -0.024383544921875 +99125 -0.050689697265625 +99126 -0.13604736328125 +99127 -0.23297119140625 +99128 -0.195709228515625 +99129 -0.33013916015625 +99130 -0.219482421875 +99131 -0.368408203125 +99132 -0.226531982421875 +99133 -0.378936767578125 +99134 -0.22625732421875 +99135 -0.376983642578125 +99136 -0.229156494140625 +99137 -0.37969970703125 +99138 -0.237884521484375 +99139 -0.391510009765625 +99140 -0.235687255859375 +99141 -0.385345458984375 +99142 -0.2105712890625 +99143 -0.3419189453125 +99144 -0.175811767578125 +99145 -0.28289794921875 +99146 -0.15802001953125 +99147 -0.251617431640625 +99148 -0.168212890625 +99149 -0.266143798828125 +99150 -0.17364501953125 +99151 -0.273345947265625 +99152 -0.13946533203125 +99153 -0.216796875 +99154 -0.085205078125 +99155 -0.128265380859375 +99156 -0.048095703125 +99157 -0.068145751953125 +99158 -0.0322265625 +99159 -0.0430908203125 +99160 -0.02001953125 +99161 -0.024444580078125 +99162 0.0087890625 +99163 0.020721435546875 +99164 0.073883056640625 +99165 0.124481201171875 +99166 0.1573486328125 +99167 0.25787353515625 +99168 0.23333740234375 +99169 0.379119873046875 +99170 0.296722412109375 +99171 0.47991943359375 +99172 0.32763671875 +99173 0.5281982421875 +99174 0.318145751953125 +99175 0.511138916015625 +99176 0.285125732421875 +99177 0.456207275390625 +99178 0.255706787109375 +99179 0.407470703125 +99180 0.241424560546875 +99181 0.383758544921875 +99182 0.224884033203125 +99183 0.35687255859375 +99184 0.1968994140625 +99185 0.31182861328125 +99186 0.158843994140625 +99187 0.250885009765625 +99188 0.105438232421875 +99189 0.1654052734375 +99190 0.02435302734375 +99191 0.035247802734375 +99192 -0.085906982421875 +99193 -0.142059326171875 +99194 -0.20623779296875 +99195 -0.33563232421875 +99196 -0.329803466796875 +99197 -0.5345458984375 +99198 -0.446136474609375 +99199 -0.72186279296875 +99200 -0.5177001953125 +99201 -0.836669921875 +99202 -0.515899658203125 +99203 -0.8326416015625 +99204 -0.452911376953125 +99205 -0.7296142578125 +99206 -0.36260986328125 +99207 -0.582550048828125 +99208 -0.274932861328125 +99209 -0.440093994140625 +99210 -0.203460693359375 +99211 -0.324310302734375 +99212 -0.12744140625 +99213 -0.20147705078125 +99214 -0.0302734375 +99215 -0.044647216796875 +99216 0.061981201171875 +99217 0.103973388671875 +99218 0.1234130859375 +99219 0.202392578125 +99220 0.16253662109375 +99221 0.264495849609375 +99222 0.209228515625 +99223 0.338897705078125 +99224 0.274658203125 +99225 0.443817138671875 +99226 0.337738037109375 +99227 0.545074462890625 +99228 0.382781982421875 +99229 0.6173095703125 +99230 0.40484619140625 +99231 0.6524658203125 +99232 0.41180419921875 +99233 0.66339111328125 +99234 0.4073486328125 +99235 0.6561279296875 +99236 0.376800537109375 +99237 0.606781005859375 +99238 0.311431884765625 +99239 0.501190185546875 +99240 0.21954345703125 +99241 0.352783203125 +99242 0.110382080078125 +99243 0.176544189453125 +99244 -0.020477294921875 +99245 -0.034820556640625 +99246 -0.15875244140625 +99247 -0.258209228515625 +99248 -0.27288818359375 +99249 -0.44244384765625 +99250 -0.355316162109375 +99251 -0.5753173828125 +99252 -0.403076171875 +99253 -0.65203857421875 +99254 -0.397064208984375 +99255 -0.641632080078125 +99256 -0.348388671875 +99257 -0.562164306640625 +99258 -0.284393310546875 +99259 -0.458038330078125 +99260 -0.21820068359375 +99261 -0.350555419921875 +99262 -0.162628173828125 +99263 -0.260528564453125 +99264 -0.120269775390625 +99265 -0.192108154296875 +99266 -0.08905029296875 +99267 -0.141937255859375 +99268 -0.06414794921875 +99269 -0.1021728515625 +99270 -0.03948974609375 +99271 -0.062896728515625 +99272 -0.007568359375 +99273 -0.011932373046875 +99274 0.03900146484375 +99275 0.062835693359375 +99276 0.0924072265625 +99277 0.148712158203125 +99278 0.150146484375 +99279 0.241729736328125 +99280 0.2166748046875 +99281 0.34912109375 +99282 0.283599853515625 +99283 0.457305908203125 +99284 0.33709716796875 +99285 0.54388427734375 +99286 0.355010986328125 +99287 0.5728759765625 +99288 0.31414794921875 +99289 0.506591796875 +99290 0.218292236328125 +99291 0.351226806640625 +99292 0.0919189453125 +99293 0.146514892578125 +99294 -0.032684326171875 +99295 -0.05523681640625 +99296 -0.132232666015625 +99297 -0.21624755859375 +99298 -0.205718994140625 +99299 -0.334930419921875 +99300 -0.248016357421875 +99301 -0.402984619140625 +99302 -0.27197265625 +99303 -0.4412841796875 +99304 -0.305908203125 +99305 -0.49578857421875 +99306 -0.345855712890625 +99307 -0.5601806640625 +99308 -0.371063232421875 +99309 -0.600738525390625 +99310 -0.361053466796875 +99311 -0.584228515625 +99312 -0.2965087890625 +99313 -0.47930908203125 +99314 -0.173370361328125 +99315 -0.27935791015625 +99316 -0.006744384765625 +99317 -0.0089111328125 +99318 0.164398193359375 +99319 0.268798828125 +99320 0.29638671875 +99321 0.482818603515625 +99322 0.371063232421875 +99323 0.60369873046875 +99324 0.40008544921875 +99325 0.650421142578125 +99326 0.408721923828125 +99327 0.66400146484375 +99328 0.395355224609375 +99329 0.6414794921875 +99330 0.353546142578125 +99331 0.572540283203125 +99332 0.307373046875 +99333 0.498138427734375 +99334 0.26947021484375 +99335 0.439453125 +99336 0.227874755859375 +99337 0.375518798828125 +99338 0.164276123046875 +99339 0.274505615234375 +99340 0.06280517578125 +99341 0.1087646484375 +99342 -0.063201904296875 +99343 -0.099395751953125 +99344 -0.1949462890625 +99345 -0.3182373046875 +99346 -0.33294677734375 +99347 -0.5489501953125 +99348 -0.4666748046875 +99349 -0.7738037109375 +99350 -0.56512451171875 +99351 -0.86383056640625 +99352 -0.60882568359375 +99353 -0.870391845703125 +99354 -0.608154296875 +99355 -0.86895751953125 +99356 -0.570831298828125 +99357 -0.861053466796875 +99358 -0.486846923828125 +99359 -0.765869140625 +99360 -0.349761962890625 +99361 -0.5301513671875 +99362 -0.163909912109375 +99363 -0.214691162109375 +99364 0.045379638671875 +99365 0.137359619140625 +99366 0.2479248046875 +99367 0.474822998046875 +99368 0.422760009765625 +99369 0.76239013671875 +99370 0.553924560546875 +99371 0.867462158203125 +99372 0.641510009765625 +99373 0.870361328125 +99374 0.678619384765625 +99375 0.86480712890625 +99376 0.668304443359375 +99377 0.831817626953125 +99378 0.624725341796875 +99379 0.677581787109375 +99380 0.55126953125 +99381 0.495880126953125 +99382 0.458831787109375 +99383 0.30767822265625 +99384 0.3487548828125 +99385 0.116180419921875 +99386 0.20263671875 +99387 -0.110748291015625 +99388 0.01654052734375 +99389 -0.381805419921875 +99390 -0.184326171875 +99391 -0.6572265625 +99392 -0.364837646484375 +99393 -0.857421875 +99394 -0.499755859375 +99395 -0.870391845703125 +99396 -0.584747314453125 +99397 -0.870391845703125 +99398 -0.635406494140625 +99399 -0.86444091796875 +99400 -0.67242431640625 +99401 -0.85723876953125 +99402 -0.68499755859375 +99403 -0.790008544921875 +99404 -0.641387939453125 +99405 -0.62847900390625 +99406 -0.539703369140625 +99407 -0.3956298828125 +99408 -0.39910888671875 +99409 -0.126708984375 +99410 -0.23565673828125 +99411 0.150115966796875 +99412 -0.0562744140625 +99413 0.424041748046875 +99414 0.123138427734375 +99415 0.670623779296875 +99416 0.279815673828125 +99417 0.854522705078125 +99418 0.403289794921875 +99419 0.866485595703125 +99420 0.48443603515625 +99421 0.86920166015625 +99422 0.53369140625 +99423 0.8653564453125 +99424 0.558746337890625 +99425 0.857147216796875 +99426 0.55780029296875 +99427 0.766845703125 +99428 0.533721923828125 +99429 0.628509521484375 +99430 0.482513427734375 +99431 0.462127685546875 +99432 0.41925048828125 +99433 0.297210693359375 +99434 0.351165771484375 +99435 0.14862060546875 +99436 0.26495361328125 +99437 -0.00537109375 +99438 0.16510009765625 +99439 -0.15753173828125 +99440 0.049560546875 +99441 -0.31304931640625 +99442 -0.0897216796875 +99443 -0.48876953125 +99444 -0.2252197265625 +99445 -0.6416015625 +99446 -0.34234619140625 +99447 -0.751373291015625 +99448 -0.4544677734375 +99449 -0.84619140625 +99450 -0.5528564453125 +99451 -0.861297607421875 +99452 -0.6180419921875 +99453 -0.863250732421875 +99454 -0.631500244140625 +99455 -0.856597900390625 +99456 -0.60028076171875 +99457 -0.7498779296875 +99458 -0.558135986328125 +99459 -0.624542236328125 +99460 -0.492218017578125 +99461 -0.47808837890625 +99462 -0.368408203125 +99463 -0.253387451171875 +99464 -0.21343994140625 +99465 0.003692626953125 +99466 -0.06732177734375 +99467 0.2257080078125 +99468 0.077178955078125 +99469 0.427154541015625 +99470 0.23883056640625 +99471 0.643218994140625 +99472 0.411865234375 +99473 0.855926513671875 +99474 0.56231689453125 +99475 0.870361328125 +99476 0.66107177734375 +99477 0.870361328125 +99478 0.712188720703125 +99479 0.862762451171875 +99480 0.7138671875 +99481 0.79669189453125 +99482 0.6605224609375 +99483 0.595794677734375 +99484 0.5692138671875 +99485 0.362152099609375 +99486 0.456298828125 +99487 0.1270751953125 +99488 0.33416748046875 +99489 -0.086944580078125 +99490 0.2041015625 +99491 -0.2784423828125 +99492 0.04583740234375 +99493 -0.484832763671875 +99494 -0.15167236328125 +99495 -0.729583740234375 +99496 -0.358734130859375 +99497 -0.86688232421875 +99498 -0.538238525390625 +99499 -0.870391845703125 +99500 -0.687103271484375 +99501 -0.86859130859375 +99502 -0.803955078125 +99503 -0.86279296875 +99504 -0.85595703125 +99505 -0.817962646484375 +99506 -0.851593017578125 +99507 -0.6116943359375 +99508 -0.751495361328125 +99509 -0.3128662109375 +99510 -0.5870361328125 +99511 0.039398193359375 +99512 -0.369903564453125 +99513 0.422821044921875 +99514 -0.119598388671875 +99515 0.805145263671875 +99516 0.1240234375 +99517 0.870361328125 +99518 0.3275146484375 +99519 0.870361328125 +99520 0.48382568359375 +99521 0.860015869140625 +99522 0.588226318359375 +99523 0.727935791015625 +99524 0.637176513671875 +99525 0.48114013671875 +99526 0.644561767578125 +99527 0.2059326171875 +99528 0.62335205078125 +99529 -0.06103515625 +99530 0.579193115234375 +99531 -0.29913330078125 +99532 0.503448486328125 +99533 -0.516204833984375 +99534 0.3870849609375 +99535 -0.7252197265625 +99536 0.24462890625 +99537 -0.85980224609375 +99538 0.096221923828125 +99539 -0.870391845703125 +99540 -0.0406494140625 +99541 -0.870391845703125 +99542 -0.13726806640625 +99543 -0.858062744140625 +99544 -0.190826416015625 +99545 -0.673004150390625 +99546 -0.231597900390625 +99547 -0.42694091796875 +99548 -0.285125732421875 +99549 -0.2100830078125 +99550 -0.3497314453125 +99551 -0.0362548828125 +99552 -0.4080810546875 +99553 0.10943603515625 +99554 -0.448211669921875 +99555 0.23516845703125 +99556 -0.4456787109375 +99557 0.373687744140625 +99558 -0.40142822265625 +99559 0.517791748046875 +99560 -0.352142333984375 +99561 0.602783203125 +99562 -0.294830322265625 +99563 0.635711669921875 +99564 -0.21014404296875 +99565 0.655181884765625 +99566 -0.104095458984375 +99567 0.65948486328125 +99568 0.018341064453125 +99569 0.651275634765625 +99570 0.142486572265625 +99571 0.61846923828125 +99572 0.246307373046875 +99573 0.53753662109375 +99574 0.318817138671875 +99575 0.404144287109375 +99576 0.353912353515625 +99577 0.22186279296875 +99578 0.351959228515625 +99579 0.003997802734375 +99580 0.32318115234375 +99581 -0.22100830078125 +99582 0.279327392578125 +99583 -0.42449951171875 +99584 0.23236083984375 +99585 -0.579833984375 +99586 0.206451416015625 +99587 -0.641876220703125 +99588 0.19830322265625 +99589 -0.6177978515625 +99590 0.17205810546875 +99591 -0.575531005859375 +99592 0.124725341796875 +99593 -0.526336669921875 +99594 0.084991455078125 +99595 -0.42645263671875 +99596 0.068267822265625 +99597 -0.2581787109375 +99598 0.0548095703125 +99599 -0.068695068359375 +99600 0.023773193359375 +99601 0.09222412109375 +99602 -0.014068603515625 +99603 0.232147216796875 +99604 -0.052642822265625 +99605 0.3509521484375 +99606 -0.107879638671875 +99607 0.410064697265625 +99608 -0.19561767578125 +99609 0.372955322265625 +99610 -0.303955078125 +99611 0.2554931640625 +99612 -0.4039306640625 +99613 0.10711669921875 +99614 -0.484588623046875 +99615 -0.052886962890625 +99616 -0.52593994140625 +99617 -0.186279296875 +99618 -0.497314453125 +99619 -0.23291015625 +99620 -0.411468505859375 +99621 -0.209442138671875 +99622 -0.3050537109375 +99623 -0.174163818359375 +99624 -0.183013916015625 +99625 -0.126739501953125 +99626 -0.040313720703125 +99627 -0.048126220703125 +99628 0.106964111328125 +99629 0.0426025390625 +99630 0.232635498046875 +99631 0.10748291015625 +99632 0.32891845703125 +99633 0.1409912109375 +99634 0.4217529296875 +99635 0.19708251953125 +99636 0.507049560546875 +99637 0.273651123046875 +99638 0.553741455078125 +99639 0.31768798828125 +99640 0.567779541015625 +99641 0.341094970703125 +99642 0.56304931640625 +99643 0.368011474609375 +99644 0.526885986328125 +99645 0.37249755859375 +99646 0.432220458984375 +99647 0.30072021484375 +99648 0.282012939453125 +99649 0.1517333984375 +99650 0.113311767578125 +99651 -0.01470947265625 +99652 -0.063751220703125 +99653 -0.1883544921875 +99654 -0.24658203125 +99655 -0.372711181640625 +99656 -0.401092529296875 +99657 -0.51397705078125 +99658 -0.50091552734375 +99659 -0.57177734375 +99660 -0.5389404296875 +99661 -0.53948974609375 +99662 -0.52239990234375 +99663 -0.43511962890625 +99664 -0.470245361328125 +99665 -0.2962646484375 +99666 -0.4027099609375 +99667 -0.161102294921875 +99668 -0.32757568359375 +99669 -0.0435791015625 +99670 -0.24365234375 +99671 0.060394287109375 +99672 -0.16064453125 +99673 0.13665771484375 +99674 -0.089508056640625 +99675 0.170135498046875 +99676 -0.0308837890625 +99677 0.16552734375 +99678 0.0306396484375 +99679 0.15728759765625 +99680 0.09429931640625 +99681 0.150787353515625 +99682 0.14312744140625 +99683 0.12200927734375 +99684 0.1787109375 +99685 0.080108642578125 +99686 0.212493896484375 +99687 0.05126953125 +99688 0.25714111328125 +99689 0.062896728515625 +99690 0.298583984375 +99691 0.09271240234375 +99692 0.309539794921875 +99693 0.092987060546875 +99694 0.2979736328125 +99695 0.07855224609375 +99696 0.272735595703125 +99697 0.06427001953125 +99698 0.2266845703125 +99699 0.0347900390625 +99700 0.1607666015625 +99701 -0.01171875 +99702 0.08807373046875 +99703 -0.056060791015625 +99704 0.0350341796875 +99705 -0.055511474609375 +99706 0.0045166015625 +99707 -0.010467529296875 +99708 -0.030181884765625 +99709 0.02508544921875 +99710 -0.0802001953125 +99711 0.025665283203125 +99712 -0.128509521484375 +99713 0.017333984375 +99714 -0.17193603515625 +99715 0.00189208984375 +99716 -0.214935302734375 +99717 -0.03173828125 +99718 -0.249847412109375 +99719 -0.071502685546875 +99720 -0.2862548828125 +99721 -0.13543701171875 +99722 -0.322479248046875 +99723 -0.219970703125 +99724 -0.3458251953125 +99725 -0.300506591796875 +99726 -0.357330322265625 +99727 -0.376312255859375 +99728 -0.341644287109375 +99729 -0.416107177734375 +99730 -0.27410888671875 +99731 -0.371124267578125 +99732 -0.157745361328125 +99733 -0.242279052734375 +99734 -0.017242431640625 +99735 -0.069732666015625 +99736 0.133392333984375 +99737 0.125640869140625 +99738 0.274688720703125 +99739 0.31268310546875 +99740 0.3846435546875 +99741 0.45501708984375 +99742 0.462921142578125 +99743 0.554779052734375 +99744 0.507781982421875 +99745 0.61065673828125 +99746 0.512237548828125 +99747 0.610931396484375 +99748 0.4630126953125 +99749 0.531463623046875 +99750 0.36956787109375 +99751 0.3883056640625 +99752 0.262298583984375 +99753 0.23468017578125 +99754 0.15631103515625 +99755 0.095245361328125 +99756 0.06768798828125 +99757 -0.00396728515625 +99758 0.006378173828125 +99759 -0.04852294921875 +99760 -0.03472900390625 +99761 -0.055145263671875 +99762 -0.082275390625 +99763 -0.0758056640625 +99764 -0.149871826171875 +99765 -0.138702392578125 +99766 -0.216705322265625 +99767 -0.209197998046875 +99768 -0.2823486328125 +99769 -0.289031982421875 +99770 -0.346160888671875 +99771 -0.37884521484375 +99772 -0.395263671875 +99773 -0.456329345703125 +99774 -0.4267578125 +99775 -0.51641845703125 +99776 -0.418975830078125 +99777 -0.519287109375 +99778 -0.368988037109375 +99779 -0.458251953125 +99780 -0.3062744140625 +99781 -0.384796142578125 +99782 -0.245880126953125 +99783 -0.323699951171875 +99784 -0.186248779296875 +99785 -0.269287109375 +99786 -0.114532470703125 +99787 -0.1951904296875 +99788 -0.03167724609375 +99789 -0.100006103515625 +99790 0.04583740234375 +99791 -0.01055908203125 +99792 0.13323974609375 +99793 0.1033935546875 +99794 0.233306884765625 +99795 0.24908447265625 +99796 0.315673828125 +99797 0.373199462890625 +99798 0.370025634765625 +99799 0.45806884765625 +99800 0.400390625 +99801 0.511474609375 +99802 0.424591064453125 +99803 0.565399169921875 +99804 0.43841552734375 +99805 0.61138916015625 +99806 0.40972900390625 +99807 0.5897216796875 +99808 0.334136962890625 +99809 0.4906005859375 +99810 0.222564697265625 +99811 0.33148193359375 +99812 0.095947265625 +99813 0.147796630859375 +99814 -0.021240234375 +99815 -0.01873779296875 +99816 -0.112274169921875 +99817 -0.140289306640625 +99818 -0.162139892578125 +99819 -0.191986083984375 +99820 -0.175537109375 +99821 -0.184295654296875 +99822 -0.176239013671875 +99823 -0.161834716796875 +99824 -0.18682861328125 +99825 -0.166595458984375 +99826 -0.204437255859375 +99827 -0.19390869140625 +99828 -0.218414306640625 +99829 -0.22442626953125 +99830 -0.240997314453125 +99831 -0.279754638671875 +99832 -0.26123046875 +99833 -0.3389892578125 +99834 -0.253570556640625 +99835 -0.3543701171875 +99836 -0.231292724609375 +99837 -0.348175048828125 +99838 -0.198577880859375 +99839 -0.32598876953125 +99840 -0.1402587890625 +99841 -0.2581787109375 +99842 -0.054779052734375 +99843 -0.139801025390625 +99844 0.04876708984375 +99845 0.014617919921875 +99846 0.135955810546875 +99847 0.144378662109375 +99848 0.1904296875 +99849 0.221038818359375 +99850 0.225921630859375 +99851 0.27069091796875 +99852 0.24249267578125 +99853 0.294036865234375 +99854 0.25146484375 +99855 0.311767578125 +99856 0.261322021484375 +99857 0.339141845703125 +99858 0.263336181640625 +99859 0.360260009765625 +99860 0.250213623046875 +99861 0.360504150390625 +99862 0.20654296875 +99863 0.308380126953125 +99864 0.121856689453125 +99865 0.18170166015625 +99866 0.010009765625 +99867 0.0047607421875 +99868 -0.10345458984375 +99869 -0.17559814453125 +99870 -0.194000244140625 +99871 -0.3143310546875 +99872 -0.238006591796875 +99873 -0.36785888671875 +99874 -0.248321533203125 +99875 -0.36248779296875 +99876 -0.247894287109375 +99877 -0.343536376953125 +99878 -0.2315673828125 +99879 -0.3018798828125 +99880 -0.19598388671875 +99881 -0.231414794921875 +99882 -0.133697509765625 +99883 -0.117645263671875 +99884 -0.06182861328125 +99885 0.007049560546875 +99886 -0.009307861328125 +99887 0.087982177734375 +99888 0.030609130859375 +99889 0.13946533203125 +99890 0.06378173828125 +99891 0.17425537109375 +99892 0.087158203125 +99893 0.188201904296875 +99894 0.094573974609375 +99895 0.171234130859375 +99896 0.08258056640625 +99897 0.118438720703125 +99898 0.064544677734375 +99899 0.05706787109375 +99900 0.040863037109375 +99901 -0.010711669921875 +99902 0.007568359375 +99903 -0.0914306640625 +99904 -0.023834228515625 +99905 -0.162322998046875 +99906 -0.03857421875 +99907 -0.194549560546875 +99908 -0.0164794921875 +99909 -0.1492919921875 +99910 0.045135498046875 +99911 -0.02166748046875 +99912 0.11322021484375 +99913 0.124053955078125 +99914 0.14837646484375 +99915 0.211151123046875 +99916 0.151641845703125 +99917 0.240447998046875 +99918 0.13946533203125 +99919 0.242218017578125 +99920 0.117431640625 +99921 0.2257080078125 +99922 0.08807373046875 +99923 0.194366455078125 +99924 0.03509521484375 +99925 0.115509033203125 +99926 -0.028533935546875 +99927 0.0128173828125 +99928 -0.0711669921875 +99929 -0.053802490234375 +99930 -0.1060791015625 +99931 -0.110626220703125 +99932 -0.15484619140625 +99933 -0.199493408203125 +99934 -0.203887939453125 +99935 -0.29437255859375 +99936 -0.220458984375 +99937 -0.33221435546875 +99938 -0.187530517578125 +99939 -0.27972412109375 +99940 -0.13067626953125 +99941 -0.185333251953125 +99942 -0.091522216796875 +99943 -0.128204345703125 +99944 -0.074462890625 +99945 -0.115692138671875 +99946 -0.0638427734375 +99947 -0.116455078125 +99948 -0.047454833984375 +99949 -0.105926513671875 +99950 -0.01025390625 +99951 -0.053955078125 +99952 0.052093505859375 +99953 0.048797607421875 +99954 0.115753173828125 +99955 0.157318115234375 +99956 0.14935302734375 +99957 0.212005615234375 +99958 0.155609130859375 +99959 0.218475341796875 +99960 0.165863037109375 +99961 0.23724365234375 +99962 0.199432373046875 +99963 0.30535888671875 +99964 0.234893798828125 +99965 0.38128662109375 +99966 0.24102783203125 +99967 0.404449462890625 +99968 0.228363037109375 +99969 0.3944091796875 +99970 0.216827392578125 +99971 0.3885498046875 +99972 0.194305419921875 +99973 0.362640380859375 +99974 0.138916015625 +99975 0.27362060546875 +99976 0.04888916015625 +99977 0.11712646484375 +99978 -0.04827880859375 +99979 -0.054901123046875 +99980 -0.125335693359375 +99981 -0.19085693359375 +99982 -0.17938232421875 +99983 -0.28570556640625 +99984 -0.21014404296875 +99985 -0.339263916015625 +99986 -0.23101806640625 +99987 -0.3775634765625 +99988 -0.2655029296875 +99989 -0.445709228515625 +99990 -0.309173583984375 +99991 -0.535064697265625 +99992 -0.3536376953125 +99993 -0.629058837890625 +99994 -0.383514404296875 +99995 -0.697601318359375 +99996 -0.38006591796875 +99997 -0.70391845703125 +99998 -0.340789794921875 +99999 -0.6424560546875 +100000 -0.254669189453125 +100001 -0.491241455078125 +100002 -0.130157470703125 +100003 -0.265716552734375 +100004 0.00225830078125 +100005 -0.023712158203125 +100006 0.125091552734375 +100007 0.201751708984375 +100008 0.219940185546875 +100009 0.375823974609375 +100010 0.27960205078125 +100011 0.485076904296875 +100012 0.324432373046875 +100013 0.56884765625 +100014 0.3583984375 +100015 0.634765625 +100016 0.3580322265625 +100017 0.63763427734375 +100018 0.317535400390625 +100019 0.5660400390625 +100020 0.26422119140625 +100021 0.4720458984375 +100022 0.225006103515625 +100023 0.40692138671875 +100024 0.203948974609375 +100025 0.3778076171875 +100026 0.197357177734375 +100027 0.376953125 +100028 0.188720703125 +100029 0.371978759765625 +100030 0.15252685546875 +100031 0.313140869140625 +100032 0.0806884765625 +100033 0.184417724609375 +100034 -0.0133056640625 +100035 0.011199951171875 +100036 -0.110809326171875 +100037 -0.171051025390625 +100038 -0.198760986328125 +100039 -0.33740234375 +100040 -0.268829345703125 +100041 -0.47198486328125 +100042 -0.3135986328125 +100043 -0.560394287109375 +100044 -0.321685791015625 +100045 -0.58056640625 +100046 -0.30108642578125 +100047 -0.54754638671875 +100048 -0.276580810546875 +100049 -0.508575439453125 +100050 -0.24627685546875 +100051 -0.459503173828125 +100052 -0.207366943359375 +100053 -0.394378662109375 +100054 -0.18060302734375 +100055 -0.35260009765625 +100056 -0.154571533203125 +100057 -0.31170654296875 +100058 -0.090911865234375 +100059 -0.197418212890625 +100060 0.01104736328125 +100061 -0.007965087890625 +100062 0.125579833984375 +100063 0.207489013671875 +100064 0.23193359375 +100065 0.409210205078125 +100066 0.3170166015625 +100067 0.57208251953125 +100068 0.365142822265625 +100069 0.66595458984375 +100070 0.359710693359375 +100071 0.65875244140625 +100072 0.30963134765625 +100073 0.56744384765625 +100074 0.235565185546875 +100075 0.431396484375 +100076 0.1605224609375 +100077 0.29443359375 +100078 0.098175048828125 +100079 0.182464599609375 +100080 0.0322265625 +100081 0.06365966796875 +100082 -0.044342041015625 +100083 -0.075958251953125 +100084 -0.10693359375 +100085 -0.189422607421875 +100086 -0.152862548828125 +100087 -0.271942138671875 +100088 -0.19183349609375 +100089 -0.342529296875 +100090 -0.204559326171875 +100091 -0.364166259765625 +100092 -0.18597412109375 +100093 -0.327239990234375 +100094 -0.159576416015625 +100095 -0.2769775390625 +100096 -0.146087646484375 +100097 -0.253692626953125 +100098 -0.138702392578125 +100099 -0.24365234375 +100100 -0.1134033203125 +100101 -0.1983642578125 +100102 -0.069488525390625 +100103 -0.116241455078125 +100104 -0.026336669921875 +100105 -0.036834716796875 +100106 0.013427734375 +100107 0.034881591796875 +100108 0.04583740234375 +100109 0.09124755859375 +100110 0.059234619140625 +100111 0.10888671875 +100112 0.071746826171875 +100113 0.125518798828125 +100114 0.09124755859375 +100115 0.15771484375 +100116 0.104248046875 +100117 0.17828369140625 +100118 0.10272216796875 +100119 0.17108154296875 +100120 0.083587646484375 +100121 0.129974365234375 +100122 0.060211181640625 +100123 0.082427978515625 +100124 0.032257080078125 +100125 0.027679443359375 +100126 -0.015472412109375 +100127 -0.065643310546875 +100128 -0.064178466796875 +100129 -0.15936279296875 +100130 -0.093994140625 +100131 -0.21307373046875 +100132 -0.108551025390625 +100133 -0.234649658203125 +100134 -0.095947265625 +100135 -0.2001953125 +100136 -0.060577392578125 +100137 -0.119171142578125 +100138 -0.018402099609375 +100139 -0.024749755859375 +100140 0.032073974609375 +100141 0.085784912109375 +100142 0.074310302734375 +100143 0.178131103515625 +100144 0.09051513671875 +100145 0.215576171875 +100146 0.0872802734375 +100147 0.211456298828125 +100148 0.06927490234375 +100149 0.17523193359375 +100150 0.04718017578125 +100151 0.128753662109375 +100152 0.0355224609375 +100153 0.1019287109375 +100154 0.02423095703125 +100155 0.0743408203125 +100156 0.0118408203125 +100157 0.04327392578125 +100158 0.012542724609375 +100159 0.038177490234375 +100160 0.034576416015625 +100161 0.076263427734375 +100162 0.069671630859375 +100163 0.14105224609375 +100164 0.09515380859375 +100165 0.186431884765625 +100166 0.099334716796875 +100167 0.188812255859375 +100168 0.07757568359375 +100169 0.1390380859375 +100170 0.03204345703125 +100171 0.041778564453125 +100172 -0.025848388671875 +100173 -0.079437255859375 +100174 -0.093597412109375 +100175 -0.219390869140625 +100176 -0.16619873046875 +100177 -0.367828369140625 +100178 -0.229034423828125 +100179 -0.494873046875 +100180 -0.260467529296875 +100181 -0.556243896484375 +100182 -0.239288330078125 +100183 -0.508697509765625 +100184 -0.176788330078125 +100185 -0.3756103515625 +100186 -0.10302734375 +100187 -0.218902587890625 +100188 -0.030120849609375 +100189 -0.063751220703125 +100190 0.042877197265625 +100191 0.091552734375 +100192 0.110748291015625 +100193 0.23602294921875 +100194 0.160614013671875 +100195 0.342987060546875 +100196 0.1842041015625 +100197 0.39520263671875 +100198 0.17999267578125 +100199 0.389373779296875 +100200 0.147430419921875 +100201 0.324249267578125 +100202 0.098388671875 +100203 0.224090576171875 +100204 0.050140380859375 +100205 0.124267578125 +100206 0.00860595703125 +100207 0.037078857421875 +100208 -0.012908935546875 +100209 -0.010101318359375 +100210 -0.01556396484375 +100211 -0.019439697265625 +100212 -0.0150146484375 +100213 -0.022796630859375 +100214 -0.002288818359375 +100215 -0.001556396484375 +100216 0.0283203125 +100217 0.056304931640625 +100218 0.05517578125 +100219 0.106719970703125 +100220 0.05242919921875 +100221 0.096893310546875 +100222 0.027679443359375 +100223 0.042694091796875 +100224 -0.00067138671875 +100225 -0.018035888671875 +100226 -0.028076171875 +100227 -0.07586669921875 +100228 -0.04901123046875 +100229 -0.11944580078125 +100230 -0.06884765625 +100231 -0.15972900390625 +100232 -0.0904541015625 +100233 -0.202606201171875 +100234 -0.113983154296875 +100235 -0.24859619140625 +100236 -0.143035888671875 +100237 -0.30517578125 +100238 -0.17254638671875 +100239 -0.36212158203125 +100240 -0.188720703125 +100241 -0.39141845703125 +100242 -0.173004150390625 +100243 -0.35528564453125 +100244 -0.12347412109375 +100245 -0.249969482421875 +100246 -0.04852294921875 +100247 -0.092864990234375 +100248 0.03875732421875 +100249 0.08905029296875 +100250 0.10888671875 +100251 0.2352294921875 +100252 0.148834228515625 +100253 0.318817138671875 +100254 0.167816162109375 +100255 0.358642578125 +100256 0.162445068359375 +100257 0.347747802734375 +100258 0.132476806640625 +100259 0.28564453125 +100260 0.102691650390625 +100261 0.223175048828125 +100262 0.090789794921875 +100263 0.196746826171875 +100264 0.08380126953125 +100265 0.179840087890625 +100266 0.073394775390625 +100267 0.155548095703125 +100268 0.07281494140625 +100269 0.151214599609375 +100270 0.0771484375 +100271 0.156951904296875 +100272 0.066314697265625 +100273 0.13177490234375 +100274 0.052520751953125 +100275 0.100799560546875 +100276 0.04693603515625 +100277 0.087127685546875 +100278 0.032012939453125 +100279 0.05487060546875 +100280 0.0013427734375 +100281 -0.009002685546875 +100282 -0.044830322265625 +100283 -0.10400390625 +100284 -0.10614013671875 +100285 -0.229400634765625 +100286 -0.1680908203125 +100287 -0.35552978515625 +100288 -0.210906982421875 +100289 -0.441925048828125 +100290 -0.227386474609375 +100291 -0.473846435546875 +100292 -0.22406005859375 +100293 -0.464813232421875 +100294 -0.202911376953125 +100295 -0.419097900390625 +100296 -0.1627197265625 +100297 -0.334320068359375 +100298 -0.111968994140625 +100299 -0.227935791015625 +100300 -0.06207275390625 +100301 -0.12347412109375 +100302 -0.0162353515625 +100303 -0.02764892578125 +100304 0.034423828125 +100305 0.077667236328125 +100306 0.100067138671875 +100307 0.2132568359375 +100308 0.185455322265625 +100309 0.38885498046875 +100310 0.280029296875 +100311 0.582794189453125 +100312 0.35400390625 +100313 0.734039306640625 +100314 0.38665771484375 +100315 0.800140380859375 +100316 0.3765869140625 +100317 0.7783203125 +100318 0.322113037109375 +100319 0.6651611328125 +100320 0.222686767578125 +100321 0.45965576171875 +100322 0.09649658203125 +100323 0.199188232421875 +100324 -0.024505615234375 +100325 -0.050689697265625 +100326 -0.112548828125 +100327 -0.23297119140625 +100328 -0.159149169921875 +100329 -0.33013916015625 +100330 -0.177093505859375 +100331 -0.368408203125 +100332 -0.181640625 +100333 -0.378936767578125 +100334 -0.1802978515625 +100335 -0.376983642578125 +100336 -0.18145751953125 +100337 -0.37969970703125 +100338 -0.187255859375 +100339 -0.391510009765625 +100340 -0.1844482421875 +100341 -0.385345458984375 +100342 -0.16363525390625 +100343 -0.3419189453125 +100344 -0.1353759765625 +100345 -0.28289794921875 +100346 -0.12078857421875 +100347 -0.251617431640625 +100348 -0.12860107421875 +100349 -0.266143798828125 +100350 -0.13287353515625 +100351 -0.273345947265625 +100352 -0.106170654296875 +100353 -0.216796875 +100354 -0.06365966796875 +100355 -0.128265380859375 +100356 -0.0338134765625 +100357 -0.068145751953125 +100358 -0.019805908203125 +100359 -0.0430908203125 +100360 -0.008697509765625 +100361 -0.024444580078125 +100362 0.01434326171875 +100363 0.020721435546875 +100364 0.06378173828125 +100365 0.124481201171875 +100366 0.126312255859375 +100367 0.25787353515625 +100368 0.182769775390625 +100369 0.379119873046875 +100370 0.229339599609375 +100371 0.47991943359375 +100372 0.251373291015625 +100373 0.5281982421875 +100374 0.243011474609375 +100375 0.511138916015625 +100376 0.216827392578125 +100377 0.456207275390625 +100378 0.193023681640625 +100379 0.407470703125 +100380 0.1802978515625 +100381 0.383758544921875 +100382 0.1658935546875 +100383 0.35687255859375 +100384 0.143096923828125 +100385 0.31182861328125 +100386 0.113037109375 +100387 0.250885009765625 +100388 0.071929931640625 +100389 0.1654052734375 +100390 0.010711669921875 +100391 0.035247802734375 +100392 -0.071624755859375 +100393 -0.142059326171875 +100394 -0.160919189453125 +100395 -0.33563232421875 +100396 -0.252166748046875 +100397 -0.5345458984375 +100398 -0.337615966796875 +100399 -0.72186279296875 +100400 -0.389495849609375 +100401 -0.836669921875 +100402 -0.386749267578125 +100403 -0.8326416015625 +100404 -0.3385009765625 +100405 -0.7296142578125 +100406 -0.2698974609375 +100407 -0.582550048828125 +100408 -0.20318603515625 +100409 -0.440093994140625 +100410 -0.1485595703125 +100411 -0.324310302734375 +100412 -0.0906982421875 +100413 -0.20147705078125 +100414 -0.017425537109375 +100415 -0.044647216796875 +100416 0.051910400390625 +100417 0.103973388671875 +100418 0.098052978515625 +100419 0.202392578125 +100420 0.12725830078125 +100421 0.264495849609375 +100422 0.16168212890625 +100423 0.338897705078125 +100424 0.209625244140625 +100425 0.443817138671875 +100426 0.2554931640625 +100427 0.545074462890625 +100428 0.287750244140625 +100429 0.6173095703125 +100430 0.302764892578125 +100431 0.6524658203125 +100432 0.30645751953125 +100433 0.66339111328125 +100434 0.301666259765625 +100435 0.6561279296875 +100436 0.277587890625 +100437 0.606781005859375 +100438 0.22784423828125 +100439 0.501190185546875 +100440 0.158660888671875 +100441 0.352783203125 +100442 0.076934814453125 +100443 0.176544189453125 +100444 -0.020538330078125 +100445 -0.034820556640625 +100446 -0.1231689453125 +100447 -0.258209228515625 +100448 -0.20758056640625 +100449 -0.44244384765625 +100450 -0.268218994140625 +100451 -0.5753173828125 +100452 -0.30291748046875 +100453 -0.65203857421875 +100454 -0.297576904296875 +100455 -0.641632080078125 +100456 -0.260467529296875 +100457 -0.562164306640625 +100458 -0.2119140625 +100459 -0.458038330078125 +100460 -0.16168212890625 +100461 -0.350555419921875 +100462 -0.11932373046875 +100463 -0.260528564453125 +100464 -0.086822509765625 +100465 -0.192108154296875 +100466 -0.062713623046875 +100467 -0.141937255859375 +100468 -0.043487548828125 +100469 -0.1021728515625 +100470 -0.024658203125 +100471 -0.062896728515625 +100472 -0.000701904296875 +100473 -0.011932373046875 +100474 0.033843994140625 +100475 0.062835693359375 +100476 0.07318115234375 +100477 0.148712158203125 +100478 0.115478515625 +100479 0.241729736328125 +100480 0.164031982421875 +100481 0.34912109375 +100482 0.212677001953125 +100483 0.457305908203125 +100484 0.251251220703125 +100485 0.54388427734375 +100486 0.263427734375 +100487 0.5728759765625 +100488 0.232086181640625 +100489 0.506591796875 +100490 0.16009521484375 +100491 0.351226806640625 +100492 0.065643310546875 +100493 0.146514892578125 +100494 -0.02734375 +100495 -0.05523681640625 +100496 -0.101593017578125 +100497 -0.21624755859375 +100498 -0.156341552734375 +100499 -0.334930419921875 +100500 -0.187774658203125 +100501 -0.402984619140625 +100502 -0.20538330078125 +100503 -0.4412841796875 +100504 -0.230133056640625 +100505 -0.49578857421875 +100506 -0.2591552734375 +100507 -0.5601806640625 +100508 -0.277099609375 +100509 -0.600738525390625 +100510 -0.268829345703125 +100511 -0.584228515625 +100512 -0.220123291015625 +100513 -0.47930908203125 +100514 -0.128021240234375 +100515 -0.27935791015625 +100516 -0.003753662109375 +100517 -0.0089111328125 +100518 0.123748779296875 +100519 0.268798828125 +100520 0.222137451171875 +100521 0.482818603515625 +100522 0.277923583984375 +100523 0.60369873046875 +100524 0.299713134765625 +100525 0.650421142578125 +100526 0.30621337890625 +100527 0.66400146484375 +100528 0.296051025390625 +100529 0.6414794921875 +100530 0.2645263671875 +100531 0.572540283203125 +100532 0.230316162109375 +100533 0.498138427734375 +100534 0.203094482421875 +100535 0.439453125 +100536 0.173370361328125 +100537 0.375518798828125 +100538 0.12664794921875 +100539 0.274505615234375 +100540 0.05035400390625 +100541 0.1087646484375 +100542 -0.0452880859375 +100543 -0.099395751953125 +100544 -0.145782470703125 +100545 -0.3182373046875 +100546 -0.251617431640625 +100547 -0.5489501953125 +100548 -0.35467529296875 +100549 -0.7738037109375 +100550 -0.4307861328125 +100551 -0.86383056640625 +100552 -0.464752197265625 +100553 -0.870391845703125 +100554 -0.46466064453125 +100555 -0.86895751953125 +100556 -0.436492919921875 +100557 -0.861053466796875 +100558 -0.37237548828125 +100559 -0.765869140625 +100560 -0.26715087890625 +100561 -0.5301513671875 +100562 -0.124114990234375 +100563 -0.214691162109375 +100564 0.037078857421875 +100565 0.137359619140625 +100566 0.1929931640625 +100567 0.474822998046875 +100568 0.327362060546875 +100569 0.76239013671875 +100570 0.427825927734375 +100571 0.867462158203125 +100572 0.49456787109375 +100573 0.870361328125 +100574 0.522308349609375 +100575 0.86480712890625 +100576 0.513458251953125 +100577 0.831817626953125 +100578 0.4791259765625 +100579 0.677581787109375 +100580 0.42193603515625 +100581 0.495880126953125 +100582 0.35040283203125 +100583 0.30767822265625 +100584 0.2655029296875 +100585 0.116180419921875 +100586 0.152801513671875 +100587 -0.110748291015625 +100588 0.009185791015625 +100589 -0.381805419921875 +100590 -0.14581298828125 +100591 -0.6572265625 +100592 -0.28485107421875 +100593 -0.857421875 +100594 -0.388336181640625 +100595 -0.870391845703125 +100596 -0.4530029296875 +100597 -0.870391845703125 +100598 -0.4910888671875 +100599 -0.86444091796875 +100600 -0.518829345703125 +100601 -0.85723876953125 +100602 -0.52783203125 +100603 -0.790008544921875 +100604 -0.49334716796875 +100605 -0.62847900390625 +100606 -0.413909912109375 +100607 -0.3956298828125 +100608 -0.3045654296875 +100609 -0.126708984375 +100610 -0.17779541015625 +100611 0.150115966796875 +100612 -0.039276123046875 +100613 0.424041748046875 +100614 0.098876953125 +100615 0.670623779296875 +100616 0.21966552734375 +100617 0.854522705078125 +100618 0.315093994140625 +100619 0.866485595703125 +100620 0.37823486328125 +100621 0.86920166015625 +100622 0.41650390625 +100623 0.8653564453125 +100624 0.4354248046875 +100625 0.857147216796875 +100626 0.433685302734375 +100627 0.766845703125 +100628 0.413543701171875 +100629 0.628509521484375 +100630 0.372314453125 +100631 0.462127685546875 +100632 0.3211669921875 +100633 0.297210693359375 +100634 0.265716552734375 +100635 0.14862060546875 +100636 0.1966552734375 +100637 -0.00537109375 +100638 0.11761474609375 +100639 -0.15753173828125 +100640 0.027496337890625 +100641 -0.31304931640625 +100642 -0.079193115234375 +100643 -0.48876953125 +100644 -0.182220458984375 +100645 -0.6416015625 +100646 -0.270751953125 +100647 -0.751373291015625 +100648 -0.35430908203125 +100649 -0.84619140625 +100650 -0.426513671875 +100651 -0.861297607421875 +100652 -0.47320556640625 +100653 -0.863250732421875 +100654 -0.480987548828125 +100655 -0.856597900390625 +100656 -0.455108642578125 +100657 -0.7498779296875 +100658 -0.420318603515625 +100659 -0.624542236328125 +100660 -0.367523193359375 +100661 -0.47808837890625 +100662 -0.27227783203125 +100663 -0.253387451171875 +100664 -0.154266357421875 +100665 0.003692626953125 +100666 -0.042877197265625 +100667 0.2257080078125 +100668 0.066802978515625 +100669 0.427154541015625 +100670 0.188201904296875 +100671 0.643218994140625 +100672 0.31695556640625 +100673 0.855926513671875 +100674 0.42822265625 +100675 0.870361328125 +100676 0.500823974609375 +100677 0.870361328125 +100678 0.537689208984375 +100679 0.862762451171875 +100680 0.53753662109375 +100681 0.79669189453125 +100682 0.496429443359375 +100683 0.595794677734375 +100684 0.4268798828125 +100685 0.362152099609375 +100686 0.340972900390625 +100687 0.1270751953125 +100688 0.2479248046875 +100689 -0.086944580078125 +100690 0.148956298828125 +100691 -0.2784423828125 +100692 0.02960205078125 +100693 -0.484832763671875 +100694 -0.117889404296875 +100695 -0.729583740234375 +100696 -0.27178955078125 +100697 -0.86688232421875 +100698 -0.404937744140625 +100699 -0.870391845703125 +100700 -0.514984130859375 +100701 -0.86859130859375 +100702 -0.600830078125 +100703 -0.86279296875 +100704 -0.6470947265625 +100705 -0.817962646484375 +100706 -0.634490966796875 +100707 -0.6116943359375 +100708 -0.56005859375 +100709 -0.3128662109375 +100710 -0.43817138671875 +100711 0.039398193359375 +100712 -0.2774658203125 +100713 0.422821044921875 +100714 -0.092254638671875 +100715 0.805145263671875 +100716 0.0882568359375 +100717 0.870361328125 +100718 0.239593505859375 +100719 0.870361328125 +100720 0.356475830078125 +100721 0.860015869140625 +100722 0.435302734375 +100723 0.727935791015625 +100724 0.473358154296875 +100725 0.48114013671875 +100726 0.480560302734375 +100727 0.2059326171875 +100728 0.46624755859375 +100729 -0.06103515625 +100730 0.43450927734375 +100731 -0.29913330078125 +100732 0.37908935546875 +100733 -0.516204833984375 +100734 0.29345703125 +100735 -0.7252197265625 +100736 0.188262939453125 +100737 -0.85980224609375 +100738 0.0782470703125 +100739 -0.870391845703125 +100740 -0.023773193359375 +100741 -0.870391845703125 +100742 -0.0968017578125 +100743 -0.858062744140625 +100744 -0.138641357421875 +100745 -0.673004150390625 +100746 -0.171112060546875 +100747 -0.42694091796875 +100748 -0.212615966796875 +100749 -0.2100830078125 +100750 -0.26177978515625 +100751 -0.0362548828125 +100752 -0.305877685546875 +100753 0.10943603515625 +100754 -0.336151123046875 +100755 0.23516845703125 +100756 -0.334808349609375 +100757 0.373687744140625 +100758 -0.302520751953125 +100759 0.517791748046875 +100760 -0.2659912109375 +100761 0.602783203125 +100762 -0.22308349609375 +100763 0.635711669921875 +100764 -0.15985107421875 +100765 0.655181884765625 +100766 -0.080718994140625 +100767 0.65948486328125 +100768 0.010498046875 +100769 0.651275634765625 +100770 0.10302734375 +100771 0.61846923828125 +100772 0.180755615234375 +100773 0.53753662109375 +100774 0.235565185546875 +100775 0.404144287109375 +100776 0.262939453125 +100777 0.22186279296875 +100778 0.263031005859375 +100779 0.003997802734375 +100780 0.243194580078125 +100781 -0.22100830078125 +100782 0.2119140625 +100783 -0.42449951171875 +100784 0.1781005859375 +100785 -0.579833984375 +100786 0.159820556640625 +100787 -0.641876220703125 +100788 0.154266357421875 +100789 -0.6177978515625 +100790 0.134185791015625 +100791 -0.575531005859375 +100792 0.097503662109375 +100793 -0.526336669921875 +100794 0.06646728515625 +100795 -0.42645263671875 +100796 0.053009033203125 +100797 -0.2581787109375 +100798 0.0421142578125 +100799 -0.068695068359375 +100800 0.017852783203125 +100801 0.09222412109375 +100802 -0.011474609375 +100803 0.232147216796875 +100804 -0.041168212890625 +100805 0.3509521484375 +100806 -0.08349609375 +100807 0.410064697265625 +100808 -0.150604248046875 +100809 0.372955322265625 +100810 -0.23345947265625 +100811 0.2554931640625 +100812 -0.309814453125 +100813 0.10711669921875 +100814 -0.371337890625 +100815 -0.052886962890625 +100816 -0.4027099609375 +100817 -0.186279296875 +100818 -0.380340576171875 +100819 -0.23291015625 +100820 -0.3140869140625 +100821 -0.209442138671875 +100822 -0.232147216796875 +100823 -0.174163818359375 +100824 -0.138336181640625 +100825 -0.126739501953125 +100826 -0.02880859375 +100827 -0.048126220703125 +100828 0.084136962890625 +100829 0.0426025390625 +100830 0.180389404296875 +100831 0.10748291015625 +100832 0.2540283203125 +100833 0.1409912109375 +100834 0.32489013671875 +100835 0.19708251953125 +100836 0.389923095703125 +100837 0.273651123046875 +100838 0.42529296875 +100839 0.31768798828125 +100840 0.43560791015625 +100841 0.341094970703125 +100842 0.4315185546875 +100843 0.368011474609375 +100844 0.403350830078125 +100845 0.37249755859375 +100846 0.330322265625 +100847 0.30072021484375 +100848 0.2147216796875 +100849 0.1517333984375 +100850 0.08502197265625 +100851 -0.01470947265625 +100852 -0.05096435546875 +100853 -0.1883544921875 +100854 -0.191253662109375 +100855 -0.372711181640625 +100856 -0.309661865234375 +100857 -0.51397705078125 +100858 -0.385986328125 +100859 -0.57177734375 +100860 -0.414794921875 +100861 -0.53948974609375 +100862 -0.40167236328125 +100863 -0.43511962890625 +100864 -0.3614501953125 +100865 -0.2962646484375 +100866 -0.309814453125 +100867 -0.161102294921875 +100868 -0.252593994140625 +100869 -0.0435791015625 +100870 -0.188812255859375 +100871 0.060394287109375 +100872 -0.125457763671875 +100873 0.13665771484375 +100874 -0.070465087890625 +100875 0.170135498046875 +100876 -0.02435302734375 +100877 0.16552734375 +100878 0.023895263671875 +100879 0.15728759765625 +100880 0.0736083984375 +100881 0.150787353515625 +100882 0.1123046875 +100883 0.12200927734375 +100884 0.1409912109375 +100885 0.080108642578125 +100886 0.16778564453125 +100887 0.05126953125 +100888 0.201751708984375 +100889 0.062896728515625 +100890 0.23260498046875 +100891 0.09271240234375 +100892 0.240509033203125 +100893 0.092987060546875 +100894 0.231292724609375 +100895 0.07855224609375 +100896 0.21136474609375 +100897 0.06427001953125 +100898 0.1756591796875 +100899 0.0347900390625 +100900 0.125 +100901 -0.01171875 +100902 0.069061279296875 +100903 -0.056060791015625 +100904 0.027191162109375 +100905 -0.055511474609375 +100906 0.001617431640625 +100907 -0.010467529296875 +100908 -0.02679443359375 +100909 0.02508544921875 +100910 -0.06591796875 +100911 0.025665283203125 +100912 -0.103302001953125 +100913 0.017333984375 +100914 -0.13653564453125 +100915 0.00189208984375 +100916 -0.16876220703125 +100917 -0.03173828125 +100918 -0.19439697265625 +100919 -0.071502685546875 +100920 -0.220367431640625 +100921 -0.13543701171875 +100922 -0.245513916015625 +100923 -0.219970703125 +100924 -0.26068115234375 +100925 -0.300506591796875 +100926 -0.266754150390625 +100927 -0.376312255859375 +100928 -0.252777099609375 +100929 -0.416107177734375 +100930 -0.2010498046875 +100931 -0.371124267578125 +100932 -0.113861083984375 +100933 -0.242279052734375 +100934 -0.00927734375 +100935 -0.069732666015625 +100936 0.102386474609375 +100937 0.125640869140625 +100938 0.206878662109375 +100939 0.31268310546875 +100940 0.288177490234375 +100941 0.45501708984375 +100942 0.345947265625 +100943 0.554779052734375 +100944 0.37890625 +100945 0.61065673828125 +100946 0.381988525390625 +100947 0.610931396484375 +100948 0.3455810546875 +100949 0.531463623046875 +100950 0.276580810546875 +100951 0.3883056640625 +100952 0.1971435546875 +100953 0.23468017578125 +100954 0.1182861328125 +100955 0.095245361328125 +100956 0.05181884765625 +100957 -0.00396728515625 +100958 0.00506591796875 +100959 -0.04852294921875 +100960 -0.027008056640625 +100961 -0.055145263671875 +100962 -0.063568115234375 +100963 -0.0758056640625 +100964 -0.1143798828125 +100965 -0.138702392578125 +100966 -0.164276123046875 +100967 -0.209197998046875 +100968 -0.212860107421875 +100969 -0.289031982421875 +100970 -0.259674072265625 +100971 -0.37884521484375 +100972 -0.295318603515625 +100973 -0.456329345703125 +100974 -0.31768798828125 +100975 -0.51641845703125 +100976 -0.3111572265625 +100977 -0.519287109375 +100978 -0.27362060546875 +100979 -0.458251953125 +100980 -0.2265625 +100981 -0.384796142578125 +100982 -0.18096923828125 +100983 -0.323699951171875 +100984 -0.13580322265625 +100985 -0.269287109375 +100986 -0.081878662109375 +100987 -0.1951904296875 +100988 -0.019989013671875 +100989 -0.100006103515625 +100990 0.037841796875 +100991 -0.01055908203125 +100992 0.1025390625 +100993 0.1033935546875 +100994 0.176055908203125 +100995 0.24908447265625 +100996 0.236328125 +100997 0.373199462890625 +100998 0.275848388671875 +100999 0.45806884765625 +101000 0.297576904296875 +101001 0.511474609375 +101002 0.314422607421875 +101003 0.565399169921875 +101004 0.32342529296875 +101005 0.61138916015625 +101006 0.30133056640625 +101007 0.5897216796875 +101008 0.24505615234375 +101009 0.4906005859375 +101010 0.16259765625 +101011 0.33148193359375 +101012 0.0692138671875 +101013 0.147796630859375 +101014 -0.01727294921875 +101015 -0.01873779296875 +101016 -0.084625244140625 +101017 -0.140289306640625 +101018 -0.121917724609375 +101019 -0.191986083984375 +101020 -0.13250732421875 +101021 -0.184295654296875 +101022 -0.133575439453125 +101023 -0.161834716796875 +101024 -0.141448974609375 +101025 -0.166595458984375 +101026 -0.154083251953125 +101027 -0.19390869140625 +101028 -0.163726806640625 +101029 -0.22442626953125 +101030 -0.179290771484375 +101031 -0.279754638671875 +101032 -0.192901611328125 +101033 -0.3389892578125 +101034 -0.1861572265625 +101035 -0.3543701171875 +101036 -0.168731689453125 +101037 -0.348175048828125 +101038 -0.143707275390625 +101039 -0.32598876953125 +101040 -0.100189208984375 +101041 -0.2581787109375 +101042 -0.037078857421875 +101043 -0.139801025390625 +101044 0.038970947265625 +101045 0.014617919921875 +101046 0.1029052734375 +101047 0.144378662109375 +101048 0.142822265625 +101049 0.221038818359375 +101050 0.168701171875 +101051 0.27069091796875 +101052 0.18060302734375 +101053 0.294036865234375 +101054 0.186737060546875 +101055 0.311767578125 +101056 0.193328857421875 +101057 0.339141845703125 +101058 0.194305419921875 +101059 0.360260009765625 +101060 0.184295654296875 +101061 0.360504150390625 +101062 0.151611328125 +101063 0.308380126953125 +101064 0.088348388671875 +101065 0.18170166015625 +101066 0.004852294921875 +101067 0.0047607421875 +101068 -0.0797119140625 +101069 -0.17559814453125 +101070 -0.146942138671875 +101071 -0.3143310546875 +101072 -0.179107666015625 +101073 -0.36785888671875 +101074 -0.185943603515625 +101075 -0.36248779296875 +101076 -0.184783935546875 +101077 -0.343536376953125 +101078 -0.17181396484375 +101079 -0.3018798828125 +101080 -0.144500732421875 +101081 -0.231414794921875 +101082 -0.097259521484375 +101083 -0.117645263671875 +101084 -0.042999267578125 +101085 0.007049560546875 +101086 -0.0035400390625 +101087 0.087982177734375 +101088 0.026214599609375 +101089 0.13946533203125 +101090 0.05072021484375 +101091 0.17425537109375 +101092 0.06768798828125 +101093 0.188201904296875 +101094 0.072540283203125 +101095 0.171234130859375 +101096 0.062744140625 +101097 0.118438720703125 +101098 0.04840087890625 +101099 0.05706787109375 +101100 0.02984619140625 +101101 -0.010711669921875 +101102 0.004119873046875 +101103 -0.0914306640625 +101104 -0.02008056640625 +101105 -0.162322998046875 +101106 -0.031585693359375 +101107 -0.194549560546875 +101108 -0.015167236328125 +101109 -0.1492919921875 +101110 0.031219482421875 +101111 -0.02166748046875 +101112 0.0826416015625 +101113 0.124053955078125 +101114 0.109375 +101115 0.211151123046875 +101116 0.112213134765625 +101117 0.240447998046875 +101118 0.103515625 +101119 0.242218017578125 +101120 0.086944580078125 +101121 0.2257080078125 +101122 0.06463623046875 +101123 0.194366455078125 +101124 0.025970458984375 +101125 0.115509033203125 +101126 -0.019927978515625 +101127 0.0128173828125 +101128 -0.05108642578125 +101129 -0.053802490234375 +101130 -0.076629638671875 +101131 -0.110626220703125 +101132 -0.111480712890625 +101133 -0.199493408203125 +101134 -0.146148681640625 +101135 -0.29437255859375 +101136 -0.15802001953125 +101137 -0.33221435546875 +101138 -0.13531494140625 +101139 -0.27972412109375 +101140 -0.095703125 +101141 -0.185333251953125 +101142 -0.06805419921875 +101143 -0.128204345703125 +101144 -0.055450439453125 +101145 -0.115692138671875 +101146 -0.047088623046875 +101147 -0.116455078125 +101148 -0.03460693359375 +101149 -0.105926513671875 +101150 -0.00762939453125 +101151 -0.053955078125 +101152 0.0367431640625 +101153 0.048797607421875 +101154 0.081939697265625 +101155 0.157318115234375 +101156 0.106201171875 +101157 0.212005615234375 +101158 0.111328125 +101159 0.218475341796875 +101160 0.1190185546875 +101161 0.23724365234375 +101162 0.142608642578125 +101163 0.30535888671875 +101164 0.167236328125 +101165 0.38128662109375 +101166 0.1712646484375 +101167 0.404449462890625 +101168 0.16204833984375 +101169 0.3944091796875 +101170 0.153411865234375 +101171 0.3885498046875 +101172 0.13702392578125 +101173 0.362640380859375 +101174 0.0977783203125 +101175 0.27362060546875 +101176 0.034515380859375 +101177 0.11712646484375 +101178 -0.03369140625 +101179 -0.054901123046875 +101180 -0.087921142578125 +101181 -0.19085693359375 +101182 -0.126129150390625 +101183 -0.28570556640625 +101184 -0.148101806640625 +101185 -0.339263916015625 +101186 -0.163055419921875 +101187 -0.3775634765625 +101188 -0.187225341796875 +101189 -0.445709228515625 +101190 -0.217559814453125 +101191 -0.535064697265625 +101192 -0.248260498046875 +101193 -0.629058837890625 +101194 -0.2686767578125 +101195 -0.697601318359375 +101196 -0.26580810546875 +101197 -0.70391845703125 +101198 -0.23797607421875 +101199 -0.6424560546875 +101200 -0.1776123046875 +101201 -0.491241455078125 +101202 -0.090606689453125 +101203 -0.265716552734375 +101204 0.00189208984375 +101205 -0.023712158203125 +101206 0.08770751953125 +101207 0.201751708984375 +101208 0.154052734375 +101209 0.375823974609375 +101210 0.1959228515625 +101211 0.485076904296875 +101212 0.227386474609375 +101213 0.56884765625 +101214 0.25115966796875 +101215 0.634765625 +101216 0.2509765625 +101217 0.63763427734375 +101218 0.22283935546875 +101219 0.5660400390625 +101220 0.185638427734375 +101221 0.4720458984375 +101222 0.158050537109375 +101223 0.40692138671875 +101224 0.1429443359375 +101225 0.3778076171875 +101226 0.137786865234375 +101227 0.376953125 +101228 0.13116455078125 +101229 0.371978759765625 +101230 0.10540771484375 +101231 0.313140869140625 +101232 0.055023193359375 +101233 0.184417724609375 +101234 -0.0106201171875 +101235 0.011199951171875 +101236 -0.078582763671875 +101237 -0.171051025390625 +101238 -0.139801025390625 +101239 -0.33740234375 +101240 -0.18853759765625 +101241 -0.47198486328125 +101242 -0.2196044921875 +101243 -0.560394287109375 +101244 -0.225128173828125 +101245 -0.58056640625 +101246 -0.210662841796875 +101247 -0.54754638671875 +101248 -0.193389892578125 +101249 -0.508575439453125 +101250 -0.1719970703125 +101251 -0.459503173828125 +101252 -0.144561767578125 +101253 -0.394378662109375 +101254 -0.125457763671875 +101255 -0.35260009765625 +101256 -0.106842041015625 +101257 -0.31170654296875 +101258 -0.06219482421875 +101259 -0.197418212890625 +101260 0.0089111328125 +101261 -0.007965087890625 +101262 0.088653564453125 +101263 0.207489013671875 +101264 0.16259765625 +101265 0.409210205078125 +101266 0.2216796875 +101267 0.57208251953125 +101268 0.25506591796875 +101269 0.66595458984375 +101270 0.251251220703125 +101271 0.65875244140625 +101272 0.2164306640625 +101273 0.56744384765625 +101274 0.164886474609375 +101275 0.431396484375 +101276 0.112579345703125 +101277 0.29443359375 +101278 0.069000244140625 +101279 0.182464599609375 +101280 0.02288818359375 +101281 0.06365966796875 +101282 -0.03057861328125 +101283 -0.075958251953125 +101284 -0.0743408203125 +101285 -0.189422607421875 +101286 -0.10650634765625 +101287 -0.271942138671875 +101288 -0.1337890625 +101289 -0.342529296875 +101290 -0.142822265625 +101291 -0.364166259765625 +101292 -0.130096435546875 +101293 -0.327239990234375 +101294 -0.111846923828125 +101295 -0.2769775390625 +101296 -0.1026611328125 +101297 -0.253692626953125 +101298 -0.097625732421875 +101299 -0.24365234375 +101300 -0.079376220703125 +101301 -0.1983642578125 +101302 -0.0474853515625 +101303 -0.116241455078125 +101304 -0.01629638671875 +101305 -0.036834716796875 +101306 0.01220703125 +101307 0.034881591796875 +101308 0.035125732421875 +101309 0.09124755859375 +101310 0.043914794921875 +101311 0.10888671875 +101312 0.052001953125 +101313 0.125518798828125 +101314 0.065277099609375 +101315 0.15771484375 +101316 0.0738525390625 +101317 0.17828369140625 +101318 0.071868896484375 +101319 0.17108154296875 +101320 0.057098388671875 +101321 0.129974365234375 +101322 0.039459228515625 +101323 0.082427978515625 +101324 0.018707275390625 +101325 0.027679443359375 +101326 -0.016357421875 +101327 -0.065643310546875 +101328 -0.0518798828125 +101329 -0.15936279296875 +101330 -0.0732421875 +101331 -0.21307373046875 +101332 -0.0831298828125 +101333 -0.234649658203125 +101334 -0.072845458984375 +101335 -0.2001953125 +101336 -0.045684814453125 +101337 -0.119171142578125 +101338 -0.013458251953125 +101339 -0.024749755859375 +101340 0.024871826171875 +101341 0.085784912109375 +101342 0.0570068359375 +101343 0.178131103515625 +101344 0.06976318359375 +101345 0.215576171875 +101346 0.0679931640625 +101347 0.211456298828125 +101348 0.05511474609375 +101349 0.17523193359375 +101350 0.038970947265625 +101351 0.128753662109375 +101352 0.030303955078125 +101353 0.1019287109375 +101354 0.021697998046875 +101355 0.0743408203125 +101356 0.012054443359375 +101357 0.04327392578125 +101358 0.01190185546875 +101359 0.038177490234375 +101360 0.027374267578125 +101361 0.076263427734375 +101362 0.052398681640625 +101363 0.14105224609375 +101364 0.070281982421875 +101365 0.186431884765625 +101366 0.07244873046875 +101367 0.188812255859375 +101368 0.055572509765625 +101369 0.1390380859375 +101370 0.02130126953125 +101371 0.041778564453125 +101372 -0.021942138671875 +101373 -0.079437255859375 +101374 -0.072296142578125 +101375 -0.219390869140625 +101376 -0.125701904296875 +101377 -0.367828369140625 +101378 -0.170928955078125 +101379 -0.494873046875 +101380 -0.192962646484375 +101381 -0.556243896484375 +101382 -0.1778564453125 +101383 -0.508697509765625 +101384 -0.133514404296875 +101385 -0.3756103515625 +101386 -0.080535888671875 +101387 -0.218902587890625 +101388 -0.027435302734375 +101389 -0.063751220703125 +101390 0.02606201171875 +101391 0.091552734375 +101392 0.07611083984375 +101393 0.23602294921875 +101394 0.113800048828125 +101395 0.342987060546875 +101396 0.13330078125 +101397 0.39520263671875 +101398 0.133392333984375 +101399 0.389373779296875 +101400 0.11358642578125 +101401 0.324249267578125 +101402 0.081787109375 +101403 0.224090576171875 +101404 0.049560546875 +101405 0.124267578125 +101406 0.02093505859375 +101407 0.037078857421875 +101408 0.0048828125 +101409 -0.010101318359375 +101410 0.000732421875 +101411 -0.019439697265625 +101412 -0.0018310546875 +101413 -0.022796630859375 +101414 0.003387451171875 +101415 -0.001556396484375 +101416 0.02044677734375 +101417 0.056304931640625 +101418 0.035003662109375 +101419 0.106719970703125 +101420 0.02984619140625 +101421 0.096893310546875 +101422 0.01031494140625 +101423 0.042694091796875 +101424 -0.011077880859375 +101425 -0.018035888671875 +101426 -0.031158447265625 +101427 -0.07586669921875 +101428 -0.046173095703125 +101429 -0.11944580078125 +101430 -0.0596923828125 +101431 -0.15972900390625 +101432 -0.073638916015625 +101433 -0.202606201171875 +101434 -0.088165283203125 +101435 -0.24859619140625 +101436 -0.10577392578125 +101437 -0.30517578125 +101438 -0.123199462890625 +101439 -0.36212158203125 +101440 -0.131317138671875 +101441 -0.39141845703125 +101442 -0.117828369140625 +101443 -0.35528564453125 +101444 -0.08160400390625 +101445 -0.249969482421875 +101446 -0.028472900390625 +101447 -0.092864990234375 +101448 0.032623291015625 +101449 0.08905029296875 +101450 0.081756591796875 +101451 0.2352294921875 +101452 0.110076904296875 +101453 0.318817138671875 +101454 0.12371826171875 +101455 0.358642578125 +101456 0.120391845703125 +101457 0.347747802734375 +101458 0.09991455078125 +101459 0.28564453125 +101460 0.0789794921875 +101461 0.223175048828125 +101462 0.069549560546875 +101463 0.196746826171875 +101464 0.06298828125 +101465 0.179840087890625 +101466 0.053802490234375 +101467 0.155548095703125 +101468 0.051055908203125 +101469 0.151214599609375 +101470 0.05157470703125 +101471 0.156951904296875 +101472 0.041961669921875 +101473 0.13177490234375 +101474 0.030548095703125 +101475 0.100799560546875 +101476 0.02496337890625 +101477 0.087127685546875 +101478 0.013519287109375 +101479 0.05487060546875 +101480 -0.00799560546875 +101481 -0.009002685546875 +101482 -0.039398193359375 +101483 -0.10400390625 +101484 -0.0804443359375 +101485 -0.229400634765625 +101486 -0.121429443359375 +101487 -0.35552978515625 +101488 -0.14910888671875 +101489 -0.441925048828125 +101490 -0.15869140625 +101491 -0.473846435546875 +101492 -0.1546630859375 +101493 -0.464813232421875 +101494 -0.13848876953125 +101495 -0.419097900390625 +101496 -0.109466552734375 +101497 -0.334320068359375 +101498 -0.0733642578125 +101499 -0.227935791015625 +101500 -0.0379638671875 +101501 -0.12347412109375 +101502 -0.00555419921875 +101503 -0.02764892578125 +101504 0.029754638671875 +101505 0.077667236328125 +101506 0.074737548828125 +101507 0.2132568359375 +101508 0.132568359375 +101509 0.38885498046875 +101510 0.196136474609375 +101511 0.582794189453125 +101512 0.24542236328125 +101513 0.734039306640625 +101514 0.266510009765625 +101515 0.800140380859375 +101516 0.258544921875 +101517 0.7783203125 +101518 0.220458984375 +101519 0.6651611328125 +101520 0.1519775390625 +101521 0.45965576171875 +101522 0.0654296875 +101523 0.199188232421875 +101524 -0.017608642578125 +101525 -0.050689697265625 +101526 -0.078338623046875 +101527 -0.23297119140625 +101528 -0.11102294921875 +101529 -0.33013916015625 +101530 -0.12420654296875 +101531 -0.368408203125 +101532 -0.1280517578125 +101533 -0.378936767578125 +101534 -0.127593994140625 +101535 -0.376983642578125 +101536 -0.128448486328125 +101537 -0.37969970703125 +101538 -0.132080078125 +101539 -0.391510009765625 +101540 -0.129608154296875 +101541 -0.385345458984375 +101542 -0.11474609375 +101543 -0.3419189453125 +101544 -0.094635009765625 +101545 -0.28289794921875 +101546 -0.08349609375 +101547 -0.251617431640625 +101548 -0.087310791015625 +101549 -0.266143798828125 +101550 -0.0887451171875 +101551 -0.273345947265625 +101552 -0.069305419921875 +101553 -0.216796875 +101554 -0.039459228515625 +101555 -0.128265380859375 +101556 -0.01904296875 +101557 -0.068145751953125 +101558 -0.01031494140625 +101559 -0.0430908203125 +101560 -0.003875732421875 +101561 -0.024444580078125 +101562 0.01104736328125 +101563 0.020721435546875 +101564 0.044921875 +101565 0.124481201171875 +101566 0.088287353515625 +101567 0.25787353515625 +101568 0.127471923828125 +101569 0.379119873046875 +101570 0.1597900390625 +101571 0.47991943359375 +101572 0.174774169921875 +101573 0.5281982421875 +101574 0.16827392578125 +101575 0.511138916015625 +101576 0.14935302734375 +101577 0.456207275390625 +101578 0.13250732421875 +101579 0.407470703125 +101580 0.12396240234375 +101581 0.383758544921875 +101582 0.114471435546875 +101583 0.35687255859375 +101584 0.099151611328125 +101585 0.31182861328125 +101586 0.078765869140625 +101587 0.250885009765625 +101588 0.050506591796875 +101589 0.1654052734375 +101590 0.0078125 +101591 0.035247802734375 +101592 -0.05010986328125 +101593 -0.142059326171875 +101594 -0.1131591796875 +101595 -0.33563232421875 +101596 -0.17779541015625 +101597 -0.5345458984375 +101598 -0.23846435546875 +101599 -0.72186279296875 +101600 -0.275238037109375 +101601 -0.836669921875 +101602 -0.272979736328125 +101603 -0.8326416015625 +101604 -0.238250732421875 +101605 -0.7296142578125 +101606 -0.18914794921875 +101607 -0.582550048828125 +101608 -0.14166259765625 +101609 -0.440093994140625 +101610 -0.10308837890625 +101611 -0.324310302734375 +101612 -0.0623779296875 +101613 -0.20147705078125 +101614 -0.01068115234375 +101615 -0.044647216796875 +101616 0.038116455078125 +101617 0.103973388671875 +101618 0.070220947265625 +101619 0.202392578125 +101620 0.090179443359375 +101621 0.264495849609375 +101622 0.113983154296875 +101623 0.338897705078125 +101624 0.14764404296875 +101625 0.443817138671875 +101626 0.17999267578125 +101627 0.545074462890625 +101628 0.202789306640625 +101629 0.6173095703125 +101630 0.21343994140625 +101631 0.6524658203125 +101632 0.2158203125 +101633 0.66339111328125 +101634 0.211822509765625 +101635 0.6561279296875 +101636 0.194244384765625 +101637 0.606781005859375 +101638 0.15911865234375 +101639 0.501190185546875 +101640 0.11065673828125 +101641 0.352783203125 +101642 0.053619384765625 +101643 0.176544189453125 +101644 -0.013824462890625 +101645 -0.034820556640625 +101646 -0.08453369140625 +101647 -0.258209228515625 +101648 -0.14312744140625 +101649 -0.44244384765625 +101650 -0.18572998046875 +101651 -0.5753173828125 +101652 -0.210784912109375 +101653 -0.65203857421875 +101654 -0.209014892578125 +101655 -0.641632080078125 +101656 -0.18572998046875 +101657 -0.562164306640625 +101658 -0.154083251953125 +101659 -0.458038330078125 +101660 -0.12042236328125 +101661 -0.350555419921875 +101662 -0.091064453125 +101663 -0.260528564453125 +101664 -0.067413330078125 +101665 -0.192108154296875 +101666 -0.04864501953125 +101667 -0.141937255859375 +101668 -0.03265380859375 +101669 -0.1021728515625 +101670 -0.016754150390625 +101671 -0.062896728515625 +101672 0.00238037109375 +101673 -0.011932373046875 +101674 0.02813720703125 +101675 0.062835693359375 +101676 0.05657958984375 +101677 0.148712158203125 +101678 0.086334228515625 +101679 0.241729736328125 +101680 0.119476318359375 +101681 0.34912109375 +101682 0.151947021484375 +101683 0.457305908203125 +101684 0.177093505859375 +101685 0.54388427734375 +101686 0.184326171875 +101687 0.5728759765625 +101688 0.16259765625 +101689 0.506591796875 +101690 0.1138916015625 +101691 0.351226806640625 +101692 0.05010986328125 +101693 0.146514892578125 +101694 -0.013031005859375 +101695 -0.05523681640625 +101696 -0.064178466796875 +101697 -0.21624755859375 +101698 -0.102630615234375 +101699 -0.334930419921875 +101700 -0.12579345703125 +101701 -0.402984619140625 +101702 -0.1396484375 +101703 -0.4412841796875 +101704 -0.15771484375 +101705 -0.49578857421875 +101706 -0.17803955078125 +101707 -0.5601806640625 +101708 -0.190582275390625 +101709 -0.600738525390625 +101710 -0.18548583984375 +101711 -0.584228515625 +101712 -0.15350341796875 +101713 -0.47930908203125 +101714 -0.0927734375 +101715 -0.27935791015625 +101716 -0.010650634765625 +101717 -0.0089111328125 +101718 0.073974609375 +101719 0.268798828125 +101720 0.139984130859375 +101721 0.482818603515625 +101722 0.178497314453125 +101723 0.60369873046875 +101724 0.194976806640625 +101725 0.650421142578125 +101726 0.201416015625 +101727 0.66400146484375 +101728 0.19683837890625 +101729 0.6414794921875 +101730 0.178070068359375 +101731 0.572540283203125 +101732 0.15716552734375 +101733 0.498138427734375 +101734 0.140380859375 +101735 0.439453125 +101736 0.1214599609375 +101737 0.375518798828125 +101738 0.09100341796875 +101739 0.274505615234375 +101740 0.0408935546875 +101741 0.1087646484375 +101742 -0.022186279296875 +101743 -0.099395751953125 +101744 -0.0887451171875 +101745 -0.3182373046875 +101746 -0.1590576171875 +101747 -0.5489501953125 +101748 -0.22772216796875 +101749 -0.7738037109375 +101750 -0.2789306640625 +101751 -0.86383056640625 +101752 -0.302764892578125 +101753 -0.870391845703125 +101754 -0.304351806640625 +101755 -0.86895751953125 +101756 -0.287506103515625 +101757 -0.861053466796875 +101758 -0.247039794921875 +101759 -0.765869140625 +101760 -0.179595947265625 +101761 -0.5301513671875 +101762 -0.087249755859375 +101763 -0.214691162109375 +101764 0.017242431640625 +101765 0.137359619140625 +101766 0.118682861328125 +101767 0.474822998046875 +101768 0.206512451171875 +101769 0.76239013671875 +101770 0.27264404296875 +101771 0.867462158203125 +101772 0.317138671875 +101773 0.870361328125 +101774 0.33648681640625 +101775 0.86480712890625 +101776 0.3321533203125 +101777 0.831817626953125 +101778 0.311279296875 +101779 0.677581787109375 +101780 0.2755126953125 +101781 0.495880126953125 +101782 0.23028564453125 +101783 0.30767822265625 +101784 0.17620849609375 +101785 0.116180419921875 +101786 0.103851318359375 +101787 -0.110748291015625 +101788 0.0111083984375 +101789 -0.381805419921875 +101790 -0.08929443359375 +101791 -0.6572265625 +101792 -0.179595947265625 +101793 -0.857421875 +101794 -0.247100830078125 +101795 -0.870391845703125 +101796 -0.289642333984375 +101797 -0.870391845703125 +101798 -0.315155029296875 +101799 -0.86444091796875 +101800 -0.3341064453125 +101801 -0.85723876953125 +101802 -0.34100341796875 +101803 -0.790008544921875 +101804 -0.3197021484375 +101805 -0.62847900390625 +101806 -0.26922607421875 +101807 -0.3956298828125 +101808 -0.199249267578125 +101809 -0.126708984375 +101810 -0.1177978515625 +101811 0.150115966796875 +101812 -0.0283203125 +101813 0.424041748046875 +101814 0.061187744140625 +101815 0.670623779296875 +101816 0.1392822265625 +101817 0.854522705078125 +101818 0.200714111328125 +101819 0.866485595703125 +101820 0.240936279296875 +101821 0.86920166015625 +101822 0.2652587890625 +101823 0.8653564453125 +101824 0.277618408203125 +101825 0.857147216796875 +101826 0.277099609375 +101827 0.766845703125 +101828 0.265167236328125 +101829 0.628509521484375 +101830 0.239776611328125 +101831 0.462127685546875 +101832 0.208526611328125 +101833 0.297210693359375 +101834 0.175018310546875 +101835 0.14862060546875 +101836 0.1324462890625 +101837 -0.00537109375 +101838 0.0830078125 +101839 -0.15753173828125 +101840 0.025634765625 +101841 -0.31304931640625 +101842 -0.0438232421875 +101843 -0.48876953125 +101844 -0.111480712890625 +101845 -0.6416015625 +101846 -0.16998291015625 +101847 -0.751373291015625 +101848 -0.22613525390625 +101849 -0.84619140625 +101850 -0.275543212890625 +101851 -0.861297607421875 +101852 -0.308380126953125 +101853 -0.863250732421875 +101854 -0.31524658203125 +101855 -0.856597900390625 +101856 -0.2996826171875 +101857 -0.7498779296875 +101858 -0.278778076171875 +101859 -0.624542236328125 +101860 -0.246002197265625 +101861 -0.47808837890625 +101862 -0.184051513671875 +101863 -0.253387451171875 +101864 -0.106414794921875 +101865 0.003692626953125 +101866 -0.0333251953125 +101867 0.2257080078125 +101868 0.038909912109375 +101869 0.427154541015625 +101870 0.119873046875 +101871 0.643218994140625 +101872 0.206695556640625 +101873 0.855926513671875 +101874 0.282196044921875 +101875 0.870361328125 +101876 0.3316650390625 +101877 0.870361328125 +101878 0.357208251953125 +101879 0.862762451171875 +101880 0.35791015625 +101881 0.79669189453125 +101882 0.330963134765625 +101883 0.595794677734375 +101884 0.28497314453125 +101885 0.362152099609375 +101886 0.22821044921875 +101887 0.1270751953125 +101888 0.166351318359375 +101889 -0.086944580078125 +101890 0.0997314453125 +101891 -0.2784423828125 +101892 0.01947021484375 +101893 -0.484832763671875 +101894 -0.078582763671875 +101895 -0.729583740234375 +101896 -0.1802978515625 +101897 -0.86688232421875 +101898 -0.268310546875 +101899 -0.870391845703125 +101900 -0.3408203125 +101901 -0.86859130859375 +101902 -0.3968505859375 +101903 -0.86279296875 +101904 -0.426727294921875 +101905 -0.817962646484375 +101906 -0.418426513671875 +101907 -0.6116943359375 +101908 -0.37017822265625 +101909 -0.3128662109375 +101910 -0.291107177734375 +101911 0.039398193359375 +101912 -0.186798095703125 +101913 0.422821044921875 +101914 -0.066497802734375 +101915 0.805145263671875 +101916 0.051300048828125 +101917 0.870361328125 +101918 0.15106201171875 +101919 0.870361328125 +101920 0.2291259765625 +101921 0.860015869140625 +101922 0.282958984375 +101923 0.727935791015625 +101924 0.310638427734375 +101925 0.48114013671875 +101926 0.318145751953125 +101927 0.2059326171875 +101928 0.3111572265625 +101929 -0.06103515625 +101930 0.292083740234375 +101931 -0.29913330078125 +101932 0.257049560546875 +101933 -0.516204833984375 +101934 0.202056884765625 +101935 -0.7252197265625 +101936 0.13385009765625 +101937 -0.85980224609375 +101938 0.061798095703125 +101939 -0.870391845703125 +101940 -0.005889892578125 +101941 -0.870391845703125 +101942 -0.055877685546875 +101943 -0.858062744140625 +101944 -0.0865478515625 +101945 -0.673004150390625 +101946 -0.111236572265625 +101947 -0.42694091796875 +101948 -0.141143798828125 +101949 -0.2100830078125 +101950 -0.17523193359375 +101951 -0.0362548828125 +101952 -0.205413818359375 +101953 0.10943603515625 +101954 -0.226043701171875 +101955 0.23516845703125 +101956 -0.225982666015625 +101957 0.373687744140625 +101958 -0.2056884765625 +101959 0.517791748046875 +101960 -0.181793212890625 +101961 0.602783203125 +101962 -0.153076171875 +101963 0.635711669921875 +101964 -0.1109619140625 +101965 0.655181884765625 +101966 -0.05841064453125 +101967 0.65948486328125 +101968 0.00201416015625 +101969 0.651275634765625 +101970 0.06341552734375 +101971 0.61846923828125 +101972 0.115509033203125 +101973 0.53753662109375 +101974 0.153076171875 +101975 0.404144287109375 +101976 0.173095703125 +101977 0.22186279296875 +101978 0.175537109375 +101979 0.003997802734375 +101980 0.16485595703125 +101981 -0.22100830078125 +101982 0.14630126953125 +101983 -0.42449951171875 +101984 0.125335693359375 +101985 -0.579833984375 +101986 0.113250732421875 +101987 -0.641876220703125 +101988 0.108367919921875 +101989 -0.6177978515625 +101990 0.09381103515625 +101991 -0.575531005859375 +101992 0.06842041015625 +101993 -0.526336669921875 +101994 0.04620361328125 +101995 -0.42645263671875 +101996 0.03472900390625 +101997 -0.2581787109375 +101998 0.02484130859375 +101999 -0.068695068359375 +102000 0.006805419921875 +102001 0.09222412109375 +102002 -0.0140380859375 +102003 0.232147216796875 +102004 -0.034637451171875 +102005 0.3509521484375 +102006 -0.062530517578125 +102007 0.410064697265625 +102008 -0.105224609375 +102009 0.372955322265625 +102010 -0.157073974609375 +102011 0.2554931640625 +102012 -0.2042236328125 +102013 0.10711669921875 +102014 -0.241485595703125 +102015 -0.052886962890625 +102016 -0.2593994140625 +102017 -0.186279296875 +102018 -0.243438720703125 +102019 -0.23291015625 +102020 -0.1998291015625 +102021 -0.209442138671875 +102022 -0.146270751953125 +102023 -0.174163818359375 +102024 -0.085296630859375 +102025 -0.126739501953125 +102026 -0.014617919921875 +102027 -0.048126220703125 +102028 0.05792236328125 +102029 0.0426025390625 +102030 0.11968994140625 +102031 0.10748291015625 +102032 0.166900634765625 +102033 0.1409912109375 +102034 0.211883544921875 +102035 0.19708251953125 +102036 0.252685546875 +102037 0.273651123046875 +102038 0.27447509765625 +102039 0.31768798828125 +102040 0.2801513671875 +102041 0.341094970703125 +102042 0.27642822265625 +102043 0.368011474609375 +102044 0.25732421875 +102045 0.37249755859375 +102046 0.209991455078125 +102047 0.30072021484375 +102048 0.135955810546875 +102049 0.1517333984375 +102050 0.053070068359375 +102051 -0.01470947265625 +102052 -0.03369140625 +102053 -0.1883544921875 +102054 -0.122955322265625 +102055 -0.372711181640625 +102056 -0.198333740234375 +102057 -0.51397705078125 +102058 -0.24713134765625 +102059 -0.57177734375 +102060 -0.26593017578125 +102061 -0.53948974609375 +102062 -0.258148193359375 +102063 -0.43511962890625 +102064 -0.232879638671875 +102065 -0.2962646484375 +102066 -0.199798583984375 +102067 -0.161102294921875 +102068 -0.162689208984375 +102069 -0.0435791015625 +102070 -0.121063232421875 +102071 0.060394287109375 +102072 -0.079681396484375 +102073 0.13665771484375 +102074 -0.04388427734375 +102075 0.170135498046875 +102076 -0.0140380859375 +102077 0.16552734375 +102078 0.017120361328125 +102079 0.15728759765625 +102080 0.049102783203125 +102081 0.150787353515625 +102082 0.07373046875 +102083 0.12200927734375 +102084 0.091705322265625 +102085 0.080108642578125 +102086 0.108428955078125 +102087 0.05126953125 +102088 0.129974365234375 +102089 0.062896728515625 +102090 0.14959716796875 +102091 0.09271240234375 +102092 0.154266357421875 +102093 0.092987060546875 +102094 0.1478271484375 +102095 0.07855224609375 +102096 0.13458251953125 +102097 0.06427001953125 +102098 0.111175537109375 +102099 0.0347900390625 +102100 0.078125 +102101 -0.01171875 +102102 0.041839599609375 +102103 -0.056060791015625 +102104 0.0150146484375 +102105 -0.055511474609375 +102106 -0.000885009765625 +102107 -0.010467529296875 +102108 -0.0185546875 +102109 0.02508544921875 +102110 -0.04327392578125 +102111 0.025665283203125 +102112 -0.066864013671875 +102113 0.017333984375 +102114 -0.087799072265625 +102115 0.00189208984375 +102116 -0.10821533203125 +102117 -0.03173828125 +102118 -0.12445068359375 +102119 -0.071502685546875 +102120 -0.14111328125 +102121 -0.13543701171875 +102122 -0.157470703125 +102123 -0.219970703125 +102124 -0.16748046875 +102125 -0.300506591796875 +102126 -0.171722412109375 +102127 -0.376312255859375 +102128 -0.1629638671875 +102129 -0.416107177734375 +102130 -0.12945556640625 +102131 -0.371124267578125 +102132 -0.072662353515625 +102133 -0.242279052734375 +102134 -0.004486083984375 +102135 -0.069732666015625 +102136 0.06829833984375 +102137 0.125640869140625 +102138 0.136322021484375 +102139 0.31268310546875 +102140 0.189056396484375 +102141 0.45501708984375 +102142 0.226348876953125 +102143 0.554779052734375 +102144 0.247161865234375 +102145 0.61065673828125 +102146 0.24835205078125 +102147 0.610931396484375 +102148 0.224212646484375 +102149 0.531463623046875 +102150 0.179229736328125 +102151 0.3883056640625 +102152 0.12738037109375 +102153 0.23468017578125 +102154 0.07574462890625 +102155 0.095245361328125 +102156 0.0318603515625 +102157 -0.00396728515625 +102158 0.000396728515625 +102159 -0.04852294921875 +102160 -0.021636962890625 +102161 -0.055145263671875 +102162 -0.046112060546875 +102163 -0.0758056640625 +102164 -0.079071044921875 +102165 -0.138702392578125 +102166 -0.1109619140625 +102167 -0.209197998046875 +102168 -0.14154052734375 +102169 -0.289031982421875 +102170 -0.170501708984375 +102171 -0.37884521484375 +102172 -0.1920166015625 +102173 -0.456329345703125 +102174 -0.204864501953125 +102175 -0.51641845703125 +102176 -0.199310302734375 +102177 -0.519287109375 +102178 -0.174163818359375 +102179 -0.458251953125 +102180 -0.142913818359375 +102181 -0.384796142578125 +102182 -0.112548828125 +102183 -0.323699951171875 +102184 -0.082489013671875 +102185 -0.269287109375 +102186 -0.047149658203125 +102187 -0.1951904296875 +102188 -0.007080078125 +102189 -0.100006103515625 +102190 0.030120849609375 +102191 -0.01055908203125 +102192 0.07122802734375 +102193 0.1033935546875 +102194 0.117431640625 +102195 0.24908447265625 +102196 0.15496826171875 +102197 0.373199462890625 +102198 0.17913818359375 +102199 0.45806884765625 +102200 0.191802978515625 +102201 0.511474609375 +102202 0.20111083984375 +102203 0.565399169921875 +102204 0.205291748046875 +102205 0.61138916015625 +102206 0.189910888671875 +102207 0.5897216796875 +102208 0.153106689453125 +102209 0.4906005859375 +102210 0.100006103515625 +102211 0.33148193359375 +102212 0.04022216796875 +102213 0.147796630859375 +102214 -0.015045166015625 +102215 -0.01873779296875 +102216 -0.058074951171875 +102217 -0.140289306640625 +102218 -0.082000732421875 +102219 -0.191986083984375 +102220 -0.088897705078125 +102221 -0.184295654296875 +102222 -0.089508056640625 +102223 -0.161834716796875 +102224 -0.094024658203125 +102225 -0.166595458984375 +102226 -0.1011962890625 +102227 -0.19390869140625 +102228 -0.10626220703125 +102229 -0.22442626953125 +102230 -0.114837646484375 +102231 -0.279754638671875 +102232 -0.1220703125 +102233 -0.3389892578125 +102234 -0.11651611328125 +102235 -0.3543701171875 +102236 -0.10430908203125 +102237 -0.348175048828125 +102238 -0.087432861328125 +102239 -0.32598876953125 +102240 -0.059112548828125 +102241 -0.2581787109375 +102242 -0.01873779296875 +102243 -0.139801025390625 +102244 0.029449462890625 +102245 0.014617919921875 +102246 0.069793701171875 +102247 0.144378662109375 +102248 0.09478759765625 +102249 0.221038818359375 +102250 0.110687255859375 +102251 0.27069091796875 +102252 0.117584228515625 +102253 0.294036865234375 +102254 0.12066650390625 +102255 0.311767578125 +102256 0.123809814453125 +102257 0.339141845703125 +102258 0.123077392578125 +102259 0.360260009765625 +102260 0.115264892578125 +102261 0.360504150390625 +102262 0.093658447265625 +102263 0.308380126953125 +102264 0.0537109375 +102265 0.18170166015625 +102266 0.001739501953125 +102267 0.0047607421875 +102268 -0.05072021484375 +102269 -0.17559814453125 +102270 -0.0926513671875 +102271 -0.3143310546875 +102272 -0.113433837890625 +102273 -0.36785888671875 +102274 -0.118743896484375 +102275 -0.36248779296875 +102276 -0.1187744140625 +102277 -0.343536376953125 +102278 -0.111236572265625 +102279 -0.3018798828125 +102280 -0.09466552734375 +102281 -0.231414794921875 +102282 -0.0657958984375 +102283 -0.117645263671875 +102284 -0.032318115234375 +102285 0.007049560546875 +102286 -0.007232666015625 +102287 0.087982177734375 +102288 0.012359619140625 +102289 0.13946533203125 +102290 0.028961181640625 +102291 0.17425537109375 +102292 0.041107177734375 +102293 0.188201904296875 +102294 0.04595947265625 +102295 0.171234130859375 +102296 0.041900634765625 +102297 0.118438720703125 +102298 0.034881591796875 +102299 0.05706787109375 +102300 0.02496337890625 +102301 -0.010711669921875 +102302 0.0103759765625 +102303 -0.0914306640625 +102304 -0.00372314453125 +102305 -0.162322998046875 +102306 -0.0107421875 +102307 -0.194549560546875 +102308 -0.001678466796875 +102309 -0.1492919921875 +102310 0.02471923828125 +102311 -0.02166748046875 +102312 0.053802490234375 +102313 0.124053955078125 +102314 0.068023681640625 +102315 0.211151123046875 +102316 0.067962646484375 +102317 0.240447998046875 +102318 0.061065673828125 +102319 0.242218017578125 +102320 0.049896240234375 +102321 0.2257080078125 +102322 0.035614013671875 +102323 0.194366455078125 +102324 0.011016845703125 +102325 0.115509033203125 +102326 -0.01800537109375 +102327 0.0128173828125 +102328 -0.037322998046875 +102329 -0.053802490234375 +102330 -0.0528564453125 +102331 -0.110626220703125 +102332 -0.074249267578125 +102333 -0.199493408203125 +102334 -0.095458984375 +102335 -0.29437255859375 +102336 -0.101959228515625 +102337 -0.33221435546875 +102338 -0.086181640625 +102339 -0.27972412109375 +102340 -0.059600830078125 +102341 -0.185333251953125 +102342 -0.0408935546875 +102343 -0.128204345703125 +102344 -0.032073974609375 +102345 -0.115692138671875 +102346 -0.02618408203125 +102347 -0.116455078125 +102348 -0.01788330078125 +102349 -0.105926513671875 +102350 -0.00048828125 +102351 -0.053955078125 +102352 0.02789306640625 +102353 0.048797607421875 +102354 0.05657958984375 +102355 0.157318115234375 +102356 0.071563720703125 +102357 0.212005615234375 +102358 0.074066162109375 +102359 0.218475341796875 +102360 0.078125 +102361 0.23724365234375 +102362 0.092376708984375 +102363 0.30535888671875 +102364 0.1072998046875 +102365 0.38128662109375 +102366 0.1090087890625 +102367 0.404449462890625 +102368 0.102294921875 +102369 0.3944091796875 +102370 0.0960693359375 +102371 0.3885498046875 +102372 0.08502197265625 +102373 0.362640380859375 +102374 0.0594482421875 +102375 0.27362060546875 +102376 0.018585205078125 +102377 0.11712646484375 +102378 -0.0252685546875 +102379 -0.054901123046875 +102380 -0.0599365234375 +102381 -0.19085693359375 +102382 -0.084075927734375 +102383 -0.28570556640625 +102384 -0.097564697265625 +102385 -0.339263916015625 +102386 -0.106414794921875 +102387 -0.3775634765625 +102388 -0.121124267578125 +102389 -0.445709228515625 +102390 -0.139801025390625 +102391 -0.535064697265625 +102392 -0.15875244140625 +102393 -0.629058837890625 +102394 -0.171142578125 +102395 -0.697601318359375 +102396 -0.168670654296875 +102397 -0.70391845703125 +102398 -0.150238037109375 +102399 -0.6424560546875 From 174af2ebc23f85b78c0734ba8ad061bd25bd9aca Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 1 Jun 2026 13:04:59 -0500 Subject: [PATCH 529/876] Fix ruff formatting --- tests/circuitpython/audiofilter_filter_stereo_biquads.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/circuitpython/audiofilter_filter_stereo_biquads.py b/tests/circuitpython/audiofilter_filter_stereo_biquads.py index 526630f4bd7..262f8139378 100644 --- a/tests/circuitpython/audiofilter_filter_stereo_biquads.py +++ b/tests/circuitpython/audiofilter_filter_stereo_biquads.py @@ -16,7 +16,7 @@ def stereo_filter(): Biquad(FilterMode.LOW_PASS, 400), Biquad(FilterMode.HIGH_PASS, 300, Q=8), ], - **args + **args, ) mixer = Mixer(**args) mixer.voice[0].panning = LFO() From 195aa8bfa70118f9ae52e2d63bd0a30d32a99155 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 1 Jun 2026 14:48:07 -0400 Subject: [PATCH 530/876] py/maketranslationdata.py: better var names --- py/maketranslationdata.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/py/maketranslationdata.py b/py/maketranslationdata.py index f6a6e85bf0e..c3c3442e311 100644 --- a/py/maketranslationdata.py +++ b/py/maketranslationdata.py @@ -532,17 +532,17 @@ def parse_qstrs(infile): ) content = infile.read() matches = rx.finditer(content) - static_qstrs = [] - dynamic_qstrs = [] + qdef0_qstrs = [] + qdef1_qstrs = [] for match in matches: qstr = eval(match.group("cstr")) if match.group("pool") == "0": - static_qstrs.append(qstr) + qdef0_qstrs.append(qstr) else: - dynamic_qstrs.append(qstr) - for i, qstr in enumerate(static_qstrs): + qdef1_qstrs.append(qstr) + for i, qstr in enumerate(qdef0_qstrs): r[qstr] = i - for i, qstr in enumerate(dynamic_qstrs, start=len(static_qstrs)): + for i, qstr in enumerate(qdef1_qstrs, start=len(qdef0_qstrs)): r[qstr] = i return r From d97a53d736c8521320342745e202e49da7337673 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 1 Jun 2026 14:52:11 -0400 Subject: [PATCH 531/876] address review suggestion --- shared-bindings/displayio/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-bindings/displayio/__init__.c b/shared-bindings/displayio/__init__.c index ff67be3501d..970c4826476 100644 --- a/shared-bindings/displayio/__init__.c +++ b/shared-bindings/displayio/__init__.c @@ -83,7 +83,7 @@ //| //| Once you release a builtin display (one that is initialized automatically, not by user code), //| the display will remain released even if you restart the CircuitPython VM, for instance by typing ctrl-D. -//| The display is not re-initialized until you do a hard reset. +//| The display is not re-initialized until you do a hard reset or manually initialize it again. //| """ //| ... //| From d90f4f308c417b8a2ab15837ddbe7f34954e322e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 1 Jun 2026 20:10:59 -0400 Subject: [PATCH 532/876] Validate frequency arg for ParallelBus to prevent crash on 0 --- shared-bindings/paralleldisplaybus/ParallelBus.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shared-bindings/paralleldisplaybus/ParallelBus.c b/shared-bindings/paralleldisplaybus/ParallelBus.c index dfe363bdcb7..7f8749501fb 100644 --- a/shared-bindings/paralleldisplaybus/ParallelBus.c +++ b/shared-bindings/paralleldisplaybus/ParallelBus.c @@ -85,14 +85,16 @@ static mp_obj_t paralleldisplaybus_parallelbus_make_new(const mp_obj_type_t *typ mp_raise_ValueError(MP_ERROR_TEXT("Specify exactly one of data0 or data_pins")); } + uint32_t frequency = (uint32_t)mp_arg_validate_int_min(args[ARG_frequency].u_int, 1, MP_QSTR_frequency); + if (specified_data0) { const mcu_pin_obj_t *data0 = validate_obj_is_free_pin(args[ARG_data0].u_obj, MP_QSTR_data0); - common_hal_paralleldisplaybus_parallelbus_construct(self, data0, command, chip_select, write, read, reset, args[ARG_frequency].u_int); + common_hal_paralleldisplaybus_parallelbus_construct(self, data0, command, chip_select, write, read, reset, frequency); } else { uint8_t num_pins; const mcu_pin_obj_t *data_pins[16]; validate_list_is_free_pins(MP_QSTR_data_pins, data_pins, (mp_int_t)MP_ARRAY_SIZE(data_pins), args[ARG_data_pins].u_obj, &num_pins); - common_hal_paralleldisplaybus_parallelbus_construct_nonsequential(self, num_pins, data_pins, command, chip_select, write, read, reset, args[ARG_frequency].u_int); + common_hal_paralleldisplaybus_parallelbus_construct_nonsequential(self, num_pins, data_pins, command, chip_select, write, read, reset, frequency); } return self; } From 2c169842072bdb9375d6d02a5b693ba221ddb326 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 2 Jun 2026 16:08:43 -0500 Subject: [PATCH 533/876] bit mirroring for explicitly changed output_bit_depth. Clarify docstrings. --- ports/espressif/common-hal/audioi2sin/I2SIn.c | 36 ++++++++++++----- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 39 +++++++++++++------ shared-bindings/audioi2sin/I2SIn.c | 10 ++--- 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 28c61aafc2f..0098e744266 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -142,21 +142,37 @@ static inline uint32_t i2sin_read_raw(const uint8_t *src, uint8_t in_depth) { return v; } -// Convert `raw` from `in_depth` to `out_depth` (sign-preserving for signed) and -// write it to `buffer` at sample index `idx`. When upscaling, the value is -// right-justified: the meaningful data stays in the low `in_depth` bits with the -// upper bits carrying the sign, so a wider output uses a larger container without -// scaling the magnitude up. (This means 24-bit-in-32-bit output is -// right-justified) +// Convert `raw` from `in_depth` to the explicitly-requested `out_depth` +// (sign-preserving for signed) and write it to `buffer` at sample index `idx`. +// This path runs only when the caller set `output_bit_depth`, i.e. asked for a +// real bit-depth rescale: upscaling bit-replicates so full-scale input maps to +// full-scale output (e.g. 16-bit 0xFFFF -> 24-bit 0xFFFFFF) and downscaling +// arithmetic-shifts right. This is distinct from the implicit container width +// set by the array typecode (e.g. a 24-bit sample carried in a 32-bit 'i' +// slot), which only sign-extends and is handled by the default path. // Output element size: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. static inline void i2sin_write_converted(void *buffer, uint32_t idx, uint32_t raw, uint8_t in_depth, uint8_t out_depth, bool samples_signed) { int32_t s = i2sin_normalize_signed(raw, in_depth); int32_t shifted; - if (out_depth >= in_depth) { - // Right-justify: keep the value as-is so the meaningful bits stay in the - // low `in_depth` bits (upper bits already sign-extended). The wider - // output just provides a larger container. + if (out_depth > in_depth) { + // Explicit upscale: bit-replicate the input across the wider output so + // that full-scale input maps to full-scale output (e.g. 16-bit 0xFFFF + // -> 24-bit 0xFFFFFF), filling out_depth bits rather than leaving the + // new low bits zero. + uint32_t in_mask = (in_depth >= 32) ? 0xffffffffu : ((1u << in_depth) - 1u); + uint32_t in_bits = (uint32_t)s & in_mask; + uint32_t result = 0; + int remaining = out_depth; + while (remaining > 0) { + int take = (remaining >= (int)in_depth) ? (int)in_depth : remaining; + result = (result << take) | (in_bits >> (in_depth - take)); + remaining -= take; + } + // Sign-extend the out_depth-bit result up to int32 so a 24-bit value in + // a 32-bit container decodes correctly; harmless when out_depth == 32. + shifted = (int32_t)(result << (32 - out_depth)) >> (32 - out_depth); + } else if (out_depth == in_depth) { shifted = s; } else { shifted = s >> (in_depth - out_depth); diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 3617fa11a81..2c6a2d75928 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -398,13 +398,16 @@ static inline int32_t i2sin_normalize_signed(uint32_t raw, uint8_t in_depth, } // Write `raw` (input-depth bits, just-read FIFO sample) to `buffer` at sample -// index `idx`, converting from `in_depth` to `out_depth` (sign-preserving for -// signed) and (if needed) flipping the sign bit for the unsigned-WAV -// convention. When upscaling, the value is right-justified: the meaningful data -// stays in the low `in_depth` bits with the upper bits carrying the sign, so a -// wider output simply uses a larger container without scaling the magnitude up. -// (Note this means 24-bit-in-32-bit output is right-justified.) Output element size follows `out_depth`: 1 byte -// at 8, 2 bytes at 16, 4 bytes at 24 or 32. +// index `idx`, converting from `in_depth` to the explicitly-requested +// `out_depth` (sign-preserving for signed) and (if needed) flipping the sign +// bit for the unsigned-WAV convention. This path runs only when the caller set +// `output_bit_depth`, i.e. asked for a real bit-depth rescale: upscaling +// bit-replicates so full-scale input maps to full-scale output (e.g. 16-bit +// 0xFFFF -> 24-bit 0xFFFFFF) and downscaling arithmetic-shifts right. This is +// distinct from the implicit container width set by the array typecode (e.g. a +// 24-bit sample carried in a 32-bit 'i' slot), which only sign-extends and is +// handled by the default `movesign24` path. Output element size follows +// `out_depth`: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. // // For signed 24-bit output, the int32 slot holds the sign-extended value // (range -2^23 .. 2^23-1) — unlike the default `output_bit_depth=bit_depth=24` @@ -415,10 +418,24 @@ static inline void i2sin_write_converted(void *buffer, uint32_t idx, bool samples_signed, bool left_justified) { int32_t s = i2sin_normalize_signed(raw, in_depth, left_justified); int32_t shifted; - if (out_depth >= in_depth) { - // Right-justify: keep the value as-is so the meaningful bits stay in the - // low `in_depth` bits (upper bits already sign-extended). The wider - // output just provides a larger container. + if (out_depth > in_depth) { + // Explicit upscale: bit-replicate the input across the wider output so + // that full-scale input maps to full-scale output (e.g. 16-bit 0xFFFF + // -> 24-bit 0xFFFFFF), filling out_depth bits rather than leaving the + // new low bits zero. + uint32_t in_mask = (in_depth >= 32) ? 0xffffffffu : ((1u << in_depth) - 1u); + uint32_t in_bits = (uint32_t)s & in_mask; + uint32_t result = 0; + int remaining = out_depth; + while (remaining > 0) { + int take = (remaining >= (int)in_depth) ? (int)in_depth : remaining; + result = (result << take) | (in_bits >> (in_depth - take)); + remaining -= take; + } + // Sign-extend the out_depth-bit result up to int32 so a 24-bit value in + // a 32-bit container decodes correctly; harmless when out_depth == 32. + shifted = (int32_t)(result << (32 - out_depth)) >> (32 - out_depth); + } else if (out_depth == in_depth) { shifted = s; } else { shifted = s >> (in_depth - out_depth); diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 45e3645ed2f..2b098248b62 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -67,14 +67,14 @@ //| //| Note that 24-bit samples from mics like the SPH0645LM4H / INMP441 are //| transported in 32-bit slots, so use ``bit_depth=32`` and an ``'I'`` buffer. -//| :param int output_bit_depth: If set, recorded samples are bit-shifted from +//| :param int output_bit_depth: If set, recorded samples are rescaled from //| ``bit_depth`` to this width before being written to the destination buffer -//| (8, 16, 24, or 32). Widening keeps the value right-justified: for signed -//| samples the new MSBs replicate the sign bit (zeros for positive values, ones -//| for negative), while for unsigned samples the new MSBs are zero. Narrowing +//| (8, 16, 24, or 32). Widening bit-replicates so full-scale input maps to +//| full-scale output (e.g. 16-bit ``0xFFFF`` -> 24-bit ``0xFFFFFF``); narrowing //| arithmetic-shifts the value right (sign-preserving when ``samples_signed`` is //| True). When ``None`` (the default) the destination buffer holds samples at -//| ``bit_depth``. +//| ``bit_depth`` (a 24-bit sample still occupies a 32-bit ``'i'``/``'I'`` slot, +//| sign-extended without rescaling). //| :param bool mono: True when capturing a single channel of audio, captures two channels otherwise. //| :param bool left_justified: True when data bits are aligned with the word select clock. False //| when they are shifted by one to match classic I2S protocol. Set True for mics like the SPH0645LM4H. From 659ec1644b768e23f224e3555cd6d2dc28f7331c Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Wed, 3 Jun 2026 07:24:15 +0200 Subject: [PATCH 534/876] install necessary cmake version directly from cmake github releases --- .devcontainer/add_kitware_archive.sh | 107 --------------------------- .devcontainer/common_tools.sh | 10 ++- 2 files changed, 6 insertions(+), 111 deletions(-) delete mode 100755 .devcontainer/add_kitware_archive.sh diff --git a/.devcontainer/add_kitware_archive.sh b/.devcontainer/add_kitware_archive.sh deleted file mode 100755 index aff0b6c8d0f..00000000000 --- a/.devcontainer/add_kitware_archive.sh +++ /dev/null @@ -1,107 +0,0 @@ -#!/bin/sh -# ----------------------------------------------------------------------------- -# This script is from: https://apt.kitware.com/kitware-archive.sh -# -# It installs key and repo for the kitware CMAKE-archive. -# -# Author: Bernhard Bablok -# -# ----------------------------------------------------------------------------- - -set -eu - -help() { - echo "Usage: $0 [--release ] [--rc]" > /dev/stderr -} - -doing= -rc= -release= -help= -for opt in "$@" -do - case "${doing}" in - release) - release="${opt}" - doing= - ;; - "") - case "${opt}" in - --rc) - rc=1 - ;; - --release) - doing=release - ;; - --help) - help=1 - ;; - esac - ;; - esac -done - -if [ -n "${doing}" ] -then - echo "--${doing} option given no argument." > /dev/stderr - echo > /dev/stderr - help - exit 1 -fi - -if [ -n "${help}" ] -then - help - exit -fi - -if [ -z "${release}" ] -then - unset UBUNTU_CODENAME - . /etc/os-release - - if [ -z "${UBUNTU_CODENAME+x}" ] - then - echo "This is not an Ubuntu system. Aborting." > /dev/stderr - exit 1 - fi - - release="${UBUNTU_CODENAME}" -fi - -case "${release}" in -noble|jammy|focal) - packages= - keyring_packages="ca-certificates gpg wget" - ;; -*) - echo "Only Ubuntu Noble (24.04), Jammy (22.04), and Focal (20.04) are supported. Aborting." > /dev/stderr - exit 1 - ;; -esac - -get_keyring= -if [ ! -f /usr/share/doc/kitware-archive-keyring/copyright ] -then - packages="${packages} ${keyring_packages}" - get_keyring=1 -fi - -# Start the real work -set -x - -apt-get update -# shellcheck disable=SC2086 -apt-get install -y ${packages} - -test -n "${get_keyring}" && (wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - > /usr/share/keyrings/kitware-archive-keyring.gpg) - -echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ ${release} main" > /etc/apt/sources.list.d/kitware.list -if [ -n "${rc}" ] -then - echo "deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ ${release}-rc main" >> /etc/apt/sources.list.d/kitware.list -fi - -apt-get update -test -n "${get_keyring}" && rm /usr/share/keyrings/kitware-archive-keyring.gpg -apt-get install -y kitware-archive-keyring diff --git a/.devcontainer/common_tools.sh b/.devcontainer/common_tools.sh index d94977b01cc..1231b8e4f4b 100755 --- a/.devcontainer/common_tools.sh +++ b/.devcontainer/common_tools.sh @@ -9,16 +9,18 @@ # ----------------------------------------------------------------------------- REPO_ROOT="/workspaces/circuitpython" +CMAKE_VERSION="3.31.12" echo -e "[common_tools.sh] starting install" cd "$REPO_ROOT" # --- repositories and tools ------------------------------------------------ -echo -e "[common_tools.sh] adding kitware-archive (for current CMAKE)" -sudo .devcontainer/add_kitware_archive.sh -echo -e "[common_tools.sh] installing current version of CMAKE" -sudo apt-get -y install cmake +echo -e "[common_tools.sh] installing CMAKE $CMAKE_VERSION" +wget -q https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-$(arch).sh +chmod +x cmake-$CMAKE_VERSION-linux-$(arch).sh +sudo ./cmake-$CMAKE_VERSION-linux-$(arch).sh --prefix=/usr/local --skip-license +rm cmake-$CMAKE_VERSION-linux-$(arch).sh echo -e "[common_tools.sh] adding pybricks/ppa" sudo add-apt-repository -y ppa:pybricks/ppa From 78c3c7331a732e5391b3414234eecd7680d4a579 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 3 Jun 2026 09:10:24 -0500 Subject: [PATCH 535/876] refactor common code. Use bitmath instead of loop --- ports/espressif/common-hal/audioi2sin/I2SIn.c | 59 ++------------- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 62 +++------------- shared-module/audioi2sin/__init__.h | 71 +++++++++++++++++++ 3 files changed, 86 insertions(+), 106 deletions(-) create mode 100644 shared-module/audioi2sin/__init__.h diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 0098e744266..50cf5d65c33 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -12,6 +12,7 @@ #include "py/runtime.h" #include "shared-bindings/audioi2sin/I2SIn.h" #include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audioi2sin/__init__.h" #include "driver/i2s_std.h" @@ -142,61 +143,15 @@ static inline uint32_t i2sin_read_raw(const uint8_t *src, uint8_t in_depth) { return v; } -// Convert `raw` from `in_depth` to the explicitly-requested `out_depth` -// (sign-preserving for signed) and write it to `buffer` at sample index `idx`. -// This path runs only when the caller set `output_bit_depth`, i.e. asked for a -// real bit-depth rescale: upscaling bit-replicates so full-scale input maps to -// full-scale output (e.g. 16-bit 0xFFFF -> 24-bit 0xFFFFFF) and downscaling -// arithmetic-shifts right. This is distinct from the implicit container width -// set by the array typecode (e.g. a 24-bit sample carried in a 32-bit 'i' -// slot), which only sign-extends and is handled by the default path. -// Output element size: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. +// Normalize `raw` from `in_depth` for this port's wire format, then hand off to +// the shared converter to rescale `in_depth` -> `out_depth` and write it to +// `buffer` at sample index `idx`. The depth conversion + unsigned-WAV flip + +// container store live in `shared_audioi2sin_write_converted` (shared with other +// ports); see that helper for the upscale/downscale semantics. static inline void i2sin_write_converted(void *buffer, uint32_t idx, uint32_t raw, uint8_t in_depth, uint8_t out_depth, bool samples_signed) { int32_t s = i2sin_normalize_signed(raw, in_depth); - int32_t shifted; - if (out_depth > in_depth) { - // Explicit upscale: bit-replicate the input across the wider output so - // that full-scale input maps to full-scale output (e.g. 16-bit 0xFFFF - // -> 24-bit 0xFFFFFF), filling out_depth bits rather than leaving the - // new low bits zero. - uint32_t in_mask = (in_depth >= 32) ? 0xffffffffu : ((1u << in_depth) - 1u); - uint32_t in_bits = (uint32_t)s & in_mask; - uint32_t result = 0; - int remaining = out_depth; - while (remaining > 0) { - int take = (remaining >= (int)in_depth) ? (int)in_depth : remaining; - result = (result << take) | (in_bits >> (in_depth - take)); - remaining -= take; - } - // Sign-extend the out_depth-bit result up to int32 so a 24-bit value in - // a 32-bit container decodes correctly; harmless when out_depth == 32. - shifted = (int32_t)(result << (32 - out_depth)) >> (32 - out_depth); - } else if (out_depth == in_depth) { - shifted = s; - } else { - shifted = s >> (in_depth - out_depth); - } - uint32_t u = (uint32_t)shifted; - if (!samples_signed) { - if (out_depth >= 32) { - u ^= 0x80000000u; - } else { - uint32_t mask = (1u << out_depth) - 1u; - u = (u & mask) ^ (1u << (out_depth - 1)); - } - } - switch (out_depth) { - case 8: - ((uint8_t *)buffer)[idx] = (uint8_t)(u & 0xffu); - break; - case 16: - ((uint16_t *)buffer)[idx] = (uint16_t)(u & 0xffffu); - break; - default: // 24 or 32 - ((uint32_t *)buffer)[idx] = u; - break; - } + shared_audioi2sin_write_converted(buffer, idx, s, in_depth, out_depth, samples_signed); } // I2S delivers signed PCM. When samples_signed is false, XOR each sample with diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 2c6a2d75928..59106260159 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -14,6 +14,7 @@ #include "common-hal/audioi2sin/I2SIn.h" #include "shared-bindings/audioi2sin/I2SIn.h" #include "shared-bindings/microcontroller/Pin.h" +#include "shared-module/audioi2sin/__init__.h" #include "bindings/rp2pio/StateMachine.h" #include "supervisor/port.h" @@ -397,17 +398,12 @@ static inline int32_t i2sin_normalize_signed(uint32_t raw, uint8_t in_depth, return (int16_t)(raw & 0xffffu); } -// Write `raw` (input-depth bits, just-read FIFO sample) to `buffer` at sample -// index `idx`, converting from `in_depth` to the explicitly-requested -// `out_depth` (sign-preserving for signed) and (if needed) flipping the sign -// bit for the unsigned-WAV convention. This path runs only when the caller set -// `output_bit_depth`, i.e. asked for a real bit-depth rescale: upscaling -// bit-replicates so full-scale input maps to full-scale output (e.g. 16-bit -// 0xFFFF -> 24-bit 0xFFFFFF) and downscaling arithmetic-shifts right. This is -// distinct from the implicit container width set by the array typecode (e.g. a -// 24-bit sample carried in a 32-bit 'i' slot), which only sign-extends and is -// handled by the default `movesign24` path. Output element size follows -// `out_depth`: 1 byte at 8, 2 bytes at 16, 4 bytes at 24 or 32. +// Normalize `raw` (input-depth bits, just-read FIFO sample) for this port's wire +// format, then hand off to the shared converter to rescale `in_depth` -> +// `out_depth` and write it to `buffer` at sample index `idx`. The depth +// conversion + unsigned-WAV flip + container store live in +// `shared_audioi2sin_write_converted` (shared with other ports); see that helper +// for the upscale/downscale semantics. // // For signed 24-bit output, the int32 slot holds the sign-extended value // (range -2^23 .. 2^23-1) — unlike the default `output_bit_depth=bit_depth=24` @@ -417,49 +413,7 @@ static inline void i2sin_write_converted(void *buffer, uint32_t idx, uint32_t raw, uint8_t in_depth, uint8_t out_depth, bool samples_signed, bool left_justified) { int32_t s = i2sin_normalize_signed(raw, in_depth, left_justified); - int32_t shifted; - if (out_depth > in_depth) { - // Explicit upscale: bit-replicate the input across the wider output so - // that full-scale input maps to full-scale output (e.g. 16-bit 0xFFFF - // -> 24-bit 0xFFFFFF), filling out_depth bits rather than leaving the - // new low bits zero. - uint32_t in_mask = (in_depth >= 32) ? 0xffffffffu : ((1u << in_depth) - 1u); - uint32_t in_bits = (uint32_t)s & in_mask; - uint32_t result = 0; - int remaining = out_depth; - while (remaining > 0) { - int take = (remaining >= (int)in_depth) ? (int)in_depth : remaining; - result = (result << take) | (in_bits >> (in_depth - take)); - remaining -= take; - } - // Sign-extend the out_depth-bit result up to int32 so a 24-bit value in - // a 32-bit container decodes correctly; harmless when out_depth == 32. - shifted = (int32_t)(result << (32 - out_depth)) >> (32 - out_depth); - } else if (out_depth == in_depth) { - shifted = s; - } else { - shifted = s >> (in_depth - out_depth); - } - uint32_t u = (uint32_t)shifted; - if (!samples_signed) { - if (out_depth >= 32) { - u ^= 0x80000000u; - } else { - uint32_t mask = (1u << out_depth) - 1u; - u = (u & mask) ^ (1u << (out_depth - 1)); - } - } - switch (out_depth) { - case 8: - ((uint8_t *)buffer)[idx] = (uint8_t)(u & 0xffu); - break; - case 16: - ((uint16_t *)buffer)[idx] = (uint16_t)(u & 0xffffu); - break; - default: // 24 or 32 - ((uint32_t *)buffer)[idx] = u; - break; - } + shared_audioi2sin_write_converted(buffer, idx, s, in_depth, out_depth, samples_signed); } uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, diff --git a/shared-module/audioi2sin/__init__.h b/shared-module/audioi2sin/__init__.h new file mode 100644 index 00000000000..852616ee3a7 --- /dev/null +++ b/shared-module/audioi2sin/__init__.h @@ -0,0 +1,71 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +// Rescale an already-normalized signed sample and write it to `buffer` at sample +// index `idx`. `s` is the sign-extended int32 value of the sample at `in_depth` +// scale (the per-port `i2sin_normalize_signed` produces it from the raw FIFO +// word, handling wire-format details like left-justification). This helper does +// the depth conversion + unsigned-WAV flip + container store, which is identical +// across ports. +// +// This path runs only when the caller set `output_bit_depth`, i.e. asked for a +// real bit-depth rescale: upscaling bit-replicates so full-scale input maps to +// full-scale output (e.g. 16-bit 0xFFFF -> 24-bit 0xFFFFFF) and downscaling +// arithmetic-shifts right. This is distinct from the implicit container width +// set by the array typecode (e.g. a 24-bit sample carried in a 32-bit 'i' slot), +// which only sign-extends and is handled by the default (non-converting) path. +// Output element size follows `out_depth`: 1 byte at 8, 2 bytes at 16, 4 bytes +// at 24 or 32. +static inline void shared_audioi2sin_write_converted(void *buffer, uint32_t idx, + int32_t s, uint8_t in_depth, uint8_t out_depth, bool samples_signed) { + int32_t shifted; + if (out_depth > in_depth) { + // Explicit upscale: left-justify the in_depth-bit sample at the top of a + // 32-bit word and replicate the pattern downward so full-scale input + // maps to full-scale output (e.g. 16-bit 0xFFFF -> 24-bit 0xFFFFFF). Two + // steps cover every supported ratio (widest is 8 -> 32); the guard skips + // the second step (and the resulting shift-by->=32 UB) when one suffices. + uint32_t top = (uint32_t)s << (32 - in_depth); + top |= top >> in_depth; + if (in_depth * 2 < out_depth) { + top |= top >> (in_depth * 2); + } + // Arithmetic-shift the high out_depth bits down, sign-extending to int32 + // so a 24-bit value in a 32-bit slot decodes correctly (no-op at 32). + shifted = (int32_t)top >> (32 - out_depth); + } else if (out_depth == in_depth) { + shifted = s; + } else { + shifted = s >> (in_depth - out_depth); + } + uint32_t u = (uint32_t)shifted; + if (!samples_signed) { + // I2S delivers signed PCM; flip the sign bit to match the WAV unsigned + // convention, at the output bit width. + if (out_depth >= 32) { + u ^= 0x80000000u; + } else { + uint32_t mask = (1u << out_depth) - 1u; + u = (u & mask) ^ (1u << (out_depth - 1)); + } + } + switch (out_depth) { + case 8: + ((uint8_t *)buffer)[idx] = (uint8_t)(u & 0xffu); + break; + case 16: + ((uint16_t *)buffer)[idx] = (uint16_t)(u & 0xffffu); + break; + default: // 24 or 32 + ((uint32_t *)buffer)[idx] = u; + break; + } +} From 258a91d3aa15f10e97afaad456131463ae869e4a Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Wed, 3 Jun 2026 18:54:41 +0200 Subject: [PATCH 536/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 24 ++++++++++++++++++------ locale/el.po | 24 ++++++++++++++++++------ locale/hi.po | 24 ++++++++++++++++++------ locale/ko.po | 24 ++++++++++++++++++------ locale/ru.po | 27 +++++++++++++++++++++------ locale/tr.po | 24 ++++++++++++++++++------ 6 files changed, 111 insertions(+), 36 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 8b74ea65cf9..9a0c478cc2d 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -197,6 +197,15 @@ msgstr "%q musí být %d-%d" msgid "%q must be 1 when %q is True" msgstr "%q musí být 1, pokud %q je True" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -673,6 +682,7 @@ msgid "Below minimum frame rate" msgstr "Pod minimální obnovovací frekvencí" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" @@ -820,7 +830,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "Nelze aktivovat pull rezistor na pinu, který je pouze pro vstup." -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "Nelze nahrávat do souboru" @@ -944,7 +954,7 @@ msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" "Piny pro hluboký spánek musí používat náběžnou hranu s pulldown rezistorem" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "Cílová kapacita je menší než destination_length." @@ -1836,6 +1846,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "Periférie je používána" @@ -2733,10 +2744,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -3547,6 +3554,11 @@ msgstr "chybné bits_per_pixel %d, musí být 1, 2, 4, 8, 16, 24, or 32" msgid "invalid cert" msgstr "špatný certifikár" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" diff --git a/locale/el.po b/locale/el.po index 35706161025..3bb156d02d2 100644 --- a/locale/el.po +++ b/locale/el.po @@ -201,6 +201,15 @@ msgstr "%q πρέπει να είναι %d-%d" msgid "%q must be 1 when %q is True" msgstr "%q πρέπει να είναι 1 όταν %q είναι True" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -677,6 +686,7 @@ msgid "Below minimum frame rate" msgstr "Χαμηλότερο από το ελάχιστο frame rate" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" msgstr "Ρολόι bit και ορισμού λέξης πρέπει να είναι διαδοχικά GPIO pins" @@ -825,7 +835,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "Δεν γίνεται pull σε pin μόνο για εισόδο." -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "Δεν μπορεί να γίνει καταγραφή σε αρχείο" @@ -949,7 +959,7 @@ msgstr "Τα δεδομένα είναι πολύ μεγάλα για πακέτ msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "Τα pins βαθύ ύπνου πρέπει να χρησιμοποιούν rising edge με pulldown" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" "Το μέγεθος προορισμού πρέπει να είναι μικρότερο από το destination_length." @@ -1841,6 +1851,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "" @@ -2732,10 +2743,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -3546,6 +3553,11 @@ msgstr "" msgid "invalid cert" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" diff --git a/locale/hi.po b/locale/hi.po index 0ad0394d060..a9f0e14fbb0 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -188,6 +188,15 @@ msgstr "" msgid "%q must be 1 when %q is True" msgstr "" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -662,6 +671,7 @@ msgid "Below minimum frame rate" msgstr "" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" @@ -806,7 +816,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "" @@ -928,7 +938,7 @@ msgstr "" msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "" @@ -1817,6 +1827,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "" @@ -2706,10 +2717,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -3520,6 +3527,11 @@ msgstr "" msgid "invalid cert" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" diff --git a/locale/ko.po b/locale/ko.po index 8731a7e8d4b..a2a2b15e647 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -199,6 +199,15 @@ msgstr "%q는 %d-%d이어야 합니다" msgid "%q must be 1 when %q is True" msgstr "%q가 참일 때 %q는 1이어야 합니다" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c #, fuzzy @@ -703,6 +712,7 @@ msgid "Below minimum frame rate" msgstr "최소 프레임 속도 미만" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" msgstr "비트 클럭 및 워드 선택은 순차적 GPIO 핀이어야 합니다" @@ -848,7 +858,7 @@ msgstr "확장되고 연결 가능한 광고에 대한 검색 응답을 가질 msgid "Cannot pull on input-only pin." msgstr "입력 전용 핀을 끌어올 수 없습니다." -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "파일에 녹음 할 수 없습니다" @@ -973,7 +983,7 @@ msgstr "광고 (브로드 캐스트) 패킷에 대한 데이터가 너무 큽니 msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "딥 슬립 핀은 풀다운이 있는 상승 에지를 사용해야 합니다" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "대상 용량이 destination_length보다 작습니다." @@ -1886,6 +1896,7 @@ msgid "Parameter error" msgstr "파라미터 오류" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c #, fuzzy msgid "Peripheral in use" msgstr "주변 기기가 사용 중입니다" @@ -2780,10 +2791,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -3594,6 +3601,11 @@ msgstr "" msgid "invalid cert" msgstr "cert가 유효하지 않습니다" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" diff --git a/locale/ru.po b/locale/ru.po index e535756a036..4e972e31931 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -201,6 +201,15 @@ msgstr "%q должно быть %d-%d" msgid "%q must be 1 when %q is True" msgstr "%q должен быть равен 1, если %q имеет значение True" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -677,6 +686,7 @@ msgid "Below minimum frame rate" msgstr "Ниже минимальной частоты кадров" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" msgstr "Несколько часов и слов должны быть последовательными GPIO пинами" @@ -827,7 +837,7 @@ msgstr "" msgid "Cannot pull on input-only pin." msgstr "Невозможно вытащить контакт только для ввода." -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "Невозможно записать в файл" @@ -954,7 +964,7 @@ msgstr "" "Выводы глубокого сна должны использовать сигнал по возрастанию с подтяжкой к " "земле" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "Емкость места назначения меньше длины места назначения." @@ -1862,6 +1872,7 @@ msgid "Parameter error" msgstr "Ошибка параметра" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "Периферийные устройства в использовании" @@ -2776,10 +2787,6 @@ msgstr "Неверный шрифт" msgid "binary op %q not implemented" msgstr "двоичная операция %q не реализована" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "Глубина_бита должна быть равна 8, 16, 24 или 32." - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "Размер и глубина растрового изображения должны совпадать" @@ -3601,6 +3608,11 @@ msgstr "неверный бит_на_пиксель %d, должно быть 1, msgid "invalid cert" msgstr "Неверный сертификат" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" @@ -4692,6 +4704,9 @@ msgstr "zi должно быть типа float" msgid "zi must be of shape (n_section, 2)" msgstr "zi должен иметь форму (n_section, 2)" +#~ msgid "bit_depth must be 8, 16, 24, or 32." +#~ msgstr "Глубина_бита должна быть равна 8, 16, 24 или 32." + #~ msgid "%q renamed %q" #~ msgstr "%q переименован %q" diff --git a/locale/tr.po b/locale/tr.po index 7b367e53c12..c99e56326af 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -199,6 +199,15 @@ msgstr "%q, %d-%d olmalıdır" msgid "%q must be 1 when %q is True" msgstr "%q 1 olmalı, %q True olduğu zaman" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c msgid "%q must be <= %d" @@ -675,6 +684,7 @@ msgid "Below minimum frame rate" msgstr "Minimum kare hızından altında" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" @@ -820,7 +830,7 @@ msgstr "Genişletilmiş, bağlanabilir reklamlar için tarama yanıtları yapıl msgid "Cannot pull on input-only pin." msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" msgstr "Dosyaya kayıt yapılamıyor" @@ -942,7 +952,7 @@ msgstr "" msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." msgstr "Hedef kapasitesi, hedef_uzunluğundan daha küçük." @@ -1836,6 +1846,7 @@ msgid "Parameter error" msgstr "" #: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c msgid "Peripheral in use" msgstr "" @@ -2728,10 +2739,6 @@ msgstr "" msgid "binary op %q not implemented" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -msgid "bit_depth must be 8, 16, 24, or 32." -msgstr "" - #: shared-module/bitmapfilter/__init__.c msgid "bitmap size and depth must match" msgstr "" @@ -3542,6 +3549,11 @@ msgstr "" msgid "invalid cert" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" + #: shared-bindings/bitmaptools/__init__.c #, c-format msgid "invalid element size %d for bits_per_pixel %d\n" From d18aca4bd239c95ba97cbbfb0173a073a231032e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 4 Jun 2026 13:55:40 -0700 Subject: [PATCH 537/876] Pin protobuf version to 6.33.5 Add protobuf version pinning due to Perfetto package issue. --- requirements-dev.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requirements-dev.txt b/requirements-dev.txt index 6a33c49daec..069caf4ce6c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -43,3 +43,5 @@ tomlkit pytest pytest-rerunfailures perfetto +# Perfetto Python package doesn't correctly pin it's protobuf version so we add it here. +protobuf==6.33.5 From 683d55ca7d0596f9f120b0ab8924c379a78127a7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 4 Jun 2026 14:08:27 -0700 Subject: [PATCH 538/876] Update requirements-dev.txt Co-authored-by: Dan Halbert --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 069caf4ce6c..ab7c6b3aaf0 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -43,5 +43,5 @@ tomlkit pytest pytest-rerunfailures perfetto -# Perfetto Python package doesn't correctly pin it's protobuf version so we add it here. +# Perfetto Python package doesn't correctly pin its protobuf version so we add it here. protobuf==6.33.5 From c5c96296450305b3544d729bfe26955fb0be2c00 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 4 Jun 2026 22:45:22 +0000 Subject: [PATCH 539/876] Scope protobuf pin to Zephyr setup only --- .github/actions/deps/ports/zephyr-cp/action.yml | 3 +++ requirements-dev.txt | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/actions/deps/ports/zephyr-cp/action.yml b/.github/actions/deps/ports/zephyr-cp/action.yml index 6c538e3fa57..4475132e185 100644 --- a/.github/actions/deps/ports/zephyr-cp/action.yml +++ b/.github/actions/deps/ports/zephyr-cp/action.yml @@ -26,3 +26,6 @@ runs: run: west zephyr-export shell: bash working-directory: ports/zephyr-cp + - name: Install Zephyr protobuf dependency + run: pip install protobuf==6.33.5 + shell: bash diff --git a/requirements-dev.txt b/requirements-dev.txt index ab7c6b3aaf0..6a33c49daec 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -43,5 +43,3 @@ tomlkit pytest pytest-rerunfailures perfetto -# Perfetto Python package doesn't correctly pin its protobuf version so we add it here. -protobuf==6.33.5 From ff80caadbf58e3f3d8ae2939882e706508d81014 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 4 Jun 2026 19:15:42 -0400 Subject: [PATCH 540/876] Restrict Build CI push branches Limit Build CI push runs to main and maintenance branches. This avoids duplicate board builds for same-repo pull requests, where both push and pull_request events currently run the same workflow. It also avoids duplicate release builds, where publishing a release currently triggers both a tag push run and a release run for the same SHA. Fork pull requests continue to work because upstream CI still runs on pull_request; only the upstream push trigger is narrowed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a2329a4113..bd803a5eb6b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,6 +6,9 @@ name: Build CI on: push: + branches: + - main + - '*.x' pull_request: release: types: [published] From f5374e12008fbd22331611b6c7d83703617b255e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 5 Jun 2026 16:50:43 -0400 Subject: [PATCH 541/876] espressif/Makefile: add sdkconfig-ble.defaults in proper priority order --- ports/espressif/Makefile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ports/espressif/Makefile b/ports/espressif/Makefile index 792444948ad..da1f1e4e878 100644 --- a/ports/espressif/Makefile +++ b/ports/espressif/Makefile @@ -839,16 +839,18 @@ ifeq ($(ENABLE_JTAG), 1) CFLAGS += -DENABLE_JTAG=1 endif -SDKCONFIGS := esp-idf-config/sdkconfig.defaults;$(DEBUG_SDKCONFIG);$(FLASH_SIZE_SDKCONFIG);$(FLASH_MODE_SDKCONFIG);$(FLASH_SPEED_SDKCONFIG);$(PSRAM_SDKCONFIG);$(PSRAM_SIZE_SDKCONFIG);$(PSRAM_MODE_SDKCONFIG);$(PSRAM_SPEED_SDKCONFIG);$(TARGET_SDKCONFIG);boards/$(BOARD)/sdkconfig ifneq ($(CIRCUITPY_BLEIO_NATIVE),0) - SDKCONFIGS := esp-idf-config/sdkconfig-ble.defaults;$(SDKCONFIGS) + BLE_SDKCONFIG := ;esp-idf-config/sdkconfig-ble.defaults endif + +SDKCONFIGS := esp-idf-config/sdkconfig.defaults;$(DEBUG_SDKCONFIG);$(FLASH_SIZE_SDKCONFIG);$(FLASH_MODE_SDKCONFIG);$(FLASH_SPEED_SDKCONFIG);$(PSRAM_SDKCONFIG);$(PSRAM_SIZE_SDKCONFIG);$(PSRAM_MODE_SDKCONFIG);$(PSRAM_SPEED_SDKCONFIG);$(BLE_SDKCONFIG);$(TARGET_SDKCONFIG);boards/$(BOARD)/sdkconfig + # create the config headers .PHONY: do-sdkconfig do-sdkconfig: $(BUILD)/esp-idf/config/sdkconfig.h QSTR_GLOBAL_REQUIREMENTS += $(BUILD)/esp-idf/config/sdkconfig.h $(BUILD)/esp-idf/config/sdkconfig.h: boards/$(BOARD)/sdkconfig boards/$(BOARD)/mpconfigboard.mk CMakeLists.txt | $(BUILD)/esp-idf - $(STEPECHO) "LINK $@" + $(STEPECHO) "Create $@" $(Q)env IDF_PATH=$(IDF_PATH) IDF_COMPONENT_MANAGER=0 cmake -S . -B $(BUILD)/esp-idf -DSDKCONFIG=$(BUILD)/esp-idf/sdkconfig -DSDKCONFIG_DEFAULTS="$(SDKCONFIGS)" -DCMAKE_TOOLCHAIN_FILE=$(IDF_PATH)/tools/cmake/toolchain-$(IDF_TARGET).cmake -DIDF_TARGET=$(IDF_TARGET) -GNinja $(Q)$(PYTHON) tools/check-sdkconfig.py \ CIRCUITPY_DUALBANK=$(CIRCUITPY_DUALBANK) \ From bf1059ba7b4b4f3993f11e89e41b5b4d29cf0847 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 7 Jun 2026 21:13:03 -0400 Subject: [PATCH 542/876] Prevent safe mode caused by BLE watchdog mode firing. Fix by stopping all connections before cleaning up event handlers. Before this change, ctrl-c during a BLE program would sometimes caused safe mode. There was no backtrace printed in debug output. I thought perhaps `ble_event_remove_heap_handlers()` was a problem, because it might be removing event handlers that were running in the BLE task. If I wrapped the insides of that in `common_hal_mcu_disable_interrupts()` and `common_hal_cmu_enable_interrupts()`, then I could _reliably_ cause safe mode. --- ports/espressif/common-hal/_bleio/Adapter.c | 4 +--- ports/espressif/common-hal/_bleio/__init__.c | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index d39b22a3ae9..0f53005d2bc 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -820,9 +820,7 @@ void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) { void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { common_hal_bleio_adapter_stop_scan(adapter); - if (common_hal_bleio_adapter_get_advertising(adapter)) { - common_hal_bleio_adapter_stop_advertising(adapter); - } + common_hal_bleio_adapter_stop_advertising(adapter); adapter->connection_objs = NULL; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index 4fdd0a48a20..49bc947c21d 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -32,9 +32,9 @@ static uint64_t _timeout_start_time; background_callback_t bleio_background_callback; void bleio_user_reset(void) { - // Stop any user scanning or advertising. - common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); - common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); + // Stop any user scanning or advertising, and stop all connections. + // TODO: Don't stop BLE workflow connection. + bleio_adapter_reset(&common_hal_bleio_adapter_obj); ble_event_remove_heap_handlers(); From adb362fc5cc87374817b20ac891d3b71928451e1 Mon Sep 17 00:00:00 2001 From: Piclaw Date: Tue, 9 Jun 2026 09:36:07 -0700 Subject: [PATCH 543/876] tools/ci_fetch_deps: add lib/mbedtls/ to nordic submodule list nordic boards build with CIRCUITPY_HASHLIB_MBEDTLS_ONLY=1 which pulls sha1.c / sha256.c / sha512.c / platform_util.c from lib/mbedtls but ci_fetch_deps.py never fetched the submodule, breaking custom builds. Drive-by; not strictly part of the #10972 fix, but needed for the custom build-board workflow to produce a CLUE UF2 for verification. --- tools/ci_fetch_deps.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci_fetch_deps.py b/tools/ci_fetch_deps.py index 339eec28712..05559ac2d12 100644 --- a/tools/ci_fetch_deps.py +++ b/tools/ci_fetch_deps.py @@ -69,6 +69,7 @@ def _all_submodules(): "mimxrt10xx": ["extmod/ulab/", "lib/tinyusb/", "lib/tlsf", "data/nvm.toml/"], "nordic": [ "extmod/ulab/", + "lib/mbedtls/", "lib/mp3/", "lib/protomatter/", "lib/tinyusb/", From a8924a8ef103b6bdbb8bbf47ad928ca748fb1fde Mon Sep 17 00:00:00 2001 From: Piclaw Date: Tue, 9 Jun 2026 10:15:43 -0700 Subject: [PATCH 544/876] supervisor/filesystem: let alternative writers (BLE-FT, web workflow) bypass STA_PROTECT while they hold the lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since #10659, filesystem_is_writable_by_python() returns false on any USB-device-capable board after main.c boot (CONCURRENT_WRITE_PROTECTED and USB_WRITABLE are both set). vfs_fat_diskio.c:disk_ioctl(IOCTL_STATUS) calls this function and reports STA_PROTECT when it returns false, so f_open(FA_WRITE) returns FR_WRITE_PROTECTED. This affects every non-USB-MSC writer that calls f_open directly through FatFS: - BLE File Transfer (supervisor/shared/bluetooth/file_transfer.c): all WRITE/MOVE/MKDIR/DELETE commands fail with STATUS_ERROR_READONLY even when the board has no host on the bus. This is the original #10972 repro on CLUE running from battery. - Web workflow PUT/POST/MOVE/DELETE (supervisor/shared/web_workflow): same path, web-editor #460/#506 surfaces this as a read-only error. - storage.remount(readonly=False): can take the lock but then can't actually write while the lock is held. Each of these already calls filesystem_lock() to claim the blockdev LOCKED flag before writing. USB MSC does NOT go through filesystem_lock; it grabs LOCKED directly via blockdev_lock() inside tud_msc_is_writable_cb. So filesystem_lock() is exactly the right place to grant temporary write permission via IGNORE_WRITE_PROTECTION, mirroring the pattern main.c uses around boot.py. After this change: - filesystem_lock() is the single source of truth for 'I'm the local writer right now'. Holders can f_open(FA_WRITE) and operate normally. - USB MSC continues to be mutually excluded via LOCKED; it never sets IGNORE_WRITE_PROTECTION because it doesn't go through filesystem_lock. - _is_writable_by_python and _is_writable_by_usb are unchanged; the symmetric mutex from #10659 is preserved. - Python direct open(FA_WRITE) without a lock still requires storage.disable_usb_drive() or storage.remount(readonly=False) — same as current behavior. Fixes #10972 --- supervisor/shared/filesystem.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 55fef541a67..1d2a6180a94 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -327,12 +327,23 @@ bool filesystem_lock(fs_user_mount_t *fs_mount) { return false; } fs_mount->lock_count += 1; + // CIRCUITPY-CHANGE: while a non-USB-MSC writer (BLE file transfer, web + // workflow, storage.remount) holds the filesystem lock, allow the + // FatFS f_open(FA_WRITE) path to bypass STA_PROTECT. Without this, the + // disk_ioctl(IOCTL_STATUS) -> filesystem_is_writable_by_python() check + // added by #10659 always sets STA_PROTECT on USB-device-capable boards, + // so even after the lock is held, f_open returns FR_WRITE_PROTECTED. + // USB MSC takes the lock via blockdev_lock() directly, NOT via + // filesystem_lock(), so this flag is never set on its behalf. + fs_mount->blockdev.flags |= MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION; return true; } void filesystem_unlock(fs_user_mount_t *fs_mount) { fs_mount->lock_count -= 1; if (fs_mount->lock_count == 0) { + // CIRCUITPY-CHANGE: clear the bypass when releasing the lock. + fs_mount->blockdev.flags &= ~MP_BLOCKDEV_FLAG_IGNORE_WRITE_PROTECTION; blockdev_unlock(fs_mount); } } From 7e5709f1bbe15ca8e117a90defa90fd7a75ce7af Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Wed, 10 Jun 2026 13:48:23 +0200 Subject: [PATCH 545/876] support DigitialInOutProtocol for CS of sdcardio.SDCard --- shared-bindings/sdcardio/SDCard.c | 8 +++++--- shared-bindings/sdcardio/SDCard.h | 2 +- shared-module/sdcardio/SDCard.c | 32 ++++++++++++++++++++++--------- shared-module/sdcardio/SDCard.h | 5 +++-- 4 files changed, 32 insertions(+), 15 deletions(-) diff --git a/shared-bindings/sdcardio/SDCard.c b/shared-bindings/sdcardio/SDCard.c index 79f0a83b8cf..506009f64d6 100644 --- a/shared-bindings/sdcardio/SDCard.c +++ b/shared-bindings/sdcardio/SDCard.c @@ -25,7 +25,10 @@ //| with ``storage.VfsFat`` to allow file I/O to an SD card.""" //| //| def __init__( -//| self, bus: busio.SPI, cs: microcontroller.Pin, baudrate: int = 8000000 +//| self, +//| bus: busio.SPI, +//| cs: Union[microcontroller.Pin, digitalio.DigitalInOutProtocol], +//| baudrate: int = 8000000 //| ) -> None: //| """Construct an SPI SD Card object with the given properties //| @@ -87,10 +90,9 @@ static mp_obj_t sdcardio_sdcard_make_new(const mp_obj_type_t *type, size_t n_arg mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); busio_spi_obj_t *spi = validate_obj_is_spi_bus(args[ARG_spi].u_obj, MP_QSTR_spi); - const mcu_pin_obj_t *cs = validate_obj_is_free_pin(args[ARG_cs].u_obj, MP_QSTR_cs); sdcardio_sdcard_obj_t *self = mp_obj_malloc_with_finaliser(sdcardio_sdcard_obj_t, &sdcardio_SDCard_type); - common_hal_sdcardio_sdcard_construct(self, spi, cs, args[ARG_baudrate].u_int); + common_hal_sdcardio_sdcard_construct(self, spi, args[ARG_cs].u_obj, args[ARG_baudrate].u_int); return MP_OBJ_FROM_PTR(self); } diff --git a/shared-bindings/sdcardio/SDCard.h b/shared-bindings/sdcardio/SDCard.h index d0cb8206c34..4251575f8fd 100644 --- a/shared-bindings/sdcardio/SDCard.h +++ b/shared-bindings/sdcardio/SDCard.h @@ -12,7 +12,7 @@ extern const mp_obj_type_t sdcardio_SDCard_type; -void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, const mcu_pin_obj_t *cs, int baudrate); +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *spi, mp_obj_t cs, int baudrate); void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self); bool common_hal_sdcardio_sdcard_deinited(sdcardio_sdcard_obj_t *self); void common_hal_sdcardio_sdcard_check_for_deinit(sdcardio_sdcard_obj_t *self); diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index 3630e4ea167..7ed9d607c47 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -17,6 +17,8 @@ #include "py/mperrno.h" #include "py/mphal.h" +#include "py/gc.h" +#include "supervisor/port.h" #if 0 #define DEBUG_PRINT(...) ((void)mp_printf(&mp_plat_print,##__VA_ARGS__)) @@ -78,7 +80,7 @@ static bool lock_and_configure_bus(sdcardio_sdcard_obj_t *self) { } common_hal_busio_spi_configure(self->bus, self->baudrate, 0, 0, 8); - common_hal_digitalio_digitalinout_set_value(&self->cs, false); + digitalinout_protocol_set_value(self->cs, false); return true; } @@ -91,7 +93,7 @@ static void lock_bus_or_throw(sdcardio_sdcard_obj_t *self) { static void clock_card(sdcardio_sdcard_obj_t *self, int bytes) { uint8_t buf[bytes]; memset(buf, 0xff, bytes); - common_hal_digitalio_digitalinout_set_value(&self->cs, true); + digitalinout_protocol_set_value(self->cs, true); common_hal_busio_spi_write(self->bus, buf, bytes); } @@ -260,7 +262,7 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { // and says 80 bit clocks(10*8) is common. Value below is bytes, not bits. clock_card(self, 10); - common_hal_digitalio_digitalinout_set_value(&self->cs, false); + digitalinout_protocol_set_value(self->cs, false); assert(!self->in_cmd25); self->in_cmd25 = false; // should be false already @@ -336,11 +338,17 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { return NULL; } -mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate, bool persistent_mount) { +mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mp_obj_t cs, int baudrate, bool persistent_mount) { self->bus = bus; self->persistent_mount = persistent_mount; - common_hal_digitalio_digitalinout_construct(&self->cs, cs); - common_hal_digitalio_digitalinout_switch_to_output(&self->cs, true, DRIVE_MODE_PUSH_PULL); + + // Allocate the pins in the same place as self. + bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); + + self->cs = digitalinout_protocol_from_pin(cs, MP_QSTR_cs, true, use_port_allocation, &self->own_cs); + if (self->cs != mp_const_none) { + digitalinout_protocol_switch_to_output(self->cs, true, DRIVE_MODE_PUSH_PULL); + } self->cdv = 512; self->sectors = 0; @@ -353,7 +361,10 @@ mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio extraclock_and_unlock_bus(self); if (result != NULL) { - common_hal_digitalio_digitalinout_deinit(&self->cs); + if (self->cs != mp_const_none && self->own_cs) { + digitalinout_protocol_deinit(self->cs); + circuitpy_free_obj(self->cs); + } return result; } @@ -362,7 +373,7 @@ mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio } -void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate) { +void common_hal_sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mp_obj_t cs, int baudrate) { // User mounted, so persistent_mount=false. mp_rom_error_text_t result = sdcardio_sdcard_construct(self, bus, cs, baudrate, false); if (result != NULL) { @@ -376,7 +387,10 @@ void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self) { } common_hal_sdcardio_sdcard_sync(self); common_hal_sdcardio_sdcard_mark_deinit(self); - common_hal_digitalio_digitalinout_deinit(&self->cs); + if (self->cs != mp_const_none && self->own_cs) { + digitalinout_protocol_deinit(self->cs); + circuitpy_free_obj(self->cs); + } } int common_hal_sdcardio_sdcard_get_blockcount(sdcardio_sdcard_obj_t *self) { diff --git a/shared-module/sdcardio/SDCard.h b/shared-module/sdcardio/SDCard.h index 35a9ed1bf3c..6af68c274cd 100644 --- a/shared-module/sdcardio/SDCard.h +++ b/shared-module/sdcardio/SDCard.h @@ -17,7 +17,7 @@ typedef struct { mp_obj_base_t base; busio_spi_obj_t *bus; - digitalio_digitalinout_obj_t cs; + mp_obj_t cs; int cdv; int baudrate; uint32_t sectors; @@ -26,6 +26,7 @@ typedef struct { // Automounted SD cards are usually persistent across VM's. Note this as needed to allow access // when the VM is not running. bool persistent_mount; + bool own_cs; } sdcardio_sdcard_obj_t; -mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, const mcu_pin_obj_t *cs, int baudrate, bool persistent_mount); +mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio_spi_obj_t *bus, mp_obj_t cs, int baudrate, bool persistent_mount); From 227d938635ee5961736928b8e07e2bd94b5e7715 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 11 Jun 2026 20:41:14 -0400 Subject: [PATCH 546/876] espressif: don't do ble resets if adapter is not enabled; can cause crashes --- ports/espressif/common-hal/_bleio/Adapter.c | 3 +++ ports/espressif/common-hal/_bleio/__init__.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index 0f53005d2bc..4feb6b2b96b 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -819,6 +819,9 @@ void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter) { } void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + return; + } common_hal_bleio_adapter_stop_scan(adapter); common_hal_bleio_adapter_stop_advertising(adapter); diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index 49bc947c21d..552ba0575b3 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -32,6 +32,9 @@ static uint64_t _timeout_start_time; background_callback_t bleio_background_callback; void bleio_user_reset(void) { + if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { + return; + } // Stop any user scanning or advertising, and stop all connections. // TODO: Don't stop BLE workflow connection. bleio_adapter_reset(&common_hal_bleio_adapter_obj); From 281a67408fd5e6aa7c43588b195811f6190c4570 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 11 Jun 2026 20:20:28 -0400 Subject: [PATCH 547/876] Fix slow espressif BLE discovery Avoid writing to remote characteristics during discovery, and make descriptor discovery use per-step timeouts and the correct end handle. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../common-hal/_bleio/Characteristic.c | 2 +- .../espressif/common-hal/_bleio/Connection.c | 53 +++++++++---------- 2 files changed, 25 insertions(+), 30 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Characteristic.c b/ports/espressif/common-hal/_bleio/Characteristic.c index 736c61c650e..ff9ab35c1b9 100644 --- a/ports/espressif/common-hal/_bleio/Characteristic.c +++ b/ports/espressif/common-hal/_bleio/Characteristic.c @@ -92,7 +92,7 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->max_length = max_length; self->fixed_length = fixed_length; - if (initial_value_bufinfo != NULL) { + if (!service->is_remote && initial_value_bufinfo != NULL) { common_hal_bleio_characteristic_set_value(self, initial_value_bufinfo); } diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 42816cffb6f..d9597bdd73e 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -183,7 +183,7 @@ static volatile int _last_discovery_status; static uint64_t _discovery_start_time; -// Give 20 seconds for discovery +// Give 20 seconds for each discovery step. #define DISCOVERY_TIMEOUT_MS 20000 static void _start_discovery_timeout(void) { @@ -199,6 +199,9 @@ static int _wait_for_discovery_step_done(void) { _last_discovery_status = BLE_HS_EDONE; } } + if (_last_discovery_status == 0) { + return BLE_HS_ETIMEOUT; + } return _last_discovery_status; } @@ -207,6 +210,17 @@ static void _set_discovery_step_status(int status) { _last_discovery_status = status; } +static void _check_discovery_status(int status) { + if (status == BLE_HS_EDONE) { + return; + } + if (status < BLE_HS_ERR_ATT_BASE) { + CHECK_NIMBLE_ERROR(status); + return; + } + CHECK_BLE_ERROR(status); +} + static int _discovered_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *svc, @@ -280,10 +294,6 @@ static int _discovered_characteristic_cb(uint16_t conn_handle, // Set def_handle directly since it is only used in discovery. characteristic->def_handle = chr->def_handle; - #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_characteristic_cb: char handle: %d\n", characteristic->handle); - #endif - mp_obj_list_append(MP_OBJ_FROM_PTR(service->characteristic_list), MP_OBJ_FROM_PTR(characteristic)); return 0; @@ -297,12 +307,6 @@ static int _discovered_descriptor_cb(uint16_t conn_handle, bleio_characteristic_obj_t *characteristic = (bleio_characteristic_obj_t *)arg; if (error->status != 0) { - - #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_descriptor_cb error->status: %d, handle: %d\n", - error->status, error->att_handle); - #endif - // BLE_HS_EDONE or some error has occurred. _set_discovery_step_status(error->status); return 0; @@ -336,11 +340,6 @@ static int _discovered_descriptor_cb(uint16_t conn_handle, GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); descriptor->handle = dsc->handle; - #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_descriptor_cb: char handle: %d, desc handle: %d, uuid type: %d, u16 value: 0x%x\n", - characteristic->handle, descriptor->handle, dsc->uuid.u.type, dsc->uuid.u16.value); - #endif - mp_obj_list_append(MP_OBJ_FROM_PTR(characteristic->descriptor_list), MP_OBJ_FROM_PTR(descriptor)); return 0; @@ -356,14 +355,13 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t if (service_uuids_whitelist == mp_const_none) { // Reset discovery status before starting callbacks _set_discovery_step_status(0); + _start_discovery_timeout(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_svcs(self->conn_handle, _discovered_service_cb, self)); // Wait for _discovered_service_cb() to be called multiple times until it's done. int status = _wait_for_discovery_step_done(); - if (status != BLE_HS_EDONE) { - CHECK_BLE_ERROR(status); - } + _check_discovery_status(status); } else { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); @@ -376,15 +374,14 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Reset discovery status before starting callbacks _set_discovery_step_status(0); + _start_discovery_timeout(); CHECK_NIMBLE_ERROR(ble_gattc_disc_svc_by_uuid(self->conn_handle, &uuid->nimble_ble_uuid.u, _discovered_service_cb, self)); // Wait for _discovered_service_cb() to be called multiple times until it's done. int status = _wait_for_discovery_step_done(); - if (status != BLE_HS_EDONE) { - CHECK_BLE_ERROR(status); - } + _check_discovery_status(status); } } @@ -395,6 +392,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Reset discovery status before starting callbacks _set_discovery_step_status(0); + _start_discovery_timeout(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_chrs(self->conn_handle, service->start_handle, @@ -404,9 +402,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Wait for _discovered_characteristic_cb() to be called multiple times until it's done. int status = _wait_for_discovery_step_done(); - if (status != BLE_HS_EDONE) { - CHECK_BLE_ERROR(status); - } + _check_discovery_status(status); // Got characteristics for this service. Now discover descriptors for each characteristic. size_t char_list_len = service->characteristic_list->len; @@ -423,7 +419,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t uint16_t end_handle = next_characteristic == NULL ? service->end_handle - : next_characteristic->handle - 1; + : next_characteristic->def_handle - 1; // Pre-check if there are no descriptors to discover so descriptor discovery doesn't fail if (end_handle <= characteristic->handle) { @@ -432,6 +428,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Reset discovery status before starting callbacks _set_discovery_step_status(0); + _start_discovery_timeout(); // The descriptor handle inclusive range is [characteristic->handle + 1, end_handle], // but ble_gattc_disc_all_dscs() requires starting with characteristic->handle. @@ -441,9 +438,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Wait for _discovered_descriptor_cb to be called multiple times until it's done. status = _wait_for_discovery_step_done(); - if (status != BLE_HS_EDONE) { - CHECK_BLE_ERROR(status); - } + _check_discovery_status(status); } } } From 4433e995fd1765c80579d66ad58635abdeb1dd72 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 12 Jun 2026 07:36:16 -0400 Subject: [PATCH 548/876] restore debugging code; shorten discovery step timeout --- .../espressif/common-hal/_bleio/Connection.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index d9597bdd73e..86ebd6c8e91 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -183,8 +183,8 @@ static volatile int _last_discovery_status; static uint64_t _discovery_start_time; -// Give 20 seconds for each discovery step. -#define DISCOVERY_TIMEOUT_MS 20000 +// Give 3 seconds for each discovery step. +#define DISCOVERY_TIMEOUT_MS 3000 static void _start_discovery_timeout(void) { _discovery_start_time = common_hal_time_monotonic_ms(); @@ -294,6 +294,10 @@ static int _discovered_characteristic_cb(uint16_t conn_handle, // Set def_handle directly since it is only used in discovery. characteristic->def_handle = chr->def_handle; + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_characteristic_cb: char handle: %d\n", characteristic->handle); + #endif + mp_obj_list_append(MP_OBJ_FROM_PTR(service->characteristic_list), MP_OBJ_FROM_PTR(characteristic)); return 0; @@ -307,6 +311,12 @@ static int _discovered_descriptor_cb(uint16_t conn_handle, bleio_characteristic_obj_t *characteristic = (bleio_characteristic_obj_t *)arg; if (error->status != 0) { + + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_descriptor_cb error->status: %d, handle: %d\n", + error->status, error->att_handle); + #endif + // BLE_HS_EDONE or some error has occurred. _set_discovery_step_status(error->status); return 0; @@ -340,6 +350,11 @@ static int _discovered_descriptor_cb(uint16_t conn_handle, GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); descriptor->handle = dsc->handle; + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_descriptor_cb: char handle: %d, desc handle: %d, uuid type: %d, u16 value: 0x%x\n", + characteristic->handle, descriptor->handle, dsc->uuid.u.type, dsc->uuid.u16.value); + #endif + mp_obj_list_append(MP_OBJ_FROM_PTR(characteristic->descriptor_list), MP_OBJ_FROM_PTR(descriptor)); return 0; From daa8531137283ad96473c438fe69b07683b8f2e5 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 12 Jun 2026 10:24:41 -0400 Subject: [PATCH 549/876] simplify BLE connection timeout; increase back to 20 secs; 3 secs was too short --- .../espressif/common-hal/_bleio/Connection.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 86ebd6c8e91..8df4dc26545 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -181,17 +181,11 @@ void common_hal_bleio_connection_set_connection_interval(bleio_connection_intern // Zero when discovery is in process. BLE_HS_EDONE or a BLE_HS_ error code when done. static volatile int _last_discovery_status; -static uint64_t _discovery_start_time; - -// Give 3 seconds for each discovery step. -#define DISCOVERY_TIMEOUT_MS 3000 - -static void _start_discovery_timeout(void) { - _discovery_start_time = common_hal_time_monotonic_ms(); -} +// Give 20 seconds for each step of discovery: services, characteristics, attributes. +#define DISCOVERY_TIMEOUT_MS 20000 static int _wait_for_discovery_step_done(void) { - const uint64_t timeout_time_ms = _discovery_start_time + DISCOVERY_TIMEOUT_MS; + const uint64_t timeout_time_ms = common_hal_time_monotonic_ms() + DISCOVERY_TIMEOUT_MS; while ((_last_discovery_status == 0) && (common_hal_time_monotonic_ms() < timeout_time_ms)) { RUN_BACKGROUND_TASKS; if (mp_hal_is_interrupted()) { @@ -364,13 +358,9 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Start over with an empty list. self->remote_service_list = mp_obj_new_list(0, NULL); - // Start timeout in case discovery gets stuck. - _start_discovery_timeout(); - if (service_uuids_whitelist == mp_const_none) { // Reset discovery status before starting callbacks _set_discovery_step_status(0); - _start_discovery_timeout(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_svcs(self->conn_handle, _discovered_service_cb, self)); @@ -389,7 +379,6 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Reset discovery status before starting callbacks _set_discovery_step_status(0); - _start_discovery_timeout(); CHECK_NIMBLE_ERROR(ble_gattc_disc_svc_by_uuid(self->conn_handle, &uuid->nimble_ble_uuid.u, _discovered_service_cb, self)); @@ -407,7 +396,6 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Reset discovery status before starting callbacks _set_discovery_step_status(0); - _start_discovery_timeout(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_chrs(self->conn_handle, service->start_handle, @@ -443,7 +431,6 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t // Reset discovery status before starting callbacks _set_discovery_step_status(0); - _start_discovery_timeout(); // The descriptor handle inclusive range is [characteristic->handle + 1, end_handle], // but ble_gattc_disc_all_dscs() requires starting with characteristic->handle. From f73642a4ee19899a5c72272a14145b5cf0a57639 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 12 Jun 2026 15:24:28 -0400 Subject: [PATCH 550/876] rp2: use irq_add_shared_handler() for DMA_IRQ_0 instead of fixed isr_dma_0() audio_dma.c defined the DMA_IRQ_0 handler as the fixed isr_dma_0() linker symbol and dispatched to both audio and rp2pio from it. Per the Pico SDK docs this is impolite: it permanently owns the vector and prevents other code from cooperating on the IRQ at runtime. It also meant rp2pio's DMA completion was silently broken when CIRCUITPY_AUDIOCORE=0, since the dispatch lived inside that guard. Convert DMA_IRQ_0 to per-subsystem shared handlers: audiocore and rp2pio each register their own handler with irq_add_shared_handler(), add it on the first channel they enable and remove it on the last, and acknowledge only their own channels. picodvi's exclusive DMA_IRQ_1 handler is unchanged. Document the DMA IRQ allocation policy (which IRQs are shared vs. exclusive) in common-hal/microcontroller/__init__.c. Adds manual hardware regression tests under tests/circuitpython-manual/rp2pio/ that exercise audio DMA, rp2pio background write, and rp2pio background read sharing DMA_IRQ_0. They use only pre-existing public APIs and pass identically before and after this change. Closes #9992 Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/raspberrypi/audio_dma.c | 85 ++++++++++++------- .../common-hal/microcontroller/__init__.c | 16 ++++ .../common-hal/rp2pio/StateMachine.c | 82 +++++++++++++----- tests/circuitpython-manual/rp2pio/README.md | 44 ++++++++++ .../rp2pio/audio_dma_shared_irq_loopback.py | 85 +++++++++++++++++++ .../rp2pio/audio_dma_shared_irq_write.py | 67 +++++++++++++++ .../rp2pio/pio_background_write.py | 53 ++++++++++++ 7 files changed, 382 insertions(+), 50 deletions(-) create mode 100644 tests/circuitpython-manual/rp2pio/README.md create mode 100644 tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_loopback.py create mode 100644 tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_write.py create mode 100644 tests/circuitpython-manual/rp2pio/pio_background_write.py diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index 03d98ae876a..36b86cbf844 100644 --- a/ports/raspberrypi/audio_dma.c +++ b/ports/raspberrypi/audio_dma.c @@ -9,18 +9,23 @@ #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" #include "shared-bindings/microcontroller/__init__.h" -#include "bindings/rp2pio/StateMachine.h" #include "supervisor/background_callback.h" #include "py/mpstate.h" #include "py/runtime.h" #include "hardware/irq.h" -#include "hardware/regs/intctrl.h" // For isr_ macro. #if CIRCUITPY_AUDIOCORE +// audio_dma and rp2pio cooperate on DMA_IRQ_0 using the SDK's shared interrupt +// handlers. We add our handler when we enable our first channel and remove it +// when our last channel is disabled. See the DMA IRQ allocation notes in +// common-hal/microcontroller/__init__.c. +static void audio_dma_enable_irq(uint channel); +static void audio_dma_disable_irq(uint channel); + void audio_dma_reset(void) { for (size_t channel = 0; channel < NUM_DMA_CHANNELS; channel++) { if (MP_STATE_PORT(playing_audio)[channel] == NULL) { @@ -335,12 +340,10 @@ audio_dma_result audio_dma_setup_playback( 1, // transaction count false); // trigger } else { - // Clear any latent interrupts so that we don't immediately disable channels. - dma_hw->ints0 |= (1 << dma->channel[0]) | (1 << dma->channel[1]); // Enable our DMA channels on DMA_IRQ_0 to the CPU. This will wake us up when // we're WFI. - dma_hw->inte0 |= (1 << dma->channel[0]) | (1 << dma->channel[1]); - irq_set_mask_enabled(1 << DMA_IRQ_0, true); + audio_dma_enable_irq(dma->channel[0]); + audio_dma_enable_irq(dma->channel[1]); } dma->playing_in_progress = true; @@ -353,16 +356,11 @@ void audio_dma_stop(audio_dma_t *dma) { dma->paused = true; // Disable our interrupts. - uint32_t channel_mask = 0; if (dma->channel[0] < NUM_DMA_CHANNELS) { - channel_mask |= 1 << dma->channel[0]; + audio_dma_disable_irq(dma->channel[0]); } if (dma->channel[1] < NUM_DMA_CHANNELS) { - channel_mask |= 1 << dma->channel[1]; - } - dma_hw->inte0 &= ~channel_mask; - if (!dma_hw->inte0) { - irq_set_mask_enabled(1 << DMA_IRQ_0, false); + audio_dma_disable_irq(dma->channel[1]); } // Run any remaining audio tasks because we remove ourselves from @@ -532,34 +530,59 @@ static void dma_callback_fun(void *arg) { } } -void __not_in_flash_func(isr_dma_0)(void) { +// Shared DMA_IRQ_0 handler for audio. It acknowledges and services only audio +// channels, leaving any other channels' interrupts for the other shared +// handlers (e.g. rp2pio) to acknowledge. +static void __not_in_flash_func(audio_dma_irq_handler)(void) { for (size_t i = 0; i < NUM_DMA_CHANNELS; i++) { uint32_t mask = 1 << i; if ((dma_hw->ints0 & mask) == 0) { continue; } + audio_dma_t *dma = MP_STATE_PORT(playing_audio)[i]; + if (dma == NULL) { + // Not one of our channels; leave it for another shared handler. + continue; + } // acknowledge interrupt early. Doing so late means that you could lose an // interrupt if the buffer is very small and the DMA operation // completed by the time callback_add() / dma_complete() returned. This // affected PIO continuous write more than audio. dma_hw->ints0 = mask; - if (MP_STATE_PORT(playing_audio)[i] != NULL) { - audio_dma_t *dma = MP_STATE_PORT(playing_audio)[i]; - // Record all channels whose DMA has completed; they need loading. - dma->channels_to_load_mask |= mask; - // Disable the channel so that we don't play it without filling it. - dma_hw->ch[i].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS; - // This is a noop if the callback is already queued. - background_callback_add(&dma->callback, dma_callback_fun, (void *)dma); - } - if (MP_STATE_PORT(background_pio_read)[i] != NULL) { - rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(background_pio_read)[i]; - rp2pio_statemachine_dma_complete_read(pio, i); - } - if (MP_STATE_PORT(background_pio_write)[i] != NULL) { - rp2pio_statemachine_obj_t *pio = MP_STATE_PORT(background_pio_write)[i]; - rp2pio_statemachine_dma_complete_write(pio, i); - } + // Record all channels whose DMA has completed; they need loading. + dma->channels_to_load_mask |= mask; + // Disable the channel so that we don't play it without filling it. + dma_hw->ch[i].al1_ctrl &= ~DMA_CH0_CTRL_TRIG_EN_BITS; + // This is a noop if the callback is already queued. + background_callback_add(&dma->callback, dma_callback_fun, (void *)dma); + } +} + +// Channels (bitmask) audio currently has enabled on DMA_IRQ_0. Used to decide +// when to add/remove our shared interrupt handler. +static uint32_t audio_dma_irq0_channel_mask = 0; + +static void audio_dma_enable_irq(uint channel) { + // Clear any latent interrupt so that we don't immediately disable the channel. + dma_hw->ints0 = 1u << channel; + if (audio_dma_irq0_channel_mask == 0) { + irq_add_shared_handler(DMA_IRQ_0, audio_dma_irq_handler, + PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); + } + audio_dma_irq0_channel_mask |= 1u << channel; + dma_irqn_set_channel_enabled(0, channel, true); + irq_set_enabled(DMA_IRQ_0, true); +} + +static void audio_dma_disable_irq(uint channel) { + dma_irqn_set_channel_enabled(0, channel, false); + audio_dma_irq0_channel_mask &= ~(1u << channel); + if (audio_dma_irq0_channel_mask == 0) { + irq_remove_handler(DMA_IRQ_0, audio_dma_irq_handler); + } + // Turn off the IRQ line entirely once no one (audio or rp2pio) needs it. + if (dma_hw->inte0 == 0) { + irq_set_enabled(DMA_IRQ_0, false); } } diff --git a/ports/raspberrypi/common-hal/microcontroller/__init__.c b/ports/raspberrypi/common-hal/microcontroller/__init__.c index 49dbc6082b0..3d8bd381f5e 100644 --- a/ports/raspberrypi/common-hal/microcontroller/__init__.c +++ b/ports/raspberrypi/common-hal/microcontroller/__init__.c @@ -25,6 +25,22 @@ #include "hardware/watchdog.h" #include "hardware/irq.h" +// DMA interrupt (DMA_IRQ_n) allocation for this port: +// +// DMA_IRQ_0 Shared. audiocore (audio_dma.c) and rp2pio (StateMachine.c) each +// register a shared handler with irq_add_shared_handler() and +// service only their own DMA channels. Any new code that needs a +// DMA completion interrupt should do the same: add a shared handler +// on DMA_IRQ_0, check dma_hw->ints0, and acknowledge only its own +// channels. Runs at the default IRQ priority and is masked during +// flash writes (see common_hal_mcu_disable_interrupts below). +// DMA_IRQ_1 Exclusive to picodvi (Framebuffer_RP2040.c / Framebuffer_RP2350.c), +// registered with irq_set_exclusive_handler() at the highest +// priority. On RP2350 it is deliberately kept enabled during flash +// writes via BASEPRI (see below) so the display keeps refreshing. +// DMA_IRQ_2 RP2350 only; currently unused / free. +// DMA_IRQ_3 RP2350 only; currently unused / free. + void common_hal_mcu_delay_us(uint32_t delay) { mp_hal_delay_us(delay); } diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index af6e98bbc85..8e1ea26ab0d 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -68,14 +68,69 @@ static void rp2pio_statemachine_set_pull(pio_pinmask_t pull_pin_up, pio_pinmask_ } } +// audio_dma and rp2pio cooperate on DMA_IRQ_0 using the SDK's shared interrupt +// handlers. We add our handler when we enable our first channel and remove it +// when our last channel is disabled. See the DMA IRQ allocation notes in +// common-hal/microcontroller/__init__.c. + +// Shared DMA_IRQ_0 handler for rp2pio background reads and writes. It +// acknowledges and services only its own channels, leaving any other channels' +// interrupts (e.g. audio) for the other shared handlers to acknowledge. +static void __not_in_flash_func(rp2pio_dma_irq_handler)(void) { + for (size_t i = 0; i < NUM_DMA_CHANNELS; i++) { + uint32_t mask = 1 << i; + if ((dma_hw->ints0 & mask) == 0) { + continue; + } + rp2pio_statemachine_obj_t *read = MP_STATE_PORT(background_pio_read)[i]; + rp2pio_statemachine_obj_t *write = MP_STATE_PORT(background_pio_write)[i]; + if (read == NULL && write == NULL) { + // Not one of our channels; leave it for another shared handler. + continue; + } + // Acknowledge the interrupt early; see the comment in audio_dma.c. + dma_hw->ints0 = mask; + if (read != NULL) { + rp2pio_statemachine_dma_complete_read(read, i); + } + if (write != NULL) { + rp2pio_statemachine_dma_complete_write(write, i); + } + } +} + +// Channels (bitmask) rp2pio currently has enabled on DMA_IRQ_0. Used to decide +// when to add/remove our shared interrupt handler. +static uint32_t rp2pio_dma_irq0_channel_mask = 0; + +static void rp2pio_dma_enable_irq(uint channel) { + // Clear any latent interrupt so that we don't immediately re-trigger. + dma_hw->ints0 = 1u << channel; + if (rp2pio_dma_irq0_channel_mask == 0) { + irq_add_shared_handler(DMA_IRQ_0, rp2pio_dma_irq_handler, + PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY); + } + rp2pio_dma_irq0_channel_mask |= 1u << channel; + dma_irqn_set_channel_enabled(0, channel, true); + irq_set_enabled(DMA_IRQ_0, true); +} + +static void rp2pio_dma_disable_irq(uint channel) { + dma_irqn_set_channel_enabled(0, channel, false); + rp2pio_dma_irq0_channel_mask &= ~(1u << channel); + if (rp2pio_dma_irq0_channel_mask == 0) { + irq_remove_handler(DMA_IRQ_0, rp2pio_dma_irq_handler); + } + // Turn off the IRQ line entirely once no one (audio or rp2pio) needs it. + if (dma_hw->inte0 == 0) { + irq_set_enabled(DMA_IRQ_0, false); + } +} + static void rp2pio_statemachine_clear_dma_write(int pio_index, int sm) { if (SM_DMA_ALLOCATED_WRITE(pio_index, sm)) { int channel_write = SM_DMA_GET_CHANNEL_WRITE(pio_index, sm); - uint32_t channel_mask_write = 1u << channel_write; - dma_hw->inte0 &= ~channel_mask_write; - if (!dma_hw->inte0) { - irq_set_mask_enabled(1 << DMA_IRQ_0, false); - } + rp2pio_dma_disable_irq(channel_write); MP_STATE_PORT(background_pio_write)[channel_write] = NULL; dma_channel_abort(channel_write); dma_channel_unclaim(channel_write); @@ -86,11 +141,7 @@ static void rp2pio_statemachine_clear_dma_write(int pio_index, int sm) { static void rp2pio_statemachine_clear_dma_read(int pio_index, int sm) { if (SM_DMA_ALLOCATED_READ(pio_index, sm)) { int channel_read = SM_DMA_GET_CHANNEL_READ(pio_index, sm); - uint32_t channel_mask_read = 1u << channel_read; - dma_hw->inte0 &= ~channel_mask_read; - if (!dma_hw->inte0) { - irq_set_mask_enabled(1 << DMA_IRQ_0, false); - } + rp2pio_dma_disable_irq(channel_read); MP_STATE_PORT(background_pio_read)[channel_read] = NULL; dma_channel_abort(channel_read); dma_channel_unclaim(channel_read); @@ -1274,12 +1325,8 @@ bool common_hal_rp2pio_statemachine_background_write(rp2pio_statemachine_obj_t * common_hal_mcu_disable_interrupts(); - // Acknowledge any previous pending interrupt - dma_hw->ints0 |= 1u << channel_write; MP_STATE_PORT(background_pio_write)[channel_write] = self; - dma_hw->inte0 |= 1u << channel_write; - - irq_set_mask_enabled(1 << DMA_IRQ_0, true); + rp2pio_dma_enable_irq(channel_write); dma_start_channel_mask(1u << channel_write); common_hal_mcu_enable_interrupts(); @@ -1438,11 +1485,8 @@ bool common_hal_rp2pio_statemachine_background_read(rp2pio_statemachine_obj_t *s false); common_hal_mcu_disable_interrupts(); - // Acknowledge any previous pending interrupt - dma_hw->ints0 |= 1u << channel_read; MP_STATE_PORT(background_pio_read)[channel_read] = self; - dma_hw->inte0 |= 1u << channel_read; - irq_set_mask_enabled(1 << DMA_IRQ_0, true); + rp2pio_dma_enable_irq(channel_read); dma_start_channel_mask((1u << channel_read)); common_hal_mcu_enable_interrupts(); diff --git a/tests/circuitpython-manual/rp2pio/README.md b/tests/circuitpython-manual/rp2pio/README.md new file mode 100644 index 00000000000..de67cf203d2 --- /dev/null +++ b/tests/circuitpython-manual/rp2pio/README.md @@ -0,0 +1,44 @@ +# rp2pio + audio DMA shared-IRQ manual tests + +These programs exercise the `DMA_IRQ_0` interrupt handlers on the RP2040 / +RP2350, which are shared between `audiocore`/`audiopwmio` (audio DMA) and +`rp2pio` (PIO background read/write DMA). + +They were written to validate the change in issue #9992 (moving `audio_dma.c` +off the fixed `isr_dma_0()` linker symbol and onto `irq_add_shared_handler()`, +with `rp2pio` registering its own shared handler). **They use only public APIs +that predate that change, so each program should behave identically before and +after it** — that is the point: they are regression tests, not feature tests. + +## What each program covers + +| Program | Audio DMA | PIO write DMA | PIO read DMA | +|---|---|---|---| +| `pio_background_write.py` | | ✓ | | +| `audio_dma_shared_irq_write.py` | ✓ | ✓ | | +| `audio_dma_shared_irq_loopback.py` | ✓ | ✓ | ✓ | + +Each goes through the background-DMA path (`background_write` / +`background_read`), which is interrupt-driven. The blocking `write`/`readinto`/ +`write_readinto` calls poll instead and do **not** use the DMA IRQ, so they are +deliberately not used here. The audio sample is created with +`single_buffer=False` so audio also uses the interrupt-driven (double-buffered) +DMA path rather than the no-interrupt single-buffer chaining path. + +## Wiring (Raspberry Pi Pico / Pico 2) + +- `GP13` — PWM audio output. Connect to an amplifier/speaker, or just leave it; + the test does not require you to hear anything, only that playback keeps + running. +- `GP2` — PIO output pin. +- `GP3` — PIO input pin (loopback test only). For a meaningful loopback, + connect `GP2` to `GP3` with a jumper. Without the jumper the read still + completes (it just reads whatever the floating/pulled pin sees), so the DMA + path is still exercised. + +## Running + +Copy one file at a time to `CIRCUITPY/code.py` and watch the serial console. +A successful run ends with a `PASS:` line. A hang (no further output) or a +`RuntimeError`/crash/safe-mode indicates a regression in the shared DMA IRQ +handling. diff --git a/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_loopback.py b/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_loopback.py new file mode 100644 index 00000000000..ba8ebbb589d --- /dev/null +++ b/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_loopback.py @@ -0,0 +1,85 @@ +"""Audio + rp2pio background write AND read sharing DMA_IRQ_0. + +Exercises all three DMA_IRQ_0 dispatch arms at once: + * audio playback (double-buffered, interrupt-driven), + * a continuous PIO background_write (write-completion interrupts), and + * repeated PIO background_read one-shots (read-completion interrupts). + +The continuous background_write keeps the state machine clocking so the read +side always has data to capture. Each background_read is a one-shot whose +completion is detected by polling `StateMachine.reading`; if that never clears, +the read-completion interrupt is not being serviced (a regression). Audio must +also keep playing throughout. + +Wiring: PWM audio on GP13 (speaker optional), PIO output on GP2, PIO input on +GP3. Jumper GP2 -> GP3 for a true loopback (then the captured data reflects what +was written); without the jumper the read still completes, so the DMA path is +still exercised. +""" + +import array +import math +import time + +import audiocore +import audiopwmio +import board +import rp2pio + +# --- Audio: signed-16 sine wave, double-buffered so it uses the DMA IRQ path. +SAMPLE_RATE = 16000 +SAMPLE_COUNT = 4000 # even count (required for single_buffer=False) +PERIODS = 32 +sine = array.array("h", [0] * SAMPLE_COUNT) +for i in range(SAMPLE_COUNT): + sine[i] = int(math.sin(2 * math.pi * PERIODS * i / SAMPLE_COUNT) * (2**14)) +sample = audiocore.RawSample(sine, sample_rate=SAMPLE_RATE, single_buffer=False) + +audio = audiopwmio.PWMAudioOut(board.GP13) +audio.play(sample, loop=True) +print("audio playing:", audio.playing) + +# --- PIO loopback program (hand assembled): +# .wrap_target +# out pins, 1 ; 0x6001 shift one bit OSR -> output pin (GP2) +# in pins, 1 ; 0x4001 shift one bit input pin (GP3) -> ISR +# .wrap +# auto_pull/auto_push at 32 bits keep both FIFOs (and their DMA) moving. +PROGRAM = array.array("H", [0x6001, 0x4001]) +sm = rp2pio.StateMachine( + PROGRAM, + frequency=2_000_000, + first_out_pin=board.GP2, + first_in_pin=board.GP3, + auto_pull=True, + pull_threshold=32, + out_shift_right=True, + auto_push=True, + push_threshold=32, + in_shift_right=True, +) + +out_buf = array.array("I", [0x0F0F0F0F] * 1024) +in_buf = array.array("I", [0] * 1024) + +# Continuous background write to keep the state machine clocking. +sm.background_write(loop=out_buf) + +ITERATIONS = 100 +for n in range(ITERATIONS): + sm.background_read(once=in_buf) + deadline = time.monotonic() + 2.0 + while sm.reading and time.monotonic() < deadline: + pass + if sm.reading: + raise RuntimeError(f"background_read stuck on iteration {n} (shared DMA IRQ wedged?)") + if not audio.playing: + raise RuntimeError(f"audio stopped unexpectedly on iteration {n}") + if n % 20 == 0: + print("iteration", n, "audio.playing", audio.playing, "first read word", hex(in_buf[0])) + +sm.stop_background_write() +audio.stop() +sm.deinit() +audio.deinit() +print("PASS: audio + rp2pio background write/read shared DMA_IRQ_0 for", ITERATIONS, "iterations") diff --git a/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_write.py b/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_write.py new file mode 100644 index 00000000000..fe00df06815 --- /dev/null +++ b/tests/circuitpython-manual/rp2pio/audio_dma_shared_irq_write.py @@ -0,0 +1,67 @@ +"""Audio playback + rp2pio background_write sharing DMA_IRQ_0. + +This is the scenario from issue #9868: audio output and a PIO peripheral (e.g. a +status NeoPixel) both want DMA completion interrupts at the same time. Audio +uses the interrupt-driven double-buffered path (`single_buffer=False`) and +rp2pio uses background_write, so both subsystems are serviced by DMA_IRQ_0 +concurrently. + +The test passes if the PIO writes keep completing AND audio keeps playing for +the whole run. A hang, crash, or audio stopping early indicates a regression. + +Wiring: PWM audio on GP13 (speaker optional), PIO output on GP2 (no connection +required). +""" + +import array +import math +import time + +import audiocore +import audiopwmio +import board +import rp2pio + +# --- Audio: signed-16 sine wave, double-buffered so it uses the DMA IRQ path. +SAMPLE_RATE = 16000 +SAMPLE_COUNT = 4000 # even count (required for single_buffer=False), several periods +PERIODS = 32 +sine = array.array("h", [0] * SAMPLE_COUNT) +for i in range(SAMPLE_COUNT): + sine[i] = int(math.sin(2 * math.pi * PERIODS * i / SAMPLE_COUNT) * (2**14)) +sample = audiocore.RawSample(sine, sample_rate=SAMPLE_RATE, single_buffer=False) + +audio = audiopwmio.PWMAudioOut(board.GP13) +audio.play(sample, loop=True) +print("audio playing:", audio.playing) + +# --- PIO: drain program that clocks the TX FIFO out on GP2 (see +# pio_background_write.py for the encoding). +PROGRAM = array.array("H", [0x6001]) +sm = rp2pio.StateMachine( + PROGRAM, + frequency=2_000_000, + first_out_pin=board.GP2, + auto_pull=True, + pull_threshold=32, + out_shift_right=True, +) +data = array.array("I", [0x5555AAAA] * 4096) + +ITERATIONS = 100 +for n in range(ITERATIONS): + sm.background_write(once=data) + deadline = time.monotonic() + 2.0 + while sm.writing and time.monotonic() < deadline: + pass + if sm.writing: + raise RuntimeError(f"background_write stuck on iteration {n} (shared DMA IRQ wedged?)") + if not audio.playing: + raise RuntimeError(f"audio stopped unexpectedly on iteration {n}") + if n % 20 == 0: + print("iteration", n, "audio.playing", audio.playing) + +audio.stop() +sm.deinit() +audio.deinit() +print("PASS: audio + rp2pio background_write shared DMA_IRQ_0 for", ITERATIONS, "iterations") diff --git a/tests/circuitpython-manual/rp2pio/pio_background_write.py b/tests/circuitpython-manual/rp2pio/pio_background_write.py new file mode 100644 index 00000000000..796175da7b1 --- /dev/null +++ b/tests/circuitpython-manual/rp2pio/pio_background_write.py @@ -0,0 +1,53 @@ +"""Baseline: rp2pio background_write DMA only (no audio). + +Exercises the PIO *write* arm of the shared DMA_IRQ_0 handler, plus the +add/remove of the shared handler as the only channel comes and goes. + +Repeatedly starts a one-shot background write and waits for it to finish by +polling `StateMachine.writing`. If `writing` never clears, the DMA completion +interrupt is not being serviced (a regression). Ends with a PASS line. + +Wiring: PIO output on GP2 (no connection required). +""" + +import array +import time + +import board +import rp2pio + +# PIO program (hand assembled, no adafruit_pioasm dependency): +# .wrap_target +# out pins, 1 ; shift one bit from OSR to the output pin +# .wrap +# With auto_pull and pull_threshold=32, the OSR is refilled from the TX FIFO +# every 32 bits, so the FIFO (and therefore the DMA) drains continuously. +# Encoding of `out pins, 1`: opcode OUT=0b011, dest PINS=0b000, count 1 -> 0x6001 +PROGRAM = array.array("H", [0x6001]) + +sm = rp2pio.StateMachine( + PROGRAM, + frequency=2_000_000, + first_out_pin=board.GP2, + auto_pull=True, + pull_threshold=32, + out_shift_right=True, +) + +# 16 KB of data per transfer, enough that the DMA genuinely runs and completes +# via interrupt rather than fitting in the FIFO. +data = array.array("I", [0x5555AAAA] * 4096) + +ITERATIONS = 50 +for n in range(ITERATIONS): + sm.background_write(once=data) + deadline = time.monotonic() + 2.0 + while sm.writing and time.monotonic() < deadline: + pass + if sm.writing: + raise RuntimeError(f"background_write stuck on iteration {n} (DMA IRQ not serviced?)") + if n % 10 == 0: + print("iteration", n, "ok") + +sm.deinit() +print("PASS: rp2pio background_write completed", ITERATIONS, "times") From 18425dbd37e630ebec3e356e07247a560d8b909d Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Sat, 13 Jun 2026 10:33:22 +0200 Subject: [PATCH 551/876] fix sdcard creation from automount_sd_card() --- shared-module/sdcardio/__init__.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/shared-module/sdcardio/__init__.c b/shared-module/sdcardio/__init__.c index 4a7a4d500cc..f4f702c31c7 100644 --- a/shared-module/sdcardio/__init__.c +++ b/shared-module/sdcardio/__init__.c @@ -6,8 +6,11 @@ #include "shared-module/sdcardio/__init__.h" +#include "py/obj.h" + #include "extmod/vfs_fat.h" +#include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/busio/SPI.h" #include "shared-bindings/digitalio/DigitalInOut.h" #include "shared-bindings/sdcardio/SDCard.h" @@ -81,7 +84,8 @@ void automount_sd_card(void) { common_hal_busio_spi_never_reset(spi_obj); #endif sdcard.base.type = &sdcardio_SDCard_type; - mp_rom_error_text_t error = sdcardio_sdcard_construct(&sdcard, spi_obj, DEFAULT_SD_CS, 25000000, true); + mp_obj_t cs_obj = MP_OBJ_FROM_PTR(DEFAULT_SD_CS); + mp_rom_error_text_t error = sdcardio_sdcard_construct(&sdcard, spi_obj, cs_obj, 25000000, true); if (error != NULL) { // Failed to communicate with the card. _automounted = false; @@ -91,8 +95,9 @@ void automount_sd_card(void) { #endif return; } - common_hal_digitalio_digitalinout_never_reset(&sdcard.cs); - + if (mp_obj_is_type(cs_obj, &mcu_pin_type)) { + common_hal_digitalio_digitalinout_never_reset(MP_OBJ_TO_PTR(&sdcard.cs)); + } fs_user_mount_t *vfs = &_sdcard_usermount; vfs->base.type = &mp_fat_vfs_type; vfs->fatfs.drv = vfs; From dc11d410d18e893424a823b78c0b433a1b5c9af4 Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Tue, 16 Jun 2026 09:02:48 +0200 Subject: [PATCH 552/876] bugfix: pass object instead of address to MP_OBJ_TO_PTR() --- shared-module/sdcardio/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/sdcardio/__init__.c b/shared-module/sdcardio/__init__.c index f4f702c31c7..751e6f58127 100644 --- a/shared-module/sdcardio/__init__.c +++ b/shared-module/sdcardio/__init__.c @@ -96,7 +96,7 @@ void automount_sd_card(void) { return; } if (mp_obj_is_type(cs_obj, &mcu_pin_type)) { - common_hal_digitalio_digitalinout_never_reset(MP_OBJ_TO_PTR(&sdcard.cs)); + common_hal_digitalio_digitalinout_never_reset(MP_OBJ_TO_PTR(sdcard.cs)); } fs_user_mount_t *vfs = &_sdcard_usermount; vfs->base.type = &mp_fat_vfs_type; From ea254f5f1c952eea2acc43b8b9fcf5b187e0b9e7 Mon Sep 17 00:00:00 2001 From: Paula Scharf Date: Wed, 17 Jun 2026 14:21:15 +0200 Subject: [PATCH 553/876] update senseBox MCU Eye name and pins --- .../{sensebox_eye_esp32s3 => sensebox_mcu_eye_esp32s3}/board.c | 0 .../mpconfigboard.h | 2 +- .../mpconfigboard.mk | 2 +- .../{sensebox_eye_esp32s3 => sensebox_mcu_eye_esp32s3}/pins.c | 2 +- .../sdkconfig | 0 5 files changed, 3 insertions(+), 3 deletions(-) rename ports/espressif/boards/{sensebox_eye_esp32s3 => sensebox_mcu_eye_esp32s3}/board.c (100%) rename ports/espressif/boards/{sensebox_eye_esp32s3 => sensebox_mcu_eye_esp32s3}/mpconfigboard.h (88%) rename ports/espressif/boards/{sensebox_eye_esp32s3 => sensebox_mcu_eye_esp32s3}/mpconfigboard.mk (93%) rename ports/espressif/boards/{sensebox_eye_esp32s3 => sensebox_mcu_eye_esp32s3}/pins.c (98%) rename ports/espressif/boards/{sensebox_eye_esp32s3 => sensebox_mcu_eye_esp32s3}/sdkconfig (100%) diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/board.c b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/board.c similarity index 100% rename from ports/espressif/boards/sensebox_eye_esp32s3/board.c rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/board.c diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.h b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.h similarity index 88% rename from ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.h rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.h index 3908c492f1b..300154fe344 100644 --- a/ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.h +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.h @@ -6,7 +6,7 @@ // Micropython setup -#define MICROPY_HW_BOARD_NAME "senseBox-eye ESP32S3" +#define MICROPY_HW_BOARD_NAME "senseBox MCU Eye ESP32S3" #define MICROPY_HW_MCU_NAME "ESP32S3" #define MICROPY_HW_NEOPIXEL (&pin_GPIO45) diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.mk b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk similarity index 93% rename from ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.mk rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk index 55e822c5dea..be3c65746c8 100644 --- a/ports/espressif/boards/sensebox_eye_esp32s3/mpconfigboard.mk +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/mpconfigboard.mk @@ -7,7 +7,7 @@ USB_MANUFACTURER = "senseBox" IDF_TARGET = esp32s3 CIRCUITPY_ESP_FLASH_MODE = qio -CIRCUITPY_ESP_FLASH_SIZE = 8MB +CIRCUITPY_ESP_FLASH_SIZE = 16MB CIRCUITPY_ESP_FLASH_FREQ = 80m CIRCUITPY_ESP_PSRAM_MODE = opi diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/pins.c b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c similarity index 98% rename from ports/espressif/boards/sensebox_eye_esp32s3/pins.c rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c index c218fafa918..71b984f7ff5 100644 --- a/ports/espressif/boards/sensebox_eye_esp32s3/pins.c +++ b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/pins.c @@ -33,7 +33,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, - {MP_ROM_QSTR(MP_QSTR_BUTTON_SW), MP_ROM_PTR(&pin_GPIO47) }, + {MP_ROM_QSTR(MP_QSTR_BUTTON_SW), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO1) }, diff --git a/ports/espressif/boards/sensebox_eye_esp32s3/sdkconfig b/ports/espressif/boards/sensebox_mcu_eye_esp32s3/sdkconfig similarity index 100% rename from ports/espressif/boards/sensebox_eye_esp32s3/sdkconfig rename to ports/espressif/boards/sensebox_mcu_eye_esp32s3/sdkconfig From a84cec9c1589f4eefb7963d4336b4502fad17965 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 17 Jun 2026 13:25:59 -0400 Subject: [PATCH 554/876] Turn on PDMIn on ESP32. Update limitations doc for PDMIn and TouchAlarm. Improve option handling in espressif/mpconfigport.mk. --- ports/espressif/mpconfigport.mk | 41 ++++++++++++++++++------ shared-bindings/alarm/touch/TouchAlarm.c | 1 + shared-bindings/audiobusio/PDMIn.c | 2 +- 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 2f16a90d8a2..33a989ae970 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -64,10 +64,10 @@ CIRCUITPY_LIBC_STRING0 = 0 # These modules are implemented in ports//common-hal: CIRCUITPY__EVE ?= 1 CIRCUITPY_ALARM ?= 1 -CIRCUITPY_ALARM_TOUCH ?= 0 +CIRCUITPY_ALARM_TOUCH ?= 1 CIRCUITPY_ANALOGBUFIO ?= 1 CIRCUITPY_AUDIOBUSIO ?= 1 -CIRCUITPY_AUDIOBUSIO_PDMIN ?= 0 +CIRCUITPY_AUDIOBUSIO_PDMIN ?= 1 CIRCUITPY_AUDIOI2SIN ?= 1 CIRCUITPY_AUDIOIO ?= 1 CIRCUITPY_BLEIO_HCI = 0 @@ -80,7 +80,7 @@ CIRCUITPY_ESPULP ?= 1 CIRCUITPY_FRAMEBUFFERIO ?= 1 CIRCUITPY_FREQUENCYIO ?= 1 CIRCUITPY_HASHLIB ?= 1 -CIRCUITPY_I2CTARGET ?= 0 +CIRCUITPY_I2CTARGET = 0 CIRCUITPY_MAX3421E ?= 1 CIRCUITPY_MEMORYMAP ?= 1 CIRCUITPY_RCLCPY ?= 0 @@ -101,7 +101,6 @@ CIRCUITPY_SOCKETPOOL_IPV6 ?= 1 #### esp32 ############################################################ ifeq ($(IDF_TARGET),esp32) # Modules -CIRCUITPY_ALARM_TOUCH = 1 CIRCUITPY_RGBMATRIX = 0 # Has no USB @@ -117,6 +116,9 @@ CIRCUITPY_ESPCAMERA = 0 CIRCUITPY_ESPULP = 0 CIRCUITPY_MEMORYMAP = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 + # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 @@ -162,9 +164,15 @@ CIRCUITPY_MEMORYMAP = 0 # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 + # No DAC CIRCUITPY_AUDIOIO = 0 +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + # No PCNT peripheral CIRCUITPY_FREQUENCYIO = 0 CIRCUITPY_COUNTIO = 0 @@ -187,9 +195,15 @@ CIRCUITPY_ESPULP = 0 CIRCUITPY_MEMORYMAP = 0 CIRCUITPY_RGBMATRIX = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 + # No DAC CIRCUITPY_AUDIOIO = 0 +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + # No space for this CIRCUITPY_AUDIOBUSIO = 0 @@ -213,6 +227,9 @@ CIRCUITPY_ESPULP = 0 CIRCUITPY_MEMORYMAP = 0 CIRCUITPY_RGBMATRIX = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 + # No DAC CIRCUITPY_AUDIOIO = 0 @@ -252,9 +269,15 @@ CIRCUITPY_ESPULP = 0 CIRCUITPY_MEMORYMAP = 0 CIRCUITPY_RGBMATRIX = 0 +# No capacitive touch peripheral +CIRCUITPY_ALARM_TOUCH = 0 + # No DAC CIRCUITPY_AUDIOIO = 0 +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 @@ -283,7 +306,7 @@ CIRCUITPY_BLEIO_NATIVE = 0 CIRCUITPY_WIFI = 0 CIRCUITPY_SSL = 0 -CIRCUITPY_TOUCHIO = 1 +CIRCUITPY_TOUCHIO ?= 1 CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # Second stage bootloader doesn't work when the factory partition is empty due to @@ -316,9 +339,11 @@ CIRCUITPY_MIPIDSI = 1 #### esp32s2 ########################################################## else ifeq ($(IDF_TARGET),esp32s2) # Modules -CIRCUITPY_ALARM_TOUCH = $(CIRCUITPY_ALARM) CIRCUITPY_AUDIOIO ?= 1 +# No I2S peripheral PDM-to-PCM hardware support +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 + # No BLE in hw CIRCUITPY_BLEIO_NATIVE = 0 @@ -331,8 +356,6 @@ CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0 else ifeq ($(IDF_TARGET),esp32s3) # Modules -CIRCUITPY_ALARM_TOUCH = $(CIRCUITPY_ALARM) -CIRCUITPY_AUDIOBUSIO_PDMIN = 1 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 0 # No DAC @@ -342,7 +365,7 @@ endif #### end chip-specific choices ######################################## # By default, enable dualbank, and it'll be disabled for small flash sizes -CIRCUITPY_DUALBANK = 1 +CIRCUITPY_DUALBANK ?= 1 # No room for large modules on 2MB boards # 2MB boards have a single firmware partition, and can't do dualbank. diff --git a/shared-bindings/alarm/touch/TouchAlarm.c b/shared-bindings/alarm/touch/TouchAlarm.c index 42b149c9eee..eac3f37b8f4 100644 --- a/shared-bindings/alarm/touch/TouchAlarm.c +++ b/shared-bindings/alarm/touch/TouchAlarm.c @@ -21,6 +21,7 @@ //| may be limited due to hardware restrictions, particularly for deep-sleep alarms. //| //| **Limitations:** Not available on SAMD, Nordic, or RP2040. +//| On Espressif, only available on ESP32, ESP32-S2, ESP32-S3, and ESP32-P4. //| """ //| ... //| diff --git a/shared-bindings/audiobusio/PDMIn.c b/shared-bindings/audiobusio/PDMIn.c index 092897a15cf..aba8a019f35 100644 --- a/shared-bindings/audiobusio/PDMIn.c +++ b/shared-bindings/audiobusio/PDMIn.c @@ -48,7 +48,7 @@ //| //| **Limitations:** On SAMD and RP2040, supports only 8 or 16 bit mono input, with 64x oversampling. //| On nRF52840, supports only 16 bit mono input at 16 kHz; oversampling is fixed at 64x. Not provided -//| on nRF52833 for space reasons. Not available on Espressif. +//| on nRF52833 for space reasons. On Espressif, only available on ESP32, ESP32-S3, and ESP32-P4. //| //| For example, to record 8-bit unsigned samples to a buffer:: //| From d78b6d8ae7a678f606266b5c635d85a54c2afe3f Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 17 Jun 2026 13:49:42 -0500 Subject: [PATCH 555/876] Initial build of resampler --- py/circuitpy_defns.mk | 1 + shared-bindings/audiospeed/Resampler.c | 156 ++++++++++++++++++ shared-bindings/audiospeed/Resampler.h | 22 +++ shared-bindings/audiospeed/SpeedChanger.c | 23 +-- shared-bindings/audiospeed/SpeedChanger.h | 7 +- shared-bindings/audiospeed/__init__.c | 2 + shared-module/audiocore/__init__.c | 9 +- shared-module/audiospeed/Resampler.c | 57 +++++++ shared-module/audiospeed/Resampler.h | 22 +++ shared-module/audiospeed/SpeedChanger.c | 154 ++---------------- shared-module/audiospeed/SpeedChanger.h | 20 +-- shared-module/audiospeed/__init__.c | 188 ++++++++++++++++++++++ shared-module/audiospeed/__init__.h | 66 ++++++++ 13 files changed, 543 insertions(+), 184 deletions(-) create mode 100644 shared-bindings/audiospeed/Resampler.c create mode 100644 shared-bindings/audiospeed/Resampler.h create mode 100644 shared-module/audiospeed/Resampler.c create mode 100644 shared-module/audiospeed/Resampler.h diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 67be45325d5..a505d5c86d9 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -701,6 +701,7 @@ SRC_SHARED_MODULE_ALL = \ audiocore/RawSample.c \ audiocore/WaveFile.c \ audiocore/__init__.c \ + audiospeed/Resampler.c \ audiospeed/SpeedChanger.c \ audiospeed/__init__.c \ audiodelays/Echo.c \ diff --git a/shared-bindings/audiospeed/Resampler.c b/shared-bindings/audiospeed/Resampler.c new file mode 100644 index 00000000000..db559cd1212 --- /dev/null +++ b/shared-bindings/audiospeed/Resampler.c @@ -0,0 +1,156 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/audiospeed/Resampler.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/util.h" +#include "shared-module/audiospeed/Resampler.h" + +//| class Resampler: +//| """Wraps an audio sample to match it to the destination sample rate.""" +//| +//| def __init__(self) -> None: +//| """Create a Resampler that wraps ``source``. +//| +//| :param audiosample source: The audio source to resample. +//| +//| Playing a wave file through a mixer with half the sample rate:: +//| +//| import board +//| import audiocore +//| import audiomixer +//| import audiospeed +//| import audioio +//| +//| wav = audiocore.WaveFile("sample.wav") +//| resampler = audiospeed.Resampler(wav) +//| mixer = audiomixer.Mixer( +//| channel_count=wav.channel_count, +//| bits_per_sample=wav.bits_per_sample, +//| sample_rate=wav.sample_rate // 2, +//| ) +//| audio = audioio.AudioOut(board.A0) +//| audio.play(mixer) +//| mixer.play(resampler) +//| """ +//| ... +//| +static mp_obj_t audiospeed_resampler_make_new(const mp_obj_type_t *type, + size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + audiospeed_resampler_obj_t *self = mp_obj_malloc(audiospeed_resampler_obj_t, &audiospeed_resampler_type); + common_hal_audiospeed_resampler_construct(self); + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the Resampler and releases all memory resources for reuse.""" +//| ... +//| +static mp_obj_t audiospeed_resampler_deinit(mp_obj_t self_in) { + audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiospeed_resampler_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_deinit_obj, audiospeed_resampler_deinit); + +//| playing: bool +//| """True when the resampler is playing a sample. (read-only)""" +//| +static mp_obj_t audiospeed_resampler_obj_get_playing(mp_obj_t self_in) { + audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(&self->base.base); + return mp_obj_new_bool(common_hal_audiospeed_resampler_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_get_playing_obj, audiospeed_resampler_obj_get_playing); + +MP_PROPERTY_GETTER(audiospeed_resampler_playing_obj, + (mp_obj_t)&audiospeed_resampler_get_playing_obj); + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Resampler: +//| """Plays the sample. Use an `audiomixer.Mixer` object to enable looping. +//| Does not block. Use `playing` to block. +//| +//| :return: The resampler object itself. Can be used for chaining, ie: +//| ``mixer.play(resampler.play(sample))``. +//| :rtype: Resampler""" +//| ... +//| +static mp_obj_t audiospeed_resampler_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED, {} }, + }; + audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + audiosample_check_for_deinit(&self->base.base); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audiospeed_resampler_play(self, sample); + + return MP_OBJ_FROM_PTR(self); +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiospeed_resampler_play_obj, 1, audiospeed_resampler_obj_play); + +//| def stop(self) -> None: +//| """Stops playback of the sample.""" +//| ... +//| +//| +static mp_obj_t audiospeed_resampler_obj_stop(mp_obj_t self_in) { + audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_audiospeed_resampler_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_stop_obj, audiospeed_resampler_obj_stop); + +//| rate: float +//| """Playback speed multiplier.""" +//| +static mp_obj_t audiospeed_resampler_obj_get_rate(mp_obj_t self_in) { + audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(self_in); + audiosample_check_for_deinit(&self->base.base); + return common_hal_audiospeed_resampler_get_rate(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_get_rate_obj, audiospeed_resampler_obj_get_rate); + +MP_PROPERTY_GETTER(audiospeed_resampler_rate_obj, + (mp_obj_t)&audiospeed_resampler_get_rate_obj); + +static const mp_rom_map_elem_t audiospeed_resampler_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiospeed_resampler_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiospeed_resampler_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiospeed_resampler_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiospeed_resampler_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiospeed_resampler_rate_obj) }, +}; +static MP_DEFINE_CONST_DICT(audiospeed_resampler_locals_dict, audiospeed_resampler_locals_dict_table); + +static const audiosample_p_t audiospeed_resampler_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiospeed_resampler_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiospeed_resampler_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiospeed_resampler_type, + MP_QSTR_Resampler, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiospeed_resampler_make_new, + locals_dict, &audiospeed_resampler_locals_dict, + protocol, &audiospeed_resampler_proto + ); diff --git a/shared-bindings/audiospeed/Resampler.h b/shared-bindings/audiospeed/Resampler.h new file mode 100644 index 00000000000..60425f4f8d3 --- /dev/null +++ b/shared-bindings/audiospeed/Resampler.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiospeed/Resampler.h" + +extern const mp_obj_type_t audiospeed_resampler_type; + +void common_hal_audiospeed_resampler_construct(audiospeed_resampler_obj_t *self); +void common_hal_audiospeed_resampler_deinit(audiospeed_resampler_obj_t *self); + +bool common_hal_audiospeed_resampler_get_playing(audiospeed_resampler_obj_t *self); +void common_hal_audiospeed_resampler_play(audiospeed_resampler_obj_t *self, mp_obj_t sample); +void common_hal_audiospeed_resampler_stop(audiospeed_resampler_obj_t *self); + +mp_obj_t common_hal_audiospeed_resampler_get_rate(audiospeed_resampler_obj_t *self); + +void audiospeed_resampler_set_sample_rate(audiospeed_resampler_obj_t *self, uint32_t sample_rate); diff --git a/shared-bindings/audiospeed/SpeedChanger.c b/shared-bindings/audiospeed/SpeedChanger.c index 34efa1516b0..bcac6b7ff20 100644 --- a/shared-bindings/audiospeed/SpeedChanger.c +++ b/shared-bindings/audiospeed/SpeedChanger.c @@ -12,19 +12,9 @@ #include "shared-bindings/audiospeed/SpeedChanger.h" #include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/util.h" +#include "shared-module/audiospeed/__init__.h" #include "shared-module/audiospeed/SpeedChanger.h" -// Convert a Python float to 16.16 fixed-point rate -static uint32_t rate_to_fp(mp_obj_t rate_obj) { - mp_float_t rate = mp_arg_validate_obj_float_range(rate_obj, 0.001, 1000.0, MP_QSTR_rate); - return (uint32_t)(rate * (1 << 16)); -} - -// Convert 16.16 fixed-point rate to Python float -static mp_obj_t fp_to_rate(uint32_t rate_fp) { - return mp_obj_new_float((mp_float_t)rate_fp / (1 << 16)); -} - //| class SpeedChanger: //| """Wraps an audio sample to play it back at a different speed. //| @@ -70,13 +60,8 @@ static mp_obj_t audiospeed_speedchanger_make_new(const mp_obj_type_t *type, mp_obj_t source = args[ARG_source].u_obj; audiosample_check(source); - uint32_t rate_fp = 1 << 16; // default 1.0 - if (args[ARG_rate].u_obj != mp_const_none) { - rate_fp = rate_to_fp(args[ARG_rate].u_obj); - } - audiospeed_speedchanger_obj_t *self = mp_obj_malloc(audiospeed_speedchanger_obj_t, &audiospeed_speedchanger_type); - common_hal_audiospeed_speedchanger_construct(self, source, rate_fp); + common_hal_audiospeed_speedchanger_construct(self, source, args[ARG_rate].u_obj); return MP_OBJ_FROM_PTR(self); } @@ -97,14 +82,14 @@ static MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_speedchanger_deinit_obj, audiospeed_ static mp_obj_t audiospeed_speedchanger_obj_get_rate(mp_obj_t self_in) { audiospeed_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); audiosample_check_for_deinit(&self->base); - return fp_to_rate(common_hal_audiospeed_speedchanger_get_rate(self)); + return common_hal_audiospeed_speedchanger_get_rate(self); } MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_speedchanger_get_rate_obj, audiospeed_speedchanger_obj_get_rate); static mp_obj_t audiospeed_speedchanger_obj_set_rate(mp_obj_t self_in, mp_obj_t rate_obj) { audiospeed_speedchanger_obj_t *self = MP_OBJ_TO_PTR(self_in); audiosample_check_for_deinit(&self->base); - common_hal_audiospeed_speedchanger_set_rate(self, rate_to_fp(rate_obj)); + common_hal_audiospeed_speedchanger_set_rate(self, rate_obj); return mp_const_none; } MP_DEFINE_CONST_FUN_OBJ_2(audiospeed_speedchanger_set_rate_obj, audiospeed_speedchanger_obj_set_rate); diff --git a/shared-bindings/audiospeed/SpeedChanger.h b/shared-bindings/audiospeed/SpeedChanger.h index 64a126a7a61..bc0b166b612 100644 --- a/shared-bindings/audiospeed/SpeedChanger.h +++ b/shared-bindings/audiospeed/SpeedChanger.h @@ -11,7 +11,8 @@ extern const mp_obj_type_t audiospeed_speedchanger_type; void common_hal_audiospeed_speedchanger_construct(audiospeed_speedchanger_obj_t *self, - mp_obj_t source, uint32_t rate_fp); + mp_obj_t source, mp_obj_t rate_obj); void common_hal_audiospeed_speedchanger_deinit(audiospeed_speedchanger_obj_t *self); -void common_hal_audiospeed_speedchanger_set_rate(audiospeed_speedchanger_obj_t *self, uint32_t rate_fp); -uint32_t common_hal_audiospeed_speedchanger_get_rate(audiospeed_speedchanger_obj_t *self); + +void common_hal_audiospeed_speedchanger_set_rate(audiospeed_speedchanger_obj_t *self, mp_obj_t rate_obj); +mp_obj_t common_hal_audiospeed_speedchanger_get_rate(audiospeed_speedchanger_obj_t *self); diff --git a/shared-bindings/audiospeed/__init__.c b/shared-bindings/audiospeed/__init__.c index b12e6db7e6b..3eca41e6467 100644 --- a/shared-bindings/audiospeed/__init__.c +++ b/shared-bindings/audiospeed/__init__.c @@ -9,12 +9,14 @@ #include "py/obj.h" #include "py/runtime.h" +#include "shared-bindings/audiospeed/Resampler.h" #include "shared-bindings/audiospeed/SpeedChanger.h" //| """Audio processing tools""" static const mp_rom_map_elem_t audiospeed_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiospeed) }, + { MP_ROM_QSTR(MP_QSTR_Resampler), MP_ROM_PTR(&audiospeed_resampler_type) }, { MP_ROM_QSTR(MP_QSTR_SpeedChanger), MP_ROM_PTR(&audiospeed_speedchanger_type) }, }; diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 2ee683d75e1..0767f93b811 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -13,6 +13,8 @@ #include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/WaveFile.h" +#include "shared-bindings/audiospeed/Resampler.h" + #include "shared-bindings/audiomixer/Mixer.h" #include "shared-module/audiomixer/Mixer.h" @@ -198,7 +200,7 @@ void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool allow_mono_to_stereo) { const audiosample_base_t *other = audiosample_check(other_in); - if (other->sample_rate != self->sample_rate) { + if (other->sample_rate != self->sample_rate && !mp_obj_is_type(other_in, &audiospeed_resampler_type)) { mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); } if ((!allow_mono_to_stereo || (allow_mono_to_stereo && self->channel_count != 2)) && other->channel_count != self->channel_count) { @@ -210,4 +212,9 @@ void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool al if (other->samples_signed != self->samples_signed) { mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); } + + if (mp_obj_is_type(other_in, &audiospeed_resampler_type)) { + audiospeed_resampler_obj_t *other_resampler = MP_OBJ_TO_PTR(other_in); + audiospeed_resampler_set_sample_rate(other_resampler, self->sample_rate); + } } diff --git a/shared-module/audiospeed/Resampler.c b/shared-module/audiospeed/Resampler.c new file mode 100644 index 00000000000..47b721834d1 --- /dev/null +++ b/shared-module/audiospeed/Resampler.c @@ -0,0 +1,57 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiospeed/Resampler.h" + +static void calculate_rate(audiospeed_base_t *self, uint32_t sample_rate) { + if (self->source != NULL && sample_rate) { + self->speed.rate_fp = (uint32_t)((mp_float_t)self->base.sample_rate / sample_rate * (1 << SPEED_SHIFT)); + } else { + audiospeed_set_rate(&self->speed, mp_const_none); + } +} + +void common_hal_audiospeed_resampler_construct(audiospeed_resampler_obj_t *self) { + audiospeed_construct(&self->base, mp_const_none); // default rate 1.0 + self->sample_rate = 0; +} + +void common_hal_audiospeed_resampler_deinit(audiospeed_resampler_obj_t *self) { + audiospeed_deinit(&self->base); +} + +bool common_hal_audiospeed_resampler_get_playing(audiospeed_resampler_obj_t *self) { + return self->base.source != NULL; +} + +void common_hal_audiospeed_resampler_play(audiospeed_resampler_obj_t *self, mp_obj_t sample) { + audiospeed_assign_source(&self->base, sample); + calculate_rate(&self->base, self->sample_rate); +} + +void common_hal_audiospeed_resampler_stop(audiospeed_resampler_obj_t *self) { + self->base.source = NULL; +} + +mp_obj_t common_hal_audiospeed_resampler_get_rate(audiospeed_resampler_obj_t *self) { + return audiospeed_get_rate(&self->base.speed); +} + +void audiospeed_resampler_set_sample_rate(audiospeed_resampler_obj_t *self, uint32_t sample_rate) { + self->sample_rate = sample_rate; + calculate_rate(&self->base, self->sample_rate); +} + +void audiospeed_resampler_reset_buffer(audiospeed_resampler_obj_t *self, + bool single_channel_output, uint8_t channel) { + audiospeed_reset_buffer(&self->base, single_channel_output, channel); +} + +audioio_get_buffer_result_t audiospeed_resampler_get_buffer(audiospeed_resampler_obj_t *self, + bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + return audiospeed_get_buffer(&self->base, single_channel_output, channel, buffer, buffer_length); +} diff --git a/shared-module/audiospeed/Resampler.h b/shared-module/audiospeed/Resampler.h new file mode 100644 index 00000000000..a105c5c2ab9 --- /dev/null +++ b/shared-module/audiospeed/Resampler.h @@ -0,0 +1,22 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" +#include "shared-module/audiocore/__init__.h" +#include "shared-module/audiospeed/__init__.h" + +typedef struct { + audiospeed_base_t base; + uint32_t sample_rate; +} audiospeed_resampler_obj_t; + +void audiospeed_resampler_reset_buffer(audiospeed_resampler_obj_t *self, + bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t audiospeed_resampler_get_buffer(audiospeed_resampler_obj_t *self, + bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length); diff --git a/shared-module/audiospeed/SpeedChanger.c b/shared-module/audiospeed/SpeedChanger.c index 6f417e9d7b1..813132e4f14 100644 --- a/shared-module/audiospeed/SpeedChanger.c +++ b/shared-module/audiospeed/SpeedChanger.c @@ -10,166 +10,34 @@ #include "py/runtime.h" #include "py/gc.h" -#include "shared-module/audiocore/WaveFile.h" +#include "shared-module/audiocore/__init__.h" #include "shared-bindings/audiocore/__init__.h" -#define OUTPUT_BUFFER_FRAMES 128 - void common_hal_audiospeed_speedchanger_construct(audiospeed_speedchanger_obj_t *self, - mp_obj_t source, uint32_t rate_fp) { - audiosample_base_t *src_base = audiosample_check(source); - - self->source = source; - self->rate_fp = rate_fp; - self->phase = 0; - self->src_buffer = NULL; - self->src_buffer_length = 0; - self->src_sample_count = 0; - self->source_done = false; - self->source_exhausted = false; - - // Copy format from source - self->base.sample_rate = src_base->sample_rate; - self->base.channel_count = src_base->channel_count; - self->base.bits_per_sample = src_base->bits_per_sample; - self->base.samples_signed = src_base->samples_signed; - self->base.single_buffer = false; - - uint8_t bytes_per_frame = (src_base->bits_per_sample / 8) * src_base->channel_count; - self->output_buffer_length = OUTPUT_BUFFER_FRAMES * bytes_per_frame; - self->base.max_buffer_length = self->output_buffer_length; - - self->output_buffer = m_malloc_without_collect(self->output_buffer_length); - if (self->output_buffer == NULL) { - m_malloc_fail(self->output_buffer_length); - } + mp_obj_t source, mp_obj_t rate_obj) { + audiospeed_construct(self, rate_obj); + audiospeed_assign_source(self, source); } void common_hal_audiospeed_speedchanger_deinit(audiospeed_speedchanger_obj_t *self) { - self->output_buffer = NULL; - self->source = MP_OBJ_NULL; - audiosample_mark_deinit(&self->base); -} - -void common_hal_audiospeed_speedchanger_set_rate(audiospeed_speedchanger_obj_t *self, uint32_t rate_fp) { - self->rate_fp = rate_fp; + audiospeed_deinit(self); } -uint32_t common_hal_audiospeed_speedchanger_get_rate(audiospeed_speedchanger_obj_t *self) { - return self->rate_fp; +void common_hal_audiospeed_speedchanger_set_rate(audiospeed_speedchanger_obj_t *self, mp_obj_t rate_obj) { + audiospeed_set_rate(&self->speed, rate_obj); } -// Fetch the next buffer from the source. Returns false if no data available. -static bool fetch_source_buffer(audiospeed_speedchanger_obj_t *self) { - if (self->source_exhausted) { - return false; - } - uint8_t *buf = NULL; - uint32_t len = 0; - audioio_get_buffer_result_t result = audiosample_get_buffer(self->source, false, 0, &buf, &len); - if (result == GET_BUFFER_ERROR) { - self->source_exhausted = true; - return false; - } - if (len == 0) { - self->source_exhausted = true; - return false; - } - self->src_buffer = buf; - self->src_buffer_length = len; - uint8_t bytes_per_frame = (self->base.bits_per_sample / 8) * self->base.channel_count; - self->src_sample_count = len / bytes_per_frame; - self->source_done = (result == GET_BUFFER_DONE); - // Reset phase to index within this new buffer - self->phase = 0; - return true; +mp_obj_t common_hal_audiospeed_speedchanger_get_rate(audiospeed_speedchanger_obj_t *self) { + return audiospeed_get_rate(&self->speed); } void audiospeed_speedchanger_reset_buffer(audiospeed_speedchanger_obj_t *self, bool single_channel_output, uint8_t channel) { - if (single_channel_output && channel == 1) { - return; - } - audiosample_reset_buffer(self->source, false, 0); - self->phase = 0; - self->src_buffer = NULL; - self->src_buffer_length = 0; - self->src_sample_count = 0; - self->source_done = false; - self->source_exhausted = false; + audiospeed_reset_buffer(self, single_channel_output, channel); } audioio_get_buffer_result_t audiospeed_speedchanger_get_buffer(audiospeed_speedchanger_obj_t *self, bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { - - // Ensure we have a source buffer - if (self->src_buffer == NULL) { - if (!fetch_source_buffer(self)) { - *buffer = NULL; - *buffer_length = 0; - return GET_BUFFER_DONE; - } - } - - uint8_t bytes_per_sample = self->base.bits_per_sample / 8; - uint8_t channels = self->base.channel_count; - uint8_t bytes_per_frame = bytes_per_sample * channels; - uint32_t out_frames = 0; - uint32_t max_out_frames = self->output_buffer_length / bytes_per_frame; - - if (bytes_per_sample == 1) { - // 8-bit samples - uint8_t *out = self->output_buffer; - while (out_frames < max_out_frames) { - uint32_t src_index = self->phase >> SPEED_SHIFT; - // Advance to next source buffer if needed - if (src_index >= self->src_sample_count) { - if (self->source_done) { - self->source_exhausted = true; - break; - } - if (!fetch_source_buffer(self)) { - break; - } - src_index = 0; // phase was reset by fetch - } - uint8_t *src = self->src_buffer + src_index * bytes_per_frame; - for (uint8_t c = 0; c < channels; c++) { - *out++ = src[c]; - } - out_frames++; - self->phase += self->rate_fp; - } - } else { - // 16-bit samples - int16_t *out = (int16_t *)self->output_buffer; - while (out_frames < max_out_frames) { - uint32_t src_index = self->phase >> SPEED_SHIFT; - if (src_index >= self->src_sample_count) { - if (self->source_done) { - self->source_exhausted = true; - break; - } - if (!fetch_source_buffer(self)) { - break; - } - src_index = 0; - } - int16_t *src = (int16_t *)(self->src_buffer + src_index * bytes_per_frame); - for (uint8_t c = 0; c < channels; c++) { - *out++ = src[c]; - } - out_frames++; - self->phase += self->rate_fp; - } - } - - *buffer = self->output_buffer; - *buffer_length = out_frames * bytes_per_frame; - - if (out_frames == 0) { - return GET_BUFFER_DONE; - } - return self->source_exhausted ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA; + return audiospeed_get_buffer(self, single_channel_output, channel, buffer, buffer_length); } diff --git a/shared-module/audiospeed/SpeedChanger.h b/shared-module/audiospeed/SpeedChanger.h index e920c72caf4..34969e42bd6 100644 --- a/shared-module/audiospeed/SpeedChanger.h +++ b/shared-module/audiospeed/SpeedChanger.h @@ -8,25 +8,9 @@ #include "py/obj.h" #include "shared-module/audiocore/__init__.h" +#include "shared-module/audiospeed/__init__.h" -// Fixed-point 16.16 format -#define SPEED_SHIFT 16 - -typedef struct { - audiosample_base_t base; - mp_obj_t source; - uint8_t *output_buffer; - uint32_t output_buffer_length; // in bytes, allocated size - // Source buffer cache - uint8_t *src_buffer; - uint32_t src_buffer_length; // in bytes - uint32_t src_sample_count; // in frames - // Phase accumulator and rate in 16.16 fixed-point (units: source frames) - uint32_t phase; - uint32_t rate_fp; // 16.16 fixed-point rate - bool source_done; // source returned DONE on last get_buffer - bool source_exhausted; // source DONE and we consumed all of it -} audiospeed_speedchanger_obj_t; +typedef audiospeed_base_t audiospeed_speedchanger_obj_t; void audiospeed_speedchanger_reset_buffer(audiospeed_speedchanger_obj_t *self, bool single_channel_output, uint8_t channel); diff --git a/shared-module/audiospeed/__init__.c b/shared-module/audiospeed/__init__.c index 7c9b271a4b5..5f1254b8dd7 100644 --- a/shared-module/audiospeed/__init__.c +++ b/shared-module/audiospeed/__init__.c @@ -3,3 +3,191 @@ // SPDX-FileCopyrightText: Copyright (c) 2026 Tod Kurt // // SPDX-License-Identifier: MIT + +#include + +#include "py/gc.h" +#include "py/objproperty.h" +#include "py/runtime.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/audiospeed/__init__.h" +#include "shared-bindings/audiocore/__init__.h" + +// Convert a Python float to 16.16 fixed-point rate +uint32_t audiospeed_rate_to_fp(mp_obj_t rate_obj) { + mp_float_t rate = mp_arg_validate_obj_float_range(rate_obj, 0.001, 1000.0, MP_QSTR_rate); + return (uint32_t)(rate * (1 << SPEED_SHIFT)); +} + +// Convert 16.16 fixed-point rate to Python float +mp_obj_t audiospeed_fp_to_rate(uint32_t rate_fp) { + return mp_obj_new_float((mp_float_t)rate_fp / (1 << SPEED_SHIFT)); +} + +void audiospeed_construct(audiospeed_base_t *self, mp_obj_t rate_obj) { + self->src_buffer = NULL; + self->src_buffer_length = 0; + self->src_sample_count = 0; + self->source_done = false; + self->source_exhausted = false; + + self->base.channel_count = 1; + self->base.single_buffer = false; + + audiospeed_set_rate(&self->speed, rate_obj); + audiospeed_reset_phase(&self->speed); + + self->output_buffer_length = 0; + self->output_buffer = NULL; +} + +void audiospeed_assign_source(audiospeed_base_t *self, mp_obj_t source) { + audiosample_base_t *src_base = audiosample_check(source); + + self->source = source; + + // Copy format from source + self->base.sample_rate = src_base->sample_rate; + self->base.channel_count = src_base->channel_count; + self->base.bits_per_sample = src_base->bits_per_sample; + self->base.samples_signed = src_base->samples_signed; + + uint8_t bytes_per_frame = (src_base->bits_per_sample / 8) * src_base->channel_count; + uint32_t output_buffer_length = OUTPUT_BUFFER_FRAMES * bytes_per_frame; + + if (self->output_buffer != NULL && output_buffer_length != self->output_buffer_length) { + self->output_buffer = m_realloc(self->output_buffer, + #if MICROPY_MALLOC_USES_ALLOCATED_SIZE + self->output_buffer_length, + #endif + output_buffer_length); + } else if (self->output_buffer == NULL) { + self->output_buffer = m_malloc_without_collect(output_buffer_length); + } + if (self->output_buffer == NULL) { + m_malloc_fail(output_buffer_length); + } + + self->output_buffer_length = output_buffer_length; + self->base.max_buffer_length = self->output_buffer_length; +} + +void audiospeed_deinit(audiospeed_base_t *self) { + self->output_buffer = NULL; + self->source = MP_OBJ_NULL; + audiosample_mark_deinit(&self->base); +} + +// Fetch the next buffer from the source. Returns false if no data available. +bool audiospeed_fetch_source_buffer(audiospeed_base_t *self) { + if (self->source_exhausted || self->source == NULL) { + return false; + } + uint8_t *buf = NULL; + uint32_t len = 0; + audioio_get_buffer_result_t result = audiosample_get_buffer(self->source, false, 0, &buf, &len); + if (result == GET_BUFFER_ERROR) { + self->source_exhausted = true; + return false; + } + if (len == 0) { + self->source_exhausted = true; + return false; + } + self->src_buffer = buf; + self->src_buffer_length = len; + uint8_t bytes_per_frame = (self->base.bits_per_sample / 8) * self->base.channel_count; + self->src_sample_count = len / bytes_per_frame; + self->source_done = (result == GET_BUFFER_DONE); + // Reset phase to index within this new buffer + audiospeed_reset_phase(&self->speed); + return true; +} + +void audiospeed_reset_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel) { + if (single_channel_output && channel == 1) { + return; + } + audiosample_reset_buffer(self->source, false, 0); + audiospeed_reset_phase(&self->speed); + self->src_buffer = NULL; + self->src_buffer_length = 0; + self->src_sample_count = 0; + self->source_done = false; + self->source_exhausted = false; +} + +audioio_get_buffer_result_t audiospeed_get_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + + // Ensure we have a source buffer + if (self->src_buffer == NULL) { + if (!audiospeed_fetch_source_buffer(self)) { + *buffer = NULL; + *buffer_length = 0; + return GET_BUFFER_DONE; + } + } + + uint8_t bytes_per_sample = self->base.bits_per_sample / 8; + uint8_t channels = self->base.channel_count; + uint8_t bytes_per_frame = bytes_per_sample * channels; + uint32_t out_frames = 0; + uint32_t max_out_frames = self->output_buffer_length / bytes_per_frame; + + if (bytes_per_sample == 1) { + // 8-bit samples + uint8_t *out = self->output_buffer; + while (out_frames < max_out_frames) { + uint32_t src_index = audiospeed_get_index(&self->speed); + // Advance to next source buffer if needed + if (src_index >= self->src_sample_count) { + if (self->source_done) { + self->source_exhausted = true; + break; + } + if (!audiospeed_fetch_source_buffer(self)) { + break; + } + src_index = 0; // phase was reset by fetch + } + uint8_t *src = self->src_buffer + src_index * bytes_per_frame; + for (uint8_t c = 0; c < channels; c++) { + *out++ = src[c]; + } + out_frames++; + audiospeed_increment_phase(&self->speed); + } + } else { + // 16-bit samples + int16_t *out = (int16_t *)self->output_buffer; + while (out_frames < max_out_frames) { + uint32_t src_index = audiospeed_get_index(&self->speed); + if (src_index >= self->src_sample_count) { + if (self->source_done) { + self->source_exhausted = true; + break; + } + if (!audiospeed_fetch_source_buffer(self)) { + break; + } + src_index = 0; + } + int16_t *src = (int16_t *)(self->src_buffer + src_index * bytes_per_frame); + for (uint8_t c = 0; c < channels; c++) { + *out++ = src[c]; + } + out_frames++; + audiospeed_increment_phase(&self->speed); + } + } + + *buffer = self->output_buffer; + *buffer_length = out_frames * bytes_per_frame; + + if (out_frames == 0) { + return GET_BUFFER_DONE; + } + return self->source_exhausted ? GET_BUFFER_DONE : GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/audiospeed/__init__.h b/shared-module/audiospeed/__init__.h index c4a52e5819d..8094778eba4 100644 --- a/shared-module/audiospeed/__init__.h +++ b/shared-module/audiospeed/__init__.h @@ -5,3 +5,69 @@ // SPDX-License-Identifier: MIT #pragma once + +#include + +#include "py/objproperty.h" +#include "shared-module/audiocore/__init__.h" + +// Fixed-point 16.16 format +#define SPEED_SHIFT 16 +#define SPEED_DEFAULT (1 << SPEED_SHIFT) // default 1.0 + +typedef struct { + // Phase accumulator and rate in 16.16 fixed-point (units: source frames) + uint32_t phase; + uint32_t rate_fp; // 16.16 fixed-point rate +} audiospeed_speed_t; + +uint32_t audiospeed_rate_to_fp(mp_obj_t rate_obj); +mp_obj_t audiospeed_fp_to_rate(uint32_t rate_fp); + +static inline void audiospeed_set_rate(audiospeed_speed_t *self, mp_obj_t rate_obj) { + if (rate_obj != mp_const_none) { + self->rate_fp = audiospeed_rate_to_fp(rate_obj); + } else { + self->rate_fp = SPEED_DEFAULT; + } +} + +static inline mp_obj_t audiospeed_get_rate(audiospeed_speed_t *self) { + return audiospeed_fp_to_rate(self->rate_fp); +} + +static inline void audiospeed_reset_phase(audiospeed_speed_t *self) { + self->phase = 0; +} + +static inline void audiospeed_increment_phase(audiospeed_speed_t *self) { + self->phase += self->rate_fp; +} + +static inline uint32_t audiospeed_get_index(audiospeed_speed_t *self) { + return self->phase >> SPEED_SHIFT; +} + +#define OUTPUT_BUFFER_FRAMES 128 + +typedef struct { + audiosample_base_t base; + mp_obj_t source; + uint8_t *output_buffer; + uint32_t output_buffer_length; // in bytes, allocated size + // Source buffer cache + uint8_t *src_buffer; + uint32_t src_buffer_length; // in bytes + uint32_t src_sample_count; // in frames + audiospeed_speed_t speed; + bool source_done; // source returned DONE on last get_buffer + bool source_exhausted; // source DONE and we consumed all of it +} audiospeed_base_t; + +void audiospeed_construct(audiospeed_base_t *self, mp_obj_t rate_obj); +void audiospeed_deinit(audiospeed_base_t *self); +void audiospeed_assign_source(audiospeed_base_t *self, mp_obj_t source); +bool audiospeed_fetch_source_buffer(audiospeed_base_t *self); +void audiospeed_reset_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t audiospeed_get_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length); From 48bad18db9d22a2968975130d23f6de7cf2e3a88 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 17 Jun 2026 15:13:27 -0400 Subject: [PATCH 556/876] espressif: handle SOC_TOUCH_SENSOR_VERSION == 3 (ESP32-P4 and other newer chips) --- ports/espressif/common-hal/alarm/touch/TouchAlarm.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ports/espressif/common-hal/alarm/touch/TouchAlarm.c b/ports/espressif/common-hal/alarm/touch/TouchAlarm.c index 617f7632e63..93756b3c2ca 100644 --- a/ports/espressif/common-hal/alarm/touch/TouchAlarm.c +++ b/ports/espressif/common-hal/alarm/touch/TouchAlarm.c @@ -125,12 +125,19 @@ void alarm_touch_touchalarm_set_alarm(const bool deep_sleep, const size_t n_alar .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, .group = TOUCH_CHAN_TRIG_GROUP_BOTH, }; - #else + #elif SOC_TOUCH_SENSOR_VERSION == 2 touch_channel_config_t chan_cfg = { .active_thresh = {(uint32_t)(benchmark / 10)}, .charge_speed = TOUCH_CHARGE_SPEED_7, .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, }; + #elif SOC_TOUCH_SENSOR_VERSION == 3 + // Values are similar to an ESP-IDF example: 1000, 2500, 5000. + touch_channel_config_t chan_cfg = { + .active_thresh = {(uint32_t)(benchmark / 10), (uint32_t)(benchmark / 4), (uint32_t)(benchmark / 2)}, + }; + #else + #error bad SOC_TOUCH_SENSOR_VERSION #endif touch_sensor_reconfig_channel(chan, &chan_cfg); } From cfd0a18f34e20c08e63e0029f57636890ef95d8c Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 17 Jun 2026 14:15:59 -0500 Subject: [PATCH 557/876] Fix audiocore build for other ports --- py/circuitpy_defns.mk | 1 + shared-module/audiocore/__init__.c | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index a505d5c86d9..e5698c77cc3 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -151,6 +151,7 @@ SRC_PATTERNS += audiomp3/% endif ifeq ($(CIRCUITPY_AUDIOSPEED),1) SRC_PATTERNS += audiospeed/% +CFLAGS += -DCIRCUITPY_AUDIOSPEED endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 0767f93b811..945ff823ac6 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -13,7 +13,9 @@ #include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/WaveFile.h" +#if defined(CIRCUITPY_AUDIOSPEED) #include "shared-bindings/audiospeed/Resampler.h" +#endif #include "shared-bindings/audiomixer/Mixer.h" #include "shared-module/audiomixer/Mixer.h" @@ -200,8 +202,14 @@ void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool allow_mono_to_stereo) { const audiosample_base_t *other = audiosample_check(other_in); - if (other->sample_rate != self->sample_rate && !mp_obj_is_type(other_in, &audiospeed_resampler_type)) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); + if (other->sample_rate != self->sample_rate) { + #if defined(CIRCUITPY_AUDIOSPEED) + if (!mp_obj_is_type(other_in, &audiospeed_resampler_type)) { + #endif + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); + #if defined(CIRCUITPY_AUDIOSPEED) + } + #endif } if ((!allow_mono_to_stereo || (allow_mono_to_stereo && self->channel_count != 2)) && other->channel_count != self->channel_count) { mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); @@ -213,8 +221,10 @@ void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool al mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); } + #if defined(CIRCUITPY_AUDIOSPEED) if (mp_obj_is_type(other_in, &audiospeed_resampler_type)) { audiospeed_resampler_obj_t *other_resampler = MP_OBJ_TO_PTR(other_in); audiospeed_resampler_set_sample_rate(other_resampler, self->sample_rate); } + #endif } From cae3c81c339e45564879bbc5bf76e39409782a6f Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 17 Jun 2026 14:28:09 -0500 Subject: [PATCH 558/876] Assign source to resampler in constructor --- shared-bindings/audiospeed/Resampler.c | 69 +++++-------------------- shared-bindings/audiospeed/Resampler.h | 6 +-- shared-module/audiospeed/Resampler.c | 17 +----- shared-module/audiospeed/SpeedChanger.c | 3 +- shared-module/audiospeed/__init__.c | 43 +++++---------- shared-module/audiospeed/__init__.h | 3 +- 6 files changed, 31 insertions(+), 110 deletions(-) diff --git a/shared-bindings/audiospeed/Resampler.c b/shared-bindings/audiospeed/Resampler.c index db559cd1212..8abf52905d4 100644 --- a/shared-bindings/audiospeed/Resampler.c +++ b/shared-bindings/audiospeed/Resampler.c @@ -45,8 +45,19 @@ //| static mp_obj_t audiospeed_resampler_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_source }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_source, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Validate source implements audiosample protocol + mp_obj_t source = args[ARG_source].u_obj; + audiosample_check(source); + audiospeed_resampler_obj_t *self = mp_obj_malloc(audiospeed_resampler_obj_t, &audiospeed_resampler_type); - common_hal_audiospeed_resampler_construct(self); + common_hal_audiospeed_resampler_construct(self, source); return MP_OBJ_FROM_PTR(self); } @@ -61,58 +72,6 @@ static mp_obj_t audiospeed_resampler_deinit(mp_obj_t self_in) { } static MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_deinit_obj, audiospeed_resampler_deinit); -//| playing: bool -//| """True when the resampler is playing a sample. (read-only)""" -//| -static mp_obj_t audiospeed_resampler_obj_get_playing(mp_obj_t self_in) { - audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(self_in); - audiosample_check_for_deinit(&self->base.base); - return mp_obj_new_bool(common_hal_audiospeed_resampler_get_playing(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_get_playing_obj, audiospeed_resampler_obj_get_playing); - -MP_PROPERTY_GETTER(audiospeed_resampler_playing_obj, - (mp_obj_t)&audiospeed_resampler_get_playing_obj); - -//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Resampler: -//| """Plays the sample. Use an `audiomixer.Mixer` object to enable looping. -//| Does not block. Use `playing` to block. -//| -//| :return: The resampler object itself. Can be used for chaining, ie: -//| ``mixer.play(resampler.play(sample))``. -//| :rtype: Resampler""" -//| ... -//| -static mp_obj_t audiospeed_resampler_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample, ARG_loop }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED, {} }, - }; - audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); - audiosample_check_for_deinit(&self->base.base); - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t sample = args[ARG_sample].u_obj; - common_hal_audiospeed_resampler_play(self, sample); - - return MP_OBJ_FROM_PTR(self); -} -MP_DEFINE_CONST_FUN_OBJ_KW(audiospeed_resampler_play_obj, 1, audiospeed_resampler_obj_play); - -//| def stop(self) -> None: -//| """Stops playback of the sample.""" -//| ... -//| -//| -static mp_obj_t audiospeed_resampler_obj_stop(mp_obj_t self_in) { - audiospeed_resampler_obj_t *self = MP_OBJ_TO_PTR(self_in); - - common_hal_audiospeed_resampler_stop(self); - return mp_const_none; -} -MP_DEFINE_CONST_FUN_OBJ_1(audiospeed_resampler_stop_obj, audiospeed_resampler_obj_stop); - //| rate: float //| """Playback speed multiplier.""" //| @@ -131,12 +90,10 @@ static const mp_rom_map_elem_t audiospeed_resampler_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiospeed_resampler_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiospeed_resampler_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiospeed_resampler_stop_obj) }, // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiospeed_resampler_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiospeed_resampler_rate_obj) }, + AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiospeed_resampler_locals_dict, audiospeed_resampler_locals_dict_table); diff --git a/shared-bindings/audiospeed/Resampler.h b/shared-bindings/audiospeed/Resampler.h index 60425f4f8d3..7a744474bd1 100644 --- a/shared-bindings/audiospeed/Resampler.h +++ b/shared-bindings/audiospeed/Resampler.h @@ -10,13 +10,9 @@ extern const mp_obj_type_t audiospeed_resampler_type; -void common_hal_audiospeed_resampler_construct(audiospeed_resampler_obj_t *self); +void common_hal_audiospeed_resampler_construct(audiospeed_resampler_obj_t *self, mp_obj_t source); void common_hal_audiospeed_resampler_deinit(audiospeed_resampler_obj_t *self); -bool common_hal_audiospeed_resampler_get_playing(audiospeed_resampler_obj_t *self); -void common_hal_audiospeed_resampler_play(audiospeed_resampler_obj_t *self, mp_obj_t sample); -void common_hal_audiospeed_resampler_stop(audiospeed_resampler_obj_t *self); - mp_obj_t common_hal_audiospeed_resampler_get_rate(audiospeed_resampler_obj_t *self); void audiospeed_resampler_set_sample_rate(audiospeed_resampler_obj_t *self, uint32_t sample_rate); diff --git a/shared-module/audiospeed/Resampler.c b/shared-module/audiospeed/Resampler.c index 47b721834d1..cd1ac681246 100644 --- a/shared-module/audiospeed/Resampler.c +++ b/shared-module/audiospeed/Resampler.c @@ -14,8 +14,8 @@ static void calculate_rate(audiospeed_base_t *self, uint32_t sample_rate) { } } -void common_hal_audiospeed_resampler_construct(audiospeed_resampler_obj_t *self) { - audiospeed_construct(&self->base, mp_const_none); // default rate 1.0 +void common_hal_audiospeed_resampler_construct(audiospeed_resampler_obj_t *self, mp_obj_t source) { + audiospeed_construct(&self->base, source, mp_const_none); // default rate 1.0 self->sample_rate = 0; } @@ -23,19 +23,6 @@ void common_hal_audiospeed_resampler_deinit(audiospeed_resampler_obj_t *self) { audiospeed_deinit(&self->base); } -bool common_hal_audiospeed_resampler_get_playing(audiospeed_resampler_obj_t *self) { - return self->base.source != NULL; -} - -void common_hal_audiospeed_resampler_play(audiospeed_resampler_obj_t *self, mp_obj_t sample) { - audiospeed_assign_source(&self->base, sample); - calculate_rate(&self->base, self->sample_rate); -} - -void common_hal_audiospeed_resampler_stop(audiospeed_resampler_obj_t *self) { - self->base.source = NULL; -} - mp_obj_t common_hal_audiospeed_resampler_get_rate(audiospeed_resampler_obj_t *self) { return audiospeed_get_rate(&self->base.speed); } diff --git a/shared-module/audiospeed/SpeedChanger.c b/shared-module/audiospeed/SpeedChanger.c index 813132e4f14..1bf21dfab7a 100644 --- a/shared-module/audiospeed/SpeedChanger.c +++ b/shared-module/audiospeed/SpeedChanger.c @@ -15,8 +15,7 @@ void common_hal_audiospeed_speedchanger_construct(audiospeed_speedchanger_obj_t *self, mp_obj_t source, mp_obj_t rate_obj) { - audiospeed_construct(self, rate_obj); - audiospeed_assign_source(self, source); + audiospeed_construct(self, source, rate_obj); } void common_hal_audiospeed_speedchanger_deinit(audiospeed_speedchanger_obj_t *self) { diff --git a/shared-module/audiospeed/__init__.c b/shared-module/audiospeed/__init__.c index 5f1254b8dd7..19c4c9bf20d 100644 --- a/shared-module/audiospeed/__init__.c +++ b/shared-module/audiospeed/__init__.c @@ -25,52 +25,35 @@ mp_obj_t audiospeed_fp_to_rate(uint32_t rate_fp) { return mp_obj_new_float((mp_float_t)rate_fp / (1 << SPEED_SHIFT)); } -void audiospeed_construct(audiospeed_base_t *self, mp_obj_t rate_obj) { +void audiospeed_construct(audiospeed_base_t *self, mp_obj_t source, mp_obj_t rate_obj) { + audiosample_base_t *src_base = audiosample_check(source); + + self->source = source; self->src_buffer = NULL; self->src_buffer_length = 0; self->src_sample_count = 0; self->source_done = false; self->source_exhausted = false; - self->base.channel_count = 1; - self->base.single_buffer = false; - - audiospeed_set_rate(&self->speed, rate_obj); - audiospeed_reset_phase(&self->speed); - - self->output_buffer_length = 0; - self->output_buffer = NULL; -} - -void audiospeed_assign_source(audiospeed_base_t *self, mp_obj_t source) { - audiosample_base_t *src_base = audiosample_check(source); - - self->source = source; // Copy format from source self->base.sample_rate = src_base->sample_rate; self->base.channel_count = src_base->channel_count; self->base.bits_per_sample = src_base->bits_per_sample; self->base.samples_signed = src_base->samples_signed; + self->base.single_buffer = false; + + audiospeed_set_rate(&self->speed, rate_obj); + audiospeed_reset_phase(&self->speed); uint8_t bytes_per_frame = (src_base->bits_per_sample / 8) * src_base->channel_count; - uint32_t output_buffer_length = OUTPUT_BUFFER_FRAMES * bytes_per_frame; - - if (self->output_buffer != NULL && output_buffer_length != self->output_buffer_length) { - self->output_buffer = m_realloc(self->output_buffer, - #if MICROPY_MALLOC_USES_ALLOCATED_SIZE - self->output_buffer_length, - #endif - output_buffer_length); - } else if (self->output_buffer == NULL) { - self->output_buffer = m_malloc_without_collect(output_buffer_length); - } + self->output_buffer_length = OUTPUT_BUFFER_FRAMES * bytes_per_frame; + self->base.max_buffer_length = self->output_buffer_length; + + self->output_buffer = m_malloc_without_collect(self->output_buffer_length); if (self->output_buffer == NULL) { - m_malloc_fail(output_buffer_length); + m_malloc_fail(self->output_buffer_length); } - - self->output_buffer_length = output_buffer_length; - self->base.max_buffer_length = self->output_buffer_length; } void audiospeed_deinit(audiospeed_base_t *self) { diff --git a/shared-module/audiospeed/__init__.h b/shared-module/audiospeed/__init__.h index 8094778eba4..4a36a8b79b7 100644 --- a/shared-module/audiospeed/__init__.h +++ b/shared-module/audiospeed/__init__.h @@ -64,9 +64,8 @@ typedef struct { bool source_exhausted; // source DONE and we consumed all of it } audiospeed_base_t; -void audiospeed_construct(audiospeed_base_t *self, mp_obj_t rate_obj); +void audiospeed_construct(audiospeed_base_t *self, mp_obj_t source, mp_obj_t rate_obj); void audiospeed_deinit(audiospeed_base_t *self); -void audiospeed_assign_source(audiospeed_base_t *self, mp_obj_t source); bool audiospeed_fetch_source_buffer(audiospeed_base_t *self); void audiospeed_reset_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel); audioio_get_buffer_result_t audiospeed_get_buffer(audiospeed_base_t *self, bool single_channel_output, uint8_t channel, From cc5020bcb0479765cb16f79c311ead6f73c8fb93 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 17 Jun 2026 14:44:05 -0500 Subject: [PATCH 559/876] Fix formatting --- shared-module/audiocore/__init__.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 945ff823ac6..24f838c766f 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -13,7 +13,7 @@ #include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/WaveFile.h" -#if defined(CIRCUITPY_AUDIOSPEED) +#ifdef CIRCUITPY_AUDIOSPEED #include "shared-bindings/audiospeed/Resampler.h" #endif @@ -202,14 +202,12 @@ void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool allow_mono_to_stereo) { const audiosample_base_t *other = audiosample_check(other_in); + #ifndef CIRCUITPY_AUDIOSPEED if (other->sample_rate != self->sample_rate) { - #if defined(CIRCUITPY_AUDIOSPEED) - if (!mp_obj_is_type(other_in, &audiospeed_resampler_type)) { - #endif - mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); - #if defined(CIRCUITPY_AUDIOSPEED) - } + #else + if (other->sample_rate != self->sample_rate && !mp_obj_is_type(other_in, &audiospeed_resampler_type)) { #endif + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); } if ((!allow_mono_to_stereo || (allow_mono_to_stereo && self->channel_count != 2)) && other->channel_count != self->channel_count) { mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); @@ -221,7 +219,7 @@ void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool al mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); } - #if defined(CIRCUITPY_AUDIOSPEED) + #ifdef CIRCUITPY_AUDIOSPEED if (mp_obj_is_type(other_in, &audiospeed_resampler_type)) { audiospeed_resampler_obj_t *other_resampler = MP_OBJ_TO_PTR(other_in); audiospeed_resampler_set_sample_rate(other_resampler, self->sample_rate); From b9602c70a74404b16daf86027feb06ef5e49f9ac Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 17 Jun 2026 16:24:42 -0400 Subject: [PATCH 560/876] fix up touchio compile flags --- ports/espressif/mpconfigport.mk | 20 ++++++-------------- ports/espressif/peripherals/touch.c | 11 ++++++++++- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 33a989ae970..310743063f4 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -92,6 +92,7 @@ CIRCUITPY_ROTARYIO ?= 1 CIRCUITPY_SDIOIO ?= 1 CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY ?= 1 CIRCUITPY_SYNTHIO_MAX_CHANNELS ?= 12 +CIRCUITPY_TOUCHIO ?= 1 CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1 CIRCUITPY_WATCHDOG ?= 1 CIRCUITPY_WIFI ?= 1 @@ -118,6 +119,7 @@ CIRCUITPY_MEMORYMAP = 0 # No capacitive touch peripheral CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 @@ -148,8 +150,6 @@ CIRCUITPY_RGBMATRIX = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG = 0 @@ -166,6 +166,7 @@ CIRCUITPY_PARALLELDISPLAYBUS = 0 # No capacitive touch peripheral CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # No DAC CIRCUITPY_AUDIOIO = 0 @@ -181,8 +182,6 @@ CIRCUITPY_ROTARYIO = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 @@ -197,6 +196,7 @@ CIRCUITPY_RGBMATRIX = 0 # No capacitive touch peripheral CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # No DAC CIRCUITPY_AUDIOIO = 0 @@ -213,8 +213,6 @@ CIRCUITPY_PARALLELDISPLAYBUS = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 @@ -229,6 +227,7 @@ CIRCUITPY_RGBMATRIX = 0 # No capacitive touch peripheral CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # No DAC CIRCUITPY_AUDIOIO = 0 @@ -242,8 +241,6 @@ CIRCUITPY_PARALLELDISPLAYBUS = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 @@ -271,6 +268,7 @@ CIRCUITPY_RGBMATRIX = 0 # No capacitive touch peripheral CIRCUITPY_ALARM_TOUCH = 0 +CIRCUITPY_TOUCHIO_USE_NATIVE = 0 # No DAC CIRCUITPY_AUDIOIO = 0 @@ -284,9 +282,6 @@ CIRCUITPY_PARALLELDISPLAYBUS = 0 # No SDMMC CIRCUITPY_SDIOIO = 0 -CIRCUITPY_TOUCHIO ?= 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 - # Features CIRCUITPY_USB_DEVICE = 0 CIRCUITPY_ESP_USB_SERIAL_JTAG ?= 1 @@ -306,9 +301,6 @@ CIRCUITPY_BLEIO_NATIVE = 0 CIRCUITPY_WIFI = 0 CIRCUITPY_SSL = 0 -CIRCUITPY_TOUCHIO ?= 1 -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 - # Second stage bootloader doesn't work when the factory partition is empty due to # UF2 missing. UF2_BOOTLOADER = 0 diff --git a/ports/espressif/peripherals/touch.c b/ports/espressif/peripherals/touch.c index 1084a030ec8..e53a38c313b 100644 --- a/ports/espressif/peripherals/touch.c +++ b/ports/espressif/peripherals/touch.c @@ -74,6 +74,8 @@ void peripherals_touch_init(const int channel_id) { touch_sensor_sample_config_t sample_cfg = TOUCH_SENSOR_V2_DEFAULT_SAMPLE_CONFIG(500, TOUCH_VOLT_LIM_L_0V5, TOUCH_VOLT_LIM_H_2V2); #elif SOC_TOUCH_SENSOR_VERSION == 3 touch_sensor_sample_config_t sample_cfg = TOUCH_SENSOR_V3_DEFAULT_SAMPLE_CONFIG2(3, 29, 8, 3); + #else + #error bad SOC_TOUCH_SENSOR_VERSION #endif touch_sensor_config_t sens_cfg = TOUCH_SENSOR_DEFAULT_BASIC_CONFIG(1, &sample_cfg); touch_sensor_new_controller(&sens_cfg, &touch_controller); @@ -86,12 +88,19 @@ void peripherals_touch_init(const int channel_id) { .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, .group = TOUCH_CHAN_TRIG_GROUP_BOTH, }; - #else + #elif SOC_TOUCH_SENSOR_VERSION == 2 touch_channel_config_t chan_cfg = { .active_thresh = {2000}, .charge_speed = TOUCH_CHARGE_SPEED_7, .init_charge_volt = TOUCH_INIT_CHARGE_VOLT_DEFAULT, }; + #elif SOC_TOUCH_SENSOR_VERSION == 3 + // Values are similar to an ESP-IDF example: 1000, 2500, 5000. + touch_channel_config_t chan_cfg = { + .active_thresh = {1000, 2000, 5000}, + }; + #else + #error bad SOC_TOUCH_SENSOR_VERSION #endif touch_sensor_new_channel(touch_controller, channel_id, &chan_cfg, &touch_channels[idx]); From 704fe543e466c805c4e658ca7febe6b20ff18f52 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 17 Jun 2026 19:43:04 -0400 Subject: [PATCH 561/876] peripherals/touch.c: update for ESP32-P4 --- ports/espressif/peripherals/touch.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/ports/espressif/peripherals/touch.c b/ports/espressif/peripherals/touch.c index e53a38c313b..f55c16d3969 100644 --- a/ports/espressif/peripherals/touch.c +++ b/ports/espressif/peripherals/touch.c @@ -119,19 +119,29 @@ uint16_t peripherals_touch_read(int channel_id) { } uint32_t touch_value = 0; - touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_RAW, &touch_value); #if SOC_TOUCH_SENSOR_VERSION == 1 // ESP32 touch reads a lower value when touched. // Flip the values to be consistent with TouchIn assumptions. + touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_RAW, &touch_value); if (touch_value > UINT16_MAX) { return 0; } return UINT16_MAX - (uint16_t)touch_value; - #else + touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_RAW, &touch_value); + return UINT16_MAX - (uint16_t)touch_value; + #elif SOC_TOUCH_SENSOR_VERSION == 2 if (touch_value > UINT16_MAX) { return UINT16_MAX; } return (uint16_t)touch_value; + #elif SOC_TOUCH_SENSOR_VERSION == 3 + touch_channel_read_data(touch_channels[idx], TOUCH_CHAN_DATA_TYPE_SMOOTH, &touch_value); + if (touch_value > UINT16_MAX) { + return UINT16_MAX; + } + return (uint16_t)touch_value; + #else + #error bad SOC_TOUCH_SENSOR_VERSION #endif } From 9cb124a8450e3e9d9f0f2db9ecce4210b893e8e1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 18 Jun 2026 09:42:04 -0500 Subject: [PATCH 562/876] usb_audio module and USBMicrophone class --- locale/circuitpython.pot | 13 +- ports/raspberrypi/mpconfigport.mk | 1 + py/circuitpy_defns.mk | 3 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/usb_audio/USBMicrophone.c | 197 +++++++++++++ shared-bindings/usb_audio/USBMicrophone.h | 21 ++ shared-bindings/usb_audio/__init__.c | 98 +++++++ shared-bindings/usb_audio/__init__.h | 9 + shared-module/usb_audio/USBMicrophone.c | 149 ++++++++++ shared-module/usb_audio/USBMicrophone.h | 33 +++ shared-module/usb_audio/__init__.c | 275 ++++++++++++++++++ shared-module/usb_audio/__init__.h | 40 +++ shared-module/usb_audio/tusb_config.h | 7 + .../usb_audio/usb_audio_descriptors.h | 26 ++ supervisor/shared/usb/tusb_config.h | 20 ++ supervisor/shared/usb/usb.c | 7 + supervisor/shared/usb/usb_desc.c | 17 ++ supervisor/supervisor.mk | 12 + 18 files changed, 927 insertions(+), 4 deletions(-) create mode 100644 shared-bindings/usb_audio/USBMicrophone.c create mode 100644 shared-bindings/usb_audio/USBMicrophone.h create mode 100644 shared-bindings/usb_audio/__init__.c create mode 100644 shared-bindings/usb_audio/__init__.h create mode 100644 shared-module/usb_audio/USBMicrophone.c create mode 100644 shared-module/usb_audio/USBMicrophone.h create mode 100644 shared-module/usb_audio/__init__.c create mode 100644 shared-module/usb_audio/__init__.h create mode 100644 shared-module/usb_audio/tusb_config.h create mode 100644 shared-module/usb_audio/usb_audio_descriptors.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index eefb0f3dc22..fa088fdda5e 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -775,9 +775,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c msgid "Cannot change USB devices now" msgstr "" @@ -1686,6 +1686,7 @@ msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c #: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "" @@ -2148,7 +2149,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2270,6 +2271,10 @@ msgstr "" msgid "UID:" msgstr "" +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "USB audio not enabled in boot.py" +msgstr "" + #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 76f468beee6..c3fc727d889 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -26,6 +26,7 @@ CIRCUITPY_ROTARYIO_SOFTENCODER = 1 CIRCUITPY_SYNTHIO_MAX_CHANNELS = 24 CIRCUITPY_USB_HOST ?= 1 CIRCUITPY_USB_VIDEO ?= 1 +CIRCUITPY_USB_AUDIO ?= 1 # Things that need to be implemented. CIRCUITPY_FREQUENCYIO = 0 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 67be45325d5..67801216c4b 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -450,6 +450,9 @@ endif ifeq ($(CIRCUITPY_USB_VIDEO),1) SRC_PATTERNS += usb_video/% endif +ifeq ($(CIRCUITPY_USB_AUDIO),1) +SRC_PATTERNS += usb_audio/% +endif ifeq ($(CIRCUITPY_USB_HOST),1) SRC_PATTERNS += usb_host/% endif diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index f56813f3b91..d8c15ba9440 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -671,6 +671,9 @@ CFLAGS += -DCIRCUITPY_USB_HID_ENABLED_DEFAULT=$(CIRCUITPY_USB_HID_ENABLED_DEFAUL CIRCUITPY_USB_VIDEO ?= 0 CFLAGS += -DCIRCUITPY_USB_VIDEO=$(CIRCUITPY_USB_VIDEO) +CIRCUITPY_USB_AUDIO ?= 0 +CFLAGS += -DCIRCUITPY_USB_AUDIO=$(CIRCUITPY_USB_AUDIO) + CIRCUITPY_USB_HOST ?= 0 CFLAGS += -DCIRCUITPY_USB_HOST=$(CIRCUITPY_USB_HOST) diff --git a/shared-bindings/usb_audio/USBMicrophone.c b/shared-bindings/usb_audio/USBMicrophone.c new file mode 100644 index 00000000000..2ccf7b2d17b --- /dev/null +++ b/shared-bindings/usb_audio/USBMicrophone.c @@ -0,0 +1,197 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-bindings/util.h" +#include "shared-module/usb_audio/__init__.h" + +//| class USBMicrophone: +//| """Streams an audio sample to the host computer as a USB Audio Class microphone. +//| +//| A ``USBMicrophone`` is a *consumer* of an audio sample, exactly like +//| `audioio.AudioOut`, `audiobusio.I2SOut` and `audiopwmio.PWMAudioOut`. The +//| samples it pulls are streamed to the host PC over USB rather than to a pin, +//| so the board appears as a microphone. +//| +//| ``usb_audio.enable()`` must have been called in ``boot.py`` before this object +//| can be constructed.""" +//| +//| def __init__(self) -> None: +//| """Create a USBMicrophone using the audio format configured in ``boot.py``.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = {}; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // The audio format is chosen by usb_audio.enable() in boot.py, which also claims + // the USB interface. Without it there is no microphone for the host to read. + if (!usb_audio_enabled()) { + mp_raise_RuntimeError(MP_ERROR_TEXT("USB audio not enabled in boot.py")); + } + + usb_audio_usbmicrophone_obj_t *self = mp_obj_malloc_with_finaliser(usb_audio_usbmicrophone_obj_t, &usb_audio_USBMicrophone_type); + common_hal_usb_audio_usbmicrophone_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the USBMicrophone and releases any resources for reuse.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_deinit(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_usb_audio_usbmicrophone_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_deinit_obj, usb_audio_usbmicrophone_deinit); + +static void check_for_deinit(usb_audio_usbmicrophone_obj_t *self) { + if (common_hal_usb_audio_usbmicrophone_deinited(self)) { + raise_deinited_error(); + } +} + +//| def __enter__(self) -> USBMicrophone: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> None: +//| """Streams the sample to the host once when loop=False and continuously when +//| loop=True. Does not block. Use `playing` to block. +//| +//| Sample must be an `audiocore.WaveFile`, `audiocore.RawSample`, `audiomixer.Mixer`, +//| `audiomp3.MP3Decoder` or `synthio.Synthesizer`.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + common_hal_usb_audio_usbmicrophone_play(self, args[ARG_sample].u_obj, args[ARG_loop].u_bool); + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_KW(usb_audio_usbmicrophone_play_obj, 1, usb_audio_usbmicrophone_obj_play); + +//| def stop(self) -> None: +//| """Stops streaming and resets to the start of the sample.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_obj_stop(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_usb_audio_usbmicrophone_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_stop_obj, usb_audio_usbmicrophone_obj_stop); + +//| playing: bool +//| """True when an audio sample is being streamed even if `paused`. (read-only)""" +//| +static mp_obj_t usb_audio_usbmicrophone_obj_get_playing(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_usb_audio_usbmicrophone_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_get_playing_obj, usb_audio_usbmicrophone_obj_get_playing); + +MP_PROPERTY_GETTER(usb_audio_usbmicrophone_playing_obj, + (mp_obj_t)&usb_audio_usbmicrophone_get_playing_obj); + +//| def pause(self) -> None: +//| """Stops streaming temporarily while remembering the position. Use `resume` to resume.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_obj_pause(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (!common_hal_usb_audio_usbmicrophone_get_playing(self)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Not playing")); + } + common_hal_usb_audio_usbmicrophone_pause(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_pause_obj, usb_audio_usbmicrophone_obj_pause); + +//| def resume(self) -> None: +//| """Resumes streaming after :py:func:`pause`.""" +//| ... +//| +static mp_obj_t usb_audio_usbmicrophone_obj_resume(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + + if (common_hal_usb_audio_usbmicrophone_get_paused(self)) { + common_hal_usb_audio_usbmicrophone_resume(self); + } + + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_resume_obj, usb_audio_usbmicrophone_obj_resume); + +//| paused: bool +//| """True when streaming is paused. (read-only)""" +//| +//| +static mp_obj_t usb_audio_usbmicrophone_obj_get_paused(mp_obj_t self_in) { + usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_usb_audio_usbmicrophone_get_paused(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbmicrophone_get_paused_obj, usb_audio_usbmicrophone_obj_get_paused); + +MP_PROPERTY_GETTER(usb_audio_usbmicrophone_paused_obj, + (mp_obj_t)&usb_audio_usbmicrophone_get_paused_obj); + +static const mp_rom_map_elem_t usb_audio_usbmicrophone_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usb_audio_usbmicrophone_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&usb_audio_usbmicrophone_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&usb_audio_usbmicrophone_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&usb_audio_usbmicrophone_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_pause), MP_ROM_PTR(&usb_audio_usbmicrophone_pause_obj) }, + { MP_ROM_QSTR(MP_QSTR_resume), MP_ROM_PTR(&usb_audio_usbmicrophone_resume_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&usb_audio_usbmicrophone_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_paused), MP_ROM_PTR(&usb_audio_usbmicrophone_paused_obj) }, +}; +static MP_DEFINE_CONST_DICT(usb_audio_usbmicrophone_locals_dict, usb_audio_usbmicrophone_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + usb_audio_USBMicrophone_type, + MP_QSTR_USBMicrophone, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, usb_audio_usbmicrophone_make_new, + locals_dict, &usb_audio_usbmicrophone_locals_dict + ); diff --git a/shared-bindings/usb_audio/USBMicrophone.h b/shared-bindings/usb_audio/USBMicrophone.h new file mode 100644 index 00000000000..4fe096778bc --- /dev/null +++ b/shared-bindings/usb_audio/USBMicrophone.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/usb_audio/USBMicrophone.h" + +extern const mp_obj_type_t usb_audio_USBMicrophone_type; + +void common_hal_usb_audio_usbmicrophone_construct(usb_audio_usbmicrophone_obj_t *self); +void common_hal_usb_audio_usbmicrophone_deinit(usb_audio_usbmicrophone_obj_t *self); +bool common_hal_usb_audio_usbmicrophone_deinited(usb_audio_usbmicrophone_obj_t *self); +void common_hal_usb_audio_usbmicrophone_play(usb_audio_usbmicrophone_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_usb_audio_usbmicrophone_stop(usb_audio_usbmicrophone_obj_t *self); +bool common_hal_usb_audio_usbmicrophone_get_playing(usb_audio_usbmicrophone_obj_t *self); +void common_hal_usb_audio_usbmicrophone_pause(usb_audio_usbmicrophone_obj_t *self); +void common_hal_usb_audio_usbmicrophone_resume(usb_audio_usbmicrophone_obj_t *self); +bool common_hal_usb_audio_usbmicrophone_get_paused(usb_audio_usbmicrophone_obj_t *self); diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c new file mode 100644 index 00000000000..d6b5e15f02e --- /dev/null +++ b/shared-bindings/usb_audio/__init__.c @@ -0,0 +1,98 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/usb_audio/__init__.h" +#include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-module/usb_audio/__init__.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +//| """Stream audio to a host computer via USB +//| +//| This makes your CircuitPython device identify to the host computer as a USB +//| Audio Class (UAC2) microphone: the board is the audio *source* and streams +//| samples to the host over a USB isochronous IN endpoint. +//| +//| This mode requires 1 IN endpoint and 2 interfaces. Generally, microcontrollers +//| have a limit on the number of endpoints. If you exceed the number of endpoints, +//| CircuitPython will automatically enter Safe Mode. Even in this case, you may be +//| able to enable USB audio by also disabling other USB functions, such as +//| `usb_hid` or `usb_midi`. +//| +//| To enable this mode, you must configure the audio format in ``boot.py`` and then +//| create a `USBMicrophone` in ``code.py``. +//| +//| .. code-block:: py +//| +//| # boot.py +//| import usb_audio +//| usb_audio.enable(sample_rate=16000, channel_count=1, bits_per_sample=16) +//| +//| .. code-block:: py +//| +//| # code.py +//| import usb_audio +//| import synthio +//| +//| mic = usb_audio.USBMicrophone() +//| synth = synthio.Synthesizer(sample_rate=16000, channel_count=1) +//| mic.play(synth, loop=True) +//| synth.press(60) +//| +//| """ +//| +//| + +//| def enable( +//| sample_rate: int = 16000, channel_count: int = 1, bits_per_sample: int = 16 +//| ) -> None: +//| """Enable the USB audio microphone interface with the given PCM format. +//| +//| This function may only be used from ``boot.py``. +//| +//| :param int sample_rate: Samples per second of the streamed audio. +//| :param int channel_count: Number of channels. Only mono (1) is supported initially. +//| :param int bits_per_sample: Bits per signed PCM sample. Only 16 is supported initially.""" +//| +//| +static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample_rate, ARG_channel_count, ARG_bits_per_sample }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample_rate, MP_ARG_INT, { .u_int = 16000 } }, + { MP_QSTR_channel_count, MP_ARG_INT, { .u_int = 1 } }, + { MP_QSTR_bits_per_sample, MP_ARG_INT, { .u_int = 16 } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t sample_rate = mp_arg_validate_int_range(args[ARG_sample_rate].u_int, 1, USB_AUDIO_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_N_CHANNELS, MP_QSTR_channel_count); + mp_int_t bits_per_sample = mp_arg_validate_int(args[ARG_bits_per_sample].u_int, USB_AUDIO_BITS_PER_SAMPLE, MP_QSTR_bits_per_sample); + + if (!shared_module_usb_audio_enable(sample_rate, channel_count, bits_per_sample)) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot change USB devices now")); + } + + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(usb_audio_enable_obj, 0, usb_audio_enable); + +static const mp_rom_map_elem_t usb_audio_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_audio) }, + { MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_ROM_PTR(&usb_audio_USBMicrophone_type) }, + { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&usb_audio_enable_obj) }, +}; + +static MP_DEFINE_CONST_DICT(usb_audio_module_globals, usb_audio_module_globals_table); + +const mp_obj_module_t usb_audio_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&usb_audio_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_usb_audio, usb_audio_module); diff --git a/shared-bindings/usb_audio/__init__.h b/shared-bindings/usb_audio/__init__.h new file mode 100644 index 00000000000..b0c8d2b9205 --- /dev/null +++ b/shared-bindings/usb_audio/__init__.h @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/usb_audio/__init__.h" diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c new file mode 100644 index 00000000000..fd5309abeb9 --- /dev/null +++ b/shared-module/usb_audio/USBMicrophone.c @@ -0,0 +1,149 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/misc.h" +#include "py/runtime.h" + +#include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-module/usb_audio/__init__.h" +#include "shared-module/audiocore/__init__.h" + +// Only one microphone may feed the single USB IN endpoint at a time. This points +// at the USBMicrophone whose play() was called most recently, or NULL when none +// is streaming. The USB background task pulls from it via +// usb_audio_usbmicrophone_background_fill(). +static usb_audio_usbmicrophone_obj_t *active_microphone = NULL; + +void common_hal_usb_audio_usbmicrophone_construct(usb_audio_usbmicrophone_obj_t *self) { + self->sample = MP_OBJ_NULL; + self->buffer = NULL; + self->buffer_length = 0; + self->loop = false; + self->playing = false; + self->paused = false; + self->deinited = false; + self->more_data = false; +} + +void common_hal_usb_audio_usbmicrophone_deinit(usb_audio_usbmicrophone_obj_t *self) { + common_hal_usb_audio_usbmicrophone_stop(self); + self->deinited = true; +} + +bool common_hal_usb_audio_usbmicrophone_deinited(usb_audio_usbmicrophone_obj_t *self) { + return self->deinited; +} + +void common_hal_usb_audio_usbmicrophone_play(usb_audio_usbmicrophone_obj_t *self, mp_obj_t sample, bool loop) { + // The negotiated USB format is fixed 16-bit signed LE PCM at the rate/channel + // count chosen by usb_audio.enable() in boot.py. Resampling and format + // conversion are out of scope, so the source must already match exactly. This + // mirrors how audiocore's audiosample_must_match() validates an output's input + // (and reuses its error messages), but checks against the USB format rather + // than another audiosample. + audiosample_base_t *sample_base = audiosample_check(sample); + if (audiosample_get_sample_rate(sample_base) != usb_audio_sample_rate) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_sample_rate); + } + if (audiosample_get_channel_count(sample_base) != usb_audio_channel_count) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); + } + if (audiosample_get_bits_per_sample(sample_base) != usb_audio_bits_per_sample) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_bits_per_sample); + } + if (!sample_base->samples_signed) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); + } + + // Start at the beginning and arm the pull loop to request the first chunk. + audiosample_reset_buffer(sample, false, 0); + self->sample = sample; + self->buffer = NULL; + self->buffer_length = 0; + self->loop = loop; + self->playing = true; + self->paused = false; + self->more_data = true; + // Take over the single USB IN endpoint from any other microphone. + active_microphone = self; +} + +void common_hal_usb_audio_usbmicrophone_stop(usb_audio_usbmicrophone_obj_t *self) { + self->sample = MP_OBJ_NULL; + self->buffer = NULL; + self->buffer_length = 0; + self->playing = false; + self->paused = false; + self->more_data = false; + if (active_microphone == self) { + active_microphone = NULL; + } +} + +bool common_hal_usb_audio_usbmicrophone_get_playing(usb_audio_usbmicrophone_obj_t *self) { + return self->playing && !self->paused; +} + +void common_hal_usb_audio_usbmicrophone_pause(usb_audio_usbmicrophone_obj_t *self) { + self->paused = true; +} + +void common_hal_usb_audio_usbmicrophone_resume(usb_audio_usbmicrophone_obj_t *self) { + self->paused = false; +} + +bool common_hal_usb_audio_usbmicrophone_get_paused(usb_audio_usbmicrophone_obj_t *self) { + return self->playing && self->paused; +} + +size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { + usb_audio_usbmicrophone_obj_t *self = active_microphone; + if (self == NULL || !self->playing || self->paused || self->sample == MP_OBJ_NULL) { + return 0; + } + + // The negotiated USB format is 16-bit signed mono PCM. For this step the + // bound sample is assumed to already be in that format (e.g. a 16-bit signed + // mono audiocore.RawSample), so its bytes are copied straight through. + size_t filled = 0; + while (filled < max_bytes) { + if (self->buffer_length == 0) { + if (!self->more_data) { + // The previous chunk was the sample's last and we've played it + // out. Loop back to the start or stop. + if (self->loop) { + audiosample_reset_buffer(self->sample, false, 0); + self->more_data = true; + } else { + common_hal_usb_audio_usbmicrophone_stop(self); + break; + } + } + audioio_get_buffer_result_t result = + audiosample_get_buffer(self->sample, false, 0, &self->buffer, &self->buffer_length); + if (result == GET_BUFFER_ERROR) { + common_hal_usb_audio_usbmicrophone_stop(self); + break; + } + self->more_data = (result == GET_BUFFER_MORE_DATA); + if (self->buffer_length == 0) { + // No samples available right now (underrun); the caller fills the + // rest of the frame with silence and we retry next tick. + break; + } + } + + size_t n = MIN(self->buffer_length, max_bytes - filled); + memcpy(out + filled, self->buffer, n); + self->buffer += n; + self->buffer_length -= n; + filled += n; + } + + return filled; +} diff --git a/shared-module/usb_audio/USBMicrophone.h b/shared-module/usb_audio/USBMicrophone.h new file mode 100644 index 00000000000..74f167e8e43 --- /dev/null +++ b/shared-module/usb_audio/USBMicrophone.h @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +typedef struct usb_audio_usbmicrophone_obj { + mp_obj_base_t base; + // The audiosample currently bound for streaming, or MP_OBJ_NULL. + mp_obj_t sample; + // Cursor into the chunk last returned by audiosample_get_buffer(): the next + // unread byte and the number of bytes still unread in that chunk. + uint8_t *buffer; + uint32_t buffer_length; + bool loop; + bool playing; + bool paused; + bool deinited; + // False once audiosample_get_buffer() reported GET_BUFFER_DONE for the + // current chunk; the chunk is still played out, then we loop or stop. + bool more_data; +} usb_audio_usbmicrophone_obj_t; + +// Pull up to max_bytes of audio (in the negotiated USB PCM format) from whichever +// USBMicrophone is currently playing, writing it into out. Returns the number of +// bytes written, which is < max_bytes (possibly 0) when nothing is streaming or +// the source underruns; the caller pads the remainder with silence. Called from +// the USB background task in shared-module/usb_audio/__init__.c. +size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes); diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c new file mode 100644 index 00000000000..1ce2c6691fd --- /dev/null +++ b/shared-module/usb_audio/__init__.c @@ -0,0 +1,275 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include "shared-module/usb_audio/__init__.h" +#include "shared-module/usb_audio/USBMicrophone.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +#include + +#include "tusb.h" + +static bool usb_audio_is_enabled = false; +static bool usb_audio_is_streaming = false; + +uint32_t usb_audio_sample_rate; +uint8_t usb_audio_channel_count; +uint8_t usb_audio_bits_per_sample; + +// Audio control state surfaced to the host. One extra entry for the master channel 0. +static int8_t usb_audio_mute[USB_AUDIO_N_CHANNELS + 1]; +static int16_t usb_audio_volume[USB_AUDIO_N_CHANNELS + 1]; + +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample) { + if (tud_connected()) { + return false; + } + + usb_audio_sample_rate = sample_rate; + usb_audio_channel_count = channel_count; + usb_audio_bits_per_sample = bits_per_sample; + usb_audio_is_enabled = true; + + return true; +} + +bool shared_module_usb_audio_disable(void) { + if (tud_connected()) { + return false; + } + usb_audio_is_enabled = false; + return true; +} + +bool usb_audio_enabled(void) { + return usb_audio_is_enabled; +} + +bool usb_audio_streaming(void) { + return usb_audio_is_streaming; +} + +size_t usb_audio_descriptor_length(void) { + return TUD_AUDIO_MIC_ONE_CH_DESC_LEN; +} + +size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) { + usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); + const uint8_t usb_audio_descriptor[] = { + TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epin*/ descriptor_counts->current_endpoint | 0x80, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) + }; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. + descriptor_counts->current_interface += 2; + descriptor_counts->num_in_endpoints++; + descriptor_counts->current_endpoint++; + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); +} + +void usb_audio_task(void) { + if (!usb_audio_is_streaming) { + return; + } + + // Pace production by the IN FIFO level. Each pass we top the software FIFO + // back up to its half-full setpoint, generating only the samples the host has + // actually drained since the last pass. This limits our production rate to the + // host's true consumption rate (its USB SOF / audio clock), keeps the FIFO + // around the level TinyUSB's flow control targets so it can send steady + // nominal-size packets, and automatically catches up after any scheduling gap + // (GCpause, other background work) in a single pass instead of underrunning. + // Underruns here showed up to the host as discrete sample-drop/insert splices, + // i.e. the erratic ticking on a held tone. + tu_fifo_t *ep_in_ff = tud_audio_get_ep_in_ff(); + uint16_t const target = tu_fifo_depth(ep_in_ff) / 2; + + // One scratch chunk (1 ms at the max rate); we loop until the FIFO reaches + // the setpoint. Sized for the highest rate enable() accepts. + static int16_t samples[USB_AUDIO_MAX_SAMPLE_RATE / 1000 * USB_AUDIO_N_CHANNELS]; + + uint16_t count; + while ((count = tu_fifo_count(ep_in_ff)) < target) { + size_t want = target - count; + if (want > sizeof(samples)) { + want = sizeof(samples); + } + + // Pull the next chunk from whichever USBMicrophone is playing. + bool underran = false; + size_t filled = usb_audio_usbmicrophone_background_fill((uint8_t *)samples, want); + if (filled == 0) { + // No source attached, paused, or fully drained: keep the endpoint + // alive with silence so the host never sees a starved stream. + memset((uint8_t *)samples, 0, want); + } else if (filled < want) { + // The source momentarily underran. Send just what it produced and + // let the FIFO cushion ride until it catches up next pass, rather + // than flooding the stream with a burst of silence. + want = filled; + underran = true; + } + + if (tud_audio_write((uint8_t *)samples, (uint16_t)want) == 0) { + break; // FIFO unexpectedly full / host not ready + } + if (underran) { + break; + } + } +} + +// --------------------------------------------------------------------+ +// TinyUSB audio class callbacks (weak symbols overridden here) +// --------------------------------------------------------------------+ + +// Host opened/closed the AudioStreaming alternate setting. +bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void)rhport; + uint8_t const alt = (uint8_t)tu_u16_low(p_request->wValue); + usb_audio_is_streaming = (alt != 0); + return true; +} + +bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void)rhport; + (void)p_request; + usb_audio_is_streaming = false; + return true; +} + +// Class-specific SET requests for an entity (we accept mute/volume on the feature unit). +bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request, uint8_t *pBuff) { + (void)rhport; + + uint8_t const channelNum = (uint8_t)tu_u16_low(p_request->wValue); + uint8_t const ctrlSel = (uint8_t)tu_u16_high(p_request->wValue); + uint8_t const entityID = (uint8_t)tu_u16_high(p_request->wIndex); + + // Only current-value requests are supported. + TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + + if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT) { + if (channelNum > USB_AUDIO_N_CHANNELS) { + return false; + } + switch (ctrlSel) { + case AUDIO_FU_CTRL_MUTE: + TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); + usb_audio_mute[channelNum] = ((audio_control_cur_1_t *)pBuff)->bCur; + return true; + + case AUDIO_FU_CTRL_VOLUME: + TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); + usb_audio_volume[channelNum] = ((audio_control_cur_2_t *)pBuff)->bCur; + return true; + + default: + return false; + } + } + return false; +} + +// Class-specific GET requests for an entity (clock source, feature unit, input terminal). +bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p_request) { + (void)rhport; + + uint8_t const channelNum = (uint8_t)tu_u16_low(p_request->wValue); + uint8_t const ctrlSel = (uint8_t)tu_u16_high(p_request->wValue); + uint8_t const entityID = (uint8_t)tu_u16_high(p_request->wIndex); + + // Input terminal (microphone). + if (entityID == USB_AUDIO_ENTITY_INPUT_TERMINAL) { + switch (ctrlSel) { + case AUDIO_TE_CTRL_CONNECTOR: { + audio_desc_channel_cluster_t ret; + ret.bNrChannels = USB_AUDIO_N_CHANNELS; + ret.bmChannelConfig = (audio_channel_config_t)0; + ret.iChannelNames = 0; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); + } + default: + return false; + } + } + + // Feature unit (mute/volume). + if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT) { + if (channelNum > USB_AUDIO_N_CHANNELS) { + return false; + } + switch (ctrlSel) { + case AUDIO_FU_CTRL_MUTE: + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &usb_audio_mute[channelNum], sizeof(usb_audio_mute[channelNum])); + + case AUDIO_FU_CTRL_VOLUME: + switch (p_request->bRequest) { + case AUDIO_CS_REQ_CUR: + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &usb_audio_volume[channelNum], sizeof(usb_audio_volume[channelNum])); + + case AUDIO_CS_REQ_RANGE: { + audio_control_range_2_n_t(1) ret; + ret.wNumSubRanges = 1; + ret.subrange[0].bMin = -90 * 256; // -90 dB + ret.subrange[0].bMax = 90 * 256; // +90 dB + ret.subrange[0].bRes = 256; // 1 dB steps + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); + } + + default: + return false; + } + + default: + return false; + } + } + + // Clock source (sample rate set in usb_audio.enable()). + if (entityID == USB_AUDIO_ENTITY_CLOCK_SOURCE) { + switch (ctrlSel) { + case AUDIO_CS_CTRL_SAM_FREQ: + switch (p_request->bRequest) { + case AUDIO_CS_REQ_CUR: { + audio_control_cur_4_t cur = { .bCur = (int32_t)usb_audio_sample_rate }; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur, sizeof(cur)); + } + + case AUDIO_CS_REQ_RANGE: { + audio_control_range_4_n_t(1) ret; + ret.wNumSubRanges = 1; + ret.subrange[0].bMin = (int32_t)usb_audio_sample_rate; + ret.subrange[0].bMax = (int32_t)usb_audio_sample_rate; + ret.subrange[0].bRes = 0; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); + } + + default: + return false; + } + + case AUDIO_CS_CTRL_CLK_VALID: { + audio_control_cur_1_t cur = { .bCur = 1 }; + return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur, sizeof(cur)); + } + + default: + return false; + } + } + + return false; +} diff --git a/shared-module/usb_audio/__init__.h b/shared-module/usb_audio/__init__.h new file mode 100644 index 00000000000..c2ef25d0590 --- /dev/null +++ b/shared-module/usb_audio/__init__.h @@ -0,0 +1,40 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include + +#include "py/obj.h" +#include "supervisor/usb.h" + +// Enable/disable the USB Audio Class (UAC2) microphone interface. These may +// only be called before USB is connected (i.e. from boot.py); they return +// false otherwise. +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample); +bool shared_module_usb_audio_disable(void); + +// True once enable() has been called successfully. +bool usb_audio_enabled(void); + +// True while the host has opened the AudioStreaming alternate setting, i.e. it is +// actively listening. This is the real "stream the audio now" signal. +bool usb_audio_streaming(void); + +// Negotiated audio format, valid when usb_audio_enabled() is true. +extern uint32_t usb_audio_sample_rate; +extern uint8_t usb_audio_channel_count; +extern uint8_t usb_audio_bits_per_sample; + +// Descriptor injection hooks, called from supervisor/shared/usb/usb_desc.c. +size_t usb_audio_descriptor_length(void); +size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string); + +// Background task that streams samples to the host, called from +// supervisor/shared/usb/usb.c. +void usb_audio_task(void); diff --git a/shared-module/usb_audio/tusb_config.h b/shared-module/usb_audio/tusb_config.h new file mode 100644 index 00000000000..d7bfb65b148 --- /dev/null +++ b/shared-module/usb_audio/tusb_config.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h new file mode 100644 index 00000000000..e2124214d41 --- /dev/null +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -0,0 +1,26 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Fixed audio format for the UAC2 microphone profile. These must have no other +// dependencies because this header is included from the TinyUSB tusb_config.h +// (to size the IN endpoint) as well as from the descriptor/binding code. + +// The isochronous IN endpoint's wMaxPacketSize in the USB descriptor is computed +// for this rate, so it is the highest rate usb_audio.enable() will accept. +#define USB_AUDIO_MAX_SAMPLE_RATE (48000) + +// 16-bit signed LE PCM, mono. +#define USB_AUDIO_N_BYTES_PER_SAMPLE (2) +#define USB_AUDIO_N_CHANNELS (1) +#define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) + +// Fixed UAC2 entity IDs baked into TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR. +#define USB_AUDIO_ENTITY_INPUT_TERMINAL (0x01) +#define USB_AUDIO_ENTITY_FEATURE_UNIT (0x02) +#define USB_AUDIO_ENTITY_OUTPUT_TERMINAL (0x03) +#define USB_AUDIO_ENTITY_CLOCK_SOURCE (0x04) diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index f2d800b9912..37a8a670b6b 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -115,8 +115,28 @@ extern "C" { #define CFG_TUD_HID CIRCUITPY_USB_HID #define CFG_TUD_MIDI CIRCUITPY_USB_MIDI #define CFG_TUD_VENDOR CIRCUITPY_USB_VENDOR +#define CFG_TUD_AUDIO CIRCUITPY_USB_AUDIO #define CFG_TUD_CUSTOM_CLASS 0 +// ------------- AUDIO CLASS (UAC2 microphone) -------------// +#if CIRCUITPY_USB_AUDIO +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +// Single audio function: 1 AudioStreaming interface, 1 isochronous IN endpoint. +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN +#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 +// EP0 buffer for class-specific control requests (sample-freq range, volume range, ...). +#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 + +#define CFG_TUD_AUDIO_ENABLE_EP_IN 1 +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX USB_AUDIO_N_BYTES_PER_SAMPLE +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_N_CHANNELS +// wMaxPacketSize, sized for the highest supported sample rate. +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +// Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) +#endif + /*------------------------------------------------------------------*/ /* CLASS DRIVER *------------------------------------------------------------------*/ diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index 5061fee0063..e8a4422bb36 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -39,6 +39,10 @@ #include "shared-module/usb_video/__init__.h" #endif +#if CIRCUITPY_USB_AUDIO +#include "shared-module/usb_audio/__init__.h" +#endif + #endif #include "tusb.h" @@ -174,6 +178,9 @@ void usb_background(void) { #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_VIDEO usb_video_task(); #endif + #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_AUDIO + usb_audio_task(); + #endif } } diff --git a/supervisor/shared/usb/usb_desc.c b/supervisor/shared/usb/usb_desc.c index 9427171fe9b..7a0bc4686bb 100644 --- a/supervisor/shared/usb/usb_desc.c +++ b/supervisor/shared/usb/usb_desc.c @@ -32,6 +32,10 @@ #include "shared-module/usb_video/__init__.h" #endif +#if CIRCUITPY_USB_AUDIO +#include "shared-module/usb_audio/__init__.h" +#endif + #include "shared-bindings/microcontroller/Processor.h" @@ -170,6 +174,12 @@ static bool usb_build_configuration_descriptor(void) { } #endif + #if CIRCUITPY_USB_AUDIO + if (usb_audio_enabled()) { + total_descriptor_length += usb_audio_descriptor_length(); + } + #endif + // Now we know how big the configuration descriptor will be, so we can allocate space for it. configuration_descriptor = (uint8_t *)port_malloc(total_descriptor_length, @@ -259,6 +269,13 @@ static bool usb_build_configuration_descriptor(void) { descriptor_buf_remaining, &descriptor_counts, ¤t_interface_string); } #endif + + #if CIRCUITPY_USB_AUDIO + if (usb_audio_enabled()) { + descriptor_buf_remaining += usb_audio_add_descriptor( + descriptor_buf_remaining, &descriptor_counts, ¤t_interface_string); + } + #endif // Now we know how many interfaces have been used. configuration_descriptor[CONFIG_NUM_INTERFACES_INDEX] = descriptor_counts.current_interface; diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index bce47353f57..23ae866242c 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -182,6 +182,18 @@ ifeq ($(CIRCUITPY_TINYUSB),1) CFLAGS += -DCFG_TUD_VIDEO=1 -DCFG_TUD_VIDEO_STREAMING=1 -DCFG_TUD_VIDEO_STREAMING_EP_BUFSIZE=256 -DCFG_TUD_VIDEO_STREAMING_BULK=1 endif + ifeq ($(CIRCUITPY_USB_AUDIO), 1) + SRC_SUPERVISOR += \ + shared-bindings/usb_audio/__init__.c \ + shared-module/usb_audio/__init__.c \ + shared-bindings/usb_audio/USBMicrophone.c \ + shared-module/usb_audio/USBMicrophone.c \ + lib/tinyusb/src/class/audio/audio_device.c \ + + # The CFG_TUD_AUDIO_* class driver settings are defined in + # supervisor/shared/usb/tusb_config.h, gated on CIRCUITPY_USB_AUDIO. + endif + ifeq ($(CIRCUITPY_USB_VENDOR), 1) SRC_SUPERVISOR += \ From 9e6bd5aad691e48ab44967692bb6a1419a89060f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 17 Jun 2026 11:46:44 -0400 Subject: [PATCH 563/876] fix IDF v6 support for cameras; need to update esp-camera before a PR on this --- ports/espressif/bindings/espcamera/Camera.c | 2 +- ports/espressif/common-hal/busio/I2C.c | 14 ++++++++++++++ ports/espressif/common-hal/busio/I2C.h | 1 + ports/espressif/common-hal/espcamera/Camera.c | 9 ++++++--- ports/espressif/esp-camera | 2 +- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ports/espressif/bindings/espcamera/Camera.c b/ports/espressif/bindings/espcamera/Camera.c index 712ff8827d7..9a74824a053 100644 --- a/ports/espressif/bindings/espcamera/Camera.c +++ b/ports/espressif/bindings/espcamera/Camera.c @@ -179,7 +179,7 @@ static void check_for_deinit(espcamera_camera_obj_t *self) { static mp_obj_t espcamera_camera_frame_available_get(const mp_obj_t self_in) { espcamera_camera_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - return mp_obj_new_bool(esp_camera_fb_available()); + return mp_obj_new_bool(common_hal_espcamera_camera_available(self)); } static MP_DEFINE_CONST_FUN_OBJ_1(espcamera_camera_frame_available_get_obj, espcamera_camera_frame_available_get); diff --git a/ports/espressif/common-hal/busio/I2C.c b/ports/espressif/common-hal/busio/I2C.c index 662633c638b..30f16276eae 100644 --- a/ports/espressif/common-hal/busio/I2C.c +++ b/ports/espressif/common-hal/busio/I2C.c @@ -10,6 +10,7 @@ #include "py/runtime.h" #include "driver/gpio.h" +#include "soc/soc_caps.h" #include "bindings/espidf/__init__.h" #include "shared-bindings/microcontroller/__init__.h" @@ -88,6 +89,19 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, } CHECK_ESP_RESULT(result); + // Record which port the auto-selected bus landed on. There is no public accessor to map + // a bus handle back to its port, so match the handle against each initialized port. + // Other code (e.g. espcamera) needs the port number to reuse this same bus rather than + // create a second master bus on the same pins. + self->port = -1; + for (i2c_port_num_t port = 0; port < (int)SOC_HP_I2C_NUM; port++) { + i2c_master_bus_handle_t bus_handle; + if (i2c_master_get_bus_handle(port, &bus_handle) == ESP_OK && bus_handle == self->handle) { + self->port = port; + break; + } + } + self->xSemaphore = xSemaphoreCreateMutex(); if (self->xSemaphore == NULL) { i2c_del_master_bus(self->handle); diff --git a/ports/espressif/common-hal/busio/I2C.h b/ports/espressif/common-hal/busio/I2C.h index 52674e336e2..ef69cba7091 100644 --- a/ports/espressif/common-hal/busio/I2C.h +++ b/ports/espressif/common-hal/busio/I2C.h @@ -22,6 +22,7 @@ typedef struct { size_t timeout_ms; size_t frequency; i2c_master_bus_handle_t handle; + i2c_port_num_t port; SemaphoreHandle_t xSemaphore; bool has_lock; } busio_i2c_obj_t; diff --git a/ports/espressif/common-hal/espcamera/Camera.c b/ports/espressif/common-hal/espcamera/Camera.c index e7d91febbfa..80111311bb7 100644 --- a/ports/espressif/common-hal/espcamera/Camera.c +++ b/ports/espressif/common-hal/espcamera/Camera.c @@ -86,8 +86,11 @@ void common_hal_espcamera_camera_construct( self->camera_config.pin_reset = reset_pin ? common_hal_mcu_pin_number(reset_pin) : NO_PIN; self->camera_config.pin_xclk = external_clock_pin ? common_hal_mcu_pin_number(external_clock_pin) : NO_PIN; - self->camera_config.pin_sccb_sda = common_hal_mcu_pin_number(i2c->sda_pin); - self->camera_config.pin_sccb_scl = common_hal_mcu_pin_number(i2c->scl_pin); + // Reuse the I2C bus that CircuitPython already created on these pins instead of letting + // esp32-camera create a second master bus on the same pins, which doesn't work. + self->camera_config.pin_sccb_sda = -1; + self->camera_config.pin_sccb_scl = -1; + self->camera_config.sccb_i2c_port = i2c->port; self->camera_config.pin_d7 = data_pins[7]; self->camera_config.pin_d6 = data_pins[6]; @@ -154,7 +157,7 @@ bool common_hal_espcamera_camera_deinited(espcamera_camera_obj_t *self) { } bool common_hal_espcamera_camera_available(espcamera_camera_obj_t *self) { - return esp_camera_fb_available(); + return esp_camera_available_frames(); } camera_fb_t *common_hal_espcamera_camera_take(espcamera_camera_obj_t *self, int timeout_ms) { diff --git a/ports/espressif/esp-camera b/ports/espressif/esp-camera index 015eb6534c4..1ba022bcf47 160000 --- a/ports/espressif/esp-camera +++ b/ports/espressif/esp-camera @@ -1 +1 @@ -Subproject commit 015eb6534c4efa406aa90e5b9f4752ef71af0d25 +Subproject commit 1ba022bcf472b509444276045a3b6538fb1d1ce8 From 22fd04d158349405bbba3e4a88bacfae90ac2cab Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 18 Jun 2026 12:32:10 -0400 Subject: [PATCH 564/876] update esp32-camera submodule --- ports/espressif/esp-camera | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/esp-camera b/ports/espressif/esp-camera index 1ba022bcf47..303985ab678 160000 --- a/ports/espressif/esp-camera +++ b/ports/espressif/esp-camera @@ -1 +1 @@ -Subproject commit 1ba022bcf472b509444276045a3b6538fb1d1ce8 +Subproject commit 303985ab678391b78ebe0baff98edcc863f296c2 From a61d548cd54132cfead7a19263eba7c7a6a57071 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Fri, 19 Jun 2026 16:45:55 +0200 Subject: [PATCH 565/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 13 +++++++++---- locale/el.po | 13 +++++++++---- locale/hi.po | 13 +++++++++---- locale/ko.po | 13 +++++++++---- locale/ru.po | 13 +++++++++---- locale/tr.po | 13 +++++++++---- 6 files changed, 54 insertions(+), 24 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 9a0c478cc2d..3e64021b216 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -791,9 +791,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "Nelze nastavit CCCD na místní charakteristiku" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c msgid "Cannot change USB devices now" msgstr "Nelze změnit USB zařízení" @@ -1706,6 +1706,7 @@ msgstr "Nepřipojený" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c #: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "Nehraje" @@ -2171,7 +2172,7 @@ msgstr "Výše uvedená výjimka byla přímá příčina následující výjimk msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "Počet prvků rgb_pin musí být 6, 12, 18, 24, nebo 30" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2294,6 +2295,10 @@ msgstr "Zápis na UART" msgid "UID:" msgstr "UID:" +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "USB audio not enabled in boot.py" +msgstr "" + #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "USB zaneprázdněno" diff --git a/locale/el.po b/locale/el.po index 3bb156d02d2..052d61e489b 100644 --- a/locale/el.po +++ b/locale/el.po @@ -793,9 +793,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "Δεν μπορεί να οριστεί CCCD σε τοπικό Characteristic" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c msgid "Cannot change USB devices now" msgstr "Δεν μπορούν να αλλάξουν οι USB συσκευές τώρα" @@ -1712,6 +1712,7 @@ msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c #: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "" @@ -2176,7 +2177,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2298,6 +2299,10 @@ msgstr "" msgid "UID:" msgstr "" +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "USB audio not enabled in boot.py" +msgstr "" + #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index a9f0e14fbb0..428a68ae748 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -777,9 +777,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c msgid "Cannot change USB devices now" msgstr "" @@ -1688,6 +1688,7 @@ msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c #: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "" @@ -2150,7 +2151,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2272,6 +2273,10 @@ msgstr "" msgid "UID:" msgstr "UID:" +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "USB audio not enabled in boot.py" +msgstr "" + #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index a2a2b15e647..9eff441710f 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -819,9 +819,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "로컬 특성에 CCCD를 설정할 수 없습니다" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c msgid "Cannot change USB devices now" msgstr "현재 USB 디바이스를 변경할 수 없습니다" @@ -1746,6 +1746,7 @@ msgstr "연결되지 않았습니다" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c #: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "재생되지 않았습니다" @@ -2223,7 +2224,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2345,6 +2346,10 @@ msgstr "" msgid "UID:" msgstr "UID:" +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "USB audio not enabled in boot.py" +msgstr "" + #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 4e972e31931..1ec1233fcff 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -796,9 +796,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "Невозможно установить CCCD для локальной характеристики" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c msgid "Cannot change USB devices now" msgstr "Невозможно изменить USB устройство сейчас" @@ -1729,6 +1729,7 @@ msgstr "Не подключено" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c #: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "Не воспроизводится (Not playing)" @@ -2204,7 +2205,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "Длина rgb_pins должна быть 6, 12, 18, 24 или 30" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "%q образца не совпадает" @@ -2328,6 +2329,10 @@ msgstr "Запись UART" msgid "UID:" msgstr "UID:" +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "USB audio not enabled in boot.py" +msgstr "" + #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "USB занят" diff --git a/locale/tr.po b/locale/tr.po index c99e56326af..60370c5fa56 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -790,9 +790,9 @@ msgstr "" msgid "Can't set CCCD on local Characteristic" msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_cdc/__init__.c -#: shared-bindings/usb_hid/__init__.c shared-bindings/usb_midi/__init__.c -#: shared-bindings/usb_video/__init__.c +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c msgid "Cannot change USB devices now" msgstr "USB aygıtları şu an değiştirilemez" @@ -1707,6 +1707,7 @@ msgstr "" #: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c #: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c msgid "Not playing" msgstr "" @@ -2172,7 +2173,7 @@ msgstr "" msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: shared-module/audiocore/__init__.c +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c msgid "The sample's %q does not match" msgstr "" @@ -2294,6 +2295,10 @@ msgstr "" msgid "UID:" msgstr "UID:" +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "USB audio not enabled in boot.py" +msgstr "" + #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" From 5eedac91be696b13470b03aa747261ead441bd69 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 19 Jun 2026 12:04:17 -0500 Subject: [PATCH 566/876] usb_audio.USBSpeaker class and enable for nordic --- locale/circuitpython.pot | 9 + ports/nordic/mpconfigport.mk | 10 + shared-bindings/usb_audio/Direction.c | 51 ++++ shared-bindings/usb_audio/Direction.h | 20 ++ shared-bindings/usb_audio/USBSpeaker.c | 193 +++++++++++++++ shared-bindings/usb_audio/USBSpeaker.h | 17 ++ shared-bindings/usb_audio/__init__.c | 46 +++- shared-module/usb_audio/USBSpeaker.c | 226 ++++++++++++++++++ shared-module/usb_audio/USBSpeaker.h | 73 ++++++ shared-module/usb_audio/__init__.c | 131 +++++++++- shared-module/usb_audio/__init__.h | 13 +- .../usb_audio/usb_audio_descriptors.h | 39 ++- supervisor/shared/usb/tusb_config.h | 20 +- supervisor/supervisor.mk | 3 + 14 files changed, 833 insertions(+), 18 deletions(-) create mode 100644 shared-bindings/usb_audio/Direction.c create mode 100644 shared-bindings/usb_audio/Direction.h create mode 100644 shared-bindings/usb_audio/USBSpeaker.c create mode 100644 shared-bindings/usb_audio/USBSpeaker.h create mode 100644 shared-module/usb_audio/USBSpeaker.c create mode 100644 shared-module/usb_audio/USBSpeaker.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index fa088fdda5e..4cfc7ff1f44 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -2271,7 +2271,12 @@ msgstr "" msgid "UID:" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "USB audio not enabled for output in boot.py" +msgstr "" + #: shared-bindings/usb_audio/USBMicrophone.c +#: shared-bindings/usb_audio/USBSpeaker.c msgid "USB audio not enabled in boot.py" msgstr "" @@ -3117,6 +3122,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index 48536ec2acd..c243d54a707 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -9,6 +9,15 @@ CIRCUITPY_BUILD_EXTENSIONS ?= uf2 # Number of USB endpoint pairs. USB_NUM_ENDPOINT_PAIRS = 8 +# The nRF52 USBD implements isochronous transfers only on the fixed, dedicated +# endpoint number 8 (EP_ISO_NUM in TinyUSB's dcd_nrf5x.c); dcd_edpt_open() rejects +# an ISO endpoint on any other number, so a usb_audio mic/speaker placed on a +# sequentially-allocated endpoint would enumerate but never transfer data. Force +# the usb_audio isochronous endpoint onto endpoint 8. (Only read by usb_audio +# code, so it is harmless when CIRCUITPY_USB_AUDIO is off; defined unconditionally +# to stay independent of where that flag gets set in the include order.) +CFLAGS += -DUSB_AUDIO_ISO_EP_NUM=8 + # All nRF ports have longints. LONGINT_IMPL = MPZ @@ -48,6 +57,7 @@ CIRCUITPY_SERIAL_BLE ?= 1 CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE ?= 1 +CIRCUITPY_USB_AUDIO ?= 1 # nRF52840-specific diff --git a/shared-bindings/usb_audio/Direction.c b/shared-bindings/usb_audio/Direction.c new file mode 100644 index 00000000000..1dbe17c11aa --- /dev/null +++ b/shared-bindings/usb_audio/Direction.c @@ -0,0 +1,51 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include "py/obj.h" +#include "py/enum.h" +#include "py/runtime.h" + +#include "shared-bindings/usb_audio/Direction.h" + +MAKE_ENUM_VALUE(usb_audio_direction_type, direction, INPUT, USB_AUDIO_DIRECTION_INPUT); +MAKE_ENUM_VALUE(usb_audio_direction_type, direction, OUTPUT, USB_AUDIO_DIRECTION_OUTPUT); +MAKE_ENUM_VALUE(usb_audio_direction_type, direction, INPUT_OUTPUT, USB_AUDIO_DIRECTION_INPUT_OUTPUT); + +//| class Direction: +//| """The direction of a USB audio stream, relative to the host computer.""" +//| +//| def __init__(self) -> None: +//| """Enum-like class to define the USB audio stream direction.""" +//| ... +//| +//| INPUT: Direction +//| """Audio flows board -> host: the board appears as a USB microphone +//| (audio *source*). This is the default.""" +//| +//| OUTPUT: Direction +//| """Audio flows host -> board: the board appears as a USB speaker +//| (audio *sink*).""" +//| +//| INPUT_OUTPUT: Direction +//| """Audio flows in both directions: the board appears as a USB headset +//| (microphone + speaker).""" +//| +//| +MAKE_ENUM_MAP(usb_audio_direction) { + MAKE_ENUM_MAP_ENTRY(direction, INPUT), + MAKE_ENUM_MAP_ENTRY(direction, OUTPUT), + MAKE_ENUM_MAP_ENTRY(direction, INPUT_OUTPUT), +}; + +static MP_DEFINE_CONST_DICT(usb_audio_direction_locals_dict, usb_audio_direction_locals_table); + +MAKE_PRINTER(usb_audio, usb_audio_direction); + +MAKE_ENUM_TYPE(usb_audio, Direction, usb_audio_direction); + +usb_audio_direction_t validate_direction(mp_obj_t obj, qstr arg_name) { + return cp_enum_value(&usb_audio_direction_type, obj, arg_name); +} diff --git a/shared-bindings/usb_audio/Direction.h b/shared-bindings/usb_audio/Direction.h new file mode 100644 index 00000000000..53ad3be16c4 --- /dev/null +++ b/shared-bindings/usb_audio/Direction.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/enum.h" +#include "py/obj.h" + +typedef enum _usb_audio_direction_t { + USB_AUDIO_DIRECTION_INPUT, + USB_AUDIO_DIRECTION_OUTPUT, + USB_AUDIO_DIRECTION_INPUT_OUTPUT, +} usb_audio_direction_t; + +extern const mp_obj_type_t usb_audio_direction_type; + +usb_audio_direction_t validate_direction(mp_obj_t obj, qstr arg_name); diff --git a/shared-bindings/usb_audio/USBSpeaker.c b/shared-bindings/usb_audio/USBSpeaker.c new file mode 100644 index 00000000000..7df8cf5798d --- /dev/null +++ b/shared-bindings/usb_audio/USBSpeaker.c @@ -0,0 +1,193 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/usb_audio/USBSpeaker.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/util.h" +#include "shared-module/usb_audio/__init__.h" + +//| class USBSpeaker: +//| """Plays audio streamed from the host computer as a USB Audio Class speaker. +//| +//| A ``USBSpeaker`` is a *source* of audio samples, exactly like +//| `audiocore.RawSample` or `audiocore.WaveFile`. The host PC streams audio to +//| the board over USB, and the ``USBSpeaker`` hands that audio to a consumer +//| such as `audiobusio.I2SOut`, `audiopwmio.PWMAudioOut` or `audioio.AudioOut` +//| (optionally through the effect modules), so the board appears as a speaker. +//| +//| ``usb_audio.enable(direction=usb_audio.Direction.OUTPUT)`` must have been +//| called in ``boot.py`` before this object can be constructed. +//| +//| .. code-block:: py +//| +//| # boot.py +//| import usb_audio +//| usb_audio.enable(sample_rate=16000, channel_count=1, bits_per_sample=16, +//| direction=usb_audio.Direction.OUTPUT) +//| +//| .. code-block:: py +//| +//| # code.py +//| import board +//| import usb_audio +//| import audiobusio +//| +//| spk = usb_audio.USBSpeaker() +//| out = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) +//| out.play(spk, loop=True) +//| +//| """ +//| +//| def __init__(self) -> None: +//| """Create a USBSpeaker using the audio format configured in ``boot.py``.""" +//| ... +//| +static mp_obj_t usb_audio_usbspeaker_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + static const mp_arg_t allowed_args[] = {}; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // The audio format and USB interface are claimed by usb_audio.enable() in + // boot.py. Without it there is no speaker for the host to play to. + if (!usb_audio_enabled()) { + mp_raise_RuntimeError(MP_ERROR_TEXT("USB audio not enabled in boot.py")); + } + // A USBSpeaker only makes sense when the OUT endpoint is enumerated. + if (usb_audio_direction != USB_AUDIO_DIRECTION_OUTPUT && + usb_audio_direction != USB_AUDIO_DIRECTION_INPUT_OUTPUT) { + mp_raise_RuntimeError(MP_ERROR_TEXT("USB audio not enabled for output in boot.py")); + } + + usb_audio_usbspeaker_obj_t *self = mp_obj_malloc_with_finaliser(usb_audio_usbspeaker_obj_t, &usb_audio_USBSpeaker_type); + common_hal_usb_audio_usbspeaker_construct(self); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the USBSpeaker and releases any resources for reuse.""" +//| ... +//| +static mp_obj_t usb_audio_usbspeaker_deinit(mp_obj_t self_in) { + usb_audio_usbspeaker_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_usb_audio_usbspeaker_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbspeaker_deinit_obj, usb_audio_usbspeaker_deinit); + +static void check_for_deinit(usb_audio_usbspeaker_obj_t *self) { + audiosample_check_for_deinit(&self->base); +} + +//| def read(self, destination: circuitpython_typing.WriteableBuffer, destination_length: int) -> int: +//| """Copies up to ``destination_length`` of the most recent samples streamed +//| from the host into ``destination``, for analysis such as an audio-reactive +//| effect or VU meter. This does not block: it returns whatever the host has +//| delivered so far, which may be fewer than ``destination_length`` samples +//| (or zero when the host is not streaming). +//| +//| ``destination`` must be an ``array.array`` of 16-bit signed samples +//| (typecode ``"h"``), matching the negotiated speaker format. +//| +//| Reading consumes the samples, so a ``USBSpeaker`` being read this way +//| should not also be passed to an output backend's ``play()`` at the same +//| time. +//| +//| :return: The number of samples copied into ``destination``.""" +//| ... +//| +static mp_obj_t usb_audio_usbspeaker_obj_read(mp_obj_t self_in, mp_obj_t destination, mp_obj_t destination_length) { + usb_audio_usbspeaker_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + uint32_t length = mp_arg_validate_type_int(destination_length, MP_QSTR_length); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(destination, &bufinfo, MP_BUFFER_WRITE); + // The negotiated speaker format is 16-bit signed PCM, so require a matching + // 'h' array. This keeps the copy a straight memcpy with no conversion. + if (bufinfo.typecode != 'h') { + mp_raise_TypeError(MP_ERROR_TEXT("destination must be an array of type 'h'")); + } + size_t capacity = bufinfo.len / sizeof(int16_t); + if (capacity < length) { + length = capacity; + } + + uint32_t length_read = common_hal_usb_audio_usbspeaker_read(self, bufinfo.buf, length); + return MP_OBJ_NEW_SMALL_INT(length_read); +} +static MP_DEFINE_CONST_FUN_OBJ_3(usb_audio_usbspeaker_read_obj, usb_audio_usbspeaker_obj_read); + +//| def __enter__(self) -> USBSpeaker: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes the hardware when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| connected: bool +//| """True while the host is streaming audio to this speaker. (read-only)""" +//| +//| +static mp_obj_t usb_audio_usbspeaker_obj_get_connected(mp_obj_t self_in) { + usb_audio_usbspeaker_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_usb_audio_usbspeaker_get_connected(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(usb_audio_usbspeaker_get_connected_obj, usb_audio_usbspeaker_obj_get_connected); + +MP_PROPERTY_GETTER(usb_audio_usbspeaker_connected_obj, + (mp_obj_t)&usb_audio_usbspeaker_get_connected_obj); + +//| sample_rate: int +//| """The sample rate negotiated with the host in ``boot.py``. (read-only)""" +//| +//| bits_per_sample: int +//| """The bit depth negotiated with the host in ``boot.py``. (read-only)""" +//| +//| channel_count: int +//| """The number of channels negotiated with the host in ``boot.py``. (read-only)""" +//| +//| +static const mp_rom_map_elem_t usb_audio_usbspeaker_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&usb_audio_usbspeaker_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&usb_audio_usbspeaker_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&usb_audio_usbspeaker_read_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_connected), MP_ROM_PTR(&usb_audio_usbspeaker_connected_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(usb_audio_usbspeaker_locals_dict, usb_audio_usbspeaker_locals_dict_table); + +static const audiosample_p_t usb_audio_usbspeaker_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)usb_audio_usbspeaker_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)usb_audio_usbspeaker_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + usb_audio_USBSpeaker_type, + MP_QSTR_USBSpeaker, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, usb_audio_usbspeaker_make_new, + locals_dict, &usb_audio_usbspeaker_locals_dict, + protocol, &usb_audio_usbspeaker_proto + ); diff --git a/shared-bindings/usb_audio/USBSpeaker.h b/shared-bindings/usb_audio/USBSpeaker.h new file mode 100644 index 00000000000..30d2b0862a3 --- /dev/null +++ b/shared-bindings/usb_audio/USBSpeaker.h @@ -0,0 +1,17 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/usb_audio/USBSpeaker.h" + +extern const mp_obj_type_t usb_audio_USBSpeaker_type; + +void common_hal_usb_audio_usbspeaker_construct(usb_audio_usbspeaker_obj_t *self); +void common_hal_usb_audio_usbspeaker_deinit(usb_audio_usbspeaker_obj_t *self); +bool common_hal_usb_audio_usbspeaker_deinited(usb_audio_usbspeaker_obj_t *self); +bool common_hal_usb_audio_usbspeaker_get_connected(usb_audio_usbspeaker_obj_t *self); +uint32_t common_hal_usb_audio_usbspeaker_read(usb_audio_usbspeaker_obj_t *self, void *buffer, uint32_t length); diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index d6b5e15f02e..027dc1fa92c 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -8,7 +8,9 @@ #include "py/runtime.h" #include "shared-bindings/usb_audio/__init__.h" +#include "shared-bindings/usb_audio/Direction.h" #include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-bindings/usb_audio/USBSpeaker.h" #include "shared-module/usb_audio/__init__.h" #include "shared-module/usb_audio/usb_audio_descriptors.h" @@ -36,36 +38,61 @@ //| .. code-block:: py //| //| # code.py +//| import time //| import usb_audio //| import synthio //| +//| # A USBMicrophone is a consumer of an audio sample, just like audioio.AudioOut: +//| # the samples it pulls are streamed to the host PC instead of to a pin. //| mic = usb_audio.USBMicrophone() //| synth = synthio.Synthesizer(sample_rate=16000, channel_count=1) //| mic.play(synth, loop=True) -//| synth.press(60) //| -//| """ +//| c_major_scale = [60, 62, 64, 65, 67, 69, 71, 72] +//| try: +//| while True: +//| for note in c_major_scale: +//| synth.press(note) +//| time.sleep(0.1) +//| synth.release(note) +//| time.sleep(0.05) +//| except KeyboardInterrupt: +//| pass +//| mic.stop() +//| +//| The ``sample_rate`` and ``channel_count`` of the sample played must match the +//| values passed to `enable`, and the sample must be 16-bit signed; otherwise +//| ``play`` raises a ``ValueError``. +//| +//| This interface is experimental and may change without notice even in stable +//| versions of CircuitPython.""" //| //| //| def enable( -//| sample_rate: int = 16000, channel_count: int = 1, bits_per_sample: int = 16 +//| sample_rate: int = 16000, +//| channel_count: int = 1, +//| bits_per_sample: int = 16, +//| direction: Direction = Direction.INPUT, //| ) -> None: -//| """Enable the USB audio microphone interface with the given PCM format. +//| """Enable the USB audio interface with the given PCM format. //| //| This function may only be used from ``boot.py``. //| //| :param int sample_rate: Samples per second of the streamed audio. //| :param int channel_count: Number of channels. Only mono (1) is supported initially. -//| :param int bits_per_sample: Bits per signed PCM sample. Only 16 is supported initially.""" +//| :param int bits_per_sample: Bits per signed PCM sample. Only 16 is supported initially. +//| :param Direction direction: Stream direction relative to the host. ``Direction.INPUT`` +//| (the default) presents a microphone; ``Direction.OUTPUT`` presents a speaker.""" //| //| static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample_rate, ARG_channel_count, ARG_bits_per_sample }; + enum { ARG_sample_rate, ARG_channel_count, ARG_bits_per_sample, ARG_direction }; static const mp_arg_t allowed_args[] = { { MP_QSTR_sample_rate, MP_ARG_INT, { .u_int = 16000 } }, { MP_QSTR_channel_count, MP_ARG_INT, { .u_int = 1 } }, { MP_QSTR_bits_per_sample, MP_ARG_INT, { .u_int = 16 } }, + { MP_QSTR_direction, MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -73,8 +100,11 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map mp_int_t sample_rate = mp_arg_validate_int_range(args[ARG_sample_rate].u_int, 1, USB_AUDIO_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_N_CHANNELS, MP_QSTR_channel_count); mp_int_t bits_per_sample = mp_arg_validate_int(args[ARG_bits_per_sample].u_int, USB_AUDIO_BITS_PER_SAMPLE, MP_QSTR_bits_per_sample); + usb_audio_direction_t direction = args[ARG_direction].u_obj == MP_OBJ_NULL + ? USB_AUDIO_DIRECTION_INPUT + : validate_direction(args[ARG_direction].u_obj, MP_QSTR_direction); - if (!shared_module_usb_audio_enable(sample_rate, channel_count, bits_per_sample)) { + if (!shared_module_usb_audio_enable(sample_rate, channel_count, bits_per_sample, direction)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot change USB devices now")); } @@ -84,7 +114,9 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(usb_audio_enable_obj, 0, usb_audio_enable); static const mp_rom_map_elem_t usb_audio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_audio) }, + { MP_ROM_QSTR(MP_QSTR_Direction), MP_ROM_PTR(&usb_audio_direction_type) }, { MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_ROM_PTR(&usb_audio_USBMicrophone_type) }, + { MP_ROM_QSTR(MP_QSTR_USBSpeaker), MP_ROM_PTR(&usb_audio_USBSpeaker_type) }, { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&usb_audio_enable_obj) }, }; diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c new file mode 100644 index 00000000000..ec21f7457f0 --- /dev/null +++ b/shared-module/usb_audio/USBSpeaker.c @@ -0,0 +1,226 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/misc.h" + +#include "shared-bindings/usb_audio/USBSpeaker.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-bindings/microcontroller/__init__.h" +#include "shared-module/usb_audio/__init__.h" + +#include "tusb.h" + +// The ring is sized independently of the TinyUSB headers (see USBSpeaker.h); +// check it still matches the OUT endpoint's software FIFO so the push side can be +// reasoned about against the USB plumbing. +MP_STATIC_ASSERT(USB_AUDIO_SPEAKER_RING_SIZE == CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); + +// Only one speaker can be fed by the single USB OUT endpoint at a time. This +// points at the most recently constructed USBSpeaker, or NULL when none exists, +// mirroring active_microphone in USBMicrophone.c. The USB background task pushes +// received bytes into it via usb_audio_usbspeaker_background_drain(). +static usb_audio_usbspeaker_obj_t *active_speaker = NULL; + +void common_hal_usb_audio_usbspeaker_construct(usb_audio_usbspeaker_obj_t *self) { + // The pipeline treats the speaker as an ordinary audiosample source, so + // populate base from the format negotiated by usb_audio.enable(). The UAC2 + // format we present is 16-bit signed LE PCM, which is exactly what the + // CircuitPython audio pipeline carries, so no conversion is needed. + self->base.sample_rate = usb_audio_sample_rate; + self->base.bits_per_sample = usb_audio_bits_per_sample; + self->base.channel_count = usb_audio_channel_count; + self->base.samples_signed = true; + self->base.single_buffer = false; + self->base.max_buffer_length = USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE; + + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + self->output_index = 0; + + // The most recently created speaker receives the host's OUT stream. + active_speaker = self; +} + +void common_hal_usb_audio_usbspeaker_deinit(usb_audio_usbspeaker_obj_t *self) { + // Stop directing USB OUT data at this object. The producer (drain) and this + // deinit both run in non-interrupt context, so the pointer swap needs no + // interrupt guard. + if (active_speaker == self) { + active_speaker = NULL; + } + audiosample_mark_deinit(&self->base); +} + +bool common_hal_usb_audio_usbspeaker_deinited(usb_audio_usbspeaker_obj_t *self) { + return audiosample_deinited(&self->base); +} + +bool common_hal_usb_audio_usbspeaker_get_connected(usb_audio_usbspeaker_obj_t *self) { + (void)self; + // True while the host has opened the OUT streaming interface, i.e. it is + // actively sending audio. + return usb_audio_streaming(); +} + +// --------------------------------------------------------------------+ +// Receive ring (push side, producer = USB background task) +// --------------------------------------------------------------------+ +// +// The ring decouples the two independently clocked stages from +// usb_audio_output_plan.md: USB push (paced by the host's SOF clock, in the +// background task) and the audiosample pull (paced by the output backend's +// sample clock, in its refill interrupt). It is a single-producer/ +// single-consumer ring across an interrupt boundary: +// +// * Producer: usb_audio_usbspeaker_background_drain(), task context. +// * Consumer: usb_audio_usbspeaker_get_buffer(), output DMA/refill ISR. +// +// The consumer is an interrupt, so it can never be preempted by the producer and +// needs no guard of its own. The producer can be preempted by the consumer, and +// its drop-oldest overrun handling touches both cursors, so it does its whole +// read-modify-write with interrupts disabled. + +void usb_audio_usbspeaker_streaming_reset(void) { + usb_audio_usbspeaker_obj_t *self = active_speaker; + if (self == NULL) { + return; + } + common_hal_mcu_disable_interrupts(); + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + common_hal_mcu_enable_interrupts(); +} + +void usb_audio_usbspeaker_background_drain(const uint8_t *in, size_t n) { + usb_audio_usbspeaker_obj_t *self = active_speaker; + if (self == NULL || n == 0) { + return; + } + if (n >= USB_AUDIO_SPEAKER_RING_SIZE) { + // A single chunk larger than the whole ring can only contribute its + // newest tail. (Cannot happen with USB packets << ring size, but keep + // the copies provably in-bounds.) + in += n - USB_AUDIO_SPEAKER_RING_SIZE; + n = USB_AUDIO_SPEAKER_RING_SIZE; + } + + common_hal_mcu_disable_interrupts(); + + size_t free_space = USB_AUDIO_SPEAKER_RING_SIZE - self->ring_count; + if (n > free_space) { + // Overrun: advance the read cursor past the oldest bytes we're about to + // overwrite, keeping latency bounded and following the newest host audio. + size_t drop = n - free_space; + self->ring_tail = (self->ring_tail + drop) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count -= drop; + } + + // Copy in one or two segments, wrapping at the end of the ring. + size_t first = MIN(n, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_head); + memcpy(&self->ring[self->ring_head], in, first); + if (n > first) { + memcpy(&self->ring[0], in + first, n - first); + } + self->ring_head = (self->ring_head + n) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count += n; + + common_hal_mcu_enable_interrupts(); +} + +uint32_t common_hal_usb_audio_usbspeaker_read(usb_audio_usbspeaker_obj_t *self, + void *buffer, uint32_t length) { + // Hand the most recent host audio to Python so it can be analysed (e.g. an + // audio-reactive effect or VU meter). This drains the ring just like the + // output backend's get_buffer() does, so it is an alternative *consumer*: + // a USBSpeaker being read this way must not also be play()ed to an output + // backend at the same time, or the two consumers would race on the single + // SPSC ring. + // + // Unlike get_buffer() (which runs in the output refill ISR and so needs no + // guard) this runs in VM/task context and can be preempted by the USB + // producer, so it brackets its read-modify-write with interrupts disabled, + // mirroring usb_audio_usbspeaker_background_drain(). + size_t bytes_per_frame = (self->base.bits_per_sample / 8) * self->base.channel_count; + size_t want = (size_t)length * bytes_per_frame; + + common_hal_mcu_disable_interrupts(); + size_t to_copy = MIN(self->ring_count, want); + // Never split a frame across calls (the ring always holds whole UAC2 frames, + // but stay defensive so the returned count is always a whole number). + to_copy -= to_copy % bytes_per_frame; + + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + memcpy(buffer, &self->ring[self->ring_tail], first); + if (to_copy > first) { + memcpy((uint8_t *)buffer + first, &self->ring[0], to_copy - first); + } + self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count -= to_copy; + common_hal_mcu_enable_interrupts(); + + return to_copy / bytes_per_frame; +} + +// --------------------------------------------------------------------+ +// audiosample protocol (pull side, consumer = output backend) +// --------------------------------------------------------------------+ + +void usb_audio_usbspeaker_reset_buffer(usb_audio_usbspeaker_obj_t *self, + bool single_channel_output, uint8_t channel) { + (void)single_channel_output; + (void)channel; + // Begin playback from live audio rather than whatever was buffered before: + // drop the ring and restart the double-buffer. Guarded because some ports may + // call reset_buffer outside the initial setup. + common_hal_mcu_disable_interrupts(); + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + common_hal_mcu_enable_interrupts(); + self->output_index = 0; +} + +audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker_obj_t *self, + bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { + + uint32_t half = self->base.max_buffer_length / 2; + uint8_t *out = self->output_buffer + half * self->output_index; + self->output_index = 1 - self->output_index; + + // Consumer side of the SPSC ring (runs in the output backend's refill ISR). + // It is never preempted by the producer, so no interrupt guard is required. + size_t to_copy = MIN(self->ring_count, (size_t)half); + + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + memcpy(out, &self->ring[self->ring_tail], first); + if (to_copy > first) { + memcpy(out + first, &self->ring[0], to_copy - first); + } + self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_count -= to_copy; + + if (to_copy < half) { + // Underrun: pad the remainder with silence. Samples are signed, so + // silence is 0. This is the consume-side of the pacing failure mode + // tracked in the usb-audio-artifact-pacing memory: we never spin. + memset(out + to_copy, 0, half - to_copy); + } + + // Mono only for v1, so the single-channel offset is always 0; computed the + // same way as audiocore.RawSample so stereo (interleaved ring) can extend it. + if (single_channel_output) { + out += (channel % self->base.channel_count) * (self->base.bits_per_sample / 8); + } + + *buffer = out; + *buffer_length = half; + // A live USB stream is infinite; never report DONE or the backend would stop. + return GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/usb_audio/USBSpeaker.h b/shared-module/usb_audio/USBSpeaker.h new file mode 100644 index 00000000000..8c06cff519d --- /dev/null +++ b/shared-module/usb_audio/USBSpeaker.h @@ -0,0 +1,73 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" + +// One half-buffer of the audiosample double-buffer holds this many frames. The +// output backend pulls a half each get_buffer() call, so this sets the pull +// granularity and the silence-pad chunk on underrun. It is deliberately +// independent of the USB OUT software FIFO (the ring below) so the push and pull +// stages can be tuned separately, and small enough that two halves sit +// comfortably inside the ring. +#define USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER (128) + +// Bytes per audio frame in the negotiated UAC2 format (mono 16-bit for v1). +#define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) + +// Full owned double-buffer: two halves of FRAMES_PER_BUFFER frames each. Matches +// audiocore.RawSample's convention where base.max_buffer_length is the whole +// buffer and get_buffer() returns half of it. +#define USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE (2 * USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER * USB_AUDIO_SPEAKER_BYTES_PER_FRAME) + +// Host -> board receive ring size. Mirrors CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ +// (16 * the full-speed OUT wMaxPacketSize) but is spelled out from the format +// constants so this struct definition stays free of the TinyUSB headers. A +// MP_STATIC_ASSERT in USBSpeaker.c checks the two stay equal. +#define USB_AUDIO_SPEAKER_OUT_PACKET_SIZE ((USB_AUDIO_MAX_SAMPLE_RATE / 1000 + 1) * USB_AUDIO_SPEAKER_BYTES_PER_FRAME) +#define USB_AUDIO_SPEAKER_RING_SIZE (16 * USB_AUDIO_SPEAKER_OUT_PACKET_SIZE) + +typedef struct usb_audio_usbspeaker_obj { + // First member so the object can be used directly as an audiosample source. + audiosample_base_t base; + + // Host -> board receive ring (the "push" stage). Filled by the USB + // background task via usb_audio_usbspeaker_background_drain() and drained by + // get_buffer(). Single producer (task), single consumer (output DMA ISR); + // see the concurrency notes in USBSpeaker.c. + uint8_t ring[USB_AUDIO_SPEAKER_RING_SIZE]; + size_t ring_head; // next write offset + size_t ring_tail; // next read offset + size_t ring_count; // valid bytes currently in the ring + + // Owned double-buffer returned to the output backend by get_buffer(). + uint8_t output_buffer[USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE]; + uint8_t output_index; // 0 or 1: which half get_buffer() fills next +} usb_audio_usbspeaker_obj_t; + +// audiosample protocol implementation. Not exposed to Python because get_buffer() +// runs in the output backend's refill interrupt. +void usb_audio_usbspeaker_reset_buffer(usb_audio_usbspeaker_obj_t *self, + bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker_obj_t *self, + bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length); + +// Push n bytes received on the USB OUT endpoint into the active speaker's ring. +// Called from the USB background task (see usb_audio_task()). No-op when no +// speaker is active. Overrun policy: drop the oldest buffered bytes. +void usb_audio_usbspeaker_background_drain(const uint8_t *in, size_t n); + +// Drop anything buffered in the active speaker's ring so a (re)opened stream +// starts from live audio. Called when the host opens/closes the OUT streaming +// interface. +void usb_audio_usbspeaker_streaming_reset(void); diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 1ce2c6691fd..d4e1ae6dd6d 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -6,10 +6,12 @@ #include "shared-module/usb_audio/__init__.h" #include "shared-module/usb_audio/USBMicrophone.h" +#include "shared-module/usb_audio/USBSpeaker.h" #include "shared-module/usb_audio/usb_audio_descriptors.h" #include +#include "py/misc.h" #include "tusb.h" static bool usb_audio_is_enabled = false; @@ -18,12 +20,13 @@ static bool usb_audio_is_streaming = false; uint32_t usb_audio_sample_rate; uint8_t usb_audio_channel_count; uint8_t usb_audio_bits_per_sample; +usb_audio_direction_t usb_audio_direction; // Audio control state surfaced to the host. One extra entry for the master channel 0. static int8_t usb_audio_mute[USB_AUDIO_N_CHANNELS + 1]; static int16_t usb_audio_volume[USB_AUDIO_N_CHANNELS + 1]; -bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample) { +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, usb_audio_direction_t direction) { if (tud_connected()) { return false; } @@ -31,6 +34,7 @@ bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count usb_audio_sample_rate = sample_rate; usb_audio_channel_count = channel_count; usb_audio_bits_per_sample = bits_per_sample; + usb_audio_direction = direction; usb_audio_is_enabled = true; return true; @@ -52,11 +56,89 @@ bool usb_audio_streaming(void) { return usb_audio_is_streaming; } +// Hand-rolled UAC2 mono speaker (host -> board) descriptor WITHOUT an async +// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR +// (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so +// the streaming alt-setting declares a single OUT endpoint (_nEPs = 0x01). The +// entity IDs match the mic descriptor (see usb_audio_descriptors.h); only the +// terminal roles reverse: the input terminal is the USB-streaming side and the +// output terminal is the desktop speaker, and the AS interface links the input +// terminal (0x01). Async feedback for true clock matching is a later step. +#define USB_AUDIO_SPEAKER_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +static bool usb_audio_direction_is_output(void) { + return usb_audio_direction == USB_AUDIO_DIRECTION_OUTPUT; +} + size_t usb_audio_descriptor_length(void) { + if (usb_audio_direction_is_output()) { + return USB_AUDIO_SPEAKER_DESC_LEN; + } return TUD_AUDIO_MIC_ONE_CH_DESC_LEN; } size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) { + // Pick the isochronous endpoint number. By default it follows the same + // sequential allocation as every other interface. On ports that pin ISO to a + // fixed, dedicated endpoint (USB_AUDIO_ISO_EP_NUM != 0; see the header for the + // nRF52 case), we use that number instead and leave the sequential counters + // untouched: the dedicated ISO endpoint is a separate hardware resource, so + // it must not consume one of the regular endpoint numbers the other + // interfaces draw from. + const bool forced_iso_ep = (USB_AUDIO_ISO_EP_NUM != 0); + const uint8_t iso_ep_num = forced_iso_ep ? USB_AUDIO_ISO_EP_NUM : descriptor_counts->current_endpoint; + + if (usb_audio_direction_is_output()) { + usb_add_interface_string(*current_interface_string, "CircuitPython Speaker"); + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_SPEAKER_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epout*/ iso_ep_num, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) + }; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. + descriptor_counts->current_interface += 2; + if (!forced_iso_ep) { + descriptor_counts->num_out_endpoints++; + descriptor_counts->current_endpoint++; + } + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); + } + usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); const uint8_t usb_audio_descriptor[] = { TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR( @@ -64,21 +146,52 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de /*_stridx*/ *current_interface_string, /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, - /*_epin*/ descriptor_counts->current_endpoint | 0x80, + /*_epin*/ iso_ep_num | 0x80, /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) }; (*current_interface_string)++; // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. descriptor_counts->current_interface += 2; - descriptor_counts->num_in_endpoints++; - descriptor_counts->current_endpoint++; + if (!forced_iso_ep) { + descriptor_counts->num_in_endpoints++; + descriptor_counts->current_endpoint++; + } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); return sizeof(usb_audio_descriptor); } +// --------------------------------------------------------------------+ +// Speaker (host -> board) receive task +// --------------------------------------------------------------------+ + +// Drain everything the host has delivered to the OUT endpoint since the last +// pass into the active USBSpeaker's ring. TinyUSB's weak rx-done handler has +// already moved the isochronous data into ep_out_ff; we copy it out here, in +// task (non-ISR) context, matching the project's "defer ISR work" rule. The ring +// itself, and the overrun/underrun handling, live in USBSpeaker.c so the data +// sits in the audiosample source the output backend pulls from. +static void usb_audio_speaker_task(void) { + // One USB packet of scratch; we loop until ep_out_ff is empty. + static uint8_t chunk[CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX]; + + while (tud_audio_available() > 0) { + uint16_t got = tud_audio_read(chunk, sizeof(chunk)); + if (got == 0) { + break; + } + // tud_audio_read() never returns more than the buffer it was given, but + // clamp so the compiler can prove the drain copies stay within chunk[] + // once this loop is inlined into it. + if (got > sizeof(chunk)) { + got = sizeof(chunk); + } + usb_audio_usbspeaker_background_drain(chunk, got); + } +} + void usb_audio_task(void) { if (!usb_audio_is_streaming) { return; @@ -140,6 +253,12 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_reques (void)rhport; uint8_t const alt = (uint8_t)tu_u16_low(p_request->wValue); usb_audio_is_streaming = (alt != 0); + if (usb_audio_direction_is_output()) { + // Start each speaker streaming session from live audio: drop anything + // left in the OUT FIFO/ring from a previous session. + tud_audio_clear_ep_out_ff(); + usb_audio_usbspeaker_streaming_reset(); + } return true; } @@ -147,6 +266,10 @@ bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const (void)rhport; (void)p_request; usb_audio_is_streaming = false; + if (usb_audio_direction_is_output()) { + tud_audio_clear_ep_out_ff(); + usb_audio_usbspeaker_streaming_reset(); + } return true; } diff --git a/shared-module/usb_audio/__init__.h b/shared-module/usb_audio/__init__.h index c2ef25d0590..3b13568e4e6 100644 --- a/shared-module/usb_audio/__init__.h +++ b/shared-module/usb_audio/__init__.h @@ -13,10 +13,12 @@ #include "py/obj.h" #include "supervisor/usb.h" -// Enable/disable the USB Audio Class (UAC2) microphone interface. These may -// only be called before USB is connected (i.e. from boot.py); they return -// false otherwise. -bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample); +#include "shared-bindings/usb_audio/Direction.h" + +// Enable/disable the USB Audio Class (UAC2) interface. These may only be +// called before USB is connected (i.e. from boot.py); they return false +// otherwise. +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, usb_audio_direction_t direction); bool shared_module_usb_audio_disable(void); // True once enable() has been called successfully. @@ -31,6 +33,9 @@ extern uint32_t usb_audio_sample_rate; extern uint8_t usb_audio_channel_count; extern uint8_t usb_audio_bits_per_sample; +// Stream direction requested in enable(), valid when usb_audio_enabled() is true. +extern usb_audio_direction_t usb_audio_direction; + // Descriptor injection hooks, called from supervisor/shared/usb/usb_desc.c. size_t usb_audio_descriptor_length(void); size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string); diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index e2124214d41..5f43c0143d2 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -19,8 +19,45 @@ #define USB_AUDIO_N_CHANNELS (1) #define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) -// Fixed UAC2 entity IDs baked into TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR. +// Endpoint number for the single isochronous audio data endpoint. Most device +// controllers accept an ISO endpoint on any number, so the descriptor builder +// just takes the next sequential one (signalled by 0 here). The nRF52 USBD, +// however, implements isochronous transfers only on a fixed, dedicated endpoint +// number (8): its dcd_edpt_open() rejects any other number for an ISO endpoint, +// so the stream silently never opens and the host sees a mic/speaker that +// transfers no data. Such ports override this (e.g. -DUSB_AUDIO_ISO_EP_NUM=8 in +// the port's mpconfigport.mk) to force the audio endpoint onto that number. +#ifndef USB_AUDIO_ISO_EP_NUM +#define USB_AUDIO_ISO_EP_NUM (0) +#endif + +// Fixed UAC2 entity IDs baked into TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR and the +// hand-rolled speaker descriptor (USB_AUDIO_SPEAKER_DESCRIPTOR in __init__.c). +// The speaker reuses the same IDs as the mic; only the terminal roles reverse +// (input terminal = USB streaming, output terminal = desktop speaker). #define USB_AUDIO_ENTITY_INPUT_TERMINAL (0x01) #define USB_AUDIO_ENTITY_FEATURE_UNIT (0x02) #define USB_AUDIO_ENTITY_OUTPUT_TERMINAL (0x03) #define USB_AUDIO_ENTITY_CLOCK_SOURCE (0x04) + +// Length of the no-feedback mono speaker descriptor. It uses the same set of +// sub-descriptors as TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR (one isochronous data +// endpoint, no feedback endpoint), so this is identical to +// TUD_AUDIO_MIC_ONE_CH_DESC_LEN -- but spell it out independently so the two +// can diverge later (e.g. stereo) without silently mis-sizing the descriptor. +// These TUD_AUDIO_DESC_*_LEN macros come from TinyUSB's usbd.h; this expression +// is only expanded where that header is already included (never at the point +// tusb_config.h includes us), so the header stays dependency-free. +#define USB_AUDIO_SPEAKER_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index 37a8a670b6b..354d50b152a 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -122,8 +122,12 @@ extern "C" { #if CIRCUITPY_USB_AUDIO #include "shared-module/usb_audio/usb_audio_descriptors.h" -// Single audio function: 1 AudioStreaming interface, 1 isochronous IN endpoint. -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TUD_AUDIO_MIC_ONE_CH_DESC_LEN +// Single audio function: 1 AudioStreaming interface, 1 isochronous endpoint. +// The emitted descriptor (mic IN vs. speaker OUT) is chosen at boot from the +// stored direction, so size the class driver's descriptor buffer for the +// larger of the two. They are equal today, but TU_MAX keeps it correct if the +// speaker descriptor grows (e.g. stereo) independently of the mic. +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TU_MAX(TUD_AUDIO_MIC_ONE_CH_DESC_LEN, USB_AUDIO_SPEAKER_DESC_LEN) #define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 // EP0 buffer for class-specific control requests (sample-freq range, volume range, ...). #define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 @@ -135,6 +139,18 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) + +// OUT endpoint (host -> board speaker). Compiled into the class driver +// unconditionally; whether it actually enumerates is decided by the emitted +// descriptor (still mic-only until the speaker descriptor lands). Mirrors the +// IN sizing above. +#define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX USB_AUDIO_N_BYTES_PER_SAMPLE +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_N_CHANNELS +// wMaxPacketSize, sized for the highest supported sample rate. +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +// Deep software FIFO so the 1 ms drain keeps clear of the overrun ceiling. +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) #endif /*------------------------------------------------------------------*/ diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 23ae866242c..63c0b903b1c 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -185,9 +185,12 @@ ifeq ($(CIRCUITPY_TINYUSB),1) ifeq ($(CIRCUITPY_USB_AUDIO), 1) SRC_SUPERVISOR += \ shared-bindings/usb_audio/__init__.c \ + shared-bindings/usb_audio/Direction.c \ shared-module/usb_audio/__init__.c \ shared-bindings/usb_audio/USBMicrophone.c \ shared-module/usb_audio/USBMicrophone.c \ + shared-bindings/usb_audio/USBSpeaker.c \ + shared-module/usb_audio/USBSpeaker.c \ lib/tinyusb/src/class/audio/audio_device.c \ # The CFG_TUD_AUDIO_* class driver settings are defined in From df24ccd335bf2894f85f103f9b02c0322a22bc94 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 19 Jun 2026 12:57:03 -0500 Subject: [PATCH 567/876] fix usb_audio_speaker_task() call --- shared-module/usb_audio/__init__.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index d4e1ae6dd6d..d1462349022 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -197,6 +197,11 @@ void usb_audio_task(void) { return; } + if (usb_audio_direction_is_output()) { + usb_audio_speaker_task(); + return; + } + // Pace production by the IN FIFO level. Each pass we top the software FIFO // back up to its half-full setpoint, generating only the samples the host has // actually drained since the last pass. This limits our production rate to the From 927abdf31a327b1b12f750f6907c50526e3c1924 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 19 Jun 2026 13:36:48 -0500 Subject: [PATCH 568/876] implement bi-directional usb_audio --- shared-module/usb_audio/USBSpeaker.c | 5 +- shared-module/usb_audio/__init__.c | 205 ++++++++++++++++-- shared-module/usb_audio/__init__.h | 10 +- .../usb_audio/usb_audio_descriptors.h | 50 +++++ supervisor/shared/usb/tusb_config.h | 17 +- 5 files changed, 253 insertions(+), 34 deletions(-) diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c index ec21f7457f0..12921430bc3 100644 --- a/shared-module/usb_audio/USBSpeaker.c +++ b/shared-module/usb_audio/USBSpeaker.c @@ -64,8 +64,9 @@ bool common_hal_usb_audio_usbspeaker_deinited(usb_audio_usbspeaker_obj_t *self) bool common_hal_usb_audio_usbspeaker_get_connected(usb_audio_usbspeaker_obj_t *self) { (void)self; // True while the host has opened the OUT streaming interface, i.e. it is - // actively sending audio. - return usb_audio_streaming(); + // actively sending audio. Speaker-specific so it stays correct when a mic + // shares the same headset function. + return usb_audio_speaker_streaming(); } // --------------------------------------------------------------------+ diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index d1462349022..41d8b14ba2c 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -15,7 +15,18 @@ #include "tusb.h" static bool usb_audio_is_enabled = false; -static bool usb_audio_is_streaming = false; + +// The host opens each AudioStreaming interface independently (alt 0 = idle, alt 1 +// = streaming), so the two directions of a headset are tracked separately. For +// the single-direction microphone/speaker only the matching flag is ever set. +static bool usb_audio_mic_streaming = false; +static bool usb_audio_spk_streaming = false; + +// AudioStreaming interface numbers assigned when the descriptor is built, used to +// route the host's set-interface requests to the right direction. 0xff until a +// descriptor that includes that direction has been emitted. +static uint8_t usb_audio_mic_as_itf = 0xff; +static uint8_t usb_audio_spk_as_itf = 0xff; uint32_t usb_audio_sample_rate; uint8_t usb_audio_channel_count; @@ -53,7 +64,14 @@ bool usb_audio_enabled(void) { } bool usb_audio_streaming(void) { - return usb_audio_is_streaming; + return usb_audio_mic_streaming || usb_audio_spk_streaming; +} + +// True while the host has the speaker (OUT) stream open, i.e. it is actively +// sending audio. Used by USBSpeaker.connected so it reflects the speaker +// direction specifically even when a mic shares the same headset function. +bool usb_audio_speaker_streaming(void) { + return usb_audio_spk_streaming; } // Hand-rolled UAC2 mono speaker (host -> board) descriptor WITHOUT an async @@ -92,11 +110,78 @@ bool usb_audio_streaming(void) { /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) +// Hand-rolled UAC2 mono headset (Direction.INPUT_OUTPUT): one audio function +// presenting both a speaker (host -> board OUT) and a microphone (board -> host +// IN) at once. This combines USB_AUDIO_SPEAKER_DESCRIPTOR's speaker chain with +// TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR's mic chain under a single IAD. The two chains +// must use distinct entity IDs (USB_AUDIO_HS_ENTITY_*; see usb_audio_descriptors.h) +// because they live in the same AudioControl interface, and they share one clock +// source. The function spans three interfaces: AudioControl (_itfnum), the +// speaker AudioStreaming interface (_itfnum + 1, OUT endpoint), and the mic +// AudioStreaming interface (_itfnum + 2, IN endpoint). Neither stream has an +// async feedback endpoint, matching the single-direction descriptors. +#define USB_AUDIO_HEADSET_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) -- 3 interfaces */ \ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x03, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) -- clock + both chains */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + 2 * (TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN), /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) -- shared by both chains */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ + /* --- Speaker chain (host -> board) --- */ \ + /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* --- Mic chain (board -> host) --- */ \ + /* Input Terminal Descriptor(4.7.2.4) -- generic microphone */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- USB streaming out to the host */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* --- Speaker AudioStreaming interface (_itfnum + 1) --- */ \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the speaker input terminal */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000), \ + /* --- Mic AudioStreaming interface (_itfnum + 2) --- */ \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one IN endpoint */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the mic output terminal */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +static bool usb_audio_direction_is_input_output(void) { + return usb_audio_direction == USB_AUDIO_DIRECTION_INPUT_OUTPUT; +} + static bool usb_audio_direction_is_output(void) { return usb_audio_direction == USB_AUDIO_DIRECTION_OUTPUT; } size_t usb_audio_descriptor_length(void) { + if (usb_audio_direction_is_input_output()) { + return USB_AUDIO_HEADSET_DESC_LEN; + } if (usb_audio_direction_is_output()) { return USB_AUDIO_SPEAKER_DESC_LEN; } @@ -114,6 +199,48 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de const bool forced_iso_ep = (USB_AUDIO_ISO_EP_NUM != 0); const uint8_t iso_ep_num = forced_iso_ep ? USB_AUDIO_ISO_EP_NUM : descriptor_counts->current_endpoint; + if (usb_audio_direction_is_input_output()) { + // Combined headset: a speaker AudioStreaming interface (OUT) and a mic + // AudioStreaming interface (IN) under one AudioControl interface. This + // needs two isochronous endpoints, so it cannot be served by ports that + // pin ISO to a single dedicated endpoint number (forced_iso_ep, e.g. + // nRF52, which has only one ISO-capable endpoint). On those ports the + // sequential numbers below will not match the hardware's required ISO + // endpoint and the stream will not open; INPUT_OUTPUT is effectively + // unsupported there. The sequential-allocation ports (e.g. RP2) take a + // distinct number for each direction. + const uint8_t ep_out = descriptor_counts->current_endpoint; + const uint8_t ep_in = descriptor_counts->current_endpoint + 1; + + usb_add_interface_string(*current_interface_string, "CircuitPython Headset"); + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_HEADSET_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epout*/ ep_out, + /*_epin*/ ep_in | 0x80, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) + }; + + // Speaker AS is the first interface after AudioControl, mic AS the second. + usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; + usb_audio_mic_as_itf = descriptor_counts->current_interface + 2; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus + // one OUT and one IN endpoint. + descriptor_counts->current_interface += 3; + descriptor_counts->num_out_endpoints++; + descriptor_counts->num_in_endpoints++; + descriptor_counts->current_endpoint += 2; + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); + } + if (usb_audio_direction_is_output()) { usb_add_interface_string(*current_interface_string, "CircuitPython Speaker"); const uint8_t usb_audio_descriptor[] = { @@ -126,6 +253,9 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) }; + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; + (*current_interface_string)++; // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. descriptor_counts->current_interface += 2; @@ -150,6 +280,9 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) }; + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_mic_as_itf = descriptor_counts->current_interface + 1; + (*current_interface_string)++; // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. descriptor_counts->current_interface += 2; @@ -192,16 +325,11 @@ static void usb_audio_speaker_task(void) { } } -void usb_audio_task(void) { - if (!usb_audio_is_streaming) { - return; - } - - if (usb_audio_direction_is_output()) { - usb_audio_speaker_task(); - return; - } +// --------------------------------------------------------------------+ +// Microphone (board -> host) transmit task +// --------------------------------------------------------------------+ +static void usb_audio_microphone_task(void) { // Pace production by the IN FIFO level. Each pass we top the software FIFO // back up to its half-full setpoint, generating only the samples the host has // actually drained since the last pass. This limits our production rate to the @@ -249,31 +377,53 @@ void usb_audio_task(void) { } } +void usb_audio_task(void) { + // Each direction is gated on the host having opened its AudioStreaming + // interface. For a headset both run in the same pass: drain the host's + // speaker audio and refill the mic stream independently. The single-direction + // modes simply never have the other flag set. + if (usb_audio_spk_streaming) { + usb_audio_speaker_task(); + } + if (usb_audio_mic_streaming) { + usb_audio_microphone_task(); + } +} + // --------------------------------------------------------------------+ // TinyUSB audio class callbacks (weak symbols overridden here) // --------------------------------------------------------------------+ -// Host opened/closed the AudioStreaming alternate setting. +// Host opened/closed the AudioStreaming alternate setting. The host selects each +// direction's interface independently (a headset has two), so route by interface +// number to the matching streaming flag rather than assuming a single stream. bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void)rhport; - uint8_t const alt = (uint8_t)tu_u16_low(p_request->wValue); - usb_audio_is_streaming = (alt != 0); - if (usb_audio_direction_is_output()) { + uint8_t const itf = (uint8_t)tu_u16_low(p_request->wIndex); + bool const streaming = (tu_u16_low(p_request->wValue) != 0); + + if (itf == usb_audio_spk_as_itf) { + usb_audio_spk_streaming = streaming; // Start each speaker streaming session from live audio: drop anything // left in the OUT FIFO/ring from a previous session. tud_audio_clear_ep_out_ff(); usb_audio_usbspeaker_streaming_reset(); + } else if (itf == usb_audio_mic_as_itf) { + usb_audio_mic_streaming = streaming; } return true; } bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void)rhport; - (void)p_request; - usb_audio_is_streaming = false; - if (usb_audio_direction_is_output()) { + uint8_t const itf = (uint8_t)tu_u16_low(p_request->wIndex); + + if (itf == usb_audio_spk_as_itf) { + usb_audio_spk_streaming = false; tud_audio_clear_ep_out_ff(); usb_audio_usbspeaker_streaming_reset(); + } else if (itf == usb_audio_mic_as_itf) { + usb_audio_mic_streaming = false; } return true; } @@ -289,7 +439,11 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Only current-value requests are supported. TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); - if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT) { + // A headset exposes a feature unit per direction; the speaker's id matches the + // single-direction USB_AUDIO_ENTITY_FEATURE_UNIT, the mic adds a second one. + // Mute/volume state is shared across them (mono, cosmetic for now). + if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || + entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { if (channelNum > USB_AUDIO_N_CHANNELS) { return false; } @@ -319,8 +473,12 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p uint8_t const ctrlSel = (uint8_t)tu_u16_high(p_request->wValue); uint8_t const entityID = (uint8_t)tu_u16_high(p_request->wIndex); - // Input terminal (microphone). - if (entityID == USB_AUDIO_ENTITY_INPUT_TERMINAL) { + // Input terminal connector control. The single-mic descriptor uses + // USB_AUDIO_ENTITY_INPUT_TERMINAL; the headset's microphone input terminal is + // a distinct id. (The USB-streaming input terminals don't advertise a readable + // connector control, so the host won't query them here.) + if (entityID == USB_AUDIO_ENTITY_INPUT_TERMINAL || + entityID == USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL) { switch (ctrlSel) { case AUDIO_TE_CTRL_CONNECTOR: { audio_desc_channel_cluster_t ret; @@ -334,8 +492,9 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p } } - // Feature unit (mute/volume). - if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT) { + // Feature unit (mute/volume) for either the speaker or mic chain. + if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || + entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { if (channelNum > USB_AUDIO_N_CHANNELS) { return false; } diff --git a/shared-module/usb_audio/__init__.h b/shared-module/usb_audio/__init__.h index 3b13568e4e6..a275996f7a6 100644 --- a/shared-module/usb_audio/__init__.h +++ b/shared-module/usb_audio/__init__.h @@ -24,10 +24,16 @@ bool shared_module_usb_audio_disable(void); // True once enable() has been called successfully. bool usb_audio_enabled(void); -// True while the host has opened the AudioStreaming alternate setting, i.e. it is -// actively listening. This is the real "stream the audio now" signal. +// True while the host has opened either AudioStreaming alternate setting, i.e. it +// is actively listening or sending. This is the real "stream the audio now" +// signal. bool usb_audio_streaming(void); +// True while the host has the speaker (host -> board OUT) stream open. Distinct +// from usb_audio_streaming() so USBSpeaker can report its own direction even when +// it shares a headset function with a microphone. +bool usb_audio_speaker_streaming(void); + // Negotiated audio format, valid when usb_audio_enabled() is true. extern uint32_t usb_audio_sample_rate; extern uint8_t usb_audio_channel_count; diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 5f43c0143d2..9b6b98a49c1 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -40,6 +40,20 @@ #define USB_AUDIO_ENTITY_OUTPUT_TERMINAL (0x03) #define USB_AUDIO_ENTITY_CLOCK_SOURCE (0x04) +// Combined headset (Direction.INPUT_OUTPUT) topology. A single audio function +// carries both a speaker chain (host -> board) and a mic chain (board -> host), +// so every unit/terminal needs an ID unique across the whole function -- unlike +// the single-direction descriptors above, which can reuse the same small set. +// The clock source is shared by both chains. (USB_AUDIO_HEADSET_DESCRIPTOR in +// __init__.c bakes these in.) +#define USB_AUDIO_HS_ENTITY_CLOCK_SOURCE (0x04) +#define USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL (0x01) // USB streaming in from host +#define USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT (0x02) +#define USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL (0x03) // desktop speaker +#define USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL (0x05) // generic microphone +#define USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT (0x06) +#define USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL (0x07) // USB streaming out to host + // Length of the no-feedback mono speaker descriptor. It uses the same set of // sub-descriptors as TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR (one isochronous data // endpoint, no feedback endpoint), so this is identical to @@ -61,3 +75,39 @@ + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +// Length of the combined headset descriptor (Direction.INPUT_OUTPUT): one IAD +// wrapping a single AudioControl interface plus two AudioStreaming interfaces +// (speaker OUT + mic IN). The AC interface declares one shared clock, plus an +// input terminal / feature unit / output terminal for each of the two chains; +// each AS interface contributes a zero-bandwidth alt 0 and a streaming alt 1 +// with one isochronous data endpoint (no feedback endpoint, matching the +// single-direction descriptors). See USB_AUDIO_HEADSET_DESCRIPTOR in __init__.c. +// Expanded only where TinyUSB's usbd.h is already included (never at the point +// tusb_config.h includes us), so this header stays dependency-free. +#define USB_AUDIO_HEADSET_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + /* speaker chain: USB-streaming input terminal -> feature unit -> speaker */ \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + /* speaker AudioStreaming interface (alt 0 + alt 1 with OUT endpoint) */ \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN \ + /* mic AudioStreaming interface (alt 0 + alt 1 with IN endpoint) */ \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index 354d50b152a..ba248e5b7ec 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -122,13 +122,16 @@ extern "C" { #if CIRCUITPY_USB_AUDIO #include "shared-module/usb_audio/usb_audio_descriptors.h" -// Single audio function: 1 AudioStreaming interface, 1 isochronous endpoint. -// The emitted descriptor (mic IN vs. speaker OUT) is chosen at boot from the -// stored direction, so size the class driver's descriptor buffer for the -// larger of the two. They are equal today, but TU_MAX keeps it correct if the -// speaker descriptor grows (e.g. stereo) independently of the mic. -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TU_MAX(TUD_AUDIO_MIC_ONE_CH_DESC_LEN, USB_AUDIO_SPEAKER_DESC_LEN) -#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 1 +// Single audio function. The emitted descriptor is chosen at boot from the +// stored direction: a mic (1 AS interface, IN endpoint), a speaker (1 AS +// interface, OUT endpoint), or a combined headset (2 AS interfaces, one IN and +// one OUT endpoint). Size the class driver's descriptor buffer and AS-interface +// arrays for the largest case so any of them fits. +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TU_MAX(TU_MAX(TUD_AUDIO_MIC_ONE_CH_DESC_LEN, USB_AUDIO_SPEAKER_DESC_LEN), USB_AUDIO_HEADSET_DESC_LEN) +// The headset presents two AudioStreaming interfaces; the single-direction +// descriptors use only the first. The class driver sizes its per-interface alt +// tracking from this, so it must cover the largest case. +#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 2 // EP0 buffer for class-specific control requests (sample-freq range, volume range, ...). #define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 From ab177982d0533ff4495f6ec3dc5d5d7e2d3bf3b8 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Fri, 19 Jun 2026 14:27:08 -0500 Subject: [PATCH 569/876] Fix definition of `CIRCUITPY_AUDIOSPEED` --- py/circuitpy_defns.mk | 1 - py/circuitpy_mpconfig.mk | 3 +++ shared-module/audiocore/__init__.c | 6 +++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index be180d2bc1c..4c91ed102c2 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -151,7 +151,6 @@ SRC_PATTERNS += audiomp3/% endif ifeq ($(CIRCUITPY_AUDIOSPEED),1) SRC_PATTERNS += audiospeed/% -CFLAGS += -DCIRCUITPY_AUDIOSPEED endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index d8c15ba9440..4f5a4bbd64d 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -159,6 +159,9 @@ CFLAGS += -DCIRCUITPY_AUDIOCORE_DEBUG=$(CIRCUITPY_AUDIOCORE_DEBUG) CIRCUITPY_AUDIOMP3 ?= $(call enable-if-all,$(CIRCUITPY_FULL_BUILD) $(CIRCUITPY_AUDIOCORE)) CFLAGS += -DCIRCUITPY_AUDIOMP3=$(CIRCUITPY_AUDIOMP3) +CIRCUITPY_AUDIOSPEED ?= 0 +CFLAGS += -DCIRCUITPY_AUDIOSPEED=$(CIRCUITPY_AUDIOSPEED) + CIRCUITPY_AUDIOEFFECTS ?= 0 CIRCUITPY_AUDIODELAYS ?= $(CIRCUITPY_AUDIOEFFECTS) CFLAGS += -DCIRCUITPY_AUDIODELAYS=$(CIRCUITPY_AUDIODELAYS) diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 24f838c766f..3a80d6b6f42 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -13,7 +13,7 @@ #include "shared-module/audiocore/RawSample.h" #include "shared-module/audiocore/WaveFile.h" -#ifdef CIRCUITPY_AUDIOSPEED +#if CIRCUITPY_AUDIOSPEED #include "shared-bindings/audiospeed/Resampler.h" #endif @@ -202,7 +202,7 @@ void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool allow_mono_to_stereo) { const audiosample_base_t *other = audiosample_check(other_in); - #ifndef CIRCUITPY_AUDIOSPEED + #if !CIRCUITPY_AUDIOSPEED if (other->sample_rate != self->sample_rate) { #else if (other->sample_rate != self->sample_rate && !mp_obj_is_type(other_in, &audiospeed_resampler_type)) { @@ -219,7 +219,7 @@ void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool al mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_signedness); } - #ifdef CIRCUITPY_AUDIOSPEED + #if CIRCUITPY_AUDIOSPEED if (mp_obj_is_type(other_in, &audiospeed_resampler_type)) { audiospeed_resampler_obj_t *other_resampler = MP_OBJ_TO_PTR(other_in); audiospeed_resampler_set_sample_rate(other_resampler, self->sample_rate); From 9c70f2d16ef8413718c10416e177d00e281fed2d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 19 Jun 2026 15:01:39 -0500 Subject: [PATCH 570/876] fix single direction modes --- shared-module/usb_audio/usb_audio_descriptors.h | 14 ++++++++++++++ supervisor/shared/usb/tusb_config.h | 11 ++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 9b6b98a49c1..20103b1907c 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -6,10 +6,24 @@ #pragma once +#include + // Fixed audio format for the UAC2 microphone profile. These must have no other // dependencies because this header is included from the TinyUSB tusb_config.h // (to size the IN endpoint) as well as from the descriptor/binding code. +// Actual length, in bytes, of the audio function descriptor emitted for the +// current direction (mic, speaker, or headset). Declared here -- in the +// dependency-free header tusb_config.h already includes -- because TinyUSB's +// audio class driver reads CFG_TUD_AUDIO_FUNC_1_DESC_LEN at enumeration time and +// returns it to the device core as the number of configuration-descriptor bytes +// the function owns. That value MUST equal the descriptor we actually emitted: +// the three directions differ in length, so a compile-time maximum would over- +// report for the shorter ones and make the core swallow the interfaces that +// follow audio (CDC/MSC), breaking their enumeration. The full definition lives +// in __init__.c (also declared in __init__.h for the descriptor builder). +size_t usb_audio_descriptor_length(void); + // The isochronous IN endpoint's wMaxPacketSize in the USB descriptor is computed // for this rate, so it is the highest rate usb_audio.enable() will accept. #define USB_AUDIO_MAX_SAMPLE_RATE (48000) diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index ba248e5b7ec..a10cd712226 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -125,9 +125,14 @@ extern "C" { // Single audio function. The emitted descriptor is chosen at boot from the // stored direction: a mic (1 AS interface, IN endpoint), a speaker (1 AS // interface, OUT endpoint), or a combined headset (2 AS interfaces, one IN and -// one OUT endpoint). Size the class driver's descriptor buffer and AS-interface -// arrays for the largest case so any of them fits. -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN TU_MAX(TU_MAX(TUD_AUDIO_MIC_ONE_CH_DESC_LEN, USB_AUDIO_SPEAKER_DESC_LEN), USB_AUDIO_HEADSET_DESC_LEN) +// one OUT endpoint). The class driver returns this length to the device core as +// the span of config descriptor the function owns, so it must equal the +// descriptor we actually emitted -- the three directions differ in length, so a +// compile-time maximum would over-report for the shorter ones and make the core +// skip the interfaces that follow audio. usb_audio_descriptor_length() returns +// the live length for the stored direction; it is only read at enumeration time +// (audiod_open), by which point usb_audio.enable() has fixed the direction. +#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN usb_audio_descriptor_length() // The headset presents two AudioStreaming interfaces; the single-direction // descriptors use only the first. The class driver sizes its per-interface alt // tracking from this, so it must cover the largest case. From 5438a56f0d0a75ec4945920b1a6ebb436a763c43 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Sat, 20 Jun 2026 07:55:09 -0500 Subject: [PATCH 571/876] in nordic enable when internal flash != 1 --- ports/nordic/mpconfigport.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index c243d54a707..0316e904b38 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -57,7 +57,6 @@ CIRCUITPY_SERIAL_BLE ?= 1 CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE ?= 1 -CIRCUITPY_USB_AUDIO ?= 1 # nRF52840-specific @@ -93,6 +92,8 @@ ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) OPTIMIZATION_FLAGS ?= -Os CIRCUITPY_LTO = 1 CIRCUITPY_LTO_PARTITION = balanced +else + CIRCUITPY_USB_AUDIO ?= 1 endif else From 53565864b7089a4e9b956709e0293033dc8f1e4e Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 22 Jun 2026 07:24:29 -0500 Subject: [PATCH 572/876] stream protocol for I2SIn --- locale/circuitpython.pot | 5 + ports/espressif/common-hal/audioi2sin/I2SIn.c | 137 +++++++++++++++ ports/espressif/common-hal/audioi2sin/I2SIn.h | 15 +- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 166 ++++++++++++++++++ .../raspberrypi/common-hal/audioi2sin/I2SIn.h | 18 +- shared-bindings/audioi2sin/I2SIn.c | 50 ++++-- shared-bindings/audioi2sin/I2SIn.h | 12 ++ 7 files changed, 389 insertions(+), 14 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index fa088fdda5e..92177dd04fd 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -190,6 +190,11 @@ msgstr "" msgid "%q must be 16, 24, or 32" msgstr "" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" + #: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 50cf5d65c33..c270f500305 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -11,8 +11,10 @@ #include "common-hal/audioi2sin/I2SIn.h" #include "py/runtime.h" #include "shared-bindings/audioi2sin/I2SIn.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/audioi2sin/__init__.h" +#include "supervisor/port.h" #include "driver/i2s_std.h" @@ -67,6 +69,21 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, self->mono = mono; self->samples_signed = samples_signed; + // Populate the audiosample base so I2SIn can stream into the audio pipeline. + // Streaming requires an 8- or 16-bit output depth (reset_buffer enforces it); + // the owned conversion buffer is allocated lazily on first reset_buffer(). + uint8_t channel_count = mono ? 1 : 2; + self->base.sample_rate = sample_rate; + self->base.bits_per_sample = output_bit_depth; + self->base.channel_count = channel_count; + self->base.samples_signed = samples_signed; + self->base.single_buffer = false; + self->base.max_buffer_length = + 2 * AUDIOI2SIN_STREAM_FRAMES * (output_bit_depth / 8) * channel_count; + self->output_buffer = NULL; + self->output_half_bytes = self->base.max_buffer_length / 2; + self->output_index = 0; + claim_pin(bit_clock); claim_pin(word_select); claim_pin(data); @@ -109,6 +126,12 @@ void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { reset_pin_number(self->mclk->number); } self->mclk = NULL; + + if (self->output_buffer != NULL) { + port_free(self->output_buffer); + self->output_buffer = NULL; + } + audiosample_mark_deinit(&self->base); } // Sign-extend a raw I2S sample (in the low `in_depth` bits of `raw`) to a @@ -302,4 +325,118 @@ bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self return self->samples_signed; } +// Write `count` silence samples at output depth starting at sample index `idx`. +// For signed PCM silence is 0; for unsigned (WAV) it is mid-scale. +static void i2sin_fill_silence(void *buffer, uint32_t idx, uint32_t count, + uint8_t out_depth, bool samples_signed) { + if (out_depth == 8) { + uint8_t v = samples_signed ? 0 : 0x80u; + memset((uint8_t *)buffer + idx, v, count); + } else { // 16-bit (the only other streamable width) + uint16_t v = samples_signed ? 0 : 0x8000u; + uint16_t *p = (uint16_t *)buffer + idx; + for (uint32_t i = 0; i < count; i++) { + p[i] = v; + } + } +} + +// Non-blocking fill: read whatever frames are immediately available from the I2S +// driver and convert them into `buffer` (output depth, interleaved), padding the +// remainder with silence on underrun. The bus is configured stereo, so each WS +// frame yields two slots; for mono we keep the left slot. `out_depth` is always 8 +// or 16 here (reset_buffer rejects 24/32). Runs in the output backend's refill +// (background callback) context, so i2s_channel_read is called with a 0 ms +// timeout and never blocks. +void common_hal_audioi2sin_i2sin_fill_buffer(audioi2sin_i2sin_obj_t *self, + uint8_t *buffer, uint32_t frames) { + const uint8_t in_depth = self->bit_depth; + const uint8_t out_depth = self->output_bit_depth; + const bool samples_signed = self->samples_signed; + const bool stereo = !self->mono; + const uint8_t channel_count = stereo ? 2 : 1; + size_t element_size = (in_depth == 24) ? 4 : (in_depth / 8); + const size_t in_frame_bytes = 2 * element_size; // bus is always stereo + const uint32_t total_samples = frames * channel_count; + + uint8_t scratch[256]; + const size_t scratch_frames = sizeof(scratch) / in_frame_bytes; + + uint32_t produced = 0; + while (produced < total_samples) { + size_t want_frames = (total_samples - produced + channel_count - 1) / channel_count; + if (want_frames > scratch_frames) { + want_frames = scratch_frames; + } + size_t got_bytes = 0; + // 0 ms timeout: return immediately with whatever is buffered. + esp_err_t err = i2s_channel_read(self->rx_chan, scratch, + want_frames * in_frame_bytes, &got_bytes, 0); + if (err != ESP_OK && err != ESP_ERR_TIMEOUT) { + break; + } + size_t got_frames = got_bytes / in_frame_bytes; + if (got_frames == 0) { + break; // underrun: pad with silence below + } + for (size_t i = 0; i < got_frames && produced < total_samples; i++) { + const uint8_t *frame = scratch + i * in_frame_bytes; + uint32_t left_raw = i2sin_read_raw(frame, in_depth); + i2sin_write_converted(buffer, produced++, left_raw, + in_depth, out_depth, samples_signed); + if (stereo && produced < total_samples) { + uint32_t right_raw = i2sin_read_raw(frame + element_size, in_depth); + i2sin_write_converted(buffer, produced++, right_raw, + in_depth, out_depth, samples_signed); + } + } + if (got_frames < want_frames) { + break; + } + } + if (produced < total_samples) { + i2sin_fill_silence(buffer, produced, total_samples - produced, + out_depth, samples_signed); + } +} + +void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, + bool single_channel_output, uint8_t channel) { + (void)single_channel_output; + (void)channel; + // The audio pipeline only carries 8- or 16-bit samples; 24/32-bit modes can + // still record() but cannot stream. + if (self->output_bit_depth != 8 && self->output_bit_depth != 16) { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("%q must be 8 or 16"), MP_QSTR_output_bit_depth); + } + if (self->output_buffer == NULL) { + self->output_buffer = (uint8_t *)port_malloc(self->base.max_buffer_length, false); + if (self->output_buffer == NULL) { + m_malloc_fail(self->base.max_buffer_length); + } + } + self->output_index = 0; +} + +audioio_get_buffer_result_t common_hal_audioi2sin_i2sin_get_buffer( + audioi2sin_i2sin_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + uint32_t half = self->output_half_bytes; + uint8_t *out = self->output_buffer + half * self->output_index; + self->output_index = 1 - self->output_index; + + uint32_t bytes_per_sample = self->output_bit_depth / 8; + uint32_t frames = half / (bytes_per_sample * self->base.channel_count); + common_hal_audioi2sin_i2sin_fill_buffer(self, out, frames); + + if (single_channel_output) { + out += (channel % self->base.channel_count) * bytes_per_sample; + } + *buffer = out; + *buffer_length = half; + // A live mic is an infinite stream; never report DONE or the backend stops. + return GET_BUFFER_MORE_DATA; +} + #endif // CIRCUITPY_AUDIOI2SIN diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.h b/ports/espressif/common-hal/audioi2sin/I2SIn.h index 05b533ac89d..4d5e1b4127a 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.h +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.h @@ -10,12 +10,19 @@ #include "common-hal/microcontroller/Pin.h" +#include "shared-module/audiocore/__init__.h" + #include "driver/i2s_std.h" #if CIRCUITPY_AUDIOI2SIN +// Frames handed to the output backend per get_buffer() call; see the matching +// rp2 header for the rationale. +#define AUDIOI2SIN_STREAM_FRAMES (256) + typedef struct { - mp_obj_base_t base; + // MUST be first so I2SIn can be used directly as an audiosample source. + audiosample_base_t base; i2s_chan_handle_t rx_chan; const mcu_pin_obj_t *bit_clock; const mcu_pin_obj_t *word_select; @@ -26,6 +33,12 @@ typedef struct { uint8_t output_bit_depth; bool mono; bool samples_signed; + // Owned double-buffer of converted (output-depth, interleaved) samples, + // allocated lazily on first reset_buffer(). base.max_buffer_length is the + // whole buffer; get_buffer() returns output_half_bytes of it. + uint8_t *output_buffer; + size_t output_half_bytes; + uint8_t output_index; } audioi2sin_i2sin_obj_t; #endif diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 59106260159..8f4fc880045 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -13,6 +13,7 @@ #include "shared/runtime/interrupt_char.h" #include "common-hal/audioi2sin/I2SIn.h" #include "shared-bindings/audioi2sin/I2SIn.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-module/audioi2sin/__init__.h" #include "bindings/rp2pio/StateMachine.h" @@ -278,6 +279,28 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, self->dma_channel = -1; self->overflow = false; + // Populate the audiosample base so I2SIn can feed the audio pipeline as a + // streaming source. The output depth must be 8 or 16 to actually stream; we + // still fill base here (so sample_rate/bits_per_sample/etc. read back) and + // raise from reset_buffer if a 24/32-bit instance is played. The owned + // conversion buffer is allocated lazily on first reset_buffer(). + uint8_t channel_count = mono ? 1 : 2; + // Report the *nominal* requested rate (not the PIO-derived self->sample_rate, + // which can be off by a fraction of a Hz). audiosample_must_match requires + // exact equality against the consumer, which is configured for the nominal + // rate; the tiny capture-clock difference shows up as the slow drift that the + // underrun silence-pad / overflow-drop paths in fill_buffer absorb. + self->base.sample_rate = sample_rate; + self->base.bits_per_sample = output_bit_depth; + self->base.channel_count = channel_count; + self->base.samples_signed = samples_signed; + self->base.single_buffer = false; + self->base.max_buffer_length = + 2 * AUDIOI2SIN_STREAM_FRAMES * (output_bit_depth / 8) * channel_count; + self->output_buffer = NULL; + self->output_half_bytes = self->base.max_buffer_length / 2; + self->output_index = 0; + // Each PIO frame produces 4 bytes in the FIFO regardless of bit depth // (16-bit auto-pushes one packed stereo word, 24/32-bit pushes two // separate 32-bit words). One stereo frame is therefore either 4 or @@ -325,9 +348,14 @@ void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self) { port_free(self->ring); self->ring = NULL; } + if (self->output_buffer != NULL) { + port_free(self->output_buffer); + self->output_buffer = NULL; + } self->ring_size = 0; self->half_size = 0; self->dma_channel = -1; + audiosample_mark_deinit(&self->base); } uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) { @@ -578,4 +606,142 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se return output_count; } +// Write `count` silence samples at output depth starting at sample index `idx`. +// For signed PCM silence is 0; for unsigned (WAV) it is mid-scale. +static void i2sin_fill_silence(void *buffer, uint32_t idx, uint32_t count, + uint8_t out_depth, bool samples_signed) { + if (out_depth == 8) { + uint8_t v = samples_signed ? 0 : 0x80u; + memset((uint8_t *)buffer + idx, v, count); + } else { // 16-bit (the only other streamable width) + uint16_t v = samples_signed ? 0 : 0x8000u; + uint16_t *p = (uint16_t *)buffer + idx; + for (uint32_t i = 0; i < count; i++) { + p[i] = v; + } + } +} + +// Non-blocking fill: convert up to `frames` frames currently available in the +// DMA ring into `buffer` (output depth, interleaved), padding the remainder with +// silence on underrun rather than spinning. Used by get_buffer() from the output +// backend's refill interrupt, so it must never block. `out_depth` is always 8 or +// 16 here (reset_buffer rejects 24/32). Reuses the same per-sample conversion as +// record_to_buffer via i2sin_write_converted. +void common_hal_audioi2sin_i2sin_fill_buffer(audioi2sin_i2sin_obj_t *self, + uint8_t *buffer, uint32_t frames) { + const size_t ring_size = self->ring_size; + const size_t half_size = self->half_size; + const uint8_t in_depth = self->bit_depth; + const uint8_t out_depth = self->output_bit_depth; + const bool samples_signed = self->samples_signed; + const bool left_justified = self->left_justified; + const bool stereo = !self->mono; + const uint8_t channel_count = stereo ? 2 : 1; + const size_t frame_bytes = (in_depth == 16) ? 4 : 8; + const uint32_t total_samples = frames * channel_count; + + uint32_t produced = 0; + while (produced < total_samples) { + size_t write_pos = i2sin_write_pos(self); + size_t avail = (write_pos + ring_size - self->read_pos) % ring_size; + if (avail > half_size) { + // The consumer is slower than the mic and the ring is filling up + // (the overflow case record_to_buffer also handles). Drop back to + // just behind the DMA so latency stays bounded; the discarded audio + // shows up as a brief discontinuity, not a hang. + self->overflow = true; + if (in_depth == 16) { + self->read_pos = write_pos & ~(size_t)3u; + } else { + size_t cur_half = (write_pos < half_size) ? 0 : half_size; + self->read_pos = (cur_half + half_size) % ring_size; + self->settled = false; + } + avail = (write_pos + ring_size - self->read_pos) % ring_size; + } + if (!self->settled && avail >= frame_bytes) { + // Drop one frame so playback starts on a settled sample and (for + // 24/32-bit) on the right-channel word the program emits first. + self->read_pos = (self->read_pos + frame_bytes) % ring_size; + avail -= frame_bytes; + self->settled = true; + } + if (avail < frame_bytes) { + break; // underrun: pad the rest with silence below + } + uint32_t left, right; + if (in_depth == 16) { + uint32_t fr = *(volatile uint32_t *)(self->ring + self->read_pos); + left = fr & 0xffffu; + right = fr >> 16; + } else { + right = *(volatile uint32_t *)(self->ring + self->read_pos); + size_t next_pos = (self->read_pos + 4) % ring_size; + left = *(volatile uint32_t *)(self->ring + next_pos); + } + i2sin_write_converted(buffer, produced++, left, + in_depth, out_depth, samples_signed, left_justified); + if (stereo && produced < total_samples) { + i2sin_write_converted(buffer, produced++, right, + in_depth, out_depth, samples_signed, left_justified); + } + self->read_pos = (self->read_pos + frame_bytes) % ring_size; + } + if (produced < total_samples) { + i2sin_fill_silence(buffer, produced, total_samples - produced, + out_depth, samples_signed); + } +} + +void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, + bool single_channel_output, uint8_t channel) { + (void)single_channel_output; + (void)channel; + // The audio pipeline only carries 8- or 16-bit samples. 24/32-bit modes can + // still record() but cannot stream; fail clearly the first time playback is + // set up rather than emitting garbage. + if (self->output_bit_depth != 8 && self->output_bit_depth != 16) { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("%q must be 8 or 16"), MP_QSTR_output_bit_depth); + } + if (self->output_buffer == NULL) { + // The output backend's DMA reads this buffer directly, so it must be + // DMA-capable like the input ring. + self->output_buffer = (uint8_t *)port_malloc(self->base.max_buffer_length, true); + if (self->output_buffer == NULL) { + m_malloc_fail(self->base.max_buffer_length); + } + } + self->output_index = 0; + // Resync to live audio: snap the read cursor just behind the DMA write head + // (frame-aligned) and re-settle so playback begins on fresh samples. + size_t write_pos = i2sin_write_pos(self); + self->read_pos = (self->bit_depth == 16) + ? (write_pos & ~(size_t)3u) + : (write_pos & ~(size_t)7u); + self->settled = false; + self->overflow = false; +} + +audioio_get_buffer_result_t common_hal_audioi2sin_i2sin_get_buffer( + audioi2sin_i2sin_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + uint32_t half = self->output_half_bytes; + uint8_t *out = self->output_buffer + half * self->output_index; + self->output_index = 1 - self->output_index; + + uint32_t bytes_per_sample = self->output_bit_depth / 8; + uint32_t frames = half / (bytes_per_sample * self->base.channel_count); + common_hal_audioi2sin_i2sin_fill_buffer(self, out, frames); + + if (single_channel_output) { + out += (channel % self->base.channel_count) * bytes_per_sample; + } + *buffer = out; + *buffer_length = half; + // A live mic is an infinite stream; never report DONE or the backend stops. + return GET_BUFFER_MORE_DATA; +} + #endif // CIRCUITPY_AUDIOI2SIN diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h index 525c72e3c5e..fc17507d2c8 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -11,8 +11,17 @@ #include "py/obj.h" +#include "shared-module/audiocore/__init__.h" + +// Number of audio frames a single get_buffer() call hands to the output backend +// (one frame = one mono sample, or an L+R pair in stereo). This sets the pull +// granularity and the silence-pad chunk on underrun. Kept independent of the DMA +// half-buffer so the two can be tuned separately. +#define AUDIOI2SIN_STREAM_FRAMES (256) + typedef struct { - mp_obj_base_t base; + // MUST be first so I2SIn can be used directly as an audiosample source. + audiosample_base_t base; uint32_t sample_rate; uint8_t bit_depth; uint8_t output_bit_depth; @@ -29,4 +38,11 @@ typedef struct { size_t read_pos; int dma_channel; bool overflow; + // Owned double-buffer returned to the output backend by get_buffer(), holding + // converted (output-depth, interleaved) samples. Allocated lazily on the first + // reset_buffer() so record()-only use pays no extra RAM. base.max_buffer_length + // is the whole buffer; get_buffer() returns output_half_bytes of it. + uint8_t *output_buffer; + size_t output_half_bytes; + uint8_t output_index; } audioi2sin_i2sin_obj_t; diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 2b098248b62..00303a7b7c5 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -14,6 +14,8 @@ #include "py/runtime.h" #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/audioi2sin/I2SIn.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiocore/__init__.h" #include "shared-bindings/util.h" //| class I2SIn: @@ -237,18 +239,19 @@ static mp_obj_t audioi2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destinat MP_DEFINE_CONST_FUN_OBJ_3(audioi2sin_i2sin_record_obj, audioi2sin_i2sin_obj_record); //| sample_rate: int -//| """The actual sample rate of the recording. This may not match the constructed -//| sample rate due to internal clock limitations.""" +//| """The configured (nominal) sample rate, in Hz. This is the rate reported to +//| the audio pipeline so it matches the output/consumer it is played into. The +//| true capture rate may differ from this by a fraction of a Hz due to internal +//| clock limitations. (Provided by the audiosample protocol via +//| ``AUDIOSAMPLE_FIELDS``.)""" +//| +//| bits_per_sample: int +//| """The number of bits per sample as it is streamed through the audio pipeline, +//| i.e. ``output_bit_depth``. (read-only)""" +//| +//| channel_count: int +//| """The number of channels (1 for mono, 2 for stereo). (read-only)""" //| -static mp_obj_t audioi2sin_i2sin_obj_get_sample_rate(mp_obj_t self_in) { - audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioi2sin_i2sin_get_sample_rate(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_sample_rate_obj, audioi2sin_i2sin_obj_get_sample_rate); - -MP_PROPERTY_GETTER(audioi2sin_i2sin_sample_rate_obj, - (mp_obj_t)&audioi2sin_i2sin_get_sample_rate_obj); //| bit_depth: int //| """The actual bit depth of the recording. (read-only)""" @@ -293,18 +296,40 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_samples_signed_obj, audioi2sin_i2 MP_PROPERTY_GETTER(audioi2sin_i2sin_samples_signed_obj, (mp_obj_t)&audioi2sin_i2sin_get_samples_signed_obj); +// Thin wrappers exposing the common-hal streaming functions to the audiosample +// protocol. get_buffer() runs in the output backend's refill interrupt, so it is +// not exposed to Python. +static void audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, + bool single_channel_output, uint8_t channel) { + common_hal_audioi2sin_i2sin_reset_buffer(self, single_channel_output, channel); +} + +static audioio_get_buffer_result_t audioi2sin_i2sin_get_buffer(audioi2sin_i2sin_obj_t *self, + bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { + return common_hal_audioi2sin_i2sin_get_buffer(self, single_channel_output, channel, + buffer, buffer_length); +} + static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, { MP_ROM_QSTR(MP_QSTR_record), MP_ROM_PTR(&audioi2sin_i2sin_record_obj) }, - { MP_ROM_QSTR(MP_QSTR_sample_rate), MP_ROM_PTR(&audioi2sin_i2sin_sample_rate_obj) }, + // sample_rate / bits_per_sample / channel_count come from the audiosample + // protocol's shared property getters. + AUDIOSAMPLE_FIELDS, { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_bit_depth_obj) }, { MP_ROM_QSTR(MP_QSTR_output_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_output_bit_depth_obj) }, { MP_ROM_QSTR(MP_QSTR_samples_signed), MP_ROM_PTR(&audioi2sin_i2sin_samples_signed_obj) }, }; static MP_DEFINE_CONST_DICT(audioi2sin_i2sin_locals_dict, audioi2sin_i2sin_locals_dict_table); + +static const audiosample_p_t audioi2sin_i2sin_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audioi2sin_i2sin_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audioi2sin_i2sin_get_buffer, +}; #endif // CIRCUITPY_AUDIOI2SIN MP_DEFINE_CONST_OBJ_TYPE( @@ -314,5 +339,6 @@ MP_DEFINE_CONST_OBJ_TYPE( make_new, audioi2sin_i2sin_make_new #if CIRCUITPY_AUDIOI2SIN , locals_dict, &audioi2sin_i2sin_locals_dict + , protocol, &audioi2sin_i2sin_proto #endif ); diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h index dc9c671741a..ec1f1640d0e 100644 --- a/shared-bindings/audioi2sin/I2SIn.h +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -10,6 +10,7 @@ #if CIRCUITPY_AUDIOI2SIN #include "common-hal/audioi2sin/I2SIn.h" +#include "shared-module/audiocore/__init__.h" #endif extern const mp_obj_type_t audioi2sin_i2sin_type; @@ -28,4 +29,15 @@ uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self); uint8_t common_hal_audioi2sin_i2sin_get_output_bit_depth(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self); + +// audiosample protocol: streaming source support. fill_buffer converts the +// frames currently available from the live mic into `buffer` (output depth, +// interleaved), padding with silence on underrun; it never blocks. +void common_hal_audioi2sin_i2sin_fill_buffer(audioi2sin_i2sin_obj_t *self, + uint8_t *buffer, uint32_t frames); +void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, + bool single_channel_output, uint8_t channel); +audioio_get_buffer_result_t common_hal_audioi2sin_i2sin_get_buffer( + audioi2sin_i2sin_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length); #endif From a0a7db82145b094a32d6a7758794baf81aa20e7d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 22 Jun 2026 08:37:49 -0500 Subject: [PATCH 573/876] make USBMicrophone and USBSpeaker singletons, use speaker and microphone args for enable() instead of Direction enum --- locale/circuitpython.pot | 13 +--- shared-bindings/usb_audio/USBMicrophone.c | 28 +------ shared-bindings/usb_audio/USBSpeaker.c | 42 ++--------- shared-bindings/usb_audio/__init__.c | 53 +++++++++----- shared-bindings/usb_audio/__init__.h | 6 ++ shared-module/usb_audio/__init__.c | 73 +++++++++++++++++-- shared-module/usb_audio/__init__.h | 21 ++++-- .../usb_audio/usb_audio_descriptors.h | 4 +- supervisor/shared/usb.c | 8 ++ supervisor/supervisor.mk | 1 - 10 files changed, 146 insertions(+), 103 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 4cfc7ff1f44..8347be5ea81 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -625,6 +625,10 @@ msgstr "" msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -2271,15 +2275,6 @@ msgstr "" msgid "UID:" msgstr "" -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "USB audio not enabled for output in boot.py" -msgstr "" - -#: shared-bindings/usb_audio/USBMicrophone.c -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "USB audio not enabled in boot.py" -msgstr "" - #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" diff --git a/shared-bindings/usb_audio/USBMicrophone.c b/shared-bindings/usb_audio/USBMicrophone.c index 2ccf7b2d17b..11524bd06de 100644 --- a/shared-bindings/usb_audio/USBMicrophone.c +++ b/shared-bindings/usb_audio/USBMicrophone.c @@ -21,34 +21,15 @@ //| samples it pulls are streamed to the host PC over USB rather than to a pin, //| so the board appears as a microphone. //| -//| ``usb_audio.enable()`` must have been called in ``boot.py`` before this object -//| can be constructed.""" +//| You cannot create an instance of `usb_audio.USBMicrophone`. //| -//| def __init__(self) -> None: -//| """Create a USBMicrophone using the audio format configured in ``boot.py``.""" -//| ... +//| There is a single shared instance, available as ``usb_audio.USBMicrophone`` +//| once ``usb_audio.enable()`` has configured an input (microphone) stream in +//| ``boot.py``. Until then ``usb_audio.USBMicrophone`` is ``None``.""" //| -static mp_obj_t usb_audio_usbmicrophone_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - static const mp_arg_t allowed_args[] = {}; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - // The audio format is chosen by usb_audio.enable() in boot.py, which also claims - // the USB interface. Without it there is no microphone for the host to read. - if (!usb_audio_enabled()) { - mp_raise_RuntimeError(MP_ERROR_TEXT("USB audio not enabled in boot.py")); - } - usb_audio_usbmicrophone_obj_t *self = mp_obj_malloc_with_finaliser(usb_audio_usbmicrophone_obj_t, &usb_audio_USBMicrophone_type); - common_hal_usb_audio_usbmicrophone_construct(self); - return MP_OBJ_FROM_PTR(self); -} - -//| def deinit(self) -> None: -//| """Deinitialises the USBMicrophone and releases any resources for reuse.""" -//| ... -//| static mp_obj_t usb_audio_usbmicrophone_deinit(mp_obj_t self_in) { usb_audio_usbmicrophone_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_usb_audio_usbmicrophone_deinit(self); @@ -192,6 +173,5 @@ MP_DEFINE_CONST_OBJ_TYPE( usb_audio_USBMicrophone_type, MP_QSTR_USBMicrophone, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, usb_audio_usbmicrophone_make_new, locals_dict, &usb_audio_usbmicrophone_locals_dict ); diff --git a/shared-bindings/usb_audio/USBSpeaker.c b/shared-bindings/usb_audio/USBSpeaker.c index 7df8cf5798d..1407d50e55c 100644 --- a/shared-bindings/usb_audio/USBSpeaker.c +++ b/shared-bindings/usb_audio/USBSpeaker.c @@ -23,15 +23,18 @@ //| such as `audiobusio.I2SOut`, `audiopwmio.PWMAudioOut` or `audioio.AudioOut` //| (optionally through the effect modules), so the board appears as a speaker. //| -//| ``usb_audio.enable(direction=usb_audio.Direction.OUTPUT)`` must have been -//| called in ``boot.py`` before this object can be constructed. +//| You cannot create an instance of `usb_audio.USBSpeaker`. +//| +//| There is a single shared instance, available as ``usb_audio.USBSpeaker`` +//| once ``usb_audio.enable()`` has configured an output (speaker) stream in +//| ``boot.py``. Until then ``usb_audio.USBSpeaker`` is ``None``. //| //| .. code-block:: py //| //| # boot.py //| import usb_audio //| usb_audio.enable(sample_rate=16000, channel_count=1, bits_per_sample=16, -//| direction=usb_audio.Direction.OUTPUT) +//| microphone=False, speaker=True) //| //| .. code-block:: py //| @@ -40,42 +43,12 @@ //| import usb_audio //| import audiobusio //| -//| spk = usb_audio.USBSpeaker() +//| spk = usb_audio.USBSpeaker //| out = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) //| out.play(spk, loop=True) //| //| """ -//| -//| def __init__(self) -> None: -//| """Create a USBSpeaker using the audio format configured in ``boot.py``.""" -//| ... -//| -static mp_obj_t usb_audio_usbspeaker_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - static const mp_arg_t allowed_args[] = {}; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - // The audio format and USB interface are claimed by usb_audio.enable() in - // boot.py. Without it there is no speaker for the host to play to. - if (!usb_audio_enabled()) { - mp_raise_RuntimeError(MP_ERROR_TEXT("USB audio not enabled in boot.py")); - } - // A USBSpeaker only makes sense when the OUT endpoint is enumerated. - if (usb_audio_direction != USB_AUDIO_DIRECTION_OUTPUT && - usb_audio_direction != USB_AUDIO_DIRECTION_INPUT_OUTPUT) { - mp_raise_RuntimeError(MP_ERROR_TEXT("USB audio not enabled for output in boot.py")); - } - - usb_audio_usbspeaker_obj_t *self = mp_obj_malloc_with_finaliser(usb_audio_usbspeaker_obj_t, &usb_audio_USBSpeaker_type); - common_hal_usb_audio_usbspeaker_construct(self); - - return MP_OBJ_FROM_PTR(self); -} -//| def deinit(self) -> None: -//| """Deinitialises the USBSpeaker and releases any resources for reuse.""" -//| ... -//| static mp_obj_t usb_audio_usbspeaker_deinit(mp_obj_t self_in) { usb_audio_usbspeaker_obj_t *self = MP_OBJ_TO_PTR(self_in); common_hal_usb_audio_usbspeaker_deinit(self); @@ -187,7 +160,6 @@ MP_DEFINE_CONST_OBJ_TYPE( usb_audio_USBSpeaker_type, MP_QSTR_USBSpeaker, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, usb_audio_usbspeaker_make_new, locals_dict, &usb_audio_usbspeaker_locals_dict, protocol, &usb_audio_usbspeaker_proto ); diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index 027dc1fa92c..a6c9d06caa9 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -8,7 +8,6 @@ #include "py/runtime.h" #include "shared-bindings/usb_audio/__init__.h" -#include "shared-bindings/usb_audio/Direction.h" #include "shared-bindings/usb_audio/USBMicrophone.h" #include "shared-bindings/usb_audio/USBSpeaker.h" #include "shared-module/usb_audio/__init__.h" @@ -27,7 +26,7 @@ //| `usb_hid` or `usb_midi`. //| //| To enable this mode, you must configure the audio format in ``boot.py`` and then -//| create a `USBMicrophone` in ``code.py``. +//| use the `USBMicrophone` singleton instance in ``code.py``. //| //| .. code-block:: py //| @@ -42,9 +41,11 @@ //| import usb_audio //| import synthio //| -//| # A USBMicrophone is a consumer of an audio sample, just like audioio.AudioOut: -//| # the samples it pulls are streamed to the host PC instead of to a pin. -//| mic = usb_audio.USBMicrophone() +//| # usb_audio.USBMicrophone is a singleton instance (created by enable() above), +//| # not a class you construct. It is a consumer of an audio sample, just like +//| # audioio.AudioOut: the samples it pulls are streamed to the host PC instead +//| # of to a pin. +//| mic = usb_audio.USBMicrophone //| synth = synthio.Synthesizer(sample_rate=16000, channel_count=1) //| mic.play(synth, loop=True) //| @@ -73,7 +74,8 @@ //| sample_rate: int = 16000, //| channel_count: int = 1, //| bits_per_sample: int = 16, -//| direction: Direction = Direction.INPUT, +//| microphone: bool = True, +//| speaker: bool = False, //| ) -> None: //| """Enable the USB audio interface with the given PCM format. //| @@ -82,17 +84,21 @@ //| :param int sample_rate: Samples per second of the streamed audio. //| :param int channel_count: Number of channels. Only mono (1) is supported initially. //| :param int bits_per_sample: Bits per signed PCM sample. Only 16 is supported initially. -//| :param Direction direction: Stream direction relative to the host. ``Direction.INPUT`` -//| (the default) presents a microphone; ``Direction.OUTPUT`` presents a speaker.""" +//| :param bool microphone: Present a microphone (audio flows board -> host). Enabled by default. +//| :param bool speaker: Present a speaker (audio flows host -> board). +//| +//| Enabling both ``microphone`` and ``speaker`` presents a combined headset. At +//| least one of the two must be enabled.""" //| //| static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample_rate, ARG_channel_count, ARG_bits_per_sample, ARG_direction }; + enum { ARG_sample_rate, ARG_channel_count, ARG_bits_per_sample, ARG_microphone, ARG_speaker }; static const mp_arg_t allowed_args[] = { { MP_QSTR_sample_rate, MP_ARG_INT, { .u_int = 16000 } }, { MP_QSTR_channel_count, MP_ARG_INT, { .u_int = 1 } }, { MP_QSTR_bits_per_sample, MP_ARG_INT, { .u_int = 16 } }, - { MP_QSTR_direction, MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_microphone, MP_ARG_BOOL, { .u_bool = true } }, + { MP_QSTR_speaker, MP_ARG_BOOL, { .u_bool = false } }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -100,11 +106,14 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map mp_int_t sample_rate = mp_arg_validate_int_range(args[ARG_sample_rate].u_int, 1, USB_AUDIO_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_N_CHANNELS, MP_QSTR_channel_count); mp_int_t bits_per_sample = mp_arg_validate_int(args[ARG_bits_per_sample].u_int, USB_AUDIO_BITS_PER_SAMPLE, MP_QSTR_bits_per_sample); - usb_audio_direction_t direction = args[ARG_direction].u_obj == MP_OBJ_NULL - ? USB_AUDIO_DIRECTION_INPUT - : validate_direction(args[ARG_direction].u_obj, MP_QSTR_direction); + bool microphone = args[ARG_microphone].u_bool; + bool speaker = args[ARG_speaker].u_bool; + + if (!microphone && !speaker) { + mp_raise_ValueError(MP_ERROR_TEXT("At least one of microphone and speaker must be enabled")); + } - if (!shared_module_usb_audio_enable(sample_rate, channel_count, bits_per_sample, direction)) { + if (!shared_module_usb_audio_enable(sample_rate, channel_count, bits_per_sample, microphone, speaker)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot change USB devices now")); } @@ -112,15 +121,19 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map } static MP_DEFINE_CONST_FUN_OBJ_KW(usb_audio_enable_obj, 0, usb_audio_enable); -static const mp_rom_map_elem_t usb_audio_module_globals_table[] = { +mp_map_elem_t usb_audio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_audio) }, - { MP_ROM_QSTR(MP_QSTR_Direction), MP_ROM_PTR(&usb_audio_direction_type) }, - { MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_ROM_PTR(&usb_audio_USBMicrophone_type) }, - { MP_ROM_QSTR(MP_QSTR_USBSpeaker), MP_ROM_PTR(&usb_audio_USBSpeaker_type) }, - { MP_ROM_QSTR(MP_QSTR_enable), MP_ROM_PTR(&usb_audio_enable_obj) }, + // USBMicrophone and USBSpeaker are not classes you instantiate: they are + // pre-made singleton instances, like usb_midi.ports. usb_audio_setup_singletons() + // replaces these None placeholders with the real instances at the start of + // each VM when the matching direction was enabled in boot.py. + { MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_ROM_NONE }, + { MP_ROM_QSTR(MP_QSTR_USBSpeaker), MP_ROM_NONE }, + { MP_ROM_QSTR(MP_QSTR_enable), MP_OBJ_FROM_PTR(&usb_audio_enable_obj) }, }; -static MP_DEFINE_CONST_DICT(usb_audio_module_globals, usb_audio_module_globals_table); +// This isn't const so the singleton instances can be installed dynamically. +MP_DEFINE_MUTABLE_DICT(usb_audio_module_globals, usb_audio_module_globals_table); const mp_obj_module_t usb_audio_module = { .base = { &mp_type_module }, diff --git a/shared-bindings/usb_audio/__init__.h b/shared-bindings/usb_audio/__init__.h index b0c8d2b9205..f9ad0eeeb78 100644 --- a/shared-bindings/usb_audio/__init__.h +++ b/shared-bindings/usb_audio/__init__.h @@ -6,4 +6,10 @@ #pragma once +#include "py/obj.h" + #include "shared-module/usb_audio/__init__.h" + +// The module globals dict is mutable so the USBMicrophone and USBSpeaker +// singleton instances can be installed at runtime (see usb_audio_setup_singletons). +extern mp_obj_dict_t usb_audio_module_globals; diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 41d8b14ba2c..17ee8cf2955 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -4,6 +4,9 @@ // // SPDX-License-Identifier: MIT +#include "shared-bindings/usb_audio/__init__.h" +#include "shared-bindings/usb_audio/USBMicrophone.h" +#include "shared-bindings/usb_audio/USBSpeaker.h" #include "shared-module/usb_audio/__init__.h" #include "shared-module/usb_audio/USBMicrophone.h" #include "shared-module/usb_audio/USBSpeaker.h" @@ -12,6 +15,9 @@ #include #include "py/misc.h" +#include "py/mphal.h" +#include "py/runtime.h" +#include "supervisor/shared/tick.h" #include "tusb.h" static bool usb_audio_is_enabled = false; @@ -31,13 +37,14 @@ static uint8_t usb_audio_spk_as_itf = 0xff; uint32_t usb_audio_sample_rate; uint8_t usb_audio_channel_count; uint8_t usb_audio_bits_per_sample; -usb_audio_direction_t usb_audio_direction; +bool usb_audio_microphone_enabled; +bool usb_audio_speaker_enabled; // Audio control state surfaced to the host. One extra entry for the master channel 0. static int8_t usb_audio_mute[USB_AUDIO_N_CHANNELS + 1]; static int16_t usb_audio_volume[USB_AUDIO_N_CHANNELS + 1]; -bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, usb_audio_direction_t direction) { +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, bool microphone, bool speaker) { if (tud_connected()) { return false; } @@ -45,7 +52,8 @@ bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count usb_audio_sample_rate = sample_rate; usb_audio_channel_count = channel_count; usb_audio_bits_per_sample = bits_per_sample; - usb_audio_direction = direction; + usb_audio_microphone_enabled = microphone; + usb_audio_speaker_enabled = speaker; usb_audio_is_enabled = true; return true; @@ -74,6 +82,50 @@ bool usb_audio_speaker_streaming(void) { return usb_audio_spk_streaming; } +void usb_audio_setup_singletons(void) { + // USBMicrophone and USBSpeaker are singletons rather than constructible + // classes (like usb_midi.ports). The host-facing format and direction are + // fixed by usb_audio.enable() in boot.py and persist in C globals, but the + // instances themselves live on the GC heap, which is reset between boot.py + // and code.py, so they are rebuilt here once per VM. Each is created only + // when its direction was enabled; otherwise it is left as None. + // + // The objects are held in MP_STATE_VM root pointers so the GC keeps them + // alive for the whole VM (the module globals table is static data and is not + // a GC root, so a reference from there alone would be swept). Rooting the + // microphone also traces its bound audiosample (self->sample). They are then + // installed in the module globals so they are reachable as the + // usb_audio.USBMicrophone / usb_audio.USBSpeaker attributes. + mp_obj_t microphone = mp_const_none; + mp_obj_t speaker = mp_const_none; + + if (usb_audio_is_enabled) { + const bool has_input = usb_audio_microphone_enabled; + const bool has_output = usb_audio_speaker_enabled; + + if (has_input) { + usb_audio_usbmicrophone_obj_t *self = + mp_obj_malloc_with_finaliser(usb_audio_usbmicrophone_obj_t, &usb_audio_USBMicrophone_type); + common_hal_usb_audio_usbmicrophone_construct(self); + microphone = MP_OBJ_FROM_PTR(self); + } + if (has_output) { + usb_audio_usbspeaker_obj_t *self = + mp_obj_malloc_with_finaliser(usb_audio_usbspeaker_obj_t, &usb_audio_USBSpeaker_type); + common_hal_usb_audio_usbspeaker_construct(self); + speaker = MP_OBJ_FROM_PTR(self); + } + } + + MP_STATE_VM(usb_audio_microphone_singleton) = microphone; + MP_STATE_VM(usb_audio_speaker_singleton) = speaker; + + mp_map_lookup(&usb_audio_module_globals.map, MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_MAP_LOOKUP)->value = + microphone; + mp_map_lookup(&usb_audio_module_globals.map, MP_ROM_QSTR(MP_QSTR_USBSpeaker), MP_MAP_LOOKUP)->value = + speaker; +} + // Hand-rolled UAC2 mono speaker (host -> board) descriptor WITHOUT an async // feedback endpoint. This mirrors TinyUSB's TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR // (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so @@ -110,7 +162,7 @@ bool usb_audio_speaker_streaming(void) { /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) -// Hand-rolled UAC2 mono headset (Direction.INPUT_OUTPUT): one audio function +// Hand-rolled UAC2 mono headset (microphone + speaker both enabled): one audio function // presenting both a speaker (host -> board OUT) and a microphone (board -> host // IN) at once. This combines USB_AUDIO_SPEAKER_DESCRIPTOR's speaker chain with // TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR's mic chain under a single IAD. The two chains @@ -170,12 +222,15 @@ bool usb_audio_speaker_streaming(void) { /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) +// Combined headset: both a microphone (board -> host IN) and a speaker +// (host -> board OUT) under one audio function. static bool usb_audio_direction_is_input_output(void) { - return usb_audio_direction == USB_AUDIO_DIRECTION_INPUT_OUTPUT; + return usb_audio_microphone_enabled && usb_audio_speaker_enabled; } +// Speaker only (host -> board OUT), no microphone. static bool usb_audio_direction_is_output(void) { - return usb_audio_direction == USB_AUDIO_DIRECTION_OUTPUT; + return usb_audio_speaker_enabled && !usb_audio_microphone_enabled; } size_t usb_audio_descriptor_length(void) { @@ -560,3 +615,9 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p return false; } + +// Keep the per-VM singleton instances (and, for the microphone, its bound +// audiosample) alive for the GC. Installed in the module globals by +// usb_audio_setup_singletons() and reset to NULL at each VM start. +MP_REGISTER_ROOT_POINTER(mp_obj_t usb_audio_microphone_singleton); +MP_REGISTER_ROOT_POINTER(mp_obj_t usb_audio_speaker_singleton); diff --git a/shared-module/usb_audio/__init__.h b/shared-module/usb_audio/__init__.h index a275996f7a6..4e1dba923f7 100644 --- a/shared-module/usb_audio/__init__.h +++ b/shared-module/usb_audio/__init__.h @@ -13,12 +13,11 @@ #include "py/obj.h" #include "supervisor/usb.h" -#include "shared-bindings/usb_audio/Direction.h" - // Enable/disable the USB Audio Class (UAC2) interface. These may only be // called before USB is connected (i.e. from boot.py); they return false -// otherwise. -bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, usb_audio_direction_t direction); +// otherwise. At least one of microphone/speaker must be true; enabling both +// presents a combined headset. +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, bool microphone, bool speaker); bool shared_module_usb_audio_disable(void); // True once enable() has been called successfully. @@ -39,8 +38,10 @@ extern uint32_t usb_audio_sample_rate; extern uint8_t usb_audio_channel_count; extern uint8_t usb_audio_bits_per_sample; -// Stream direction requested in enable(), valid when usb_audio_enabled() is true. -extern usb_audio_direction_t usb_audio_direction; +// Which streams were requested in enable(), valid when usb_audio_enabled() is +// true. Both true presents a combined headset. +extern bool usb_audio_microphone_enabled; +extern bool usb_audio_speaker_enabled; // Descriptor injection hooks, called from supervisor/shared/usb/usb_desc.c. size_t usb_audio_descriptor_length(void); @@ -49,3 +50,11 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de // Background task that streams samples to the host, called from // supervisor/shared/usb/usb.c. void usb_audio_task(void); + +// (Re)create the USBMicrophone and USBSpeaker singleton instances for the +// current VM and install them as the usb_audio.USBMicrophone and +// usb_audio.USBSpeaker module attributes (or None when that direction was not +// enabled in boot.py). Called once per VM from usb_setup_with_vm(), mirroring +// usb_midi_setup_ports(): the instances live on the GC heap, which is reset +// between boot.py and code.py, so they must be rebuilt each time. +void usb_audio_setup_singletons(void); diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 20103b1907c..1313e198959 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -54,7 +54,7 @@ size_t usb_audio_descriptor_length(void); #define USB_AUDIO_ENTITY_OUTPUT_TERMINAL (0x03) #define USB_AUDIO_ENTITY_CLOCK_SOURCE (0x04) -// Combined headset (Direction.INPUT_OUTPUT) topology. A single audio function +// Combined headset (microphone + speaker both enabled) topology. A single audio function // carries both a speaker chain (host -> board) and a mic chain (board -> host), // so every unit/terminal needs an ID unique across the whole function -- unlike // the single-direction descriptors above, which can reuse the same small set. @@ -90,7 +90,7 @@ size_t usb_audio_descriptor_length(void); + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) -// Length of the combined headset descriptor (Direction.INPUT_OUTPUT): one IAD +// Length of the combined headset descriptor (microphone + speaker both enabled): one IAD // wrapping a single AudioControl interface plus two AudioStreaming interfaces // (speaker OUT + mic IN). The AC interface declares one shared clock, plus an // input terminal / feature unit / output terminal for each of the two chains; diff --git a/supervisor/shared/usb.c b/supervisor/shared/usb.c index ff0dd1f8467..3aa24e62675 100644 --- a/supervisor/shared/usb.c +++ b/supervisor/shared/usb.c @@ -25,6 +25,10 @@ #include "shared-module/usb_midi/__init__.h" #endif +#if CIRCUITPY_USB_AUDIO +#include "shared-module/usb_audio/__init__.h" +#endif + #if CIRCUITPY_USB_VIDEO #include "shared-module/usb_video/__init__.h" #endif @@ -61,5 +65,9 @@ void usb_setup_with_vm(void) { #if CIRCUITPY_USB_MIDI usb_midi_setup_ports(); #endif + + #if CIRCUITPY_USB_AUDIO + usb_audio_setup_singletons(); + #endif #endif } diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 63c0b903b1c..1f40cebd0d2 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -185,7 +185,6 @@ ifeq ($(CIRCUITPY_TINYUSB),1) ifeq ($(CIRCUITPY_USB_AUDIO), 1) SRC_SUPERVISOR += \ shared-bindings/usb_audio/__init__.c \ - shared-bindings/usb_audio/Direction.c \ shared-module/usb_audio/__init__.c \ shared-bindings/usb_audio/USBMicrophone.c \ shared-module/usb_audio/USBMicrophone.c \ From d65c998e11c58e3d25205c8ba8fdad5b1c66a8c1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 22 Jun 2026 08:43:17 -0500 Subject: [PATCH 574/876] remove Direction files --- shared-bindings/usb_audio/Direction.c | 51 --------------------------- shared-bindings/usb_audio/Direction.h | 20 ----------- 2 files changed, 71 deletions(-) delete mode 100644 shared-bindings/usb_audio/Direction.c delete mode 100644 shared-bindings/usb_audio/Direction.h diff --git a/shared-bindings/usb_audio/Direction.c b/shared-bindings/usb_audio/Direction.c deleted file mode 100644 index 1dbe17c11aa..00000000000 --- a/shared-bindings/usb_audio/Direction.c +++ /dev/null @@ -1,51 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC -// -// SPDX-License-Identifier: MIT - -#include "py/obj.h" -#include "py/enum.h" -#include "py/runtime.h" - -#include "shared-bindings/usb_audio/Direction.h" - -MAKE_ENUM_VALUE(usb_audio_direction_type, direction, INPUT, USB_AUDIO_DIRECTION_INPUT); -MAKE_ENUM_VALUE(usb_audio_direction_type, direction, OUTPUT, USB_AUDIO_DIRECTION_OUTPUT); -MAKE_ENUM_VALUE(usb_audio_direction_type, direction, INPUT_OUTPUT, USB_AUDIO_DIRECTION_INPUT_OUTPUT); - -//| class Direction: -//| """The direction of a USB audio stream, relative to the host computer.""" -//| -//| def __init__(self) -> None: -//| """Enum-like class to define the USB audio stream direction.""" -//| ... -//| -//| INPUT: Direction -//| """Audio flows board -> host: the board appears as a USB microphone -//| (audio *source*). This is the default.""" -//| -//| OUTPUT: Direction -//| """Audio flows host -> board: the board appears as a USB speaker -//| (audio *sink*).""" -//| -//| INPUT_OUTPUT: Direction -//| """Audio flows in both directions: the board appears as a USB headset -//| (microphone + speaker).""" -//| -//| -MAKE_ENUM_MAP(usb_audio_direction) { - MAKE_ENUM_MAP_ENTRY(direction, INPUT), - MAKE_ENUM_MAP_ENTRY(direction, OUTPUT), - MAKE_ENUM_MAP_ENTRY(direction, INPUT_OUTPUT), -}; - -static MP_DEFINE_CONST_DICT(usb_audio_direction_locals_dict, usb_audio_direction_locals_table); - -MAKE_PRINTER(usb_audio, usb_audio_direction); - -MAKE_ENUM_TYPE(usb_audio, Direction, usb_audio_direction); - -usb_audio_direction_t validate_direction(mp_obj_t obj, qstr arg_name) { - return cp_enum_value(&usb_audio_direction_type, obj, arg_name); -} diff --git a/shared-bindings/usb_audio/Direction.h b/shared-bindings/usb_audio/Direction.h deleted file mode 100644 index 53ad3be16c4..00000000000 --- a/shared-bindings/usb_audio/Direction.h +++ /dev/null @@ -1,20 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks Adafruit Industries LLC -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/enum.h" -#include "py/obj.h" - -typedef enum _usb_audio_direction_t { - USB_AUDIO_DIRECTION_INPUT, - USB_AUDIO_DIRECTION_OUTPUT, - USB_AUDIO_DIRECTION_INPUT_OUTPUT, -} usb_audio_direction_t; - -extern const mp_obj_type_t usb_audio_direction_type; - -usb_audio_direction_t validate_direction(mp_obj_t obj, qstr arg_name); From 076f3c5f05377c608964a2472ac04aa821b95f85 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 22 Jun 2026 13:48:35 -0500 Subject: [PATCH 575/876] use usb_microphone and usb_speaker as the names for the singletons --- shared-bindings/usb_audio/USBMicrophone.c | 4 +-- shared-bindings/usb_audio/USBSpeaker.c | 6 ++-- shared-bindings/usb_audio/__init__.c | 35 +++++++++++++++++------ shared-module/usb_audio/__init__.c | 6 ++-- shared-module/usb_audio/__init__.h | 4 +-- 5 files changed, 36 insertions(+), 19 deletions(-) diff --git a/shared-bindings/usb_audio/USBMicrophone.c b/shared-bindings/usb_audio/USBMicrophone.c index 11524bd06de..ff53d812e49 100644 --- a/shared-bindings/usb_audio/USBMicrophone.c +++ b/shared-bindings/usb_audio/USBMicrophone.c @@ -23,9 +23,9 @@ //| //| You cannot create an instance of `usb_audio.USBMicrophone`. //| -//| There is a single shared instance, available as ``usb_audio.USBMicrophone`` +//| There is a single shared instance, available as ``usb_audio.usb_microphone`` //| once ``usb_audio.enable()`` has configured an input (microphone) stream in -//| ``boot.py``. Until then ``usb_audio.USBMicrophone`` is ``None``.""" +//| ``boot.py``. Until then ``usb_audio.usb_microphone`` is ``None``.""" //| diff --git a/shared-bindings/usb_audio/USBSpeaker.c b/shared-bindings/usb_audio/USBSpeaker.c index 1407d50e55c..93fc01d1ddf 100644 --- a/shared-bindings/usb_audio/USBSpeaker.c +++ b/shared-bindings/usb_audio/USBSpeaker.c @@ -25,9 +25,9 @@ //| //| You cannot create an instance of `usb_audio.USBSpeaker`. //| -//| There is a single shared instance, available as ``usb_audio.USBSpeaker`` +//| There is a single shared instance, available as ``usb_audio.usb_speaker`` //| once ``usb_audio.enable()`` has configured an output (speaker) stream in -//| ``boot.py``. Until then ``usb_audio.USBSpeaker`` is ``None``. +//| ``boot.py``. Until then ``usb_audio.usb_speaker`` is ``None``. //| //| .. code-block:: py //| @@ -43,7 +43,7 @@ //| import usb_audio //| import audiobusio //| -//| spk = usb_audio.USBSpeaker +//| spk = usb_audio.usb_speaker //| out = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) //| out.play(spk, loop=True) //| diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index a6c9d06caa9..49eaa9716f2 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -26,7 +26,7 @@ //| `usb_hid` or `usb_midi`. //| //| To enable this mode, you must configure the audio format in ``boot.py`` and then -//| use the `USBMicrophone` singleton instance in ``code.py``. +//| use the `usb_microphone` singleton instance in ``code.py``. //| //| .. code-block:: py //| @@ -41,11 +41,11 @@ //| import usb_audio //| import synthio //| -//| # usb_audio.USBMicrophone is a singleton instance (created by enable() above), +//| # usb_audio.usb_microphone is a singleton instance (created by enable() above), //| # not a class you construct. It is a consumer of an audio sample, just like //| # audioio.AudioOut: the samples it pulls are streamed to the host PC instead //| # of to a pin. -//| mic = usb_audio.USBMicrophone +//| mic = usb_audio.usb_microphone //| synth = synthio.Synthesizer(sample_rate=16000, channel_count=1) //| mic.play(synth, loop=True) //| @@ -70,6 +70,17 @@ //| //| +//| usb_microphone: Optional[USBMicrophone] +//| """The shared `USBMicrophone` singleton instance, or ``None`` until +//| ``usb_audio.enable()`` has configured an input (microphone) stream in ``boot.py``. +//| `USBMicrophone` is exposed only as a type; you do not construct it.""" +//| +//| usb_speaker: Optional[USBSpeaker] +//| """The shared `USBSpeaker` singleton instance, or ``None`` until +//| ``usb_audio.enable()`` has configured an output (speaker) stream in ``boot.py``. +//| `USBSpeaker` is exposed only as a type; you do not construct it.""" +//| + //| def enable( //| sample_rate: int = 16000, //| channel_count: int = 1, @@ -123,12 +134,18 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(usb_audio_enable_obj, 0, usb_audio_enable); mp_map_elem_t usb_audio_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usb_audio) }, - // USBMicrophone and USBSpeaker are not classes you instantiate: they are - // pre-made singleton instances, like usb_midi.ports. usb_audio_setup_singletons() - // replaces these None placeholders with the real instances at the start of - // each VM when the matching direction was enabled in boot.py. - { MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_ROM_NONE }, - { MP_ROM_QSTR(MP_QSTR_USBSpeaker), MP_ROM_NONE }, + // USBMicrophone and USBSpeaker are the classes, exposed only for typing and + // isinstance() checks; you do not construct them. The usable objects are the + // pre-made singleton instances installed at the usb_microphone / usb_speaker + // attributes below. + { MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_OBJ_FROM_PTR(&usb_audio_USBMicrophone_type) }, + { MP_ROM_QSTR(MP_QSTR_USBSpeaker), MP_OBJ_FROM_PTR(&usb_audio_USBSpeaker_type) }, + // usb_microphone and usb_speaker are the singleton instances, like + // usb_midi.ports. usb_audio_setup_singletons() replaces these None + // placeholders with the real instances at the start of each VM when the + // matching direction was enabled in boot.py. + { MP_ROM_QSTR(MP_QSTR_usb_microphone), MP_ROM_NONE }, + { MP_ROM_QSTR(MP_QSTR_usb_speaker), MP_ROM_NONE }, { MP_ROM_QSTR(MP_QSTR_enable), MP_OBJ_FROM_PTR(&usb_audio_enable_obj) }, }; diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 17ee8cf2955..5964b8acf78 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -95,7 +95,7 @@ void usb_audio_setup_singletons(void) { // a GC root, so a reference from there alone would be swept). Rooting the // microphone also traces its bound audiosample (self->sample). They are then // installed in the module globals so they are reachable as the - // usb_audio.USBMicrophone / usb_audio.USBSpeaker attributes. + // usb_audio.usb_microphone / usb_audio.usb_speaker attributes. mp_obj_t microphone = mp_const_none; mp_obj_t speaker = mp_const_none; @@ -120,9 +120,9 @@ void usb_audio_setup_singletons(void) { MP_STATE_VM(usb_audio_microphone_singleton) = microphone; MP_STATE_VM(usb_audio_speaker_singleton) = speaker; - mp_map_lookup(&usb_audio_module_globals.map, MP_ROM_QSTR(MP_QSTR_USBMicrophone), MP_MAP_LOOKUP)->value = + mp_map_lookup(&usb_audio_module_globals.map, MP_ROM_QSTR(MP_QSTR_usb_microphone), MP_MAP_LOOKUP)->value = microphone; - mp_map_lookup(&usb_audio_module_globals.map, MP_ROM_QSTR(MP_QSTR_USBSpeaker), MP_MAP_LOOKUP)->value = + mp_map_lookup(&usb_audio_module_globals.map, MP_ROM_QSTR(MP_QSTR_usb_speaker), MP_MAP_LOOKUP)->value = speaker; } diff --git a/shared-module/usb_audio/__init__.h b/shared-module/usb_audio/__init__.h index 4e1dba923f7..8ec13f90853 100644 --- a/shared-module/usb_audio/__init__.h +++ b/shared-module/usb_audio/__init__.h @@ -52,8 +52,8 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de void usb_audio_task(void); // (Re)create the USBMicrophone and USBSpeaker singleton instances for the -// current VM and install them as the usb_audio.USBMicrophone and -// usb_audio.USBSpeaker module attributes (or None when that direction was not +// current VM and install them as the usb_audio.usb_microphone and +// usb_audio.usb_speaker module attributes (or None when that direction was not // enabled in boot.py). Called once per VM from usb_setup_with_vm(), mirroring // usb_midi_setup_ports(): the instances live on the GC heap, which is reset // between boot.py and code.py, so they must be rebuilt each time. From 1b3636e24b51651bc7afa88755815b845048233f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 22 Jun 2026 21:07:48 -0500 Subject: [PATCH 576/876] correct usb_speaker example code --- shared-bindings/usb_audio/USBSpeaker.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared-bindings/usb_audio/USBSpeaker.c b/shared-bindings/usb_audio/USBSpeaker.c index 93fc01d1ddf..d9302886c64 100644 --- a/shared-bindings/usb_audio/USBSpeaker.c +++ b/shared-bindings/usb_audio/USBSpeaker.c @@ -46,6 +46,8 @@ //| spk = usb_audio.usb_speaker //| out = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WORD_SELECT, board.I2S_DATA) //| out.play(spk, loop=True) +//| while True: +//| pass //| //| """ From 2a011266c1ca34ec85717bfb3389e6ee65105a47 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 23 Jun 2026 15:16:41 +0200 Subject: [PATCH 577/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 12 ++++++++---- locale/el.po | 12 ++++++++---- locale/hi.po | 12 ++++++++---- locale/ko.po | 12 ++++++++---- locale/ru.po | 12 ++++++++---- locale/tr.po | 12 ++++++++---- 6 files changed, 48 insertions(+), 24 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 3e64021b216..391f584538c 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -636,6 +636,10 @@ msgstr "Hodnoty pole by měly být jednoduché bajty." msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -2295,10 +2299,6 @@ msgstr "Zápis na UART" msgid "UID:" msgstr "UID:" -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "USB audio not enabled in boot.py" -msgstr "" - #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "USB zaneprázdněno" @@ -3146,6 +3146,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" diff --git a/locale/el.po b/locale/el.po index 052d61e489b..58dc89efbbf 100644 --- a/locale/el.po +++ b/locale/el.po @@ -640,6 +640,10 @@ msgstr "Η τιμές της παράταξη πρέπει να είναι μο msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -2299,10 +2303,6 @@ msgstr "" msgid "UID:" msgstr "" -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "USB audio not enabled in boot.py" -msgstr "" - #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" @@ -3145,6 +3145,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index 428a68ae748..82bd5134d7d 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -627,6 +627,10 @@ msgstr "" msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -2273,10 +2277,6 @@ msgstr "" msgid "UID:" msgstr "UID:" -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "USB audio not enabled in boot.py" -msgstr "" - #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" @@ -3119,6 +3119,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 9eff441710f..ab0baa73d7f 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -666,6 +666,10 @@ msgstr "배열 값은 1바이트 여야합니다." msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -2346,10 +2350,6 @@ msgstr "" msgid "UID:" msgstr "UID:" -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "USB audio not enabled in boot.py" -msgstr "" - #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" @@ -3193,6 +3193,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index 1ec1233fcff..5866d5bb5f7 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -640,6 +640,10 @@ msgstr "Значения массива должны быть однобайто msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -2329,10 +2333,6 @@ msgstr "Запись UART" msgid "UID:" msgstr "UID:" -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "USB audio not enabled in boot.py" -msgstr "" - #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "USB занят" @@ -3200,6 +3200,10 @@ msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" "буфер назначения должен быть массивом типа «H» для битовой_глубины = 16" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "последовательность обновления дикта имеет неправильную длину" diff --git a/locale/tr.po b/locale/tr.po index 60370c5fa56..19bf9557473 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -638,6 +638,10 @@ msgstr "Dizi değerleri tekil bytelar olmalıdır." msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" + #: shared-module/memorymonitor/AllocationAlarm.c #, c-format msgid "Attempt to allocate %d blocks" @@ -2295,10 +2299,6 @@ msgstr "" msgid "UID:" msgstr "UID:" -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "USB audio not enabled in boot.py" -msgstr "" - #: shared-module/usb_hid/Device.c msgid "USB busy" msgstr "" @@ -3141,6 +3141,10 @@ msgstr "" msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" + #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" From 2eeebdb2fb0d829ee813998f19e9ad349e8aa536 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 23 Jun 2026 10:47:20 -0500 Subject: [PATCH 578/876] disable audioi2sin on esp32c6/c61 and memento --- ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk | 1 + ports/espressif/mpconfigport.mk | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk b/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk index d1b6d503125..62b6d3612b3 100644 --- a/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk +++ b/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.mk @@ -16,6 +16,7 @@ CIRCUITPY_ESP_PSRAM_FREQ = 80m CIRCUITPY_ESPCAMERA = 1 CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 CIRCUITPY_CANIO = 0 CIRCUITPY_DUALBANK = 0 CIRCUITPY_FRAMEBUFFERIO = 0 diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 310743063f4..64f61dba7c1 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -206,6 +206,7 @@ CIRCUITPY_AUDIOBUSIO_PDMIN = 0 # No space for this CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 @@ -234,6 +235,7 @@ CIRCUITPY_AUDIOIO = 0 # No space for this CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOI2SIN = 0 # No I80 support from the IDF CIRCUITPY_PARALLELDISPLAYBUS = 0 From 78d44093eae7f3b3d459bd4d836ee7140d560f41 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 23 Jun 2026 10:49:44 -0500 Subject: [PATCH 579/876] disable audioi2sin on esp32c3 --- ports/espressif/mpconfigport.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 64f61dba7c1..f7a14f83202 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -173,6 +173,7 @@ CIRCUITPY_AUDIOIO = 0 # No I2S peripheral PDM-to-PCM hardware support CIRCUITPY_AUDIOBUSIO_PDMIN = 0 +CIRCUITPY_AUDIOI2SIN = 0 # No PCNT peripheral CIRCUITPY_FREQUENCYIO = 0 From 7553fc53e4d54c72254d616acd4afcdc1287451e Mon Sep 17 00:00:00 2001 From: Bernhard Bablok Date: Tue, 23 Jun 2026 21:12:35 +0200 Subject: [PATCH 580/876] verify CS pin is not None --- shared-module/sdcardio/SDCard.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index 7ed9d607c47..40d09aa99ca 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -345,10 +345,8 @@ mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio // Allocate the pins in the same place as self. bool use_port_allocation = !gc_alloc_possible() || !gc_ptr_on_heap(self); - self->cs = digitalinout_protocol_from_pin(cs, MP_QSTR_cs, true, use_port_allocation, &self->own_cs); - if (self->cs != mp_const_none) { - digitalinout_protocol_switch_to_output(self->cs, true, DRIVE_MODE_PUSH_PULL); - } + self->cs = digitalinout_protocol_from_pin(cs, MP_QSTR_cs, false, use_port_allocation, &self->own_cs); + digitalinout_protocol_switch_to_output(self->cs, true, DRIVE_MODE_PUSH_PULL); self->cdv = 512; self->sectors = 0; @@ -361,7 +359,7 @@ mp_rom_error_text_t sdcardio_sdcard_construct(sdcardio_sdcard_obj_t *self, busio extraclock_and_unlock_bus(self); if (result != NULL) { - if (self->cs != mp_const_none && self->own_cs) { + if (self->own_cs) { digitalinout_protocol_deinit(self->cs); circuitpy_free_obj(self->cs); } @@ -387,7 +385,7 @@ void common_hal_sdcardio_sdcard_deinit(sdcardio_sdcard_obj_t *self) { } common_hal_sdcardio_sdcard_sync(self); common_hal_sdcardio_sdcard_mark_deinit(self); - if (self->cs != mp_const_none && self->own_cs) { + if (self->own_cs) { digitalinout_protocol_deinit(self->cs); circuitpy_free_obj(self->cs); } From f225c9fe5b8c63d29460d00151b3cf1627a042c1 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 23 Jun 2026 21:55:01 +0200 Subject: [PATCH 581/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 5 +++++ locale/el.po | 5 +++++ locale/hi.po | 5 +++++ locale/ko.po | 5 +++++ locale/ru.po | 5 +++++ locale/tr.po | 5 +++++ 6 files changed, 30 insertions(+) diff --git a/locale/cs.po b/locale/cs.po index 391f584538c..e4a09a220ee 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -201,6 +201,11 @@ msgstr "%q musí být 1, pokud %q je True" msgid "%q must be 16, 24, or 32" msgstr "" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" + #: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" diff --git a/locale/el.po b/locale/el.po index 58dc89efbbf..f4294d794a8 100644 --- a/locale/el.po +++ b/locale/el.po @@ -205,6 +205,11 @@ msgstr "%q πρέπει να είναι 1 όταν %q είναι True" msgid "%q must be 16, 24, or 32" msgstr "" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" + #: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" diff --git a/locale/hi.po b/locale/hi.po index 82bd5134d7d..21b28028a29 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -192,6 +192,11 @@ msgstr "" msgid "%q must be 16, 24, or 32" msgstr "" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" + #: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" diff --git a/locale/ko.po b/locale/ko.po index ab0baa73d7f..4789c8a566b 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -203,6 +203,11 @@ msgstr "%q가 참일 때 %q는 1이어야 합니다" msgid "%q must be 16, 24, or 32" msgstr "" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" + #: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" diff --git a/locale/ru.po b/locale/ru.po index 5866d5bb5f7..a88c6cbbea3 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -205,6 +205,11 @@ msgstr "%q должен быть равен 1, если %q имеет значе msgid "%q must be 16, 24, or 32" msgstr "" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" + #: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" diff --git a/locale/tr.po b/locale/tr.po index 19bf9557473..2ff8c837768 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -203,6 +203,11 @@ msgstr "%q 1 olmalı, %q True olduğu zaman" msgid "%q must be 16, 24, or 32" msgstr "" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" + #: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" From d73e3435e75b2bd5e7bb466831f0dbc6e22166a1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 24 Jun 2026 11:38:05 -0500 Subject: [PATCH 582/876] remove buffer function wrappers, remove output_bit_depth property, cleanup comments --- ports/espressif/common-hal/audioi2sin/I2SIn.c | 15 +++---- ports/espressif/common-hal/audioi2sin/I2SIn.h | 3 +- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 15 +++---- .../raspberrypi/common-hal/audioi2sin/I2SIn.h | 3 +- shared-bindings/audioi2sin/I2SIn.c | 42 +++---------------- shared-bindings/audioi2sin/I2SIn.h | 1 - 6 files changed, 18 insertions(+), 61 deletions(-) diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index c270f500305..ef8e908e2de 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -65,7 +65,6 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, self->mclk = main_clock; self->sample_rate = sample_rate; self->bit_depth = bit_depth; - self->output_bit_depth = output_bit_depth; self->mono = mono; self->samples_signed = samples_signed; @@ -222,11 +221,11 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se element_size = 4; } - if (self->output_bit_depth != self->bit_depth) { + if (self->base.bits_per_sample != self->bit_depth) { // Bit-depth conversion path: always read at input width into scratch, // convert each sample into the user's buffer at output width. const uint8_t in_depth = self->bit_depth; - const uint8_t out_depth = self->output_bit_depth; + const uint8_t out_depth = self->base.bits_per_sample; const bool samples_signed = self->samples_signed; uint8_t scratch[256]; const size_t in_frame_bytes = 2 * element_size; @@ -313,10 +312,6 @@ uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) return self->bit_depth; } -uint8_t common_hal_audioi2sin_i2sin_get_output_bit_depth(audioi2sin_i2sin_obj_t *self) { - return self->output_bit_depth; -} - uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self) { return self->sample_rate; } @@ -351,7 +346,7 @@ static void i2sin_fill_silence(void *buffer, uint32_t idx, uint32_t count, void common_hal_audioi2sin_i2sin_fill_buffer(audioi2sin_i2sin_obj_t *self, uint8_t *buffer, uint32_t frames) { const uint8_t in_depth = self->bit_depth; - const uint8_t out_depth = self->output_bit_depth; + const uint8_t out_depth = self->base.bits_per_sample; const bool samples_signed = self->samples_signed; const bool stereo = !self->mono; const uint8_t channel_count = stereo ? 2 : 1; @@ -406,7 +401,7 @@ void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, (void)channel; // The audio pipeline only carries 8- or 16-bit samples; 24/32-bit modes can // still record() but cannot stream. - if (self->output_bit_depth != 8 && self->output_bit_depth != 16) { + if (self->base.bits_per_sample != 8 && self->base.bits_per_sample != 16) { mp_raise_ValueError_varg( MP_ERROR_TEXT("%q must be 8 or 16"), MP_QSTR_output_bit_depth); } @@ -426,7 +421,7 @@ audioio_get_buffer_result_t common_hal_audioi2sin_i2sin_get_buffer( uint8_t *out = self->output_buffer + half * self->output_index; self->output_index = 1 - self->output_index; - uint32_t bytes_per_sample = self->output_bit_depth / 8; + uint32_t bytes_per_sample = self->base.bits_per_sample / 8; uint32_t frames = half / (bytes_per_sample * self->base.channel_count); common_hal_audioi2sin_i2sin_fill_buffer(self, out, frames); diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.h b/ports/espressif/common-hal/audioi2sin/I2SIn.h index 4d5e1b4127a..a6fc7224c32 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.h +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.h @@ -21,7 +21,7 @@ #define AUDIOI2SIN_STREAM_FRAMES (256) typedef struct { - // MUST be first so I2SIn can be used directly as an audiosample source. + // so I2SIn can be used directly as an audiosample source. audiosample_base_t base; i2s_chan_handle_t rx_chan; const mcu_pin_obj_t *bit_clock; @@ -30,7 +30,6 @@ typedef struct { const mcu_pin_obj_t *mclk; uint32_t sample_rate; uint8_t bit_depth; - uint8_t output_bit_depth; bool mono; bool samples_signed; // Owned double-buffer of converted (output-depth, interleaved) samples, diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 8f4fc880045..8bdc4cfeb3b 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -267,7 +267,6 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); self->sample_rate = actual_frequency / pio_clocks_per_frame; self->bit_depth = bit_depth; - self->output_bit_depth = output_bit_depth; self->mono = mono; self->samples_signed = samples_signed; self->left_justified = left_justified; @@ -362,10 +361,6 @@ uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self) return self->bit_depth; } -uint8_t common_hal_audioi2sin_i2sin_get_output_bit_depth(audioi2sin_i2sin_obj_t *self) { - return self->output_bit_depth; -} - uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self) { return self->sample_rate; } @@ -456,7 +451,7 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se // convention. The default (no-conversion) path applies the flip to the // raw FIFO word before splitting into channels; the conversion path // applies the flip per output sample at output bit width. - const bool convert = self->output_bit_depth != self->bit_depth; + const bool convert = self->base.bits_per_sample != self->bit_depth; const uint32_t flip16 = (!convert && !self->samples_signed) ? 0x80008000u : 0u; const uint32_t flip32 = (!convert && !self->samples_signed) ? (self->bit_depth == 24 ? 0x800000u : 0x80000000u) @@ -466,7 +461,7 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se && self->samples_signed && !self->left_justified; const uint8_t in_depth = self->bit_depth; - const uint8_t out_depth = self->output_bit_depth; + const uint8_t out_depth = self->base.bits_per_sample; const bool left_justified = self->left_justified; const bool samples_signed = self->samples_signed; @@ -633,7 +628,7 @@ void common_hal_audioi2sin_i2sin_fill_buffer(audioi2sin_i2sin_obj_t *self, const size_t ring_size = self->ring_size; const size_t half_size = self->half_size; const uint8_t in_depth = self->bit_depth; - const uint8_t out_depth = self->output_bit_depth; + const uint8_t out_depth = self->base.bits_per_sample; const bool samples_signed = self->samples_signed; const bool left_justified = self->left_justified; const bool stereo = !self->mono; @@ -701,7 +696,7 @@ void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, // The audio pipeline only carries 8- or 16-bit samples. 24/32-bit modes can // still record() but cannot stream; fail clearly the first time playback is // set up rather than emitting garbage. - if (self->output_bit_depth != 8 && self->output_bit_depth != 16) { + if (self->base.bits_per_sample != 8 && self->base.bits_per_sample != 16) { mp_raise_ValueError_varg( MP_ERROR_TEXT("%q must be 8 or 16"), MP_QSTR_output_bit_depth); } @@ -731,7 +726,7 @@ audioio_get_buffer_result_t common_hal_audioi2sin_i2sin_get_buffer( uint8_t *out = self->output_buffer + half * self->output_index; self->output_index = 1 - self->output_index; - uint32_t bytes_per_sample = self->output_bit_depth / 8; + uint32_t bytes_per_sample = self->base.bits_per_sample / 8; uint32_t frames = half / (bytes_per_sample * self->base.channel_count); common_hal_audioi2sin_i2sin_fill_buffer(self, out, frames); diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h index fc17507d2c8..bd5cdea577e 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -20,11 +20,10 @@ #define AUDIOI2SIN_STREAM_FRAMES (256) typedef struct { - // MUST be first so I2SIn can be used directly as an audiosample source. + // so I2SIn can be used directly as an audiosample source. audiosample_base_t base; uint32_t sample_rate; uint8_t bit_depth; - uint8_t output_bit_depth; bool mono; bool samples_signed; bool left_justified; diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 00303a7b7c5..056aa859abe 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -206,7 +206,7 @@ static mp_obj_t audioi2sin_i2sin_obj_record(mp_obj_t self_obj, mp_obj_t destinat if (bufinfo.len / mp_binary_get_size('@', bufinfo.typecode, NULL) < length) { mp_raise_ValueError(MP_ERROR_TEXT("Destination capacity is smaller than destination_length.")); } - uint8_t output_bit_depth = common_hal_audioi2sin_i2sin_get_output_bit_depth(self); + uint8_t output_bit_depth = self->base.bits_per_sample; char error_type = ' '; bool samples_signed = common_hal_audioi2sin_i2sin_get_samples_signed(self); if (samples_signed) { @@ -242,12 +242,11 @@ MP_DEFINE_CONST_FUN_OBJ_3(audioi2sin_i2sin_record_obj, audioi2sin_i2sin_obj_reco //| """The configured (nominal) sample rate, in Hz. This is the rate reported to //| the audio pipeline so it matches the output/consumer it is played into. The //| true capture rate may differ from this by a fraction of a Hz due to internal -//| clock limitations. (Provided by the audiosample protocol via -//| ``AUDIOSAMPLE_FIELDS``.)""" +//| clock limitations.""" //| //| bits_per_sample: int -//| """The number of bits per sample as it is streamed through the audio pipeline, -//| i.e. ``output_bit_depth``. (read-only)""" +//| """The number of bits per sample as it is streamed through the audio pipeline. +//| (read-only)""" //| //| channel_count: int //| """The number of channels (1 for mono, 2 for stereo). (read-only)""" @@ -267,20 +266,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_bit_depth_obj, audioi2sin_i2sin_o MP_PROPERTY_GETTER(audioi2sin_i2sin_bit_depth_obj, (mp_obj_t)&audioi2sin_i2sin_get_bit_depth_obj); -//| output_bit_depth: int -//| """The bit depth of samples written to the destination buffer. Equals ``bit_depth`` when -//| ``output_bit_depth`` was not supplied (or was ``None``) at construction time. (read-only)""" -//| -//| -static mp_obj_t audioi2sin_i2sin_obj_get_output_bit_depth(mp_obj_t self_in) { - audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); - check_for_deinit(self); - return MP_OBJ_NEW_SMALL_INT(common_hal_audioi2sin_i2sin_get_output_bit_depth(self)); -} -MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_output_bit_depth_obj, audioi2sin_i2sin_obj_get_output_bit_depth); - -MP_PROPERTY_GETTER(audioi2sin_i2sin_output_bit_depth_obj, - (mp_obj_t)&audioi2sin_i2sin_get_output_bit_depth_obj); //| samples_signed: bool //| """True if recorded samples are signed PCM, False for unsigned. (read-only)""" @@ -296,20 +281,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_samples_signed_obj, audioi2sin_i2 MP_PROPERTY_GETTER(audioi2sin_i2sin_samples_signed_obj, (mp_obj_t)&audioi2sin_i2sin_get_samples_signed_obj); -// Thin wrappers exposing the common-hal streaming functions to the audiosample -// protocol. get_buffer() runs in the output backend's refill interrupt, so it is -// not exposed to Python. -static void audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, - bool single_channel_output, uint8_t channel) { - common_hal_audioi2sin_i2sin_reset_buffer(self, single_channel_output, channel); -} - -static audioio_get_buffer_result_t audioi2sin_i2sin_get_buffer(audioi2sin_i2sin_obj_t *self, - bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { - return common_hal_audioi2sin_i2sin_get_buffer(self, single_channel_output, channel, - buffer, buffer_length); -} - static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, @@ -320,15 +291,14 @@ static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { // protocol's shared property getters. AUDIOSAMPLE_FIELDS, { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_bit_depth_obj) }, - { MP_ROM_QSTR(MP_QSTR_output_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_output_bit_depth_obj) }, { MP_ROM_QSTR(MP_QSTR_samples_signed), MP_ROM_PTR(&audioi2sin_i2sin_samples_signed_obj) }, }; static MP_DEFINE_CONST_DICT(audioi2sin_i2sin_locals_dict, audioi2sin_i2sin_locals_dict_table); static const audiosample_p_t audioi2sin_i2sin_proto = { MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) - .reset_buffer = (audiosample_reset_buffer_fun)audioi2sin_i2sin_reset_buffer, - .get_buffer = (audiosample_get_buffer_fun)audioi2sin_i2sin_get_buffer, + .reset_buffer = (audiosample_reset_buffer_fun)common_hal_audioi2sin_i2sin_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)common_hal_audioi2sin_i2sin_get_buffer, }; #endif // CIRCUITPY_AUDIOI2SIN diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h index ec1f1640d0e..c0fc48a6d09 100644 --- a/shared-bindings/audioi2sin/I2SIn.h +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -26,7 +26,6 @@ bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, void *buffer, uint32_t length); uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self); -uint8_t common_hal_audioi2sin_i2sin_get_output_bit_depth(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self); From 7e61a625df14daed4f0ea876b97f3032584d0a5d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 24 Jun 2026 15:45:10 -0400 Subject: [PATCH 583/876] fix CIRCUITPY_ flags that should be #if, not #ifder --- ports/analog/supervisor/port.c | 2 +- ports/atmel-samd/background.c | 2 +- shared-bindings/displayio/TileGrid.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/analog/supervisor/port.c b/ports/analog/supervisor/port.c index ee410a38148..e95deaba2a8 100644 --- a/ports/analog/supervisor/port.c +++ b/ports/analog/supervisor/port.c @@ -126,7 +126,7 @@ safe_mode_t port_init(void) { ; // enable TRNG (true random number generator) - #ifdef CIRCUITPY_RANDOM + #if CIRCUITPY_RANDOM MXC_TRNG_Init(); #endif diff --git a/ports/atmel-samd/background.c b/ports/atmel-samd/background.c index 2410f0fddb7..3d25bd340b1 100644 --- a/ports/atmel-samd/background.c +++ b/ports/atmel-samd/background.c @@ -14,7 +14,7 @@ #include "supervisor/shared/stack.h" #include "supervisor/port.h" -#ifdef CIRCUITPY_DISPLAYIO +#if CIRCUITPY_DISPLAYIO #include "shared-module/displayio/__init__.h" #endif diff --git a/shared-bindings/displayio/TileGrid.c b/shared-bindings/displayio/TileGrid.c index 5d54c1e3e30..fb5cabf05bf 100644 --- a/shared-bindings/displayio/TileGrid.c +++ b/shared-bindings/displayio/TileGrid.c @@ -17,7 +17,7 @@ #include "shared-bindings/displayio/ColorConverter.h" #include "shared-bindings/displayio/OnDiskBitmap.h" #include "shared-bindings/displayio/Palette.h" -#ifdef CIRCUITPY_TILEPALETTEMAPPER +#if CIRCUITPY_TILEPALETTEMAPPER #include "shared-bindings/tilepalettemapper/TilePaletteMapper.h" #endif From d09cebc2bf9f5fcbca8679af541b3afb0b3833e2 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 26 Jun 2026 09:15:26 -0400 Subject: [PATCH 584/876] add settings.toml CIRCUITPY_WIFI_HOSTNAME --- docs/environment.rst | 20 ++++++--- ports/espressif/common-hal/wifi/__init__.c | 45 ++++++++++++++------ ports/raspberrypi/common-hal/wifi/__init__.c | 13 ++++++ ports/zephyr-cp/common-hal/wifi/__init__.c | 27 +++++++++--- 4 files changed, 79 insertions(+), 26 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index ed32cfe89dc..395814c9aed 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -75,7 +75,8 @@ Keys that affect CircuitPython behavior CIRCUITPY_BLE_NAME ~~~~~~~~~~~~~~~~~~ -Default BLE name the board advertises as, including for the BLE workflow. +If supplied, sets the BLE name the board advertises as, including for the BLE workflow. +Otherwise, defaults to ``CIRCUITPYxxxx``, where ``xxxx`` varies per board. CIRCUITPY_HEAP_START_SIZE ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -103,16 +104,23 @@ TCP port number used for the Web Workflow HTTP API. Defaults to 80 when omitted. CIRCUITPY_WEB_INSTANCE_NAME ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Hostname the board advertises as, using mDNS, for the Web Workflow. -Defaults to a semi-unique name if omitted. +Human-friendly name the board advertises over mDNS for the Web Workflow. +Defaults to the human-readable board name if omitted. +This is not the hostname. CIRCUITPY_WIFI_SSID ~~~~~~~~~~~~~~~~~~~ CIRCUITPY_WIFI_PASSWORD ~~~~~~~~~~~~~~~~~~~~~~~ -If these values are specified, -CircuitPython will connect automatically to a local WiFi network using the supplied SSID -and password before ``boot.py`` and/or ``code.py`` are run. +If these values are supplied, connects automatically to a local WiFi network +with the specified SSID and password before ``boot.py`` and/or ``code.py`` are run. + +CIRCUITPY_WIFI_HOSTNAME +~~~~~~~~~~~~~~~~~~~~~~~ +If supplied, sets the initial ``wifi.radio.hostname`` to the given value. +Otherwise, the default value is ``cpy--``, +with some shortening for length if necessary. +If the supplied value is an invalid hostname or is too long, it is ignored. CIRCUITPY_SDCARD_USB ^^^^^^^^^^^^^^^^^^^^ diff --git a/ports/espressif/common-hal/wifi/__init__.c b/ports/espressif/common-hal/wifi/__init__.c index 85908855f26..7a9aea3b5e0 100644 --- a/ports/espressif/common-hal/wifi/__init__.c +++ b/ports/espressif/common-hal/wifi/__init__.c @@ -30,6 +30,10 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include "lwip/sockets.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #if CIRCUITPY_STATUS_BAR #include "supervisor/shared/status_bar.h" #endif @@ -507,23 +511,36 @@ void common_hal_wifi_init(bool user_initiated) { ESP_LOGE(TAG, "WiFi error code: %x", result); return; } - // Set the default lwip_local_hostname capped at 32 characters. We trim off - // the start of the board name (likely manufacturer) because the end is - // often more unique to the board. - size_t board_len = MIN(32 - ((MAC_ADDRESS_LENGTH * 2) + 6), strlen(CIRCUITPY_BOARD_ID)); - size_t board_trim = strlen(CIRCUITPY_BOARD_ID) - board_len; - // Avoid double _ in the hostname. - if (CIRCUITPY_BOARD_ID[board_trim] == '_') { - board_trim++; + + #if CIRCUITPY_SETTINGS_TOML + char hostname[CONFIG_LWIP_DHCPS_MAX_HOSTNAME_LEN]; + if (settings_get_str("CIRCUITPY_WIFI_HOSTNAME", hostname, sizeof(hostname)) == SETTINGS_OK) { + ESP_ERROR_CHECK(esp_netif_set_hostname(self->netif, hostname)); + } + #else + if (false) { } + #endif + else { + // Set the default lwip_local_hostname capped at 32 characters. We trim off + // the start of the board name (likely manufacturer) because the end is + // often more unique to the board. + size_t board_len = MIN(32 - ((MAC_ADDRESS_LENGTH * 2) + 6), strlen(CIRCUITPY_BOARD_ID)); + size_t board_trim = strlen(CIRCUITPY_BOARD_ID) - board_len; + // Avoid double _ in the hostname. + if (CIRCUITPY_BOARD_ID[board_trim] == '_') { + board_trim++; + } - char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; - uint8_t mac[MAC_ADDRESS_LENGTH]; - esp_wifi_get_mac(WIFI_IF_STA, mac); - snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; + uint8_t mac[MAC_ADDRESS_LENGTH]; + esp_wifi_get_mac(WIFI_IF_STA, mac); + snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + const char *default_lwip_local_hostname = cpy_default_hostname; + ESP_ERROR_CHECK(esp_netif_set_hostname(self->netif, default_lwip_local_hostname)); + } - const char *default_lwip_local_hostname = cpy_default_hostname; - ESP_ERROR_CHECK(esp_netif_set_hostname(self->netif, default_lwip_local_hostname)); // set station mode to avoid the default SoftAP common_hal_wifi_radio_start_station(self); // start wifi diff --git a/ports/raspberrypi/common-hal/wifi/__init__.c b/ports/raspberrypi/common-hal/wifi/__init__.c index 5fbe3fe58d1..84dba581fbf 100644 --- a/ports/raspberrypi/common-hal/wifi/__init__.c +++ b/ports/raspberrypi/common-hal/wifi/__init__.c @@ -15,6 +15,10 @@ #include "py/mpstate.h" #include "py/runtime.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + wifi_radio_obj_t common_hal_wifi_radio_obj; #include "supervisor/port.h" @@ -45,6 +49,15 @@ void common_hal_wifi_init(bool user_initiated) { // set station mode to avoid the default SoftAP common_hal_wifi_radio_start_station(self); + + #if CIRCUITPY_SETTINGS_TOML + // Must be set after station starts. + char hostname[sizeof(self->hostname)]; + if (settings_get_str("CIRCUITPY_WIFI_HOSTNAME", hostname, sizeof(hostname)) == SETTINGS_OK) { + common_hal_wifi_radio_set_hostname(self, hostname); + } + #endif + // start wifi common_hal_wifi_radio_set_enabled(self, true); } diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index f9e02be2476..4b967bc2780 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -22,6 +22,10 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #include "supervisor/port.h" #include "supervisor/workflow.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #if CIRCUITPY_STATUS_BAR #include "supervisor/shared/status_bar.h" #endif @@ -300,14 +304,25 @@ void common_hal_wifi_init(bool user_initiated) { board_trim++; } - char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; - struct net_linkaddr *mac = net_if_get_link_addr(self->sta_netif); - if (mac->len < MAC_ADDRESS_LENGTH) { - printk("MAC address too short"); + #if CIRCUITPY_SETTINGS_TOML + char hostname[NET_HOSTNAME_MAX_LEN]; + if (settings_get_str("CIRCUITPY_WIFI_HOSTNAME", hostname, sizeof(hostname)) == SETTINGS_OK) { + CHECK_ZEPHYR_RESULT(net_hostname_set(hostname, strlen(hostname))); + } + #else + if (false) { } - snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac->addr[0], mac->addr[1], mac->addr[2], mac->addr[3], mac->addr[4], mac->addr[5]); + #endif + else { + char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; + struct net_linkaddr *mac = net_if_get_link_addr(self->sta_netif); + if (mac->len < MAC_ADDRESS_LENGTH) { + printk("MAC address too short"); + } + snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac->addr[0], mac->addr[1], mac->addr[2], mac->addr[3], mac->addr[4], mac->addr[5]); - CHECK_ZEPHYR_RESULT(net_hostname_set(cpy_default_hostname, strlen(cpy_default_hostname))); + CHECK_ZEPHYR_RESULT(net_hostname_set(cpy_default_hostname, strlen(cpy_default_hostname))); + } #else printk("Hostname support disabled in Zephyr config\n"); #endif From 4645b97cf62b38602b908af4c466b0a4eba3945e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 26 Jun 2026 12:14:01 -0400 Subject: [PATCH 585/876] handle CIRCUITPY_SAFE_MODE_DELAY in settings.toml --- docs/environment.rst | 7 +++++++ main.c | 13 +++++++------ supervisor/shared/safe_mode.c | 18 +++++++++++++++++- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index ed32cfe89dc..eb0f68c98f4 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -205,6 +205,13 @@ Example: Configure the display to 640x480 black and white (1 bit per pixel): `Adafruit Feather RP2350 `_ `Adafruit Metro RP2350 `_ +CIRCUITPY_SAFEMODE_DELAY +~~~~~~~~~~~~~~~~~~~~~~~~ +Wait for the specified amount of time, in seconds (as a float), for the user to press the reset button +to initiate safe mode after a hard reset. +The status LED blinks during this time. +If not specified, use the default delay, which is one second. + CIRCUITPY_TERMINAL_SCALE ~~~~~~~~~~~~~~~~~~~~~~~~ Allows the entry of a display scaling factor used during the terminalio console construction. diff --git a/main.c b/main.c index f4b2bf8b362..063044e44f2 100644 --- a/main.c +++ b/main.c @@ -1022,18 +1022,12 @@ int __attribute__((used)) main(void) { serial_early_init(); mp_hal_stdout_tx_str(line_clear); - // Wait briefly to give a reset window where we'll enter safe mode after the reset. - if (get_safe_mode() == SAFE_MODE_NONE) { - set_safe_mode(wait_for_safe_mode_reset()); - } - stack_init(); #if CIRCUITPY_STATUS_BAR supervisor_status_bar_init(); #endif - #if !INTERNAL_FLASH_FILESYSTEM // Set up anything that might need to get done before we try to use SPI flash // This is needed for some boards where flash relies on GPIO setup to work @@ -1050,6 +1044,13 @@ int __attribute__((used)) main(void) { set_safe_mode(SAFE_MODE_NO_CIRCUITPY); } + // Wait briefly to give a reset window where we'll enter safe mode after the reset. + // Do this after mounting the filesystem because settings.toml can contain + // CIRCUITPY_SAFE_MODE_DELAY to change the default delay. + if (get_safe_mode() == SAFE_MODE_NONE) { + set_safe_mode(wait_for_safe_mode_reset()); + } + #if CIRCUITPY_BLEIO // Early init so that a reset press can cause BLE public advertising. Need the filesystem to // read settings.toml. diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 3860de6621f..da528d27df7 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -18,6 +18,10 @@ #include "supervisor/shared/translate/translate.h" #include "supervisor/shared/tick.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #ifdef __ZEPHYR__ #include #endif @@ -65,10 +69,22 @@ safe_mode_t wait_for_safe_mode_reset(void) { #if CIRCUITPY_STATUS_LED status_led_init(); #endif + + uint32_t safe_mode_delay_msecs = 1000; + + #if CIRCUITPY_SETTINGS_TOML + mp_float_t safe_mode_delay_secs = 1.0f; + // Will update delay_secs if setting is present. + settings_get_float("CIRCUITPY_SAFE_MODE_DELAY", &safe_mode_delay_secs); + if (safe_mode_delay_secs >= 0.0f && safe_mode_delay_secs <= (mp_float_t)UINT32_MAX) { + safe_mode_delay_msecs = safe_mode_delay_secs * 1000; + } + #endif + uint64_t start_ticks = supervisor_ticks_ms64(); uint64_t diff = 0; bool boot_in_safe_mode = false; - while (diff < 1000) { + while (diff < safe_mode_delay_msecs) { #if CIRCUITPY_STATUS_LED // Blink on for 100, off for 100 bool led_on = (diff % 250) < 125; From 6b4cad98a639dc041b933218f4fc015e11f8e85b Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 26 Jun 2026 12:03:03 -0500 Subject: [PATCH 586/876] enable AUDIOEFFECTS on raspberry pi port --- ports/raspberrypi/mpconfigport.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index c3fc727d889..b4d1ed99696 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -12,6 +12,7 @@ CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_DISPLAYIO) CIRCUITPY_FULL_BUILD ?= 1 CIRCUITPY_AUDIOMP3 ?= 1 CIRCUITPY_AUDIOSPEED ?= 1 +CIRCUITPY_AUDIOEFFECTS ?= 1 CIRCUITPY_BITOPS ?= 1 CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 From d25fe6979492a21bd5d5dfe662ecb63118a8f101 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 26 Jun 2026 14:37:50 -0500 Subject: [PATCH 587/876] disable AUDIOEFFECTS for pajenicko_picopad --- ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk index 764e41d4d91..1c3801edaac 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk @@ -12,6 +12,7 @@ EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" CIRCUITPY_KEYPAD = 1 CIRCUITPY_STAGE = 1 CIRCUITPY_AUDIOIO = 1 +CIRCUITPY_AUDIOEFFECTS = 0 CIRCUITPY__EVE = 1 From a1e9594bc7c1043396a3834bb69cead67bf43f8c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 26 Jun 2026 20:56:40 -0400 Subject: [PATCH 588/876] restore ESPNow to some functionality --- ports/espressif/bindings/espnow/ESPNow.c | 4 ++++ ports/espressif/common-hal/espnow/ESPNow.c | 21 +++++++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/ports/espressif/bindings/espnow/ESPNow.c b/ports/espressif/bindings/espnow/ESPNow.c index 01cc06e3be4..345d51b6dff 100644 --- a/ports/espressif/bindings/espnow/ESPNow.c +++ b/ports/espressif/bindings/espnow/ESPNow.c @@ -40,6 +40,8 @@ static void espnow_check_for_deinit(espnow_obj_t *self) { //| :param int buffer_size: The size of the internal ring buffer. Default: 526 bytes. //| :param int phy_rate: The ESP-NOW physical layer rate. Default: 1 Mbps. //| `wifi_phy_rate_t `_ +//| +//| **Limitations:** Currently, setting ``phy_rate`` does nothing. The rate is always 1 Mbps. //| """ //| ... //| @@ -231,6 +233,8 @@ MP_PROPERTY_GETTER(espnow_buffer_size_obj, //| phy_rate: int //| """The ESP-NOW physical layer rate. //| `wifi_phy_rate_t `_ +//| +//| **Limitations:** Currently, setting ``phy_rate`` does nothing. The rate is always 1 Mbps. //| """ //| static mp_obj_t espnow_get_phy_rate(const mp_obj_t self_in) { diff --git a/ports/espressif/common-hal/espnow/ESPNow.c b/ports/espressif/common-hal/espnow/ESPNow.c index 6d7580429a9..eb3b57174a3 100644 --- a/ports/espressif/common-hal/espnow/ESPNow.c +++ b/ports/espressif/common-hal/espnow/ESPNow.c @@ -120,15 +120,20 @@ void common_hal_espnow_init(espnow_obj_t *self) { common_hal_wifi_radio_set_enabled(&common_hal_wifi_radio_obj, true); } - esp_now_rate_config_t rate_config = { - .phymode = WIFI_PHY_MODE_LR, - .rate = self->phy_rate, - .ersu = false, - .dcm = false, - }; - CHECK_ESP_RESULT(esp_now_set_peer_rate_config(NULL, &rate_config)); - CHECK_ESP_RESULT(esp_now_init()); + + // esp_now_set_peer_rate_config() is poorly documented, and we haven't figured out + // what the esp_now_rate_config_t settings should be. For now, just ignore phy_rate. + // Note that esp_now_set_peer_rate_config() must be called after esp_now-init(). + // + // esp_now_rate_config_t rate_config = { + // .phymode = WIFI_PHY_MODE_LR, + // .rate = self->phy_rate, + // .ersu = false, + // .dcm = false, + // }; + // CHECK_ESP_RESULT(esp_now_set_peer_rate_config(NULL, &rate_config)); + CHECK_ESP_RESULT(esp_now_register_send_cb(send_cb)); CHECK_ESP_RESULT(esp_now_register_recv_cb(recv_cb)); } From 8d967d952b8be406efef742db4c8b099ae0f8318 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 28 Jun 2026 16:10:47 -0400 Subject: [PATCH 589/876] clear reference to BLE name on adapter init --- devices/ble_hci/common-hal/_bleio/Adapter.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index 03ec7a5588f..aaff47f42a6 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -259,6 +259,8 @@ static void _adapter_set_name(bleio_adapter_obj_t *self, mp_obj_str_t *name_obj) // Get various values and limits set by the adapter. // Set event mask. static void bleio_adapter_hci_init(bleio_adapter_obj_t *self) { + self->name = NULL; + mp_int_t name_len = 0; #if CIRCUITPY_SETTINGS_TOML @@ -950,7 +952,6 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { } connection->connection_obj = mp_const_none; } - } void bleio_adapter_background(bleio_adapter_obj_t *adapter) { From e2e37675634cf3b325286f278dfee0cda262998f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 29 Jun 2026 16:10:51 -0400 Subject: [PATCH 590/876] atmel-samd: update samd-peripherals for SPI baudrate ceiling Bump the samd-peripherals submodule to pick up adafruit/samd-peripherals#49, which makes busio.SPI treat the requested baudrate as a ceiling (the resulting frequency is the requested value or the nearest lower available value, never higher) instead of rounding to the nearest available baudrate. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/atmel-samd/peripherals | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/atmel-samd/peripherals b/ports/atmel-samd/peripherals index da0a1d7dccb..e98b6b79976 160000 --- a/ports/atmel-samd/peripherals +++ b/ports/atmel-samd/peripherals @@ -1 +1 @@ -Subproject commit da0a1d7dccb34b7fa07738e7a8ce25118c88d1a3 +Subproject commit e98b6b799768d21d8f8e2d0a071f19cf7d80467d From 23199bcbd2159858440fdc162f0556af769968aa Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 29 Jun 2026 17:49:34 -0400 Subject: [PATCH 591/876] espressif: treat busio.SPI baudrate as a ceiling The ESP-IDF driver rounds clock_speed_hz to the nearest achievable frequency, which can be higher than requested and overclock a device. Probe candidate targets through the public API (spi_bus_add_device -> spi_device_get_actual_freq -> spi_bus_remove_device), bisecting downward to find the highest achievable frequency that does not exceed the requested baudrate, without depending on divisor internals that vary between Espressif chips. The reported frequency is read back from the configured device. Tested on ESP32-S3, ESP32-C6, and ESP32. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/espressif/common-hal/busio/SPI.c | 60 +++++++++++++++++++++++--- ports/espressif/common-hal/busio/SPI.h | 3 +- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/ports/espressif/common-hal/busio/SPI.c b/ports/espressif/common-hal/busio/SPI.c index 21dc8c38379..b85f8cddd2a 100644 --- a/ports/espressif/common-hal/busio/SPI.c +++ b/ports/espressif/common-hal/busio/SPI.c @@ -22,22 +22,70 @@ static bool spi_bus_is_free(spi_host_device_t host_id) { return spi_bus_get_attr(host_id) == NULL; } +// Add a throwaway device at the given target clock, ask the driver what +// frequency it would actually produce, then remove it. Returns the actual +// frequency in Hz, or -1 if a device could not be added at that target. +static int spi_probe_actual_freq(busio_spi_obj_t *self, + spi_device_interface_config_t *device_config, int target_hz) { + device_config->clock_speed_hz = target_hz; + spi_device_handle_t handle; + if (spi_bus_add_device(self->host_id, device_config, &handle) != ESP_OK) { + return -1; + } + int freq_khz = 0; + spi_device_get_actual_freq(handle, &freq_khz); + spi_bus_remove_device(handle); + return freq_khz * 1000; +} + static void set_spi_config(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { - // 128 is a 50% duty cycle. - const int closest_clock = spi_get_actual_clock(APB_CLK_FREQ, baudrate, 128); - const spi_device_interface_config_t device_config = { - .clock_speed_hz = closest_clock, + spi_device_interface_config_t device_config = { + .clock_speed_hz = baudrate, .mode = phase | (polarity << 1), .spics_io_num = -1, // No CS pin .queue_size = MAX_SPI_TRANSACTIONS, .pre_cb = NULL }; + + // The ESP-IDF driver rounds clock_speed_hz to the nearest frequency it can + // produce, which may be HIGHER than requested. Treat baudrate as a ceiling: + // probe candidate targets (each time adding a throwaway device, asking the + // driver what it actually produced, and removing it) and keep the highest + // target whose actual frequency does not exceed baudrate. We don't inspect + // divisor internals -- those vary between Espressif chips -- only the + // public add/measure/remove API. + int target = baudrate; + int actual = spi_probe_actual_freq(self, &device_config, target); + if (actual < 0 || actual > (int)baudrate) { + // Bisect for the highest target whose actual frequency is <= baudrate. + // Stop refining once the interval is within 1 kHz, the resolution that + // spi_device_get_actual_freq reports. + int lo = 1; + int hi = baudrate; + while (hi - lo > 1000) { + int mid = lo + (hi - lo) / 2; + int mid_actual = spi_probe_actual_freq(self, &device_config, mid); + if (mid_actual >= 0 && mid_actual <= (int)baudrate) { + lo = mid; + } else { + hi = mid; + } + } + target = lo; + } + + device_config.clock_speed_hz = target; esp_err_t result = spi_bus_add_device(self->host_id, &device_config, &spi_handle[self->host_id]); if (result != ESP_OK) { mp_raise_RuntimeError(MP_ERROR_TEXT("SPI configuration failed")); } - self->baudrate = closest_clock; + + // Report the frequency the driver actually settled on for the real device. + int actual_khz = 0; + spi_device_get_actual_freq(spi_handle[self->host_id], &actual_khz); + self->baudrate = actual_khz * 1000; + self->requested_baudrate = baudrate; self->polarity = polarity; self->phase = phase; self->bits = bits; @@ -146,7 +194,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { - if (baudrate == self->baudrate && + if (baudrate == self->requested_baudrate && polarity == self->polarity && phase == self->phase && bits == self->bits) { diff --git a/ports/espressif/common-hal/busio/SPI.h b/ports/espressif/common-hal/busio/SPI.h index ac2f404042b..4886ab173ab 100644 --- a/ports/espressif/common-hal/busio/SPI.h +++ b/ports/espressif/common-hal/busio/SPI.h @@ -21,7 +21,8 @@ typedef struct { uint8_t bits; uint8_t phase; uint8_t polarity; - uint32_t baudrate; + uint32_t baudrate; // Actual frequency, reported by the frequency property. + uint32_t requested_baudrate; // Value passed to configure(); used for the cache-hit check. SemaphoreHandle_t mutex; } busio_spi_obj_t; From 4675b4d05a6909e85088430eefeb7cfd1b79243f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 29 Jun 2026 17:50:25 -0400 Subject: [PATCH 592/876] busio.SPI: document that baudrate is treated as a ceiling The actual SPI clock is now set to the requested rate or the nearest lower available rate, never higher. Update the configure() baudrate parameter and the frequency attribute docstrings to match. Co-Authored-By: Claude Opus 4.8 (1M context) --- shared-bindings/busio/SPI.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index 962080648ce..b675190d856 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -157,8 +157,10 @@ static void check_for_deinit(busio_spi_obj_t *self) { //| ) -> None: //| """Configures the SPI bus. The SPI object must be locked. //| -//| :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be higher or lower -//| due to the granularity of available clock settings. +//| :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be lower +//| due to the granularity of available clock settings, but it will not exceed the +//| requested rate: the value is treated as a ceiling, so the clock is set to the +//| requested rate or the nearest lower available rate. //| Check the `frequency` attribute for the actual clock rate. //| :param int polarity: the base state of the clock line (0 or 1) //| :param int phase: the edge of the clock that data is captured. First (0) @@ -445,8 +447,8 @@ static mp_obj_t busio_spi_write_readinto(size_t n_args, const mp_obj_t *pos_args MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 1, busio_spi_write_readinto); //| frequency: int -//| """The actual SPI bus frequency. This may not match the frequency requested -//| due to internal limitations.""" +//| """The actual SPI bus frequency. This may be lower than the frequency requested +//| due to internal limitations, but it will not be higher.""" //| //| From 351a3c1ac1661586921e8ba725a95f19035b8e81 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 29 Jun 2026 18:04:39 -0400 Subject: [PATCH 593/876] cxd56: treat busio.SPI baudrate as a ceiling SPI_SETFREQUENCY() picks the nearest available frequency, which overshoots the request at low frequencies (e.g. 100000 -> 102362). Treat baudrate as a ceiling: when the driver overshoots, bisect downward on the requested target for the highest available frequency that does not exceed baudrate. The driver returns the actual frequency each call, so this does not depend on its divisor internals. Tested on SPRESENSE (CXD5602): no frequency exceeds the requested baudrate. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/cxd56/common-hal/busio/SPI.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/ports/cxd56/common-hal/busio/SPI.c b/ports/cxd56/common-hal/busio/SPI.c index 6c49e0f2750..595b868f348 100644 --- a/ports/cxd56/common-hal/busio/SPI.c +++ b/ports/cxd56/common-hal/busio/SPI.c @@ -72,8 +72,27 @@ void common_hal_busio_spi_mark_deinit(busio_spi_obj_t *self) { bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) { uint8_t mode; - self->frequency = baudrate; - SPI_SETFREQUENCY(self->spi_dev, baudrate); + // SPI_SETFREQUENCY() picks the nearest available frequency and returns it, + // which can be HIGHER than requested (it overshoots at low frequencies). + // Treat baudrate as a ceiling: if the driver overshoots, bisect downward on + // the requested target for the highest available frequency that does not + // exceed baudrate. The driver returns the actual frequency each call, so we + // don't depend on its divisor internals. + uint32_t actual = SPI_SETFREQUENCY(self->spi_dev, baudrate); + if (actual > baudrate) { + uint32_t lo = 1; // f(lo) <= baudrate + uint32_t hi = baudrate; // f(hi) > baudrate (just measured) + while (hi - lo > 1) { + uint32_t mid = lo + (hi - lo) / 2; + if (SPI_SETFREQUENCY(self->spi_dev, mid) <= baudrate) { + lo = mid; + } else { + hi = mid; + } + } + actual = SPI_SETFREQUENCY(self->spi_dev, lo); + } + self->frequency = actual; if (polarity == 0) { if (phase == 0) { From 11e228036f3de68d16c44ea959d4a3d1b4a40dc9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 29 Jun 2026 18:26:15 -0400 Subject: [PATCH 594/876] analog: treat busio.SPI baudrate as a ceiling MXC_SPI_SetFrequency() floors the clock divisor, so the actual SPI clock can be higher than requested (e.g. a 30 MHz request on a 50 MHz peripheral clock runs at the full 50 MHz). Treat baudrate as a ceiling: when the hardware overshoots, bisect downward on the requested target for the highest rate that does not exceed baudrate. MXC_SPI_GetFrequency() reports the actual configured rate, so this does not depend on the divisor internals. Also store the actual rate so the frequency property reports it instead of the requested value. Not tested on hardware (no MAX32xxx board available); logic mirrors the cxd56 and espressif ceiling fixes. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/analog/common-hal/busio/SPI.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/ports/analog/common-hal/busio/SPI.c b/ports/analog/common-hal/busio/SPI.c index de3856b23b3..bdbe6da9d94 100644 --- a/ports/analog/common-hal/busio/SPI.c +++ b/ports/analog/common-hal/busio/SPI.c @@ -157,7 +157,6 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, mxc_spi_clkmode_t clk_mode; int ret; - self->baudrate = baudrate; self->polarity = polarity; self->phase = phase; self->bits = bits; @@ -185,6 +184,29 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_baudrate); return false; } + + // MXC_SPI_SetFrequency() floors the clock divisor, so the actual rate can be + // HIGHER than requested. Treat baudrate as a ceiling: if the hardware + // overshoots, bisect downward on the requested target for the highest rate + // that does not exceed baudrate. MXC_SPI_GetFrequency() reports the actual + // configured rate, so we don't depend on the divisor internals. + uint32_t actual = MXC_SPI_GetFrequency(self->spi_regs); + if (actual > baudrate) { + uint32_t lo = 1; // f(lo) <= baudrate + uint32_t hi = baudrate; // f(hi) > baudrate (just measured) + while (hi - lo > 1) { + uint32_t mid = lo + (hi - lo) / 2; + MXC_SPI_SetFrequency(self->spi_regs, mid); + if (MXC_SPI_GetFrequency(self->spi_regs) <= baudrate) { + lo = mid; + } else { + hi = mid; + } + } + MXC_SPI_SetFrequency(self->spi_regs, lo); + actual = MXC_SPI_GetFrequency(self->spi_regs); + } + self->baudrate = actual; ret = MXC_SPI_SetDataSize(self->spi_regs, bits); if (ret == E_BAD_PARAM) { mp_raise_ValueError_varg(MP_ERROR_TEXT("%q out of range"), MP_QSTR_bits); From 138c7d694c84b5351ddab3e43e83e405c311ca4c Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 29 Jun 2026 18:52:50 -0400 Subject: [PATCH 595/876] busio.SPI: clarify baudrate ceiling docs and note Zephyr limitation Tighten the configure() baudrate wording and document that on Zephyr the ceiling behavior may be violated and the frequency attribute may not reflect the actual baudrate. Co-Authored-By: Claude Opus 4.8 (1M context) --- shared-bindings/busio/SPI.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/shared-bindings/busio/SPI.c b/shared-bindings/busio/SPI.c index b675190d856..6ff74880266 100644 --- a/shared-bindings/busio/SPI.c +++ b/shared-bindings/busio/SPI.c @@ -157,11 +157,12 @@ static void check_for_deinit(busio_spi_obj_t *self) { //| ) -> None: //| """Configures the SPI bus. The SPI object must be locked. //| -//| :param int baudrate: the desired clock rate in Hertz. The actual clock rate may be lower -//| due to the granularity of available clock settings, but it will not exceed the -//| requested rate: the value is treated as a ceiling, so the clock is set to the -//| requested rate or the nearest lower available rate. +//| :param int baudrate: the desired clock rate in Hertz. The value is treated as a ceiling: +//| the actual clock rate may be lower due to the granularity of available clock settings, +//| but it will not exceed the given value. //| Check the `frequency` attribute for the actual clock rate. +//| **Limitations**: On Zephyr, the ceiling behavior may be violated, and +//| the `frequency` value does not reflect the actual baudrate. //| :param int polarity: the base state of the clock line (0 or 1) //| :param int phase: the edge of the clock that data is captured. First (0) //| or second (1). Rising or falling depends on clock polarity. @@ -170,13 +171,7 @@ static void check_for_deinit(busio_spi_obj_t *self) { //| .. note:: On the SAMD21, it is possible to set the baudrate to 24 MHz, but that //| speed is not guaranteed to work. 12 MHz is the next available lower speed, and is //| within spec for the SAMD21. -//| -//| .. note:: On the nRF52840, these baudrates are available: 125kHz, 250kHz, 1MHz, 2MHz, 4MHz, -//| and 8MHz. -//| If you pick a a baudrate other than one of these, the nearest lower -//| baudrate will be chosen, with a minimum of 125kHz. -//| Two SPI objects may be created, except on the Circuit Playground Bluefruit, -//| which allows only one (to allow for an additional I2C object).""" +//| """ //| ... //| @@ -448,8 +443,13 @@ MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_write_readinto_obj, 1, busio_spi_write_read //| frequency: int //| """The actual SPI bus frequency. This may be lower than the frequency requested -//| due to internal limitations, but it will not be higher.""" +//| due to internal limitations, but it will not be higher. //| +//| **Limitations**: On Zephyr, the returned value does not reflect the actual baudrate, +//| because there is `no way to fetch the actual chosen frequency +//| `_. +//| In addition, on Zephyr, the ceiling behavior described in `configure` may be violated. +//| """ //| static mp_obj_t busio_spi_obj_get_frequency(mp_obj_t self_in) { From b3a8288cddd5930994a26b3a09e271922c391b78 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 30 Jun 2026 15:34:49 -0400 Subject: [PATCH 596/876] espressif: wait a bit for AP to start so its IP address will be set --- ports/espressif/common-hal/wifi/Radio.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ports/espressif/common-hal/wifi/Radio.c b/ports/espressif/common-hal/wifi/Radio.c index 31dd7e4317f..51d4913926f 100644 --- a/ports/espressif/common-hal/wifi/Radio.c +++ b/ports/espressif/common-hal/wifi/Radio.c @@ -13,6 +13,7 @@ #include "common-hal/wifi/__init__.h" #include "shared/runtime/interrupt_char.h" #include "py/gc.h" +#include "py/mphal.h" #include "py/obj.h" #include "py/runtime.h" #include "shared-bindings/ipaddress/IPv4Address.h" @@ -269,6 +270,13 @@ void common_hal_wifi_radio_start_ap(wifi_radio_obj_t *self, uint8_t *ssid, size_ config->ap.max_connection = max_connections; esp_wifi_set_config(WIFI_IF_AP, config); + // Wait a few ms for the AP to start. Empirically, this takes < 3ms on ESP32, and < 1ms on other chips. + for (size_t ms = 0; ms < 10; ms++) { + if (common_hal_wifi_radio_get_ap_active(self)) { + break; + } + mp_hal_delay_ms(1); + } } bool common_hal_wifi_radio_get_ap_active(wifi_radio_obj_t *self) { From 80f3496e26cecef84a62465aad46925c07f7304f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 1 Jul 2026 12:30:48 -0400 Subject: [PATCH 597/876] espressif: fix I2S audio under IDF v6 (dma_buf is the buffer pointer) The ESP-IDF v6.0 migration (#10922, commit 6a34aa1010) mechanically renamed the I2S event field `data` -> `dma_buf` but kept an extra pointer dereference. In IDF v5.x `i2s_event_data_t.data` pointed *to* the buffer pointer (`&finish_desc->buf`), so `*(int16_t **)event->data` was correct. In v6 `dma_buf` *is* the buffer pointer directly (`.dma_buf = curr_buf`). The stale double-dereference reinterpreted the first bytes of audio data as an address, so `next_buffer` became garbage/NULL. That caused a NULL-pointer safe mode crash in `audiosample_convert_*` and, otherwise, DMA buffers that were never refilled (audio played as short bursts of tone separated by silence). Fixes #11070 Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/espressif/common-hal/audiobusio/__init__.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/common-hal/audiobusio/__init__.c b/ports/espressif/common-hal/audiobusio/__init__.c index 2ae34d04960..fb875cfe501 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -108,7 +108,7 @@ static void i2s_callback_fun(void *self_in) { static bool i2s_event_interrupt(i2s_chan_handle_t handle, i2s_event_data_t *event, void *self_in) { i2s_t *self = self_in; self->underrun = self->underrun || self->next_buffer != NULL; - self->next_buffer = *(int16_t **)event->dma_buf; + self->next_buffer = (int16_t *)event->dma_buf; self->next_buffer_size = event->size; background_callback_add(&self->callback, i2s_callback_fun, self_in); return false; From 61803455fcd3069789c0c789b9ca5d53b7cbfdf1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 1 Jul 2026 13:51:11 -0400 Subject: [PATCH 598/876] espressif: play non-looping samples fully over I2S audiobusio.I2SOut dropped the final buffer that audiosample_get_buffer returns together with GET_BUFFER_DONE, breaking before it was copied. A single-buffer RawSample played with loop=False returns its entire buffer with GET_BUFFER_DONE on the first call, so nothing was ever output. - Add a last_buffer flag so the final buffer is copied out before stopping, instead of breaking before the copy. - Silence any unfilled remainder of the DMA buffer so a sample that ends mid-buffer (or a zero-length sample) does not play stale data. - Fix the preload cap, which compared a byte count against a frame count and left the DMA only ~1/4 primed, splitting playback into a short tone, a gap, then the rest. Addresses #10539. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../common-hal/audiobusio/__init__.c | 30 ++++++++++++++----- .../common-hal/audiobusio/__init__.h | 1 + 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/ports/espressif/common-hal/audiobusio/__init__.c b/ports/espressif/common-hal/audiobusio/__init__.c index fb875cfe501..4aff753325f 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -39,25 +39,32 @@ static void i2s_fill_buffer(i2s_t *self) { self->next_buffer_size = 0; return; } - while (!self->stopping && output_buffer_size > 0) { + while (output_buffer_size > 0) { if (self->sample_data == self->sample_end) { + if (self->last_buffer) { + // The final buffer has been fully output; stop now instead of + // fetching another (which for a single-buffer sample would just + // replay it). + self->stopping = true; + break; + } uint32_t sample_buffer_length; audioio_get_buffer_result_t get_buffer_result = audiosample_get_buffer(self->sample, false, 0, &self->sample_data, &sample_buffer_length); self->sample_end = self->sample_data + sample_buffer_length; + if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) { + self->stopping = true; + break; + } if (get_buffer_result == GET_BUFFER_DONE) { if (self->loop) { audiosample_reset_buffer(self->sample, false, 0); } else { - self->stopping = true; - break; + // Output this final buffer before stopping; don't fetch again. + self->last_buffer = true; } } - if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) { - self->stopping = true; - break; - } } size_t sample_bytecount = self->sample_end - self->sample_data; // The framecount is the minimum of space left in the output buffer or left in the incoming sample. @@ -96,6 +103,11 @@ static void i2s_fill_buffer(i2s_t *self) { output_buffer += framecount * CIRCUITPY_OUTPUT_SLOTS; output_buffer_size -= framecount * bytes_per_output_frame; } + // Sample ended mid-buffer (or was empty/errored): silence the rest so the + // DMA doesn't play stale data. + if (output_buffer_size > 0) { + memset(output_buffer, 0, output_buffer_size); + } self->next_buffer = NULL; self->next_buffer_size = 0; } @@ -172,6 +184,7 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { self->playing = true; self->paused = false; self->stopping = false; + self->last_buffer = false; // This will be slow but we can't rewind the underlying sample. So, we will // preload one frame at a time and drop the last sample that can't fit. // We cap ourselves at the max DMA set to prevent a sample drop if starting @@ -179,7 +192,7 @@ void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { uint32_t starting_frame; size_t bytes_loaded = 4; size_t preloaded = 0; - while (bytes_loaded > 0 && preloaded < CIRCUITPY_BUFFER_SIZE * CIRCUITPY_BUFFER_COUNT) { + while (bytes_loaded > 0 && preloaded < I2S_DMA_BUFFER_MAX_SIZE * CIRCUITPY_BUFFER_COUNT) { self->next_buffer = &starting_frame; self->next_buffer_size = sizeof(starting_frame); i2s_fill_buffer(self); @@ -209,6 +222,7 @@ void port_i2s_stop(i2s_t *self) { self->sample = NULL; self->playing = false; self->stopping = false; + self->last_buffer = false; } void port_i2s_pause(i2s_t *self) { diff --git a/ports/espressif/common-hal/audiobusio/__init__.h b/ports/espressif/common-hal/audiobusio/__init__.h index 0088cb87d5f..af341460e49 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.h +++ b/ports/espressif/common-hal/audiobusio/__init__.h @@ -19,6 +19,7 @@ typedef struct { bool paused; // True when the I2S channel is configured but disabled. bool playing; // True when the I2S channel is configured. bool stopping; + bool last_buffer; // True once the sample's final buffer has been fetched but not yet fully output. bool samples_signed; int8_t bytes_per_sample; int8_t channel_count; From 9bcb76626ceeb456ea4714fc6e8c848be85bfda2 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 1 Jul 2026 14:31:01 -0400 Subject: [PATCH 599/876] nordic: play non-looping samples fully over I2S audiobusio.I2SOut dropped the final buffer that audiosample_get_buffer returns together with GET_BUFFER_DONE, breaking before it was copied. A single-buffer RawSample played with loop=False returns its entire buffer with GET_BUFFER_DONE on the first call, so nothing was ever output. Add a last_buffer flag so the final buffer is copied out before stopping, instead of breaking before the copy. The existing hold_value tail fill and external stopping/paused handling are unchanged. Addresses #10539. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/nordic/common-hal/audiobusio/I2SOut.c | 20 ++++++++++++++------ ports/nordic/common-hal/audiobusio/I2SOut.h | 1 + 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.c b/ports/nordic/common-hal/audiobusio/I2SOut.c index 249b4f9d116..00b34e17e82 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.c +++ b/ports/nordic/common-hal/audiobusio/I2SOut.c @@ -107,23 +107,30 @@ static void i2s_buffer_fill(audiobusio_i2sout_obj_t *self) { while (!self->paused && !self->stopping && bytesleft) { if (self->sample_data == self->sample_end) { + if (self->last_buffer) { + // The final buffer has been fully output; stop now instead of + // fetching another (which for a single-buffer sample would just + // replay it). + self->stopping = true; + break; + } uint32_t sample_buffer_length; audioio_get_buffer_result_t get_buffer_result = audiosample_get_buffer(self->sample, false, 0, &self->sample_data, &sample_buffer_length); self->sample_end = self->sample_data + sample_buffer_length; + if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) { + self->stopping = true; + break; + } if (get_buffer_result == GET_BUFFER_DONE) { if (self->loop) { audiosample_reset_buffer(self->sample, false, 0); } else { - self->stopping = true; - break; + // Output this final buffer before stopping; don't fetch again. + self->last_buffer = true; } } - if (get_buffer_result == GET_BUFFER_ERROR || sample_buffer_length == 0) { - self->stopping = true; - break; - } } uint16_t bytecount = MIN(bytesleft, (size_t)(self->sample_end - self->sample_data)); if (self->samples_signed) { @@ -280,6 +287,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, self->playing = true; self->paused = false; self->stopping = false; + self->last_buffer = false; i2s_buffer_fill(self); NRF_I2S->RXTXD.MAXCNT = self->buffer_length / 4; diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.h b/ports/nordic/common-hal/audiobusio/I2SOut.h index 7cb62ae3d2b..33ec917eb64 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.h +++ b/ports/nordic/common-hal/audiobusio/I2SOut.h @@ -30,6 +30,7 @@ typedef struct { bool left_justified : 1; bool playing : 1; bool stopping : 1; + bool last_buffer : 1; bool paused : 1; bool loop : 1; bool samples_signed : 1; From f7bebe7fc738d53f0c4dff21bb068ad8e2f88792 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 1 Jul 2026 14:43:14 -0400 Subject: [PATCH 600/876] raspberrypi: clear playing for single-buffer non-looping samples A single-buffer sample plays entirely in hardware via DMA chaining with no completion interrupt (the interrupt is only enabled for the multi-buffer path). With loop=False, channel[0] chains to itself and stops after one pass, but nothing ever ran audio_dma_stop, so playing_in_progress stayed true forever and I2SOut.playing (and AudioOut/PWMAudioOut) never became false. Detect this in audio_dma_get_playing: when a single-buffer, non-looping, non-paused sample's DMA channel has drained, stop and report not playing. Addresses #10539. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/raspberrypi/audio_dma.c | 10 ++++++++++ ports/raspberrypi/audio_dma.h | 1 + 2 files changed, 11 insertions(+) diff --git a/ports/raspberrypi/audio_dma.c b/ports/raspberrypi/audio_dma.c index 36b86cbf844..8b2f78266e3 100644 --- a/ports/raspberrypi/audio_dma.c +++ b/ports/raspberrypi/audio_dma.c @@ -227,6 +227,7 @@ audio_dma_result audio_dma_setup_playback( uint32_t max_buffer_length; audiosample_get_buffer_structure(sample, single_channel_output, &single_buffer, &samples_signed, &max_buffer_length, &dma->sample_spacing); + dma->single_buffer = single_buffer; // Check to see if we have to scale the resolution up. if (dma->sample_resolution <= 8 && dma->output_resolution > 8) { @@ -487,6 +488,15 @@ bool audio_dma_get_playing(audio_dma_t *dma) { if (dma->channel[0] == NUM_DMA_CHANNELS) { return false; } + // A single-buffer, non-looping sample plays entirely in hardware via DMA + // chaining, with no completion interrupt to stop it. Detect when its DMA + // channel has drained and finish so that playing_in_progress is cleared. + if (dma->single_buffer && !dma->loop && + dma->playing_in_progress && !dma->paused && + !dma_channel_is_busy(dma->channel[0])) { + audio_dma_stop(dma); + return false; + } return dma->playing_in_progress; } diff --git a/ports/raspberrypi/audio_dma.h b/ports/raspberrypi/audio_dma.h index cd892f5151b..57e47c7444e 100644 --- a/ports/raspberrypi/audio_dma.h +++ b/ports/raspberrypi/audio_dma.h @@ -33,6 +33,7 @@ typedef struct { uint8_t sample_resolution; // in bits audio_dma_result dma_result; bool loop; + bool single_buffer; bool single_channel_output; bool signed_to_unsigned; bool unsigned_to_signed; From 896f67a88692ebf21e9355ed4169afa6a2095e53 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 1 Jul 2026 15:13:41 -0400 Subject: [PATCH 601/876] zephyr-cp: play non-looping samples fully over I2S fill_buffer set stopping and returned on GET_BUFFER_DONE with loop=False before copying the returned data. A single-buffer RawSample returns its entire buffer with GET_BUFFER_DONE on the first call, so the block was filled with silence and nothing was heard. Copy the returned buffer first, then handle GET_BUFFER_DONE (drain and stop). Add a native_sim regression test that plays a single-buffer, non-looping sample and asserts the sine wave reaches the I2S output. Addresses #10539. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../zephyr-cp/common-hal/audiobusio/I2SOut.c | 23 +++--- ports/zephyr-cp/tests/test_audiobusio.py | 74 +++++++++++++++++++ 2 files changed, 87 insertions(+), 10 deletions(-) diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c index e858552c524..e159b4fcc10 100644 --- a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -87,27 +87,30 @@ static void fill_buffer(audiobusio_i2sout_obj_t *self, uint8_t *buffer, size_t b return; } + // Copy the returned data first, even when this is the final buffer + // (GET_BUFFER_DONE). A single-buffer sample returns its entire buffer + // together with GET_BUFFER_DONE on the first call, so handling DONE + // before the copy would drop the audio and produce silence. + uint32_t bytes_to_copy = sample_buffer_length; + if (bytes_filled + bytes_to_copy > buffer_size) { + bytes_to_copy = buffer_size - bytes_filled; + } + + memcpy(buffer + bytes_filled, sample_buffer, bytes_to_copy); + bytes_filled += bytes_to_copy; + if (result == GET_BUFFER_DONE) { if (self->loop) { // Reset to beginning audiosample_reset_buffer(self->sample, false, 0); } else { - // Done playing, fill rest with silence + // Final buffer copied; stop once this block drains. self->stopping = true; i2s_trigger(self->i2s_dev, I2S_DIR_TX, I2S_TRIGGER_DRAIN); memset(buffer + bytes_filled, 0, buffer_size - bytes_filled); return; } } - - // Copy data to buffer - uint32_t bytes_to_copy = sample_buffer_length; - if (bytes_filled + bytes_to_copy > buffer_size) { - bytes_to_copy = buffer_size - bytes_filled; - } - - memcpy(buffer + bytes_filled, sample_buffer, bytes_to_copy); - bytes_filled += bytes_to_copy; } } diff --git a/ports/zephyr-cp/tests/test_audiobusio.py b/ports/zephyr-cp/tests/test_audiobusio.py index 5a899139c22..8bfa6a5a586 100644 --- a/ports/zephyr-cp/tests/test_audiobusio.py +++ b/ports/zephyr-cp/tests/test_audiobusio.py @@ -214,3 +214,77 @@ def test_i2s_pause_resume(circuitpython): assert "paused" in output assert "resumed" in output assert "done" in output + + +I2S_PLAY_LOOP_FALSE_CODE = """\ +import array +import math +import audiocore +import board +import time + +# 440 Hz sine, 16-bit signed stereo at 16000 Hz, several periods. +sample_rate = 16000 +length = sample_rate // 440 +periods = 10 +values = [] +for _ in range(periods): + for i in range(length): + v = int(math.sin(math.pi * 2 * i / length) * 30000) + values.append(v) # left + values.append(v) # right + +# Default single_buffer=True: get_buffer returns the whole buffer together with +# GET_BUFFER_DONE on the very first call. With loop=False that buffer used to be +# discarded before being copied, producing silence (issue #10539). +sample = audiocore.RawSample( + array.array("h", values), + sample_rate=sample_rate, + channel_count=2, +) + +dac = board.I2S0() +print("playing") +dac.play(sample, loop=False) +time.sleep(0.5) +# Stop explicitly so this test does not depend on `playing` clearing on its own. +dac.stop() +print("done") +""" + + +@pytest.mark.duration(10) +@pytest.mark.circuitpy_drive({"code.py": I2S_PLAY_LOOP_FALSE_CODE}) +def test_i2s_play_non_looping_single_buffer(circuitpython): + """A single-buffer RawSample played with loop=False must be heard, not dropped. + + Regression test for #10539: the final buffer, returned together with + GET_BUFFER_DONE, was discarded before being copied, so a single-buffer + sample (whole buffer + DONE on the first get_buffer call) produced silence. + """ + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "playing" in output + assert "done" in output + + left_trace = parse_i2s_trace(circuitpython.trace_file, "Left") + right_trace = parse_i2s_trace(circuitpython.trace_file, "Right") + + # The sine wave must actually reach the I2S output. On the bug every value is + # zero (silence) because the sole buffer was dropped. + left_values = [v for _, v in left_trace if v != 0] + right_values = [v for _, v in right_trace if v != 0] + assert len(left_values) > 5, "Left channel is silent; non-looping sample was dropped" + assert len(right_values) > 5, "Right channel is silent; non-looping sample was dropped" + + # A sine wave has both positive and negative excursions at the expected amplitude. + assert max(left_values) > 20000, f"Left max {max(left_values)} too low" + assert min(left_values) < -20000, f"Left min {min(left_values)} too high" + + # We wrote the same value to both channels. + left_by_ts = dict(left_trace) + right_by_ts = dict(right_trace) + common_ts = sorted(set(left_by_ts) & set(right_by_ts)) + mismatches = sum(1 for ts in common_ts[:100] if left_by_ts[ts] != right_by_ts[ts]) + assert mismatches == 0, f"{mismatches} L/R mismatches in first common timestamps" From c9f859716f96c10b28c5a31bf70e2a476282ab68 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 2 Jul 2026 14:53:08 -0400 Subject: [PATCH 602/876] Fix preserve_dios during fake deep sleep --- main.c | 6 ++++++ ports/atmel-samd/common-hal/alarm/__init__.c | 3 --- ports/espressif/common-hal/alarm/__init__.c | 2 +- ports/espressif/common-hal/microcontroller/Pin.c | 3 ++- ports/espressif/common-hal/microcontroller/Pin.h | 1 - ports/espressif/mpconfigport.mk | 1 + ports/nordic/common-hal/alarm/__init__.c | 3 --- ports/raspberrypi/common-hal/alarm/__init__.c | 3 --- ports/stm/common-hal/alarm/__init__.c | 3 --- py/circuitpy_mpconfig.mk | 4 ++++ shared-bindings/alarm/__init__.c | 7 +++++++ shared-bindings/alarm/__init__.h | 7 +++++++ 12 files changed, 28 insertions(+), 15 deletions(-) diff --git a/main.c b/main.c index 063044e44f2..ff5238d0c53 100644 --- a/main.c +++ b/main.c @@ -789,6 +789,12 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s #if CIRCUITPY_DISPLAYIO common_hal_displayio_auto_primary_display(); #endif + // Undo any preserve_dios. + #if CIRCUITPY_ALARM_PRESERVE_DIOS + common_hal_alarm_clear_pin_preservations(); + #endif + // Reset pins, as if there was a hard reset. + reset_all_pins(); // Pretend that the next run is the first run, as if we were reset. *simulate_reset = true; } diff --git a/ports/atmel-samd/common-hal/alarm/__init__.c b/ports/atmel-samd/common-hal/alarm/__init__.c index 38ef58bea76..153647f4e89 100644 --- a/ports/atmel-samd/common-hal/alarm/__init__.c +++ b/ports/atmel-samd/common-hal/alarm/__init__.c @@ -127,9 +127,6 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { - if (n_dios > 0) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); - } _setup_sleep_alarms(true, n_alarms, alarms); } diff --git a/ports/espressif/common-hal/alarm/__init__.c b/ports/espressif/common-hal/alarm/__init__.c index b2a6e00969a..751ef121e5f 100644 --- a/ports/espressif/common-hal/alarm/__init__.c +++ b/ports/espressif/common-hal/alarm/__init__.c @@ -182,7 +182,7 @@ void MP_NORETURN common_hal_alarm_enter_deep_sleep(void) { #endif // We no longer need to remember the pin preservations, since any pin resets are all done. - clear_pin_preservations(); + common_hal_alarm_clear_pin_preservations(); // The ESP-IDF caches the deep sleep settings and applies them before sleep. // We don't need to worry about resetting them in the interim. diff --git a/ports/espressif/common-hal/microcontroller/Pin.c b/ports/espressif/common-hal/microcontroller/Pin.c index f995e65545d..34b9578d580 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.c +++ b/ports/espressif/common-hal/microcontroller/Pin.c @@ -7,6 +7,7 @@ #include "shared-bindings/microcontroller/Pin.h" #include "shared-bindings/digitalio/DigitalInOut.h" +#include "shared-bindings/alarm/__init__.h" #include "py/mphal.h" @@ -368,7 +369,7 @@ void preserve_pin_number(gpio_num_t pin_number) { } } -void clear_pin_preservations(void) { +void common_hal_alarm_clear_pin_preservations(void) { _preserved_pin_mask = 0; } diff --git a/ports/espressif/common-hal/microcontroller/Pin.h b/ports/espressif/common-hal/microcontroller/Pin.h index aba7fa68323..7925ac9f8de 100644 --- a/ports/espressif/common-hal/microcontroller/Pin.h +++ b/ports/espressif/common-hal/microcontroller/Pin.h @@ -29,7 +29,6 @@ extern bool pin_number_is_free(gpio_num_t pin_number); extern void never_reset_pin_number(gpio_num_t pin_number); extern void preserve_pin_number(gpio_num_t pin_number); -extern void clear_pin_preservations(void); // Allow the board to reset a pin in a board-specific way. This can be used // for LEDs or enable pins to put them in a state beside the default pull-up. diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index f7a14f83202..0b027333b97 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -64,6 +64,7 @@ CIRCUITPY_LIBC_STRING0 = 0 # These modules are implemented in ports//common-hal: CIRCUITPY__EVE ?= 1 CIRCUITPY_ALARM ?= 1 +CIRCUITPY_ALARM_PRESERVE_DIOS ?= 1 CIRCUITPY_ALARM_TOUCH ?= 1 CIRCUITPY_ANALOGBUFIO ?= 1 CIRCUITPY_AUDIOBUSIO ?= 1 diff --git a/ports/nordic/common-hal/alarm/__init__.c b/ports/nordic/common-hal/alarm/__init__.c index 026e117b9a6..5db3e269994 100644 --- a/ports/nordic/common-hal/alarm/__init__.c +++ b/ports/nordic/common-hal/alarm/__init__.c @@ -232,9 +232,6 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { - if (n_dios > 0) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); - } _setup_sleep_alarms(true, n_alarms, alarms); } diff --git a/ports/raspberrypi/common-hal/alarm/__init__.c b/ports/raspberrypi/common-hal/alarm/__init__.c index a72b3a368d4..39ad8ca1fe6 100644 --- a/ports/raspberrypi/common-hal/alarm/__init__.c +++ b/ports/raspberrypi/common-hal/alarm/__init__.c @@ -191,9 +191,6 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { - if (n_dios > 0) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); - } _setup_sleep_alarms(true, n_alarms, alarms); } diff --git a/ports/stm/common-hal/alarm/__init__.c b/ports/stm/common-hal/alarm/__init__.c index 1be8f8dc10d..4cdf01b7f25 100644 --- a/ports/stm/common-hal/alarm/__init__.c +++ b/ports/stm/common-hal/alarm/__init__.c @@ -129,9 +129,6 @@ mp_obj_t common_hal_alarm_light_sleep_until_alarms(size_t n_alarms, const mp_obj } void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj_t *alarms, size_t n_dios, digitalio_digitalinout_obj_t **preserve_dios) { - if (n_dios > 0) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); - } _setup_sleep_alarms(true, n_alarms, alarms); } diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index 4f5a4bbd64d..ed0f5e5f1f2 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -104,6 +104,10 @@ CFLAGS += -DCIRCUITPY_AESIO=$(CIRCUITPY_AESIO) CIRCUITPY_ALARM ?= 0 CFLAGS += -DCIRCUITPY_ALARM=$(CIRCUITPY_ALARM) +# Whether `alarm.exit_and_deep_sleep_until_alarms()` supports `preserve_dios`. +CIRCUITPY_ALARM_PRESERVE_DIOS ?= 0 +CFLAGS += -DCIRCUITPY_ALARM_PRESERVE_DIOS=$(CIRCUITPY_ALARM_PRESERVE_DIOS) + CIRCUITPY_ALARM_TOUCH ?= $(CIRCUITPY_ALARM) CFLAGS += -DCIRCUITPY_ALARM_TOUCH=$(CIRCUITPY_ALARM_TOUCH) diff --git a/shared-bindings/alarm/__init__.c b/shared-bindings/alarm/__init__.c index d229246e781..ff3aa2f02f6 100644 --- a/shared-bindings/alarm/__init__.c +++ b/shared-bindings/alarm/__init__.c @@ -137,6 +137,8 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(alarm_light_sleep_until_alarms_obj, 1, MP_OB //| //| Preserving `DigitalInOut` states during deep sleep can be used to ensure that //| external or on-board devices are powered or unpowered during sleep, among other purposes. +//| Once the board wakes up from deep sleep, the `DigitalInOut` states are no longer preserved +//| and must be restored by your code. //| //| On some microcontrollers, some pins cannot remain in their original state for hardware reasons. //| @@ -193,6 +195,11 @@ static mp_obj_t alarm_exit_and_deep_sleep_until_alarms(size_t n_args, const mp_o mp_obj_t preserve_dios = args[ARG_preserve_dios].u_obj; const size_t num_dios = (size_t)MP_OBJ_SMALL_INT_VALUE(mp_obj_len(preserve_dios)); + #if !CIRCUITPY_ALARM_PRESERVE_DIOS + if (num_dios > 0) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_preserve_dios); + } + #endif digitalio_digitalinout_obj_t *dios_array[num_dios]; for (mp_uint_t i = 0; i < num_dios; i++) { diff --git a/shared-bindings/alarm/__init__.h b/shared-bindings/alarm/__init__.h index 37bfd9c51b7..5b8823162cc 100644 --- a/shared-bindings/alarm/__init__.h +++ b/shared-bindings/alarm/__init__.h @@ -26,6 +26,13 @@ extern void common_hal_alarm_set_deep_sleep_alarms(size_t n_alarms, const mp_obj extern MP_NORETURN void common_hal_alarm_enter_deep_sleep(void); +#if CIRCUITPY_ALARM_PRESERVE_DIOS +// Clear any pin preservations set up for deep sleep (real or fake), releasing +// held pins so they can be reset. Only declared on ports that implement +// `preserve_dios`. +extern void common_hal_alarm_clear_pin_preservations(void); +#endif + // May be used to re-initialize peripherals like GPIO, if the VM reset returned // them to a default state extern void common_hal_alarm_pretending_deep_sleep(void); From e8669a865acd42b621de6925362b3741eb3effc9 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 2 Jul 2026 16:48:45 -0500 Subject: [PATCH 603/876] sdioio implementation for raspberrypi port --- locale/circuitpython.pot | 15 + ports/raspberrypi/Makefile | 25 + .../adafruit_fruit_jam/mpconfigboard.mk | 2 + .../boards/adafruit_fruit_jam/pins.c | 15 + .../adafruit_metro_rp2350/mpconfigboard.h | 5 + .../adafruit_metro_rp2350/mpconfigboard.mk | 2 + .../boards/adafruit_metro_rp2350/pins.c | 15 + .../common-hal/rp2pio/StateMachine.c | 32 + ports/raspberrypi/common-hal/sdioio/SDCard.c | 263 +++++ ports/raspberrypi/common-hal/sdioio/SDCard.h | 29 + .../raspberrypi/common-hal/sdioio/__init__.c | 8 + .../sdioio/sdfat_pio/SdCard/PioSdio/DbgLog.h | 41 + .../sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp | 1026 +++++++++++++++++ .../sdfat_pio/SdCard/PioSdio/PioSdioCard.h | 350 ++++++ .../SdCard/PioSdio/PioSdioCard.pio.h | 331 ++++++ .../sdioio/sdfat_pio/SdCard/SdCardInfo.h | 530 +++++++++ .../sdioio/sdfat_pio/SdCard/SdCardInterface.h | 110 ++ .../sdfat_pio/common/FsBlockDeviceInterface.h | 117 ++ .../sdioio/sdfat_pio/common/SysCall.h | 56 + .../sdioio/sdfat_pio/cxx_runtime.cpp | 33 + .../sdioio/sdfat_pio/rp2_pio_alloc.h | 36 + .../common-hal/sdioio/sdfat_pio/shim.cpp | 80 ++ .../common-hal/sdioio/sdfat_pio/shim.h | 74 ++ ports/raspberrypi/supervisor/port.c | 8 + shared-module/sdcardio/__init__.c | 16 + supervisor/shared/filesystem.c | 2 + 26 files changed, 3221 insertions(+) create mode 100644 ports/raspberrypi/common-hal/sdioio/SDCard.c create mode 100644 ports/raspberrypi/common-hal/sdioio/SDCard.h create mode 100644 ports/raspberrypi/common-hal/sdioio/__init__.c create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/DbgLog.h create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.pio.h create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInfo.h create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/FsBlockDeviceInterface.h create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/SysCall.h create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/cxx_runtime.cpp create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp create mode 100644 ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 117b3053610..4ae873b6afe 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -717,6 +717,7 @@ msgstr "" #: ports/atmel-samd/common-hal/sdioio/SDCard.c #: ports/cxd56/common-hal/sdioio/SDCard.c #: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c #: shared-module/sdcardio/SDCard.c #, c-format @@ -936,6 +937,10 @@ msgstr "" msgid "Data not supported with directed advertising" msgstr "" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" +msgstr "" + #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c msgid "Data too large for advertisement packet" @@ -1705,6 +1710,11 @@ msgstr "" msgid "Number of data_pins must be %d or %d, not %d" msgstr "" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" +msgstr "" + #: shared-bindings/util.c msgid "" "Object has been deinitialized and can no longer be used. Create a new object." @@ -2058,6 +2068,11 @@ msgstr "" msgid "SDIO Init Error %x" msgstr "" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" +msgstr "" + #: ports/espressif/common-hal/busio/SPI.c msgid "SPI configuration failed" msgstr "" diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index d2c550c90fa..96ba25ce30c 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -580,6 +580,22 @@ endif endif +ifeq ($(CIRCUITPY_SDIOIO),1) +# Vendored Adafruit SdFat PIO SDIO card driver (C++). The common-hal C sources +# (SDCard.c, __init__.c) are picked up automatically through SRC_COMMON_HAL. +SRC_SDIOIO_CXX := \ + common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp \ + common-hal/sdioio/sdfat_pio/shim.cpp \ + common-hal/sdioio/sdfat_pio/cxx_runtime.cpp \ + +INC += -Icommon-hal/sdioio/sdfat_pio + +# The upstream driver body is guarded by ARDUINO_ARCH_RP2040 and was written +# against the Arduino RP2040 core, so define that macro for it. It is vendored +# third-party code, so don't fail the build on its warnings. +$(BUILD)/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.o: CXXFLAGS += -DARDUINO_ARCH_RP2040 -Wno-error +endif + ifeq ($(CIRCUITPY_SSL),1) CFLAGS += -isystem $(TOP)/mbedtls/include SRC_MBEDTLS := $(addprefix lib/mbedtls/library/, \ @@ -683,6 +699,12 @@ endif $(patsubst %.S,$(BUILD)/%.o,$(SRC_S_UPPER)): CFLAGS += -Wno-undef +# Derive the C++ flags from the C flags (mirroring the unix port) so the +# vendored C++ translation unit picks up all the SDK include paths and defines. +# Strip the C-only options that g++ rejects, and disable exceptions/RTTI to +# match the firmware's constraints. +CXXFLAGS += $(filter-out -std=gnu11 -Werror=missing-prototypes -Wold-style-definition -Wstrict-prototypes -Werror-implicit-function-declaration -Wnested-externs,$(CFLAGS)) -std=gnu++17 -fno-exceptions -fno-rtti + OBJ = $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_SDK:.c=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_SHARED_MODULE_EXPANDED:.c=.o)) @@ -695,6 +717,9 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_S_UPPER:.S=.o)) OBJ += $(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)) OBJ += $(BUILD)/boot2_padded_checksummed.o OBJ += $(OBJ_MBEDTLS) +ifeq ($(CIRCUITPY_SDIOIO),1) +OBJ += $(addprefix $(BUILD)/, $(SRC_SDIOIO_CXX:.cpp=.o)) +endif $(BUILD)/%.o: $(BUILD)/%.S $(STEPECHO) "CC $<" diff --git a/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk index 31c4b130d0e..086c823adb4 100644 --- a/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk @@ -9,5 +9,7 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" +CIRCUITPY_SDIOIO = 1 + # CIRCUITPY_DISPLAY_FONT = $(TOP)/tools/fonts/unifont-16.0.02-all.bdf # CIRCUITPY_FONT_EXTRA_CHARACTERS = "🖮🖱️" diff --git a/ports/raspberrypi/boards/adafruit_fruit_jam/pins.c b/ports/raspberrypi/boards/adafruit_fruit_jam/pins.c index 82c4d19eb38..e6d41ae4989 100644 --- a/ports/raspberrypi/boards/adafruit_fruit_jam/pins.c +++ b/ports/raspberrypi/boards/adafruit_fruit_jam/pins.c @@ -4,8 +4,21 @@ // // SPDX-License-Identifier: MIT +#include "py/objtuple.h" #include "shared-bindings/board/__init__.h" +// Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). +static const mp_rom_obj_tuple_t sdio_data_tuple = { + {&mp_type_tuple}, + 4, + { + MP_ROM_PTR(&pin_GPIO36), + MP_ROM_PTR(&pin_GPIO37), + MP_ROM_PTR(&pin_GPIO38), + MP_ROM_PTR(&pin_GPIO39), + } +}; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -91,6 +104,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO39) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA3), MP_ROM_PTR(&pin_GPIO39) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CARD_DETECT), MP_ROM_PTR(&pin_GPIO33) }, { MP_ROM_QSTR(MP_QSTR_USB_HOST_DATA_PLUS), MP_ROM_PTR(&pin_GPIO1) }, diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h index 1a583046416..c8f4d7975dd 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h @@ -36,6 +36,11 @@ #define DEFAULT_DVI_BUS_BLUE_DN (&pin_GPIO13) #define DEFAULT_DVI_BUS_BLUE_DP (&pin_GPIO12) +// These SD pins double as the 4-bit SDIO interface (board.SDIO_*): SCK=CLOCK, +// MOSI=COMMAND, MISO=DATA0, CS=DATA3. By default the SPI automount claims them +// and mounts the card over SPI, so sdioio.SDCard() would fail with " in +// use". Set CIRCUITPY_SDCARD_USB = false in settings.toml to free the pins for +// sdioio (this also disables the automatic /sd mount on this board). #define DEFAULT_SD_SCK (&pin_GPIO34) #define DEFAULT_SD_MOSI (&pin_GPIO35) #define DEFAULT_SD_MISO (&pin_GPIO36) diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk index e43a8dcf2a3..6d499c367d7 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.mk @@ -8,3 +8,5 @@ CHIP_PACKAGE = B CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" + +CIRCUITPY_SDIOIO = 1 diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/pins.c b/ports/raspberrypi/boards/adafruit_metro_rp2350/pins.c index 3fa135b1796..a38c2496dd6 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2350/pins.c +++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/pins.c @@ -4,8 +4,21 @@ // // SPDX-License-Identifier: MIT +#include "py/objtuple.h" #include "shared-bindings/board/__init__.h" +// Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). +static const mp_rom_obj_tuple_t sdio_data_tuple = { + {&mp_type_tuple}, + 4, + { + MP_ROM_PTR(&pin_GPIO36), + MP_ROM_PTR(&pin_GPIO37), + MP_ROM_PTR(&pin_GPIO38), + MP_ROM_PTR(&pin_GPIO39), + } +}; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -85,6 +98,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO39) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA3), MP_ROM_PTR(&pin_GPIO39) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CARD_DETECT), MP_ROM_PTR(&pin_GPIO40) }, { MP_ROM_QSTR(MP_QSTR_USB_HOST_DATA_PLUS), MP_ROM_PTR(&pin_GPIO32) }, diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 8e1ea26ab0d..407c2c94b73 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -862,6 +862,38 @@ void rp2pio_statemachine_never_reset(PIO pio, int sm) { _never_reset[pio_index][sm] = true; } +// Pick a PIO that has room for a program of program_size instructions and at +// least sm_count free state machines; returns its index, or NUM_PIOS if none +// qualifies. This lets an out-of-tree PIO user (e.g. the sdioio SDIO driver, +// which manages its own SDK-level pio_claim_unused_sm / pio_add_program) pick a +// PIO cooperatively rather than blindly seizing pio0/pio1/pio2. Because it uses +// the same SDK claim/instruction bookkeeping that rp2pio itself relies on, a hit +// here means the caller's subsequent claims on the returned PIO will succeed and +// will not collide with an existing rp2pio user. +uint8_t rp2pio_statemachine_find_pio(int program_size, int sm_count) { + pio_program_t test_program = { + .instructions = NULL, + .length = program_size, + .origin = -1, + }; + for (size_t i = 0; i < NUM_PIOS; i++) { + PIO pio = pio_get_instance(i); + if (!pio_can_add_program(pio, &test_program)) { + continue; + } + int free_sms = 0; + for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { + if (!pio_sm_is_claimed(pio, j)) { + free_sms++; + } + } + if (free_sms >= sm_count) { + return i; + } + } + return NUM_PIOS; +} + void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins) { common_hal_rp2pio_statemachine_stop(self); (void)common_hal_rp2pio_statemachine_stop_background_write(self); diff --git a/ports/raspberrypi/common-hal/sdioio/SDCard.c b/ports/raspberrypi/common-hal/sdioio/SDCard.c new file mode 100644 index 00000000000..46510ae8576 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/SDCard.c @@ -0,0 +1,263 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +#include "common-hal/sdioio/SDCard.h" +#include "common-hal/sdioio/sdfat_pio/shim.h" + +#include "extmod/vfs.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "shared-bindings/sdioio/SDCard.h" +#include "shared-bindings/util.h" +#include "py/mperrno.h" +#include "py/runtime.h" + +#include "hardware/platform_defs.h" // NUM_PIOS + +// Live-instance tracking for soft-reset cleanup. The vendored SdFat PIO driver +// claims its PIO block through the raw SDK (pio_claim_unused_sm), whose claim +// bitset lives in static RAM and survives a soft reboot. Because the GC heap is +// wiped without running finalizers, a successfully-constructed card would leak +// its whole PIO block on every Ctrl-D (see sdio_init_troubleshooting.md, +// "Error 43 is a PIO-leak red herring"). We keep a static table of the live +// cards so sdioio_reset() can deinit them (→ pioEnd() → SDK unclaim) before the +// heap is reset. A card is registered only after a fully successful construct +// and removed on deinit; each card consumes a whole PIO, so NUM_PIOS slots is a +// hard upper bound. +static sdioio_sdcard_obj_t *_active_cards[NUM_PIOS]; + +static void register_card(sdioio_sdcard_obj_t *self) { + for (size_t i = 0; i < MP_ARRAY_SIZE(_active_cards); i++) { + if (_active_cards[i] == NULL) { + _active_cards[i] = self; + return; + } + } +} + +static void unregister_card(sdioio_sdcard_obj_t *self) { + for (size_t i = 0; i < MP_ARRAY_SIZE(_active_cards); i++) { + if (_active_cards[i] == self) { + _active_cards[i] = NULL; + return; + } + } +} + +// Maximum SD clock the PIO driver is allowed to be asked for. At a typical +// 150 MHz clk_sys the driver tops out near 37.5 MHz (clkDiv == 1); the cap is +// generous and the achieved rate is reported back through the `frequency` +// property. +#define SDIO_MAX_FREQUENCY (50000000) + +void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, + const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, + uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency) { + // The vendored PIO driver only supports 4-bit mode and requires the four + // data lines to be on consecutive GPIOs (DAT0..DAT3). 1-bit mode is a + // documented follow-up. + if (num_data != 4) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Number of data_pins must be %d, not %d"), 4, num_data); + } + for (size_t i = 1; i < num_data; i++) { + if (data[i]->number != data[0]->number + i) { + mp_raise_ValueError(MP_ERROR_TEXT("Data pins must be consecutive")); + } + } + + mp_arg_validate_int_max(frequency, SDIO_MAX_FREQUENCY, MP_QSTR_frequency); + + self->num_data = num_data; + self->clock = clock->number; + self->command = command->number; + for (size_t i = 0; i < num_data; i++) { + self->data[i] = data[i]->number; + } + + claim_pin(clock); + claim_pin(command); + for (size_t i = 0; i < num_data; i++) { + claim_pin(data[i]); + } + + sdfat_pio_card_new(&self->card); + uint32_t actual_frequency = 0; + bool ok = sdfat_pio_card_begin(&self->card, clock->number, command->number, + data[0]->number, frequency, &actual_frequency); + if (!ok) { + // The driver's error code identifies the SD command/phase that failed + // (see SdCardInfo.h SD_CARD_ERROR_* codes). + uint8_t error_code = sdfat_pio_card_error_code(&self->card); + sdfat_pio_card_end(&self->card); + sdfat_pio_card_free(&self->card); + reset_pin_number(self->clock); + reset_pin_number(self->command); + for (size_t i = 0; i < num_data; i++) { + reset_pin_number(self->data[i]); + } + self->command = COMMON_HAL_MCU_NO_PIN; + mp_raise_OSError_msg_varg( + MP_ERROR_TEXT("SDIO Init Error 0x%02x"), error_code); + } + + self->frequency = actual_frequency; + self->capacity = sdfat_pio_card_sector_count(&self->card); + + // Track the live card so sdioio_reset() can release its leaked PIO block on + // the next soft reboot. + register_card(self); +} + +uint32_t common_hal_sdioio_sdcard_get_count(sdioio_sdcard_obj_t *self) { + return self->capacity; +} + +uint32_t common_hal_sdioio_sdcard_get_frequency(sdioio_sdcard_obj_t *self) { + return self->frequency; +} + +uint8_t common_hal_sdioio_sdcard_get_width(sdioio_sdcard_obj_t *self) { + return self->num_data; +} + +static void check_for_deinit(sdioio_sdcard_obj_t *self) { + if (common_hal_sdioio_sdcard_deinited(self)) { + raise_deinited_error(); + } +} + +static void check_whole_block(mp_buffer_info_t *bufinfo) { + if (bufinfo->len % 512) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 512); + } +} + +// Native function for the VFS blockdev layer. The PIO driver is synchronous and +// polling, so these block until the transfer completes. +mp_negative_errno_t sdioio_sdcard_readblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!sdfat_pio_card_read_sectors(&self->card, start_block, buf, num_blocks)) { + return -MP_EIO; + } + return 0; +} + +mp_negative_errno_t sdioio_sdcard_writeblocks(mp_obj_t self_in, uint8_t *buf, + uint32_t start_block, uint32_t num_blocks) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + if (!sdfat_pio_card_write_sectors(&self->card, start_block, buf, num_blocks)) { + return -MP_EIO; + } + return 0; +} + +mp_negative_errno_t common_hal_sdioio_sdcard_readblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_readblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +mp_negative_errno_t common_hal_sdioio_sdcard_writeblocks(sdioio_sdcard_obj_t *self, uint32_t start_block, mp_buffer_info_t *bufinfo) { + check_for_deinit(self); + check_whole_block(bufinfo); + uint32_t num_blocks = bufinfo->len / 512; + return sdioio_sdcard_writeblocks(MP_OBJ_FROM_PTR(self), bufinfo->buf, + start_block, num_blocks); +} + +// Native function for VFS blockdev layer. +bool sdioio_sdcard_ioctl(mp_obj_t self_in, size_t cmd, size_t arg, + mp_int_t *out_value) { + sdioio_sdcard_obj_t *self = MP_OBJ_TO_PTR(self_in); + *out_value = 0; + + switch (cmd) { + case MP_BLOCKDEV_IOCTL_DEINIT: + case MP_BLOCKDEV_IOCTL_SYNC: + // SDIO operations are synchronous, no action needed. + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_COUNT: + *out_value = common_hal_sdioio_sdcard_get_count(self); + return true; + + case MP_BLOCKDEV_IOCTL_BLOCK_SIZE: + *out_value = 512; // SD cards use 512-byte sectors. + return true; + + default: + return false; // Unsupported command. + } +} + +bool common_hal_sdioio_sdcard_configure(sdioio_sdcard_obj_t *self, uint32_t frequency, uint8_t bits) { + // Only 4-bit mode is supported (see construct); reject a request for any + // other width. Reconfiguring the clock at runtime is not implemented yet, + // so the frequency argument is accepted but ignored. + if (bits != 0 && bits != self->num_data) { + return false; + } + return true; +} + +bool common_hal_sdioio_sdcard_deinited(sdioio_sdcard_obj_t *self) { + return self->command == COMMON_HAL_MCU_NO_PIN; +} + +void common_hal_sdioio_sdcard_deinit(sdioio_sdcard_obj_t *self) { + if (common_hal_sdioio_sdcard_deinited(self)) { + return; + } + + unregister_card(self); + + sdfat_pio_card_end(&self->card); + sdfat_pio_card_free(&self->card); + + reset_pin_number(self->command); + self->command = COMMON_HAL_MCU_NO_PIN; + reset_pin_number(self->clock); + self->clock = COMMON_HAL_MCU_NO_PIN; + for (size_t i = 0; i < self->num_data; i++) { + reset_pin_number(self->data[i]); + self->data[i] = COMMON_HAL_MCU_NO_PIN; + } +} + +void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) { + if (common_hal_sdioio_sdcard_deinited(self)) { + return; + } + + self->never_reset = true; + + never_reset_pin_number(self->command); + never_reset_pin_number(self->clock); + for (size_t i = 0; i < self->num_data; i++) { + never_reset_pin_number(self->data[i]); + } + + // Also protect the PIO state machines the driver claimed so the rp2pio + // soft-reset path keeps its never-reset bookkeeping coherent with them. + sdfat_pio_card_never_reset(&self->card); +} + +void sdioio_reset(void) { + // Release every live card that isn't protected by never_reset. deinit() + // runs pioEnd(), which unclaims the PIO at the SDK level — without this the + // claim (static RAM) survives the soft reboot even though the object heap is + // wiped, permanently burning a PIO block per successful construct. + for (size_t i = 0; i < MP_ARRAY_SIZE(_active_cards); i++) { + sdioio_sdcard_obj_t *self = _active_cards[i]; + if (self == NULL || self->never_reset) { + continue; + } + // deinit() calls unregister_card(), clearing this slot. + common_hal_sdioio_sdcard_deinit(self); + } +} diff --git a/ports/raspberrypi/common-hal/sdioio/SDCard.h b/ports/raspberrypi/common-hal/sdioio/SDCard.h new file mode 100644 index 00000000000..e25331fd51d --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/SDCard.h @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/microcontroller/Pin.h" +#include "common-hal/sdioio/sdfat_pio/shim.h" +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + // In-place storage for the vendored C++ PioSdioCard instance, constructed + // and torn down through the extern "C" shim in sdfat_pio/. + sdioio_pio_card_storage_t card; + uint32_t frequency; + uint32_t capacity; // Number of 512-byte blocks. + uint8_t num_data; + uint8_t command; + uint8_t clock; + uint8_t data[4]; + bool never_reset; +} sdioio_sdcard_obj_t; + +// Called by the supervisor on soft reset to release any card that is not +// protected with never_reset. +void sdioio_reset(void); diff --git a/ports/raspberrypi/common-hal/sdioio/__init__.c b/ports/raspberrypi/common-hal/sdioio/__init__.c new file mode 100644 index 00000000000..16ed83d3e9b --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/__init__.c @@ -0,0 +1,8 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +// No sdioio module functions. The whole API lives on sdioio.SDCard, which is +// implemented in SDCard.c. diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/DbgLog.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/DbgLog.h new file mode 100644 index 00000000000..8d1ba8db85a --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/DbgLog.h @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief Classes for Debug messages. + * + * CircuitPython vendored, trimmed copy. The upstream DbgLog.h includes the + * Arduino Printable.h and defines a family of helper print classes (Bin, Hex, + * Num, Dbl, logmsg...). Those are only referenced when debug output is enabled + * (ENABLE_DBG_MSG / USE_DEBUG_MODE), which it is not in this build, so they are + * omitted to keep the Arduino Print dependency out of the firmware. Only the + * no-op DBG_MSG() macro that PioSdioCard.cpp uses on its normal paths remains. + */ +#pragma once + +/** Debug messages are disabled in the CircuitPython build. */ +#define DBG_MSG(...) \ + do { \ + } while (0) diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp new file mode 100644 index 00000000000..7c0bf8d323a --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp @@ -0,0 +1,1026 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +#ifdef ARDUINO_ARCH_RP2040 +#include + +#include // Required for std::max, std::min +#define DEBUG_FILE "PioSdioCard.cpp" +#include "../SdCardInfo.h" +#include "DbgLog.h" +#include "PioSdioCard.h" +#include "PioSdioCard.pio.h" +// CIRCUITPY-CHANGE: cooperate with CircuitPython's rp2pio PIO allocator. +#include "../../rp2_pio_alloc.h" +//------------------------------------------------------------------------------ +// USE_DEBUG_MODE 0 - no debug, 1 - print message, 2 - Use scope/analyzer. +#define USE_DEBUG_MODE 0 + +const uint PIO_CLK_DIV_RUN = 1; + +const uint PIN_SDIO_UNDEFINED = 63u; + +const uint DAT_FIFO_DEPTH = 8; +//============================================================================== +// Command definitions. +enum { RSP_R0 = 0, RSP_R1 = 1, RSP_R2 = 2, RSP_R3 = 3, RSP_R6 = 6, RSP_R7 = 7 }; +static const CmdRsp_t CMD0_R0(CMD0, RSP_R0); +static const CmdRsp_t CMD2_R2(CMD2, RSP_R2); +static const CmdRsp_t CMD3_R6(CMD3, RSP_R6); +static const CmdRsp_t CMD6_R1(CMD6, RSP_R1); +static const CmdRsp_t CMD7_R1(CMD7, RSP_R1); +static const CmdRsp_t CMD8_R7(CMD8, RSP_R7); +static const CmdRsp_t CMD9_R2(CMD9, RSP_R2); +static const CmdRsp_t CMD10_R2(CMD10, RSP_R2); +static const CmdRsp_t CMD12_R1(CMD12, RSP_R1); +static const CmdRsp_t CMD13_R1(CMD13, RSP_R1); +static const CmdRsp_t CMD18_R1(CMD18, RSP_R1); +static const CmdRsp_t CMD25_R1(CMD25, RSP_R1); +static const CmdRsp_t CMD32_R1(CMD32, RSP_R1); +static const CmdRsp_t CMD33_R1(CMD33, RSP_R1); +static const CmdRsp_t CMD38_R1(CMD38, RSP_R1); +static const CmdRsp_t CMD55_R1(CMD55, RSP_R1); +static const CmdRsp_t ACMD6_R1(ACMD6, RSP_R1); +static const CmdRsp_t ACMD13_R1(ACMD13, RSP_R1); +static const CmdRsp_t ACMD41_R3(ACMD41, RSP_R3); +static const CmdRsp_t ACMD51_R1(ACMD51, RSP_R1); +//============================================================================== +class Timeout { + public: + explicit Timeout(uint ms) : _usStart(0), _usTimeout(1000 * ms) {} + bool timedOut() { + if (_usStart) { + return (usSinceBoot() - _usStart) > _usTimeout; + } + _usStart = usSinceBoot(); + return false; + } + uint32_t usSinceBoot() { return to_us_since_boot(get_absolute_time()); } + uint32_t _usStart; + uint32_t _usTimeout; +}; +//============================================================================== +#if USE_DEBUG_MODE +//------------------------------------------------------------------------------ +static inline void gpioStatus(uint gpio) { + logmsgln("gpio", gpio, " drive: ", gpio_get_drive_strength(gpio)); + // logmsgln("gpio", gpio, + // " drive: ", static_cast(gpio_get_drive_strength(gpio))); + logmsgln("gpio", gpio, " slew: ", gpio_get_slew_rate(gpio)); + logmsgln("gpio", gpio, " hyst: ", gpio_is_input_hysteresis_enabled(gpio)); + logmsgln("gpio", gpio, " pull: ", gpio_is_pulled_up(gpio)); +} +//------------------------------------------------------------------------------ +static inline void pioRegs(PIO pio) { + logmsgln("ctrl: 0b", Bin(pio->ctrl)); + logmsgln("fstat: 0b", Bin(pio->fstat)); + logmsgln("fdebug: 0b", Bin(pio->fdebug)); + logmsgln("flevel: 0b", Bin(pio->flevel)); + logmsgln("padout: 0b", Bin(pio->dbg_padout)); + logmsgln("padoe: 0b", Bin(pio->dbg_padoe)); + logmsgln("cfginfo: 0x", Hex(pio->dbg_cfginfo)); + logmsgln("sync_bypass: 0b", Bin(pio->input_sync_bypass)); +} +//------------------------------------------------------------------------------ +static inline void pioSmRegs(PIO pio, uint sm) { + logmsgln("sm", sm, " clkdiv: 0x", Hex(pio->sm[sm].clkdiv)); + logmsgln("sm", sm, " execctrl: 0x", Hex(pio->sm[sm].execctrl)); + logmsgln("sm", sm, " shiftctrl: 0x", Hex(pio->sm[sm].shiftctrl)); + logmsgln("sm", sm, " addr: 0x", Hex(pio->sm[sm].addr)); + logmsgln("sm", sm, " pinctrl: 0x", Hex(pio->sm[sm].pinctrl)); +} +//------------------------------------------------------------------------------ +#endif // USE_DEBUG_MODE +#define sdError(code) \ + { \ + setSdErrorCode(code, __LINE__); \ + DBG_MSG(#code); \ + } +#define SDIO_FAIL() DBG_MSG("SDIO_FAIL") +//============================================================================== +// CRC functions. +//------------------------------------------------------------------------------ +// See this library's extras folder. +static const uint8_t crc7_table[256] = { + 0x00, 0x12, 0x24, 0x36, 0x48, 0x5a, 0x6c, 0x7e, // 00 - 07 + 0x90, 0x82, 0xb4, 0xa6, 0xd8, 0xca, 0xfc, 0xee, // 08 - 0f + 0x32, 0x20, 0x16, 0x04, 0x7a, 0x68, 0x5e, 0x4c, // 10 - 17 + 0xa2, 0xb0, 0x86, 0x94, 0xea, 0xf8, 0xce, 0xdc, // 18 - 1f + 0x64, 0x76, 0x40, 0x52, 0x2c, 0x3e, 0x08, 0x1a, // 20 - 27 + 0xf4, 0xe6, 0xd0, 0xc2, 0xbc, 0xae, 0x98, 0x8a, // 28 - 2f + 0x56, 0x44, 0x72, 0x60, 0x1e, 0x0c, 0x3a, 0x28, // 30 - 37 + 0xc6, 0xd4, 0xe2, 0xf0, 0x8e, 0x9c, 0xaa, 0xb8, // 38 - 3f + 0xc8, 0xda, 0xec, 0xfe, 0x80, 0x92, 0xa4, 0xb6, // 40 - 47 + 0x58, 0x4a, 0x7c, 0x6e, 0x10, 0x02, 0x34, 0x26, // 48 - 4f + 0xfa, 0xe8, 0xde, 0xcc, 0xb2, 0xa0, 0x96, 0x84, // 50 - 57 + 0x6a, 0x78, 0x4e, 0x5c, 0x22, 0x30, 0x06, 0x14, // 58 - 5f + 0xac, 0xbe, 0x88, 0x9a, 0xe4, 0xf6, 0xc0, 0xd2, // 60 - 67 + 0x3c, 0x2e, 0x18, 0x0a, 0x74, 0x66, 0x50, 0x42, // 68 - 6f + 0x9e, 0x8c, 0xba, 0xa8, 0xd6, 0xc4, 0xf2, 0xe0, // 70 - 77 + 0x0e, 0x1c, 0x2a, 0x38, 0x46, 0x54, 0x62, 0x70, // 78 - 7f + 0x82, 0x90, 0xa6, 0xb4, 0xca, 0xd8, 0xee, 0xfc, // 80 - 87 + 0x12, 0x00, 0x36, 0x24, 0x5a, 0x48, 0x7e, 0x6c, // 88 - 8f + 0xb0, 0xa2, 0x94, 0x86, 0xf8, 0xea, 0xdc, 0xce, // 90 - 97 + 0x20, 0x32, 0x04, 0x16, 0x68, 0x7a, 0x4c, 0x5e, // 98 - 9f + 0xe6, 0xf4, 0xc2, 0xd0, 0xae, 0xbc, 0x8a, 0x98, // a0 - a7 + 0x76, 0x64, 0x52, 0x40, 0x3e, 0x2c, 0x1a, 0x08, // a8 - af + 0xd4, 0xc6, 0xf0, 0xe2, 0x9c, 0x8e, 0xb8, 0xaa, // b0 - b7 + 0x44, 0x56, 0x60, 0x72, 0x0c, 0x1e, 0x28, 0x3a, // b8 - bf + 0x4a, 0x58, 0x6e, 0x7c, 0x02, 0x10, 0x26, 0x34, // c0 - c7 + 0xda, 0xc8, 0xfe, 0xec, 0x92, 0x80, 0xb6, 0xa4, // c8 - cf + 0x78, 0x6a, 0x5c, 0x4e, 0x30, 0x22, 0x14, 0x06, // d0 - d7 + 0xe8, 0xfa, 0xcc, 0xde, 0xa0, 0xb2, 0x84, 0x96, // d8 - df + 0x2e, 0x3c, 0x0a, 0x18, 0x66, 0x74, 0x42, 0x50, // e0 - e7 + 0xbe, 0xac, 0x9a, 0x88, 0xf6, 0xe4, 0xd2, 0xc0, // e8 - ef + 0x1c, 0x0e, 0x38, 0x2a, 0x54, 0x46, 0x70, 0x62, // f0 - f7 + 0x8c, 0x9e, 0xa8, 0xba, 0xc4, 0xd6, 0xe0, 0xf2 // f8 - ff +}; +//------------------------------------------------------------------------------ +inline static uint8_t CRC7(const uint8_t* data, uint8_t n) { + uint8_t crc = 0; + for (uint8_t i = 0; i < n; i++) { + crc = crc7_table[crc ^ data[i]]; + } + return crc | 1; +} +//------------------------------------------------------------------------------ +// Modified from sdio_crc16_4bit_checksum() in +// https://github.com/ZuluSCSI/ZuluSCSI-firmware +// +static inline __attribute__((always_inline)) uint64_t crc16(uint64_t crc, + uint32_t data_in) { + // Shift out 8 bits for each line + uint32_t data_out = crc >> 32; + crc <<= 32; + + // XOR outgoing data to itself with 4 bit delay + data_out ^= (data_out >> 16); + + // XOR incoming data to outgoing data with 4 bit delay + data_out ^= (data_in >> 16); + + // XOR outgoing and incoming data to accumulator at each tap + uint64_t xorred = data_out ^ data_in; + crc ^= xorred; + crc ^= xorred << (5 * 4); + crc ^= xorred << (12 * 4); + return crc; +} +//------------------------------------------------------------------------------ +//============================================================================== +// add to PioSdioCard class int the future. +// PioSdioCard::PioSdioCard() +// PioSdioCard::~PioSdioCard() +//------------------------------------------------------------------------------ +bool PioSdioCard::cardAcmd(uint32_t rca, CmdRsp_t cmdRsp, uint32_t arg) { + return cardCommand(CMD55_R1, rca) && cardCommand(cmdRsp, arg); +} +//------------------------------------------------------------------------------ +bool PioSdioCard::begin(PioSdioConfig sdioConfig) { + pioEnd(); + Timeout timeout(SD_INIT_TIMEOUT); + uint32_t arg; + m_curState = IDLE_STATE; + m_errorCode = SD_CARD_ERROR_NONE; + m_highCapacity = false; + m_initDone = false; + m_version2 = false; + m_clkPin = sdioConfig.clkPin(); + m_cmdPin = sdioConfig.cmdPin(); + m_dat0Pin = sdioConfig.dat0Pin(); + + // Four PIO cycles per SD CLK cycle. + m_clkDiv = ceil((0.00025 * clock_get_hz(clk_sys)) / SD_MAX_INIT_RATE_KHZ); + +#if USE_DEBUG_MODE == 2 + Serial.println(); + pioRegs(m_pio); + pioSmRegs(m_pio, m_sm0); + pioSmRegs(m_pio, m_sm1); + gpioStatus(m_clkPin); + gpioStatus(m_cmdPin); + while (Serial.read() >= 0) { + } + Serial.println("Logic Analyzer on then type any char"); + while (!Serial.available()) { + } +#endif // USE_DEBUG_MODE + // A few cards still require clocks after power-up. + powerUpClockCycles(); + if (!pioInit()) { + goto fail; + } + pioConfig(m_clkDiv); + if (!cardCommand(CMD0_R0, 0)) { + sdError(SD_CARD_ERROR_CMD0); + goto fail; + } + if (cardCommand(CMD8_R7, 0X1AA)) { + if (m_cardRsp != 0X1AA) { + sdError(SD_CARD_ERROR_CMD8); + goto fail; + } + m_version2 = true; + } else { + m_version2 = false; + m_errorCode = SD_CARD_ERROR_NONE; + } + arg = m_version2 ? 0X40300000 : 0x00300000; + while (true) { + if (!cardAcmd(0, ACMD41_R3, arg)) { + sdError(SD_CARD_ERROR_ACMD41); + goto fail; + } + if (m_cardRsp & 0x80000000) { + break; + } + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_ACMD41); + goto fail; + } + } + m_ocr = m_cardRsp; + if (m_cardRsp & 0x40000000) { + // Is high capacity. + m_highCapacity = true; + } + if (!cardCommand(CMD2_R2, 0)) { + sdError(SD_CARD_ERROR_CMD2); + goto fail; + } + if (!cardCommand(CMD3_R6, 0)) { + sdError(SD_CARD_ERROR_CMD3); + goto fail; + } + m_rca = m_cardRsp & 0xFFFF0000; + if (!cardCommand(CMD9_R2, m_rca, &m_csd)) { + sdError(SD_CARD_ERROR_CMD9); + goto fail; + } + if (!cardCommand(CMD10_R2, m_rca, &m_cid)) { + sdError(SD_CARD_ERROR_CMD10); + goto fail; + } + if (!cardCommand(CMD7_R1, m_rca)) { + sdError(SD_CARD_ERROR_CMD7); + goto fail; + } + + if (!cardAcmd(m_rca, ACMD6_R1, 2)) { + sdError(SD_CARD_ERROR_ACMD6); + goto fail; + } + m_clkDiv = sdioConfig.clkDiv(); + pioConfig(m_clkDiv); + if (!cardAcmd(m_rca, ACMD51_R1, 0)) { + sdError(SD_CARD_ERROR_ACMD51); + goto fail; + } + if (!readData(&m_scr, sizeof(m_scr))) { + DBG_MSG("readData"); + goto fail; + } + if (!cardAcmd(m_rca, ACMD13_R1, 0)) { + sdError(SD_CARD_ERROR_ACMD13); + SDIO_FAIL(); + goto fail; + } + + if (!readData(&m_sds, sizeof(m_sds))) { + SDIO_FAIL(); + goto fail; + } + m_initDone = true; + + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::cardCMD6(uint32_t arg, uint8_t* status) { + if (!cardCommand(CMD6_R1, arg)) { + sdError(SD_CARD_ERROR_CMD6); + goto fail; + } + if (!readData(status, 64)) { + SDIO_FAIL(); + goto fail; + } + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::cardCommand(CmdRsp_t cmd, uint32_t arg, void* rsp) { + uint8_t buf[6]; + uint nRsp = cmd.rsp == RSP_R0 ? 0 : cmd.rsp == RSP_R2 ? 17 : 6; + const io_ro_8* rxFifo = reinterpret_cast(&m_pio->rxf[m_sm0]); + io_wo_8* txFifo = reinterpret_cast(&m_pio->txf[m_sm0]); + pio_sm_set_enabled(m_pio, m_sm1, false); + pio_sm_init(m_pio, m_sm0, m_cmdRspOffset, &m_cmdConfig); + pio_sm_exec(m_pio, m_sm0, pio_encode_set(pio_pindirs, 1)); + *txFifo = 55; + pio_sm_exec(m_pio, m_sm0, pio_encode_out(pio_x, 8)); + *txFifo = nRsp ? 8 * nRsp - 1 : 0; + pio_sm_exec(m_pio, m_sm0, pio_encode_out(pio_y, 8)); + pio_sm_set_enabled(m_pio, m_sm0, true); + uint n = 0; + buf[n++] = (uint8_t)(cmd.idx | 0x40); + buf[n++] = (uint8_t)(arg >> 24U); + buf[n++] = (uint8_t)(arg >> 16U); + buf[n++] = (uint8_t)(arg >> 8U); + buf[n++] = (uint8_t)arg; + buf[n++] = CRC7(buf, 5); + *txFifo = 0XFF; + for (uint i = 0; i < n; i++) { + while (pio_sm_is_tx_fifo_full(m_pio, m_sm0)) { + } + *txFifo = buf[i]; + } + + Timeout timeout(SD_CMD_TIMEOUT); + if (!nRsp) { + uint32_t fdebug_tx_stall = 1u << (PIO_FDEBUG_TXSTALL_LSB + m_sm0); + m_pio->fdebug = fdebug_tx_stall; + while (!(m_pio->fdebug & fdebug_tx_stall)) { + if (timeout.timedOut()) { + goto fail; + } + } + goto done; + } + uint8_t rtn[20]; + + for (uint i = 0; i < nRsp; i++) { + while (pio_sm_is_rx_fifo_empty(m_pio, m_sm0)) { + if (timeout.timedOut()) { + goto fail; + } + } + rtn[i] = *rxFifo; + } + if (cmd.rsp == RSP_R3) { + if (rtn[0] != 0X3F || rtn[5] != 0XFF) { + goto fail; + } + } else { + uint8_t crc; + if (cmd.rsp == RSP_R2) { + crc = CRC7(rtn + 1, nRsp - 2); + } else { + crc = CRC7(rtn, nRsp - 1); + } + if (rtn[nRsp - 1] != crc) { +#if USE_DEBUG_MODE + Serial.printf("CHK: %02X, CRC: %02X\n", rtn[nRsp - 1], crc); + for (uint i = 0; i < nRsp; i++) { + Serial.printf(" %02X", rtn[i]); + } + Serial.println(); +#endif // USE_DEBUG_MODE + sdError(SD_CARD_ERROR_READ_CRC); + goto fail; + } + } + if (nRsp == 6) { + m_cardRsp = (rtn[1] << 24) | (rtn[2] << 16) | (rtn[3] << 8) | rtn[4]; + if (rsp) { + *reinterpret_cast(rsp) = m_cardRsp; + } + } else if (rsp && nRsp == 17) { + memcpy(rsp, rtn + 1, 16); + } + +done: + pio_sm_set_enabled(m_pio, m_sm0, false); + return true; + +fail: +#if USE_DEBUG_MODE + DBG_MSG("CMD", cmd.idx, " failed"); +#endif // USE_DEBUG_MODE + pio_sm_set_enabled(m_pio, m_sm0, false); + return false; +} +//------------------------------------------------------------------------------ +void PioSdioCard::end() { pioEnd(); } +//------------------------------------------------------------------------------ +void PioSdioCard::neverReset() { + if (!m_pio) { + return; + } + if (m_sm0 >= 0) { + rp2pio_statemachine_never_reset(m_pio, m_sm0); + } + if (m_sm1 >= 0) { + rp2pio_statemachine_never_reset(m_pio, m_sm1); + } +} +//------------------------------------------------------------------------------ +bool PioSdioCard::erase(uint32_t firstSector, uint32_t lastSector) { + Timeout timeout(SD_ERASE_TIMEOUT); + if (!syncDevice()) { + SDIO_FAIL(); + goto fail; + } + // check for single sector erase + if (!m_csd.eraseSingleBlock()) { + // erase size mask + uint8_t m = m_csd.eraseSize() - 1; + if ((firstSector & m) != 0 || ((lastSector + 1) & m) != 0) { + // error card can't erase specified area + sdError(SD_CARD_ERROR_ERASE_SINGLE_SECTOR); + goto fail; + } + } + if (!m_highCapacity) { + firstSector <<= 9; + lastSector <<= 9; + } + if (!cardCommand(CMD32_R1, firstSector)) { + sdError(SD_CARD_ERROR_CMD32); + goto fail; + } + if (!cardCommand(CMD33_R1, lastSector)) { + sdError(SD_CARD_ERROR_CMD33); + goto fail; + } + if (!cardCommand(CMD38_R1, 0)) { + sdError(SD_CARD_ERROR_CMD38); + goto fail; + } + while (isBusy()) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_ERASE_TIMEOUT); + goto fail; + } + } + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +uint8_t PioSdioCard::errorCode() const { return m_errorCode; } +//------------------------------------------------------------------------------ +uint32_t PioSdioCard::errorData() const { return m_cardRsp; } +//------------------------------------------------------------------------------ +uint32_t PioSdioCard::errorLine() const { return m_errorLine; } +//------------------------------------------------------------------------------ +bool PioSdioCard::isBusy() { + return gpio_get(m_dat0Pin) ? false : !(status() & CARD_STATUS_READY_FOR_DATA); +} +//------------------------------------------------------------------------------ +void PioSdioCard::pioConfig(float clkDiv) { + m_cmdConfig = + pio_cmd_rsp_program_config(m_cmdRspOffset, m_cmdPin, m_clkPin, clkDiv); + m_rdClkConfig = + pio_rd_clk_program_config(m_rdClkOffset, m_dat0Pin, m_clkPin, clkDiv); + m_rdDataConfig = + pio_rd_data_program_config(m_rdDataOffset, m_dat0Pin, clkDiv); + m_wrDataConfig = + pio_wr_data_program_config(m_wrDataOffset, m_dat0Pin, m_clkPin, clkDiv); + m_wrRespConfig = + pio_wr_resp_program_config(m_wrRespOffset, m_dat0Pin, m_clkPin, clkDiv); +} +//------------------------------------------------------------------------------ +void PioSdioCard::pioEnd() { + if (!m_pio) { + return; + } + // CIRCUITPY-CHANGE: release only the two state machines we claimed (see + // pioInit) rather than every SM on the block, and clear their rp2pio + // never-reset flag so a later reuse of the same SM number by rp2pio is not + // wrongly protected across a soft reset. + if (m_sm0 >= 0) { + pio_sm_set_enabled(m_pio, m_sm0, false); + rp2pio_statemachine_reset_ok(m_pio, m_sm0); + pio_sm_unclaim(m_pio, m_sm0); + m_sm0 = -1; + } + if (m_sm1 >= 0) { + pio_sm_set_enabled(m_pio, m_sm1, false); + rp2pio_statemachine_reset_ok(m_pio, m_sm1); + pio_sm_unclaim(m_pio, m_sm1); + m_sm1 = -1; + } + if (m_cmdRspOffset >= 0) { + pio_remove_program(m_pio, &cmd_rsp_program, m_cmdRspOffset); + m_cmdRspOffset = -1; + } + if (m_rdClkOffset >= 0) { + pio_remove_program(m_pio, &rd_clk_program, m_rdClkOffset); + m_rdClkOffset = -1; + } + if (m_rdDataOffset >= 0) { + pio_remove_program(m_pio, &rd_data_program, m_rdDataOffset); + m_rdDataOffset = -1; + } + if (m_wrDataOffset >= 0) { + pio_remove_program(m_pio, &wr_data_program, m_wrDataOffset); + m_wrDataOffset = -1; + } + if (m_wrRespOffset >= 0) { + pio_remove_program(m_pio, &wr_resp_program, m_wrRespOffset); + m_wrRespOffset = -1; + } + m_pio = nullptr; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::pioInit() { + uint pin[] = {m_clkPin, m_cmdPin, m_dat0Pin, + m_dat0Pin + 1, m_dat0Pin + 2, m_dat0Pin + 3}; + // CIRCUITPY-CHANGE: the PIO's gpio_base (0 or 16). input_sync_bypass bits are + // relative to this base, so it must be subtracted from the raw GPIO numbers + // below (a raw `1 << pin` is UB for pins >= 32, e.g. Fruit Jam's GPIO34-39, + // and silently becomes a no-op on Cortex-M). Declared before the first goto so + // the error paths don't bypass its initialization. + uint gpio_base = 0; + // Declared before the first goto for the same reason as gpio_base. + uint pio_index = 0; + uint16_t pio_instructions[PIO_INSTRUCTION_COUNT]; + pio_program_t pio_program = {.instructions = nullptr, + .length = PIO_INSTRUCTION_COUNT, + .origin = -1, + .pio_version = 0, +#if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 +#endif + }; + // CIRCUITPY-CHANGE: pick a PIO through CircuitPython's rp2pio allocator and + // claim only the two state machines this driver uses, rather than seizing an + // entire PIO block via the raw SDK. This lets sdioio coexist with rp2pio and + // other PIO users. The five programs total total_pio_length (31) instructions, + // so this effectively requires an empty PIO; find_pio enforces that, which in + // turn guarantees the chosen PIO has no other user whose gpio_base the + // pio_set_gpio_base() call below could disturb. + pio_index = rp2pio_statemachine_find_pio(total_pio_length, 2); + if (pio_index >= NUM_PIOS) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_pio = pio_get_instance(pio_index); + m_sm0 = pio_claim_unused_sm(m_pio, false); + m_sm1 = pio_claim_unused_sm(m_pio, false); + if (m_sm0 < 0 || m_sm1 < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } +#if PICO_PIO_USE_GPIO_BASE + if (std::max({m_clkPin, m_cmdPin, m_dat0Pin + 3}) > 31) { + if (std::min({m_clkPin, m_cmdPin, m_dat0Pin}) < 16 || + pio_set_gpio_base(m_pio, 16) != PICO_OK) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + gpio_base = 16; + } else if (pio_set_gpio_base(m_pio, 0) != PICO_OK) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } +#endif // PICO_PIO_USE_GPIO_BASE + rd_data_patch_program(&pio_program, pio_instructions, m_clkPin); + m_rdDataOffset = pio_add_program(m_pio, &pio_program); + if (m_rdDataOffset < 0) { + DBG_MSG("m_rdDataOffset: ", m_rdDataOffset); + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_cmdRspOffset = pio_add_program(m_pio, &cmd_rsp_program); + if (m_cmdRspOffset < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_rdClkOffset = pio_add_program(m_pio, &rd_clk_program); + if (m_rdClkOffset < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_wrDataOffset = pio_add_program(m_pio, &wr_data_program); + if (m_wrDataOffset < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + m_wrRespOffset = pio_add_program(m_pio, &wr_resp_program); + if (m_wrRespOffset < 0) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + for (uint i = 0; i < 6U; i++) { + gpio_pull_up(pin[i]); + } + gpio_set_drive_strength(m_clkPin, GPIO_DRIVE_STRENGTH_8MA); + gpio_set_slew_rate(m_clkPin, GPIO_SLEW_RATE_FAST); + + for (uint i = 0; i < 6U; i++) { + pio_gpio_init(m_pio, pin[i]); + } + // input_sync_bypass bits are relative to the PIO's gpio_base (0 or 16), so + // subtract it. Using the raw pin numbers here is undefined for pins >= 32 + // (Fruit Jam's SD pins are GPIO34-39) and evaluates to 0 on Cortex-M, leaving + // the input synchronizers in place -- benign at the ~400 kHz init rate but a + // source of CMD/DAT mis-sampling at the 25 MHz run rate. + m_pio->input_sync_bypass |= (1u << (m_clkPin - gpio_base)) | + (1u << (m_cmdPin - gpio_base)) | (0xFu << (m_dat0Pin - gpio_base)); + if (pio_sm_set_consecutive_pindirs(m_pio, m_sm0, m_clkPin, 1, true) != + PICO_OK || + pio_sm_set_consecutive_pindirs(m_pio, m_sm0, m_cmdPin, 1, true) != + PICO_OK || + pio_sm_set_consecutive_pindirs(m_pio, m_sm0, m_dat0Pin, 4, false) != + PICO_OK) { + sdError(SD_CARD_ERROR_ADD_PIO_PROGRAM); + goto fail; + } + return true; + +fail: + pioEnd(); + return false; +} +//------------------------------------------------------------------------------ +// A few cards still need at least 74 clocks after power-up. from the spec: +// +// After 1 ms VDD stable time, host provides at least 74 clocks while keeping +// CMD high before issuing the first command. In the case of SPI mode, CS +// shall be held high during 74 clock cycles. +// +// The original April 15, 2001 spec explains the 74 clocks: +// +// The additional 10 clocks (over the 64 clocks after which the card should be +// ready for communication) is provided to eliminate power-up synchronization +// problems. +// +void PioSdioCard::powerUpClockCycles() { + // Two clk_sys per SD clock cycle. + uint32_t nWait = ceil(0.0005 * clock_get_hz(clk_sys) / SD_MAX_INIT_RATE_KHZ); + gpio_init(m_cmdPin); + gpio_set_drive_strength(m_cmdPin, GPIO_DRIVE_STRENGTH_8MA); + gpio_set_dir(m_cmdPin, true); + gpio_put(m_cmdPin, 1); + gpio_init(m_clkPin); + gpio_set_drive_strength(m_clkPin, GPIO_DRIVE_STRENGTH_8MA); + gpio_set_dir(m_clkPin, true); + + // Send 80 SD CLK cycles with CMD high. End with CLK low. + for (uint i = 0; i <= 160; i++) { + gpio_put(m_clkPin, 1 & i); + busy_wait_at_least_cycles(nWait); + } +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readCID(cid_t* cid) { + memcpy(cid, &m_cid, sizeof(cid_t)); + return true; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readCSD(csd_t* csd) { + memcpy(csd, &m_csd, sizeof(csd_t)); + return true; +} +//------------------------------------------------------------------------------ +bool __time_critical_func(PioSdioCard::readData)(void* dst, size_t count) { + uint32_t buf[128]; + uint n32 = count / 4; + uint nr = n32 + 2; + const uint mask = (1ul << m_sm0) | (1ul << m_sm1); + io_wo_8* txFifo = reinterpret_cast(&m_pio->txf[m_sm1]); + pio_sm_init(m_pio, m_sm0, m_rdDataOffset, &m_rdDataConfig); + pio_sm_init(m_pio, m_sm1, m_rdClkOffset, &m_rdClkConfig); + pio_set_sm_mask_enabled(m_pio, mask, true); + + uint nf = nr < DAT_FIFO_DEPTH ? nr : DAT_FIFO_DEPTH; + for (uint it = 0; it < nf; it++) { + *txFifo = 0XFF; + } + io_ro_32* rxFifo = reinterpret_cast(&m_pio->rxf[m_sm0]); + uint32_t* dst32 = (uint)dst & 3 ? buf : reinterpret_cast(dst); + uint64_t crc = 0; + uint64_t chk = 0; + Timeout timeout(SD_READ_TIMEOUT); + uint ir = 0; + if (nf < nr) { + uint nb = nr - nf; + while (true) { + while (pio_sm_get_rx_fifo_level(m_pio, m_sm0) < 4) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + uint32_t tmp = *rxFifo; + *txFifo = 0XFF; + dst32[ir++] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + tmp = *rxFifo; + *txFifo = 0XFF; + dst32[ir++] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + if (ir == nb) { + break; + } + tmp = *rxFifo; + *txFifo = 0XFF; + dst32[ir++] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + tmp = *rxFifo; + *txFifo = 0XFF; + dst32[ir++] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + } + } + for (; ir < nr; ir++) { + while (pio_sm_is_rx_fifo_empty(m_pio, m_sm0)) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_READ_TIMEOUT); + goto fail; + } + } + uint32_t tmp = *rxFifo; + if (ir < n32) { + dst32[ir] = __builtin_bswap32(tmp); + crc = crc16(crc, tmp); + } else { + chk <<= 32; + chk |= tmp; + } + } + if (crc != chk) { +#if USE_DEBUG_MODE + Serial.printf("crc: %llX\r\nchk: %llX\r\n", crc, chk); +#endif // USE_DEBUG_MODE + sdError(SD_CARD_ERROR_READ_CRC); + goto fail; + } + pio_set_sm_mask_enabled(m_pio, mask, false); + if (dst32 == buf) { + memcpy(dst, buf, count); + } + return true; + +fail: + pio_set_sm_mask_enabled(m_pio, mask, false); + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readData(uint8_t* dst) { return readData(dst, 512); } +//------------------------------------------------------------------------------ +bool PioSdioCard::readOCR(uint32_t* ocr) { + *ocr = m_ocr; + return true; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readSCR(scr_t* scr) { + memcpy(scr, &m_scr, sizeof(scr_t)); + return true; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readSDS(sds_t* sds) { + memcpy(sds, &m_sds, sizeof(sds_t)); + return true; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readSector(Sector_t sector, uint8_t* dst) { + if (m_curState != READ_STATE || sector != m_curSector) { + if (!syncDevice()) { + SDIO_FAIL(); + goto fail; + } + if (!readStart(sector)) { + sdError(SD_CARD_ERROR_READ_START); + goto fail; + } + m_curSector = sector; + m_curState = READ_STATE; + } + if (!readData(dst, 512)) { + SDIO_FAIL(); + goto fail; + } + m_curSector++; + return true; + +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readSectors(Sector_t sector, uint8_t* dst, size_t ns) { + for (size_t i = 0; i < ns; i++) { + if (!readSector(sector + i, dst + i * 512UL)) { + SDIO_FAIL(); + goto fail; + } + } + return true; + +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readStart(Sector_t sector) { + uint arg = m_highCapacity ? sector : 512 * sector; + if (!cardCommand(CMD18_R1, arg)) { + sdError(SD_CARD_ERROR_CMD18); + goto fail; + } + return true; + +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::readStop() { + if (!syncDevice()) { + SDIO_FAIL(); + return false; + } + return true; +} +//------------------------------------------------------------------------------ +uint32_t PioSdioCard::status() { + return cardCommand(CMD13_R1, m_rca) ? m_cardRsp : CARD_STATUS_ERROR; +} +//------------------------------------------------------------------------------ +Sector_t PioSdioCard::sectorCount() { return m_csd.capacity(); } +//------------------------------------------------------------------------------ +bool PioSdioCard::syncDevice() { + if (m_curState != IDLE_STATE) { + Timeout timeout(SD_INIT_TIMEOUT); + while (!gpio_get(m_dat0Pin)) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_CMD12); + goto fail; + } + } + if (!cardCommand(CMD12_R1, 0)) { + sdError(SD_CARD_ERROR_CMD12); + goto fail; + } + while (isBusy()) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_CMD12); + goto fail; + } + } + m_curState = IDLE_STATE; + } + return true; + +fail: + return false; +} +//------------------------------------------------------------------------------ +uint8_t PioSdioCard::type() const { + return !m_initDone ? 0 + : !m_version2 ? SD_CARD_TYPE_SD1 + : !m_highCapacity ? SD_CARD_TYPE_SD2 + : SD_CARD_TYPE_SDHC; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::writeSector(Sector_t sector, const uint8_t* src) { + return writeSectors(sector, src, 1); +} +//------------------------------------------------------------------------------ +bool PioSdioCard::writeSectors(Sector_t sector, const uint8_t* src, size_t ns) { + if (m_curState != WRITE_STATE || m_curSector != sector) { + if (!syncDevice()) { + SDIO_FAIL(); + goto fail; + } + if (!writeStart(sector)) { + sdError(SD_CARD_ERROR_WRITE_START); + goto fail; + } + m_curSector = sector; + m_curState = WRITE_STATE; + } + for (size_t i = 0; i < ns; i++, src += 512) { + if (!writeData(src)) { + sdError(SD_CARD_ERROR_WRITE_DATA); + goto fail; + } + } + m_curSector += ns; + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +bool __time_critical_func(PioSdioCard::writeData)(const uint8_t* src) { + const uint32_t* src32; + uint32_t buf[128]; + if ((uint)src & 3) { + memcpy(buf, src, 512); + src32 = (const uint32_t*)buf; + } else { + src32 = (const uint32_t*)src; + } + uint32_t tmp; + io_wo_32* txFifo = reinterpret_cast(&m_pio->txf[m_sm0]); + io_ro_32* rxFifo = reinterpret_cast(&m_pio->rxf[m_sm1]); + uint8_t rsp; + uint mask = (1ul << m_sm0) | (1ul << m_sm1); + uint64_t crc = 0; + + Timeout timeout(SD_WRITE_TIMEOUT); + while (!gpio_get(m_dat0Pin)) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_WRITE_TIMEOUT); + goto fail; + } + } + pio_sm_init(m_pio, m_sm0, m_wrDataOffset, &m_wrDataConfig); + pio_sm_init(m_pio, m_sm1, m_wrRespOffset, &m_wrRespConfig); + *txFifo = 1048; // 8 + 1024 + 16 + 1 - 1; + pio_sm_exec(m_pio, m_sm0, pio_encode_out(pio_x, 32)); + pio_sm_exec(m_pio, m_sm0, pio_encode_set(pio_pindirs, 0XF)); + *txFifo = 0xFFFFFFF0; + pio_set_sm_mask_enabled(m_pio, mask, true); + for (int i = 0; i < 128;) { + while (pio_sm_get_tx_fifo_level(m_pio, m_sm0) > 4) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_WRITE_FIFO); + goto fail; + } + } + tmp = __builtin_bswap32(src32[i++]); + crc = crc16(crc, tmp); + *txFifo = tmp; + tmp = __builtin_bswap32(src32[i++]); + crc = crc16(crc, tmp); + *txFifo = tmp; + tmp = __builtin_bswap32(src32[i++]); + crc = crc16(crc, tmp); + *txFifo = tmp; + tmp = __builtin_bswap32(src32[i++]); + crc = crc16(crc, tmp); + *txFifo = tmp; + } + while (pio_sm_get_tx_fifo_level(m_pio, m_sm0) > 5) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_WRITE_FIFO); + goto fail; + } + } + *txFifo = static_cast(crc >> 32); + *txFifo = static_cast(crc); + *txFifo = 0xFFFFFFFF; + + while (pio_sm_is_rx_fifo_empty(m_pio, m_sm1)) { + if (timeout.timedOut()) { + sdError(SD_CARD_ERROR_READ_FIFO); + goto fail; + } + } + rsp = *rxFifo; + if ((rsp & 0X1F) != 0b101) { +#if USE_DEBUG_MODE + Serial.printf("wr rsp: %02X\n", rsp); +#endif // USE_DEBUG_MODE + sdError(SD_CARD_ERROR_WRITE_DATA); + goto fail; + } + return true; +fail: + pio_set_sm_mask_enabled(m_pio, mask, false); + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::writeStart(Sector_t sector) { + uint arg = m_highCapacity ? sector : 512 * sector; + if (!cardCommand(CMD25_R1, arg)) { + sdError(SD_CARD_ERROR_CMD25); + goto fail; + } + return true; +fail: + return false; +} +//------------------------------------------------------------------------------ +bool PioSdioCard::writeStop() { + if (!syncDevice()) { + SDIO_FAIL(); + return false; + } + return true; +} +#endif // ARDUINO_ARCH_RP2040 diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h new file mode 100644 index 00000000000..ca3cb650a30 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h @@ -0,0 +1,350 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief Classes for PIO SDIO cards. + */ +#pragma once +// CIRCUITPY-CHANGE: Upstream relies on Arduino.h (pulled in via SdFatConfig.h) +// to declare the RP2 SDK PIO types (PIO, pio_sm_config), the `uint` alias used +// by this class's members, and the SDK functions the driver calls (gpio_*, +// clock_get_hz, the pico/time helpers) plus memcpy. This vendored build trims +// that Arduino path, so include those directly here. +#include +#include "hardware/clocks.h" +#include "hardware/gpio.h" +#include "hardware/pio.h" +#include "pico/time.h" +#include "../../common/SysCall.h" +#include "../SdCardInterface.h" +#if defined(ARDUINO_ARCH_RP2040) && defined(PIN_SD_CLK) && \ + defined(PIN_SD_CMD_MOSI) && defined(PIN_SD_DAT0_MISO) && \ + defined(PIN_SD_DAT1) && defined(PIN_SD_DAT2) && defined(PIN_SD_DAT3_CS) +#define HAS_BUILTIN_PIO_SDIO +#endif +class PioSdioConfig; +/** SdioConfig type for PIO SDIO */ +typedef PioSdioConfig SdioConfig; +class PioSdioCard; +/** Sdio type for PIO SDIO */ +typedef PioSdioCard SdioCard; +//------------------------------------------------------------------------------ +/** + * \class PioSdioConfig + * \brief SDIO card configuration. + */ +class PioSdioConfig { + public: + /** + * PioSdioConfig constructor. + * \param[in] clkPin gpio pin for SDIO CLK. + * \param[in] cmdPin gpio pin for SDIO CMD. + * \param[in] dat0Pin gpio start pin for SDIO DAT[4]. + * \param[in] clkDiv PIO clock divisor. + */ + PioSdioConfig(uint clkPin, uint cmdPin, uint dat0Pin, float clkDiv = 1.0) + : m_clkPin(clkPin), + m_cmdPin(cmdPin), + m_dat0Pin(dat0Pin), + m_clkDiv(clkDiv) {} + /** \return gpio for SDIO CLK */ + uint clkPin() { return m_clkPin; } + /** \return gpio for SDIO CMD */ + uint cmdPin() { return m_cmdPin; } + /** \return gpio for SDIO DAT0 */ + uint dat0Pin() { return m_dat0Pin; } + /** \return PIO clock divisor */ + float clkDiv() { return m_clkDiv; } + + private: + PioSdioConfig() : m_clkPin(63u), m_cmdPin(63u), m_dat0Pin(63u), m_clkDiv(0) {} + const uint8_t m_clkPin; + const uint8_t m_cmdPin; + const uint8_t m_dat0Pin; + const float m_clkDiv; +}; +//------------------------------------------------------------------------------ +/** + * \class CmdRsp_t + * \brief SD command/response type. + */ +class CmdRsp_t { + public: + /** + * \param[in] idx_ Command index. + * \param[in] rsp_ Response type. + */ + CmdRsp_t(uint8_t idx_, uint8_t rsp_) : idx(idx_), rsp(rsp_) {} + uint8_t idx; ///< Command index. + uint8_t rsp; ///< Response type. +}; +//------------------------------------------------------------------------------ +/** + * \class PioSdioCard + * \brief Raw SDIO access to SD and SDHC flash memory cards. + */ +class PioSdioCard : public SdCardInterface { + public: + PioSdioCard() = default; // cppcheck-suppress uninitMemberVar + /** Initialize the SD card. + * \param[in] config SDIO card configuration. + * \return true for success or false for failure. + */ + bool begin(PioSdioConfig config); + /** CMD6 Switch mode: Check Function Set Function. + * \param[in] arg CMD6 argument. + * \param[out] status return status data. + * + * \return true for success or false for failure. + */ + bool cardCMD6(uint32_t arg, uint8_t* status) final; + /** Disable an SDIO card. + * not implemented. + */ + void end() final; + /** CIRCUITPY-CHANGE: mark this card's PIO state machines as surviving a soft + * reset, keeping rp2pio's never-reset bookkeeping coherent with the SMs this + * driver claims directly. */ + void neverReset(); + +#ifndef DOXYGEN_SHOULD_SKIP_THIS + uint32_t __attribute__((error("use sectorCount()"))) cardSize(); +#endif // DOXYGEN_SHOULD_SKIP_THIS + /** Erase a range of sectors. + * + * \param[in] firstSector The address of the first sector in the range. + * \param[in] lastSector The address of the last sector in the range. + * + * \note This function requests the SD card to do a flash erase for a + * range of sectors. The data on the card after an erase operation is + * either 0 or 1, depends on the card vendor. The card must support + * single sector erase. + * + * \return true for success or false for failure. + */ + bool erase(Sector_t firstSector, Sector_t lastSector) final; + /** + * \return code for the last error. See SdCardInfo.h for a list of error + * codes. + */ + uint8_t errorCode() const final; + /** \return error data for last error. */ + uint32_t errorData() const final; + /** \return error line for last error. Tmp function for debug. */ + uint32_t errorLine() const; + /** + * Check for busy with CMD13. + * + * \return true if busy else false. + */ + bool isBusy() final; + /** \return the SD clock frequency in kHz. */ + uint32_t kHzSdClk(); + /** + * Read a 512 byte sector from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSector(Sector_t sector, uint8_t* dst) final; + /** + * Read multiple 512 byte sectors from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSectors(Sector_t sector, uint8_t* dst, size_t ns) final; + /** + * Read a card's CID register. The CID contains card identification + * information such as Manufacturer ID, Product name, Product serial + * number and Manufacturing date. + * + * \param[out] cid pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCID(cid_t* cid) final; + /** + * Read a card's CSD register. The CSD contains Card-Specific Data that + * provides information regarding access to the card's contents. + * + * \param[out] csd pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCSD(csd_t* csd) final; + /** Read one data sector in a multiple sector read sequence + * + * \param[out] dst Pointer to the location for the data to be read. + * + * \return true for success or false for failure. + */ + bool readData(uint8_t* dst); + /** Read OCR register. + * + * \param[out] ocr Value of OCR register. + * \return true for success or false for failure. + */ + bool readOCR(uint32_t* ocr) final; + /** Read SCR register. + * + * \param[out] scr Value of SCR register. + * \return true for success or false for failure. + */ + bool readSCR(scr_t* scr) final; + /** Return the 64 byte SD Status register. + * \param[out] sds location for 64 status bytes. + * \return true for success or false for failure. + */ + bool readSDS(sds_t* sds) final; + /** Start a read multiple sectors sequence. + * + * \param[in] sector Address of first sector in sequence. + * + * \note This function is used with readData() and readStop() for optimized + * multiple sector reads. + * + * \return true for success or false for failure. + */ + bool readStart(Sector_t sector); + /** End a read multiple sectors sequence. + * + * \return true for success or false for failure. + */ + bool readStop(); + /** \return SDIO card status. */ + uint32_t status() final; + /** + * Determine the size of an SD flash memory card. + * + * \return The number of 512 byte data sectors in the card + * or zero if an error occurs. + */ + Sector_t sectorCount() final; + /** + * Send CMD12 to stop read or write. + * + * \param[in] blocking If true, wait for command complete. + * + * \return true for success or false for failure. + */ + bool stopTransmission(bool blocking); + /** \return success if sync successful. Not for user apps. */ + bool syncDevice() final; + /** Return the card type: SD V1, SD V2 or SDHC + * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. + */ + uint8_t type() const final; + /** + * Writes a 512 byte sector to an SD card. + * + * \param[in] sector Logical sector to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeSector(Sector_t sector, const uint8_t* src) final; + /** + * Write multiple 512 byte sectors to an SD card. + * + * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeSectors(Sector_t sector, const uint8_t* src, size_t ns) final; + /** Write one data sector in a multiple sector write sequence. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeData(const uint8_t* src); + /** Start a write multiple sectors sequence. + * + * \param[in] sector Address of first sector in sequence. + * + * \note This function is used with writeData() and writeStop() + * for optimized multiple sector writes. + * + * \return true for success or false for failure. + */ + bool writeStart(Sector_t sector); + + /** End a write multiple sectors sequence. + * + * \return true for success or false for failure. + */ + bool writeStop(); + + private: + //---------------------------------------------------------------------------- + bool cardAcmd(uint32_t rca, CmdRsp_t cmdRsp, uint32_t arg); + bool cardCommand(CmdRsp_t cmd, uint32_t arg, void* rsp = nullptr); + void pioConfig(float clkDiv); + void pioEnd(); + bool pioInit(); + void powerUpClockCycles(); + bool readData(void* dst, size_t count); + void setSdErrorCode(uint8_t code, uint32_t line) { + m_errorCode = code; + m_errorLine = line; + } + static const uint8_t IDLE_STATE = 0; + static const uint8_t READ_STATE = 1; + static const uint8_t WRITE_STATE = 2; + Sector_t m_curSector = 0; + uint8_t m_curState = IDLE_STATE; + uint m_cardRsp; + uint m_errorCode; + uint m_errorLine; + bool m_highCapacity; + bool m_initDone = false; + uint m_ocr; + bool m_version2; + uint m_rca; + cid_t m_cid; + csd_t m_csd; + scr_t m_scr; + sds_t m_sds; + + float m_clkDiv = 0; + uint m_clkPin = 63u; // PIN_SDIO_UNDEFINED; + uint m_cmdPin = 63u; // PIN_SDIO_UNDEFINED; + uint m_dat0Pin = 63u; // PIN_SDIO_UNDEFINED; + PIO m_pio = nullptr; + int m_sm0 = -1; + int m_sm1 = -1; + int m_cmdRspOffset = -1; + pio_sm_config m_cmdConfig; + int m_rdDataOffset = -1; + pio_sm_config m_rdDataConfig; + int m_rdClkOffset = -1; + pio_sm_config m_rdClkConfig; + int m_wrDataOffset = -1; + pio_sm_config m_wrDataConfig; + int m_wrRespOffset = -1; + pio_sm_config m_wrRespConfig; +}; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.pio.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.pio.h new file mode 100644 index 00000000000..3130fd4edc0 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.pio.h @@ -0,0 +1,331 @@ +/** +* Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +// -------------------------------------------------- // +// This file is autogenerated by pioasm; do not edit! // +// -------------------------------------------------- // + +#pragma once + +#if !PICO_NO_HARDWARE +#include "hardware/pio.h" +#endif + +#define SDIO_IRQ 7 + +// ------- // +// cmd_rsp // +// ------- // + +#define cmd_rsp_wrap_target 0 +#define cmd_rsp_wrap 9 +#define cmd_rsp_pio_version 0 + +static const uint16_t cmd_rsp_program_instructions[] = { + // .wrap_target + 0x7101, // 0: out pins, 1 side 0 [1] + 0x1940, // 1: jmp x--, 0 side 1 [1] + 0x1160, // 2: jmp !y, 0 side 0 [1] + 0xfb80, // 3: set pindirs, 0 side 1 [3] + 0xb342, // 4: nop side 0 [3] + 0xba42, // 5: nop side 1 [2] + 0x00c4, // 6: jmp pin, 4 + 0x4001, // 7: in pins, 1 + 0x9260, // 8: push iffull block side 0 [2] + 0x1987, // 9: jmp y--, 7 side 1 [1] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program cmd_rsp_program = { + .instructions = cmd_rsp_program_instructions, + .length = 10, + .origin = -1, + .pio_version = cmd_rsp_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config cmd_rsp_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + cmd_rsp_wrap_target, offset + cmd_rsp_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +static inline pio_sm_config pio_cmd_rsp_program_config(uint offset, uint cmd_pin, uint clk_pin, float clk_div) { + pio_sm_config c = cmd_rsp_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_out_pins(&c, cmd_pin, 1); + sm_config_set_in_pins(&c, cmd_pin); + sm_config_set_set_pins(&c, cmd_pin, 1); + sm_config_set_jmp_pin(&c, cmd_pin); + sm_config_set_in_shift(&c, false, false, 8); + sm_config_set_out_shift(&c, false, true, 8); + sm_config_set_clkdiv(&c, clk_div); + return c; +} + +#endif + +// ------ // +// rd_clk // +// ------ // + +#define rd_clk_wrap_target 3 +#define rd_clk_wrap 4 +#define rd_clk_pio_version 0 + +static const uint16_t rd_clk_program_instructions[] = { + 0xb342, // 0: nop side 0 [3] + 0x1bc0, // 1: jmp pin, 0 side 1 [3] + 0xc007, // 2: irq nowait 7 + // .wrap_target + 0x7261, // 3: out null, 1 side 0 [2] + 0xb942, // 4: nop side 1 [1] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program rd_clk_program = { + .instructions = rd_clk_program_instructions, + .length = 5, + .origin = -1, + .pio_version = rd_clk_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config rd_clk_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + rd_clk_wrap_target, offset + rd_clk_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +static inline pio_sm_config pio_rd_clk_program_config(uint offset, uint d0_pin, uint clk_pin, float clk_div) { + pio_sm_config c = rd_clk_program_get_default_config(offset); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_in_pins(&c, d0_pin); + sm_config_set_jmp_pin(&c, d0_pin); + sm_config_set_out_shift(&c, false, true, 8); + sm_config_set_clkdiv(&c, clk_div); + return c; +} + +#endif + +// ------- // +// rd_data // +// ------- // + +#define rd_data_wrap_target 1 +#define rd_data_wrap 3 +#define rd_data_pio_version 0 + +#define rd_data_offset_wait0 1u +#define rd_data_offset_wait1 2u + +static const uint16_t rd_data_program_instructions[] = { + 0x20c7, // 0: wait 1 irq, 7 + // .wrap_target + 0x2000, // 1: wait 0 gpio, 0 + 0x2080, // 2: wait 1 gpio, 0 + 0x4004, // 3: in pins, 4 + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program rd_data_program = { + .instructions = rd_data_program_instructions, + .length = 4, + .origin = -1, + .pio_version = rd_data_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x1 + #endif +}; + +static inline pio_sm_config rd_data_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + rd_data_wrap_target, offset + rd_data_wrap); + return c; +} + +static inline void rd_data_patch_program(pio_program *prog, uint16_t *inst, uint clk_pin) { + *prog = rd_data_program; + prog->instructions = inst; + #if PICO_PIO_VERSION > 0 + prog->used_gpio_ranges = clk_pin < 16 ? 1 : clk_pin < 32 ? 2 : clk_pin < 48 ? 4 : 8; + #endif + memcpy(inst, rd_data_program_instructions, sizeof(rd_data_program_instructions)); + inst[rd_data_offset_wait0] = pio_encode_wait_gpio(0, clk_pin); + inst[rd_data_offset_wait1] = pio_encode_wait_gpio(1, clk_pin); +} +static inline pio_sm_config pio_rd_data_program_config(uint offset, uint data_pin, float clk_div) { + pio_sm_config c = rd_data_program_get_default_config(offset); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX); + sm_config_set_in_pins(&c, data_pin); + sm_config_set_in_shift(&c, false, true, 32); + sm_config_set_clkdiv(&c, clk_div); + return c; +} + +#endif + +// ------- // +// wr_data // +// ------- // + +#define wr_data_wrap_target 3 +#define wr_data_wrap 3 +#define wr_data_pio_version 0 + +static const uint16_t wr_data_program_instructions[] = { + 0x7104, // 0: out pins, 4 side 0 [1] + 0x1940, // 1: jmp x--, 0 side 1 [1] + 0xc007, // 2: irq nowait 7 + // .wrap_target + 0xa042, // 3: nop + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program wr_data_program = { + .instructions = wr_data_program_instructions, + .length = 4, + .origin = -1, + .pio_version = wr_data_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config wr_data_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + wr_data_wrap_target, offset + wr_data_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +static inline pio_sm_config pio_wr_data_program_config(uint offset, uint data_pin, uint clk_pin, float clk_div) { + pio_sm_config c = wr_data_program_get_default_config(offset); + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_out_pins(&c, data_pin, 4); + sm_config_set_set_pins(&c, data_pin, 4); + sm_config_set_out_shift(&c, false, true, 32); + sm_config_set_clkdiv(&c, clk_div); + return c; +} + +#endif + +// ------- // +// wr_resp // +// ------- // + +#define wr_resp_wrap_target 2 +#define wr_resp_wrap 3 +#define wr_resp_pio_version 0 + +static const uint16_t wr_resp_program_instructions[] = { + 0x20c7, // 0: wait 1 irq, 7 + 0xe180, // 1: set pindirs, 0 [1] + // .wrap_target + 0x5c01, // 2: in pins, 1 side 1 [4] + 0x9440, // 3: push iffull noblock side 0 [4] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program wr_resp_program = { + .instructions = wr_resp_program_instructions, + .length = 4, + .origin = -1, + .pio_version = wr_resp_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config wr_resp_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + wr_resp_wrap_target, offset + wr_resp_wrap); + sm_config_set_sideset(&c, 2, true, false); + return c; +} + +static inline pio_sm_config pio_wr_resp_program_config(uint offset, uint data_pin, uint clk_pin, float clk_div) { + pio_sm_config c = wr_resp_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, clk_pin); + sm_config_set_in_pins(&c, data_pin); + sm_config_set_set_pins(&c, data_pin, 4); + sm_config_set_in_shift(&c, false, false, 8); + sm_config_set_clkdiv(&c, clk_div); + return c; +} +static const size_t total_pio_length = + cmd_rsp_program.length + rd_data_program.length + rd_clk_program.length + + wr_data_program.length + wr_resp_program.length; + +#endif + +// -------- // +// fill_pio // +// -------- // + +#define fill_pio_wrap_target 0 +#define fill_pio_wrap 3 +#define fill_pio_pio_version 0 + +static const uint16_t fill_pio_program_instructions[] = { + // .wrap_target + 0x0000, // 0: jmp 0 + 0x0001, // 1: jmp 1 + 0x0002, // 2: jmp 2 + 0x0003, // 3: jmp 3 + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program fill_pio_program = { + .instructions = fill_pio_program_instructions, + .length = 4, + .origin = -1, + .pio_version = fill_pio_pio_version, + #if PICO_PIO_VERSION > 0 + .used_gpio_ranges = 0x0 + #endif +}; + +static inline pio_sm_config fill_pio_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + fill_pio_wrap_target, offset + fill_pio_wrap); + return c; +} +#endif diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInfo.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInfo.h new file mode 100644 index 00000000000..c84f9778725 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInfo.h @@ -0,0 +1,530 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief Definitions for SD cards. + */ +#pragma once +#include + +#include "../common/SysCall.h" +// Based on the document: +// +// SD Specifications +// Part 1 +// Physical Layer +// Simplified Specification +// Version 8.00 +// Sep 23, 2020 +// +// https://www.sdcard.org/downloads/pls/ +#if __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +// SD registers are big endian. +#error bit fields in structures assume little endian processor. +#endif // __BYTE_ORDER__ != __ORDER_LITTLE_ENDIAN__ +// ------------------------------------------------------------------------------ +// SD card errors +// See the SD Specification for command info. +/** Define error codes and brief description. */ +#define SD_ERROR_CODE_LIST \ + SD_CARD_ERROR(NONE, "No error") \ + SD_CARD_ERROR(CMD0, "Card reset failed") \ + SD_CARD_ERROR(CMD2, "SDIO read CID") \ + SD_CARD_ERROR(CMD3, "SDIO publish RCA") \ + SD_CARD_ERROR(CMD6, "Switch card function") \ + SD_CARD_ERROR(CMD7, "SDIO card select") \ + SD_CARD_ERROR(CMD8, "Send and check interface settings") \ + SD_CARD_ERROR(CMD9, "Read CSD data") \ + SD_CARD_ERROR(CMD10, "Read CID data") \ + SD_CARD_ERROR(CMD12, "Stop multiple block transmission") \ + SD_CARD_ERROR(CMD13, "Read card status") \ + SD_CARD_ERROR(CMD17, "Read single block") \ + SD_CARD_ERROR(CMD18, "Read multiple blocks") \ + SD_CARD_ERROR(CMD24, "Write single block") \ + SD_CARD_ERROR(CMD25, "Write multiple blocks") \ + SD_CARD_ERROR(CMD32, "Set first erase block") \ + SD_CARD_ERROR(CMD33, "Set last erase block") \ + SD_CARD_ERROR(CMD38, "Erase selected blocks") \ + SD_CARD_ERROR(CMD58, "Read OCR register") \ + SD_CARD_ERROR(CMD59, "Set CRC mode") \ + SD_CARD_ERROR(ACMD6, "Set SDIO bus width") \ + SD_CARD_ERROR(ACMD13, "Read extended status") \ + SD_CARD_ERROR(ACMD23, "Set pre-erased count") \ + SD_CARD_ERROR(ACMD41, "Activate card initialization") \ + SD_CARD_ERROR(ACMD51, "Read SCR data") \ + SD_CARD_ERROR(READ_TOKEN, "Bad read data token") \ + SD_CARD_ERROR(READ_CRC, "Read CRC error") \ + SD_CARD_ERROR(READ_FIFO, "SDIO fifo read timeout") \ + SD_CARD_ERROR(READ_REG, "Read CID or CSD failed.") \ + SD_CARD_ERROR(READ_START, "Bad readStart argument") \ + SD_CARD_ERROR(READ_TIMEOUT, "Read data timeout") \ + SD_CARD_ERROR(STOP_TRAN, "Multiple block stop failed") \ + SD_CARD_ERROR(TRANSFER_COMPLETE, "SDIO transfer complete") \ + SD_CARD_ERROR(WRITE_DATA, "Write data not accepted") \ + SD_CARD_ERROR(WRITE_FIFO, "SDIO fifo write timeout") \ + SD_CARD_ERROR(WRITE_START, "Bad writeStart argument") \ + SD_CARD_ERROR(WRITE_PROGRAMMING, "Flash programming") \ + SD_CARD_ERROR(WRITE_TIMEOUT, "Write timeout") \ + SD_CARD_ERROR(DMA, "DMA transfer failed") \ + SD_CARD_ERROR(ERASE, "Card did not accept erase commands") \ + SD_CARD_ERROR(ERASE_SINGLE_SECTOR, "Card does not support erase") \ + SD_CARD_ERROR(ERASE_TIMEOUT, "Erase command timeout") \ + SD_CARD_ERROR(INIT_NOT_CALLED, "Card has not been initialized") \ + SD_CARD_ERROR(ADD_PIO_PROGRAM, "Add PIO program") \ + SD_CARD_ERROR(INVALID_CARD_CONFIG, "Invalid card config") \ + SD_CARD_ERROR(FUNCTION_NOT_SUPPORTED, "Unsupported SDIO command") + +enum { +/** Macro for generation of error codes using an enum. */ +#define SD_CARD_ERROR(e, m) SD_CARD_ERROR_##e, + SD_ERROR_CODE_LIST +#undef SD_CARD_ERROR + SD_CARD_ERROR_UNKNOWN +}; +/** Print the enum symbol for an error code. + * \param[in] pr Print stream. + * \param[in] code enum value for error. + */ +void printSdErrorSymbol(print_t *pr, uint8_t code); +/** Print text for an error code. + * \param[in] pr Print stream. + * \param[in] code enum value for error. + */ +void printSdErrorText(print_t *pr, uint8_t code); +// ------------------------------------------------------------------------------ +// card types +/** Standard capacity V1 SD card */ +const uint8_t SD_CARD_TYPE_SD1 = 1; +/** Standard capacity V2 SD card */ +const uint8_t SD_CARD_TYPE_SD2 = 2; +/** High Capacity SD card */ +const uint8_t SD_CARD_TYPE_SDHC = 3; +// ------------------------------------------------------------------------------ +// SD operation timeouts +/** command timeout ms */ +const uint16_t SD_CMD_TIMEOUT = 300; +/** erase timeout ms */ +const uint16_t SD_ERASE_TIMEOUT = 10000; +/** init timeout ms */ +const uint16_t SD_INIT_TIMEOUT = 2000; +/** read timeout ms */ +const uint16_t SD_READ_TIMEOUT = 300; +/** write time out ms */ +const uint16_t SD_WRITE_TIMEOUT = 600; +// ------------------------------------------------------------------------------ +// SD card commands +/** GO_IDLE_STATE - init card in spi mode if CS low */ +const uint8_t CMD0 = 0X00; +/** ALL_SEND_CID - Asks any card to send the CID. */ +const uint8_t CMD2 = 0X02; +/** SEND_RELATIVE_ADDR - Ask the card to publish a new RCA. */ +const uint8_t CMD3 = 0X03; +/** SWITCH_FUNC - Switch Function Command */ +const uint8_t CMD6 = 0X06; +/** SELECT/DESELECT_CARD - toggles between the stand-by and transfer states. */ +const uint8_t CMD7 = 0X07; +/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/ +const uint8_t CMD8 = 0X08; +/** SEND_CSD - read the Card Specific Data (CSD register) */ +const uint8_t CMD9 = 0X09; +/** SEND_CID - read the card identification information (CID register) */ +const uint8_t CMD10 = 0X0A; +/** VOLTAGE_SWITCH -Switch to 1.8V bus signaling level. */ +const uint8_t CMD11 = 0X0B; +/** STOP_TRANSMISSION - end multiple sector read sequence */ +const uint8_t CMD12 = 0X0C; +/** SEND_STATUS - read the card status register */ +const uint8_t CMD13 = 0X0D; +/** READ_SINGLE_SECTOR - read a single data sector from the card */ +const uint8_t CMD17 = 0X11; +/** READ_MULTIPLE_SECTOR - read multiple data sectors from the card */ +const uint8_t CMD18 = 0X12; +/** WRITE_SECTOR - write a single data sector to the card */ +const uint8_t CMD24 = 0X18; +/** WRITE_MULTIPLE_SECTOR - write sectors of data until a STOP_TRANSMISSION */ +const uint8_t CMD25 = 0X19; +/** ERASE_WR_BLK_START - sets the address of the first sector to be erased */ +const uint8_t CMD32 = 0X20; +/** ERASE_WR_BLK_END - sets the address of the last sector of the continuous + range to be erased*/ +const uint8_t CMD33 = 0X21; +/** ERASE - erase all previously selected sectors */ +const uint8_t CMD38 = 0X26; +/** APP_CMD - escape for application specific command */ +const uint8_t CMD55 = 0X37; +/** READ_OCR - read the OCR register of a card */ +const uint8_t CMD58 = 0X3A; +/** CRC_ON_OFF - enable or disable CRC checking */ +const uint8_t CMD59 = 0X3B; +/** SET_BUS_WIDTH - Defines the data bus width for data transfer. */ +const uint8_t ACMD6 = 0X06; +/** SD_STATUS - Send the SD Status. */ +const uint8_t ACMD13 = 0X0D; +/** SET_WR_BLK_ERASE_COUNT - Set the number of write sectors to be + pre-erased before writing */ +const uint8_t ACMD23 = 0X17; +/** SD_SEND_OP_COMD - Sends host capacity support information and + activates the card's initialization process */ +const uint8_t ACMD41 = 0X29; +/** Reads the SD Configuration Register (SCR). */ +const uint8_t ACMD51 = 0X33; +// ============================================================================== +// CARD_STATUS +/** The command's argument was out of the allowed range for this card. */ +const uint32_t CARD_STATUS_OUT_OF_RANGE = 1UL << 31; +/** A misaligned address which did not match the sector length. */ +const uint32_t CARD_STATUS_ADDRESS_ERROR = 1UL << 30; +/** The transferred sector length is not allowed for this card. */ +const uint32_t CARD_STATUS_SECTOR_LEN_ERROR = 1UL << 29; +/** An error in the sequence of erase commands occurred. */ +const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL << 28; +/** An invalid selection of write-sectors for erase occurred. */ +const uint32_t CARD_STATUS_ERASE_PARAM = 1UL << 27; +/** Set when the host attempts to write to a protected sector. */ +const uint32_t CARD_STATUS_WP_VIOLATION = 1UL << 26; +/** When set, signals that the card is locked by the host. */ +const uint32_t CARD_STATUS_CARD_IS_LOCKED = 1UL << 25; +/** Set when a sequence or password error has been detected. */ +const uint32_t CARD_STATUS_LOCK_UNLOCK_FAILED = 1UL << 24; +/** The CRC check of the previous command failed. */ +const uint32_t CARD_STATUS_COM_CRC_ERROR = 1UL << 23; +/** Command not legal for the card state. */ +const uint32_t CARD_STATUS_ILLEGAL_COMMAND = 1UL << 22; +/** Card internal ECC was applied but failed to correct the data. */ +const uint32_t CARD_STATUS_CARD_ECC_FAILED = 1UL << 21; +/** Internal card controller error */ +const uint32_t CARD_STATUS_CC_ERROR = 1UL << 20; +/** A general or an unknown error occurred during the operation. */ +const uint32_t CARD_STATUS_ERROR = 1UL << 19; +// bits 19, 18, and 17 reserved. +/** Permanent WP set or attempt to change read only values of CSD. */ +const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL << 16; +/** partial address space was erased due to write protect. */ +const uint32_t CARD_STATUS_WP_ERASE_SKIP = 1UL << 15; +/** The command has been executed without using the internal ECC. */ +const uint32_t CARD_STATUS_CARD_ECC_DISABLED = 1UL << 14; +/** out of erase sequence command was received. */ +const uint32_t CARD_STATUS_ERASE_RESET = 1UL << 13; +/** The state of the card when receiving the command. + * 0 = idle + * 1 = ready + * 2 = ident + * 3 = stby + * 4 = tran + * 5 = data + * 6 = rcv + * 7 = prg + * 8 = dis + * 9-14 = reserved + * 15 = reserved for I/O mode + */ +const uint32_t CARD_STATUS_CURRENT_STATE = 0XF << 9; +/** Shift for current state. */ +const uint32_t CARD_STATUS_CURRENT_STATE_SHIFT = 9; +/** Corresponds to buffer empty signaling on the bus. */ +const uint32_t CARD_STATUS_READY_FOR_DATA = 1UL << 8; +// bit 7 reserved. +/** Extension Functions may set this bit to get host to deal with events. */ +const uint32_t CARD_STATUS_FX_EVENT = 1UL << 6; +/** The card will expect ACMD, or the command has been interpreted as ACMD */ +const uint32_t CARD_STATUS_APP_CMD = 1UL << 5; +// bit 4 reserved. +/** Error in the sequence of the authentication process. */ +const uint32_t CARD_STATUS_AKE_SEQ_ERROR = 1UL << 3; +// bits 2,1, and 0 reserved for manufacturer test mode. +// ============================================================================== +/** status for card in the ready state */ +const uint8_t R1_READY_STATE = 0X00; +/** status for card in the idle state */ +const uint8_t R1_IDLE_STATE = 0X01; +/** status bit for illegal command */ +const uint8_t R1_ILLEGAL_COMMAND = 0X04; +/** start data token for read or write single sector*/ +const uint8_t DATA_START_SECTOR = 0XFE; +/** stop token for write multiple sectors*/ +const uint8_t STOP_TRAN_TOKEN = 0XFD; +/** start data token for write multiple sectors*/ +const uint8_t WRITE_MULTIPLE_TOKEN = 0XFC; +/** mask for data response tokens after a write sector operation */ +const uint8_t DATA_RES_MASK = 0X1F; +/** write data accepted token */ +const uint8_t DATA_RES_ACCEPTED = 0X05; +// ============================================================================== +/** + * \class cid_t + * \brief Card Identification (CID) register. + */ +struct cid_t { + // byte 0 + /** Manufacturer ID */ + uint8_t mid; + // byte 1-2 + /** OEM/Application ID. */ + char oid[2]; + // byte 3-7 + /** Product name. */ + char pnm[5]; + // byte 8 + /** Product revision - n.m two 4-bit nibbles. */ + uint8_t prv; + // byte 9-12 + /** Product serial 32-bit number Big Endian format. */ + uint8_t psn8[4]; + // byte 13-14 + /** Manufacturing date big endian - four nibbles RYYM Reserved Year Month. */ + uint8_t mdt[2]; + // byte 15 + /** CRC7 bits 1-7 checksum, bit 0 always 1 */ + uint8_t crc; + // Extract big endian fields. + /** \return major revision number. */ + int prvN() const { + return prv >> 4; + } + /** \return minor revision number. */ + int prvM() const { + return prv & 0XF; + } + /** \return Manufacturing Year. */ + int mdtYear() const { + return 2000 + ((mdt[0] & 0XF) << 4) + (mdt[1] >> 4); + } + /** \return Manufacturing Month. */ + int mdtMonth() const { + return mdt[1] & 0XF; + } + /** \return Product Serial Number. */ + uint32_t psn() const { + return static_cast < uint32_t > (psn8[0]) << 24 | + static_cast < uint32_t > (psn8[1]) << 16 | + static_cast < uint32_t > (psn8[2]) << 8 | static_cast < uint32_t > (psn8[3]); + } +} __attribute__((packed)); +// ============================================================================== +/** + * \class csd_t + * \brief Union of old and new style CSD register. + */ +struct csd_t { + /** union of all CSD versions */ + uint8_t csd[16]; + // Extract big endian fields. + /** \return Capacity in sectors */ + uint32_t capacity() const { + uint32_t c_size; + uint8_t ver = csd[0] >> 6; + if (ver == 0) { + c_size = static_cast < uint32_t > (csd[6] & 3) << 10; + c_size |= static_cast < uint32_t > (csd[7]) << 2 | csd[8] >> 6; + uint8_t c_size_mult = (csd[9] & 3) << 1 | csd[10] >> 7; + uint8_t read_bl_len = csd[5] & 15; + return (c_size + 1) << (c_size_mult + read_bl_len + 2 - 9); + } else if (ver == 1) { + c_size = static_cast < uint32_t > (csd[7] & 63) << 16; + c_size |= static_cast < uint32_t > (csd[8]) << 8; + c_size |= csd[9]; + return (c_size + 1) << 10; + } else { + return 0; + } + } + /** \return true if erase granularity is single block. */ + bool eraseSingleBlock() const { + return csd[10] & 0X40; + } + /** \return erase size in 512 byte blocks if eraseSingleBlock is false. */ + int eraseSize() const { + return ((csd[10] & 0X3F) << 1 | csd[11] >> 7) + 1; + } + /** \return true if the contents is copied or true if original. */ + bool copy() const { + return csd[14] & 0X40; + } + /** \return true if the entire card is permanently write protected. */ + bool permWriteProtect() const { + return csd[14] & 0X20; + } + /** \return true if the entire card is temporarily write protected. */ + bool tempWriteProtect() const { + return csd[14] & 0X10; + } +}; +// ============================================================================== +/** + * \class scr_t + * \brief SCR register. + */ +struct scr_t { + /** Bytes 0-3 SD Association, bytes 4-7 reserved for manufacturer. */ + uint8_t scr[8]; + /** \return SCR_STRUCTURE field - must be zero.*/ + uint8_t srcStructure() const { + return scr[0] >> 4; + } + /** \return SD_SPEC field 0 - v1.0 or V1.01, 1 - 1.10, 2 - V2.00 or greater */ + uint8_t sdSpec() const { + return scr[0] & 0XF; + } + /** \return false if all zero, true if all one. */ + bool dataAfterErase() const { + return scr[1] & 0X80; + } + /** \return CPRM Security Version. */ + uint8_t sdSecurity() const { + return (scr[1] >> 4) & 0X7; + } + /** \return 0101b. */ + uint8_t sdBusWidths() const { + return scr[1] & 0XF; + } + /** \return true if V3.0 or greater. */ + bool sdSpec3() const { + return scr[2] & 0X80; + } + /** \return if true and sdSpecX is zero V4.xx. */ + bool sdSpec4() const { + return scr[2] & 0X4; + } + /** \return nonzero for version 5 or greater if sdSpec == 2, + sdSpec3 == true. Version is return plus four.*/ + uint8_t sdSpecX() const { + return (scr[2] & 0X3) << 2 | scr[3] >> 6; + } + /** \return bit map for support CMD58/59, CMD48/49, CMD23, and CMD20 */ + uint8_t cmdSupport() const { + return scr[3] & 0XF; + } + /** \return SD spec version */ + int16_t sdSpecVer() const { + if (sdSpec() > 2) { + return -1; + } else if (sdSpec() < 2) { + return sdSpec() ? 110 : 101; + } else if (!sdSpec3()) { + return 200; + } else if (!sdSpec4() && !sdSpecX()) { + return 300; + } + return 400 + 100 * sdSpecX(); + } +}; +// ============================================================================== +/** + * \class sds_t + * \brief SD Status. + */ +// fields are big endian +struct sds_t { + /** byte 0, bit 7-6 width, bit 5 secured mode, bits 4-0 reserved. */ + uint8_t busWidthSecureMode; + /** byte 1 reserved */ + uint8_t reserved1; + /** byte 2-3 zero for SD rd/wr memory card. */ + uint8_t sdCardType[2]; + /** byte 4-7 size of protected area big endian */ + uint8_t sizeOfProtectedArea[4]; + /** byte 8 speed class. */ + uint8_t speed; + /** byte 9 performance move */ + uint8_t performanceMove; + /** byte 10 AU size code. */ + uint8_t auSize; + /** byte 11-12 erase size big endian */ + uint8_t eraseSize[2]; + /** byte 13 erase timeout and erase offset */ + uint8_t eraseTimeoutOffset; + /** byte 14 */ + uint8_t uhsClassAuSize; + /** byte 15 */ + uint8_t videoSpeedClass; + /** byte 16-17 */ + uint8_t vscAuSize[2]; + /** byte 18-21 */ + uint8_t susAddr[3]; + /** byte 21 */ + uint8_t appPerfClass; + /** byte 22 */ + uint8_t perfEnhance; + /** byte 23 */ + uint8_t discardFule; + /** byte 24 */ + uint8_t reservedManufacturer[40]; + + /** \return appClass. */ + int appClass() { + return appPerfClass; + } + /** \return AU size in KB. or zero for error. */ + uint32_t auSizeKB() { + // 0XF mask and uint16_t array helps compiler optimize size on Uno. + uint8_t val = (auSize >> 4) & 0XF; + static const uint16_t au[] = {0, 16, 32, 64, 128, + 256, 512, 1024, 2048, 4096, + 8192, 12288, 16384, 24576, 32768}; + return val < 0XF ? au[val] : 65536UL; + } + /** \return current bus width or -1 for error. */ + uint8_t busWidth() const { + uint8_t w = busWidthSecureMode >> 6; + return w == 2 ? 4 : w == 0 ? 1 : -1; + } + /** \return true is discard operation is supported else true. */ + bool discard() const { + return discardFule & 2; + } + /** \return eraseSize in AUs. */ + uint16_t eraseSizeAU() const { + return static_cast < uint16_t > (eraseSize[0]) << 8 | + static_cast < uint16_t > (eraseSize[1]); + } + /** \return eraseTimeout seconds. */ + uint8_t eraseTimeout() const { + return eraseTimeoutOffset >> 2; + } + /** \return eraseOffset seconds. */ + uint8_t eraseOffset() const { + return eraseTimeoutOffset & 3; + } + /** \return true if full user logical erase is supported else false. */ + bool file() const { + return discardFule & 1; + } + /** \return true for secure mode else false. */ + bool secureMode() const { + return busWidthSecureMode & 0X20; + } + /** \return speed class or -1 for error. */ + int speedClass() const { + return speed < 4 ? 2 * speed : speed == 4 ? 10 : -1; + } + /** \return UHS Speed Grade. */ + int uhsClass() const { + return uhsClassAuSize >> 4; + } + /** \return Video Speed */ + int videoClass() { + return videoSpeedClass; + } +}; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h new file mode 100644 index 00000000000..a4378ea67e4 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h @@ -0,0 +1,110 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman, 2026 Tim Cocks for Adafruit Industries + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief Abstract interface for an SD card. + */ +#pragma once +#include "../common/FsBlockDeviceInterface.h" +#include "SdCardInfo.h" +/** + * \class SdCardInterface + * \brief Abstract interface for an SD card. + */ +class SdCardInterface : public FsBlockDeviceInterface { + public: + /** CMD6 Switch mode: Check Function Set Function. + * \param[in] arg CMD6 argument. + * \param[out] status return status data. + * + * \return true for success or false for failure. + */ + virtual bool cardCMD6(uint32_t arg, uint8_t* status) = 0; + /** Erase a range of sectors. + * + * \param[in] firstSector The address of the first sector in the range. + * \param[in] lastSector The address of the last sector in the range. + * + * \return true for success or false for failure. + */ + virtual bool erase(Sector_t firstSector, Sector_t lastSector) = 0; + /** \return error code. */ + virtual uint8_t errorCode() const = 0; + /** \return error data. */ + virtual uint32_t errorData() const = 0; + /** \return false by default */ + virtual bool hasDedicatedSpi() { return false; } + /** \return false by default */ + virtual bool isDedicatedSpi() { return false; } + /** \return false by default */ + virtual bool isSpi() { return false; } + /** Set SPI sharing state + * \param[in] value desired state. + * \return false by default. + */ + virtual bool setDedicatedSpi(bool value) { + (void)value; + return false; + } + /** + * Read a card's CID register. + * + * \param[out] cid pointer to area for returned data. + * + * \return true for success or false for failure. + */ + virtual bool readCID(cid_t* cid) = 0; + /** + * Read a card's CSD register. + * + * \param[out] csd pointer to area for returned data. + * + * \return true for success or false for failure. + */ + virtual bool readCSD(csd_t* csd) = 0; + /** Read OCR register. + * + * \param[out] ocr Value of OCR register. + * \return true for success or false for failure. + */ + virtual bool readOCR(uint32_t* ocr) = 0; + /** Read SCR register. + * + * \param[out] scr Value of SCR register. + * \return true for success or false for failure. + */ + virtual bool readSCR(scr_t* scr) = 0; + /** Return the 64 byte SD Status register. + * \param[out] sds location for 64 status bytes. + * \return true for success or false for failure. + */ + virtual bool readSDS(sds_t* sds) = 0; + /** \return card status. */ + virtual uint32_t status() { return 0XFFFFFFFF; } + /** Return the card type: SD V1, SD V2 or SDHC/SDXC + * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC/SDXC. + */ + virtual uint8_t type() const = 0; +}; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/FsBlockDeviceInterface.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/FsBlockDeviceInterface.h new file mode 100644 index 00000000000..f5f5b0a8b0c --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/FsBlockDeviceInterface.h @@ -0,0 +1,117 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief FsBlockDeviceInterface include file. + */ +#pragma once +#include +#include +/** + * \class FsBlockDeviceInterface + * \brief FsBlockDeviceInterface class. + */ +class FsBlockDeviceInterface { +public: + virtual ~FsBlockDeviceInterface() { + } + + /** end use of device */ + virtual void end() { + } + /** + * Check for FsBlockDevice busy. + * + * \return true if busy else false. + */ + virtual bool isBusy() = 0; + /** + * Read a sector. + * + * \param[in] sector Logical sector to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + virtual bool readSector(Sector_t sector, uint8_t *dst) = 0; + + /** + * Read multiple sectors. + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + virtual bool readSectors(Sector_t sector, uint8_t *dst, size_t ns) = 0; + + /** \return device size in sectors. */ + virtual Sector_t sectorCount() = 0; + + /** End multi-sector transfer and go to idle state. + * \return true for success or false for failure. + */ + virtual bool syncDevice() = 0; + + /** + * Writes a sector. + * + * \param[in] sector Logical sector to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + virtual bool writeSector(Sector_t sector, const uint8_t *src) = 0; + + /** + * Write multiple sectors. + * + * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + virtual bool writeSectors(Sector_t sector, const uint8_t *src, size_t ns) = 0; + + // Adafruit SdFat v1 BaseBlockDRiver API for backward-compatible + // maybe removal since v1 is deprecated now + virtual bool syncBlocks() { + return syncDevice(); + } + + virtual bool readBlock(uint32_t block, uint8_t *dst) { + return readSector(block, dst); + } + + virtual bool readBlocks(uint32_t block, uint8_t *dst, size_t nb) { + return readSectors(block, dst, nb); + } + + virtual bool writeBlock(uint32_t block, const uint8_t *src) { + return writeSector(block, src); + } + + virtual bool writeBlocks(uint32_t block, const uint8_t *src, size_t nb) { + return writeSectors(block, src, nb); + } +}; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/SysCall.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/SysCall.h new file mode 100644 index 00000000000..e8735ff2fd6 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/common/SysCall.h @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2011-2025 Bill Greiman + * This file is part of the SdFat library for SD memory cards. + * + * MIT License + * + * 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. + */ +/** + * \file + * \brief SysCall class + * + * CircuitPython vendored, trimmed copy. The upstream SysCall.h pulls in + * SdFatConfig.h (and through it Arduino.h / avr/io.h) plus PrintBasic.h. The + * PIO SDIO card driver only needs the Sector_t typedef, nullptr handling, and + * the SD_MAX_INIT_RATE_KHZ tuning constant, so we provide just those here and + * leave the Arduino/Print machinery out of the build. + */ +#pragma once +#include +#include + +#if __cplusplus < 201103 +#warning nullptr defined +/** Define nullptr if not C++11 */ +#define nullptr NULL +#endif // __cplusplus < 201103 +// ------------------------------------------------------------------------------ +/** Type for FsBlockDevice sector */ +typedef uint32_t Sector_t; +// ------------------------------------------------------------------------------ +// SdCardInfo.h declares (but, in this vendored build, never defines) two error +// printing helpers that take a print_t*. Forward declare the type so those +// pointer-only declarations parse without dragging in PrintBasic / Arduino. +class print_t; +// ------------------------------------------------------------------------------ +// Normally supplied by SdFatConfig.h. +#ifndef SD_MAX_INIT_RATE_KHZ +#define SD_MAX_INIT_RATE_KHZ 400 +#endif // SD_MAX_INIT_RATE_KHZ diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/cxx_runtime.cpp b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/cxx_runtime.cpp new file mode 100644 index 00000000000..85a28ed8d95 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/cxx_runtime.cpp @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Minimal freestanding C++ ABI support for the vendored SdFat PIO driver. +// +// CircuitPython links the firmware with gcc and without libstdc++/libsupc++, so +// a few C++ ABI symbols that the driver's class hierarchy makes the compiler +// reference must be provided here: +// * PioSdioCard's vtable contains a deleting destructor slot that names +// `operator delete`, even though we only ever placement-new the object and +// call its destructor explicitly (so it is never actually invoked). +// * The abstract base classes (SdCardInterface / FsBlockDeviceInterface) have +// pure virtuals, so their transient vtables reference `__cxa_pure_virtual`. +// Both are effectively unreachable at run time; they exist only to satisfy the +// linker. + +#include +#include + +extern "C" void __cxa_pure_virtual(void) { + abort(); +} + +void operator delete(void *ptr) noexcept { + free(ptr); +} + +void operator delete(void *ptr, size_t) noexcept { + free(ptr); +} diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h new file mode 100644 index 00000000000..9bf858ec539 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h @@ -0,0 +1,36 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +// Bridge declarations that let the vendored (C++) PioSdioCard driver cooperate +// with CircuitPython's rp2pio PIO allocator instead of seizing whole PIO blocks +// through the raw SDK. The definitions live in +// common-hal/rp2pio/StateMachine.c (compiled as C), so they are declared with C +// linkage here. This header deliberately does NOT include the full rp2pio +// StateMachine.h, which pulls in MicroPython object headers that are awkward in +// this C++ translation unit. + +#pragma once + +#include "hardware/pio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// See common-hal/rp2pio/StateMachine.c. Returns a PIO index (0..NUM_PIOS-1) with +// room for program_size instructions and sm_count free state machines, or +// NUM_PIOS if none qualifies. +uint8_t rp2pio_statemachine_find_pio(int program_size, int sm_count); + +// Mark / unmark a state machine as surviving (or not) a soft reset, so +// rp2pio's reset path keeps its bookkeeping coherent with the SMs this driver +// claims directly. +void rp2pio_statemachine_never_reset(PIO pio, int sm); +void rp2pio_statemachine_reset_ok(PIO pio, int sm); + +#ifdef __cplusplus +} +#endif diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp new file mode 100644 index 00000000000..6338229cc87 --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp @@ -0,0 +1,80 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +// C-callable shim around the vendored C++ PioSdioCard driver. This is the only +// translation unit that includes the C++ class; everything the common-hal C +// code needs is exposed through the extern "C" entry points in shim.h. + +#include + +#include "hardware/clocks.h" + +#include "SdCard/PioSdio/PioSdioCard.h" +#include "shim.h" + +static_assert(sizeof(PioSdioCard) <= SDIOIO_PIO_CARD_STORAGE_SIZE, + "SDIOIO_PIO_CARD_STORAGE_SIZE is too small for PioSdioCard"); +static_assert(alignof(PioSdioCard) <= alignof(sdioio_pio_card_storage_t), + "sdioio_pio_card_storage_t is not aligned enough for PioSdioCard"); + +extern "C" { + +void sdfat_pio_card_new(void *storage) { + new (storage) PioSdioCard(); +} + +void sdfat_pio_card_free(void *storage) { + reinterpret_cast(storage)->~PioSdioCard(); +} + +bool sdfat_pio_card_begin(void *storage, uint32_t clk_pin, uint32_t cmd_pin, + uint32_t dat0_pin, uint32_t frequency, uint32_t *actual_frequency_out) { + PioSdioCard *card = reinterpret_cast(storage); + + // The PIO driver clocks four PIO cycles per SD clock, so the resulting SD + // clock is clk_sys / (4 * clkDiv). Invert that to turn the requested rate + // into a divisor, clamped to the fastest the divisor allows (clkDiv >= 1). + float sys_hz = (float)clock_get_hz(clk_sys); + float clk_div = sys_hz / (4.0f * (float)frequency); + if (clk_div < 1.0f) { + clk_div = 1.0f; + } + + bool ok = card->begin(PioSdioConfig(clk_pin, cmd_pin, dat0_pin, clk_div)); + + if (actual_frequency_out != nullptr) { + *actual_frequency_out = (uint32_t)(sys_hz / (4.0f * clk_div)); + } + return ok; +} + +uint32_t sdfat_pio_card_sector_count(void *storage) { + return reinterpret_cast(storage)->sectorCount(); +} + +bool sdfat_pio_card_read_sectors(void *storage, uint32_t start_sector, + uint8_t *dst, size_t num_sectors) { + return reinterpret_cast(storage)->readSectors(start_sector, dst, num_sectors); +} + +bool sdfat_pio_card_write_sectors(void *storage, uint32_t start_sector, + const uint8_t *src, size_t num_sectors) { + return reinterpret_cast(storage)->writeSectors(start_sector, src, num_sectors); +} + +uint8_t sdfat_pio_card_error_code(void *storage) { + return reinterpret_cast(storage)->errorCode(); +} + +void sdfat_pio_card_end(void *storage) { + reinterpret_cast(storage)->end(); +} + +void sdfat_pio_card_never_reset(void *storage) { + reinterpret_cast(storage)->neverReset(); +} + +} // extern "C" diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h new file mode 100644 index 00000000000..c279fe0ca0d --- /dev/null +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h @@ -0,0 +1,74 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +// C-callable shim around the vendored C++ PioSdioCard driver. All use of the +// C++ class is confined to shim.cpp so the common-hal C sources never include +// any C++ headers. + +#pragma once + +#include +#include +#include + +// Size of the opaque storage the C object struct reserves for an in-place +// PioSdioCard instance. shim.cpp static_asserts that the real class fits. The +// real object is well under this (~320 bytes); the slack is intentional so the +// build does not break if the upstream class grows slightly. +#define SDIOIO_PIO_CARD_STORAGE_SIZE 512 + +// Opaque storage for one PioSdioCard, constructed in place by +// sdfat_pio_card_new(). The class's members are at most pointer/word aligned, so +// a pointer member is enough to align the buffer (and matches what the GC heap +// guarantees); shim.cpp static_asserts that this is sufficient. Kept as a plain +// union so the C struct needs no knowledge of the C++ type. +typedef union { + void *for_alignment; + uint8_t bytes[SDIOIO_PIO_CARD_STORAGE_SIZE]; +} sdioio_pio_card_storage_t; + +#ifdef __cplusplus +extern "C" { +#endif + +// Construct a PioSdioCard in place in the given storage buffer. +void sdfat_pio_card_new(void *storage); + +// Run the destructor for the in-place PioSdioCard. +void sdfat_pio_card_free(void *storage); + +// Initialize the card. dat0_pin is the base of four consecutive data GPIOs. +// frequency is the requested SD clock in Hz; the achieved rate is written to +// actual_frequency_out (in Hz) when it is non-NULL. Returns true on success. +bool sdfat_pio_card_begin(void *storage, uint32_t clk_pin, uint32_t cmd_pin, + uint32_t dat0_pin, uint32_t frequency, uint32_t *actual_frequency_out); + +// Number of 512-byte sectors on the card (0 if unknown). +uint32_t sdfat_pio_card_sector_count(void *storage); + +// Read `num_sectors` 512-byte sectors starting at `start_sector` into `dst`. +// Returns true on success. The driver is synchronous/polling, so this blocks. +bool sdfat_pio_card_read_sectors(void *storage, uint32_t start_sector, + uint8_t *dst, size_t num_sectors); + +// Write `num_sectors` 512-byte sectors from `src` starting at `start_sector`. +// Returns true on success. Blocks like the read path. +bool sdfat_pio_card_write_sectors(void *storage, uint32_t start_sector, + const uint8_t *src, size_t num_sectors); + +// Last error code from the driver (see SdCardInfo.h). +uint8_t sdfat_pio_card_error_code(void *storage); + +// Release the card's PIO/state-machine resources. +void sdfat_pio_card_end(void *storage); + +// Mark the card's PIO state machines as surviving a soft reset, so rp2pio's +// reset path leaves them (and their loaded programs) in place. +void sdfat_pio_card_never_reset(void *storage); + +#ifdef __cplusplus +} +#endif diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 01940acc079..6ffd48547d7 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -34,6 +34,10 @@ #include "common-hal/rtc/RTC.h" #include "common-hal/busio/UART.h" +#if CIRCUITPY_SDIOIO +#include "common-hal/sdioio/SDCard.h" +#endif + #include "supervisor/shared/safe_mode.h" #include "supervisor/shared/stack.h" #include "supervisor/shared/tick.h" @@ -433,6 +437,10 @@ void reset_port(void) { reset_rp2pio_statemachine(); #endif + #if CIRCUITPY_SDIOIO + sdioio_reset(); + #endif + #if CIRCUITPY_RTC rtc_reset(); #endif diff --git a/shared-module/sdcardio/__init__.c b/shared-module/sdcardio/__init__.c index 751e6f58127..d53f7a3fabd 100644 --- a/shared-module/sdcardio/__init__.c +++ b/shared-module/sdcardio/__init__.c @@ -16,6 +16,7 @@ #include "shared-bindings/sdcardio/SDCard.h" #include "supervisor/filesystem.h" +#include "supervisor/shared/settings.h" #ifdef DEFAULT_SD_CARD_DETECT static digitalio_digitalinout_obj_t sd_card_detect_pin; @@ -45,6 +46,21 @@ void sdcardio_init(void) { void automount_sd_card(void) { #ifdef DEFAULT_SD_CARD_DETECT + #if CIRCUITPY_SETTINGS_TOML + // Honor the runtime CIRCUITPY_SDCARD_USB setting. When disabled, never + // claim the shared SD pins (SCK/MOSI/MISO/CS) via SPI, so they remain free + // for other uses such as sdioio, which drives the same physical pins. + // Read once and cache, matching usb_msc_flash.c's handling. + static int8_t _sdcard_usb_enabled = -1; // -1 unknown, 0 false, 1 true + if (_sdcard_usb_enabled < 0) { + bool setting = true; + (void)settings_get_bool("CIRCUITPY_SDCARD_USB", &setting); + _sdcard_usb_enabled = setting ? 1 : 0; + } + if (!_sdcard_usb_enabled) { + return; + } + #endif if (common_hal_digitalio_digitalinout_get_value(&sd_card_detect_pin) != DEFAULT_SD_CARD_INSERTED) { // No card. _init_error = false; diff --git a/supervisor/shared/filesystem.c b/supervisor/shared/filesystem.c index 1d2a6180a94..3998c304b7f 100644 --- a/supervisor/shared/filesystem.c +++ b/supervisor/shared/filesystem.c @@ -224,6 +224,8 @@ bool filesystem_init(bool create_allowed, bool force_create) { // Lazy mount from tud_msc_test_unit_ready_cb can lose races with // macOS's probe timing. Gated on CIRCUITPY_SDCARD_USB to match the // existing call site in usb_msc_flash.c (guarded by SDCARD_LUN). + // automount_sd_card() itself honors the runtime CIRCUITPY_SDCARD_USB + // setting and is a no-op when it is disabled. automount_sd_card(); #endif #endif From 911b1ff9fd6dc84b29781367f780d32aa6ae3617 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 3 Jul 2026 13:16:03 -0500 Subject: [PATCH 604/876] cleanup comments --- .../boards/adafruit_metro_rp2350/mpconfigboard.h | 5 ----- ports/raspberrypi/common-hal/sdioio/SDCard.c | 9 +++------ ports/raspberrypi/common-hal/sdioio/SDCard.h | 2 +- ports/raspberrypi/common-hal/sdioio/__init__.c | 2 +- .../common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h | 2 +- ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp | 2 +- ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h | 2 +- 7 files changed, 8 insertions(+), 16 deletions(-) diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h index c8f4d7975dd..1a583046416 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h +++ b/ports/raspberrypi/boards/adafruit_metro_rp2350/mpconfigboard.h @@ -36,11 +36,6 @@ #define DEFAULT_DVI_BUS_BLUE_DN (&pin_GPIO13) #define DEFAULT_DVI_BUS_BLUE_DP (&pin_GPIO12) -// These SD pins double as the 4-bit SDIO interface (board.SDIO_*): SCK=CLOCK, -// MOSI=COMMAND, MISO=DATA0, CS=DATA3. By default the SPI automount claims them -// and mounts the card over SPI, so sdioio.SDCard() would fail with " in -// use". Set CIRCUITPY_SDCARD_USB = false in settings.toml to free the pins for -// sdioio (this also disables the automatic /sd mount on this board). #define DEFAULT_SD_SCK (&pin_GPIO34) #define DEFAULT_SD_MOSI (&pin_GPIO35) #define DEFAULT_SD_MISO (&pin_GPIO36) diff --git a/ports/raspberrypi/common-hal/sdioio/SDCard.c b/ports/raspberrypi/common-hal/sdioio/SDCard.c index 46510ae8576..04b78dbc4d2 100644 --- a/ports/raspberrypi/common-hal/sdioio/SDCard.c +++ b/ports/raspberrypi/common-hal/sdioio/SDCard.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -56,8 +56,7 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, const mcu_pin_obj_t *clock, const mcu_pin_obj_t *command, uint8_t num_data, const mcu_pin_obj_t **data, uint32_t frequency) { // The vendored PIO driver only supports 4-bit mode and requires the four - // data lines to be on consecutive GPIOs (DAT0..DAT3). 1-bit mode is a - // documented follow-up. + // data lines to be on consecutive GPIOs (DAT0..DAT3). if (num_data != 4) { mp_raise_ValueError_varg(MP_ERROR_TEXT("Number of data_pins must be %d, not %d"), 4, num_data); } @@ -249,9 +248,7 @@ void common_hal_sdioio_sdcard_never_reset(sdioio_sdcard_obj_t *self) { void sdioio_reset(void) { // Release every live card that isn't protected by never_reset. deinit() - // runs pioEnd(), which unclaims the PIO at the SDK level — without this the - // claim (static RAM) survives the soft reboot even though the object heap is - // wiped, permanently burning a PIO block per successful construct. + // runs pioEnd(), which unclaims the PIO at the SDK level. for (size_t i = 0; i < MP_ARRAY_SIZE(_active_cards); i++) { sdioio_sdcard_obj_t *self = _active_cards[i]; if (self == NULL || self->never_reset) { diff --git a/ports/raspberrypi/common-hal/sdioio/SDCard.h b/ports/raspberrypi/common-hal/sdioio/SDCard.h index e25331fd51d..a4dca731f73 100644 --- a/ports/raspberrypi/common-hal/sdioio/SDCard.h +++ b/ports/raspberrypi/common-hal/sdioio/SDCard.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/raspberrypi/common-hal/sdioio/__init__.c b/ports/raspberrypi/common-hal/sdioio/__init__.c index 16ed83d3e9b..4a92fca8794 100644 --- a/ports/raspberrypi/common-hal/sdioio/__init__.c +++ b/ports/raspberrypi/common-hal/sdioio/__init__.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h index 9bf858ec539..5782aef96f0 100644 --- a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp index 6338229cc87..5aeea4c8e94 100644 --- a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.cpp @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h index c279fe0ca0d..c968ea0f734 100644 --- a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/shim.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT From 292758acc800988f693fd1f6bd4e21fe09929941 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 3 Jul 2026 13:44:04 -0500 Subject: [PATCH 605/876] code format --- .../sdfat_pio/SdCard/PioSdio/PioSdioCard.h | 559 +++++++++--------- .../sdioio/sdfat_pio/SdCard/SdCardInterface.h | 156 ++--- 2 files changed, 367 insertions(+), 348 deletions(-) diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h index ca3cb650a30..bc1d39a26fb 100644 --- a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.h @@ -50,301 +50,312 @@ typedef PioSdioConfig SdioConfig; class PioSdioCard; /** Sdio type for PIO SDIO */ typedef PioSdioCard SdioCard; -//------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ /** * \class PioSdioConfig * \brief SDIO card configuration. */ class PioSdioConfig { - public: - /** - * PioSdioConfig constructor. - * \param[in] clkPin gpio pin for SDIO CLK. - * \param[in] cmdPin gpio pin for SDIO CMD. - * \param[in] dat0Pin gpio start pin for SDIO DAT[4]. - * \param[in] clkDiv PIO clock divisor. - */ - PioSdioConfig(uint clkPin, uint cmdPin, uint dat0Pin, float clkDiv = 1.0) - : m_clkPin(clkPin), +public: + /** + * PioSdioConfig constructor. + * \param[in] clkPin gpio pin for SDIO CLK. + * \param[in] cmdPin gpio pin for SDIO CMD. + * \param[in] dat0Pin gpio start pin for SDIO DAT[4]. + * \param[in] clkDiv PIO clock divisor. + */ + PioSdioConfig(uint clkPin, uint cmdPin, uint dat0Pin, float clkDiv = 1.0) + : m_clkPin(clkPin), m_cmdPin(cmdPin), m_dat0Pin(dat0Pin), - m_clkDiv(clkDiv) {} - /** \return gpio for SDIO CLK */ - uint clkPin() { return m_clkPin; } - /** \return gpio for SDIO CMD */ - uint cmdPin() { return m_cmdPin; } - /** \return gpio for SDIO DAT0 */ - uint dat0Pin() { return m_dat0Pin; } - /** \return PIO clock divisor */ - float clkDiv() { return m_clkDiv; } + m_clkDiv(clkDiv) { + } + /** \return gpio for SDIO CLK */ + uint clkPin() { + return m_clkPin; + } + /** \return gpio for SDIO CMD */ + uint cmdPin() { + return m_cmdPin; + } + /** \return gpio for SDIO DAT0 */ + uint dat0Pin() { + return m_dat0Pin; + } + /** \return PIO clock divisor */ + float clkDiv() { + return m_clkDiv; + } - private: - PioSdioConfig() : m_clkPin(63u), m_cmdPin(63u), m_dat0Pin(63u), m_clkDiv(0) {} - const uint8_t m_clkPin; - const uint8_t m_cmdPin; - const uint8_t m_dat0Pin; - const float m_clkDiv; +private: + PioSdioConfig() : m_clkPin(63u), m_cmdPin(63u), m_dat0Pin(63u), m_clkDiv(0) { + } + const uint8_t m_clkPin; + const uint8_t m_cmdPin; + const uint8_t m_dat0Pin; + const float m_clkDiv; }; -//------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ /** * \class CmdRsp_t * \brief SD command/response type. */ class CmdRsp_t { - public: - /** - * \param[in] idx_ Command index. - * \param[in] rsp_ Response type. - */ - CmdRsp_t(uint8_t idx_, uint8_t rsp_) : idx(idx_), rsp(rsp_) {} - uint8_t idx; ///< Command index. - uint8_t rsp; ///< Response type. +public: + /** + * \param[in] idx_ Command index. + * \param[in] rsp_ Response type. + */ + CmdRsp_t(uint8_t idx_, uint8_t rsp_) : idx(idx_), rsp(rsp_) { + } + uint8_t idx; ///< Command index. + uint8_t rsp; ///< Response type. }; -//------------------------------------------------------------------------------ +// ------------------------------------------------------------------------------ /** * \class PioSdioCard * \brief Raw SDIO access to SD and SDHC flash memory cards. */ -class PioSdioCard : public SdCardInterface { - public: - PioSdioCard() = default; // cppcheck-suppress uninitMemberVar - /** Initialize the SD card. - * \param[in] config SDIO card configuration. - * \return true for success or false for failure. - */ - bool begin(PioSdioConfig config); - /** CMD6 Switch mode: Check Function Set Function. - * \param[in] arg CMD6 argument. - * \param[out] status return status data. - * - * \return true for success or false for failure. - */ - bool cardCMD6(uint32_t arg, uint8_t* status) final; - /** Disable an SDIO card. - * not implemented. - */ - void end() final; - /** CIRCUITPY-CHANGE: mark this card's PIO state machines as surviving a soft - * reset, keeping rp2pio's never-reset bookkeeping coherent with the SMs this - * driver claims directly. */ - void neverReset(); +class PioSdioCard: public SdCardInterface { +public: + PioSdioCard() = default; // cppcheck-suppress uninitMemberVar + /** Initialize the SD card. + * \param[in] config SDIO card configuration. + * \return true for success or false for failure. + */ + bool begin(PioSdioConfig config); + /** CMD6 Switch mode: Check Function Set Function. + * \param[in] arg CMD6 argument. + * \param[out] status return status data. + * + * \return true for success or false for failure. + */ + bool cardCMD6(uint32_t arg, uint8_t *status) final; + /** Disable an SDIO card. + * not implemented. + */ + void end() final; + /** CIRCUITPY-CHANGE: mark this card's PIO state machines as surviving a soft + * reset, keeping rp2pio's never-reset bookkeeping coherent with the SMs this + * driver claims directly. */ + void neverReset(); -#ifndef DOXYGEN_SHOULD_SKIP_THIS - uint32_t __attribute__((error("use sectorCount()"))) cardSize(); -#endif // DOXYGEN_SHOULD_SKIP_THIS - /** Erase a range of sectors. - * - * \param[in] firstSector The address of the first sector in the range. - * \param[in] lastSector The address of the last sector in the range. - * - * \note This function requests the SD card to do a flash erase for a - * range of sectors. The data on the card after an erase operation is - * either 0 or 1, depends on the card vendor. The card must support - * single sector erase. - * - * \return true for success or false for failure. - */ - bool erase(Sector_t firstSector, Sector_t lastSector) final; - /** - * \return code for the last error. See SdCardInfo.h for a list of error - * codes. - */ - uint8_t errorCode() const final; - /** \return error data for last error. */ - uint32_t errorData() const final; - /** \return error line for last error. Tmp function for debug. */ - uint32_t errorLine() const; - /** - * Check for busy with CMD13. - * - * \return true if busy else false. - */ - bool isBusy() final; - /** \return the SD clock frequency in kHz. */ - uint32_t kHzSdClk(); - /** - * Read a 512 byte sector from an SD card. - * - * \param[in] sector Logical sector to be read. - * \param[out] dst Pointer to the location that will receive the data. - * \return true for success or false for failure. - */ - bool readSector(Sector_t sector, uint8_t* dst) final; - /** - * Read multiple 512 byte sectors from an SD card. - * - * \param[in] sector Logical sector to be read. - * \param[in] ns Number of sectors to be read. - * \param[out] dst Pointer to the location that will receive the data. - * \return true for success or false for failure. - */ - bool readSectors(Sector_t sector, uint8_t* dst, size_t ns) final; - /** - * Read a card's CID register. The CID contains card identification - * information such as Manufacturer ID, Product name, Product serial - * number and Manufacturing date. - * - * \param[out] cid pointer to area for returned data. - * - * \return true for success or false for failure. - */ - bool readCID(cid_t* cid) final; - /** - * Read a card's CSD register. The CSD contains Card-Specific Data that - * provides information regarding access to the card's contents. - * - * \param[out] csd pointer to area for returned data. - * - * \return true for success or false for failure. - */ - bool readCSD(csd_t* csd) final; - /** Read one data sector in a multiple sector read sequence - * - * \param[out] dst Pointer to the location for the data to be read. - * - * \return true for success or false for failure. - */ - bool readData(uint8_t* dst); - /** Read OCR register. - * - * \param[out] ocr Value of OCR register. - * \return true for success or false for failure. - */ - bool readOCR(uint32_t* ocr) final; - /** Read SCR register. - * - * \param[out] scr Value of SCR register. - * \return true for success or false for failure. - */ - bool readSCR(scr_t* scr) final; - /** Return the 64 byte SD Status register. - * \param[out] sds location for 64 status bytes. - * \return true for success or false for failure. - */ - bool readSDS(sds_t* sds) final; - /** Start a read multiple sectors sequence. - * - * \param[in] sector Address of first sector in sequence. - * - * \note This function is used with readData() and readStop() for optimized - * multiple sector reads. - * - * \return true for success or false for failure. - */ - bool readStart(Sector_t sector); - /** End a read multiple sectors sequence. - * - * \return true for success or false for failure. - */ - bool readStop(); - /** \return SDIO card status. */ - uint32_t status() final; - /** - * Determine the size of an SD flash memory card. - * - * \return The number of 512 byte data sectors in the card - * or zero if an error occurs. - */ - Sector_t sectorCount() final; - /** - * Send CMD12 to stop read or write. - * - * \param[in] blocking If true, wait for command complete. - * - * \return true for success or false for failure. - */ - bool stopTransmission(bool blocking); - /** \return success if sync successful. Not for user apps. */ - bool syncDevice() final; - /** Return the card type: SD V1, SD V2 or SDHC - * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. - */ - uint8_t type() const final; - /** - * Writes a 512 byte sector to an SD card. - * - * \param[in] sector Logical sector to be written. - * \param[in] src Pointer to the location of the data to be written. - * \return true for success or false for failure. - */ - bool writeSector(Sector_t sector, const uint8_t* src) final; - /** - * Write multiple 512 byte sectors to an SD card. - * - * \param[in] sector Logical sector to be written. - * \param[in] ns Number of sectors to be written. - * \param[in] src Pointer to the location of the data to be written. - * \return true for success or false for failure. - */ - bool writeSectors(Sector_t sector, const uint8_t* src, size_t ns) final; - /** Write one data sector in a multiple sector write sequence. - * \param[in] src Pointer to the location of the data to be written. - * \return true for success or false for failure. - */ - bool writeData(const uint8_t* src); - /** Start a write multiple sectors sequence. - * - * \param[in] sector Address of first sector in sequence. - * - * \note This function is used with writeData() and writeStop() - * for optimized multiple sector writes. - * - * \return true for success or false for failure. - */ - bool writeStart(Sector_t sector); + #ifndef DOXYGEN_SHOULD_SKIP_THIS + uint32_t __attribute__((error("use sectorCount()"))) cardSize(); + #endif // DOXYGEN_SHOULD_SKIP_THIS + /** Erase a range of sectors. + * + * \param[in] firstSector The address of the first sector in the range. + * \param[in] lastSector The address of the last sector in the range. + * + * \note This function requests the SD card to do a flash erase for a + * range of sectors. The data on the card after an erase operation is + * either 0 or 1, depends on the card vendor. The card must support + * single sector erase. + * + * \return true for success or false for failure. + */ + bool erase(Sector_t firstSector, Sector_t lastSector) final; + /** + * \return code for the last error. See SdCardInfo.h for a list of error + * codes. + */ + uint8_t errorCode() const final; + /** \return error data for last error. */ + uint32_t errorData() const final; + /** \return error line for last error. Tmp function for debug. */ + uint32_t errorLine() const; + /** + * Check for busy with CMD13. + * + * \return true if busy else false. + */ + bool isBusy() final; + /** \return the SD clock frequency in kHz. */ + uint32_t kHzSdClk(); + /** + * Read a 512 byte sector from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSector(Sector_t sector, uint8_t *dst) final; + /** + * Read multiple 512 byte sectors from an SD card. + * + * \param[in] sector Logical sector to be read. + * \param[in] ns Number of sectors to be read. + * \param[out] dst Pointer to the location that will receive the data. + * \return true for success or false for failure. + */ + bool readSectors(Sector_t sector, uint8_t *dst, size_t ns) final; + /** + * Read a card's CID register. The CID contains card identification + * information such as Manufacturer ID, Product name, Product serial + * number and Manufacturing date. + * + * \param[out] cid pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCID(cid_t *cid) final; + /** + * Read a card's CSD register. The CSD contains Card-Specific Data that + * provides information regarding access to the card's contents. + * + * \param[out] csd pointer to area for returned data. + * + * \return true for success or false for failure. + */ + bool readCSD(csd_t *csd) final; + /** Read one data sector in a multiple sector read sequence + * + * \param[out] dst Pointer to the location for the data to be read. + * + * \return true for success or false for failure. + */ + bool readData(uint8_t *dst); + /** Read OCR register. + * + * \param[out] ocr Value of OCR register. + * \return true for success or false for failure. + */ + bool readOCR(uint32_t *ocr) final; + /** Read SCR register. + * + * \param[out] scr Value of SCR register. + * \return true for success or false for failure. + */ + bool readSCR(scr_t *scr) final; + /** Return the 64 byte SD Status register. + * \param[out] sds location for 64 status bytes. + * \return true for success or false for failure. + */ + bool readSDS(sds_t *sds) final; + /** Start a read multiple sectors sequence. + * + * \param[in] sector Address of first sector in sequence. + * + * \note This function is used with readData() and readStop() for optimized + * multiple sector reads. + * + * \return true for success or false for failure. + */ + bool readStart(Sector_t sector); + /** End a read multiple sectors sequence. + * + * \return true for success or false for failure. + */ + bool readStop(); + /** \return SDIO card status. */ + uint32_t status() final; + /** + * Determine the size of an SD flash memory card. + * + * \return The number of 512 byte data sectors in the card + * or zero if an error occurs. + */ + Sector_t sectorCount() final; + /** + * Send CMD12 to stop read or write. + * + * \param[in] blocking If true, wait for command complete. + * + * \return true for success or false for failure. + */ + bool stopTransmission(bool blocking); + /** \return success if sync successful. Not for user apps. */ + bool syncDevice() final; + /** Return the card type: SD V1, SD V2 or SDHC + * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC. + */ + uint8_t type() const final; + /** + * Writes a 512 byte sector to an SD card. + * + * \param[in] sector Logical sector to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeSector(Sector_t sector, const uint8_t *src) final; + /** + * Write multiple 512 byte sectors to an SD card. + * + * \param[in] sector Logical sector to be written. + * \param[in] ns Number of sectors to be written. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeSectors(Sector_t sector, const uint8_t *src, size_t ns) final; + /** Write one data sector in a multiple sector write sequence. + * \param[in] src Pointer to the location of the data to be written. + * \return true for success or false for failure. + */ + bool writeData(const uint8_t *src); + /** Start a write multiple sectors sequence. + * + * \param[in] sector Address of first sector in sequence. + * + * \note This function is used with writeData() and writeStop() + * for optimized multiple sector writes. + * + * \return true for success or false for failure. + */ + bool writeStart(Sector_t sector); - /** End a write multiple sectors sequence. - * - * \return true for success or false for failure. - */ - bool writeStop(); + /** End a write multiple sectors sequence. + * + * \return true for success or false for failure. + */ + bool writeStop(); - private: - //---------------------------------------------------------------------------- - bool cardAcmd(uint32_t rca, CmdRsp_t cmdRsp, uint32_t arg); - bool cardCommand(CmdRsp_t cmd, uint32_t arg, void* rsp = nullptr); - void pioConfig(float clkDiv); - void pioEnd(); - bool pioInit(); - void powerUpClockCycles(); - bool readData(void* dst, size_t count); - void setSdErrorCode(uint8_t code, uint32_t line) { - m_errorCode = code; - m_errorLine = line; - } - static const uint8_t IDLE_STATE = 0; - static const uint8_t READ_STATE = 1; - static const uint8_t WRITE_STATE = 2; - Sector_t m_curSector = 0; - uint8_t m_curState = IDLE_STATE; - uint m_cardRsp; - uint m_errorCode; - uint m_errorLine; - bool m_highCapacity; - bool m_initDone = false; - uint m_ocr; - bool m_version2; - uint m_rca; - cid_t m_cid; - csd_t m_csd; - scr_t m_scr; - sds_t m_sds; +private: + // ---------------------------------------------------------------------------- + bool cardAcmd(uint32_t rca, CmdRsp_t cmdRsp, uint32_t arg); + bool cardCommand(CmdRsp_t cmd, uint32_t arg, void *rsp = nullptr); + void pioConfig(float clkDiv); + void pioEnd(); + bool pioInit(); + void powerUpClockCycles(); + bool readData(void *dst, size_t count); + void setSdErrorCode(uint8_t code, uint32_t line) { + m_errorCode = code; + m_errorLine = line; + } + static const uint8_t IDLE_STATE = 0; + static const uint8_t READ_STATE = 1; + static const uint8_t WRITE_STATE = 2; + Sector_t m_curSector = 0; + uint8_t m_curState = IDLE_STATE; + uint m_cardRsp; + uint m_errorCode; + uint m_errorLine; + bool m_highCapacity; + bool m_initDone = false; + uint m_ocr; + bool m_version2; + uint m_rca; + cid_t m_cid; + csd_t m_csd; + scr_t m_scr; + sds_t m_sds; - float m_clkDiv = 0; - uint m_clkPin = 63u; // PIN_SDIO_UNDEFINED; - uint m_cmdPin = 63u; // PIN_SDIO_UNDEFINED; - uint m_dat0Pin = 63u; // PIN_SDIO_UNDEFINED; - PIO m_pio = nullptr; - int m_sm0 = -1; - int m_sm1 = -1; - int m_cmdRspOffset = -1; - pio_sm_config m_cmdConfig; - int m_rdDataOffset = -1; - pio_sm_config m_rdDataConfig; - int m_rdClkOffset = -1; - pio_sm_config m_rdClkConfig; - int m_wrDataOffset = -1; - pio_sm_config m_wrDataConfig; - int m_wrRespOffset = -1; - pio_sm_config m_wrRespConfig; + float m_clkDiv = 0; + uint m_clkPin = 63u; // PIN_SDIO_UNDEFINED; + uint m_cmdPin = 63u; // PIN_SDIO_UNDEFINED; + uint m_dat0Pin = 63u; // PIN_SDIO_UNDEFINED; + PIO m_pio = nullptr; + int m_sm0 = -1; + int m_sm1 = -1; + int m_cmdRspOffset = -1; + pio_sm_config m_cmdConfig; + int m_rdDataOffset = -1; + pio_sm_config m_rdDataConfig; + int m_rdClkOffset = -1; + pio_sm_config m_rdClkConfig; + int m_wrDataOffset = -1; + pio_sm_config m_wrDataConfig; + int m_wrRespOffset = -1; + pio_sm_config m_wrRespConfig; }; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h index a4378ea67e4..5d36ae4d043 100644 --- a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/SdCardInterface.h @@ -33,78 +33,86 @@ * \class SdCardInterface * \brief Abstract interface for an SD card. */ -class SdCardInterface : public FsBlockDeviceInterface { - public: - /** CMD6 Switch mode: Check Function Set Function. - * \param[in] arg CMD6 argument. - * \param[out] status return status data. - * - * \return true for success or false for failure. - */ - virtual bool cardCMD6(uint32_t arg, uint8_t* status) = 0; - /** Erase a range of sectors. - * - * \param[in] firstSector The address of the first sector in the range. - * \param[in] lastSector The address of the last sector in the range. - * - * \return true for success or false for failure. - */ - virtual bool erase(Sector_t firstSector, Sector_t lastSector) = 0; - /** \return error code. */ - virtual uint8_t errorCode() const = 0; - /** \return error data. */ - virtual uint32_t errorData() const = 0; - /** \return false by default */ - virtual bool hasDedicatedSpi() { return false; } - /** \return false by default */ - virtual bool isDedicatedSpi() { return false; } - /** \return false by default */ - virtual bool isSpi() { return false; } - /** Set SPI sharing state - * \param[in] value desired state. - * \return false by default. - */ - virtual bool setDedicatedSpi(bool value) { - (void)value; - return false; - } - /** - * Read a card's CID register. - * - * \param[out] cid pointer to area for returned data. - * - * \return true for success or false for failure. - */ - virtual bool readCID(cid_t* cid) = 0; - /** - * Read a card's CSD register. - * - * \param[out] csd pointer to area for returned data. - * - * \return true for success or false for failure. - */ - virtual bool readCSD(csd_t* csd) = 0; - /** Read OCR register. - * - * \param[out] ocr Value of OCR register. - * \return true for success or false for failure. - */ - virtual bool readOCR(uint32_t* ocr) = 0; - /** Read SCR register. - * - * \param[out] scr Value of SCR register. - * \return true for success or false for failure. - */ - virtual bool readSCR(scr_t* scr) = 0; - /** Return the 64 byte SD Status register. - * \param[out] sds location for 64 status bytes. - * \return true for success or false for failure. - */ - virtual bool readSDS(sds_t* sds) = 0; - /** \return card status. */ - virtual uint32_t status() { return 0XFFFFFFFF; } - /** Return the card type: SD V1, SD V2 or SDHC/SDXC - * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC/SDXC. - */ - virtual uint8_t type() const = 0; +class SdCardInterface: public FsBlockDeviceInterface { +public: + /** CMD6 Switch mode: Check Function Set Function. + * \param[in] arg CMD6 argument. + * \param[out] status return status data. + * + * \return true for success or false for failure. + */ + virtual bool cardCMD6(uint32_t arg, uint8_t *status) = 0; + /** Erase a range of sectors. + * + * \param[in] firstSector The address of the first sector in the range. + * \param[in] lastSector The address of the last sector in the range. + * + * \return true for success or false for failure. + */ + virtual bool erase(Sector_t firstSector, Sector_t lastSector) = 0; + /** \return error code. */ + virtual uint8_t errorCode() const = 0; + /** \return error data. */ + virtual uint32_t errorData() const = 0; + /** \return false by default */ + virtual bool hasDedicatedSpi() { + return false; + } + /** \return false by default */ + virtual bool isDedicatedSpi() { + return false; + } + /** \return false by default */ + virtual bool isSpi() { + return false; + } + /** Set SPI sharing state + * \param[in] value desired state. + * \return false by default. + */ + virtual bool setDedicatedSpi(bool value) { + (void)value; + return false; + } + /** + * Read a card's CID register. + * + * \param[out] cid pointer to area for returned data. + * + * \return true for success or false for failure. + */ + virtual bool readCID(cid_t *cid) = 0; + /** + * Read a card's CSD register. + * + * \param[out] csd pointer to area for returned data. + * + * \return true for success or false for failure. + */ + virtual bool readCSD(csd_t *csd) = 0; + /** Read OCR register. + * + * \param[out] ocr Value of OCR register. + * \return true for success or false for failure. + */ + virtual bool readOCR(uint32_t *ocr) = 0; + /** Read SCR register. + * + * \param[out] scr Value of SCR register. + * \return true for success or false for failure. + */ + virtual bool readSCR(scr_t *scr) = 0; + /** Return the 64 byte SD Status register. + * \param[out] sds location for 64 status bytes. + * \return true for success or false for failure. + */ + virtual bool readSDS(sds_t *sds) = 0; + /** \return card status. */ + virtual uint32_t status() { + return 0XFFFFFFFF; + } + /** Return the card type: SD V1, SD V2 or SDHC/SDXC + * \return 0 - SD V1, 1 - SD V2, or 3 - SDHC/SDXC. + */ + virtual uint8_t type() const = 0; }; From 43aa187469c77c93d0528cfe6fe1259157560e29 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 3 Jul 2026 13:15:50 -0700 Subject: [PATCH 606/876] raspberrypi: enable sdioio on Feather RP2040 Adalogger Turn on the PIO SDIO driver for the Feather RP2040 Adalogger's built-in microSD slot, which is already wired for 4-bit SDIO on consecutive GPIOs (CLK=GPIO18, CMD=GPIO19, DAT0..3=GPIO20..23). Set CIRCUITPY_SDIOIO = 1 and add the standard SDIO_CLOCK / SDIO_COMMAND / SDIO_DATA0..3 pin aliases plus the SDIO_DATA four-pin tuple, matching the Metro RP2350 board's pattern so board.SDIO_DATA works out of the box. Tested on hardware: mounts at 25 MHz 4-bit and benchmarks ~9.6 MB/s write, ~8.1 MB/s read (bulk 4096x16) vs ~1.9 / 1.8 MB/s over the SPI auto-mount on the same board and card -- roughly a 5x throughput improvement. The vendored SdFat PIO driver builds cleanly for RP2040 (the RP2350-only gpio_base block compiles out); firmware fits at 92% of the FLASH region. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../mpconfigboard.mk | 2 ++ .../adafruit_feather_rp2040_adalogger/pins.c | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.mk index 529853b22f5..cc0880ac544 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/mpconfigboard.mk @@ -7,3 +7,5 @@ CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ" + +CIRCUITPY_SDIOIO = 1 diff --git a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/pins.c b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/pins.c index 78d09407a65..1ab755f0aa1 100644 --- a/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/pins.c +++ b/ports/raspberrypi/boards/adafruit_feather_rp2040_adalogger/pins.c @@ -4,8 +4,21 @@ // // SPDX-License-Identifier: MIT +#include "py/objtuple.h" #include "shared-bindings/board/__init__.h" +// Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). +static const mp_rom_obj_tuple_t sdio_data_tuple = { + {&mp_type_tuple}, + 4, + { + MP_ROM_PTR(&pin_GPIO20), + MP_ROM_PTR(&pin_GPIO21), + MP_ROM_PTR(&pin_GPIO22), + MP_ROM_PTR(&pin_GPIO23), + } +}; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -49,18 +62,26 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_SD_CARD_DETECT), MP_ROM_PTR(&pin_GPIO16) }, { MP_ROM_QSTR(MP_QSTR_SD_CLK), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_CLOCK), MP_ROM_PTR(&pin_GPIO18) }, { MP_ROM_QSTR(MP_QSTR_SD_MOSI), MP_ROM_PTR(&pin_GPIO19) }, { MP_ROM_QSTR(MP_QSTR_SD_CMD), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_COMMAND), MP_ROM_PTR(&pin_GPIO19) }, { MP_ROM_QSTR(MP_QSTR_SD_MISO), MP_ROM_PTR(&pin_GPIO20) }, { MP_ROM_QSTR(MP_QSTR_SD_DAT0), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA0), MP_ROM_PTR(&pin_GPIO20) }, { MP_ROM_QSTR(MP_QSTR_SD_DAT1), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA1), MP_ROM_PTR(&pin_GPIO21) }, { MP_ROM_QSTR(MP_QSTR_SD_DAT2), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA2), MP_ROM_PTR(&pin_GPIO22) }, { MP_ROM_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO23) }, { MP_ROM_QSTR(MP_QSTR_SD_DAT3), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA3), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) }, { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, From 6b3ff042d84d33fd04e7e3a3e3ff1768b7d69ec5 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sat, 4 Jul 2026 15:54:41 -0400 Subject: [PATCH 607/876] espressif/boards/lilygo_tdongle_s3/board.c: flip brightness sense --- ports/espressif/boards/lilygo_tdongle_s3/board.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/lilygo_tdongle_s3/board.c b/ports/espressif/boards/lilygo_tdongle_s3/board.c index ede75a5842e..47fef9ee214 100644 --- a/ports/espressif/boards/lilygo_tdongle_s3/board.c +++ b/ports/espressif/boards/lilygo_tdongle_s3/board.c @@ -97,7 +97,7 @@ static void display_init(void) { false, // data_as_commands true, // auto_refresh 60, // native_frames_per_second - true, // backlight_on_high + false, // backlight_on_high false, // SH1107_addressing 50000 // backlight pwm frequency ); From 894397c449c1a03f624b621e1561e834723c022c Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Sun, 5 Jul 2026 12:25:16 -0700 Subject: [PATCH 608/876] Bump tinyusb to include MAX3421E host startup-hang fix (#3748) Advance lib/tinyusb c1bf19ed6 -> fcd5a0603 to pull in hathach/tinyusb#3748 (adafruit/circuitpython#10053), and adapt to its API drift: XFER_RESULT_ABORTED enum, usbd_control.c merged into usbd.c, TUD_AUDIO_EP_SIZE is_highspeed arg, and CFG_TUD_CDC_EP_BUFSIZE -> RX_EPSIZE. Builds clean on espressif and atmel-samd; nordic still needs a usb_audio descriptor macro migration (see PR). Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/tinyusb | 2 +- shared-module/usb/core/Device.c | 2 ++ supervisor/shared/usb/tusb_config.h | 4 ++-- supervisor/shared/usb/usb_device.c | 2 +- supervisor/supervisor.mk | 1 - 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/tinyusb b/lib/tinyusb index c1bf19ed6cf..fcd5a0603e3 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit c1bf19ed6cf1eaa791f221c1bc5ce4b3d069f76d +Subproject commit fcd5a0603e3588cbf4b33f0335da2b630dc76368 diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index 83def37de91..53c87de180a 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -135,6 +135,7 @@ static bool _wait_for_callback(void) { switch (result) { case XFER_RESULT_SUCCESS: return true; + case XFER_RESULT_ABORTED: case XFER_RESULT_FAILED: mp_raise_usb_core_USBError(NULL); break; @@ -201,6 +202,7 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout switch (result) { case XFER_RESULT_SUCCESS: return _actual_len; + case XFER_RESULT_ABORTED: case XFER_RESULT_FAILED: mp_raise_usb_core_USBError(NULL); break; diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index a10cd712226..a34d22d5409 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -144,7 +144,7 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX USB_AUDIO_N_BYTES_PER_SAMPLE #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_N_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) @@ -156,7 +156,7 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX USB_AUDIO_N_BYTES_PER_SAMPLE #define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_N_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms drain keeps clear of the overrun ceiling. #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) #endif diff --git a/supervisor/shared/usb/usb_device.c b/supervisor/shared/usb/usb_device.c index 16ae137edde..e3f1a0d4e26 100644 --- a/supervisor/shared/usb/usb_device.c +++ b/supervisor/shared/usb/usb_device.c @@ -156,7 +156,7 @@ bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_requ // size. Setting CFG_TUD_CDC_RX_BUFSIZE to the endpoint size and then sending // any character will prevent ctrl-c from working. Require at least a 64 // character buffer. -#if CFG_TUD_CDC_RX_BUFSIZE < CFG_TUD_CDC_EP_BUFSIZE + 64 +#if CFG_TUD_CDC_RX_BUFSIZE < CFG_TUD_CDC_RX_EPSIZE + 64 #error "CFG_TUD_CDC_RX_BUFSIZE must be 64 bytes bigger than endpoint size." #endif diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 1f40cebd0d2..e48c2146e7d 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -127,7 +127,6 @@ ifeq ($(CIRCUITPY_TINYUSB),1) SRC_SUPERVISOR += \ lib/tinyusb/src/class/cdc/cdc_device.c \ lib/tinyusb/src/device/usbd.c \ - lib/tinyusb/src/device/usbd_control.c \ supervisor/shared/usb/usb_desc.c \ supervisor/shared/usb/usb_device.c \ From 8c817ab187753107e379041d38e81ef743cd37cc Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 6 Jul 2026 17:00:36 -0500 Subject: [PATCH 609/876] use improved SDIO error message everywhere, remove old message --- locale/circuitpython.pot | 6 +----- ports/espressif/common-hal/sdioio/SDCard.c | 6 +++--- ports/stm/common-hal/sdioio/SDCard.c | 2 +- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 4ae873b6afe..dcf10e4276f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -2063,12 +2063,8 @@ msgid "SDIO GetCardInfo Error %d" msgstr "" #: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" -msgstr "" - #: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format msgid "SDIO Init Error 0x%02x" msgstr "" diff --git a/ports/espressif/common-hal/sdioio/SDCard.c b/ports/espressif/common-hal/sdioio/SDCard.c index 04a9b62ec3e..35850f2f8ae 100644 --- a/ports/espressif/common-hal/sdioio/SDCard.c +++ b/ports/espressif/common-hal/sdioio/SDCard.c @@ -111,7 +111,7 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, if (!slot_in_use[0] && !slot_in_use[1]) { err = sdmmc_host_init(); if (err != ESP_OK) { - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error %x"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error 0x%02x"), err); } host_initialized = true; } @@ -119,14 +119,14 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, err = sdmmc_host_init_slot(sd_slot, &slot_config); if (err != ESP_OK) { ESP_LOGW(TAG, "Failed to initialize SDMMC slot: %x", err); - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error %x"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error 0x%02x"), err); } // sdmmc_card_t card; // self->card = malloc(sizeof(sdmmc_card_t)); err = sdmmc_card_init(&host, &self->card); if (err != ESP_OK) { ESP_LOGW(TAG, "Failed to initialize SDMMC card: %x", err); - mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error %x"), err); + mp_raise_OSError_msg_varg(MP_ERROR_TEXT("SDIO Init Error 0x%02x"), err); } common_hal_sdioio_sdcard_check_for_deinit(self); diff --git a/ports/stm/common-hal/sdioio/SDCard.c b/ports/stm/common-hal/sdioio/SDCard.c index 2d24f24d825..ef708248716 100644 --- a/ports/stm/common-hal/sdioio/SDCard.c +++ b/ports/stm/common-hal/sdioio/SDCard.c @@ -166,7 +166,7 @@ void common_hal_sdioio_sdcard_construct(sdioio_sdcard_obj_t *self, HAL_StatusTypeDef r = HAL_SD_Init(&self->handle); if (r != HAL_OK) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("SDIO Init Error %x"), (unsigned int)r); + mp_raise_ValueError_varg(MP_ERROR_TEXT("SDIO Init Error 0x%02x"), (unsigned int)r); } HAL_SD_CardInfoTypeDef info; From f40dfc4faacc34c18b7e0bde341d5a7b2f96ce6f Mon Sep 17 00:00:00 2001 From: H B Date: Mon, 6 Jul 2026 00:42:31 +0200 Subject: [PATCH 610/876] Translated using Weblate (Turkish) Currently translated at 20.6% (216 of 1046 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/tr/ --- locale/tr.po | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/locale/tr.po b/locale/tr.po index 2ff8c837768..32161ea2419 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -7,15 +7,15 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-06-30 16:02+0000\n" -"Last-Translator: MAE \n" +"PO-Revision-Date: 2026-07-06 23:01+0000\n" +"Last-Translator: H B \n" "Language-Team: none\n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 5.13-dev\n" +"X-Generator: Weblate 2026.7.1.dev0\n" #: main.c msgid "" @@ -49,6 +49,8 @@ msgid "" "\n" "Press reset to exit safe mode.\n" msgstr "" +"\n" +"Güvenli moddan çıkmak için reset'e basın\n" #: supervisor/shared/safe_mode.c msgid "" @@ -81,7 +83,7 @@ msgstr " çıktı:\n" #: py/objstr.c #, c-format msgid "%%c needs int or char" -msgstr "" +msgstr "%%c int ya da char gerektirir" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format @@ -94,7 +96,7 @@ msgstr "" #: py/emitinlinextensa.c #, c-format msgid "%d is not a multiple of %d" -msgstr "" +msgstr "%d %d'nin katı değil" #: shared-bindings/microcontroller/Pin.c msgid "%q and %q contain duplicate pins" @@ -165,7 +167,7 @@ msgstr "%q %q dir" #: ports/raspberrypi/common-hal/wifi/Radio.c msgid "%q is read-only for this board" -msgstr "" +msgstr "%q bu kart için salt okunur" #: py/argcheck.c shared-bindings/usb_hid/Device.c msgid "%q length must be %d" @@ -201,17 +203,17 @@ msgstr "%q 1 olmalı, %q True olduğu zaman" #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "%q must be 16, 24, or 32" -msgstr "" +msgstr "%q 16,24 veya 32 olmalıdır" #: ports/espressif/common-hal/audioi2sin/I2SIn.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "%q must be 8 or 16" -msgstr "" +msgstr "%q 8 veya 16 olmalıdır" #: ports/espressif/common-hal/audiobusio/PDMIn.c #: shared-bindings/audioi2sin/I2SIn.c msgid "%q must be 8, 16, 24, or 32" -msgstr "" +msgstr "%q 8, 16, 24 veya 32 olmalıdır" #: py/argcheck.c shared-bindings/gifio/GifWriter.c #: shared-module/gifio/OnDiskGif.c @@ -220,7 +222,7 @@ msgstr "%q <= %d olmalıdır" #: ports/espressif/common-hal/watchdog/WatchDogTimer.c msgid "%q must be <= %u" -msgstr "" +msgstr "%q, %u değerinden küçük veya eşit olmalıdır" #: py/argcheck.c msgid "%q must be >= %d" @@ -248,7 +250,7 @@ msgstr "" #: shared-bindings/audiobusio/PDMIn.c msgid "%q must be multiple of 8." -msgstr "" +msgstr "%q 8'in katı olmalıdır." #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c From 0c98956e445010db2b6bb93dc5bbd69b6ce015a4 Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Tue, 7 Jul 2026 06:43:29 +0000 Subject: [PATCH 611/876] Add PCBCupid GLYPH C3 board support --- .../boards/pcbcupid_glyph_c3/board.c | 9 +++++ .../boards/pcbcupid_glyph_c3/mpconfigboard.h | 20 +++++++++++ .../boards/pcbcupid_glyph_c3/mpconfigboard.mk | 10 ++++++ .../espressif/boards/pcbcupid_glyph_c3/pins.c | 36 +++++++++++++++++++ .../boards/pcbcupid_glyph_c3/sdkconfig | 14 ++++++++ 5 files changed, 89 insertions(+) create mode 100644 ports/espressif/boards/pcbcupid_glyph_c3/board.c create mode 100644 ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h create mode 100644 ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.mk create mode 100644 ports/espressif/boards/pcbcupid_glyph_c3/pins.c create mode 100644 ports/espressif/boards/pcbcupid_glyph_c3/sdkconfig diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/board.c b/ports/espressif/boards/pcbcupid_glyph_c3/board.c new file mode 100644 index 00000000000..8bc15c17551 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h new file mode 100644 index 00000000000..a5e873e12d2 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 PCBCupid +// +// SPDX-License-Identifier: MIT +#pragma once + +#define MICROPY_HW_BOARD_NAME "PCBCupid GLYPH C3" +#define MICROPY_HW_MCU_NAME "ESP32-C3" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO1) + +#define DEFAULT_UART_BUS_TX (&pin_GPIO21) +#define DEFAULT_UART_BUS_RX (&pin_GPIO20) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO10) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO6) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO7) + diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.mk new file mode 100644 index 00000000000..dea0619ee7e --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.mk @@ -0,0 +1,10 @@ +CIRCUITPY_CREATOR_ID = 0x20241402 +CIRCUITPY_CREATION_ID = 0x00C30001 + +IDF_TARGET = esp32c3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 4MB + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/pins.c b/ports/espressif/boards/pcbcupid_glyph_c3/pins.c new file mode 100644 index 00000000000..2d15da17bd9 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/pins.c @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 PCBCupid +// +// SPDX-License-Identifier: MIT +#include "shared-bindings/board/__init__.h" +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/sdkconfig b/ports/espressif/boards/pcbcupid_glyph_c3/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c3/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From e40d1a492166173550a1f6eedc9834c30de819f1 Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Tue, 7 Jul 2026 08:16:53 +0000 Subject: [PATCH 612/876] Fix EOF newline --- ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h index a5e873e12d2..064559a4dc8 100644 --- a/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h +++ b/ports/espressif/boards/pcbcupid_glyph_c3/mpconfigboard.h @@ -17,4 +17,3 @@ #define DEFAULT_SPI_BUS_SCK (&pin_GPIO10) #define DEFAULT_SPI_BUS_MOSI (&pin_GPIO6) #define DEFAULT_SPI_BUS_MISO (&pin_GPIO7) - From eb544ea0880a5a9d92634875cbce1341de3342e2 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 7 Jul 2026 09:03:28 -0500 Subject: [PATCH 613/876] Allow `channel_count=2` --- shared-bindings/usb_audio/__init__.c | 2 +- shared-module/usb_audio/usb_audio_descriptors.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index 49eaa9716f2..7ac882e982b 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -93,7 +93,7 @@ //| This function may only be used from ``boot.py``. //| //| :param int sample_rate: Samples per second of the streamed audio. -//| :param int channel_count: Number of channels. Only mono (1) is supported initially. +//| :param int channel_count: Number of channels. Either mono (1) or stereo (2) is supported. //| :param int bits_per_sample: Bits per signed PCM sample. Only 16 is supported initially. //| :param bool microphone: Present a microphone (audio flows board -> host). Enabled by default. //| :param bool speaker: Present a speaker (audio flows host -> board). diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 1313e198959..8b297c3218f 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -30,7 +30,7 @@ size_t usb_audio_descriptor_length(void); // 16-bit signed LE PCM, mono. #define USB_AUDIO_N_BYTES_PER_SAMPLE (2) -#define USB_AUDIO_N_CHANNELS (1) +#define USB_AUDIO_N_CHANNELS (2) #define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) // Endpoint number for the single isochronous audio data endpoint. Most device From 2b88f851c27255a74170b97f00cd1fade3478513 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 7 Jul 2026 09:05:25 -0500 Subject: [PATCH 614/876] fix module name typo, enable sdioio for metro rp2040 --- .../boards/adafruit_metro_rp2040/mpconfigboard.mk | 2 ++ .../boards/adafruit_metro_rp2040/pins.c | 14 ++++++++++++++ shared-bindings/sdioio/__init__.c | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk index 20c3042b7a1..8b3ce22c1bc 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/mpconfigboard.mk @@ -7,3 +7,5 @@ CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "GD25Q64C,W25Q64JVxQ,W25Q128JV" + +CIRCUITPY_SDIOIO = 1 diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c b/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c index 859e7cacb08..39ff38e4cad 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c @@ -6,6 +6,18 @@ #include "shared-bindings/board/__init__.h" +// Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). +static const mp_rom_obj_tuple_t sdio_data_tuple = { + {&mp_type_tuple}, + 4, + { + MP_ROM_PTR(&pin_GPIO36), + MP_ROM_PTR(&pin_GPIO37), + MP_ROM_PTR(&pin_GPIO38), + MP_ROM_PTR(&pin_GPIO39), + } +}; + static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS @@ -64,6 +76,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR_SD_CS), MP_ROM_PTR(&pin_GPIO23) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA3), MP_ROM_PTR(&pin_GPIO23) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SDIO_DATA), MP_ROM_PTR(&sdio_data_tuple) }, + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_STEMMA_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, diff --git a/shared-bindings/sdioio/__init__.c b/shared-bindings/sdioio/__init__.c index 45f1219f95a..d2e66f9633d 100644 --- a/shared-bindings/sdioio/__init__.c +++ b/shared-bindings/sdioio/__init__.c @@ -15,7 +15,7 @@ //| """Interface to an SD card via the SDIO bus""" static const mp_rom_map_elem_t sdioio_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdio) }, + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_sdioio) }, { MP_ROM_QSTR(MP_QSTR_SDCard), MP_ROM_PTR(&sdioio_SDCard_type) }, }; From 2285442c5901a3e91b5445c11d3ec655d34e159f Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 7 Jul 2026 09:09:51 -0500 Subject: [PATCH 615/876] Add error to disallow stereo microphone and speaker --- shared-bindings/usb_audio/__init__.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index 7ac882e982b..108c8ee2bdf 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -124,6 +124,10 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map mp_raise_ValueError(MP_ERROR_TEXT("At least one of microphone and speaker must be enabled")); } + if (microphone && speaker && channel_count == 2) { + mp_raise_ValueError(MP_ERROR_TEXT("Only mono operation is supported when microphone and speaker are both enabled")); + } + if (!shared_module_usb_audio_enable(sample_rate, channel_count, bits_per_sample, microphone, speaker)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot change USB devices now")); } From 640e9ff3d9460e5d409d43e9f86dd868ea381419 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 7 Jul 2026 08:38:23 -0700 Subject: [PATCH 616/876] raspberrypi: fix metro_rp2040 sdio_data_tuple (build failure) The sdio_data_tuple added to enable sdioio on metro_rp2040 was copied from metro_rp2350 without adjusting for the chip, so the board fails to compile under -Werror: - add missing `#include "py/objtuple.h"` (for mp_rom_obj_tuple_t and mp_type_tuple, which the other three boards already include) - use GPIO20-23 (the RP2040's DAT0-3) instead of GPIO36-39 (the RP2350's pins); RP2040 has no GPIO36-39, and the SDIO_DATA0..3 entries in this same file already map to 20-23 Builds and benchmarks clean on Metro RP2040 hardware (4-bit SDIO, 31.25 MHz = clk_sys/4). Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c b/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c index 39ff38e4cad..b541aea6f1f 100644 --- a/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c +++ b/ports/raspberrypi/boards/adafruit_metro_rp2040/pins.c @@ -4,6 +4,7 @@ // // SPDX-License-Identifier: MIT +#include "py/objtuple.h" #include "shared-bindings/board/__init__.h" // Four consecutive data GPIOs for the 4-bit SDIO interface (sdioio.SDCard). @@ -11,10 +12,10 @@ static const mp_rom_obj_tuple_t sdio_data_tuple = { {&mp_type_tuple}, 4, { - MP_ROM_PTR(&pin_GPIO36), - MP_ROM_PTR(&pin_GPIO37), - MP_ROM_PTR(&pin_GPIO38), - MP_ROM_PTR(&pin_GPIO39), + MP_ROM_PTR(&pin_GPIO20), + MP_ROM_PTR(&pin_GPIO21), + MP_ROM_PTR(&pin_GPIO22), + MP_ROM_PTR(&pin_GPIO23), } }; From 5c623a8dece8a3a003ebc6edeac744df24314075 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 7 Jul 2026 15:40:58 -0500 Subject: [PATCH 617/876] use new find_pio function in usb host Port and Framebuffer_RP2040. Refactor signature declarations --- .../common-hal/picodvi/Framebuffer_RP2040.c | 35 +++++++------------ .../common-hal/rp2pio/StateMachine.h | 10 +++--- .../rp2_pio_alloc.h => rp2pio/pio_alloc.h} | 16 ++++----- .../sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp | 4 +-- ports/raspberrypi/common-hal/usb_host/Port.c | 32 +++-------------- 5 files changed, 33 insertions(+), 64 deletions(-) rename ports/raspberrypi/common-hal/{sdioio/sdfat_pio/rp2_pio_alloc.h => rp2pio/pio_alloc.h} (61%) diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c index 788f10d6df6..8dddb451d96 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -174,32 +174,23 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self, uint8_t slice = pwm_gpio_to_slice_num(self->pin_pair[0]); - pio_program_t program_struct = { - .instructions = NULL, - .length = 2, - .origin = -1 - }; - size_t pio_index = NUM_PIOS; - int free_state_machines[4]; // We may find all four free. We only use the first three. - for (size_t i = 0; i < NUM_PIOS; i++) { - PIO pio = pio_get_instance(i); - uint8_t free_count = 0; - for (size_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { - if (!pio_sm_is_claimed(pio, sm)) { - free_state_machines[free_count] = sm; - free_count++; - } - } - if (free_count >= 3 && pio_can_add_program(pio, &program_struct)) { - pio_index = i; - break; - } - } - + // We need a PIO with room for a 2-instruction program and 3 free state machines. + size_t pio_index = rp2pio_statemachine_find_pio(2, 3); if (pio_index == NUM_PIOS) { mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); } + // Collect the free state machines on the chosen PIO. We only use the first three. + int free_state_machines[4]; // We may find all four free. + uint8_t free_count = 0; + PIO pio = pio_get_instance(pio_index); + for (size_t sm = 0; sm < NUM_PIO_STATE_MACHINES; sm++) { + if (!pio_sm_is_claimed(pio, sm)) { + free_state_machines[free_count] = sm; + free_count++; + } + } + self->width = width; self->height = height; diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h index c7ef12e1b01..eae1247d6f4 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -12,6 +12,11 @@ #include "common-hal/memorymap/AddressRange.h" #include "hardware/pio.h" +// Shared PIO allocator declarations (rp2pio_statemachine_find_pio, +// rp2pio_statemachine_never_reset, rp2pio_statemachine_reset_ok). Kept in a +// separate, mp-free header so external C++ drivers can include them too. +#include "pio_alloc.h" + // pio_pinmask_t can hold ANY pin masks, so it is used before selection of gpiobase #if NUM_BANK0_GPIOS > 32 typedef struct { uint64_t value; @@ -174,9 +179,4 @@ void rp2pio_statemachine_deinit(rp2pio_statemachine_obj_t *self, bool leave_pins void rp2pio_statemachine_dma_complete_write(rp2pio_statemachine_obj_t *self, int channel); void rp2pio_statemachine_dma_complete_read(rp2pio_statemachine_obj_t *self, int channel); -void rp2pio_statemachine_reset_ok(PIO pio, int sm); -void rp2pio_statemachine_never_reset(PIO pio, int sm); - -uint8_t rp2pio_statemachine_find_pio(int program_size, int sm_count); - extern const mp_obj_type_t rp2pio_statemachine_type; diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h b/ports/raspberrypi/common-hal/rp2pio/pio_alloc.h similarity index 61% rename from ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h rename to ports/raspberrypi/common-hal/rp2pio/pio_alloc.h index 5782aef96f0..ceb4e31631a 100644 --- a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/rp2_pio_alloc.h +++ b/ports/raspberrypi/common-hal/rp2pio/pio_alloc.h @@ -4,13 +4,13 @@ // // SPDX-License-Identifier: MIT -// Bridge declarations that let the vendored (C++) PioSdioCard driver cooperate -// with CircuitPython's rp2pio PIO allocator instead of seizing whole PIO blocks -// through the raw SDK. The definitions live in -// common-hal/rp2pio/StateMachine.c (compiled as C), so they are declared with C -// linkage here. This header deliberately does NOT include the full rp2pio -// StateMachine.h, which pulls in MicroPython object headers that are awkward in -// this C++ translation unit. +// Shared PIO allocator declarations that let external drivers (including the +// vendored C++ PioSdioCard driver) cooperate with CircuitPython's rp2pio PIO +// allocator instead of seizing whole PIO blocks through the raw SDK. The +// definitions live in common-hal/rp2pio/StateMachine.c. This header +// deliberately does NOT include the MicroPython object headers pulled in by the +// full rp2pio StateMachine.h, so it can be included from C++ translation units. +// The declarations are given C linkage for that reason. #pragma once @@ -26,7 +26,7 @@ extern "C" { uint8_t rp2pio_statemachine_find_pio(int program_size, int sm_count); // Mark / unmark a state machine as surviving (or not) a soft reset, so -// rp2pio's reset path keeps its bookkeeping coherent with the SMs this driver +// rp2pio's reset path keeps its bookkeeping coherent with the SMs a driver // claims directly. void rp2pio_statemachine_never_reset(PIO pio, int sm); void rp2pio_statemachine_reset_ok(PIO pio, int sm); diff --git a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp index 7c0bf8d323a..f91515ccef2 100644 --- a/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp +++ b/ports/raspberrypi/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.cpp @@ -31,8 +31,8 @@ #include "DbgLog.h" #include "PioSdioCard.h" #include "PioSdioCard.pio.h" -// CIRCUITPY-CHANGE: cooperate with CircuitPython's rp2pio PIO allocator. -#include "../../rp2_pio_alloc.h" +// CIRCUITPY-CHANGE: cooperate with CircuitPython's rp2pio PIO allocator +#include "common-hal/rp2pio/pio_alloc.h" //------------------------------------------------------------------------------ // USE_DEBUG_MODE 0 - no debug, 1 - print message, 2 - Use scope/analyzer. #define USE_DEBUG_MODE 0 diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c index 36f255df021..da09fdc91c0 100644 --- a/ports/raspberrypi/common-hal/usb_host/Port.c +++ b/ports/raspberrypi/common-hal/usb_host/Port.c @@ -73,41 +73,19 @@ static void __not_in_flash_func(core1_main)(void) { } } -static uint8_t _sm_free_count(uint8_t pio_index) { - PIO pio = pio_get_instance(pio_index); - uint8_t free_count = 0; - for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { - if (!pio_sm_is_claimed(pio, j)) { - free_count++; - } - } - return free_count; -} - -static bool _has_program_room(uint8_t pio_index, uint8_t program_size) { - PIO pio = pio_get_instance(pio_index); - pio_program_t program_struct = { - .instructions = NULL, - .length = program_size, - .origin = -1 - }; - return pio_can_add_program(pio, &program_struct); -} - // As of 0.6.1, the PIO resource requirement is 1 PIO with 3 state machines & // 32 instructions. Since there are only 32 instructions in a state machine, it should // be impossible to have an allocated state machine but 32 instruction slots available; // go ahead and check for it anyway. // -// Since we check that ALL state machines are available, it's not possible for the GPIO +// Since we require ALL state machines to be available, it's not possible for the GPIO // ranges to mismatch on rp2350b static size_t get_usb_pio(void) { - for (size_t i = 0; i < NUM_PIOS; i++) { - if (_has_program_room(i, 32) && _sm_free_count(i) == NUM_PIO_STATE_MACHINES) { - return i; - } + size_t pio_index = rp2pio_statemachine_find_pio(32, NUM_PIO_STATE_MACHINES); + if (pio_index == NUM_PIOS) { + mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); } - mp_raise_RuntimeError(MP_ERROR_TEXT("All state machines in use")); + return pio_index; } From 478762cd1d0338f3d885595f70f1d7d71436db74 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 7 Jul 2026 16:46:31 -0500 Subject: [PATCH 618/876] Support stereo audio device descriptors --- shared-bindings/usb_audio/__init__.c | 16 +- shared-module/usb_audio/USBMicrophone.c | 4 +- shared-module/usb_audio/USBSpeaker.c | 52 ++-- shared-module/usb_audio/USBSpeaker.h | 20 +- shared-module/usb_audio/__init__.c | 281 ++++++++++++++---- .../usb_audio/usb_audio_descriptors.h | 64 +++- supervisor/shared/usb/tusb_config.h | 8 +- 7 files changed, 330 insertions(+), 115 deletions(-) diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index 108c8ee2bdf..77c3201fcb5 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -19,9 +19,9 @@ //| Audio Class (UAC2) microphone: the board is the audio *source* and streams //| samples to the host over a USB isochronous IN endpoint. //| -//| This mode requires 1 IN endpoint and 2 interfaces. Generally, microcontrollers -//| have a limit on the number of endpoints. If you exceed the number of endpoints, -//| CircuitPython will automatically enter Safe Mode. Even in this case, you may be +//| This mode requires 1 (mono) or 2 (stereo / bidirectional) IN endpoint and 2 interfaces. +//| Generally, microcontrollers have a limit on the number of endpoints. If you exceed the number +//| of endpoints, CircuitPython will automatically enter Safe Mode. Even in this case, you may be //| able to enable USB audio by also disabling other USB functions, such as //| `usb_hid` or `usb_midi`. //| @@ -61,9 +61,11 @@ //| pass //| mic.stop() //| -//| The ``sample_rate`` and ``channel_count`` of the sample played must match the -//| values passed to `enable`, and the sample must be 16-bit signed; otherwise -//| ``play`` raises a ``ValueError``. +//| The ``sample_rate`` and ``channel_count`` of the sample played must match the values passed to `enable`, +//| and the sample must be 16-bit signed; otherwise ``play`` raises a ``ValueError``. +//| +//| If both speaker and headphone features are enabled (bidirectional), only mono operation is +//| permitted. //| //| This interface is experimental and may change without notice even in stable //| versions of CircuitPython.""" @@ -115,7 +117,7 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_int_t sample_rate = mp_arg_validate_int_range(args[ARG_sample_rate].u_int, 1, USB_AUDIO_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); - mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_N_CHANNELS, MP_QSTR_channel_count); + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_MAX_CHANNELS, MP_QSTR_channel_count); mp_int_t bits_per_sample = mp_arg_validate_int(args[ARG_bits_per_sample].u_int, USB_AUDIO_BITS_PER_SAMPLE, MP_QSTR_bits_per_sample); bool microphone = args[ARG_microphone].u_bool; bool speaker = args[ARG_speaker].u_bool; diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c index fd5309abeb9..c9245b2edb2 100644 --- a/shared-module/usb_audio/USBMicrophone.c +++ b/shared-module/usb_audio/USBMicrophone.c @@ -107,9 +107,9 @@ size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { return 0; } - // The negotiated USB format is 16-bit signed mono PCM. For this step the + // The negotiated USB format is 16-bit signed PCM. For this step the // bound sample is assumed to already be in that format (e.g. a 16-bit signed - // mono audiocore.RawSample), so its bytes are copied straight through. + // audiocore.RawSample), so its bytes are copied straight through. size_t filled = 0; while (filled < max_bytes) { if (self->buffer_length == 0) { diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c index 12921430bc3..63c75dbf5b5 100644 --- a/shared-module/usb_audio/USBSpeaker.c +++ b/shared-module/usb_audio/USBSpeaker.c @@ -15,11 +15,6 @@ #include "tusb.h" -// The ring is sized independently of the TinyUSB headers (see USBSpeaker.h); -// check it still matches the OUT endpoint's software FIFO so the push side can be -// reasoned about against the USB plumbing. -MP_STATIC_ASSERT(USB_AUDIO_SPEAKER_RING_SIZE == CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); - // Only one speaker can be fed by the single USB OUT endpoint at a time. This // points at the most recently constructed USBSpeaker, or NULL when none exists, // mirroring active_microphone in USBMicrophone.c. The USB background task pushes @@ -36,7 +31,30 @@ void common_hal_usb_audio_usbspeaker_construct(usb_audio_usbspeaker_obj_t *self) self->base.channel_count = usb_audio_channel_count; self->base.samples_signed = true; self->base.single_buffer = false; - self->base.max_buffer_length = USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE; + + // Full owned double-buffer: two halves of FRAMES_PER_BUFFER frames each. Matches + // audiocore.RawSample's convention where base.max_buffer_length is the whole + // buffer and get_buffer() returns half of it. + self->base.max_buffer_length = (2 * USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER * USB_AUDIO_N_BYTES_PER_SAMPLE * usb_audio_channel_count); + self->output_buffer = m_malloc_without_collect(self->base.max_buffer_length); + if (self->output_buffer == NULL) { + common_hal_usb_audio_usbspeaker_deinit(self); + m_malloc_fail(self->base.max_buffer_length); + } + memset(self->output_buffer, 0, self->base.max_buffer_length); + + // The ring is sized independently of the TinyUSB headers; check it still + // matches the OUT endpoint's software FIFO so the push side can be reasoned + // about against the USB plumbing. + self->ring_len = 16 * ((usb_audio_sample_rate / 1000 + 1) * (USB_AUDIO_N_BYTES_PER_SAMPLE * usb_audio_channel_count)); + assert(self->ring_len == CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); + + self->ring = m_malloc_without_collect(self->ring_len); + if (self->ring == NULL) { + common_hal_usb_audio_usbspeaker_deinit(self); + m_malloc_fail(self->ring_len); + } + memset(self->ring, 0, self->ring_len); self->ring_head = 0; self->ring_tail = 0; @@ -104,32 +122,32 @@ void usb_audio_usbspeaker_background_drain(const uint8_t *in, size_t n) { if (self == NULL || n == 0) { return; } - if (n >= USB_AUDIO_SPEAKER_RING_SIZE) { + if (n >= self->ring_len) { // A single chunk larger than the whole ring can only contribute its // newest tail. (Cannot happen with USB packets << ring size, but keep // the copies provably in-bounds.) - in += n - USB_AUDIO_SPEAKER_RING_SIZE; - n = USB_AUDIO_SPEAKER_RING_SIZE; + in += n - self->ring_len; + n = self->ring_len; } common_hal_mcu_disable_interrupts(); - size_t free_space = USB_AUDIO_SPEAKER_RING_SIZE - self->ring_count; + size_t free_space = self->ring_len - self->ring_count; if (n > free_space) { // Overrun: advance the read cursor past the oldest bytes we're about to // overwrite, keeping latency bounded and following the newest host audio. size_t drop = n - free_space; - self->ring_tail = (self->ring_tail + drop) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_tail = (self->ring_tail + drop) % self->ring_len; self->ring_count -= drop; } // Copy in one or two segments, wrapping at the end of the ring. - size_t first = MIN(n, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_head); + size_t first = MIN(n, self->ring_len - self->ring_head); memcpy(&self->ring[self->ring_head], in, first); if (n > first) { memcpy(&self->ring[0], in + first, n - first); } - self->ring_head = (self->ring_head + n) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_head = (self->ring_head + n) % self->ring_len; self->ring_count += n; common_hal_mcu_enable_interrupts(); @@ -157,12 +175,12 @@ uint32_t common_hal_usb_audio_usbspeaker_read(usb_audio_usbspeaker_obj_t *self, // but stay defensive so the returned count is always a whole number). to_copy -= to_copy % bytes_per_frame; - size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + size_t first = MIN(to_copy, self->ring_len - self->ring_tail); memcpy(buffer, &self->ring[self->ring_tail], first); if (to_copy > first) { memcpy((uint8_t *)buffer + first, &self->ring[0], to_copy - first); } - self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_tail = (self->ring_tail + to_copy) % self->ring_len; self->ring_count -= to_copy; common_hal_mcu_enable_interrupts(); @@ -199,12 +217,12 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker // It is never preempted by the producer, so no interrupt guard is required. size_t to_copy = MIN(self->ring_count, (size_t)half); - size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + size_t first = MIN(to_copy, self->ring_len - self->ring_tail); memcpy(out, &self->ring[self->ring_tail], first); if (to_copy > first) { memcpy(out + first, &self->ring[0], to_copy - first); } - self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; + self->ring_tail = (self->ring_tail + to_copy) % self->ring_len; self->ring_count -= to_copy; if (to_copy < half) { diff --git a/shared-module/usb_audio/USBSpeaker.h b/shared-module/usb_audio/USBSpeaker.h index 8c06cff519d..1483ff89085 100644 --- a/shared-module/usb_audio/USBSpeaker.h +++ b/shared-module/usb_audio/USBSpeaker.h @@ -22,21 +22,6 @@ // comfortably inside the ring. #define USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER (128) -// Bytes per audio frame in the negotiated UAC2 format (mono 16-bit for v1). -#define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) - -// Full owned double-buffer: two halves of FRAMES_PER_BUFFER frames each. Matches -// audiocore.RawSample's convention where base.max_buffer_length is the whole -// buffer and get_buffer() returns half of it. -#define USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE (2 * USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER * USB_AUDIO_SPEAKER_BYTES_PER_FRAME) - -// Host -> board receive ring size. Mirrors CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ -// (16 * the full-speed OUT wMaxPacketSize) but is spelled out from the format -// constants so this struct definition stays free of the TinyUSB headers. A -// MP_STATIC_ASSERT in USBSpeaker.c checks the two stay equal. -#define USB_AUDIO_SPEAKER_OUT_PACKET_SIZE ((USB_AUDIO_MAX_SAMPLE_RATE / 1000 + 1) * USB_AUDIO_SPEAKER_BYTES_PER_FRAME) -#define USB_AUDIO_SPEAKER_RING_SIZE (16 * USB_AUDIO_SPEAKER_OUT_PACKET_SIZE) - typedef struct usb_audio_usbspeaker_obj { // First member so the object can be used directly as an audiosample source. audiosample_base_t base; @@ -45,13 +30,14 @@ typedef struct usb_audio_usbspeaker_obj { // background task via usb_audio_usbspeaker_background_drain() and drained by // get_buffer(). Single producer (task), single consumer (output DMA ISR); // see the concurrency notes in USBSpeaker.c. - uint8_t ring[USB_AUDIO_SPEAKER_RING_SIZE]; + uint8_t *ring; + size_t ring_len; size_t ring_head; // next write offset size_t ring_tail; // next read offset size_t ring_count; // valid bytes currently in the ring // Owned double-buffer returned to the output backend by get_buffer(). - uint8_t output_buffer[USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE]; + uint8_t *output_buffer; uint8_t output_index; // 0 or 1: which half get_buffer() fills next } usb_audio_usbspeaker_obj_t; diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 5964b8acf78..113f503ee66 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -20,6 +20,9 @@ #include "supervisor/shared/tick.h" #include "tusb.h" +int16_t *usb_audio_mic_samples; +size_t usb_audio_mic_samples_len; + static bool usb_audio_is_enabled = false; // The host opens each AudioStreaming interface independently (alt 0 = idle, alt 1 @@ -41,14 +44,24 @@ bool usb_audio_microphone_enabled; bool usb_audio_speaker_enabled; // Audio control state surfaced to the host. One extra entry for the master channel 0. -static int8_t usb_audio_mute[USB_AUDIO_N_CHANNELS + 1]; -static int16_t usb_audio_volume[USB_AUDIO_N_CHANNELS + 1]; +static int8_t usb_audio_mute[USB_AUDIO_MAX_CHANNELS + 1]; +static int16_t usb_audio_volume[USB_AUDIO_MAX_CHANNELS + 1]; bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, bool microphone, bool speaker) { if (tud_connected()) { return false; } + // One scratch chunk (1 ms at the sample rate); we loop until the FIFO reaches + // the setpoint. + usb_audio_mic_samples_len = sample_rate / 1000 * channel_count * USB_AUDIO_N_BYTES_PER_SAMPLE; + usb_audio_mic_samples = (int16_t *)m_malloc_without_collect(usb_audio_mic_samples_len); + if (usb_audio_mic_samples == NULL) { + m_malloc_fail(usb_audio_mic_samples_len); + return false; + } + memset(usb_audio_mic_samples, 0, usb_audio_mic_samples_len); + usb_audio_sample_rate = sample_rate; usb_audio_channel_count = channel_count; usb_audio_bits_per_sample = bits_per_sample; @@ -126,25 +139,25 @@ void usb_audio_setup_singletons(void) { speaker; } -// Hand-rolled UAC2 mono speaker (host -> board) descriptor WITHOUT an async -// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR +// Hand-rolled UAC2 speaker (host -> board) descriptor WITHOUT an async +// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO_SPEAKER_STEREO_FB_DESCRIPTOR // (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so // the streaming alt-setting declares a single OUT endpoint (_nEPs = 0x01). The // entity IDs match the mic descriptor (see usb_audio_descriptors.h); only the // terminal roles reverse: the input terminal is the USB-streaming side and the // output terminal is the desktop speaker, and the AS interface links the input // terminal (0x01). Async feedback for true clock matching is a later step. -#define USB_AUDIO_SPEAKER_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ +#define USB_AUDIO_SPEAKER_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ /* Standard Interface Association Descriptor (IAD) */ \ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ /* Standard AC Interface Descriptor(4.7.1) */ \ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ /* Clock Source Descriptor(4.7.2.1) */ \ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ @@ -154,7 +167,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -162,10 +175,103 @@ void usb_audio_setup_singletons(void) { /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) +#define USB_AUDIO_SPEAKER_TWO_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +// Hand-rolled UAC2 microphone (board -> host) descriptor WITHOUT an async +// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR +// (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so +// the streaming alt-setting declares a single IN endpoint (_nEPs = 0x00). Async +// feedback for true clock matching is a later step. +#define USB_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + +#define USB_AUDIO_MIC_TWO_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ + TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + // Hand-rolled UAC2 mono headset (microphone + speaker both enabled): one audio function // presenting both a speaker (host -> board OUT) and a microphone (board -> host // IN) at once. This combines USB_AUDIO_SPEAKER_DESCRIPTOR's speaker chain with -// TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR's mic chain under a single IAD. The two chains +// USB_AUDIO_MIC_DESCRIPTOR's mic chain under a single IAD. The two chains // must use distinct entity IDs (USB_AUDIO_HS_ENTITY_*; see usb_audio_descriptors.h) // because they live in the same AudioControl interface, and they share one clock // source. The function spans three interfaces: AudioControl (_itfnum), the @@ -183,14 +289,14 @@ void usb_audio_setup_singletons(void) { TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ /* --- Speaker chain (host -> board) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* --- Mic chain (board -> host) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- generic microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming out to the host */ \ @@ -201,7 +307,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the speaker input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -214,7 +320,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one IN endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the mic output terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -238,9 +344,17 @@ size_t usb_audio_descriptor_length(void) { return USB_AUDIO_HEADSET_DESC_LEN; } if (usb_audio_direction_is_output()) { - return USB_AUDIO_SPEAKER_DESC_LEN; + if (usb_audio_channel_count == 1) { + return USB_AUDIO_SPEAKER_ONE_CH_DESC_LEN; + } else { + return USB_AUDIO_SPEAKER_TWO_CH_DESC_LEN; + } + } + if (usb_audio_channel_count == 1) { + return USB_AUDIO_MIC_ONE_CH_DESC_LEN; + } else { + return USB_AUDIO_MIC_TWO_CH_DESC_LEN; } - return TUD_AUDIO_MIC_ONE_CH_DESC_LEN; } size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) { @@ -268,6 +382,8 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de const uint8_t ep_in = descriptor_counts->current_endpoint + 1; usb_add_interface_string(*current_interface_string, "CircuitPython Headset"); + (*current_interface_string)++; + const uint8_t usb_audio_descriptor[] = { USB_AUDIO_HEADSET_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, @@ -283,7 +399,6 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; usb_audio_mic_as_itf = descriptor_counts->current_interface + 2; - (*current_interface_string)++; // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus // one OUT and one IN endpoint. descriptor_counts->current_interface += 3; @@ -298,57 +413,105 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de if (usb_audio_direction_is_output()) { usb_add_interface_string(*current_interface_string, "CircuitPython Speaker"); + (*current_interface_string)++; + + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; + + if (usb_audio_channel_count == 1) { + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_SPEAKER_ONE_CH_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epout*/ iso_ep_num, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) + }; + + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. + descriptor_counts->current_interface += 2; + if (!forced_iso_ep) { + descriptor_counts->num_out_endpoints++; + descriptor_counts->current_endpoint++; + } + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); + } else { + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_SPEAKER_TWO_CH_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epout*/ iso_ep_num, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) + }; + + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. + descriptor_counts->current_interface += 3; + if (!forced_iso_ep) { + descriptor_counts->num_out_endpoints += 2; + descriptor_counts->current_endpoint += 2; + } + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); + } + } + + usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); + (*current_interface_string)++; + + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_mic_as_itf = descriptor_counts->current_interface + 1; + + if (usb_audio_channel_count == 2) { const uint8_t usb_audio_descriptor[] = { - USB_AUDIO_SPEAKER_DESCRIPTOR( + USB_AUDIO_MIC_ONE_CH_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, - /*_epout*/ iso_ep_num, - /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) + /*_epin*/ iso_ep_num | 0x80, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) }; - // The AudioStreaming interface follows the AudioControl interface. - usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; - - (*current_interface_string)++; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { - descriptor_counts->num_out_endpoints++; + descriptor_counts->num_in_endpoints++; descriptor_counts->current_endpoint++; } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); return sizeof(usb_audio_descriptor); - } + } else { + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_MIC_TWO_CH_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epin*/ iso_ep_num | 0x80, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) + }; - usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); - const uint8_t usb_audio_descriptor[] = { - TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR( - /*_itfnum*/ descriptor_counts->current_interface, - /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, - /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, - /*_epin*/ iso_ep_num | 0x80, - /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) - }; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. + descriptor_counts->current_interface += 3; + if (!forced_iso_ep) { + descriptor_counts->num_in_endpoints += 2; + descriptor_counts->current_endpoint += 2; + } - // The AudioStreaming interface follows the AudioControl interface. - usb_audio_mic_as_itf = descriptor_counts->current_interface + 1; + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); - (*current_interface_string)++; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. - descriptor_counts->current_interface += 2; - if (!forced_iso_ep) { - descriptor_counts->num_in_endpoints++; - descriptor_counts->current_endpoint++; + return sizeof(usb_audio_descriptor); } - - memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); - - return sizeof(usb_audio_descriptor); } // --------------------------------------------------------------------+ @@ -397,24 +560,20 @@ static void usb_audio_microphone_task(void) { tu_fifo_t *ep_in_ff = tud_audio_get_ep_in_ff(); uint16_t const target = tu_fifo_depth(ep_in_ff) / 2; - // One scratch chunk (1 ms at the max rate); we loop until the FIFO reaches - // the setpoint. Sized for the highest rate enable() accepts. - static int16_t samples[USB_AUDIO_MAX_SAMPLE_RATE / 1000 * USB_AUDIO_N_CHANNELS]; - uint16_t count; while ((count = tu_fifo_count(ep_in_ff)) < target) { size_t want = target - count; - if (want > sizeof(samples)) { - want = sizeof(samples); + if (want > usb_audio_mic_samples_len) { + want = usb_audio_mic_samples_len; } // Pull the next chunk from whichever USBMicrophone is playing. bool underran = false; - size_t filled = usb_audio_usbmicrophone_background_fill((uint8_t *)samples, want); + size_t filled = usb_audio_usbmicrophone_background_fill((uint8_t *)usb_audio_mic_samples, want); if (filled == 0) { // No source attached, paused, or fully drained: keep the endpoint // alive with silence so the host never sees a starved stream. - memset((uint8_t *)samples, 0, want); + memset((uint8_t *)usb_audio_mic_samples, 0, want); } else if (filled < want) { // The source momentarily underran. Send just what it produced and // let the FIFO cushion ride until it catches up next pass, rather @@ -423,7 +582,7 @@ static void usb_audio_microphone_task(void) { underran = true; } - if (tud_audio_write((uint8_t *)samples, (uint16_t)want) == 0) { + if (tud_audio_write((uint8_t *)usb_audio_mic_samples, (uint16_t)want) == 0) { break; // FIFO unexpectedly full / host not ready } if (underran) { @@ -496,10 +655,10 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // A headset exposes a feature unit per direction; the speaker's id matches the // single-direction USB_AUDIO_ENTITY_FEATURE_UNIT, the mic adds a second one. - // Mute/volume state is shared across them (mono, cosmetic for now). + // Mute/volume state is shared across them. if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { - if (channelNum > USB_AUDIO_N_CHANNELS) { + if (channelNum > USB_AUDIO_MAX_CHANNELS) { return false; } switch (ctrlSel) { @@ -537,7 +696,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p switch (ctrlSel) { case AUDIO_TE_CTRL_CONNECTOR: { audio_desc_channel_cluster_t ret; - ret.bNrChannels = USB_AUDIO_N_CHANNELS; + ret.bNrChannels = usb_audio_channel_count; ret.bmChannelConfig = (audio_channel_config_t)0; ret.iChannelNames = 0; return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); @@ -550,7 +709,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit (mute/volume) for either the speaker or mic chain. if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { - if (channelNum > USB_AUDIO_N_CHANNELS) { + if (channelNum > USB_AUDIO_MAX_CHANNELS) { return false; } switch (ctrlSel) { diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 8b297c3218f..d94c8acabdf 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -27,10 +27,10 @@ size_t usb_audio_descriptor_length(void); // The isochronous IN endpoint's wMaxPacketSize in the USB descriptor is computed // for this rate, so it is the highest rate usb_audio.enable() will accept. #define USB_AUDIO_MAX_SAMPLE_RATE (48000) +#define USB_AUDIO_MAX_CHANNELS (2) -// 16-bit signed LE PCM, mono. +// 16-bit signed LE PCM. #define USB_AUDIO_N_BYTES_PER_SAMPLE (2) -#define USB_AUDIO_N_CHANNELS (2) #define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) // Endpoint number for the single isochronous audio data endpoint. Most device @@ -45,7 +45,7 @@ size_t usb_audio_descriptor_length(void); #define USB_AUDIO_ISO_EP_NUM (0) #endif -// Fixed UAC2 entity IDs baked into TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR and the +// Fixed UAC2 entity IDs baked into USB_AUDIO_MIC_DESCRIPTOR and the // hand-rolled speaker descriptor (USB_AUDIO_SPEAKER_DESCRIPTOR in __init__.c). // The speaker reuses the same IDs as the mic; only the terminal roles reverse // (input terminal = USB streaming, output terminal = desktop speaker). @@ -68,21 +68,71 @@ size_t usb_audio_descriptor_length(void); #define USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT (0x06) #define USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL (0x07) // USB streaming out to host -// Length of the no-feedback mono speaker descriptor. It uses the same set of -// sub-descriptors as TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR (one isochronous data +// Length of the no-feedback speaker descriptor. It uses the same set of +// sub-descriptors as USB_AUDIO_MIC_DESCRIPTOR (except one isochronous data // endpoint, no feedback endpoint), so this is identical to -// TUD_AUDIO_MIC_ONE_CH_DESC_LEN -- but spell it out independently so the two +// USB_AUDIO_MIC_DESC_LEN -- but spell it out independently so the two // can diverge later (e.g. stereo) without silently mis-sizing the descriptor. // These TUD_AUDIO_DESC_*_LEN macros come from TinyUSB's usbd.h; this expression // is only expanded where that header is already included (never at the point // tusb_config.h includes us), so the header stays dependency-free. -#define USB_AUDIO_SPEAKER_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ +#define USB_AUDIO_SPEAKER_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + TUD_AUDIO_DESC_STD_AC_LEN \ + TUD_AUDIO_DESC_CS_AC_LEN \ + TUD_AUDIO_DESC_CLK_SRC_LEN \ + /* speaker chain: USB-streaming input terminal -> feature unit -> speaker */ \ + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + /* speaker AudioStreaming interface (alt 0 + alt 1 with OUT endpoint) */ \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define USB_AUDIO_SPEAKER_TWO_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + /* speaker chain: USB-streaming input terminal -> feature unit -> speaker */ \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN \ + /* speaker AudioStreaming interface (alt 0 + alt 1 with OUT endpoint) */ \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define USB_AUDIO_MIC_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + /* mic AudioStreaming interface (alt 0 + alt 1 with IN endpoint) */ \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + + TUD_AUDIO_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + +#define USB_AUDIO_MIC_TWO_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + + TUD_AUDIO_DESC_STD_AC_LEN \ + + TUD_AUDIO_DESC_CS_AC_LEN \ + + TUD_AUDIO_DESC_CLK_SRC_LEN \ + /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ + + TUD_AUDIO_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN \ + /* mic AudioStreaming interface (alt 0 + alt 1 with IN endpoint) */ \ + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + TUD_AUDIO_DESC_STD_AS_INT_LEN \ + TUD_AUDIO_DESC_CS_AS_INT_LEN \ diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index a10cd712226..12f32988bc2 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -142,9 +142,9 @@ extern "C" { #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX USB_AUDIO_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_N_CHANNELS +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_MAX_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_MAX_CHANNELS) // Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) @@ -154,9 +154,9 @@ extern "C" { // IN sizing above. #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX USB_AUDIO_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_N_CHANNELS +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_MAX_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_MAX_CHANNELS) // Deep software FIFO so the 1 ms drain keeps clear of the overrun ceiling. #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) #endif From ff4b108b746a68122ea1bf6d1447c448ffb11b7a Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 7 Jul 2026 18:09:29 -0500 Subject: [PATCH 619/876] Fix descriptor declaration --- shared-module/usb_audio/__init__.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 113f503ee66..add1ec1c972 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -382,7 +382,6 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de const uint8_t ep_in = descriptor_counts->current_endpoint + 1; usb_add_interface_string(*current_interface_string, "CircuitPython Headset"); - (*current_interface_string)++; const uint8_t usb_audio_descriptor[] = { USB_AUDIO_HEADSET_DESCRIPTOR( @@ -399,6 +398,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; usb_audio_mic_as_itf = descriptor_counts->current_interface + 2; + (*current_interface_string)++; // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus // one OUT and one IN endpoint. descriptor_counts->current_interface += 3; @@ -413,7 +413,6 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de if (usb_audio_direction_is_output()) { usb_add_interface_string(*current_interface_string, "CircuitPython Speaker"); - (*current_interface_string)++; // The AudioStreaming interface follows the AudioControl interface. usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; @@ -429,6 +428,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) }; + (*current_interface_string)++; // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { @@ -450,8 +450,9 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) }; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. - descriptor_counts->current_interface += 3; + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two OUT endpoints. + descriptor_counts->current_interface += 2; if (!forced_iso_ep) { descriptor_counts->num_out_endpoints += 2; descriptor_counts->current_endpoint += 2; @@ -464,12 +465,11 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de } usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); - (*current_interface_string)++; // The AudioStreaming interface follows the AudioControl interface. usb_audio_mic_as_itf = descriptor_counts->current_interface + 1; - if (usb_audio_channel_count == 2) { + if (usb_audio_channel_count == 1) { const uint8_t usb_audio_descriptor[] = { USB_AUDIO_MIC_ONE_CH_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, @@ -480,6 +480,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) }; + (*current_interface_string)++; // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { @@ -501,8 +502,9 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) }; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. - descriptor_counts->current_interface += 3; + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two IN endpoints. + descriptor_counts->current_interface += 2; if (!forced_iso_ep) { descriptor_counts->num_in_endpoints += 2; descriptor_counts->current_endpoint += 2; From a0a6b79701179cf5f0f3a7321826e98a6d4797ad Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 7 Jul 2026 18:17:29 -0500 Subject: [PATCH 620/876] Revert dynamic ring buffer --- shared-module/usb_audio/USBSpeaker.c | 18 +++++------------- shared-module/usb_audio/USBSpeaker.h | 13 +++++++++++-- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c index 63c75dbf5b5..58601c69ed2 100644 --- a/shared-module/usb_audio/USBSpeaker.c +++ b/shared-module/usb_audio/USBSpeaker.c @@ -15,6 +15,11 @@ #include "tusb.h" +// The ring is sized independently of the TinyUSB headers (see USBSpeaker.h); +// check it still matches the OUT endpoint's software FIFO so the push side can be +// reasoned about against the USB plumbing. +MP_STATIC_ASSERT(USB_AUDIO_SPEAKER_RING_SIZE == CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); + // Only one speaker can be fed by the single USB OUT endpoint at a time. This // points at the most recently constructed USBSpeaker, or NULL when none exists, // mirroring active_microphone in USBMicrophone.c. The USB background task pushes @@ -43,19 +48,6 @@ void common_hal_usb_audio_usbspeaker_construct(usb_audio_usbspeaker_obj_t *self) } memset(self->output_buffer, 0, self->base.max_buffer_length); - // The ring is sized independently of the TinyUSB headers; check it still - // matches the OUT endpoint's software FIFO so the push side can be reasoned - // about against the USB plumbing. - self->ring_len = 16 * ((usb_audio_sample_rate / 1000 + 1) * (USB_AUDIO_N_BYTES_PER_SAMPLE * usb_audio_channel_count)); - assert(self->ring_len == CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ); - - self->ring = m_malloc_without_collect(self->ring_len); - if (self->ring == NULL) { - common_hal_usb_audio_usbspeaker_deinit(self); - m_malloc_fail(self->ring_len); - } - memset(self->ring, 0, self->ring_len); - self->ring_head = 0; self->ring_tail = 0; self->ring_count = 0; diff --git a/shared-module/usb_audio/USBSpeaker.h b/shared-module/usb_audio/USBSpeaker.h index 1483ff89085..d1694cd4745 100644 --- a/shared-module/usb_audio/USBSpeaker.h +++ b/shared-module/usb_audio/USBSpeaker.h @@ -22,6 +22,16 @@ // comfortably inside the ring. #define USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER (128) +// Bytes per audio frame in the negotiated UAC2 format (mono 16-bit for v1). +#define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) + +// Host -> board receive ring size. Mirrors CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ +// (16 * the full-speed OUT wMaxPacketSize) but is spelled out from the format +// constants so this struct definition stays free of the TinyUSB headers. A +// MP_STATIC_ASSERT in USBSpeaker.c checks the two stay equal. +#define USB_AUDIO_SPEAKER_OUT_PACKET_SIZE ((USB_AUDIO_MAX_SAMPLE_RATE / 1000 + 1) * USB_AUDIO_SPEAKER_BYTES_PER_FRAME) +#define USB_AUDIO_SPEAKER_RING_SIZE (16 * USB_AUDIO_SPEAKER_OUT_PACKET_SIZE) + typedef struct usb_audio_usbspeaker_obj { // First member so the object can be used directly as an audiosample source. audiosample_base_t base; @@ -30,8 +40,7 @@ typedef struct usb_audio_usbspeaker_obj { // background task via usb_audio_usbspeaker_background_drain() and drained by // get_buffer(). Single producer (task), single consumer (output DMA ISR); // see the concurrency notes in USBSpeaker.c. - uint8_t *ring; - size_t ring_len; + uint8_t ring[USB_AUDIO_SPEAKER_RING_SIZE]; size_t ring_head; // next write offset size_t ring_tail; // next read offset size_t ring_count; // valid bytes currently in the ring From 2d9d805ab734b5125919262ac607fcd035826127 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 7 Jul 2026 22:41:10 -0500 Subject: [PATCH 621/876] Assume stereo operation --- shared-bindings/usb_audio/USBMicrophone.c | 1 + shared-bindings/usb_audio/__init__.c | 20 +- shared-module/usb_audio/USBMicrophone.c | 17 +- shared-module/usb_audio/USBSpeaker.c | 71 +++--- shared-module/usb_audio/USBSpeaker.h | 7 +- shared-module/usb_audio/__init__.c | 226 +++++------------- shared-module/usb_audio/__init__.h | 3 +- .../usb_audio/usb_audio_descriptors.h | 44 +--- supervisor/shared/usb/tusb_config.h | 8 +- 9 files changed, 133 insertions(+), 264 deletions(-) diff --git a/shared-bindings/usb_audio/USBMicrophone.c b/shared-bindings/usb_audio/USBMicrophone.c index ff53d812e49..c66c78942dd 100644 --- a/shared-bindings/usb_audio/USBMicrophone.c +++ b/shared-bindings/usb_audio/USBMicrophone.c @@ -12,6 +12,7 @@ #include "shared-bindings/usb_audio/USBMicrophone.h" #include "shared-bindings/util.h" #include "shared-module/usb_audio/__init__.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" //| class USBMicrophone: //| """Streams an audio sample to the host computer as a USB Audio Class microphone. diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index 77c3201fcb5..00ec82f10ae 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -19,7 +19,7 @@ //| Audio Class (UAC2) microphone: the board is the audio *source* and streams //| samples to the host over a USB isochronous IN endpoint. //| -//| This mode requires 1 (mono) or 2 (stereo / bidirectional) IN endpoint and 2 interfaces. +//| This mode requires 2 IN endpoints and 2 interfaces. //| Generally, microcontrollers have a limit on the number of endpoints. If you exceed the number //| of endpoints, CircuitPython will automatically enter Safe Mode. Even in this case, you may be //| able to enable USB audio by also disabling other USB functions, such as @@ -32,7 +32,7 @@ //| //| # boot.py //| import usb_audio -//| usb_audio.enable(sample_rate=16000, channel_count=1, bits_per_sample=16) +//| usb_audio.enable(sample_rate=16000, bits_per_sample=16) //| //| .. code-block:: py //| @@ -64,9 +64,6 @@ //| The ``sample_rate`` and ``channel_count`` of the sample played must match the values passed to `enable`, //| and the sample must be 16-bit signed; otherwise ``play`` raises a ``ValueError``. //| -//| If both speaker and headphone features are enabled (bidirectional), only mono operation is -//| permitted. -//| //| This interface is experimental and may change without notice even in stable //| versions of CircuitPython.""" //| @@ -86,7 +83,6 @@ //| def enable( //| sample_rate: int = 16000, //| channel_count: int = 1, -//| bits_per_sample: int = 16, //| microphone: bool = True, //| speaker: bool = False, //| ) -> None: @@ -105,11 +101,10 @@ //| //| static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_sample_rate, ARG_channel_count, ARG_bits_per_sample, ARG_microphone, ARG_speaker }; + enum { ARG_sample_rate, ARG_channel_count, ARG_microphone, ARG_speaker }; static const mp_arg_t allowed_args[] = { { MP_QSTR_sample_rate, MP_ARG_INT, { .u_int = 16000 } }, { MP_QSTR_channel_count, MP_ARG_INT, { .u_int = 1 } }, - { MP_QSTR_bits_per_sample, MP_ARG_INT, { .u_int = 16 } }, { MP_QSTR_microphone, MP_ARG_BOOL, { .u_bool = true } }, { MP_QSTR_speaker, MP_ARG_BOOL, { .u_bool = false } }, }; @@ -117,8 +112,7 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_int_t sample_rate = mp_arg_validate_int_range(args[ARG_sample_rate].u_int, 1, USB_AUDIO_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); - mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_MAX_CHANNELS, MP_QSTR_channel_count); - mp_int_t bits_per_sample = mp_arg_validate_int(args[ARG_bits_per_sample].u_int, USB_AUDIO_BITS_PER_SAMPLE, MP_QSTR_bits_per_sample); + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_N_CHANNELS, MP_QSTR_channel_count); bool microphone = args[ARG_microphone].u_bool; bool speaker = args[ARG_speaker].u_bool; @@ -126,11 +120,7 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map mp_raise_ValueError(MP_ERROR_TEXT("At least one of microphone and speaker must be enabled")); } - if (microphone && speaker && channel_count == 2) { - mp_raise_ValueError(MP_ERROR_TEXT("Only mono operation is supported when microphone and speaker are both enabled")); - } - - if (!shared_module_usb_audio_enable(sample_rate, channel_count, bits_per_sample, microphone, speaker)) { + if (!shared_module_usb_audio_enable(sample_rate, channel_count, microphone, speaker)) { mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot change USB devices now")); } diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c index c9245b2edb2..a1228ad1c64 100644 --- a/shared-module/usb_audio/USBMicrophone.c +++ b/shared-module/usb_audio/USBMicrophone.c @@ -11,6 +11,7 @@ #include "shared-bindings/usb_audio/USBMicrophone.h" #include "shared-module/usb_audio/__init__.h" +#include "shared-module/usb_audio/usb_audio_descriptors.h" #include "shared-module/audiocore/__init__.h" // Only one microphone may feed the single USB IN endpoint at a time. This points @@ -53,7 +54,7 @@ void common_hal_usb_audio_usbmicrophone_play(usb_audio_usbmicrophone_obj_t *self if (audiosample_get_channel_count(sample_base) != usb_audio_channel_count) { mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_channel_count); } - if (audiosample_get_bits_per_sample(sample_base) != usb_audio_bits_per_sample) { + if (audiosample_get_bits_per_sample(sample_base) != USB_AUDIO_BITS_PER_SAMPLE) { mp_raise_ValueError_varg(MP_ERROR_TEXT("The sample's %q does not match"), MP_QSTR_bits_per_sample); } if (!sample_base->samples_signed) { @@ -138,8 +139,18 @@ size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { } } - size_t n = MIN(self->buffer_length, max_bytes - filled); - memcpy(out + filled, self->buffer, n); + size_t n; + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + n = MIN(self->buffer_length, max_bytes - filled); + memcpy(out + filled, self->buffer, n); + } else { + n = MIN(self->buffer_length << 1, max_bytes - filled); + int16_t *word_buffer = (int16_t *)self->buffer; + int16_t *word_out = (int16_t *)(out + filled); + for (size_t i = 0; i < n / USB_AUDIO_N_BYTES_PER_SAMPLE; i++) { + word_out[i] = word_buffer[i >> 1]; + } + } self->buffer += n; self->buffer_length -= n; filled += n; diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c index 58601c69ed2..310eb3cd7d2 100644 --- a/shared-module/usb_audio/USBSpeaker.c +++ b/shared-module/usb_audio/USBSpeaker.c @@ -32,22 +32,12 @@ void common_hal_usb_audio_usbspeaker_construct(usb_audio_usbspeaker_obj_t *self) // format we present is 16-bit signed LE PCM, which is exactly what the // CircuitPython audio pipeline carries, so no conversion is needed. self->base.sample_rate = usb_audio_sample_rate; - self->base.bits_per_sample = usb_audio_bits_per_sample; + self->base.bits_per_sample = USB_AUDIO_BITS_PER_SAMPLE; self->base.channel_count = usb_audio_channel_count; self->base.samples_signed = true; self->base.single_buffer = false; + self->base.max_buffer_length = USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE; - // Full owned double-buffer: two halves of FRAMES_PER_BUFFER frames each. Matches - // audiocore.RawSample's convention where base.max_buffer_length is the whole - // buffer and get_buffer() returns half of it. - self->base.max_buffer_length = (2 * USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER * USB_AUDIO_N_BYTES_PER_SAMPLE * usb_audio_channel_count); - self->output_buffer = m_malloc_without_collect(self->base.max_buffer_length); - if (self->output_buffer == NULL) { - common_hal_usb_audio_usbspeaker_deinit(self); - m_malloc_fail(self->base.max_buffer_length); - } - memset(self->output_buffer, 0, self->base.max_buffer_length); - self->ring_head = 0; self->ring_tail = 0; self->ring_count = 0; @@ -114,32 +104,32 @@ void usb_audio_usbspeaker_background_drain(const uint8_t *in, size_t n) { if (self == NULL || n == 0) { return; } - if (n >= self->ring_len) { + if (n >= USB_AUDIO_SPEAKER_RING_SIZE) { // A single chunk larger than the whole ring can only contribute its // newest tail. (Cannot happen with USB packets << ring size, but keep // the copies provably in-bounds.) - in += n - self->ring_len; - n = self->ring_len; + in += n - USB_AUDIO_SPEAKER_RING_SIZE; + n = USB_AUDIO_SPEAKER_RING_SIZE; } common_hal_mcu_disable_interrupts(); - size_t free_space = self->ring_len - self->ring_count; + size_t free_space = USB_AUDIO_SPEAKER_RING_SIZE - self->ring_count; if (n > free_space) { // Overrun: advance the read cursor past the oldest bytes we're about to // overwrite, keeping latency bounded and following the newest host audio. size_t drop = n - free_space; - self->ring_tail = (self->ring_tail + drop) % self->ring_len; + self->ring_tail = (self->ring_tail + drop) % USB_AUDIO_SPEAKER_RING_SIZE; self->ring_count -= drop; } // Copy in one or two segments, wrapping at the end of the ring. - size_t first = MIN(n, self->ring_len - self->ring_head); + size_t first = MIN(n, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_head); memcpy(&self->ring[self->ring_head], in, first); if (n > first) { memcpy(&self->ring[0], in + first, n - first); } - self->ring_head = (self->ring_head + n) % self->ring_len; + self->ring_head = (self->ring_head + n) % USB_AUDIO_SPEAKER_RING_SIZE; self->ring_count += n; common_hal_mcu_enable_interrupts(); @@ -167,12 +157,12 @@ uint32_t common_hal_usb_audio_usbspeaker_read(usb_audio_usbspeaker_obj_t *self, // but stay defensive so the returned count is always a whole number). to_copy -= to_copy % bytes_per_frame; - size_t first = MIN(to_copy, self->ring_len - self->ring_tail); + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); memcpy(buffer, &self->ring[self->ring_tail], first); if (to_copy > first) { memcpy((uint8_t *)buffer + first, &self->ring[0], to_copy - first); } - self->ring_tail = (self->ring_tail + to_copy) % self->ring_len; + self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; self->ring_count -= to_copy; common_hal_mcu_enable_interrupts(); @@ -203,35 +193,56 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker uint32_t half = self->base.max_buffer_length / 2; uint8_t *out = self->output_buffer + half * self->output_index; + int16_t *word_out = (int16_t *)out; + int16_t *word_ring = (int16_t *)self->ring; self->output_index = 1 - self->output_index; // Consumer side of the SPSC ring (runs in the output backend's refill ISR). // It is never preempted by the producer, so no interrupt guard is required. size_t to_copy = MIN(self->ring_count, (size_t)half); - size_t first = MIN(to_copy, self->ring_len - self->ring_tail); - memcpy(out, &self->ring[self->ring_tail], first); - if (to_copy > first) { - memcpy(out + first, &self->ring[0], to_copy - first); + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + memcpy(out, &self->ring[self->ring_tail], first); + if (to_copy > first) { + memcpy(out + first, &self->ring[0], to_copy - first); + } + } else { + for (size_t i = self->ring_tail / USB_AUDIO_N_BYTES_PER_SAMPLE; i < first / USB_AUDIO_N_BYTES_PER_SAMPLE; i += 2) { + word_out[i >> 1] = word_ring[i]; + } + if (to_copy > first) { + for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_N_BYTES_PER_SAMPLE; i += 2) { + word_out[(first / USB_AUDIO_N_BYTES_PER_SAMPLE) + (i >> 1)] = word_ring[i]; + } + } } - self->ring_tail = (self->ring_tail + to_copy) % self->ring_len; + self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; self->ring_count -= to_copy; if (to_copy < half) { // Underrun: pad the remainder with silence. Samples are signed, so // silence is 0. This is the consume-side of the pacing failure mode // tracked in the usb-audio-artifact-pacing memory: we never spin. - memset(out + to_copy, 0, half - to_copy); + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + memset(out + to_copy, 0, half - to_copy); + } else { + memset(out + (to_copy >> 1), 0, (half - to_copy) >> 1); + } } - // Mono only for v1, so the single-channel offset is always 0; computed the - // same way as audiocore.RawSample so stereo (interleaved ring) can extend it. + // Computed the same way as audiocore.RawSample so stereo (interleaved ring) + // can extend it. if (single_channel_output) { out += (channel % self->base.channel_count) * (self->base.bits_per_sample / 8); } *buffer = out; - *buffer_length = half; + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + *buffer_length = half; + } else { + *buffer_length = half >> 1; + } // A live USB stream is infinite; never report DONE or the backend would stop. return GET_BUFFER_MORE_DATA; } diff --git a/shared-module/usb_audio/USBSpeaker.h b/shared-module/usb_audio/USBSpeaker.h index d1694cd4745..8c06cff519d 100644 --- a/shared-module/usb_audio/USBSpeaker.h +++ b/shared-module/usb_audio/USBSpeaker.h @@ -25,6 +25,11 @@ // Bytes per audio frame in the negotiated UAC2 format (mono 16-bit for v1). #define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) +// Full owned double-buffer: two halves of FRAMES_PER_BUFFER frames each. Matches +// audiocore.RawSample's convention where base.max_buffer_length is the whole +// buffer and get_buffer() returns half of it. +#define USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE (2 * USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER * USB_AUDIO_SPEAKER_BYTES_PER_FRAME) + // Host -> board receive ring size. Mirrors CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ // (16 * the full-speed OUT wMaxPacketSize) but is spelled out from the format // constants so this struct definition stays free of the TinyUSB headers. A @@ -46,7 +51,7 @@ typedef struct usb_audio_usbspeaker_obj { size_t ring_count; // valid bytes currently in the ring // Owned double-buffer returned to the output backend by get_buffer(). - uint8_t *output_buffer; + uint8_t output_buffer[USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE]; uint8_t output_index; // 0 or 1: which half get_buffer() fills next } usb_audio_usbspeaker_obj_t; diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index add1ec1c972..9d3a244af8e 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -39,15 +39,14 @@ static uint8_t usb_audio_spk_as_itf = 0xff; uint32_t usb_audio_sample_rate; uint8_t usb_audio_channel_count; -uint8_t usb_audio_bits_per_sample; bool usb_audio_microphone_enabled; bool usb_audio_speaker_enabled; // Audio control state surfaced to the host. One extra entry for the master channel 0. -static int8_t usb_audio_mute[USB_AUDIO_MAX_CHANNELS + 1]; -static int16_t usb_audio_volume[USB_AUDIO_MAX_CHANNELS + 1]; +static int8_t usb_audio_mute[USB_AUDIO_N_CHANNELS + 1]; +static int16_t usb_audio_volume[USB_AUDIO_N_CHANNELS + 1]; -bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, bool microphone, bool speaker) { +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, bool microphone, bool speaker) { if (tud_connected()) { return false; } @@ -64,7 +63,6 @@ bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count usb_audio_sample_rate = sample_rate; usb_audio_channel_count = channel_count; - usb_audio_bits_per_sample = bits_per_sample; usb_audio_microphone_enabled = microphone; usb_audio_speaker_enabled = speaker; usb_audio_is_enabled = true; @@ -147,7 +145,7 @@ void usb_audio_setup_singletons(void) { // terminal roles reverse: the input terminal is the USB-streaming side and the // output terminal is the desktop speaker, and the AS interface links the input // terminal (0x01). Async feedback for true clock matching is a later step. -#define USB_AUDIO_SPEAKER_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ +#define USB_AUDIO_SPEAKER_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ /* Standard Interface Association Descriptor (IAD) */ \ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ /* Standard AC Interface Descriptor(4.7.1) */ \ @@ -157,35 +155,7 @@ void usb_audio_setup_singletons(void) { /* Clock Source Descriptor(4.7.2.1) */ \ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ - /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ - /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ - /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ - /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ - /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ - /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ - /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ - /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ - TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) - -#define USB_AUDIO_SPEAKER_TWO_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ - /* Standard Interface Association Descriptor (IAD) */ \ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ - /* Standard AC Interface Descriptor(4.7.1) */ \ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ - /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ - /* Clock Source Descriptor(4.7.2.1) */ \ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ - /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ @@ -195,7 +165,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -208,37 +178,7 @@ void usb_audio_setup_singletons(void) { // (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so // the streaming alt-setting declares a single IN endpoint (_nEPs = 0x00). Async // feedback for true clock matching is a later step. -#define USB_AUDIO_MIC_ONE_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ - /* Standard Interface Association Descriptor (IAD) */ \ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ - /* Standard AC Interface Descriptor(4.7.1) */ \ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ - /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ - /* Clock Source Descriptor(4.7.2.1) */ \ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ - /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ - /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ - /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ - /* Standard AS Interface Descriptor(4.9.1) */ \ - /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ - /* Standard AS Interface Descriptor(4.9.1) */ \ - /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ - /* Class-Specific AS Interface Descriptor(4.9.2) */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ - /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ - /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ - /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ - TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) - -#define USB_AUDIO_MIC_TWO_CH_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ +#define USB_AUDIO_MIC_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */ \ TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ /* Standard AC Interface Descriptor(4.7.1) */ \ @@ -248,7 +188,7 @@ void usb_audio_setup_singletons(void) { /* Clock Source Descriptor(4.7.2.1) */ \ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ @@ -260,7 +200,7 @@ void usb_audio_setup_singletons(void) { /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x02, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -268,7 +208,7 @@ void usb_audio_setup_singletons(void) { /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) -// Hand-rolled UAC2 mono headset (microphone + speaker both enabled): one audio function +// Hand-rolled UAC2 headset (microphone + speaker both enabled): one audio function // presenting both a speaker (host -> board OUT) and a microphone (board -> host // IN) at once. This combines USB_AUDIO_SPEAKER_DESCRIPTOR's speaker chain with // USB_AUDIO_MIC_DESCRIPTOR's mic chain under a single IAD. The two chains @@ -284,21 +224,21 @@ void usb_audio_setup_singletons(void) { /* Standard AC Interface Descriptor(4.7.1) */ \ TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ /* Class-Specific AC Interface Header Descriptor(4.7.2) -- clock + both chains */ \ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + 2 * (TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN), /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + 2 * (TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN), /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ /* Clock Source Descriptor(4.7.2.1) -- shared by both chains */ \ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ /* --- Speaker chain (host -> board) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* --- Mic chain (board -> host) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- generic microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming out to the host */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* --- Speaker AudioStreaming interface (_itfnum + 1) --- */ \ @@ -307,7 +247,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the speaker input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -320,7 +260,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one IN endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the mic output terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ 0x01, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -344,17 +284,9 @@ size_t usb_audio_descriptor_length(void) { return USB_AUDIO_HEADSET_DESC_LEN; } if (usb_audio_direction_is_output()) { - if (usb_audio_channel_count == 1) { - return USB_AUDIO_SPEAKER_ONE_CH_DESC_LEN; - } else { - return USB_AUDIO_SPEAKER_TWO_CH_DESC_LEN; - } - } - if (usb_audio_channel_count == 1) { - return USB_AUDIO_MIC_ONE_CH_DESC_LEN; - } else { - return USB_AUDIO_MIC_TWO_CH_DESC_LEN; + return USB_AUDIO_SPEAKER_DESC_LEN; } + return USB_AUDIO_MIC_DESC_LEN; } size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) { @@ -400,11 +332,11 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de (*current_interface_string)++; // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus - // one OUT and one IN endpoint. + // two OUT and two IN endpoints. descriptor_counts->current_interface += 3; - descriptor_counts->num_out_endpoints++; - descriptor_counts->num_in_endpoints++; - descriptor_counts->current_endpoint += 2; + descriptor_counts->num_out_endpoints += USB_AUDIO_N_CHANNELS; + descriptor_counts->num_in_endpoints += USB_AUDIO_N_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS * 2; memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -417,103 +349,55 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de // The AudioStreaming interface follows the AudioControl interface. usb_audio_spk_as_itf = descriptor_counts->current_interface + 1; - if (usb_audio_channel_count == 1) { - const uint8_t usb_audio_descriptor[] = { - USB_AUDIO_SPEAKER_ONE_CH_DESCRIPTOR( - /*_itfnum*/ descriptor_counts->current_interface, - /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, - /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, - /*_epout*/ iso_ep_num, - /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) - }; - - (*current_interface_string)++; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one OUT endpoint. - descriptor_counts->current_interface += 2; - if (!forced_iso_ep) { - descriptor_counts->num_out_endpoints++; - descriptor_counts->current_endpoint++; - } - - memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); - - return sizeof(usb_audio_descriptor); - } else { - const uint8_t usb_audio_descriptor[] = { - USB_AUDIO_SPEAKER_TWO_CH_DESCRIPTOR( - /*_itfnum*/ descriptor_counts->current_interface, - /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, - /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, - /*_epout*/ iso_ep_num, - /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) - }; - - (*current_interface_string)++; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two OUT endpoints. - descriptor_counts->current_interface += 2; - if (!forced_iso_ep) { - descriptor_counts->num_out_endpoints += 2; - descriptor_counts->current_endpoint += 2; - } - - memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); - - return sizeof(usb_audio_descriptor); - } - } - - usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); - - // The AudioStreaming interface follows the AudioControl interface. - usb_audio_mic_as_itf = descriptor_counts->current_interface + 1; - - if (usb_audio_channel_count == 1) { const uint8_t usb_audio_descriptor[] = { - USB_AUDIO_MIC_ONE_CH_DESCRIPTOR( + USB_AUDIO_SPEAKER_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, - /*_epin*/ iso_ep_num | 0x80, - /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) + /*_epout*/ iso_ep_num, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) }; (*current_interface_string)++; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus one IN endpoint. + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two OUT endpoints. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { - descriptor_counts->num_in_endpoints++; - descriptor_counts->current_endpoint++; + descriptor_counts->num_out_endpoints += USB_AUDIO_N_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS; } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); return sizeof(usb_audio_descriptor); - } else { - const uint8_t usb_audio_descriptor[] = { - USB_AUDIO_MIC_TWO_CH_DESCRIPTOR( - /*_itfnum*/ descriptor_counts->current_interface, - /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, - /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, - /*_epin*/ iso_ep_num | 0x80, - /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) - }; + } - (*current_interface_string)++; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two IN endpoints. - descriptor_counts->current_interface += 2; - if (!forced_iso_ep) { - descriptor_counts->num_in_endpoints += 2; - descriptor_counts->current_endpoint += 2; - } + usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); - memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + // The AudioStreaming interface follows the AudioControl interface. + usb_audio_mic_as_itf = descriptor_counts->current_interface + 1; - return sizeof(usb_audio_descriptor); + const uint8_t usb_audio_descriptor[] = { + USB_AUDIO_MIC_DESCRIPTOR( + /*_itfnum*/ descriptor_counts->current_interface, + /*_stridx*/ *current_interface_string, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, + /*_epin*/ iso_ep_num | 0x80, + /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) + }; + + (*current_interface_string)++; + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two IN endpoints. + descriptor_counts->current_interface += 2; + if (!forced_iso_ep) { + descriptor_counts->num_in_endpoints += USB_AUDIO_N_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS; } + + memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); + + return sizeof(usb_audio_descriptor); } // --------------------------------------------------------------------+ @@ -660,7 +544,7 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Mute/volume state is shared across them. if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { - if (channelNum > USB_AUDIO_MAX_CHANNELS) { + if (channelNum > USB_AUDIO_N_CHANNELS) { return false; } switch (ctrlSel) { @@ -711,7 +595,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit (mute/volume) for either the speaker or mic chain. if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { - if (channelNum > USB_AUDIO_MAX_CHANNELS) { + if (channelNum > USB_AUDIO_N_CHANNELS) { return false; } switch (ctrlSel) { diff --git a/shared-module/usb_audio/__init__.h b/shared-module/usb_audio/__init__.h index 8ec13f90853..5730e6ef60b 100644 --- a/shared-module/usb_audio/__init__.h +++ b/shared-module/usb_audio/__init__.h @@ -17,7 +17,7 @@ // called before USB is connected (i.e. from boot.py); they return false // otherwise. At least one of microphone/speaker must be true; enabling both // presents a combined headset. -bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, mp_int_t bits_per_sample, bool microphone, bool speaker); +bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, bool microphone, bool speaker); bool shared_module_usb_audio_disable(void); // True once enable() has been called successfully. @@ -36,7 +36,6 @@ bool usb_audio_speaker_streaming(void); // Negotiated audio format, valid when usb_audio_enabled() is true. extern uint32_t usb_audio_sample_rate; extern uint8_t usb_audio_channel_count; -extern uint8_t usb_audio_bits_per_sample; // Which streams were requested in enable(), valid when usb_audio_enabled() is // true. Both true presents a combined headset. diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index d94c8acabdf..597a78ab82c 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -27,10 +27,10 @@ size_t usb_audio_descriptor_length(void); // The isochronous IN endpoint's wMaxPacketSize in the USB descriptor is computed // for this rate, so it is the highest rate usb_audio.enable() will accept. #define USB_AUDIO_MAX_SAMPLE_RATE (48000) -#define USB_AUDIO_MAX_CHANNELS (2) -// 16-bit signed LE PCM. +// 16-bit signed LE stereo PCM. #define USB_AUDIO_N_BYTES_PER_SAMPLE (2) +#define USB_AUDIO_N_CHANNELS (2) #define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) // Endpoint number for the single isochronous audio data endpoint. Most device @@ -76,23 +76,7 @@ size_t usb_audio_descriptor_length(void); // These TUD_AUDIO_DESC_*_LEN macros come from TinyUSB's usbd.h; this expression // is only expanded where that header is already included (never at the point // tusb_config.h includes us), so the header stays dependency-free. -#define USB_AUDIO_SPEAKER_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ - + TUD_AUDIO_DESC_STD_AC_LEN \ - + TUD_AUDIO_DESC_CS_AC_LEN \ - + TUD_AUDIO_DESC_CLK_SRC_LEN \ - /* speaker chain: USB-streaming input terminal -> feature unit -> speaker */ \ - + TUD_AUDIO_DESC_INPUT_TERM_LEN \ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ - /* speaker AudioStreaming interface (alt 0 + alt 1 with OUT endpoint) */ \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_CS_AS_INT_LEN \ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) - -#define USB_AUDIO_SPEAKER_TWO_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ +#define USB_AUDIO_SPEAKER_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + TUD_AUDIO_DESC_STD_AC_LEN \ + TUD_AUDIO_DESC_CS_AC_LEN \ + TUD_AUDIO_DESC_CLK_SRC_LEN \ @@ -108,23 +92,7 @@ size_t usb_audio_descriptor_length(void); + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) -#define USB_AUDIO_MIC_ONE_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ - + TUD_AUDIO_DESC_STD_AC_LEN \ - + TUD_AUDIO_DESC_CS_AC_LEN \ - + TUD_AUDIO_DESC_CLK_SRC_LEN \ - /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ - + TUD_AUDIO_DESC_INPUT_TERM_LEN \ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ - /* mic AudioStreaming interface (alt 0 + alt 1 with IN endpoint) */ \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_CS_AS_INT_LEN \ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) - -#define USB_AUDIO_MIC_TWO_CH_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ +#define USB_AUDIO_MIC_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ + TUD_AUDIO_DESC_STD_AC_LEN \ + TUD_AUDIO_DESC_CS_AC_LEN \ + TUD_AUDIO_DESC_CLK_SRC_LEN \ @@ -155,11 +123,11 @@ size_t usb_audio_descriptor_length(void); + TUD_AUDIO_DESC_CLK_SRC_LEN \ /* speaker chain: USB-streaming input terminal -> feature unit -> speaker */ \ + TUD_AUDIO_DESC_INPUT_TERM_LEN \ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ + TUD_AUDIO_DESC_INPUT_TERM_LEN \ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ + + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN \ + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ /* speaker AudioStreaming interface (alt 0 + alt 1 with OUT endpoint) */ \ + TUD_AUDIO_DESC_STD_AS_INT_LEN \ diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index 12f32988bc2..a10cd712226 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -142,9 +142,9 @@ extern "C" { #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX USB_AUDIO_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_MAX_CHANNELS +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_N_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_MAX_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) @@ -154,9 +154,9 @@ extern "C" { // IN sizing above. #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 #define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX USB_AUDIO_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_MAX_CHANNELS +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_N_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_MAX_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms drain keeps clear of the overrun ceiling. #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) #endif From b26ef7d3ab67fcbd9978d077828ee6177a14dfd3 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 7 Jul 2026 22:43:29 -0500 Subject: [PATCH 622/876] Rename audio constants --- shared-bindings/usb_audio/__init__.c | 2 +- shared-module/usb_audio/USBMicrophone.c | 4 +- shared-module/usb_audio/USBSpeaker.c | 12 ++--- shared-module/usb_audio/USBSpeaker.h | 4 +- shared-module/usb_audio/__init__.c | 46 +++++++++---------- .../usb_audio/usb_audio_descriptors.h | 8 ++-- 6 files changed, 38 insertions(+), 38 deletions(-) diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index 00ec82f10ae..7bf20807f3e 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -112,7 +112,7 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_int_t sample_rate = mp_arg_validate_int_range(args[ARG_sample_rate].u_int, 1, USB_AUDIO_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); - mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_N_CHANNELS, MP_QSTR_channel_count); + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_MAX_CHANNELS, MP_QSTR_channel_count); bool microphone = args[ARG_microphone].u_bool; bool speaker = args[ARG_speaker].u_bool; diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c index a1228ad1c64..c10258477c2 100644 --- a/shared-module/usb_audio/USBMicrophone.c +++ b/shared-module/usb_audio/USBMicrophone.c @@ -140,14 +140,14 @@ size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { } size_t n; - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_MAX_CHANNELS)) { n = MIN(self->buffer_length, max_bytes - filled); memcpy(out + filled, self->buffer, n); } else { n = MIN(self->buffer_length << 1, max_bytes - filled); int16_t *word_buffer = (int16_t *)self->buffer; int16_t *word_out = (int16_t *)(out + filled); - for (size_t i = 0; i < n / USB_AUDIO_N_BYTES_PER_SAMPLE; i++) { + for (size_t i = 0; i < n / USB_AUDIO_BYTES_PER_SAMPLE; i++) { word_out[i] = word_buffer[i >> 1]; } } diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c index 310eb3cd7d2..e2f2bf4f525 100644 --- a/shared-module/usb_audio/USBSpeaker.c +++ b/shared-module/usb_audio/USBSpeaker.c @@ -202,18 +202,18 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker size_t to_copy = MIN(self->ring_count, (size_t)half); size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_MAX_CHANNELS)) { memcpy(out, &self->ring[self->ring_tail], first); if (to_copy > first) { memcpy(out + first, &self->ring[0], to_copy - first); } } else { - for (size_t i = self->ring_tail / USB_AUDIO_N_BYTES_PER_SAMPLE; i < first / USB_AUDIO_N_BYTES_PER_SAMPLE; i += 2) { + for (size_t i = self->ring_tail / USB_AUDIO_BYTES_PER_SAMPLE; i < first / USB_AUDIO_BYTES_PER_SAMPLE; i += 2) { word_out[i >> 1] = word_ring[i]; } if (to_copy > first) { - for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_N_BYTES_PER_SAMPLE; i += 2) { - word_out[(first / USB_AUDIO_N_BYTES_PER_SAMPLE) + (i >> 1)] = word_ring[i]; + for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_BYTES_PER_SAMPLE; i += 2) { + word_out[(first / USB_AUDIO_BYTES_PER_SAMPLE) + (i >> 1)] = word_ring[i]; } } } @@ -224,7 +224,7 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker // Underrun: pad the remainder with silence. Samples are signed, so // silence is 0. This is the consume-side of the pacing failure mode // tracked in the usb-audio-artifact-pacing memory: we never spin. - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_MAX_CHANNELS)) { memset(out + to_copy, 0, half - to_copy); } else { memset(out + (to_copy >> 1), 0, (half - to_copy) >> 1); @@ -238,7 +238,7 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker } *buffer = out; - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_MAX_CHANNELS)) { *buffer_length = half; } else { *buffer_length = half >> 1; diff --git a/shared-module/usb_audio/USBSpeaker.h b/shared-module/usb_audio/USBSpeaker.h index 8c06cff519d..27007ad275d 100644 --- a/shared-module/usb_audio/USBSpeaker.h +++ b/shared-module/usb_audio/USBSpeaker.h @@ -22,8 +22,8 @@ // comfortably inside the ring. #define USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER (128) -// Bytes per audio frame in the negotiated UAC2 format (mono 16-bit for v1). -#define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) +// Bytes per audio frame in the negotiated UAC2 format (stereo 16-bit). +#define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_BYTES_PER_SAMPLE * USB_AUDIO_MAX_CHANNELS) // Full owned double-buffer: two halves of FRAMES_PER_BUFFER frames each. Matches // audiocore.RawSample's convention where base.max_buffer_length is the whole diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 9d3a244af8e..10bc368616a 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -43,8 +43,8 @@ bool usb_audio_microphone_enabled; bool usb_audio_speaker_enabled; // Audio control state surfaced to the host. One extra entry for the master channel 0. -static int8_t usb_audio_mute[USB_AUDIO_N_CHANNELS + 1]; -static int16_t usb_audio_volume[USB_AUDIO_N_CHANNELS + 1]; +static int8_t usb_audio_mute[USB_AUDIO_MAX_CHANNELS + 1]; +static int16_t usb_audio_volume[USB_AUDIO_MAX_CHANNELS + 1]; bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, bool microphone, bool speaker) { if (tud_connected()) { @@ -53,7 +53,7 @@ bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count // One scratch chunk (1 ms at the sample rate); we loop until the FIFO reaches // the setpoint. - usb_audio_mic_samples_len = sample_rate / 1000 * channel_count * USB_AUDIO_N_BYTES_PER_SAMPLE; + usb_audio_mic_samples_len = sample_rate / 1000 * channel_count * USB_AUDIO_BYTES_PER_SAMPLE; usb_audio_mic_samples = (int16_t *)m_malloc_without_collect(usb_audio_mic_samples_len); if (usb_audio_mic_samples == NULL) { m_malloc_fail(usb_audio_mic_samples_len); @@ -155,7 +155,7 @@ void usb_audio_setup_singletons(void) { /* Clock Source Descriptor(4.7.2.1) */ \ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ @@ -165,7 +165,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -188,7 +188,7 @@ void usb_audio_setup_singletons(void) { /* Clock Source Descriptor(4.7.2.1) */ \ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ @@ -200,7 +200,7 @@ void usb_audio_setup_singletons(void) { /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -229,14 +229,14 @@ void usb_audio_setup_singletons(void) { TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ /* --- Speaker chain (host -> board) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* --- Mic chain (board -> host) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- generic microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming out to the host */ \ @@ -247,7 +247,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the speaker input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -260,7 +260,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one IN endpoint */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the mic output terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -319,7 +319,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de USB_AUDIO_HEADSET_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBytesPerSample*/ USB_AUDIO_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, /*_epout*/ ep_out, /*_epin*/ ep_in | 0x80, @@ -334,9 +334,9 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus // two OUT and two IN endpoints. descriptor_counts->current_interface += 3; - descriptor_counts->num_out_endpoints += USB_AUDIO_N_CHANNELS; - descriptor_counts->num_in_endpoints += USB_AUDIO_N_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS * 2; + descriptor_counts->num_out_endpoints += USB_AUDIO_MAX_CHANNELS; + descriptor_counts->num_in_endpoints += USB_AUDIO_MAX_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_MAX_CHANNELS * 2; memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -353,7 +353,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de USB_AUDIO_SPEAKER_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBytesPerSample*/ USB_AUDIO_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, /*_epout*/ iso_ep_num, /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) @@ -363,8 +363,8 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two OUT endpoints. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { - descriptor_counts->num_out_endpoints += USB_AUDIO_N_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS; + descriptor_counts->num_out_endpoints += USB_AUDIO_MAX_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_MAX_CHANNELS; } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -381,7 +381,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de USB_AUDIO_MIC_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, + /*_nBytesPerSample*/ USB_AUDIO_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, /*_epin*/ iso_ep_num | 0x80, /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) @@ -391,8 +391,8 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two IN endpoints. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { - descriptor_counts->num_in_endpoints += USB_AUDIO_N_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS; + descriptor_counts->num_in_endpoints += USB_AUDIO_MAX_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_MAX_CHANNELS; } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -544,7 +544,7 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Mute/volume state is shared across them. if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { - if (channelNum > USB_AUDIO_N_CHANNELS) { + if (channelNum > USB_AUDIO_MAX_CHANNELS) { return false; } switch (ctrlSel) { @@ -595,7 +595,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit (mute/volume) for either the speaker or mic chain. if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { - if (channelNum > USB_AUDIO_N_CHANNELS) { + if (channelNum > USB_AUDIO_MAX_CHANNELS) { return false; } switch (ctrlSel) { diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 597a78ab82c..a6622c8f8eb 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -27,11 +27,11 @@ size_t usb_audio_descriptor_length(void); // The isochronous IN endpoint's wMaxPacketSize in the USB descriptor is computed // for this rate, so it is the highest rate usb_audio.enable() will accept. #define USB_AUDIO_MAX_SAMPLE_RATE (48000) +#define USB_AUDIO_MAX_CHANNELS (2) -// 16-bit signed LE stereo PCM. -#define USB_AUDIO_N_BYTES_PER_SAMPLE (2) -#define USB_AUDIO_N_CHANNELS (2) -#define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) +// 16-bit signed LE PCM. +#define USB_AUDIO_BYTES_PER_SAMPLE (2) +#define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_BYTES_PER_SAMPLE * 8) // Endpoint number for the single isochronous audio data endpoint. Most device // controllers accept an ISO endpoint on any number, so the descriptor builder From 33eaf37299f366622827c0ab098a1475eefeb413 Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Wed, 8 Jul 2026 06:49:13 +0000 Subject: [PATCH 623/876] espressif: add pcbcupid_glyph_c6 board --- .../boards/pcbcupid_glyph_c6/board.c | 9 +++ .../boards/pcbcupid_glyph_c6/mpconfigboard.h | 18 ++++++ .../boards/pcbcupid_glyph_c6/mpconfigboard.mk | 10 ++++ .../espressif/boards/pcbcupid_glyph_c6/pins.c | 56 +++++++++++++++++++ .../boards/pcbcupid_glyph_c6/sdkconfig | 14 +++++ 5 files changed, 107 insertions(+) create mode 100644 ports/espressif/boards/pcbcupid_glyph_c6/board.c create mode 100644 ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.h create mode 100644 ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.mk create mode 100644 ports/espressif/boards/pcbcupid_glyph_c6/pins.c create mode 100644 ports/espressif/boards/pcbcupid_glyph_c6/sdkconfig diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/board.c b/ports/espressif/boards/pcbcupid_glyph_c6/board.c new file mode 100644 index 00000000000..3c254a05417 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.h new file mode 100644 index 00000000000..6c83a0f4ecb --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.h @@ -0,0 +1,18 @@ +#pragma once + +#define MICROPY_HW_BOARD_NAME "Pcbcupid GLYPH C6" +#define MICROPY_HW_MCU_NAME "ESP32-C6" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO14) + +#define DEFAULT_UART_BUS_TX (&pin_GPIO16) +#define DEFAULT_UART_BUS_RX (&pin_GPIO17) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO21) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO22) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO23) + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.mk new file mode 100644 index 00000000000..8c2e6d74453 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/mpconfigboard.mk @@ -0,0 +1,10 @@ +CIRCUITPY_CREATOR_ID = 0x20241402 +CIRCUITPY_CREATION_ID = 0x00C60001 + +IDF_TARGET = esp32c6 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m +CIRCUITPY_ESP_FLASH_SIZE = 4MB + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/pins.c b/ports/espressif/boards/pcbcupid_glyph_c6/pins.c new file mode 100644 index 00000000000..c2a4db30854 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/pins.c @@ -0,0 +1,56 @@ +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_D18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_D19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_D20), MP_ROM_PTR(&pin_GPIO20) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO23) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/pcbcupid_glyph_c6/sdkconfig b/ports/espressif/boards/pcbcupid_glyph_c6/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_c6/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From b5a6a3f999ed40f8908b145bc5fd8826ef6fb912 Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Wed, 8 Jul 2026 13:21:09 +0000 Subject: [PATCH 624/876] Add PCBCupid GLYPH H2 board support --- .../boards/pcbcupid_glyph_h2/board.c | 7 +++ .../boards/pcbcupid_glyph_h2/mpconfigboard.h | 20 ++++++ .../boards/pcbcupid_glyph_h2/mpconfigboard.mk | 11 ++++ .../espressif/boards/pcbcupid_glyph_h2/pins.c | 62 +++++++++++++++++++ .../boards/pcbcupid_glyph_h2/sdkconfig | 0 5 files changed, 100 insertions(+) create mode 100644 ports/espressif/boards/pcbcupid_glyph_h2/board.c create mode 100644 ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.h create mode 100644 ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.mk create mode 100644 ports/espressif/boards/pcbcupid_glyph_h2/pins.c create mode 100644 ports/espressif/boards/pcbcupid_glyph_h2/sdkconfig diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/board.c b/ports/espressif/boards/pcbcupid_glyph_h2/board.c new file mode 100644 index 00000000000..4e6bc405957 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_h2/board.c @@ -0,0 +1,7 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.h b/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.h new file mode 100644 index 00000000000..0060381696e --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#pragma once + +#define MICROPY_HW_BOARD_NAME "Pcbcupid GLYPH H2" +#define MICROPY_HW_MCU_NAME "ESP32H2" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO0) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO5) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO4) + +#define DEFAULT_SPI_BUS_SCK (&pin_GPIO11) +#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO22) +#define DEFAULT_SPI_BUS_MISO (&pin_GPIO25) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO23) +#define DEFAULT_UART_BUS_TX (&pin_GPIO24) diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.mk b/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.mk new file mode 100644 index 00000000000..4acde24d6f6 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_h2/mpconfigboard.mk @@ -0,0 +1,11 @@ +CIRCUITPY_CREATOR_ID = 0x20241402 +CIRCUITPY_CREATION_ID = 0x00110001 + +IDF_TARGET = esp32h2 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 48m +CIRCUITPY_ESP_FLASH_SIZE = 4MB +CIRCUITPY_4MB_FLASH_LARGE_USER_FS_LAYOUT = 1 + +CIRCUITPY_ESP_USB_SERIAL_JTAG = 1 diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/pins.c b/ports/espressif/boards/pcbcupid_glyph_h2/pins.c new file mode 100644 index 00000000000..31ec7fa3862 --- /dev/null +++ b/ports/espressif/boards/pcbcupid_glyph_h2/pins.c @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: Copyright (c) 2024 PCBCupid +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO0) }, + + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_IO23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_IO24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_IO25), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, + + + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_D12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_D13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO3) }, + + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO25) }, + { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO23) }, + + + { MP_ROM_QSTR(MP_QSTR_MTMS), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_MTDO), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_MTCK), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_MTDI), MP_ROM_PTR(&pin_GPIO5) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/sdkconfig b/ports/espressif/boards/pcbcupid_glyph_h2/sdkconfig new file mode 100644 index 00000000000..e69de29bb2d From 870c2ea79cd83d48d3d554b03312c15cb313dd4f Mon Sep 17 00:00:00 2001 From: Abhi-00047 Date: Wed, 8 Jul 2026 13:34:08 +0000 Subject: [PATCH 625/876] Fix trailing whitespace in pins.c --- ports/espressif/boards/pcbcupid_glyph_h2/pins.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ports/espressif/boards/pcbcupid_glyph_h2/pins.c b/ports/espressif/boards/pcbcupid_glyph_h2/pins.c index 31ec7fa3862..550ba4e3101 100644 --- a/ports/espressif/boards/pcbcupid_glyph_h2/pins.c +++ b/ports/espressif/boards/pcbcupid_glyph_h2/pins.c @@ -10,7 +10,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BOOT), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO0) }, - + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, @@ -31,7 +31,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_IO26), MP_ROM_PTR(&pin_GPIO26) }, { MP_ROM_QSTR(MP_QSTR_IO27), MP_ROM_PTR(&pin_GPIO27) }, - + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, @@ -44,7 +44,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO2) }, { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO3) }, - + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO4) }, { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO5) }, { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO22) }, From 3a2934f42b9a368ac742c6dd17bbd07983d91063 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 8 Jul 2026 08:36:02 -0500 Subject: [PATCH 626/876] Fix CFG_TUD_AUDIO constants --- supervisor/shared/usb/tusb_config.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index a10cd712226..5530f751d1c 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -141,10 +141,10 @@ extern "C" { #define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX USB_AUDIO_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_N_CHANNELS +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX USB_AUDIO_BYTES_PER_SAMPLE +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_MAX_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_BYTES_PER_SAMPLE, USB_AUDIO_MAX_CHANNELS) // Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) @@ -153,10 +153,10 @@ extern "C" { // descriptor (still mic-only until the speaker descriptor lands). Mirrors the // IN sizing above. #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 -#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX USB_AUDIO_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_N_CHANNELS +#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX USB_AUDIO_BYTES_PER_SAMPLE +#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_MAX_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_BYTES_PER_SAMPLE, USB_AUDIO_MAX_CHANNELS) // Deep software FIFO so the 1 ms drain keeps clear of the overrun ceiling. #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) #endif From f17c5d9ab8a4f5291dd25dd8404f5d5903ac6c84 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 8 Jul 2026 09:37:41 -0500 Subject: [PATCH 627/876] Improve mono to stereo conversion on USBMicrophone --- shared-module/usb_audio/USBMicrophone.c | 28 +++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c index c10258477c2..172ef5465e3 100644 --- a/shared-module/usb_audio/USBMicrophone.c +++ b/shared-module/usb_audio/USBMicrophone.c @@ -102,6 +102,24 @@ bool common_hal_usb_audio_usbmicrophone_get_paused(usb_audio_usbmicrophone_obj_t return self->playing && self->paused; } +static inline uint32_t copy16lsb(uint32_t val) { + #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) + return __PKHBT(val, val, 16); + #else + val &= 0x0000ffff; + return val | (val << 16); + #endif +} + +static inline uint32_t copy16msb(uint32_t val) { + #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) + return __PKHTB(val, val, 16); + #else + val &= 0xffff0000; + return val | (val >> 16); + #endif +} + size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { usb_audio_usbmicrophone_obj_t *self = active_microphone; if (self == NULL || !self->playing || self->paused || self->sample == MP_OBJ_NULL) { @@ -145,10 +163,12 @@ size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { memcpy(out + filled, self->buffer, n); } else { n = MIN(self->buffer_length << 1, max_bytes - filled); - int16_t *word_buffer = (int16_t *)self->buffer; - int16_t *word_out = (int16_t *)(out + filled); - for (size_t i = 0; i < n / USB_AUDIO_BYTES_PER_SAMPLE; i++) { - word_out[i] = word_buffer[i >> 1]; + uint32_t *word_buffer = (uint32_t *)self->buffer; + uint32_t *word_out = (uint32_t *)(out + filled); + for (size_t i = 0; i < n / sizeof(uint32_t); i += 2) { + uint32_t v = word_buffer[i >> 1]; + word_out[i] = copy16lsb(v); + word_out[i + 1] = copy16msb(v); } } self->buffer += n; From f38deba20b14348ab9f722698138f6722f4a456d Mon Sep 17 00:00:00 2001 From: H B Date: Tue, 7 Jul 2026 17:57:53 +0200 Subject: [PATCH 628/876] Translated using Weblate (Turkish) Currently translated at 24.9% (261 of 1046 strings) Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/tr/ --- locale/tr.po | 92 ++++++++++++++++++++++++++++------------------------ 1 file changed, 49 insertions(+), 43 deletions(-) diff --git a/locale/tr.po b/locale/tr.po index 32161ea2419..85315ad5db8 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-07-06 23:01+0000\n" -"Last-Translator: H B \n" +"PO-Revision-Date: 2026-07-08 15:01+0000\n" +"Last-Translator: H B \n" "Language-Team: none\n" "Language: tr\n" "MIME-Version: 1.0\n" @@ -108,7 +108,7 @@ msgstr "%q ve %q farklı olmalılar" #: ports/atmel-samd/common-hal/audiobusio/I2SOut.c msgid "%q and %q must share a clock unit" -msgstr "" +msgstr "%q ve %q bir saat birimi paylaşmalıdır" #: ports/nordic/common-hal/watchdog/WatchDogTimer.c msgid "%q cannot be changed once mode is set to %q" @@ -125,11 +125,11 @@ msgstr "%q hata: %d" #: shared-module/audiodelays/MultiTapDelay.c msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +msgstr "%q'nün içindeki %q, %q veya %q tipi olmalıdır, %q değil" #: py/argcheck.c shared-module/audiofilters/Filter.c msgid "%q in %q must be of type %q, not %q" -msgstr "" +msgstr "%q'nün içindeki %q, %q tipi olmalıdır, %q değil" #: ports/espressif/common-hal/espulp/ULP.c #: ports/espressif/common-hal/mipidsi/Bus.c @@ -238,15 +238,15 @@ msgstr "%q 'h', 'H', 'b' ya da 'B' tipi bir bytearray ya da array olmalı" #: shared-bindings/warnings/__init__.c msgid "%q must be a subclass of %q" -msgstr "" +msgstr "%q, %q'nün alt türü olmalıdır" #: ports/espressif/common-hal/analogbufio/BufferedIn.c msgid "%q must be array of type 'H'" -msgstr "" +msgstr "%q, 'H' dizisi türünde olmalıdır" #: shared-module/synthio/__init__.c msgid "%q must be array of type 'h'" -msgstr "" +msgstr "%q, 'h' dizisi türünde olmalıdır" #: shared-bindings/audiobusio/PDMIn.c msgid "%q must be multiple of 8." @@ -258,17 +258,17 @@ msgstr "%q 8'in katı olmalıdır." #: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c #: shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" -msgstr "" +msgstr "%q; %q veya %q tipi olmalıdır, %q değil" #: shared-bindings/jpegio/JpegDecoder.c msgid "%q must be of type %q, %q, or %q, not %q" -msgstr "" +msgstr "%q; %q, %q veya %q tipi olmalıdır, %q değil" #: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c #: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c #: shared-module/synthio/__init__.c msgid "%q must be of type %q, not %q" -msgstr "" +msgstr "%q; %q tipi olmalıdır, %q değil" #: ports/atmel-samd/common-hal/busio/UART.c msgid "%q must be power of 2" @@ -276,11 +276,11 @@ msgstr "%q, 2'nin kuvveti olmalıdır" #: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q object missing '%q' attribute" -msgstr "" +msgstr "%q nesnesinde '%q' niteliği eksik" #: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "%q object missing '%q' method" -msgstr "" +msgstr "%q nesnesinde '%q' metodu eksik" #: shared-bindings/wifi/Monitor.c msgid "%q out of bounds" @@ -524,7 +524,7 @@ msgstr "" #: shared-bindings/memorymap/AddressRange.c msgid "Address range wraps around" -msgstr "" +msgstr "Adres aralığı başa döner" #: ports/espressif/common-hal/canio/CAN.c msgid "All CAN peripherals are in use" @@ -559,7 +559,7 @@ msgstr "Tüm kanallar kullanımda" #: ports/raspberrypi/common-hal/usb_host/Port.c msgid "All dma channels in use" -msgstr "" +msgstr "Kullanımdaki tüm dma kanalları" #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "All event channels in use" @@ -603,7 +603,7 @@ msgstr "Tüm eşleşmelerle eşleşen dinleyiciniz var" #: ports/espressif/common-hal/_bleio/__init__.c msgid "Already in progress" -msgstr "" +msgstr "Zaten işlemde" #: ports/espressif/bindings/espnow/ESPNow.c #: ports/espressif/common-hal/espulp/ULP.c @@ -621,7 +621,7 @@ msgstr "Halihazırda wifi ağları için tarama yapılıyor" #: supervisor/shared/settings.c #, c-format msgid "An error occurred while retrieving '%s':\n" -msgstr "" +msgstr "'%s' alınırken hata yaşandı:\n" #: ports/stm/common-hal/audiopwmio/PWMAudioOut.c msgid "Another PWMAudioOut is already active" @@ -644,10 +644,11 @@ msgstr "Dizi değerleri tekil bytelar olmalıdır." #: ports/atmel-samd/common-hal/spitarget/SPITarget.c msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" +"Bu veri yolunda asenkron SPI transferi devam ediyor, beklemeye devam edin." #: shared-bindings/usb_audio/__init__.c msgid "At least one of microphone and speaker must be enabled" -msgstr "" +msgstr "Mikrofon veya hoparlörden en az biri etkinleştirilmiş olmalı" #: shared-module/memorymonitor/AllocationAlarm.c #, c-format @@ -662,7 +663,7 @@ msgstr "Ses dönüşümü implemente edilmedi" #: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c #: ports/raspberrypi/common-hal/mcp4822/MCP4822.c msgid "Audio source error" -msgstr "" +msgstr "Ses kaynağı hatası" #: shared-bindings/wifi/Radio.c msgid "AuthMode.OPEN is not used with password" @@ -697,7 +698,7 @@ msgstr "Minimum kare hızından altında" #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "" +msgstr "Bit saati ve kelime seçimi ardışık GPIO pinleri olmalı" #: shared-bindings/bitmaptools/__init__.c msgid "Bitmap size and bits per value must match" @@ -705,7 +706,7 @@ msgstr "Bitmap boyutu ve bit başına değer uyuşmalı" #: supervisor/shared/safe_mode.c msgid "Boot device must be first (interface #0)." -msgstr "" +msgstr "Önyükleme cihazı birinci olmalı (arayüz #0)." #: ports/analog/common-hal/busio/UART.c #: ports/mimxrt10xx/common-hal/busio/UART.c @@ -738,7 +739,7 @@ msgstr "Mevcut arabellek boyutu %d çok büyük. En fazla %d kadar olmalı" #: shared-module/sdcardio/SDCard.c #, c-format msgid "Buffer must be a multiple of %d bytes" -msgstr "" +msgstr "Tampon, %d baytların katı olmalıdır" #: shared-bindings/_bleio/PacketBuffer.c #, c-format @@ -750,7 +751,7 @@ msgstr "Buffer bitten %d daha az" #: shared-bindings/framebufferio/FramebufferDisplay.c #: shared-bindings/struct/__init__.c shared-module/struct/__init__.c msgid "Buffer too small" -msgstr "" +msgstr "Tampon çok küçük" #: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c @@ -778,7 +779,7 @@ msgstr "Yerel nesneye erişmeden önce super().__init__() fonksiyonunu çağır #: ports/cxd56/common-hal/camera/Camera.c msgid "Camera init" -msgstr "" +msgstr "Kamerayı başlat" #: ports/espressif/common-hal/alarm/pin/PinAlarm.c msgid "Can only alarm on RTC IO from deep sleep." @@ -787,19 +788,21 @@ msgstr "Sadece alarm RTC IO'yu uyandırabilir." #: ports/espressif/common-hal/alarm/pin/PinAlarm.c msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" +"Derin uykudan uyanırken, diğerleri yüksek seviyede alarm verecek şekilde " +"ayarlanmışken sadece tek bir düşük pinde alarm tetiklenebilir." #: ports/espressif/common-hal/alarm/pin/PinAlarm.c msgid "Can only alarm on two low pins from deep sleep." -msgstr "" +msgstr "Derin uykudan uyanırken yalnızca iki düşük pinde alarm tetiklenebilir." #: ports/espressif/common-hal/audioio/AudioOut.c msgid "Can't construct AudioOut because continuous channel already open" -msgstr "" +msgstr "AudioOut oluşturulamıyor çünkü kesintisiz kanal zaten açık" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c msgid "Can't set CCCD on local Characteristic" -msgstr "" +msgstr "Yerel Karakteristikte CCCD ayarlanamaz" #: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c #: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c @@ -813,7 +816,7 @@ msgstr "yeni Adaptör oluşturulamadı; _bleio.adapter kullanın;" #: shared-module/i2cioexpander/IOExpander.c msgid "Cannot deinitialize board IOExpander" -msgstr "" +msgstr "Kart IOExpander'ı devreden çıkarılamıyor" #: shared-bindings/displayio/Bitmap.c #: shared-bindings/memorymonitor/AllocationSize.c @@ -839,7 +842,7 @@ msgstr "Genişletilmiş, bağlanabilir reklamlar için tarama yanıtları yapıl #: ports/espressif/common-hal/alarm/pin/PinAlarm.c msgid "Cannot pull on input-only pin." -msgstr "" +msgstr "Sadece giriş olan pinde pull ayarlanamaz." #: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Cannot record to a file" @@ -847,7 +850,7 @@ msgstr "Dosyaya kayıt yapılamıyor" #: shared-module/storage/__init__.c msgid "Cannot remount path when visible via USB." -msgstr "" +msgstr "USB üzerinden görünür durumdayken yol yeniden bağlanamaz." #: shared-bindings/digitalio/DigitalInOut.c #: shared-bindings/i2cioexpander/IOPin.c @@ -861,15 +864,15 @@ msgstr "RS485 modunda RTS veya CTS belirtilemez" #: py/objslice.c msgid "Cannot subclass slice" -msgstr "" +msgstr "Alt sınıf kesilemez" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" +msgstr "GPIO0..15, GPIO32..47 ile birlikte kullanılamaz" #: ports/nordic/common-hal/alarm/pin/PinAlarm.c msgid "Cannot wake on pin edge, only level" -msgstr "" +msgstr "Pin kenarı ile uyandırılamaz, yalnızca seviye ile uyanabilir" #: ports/espressif/common-hal/alarm/pin/PinAlarm.c msgid "Cannot wake on pin edge. Only level." @@ -895,19 +898,19 @@ msgstr "Bağlantı koparıldı ve tekrar kullanılamaz. Yeni bir bağlantı kuru #: shared-bindings/bitmaptools/__init__.c msgid "Coordinate arrays have different lengths" -msgstr "" +msgstr "Kordinat dizilerinin uzunlukları farklı" #: shared-bindings/bitmaptools/__init__.c msgid "Coordinate arrays types have different sizes" -msgstr "" +msgstr "Kordinat dizilerinin türlerifarklı boyutlara sahip" #: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c msgid "Could not allocate DMA capable buffer" -msgstr "" +msgstr "DMA yetenekli tampon tahsis edilemedi" #: ports/espressif/common-hal/rclcpy/Publisher.c msgid "Could not publish to ROS topic" -msgstr "" +msgstr "ROS konusuna yayımlanamadı" #: shared-bindings/_bleio/Adapter.c msgid "Could not set address" @@ -919,22 +922,24 @@ msgstr "Kesinti başlatılamadı, RX kullanımda" #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate decoder" -msgstr "" +msgstr "Deşifre edici tahsis edilemedi" #: ports/espressif/common-hal/rclcpy/__init__.c #, c-format msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" +"Yazılımsal yeniden başlatma sırasında kritik ROS hatası, sıfırlama " +"gerekiyor: %d" #: ports/stm/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Channel Init Error" -msgstr "" +msgstr "DAC kanalı başlatma hatası" #: ports/stm/common-hal/analogio/AnalogOut.c #: ports/stm/common-hal/audioio/AudioOut.c msgid "DAC Device Init Error" -msgstr "" +msgstr "DAC cihazı başlatma hatası" #: ports/atmel-samd/common-hal/audioio/AudioOut.c msgid "DAC already in use" @@ -947,21 +952,22 @@ msgstr "Data 0 pini bite hizalı olmalı" #: shared-module/jpegio/JpegDecoder.c msgid "Data format error (may be broken data)" -msgstr "" +msgstr "Veri formatı hatası (bozuk veri olabilir)" #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c msgid "Data not supported with directed advertising" -msgstr "" +msgstr "Veri, hedefli reklamcılıkla desteklenmemektedir" #: ports/espressif/common-hal/_bleio/Adapter.c #: ports/nordic/common-hal/_bleio/Adapter.c msgid "Data too large for advertisement packet" -msgstr "" +msgstr "Veri, reklam paketi için çok büyük" #: ports/stm/common-hal/alarm/pin/PinAlarm.c msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" +"Derin uyku pinleri, aşağı çekme direnci ile yükselen kenar kullanmalıdır" #: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c msgid "Destination capacity is smaller than destination_length." From 2bae80af95390121dfcaa3482697fa2347ecc6ee Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 7 Jul 2026 23:00:00 -0400 Subject: [PATCH 629/876] espressif/_bleio: build discovered GATT objects on the VM task Remote service/characteristic/descriptor discovery callbacks run on the NimBLE host task, not the CircuitPython VM task, and were allocating CircuitPython objects (mp_obj_malloc, etc.) directly in that context. Because the espressif port has no GIL (MICROPY_PY_THREAD == 0), an allocation on the host task can trigger a gc_collect() there, which scans the host task's stack instead of the VM task's and frees the still-live half-built discovery objects. The resulting heap corruption showed up as an interrupt-watchdog reset (ESP_RST_INT_WDT) partway through discovery. The callbacks now only copy the plain NimBLE result struct into a fixed ring buffer (a non-allocating memcpy, guarded with interrupts disabled since ringbuf ops are not atomic and the host and VM tasks preempt each other). The VM task drains the ring and builds the Python objects, so all heap allocation happens on the VM task. The ring storage is allocated on first use from the port (IDF) heap, so it needs no GC root, survives soft reloads, and costs no RAM until a central actually discovers services. Co-Authored-By: Claude Opus 4.8 (1M context) Co-Authored-By: Claude Fable 5 --- .../espressif/common-hal/_bleio/Connection.c | 242 +++++++++++++----- 1 file changed, 172 insertions(+), 70 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 8df4dc26545..5236ee6e6e7 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -14,6 +14,7 @@ #include "py/objlist.h" #include "py/objstr.h" #include "py/qstr.h" +#include "py/ringbuf.h" #include "py/runtime.h" #include "shared/runtime/interrupt_char.h" @@ -24,8 +25,10 @@ #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" +#include "supervisor/port_heap.h" #include "supervisor/shared/tick.h" #include "common-hal/_bleio/ble_events.h" @@ -184,21 +187,6 @@ static volatile int _last_discovery_status; // Give 20 seconds for each step of discovery: services, characteristics, attributes. #define DISCOVERY_TIMEOUT_MS 20000 -static int _wait_for_discovery_step_done(void) { - const uint64_t timeout_time_ms = common_hal_time_monotonic_ms() + DISCOVERY_TIMEOUT_MS; - while ((_last_discovery_status == 0) && (common_hal_time_monotonic_ms() < timeout_time_ms)) { - RUN_BACKGROUND_TASKS; - if (mp_hal_is_interrupted()) { - // Return prematurely. Then the interrupt will be raised. - _last_discovery_status = BLE_HS_EDONE; - } - } - if (_last_discovery_status == 0) { - return BLE_HS_ETIMEOUT; - } - return _last_discovery_status; -} - // Record result of last discovery step: services, characteristics, descriptors. static void _set_discovery_step_status(int status) { _last_discovery_status = status; @@ -215,18 +203,123 @@ static void _check_discovery_status(int status) { CHECK_BLE_ERROR(status); } +// Raw discovery results are staged here by the NimBLE host-task callbacks. +// Those callbacks run on the "nimble_host" task, NOT the VM task, so they must +// not allocate from the MicroPython heap: an allocation there can trigger a +// gc_collect() that scans the wrong task's stack and frees the VM's live +// objects. Instead the callbacks copy the plain NimBLE result struct into this +// ring (a non-allocating memcpy), and the VM task drains it and builds the +// Python objects. See shared-module/_bleio/ScanResults.c for the same pattern. +// +// Discovery is serialized (one discover_remote_services() at a time), so a +// single file-static ring suffices. It must hold one ATT-PDU burst of records: +// within a response PDU the host task invokes the callback repeatedly without +// yielding, so the VM task cannot drain until the next PDU's round-trip. +// +// The storage is allocated on first use from the port (IDF) heap, not the GC +// heap, so it needs no GC root and survives soft reloads: a stale procedure's +// pushes always land in live memory. It is never freed. (Same pattern as the +// port_malloc-backed ringbuf in shared-module/keypad/EventQueue.c.) +#define DISCOVERY_RING_SIZE (4096) +static uint8_t *_discovery_ring_buffer; +static ringbuf_t _discovery_ring; + +// Stage one fixed-size record. Runs on the nimble_host task. +// ringbuf ops are not atomic and the two tasks preempt each other, so guard +// with interrupts disabled; the guarded region is a single small record copy. +static bool _push_record(const void *record, size_t size) { + common_hal_mcu_disable_interrupts(); + bool ok = ringbuf_num_empty(&_discovery_ring) >= size; + if (ok) { + ringbuf_put_n(&_discovery_ring, (const uint8_t *)record, size); + } + common_hal_mcu_enable_interrupts(); + return ok; +} + +// Retrieve one fixed-size record. Runs on the VM task. +static bool _pop_record(void *record, size_t size) { + common_hal_mcu_disable_interrupts(); + bool ok = ringbuf_num_filled(&_discovery_ring) >= size; + if (ok) { + ringbuf_get_n(&_discovery_ring, (uint8_t *)record, size); + } + common_hal_mcu_enable_interrupts(); + return ok; +} + +// Reset the ring before a discovery step. Runs on the VM task. Guarded because +// a stale procedure from a previous errored, timed-out, or interrupted +// discovery may still be pushing records on the nimble_host task. +static void _reset_discovery_ring(void) { + if (_discovery_ring_buffer == NULL) { + _discovery_ring_buffer = port_malloc(DISCOVERY_RING_SIZE, false); + if (_discovery_ring_buffer == NULL) { + m_malloc_fail(DISCOVERY_RING_SIZE); + } + } + common_hal_mcu_disable_interrupts(); + ringbuf_init(&_discovery_ring, _discovery_ring_buffer, DISCOVERY_RING_SIZE); + common_hal_mcu_enable_interrupts(); +} + static int _discovered_service_cb(uint16_t conn_handle, const struct ble_gatt_error *error, const struct ble_gatt_svc *svc, void *arg) { - bleio_connection_internal_t *self = (bleio_connection_internal_t *)arg; + if (error->status != 0) { + // BLE_HS_EDONE or some error has occurred. + _set_discovery_step_status(error->status); + return 0; + } + + // Runs on the nimble_host task: stage the raw result only, never allocate. + if (!_push_record(svc, sizeof(*svc))) { + _set_discovery_step_status(BLE_HS_ENOMEM); + } + return 0; +} +static int _discovered_characteristic_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + const struct ble_gatt_chr *chr, + void *arg) { + if (error->status != 0) { + // BLE_HS_EDONE or some error has occurred. + _set_discovery_step_status(error->status); + return 0; + } + + // Runs on the nimble_host task: stage the raw result only, never allocate. + if (!_push_record(chr, sizeof(*chr))) { + _set_discovery_step_status(BLE_HS_ENOMEM); + } + return 0; +} + +static int _discovered_descriptor_cb(uint16_t conn_handle, + const struct ble_gatt_error *error, + uint16_t chr_val_handle, + const struct ble_gatt_dsc *dsc, + void *arg) { if (error->status != 0) { // BLE_HS_EDONE or some error has occurred. _set_discovery_step_status(error->status); return 0; } + // Runs on the nimble_host task: stage the raw result only, never allocate. + if (!_push_record(dsc, sizeof(*dsc))) { + _set_discovery_step_status(BLE_HS_ENOMEM); + } + return 0; +} + +// Build a Service object from a staged raw record. Runs on the VM task. +static void _build_service(void *ctx, const void *record) { + bleio_connection_internal_t *self = ctx; + const struct ble_gatt_svc *svc = record; + bleio_service_obj_t *service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type); // Initialize several fields at once. @@ -244,27 +337,58 @@ static int _discovered_service_cb(uint16_t conn_handle, mp_obj_list_append(MP_OBJ_FROM_PTR(self->remote_service_list), MP_OBJ_FROM_PTR(service)); - return 0; } -static int _discovered_characteristic_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - const struct ble_gatt_chr *chr, - void *arg) { - bleio_service_obj_t *service = (bleio_service_obj_t *)arg; - - if (error->status != 0) { - // BLE_HS_EDONE or some error has occurred. - _set_discovery_step_status(error->status); - return 0; +// Drain and build all staged records on the VM task, until the step completes +// and the ring is empty. build() is invoked for each raw record with ctx passed +// through. Returns the discovery step status. +static int _drain_records(void *ctx, size_t record_size, + void (*build)(void *ctx, const void *record)) { + const uint64_t timeout_time_ms = common_hal_time_monotonic_ms() + DISCOVERY_TIMEOUT_MS; + // Sized to the largest record type so one buffer serves every step. + union { + struct ble_gatt_svc svc; + struct ble_gatt_chr chr; + struct ble_gatt_dsc dsc; + } record; + while (true) { + if (_pop_record(&record, record_size)) { + build(ctx, &record); + continue; + } + // Ring is empty. + if (_last_discovery_status != 0) { + // On EDONE or a NimBLE error, the terminal callback has already + // run, so no more records will arrive: drain any that raced in, + // then stop. On ENOMEM (our own push failure) the procedure may + // still be running, but we are raising anyway; any later + // discovery resets the ring before reuse. + while (_pop_record(&record, record_size)) { + build(ctx, &record); + } + return _last_discovery_status; + } + if (common_hal_time_monotonic_ms() >= timeout_time_ms) { + return BLE_HS_ETIMEOUT; + } + RUN_BACKGROUND_TASKS; + if (mp_hal_is_interrupted()) { + // Return prematurely. Then the interrupt will be raised. + _set_discovery_step_status(BLE_HS_EDONE); + } } +} + +// Build a Characteristic object from a staged raw record. Runs on the VM task. +static void _build_characteristic(void *ctx, const void *record) { + bleio_service_obj_t *service = ctx; + const struct ble_gatt_chr *chr = record; bleio_characteristic_obj_t *characteristic = mp_obj_malloc(bleio_characteristic_obj_t, &bleio_characteristic_type); // Known characteristic UUID. bleio_uuid_obj_t *uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); - uuid->nimble_ble_uuid = chr->uuid; bleio_characteristic_properties_t props = @@ -288,33 +412,14 @@ static int _discovered_characteristic_cb(uint16_t conn_handle, // Set def_handle directly since it is only used in discovery. characteristic->def_handle = chr->def_handle; - #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_characteristic_cb: char handle: %d\n", characteristic->handle); - #endif - mp_obj_list_append(MP_OBJ_FROM_PTR(service->characteristic_list), MP_OBJ_FROM_PTR(characteristic)); - return 0; } -static int _discovered_descriptor_cb(uint16_t conn_handle, - const struct ble_gatt_error *error, - uint16_t chr_val_handle, - const struct ble_gatt_dsc *dsc, - void *arg) { - bleio_characteristic_obj_t *characteristic = (bleio_characteristic_obj_t *)arg; - - if (error->status != 0) { - - #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_descriptor_cb error->status: %d, handle: %d\n", - error->status, error->att_handle); - #endif - - // BLE_HS_EDONE or some error has occurred. - _set_discovery_step_status(error->status); - return 0; - } +// Build a Descriptor object from a staged raw record. Runs on the VM task. +static void _build_descriptor(void *ctx, const void *record) { + bleio_characteristic_obj_t *characteristic = ctx; + const struct ble_gatt_dsc *dsc = record; // Remember handles for certain well-known descriptors. switch (dsc->uuid.u16.value) { @@ -344,14 +449,8 @@ static int _discovered_descriptor_cb(uint16_t conn_handle, GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); descriptor->handle = dsc->handle; - #if CIRCUITPY_VERBOSE_BLE - mp_printf(&mp_plat_print, "_discovered_descriptor_cb: char handle: %d, desc handle: %d, uuid type: %d, u16 value: 0x%x\n", - characteristic->handle, descriptor->handle, dsc->uuid.u.type, dsc->uuid.u16.value); - #endif - mp_obj_list_append(MP_OBJ_FROM_PTR(characteristic->descriptor_list), MP_OBJ_FROM_PTR(descriptor)); - return 0; } static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t service_uuids_whitelist) { @@ -359,13 +458,14 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t self->remote_service_list = mp_obj_new_list(0, NULL); if (service_uuids_whitelist == mp_const_none) { - // Reset discovery status before starting callbacks + // Reset discovery status and staging ring before starting callbacks. _set_discovery_step_status(0); + _reset_discovery_ring(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_svcs(self->conn_handle, _discovered_service_cb, self)); - // Wait for _discovered_service_cb() to be called multiple times until it's done. - int status = _wait_for_discovery_step_done(); + // Drain staged services and build them on the VM task until done. + int status = _drain_records(self, sizeof(struct ble_gatt_svc), _build_service); _check_discovery_status(status); } else { mp_obj_iter_buf_t iter_buf; @@ -377,25 +477,26 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t } bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - // Reset discovery status before starting callbacks + // Reset discovery status and staging ring before starting callbacks. _set_discovery_step_status(0); + _reset_discovery_ring(); CHECK_NIMBLE_ERROR(ble_gattc_disc_svc_by_uuid(self->conn_handle, &uuid->nimble_ble_uuid.u, _discovered_service_cb, self)); - // Wait for _discovered_service_cb() to be called multiple times until it's done. - int status = _wait_for_discovery_step_done(); + // Drain staged services and build them on the VM task until done. + int status = _drain_records(self, sizeof(struct ble_gatt_svc), _build_service); _check_discovery_status(status); } } // Now discover characteristics for each discovered service. - for (size_t i = 0; i < self->remote_service_list->len; i++) { bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->remote_service_list->items[i]); - // Reset discovery status before starting callbacks + // Reset discovery status and staging ring before starting callbacks. _set_discovery_step_status(0); + _reset_discovery_ring(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_chrs(self->conn_handle, service->start_handle, @@ -403,8 +504,8 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t _discovered_characteristic_cb, service)); - // Wait for _discovered_characteristic_cb() to be called multiple times until it's done. - int status = _wait_for_discovery_step_done(); + // Drain staged characteristics and build them on the VM task until done. + int status = _drain_records(service, sizeof(struct ble_gatt_chr), _build_characteristic); _check_discovery_status(status); // Got characteristics for this service. Now discover descriptors for each characteristic. @@ -429,8 +530,9 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t continue; } - // Reset discovery status before starting callbacks + // Reset discovery status and staging ring before starting callbacks. _set_discovery_step_status(0); + _reset_discovery_ring(); // The descriptor handle inclusive range is [characteristic->handle + 1, end_handle], // but ble_gattc_disc_all_dscs() requires starting with characteristic->handle. @@ -438,8 +540,8 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t end_handle, _discovered_descriptor_cb, characteristic)); - // Wait for _discovered_descriptor_cb to be called multiple times until it's done. - status = _wait_for_discovery_step_done(); + // Drain staged descriptors and build them on the VM task until done. + status = _drain_records(characteristic, sizeof(struct ble_gatt_dsc), _build_descriptor); _check_discovery_status(status); } } From 97cf5c585580abaebadc2cefa7da1dacdb0d7ce6 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 8 Jul 2026 15:14:06 -0400 Subject: [PATCH 630/876] espressif/_bleio: guard buffer state shared with the NimBLE host task CharacteristicBuffer and PacketBuffer ringbufs are filled from the nimble_host task, which preempts the VM task at arbitrary points, but the non-atomic ringbuf operations were unguarded: the comment claiming the BLE host task "won't interrupt us" has been wrong since the code was written (the host task runs at a much higher priority on the same core). PacketBuffer's pending outgoing buffers have the same problem: write() on the VM task appends to them while queue_next_write() on the host task consumes them. Guard these operations with interrupts disabled, mirroring the nordic port's critical sections around the same code, in the same places. Co-Authored-By: Claude Fable 5 --- .../common-hal/_bleio/CharacteristicBuffer.c | 21 ++++++++++++++----- .../common-hal/_bleio/PacketBuffer.c | 20 ++++++++++++++++++ 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c b/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c index 3c0cbf323f3..2f34666420b 100644 --- a/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c +++ b/ports/espressif/common-hal/_bleio/CharacteristicBuffer.c @@ -16,12 +16,19 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/CharacteristicBuffer.h" +#include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/tick.h" #include "common-hal/_bleio/ble_events.h" +// The ringbuf is filled from the nimble_host task, which preempts the VM task +// at arbitrary points, and ringbuf operations are not atomic, so guard them +// with interrupts disabled. + +// Runs on the nimble_host task. void bleio_characteristic_buffer_extend(bleio_characteristic_buffer_obj_t *self, const uint8_t *data, size_t len) { + common_hal_mcu_disable_interrupts(); if (self->watch_for_interrupt_char) { for (uint16_t i = 0; i < len; i++) { if (data[i] == mp_interrupt_char) { @@ -34,6 +41,7 @@ void bleio_characteristic_buffer_extend(bleio_characteristic_buffer_obj_t *self, } else { ringbuf_put_n(&self->ringbuf, data, len); } + common_hal_mcu_enable_interrupts(); } void _common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, @@ -70,20 +78,23 @@ uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer } } + common_hal_mcu_disable_interrupts(); uint32_t num_bytes_read = ringbuf_get_n(&self->ringbuf, data, len); + common_hal_mcu_enable_interrupts(); return num_bytes_read; } -// NOTE: The nRF port has protection around these operations because the ringbuf -// is filled from an interrupt. On ESP the ringbuf is filled from the BLE host -// task that won't interrupt us. - uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) { - return ringbuf_num_filled(&self->ringbuf); + common_hal_mcu_disable_interrupts(); + uint32_t count = ringbuf_num_filled(&self->ringbuf); + common_hal_mcu_enable_interrupts(); + return count; } void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) { + common_hal_mcu_disable_interrupts(); ringbuf_clear(&self->ringbuf); + common_hal_mcu_enable_interrupts(); } bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { diff --git a/ports/espressif/common-hal/_bleio/PacketBuffer.c b/ports/espressif/common-hal/_bleio/PacketBuffer.c index db035157ceb..a14c627f110 100644 --- a/ports/espressif/common-hal/_bleio/PacketBuffer.c +++ b/ports/espressif/common-hal/_bleio/PacketBuffer.c @@ -15,6 +15,7 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/PacketBuffer.h" +#include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/tick.h" #include "supervisor/shared/bluetooth/serial.h" @@ -23,6 +24,11 @@ #include "host/ble_att.h" +// The ringbuf and the pending outgoing buffers are shared with the nimble_host +// task, which preempts the VM task at arbitrary points, and ringbuf operations +// are not atomic, so guard the shared accesses with interrupts disabled. + +// Runs on the nimble_host task. void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, uint16_t conn_handle, const uint8_t *data, size_t len) { if (self->conn_handle != conn_handle) { return; @@ -34,6 +40,8 @@ void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, uint16_t conn_h return; } + common_hal_mcu_disable_interrupts(); + // Make room for the new value by dropping the oldest packets first. while (ringbuf_num_empty(&self->ringbuf) < len + sizeof(uint16_t)) { uint16_t packet_length; @@ -45,6 +53,8 @@ void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, uint16_t conn_h } ringbuf_put_n(&self->ringbuf, (uint8_t *)&len, sizeof(uint16_t)); ringbuf_put_n(&self->ringbuf, data, len); + + common_hal_mcu_enable_interrupts(); } static int packet_buffer_on_ble_client_evt(struct ble_gap_event *event, void *param); @@ -264,6 +274,8 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self return 0; } + common_hal_mcu_disable_interrupts(); + // Get packet length, which is in first two bytes of packet. uint16_t packet_length; ringbuf_get_n(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); @@ -282,6 +294,8 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self ret = packet_length; } + common_hal_mcu_enable_interrupts(); + return ret; } @@ -324,6 +338,10 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, c size_t num_bytes_written = 0; + // The nimble_host task may modify pending_size, pending_index, and + // packet_queued via queue_next_write(), so guard the append. + common_hal_mcu_disable_interrupts(); + uint32_t *pending = self->outgoing[self->pending_index]; if (self->pending_size == 0) { @@ -335,6 +353,8 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, c self->pending_size += len; num_bytes_written += len; + common_hal_mcu_enable_interrupts(); + // If no writes are queued then sneak in this data. if (!self->packet_queued) { // This will queue up the packet even if it can't send immediately. From 8eb5e6f958f0688f99bb988a6f39e4d4496dc6da Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 8 Jul 2026 15:55:38 -0400 Subject: [PATCH 631/876] espressif/_bleio: restore CIRCUITPY_VERBOSE_BLE discovery prints Restore the verbose prints dropped when discovery object construction moved off the NimBLE host task, and add matching error prints to all three discovery callbacks for consistency (only the descriptor callback had one before). The object prints now live in _build_characteristic() and _build_descriptor(), which run on the VM task. Also print the step status in _check_discovery_status(), which covers the timeout and ring-full errors that never pass through a callback. Co-Authored-By: Claude Fable 5 --- .../espressif/common-hal/_bleio/Connection.c | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 5236ee6e6e7..131a89bc9ee 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -193,6 +193,10 @@ static void _set_discovery_step_status(int status) { } static void _check_discovery_status(int status) { + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "discovery step status: %d\n", status); + #endif + if (status == BLE_HS_EDONE) { return; } @@ -268,6 +272,11 @@ static int _discovered_service_cb(uint16_t conn_handle, const struct ble_gatt_svc *svc, void *arg) { if (error->status != 0) { + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_service_cb error->status: %d, handle: %d\n", + error->status, error->att_handle); + #endif + // BLE_HS_EDONE or some error has occurred. _set_discovery_step_status(error->status); return 0; @@ -285,6 +294,11 @@ static int _discovered_characteristic_cb(uint16_t conn_handle, const struct ble_gatt_chr *chr, void *arg) { if (error->status != 0) { + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_characteristic_cb error->status: %d, handle: %d\n", + error->status, error->att_handle); + #endif + // BLE_HS_EDONE or some error has occurred. _set_discovery_step_status(error->status); return 0; @@ -303,6 +317,11 @@ static int _discovered_descriptor_cb(uint16_t conn_handle, const struct ble_gatt_dsc *dsc, void *arg) { if (error->status != 0) { + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_discovered_descriptor_cb error->status: %d, handle: %d\n", + error->status, error->att_handle); + #endif + // BLE_HS_EDONE or some error has occurred. _set_discovery_step_status(error->status); return 0; @@ -412,6 +431,10 @@ static void _build_characteristic(void *ctx, const void *record) { // Set def_handle directly since it is only used in discovery. characteristic->def_handle = chr->def_handle; + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_build_characteristic: char handle: %d\n", characteristic->handle); + #endif + mp_obj_list_append(MP_OBJ_FROM_PTR(service->characteristic_list), MP_OBJ_FROM_PTR(characteristic)); } @@ -449,6 +472,11 @@ static void _build_descriptor(void *ctx, const void *record) { GATT_MAX_DATA_LENGTH, false, mp_const_empty_bytes); descriptor->handle = dsc->handle; + #if CIRCUITPY_VERBOSE_BLE + mp_printf(&mp_plat_print, "_build_descriptor: char handle: %d, desc handle: %d, uuid type: %d, u16 value: 0x%x\n", + characteristic->handle, descriptor->handle, dsc->uuid.u.type, dsc->uuid.u16.value); + #endif + mp_obj_list_append(MP_OBJ_FROM_PTR(characteristic->descriptor_list), MP_OBJ_FROM_PTR(descriptor)); } From b531a07e0f1c6540937b3a8609e639af7fefa512 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Jul 2026 10:23:49 -0500 Subject: [PATCH 632/876] audiowriter module --- locale/circuitpython.pot | 9 + main.c | 8 + ports/espressif/mpconfigport.mk | 1 + ports/raspberrypi/mpconfigport.mk | 1 + py/circuitpy_defns.mk | 5 + py/circuitpy_mpconfig.mk | 3 + shared-bindings/audiowriter/AudioWriter.c | 168 +++++++++ shared-bindings/audiowriter/AudioWriter.h | 23 ++ shared-bindings/audiowriter/__init__.c | 35 ++ shared-bindings/audiowriter/__init__.h | 7 + shared-module/audiowriter/AudioWriter.c | 403 ++++++++++++++++++++++ shared-module/audiowriter/AudioWriter.h | 67 ++++ shared-module/audiowriter/__init__.c | 5 + supervisor/shared/tick.c | 8 + 14 files changed, 743 insertions(+) create mode 100644 shared-bindings/audiowriter/AudioWriter.c create mode 100644 shared-bindings/audiowriter/AudioWriter.h create mode 100644 shared-bindings/audiowriter/__init__.c create mode 100644 shared-bindings/audiowriter/__init__.h create mode 100644 shared-module/audiowriter/AudioWriter.c create mode 100644 shared-module/audiowriter/AudioWriter.h create mode 100644 shared-module/audiowriter/__init__.c diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index dcf10e4276f..b3ce45404c9 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -587,6 +587,7 @@ msgid "Already have all-matches listener" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiowriter/AudioWriter.c msgid "Already in progress" msgstr "" @@ -1738,6 +1739,10 @@ msgstr "" msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" +#: shared-module/audiowriter/AudioWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" + #: ports/espressif/common-hal/wifi/__init__.c #: ports/raspberrypi/common-hal/wifi/__init__.c msgid "Only IPv4 addresses supported" @@ -2789,6 +2794,10 @@ msgstr "" msgid "buffer too small for requested bytes" msgstr "" +#: shared-module/audiowriter/AudioWriter.c +msgid "buffer_size too small for source" +msgstr "" + #: py/emitbc.c msgid "bytecode overflow" msgstr "" diff --git a/main.c b/main.c index ff5238d0c53..cfd6d140cea 100644 --- a/main.c +++ b/main.c @@ -84,6 +84,10 @@ #include "shared-module/keypad/__init__.h" #endif +#if CIRCUITPY_AUDIOWRITER +#include "shared-module/audiowriter/AudioWriter.h" +#endif + #if CIRCUITPY_MEMORYMONITOR #include "shared-module/memorymonitor/__init__.h" #endif @@ -396,6 +400,10 @@ static void cleanup_after_vm(mp_obj_t exception) { keypad_reset(); #endif + #if CIRCUITPY_AUDIOWRITER + audiowriter_reset(); + #endif + // Close user-initiated sockets. #if CIRCUITPY_SOCKETPOOL socketpool_user_reset(); diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 0b027333b97..57cef1917ad 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -336,6 +336,7 @@ CIRCUITPY_MIPIDSI = 1 else ifeq ($(IDF_TARGET),esp32s2) # Modules CIRCUITPY_AUDIOIO ?= 1 +CIRCUITPY_AUDIOWRITER ?= 1 # No I2S peripheral PDM-to-PCM hardware support CIRCUITPY_AUDIOBUSIO_PDMIN = 0 diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index b4d1ed99696..1b2d276145f 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -13,6 +13,7 @@ CIRCUITPY_FULL_BUILD ?= 1 CIRCUITPY_AUDIOMP3 ?= 1 CIRCUITPY_AUDIOSPEED ?= 1 CIRCUITPY_AUDIOEFFECTS ?= 1 +CIRCUITPY_AUDIOWRITER ?= 1 CIRCUITPY_BITOPS ?= 1 CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 4c91ed102c2..453328861e7 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -152,6 +152,9 @@ endif ifeq ($(CIRCUITPY_AUDIOSPEED),1) SRC_PATTERNS += audiospeed/% endif +ifeq ($(CIRCUITPY_AUDIOWRITER),1) +SRC_PATTERNS += audiowriter/% +endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% endif @@ -718,6 +721,8 @@ SRC_SHARED_MODULE_ALL = \ audiofilters/__init__.c \ audiofreeverb/__init__.c \ audiofreeverb/Freeverb.c \ + audiowriter/AudioWriter.c \ + audiowriter/__init__.c \ audioio/__init__.c \ audiomixer/Mixer.c \ audiomixer/MixerVoice.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index ed0f5e5f1f2..d9b2d35dd05 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -174,6 +174,9 @@ CFLAGS += -DCIRCUITPY_AUDIOFILTERS=$(CIRCUITPY_AUDIOFILTERS) CIRCUITPY_AUDIOFREEVERB ?= $(CIRCUITPY_AUDIOEFFECTS) CFLAGS += -DCIRCUITPY_AUDIOFREEVERB=$(CIRCUITPY_AUDIOFREEVERB) +CIRCUITPY_AUDIOWRITER ?= 0 +CFLAGS += -DCIRCUITPY_AUDIOWRITER=$(CIRCUITPY_AUDIOWRITER) + CIRCUITPY_AURORA_EPAPER ?= 0 CFLAGS += -DCIRCUITPY_AURORA_EPAPER=$(CIRCUITPY_AURORA_EPAPER) diff --git a/shared-bindings/audiowriter/AudioWriter.c b/shared-bindings/audiowriter/AudioWriter.c new file mode 100644 index 00000000000..0751d3a3c21 --- /dev/null +++ b/shared-bindings/audiowriter/AudioWriter.c @@ -0,0 +1,168 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared/runtime/context_manager_helpers.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/audiowriter/AudioWriter.h" +#include "shared-bindings/util.h" + +// ~1 s of 16 kHz mono 16-bit PCM. Sized to absorb a worst-case SD-write stall. +#define AUDIOWRITER_DEFAULT_BUFFER_SIZE (32 * 1024) + +//| class AudioWriter: +//| """Streams an audio source to a ``.wav`` file in the background. +//| +//| ``AudioWriter`` is the inverse of `audiocore.WaveFile`: rather than being +//| an audio *source* played by an `audioio.AudioOut`, it is a *sink* that +//| drives an audio source (a microphone, or an ``audiofilters``/ +//| ``audiodelays``/``audiofreeverb``/``audiospeed`` effect chain) and writes +//| the resulting PCM to a file as a WAV. +//| +//| Recording runs on a background pump paced to the source's real-time rate, +//| so it does not block and does not require a Python read loop (which is +//| what makes hand-rolled recorders choppy).""" +//| +//| def __init__(self, file: typing.BinaryIO, *, buffer_size: int = 32768) -> None: +//| """Create an ``AudioWriter`` that writes to ``file``. +//| +//| :param typing.BinaryIO file: An already-open writable binary stream +//| (a file opened in ``"wb"`` mode, or an `io.BytesIO`). The stream must +//| support seeking so the WAV header sizes can be patched when recording +//| stops. ``AudioWriter`` does not close it; the caller owns it. +//| :param int buffer_size: Size in bytes of the internal RAM ring that +//| decouples file-write latency from the source. Larger values tolerate +//| longer write stalls (e.g. a slow SD card) at the cost of RAM. +//| +//| The audio format (sample rate, channel count, bit depth) is taken from +//| the source at `play()` time, so there are no format arguments here. +//| +//| Recording a microphone through an effect chain to SD:: +//| +//| import audiowriter, board +//| # ``amp`` is the top of an effect chain pulling from a mic +//| with open("/sd/recording.wav", "wb") as f: +//| writer = audiowriter.AudioWriter(f) +//| writer.play(amp) +//| time.sleep(5) +//| writer.stop() +//| """ +//| ... +//| +static mp_obj_t audiowriter_audiowriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_file, ARG_buffer_size }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = AUDIOWRITER_DEFAULT_BUFFER_SIZE} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // A buffer smaller than one source buffer is useless; require a sane floor. + mp_int_t buffer_size = mp_arg_validate_int_min(args[ARG_buffer_size].u_int, 512, MP_QSTR_buffer_size); + + audiowriter_audiowriter_obj_t *self = mp_obj_malloc(audiowriter_audiowriter_obj_t, &audiowriter_audiowriter_type); + common_hal_audiowriter_audiowriter_construct(self, args[ARG_file].u_obj, (uint32_t)buffer_size); + + return MP_OBJ_FROM_PTR(self); +} + +static void check_for_deinit(audiowriter_audiowriter_obj_t *self) { + if (common_hal_audiowriter_audiowriter_deinited(self)) { + raise_deinited_error(); + } +} + +//| def deinit(self) -> None: +//| """Stops recording (patching the WAV header) and releases resources.""" +//| ... +//| +static mp_obj_t audiowriter_audiowriter_deinit(mp_obj_t self_in) { + audiowriter_audiowriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiowriter_audiowriter_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiowriter_audiowriter_deinit_obj, audiowriter_audiowriter_deinit); + +//| def __enter__(self) -> AudioWriter: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +// Provided by context manager helper. + +//| def play(self, sample: circuitpython_typing.AudioSample) -> None: +//| """Begin recording ``sample`` to the file. Does not block. +//| +//| Writes a WAV header (in the format of ``sample``) and starts the +//| background pump. ``sample`` must be an 8-bit or 16-bit mono or stereo +//| audio source. Use `playing` to tell when a finite source has finished, +//| or call `stop()` to end recording of a continuous source (e.g. a mic).""" +//| ... +//| +static mp_obj_t audiowriter_audiowriter_obj_play(mp_obj_t self_in, mp_obj_t sample_in) { + audiowriter_audiowriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_audiowriter_audiowriter_play(self, sample_in); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(audiowriter_audiowriter_play_obj, audiowriter_audiowriter_obj_play); + +//| def stop(self) -> None: +//| """Stop recording, flush the RAM ring to the file, and patch the WAV +//| header sizes. The file is left open for the caller to close.""" +//| ... +//| +static mp_obj_t audiowriter_audiowriter_obj_stop(mp_obj_t self_in) { + audiowriter_audiowriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + common_hal_audiowriter_audiowriter_stop(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiowriter_audiowriter_stop_obj, audiowriter_audiowriter_obj_stop); + +//| playing: bool +//| """True while recording is in progress. Becomes False on its own when a +//| finite source finishes, or after `stop()`. (read-only)""" +//| +static mp_obj_t audiowriter_audiowriter_obj_get_playing(mp_obj_t self_in) { + audiowriter_audiowriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiowriter_audiowriter_get_playing(self)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiowriter_audiowriter_get_playing_obj, audiowriter_audiowriter_obj_get_playing); + +MP_PROPERTY_GETTER(audiowriter_audiowriter_playing_obj, + (mp_obj_t)&audiowriter_audiowriter_get_playing_obj); + +static const mp_rom_map_elem_t audiowriter_audiowriter_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiowriter_audiowriter_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiowriter_audiowriter_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiowriter_audiowriter_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiowriter_audiowriter_playing_obj) }, +}; +static MP_DEFINE_CONST_DICT(audiowriter_audiowriter_locals_dict, audiowriter_audiowriter_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + audiowriter_audiowriter_type, + MP_QSTR_AudioWriter, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiowriter_audiowriter_make_new, + locals_dict, &audiowriter_audiowriter_locals_dict + ); diff --git a/shared-bindings/audiowriter/AudioWriter.h b/shared-bindings/audiowriter/AudioWriter.h new file mode 100644 index 00000000000..f39e0fcfc88 --- /dev/null +++ b/shared-bindings/audiowriter/AudioWriter.h @@ -0,0 +1,23 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "shared-module/audiowriter/AudioWriter.h" + +extern const mp_obj_type_t audiowriter_audiowriter_type; + +void common_hal_audiowriter_audiowriter_construct(audiowriter_audiowriter_obj_t *self, + mp_obj_t file, uint32_t buffer_size); + +void common_hal_audiowriter_audiowriter_deinit(audiowriter_audiowriter_obj_t *self); +bool common_hal_audiowriter_audiowriter_deinited(audiowriter_audiowriter_obj_t *self); + +void common_hal_audiowriter_audiowriter_play(audiowriter_audiowriter_obj_t *self, mp_obj_t sample); +void common_hal_audiowriter_audiowriter_stop(audiowriter_audiowriter_obj_t *self); +bool common_hal_audiowriter_audiowriter_get_playing(audiowriter_audiowriter_obj_t *self); diff --git a/shared-bindings/audiowriter/__init__.c b/shared-bindings/audiowriter/__init__.c new file mode 100644 index 00000000000..2cf88e76076 --- /dev/null +++ b/shared-bindings/audiowriter/__init__.c @@ -0,0 +1,35 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/audiowriter/__init__.h" +#include "shared-bindings/audiowriter/AudioWriter.h" + +//| """Support for streaming audio to a WAV file +//| +//| The `audiowriter` module contains `AudioWriter`, a *sink* that records an +//| audio source (a microphone or an effect chain) to a ``.wav`` file in the +//| background -- the inverse of `audiocore.WaveFile`. +//| +//| """ + +static const mp_rom_map_elem_t audiowriter_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiowriter) }, + { MP_ROM_QSTR(MP_QSTR_AudioWriter), MP_ROM_PTR(&audiowriter_audiowriter_type) }, +}; + +static MP_DEFINE_CONST_DICT(audiowriter_module_globals, audiowriter_module_globals_table); + +const mp_obj_module_t audiowriter_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&audiowriter_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_audiowriter, audiowriter_module); diff --git a/shared-bindings/audiowriter/__init__.h b/shared-bindings/audiowriter/__init__.h new file mode 100644 index 00000000000..3ddd6344a68 --- /dev/null +++ b/shared-bindings/audiowriter/__init__.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once diff --git a/shared-module/audiowriter/AudioWriter.c b/shared-module/audiowriter/AudioWriter.c new file mode 100644 index 00000000000..01111699669 --- /dev/null +++ b/shared-module/audiowriter/AudioWriter.c @@ -0,0 +1,403 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/audiowriter/AudioWriter.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiocore/__init__.h" + +#include + +#include "py/mperrno.h" +#include "py/runtime.h" +#include "py/stream.h" + +#include "supervisor/background_callback.h" +#include "supervisor/shared/tick.h" + +// --------------------------------------------------------------------------- +// Little-endian header helpers +// --------------------------------------------------------------------------- + +static void put_u16le(uint8_t *p, uint16_t v) { + p[0] = (uint8_t)v; + p[1] = (uint8_t)(v >> 8); +} + +static void put_u32le(uint8_t *p, uint32_t v) { + p[0] = (uint8_t)v; + p[1] = (uint8_t)(v >> 8); + p[2] = (uint8_t)(v >> 16); + p[3] = (uint8_t)(v >> 24); +} + +// --------------------------------------------------------------------------- +// Active-writer registry, walked once per supervisor tick. +// +// The list head lives in MP_STATE_VM (see MP_REGISTER_ROOT_POINTER below) so +// that (a) active writers and their reg_next chain are GC-rooted while +// recording, and (b) the list is wiped automatically when the VM heap is +// recreated on soft reset. +// --------------------------------------------------------------------------- + +#define REGISTRY_HEAD ((audiowriter_audiowriter_obj_t *)MP_STATE_VM(audiowriter_linked_list)) + +// Add self to the registry. Called from Python (play()) context, so it must +// guard against a background tick walking the list mid-mutation. +static void audiowriter_register(audiowriter_audiowriter_obj_t *self) { + background_callback_prevent(); + // Avoid double-linking if already present. + bool present = false; + for (audiowriter_audiowriter_obj_t *w = REGISTRY_HEAD; w != NULL; w = w->reg_next) { + if (w == self) { + present = true; + break; + } + } + if (!present) { + self->reg_next = REGISTRY_HEAD; + MP_STATE_VM(audiowriter_linked_list) = self; + } + background_callback_allow(); +} + +// Remove self from the registry. Callers must ensure no background tick is +// walking the list concurrently: either they are the background tick itself +// (single-threaded, so safe), or they wrap the call in prevent/allow. +static void audiowriter_unregister(audiowriter_audiowriter_obj_t *self) { + audiowriter_audiowriter_obj_t **pp = (audiowriter_audiowriter_obj_t **)&MP_STATE_VM(audiowriter_linked_list); + while (*pp != NULL) { + if (*pp == self) { + *pp = self->reg_next; + self->reg_next = NULL; + return; + } + pp = &(*pp)->reg_next; + } +} + +// --------------------------------------------------------------------------- +// RAM ring +// --------------------------------------------------------------------------- + +// Copy len bytes from src into the ring. The caller guarantees there is room. +// 8-bit signed PCM is flipped to unsigned to match the WAV convention. +static void audiowriter_ring_write(audiowriter_audiowriter_obj_t *self, const uint8_t *src, uint32_t len) { + bool flip = (self->bits_per_sample == 8 && self->samples_signed); + uint32_t i = 0; + while (i < len) { + uint32_t span = self->ring_size - self->ring_head; + if (span > (len - i)) { + span = len - i; + } + if (flip) { + for (uint32_t j = 0; j < span; j++) { + self->ring[self->ring_head + j] = src[i + j] ^ 0x80; + } + } else { + memcpy(self->ring + self->ring_head, src + i, span); + } + self->ring_head += span; + if (self->ring_head == self->ring_size) { + self->ring_head = 0; + } + i += span; + } + self->ring_count += len; +} + +// Drain the ring to the file. Returns false on a write error. Non-raising: +// safe to call from background-task context. +static bool audiowriter_flush(audiowriter_audiowriter_obj_t *self) { + while (self->ring_count > 0) { + uint32_t span = self->ring_size - self->ring_tail; + if (span > self->ring_count) { + span = self->ring_count; + } + int err = 0; + mp_uint_t wrote = mp_stream_write_exactly(self->file, self->ring + self->ring_tail, span, &err); + if (err != 0 || wrote != span) { + return false; + } + self->ring_tail += span; + if (self->ring_tail == self->ring_size) { + self->ring_tail = 0; + } + self->ring_count -= span; + self->data_bytes += span; + } + return true; +} + +// --------------------------------------------------------------------------- +// Header patching + finalize +// --------------------------------------------------------------------------- + +static void audiowriter_patch_header(audiowriter_audiowriter_obj_t *self) { + uint8_t sz[4]; + int err = 0; + + // RIFF chunk size lives at header_offset + 4. + put_u32le(sz, 36 + self->data_bytes); + if (mp_stream_seek(self->file, self->header_offset + 4, MP_SEEK_SET, &err) == (mp_off_t)-1) { + return; + } + mp_stream_write_exactly(self->file, sz, 4, &err); + + // data chunk size lives at header_offset + 40. + put_u32le(sz, self->data_bytes); + if (mp_stream_seek(self->file, self->header_offset + 40, MP_SEEK_SET, &err) == (mp_off_t)-1) { + return; + } + mp_stream_write_exactly(self->file, sz, 4, &err); + + // Leave the cursor at the end of the PCM so the caller can keep appending + // or simply close the file. + mp_stream_seek(self->file, self->header_offset + 44 + self->data_bytes, MP_SEEK_SET, &err); +} + +// Stop pumping, drain, patch the header, and release the source. Idempotent: +// only the first call (while playing) does work. Non-raising. +static void audiowriter_finalize(audiowriter_audiowriter_obj_t *self) { + if (!self->playing) { + return; + } + // Stop the pump first so a background tick can't re-enter us. + self->playing = false; + + audiowriter_flush(self); + audiowriter_patch_header(self); + + supervisor_disable_tick(); + audiowriter_unregister(self); + self->sample = MP_OBJ_NULL; +} + +// --------------------------------------------------------------------------- +// The pump: one real-time-paced step per supervisor tick +// --------------------------------------------------------------------------- + +static void audiowriter_pump(audiowriter_audiowriter_obj_t *self) { + if (!self->playing) { + return; + } + + // The pull granularity through the chain is one source buffer, so we pace + // in whole-buffer units. + int64_t frames_per_pull = (int64_t)(self->source_max_buffer / self->bytes_per_frame); + if (frames_per_pull < 1) { + frames_per_pull = 1; + } + + // Accrue a real-time sample budget from elapsed ticks. + uint64_t now = supervisor_ticks_ms64(); + uint64_t elapsed = now - self->last_tick_ms; + self->last_tick_ms = now; + // Ignore long gaps (GC pause, SD stall) so we don't try to catch up an + // unbounded backlog all at once. + if (elapsed > 100) { + elapsed = 100; + } + self->budget_frames += (int64_t)((elapsed * self->sample_rate) / 1000); + // Never bank more than a single buffer of catch-up. For a LIVE source the + // captured audio sits in the source's own bounded ring; once we fall more + // than that behind, the surplus is already gone, so a large banked budget + // cannot recover it -- it would only burst-drain the source on consecutive + // ticks and then silence-pad, stretching one stall into a long glitch. + // Capping at one buffer yields at most one brief discontinuity per stall. + if (self->budget_frames > frames_per_pull) { + self->budget_frames = frames_per_pull; + } + + // Pull one buffer only once a full buffer of real time has elapsed: strict + // real-time pacing so we never pull ahead of a live source (which would + // only hand back silence). Also require room for a full source buffer. + if (!self->source_done && self->budget_frames >= frames_per_pull && + (self->ring_size - self->ring_count) >= self->source_max_buffer) { + uint8_t *buf = NULL; + uint32_t len = 0; + audioio_get_buffer_result_t res = + audiosample_get_buffer(self->sample, false, 0, &buf, &len); + if (res == GET_BUFFER_ERROR) { + self->source_done = true; + } else { + if (len > 0 && buf != NULL) { + // Defend against a source that hands back more than it advertised. + if (len > self->source_max_buffer) { + len = self->source_max_buffer; + } + audiowriter_ring_write(self, buf, len); + self->budget_frames -= (int64_t)(len / self->bytes_per_frame); + } + if (res == GET_BUFFER_DONE) { + self->source_done = true; + } + } + } + + if (!audiowriter_flush(self)) { + // File write failed; give up gracefully rather than spin. + self->source_done = true; + } + + if (self->source_done && self->ring_count == 0) { + audiowriter_finalize(self); + } +} + +void audiowriter_background(void) { + audiowriter_audiowriter_obj_t *self = REGISTRY_HEAD; + while (self != NULL) { + // Capture next before pumping: pump() may finalize self, which unlinks + // it from the registry (but leaves our saved next pointer valid). + audiowriter_audiowriter_obj_t *next = self->reg_next; + audiowriter_pump(self); + self = next; + } +} + +// Called during soft reset (VM teardown). Any writer still active is abandoned: +// we don't try to touch its file (it may already be gone), we just balance the +// tick-enable count and drop it from the list. +void audiowriter_reset(void) { + audiowriter_audiowriter_obj_t *self = REGISTRY_HEAD; + while (self != NULL) { + audiowriter_audiowriter_obj_t *next = self->reg_next; + if (self->playing) { + self->playing = false; + supervisor_disable_tick(); + } + self->reg_next = NULL; + self = next; + } + MP_STATE_VM(audiowriter_linked_list) = NULL; +} + +// --------------------------------------------------------------------------- +// common-hal surface +// --------------------------------------------------------------------------- + +void common_hal_audiowriter_audiowriter_construct(audiowriter_audiowriter_obj_t *self, + mp_obj_t file, uint32_t buffer_size) { + // The file must be a writable, seekable binary stream (a file or BytesIO). + mp_get_stream_raise(file, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + + self->file = file; + self->sample = MP_OBJ_NULL; + self->ring_size = buffer_size; + self->ring = m_malloc(buffer_size); + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + self->playing = false; + self->source_done = false; + self->reg_next = NULL; +} + +bool common_hal_audiowriter_audiowriter_deinited(audiowriter_audiowriter_obj_t *self) { + return self->ring == NULL; +} + +void common_hal_audiowriter_audiowriter_deinit(audiowriter_audiowriter_obj_t *self) { + if (self->playing) { + common_hal_audiowriter_audiowriter_stop(self); + } + self->ring = NULL; + self->file = MP_OBJ_NULL; + self->sample = MP_OBJ_NULL; +} + +void common_hal_audiowriter_audiowriter_play(audiowriter_audiowriter_obj_t *self, mp_obj_t sample_obj) { + if (self->playing) { + mp_raise_RuntimeError(MP_ERROR_TEXT("Already in progress")); + } + + audiosample_base_t *sample = audiosample_check(sample_obj); + uint32_t rate = audiosample_get_sample_rate(sample); + uint8_t channels = audiosample_get_channel_count(sample); + uint8_t bits = audiosample_get_bits_per_sample(sample); + bool single_buffer, samples_signed; + uint32_t max_buffer_length; + uint8_t spacing; + audiosample_get_buffer_structure(sample, false, &single_buffer, &samples_signed, + &max_buffer_length, &spacing); + + if ((bits != 8 && bits != 16) || channels < 1 || channels > 2) { + mp_raise_ValueError(MP_ERROR_TEXT("Only 8/16-bit mono/stereo is supported")); + } + if (max_buffer_length == 0 || self->ring_size < max_buffer_length) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer_size too small for source")); + } + + self->sample_rate = rate; + self->channel_count = channels; + self->bits_per_sample = bits; + self->samples_signed = samples_signed; + self->bytes_per_frame = (uint8_t)(channels * (bits / 8)); + self->source_max_buffer = max_buffer_length; + + // Remember where the header starts so stop() can patch its size fields, + // then write a placeholder header with zeroed sizes. + int err = 0; + mp_off_t off = mp_stream_seek(self->file, 0, MP_SEEK_CUR, &err); + if (off == (mp_off_t)-1) { + mp_raise_OSError(err ? err : MP_EIO); + } + self->header_offset = (uint32_t)off; + + uint32_t block_align = self->bytes_per_frame; + uint32_t byte_rate = rate * block_align; + uint8_t hdr[44]; + memcpy(hdr + 0, "RIFF", 4); + put_u32le(hdr + 4, 36); // RIFF size (patched at stop) + memcpy(hdr + 8, "WAVE", 4); + memcpy(hdr + 12, "fmt ", 4); + put_u32le(hdr + 16, 16); // fmt chunk size + put_u16le(hdr + 20, 1); // PCM + put_u16le(hdr + 22, channels); + put_u32le(hdr + 24, rate); + put_u32le(hdr + 28, byte_rate); + put_u16le(hdr + 32, (uint16_t)block_align); + put_u16le(hdr + 34, bits); + memcpy(hdr + 36, "data", 4); + put_u32le(hdr + 40, 0); // data size (patched at stop) + + err = 0; + mp_uint_t wrote = mp_stream_write_exactly(self->file, hdr, sizeof(hdr), &err); + if (err != 0 || wrote != sizeof(hdr)) { + mp_raise_OSError(err ? err : MP_EIO); + } + + audiosample_reset_buffer(sample_obj, false, 0); + + self->sample = sample_obj; + self->ring_head = 0; + self->ring_tail = 0; + self->ring_count = 0; + self->budget_frames = 0; + self->data_bytes = 0; + self->source_done = false; + self->last_tick_ms = supervisor_ticks_ms64(); + self->playing = true; + + audiowriter_register(self); + supervisor_enable_tick(); +} + +void common_hal_audiowriter_audiowriter_stop(audiowriter_audiowriter_obj_t *self) { + if (!self->playing) { + return; + } + // Keep the background pump out while we finalize from Python context. + background_callback_prevent(); + audiowriter_finalize(self); + background_callback_allow(); +} + +bool common_hal_audiowriter_audiowriter_get_playing(audiowriter_audiowriter_obj_t *self) { + return self->playing; +} + +MP_REGISTER_ROOT_POINTER(mp_obj_t audiowriter_linked_list); diff --git a/shared-module/audiowriter/AudioWriter.h b/shared-module/audiowriter/AudioWriter.h new file mode 100644 index 00000000000..4b1874167f5 --- /dev/null +++ b/shared-module/audiowriter/AudioWriter.h @@ -0,0 +1,67 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include + +#include "py/obj.h" + +// A streaming WAV *sink*: it consumes an audiosample source (a mic or an effect +// chain) and writes the resulting PCM to a file. Unlike WaveFile it is NOT an +// audiosample (it has no audiosample_base_t) -- it is the thing that drives a +// source, playing the role an AudioOut would. +typedef struct _audiowriter_audiowriter_obj_t { + mp_obj_base_t base; + + // Output stream (anything with write + MP_STREAM_SEEK ioctl: a file or a + // BytesIO). Held so it stays referenced while recording. + mp_obj_t file; + // The source being recorded. Only valid (and referenced) while playing. + mp_obj_t sample; + + // Format, captured from the source at play() time. AudioWriter is the + // format authority for the WAV header. + uint32_t sample_rate; + uint8_t channel_count; + uint8_t bits_per_sample; + bool samples_signed; + uint8_t bytes_per_frame; // channel_count * bits_per_sample / 8 + uint32_t source_max_buffer; // largest buffer the source can hand back, bytes + + // RAM ring that decouples SD-write latency from the source. Written by the + // pump, drained to the file by the pump. Only touched from background-task + // context (never an ISR), so no locking is needed. + uint8_t *ring; + uint32_t ring_size; // capacity in bytes + uint32_t ring_head; // write cursor + uint32_t ring_tail; // read cursor + uint32_t ring_count; // bytes currently buffered + + // Real-time pacing: budget accrues sample_rate frames per second of elapsed + // supervisor ticks; a buffer is pulled only when budget is positive. + int64_t budget_frames; + uint64_t last_tick_ms; + + // Absolute file offset of the RIFF header start, so stop() can seek back and + // patch the two size fields once the final length is known. + uint32_t header_offset; + uint32_t data_bytes; // total PCM bytes handed to the file + + bool playing; + bool source_done; // source returned DONE/ERROR; drain then finalize + + // Intrusive linked list of active writers, walked once per supervisor tick. + struct _audiowriter_audiowriter_obj_t *reg_next; +} audiowriter_audiowriter_obj_t; + +// Called once per supervisor tick (from supervisor_background_tick), in +// background-task context. Pumps every active writer. +void audiowriter_background(void); + +// Called during soft reset to abandon any writer left recording. +void audiowriter_reset(void); diff --git a/shared-module/audiowriter/__init__.c b/shared-module/audiowriter/__init__.c new file mode 100644 index 00000000000..6a919f9fcbf --- /dev/null +++ b/shared-module/audiowriter/__init__.c @@ -0,0 +1,5 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// +// SPDX-License-Identifier: MIT diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c index 346ef9a93c4..a224de14720 100644 --- a/supervisor/shared/tick.c +++ b/supervisor/shared/tick.c @@ -27,6 +27,10 @@ #include "shared-module/keypad/__init__.h" #endif +#if CIRCUITPY_AUDIOWRITER +#include "shared-module/audiowriter/AudioWriter.h" +#endif + #include "shared-bindings/microcontroller/__init__.h" #if CIRCUITPY_WATCHDOG @@ -59,6 +63,10 @@ static void supervisor_background_tick(void *unused) { filesystem_background(); + #if CIRCUITPY_AUDIOWRITER + audiowriter_background(); + #endif + port_background_tick(); assert_heap_ok(); From dc6db28b7e5238a043b8f3911e401ed5aabb4382 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Jul 2026 12:47:27 -0500 Subject: [PATCH 633/876] cleanup docstrings, example, and comments --- shared-bindings/audiowriter/AudioWriter.c | 35 ++++++++++++++++------- shared-bindings/audiowriter/AudioWriter.h | 2 +- shared-bindings/audiowriter/__init__.c | 10 ++----- shared-bindings/audiowriter/__init__.h | 2 +- shared-module/audiowriter/AudioWriter.c | 2 +- shared-module/audiowriter/AudioWriter.h | 10 +++---- shared-module/audiowriter/__init__.c | 2 +- 7 files changed, 35 insertions(+), 28 deletions(-) diff --git a/shared-bindings/audiowriter/AudioWriter.c b/shared-bindings/audiowriter/AudioWriter.c index 0751d3a3c21..d6ad33f1a54 100644 --- a/shared-bindings/audiowriter/AudioWriter.c +++ b/shared-bindings/audiowriter/AudioWriter.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -20,13 +20,12 @@ //| //| ``AudioWriter`` is the inverse of `audiocore.WaveFile`: rather than being //| an audio *source* played by an `audioio.AudioOut`, it is a *sink* that -//| drives an audio source (a microphone, or an ``audiofilters``/ +//| drives an audio source (a microphone, ``synthio``, or an ``audiofilters``/ //| ``audiodelays``/``audiofreeverb``/``audiospeed`` effect chain) and writes //| the resulting PCM to a file as a WAV. //| //| Recording runs on a background pump paced to the source's real-time rate, -//| so it does not block and does not require a Python read loop (which is -//| what makes hand-rolled recorders choppy).""" +//| so it does not block and does not require a Python read loop.""" //| //| def __init__(self, file: typing.BinaryIO, *, buffer_size: int = 32768) -> None: //| """Create an ``AudioWriter`` that writes to ``file``. @@ -42,15 +41,29 @@ //| The audio format (sample rate, channel count, bit depth) is taken from //| the source at `play()` time, so there are no format arguments here. //| -//| Recording a microphone through an effect chain to SD:: +//| Recording synthio to SD:: //| -//| import audiowriter, board -//| # ``amp`` is the top of an effect chain pulling from a mic -//| with open("/sd/recording.wav", "wb") as f: -//| writer = audiowriter.AudioWriter(f) -//| writer.play(amp) -//| time.sleep(5) +//| import time +//| import synthio +//| from audiowriter import AudioWriter +//| import storage +//| +//| SAMPLE_RATE = 16000 +//| OUTPUT_PATH = "/sd/demo_file.wav" +//| +//| C_major_scale = [60, 62, 64, 65, 67, 69, 71, 72, 71, 69, 67, 65, 64, 62, 60] +//| synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE) +//| +//| with open(OUTPUT_PATH, "wb") as f: +//| writer = AudioWriter(f) +//| writer.play(synth) +//| for note in C_major_scale: +//| synth.press(note) +//| time.sleep(0.1) +//| synth.release(note) +//| time.sleep(0.10) //| writer.stop() +//| print("Done ->", OUTPUT_PATH) //| """ //| ... //| diff --git a/shared-bindings/audiowriter/AudioWriter.h b/shared-bindings/audiowriter/AudioWriter.h index f39e0fcfc88..e0de6b2ad9f 100644 --- a/shared-bindings/audiowriter/AudioWriter.h +++ b/shared-bindings/audiowriter/AudioWriter.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/shared-bindings/audiowriter/__init__.c b/shared-bindings/audiowriter/__init__.c index 2cf88e76076..21c0d15cc7b 100644 --- a/shared-bindings/audiowriter/__init__.c +++ b/shared-bindings/audiowriter/__init__.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -12,13 +12,7 @@ #include "shared-bindings/audiowriter/__init__.h" #include "shared-bindings/audiowriter/AudioWriter.h" -//| """Support for streaming audio to a WAV file -//| -//| The `audiowriter` module contains `AudioWriter`, a *sink* that records an -//| audio source (a microphone or an effect chain) to a ``.wav`` file in the -//| background -- the inverse of `audiocore.WaveFile`. -//| -//| """ +//| """Support for streaming audio to a WAV file""" static const mp_rom_map_elem_t audiowriter_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiowriter) }, diff --git a/shared-bindings/audiowriter/__init__.h b/shared-bindings/audiowriter/__init__.h index 3ddd6344a68..779b49ffd8d 100644 --- a/shared-bindings/audiowriter/__init__.h +++ b/shared-bindings/audiowriter/__init__.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/shared-module/audiowriter/AudioWriter.c b/shared-module/audiowriter/AudioWriter.c index 01111699669..0ddbe07c96c 100644 --- a/shared-module/audiowriter/AudioWriter.c +++ b/shared-module/audiowriter/AudioWriter.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/shared-module/audiowriter/AudioWriter.h b/shared-module/audiowriter/AudioWriter.h index 4b1874167f5..1aab3f401ad 100644 --- a/shared-module/audiowriter/AudioWriter.h +++ b/shared-module/audiowriter/AudioWriter.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -11,10 +11,10 @@ #include "py/obj.h" -// A streaming WAV *sink*: it consumes an audiosample source (a mic or an effect -// chain) and writes the resulting PCM to a file. Unlike WaveFile it is NOT an -// audiosample (it has no audiosample_base_t) -- it is the thing that drives a -// source, playing the role an AudioOut would. +// A streaming WAV *sink*: it consumes an audiosample source (a mic, synthio, +// or an effect chain) and writes the resulting PCM to a file. Unlike WaveFile +// it is NOT an audiosample, it is the thing that drives a source, playing the +// role an AudioOut would. typedef struct _audiowriter_audiowriter_obj_t { mp_obj_base_t base; diff --git a/shared-module/audiowriter/__init__.c b/shared-module/audiowriter/__init__.c index 6a919f9fcbf..584c821b996 100644 --- a/shared-module/audiowriter/__init__.c +++ b/shared-module/audiowriter/__init__.c @@ -1,5 +1,5 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2026 Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT From 80d6cae03663306d0da700a34a2eedbc9e466ea1 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 9 Jul 2026 12:51:25 -0700 Subject: [PATCH 634/876] usb_audio: migrate to TUD_AUDIO20_* / AUDIO20_* names The tinyusb bump splits the flat UAC descriptor API into version-namespaced UAC 1.0 and UAC 2.0 variants, so shared-module/usb_audio, which targets UAC 2.0, no longer compiles against the old names. Three layers moved: descriptor macros TUD_AUDIO_DESC_IAD -> TUD_AUDIO20_DESC_IAD enum constants AUDIO_CTRL_RW -> AUDIO20_CTRL_RW C types audio_control_cur_1_t -> audio20_control_cur_1_t AUDIO_TERM_TYPE_* is shared between UAC 1.0 and 2.0 upstream and keeps its old name. Two of the renames are not a literal insertion of "20": TUD_AUDIO_DESC_STD_AS_INT_LEN -> TUD_AUDIO20_DESC_STD_AS_LEN the length macro drops _INT; the emitter keeps it. TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(unitid, srcid, ch0, ch1, stridx) -> TUD_AUDIO20_DESC_FEATURE_UNIT(unitid, srcid, stridx, ch0, ch1) ONE/TWO_CHANNEL collapse into one varargs macro: stridx moves from last to third and the per-channel controls become trailing varargs. The paired length macro becomes TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1), still 14 bytes, so the *_DESC_LEN totals are unchanged. Verified by emitting the speaker/headset/mic descriptors before and after (old source + old tinyusb vs new source + new tinyusb) and diffing the bytes: identical at 132/230/132. Clean builds of adafruit_feather_rp2350 and feather_bluefruit_sense, both with CIRCUITPY_USB_AUDIO=1. Co-Authored-By: Claude Opus 4.8 (1M context) --- shared-module/usb_audio/__init__.c | 122 +++++++++--------- .../usb_audio/usb_audio_descriptors.h | 78 +++++------ 2 files changed, 100 insertions(+), 100 deletions(-) diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 5964b8acf78..cac47bbc5fe 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -127,7 +127,7 @@ void usb_audio_setup_singletons(void) { } // Hand-rolled UAC2 mono speaker (host -> board) descriptor WITHOUT an async -// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO_SPEAKER_MONO_FB_DESCRIPTOR +// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO20_SPEAKER_MONO_FB_DESCRIPTOR // (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so // the streaming alt-setting declares a single OUT endpoint (_nEPs = 0x01). The // entity IDs match the mic descriptor (see usb_audio_descriptors.h); only the @@ -136,36 +136,36 @@ void usb_audio_setup_singletons(void) { // terminal (0x01). Async feedback for true clock matching is a later step. #define USB_AUDIO_SPEAKER_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epsize) \ /* Standard Interface Association Descriptor (IAD) */ \ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ /* Standard AC Interface Descriptor(4.7.1) */ \ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_DESKTOP_SPEAKER, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN + TUD_AUDIO20_DESC_INPUT_TERM_LEN + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ /* Clock Source Descriptor(4.7.2.1) */ \ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ - TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) // Hand-rolled UAC2 mono headset (microphone + speaker both enabled): one audio function // presenting both a speaker (host -> board OUT) and a microphone (board -> host // IN) at once. This combines USB_AUDIO_SPEAKER_DESCRIPTOR's speaker chain with -// TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR's mic chain under a single IAD. The two chains +// TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR's mic chain under a single IAD. The two chains // must use distinct entity IDs (USB_AUDIO_HS_ENTITY_*; see usb_audio_descriptors.h) // because they live in the same AudioControl interface, and they share one clock // source. The function spans three interfaces: AudioControl (_itfnum), the @@ -174,53 +174,53 @@ void usb_audio_setup_singletons(void) { // async feedback endpoint, matching the single-direction descriptors. #define USB_AUDIO_HEADSET_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epout, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) -- 3 interfaces */ \ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x03, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x03, /*_stridx*/ 0x00), \ /* Standard AC Interface Descriptor(4.7.1) */ \ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ /* Class-Specific AC Interface Header Descriptor(4.7.2) -- clock + both chains */ \ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + 2 * (TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN), /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_HEADSET, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN + 2 * (TUD_AUDIO20_DESC_INPUT_TERM_LEN + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1) + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ /* Clock Source Descriptor(4.7.2.1) -- shared by both chains */ \ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ /* --- Speaker chain (host -> board) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* --- Mic chain (board -> host) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- generic microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming out to the host */ \ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* --- Speaker AudioStreaming interface (_itfnum + 1) --- */ \ /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the speaker input terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epout, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ - TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000), \ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000), \ /* --- Mic AudioStreaming interface (_itfnum + 2) --- */ \ /* Standard AS Interface Descriptor(4.9.1) -- alt 0, zero bandwidth */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one IN endpoint */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the mic output terminal */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ - TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) // Combined headset: both a microphone (board -> host IN) and a speaker // (host -> board OUT) under one audio function. @@ -240,7 +240,7 @@ size_t usb_audio_descriptor_length(void) { if (usb_audio_direction_is_output()) { return USB_AUDIO_SPEAKER_DESC_LEN; } - return TUD_AUDIO_MIC_ONE_CH_DESC_LEN; + return TUD_AUDIO20_MIC_ONE_CH_DESC_LEN; } size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *descriptor_counts, uint8_t *current_interface_string) { @@ -326,7 +326,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de usb_add_interface_string(*current_interface_string, "CircuitPython Microphone"); const uint8_t usb_audio_descriptor[] = { - TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR( + TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, @@ -492,7 +492,7 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p uint8_t const entityID = (uint8_t)tu_u16_high(p_request->wIndex); // Only current-value requests are supported. - TU_VERIFY(p_request->bRequest == AUDIO_CS_REQ_CUR); + TU_VERIFY(p_request->bRequest == AUDIO20_CS_REQ_CUR); // A headset exposes a feature unit per direction; the speaker's id matches the // single-direction USB_AUDIO_ENTITY_FEATURE_UNIT, the mic adds a second one. @@ -503,14 +503,14 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p return false; } switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_1_t)); - usb_audio_mute[channelNum] = ((audio_control_cur_1_t *)pBuff)->bCur; + case AUDIO20_FU_CTRL_MUTE: + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_1_t)); + usb_audio_mute[channelNum] = ((audio20_control_cur_1_t *)pBuff)->bCur; return true; - case AUDIO_FU_CTRL_VOLUME: - TU_VERIFY(p_request->wLength == sizeof(audio_control_cur_2_t)); - usb_audio_volume[channelNum] = ((audio_control_cur_2_t *)pBuff)->bCur; + case AUDIO20_FU_CTRL_VOLUME: + TU_VERIFY(p_request->wLength == sizeof(audio20_control_cur_2_t)); + usb_audio_volume[channelNum] = ((audio20_control_cur_2_t *)pBuff)->bCur; return true; default: @@ -535,10 +535,10 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p if (entityID == USB_AUDIO_ENTITY_INPUT_TERMINAL || entityID == USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL) { switch (ctrlSel) { - case AUDIO_TE_CTRL_CONNECTOR: { - audio_desc_channel_cluster_t ret; + case AUDIO20_TE_CTRL_CONNECTOR: { + audio20_desc_channel_cluster_t ret; ret.bNrChannels = USB_AUDIO_N_CHANNELS; - ret.bmChannelConfig = (audio_channel_config_t)0; + ret.bmChannelConfig = (audio20_channel_config_t)0; ret.iChannelNames = 0; return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); } @@ -554,16 +554,16 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p return false; } switch (ctrlSel) { - case AUDIO_FU_CTRL_MUTE: + case AUDIO20_FU_CTRL_MUTE: return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &usb_audio_mute[channelNum], sizeof(usb_audio_mute[channelNum])); - case AUDIO_FU_CTRL_VOLUME: + case AUDIO20_FU_CTRL_VOLUME: switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: + case AUDIO20_CS_REQ_CUR: return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &usb_audio_volume[channelNum], sizeof(usb_audio_volume[channelNum])); - case AUDIO_CS_REQ_RANGE: { - audio_control_range_2_n_t(1) ret; + case AUDIO20_CS_REQ_RANGE: { + audio20_control_range_2_n_t(1) ret; ret.wNumSubRanges = 1; ret.subrange[0].bMin = -90 * 256; // -90 dB ret.subrange[0].bMax = 90 * 256; // +90 dB @@ -583,15 +583,15 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Clock source (sample rate set in usb_audio.enable()). if (entityID == USB_AUDIO_ENTITY_CLOCK_SOURCE) { switch (ctrlSel) { - case AUDIO_CS_CTRL_SAM_FREQ: + case AUDIO20_CS_CTRL_SAM_FREQ: switch (p_request->bRequest) { - case AUDIO_CS_REQ_CUR: { - audio_control_cur_4_t cur = { .bCur = (int32_t)usb_audio_sample_rate }; + case AUDIO20_CS_REQ_CUR: { + audio20_control_cur_4_t cur = { .bCur = (int32_t)usb_audio_sample_rate }; return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur, sizeof(cur)); } - case AUDIO_CS_REQ_RANGE: { - audio_control_range_4_n_t(1) ret; + case AUDIO20_CS_REQ_RANGE: { + audio20_control_range_4_n_t(1) ret; ret.wNumSubRanges = 1; ret.subrange[0].bMin = (int32_t)usb_audio_sample_rate; ret.subrange[0].bMax = (int32_t)usb_audio_sample_rate; @@ -603,8 +603,8 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p return false; } - case AUDIO_CS_CTRL_CLK_VALID: { - audio_control_cur_1_t cur = { .bCur = 1 }; + case AUDIO20_CS_CTRL_CLK_VALID: { + audio20_control_cur_1_t cur = { .bCur = 1 }; return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &cur, sizeof(cur)); } diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 1313e198959..642246f9ca7 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -45,7 +45,7 @@ size_t usb_audio_descriptor_length(void); #define USB_AUDIO_ISO_EP_NUM (0) #endif -// Fixed UAC2 entity IDs baked into TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR and the +// Fixed UAC2 entity IDs baked into TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR and the // hand-rolled speaker descriptor (USB_AUDIO_SPEAKER_DESCRIPTOR in __init__.c). // The speaker reuses the same IDs as the mic; only the terminal roles reverse // (input terminal = USB streaming, output terminal = desktop speaker). @@ -69,26 +69,26 @@ size_t usb_audio_descriptor_length(void); #define USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL (0x07) // USB streaming out to host // Length of the no-feedback mono speaker descriptor. It uses the same set of -// sub-descriptors as TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR (one isochronous data +// sub-descriptors as TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR (one isochronous data // endpoint, no feedback endpoint), so this is identical to -// TUD_AUDIO_MIC_ONE_CH_DESC_LEN -- but spell it out independently so the two +// TUD_AUDIO20_MIC_ONE_CH_DESC_LEN -- but spell it out independently so the two // can diverge later (e.g. stereo) without silently mis-sizing the descriptor. -// These TUD_AUDIO_DESC_*_LEN macros come from TinyUSB's usbd.h; this expression +// These TUD_AUDIO20_DESC_*_LEN macros come from TinyUSB's usbd.h; this expression // is only expanded where that header is already included (never at the point // tusb_config.h includes us), so the header stays dependency-free. -#define USB_AUDIO_SPEAKER_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ - + TUD_AUDIO_DESC_STD_AC_LEN \ - + TUD_AUDIO_DESC_CS_AC_LEN \ - + TUD_AUDIO_DESC_CLK_SRC_LEN \ - + TUD_AUDIO_DESC_INPUT_TERM_LEN \ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_CS_AS_INT_LEN \ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) +#define USB_AUDIO_SPEAKER_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN \ + + TUD_AUDIO20_DESC_STD_AC_LEN \ + + TUD_AUDIO20_DESC_CS_AC_LEN \ + + TUD_AUDIO20_DESC_CLK_SRC_LEN \ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1) \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) // Length of the combined headset descriptor (microphone + speaker both enabled): one IAD // wrapping a single AudioControl interface plus two AudioStreaming interfaces @@ -99,29 +99,29 @@ size_t usb_audio_descriptor_length(void); // single-direction descriptors). See USB_AUDIO_HEADSET_DESCRIPTOR in __init__.c. // Expanded only where TinyUSB's usbd.h is already included (never at the point // tusb_config.h includes us), so this header stays dependency-free. -#define USB_AUDIO_HEADSET_DESC_LEN (TUD_AUDIO_DESC_IAD_LEN \ - + TUD_AUDIO_DESC_STD_AC_LEN \ - + TUD_AUDIO_DESC_CS_AC_LEN \ - + TUD_AUDIO_DESC_CLK_SRC_LEN \ +#define USB_AUDIO_HEADSET_DESC_LEN (TUD_AUDIO20_DESC_IAD_LEN \ + + TUD_AUDIO20_DESC_STD_AC_LEN \ + + TUD_AUDIO20_DESC_CS_AC_LEN \ + + TUD_AUDIO20_DESC_CLK_SRC_LEN \ /* speaker chain: USB-streaming input terminal -> feature unit -> speaker */ \ - + TUD_AUDIO_DESC_INPUT_TERM_LEN \ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1) \ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN \ /* mic chain: microphone input terminal -> feature unit -> USB-streaming out */ \ - + TUD_AUDIO_DESC_INPUT_TERM_LEN \ - + TUD_AUDIO_DESC_FEATURE_UNIT_ONE_CHANNEL_LEN \ - + TUD_AUDIO_DESC_OUTPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_INPUT_TERM_LEN \ + + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(1) \ + + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN \ /* speaker AudioStreaming interface (alt 0 + alt 1 with OUT endpoint) */ \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_CS_AS_INT_LEN \ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN \ /* mic AudioStreaming interface (alt 0 + alt 1 with IN endpoint) */ \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_STD_AS_INT_LEN \ - + TUD_AUDIO_DESC_CS_AS_INT_LEN \ - + TUD_AUDIO_DESC_TYPE_I_FORMAT_LEN \ - + TUD_AUDIO_DESC_STD_AS_ISO_EP_LEN \ - + TUD_AUDIO_DESC_CS_AS_ISO_EP_LEN) + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_STD_AS_LEN \ + + TUD_AUDIO20_DESC_CS_AS_INT_LEN \ + + TUD_AUDIO20_DESC_TYPE_I_FORMAT_LEN \ + + TUD_AUDIO20_DESC_STD_AS_ISO_EP_LEN \ + + TUD_AUDIO20_DESC_CS_AS_ISO_EP_LEN) From d4d5ad399b569167de658bfdc89aeb938ea13e59 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 9 Jul 2026 12:54:43 -0700 Subject: [PATCH 635/876] stm: build fsdev_common.c for STM32L433xx The tinyusb bump splits the STM32 fsdev driver: fsdev_core_reset, pma_align_buffer_size and btable_set_rx_bufsize moved out of dcd_stm32_fsdev.c into a new fsdev_common.c. Add it to SRC_C, mirroring the dwc2 / dwc2_common.c pattern just below. Only STM32L433xx boards take the fsdev path, so blues_cygnet was the sole board failing to link on the three symbols above. It now builds clean. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/stm/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm/Makefile b/ports/stm/Makefile index 2ed3bddb5b7..5ad0c82654c 100755 --- a/ports/stm/Makefile +++ b/ports/stm/Makefile @@ -205,6 +205,7 @@ endif ifneq ($(CIRCUITPY_USB),0) ifeq ($(MCU_VARIANT),$(filter $(MCU_VARIANT),STM32L433xx)) SRC_C += lib/tinyusb/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c + SRC_C += lib/tinyusb/src/portable/st/stm32_fsdev/fsdev_common.c else SRC_C += lib/tinyusb/src/portable/synopsys/dwc2/dcd_dwc2.c SRC_C += lib/tinyusb/src/portable/synopsys/dwc2/dwc2_common.c From 04a0950aea300097b17c5fa9a8d24d3e10d4b777 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Jul 2026 14:58:37 -0500 Subject: [PATCH 636/876] GranularPitchShift initial code --- py/circuitpy_defns.mk | 6 + .../audiodelays/GranularPitchShift.c | 282 ++++++++++++ .../audiodelays/GranularPitchShift.h | 28 ++ shared-bindings/audiodelays/__init__.c | 2 + .../audiodelays/GranularPitchShift.c | 430 ++++++++++++++++++ .../audiodelays/GranularPitchShift.h | 95 ++++ 6 files changed, 843 insertions(+) create mode 100644 shared-bindings/audiodelays/GranularPitchShift.c create mode 100644 shared-bindings/audiodelays/GranularPitchShift.h create mode 100644 shared-module/audiodelays/GranularPitchShift.c create mode 100644 shared-module/audiodelays/GranularPitchShift.h diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 4c91ed102c2..f60c19bbe73 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -152,6 +152,9 @@ endif ifeq ($(CIRCUITPY_AUDIOSPEED),1) SRC_PATTERNS += audiospeed/% endif +ifeq ($(CIRCUITPY_AUDIOWRITER),1) +SRC_PATTERNS += audiowriter/% +endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% endif @@ -710,6 +713,7 @@ SRC_SHARED_MODULE_ALL = \ audiodelays/Echo.c \ audiodelays/Chorus.c \ audiodelays/PitchShift.c \ + audiodelays/GranularPitchShift.c \ audiodelays/MultiTapDelay.c \ audiodelays/__init__.c \ audiofilters/Distortion.c \ @@ -718,6 +722,8 @@ SRC_SHARED_MODULE_ALL = \ audiofilters/__init__.c \ audiofreeverb/__init__.c \ audiofreeverb/Freeverb.c \ + audiowriter/AudioWriter.c \ + audiowriter/__init__.c \ audioio/__init__.c \ audiomixer/Mixer.c \ audiomixer/MixerVoice.c \ diff --git a/shared-bindings/audiodelays/GranularPitchShift.c b/shared-bindings/audiodelays/GranularPitchShift.c new file mode 100644 index 00000000000..ed57c36dd06 --- /dev/null +++ b/shared-bindings/audiodelays/GranularPitchShift.c @@ -0,0 +1,282 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared-bindings/audiodelays/GranularPitchShift.h" +#include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiodelays/GranularPitchShift.h" + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/util.h" +#include "shared-module/synthio/block.h" + +//| class GranularPitchShift: +//| """A granular-synthesis pitch shift effect""" +//| +//| def __init__( +//| self, +//| semitones: synthio.BlockInput = 0.0, +//| mix: synthio.BlockInput = 1.0, +//| grain_size: int = 1024, +//| density: int = 2, +//| buffer_size: int = 512, +//| sample_rate: int = 8000, +//| bits_per_sample: int = 16, +//| samples_signed: bool = True, +//| channel_count: int = 1, +//| ) -> None: +//| """Create a pitch shift effect that shifts pitch using granular synthesis: a cloud of +//| short, overlapping, individually-enveloped grains resampled from a capture buffer. Unlike +//| `PitchShift` (a single crossfaded window), the overlapping grains tend to sound smoother +//| and less "robotic" at large shifts. This effect introduces a slight delay in the output +//| proportional to ``grain_size``. +//| +//| The mix parameter allows you to change how much of the unchanged sample passes through to +//| the output to how much of the effect audio you hear as the output. +//| +//| :param synthio.BlockInput semitones: The amount of pitch shifting in semitones (1/12th of an octave) +//| :param synthio.BlockInput mix: The mix as a ratio of the sample (0.0) to the effect (1.0) +//| :param int grain_size: The length in samples of each grain +//| :param int density: The number of overlapping grains (overlap factor). Must be between 1 and 8. +//| :param int buffer_size: The total size in bytes of each of the two playback buffers to use +//| :param int sample_rate: The sample rate to be used +//| :param int channel_count: The number of channels the source samples contain. 1 = mono; 2 = stereo. +//| :param int bits_per_sample: The bits per sample of the effect +//| :param bool samples_signed: Effect is signed (True) or unsigned (False) +//| +//| .. note:: Grain start position is currently deterministic (no randomization/jitter). A +//| ``spread`` parameter for classic granular jitter may be added in a future release. +//| +//| Shifting the pitch of a synth by 5 semitones:: +//| +//| import time +//| import board +//| import audiobusio +//| import synthio +//| import audiodelays +//| +//| audio = audiobusio.I2SOut(bit_clock=board.GP0, word_select=board.GP1, data=board.GP2) +//| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) +//| pitch_shift = audiodelays.GranularPitchShift(semitones=5.0, mix=0.5, grain_size=2048, density=2, buffer_size=1024, channel_count=1, sample_rate=44100) +//| pitch_shift.play(synth) +//| audio.play(pitch_shift) +//| +//| while True: +//| for notenum in (60, 64, 67, 71): +//| synth.press(notenum) +//| time.sleep(0.25) +//| synth.release_all()""" +//| ... +//| +static mp_obj_t audiodelays_granular_pitch_shift_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_semitones, ARG_mix, ARG_grain_size, ARG_density, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_semitones, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(0)} }, + { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1)} }, + { MP_QSTR_grain_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, + { MP_QSTR_density, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, 2, MP_QSTR_channel_count); + mp_int_t sample_rate = mp_arg_validate_int_min(args[ARG_sample_rate].u_int, 1, MP_QSTR_sample_rate); + mp_int_t grain_size = mp_arg_validate_int_min(args[ARG_grain_size].u_int, 2, MP_QSTR_grain_size); + mp_int_t density = mp_arg_validate_int_range(args[ARG_density].u_int, 1, GRANULAR_MAX_GRAINS, MP_QSTR_density); + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(MP_ERROR_TEXT("bits_per_sample must be 8 or 16")); + } + + audiodelays_granular_pitch_shift_obj_t *self = + mp_obj_malloc(audiodelays_granular_pitch_shift_obj_t, &audiodelays_granular_pitch_shift_type); + common_hal_audiodelays_granular_pitch_shift_construct(self, + args[ARG_semitones].u_obj, + args[ARG_mix].u_obj, + grain_size, + density, + args[ARG_buffer_size].u_int, + bits_per_sample, + args[ARG_samples_signed].u_bool, + channel_count, + sample_rate); + + return MP_OBJ_FROM_PTR(self); +} + + +//| def deinit(self) -> None: +//| """Deinitialises the GranularPitchShift.""" +//| ... +//| +static mp_obj_t audiodelays_granular_pitch_shift_deinit(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_deinit_obj, audiodelays_granular_pitch_shift_deinit); + +static void check_for_deinit(audiodelays_granular_pitch_shift_obj_t *self) { + audiosample_check_for_deinit(&self->base); +} + + +//| def __enter__(self) -> GranularPitchShift: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audiodelays_granular_pitch_shift_deinit(args[0]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiodelays_granular_pitch_shift___exit___obj, 4, 4, audiodelays_granular_pitch_shift_obj___exit__); + + +//| semitones: synthio.BlockInput +//| """The amount of pitch shifting in semitones (1/12th of an octave).""" +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj_get_semitones(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + return common_hal_audiodelays_granular_pitch_shift_get_semitones(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_get_semitones_obj, audiodelays_granular_pitch_shift_obj_get_semitones); + +static mp_obj_t audiodelays_granular_pitch_shift_obj_set_semitones(mp_obj_t self_in, mp_obj_t semitones_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_set_semitones(self, semitones_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_granular_pitch_shift_set_semitones_obj, audiodelays_granular_pitch_shift_obj_set_semitones); + +MP_PROPERTY_GETSET(audiodelays_granular_pitch_shift_semitones_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_get_semitones_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_set_semitones_obj); + + +//| mix: synthio.BlockInput +//| """The output mix between 0 and 1 where 0 is only sample and 1 is all effect.""" +static mp_obj_t audiodelays_granular_pitch_shift_obj_get_mix(mp_obj_t self_in) { + return common_hal_audiodelays_granular_pitch_shift_get_mix(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_get_mix_obj, audiodelays_granular_pitch_shift_obj_get_mix); + +static mp_obj_t audiodelays_granular_pitch_shift_obj_set_mix(mp_obj_t self_in, mp_obj_t mix_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_set_mix(self, mix_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_granular_pitch_shift_set_mix_obj, audiodelays_granular_pitch_shift_obj_set_mix); + +MP_PROPERTY_GETSET(audiodelays_granular_pitch_shift_mix_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_get_mix_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_set_mix_obj); + + +//| playing: bool +//| """True when the effect is playing a sample. (read-only)""" +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj_get_playing(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiodelays_granular_pitch_shift_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_get_playing_obj, audiodelays_granular_pitch_shift_obj_get_playing); + +MP_PROPERTY_GETTER(audiodelays_granular_pitch_shift_playing_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_get_playing_obj); + + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> GranularPitchShift: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: GranularPitchShift""" +//| ... +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED, {} }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audiodelays_granular_pitch_shift_play(self, sample, args[ARG_loop].u_bool); + + return MP_OBJ_FROM_PTR(self); +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_granular_pitch_shift_play_obj, 1, audiodelays_granular_pitch_shift_obj_play); + + +//| def stop(self) -> None: +//| """Stops playback of the sample.""" +//| ... +//| +//| +static mp_obj_t audiodelays_granular_pitch_shift_obj_stop(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_stop_obj, audiodelays_granular_pitch_shift_obj_stop); + + +static const mp_rom_map_elem_t audiodelays_granular_pitch_shift_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiodelays_granular_pitch_shift_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiodelays_granular_pitch_shift___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiodelays_granular_pitch_shift_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiodelays_granular_pitch_shift_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_granular_pitch_shift_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_semitones), MP_ROM_PTR(&audiodelays_granular_pitch_shift_semitones_obj) }, + { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_granular_pitch_shift_mix_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(audiodelays_granular_pitch_shift_locals_dict, audiodelays_granular_pitch_shift_locals_dict_table); + +static const audiosample_p_t audiodelays_granular_pitch_shift_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiodelays_granular_pitch_shift_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiodelays_granular_pitch_shift_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiodelays_granular_pitch_shift_type, + MP_QSTR_GranularPitchShift, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiodelays_granular_pitch_shift_make_new, + locals_dict, &audiodelays_granular_pitch_shift_locals_dict, + protocol, &audiodelays_granular_pitch_shift_proto + ); diff --git a/shared-bindings/audiodelays/GranularPitchShift.h b/shared-bindings/audiodelays/GranularPitchShift.h new file mode 100644 index 00000000000..af85d179ea0 --- /dev/null +++ b/shared-bindings/audiodelays/GranularPitchShift.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiodelays/GranularPitchShift.h" + +extern const mp_obj_type_t audiodelays_granular_pitch_shift_type; + +void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_pitch_shift_obj_t *self, + mp_obj_t semitones, mp_obj_t mix, uint32_t grain_size, uint32_t density, + uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, + uint8_t channel_count, uint32_t sample_rate); + +void common_hal_audiodelays_granular_pitch_shift_deinit(audiodelays_granular_pitch_shift_obj_t *self); + +mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_semitones(audiodelays_granular_pitch_shift_obj_t *self); +void common_hal_audiodelays_granular_pitch_shift_set_semitones(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t semitones); + +mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_mix(audiodelays_granular_pitch_shift_obj_t *self); +void common_hal_audiodelays_granular_pitch_shift_set_mix(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t arg); + +bool common_hal_audiodelays_granular_pitch_shift_get_playing(audiodelays_granular_pitch_shift_obj_t *self); +void common_hal_audiodelays_granular_pitch_shift_play(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_audiodelays_granular_pitch_shift_stop(audiodelays_granular_pitch_shift_obj_t *self); diff --git a/shared-bindings/audiodelays/__init__.c b/shared-bindings/audiodelays/__init__.c index e93052eabfd..2125aa54683 100644 --- a/shared-bindings/audiodelays/__init__.c +++ b/shared-bindings/audiodelays/__init__.c @@ -13,6 +13,7 @@ #include "shared-bindings/audiodelays/Echo.h" #include "shared-bindings/audiodelays/Chorus.h" #include "shared-bindings/audiodelays/PitchShift.h" +#include "shared-bindings/audiodelays/GranularPitchShift.h" #include "shared-bindings/audiodelays/MultiTapDelay.h" //| """Support for audio delay effects @@ -26,6 +27,7 @@ static const mp_rom_map_elem_t audiodelays_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_Echo), MP_ROM_PTR(&audiodelays_echo_type) }, { MP_ROM_QSTR(MP_QSTR_Chorus), MP_ROM_PTR(&audiodelays_chorus_type) }, { MP_ROM_QSTR(MP_QSTR_PitchShift), MP_ROM_PTR(&audiodelays_pitch_shift_type) }, + { MP_ROM_QSTR(MP_QSTR_GranularPitchShift), MP_ROM_PTR(&audiodelays_granular_pitch_shift_type) }, { MP_ROM_QSTR(MP_QSTR_MultiTapDelay), MP_ROM_PTR(&audiodelays_multi_tap_delay_type) }, }; diff --git a/shared-module/audiodelays/GranularPitchShift.c b/shared-module/audiodelays/GranularPitchShift.c new file mode 100644 index 00000000000..f7b6a9b9062 --- /dev/null +++ b/shared-module/audiodelays/GranularPitchShift.c @@ -0,0 +1,430 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT +#include "shared-bindings/audiodelays/GranularPitchShift.h" +#include "shared-bindings/audiocore/__init__.h" + +#include +#include "py/runtime.h" +#include + +void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_pitch_shift_obj_t *self, + mp_obj_t semitones, mp_obj_t mix, uint32_t grain_size, uint32_t density, + uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, + uint8_t channel_count, uint32_t sample_rate) { + + // Basic settings every effect and audio sample has + // These are the effect's values, not the source sample(s) + self->base.bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places + self->base.samples_signed = samples_signed; // Are the samples we provide signed (common is true) + self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo + self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.single_buffer = false; + self->base.max_buffer_length = buffer_size; + + // To smooth things out as CircuitPython is doing other tasks most audio objects have a buffer + // A double buffer is set up here so the audio output can use DMA on buffer 1 while we + // write to and create buffer 2. + // This buffer is what is passed to the audio component that plays the effect. + // Samples are set sequentially. For stereo audio they are passed L/R/L/R/... + self->buffer_len = buffer_size; // in bytes + + self->buffer[0] = m_malloc_without_collect(self->buffer_len); + if (self->buffer[0] == NULL) { + common_hal_audiodelays_granular_pitch_shift_deinit(self); + m_malloc_fail(self->buffer_len); + } + memset(self->buffer[0], 0, self->buffer_len); + + self->buffer[1] = m_malloc_without_collect(self->buffer_len); + if (self->buffer[1] == NULL) { + common_hal_audiodelays_granular_pitch_shift_deinit(self); + m_malloc_fail(self->buffer_len); + } + memset(self->buffer[1], 0, self->buffer_len); + + self->last_buf_idx = 1; // Which buffer to use first, toggle between 0 and 1 + + // Initialize other values most effects will need. + self->sample = NULL; // The current playing sample + self->sample_remaining_buffer = NULL; // Pointer to the start of the sample buffer we have not played + self->sample_buffer_length = 0; // How many samples do we have left to play (these may be 16 bit!) + self->loop = false; // When the sample is done do we loop to the start again or stop (e.g. in a wav file) + self->more_data = false; // Is there still more data to read from the sample or did we finish + + // The below section sets up the effect's starting values. + + synthio_block_assign_slot(semitones, &self->semitones, MP_QSTR_semitones); + synthio_block_assign_slot(mix, &self->mix, MP_QSTR_mix); + + // Grain scheduling parameters. `density` (number of overlapping grains) is + // clamped to the fixed grain pool size so allocation stays deterministic. + self->grain_size = grain_size; + if (density < 1) { + density = 1; + } + if (density > GRANULAR_MAX_GRAINS) { + density = GRANULAR_MAX_GRAINS; + } + self->density = density; + + // Normalization for the overlap-add gain of the grain envelopes. A Hann + // window overlapped at hop = grain_size / density sums to a constant gain of + // density/2, so we scale the summed grains by 2/density in Q15 to keep the + // output at ~unity. Cap at 1.0 so the degenerate density==1 case (a single + // windowed grain, no overlap partner) is never amplified. + self->grain_gain = (1 << 15) * 2 / density; // 2/density in Q15 + if (self->grain_gain > (1 << 15)) { + self->grain_gain = (1 << 15); + } + + // Capture buffer (the delay line grains read from), stored as 16-bit, + // planar per channel. Length is grain_size * 2 words per channel so a grain + // starting grain_size words behind the write pointer never overruns the live + // write cursor even when reading ahead at a raised pitch (see plan sizing + // notes). + self->capture_len = self->grain_size * 2; // words per channel + uint32_t capture_bytes = self->capture_len * self->base.channel_count * sizeof(int16_t); + self->capture_buffer = m_malloc_without_collect(capture_bytes); + if (self->capture_buffer == NULL) { + common_hal_audiodelays_granular_pitch_shift_deinit(self); + m_malloc_fail(capture_bytes); + } + memset(self->capture_buffer, 0, capture_bytes); + self->write_index = 0; + + // Precompute the grain amplitude envelope: a raised-cosine (Hann) window in + // Q15 (0..32767), indexed directly by a grain's phase. Computed once here (a + // little float math at construction is fine; the inner playback loop stays + // integer-only). + self->envelope_len = self->grain_size; + uint32_t envelope_bytes = self->envelope_len * sizeof(int16_t); + self->envelope_table = m_malloc_without_collect(envelope_bytes); + if (self->envelope_table == NULL) { + common_hal_audiodelays_granular_pitch_shift_deinit(self); + m_malloc_fail(envelope_bytes); + } + mp_float_t denom = (self->envelope_len > 1) ? (mp_float_t)(self->envelope_len - 1) : MICROPY_FLOAT_CONST(1.0); + for (uint32_t n = 0; n < self->envelope_len; n++) { + mp_float_t w = MICROPY_FLOAT_CONST(0.5) * + (MICROPY_FLOAT_CONST(1.0) - MICROPY_FLOAT_C_FUN(cos)( + MICROPY_FLOAT_CONST(2.0) * MICROPY_FLOAT_CONST(3.14159265358979323846) * (mp_float_t)n / denom)); + self->envelope_table[n] = (int16_t)(w * MICROPY_FLOAT_CONST(32767.0)); + } + + // Deactivate all grains and prime the scheduler so the first grain launches + // immediately on the first output sample. + for (uint32_t i = 0; i < GRANULAR_MAX_GRAINS; i++) { + self->grains[i].active = false; + } + self->samples_until_next_grain = 0; + + // Calculate the fixed-point read-rate increment applied to launched grains. + mp_float_t f_semitones = synthio_block_slot_get(&self->semitones); + granular_pitch_shift_recalculate_rate(self, f_semitones); +} + +void common_hal_audiodelays_granular_pitch_shift_deinit(audiodelays_granular_pitch_shift_obj_t *self) { + audiosample_mark_deinit(&self->base); + self->envelope_table = NULL; + self->capture_buffer = NULL; + self->buffer[0] = NULL; + self->buffer[1] = NULL; +} + +mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_semitones(audiodelays_granular_pitch_shift_obj_t *self) { + return self->semitones.obj; +} + +void common_hal_audiodelays_granular_pitch_shift_set_semitones(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t semitones_in) { + synthio_block_assign_slot(semitones_in, &self->semitones, MP_QSTR_semitones); + mp_float_t semitones = synthio_block_slot_get(&self->semitones); + granular_pitch_shift_recalculate_rate(self, semitones); +} + +void granular_pitch_shift_recalculate_rate(audiodelays_granular_pitch_shift_obj_t *self, mp_float_t semitones) { + self->read_rate = (uint32_t)(MICROPY_FLOAT_C_FUN(pow)(2.0, semitones / MICROPY_FLOAT_CONST(12.0)) * (1 << GRANULAR_PITCH_READ_SHIFT)); + self->current_semitones = semitones; +} + +mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_mix(audiodelays_granular_pitch_shift_obj_t *self) { + return self->mix.obj; +} + +void common_hal_audiodelays_granular_pitch_shift_set_mix(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t arg) { + synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); +} + +void audiodelays_granular_pitch_shift_reset_buffer(audiodelays_granular_pitch_shift_obj_t *self, + bool single_channel_output, + uint8_t channel) { + + memset(self->buffer[0], 0, self->buffer_len); + memset(self->buffer[1], 0, self->buffer_len); + memset(self->capture_buffer, 0, self->capture_len * self->base.channel_count * sizeof(int16_t)); + + // Deactivate all grains and reset the scheduler/write cursor. + for (uint32_t i = 0; i < GRANULAR_MAX_GRAINS; i++) { + self->grains[i].active = false; + } + self->samples_until_next_grain = 0; + self->write_index = 0; +} + +bool common_hal_audiodelays_granular_pitch_shift_get_playing(audiodelays_granular_pitch_shift_obj_t *self) { + return self->sample != NULL; +} + +void common_hal_audiodelays_granular_pitch_shift_play(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t sample, bool loop) { + audiosample_must_match(&self->base, sample, false); + + self->sample = sample; + self->loop = loop; + + audiosample_reset_buffer(self->sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + + // Track remaining sample length in terms of bytes per sample + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + // Store if we have more data in the sample to retrieve + self->more_data = result == GET_BUFFER_MORE_DATA; + + return; +} + +void common_hal_audiodelays_granular_pitch_shift_stop(audiodelays_granular_pitch_shift_obj_t *self) { + // When the sample is set to stop playing do any cleanup here + self->sample = NULL; + return; +} + +// Launch a grain into the first free pool slot, seeded to read from the capture +// buffer starting grain_size words behind the current write cursor (so it reads +// already-captured audio) at the current pitch-shift read rate. Grain read +// state (read_index/phase) is per-frame / channel-independent; the per-channel +// plane offset is applied at read time. +static void granular_pitch_shift_launch_grain(audiodelays_granular_pitch_shift_obj_t *self) { + for (uint32_t g = 0; g < GRANULAR_MAX_GRAINS; g++) { + if (!self->grains[g].active) { + uint32_t start = (self->write_index + self->capture_len - self->grain_size) % self->capture_len; + self->grains[g].active = true; + self->grains[g].read_index = start << GRANULAR_PITCH_READ_SHIFT; + self->grains[g].read_rate = self->read_rate; + self->grains[g].phase = 0; + self->grains[g].length = self->grain_size; + return; + } + } +} + +audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodelays_granular_pitch_shift_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + + // Grain scheduler + enveloped grain playback with dry/wet `mix` blending. + // Grains are launched at a fixed spacing (grain_size / density) and each + // active grain reads the capture buffer at its own pitch-shifted (fractional, + // linearly interpolated) read rate, scaled by a Hann amplitude envelope so + // overlapping grains fade in/out and add without seam clicks. The summed + // grains are normalized by grain_gain for ~unity overlap-add gain, then + // crossfaded against the dry input via the `mix` slot. The 8/16-bit, + // signed/unsigned, and mono/stereo (planar capture, buf_offset) paths are all + // handled below, mirroring PitchShift. + + if (!single_channel_output) { + channel = 0; + } + + // Switch our buffers to the other buffer + self->last_buf_idx = !self->last_buf_idx; + + // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer + int16_t *word_buffer = (int16_t *)self->buffer[self->last_buf_idx]; + int8_t *hword_buffer = self->buffer[self->last_buf_idx]; + uint32_t length = self->buffer_len / (self->base.bits_per_sample / 8); + + // The capture buffer (delay line) is always stored as 16-bit, planar per + // channel: channel c occupies capture_buffer[c * capture_len .. ). + int16_t *capture_buffer = self->capture_buffer; + + // Grains are launched this many frames apart (overlap factor `density`). + uint32_t grain_spacing = self->grain_size / self->density; + if (grain_spacing == 0) { + grain_spacing = 1; + } + + // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample + while (length != 0) { + // Check if there is no more sample to play, we will either load more data, reset the sample if loop is on or clear the sample + if (self->sample_buffer_length == 0) { + if (!self->more_data) { // The sample has indicated it has no more data to play + if (self->loop && self->sample) { // If we are supposed to loop reset the sample to the start + audiosample_reset_buffer(self->sample, false, 0); + } else { // If we were not supposed to loop the sample, stop playing it + self->sample = NULL; + } + } + if (self->sample) { + // Load another sample buffer to play + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } + } + + if (self->sample == NULL) { + if (self->base.samples_signed) { + memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); + } else { + // For unsigned samples set to the middle which is "quiet" + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + memset(word_buffer, 32768, length * (self->base.bits_per_sample / 8)); + } else { + memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); + } + } + + // tick all block inputs + shared_bindings_synthio_lfo_tick(self->base.sample_rate, length / self->base.channel_count); + (void)synthio_block_slot_get(&self->semitones); + (void)synthio_block_slot_get(&self->mix); + + length = 0; + } else { + // we have a sample to play and apply effect + // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining + uint32_t n = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * self->base.channel_count); + + int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; // for 16-bit samples + int8_t *sample_hsrc = (int8_t *)self->sample_remaining_buffer; // for 8-bit samples + + // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required + shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); + mp_float_t semitones = synthio_block_slot_get(&self->semitones); + // Doubled (0.0..2.0) so the crossfade below can hold both dry and wet + // at full gain around the midpoint, matching PitchShift's mix curve. + mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * MICROPY_FLOAT_CONST(2.0); + + // Only recalculate rate if semitones has changed + if (memcmp(&semitones, &self->current_semitones, sizeof(mp_float_t))) { + granular_pitch_shift_recalculate_rate(self, semitones); + } + + for (uint32_t i = 0; i < n; i++) { + bool buf_offset = (channel == 1 || i % self->base.channel_count == 1); + + int32_t sample_word = 0; + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + sample_word = sample_src[i]; + } else { + if (self->base.samples_signed) { + sample_word = sample_hsrc[i]; + } else { + // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed + sample_word = (int8_t)(((uint8_t)sample_hsrc[i]) ^ 0x80); + } + } + + // Write the incoming sample into the capture buffer (the delay + // line grains read from) at the per-channel write cursor. + capture_buffer[self->write_index + self->capture_len * buf_offset] = (int16_t)sample_word; + + // Sum all active grains. Each grain reads the capture buffer at + // its own fractional read cursor (linearly interpolated between + // adjacent words), which is what produces the pitch shift, then + // is scaled by its amplitude envelope (Hann, indexed by the + // grain's phase) so grains fade in/out and overlap-add without + // seam clicks. + int32_t word = 0; + for (uint32_t g = 0; g < GRANULAR_MAX_GRAINS; g++) { + if (!self->grains[g].active) { + continue; + } + uint32_t read_index_fp = self->grains[g].read_index; + uint32_t ipart = read_index_fp >> GRANULAR_PITCH_READ_SHIFT; + uint32_t frac = read_index_fp & ((1 << GRANULAR_PITCH_READ_SHIFT) - 1); + uint32_t i0 = ipart % self->capture_len; + uint32_t i1 = (ipart + 1) % self->capture_len; + int32_t s0 = capture_buffer[i0 + self->capture_len * buf_offset]; + int32_t s1 = capture_buffer[i1 + self->capture_len * buf_offset]; + int32_t grain_out = s0 + (((s1 - s0) * (int32_t)frac) >> GRANULAR_PITCH_READ_SHIFT); + // Apply the grain envelope (Q15). phase < length == envelope_len. + int32_t env = self->envelope_table[self->grains[g].phase]; + word += (grain_out * env) >> 15; + } + + // Normalize the overlap-add gain of the enveloped grains back to + // ~unity (int64 guards the Q15 multiply against overflow). This is + // the fully-wet (pitch-shifted) sample. + word = (int32_t)(((int64_t)word * (int64_t)self->grain_gain) >> 15); + + // Dry/wet crossfade: `mix` is doubled to 0.0..2.0 so both terms + // sit at full gain around the midpoint, then synthio_mix_down_sample + // scales/soft-clips the summed pair back into range (same curve as + // PitchShift). mix=0.0 -> dry input, mix=1.0 -> fully wet. + word = (int32_t)((sample_word * MIN(MICROPY_FLOAT_CONST(2.0) - mix, MICROPY_FLOAT_CONST(1.0))) + (word * MIN(mix, MICROPY_FLOAT_CONST(1.0)))); + word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); + + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + word_buffer[i] = (int16_t)word; + if (!self->base.samples_signed) { + word_buffer[i] ^= 0x8000; + } + } else { + int8_t mixed = (int8_t)word; + if (self->base.samples_signed) { + hword_buffer[i] = mixed; + } else { + hword_buffer[i] = (uint8_t)mixed ^ 0x80; + } + } + + // Per-frame shared work (once per frame: mono every sample, + // interleaved stereo on the right-channel sample) so both + // channels read consistent grain state before it advances. + if (self->base.channel_count == 1 || buf_offset) { + // Advance and retire active grains (they were read above). + for (uint32_t g = 0; g < GRANULAR_MAX_GRAINS; g++) { + if (!self->grains[g].active) { + continue; + } + self->grains[g].read_index += self->grains[g].read_rate; + self->grains[g].phase++; + if (self->grains[g].phase >= self->grains[g].length) { + self->grains[g].active = false; + } + } + + // Launch a new grain when the scheduler counter elapses. + if (self->samples_until_next_grain == 0) { + granular_pitch_shift_launch_grain(self); + self->samples_until_next_grain = grain_spacing; + } else { + self->samples_until_next_grain--; + } + + // Advance the per-channel write cursor. + self->write_index++; + if (self->write_index >= self->capture_len) { + self->write_index = 0; + } + } + } + + // Update the remaining length and the buffer positions based on how much we wrote into our buffer + length -= n; + word_buffer += n; + hword_buffer += n; + self->sample_remaining_buffer += (n * (self->base.bits_per_sample / 8)); + self->sample_buffer_length -= n; + } + } + + // Finally pass our buffer and length to the calling audio function + *buffer = (uint8_t *)self->buffer[self->last_buf_idx]; + *buffer_length = self->buffer_len; + + return GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/audiodelays/GranularPitchShift.h b/shared-module/audiodelays/GranularPitchShift.h new file mode 100644 index 00000000000..a0d5a309f96 --- /dev/null +++ b/shared-module/audiodelays/GranularPitchShift.h @@ -0,0 +1,95 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// +// SPDX-License-Identifier: MIT +#pragma once + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/synthio/__init__.h" +#include "shared-module/synthio/block.h" + +// Fixed-point fractional bits for grain read cursors and read rate. A grain's +// read_index and read_rate are stored as (words << GRANULAR_PITCH_READ_SHIFT), +// mirroring PITCH_READ_SHIFT from PitchShift.h. +#define GRANULAR_PITCH_READ_SHIFT (8) + +// Maximum number of concurrently active grains. `density` is clamped to this at +// construction so the grain pool is a fixed, deterministic allocation. +#define GRANULAR_MAX_GRAINS (8) + +extern const mp_obj_type_t audiodelays_granular_pitch_shift_type; + +// A single grain: a short, independently-scheduled, enveloped read of the +// capture buffer. Retired when `phase` reaches `length`. +typedef struct { + bool active; + uint32_t read_index; // words << GRANULAR_PITCH_READ_SHIFT into the capture buffer + uint32_t read_rate; // words << GRANULAR_PITCH_READ_SHIFT, the pitch-shift increment + uint32_t phase; // samples elapsed since the grain launched + uint32_t length; // grain length in samples (== grain_size) +} audiodelays_granular_grain_t; + +typedef struct { + audiosample_base_t base; + synthio_block_slot_t semitones; + mp_float_t current_semitones; + synthio_block_slot_t mix; + + // Double playback buffers (what we hand back to the audio component). + int8_t *buffer[2]; + uint8_t last_buf_idx; + uint32_t buffer_len; // max buffer in bytes + + // Current sample source bookkeeping. + uint8_t *sample_remaining_buffer; + uint32_t sample_buffer_length; + + bool loop; + bool more_data; + + // Capture buffer (the delay line grains read from). Always stored as 16-bit + // internally, planar per channel: channel c occupies + // capture_buffer[c * capture_len .. (c + 1) * capture_len). + int16_t *capture_buffer; + uint32_t capture_len; // words per channel + uint32_t write_index; // words, per-channel write cursor (0 .. capture_len) + + // Grain pool + scheduler. + audiodelays_granular_grain_t grains[GRANULAR_MAX_GRAINS]; + uint32_t samples_until_next_grain; + + uint32_t grain_size; // samples per grain + uint32_t density; // number of overlapping grains (<= GRANULAR_MAX_GRAINS) + + // Q15 (0..32768) normalization applied to the enveloped grain sum so the + // overlap-add gain of `density` Hann grains stays ~unity (Hann satisfies + // COLA at these hops with a summed gain of density/2, so the factor is + // 2/density, capped at 1.0 so a single grain is never amplified). + uint32_t grain_gain; + + // Precomputed amplitude envelope (raised-cosine / Hann), Q15 (0..32767), + // indexed directly by a grain's phase (envelope_len == grain_size). + int16_t *envelope_table; + uint32_t envelope_len; + + // Fixed-point read-rate increment computed from `semitones`, applied to each + // launched grain's read_rate. + uint32_t read_rate; // words << GRANULAR_PITCH_READ_SHIFT + + mp_obj_t sample; +} audiodelays_granular_pitch_shift_obj_t; + +void granular_pitch_shift_recalculate_rate(audiodelays_granular_pitch_shift_obj_t *self, mp_float_t semitones); + +void audiodelays_granular_pitch_shift_reset_buffer(audiodelays_granular_pitch_shift_obj_t *self, + bool single_channel_output, + uint8_t channel); + +audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodelays_granular_pitch_shift_obj_t *self, + bool single_channel_output, + uint8_t channel, + uint8_t **buffer, + uint32_t *buffer_length); // length in bytes From 78dc0157822773f13a42c093549903b862152dbd Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 9 Jul 2026 14:59:53 -0500 Subject: [PATCH 637/876] disable for pimoroni_pico_dv_base_w --- .../raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk index 9218192d083..45bea72a65d 100644 --- a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk @@ -19,6 +19,7 @@ CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 CIRCUITPY_PICODVI = 1 +CIRCUITPY_AUDIOWRITER = 0 CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ From 5419c2321566f0b0a4a9761dfb7902d86f7a75a1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 9 Jul 2026 17:03:01 -0400 Subject: [PATCH 638/876] simplify and clarify PWMOut shared resource conflict errors --- ports/mimxrt10xx/common-hal/pwmio/PWMOut.c | 4 ++-- ports/raspberrypi/common-hal/pwmio/PWMOut.c | 4 ++-- ports/stm/common-hal/pwmio/PWMOut.c | 4 ++-- shared-bindings/pwmio/PWMOut.c | 8 +------- shared-bindings/pwmio/PWMOut.h | 2 -- 5 files changed, 7 insertions(+), 15 deletions(-) diff --git a/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c b/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c index e1507c7fc02..169ce096307 100644 --- a/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +++ b/ports/mimxrt10xx/common-hal/pwmio/PWMOut.c @@ -144,7 +144,7 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self, // We want variable frequency but another class has already claim a fixed frequency. if (variable_frequency) { - return PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE; + return PWMOUT_INTERNAL_RESOURCES_IN_USE; } // Another pin is already using this output. @@ -153,7 +153,7 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self, } if (frequency != _pwm_sm_frequencies[flexpwm_index][submodule]) { - return PWMOUT_INVALID_FREQUENCY_ON_PIN; + return PWMOUT_INTERNAL_RESOURCES_IN_USE; } // Submodule is already running at our target frequency and the output diff --git a/ports/raspberrypi/common-hal/pwmio/PWMOut.c b/ports/raspberrypi/common-hal/pwmio/PWMOut.c index 9ceb5a0185d..2a643974291 100644 --- a/ports/raspberrypi/common-hal/pwmio/PWMOut.c +++ b/ports/raspberrypi/common-hal/pwmio/PWMOut.c @@ -78,7 +78,7 @@ pwmout_result_t pwmout_allocate(uint8_t slice, uint8_t ab_channel, bool variable if (target_slice_frequencies[slice] > 0) { // If we want to change frequency then we can't share. if (variable_frequency) { - return PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE; + return PWMOUT_INTERNAL_RESOURCES_IN_USE; } // If the other user wants a variable frequency then we can't share either. if ((slice_variable_frequency & (1 << slice)) != 0) { @@ -86,7 +86,7 @@ pwmout_result_t pwmout_allocate(uint8_t slice, uint8_t ab_channel, bool variable } // If we're both fixed frequency but we don't match target frequencies then we can't share. if (target_slice_frequencies[slice] != frequency) { - return PWMOUT_INVALID_FREQUENCY_ON_PIN; + return PWMOUT_INTERNAL_RESOURCES_IN_USE; } } diff --git a/ports/stm/common-hal/pwmio/PWMOut.c b/ports/stm/common-hal/pwmio/PWMOut.c index ed3bd67e7ec..fe516065fbd 100644 --- a/ports/stm/common-hal/pwmio/PWMOut.c +++ b/ports/stm/common-hal/pwmio/PWMOut.c @@ -74,12 +74,12 @@ pwmout_result_t common_hal_pwmio_pwmout_construct(pwmio_pwmout_obj_t *self, } // If the frequencies are the same it's ok if (tim_frequencies[tim_index] != frequency) { - last_failure = PWMOUT_INVALID_FREQUENCY_ON_PIN; + last_failure = PWMOUT_INTERNAL_RESOURCES_IN_USE; continue; // keep looking } // you can't put a variable frequency on a partially reserved timer if (variable_frequency) { - last_failure = PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE; + last_failure = PWMOUT_INTERNAL_RESOURCES_IN_USE; continue; // keep looking } first_time_setup = false; // skip setting up the timer diff --git a/shared-bindings/pwmio/PWMOut.c b/shared-bindings/pwmio/PWMOut.c index 97dbd2079f7..9619b4b9d6c 100644 --- a/shared-bindings/pwmio/PWMOut.c +++ b/shared-bindings/pwmio/PWMOut.c @@ -25,14 +25,8 @@ void common_hal_pwmio_pwmout_raise_error(pwmout_result_t result) { case PWMOUT_INVALID_FREQUENCY: mp_arg_error_invalid(MP_QSTR_frequency); break; - case PWMOUT_INVALID_FREQUENCY_ON_PIN: - mp_arg_error_invalid(MP_QSTR_frequency); - break; - case PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE: - mp_arg_error_invalid(MP_QSTR_variable_frequency); - break; case PWMOUT_INTERNAL_RESOURCES_IN_USE: - mp_raise_RuntimeError(MP_ERROR_TEXT("Internal resource(s) in use")); + mp_raise_RuntimeError(MP_ERROR_TEXT("Conflicting settings for shared resource")); break; default: case PWMOUT_INITIALIZATION_ERROR: diff --git a/shared-bindings/pwmio/PWMOut.h b/shared-bindings/pwmio/PWMOut.h index d8bab978228..3c3093ae628 100644 --- a/shared-bindings/pwmio/PWMOut.h +++ b/shared-bindings/pwmio/PWMOut.h @@ -15,8 +15,6 @@ typedef enum pwmout_result_t { PWMOUT_OK, PWMOUT_INVALID_PIN, PWMOUT_INVALID_FREQUENCY, - PWMOUT_INVALID_FREQUENCY_ON_PIN, - PWMOUT_VARIABLE_FREQUENCY_NOT_AVAILABLE, PWMOUT_INTERNAL_RESOURCES_IN_USE, PWMOUT_INITIALIZATION_ERROR, } pwmout_result_t; From 7127be45f7dde12e5bc046f6f513bc84f02d501d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 9 Jul 2026 17:19:01 -0400 Subject: [PATCH 639/876] Makefile: xgettext and msgmerge -s deprecated; use --sort-by-file instead --- Makefile | 4 +- locale/circuitpython.pot | 5007 +++++++++++++++++++------------------- 2 files changed, 2507 insertions(+), 2504 deletions(-) diff --git a/Makefile b/Makefile index 175a1b6a302..3fc38581f9b 100644 --- a/Makefile +++ b/Makefile @@ -237,7 +237,7 @@ pseudoxml: all-source: TRANSLATE_CHECK_SUBMODULES=if ! [ -f extmod/ulab/README.md ]; then $(PYTHON) tools/ci_fetch_deps.py translate; fi -TRANSLATE_COMMAND=find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -x locale/synthetic.pot -f- -L C -s --add-location=file --keyword=MP_ERROR_TEXT -o - | sed -e '/"POT-Creation-Date: /d' +TRANSLATE_COMMAND=find $(TRANSLATE_SOURCES) -type d \( $(TRANSLATE_SOURCES_EXC) \) -prune -o -type f \( -iname "*.c" -o -iname "*.h" \) -print | (LC_ALL=C sort) | xgettext -x locale/synthetic.pot -f- -L C --sort-by-file --add-location=file --keyword=MP_ERROR_TEXT -o - | sed -e '/"POT-Creation-Date: /d' locale/circuitpython.pot: all-source $(TRANSLATE_CHECK_SUBMODULES) $(TRANSLATE_COMMAND) > $@ @@ -255,7 +255,7 @@ translate: locale/circuitpython.pot # needed we preserve a rule to do it. .PHONY: msgmerge msgmerge: - for po in $(shell ls locale/*.po); do msgmerge -U $$po -s --no-fuzzy-matching --add-location=file locale/circuitpython.pot; done + for po in $(shell ls locale/*.po); do msgmerge -U $$po --sort-by-file --no-fuzzy-matching --add-location=file locale/circuitpython.pot; done merge-translate: git merge HEAD 1>&2 2> /dev/null; test $$? -eq 128 diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index dcf10e4276f..b5dbf7d6091 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -16,1237 +16,1247 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" -msgstr "" - -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -#: py/obj.c -msgid " File \"%q\"" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" +#: extmod/moddeflate.c +msgid "format" msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" +#: extmod/moddeflate.c +msgid "wbits" msgstr "" -#: main.c -msgid " not found.\n" +#: extmod/modhashlib.c +msgid "hash is final" msgstr "" -#: main.c -msgid " output:\n" +#: extmod/modheapq.c +msgid "heap must be a list" msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modjson.c +msgid "syntax error in JSON" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c +msgid "bits must be 32 or less" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "%d is not a multiple of %d" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" +#: extmod/modre.c +msgid "splitting with sub-captures" msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modre.c +msgid "Error in regex" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" +#: extmod/modzlib.c +msgid "compression header" msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" msgstr "" -#: py/objstr.c -msgid "%q index out of range" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: ports/stm/common-hal/audioio/AudioOut.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c -msgid "%q init failed" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" msgstr "" -#: py/argcheck.c -msgid "%q must be %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c -#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" msgstr "" -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 16, 24, or 32" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" msgstr "" -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 8 or 16" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q must be 8, 16, 24, or 32" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" msgstr "" -#: py/argcheck.c -msgid "%q must be >= %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" msgstr "" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -msgid "%q out of range" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" msgstr "" -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" msgstr "" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" msgstr "" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" msgstr "" -#: py/compile.c -msgid "'await' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" msgstr "" -#: py/compile.c -msgid "'break'/'continue' outside loop" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" msgstr "" -#: py/compile.c -msgid "'data' requires integer arguments" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" msgstr "" -#: py/compile.c -msgid "'label' requires 1 argument" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" msgstr "" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "'return' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "'yield from' inside async function" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" msgstr "" -#: py/compile.c -msgid "'yield' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" msgstr "" -#: py/compile.c -msgid "* arg after **" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" msgstr "" -#: py/compile.c -msgid "*x must be assignment target" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: py/obj.c -msgid ", in %q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" msgstr "" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" msgstr "" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" msgstr "" -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" msgstr "" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" msgstr "" -#: shared-bindings/usb_audio/__init__.c -msgid "At least one of microphone and speaker must be enabled" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" msgstr "" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Audio source error" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" msgstr "" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" msgstr "" -#: main.c -msgid "Auto-reload is off.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" msgstr "" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" msgstr "" -#: ports/zephyr-cp/common-hal/zephyr_display/Display.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "Bit clock and word select must be sequential GPIO pins" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/raspberrypi/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: main.c +msgid "Done" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: main.c +msgid " output:\n" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c -#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c -#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" +#: main.c +msgid "Auto-reload is off.\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" msgstr "" -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" +#: main.c +msgid " not found.\n" msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Cannot record to a file" +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" msgstr "" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "UID:" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." +#: main.c +msgid "soft reboot\n" msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" msgstr "" -#: py/objslice.c -msgid "Cannot subclass slice" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Channel Init Error" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Device Init Error" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." msgstr "" +#: ports/atmel-samd/common-hal/_pew/PewPew.c #: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" msgstr "" -#: ports/raspberrypi/common-hal/sdioio/SDCard.c -msgid "Data pins must be consecutive" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Destination capacity is smaller than destination_length." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: main.c -msgid "Done" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" msgstr "" -#: py/asmxtensa.c -msgid "ERROR: %q %q not word-aligned" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" msgstr "" -#: py/asmxtensa.c -msgid "ERROR: xtensa %q out of range" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c #: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" msgstr "" -#: extmod/modre.c -msgid "Error in regex" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" msgstr "" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" msgstr "" -#: ports/nordic/sd_mutex.c +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c #, c-format -msgid "Failed to acquire mutex, err 0x%04x" +msgid "Bus pin %d is already in use" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" msgstr "" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" msgstr "" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" msgstr "" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." msgstr "" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." msgstr "" -#: py/moderrno.c -msgid "File exists" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." msgstr "" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" +msgid "Update failed" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" msgstr "" -#: shared-bindings/bitops/__init__.c +#: ports/espressif/common-hal/_bleio/__init__.c #, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "" - -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: py/moderrno.c -msgid "Input/output error" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c @@ -1259,3377 +1269,3370 @@ msgstr "" msgid "Insufficient encryption" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c -#: supervisor/shared/settings.c -msgid "Internal error" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +msgid "Peripheral in use" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/espressif/common-hal/mipidsi/Display.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c -#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" msgstr "" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" msgstr "" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" msgstr "" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" msgstr "" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" msgstr "" -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap must have 8 bits per pixel" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap size must match the other bitmaps" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" msgstr "" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." msgstr "" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" msgstr "" #: ports/espressif/common-hal/nvm/ByteArray.c msgid "NVS Error" msgstr "" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c -msgid "No %q pin" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "No DAC on chip" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "No DMA channel found" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" msgstr "" -#: py/moderrno.c -msgid "No space left on device" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" msgstr "" -#: py/moderrno.c -msgid "No such device" +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" msgstr "" -#: py/moderrno.c -msgid "No such file/directory" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "Not playing" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d or %d, not %d" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: ports/raspberrypi/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d, not %d" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" msgstr "" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" msgstr "" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" msgstr "" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" msgstr "" -#: py/moderrno.c -msgid "Operation not permitted" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Operation timed out" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: ports/espressif/common-hal/audiobusio/__init__.c -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -msgid "Peripheral in use" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: py/moderrno.c -msgid "Permission denied" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" +#: ports/raspberrypi/common-hal/busio/SPI.c +msgid "SPI peripheral in use" msgstr "" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "Pin must be on PWM Channel B" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" -msgstr "" - -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" msgstr "" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" msgstr "" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Pull not used when direction is output." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" msgstr "" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" msgstr "" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" msgstr "" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" msgstr "" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/raspberrypi/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error 0x%02x" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" #: ports/stm/common-hal/microcontroller/Processor.c msgid "Temperature read timed out" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." -msgstr "" - -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c -msgid "The sample's %q does not match" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" msgstr "" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Too many channels in sample." +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many displays" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: py/argcheck.c +msgid "'%q' argument required" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c +msgid "argument num/types mismatch" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" +#: py/argcheck.c +msgid "%q must be %d" msgstr "" -#: main.c -msgid "UID:" +#: py/argcheck.c +msgid "%q must be >= %d" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB busy" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." +#: py/argcheck.c +msgid "%q length must be %d-%d" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: py/argcheck.c +msgid "%q length must be >= %d" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: py/argcheck.c +msgid "%q length must be <= %d" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Unable to allocate buffers for signed conversion" +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" msgstr "" -#: py/parse.c -msgid "Unable to init parser" +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" +#: py/builtinhelp.c +msgid "object " msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: py/builtinhelp.c +msgid " is of type %q\n" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c +#: py/builtinhelp.c #, c-format -msgid "Unknown error code %d" +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: py/compile.c +msgid "non-default argument follows default argument" +msgstr "" + +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: py/compile.c +msgid "invalid arch" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: py/compile.c +msgid "'break'/'continue' outside loop" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" +#: py/compile.c +msgid "'return' outside function" msgstr "" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c -#: ports/zephyr-cp/common-hal/busio/I2C.c -#: ports/zephyr-cp/common-hal/busio/SPI.c -#: ports/zephyr-cp/common-hal/busio/UART.c -msgid "Use device tree to define %q devices" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: py/compile.c +msgid "*x must be assignment target" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: py/compile.c +msgid "* arg after **" msgstr "" -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +#: py/compile.c +msgid "too many args" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/compile.c +msgid "'yield' outside function" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/compile.c +msgid "'yield from' inside async function" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/compile.c +msgid "'await' outside function" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/compile.c +msgid "argument name reused" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." +#: py/compile.c +msgid "unknown type" msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: py/compile.c +msgid "'label' requires 1 argument" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/compile.c +msgid "label redefined" msgstr "" -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" +#: py/compile.c +msgid "'align' requires 1 argument" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/compile.c +msgid "'data' requires at least 2 arguments" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/compile.c +msgid "'data' requires integer arguments" msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/emitbc.c +msgid "bytecode overflow" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: py/compile.c -msgid "argument name reused" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "" + +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" msgstr "" -#: py/compile.c -msgid "async for/with outside async function" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/emitnative.c +msgid "conversion to object" msgstr "" #: py/emitnative.c -msgid "binary op %q not implemented" +msgid "local '%q' used before type known" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/emitnative.c +msgid "can't store to '%q'" msgstr "" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/emitnative.c +msgid "'not' not implemented" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/emitnative.c +msgid "can't do unary op of '%q'" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/emitnative.c +msgid "comparison of int and uint" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: py/emitbc.c -msgid "bytecode overflow" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/emitnative.c +msgid "casting" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/emitnative.c +msgid "must raise an object" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +#: py/modbuiltins.c +msgid "chr() arg not in range(0x110000)" msgstr "" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: py/compile.c -msgid "can't assign to expression" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" +#: py/moderrno.c +msgid "Operation not permitted" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to complex" +#: py/moderrno.c +msgid "No such file/directory" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to float" +#: py/moderrno.c +msgid "Input/output error" msgstr "" -#: py/objint.c py/runtime.c -#, c-format -msgid "can't convert %s to int" +#: py/moderrno.c +msgid "Permission denied" msgstr "" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" +#: py/moderrno.c +msgid "File exists" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" +#: py/moderrno.c +msgid "No such device" msgstr "" -#: py/obj.c -msgid "can't convert to complex" +#: py/moderrno.c +msgid "No space left on device" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: py/objtype.c -msgid "can't create instance" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: py/emitnative.c -msgid "can't do unary op of '%q'" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" msgstr "" -#: py/emitnative.c -msgid "can't load from '%q'" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: py/emitnative.c -msgid "can't load with '%q' index" +#: py/obj.c +msgid " File \"%q\", line %d" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/obj.c +msgid " File \"%q\"" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/obj.c +msgid ", in %q\n" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" msgstr "" -#: py/emitnative.c -msgid "can't store '%q'" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: py/emitnative.c -msgid "can't store to '%q'" +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" msgstr "" -#: py/emitnative.c -msgid "can't store with '%q' index" +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/obj.c +msgid "%q indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/obj.c +msgid "object has no len" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" msgstr "" -#: py/compile.c -msgid "cannot emit native code for this architecture" +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" msgstr "" -#: py/emitnative.c -msgid "casting" +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" #: py/objcomplex.c msgid "complex divide by zero" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/objcomplex.c +msgid "0.0 to a complex power" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/objdeque.c +msgid "full" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/objdeque.c +msgid "empty" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/objdict.c +msgid "dict update sequence has wrong length" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/objint.c +msgid "float too big" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/objint.c #, c-format -msgid "data pin #%d in use" +msgid "value must fit in %d byte(s)" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "destination must be an array of type 'h'" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" msgstr "" -#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c -msgid "divide by zero" +#: py/objslice.c +msgid "Cannot subclass slice" msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objstr.c +msgid "bytes value out of range" +msgstr "" + +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" +msgstr "" + +#: py/objstr.c +msgid "empty separator" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/objstr.c +msgid "rsplit(None,n)" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: py/objdeque.c -msgid "empty" +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" #: py/objstr.c -msgid "empty separator" +#, c-format +msgid "unknown conversion specifier %c" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" #: py/objstr.c -msgid "end of format while looking for conversion specifier" +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objstr.c +msgid "%q index out of range" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" #: py/objstr.c -msgid "expected ':' after format specifier" +msgid "invalid format specifier" msgstr "" -#: py/obj.c -msgid "expected tuple/list" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objstr.c +msgid "incomplete format" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: py/objstr.c -msgid "format needs a dict" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: py/objstr.c -msgid "format string didn't convert all arguments" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objstr.c -msgid "format string needs more arguments" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: py/objdeque.c -msgid "full" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/parse.c +msgid "not a constant" msgstr "" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" +#: py/parse.c +msgid "Unable to init parser" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" #: py/persistentcode.c -msgid "incompatible .mpy arch" +msgid "native code in .mpy unsupported" msgstr "" #: py/persistentcode.c -msgid "incompatible .mpy file" +msgid "incompatible .mpy arch" msgstr "" -#: py/objstr.c -msgid "incomplete format" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" msgstr "" -#: py/objstr.c -msgid "incomplete format key" +#: py/qstr.c +msgid "name too long" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/runtime.c +msgid "'%q' object isn't iterable" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/runtime.c +msgid "'%q' object isn't an iterator" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/vm.c +msgid "local variable referenced before assignment" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/vm.c +msgid "opcode" msgstr "" #: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" -msgstr "" - -#: py/emitinlinerv32.c -msgid "invalid RV32 instruction '%q'" +msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" msgstr "" -#: shared-bindings/bitmaptools/__init__.c +#: shared-bindings/_bleio/Adapter.c #, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgid "interval must be in range %s-%s" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -#, c-format -msgid "invalid destination buffer, must be an array of type: %c" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" msgstr "" -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: py/compile.c -msgid "label redefined" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" msgstr "" -#: py/vm.c -msgid "local variable referenced before assignment" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" msgstr "" -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: py/runtime.c -msgid "module '%q' has no attribute '%q'" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: py/builtinimport.c -msgid "module not found" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" msgstr "" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: py/objtype.c -msgid "multiple inheritance not supported" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" msgstr "" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: py/builtinimport.c -msgid "no module named '%q'" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" #: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/obj.c -msgid "object doesn't support item assignment" -msgstr "" - -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" #: shared-bindings/dualbank/__init__.c msgid "offset must be >= 0" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" -msgstr "" - -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: py/vm.c -msgid "opcode" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: py/modstruct.c +#: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "" - -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" -msgstr "" - -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" #: shared-bindings/socketpool/Socket.c msgid "port must be >= 0" msgstr "" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" +msgstr "" + +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: extmod/modre.c -msgid "regex too complex" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: py/objint_longlong.c py/parsenum.c -msgid "result overflows long long storage" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: py/objstr.c -msgid "rsplit(None,n)" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" msgstr "" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: py/objstrunicode.c -#, c-format -msgid "string indices must be integers, not %s" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" msgstr "" -#: py/compile.c -msgid "too many args" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Internal error #%d" msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: py/runtime.c -#, c-format -msgid "too many values to unpack (expected %d)" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/parse.c -msgid "unexpected indent" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" msgstr "" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" msgstr "" -#: py/compile.c -msgid "unknown type" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: py/compile.c -msgid "unknown type '%q'" +#: shared-module/usb/core/Device.c +msgid "No configuration set" msgstr "" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" msgstr "" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: extmod/moddeflate.c -msgid "wbits" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." msgstr "" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" msgstr "" From 6c8a542dd04f4d2a2f01698a8548b079e405d470 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 9 Jul 2026 15:31:39 -0700 Subject: [PATCH 640/876] pimoroni_pico_dv_base_w: disable usb_audio to fit flash The tinyusb bump grows the binary and this board was already at 100.0% of FLASH_FIRMWARE, so it overflowed by 232 bytes. It never opted into usb_audio; it inherited CIRCUITPY_USB_AUDIO=1 from the rp2 port default. Turning it off frees ~9kB. usb_audio is the USB Audio Class device (enumerating to a host as a mic or speaker). The board's own audio path is the I2S DAC on GPIO26/27/28 driven by audiobusio.I2SOut, which is unaffected, as are audiocore, audiomixer, audiomp3, audiopwmio and synthio. The non-W pimoroni_pico_dv_base has more headroom and keeps usb_audio. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../boards/pimoroni_pico_dv_base_w/mpconfigboard.mk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk index 9218192d083..81d43da5b04 100644 --- a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk @@ -20,6 +20,10 @@ CIRCUITPY_WIFI = 1 CIRCUITPY_PICODVI = 1 +# No room: this board fills FLASH_FIRMWARE. Frees ~9kB. Not the board's I2S +# line-out/HDMI audio, which audiobusio still provides. +CIRCUITPY_USB_AUDIO = 0 + CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ -DCYW43_DEFAULT_PIN_WL_HOST_WAKE=24 \ From 8f4943766f5a244286c4926728f99a474e5a5446 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 10 Jul 2026 06:27:43 -0700 Subject: [PATCH 641/876] Advance lib/tinyusb to include the nrfx v2.0.0 fix fcd5a0603 -> 5453ed09f. Picks up hathach/tinyusb#3766, which adds an nrfx v2.0.0 path to hfclk_running() in dcd_nrf5x.c; without it the nordic port does not compile, since CircuitPython pins nrfx v2.0.0 (MDK 8.29.0) and tinyusb's v2 path called nrf_clock_is_running(), added in nrfx 2.1.0. Only other change in the range is a docs line in AGENTS.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- lib/tinyusb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/tinyusb b/lib/tinyusb index fcd5a0603e3..5453ed09f19 160000 --- a/lib/tinyusb +++ b/lib/tinyusb @@ -1 +1 @@ -Subproject commit fcd5a0603e3588cbf4b33f0335da2b630dc76368 +Subproject commit 5453ed09f19af010b6a361562d967cfa30aaadc6 From 51c0e41927dc59e74dc8bbef4e52a65c8c6ce04d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 10 Jul 2026 11:38:04 -0400 Subject: [PATCH 642/876] espressif: accept build-/ arg in decode_backtrace.py Strip a leading "build-" and trailing "/" from the board argument so the build directory name (which tab-completes) can be passed directly. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/espressif/tools/decode_backtrace.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/espressif/tools/decode_backtrace.py b/ports/espressif/tools/decode_backtrace.py index 16cef9e0822..2001482ffd6 100644 --- a/ports/espressif/tools/decode_backtrace.py +++ b/ports/espressif/tools/decode_backtrace.py @@ -10,6 +10,8 @@ import sys board = sys.argv[1] +# Allow `board-name` or `build-board-name/ as the arg, to allow simple tab completion of boardname. +board = board.replace("build-", "").replace("/", "") print(board) elfs = [ From c1e64dbfebbc593898ec4e3f36b372d4404e7709 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 10 Jul 2026 11:38:30 -0400 Subject: [PATCH 643/876] espressif: tear down espcamera before resetting board buses espcamera.Camera registers a device on the shared busio.I2C bus (esp-camera's SCCB reuses the CircuitPython-created I2C port). At VM teardown, cleanup_after_vm() calls reset_board_buses() early, which calls i2c_del_master_bus(). That failed with ESP_ERR_INVALID_STATE because the camera's device was still attached: the camera was only torn down later by its GC finalizer. Add a reset_port_early() port hook, called at the very start of cleanup_after_vm() before reset_board_buses(). It has a MP_WEAK no-op default, and the espressif port implements it to deinit the active camera, releasing its device from the bus in time. esp-camera is a driver-level singleton, so a static live_camera pointer tracks the one live instance; it is set only after esp_camera_init() succeeds and cleared on deinit. esp_camera_deinit() is now guarded so a failed second construction's finalizer cannot tear down the live camera's driver state. The old, mis-ordered esp_camera_deinit() call in reset_port() is removed. Co-Authored-By: Claude Opus 4.8 (1M context) --- main.c | 3 +++ ports/espressif/common-hal/espcamera/Camera.c | 27 ++++++++++++++++++- ports/espressif/common-hal/espcamera/Camera.h | 4 +++ ports/espressif/supervisor/port.c | 14 +++++++--- supervisor/port.h | 3 +++ supervisor/shared/port.c | 3 +++ 6 files changed, 49 insertions(+), 5 deletions(-) diff --git a/main.c b/main.c index ff5238d0c53..3238bd9a08a 100644 --- a/main.c +++ b/main.c @@ -337,6 +337,9 @@ static void count_strn(void *data, const char *str, size_t len) { } static void cleanup_after_vm(mp_obj_t exception) { + // Do any port cleanup needed before anything else, including releasing board buses. + reset_port_early(); + // Get the traceback of any exception from this run off the heap. // MP_OBJ_SENTINEL means "this run does not contribute to traceback storage, don't touch it" // MP_OBJ_NULL (=0) means "this run completed successfully, clear any stored traceback" diff --git a/ports/espressif/common-hal/espcamera/Camera.c b/ports/espressif/common-hal/espcamera/Camera.c index 80111311bb7..c8f693fa3f1 100644 --- a/ports/espressif/common-hal/espcamera/Camera.c +++ b/ports/espressif/common-hal/espcamera/Camera.c @@ -21,6 +21,11 @@ #error espcamera only works on boards configured with spiram, disable it in mpconfigboard.mk #endif +// The underlying esp-camera driver only handles a singleton camera. +// Track it here so it can be reset, releasing its +// device on the shared I2C bus, before the I2C bus is deinited. +static espcamera_camera_obj_t *live_camera = NULL; + static void i2c_lock(espcamera_camera_obj_t *self) { if (common_hal_busio_i2c_deinited(self->i2c)) { raise_deinited_error(); @@ -120,6 +125,16 @@ void common_hal_espcamera_camera_construct( i2c_unlock(self); CHECK_ESP_RESULT(result); + + // Only record the camera once esp_camera_init() has succeeded, so a failed + // second construction doesn't overwrite the live singleton. + live_camera = self; +} + +void espcamera_reset(void) { + if (live_camera != NULL) { + common_hal_espcamera_camera_deinit(live_camera); + } } extern void common_hal_espcamera_camera_deinit(espcamera_camera_obj_t *self) { @@ -127,6 +142,14 @@ extern void common_hal_espcamera_camera_deinit(espcamera_camera_obj_t *self) { return; } + // Only tear down the shared esp-camera driver if this object owns it. A + // second, failed construction leaves live_camera pointing at the first + // camera; deiniting that failed object must not destroy the live one. + bool was_live = (live_camera == self); + if (was_live) { + live_camera = NULL; + } + common_hal_pwmio_pwmout_deinit(&self->pwm); // Does nothing if pin is NO_PIN (-1). @@ -143,7 +166,9 @@ extern void common_hal_espcamera_camera_deinit(espcamera_camera_obj_t *self) { reset_pin_number(self->camera_config.pin_d1); reset_pin_number(self->camera_config.pin_d0); - esp_camera_deinit(); + if (was_live) { + esp_camera_deinit(); + } reset_pin_number(self->camera_config.pin_pclk); reset_pin_number(self->camera_config.pin_vsync); diff --git a/ports/espressif/common-hal/espcamera/Camera.h b/ports/espressif/common-hal/espcamera/Camera.h index 718fe9a69c4..dd099558aa6 100644 --- a/ports/espressif/common-hal/espcamera/Camera.h +++ b/ports/espressif/common-hal/espcamera/Camera.h @@ -18,3 +18,7 @@ typedef struct espcamera_camera_obj { pwmio_pwmout_obj_t pwm; busio_i2c_obj_t *i2c; } espcamera_obj_t; + +// Deinitialize the active camera, if any, so it releases its device on the +// shared I2C bus. Called from reset_port_early(). +void espcamera_reset(void); diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 287fe54cc05..0d47f7ecd19 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -52,7 +52,7 @@ #endif #if CIRCUITPY_ESPCAMERA -#include "esp_camera.h" +#include "common-hal/espcamera/Camera.h" #endif #if CIRCUITPY_RCLCPY @@ -346,11 +346,17 @@ size_t port_heap_get_largest_free_size(void) { return free_size; } -void reset_port(void) { - // TODO deinit for esp32-camera +void reset_port_early(void) { + // esp-camera adds an I2C device on the ESP I2C bus, and keeps it there. This + // is unlike busio.I2C, which adds and removes the device on each operation. + // So have the esp-camera API shut down the camera now, before reset_board_buses() tries to delete the I2C bus. + // Unfortunately, there is no I2C driver API to enumerate or delete all the devices. #if CIRCUITPY_ESPCAMERA - esp_camera_deinit(); + espcamera_reset(); #endif +} + +void reset_port(void) { #if CIRCUITPY_SSL ssl_reset(); diff --git a/supervisor/port.h b/supervisor/port.h index f0e13e167cc..2437edafb14 100644 --- a/supervisor/port.h +++ b/supervisor/port.h @@ -26,6 +26,9 @@ safe_mode_t port_init(void); // Reset the microcontroller completely. void reset_cpu(void) MP_NORETURN; +// Reset port state that must be torn down before anything else is reset. +void reset_port_early(void); + // Reset the microcontroller state. void reset_port(void); diff --git a/supervisor/shared/port.c b/supervisor/shared/port.c index 3c95f2b7409..15b0751c757 100644 --- a/supervisor/shared/port.c +++ b/supervisor/shared/port.c @@ -21,6 +21,9 @@ static tlsf_t heap; +MP_WEAK void reset_port_early(void) { +} + MP_WEAK void port_wake_main_task(void) { } From 65ee5f9fb2f69f908848e105509b35b740e0ce1b Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 10 Jul 2026 10:44:24 -0700 Subject: [PATCH 644/876] usb_audio: drop dead tusb_config defines left by the tinyusb bump The UAC2 driver bump stopped reading several CFG_TUD_AUDIO_FUNC_1_* macros (it walks the descriptor itself now). Remove the ones that went dead: DESC_LEN, N_AS_INT, N_BYTES_PER_SAMPLE_TX/RX, N_CHANNELS_TX/RX. CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ was silently orphaned too -- the driver now reads CFG_TUD_AUDIO_CTRL_BUF_SZ (no _FUNC_1_), falling back to its own default of 64. Rename ours so CP keeps setting 64 explicitly. usb_audio_descriptor_length() stays: usb_desc.c still calls it to size total_descriptor_length. Rewrote the stale usb_audio_descriptors.h comment that claimed TinyUSB reads the now-removed DESC_LEN macro. Verified with clean CIRCUITPY_USB_AUDIO=1 builds of adafruit_feather_rp2350 and feather_bluefruit_sense. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../usb_audio/usb_audio_descriptors.h | 17 +++++++-------- supervisor/shared/usb/tusb_config.h | 21 +------------------ 2 files changed, 9 insertions(+), 29 deletions(-) diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 642246f9ca7..18d72dcabc5 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -13,15 +13,14 @@ // (to size the IN endpoint) as well as from the descriptor/binding code. // Actual length, in bytes, of the audio function descriptor emitted for the -// current direction (mic, speaker, or headset). Declared here -- in the -// dependency-free header tusb_config.h already includes -- because TinyUSB's -// audio class driver reads CFG_TUD_AUDIO_FUNC_1_DESC_LEN at enumeration time and -// returns it to the device core as the number of configuration-descriptor bytes -// the function owns. That value MUST equal the descriptor we actually emitted: -// the three directions differ in length, so a compile-time maximum would over- -// report for the shorter ones and make the core swallow the interfaces that -// follow audio (CDC/MSC), breaking their enumeration. The full definition lives -// in __init__.c (also declared in __init__.h for the descriptor builder). +// current direction (mic, speaker, or headset). usb_desc.c reads this while +// assembling the configuration descriptor, adding it to total_descriptor_length +// so wTotalLength covers the exact bytes the audio function emits. That value +// MUST equal the descriptor we actually emitted: the three directions differ in +// length, so a compile-time maximum would over-report for the shorter ones and +// make the host swallow the interfaces that follow audio (CDC/MSC), breaking +// their enumeration. The full definition lives in __init__.c (also declared in +// __init__.h for the descriptor builder). size_t usb_audio_descriptor_length(void); // The isochronous IN endpoint's wMaxPacketSize in the USB descriptor is computed diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index a34d22d5409..ac63542b8e4 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -122,27 +122,10 @@ extern "C" { #if CIRCUITPY_USB_AUDIO #include "shared-module/usb_audio/usb_audio_descriptors.h" -// Single audio function. The emitted descriptor is chosen at boot from the -// stored direction: a mic (1 AS interface, IN endpoint), a speaker (1 AS -// interface, OUT endpoint), or a combined headset (2 AS interfaces, one IN and -// one OUT endpoint). The class driver returns this length to the device core as -// the span of config descriptor the function owns, so it must equal the -// descriptor we actually emitted -- the three directions differ in length, so a -// compile-time maximum would over-report for the shorter ones and make the core -// skip the interfaces that follow audio. usb_audio_descriptor_length() returns -// the live length for the stored direction; it is only read at enumeration time -// (audiod_open), by which point usb_audio.enable() has fixed the direction. -#define CFG_TUD_AUDIO_FUNC_1_DESC_LEN usb_audio_descriptor_length() -// The headset presents two AudioStreaming interfaces; the single-direction -// descriptors use only the first. The class driver sizes its per-interface alt -// tracking from this, so it must cover the largest case. -#define CFG_TUD_AUDIO_FUNC_1_N_AS_INT 2 // EP0 buffer for class-specific control requests (sample-freq range, volume range, ...). -#define CFG_TUD_AUDIO_FUNC_1_CTRL_BUF_SZ 64 +#define CFG_TUD_AUDIO_CTRL_BUF_SZ 64 #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 -#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_TX USB_AUDIO_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_TX USB_AUDIO_N_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. @@ -153,8 +136,6 @@ extern "C" { // descriptor (still mic-only until the speaker descriptor lands). Mirrors the // IN sizing above. #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 -#define CFG_TUD_AUDIO_FUNC_1_N_BYTES_PER_SAMPLE_RX USB_AUDIO_N_BYTES_PER_SAMPLE -#define CFG_TUD_AUDIO_FUNC_1_N_CHANNELS_RX USB_AUDIO_N_CHANNELS // wMaxPacketSize, sized for the highest supported sample rate. #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms drain keeps clear of the overrun ceiling. From c5c0603568169df1e51a4b12170679df5f7bba7e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 10 Jul 2026 14:32:39 -0400 Subject: [PATCH 645/876] espressif/_bleio: use a FreeRTOS queue for discovery staging Per review, replace the interrupt-guarded ringbuf with a FreeRTOS queue, the RTOS-native primitive for task-to-task message passing. xQueueSend(), xQueueReceive(), and xQueueReset() are thread-safe by construction, so the hand-rolled critical sections go away, along with the port_malloc() storage management: the queue is created lazily from the FreeRTOS (IDF) heap on first use and never deleted. Queue-full still maps to BLE_HS_ENOMEM, and the drain loop and error handling are unchanged. Co-Authored-By: Claude Fable 5 --- .../espressif/common-hal/_bleio/Connection.c | 138 ++++++++---------- 1 file changed, 60 insertions(+), 78 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 131a89bc9ee..91d2336ee68 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -14,7 +14,6 @@ #include "py/objlist.h" #include "py/objstr.h" #include "py/qstr.h" -#include "py/ringbuf.h" #include "py/runtime.h" #include "shared/runtime/interrupt_char.h" @@ -25,14 +24,15 @@ #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" -#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/time/__init__.h" -#include "supervisor/port_heap.h" #include "supervisor/shared/tick.h" #include "common-hal/_bleio/ble_events.h" +#include "freertos/FreeRTOS.h" +#include "freertos/queue.h" + #include "host/ble_att.h" // Uncomment to turn on debug logging just in this file. @@ -212,59 +212,43 @@ static void _check_discovery_status(int status) { // not allocate from the MicroPython heap: an allocation there can trigger a // gc_collect() that scans the wrong task's stack and frees the VM's live // objects. Instead the callbacks copy the plain NimBLE result struct into this -// ring (a non-allocating memcpy), and the VM task drains it and builds the -// Python objects. See shared-module/_bleio/ScanResults.c for the same pattern. +// FreeRTOS queue, and the VM task drains it and builds the Python objects. // // Discovery is serialized (one discover_remote_services() at a time), so a -// single file-static ring suffices. It must hold one ATT-PDU burst of records: +// single file-static queue suffices. It must hold one ATT-PDU burst of records: // within a response PDU the host task invokes the callback repeatedly without -// yielding, so the VM task cannot drain until the next PDU's round-trip. +// yielding, so the VM task cannot drain until the next PDU's round-trip. The +// largest burst is a find-information response at the maximum ATT MTU we +// advertise (CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU, 256): about 64 descriptor +// records. The depth is twice that. // -// The storage is allocated on first use from the port (IDF) heap, not the GC +// The queue is created on first use from the FreeRTOS (IDF) heap, not the GC // heap, so it needs no GC root and survives soft reloads: a stale procedure's -// pushes always land in live memory. It is never freed. (Same pattern as the -// port_malloc-backed ringbuf in shared-module/keypad/EventQueue.c.) -#define DISCOVERY_RING_SIZE (4096) -static uint8_t *_discovery_ring_buffer; -static ringbuf_t _discovery_ring; - -// Stage one fixed-size record. Runs on the nimble_host task. -// ringbuf ops are not atomic and the two tasks preempt each other, so guard -// with interrupts disabled; the guarded region is a single small record copy. -static bool _push_record(const void *record, size_t size) { - common_hal_mcu_disable_interrupts(); - bool ok = ringbuf_num_empty(&_discovery_ring) >= size; - if (ok) { - ringbuf_put_n(&_discovery_ring, (const uint8_t *)record, size); - } - common_hal_mcu_enable_interrupts(); - return ok; -} - -// Retrieve one fixed-size record. Runs on the VM task. -static bool _pop_record(void *record, size_t size) { - common_hal_mcu_disable_interrupts(); - bool ok = ringbuf_num_filled(&_discovery_ring) >= size; - if (ok) { - ringbuf_get_n(&_discovery_ring, (uint8_t *)record, size); - } - common_hal_mcu_enable_interrupts(); - return ok; -} - -// Reset the ring before a discovery step. Runs on the VM task. Guarded because -// a stale procedure from a previous errored, timed-out, or interrupted -// discovery may still be pushing records on the nimble_host task. -static void _reset_discovery_ring(void) { - if (_discovery_ring_buffer == NULL) { - _discovery_ring_buffer = port_malloc(DISCOVERY_RING_SIZE, false); - if (_discovery_ring_buffer == NULL) { - m_malloc_fail(DISCOVERY_RING_SIZE); +// sends always land in live memory. It is never deleted. + +// One queue item, sized to the largest record type, so one queue can serve every +// discovery step. +typedef union { + struct ble_gatt_svc svc; + struct ble_gatt_chr chr; + struct ble_gatt_dsc dsc; +} discovery_record_t; + +#define DISCOVERY_QUEUE_DEPTH (128) +static QueueHandle_t _discovery_queue; + +// Create the queue on first use, and empty it before a discovery step. Runs on +// the VM task. xQueueReset() is safe against a stale procedure from a previous +// errored, timed-out, or interrupted discovery that may still be sending +// records on the nimble_host task. +static void _reset_discovery_queue(void) { + if (_discovery_queue == NULL) { + _discovery_queue = xQueueCreate(DISCOVERY_QUEUE_DEPTH, sizeof(discovery_record_t)); + if (_discovery_queue == NULL) { + m_malloc_fail(DISCOVERY_QUEUE_DEPTH * sizeof(discovery_record_t)); } } - common_hal_mcu_disable_interrupts(); - ringbuf_init(&_discovery_ring, _discovery_ring_buffer, DISCOVERY_RING_SIZE); - common_hal_mcu_enable_interrupts(); + xQueueReset(_discovery_queue); } static int _discovered_service_cb(uint16_t conn_handle, @@ -283,7 +267,8 @@ static int _discovered_service_cb(uint16_t conn_handle, } // Runs on the nimble_host task: stage the raw result only, never allocate. - if (!_push_record(svc, sizeof(*svc))) { + discovery_record_t record = { .svc = *svc }; + if (xQueueSend(_discovery_queue, &record, 0) != pdTRUE) { _set_discovery_step_status(BLE_HS_ENOMEM); } return 0; @@ -305,7 +290,8 @@ static int _discovered_characteristic_cb(uint16_t conn_handle, } // Runs on the nimble_host task: stage the raw result only, never allocate. - if (!_push_record(chr, sizeof(*chr))) { + discovery_record_t record = { .chr = *chr }; + if (xQueueSend(_discovery_queue, &record, 0) != pdTRUE) { _set_discovery_step_status(BLE_HS_ENOMEM); } return 0; @@ -328,7 +314,8 @@ static int _discovered_descriptor_cb(uint16_t conn_handle, } // Runs on the nimble_host task: stage the raw result only, never allocate. - if (!_push_record(dsc, sizeof(*dsc))) { + discovery_record_t record = { .dsc = *dsc }; + if (xQueueSend(_discovery_queue, &record, 0) != pdTRUE) { _set_discovery_step_status(BLE_HS_ENOMEM); } return 0; @@ -359,30 +346,25 @@ static void _build_service(void *ctx, const void *record) { } // Drain and build all staged records on the VM task, until the step completes -// and the ring is empty. build() is invoked for each raw record with ctx passed -// through. Returns the discovery step status. -static int _drain_records(void *ctx, size_t record_size, +// and the queue is empty. build() is invoked for each raw record with ctx +// passed through. Returns the discovery step status. +static int _drain_records(void *ctx, void (*build)(void *ctx, const void *record)) { const uint64_t timeout_time_ms = common_hal_time_monotonic_ms() + DISCOVERY_TIMEOUT_MS; - // Sized to the largest record type so one buffer serves every step. - union { - struct ble_gatt_svc svc; - struct ble_gatt_chr chr; - struct ble_gatt_dsc dsc; - } record; + discovery_record_t record; while (true) { - if (_pop_record(&record, record_size)) { + if (xQueueReceive(_discovery_queue, &record, 0) == pdTRUE) { build(ctx, &record); continue; } - // Ring is empty. + // Queue is empty. if (_last_discovery_status != 0) { // On EDONE or a NimBLE error, the terminal callback has already // run, so no more records will arrive: drain any that raced in, - // then stop. On ENOMEM (our own push failure) the procedure may + // then stop. On ENOMEM (our own send failure) the procedure may // still be running, but we are raising anyway; any later - // discovery resets the ring before reuse. - while (_pop_record(&record, record_size)) { + // discovery resets the queue before reuse. + while (xQueueReceive(_discovery_queue, &record, 0) == pdTRUE) { build(ctx, &record); } return _last_discovery_status; @@ -486,14 +468,14 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t self->remote_service_list = mp_obj_new_list(0, NULL); if (service_uuids_whitelist == mp_const_none) { - // Reset discovery status and staging ring before starting callbacks. + // Reset discovery status and staging queue before starting callbacks. _set_discovery_step_status(0); - _reset_discovery_ring(); + _reset_discovery_queue(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_svcs(self->conn_handle, _discovered_service_cb, self)); // Drain staged services and build them on the VM task until done. - int status = _drain_records(self, sizeof(struct ble_gatt_svc), _build_service); + int status = _drain_records(self, _build_service); _check_discovery_status(status); } else { mp_obj_iter_buf_t iter_buf; @@ -505,15 +487,15 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t } bleio_uuid_obj_t *uuid = MP_OBJ_TO_PTR(uuid_obj); - // Reset discovery status and staging ring before starting callbacks. + // Reset discovery status and staging queue before starting callbacks. _set_discovery_step_status(0); - _reset_discovery_ring(); + _reset_discovery_queue(); CHECK_NIMBLE_ERROR(ble_gattc_disc_svc_by_uuid(self->conn_handle, &uuid->nimble_ble_uuid.u, _discovered_service_cb, self)); // Drain staged services and build them on the VM task until done. - int status = _drain_records(self, sizeof(struct ble_gatt_svc), _build_service); + int status = _drain_records(self, _build_service); _check_discovery_status(status); } } @@ -522,9 +504,9 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t for (size_t i = 0; i < self->remote_service_list->len; i++) { bleio_service_obj_t *service = MP_OBJ_TO_PTR(self->remote_service_list->items[i]); - // Reset discovery status and staging ring before starting callbacks. + // Reset discovery status and staging queue before starting callbacks. _set_discovery_step_status(0); - _reset_discovery_ring(); + _reset_discovery_queue(); CHECK_NIMBLE_ERROR(ble_gattc_disc_all_chrs(self->conn_handle, service->start_handle, @@ -533,7 +515,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t service)); // Drain staged characteristics and build them on the VM task until done. - int status = _drain_records(service, sizeof(struct ble_gatt_chr), _build_characteristic); + int status = _drain_records(service, _build_characteristic); _check_discovery_status(status); // Got characteristics for this service. Now discover descriptors for each characteristic. @@ -558,9 +540,9 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t continue; } - // Reset discovery status and staging ring before starting callbacks. + // Reset discovery status and staging queue before starting callbacks. _set_discovery_step_status(0); - _reset_discovery_ring(); + _reset_discovery_queue(); // The descriptor handle inclusive range is [characteristic->handle + 1, end_handle], // but ble_gattc_disc_all_dscs() requires starting with characteristic->handle. @@ -569,7 +551,7 @@ static void discover_remote_services(bleio_connection_internal_t *self, mp_obj_t _discovered_descriptor_cb, characteristic)); // Drain staged descriptors and build them on the VM task until done. - status = _drain_records(characteristic, sizeof(struct ble_gatt_dsc), _build_descriptor); + status = _drain_records(characteristic, _build_descriptor); _check_discovery_status(status); } } From 9fd8e3fe314970b2e19ca9e49058acd4fedec4d0 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 10 Jul 2026 14:16:16 -0500 Subject: [PATCH 646/876] move to audiofilewriter.AudioFileWriter --- locale/circuitpython.pot | 6 +- main.c | 8 +- ports/espressif/mpconfigport.mk | 2 +- .../pimoroni_pico_dv_base_w/mpconfigboard.mk | 2 +- ports/raspberrypi/mpconfigport.mk | 2 +- py/circuitpy_defns.mk | 8 +- py/circuitpy_mpconfig.mk | 4 +- .../AudioFileWriter.c} | 86 +++++++++---------- .../audiofilewriter/AudioFileWriter.h | 23 +++++ shared-bindings/audiofilewriter/__init__.c | 29 +++++++ .../__init__.h | 0 shared-bindings/audiowriter/AudioWriter.h | 23 ----- shared-bindings/audiowriter/__init__.c | 29 ------- .../AudioFileWriter.c} | 72 ++++++++-------- .../AudioFileWriter.h} | 12 +-- .../__init__.c | 0 supervisor/shared/tick.c | 8 +- 17 files changed, 157 insertions(+), 157 deletions(-) rename shared-bindings/{audiowriter/AudioWriter.c => audiofilewriter/AudioFileWriter.c} (59%) create mode 100644 shared-bindings/audiofilewriter/AudioFileWriter.h create mode 100644 shared-bindings/audiofilewriter/__init__.c rename shared-bindings/{audiowriter => audiofilewriter}/__init__.h (100%) delete mode 100644 shared-bindings/audiowriter/AudioWriter.h delete mode 100644 shared-bindings/audiowriter/__init__.c rename shared-module/{audiowriter/AudioWriter.c => audiofilewriter/AudioFileWriter.c} (83%) rename shared-module/{audiowriter/AudioWriter.h => audiofilewriter/AudioFileWriter.h} (88%) rename shared-module/{audiowriter => audiofilewriter}/__init__.c (100%) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index b3ce45404c9..e480912e721 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -587,7 +587,7 @@ msgid "Already have all-matches listener" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c -#: shared-module/audiowriter/AudioWriter.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Already in progress" msgstr "" @@ -1739,7 +1739,7 @@ msgstr "" msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: shared-module/audiowriter/AudioWriter.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Only 8/16-bit mono/stereo is supported" msgstr "" @@ -2794,7 +2794,7 @@ msgstr "" msgid "buffer too small for requested bytes" msgstr "" -#: shared-module/audiowriter/AudioWriter.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "buffer_size too small for source" msgstr "" diff --git a/main.c b/main.c index cfd6d140cea..135195f2d51 100644 --- a/main.c +++ b/main.c @@ -84,8 +84,8 @@ #include "shared-module/keypad/__init__.h" #endif -#if CIRCUITPY_AUDIOWRITER -#include "shared-module/audiowriter/AudioWriter.h" +#if CIRCUITPY_AUDIOFILEWRITER +#include "shared-module/audiofilewriter/AudioFileWriter.h" #endif #if CIRCUITPY_MEMORYMONITOR @@ -400,8 +400,8 @@ static void cleanup_after_vm(mp_obj_t exception) { keypad_reset(); #endif - #if CIRCUITPY_AUDIOWRITER - audiowriter_reset(); + #if CIRCUITPY_AUDIOFILEWRITER + audiofilewriter_reset(); #endif // Close user-initiated sockets. diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 57cef1917ad..bbe815af468 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -336,7 +336,7 @@ CIRCUITPY_MIPIDSI = 1 else ifeq ($(IDF_TARGET),esp32s2) # Modules CIRCUITPY_AUDIOIO ?= 1 -CIRCUITPY_AUDIOWRITER ?= 1 +CIRCUITPY_AUDIOFILEWRITER ?= 1 # No I2S peripheral PDM-to-PCM hardware support CIRCUITPY_AUDIOBUSIO_PDMIN = 0 diff --git a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk index 45bea72a65d..d380732afc1 100644 --- a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk @@ -19,7 +19,7 @@ CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 CIRCUITPY_PICODVI = 1 -CIRCUITPY_AUDIOWRITER = 0 +CIRCUITPY_AUDIOFILEWRITER = 0 CFLAGS += \ -DCYW43_PIN_WL_DYNAMIC=0 \ diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 1b2d276145f..f4c6e809ba0 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -13,7 +13,7 @@ CIRCUITPY_FULL_BUILD ?= 1 CIRCUITPY_AUDIOMP3 ?= 1 CIRCUITPY_AUDIOSPEED ?= 1 CIRCUITPY_AUDIOEFFECTS ?= 1 -CIRCUITPY_AUDIOWRITER ?= 1 +CIRCUITPY_AUDIOFILEWRITER ?= 1 CIRCUITPY_BITOPS ?= 1 CIRCUITPY_HASHLIB ?= 1 CIRCUITPY_HASHLIB_MBEDTLS ?= 1 diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 453328861e7..63a874b094e 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -152,8 +152,8 @@ endif ifeq ($(CIRCUITPY_AUDIOSPEED),1) SRC_PATTERNS += audiospeed/% endif -ifeq ($(CIRCUITPY_AUDIOWRITER),1) -SRC_PATTERNS += audiowriter/% +ifeq ($(CIRCUITPY_AUDIOFILEWRITER),1) +SRC_PATTERNS += audiofilewriter/% endif ifeq ($(CIRCUITPY_AURORA_EPAPER),1) SRC_PATTERNS += aurora_epaper/% @@ -721,8 +721,8 @@ SRC_SHARED_MODULE_ALL = \ audiofilters/__init__.c \ audiofreeverb/__init__.c \ audiofreeverb/Freeverb.c \ - audiowriter/AudioWriter.c \ - audiowriter/__init__.c \ + audiofilewriter/AudioFileWriter.c \ + audiofilewriter/__init__.c \ audioio/__init__.c \ audiomixer/Mixer.c \ audiomixer/MixerVoice.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index d9b2d35dd05..62943cff3ad 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -174,8 +174,8 @@ CFLAGS += -DCIRCUITPY_AUDIOFILTERS=$(CIRCUITPY_AUDIOFILTERS) CIRCUITPY_AUDIOFREEVERB ?= $(CIRCUITPY_AUDIOEFFECTS) CFLAGS += -DCIRCUITPY_AUDIOFREEVERB=$(CIRCUITPY_AUDIOFREEVERB) -CIRCUITPY_AUDIOWRITER ?= 0 -CFLAGS += -DCIRCUITPY_AUDIOWRITER=$(CIRCUITPY_AUDIOWRITER) +CIRCUITPY_AUDIOFILEWRITER ?= 0 +CFLAGS += -DCIRCUITPY_AUDIOFILEWRITER=$(CIRCUITPY_AUDIOFILEWRITER) CIRCUITPY_AURORA_EPAPER ?= 0 CFLAGS += -DCIRCUITPY_AURORA_EPAPER=$(CIRCUITPY_AURORA_EPAPER) diff --git a/shared-bindings/audiowriter/AudioWriter.c b/shared-bindings/audiofilewriter/AudioFileWriter.c similarity index 59% rename from shared-bindings/audiowriter/AudioWriter.c rename to shared-bindings/audiofilewriter/AudioFileWriter.c index d6ad33f1a54..51b63d834aa 100644 --- a/shared-bindings/audiowriter/AudioWriter.c +++ b/shared-bindings/audiofilewriter/AudioFileWriter.c @@ -9,16 +9,16 @@ #include "shared/runtime/context_manager_helpers.h" #include "py/objproperty.h" #include "py/runtime.h" -#include "shared-bindings/audiowriter/AudioWriter.h" +#include "shared-bindings/audiofilewriter/AudioFileWriter.h" #include "shared-bindings/util.h" // ~1 s of 16 kHz mono 16-bit PCM. Sized to absorb a worst-case SD-write stall. -#define AUDIOWRITER_DEFAULT_BUFFER_SIZE (32 * 1024) +#define AUDIOFILEWRITER_DEFAULT_BUFFER_SIZE (32 * 1024) -//| class AudioWriter: +//| class AudioFileWriter: //| """Streams an audio source to a ``.wav`` file in the background. //| -//| ``AudioWriter`` is the inverse of `audiocore.WaveFile`: rather than being +//| ``AudioFileWriter`` is the inverse of `audiocore.WaveFile`: rather than being //| an audio *source* played by an `audioio.AudioOut`, it is a *sink* that //| drives an audio source (a microphone, ``synthio``, or an ``audiofilters``/ //| ``audiodelays``/``audiofreeverb``/``audiospeed`` effect chain) and writes @@ -28,12 +28,12 @@ //| so it does not block and does not require a Python read loop.""" //| //| def __init__(self, file: typing.BinaryIO, *, buffer_size: int = 32768) -> None: -//| """Create an ``AudioWriter`` that writes to ``file``. +//| """Create an ``AudioFileWriter`` that writes to ``file``. //| //| :param typing.BinaryIO file: An already-open writable binary stream //| (a file opened in ``"wb"`` mode, or an `io.BytesIO`). The stream must //| support seeking so the WAV header sizes can be patched when recording -//| stops. ``AudioWriter`` does not close it; the caller owns it. +//| stops. ``AudioFileWriter`` does not close it; the caller owns it. //| :param int buffer_size: Size in bytes of the internal RAM ring that //| decouples file-write latency from the source. Larger values tolerate //| longer write stalls (e.g. a slow SD card) at the cost of RAM. @@ -45,7 +45,7 @@ //| //| import time //| import synthio -//| from audiowriter import AudioWriter +//| from audiofilewriter import AudioFileWriter //| import storage //| //| SAMPLE_RATE = 16000 @@ -55,7 +55,7 @@ //| synth = synthio.Synthesizer(sample_rate=SAMPLE_RATE) //| //| with open(OUTPUT_PATH, "wb") as f: -//| writer = AudioWriter(f) +//| writer = AudioFileWriter(f) //| writer.play(synth) //| for note in C_major_scale: //| synth.press(note) @@ -67,11 +67,11 @@ //| """ //| ... //| -static mp_obj_t audiowriter_audiowriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { +static mp_obj_t audiofilewriter_audiofilewriter_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { enum { ARG_file, ARG_buffer_size }; static const mp_arg_t allowed_args[] = { { MP_QSTR_file, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = MP_OBJ_NULL} }, - { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = AUDIOWRITER_DEFAULT_BUFFER_SIZE} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = AUDIOFILEWRITER_DEFAULT_BUFFER_SIZE} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); @@ -79,14 +79,14 @@ static mp_obj_t audiowriter_audiowriter_make_new(const mp_obj_type_t *type, size // A buffer smaller than one source buffer is useless; require a sane floor. mp_int_t buffer_size = mp_arg_validate_int_min(args[ARG_buffer_size].u_int, 512, MP_QSTR_buffer_size); - audiowriter_audiowriter_obj_t *self = mp_obj_malloc(audiowriter_audiowriter_obj_t, &audiowriter_audiowriter_type); - common_hal_audiowriter_audiowriter_construct(self, args[ARG_file].u_obj, (uint32_t)buffer_size); + audiofilewriter_audiofilewriter_obj_t *self = mp_obj_malloc(audiofilewriter_audiofilewriter_obj_t, &audiofilewriter_audiofilewriter_type); + common_hal_audiofilewriter_audiofilewriter_construct(self, args[ARG_file].u_obj, (uint32_t)buffer_size); return MP_OBJ_FROM_PTR(self); } -static void check_for_deinit(audiowriter_audiowriter_obj_t *self) { - if (common_hal_audiowriter_audiowriter_deinited(self)) { +static void check_for_deinit(audiofilewriter_audiofilewriter_obj_t *self) { + if (common_hal_audiofilewriter_audiofilewriter_deinited(self)) { raise_deinited_error(); } } @@ -95,14 +95,14 @@ static void check_for_deinit(audiowriter_audiowriter_obj_t *self) { //| """Stops recording (patching the WAV header) and releases resources.""" //| ... //| -static mp_obj_t audiowriter_audiowriter_deinit(mp_obj_t self_in) { - audiowriter_audiowriter_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audiowriter_audiowriter_deinit(self); +static mp_obj_t audiofilewriter_audiofilewriter_deinit(mp_obj_t self_in) { + audiofilewriter_audiofilewriter_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofilewriter_audiofilewriter_deinit(self); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(audiowriter_audiowriter_deinit_obj, audiowriter_audiowriter_deinit); +static MP_DEFINE_CONST_FUN_OBJ_1(audiofilewriter_audiofilewriter_deinit_obj, audiofilewriter_audiofilewriter_deinit); -//| def __enter__(self) -> AudioWriter: +//| def __enter__(self) -> AudioFileWriter: //| """No-op used by Context Managers.""" //| ... //| @@ -124,58 +124,58 @@ static MP_DEFINE_CONST_FUN_OBJ_1(audiowriter_audiowriter_deinit_obj, audiowriter //| or call `stop()` to end recording of a continuous source (e.g. a mic).""" //| ... //| -static mp_obj_t audiowriter_audiowriter_obj_play(mp_obj_t self_in, mp_obj_t sample_in) { - audiowriter_audiowriter_obj_t *self = MP_OBJ_TO_PTR(self_in); +static mp_obj_t audiofilewriter_audiofilewriter_obj_play(mp_obj_t self_in, mp_obj_t sample_in) { + audiofilewriter_audiofilewriter_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - common_hal_audiowriter_audiowriter_play(self, sample_in); + common_hal_audiofilewriter_audiofilewriter_play(self, sample_in); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_2(audiowriter_audiowriter_play_obj, audiowriter_audiowriter_obj_play); +static MP_DEFINE_CONST_FUN_OBJ_2(audiofilewriter_audiofilewriter_play_obj, audiofilewriter_audiofilewriter_obj_play); //| def stop(self) -> None: //| """Stop recording, flush the RAM ring to the file, and patch the WAV //| header sizes. The file is left open for the caller to close.""" //| ... //| -static mp_obj_t audiowriter_audiowriter_obj_stop(mp_obj_t self_in) { - audiowriter_audiowriter_obj_t *self = MP_OBJ_TO_PTR(self_in); +static mp_obj_t audiofilewriter_audiofilewriter_obj_stop(mp_obj_t self_in) { + audiofilewriter_audiofilewriter_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - common_hal_audiowriter_audiowriter_stop(self); + common_hal_audiofilewriter_audiofilewriter_stop(self); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_1(audiowriter_audiowriter_stop_obj, audiowriter_audiowriter_obj_stop); +static MP_DEFINE_CONST_FUN_OBJ_1(audiofilewriter_audiofilewriter_stop_obj, audiofilewriter_audiofilewriter_obj_stop); //| playing: bool //| """True while recording is in progress. Becomes False on its own when a //| finite source finishes, or after `stop()`. (read-only)""" //| -static mp_obj_t audiowriter_audiowriter_obj_get_playing(mp_obj_t self_in) { - audiowriter_audiowriter_obj_t *self = MP_OBJ_TO_PTR(self_in); +static mp_obj_t audiofilewriter_audiofilewriter_obj_get_playing(mp_obj_t self_in) { + audiofilewriter_audiofilewriter_obj_t *self = MP_OBJ_TO_PTR(self_in); check_for_deinit(self); - return mp_obj_new_bool(common_hal_audiowriter_audiowriter_get_playing(self)); + return mp_obj_new_bool(common_hal_audiofilewriter_audiofilewriter_get_playing(self)); } -static MP_DEFINE_CONST_FUN_OBJ_1(audiowriter_audiowriter_get_playing_obj, audiowriter_audiowriter_obj_get_playing); +static MP_DEFINE_CONST_FUN_OBJ_1(audiofilewriter_audiofilewriter_get_playing_obj, audiofilewriter_audiofilewriter_obj_get_playing); -MP_PROPERTY_GETTER(audiowriter_audiowriter_playing_obj, - (mp_obj_t)&audiowriter_audiowriter_get_playing_obj); +MP_PROPERTY_GETTER(audiofilewriter_audiofilewriter_playing_obj, + (mp_obj_t)&audiofilewriter_audiofilewriter_get_playing_obj); -static const mp_rom_map_elem_t audiowriter_audiowriter_locals_dict_table[] = { +static const mp_rom_map_elem_t audiofilewriter_audiofilewriter_locals_dict_table[] = { // Methods - { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiowriter_audiowriter_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiofilewriter_audiofilewriter_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&default___exit___obj) }, - { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiowriter_audiowriter_play_obj) }, - { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiowriter_audiowriter_stop_obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiofilewriter_audiofilewriter_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiofilewriter_audiofilewriter_stop_obj) }, // Properties - { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiowriter_audiowriter_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiofilewriter_audiofilewriter_playing_obj) }, }; -static MP_DEFINE_CONST_DICT(audiowriter_audiowriter_locals_dict, audiowriter_audiowriter_locals_dict_table); +static MP_DEFINE_CONST_DICT(audiofilewriter_audiofilewriter_locals_dict, audiofilewriter_audiofilewriter_locals_dict_table); MP_DEFINE_CONST_OBJ_TYPE( - audiowriter_audiowriter_type, - MP_QSTR_AudioWriter, + audiofilewriter_audiofilewriter_type, + MP_QSTR_AudioFileWriter, MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, audiowriter_audiowriter_make_new, - locals_dict, &audiowriter_audiowriter_locals_dict + make_new, audiofilewriter_audiofilewriter_make_new, + locals_dict, &audiofilewriter_audiofilewriter_locals_dict ); diff --git a/shared-bindings/audiofilewriter/AudioFileWriter.h b/shared-bindings/audiofilewriter/AudioFileWriter.h new file mode 100644 index 00000000000..22d456979b9 --- /dev/null +++ b/shared-bindings/audiofilewriter/AudioFileWriter.h @@ -0,0 +1,23 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +#include "shared-module/audiofilewriter/AudioFileWriter.h" + +extern const mp_obj_type_t audiofilewriter_audiofilewriter_type; + +void common_hal_audiofilewriter_audiofilewriter_construct(audiofilewriter_audiofilewriter_obj_t *self, + mp_obj_t file, uint32_t buffer_size); + +void common_hal_audiofilewriter_audiofilewriter_deinit(audiofilewriter_audiofilewriter_obj_t *self); +bool common_hal_audiofilewriter_audiofilewriter_deinited(audiofilewriter_audiofilewriter_obj_t *self); + +void common_hal_audiofilewriter_audiofilewriter_play(audiofilewriter_audiofilewriter_obj_t *self, mp_obj_t sample); +void common_hal_audiofilewriter_audiofilewriter_stop(audiofilewriter_audiofilewriter_obj_t *self); +bool common_hal_audiofilewriter_audiofilewriter_get_playing(audiofilewriter_audiofilewriter_obj_t *self); diff --git a/shared-bindings/audiofilewriter/__init__.c b/shared-bindings/audiofilewriter/__init__.c new file mode 100644 index 00000000000..e67a74b9451 --- /dev/null +++ b/shared-bindings/audiofilewriter/__init__.c @@ -0,0 +1,29 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/obj.h" +#include "py/runtime.h" + +#include "shared-bindings/audiofilewriter/__init__.h" +#include "shared-bindings/audiofilewriter/AudioFileWriter.h" + +//| """Support for streaming audio to a WAV file""" + +static const mp_rom_map_elem_t audiofilewriter_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiofilewriter) }, + { MP_ROM_QSTR(MP_QSTR_AudioFileWriter), MP_ROM_PTR(&audiofilewriter_audiofilewriter_type) }, +}; + +static MP_DEFINE_CONST_DICT(audiofilewriter_module_globals, audiofilewriter_module_globals_table); + +const mp_obj_module_t audiofilewriter_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&audiofilewriter_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_audiofilewriter, audiofilewriter_module); diff --git a/shared-bindings/audiowriter/__init__.h b/shared-bindings/audiofilewriter/__init__.h similarity index 100% rename from shared-bindings/audiowriter/__init__.h rename to shared-bindings/audiofilewriter/__init__.h diff --git a/shared-bindings/audiowriter/AudioWriter.h b/shared-bindings/audiowriter/AudioWriter.h deleted file mode 100644 index e0de6b2ad9f..00000000000 --- a/shared-bindings/audiowriter/AudioWriter.h +++ /dev/null @@ -1,23 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#pragma once - -#include "py/obj.h" - -#include "shared-module/audiowriter/AudioWriter.h" - -extern const mp_obj_type_t audiowriter_audiowriter_type; - -void common_hal_audiowriter_audiowriter_construct(audiowriter_audiowriter_obj_t *self, - mp_obj_t file, uint32_t buffer_size); - -void common_hal_audiowriter_audiowriter_deinit(audiowriter_audiowriter_obj_t *self); -bool common_hal_audiowriter_audiowriter_deinited(audiowriter_audiowriter_obj_t *self); - -void common_hal_audiowriter_audiowriter_play(audiowriter_audiowriter_obj_t *self, mp_obj_t sample); -void common_hal_audiowriter_audiowriter_stop(audiowriter_audiowriter_obj_t *self); -bool common_hal_audiowriter_audiowriter_get_playing(audiowriter_audiowriter_obj_t *self); diff --git a/shared-bindings/audiowriter/__init__.c b/shared-bindings/audiowriter/__init__.c deleted file mode 100644 index 21c0d15cc7b..00000000000 --- a/shared-bindings/audiowriter/__init__.c +++ /dev/null @@ -1,29 +0,0 @@ -// This file is part of the CircuitPython project: https://circuitpython.org -// -// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries -// -// SPDX-License-Identifier: MIT - -#include - -#include "py/obj.h" -#include "py/runtime.h" - -#include "shared-bindings/audiowriter/__init__.h" -#include "shared-bindings/audiowriter/AudioWriter.h" - -//| """Support for streaming audio to a WAV file""" - -static const mp_rom_map_elem_t audiowriter_module_globals_table[] = { - { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiowriter) }, - { MP_ROM_QSTR(MP_QSTR_AudioWriter), MP_ROM_PTR(&audiowriter_audiowriter_type) }, -}; - -static MP_DEFINE_CONST_DICT(audiowriter_module_globals, audiowriter_module_globals_table); - -const mp_obj_module_t audiowriter_module = { - .base = { &mp_type_module }, - .globals = (mp_obj_dict_t *)&audiowriter_module_globals, -}; - -MP_REGISTER_MODULE(MP_QSTR_audiowriter, audiowriter_module); diff --git a/shared-module/audiowriter/AudioWriter.c b/shared-module/audiofilewriter/AudioFileWriter.c similarity index 83% rename from shared-module/audiowriter/AudioWriter.c rename to shared-module/audiofilewriter/AudioFileWriter.c index 0ddbe07c96c..099345888a0 100644 --- a/shared-module/audiowriter/AudioWriter.c +++ b/shared-module/audiofilewriter/AudioFileWriter.c @@ -4,7 +4,7 @@ // // SPDX-License-Identifier: MIT -#include "shared-bindings/audiowriter/AudioWriter.h" +#include "shared-bindings/audiofilewriter/AudioFileWriter.h" #include "shared-bindings/audiocore/__init__.h" #include "shared-module/audiocore/__init__.h" @@ -42,15 +42,15 @@ static void put_u32le(uint8_t *p, uint32_t v) { // recreated on soft reset. // --------------------------------------------------------------------------- -#define REGISTRY_HEAD ((audiowriter_audiowriter_obj_t *)MP_STATE_VM(audiowriter_linked_list)) +#define REGISTRY_HEAD ((audiofilewriter_audiofilewriter_obj_t *)MP_STATE_VM(audiofilewriter_linked_list)) // Add self to the registry. Called from Python (play()) context, so it must // guard against a background tick walking the list mid-mutation. -static void audiowriter_register(audiowriter_audiowriter_obj_t *self) { +static void audiofilewriter_register(audiofilewriter_audiofilewriter_obj_t *self) { background_callback_prevent(); // Avoid double-linking if already present. bool present = false; - for (audiowriter_audiowriter_obj_t *w = REGISTRY_HEAD; w != NULL; w = w->reg_next) { + for (audiofilewriter_audiofilewriter_obj_t *w = REGISTRY_HEAD; w != NULL; w = w->reg_next) { if (w == self) { present = true; break; @@ -58,7 +58,7 @@ static void audiowriter_register(audiowriter_audiowriter_obj_t *self) { } if (!present) { self->reg_next = REGISTRY_HEAD; - MP_STATE_VM(audiowriter_linked_list) = self; + MP_STATE_VM(audiofilewriter_linked_list) = self; } background_callback_allow(); } @@ -66,8 +66,8 @@ static void audiowriter_register(audiowriter_audiowriter_obj_t *self) { // Remove self from the registry. Callers must ensure no background tick is // walking the list concurrently: either they are the background tick itself // (single-threaded, so safe), or they wrap the call in prevent/allow. -static void audiowriter_unregister(audiowriter_audiowriter_obj_t *self) { - audiowriter_audiowriter_obj_t **pp = (audiowriter_audiowriter_obj_t **)&MP_STATE_VM(audiowriter_linked_list); +static void audiofilewriter_unregister(audiofilewriter_audiofilewriter_obj_t *self) { + audiofilewriter_audiofilewriter_obj_t **pp = (audiofilewriter_audiofilewriter_obj_t **)&MP_STATE_VM(audiofilewriter_linked_list); while (*pp != NULL) { if (*pp == self) { *pp = self->reg_next; @@ -84,7 +84,7 @@ static void audiowriter_unregister(audiowriter_audiowriter_obj_t *self) { // Copy len bytes from src into the ring. The caller guarantees there is room. // 8-bit signed PCM is flipped to unsigned to match the WAV convention. -static void audiowriter_ring_write(audiowriter_audiowriter_obj_t *self, const uint8_t *src, uint32_t len) { +static void audiofilewriter_ring_write(audiofilewriter_audiofilewriter_obj_t *self, const uint8_t *src, uint32_t len) { bool flip = (self->bits_per_sample == 8 && self->samples_signed); uint32_t i = 0; while (i < len) { @@ -110,7 +110,7 @@ static void audiowriter_ring_write(audiowriter_audiowriter_obj_t *self, const ui // Drain the ring to the file. Returns false on a write error. Non-raising: // safe to call from background-task context. -static bool audiowriter_flush(audiowriter_audiowriter_obj_t *self) { +static bool audiofilewriter_flush(audiofilewriter_audiofilewriter_obj_t *self) { while (self->ring_count > 0) { uint32_t span = self->ring_size - self->ring_tail; if (span > self->ring_count) { @@ -135,7 +135,7 @@ static bool audiowriter_flush(audiowriter_audiowriter_obj_t *self) { // Header patching + finalize // --------------------------------------------------------------------------- -static void audiowriter_patch_header(audiowriter_audiowriter_obj_t *self) { +static void audiofilewriter_patch_header(audiofilewriter_audiofilewriter_obj_t *self) { uint8_t sz[4]; int err = 0; @@ -160,18 +160,18 @@ static void audiowriter_patch_header(audiowriter_audiowriter_obj_t *self) { // Stop pumping, drain, patch the header, and release the source. Idempotent: // only the first call (while playing) does work. Non-raising. -static void audiowriter_finalize(audiowriter_audiowriter_obj_t *self) { +static void audiofilewriter_finalize(audiofilewriter_audiofilewriter_obj_t *self) { if (!self->playing) { return; } // Stop the pump first so a background tick can't re-enter us. self->playing = false; - audiowriter_flush(self); - audiowriter_patch_header(self); + audiofilewriter_flush(self); + audiofilewriter_patch_header(self); supervisor_disable_tick(); - audiowriter_unregister(self); + audiofilewriter_unregister(self); self->sample = MP_OBJ_NULL; } @@ -179,7 +179,7 @@ static void audiowriter_finalize(audiowriter_audiowriter_obj_t *self) { // The pump: one real-time-paced step per supervisor tick // --------------------------------------------------------------------------- -static void audiowriter_pump(audiowriter_audiowriter_obj_t *self) { +static void audiofilewriter_pump(audiofilewriter_audiofilewriter_obj_t *self) { if (!self->playing) { return; } @@ -228,7 +228,7 @@ static void audiowriter_pump(audiowriter_audiowriter_obj_t *self) { if (len > self->source_max_buffer) { len = self->source_max_buffer; } - audiowriter_ring_write(self, buf, len); + audiofilewriter_ring_write(self, buf, len); self->budget_frames -= (int64_t)(len / self->bytes_per_frame); } if (res == GET_BUFFER_DONE) { @@ -237,23 +237,23 @@ static void audiowriter_pump(audiowriter_audiowriter_obj_t *self) { } } - if (!audiowriter_flush(self)) { + if (!audiofilewriter_flush(self)) { // File write failed; give up gracefully rather than spin. self->source_done = true; } if (self->source_done && self->ring_count == 0) { - audiowriter_finalize(self); + audiofilewriter_finalize(self); } } -void audiowriter_background(void) { - audiowriter_audiowriter_obj_t *self = REGISTRY_HEAD; +void audiofilewriter_background(void) { + audiofilewriter_audiofilewriter_obj_t *self = REGISTRY_HEAD; while (self != NULL) { // Capture next before pumping: pump() may finalize self, which unlinks // it from the registry (but leaves our saved next pointer valid). - audiowriter_audiowriter_obj_t *next = self->reg_next; - audiowriter_pump(self); + audiofilewriter_audiofilewriter_obj_t *next = self->reg_next; + audiofilewriter_pump(self); self = next; } } @@ -261,10 +261,10 @@ void audiowriter_background(void) { // Called during soft reset (VM teardown). Any writer still active is abandoned: // we don't try to touch its file (it may already be gone), we just balance the // tick-enable count and drop it from the list. -void audiowriter_reset(void) { - audiowriter_audiowriter_obj_t *self = REGISTRY_HEAD; +void audiofilewriter_reset(void) { + audiofilewriter_audiofilewriter_obj_t *self = REGISTRY_HEAD; while (self != NULL) { - audiowriter_audiowriter_obj_t *next = self->reg_next; + audiofilewriter_audiofilewriter_obj_t *next = self->reg_next; if (self->playing) { self->playing = false; supervisor_disable_tick(); @@ -272,14 +272,14 @@ void audiowriter_reset(void) { self->reg_next = NULL; self = next; } - MP_STATE_VM(audiowriter_linked_list) = NULL; + MP_STATE_VM(audiofilewriter_linked_list) = NULL; } // --------------------------------------------------------------------------- // common-hal surface // --------------------------------------------------------------------------- -void common_hal_audiowriter_audiowriter_construct(audiowriter_audiowriter_obj_t *self, +void common_hal_audiofilewriter_audiofilewriter_construct(audiofilewriter_audiofilewriter_obj_t *self, mp_obj_t file, uint32_t buffer_size) { // The file must be a writable, seekable binary stream (a file or BytesIO). mp_get_stream_raise(file, MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); @@ -296,20 +296,20 @@ void common_hal_audiowriter_audiowriter_construct(audiowriter_audiowriter_obj_t self->reg_next = NULL; } -bool common_hal_audiowriter_audiowriter_deinited(audiowriter_audiowriter_obj_t *self) { +bool common_hal_audiofilewriter_audiofilewriter_deinited(audiofilewriter_audiofilewriter_obj_t *self) { return self->ring == NULL; } -void common_hal_audiowriter_audiowriter_deinit(audiowriter_audiowriter_obj_t *self) { +void common_hal_audiofilewriter_audiofilewriter_deinit(audiofilewriter_audiofilewriter_obj_t *self) { if (self->playing) { - common_hal_audiowriter_audiowriter_stop(self); + common_hal_audiofilewriter_audiofilewriter_stop(self); } self->ring = NULL; self->file = MP_OBJ_NULL; self->sample = MP_OBJ_NULL; } -void common_hal_audiowriter_audiowriter_play(audiowriter_audiowriter_obj_t *self, mp_obj_t sample_obj) { +void common_hal_audiofilewriter_audiofilewriter_play(audiofilewriter_audiofilewriter_obj_t *self, mp_obj_t sample_obj) { if (self->playing) { mp_raise_RuntimeError(MP_ERROR_TEXT("Already in progress")); } @@ -382,22 +382,22 @@ void common_hal_audiowriter_audiowriter_play(audiowriter_audiowriter_obj_t *self self->last_tick_ms = supervisor_ticks_ms64(); self->playing = true; - audiowriter_register(self); + audiofilewriter_register(self); supervisor_enable_tick(); } -void common_hal_audiowriter_audiowriter_stop(audiowriter_audiowriter_obj_t *self) { +void common_hal_audiofilewriter_audiofilewriter_stop(audiofilewriter_audiofilewriter_obj_t *self) { if (!self->playing) { return; } // Keep the background pump out while we finalize from Python context. background_callback_prevent(); - audiowriter_finalize(self); + audiofilewriter_finalize(self); background_callback_allow(); } -bool common_hal_audiowriter_audiowriter_get_playing(audiowriter_audiowriter_obj_t *self) { +bool common_hal_audiofilewriter_audiofilewriter_get_playing(audiofilewriter_audiofilewriter_obj_t *self) { return self->playing; } -MP_REGISTER_ROOT_POINTER(mp_obj_t audiowriter_linked_list); +MP_REGISTER_ROOT_POINTER(mp_obj_t audiofilewriter_linked_list); diff --git a/shared-module/audiowriter/AudioWriter.h b/shared-module/audiofilewriter/AudioFileWriter.h similarity index 88% rename from shared-module/audiowriter/AudioWriter.h rename to shared-module/audiofilewriter/AudioFileWriter.h index 1aab3f401ad..0e99e90e915 100644 --- a/shared-module/audiowriter/AudioWriter.h +++ b/shared-module/audiofilewriter/AudioFileWriter.h @@ -15,7 +15,7 @@ // or an effect chain) and writes the resulting PCM to a file. Unlike WaveFile // it is NOT an audiosample, it is the thing that drives a source, playing the // role an AudioOut would. -typedef struct _audiowriter_audiowriter_obj_t { +typedef struct _audiofilewriter_audiofilewriter_obj_t { mp_obj_base_t base; // Output stream (anything with write + MP_STREAM_SEEK ioctl: a file or a @@ -24,7 +24,7 @@ typedef struct _audiowriter_audiowriter_obj_t { // The source being recorded. Only valid (and referenced) while playing. mp_obj_t sample; - // Format, captured from the source at play() time. AudioWriter is the + // Format, captured from the source at play() time. AudioFileWriter is the // format authority for the WAV header. uint32_t sample_rate; uint8_t channel_count; @@ -56,12 +56,12 @@ typedef struct _audiowriter_audiowriter_obj_t { bool source_done; // source returned DONE/ERROR; drain then finalize // Intrusive linked list of active writers, walked once per supervisor tick. - struct _audiowriter_audiowriter_obj_t *reg_next; -} audiowriter_audiowriter_obj_t; + struct _audiofilewriter_audiofilewriter_obj_t *reg_next; +} audiofilewriter_audiofilewriter_obj_t; // Called once per supervisor tick (from supervisor_background_tick), in // background-task context. Pumps every active writer. -void audiowriter_background(void); +void audiofilewriter_background(void); // Called during soft reset to abandon any writer left recording. -void audiowriter_reset(void); +void audiofilewriter_reset(void); diff --git a/shared-module/audiowriter/__init__.c b/shared-module/audiofilewriter/__init__.c similarity index 100% rename from shared-module/audiowriter/__init__.c rename to shared-module/audiofilewriter/__init__.c diff --git a/supervisor/shared/tick.c b/supervisor/shared/tick.c index a224de14720..81815c0813b 100644 --- a/supervisor/shared/tick.c +++ b/supervisor/shared/tick.c @@ -27,8 +27,8 @@ #include "shared-module/keypad/__init__.h" #endif -#if CIRCUITPY_AUDIOWRITER -#include "shared-module/audiowriter/AudioWriter.h" +#if CIRCUITPY_AUDIOFILEWRITER +#include "shared-module/audiofilewriter/AudioFileWriter.h" #endif #include "shared-bindings/microcontroller/__init__.h" @@ -63,8 +63,8 @@ static void supervisor_background_tick(void *unused) { filesystem_background(); - #if CIRCUITPY_AUDIOWRITER - audiowriter_background(); + #if CIRCUITPY_AUDIOFILEWRITER + audiofilewriter_background(); #endif port_background_tick(); From 2e40b01e78ca90beb07abf218f33452320ed6b86 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 10 Jul 2026 14:20:12 -0500 Subject: [PATCH 647/876] merge main, fix translations --- locale/circuitpython.pot | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 9c81ed5dbd7..32f6e4ef631 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -498,9 +498,8 @@ msgstr "" msgid "wrong length of index array" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: shared-module/audiofilewriter/AudioFileWriter.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" msgstr "" #: extmod/ulab/code/numpy/vector.c @@ -1247,6 +1246,7 @@ msgid "Not connected" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Already in progress" msgstr "" @@ -1783,10 +1783,6 @@ msgstr "" msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: shared-module/audiofilewriter/AudioFileWriter.c -msgid "Only 8/16-bit mono/stereo is supported" -msgstr "" - #: ports/nordic/common-hal/watchdog/WatchDogTimer.c msgid "timeout duration exceeded the maximum supported value" msgstr "" @@ -2654,10 +2650,6 @@ msgstr "" msgid "'%s' expects an FPU register" msgstr "" -#: shared-module/audiofilewriter/AudioFileWriter.c -msgid "buffer_size too small for source" -msgstr "" - #: py/emitinlinethumb.c #, c-format msgid "'%s' expects {r0, r1, ...}" @@ -4261,6 +4253,14 @@ msgstr "" msgid "%q in %q must be of type %q or %q, not %q" msgstr "" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" + +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate decoder" msgstr "" From a859735659998042bddbb6007767ad1fb7af68f8 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sun, 12 Jul 2026 16:23:24 +0200 Subject: [PATCH 648/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 6556 ++++++++++++++++++++++----------------------- locale/el.po | 5666 +++++++++++++++++++-------------------- locale/hi.po | 5022 ++++++++++++++++++----------------- locale/ko.po | 6346 ++++++++++++++++++++++---------------------- locale/ru.po | 7218 +++++++++++++++++++++++++------------------------- locale/tr.po | 5972 ++++++++++++++++++++--------------------- 6 files changed, 18434 insertions(+), 18346 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index e4a09a220ee..611b42f2746 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -16,1347 +16,984 @@ msgstr "" "Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -"\n" -"Běh programu byl dokončen.\n" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" -msgstr "" -"\n" -"Kód byl zastaven kvůli automatickému načtení. K načtení dojde brzy.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" +msgstr "nelze zrušit sám sebe" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." -msgstr "" -"\n" -"Prosím, založte issue s vaším programem na github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" +msgstr "nelze čekat" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -"\n" -"Stiskněte reset pro ukončení nouzového režimu.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -"\n" -"Jste v bezpečnostním režimu z důvodu:\n" - -#: py/obj.c -msgid " File \"%q\"" -msgstr " Soubor \"%q\"" - -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " Soubor \"%q\", řádek %d" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " je typu %q\n" +#: extmod/moddeflate.c +msgid "format" +msgstr "" -#: main.c -msgid " not found.\n" -msgstr " nenalezen\n" +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" -#: main.c -msgid " output:\n" -msgstr " výstup:\n" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "hash je konečný" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modheapq.c +msgid "heap must be a list" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" -msgstr "%d adresní pin, %d rgb pin a %d dlaždice indikuje výšku %d, ne %d" - -#: py/emitinlinextensa.c -#, c-format -msgid "%d is not a multiple of %d" +#: extmod/modjson.c +msgid "syntax error in JSON" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q a %q obsahují duplicitní piny" +#: extmod/modrandom.c +msgid "bits must be 32 or less" +msgstr "počet bitů nesmí přesáhnout 32" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q a %q musí být rozdílné" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modre.c +msgid "splitting with sub-captures" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q obsahuje duplicitní piny" +#: extmod/modre.c +msgid "Error in regex" +msgstr "Chyba v regulárním výrazu" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" -msgstr "%q: selhání %d" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" +msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q v %q musí být typu %q, ne %q" +#: extmod/modzlib.c +msgid "compression header" +msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q se právě používá" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "datový typ nebyl rozpoznán" -#: py/objstr.c -msgid "%q index out of range" -msgstr "Index %q je mimo rozsah" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "pole je příliš velké" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "Indexy %q musí být celá čísla, nikoli %s" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "délka ndarray přetekla" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: ports/stm/common-hal/audioio/AudioOut.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c -msgid "%q init failed" -msgstr "Inicializace %q selhala" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "nelze převést typ complex" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q je %q" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "příliš mnoho dimenzí" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q je pouze u této desky pouze pro čtení" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "Délka %q musí být %d" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "%q délka musí být %d-%d" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "Délka %q musí být <= %d" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "Pole a index musí mít stejnou délku" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "Délka %q musí být >= %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "nelze převést complex na dtype" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q musí být %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "operace je immplementována pouze pro 1D boolean pole" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c -#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q musí být %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q musí být 1, pokud %q je True" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "nelze smazat prvky pole" -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 16, 24, or 32" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" msgstr "" -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 8 or 16" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q must be 8, 16, 24, or 32" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "%q musí být <= %d" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "tvar musí být integer nebo tuple integerů" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "%q musí být <= %u" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "maximální počet dimenzí je " -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "%q musí být >= %d" - -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q musí být bytearray nebo pole typu 'H' nebo 'B'" - -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q musí být bytearray nebo pole typu 'h', 'H', 'b', nebo 'B'" - -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "%q musí být pole typu 'H V" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "nelze změnit rozměry pole" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "%q musí být pole typu 'h'" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "nelze přiřadit nový tvar" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "funkce je definována pouze pro ndarraye" + +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q musí být typu %q nebo %q, ne %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q musí být typu %q, ne %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q musí být mocnina 2" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "%q je mimo hranice" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "není podporováno pro vstupní typy" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "%q je mimo rozsah" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "funkce je implementována jen pro ndarraye" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "%q krok nemůže být nula" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "vstup musí být ndarray nebo scalar" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" -msgstr "" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "vstup musí být 1D ndarray" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q() vyžaduje %d pozičních argumentů, ale pouze %d jich bylo zadáno" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "není implementováno pro komplexní dtype" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q, a %q musí mít všechny shodnou délku" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "vstupní argument musí být integer, tuple nebo list" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "%q[%u] posouvá dovnitř o více bitů než je počet pinů" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "dělení nulou" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "%q[%u] posouvá ven o více bitů než je počet pinů" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "%q[%u] používá extra pin" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "první argument musí být tuple nebo ndarray" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "%q[%u] čeká na vstup mimo rozsah" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "pouze ndarraye mohou být spojeny" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "%s chyba 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "Je vyžadován argument '%q'" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "vstupní pole nejsou kompatibilní" -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" -msgstr "Objekt '%q' nepodporuje '%q'" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "vstup musí být 1- nebo 2-d" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "Objekt '%q' není iterátor" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "Objekt '%q' není iterovatelný" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "velikost bufferu musí být násobkem velikosti elementu" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' očekává label" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "buffer je menší než požadovaná velikost" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' očekává registr" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "FFT lze použít pouze pro ndarrays" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' očekává speciální registr" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "FFT je implementován pouze pro lineární pole" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' očekává registr FPU" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s' očekává adresu ve formátu [a, b]" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' očekává integer (celé číslo)" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s' očekává nanejvýš r%d" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' očekává {r0, r1, ...}" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' integer %d není v rozsahu %d..%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "poškozený soubor" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' integer 0x%x nepatří do masky 0x%x" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "špatný dtype" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "'%s' objekt nepodporuje přiřazení položky" - -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "'%s' objekt nepodporuje smazání položky" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "'%s' objekt nemá žádný atribut '%q'" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "prázdný soubor" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "'%s' objekt není vložitelný" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "Specifikátor zarovnání '=' není ve formátovacím řetězci povolen" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "pole má příliš mnoho dimenzí" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' a 'O' nejsou podporované typy formátů" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "'align' vyžaduje 1 argument" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" -#: py/compile.c -msgid "'await' outside function" -msgstr "'await' je volán mimo funkci" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" -#: py/compile.c -msgid "'break'/'continue' outside loop" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "'data' vyžaduje nejméně 2 argumenty" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "operace je definována pouze pro ndarray pole" -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "'data' vyžaduje celočíselné argumenty" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "operace je definována pouze pro 2D pole" -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "'label' vyžaduje 1 argument" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" msgstr "" -#: py/compile.c -msgid "'return' outside function" -msgstr "'return' je volán mimo funkci" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "pokus o získání (arg)min/(arg)max z prázdné sekvence" -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "'yield from' volán uvnitř funkce async" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "osa musí být None nebo integer" -#: py/compile.c -msgid "'yield' outside function" -msgstr "'yield' je volán mimo funkci" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" -#: py/compile.c -msgid "* arg after **" -msgstr "* arg po **" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "" -#: py/compile.c -msgid "*x must be assignment target" -msgstr "∗x musí být cíl přiřazení" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" -#: py/obj.c -msgid ", in %q\n" -msgstr ", v% q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "argsort není implementován pro zploštěná pole" + +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" +msgstr "osa je příliš dlouhá" + +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "0.0 na komplexní mocninu" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "pow() nepodporuje 3 argumenty" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "AP nemohl být spuštěn" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "Adresa musí být %d bajtů dlouhá" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "Adresní rozsah není povolen" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "Adresní rozsah se překlápí přes maximální možnou adresu" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "Všechny CAN periferie jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "Všechny I2C periferie jsou používány" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "Všechny RX FIFO jsou používány" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "Všechny SPI periferie jsou používány" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "Všechny UART periferie jsou používány" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "Všechny kanály jsou používány" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" +msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "Všechny DMA kanály jsou používány" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "vstup není iterovatelný" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "Všechny kanály událostí jsou již používány" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "Všechny stavové automaty jsou používány" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "Všechny časovače pro tento pin jsou používány" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "Všechny časovače jsou používány" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "Již propagujeme." +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "Již existuje posluchač pro všechny zprávy" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "Již běží" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "špatný typ indexu" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "Již skenuje wifi sítě" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" +msgstr "" -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "Došlo k chybě při načítání '%s'\n" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "dimenze nesouhlasí" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "Jiný PWMAudioOut je již aktivní" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "Další odesílání je již aktivní" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" +msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "Pole musí obsahovat poloviční slova (typ „H“)" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "dimenze vstupu a výstupu se liší" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "Hodnoty pole by měly být jednoduché bajty." +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "vstupní a výstupní tvar je růzmý" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" msgstr "" -#: shared-bindings/usb_audio/__init__.c -msgid "At least one of microphone and speaker must be enabled" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "Pokus o alokování %d bloků" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" +msgstr "dtype musí být float nebo complex" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "Konverze audia není implementována" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "nelze převést complex na float" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Audio source error" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "vstupní dtype musí být float nebo complex" + +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "První argument musí být zavolatelný" + +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "AuthMode.OPEN nepoužívá heslo" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "první dva argumenty musí být ndarray" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "Autentizace selhala" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "vstup musí být hustý ndarray" -#: main.c -msgid "Auto-reload is off.\n" -msgstr "Automatické načtení je vypnuto.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "první argument musí být funkce" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" msgstr "" -"Automatické opětovné načtení je zapnuto. Jednoduše uložte soubory přes USB a " -"spusťte je, nebo vypněte REPL.\n" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "Baudrate není podporován periférií" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "maxiter by měl být > 0" -#: ports/zephyr-cp/common-hal/zephyr_display/Display.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "Pod minimální obnovovací frekvencí" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "maxiter musí být > 0" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "data musí být iterovatelná" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "Velikost bitmapy a počet bitů na hodnotu se musí shodovat" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "výchozí hodnoty musí být iterovatelné" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "Bootovací zařízení musí být první (rozhraní #0)." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "data musí mít stejnou délku" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "RX a TX jsou vyžadovány pro kontrolu toku" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "Jas není nastavitelný" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "vstup musí být jednorozměrný" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "Prvky bufferu musí být 4 bajty dlouhé nebo méně" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "Buffer není bytearray." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "Délka vyrovnávací paměti %d je příliš velká. Musí být menší než %d" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" +msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "Buffer je příliš krátký o %d bajtů" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "Buffer příliš malý" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "osa je mimo rozsah" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Sběrnicový pin %d je již používán" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "Bloky CBC musí být násobky 16 bajtů" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "Disk CIRCUITPY nelze nalézt nebo vytvořit." +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" +msgstr "vstup musí být ndarray" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC nebo kontrolní součet byl neplatný" +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" +msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "Volání super().__init__() před přístupem k nativnímu objektu." +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" +msgstr "offset je příliš velký" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "Inizializace kamery" +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" +msgstr "výstupní pole je příliš malé" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "Alarm z IO RTC je možné generovat pouze z hlubokého spánku." +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "Filesystém pouze pro čtení" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." -msgstr "" -"Lze nastavit alarm na jednom pinu ve stavu low při hlubokém spánku, ostatní " -"musí být ve stavu high." +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "I/O operace nad zavřeným souborem" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -"Lze nastavit alarm na maximálně dvou pinech ve stavu low při hlubokém spánku." -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: main.c +msgid "Done" +msgstr "Hotovo" + +#: main.c +msgid " output:\n" +msgstr " výstup:\n" + +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" +"Automatické opětovné načtení je zapnuto. Jednoduše uložte soubory přes USB a " +"spusťte je, nebo vypněte REPL.\n" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "Nelze nastavit CCCD na místní charakteristiku" +#: main.c +msgid "Auto-reload is off.\n" +msgstr "Automatické načtení je vypnuto.\n" -#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c -#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c -#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "Nelze změnit USB zařízení" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "Běh v nouzovém režimu! Uložený kód není zpracováván.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "Není možné vytvořit nový adaptér; použití _bleio.adapter;" +#: main.c +msgid " not found.\n" +msgstr " nenalezen\n" -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" -msgstr "" +#: main.c +msgid "WARNING: Your code filename has two extensions\n" +msgstr "UPOZORNĚNÍ: Název souboru vašeho kódu má dvě koncovky\n" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "Nelze odstranit hodnoty" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" +msgstr "" +"\n" +"Kód byl zastaven kvůli automatickému načtení. K načtení dojde brzy.\n" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "Nelze získat ve výstupním režimu" +#: main.c +msgid "" +"\n" +"Code done running.\n" +msgstr "" +"\n" +"Běh programu byl dokončen.\n" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "Nelze získat teplotu (°C)" +#: main.c +msgid "Woken up by alarm.\n" +msgstr "Probuzen alarmem.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" +"Zmáčkněte jakoukoli klávesu pro spuštění REPLu. Použijte CTRL-D pro opětovné " +"načtení.\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "Nelze aktivovat pull rezistor na pinu, který je pouze pro vstup." +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "Předstírám hluboký spánek do alarmu, CTRL-C nebo zápisu souboru.\n" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Cannot record to a file" -msgstr "Nelze nahrávat do souboru" +#: main.c +msgid "UID:" +msgstr "UID:" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "soft reboot\n" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." -msgstr "Nelze nastavit hodnotu, když směr je vstup." - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "Nelze určit RTS nebo CTS v režimu RS485" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" +msgstr "Inicializace %q selhala" -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "Nelze použít řez podtřídy" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "%q je mimo rozsah" + +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "Chybný stav" + +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" -msgstr "Nelze probudit hranou na pinu, pouze úrovní" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." -msgstr "Nelze probudit hranou na pinu. Pouze úrovní." +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "CharacteristicBuffer psaní není poskytováno" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "RX a TX jsou vyžadovány pro kontrolu toku" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "Jádro kódu CircuitPython tvrdě havarovalo. Jejda!\n" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "Chyba alokace %q bufferu" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "Jednotka hodin je používána" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -"Připojení bylo odpojeno a nelze jej dále používat. Vytvořte nové připojení." -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "Pole souřadnic mají různé délky" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "Všechny UART periferie jsou používány" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "Špatný %s" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "Není možné nastavit adresu" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "Interní audio buffer je příliš malý" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "Nelze začít přerušení, RX je zaneprázdněn" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "Dekodér nelze přiřadit" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" -msgstr "" - -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Channel Init Error" -msgstr "Chyba inicializace kanálu DAC" - -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Device Init Error" -msgstr "Chyba inicializace zařízení DAC" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "Při spuštění jsi stiskl obě tlačítka." +#: ports/atmel-samd/common-hal/_pew/PewPew.c #: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC se již používá" - -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "Datový pin 0 musí být zarovnán na bajty" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "Data nejsou podporována s cíleným oznamováním" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "Data jsou příliš velká pro propagovaný paket" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "" -"Piny pro hluboký spánek musí používat náběžnou hranu s pulldown rezistorem" - -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "Cílová kapacita je menší než destination_length." - -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "Zařízení je používáno" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "Displej musí mít 16bitový barevný prostor." - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" -msgstr "Otočení displeje musí být po 90 stupních" - -#: main.c -msgid "Done" -msgstr "Hotovo" - -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." -msgstr "" - -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "Při zpracování uvedené výjimky nastala další výjimka:" - -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB operuje najednou pouze 16 bajtů" - -#: py/asmxtensa.c -msgid "ERROR: %q %q not word-aligned" -msgstr "" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "Všechny časovače jsou používány" -#: py/asmxtensa.c -msgid "ERROR: xtensa %q out of range" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" -msgstr "ESP-IDF alokace paměti selhala" - -#: extmod/modre.c -msgid "Error in regex" -msgstr "Chyba v regulárním výrazu" - +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c #: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "Chyba v safemode.py." - -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" -msgstr "Očekáván typ %q" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." -msgstr "" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "FFT lze použít pouze pro ndarrays" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "FFT je implementován pouze pro lineární pole" - -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "Nepodařilo se odeslat příkaz." - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "Nepodařilo se získat mutex, err 0x%04x" - -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" -msgstr "" - -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" -msgstr "" - -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "Chyba alokace %q bufferu" - -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" -msgstr "Chyba alokace paměti WiFi" - -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "Nepodařilo se alokovat paměť pro wifi scan" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" -msgstr "Nepodařilo se nabufferovat sample" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "Připojení se nezdařilo: interní chyba" - -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "Nepodařilo se připojit: časový limit" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" -msgstr "" - -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "Soubor MP3 se nepodařilo analyzovat" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" -msgstr "" - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "Nepodařilo se uvolnit mutex, err 0x%04x" +msgid "Unknown reason." +msgstr "Neznámý důvod." -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" -msgstr "" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "Lze nastavit pouze jeden alarm typu alarm.time" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" +msgstr "Žádný DAC na čipu" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "Nepodařilo se zapsat do interní paměti." - -#: py/moderrno.c -msgid "File exists" -msgstr "soubor existuje" - -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" -msgstr "Soubor nenalezen" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" -msgstr "Filtry jsou příliš komplexní" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "Firmware je duplicitní" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "Firmware není validní" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "Firmware je příliš velký" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "Pro barevný prostor L8 musí mít vstupní bitmapa 8 bitů na pixel" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "Pro barevný prostor RGB musí mít vstupní bitmapa 16 bitů na pixel" - -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "Formát není podporován" - -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -"Frekvence musí být 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 nebo 1008 " -"Mhz" - -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Funkce vyžaduje zámek" - -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "Inicializace GNSS" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" -msgstr "Základní chyba" - -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "Skupina již byla použita" - -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "Fatální chyba: přístup k paměti nebo chyba instrukce." - -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "Hardware je používán, zkuste alternativní piny" - -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." -msgstr "Alokace heapu při neběžícím VM." - -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "I/O operace nad zavřeným souborem" - -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "Chyba inicializace I2C" - -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "Periférie I2C je používána" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "Elementy v bufferu musí být <= 4 bajty" - -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "Nesprávná velikost vyrovnávací paměti" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "Jednotka hodin je používána" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "Velikost init programu není správná" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" +msgstr "Žádné volné GCLK" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" +msgstr "V samplu je příliš mnoho kanálů" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" +msgstr "Nebyl nalezen žádný kanál DMA" -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "Vstup trval příliš dlouho" - -#: py/moderrno.c -msgid "Input/output error" -msgstr "Chyba vstupu/výstupu" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" -msgstr "Nedostatečná autentizace" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "Nedostatečné šifrování" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "Rozhraní musí být nastartováno" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC se již používá" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "Interní audio buffer je příliš malý" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" +msgstr "Pravý kanál nepodporován" -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "Všechny kanály událostí jsou již používány" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c -#: supervisor/shared/settings.c -msgid "Internal error" -msgstr "Interní chyba" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "SDA nebo SCL zřejmě nemá pull up; zkontroluj zapojení" -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" -msgstr "Vnitřní chyba #%d" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q musí být mocnina 2" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "Žádný %q pin" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "Interní watchdog timer expiroval." +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "Všechny RX FIFO jsou používány" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "Chyba přerušení." +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "Již existuje posluchač pro všechny zprávy" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" +msgstr "Filtry jsou příliš komplexní" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/espressif/common-hal/mipidsi/Display.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c -#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "Špatný %s" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "Nelze získat ve výstupním režimu" -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" -msgstr "" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" +msgstr "Chybný data_pin[%d]" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" +msgstr "datový pin #%d je používán" #: ports/atmel-samd/common-hal/microcontroller/Pin.c #: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c @@ -1365,420 +1002,531 @@ msgstr "" msgid "Invalid %q pin" msgstr "Neplatný pin %q" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "Neplatná hodnota jednotky ADC" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "Chybný BLE parametr" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "Datový pin 0 musí být zarovnán na bajty" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "Chybné BSSID" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Sběrnicový pin %d je již používán" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "Chybná MAC adresa" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "pop z prázdného %q" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "Vstup trval příliš dlouho" + +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "Další odesílání je již aktivní" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" +msgstr "%q: selhání %d" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "Neplatný argument" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" +msgstr "Inicializace UART" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "Inizializace kamery" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "Chybný data_pin[%d]" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "Velikost není podporována" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "Špatný formát" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "Buffer příliš malý" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "Neplatná velikost bloku" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "Formát není podporován" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" -msgstr "Špatné heslo v hex" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "Inicializace GNSS" + +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" +msgstr "Inicializace SD karty" + +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "Již běží" + +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q je %q" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "Chybná multicastová MAC adresa" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "Při spuštění jsi stiskl tlačítko SW38." -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "Chybná velikost" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "Chybný soket pro TLS" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "Při spuštění jsi stiskl tlačítko na pinu GPIO0." -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "Chybný stav" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "Při spuštění jsi stiskl tlačítko Rec." -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" -msgstr "Neplatná unicode escape sekvence" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "Při spuštění jsi stiskl tlačítko VOLUME." -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "Klíč musí být dlouhý 16, 24 nebo 32 bajtů" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "Při spuštění jsi stiskl středové tlačítko." -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "Mapování LED musí korespondovat s velikostí displeje" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "Při spuštění jsi stiskl tlačítko A." -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "Při spuštění jsi stiskl tlačítko DOWN." + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "Vrstva již v groupě je" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "Scan již probíhá. Lze zastavit pomocí stop_scan." -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "Vrstva musí být Group nebo TileGrid" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "Připojení se nezdařilo: interní chyba" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" -msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "Data jsou příliš velká pro propagovaný paket" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "MAC adresa byla chybná" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "Již propagujeme." -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "Data nejsou podporována s cíleným oznamováním" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c #, c-format -msgid "MMC/SDIO Clock Error %x" -msgstr "" +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "Časový limit je příliš dlouhý: maximální limit je %d vteřin" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap must have 8 bits per pixel" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap size must match the other bitmaps" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "Nekorespondující velikost dat" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" +msgstr "Žádné CCCD pro tuto charakteristiku" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" -msgstr "Nekorespondující swap flag" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "Nelze nastavit CCCD na místní charakteristiku" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "Chybí first_in_pin. %q[%u] čte z pinu(ů)" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "Chybí first_in_pin. %q[%u] posunuje z pinu(ů)" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "Chybí first_in_pin. %q[%u] čeká na základě pinu" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "Chybí first_out_pin. %q[%u] posunuje do pinu(ů)" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" +msgstr "Velikost dat k zápisu je větší než %q" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "Chybí first_out_pin. %q[%u] zapisuje do pinu(ů)" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "Chybí first_set_pin. %q[%u] nastavuje pin(y)" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "Chybný BLE parametr" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "Chybí jmp_pin. %q[%u] skáče na pin" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" +msgstr "Nepřipojený" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "Musí být podtřída %q." +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" +msgstr "Neznámá chyba firmwaru na %s:%d: %d" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" -msgstr "Je třeba poskytnout 5/6/5 RGB piny" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" +msgstr "Neznámá chyba firmwaru: %d" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "Musí poskytnout pin MISO nebo MOSI" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" +msgstr "Nedostatečná autentizace" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "Je nutné použít několik kolíků 6 rgb, nikoli %d" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" +msgstr "Nedostatečné šifrování" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." -msgstr "NLR skok selhal. Pravděpodobně poškozením paměti." +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "Neznámá chyba BLE na %s:%d: %d" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "Chyba NVS" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" +msgstr "Neznámá chyba BLE: %d" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" -msgstr "Jméno nebo služba není známa" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "Nelze probudit hranou na pinu. Pouze úrovní." -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" -msgstr "Nová bitmapa musí mít stejnou velikost jako původní bitmapa" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "Nelze aktivovat pull rezistor na pinu, který je pouze pro vstup." -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." msgstr "" +"Lze nastavit alarm na maximálně dvou pinech ve stavu low při hlubokém spánku." -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "Žádný %q pin" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." +msgstr "" +"Lze nastavit alarm na jednom pinu ve stavu low při hlubokém spánku, ostatní " +"musí být ve stavu high." -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "Žádné CCCD pro tuto charakteristiku" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "Alarm z IO RTC je možné generovat pouze z hlubokého spánku." -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "No DAC on chip" -msgstr "Žádný DAC na čipu" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." +msgstr "Může být nastaven pouze jeden alarm typu alarm.time." -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "No DMA channel found" -msgstr "Nebyl nalezen žádný kanál DMA" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." +msgstr "Pouze jeden %q lze nastavit v hlubokém spánku." -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "%q musí být pole typu 'H V" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" -msgstr "Žádné I2C zařízení na adrese: 0x%x" +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +msgid "Peripheral in use" +msgstr "Periférie je používána" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "Není IP" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" -msgstr "Konfigurace není nastavena" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" +msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" -msgstr "Žádné připojení: nelze určit délku" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" +msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" -msgstr "Žádná výchozí sběrnice %q" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "Žádné volné GCLK" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" +msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" -msgstr "V programu není vstup" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" -msgstr "V programu není vstup nebo výstup" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" +msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "Není podpora long integer" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "Žádná síť s takovým SSID" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" -msgstr "V programu není výstup" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "Všechny I2C periferie jsou používány" -#: ports/atmel-samd/common-hal/busio/I2C.c #: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "SDA nebo SCL zřejmě nemá pull up; zkontroluj zapojení" +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" +msgstr "Není možné vytvořit zámek" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" -msgstr "Žádný pulldown na pinu; doporučeno 1Mohm" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" +msgstr "Konfigurace SPI selhala" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "Všechny SPI periferie jsou používány" + +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "ESP-IDF alokace paměti selhala" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "Nelze určit RTS nebo CTS v režimu RS485" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: py/moderrno.c -msgid "No space left on device" -msgstr "Na zařízení nezůstal žádný prostor" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "Baudrate není podporován periférií" -#: py/moderrno.c -msgid "No such device" -msgstr "Žádné takové zařízení" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "Všechny CAN periferie jsou používány" -#: py/moderrno.c -msgid "No such file/directory" -msgstr "Žádný takový soubor / adresář" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" +msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" -msgstr "Není k dispozici žádný časovač" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" +msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" -msgstr "Žádný USB host port není inicializován" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" +msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" -msgstr "Nordic system firmware - nedostatek paměti" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" +msgstr "Je třeba poskytnout 5/6/5 RGB piny" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" -msgstr "Nevalidní IP string" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" +msgstr "Firmware je duplicitní" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" -msgstr "Nepřipojený" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "Firmware není validní" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "Not playing" -msgstr "Nehraje" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "Firmware je příliš velký" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d or %d, not %d" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." -msgstr "" -"Objekt byl deinicializován a nelze jej dále používat. Vytvořte nový objekt." +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" +msgstr "neplatné nastavení" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" +msgstr "Základní chyba" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" +msgstr "Došla paměť" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "Neplatný argument" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" -msgstr "Vypnuto" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "Chybná velikost" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" -msgstr "Ok" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" +msgstr "Požadovaný zdroj nebyl nalezen" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" +msgstr "Operace nebo funkce není podporována" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" -msgstr "Pouze IPv4 adresy podporovány" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" +msgstr "Časový limit operace vypršel" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" -msgstr "Pouze IPv4 sokety podporovány" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" +msgstr "Přijatá odpověď nebyla validní" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC nebo kontrolní součet byl neplatný" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" +msgstr "Verze byla neplatná" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "Na tomto hardware je dostupná pouze detekce hrany" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "MAC adresa byla chybná" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" -msgstr "Pro IP je podporován pouze int nebo string" +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" +msgstr "%s chyba 0x%x" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." -msgstr "Pouze jeden %q lze nastavit v hlubokém spánku." +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" +msgstr "Program je příliš dlouhý" + +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q se právě používá" #: ports/espressif/common-hal/espulp/ULPAlarm.c msgid "Only one %q can be set." @@ -1789,692 +1537,705 @@ msgstr "Lze nastavit pouze jeden %q ." msgid "Only one address is allowed" msgstr "Je povolena pouze jedna adresa" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" -msgstr "Lze nastavit pouze jeden alarm typu alarm.time" +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" +msgstr "Neznámý chybový kód %d" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." -msgstr "Může být nastaven pouze jeden alarm typu alarm.time." +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" +msgstr "mDNS pracuje pouze s vestavěnou WiFi" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" -msgstr "Pouze jedna barva může být nastavena jako transparentní" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" +msgstr "mDNS je již inicializováno" -#: py/moderrno.c -msgid "Operation not permitted" -msgstr "Operace není povolena" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" +msgstr "Nepodařilo se začít mDNS dotaz" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" -msgstr "Operace nebo funkce není podporována" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "Adresní rozsah není povolen" -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Operation timed out" -msgstr "Časový limit operace vypršel" +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "Chyba NVS" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "Došly mDNS sloty" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" -msgstr "Došla paměť" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" +msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" -msgstr "Došly sockety" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "Interní chyba" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" -msgstr "Restart PWM" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" -msgstr "PWM kanál je již využíván" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" -msgstr "PWM kanál A je již využíván" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" +msgstr "" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: ports/espressif/common-hal/audiobusio/__init__.c -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -msgid "Peripheral in use" -msgstr "Periférie je používána" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" -#: py/moderrno.c -msgid "Permission denied" -msgstr "Přístup odepřen" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" -msgstr "Z Deep Sleep nelze probudit pinem" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" -msgstr "Počet pinů je příliš velký" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" -msgstr "Přerušení od pinu je již používáno" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" +msgstr "Došly sockety" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "Pin je pouze vstupní" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" +msgstr "SocketPool je možné použít pouze s wifi.radio" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "Pin musí být na PWM kanálu B" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "%q musí být <= %u" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "Rozhraní musí být nastartováno" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "Chybná multicastová MAC adresa" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "Již skenuje wifi sítě" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" -msgstr "" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" +msgstr "Nepodařilo se alokovat paměť pro wifi scan" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "Plus všechny moduly na filesystému\n" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" +msgstr "Chyba alokace paměti WiFi" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" -msgstr "Polygon potřebuje nejméně 3 body" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" +msgstr "Pouze IPv4 adresy podporovány" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "Pokles napájení. Zkontroluj, zda je k dispozici dostatečné napájení." +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" +msgstr "Musí poskytnout pin MISO nebo MOSI" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" -msgstr "" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" +msgstr "Hardware je používán, zkuste alternativní piny" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -"Zmáčkněte jakoukoli klávesu pro spuštění REPLu. Použijte CTRL-D pro opětovné " -"načtení.\n" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "Předstírám hluboký spánek do alarmu, CTRL-C nebo zápisu souboru.\n" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +msgstr "" +"Frekvence musí být 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 nebo 1008 " +"Mhz" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" -msgstr "Program provedl IN bez načtení ISR" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." +msgstr "Při spuštění jsi stiskl tlačítko doleva." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "Program provedl OUT bez načtení OSR" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" +msgstr "timeout musí být < 655.35 s" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "Velikost programu je nesprávná" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" +msgstr "nenulový timeout musí být > 0.01" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" -msgstr "Program je příliš dlouhý" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "Nepodařilo se připojit: časový limit" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Pull not used when direction is output." -msgstr "" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" +msgstr "Nordic system firmware - nedostatek paměti" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" -msgstr "RISE_AND_FALL není na tomto čipu k dispozici" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" +msgstr "Neznámá chyba firmwaru: %04x" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" -msgstr "" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown security error: 0x%04x" +msgstr "Neznámá bezpečnostní chyba: 0x%04x" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" -msgstr "" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "Nelze probudit hranou na pinu, pouze úrovní" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "Zařízení je používáno" + +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "Všechny kanály jsou používány" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" -msgstr "" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "Nelze získat teplotu (°C)" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "RTC není na této desce podporován" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +msgstr "WatchDogTimer nelze deaktivovat v režimu RESET" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "Chyba generování náhodných čísel" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" +msgstr "timeout překročil maximální podporovanou hodnotu" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "Pouze pro čtení" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" +msgstr "" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "Filesystém pouze pro čtení" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "Nepodařilo se získat mutex, err 0x%04x" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "Přijatá odpověď nebyla validní" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "Nepodařilo se uvolnit mutex, err 0x%04x" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "Opětovné připojování" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "Konverze audia není implementována" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" -msgstr "Pokus o obnovení příliš brzo" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q musí být typu %q nebo %q, ne %q" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" -msgstr "RemoteTransmissionRequests je limitován na 8 bajtů" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" +msgstr "Velikost programu je nesprávná" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "Požadovaný režim AES je nepodporovaný" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "Velikost init programu není správná" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "Požadovaný zdroj nebyl nalezen" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "Prvky bufferu musí být 4 bajty dlouhé nebo méně" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" -msgstr "Pravý kanál nepodporován" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" +msgstr "Nekorespondující velikost dat" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" -msgstr "Běh v nouzovém režimu! Uložený kód není zpracováván.\n" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "Elementy v bufferu musí být <= 4 bajty" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" -msgstr "CSD formát SD karty není podporován" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" +msgstr "Touch alarmy nejsou dostupné" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" -msgstr "Inicializace SD karty" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" -msgstr "SDIO GetCardInfo chyba %d" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." +msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" -msgstr "Konfigurace SPI selhala" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" -msgstr "Chyba inicializace SPI" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "Periférie I2C je používána" + #: ports/raspberrypi/common-hal/busio/SPI.c msgid "SPI peripheral in use" msgstr "SPI periferie je používána" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" -msgstr "Opětovná inicializace SPI" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" +msgstr "UART periférie je používána" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "Pin musí být na PWM kanálu B" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." -msgstr "Scan již probíhá. Lze zastavit pomocí stop_scan." +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" +msgstr "RISE_AND_FALL není na tomto čipu k dispozici" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" +msgstr "PWM kanál je již využíván" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" +msgstr "PWM kanál A je již využíván" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "Velikost není podporována" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "Všechny stavové automaty jsou používány" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" -msgstr "SocketPool je možné použít pouze s wifi.radio" - -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" -msgstr "Zdrojové a cílové buffery musí být stejné délky" - -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" -msgstr "Specifikuj přesně jeden z data0 nebo data_pins" - -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" -msgstr "Musíš definovat monotonic_time nebo epoch_time" - -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" -msgstr "Parametr \"system\" musí být gnss.SatelliteSystem" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" +msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" -msgstr "Čas pro čtení teploty vypršel" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" +msgstr "Došly mDNS sloty" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." -msgstr "Modul `microcontroller` byl použit pro spuštění do nouzového režimu." +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" +msgstr "Nelze přistupovat k nezarovnanému IO registru" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" -msgstr "Výše uvedená výjimka byla přímá příčina následující výjimky:" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" +msgstr "Není možné zapisovat do paměti jen pro čtení" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "Počet prvků rgb_pin musí být 6, 12, 18, 24, nebo 30" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "Všechny časovače pro tento pin jsou používány" -#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c -msgid "The sample's %q does not match" +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." -msgstr "Fatální chyby firmware třetí strany." - -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." -msgstr "Tento mikrokontrolér nepodporuje kontinuální snímání." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" +msgstr "Počet pinů je příliš velký" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" +msgstr "Chybí jmp_pin. %q[%u] skáče na pin" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "%q[%u] používá extra pin" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" +msgstr "Chybí first_in_pin. %q[%u] čeká na základě pinu" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" +msgstr "%q[%u] čeká na vstup mimo rozsah" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +msgstr "Chybí first_in_pin. %q[%u] posunuje z pinu(ů)" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." -msgstr "Čas je v minulosti." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" +msgstr "%q[%u] posouvá dovnitř o více bitů než je počet pinů" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "Časový limit je příliš dlouhý: maximální limit je %d vteřin" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "Chybí first_out_pin. %q[%u] posunuje do pinu(ů)" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "%q[%u] posouvá ven o více bitů než je počet pinů" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" -msgstr "V samplu je příliš mnoho kanálů" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "Chybí first_set_pin. %q[%u] nastavuje pin(y)" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Too many channels in sample." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "Chybí first_out_pin. %q[%u] zapisuje do pinu(ů)" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" +msgstr "Chybí first_in_pin. %q[%u] čte z pinu(ů)" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -"Příliš mnoho sběrnic displaye; nezapomněl si na displayio.release_displays()?" -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "Příliš mnoho displejů" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" +msgstr "Program provedl IN bez načtení ISR" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" -msgstr "Velikost dat k zápisu je větší než %q" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" +msgstr "Program provedl OUT bez načtení OSR" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" -msgstr "Touch alarmy nejsou dostupné" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" +msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" -msgstr "De-inicializace UART" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" +msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" -msgstr "Inicializace UART" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" +msgstr "V programu není výstup" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" +msgstr "V programu není vstup" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" -msgstr "UART periférie je používána" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" +msgstr "V programu není vstup nebo výstup" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" -msgstr "Opětovná inicializace UART" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "Nekorespondující swap flag" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "Zápis na UART" - -#: main.c -msgid "UID:" -msgstr "UID:" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" +msgstr "Pouze IPv4 sokety podporovány" -#: shared-module/usb_hid/Device.c -msgid "USB busy" -msgstr "USB zaneprázdněno" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "Všechny DMA kanály jsou používány" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." -msgstr "USB zařízení potřebují více endpointů než je k dispozici." +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" +msgstr "wifi.Monitor není dostupný" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." -msgstr "USB zařízení používají příliš mnoho názvů rozhraní." +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q je pouze u této desky pouze pro čtení" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "Chyba USB" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "AP nemohl být spuštěn" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -msgstr "UUID řetězec neodpovídá 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" +msgstr "Na tomto hardware je dostupná pouze detekce hrany" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" -msgstr "Hodnota UUID není str, int ani byte buffer" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" +msgstr "Přerušení od pinu je již používáno" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" -msgstr "Nelze přistupovat k nezarovnanému IO registru" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" +msgstr "Z Deep Sleep nelze probudit pinem" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Unable to allocate buffers for signed conversion" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" +"Piny pro hluboký spánek musí používat náběžnou hranu s pulldown rezistorem" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." -msgstr "" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "Neplatná hodnota jednotky ADC" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" -msgstr "Není možné vytvořit zámek" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "Chyba inicializace zařízení DAC" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" -msgstr "I2C display nenalezen na %x" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "Chyba inicializace kanálu DAC" -#: py/parse.c -msgid "Unable to init parser" -msgstr "" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" +msgstr "je podporováno pouze mono" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" -msgstr "Nelze číst data palety barev" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" +msgstr "je podporován pouze oversampling 64" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "Jiný PWMAudioOut je již aktivní" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "Nepodařilo se začít mDNS dotaz" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "Délka vyrovnávací paměti %d je příliš velká. Musí být menší než %d" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." -msgstr "Není možné zapisovat do nvm." +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" +msgstr "Nepodařilo se nabufferovat sample" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "Není možné zapisovat do paměti jen pro čtení" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "Chyba inicializace I2C" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." -msgstr "Nelze zapsat do sleep_memory." +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" +msgstr "Chyba inicializace SPI" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" +msgstr "Opětovná inicializace SPI" + +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" -msgstr "Neznámá chyba BLE na %s:%d: %d" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "Nelze začít přerušení, RX je zaneprázdněn" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" -msgstr "Neznámá chyba BLE: %d" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" +msgstr "Zápis na UART" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" -msgstr "Neznámý chybový kód %d" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" +msgstr "De-inicializace UART" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" -msgstr "Neznámé selhání %d" +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" +msgstr "Opětovná inicializace UART" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" +msgstr "Čas pro čtení teploty vypršel" + +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" +msgstr "Časový limit čtení napětí vypršel" + +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." -msgstr "Neznámý důvod." +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" +msgstr "Chyba generování náhodných čísel" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" -msgstr "Neznámá bezpečnostní chyba: 0x%04x" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" -msgstr "Neznámá chyba firmwaru na %s:%d: %d" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" +msgstr "opětovný init timeru" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" -msgstr "Neznámá chyba firmwaru: %04x" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" +msgstr "opětovná inicializace kanálu" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" -msgstr "Neznámá chyba firmwaru: %d" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" +msgstr "Restart PWM" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." -msgstr "" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" +msgstr "SDIO GetCardInfo chyba %d" -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" -msgstr "Nepodporovaný barevný prostor" - -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" -msgstr "Nepodporovaná sběrnice dispalye" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "Jas není nastavitelný" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" -msgstr "Nepodporovaný hash algoritmus" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q musí být %d-%d" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "Skupina již byla použita" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" #: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -2484,455 +2245,496 @@ msgstr "" msgid "Use device tree to define %q devices" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" -msgstr "Verze byla neplatná" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "Pod minimální obnovovací frekvencí" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" -msgstr "Časový limit čtení napětí vypršel" +#: py/argcheck.c +msgid "function doesn't take keyword arguments" +msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" -msgstr "UPOZORNĚNÍ: Název souboru vašeho kódu má dvě koncovky\n" +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" +msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" -msgstr "WatchDogTimer nelze deaktivovat v režimu RESET" +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" +msgstr "funkci chybí %d povinné poziční argumenty" -#: py/builtinhelp.c +#: py/argcheck.c #, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +msgid "function expected at most %d arguments, got %d" msgstr "" -"Vítejte v Adafruit CircuitPython %s!\n" -"\n" -"Pro více informací navštivte circuitpython.org.\n" -"\n" -"Seznam vestavěných modulů můžete vypsat pomocí `help(\"modules\")`.\n" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " +#: py/argcheck.c +msgid "'%q' argument required" +msgstr "Je vyžadován argument '%q'" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" -msgstr "Probuzen alarmem.\n" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" +msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." -msgstr "Při spuštění jsi stiskl obě tlačítka." +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c +msgid "argument num/types mismatch" +msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." -msgstr "Při spuštění jsi stiskl tlačítko A." +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" +msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." -msgstr "Při spuštění jsi stiskl tlačítko DOWN." +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q musí být %d" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" -msgstr "Při spuštění jsi stiskl tlačítko BOOT" +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "%q musí být >= %d" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." -msgstr "" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "%q musí být <= %d" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." -msgstr "Při spuštění jsi stiskl tlačítko na pinu GPIO0." +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q musí být typu %q, ne %q" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." -msgstr "Při spuštění jsi stiskl tlačítko Rec." +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "%q délka musí být %d-%d" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." -msgstr "Při spuštění jsi stiskl tlačítko SW38." +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "Délka %q musí být >= %d" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." -msgstr "Při spuštění jsi stiskl tlačítko VOLUME." +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "Délka %q musí být <= %d" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." -msgstr "Při spuštění jsi stiskl středové tlačítko." +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "Délka %q musí být %d" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." -msgstr "Při spuštění jsi stiskl tlačítko doleva." +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q v %q musí být typu %q, ne %q" + +#: py/asmthumb.c +msgid "too many locals for native method" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" +msgstr "" + +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." -msgstr "Při spuštění jsi stiskl tlačítko reset." +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q() vyžaduje %d pozičních argumentů, ale pouze %d jich bylo zadáno" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" -msgstr "[zkráceno kvůli délce]" +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" +msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: py/objtype.c +#: py/bc.c #, c-format -msgid "__init__() should return None, not '%s'" -msgstr "" +msgid "function missing required positional argument #%d" +msgstr "funkci chybí požadovaný argument na pozici #%d" -#: py/objobject.c -msgid "__new__ arg must be a user-type" -msgstr "" +#: py/bc.c +msgid "function missing required keyword argument '%q'" +msgstr "funkci chybí argument specifikovaný klíčovým slovem" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/bc.c +msgid "function missing keyword-only argument" +msgstr "funkci chybí argument pouze pro klíčové slovo" + +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" +msgstr "Plus všechny moduly na filesystému\n" + +#: py/builtinhelp.c +msgid "object " +msgstr "objekt " + +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " je typu %q\n" + +#: py/builtinhelp.c +#, c-format +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" +"Vítejte v Adafruit CircuitPython %s!\n" +"\n" +"Pro více informací navštivte circuitpython.org.\n" +"\n" +"Seznam vestavěných modulů můžete vypsat pomocí `help(\"modules\")`.\n" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" -msgstr "anotace musí být identifikátor" +#: py/builtinimport.c +msgid "can't perform relative import" +msgstr "nelze provést relativní import" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" -msgstr "argsort není implementován pro zploštěná pole" +#: py/compile.c +msgid "multiple *x in assignment" +msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" #: py/compile.c -msgid "argument name reused" -msgstr "jméno argumentu znovupoužito" +msgid "invalid micropython decorator" +msgstr "" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" +#: py/compile.c +msgid "invalid arch" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" -msgstr "Pole a index musí mít stejnou délku" +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" -msgstr "pole má příliš mnoho dimenzí" +#: py/compile.c +msgid "'return' outside function" +msgstr "'return' je volán mimo funkci" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" -msgstr "pole je příliš velké" +#: py/compile.c +msgid "import * not at module level" +msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" #: py/compile.c -msgid "async for/with outside async function" +msgid "no binding for nonlocal found" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" -msgstr "pokus o získání (arg)min/(arg)max z prázdné sekvence" +#: py/compile.c +msgid "identifier redefined as nonlocal" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" -msgstr "osa je mimo rozsah" +#: py/compile.c +msgid "*x must be assignment target" +msgstr "∗x musí být cíl přiřazení" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" -msgstr "osa musí být None nebo integer" +#: py/compile.c +msgid "super() can't find self" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" -msgstr "osa je příliš dlouhá" +#: py/compile.c +msgid "* arg after **" +msgstr "* arg po **" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" -msgstr "" +#: py/compile.c +msgid "too many args" +msgstr "příliš mnoho argumentů" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: py/emitnative.c -msgid "binary op %q not implemented" +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" -msgstr "velikosti bitmapy musí odpovídat" +#: py/compile.c +msgid "'yield' outside function" +msgstr "'yield' je volán mimo funkci" -#: extmod/modrandom.c -msgid "bits must be 32 or less" -msgstr "počet bitů nesmí přesáhnout 32" +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "'yield from' volán uvnitř funkce async" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" -msgstr "" +#: py/compile.c +msgid "'await' outside function" +msgstr "'await' je volán mimo funkci" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" -msgstr "" +#: py/compile.c +msgid "unknown type '%q'" +msgstr "neznámý typ '%q'" -#: py/emitinlinethumb.c -msgid "branch not in range" -msgstr "" +#: py/compile.c +msgid "annotation must be an identifier" +msgstr "anotace musí být identifikátor" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" -msgstr "buffer je menší než požadovaná velikost" +#: py/compile.c +msgid "argument name reused" +msgstr "jméno argumentu znovupoužito" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" -msgstr "velikost bufferu musí být násobkem velikosti elementu" +#: py/compile.c +msgid "inline assembler must be a function" +msgstr "" + +#: py/compile.c +msgid "unknown type" +msgstr "neznámý typ" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "'label' vyžaduje 1 argument" + +#: py/compile.c +msgid "label redefined" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" -msgstr "buffer je příliš malý pro počet požadovaných bajtů" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "'align' vyžaduje 1 argument" + +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "'data' vyžaduje nejméně 2 argumenty" + +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "'data' vyžaduje celočíselné argumenty" + +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" #: py/emitbc.c msgid "bytecode overflow" msgstr "přetečení bytecode" -#: py/objarray.c -msgid "bytes length not a multiple of item size" -msgstr "Počet bajtů není násobkem velikosti prvku" - -#: py/objstr.c -msgid "bytes value out of range" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" -msgstr "může mít pouze jednoho rodiče" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" +msgstr "" #: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: py/compile.c -msgid "can't assign to expression" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "nelze zrušit sám sebe" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" +msgstr "" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" -msgstr "není možné převést %q na %q" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s' očekává nanejvýš r%d" -#: py/obj.c +#: py/emitinlinethumb.c py/emitinlinextensa.c #, c-format -msgid "can't convert %s to complex" -msgstr "nelze převést %s na complex" +msgid "'%s' expects a register" +msgstr "'%s' očekává registr" -#: py/obj.c +#: py/emitinlinethumb.c #, c-format -msgid "can't convert %s to float" -msgstr "nelze převést %s na float" +msgid "'%s' expects a special register" +msgstr "'%s' očekává speciální registr" -#: py/objint.c py/runtime.c +#: py/emitinlinethumb.c #, c-format -msgid "can't convert %s to int" -msgstr "" +msgid "'%s' expects an FPU register" +msgstr "'%s' očekává registr FPU" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' očekává {r0, r1, ...}" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" -msgstr "nelze převést complex na float" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' očekává integer (celé číslo)" -#: py/obj.c -msgid "can't convert to complex" -msgstr "nelze převést na complex" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' integer 0x%x nepatří do masky 0x%x" -#: py/obj.c -msgid "can't convert to float" -msgstr "nelze převést na float" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s' očekává adresu ve formátu [a, b]" -#: py/runtime.c -msgid "can't convert to int" -msgstr "nelze převést na int" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' očekává label" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: py/objtype.c -msgid "can't create instance" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' integer %d není v rozsahu %d..%d" + +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" msgstr "" -#: py/emitnative.c -msgid "can't do unary op of '%q'" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" #: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +msgid "conversion to object" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/emitnative.c +msgid "local '%q' used before type known" msgstr "" #: py/emitnative.c @@ -2943,26 +2745,10 @@ msgstr "" msgid "can't load with '%q' index" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" -msgstr "nelze provést relativní import" - -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" -msgstr "" - -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" -msgstr "nelze nastavit velikost bloku 512" - -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" -msgstr "nelze nastavit atribut '%q'" - #: py/emitnative.c msgid "can't store '%q'" msgstr "" @@ -2975,62 +2761,52 @@ msgstr "" msgid "can't store with '%q' index" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/emitnative.c +msgid "'not' not implemented" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/emitnative.c +msgid "can't do unary op of '%q'" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" -msgstr "nelze čekat" +#: py/emitnative.c +msgid "div/mod not implemented for uint" +msgstr "div/mod nejsou implementované pro uint" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" -msgstr "nelze přiřadit nový tvar" +#: py/emitnative.c +msgid "comparison of int and uint" +msgstr "porovnání int a uint" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" -msgstr "nelze převést complex na dtype" - -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" -msgstr "nelze převést typ complex" - -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" -msgstr "nelze smazat prvky pole" - -#: py/compile.c -msgid "cannot emit native code for this architecture" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" +msgstr "" + +#: py/emitnative.c +msgid "casting" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" -msgstr "nelze změnit rozměry pole" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" +msgstr "" #: py/emitnative.c -msgid "casting" +msgid "must raise an object" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" -msgstr "opětovná inicializace kanálu" +#: py/emitnative.c +msgid "native yield" +msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" #: py/modbuiltins.c @@ -3041,1174 +2817,1318 @@ msgstr "" msgid "chr() arg not in range(256)" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" -msgstr "kód mimo rozsah 0~127" - -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" -msgstr "" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "pow() nepodporuje 3 argumenty" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" -msgstr "porovnání int a uint" +#: py/moderrno.c +msgid "Operation not permitted" +msgstr "Operace není povolena" -#: py/objcomplex.c -msgid "complex divide by zero" -msgstr "" +#: py/moderrno.c +msgid "No such file/directory" +msgstr "Žádný takový soubor / adresář" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/moderrno.c +msgid "Input/output error" +msgstr "Chyba vstupu/výstupu" + +#: py/moderrno.c +msgid "Permission denied" +msgstr "Přístup odepřen" + +#: py/moderrno.c +msgid "File exists" +msgstr "soubor existuje" + +#: py/moderrno.c +msgid "No such device" +msgstr "Žádné takové zařízení" + +#: py/moderrno.c +msgid "No space left on device" +msgstr "Na zařízení nezůstal žádný prostor" + +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/modmath.c +msgid "negative factorial" +msgstr "záporný faktoriál" + +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/nativeglue.c +msgid "set unsupported" +msgstr "set neoodporován" + +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" -msgstr "poškozený soubor" +#: py/nativeglue.c +msgid "float unsupported" +msgstr "float není podporován" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" +msgstr "není možné převést %q na %q" + +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" +msgstr "Při zpracování uvedené výjimky nastala další výjimka:" + +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" +msgstr "Výše uvedená výjimka byla přímá příčina následující výjimky:" + +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " Soubor \"%q\", řádek %d" + +#: py/obj.c +msgid " File \"%q\"" +msgstr " Soubor \"%q\"" + +#: py/obj.c +msgid ", in %q\n" +msgstr ", v% q\n" + +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" -msgstr "nelze zjistit verzi SD karty" +#: py/obj.c +msgid "can't convert to float" +msgstr "nelze převést na float" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" +msgstr "nelze převést %s na float" + +#: py/obj.c +msgid "can't convert to complex" +msgstr "nelze převést na complex" + +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" +msgstr "nelze převést %s na complex" + +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" -msgstr "data musí být iterovatelná" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" +msgstr "objekt '%s' není tuple or nebo list" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" -msgstr "data musí mít stejnou délku" +#: py/obj.c +msgid "tuple/list has wrong length" +msgstr "tuple/list má špatnou délku" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/obj.c #, c-format -msgid "data pin #%d in use" -msgstr "datový pin #%d je používán" +msgid "requested length %d but object has length %d" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" -msgstr "datový typ nebyl rozpoznán" +#: py/obj.c +msgid "indices must be integers" +msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "Indexy %q musí být celá čísla, nikoli %s" + +#: py/obj.c +msgid "object has no len" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" +msgstr "objekt typu '%s' nemá len()" + +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "'%s' objekt nepodporuje smazání položky" + +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "'%s' objekt není vložitelný" + +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "'%s' objekt nepodporuje přiřazení položky" + +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "destination must be an array of type 'h'" +#: py/objarray.c +msgid "bytes length not a multiple of item size" +msgstr "Počet bajtů není násobkem velikosti prvku" + +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" +msgstr "" + +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" +msgstr "memoryview: délka není násobkem velikosti položky" + +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" -msgstr "dimenze nesouhlasí" - -#: py/emitnative.c -msgid "div/mod not implemented for uint" -msgstr "div/mod nejsou implementované pro uint" +#: py/objarray.c +msgid "memoryview offset too large" +msgstr "" -#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c -msgid "divide by zero" -msgstr "dělení nulou" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" +msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" -msgstr "dtype musí být float nebo complex" +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "0.0 na komplexní mocninu" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objdeque.c +msgid "full" msgstr "" #: py/objdeque.c msgid "empty" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" -msgstr "prázdný soubor" +#: py/objdict.c +msgid "dict update sequence has wrong length" +msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: py/objstr.c -msgid "empty separator" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: py/objstr.c -msgid "end of format while looking for conversion specifier" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" -msgstr "epoch_time není podporován na této desce" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" +msgstr "generátor způsobil StopIteration" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: py/objstr.c -msgid "expected ':' after format specifier" +#: py/objint.c +msgid "float too big" msgstr "" -#: py/obj.c -msgid "expected tuple/list" +#: py/objint.c +#, c-format +msgid "value must fit in %d byte(s)" msgstr "" -#: py/modthread.c -msgid "expecting a dict for keyword args" -msgstr "" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" +msgstr "Není podpora long integer" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" -msgstr "" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" -msgstr "zápis do souboru není dostupný" - -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" -msgstr "První argument musí být zavolatelný" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" -msgstr "první argument musí být funkce" - -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" -msgstr "první argument musí být tuple nebo ndarray" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" +msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" -msgstr "první dva argumenty musí být ndarray" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "%q krok nemůže být nula" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" -msgstr "" +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "Nelze použít řez podtřídy" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" -#: py/nativeglue.c -msgid "float unsupported" -msgstr "float není podporován" - -#: extmod/moddeflate.c -msgid "format" +#: py/objstr.c +msgid "empty separator" msgstr "" #: py/objstr.c -msgid "format needs a dict" -msgstr "" +msgid "rsplit(None,n)" +msgstr "rsplit(None,n)" #: py/objstr.c -msgid "format string didn't convert all arguments" +msgid "bad format string" msgstr "" #: py/objstr.c -msgid "format string needs more arguments" -msgstr "" +#, c-format +msgid "unmatched '%c' in format" +msgstr "neshoduje se '%c' ve formátu" -#: py/objdeque.c -msgid "full" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" -#: py/argcheck.c +#: py/objstr.c #, c-format -msgid "function expected at most %d arguments, got %d" +msgid "unknown conversion specifier %c" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" -msgstr "funkce je definována pouze pro ndarraye" - -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" -msgstr "funkce je implementována jen pro ndarraye" - -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" -msgstr "funkci chybí %d povinné poziční argumenty" - -#: py/bc.c -msgid "function missing keyword-only argument" -msgstr "funkci chybí argument pouze pro klíčové slovo" +#: py/objstr.c +msgid "%q index out of range" +msgstr "Index %q je mimo rozsah" -#: py/bc.c -msgid "function missing required keyword argument '%q'" -msgstr "funkci chybí argument specifikovaný klíčovým slovem" +#: py/objstr.c +msgid "attributes not supported" +msgstr "" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" -msgstr "funkci chybí požadovaný argument na pozici #%d" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" +msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/objstr.c +msgid "invalid format specifier" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" -msgstr "generátor způsobil StopIteration" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" +msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" -msgstr "hash je konečný" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "Specifikátor zarovnání '=' není ve formátovacím řetězci povolen" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/objstr.c +msgid "incomplete format" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy arch" -msgstr "nekopmatibilní architektura .mpy" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" +msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy file" -msgstr "nekompatibilní .mpy soubor" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" +msgstr "" #: py/objstr.c -msgid "incomplete format" +msgid "format string didn't convert all arguments" msgstr "" #: py/objstr.c -msgid "incomplete format key" +msgid "non-hex digit" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" -msgstr "index musí být tuple nebo int" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "Volání super().__init__() před přístupem k nativnímu objektu." + +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" -msgstr "výchozí hodnoty musí být iterovatelné" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" +msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" -msgstr "dimenze vstupu a výstupu se liší" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" +msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" -msgstr "vstupní a výstupní tvar je růzmý" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" +msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" -msgstr "vstupní argument musí být integer, tuple nebo list" +#: py/objtype.c +msgid "can't create instance" +msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" -msgstr "vstupní pole nejsou kompatibilní" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" +msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" -msgstr "vstupní dtype musí být float nebo complex" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" +msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" -msgstr "vstup není iterovatelný" +#: py/objtype.c +msgid "multiple inheritance not supported" +msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" -msgstr "vstup musí být 1- nebo 2-d" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" +msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" -msgstr "vstup musí být 1D ndarray" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" +msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" -msgstr "vstup musí být hustý ndarray" +#: py/parse.c +msgid "not a constant" +msgstr "není konstanta" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" -msgstr "vstup musí být ndarray" +#: py/parse.c +msgid "Unable to init parser" +msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" -msgstr "vstup musí být ndarray nebo scalar" +#: py/parse.c +msgid "unexpected indent" +msgstr "neočekávané odsazení" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" -msgstr "vstup musí být jednorozměrný" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" +msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: py/emitinlinerv32.c -msgid "invalid RV32 instruction '%q'" +#: py/persistentcode.c +msgid "incompatible .mpy file" +msgstr "nekompatibilní .mpy soubor" + +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" -msgstr "chybné bits_per_pixel %d, musí být 1, 2, 4, 8, 16, 24, or 32" +#: py/persistentcode.c +msgid "incompatible .mpy arch" +msgstr "nekopmatibilní architektura .mpy" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "špatný certifikár" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "Objekt '%q' nepodporuje '%q'" + +#: py/qstr.c +msgid "name too long" +msgstr "" + +#: py/runtime.c +msgid "name not defined" +msgstr "" + +#: py/runtime.c +msgid "name '%q' isn't defined" +msgstr "" + +#: py/runtime.c +msgid "unsupported type for operator" +msgstr "" + +#: py/runtime.c +msgid "unsupported type for %q: '%s'" +msgstr "" + +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" +msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -#, c-format -msgid "invalid destination buffer, must be an array of type: %c" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: shared-bindings/bitmaptools/__init__.c +#: py/runtime.c #, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +msgid "need more than %d values to unpack" msgstr "" -#: shared-bindings/bitmaptools/__init__.c +#: py/runtime.c #, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" -msgstr "chybná element_size %d, musí být 1, 2, nebo 4" +msgid "too many values to unpack (expected %d)" +msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" -msgstr "špatná výjimka" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" +msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" -msgstr "špatný hostname" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "'%s' objekt nemá žádný atribut '%q'" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" -msgstr "špatný klíč" +#: py/runtime.c +msgid "can't set attribute '%q'" +msgstr "nelze nastavit atribut '%q'" -#: py/compile.c -msgid "invalid micropython decorator" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" -msgstr "neplatné nastavení" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "Objekt '%q' není iterovatelný" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "Objekt '%q' není iterátor" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: py/parsenum.c +#: py/runtime.c +msgid "memory allocation failed, heap is locked" +msgstr "" + +#: py/runtime.c #, c-format -msgid "invalid syntax for integer with base %d" +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: py/runtime.c +msgid "can't convert to int" +msgstr "nelze převést na int" + +#: py/runtime.c +msgid "division by zero" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: py/vm.c +msgid "local variable referenced before assignment" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: py/vm.c +msgid "opcode" +msgstr "opcode" + +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "Není možné vytvořit nový adaptér; použití _bleio.adapter;" + +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "Není možné nastavit adresu" + +#: shared-bindings/_bleio/Adapter.c +#, c-format +msgid "interval must be in range %s-%s" msgstr "" -#: py/compile.c -msgid "label redefined" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" +msgstr "nenulový timeout musí být >= interval" + +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: py/vm.c -msgid "local variable referenced before assignment" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "CharacteristicBuffer psaní není poskytováno" + +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." msgstr "" +"Připojení bylo odpojeno a nelze jej dále používat. Vytvořte nové připojení." -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "Buffer je příliš krátký o %d bajtů" + +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" +msgstr "Žádné připojení: nelze určit délku" + +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +msgstr "UUID řetězec neodpovídá 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" + +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" +msgstr "Hodnota UUID není str, int ani byte buffer" + +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" -msgstr "mDNS je již inicializováno" +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" +msgstr "Pouze pro čtení" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" -msgstr "mDNS pracuje pouze s vestavěnou WiFi" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "Nesprávná velikost vyrovnávací paměti" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" +msgstr "index musí být tuple nebo int" + #: shared-bindings/_stage/Layer.c msgid "map buffer too small" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" -msgstr "" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" +msgstr "Pin je pouze vstupní" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c #, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "maximální počet dimenzí je " +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "Klíč musí být dlouhý 16, 24 nebo 32 bajtů" -#: py/runtime.c -msgid "maximum recursion depth exceeded" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" +msgstr "Požadovaný režim AES je nepodporovaný" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" -msgstr "maxiter musí být > 0" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" +msgstr "Zdrojové a cílové buffery musí být stejné délky" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" -msgstr "maxiter by měl být > 0" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB operuje najednou pouze 16 bajtů" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "Bloky CBC musí být násobky 16 bajtů" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "Hodnoty pole by měly být jednoduché bajty." -#: py/objarray.c -msgid "memoryview offset too large" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." +msgstr "Nelze zapsat do sleep_memory." -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" -msgstr "memoryview: délka není násobkem velikosti položky" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" +msgstr "Očekáván typ %q" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" -msgstr "" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" +msgstr "RTC není na této desce podporován" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" -msgstr "" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" +msgstr "Musíš definovat monotonic_time nebo epoch_time" -#: py/runtime.c -msgid "module '%q' has no attribute '%q'" -msgstr "" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" +msgstr "epoch_time není podporován na této desce" -#: py/builtinimport.c -msgid "module not found" -msgstr "" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." +msgstr "Čas je v minulosti." -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" -msgstr "" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q musí být bytearray nebo pole typu 'H' nebo 'B'" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" -msgstr "" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" +msgstr "Nehraje" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "Nelze nahrávat do souboru" -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "Cílová kapacita je menší než destination_length." -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q musí být bytearray nebo pole typu 'h', 'H', 'b', nebo 'B'" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" -msgstr "délka ndarray přetekla" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" +msgstr "" -#: py/runtime.c +#: shared-bindings/audioi2sin/I2SIn.c #, c-format -msgid "need more than %d values to unpack" +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: py/modmath.c -msgid "negative factorial" -msgstr "záporný faktoriál" +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" +msgstr "%q a %q musí být rozdílné" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" -msgstr "" +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Funkce vyžaduje zámek" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "není vložena SD karta" - -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" +msgstr "zdrojová paleta je příliš velká" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "Velikost bitmapy a počet bitů na hodnotu se musí shodovat" -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +msgstr "Pro barevný prostor L8 musí mít vstupní bitmapa 8 bitů na pixel" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" -msgstr "žádná odpověď z SD karty" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +msgstr "Pro barevný prostor RGB musí mít vstupní bitmapa 16 bitů na pixel" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" +msgstr "Nepodporovaný barevný prostor" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" -msgstr "nenulový timeout musí být > 0.01" - -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" -msgstr "nenulový timeout musí být >= interval" - -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/parse.c -msgid "not a constant" -msgstr "není konstanta" - -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" -msgstr "není implementováno pro komplexní dtype" - -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" -msgstr "není podporováno pro vstupní typy" - -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" msgstr "" -#: py/builtinhelp.c -msgid "object " -msgstr "objekt " +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "Pole souřadnic mají různé délky" -#: py/obj.c +#: shared-bindings/bitmaptools/__init__.c #, c-format -msgid "object '%s' isn't a tuple or list" -msgstr "objekt '%s' není tuple or nebo list" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "object does not support DigitalInOut protocol" -msgstr "" - -#: py/obj.c -msgid "object doesn't support item assignment" -msgstr "" +msgid "invalid element_size %d, must be, 1, 2, or 4" +msgstr "chybná element_size %d, musí být 1, 2, nebo 4" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/obj.c -msgid "object has no len" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgstr "chybné bits_per_pixel %d, musí být 1, 2, 4, 8, 16, 24, or 32" -#: py/obj.c -msgid "object isn't subscriptable" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" +msgstr "velikosti bitmapy musí odpovídat" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: py/obj.c +#: shared-bindings/bitops/__init__.c #, c-format -msgid "object of type '%s' has no len()" -msgstr "objekt typu '%s' nemá len()" - -#: py/obj.c -msgid "object with buffer protocol required" +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" -msgstr "vypnuto" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" +msgstr "Žádná výchozí sběrnice %q" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" -msgstr "offset je příliš velký" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "Otočení displeje musí být po 90 stupních" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" -msgstr "offset musí být >= 0" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q musí být 1, pokud %q je True" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "Displej musí mít 16bitový barevný prostor." -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" -msgstr "je podporováno pouze mono" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." +msgstr "Musí být podtřída %q." -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" -msgstr "pouze ndarraye mohou být spojeny" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" +msgstr "RemoteTransmissionRequests je limitován na 8 bajtů" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "je podporován pouze oversampling 64" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "Nelze nastavit hodnotu, když směr je vstup." -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." msgstr "" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/vm.c -msgid "opcode" -msgstr "opcode" - -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" -msgstr "" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "Nelze odstranit hodnoty" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" -msgstr "operace je definována pouze pro 2D pole" - -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" -msgstr "operace je definována pouze pro ndarray pole" - -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" -msgstr "operace je immplementována pouze pro 1D boolean pole" - -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" -msgstr "" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" +msgstr "nepodporovaný typ% q" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" -msgstr "výstupní pole je příliš malé" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" +msgstr "Nová bitmapa musí mít stejnou velikost jako původní bitmapa" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" -msgstr "" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" +msgstr "offset musí být >= 0" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" -msgstr "" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "Pokus o obnovení příliš brzo" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" -msgstr "" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "Buffer není bytearray." -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" -msgstr "" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" +msgstr "Parametr \"system\" musí být gnss.SatelliteSystem" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" -msgstr "" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" +msgstr "Nepodporovaný hash algoritmus" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c -msgid "overflow converting long int to machine word" -msgstr "" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" +msgstr "Nevalidní IP string" -#: py/modstruct.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format -msgid "pack expected %d items for packing (got %d)" +msgid "Address must be %d bytes long" +msgstr "Adresa musí být %d bajtů dlouhá" + +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "Pro IP je podporován pouze int nebo string" + +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" -msgstr "" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" +msgstr "Adresní rozsah se překlápí přes maximální možnou adresu" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" -msgstr "pop z prázdného %q" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q obsahuje duplicitní piny" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" -msgstr "port musí být >= 0" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q a %q obsahují duplicitní piny" -#: py/compile.c -msgid "positional arg after **" -msgstr "" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" +msgstr "kód mimo rozsah 0~127" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" -msgstr "" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." +msgstr "Není možné zapisovat do nvm." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" -msgstr "" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" +msgstr "Specifikuj přesně jeden z data0 nebo data_pins" -#: extmod/modre.c -msgid "regex too complex" -msgstr "" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "Nepodařilo se odeslat příkaz." -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "Pole musí obsahovat poloviční slova (typ „H“)" + +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: py/objint_longlong.c py/parsenum.c -msgid "result overflows long long storage" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +msgstr "Počet prvků rgb_pin musí být 6, 12, 18, 24, nebo 30" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -4218,439 +4138,533 @@ msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" -msgstr "" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" +msgstr "Je nutné použít několik kolíků 6 rgb, nikoli %d" -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "rsplit(None,n)" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +msgstr "%d adresní pin, %d rgb pin a %d dlaždice indikuje výšku %d, ne %d" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" -msgstr "" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" +msgstr "port musí být >= 0" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" -msgstr "" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" +msgstr "buffer je příliš malý pro počet požadovaných bajtů" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" +msgstr "Jméno nebo služba není známa" + +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" -msgstr "set neoodporován" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "Nelze změnit USB zařízení" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" +msgstr "Soubor nenalezen" + +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" -msgstr "tvar musí být integer nebo tuple integerů" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" +msgstr "zápis do souboru není dostupný" -#: shared-module/msgpack/__init__.c -msgid "short read" -msgstr "" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" +msgstr "špatná výjimka" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" -msgstr "" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q, a %q musí mít všechny shodnou délku" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" +"Objekt byl deinicializován a nelze jej dále používat. Vytvořte nový objekt." -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" +msgstr "%q je mimo hranice" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" +msgstr "Špatné heslo v hex" + +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" +msgstr "špatný hostname" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "Chybná MAC adresa" + +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "AuthMode.OPEN nepoužívá heslo" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "Chybné BSSID" + +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "Autentizace selhala" + +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" +msgstr "Žádná síť s takovým SSID" + +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" +msgstr "Neznámé selhání %d" + +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" +msgstr "Žádné I2C zařízení na adrese: 0x%x" + +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "Neplatná velikost bloku" + +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "Dekodér nelze přiřadit" + +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "Soubor MP3 se nepodařilo analyzovat" + +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "zdrojová paleta je příliš velká" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" +msgstr "Pouze jedna barva může být nastavena jako transparentní" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "Vrstva již v groupě je" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" -msgstr "" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "Vrstva musí být Group nebo TileGrid" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" -msgstr "" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" +msgstr "Nelze číst data palety barev" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" -msgstr "" +#: shared-module/displayio/__init__.c +msgid "Too many displays" +msgstr "Příliš mnoho displejů" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" +"Příliš mnoho sběrnic displaye; nezapomněl si na displayio.release_displays()?" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" +msgstr "Nepodporovaná sběrnice dispalye" + +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: py/objstrunicode.c +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c #, c-format -msgid "string indices must be integers, not %s" -msgstr "" +msgid "Unable to find I2C Display at %x" +msgstr "I2C display nenalezen na %x" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." +msgstr "Tento mikrokontrolér nepodporuje kontinuální snímání." + +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "Mapování LED musí korespondovat s velikostí displeje" + +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" -msgstr "timeout překročil maximální podporovanou hodnotu" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" +msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" -msgstr "timeout musí být < 655.35 s" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" +msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" -msgstr "opětovný init timeru" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" +msgstr "Pokus o alokování %d bloků" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: py/compile.c -msgid "too many args" -msgstr "příliš mnoho argumentů" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" -msgstr "příliš mnoho dimenzí" +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" +msgstr "Špatný formát" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" -msgstr "" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" +msgstr "Není k dispozici žádný časovač" -#: py/runtime.c +#: shared-module/rgbmatrix/RGBMatrix.c #, c-format -msgid "too many values to unpack (expected %d)" -msgstr "" +msgid "Internal error #%d" +msgstr "Vnitřní chyba #%d" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" -msgstr "tuple/list má špatnou délku" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" +msgstr "není vložena SD karta" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" -msgstr "" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" +msgstr "nelze zjistit verzi SD karty" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" -msgstr "" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" +msgstr "žádná odpověď z SD karty" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" -msgstr "" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" +msgstr "CSD formát SD karty není podporován" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" -msgstr "" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" +msgstr "nelze nastavit velikost bloku 512" -#: py/objtype.c -msgid "type isn't an acceptable base type" -msgstr "" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "Chybný soket pro TLS" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" +msgstr "špatný klíč" + +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "špatný certifikár" + +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/parse.c -msgid "unexpected indent" -msgstr "neočekávané odsazení" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' a 'O' nejsou podporované typy formátů" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" -msgstr "" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "%q musí být pole typu 'h'" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" -msgstr "" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" +msgstr "Žádný pulldown na pinu; doporučeno 1Mohm" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" -msgstr "" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" +msgstr "Žádný USB host port není inicializován" -#: py/compile.c -msgid "unknown type" -msgstr "neznámý typ" +#: shared-module/usb/core/Device.c +msgid "Pipe error" +msgstr "" -#: py/compile.c -msgid "unknown type '%q'" -msgstr "neznámý typ '%q'" +#: shared-module/usb/core/Device.c +msgid "No configuration set" +msgstr "Konfigurace není nastavena" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" -msgstr "neshoduje se '%c' ve formátu" +#: shared-module/usb_hid/Device.c +msgid "USB busy" +msgstr "USB zaneprázdněno" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" -msgstr "" +#: shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "Chyba USB" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" -msgstr "nepodporovaný typ% q" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" +msgstr "může mít pouze jednoho rodiče" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" -msgstr "" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" +msgstr "Polygon potřebuje nejméně 3 body" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" +msgstr "Opětovné připojování" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" +msgstr "Ok" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" +msgstr "Vypnuto" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" -msgstr "" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "[zkráceno kvůli délce]" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" +"\n" +"Jste v bezpečnostním režimu z důvodu:\n" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." +msgstr "Pokles napájení. Zkontroluj, zda je k dispozici dostatečné napájení." -#: py/runtime.c -msgid "unsupported type for operator" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" +msgstr "Při spuštění jsi stiskl tlačítko BOOT" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." +msgstr "Při spuštění jsi stiskl tlačítko reset." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "Disk CIRCUITPY nelze nalézt nebo vytvořit." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." +msgstr "Modul `microcontroller` byl použit pro spuštění do nouzového režimu." -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "Chyba v safemode.py." -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: extmod/moddeflate.c -msgid "wbits" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." +msgstr "USB zařízení potřebují více endpointů než je k dispozici." -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." +msgstr "USB zařízení používají příliš mnoho názvů rozhraní." -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "Bootovací zařízení musí být první (rozhraní #0)." -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "Interní watchdog timer expiroval." -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" -msgstr "wifi.Monitor není dostupný" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "Jádro kódu CircuitPython tvrdě havarovalo. Jejda!\n" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." +msgstr "Alokace heapu při neběžícím VM." -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." +msgstr "Nepodařilo se zapsat do interní paměti." -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." +msgstr "Fatální chyba: přístup k paměti nebo chyba instrukce." -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" -msgstr "špatný dtype" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "Chyba přerušení." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" -msgstr "špatný typ indexu" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." +msgstr "NLR skok selhal. Pravděpodobně poškozením paměti." -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." +msgstr "Fatální chyby firmware třetí strany." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" +"\n" +"Prosím, založte issue s vaším programem na github.com/adafruit/circuitpython/" +"issues." -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" +"\n" +"Stiskněte reset pro ukončení nouzového režimu.\n" -#: py/runtime.c -msgid "wrong number of values to unpack" -msgstr "" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "Došlo k chybě při načítání '%s'\n" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" -msgstr "" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "Neplatná unicode escape sekvence" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" -msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" +msgstr "vypnuto" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" -msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "Není IP" #~ msgid "asm overflow" #~ msgstr "přetečení v asm" diff --git a/locale/el.po b/locale/el.po index f4294d794a8..af3339e612a 100644 --- a/locale/el.po +++ b/locale/el.po @@ -18,1816 +18,1619 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -"\n" -"Η εκτέλεση του κώδικα ολοκληρώθηκε.\n" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -"\n" -"Ο κώδικας σταμάτησε λόγω της αυτόματης επαναφόρτωσης. Η επαναφόρτωση θα " -"γίνει σύντομα.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -"\n" -"Παρακαλώ δημιουργήστε ένα πρόβλημα με το πρόγραμμά σας στο github.com/" -"adafruit/circuitpython/issues." -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -"\n" -"Πατήστε reset για να βγείτε από την ασφαλή λειτουργία.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -"\n" -"Είσαστε τε ασφαλή λειτουργία διότι:\n" -#: py/obj.c -msgid " File \"%q\"" -msgstr " Αρχείο \"%q\"" +#: extmod/moddeflate.c +msgid "format" +msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " Αρχείο \"%q\", γραμμή %d" +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " είναι τύπου %q\n" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "" -#: main.c -msgid " not found.\n" -msgstr " δεν βρέθηκε.\n" +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "" -#: main.c -msgid " output:\n" -msgstr " έξοδος:\n" +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modrandom.c +msgid "bits must be 32 or less" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -"%d pin διεύθυνσης, %d rgb ping και %d πλακίδια αναδεικνύουν ύψος %d, όχι %d" -#: py/emitinlinextensa.c -#, c-format -msgid "%d is not a multiple of %d" +#: extmod/modre.c +msgid "splitting with sub-captures" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q και %q περιέχουν διπλότυπα pins" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q και %q πρεπει να είναι διαφορετικά" +#: extmod/modre.c +msgid "Error in regex" +msgstr "Σφάλμα σε regex" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q περιέχει διπλότυπα pins" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" -msgstr "%q αποτυχία: %d" +#: extmod/modzlib.c +msgid "compression header" +msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %q" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q είναι σε χρήση" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "" -#: py/objstr.c -msgid "%q index out of range" -msgstr "%q δείκτης εκτός εμβέλειας" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι %s" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: ports/stm/common-hal/audioio/AudioOut.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c -msgid "%q init failed" -msgstr "%q εκκίνηση απέτυχε" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q είναι %q" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q είναι μόνο για ανάγνωση για αυτήν την πλακέτα" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "%q μήκος πρέπει να είναι %d" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "%q μήκος πρέπει να είναι %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "%q μήκος πρέπει να είναι <= %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "%q μήκος πρέπει να είναι >= %d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q πρέπει να είναι %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c -#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q πρέπει να είναι %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q πρέπει να είναι 1 όταν %q είναι True" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 16, 24, or 32" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" msgstr "" -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 8 or 16" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q must be 8, 16, 24, or 32" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "%q πρέπει να είναι <= %d" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "%q πρέπει να είναι <= %u" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "" -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "%q πρέπει να είναι >= %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q πρέπει να είναι bytearray ή array τύπου 'H' ή 'B'" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q πρέπει να είναι bytearray ή array τύπου 'h', 'H', 'b', ή 'B'" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "%q πρέπει να είναι υποκλάση του %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "%q πρέπει να είναι πίνακας τύπου 'H'" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "%q πρέπει να είναι λίστα τύπου 'h'" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q πρέπει να είναι τύπου %q ή %q, όχι %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q πρέπει να είναι τύπου %q, όχι %q" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q πρέπει να είναι δύναμη του 2" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "%q εκτός ορίων" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "%q εκτός εμβέλειας" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "%q βήμα δεν μπορεί να είναι μηδέν" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q() παίρνει %d ορίσματα θέσεως αλλά %d δόθηκαν" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q, και %q πρέπει να είναι όλα του ιδίου μήκους" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "%q[%u] μετατοπίζει σε περισσότερα bits από αριθμό pin" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "%q[%u] μετατοπίζει από περισσότερα bits από αριθμό pin" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "%q[%u] χρησιμοποιεί παραπάνω pin" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "%s σφάλμα 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "'%q' όρισμα απαιτείται" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "" -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" -msgstr "'%q' αντικείμενο δεν υποστηρίζει '%q'" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "'%q' αντικείμενο δεν είναι επαναλήπτης" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "'%q' αντικείμενο δεν είναι επαναληπτικό" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' περιμένει μια ετικέτα" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' περιμένει έναν καταχωρητή" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' περιμένει έναν ειδικό καταχωρητή" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' περιμένει έναν FPU καταχωρητή" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s' περιμένει μια διεύθυνση της μορφής [a, b]" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' περιμένει έναν ακέραιο" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s' περιμένει το πολύ r%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' περιμένει {r0, r1, ...}" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' ακέραιος %d δεν είναι μέσα στο επιτρεπτό εύρος %d..%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' ακέραιος 0x%x δεν χωράει στην μάσκα 0x%x" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "'%s' αντικείμενο δεν υποστηρίζει ορισμό πράγματος" - -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "'%s' αντικείμενο δεν υποστηρίζει διαγραφή πράγματος" - -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "'%s' αντικείμενο δεν έχει γνώρισμα '%q'" - -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "'%s' αντικείμενο δεν είναι subscriptable" - -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "Ευθυγράμμιση του '=' δεν επιτρέπεται εντός προσδιοριστή string format" - -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' και 'O' δεν είναι υποστηριζόμενοι τύποι format" - -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "'align' απαιτεί τουλάχιστον ένα όρισμα" - -#: py/compile.c -msgid "'await' outside function" -msgstr "'await' εκτός συνάρτησης" - -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "'break'/'continue' εκτός επανάληψης" - -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "'data' απαιτεί τουλάχιστον 2 παραμέτρους" - -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "'data' απαιτεί ακέραιες παραμέτρους" - -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "'label' απαιτεί ένα όρισμα" - -#: py/emitnative.c -msgid "'not' not implemented" -msgstr "" - -#: py/compile.c -msgid "'return' outside function" -msgstr "'return' εκτός συνάρτησης" - -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "'yield from' εκτός ασύνχρονης συνάρτησης" - -#: py/compile.c -msgid "'yield' outside function" -msgstr "'yield' εκτός συνάρτησης" - -#: py/compile.c -msgid "* arg after **" -msgstr "* όρισμα μετά **" - -#: py/compile.c -msgid "*x must be assignment target" -msgstr "*x πρέπει να είναι στόχος ανάθεσης" - -#: py/obj.c -msgid ", in %q\n" -msgstr ", στο %q\n" - -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" -msgstr ".show(x) αφαιρέθηκε. Χρησιμοποιήστε το .root_group = x" - -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "0.0 σε μία σύνθετη δύναμη" - -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "pow() με 3 παραμέτρους δεν υποστηρίζεται" - -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "AP δεν μπόρεσε να εκκινηθεί" - -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "Η διεύθυνση πρέπει να είναι %d bytes μεγάλη" - -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "Εμβέλεια διευθύνσεων δεν επιτρέπεται" - -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "Όλα τα περιφεριακά CAN είναι σε χρήση" - -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "Όλα τα I2C περιφεριακά ειναι σε χρήση" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "Όλα τα RX FIFOs είναι σε χρήση" - -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "Όλα τα SPI περιφεριακά είναι σε χρήση" - -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "Όλα τα UART περιφεριακά ειναι σε χρήση" - -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "Όλα τα κανάλια είναι σε χρήση" - -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "Όλα τα κανάλια dma είναι σε χρήση" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "Όλα τα κανάλια συμβάντων είναι σε χρήση" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "Όλες οι μηχανές κατάστασης είναι σε χρήση" - -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" -msgstr "Όλα τα κανάλια συμβάντων συγχρονισμού είναι σε χρήση" - -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "Όλοι οι χρονιστές για αυτό το pin χρησιμοποιούνται ήδη" - -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "Όλοι οι χρονιστές βρίσκονται σε χρήση" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "Ήδη διαφημίζουμε." - -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "Ύπάρχει ήδη all-matches ακροατής" - -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" -msgstr "" - -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "Τρέχει ήδη" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "Ήδη γίνεται σάρωση για δίκτυα wifi" - -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "Παρουσιάστηκε σφάλμα κατά την ανάκτηση '%s':\n" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "Και άλλο PWMAudioOut είναι σε χρήση" - -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "Άλλη αποστολή είναι ήδη ενεργή" - -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "H παράταξη πρέπει να περιέχει halfwords (τύπου 'H')" - -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "Η τιμές της παράταξη πρέπει να είναι μονά bytes." - -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" - -#: shared-bindings/usb_audio/__init__.c -msgid "At least one of microphone and speaker must be enabled" -msgstr "" - -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "Προσπάθεια να δεσμευτούν %d blocks" - -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "Η μετατροπή ήχου δεν υποστηρίζεται" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Audio source error" -msgstr "" - -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "AuthMode.OPEN δεν μπορεί να χρησιμοποιηθεί με κωδικό" - -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "Αποτυχία αυθεντικοποίησης" - -#: main.c -msgid "Auto-reload is off.\n" -msgstr "Η αυτόματη επαναφόρτωση είναι απενεργοποιημένη.\n" - -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" -msgstr "" -"Η αυτόματη επαναφόρτωση είναι ενεργή. Αποθηκεύστε αρχεία μέσω USB για να " -"τρέξετε ή ανοίξτε το REPL για απενεργοποίηση.\n" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "Baudrate δεν υποστηρίζεται από την περιφεριακή συσκευή" - -#: ports/zephyr-cp/common-hal/zephyr_display/Display.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "Χαμηλότερο από το ελάχιστο frame rate" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "Ρολόι bit και ορισμού λέξης πρέπει να είναι διαδοχικά GPIO pins" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "Το μέγεθος του bitmap και τα bits ανα τιμή πρέπει να ταιριάζουν" - -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "Η συσκευή εκκίνησης πρέπει να επιλεχθεί πρώτα (διεπαφή #0)." - -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "Και RX και TX απαιτούνται για έλεγχο flow" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "H φωτεινότητα δεν μπορεί να προσαρμοστεί" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "Στοιχεία του buffer πρέπει να είναι το πολύ 4 bytes" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "Το buffer δεν είναι ένα bytearray." +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "Το μήκος buffer %d είναι πολύ μεγάλο. Πρέπει ν α είναι λιγότερο απο %d" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "Buffer πολύ μικρό κατα %d bytes" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "Buffer πολύ μικρός" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Bus pin %d είναι ήδη σε χρήση" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "CBC blocks πρέπει να είναι πολλαπλάσια του 16 bytes" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "Ο CIRCUITPY δίσκος δεν μπόρεσε να βρεθεί ή να δημιουργηθεί." +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC ή checksum ήταν άκυρο" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "Κλήση super().__init__() πρίν την πρόσβαση του τοπικού αντικειμένου." +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "Εκκίνηση κάμερας" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "Μόνο IO alarm ή RTC επιτρέπονται από βαθύ ύπνο." +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" msgstr "" -"Μόνο ένα alarm από low pin ενώ τα άλλα alarm θα είναι απο high σε βαθύ ύπνο." -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." -msgstr "Μπορεί να γίνει alarm μόνο σε δύο low pins σε βαθύ ύπνο." +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "Δεν μπορεί να οριστεί CCCD σε τοπικό Characteristic" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c -#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c -#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "Δεν μπορούν να αλλάξουν οι USB συσκευές τώρα" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" msgstr "" -"Δεν μπορεί να δημιουργηθεί νέο Adapter; χρησιμοποιείστε _bleio.adapter;" -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "Δεν μπορούν να διαγραφούν οι τιμές" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "Δεν γίνεται να διαβαστεί το pull όσο είναι σε output mode" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "Δεν μπορεί να διαβαστεί η θερμοκρασία" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" msgstr "" -"Δεν μπορούμε να έχουμε απαντήσεις scan για εκτεταμένες, συνδεόμενες " -"διαφημήσεις." -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "Δεν γίνεται pull σε pin μόνο για εισόδο." +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Cannot record to a file" -msgstr "Δεν μπορεί να γίνει καταγραφή σε αρχείο" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." -msgstr "Δεν μπορεί να οριστεί τιμή οταν η κατεύθυνση είναι input." +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "Δεν μπορεί να οριστεί RTS ή CTS σε RS485 mode" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "Δεν γίνεται υποκατηγορία ενός slice" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" -msgstr "Δεν γίνεται αφύπνηση σε pin edge, αλλά μόνο σε level" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." -msgstr "Δεν μπορεί να γίνει αφύπνηση σε pin edge. Μόνο level." +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "Δεν υποστηρίζονται εγγραφές στο CharacteristicBuffer" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "Ο πυρήνας της CircuitPython κατέρευσε. Οουπς!\n" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "Μονάδα ρολογιού ήδη σε χρήση" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" msgstr "" -"Έχει γίνει αποσύνδεση και αυτή η συνδεση δεν μπορεί να χρησιμοποιηθεί. " -"Δημιουργήστε μια νέα σύνδεση." -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "Δεν μπόρεσε να ρυθμιστεί η διεύθυνση" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "Δεν μπόρεσε να εκκινηθεί το interrupt, RX κατειλημμένο" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "Δεν μπόρεσε να δεσμευτεί decoder" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Channel Init Error" -msgstr "Σφάλμα εκκίνησης καναλιού DAC" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" +msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Device Init Error" -msgstr "Σφάλμα εκκίνησης συσκευής DAC" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC είναι ήδη σε χρήση" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "Το Data 0 pin πρέπει να είναι byte aligned" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "Δεν υποστηρίζονται δεδομένα με κατευθυνόμενη διαφήμιση" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "Τα δεδομένα είναι πολύ μεγάλα για πακέτο διαφημίσεων" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "Τα pins βαθύ ύπνου πρέπει να χρησιμοποιούν rising edge με pulldown" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Destination capacity is smaller than destination_length." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" msgstr "" -"Το μέγεθος προορισμού πρέπει να είναι μικρότερο από το destination_length." -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "Συσκευή σε χρήση" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#, fuzzy -msgid "Display must have a 16 bit colorspace." -msgstr "Η οθόνη πρέπει να έχει 16 bit χρωματική ευκρίνεια." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" -msgstr "Η περιστροφή της οθόνη πρέπει να γίνεται σε βήματα 90 μοιρών" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "" -#: main.c -msgid "Done" -msgstr "Ολοκληρώθηκε" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." -msgstr "Ο τρόπος οδήγησης δεν χρησιμοποιείται όταν η κατεύθυνση είναι είσοδος." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" msgstr "" -"Κατά την αντιμετώπιση της παραπάνω εξαίρεσης, ακόμα μία εξαίρεση συνέβη:" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB δουλεύει μόνο σε 16 bytes κάθε φορά" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "" -#: py/asmxtensa.c -msgid "ERROR: %q %q not word-aligned" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" msgstr "" -#: py/asmxtensa.c -msgid "ERROR: xtensa %q out of range" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" -msgstr "ESP-IDF δέσμευση μνήμης απέτυχε" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" +msgstr "" -#: extmod/modre.c -msgid "Error in regex" -msgstr "Σφάλμα σε regex" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "Σφάλμα στο safemode.py." +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" msgstr "" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" msgstr "" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" +#: main.c +msgid "Done" +msgstr "Ολοκληρώθηκε" + +#: main.c +msgid " output:\n" +msgstr " έξοδος:\n" + +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" +"Η αυτόματη επαναφόρτωση είναι ενεργή. Αποθηκεύστε αρχεία μέσω USB για να " +"τρέξετε ή ανοίξτε το REPL για απενεργοποίηση.\n" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" +#: main.c +msgid "Auto-reload is off.\n" +msgstr "Η αυτόματη επαναφόρτωση είναι απενεργοποιημένη.\n" + +#: main.c +msgid "Running in safe mode! Not running saved code.\n" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" +#: main.c +msgid " not found.\n" +msgstr " δεν βρέθηκε.\n" + +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" +"\n" +"Ο κώδικας σταμάτησε λόγω της αυτόματης επαναφόρτωσης. Η επαναφόρτωση θα " +"γίνει σύντομα.\n" -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" +"\n" +"Η εκτέλεση του κώδικα ολοκληρώθηκε.\n" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" +"Πατήστε οποιοδήποτε πλήκτρο για να μπείτε στο REPL. Πατήστε CTRL-D για " +"επαναφόρτωση.\n" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" -msgstr "" +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "Προσποίηση βαθύ ύπνου μεχρι γεγονότος, CTRL-C ή εγγραφή αρχείου.\n" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: main.c +msgid "UID:" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: main.c +msgid "soft reboot\n" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" +msgstr "%q εκκίνηση απέτυχε" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "%q εκτός εμβέλειας" + +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" msgstr "" #: ports/analog/common-hal/busio/SPI.c msgid "Failed to set SPI Clock Mode" msgstr "" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "Και RX και TX απαιτούνται για έλεγχο flow" -#: py/moderrno.c -msgid "File exists" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" msgstr "" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "Όλα τα UART περιφεριακά ειναι σε χρήση" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "Όλα τα κανάλια συμβάντων συγχρονισμού είναι σε χρήση" -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" msgstr "" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." msgstr "" -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "Όλοι οι χρονιστές βρίσκονται σε χρήση" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "Μονάδα ρολογιού ήδη σε χρήση" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" msgstr "" -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC είναι ήδη σε χρήση" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" msgstr "" -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "Όλα τα κανάλια συμβάντων είναι σε χρήση" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" msgstr "" -#: py/moderrno.c -msgid "Input/output error" -msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q πρέπει να είναι δύναμη του 2" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "Όλα τα RX FIFOs είναι σε χρήση" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "Ύπάρχει ήδη all-matches ακροατής" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "Δεν γίνεται να διαβαστεί το pull όσο είναι σε output mode" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" msgstr "" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c -#: supervisor/shared/settings.c -msgid "Internal error" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "Το Data 0 pin πρέπει να είναι byte aligned" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c #, c-format -msgid "Internal error #%d" -msgstr "" +msgid "Bus pin %d is already in use" +msgstr "Bus pin %d είναι ήδη σε χρήση" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c #: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c #: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "Άλλη αποστολή είναι ήδη ενεργή" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" -msgstr "" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" +msgstr "%q αποτυχία: %d" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/espressif/common-hal/mipidsi/Display.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c -#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" msgstr "" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "Εκκίνηση κάμερας" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "Buffer πολύ μικρός" + +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "Τρέχει ήδη" + +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q είναι %q" + +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." msgstr "" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." msgstr "" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" msgstr "" -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" -msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "Τα δεδομένα είναι πολύ μεγάλα για πακέτο διαφημίσεων" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "Ήδη διαφημίζουμε." + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "Δεν υποστηρίζονται δεδομένα με κατευθυνόμενη διαφήμιση" + +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "Δεν μπορεί να οριστεί CCCD σε τοπικό Characteristic" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c #, c-format -msgid "MMC/SDIO Clock Error %x" +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap must have 8 bits per pixel" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap size must match the other bitmaps" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "Δεν μπορεί να γίνει αφύπνηση σε pin edge. Μόνο level." -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" -msgstr "" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "Δεν γίνεται pull σε pin μόνο για εισόδο." -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." +msgstr "Μπορεί να γίνει alarm μόνο σε δύο low pins σε βαθύ ύπνο." -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" +"Μόνο ένα alarm από low pin ενώ τα άλλα alarm θα είναι απο high σε βαθύ ύπνο." -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "Μόνο IO alarm ή RTC επιτρέπονται από βαθύ ύπνο." + +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "%q πρέπει να είναι πίνακας τύπου 'H'" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" msgstr "" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +msgid "Peripheral in use" msgstr "" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c -msgid "No %q pin" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "No DAC on chip" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "No DMA channel found" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "Όλα τα I2C περιφεριακά ειναι σε χρήση" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "Όλα τα SPI περιφεριακά είναι σε χρήση" + +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "ESP-IDF δέσμευση μνήμης απέτυχε" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "Δεν μπορεί να οριστεί RTS ή CTS σε RS485 mode" + +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "Baudrate δεν υποστηρίζεται από την περιφεριακή συσκευή" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "Όλα τα περιφεριακά CAN είναι σε χρήση" + +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" msgstr "" -#: py/moderrno.c -msgid "No space left on device" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" msgstr "" -#: py/moderrno.c -msgid "No such device" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" msgstr "" -#: py/moderrno.c -msgid "No such file/directory" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC ή checksum ήταν άκυρο" + +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "Not playing" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/espidf/__init__.c #, c-format -msgid "Number of data_pins must be %d or %d, not %d" -msgstr "" +msgid "%s error 0x%x" +msgstr "%s σφάλμα 0x%x" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q είναι σε χρήση" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c #, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgid "Unknown error code %d" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "Εμβέλεια διευθύνσεων δεν επιτρέπεται" + +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" msgstr "" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: py/moderrno.c -msgid "Operation not permitted" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Operation timed out" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" #: ports/espressif/common-hal/socketpool/Socket.c @@ -1836,686 +1639,766 @@ msgstr "" msgid "Out of sockets" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" -msgstr "" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "%q πρέπει να είναι <= %u" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" msgstr "" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "Ήδη γίνεται σάρωση για δίκτυα wifi" -#: ports/espressif/common-hal/audiobusio/__init__.c -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -msgid "Peripheral in use" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: py/moderrno.c -msgid "Permission denied" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" msgstr "" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" msgstr "" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." msgstr "" -"Πατήστε οποιοδήποτε πλήκτρο για να μπείτε στο REPL. Πατήστε CTRL-D για " -"επαναφόρτωση.\n" - -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "Προσποίηση βαθύ ύπνου μεχρι γεγονότος, CTRL-C ή εγγραφή αρχείου.\n" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "Δεν γίνεται αφύπνηση σε pin edge, αλλά μόνο σε level" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "Συσκευή σε χρήση" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Pull not used when direction is output." +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" -msgstr "" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "Όλα τα κανάλια είναι σε χρήση" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "Δεν μπορεί να διαβαστεί η θερμοκρασία" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "Η μετατροπή ήχου δεν υποστηρίζεται" + +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q πρέπει να είναι τύπου %q ή %q, όχι %q" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "Στοιχεία του buffer πρέπει να είναι το πολύ 4 bytes" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" msgstr "" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "Ρολόι bit και ορισμού λέξης πρέπει να είναι διαδοχικά GPIO pins" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/raspberrypi/common-hal/busio/SPI.c +msgid "SPI peripheral in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" -msgstr "" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "Όλες οι μηχανές κατάστασης είναι σε χρήση" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" -msgstr "" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "Όλοι οι χρονιστές για αυτό το pin χρησιμοποιούνται ήδη" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "%q[%u] χρησιμοποιεί παραπάνω pin" -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" +msgstr "%q[%u] μετατοπίζει σε περισσότερα bits από αριθμό pin" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "%q[%u] μετατοπίζει από περισσότερα bits από αριθμό pin" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" msgstr "" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c -msgid "The sample's %q does not match" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" msgstr "" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c #, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Too many channels in sample." -msgstr "" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "Όλα τα κανάλια dma είναι σε χρήση" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q είναι μόνο για ανάγνωση για αυτήν την πλακέτα" -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "AP δεν μπόρεσε να εκκινηθεί" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" msgstr "" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" +msgstr "Τα pins βαθύ ύπνου πρέπει να χρησιμοποιούν rising edge με pulldown" + +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "Σφάλμα εκκίνησης συσκευής DAC" + +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "Σφάλμα εκκίνησης καναλιού DAC" + +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "Και άλλο PWMAudioOut είναι σε χρήση" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "Το μήκος buffer %d είναι πολύ μεγάλο. Πρέπει ν α είναι λιγότερο απο %d" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" #: ports/stm/common-hal/busio/UART.c -msgid "UART write" +msgid "Internal define error" msgstr "" -#: main.c -msgid "UID:" -msgstr "" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "Δεν μπόρεσε να εκκινηθεί το interrupt, RX κατειλημμένο" -#: shared-module/usb_hid/Device.c -msgid "USB busy" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Unable to allocate buffers for signed conversion" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" msgstr "" -#: py/parse.c -msgid "Unable to init parser" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" +msgstr ".show(x) αφαιρέθηκε. Χρησιμοποιήστε το .root_group = x" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "H φωτεινότητα δεν μπορεί να προσαρμοστεί" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q πρέπει να είναι %d-%d" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" msgstr "" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" -msgstr "" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "Χαμηλότερο από το ελάχιστο frame rate" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c #, c-format -msgid "Unknown gatt error: 0x%04x" -msgstr "" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c +#: py/argcheck.c #, c-format -msgid "Unknown security error: 0x%04x" +msgid "function missing %d required positional arguments" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c +#: py/argcheck.c #, c-format -msgid "Unknown system firmware error at %s:%d: %d" +msgid "function expected at most %d arguments, got %d" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" +#: py/argcheck.c +msgid "'%q' argument required" +msgstr "'%q' όρισμα απαιτείται" + +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c +msgid "argument num/types mismatch" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q πρέπει να είναι %d" + +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "%q πρέπει να είναι >= %d" + +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "%q πρέπει να είναι <= %d" + +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q πρέπει να είναι τύπου %q, όχι %q" + +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "%q μήκος πρέπει να είναι %d-%d" + +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "%q μήκος πρέπει να είναι >= %d" + +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "%q μήκος πρέπει να είναι <= %d" + +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "%q μήκος πρέπει να είναι %d" + +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q στο %q πρέπει να είναι τύπου %q, όχι %q" + +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q() παίρνει %d ορίσματα θέσεως αλλά %d δόθηκαν" + +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c -#: ports/zephyr-cp/common-hal/busio/I2C.c -#: ports/zephyr-cp/common-hal/busio/SPI.c -#: ports/zephyr-cp/common-hal/busio/UART.c -msgid "Use device tree to define %q devices" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: py/builtinhelp.c +msgid "object " msgstr "" +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " είναι τύπου %q\n" + #: py/builtinhelp.c #, c-format msgid "" @@ -2526,396 +2409,373 @@ msgid "" "To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" -msgstr "" - -#: main.c -msgid "Woken up by alarm.\n" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/compile.c +msgid "invalid arch" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." -msgstr "" +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "'break'/'continue' εκτός επανάληψης" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." -msgstr "" +#: py/compile.c +msgid "'return' outside function" +msgstr "'return' εκτός συνάρτησης" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" -msgstr "" +#: py/compile.c +msgid "*x must be assignment target" +msgstr "*x πρέπει να είναι στόχος ανάθεσης" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/compile.c +msgid "super() can't find self" msgstr "" #: py/compile.c -msgid "annotation must be an identifier" -msgstr "" +msgid "* arg after **" +msgstr "* όρισμα μετά **" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/compile.c +msgid "too many args" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" #: py/compile.c -msgid "argument name reused" +msgid "expecting just a value for set" msgstr "" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" -msgstr "" +#: py/compile.c +msgid "'yield' outside function" +msgstr "'yield' εκτός συνάρτησης" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" -msgstr "" +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "'yield from' εκτός ασύνχρονης συνάρτησης" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" -msgstr "" +#: py/compile.c +msgid "'await' outside function" +msgstr "'await' εκτός συνάρτησης" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/compile.c +msgid "argument name reused" msgstr "" #: py/compile.c -msgid "async for/with outside async function" +msgid "inline assembler must be a function" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/compile.c +msgid "unknown type" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" -msgstr "" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "'label' απαιτεί ένα όρισμα" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/compile.c +msgid "label redefined" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" -msgstr "" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "'align' απαιτεί τουλάχιστον ένα όρισμα" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" -msgstr "" +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "'data' απαιτεί τουλάχιστον 2 παραμέτρους" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" -msgstr "" +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "'data' απαιτεί ακέραιες παραμέτρους" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/emitbc.c +msgid "bytecode overflow" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: py/emitnative.c -msgid "binary op %q not implemented" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s' περιμένει το πολύ r%d" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "'%s' περιμένει έναν καταχωρητή" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "'%s' περιμένει έναν ειδικό καταχωρητή" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "'%s' περιμένει έναν FPU καταχωρητή" -#: py/emitbc.c -msgid "bytecode overflow" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' περιμένει {r0, r1, ...}" -#: py/objarray.c -msgid "bytes length not a multiple of item size" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' περιμένει έναν ακέραιο" -#: py/objstr.c -msgid "bytes value out of range" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' ακέραιος 0x%x δεν χωράει στην μάσκα 0x%x" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s' περιμένει μια διεύθυνση της μορφής [a, b]" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' περιμένει μια ετικέτα" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" #: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +msgid "branch not in range" msgstr "" #: py/emitinlinextensa.c msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" -msgstr "" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' ακέραιος %d δεν είναι μέσα στο επιτρεπτό εύρος %d..%d" -#: py/compile.c -msgid "can't assign to expression" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" +#: py/emitnative.c +msgid "conversion to object" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to complex" +#: py/emitnative.c +msgid "local '%q' used before type known" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to float" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: py/objint.c py/runtime.c -#, c-format -msgid "can't convert %s to int" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" -#: py/obj.c -msgid "can't convert to complex" +#: py/emitnative.c +msgid "can't store to '%q'" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/emitnative.c +msgid "'not' not implemented" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/emitnative.c +msgid "can't do unary op of '%q'" msgstr "" -#: py/objtype.c -msgid "can't create instance" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/emitnative.c +msgid "comparison of int and uint" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" #: py/emitnative.c @@ -2923,1732 +2783,1886 @@ msgid "can't do binary op between '%q' and '%q'" msgstr "" #: py/emitnative.c -msgid "can't do unary op of '%q'" +msgid "casting" msgstr "" #: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +msgid "return expected '%q' but got '%q'" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/emitnative.c +msgid "must raise an object" msgstr "" #: py/emitnative.c -msgid "can't load from '%q'" +msgid "native yield" msgstr "" -#: py/emitnative.c -msgid "can't load with '%q' index" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/modbuiltins.c +msgid "chr() arg not in range(0x110000)" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: py/emitnative.c -msgid "can't store '%q'" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "pow() με 3 παραμέτρους δεν υποστηρίζεται" + +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: py/emitnative.c -msgid "can't store to '%q'" +#: py/moderrno.c +msgid "Operation not permitted" msgstr "" -#: py/emitnative.c -msgid "can't store with '%q' index" +#: py/moderrno.c +msgid "No such file/directory" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/moderrno.c +msgid "Input/output error" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/moderrno.c +msgid "Permission denied" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/moderrno.c +msgid "File exists" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/moderrno.c +msgid "No such device" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/moderrno.c +msgid "No space left on device" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: py/compile.c -msgid "cannot emit native code for this architecture" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: py/emitnative.c -msgid "casting" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" msgstr "" +"Κατά την αντιμετώπιση της παραπάνω εξαίρεσης, ακόμα μία εξαίρεση συνέβη:" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " Αρχείο \"%q\", γραμμή %d" + +#: py/obj.c +msgid " File \"%q\"" +msgstr " Αρχείο \"%q\"" + +#: py/obj.c +msgid ", in %q\n" +msgstr ", στο %q\n" + +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/obj.c +msgid "indices must be integers" +msgstr "" + +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "%q δείκτες πρέπει να είναι ακέραιοι, όχι %s" + +#: py/obj.c +msgid "object has no len" +msgstr "" + +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" -msgstr "" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "'%s' αντικείμενο δεν υποστηρίζει διαγραφή πράγματος" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "'%s' αντικείμενο δεν είναι subscriptable" + +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "'%s' αντικείμενο δεν υποστηρίζει ορισμό πράγματος" + +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "data pin #%d in use" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "0.0 σε μία σύνθετη δύναμη" + +#: py/objdeque.c +msgid "full" msgstr "" -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "destination must be an array of type 'h'" +#: py/objdeque.c +msgid "empty" msgstr "" #: py/objdict.c msgid "dict update sequence has wrong length" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c -msgid "divide by zero" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objint.c +msgid "float too big" msgstr "" -#: py/objdeque.c -msgid "empty" +#: py/objint.c +#, c-format +msgid "value must fit in %d byte(s)" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: py/objstr.c -msgid "empty separator" -msgstr "" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: py/objstr.c -msgid "end of format while looking for conversion specifier" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: py/objstr.c -msgid "expected ':' after format specifier" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: py/obj.c -msgid "expected tuple/list" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" -msgstr "" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "%q βήμα δεν μπορεί να είναι μηδέν" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "Δεν γίνεται υποκατηγορία ενός slice" + +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objstr.c +msgid "empty separator" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objstr.c +msgid "rsplit(None,n)" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objstr.c +#, c-format +msgid "unknown conversion specifier %c" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objstr.c +msgid "%q index out of range" +msgstr "%q δείκτης εκτός εμβέλειας" + +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objstr.c +msgid "invalid format specifier" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: extmod/moddeflate.c -msgid "format" -msgstr "" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "Ευθυγράμμιση του '=' δεν επιτρέπεται εντός προσδιοριστή string format" #: py/objstr.c msgid "format needs a dict" msgstr "" #: py/objstr.c -msgid "format string didn't convert all arguments" +msgid "incomplete format key" msgstr "" #: py/objstr.c -msgid "format string needs more arguments" +msgid "incomplete format" msgstr "" -#: py/objdeque.c -msgid "full" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" msgstr "" -#: py/argcheck.c +#: py/objstr.c #, c-format -msgid "function expected at most %d arguments, got %d" +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: py/argcheck.c +#: py/objstrunicode.c #, c-format -msgid "function missing %d required positional arguments" +msgid "string indices must be integers, not %s" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" -msgstr "" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "Κλήση super().__init__() πρίν την πρόσβαση του τοπικού αντικειμένου." -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c +#: py/objtype.c #, c-format -msgid "function takes %d positional arguments but %d were given" +msgid "__init__() should return None, not '%s'" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy arch" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy file" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: py/objstr.c -msgid "incomplete format" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: py/objstr.c -msgid "incomplete format key" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/parse.c +msgid "not a constant" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/parse.c +msgid "Unable to init parser" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/persistentcode.c +msgid "incompatible .mpy arch" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" -msgstr "" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "'%q' αντικείμενο δεν υποστηρίζει '%q'" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/qstr.c +msgid "name too long" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "'%s' αντικείμενο δεν έχει γνώρισμα '%q'" + +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: py/emitinlinerv32.c -msgid "invalid RV32 instruction '%q'" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "'%q' αντικείμενο δεν είναι επαναληπτικό" + +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: py/compile.c -msgid "invalid arch" -msgstr "" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "'%q' αντικείμενο δεν είναι επαναλήπτης" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -#, c-format -msgid "invalid destination buffer, must be an array of type: %c" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: shared-bindings/bitmaptools/__init__.c +#: py/runtime.c #, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: py/vm.c +msgid "local variable referenced before assignment" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: py/vm.c +msgid "opcode" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" +"Δεν μπορεί να δημιουργηθεί νέο Adapter; χρησιμοποιείστε _bleio.adapter;" -#: py/parsenum.c -msgid "invalid syntax for integer" -msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "Δεν μπόρεσε να ρυθμιστεί η διεύθυνση" -#: py/parsenum.c +#: shared-bindings/_bleio/Adapter.c #, c-format -msgid "invalid syntax for integer with base %d" +msgid "interval must be in range %s-%s" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" +"Δεν μπορούμε να έχουμε απαντήσεις scan για εκτεταμένες, συνδεόμενες " +"διαφημήσεις." -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" -msgstr "" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "Δεν υποστηρίζονται εγγραφές στο CharacteristicBuffer" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." msgstr "" +"Έχει γίνει αποσύνδεση και αυτή η συνδεση δεν μπορεί να χρησιμοποιηθεί. " +"Δημιουργήστε μια νέα σύνδεση." -#: py/compile.c -msgid "label redefined" -msgstr "" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "Buffer πολύ μικρό κατα %d bytes" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" -#: py/vm.c -msgid "local variable referenced before assignment" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" #: shared-bindings/_stage/Layer.c msgid "map buffer too small" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c #, c-format -msgid "max_length must be 0-%d when fixed_length is %s" -msgstr "" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "" - -#: py/runtime.c -msgid "maximum recursion depth exceeded" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" -msgstr "" - -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB δουλεύει μόνο σε 16 bytes κάθε φορά" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "CBC blocks πρέπει να είναι πολλαπλάσια του 16 bytes" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "Η τιμές της παράταξη πρέπει να είναι μονά bytes." -#: py/runtime.c -msgid "module '%q' has no attribute '%q'" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: py/builtinimport.c -msgid "module not found" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" msgstr "" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q πρέπει να είναι bytearray ή array τύπου 'H' ή 'B'" -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" msgstr "" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "Δεν μπορεί να γίνει καταγραφή σε αρχείο" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." msgstr "" +"Το μέγεθος προορισμού πρέπει να είναι μικρότερο από το destination_length." -#: py/qstr.c -msgid "name too long" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/emitnative.c -msgid "native yield" -msgstr "" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q πρέπει να είναι bytearray ή array τύπου 'h', 'H', 'b', ή 'B'" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "" +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" +msgstr "%q και %q πρεπει να είναι διαφορετικά" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/builtinimport.c -msgid "no module named '%q'" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "Το μέγεθος του bitmap και τα bits ανα τιμή πρέπει να ταιριάζουν" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/obj.c +#: shared-bindings/bitmaptools/__init__.c #, c-format -msgid "object '%s' isn't a tuple or list" +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "object does not support DigitalInOut protocol" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "Η περιστροφή της οθόνη πρέπει να γίνεται σε βήματα 90 μοιρών" -#: py/runtime.c -msgid "object not iterable" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q πρέπει να είναι 1 όταν %q είναι True" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#, fuzzy +msgid "Display must have a 16 bit colorspace." +msgstr "Η οθόνη πρέπει να έχει 16 bit χρωματική ευκρίνεια." -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "Δεν μπορεί να οριστεί τιμή οταν η κατεύθυνση είναι input." + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "Ο τρόπος οδήγησης δεν χρησιμοποιείται όταν η κατεύθυνση είναι είσοδος." + +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "Δεν μπορούν να διαγραφούν οι τιμές" + +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: py/vm.c -msgid "opcode" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" -msgstr "" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "Το buffer δεν είναι ένα bytearray." -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" msgstr "" -#: py/modbuiltins.c +#: shared-bindings/ipaddress/IPv4Address.c #, c-format -msgid "ord() expected a character, but string of length %d found" -msgstr "" +msgid "Address must be %d bytes long" +msgstr "Η διεύθυνση πρέπει να είναι %d bytes μεγάλη" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q περιέχει διπλότυπα pins" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q και %q περιέχουν διπλότυπα pins" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" -msgstr "" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "H παράταξη πρέπει να περιέχει halfwords (τύπου 'H')" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: extmod/modre.c -msgid "regex too complex" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" msgstr "" -#: py/obj.c +#: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "requested length %d but object has length %d" +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +"%d pin διεύθυνσης, %d rgb ping και %d πλακίδια αναδεικνύουν ύψος %d, όχι %d" -#: py/objint_longlong.c py/parsenum.c -msgid "result overflows long long storage" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." +msgstr "" + +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "Δεν μπορούν να αλλάξουν οι USB συσκευές τώρα" + +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: py/objstr.c -msgid "rsplit(None,n)" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" -msgstr "" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q, και %q πρέπει να είναι όλα του ιδίου μήκους" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" -#: py/nativeglue.c -msgid "set unsupported" -msgstr "" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "%q πρέπει να είναι υποκλάση του %q" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" -msgstr "" +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" +msgstr "%q εκτός ορίων" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "AuthMode.OPEN δεν μπορεί να χρησιμοποιηθεί με κωδικό" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" -msgstr "" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "Αποτυχία αυθεντικοποίησης" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "Δεν μπόρεσε να δεσμευτεί decoder" + +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: py/objstrunicode.c -#, c-format -msgid "string indices must be integers, not %s" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: py/compile.c -msgid "too many args" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: py/runtime.c +#: shared-module/memorymonitor/AllocationAlarm.c #, c-format -msgid "too many values to unpack (expected %d)" +msgid "Attempt to allocate %d blocks" +msgstr "Προσπάθεια να δεσμευτούν %d blocks" + +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c +#: shared-module/rgbmatrix/RGBMatrix.c #, c-format -msgid "twai_start returned esp-idf error #%d" +msgid "Internal error #%d" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: py/parse.c -msgid "unexpected indent" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/compile.c -msgid "unknown type" -msgstr "" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' και 'O' δεν είναι υποστηριζόμενοι τύποι format" -#: py/compile.c -msgid "unknown type '%q'" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "%q πρέπει να είναι λίστα τύπου 'h'" + +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" +#: shared-module/usb/core/Device.c +msgid "No configuration set" msgstr "" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" +#: shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" +"\n" +"Είσαστε τε ασφαλή λειτουργία διότι:\n" -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." msgstr "" -#: extmod/moddeflate.c -msgid "wbits" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "Ο CIRCUITPY δίσκος δεν μπόρεσε να βρεθεί ή να δημιουργηθεί." + +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "Σφάλμα στο safemode.py." + +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "Η συσκευή εκκίνησης πρέπει να επιλεχθεί πρώτα (διεπαφή #0)." + +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "Ο πυρήνας της CircuitPython κατέρευσε. Οουπς!\n" + +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." msgstr "" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" +"\n" +"Παρακαλώ δημιουργήστε ένα πρόβλημα με το πρόγραμμά σας στο github.com/" +"adafruit/circuitpython/issues." -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" +"\n" +"Πατήστε reset για να βγείτε από την ασφαλή λειτουργία.\n" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "Παρουσιάστηκε σφάλμα κατά την ανάκτηση '%s':\n" + +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" msgstr "" #~ msgid "%q renamed %q" diff --git a/locale/hi.po b/locale/hi.po index 21b28028a29..e8d82a20db4 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -18,4609 +18,4623 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n > 1;\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" -msgstr "" - -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -#: py/obj.c -msgid " File \"%q\"" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" +#: extmod/moddeflate.c +msgid "format" msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" +#: extmod/moddeflate.c +msgid "wbits" msgstr "" -#: main.c -msgid " not found.\n" +#: extmod/modhashlib.c +msgid "hash is final" msgstr "" -#: main.c -msgid " output:\n" +#: extmod/modheapq.c +msgid "heap must be a list" msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modjson.c +msgid "syntax error in JSON" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c +msgid "bits must be 32 or less" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "%d is not a multiple of %d" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" +#: extmod/modre.c +msgid "splitting with sub-captures" msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modre.c +msgid "Error in regex" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" +#: extmod/modzlib.c +msgid "compression header" msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" msgstr "" -#: py/objstr.c -msgid "%q index out of range" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: ports/stm/common-hal/audioio/AudioOut.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c -msgid "%q init failed" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" msgstr "" -#: py/argcheck.c -msgid "%q must be %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c -#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" msgstr "" -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 16, 24, or 32" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" msgstr "" -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 8 or 16" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q must be 8, 16, 24, or 32" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" msgstr "" -#: py/argcheck.c -msgid "%q must be >= %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" msgstr "" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" msgstr "" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -msgid "%q out of range" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" msgstr "" -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" msgstr "" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" msgstr "" -#: py/runtime.c -msgid "'%q' object isn't iterable" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" msgstr "" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" msgstr "" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" msgstr "" -#: py/compile.c -msgid "'await' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" msgstr "" -#: py/compile.c -msgid "'break'/'continue' outside loop" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" msgstr "" -#: py/compile.c -msgid "'data' requires integer arguments" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" msgstr "" -#: py/compile.c -msgid "'label' requires 1 argument" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" msgstr "" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "'return' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" msgstr "" -#: py/compile.c -msgid "'yield from' inside async function" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" msgstr "" -#: py/compile.c -msgid "'yield' outside function" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" msgstr "" -#: py/compile.c -msgid "* arg after **" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" msgstr "" -#: py/compile.c -msgid "*x must be assignment target" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: py/obj.c -msgid ", in %q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" msgstr "" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" msgstr "" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" msgstr "" -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" msgstr "" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" msgstr "" -#: shared-bindings/usb_audio/__init__.c -msgid "At least one of microphone and speaker must be enabled" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" msgstr "" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Audio source error" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" msgstr "" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" msgstr "" -#: main.c -msgid "Auto-reload is off.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" msgstr "" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" msgstr "" -#: ports/zephyr-cp/common-hal/zephyr_display/Display.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "Bit clock and word select must be sequential GPIO pins" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: main.c +msgid "Done" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" +#: main.c +msgid " output:\n" msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c -#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c -#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" +#: main.c +msgid "Auto-reload is off.\n" msgstr "" -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" +#: main.c +msgid " not found.\n" msgstr "" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Cannot record to a file" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" msgstr "" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." +#: main.c +msgid "UID:" +msgstr "UID:" + +#: main.c +msgid "soft reboot\n" msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" msgstr "" -#: py/objslice.c -msgid "Cannot subclass slice" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" msgstr "" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Channel Init Error" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Device Init Error" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." msgstr "" +#: ports/atmel-samd/common-hal/_pew/PewPew.c #: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Destination capacity is smaller than destination_length." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" msgstr "" -#: main.c -msgid "Done" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" msgstr "" -#: py/asmxtensa.c -msgid "ERROR: %q %q not word-aligned" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" msgstr "" -#: py/asmxtensa.c -msgid "ERROR: xtensa %q out of range" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "" + +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c #: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" msgstr "" -#: extmod/modre.c -msgid "Error in regex" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" msgstr "" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" msgstr "" -#: ports/nordic/sd_mutex.c +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c #, c-format -msgid "Failed to acquire mutex, err 0x%04x" +msgid "Bus pin %d is already in use" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" msgstr "" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" msgstr "" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" msgstr "" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." msgstr "" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." msgstr "" -#: py/moderrno.c -msgid "File exists" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." msgstr "" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c #: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" +msgid "Update failed" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" msgstr "" -#: shared-bindings/bitops/__init__.c +#: ports/espressif/common-hal/_bleio/__init__.c #, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" msgstr "" -#: py/moderrno.c -msgid "Input/output error" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" +msgid "Insufficient encryption" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" +msgstr "" + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." msgstr "" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c -#: supervisor/shared/settings.c -msgid "Internal error" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +msgid "Peripheral in use" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/espressif/common-hal/mipidsi/Display.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c -#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" msgstr "" -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" msgstr "" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" msgstr "" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" msgstr "" -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" msgstr "" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" msgstr "" -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +msgid "Generic Failure" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap must have 8 bits per pixel" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap size must match the other bitmaps" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" msgstr "" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." msgstr "" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" msgstr "" #: ports/espressif/common-hal/nvm/ByteArray.c msgid "NVS Error" msgstr "" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c -msgid "No %q pin" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "No DAC on chip" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "No DMA channel found" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" msgstr "" -#: py/moderrno.c -msgid "No space left on device" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" msgstr "" -#: py/moderrno.c -msgid "No such device" +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" msgstr "" -#: py/moderrno.c -msgid "No such file/directory" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "Not playing" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#, c-format -msgid "Number of data_pins must be %d or %d, not %d" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#: ports/nordic/common-hal/_bleio/__init__.c #, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgid "Unknown security error: 0x%04x" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" msgstr "" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" msgstr "" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" msgstr "" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" msgstr "" -#: py/moderrno.c -msgid "Operation not permitted" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Operation timed out" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" msgstr "" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" msgstr "" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: ports/espressif/common-hal/audiobusio/__init__.c -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -msgid "Peripheral in use" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: py/moderrno.c -msgid "Permission denied" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" +#: ports/raspberrypi/common-hal/busio/SPI.c +msgid "SPI peripheral in use" msgstr "" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" #: ports/raspberrypi/common-hal/countio/Counter.c msgid "Pin must be on PWM Channel B" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" msgstr "" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" msgstr "" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" msgstr "" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" +msgstr "" + +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "" + +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" msgstr "" #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" +msgid "Pin count too large" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Pull not used when direction is output." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" +msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" msgstr "" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" msgstr "" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" msgstr "" -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c -msgid "The sample's %q does not match" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" msgstr "" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Too many channels in sample." +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many displays" +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" +#: py/argcheck.c +msgid "'%q' argument required" msgstr "" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c +msgid "argument num/types mismatch" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" +#: py/argcheck.c +msgid "%q must be %d" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" +#: py/argcheck.c +msgid "%q must be >= %d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" +#: py/argcheck.c +msgid "%q length must be %d-%d" msgstr "" -#: main.c -msgid "UID:" -msgstr "UID:" - -#: shared-module/usb_hid/Device.c -msgid "USB busy" +#: py/argcheck.c +msgid "%q length must be >= %d" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: py/argcheck.c +msgid "%q length must be <= %d" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Unable to allocate buffers for signed conversion" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c +#: py/bc.c #, c-format -msgid "Unable to find I2C Display at %x" -msgstr "" - -#: py/parse.c -msgid "Unable to init parser" +msgid "function missing required positional argument #%d" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" msgstr "" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: py/builtinhelp.c +msgid "object " msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: py/builtinhelp.c +msgid " is of type %q\n" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c +#: py/builtinhelp.c #, c-format -msgid "Unknown BLE error at %s:%d: %d" +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: py/compile.c +msgid "invalid arch" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" +#: py/compile.c +msgid "'break'/'continue' outside loop" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: py/compile.c +msgid "'return' outside function" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c -#: ports/zephyr-cp/common-hal/busio/I2C.c -#: ports/zephyr-cp/common-hal/busio/SPI.c -#: ports/zephyr-cp/common-hal/busio/UART.c -msgid "Use device tree to define %q devices" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" +#: py/compile.c +msgid "*x must be assignment target" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: py/compile.c +msgid "* arg after **" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: py/compile.c +msgid "too many args" msgstr "" -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " +#: py/compile.c +msgid "positional arg after **" +msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." +#: py/compile.c +msgid "'yield' outside function" msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/compile.c +msgid "'yield from' inside async function" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/compile.c +msgid "'await' outside function" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/compile.c +msgid "argument name reused" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/compile.c +msgid "unknown type" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/compile.c +msgid "'label' requires 1 argument" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: py/compile.c +msgid "label redefined" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/compile.c +msgid "'align' requires 1 argument" msgstr "" -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" +#: py/compile.c +msgid "'data' requires at least 2 arguments" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/compile.c +msgid "'data' requires integer arguments" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" +#: py/emitbc.c +msgid "bytecode overflow" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: py/compile.c -msgid "argument name reused" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" msgstr "" -#: py/compile.c -msgid "async for/with outside async function" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/emitnative.c +msgid "conversion to object" msgstr "" #: py/emitnative.c -msgid "binary op %q not implemented" +msgid "local '%q' used before type known" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/emitnative.c +msgid "can't store to '%q'" msgstr "" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/emitnative.c +msgid "'not' not implemented" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/emitnative.c +msgid "can't do unary op of '%q'" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/emitnative.c +msgid "comparison of int and uint" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: py/emitbc.c -msgid "bytecode overflow" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/emitnative.c +msgid "casting" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/emitnative.c +msgid "must raise an object" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +#: py/modbuiltins.c +msgid "chr() arg not in range(0x110000)" msgstr "" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: py/compile.c -msgid "can't assign to expression" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" +#: py/moderrno.c +msgid "Operation not permitted" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to complex" +#: py/moderrno.c +msgid "No such file/directory" msgstr "" -#: py/obj.c -#, c-format -msgid "can't convert %s to float" +#: py/moderrno.c +msgid "Input/output error" msgstr "" -#: py/objint.c py/runtime.c -#, c-format -msgid "can't convert %s to int" +#: py/moderrno.c +msgid "Permission denied" msgstr "" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" +#: py/moderrno.c +msgid "File exists" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" +#: py/moderrno.c +msgid "No such device" msgstr "" -#: py/obj.c -msgid "can't convert to complex" +#: py/moderrno.c +msgid "No space left on device" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: py/objtype.c -msgid "can't create instance" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: py/compile.c -msgid "can't delete expression" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: py/emitnative.c -msgid "can't do unary op of '%q'" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" msgstr "" -#: py/emitnative.c -msgid "can't load from '%q'" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: py/emitnative.c -msgid "can't load with '%q' index" +#: py/obj.c +msgid " File \"%q\", line %d" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/obj.c +msgid " File \"%q\"" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/obj.c +msgid ", in %q\n" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" msgstr "" -#: py/emitnative.c -msgid "can't store '%q'" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: py/emitnative.c -msgid "can't store to '%q'" +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" msgstr "" -#: py/emitnative.c -msgid "can't store with '%q' index" +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/obj.c +msgid "%q indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/obj.c +msgid "object has no len" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" msgstr "" -#: py/compile.c -msgid "cannot emit native code for this architecture" +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" msgstr "" -#: py/emitnative.c -msgid "casting" +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" #: py/objcomplex.c msgid "complex divide by zero" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/objcomplex.c +msgid "0.0 to a complex power" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/objdeque.c +msgid "full" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/objdeque.c +msgid "empty" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/objdict.c +msgid "dict update sequence has wrong length" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/objint.c +msgid "float too big" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/objint.c #, c-format -msgid "data pin #%d in use" +msgid "value must fit in %d byte(s)" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "destination must be an array of type 'h'" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" msgstr "" -#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c -msgid "divide by zero" +#: py/objslice.c +msgid "Cannot subclass slice" msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" +msgstr "" + +#: py/objstr.c +msgid "empty separator" +msgstr "" + +#: py/objstr.c +msgid "rsplit(None,n)" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: py/objdeque.c -msgid "empty" +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" #: py/objstr.c -msgid "empty separator" +#, c-format +msgid "unknown conversion specifier %c" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" #: py/objstr.c -msgid "end of format while looking for conversion specifier" +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objstr.c +msgid "%q index out of range" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" #: py/objstr.c -msgid "expected ':' after format specifier" +msgid "invalid format specifier" msgstr "" -#: py/obj.c -msgid "expected tuple/list" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objstr.c +msgid "incomplete format" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: py/objstr.c -msgid "format needs a dict" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: py/objstr.c -msgid "format string didn't convert all arguments" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: py/objstr.c -msgid "format string needs more arguments" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: py/objdeque.c -msgid "full" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/parse.c +msgid "not a constant" msgstr "" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" +#: py/parse.c +msgid "Unable to init parser" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" #: py/persistentcode.c -msgid "incompatible .mpy arch" +msgid "native code in .mpy unsupported" msgstr "" #: py/persistentcode.c -msgid "incompatible .mpy file" +msgid "incompatible .mpy arch" msgstr "" -#: py/objstr.c -msgid "incomplete format" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" msgstr "" -#: py/objstr.c -msgid "incomplete format key" +#: py/qstr.c +msgid "name too long" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/runtime.c +msgid "'%q' object isn't iterable" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/runtime.c +msgid "'%q' object isn't an iterator" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/vm.c +msgid "local variable referenced before assignment" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/vm.c +msgid "opcode" msgstr "" #: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" -msgstr "" - -#: py/emitinlinerv32.c -msgid "invalid RV32 instruction '%q'" +msgid "Cannot create a new Adapter; use _bleio.adapter;" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" msgstr "" -#: shared-bindings/bitmaptools/__init__.c +#: shared-bindings/_bleio/Adapter.c #, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgid "interval must be in range %s-%s" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -#, c-format -msgid "invalid destination buffer, must be an array of type: %c" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" msgstr "" -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" msgstr "" -#: py/compile.c -msgid "label redefined" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" msgstr "" -#: py/vm.c -msgid "local variable referenced before assignment" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" msgstr "" -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: py/runtime.c -msgid "module '%q' has no attribute '%q'" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: py/builtinimport.c -msgid "module not found" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" msgstr "" -#: py/compile.c -msgid "multiple *x in assignment" +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: py/objtype.c -msgid "multiple inheritance not supported" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" msgstr "" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: py/builtinimport.c -msgid "no module named '%q'" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" #: shared-bindings/digitalio/DigitalInOutProtocol.c msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/obj.c -msgid "object doesn't support item assignment" -msgstr "" - -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" #: shared-bindings/dualbank/__init__.c msgid "offset must be >= 0" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "" - -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" -msgstr "" - -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: py/vm.c -msgid "opcode" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: py/modstruct.c +#: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "" - -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" -msgstr "" - -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" #: shared-bindings/socketpool/Socket.c msgid "port must be >= 0" msgstr "" -#: py/compile.c -msgid "positional arg after **" -msgstr "" - -#: py/compile.c -msgid "positional arg after keyword arg" -msgstr "" - -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: extmod/modre.c -msgid "regex too complex" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: py/objint_longlong.c py/parsenum.c -msgid "result overflows long long storage" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" msgstr "" -#: py/objstr.c -msgid "rsplit(None,n)" +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" msgstr "" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" msgstr "" -#: main.c -msgid "soft reboot\n" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: py/objstrunicode.c +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c #, c-format -msgid "string indices must be integers, not %s" +msgid "Unable to find I2C Display at %x" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" msgstr "" -#: py/compile.c -msgid "too many args" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" +msgstr "" + +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" msgstr "" -#: py/runtime.c +#: shared-module/rgbmatrix/RGBMatrix.c #, c-format -msgid "too many values to unpack (expected %d)" +msgid "Internal error #%d" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" msgstr "" -#: py/parse.c -msgid "unexpected indent" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/compile.c -msgid "unknown type" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" msgstr "" -#: py/compile.c -msgid "unknown type '%q'" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" msgstr "" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: shared-module/usb/core/Device.c +msgid "No configuration set" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" msgstr "" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" msgstr "" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: extmod/moddeflate.c -msgid "wbits" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." msgstr "" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" +msgstr "" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 4789c8a566b..0d363de683f 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -17,1351 +17,772 @@ msgstr "" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -"\n" -"코드 실행 완료.\n" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -"\n" -"자동 업로드에 의해 코드가 중지되었습니다. 곧 다시 로드됩니다.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -"\n" -"github.com/adafruit/circuitpython/issues 에\n" -"프로그램 오류를 제출하세요." -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -"\n" -"재설정을 눌러 안전 모드를 종료합니다.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -"\n" -"안전 모드에 있는 이유는 다음과 같습니다:\n" -#: py/obj.c -msgid " File \"%q\"" -msgstr " 파일 \"%q\"" +#: extmod/moddeflate.c +msgid "format" +msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " 파일 \"%q\", 라인 %d" +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " %q 유형입니다\n" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "" -#: main.c -msgid " not found.\n" -msgstr " 찾을 수 없습니다.\n" +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "" -#: main.c -msgid " output:\n" -msgstr " 산출:\n" +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" +#: extmod/modrandom.c +msgid "bits must be 32 or less" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -"%d 주소 핀들, %d rgb 핀들과 %d 타일 들은 높이가 %d임을 나타낸다, %d가 아니라" -#: py/emitinlinextensa.c -#, c-format -msgid "%d is not a multiple of %d" +#: extmod/modre.c +msgid "splitting with sub-captures" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q 및 %q에 중복된 핀이 포함" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q와 %q는 달라야 합니다" +#: extmod/modre.c +msgid "Error in regex" +msgstr "Regex에 오류가 있습니다." -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" +#: extmod/modtime.c +msgid "ticks interval overflow" msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q에 중복된 핀이 포함" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" -msgstr "%q 실패: %d" +#: extmod/modzlib.c +msgid "compression header" +msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q의 %q는 %q가 아니라 %q 유형이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q 사용 중입니다" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "" -#: py/objstr.c -msgid "%q index out of range" -msgstr "%q 인덱스 범위를 벗어났습니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: ports/stm/common-hal/audioio/AudioOut.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c -msgid "%q init failed" -msgstr "%q 초기화 실패" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q는 %q입니다" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q는 이 보드에 대한 읽기 전용입니다" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "%q 길이는 %d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "%q 길이는 %d - %d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "%q 길이는 <= %d>여야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "%q 길이는 >= %d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q는 %d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c -#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q는 %d-%d이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q가 참일 때 %q는 1이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 16, 24, or 32" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" msgstr "" -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 8 or 16" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q must be 8, 16, 24, or 32" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " msgstr "" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -#, fuzzy -msgid "%q must be <= %d" -msgstr "%q 는 <= %d 여야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -#, fuzzy -msgid "%q must be <= %u" -msgstr "%q 는 <= %u 여야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "" -#: py/argcheck.c -#, fuzzy -msgid "%q must be >= %d" -msgstr "%q 는 >= %d 여야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q는 'H' 또는 'B' 타입의 바이트 배열 또는 배열이어야 합니다" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q는 h, H, b 또는 B 유형의 바이트 배열 또는 배열이어야 합니다" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "%q는 %q의 하위 클래스여야 합니다" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -#, fuzzy -msgid "%q must be array of type 'H'" -msgstr "%q는 'H' 유형의 배열이어야 합니다" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "" -#: shared-module/synthio/__init__.c -#, fuzzy -msgid "%q must be array of type 'h'" -msgstr "%q는 'h' 유형의 배열이어야 합니다" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" msgstr "" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q는 %q가 아닌 %q 또는 %q 유형이어야 합니다" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q는 %q가 아니라 %q 유형이어야 합니다" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q는 2의 거듭제곱이어야 합니다" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" msgstr "" -#: shared-bindings/wifi/Monitor.c -#, fuzzy -msgid "%q out of bounds" -msgstr "%q가 경계를 벗어남" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -#, fuzzy -msgid "%q out of range" -msgstr "%q가 범위를 벗어남" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -#, fuzzy -msgid "%q step cannot be zero" -msgstr "%q 단계는 0일 수 없습니다" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" msgstr "" -#: py/bc.c py/objnamedtuple.c -#, fuzzy -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q()는 %d 위치 인수를 사용하지만 %d이(가) 주어졌습니다" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" msgstr "" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q 및 %q의 길이는 모두 같아야 합니다" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "%q[%u] shifts in more bits than pin count" -msgstr "%q[%u]가 핀 수보다 더 많은 비트로 이동했습니다" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "%q[%u] shifts out more bits than pin count" -msgstr "%q[%u]이(가) 핀 수보다 많은 비트를 전송합니다" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "%q[%u]에서 추가 핀 사용" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "%q[%u]이(가) 카운트 외부의 입력을 대기합니다" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, fuzzy, c-format -msgid "%s error 0x%x" -msgstr "%s 오류 0x%x" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "'%q' 인수가 필요합니다" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "" -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" -msgstr "'%q' 개체가 '%q'를 지원하지 않습니다" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "'%q' 개체가 iterator가 아닙니다" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "FFT는 ndarrays에 대해서만 정의됩니다" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" -msgstr "" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "FFT는 선형 배열에 대해서만 구현됩니다" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "'%q' 개체를 사용할 수 없습니다" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' 에는 라벨이 필요합니다" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' 에는 레지스터가 필요합니다" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' 에는 특별한 레지스터가 필요합니다" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' 에는 FPU레지스터가 필요합니다" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" -#: py/emitinlinethumb.c -#, fuzzy, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s' 에는 [a, b] 형식의 주소가 필요합니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' 는 정수 여야합니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "" -#: py/emitinlinethumb.c -#, fuzzy, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s'는 최대 r%d를 필요로 합니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' {r0, r1, ...}은 을 기대합니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "" -#: py/emitinlinextensa.c -#, fuzzy, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' 정수 %d가 %d..%d 범위 내에 있지 않습니다" - -#: py/emitinlinethumb.c -#, fuzzy, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' 정수 0x%x 이 마스크 0x%x에 맞지 않습니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" -#: py/obj.c -#, fuzzy, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "'%s' 개체가 항목 할당을 지원하지 않습니다" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "" -#: py/obj.c -#, fuzzy, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "'%s' 개체가 항목 삭제를 지원하지 않습니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" -#: py/runtime.c -#, fuzzy -msgid "'%s' object has no attribute '%q'" -msgstr "'%s' 개체에 '%q' 특성이 없습니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "'%s' 개체를 subscriptable 할 수 없습니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" -#: py/objstr.c -#, fuzzy -msgid "'=' alignment not allowed in string format specifier" -msgstr "'=' 문자열 형식 지정자에서 정렬이 허용되지 않습니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' 및 'O'는 지원되지 않는 형식 유형입니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "" -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "'align' 에는 1 개의 독립변수가 필요합니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "" -#: py/compile.c -msgid "'await' outside function" -msgstr "'await' 는 펑크션 외부에 있습니다" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "" -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "'break'/'continue' 외부 루프" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "'data' 에는 >=2 개의 독립변수가 필요합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "" -#: py/compile.c -#, fuzzy -msgid "'data' requires integer arguments" -msgstr "'data' 에는 정수 인수가 필요합니다" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "" -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "'label' 에는 1 개의 독립변수가 필요합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "" -#: py/emitnative.c -msgid "'not' not implemented" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" msgstr "" -#: py/compile.c -msgid "'return' outside function" -msgstr "'return' 는 함수 외부에 존재합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" -#: py/compile.c -#, fuzzy -msgid "'yield from' inside async function" -msgstr "비동기 함수 내 'yield from'" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" -#: py/compile.c -msgid "'yield' outside function" -msgstr "'yield' 는 함수 외부에 존재합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "" -#: py/compile.c -#, fuzzy -msgid "* arg after **" -msgstr "* 인수 뒤에 **" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" +msgstr "" -#: py/compile.c -#, fuzzy -msgid "*x must be assignment target" -msgstr "*x는 할당 대상이어야 합니다" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "" -#: py/obj.c -msgid ", in %q\n" -msgstr ", 에서 %q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#, fuzzy -msgid ".show(x) removed. Use .root_group = x" -msgstr ".show(x)가 제거되었습니다. .root_group = x를 사용합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "" -#: py/objcomplex.c -msgid "0.0 to a complex power" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" msgstr "" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "pow() 는 3개의 인수를 지원하지 않습니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "AP를 시작할 수 없습니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "주소 길이는 %d 바이트 여야합니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "주소 범위가 허용되지 않습니다" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, fuzzy -msgid "All CAN peripherals are in use" -msgstr "모든 CAN 주변 기기가 사용 중입니다" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "사용 중인 모든 I2C주변 기기" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -#, fuzzy -msgid "All RX FIFOs in use" -msgstr "모든 RX FIFOs가 사용 중입니다" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "사용중인 모든 SPI주변 기기" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" +msgstr "" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "사용중인 모든 UART주변 기기" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "모든 채널이 사용중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "모든 dma채널이 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#, fuzzy -msgid "All event channels in use" -msgstr "모든 이벤트 채널이 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" +msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#, fuzzy -msgid "All state machines in use" -msgstr "모든 상태 머신이 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "" -#: ports/atmel-samd/audio_dma.c -#, fuzzy -msgid "All sync event channels in use" -msgstr "모든 동기화 이벤트 채널이 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "핀의 모든 타이머가 사용 중입니다" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "모든 타이머가 사용 중입니다" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, fuzzy -msgid "Already advertising." -msgstr "이미 광고 중입니다." +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#, fuzzy -msgid "Already have all-matches listener" -msgstr "이미 모든 일치 리스너가 있습니다" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" msgstr "" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "이미 실행 중입니다" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -#, fuzzy -msgid "Already scanning for wifi networks" -msgstr "이미 wifi 네트워크를 찾고 있습니다" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "" -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "%s'을(를) 검색하는 동안 오류가 발생했습니다:\n" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" +msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, fuzzy -msgid "Another PWMAudioOut is already active" -msgstr "다른 PWMaudioOut이 이미 활성화되어 있습니다" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "다른 전송이 이미 활성화되었습니다" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "배열은 하프워드(유형 'H')가 포함되어야 합니다" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -#, fuzzy -msgid "Array values should be single bytes." -msgstr "배열 값은 1바이트 여야합니다." +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" +msgstr "" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" msgstr "" -#: shared-bindings/usb_audio/__init__.c -msgid "At least one of microphone and speaker must be enabled" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" msgstr "" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "%d 블록 할당 시도" +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "오디오 변환이 구현되지 않음" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Audio source error" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "AuthMode.OPEN은 암호와 함께 사용되지 않습니다" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "인증 실패" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "" -#: main.c -msgid "Auto-reload is off.\n" -msgstr "자동 재 장전이 꺼져 있습니다\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" msgstr "" -"자동 새로 고침이 켜져 있습니다. USB를 통해 파일을 저장하여 실행하십시오. 비활" -"성화하려면 REPL을 입력하십시오.\n" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "주변 기기에서 전송 속도가 지원되지 않습니다" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "" -#: ports/zephyr-cp/common-hal/zephyr_display/Display.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "최소 프레임 속도 미만" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "비트 클럭 및 워드 선택은 순차적 GPIO 핀이어야 합니다" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "비트맵 크기와 값 당 비트가 일치해야 합니다" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "부팅 장치는 첫 번째(인터페이스 #0)여야 합니다." +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "플로우 제어에 RX와 TX가 모두 필요합니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "밝기를 조절할 수 없습니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "버퍼 요소는 4바이트 이하여야 합니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "버퍼는 바이트 배열이 아닙니다." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "버퍼 길이 %d가 너무 큽니다. 그것은 %d보다 작아야 합니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" +msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "버퍼가 %d 바이트로 너무 짧습니다" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "버퍼가 너무 작습니다" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Bus 핀 %d은 이미 사용 중입니다" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "CBC 블록은 16 바이트의 배수여야 합니다" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "CIRCUITPY 드라이브를 찾거나 만들 수 없습니다." - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC 또는 checksum이 잘못되었습니다" - -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "네이티브 개체에 액세스하기 전에 super().__init__()를 호출하십시오." - -#: ports/cxd56/common-hal/camera/Camera.c -#, fuzzy -msgid "Camera init" -msgstr "카메라 초기화" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "로컬 특성에 CCCD를 설정할 수 없습니다" - -#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c -#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c -#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "현재 USB 디바이스를 변경할 수 없습니다" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "읽기 전용 파일 시스템" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "_bleio.adapter를 사용해서; 새로운 Adapter를 만들 수 없습니다;" +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "닫힌 파일에서 I/O 작업" -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "값을 삭제할 수 없습니다" +#: main.c +msgid "Done" +msgstr "완료" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "출력 모드에서는 끌어올 수 없습니다" +#: main.c +msgid " output:\n" +msgstr " 산출:\n" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "온도 데이터를 수신 할 수 없습니다" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" +msgstr "" +"자동 새로 고침이 켜져 있습니다. USB를 통해 파일을 저장하여 실행하십시오. 비활" +"성화하려면 REPL을 입력하십시오.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." -msgstr "확장되고 연결 가능한 광고에 대한 검색 응답을 가질 수 없습니다." +#: main.c +msgid "Auto-reload is off.\n" +msgstr "자동 재 장전이 꺼져 있습니다\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "입력 전용 핀을 끌어올 수 없습니다." +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Cannot record to a file" -msgstr "파일에 녹음 할 수 없습니다" +#: main.c +msgid " not found.\n" +msgstr " 찾을 수 없습니다.\n" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." -msgstr "방향이 입력되면 값을 설정할 수 없습니다." - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "RS485 모드에서는 RTS 또는 CTS를 지정할 수 없습니다" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" +msgstr "" +"\n" +"자동 업로드에 의해 코드가 중지되었습니다. 곧 다시 로드됩니다.\n" -#: py/objslice.c -msgid "Cannot subclass slice" +#: main.c +msgid "" +"\n" +"Code done running.\n" msgstr "" +"\n" +"코드 실행 완료.\n" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" +#: main.c +msgid "Woken up by alarm.\n" msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -#, fuzzy -msgid "Cannot wake on pin edge, only level" -msgstr "핀의 에지에서 깨울 수 없고, 레벨에서만 깨울 수 있습니다" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +msgstr "아무 키나 눌러 REPL을 입력한다. 다시 로드할땐 CTRL-D를 사용한다.\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -#, fuzzy -msgid "Cannot wake on pin edge. Only level." -msgstr "핀의 에지에서는 깨울 수 없습니다. 레벨에서만 깨울 수 있습니다." +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +msgstr "알람, CTRL-C 또는 파일을 작성하기 전까지 딥 슬립을 하는 척합니다\n" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "CharacteristicBuffer 쓰기는 제공되지 않습니다" +#: main.c +msgid "UID:" +msgstr "UID:" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "CircuitPython 핵심 코드가 심하게 충돌했습니다. 앗!\n" +#: main.c +msgid "soft reboot\n" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "시계 장치가 사용 중입니다" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" +msgstr "%q 초기화 실패" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." -msgstr "연결이 끊어져 더 이상 사용할 수 없습니다. 새로운 연결을 만드십시오." +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "좌표 배열의 길이가 다릅니다" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +#, fuzzy +msgid "%q out of range" +msgstr "%q가 범위를 벗어남" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" -msgstr "좌표 배열 유형은 크기가 다릅니다" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "잘못된 상태" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "주소를 설정할 수 없습니다" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" +msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "인터럽트를 시작할 수 없습니다, RX가 사용 중입니다" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "플로우 제어에 RX와 TX가 모두 필요합니다" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "디코더를 할당할 수 없습니다" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "%q 버퍼 할당에 실패했습니다" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Channel Init Error" -msgstr "DAC 채널 초기화 오류" - -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Device Init Error" -msgstr "DAC 장치 초기화 오류" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC가 현재 사용 중입니다" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" +msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "데이터 0 핀은 바이트 정렬되어야 합니다" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" -msgstr "데이터 형식 오류(손상된 데이터일 수 있습니다)" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "직접 광고에서는 데이터가 지원되지 않습니다" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "광고 (브로드 캐스트) 패킷에 대한 데이터가 너무 큽니다" - -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#, fuzzy -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "딥 슬립 핀은 풀다운이 있는 상승 에지를 사용해야 합니다" - -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "대상 용량이 destination_length보다 작습니다." - -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" -msgstr "장치 오류 또는 입력 스트림의 잘못된 종료" - -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "사용 중인 장치" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "디스플레이는 16 비트 색 공간을 가져야 합니다." - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" -msgstr "디스플레이 회전은 90도씩 증가해야 합니다" - -#: main.c -msgid "Done" -msgstr "완료" - -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." -msgstr "방향을 입력할 때 드라이브 모드는 사용되지 않습니다." - -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "위 예외를 처리하는 동안, 또 다른 예외가 발생하였습니다:" - -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB는 한 번에 16 바이트에서만 작동합니다" - -#: py/asmxtensa.c -msgid "ERROR: %q %q not word-aligned" -msgstr "" - -#: py/asmxtensa.c -msgid "ERROR: xtensa %q out of range" -msgstr "" - -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" -msgstr "ESP-IDF 메모리 할당에 실패하였습니다" - -#: extmod/modre.c -msgid "Error in regex" -msgstr "Regex에 오류가 있습니다." - -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "safemode.py에 오류가 있습니다." - -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" -msgstr "%q 유형이 필요합니다" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, fuzzy -msgid "Extended advertisements with scan response not supported." -msgstr "검색 응답이 있는 확장 광고는 지원되지 않습니다." - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "FFT는 ndarrays에 대해서만 정의됩니다" - -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "FFT는 선형 배열에 대해서만 구현됩니다" - -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "명령을 보내는 것에 실패했습니다." - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "뮤텍스 획득에 실패했습니다, 오류 0x%04x" - -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" -msgstr "서비스 TXT 레코드를 추가하는 것에 실패했습니다" - -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" -msgstr "" -"서비스 TXT 레코드를 추가하는 것에 실패했습니다; txt_records에서 비문자열 또" -"는 바이트가 발견되었습니다" - -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "%q 버퍼 할당에 실패했습니다" - -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" -msgstr "Wifi 메모리 할당에 실패했습니다" - -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "wifi 검색 메모리 할당에 실패했습니다" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" -msgstr "샘플 버퍼링에 실패했습니다" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "연결에 실패했습니다: 내부 오류" - -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "연결에 실패했습니다: 시간 초과" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" -msgstr "" - -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "MP3 파일 분석에 실패했습니다" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" -msgstr "" - -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "뮤텍스 해제에 실패했습니다, 오류 0x%04x" - -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" -msgstr "" - -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" -msgstr "" - -#: supervisor/shared/safe_mode.c -#, fuzzy -msgid "Failed to write internal flash." -msgstr "내부 플래시를 쓰는 것에 실패했습니다." - -#: py/moderrno.c -msgid "File exists" -msgstr "파일이 있습니다" - -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" -msgstr "파일을 찾을 수 없습니다" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" -msgstr "필터가 너무 복잡합니다" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "펌웨어가 중복되었습니다" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "펌웨어가 잘못되었습니다" - -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "펌웨어가 너무 큽니다" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "L8 색상 공간의 경우, 입력 비트맵은 픽셀 당 8 비트를 가져야 합니다" - -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "RGB 색상 공간의 경우, 입력 비트맵은 픽셀 당 16 비트를 가져야 합니다" - -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "지원되지 않는 형식입니다" - -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" -msgstr "" -"주파수는 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 또는 1008 Mhz 여야 " -"합니다" - -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "이 함수에는 잠금이 필요합니다" - -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "GNSS 초기화" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" -msgstr "일반 오류" - -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "이미 사용된 그룹" - -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "치명적인 실수: 메모리 액세스 또는 명령 오류." - -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "하드웨어가 사용 중입니다, 대체 핀을 사용해보십시오" - -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." -msgstr "VM이 작동하지 않을 때 힙이 할당됩니다." - -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "닫힌 파일에서 I/O 작업" - -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "I2C 초기화 오류" - -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "I2C 주변 기기가 사용 중입니다" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "버퍼 내 요소 길이는 <= 4여야 합니다" - -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "잘못된 버퍼 크기" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "초기화 프로그램의 크기가 잘못되었습니다" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "초기 설정한 핀의 방향이 초기 바깥쪽 핀의 방향과 충돌합니다" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "초기 설정한 핀의 상태가 초기 바깥쪽 핀의 상태와 충돌합니다" - -#: shared-bindings/bitops/__init__.c -#, fuzzy, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "입력 버퍼 길이 (%d) 는 스트랜드 수 (%d)의 배수여야 한다" - -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "입력이 너무 오래 걸린다" - -#: py/moderrno.c -msgid "Input/output error" -msgstr "입력/출력 오류" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" -msgstr "불충분한 인증" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "불충분한 암호화" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "이미지에 대한 메모리 풀이 부족합니다" - -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" -msgstr "불충분한 스트림 입력 버퍼" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "인터페이스를 시작해야 합니다" - -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "내부 오디오 버퍼가 너무 작습니다" - -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "내부 정의 오류" - -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c -#: supervisor/shared/settings.c -msgid "Internal error" -msgstr "내부 오류" - -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" -msgstr "내부 오류 #%d" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "" - -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "내부 감시 타이머가 만료되었습니다." - -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "인터럽트 오류." - -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" -msgstr "출력 함수로 인해 종료되었다" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "사용중인 모든 UART주변 기기" #: ports/analog/common-hal/busio/UART.c #: ports/analog/peripherals/max32690/max32_i2c.c @@ -1385,367 +806,454 @@ msgstr "출력 함수로 인해 종료되었다" msgid "Invalid %q" msgstr "잘못된 %q" -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "잘못된 %q 핀" +#: ports/atmel-samd/audio_dma.c +#, fuzzy +msgid "All sync event channels in use" +msgstr "모든 동기화 이벤트 채널이 사용 중입니다" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "잘못된 ADC 단위 값" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "내부 오디오 버퍼가 너무 작습니다" + +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "" + +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "" + +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "" + +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "모든 타이머가 사용 중입니다" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "잘못된 BLE 파라미터" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "잘못된 BSSID" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "잘못된 MAC 주소" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" +msgstr "칩에 DAC가 없습니다" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "잘못된 인수" - -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" -msgstr "값 당 잘못된 비트" - -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "잘못된 data_pins[%d]" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "시계 장치가 사용 중입니다" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "잘못된 형식" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" +msgstr "무료 GCLKs가 없습니다" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "형식 청크 크기가 잘못되었습니다" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" -msgstr "잘못된 16진수 패스워드" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" +msgstr "DMA 채널을 찾을 수 없습니다" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "잘못된 멀티캐스트 MAC 주소" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "잘못된 크기" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgstr "%dx 오버샘플링이 포함된 8 또는 16 비트 모노만 지원됩니다." -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "TLS에 대한 잘못된 소켓" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "잘못된 상태" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC가 현재 사용 중입니다" -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" -msgstr "잘못된 유니코드 이스케이프" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "키는 16, 24, 또는 32 바이트 길이여야 합니다" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#, fuzzy +msgid "All event channels in use" +msgstr "모든 이벤트 채널이 사용 중입니다" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "LED 매핑은 디스플레이 크기와 일치해야 합니다" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "SDA 또는 SCL에서 풀업을 찾을 수 없습니다; 케이블 연결을 확인하십시오" -#: py/compile.c -msgid "LHS of keyword arg must be an id" -msgstr "키워드 인수의 LHS 는 id 여야 합니다" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q는 2의 거듭제곱이어야 합니다" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "레이어가 이미 그룹에 있습니다" +#: ports/atmel-samd/common-hal/busio/UART.c +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "%q 핀이 없습니다" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "레이어는 그룹 또는 TileGrid 하위 클래스 여야 합니다" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +#, fuzzy +msgid "All RX FIFOs in use" +msgstr "모든 RX FIFOs가 사용 중입니다" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +#, fuzzy +msgid "Already have all-matches listener" +msgstr "이미 모든 일치 리스너가 있습니다" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "MAC 주소는 잘못되었습니다" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" +msgstr "필터가 너무 복잡합니다" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" -msgstr "" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "출력 모드에서는 끌어올 수 없습니다" -#: ports/stm/common-hal/sdioio/SDCard.c +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format -msgid "MMC/SDIO Clock Error %x" -msgstr "" - -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "매핑은 투플이어야 합니다" +msgid "Invalid data_pins[%d]" +msgstr "잘못된 data_pins[%d]" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap must have 8 bits per pixel" +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap size must match the other bitmaps" -msgstr "" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "잘못된 %q 핀" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "일치하지 않는 데이터 크기" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" -msgstr "일치하지 않는 스왑 플래그" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "first_in_pin이 누락되어 있습니다. %q[%u]이 pin(s)을 읽습니다" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "first_in_pin이 누락되었습니다. %q[%u]는 pin(s)에서 이동합니다" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "데이터 0 핀은 바이트 정렬되어야 합니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "first_in_pin이 누락되었습니다. %q[%u]는 핀에 따라 대기 중입니다" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Bus 핀 %d은 이미 사용 중입니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)으로 이동합니다" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)에 씁니다" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "입력이 너무 오래 걸린다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "first_set_pin이 누락되었습니다. %q[%u]는 pin(s)을 설정합니다" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "다른 전송이 이미 활성화되었습니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "jmp_pin이 누락되었습니다. %q[%u] 핀으로 점프합니다" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" +msgstr "%q 실패: %d" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "%q의 하위클래스여야 합니다." +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." +msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" -msgstr "5/6/5 RGB 핀을 제공해야 합니다" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" +msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "MISO 또는 MOSI 핀을 제공해야 합니다" +#: ports/cxd56/common-hal/camera/Camera.c +#, fuzzy +msgid "Camera init" +msgstr "카메라 초기화" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "%d이 아닌, 6 rgb 핀을 여러 개 사용해야 합니다" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." -msgstr "NLR 는 점프에 실패했습니다. 아마도 메모리 손상일 것입니다." +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "버퍼가 너무 작습니다" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "NVS 오류" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "지원되지 않는 형식입니다" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" -msgstr "이름 또는 서비스를 알 수 없습니다" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "GNSS 초기화" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" -msgstr "새로운 비트맵은 원본 비트맵과 크기가 같아야 합니다" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, fuzzy -msgid "Nimble out of memory" -msgstr "빠른 메모리 부족" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "이미 실행 중입니다" -#: ports/atmel-samd/common-hal/busio/UART.c -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "%q 핀이 없습니다" +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q는 %q입니다" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "이 특성에 대한 CCCD가 없습니다" +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "No DAC on chip" -msgstr "칩에 DAC가 없습니다" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "No DMA channel found" -msgstr "DMA 채널을 찾을 수 없습니다" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" -msgstr "DMA 간격 타이머를 찾을 수 없습니다" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c -#, c-format -msgid "No I2C device at address: 0x%x" -msgstr "주소에 I2C 장치가 없습니다: 0x%x" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "IP가 없습니다" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." msgstr "" -#: shared-module/usb/core/Device.c -#, fuzzy -msgid "No configuration set" -msgstr "구성이 설정되어 있지 않습니다" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" -msgstr "연결이 없습니다: 길이를 결정할 수 없습니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" +msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" -msgstr "기본 버스 %q가 없습니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "무료 GCLKs가 없습니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "연결에 실패했습니다: 내부 오류" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" -msgstr "임의의 하드웨어를 사용할 수 없습니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "광고 (브로드 캐스트) 패킷에 대한 데이터가 너무 큽니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c #, fuzzy -msgid "No in in program" -msgstr "프로그램에 입력이 없습니다" +msgid "Already advertising." +msgstr "이미 광고 중입니다." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c #, fuzzy -msgid "No in or out in program" -msgstr "프로그램에 입력 또는 출력이 없습니다" +msgid "Extended advertisements with scan response not supported." +msgstr "검색 응답이 있는 확장 광고는 지원되지 않습니다." -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "긴 정수 지원이 없습니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "직접 광고에서는 데이터가 지원되지 않습니다" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "이 ssid를 사용하는 네트워크가 없습니다" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "" + +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" -msgstr "프로그램에 출력이 없습니다" +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" +msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "SDA 또는 SCL에서 풀업을 찾을 수 없습니다; 케이블 연결을 확인하십시오" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" +msgstr "이 특성에 대한 CCCD가 없습니다" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" -msgstr "핀에 풀다운이 없습니다; 1Mohm를 권장합니다" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "로컬 특성에 CCCD를 설정할 수 없습니다" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: py/moderrno.c -msgid "No space left on device" -msgstr "장치에 남은 공간이 없습니다" - -#: py/moderrno.c -msgid "No such device" -msgstr "해당 장치가 없습니다" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "" -#: py/moderrno.c -msgid "No such file/directory" -msgstr "해당 파일/디렉토리가 없습니다" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" +msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" -msgstr "사용 가능한 타이머가 없습니다" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" +msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" -msgstr "usb 호스트 포트가 초기화되지 않았습니다" +#: ports/espressif/common-hal/_bleio/__init__.c +#, fuzzy +msgid "Nimble out of memory" +msgstr "빠른 메모리 부족" +#: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" -msgstr "Nordic 시스템 펌웨어에 메모리가 부족합니다" - -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" -msgstr "유효한 IP 문자열이 아닙니다" +msgid "Invalid BLE parameter" +msgstr "잘못된 BLE 파라미터" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c @@ -1753,293 +1261,344 @@ msgstr "유효한 IP 문자열이 아닙니다" msgid "Not connected" msgstr "연결되지 않았습니다" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "Not playing" -msgstr "재생되지 않았습니다" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" +msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/_bleio/__init__.c #, c-format -msgid "Number of data_pins must be %d or %d, not %d" +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" msgstr "" -"개체가 초기화 해제되어 더 이사 사용될 수 없습니다. 새로운 개체를 만드십시오." -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "홀수 패리티는 지원되지 않습니다" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" +msgstr "불충분한 인증" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" -msgstr "꺼짐 (연결 끊김)" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" +msgstr "불충분한 암호화" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" -msgstr "켜짐 (연결됨)" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#: ports/espressif/common-hal/_bleio/__init__.c #, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "%dx 오버샘플링이 포함된 8 또는 16 비트 모노만 지원됩니다." +msgid "Unknown BLE error: %d" +msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" -msgstr "IPv4 주소만 지원됩니다" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +#, fuzzy +msgid "Cannot wake on pin edge. Only level." +msgstr "핀의 에지에서는 깨울 수 없습니다. 레벨에서만 깨울 수 있습니다." -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" -msgstr "IPv4 소켓만 지원됩니다" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "입력 전용 핀을 끌어올 수 없습니다." -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" -msgstr "윈도우 형식, 비압축 BMP만 지원됩니다: 지정된 헤더 크기는 %d 입니다" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." +msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, fuzzy -msgid "Only connectable advertisements can be directed" -msgstr "연결 가능한 광고만 지시할 수 있습니다" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "이 하드웨어에서는 에지 감지만 가능합니다" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" -msgstr "ip에는 정수 또는 문자열만 지원됩니다" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." +msgstr "" #: ports/espressif/common-hal/alarm/touch/TouchAlarm.c msgid "Only one %q can be set in deep sleep." msgstr "딥 슬립에서는 하나의 %q만 설정할 수 있습니다." -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." -msgstr "하나의 %q만 설정할 수 있습니다." +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +#, fuzzy +msgid "%q must be array of type 'H'" +msgstr "%q는 'H' 유형의 배열이어야 합니다" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" + +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c #, fuzzy -msgid "Only one address is allowed" -msgstr "오직 하나의 주소만 허용됩니다" +msgid "Peripheral in use" +msgstr "주변 기기가 사용 중입니다" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: shared-module/displayio/ColorConverter.c -#, fuzzy -msgid "Only one color can be transparent at a time" -msgstr "한 번에 한 가지 색상만 투명할 수 있습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" +msgstr "" -#: py/moderrno.c -#, fuzzy -msgid "Operation not permitted" -msgstr "작업이 허용되지 않습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" -msgstr "작업 또는 기능이 지원되지 않습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#, fuzzy -msgid "Operation timed out" -msgstr "작업 시간 초과되었습니다" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" +msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "MDNS 서비스 슬롯 부족" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -#, fuzzy -msgid "Out of memory" -msgstr "메모리 부족" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" +msgstr "" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "사용 중인 모든 I2C주변 기기" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" +msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" -msgstr "소켓 부족" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "출력 버퍼 요소의 길이는 <= 4 바이트 여야 합니다" +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "사용중인 모든 SPI주변 기기" -#: ports/stm/common-hal/pwmio/PWMOut.c -#, fuzzy -msgid "PWM restart" -msgstr "PWM 재시작" +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "ESP-IDF 메모리 할당에 실패하였습니다" -#: ports/raspberrypi/common-hal/countio/Counter.c -#, fuzzy -msgid "PWM slice already in use" -msgstr "PWM slice가 이미 사용 중입니다" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "RS485 모드에서는 RTS 또는 CTS를 지정할 수 없습니다" -#: ports/raspberrypi/common-hal/countio/Counter.c -#, fuzzy -msgid "PWM slice channel A already in use" -msgstr "PWM slice channel A가 이미 사용 중입니다" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" +msgstr "RS485 모드가 아닐 때 RS485 반전이 지정됩니다" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." -msgstr "" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "주변 기기에서 전송 속도가 지원되지 않습니다" -#: shared-module/jpegio/JpegDecoder.c +#: ports/espressif/common-hal/canio/CAN.c #, fuzzy -msgid "Parameter error" -msgstr "파라미터 오류" +msgid "All CAN peripherals are in use" +msgstr "모든 CAN 주변 기기가 사용 중입니다" -#: ports/espressif/common-hal/audiobusio/__init__.c -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -#, fuzzy -msgid "Peripheral in use" -msgstr "주변 기기가 사용 중입니다" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" +msgstr "" -#: py/moderrno.c -msgid "Permission denied" -msgstr "권한이 거부 되었습니다" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" -msgstr "핀은 딥 슬립에서 깨어날 수 없습니다" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#, fuzzy -msgid "Pin count too large" -msgstr "핀 수 너무 큼" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" +msgstr "5/6/5 RGB 핀을 제공해야 합니다" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" -msgstr "핀 인터럽트는 이미 사용 중입니다" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" +msgstr "펌웨어가 중복되었습니다" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "핀은 입력 전용입니다" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "펌웨어가 잘못되었습니다" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "핀은 PWM 채널 B에 있어야 합니다" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "펌웨어가 너무 큽니다" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" -msgstr "핀은 순차적이어야 합니다" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" +msgstr "" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" -msgstr "핀은 순차적인 GPIO 핀이어야 합니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" +msgstr "일반 오류" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +#, fuzzy +msgid "Out of memory" +msgstr "메모리 부족" -#: shared-module/usb/core/Device.c -msgid "Pipe error" -msgstr "파이프 오류" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "잘못된 인수" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "게다가 파일 시스템의 모든 모듈\n" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "잘못된 크기" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" -msgstr "다각형은 최소 3개의 점이 필요합니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "전력이 내려갔습니다. 충분한 전력을 제공할 수 있는지 확인하십시오." +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" +msgstr "작업 또는 기능이 지원되지 않습니다" -#: shared-bindings/_bleio/Adapter.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c #, fuzzy -msgid "Prefix buffer must be on the heap" -msgstr "앞의 버퍼는 힙에 있어야 합니다" +msgid "Operation timed out" +msgstr "작업 시간 초과되었습니다" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" -msgstr "아무 키나 눌러 REPL을 입력한다. 다시 로드할땐 CTRL-D를 사용한다.\n" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" +msgstr "수신된 응답이 잘못되었습니다" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" -msgstr "알람, CTRL-C 또는 파일을 작성하기 전까지 딥 슬립을 하는 척합니다\n" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC 또는 checksum이 잘못되었습니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" -msgstr "프로그램이 ISR을 로드하지 않고 IN을 실행했습니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "프로그램이 OSR을 로드하지 않고 OUT을 실행했습니다" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "MAC 주소는 잘못되었습니다" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" -msgstr "프로그램 크기가 잘못되었습니다" +#: ports/espressif/common-hal/espidf/__init__.c +#, fuzzy, c-format +msgid "%s error 0x%x" +msgstr "%s 오류 0x%x" #: ports/espressif/common-hal/espulp/ULP.c msgid "Program too long" msgstr "프로그램이 너무 깁니다" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" -msgstr "" - +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c #: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q 사용 중입니다" + +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." +msgstr "하나의 %q만 설정할 수 있습니다." + +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c #, fuzzy -msgid "Pull not used when direction is output." -msgstr "방향이 출력 될 때 풀은 사용되지 않습니다" +msgid "Only one address is allowed" +msgstr "오직 하나의 주소만 허용됩니다" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" -msgstr "이 칩에서는 RISE_AND_FALL을 사용할 수 없습니다" +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" +msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" -msgstr "RNG DeInit 오류" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" +msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" -msgstr "RNG 초기화 오류" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" +msgstr "" + +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "주소 범위가 허용되지 않습니다" + +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "NVS 오류" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" msgstr "" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "내부 오류" + #: ports/espressif/common-hal/rclcpy/Node.c msgid "ROS node failed to initialize" msgstr "" @@ -2048,675 +1607,722 @@ msgstr "" msgid "ROS topic failed to initialize" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" -msgstr "RS485 모드가 아닐 때 RS485 반전이 지정됩니다" - -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "이 보드에서는 PTC가 지원되지 않습니다" - -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "난수 생성 오류" - -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "읽기 전용" - -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "읽기 전용 파일 시스템" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "수신된 응답이 잘못되었습니다" - -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "다시 연결하는 중입니다" - -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" -msgstr "너무 빨리 새로고침하였습니다" - -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" -msgstr "" - -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" msgstr "" #: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "SDIO Init Error %x" +msgid "SDIO Init Error 0x%02x" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" -msgstr "" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" +msgstr "소켓 부족" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" -msgstr "" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +#, fuzzy +msgid "%q must be <= %u" +msgstr "%q 는 <= %u 여야 합니다" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "인터페이스를 시작해야 합니다" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "잘못된 멀티캐스트 MAC 주소" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" -msgstr "" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +#, fuzzy +msgid "Already scanning for wifi networks" +msgstr "이미 wifi 네트워크를 찾고 있습니다" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" +msgstr "wifi 검색 메모리 할당에 실패했습니다" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." -msgstr "" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" +msgstr "Wifi 메모리 할당에 실패했습니다" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" -msgstr "" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" +msgstr "IPv4 주소만 지원됩니다" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" +msgstr "MISO 또는 MOSI 핀을 제공해야 합니다" + +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" +msgstr "하드웨어가 사용 중입니다, 대체 핀을 사용해보십시오" + +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" +"주파수는 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 또는 1008 Mhz 여야 " +"합니다" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "연결에 실패했습니다: 시간 초과" + +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" +msgstr "Nordic 시스템 펌웨어에 메모리가 부족합니다" + +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." msgstr "" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +#, fuzzy +msgid "Cannot wake on pin edge, only level" +msgstr "핀의 에지에서 깨울 수 없고, 레벨에서만 깨울 수 있습니다" + +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "사용 중인 장치" -#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c -msgid "The sample's %q does not match" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." -msgstr "" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" +msgstr "홀수 패리티는 지원되지 않습니다" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "모든 채널이 사용중입니다" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "온도 데이터를 수신 할 수 없습니다" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/nordic/sd_mutex.c #, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "" +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "뮤텍스 획득에 실패했습니다, 오류 0x%04x" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" -msgstr "" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "뮤텍스 해제에 실패했습니다, 오류 0x%04x" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" -msgstr "" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "오디오 변환이 구현되지 않음" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Too many channels in sample." -msgstr "" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q는 %q가 아닌 %q 또는 %q 유형이어야 합니다" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" +msgstr "프로그램 크기가 잘못되었습니다" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "초기화 프로그램의 크기가 잘못되었습니다" -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "버퍼 요소는 4바이트 이하여야 합니다" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" +msgstr "일치하지 않는 데이터 크기" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" +msgstr "출력 버퍼 요소의 길이는 <= 4 바이트 여야 합니다" + +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "버퍼 내 요소 길이는 <= 4여야 합니다" #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "비트 클럭 및 워드 선택은 순차적 GPIO 핀이어야 합니다" + +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" +msgstr "" + +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" +msgstr "DMA 간격 타이머를 찾을 수 없습니다" + +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "I2C 주변 기기가 사용 중입니다" + +#: ports/raspberrypi/common-hal/busio/SPI.c +msgid "SPI peripheral in use" msgstr "" #: ports/raspberrypi/common-hal/busio/UART.c msgid "UART peripheral in use" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "핀은 PWM 채널 B에 있어야 합니다" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" +msgstr "이 칩에서는 RISE_AND_FALL을 사용할 수 없습니다" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +#, fuzzy +msgid "PWM slice already in use" +msgstr "PWM slice가 이미 사용 중입니다" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "" +#: ports/raspberrypi/common-hal/countio/Counter.c +#, fuzzy +msgid "PWM slice channel A already in use" +msgstr "PWM slice channel A가 이미 사용 중입니다" -#: main.c -msgid "UID:" -msgstr "UID:" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#, fuzzy +msgid "All state machines in use" +msgstr "모든 상태 머신이 사용 중입니다" -#: shared-module/usb_hid/Device.c -msgid "USB busy" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." -msgstr "" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" +msgstr "핀은 순차적이어야 합니다" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -msgstr "UUID문자열이 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'형식이 아닙니다" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" +msgstr "서비스 TXT 레코드를 추가하는 것에 실패했습니다" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" -msgstr "" -"UUID값이 문자열(str), 정수(int) 또는 바이트버퍼가(byte buffer) 아닙니다" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" +msgstr "MDNS 서비스 슬롯 부족" #: ports/raspberrypi/common-hal/memorymap/AddressRange.c msgid "Unable to access unaligned IO register" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Unable to allocate buffers for signed conversion" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." -msgstr "" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "핀의 모든 타이머가 사용 중입니다" + +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" +msgstr "핀은 순차적인 GPIO 핀이어야 합니다" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "Pin count too large" +msgstr "핀 수 너무 큼" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "Missing jmp_pin. %q[%u] jumps on pin" +msgstr "jmp_pin이 누락되었습니다. %q[%u] 핀으로 점프합니다" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "%q[%u]에서 추가 핀 사용" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" +msgstr "first_in_pin이 누락되었습니다. %q[%u]는 핀에 따라 대기 중입니다" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" +msgstr "%q[%u]이(가) 카운트 외부의 입력을 대기합니다" -#: py/parse.c -msgid "Unable to init parser" -msgstr "파서를 초기화(init) 할 수 없습니다" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +msgstr "first_in_pin이 누락되었습니다. %q[%u]는 pin(s)에서 이동합니다" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "%q[%u] shifts in more bits than pin count" +msgstr "%q[%u]가 핀 수보다 더 많은 비트로 이동했습니다" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)으로 이동합니다" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "%q[%u] shifts out more bits than pin count" +msgstr "%q[%u]이(가) 핀 수보다 많은 비트를 전송합니다" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "first_set_pin이 누락되었습니다. %q[%u]는 pin(s)을 설정합니다" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)에 씁니다" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "Missing first_in_pin. %q[%u] reads pin(s)" +msgstr "first_in_pin이 누락되어 있습니다. %q[%u]이 pin(s)을 읽습니다" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" +msgstr "프로그램이 ISR을 로드하지 않고 IN을 실행했습니다" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" +msgstr "프로그램이 OSR을 로드하지 않고 OUT을 실행했습니다" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" +msgstr "초기 설정한 핀의 상태가 초기 바깥쪽 핀의 상태와 충돌합니다" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" +msgstr "초기 설정한 핀의 방향이 초기 바깥쪽 핀의 방향과 충돌합니다" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" +msgstr "프로그램에 출력이 없습니다" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "No in in program" +msgstr "프로그램에 입력이 없습니다" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#, fuzzy +msgid "No in or out in program" +msgstr "프로그램에 입력 또는 출력이 없습니다" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "일치하지 않는 스왑 플래그" -#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c #, c-format -msgid "Unknown system firmware error: %d" +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." -msgstr "" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" +msgstr "IPv4 소켓만 지원됩니다" -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" -msgstr "" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "모든 dma채널이 사용 중입니다" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q는 이 보드에 대한 읽기 전용입니다" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" -msgstr "" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "AP를 시작할 수 없습니다" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" +msgstr "이 하드웨어에서는 에지 감지만 가능합니다" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" +msgstr "핀 인터럽트는 이미 사용 중입니다" -#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c -#: ports/zephyr-cp/common-hal/busio/I2C.c -#: ports/zephyr-cp/common-hal/busio/SPI.c -#: ports/zephyr-cp/common-hal/busio/UART.c -msgid "Use device tree to define %q devices" -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" +msgstr "핀은 딥 슬립에서 깨어날 수 없습니다" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" -msgstr "" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#, fuzzy +msgid "Deep sleep pins must use a rising edge with pulldown" +msgstr "딥 슬립 핀은 풀다운이 있는 상승 에지를 사용해야 합니다" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "잘못된 ADC 단위 값" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "DAC 장치 초기화 오류" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "DAC 채널 초기화 오류" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" msgstr "" -#: py/builtinhelp.c -#, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" -msgstr "" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, fuzzy +msgid "Another PWMAudioOut is already active" +msgstr "다른 PWMaudioOut이 이미 활성화되어 있습니다" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "버퍼 길이 %d가 너무 큽니다. 그것은 %d보다 작아야 합니다" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" -msgstr "" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" +msgstr "샘플 버퍼링에 실패했습니다" -#: main.c -msgid "Woken up by alarm.\n" -msgstr "" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "I2C 초기화 오류" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." -msgstr "" +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" +msgstr "내부 정의 오류" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." -msgstr "" +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "인터럽트를 시작할 수 없습니다, RX가 사용 중입니다" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." -msgstr "" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" +msgstr "RNG 초기화 오류" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." -msgstr "" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" +msgstr "난수 생성 오류" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." -msgstr "" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" +msgstr "RNG DeInit 오류" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" -msgstr "" +#: ports/stm/common-hal/pwmio/PWMOut.c +#, fuzzy +msgid "PWM restart" +msgstr "PWM 재시작" -#: py/objtype.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "__init__() should return None, not '%s'" +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" -msgstr "" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#, fuzzy +msgid ".show(x) removed. Use .root_group = x" +msgstr ".show(x)가 제거되었습니다. .root_group = x를 사용합니다" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "밝기를 조절할 수 없습니다" + +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q는 %d-%d이어야 합니다" + +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "이미 사용된 그룹" + +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "최소 프레임 속도 미만" + +#: py/argcheck.c +msgid "function doesn't take keyword arguments" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/argcheck.c +msgid "'%q' argument required" +msgstr "'%q' 인수가 필요합니다" + +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: py/compile.c -msgid "argument name reused" +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" #: py/argcheck.c shared-bindings/_stage/__init__.c @@ -2724,943 +2330,1094 @@ msgstr "" msgid "argument num/types mismatch" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" -msgstr "" +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q는 %d이어야 합니다" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" -msgstr "" +#: py/argcheck.c +#, fuzzy +msgid "%q must be >= %d" +msgstr "%q 는 >= %d 여야 합니다" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" -msgstr "" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +#, fuzzy +msgid "%q must be <= %d" +msgstr "%q 는 <= %d 여야 합니다" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" -msgstr "" +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q는 %q가 아니라 %q 유형이어야 합니다" + +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "%q 길이는 %d - %d이어야 합니다" + +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "%q 길이는 >= %d이어야 합니다" + +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "%q 길이는 <= %d>여야 합니다" + +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "%q 길이는 %d이어야 합니다" + +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q의 %q는 %q가 아니라 %q 유형이어야 합니다" -#: py/compile.c -msgid "async for/with outside async function" +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/bc.c py/objnamedtuple.c +#, fuzzy +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q()는 %d 위치 인수를 사용하지만 %d이(가) 주어졌습니다" + +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" #: py/builtinevex.c msgid "bad compile mode" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" -msgstr "" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" +msgstr "게다가 파일 시스템의 모든 모듈\n" -#: py/objstr.c -msgid "bad format string" +#: py/builtinhelp.c +msgid "object " msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" -msgstr "" +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " %q 유형입니다\n" -#: py/emitnative.c -msgid "binary op %q not implemented" +#: py/builtinhelp.c +#, c-format +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" -msgstr "bits_per_sample은 8 또는 16이어야합니다" - -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/builtinimport.c +msgid "relative import" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/compile.c +msgid "can't assign to expression" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/compile.c +msgid "invalid arch" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: py/emitbc.c -msgid "bytecode overflow" -msgstr "" +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "'break'/'continue' 외부 루프" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/compile.c +msgid "'return' outside function" +msgstr "'return' 는 함수 외부에 존재합니다" + +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/compile.c +#, fuzzy +msgid "*x must be assignment target" +msgstr "*x는 할당 대상이어야 합니다" + +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/compile.c +#, fuzzy +msgid "* arg after **" +msgstr "* 인수 뒤에 **" + +#: py/compile.c +msgid "too many args" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/compile.c +msgid "LHS of keyword arg must be an id" +msgstr "키워드 인수의 LHS 는 id 여야 합니다" + +#: py/compile.c +msgid "positional arg after **" msgstr "" #: py/compile.c -msgid "can't assign to expression" +msgid "positional arg after keyword arg" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" +#: py/compile.c py/parse.c +msgid "invalid syntax" +msgstr "구문(syntax)가 유효하지 않습니다" + +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: py/obj.c -#, fuzzy, c-format -msgid "can't convert %s to complex" -msgstr "%s 를 복합어로 변환할 수 없습니다" +#: py/compile.c +msgid "'yield' outside function" +msgstr "'yield' 는 함수 외부에 존재합니다" -#: py/obj.c -#, c-format -msgid "can't convert %s to float" -msgstr "" +#: py/compile.c +#, fuzzy +msgid "'yield from' inside async function" +msgstr "비동기 함수 내 'yield from'" -#: py/objint.c py/runtime.c -#, c-format -msgid "can't convert %s to int" +#: py/compile.c +msgid "'await' outside function" +msgstr "'await' 는 펑크션 외부에 있습니다" + +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" +#: py/compile.c +msgid "argument name reused" msgstr "" -#: py/obj.c -msgid "can't convert to complex" +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: py/obj.c -msgid "can't convert to float" +#: py/compile.c +msgid "unknown type" msgstr "" -#: py/runtime.c -msgid "can't convert to int" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "'label' 에는 1 개의 독립변수가 필요합니다" + +#: py/compile.c +msgid "label redefined" msgstr "" -#: py/objtype.c -msgid "can't create instance" -msgstr "" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "'align' 에는 1 개의 독립변수가 필요합니다" #: py/compile.c -msgid "can't declare nonlocal in outer code" -msgstr "" +msgid "'data' requires at least 2 arguments" +msgstr "'data' 에는 >=2 개의 독립변수가 필요합니다" #: py/compile.c -msgid "can't delete expression" -msgstr "" +#, fuzzy +msgid "'data' requires integer arguments" +msgstr "'data' 에는 정수 인수가 필요합니다" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" -#: py/emitnative.c -msgid "can't do unary op of '%q'" +#: py/emitbc.c +msgid "bytecode overflow" msgstr "" -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: py/emitnative.c -msgid "can't load from '%q'" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: py/emitnative.c -msgid "can't load with '%q' index" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: py/emitnative.c -msgid "can't store '%q'" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: py/emitnative.c -msgid "can't store to '%q'" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: py/emitnative.c -msgid "can't store with '%q' index" -msgstr "" +#: py/emitinlinethumb.c +#, fuzzy, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s'는 최대 r%d를 필요로 합니다" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "'%s' 에는 레지스터가 필요합니다" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "'%s' 에는 특별한 레지스터가 필요합니다" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "'%s' 에는 FPU레지스터가 필요합니다" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' {r0, r1, ...}은 을 기대합니다" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' 는 정수 여야합니다" + +#: py/emitinlinethumb.c +#, fuzzy, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' 정수 0x%x 이 마스크 0x%x에 맞지 않습니다" + +#: py/emitinlinethumb.c +#, fuzzy, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s' 에는 [a, b] 형식의 주소가 필요합니다" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' 에는 라벨이 필요합니다" + +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/emitinlinextensa.c +#, fuzzy, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' 정수 %d가 %d..%d 범위 내에 있지 않습니다" + +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" msgstr "" -#: py/compile.c -msgid "cannot emit native code for this architecture" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/emitnative.c +msgid "conversion to object" msgstr "" #: py/emitnative.c -msgid "casting" +msgid "local '%q' used before type known" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/emitnative.c +msgid "can't load from '%q'" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/emitnative.c +msgid "can't load with '%q' index" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/emitnative.c +msgid "can't store to '%q'" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/emitnative.c +msgid "'not' not implemented" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +#: py/emitnative.c +msgid "can't do unary op of '%q'" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" #: py/emitnative.c msgid "comparison of int and uint" msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/emitnative.c +msgid "casting" msgstr "" #: py/emitnative.c -msgid "conversion to object" +msgid "return expected '%q' but got '%q'" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/emitnative.c +msgid "must raise an object" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/modbuiltins.c +msgid "chr() arg not in range(0x110000)" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "pow() 는 3개의 인수를 지원하지 않습니다" + +#: py/modbuiltins.c +msgid "must use keyword argument for key function" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "data pin #%d in use" -msgstr "" +#: py/moderrno.c +#, fuzzy +msgid "Operation not permitted" +msgstr "작업이 허용되지 않습니다" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" -msgstr "" +#: py/moderrno.c +msgid "No such file/directory" +msgstr "해당 파일/디렉토리가 없습니다" -#: py/parsenum.c -msgid "decimal numbers not supported" -msgstr "" +#: py/moderrno.c +msgid "Input/output error" +msgstr "입력/출력 오류" -#: py/compile.c -msgid "default 'except' must be last" -msgstr "" +#: py/moderrno.c +msgid "Permission denied" +msgstr "권한이 거부 되었습니다" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" -msgstr "" +#: py/moderrno.c +msgid "File exists" +msgstr "파일이 있습니다" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" -msgstr "" +#: py/moderrno.c +msgid "No such device" +msgstr "해당 장치가 없습니다" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" +#: py/moderrno.c +msgid "No space left on device" +msgstr "장치에 남은 공간이 없습니다" -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "destination must be an array of type 'h'" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" -msgstr "" +#: py/modthread.c +msgid "expecting a dict for keyword args" +msgstr "사전(dict)이 예상되었습니다" -#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c -msgid "divide by zero" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: py/runtime.c -msgid "division by zero" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: py/objdeque.c -msgid "empty" -msgstr "" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" +msgstr "위 예외를 처리하는 동안, 또 다른 예외가 발생하였습니다:" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" -msgstr "" +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " 파일 \"%q\", 라인 %d" -#: py/objstr.c -msgid "empty separator" -msgstr "" +#: py/obj.c +msgid " File \"%q\"" +msgstr " 파일 \"%q\"" -#: shared-bindings/random/__init__.c -msgid "empty sequence" -msgstr "" +#: py/obj.c +msgid ", in %q\n" +msgstr ", 에서 %q\n" -#: py/objstr.c -msgid "end of format while looking for conversion specifier" +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: ports/nordic/common-hal/busio/UART.c +#: py/obj.c #, c-format -msgid "error = 0x%08lX" +msgid "can't convert %s to float" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: py/objstr.c -msgid "expected ':' after format specifier" -msgstr "':'이 예상되었습니다" +#: py/obj.c +#, fuzzy, c-format +msgid "can't convert %s to complex" +msgstr "%s 를 복합어로 변환할 수 없습니다" #: py/obj.c msgid "expected tuple/list" msgstr "튜플(tuple) 또는 리스트(list)이 예상되었습니다" -#: py/modthread.c -msgid "expecting a dict for keyword args" -msgstr "사전(dict)이 예상되었습니다" - -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" -msgstr "" +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "%q 인덱스는 %s 가 아닌 정수 여야합니다" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/obj.c +msgid "object has no len" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/obj.c +#, fuzzy, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "'%s' 개체가 항목 삭제를 지원하지 않습니다" + +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "'%s' 개체를 subscriptable 할 수 없습니다" + +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/obj.c +#, fuzzy, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "'%s' 개체가 항목 할당을 지원하지 않습니다" + +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: py/objint.c -msgid "float too big" -msgstr "float이 너무 큽니다" +#: py/objarray.c +msgid "lhs and rhs should be compatible" +msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: py/objstr.c -msgid "format needs a dict" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" -#: py/objstr.c -msgid "format string didn't convert all arguments" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: py/objstr.c -msgid "format string needs more arguments" +#: py/objcomplex.c +msgid "0.0 to a complex power" msgstr "" #: py/objdeque.c msgid "full" msgstr "완전한(full)" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" +#: py/objdeque.c +msgid "empty" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objdict.c +msgid "dict update sequence has wrong length" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: py/bc.c +#: py/objint.c +msgid "float too big" +msgstr "float이 너무 큽니다" + +#: py/objint.c #, c-format -msgid "function missing required positional argument #%d" +msgid "value must fit in %d byte(s)" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" +msgstr "긴 정수 지원이 없습니다" + +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" + +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy arch" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +#, fuzzy +msgid "%q step cannot be zero" +msgstr "%q 단계는 0일 수 없습니다" + +#: py/objslice.c +msgid "Cannot subclass slice" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy file" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" #: py/objstr.c -msgid "incomplete format" +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" #: py/objstr.c -msgid "incomplete format key" +msgid "empty separator" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/objstr.c +msgid "rsplit(None,n)" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/objstr.c +#, c-format +msgid "unknown conversion specifier %c" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/objstr.c +msgid "expected ':' after format specifier" +msgstr "':'이 예상되었습니다" + +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/objstr.c +msgid "%q index out of range" +msgstr "%q 인덱스 범위를 벗어났습니다" + +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/objstr.c +msgid "invalid format specifier" +msgstr "형식 지정자(format specifier)가 유효하지 않습니다" + +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/objstr.c +#, fuzzy +msgid "'=' alignment not allowed in string format specifier" +msgstr "'=' 문자열 형식 지정자에서 정렬이 허용되지 않습니다" + +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/objstr.c +msgid "incomplete format" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/objstr.c +msgid "format string needs more arguments" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "네이티브 개체에 액세스하기 전에 super().__init__()를 호출하십시오." + +#: py/objtype.c +msgid "__init__() should return None" +msgstr "" + +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" +msgstr "" + +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, c-format -msgid "interval must be in range %s-%s" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: py/emitinlinerv32.c -msgid "invalid RV32 instruction '%q'" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "cert가 유효하지 않습니다" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" +msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -#, c-format -msgid "invalid destination buffer, must be an array of type: %c" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" -msgstr "형식 지정자(format specifier)가 유효하지 않습니다" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: py/parse.c +msgid "not a constant" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" -msgstr "키가 유효하지 않습니다" +#: py/parse.c +msgid "Unable to init parser" +msgstr "파서를 초기화(init) 할 수 없습니다" -#: py/compile.c -msgid "invalid micropython decorator" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" -msgstr "단계(step)가 유효하지 않습니다" - -#: py/compile.c py/parse.c -msgid "invalid syntax" -msgstr "구문(syntax)가 유효하지 않습니다" +#: py/parse.c +msgid "malformed f-string" +msgstr "" #: py/parsenum.c msgid "invalid syntax for integer" @@ -3675,105 +3432,111 @@ msgstr "구문(syntax)가 정수가 유효하지 않습니다" msgid "invalid syntax for number" msgstr "숫자에 대한 구문(syntax)가 유효하지 않습니다" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: py/persistentcode.c +msgid "incompatible .mpy arch" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" -msgstr "" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "'%q' 개체가 '%q'를 지원하지 않습니다" -#: py/compile.c -msgid "label redefined" +#: py/qstr.c +msgid "name too long" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: py/vm.c -msgid "local variable referenced before assignment" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" -msgstr "" +#: py/runtime.c +#, fuzzy +msgid "'%s' object has no attribute '%q'" +msgstr "'%s' 개체에 '%q' 특성이 없습니다" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " +#: py/runtime.c +msgid "object not iterable" msgstr "" #: py/runtime.c -msgid "maximum recursion depth exceeded" +msgid "'%q' object isn't iterable" +msgstr "'%q' 개체를 사용할 수 없습니다" + +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "'%q' 개체가 iterator가 아닙니다" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" #: py/runtime.c @@ -3782,480 +3545,631 @@ msgid "memory allocation failed, allocating %u bytes" msgstr "" #: py/runtime.c -msgid "memory allocation failed, heap is locked" +msgid "can't convert to int" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" +msgstr "" + +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" +msgstr "" + +#: py/vm.c +msgid "local variable referenced before assignment" +msgstr "" + +#: py/vm.c +msgid "no active exception to reraise" +msgstr "" + +#: py/vm.c +msgid "opcode" +msgstr "" + +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "_bleio.adapter를 사용해서; 새로운 Adapter를 만들 수 없습니다;" + +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "주소를 설정할 수 없습니다" + +#: shared-bindings/_bleio/Adapter.c +#, c-format +msgid "interval must be in range %s-%s" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." +msgstr "확장되고 연결 가능한 광고에 대한 검색 응답을 가질 수 없습니다." + +#: shared-bindings/_bleio/Adapter.c +#, fuzzy +msgid "Only connectable advertisements can be directed" +msgstr "연결 가능한 광고만 지시할 수 있습니다" + +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: py/runtime.c -msgid "module '%q' has no attribute '%q'" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: py/builtinimport.c -msgid "module not found" -msgstr "" +#: shared-bindings/_bleio/Adapter.c +#, fuzzy +msgid "Prefix buffer must be on the heap" +msgstr "앞의 버퍼는 힙에 있어야 합니다" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" -msgstr "" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "CharacteristicBuffer 쓰기는 제공되지 않습니다" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" -msgstr "" +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." +msgstr "연결이 끊어져 더 이상 사용할 수 없습니다. 새로운 연결을 만드십시오." -#: py/compile.c -msgid "multiple *x in assignment" -msgstr "" +#: shared-bindings/_bleio/PacketBuffer.c +#, c-format +msgid "Buffer too short by %d bytes" +msgstr "버퍼가 %d 바이트로 너무 짧습니다" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" -msgstr "" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" +msgstr "연결이 없습니다: 길이를 결정할 수 없습니다" -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +msgstr "UUID문자열이 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'형식이 아닙니다" -#: py/emitnative.c -msgid "must raise an object" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" +"UUID값이 문자열(str), 정수(int) 또는 바이트버퍼가(byte buffer) 아닙니다" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "" +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" +msgstr "읽기 전용" -#: py/runtime.c -msgid "name not defined" -msgstr "" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "잘못된 버퍼 크기" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: py/runtime.c +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" +msgstr "핀은 입력 전용입니다" + +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c #, c-format -msgid "need more than %d values to unpack" +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/modmath.c -msgid "negative factorial" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "키는 16, 24, 또는 32 바이트 길이여야 합니다" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB는 한 번에 16 바이트에서만 작동합니다" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "CBC 블록은 16 바이트의 배수여야 합니다" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +#, fuzzy +msgid "Array values should be single bytes." +msgstr "배열 값은 1바이트 여야합니다." -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" -msgstr "" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" +msgstr "%q 유형이 필요합니다" -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" +msgstr "이 보드에서는 PTC가 지원되지 않습니다" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" -msgstr "" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q는 'H' 또는 'B' 타입의 바이트 배열 또는 배열이어야 합니다" -#: py/objstr.c -msgid "non-hex digit" -msgstr "" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" +msgstr "재생되지 않았습니다" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "파일에 녹음 할 수 없습니다" + +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "대상 용량이 destination_length보다 작습니다." + +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q는 h, H, b 또는 B 유형의 바이트 배열 또는 배열이어야 합니다" + +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" +msgstr "bits_per_sample은 8 또는 16이어야합니다" + +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" +msgstr "%q와 %q는 달라야 합니다" + +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "이 함수에는 잠금이 필요합니다" + +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "object does not support DigitalInOut protocol" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "비트맵 크기와 값 당 비트가 일치해야 합니다" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +msgstr "L8 색상 공간의 경우, 입력 비트맵은 픽셀 당 8 비트를 가져야 합니다" + +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +msgstr "RGB 색상 공간의 경우, 입력 비트맵은 픽셀 당 16 비트를 가져야 합니다" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/obj.c +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" +msgstr "좌표 배열 유형은 크기가 다릅니다" + +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "좌표 배열의 길이가 다릅니다" + +#: shared-bindings/bitmaptools/__init__.c #, c-format -msgid "object of type '%s' has no len()" +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" -msgstr "" +#: shared-bindings/bitops/__init__.c +#, fuzzy, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgstr "입력 버퍼 길이 (%d) 는 스트랜드 수 (%d)의 배수여야 한다" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" +msgstr "기본 버스 %q가 없습니다" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "디스플레이 회전은 90도씩 증가해야 합니다" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q가 참일 때 %q는 1이어야 합니다" -#: py/vm.c -msgid "opcode" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "디스플레이는 16 비트 색 공간을 가져야 합니다." -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" -msgstr "" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." +msgstr "%q의 하위클래스여야 합니다." -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "방향이 입력되면 값을 설정할 수 없습니다." -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "방향을 입력할 때 드라이브 모드는 사용되지 않습니다." -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +#, fuzzy +msgid "Pull not used when direction is output." +msgstr "방향이 출력 될 때 풀은 사용되지 않습니다" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" -msgstr "" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "값을 삭제할 수 없습니다" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" -msgstr "" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" +msgstr "새로운 비트맵은 원본 비트맵과 크기가 같아야 합니다" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "너무 빨리 새로고침하였습니다" + +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "버퍼는 바이트 배열이 아닙니다." + +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: py/modstruct.c +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" +msgstr "유효한 IP 문자열이 아닙니다" + +#: shared-bindings/ipaddress/IPv4Address.c #, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "" +msgid "Address must be %d bytes long" +msgstr "주소 길이는 %d 바이트 여야합니다" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" -msgstr "" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "ip에는 정수 또는 문자열만 지원됩니다" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" -msgstr "" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" +msgstr "매핑은 투플이어야 합니다" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" +"서비스 TXT 레코드를 추가하는 것에 실패했습니다; txt_records에서 비문자열 또" +"는 바이트가 발견되었습니다" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" msgstr "" -#: py/compile.c -msgid "positional arg after **" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q에 중복된 핀이 포함" -#: py/compile.c -msgid "positional arg after keyword arg" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q 및 %q에 중복된 핀이 포함" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: extmod/modre.c -msgid "regex too complex" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" +msgstr "임의의 하드웨어를 사용할 수 없습니다" + +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "명령을 보내는 것에 실패했습니다." + +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "배열은 하프워드(유형 'H')가 포함되어야 합니다" + +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: py/objint_longlong.c py/parsenum.c -msgid "result overflows long long storage" +#: shared-bindings/random/__init__.c +msgid "invalid step" +msgstr "단계(step)가 유효하지 않습니다" + +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c @@ -4265,440 +4179,540 @@ msgstr "" #: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" +msgstr "%d이 아닌, 6 rgb 핀을 여러 개 사용해야 합니다" + +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +"%d 주소 핀들, %d rgb 핀들과 %d 타일 들은 높이가 %d임을 나타낸다, %d가 아니라" -#: py/objstr.c -msgid "rsplit(None,n)" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" +msgstr "이름 또는 서비스를 알 수 없습니다" + +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "현재 USB 디바이스를 변경할 수 없습니다" + +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" +msgstr "파일을 찾을 수 없습니다" + +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "short read" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" msgstr "" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q 및 %q의 길이는 모두 같아야 합니다" + +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" +"개체가 초기화 해제되어 더 이사 사용될 수 없습니다. 새로운 개체를 만드십시오." -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "%q는 %q의 하위 클래스여야 합니다" + +#: shared-bindings/wifi/Monitor.c +#, fuzzy +msgid "%q out of bounds" +msgstr "%q가 경계를 벗어남" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" +msgstr "잘못된 16진수 패스워드" + +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" +msgstr "" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "잘못된 MAC 주소" + +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "AuthMode.OPEN은 암호와 함께 사용되지 않습니다" + +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "잘못된 BSSID" + +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "인증 실패" + +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" +msgstr "이 ssid를 사용하는 네트워크가 없습니다" + +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" -msgstr "" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" +msgstr "주소에 I2C 장치가 없습니다: 0x%x" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" -msgstr "" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "형식 청크 크기가 잘못되었습니다" -#: py/nativeglue.c -msgid "slice unsupported" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: py/objint.c py/sequence.c -msgid "small int overflow" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: main.c -msgid "soft reboot\n" -msgstr "" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "디코더를 할당할 수 없습니다" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" -msgstr "" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "MP3 파일 분석에 실패했습니다" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" +msgstr "값 당 잘못된 비트" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" +#: shared-module/displayio/ColorConverter.c +#, fuzzy +msgid "Only one color can be transparent at a time" +msgstr "한 번에 한 가지 색상만 투명할 수 있습니다" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" -msgstr "" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "레이어가 이미 그룹에 있습니다" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "레이어는 그룹 또는 TileGrid 하위 클래스 여야 합니다" + +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" +msgstr "윈도우 형식, 비압축 BMP만 지원됩니다: 지정된 헤더 크기는 %d 입니다" + +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: py/objstrunicode.c +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c #, c-format -msgid "string indices must be integers, not %s" +msgid "Unable to find I2C Display at %x" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" -msgstr "" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "LED 매핑은 디스플레이 크기와 일치해야 합니다" -#: extmod/modtime.c -msgid "ticks interval overflow" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" +msgstr "출력 함수로 인해 종료되었다" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" +msgstr "장치 오류 또는 입력 스트림의 잘못된 종료" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" +msgstr "이미지에 대한 메모리 풀이 부족합니다" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" +msgstr "불충분한 스트림 입력 버퍼" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +#, fuzzy +msgid "Parameter error" +msgstr "파라미터 오류" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" +msgstr "데이터 형식 오류(손상된 데이터일 수 있습니다)" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" -msgstr "" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" +msgstr "%d 블록 할당 시도" -#: py/compile.c -msgid "too many args" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" -msgstr "" +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" +msgstr "잘못된 형식" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/runtime.c +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" +msgstr "사용 가능한 타이머가 없습니다" + +#: shared-module/rgbmatrix/RGBMatrix.c #, c-format -msgid "too many values to unpack (expected %d)" -msgstr "" +msgid "Internal error #%d" +msgstr "내부 오류 #%d" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" -msgstr "" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "TLS에 대한 잘못된 소켓" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" -msgstr "" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" +msgstr "키가 유효하지 않습니다" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" -msgstr "" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "cert가 유효하지 않습니다" -#: py/parse.c -msgid "unexpected indent" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" -msgstr "" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' 및 'O'는 지원되지 않는 형식 유형입니다" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" -msgstr "" +#: shared-module/synthio/__init__.c +#, fuzzy +msgid "%q must be array of type 'h'" +msgstr "%q는 'h' 유형의 배열이어야 합니다" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: py/compile.c -msgid "unknown type" -msgstr "" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" +msgstr "핀에 풀다운이 없습니다; 1Mohm를 권장합니다" -#: py/compile.c -msgid "unknown type '%q'" -msgstr "" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" +msgstr "usb 호스트 포트가 초기화되지 않았습니다" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" -msgstr "" +#: shared-module/usb/core/Device.c +msgid "Pipe error" +msgstr "파이프 오류" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" -msgstr "" +#: shared-module/usb/core/Device.c +#, fuzzy +msgid "No configuration set" +msgstr "구성이 설정되어 있지 않습니다" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" -msgstr "" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" +msgstr "다각형은 최소 3개의 점이 필요합니다" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" +msgstr "다시 연결하는 중입니다" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" +msgstr "켜짐 (연결됨)" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" -msgstr "" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" +msgstr "꺼짐 (연결 끊김)" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" msgstr "" +"\n" +"안전 모드에 있는 이유는 다음과 같습니다:\n" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." +msgstr "전력이 내려갔습니다. 충분한 전력을 제공할 수 있는지 확인하십시오." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "CIRCUITPY 드라이브를 찾거나 만들 수 없습니다." -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: extmod/moddeflate.c -msgid "wbits" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "safemode.py에 오류가 있습니다." -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "부팅 장치는 첫 번째(인터페이스 #0)여야 합니다." -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "내부 감시 타이머가 만료되었습니다." -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "CircuitPython 핵심 코드가 심하게 충돌했습니다. 앗!\n" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." +msgstr "VM이 작동하지 않을 때 힙이 할당됩니다." -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" -msgstr "" +#: supervisor/shared/safe_mode.c +#, fuzzy +msgid "Failed to write internal flash." +msgstr "내부 플래시를 쓰는 것에 실패했습니다." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." +msgstr "치명적인 실수: 메모리 액세스 또는 명령 오류." -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "인터럽트 오류." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." +msgstr "NLR 는 점프에 실패했습니다. 아마도 메모리 손상일 것입니다." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" +"\n" +"github.com/adafruit/circuitpython/issues 에\n" +"프로그램 오류를 제출하세요." -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" +"\n" +"재설정을 눌러 안전 모드를 종료합니다.\n" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "%s'을(를) 검색하는 동안 오류가 발생했습니다:\n" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "잘못된 유니코드 이스케이프" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "IP가 없습니다" + #~ msgid "%q renamed %q" #~ msgstr "%q가 %q로 이름이 변경되었습니다" diff --git a/locale/ru.po b/locale/ru.po index a88c6cbbea3..b0a6e3ef710 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -18,1729 +18,1564 @@ msgstr "" "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Weblate 5.13-dev\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" -msgstr "" -"\n" -"Программа закончила выполнение.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" +msgstr "пустая куча" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" -msgstr "" -"\n" -"Программа остановлена автоматической перезагрузкой. Скоро перезагрузка.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" +msgstr "Не могу отменить себя" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." -msgstr "" -"\n" -"Пожалуйста подайте вопрос с вашей программой на github.com/adafruit/" -"circuitpython/issues." +#: extmod/modasyncio.c +msgid "can't wait" +msgstr "не может ждать" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" -msgstr "" -"\n" -"Нажмите на сброс чтобы выйти из безопасного режима.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" +msgstr "Требуется байтоподобный объект" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" +msgstr "Неправильная набивка" + +#: extmod/moddeflate.c +msgid "format" +msgstr "формат" + +#: extmod/moddeflate.c +msgid "wbits" msgstr "" -"\n" -"Вы в безопасном режиме потому что:\n" -#: py/obj.c -msgid " File \"%q\"" -msgstr " Файл \"%q\"" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "хэш является окончательным" -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " Файл \"%q\", строка %d" +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "куча должна быть списком" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " имеет тип %q\n" +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "синтаксис ошибка в JSON" -#: main.c -msgid " not found.\n" -msgstr " не найден.\n" +#: extmod/modrandom.c +msgid "bits must be 32 or less" +msgstr "биты должны быть 32 или менее" -#: main.c -msgid " output:\n" -msgstr " вывод:\n" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" +msgstr "Нет начального числа по умолчанию" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" -msgstr "" +#: extmod/modre.c +msgid "splitting with sub-captures" +msgstr "разделение с помощью подзахватов" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modre.c +msgid "regex too complex" msgstr "" -"Адресные контакты %d, контакты rgb %d и плитки %d обозначают высоту %d, а не " -"%d" -#: py/emitinlinextensa.c -#, c-format -msgid "%d is not a multiple of %d" -msgstr "" +#: extmod/modre.c +msgid "Error in regex" +msgstr "Ошибка в регулярном выражении" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q и %q содержат пины дупликаты" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" +msgstr "mktime нужен кортеж длины 8 или 9" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q и %q должны быть разными" +#: extmod/modtime.c +msgid "ticks interval overflow" +msgstr "переполнение интервала тиков" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" -msgstr "%q и %q должны иметь общую единицу тактового генератора" +#: extmod/modzlib.c +msgid "compression header" +msgstr "Заголовок сжатия" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" -msgstr "%q не может быть изменен после установки режима на %q" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "Тип данных не понят" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q содержит пины дупликаты" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "массив слишком велик" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" -msgstr "%q сбой: %d" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "Переполнение длины массива ndarray" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" -msgstr "" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "Не удается преобразовать сложный тип" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q в %q должно быть типа %q, а не %q" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "Слишком много измерений" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q используется" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "индекс выходит из границ" -#: py/objstr.c -msgid "%q index out of range" -msgstr "Индекс %q вне диапазона" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "индексы должны быть целыми числами, срезами или логическими списками" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "Индексы %q должны быть целыми числами, а не %s" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "Операнды не могут транслироваться вместе" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: ports/stm/common-hal/audioio/AudioOut.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c -msgid "%q init failed" -msgstr "Инициализация %q не удалась" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "Длина массива и индекса должна быть равна" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q является %q" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "не может превратить комплекс в dtype" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q читается только для этой доски" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "операция реализована только для 1D логических массивов" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "Длинна %q должна быть %d" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "Слишком много индексов" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "Длинна %q должна быть %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "Не удается удалить элементы массива" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "Длинна %q должна быть <= %d" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "порядок сглаживания должен быть либо 'C', либо 'F'" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "Длинна %q должна быть >= %d" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "Тобайты могут быть вызваны только для плотных массивов" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q должно быть %d" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "Операция не поддерживается для данного типа" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c -#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q должно быть %d-%d" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "фигура должна быть целым числом или кортежом целых чисел" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q должен быть равен 1, если %q имеет значение True" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "Максимальное количество измерений составляет " -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 16, 24, or 32" -msgstr "" - -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 8 or 16" -msgstr "" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "Можно указать только одно неизвестное измерение" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q must be 8, 16, 24, or 32" -msgstr "" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "Не удается изменить форму массива" -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "%q должно быть <= %d" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "Не удается назначить новую фигуру" -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "%q должно быть <= %u" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "Функция определяется только для массивов ndarrays" -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "%q должно быть >= %d" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "операция не поддерживается для типов ввода" -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q должен быть массивом байтов или массивом типа «H» или «B»" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "dtype int32 не поддерживается" -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q должен быть массивом байтов или массивом типа «h», «H», «b» или «B»" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "Не удается привести выходные данные с помощью правила приведения" -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "%q должен быть подклассом %q" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "Результаты не могут быть приведены к указанному типу" -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "%q должен быть массивом типа 'H \"" +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "interp определен для 1D-итераций одинаковой длины" -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "%q должен быть массивом типа 'h \"" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "ловушка определена для одномерных 1D итераций" -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." -msgstr "%q должно быть кратно 8." +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "ловушка определена для одномерных 1D массивов одинаковой длины" -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q должно быть типа%q или%q, а не%q" +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "Не поддерживается для типов ввода" -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" -msgstr "%q должен иметь тип %q, %q или %q, а не %q" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "Функция реализована только для массивов ndarrays" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q должно быть типа %q, а не %q" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "Ввод должен быть массивом ndarray или скаляр" -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q должен быть во 2-й степени" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "Ввод должен быть 1D массивом ndarray" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" -msgstr "" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "не реализовано для сложного типа d" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" -msgstr "" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "Неправильный тип ввода" -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "%q за пределом" +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" +msgstr "Входной аргумент должен быть целым числом, кортежом или списком" -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "%q вне диапазона" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "неправильное количество аргументов" -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "Шаг %q не может быть нулём" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "Делим на ноль" -#: shared-module/bitbangio/I2C.c -msgid "%q too long" -msgstr "%q слишком долго" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" +msgstr "arange: не удается вычислить длину" -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q() принимает %d позиционных аргументов, но было передано %d" +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "Первый аргумент должен быть кортежом массива ndarrays" -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" -msgstr "%q() без %q()" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "только массивы ndarrays могут быть объединены" -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q, и %q должны быть одной длинны" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "Указана неправильная ось" -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "Входные массивы несовместимы" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "%q [%u] смещается в большем количестве чем количество пинов" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "Вход должен быть 1- или 2-D" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "%q[%u] смещает больше битов чем количество выводов" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "Количество баллов должно быть не менее 2" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "%q[%u] использует дополнительный контакт" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "Смещение должно быть неотрицательным и не превышать длину буфера" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "%q [%u] ожидает ввода за пределами графа" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "Размер буфера должен быть кратен размеру элемента" -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "%s ошибка 0x%x" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" +msgstr "Размер буфера меньше запрошенного" -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "Требуется аргумент '%q'" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "FFT определено только для массивов ndarrays" -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" -msgstr "Объект '%q' не поддерживает '%q'" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "FFT реализовано только для линейных массивов" -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "Объект '%q' не является итератором" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "Длина входного массива должна быть равна степени 2" -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" -msgstr "" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "реальные и воображаемые части должны быть одинаковой длины" -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "Объект '%q' не является итерируемым" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "переплетение аргументов должно быть массивами ndarrays" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' ожидает метку" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "Аргументы свертки должны быть линейными массивами" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' ожидает регистр" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "аргументы свертки не должны быть пустыми" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' ожидает специальный регистр" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" +msgstr "Поврежденный файл" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' ожидает регистр FPU" +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "Неправильный тип" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s' ожидает адрес в формате [a, b]" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "Ключевое слово usecols должно быть указано" -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' ожидает целое число" +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" +msgstr "пустой файл" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s' ожидает не более r%d" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "Usecols слишком высок" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' ожидает {r0, r1, ...}" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "Массив имеет слишком много измерений" -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' целое число %d не находится в пределах диапазона %d..%d" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "Входная матрица асимметрична" -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' целое число 0x%x не помещается в маску 0x%x" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "матрица не является положительно определенной" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "Объект '%s' не поддерживает присвоение элементов" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "итерации не сходятся" -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "Объект '%s' не поддерживает удаление элементов" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "Входная матрица является сингулярной" -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "Объект '%s' не имеет атрибута '%q'" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" +msgstr "операция определена только для массивов ndarrays" -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "Объект '%s' не может быть подписан" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" +msgstr "операция определена только для 2D-массивов" -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "Выравнивание '=' недопустимо в спецификаторе формата строки" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" +msgstr "Режим должен быть завершенным или уменьшенным" -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' и 'O' не являются поддерживаемыми типами форматов" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" +"Попытка получить аргумент минимальный/аргумент максимальный пустой " +"последовательности" -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "«выравнивание» требует 1 аргумента" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" +msgstr "" +"Попытка получить (аргумент)минимальный/(аргумент)максимальный пустой " +"последовательности" -#: py/compile.c -msgid "'await' outside function" -msgstr "«ожидание» внешняя функция" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" +msgstr "ось должна быть None или целым числом" -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "'прервать'/'продолжить' вне цикла" +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" +msgstr "операция не реализована на массивах ndarrays" -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "«данные» требуют как минимум 2 аргумента" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "Ввод должен быть кортеж, список, диапазон или массивом ndarray" -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "«данные» требуют целочисленных аргументов" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "аргумент сортировки должен быть массивом ndarray" -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "«метка» требует 1 аргумент" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "аргумент сортировки должен быть аргументом массива ndarray" -#: py/emitnative.c -msgid "'not' not implemented" -msgstr "'не' не реализовано" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "сортировка arg не реализована для сглаженных массивов" -#: py/compile.c -msgid "'return' outside function" -msgstr "«возврат» внешняя функция" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" +msgstr "Слишком длинная ось" -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "«выход из» внутри асинхронной функции" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" +msgstr "Аргументы должны быть массивами ndarrays" -#: py/compile.c -msgid "'yield' outside function" -msgstr "внешняя функция \"выход\"" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" +msgstr "крест определяется для 1D массивов длины 3" -#: py/compile.c -msgid "* arg after **" -msgstr "* аргумент после **" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" +msgstr "аргумент DIFF должен быть массивом ndarray" -#: py/compile.c -msgid "*x must be assignment target" -msgstr "*x должно быть целью назначения" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" +msgstr "индекс вне диапазона" -#: py/obj.c -msgid ", in %q\n" -msgstr ", в %q\n" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" +msgstr "Порядок дифференциации вне диапазона" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" -msgstr ". Показать(x) удален. Используйте . корневую_группу = x" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "Флип -аргумент должен быть массивом ndarray" -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "0.0 в комплексную степень" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "Неправильный индекс оси" -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "Pow() с 3 аргументами не поддерживается" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" +msgstr "Средний аргумент должен быть массивом ndarray" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "AP не может быть запущен" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" +msgstr "аргумент roll должен быть массивом ndarray" -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "Адрес должен быть длиной %d байт" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" +msgstr "Входные данные должны быть итерируемыми" -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "Диапазон адресов не разрешен" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" +msgstr "Больше степеней свободы чем точек данных" -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "Обертывание диапазона адресов" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" +msgstr "Входные векторы должны быть одинаковой длины" -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "Все периферийные устройства CAN уже используются" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" +msgstr "не удалось инвертировать матрицу Вандермонда" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "Все периферийные устройства I2C уже используются" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" +msgstr "Ввод не является итерируемым" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "Все RX FIFO уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "аргумент должен быть None, целым числом или кортежем целых чисел" -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "Все периферийные устройства SPI уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" +msgstr "форма должна быть None, целым числом или кортежем целых чисел" -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "Все периферийные устройства UART уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" +msgstr "out имеет неправильный тип" -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "Все каналы уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" +msgstr "Выходной массив имеет неправильный тип" -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "Все используемые каналы dma" +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "Размер должен соответствовать out.shape при совместном использовании" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "Все каналы событий уже используются" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "выходной массив должен быть непрерывным" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "Все машины состояний уже используются" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" +msgstr "неправильная длина массива состояния" -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" -msgstr "Все каналы событий синхронизации уже используются" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "Первым аргументом должен быть массивом ndarray" -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "Все таймеры для этого пина уже используются" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" +msgstr "Неправильный тип индекса" -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "Все таймеры уже используются" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" +msgstr "неправильная длина массива индексов" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "Уже реклама." +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "Размеры не совпадают" -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "Уже есть универсальный слушатель" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" +msgstr "out должен быть массивом ndarray" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" -msgstr "Уже в процессе" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" +msgstr "Выход должен быть поплавкового типа" -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "Уже запущен" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "Входные и выходные размеры различаются" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "Поиск сетей wifi уже происходит" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" +msgstr "Входные и выходные формы различаются" -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "Произошла ошибка при получении '%s':\n" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "ключевое слово не поддерживается для функции" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "Другой аудиовыход PWM уже активен" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" +msgstr "Ключевое слово out не поддерживается для сложного типа d" -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "Другая передача уже активна" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" +msgstr "Тип d должен быть плавающим или сложным" -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "Массив должен содержать полуслова (тип 'H')" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "Не может преобразовать сложный в плавающий" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "Значения массива должны быть однобайтовыми." +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" +msgstr "Входной тип dtype должен быть плавающим или сложным" -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "Первый аргумент должен быть вызываемым" -#: shared-bindings/usb_audio/__init__.c -msgid "At least one of microphone and speaker must be enabled" -msgstr "" +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" +msgstr "неверный тип вывода" -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "Попытка выделения %d блоков" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "Первые два аргумента должны быть массивами ndarrays" -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "Преобразование звука не реализовано" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "Ввод должен быть плотным массивом ndarray" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Audio source error" -msgstr "" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "первый аргумент должен быть функцией" -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "Режим авторизации.OPEN не используется с паролем" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "функция имеет один и тот же знак в конце интервала" -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "Ошибка аутентификации" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "макситер должен быть > 0" -#: main.c -msgid "Auto-reload is off.\n" -msgstr "Автоматическая перезагрузка отключена.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "maxiter должен быть > 0" -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" -msgstr "" -"Автоматическая перезагрузка включена. Просто сохрани файл по USB или зайди в " -"REPL чтобы отключить.\n" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "Данные должны быть итерируемыми" -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "Скорость передачи данных не поддерживается периферийным устройством" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "Начальные значения должны быть итерируемыми" -#: ports/zephyr-cp/common-hal/zephyr_display/Display.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "Ниже минимальной частоты кадров" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "Данные должны быть одинаковой длины" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "Несколько часов и слов должны быть последовательными GPIO пинами" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "sosфильтр требует повторяющихся аргументов" -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "" -"Размер растрового изображения и число битов на значение должны совпадать" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "Входные данные должны быть одномерными" -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "Загрузочное устройство должно быть первым (интерфейс #0)." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "зи, должно быть, массивом ndarray" -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "Для управления потоком требуется как RX так и TX" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "zi должен иметь форму (n_section, 2)" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "Яркость не регулируется" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" +msgstr "zi должно быть типа float" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "Элементы буфера должны иметь длину не более 4 байт" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" +msgstr "Массив sos должен иметь форму (n_section, 6)" -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "Буфер не является байтовым массивом." +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "sos[:, 3] должны быть все единицы" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "Размер буфера %d слишком большой. Он должен быть меньше чем %d" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "Ось выходит за пределы" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" -msgstr "Буфер должен быть кратен %d байт" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "размер определен только для массива ndarrays" -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "Буфер слишком короткий на %d байт" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "Входные данные должны быть квадратной матрицей" -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "Слишком маленький буфер" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" +msgstr "Ввод должен быть массивом ndarray" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Вывод шины %d уже используется" +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" +msgstr "Out должен быть плотным массивом с плавающей запятой" -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "Блоки CBC должны быть кратны 16 байтам" +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" +msgstr "Смещение слишком большое" -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "Диск CIRCUTPY не удалось найти или создать." +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" +msgstr "Наш массив слишком мал" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC или контрольная сумма неправильная" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" +msgstr "Файловая система только для чтения" -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "Вызовите super().__init__() перед доступом к собственному объекту." +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "Операция ввода-вывода на закрытом файле" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "Иницализация камеры" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" +msgstr "Опрос в файле недоступен в Win32" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "Возможен только сигнал тревоги по RTC IO из глубокого сна." +#: main.c +msgid "Done" +msgstr "Выполнено" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." -msgstr "" -"Может сигнализировать только по одному низкому контакту в то время как " -"другие сигнализируют о высоком уровне после глубокого сна." +#: main.c +msgid " output:\n" +msgstr " вывод:\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" msgstr "" -"Из глубокого сна может сигнализировать только по двум низким контактам." +"Автоматическая перезагрузка включена. Просто сохрани файл по USB или зайди в " +"REPL чтобы отключить.\n" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" -msgstr "" +#: main.c +msgid "Auto-reload is off.\n" +msgstr "Автоматическая перезагрузка отключена.\n" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "Невозможно установить CCCD для локальной характеристики" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "Работает в безопасном режиме! Сохраненный код не выполняется.\n" -#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c -#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c -#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "Невозможно изменить USB устройство сейчас" +#: main.c +msgid " not found.\n" +msgstr " не найден.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "Невозможно создать новый Adapter; используйте _bleio.adapter;" +#: main.c +msgid "WARNING: Your code filename has two extensions\n" +msgstr "ВНИМАНИЕ: Имя файла кода имеет два расширения\n" -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" +"\n" +"Программа остановлена автоматической перезагрузкой. Скоро перезагрузка.\n" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "Невозможно удалить значения" +#: main.c +msgid "" +"\n" +"Code done running.\n" +msgstr "" +"\n" +"Программа закончила выполнение.\n" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "Невозможно получить pull в режиме вывода" +#: main.c +msgid "Woken up by alarm.\n" +msgstr "Проснулся по тревоге.\n" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "Невозможно получить температуру" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +msgstr "" +"Нажмите любую клавишу чтобы зайти в REPL. Используйте CTRL-D для " +"перезагрузки.\n" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot have scan responses for extended, connectable advertisements." +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" msgstr "" -"Не может быть ответов на сканирование для расширенных подключаемых рекламных " -"объявлений." +"Притворяюсь глубоким сном до сигнала тревоги, CTRL-C или записи файла.\n" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "Невозможно вытащить контакт только для ввода." +#: main.c +msgid "UID:" +msgstr "UID:" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Cannot record to a file" -msgstr "Невозможно записать в файл" +#: main.c +msgid "soft reboot\n" +msgstr "Мягкая перезагрузка\n" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" +msgstr "Инициализация %q не удалась" + +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." -msgstr "Невозможно установить значение при вводе направления." +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "%q вне диапазона" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "Невозможно указать RTS или CTS в режиме RS485" +#: ports/analog/common-hal/busio/SPI.c +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid state" +msgstr "Неверное состояние" -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "Невозможно создать подкласс среза" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "Невозможно использовать GPIO0..15 вместе с GPIO32..47" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -"Невозможно проснуться по изменению логического уровня, только по уровню" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." -msgstr "Невозможно проснуться по спаду росту на пине. Только по уровню." -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "ХарактеристикаЗапись в буфер не предусмотрена" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "Для управления потоком требуется как RX так и TX" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "Основной код CircuitPython сильно разбился. Упс!\n" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" +msgstr "Не удалось выделить буфер %q" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "Источник тактирования уже используется" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" +msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -"Соединение было отключено и больше не может использоваться. Создайте новое " -"соединение." -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "Координатные массивы имеют разные длины" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "Все периферийные устройства UART уже используются" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" -msgstr "Типы массивов координат имеют разные размеры" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "Недопустимый %q" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" -msgstr "" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "Все каналы событий синхронизации уже используются" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "Не удалось задать адрес" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "Внутренний звуковой буфер слишком мал" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "Не удалось запустить прерывание, RX занят" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" +msgstr "Калибровка доступна только для чтения" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "Не удалось выделить место для декодера" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" +msgstr "Калибровка выходит за пределы допустимого диапазона" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" -msgstr "" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." +msgstr "Вы нажали обе кнопки при запуске." -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Channel Init Error" -msgstr "Ошибка инициализации канала DAC" +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "Все таймеры уже используются" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Device Init Error" -msgstr "Ошибка инициализации устройства DAC" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" +msgstr "Используемые внутренние ресурсы" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC уже используется" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." +msgstr "Причина неизвестна." -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "Пин data 0 должен быть байтово выровнен" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" +msgstr "Можно установить только один будильник" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" -msgstr "Ошибка формата данных (возможно, данные повреждены)" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" +msgstr "DAC отсутствует на чипе" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "Данные не поддерживаются направленным объявлением" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" +msgstr "%q и %q должны иметь общую единицу тактового генератора" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "Данные слишком велики для пакета объявления" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" +msgstr "Сериализатор используется" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" -msgstr "" -"Выводы глубокого сна должны использовать сигнал по возрастанию с подтяжкой к " -"земле" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "Источник тактирования уже используется" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "Емкость места назначения меньше длины места назначения." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" +msgstr "Свободные GCLK отсутствуют" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" -msgstr "Ошибка устройства или неправильное завершение входного потока" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" +msgstr "Слишком много каналов в выборке" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "Устройство используется" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" +msgstr "Канал DMA не найден" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "Дисплей должен иметь 16 битное цветовое пространство." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" +msgstr "Не удается выделить буферы для подписанного преобразования" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" -msgstr "Поворот дисплея должен осуществляться с шагом 90 градусов" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +#, c-format +msgid "Only 8 or 16 bit mono with %dx oversampling supported." +msgstr "Поддерживается только 8 или 16-битное моно с передискретизацией %dx." -#: main.c -msgid "Done" -msgstr "Выполнено" +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" +msgstr "Частота дискретизации выходит за пределы допустимого диапазона" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." -msgstr "Режим движения не используется при вводе направления." +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC уже используется" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "" -"При обращении с вышеуказанным исключением произошло еще одно исключение:" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" +msgstr "Правый канал не поддерживается" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB работает только с 16 байтами за раз" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "Все каналы событий уже используются" -#: py/asmxtensa.c -msgid "ERROR: %q %q not word-aligned" -msgstr "" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" +msgstr "На SDA или SCL не обнаружено подтягивания; проверь свою проводку" -#: py/asmxtensa.c -msgid "ERROR: xtensa %q out of range" -msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q должен быть во 2-й степени" +#: ports/atmel-samd/common-hal/busio/UART.c #: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" -msgstr "Ошибка выделения памяти ESP-IDF" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c +#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c +#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c +#: shared-bindings/paralleldisplaybus/ParallelBus.c +#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c +msgid "No %q pin" +msgstr "Нет пина %q" -#: extmod/modre.c -msgid "Error in regex" -msgstr "Ошибка в регулярном выражении" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "Все RX FIFO уже используются" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." -msgstr "Ошибка в сейфе. py." - -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" -msgstr "Ожидаемый вид %q" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." -msgstr "Расширенные объявления с ответом сканирования не поддерживаются." +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "Уже есть универсальный слушатель" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "FFT определено только для массивов ndarrays" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" +msgstr "Фильтры слишком сложные" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "FFT реализовано только для линейных массивов" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "Невозможно получить pull в режиме вывода" -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "Не удалось отправить команду." +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "Invalid data_pins[%d]" +msgstr "Неверный data_pins[%d]" -#: ports/nordic/sd_mutex.c +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "Не удалось получить mutex, ошибка 0x%04x" +msgid "data pin #%d in use" +msgstr "data-пин #%d уже используется" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" -msgstr "Не удалось добавить служебную запись TXT" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "Недопустимый пин %q" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" -msgstr "" -"Не удалось добавить служебную TXT-запись; в txt_records обнаружена нестрока " -"или байт" +#: ports/atmel-samd/common-hal/microcontroller/__init__.c +#: ports/cxd56/common-hal/microcontroller/__init__.c +#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c +msgid "No bootloader present" +msgstr "Отсутствует загрузчик" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" -msgstr "Не удалось выделить буфер %q" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "Пин data 0 должен быть байтово выровнен" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" -msgstr "Не удалось выделить память Wifi" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Вывод шины %d уже используется" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" -msgstr "Не удалось выделить память для сканирования wifi" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "Всплывающее окно из пустого %q" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" -msgstr "Не удалось выполнить буферизацию образца" +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "Ввод занимает слишком много времени" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "Не удалось подключиться: внутренняя ошибка" +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "Другая передача уже активна" -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "Не удалось подключиться: таймаут" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" +msgstr "%q сбой: %d" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" -msgstr "" +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" +msgstr "Буфер должен быть кратен %d байт" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" -msgstr "" +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" +msgstr "Инициализация UART" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "Иницализация камеры" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "Размер не поддерживается" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "Не удалось распарсить файл MP3" +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "Слишком маленький буфер" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" -msgstr "" +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "Формат не поддерживается" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "Не удалось освободить mutex, ошибка 0x%04x" +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "Инициализация GNSS" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" -msgstr "" +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" +msgstr "Инициализация SD-карты" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" -msgstr "" +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "Уже запущен" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" -msgstr "" +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q является %q" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "Не удалось записать внутреннюю флэш-память." +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "Вы нажали кнопку SW38 при запуске." -#: py/moderrno.c -msgid "File exists" -msgstr "Файл существует" +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "При запуске вы нажали кнопку BOOT." -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" -msgstr "Файл не найден" +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "Вы нажали кнопку GPIO0 при запуске." -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" -msgstr "Фильтры слишком сложные" +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "Вы нажали кнопку «Запись» при запуске." -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" -msgstr "Прошивка дублируется" +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "Вы нажали кнопку ГРОМКОСТЬ при запуске." -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "Недопустимая прошивка" +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "Вы нажали центральную кнопку при запуске." -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "Прошивка слишком большая" +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." +msgstr "Вы нажали кнопку A при запуске." -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" -msgstr "" -"Для цветового пространства L8 входное растровое изображение должно иметь 8 " -"бит на пиксель" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." +msgstr "Вы нажали кнопку ВНИЗ при запуске." -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" -msgstr "" -"Для цветовых пространств RGB входное растровое изображение должно иметь 16 " -"бит на пиксель" - -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "Формат не поддерживается" - -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" -msgstr "" -"Частота должна быть 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 или 1008 " -"МГц" - -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Функция требует блокировки" - -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "Инициализация GNSS" - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" -msgstr "Общий сбой" - -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "Группа уже используется" - -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." -msgstr "Жесткая ошибка: доступ к памяти или ошибка инструкции." - -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "Оборудование используется, попробуйте использовать другие пины" - -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." -msgstr "Выделение кучи, когда виртуальная машина не запущена." - -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "Операция ввода-вывода на закрытом файле" - -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "Ошибка инициализации I2C" - -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "Периферийное устройство I2C уже используется" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "Элементы буфера должны быть длиной <= 4 байта" - -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "Неправильный размер буфера" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "Неверный размер программы инициализации" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "" -"Исходное установленное направление штифта конфликтует с исходным " -"направлением вывода" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "" -"Исходное установленное состояние контакта конфликтует с исходным состоянием " -"выхода" - -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "Длина входного буфера (%d) должна быть кратна количеству цепочек (%d)" - -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "Ввод занимает слишком много времени" - -#: py/moderrno.c -msgid "Input/output error" -msgstr "Ошибка ввода/вывода" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" -msgstr "Неполная аутентификация" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "Недостаточное шифрование" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" +msgstr "Обновление не удалось" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" -msgstr "Недостаточный объем памяти для изображения" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." +msgstr "Сканирование уже выполняется. Остановитесь на stop_scan." -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" -msgstr "Недостаточный буфер ввода потока" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "Не удалось подключиться: внутренняя ошибка" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "Интерфейс должен быть запущен" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "Данные слишком велики для пакета объявления" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "Внутренний звуковой буфер слишком мал" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "Уже реклама." -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "Внутренняя ошибка определения" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." +msgstr "Расширенные объявления с ответом сканирования не поддерживаются." -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c -#: supervisor/shared/settings.c -msgid "Internal error" -msgstr "Внутренняя ошибка" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "Данные не поддерживаются направленным объявлением" -#: shared-module/rgbmatrix/RGBMatrix.c +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c #, c-format -msgid "Internal error #%d" -msgstr "Внутренняя ошибка #%d" - -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" -msgstr "Используемые внутренние ресурсы" - -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "Внутренний сторожевой таймер истек." - -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." -msgstr "Прерванная ошибка." - -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" -msgstr "Прерывается функцией выхода" - -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/espressif/common-hal/mipidsi/Display.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c -#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "Недопустимый %q" - -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" -msgstr "Недопустимые %q и %q" - -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "Недопустимый пин %q" - -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "Недопустимое значение единицы ADC" - -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "Недопустимый параметр BLE" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "Неверный BSSID" - -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "Неверный MAC-адрес" - -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" -msgstr "" - -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" -msgstr "" +msgid "Timeout is too long: Maximum timeout length is %d seconds" +msgstr "Таймаут слишком длинный: максимальная длина таймаута %d секунд" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "Недопустимый аргумент" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" +msgstr "Защита от MITM не поддерживается" -#: shared-module/displayio/Bitmap.c -msgid "Invalid bits per value" -msgstr "Недопустимое бит-на-значение" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" +msgstr "Длина значения! = требуемая фиксированная длина" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "Неверный data_pins[%d]" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" +msgstr "Длина значения > максимальная_длина" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "Недопустимый формат" +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" +msgstr "Слишком много дескрипторов" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "Неверный размер блока формата" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" +msgstr "Для этой характеристики нет CCCD" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" -msgstr "Неверный шестнадцатеричный пароль" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "Невозможно установить CCCD для локальной характеристики" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "Неверный MAC-адрес многоадресной рассылки" +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" +msgstr "не-UUID найден в сервисе_uuids_белый список" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "Неверный размер" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" +msgstr "максимальная_длина должна быть 0-%d когда фиксированная длина %s" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "Неверный сокет для TLS" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" +msgstr "Запись не поддерживается в Характеристика" -#: ports/analog/common-hal/busio/SPI.c -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid state" -msgstr "Неверное состояние" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" +msgstr "Общее количество данных для записи превышает %q" -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" -msgstr "Недопустимое экранирование Юникода" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" +msgstr "Изображение памяти" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "Ключ должен быть длинной 16, 24 или 32 байта" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "Недопустимый параметр BLE" -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "Светодиодные сопоставления должны соответствовать размеру дисплея" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "Not connected" +msgstr "Не подключено" -#: py/compile.c -msgid "LHS of keyword arg must be an id" -msgstr "LHS ключевого слова arg должен быть идентификатором(id)" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" +msgstr "Уже в процессе" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "Слой уже в группе (Group)" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" +msgstr "Неизвестная системная ошибка прошивки на %s:%d: %d" -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "Слой должен быть группой (Group) или субклассом TileGrid" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %d" +msgstr "Неизвестная ошибка прошивки системы: %d" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" -msgstr "Длина %q должна быть четной, кратной количеству каналов * размер_типа" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" +msgstr "Неполная аутентификация" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "MAC адрес был недействительным" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" +msgstr "Недостаточное шифрование" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" -msgstr "Защита от MITM не поддерживается" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" +msgstr "Неизвестная ошибка BLE в %s:%d: %d" -#: ports/stm/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/_bleio/__init__.c #, c-format -msgid "MMC/SDIO Clock Error %x" -msgstr "" +msgid "Unknown BLE error: %d" +msgstr "Неизвестная ошибка BLE: %d" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "Сопоставление должно быть кортежом" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." +msgstr "Невозможно проснуться по спаду росту на пине. Только по уровню." -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap must have 8 bits per pixel" -msgstr "" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "Невозможно вытащить контакт только для ввода." -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap size must match the other bitmaps" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." msgstr "" +"Из глубокого сна может сигнализировать только по двум низким контактам." -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" +"Может сигнализировать только по одному низкому контакту в то время как " +"другие сигнализируют о высоком уровне после глубокого сна." -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "Размер данных различается" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" -msgstr "Несоответствующий флаг подкачки" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "Возможен только сигнал тревоги по RTC IO из глубокого сна." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" -msgstr "Отсутствует first_in_pin. %q[%u] читает выводы" +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." +msgstr "Можно установить только один будильник alarm.time." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" -msgstr "Отсутствует first_in_pin. %q[%u] смещается от контакта (контактов)" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." +msgstr "Только один %q может быть переведен в режим глубокого сна." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" -msgstr "Отсутствует first_in_pin. Инструкция %d ожидает на основе пина" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "%q должен быть массивом типа 'H \"" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" -msgstr "Отсутствует first_out_pin. %q[%u] переключается на контакты" +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" -msgstr "Отсутствует first_out_pin. %q[%u] записывает выводы" +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +msgid "Peripheral in use" +msgstr "Периферийные устройства в использовании" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" -msgstr "Отсутствует first_set_pin. %q[%u] устанавливает контакты" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" -msgstr "Не хватает jmp_pin.%q [%u] прыгает на пин" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" +msgstr "" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" -msgstr "Отсутствует каталог точки монтирования" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" +msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." -msgstr "Должен быть субклассом %q." +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" +msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" -msgstr "Должен иметь 5/6/5 контактов RGB" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" +msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" -msgstr "Пин MISO или MOSI должен быть предоставлен" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" +msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" -msgstr "Количество используемых rgb-пинов должно быть кратно 6, а не %d" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." -msgstr "Прыжок NLR не удался. Вероятно повреждение памяти." +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" +msgstr "" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "Ошибка NVS" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" +msgstr "" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" -msgstr "Имя или услуга не известны" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -"Новое растровое изображение должно быть того же размера, что и старое " -"растровое изображение" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" -msgstr "Изображение памяти" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "Все периферийные устройства I2C уже используются" + +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" +msgstr "Не удается создать блокировку" + +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" +msgstr "Сбой конфигурации SPI" + +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "Все периферийные устройства SPI уже используются" -#: ports/atmel-samd/common-hal/busio/UART.c #: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "ESP-IDF memory allocation failed" +msgstr "Ошибка выделения памяти ESP-IDF" + #: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/SPI.c #: ports/mimxrt10xx/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -#: ports/raspberrypi/common-hal/busio/UART.c ports/stm/common-hal/busio/SPI.c -#: ports/stm/common-hal/busio/UART.c shared-bindings/fourwire/FourWire.c -#: shared-bindings/i2cdisplaybus/I2CDisplayBus.c -#: shared-bindings/paralleldisplaybus/ParallelBus.c -#: shared-bindings/qspibus/QSPIBus.c shared-module/bitbangio/SPI.c -msgid "No %q pin" -msgstr "Нет пина %q" +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "Невозможно указать RTS или CTS в режиме RS485" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "Для этой характеристики нет CCCD" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" +msgstr "Инверсия RS485 указана, когда она не находится в режиме RS485" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "No DAC on chip" -msgstr "DAC отсутствует на чипе" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "Скорость передачи данных не поддерживается периферийным устройством" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "No DMA channel found" -msgstr "Канал DMA не найден" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "Все периферийные устройства CAN уже используются" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" -msgstr "Таймер стимуляции DMA не найден" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" +msgstr "" +"Замыкание на себя + бесшумный режим, не поддерживаемый периферийными " +"устройствами" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#: ports/espressif/common-hal/canio/CAN.c #, c-format -msgid "No I2C device at address: 0x%x" -msgstr "Нет устройства I2C по адресу: %x" +msgid "twai_driver_install returned esp-idf error #%d" +msgstr "twai_driver_install вернул ошибку esp-idf #%d" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "Нет IP" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" +msgstr "twai_start вернул ошибку esp-idf #%d" -#: ports/atmel-samd/common-hal/microcontroller/__init__.c -#: ports/cxd56/common-hal/microcontroller/__init__.c -#: ports/mimxrt10xx/common-hal/microcontroller/__init__.c -msgid "No bootloader present" -msgstr "Отсутствует загрузчик" +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" +msgstr "Должен иметь 5/6/5 контактов RGB" -#: shared-module/usb/core/Device.c -msgid "No configuration set" -msgstr "Нет конфигураций" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" +msgstr "Прошивка дублируется" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" -msgstr "Нет соединения: длина не может быть определена" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "Недопустимая прошивка" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" -msgstr "Нет шины %q по умолчанию" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "Прошивка слишком большая" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" -msgstr "Свободные GCLK отсутствуют" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" +msgstr "нет такого атрибута" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" -msgstr "Отсутствует аппаратный генератор случайных чисел" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" +msgstr "Недопустимый параметр" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" -msgstr "Нет в программе" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" +msgstr "Общий сбой" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" -msgstr "В программе отсутствует ввод или вывод" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" +msgstr "Не хватает памяти" -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" -msgstr "Нет поддержки длинных целых чисел (long integer)" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "Недопустимый аргумент" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "Нет сети с этим ssid" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "Неверный размер" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" -msgstr "В программе отсутствует вывод" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" +msgstr "Запрошенный ресурс не найден" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" -msgstr "На SDA или SCL не обнаружено подтягивания; проверь свою проводку" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" +msgstr "Операция или функция, не поддерживаемые" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" -msgstr "Отсутствует подтяжка к земле на пине; Рекомендуется 1 Мегаом" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" +msgstr "Истекло время ожидания операции" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" +msgstr "Полученный ответ недействителен" -#: py/moderrno.c -msgid "No space left on device" -msgstr "На устройстве не осталось свободного места" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC или контрольная сумма неправильная" -#: py/moderrno.c -msgid "No such device" -msgstr "Нет такого устройства" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" +msgstr "Версия была недействительной" -#: py/moderrno.c -msgid "No such file/directory" -msgstr "Файл/директория не существует" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "MAC адрес был недействительным" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" -msgstr "Нет доступного таймера" +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" +msgstr "%s ошибка 0x%x" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" -msgstr "Порт USB-хоста не инициализирован" +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" +msgstr "Слишком длинная программа" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" -msgstr "Скандинавская система прошивки из памяти" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q используется" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" -msgstr "Недействительная строка IP" +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." +msgstr "Можно установить только один %q." -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "Not connected" -msgstr "Не подключено" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" +msgstr "Разрешен только один адрес" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "Not playing" -msgstr "Не воспроизводится (Not playing)" +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" +msgstr "Неизвестный код ошибки %d" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" +msgstr "mDNS работает только со встроенным WiFi" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" +msgstr "mDNS уже инициализирован" + +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" +msgstr "Не удается запустить запрос mDNS" + +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" +msgstr "Диапазон адресов не разрешен" + +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "Ошибка NVS" #: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c #: ports/espressif/common-hal/sdioio/SDCard.c @@ -1748,808 +1583,845 @@ msgstr "Не воспроизводится (Not playing)" msgid "Number of data_pins must be %d or %d, not %d" msgstr "Количество выводов_данных должно быть %d или %d, а не %d" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." -msgstr "" -"Объект был деинициализирован и больше не может быть использован. Создайте " -"новый объект." - -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" -msgstr "Нечетная четность не поддерживается" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" +msgstr "вытолкнуть из пустого импульсного входа" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" -msgstr "Выключено" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" -msgstr "Да" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "Внутренняя ошибка" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." -msgstr "Поддерживается только 8 или 16-битное моно с передискретизацией %dx." +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" +msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" -msgstr "Поддерживаются только адреса IPv4" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" +msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" -msgstr "Поддерживаются только сокеты IPv4" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "" -#: shared-module/displayio/OnDiskBitmap.c +#: ports/espressif/common-hal/rclcpy/__init__.c #, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" -"Поддерживается только формат Windows, несжатый BMP: заданный размер " -"заголовка - %d" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" -msgstr "Только подключаемые объявления могут быть направлены" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS memory allocator failure" +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" -msgstr "На этом аппаратном обеспечении доступно только обнаружение края" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS internal setup failure" +msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" -msgstr "Для IP поддерживаются только int или строка" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "Invalid ROS domain ID" +msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." -msgstr "Только один %q может быть переведен в режим глубокого сна." +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" +msgstr "" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." -msgstr "Можно установить только один %q." +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" +msgstr "" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" -msgstr "Разрешен только один адрес" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" +msgstr "Неподдерживаемый тип сокета" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" -msgstr "Можно установить только один будильник" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" +msgstr "Вне розеток" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." -msgstr "Можно установить только один будильник alarm.time." +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" +msgstr "SocketPool можно использовать только с wifi.radio" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" -msgstr "Только один цвет может быть прозрачным одновременно" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "%q должно быть <= %u" -#: py/moderrno.c -msgid "Operation not permitted" -msgstr "Операция не разрешена" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" +msgstr "Сбой инициализации монитора" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" -msgstr "Операция или функция, не поддерживаемые" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "Интерфейс должен быть запущен" -#: ports/espressif/common-hal/espidf/__init__.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Operation timed out" -msgstr "Истекло время ожидания операции" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "Неверный MAC-адрес многоадресной рассылки" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "Отсутствуют сервисные слоты MDNS" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "Поиск сетей wifi уже происходит" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" -msgstr "Не хватает памяти" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" +msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" -msgstr "Вне розеток" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" +msgstr "Не удалось выделить память для сканирования wifi" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "Элементы вне буфера должны иметь длину <= 4 байта" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" +msgstr "Не удалось выделить память Wifi" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" -msgstr "PWM перезагрузка" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" +msgstr "Поддерживаются только адреса IPv4" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" -msgstr "PWM уже используется" +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" +msgstr "Пин MISO или MOSI должен быть предоставлен" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" -msgstr "PWM канал среза A уже используется" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" +msgstr "Оборудование используется, попробуйте использовать другие пины" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" -msgstr "Ошибка параметра" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +msgstr "" +"Частота должна быть 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 или 1008 " +"МГц" -#: ports/espressif/common-hal/audiobusio/__init__.c -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -msgid "Peripheral in use" -msgstr "Периферийные устройства в использовании" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." +msgstr "Вы нажали левую кнопку при запуске." -#: py/moderrno.c -msgid "Permission denied" -msgstr "Отказано в разрешении" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" +msgstr "таймаут должен быть < 655.35 сек" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" -msgstr "Пин не может вывести из глубокого сна" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" +msgstr "Ненулевое время ожидания должно быть > 0,01" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" -msgstr "Слишком большое количество пинов" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "Не удалось подключиться: таймаут" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" -msgstr "Прерывание пина уже используется" +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" +msgstr "Неожиданный тип nrfx uuid" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" -msgstr "Пин является только входом" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" +msgstr "Скандинавская система прошивки из памяти" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "Пин должен быть на канале ШИМ B" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error: %04x" +msgstr "Неизвестная системная ошибка прошивки: %04x" -#: shared-bindings/rgbmatrix/RGBMatrix.c +#: ports/nordic/common-hal/_bleio/__init__.c #, c-format +msgid "Unknown gatt error: 0x%04x" +msgstr "Неизвестная ошибка gatt: 0x%04x" + +#: ports/nordic/common-hal/_bleio/__init__.c msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." msgstr "" -"Распиновка использует %d байт на элемент, что превышает идеальное %d байт. " -"Если этого нельзя избежать, передайте конструктору allow_inefficient=True" +"Неуказанная проблема. Возможно, запрос на сопряжение на другом устройстве " +"был отклонен или проигнорирован." -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" -msgstr "Пины должны быть последовательными" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown security error: 0x%04x" +msgstr "Неизвестная ошибка безопасности: 0x%04x" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" -msgstr "Пины должны быть последовательными выводами GPIO" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "" +"Невозможно проснуться по изменению логического уровня, только по уровню" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" -msgstr "Пины должны иметь общий срез PWM" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "Устройство используется" -#: shared-module/usb/core/Device.c -msgid "Pipe error" -msgstr "Ошибка трубопровода" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" +msgstr "только образец_рейт=16000 поддерживается" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "Плюс любые модули в файловой системе\n" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" +msgstr "поддерживается только бит_глубина=16" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" -msgstr "Полигону необходимо как минимум 3 точки" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" +msgstr "ошибка = 0x%08lX" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "" -"Мощность просела. Убедитесь, что вы обеспечиваете достаточную мощность." +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" +msgstr "Нечетная четность не поддерживается" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" -msgstr "Буфер префикса должен находиться в куче" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "Все каналы уже используются" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "Невозможно получить температуру" + +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -"Нажмите любую клавишу чтобы зайти в REPL. Используйте CTRL-D для " -"перезагрузки.\n" +"Сторожевой таймер не может быть деинициализирован, если установлен режим " +"RESET" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -"Притворяюсь глубоким сном до сигнала тревоги, CTRL-C или записи файла.\n" +"Продолжительность таймаута превысила максимальное поддерживаемое значение" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" -msgstr "Программа выполняет IN без загрузки ISR" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" +msgstr "%q не может быть изменен после установки режима на %q" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" -msgstr "Программа выполняет ВЫХОД без загрузки OSR" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "Не удалось получить mutex, ошибка 0x%04x" + +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "Не удалось освободить mutex, ошибка 0x%04x" + +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "Преобразование звука не реализовано" + +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q должно быть типа%q или%q, а не%q" #: ports/raspberrypi/bindings/rp2pio/StateMachine.c msgid "Program size invalid" msgstr "Недопустимый размер программы" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" -msgstr "Слишком длинная программа" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "Неверный размер программы инициализации" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "Элементы буфера должны иметь длину не более 4 байт" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Pull not used when direction is output." -msgstr "Тяга не используется, когда выводится направление." +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" +msgstr "Размер данных различается" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" -msgstr "RISE_AND_FALL недоступен на этом чипе" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" +msgstr "Элементы вне буфера должны иметь длину <= 4 байта" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" -msgstr "RLE-сжатый BMP не поддерживается" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "Элементы буфера должны быть длиной <= 4 байта" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" -msgstr "Ошибка деинициализации генератора случайных чисел" +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" +msgstr "Сенсорные сигналы недоступны" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" -msgstr "Ошибка инициализации RNG" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "Несколько часов и слов должны быть последовательными GPIO пинами" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" -msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." +msgstr "Слишком много каналов в выборке." -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS internal setup failure" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" -msgstr "" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" +msgstr "Пины должны иметь общий срез PWM" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" -msgstr "" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" +msgstr "Таймер стимуляции DMA не найден" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "Периферийное устройство I2C уже используется" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" -msgstr "Инверсия RS485 указана, когда она не находится в режиме RS485" +#: ports/raspberrypi/common-hal/busio/SPI.c +msgid "SPI peripheral in use" +msgstr "Используемое периферийное устройство SPI" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" -msgstr "RTC не поддерживается на этой плате" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" +msgstr "Используемое периферийное устройство UART" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" -msgstr "Ошибка генерации случайных чисел" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" +msgstr "Пин должен быть на канале ШИМ B" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "Только для чтения" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" +msgstr "RISE_AND_FALL недоступен на этом чипе" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" -msgstr "Файловая система только для чтения" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" +msgstr "PWM уже используется" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" -msgstr "Полученный ответ недействителен" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" +msgstr "PWM канал среза A уже используется" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" -msgstr "Повторное соединение" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "Все машины состояний уже используются" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" -msgstr "Слишком раннее обновление" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" +msgstr "таймаут ожидания потока" + +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" +msgstr "таймаут ожидания индексного импульса" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" -msgstr "Запросы на удаленную передачу ограничены 8 байтами" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" +msgstr "Пины должны быть последовательными" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" -msgstr "Запрошенный режим AES не поддерживается" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" +msgstr "Недопустимые %q и %q" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" -msgstr "Запрошенный ресурс не найден" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" +msgstr "Не удалось добавить служебную запись TXT" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" -msgstr "Правый канал не поддерживается" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" +msgstr "Отсутствуют сервисные слоты MDNS" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" -msgstr "Правильный формат, но не поддерживается" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" +msgstr "Невозможно получить доступ к невыровненному регистру ввода-вывода" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" -msgstr "Работает в безопасном режиме! Сохраненный код не выполняется.\n" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" +msgstr "Невозможно записать в постоянную память" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" -msgstr "Формат CSD SD-карты не поддерживается" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "Все таймеры для этого пина уже используются" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" -msgstr "Инициализация SD-карты" +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" +msgstr "Пины должны быть последовательными выводами GPIO" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" -msgstr "Ошибка получения информации о карте SDIO %d" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" +msgstr "Слишком большое количество пинов" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO Init Error %x" -msgstr "Ошибка инициализации SDIO %x" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" +msgstr "Не хватает jmp_pin.%q [%u] прыгает на пин" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" -msgstr "Сбой конфигурации SPI" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" +msgstr "%q[%u] использует дополнительный контакт" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" -msgstr "Ошибка инициализации SPI" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" +msgstr "Отсутствует first_in_pin. Инструкция %d ожидает на основе пина" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" +msgstr "%q [%u] ожидает ввода за пределами графа" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" -msgstr "Используемое периферийное устройство SPI" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +msgstr "Отсутствует first_in_pin. %q[%u] смещается от контакта (контактов)" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" -msgstr "Повторная инициализация SPI" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" +msgstr "%q [%u] смещается в большем количестве чем количество пинов" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" -msgstr "Размеры шкалы необходимо разделить на 3" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +msgstr "Отсутствует first_out_pin. %q[%u] переключается на контакты" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." -msgstr "Сканирование уже выполняется. Остановитесь на stop_scan." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" +msgstr "%q[%u] смещает больше битов чем количество выводов" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" -msgstr "Сериализатор используется" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" +msgstr "Отсутствует first_set_pin. %q[%u] устанавливает контакты" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" -msgstr "Контекст на стороне сервера не может иметь имя хоста" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" +msgstr "Отсутствует first_out_pin. %q[%u] записывает выводы" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "Размер не поддерживается" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" +msgstr "Отсутствует first_in_pin. %q[%u] читает выводы" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." -msgstr "Нарежьте и оцените разную длину." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "Невозможно использовать GPIO0..15 вместе с GPIO32..47" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" -msgstr "Фрагменты не поддерживаются" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" +msgstr "Программа выполняет IN без загрузки ISR" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" -msgstr "SocketPool можно использовать только с wifi.radio" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" +msgstr "Программа выполняет ВЫХОД без загрузки OSR" -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" msgstr "" +"Исходное установленное состояние контакта конфликтует с исходным состоянием " +"выхода" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" -msgstr "Исходный и конечный буферы должны иметь одинаковую длину" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" +msgstr "" +"Исходное установленное направление штифта конфликтует с исходным " +"направлением вывода" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" -msgstr "Укажите точно один из data0 или data_pins" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" +msgstr "Маски вытягивания конфликтуют с масками направления" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." -msgstr "Переполнение стека. Увеличьте размер стека." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" +msgstr "В программе отсутствует вывод" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" -msgstr "Поставьте один из monotonic_time или epoch_time" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" +msgstr "Нет в программе" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" -msgstr "Системная запись должна быть gnss. Спутниковая система" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" +msgstr "В программе отсутствует ввод или вывод" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" -msgstr "Истекло время ожидания считывания температуры" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" +msgstr "Несоответствующий флаг подкачки" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d, not %d" msgstr "" -"Модуль «микроконтроллер» использовался для загрузки в безопасном режиме." -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -"Вышеупомянутое исключение было непосредственной причиной следующего " -"исключения:" - -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" -msgstr "Длина rgb_pins должна быть 6, 12, 18, 24 или 30" -#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c -msgid "The sample's %q does not match" -msgstr "%q образца не совпадает" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" +msgstr "Поддерживаются только сокеты IPv4" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." -msgstr "Неустранимая ошибка прошивки стороннего производителя." +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "Все используемые каналы dma" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." -msgstr "Этот микроконтроллер не поддерживает непрерывный захват." +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" +msgstr "Wi-Fi. Монитор недоступен" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." -msgstr "" -"Этот микроконтроллер поддерживает только data0=, а не data_pins=, поскольку " -"для него требуются смежные выводы." +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q читается только для этой доски" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "Высота плитки должна точно делить высоту растрового изображения" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" +msgstr "AP не может быть запущен" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "Выход индекса плитки за пределы" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" +msgstr "На этом аппаратном обеспечении доступно только обнаружение края" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" -msgstr "Ширина плитки должна точно делить ширину растрового изображения" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" +msgstr "Прерывание пина уже используется" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" +msgstr "Пин не может вывести из глубокого сна" + +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" +"Выводы глубокого сна должны использовать сигнал по возрастанию с подтяжкой к " +"земле" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." -msgstr "Время в прошлом." +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "Недопустимое значение единицы ADC" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" -msgstr "Таймаут слишком длинный: максимальная длина таймаута %d секунд" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "Ошибка инициализации устройства DAC" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" -msgstr "" +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "Ошибка инициализации канала DAC" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" -msgstr "Слишком много каналов в выборке" +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" +msgstr "Поддерживается только моно" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Too many channels in sample." -msgstr "Слишком много каналов в выборке." +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" +msgstr "поддерживается только выборка = 64" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" -msgstr "Слишком много дескрипторов" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "Другой аудиовыход PWM уже активен" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" -msgstr "Слишком много шин дисплея; забыл displayio.release_displays()?" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +#, c-format +msgid "Buffer length %d too big. It must be less than %d" +msgstr "Размер буфера %d слишком большой. Он должен быть меньше чем %d" -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "Слишком много дисплеев" +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" +msgstr "Не удалось выполнить буферизацию образца" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" -msgstr "Общее количество данных для записи превышает %q" +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "Ошибка инициализации I2C" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" -msgstr "Сенсорные сигналы недоступны" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" +msgstr "Ошибка инициализации SPI" -#: py/obj.c -msgid "Traceback (most recent call last):\n" -msgstr "Трассировка (последний вызов):\n" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" +msgstr "Повторная инициализация SPI" #: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" -msgstr "Деинициализация UART" +msgid "Internal define error" +msgstr "Внутренняя ошибка определения" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c #: ports/stm/common-hal/busio/UART.c -msgid "UART init" -msgstr "Инициализация UART" +msgid "Could not start interrupt, RX busy" +msgstr "Не удалось запустить прерывание, RX занят" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" -msgstr "" +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" +msgstr "Запись UART" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" -msgstr "Используемое периферийное устройство UART" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" +msgstr "Деинициализация UART" #: ports/stm/common-hal/busio/UART.c msgid "UART re-init" msgstr "Повторная инициализация UART" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" -msgstr "" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" +msgstr "Истекло время ожидания считывания температуры" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" -msgstr "" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" +msgstr "Истекло время ожидания считывания напряжения" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" -msgstr "Запись UART" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" +msgstr "Ошибка инициализации RNG" -#: main.c -msgid "UID:" -msgstr "UID:" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" +msgstr "Ошибка генерации случайных чисел" -#: shared-module/usb_hid/Device.c -msgid "USB busy" -msgstr "USB занят" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" +msgstr "Ошибка деинициализации генератора случайных чисел" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." -msgstr "USB-устройствам требуется больше конечных точек, чем доступно." +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" +msgstr "Повторное инициализация таймера" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." -msgstr "USB-устройства указывают слишком много имен интерфейсов." +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" +msgstr "Реинициализация канала" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "Ошибка USB" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" +msgstr "PWM перезагрузка" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" -msgstr "UUID строка не 'xxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxxx \"" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" +msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" -msgstr "Значение UUID не является строковым, целым или байтовым буфером" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO GetCardInfo Error %d" +msgstr "Ошибка получения информации о карте SDIO %d" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" -msgstr "Невозможно получить доступ к невыровненному регистру ввода-вывода" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" +msgstr ". Показать(x) удален. Используйте . корневую_группу = x" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Unable to allocate buffers for signed conversion" -msgstr "Не удается выделить буферы для подписанного преобразования" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "Яркость не регулируется" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." -msgstr "Невозможно выделить место в куче." +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q должно быть %d-%d" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" -msgstr "Не удается создать блокировку" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "Группа уже используется" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" -msgstr "Не удается найти дисплей I2C в %x" +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" +msgstr "" -#: py/parse.c -msgid "Unable to init parser" -msgstr "Не удается инициировать синтаксический анализатор" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" +msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" -msgstr "Не удается прочитать данные цветовой палитры" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" +msgstr "" + +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" +msgstr "" + +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "Ниже минимальной частоты кадров" + +#: py/argcheck.c +msgid "function doesn't take keyword arguments" +msgstr "функция не принимает аргументы ключевых слов" + +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" +msgstr "функция принимает %d позиционные аргументы, но %d были заданы" + +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" +msgstr "Функция отсутствует %d обязательные позиционные аргументы" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" -msgstr "" +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" +msgstr "функция, ожидаемая в большинстве %d аргументов, получила %d" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" -msgstr "Не удается запустить запрос mDNS" +#: py/argcheck.c +msgid "'%q' argument required" +msgstr "Требуется аргумент '%q'" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." -msgstr "Невозможно выполнить запись в nvm." +#: py/argcheck.c +msgid "extra positional arguments given" +msgstr "Приведены дополнительные позиционные аргументы" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" -msgstr "Невозможно записать в постоянную память" +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" +msgstr "неожиданный аргумент ключевого слова '%q'" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." -msgstr "Невозможно записать в Sleep_memory." +#: py/argcheck.c +msgid "extra keyword arguments given" +msgstr "Приведены дополнительные аргументы ключевых слов" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" -msgstr "Неожиданный тип nrfx uuid" +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c +msgid "argument num/types mismatch" +msgstr "Аргумент Несоответствие числа/типов" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error at %s:%d: %d" -msgstr "Неизвестная ошибка BLE в %s:%d: %d" +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" +msgstr "" +"Аргумент(ы) ключевого слова не реализован - используйте вместо него обычные " +"аргументы" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" -msgstr "Неизвестная ошибка BLE: %d" +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q должно быть %d" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" -msgstr "Неизвестный код ошибки %d" +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "%q должно быть >= %d" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" -msgstr "Неизвестный сбой %d" +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "%q должно быть <= %d" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" -msgstr "Неизвестная ошибка gatt: 0x%04x" +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q должно быть типа %q, а не %q" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." -msgstr "Причина неизвестна." +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "Длинна %q должна быть %d-%d" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" -msgstr "Неизвестная ошибка безопасности: 0x%04x" +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "Длинна %q должна быть >= %d" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" -msgstr "Неизвестная системная ошибка прошивки на %s:%d: %d" +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "Длинна %q должна быть <= %d" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" -msgstr "Неизвестная системная ошибка прошивки: %04x" +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "Длинна %q должна быть %d" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" -msgstr "Неизвестная ошибка прошивки системы: %d" +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q в %q должно быть типа %q, а не %q" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c -#, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." -msgstr "" -"Непревзойденное количество элементов на RHS (ожидалось %d, получено %d)." +#: py/asmthumb.c +msgid "too many locals for native method" +msgstr "Слишком много местных жителей для нативного метода" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -"Неуказанная проблема. Возможно, запрос на сопряжение на другом устройстве " -"был отклонен или проигнорирован." -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" -msgstr "Неподдерживаемое цветовое пространство" - -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" -msgstr "Неподдерживаемый тип шины дисплея" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q() принимает %d позиционных аргументов, но было передано %d" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" -msgstr "Неподдерживаемый алгоритм хеширования" +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" +msgstr "функция имеет несколько значений для аргументации%q \"" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" -msgstr "Неподдерживаемый тип сокета" +#: py/bc.c +msgid "unexpected keyword argument" +msgstr "Неожиданный аргумент ключевого слова" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" -msgstr "Обновление не удалось" +#: py/bc.c +#, c-format +msgid "function missing required positional argument #%d" +msgstr "В функции отсутствует обязательный позиционный аргумент #%d" -#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c -#: ports/zephyr-cp/common-hal/busio/I2C.c -#: ports/zephyr-cp/common-hal/busio/SPI.c -#: ports/zephyr-cp/common-hal/busio/UART.c -msgid "Use device tree to define %q devices" -msgstr "" +#: py/bc.c +msgid "function missing required keyword argument '%q'" +msgstr "В функции отсутствует обязательный аргумент ключевого слова '%q'" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" -msgstr "Длина значения! = требуемая фиксированная длина" +#: py/bc.c +msgid "function missing keyword-only argument" +msgstr "функция отсутствует аргумент только по ключевому слову" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" -msgstr "Длина значения > максимальная_длина" +#: py/binary.c py/objarray.c +msgid "bad typecode" +msgstr "Неверный шрифт" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" -msgstr "Версия была недействительной" +#: py/builtinevex.c +msgid "bad compile mode" +msgstr "Неверный режим компиляции" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" -msgstr "Истекло время ожидания считывания напряжения" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" +msgstr "Плюс любые модули в файловой системе\n" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" -msgstr "ВНИМАНИЕ: Имя файла кода имеет два расширения\n" +#: py/builtinhelp.c +msgid "object " +msgstr "объект " -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" -msgstr "" -"Сторожевой таймер не может быть деинициализирован, если установлен режим " -"RESET" +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " имеет тип %q\n" #: py/builtinhelp.c #, c-format @@ -2560,1888 +2432,2063 @@ msgid "" "\n" "To list built-in modules type `help(\"modules\")`.\n" msgstr "" -"Добро пожаловать в Adafruit CircuitPython %s! \n" -"\n" -"Посетите circuitpython.org для получения дополнительной информации. \n" -"\n" -"Чтобы получить список встроенных модулей, введите 'help(\"modules\")'.\n" +"Добро пожаловать в Adafruit CircuitPython %s! \n" +"\n" +"Посетите circuitpython.org для получения дополнительной информации. \n" +"\n" +"Чтобы получить список встроенных модулей, введите 'help(\"modules\")'.\n" + +#: py/builtinimport.c +msgid "script compilation not supported" +msgstr "Компиляция скриптов не поддерживается" + +#: py/builtinimport.c +msgid "can't perform relative import" +msgstr "Не удается выполнить относительный импорт" + +#: py/builtinimport.c +msgid "module not found" +msgstr "модуль не найден" + +#: py/builtinimport.c +msgid "no module named '%q'" +msgstr "Нет модуля с именем '%Q'" + +#: py/builtinimport.c +msgid "relative import" +msgstr "Относительный импорт" + +#: py/compile.c +msgid "can't assign to expression" +msgstr "Не удается назначить выражение" + +#: py/compile.c +msgid "multiple *x in assignment" +msgstr "Несколько *x в назначении" + +#: py/compile.c +msgid "non-default argument follows default argument" +msgstr "" +"Аргумент отличный от аргумента по умолчанию следует за аргументом по " +"умолчанию" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " +#: py/compile.c +msgid "invalid micropython decorator" +msgstr "неверный декоратор микропитона" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" -msgstr "" +#: py/compile.c +msgid "invalid arch" +msgstr "недействительная арка" -#: main.c -msgid "Woken up by alarm.\n" -msgstr "Проснулся по тревоге.\n" +#: py/compile.c +msgid "can't delete expression" +msgstr "Не удается удалить выражение" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" -msgstr "Запись не поддерживается в Характеристика" +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "'прервать'/'продолжить' вне цикла" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." -msgstr "Вы нажали обе кнопки при запуске." +#: py/compile.c +msgid "'return' outside function" +msgstr "«возврат» внешняя функция" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." -msgstr "Вы нажали кнопку A при запуске." +#: py/compile.c +msgid "import * not at module level" +msgstr "Импорт * не на уровне модуля" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." -msgstr "Вы нажали кнопку ВНИЗ при запуске." +#: py/compile.c +msgid "identifier redefined as global" +msgstr "идентификатор переопределен как глобальный" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" -msgstr "Вы нажали кнопку BOOT при запуске" +#: py/compile.c +msgid "no binding for nonlocal found" +msgstr "Привязка для нелокальных не найдена" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." -msgstr "При запуске вы нажали кнопку BOOT." +#: py/compile.c +msgid "identifier redefined as nonlocal" +msgstr "идентификатор переопределен как нелокальный" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." -msgstr "Вы нажали кнопку GPIO0 при запуске." +#: py/compile.c +msgid "can't declare nonlocal in outer code" +msgstr "не может объявить нелокальный во внешнем коде" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." -msgstr "Вы нажали кнопку «Запись» при запуске." +#: py/compile.c +msgid "default 'except' must be last" +msgstr "по умолчанию \"за исключением\" должно быть последним" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." -msgstr "Вы нажали кнопку SW38 при запуске." +#: py/compile.c +msgid "async for/with outside async function" +msgstr "async для/вместе с внешней async-функцией" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." -msgstr "Вы нажали кнопку ГРОМКОСТЬ при запуске." +#: py/compile.c +msgid "*x must be assignment target" +msgstr "*x должно быть целью назначения" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." -msgstr "Вы нажали центральную кнопку при запуске." +#: py/compile.c +msgid "super() can't find self" +msgstr "super() не может найти себя" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." -msgstr "Вы нажали левую кнопку при запуске." +#: py/compile.c +msgid "* arg after **" +msgstr "* аргумент после **" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." -msgstr "Вы нажали кнопку сброса во время загрузки." +#: py/compile.c +msgid "too many args" +msgstr "слишком много аргументов" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" -msgstr "[отрезается по длине]" +#: py/compile.c +msgid "LHS of keyword arg must be an id" +msgstr "LHS ключевого слова arg должен быть идентификатором(id)" -#: py/objtype.c -msgid "__init__() should return None" -msgstr "__init__() должен возвращать значение None" +#: py/compile.c +msgid "positional arg after **" +msgstr "позиционный аргумент после **" -#: py/objtype.c -#, c-format -msgid "__init__() should return None, not '%s'" -msgstr "__init__() должна возвращать Нет, а не \"%s\"" +#: py/compile.c +msgid "positional arg after keyword arg" +msgstr "позиционный аргумент после ключевого слова аргумента" -#: py/objobject.c -msgid "__new__ arg must be a user-type" -msgstr "__new__ arg должен быть пользовательского типа" +#: py/compile.c py/parse.c +msgid "invalid syntax" +msgstr "недействительный синтаксис" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" -msgstr "Требуется байтоподобный объект" +#: py/compile.c +msgid "expecting key:value for dict" +msgstr "ожидание ключа: значение для дикта" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" -msgstr "" +#: py/compile.c +msgid "expecting just a value for set" +msgstr "ожидание только значения для набора" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" -msgstr "адреса пусты" +#: py/compile.c +msgid "'yield' outside function" +msgstr "внешняя функция \"выход\"" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" -msgstr "" +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "«выход из» внутри асинхронной функции" + +#: py/compile.c +msgid "'await' outside function" +msgstr "«ожидание» внешняя функция" + +#: py/compile.c +msgid "unknown type '%q'" +msgstr "Неизвестный тип '%q'" #: py/compile.c msgid "annotation must be an identifier" msgstr "Аннотация должна быть идентификатором" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" -msgstr "arange: не удается вычислить длину" +#: py/compile.c +msgid "argument name reused" +msgstr "Повторное использование имени аргумента" -#: py/modbuiltins.c -msgid "arg is an empty sequence" -msgstr "arg - пустая последовательность" +#: py/compile.c +msgid "inline assembler must be a function" +msgstr "Встроенный ассемблер должен быть функцией" -#: py/objobject.c -msgid "arg must be user-type" -msgstr "arg должен быть пользовательского типа" +#: py/compile.c +msgid "unknown type" +msgstr "Неизвестный тип" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" -msgstr "аргумент сортировки должен быть аргументом массива ndarray" +#: py/compile.c +msgid "return annotation must be an identifier" +msgstr "Возвращаемая аннотация должна быть идентификатором" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" -msgstr "сортировка arg не реализована для сглаженных массивов" +#: py/compile.c +msgid "expecting an assembler instruction" +msgstr "Ожидание инструкции ассемблера" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" -msgstr "аргумент должен быть None, целым числом или кортежем целых чисел" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "«метка» требует 1 аргумент" #: py/compile.c -msgid "argument name reused" -msgstr "Повторное использование имени аргумента" +msgid "label redefined" +msgstr "Метка переопределена" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" -msgstr "Аргумент Несоответствие числа/типов" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "«выравнивание» требует 1 аргумента" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" -msgstr "Аргументы должны быть массивами ndarrays" +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "«данные» требуют как минимум 2 аргумента" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" -msgstr "Длина массива и индекса должна быть равна" +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "«данные» требуют целочисленных аргументов" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" -msgstr "Массив имеет слишком много измерений" +#: py/compile.c +msgid "cannot emit native code for this architecture" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" -msgstr "массив слишком велик" +#: py/emitbc.c +msgid "bytecode overflow" +msgstr "Переполнение байт-кода" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" -msgstr "массив/байты, необходимые справа" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" +msgstr "" + +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" +msgstr "" -#: py/compile.c -msgid "async for/with outside async function" -msgstr "async для/вместе с внешней async-функцией" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -"Попытка получить (аргумент)минимальный/(аргумент)максимальный пустой " -"последовательности" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" -"Попытка получить аргумент минимальный/аргумент максимальный пустой " -"последовательности" -#: py/objstr.c -msgid "attributes not supported" -msgstr "Атрибуты не поддерживаются" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: unknown register" +msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" -msgstr "Ось выходит за пределы" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" -msgstr "ось должна быть None или целым числом" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" -msgstr "Слишком длинная ось" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" +msgstr "может иметь только до 4 параметров для сборки большого пальца" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" -msgstr "Фоновое значение вне диапазона цели" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" +msgstr "Параметры должны быть регистрами в последовательности от r0 до r3" -#: py/builtinevex.c -msgid "bad compile mode" -msgstr "Неверный режим компиляции" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s' ожидает не более r%d" -#: py/objstr.c -msgid "bad conversion specifier" -msgstr "Неверный спецификатор преобразования" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "'%s' ожидает регистр" -#: py/objstr.c -msgid "bad format string" -msgstr "Строка неверного формата" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects a special register" +msgstr "'%s' ожидает специальный регистр" -#: py/binary.c py/objarray.c -msgid "bad typecode" -msgstr "Неверный шрифт" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an FPU register" +msgstr "'%s' ожидает регистр FPU" -#: py/emitnative.c -msgid "binary op %q not implemented" -msgstr "двоичная операция %q не реализована" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' ожидает {r0, r1, ...}" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" -msgstr "Размер и глубина растрового изображения должны совпадать" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' ожидает целое число" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" -msgstr "Размеры растровых изображений должны совпадать" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' целое число 0x%x не помещается в маску 0x%x" -#: extmod/modrandom.c -msgid "bits must be 32 or less" -msgstr "биты должны быть 32 или менее" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s' ожидает адрес в формате [a, b]" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' ожидает метку" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" -msgstr "bits_per_sample должно быть 8 или 16" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" +msgstr "Метка '%q' не определена" + +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" +msgstr "неподдерживаемая инструкция Thumb '%s' с аргументами %d" #: py/emitinlinethumb.c msgid "branch not in range" msgstr "Ветвь не в пределах досягаемости" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" -msgstr "Размер буфера меньше запрошенного" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" +msgstr "может иметь только до 4 параметров для сборки Xtensa" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" -msgstr "Размер буфера должен быть кратен размеру элемента" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" +msgstr "Параметры должны быть регистрами в последовательности от a2 до a5" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" -msgstr "Размер буфера должен соответствовать формату" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' целое число %d не находится в пределах диапазона %d..%d" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "Буферные фрагменты должны быть одинаковой длины" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" -msgstr "буфер слишком мал" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" +msgstr "неподдерживаемая инструкция Xtensa '%s' с аргументами %d" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" -msgstr "Слишком маленький буфер для запрашиваемых байтов" +#: py/emitnative.c +msgid "conversion to object" +msgstr "Преобразование в объект" -#: py/emitbc.c -msgid "bytecode overflow" -msgstr "Переполнение байт-кода" +#: py/emitnative.c +msgid "local '%q' used before type known" +msgstr "местный '%q' используется перед типом" -#: py/objarray.c -msgid "bytes length not a multiple of item size" -msgstr "длина байтов, не кратная размеру элемента" +#: py/emitnative.c +msgid "can't load from '%q'" +msgstr "Не удается загрузить из '%q'" -#: py/objstr.c -msgid "bytes value out of range" -msgstr "Значение байтов вне диапазона" +#: py/emitnative.c +msgid "can't load with '%q' index" +msgstr "Не удается загрузить с индексом '%q'" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" -msgstr "Калибровка выходит за пределы допустимого диапазона" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" +msgstr "Локальный '%q' имеет тип '%q', но источник '%q'" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" -msgstr "Калибровка доступна только для чтения" +#: py/emitnative.c +msgid "can't store '%q'" +msgstr "Не удается сохранить '%q'" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" -msgstr "может иметь только одного родителя" +#: py/emitnative.c +msgid "can't store to '%q'" +msgstr "невозможно сохранить в «%q»" -#: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" -msgstr "" +#: py/emitnative.c +msgid "can't store with '%q' index" +msgstr "не может хранить с индексом%q" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" -msgstr "может иметь только до 4 параметров для сборки большого пальца" +#: py/emitnative.c +msgid "can't implicitly convert '%q' to 'bool'" +msgstr "не может неявно преобразовать '%q' в 'bool'" + +#: py/emitnative.c +msgid "'not' not implemented" +msgstr "'не' не реализовано" + +#: py/emitnative.c +msgid "can't do unary op of '%q'" +msgstr "Невозможно выполнить унарную операцию '%q'" + +#: py/emitnative.c +msgid "div/mod not implemented for uint" +msgstr "div/mod не реализован для uint" + +#: py/emitnative.c +msgid "comparison of int and uint" +msgstr "сравнение int и uint" + +#: py/emitnative.c +msgid "binary op %q not implemented" +msgstr "двоичная операция %q не реализована" + +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" +msgstr "Не могу выполнить двоичную операцию между '%q' и '%q'" + +#: py/emitnative.c +msgid "casting" +msgstr "кастинг" + +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" +msgstr "Возврат ожидался '%q', но получил '%q'" + +#: py/emitnative.c +msgid "must raise an object" +msgstr "должен поднять объект" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" -msgstr "может иметь только до 4 параметров для сборки Xtensa" +#: py/emitnative.c +msgid "native yield" +msgstr "родной урожай" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" -msgstr "Можно указать только одно неизвестное измерение" +#: py/lexer.c +msgid "unicode name escapes" +msgstr "Экранирование имен в Юникоде" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" -msgstr "" -"Не удается добавить специальный метод к уже имеющемуся подклассу классу" +#: py/modbuiltins.c +msgid "chr() arg not in range(0x110000)" +msgstr "chr() аргумент вне диапазона (0x110000)" -#: py/compile.c -msgid "can't assign to expression" -msgstr "Не удается назначить выражение" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" +msgstr "chr() аргумент вне диапазона (256)" -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "Не могу отменить себя" +#: py/modbuiltins.c +msgid "arg is an empty sequence" +msgstr "arg - пустая последовательность" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" -msgstr "Не удается преобразовать %q в %q" +#: py/modbuiltins.c +msgid "ord expects a character" +msgstr "Орд ожидает персонажа" -#: py/obj.c +#: py/modbuiltins.c #, c-format -msgid "can't convert %s to complex" -msgstr "не может преобразовать %s в сложный" +msgid "ord() expected a character, but string of length %d found" +msgstr "ord() ожидал символ, но строка длины %d найдена" -#: py/obj.c -#, c-format -msgid "can't convert %s to float" -msgstr "не могу преобразовать %s в число с плавающей запятой" +#: py/modbuiltins.c +msgid "3-arg pow() not supported" +msgstr "Pow() с 3 аргументами не поддерживается" -#: py/objint.c py/runtime.c -#, c-format -msgid "can't convert %s to int" -msgstr "Невозможно преобразовать %s в int" +#: py/modbuiltins.c +msgid "must use keyword argument for key function" +msgstr "Необходимо использовать аргумент ключевого слова для ключевой функции" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" -msgstr "не может конвертировать «%q» в% q косвенно" +#: py/moderrno.c +msgid "Operation not permitted" +msgstr "Операция не разрешена" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" -msgstr "Не может преобразовать сложный в плавающий" +#: py/moderrno.c +msgid "No such file/directory" +msgstr "Файл/директория не существует" -#: py/obj.c -msgid "can't convert to complex" -msgstr "не может быть преобразован в сложный" +#: py/moderrno.c +msgid "Input/output error" +msgstr "Ошибка ввода/вывода" -#: py/obj.c -msgid "can't convert to float" -msgstr "Не удается преобразовать в float" +#: py/moderrno.c +msgid "Permission denied" +msgstr "Отказано в разрешении" -#: py/runtime.c -msgid "can't convert to int" -msgstr "Не удается преобразовать в int" +#: py/moderrno.c +msgid "File exists" +msgstr "Файл существует" -#: py/objstr.c -msgid "can't convert to str implicitly" -msgstr "не может превратиться в полосу неявно" +#: py/moderrno.c +msgid "No such device" +msgstr "Нет такого устройства" -#: py/objtype.c -msgid "can't create '%q' instances" -msgstr "" +#: py/moderrno.c +msgid "No space left on device" +msgstr "На устройстве не осталось свободного места" -#: py/objtype.c -msgid "can't create instance" -msgstr "" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" +msgstr "Ошибка математической области" -#: py/compile.c -msgid "can't declare nonlocal in outer code" -msgstr "не может объявить нелокальный во внешнем коде" +#: py/modmath.c +msgid "negative factorial" +msgstr "отрицательный факториал" -#: py/compile.c -msgid "can't delete expression" -msgstr "Не удается удалить выражение" +#: py/modmicropython.c +msgid "schedule queue full" +msgstr "Расписание Очередь заполнена" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" -msgstr "Не могу выполнить двоичную операцию между '%q' и '%q'" +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" +msgstr "буфер слишком мал" -#: py/emitnative.c -msgid "can't do unary op of '%q'" -msgstr "Невозможно выполнить унарную операцию '%q'" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" +msgstr "Упаковка ожидаемых %d товаров для упаковки (получил %d)" -#: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" -msgstr "не может неявно преобразовать '%q' в 'bool'" +#: py/modthread.c +msgid "expecting a dict for keyword args" +msgstr "ожидание определения аргументов ключевых слов" -#: py/runtime.c -msgid "can't import name %q" -msgstr "Невозможно импортировать имя %q" +#: py/nativeglue.c +msgid "set unsupported" +msgstr "Установить не поддерживается" -#: py/emitnative.c -msgid "can't load from '%q'" -msgstr "Не удается загрузить из '%q'" +#: py/nativeglue.c +msgid "slice unsupported" +msgstr "Фрагмент не поддерживается" -#: py/emitnative.c -msgid "can't load with '%q' index" -msgstr "Не удается загрузить с индексом '%q'" +#: py/nativeglue.c +msgid "float unsupported" +msgstr "Плавающий без поддержки" -#: py/builtinimport.c -msgid "can't perform relative import" -msgstr "Не удается выполнить относительный импорт" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" +msgstr "Не удается преобразовать %q в %q" -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" msgstr "" -"не может отправить значение, отличное от None, только что запущенному " -"генератору" +"При обращении с вышеуказанным исключением произошло еще одно исключение:" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" -msgstr "Не удается установить размер блока 512" +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" +msgstr "" +"Вышеупомянутое исключение было непосредственной причиной следующего " +"исключения:" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" -msgstr "Не удается установить атрибут" +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " Файл \"%q\", строка %d" -#: py/runtime.c -msgid "can't set attribute '%q'" -msgstr "Не удается установить атрибут '%q'" +#: py/obj.c +msgid " File \"%q\"" +msgstr " Файл \"%q\"" -#: py/emitnative.c -msgid "can't store '%q'" -msgstr "Не удается сохранить '%q'" +#: py/obj.c +msgid ", in %q\n" +msgstr ", в %q\n" -#: py/emitnative.c -msgid "can't store to '%q'" -msgstr "невозможно сохранить в «%q»" +#: py/obj.c +msgid "Traceback (most recent call last):\n" +msgstr "Трассировка (последний вызов):\n" -#: py/emitnative.c -msgid "can't store with '%q' index" -msgstr "не может хранить с индексом%q" +#: py/obj.c +msgid "can't convert to float" +msgstr "Не удается преобразовать в float" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" -msgstr "" -"Не удается переключиться с автоматической нумерации полей на ручную " -"спецификацию полей" +#: py/obj.c +#, c-format +msgid "can't convert %s to float" +msgstr "не могу преобразовать %s в число с плавающей запятой" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" -msgstr "не может переключаться с ручного поля на автоматическую нумерацию поля" +#: py/obj.c +msgid "can't convert to complex" +msgstr "не может быть преобразован в сложный" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" -msgstr "нельзя усекать и делить комплексное число" +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" +msgstr "не может преобразовать %s в сложный" -#: extmod/modasyncio.c -msgid "can't wait" -msgstr "не может ждать" +#: py/obj.c +msgid "expected tuple/list" +msgstr "Ожидаемый кортеж/список" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" -msgstr "Не удается назначить новую фигуру" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" +msgstr "Объект \"%s\" не является кортежом или списком" + +#: py/obj.c +msgid "tuple/list has wrong length" +msgstr "Кортеж/список имеет неправильную длину" + +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" +msgstr "запрашиваемая длина %d, но объект имеет длину %d" + +#: py/obj.c +msgid "indices must be integers" +msgstr "индексы должны быть целыми числами" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" -msgstr "Не удается привести выходные данные с помощью правила приведения" +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "Индексы %q должны быть целыми числами, а не %s" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" -msgstr "не может превратить комплекс в dtype" +#: py/obj.c +msgid "object has no len" +msgstr "Объект не имеет объектива" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" -msgstr "Не удается преобразовать сложный тип" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" +msgstr "объект типа «%s» не имеет len()" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" -msgstr "Не удается удалить элементы массива" +#: py/obj.c +msgid "object doesn't support item deletion" +msgstr "Объект не поддерживает удаление элементов" -#: py/compile.c -msgid "cannot emit native code for this architecture" -msgstr "" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "Объект '%s' не поддерживает удаление элементов" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" -msgstr "Не удается изменить форму массива" +#: py/obj.c +msgid "object isn't subscriptable" +msgstr "Объект не имеет индекса" -#: py/emitnative.c -msgid "casting" -msgstr "кастинг" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "Объект '%s' не может быть подписан" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" -msgstr "Реинициализация канала" +#: py/obj.c +msgid "object doesn't support item assignment" +msgstr "Объект не поддерживает назначение элементов" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" -msgstr "Слишком маленький буфер символов" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "Объект '%s' не поддерживает присвоение элементов" -#: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" -msgstr "chr() аргумент вне диапазона (0x110000)" +#: py/obj.c +msgid "object with buffer protocol required" +msgstr "Объект с обязательным буферным протоколом" -#: py/modbuiltins.c -msgid "chr() arg not in range(256)" -msgstr "chr() аргумент вне диапазона (256)" +#: py/objarray.c +msgid "bytes length not a multiple of item size" +msgstr "длина байтов, не кратная размеру элемента" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" -msgstr "Точка клипа должна быть кортежом (x,y)" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" +msgstr "строковый аргумент без кодировки" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" -msgstr "код вне диапазона 0~127" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" +msgstr "вид памяти: длина не является множеством элементов" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" -msgstr "" -"Цветовой буфер должен иметь размер 3 байта (RGB) или 4 байта (RGB + байт " -"заполнения)" +#: py/objarray.c py/objstr.c +msgid "substring not found" +msgstr "Подстрока не найдена" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" -msgstr "Цветовой буфер должен быть буфером, кортежом, списком или целым числом" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" +msgstr "поддерживаются только срезы с шагом = 1 (так как нет)" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" -msgstr "" -"цветовой буфер должен быть байтом массива или массивом типа \"b\" или \"B\"" +#: py/objarray.c +msgid "lhs and rhs should be compatible" +msgstr "lhs и rhs должны быть совместимыми" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" -msgstr "Цвет должен быть от 0x000000 до 0xffffff" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" +msgstr "массив/байты, необходимые справа" -#: py/emitnative.c -msgid "comparison of int and uint" -msgstr "сравнение int и uint" +#: py/objarray.c +msgid "memoryview offset too large" +msgstr "Слишком большое смещение просмотра памяти" + +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" +msgstr "нельзя усекать и делить комплексное число" #: py/objcomplex.c msgid "complex divide by zero" msgstr "комплексное деление на ноль" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" -msgstr "Комплексные значения не поддерживаются" - -#: extmod/modzlib.c -msgid "compression header" -msgstr "Заголовок сжатия" - -#: py/emitnative.c -msgid "conversion to object" -msgstr "Преобразование в объект" +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "0.0 в комплексную степень" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" -msgstr "Аргументы свертки должны быть линейными массивами" +#: py/objdeque.c +msgid "full" +msgstr "полный" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" -msgstr "переплетение аргументов должно быть массивами ndarrays" +#: py/objdeque.c +msgid "empty" +msgstr "пусто" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" -msgstr "аргументы свертки не должны быть пустыми" +#: py/objdict.c +msgid "dict update sequence has wrong length" +msgstr "последовательность обновления дикта имеет неправильную длину" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" -msgstr "Поврежденный файл" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" +msgstr "Не удается установить атрибут" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" -msgstr "не удалось инвертировать матрицу Вандермонда" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" +msgstr "Комплексные значения не поддерживаются" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" -msgstr "Не удалось определить версию SD карты" +#: py/objgenerator.c +msgid "generator already executing" +msgstr "генератор уже работает" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" -msgstr "крест определяется для 1D массивов длины 3" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" +msgstr "" +"не может отправить значение, отличное от None, только что запущенному " +"генератору" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" -msgstr "Данные должны быть итерируемыми" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" +msgstr "генератор поднят Остановить итерацию" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" -msgstr "Данные должны быть одинаковой длины" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" +msgstr "генератор проигнорировал Выход" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/objint.c py/runtime.c #, c-format -msgid "data pin #%d in use" -msgstr "data-пин #%d уже используется" - -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" -msgstr "Тип данных не понят" +msgid "can't convert %s to int" +msgstr "Невозможно преобразовать %s в int" -#: py/parsenum.c -msgid "decimal numbers not supported" -msgstr "Десятичные числа не поддерживаются" +#: py/objint.c +msgid "float too big" +msgstr "Поплавок слишком большой" -#: py/compile.c -msgid "default 'except' must be last" -msgstr "по умолчанию \"за исключением\" должно быть последним" +#: py/objint.c +#, c-format +msgid "value must fit in %d byte(s)" +msgstr "Значение должно совпадать с байтами %d" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" -msgstr "По умолчанию не является функцией" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" +msgstr "Нет поддержки длинных целых чисел (long integer)" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" -msgstr "" -"буфер назначения должен быть байтоммассива или массивом типа \"B\" для " -"бит_глубины = 8" +#: py/objint.c py/sequence.c +msgid "small int overflow" +msgstr "Маленькое переполнение int" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" -msgstr "" -"буфер назначения должен быть массивом типа «H» для битовой_глубины = 16" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "destination must be an array of type 'h'" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" -msgstr "последовательность обновления дикта имеет неправильную длину" - -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" -msgstr "аргумент DIFF должен быть массивом ndarray" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" +msgstr "Количество отрицательных сдвигов" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" -msgstr "Порядок дифференциации вне диапазона" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" +msgstr "Отрицательная мощность без поплавковой опоры" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" -msgstr "Размеры не совпадают" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" +msgstr "переполнение преобразование длинного целого в машинное слово" -#: py/emitnative.c -msgid "div/mod not implemented for uint" -msgstr "div/mod не реализован для uint" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" +msgstr "pow() с 3 аргументами требует целых чисел" -#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c -msgid "divide by zero" -msgstr "Делим на ноль" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" +msgstr "3-й аргумент pow() не может быть равен 0" -#: py/runtime.c -msgid "division by zero" -msgstr "Деление на ноль" +#: py/objobject.c +msgid "__new__ arg must be a user-type" +msgstr "__new__ arg должен быть пользовательского типа" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" -msgstr "Тип d должен быть плавающим или сложным" +#: py/objobject.c +msgid "arg must be user-type" +msgstr "arg должен быть пользовательского типа" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" -msgstr "dtype int32 не поддерживается" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "Шаг %q не может быть нулём" -#: py/objdeque.c -msgid "empty" -msgstr "пусто" +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "Невозможно создать подкласс среза" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" -msgstr "пустой файл" +#: py/objstr.c +msgid "bytes value out of range" +msgstr "Значение байтов вне диапазона" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" -msgstr "пустая куча" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" +msgstr "" +"присоединяйтесь к ожидающему список стр/байт объектов, совместимых с " +"самообъектом" #: py/objstr.c msgid "empty separator" msgstr "пустой сепаратор" -#: shared-bindings/random/__init__.c -msgid "empty sequence" -msgstr "пустая последовательность" +#: py/objstr.c +msgid "rsplit(None,n)" +msgstr "rsplit(Нет;n)" + +#: py/objstr.c +msgid "bad format string" +msgstr "Строка неверного формата" + +#: py/objstr.c +#, c-format +msgid "unmatched '%c' in format" +msgstr "Несовпадающий '%c' в формате" + +#: py/objstr.c +msgid "bad conversion specifier" +msgstr "Неверный спецификатор преобразования" #: py/objstr.c msgid "end of format while looking for conversion specifier" msgstr "конец формата при поиске спецификатора преобразования" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" -msgstr "epoch_time не поддерживается на этой плате" - -#: ports/nordic/common-hal/busio/UART.c +#: py/objstr.c #, c-format -msgid "error = 0x%08lX" -msgstr "ошибка = 0x%08lX" - -#: py/runtime.c -msgid "exceptions must derive from BaseException" -msgstr "исключения должны быть производными от базового исключения" +msgid "unknown conversion specifier %c" +msgstr "Неизвестный спецификатор преобразования %c" #: py/objstr.c msgid "expected ':' after format specifier" msgstr "Ожидаемый ':' после спецификатора формата" -#: py/obj.c -msgid "expected tuple/list" -msgstr "Ожидаемый кортеж/список" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" +msgstr "" +"Не удается переключиться с автоматической нумерации полей на ручную " +"спецификацию полей" -#: py/modthread.c -msgid "expecting a dict for keyword args" -msgstr "ожидание определения аргументов ключевых слов" +#: py/objstr.c +msgid "%q index out of range" +msgstr "Индекс %q вне диапазона" -#: py/compile.c -msgid "expecting an assembler instruction" -msgstr "Ожидание инструкции ассемблера" +#: py/objstr.c +msgid "attributes not supported" +msgstr "Атрибуты не поддерживаются" -#: py/compile.c -msgid "expecting just a value for set" -msgstr "ожидание только значения для набора" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" +msgstr "не может переключаться с ручного поля на автоматическую нумерацию поля" -#: py/compile.c -msgid "expecting key:value for dict" -msgstr "ожидание ключа: значение для дикта" +#: py/objstr.c +msgid "invalid format specifier" +msgstr "Недопустимый спецификатор формата" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" -msgstr "ext_hook не является функцией" +#: py/objstr.c +msgid "sign not allowed in string format specifier" +msgstr "Знак не разрешен в спецификаторе строкового формата" -#: py/argcheck.c -msgid "extra keyword arguments given" -msgstr "Приведены дополнительные аргументы ключевых слов" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" +msgstr "Знак не разрешен со спецификатором целочисленного формата 'c'" -#: py/argcheck.c -msgid "extra positional arguments given" -msgstr "Приведены дополнительные позиционные аргументы" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" +msgstr "Неизвестный код формата '%c' для объекта типа '%q'" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" -msgstr "Файл должен быть файлом, открытым в байтовом режиме" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "Выравнивание '=' недопустимо в спецификаторе формата строки" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" -msgstr "Запись файлов недоступна" +#: py/objstr.c +msgid "format needs a dict" +msgstr "Формат требует диктата" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" -msgstr "Первый аргумент должен быть вызываемым" +#: py/objstr.c +msgid "incomplete format key" +msgstr "Неполный ключ форматирования" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" -msgstr "первый аргумент должен быть функцией" +#: py/objstr.c +msgid "incomplete format" +msgstr "Неполный формат" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" -msgstr "Первый аргумент должен быть кортежом массива ndarrays" +#: py/objstr.c +msgid "format string needs more arguments" +msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" -msgstr "Первым аргументом должен быть массивом ndarray" +#: py/objstr.c +#, c-format +msgid "%%c needs int or char" +msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" -msgstr "первый аргумент супер() должен быть типом" +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" +msgstr "Неподдерживаемый символ формата '%c' (0x%x) при индексе %d" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" -msgstr "Первые два аргумента должны быть массивами ndarrays" +#: py/objstr.c +msgid "format string didn't convert all arguments" +msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" -msgstr "порядок сглаживания должен быть либо 'C', либо 'F'" +#: py/objstr.c +msgid "non-hex digit" +msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" -msgstr "Флип -аргумент должен быть массивом ndarray" +#: py/objstr.c +msgid "can't convert to str implicitly" +msgstr "не может превратиться в полосу неявно" -#: py/objint.c -msgid "float too big" -msgstr "Поплавок слишком большой" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" +msgstr "не может конвертировать «%q» в% q косвенно" -#: py/nativeglue.c -msgid "float unsupported" -msgstr "Плавающий без поддержки" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" +msgstr "Индексы строк должны быть целыми числами, а не %s" -#: extmod/moddeflate.c -msgid "format" -msgstr "формат" +#: py/objstrunicode.c +msgid "string index out of range" +msgstr "индекс строки выходит за пределы диапазона" -#: py/objstr.c -msgid "format needs a dict" -msgstr "Формат требует диктата" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "Вызовите super().__init__() перед доступом к собственному объекту." + +#: py/objtype.c +msgid "__init__() should return None" +msgstr "__init__() должен возвращать значение None" + +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" +msgstr "__init__() должна возвращать Нет, а не \"%s\"" + +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" +msgstr "Нечитаемый атрибут" + +#: py/objtype.c py/runtime.c +msgid "object not callable" +msgstr "Объект не вызывается" + +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" +msgstr "" + +#: py/objtype.c +msgid "type takes 1 or 3 arguments" +msgstr "тип занимает 1 или 3 аргумента" -#: py/objstr.c -msgid "format string didn't convert all arguments" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: py/objstr.c -msgid "format string needs more arguments" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: py/objdeque.c -msgid "full" -msgstr "полный" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" +msgstr "" +"Не удается добавить специальный метод к уже имеющемуся подклассу классу" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" -msgstr "функция не принимает аргументы ключевых слов" +#: py/objtype.c +msgid "type isn't an acceptable base type" +msgstr "Тип не является приемлемым базовым типом" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" -msgstr "функция, ожидаемая в большинстве %d аргументов, получила %d" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" +msgstr "Тип '%Q' не является допустимым базовым типом" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" -msgstr "функция имеет несколько значений для аргументации%q \"" +#: py/objtype.c +msgid "multiple inheritance not supported" +msgstr "Множественное наследование не поддерживается" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" -msgstr "функция имеет один и тот же знак в конце интервала" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" +msgstr "Несколько баз имеют конфликт расположения экземпляров" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" -msgstr "Функция определяется только для массивов ndarrays" +#: py/objtype.c +msgid "first argument to super() must be type" +msgstr "первый аргумент супер() должен быть типом" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" -msgstr "Функция реализована только для массивов ndarrays" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" +msgstr "issubclass() arg 2 должен быть классом или кортежом классов" -#: py/argcheck.c -#, c-format -msgid "function missing %d required positional arguments" -msgstr "Функция отсутствует %d обязательные позиционные аргументы" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" +msgstr "issubclass() arg 1 должен быть классом" -#: py/bc.c -msgid "function missing keyword-only argument" -msgstr "функция отсутствует аргумент только по ключевому слову" +#: py/parse.c +msgid "not a constant" +msgstr "не константа" -#: py/bc.c -msgid "function missing required keyword argument '%q'" -msgstr "В функции отсутствует обязательный аргумент ключевого слова '%q'" +#: py/parse.c +msgid "Unable to init parser" +msgstr "Не удается инициировать синтаксический анализатор" -#: py/bc.c -#, c-format -msgid "function missing required positional argument #%d" -msgstr "В функции отсутствует обязательный позиционный аргумент #%d" +#: py/parse.c +msgid "unexpected indent" +msgstr "Неожиданный отступ" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" -msgstr "функция принимает %d позиционные аргументы, но %d были заданы" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" +msgstr "Отступ не совпадает ни с одним уровнем внешнего отступа" -#: py/objgenerator.c -msgid "generator already executing" -msgstr "генератор уже работает" +#: py/parse.c +msgid "malformed f-string" +msgstr "Неправильно сформированная F-строка" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" -msgstr "генератор проигнорировал Выход" +#: py/parsenum.c +msgid "invalid syntax for integer" +msgstr "недействительный синтаксис для целых чисел" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" -msgstr "генератор поднят Остановить итерацию" +#: py/parsenum.c +#, c-format +msgid "invalid syntax for integer with base %d" +msgstr "недействительный синтаксис для целых чисел с основанием %d" -#: extmod/modhashlib.c -msgid "hash is final" -msgstr "хэш является окончательным" +#: py/parsenum.c +msgid "invalid syntax for number" +msgstr "недействительный синтаксис для номера" -#: extmod/modheapq.c -msgid "heap must be a list" -msgstr "куча должна быть списком" +#: py/parsenum.c +msgid "decimal numbers not supported" +msgstr "Десятичные числа не поддерживаются" -#: py/compile.c -msgid "identifier redefined as global" -msgstr "идентификатор переопределен как глобальный" +#: py/persistentcode.c +msgid "incompatible .mpy file" +msgstr "несовместимый файл .mpy" -#: py/compile.c -msgid "identifier redefined as nonlocal" -msgstr "идентификатор переопределен как нелокальный" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" +msgstr "" -#: py/compile.c -msgid "import * not at module level" -msgstr "Импорт * не на уровне модуля" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" +msgstr "Нативный код в .mpy не поддерживается" #: py/persistentcode.c msgid "incompatible .mpy arch" msgstr "несовместимые .mpy арка" -#: py/persistentcode.c -msgid "incompatible .mpy file" -msgstr "несовместимый файл .mpy" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "Объект '%q' не поддерживает '%q'" -#: py/objstr.c -msgid "incomplete format" -msgstr "Неполный формат" +#: py/qstr.c +msgid "name too long" +msgstr "слишком длинное имя" -#: py/objstr.c -msgid "incomplete format key" -msgstr "Неполный ключ форматирования" +#: py/runtime.c +msgid "name not defined" +msgstr "Имя не определено" -#: extmod/modbinascii.c -msgid "incorrect padding" -msgstr "Неправильная набивка" +#: py/runtime.c +msgid "name '%q' isn't defined" +msgstr "Имя '%q' не определено" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" -msgstr "индекс выходит из границ" +#: py/runtime.c +msgid "unsupported type for operator" +msgstr "Неподдерживаемый тип для оператора" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" -msgstr "Индекс должен быть кортежом или целым кортежом" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" +msgstr "неподдерживаемый тип для %q: '%s'" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" -msgstr "индекс вне диапазона" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" +msgstr "Неподдерживаемые типы для %q: '%q', '%q'" -#: py/obj.c -msgid "indices must be integers" -msgstr "индексы должны быть целыми числами" +#: py/runtime.c +msgid "wrong number of values to unpack" +msgstr "Неправильное количество значений для распаковки" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" -msgstr "индексы должны быть целыми числами, срезами или логическими списками" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" +msgstr "Для распаковки требуется более значений %d" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" -msgstr "Начальные значения должны быть итерируемыми" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" +msgstr "Слишком много значений для распаковки (ожидаемый %d)" -#: py/compile.c -msgid "inline assembler must be a function" -msgstr "Встроенный ассемблер должен быть функцией" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" +msgstr "тип объекта '%q' не имеет атрибута '%q \"" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" -msgstr "Входные и выходные размеры различаются" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" +msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" -msgstr "Входные и выходные формы различаются" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "Объект '%s' не имеет атрибута '%q'" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" -msgstr "Входной аргумент должен быть целым числом, кортежом или списком" +#: py/runtime.c +msgid "can't set attribute '%q'" +msgstr "Не удается установить атрибут '%q'" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" -msgstr "Длина входного массива должна быть равна степени 2" +#: py/runtime.c +msgid "object not iterable" +msgstr "Объект не итерируемый" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" -msgstr "Входные массивы несовместимы" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "Объект '%q' не является итерируемым" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" -msgstr "Входные данные должны быть итерируемыми" +#: py/runtime.c +msgid "object not an iterator" +msgstr "объект не итератор" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" -msgstr "Входной тип dtype должен быть плавающим или сложным" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "Объект '%q' не является итератором" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" -msgstr "Ввод не является итерируемым" +#: py/runtime.c +msgid "exceptions must derive from BaseException" +msgstr "исключения должны быть производными от базового исключения" + +#: py/runtime.c +msgid "can't import name %q" +msgstr "Невозможно импортировать имя %q" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" -msgstr "Входная матрица асимметрична" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" +msgstr "Не удалось выделить память, куча заблокирована" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" -msgstr "Входная матрица является сингулярной" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" +msgstr "Сбой выделения памяти, выделение %u байт" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" -msgstr "Вход должен быть 1- или 2-D" +#: py/runtime.c +msgid "can't convert to int" +msgstr "Не удается преобразовать в int" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" -msgstr "Ввод должен быть 1D массивом ndarray" +#: py/runtime.c +msgid "division by zero" +msgstr "Деление на ноль" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" -msgstr "Ввод должен быть плотным массивом ndarray" +#: py/runtime.c +msgid "maximum recursion depth exceeded" +msgstr "Превышена максимальная глубина рекурсии" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" -msgstr "Ввод должен быть массивом ndarray" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" +msgstr "объект не в последовательности" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" -msgstr "Ввод должен быть массивом ndarray или скаляр" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" +msgstr "Потоковая операция не поддерживается" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" -msgstr "Входные данные должны быть одномерными" +#: py/vm.c +msgid "local variable referenced before assignment" +msgstr "локальная переменная, на которую ссылается перед присвоением" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" -msgstr "Входные данные должны быть квадратной матрицей" +#: py/vm.c +msgid "no active exception to reraise" +msgstr "Нет активного исключения для повторного создания" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" -msgstr "Ввод должен быть кортеж, список, диапазон или массивом ndarray" +#: py/vm.c +msgid "opcode" +msgstr "код операции" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" -msgstr "Входные векторы должны быть одинаковой длины" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "Невозможно создать новый Adapter; используйте _bleio.adapter;" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" -msgstr "interp определен для 1D-итераций одинаковой длины" +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "Не удалось задать адрес" #: shared-bindings/_bleio/Adapter.c #, c-format msgid "interval must be in range %s-%s" msgstr "Интервал должен находиться в диапазоне %s-%s" -#: py/emitinlinerv32.c -msgid "invalid RV32 instruction '%q'" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot have scan responses for extended, connectable advertisements." msgstr "" +"Не может быть ответов на сканирование для расширенных подключаемых рекламных " +"объявлений." -#: py/compile.c -msgid "invalid arch" -msgstr "недействительная арка" +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" +msgstr "Только подключаемые объявления могут быть направлены" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" -msgstr "неверный бит_на_пиксель %d, должно быть 1, 2, 4, 8, 16, 24 или 32" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" +msgstr "Ненулевое время ожидания должно быть >= интервал" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" -msgstr "Неверный сертификат" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" +msgstr "окно должно быть <= интервал" -#: shared-bindings/audioi2sin/I2SIn.c -#, c-format -msgid "invalid destination buffer, must be an array of type: %c" -msgstr "" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" +msgstr "Буфер префикса должен находиться в куче" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" -msgstr "недопустимый размер элемента %d для битов на_пиксель %d\n" +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "ХарактеристикаЗапись в буфер не предусмотрена" -#: shared-bindings/bitmaptools/__init__.c +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." +msgstr "" +"Соединение было отключено и больше не может использоваться. Создайте новое " +"соединение." + +#: shared-bindings/_bleio/PacketBuffer.c #, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" -msgstr "аннулированный элемент_размер %d, должен быть, 1, 2 или 4" +msgid "Buffer too short by %d bytes" +msgstr "Буфер слишком короткий на %d байт" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" -msgstr "Недопустимое исключение" +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" +msgstr "Нет соединения: длина не может быть определена" -#: py/objstr.c -msgid "invalid format specifier" -msgstr "Недопустимый спецификатор формата" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +msgstr "UUID строка не 'xxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxxxxx \"" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" -msgstr "Недопустимое имя хоста" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" +msgstr "Значение UUID не является строковым, целым или байтовым буфером" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" -msgstr "Неверный ключ" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" +msgstr "не 128-битный UUID" -#: py/compile.c -msgid "invalid micropython decorator" -msgstr "неверный декоратор микропитона" +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" +msgstr "Только для чтения" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" -msgstr "Недопустимый параметр" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "Неправильный размер буфера" -#: shared-bindings/random/__init__.c -msgid "invalid step" -msgstr "недействительный шаг" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" +msgstr "вложенный индекс должен быть int" -#: py/compile.c py/parse.c -msgid "invalid syntax" -msgstr "недействительный синтаксис" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" +msgstr "Индекс должен быть кортежом или целым кортежом" -#: py/parsenum.c -msgid "invalid syntax for integer" -msgstr "недействительный синтаксис для целых чисел" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" +msgstr "Слишком маленький буфер карты" -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" -msgstr "недействительный синтаксис для целых чисел с основанием %d" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" +msgstr "Слишком маленький буфер символов" -#: py/parsenum.c -msgid "invalid syntax for number" -msgstr "недействительный синтаксис для номера" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" +msgstr "Пин является только входом" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" -msgstr "issubclass() arg 1 должен быть классом" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." +msgstr "" +"Непревзойденное количество элементов на RHS (ожидалось %d, получено %d)." -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" -msgstr "issubclass() arg 2 должен быть классом или кортежом классов" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "Ключ должен быть длинной 16, 24 или 32 байта" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" -msgstr "итерации не сходятся" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" +msgstr "Запрошенный режим AES не поддерживается" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" -msgstr "" -"присоединяйтесь к ожидающему список стр/байт объектов, совместимых с " -"самообъектом" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" +msgstr "Исходный и конечный буферы должны иметь одинаковую длину" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" -msgstr "" -"Аргумент(ы) ключевого слова не реализован - используйте вместо него обычные " -"аргументы" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB работает только с 16 байтами за раз" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" -msgstr "Метка '%q' не определена" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "Блоки CBC должны быть кратны 16 байтам" -#: py/compile.c -msgid "label redefined" -msgstr "Метка переопределена" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." +msgstr "Нарежьте и оцените разную длину." -#: py/objarray.c -msgid "lhs and rhs should be compatible" -msgstr "lhs и rhs должны быть совместимыми" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "Значения массива должны быть однобайтовыми." -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" -msgstr "Локальный '%q' имеет тип '%q', но источник '%q'" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." +msgstr "Невозможно записать в Sleep_memory." -#: py/emitnative.c -msgid "local '%q' used before type known" -msgstr "местный '%q' используется перед типом" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" +msgstr "Ожидаемый вид %q" -#: py/vm.c -msgid "local variable referenced before assignment" -msgstr "локальная переменная, на которую ссылается перед присвоением" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" +msgstr "RTC не поддерживается на этой плате" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" -msgstr "" -"Замыкание на себя + бесшумный режим, не поддерживаемый периферийными " -"устройствами" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" +msgstr "Поставьте один из monotonic_time или epoch_time" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" -msgstr "mDNS уже инициализирован" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" +msgstr "epoch_time не поддерживается на этой плате" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" -msgstr "mDNS работает только со встроенным WiFi" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." +msgstr "Время в прошлом." -#: py/parse.c -msgid "malformed f-string" -msgstr "Неправильно сформированная F-строка" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q должен быть массивом байтов или массивом типа «H» или «B»" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" -msgstr "Слишком маленький буфер карты" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" +msgstr "Не воспроизводится (Not playing)" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" -msgstr "Ошибка математической области" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." +msgstr "%q должно быть кратно 8." -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" -msgstr "матрица не является положительно определенной" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "Невозможно записать в файл" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -#, c-format -msgid "max_length must be 0-%d when fixed_length is %s" -msgstr "максимальная_длина должна быть 0-%d когда фиксированная длина %s" +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "Емкость места назначения меньше длины места назначения." -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " -msgstr "Максимальное количество измерений составляет " +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +msgstr "" +"буфер назначения должен быть массивом типа «H» для битовой_глубины = 16" -#: py/runtime.c -msgid "maximum recursion depth exceeded" -msgstr "Превышена максимальная глубина рекурсии" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +msgstr "" +"буфер назначения должен быть байтоммассива или массивом типа \"B\" для " +"бит_глубины = 8" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" -msgstr "maxiter должен быть > 0" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q должен быть массивом байтов или массивом типа «h», «H», «b» или «B»" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" -msgstr "макситер должен быть > 0" +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" +msgstr "Длина %q должна быть четной, кратной количеству каналов * размер_типа" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" -msgstr "Средний аргумент должен быть массивом ndarray" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" +msgstr "Файл должен быть файлом, открытым в байтовом режиме" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" -msgstr "Сбой выделения памяти, выделение %u байт" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" +msgstr "bits_per_sample должно быть 8 или 16" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" -msgstr "Не удалось выделить память, куча заблокирована" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" +msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" -msgstr "Слишком большое смещение просмотра памяти" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" +msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" -msgstr "вид памяти: длина не является множеством элементов" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" +msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" -msgstr "mktime нужен кортеж длины 8 или 9" +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" +msgstr "%q и %q должны быть разными" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" -msgstr "Режим должен быть завершенным или уменьшенным" +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Функция требует блокировки" -#: py/runtime.c -msgid "module '%q' has no attribute '%q'" +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "Буферные фрагменты должны быть одинаковой длины" + +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" +"Весом должна быть последовательность с нечетным квадратным числом элементов " +"(обычно 9 или 25)" -#: py/builtinimport.c -msgid "module not found" -msgstr "модуль не найден" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +msgstr "Веса должны быть объектом типа %q, %q, %q или %q, а не %q " -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" -msgstr "Сбой инициализации монитора" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" +msgstr "Точка клипа должна быть кортежом (x,y)" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" -msgstr "Больше степеней свободы чем точек данных" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" +msgstr "Исходная палитра слишком велика" -#: py/compile.c -msgid "multiple *x in assignment" -msgstr "Несколько *x в назначении" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "" +"Размер растрового изображения и число битов на значение должны совпадать" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" -msgstr "Несколько баз имеют конфликт расположения экземпляров" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +msgstr "" +"Для цветового пространства L8 входное растровое изображение должно иметь 8 " +"бит на пиксель" -#: py/objtype.c -msgid "multiple inheritance not supported" -msgstr "Множественное наследование не поддерживается" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +msgstr "" +"Для цветовых пространств RGB входное растровое изображение должно иметь 16 " +"бит на пиксель" -#: py/emitnative.c -msgid "must raise an object" -msgstr "должен поднять объект" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" +msgstr "Неподдерживаемое цветовое пространство" -#: py/modbuiltins.c -msgid "must use keyword argument for key function" -msgstr "Необходимо использовать аргумент ключевого слова для ключевой функции" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" +msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" -msgstr "Имя '%q' не определено" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" +msgstr "" -#: py/runtime.c -msgid "name not defined" -msgstr "Имя не определено" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" +msgstr "вне досягаемости цели" -#: py/qstr.c -msgid "name too long" -msgstr "слишком длинное имя" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" +msgstr "Величина выходящая за пределы диапазона цели" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" -msgstr "Нативный код в .mpy не поддерживается" +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" +msgstr "Фоновое значение вне диапазона цели" -#: py/emitnative.c -msgid "native yield" -msgstr "родной урожай" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" +msgstr "Типы массивов координат имеют разные размеры" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" -msgstr "Переполнение длины массива ndarray" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "Координатные массивы имеют разные длины" -#: py/runtime.c +#: shared-bindings/bitmaptools/__init__.c #, c-format -msgid "need more than %d values to unpack" -msgstr "Для распаковки требуется более значений %d" - -#: py/modmath.c -msgid "negative factorial" -msgstr "отрицательный факториал" +msgid "invalid element_size %d, must be, 1, 2, or 4" +msgstr "аннулированный элемент_размер %d, должен быть, 1, 2 или 4" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" -msgstr "Отрицательная мощность без поплавковой опоры" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" +msgstr "недопустимый размер элемента %d для битов на_пиксель %d\n" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative shift count" -msgstr "Количество отрицательных сдвигов" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +msgstr "неверный бит_на_пиксель %d, должно быть 1, 2, 4, 8, 16, 24 или 32" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" -msgstr "вложенный индекс должен быть int" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" +msgstr "Размеры растровых изображений должны совпадать" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" -msgstr "нет SD карты" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" +msgstr "source_bitmap должен иметь значение_счет 2 или 65536" -#: py/vm.c -msgid "no active exception to reraise" -msgstr "Нет активного исключения для повторного создания" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" +msgstr "source_bitmap должен иметь значение_счет 65536" -#: py/compile.c -msgid "no binding for nonlocal found" -msgstr "Привязка для нелокальных не найдена" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" +msgstr "source_bitmap должен иметь значение_счет 8" -#: shared-module/msgpack/__init__.c -msgid "no default packer" -msgstr "Нет упаковщика по умолчанию" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" +msgstr "Неподдерживаемое цветовое пространство для дизеринга" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" -msgstr "Нет начального числа по умолчанию" +#: shared-bindings/bitops/__init__.c +#, c-format +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgstr "Длина входного буфера (%d) должна быть кратна количеству цепочек (%d)" -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "Нет модуля с именем '%Q'" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" +msgstr "Нет шины %q по умолчанию" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" -msgstr "нет ответа с SD карты" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "Поворот дисплея должен осуществляться с шагом 90 градусов" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" -msgstr "нет такого атрибута" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q должен быть равен 1, если %q имеет значение True" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" -msgstr "не-UUID найден в сервисе_uuids_белый список" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "Дисплей должен иметь 16 битное цветовое пространство." -#: py/compile.c -msgid "non-default argument follows default argument" -msgstr "" -"Аргумент отличный от аргумента по умолчанию следует за аргументом по " -"умолчанию" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" +msgstr "tx и rx не могут быть одновременно None" -#: py/objstr.c -msgid "non-hex digit" -msgstr "" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." +msgstr "Должен быть субклассом %q." -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" -msgstr "Ненулевое время ожидания должно быть > 0,01" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" +msgstr "Запросы на удаленную передачу ограничены 8 байтами" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" -msgstr "Ненулевое время ожидания должно быть >= интервал" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "Невозможно установить значение при вводе направления." -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" -msgstr "не 128-битный UUID" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "Режим движения не используется при вводе направления." -#: py/parse.c -msgid "not a constant" -msgstr "не константа" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." +msgstr "Тяга не используется, когда выводится направление." -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" -msgstr "не реализовано для сложного типа d" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" -msgstr "Не поддерживается для типов ввода" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" -msgstr "Количество баллов должно быть не менее 2" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "Невозможно удалить значения" -#: py/builtinhelp.c -msgid "object " -msgstr "объект " +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" +msgstr "Фрагменты не поддерживаются" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" -msgstr "Объект \"%s\" не является кортежом или списком" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" +msgstr "" +"цветовой буфер должен быть байтом массива или массивом типа \"b\" или \"B\"" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "object does not support DigitalInOut protocol" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" +"Цветовой буфер должен иметь размер 3 байта (RGB) или 4 байта (RGB + байт " +"заполнения)" -#: py/obj.c -msgid "object doesn't support item assignment" -msgstr "Объект не поддерживает назначение элементов" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" +msgstr "Цвет должен быть от 0x000000 до 0xffffff" -#: py/obj.c -msgid "object doesn't support item deletion" -msgstr "Объект не поддерживает удаление элементов" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" +msgstr "Цветовой буфер должен быть буфером, кортежом, списком или целым числом" -#: py/obj.c -msgid "object has no len" -msgstr "Объект не имеет объектива" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" +msgstr "Неподдерживаемый тип %Q" -#: py/obj.c -msgid "object isn't subscriptable" -msgstr "Объект не имеет индекса" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" +msgstr "Ширина плитки должна точно делить ширину растрового изображения" -#: py/runtime.c -msgid "object not an iterator" -msgstr "объект не итератор" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" +msgstr "Высота плитки должна точно делить высоту растрового изображения" -#: py/objtype.c py/runtime.c -msgid "object not callable" -msgstr "Объект не вызывается" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" +msgstr "" +"Новое растровое изображение должно быть того же размера, что и старое " +"растровое изображение" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" -msgstr "объект не в последовательности" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" +msgstr "Выход индекса плитки за пределы" -#: py/runtime.c -msgid "object not iterable" -msgstr "Объект не итерируемый" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" +msgstr "Смещение должно быть >= 0" -#: py/obj.c -#, c-format -msgid "object of type '%s' has no len()" -msgstr "объект типа «%s» не имеет len()" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" +msgstr "Слишком раннее обновление" -#: py/obj.c -msgid "object with buffer protocol required" -msgstr "Объект с обязательным буферным протоколом" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "Буфер не является байтовым массивом." -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" -msgstr "выключить" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" +msgstr "Системная запись должна быть gnss. Спутниковая система" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" -msgstr "Смещение слишком большое" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" +msgstr "Неподдерживаемый алгоритм хеширования" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" -msgstr "Смещение должно быть >= 0" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" +msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" -msgstr "Смещение должно быть неотрицательным и не превышать длину буфера" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" +msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" -msgstr "поддерживается только бит_глубина=16" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" +msgstr "адреса пусты" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" -msgstr "Поддерживается только моно" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" +msgstr "Недействительная строка IP" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" -msgstr "только массивы ndarrays могут быть объединены" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "Адрес должен быть длиной %d байт" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "поддерживается только выборка = 64" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" +msgstr "Для IP поддерживаются только int или строка" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" -msgstr "только образец_рейт=16000 поддерживается" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" +msgstr "ширина должна быть больше нуля" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" -msgstr "поддерживаются только срезы с шагом = 1 (так как нет)" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" +msgstr "Размеры шкалы необходимо разделить на 3" -#: py/vm.c -msgid "opcode" -msgstr "код операции" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" +msgstr "Сопоставление должно быть кортежом" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" -msgstr "" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" +msgstr "%q должен иметь тип %q, %q или %q, а не %q" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" +"Не удалось добавить служебную TXT-запись; в txt_records обнаружена нестрока " +"или байт" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" -msgstr "" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" +msgstr "Обертывание диапазона адресов" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q содержит пины дупликаты" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" -msgstr "" +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q и %q содержат пины дупликаты" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" -msgstr "" +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" +msgstr "код вне диапазона 0~127" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" -msgstr "Операнды не могут транслироваться вместе" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" +msgstr "По умолчанию не является функцией" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" -msgstr "операция определена только для 2D-массивов" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" +msgstr "ext_hook не является функцией" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" -msgstr "операция определена только для массивов ndarrays" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." +msgstr "Невозможно выполнить запись в nvm." -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" -msgstr "операция реализована только для 1D логических массивов" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" +msgstr "Отсутствует аппаратный генератор случайных чисел" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" -msgstr "операция не реализована на массивах ndarrays" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" +msgstr "Укажите точно один из data0 или data_pins" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" -msgstr "Операция не поддерживается для данного типа" +#: shared-bindings/ps2io/Ps2.c +msgid "Failed sending command." +msgstr "Не удалось отправить команду." -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" -msgstr "операция не поддерживается для типов ввода" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "Массив должен содержать полуслова (тип 'H')" -#: py/modbuiltins.c -msgid "ord expects a character" -msgstr "Орд ожидает персонажа" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" +msgstr "" -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" -msgstr "ord() ожидал символ, но строка длины %d найдена" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" +msgstr "Остановка недоступна с начального запуска" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" -msgstr "Наш массив слишком мал" +#: shared-bindings/random/__init__.c +msgid "invalid step" +msgstr "недействительный шаг" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" -msgstr "out имеет неправильный тип" +#: shared-bindings/random/__init__.c +msgid "empty sequence" +msgstr "пустая последовательность" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" -msgstr "Ключевое слово out не поддерживается для сложного типа d" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" +msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" -msgstr "ключевое слово не поддерживается для функции" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +msgstr "Длина rgb_pins должна быть 6, 12, 18, 24 или 30" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" -msgstr "Out должен быть плотным массивом с плавающей запятой" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" +msgstr "rgb_pins[%d] не находится на том же порту что и часы" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" -msgstr "out должен быть массивом ndarray" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" +msgstr "rgb_pins[%d] дублирует другое назначение пинов" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" -msgstr "Выход должен быть поплавкового типа" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" +msgstr "" +"Распиновка использует %d байт на элемент, что превышает идеальное %d байт. " +"Если этого нельзя избежать, передайте конструктору allow_inefficient=True" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" -msgstr "вне досягаемости цели" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" +msgstr "Количество используемых rgb-пинов должно быть кратно 6, а не %d" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" -msgstr "Выходной массив имеет неправильный тип" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +msgstr "" +"Адресные контакты %d, контакты rgb %d и плитки %d обозначают высоту %d, а не " +"%d" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" -msgstr "выходной массив должен быть непрерывным" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" +msgstr "порт должен быть >= 0" -#: py/objint_longlong.c py/objint_mpz.c -msgid "overflow converting long int to machine word" -msgstr "переполнение преобразование длинного целого в машинное слово" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" +msgstr "Слишком маленький буфер для запрашиваемых байтов" -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" -msgstr "Упаковка ожидаемых %d товаров для упаковки (получил %d)" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" +msgstr "Имя или услуга не известны" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" -msgstr "Параметры должны быть регистрами в последовательности от a2 до a5" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" +msgstr "Контекст на стороне сервера не может иметь имя хоста" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" -msgstr "Параметры должны быть регистрами в последовательности от r0 до r3" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "Невозможно изменить USB устройство сейчас" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" -msgstr "Опрос в файле недоступен в Win32" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" +msgstr "Файл не найден" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" -msgstr "вытолкнуть из пустого импульсного входа" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" +msgstr "" +"Временная метка выходит за пределы допустимого диапазона для платформы time_t" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c -#: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" -msgstr "Всплывающее окно из пустого %q" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" +msgstr "Запись файлов недоступна" -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" -msgstr "порт должен быть >= 0" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" +msgstr "Недопустимое исключение" -#: py/compile.c -msgid "positional arg after **" -msgstr "позиционный аргумент после **" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" +msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" -msgstr "позиционный аргумент после ключевого слова аргумента" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" -msgstr "3-й аргумент pow() не может быть равен 0" +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q, и %q должны быть одной длинны" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" -msgstr "pow() с 3 аргументами требует целых чисел" +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." +msgstr "" +"Объект был деинициализирован и больше не может быть использован. Создайте " +"новый объект." -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" -msgstr "Маски вытягивания конфликтуют с масками направления" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "%q должен быть подклассом %q" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" -msgstr "реальные и воображаемые части должны быть одинаковой длины" +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" +msgstr "%q за пределом" -#: extmod/modre.c -msgid "regex too complex" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" +msgstr "Неверный шестнадцатеричный пароль" -#: py/builtinimport.c -msgid "relative import" -msgstr "Относительный импорт" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" +msgstr "Недопустимое имя хоста" -#: py/obj.c -#, c-format -msgid "requested length %d but object has length %d" -msgstr "запрашиваемая длина %d, но объект имеет длину %d" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "Неверный MAC-адрес" -#: py/objint_longlong.c py/parsenum.c -msgid "result overflows long long storage" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "Режим авторизации.OPEN не используется с паролем" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" -msgstr "Результаты не могут быть приведены к указанному типу" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "Неверный BSSID" -#: py/compile.c -msgid "return annotation must be an identifier" -msgstr "Возвращаемая аннотация должна быть идентификатором" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "Ошибка аутентификации" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" -msgstr "Возврат ожидался '%q', но получил '%q'" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" +msgstr "Нет сети с этим ssid" -#: shared-bindings/rgbmatrix/RGBMatrix.c +#: shared-bindings/wifi/Radio.c #, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" -msgstr "rgb_pins[%d] дублирует другое назначение пинов" +msgid "Unknown failure %d" +msgstr "Неизвестный сбой %d" -#: shared-bindings/rgbmatrix/RGBMatrix.c +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c #, c-format -msgid "rgb_pins[%d] is not on the same port as clock" -msgstr "rgb_pins[%d] не находится на том же порту что и часы" +msgid "No I2C device at address: 0x%x" +msgstr "Нет устройства I2C по адресу: %x" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" -msgstr "аргумент roll должен быть массивом ndarray" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "Неверный размер блока формата" -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "rsplit(Нет;n)" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" +msgstr "%q образца не совпадает" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" -msgstr "Частота дискретизации выходит за пределы допустимого диапазона" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "Не удалось выделить место для декодера" -#: py/modmicropython.c -msgid "schedule queue full" -msgstr "Расписание Очередь заполнена" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "Не удалось распарсить файл MP3" -#: py/builtinimport.c -msgid "script compilation not supported" -msgstr "Компиляция скриптов не поддерживается" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" +msgstr "%q слишком долго" -#: py/nativeglue.c -msgid "set unsupported" -msgstr "Установить не поддерживается" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" +msgstr "Размер и глубина растрового изображения должны совпадать" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" -msgstr "форма должна быть None, целым числом или кортежем целых чисел" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" +msgstr "неподдерживаемая глубина растрового изображения" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" -msgstr "фигура должна быть целым числом или кортежом целых чисел" +#: shared-module/displayio/Bitmap.c +msgid "Invalid bits per value" +msgstr "Недопустимое бит-на-значение" -#: shared-module/msgpack/__init__.c -msgid "short read" -msgstr "короткое чтение" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" +msgstr "Только один цвет может быть прозрачным одновременно" -#: py/objstr.c -msgid "sign not allowed in string format specifier" -msgstr "Знак не разрешен в спецификаторе строкового формата" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "Слой уже в группе (Group)" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" -msgstr "Знак не разрешен со спецификатором целочисленного формата 'c'" +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "Слой должен быть группой (Group) или субклассом TileGrid" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" -msgstr "размер определен только для массива ndarrays" +#: shared-module/displayio/OnDiskBitmap.c +#, c-format +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" +msgstr "" +"Поддерживается только формат Windows, несжатый BMP: заданный размер " +"заголовка - %d" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" -msgstr "Размер должен соответствовать out.shape при совместном использовании" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" +msgstr "RLE-сжатый BMP не поддерживается" -#: py/nativeglue.c -msgid "slice unsupported" -msgstr "Фрагмент не поддерживается" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" +msgstr "Не удается прочитать данные цветовой палитры" -#: py/objint.c py/sequence.c -msgid "small int overflow" -msgstr "Маленькое переполнение int" +#: shared-module/displayio/__init__.c +msgid "Too many displays" +msgstr "Слишком много дисплеев" -#: main.c -msgid "soft reboot\n" -msgstr "Мягкая перезагрузка\n" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" +msgstr "Слишком много шин дисплея; забыл displayio.release_displays()?" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" -msgstr "аргумент сортировки должен быть массивом ndarray" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" +msgstr "Неподдерживаемый тип шины дисплея" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" -msgstr "Массив sos должен иметь форму (n_section, 6)" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" +msgstr "неподдерживаемое цветовое пространство для GifWriter" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" -msgstr "sos[:, 3] должны быть все единицы" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" +msgstr "Не удается найти дисплей I2C в %x" + +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "" + +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." +msgstr "Этот микроконтроллер не поддерживает непрерывный захват." -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" -msgstr "sosфильтр требует повторяющихся аргументов" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "Светодиодные сопоставления должны соответствовать размеру дисплея" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "Исходная палитра слишком велика" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" +msgstr "Прерывается функцией выхода" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "source_bitmap должен иметь значение_счет 2 или 65536" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" +msgstr "Ошибка устройства или неправильное завершение входного потока" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" -msgstr "source_bitmap должен иметь значение_счет 65536" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" +msgstr "Недостаточный объем памяти для изображения" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" -msgstr "source_bitmap должен иметь значение_счет 8" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" +msgstr "Недостаточный буфер ввода потока" -#: extmod/modre.c -msgid "splitting with sub-captures" -msgstr "разделение с помощью подзахватов" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" +msgstr "Ошибка параметра" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" -msgstr "Остановка недоступна с начального запуска" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" +msgstr "Ошибка формата данных (возможно, данные повреждены)" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" -msgstr "Потоковая операция не поддерживается" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" +msgstr "Правильный формат, но не поддерживается" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" -msgstr "строковый аргумент без кодировки" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" +msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" -msgstr "индекс строки выходит за пределы диапазона" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" +msgstr "%q() без %q()" -#: py/objstrunicode.c +#: shared-module/memorymonitor/AllocationAlarm.c #, c-format -msgid "string indices must be integers, not %s" -msgstr "Индексы строк должны быть целыми числами, а не %s" - -#: py/objarray.c py/objstr.c -msgid "substring not found" -msgstr "Подстрока не найдена" +msgid "Attempt to allocate %d blocks" +msgstr "Попытка выделения %d блоков" -#: py/compile.c -msgid "super() can't find self" -msgstr "super() не может найти себя" +#: shared-module/msgpack/__init__.c +msgid "short read" +msgstr "короткое чтение" -#: extmod/modjson.c -msgid "syntax error in JSON" -msgstr "синтаксис ошибка в JSON" +#: shared-module/msgpack/__init__.c +msgid "no default packer" +msgstr "Нет упаковщика по умолчанию" -#: extmod/modtime.c -msgid "ticks interval overflow" -msgstr "переполнение интервала тиков" +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" +msgstr "Недопустимый формат" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -"Продолжительность таймаута превысила максимальное поддерживаемое значение" - -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" -msgstr "таймаут должен быть < 655.35 сек" +"Этот микроконтроллер поддерживает только data0=, а не data_pins=, поскольку " +"для него требуются смежные выводы." -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" -msgstr "таймаут ожидания потока" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" +msgstr "Нет доступного таймера" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" -msgstr "таймаут ожидания индексного импульса" +#: shared-module/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Internal error #%d" +msgstr "Внутренняя ошибка #%d" #: shared-module/sdcardio/SDCard.c msgid "timeout waiting for v1 card" @@ -4451,272 +4498,243 @@ msgstr "Таймаут в ожидании карты v1" msgid "timeout waiting for v2 card" msgstr "Таймаут ожидания карты v2" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" -msgstr "Повторное инициализация таймера" - -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" -msgstr "" -"Временная метка выходит за пределы допустимого диапазона для платформы time_t" - -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" -msgstr "Тобайты могут быть вызваны только для плотных массивов" - -#: py/compile.c -msgid "too many args" -msgstr "слишком много аргументов" - -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" -msgstr "Слишком много измерений" - -#: extmod/ulab/code/ndarray.c -msgid "too many indices" -msgstr "Слишком много индексов" - -#: py/asmthumb.c -msgid "too many locals for native method" -msgstr "Слишком много местных жителей для нативного метода" - -#: py/runtime.c -#, c-format -msgid "too many values to unpack (expected %d)" -msgstr "Слишком много значений для распаковки (ожидаемый %d)" - -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" -msgstr "ловушка определена для одномерных 1D массивов одинаковой длины" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" +msgstr "нет SD карты" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" -msgstr "ловушка определена для одномерных 1D итераций" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" +msgstr "Не удалось определить версию SD карты" -#: py/obj.c -msgid "tuple/list has wrong length" -msgstr "Кортеж/список имеет неправильную длину" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" +msgstr "нет ответа с SD карты" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" -msgstr "twai_driver_install вернул ошибку esp-idf #%d" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" +msgstr "Формат CSD SD-карты не поддерживается" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" -msgstr "twai_start вернул ошибку esp-idf #%d" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" +msgstr "Не удается установить размер блока 512" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" -msgstr "tx и rx не могут быть одновременно None" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "Неверный сокет для TLS" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" -msgstr "Тип '%Q' не является допустимым базовым типом" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" +msgstr "Неверный ключ" -#: py/objtype.c -msgid "type isn't an acceptable base type" -msgstr "Тип не является приемлемым базовым типом" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" +msgstr "Неверный сертификат" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" -msgstr "тип объекта '%q' не имеет атрибута '%q \"" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" +msgstr "Отсутствует каталог точки монтирования" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" -msgstr "тип занимает 1 или 3 аргумента" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." +msgstr "" -#: py/parse.c -msgid "unexpected indent" -msgstr "Неожиданный отступ" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' и 'O' не являются поддерживаемыми типами форматов" -#: py/bc.c -msgid "unexpected keyword argument" -msgstr "Неожиданный аргумент ключевого слова" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" +msgstr "Размер буфера должен соответствовать формату" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" -msgstr "неожиданный аргумент ключевого слова '%q'" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "%q должен быть массивом типа 'h \"" -#: py/lexer.c -msgid "unicode name escapes" -msgstr "Экранирование имен в Юникоде" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" +msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" -msgstr "Отступ не совпадает ни с одним уровнем внешнего отступа" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" +msgstr "" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" -msgstr "Неизвестный спецификатор преобразования %c" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" +msgstr "Отсутствует подтяжка к земле на пине; Рекомендуется 1 Мегаом" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" -msgstr "Неизвестный код формата '%c' для объекта типа '%q'" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" +msgstr "Порт USB-хоста не инициализирован" -#: py/compile.c -msgid "unknown type" -msgstr "Неизвестный тип" +#: shared-module/usb/core/Device.c +msgid "Pipe error" +msgstr "Ошибка трубопровода" -#: py/compile.c -msgid "unknown type '%q'" -msgstr "Неизвестный тип '%q'" +#: shared-module/usb/core/Device.c +msgid "No configuration set" +msgstr "Нет конфигураций" -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" -msgstr "Несовпадающий '%c' в формате" +#: shared-module/usb_hid/Device.c +msgid "USB busy" +msgstr "USB занят" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" -msgstr "Нечитаемый атрибут" +#: shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "Ошибка USB" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" -msgstr "Неподдерживаемый тип %Q" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" +msgstr "может иметь только одного родителя" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" -msgstr "неподдерживаемая инструкция Thumb '%s' с аргументами %d" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" +msgstr "Полигону необходимо как минимум 3 точки" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" -msgstr "неподдерживаемая инструкция Xtensa '%s' с аргументами %d" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" +msgstr "Повторное соединение" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" -msgstr "неподдерживаемая глубина растрового изображения" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" +msgstr "Да" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" -msgstr "неподдерживаемое цветовое пространство для GifWriter" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" +msgstr "Выключено" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" -msgstr "Неподдерживаемое цветовое пространство для дизеринга" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" +msgstr "[отрезается по длине]" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" -msgstr "Неподдерживаемый символ формата '%c' (0x%x) при индексе %d" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"You are in safe mode because:\n" +msgstr "" +"\n" +"Вы в безопасном режиме потому что:\n" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" -msgstr "неподдерживаемый тип для %q: '%s'" +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." +msgstr "" +"Мощность просела. Убедитесь, что вы обеспечиваете достаточную мощность." -#: py/runtime.c -msgid "unsupported type for operator" -msgstr "Неподдерживаемый тип для оператора" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" +msgstr "Вы нажали кнопку BOOT при запуске" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" -msgstr "Неподдерживаемые типы для %q: '%q', '%q'" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." +msgstr "Вы нажали кнопку сброса во время загрузки." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" -msgstr "Usecols слишком высок" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "Диск CIRCUTPY не удалось найти или создать." -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" -msgstr "Ключевое слово usecols должно быть указано" +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." +msgstr "" +"Модуль «микроконтроллер» использовался для загрузки в безопасном режиме." -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" -msgstr "Значение должно совпадать с байтами %d" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." +msgstr "Ошибка в сейфе. py." -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" -msgstr "Величина выходящая за пределы диапазона цели" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." +msgstr "Переполнение стека. Увеличьте размер стека." -#: extmod/moddeflate.c -msgid "wbits" -msgstr "" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." +msgstr "USB-устройствам требуется больше конечных точек, чем доступно." -#: shared-bindings/bitmapfilter/__init__.c -msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" -msgstr "" -"Весом должна быть последовательность с нечетным квадратным числом элементов " -"(обычно 9 или 25)" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." +msgstr "USB-устройства указывают слишком много имен интерфейсов." -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " -msgstr "Веса должны быть объектом типа %q, %q, %q или %q, а не %q " +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "Загрузочное устройство должно быть первым (интерфейс #0)." -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" -msgstr "ширина должна быть больше нуля" +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "Внутренний сторожевой таймер истек." -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" -msgstr "Wi-Fi. Монитор недоступен" +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "Основной код CircuitPython сильно разбился. Упс!\n" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" -msgstr "окно должно быть <= интервал" +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." +msgstr "Выделение кучи, когда виртуальная машина не запущена." -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" -msgstr "Неправильный индекс оси" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." +msgstr "Не удалось записать внутреннюю флэш-память." -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" -msgstr "Указана неправильная ось" +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." +msgstr "Жесткая ошибка: доступ к памяти или ошибка инструкции." -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" -msgstr "Неправильный тип" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." +msgstr "Прерванная ошибка." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" -msgstr "Неправильный тип индекса" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." +msgstr "Прыжок NLR не удался. Вероятно повреждение памяти." -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" -msgstr "Неправильный тип ввода" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." +msgstr "Невозможно выделить место в куче." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" -msgstr "неправильная длина массива состояния" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." +msgstr "Неустранимая ошибка прошивки стороннего производителя." -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" -msgstr "неправильная длина массива индексов" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." +msgstr "" +"\n" +"Пожалуйста подайте вопрос с вашей программой на github.com/adafruit/" +"circuitpython/issues." -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" -msgstr "неправильное количество аргументов" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" +msgstr "" +"\n" +"Нажмите на сброс чтобы выйти из безопасного режима.\n" -#: py/runtime.c -msgid "wrong number of values to unpack" -msgstr "Неправильное количество значений для распаковки" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "Произошла ошибка при получении '%s':\n" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" -msgstr "неверный тип вывода" +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "Недопустимое экранирование Юникода" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" -msgstr "зи, должно быть, массивом ndarray" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" -msgstr "zi должно быть типа float" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" +msgstr "выключить" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" -msgstr "zi должен иметь форму (n_section, 2)" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "Нет IP" + +#, c-format +#~ msgid "SDIO Init Error %x" +#~ msgstr "Ошибка инициализации SDIO %x" #~ msgid "bit_depth must be 8, 16, 24, or 32." #~ msgstr "Глубина_бита должна быть равна 8, 16, 24 или 32." diff --git a/locale/tr.po b/locale/tr.po index 85315ad5db8..39a25055e11 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -17,1425 +17,733 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 2026.7.1.dev0\n" -#: main.c -msgid "" -"\n" -"Code done running.\n" +#: extmod/modasyncio.c extmod/modheapq.c +msgid "empty heap" msgstr "" -"\n" -"Program çalıştırıldı.\n" -#: main.c -msgid "" -"\n" -"Code stopped by auto-reload. Reloading soon.\n" +#: extmod/modasyncio.c +msgid "can't cancel self" msgstr "" -"\n" -"Program otomatik yeniden yükleme tarafından durduruldu. Birazdan tekrar " -"yüklenecek.\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Please file an issue with your program at github.com/adafruit/circuitpython/" -"issues." +#: extmod/modasyncio.c +msgid "can't wait" msgstr "" -"\n" -"Lütfen programınızla ilgili bir sorunu github.com/adafruit/circuitpython/" -"issues adresinden bildirin." -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"Press reset to exit safe mode.\n" +#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c +msgid "a bytes-like object is required" msgstr "" -"\n" -"Güvenli moddan çıkmak için reset'e basın\n" -#: supervisor/shared/safe_mode.c -msgid "" -"\n" -"You are in safe mode because:\n" +#: extmod/modbinascii.c +msgid "incorrect padding" msgstr "" -"\n" -"Güvenli moddasın çünkü:\n" -#: py/obj.c -msgid " File \"%q\"" -msgstr " \"%q\" dosyası" +#: extmod/moddeflate.c +msgid "format" +msgstr "" -#: py/obj.c -msgid " File \"%q\", line %d" -msgstr " \"%q\" dosyası, %d numaralı satır" +#: extmod/moddeflate.c +msgid "wbits" +msgstr "" -#: py/builtinhelp.c -msgid " is of type %q\n" -msgstr " nesnesi, %q tipindedir\n" +#: extmod/modhashlib.c +msgid "hash is final" +msgstr "" -#: main.c -msgid " not found.\n" -msgstr " bulunamadı.\n" +#: extmod/modheapq.c +msgid "heap must be a list" +msgstr "" -#: main.c -msgid " output:\n" -msgstr " çıktı:\n" +#: extmod/modjson.c +msgid "syntax error in JSON" +msgstr "" -#: py/objstr.c -#, c-format -msgid "%%c needs int or char" -msgstr "%%c int ya da char gerektirir" +#: extmod/modrandom.c +msgid "bits must be 32 or less" +msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" +#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c +msgid "no default seed" msgstr "" -"%d adres pinleri, %d RGB pinleri ve %d döşemeleri %d'nin yüksekliği " -"gösterir, %d'nin değil" -#: py/emitinlinextensa.c -#, c-format -msgid "%d is not a multiple of %d" -msgstr "%d %d'nin katı değil" +#: extmod/modre.c +msgid "splitting with sub-captures" +msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q and %q contain duplicate pins" -msgstr "%q ve %q yinelenen pinler içeriyor" +#: extmod/modre.c +msgid "regex too complex" +msgstr "" -#: shared-bindings/audioio/AudioOut.c -msgid "%q and %q must be different" -msgstr "%q ve %q farklı olmalılar" +#: extmod/modre.c +msgid "Error in regex" +msgstr "regex'te hata" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "%q and %q must share a clock unit" -msgstr "%q ve %q bir saat birimi paylaşmalıdır" +#: extmod/modtime.c +msgid "mktime needs a tuple of length 8 or 9" +msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "%q cannot be changed once mode is set to %q" -msgstr "Mod %q olarak ayarlandıktan sonra %q değiştirilemez" +#: extmod/modtime.c +msgid "ticks interval overflow" +msgstr "" -#: shared-bindings/microcontroller/Pin.c -msgid "%q contains duplicate pins" -msgstr "%q yinelenen pinler içeriyor" +#: extmod/modzlib.c +msgid "compression header" +msgstr "" -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "%q failure: %d" -msgstr "%q hata: %d" +#: extmod/ulab/code/ndarray.c +msgid "data type not understood" +msgstr "" -#: shared-module/audiodelays/MultiTapDelay.c -msgid "%q in %q must be of type %q or %q, not %q" -msgstr "%q'nün içindeki %q, %q veya %q tipi olmalıdır, %q değil" +#: extmod/ulab/code/ndarray.c +msgid "array is too big" +msgstr "" -#: py/argcheck.c shared-module/audiofilters/Filter.c -msgid "%q in %q must be of type %q, not %q" -msgstr "%q'nün içindeki %q, %q tipi olmalıdır, %q değil" +#: extmod/ulab/code/ndarray.c +msgid "ndarray length overflows" +msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/mipidsi/Bus.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/usb_host/Port.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c -#: shared-module/max3421e/Max3421E.c -msgid "%q in use" -msgstr "%q kullanımda" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex type" +msgstr "" -#: py/objstr.c -msgid "%q index out of range" -msgstr "%q indeksi aralık dışında" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c +msgid "too many dimensions" +msgstr "" -#: py/obj.c -msgid "%q indices must be integers, not %s" -msgstr "%q indeksleri integer olmalı, %s değil" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c +msgid "index is out of bounds" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c -#: ports/stm/common-hal/audioio/AudioOut.c -#: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c -msgid "%q init failed" -msgstr "%q init başarısız oldu" +#: extmod/ulab/code/ndarray.c +msgid "indices must be integers, slices, or Boolean lists" +msgstr "" -#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c -msgid "%q is %q" -msgstr "%q %q dir" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c +msgid "operands could not be broadcast together" +msgstr "" -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "%q is read-only for this board" -msgstr "%q bu kart için salt okunur" +#: extmod/ulab/code/ndarray.c +msgid "array and index length must be equal" +msgstr "" -#: py/argcheck.c shared-bindings/usb_hid/Device.c -msgid "%q length must be %d" -msgstr "%q boyutu %d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "cannot convert complex to dtype" +msgstr "" -#: py/argcheck.c -msgid "%q length must be %d-%d" -msgstr "%q boyutları %d-%d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "operation is implemented for 1D Boolean arrays only" +msgstr "" -#: py/argcheck.c -msgid "%q length must be <= %d" -msgstr "%q boyutu <= %d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "too many indices" +msgstr "" -#: py/argcheck.c -msgid "%q length must be >= %d" -msgstr "%q boyutu >= %d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "cannot delete array elements" +msgstr "" -#: py/argcheck.c -msgid "%q must be %d" -msgstr "%q, %d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "flattening order must be either 'C', or 'F'" +msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c -#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/is31fl3741/FrameBuffer.c -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "%q must be %d-%d" -msgstr "%q, %d-%d olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "tobytes can be invoked for dense arrays only" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -msgid "%q must be 1 when %q is True" -msgstr "%q 1 olmalı, %q True olduğu zaman" +#: extmod/ulab/code/ndarray.c +msgid "operation is not supported for given type" +msgstr "" -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 16, 24, or 32" -msgstr "%q 16,24 veya 32 olmalıdır" +#: extmod/ulab/code/ndarray.c +msgid "shape must be integer or tuple of integers" +msgstr "" -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "%q must be 8 or 16" -msgstr "%q 8 veya 16 olmalıdır" +#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c +msgid "maximum number of dimensions is " +msgstr "" -#: ports/espressif/common-hal/audiobusio/PDMIn.c -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q must be 8, 16, 24, or 32" -msgstr "%q 8, 16, 24 veya 32 olmalıdır" - -#: py/argcheck.c shared-bindings/gifio/GifWriter.c -#: shared-module/gifio/OnDiskGif.c -msgid "%q must be <= %d" -msgstr "%q <= %d olmalıdır" - -#: ports/espressif/common-hal/watchdog/WatchDogTimer.c -msgid "%q must be <= %u" -msgstr "%q, %u değerinden küçük veya eşit olmalıdır" - -#: py/argcheck.c -msgid "%q must be >= %d" -msgstr "%q >= %d olmalıdır" - -#: shared-bindings/analogbufio/BufferedIn.c -msgid "%q must be a bytearray or array of type 'H' or 'B'" -msgstr "%q 'H' ya da 'B' tipi bir bytearray ya da array olmalıdır" - -#: shared-bindings/audiocore/RawSample.c -msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" -msgstr "%q 'h', 'H', 'b' ya da 'B' tipi bir bytearray ya da array olmalı" - -#: shared-bindings/warnings/__init__.c -msgid "%q must be a subclass of %q" -msgstr "%q, %q'nün alt türü olmalıdır" - -#: ports/espressif/common-hal/analogbufio/BufferedIn.c -msgid "%q must be array of type 'H'" -msgstr "%q, 'H' dizisi türünde olmalıdır" - -#: shared-module/synthio/__init__.c -msgid "%q must be array of type 'h'" -msgstr "%q, 'h' dizisi türünde olmalıdır" - -#: shared-bindings/audiobusio/PDMIn.c -msgid "%q must be multiple of 8." -msgstr "%q 8'in katı olmalıdır." - -#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c -#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c -msgid "%q must be of type %q or %q, not %q" -msgstr "%q; %q veya %q tipi olmalıdır, %q değil" - -#: shared-bindings/jpegio/JpegDecoder.c -msgid "%q must be of type %q, %q, or %q, not %q" -msgstr "%q; %q, %q veya %q tipi olmalıdır, %q değil" - -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q; %q tipi olmalıdır, %q değil" - -#: ports/atmel-samd/common-hal/busio/UART.c -msgid "%q must be power of 2" -msgstr "%q, 2'nin kuvveti olmalıdır" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' attribute" -msgstr "%q nesnesinde '%q' niteliği eksik" - -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "%q object missing '%q' method" -msgstr "%q nesnesinde '%q' metodu eksik" - -#: shared-bindings/wifi/Monitor.c -msgid "%q out of bounds" -msgstr "%q sınırların dışında" - -#: ports/analog/common-hal/busio/SPI.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c -#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c -#: shared-bindings/time/__init__.c -msgid "%q out of range" -msgstr "%q aralık dışında" - -#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c -msgid "%q step cannot be zero" -msgstr "%q sıfır olamaz" - -#: shared-module/bitbangio/I2C.c -msgid "%q too long" -msgstr "%q çok uzun" - -#: py/bc.c py/objnamedtuple.c -msgid "%q() takes %d positional arguments but %d were given" -msgstr "%q(), %d konumsal argümanını alır ancak %d verildi" - -#: shared-module/jpegio/JpegDecoder.c -msgid "%q() without %q()" -msgstr "" - -#: shared-bindings/usb_hid/Device.c -msgid "%q, %q, and %q must all be the same length" -msgstr "%q, %q ve %q aynı uzunlukta olmalıdır" - -#: py/objint.c shared-bindings/_bleio/Connection.c -#: shared-bindings/storage/__init__.c -msgid "%q=%q" -msgstr "%q=%q" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts in more bits than pin count" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] shifts out more bits than pin count" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] uses extra pin" -msgstr "" - -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "%q[%u] waits on input outside of count" -msgstr "" - -#: ports/espressif/common-hal/espidf/__init__.c -#, c-format -msgid "%s error 0x%x" -msgstr "%s hatası 0x%x" - -#: py/argcheck.c -msgid "'%q' argument required" -msgstr "'%q' argümanı gerekli" - -#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "'%q' object does not support '%q'" -msgstr "'%q' nesnesi '%q' öğesini desteklemiyor" - -#: py/runtime.c -msgid "'%q' object isn't an iterator" -msgstr "'%q' nesnesi bir iteratör değildir" - -#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c -msgid "'%q' object isn't callable" -msgstr "" - -#: py/runtime.c -msgid "'%q' object isn't iterable" -msgstr "'%q' nesnesi iterable değildir" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a label" -msgstr "'%s' bir etiket bekliyor" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects a register" -msgstr "'%s' bir yazmaç bekliyor" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects a special register" -msgstr "'%s' özel bir yazmaç bekliyor" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an FPU register" -msgstr "'%s' bir FPU yazmacı bekliyor" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects an address of the form [a, b]" -msgstr "'%s', [a, b] biçiminde bir adres bekliyor" - -#: py/emitinlinethumb.c py/emitinlinextensa.c -#, c-format -msgid "'%s' expects an integer" -msgstr "'%s' bir integer bekliyor" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects at most r%d" -msgstr "'%s' en fazla r%d bekler" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' expects {r0, r1, ...}" -msgstr "'%s' {r0, r1, ...} bekliyor" - -#: py/emitinlinextensa.c -#, c-format -msgid "'%s' integer %d isn't within range %d..%d" -msgstr "'%s' integer %d, %d..%d aralığında değil" - -#: py/emitinlinethumb.c -#, c-format -msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" -msgstr "'%s' integer 0x%x, 0x%x maskesine uymuyor" - -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item assignment" -msgstr "'%s' nesnesi, öğe atamasını desteklemiyor" - -#: py/obj.c -#, c-format -msgid "'%s' object doesn't support item deletion" -msgstr "'%s' nesnesi, öğe silmeyi desteklemiyor" - -#: py/runtime.c -msgid "'%s' object has no attribute '%q'" -msgstr "'%s' nesnesinin '%q' özelliği yok" - -#: py/obj.c -#, c-format -msgid "'%s' object isn't subscriptable" -msgstr "'%s' nesnesi subscriptable özelliğe sahip değil" - -#: py/objstr.c -msgid "'=' alignment not allowed in string format specifier" -msgstr "'=' hizalamasına string biçiminde izin verilmez" - -#: shared-module/struct/__init__.c -msgid "'S' and 'O' are not supported format types" -msgstr "'S' ve 'O' desteklenen biçim türlerinden değildir" - -#: py/compile.c -msgid "'align' requires 1 argument" -msgstr "'align' 1 argümana ihtiyaç duyar" - -#: py/compile.c -msgid "'await' outside function" -msgstr "fonksiyon dışında 'await'" - -#: py/compile.c -msgid "'break'/'continue' outside loop" -msgstr "Döngü dışında 'break'/'continue'" - -#: py/compile.c -msgid "'data' requires at least 2 arguments" -msgstr "'data' en az 2 argümana ihtiyaç duyar" - -#: py/compile.c -msgid "'data' requires integer arguments" -msgstr "'data' integer tipinde argümanlara ihtiyaç duyar" - -#: py/compile.c -msgid "'label' requires 1 argument" -msgstr "'label' 1 argümana ihtiyaç duyar" - -#: py/emitnative.c -msgid "'not' not implemented" -msgstr "" - -#: py/compile.c -msgid "'return' outside function" -msgstr "fonksiyon dışında 'return'" - -#: py/compile.c -msgid "'yield from' inside async function" -msgstr "asenkron fonksiyon içinde 'yield from'" - -#: py/compile.c -msgid "'yield' outside function" -msgstr "fonksiyon dışında 'yield'" - -#: py/compile.c -msgid "* arg after **" -msgstr "" - -#: py/compile.c -msgid "*x must be assignment target" -msgstr "*x atama hedefi olmalıdır" - -#: py/obj.c -msgid ", in %q\n" -msgstr ", içinde %q\n" - -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid ".show(x) removed. Use .root_group = x" -msgstr "" - -#: py/objcomplex.c -msgid "0.0 to a complex power" -msgstr "0.0'dan bir karmaşık güce" - -#: py/modbuiltins.c -msgid "3-arg pow() not supported" -msgstr "3-argümanlı pow() desteklenmemektedir" - -#: ports/raspberrypi/common-hal/wifi/Radio.c -msgid "AP could not be started" -msgstr "" - -#: shared-bindings/ipaddress/IPv4Address.c -#, c-format -msgid "Address must be %d bytes long" -msgstr "Adres %d byte uzunluğunda olmalıdır" - -#: ports/espressif/common-hal/memorymap/AddressRange.c -#: ports/nordic/common-hal/memorymap/AddressRange.c -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Address range not allowed" -msgstr "" - -#: shared-bindings/memorymap/AddressRange.c -msgid "Address range wraps around" -msgstr "Adres aralığı başa döner" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "All CAN peripherals are in use" -msgstr "Tüm CAN çevre birimleri kullanımda" - -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/nordic/common-hal/busio/I2C.c -msgid "All I2C peripherals are in use" -msgstr "Tüm I2C çevre birimleri kullanımda" - -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "All RX FIFOs in use" -msgstr "Tüm RX FIFO'ları kullanımda" - -#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c -msgid "All SPI peripherals are in use" -msgstr "Tüm SPI çevre birimleri kullanımda" - -#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c -msgid "All UART peripherals are in use" -msgstr "Tüm UART çevre birimleri kullanımda" - -#: ports/nordic/common-hal/countio/Counter.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c -msgid "All channels in use" -msgstr "Tüm kanallar kullanımda" - -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All dma channels in use" -msgstr "Kullanımdaki tüm dma kanalları" - -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "All event channels in use" -msgstr "Tüm olay kanalları kullanımda" - -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/usb_host/Port.c -msgid "All state machines in use" -msgstr "Tüm durum makineleri kullanımda" - -#: ports/atmel-samd/audio_dma.c -msgid "All sync event channels in use" -msgstr "Tüm asenkron olay kanalları kullanımda" - -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c -msgid "All timers for this pin are in use" -msgstr "Bu pin için tüm zamanlayıcılar kullanımda" - -#: ports/atmel-samd/common-hal/_pew/PewPew.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/nordic/peripherals/nrf/timers.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "All timers in use" -msgstr "Tüm zamanlayıcılar kullanımda" - -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Already advertising." -msgstr "Halihazırda duyuruluyor." - -#: ports/atmel-samd/common-hal/canio/Listener.c -msgid "Already have all-matches listener" -msgstr "Tüm eşleşmelerle eşleşen dinleyiciniz var" - -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Already in progress" -msgstr "Zaten işlemde" - -#: ports/espressif/bindings/espnow/ESPNow.c -#: ports/espressif/common-hal/espulp/ULP.c -#: shared-module/memorymonitor/AllocationAlarm.c -#: shared-module/memorymonitor/AllocationSize.c -msgid "Already running" -msgstr "Halihazırda çalışıyor" - -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Already scanning for wifi networks" -msgstr "Halihazırda wifi ağları için tarama yapılıyor" - -#: supervisor/shared/settings.c -#, c-format -msgid "An error occurred while retrieving '%s':\n" -msgstr "'%s' alınırken hata yaşandı:\n" - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Another PWMAudioOut is already active" -msgstr "Başka bir PWMAudioOut zaten aktif durumda" - -#: ports/atmel-samd/common-hal/pulseio/PulseOut.c -#: ports/cxd56/common-hal/pulseio/PulseOut.c -msgid "Another send is already active" -msgstr "Başka bir gönderme zaten aktif" - -#: shared-bindings/pulseio/PulseOut.c -msgid "Array must contain halfwords (type 'H')" -msgstr "Dizi yarımsözcüklere sahip olmalıdır (tip 'H')" - -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Array values should be single bytes." -msgstr "Dizi değerleri tekil bytelar olmalıdır." - -#: ports/atmel-samd/common-hal/spitarget/SPITarget.c -msgid "Async SPI transfer in progress on this bus, keep awaiting." -msgstr "" -"Bu veri yolunda asenkron SPI transferi devam ediyor, beklemeye devam edin." - -#: shared-bindings/usb_audio/__init__.c -msgid "At least one of microphone and speaker must be enabled" -msgstr "Mikrofon veya hoparlörden en az biri etkinleştirilmiş olmalı" - -#: shared-module/memorymonitor/AllocationAlarm.c -#, c-format -msgid "Attempt to allocate %d blocks" -msgstr "%d bloğun ayrılması girişimi" - -#: ports/raspberrypi/audio_dma.c -msgid "Audio conversion not implemented" -msgstr "Ses dönüşümü implemente edilmedi" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Audio source error" -msgstr "Ses kaynağı hatası" - -#: shared-bindings/wifi/Radio.c -msgid "AuthMode.OPEN is not used with password" -msgstr "AuthMode.OPEN bir şifre ile kullanılmadı" - -#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c -msgid "Authentication failure" -msgstr "Kimlik doğrulama hatası" - -#: main.c -msgid "Auto-reload is off.\n" -msgstr "Otomatik yeniden yükleme devre dışı.\n" - -#: main.c -msgid "" -"Auto-reload is on. Simply save files over USB to run them or enter REPL to " -"disable.\n" -msgstr "" -"Otomatik yeniden yükleme aktif. Dosyaları çalıştırmak için USB aracılığı ile " -"kaydedin ya da deaktif etmek için REPL moda girin.\n" - -#: ports/espressif/common-hal/canio/CAN.c -msgid "Baudrate not supported by peripheral" -msgstr "Baudhızı, çevre birimi tarafından desteklenmiyor" - -#: ports/zephyr-cp/common-hal/zephyr_display/Display.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Below minimum frame rate" -msgstr "Minimum kare hızından altında" - -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c -msgid "Bit clock and word select must be sequential GPIO pins" -msgstr "Bit saati ve kelime seçimi ardışık GPIO pinleri olmalı" - -#: shared-bindings/bitmaptools/__init__.c -msgid "Bitmap size and bits per value must match" -msgstr "Bitmap boyutu ve bit başına değer uyuşmalı" - -#: supervisor/shared/safe_mode.c -msgid "Boot device must be first (interface #0)." -msgstr "Önyükleme cihazı birinci olmalı (arayüz #0)." - -#: ports/analog/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Both RX and TX required for flow control" -msgstr "Hem RX hem de TX akış kontrolü için gerekli" - -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Brightness not adjustable" -msgstr "Parlaklık ayarlanabilir değil" - -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Buffer elements must be 4 bytes long or less" -msgstr "Buffer elementleri 4 bit olmak zorunda" - -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Buffer is not a bytearray." -msgstr "Buffer bir bytearray değil." - -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -#, c-format -msgid "Buffer length %d too big. It must be less than %d" -msgstr "Mevcut arabellek boyutu %d çok büyük. En fazla %d kadar olmalı" - -#: ports/atmel-samd/common-hal/sdioio/SDCard.c -#: ports/cxd56/common-hal/sdioio/SDCard.c -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c -#, c-format -msgid "Buffer must be a multiple of %d bytes" -msgstr "Tampon, %d baytların katı olmalıdır" - -#: shared-bindings/_bleio/PacketBuffer.c -#, c-format -msgid "Buffer too short by %d bytes" -msgstr "Buffer bitten %d daha az" - -#: ports/cxd56/common-hal/camera/Camera.c -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c -msgid "Buffer too small" -msgstr "Tampon çok küçük" - -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c -#, c-format -msgid "Bus pin %d is already in use" -msgstr "Veriyolu pini %d kullanımda" - -#: shared-bindings/aesio/aes.c -msgid "CBC blocks must be multiples of 16 bytes" -msgstr "CBC blokları 16 baytın katları şeklinde olmalı" - -#: supervisor/shared/safe_mode.c -msgid "CIRCUITPY drive could not be found or created." -msgstr "CIRCUITPY sürücüsü bulunamadı veya oluşturulamadı." - -#: ports/espressif/common-hal/espidf/__init__.c -msgid "CRC or checksum was invalid" -msgstr "CRC yada checksum geçersiz" - -#: py/objtype.c -msgid "Call super().__init__() before accessing native object." -msgstr "Yerel nesneye erişmeden önce super().__init__() fonksiyonunu çağırın." - -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Camera init" -msgstr "Kamerayı başlat" - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on RTC IO from deep sleep." -msgstr "Sadece alarm RTC IO'yu uyandırabilir." - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on one low pin while others alarm high from deep sleep." -msgstr "" -"Derin uykudan uyanırken, diğerleri yüksek seviyede alarm verecek şekilde " -"ayarlanmışken sadece tek bir düşük pinde alarm tetiklenebilir." - -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Can only alarm on two low pins from deep sleep." -msgstr "Derin uykudan uyanırken yalnızca iki düşük pinde alarm tetiklenebilir." - -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Can't construct AudioOut because continuous channel already open" -msgstr "AudioOut oluşturulamıyor çünkü kesintisiz kanal zaten açık" +#: extmod/ulab/code/ndarray.c +msgid "can only specify one unknown dimension" +msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "Can't set CCCD on local Characteristic" -msgstr "Yerel Karakteristikte CCCD ayarlanamaz" +#: extmod/ulab/code/ndarray.c +msgid "cannot reshape array" +msgstr "" -#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c -#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c -#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c -msgid "Cannot change USB devices now" -msgstr "USB aygıtları şu an değiştirilemez" +#: extmod/ulab/code/ndarray.c +msgid "cannot assign new shape" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Cannot create a new Adapter; use _bleio.adapter;" -msgstr "yeni Adaptör oluşturulamadı; _bleio.adapter kullanın;" +#: extmod/ulab/code/ndarray.c +msgid "function is defined for ndarrays only" +msgstr "" -#: shared-module/i2cioexpander/IOExpander.c -msgid "Cannot deinitialize board IOExpander" -msgstr "Kart IOExpander'ı devreden çıkarılamıyor" +#: extmod/ulab/code/ndarray_operators.c +msgid "operation not supported for the input types" +msgstr "" -#: shared-bindings/displayio/Bitmap.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -msgid "Cannot delete values" -msgstr "Değerler silinemez" +#: extmod/ulab/code/ndarray_operators.c +msgid "dtype of int32 is not supported" +msgstr "" -#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c -#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c -#: ports/nordic/common-hal/digitalio/DigitalInOut.c -#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c -msgid "Cannot get pull while in output mode" -msgstr "Çıkış modundayken çekme alınamıyor" +#: extmod/ulab/code/ndarray_operators.c +msgid "cannot cast output with casting rule" +msgstr "" -#: ports/nordic/common-hal/microcontroller/Processor.c -msgid "Cannot get temperature" -msgstr "Isı okunamadı" +#: extmod/ulab/code/ndarray_operators.c +msgid "results cannot be cast to specified type" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -#, fuzzy -msgid "Cannot have scan responses for extended, connectable advertisements." -msgstr "Genişletilmiş, bağlanabilir reklamlar için tarama yanıtları yapılamaz." +#: extmod/ulab/code/numpy/approx.c +msgid "interp is defined for 1D iterables of equal length" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot pull on input-only pin." -msgstr "Sadece giriş olan pinde pull ayarlanamaz." +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D iterables" +msgstr "" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Cannot record to a file" -msgstr "Dosyaya kayıt yapılamıyor" +#: extmod/ulab/code/numpy/approx.c +msgid "trapz is defined for 1D arrays of equal length" +msgstr "" -#: shared-module/storage/__init__.c -msgid "Cannot remount path when visible via USB." -msgstr "USB üzerinden görünür durumdayken yol yeniden bağlanamaz." +#: extmod/ulab/code/numpy/bitwise.c +msgid "not supported for input types" +msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Cannot set value when direction is input." -msgstr "Yön, giriş olduğunda değer ayarlanamıyor." +#: extmod/ulab/code/numpy/carray/carray.c +msgid "function is implemented for ndarrays only" +msgstr "" -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "Cannot specify RTS or CTS in RS485 mode" -msgstr "RS485 modunda RTS veya CTS belirtilemez" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be an ndarray, or a scalar" +msgstr "" -#: py/objslice.c -msgid "Cannot subclass slice" -msgstr "Alt sınıf kesilemez" +#: extmod/ulab/code/numpy/carray/carray.c +msgid "input must be a 1D ndarray" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "GPIO0..15, GPIO32..47 ile birlikte kullanılamaz" +#: extmod/ulab/code/numpy/carray/carray_tools.c +msgid "not implemented for complex dtype" +msgstr "" -#: ports/nordic/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge, only level" -msgstr "Pin kenarı ile uyandırılamaz, yalnızca seviye ile uyanabilir" +#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c +#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c +#: extmod/ulab/code/numpy/vector.c +msgid "wrong input type" +msgstr "" -#: ports/espressif/common-hal/alarm/pin/PinAlarm.c -msgid "Cannot wake on pin edge. Only level." +#: extmod/ulab/code/numpy/create.c +msgid "input argument must be an integer, a tuple, or a list" msgstr "" -#: shared-bindings/_bleio/CharacteristicBuffer.c -msgid "CharacteristicBuffer writing not provided" -msgstr "CharacteristicBuffer yazılmı sağlanmadı" +#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c +msgid "wrong number of arguments" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "CircuitPython core code crashed hard. Whoops!\n" -msgstr "CircuitPython kor kodu patladı. Haydaaa!\n" +#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c +msgid "divide by zero" +msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Clock unit in use" -msgstr "Saat ünitesi kullanımda" +#: extmod/ulab/code/numpy/create.c +msgid "arange: cannot compute length" +msgstr "" -#: shared-bindings/_bleio/Connection.c -msgid "" -"Connection has been disconnected and can no longer be used. Create a new " -"connection." -msgstr "Bağlantı koparıldı ve tekrar kullanılamaz. Yeni bir bağlantı kurun." +#: extmod/ulab/code/numpy/create.c +msgid "first argument must be a tuple of ndarrays" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays have different lengths" -msgstr "Kordinat dizilerinin uzunlukları farklı" +#: extmod/ulab/code/numpy/create.c +msgid "only ndarrays can be concatenated" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Coordinate arrays types have different sizes" -msgstr "Kordinat dizilerinin türlerifarklı boyutlara sahip" +#: extmod/ulab/code/numpy/create.c +msgid "wrong axis specified" +msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c -msgid "Could not allocate DMA capable buffer" -msgstr "DMA yetenekli tampon tahsis edilemedi" +#: extmod/ulab/code/numpy/create.c +msgid "input arrays are not compatible" +msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "Could not publish to ROS topic" -msgstr "ROS konusuna yayımlanamadı" +#: extmod/ulab/code/numpy/create.c +msgid "input must be 1- or 2-d" +msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Could not set address" -msgstr "Adres ayarlanamadı" +#: extmod/ulab/code/numpy/create.c +msgid "number of points must be at least 2" +msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Could not start interrupt, RX busy" -msgstr "Kesinti başlatılamadı, RX kullanımda" +#: extmod/ulab/code/numpy/create.c +msgid "offset must be non-negative and no greater than buffer length" +msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Couldn't allocate decoder" -msgstr "Deşifre edici tahsis edilemedi" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer size must be a multiple of element size" +msgstr "" -#: ports/espressif/common-hal/rclcpy/__init__.c -#, c-format -msgid "Critical ROS failure during soft reboot, reset required: %d" +#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c +msgid "buffer is smaller than requested size" msgstr "" -"Yazılımsal yeniden başlatma sırasında kritik ROS hatası, sıfırlama " -"gerekiyor: %d" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Channel Init Error" -msgstr "DAC kanalı başlatma hatası" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is defined for ndarrays only" +msgstr "FFT sadece ndarrays'te tanımlandı" -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "DAC Device Init Error" -msgstr "DAC cihazı başlatma hatası" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "FFT is implemented for linear arrays only" +msgstr "FFT yalnızca doğrusal diziler için uygulanır" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "DAC already in use" -msgstr "DAC zaten kullanımda" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "input array length must be power of 2" +msgstr "" -#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c -msgid "Data 0 pin must be byte aligned" -msgstr "Data 0 pini bite hizalı olmalı" +#: extmod/ulab/code/numpy/fft/fft_tools.c +msgid "real and imaginary parts must be of equal length" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Data format error (may be broken data)" -msgstr "Veri formatı hatası (bozuk veri olabilir)" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be ndarrays" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data not supported with directed advertising" -msgstr "Veri, hedefli reklamcılıkla desteklenmemektedir" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must be linear arrays" +msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Data too large for advertisement packet" -msgstr "Veri, reklam paketi için çok büyük" +#: extmod/ulab/code/numpy/filter.c +msgid "convolve arguments must not be empty" +msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Deep sleep pins must use a rising edge with pulldown" +#: extmod/ulab/code/numpy/io/io.c +msgid "corrupted file" msgstr "" -"Derin uyku pinleri, aşağı çekme direnci ile yükselen kenar kullanmalıdır" -#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c -msgid "Destination capacity is smaller than destination_length." -msgstr "Hedef kapasitesi, hedef_uzunluğundan daha küçük." +#: extmod/ulab/code/numpy/io/io.c +msgid "wrong dtype" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Device error or wrong termination of input stream" +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols keyword must be specified" +msgstr "" + +#: extmod/ulab/code/numpy/io/io.c +msgid "empty file" msgstr "" -#: ports/nordic/common-hal/audiobusio/I2SOut.c -msgid "Device in use" -msgstr "Cihaz kullanımda" - -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -msgid "Display must have a 16 bit colorspace." -msgstr "Ekran 16 bitlik bir renk uzayına sahip olmalıdır." +#: extmod/ulab/code/numpy/io/io.c +msgid "usecols is too high" +msgstr "" -#: shared-bindings/busdisplay/BusDisplay.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-bindings/mipidsi/Display.c -msgid "Display rotation must be in 90 degree increments" -msgstr "Ekran dönüşü 90 derecelik artışlarla olmalıdır" +#: extmod/ulab/code/numpy/io/io.c +msgid "array has too many dimensions" +msgstr "" -#: main.c -msgid "Done" -msgstr "Tamamlandı" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "input matrix is asymmetric" +msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Drive mode not used when direction is input." -msgstr "Yön, giriş olduğunda sürüş modu kullanılmaz." +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "matrix is not positive definite" +msgstr "" -#: py/obj.c -msgid "During handling of the above exception, another exception occurred:" -msgstr "Yukarıdaki hatanın işlenmesi sırasında başka bir hata oluştu:" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "iterations did not converge" +msgstr "" -#: shared-bindings/aesio/aes.c -msgid "ECB only operates on 16 bytes at a time" -msgstr "ECB aynı anda yalnızca 16 baytla çalışır" +#: extmod/ulab/code/numpy/linalg/linalg.c +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "input matrix is singular" +msgstr "" -#: py/asmxtensa.c -msgid "ERROR: %q %q not word-aligned" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for ndarrays only" msgstr "" -#: py/asmxtensa.c -msgid "ERROR: xtensa %q out of range" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "operation is defined for 2D arrays only" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -#: ports/espressif/common-hal/canio/CAN.c -#: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "ESP-IDF memory allocation failed" +#: extmod/ulab/code/numpy/linalg/linalg.c +msgid "mode must be complete, or reduced" msgstr "" -#: extmod/modre.c -msgid "Error in regex" -msgstr "regex'te hata" +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get argmin/argmax of an empty sequence" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Error in safemode.py." +#: extmod/ulab/code/numpy/numerical.c +msgid "attempt to get (arg)min/(arg)max of empty sequence" msgstr "" -#: shared-bindings/alarm/__init__.c -msgid "Expected a kind of %q" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +msgid "axis must be None, or an integer" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Extended advertisements with scan response not supported." +#: extmod/ulab/code/numpy/numerical.c +msgid "operation is not implemented on ndarrays" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is defined for ndarrays only" -msgstr "FFT sadece ndarrays'te tanımlandı" +#: extmod/ulab/code/numpy/numerical.c +msgid "input must be tuple, list, range, or ndarray" +msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "FFT is implemented for linear arrays only" -msgstr "FFT yalnızca doğrusal diziler için uygulanır" +#: extmod/ulab/code/numpy/numerical.c +msgid "sort argument must be an ndarray" +msgstr "" -#: shared-bindings/ps2io/Ps2.c -msgid "Failed sending command." -msgstr "Komut gönderilemedi." +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort argument must be an ndarray" +msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to acquire mutex, err 0x%04x" -msgstr "Muteks alınamadı, err 0x%04x" +#: extmod/ulab/code/numpy/numerical.c +msgid "argsort is not implemented for flattened arrays" +msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Failed to add service TXT record" +#: extmod/ulab/code/numpy/numerical.c +msgid "axis too long" msgstr "" -#: shared-bindings/mdns/Server.c -msgid "" -"Failed to add service TXT record; non-string or bytes found in txt_records" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c +msgid "arguments must be ndarrays" msgstr "" -#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c -msgid "Failed to allocate %q buffer" +#: extmod/ulab/code/numpy/numerical.c +msgid "cross is defined for 1D arrays of length 3" msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -msgid "Failed to allocate Wifi memory" +#: extmod/ulab/code/numpy/numerical.c +msgid "diff argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/wifi/ScannedNetworks.c -msgid "Failed to allocate wifi scan memory" +#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c +#: ports/espressif/common-hal/pulseio/PulseIn.c +#: shared-bindings/bitmaptools/__init__.c +msgid "index out of range" msgstr "" -#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c -msgid "Failed to buffer the sample" +#: extmod/ulab/code/numpy/numerical.c +msgid "differentiation order out of range" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: internal error" -msgstr "Bağlantı kurulamadı: internal error" +#: extmod/ulab/code/numpy/numerical.c +msgid "flip argument must be an ndarray" +msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Failed to connect: timeout" -msgstr "Bağlantı kurulamadı: timeout" +#: extmod/ulab/code/numpy/numerical.c +msgid "wrong axis index" +msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid arg" +#: extmod/ulab/code/numpy/numerical.c +msgid "median argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: invalid state" +#: extmod/ulab/code/numpy/numerical.c +msgid "roll argument must be an ndarray" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: no mem" +#: extmod/ulab/code/numpy/poly.c +msgid "input data must be an iterable" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to create continuous channels: not found" +#: extmod/ulab/code/numpy/poly.c +msgid "more degrees of freedom than data points" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to enable continuous" +#: extmod/ulab/code/numpy/poly.c +msgid "input vectors must be of equal length" msgstr "" -#: shared-module/audiomp3/MP3Decoder.c -msgid "Failed to parse MP3 file" -msgstr "MP3 dosyası ayrıştırılamadı" +#: extmod/ulab/code/numpy/poly.c +msgid "could not invert Vandermonde matrix" +msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to register continuous events callback" +#: extmod/ulab/code/numpy/poly.c +msgid "input is not iterable" msgstr "" -#: ports/nordic/sd_mutex.c -#, c-format -msgid "Failed to release mutex, err 0x%04x" -msgstr "Muteks serbest bırakılamadı, err 0x%04x" +#: extmod/ulab/code/numpy/random/random.c +msgid "argument must be None, an integer or a tuple of integers" +msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "Failed to set SPI Clock Mode" +#: extmod/ulab/code/numpy/random/random.c +msgid "shape must be None, and integer or a tuple of integers" msgstr "" -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Failed to set hostname" +#: extmod/ulab/code/numpy/random/random.c +msgid "out has wrong type" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "Failed to start async audio" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array has wrong type" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Failed to write internal flash." -msgstr "Dahili flaş yazılamadı." +#: extmod/ulab/code/numpy/random/random.c +msgid "size must match out.shape when used together" +msgstr "" -#: py/moderrno.c -msgid "File exists" -msgstr "Dosya var" +#: extmod/ulab/code/numpy/random/random.c +msgid "output array must be contiguous" +msgstr "" -#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c -msgid "File not found" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of condition array" msgstr "" -#: ports/atmel-samd/common-hal/canio/Listener.c -#: ports/espressif/common-hal/canio/Listener.c -#: ports/mimxrt10xx/common-hal/canio/Listener.c -#: ports/stm/common-hal/canio/Listener.c -msgid "Filters too complex" -msgstr "Filtreler çok karmaşık" +#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c +msgid "first argument must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is duplicate" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong index type" msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is invalid" -msgstr "Yazılım geçersiz" +#: extmod/ulab/code/numpy/transform.c +msgid "wrong length of index array" +msgstr "" -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Firmware is too big" -msgstr "Yazılım çok büyük" +#: extmod/ulab/code/numpy/transform.c +msgid "dimensions do not match" +msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be an ndarray" msgstr "" -"L8 renk uzayı için, giriş bitmap'i piksel başına 8 bayta sahip olmalıdır" -#: shared-bindings/bitmaptools/__init__.c -msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" +#: extmod/ulab/code/numpy/vector.c +msgid "out must be of float dtype" msgstr "" -"RGB renk uzayı için, giriş bitmap'i piksel başına 16 bayta sahip olmalıdır" -#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c -msgid "Format not supported" -msgstr "Format desteklenmiyor" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output dimensions differ" +msgstr "" -#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c -msgid "" -"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" +#: extmod/ulab/code/numpy/vector.c +msgid "input and output shapes differ" msgstr "" -"Frekans 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 ya da 1008 Mhz " -"olmalıdır" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Fonksiyon kilit gerektirir" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for function" +msgstr "" -#: ports/cxd56/common-hal/gnss/GNSS.c -msgid "GNSS init" -msgstr "GNSS init" +#: extmod/ulab/code/numpy/vector.c +msgid "out keyword is not supported for complex dtype" +msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Generic Failure" +#: extmod/ulab/code/numpy/vector.c +msgid "dtype must be float, or complex" msgstr "" -#: ports/zephyr-cp/bindings/zephyr_display/Display.c -#: shared-bindings/framebufferio/FramebufferDisplay.c -#: shared-module/busdisplay/BusDisplay.c -#: shared-module/framebufferio/FramebufferDisplay.c -msgid "Group already used" -msgstr "Grup zaten kullanılıyor" +#: extmod/ulab/code/numpy/vector.c +msgid "can't convert complex to float" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Hard fault: memory access or instruction error." +#: extmod/ulab/code/numpy/vector.c +msgid "input dtype must be float or complex" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c -#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c -#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c -#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c -msgid "Hardware in use, try alternative pins" -msgstr "Donanım kullanımda, alternatif pinleri deneyin" +#: extmod/ulab/code/numpy/vector.c +msgid "first argument must be a callable" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Heap allocation when VM not running." +#: extmod/ulab/code/numpy/vector.c +msgid "wrong output type" msgstr "" -#: extmod/vfs_posix_file.c py/objstringio.c -msgid "I/O operation on closed file" -msgstr "Kapalı dosyada I/O işlemi" +#: extmod/ulab/code/scipy/linalg/linalg.c +msgid "first two arguments must be ndarrays" +msgstr "" -#: ports/stm/common-hal/busio/I2C.c -msgid "I2C init error" -msgstr "I2C init hatası" +#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c +msgid "input must be a dense ndarray" +msgstr "" -#: ports/raspberrypi/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "I2C peripheral in use" -msgstr "I2C çevre cihazı kullanımda" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "first argument must be a function" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "In-buffer elements must be <= 4 bytes long" -msgstr "Buffer öğeleri <=4 bayt uzunluğunda olmalı" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "function has the same sign at the ends of interval" +msgstr "" -#: shared-bindings/_pew/PewPew.c -msgid "Incorrect buffer size" -msgstr "Yanlış buffer size" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter should be > 0" +msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Init program size invalid" -msgstr "Init program boyutu geçersiz" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "maxiter must be > 0" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin direction conflicts with initial out pin direction" -msgstr "İlk pin yönü, ilk çıkış pin yönüyle çakışıyor" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be iterable" +msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Initial set pin state conflicts with initial out pin state" -msgstr "İlk pinin durumu, ilk çıkış pininin durumu ile çakışıyor" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "initial values must be iterable" +msgstr "" -#: shared-bindings/bitops/__init__.c -#, c-format -msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" -msgstr "Giriş buffer uzunluğu (%d) strand sayımının (%d) katı olmalıdır" +#: extmod/ulab/code/scipy/optimize/optimize.c +msgid "data must be of equal length" +msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -msgid "Input taking too long" -msgstr "Giriş çok uzun sürüyor" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sosfilt requires iterable arguments" +msgstr "" -#: py/moderrno.c -msgid "Input/output error" -msgstr "Giriş/çıkış hatası" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "input must be one-dimensional" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient authentication" -msgstr "Yetersiz kimlik doğrulama" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be an ndarray" +msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Insufficient encryption" -msgstr "Yetersiz şifreleme" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of shape (n_section, 2)" +msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient memory pool for the image" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "zi must be of float type" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Insufficient stream input buffer" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos array must be of shape (n_section, 6)" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Interface must be started" -msgstr "Arayüz başlatılmalıdır" +#: extmod/ulab/code/scipy/signal/signal.c +msgid "sos[:, 3] should be all ones" +msgstr "" -#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c -msgid "Internal audio buffer too small" -msgstr "Dahili ses arabelleği çok küçük" +#: extmod/ulab/code/ulab_tools.c +msgid "axis is out of bounds" +msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "Internal define error" -msgstr "Dahili tanımlama hatası" +#: extmod/ulab/code/ulab_tools.c +msgid "size is defined for ndarrays only" +msgstr "" -#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c -#: supervisor/shared/settings.c -msgid "Internal error" -msgstr "Dahili hata" +#: extmod/ulab/code/ulab_tools.c +msgid "input must be square matrix" +msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -#, c-format -msgid "Internal error #%d" -msgstr "Dahili hata #%d" +#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c +msgid "input must be an ndarray" +msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: ports/atmel-samd/common-hal/countio/Counter.c -#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c -#: ports/atmel-samd/common-hal/max3421e/Max3421E.c -#: ports/atmel-samd/common-hal/ps2io/Ps2.c -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-bindings/pwmio/PWMOut.c -msgid "Internal resource(s) in use" +#: extmod/ulab/code/utils/utils.c +msgid "out must be a float dense array" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Internal watchdog timer expired." -msgstr "Dahili bekçi zamanlayıcısının süresi doldu." +#: extmod/ulab/code/utils/utils.c +msgid "offset is too large" +msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Interrupt error." +#: extmod/ulab/code/utils/utils.c +msgid "out array is too small" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Interrupted by output function" +#: extmod/vfs_fat.c py/moderrno.c +msgid "Read-only filesystem" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/analog/peripherals/max32690/max32_i2c.c -#: ports/analog/peripherals/max32690/max32_spi.c -#: ports/analog/peripherals/max32690/max32_uart.c -#: ports/espressif/common-hal/_bleio/Service.c -#: ports/espressif/common-hal/espulp/ULP.c -#: ports/espressif/common-hal/microcontroller/Processor.c -#: ports/espressif/common-hal/mipidsi/Display.c -#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c -#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c -#: ports/raspberrypi/bindings/picodvi/Framebuffer.c -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/epaperdisplay/EPaperDisplay.c -#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c -#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -#: shared-module/lvfontio/OnDiskFont.c -msgid "Invalid %q" -msgstr "Geçersiz %q" +#: extmod/vfs_posix_file.c py/objstringio.c +msgid "I/O operation on closed file" +msgstr "Kapalı dosyada I/O işlemi" -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c -#: shared-module/aurora_epaper/aurora_framebuffer.c -msgid "Invalid %q and %q" +#: extmod/vfs_posix_file.c +msgid "poll on file not available on win32" msgstr "" -#: ports/atmel-samd/common-hal/microcontroller/Pin.c -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c -#: shared-bindings/microcontroller/Pin.c -msgid "Invalid %q pin" -msgstr "Geersi %q pin" +#: main.c +msgid "Done" +msgstr "Tamamlandı" -#: ports/stm/common-hal/analogio/AnalogIn.c -msgid "Invalid ADC Unit value" -msgstr "Geçersiz ADC Ünite değeri" +#: main.c +msgid " output:\n" +msgstr " çıktı:\n" -#: ports/espressif/common-hal/_bleio/__init__.c -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Invalid BLE parameter" -msgstr "Geçersiz BLE parametresi" +#: main.c +msgid "" +"Auto-reload is on. Simply save files over USB to run them or enter REPL to " +"disable.\n" +msgstr "" +"Otomatik yeniden yükleme aktif. Dosyaları çalıştırmak için USB aracılığı ile " +"kaydedin ya da deaktif etmek için REPL moda girin.\n" + +#: main.c +msgid "Auto-reload is off.\n" +msgstr "Otomatik yeniden yükleme devre dışı.\n" -#: shared-bindings/wifi/Radio.c -msgid "Invalid BSSID" -msgstr "Geçersiz BSSID" +#: main.c +msgid "Running in safe mode! Not running saved code.\n" +msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "Invalid MAC address" -msgstr "Geçersiz MAC adresi" +#: main.c +msgid " not found.\n" +msgstr " bulunamadı.\n" -#: ports/espressif/common-hal/rclcpy/__init__.c -msgid "Invalid ROS domain ID" +#: main.c +msgid "WARNING: Your code filename has two extensions\n" msgstr "" -#: ports/zephyr-cp/common-hal/_bleio/Adapter.c -msgid "Invalid advertising data" +#: main.c +msgid "" +"\n" +"Code stopped by auto-reload. Reloading soon.\n" msgstr "" +"\n" +"Program otomatik yeniden yükleme tarafından durduruldu. Birazdan tekrar " +"yüklenecek.\n" -#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c -msgid "Invalid argument" -msgstr "Geçersiz argüman" +#: main.c +msgid "" +"\n" +"Code done running.\n" +msgstr "" +"\n" +"Program çalıştırıldı.\n" -#: shared-module/displayio/Bitmap.c -#, fuzzy -msgid "Invalid bits per value" -msgstr "Geçersiz bit başına değer" +#: main.c +msgid "Woken up by alarm.\n" +msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c -#, c-format -msgid "Invalid data_pins[%d]" -msgstr "Geçersiz veri_pini [%d]" +#: main.c +msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +msgstr "" +"REPL moda girmek için herhangi bir tuşa basınız. Programı yeniden yüklemek " +"için CTRL+D tuş kombinasyonunu kullanabilirsiniz.\n" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" +#: main.c +msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" msgstr "" +"Alarma, CTRL-C'ye veya dosya yazana kadar derin uyku moduna geçiliyor.\n" -#: shared-module/audiocore/WaveFile.c -msgid "Invalid format chunk size" -msgstr "Geçersiz biçim yığın boyutu" +#: main.c +msgid "UID:" +msgstr "UID:" -#: shared-bindings/wifi/Radio.c -msgid "Invalid hex password" +#: main.c +msgid "soft reboot\n" msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "Invalid multicast MAC address" -msgstr "Geçersiz multicast MAC adresi" +#: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c +#: ports/stm/common-hal/audioio/AudioOut.c +#: shared-bindings/digitalio/DigitalInOutProtocol.c +#: shared-module/busdisplay/BusDisplay.c +msgid "%q init failed" +msgstr "%q init başarısız oldu" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Invalid size" -msgstr "Geçersiz boyut" +#: ports/analog/common-hal/busio/SPI.c +msgid "SPI needs MOSI, MISO, and SCK" +msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "Invalid socket for TLS" -msgstr "TLS için geçersiz soket" +#: ports/analog/common-hal/busio/SPI.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/argcheck.c +#: shared-bindings/bitmaptools/__init__.c shared-bindings/canio/Match.c +#: shared-bindings/time/__init__.c +msgid "%q out of range" +msgstr "%q aralık dışında" #: ports/analog/common-hal/busio/SPI.c #: ports/espressif/common-hal/espidf/__init__.c @@ -1443,142 +751,205 @@ msgstr "TLS için geçersiz soket" msgid "Invalid state" msgstr "Geçersiz durum" -#: supervisor/shared/settings.c -msgid "Invalid unicode escape" +#: ports/analog/common-hal/busio/SPI.c +msgid "Failed to set SPI Clock Mode" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Key must be 16, 24, or 32 bytes long" -msgstr "Anahtar 16, 24 veya 32 bayt uzunluğunda olmalıdır" - -#: shared-module/is31fl3741/FrameBuffer.c -msgid "LED mappings must match display size" -msgstr "LED eşlemeleri ekran boyutuyla eşleşmelidir" +#: ports/analog/common-hal/busio/UART.c +#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c +msgid "RS485" +msgstr "RS485" -#: py/compile.c -msgid "LHS of keyword arg must be an id" +#: ports/analog/common-hal/busio/UART.c +msgid "UART needs TX & RX" msgstr "" -#: shared-module/displayio/Group.c -msgid "Layer already in a group" -msgstr "Katman zaten bir grupta" - -#: shared-module/displayio/Group.c -msgid "Layer must be a Group or TileGrid subclass" -msgstr "Katman, bir Grup ya da TileGrid alt sınıfı olmalıdır" +#: ports/analog/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Both RX and TX required for flow control" +msgstr "Hem RX hem de TX akış kontrolü için gerekli" -#: shared-bindings/audiocore/RawSample.c -msgid "Length of %q must be an even multiple of channel_count * type_size" +#: ports/analog/common-hal/busio/UART.c shared-module/rgbmatrix/RGBMatrix.c +msgid "Failed to allocate %q buffer" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "MAC address was invalid" -msgstr "MAC adresi geçersiz" - -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/espressif/common-hal/_bleio/Descriptor.c -msgid "MITM security not supported" +#: ports/analog/common-hal/busio/UART.c +msgid "UART read error" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "MMC/SDIO Clock Error %x" +#: ports/analog/common-hal/busio/UART.c +msgid "UART transaction timeout" msgstr "" -#: shared-bindings/is31fl3741/IS31FL3741.c -msgid "Mapping must be a tuple" -msgstr "Map tuple olmalıdır" +#: ports/analog/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/nordic/common-hal/busio/UART.c +msgid "All UART peripherals are in use" +msgstr "Tüm UART çevre birimleri kullanımda" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap must have 8 bits per pixel" -msgstr "" +#: ports/analog/common-hal/busio/UART.c +#: ports/analog/peripherals/max32690/max32_i2c.c +#: ports/analog/peripherals/max32690/max32_spi.c +#: ports/analog/peripherals/max32690/max32_uart.c +#: ports/espressif/common-hal/_bleio/Service.c +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/microcontroller/Processor.c +#: ports/espressif/common-hal/mipidsi/Display.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/pwmio/PWMOut.c +#: ports/raspberrypi/bindings/picodvi/Framebuffer.c +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c py/argcheck.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/mipidsi/Display.c +#: shared-bindings/pwmio/PWMOut.c shared-bindings/supervisor/__init__.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +#: shared-module/lvfontio/OnDiskFont.c +msgid "Invalid %q" +msgstr "Geçersiz %q" -#: shared-bindings/bitmaptools/__init__.c -msgid "Mask bitmap size must match the other bitmaps" +#: ports/analog/common-hal/busio/UART.c +msgid "Timeout must be < 100 seconds" msgstr "" -#: py/persistentcode.c -msgid "MicroPython .mpy file; use CircuitPython mpy-cross" -msgstr "" +#: ports/atmel-samd/audio_dma.c +msgid "All sync event channels in use" +msgstr "Tüm asenkron olay kanalları kullanımda" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched data size" -msgstr "" +#: ports/atmel-samd/audio_dma.c ports/raspberrypi/audio_dma.c +msgid "Internal audio buffer too small" +msgstr "Dahili ses arabelleği çok küçük" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Mismatched swap flag" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is read only" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] reads pin(s)" +#: ports/atmel-samd/bindings/samd/Clock.c +msgid "calibration is out of range" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" +#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h +#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h +#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h +msgid "You pressed both buttons at start up." msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_in_pin. %q[%u] waits based on pin" +#: ports/atmel-samd/common-hal/_pew/PewPew.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +#: ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/peripherals/nrf/timers.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "All timers in use" +msgstr "Tüm zamanlayıcılar kullanımda" + +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: ports/atmel-samd/common-hal/countio/Counter.c +#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c +#: ports/atmel-samd/common-hal/max3421e/Max3421E.c +#: ports/atmel-samd/common-hal/ps2io/Ps2.c +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +msgid "Internal resource(s) in use" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" +#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c +#: supervisor/shared/safe_mode.c +msgid "Unknown reason." msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_out_pin. %q[%u] writes pin(s)" +#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c +#: ports/nordic/common-hal/alarm/time/TimeAlarm.c +#: ports/stm/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing first_set_pin. %q[%u] sets pin(s)" +#: ports/atmel-samd/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "No DAC on chip" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Missing jmp_pin. %q[%u] jumps on pin" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "%q and %q must share a clock unit" +msgstr "%q ve %q bir saat birimi paylaşmalıdır" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +msgid "Serializer in use" msgstr "" -#: shared-module/storage/__init__.c -msgid "Mount point directory missing" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Clock unit in use" +msgstr "Saat ünitesi kullanımda" + +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/atmel-samd/common-hal/touchio/TouchIn.c +msgid "No free GCLKs" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c -msgid "Must be a %q subclass." +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +msgid "Too many channels in sample" msgstr "" -#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c -msgid "Must provide 5/6/5 RGB pins" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "No DMA channel found" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c -msgid "Must provide MISO or MOSI pin" +#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Unable to allocate buffers for signed conversion" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c #, c-format -msgid "Must use a multiple of 6 rgb pins, not %d" +msgid "Only 8 or 16 bit mono with %dx oversampling supported." msgstr "" -#: supervisor/shared/safe_mode.c -msgid "NLR jump failed. Likely memory corruption." +#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c +#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c +msgid "sampling rate out of range" msgstr "" -#: ports/espressif/common-hal/nvm/ByteArray.c -msgid "NVS Error" -msgstr "NVS hatası" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "DAC already in use" +msgstr "DAC zaten kullanımda" -#: shared-bindings/socketpool/SocketPool.c -msgid "Name or service not known" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "Right channel unsupported" msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "New bitmap must be same size as old bitmap" -msgstr "" +#: ports/atmel-samd/common-hal/audioio/AudioOut.c +msgid "All event channels in use" +msgstr "Tüm olay kanalları kullanımda" -#: ports/espressif/common-hal/_bleio/__init__.c -msgid "Nimble out of memory" +#: ports/atmel-samd/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/I2C.c +#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/busio/I2C.c +msgid "No pull up found on SDA or SCL; check your wiring" msgstr "" +#: ports/atmel-samd/common-hal/busio/UART.c +msgid "%q must be power of 2" +msgstr "%q, 2'nin kuvveti olmalıdır" + #: ports/atmel-samd/common-hal/busio/UART.c #: ports/espressif/common-hal/busio/SPI.c #: ports/espressif/common-hal/busio/UART.c @@ -1593,37 +964,46 @@ msgstr "" msgid "No %q pin" msgstr "%q pini yok" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -msgid "No CCCD for this Characteristic" -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "All RX FIFOs in use" +msgstr "Tüm RX FIFO'ları kullanımda" -#: ports/atmel-samd/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/analogio/AnalogOut.c -#: ports/stm/common-hal/audioio/AudioOut.c -msgid "No DAC on chip" -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +msgid "Already have all-matches listener" +msgstr "Tüm eşleşmelerle eşleşen dinleyiciniz var" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "No DMA channel found" -msgstr "" +#: ports/atmel-samd/common-hal/canio/Listener.c +#: ports/espressif/common-hal/canio/Listener.c +#: ports/mimxrt10xx/common-hal/canio/Listener.c +#: ports/stm/common-hal/canio/Listener.c +msgid "Filters too complex" +msgstr "Filtreler çok karmaşık" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "No DMA pacing timer found" -msgstr "" +#: ports/atmel-samd/common-hal/digitalio/DigitalInOut.c +#: ports/mimxrt10xx/common-hal/digitalio/DigitalInOut.c +#: ports/nordic/common-hal/digitalio/DigitalInOut.c +#: ports/raspberrypi/common-hal/digitalio/DigitalInOut.c +msgid "Cannot get pull while in output mode" +msgstr "Çıkış modundayken çekme alınamıyor" -#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c #, c-format -msgid "No I2C device at address: 0x%x" +msgid "Invalid data_pins[%d]" +msgstr "Geçersiz veri_pini [%d]" + +#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#, c-format +msgid "data pin #%d in use" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "No IP" -msgstr "IP yok" +#: ports/atmel-samd/common-hal/microcontroller/Pin.c +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +#: ports/mimxrt10xx/common-hal/microcontroller/Pin.c +#: shared-bindings/microcontroller/Pin.c +msgid "Invalid %q pin" +msgstr "Geersi %q pin" #: ports/atmel-samd/common-hal/microcontroller/__init__.c #: ports/cxd56/common-hal/microcontroller/__init__.c @@ -1631,362 +1011,606 @@ msgstr "IP yok" msgid "No bootloader present" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No configuration set" +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +msgid "Data 0 pin must be byte aligned" +msgstr "Data 0 pini bite hizalı olmalı" + +#: ports/atmel-samd/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/nordic/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/raspberrypi/common-hal/paralleldisplaybus/ParallelBus.c +#, c-format +msgid "Bus pin %d is already in use" +msgstr "Veriyolu pini %d kullanımda" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +#: ports/cxd56/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/raspberrypi/common-hal/pulseio/PulseIn.c +#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c +#: shared-bindings/ps2io/Ps2.c +msgid "pop from empty %q" +msgstr "" + +#: ports/atmel-samd/common-hal/pulseio/PulseIn.c +msgid "Input taking too long" +msgstr "Giriş çok uzun sürüyor" + +#: ports/atmel-samd/common-hal/pulseio/PulseOut.c +#: ports/cxd56/common-hal/pulseio/PulseOut.c +msgid "Another send is already active" +msgstr "Başka bir gönderme zaten aktif" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "%q failure: %d" +msgstr "%q hata: %d" + +#: ports/atmel-samd/common-hal/sdioio/SDCard.c +#: ports/cxd56/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c +#: shared-module/sdcardio/SDCard.c +#, c-format +msgid "Buffer must be a multiple of %d bytes" +msgstr "Tampon, %d baytların katı olmalıdır" + +#: ports/atmel-samd/common-hal/spitarget/SPITarget.c +msgid "Async SPI transfer in progress on this bus, keep awaiting." +msgstr "" +"Bu veri yolunda asenkron SPI transferi devam ediyor, beklemeye devam edin." + +#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c +#: ports/stm/common-hal/busio/UART.c +msgid "UART init" +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Camera init" +msgstr "Kamerayı başlat" + +#: ports/cxd56/common-hal/camera/Camera.c +msgid "Size not supported" +msgstr "" + +#: ports/cxd56/common-hal/camera/Camera.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/struct/__init__.c shared-module/struct/__init__.c +msgid "Buffer too small" +msgstr "Tampon çok küçük" + +#: ports/cxd56/common-hal/camera/Camera.c shared-module/audiocore/WaveFile.c +msgid "Format not supported" +msgstr "Format desteklenmiyor" + +#: ports/cxd56/common-hal/gnss/GNSS.c +msgid "GNSS init" +msgstr "GNSS init" + +#: ports/cxd56/common-hal/sdioio/SDCard.c +msgid "SDCard init" +msgstr "" + +#: ports/espressif/bindings/espnow/ESPNow.c +#: ports/espressif/common-hal/espulp/ULP.c +#: shared-module/memorymonitor/AllocationAlarm.c +#: shared-module/memorymonitor/AllocationSize.c +msgid "Already running" +msgstr "Halihazırda çalışıyor" + +#: ports/espressif/bindings/espnow/Peer.c shared-bindings/dualbank/__init__.c +msgid "%q is %q" +msgstr "%q %q dir" + +#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h +msgid "You pressed the SW38 button at start up." +msgstr "" + +#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h +#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h +#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +msgid "You pressed the BOOT button at start up." +msgstr "" + +#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h +msgid "You pressed the GPIO0 button at start up." +msgstr "" + +#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h +msgid "You pressed the Rec button at start up." +msgstr "" + +#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h +#: ports/espressif/boards/vidi_x/mpconfigboard.h +msgid "You pressed the VOLUME button at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h +#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h +msgid "You pressed the central button at start up." +msgstr "" + +#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h +#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h +#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h +msgid "You pressed button A at start up." msgstr "" -#: shared-bindings/_bleio/PacketBuffer.c -msgid "No connection: length cannot be determined" +#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h +msgid "You pressed button DOWN at start up." msgstr "" -#: shared-bindings/board/__init__.c -msgid "No default %q bus" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Update failed" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/atmel-samd/common-hal/touchio/TouchIn.c -msgid "No free GCLKs" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Scan already in progress. Stop with stop_scan." msgstr "" -#: shared-bindings/os/__init__.c -msgid "No hardware random available" -msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: internal error" +msgstr "Bağlantı kurulamadı: internal error" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in in program" -msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data too large for advertisement packet" +msgstr "Veri, reklam paketi için çok büyük" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No in or out in program" -msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Already advertising." +msgstr "Halihazırda duyuruluyor." -#: py/objint.c shared-bindings/time/__init__.c -msgid "No long integer support" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Extended advertisements with scan response not supported." msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "No network with that ssid" -msgstr "" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "Data not supported with directed advertising" +msgstr "Veri, hedefli reklamcılıkla desteklenmemektedir" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "No out in program" +#: ports/espressif/common-hal/_bleio/Adapter.c +#: ports/nordic/common-hal/_bleio/Adapter.c +#, c-format +msgid "Timeout is too long: Maximum timeout length is %d seconds" msgstr "" -#: ports/atmel-samd/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/I2C.c -#: ports/mimxrt10xx/common-hal/busio/I2C.c ports/nordic/common-hal/busio/I2C.c -#: ports/raspberrypi/common-hal/busio/I2C.c -msgid "No pull up found on SDA or SCL; check your wiring" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/espressif/common-hal/_bleio/Descriptor.c +msgid "MITM security not supported" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pulldown on pin; 1Mohm recommended" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length != required fixed length" msgstr "" -#: shared-module/touchio/TouchIn.c -msgid "No pullup on pin; 1Mohm recommended" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +msgid "Value length > max_length" msgstr "" -#: py/moderrno.c -msgid "No space left on device" +#: ports/espressif/common-hal/_bleio/Characteristic.c +msgid "Too many descriptors" msgstr "" -#: py/moderrno.c -msgid "No such device" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "No CCCD for this Characteristic" msgstr "" -#: py/moderrno.c -msgid "No such file/directory" +#: ports/espressif/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +msgid "Can't set CCCD on local Characteristic" +msgstr "Yerel Karakteristikte CCCD ayarlanamaz" + +#: ports/espressif/common-hal/_bleio/Connection.c +#: ports/nordic/common-hal/_bleio/Connection.c +msgid "non-UUID found in service_uuids_whitelist" msgstr "" -#: shared-module/rgbmatrix/RGBMatrix.c -msgid "No timer available" +#: ports/espressif/common-hal/_bleio/Descriptor.c +#: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/nordic/common-hal/_bleio/Descriptor.c +#, c-format +msgid "max_length must be 0-%d when fixed_length is %s" msgstr "" -#: shared-module/usb/core/Device.c -msgid "No usb host port initialized" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Writes not supported on Characteristic" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "Nordic system firmware out of memory" +#: ports/espressif/common-hal/_bleio/PacketBuffer.c +#: ports/nordic/common-hal/_bleio/PacketBuffer.c +msgid "Total data to write is larger than %q" msgstr "" -#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c -msgid "Not a valid IP string" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Nimble out of memory" msgstr "" +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Invalid BLE parameter" +msgstr "Geçersiz BLE parametresi" + #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" msgstr "" -#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c -#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c -#: shared-bindings/usb_audio/USBMicrophone.c -msgid "Not playing" +#: ports/espressif/common-hal/_bleio/__init__.c +msgid "Already in progress" +msgstr "Zaten işlemde" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown system firmware error at %s:%d: %d" msgstr "" -#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c -#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/espressif/common-hal/_bleio/__init__.c #, c-format -msgid "Number of data_pins must be %d or %d, not %d" +msgid "Unknown system firmware error: %d" msgstr "" -#: shared-bindings/util.c -msgid "" -"Object has been deinitialized and can no longer be used. Create a new object." +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient authentication" +msgstr "Yetersiz kimlik doğrulama" + +#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Insufficient encryption" +msgstr "Yetersiz şifreleme" + +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error at %s:%d: %d" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -msgid "Odd parity is not supported" +#: ports/espressif/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown BLE error: %d" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Off" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge. Only level." msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Ok" +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot pull on input-only pin." +msgstr "Sadece giriş olan pinde pull ayarlanamaz." + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on two low pins from deep sleep." +msgstr "Derin uykudan uyanırken yalnızca iki düşük pinde alarm tetiklenebilir." + +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on one low pin while others alarm high from deep sleep." msgstr "" +"Derin uykudan uyanırken, diğerleri yüksek seviyede alarm verecek şekilde " +"ayarlanmışken sadece tek bir düşük pinde alarm tetiklenebilir." -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -#, c-format -msgid "Only 8 or 16 bit mono with %dx oversampling supported." +#: ports/espressif/common-hal/alarm/pin/PinAlarm.c +msgid "Can only alarm on RTC IO from deep sleep." +msgstr "Sadece alarm RTC IO'yu uyandırabilir." + +#: ports/espressif/common-hal/alarm/time/TimeAlarm.c +#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c +msgid "Only one alarm.time alarm can be set." msgstr "" -#: ports/espressif/common-hal/wifi/__init__.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -msgid "Only IPv4 addresses supported" +#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c +msgid "Only one %q can be set in deep sleep." msgstr "" -#: ports/raspberrypi/common-hal/socketpool/Socket.c -msgid "Only IPv4 sockets supported" +#: ports/espressif/common-hal/analogbufio/BufferedIn.c +msgid "%q must be array of type 'H'" +msgstr "%q, 'H' dizisi türünde olmalıdır" + +#: ports/espressif/common-hal/audiobusio/PDMIn.c +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q must be 8, 16, 24, or 32" +msgstr "%q 8, 16, 24 veya 32 olmalıdır" + +#: ports/espressif/common-hal/audiobusio/__init__.c +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +msgid "Peripheral in use" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -#, c-format -msgid "" -"Only Windows format, uncompressed BMP supported: given header size is %d" +#: ports/espressif/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 8 or 16" +msgstr "%q 8 veya 16 olmalıdır" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "audio format not supported" msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "Only connectable advertisements can be directed" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to start async audio" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Only edge detection is available on this hardware" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid arg" msgstr "" -#: shared-bindings/ipaddress/__init__.c -msgid "Only int or string supported for ip" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: invalid state" msgstr "" -#: ports/espressif/common-hal/alarm/touch/TouchAlarm.c -msgid "Only one %q can be set in deep sleep." +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: not found" msgstr "" -#: ports/espressif/common-hal/espulp/ULPAlarm.c -msgid "Only one %q can be set." +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to create continuous channels: no mem" msgstr "" -#: ports/espressif/common-hal/i2ctarget/I2CTarget.c -#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c -msgid "Only one address is allowed" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to register continuous events callback" msgstr "" -#: ports/atmel-samd/common-hal/alarm/time/TimeAlarm.c -#: ports/nordic/common-hal/alarm/time/TimeAlarm.c -#: ports/stm/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set" +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Failed to enable continuous" msgstr "" -#: ports/espressif/common-hal/alarm/time/TimeAlarm.c -#: ports/raspberrypi/common-hal/alarm/time/TimeAlarm.c -msgid "Only one alarm.time alarm can be set." +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "Can't construct AudioOut because continuous channel already open" +msgstr "AudioOut oluşturulamıyor çünkü kesintisiz kanal zaten açık" + +#: ports/espressif/common-hal/audioio/AudioOut.c +msgid "already playing" msgstr "" -#: shared-module/displayio/ColorConverter.c -msgid "Only one color can be transparent at a time" -msgstr "" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/nordic/common-hal/busio/I2C.c +msgid "All I2C peripherals are in use" +msgstr "Tüm I2C çevre birimleri kullanımda" -#: py/moderrno.c -msgid "Operation not permitted" +#: ports/espressif/common-hal/busio/I2C.c +#: ports/espressif/common-hal/busio/SPI.c +msgid "Unable to create lock" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Operation or feature not supported" +#: ports/espressif/common-hal/busio/SPI.c +msgid "SPI configuration failed" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/busio/SPI.c ports/nordic/common-hal/busio/SPI.c +msgid "All SPI peripherals are in use" +msgstr "Tüm SPI çevre birimleri kullanımda" + +#: ports/espressif/common-hal/busio/SPI.c +#: ports/espressif/common-hal/canio/CAN.c #: ports/espressif/common-hal/qspibus/QSPIBus.c -msgid "Operation timed out" +msgid "ESP-IDF memory allocation failed" msgstr "" -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Out of MDNS service slots" -msgstr "" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "Cannot specify RTS or CTS in RS485 mode" +msgstr "RS485 modunda RTS veya CTS belirtilemez" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Out of memory" +#: ports/espressif/common-hal/busio/UART.c +#: ports/mimxrt10xx/common-hal/busio/UART.c +msgid "RS485 inversion specified when not in RS485 mode" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/raspberrypi/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Out of sockets" -msgstr "" +#: ports/espressif/common-hal/canio/CAN.c +msgid "Baudrate not supported by peripheral" +msgstr "Baudhızı, çevre birimi tarafından desteklenmiyor" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Out-buffer elements must be <= 4 bytes long" -msgstr "" +#: ports/espressif/common-hal/canio/CAN.c +msgid "All CAN peripherals are in use" +msgstr "Tüm CAN çevre birimleri kullanımda" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "PWM restart" +#: ports/espressif/common-hal/canio/CAN.c +msgid "loopback + silent mode not supported by peripheral" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice already in use" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_driver_install returned esp-idf error #%d" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "PWM slice channel A already in use" +#: ports/espressif/common-hal/canio/CAN.c +#, c-format +msgid "twai_start returned esp-idf error #%d" msgstr "" -#: shared-bindings/spitarget/SPITarget.c -msgid "Packet buffers for an SPI transfer must have the same length." +#: ports/espressif/common-hal/dotclockframebuffer/DotClockFramebuffer.c +msgid "Must provide 5/6/5 RGB pins" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Parameter error" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is duplicate" msgstr "" -#: ports/espressif/common-hal/audiobusio/__init__.c -#: ports/espressif/common-hal/audioi2sin/I2SIn.c -msgid "Peripheral in use" -msgstr "" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is invalid" +msgstr "Yazılım geçersiz" -#: py/moderrno.c -msgid "Permission denied" -msgstr "" +#: ports/espressif/common-hal/dualbank/__init__.c +msgid "Firmware is too big" +msgstr "Yazılım çok büyük" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -msgid "Pin cannot wake from Deep Sleep" +#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c +msgid "no such attribute" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Pin count too large" +#: ports/espressif/common-hal/espcamera/Camera.c +msgid "invalid setting" msgstr "" -#: ports/stm/common-hal/alarm/pin/PinAlarm.c -#: ports/stm/common-hal/pulseio/PulseIn.c -msgid "Pin interrupt already in use" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Generic Failure" msgstr "" -#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c -msgid "Pin is input only" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Out of memory" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "Pin must be on PWM Channel B" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c py/moderrno.c +msgid "Invalid argument" +msgstr "Geçersiz argüman" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "" -"Pinout uses %d bytes per element, which consumes more than the ideal %d " -"bytes. If this cannot be avoided, pass allow_inefficient=True to the " -"constructor" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Invalid size" +msgstr "Geçersiz boyut" -#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c -msgid "Pins must be sequential" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Requested resource not found" msgstr "" -#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c -msgid "Pins must be sequential GPIO pins" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Operation or feature not supported" msgstr "" -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -msgid "Pins must share PWM slice" +#: ports/espressif/common-hal/espidf/__init__.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +msgid "Operation timed out" msgstr "" -#: shared-module/usb/core/Device.c -msgid "Pipe error" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Received response was invalid" msgstr "" -#: py/builtinhelp.c -msgid "Plus any modules on the filesystem\n" -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "CRC or checksum was invalid" +msgstr "CRC yada checksum geçersiz" -#: shared-module/vectorio/Polygon.c -msgid "Polygon needs at least 3 points" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "Version was invalid" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Power dipped. Make sure you are providing enough power." -msgstr "" +#: ports/espressif/common-hal/espidf/__init__.c +msgid "MAC address was invalid" +msgstr "MAC adresi geçersiz" -#: shared-bindings/_bleio/Adapter.c -msgid "Prefix buffer must be on the heap" +#: ports/espressif/common-hal/espidf/__init__.c +#, c-format +msgid "%s error 0x%x" +msgstr "%s hatası 0x%x" + +#: ports/espressif/common-hal/espulp/ULP.c +msgid "Program too long" msgstr "" -#: main.c -msgid "Press any key to enter the REPL. Use CTRL-D to reload.\n" +#: ports/espressif/common-hal/espulp/ULP.c +#: ports/espressif/common-hal/mipidsi/Bus.c +#: ports/espressif/common-hal/qspibus/QSPIBus.c +#: ports/mimxrt10xx/common-hal/audiobusio/__init__.c +#: ports/mimxrt10xx/common-hal/usb_host/Port.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c shared-bindings/microcontroller/Pin.c +#: shared-module/max3421e/Max3421E.c +msgid "%q in use" +msgstr "%q kullanımda" + +#: ports/espressif/common-hal/espulp/ULPAlarm.c +msgid "Only one %q can be set." msgstr "" -"REPL moda girmek için herhangi bir tuşa basınız. Programı yeniden yüklemek " -"için CTRL+D tuş kombinasyonunu kullanabilirsiniz.\n" -#: main.c -msgid "Pretending to deep sleep until alarm, CTRL-C or file write.\n" +#: ports/espressif/common-hal/i2ctarget/I2CTarget.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "Only one address is allowed" msgstr "" -"Alarma, CTRL-C'ye veya dosya yazana kadar derin uyku moduna geçiliyor.\n" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does IN without loading ISR" +#: ports/espressif/common-hal/max3421e/Max3421E.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +#, c-format +msgid "Unknown error code %d" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Program does OUT without loading OSR" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS only works with built-in WiFi" msgstr "" -#: ports/raspberrypi/bindings/rp2pio/StateMachine.c -msgid "Program size invalid" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "mDNS already initialized" msgstr "" -#: ports/espressif/common-hal/espulp/ULP.c -msgid "Program too long" +#: ports/espressif/common-hal/mdns/Server.c +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Unable to start mDNS query" msgstr "" -#: shared-bindings/rclcpy/Publisher.c -msgid "Publishers can only be created from a parent node" +#: ports/espressif/common-hal/memorymap/AddressRange.c +#: ports/nordic/common-hal/memorymap/AddressRange.c +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Address range not allowed" msgstr "" -#: shared-bindings/digitalio/DigitalInOut.c -#: shared-bindings/i2cioexpander/IOPin.c -msgid "Pull not used when direction is output." +#: ports/espressif/common-hal/nvm/ByteArray.c +msgid "NVS Error" +msgstr "NVS hatası" + +#: ports/espressif/common-hal/paralleldisplaybus/ParallelBus.c +#: ports/espressif/common-hal/sdioio/SDCard.c +#, c-format +msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: ports/raspberrypi/common-hal/countio/Counter.c -msgid "RISE_AND_FALL not available on this chip" +#: ports/espressif/common-hal/pulseio/PulseIn.c +msgid "pop from an empty PulseIn" msgstr "" -#: shared-module/displayio/OnDiskBitmap.c -msgid "RLE-compressed BMP not supported" +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-module/usb/core/Device.c +msgid "Could not allocate DMA capable buffer" +msgstr "DMA yetenekli tampon tahsis edilemedi" + +#: ports/espressif/common-hal/qspibus/QSPIBus.c shared-bindings/pwmio/PWMOut.c +#: supervisor/shared/settings.c +msgid "Internal error" +msgstr "Dahili hata" + +#: ports/espressif/common-hal/rclcpy/Node.c +msgid "ROS node failed to initialize" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG DeInit Error" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "ROS topic failed to initialize" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "RNG Init Error" +#: ports/espressif/common-hal/rclcpy/Publisher.c +msgid "Could not publish to ROS topic" +msgstr "ROS konusuna yayımlanamadı" + +#: ports/espressif/common-hal/rclcpy/__init__.c +#, c-format +msgid "Critical ROS failure during soft reboot, reset required: %d" msgstr "" +"Yazılımsal yeniden başlatma sırasında kritik ROS hatası, sıfırlama " +"gerekiyor: %d" #: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS failed to initialize. Is agent connected?" +msgid "ROS memory allocator failure" msgstr "" #: ports/espressif/common-hal/rclcpy/__init__.c @@ -1994,948 +1618,1123 @@ msgid "ROS internal setup failure" msgstr "" #: ports/espressif/common-hal/rclcpy/__init__.c -msgid "ROS memory allocator failure" +msgid "Invalid ROS domain ID" msgstr "" -#: ports/espressif/common-hal/rclcpy/Node.c -msgid "ROS node failed to initialize" +#: ports/espressif/common-hal/rclcpy/__init__.c +msgid "ROS failed to initialize. Is agent connected?" msgstr "" -#: ports/espressif/common-hal/rclcpy/Publisher.c -msgid "ROS topic failed to initialize" +#: ports/espressif/common-hal/sdioio/SDCard.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "SDIO Init Error 0x%02x" msgstr "" -#: ports/analog/common-hal/busio/UART.c -#: ports/atmel-samd/common-hal/busio/UART.c ports/cxd56/common-hal/busio/UART.c -#: ports/nordic/common-hal/busio/UART.c ports/stm/common-hal/busio/UART.c -msgid "RS485" -msgstr "RS485" - -#: ports/espressif/common-hal/busio/UART.c -#: ports/mimxrt10xx/common-hal/busio/UART.c -msgid "RS485 inversion specified when not in RS485 mode" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Unsupported socket type" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c -msgid "RTC is not supported on this board" +#: ports/espressif/common-hal/socketpool/Socket.c +#: ports/raspberrypi/common-hal/socketpool/Socket.c +#: ports/zephyr-cp/common-hal/socketpool/Socket.c +msgid "Out of sockets" msgstr "" -#: ports/stm/common-hal/os/__init__.c -msgid "Random number generation error" +#: ports/espressif/common-hal/socketpool/SocketPool.c +#: ports/raspberrypi/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio" msgstr "" -#: shared-bindings/_bleio/__init__.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c -#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c -msgid "Read-only" -msgstr "" +#: ports/espressif/common-hal/watchdog/WatchDogTimer.c +msgid "%q must be <= %u" +msgstr "%q, %u değerinden küçük veya eşit olmalıdır" -#: extmod/vfs_fat.c py/moderrno.c -msgid "Read-only filesystem" +#: ports/espressif/common-hal/wifi/Monitor.c +msgid "monitor init failed" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Received response was invalid" +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Interface must be started" +msgstr "Arayüz başlatılmalıdır" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Invalid multicast MAC address" +msgstr "Geçersiz multicast MAC adresi" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Already scanning for wifi networks" +msgstr "Halihazırda wifi ağları için tarama yapılıyor" + +#: ports/espressif/common-hal/wifi/Radio.c +#: ports/raspberrypi/common-hal/wifi/Radio.c +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "WiFi is not enabled" msgstr "" -#: supervisor/shared/bluetooth/bluetooth.c -msgid "Reconnecting" +#: ports/espressif/common-hal/wifi/ScannedNetworks.c +msgid "Failed to allocate wifi scan memory" msgstr "" -#: shared-bindings/epaperdisplay/EPaperDisplay.c -msgid "Refresh too soon" +#: ports/espressif/common-hal/wifi/__init__.c +msgid "Failed to allocate Wifi memory" msgstr "" -#: shared-bindings/canio/RemoteTransmissionRequest.c -msgid "RemoteTransmissionRequests limited to 8 bytes" +#: ports/espressif/common-hal/wifi/__init__.c +#: ports/raspberrypi/common-hal/wifi/__init__.c +msgid "Only IPv4 addresses supported" msgstr "" -#: shared-bindings/aesio/aes.c -msgid "Requested AES mode is unsupported" +#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +msgid "Must provide MISO or MOSI pin" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Requested resource not found" +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c +#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c +#: ports/stm/common-hal/canio/CAN.c ports/stm/common-hal/sdioio/SDCard.c +msgid "Hardware in use, try alternative pins" +msgstr "Donanım kullanımda, alternatif pinleri deneyin" + +#: ports/mimxrt10xx/common-hal/canio/CAN.c +msgid "Unable to send CAN Message: all Tx message buffers are busy" msgstr "" -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -msgid "Right channel unsupported" +#: ports/mimxrt10xx/common-hal/microcontroller/Processor.c +msgid "" +"Frequency must be 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 or 1008 Mhz" msgstr "" +"Frekans 24, 150, 396, 450, 528, 600, 720, 816, 912, 960 ya da 1008 Mhz " +"olmalıdır" -#: shared-module/jpegio/JpegDecoder.c -msgid "Right format but not supported" +#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h +msgid "You pressed the left button at start up." msgstr "" -#: main.c -msgid "Running in safe mode! Not running saved code.\n" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "timeout must be < 655.35 secs" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "SD card CSD format not supported" +#: ports/nordic/common-hal/_bleio/Adapter.c +msgid "non-zero timeout must be > 0.01" msgstr "" -#: ports/cxd56/common-hal/sdioio/SDCard.c -msgid "SDCard init" +#: ports/nordic/common-hal/_bleio/Adapter.c +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Failed to connect: timeout" +msgstr "Bağlantı kurulamadı: timeout" + +#: ports/nordic/common-hal/_bleio/UUID.c +msgid "Unexpected nrfx uuid type" msgstr "" -#: ports/stm/common-hal/sdioio/SDCard.c -#, c-format -msgid "SDIO GetCardInfo Error %d" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "Nordic system firmware out of memory" msgstr "" -#: ports/espressif/common-hal/sdioio/SDCard.c -#: ports/stm/common-hal/sdioio/SDCard.c +#: ports/nordic/common-hal/_bleio/__init__.c #, c-format -msgid "SDIO Init Error %x" +msgid "Unknown system firmware error: %04x" msgstr "" -#: ports/espressif/common-hal/busio/SPI.c -msgid "SPI configuration failed" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown gatt error: 0x%04x" msgstr "" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI init error" +#: ports/nordic/common-hal/_bleio/__init__.c +msgid "" +"Unspecified issue. Can be that the pairing prompt on the other device was " +"declined or ignored." msgstr "" -#: ports/analog/common-hal/busio/SPI.c -msgid "SPI needs MOSI, MISO, and SCK" +#: ports/nordic/common-hal/_bleio/__init__.c +#, c-format +msgid "Unknown security error: 0x%04x" msgstr "" -#: ports/raspberrypi/common-hal/busio/SPI.c -msgid "SPI peripheral in use" -msgstr "" +#: ports/nordic/common-hal/alarm/pin/PinAlarm.c +msgid "Cannot wake on pin edge, only level" +msgstr "Pin kenarı ile uyandırılamaz, yalnızca seviye ile uyanabilir" -#: ports/stm/common-hal/busio/SPI.c -msgid "SPI re-init" -msgstr "" +#: ports/nordic/common-hal/audiobusio/I2SOut.c +msgid "Device in use" +msgstr "Cihaz kullanımda" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "Scale dimensions must divide by 3" +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only sample_rate=16000 is supported" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "Scan already in progress. Stop with stop_scan." +#: ports/nordic/common-hal/audiobusio/PDMIn.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only bit_depth=16 is supported" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -msgid "Serializer in use" +#: ports/nordic/common-hal/busio/UART.c +#, c-format +msgid "error = 0x%08lX" msgstr "" -#: shared-bindings/ssl/SSLContext.c -msgid "Server side context cannot have hostname" +#: ports/nordic/common-hal/busio/UART.c +msgid "Odd parity is not supported" msgstr "" -#: ports/cxd56/common-hal/camera/Camera.c -msgid "Size not supported" -msgstr "" +#: ports/nordic/common-hal/countio/Counter.c +#: ports/nordic/common-hal/pulseio/PulseIn.c +#: ports/nordic/common-hal/rotaryio/IncrementalEncoder.c +msgid "All channels in use" +msgstr "Tüm kanallar kullanımda" -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "Slice and value different lengths." -msgstr "" +#: ports/nordic/common-hal/microcontroller/Processor.c +msgid "Cannot get temperature" +msgstr "Isı okunamadı" -#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/memorymonitor/AllocationSize.c -#: shared-bindings/pulseio/PulseIn.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -msgid "Slices not supported" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" msgstr "" -#: ports/espressif/common-hal/socketpool/SocketPool.c -#: ports/raspberrypi/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "timeout duration exceeded the maximum supported value" msgstr "" -#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c -msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" -msgstr "" +#: ports/nordic/common-hal/watchdog/WatchDogTimer.c +msgid "%q cannot be changed once mode is set to %q" +msgstr "Mod %q olarak ayarlandıktan sonra %q değiştirilemez" -#: shared-bindings/aesio/aes.c -msgid "Source and destination buffers must be the same length" -msgstr "" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to acquire mutex, err 0x%04x" +msgstr "Muteks alınamadı, err 0x%04x" -#: shared-bindings/paralleldisplaybus/ParallelBus.c -msgid "Specify exactly one of data0 or data_pins" -msgstr "" +#: ports/nordic/sd_mutex.c +#, c-format +msgid "Failed to release mutex, err 0x%04x" +msgstr "Muteks serbest bırakılamadı, err 0x%04x" -#: supervisor/shared/safe_mode.c -msgid "Stack overflow. Increase stack size." -msgstr "" +#: ports/raspberrypi/audio_dma.c +msgid "Audio conversion not implemented" +msgstr "Ses dönüşümü implemente edilmedi" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Supply one of monotonic_time or epoch_time" -msgstr "" +#: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c +#: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c +#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c +#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c +#: shared-module/synthio/Synthesizer.c +msgid "%q must be of type %q or %q, not %q" +msgstr "%q; %q veya %q tipi olmalıdır, %q değil" -#: shared-bindings/gnss/GNSS.c -msgid "System entry must be gnss.SatelliteSystem" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Program size invalid" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Temperature read timed out" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Init program size invalid" +msgstr "Init program boyutu geçersiz" -#: supervisor/shared/safe_mode.c -msgid "The `microcontroller` module was used to boot into safe mode." -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Buffer elements must be 4 bytes long or less" +msgstr "Buffer elementleri 4 bit olmak zorunda" -#: py/obj.c -msgid "The above exception was the direct cause of the following exception:" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched data size" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "Out-buffer elements must be <= 4 bytes long" msgstr "" -#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c -msgid "The sample's %q does not match" -msgstr "" +#: ports/raspberrypi/bindings/rp2pio/StateMachine.c +msgid "In-buffer elements must be <= 4 bytes long" +msgstr "Buffer öğeleri <=4 bayt uzunluğunda olmalı" -#: supervisor/shared/safe_mode.c -msgid "Third-party firmware fatal error." +#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c +#: ports/stm/common-hal/alarm/touch/TouchAlarm.c +msgid "Touch alarms not available" msgstr "" -#: shared-module/imagecapture/ParallelImageCapture.c -msgid "This microcontroller does not support continuous capture." -msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "Bit clock and word select must be sequential GPIO pins" +msgstr "Bit saati ve kelime seçimi ardışık GPIO pinleri olmalı" -#: shared-module/paralleldisplaybus/ParallelBus.c -msgid "" -"This microcontroller only supports data0=, not data_pins=, because it " -"requires contiguous pins." +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Too many channels in sample." msgstr "" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile height must exactly divide bitmap height" -msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +msgid "Audio source error" +msgstr "Ses kaynağı hatası" -#: shared-bindings/displayio/TileGrid.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-module/displayio/TileGrid.c -msgid "Tile index out of bounds" -msgstr "" +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +msgid "%q must be 16, 24, or 32" +msgstr "%q 16,24 veya 32 olmalıdır" -#: shared-bindings/displayio/TileGrid.c -msgid "Tile width must exactly divide bitmap width" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "Pins must share PWM slice" msgstr "" -#: shared-module/tilepalettemapper/TilePaletteMapper.c -msgid "TilePaletteMapper may only be bound to a TileGrid once" +#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +msgid "No DMA pacing timer found" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "Time is in the past." -msgstr "" +#: ports/raspberrypi/common-hal/busio/I2C.c +#: ports/raspberrypi/common-hal/i2ctarget/I2CTarget.c +msgid "I2C peripheral in use" +msgstr "I2C çevre cihazı kullanımda" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/nordic/common-hal/_bleio/Adapter.c -#, c-format -msgid "Timeout is too long: Maximum timeout length is %d seconds" +#: ports/raspberrypi/common-hal/busio/SPI.c +msgid "SPI peripheral in use" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "Timeout must be < 100 seconds" +#: ports/raspberrypi/common-hal/busio/UART.c +msgid "UART peripheral in use" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -msgid "Too many channels in sample" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "Pin must be on PWM Channel B" msgstr "" -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Too many channels in sample." +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "RISE_AND_FALL not available on this chip" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -msgid "Too many descriptors" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice already in use" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many display busses; forgot displayio.release_displays() ?" +#: ports/raspberrypi/common-hal/countio/Counter.c +msgid "PWM slice channel A already in use" msgstr "" -#: shared-module/displayio/__init__.c -msgid "Too many displays" -msgstr "" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All state machines in use" +msgstr "Tüm durum makineleri kullanımda" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Total data to write is larger than %q" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +msgid "timeout waiting for flux" msgstr "" -#: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c -#: ports/stm/common-hal/alarm/touch/TouchAlarm.c -msgid "Touch alarms not available" +#: ports/raspberrypi/common-hal/floppyio/__init__.c +#: shared-module/floppyio/__init__.c +msgid "timeout waiting for index pulse" msgstr "" -#: py/obj.c -msgid "Traceback (most recent call last):\n" +#: ports/raspberrypi/common-hal/imagecapture/ParallelImageCapture.c +msgid "Pins must be sequential" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART de-init" +#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +#: shared-module/aurora_epaper/aurora_framebuffer.c +msgid "Invalid %q and %q" msgstr "" -#: ports/cxd56/common-hal/busio/UART.c ports/espressif/common-hal/busio/UART.c -#: ports/stm/common-hal/busio/UART.c -msgid "UART init" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Failed to add service TXT record" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART needs TX & RX" +#: ports/raspberrypi/common-hal/mdns/Server.c +msgid "Out of MDNS service slots" msgstr "" -#: ports/raspberrypi/common-hal/busio/UART.c -msgid "UART peripheral in use" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to access unaligned IO register" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART re-init" +#: ports/raspberrypi/common-hal/memorymap/AddressRange.c +msgid "Unable to write to read-only memory" msgstr "" -#: ports/analog/common-hal/busio/UART.c -msgid "UART read error" -msgstr "" +#: ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +msgid "All timers for this pin are in use" +msgstr "Bu pin için tüm zamanlayıcılar kullanımda" -#: ports/analog/common-hal/busio/UART.c -msgid "UART transaction timeout" +#: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c +msgid "Pins must be sequential GPIO pins" msgstr "" -#: ports/stm/common-hal/busio/UART.c -msgid "UART write" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Pin count too large" msgstr "" -#: main.c -msgid "UID:" -msgstr "UID:" - -#: shared-module/usb_hid/Device.c -msgid "USB busy" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing jmp_pin. %q[%u] jumps on pin" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices need more endpoints than are available." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] uses extra pin" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "USB devices specify too many interface names." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] waits based on pin" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] waits on input outside of count" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] shifts in from pin(s)" msgstr "" -#: shared-bindings/_bleio/UUID.c -msgid "UUID value is not str, int or byte buffer" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts in more bits than pin count" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to access unaligned IO register" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] shifts out to pin(s)" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/I2SOut.c -#: ports/atmel-samd/common-hal/audioio/AudioOut.c -#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c -#: ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c -#: ports/raspberrypi/common-hal/mcp4822/MCP4822.c -msgid "Unable to allocate buffers for signed conversion" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "%q[%u] shifts out more bits than pin count" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "Unable to allocate to the heap." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_set_pin. %q[%u] sets pin(s)" msgstr "" -#: ports/espressif/common-hal/busio/I2C.c -#: ports/espressif/common-hal/busio/SPI.c -msgid "Unable to create lock" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_out_pin. %q[%u] writes pin(s)" msgstr "" -#: shared-module/i2cdisplaybus/I2CDisplayBus.c -#: shared-module/is31fl3741/IS31FL3741.c -#, c-format -msgid "Unable to find I2C Display at %x" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: py/parse.c -msgid "Unable to init parser" -msgstr "" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "GPIO0..15, GPIO32..47 ile birlikte kullanılamaz" -#: shared-module/displayio/OnDiskBitmap.c -msgid "Unable to read color palette data" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does IN without loading ISR" msgstr "" -#: ports/mimxrt10xx/common-hal/canio/CAN.c -msgid "Unable to send CAN Message: all Tx message buffers are busy" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Program does OUT without loading OSR" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "Unable to start mDNS query" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin state conflicts with initial out pin state" +msgstr "İlk pinin durumu, ilk çıkış pininin durumu ile çakışıyor" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Initial set pin direction conflicts with initial out pin direction" +msgstr "İlk pin yönü, ilk çıkış pin yönüyle çakışıyor" + +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "pull masks conflict with direction masks" msgstr "" -#: shared-bindings/nvm/ByteArray.c -msgid "Unable to write to nvm." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No out in program" msgstr "" -#: ports/raspberrypi/common-hal/memorymap/AddressRange.c -msgid "Unable to write to read-only memory" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in in program" msgstr "" -#: shared-bindings/alarm/SleepMemory.c -msgid "Unable to write to sleep_memory." +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "No in or out in program" msgstr "" -#: ports/nordic/common-hal/_bleio/UUID.c -msgid "Unexpected nrfx uuid type" +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Mismatched swap flag" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c +#: ports/raspberrypi/common-hal/sdioio/SDCard.c #, c-format -msgid "Unknown BLE error at %s:%d: %d" +msgid "Number of data_pins must be %d, not %d" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown BLE error: %d" +#: ports/raspberrypi/common-hal/sdioio/SDCard.c +msgid "Data pins must be consecutive" msgstr "" -#: ports/espressif/common-hal/max3421e/Max3421E.c -#: ports/raspberrypi/common-hal/wifi/__init__.c -#, c-format -msgid "Unknown error code %d" +#: ports/raspberrypi/common-hal/socketpool/Socket.c +msgid "Only IPv4 sockets supported" msgstr "" -#: shared-bindings/wifi/Radio.c -#, c-format -msgid "Unknown failure %d" +#: ports/raspberrypi/common-hal/usb_host/Port.c +msgid "All dma channels in use" +msgstr "Kullanımdaki tüm dma kanalları" + +#: ports/raspberrypi/common-hal/wifi/Monitor.c +msgid "wifi.Monitor not available" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown gatt error: 0x%04x" +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "%q is read-only for this board" +msgstr "%q bu kart için salt okunur" + +#: ports/raspberrypi/common-hal/wifi/Radio.c +msgid "AP could not be started" msgstr "" -#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c -#: supervisor/shared/safe_mode.c -msgid "Unknown reason." +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Only edge detection is available on this hardware" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown security error: 0x%04x" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +#: ports/stm/common-hal/pulseio/PulseIn.c +msgid "Pin interrupt already in use" msgstr "" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error at %s:%d: %d" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Pin cannot wake from Deep Sleep" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %04x" +#: ports/stm/common-hal/alarm/pin/PinAlarm.c +msgid "Deep sleep pins must use a rising edge with pulldown" msgstr "" +"Derin uyku pinleri, aşağı çekme direnci ile yükselen kenar kullanmalıdır" -#: ports/espressif/common-hal/_bleio/__init__.c -#, c-format -msgid "Unknown system firmware error: %d" +#: ports/stm/common-hal/analogio/AnalogIn.c +msgid "Invalid ADC Unit value" +msgstr "Geçersiz ADC Ünite değeri" + +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Device Init Error" +msgstr "DAC cihazı başlatma hatası" + +#: ports/stm/common-hal/analogio/AnalogOut.c +#: ports/stm/common-hal/audioio/AudioOut.c +msgid "DAC Channel Init Error" +msgstr "DAC kanalı başlatma hatası" + +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only mono is supported" msgstr "" -#: shared-bindings/adafruit_pixelbuf/PixelBuf.c -#: shared-module/_pixelmap/PixelMap.c +#: ports/stm/common-hal/audiobusio/PDMIn.c +msgid "only oversample=64 is supported" +msgstr "" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Another PWMAudioOut is already active" +msgstr "Başka bir PWMAudioOut zaten aktif durumda" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c #, c-format -msgid "Unmatched number of items on RHS (expected %d, got %d)." +msgid "Buffer length %d too big. It must be less than %d" +msgstr "Mevcut arabellek boyutu %d çok büyük. En fazla %d kadar olmalı" + +#: ports/stm/common-hal/audiopwmio/PWMAudioOut.c +msgid "Failed to buffer the sample" msgstr "" -#: ports/nordic/common-hal/_bleio/__init__.c -msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " -"declined or ignored." +#: ports/stm/common-hal/busio/I2C.c +msgid "I2C init error" +msgstr "I2C init hatası" + +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI init error" msgstr "" -#: shared-module/jpegio/JpegDecoder.c -msgid "Unsupported JPEG (may be progressive)" +#: ports/stm/common-hal/busio/SPI.c +msgid "SPI re-init" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "Unsupported colorspace" +#: ports/stm/common-hal/busio/UART.c +msgid "Internal define error" +msgstr "Dahili tanımlama hatası" + +#: ports/stm/common-hal/busio/UART.c +msgid "Could not start interrupt, RX busy" +msgstr "Kesinti başlatılamadı, RX kullanımda" + +#: ports/stm/common-hal/busio/UART.c +msgid "UART write" msgstr "" -#: shared-module/displayio/bus_core.c -msgid "Unsupported display bus type" +#: ports/stm/common-hal/busio/UART.c +msgid "UART de-init" msgstr "" -#: shared-bindings/hashlib/__init__.c -msgid "Unsupported hash algorithm" +#: ports/stm/common-hal/busio/UART.c +msgid "UART re-init" msgstr "" -#: ports/espressif/common-hal/socketpool/Socket.c -#: ports/zephyr-cp/common-hal/socketpool/Socket.c -msgid "Unsupported socket type" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Temperature read timed out" msgstr "" -#: ports/espressif/common-hal/_bleio/Adapter.c -#: ports/espressif/common-hal/dualbank/__init__.c -msgid "Update failed" +#: ports/stm/common-hal/microcontroller/Processor.c +msgid "Voltage read timed out" msgstr "" -#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c -#: ports/zephyr-cp/common-hal/busio/I2C.c -#: ports/zephyr-cp/common-hal/busio/SPI.c -#: ports/zephyr-cp/common-hal/busio/UART.c -msgid "Use device tree to define %q devices" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG Init Error" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length != required fixed length" +#: ports/stm/common-hal/os/__init__.c +msgid "Random number generation error" msgstr "" -#: ports/espressif/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c -msgid "Value length > max_length" +#: ports/stm/common-hal/os/__init__.c +msgid "RNG DeInit Error" msgstr "" -#: ports/espressif/common-hal/espidf/__init__.c -msgid "Version was invalid" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "timer re-init" msgstr "" -#: ports/stm/common-hal/microcontroller/Processor.c -msgid "Voltage read timed out" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "channel re-init" msgstr "" -#: main.c -msgid "WARNING: Your code filename has two extensions\n" +#: ports/stm/common-hal/pwmio/PWMOut.c +msgid "PWM restart" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "WatchDogTimer cannot be deinitialized once mode is set to RESET" +#: ports/stm/common-hal/sdioio/SDCard.c +#, c-format +msgid "MMC/SDIO Clock Error %x" msgstr "" -#: py/builtinhelp.c +#: ports/stm/common-hal/sdioio/SDCard.c #, c-format -msgid "" -"Welcome to Adafruit CircuitPython %s!\n" -"\n" -"Visit circuitpython.org for more information.\n" -"\n" -"To list built-in modules type `help(\"modules\")`.\n" +msgid "SDIO GetCardInfo Error %d" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "Wi-Fi: " -msgstr "Wi-Fi: " +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid ".show(x) removed. Use .root_group = x" +msgstr "" -#: ports/espressif/common-hal/wifi/Radio.c -#: ports/raspberrypi/common-hal/wifi/Radio.c -#: ports/zephyr-cp/common-hal/wifi/Radio.c -msgid "WiFi is not enabled" +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Brightness not adjustable" +msgstr "Parlaklık ayarlanabilir değil" + +#: ports/zephyr-cp/bindings/zephyr_display/Display.c py/argcheck.c +#: shared-bindings/busdisplay/BusDisplay.c shared-bindings/displayio/Bitmap.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/is31fl3741/FrameBuffer.c +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "%q must be %d-%d" +msgstr "%q, %d-%d olmalıdır" + +#: ports/zephyr-cp/bindings/zephyr_display/Display.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Group already used" +msgstr "Grup zaten kullanılıyor" + +#: ports/zephyr-cp/common-hal/_bleio/Adapter.c +msgid "Invalid advertising data" msgstr "" -#: main.c -msgid "Woken up by alarm.\n" +#: ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +#: ports/zephyr-cp/common-hal/busio/I2C.c +#: ports/zephyr-cp/common-hal/busio/SPI.c +#: ports/zephyr-cp/common-hal/busio/UART.c +msgid "Use device tree to define %q devices" msgstr "" -#: ports/espressif/common-hal/_bleio/PacketBuffer.c -#: ports/nordic/common-hal/_bleio/PacketBuffer.c -msgid "Writes not supported on Characteristic" +#: ports/zephyr-cp/common-hal/socketpool/SocketPool.c +msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" -#: ports/atmel-samd/boards/circuitplayground_express/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_crickit/mpconfigboard.h -#: ports/atmel-samd/boards/circuitplayground_express_displayio/mpconfigboard.h -#: ports/atmel-samd/boards/meowmeow/mpconfigboard.h -msgid "You pressed both buttons at start up." +#: ports/zephyr-cp/common-hal/wifi/Radio.c +msgid "Failed to set hostname" msgstr "" -#: ports/espressif/boards/m5stack_core_basic/mpconfigboard.h -#: ports/espressif/boards/m5stack_core_fire/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus/mpconfigboard.h -#: ports/espressif/boards/m5stack_stick_c_plus2/mpconfigboard.h -msgid "You pressed button A at start up." +#: ports/zephyr-cp/common-hal/zephyr_display/Display.c +#: shared-module/busdisplay/BusDisplay.c +#: shared-module/framebufferio/FramebufferDisplay.c +msgid "Below minimum frame rate" +msgstr "Minimum kare hızından altında" + +#: py/argcheck.c +msgid "function doesn't take keyword arguments" +msgstr "" + +#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c +#: shared-bindings/time/__init__.c +#, c-format +msgid "function takes %d positional arguments but %d were given" msgstr "" -#: ports/espressif/boards/m5stack_m5paper/mpconfigboard.h -msgid "You pressed button DOWN at start up." +#: py/argcheck.c +#, c-format +msgid "function missing %d required positional arguments" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the BOOT button at start up" +#: py/argcheck.c +#, c-format +msgid "function expected at most %d arguments, got %d" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32c6_4mbflash_nopsram/mpconfigboard.h -#: ports/espressif/boards/adafruit_itsybitsy_esp32/mpconfigboard.h -#: ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h -msgid "You pressed the BOOT button at start up." +#: py/argcheck.c +msgid "'%q' argument required" +msgstr "'%q' argümanı gerekli" + +#: py/argcheck.c +msgid "extra positional arguments given" msgstr "" -#: ports/espressif/boards/adafruit_huzzah32_breakout/mpconfigboard.h -msgid "You pressed the GPIO0 button at start up." +#: py/argcheck.c py/bc.c py/objnamedtuple.c +#: shared-bindings/traceback/__init__.c +msgid "unexpected keyword argument '%q'" msgstr "" -#: ports/espressif/boards/espressif_esp32_lyrat/mpconfigboard.h -msgid "You pressed the Rec button at start up." +#: py/argcheck.c +msgid "extra keyword arguments given" msgstr "" -#: ports/espressif/boards/adafruit_feather_esp32_v2/mpconfigboard.h -msgid "You pressed the SW38 button at start up." +#: py/argcheck.c shared-bindings/_stage/__init__.c +#: shared-bindings/digitalio/DigitalInOut.c +msgid "argument num/types mismatch" msgstr "" -#: ports/espressif/boards/hardkernel_odroid_go/mpconfigboard.h -#: ports/espressif/boards/vidi_x/mpconfigboard.h -msgid "You pressed the VOLUME button at start up." +#: py/argcheck.c +msgid "keyword argument(s) not implemented - use normal args instead" msgstr "" -#: ports/espressif/boards/m5stack_atom_echo/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_lite/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_matrix/mpconfigboard.h -#: ports/espressif/boards/m5stack_atom_u/mpconfigboard.h -msgid "You pressed the central button at start up." +#: py/argcheck.c +msgid "%q must be %d" +msgstr "%q, %d olmalıdır" + +#: py/argcheck.c +msgid "%q must be >= %d" +msgstr "%q >= %d olmalıdır" + +#: py/argcheck.c shared-bindings/gifio/GifWriter.c +#: shared-module/gifio/OnDiskGif.c +msgid "%q must be <= %d" +msgstr "%q <= %d olmalıdır" + +#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q; %q tipi olmalıdır, %q değil" + +#: py/argcheck.c +msgid "%q length must be %d-%d" +msgstr "%q boyutları %d-%d olmalıdır" + +#: py/argcheck.c +msgid "%q length must be >= %d" +msgstr "%q boyutu >= %d olmalıdır" + +#: py/argcheck.c +msgid "%q length must be <= %d" +msgstr "%q boyutu <= %d olmalıdır" + +#: py/argcheck.c shared-bindings/usb_hid/Device.c +msgid "%q length must be %d" +msgstr "%q boyutu %d olmalıdır" + +#: py/argcheck.c shared-module/audiofilters/Filter.c +msgid "%q in %q must be of type %q, not %q" +msgstr "%q'nün içindeki %q, %q tipi olmalıdır, %q değil" + +#: py/asmthumb.c +msgid "too many locals for native method" msgstr "" -#: ports/nordic/boards/aramcon2_badge/mpconfigboard.h -msgid "You pressed the left button at start up." +#: py/asmxtensa.c +msgid "ERROR: xtensa %q out of range" msgstr "" -#: supervisor/shared/safe_mode.c -msgid "You pressed the reset button during boot." +#: py/asmxtensa.c +msgid "ERROR: %q %q not word-aligned" msgstr "" -#: supervisor/shared/micropython.c -msgid "[truncated due to length]" +#: py/bc.c py/objnamedtuple.c +msgid "%q() takes %d positional arguments but %d were given" +msgstr "%q(), %d konumsal argümanını alır ancak %d verildi" + +#: py/bc.c py/objnamedtuple.c +msgid "function got multiple values for argument '%q'" msgstr "" -#: py/objtype.c -msgid "__init__() should return None" +#: py/bc.c +msgid "unexpected keyword argument" msgstr "" -#: py/objtype.c +#: py/bc.c #, c-format -msgid "__init__() should return None, not '%s'" +msgid "function missing required positional argument #%d" msgstr "" -#: py/objobject.c -msgid "__new__ arg must be a user-type" +#: py/bc.c +msgid "function missing required keyword argument '%q'" msgstr "" -#: extmod/modbinascii.c extmod/modhashlib.c py/objarray.c -msgid "a bytes-like object is required" +#: py/bc.c +msgid "function missing keyword-only argument" msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "address out of range" +#: py/binary.c py/objarray.c +msgid "bad typecode" msgstr "" -#: shared-bindings/i2ctarget/I2CTarget.c -msgid "addresses is empty" +#: py/builtinevex.c +msgid "bad compile mode" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "already playing" +#: py/builtinhelp.c +msgid "Plus any modules on the filesystem\n" msgstr "" -#: py/compile.c -msgid "annotation must be an identifier" +#: py/builtinhelp.c +msgid "object " msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "arange: cannot compute length" +#: py/builtinhelp.c +msgid " is of type %q\n" +msgstr " nesnesi, %q tipindedir\n" + +#: py/builtinhelp.c +#, c-format +msgid "" +"Welcome to Adafruit CircuitPython %s!\n" +"\n" +"Visit circuitpython.org for more information.\n" +"\n" +"To list built-in modules type `help(\"modules\")`.\n" msgstr "" -#: py/modbuiltins.c -msgid "arg is an empty sequence" +#: py/builtinimport.c +msgid "script compilation not supported" msgstr "" -#: py/objobject.c -msgid "arg must be user-type" +#: py/builtinimport.c +msgid "can't perform relative import" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort argument must be an ndarray" +#: py/builtinimport.c +msgid "module not found" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "argsort is not implemented for flattened arrays" +#: py/builtinimport.c +msgid "no module named '%q'" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "argument must be None, an integer or a tuple of integers" +#: py/builtinimport.c +msgid "relative import" msgstr "" #: py/compile.c -msgid "argument name reused" +msgid "can't assign to expression" msgstr "" -#: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c -msgid "argument num/types mismatch" +#: py/compile.c +msgid "multiple *x in assignment" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/numpy/transform.c -msgid "arguments must be ndarrays" +#: py/compile.c +msgid "non-default argument follows default argument" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array and index length must be equal" +#: py/compile.c +msgid "invalid micropython decorator" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "array has too many dimensions" +#: py/compile.c +msgid "invalid arch" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "array is too big" +#: py/compile.c +msgid "can't delete expression" msgstr "" -#: py/objarray.c shared-bindings/alarm/SleepMemory.c -#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c -msgid "array/bytes required on right side" -msgstr "" +#: py/compile.c +msgid "'break'/'continue' outside loop" +msgstr "Döngü dışında 'break'/'continue'" #: py/compile.c -msgid "async for/with outside async function" -msgstr "" +msgid "'return' outside function" +msgstr "fonksiyon dışında 'return'" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get (arg)min/(arg)max of empty sequence" +#: py/compile.c +msgid "import * not at module level" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "attempt to get argmin/argmax of an empty sequence" +#: py/compile.c +msgid "identifier redefined as global" msgstr "" -#: py/objstr.c -msgid "attributes not supported" +#: py/compile.c +msgid "no binding for nonlocal found" msgstr "" -#: ports/espressif/common-hal/audioio/AudioOut.c -msgid "audio format not supported" +#: py/compile.c +msgid "identifier redefined as nonlocal" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "axis is out of bounds" +#: py/compile.c +msgid "can't declare nonlocal in outer code" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -msgid "axis must be None, or an integer" +#: py/compile.c +msgid "default 'except' must be last" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "axis too long" +#: py/compile.c +msgid "async for/with outside async function" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "background value out of range of target" +#: py/compile.c +msgid "*x must be assignment target" +msgstr "*x atama hedefi olmalıdır" + +#: py/compile.c +msgid "super() can't find self" msgstr "" -#: py/builtinevex.c -msgid "bad compile mode" +#: py/compile.c +msgid "* arg after **" msgstr "" -#: py/objstr.c -msgid "bad conversion specifier" +#: py/compile.c +msgid "too many args" msgstr "" -#: py/objstr.c -msgid "bad format string" +#: py/compile.c +msgid "LHS of keyword arg must be an id" msgstr "" -#: py/binary.c py/objarray.c -msgid "bad typecode" +#: py/compile.c +msgid "positional arg after **" msgstr "" -#: py/emitnative.c -msgid "binary op %q not implemented" +#: py/compile.c +msgid "positional arg after keyword arg" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "bitmap size and depth must match" +#: py/compile.c py/parse.c +msgid "invalid syntax" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "bitmap sizes must match" +#: py/compile.c +msgid "expecting key:value for dict" msgstr "" -#: extmod/modrandom.c -msgid "bits must be 32 or less" +#: py/compile.c +msgid "expecting just a value for set" msgstr "" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "bits_per_sample must be 16" +#: py/compile.c +msgid "'yield' outside function" +msgstr "fonksiyon dışında 'yield'" + +#: py/compile.c +msgid "'yield from' inside async function" +msgstr "asenkron fonksiyon içinde 'yield from'" + +#: py/compile.c +msgid "'await' outside function" +msgstr "fonksiyon dışında 'await'" + +#: py/compile.c +msgid "unknown type '%q'" msgstr "" -#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c -#: shared-bindings/audiodelays/MultiTapDelay.c -#: shared-bindings/audiodelays/PitchShift.c -#: shared-bindings/audiofilters/Distortion.c -#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c -#: shared-bindings/audiomixer/Mixer.c -msgid "bits_per_sample must be 8 or 16" +#: py/compile.c +msgid "annotation must be an identifier" msgstr "" -#: py/emitinlinethumb.c -msgid "branch not in range" +#: py/compile.c +msgid "argument name reused" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer is smaller than requested size" +#: py/compile.c +msgid "inline assembler must be a function" msgstr "" -#: extmod/ulab/code/numpy/create.c extmod/ulab/code/utils/utils.c -msgid "buffer size must be a multiple of element size" +#: py/compile.c +msgid "unknown type" msgstr "" -#: shared-module/struct/__init__.c -msgid "buffer size must match format" +#: py/compile.c +msgid "return annotation must be an identifier" msgstr "" -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" +#: py/compile.c +msgid "expecting an assembler instruction" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c -msgid "buffer too small" +#: py/compile.c +msgid "'label' requires 1 argument" +msgstr "'label' 1 argümana ihtiyaç duyar" + +#: py/compile.c +msgid "label redefined" msgstr "" -#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c -msgid "buffer too small for requested bytes" +#: py/compile.c +msgid "'align' requires 1 argument" +msgstr "'align' 1 argümana ihtiyaç duyar" + +#: py/compile.c +msgid "'data' requires at least 2 arguments" +msgstr "'data' en az 2 argümana ihtiyaç duyar" + +#: py/compile.c +msgid "'data' requires integer arguments" +msgstr "'data' integer tipinde argümanlara ihtiyaç duyar" + +#: py/compile.c +msgid "cannot emit native code for this architecture" msgstr "" #: py/emitbc.c msgid "bytecode overflow" msgstr "" -#: py/objarray.c -msgid "bytes length not a multiple of item size" +#: py/emitinlinerv32.c +msgid "can only have up to 4 parameters for RV32 assembly" msgstr "" -#: py/objstr.c -msgid "bytes value out of range" +#: py/emitinlinerv32.c +msgid "parameters must be registers in sequence a0 to a3" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is out of range" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: expecting %q" msgstr "" -#: ports/atmel-samd/bindings/samd/Clock.c -msgid "calibration is read only" +#: py/emitinlinerv32.c +msgid "opcode '%q': expecting %d arguments" msgstr "" -#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c -#: shared-module/vectorio/Rectangle.c -msgid "can only have one parent" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: out of range" msgstr "" #: py/emitinlinerv32.c -msgid "can only have up to 4 parameters for RV32 assembly" +msgid "opcode '%q' argument %d: unknown register" msgstr "" -#: py/emitinlinethumb.c -msgid "can only have up to 4 parameters to Thumb assembly" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: undefined label '%q'" msgstr "" -#: py/emitinlinextensa.c -msgid "can only have up to 4 parameters to Xtensa assembly" +#: py/emitinlinerv32.c +msgid "opcode '%q' argument %d: must not be zero" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "can only specify one unknown dimension" +#: py/emitinlinerv32.c +msgid "invalid RV32 instruction '%q'" msgstr "" -#: py/objtype.c -msgid "can't add special method to already-subclassed class" +#: py/emitinlinethumb.c +msgid "can only have up to 4 parameters to Thumb assembly" msgstr "" -#: py/compile.c -msgid "can't assign to expression" +#: py/emitinlinethumb.c +msgid "parameters must be registers in sequence r0 to r3" msgstr "" -#: extmod/modasyncio.c -msgid "can't cancel self" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects at most r%d" +msgstr "'%s' en fazla r%d bekler" -#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c -msgid "can't convert %q to %q" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a register" +msgstr "'%s' bir yazmaç bekliyor" -#: py/obj.c +#: py/emitinlinethumb.c #, c-format -msgid "can't convert %s to complex" -msgstr "" +msgid "'%s' expects a special register" +msgstr "'%s' özel bir yazmaç bekliyor" -#: py/obj.c +#: py/emitinlinethumb.c #, c-format -msgid "can't convert %s to float" -msgstr "" +msgid "'%s' expects an FPU register" +msgstr "'%s' bir FPU yazmacı bekliyor" -#: py/objint.c py/runtime.c +#: py/emitinlinethumb.c #, c-format -msgid "can't convert %s to int" -msgstr "" +msgid "'%s' expects {r0, r1, ...}" +msgstr "'%s' {r0, r1, ...} bekliyor" -#: py/objstr.c -msgid "can't convert '%q' object to %q implicitly" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects an integer" +msgstr "'%s' bir integer bekliyor" -#: extmod/ulab/code/numpy/vector.c -msgid "can't convert complex to float" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' integer 0x%x doesn't fit in mask 0x%x" +msgstr "'%s' integer 0x%x, 0x%x maskesine uymuyor" -#: py/obj.c -msgid "can't convert to complex" -msgstr "" +#: py/emitinlinethumb.c +#, c-format +msgid "'%s' expects an address of the form [a, b]" +msgstr "'%s', [a, b] biçiminde bir adres bekliyor" -#: py/obj.c -msgid "can't convert to float" -msgstr "" +#: py/emitinlinethumb.c py/emitinlinextensa.c +#, c-format +msgid "'%s' expects a label" +msgstr "'%s' bir etiket bekliyor" -#: py/runtime.c -msgid "can't convert to int" +#: py/emitinlinethumb.c py/emitinlinextensa.c +msgid "label '%q' not defined" msgstr "" -#: py/objstr.c -msgid "can't convert to str implicitly" +#: py/emitinlinethumb.c +#, c-format +msgid "unsupported Thumb instruction '%s' with %d arguments" msgstr "" -#: py/objtype.c -msgid "can't create '%q' instances" +#: py/emitinlinethumb.c +msgid "branch not in range" msgstr "" -#: py/objtype.c -msgid "can't create instance" +#: py/emitinlinextensa.c +msgid "can only have up to 4 parameters to Xtensa assembly" msgstr "" -#: py/compile.c -msgid "can't declare nonlocal in outer code" +#: py/emitinlinextensa.c +msgid "parameters must be registers in sequence a2 to a5" msgstr "" -#: py/compile.c -msgid "can't delete expression" -msgstr "" +#: py/emitinlinextensa.c +#, c-format +msgid "'%s' integer %d isn't within range %d..%d" +msgstr "'%s' integer %d, %d..%d aralığında değil" -#: py/emitnative.c -msgid "can't do binary op between '%q' and '%q'" -msgstr "" +#: py/emitinlinextensa.c +#, c-format +msgid "%d is not a multiple of %d" +msgstr "%d %d'nin katı değil" -#: py/emitnative.c -msgid "can't do unary op of '%q'" +#: py/emitinlinextensa.c +#, c-format +msgid "unsupported Xtensa instruction '%s' with %d arguments" msgstr "" #: py/emitnative.c -msgid "can't implicitly convert '%q' to 'bool'" +msgid "conversion to object" msgstr "" -#: py/runtime.c -msgid "can't import name %q" +#: py/emitnative.c +msgid "local '%q' used before type known" msgstr "" #: py/emitnative.c @@ -2946,1715 +2745,1930 @@ msgstr "" msgid "can't load with '%q' index" msgstr "" -#: py/builtinimport.c -msgid "can't perform relative import" -msgstr "" - -#: py/objgenerator.c -msgid "can't send non-None value to a just-started generator" +#: py/emitnative.c +msgid "local '%q' has type '%q' but source is '%q'" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "can't set 512 block size" +#: py/emitnative.c +msgid "can't store '%q'" msgstr "" -#: py/objexcept.c py/objnamedtuple.c -msgid "can't set attribute" +#: py/emitnative.c +msgid "can't store to '%q'" msgstr "" -#: py/runtime.c -msgid "can't set attribute '%q'" +#: py/emitnative.c +msgid "can't store with '%q' index" msgstr "" #: py/emitnative.c -msgid "can't store '%q'" +msgid "can't implicitly convert '%q' to 'bool'" msgstr "" #: py/emitnative.c -msgid "can't store to '%q'" +msgid "'not' not implemented" msgstr "" #: py/emitnative.c -msgid "can't store with '%q' index" +msgid "can't do unary op of '%q'" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from automatic field numbering to manual field specification" +#: py/emitnative.c +msgid "div/mod not implemented for uint" msgstr "" -#: py/objstr.c -msgid "" -"can't switch from manual field specification to automatic field numbering" +#: py/emitnative.c +msgid "comparison of int and uint" msgstr "" -#: py/objcomplex.c -msgid "can't truncate-divide a complex number" +#: py/emitnative.c +msgid "binary op %q not implemented" msgstr "" -#: extmod/modasyncio.c -msgid "can't wait" +#: py/emitnative.c +msgid "can't do binary op between '%q' and '%q'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot assign new shape" +#: py/emitnative.c +msgid "casting" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "cannot cast output with casting rule" +#: py/emitnative.c +msgid "return expected '%q' but got '%q'" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex to dtype" +#: py/emitnative.c +msgid "must raise an object" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot convert complex type" +#: py/emitnative.c +msgid "native yield" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot delete array elements" +#: py/lexer.c +msgid "unicode name escapes" msgstr "" -#: py/compile.c -msgid "cannot emit native code for this architecture" +#: py/modbuiltins.c +msgid "chr() arg not in range(0x110000)" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "cannot reshape array" +#: py/modbuiltins.c +msgid "chr() arg not in range(256)" msgstr "" -#: py/emitnative.c -msgid "casting" +#: py/modbuiltins.c +msgid "arg is an empty sequence" msgstr "" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "channel re-init" +#: py/modbuiltins.c +msgid "ord expects a character" msgstr "" -#: shared-bindings/_stage/Text.c -msgid "chars buffer too small" +#: py/modbuiltins.c +#, c-format +msgid "ord() expected a character, but string of length %d found" msgstr "" #: py/modbuiltins.c -msgid "chr() arg not in range(0x110000)" -msgstr "" +msgid "3-arg pow() not supported" +msgstr "3-argümanlı pow() desteklenmemektedir" #: py/modbuiltins.c -msgid "chr() arg not in range(256)" +msgid "must use keyword argument for key function" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "clip point must be (x,y) tuple" +#: py/moderrno.c +msgid "Operation not permitted" msgstr "" -#: shared-bindings/msgpack/ExtType.c -msgid "code outside range 0~127" +#: py/moderrno.c +msgid "No such file/directory" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" -msgstr "" +#: py/moderrno.c +msgid "Input/output error" +msgstr "Giriş/çıkış hatası" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a buffer, tuple, list, or int" +#: py/moderrno.c +msgid "Permission denied" msgstr "" -#: shared-bindings/displayio/Palette.c -msgid "color buffer must be a bytearray or array of type 'b' or 'B'" -msgstr "" +#: py/moderrno.c +msgid "File exists" +msgstr "Dosya var" -#: shared-bindings/displayio/Palette.c -msgid "color must be between 0x000000 and 0xffffff" +#: py/moderrno.c +msgid "No such device" msgstr "" -#: py/emitnative.c -msgid "comparison of int and uint" +#: py/moderrno.c +msgid "No space left on device" msgstr "" -#: py/objcomplex.c -msgid "complex divide by zero" +#: py/modmath.c shared-bindings/math/__init__.c +msgid "math domain error" msgstr "" -#: py/objfloat.c py/parsenum.c -msgid "complex values not supported" +#: py/modmath.c +msgid "negative factorial" msgstr "" -#: extmod/modzlib.c -msgid "compression header" +#: py/modmicropython.c +msgid "schedule queue full" msgstr "" -#: py/emitnative.c -msgid "conversion to object" +#: py/modstruct.c shared-module/struct/__init__.c +msgid "buffer too small" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be linear arrays" +#: py/modstruct.c +#, c-format +msgid "pack expected %d items for packing (got %d)" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must be ndarrays" +#: py/modthread.c +msgid "expecting a dict for keyword args" msgstr "" -#: extmod/ulab/code/numpy/filter.c -msgid "convolve arguments must not be empty" +#: py/nativeglue.c +msgid "set unsupported" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "corrupted file" +#: py/nativeglue.c +msgid "slice unsupported" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "could not invert Vandermonde matrix" +#: py/nativeglue.c +msgid "float unsupported" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "couldn't determine SD card version" +#: py/obj.c shared-module/adafruit_pixelbuf/PixelBuf.c +msgid "can't convert %q to %q" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "cross is defined for 1D arrays of length 3" +#: py/obj.c +msgid "During handling of the above exception, another exception occurred:" +msgstr "Yukarıdaki hatanın işlenmesi sırasında başka bir hata oluştu:" + +#: py/obj.c +msgid "The above exception was the direct cause of the following exception:" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be iterable" +#: py/obj.c +msgid " File \"%q\", line %d" +msgstr " \"%q\" dosyası, %d numaralı satır" + +#: py/obj.c +msgid " File \"%q\"" +msgstr " \"%q\" dosyası" + +#: py/obj.c +msgid ", in %q\n" +msgstr ", içinde %q\n" + +#: py/obj.c +msgid "Traceback (most recent call last):\n" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "data must be of equal length" +#: py/obj.c +msgid "can't convert to float" msgstr "" -#: ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c +#: py/obj.c #, c-format -msgid "data pin #%d in use" +msgid "can't convert %s to float" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "data type not understood" +#: py/obj.c +msgid "can't convert to complex" msgstr "" -#: py/parsenum.c -msgid "decimal numbers not supported" +#: py/obj.c +#, c-format +msgid "can't convert %s to complex" msgstr "" -#: py/compile.c -msgid "default 'except' must be last" +#: py/obj.c +msgid "expected tuple/list" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "default is not a function" +#: py/obj.c +#, c-format +msgid "object '%s' isn't a tuple or list" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "" -"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" +#: py/obj.c +msgid "tuple/list has wrong length" msgstr "" -#: shared-bindings/audiobusio/PDMIn.c -msgid "destination buffer must be an array of type 'H' for bit_depth = 16" +#: py/obj.c +#, c-format +msgid "requested length %d but object has length %d" msgstr "" -#: shared-bindings/usb_audio/USBSpeaker.c -msgid "destination must be an array of type 'h'" +#: py/obj.c +msgid "indices must be integers" msgstr "" -#: py/objdict.c -msgid "dict update sequence has wrong length" -msgstr "" +#: py/obj.c +msgid "%q indices must be integers, not %s" +msgstr "%q indeksleri integer olmalı, %s değil" -#: extmod/ulab/code/numpy/numerical.c -msgid "diff argument must be an ndarray" +#: py/obj.c +msgid "object has no len" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "differentiation order out of range" +#: py/obj.c +#, c-format +msgid "object of type '%s' has no len()" msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "dimensions do not match" +#: py/obj.c +msgid "object doesn't support item deletion" msgstr "" -#: py/emitnative.c -msgid "div/mod not implemented for uint" -msgstr "" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item deletion" +msgstr "'%s' nesnesi, öğe silmeyi desteklemiyor" -#: extmod/ulab/code/numpy/create.c py/objint_longlong.c py/objint_mpz.c -msgid "divide by zero" +#: py/obj.c +msgid "object isn't subscriptable" msgstr "" -#: py/runtime.c -msgid "division by zero" -msgstr "" +#: py/obj.c +#, c-format +msgid "'%s' object isn't subscriptable" +msgstr "'%s' nesnesi subscriptable özelliğe sahip değil" -#: extmod/ulab/code/numpy/vector.c -msgid "dtype must be float, or complex" +#: py/obj.c +msgid "object doesn't support item assignment" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "dtype of int32 is not supported" +#: py/obj.c +#, c-format +msgid "'%s' object doesn't support item assignment" +msgstr "'%s' nesnesi, öğe atamasını desteklemiyor" + +#: py/obj.c +msgid "object with buffer protocol required" msgstr "" -#: py/objdeque.c -msgid "empty" +#: py/objarray.c +msgid "bytes length not a multiple of item size" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "empty file" +#: py/objarray.c py/objstr.c +msgid "string argument without an encoding" msgstr "" -#: extmod/modasyncio.c extmod/modheapq.c -msgid "empty heap" +#: py/objarray.c +msgid "memoryview: length is not a multiple of itemsize" msgstr "" -#: py/objstr.c -msgid "empty separator" +#: py/objarray.c py/objstr.c +msgid "substring not found" msgstr "" -#: shared-bindings/random/__init__.c -msgid "empty sequence" +#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "only slices with step=1 (aka None) are supported" msgstr "" -#: py/objstr.c -msgid "end of format while looking for conversion specifier" +#: py/objarray.c +msgid "lhs and rhs should be compatible" msgstr "" -#: shared-bindings/alarm/time/TimeAlarm.c -msgid "epoch_time not supported on this board" +#: py/objarray.c shared-bindings/alarm/SleepMemory.c +#: shared-bindings/memorymap/AddressRange.c shared-bindings/nvm/ByteArray.c +msgid "array/bytes required on right side" msgstr "" -#: ports/nordic/common-hal/busio/UART.c -#, c-format -msgid "error = 0x%08lX" +#: py/objarray.c +msgid "memoryview offset too large" msgstr "" -#: py/runtime.c -msgid "exceptions must derive from BaseException" +#: py/objcomplex.c +msgid "can't truncate-divide a complex number" msgstr "" -#: py/objstr.c -msgid "expected ':' after format specifier" +#: py/objcomplex.c +msgid "complex divide by zero" msgstr "" -#: py/obj.c -msgid "expected tuple/list" -msgstr "" +#: py/objcomplex.c +msgid "0.0 to a complex power" +msgstr "0.0'dan bir karmaşık güce" -#: py/modthread.c -msgid "expecting a dict for keyword args" +#: py/objdeque.c +msgid "full" msgstr "" -#: py/compile.c -msgid "expecting an assembler instruction" +#: py/objdeque.c +msgid "empty" msgstr "" -#: py/compile.c -msgid "expecting just a value for set" +#: py/objdict.c +msgid "dict update sequence has wrong length" msgstr "" -#: py/compile.c -msgid "expecting key:value for dict" +#: py/objexcept.c py/objnamedtuple.c +msgid "can't set attribute" msgstr "" -#: shared-bindings/msgpack/__init__.c -msgid "ext_hook is not a function" +#: py/objfloat.c py/parsenum.c +msgid "complex values not supported" msgstr "" -#: py/argcheck.c -msgid "extra keyword arguments given" +#: py/objgenerator.c +msgid "generator already executing" msgstr "" -#: py/argcheck.c -msgid "extra positional arguments given" +#: py/objgenerator.c +msgid "can't send non-None value to a just-started generator" msgstr "" -#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c -#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c -#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c -msgid "file must be a file opened in byte mode" +#: py/objgenerator.c py/runtime.c +msgid "generator raised StopIteration" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "file write is not available" +#: py/objgenerator.c +msgid "generator ignored GeneratorExit" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "first argument must be a callable" +#: py/objint.c py/runtime.c +#, c-format +msgid "can't convert %s to int" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "first argument must be a function" +#: py/objint.c +msgid "float too big" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "first argument must be a tuple of ndarrays" +#: py/objint.c +#, c-format +msgid "value must fit in %d byte(s)" msgstr "" -#: extmod/ulab/code/numpy/transform.c extmod/ulab/code/numpy/vector.c -msgid "first argument must be an ndarray" +#: py/objint.c shared-bindings/time/__init__.c +msgid "No long integer support" msgstr "" -#: py/objtype.c -msgid "first argument to super() must be type" +#: py/objint.c py/sequence.c +msgid "small int overflow" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "first two arguments must be ndarrays" -msgstr "" +#: py/objint.c shared-bindings/_bleio/Connection.c +#: shared-bindings/storage/__init__.c +msgid "%q=%q" +msgstr "%q=%q" -#: extmod/ulab/code/ndarray.c -msgid "flattening order must be either 'C', or 'F'" +#: py/objint_longlong.c py/parsenum.c +msgid "result overflows long long storage" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "flip argument must be an ndarray" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative shift count" msgstr "" -#: py/objint.c -msgid "float too big" +#: py/objint_longlong.c py/objint_mpz.c py/runtime.c +msgid "negative power with no float support" msgstr "" -#: py/nativeglue.c -msgid "float unsupported" +#: py/objint_longlong.c py/objint_mpz.c +msgid "overflow converting long int to machine word" msgstr "" -#: extmod/moddeflate.c -msgid "format" +#: py/objint_mpz.c +msgid "pow() with 3 arguments requires integers" msgstr "" -#: py/objstr.c -msgid "format needs a dict" +#: py/objint_mpz.c +msgid "pow() 3rd argument cannot be 0" msgstr "" -#: py/objstr.c -msgid "format string didn't convert all arguments" +#: py/objobject.c +msgid "__new__ arg must be a user-type" msgstr "" -#: py/objstr.c -msgid "format string needs more arguments" +#: py/objobject.c +msgid "arg must be user-type" msgstr "" -#: py/objdeque.c -msgid "full" -msgstr "" +#: py/objrange.c py/objslice.c shared-bindings/random/__init__.c +msgid "%q step cannot be zero" +msgstr "%q sıfır olamaz" -#: py/argcheck.c -msgid "function doesn't take keyword arguments" -msgstr "" +#: py/objslice.c +msgid "Cannot subclass slice" +msgstr "Alt sınıf kesilemez" -#: py/argcheck.c -#, c-format -msgid "function expected at most %d arguments, got %d" +#: py/objstr.c +msgid "bytes value out of range" msgstr "" -#: py/bc.c py/objnamedtuple.c -msgid "function got multiple values for argument '%q'" +#: py/objstr.c +msgid "join expects a list of str/bytes objects consistent with self object" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "function has the same sign at the ends of interval" +#: py/objstr.c +msgid "empty separator" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "function is defined for ndarrays only" -msgstr "" +#: py/objstr.c +msgid "rsplit(None,n)" +msgstr "rsplit(None,n)" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "function is implemented for ndarrays only" +#: py/objstr.c +msgid "bad format string" msgstr "" -#: py/argcheck.c +#: py/objstr.c #, c-format -msgid "function missing %d required positional arguments" +msgid "unmatched '%c' in format" msgstr "" -#: py/bc.c -msgid "function missing keyword-only argument" +#: py/objstr.c +msgid "bad conversion specifier" msgstr "" -#: py/bc.c -msgid "function missing required keyword argument '%q'" +#: py/objstr.c +msgid "end of format while looking for conversion specifier" msgstr "" -#: py/bc.c +#: py/objstr.c #, c-format -msgid "function missing required positional argument #%d" +msgid "unknown conversion specifier %c" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c shared-bindings/_eve/__init__.c -#: shared-bindings/time/__init__.c -#, c-format -msgid "function takes %d positional arguments but %d were given" +#: py/objstr.c +msgid "expected ':' after format specifier" msgstr "" -#: py/objgenerator.c -msgid "generator already executing" +#: py/objstr.c +msgid "" +"can't switch from automatic field numbering to manual field specification" msgstr "" -#: py/objgenerator.c -msgid "generator ignored GeneratorExit" +#: py/objstr.c +msgid "%q index out of range" +msgstr "%q indeksi aralık dışında" + +#: py/objstr.c +msgid "attributes not supported" msgstr "" -#: py/objgenerator.c py/runtime.c -msgid "generator raised StopIteration" +#: py/objstr.c +msgid "" +"can't switch from manual field specification to automatic field numbering" msgstr "" -#: extmod/modhashlib.c -msgid "hash is final" +#: py/objstr.c +msgid "invalid format specifier" msgstr "" -#: extmod/modheapq.c -msgid "heap must be a list" +#: py/objstr.c +msgid "sign not allowed in string format specifier" msgstr "" -#: py/compile.c -msgid "identifier redefined as global" +#: py/objstr.c +msgid "sign not allowed with integer format specifier 'c'" msgstr "" -#: py/compile.c -msgid "identifier redefined as nonlocal" +#: py/objstr.c +msgid "unknown format code '%c' for object of type '%q'" msgstr "" -#: py/compile.c -msgid "import * not at module level" +#: py/objstr.c +msgid "'=' alignment not allowed in string format specifier" +msgstr "'=' hizalamasına string biçiminde izin verilmez" + +#: py/objstr.c +msgid "format needs a dict" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy arch" +#: py/objstr.c +msgid "incomplete format key" msgstr "" -#: py/persistentcode.c -msgid "incompatible .mpy file" +#: py/objstr.c +msgid "incomplete format" msgstr "" #: py/objstr.c -msgid "incomplete format" +msgid "format string needs more arguments" msgstr "" #: py/objstr.c -msgid "incomplete format key" +#, c-format +msgid "%%c needs int or char" +msgstr "%%c int ya da char gerektirir" + +#: py/objstr.c +#, c-format +msgid "unsupported format character '%c' (0x%x) at index %d" msgstr "" -#: extmod/modbinascii.c -msgid "incorrect padding" +#: py/objstr.c +msgid "format string didn't convert all arguments" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/transform.c -msgid "index is out of bounds" +#: py/objstr.c +msgid "non-hex digit" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "index must be tuple or int" +#: py/objstr.c +msgid "can't convert to str implicitly" msgstr "" -#: extmod/ulab/code/numpy/numerical.c extmod/ulab/code/ulab_tools.c -#: ports/espressif/common-hal/pulseio/PulseIn.c -#: shared-bindings/bitmaptools/__init__.c -msgid "index out of range" +#: py/objstr.c +msgid "can't convert '%q' object to %q implicitly" msgstr "" -#: py/obj.c -msgid "indices must be integers" +#: py/objstrunicode.c +#, c-format +msgid "string indices must be integers, not %s" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "indices must be integers, slices, or Boolean lists" +#: py/objstrunicode.c +msgid "string index out of range" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "initial values must be iterable" +#: py/objtype.c +msgid "Call super().__init__() before accessing native object." +msgstr "Yerel nesneye erişmeden önce super().__init__() fonksiyonunu çağırın." + +#: py/objtype.c +msgid "__init__() should return None" msgstr "" -#: py/compile.c -msgid "inline assembler must be a function" +#: py/objtype.c +#, c-format +msgid "__init__() should return None, not '%s'" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output dimensions differ" +#: py/objtype.c py/runtime.c +msgid "unreadable attribute" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input and output shapes differ" +#: py/objtype.c py/runtime.c +msgid "object not callable" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input argument must be an integer, a tuple, or a list" +#: py/objtype.c py/runtime.c shared-module/atexit/__init__.c +msgid "'%q' object isn't callable" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "input array length must be power of 2" +#: py/objtype.c +msgid "type takes 1 or 3 arguments" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input arrays are not compatible" +#: py/objtype.c +msgid "can't create instance" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input data must be an iterable" +#: py/objtype.c +msgid "can't create '%q' instances" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "input dtype must be float or complex" +#: py/objtype.c +msgid "can't add special method to already-subclassed class" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input is not iterable" +#: py/objtype.c +msgid "type isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "input matrix is asymmetric" +#: py/objtype.c +msgid "type '%q' isn't an acceptable base type" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -#: extmod/ulab/code/scipy/linalg/linalg.c -msgid "input matrix is singular" +#: py/objtype.c +msgid "multiple inheritance not supported" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "input must be 1- or 2-d" +#: py/objtype.c +msgid "multiple bases have instance lay-out conflict" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be a 1D ndarray" +#: py/objtype.c +msgid "first argument to super() must be type" msgstr "" -#: extmod/ulab/code/scipy/linalg/linalg.c extmod/ulab/code/user/user.c -msgid "input must be a dense ndarray" +#: py/objtype.c +msgid "issubclass() arg 2 must be a class or a tuple of classes" msgstr "" -#: extmod/ulab/code/user/user.c shared-bindings/_eve/__init__.c -msgid "input must be an ndarray" +#: py/objtype.c +msgid "issubclass() arg 1 must be a class" msgstr "" -#: extmod/ulab/code/numpy/carray/carray.c -msgid "input must be an ndarray, or a scalar" +#: py/parse.c +msgid "not a constant" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "input must be one-dimensional" +#: py/parse.c +msgid "Unable to init parser" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "input must be square matrix" +#: py/parse.c +msgid "unexpected indent" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "input must be tuple, list, range, or ndarray" +#: py/parse.c +msgid "unindent doesn't match any outer indent level" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "input vectors must be of equal length" +#: py/parse.c +msgid "malformed f-string" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "interp is defined for 1D iterables of equal length" +#: py/parsenum.c +msgid "invalid syntax for integer" msgstr "" -#: shared-bindings/_bleio/Adapter.c +#: py/parsenum.c #, c-format -msgid "interval must be in range %s-%s" +msgid "invalid syntax for integer with base %d" msgstr "" -#: py/emitinlinerv32.c -msgid "invalid RV32 instruction '%q'" +#: py/parsenum.c +msgid "invalid syntax for number" msgstr "" -#: py/compile.c -msgid "invalid arch" +#: py/parsenum.c +msgid "decimal numbers not supported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" +#: py/persistentcode.c +msgid "incompatible .mpy file" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid cert" +#: py/persistentcode.c +msgid "MicroPython .mpy file; use CircuitPython mpy-cross" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -#, c-format -msgid "invalid destination buffer, must be an array of type: %c" +#: py/persistentcode.c +msgid "native code in .mpy unsupported" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element size %d for bits_per_pixel %d\n" +#: py/persistentcode.c +msgid "incompatible .mpy arch" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -#, c-format -msgid "invalid element_size %d, must be, 1, 2, or 4" +#: py/proto.c shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "'%q' object does not support '%q'" +msgstr "'%q' nesnesi '%q' öğesini desteklemiyor" + +#: py/qstr.c +msgid "name too long" msgstr "" -#: shared-bindings/traceback/__init__.c -msgid "invalid exception" +#: py/runtime.c +msgid "name not defined" msgstr "" -#: py/objstr.c -msgid "invalid format specifier" +#: py/runtime.c +msgid "name '%q' isn't defined" msgstr "" -#: shared-bindings/wifi/Radio.c -msgid "invalid hostname" +#: py/runtime.c +msgid "unsupported type for operator" msgstr "" -#: shared-module/ssl/SSLSocket.c -msgid "invalid key" +#: py/runtime.c +msgid "unsupported type for %q: '%s'" msgstr "" -#: py/compile.c -msgid "invalid micropython decorator" +#: py/runtime.c +msgid "unsupported types for %q: '%q', '%q'" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c -msgid "invalid setting" +#: py/runtime.c +msgid "wrong number of values to unpack" msgstr "" -#: shared-bindings/random/__init__.c -msgid "invalid step" +#: py/runtime.c +#, c-format +msgid "need more than %d values to unpack" msgstr "" -#: py/compile.c py/parse.c -msgid "invalid syntax" +#: py/runtime.c +#, c-format +msgid "too many values to unpack (expected %d)" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for integer" +#: py/runtime.c +msgid "type object '%q' has no attribute '%q'" msgstr "" -#: py/parsenum.c -#, c-format -msgid "invalid syntax for integer with base %d" +#: py/runtime.c +msgid "module '%q' has no attribute '%q'" msgstr "" -#: py/parsenum.c -msgid "invalid syntax for number" +#: py/runtime.c +msgid "'%s' object has no attribute '%q'" +msgstr "'%s' nesnesinin '%q' özelliği yok" + +#: py/runtime.c +msgid "can't set attribute '%q'" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 1 must be a class" +#: py/runtime.c +msgid "object not iterable" msgstr "" -#: py/objtype.c -msgid "issubclass() arg 2 must be a class or a tuple of classes" +#: py/runtime.c +msgid "'%q' object isn't iterable" +msgstr "'%q' nesnesi iterable değildir" + +#: py/runtime.c +msgid "object not an iterator" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "iterations did not converge" +#: py/runtime.c +msgid "'%q' object isn't an iterator" +msgstr "'%q' nesnesi bir iteratör değildir" + +#: py/runtime.c +msgid "exceptions must derive from BaseException" msgstr "" -#: py/objstr.c -msgid "join expects a list of str/bytes objects consistent with self object" +#: py/runtime.c +msgid "can't import name %q" msgstr "" -#: py/argcheck.c -msgid "keyword argument(s) not implemented - use normal args instead" +#: py/runtime.c +msgid "memory allocation failed, heap is locked" msgstr "" -#: py/emitinlinethumb.c py/emitinlinextensa.c -msgid "label '%q' not defined" +#: py/runtime.c +#, c-format +msgid "memory allocation failed, allocating %u bytes" +msgstr "" + +#: py/runtime.c +msgid "can't convert to int" msgstr "" -#: py/compile.c -msgid "label redefined" +#: py/runtime.c +msgid "division by zero" msgstr "" -#: py/objarray.c -msgid "lhs and rhs should be compatible" +#: py/runtime.c +msgid "maximum recursion depth exceeded" msgstr "" -#: py/emitnative.c -msgid "local '%q' has type '%q' but source is '%q'" +#: py/sequence.c shared-bindings/displayio/Group.c +msgid "object not in sequence" msgstr "" -#: py/emitnative.c -msgid "local '%q' used before type known" +#: py/stream.c shared-bindings/getpass/__init__.c +msgid "stream operation not supported" msgstr "" #: py/vm.c msgid "local variable referenced before assignment" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -msgid "loopback + silent mode not supported by peripheral" +#: py/vm.c +msgid "no active exception to reraise" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS already initialized" +#: py/vm.c +msgid "opcode" msgstr "" -#: ports/espressif/common-hal/mdns/Server.c -#: ports/raspberrypi/common-hal/mdns/Server.c -msgid "mDNS only works with built-in WiFi" +#: shared-bindings/_bleio/Adapter.c +msgid "Cannot create a new Adapter; use _bleio.adapter;" +msgstr "yeni Adaptör oluşturulamadı; _bleio.adapter kullanın;" + +#: shared-bindings/_bleio/Adapter.c +msgid "Could not set address" +msgstr "Adres ayarlanamadı" + +#: shared-bindings/_bleio/Adapter.c +#, c-format +msgid "interval must be in range %s-%s" msgstr "" -#: py/parse.c -msgid "malformed f-string" +#: shared-bindings/_bleio/Adapter.c +#, fuzzy +msgid "Cannot have scan responses for extended, connectable advertisements." +msgstr "Genişletilmiş, bağlanabilir reklamlar için tarama yanıtları yapılamaz." + +#: shared-bindings/_bleio/Adapter.c +msgid "Only connectable advertisements can be directed" msgstr "" -#: shared-bindings/_stage/Layer.c -msgid "map buffer too small" +#: shared-bindings/_bleio/Adapter.c +msgid "non-zero timeout must be >= interval" msgstr "" -#: py/modmath.c shared-bindings/math/__init__.c -msgid "math domain error" +#: shared-bindings/_bleio/Adapter.c +msgid "window must be <= interval" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "matrix is not positive definite" +#: shared-bindings/_bleio/Adapter.c +msgid "Prefix buffer must be on the heap" msgstr "" -#: ports/espressif/common-hal/_bleio/Descriptor.c -#: ports/nordic/common-hal/_bleio/Characteristic.c -#: ports/nordic/common-hal/_bleio/Descriptor.c +#: shared-bindings/_bleio/CharacteristicBuffer.c +msgid "CharacteristicBuffer writing not provided" +msgstr "CharacteristicBuffer yazılmı sağlanmadı" + +#: shared-bindings/_bleio/Connection.c +msgid "" +"Connection has been disconnected and can no longer be used. Create a new " +"connection." +msgstr "Bağlantı koparıldı ve tekrar kullanılamaz. Yeni bir bağlantı kurun." + +#: shared-bindings/_bleio/PacketBuffer.c #, c-format -msgid "max_length must be 0-%d when fixed_length is %s" -msgstr "" +msgid "Buffer too short by %d bytes" +msgstr "Buffer bitten %d daha az" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/random/random.c -msgid "maximum number of dimensions is " +#: shared-bindings/_bleio/PacketBuffer.c +msgid "No connection: length cannot be determined" msgstr "" -#: py/runtime.c -msgid "maximum recursion depth exceeded" +#: shared-bindings/_bleio/UUID.c +msgid "UUID string not 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter must be > 0" +#: shared-bindings/_bleio/UUID.c +msgid "UUID value is not str, int or byte buffer" msgstr "" -#: extmod/ulab/code/scipy/optimize/optimize.c -msgid "maxiter should be > 0" +#: shared-bindings/_bleio/UUID.c +msgid "not a 128-bit UUID" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "median argument must be an ndarray" +#: shared-bindings/_bleio/__init__.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c shared-module/bitmaptools/__init__.c +#: shared-module/displayio/Bitmap.c shared-module/displayio/Group.c +msgid "Read-only" msgstr "" -#: py/runtime.c -#, c-format -msgid "memory allocation failed, allocating %u bytes" -msgstr "" +#: shared-bindings/_pew/PewPew.c +msgid "Incorrect buffer size" +msgstr "Yanlış buffer size" -#: py/runtime.c -msgid "memory allocation failed, heap is locked" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "nested index must be int" msgstr "" -#: py/objarray.c -msgid "memoryview offset too large" +#: shared-bindings/_pixelmap/PixelMap.c +msgid "index must be tuple or int" msgstr "" -#: py/objarray.c -msgid "memoryview: length is not a multiple of itemsize" +#: shared-bindings/_stage/Layer.c +msgid "map buffer too small" msgstr "" -#: extmod/modtime.c -msgid "mktime needs a tuple of length 8 or 9" +#: shared-bindings/_stage/Text.c +msgid "chars buffer too small" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "mode must be complete, or reduced" +#: shared-bindings/adafruit_bus_device/spi_device/SPIDevice.c +msgid "Pin is input only" msgstr "" -#: py/runtime.c -msgid "module '%q' has no attribute '%q'" +#: shared-bindings/adafruit_pixelbuf/PixelBuf.c +#: shared-module/_pixelmap/PixelMap.c +#, c-format +msgid "Unmatched number of items on RHS (expected %d, got %d)." msgstr "" -#: py/builtinimport.c -msgid "module not found" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "Key must be 16, 24, or 32 bytes long" +msgstr "Anahtar 16, 24 veya 32 bayt uzunluğunda olmalıdır" -#: ports/espressif/common-hal/wifi/Monitor.c -msgid "monitor init failed" +#: shared-bindings/aesio/aes.c +msgid "Requested AES mode is unsupported" msgstr "" -#: extmod/ulab/code/numpy/poly.c -msgid "more degrees of freedom than data points" +#: shared-bindings/aesio/aes.c +msgid "Source and destination buffers must be the same length" msgstr "" -#: py/compile.c -msgid "multiple *x in assignment" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "ECB only operates on 16 bytes at a time" +msgstr "ECB aynı anda yalnızca 16 baytla çalışır" -#: py/objtype.c -msgid "multiple bases have instance lay-out conflict" -msgstr "" +#: shared-bindings/aesio/aes.c +msgid "CBC blocks must be multiples of 16 bytes" +msgstr "CBC blokları 16 baytın katları şeklinde olmalı" -#: py/objtype.c -msgid "multiple inheritance not supported" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Slice and value different lengths." msgstr "" -#: py/emitnative.c -msgid "must raise an object" -msgstr "" +#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c +#: shared-bindings/nvm/ByteArray.c +msgid "Array values should be single bytes." +msgstr "Dizi değerleri tekil bytelar olmalıdır." -#: py/modbuiltins.c -msgid "must use keyword argument for key function" +#: shared-bindings/alarm/SleepMemory.c +msgid "Unable to write to sleep_memory." msgstr "" -#: py/runtime.c -msgid "name '%q' isn't defined" +#: shared-bindings/alarm/__init__.c +msgid "Expected a kind of %q" msgstr "" -#: py/runtime.c -msgid "name not defined" +#: shared-bindings/alarm/time/TimeAlarm.c shared-bindings/time/__init__.c +msgid "RTC is not supported on this board" msgstr "" -#: py/qstr.c -msgid "name too long" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Supply one of monotonic_time or epoch_time" msgstr "" -#: py/persistentcode.c -msgid "native code in .mpy unsupported" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "epoch_time not supported on this board" msgstr "" -#: py/emitnative.c -msgid "native yield" +#: shared-bindings/alarm/time/TimeAlarm.c +msgid "Time is in the past." msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "ndarray length overflows" -msgstr "" +#: shared-bindings/analogbufio/BufferedIn.c +msgid "%q must be a bytearray or array of type 'H' or 'B'" +msgstr "%q 'H' ya da 'B' tipi bir bytearray ya da array olmalıdır" -#: py/runtime.c -#, c-format -msgid "need more than %d values to unpack" +#: shared-bindings/audiobusio/I2SOut.c shared-bindings/audioio/AudioOut.c +#: shared-bindings/audiopwmio/PWMAudioOut.c shared-bindings/mcp4822/MCP4822.c +#: shared-bindings/usb_audio/USBMicrophone.c +msgid "Not playing" msgstr "" -#: py/modmath.c -msgid "negative factorial" +#: shared-bindings/audiobusio/PDMIn.c +msgid "%q must be multiple of 8." +msgstr "%q 8'in katı olmalıdır." + +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Cannot record to a file" +msgstr "Dosyaya kayıt yapılamıyor" + +#: shared-bindings/audiobusio/PDMIn.c shared-bindings/audioi2sin/I2SIn.c +msgid "Destination capacity is smaller than destination_length." +msgstr "Hedef kapasitesi, hedef_uzunluğundan daha küçük." + +#: shared-bindings/audiobusio/PDMIn.c +msgid "destination buffer must be an array of type 'H' for bit_depth = 16" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative power with no float support" +#: shared-bindings/audiobusio/PDMIn.c +msgid "" +"destination buffer must be a bytearray or array of type 'B' for bit_depth = 8" msgstr "" -#: py/objint_longlong.c py/objint_mpz.c py/runtime.c -msgid "negative shift count" +#: shared-bindings/audiocore/RawSample.c +msgid "%q must be a bytearray or array of type 'h', 'H', 'b', or 'B'" +msgstr "%q 'h', 'H', 'b' ya da 'B' tipi bir bytearray ya da array olmalı" + +#: shared-bindings/audiocore/RawSample.c +msgid "Length of %q must be an even multiple of channel_count * type_size" msgstr "" -#: shared-bindings/_pixelmap/PixelMap.c -msgid "nested index must be int" +#: shared-bindings/audiocore/WaveFile.c shared-bindings/audiomp3/MP3Decoder.c +#: shared-bindings/displayio/OnDiskBitmap.c shared-bindings/gifio/OnDiskGif.c +#: shared-bindings/synthio/__init__.c shared-module/gifio/GifWriter.c +msgid "file must be a file opened in byte mode" msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "no SD card" +#: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/MultiTapDelay.c +#: shared-bindings/audiodelays/PitchShift.c +#: shared-bindings/audiofilters/Distortion.c +#: shared-bindings/audiofilters/Filter.c shared-bindings/audiofilters/Phaser.c +#: shared-bindings/audiomixer/Mixer.c +msgid "bits_per_sample must be 8 or 16" msgstr "" -#: py/vm.c -msgid "no active exception to reraise" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "samples_signed must be true" msgstr "" -#: py/compile.c -msgid "no binding for nonlocal found" +#: shared-bindings/audiofreeverb/Freeverb.c +msgid "bits_per_sample must be 16" msgstr "" -#: shared-module/msgpack/__init__.c -msgid "no default packer" +#: shared-bindings/audioi2sin/I2SIn.c +#, c-format +msgid "invalid destination buffer, must be an array of type: %c" msgstr "" -#: extmod/modrandom.c extmod/ulab/code/numpy/random/random.c -msgid "no default seed" -msgstr "" +#: shared-bindings/audioio/AudioOut.c +msgid "%q and %q must be different" +msgstr "%q ve %q farklı olmalılar" -#: py/builtinimport.c -msgid "no module named '%q'" -msgstr "" +#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Fonksiyon kilit gerektirir" -#: shared-module/sdcardio/SDCard.c -msgid "no response from SD card" +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" msgstr "" -#: ports/espressif/common-hal/espcamera/Camera.c py/objobject.c py/runtime.c -msgid "no such attribute" +#: shared-bindings/bitmapfilter/__init__.c +msgid "" +"weights must be a sequence with an odd square number of elements (usually 9 " +"or 25)" msgstr "" -#: ports/espressif/common-hal/_bleio/Connection.c -#: ports/nordic/common-hal/_bleio/Connection.c -msgid "non-UUID found in service_uuids_whitelist" +#: shared-bindings/bitmapfilter/__init__.c +msgid "weights must be an object of type %q, %q, %q, or %q, not %q " msgstr "" -#: py/compile.c -msgid "non-default argument follows default argument" +#: shared-bindings/bitmaptools/__init__.c +msgid "clip point must be (x,y) tuple" msgstr "" -#: py/objstr.c -msgid "non-hex digit" +#: shared-bindings/bitmaptools/__init__.c +msgid "source palette too large" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "non-zero timeout must be > 0.01" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Bitmap size and bits per value must match" +msgstr "Bitmap boyutu ve bit başına değer uyuşmalı" -#: shared-bindings/_bleio/Adapter.c -msgid "non-zero timeout must be >= interval" +#: shared-bindings/bitmaptools/__init__.c +msgid "For L8 colorspace, input bitmap must have 8 bits per pixel" msgstr "" +"L8 renk uzayı için, giriş bitmap'i piksel başına 8 bayta sahip olmalıdır" -#: shared-bindings/_bleio/UUID.c -msgid "not a 128-bit UUID" +#: shared-bindings/bitmaptools/__init__.c +msgid "For RGB colorspaces, input bitmap must have 16 bits per pixel" msgstr "" +"RGB renk uzayı için, giriş bitmap'i piksel başına 16 bayta sahip olmalıdır" -#: py/parse.c -msgid "not a constant" +#: shared-bindings/bitmaptools/__init__.c +msgid "Unsupported colorspace" msgstr "" -#: extmod/ulab/code/numpy/carray/carray_tools.c -msgid "not implemented for complex dtype" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap size must match the other bitmaps" msgstr "" -#: extmod/ulab/code/numpy/bitwise.c -msgid "not supported for input types" +#: shared-bindings/bitmaptools/__init__.c +msgid "Mask bitmap must have 8 bits per pixel" msgstr "" -#: shared-bindings/i2cioexpander/IOExpander.c -msgid "num_pins must be 8 or 16" +#: shared-bindings/bitmaptools/__init__.c +msgid "out of range of target" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "number of points must be at least 2" +#: shared-bindings/bitmaptools/__init__.c +msgid "value out of range of target" msgstr "" -#: py/builtinhelp.c -msgid "object " +#: shared-bindings/bitmaptools/__init__.c +msgid "background value out of range of target" msgstr "" -#: py/obj.c -#, c-format -msgid "object '%s' isn't a tuple or list" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays types have different sizes" +msgstr "Kordinat dizilerinin türlerifarklı boyutlara sahip" -#: shared-bindings/digitalio/DigitalInOutProtocol.c -msgid "object does not support DigitalInOut protocol" -msgstr "" +#: shared-bindings/bitmaptools/__init__.c +msgid "Coordinate arrays have different lengths" +msgstr "Kordinat dizilerinin uzunlukları farklı" -#: py/obj.c -msgid "object doesn't support item assignment" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element_size %d, must be, 1, 2, or 4" msgstr "" -#: py/obj.c -msgid "object doesn't support item deletion" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid element size %d for bits_per_pixel %d\n" msgstr "" -#: py/obj.c -msgid "object has no len" +#: shared-bindings/bitmaptools/__init__.c +#, c-format +msgid "invalid bits_per_pixel %d, must be, 1, 2, 4, 8, 16, 24, or 32" msgstr "" -#: py/obj.c -msgid "object isn't subscriptable" +#: shared-bindings/bitmaptools/__init__.c +msgid "bitmap sizes must match" msgstr "" -#: py/runtime.c -msgid "object not an iterator" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 2 or 65536" msgstr "" -#: py/objtype.c py/runtime.c -msgid "object not callable" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 65536" msgstr "" -#: py/sequence.c shared-bindings/displayio/Group.c -msgid "object not in sequence" +#: shared-bindings/bitmaptools/__init__.c +msgid "source_bitmap must have value_count of 8" msgstr "" -#: py/runtime.c -msgid "object not iterable" +#: shared-bindings/bitmaptools/__init__.c +msgid "unsupported colorspace for dither" msgstr "" -#: py/obj.c +#: shared-bindings/bitops/__init__.c #, c-format -msgid "object of type '%s' has no len()" -msgstr "" +msgid "Input buffer length (%d) must be a multiple of the strand count (%d)" +msgstr "Giriş buffer uzunluğu (%d) strand sayımının (%d) katı olmalıdır" -#: py/obj.c -msgid "object with buffer protocol required" +#: shared-bindings/board/__init__.c +msgid "No default %q bus" msgstr "" -#: supervisor/shared/web_workflow/web_workflow.c -msgid "off" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/epaperdisplay/EPaperDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +#: shared-bindings/mipidsi/Display.c +msgid "Display rotation must be in 90 degree increments" +msgstr "Ekran dönüşü 90 derecelik artışlarla olmalıdır" -#: extmod/ulab/code/utils/utils.c -msgid "offset is too large" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +msgid "%q must be 1 when %q is True" +msgstr "%q 1 olmalı, %q True olduğu zaman" -#: shared-bindings/dualbank/__init__.c -msgid "offset must be >= 0" -msgstr "" +#: shared-bindings/busdisplay/BusDisplay.c +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Display must have a 16 bit colorspace." +msgstr "Ekran 16 bitlik bir renk uzayına sahip olmalıdır." -#: extmod/ulab/code/numpy/create.c -msgid "offset must be non-negative and no greater than buffer length" +#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c +msgid "tx and rx cannot both be None" msgstr "" -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only bit_depth=16 is supported" +#: shared-bindings/busio/UART.c shared-bindings/displayio/Group.c +msgid "Must be a %q subclass." msgstr "" -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only mono is supported" +#: shared-bindings/canio/RemoteTransmissionRequest.c +msgid "RemoteTransmissionRequests limited to 8 bytes" msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "only ndarrays can be concatenated" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Cannot set value when direction is input." +msgstr "Yön, giriş olduğunda değer ayarlanamıyor." -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only oversample=64 is supported" -msgstr "" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Drive mode not used when direction is input." +msgstr "Yön, giriş olduğunda sürüş modu kullanılmaz." -#: ports/nordic/common-hal/audiobusio/PDMIn.c -#: ports/stm/common-hal/audiobusio/PDMIn.c -msgid "only sample_rate=16000 is supported" +#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/i2cioexpander/IOPin.c +msgid "Pull not used when direction is output." msgstr "" -#: py/objarray.c py/objstr.c py/objstrunicode.c py/objtuple.c -#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c -#: shared-bindings/nvm/ByteArray.c -msgid "only slices with step=1 (aka None) are supported" -msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' method" +msgstr "%q nesnesinde '%q' metodu eksik" -#: py/vm.c -msgid "opcode" -msgstr "" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "%q object missing '%q' attribute" +msgstr "%q nesnesinde '%q' niteliği eksik" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: expecting %q" +#: shared-bindings/digitalio/DigitalInOutProtocol.c +msgid "object does not support DigitalInOut protocol" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: must not be zero" +#: shared-bindings/displayio/Bitmap.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +msgid "Cannot delete values" +msgstr "Değerler silinemez" + +#: shared-bindings/displayio/Bitmap.c shared-bindings/displayio/Group.c +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/memorymonitor/AllocationSize.c +#: shared-bindings/pulseio/PulseIn.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +msgid "Slices not supported" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: out of range" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a bytearray or array of type 'b' or 'B'" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: undefined label '%q'" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be 3 bytes (RGB) or 4 bytes (RGB + pad byte)" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q' argument %d: unknown register" +#: shared-bindings/displayio/Palette.c +msgid "color must be between 0x000000 and 0xffffff" msgstr "" -#: py/emitinlinerv32.c -msgid "opcode '%q': expecting %d arguments" +#: shared-bindings/displayio/Palette.c +msgid "color buffer must be a buffer, tuple, list, or int" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/bitwise.c -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/vector.c -msgid "operands could not be broadcast together" +#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-bindings/vectorio/VectorShape.c +msgid "unsupported %q type" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for 2D arrays only" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile width must exactly divide bitmap width" msgstr "" -#: extmod/ulab/code/numpy/linalg/linalg.c -msgid "operation is defined for ndarrays only" +#: shared-bindings/displayio/TileGrid.c +msgid "Tile height must exactly divide bitmap height" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is implemented for 1D Boolean arrays only" +#: shared-bindings/displayio/TileGrid.c +msgid "New bitmap must be same size as old bitmap" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "operation is not implemented on ndarrays" +#: shared-bindings/displayio/TileGrid.c +#: shared-bindings/tilepalettemapper/TilePaletteMapper.c +#: shared-module/displayio/TileGrid.c +msgid "Tile index out of bounds" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "operation is not supported for given type" +#: shared-bindings/dualbank/__init__.c +msgid "offset must be >= 0" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "operation not supported for the input types" +#: shared-bindings/epaperdisplay/EPaperDisplay.c +msgid "Refresh too soon" msgstr "" -#: py/modbuiltins.c -msgid "ord expects a character" -msgstr "" +#: shared-bindings/framebufferio/FramebufferDisplay.c +msgid "Buffer is not a bytearray." +msgstr "Buffer bir bytearray değil." -#: py/modbuiltins.c -#, c-format -msgid "ord() expected a character, but string of length %d found" +#: shared-bindings/gnss/GNSS.c +msgid "System entry must be gnss.SatelliteSystem" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out array is too small" +#: shared-bindings/hashlib/__init__.c +msgid "Unsupported hash algorithm" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "out has wrong type" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "address out of range" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for complex dtype" +#: shared-bindings/i2cioexpander/IOExpander.c +msgid "num_pins must be 8 or 16" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out keyword is not supported for function" +#: shared-bindings/i2ctarget/I2CTarget.c +msgid "addresses is empty" msgstr "" -#: extmod/ulab/code/utils/utils.c -msgid "out must be a float dense array" +#: shared-bindings/ipaddress/IPv4Address.c shared-bindings/ipaddress/__init__.c +msgid "Not a valid IP string" msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be an ndarray" -msgstr "" +#: shared-bindings/ipaddress/IPv4Address.c +#, c-format +msgid "Address must be %d bytes long" +msgstr "Adres %d byte uzunluğunda olmalıdır" -#: extmod/ulab/code/numpy/vector.c -msgid "out must be of float dtype" +#: shared-bindings/ipaddress/__init__.c +msgid "Only int or string supported for ip" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "out of range of target" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "width must be greater than zero" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array has wrong type" +#: shared-bindings/is31fl3741/FrameBuffer.c +msgid "Scale dimensions must divide by 3" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "output array must be contiguous" -msgstr "" +#: shared-bindings/is31fl3741/IS31FL3741.c +msgid "Mapping must be a tuple" +msgstr "Map tuple olmalıdır" -#: py/objint_longlong.c py/objint_mpz.c -msgid "overflow converting long int to machine word" +#: shared-bindings/jpegio/JpegDecoder.c +msgid "%q must be of type %q, %q, or %q, not %q" +msgstr "%q; %q, %q veya %q tipi olmalıdır, %q değil" + +#: shared-bindings/mdns/Server.c +msgid "" +"Failed to add service TXT record; non-string or bytes found in txt_records" msgstr "" -#: py/modstruct.c -#, c-format -msgid "pack expected %d items for packing (got %d)" +#: shared-bindings/memorymap/AddressRange.c +msgid "Address range wraps around" +msgstr "Adres aralığı başa döner" + +#: shared-bindings/microcontroller/Pin.c +msgid "%q contains duplicate pins" +msgstr "%q yinelenen pinler içeriyor" + +#: shared-bindings/microcontroller/Pin.c +msgid "%q and %q contain duplicate pins" +msgstr "%q ve %q yinelenen pinler içeriyor" + +#: shared-bindings/msgpack/ExtType.c +msgid "code outside range 0~127" msgstr "" -#: py/emitinlinerv32.c -msgid "parameters must be registers in sequence a0 to a3" +#: shared-bindings/msgpack/__init__.c +msgid "default is not a function" msgstr "" -#: py/emitinlinextensa.c -msgid "parameters must be registers in sequence a2 to a5" +#: shared-bindings/msgpack/__init__.c +msgid "ext_hook is not a function" msgstr "" -#: py/emitinlinethumb.c -msgid "parameters must be registers in sequence r0 to r3" +#: shared-bindings/nvm/ByteArray.c +msgid "Unable to write to nvm." msgstr "" -#: extmod/vfs_posix_file.c -msgid "poll on file not available on win32" +#: shared-bindings/os/__init__.c +msgid "No hardware random available" msgstr "" -#: ports/espressif/common-hal/pulseio/PulseIn.c -msgid "pop from an empty PulseIn" +#: shared-bindings/paralleldisplaybus/ParallelBus.c +msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: ports/atmel-samd/common-hal/pulseio/PulseIn.c -#: ports/cxd56/common-hal/pulseio/PulseIn.c -#: ports/nordic/common-hal/pulseio/PulseIn.c -#: ports/raspberrypi/common-hal/pulseio/PulseIn.c -#: ports/stm/common-hal/pulseio/PulseIn.c py/objdict.c py/objlist.c py/objset.c #: shared-bindings/ps2io/Ps2.c -msgid "pop from empty %q" -msgstr "" +msgid "Failed sending command." +msgstr "Komut gönderilemedi." -#: shared-bindings/socketpool/Socket.c -msgid "port must be >= 0" -msgstr "" +#: shared-bindings/pulseio/PulseOut.c +msgid "Array must contain halfwords (type 'H')" +msgstr "Dizi yarımsözcüklere sahip olmalıdır (tip 'H')" -#: py/compile.c -msgid "positional arg after **" +#: shared-bindings/pwmio/PWMOut.c +msgid "Conflicting settings for shared resource" msgstr "" -#: py/compile.c -msgid "positional arg after keyword arg" +#: shared-bindings/random/__init__.c +msgid "stop not reachable from start" msgstr "" -#: py/objint_mpz.c -msgid "pow() 3rd argument cannot be 0" +#: shared-bindings/random/__init__.c +msgid "invalid step" msgstr "" -#: py/objint_mpz.c -msgid "pow() with 3 arguments requires integers" +#: shared-bindings/random/__init__.c +msgid "empty sequence" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "pull masks conflict with direction masks" +#: shared-bindings/rclcpy/Publisher.c +msgid "Publishers can only be created from a parent node" msgstr "" -#: extmod/ulab/code/numpy/fft/fft_tools.c -msgid "real and imaginary parts must be of equal length" +#: shared-bindings/rgbmatrix/RGBMatrix.c +msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30" msgstr "" -#: extmod/modre.c -msgid "regex too complex" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] is not on the same port as clock" msgstr "" -#: py/builtinimport.c -msgid "relative import" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "rgb_pins[%d] duplicates another pin assignment" msgstr "" -#: py/obj.c +#: shared-bindings/rgbmatrix/RGBMatrix.c #, c-format -msgid "requested length %d but object has length %d" +msgid "" +"Pinout uses %d bytes per element, which consumes more than the ideal %d " +"bytes. If this cannot be avoided, pass allow_inefficient=True to the " +"constructor" msgstr "" -#: py/objint_longlong.c py/parsenum.c -msgid "result overflows long long storage" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Must use a multiple of 6 rgb pins, not %d" msgstr "" -#: extmod/ulab/code/ndarray_operators.c -msgid "results cannot be cast to specified type" +#: shared-bindings/rgbmatrix/RGBMatrix.c +#, c-format +msgid "" +"%d address pins, %d rgb pins and %d tiles indicate a height of %d, not %d" msgstr "" +"%d adres pinleri, %d RGB pinleri ve %d döşemeleri %d'nin yüksekliği " +"gösterir, %d'nin değil" -#: py/compile.c -msgid "return annotation must be an identifier" +#: shared-bindings/socketpool/Socket.c +msgid "port must be >= 0" msgstr "" -#: py/emitnative.c -msgid "return expected '%q' but got '%q'" +#: shared-bindings/socketpool/Socket.c shared-bindings/ssl/SSLSocket.c +msgid "buffer too small for requested bytes" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] duplicates another pin assignment" +#: shared-bindings/socketpool/SocketPool.c +msgid "Name or service not known" msgstr "" -#: shared-bindings/rgbmatrix/RGBMatrix.c -#, c-format -msgid "rgb_pins[%d] is not on the same port as clock" +#: shared-bindings/spitarget/SPITarget.c +msgid "Packet buffers for an SPI transfer must have the same length." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "roll argument must be an ndarray" +#: shared-bindings/ssl/SSLContext.c +msgid "Server side context cannot have hostname" msgstr "" -#: py/objstr.c -msgid "rsplit(None,n)" -msgstr "rsplit(None,n)" +#: shared-bindings/storage/__init__.c shared-bindings/usb_audio/__init__.c +#: shared-bindings/usb_cdc/__init__.c shared-bindings/usb_hid/__init__.c +#: shared-bindings/usb_midi/__init__.c shared-bindings/usb_video/__init__.c +msgid "Cannot change USB devices now" +msgstr "USB aygıtları şu an değiştirilemez" -#: shared-bindings/audiofreeverb/Freeverb.c -msgid "samples_signed must be true" +#: shared-bindings/supervisor/__init__.c shared-module/lvfontio/OnDiskFont.c +msgid "File not found" msgstr "" -#: ports/atmel-samd/common-hal/audiobusio/PDMIn.c -#: ports/raspberrypi/common-hal/audiobusio/PDMIn.c -msgid "sampling rate out of range" +#: shared-bindings/time/__init__.c +msgid "timestamp out of range for platform time_t" msgstr "" -#: py/modmicropython.c -msgid "schedule queue full" +#: shared-bindings/traceback/__init__.c +msgid "file write is not available" msgstr "" -#: py/builtinimport.c -msgid "script compilation not supported" +#: shared-bindings/traceback/__init__.c +msgid "invalid exception" msgstr "" -#: py/nativeglue.c -msgid "set unsupported" +#: shared-bindings/usb_audio/USBSpeaker.c +msgid "destination must be an array of type 'h'" msgstr "" -#: extmod/ulab/code/numpy/random/random.c -msgid "shape must be None, and integer or a tuple of integers" +#: shared-bindings/usb_audio/__init__.c +msgid "At least one of microphone and speaker must be enabled" +msgstr "Mikrofon veya hoparlörden en az biri etkinleştirilmiş olmalı" + +#: shared-bindings/usb_hid/Device.c +msgid "%q, %q, and %q must all be the same length" +msgstr "%q, %q ve %q aynı uzunlukta olmalıdır" + +#: shared-bindings/util.c +msgid "" +"Object has been deinitialized and can no longer be used. Create a new object." msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "shape must be integer or tuple of integers" -msgstr "" +#: shared-bindings/warnings/__init__.c +msgid "%q must be a subclass of %q" +msgstr "%q, %q'nün alt türü olmalıdır" -#: shared-module/msgpack/__init__.c -msgid "short read" -msgstr "" +#: shared-bindings/wifi/Monitor.c +msgid "%q out of bounds" +msgstr "%q sınırların dışında" -#: py/objstr.c -msgid "sign not allowed in string format specifier" +#: shared-bindings/wifi/Radio.c +msgid "Invalid hex password" msgstr "" -#: py/objstr.c -msgid "sign not allowed with integer format specifier 'c'" +#: shared-bindings/wifi/Radio.c +msgid "invalid hostname" msgstr "" -#: extmod/ulab/code/ulab_tools.c -msgid "size is defined for ndarrays only" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "Invalid MAC address" +msgstr "Geçersiz MAC adresi" -#: extmod/ulab/code/numpy/random/random.c -msgid "size must match out.shape when used together" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "AuthMode.OPEN is not used with password" +msgstr "AuthMode.OPEN bir şifre ile kullanılmadı" -#: py/nativeglue.c -msgid "slice unsupported" -msgstr "" +#: shared-bindings/wifi/Radio.c +msgid "Invalid BSSID" +msgstr "Geçersiz BSSID" -#: py/objint.c py/sequence.c -msgid "small int overflow" -msgstr "" +#: shared-bindings/wifi/Radio.c supervisor/shared/web_workflow/web_workflow.c +msgid "Authentication failure" +msgstr "Kimlik doğrulama hatası" -#: main.c -msgid "soft reboot\n" +#: shared-bindings/wifi/Radio.c +msgid "No network with that ssid" msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "sort argument must be an ndarray" +#: shared-bindings/wifi/Radio.c +#, c-format +msgid "Unknown failure %d" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos array must be of shape (n_section, 6)" +#: shared-module/adafruit_bus_device/i2c_device/I2CDevice.c +#, c-format +msgid "No I2C device at address: 0x%x" msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sos[:, 3] should be all ones" -msgstr "" +#: shared-module/audiocore/WaveFile.c +msgid "Invalid format chunk size" +msgstr "Geçersiz biçim yığın boyutu" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "sosfilt requires iterable arguments" +#: shared-module/audiocore/__init__.c shared-module/usb_audio/USBMicrophone.c +msgid "The sample's %q does not match" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "source palette too large" -msgstr "" +#: shared-module/audiodelays/MultiTapDelay.c +msgid "%q in %q must be of type %q or %q, not %q" +msgstr "%q'nün içindeki %q, %q veya %q tipi olmalıdır, %q değil" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 2 or 65536" -msgstr "" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Couldn't allocate decoder" +msgstr "Deşifre edici tahsis edilemedi" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 65536" -msgstr "" +#: shared-module/audiomp3/MP3Decoder.c +msgid "Failed to parse MP3 file" +msgstr "MP3 dosyası ayrıştırılamadı" -#: shared-bindings/bitmaptools/__init__.c -msgid "source_bitmap must have value_count of 8" -msgstr "" +#: shared-module/bitbangio/I2C.c +msgid "%q too long" +msgstr "%q çok uzun" -#: extmod/modre.c -msgid "splitting with sub-captures" +#: shared-module/bitmapfilter/__init__.c +msgid "bitmap size and depth must match" msgstr "" -#: shared-bindings/random/__init__.c -msgid "stop not reachable from start" +#: shared-module/bitmapfilter/__init__.c +msgid "unsupported bitmap depth" msgstr "" -#: py/stream.c shared-bindings/getpass/__init__.c -msgid "stream operation not supported" -msgstr "" +#: shared-module/displayio/Bitmap.c +#, fuzzy +msgid "Invalid bits per value" +msgstr "Geçersiz bit başına değer" -#: py/objarray.c py/objstr.c -msgid "string argument without an encoding" +#: shared-module/displayio/ColorConverter.c +msgid "Only one color can be transparent at a time" msgstr "" -#: py/objstrunicode.c -msgid "string index out of range" -msgstr "" +#: shared-module/displayio/Group.c +msgid "Layer already in a group" +msgstr "Katman zaten bir grupta" -#: py/objstrunicode.c +#: shared-module/displayio/Group.c +msgid "Layer must be a Group or TileGrid subclass" +msgstr "Katman, bir Grup ya da TileGrid alt sınıfı olmalıdır" + +#: shared-module/displayio/OnDiskBitmap.c #, c-format -msgid "string indices must be integers, not %s" +msgid "" +"Only Windows format, uncompressed BMP supported: given header size is %d" msgstr "" -#: py/objarray.c py/objstr.c -msgid "substring not found" +#: shared-module/displayio/OnDiskBitmap.c +msgid "RLE-compressed BMP not supported" msgstr "" -#: py/compile.c -msgid "super() can't find self" +#: shared-module/displayio/OnDiskBitmap.c +msgid "Unable to read color palette data" msgstr "" -#: extmod/modjson.c -msgid "syntax error in JSON" +#: shared-module/displayio/__init__.c +msgid "Too many displays" msgstr "" -#: extmod/modtime.c -msgid "ticks interval overflow" +#: shared-module/displayio/__init__.c +msgid "Too many display busses; forgot displayio.release_displays() ?" msgstr "" -#: ports/nordic/common-hal/watchdog/WatchDogTimer.c -msgid "timeout duration exceeded the maximum supported value" +#: shared-module/displayio/bus_core.c +msgid "Unsupported display bus type" msgstr "" -#: ports/nordic/common-hal/_bleio/Adapter.c -msgid "timeout must be < 655.35 secs" +#: shared-module/gifio/GifWriter.c +msgid "unsupported colorspace for GifWriter" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -msgid "timeout waiting for flux" +#: shared-module/i2cdisplaybus/I2CDisplayBus.c +#: shared-module/is31fl3741/IS31FL3741.c +#, c-format +msgid "Unable to find I2C Display at %x" msgstr "" -#: ports/raspberrypi/common-hal/floppyio/__init__.c -#: shared-module/floppyio/__init__.c -msgid "timeout waiting for index pulse" -msgstr "" +#: shared-module/i2cioexpander/IOExpander.c +msgid "Cannot deinitialize board IOExpander" +msgstr "Kart IOExpander'ı devreden çıkarılamıyor" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v1 card" +#: shared-module/imagecapture/ParallelImageCapture.c +msgid "This microcontroller does not support continuous capture." msgstr "" -#: shared-module/sdcardio/SDCard.c -msgid "timeout waiting for v2 card" -msgstr "" +#: shared-module/is31fl3741/FrameBuffer.c +msgid "LED mappings must match display size" +msgstr "LED eşlemeleri ekran boyutuyla eşleşmelidir" -#: ports/stm/common-hal/pwmio/PWMOut.c -msgid "timer re-init" +#: shared-module/jpegio/JpegDecoder.c +msgid "Interrupted by output function" msgstr "" -#: shared-bindings/time/__init__.c -msgid "timestamp out of range for platform time_t" +#: shared-module/jpegio/JpegDecoder.c +msgid "Device error or wrong termination of input stream" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "tobytes can be invoked for dense arrays only" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient memory pool for the image" msgstr "" -#: py/compile.c -msgid "too many args" +#: shared-module/jpegio/JpegDecoder.c +msgid "Insufficient stream input buffer" msgstr "" -#: extmod/ulab/code/ndarray.c extmod/ulab/code/numpy/create.c -msgid "too many dimensions" +#: shared-module/jpegio/JpegDecoder.c +msgid "Parameter error" msgstr "" -#: extmod/ulab/code/ndarray.c -msgid "too many indices" -msgstr "" +#: shared-module/jpegio/JpegDecoder.c +msgid "Data format error (may be broken data)" +msgstr "Veri formatı hatası (bozuk veri olabilir)" -#: py/asmthumb.c -msgid "too many locals for native method" +#: shared-module/jpegio/JpegDecoder.c +msgid "Right format but not supported" msgstr "" -#: py/runtime.c -#, c-format -msgid "too many values to unpack (expected %d)" +#: shared-module/jpegio/JpegDecoder.c +msgid "Unsupported JPEG (may be progressive)" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D arrays of equal length" +#: shared-module/jpegio/JpegDecoder.c +msgid "%q() without %q()" msgstr "" -#: extmod/ulab/code/numpy/approx.c -msgid "trapz is defined for 1D iterables" -msgstr "" +#: shared-module/memorymonitor/AllocationAlarm.c +#, c-format +msgid "Attempt to allocate %d blocks" +msgstr "%d bloğun ayrılması girişimi" -#: py/obj.c -msgid "tuple/list has wrong length" +#: shared-module/msgpack/__init__.c +msgid "short read" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_driver_install returned esp-idf error #%d" +#: shared-module/msgpack/__init__.c +msgid "no default packer" msgstr "" -#: ports/espressif/common-hal/canio/CAN.c -#, c-format -msgid "twai_start returned esp-idf error #%d" +#: shared-module/msgpack/__init__.c supervisor/shared/settings.c +msgid "Invalid format" msgstr "" -#: shared-bindings/busio/UART.c shared-bindings/canio/CAN.c -msgid "tx and rx cannot both be None" +#: shared-module/paralleldisplaybus/ParallelBus.c +msgid "" +"This microcontroller only supports data0=, not data_pins=, because it " +"requires contiguous pins." msgstr "" -#: py/objtype.c -msgid "type '%q' isn't an acceptable base type" +#: shared-module/rgbmatrix/RGBMatrix.c +msgid "No timer available" msgstr "" -#: py/objtype.c -msgid "type isn't an acceptable base type" +#: shared-module/rgbmatrix/RGBMatrix.c +#, c-format +msgid "Internal error #%d" +msgstr "Dahili hata #%d" + +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v1 card" msgstr "" -#: py/runtime.c -msgid "type object '%q' has no attribute '%q'" +#: shared-module/sdcardio/SDCard.c +msgid "timeout waiting for v2 card" msgstr "" -#: py/objtype.c -msgid "type takes 1 or 3 arguments" +#: shared-module/sdcardio/SDCard.c +msgid "no SD card" msgstr "" -#: py/parse.c -msgid "unexpected indent" +#: shared-module/sdcardio/SDCard.c +msgid "couldn't determine SD card version" msgstr "" -#: py/bc.c -msgid "unexpected keyword argument" +#: shared-module/sdcardio/SDCard.c +msgid "no response from SD card" msgstr "" -#: py/argcheck.c py/bc.c py/objnamedtuple.c -#: shared-bindings/traceback/__init__.c -msgid "unexpected keyword argument '%q'" +#: shared-module/sdcardio/SDCard.c +msgid "SD card CSD format not supported" msgstr "" -#: py/lexer.c -msgid "unicode name escapes" +#: shared-module/sdcardio/SDCard.c +msgid "can't set 512 block size" msgstr "" -#: py/parse.c -msgid "unindent doesn't match any outer indent level" -msgstr "" +#: shared-module/ssl/SSLSocket.c +msgid "Invalid socket for TLS" +msgstr "TLS için geçersiz soket" -#: py/objstr.c -#, c-format -msgid "unknown conversion specifier %c" +#: shared-module/ssl/SSLSocket.c +msgid "invalid key" msgstr "" -#: py/objstr.c -msgid "unknown format code '%c' for object of type '%q'" +#: shared-module/ssl/SSLSocket.c +msgid "invalid cert" msgstr "" -#: py/compile.c -msgid "unknown type" +#: shared-module/storage/__init__.c +msgid "Mount point directory missing" msgstr "" -#: py/compile.c -msgid "unknown type '%q'" -msgstr "" +#: shared-module/storage/__init__.c +msgid "Cannot remount path when visible via USB." +msgstr "USB üzerinden görünür durumdayken yol yeniden bağlanamaz." -#: py/objstr.c -#, c-format -msgid "unmatched '%c' in format" -msgstr "" +#: shared-module/struct/__init__.c +msgid "'S' and 'O' are not supported format types" +msgstr "'S' ve 'O' desteklenen biçim türlerinden değildir" -#: py/objtype.c py/runtime.c -msgid "unreadable attribute" +#: shared-module/struct/__init__.c +msgid "buffer size must match format" msgstr "" -#: shared-bindings/displayio/TileGrid.c shared-bindings/terminalio/Terminal.c -#: shared-bindings/tilepalettemapper/TilePaletteMapper.c -#: shared-bindings/vectorio/VectorShape.c -msgid "unsupported %q type" -msgstr "" +#: shared-module/synthio/__init__.c +msgid "%q must be array of type 'h'" +msgstr "%q, 'h' dizisi türünde olmalıdır" -#: py/emitinlinethumb.c -#, c-format -msgid "unsupported Thumb instruction '%s' with %d arguments" +#: shared-module/tilepalettemapper/TilePaletteMapper.c +msgid "TilePaletteMapper may only be bound to a TileGrid once" msgstr "" -#: py/emitinlinextensa.c -#, c-format -msgid "unsupported Xtensa instruction '%s' with %d arguments" +#: shared-module/touchio/TouchIn.c +msgid "No pullup on pin; 1Mohm recommended" msgstr "" -#: shared-module/bitmapfilter/__init__.c -msgid "unsupported bitmap depth" +#: shared-module/touchio/TouchIn.c +msgid "No pulldown on pin; 1Mohm recommended" msgstr "" -#: shared-module/gifio/GifWriter.c -msgid "unsupported colorspace for GifWriter" +#: shared-module/usb/core/Device.c +msgid "No usb host port initialized" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "unsupported colorspace for dither" +#: shared-module/usb/core/Device.c +msgid "Pipe error" msgstr "" -#: py/objstr.c -#, c-format -msgid "unsupported format character '%c' (0x%x) at index %d" +#: shared-module/usb/core/Device.c +msgid "No configuration set" msgstr "" -#: py/runtime.c -msgid "unsupported type for %q: '%s'" +#: shared-module/usb_hid/Device.c +msgid "USB busy" msgstr "" -#: py/runtime.c -msgid "unsupported type for operator" +#: shared-module/usb_hid/Device.c +msgid "USB error" msgstr "" -#: py/runtime.c -msgid "unsupported types for %q: '%q', '%q'" +#: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c +#: shared-module/vectorio/Rectangle.c +msgid "can only have one parent" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols is too high" +#: shared-module/vectorio/Polygon.c +msgid "Polygon needs at least 3 points" msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "usecols keyword must be specified" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Reconnecting" msgstr "" -#: py/objint.c -#, c-format -msgid "value must fit in %d byte(s)" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Ok" msgstr "" -#: shared-bindings/bitmaptools/__init__.c -msgid "value out of range of target" +#: supervisor/shared/bluetooth/bluetooth.c +msgid "Off" msgstr "" -#: extmod/moddeflate.c -msgid "wbits" +#: supervisor/shared/micropython.c +msgid "[truncated due to length]" msgstr "" -#: shared-bindings/bitmapfilter/__init__.c +#: supervisor/shared/safe_mode.c msgid "" -"weights must be a sequence with an odd square number of elements (usually 9 " -"or 25)" +"\n" +"You are in safe mode because:\n" msgstr "" +"\n" +"Güvenli moddasın çünkü:\n" -#: shared-bindings/bitmapfilter/__init__.c -msgid "weights must be an object of type %q, %q, %q, or %q, not %q " +#: supervisor/shared/safe_mode.c +msgid "Power dipped. Make sure you are providing enough power." msgstr "" -#: shared-bindings/is31fl3741/FrameBuffer.c -msgid "width must be greater than zero" +#: supervisor/shared/safe_mode.c +msgid "You pressed the BOOT button at start up" msgstr "" -#: ports/raspberrypi/common-hal/wifi/Monitor.c -msgid "wifi.Monitor not available" +#: supervisor/shared/safe_mode.c +msgid "You pressed the reset button during boot." msgstr "" -#: shared-bindings/_bleio/Adapter.c -msgid "window must be <= interval" +#: supervisor/shared/safe_mode.c +msgid "CIRCUITPY drive could not be found or created." +msgstr "CIRCUITPY sürücüsü bulunamadı veya oluşturulamadı." + +#: supervisor/shared/safe_mode.c +msgid "The `microcontroller` module was used to boot into safe mode." msgstr "" -#: extmod/ulab/code/numpy/numerical.c -msgid "wrong axis index" +#: supervisor/shared/safe_mode.c +msgid "Error in safemode.py." msgstr "" -#: extmod/ulab/code/numpy/create.c -msgid "wrong axis specified" +#: supervisor/shared/safe_mode.c +msgid "Stack overflow. Increase stack size." msgstr "" -#: extmod/ulab/code/numpy/io/io.c -msgid "wrong dtype" +#: supervisor/shared/safe_mode.c +msgid "USB devices need more endpoints than are available." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong index type" +#: supervisor/shared/safe_mode.c +msgid "USB devices specify too many interface names." msgstr "" -#: extmod/ulab/code/numpy/compare.c extmod/ulab/code/numpy/create.c -#: extmod/ulab/code/numpy/io/io.c extmod/ulab/code/numpy/transform.c -#: extmod/ulab/code/numpy/vector.c -msgid "wrong input type" +#: supervisor/shared/safe_mode.c +msgid "Boot device must be first (interface #0)." +msgstr "Önyükleme cihazı birinci olmalı (arayüz #0)." + +#: supervisor/shared/safe_mode.c +msgid "Internal watchdog timer expired." +msgstr "Dahili bekçi zamanlayıcısının süresi doldu." + +#: supervisor/shared/safe_mode.c +msgid "CircuitPython core code crashed hard. Whoops!\n" +msgstr "CircuitPython kor kodu patladı. Haydaaa!\n" + +#: supervisor/shared/safe_mode.c +msgid "Heap allocation when VM not running." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of condition array" +#: supervisor/shared/safe_mode.c +msgid "Failed to write internal flash." +msgstr "Dahili flaş yazılamadı." + +#: supervisor/shared/safe_mode.c +msgid "Hard fault: memory access or instruction error." msgstr "" -#: extmod/ulab/code/numpy/transform.c -msgid "wrong length of index array" +#: supervisor/shared/safe_mode.c +msgid "Interrupt error." msgstr "" -#: extmod/ulab/code/numpy/create.c py/objarray.c py/objstr.c -msgid "wrong number of arguments" +#: supervisor/shared/safe_mode.c +msgid "NLR jump failed. Likely memory corruption." msgstr "" -#: py/runtime.c -msgid "wrong number of values to unpack" +#: supervisor/shared/safe_mode.c +msgid "Unable to allocate to the heap." msgstr "" -#: extmod/ulab/code/numpy/vector.c -msgid "wrong output type" +#: supervisor/shared/safe_mode.c +msgid "Third-party firmware fatal error." msgstr "" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be an ndarray" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Please file an issue with your program at github.com/adafruit/circuitpython/" +"issues." msgstr "" +"\n" +"Lütfen programınızla ilgili bir sorunu github.com/adafruit/circuitpython/" +"issues adresinden bildirin." -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of float type" +#: supervisor/shared/safe_mode.c +msgid "" +"\n" +"Press reset to exit safe mode.\n" msgstr "" +"\n" +"Güvenli moddan çıkmak için reset'e basın\n" -#: extmod/ulab/code/scipy/signal/signal.c -msgid "zi must be of shape (n_section, 2)" +#: supervisor/shared/settings.c +#, c-format +msgid "An error occurred while retrieving '%s':\n" +msgstr "'%s' alınırken hata yaşandı:\n" + +#: supervisor/shared/settings.c +msgid "Invalid unicode escape" +msgstr "" + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "Wi-Fi: " +msgstr "Wi-Fi: " + +#: supervisor/shared/web_workflow/web_workflow.c +msgid "off" msgstr "" +#: supervisor/shared/web_workflow/web_workflow.c +msgid "No IP" +msgstr "IP yok" + #, c-format #~ msgid "Buffer + offset too small %d %d %d" #~ msgstr "Buffer + offset çok küçük %d %d %d" From 459868dc67df38195ba35f53c95184774c1b19d9 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 12 Jul 2026 13:51:01 -0500 Subject: [PATCH 649/876] examples: Restore natmod examples. These have been broken for a long time but let's fix them. --- examples/natmod/.gitignore | 1 + examples/natmod/README.md | 74 +++++++++++ examples/natmod/btree/Makefile | 38 ++++++ examples/natmod/btree/btree_c.c | 171 ++++++++++++++++++++++++++ examples/natmod/deflate/Makefile | 13 ++ examples/natmod/deflate/deflate.c | 70 +++++++++++ examples/natmod/features0/Makefile | 14 +++ examples/natmod/features0/features0.c | 40 ++++++ examples/natmod/features1/Makefile | 14 +++ examples/natmod/features1/features1.c | 106 ++++++++++++++++ examples/natmod/features2/Makefile | 17 +++ examples/natmod/features2/main.c | 94 ++++++++++++++ examples/natmod/features2/prod.c | 9 ++ examples/natmod/features2/prod.h | 1 + examples/natmod/features2/test.py | 31 +++++ examples/natmod/features3/Makefile | 14 +++ examples/natmod/features3/features3.c | 60 +++++++++ examples/natmod/features4/Makefile | 14 +++ examples/natmod/features4/features4.c | 89 ++++++++++++++ examples/natmod/framebuf/Makefile | 13 ++ examples/natmod/framebuf/framebuf.c | 51 ++++++++ examples/natmod/heapq/Makefile | 13 ++ examples/natmod/heapq/heapq.c | 16 +++ examples/natmod/random/Makefile | 13 ++ examples/natmod/random/random.c | 33 +++++ examples/natmod/re/Makefile | 13 ++ examples/natmod/re/re.c | 91 ++++++++++++++ 27 files changed, 1113 insertions(+) create mode 100644 examples/natmod/.gitignore create mode 100644 examples/natmod/README.md create mode 100644 examples/natmod/btree/Makefile create mode 100644 examples/natmod/btree/btree_c.c create mode 100644 examples/natmod/deflate/Makefile create mode 100644 examples/natmod/deflate/deflate.c create mode 100644 examples/natmod/features0/Makefile create mode 100644 examples/natmod/features0/features0.c create mode 100644 examples/natmod/features1/Makefile create mode 100644 examples/natmod/features1/features1.c create mode 100644 examples/natmod/features2/Makefile create mode 100644 examples/natmod/features2/main.c create mode 100644 examples/natmod/features2/prod.c create mode 100644 examples/natmod/features2/prod.h create mode 100644 examples/natmod/features2/test.py create mode 100644 examples/natmod/features3/Makefile create mode 100644 examples/natmod/features3/features3.c create mode 100644 examples/natmod/features4/Makefile create mode 100644 examples/natmod/features4/features4.c create mode 100644 examples/natmod/framebuf/Makefile create mode 100644 examples/natmod/framebuf/framebuf.c create mode 100644 examples/natmod/heapq/Makefile create mode 100644 examples/natmod/heapq/heapq.c create mode 100644 examples/natmod/random/Makefile create mode 100644 examples/natmod/random/random.c create mode 100644 examples/natmod/re/Makefile create mode 100644 examples/natmod/re/re.c diff --git a/examples/natmod/.gitignore b/examples/natmod/.gitignore new file mode 100644 index 00000000000..4815d20f06b --- /dev/null +++ b/examples/natmod/.gitignore @@ -0,0 +1 @@ +*.mpy diff --git a/examples/natmod/README.md b/examples/natmod/README.md new file mode 100644 index 00000000000..ca6b887d034 --- /dev/null +++ b/examples/natmod/README.md @@ -0,0 +1,74 @@ +# Dynamic Native Modules + +Dynamic Native Modules are .mpy files that contain native machine code from a +language other than Python. For more info see [the +documentation](https://docs.micropython.org/en/latest/develop/natmod.html). + +This should not be confused with [User C +Modules](https://docs.micropython.org/en/latest/develop/cmodules.html) which are +a mechanism to add additional out-of-tree modules into the firmware build. + +## Examples + +This directory contains several examples of writing dynamic native modules, in +two main categories: + +1. Feature examples. + + * `features0` - A module containing a single "factorial" function which + demonstrates working with integers. + + * `features1` - A module that demonstrates some common tasks: + - defining simple functions exposed to Python + - defining local, helper C functions + - defining constant integers and strings exposed to Python + - getting and creating integer objects + - creating Python lists + - raising exceptions + - allocating memory + - BSS and constant data (rodata) + - relocated pointers in rodata + + * `features2` - This is a hybrid module containing both Python and C code, + and additionally the C code is spread over multiple files. It also + demonstrates using floating point (only when the target supports + hardware floating point). + + * `features3` - A module that shows how to use types, constant objects, + and creating dictionary instances. + + * `features4` - A module that demonstrates how to define a class. + +2. Dynamic version of existing built-ins. + + This provides a way to add missing functionality to firmware that doesn't + include certain built-in modules. See the `heapq`, `random`, `re`, + `deflate`, `btree`, and `framebuf` directories. + + So for example, if your firmware was compiled with `MICROPY_PY_FRAMEBUF` + disabled (e.g. to save flash space), then it would not include the + `framebuf` module. The `framebuf` native module provides a way to add the + `framebuf` module dynamically. + + The way these work is they define a dynamic native module which + `#include`'s the original module and then does the necessary + initialisation of the module's globals dict. + +## Build instructions + +To compile an example, you need to have the same toolchain available as +required for your target port. e.g. `arm-none-eabi-gcc` for any ARM Cortex M +target. See the port instructions for details. + +You also need to have the `pyelftools` Python package available, either via +your system package manager or installed from PyPI in a virtual environment +with `pip`. + +Each example provides a Makefile. You should specify the `ARCH` argument to +make (one of x86, x64, armv6m, armv7m, xtensa, xtensawin, rv32imc): + +``` +$ cd features0 +$ make ARCH=armv7m +$ mpremote cp features0.mpy : +``` diff --git a/examples/natmod/btree/Makefile b/examples/natmod/btree/Makefile new file mode 100644 index 00000000000..ff130d61b37 --- /dev/null +++ b/examples/natmod/btree/Makefile @@ -0,0 +1,38 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in btree so it can coexist) +MOD = btree_$(ARCH) + +# Source files (.c or .py) +SRC = btree_c.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +BTREE_DIR = $(MPY_DIR)/lib/berkeley-db-1.xx +BERKELEY_DB_CONFIG_FILE ?= \"extmod/berkeley-db/berkeley_db_config_port.h\" +CFLAGS += -I$(BTREE_DIR)/include +CFLAGS += -DBERKELEY_DB_CONFIG_FILE=$(BERKELEY_DB_CONFIG_FILE) +CFLAGS += -Wno-old-style-definition -Wno-sign-compare -Wno-unused-parameter + +SRC += $(addprefix $(realpath $(BTREE_DIR))/,\ + btree/bt_close.c \ + btree/bt_conv.c \ + btree/bt_delete.c \ + btree/bt_get.c \ + btree/bt_open.c \ + btree/bt_overflow.c \ + btree/bt_page.c \ + btree/bt_put.c \ + btree/bt_search.c \ + btree/bt_seq.c \ + btree/bt_split.c \ + btree/bt_utils.c \ + mpool/mpool.c \ + ) + +include $(MPY_DIR)/py/dynruntime.mk + +# btree needs gnu99 defined +CFLAGS += -std=gnu99 diff --git a/examples/natmod/btree/btree_c.c b/examples/natmod/btree/btree_c.c new file mode 100644 index 00000000000..4f494817e7b --- /dev/null +++ b/examples/natmod/btree/btree_c.c @@ -0,0 +1,171 @@ +#define MICROPY_PY_BTREE (1) + +#include "py/dynruntime.h" + +#include + +#if !defined(__linux__) +void *memcpy(void *dst, const void *src, size_t n) { + return mp_fun_table.memmove_(dst, src, n); +} +void *memset(void *s, int c, size_t n) { + return mp_fun_table.memset_(s, c, n); +} +#endif + +void *memmove(void *dest, const void *src, size_t n) { + return mp_fun_table.memmove_(dest, src, n); +} + +void *malloc(size_t n) { + void *ptr = m_malloc(n); + return ptr; +} +void *realloc(void *ptr, size_t n) { + mp_printf(&mp_plat_print, "UNDEF %d\n", __LINE__); + return NULL; +} +void *calloc(size_t n, size_t m) { + void *ptr = m_malloc(n * m); + // memory already cleared by conservative GC + return ptr; +} + +void free(void *ptr) { + m_free(ptr); +} + +void abort_(void) { + nlr_raise(mp_obj_new_exception(mp_load_global(MP_QSTR_RuntimeError))); +} + +int puts(const char *s) { + return mp_printf(&mp_plat_print, "%s\n", s); +} + +int native_errno; +#if defined(__linux__) +int *__errno_location (void) +#else +int *__errno (void) +#endif +{ + return &native_errno; +} + +ssize_t mp_stream_posix_write(void *stream, const void *buf, size_t len) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); + mp_uint_t out_sz = stream_p->write(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +ssize_t mp_stream_posix_read(void *stream, void *buf, size_t len) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); + mp_uint_t out_sz = stream_p->read(MP_OBJ_FROM_PTR(stream), buf, len, &native_errno); + if (out_sz == MP_STREAM_ERROR) { + return -1; + } else { + return out_sz; + } +} + +off_t mp_stream_posix_lseek(void *stream, off_t offset, int whence) { + const mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); + struct mp_stream_seek_t seek_s; + seek_s.offset = offset; + seek_s.whence = whence; + mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &native_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return seek_s.offset; +} + +int mp_stream_posix_fsync(void *stream) { + mp_obj_base_t* o = stream; + const mp_stream_p_t *stream_p = MP_OBJ_TYPE_GET_SLOT(o->type, protocol); + mp_uint_t res = stream_p->ioctl(MP_OBJ_FROM_PTR(stream), MP_STREAM_FLUSH, 0, &native_errno); + if (res == MP_STREAM_ERROR) { + return -1; + } + return res; +} + +mp_obj_full_type_t btree_type; +mp_getiter_iternext_custom_t btree_getiter_iternext; + +#include "extmod/modbtree.c" + +mp_map_elem_t btree_locals_dict_table[8]; +static MP_DEFINE_CONST_DICT(btree_locals_dict, btree_locals_dict_table); + +static mp_obj_t btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // The allowed_args array must have its qstr's populated at runtime. + enum { ARG_flags, ARG_cachesize, ARG_pagesize, ARG_minkeypage }; + mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + allowed_args[0].qst = MP_QSTR_flags; + allowed_args[1].qst = MP_QSTR_cachesize; + allowed_args[2].qst = MP_QSTR_pagesize; + allowed_args[3].qst = MP_QSTR_minkeypage; + + // Make sure we got a stream object + mp_get_stream_raise(pos_args[0], MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + BTREEINFO openinfo = {0}; + openinfo.flags = args[ARG_flags].u_int; + openinfo.cachesize = args[ARG_cachesize].u_int; + openinfo.psize = args[ARG_pagesize].u_int; + openinfo.minkeypage = args[ARG_minkeypage].u_int; + DB *db = __bt_open(MP_OBJ_TO_PTR(pos_args[0]), &btree_stream_fvtable, &openinfo, 0); + if (db == NULL) { + mp_raise_OSError(native_errno); + } + + return MP_OBJ_FROM_PTR(btree_new(db, pos_args[0])); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(btree_open_obj, 1, btree_open); + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + btree_getiter_iternext.getiter = btree_getiter; + btree_getiter_iternext.iternext = btree_iternext; + + btree_type.base.type = (void*)&mp_fun_table.type_type; + btree_type.flags = MP_TYPE_FLAG_ITER_IS_CUSTOM; + btree_type.name = MP_QSTR_btree; + MP_OBJ_TYPE_SET_SLOT(&btree_type, print, btree_print, 0); + MP_OBJ_TYPE_SET_SLOT(&btree_type, iter, &btree_getiter_iternext, 1); + MP_OBJ_TYPE_SET_SLOT(&btree_type, binary_op, btree_binary_op, 2); + MP_OBJ_TYPE_SET_SLOT(&btree_type, subscr, btree_subscr, 3); + btree_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&btree_close_obj) }; + btree_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_flush), MP_OBJ_FROM_PTR(&btree_flush_obj) }; + btree_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_get), MP_OBJ_FROM_PTR(&btree_get_obj) }; + btree_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_put), MP_OBJ_FROM_PTR(&btree_put_obj) }; + btree_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_seq), MP_OBJ_FROM_PTR(&btree_seq_obj) }; + btree_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_keys), MP_OBJ_FROM_PTR(&btree_keys_obj) }; + btree_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_values), MP_OBJ_FROM_PTR(&btree_values_obj) }; + btree_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_items), MP_OBJ_FROM_PTR(&btree_items_obj) }; + MP_OBJ_TYPE_SET_SLOT(&btree_type, locals_dict, (void*)&btree_locals_dict, 4); + + mp_store_global(MP_QSTR_open, MP_OBJ_FROM_PTR(&btree_open_obj)); + mp_store_global(MP_QSTR_INCL, MP_OBJ_NEW_SMALL_INT(FLAG_END_KEY_INCL)); + mp_store_global(MP_QSTR_DESC, MP_OBJ_NEW_SMALL_INT(FLAG_DESC)); + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/deflate/Makefile b/examples/natmod/deflate/Makefile new file mode 100644 index 00000000000..504130d5723 --- /dev/null +++ b/examples/natmod/deflate/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in uzlib so it can coexist) +MOD = deflate_$(ARCH) + +# Source files (.c or .py) +SRC = deflate.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/deflate/deflate.c b/examples/natmod/deflate/deflate.c new file mode 100644 index 00000000000..9de7e101a76 --- /dev/null +++ b/examples/natmod/deflate/deflate.c @@ -0,0 +1,70 @@ +#define MICROPY_PY_DEFLATE (1) +#define MICROPY_PY_DEFLATE_COMPRESS (1) + +#include "py/dynruntime.h" + +#if !defined(__linux__) +void *memcpy(void *dst, const void *src, size_t n) { + return mp_fun_table.memmove_(dst, src, n); +} +void *memset(void *s, int c, size_t n) { + return mp_fun_table.memset_(s, c, n); +} +#endif + +mp_obj_full_type_t deflateio_type; + +#include "extmod/moddeflate.c" + +// Re-implemented from py/stream.c, not yet available in dynruntime.h. +mp_obj_t mp_stream_close(mp_obj_t stream) { + const mp_stream_p_t *stream_p = mp_get_stream(stream); + int error; + mp_uint_t res = stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error); + if (res == MP_STREAM_ERROR) { + mp_raise_OSError(error); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_stream_close_obj, mp_stream_close); + +// Re-implemented from py/stream.c, not yet available in dynruntime.h. +static mp_obj_t mp_stream___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + return mp_stream_close(args[0]); +} +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_stream___exit___obj, 4, 4, mp_stream___exit__); + +// Re-implemented from obj.c, not yet available in dynruntime.h. +mp_obj_t mp_identity(mp_obj_t self) { + return self; +} +MP_DEFINE_CONST_FUN_OBJ_1(mp_identity_obj, mp_identity); + +mp_map_elem_t deflateio_locals_dict_table[7]; +static MP_DEFINE_CONST_DICT(deflateio_locals_dict, deflateio_locals_dict_table); + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + deflateio_type.base.type = mp_fun_table.type_type; + deflateio_type.name = MP_QSTR_DeflateIO; + MP_OBJ_TYPE_SET_SLOT(&deflateio_type, make_new, &deflateio_make_new, 0); + MP_OBJ_TYPE_SET_SLOT(&deflateio_type, protocol, &deflateio_stream_p, 1); + deflateio_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_read), MP_OBJ_FROM_PTR(&mp_stream_read_obj) }; + deflateio_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readinto), MP_OBJ_FROM_PTR(&mp_stream_readinto_obj) }; + deflateio_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_readline), MP_OBJ_FROM_PTR(&mp_stream_unbuffered_readline_obj) }; + deflateio_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_write), MP_OBJ_FROM_PTR(&mp_stream_write_obj) }; + deflateio_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_close), MP_OBJ_FROM_PTR(&mp_stream_close_obj) }; + deflateio_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___enter__), MP_OBJ_FROM_PTR(&mp_identity_obj) }; + deflateio_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR___exit__), MP_OBJ_FROM_PTR(&mp_stream___exit___obj) }; + MP_OBJ_TYPE_SET_SLOT(&deflateio_type, locals_dict, (void*)&deflateio_locals_dict, 2); + + mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_deflate)); + mp_store_global(MP_QSTR_DeflateIO, MP_OBJ_FROM_PTR(&deflateio_type)); + mp_store_global(MP_QSTR_RAW, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_RAW)); + mp_store_global(MP_QSTR_ZLIB, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_ZLIB)); + mp_store_global(MP_QSTR_GZIP, MP_OBJ_NEW_SMALL_INT(DEFLATEIO_FORMAT_GZIP)); + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features0/Makefile b/examples/natmod/features0/Makefile new file mode 100644 index 00000000000..9bc4bbf23b8 --- /dev/null +++ b/examples/natmod/features0/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features0 + +# Source files (.c or .py) +SRC = features0.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features0/features0.c b/examples/natmod/features0/features0.c new file mode 100644 index 00000000000..c3d31afb79c --- /dev/null +++ b/examples/natmod/features0/features0.c @@ -0,0 +1,40 @@ +/* This example demonstrates the following features in a native module: + - defining a simple function exposed to Python + - defining a local, helper C function + - getting and creating integer objects +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// Helper function to compute factorial +static mp_int_t factorial_helper(mp_int_t x) { + if (x == 0) { + return 1; + } + return x * factorial_helper(x - 1); +} + +// This is the function which will be called from Python, as factorial(x) +static mp_obj_t factorial(mp_obj_t x_obj) { + // Extract the integer from the MicroPython input object + mp_int_t x = mp_obj_get_int(x_obj); + // Calculate the factorial + mp_int_t result = factorial_helper(x); + // Convert the result to a MicroPython integer object and return it + return mp_obj_new_int(result); +} +// Define a Python reference to the function above +static MP_DEFINE_CONST_FUN_OBJ_1(factorial_obj, factorial); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the function available in the module's namespace + mp_store_global(MP_QSTR_factorial, MP_OBJ_FROM_PTR(&factorial_obj)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features1/Makefile b/examples/natmod/features1/Makefile new file mode 100644 index 00000000000..49040511020 --- /dev/null +++ b/examples/natmod/features1/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features1 + +# Source files (.c or .py) +SRC = features1.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features1/features1.c b/examples/natmod/features1/features1.c new file mode 100644 index 00000000000..92b96dbb183 --- /dev/null +++ b/examples/natmod/features1/features1.c @@ -0,0 +1,106 @@ +/* This example demonstrates the following features in a native module: + - defining simple functions exposed to Python + - defining local, helper C functions + - defining constant integers and strings exposed to Python + - getting and creating integer objects + - creating Python lists + - raising exceptions + - allocating memory + - BSS and constant data (rodata) + - relocated pointers in rodata +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// BSS (zero) data +uint16_t data16[4]; + +// Constant data (rodata) +const uint8_t table8[] = { 0, 1, 1, 2, 3, 5, 8, 13 }; +const uint16_t table16[] = { 0x1000, 0x2000 }; + +// Constant data pointing to BSS/constant data +uint16_t *const table_ptr16a[] = { &data16[0], &data16[1], &data16[2], &data16[3] }; +const uint16_t *const table_ptr16b[] = { &table16[0], &table16[1] }; + +// A simple function that adds its 2 arguments (must be integers) +static mp_obj_t add(mp_obj_t x_in, mp_obj_t y_in) { + mp_int_t x = mp_obj_get_int(x_in); + mp_int_t y = mp_obj_get_int(y_in); + return mp_obj_new_int(x + y); +} +static MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); + +// A local helper function (not exposed to Python) +static mp_int_t fibonacci_helper(mp_int_t x) { + if (x < MP_ARRAY_SIZE(table8)) { + return table8[x]; + } else { + return fibonacci_helper(x - 1) + fibonacci_helper(x - 2); + } +} + +// A function which computes Fibonacci numbers +static mp_obj_t fibonacci(mp_obj_t x_in) { + mp_int_t x = mp_obj_get_int(x_in); + if (x < 0) { + mp_raise_ValueError(MP_ERROR_TEXT("can't compute negative Fibonacci number")); + } + return mp_obj_new_int(fibonacci_helper(x)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(fibonacci_obj, fibonacci); + +// A function that accesses the BSS data +static mp_obj_t access(size_t n_args, const mp_obj_t *args) { + if (n_args == 0) { + // Create a list holding all items from data16 + mp_obj_list_t *lst = MP_OBJ_TO_PTR(mp_obj_new_list(MP_ARRAY_SIZE(data16), NULL)); + for (int i = 0; i < MP_ARRAY_SIZE(data16); ++i) { + lst->items[i] = mp_obj_new_int(data16[i]); + } + return MP_OBJ_FROM_PTR(lst); + } else if (n_args == 1) { + // Get one item from data16 + mp_int_t idx = mp_obj_get_int(args[0]) & 3; + return mp_obj_new_int(data16[idx]); + } else { + // Set one item in data16 (via table_ptr16a) + mp_int_t idx = mp_obj_get_int(args[0]) & 3; + *table_ptr16a[idx] = mp_obj_get_int(args[1]); + return mp_const_none; + } +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(access_obj, 0, 2, access); + +// A function that allocates memory and creates a bytearray +static mp_obj_t make_array(void) { + uint16_t *ptr = m_new(uint16_t, MP_ARRAY_SIZE(table_ptr16b)); + for (int i = 0; i < MP_ARRAY_SIZE(table_ptr16b); ++i) { + ptr[i] = *table_ptr16b[i]; + } + return mp_obj_new_bytearray_by_ref(sizeof(uint16_t) * MP_ARRAY_SIZE(table_ptr16b), ptr); +} +static MP_DEFINE_CONST_FUN_OBJ_0(make_array_obj, make_array); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Messages can be printed as usual + mp_printf(&mp_plat_print, "initialising module self=%p\n", self); + + // Make the functions available in the module's namespace + mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); + mp_store_global(MP_QSTR_fibonacci, MP_OBJ_FROM_PTR(&fibonacci_obj)); + mp_store_global(MP_QSTR_access, MP_OBJ_FROM_PTR(&access_obj)); + mp_store_global(MP_QSTR_make_array, MP_OBJ_FROM_PTR(&make_array_obj)); + + // Add some constants to the module's namespace + mp_store_global(MP_QSTR_VAL, MP_OBJ_NEW_SMALL_INT(42)); + mp_store_global(MP_QSTR_MSG, MP_OBJ_NEW_QSTR(MP_QSTR_HELLO_MICROPYTHON)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features2/Makefile b/examples/natmod/features2/Makefile new file mode 100644 index 00000000000..5ddb74087b7 --- /dev/null +++ b/examples/natmod/features2/Makefile @@ -0,0 +1,17 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features2 + +# Source files (.c or .py) +SRC = main.c prod.c test.py + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +# Link with libm.a and libgcc.a from the toolchain +LINK_RUNTIME = 1 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features2/main.c b/examples/natmod/features2/main.c new file mode 100644 index 00000000000..5ce8e7b0130 --- /dev/null +++ b/examples/natmod/features2/main.c @@ -0,0 +1,94 @@ +/* This example demonstrates the following features in a native module: + - using floats + - calling math functions from libm.a + - defining additional code in Python (see test.py) + - have extra C code in a separate file (see prod.c) +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// Include the header for auxiliary C code for this module +#include "prod.h" + +// Include standard library header +#include + +// Automatically detect if this module should include double-precision code. +// If double precision is supported by the target architecture then it can +// be used in native module regardless of what float setting the target +// MicroPython runtime uses (being none, float or double). +#if defined(__i386__) || defined(__x86_64__) || (defined(__ARM_FP) && (__ARM_FP & 8)) +#define USE_DOUBLE 1 +#else +#define USE_DOUBLE 0 +#endif + +// A function that uses the default float type configured for the current target +// This default can be overridden by specifying MICROPY_FLOAT_IMPL at the make level +static mp_obj_t add(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float(mp_obj_get_float(x) + mp_obj_get_float(y)); +} +static MP_DEFINE_CONST_FUN_OBJ_2(add_obj, add); + +// A function that explicitly uses single precision floats +static mp_obj_t add_f(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float_from_f(mp_obj_get_float_to_f(x) + mp_obj_get_float_to_f(y)); +} +static MP_DEFINE_CONST_FUN_OBJ_2(add_f_obj, add_f); + +#if USE_DOUBLE +// A function that explicitly uses double precision floats +static mp_obj_t add_d(mp_obj_t x, mp_obj_t y) { + return mp_obj_new_float_from_d(mp_obj_get_float_to_d(x) + mp_obj_get_float_to_d(y)); +} +static MP_DEFINE_CONST_FUN_OBJ_2(add_d_obj, add_d); +#endif + +// A function that uses libm +static mp_obj_t call_round(mp_obj_t x) { + return mp_obj_new_float_from_f(roundf(mp_obj_get_float_to_f(x))); +} +static MP_DEFINE_CONST_FUN_OBJ_1(round_obj, call_round); + +// A function that computes the product of floats in an array. +// This function uses the most general C argument interface, which is more difficult +// to use but has access to the globals dict of the module via self->globals. +static mp_obj_t productf(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // Check number of arguments is valid + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + // Extract buffer pointer and verify typecode + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[0], &bufinfo, MP_BUFFER_RW); + if (bufinfo.typecode != 'f') { + mp_raise_ValueError(MP_ERROR_TEXT("expecting float array")); + } + + // Compute product, store result back in first element of array + float *ptr = bufinfo.buf; + float prod = prod_array(bufinfo.len / sizeof(*ptr), ptr); + ptr[0] = prod; + + return mp_const_none; +} + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Make the functions available in the module's namespace + mp_store_global(MP_QSTR_add, MP_OBJ_FROM_PTR(&add_obj)); + mp_store_global(MP_QSTR_add_f, MP_OBJ_FROM_PTR(&add_f_obj)); + #if USE_DOUBLE + mp_store_global(MP_QSTR_add_d, MP_OBJ_FROM_PTR(&add_d_obj)); + #endif + mp_store_global(MP_QSTR_round, MP_OBJ_FROM_PTR(&round_obj)); + + // The productf function uses the most general C argument interface + mp_store_global(MP_QSTR_productf, MP_DYNRUNTIME_MAKE_FUNCTION(productf)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features2/prod.c b/examples/natmod/features2/prod.c new file mode 100644 index 00000000000..7791dcad1d2 --- /dev/null +++ b/examples/natmod/features2/prod.c @@ -0,0 +1,9 @@ +#include "prod.h" + +float prod_array(int n, float *ar) { + float ans = 1; + for (int i = 0; i < n; ++i) { + ans *= ar[i]; + } + return ans; +} diff --git a/examples/natmod/features2/prod.h b/examples/natmod/features2/prod.h new file mode 100644 index 00000000000..f27dd8d0330 --- /dev/null +++ b/examples/natmod/features2/prod.h @@ -0,0 +1 @@ +float prod_array(int n, float *ar); diff --git a/examples/natmod/features2/test.py b/examples/natmod/features2/test.py new file mode 100644 index 00000000000..af79b9692c2 --- /dev/null +++ b/examples/natmod/features2/test.py @@ -0,0 +1,31 @@ +# This Python code will be merged with the C code in main.c + +# ruff: noqa: F821 - this file is evaluated with C-defined names in scope + +import array + + +def isclose(a, b): + return abs(a - b) < 1e-3 + + +def test(): + tests = [ + isclose(add(0.1, 0.2), 0.3), + isclose(add_f(0.1, 0.2), 0.3), + ] + + ar = array.array("f", [1, 2, 3.5]) + productf(ar) + tests.append(isclose(ar[0], 7)) + + if "add_d" in globals(): + tests.append(isclose(add_d(0.1, 0.2), 0.3)) + + print(tests) + + if not all(tests): + raise SystemExit(1) + + +test() diff --git a/examples/natmod/features3/Makefile b/examples/natmod/features3/Makefile new file mode 100644 index 00000000000..3573f41caca --- /dev/null +++ b/examples/natmod/features3/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features3 + +# Source files (.c or .py) +SRC = features3.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features3/features3.c b/examples/natmod/features3/features3.c new file mode 100644 index 00000000000..1d3bc51e609 --- /dev/null +++ b/examples/natmod/features3/features3.c @@ -0,0 +1,60 @@ +/* This example demonstrates the following features in a native module: + - using types + - using constant objects + - creating dictionaries +*/ + +// Include the header file to get access to the MicroPython API. +#include "py/dynruntime.h" + +// A function that returns a tuple of object types. +static mp_obj_t get_types(void) { + return mp_obj_new_tuple(9, ((mp_obj_t []) { + MP_OBJ_FROM_PTR(&mp_type_type), + MP_OBJ_FROM_PTR(&mp_type_NoneType), + MP_OBJ_FROM_PTR(&mp_type_bool), + MP_OBJ_FROM_PTR(&mp_type_int), + MP_OBJ_FROM_PTR(&mp_type_str), + MP_OBJ_FROM_PTR(&mp_type_bytes), + MP_OBJ_FROM_PTR(&mp_type_tuple), + MP_OBJ_FROM_PTR(&mp_type_list), + MP_OBJ_FROM_PTR(&mp_type_dict), + })); +} +static MP_DEFINE_CONST_FUN_OBJ_0(get_types_obj, get_types); + +// A function that returns a tuple of constant objects. +static mp_obj_t get_const_objects(void) { + return mp_obj_new_tuple(5, ((mp_obj_t []) { + mp_const_none, + mp_const_false, + mp_const_true, + mp_const_empty_bytes, + mp_const_empty_tuple, + })); +} +static MP_DEFINE_CONST_FUN_OBJ_0(get_const_objects_obj, get_const_objects); + +// A function that creates a dictionary from the given arguments. +static mp_obj_t make_dict(size_t n_args, const mp_obj_t *args) { + mp_obj_t dict = mp_obj_new_dict(n_args / 2); + for (; n_args >= 2; n_args -= 2, args += 2) { + mp_obj_dict_store(dict, args[0], args[1]); + } + return dict; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(make_dict_obj, 0, MP_OBJ_FUN_ARGS_MAX, make_dict); + +// This is the entry point and is called when the module is imported. +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things. + MP_DYNRUNTIME_INIT_ENTRY + + // Make the functions available in the module's namespace. + mp_store_global(MP_QSTR_make_dict, MP_OBJ_FROM_PTR(&make_dict_obj)); + mp_store_global(MP_QSTR_get_types, MP_OBJ_FROM_PTR(&get_types_obj)); + mp_store_global(MP_QSTR_get_const_objects, MP_OBJ_FROM_PTR(&get_const_objects_obj)); + + // This must be last, it restores the globals dict. + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/features4/Makefile b/examples/natmod/features4/Makefile new file mode 100644 index 00000000000..34fc3a7ef7b --- /dev/null +++ b/examples/natmod/features4/Makefile @@ -0,0 +1,14 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module +MOD = features4 + +# Source files (.c or .py) +SRC = features4.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +# Include to get the rules for compiling and linking the module +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/features4/features4.c b/examples/natmod/features4/features4.c new file mode 100644 index 00000000000..e64c7f75921 --- /dev/null +++ b/examples/natmod/features4/features4.c @@ -0,0 +1,89 @@ +/* + This example extends on features0 but demonstrates how to define a class, + and a custom exception. + + The Factorial class constructor takes an integer, and then the calculate + method can be called to get the factorial. + + >>> import features4 + >>> f = features4.Factorial(4) + >>> f.calculate() + 24 + + If the argument to the Factorial class constructor is less than zero, a + FactorialError is raised. +*/ + +// Include the header file to get access to the MicroPython API +#include "py/dynruntime.h" + +// This is type(Factorial) +mp_obj_full_type_t mp_type_factorial; + +// This is the internal state of a Factorial instance. +typedef struct { + mp_obj_base_t base; + mp_int_t n; +} mp_obj_factorial_t; + +mp_obj_full_type_t mp_type_FactorialError; + +// Essentially Factorial.__new__ (but also kind of __init__). +// Takes a single argument (the number to find the factorial of) +static mp_obj_t factorial_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args_in) { + mp_arg_check_num(n_args, n_kw, 1, 1, false); + + mp_obj_factorial_t *o = mp_obj_malloc(mp_obj_factorial_t, type); + o->n = mp_obj_get_int(args_in[0]); + + if (o->n < 0) { + mp_raise_msg((mp_obj_type_t *)&mp_type_FactorialError, "argument must be zero or above"); + } + + return MP_OBJ_FROM_PTR(o); +} + +static mp_int_t factorial_helper(mp_int_t x) { + if (x == 0) { + return 1; + } + return x * factorial_helper(x - 1); +} + +// Implements Factorial.calculate() +static mp_obj_t factorial_calculate(mp_obj_t self_in) { + mp_obj_factorial_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(factorial_helper(self->n)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(factorial_calculate_obj, factorial_calculate); + +// Locals dict for the Factorial type (will have a single method, calculate, +// added in mpy_init). +mp_map_elem_t factorial_locals_dict_table[1]; +static MP_DEFINE_CONST_DICT(factorial_locals_dict, factorial_locals_dict_table); + +// This is the entry point and is called when the module is imported +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + // This must be first, it sets up the globals dict and other things + MP_DYNRUNTIME_INIT_ENTRY + + // Initialise the type. + mp_type_factorial.base.type = (void*)&mp_type_type; + mp_type_factorial.flags = MP_TYPE_FLAG_NONE; + mp_type_factorial.name = MP_QSTR_Factorial; + MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, make_new, factorial_make_new, 0); + factorial_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_calculate), MP_OBJ_FROM_PTR(&factorial_calculate_obj) }; + MP_OBJ_TYPE_SET_SLOT(&mp_type_factorial, locals_dict, (void*)&factorial_locals_dict, 1); + + // Make the Factorial type available on the module. + mp_store_global(MP_QSTR_Factorial, MP_OBJ_FROM_PTR(&mp_type_factorial)); + + // Initialise the exception type. + mp_obj_exception_init(&mp_type_FactorialError, MP_QSTR_FactorialError, &mp_type_Exception); + + // Make the FactorialError type available on the module. + mp_store_global(MP_QSTR_FactorialError, MP_OBJ_FROM_PTR(&mp_type_FactorialError)); + + // This must be last, it restores the globals dict + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/framebuf/Makefile b/examples/natmod/framebuf/Makefile new file mode 100644 index 00000000000..2e2b8159754 --- /dev/null +++ b/examples/natmod/framebuf/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in framebuf so it can coexist) +MOD = framebuf_$(ARCH) + +# Source files (.c or .py) +SRC = framebuf.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/framebuf/framebuf.c b/examples/natmod/framebuf/framebuf.c new file mode 100644 index 00000000000..1ba702e33d9 --- /dev/null +++ b/examples/natmod/framebuf/framebuf.c @@ -0,0 +1,51 @@ +#define MICROPY_PY_ARRAY (1) +#define MICROPY_PY_FRAMEBUF (1) + +#include "py/dynruntime.h" + +#if !defined(__linux__) +void *memset(void *s, int c, size_t n) { + return mp_fun_table.memset_(s, c, n); +} +#endif + +mp_obj_full_type_t mp_type_framebuf; + +#include "extmod/modframebuf.c" + +mp_map_elem_t framebuf_locals_dict_table[12]; +static MP_DEFINE_CONST_DICT(framebuf_locals_dict, framebuf_locals_dict_table); + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + mp_type_framebuf.base.type = (void*)&mp_type_type; + mp_type_framebuf.name = MP_QSTR_FrameBuffer; + MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, make_new, framebuf_make_new, 0); + MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, buffer, framebuf_get_buffer, 1); + framebuf_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_fill), MP_OBJ_FROM_PTR(&framebuf_fill_obj) }; + framebuf_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_fill_rect), MP_OBJ_FROM_PTR(&framebuf_fill_rect_obj) }; + framebuf_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_pixel), MP_OBJ_FROM_PTR(&framebuf_pixel_obj) }; + framebuf_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_hline), MP_OBJ_FROM_PTR(&framebuf_hline_obj) }; + framebuf_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_vline), MP_OBJ_FROM_PTR(&framebuf_vline_obj) }; + framebuf_locals_dict_table[5] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_rect), MP_OBJ_FROM_PTR(&framebuf_rect_obj) }; + framebuf_locals_dict_table[6] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_line), MP_OBJ_FROM_PTR(&framebuf_line_obj) }; + framebuf_locals_dict_table[7] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_ellipse), MP_OBJ_FROM_PTR(&framebuf_ellipse_obj) }; + framebuf_locals_dict_table[8] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_poly), MP_OBJ_FROM_PTR(&framebuf_poly_obj) }; + framebuf_locals_dict_table[9] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_blit), MP_OBJ_FROM_PTR(&framebuf_blit_obj) }; + framebuf_locals_dict_table[10] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_scroll), MP_OBJ_FROM_PTR(&framebuf_scroll_obj) }; + framebuf_locals_dict_table[11] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_text), MP_OBJ_FROM_PTR(&framebuf_text_obj) }; + MP_OBJ_TYPE_SET_SLOT(&mp_type_framebuf, locals_dict, (void*)&framebuf_locals_dict, 2); + + mp_store_global(MP_QSTR_FrameBuffer, MP_OBJ_FROM_PTR(&mp_type_framebuf)); + mp_store_global(MP_QSTR_MVLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB)); + mp_store_global(MP_QSTR_MONO_VLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MVLSB)); + mp_store_global(MP_QSTR_RGB565, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_RGB565)); + mp_store_global(MP_QSTR_GS2_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS2_HMSB)); + mp_store_global(MP_QSTR_GS4_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS4_HMSB)); + mp_store_global(MP_QSTR_GS8, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_GS8)); + mp_store_global(MP_QSTR_MONO_HLSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHLSB)); + mp_store_global(MP_QSTR_MONO_HMSB, MP_OBJ_NEW_SMALL_INT(FRAMEBUF_MHMSB)); + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/heapq/Makefile b/examples/natmod/heapq/Makefile new file mode 100644 index 00000000000..61e2fc8fcc0 --- /dev/null +++ b/examples/natmod/heapq/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in heapq so it can coexist) +MOD = heapq_$(ARCH) + +# Source files (.c or .py) +SRC = heapq.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/heapq/heapq.c b/examples/natmod/heapq/heapq.c new file mode 100644 index 00000000000..ed19652a66b --- /dev/null +++ b/examples/natmod/heapq/heapq.c @@ -0,0 +1,16 @@ +#define MICROPY_PY_HEAPQ (1) + +#include "py/dynruntime.h" + +#include "extmod/modheapq.c" + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_heapq)); + mp_store_global(MP_QSTR_heappush, MP_OBJ_FROM_PTR(&mod_heapq_heappush_obj)); + mp_store_global(MP_QSTR_heappop, MP_OBJ_FROM_PTR(&mod_heapq_heappop_obj)); + mp_store_global(MP_QSTR_heapify, MP_OBJ_FROM_PTR(&mod_heapq_heapify_obj)); + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/random/Makefile b/examples/natmod/random/Makefile new file mode 100644 index 00000000000..8abdb66dc87 --- /dev/null +++ b/examples/natmod/random/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in random so it can coexist) +MOD = random_$(ARCH) + +# Source files (.c or .py) +SRC = random.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/random/random.c b/examples/natmod/random/random.c new file mode 100644 index 00000000000..92257b8bc68 --- /dev/null +++ b/examples/natmod/random/random.c @@ -0,0 +1,33 @@ +#define MICROPY_PY_RANDOM (1) +#define MICROPY_PY_RANDOM_EXTRA_FUNCS (1) + +#include "py/dynruntime.h" + +// Dynamic native modules don't support a data section so these must go in the BSS +uint32_t yasmarang_pad, yasmarang_n, yasmarang_d; +uint8_t yasmarang_dat; + +#include "extmod/modrandom.c" + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + yasmarang_pad = 0xeda4baba; + yasmarang_n = 69; + yasmarang_d = 233; + + mp_store_global(MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR_random)); + mp_store_global(MP_QSTR_getrandbits, MP_OBJ_FROM_PTR(&mod_random_getrandbits_obj)); + mp_store_global(MP_QSTR_seed, MP_OBJ_FROM_PTR(&mod_random_seed_obj)); + #if MICROPY_PY_RANDOM_EXTRA_FUNCS + mp_store_global(MP_QSTR_randrange, MP_OBJ_FROM_PTR(&mod_random_randrange_obj)); + mp_store_global(MP_QSTR_randint, MP_OBJ_FROM_PTR(&mod_random_randint_obj)); + mp_store_global(MP_QSTR_choice, MP_OBJ_FROM_PTR(&mod_random_choice_obj)); + #if MICROPY_PY_BUILTINS_FLOAT + mp_store_global(MP_QSTR_random, MP_OBJ_FROM_PTR(&mod_random_random_obj)); + mp_store_global(MP_QSTR_uniform, MP_OBJ_FROM_PTR(&mod_random_uniform_obj)); + #endif + #endif + + MP_DYNRUNTIME_INIT_EXIT +} diff --git a/examples/natmod/re/Makefile b/examples/natmod/re/Makefile new file mode 100644 index 00000000000..56b08b98868 --- /dev/null +++ b/examples/natmod/re/Makefile @@ -0,0 +1,13 @@ +# Location of top-level MicroPython directory +MPY_DIR = ../../.. + +# Name of module (different to built-in re so it can coexist) +MOD = re_$(ARCH) + +# Source files (.c or .py) +SRC = re.c + +# Architecture to build for (x86, x64, armv7m, xtensa, xtensawin, rv32imc) +ARCH = x64 + +include $(MPY_DIR)/py/dynruntime.mk diff --git a/examples/natmod/re/re.c b/examples/natmod/re/re.c new file mode 100644 index 00000000000..c0279ee7e81 --- /dev/null +++ b/examples/natmod/re/re.c @@ -0,0 +1,91 @@ +#define MICROPY_STACK_CHECK (1) +#define MICROPY_PY_RE (1) +#define MICROPY_PY_RE_MATCH_GROUPS (1) +#define MICROPY_PY_RE_MATCH_SPAN_START_END (1) +#define MICROPY_PY_RE_SUB (0) // requires vstr interface + +#if defined __has_builtin +#if __has_builtin(__builtin_alloca) +#define alloca __builtin_alloca +#endif +#endif + +#if !defined(alloca) +#if defined(_PICOLIBC__) && !defined(HAVE_BUILTIN_ALLOCA) +#define alloca(n) m_malloc(n) +#else +#include +#endif +#endif + +#include "py/dynruntime.h" + +#define STACK_LIMIT (2048) + +const char *stack_top; + +void mp_cstack_check(void) { + // Assumes descending stack on target + volatile char dummy; + if (stack_top - &dummy >= STACK_LIMIT) { + mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("maximum recursion depth exceeded")); + } +} + +#if !defined(__linux__) +void *memcpy(void *dst, const void *src, size_t n) { + return mp_fun_table.memmove_(dst, src, n); +} +void *memset(void *s, int c, size_t n) { + return mp_fun_table.memset_(s, c, n); +} +#endif + +void *memmove(void *dest, const void *src, size_t n) { + return mp_fun_table.memmove_(dest, src, n); +} + +mp_obj_full_type_t match_type; +mp_obj_full_type_t re_type; + +#include "extmod/modre.c" + +mp_map_elem_t match_locals_dict_table[5]; +static MP_DEFINE_CONST_DICT(match_locals_dict, match_locals_dict_table); + +mp_map_elem_t re_locals_dict_table[3]; +static MP_DEFINE_CONST_DICT(re_locals_dict, re_locals_dict_table); + +mp_obj_t mpy_init(mp_obj_fun_bc_t *self, size_t n_args, size_t n_kw, mp_obj_t *args) { + MP_DYNRUNTIME_INIT_ENTRY + + char dummy; + stack_top = &dummy; + + // Because MP_QSTR_start/end/split are static, xtensa and xtensawin will make a small data section + // to copy in this key/value pair if they are specified as a struct, so assign them separately. + + match_type.base.type = (void*)&mp_fun_table.type_type; + match_type.name = MP_QSTR_match; + MP_OBJ_TYPE_SET_SLOT(&match_type, print, match_print, 0); + match_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_group), MP_OBJ_FROM_PTR(&match_group_obj) }; + match_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_groups), MP_OBJ_FROM_PTR(&match_groups_obj) }; + match_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_span), MP_OBJ_FROM_PTR(&match_span_obj) }; + match_locals_dict_table[3] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_start), MP_OBJ_FROM_PTR(&match_start_obj) }; + match_locals_dict_table[4] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_end), MP_OBJ_FROM_PTR(&match_end_obj) }; + MP_OBJ_TYPE_SET_SLOT(&match_type, locals_dict, (void*)&match_locals_dict, 1); + + re_type.base.type = (void*)&mp_fun_table.type_type; + re_type.name = MP_QSTR_re; + MP_OBJ_TYPE_SET_SLOT(&re_type, print, re_print, 0); + re_locals_dict_table[0] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_match), MP_OBJ_FROM_PTR(&re_match_obj) }; + re_locals_dict_table[1] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_search), MP_OBJ_FROM_PTR(&re_search_obj) }; + re_locals_dict_table[2] = (mp_map_elem_t){ MP_OBJ_NEW_QSTR(MP_QSTR_split), MP_OBJ_FROM_PTR(&re_split_obj) }; + MP_OBJ_TYPE_SET_SLOT(&re_type, locals_dict, (void*)&re_locals_dict, 1); + + mp_store_global(MP_QSTR_compile, MP_OBJ_FROM_PTR(&mod_re_compile_obj)); + mp_store_global(MP_QSTR_match, MP_OBJ_FROM_PTR(&re_match_obj)); + mp_store_global(MP_QSTR_search, MP_OBJ_FROM_PTR(&re_search_obj)); + + MP_DYNRUNTIME_INIT_EXIT +} From 6a075db36dc63c8c3262feda656fe01b5091ce41 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 12 Jul 2026 13:51:35 -0500 Subject: [PATCH 650/876] dynruntime: fix m_malloc_fail_dyn --- py/dynruntime.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/py/dynruntime.h b/py/dynruntime.h index ab155a13875..9eea5ca6e5c 100644 --- a/py/dynruntime.h +++ b/py/dynruntime.h @@ -71,7 +71,7 @@ #define m_realloc_maybe(ptr, new_num_bytes, allow_move) (m_realloc_maybe_dyn((ptr), (new_num_bytes), (allow_move))) static MP_NORETURN inline void m_malloc_fail_dyn(size_t num_bytes) { - mp_fun_table.raise_msg( + mp_fun_table.raise_msg_str( mp_fun_table.load_global(MP_QSTR_MemoryError), "memory allocation failed"); } From 86128b4bd18e3b9b9140a664a6f3d62626302f6e Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 12 Jul 2026 13:52:26 -0500 Subject: [PATCH 651/876] mpy_ld: several CIRCUITPY-CHANGEd constants With this, it is now possible to build & load the "features1" natmod test in the Unix coverage build and call its functions. --- tools/mpy_ld.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py index 26db0726163..f5fc0ffc8a7 100755 --- a/tools/mpy_ld.py +++ b/tools/mpy_ld.py @@ -50,11 +50,13 @@ MP_NATIVE_ARCH_XTENSAWIN = 10 MP_NATIVE_ARCH_RV32IMC = 11 MP_PERSISTENT_OBJ_STR = 5 -MP_SCOPE_FLAG_VIPERRELOC = 0x10 -MP_SCOPE_FLAG_VIPERRODATA = 0x20 -MP_SCOPE_FLAG_VIPERBSS = 0x40 +## CIRCUITPY-CHANGE: FLAG_ASYNC +MP_SCOPE_FLAG_VIPERRELOC = 0x20 +MP_SCOPE_FLAG_VIPERRODATA = 0x40 +MP_SCOPE_FLAG_VIPERBSS = 0x80 MP_SMALL_INT_BITS = 31 -MP_FUN_TABLE_MP_TYPE_TYPE_OFFSET = 73 +## CIRCUITPY-CHANGE (due to added assert_native_inited) +MP_FUN_TABLE_MP_TYPE_TYPE_OFFSET = 74 # ELF constants R_386_32 = 1 From 4c4e6b00ad7062e5cfc6ce749b6d2eb924b5b8c2 Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 12 Jul 2026 13:53:06 -0500 Subject: [PATCH 652/876] unix: Don't disable the native emitter anymore. This will need to be tweaked, as some of the tests fail. But it'll be needed in order to eventually test natmod at build time. --- ports/unix/mpconfigport.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/unix/mpconfigport.mk b/ports/unix/mpconfigport.mk index c836663cd23..3c844ccef3b 100644 --- a/ports/unix/mpconfigport.mk +++ b/ports/unix/mpconfigport.mk @@ -55,5 +55,4 @@ MICROPY_VFS_LFS2 = 0 # CIRCUITPY-CHANGE CIRCUITPY_ULAB = 1 CIRCUITPY_MESSAGE_COMPRESSION_LEVEL = 1 -MICROPY_EMIT_NATIVE = 0 CFLAGS += -DCIRCUITPY=1 From 4a481159b14430ae3caa37a53c5353f023acdb31 Mon Sep 17 00:00:00 2001 From: yi chen <94xhn1@gmail.com> Date: Mon, 13 Jul 2026 10:17:37 +0800 Subject: [PATCH 653/876] shared-module/os: fix size_t underflow in abspath(".." at root) common_hal_os_path_abspath() removes ".." components by decrementing slash_count and then indexing slashes[slash_count - 1]. When the input path resolves to ".." applied directly at the filesystem root ("/"), only the root boundary itself has been recorded (slash_count == 1). The unconditional slash_count-- makes it 0, and slashes[(size_t)0 - 1] reads slashes[SIZE_MAX] -- an out-of-bounds read of a single-element stack VLA whose garbage value is then used as output_len to write full_path[output_len] = '\0', an out-of-bounds/wild write. This is reachable directly from Python whenever cwd is "/" (the default at boot, before any chdir), e.g.: os.chdir("..") os.listdir("..") os.mkdir("../x") and likewise for os.remove/os.rmdir/os.rename/os.utime, since they all normalize their path argument through this same helper first. Fix: only decrement slash_count when there is more than the root boundary recorded (slash_count > 1). This matches POSIX "cd .. from / stays at /" semantics and leaves every non-root case byte-for-byte identical to the previous behavior. Co-Authored-By: Claude Sonnet 5 --- shared-module/os/__init__.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shared-module/os/__init__.c b/shared-module/os/__init__.c index 3a9c0e31f8e..2090dcbcdc4 100644 --- a/shared-module/os/__init__.c +++ b/shared-module/os/__init__.c @@ -122,8 +122,14 @@ const char *common_hal_os_path_abspath(const char *path) { // Remove the dot output_len = slashes[slash_count - 1]; } else if (component_len == 2 && full_path[i - 1] == '.' && full_path[i - 2] == '.') { - // Remove the double dot and the previous component if it exists - slash_count--; + // Remove the double dot and the previous component if it exists. + // Never rewind past the root: if the root is the only recorded + // boundary (slash_count == 1), ".." at the root is a no-op instead of + // underflowing slash_count to SIZE_MAX and reading slashes[SIZE_MAX] + // out of bounds (matches POSIX "cd .. from / stays at /" semantics). + if (slash_count > 1) { + slash_count--; + } output_len = slashes[slash_count - 1]; } else { slashes[slash_count] = output_len; From ceac7e6e9513a6f62ae21ac6b2dce5f08266e192 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 12 Jul 2026 22:37:42 -0400 Subject: [PATCH 654/876] Rename ResetReason enum members to MCU_RESET_REASON_* The mcu_reset_reason_t members used a bare RESET_REASON_ prefix. Several port SDKs also use RESET_REASON_* names for their own purposes: atmel-samd ASF4 reset_reason, esp-idf soc_reset_reason_t, Nordic softdevice, Silabs Gecko SDK, NXP SCFW. Fortunately there were no conflicts, but this could have caused either name conflicts or human confusion about which name to use. Co-Authored-By: Claude Opus 4.8 (1M context) --- main.c | 2 +- .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/Processor.c | 16 +++++++-------- .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/Processor.c | 14 ++++++------- .../common-hal/microcontroller/Processor.c | 20 +++++++++---------- .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/Processor.c | 2 +- .../common-hal/microcontroller/Processor.c | 4 ++-- .../common-hal/microcontroller/Processor.c | 2 +- shared-bindings/microcontroller/ResetReason.c | 16 +++++++-------- shared-bindings/microcontroller/ResetReason.h | 16 +++++++-------- supervisor/shared/bluetooth/bluetooth.c | 10 +++++----- supervisor/shared/safe_mode.c | 8 ++++---- supervisor/shared/web_workflow/web_workflow.c | 10 +++++----- 19 files changed, 67 insertions(+), 67 deletions(-) diff --git a/main.c b/main.c index 3238bd9a08a..84424b26e10 100644 --- a/main.c +++ b/main.c @@ -657,7 +657,7 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s #if CIRCUITPY_ALARM if (_exec_result.return_code & PYEXEC_DEEP_SLEEP) { const bool awoke_from_true_deep_sleep = - common_hal_mcu_processor_get_reset_reason() == RESET_REASON_DEEP_SLEEP_ALARM; + common_hal_mcu_processor_get_reset_reason() == MCU_RESET_REASON_DEEP_SLEEP_ALARM; if (fake_sleeping) { // This waits until a pretend deep sleep alarm occurs. They are set diff --git a/ports/analog/common-hal/microcontroller/Processor.c b/ports/analog/common-hal/microcontroller/Processor.c index 87d8047ff2c..3695ecdf671 100644 --- a/ports/analog/common-hal/microcontroller/Processor.c +++ b/ports/analog/common-hal/microcontroller/Processor.c @@ -42,5 +42,5 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { #if CIRCUITPY_ALARM // TODO: (low prior.) add reset reason in alarm / deepsleep cases (should require alarm peripheral API in "peripherals") #endif - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/atmel-samd/common-hal/microcontroller/Processor.c b/ports/atmel-samd/common-hal/microcontroller/Processor.c index 95ecde815e6..235229ab34c 100644 --- a/ports/atmel-samd/common-hal/microcontroller/Processor.c +++ b/ports/atmel-samd/common-hal/microcontroller/Processor.c @@ -328,5 +328,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/broadcom/common-hal/microcontroller/Processor.c b/ports/broadcom/common-hal/microcontroller/Processor.c index 4956604f9b6..94eafe6c3d1 100644 --- a/ports/broadcom/common-hal/microcontroller/Processor.c +++ b/ports/broadcom/common-hal/microcontroller/Processor.c @@ -31,5 +31,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/cxd56/common-hal/microcontroller/Processor.c b/ports/cxd56/common-hal/microcontroller/Processor.c index 6b9d20afa04..a3e2a44a3e4 100644 --- a/ports/cxd56/common-hal/microcontroller/Processor.c +++ b/ports/cxd56/common-hal/microcontroller/Processor.c @@ -30,5 +30,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/espressif/common-hal/microcontroller/Processor.c b/ports/espressif/common-hal/microcontroller/Processor.c index e87025067a3..6ee196699a0 100644 --- a/ports/espressif/common-hal/microcontroller/Processor.c +++ b/ports/espressif/common-hal/microcontroller/Processor.c @@ -165,23 +165,23 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { switch (esp_reset_reason()) { case ESP_RST_POWERON: - return RESET_REASON_POWER_ON; + return MCU_RESET_REASON_POWER_ON; case ESP_RST_SW: case ESP_RST_PANIC: - return RESET_REASON_SOFTWARE; + return MCU_RESET_REASON_SOFTWARE; case ESP_RST_INT_WDT: case ESP_RST_TASK_WDT: case ESP_RST_WDT: - return RESET_REASON_WATCHDOG; + return MCU_RESET_REASON_WATCHDOG; case ESP_RST_BROWNOUT: - return RESET_REASON_BROWNOUT; + return MCU_RESET_REASON_BROWNOUT; case ESP_RST_SDIO: case ESP_RST_EXT: - return RESET_REASON_RESET_PIN; + return MCU_RESET_REASON_RESET_PIN; case ESP_RST_DEEPSLEEP: { uint32_t wakeup_causes = esp_sleep_get_wakeup_causes(); @@ -191,14 +191,14 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { (1 << ESP_SLEEP_WAKEUP_TOUCHPAD) | (1 << ESP_SLEEP_WAKEUP_ULP); if (wakeup_causes & alarm_causes) { - return RESET_REASON_DEEP_SLEEP_ALARM; + return MCU_RESET_REASON_DEEP_SLEEP_ALARM; } - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } case ESP_RST_UNKNOWN: default: - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } } diff --git a/ports/litex/common-hal/microcontroller/Processor.c b/ports/litex/common-hal/microcontroller/Processor.c index cf80a01d4e6..0d1c29b1ad0 100644 --- a/ports/litex/common-hal/microcontroller/Processor.c +++ b/ports/litex/common-hal/microcontroller/Processor.c @@ -46,5 +46,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/mimxrt10xx/common-hal/microcontroller/Processor.c b/ports/mimxrt10xx/common-hal/microcontroller/Processor.c index 23e854953d6..c7cbd52566b 100644 --- a/ports/mimxrt10xx/common-hal/microcontroller/Processor.c +++ b/ports/mimxrt10xx/common-hal/microcontroller/Processor.c @@ -77,5 +77,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/nordic/common-hal/microcontroller/Processor.c b/ports/nordic/common-hal/microcontroller/Processor.c index c80da222307..fc3f0e7150e 100644 --- a/ports/nordic/common-hal/microcontroller/Processor.c +++ b/ports/nordic/common-hal/microcontroller/Processor.c @@ -109,28 +109,28 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - mcu_reset_reason_t r = RESET_REASON_UNKNOWN; + mcu_reset_reason_t r = MCU_RESET_REASON_UNKNOWN; if (reset_reason_saved == 0) { - r = RESET_REASON_POWER_ON; + r = MCU_RESET_REASON_POWER_ON; } else if (reset_reason_saved & POWER_RESETREAS_RESETPIN_Msk) { - r = RESET_REASON_RESET_PIN; + r = MCU_RESET_REASON_RESET_PIN; } else if (reset_reason_saved & POWER_RESETREAS_DOG_Msk) { - r = RESET_REASON_WATCHDOG; + r = MCU_RESET_REASON_WATCHDOG; } else if (reset_reason_saved & POWER_RESETREAS_SREQ_Msk) { - r = RESET_REASON_SOFTWARE; + r = MCU_RESET_REASON_SOFTWARE; #if CIRCUITPY_ALARM // Our "deep sleep" is still actually light sleep followed by a software // reset. Adding this check here ensures we treat it as-if we're waking // from deep sleep. if (sleepmem_wakeup_event != SLEEPMEM_WAKEUP_BY_NONE) { - r = RESET_REASON_DEEP_SLEEP_ALARM; + r = MCU_RESET_REASON_DEEP_SLEEP_ALARM; } #endif } else if ((reset_reason_saved & POWER_RESETREAS_OFF_Msk) || (reset_reason_saved & POWER_RESETREAS_LPCOMP_Msk) || (reset_reason_saved & POWER_RESETREAS_NFC_Msk) || (reset_reason_saved & POWER_RESETREAS_VBUS_Msk)) { - r = RESET_REASON_DEEP_SLEEP_ALARM; + r = MCU_RESET_REASON_DEEP_SLEEP_ALARM; } return r; } diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.c b/ports/raspberrypi/common-hal/microcontroller/Processor.c index 5a4e7071544..c093a964c39 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.c +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.c @@ -78,41 +78,41 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - mcu_reset_reason_t reason = RESET_REASON_UNKNOWN; + mcu_reset_reason_t reason = MCU_RESET_REASON_UNKNOWN; #if PICO_RP2040 uint32_t chip_reset_reg = vreg_and_chip_reset_hw->chip_reset; if (chip_reset_reg & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) { - reason = RESET_REASON_RESCUE_DEBUG; + reason = MCU_RESET_REASON_RESCUE_DEBUG; } if (chip_reset_reg & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) { - reason = RESET_REASON_RESET_PIN; + reason = MCU_RESET_REASON_RESET_PIN; } if (chip_reset_reg & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) { // NOTE: This register is also used for brownout, but there is no way to differentiate between power on and brown out - reason = RESET_REASON_POWER_ON; + reason = MCU_RESET_REASON_POWER_ON; } #endif #if PICO_RP2350 uint32_t chip_reset_reg = powman_hw->chip_reset; if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) { - reason = RESET_REASON_RESCUE_DEBUG; + reason = MCU_RESET_REASON_RESCUE_DEBUG; } if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_RUN_LOW_BITS) { - reason = RESET_REASON_RESET_PIN; + reason = MCU_RESET_REASON_RESET_PIN; } if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_BOR_BITS) { - reason = RESET_REASON_BROWNOUT; + reason = MCU_RESET_REASON_BROWNOUT; } if (chip_reset_reg & POWMAN_CHIP_RESET_HAD_POR_BITS) { - reason = RESET_REASON_POWER_ON; + reason = MCU_RESET_REASON_POWER_ON; } #endif @@ -120,12 +120,12 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { // The watchdog is used for software reboots such as resetting after copying a UF2 via the bootloader. if (watchdog_caused_reboot()) { - reason = RESET_REASON_SOFTWARE; + reason = MCU_RESET_REASON_SOFTWARE; } // Actual watchdog usage will set a special value that this function detects. if (watchdog_enable_caused_reboot()) { - reason = RESET_REASON_WATCHDOG; + reason = MCU_RESET_REASON_WATCHDOG; } return reason; diff --git a/ports/renode/common-hal/microcontroller/Processor.c b/ports/renode/common-hal/microcontroller/Processor.c index 3532aa6907a..3a6523338fc 100644 --- a/ports/renode/common-hal/microcontroller/Processor.c +++ b/ports/renode/common-hal/microcontroller/Processor.c @@ -33,5 +33,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_POWER_ON; + return MCU_RESET_REASON_POWER_ON; } diff --git a/ports/silabs/common-hal/microcontroller/Processor.c b/ports/silabs/common-hal/microcontroller/Processor.c index 226fe4529fb..741a147d1cf 100644 --- a/ports/silabs/common-hal/microcontroller/Processor.c +++ b/ports/silabs/common-hal/microcontroller/Processor.c @@ -62,5 +62,5 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/stm/common-hal/microcontroller/Processor.c b/ports/stm/common-hal/microcontroller/Processor.c index 0781f422ee1..719d29e1d53 100644 --- a/ports/stm/common-hal/microcontroller/Processor.c +++ b/ports/stm/common-hal/microcontroller/Processor.c @@ -127,8 +127,8 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { #if CIRCUITPY_ALARM if (alarm_get_wakeup_cause() != STM_WAKEUP_UNDEF) { - return RESET_REASON_DEEP_SLEEP_ALARM; + return MCU_RESET_REASON_DEEP_SLEEP_ALARM; } #endif - return RESET_REASON_UNKNOWN; + return MCU_RESET_REASON_UNKNOWN; } diff --git a/ports/zephyr-cp/common-hal/microcontroller/Processor.c b/ports/zephyr-cp/common-hal/microcontroller/Processor.c index 9f512a686ec..593d73bcc61 100644 --- a/ports/zephyr-cp/common-hal/microcontroller/Processor.c +++ b/ports/zephyr-cp/common-hal/microcontroller/Processor.c @@ -45,6 +45,6 @@ void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { } mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { - mcu_reset_reason_t r = RESET_REASON_UNKNOWN; + mcu_reset_reason_t r = MCU_RESET_REASON_UNKNOWN; return r; } diff --git a/shared-bindings/microcontroller/ResetReason.c b/shared-bindings/microcontroller/ResetReason.c index e16e8a056fb..46eb23e36aa 100644 --- a/shared-bindings/microcontroller/ResetReason.c +++ b/shared-bindings/microcontroller/ResetReason.c @@ -9,14 +9,14 @@ #include "shared-bindings/microcontroller/ResetReason.h" -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, POWER_ON, RESET_REASON_POWER_ON); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, BROWNOUT, RESET_REASON_BROWNOUT); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, SOFTWARE, RESET_REASON_SOFTWARE); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, DEEP_SLEEP_ALARM, RESET_REASON_DEEP_SLEEP_ALARM); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESET_PIN, RESET_REASON_RESET_PIN); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, WATCHDOG, RESET_REASON_WATCHDOG); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, UNKNOWN, RESET_REASON_UNKNOWN); -MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESCUE_DEBUG, RESET_REASON_RESCUE_DEBUG); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, POWER_ON, MCU_RESET_REASON_POWER_ON); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, BROWNOUT, MCU_RESET_REASON_BROWNOUT); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, SOFTWARE, MCU_RESET_REASON_SOFTWARE); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, DEEP_SLEEP_ALARM, MCU_RESET_REASON_DEEP_SLEEP_ALARM); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESET_PIN, MCU_RESET_REASON_RESET_PIN); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, WATCHDOG, MCU_RESET_REASON_WATCHDOG); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, UNKNOWN, MCU_RESET_REASON_UNKNOWN); +MAKE_ENUM_VALUE(mcu_reset_reason_type, reset_reason, RESCUE_DEBUG, MCU_RESET_REASON_RESCUE_DEBUG); //| class ResetReason: //| """The reason the microcontroller was last reset""" diff --git a/shared-bindings/microcontroller/ResetReason.h b/shared-bindings/microcontroller/ResetReason.h index 61ff80639a6..772d7ff4ba4 100644 --- a/shared-bindings/microcontroller/ResetReason.h +++ b/shared-bindings/microcontroller/ResetReason.h @@ -10,14 +10,14 @@ #include "py/enum.h" typedef enum { - RESET_REASON_POWER_ON, - RESET_REASON_BROWNOUT, - RESET_REASON_SOFTWARE, - RESET_REASON_DEEP_SLEEP_ALARM, - RESET_REASON_RESET_PIN, - RESET_REASON_WATCHDOG, - RESET_REASON_UNKNOWN, - RESET_REASON_RESCUE_DEBUG, + MCU_RESET_REASON_POWER_ON, + MCU_RESET_REASON_BROWNOUT, + MCU_RESET_REASON_SOFTWARE, + MCU_RESET_REASON_DEEP_SLEEP_ALARM, + MCU_RESET_REASON_RESET_PIN, + MCU_RESET_REASON_WATCHDOG, + MCU_RESET_REASON_UNKNOWN, + MCU_RESET_REASON_RESCUE_DEBUG, } mcu_reset_reason_t; extern const mp_obj_type_t mcu_reset_reason_type; diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index cccb371fc4d..44291d6d749 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -187,11 +187,11 @@ void supervisor_bluetooth_init(void) { } const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); boot_in_discovery_mode = false; - if (reset_reason != RESET_REASON_POWER_ON && - reset_reason != RESET_REASON_RESET_PIN && - reset_reason != RESET_REASON_DEEP_SLEEP_ALARM && - reset_reason != RESET_REASON_UNKNOWN && - reset_reason != RESET_REASON_SOFTWARE) { + if (reset_reason != MCU_RESET_REASON_POWER_ON && + reset_reason != MCU_RESET_REASON_RESET_PIN && + reset_reason != MCU_RESET_REASON_DEEP_SLEEP_ALARM && + reset_reason != MCU_RESET_REASON_UNKNOWN && + reset_reason != MCU_RESET_REASON_SOFTWARE) { return; } diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index da528d27df7..0031482ec98 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -54,10 +54,10 @@ safe_mode_t wait_for_safe_mode_reset(void) { } const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); - if (reset_reason != RESET_REASON_POWER_ON && - reset_reason != RESET_REASON_RESET_PIN && - reset_reason != RESET_REASON_UNKNOWN && - reset_reason != RESET_REASON_SOFTWARE) { + if (reset_reason != MCU_RESET_REASON_POWER_ON && + reset_reason != MCU_RESET_REASON_RESET_PIN && + reset_reason != MCU_RESET_REASON_UNKNOWN && + reset_reason != MCU_RESET_REASON_SOFTWARE) { return SAFE_MODE_NONE; } #if CIRCUITPY_SKIP_SAFE_MODE_WAIT diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index 8da8dcc5184..66b7424b06f 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -339,11 +339,11 @@ bool supervisor_start_web_workflow(void) { // Skip starting the workflow if we're not starting from power on or reset. const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); - if (reset_reason != RESET_REASON_POWER_ON && - reset_reason != RESET_REASON_RESET_PIN && - reset_reason != RESET_REASON_DEEP_SLEEP_ALARM && - reset_reason != RESET_REASON_UNKNOWN && - reset_reason != RESET_REASON_SOFTWARE) { + if (reset_reason != MCU_RESET_REASON_POWER_ON && + reset_reason != MCU_RESET_REASON_RESET_PIN && + reset_reason != MCU_RESET_REASON_DEEP_SLEEP_ALARM && + reset_reason != MCU_RESET_REASON_UNKNOWN && + reset_reason != MCU_RESET_REASON_SOFTWARE) { return false; } From 1e6db525f0486595af0443835be25e1cbc04902f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Mon, 13 Jul 2026 08:56:15 -0500 Subject: [PATCH 655/876] clarify buffer_size argument docstring --- shared-bindings/audiofilewriter/AudioFileWriter.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared-bindings/audiofilewriter/AudioFileWriter.c b/shared-bindings/audiofilewriter/AudioFileWriter.c index 51b63d834aa..8dbdba5d448 100644 --- a/shared-bindings/audiofilewriter/AudioFileWriter.c +++ b/shared-bindings/audiofilewriter/AudioFileWriter.c @@ -37,6 +37,8 @@ //| :param int buffer_size: Size in bytes of the internal RAM ring that //| decouples file-write latency from the source. Larger values tolerate //| longer write stalls (e.g. a slow SD card) at the cost of RAM. +//| Minimum valid value, and default, is ``512``. Must be at least the +//| size of the source buffer. //| //| The audio format (sample rate, channel count, bit depth) is taken from //| the source at `play()` time, so there are no format arguments here. From eaae6b7851e0580e1e90bea17e32ca0e253cc61f Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 12 Jul 2026 15:24:56 -0500 Subject: [PATCH 656/876] requirements: natmod tests now require ar. --- requirements-dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements-dev.txt b/requirements-dev.txt index 6a33c49daec..aca235d6346 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -24,6 +24,7 @@ intelhex # for building & testing natmods pyelftools +ar cryptography From 24600aa18ab393d218d406b0817952f91598e86a Mon Sep 17 00:00:00 2001 From: Jeff Epler Date: Sun, 12 Jul 2026 15:17:39 -0500 Subject: [PATCH 657/876] run-tests: restore natmod tests --- .github/workflows/run-tests.yml | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 83154bbbd2b..5bb3aaee736 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -53,19 +53,18 @@ jobs: run: ./run-tests.py -j4 --print-failures if: failure() working-directory: tests - # Not working after MicroPython v1.23 merge. - # - name: Build native modules - # if: matrix.test == 'all' - # run: | - # make -C examples/natmod/features1 - # make -C examples/natmod/features2 - # make -C examples/natmod/heapq - # make -C examples/natmod/random - # make -C examples/natmod/re - # - name: Test native modules - # if: matrix.test == 'all' - # run: ./run-natmodtests.py extmod/{heapq*,random*,re*}.py - # working-directory: tests + - name: Build native modules + if: matrix.test == 'all' + run: | + make -C examples/natmod/features1 + make -C examples/natmod/features2 + make -C examples/natmod/heapq + make -C examples/natmod/random + make -C examples/natmod/re + - name: Test native modules + if: matrix.test == 'all' + run: ./run-natmodtests.py extmod/{heapq*,random*,re*}.py + working-directory: tests zephyr: runs-on: ubuntu-24.04 From 234461b8ce9ec1364e9bdf91d606bee87f9d7b82 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 13 Jul 2026 11:18:30 -0500 Subject: [PATCH 658/876] Revert rename audio constants --- shared-bindings/usb_audio/__init__.c | 2 +- shared-module/usb_audio/USBMicrophone.c | 2 +- shared-module/usb_audio/USBSpeaker.c | 12 ++--- shared-module/usb_audio/USBSpeaker.h | 2 +- shared-module/usb_audio/__init__.c | 48 +++++++++---------- .../usb_audio/usb_audio_descriptors.h | 6 +-- supervisor/shared/usb/tusb_config.h | 4 +- 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index 7bf20807f3e..00ec82f10ae 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -112,7 +112,7 @@ static mp_obj_t usb_audio_enable(size_t n_args, const mp_obj_t *pos_args, mp_map mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_int_t sample_rate = mp_arg_validate_int_range(args[ARG_sample_rate].u_int, 1, USB_AUDIO_MAX_SAMPLE_RATE, MP_QSTR_sample_rate); - mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_MAX_CHANNELS, MP_QSTR_channel_count); + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, USB_AUDIO_N_CHANNELS, MP_QSTR_channel_count); bool microphone = args[ARG_microphone].u_bool; bool speaker = args[ARG_speaker].u_bool; diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c index 172ef5465e3..9d2a46b7985 100644 --- a/shared-module/usb_audio/USBMicrophone.c +++ b/shared-module/usb_audio/USBMicrophone.c @@ -158,7 +158,7 @@ size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { } size_t n; - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_MAX_CHANNELS)) { + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { n = MIN(self->buffer_length, max_bytes - filled); memcpy(out + filled, self->buffer, n); } else { diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c index e2f2bf4f525..310eb3cd7d2 100644 --- a/shared-module/usb_audio/USBSpeaker.c +++ b/shared-module/usb_audio/USBSpeaker.c @@ -202,18 +202,18 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker size_t to_copy = MIN(self->ring_count, (size_t)half); size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_MAX_CHANNELS)) { + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { memcpy(out, &self->ring[self->ring_tail], first); if (to_copy > first) { memcpy(out + first, &self->ring[0], to_copy - first); } } else { - for (size_t i = self->ring_tail / USB_AUDIO_BYTES_PER_SAMPLE; i < first / USB_AUDIO_BYTES_PER_SAMPLE; i += 2) { + for (size_t i = self->ring_tail / USB_AUDIO_N_BYTES_PER_SAMPLE; i < first / USB_AUDIO_N_BYTES_PER_SAMPLE; i += 2) { word_out[i >> 1] = word_ring[i]; } if (to_copy > first) { - for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_BYTES_PER_SAMPLE; i += 2) { - word_out[(first / USB_AUDIO_BYTES_PER_SAMPLE) + (i >> 1)] = word_ring[i]; + for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_N_BYTES_PER_SAMPLE; i += 2) { + word_out[(first / USB_AUDIO_N_BYTES_PER_SAMPLE) + (i >> 1)] = word_ring[i]; } } } @@ -224,7 +224,7 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker // Underrun: pad the remainder with silence. Samples are signed, so // silence is 0. This is the consume-side of the pacing failure mode // tracked in the usb-audio-artifact-pacing memory: we never spin. - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_MAX_CHANNELS)) { + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { memset(out + to_copy, 0, half - to_copy); } else { memset(out + (to_copy >> 1), 0, (half - to_copy) >> 1); @@ -238,7 +238,7 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker } *buffer = out; - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_MAX_CHANNELS)) { + if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { *buffer_length = half; } else { *buffer_length = half >> 1; diff --git a/shared-module/usb_audio/USBSpeaker.h b/shared-module/usb_audio/USBSpeaker.h index 27007ad275d..0760676b53a 100644 --- a/shared-module/usb_audio/USBSpeaker.h +++ b/shared-module/usb_audio/USBSpeaker.h @@ -23,7 +23,7 @@ #define USB_AUDIO_SPEAKER_FRAMES_PER_BUFFER (128) // Bytes per audio frame in the negotiated UAC2 format (stereo 16-bit). -#define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_BYTES_PER_SAMPLE * USB_AUDIO_MAX_CHANNELS) +#define USB_AUDIO_SPEAKER_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) // Full owned double-buffer: two halves of FRAMES_PER_BUFFER frames each. Matches // audiocore.RawSample's convention where base.max_buffer_length is the whole diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 516bcd53112..5840c861e7e 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -43,8 +43,8 @@ bool usb_audio_microphone_enabled; bool usb_audio_speaker_enabled; // Audio control state surfaced to the host. One extra entry for the master channel 0. -static int8_t usb_audio_mute[USB_AUDIO_MAX_CHANNELS + 1]; -static int16_t usb_audio_volume[USB_AUDIO_MAX_CHANNELS + 1]; +static int8_t usb_audio_mute[USB_AUDIO_N_CHANNELS + 1]; +static int16_t usb_audio_volume[USB_AUDIO_N_CHANNELS + 1]; bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count, bool microphone, bool speaker) { if (tud_connected()) { @@ -53,7 +53,7 @@ bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count // One scratch chunk (1 ms at the sample rate); we loop until the FIFO reaches // the setpoint. - usb_audio_mic_samples_len = sample_rate / 1000 * channel_count * USB_AUDIO_BYTES_PER_SAMPLE; + usb_audio_mic_samples_len = sample_rate / 1000 * channel_count * USB_AUDIO_N_BYTES_PER_SAMPLE; usb_audio_mic_samples = (int16_t *)m_malloc_without_collect(usb_audio_mic_samples_len); if (usb_audio_mic_samples == NULL) { m_malloc_fail(usb_audio_mic_samples_len); @@ -155,7 +155,7 @@ void usb_audio_setup_singletons(void) { /* Clock Source Descriptor(4.7.2.1) */ \ TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ @@ -165,7 +165,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the input terminal */ \ - TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -188,7 +188,7 @@ void usb_audio_setup_singletons(void) { /* Clock Source Descriptor(4.7.2.1) */ \ TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ @@ -200,7 +200,7 @@ void usb_audio_setup_singletons(void) { /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -229,14 +229,14 @@ void usb_audio_setup_singletons(void) { TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ 0x00, /*_stridx*/ 0x00), \ /* --- Speaker chain (host -> board) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- USB streaming in from the host */ \ - TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ 0 * (AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS), /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ /* Output Terminal Descriptor(4.7.2.5) -- desktop speaker */ \ TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_OUT_DESKTOP_SPEAKER, /*_assocTerm*/ 0x00, /*_srcid*/ USB_AUDIO_HS_ENTITY_SPK_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* --- Mic chain (board -> host) --- */ \ /* Input Terminal Descriptor(4.7.2.4) -- generic microphone */ \ - TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ 0x00, /*_clkid*/ USB_AUDIO_HS_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_HS_ENTITY_MIC_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming out to the host */ \ @@ -247,7 +247,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one OUT endpoint */ \ TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the speaker input terminal */ \ - TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_SPK_INPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -260,7 +260,7 @@ void usb_audio_setup_singletons(void) { /* Standard AS Interface Descriptor(4.9.1) -- alt 1, one IN endpoint */ \ TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 2), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ /* Class-Specific AS Interface Descriptor(4.9.2) -- linked to the mic output terminal */ \ - TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_MAX_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_HS_ENTITY_MIC_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ @@ -319,7 +319,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de USB_AUDIO_HEADSET_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_BYTES_PER_SAMPLE, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, /*_epout*/ ep_out, /*_epin*/ ep_in | 0x80, @@ -334,9 +334,9 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus // two OUT and two IN endpoints. descriptor_counts->current_interface += 3; - descriptor_counts->num_out_endpoints += USB_AUDIO_MAX_CHANNELS; - descriptor_counts->num_in_endpoints += USB_AUDIO_MAX_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_MAX_CHANNELS * 2; + descriptor_counts->num_out_endpoints += USB_AUDIO_N_CHANNELS; + descriptor_counts->num_in_endpoints += USB_AUDIO_N_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS * 2; memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -353,7 +353,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de USB_AUDIO_SPEAKER_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_BYTES_PER_SAMPLE, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, /*_epout*/ iso_ep_num, /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) @@ -363,8 +363,8 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two OUT endpoints. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { - descriptor_counts->num_out_endpoints += USB_AUDIO_MAX_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_MAX_CHANNELS; + descriptor_counts->num_out_endpoints += USB_AUDIO_N_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS; } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -381,7 +381,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de USB_AUDIO_MIC_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, /*_stridx*/ *current_interface_string, - /*_nBytesPerSample*/ USB_AUDIO_BYTES_PER_SAMPLE, + /*_nBytesPerSample*/ USB_AUDIO_N_BYTES_PER_SAMPLE, /*_nBitsUsedPerSample*/ USB_AUDIO_BITS_PER_SAMPLE, /*_epin*/ iso_ep_num | 0x80, /*_epsize*/ CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) @@ -391,8 +391,8 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two IN endpoints. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { - descriptor_counts->num_in_endpoints += USB_AUDIO_MAX_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_MAX_CHANNELS; + descriptor_counts->num_in_endpoints += USB_AUDIO_N_CHANNELS; + descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS; } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -544,7 +544,7 @@ bool tud_audio_set_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Mute/volume state is shared across them. if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { - if (channelNum > USB_AUDIO_MAX_CHANNELS) { + if (channelNum > USB_AUDIO_N_CHANNELS) { return false; } switch (ctrlSel) { @@ -582,7 +582,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p switch (ctrlSel) { case AUDIO20_TE_CTRL_CONNECTOR: { audio20_desc_channel_cluster_t ret; - ret.bNrChannels = USB_AUDIO_MAX_CHANNELS; + ret.bNrChannels = USB_AUDIO_N_CHANNELS; ret.bmChannelConfig = (audio20_channel_config_t)0; ret.iChannelNames = 0; return tud_audio_buffer_and_schedule_control_xfer(rhport, p_request, &ret, sizeof(ret)); @@ -595,7 +595,7 @@ bool tud_audio_get_req_entity_cb(uint8_t rhport, tusb_control_request_t const *p // Feature unit (mute/volume) for either the speaker or mic chain. if (entityID == USB_AUDIO_ENTITY_FEATURE_UNIT || entityID == USB_AUDIO_HS_ENTITY_MIC_FEATURE_UNIT) { - if (channelNum > USB_AUDIO_MAX_CHANNELS) { + if (channelNum > USB_AUDIO_N_CHANNELS) { return false; } switch (ctrlSel) { diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index a1ec26b26ca..40691a17529 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -26,11 +26,11 @@ size_t usb_audio_descriptor_length(void); // The isochronous IN endpoint's wMaxPacketSize in the USB descriptor is computed // for this rate, so it is the highest rate usb_audio.enable() will accept. #define USB_AUDIO_MAX_SAMPLE_RATE (48000) -#define USB_AUDIO_MAX_CHANNELS (2) +#define USB_AUDIO_N_CHANNELS (2) // 16-bit signed LE PCM. -#define USB_AUDIO_BYTES_PER_SAMPLE (2) -#define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_BYTES_PER_SAMPLE * 8) +#define USB_AUDIO_N_BYTES_PER_SAMPLE (2) +#define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) // Endpoint number for the single isochronous audio data endpoint. Most device // controllers accept an ISO endpoint on any number, so the descriptor builder diff --git a/supervisor/shared/usb/tusb_config.h b/supervisor/shared/usb/tusb_config.h index 9421dd03e0d..ac63542b8e4 100644 --- a/supervisor/shared/usb/tusb_config.h +++ b/supervisor/shared/usb/tusb_config.h @@ -127,7 +127,7 @@ extern "C" { #define CFG_TUD_AUDIO_ENABLE_EP_IN 1 // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_BYTES_PER_SAMPLE, USB_AUDIO_MAX_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms refill keeps clear of the underrun floor. #define CFG_TUD_AUDIO_FUNC_1_EP_IN_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_IN_SZ_MAX) @@ -137,7 +137,7 @@ extern "C" { // IN sizing above. #define CFG_TUD_AUDIO_ENABLE_EP_OUT 1 // wMaxPacketSize, sized for the highest supported sample rate. -#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_BYTES_PER_SAMPLE, USB_AUDIO_MAX_CHANNELS) +#define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX TUD_AUDIO_EP_SIZE(TUD_OPT_HIGH_SPEED, USB_AUDIO_MAX_SAMPLE_RATE, USB_AUDIO_N_BYTES_PER_SAMPLE, USB_AUDIO_N_CHANNELS) // Deep software FIFO so the 1 ms drain keeps clear of the overrun ceiling. #define CFG_TUD_AUDIO_FUNC_1_EP_OUT_SW_BUF_SZ (16 * CFG_TUD_AUDIO_FUNC_1_EP_OUT_SZ_MAX) #endif From 6f29d4529540ccf74495648586bb2f3bbd6f1616 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 13 Jul 2026 11:34:33 -0500 Subject: [PATCH 659/876] Update stereo mic descriptor --- shared-module/usb_audio/__init__.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 5840c861e7e..2a5948bb74f 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -174,39 +174,39 @@ void usb_audio_setup_singletons(void) { TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) // Hand-rolled UAC2 microphone (board -> host) descriptor WITHOUT an async -// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO_MIC_ONE_CH_DESCRIPTOR +// feedback endpoint. This mirrors TinyUSB's TUD_AUDIO20_MIC_ONE_CH_DESCRIPTOR // (lib/tinyusb/src/device/usbd.h) but drops the trailing feedback endpoint, so // the streaming alt-setting declares a single IN endpoint (_nEPs = 0x00). Async // feedback for true clock matching is a later step. #define USB_AUDIO_MIC_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ /* Standard Interface Association Descriptor (IAD) */ \ - TUD_AUDIO_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ /* Standard AC Interface Descriptor(4.7.1) */ \ - TUD_AUDIO_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ - TUD_AUDIO_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO_DESC_CLK_SRC_LEN + TUD_AUDIO_DESC_INPUT_TERM_LEN + TUD_AUDIO_DESC_OUTPUT_TERM_LEN + TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL_LEN, /*_ctrl*/ AUDIO_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN + TUD_AUDIO20_DESC_INPUT_TERM_LEN + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ /* Clock Source Descriptor(4.7.2.1) */ \ - TUD_AUDIO_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO_CTRL_R << AUDIO_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ - TUD_AUDIO_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO_CTRL_R << AUDIO_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ - TUD_AUDIO_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO_DESC_FEATURE_UNIT_TWO_CHANNEL(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_ctrlch0master*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO_CTRL_RW << AUDIO_FEATURE_UNIT_CTRL_VOLUME_POS, /*_stridx*/ 0x00), \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ /* Standard AS Interface Descriptor(4.9.1) */ \ /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ /* Standard AS Interface Descriptor(4.9.1) */ \ /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ - TUD_AUDIO_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ /* Class-Specific AS Interface Descriptor(4.9.2) */ \ - TUD_AUDIO_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO_CTRL_NONE, /*_formattype*/ AUDIO_FORMAT_TYPE_I, /*_formats*/ AUDIO_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ - TUD_AUDIO_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ - TUD_AUDIO_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ - TUD_AUDIO_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO_CTRL_NONE, /*_lockdelayunit*/ AUDIO_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) // Hand-rolled UAC2 headset (microphone + speaker both enabled): one audio function // presenting both a speaker (host -> board OUT) and a microphone (board -> host From 73a51c4f0aa722e027148d57f2d7b154696063fe Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 13 Jul 2026 15:14:01 -0700 Subject: [PATCH 660/876] raspberrypi: make tusb_time_millis_api RAM-resident; core1 calls it Since the TinyUSB update in #11093, tuh_task_event_ready() calls tusb_time_millis_api() (added upstream in hathach/tinyusb@3a262cb6e to report a due deferred call_after callback). On RP2 boards, usb_host polls tuh_task_event_ready() from core1's PIO-USB frame loop (common-hal/usb_host/Port.c). tuh_task_event_ready() is deliberately placed in RAM by link-rp2*.ld, and everything it calls must be RAM-resident: on RP2350 core1 sets an MPU region that makes flash execute-never, and on RP2040 flash may be unavailable while core0 writes to it. The shared tusb_time_millis_api() implementation (supervisor_ticks_ms32) lives in flash, so core1 died at the first device attach (the first time call_after was pending) and the PIO-USB bus went silent: no USB host device was ever detected. Fixes the regression reported in #10243. Make the shared implementation MP_WEAK and override it in the raspberrypi port with a PLACE_IN_ITCM function that reads the timer directly. time_us_32() >> 10 yields ~1.024 ms units rather than exact milliseconds, which is fine because TinyUSB only uses this API for relative delay arithmetic and every use goes through the same function. Tested on Feather RP2040 USB Host and Fruit Jam with a USB flash drive: both fail to enumerate on current main and enumerate immediately with this change, with the TinyUSB submodule pristine at 5453ed09f. Co-Authored-By: Claude Fable 5 --- ports/raspberrypi/supervisor/usb.c | 16 ++++++++++++++++ supervisor/shared/usb/usb.c | 5 ++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/supervisor/usb.c b/ports/raspberrypi/supervisor/usb.c index 398f3f448a1..244c5bbce9b 100644 --- a/ports/raspberrypi/supervisor/usb.c +++ b/ports/raspberrypi/supervisor/usb.c @@ -6,14 +6,30 @@ #include "lib/tinyusb/src/device/usbd.h" #include "supervisor/background_callback.h" +#include "supervisor/linker.h" #include "supervisor/usb.h" #include "hardware/irq.h" +#include "hardware/timer.h" #include "pico/platform.h" #include "hardware/regs/intctrl.h" void init_usb_hardware(void) { } +// Override the shared implementation with one that is safe to call from core1. +// TinyUSB's tuh_task_event_ready() calls this, and usb_host polls +// tuh_task_event_ready() from core1's PIO-USB frame loop (see +// common-hal/usb_host/Port.c). tuh_task_event_ready() is deliberately placed in +// RAM by link-rp2*.ld, and everything it calls must be RAM-resident too: on +// RP2350, core1 sets an MPU region that makes flash execute-never, and on +// RP2040 flash may be unavailable while core0 writes to it. time_us_32() is a +// static-inline register read. >>10 yields ~1.024 ms units rather than exact +// milliseconds, which is fine because TinyUSB only uses this API for relative +// delay arithmetic and every use goes through this same function. +uint32_t PLACE_IN_ITCM(tusb_time_millis_api)(void) { + return time_us_32() >> 10; +} + static void _usb_irq_wrapper(void) { usb_irq_handler(0); } diff --git a/supervisor/shared/usb/usb.c b/supervisor/shared/usb/usb.c index e8a4422bb36..51222be0e59 100644 --- a/supervisor/shared/usb/usb.c +++ b/supervisor/shared/usb/usb.c @@ -184,7 +184,10 @@ void usb_background(void) { } } -uint32_t tusb_time_millis_api(void) { +// Ports may override this with a RAM-resident version when TinyUSB code that +// calls it must not execute from flash (e.g. raspberrypi polls +// tuh_task_event_ready(), which calls this, from core1). +MP_WEAK uint32_t tusb_time_millis_api(void) { return supervisor_ticks_ms32(); } From ae6b9dbc36863933b98901058a32160b8ee0900b Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 14 Jul 2026 05:27:08 -0700 Subject: [PATCH 661/876] raspberrypi: bump Pico-PIO-USB for RAM-resident calc_usb_crc16 Picks up sekigon-gonnoc/Pico-PIO-USB#207: calc_usb_crc16 was the one CRC routine left in flash, and it runs on core1 when continuing multi-packet OUT transfers. Core1 must not touch flash, so any USB host write larger than one packet (e.g. writing to a USB drive) hard faulted core1 and locked up the board. Verified on Adafruit Feather RP2040 USB Host with a raw SCSI WRITE(10): locks up without the fix, completes with it. Co-Authored-By: Claude Fable 5 --- ports/raspberrypi/lib/Pico-PIO-USB | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/lib/Pico-PIO-USB b/ports/raspberrypi/lib/Pico-PIO-USB index dc9193fed51..a5a2f5ae919 160000 --- a/ports/raspberrypi/lib/Pico-PIO-USB +++ b/ports/raspberrypi/lib/Pico-PIO-USB @@ -1 +1 @@ -Subproject commit dc9193fed510da5f81f4db520e98282f61db9054 +Subproject commit a5a2f5ae91988449ba576ec9d237e806d5cd4416 From fa7f89c417b486afea6904174821690a5abcba1b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 14 Jul 2026 10:40:22 -0400 Subject: [PATCH 662/876] settings.toml (environment) doc had doubled backslashes --- docs/environment.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index 2c72b4f1004..7d0e41727d3 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -42,9 +42,9 @@ Upper and lower case may both be used in the key name. CIRCUITPY_SDCARD_USB = false # a boolean delay = 0.75 # a float FRENCH="œuvre" # unicode can be used - FRENCH2="\\u0153uvre" # same unicode string, using a 16-bit escape code - FRENCH3="\\U00000153uvre" # same unicode string, using a 32-bit escape code - STRING_WITH_ESCAPE_CODES="supported, including \\r\\n\\"\\\\" + FRENCH2="\u0153uvre" # same unicode string, using a 16-bit escape code + FRENCH3="\U00000153uvre" # same unicode string, using a 32-bit escape code + STRING_WITH_ESCAPE_CODES="supported, including \r \n \" \\" Details of the TOML language subset ----------------------------------- From 1e6b03da9336c61d9051c558ee85833b89d77721 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 14 Jul 2026 09:50:40 -0700 Subject: [PATCH 663/876] raspberrypi: keep core1's mutex-contention wait path out of flash When core1 posts a USB event while core0 holds the TinyUSB queue mutex, core1 falls into the pico-sdk blocking wait, which lived in flash. Core1 cannot execute from flash, so a contended moment hard faults core1 and USB host goes silent. Fixes #11116. On USB host builds only, --wrap best_effort_wfe_or_timeout and time_us_64 with RAM-resident implementations in usb_host/Port.c. The best_effort replacement mirrors the SDK's own documented PICO_TIME_DEFAULT_ALARM_POOL_DISABLED fallback (poll the clock, allow early return), so no alarm pool machinery is pulled into RAM. The time_us_64 replacement keeps the SDK's hi/lo/hi rollover re-read loop. Also RAM-place pico_int64_ops_aeabi.o (50 bytes) next to divider.o in the linker scripts: mutex_enter_timeout_ms multiplies ms to us through __aeabi_lmul, and the SDK already wraps that symbol so it cannot be wrapped again per-feature. Cost: +64 bytes RAM on USB host builds, 50 bytes on builds with CIRCUITPY_USB_HOST=0 (Pico baseline 70320 -> 70384). The previous approach in this branch cost 1216 bytes on every build. With this, the core1 flash-call checker (#11115) passes on Feather RP2040 USB Host, Fruit Jam, and Raspberry Pi Pico builds. Smoke tested on the Feather: 20 SCSI read/write cycles to a flash drive. Co-Authored-By: Claude Fable 5 --- ports/raspberrypi/Makefile | 6 ++++ ports/raspberrypi/common-hal/usb_host/Port.c | 34 ++++++++++++++++++++ ports/raspberrypi/link-rp2040.ld | 2 +- ports/raspberrypi/link-rp2350.ld | 2 +- 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 96ba25ce30c..6d9b557e0ba 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -557,6 +557,12 @@ SRC_C += \ INC += \ -isystem lib/Pico-PIO-USB/src + +# Core1 posts USB events while core0 may hold the TinyUSB queue mutex. The +# contended wait path calls these two flash-resident SDK functions, and core1 +# must not execute from flash. Replace them with RAM-resident implementations +# in common-hal/usb_host/Port.c on USB host builds only. See issue #11116. +PICO_LDFLAGS += -Wl,--wrap=best_effort_wfe_or_timeout -Wl,--wrap=time_us_64 endif ifeq ($(CIRCUITPY_PICODVI),1) diff --git a/ports/raspberrypi/common-hal/usb_host/Port.c b/ports/raspberrypi/common-hal/usb_host/Port.c index da09fdc91c0..f06e9e5d71d 100644 --- a/ports/raspberrypi/common-hal/usb_host/Port.c +++ b/ports/raspberrypi/common-hal/usb_host/Port.c @@ -34,6 +34,40 @@ usb_host_port_obj_t usb_host_instance; volatile bool _core1_ready = false; +// Core1 posts TinyUSB events while core0 may hold the queue FIFO mutex. The +// contended wait path calls best_effort_wfe_or_timeout() and time_us_64(), +// which normally live in flash, but core1 must not touch flash (see the MPU +// setup in core1_main below). These RAM-resident replacements are linked in +// with --wrap on USB host builds only (see the port Makefile). Issue #11116. +// +uint64_t __wrap_time_us_64(void); +bool __wrap_best_effort_wfe_or_timeout(absolute_time_t timeout_timestamp); + +// The same hi/lo/hi re-read loop as the SDK's timer_time_us_64, to defeat +// rollover between the two 32-bit halves. +uint64_t __not_in_flash_func(__wrap_time_us_64)(void) { + uint32_t hi = timer_hw->timerawh; + uint32_t lo; + do { + lo = timer_hw->timerawl; + uint32_t next_hi = timer_hw->timerawh; + if (hi == next_hi) { + break; + } + hi = next_hi; + } while (true); + return ((uint64_t)hi << 32) | lo; +} + +// Mirrors the SDK's own PICO_TIME_DEFAULT_ALARM_POOL_DISABLED fallback +// (a poll of the clock with no __wfe): "best effort" explicitly permits +// returning early, and every SDK caller re-checks in a loop. Polling honors +// the timeout exactly and avoids dragging the alarm pool machinery into RAM. +bool __not_in_flash_func(__wrap_best_effort_wfe_or_timeout)(absolute_time_t timeout_timestamp) { + tight_loop_contents(); + return __wrap_time_us_64() >= to_us_since_boot(timeout_timestamp); +} + static void __not_in_flash_func(core1_main)(void) { // The MPU is reset before this starts. SysTick->LOAD = (uint32_t)((common_hal_mcu_processor_get_frequency() / 1000) - 1UL); diff --git a/ports/raspberrypi/link-rp2040.ld b/ports/raspberrypi/link-rp2040.ld index 6e7bd15a7b6..189c3d7c338 100644 --- a/ports/raspberrypi/link-rp2040.ld +++ b/ports/raspberrypi/link-rp2040.ld @@ -82,7 +82,7 @@ SECTIONS *(.property_getset) __property_getset_end = .; - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.o *divider.o *tusb_fifo.o *mem_ops_aeabi.o *usbh.o) .text*) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.o *divider.o *pico_int64_ops_aeabi.o *tusb_fifo.o *mem_ops_aeabi.o *usbh.o) .text*) /* Allow everything in usbh.o except tuh_task_event_ready because we read it from core 1. */ *usbh.o (.text.[_uphc]* .text.tuh_[cmved]* .text.tuh_task_ext*) *(.fini) diff --git a/ports/raspberrypi/link-rp2350.ld b/ports/raspberrypi/link-rp2350.ld index a2cc62909e6..3c339b03fe2 100644 --- a/ports/raspberrypi/link-rp2350.ld +++ b/ports/raspberrypi/link-rp2350.ld @@ -63,7 +63,7 @@ SECTIONS *(.property_getset) __property_getset_end = .; - *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.o *divider.o *tusb_fifo.o *mem_ops_aeabi.o *usbh.o *string0.o) .text*) + *(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a: *interp.o *divider.o *pico_int64_ops_aeabi.o *tusb_fifo.o *mem_ops_aeabi.o *usbh.o *string0.o) .text*) /* Allow everything in usbh.o except tuh_task_event_ready because we read it from core 1. */ *usbh.o (.text.[_uphc]* .text.tuh_[cmved]* .text.tuh_task_ext*) *(.fini) From a66929590da3d546c8c11362e203ce5c60a39fa4 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Jul 2026 13:40:39 -0500 Subject: [PATCH 664/876] add spread functionality, fix defns --- py/circuitpy_defns.mk | 3 ++ .../audiodelays/GranularPitchShift.c | 34 ++++++++++-- .../audiodelays/GranularPitchShift.h | 5 +- .../audiodelays/GranularPitchShift.c | 53 +++++++++++++++++-- .../audiodelays/GranularPitchShift.h | 9 ++++ 5 files changed, 94 insertions(+), 10 deletions(-) diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 27364fbde00..7dfb9ae7c7d 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -713,6 +713,7 @@ SRC_SHARED_MODULE_ALL = \ audiodelays/Echo.c \ audiodelays/Chorus.c \ audiodelays/PitchShift.c \ + audiodelays/GranularPitchShift.c \ audiodelays/MultiTapDelay.c \ audiodelays/__init__.c \ audiofilters/Distortion.c \ @@ -721,6 +722,8 @@ SRC_SHARED_MODULE_ALL = \ audiofilters/__init__.c \ audiofreeverb/__init__.c \ audiofreeverb/Freeverb.c \ + audiofilewriter/AudioFileWriter.c \ + audiofilewriter/__init__.c \ audioio/__init__.c \ audiomixer/Mixer.c \ audiomixer/MixerVoice.c \ diff --git a/shared-bindings/audiodelays/GranularPitchShift.c b/shared-bindings/audiodelays/GranularPitchShift.c index ed57c36dd06..671f0139963 100644 --- a/shared-bindings/audiodelays/GranularPitchShift.c +++ b/shared-bindings/audiodelays/GranularPitchShift.c @@ -26,6 +26,7 @@ //| mix: synthio.BlockInput = 1.0, //| grain_size: int = 1024, //| density: int = 2, +//| spread: float = 0.0, //| buffer_size: int = 512, //| sample_rate: int = 8000, //| bits_per_sample: int = 16, @@ -45,15 +46,16 @@ //| :param synthio.BlockInput mix: The mix as a ratio of the sample (0.0) to the effect (1.0) //| :param int grain_size: The length in samples of each grain //| :param int density: The number of overlapping grains (overlap factor). Must be between 1 and 8. +//| :param float spread: The amount of random jitter applied to each grain's start position, +//| from 0.0 (deterministic; every grain starts at the same offset) to 1.0 (maximum jitter). +//| Higher values give the classic granular "cloud" texture. Jitter is always backward in +//| time, so it never introduces additional latency beyond ``grain_size``. //| :param int buffer_size: The total size in bytes of each of the two playback buffers to use //| :param int sample_rate: The sample rate to be used //| :param int channel_count: The number of channels the source samples contain. 1 = mono; 2 = stereo. //| :param int bits_per_sample: The bits per sample of the effect //| :param bool samples_signed: Effect is signed (True) or unsigned (False) //| -//| .. note:: Grain start position is currently deterministic (no randomization/jitter). A -//| ``spread`` parameter for classic granular jitter may be added in a future release. -//| //| Shifting the pitch of a synth by 5 semitones:: //| //| import time @@ -76,12 +78,13 @@ //| ... //| static mp_obj_t audiodelays_granular_pitch_shift_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_semitones, ARG_mix, ARG_grain_size, ARG_density, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + enum { ARG_semitones, ARG_mix, ARG_grain_size, ARG_density, ARG_spread, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_semitones, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(0)} }, { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(1)} }, { MP_QSTR_grain_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1024} }, { MP_QSTR_density, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 2} }, + { MP_QSTR_spread, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_INT(0)} }, { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, @@ -108,6 +111,7 @@ static mp_obj_t audiodelays_granular_pitch_shift_make_new(const mp_obj_type_t *t args[ARG_mix].u_obj, grain_size, density, + mp_obj_get_float(args[ARG_spread].u_obj), args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, @@ -193,6 +197,27 @@ MP_PROPERTY_GETSET(audiodelays_granular_pitch_shift_mix_obj, (mp_obj_t)&audiodelays_granular_pitch_shift_set_mix_obj); +//| spread: float +//| """The amount of random jitter applied to each grain's start position, from 0.0 +//| (deterministic) to 1.0 (maximum jitter). Higher values give a thicker granular texture.""" +static mp_obj_t audiodelays_granular_pitch_shift_obj_get_spread(mp_obj_t self_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_float(common_hal_audiodelays_granular_pitch_shift_get_spread(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_granular_pitch_shift_get_spread_obj, audiodelays_granular_pitch_shift_obj_get_spread); + +static mp_obj_t audiodelays_granular_pitch_shift_obj_set_spread(mp_obj_t self_in, mp_obj_t spread_in) { + audiodelays_granular_pitch_shift_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_granular_pitch_shift_set_spread(self, mp_obj_get_float(spread_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_granular_pitch_shift_set_spread_obj, audiodelays_granular_pitch_shift_obj_set_spread); + +MP_PROPERTY_GETSET(audiodelays_granular_pitch_shift_spread_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_get_spread_obj, + (mp_obj_t)&audiodelays_granular_pitch_shift_set_spread_obj); + + //| playing: bool //| """True when the effect is playing a sample. (read-only)""" //| @@ -262,6 +287,7 @@ static const mp_rom_map_elem_t audiodelays_granular_pitch_shift_locals_dict_tabl { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_granular_pitch_shift_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_semitones), MP_ROM_PTR(&audiodelays_granular_pitch_shift_semitones_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_granular_pitch_shift_mix_obj) }, + { MP_ROM_QSTR(MP_QSTR_spread), MP_ROM_PTR(&audiodelays_granular_pitch_shift_spread_obj) }, AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiodelays_granular_pitch_shift_locals_dict, audiodelays_granular_pitch_shift_locals_dict_table); diff --git a/shared-bindings/audiodelays/GranularPitchShift.h b/shared-bindings/audiodelays/GranularPitchShift.h index af85d179ea0..f909abad0e2 100644 --- a/shared-bindings/audiodelays/GranularPitchShift.h +++ b/shared-bindings/audiodelays/GranularPitchShift.h @@ -12,7 +12,7 @@ extern const mp_obj_type_t audiodelays_granular_pitch_shift_type; void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t semitones, mp_obj_t mix, uint32_t grain_size, uint32_t density, - uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, + mp_float_t spread, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate); void common_hal_audiodelays_granular_pitch_shift_deinit(audiodelays_granular_pitch_shift_obj_t *self); @@ -23,6 +23,9 @@ void common_hal_audiodelays_granular_pitch_shift_set_semitones(audiodelays_granu mp_obj_t common_hal_audiodelays_granular_pitch_shift_get_mix(audiodelays_granular_pitch_shift_obj_t *self); void common_hal_audiodelays_granular_pitch_shift_set_mix(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t arg); +mp_float_t common_hal_audiodelays_granular_pitch_shift_get_spread(audiodelays_granular_pitch_shift_obj_t *self); +void common_hal_audiodelays_granular_pitch_shift_set_spread(audiodelays_granular_pitch_shift_obj_t *self, mp_float_t spread); + bool common_hal_audiodelays_granular_pitch_shift_get_playing(audiodelays_granular_pitch_shift_obj_t *self); void common_hal_audiodelays_granular_pitch_shift_play(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t sample, bool loop); void common_hal_audiodelays_granular_pitch_shift_stop(audiodelays_granular_pitch_shift_obj_t *self); diff --git a/shared-module/audiodelays/GranularPitchShift.c b/shared-module/audiodelays/GranularPitchShift.c index f7b6a9b9062..de545eb877d 100644 --- a/shared-module/audiodelays/GranularPitchShift.c +++ b/shared-module/audiodelays/GranularPitchShift.c @@ -12,7 +12,7 @@ void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_pitch_shift_obj_t *self, mp_obj_t semitones, mp_obj_t mix, uint32_t grain_size, uint32_t density, - uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, + mp_float_t spread, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate) { // Basic settings every effect and audio sample has @@ -70,6 +70,12 @@ void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_ } self->density = density; + // Grain-start jitter amount and the PRNG that drives it. Seeded with a fixed + // nonzero constant so xorshift32 never degenerates to the all-zero state and + // the jitter sequence is reproducible from run to run. + common_hal_audiodelays_granular_pitch_shift_set_spread(self, spread); + self->rng_state = 0x1234abcdu; + // Normalization for the overlap-add gain of the grain envelopes. A Hann // window overlapped at hop = grain_size / density sums to a constant gain of // density/2, so we scale the summed grains by 2/density in Q15 to keep the @@ -157,6 +163,19 @@ void common_hal_audiodelays_granular_pitch_shift_set_mix(audiodelays_granular_pi synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); } +mp_float_t common_hal_audiodelays_granular_pitch_shift_get_spread(audiodelays_granular_pitch_shift_obj_t *self) { + return self->spread; +} + +void common_hal_audiodelays_granular_pitch_shift_set_spread(audiodelays_granular_pitch_shift_obj_t *self, mp_float_t spread) { + if (spread < MICROPY_FLOAT_CONST(0.0)) { + spread = MICROPY_FLOAT_CONST(0.0); + } else if (spread > MICROPY_FLOAT_CONST(1.0)) { + spread = MICROPY_FLOAT_CONST(1.0); + } + self->spread = spread; +} + void audiodelays_granular_pitch_shift_reset_buffer(audiodelays_granular_pitch_shift_obj_t *self, bool single_channel_output, uint8_t channel) { @@ -200,15 +219,39 @@ void common_hal_audiodelays_granular_pitch_shift_stop(audiodelays_granular_pitch return; } +// xorshift32 PRNG for grain-start jitter. Kept local to this module so the +// effect doesn't depend on the `random` module being enabled in a build. +static uint32_t granular_pitch_shift_rand(audiodelays_granular_pitch_shift_obj_t *self) { + uint32_t x = self->rng_state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + self->rng_state = x; + return x; +} + // Launch a grain into the first free pool slot, seeded to read from the capture // buffer starting grain_size words behind the current write cursor (so it reads -// already-captured audio) at the current pitch-shift read rate. Grain read -// state (read_index/phase) is per-frame / channel-independent; the per-channel -// plane offset is applied at read time. +// already-captured audio) at the current pitch-shift read rate. When `spread` is +// nonzero the start is jittered up to a further grain_size words backward, which +// is what gives granular synthesis its characteristic "cloud" texture. Jitter is +// always backward (further behind the write cursor), so a grain never reads ahead +// of captured audio and the capture buffer (capture_len == grain_size * 2) is +// never overrun. Grain read state (read_index/phase) is per-frame / +// channel-independent; the per-channel plane offset is applied at read time. static void granular_pitch_shift_launch_grain(audiodelays_granular_pitch_shift_obj_t *self) { for (uint32_t g = 0; g < GRANULAR_MAX_GRAINS; g++) { if (!self->grains[g].active) { - uint32_t start = (self->write_index + self->capture_len - self->grain_size) % self->capture_len; + // Backward jitter in [0, spread * grain_size]. Capped at grain_size + // so grain_size + jitter <= capture_len (== grain_size * 2). + uint32_t jitter = 0; + if (self->spread > MICROPY_FLOAT_CONST(0.0)) { + uint32_t max_jitter = (uint32_t)(self->spread * (mp_float_t)self->grain_size); + if (max_jitter > 0) { + jitter = granular_pitch_shift_rand(self) % (max_jitter + 1); + } + } + uint32_t start = (self->write_index + self->capture_len - self->grain_size - jitter) % self->capture_len; self->grains[g].active = true; self->grains[g].read_index = start << GRANULAR_PITCH_READ_SHIFT; self->grains[g].read_rate = self->read_rate; diff --git a/shared-module/audiodelays/GranularPitchShift.h b/shared-module/audiodelays/GranularPitchShift.h index a0d5a309f96..90579e86c06 100644 --- a/shared-module/audiodelays/GranularPitchShift.h +++ b/shared-module/audiodelays/GranularPitchShift.h @@ -64,6 +64,15 @@ typedef struct { uint32_t grain_size; // samples per grain uint32_t density; // number of overlapping grains (<= GRANULAR_MAX_GRAINS) + // Granular jitter: randomizes each grain's start position within the capture + // buffer. 0.0 is fully deterministic (grains always start grain_size words + // behind the write cursor); 1.0 spreads the start up to a further grain_size + // words backward, giving the classic granular "cloud" texture. Jitter is + // always backward (further behind the write cursor) so it never reads ahead + // of captured audio. + mp_float_t spread; + uint32_t rng_state; // xorshift32 state for grain-start jitter + // Q15 (0..32768) normalization applied to the enveloped grain sum so the // overlap-add gain of `density` Hann grains stays ~unity (Hann satisfies // COLA at these hops with a summed gain of density/2, so the factor is From 23dd83d96fe8fb50a825a18fc9aa63a4054473e1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Jul 2026 14:37:36 -0500 Subject: [PATCH 665/876] translations and format --- locale/circuitpython.pot | 1 + shared-module/audiodelays/GranularPitchShift.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 32f6e4ef631..bc0286dfe61 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -3724,6 +3724,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c #: shared-bindings/audiofilters/Distortion.c diff --git a/shared-module/audiodelays/GranularPitchShift.c b/shared-module/audiodelays/GranularPitchShift.c index de545eb877d..847cab1f8bb 100644 --- a/shared-module/audiodelays/GranularPitchShift.c +++ b/shared-module/audiodelays/GranularPitchShift.c @@ -116,7 +116,7 @@ void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_ for (uint32_t n = 0; n < self->envelope_len; n++) { mp_float_t w = MICROPY_FLOAT_CONST(0.5) * (MICROPY_FLOAT_CONST(1.0) - MICROPY_FLOAT_C_FUN(cos)( - MICROPY_FLOAT_CONST(2.0) * MICROPY_FLOAT_CONST(3.14159265358979323846) * (mp_float_t)n / denom)); + MICROPY_FLOAT_CONST(2.0) * MICROPY_FLOAT_CONST(3.14159265358979323846) * (mp_float_t)n / denom)); self->envelope_table[n] = (int16_t)(w * MICROPY_FLOAT_CONST(32767.0)); } From 4b14747c7f9aae5c4ecfa58c0255eb7826fa8e2c Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Jul 2026 15:59:30 -0500 Subject: [PATCH 666/876] cleanup comments, improve example code, improve var names --- .../audiodelays/GranularPitchShift.c | 13 +++++++--- .../audiodelays/GranularPitchShift.h | 2 +- .../audiodelays/GranularPitchShift.c | 25 ++++++++----------- .../audiodelays/GranularPitchShift.h | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/shared-bindings/audiodelays/GranularPitchShift.c b/shared-bindings/audiodelays/GranularPitchShift.c index 671f0139963..afbda30156a 100644 --- a/shared-bindings/audiodelays/GranularPitchShift.c +++ b/shared-bindings/audiodelays/GranularPitchShift.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT @@ -63,10 +63,17 @@ //| import audiobusio //| import synthio //| import audiodelays +//| from pwmio import PWMOut +//| import adafruit_tlv320 //| -//| audio = audiobusio.I2SOut(bit_clock=board.GP0, word_select=board.GP1, data=board.GP2) +//| mclk_pwm = PWMOut(board.I2S_MCLK, frequency=15_000_000, duty_cycle=2**15) +//| i2c = board.I2C() +//| dac = adafruit_tlv320.TLV320DAC3100(i2c) +//| dac.configure_clocks(sample_rate=44100, bit_depth=16, mclk_freq=15_000_000) +//| dac.headphone_output = True +//| audio = audiobusio.I2SOut(board.I2S_BCLK, board.I2S_WS, board.I2S_DIN) //| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) -//| pitch_shift = audiodelays.GranularPitchShift(semitones=5.0, mix=0.5, grain_size=2048, density=2, buffer_size=1024, channel_count=1, sample_rate=44100) +//| pitch_shift = audiodelays.GranularPitchShift(semitones=5.0, mix=1.0, spread=0.25, grain_size=2048, density=2, buffer_size=1024, channel_count=1, sample_rate=44100) //| pitch_shift.play(synth) //| audio.play(pitch_shift) //| diff --git a/shared-bindings/audiodelays/GranularPitchShift.h b/shared-bindings/audiodelays/GranularPitchShift.h index f909abad0e2..e5a518110bd 100644 --- a/shared-bindings/audiodelays/GranularPitchShift.h +++ b/shared-bindings/audiodelays/GranularPitchShift.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT diff --git a/shared-module/audiodelays/GranularPitchShift.c b/shared-module/audiodelays/GranularPitchShift.c index 847cab1f8bb..d439270b48a 100644 --- a/shared-module/audiodelays/GranularPitchShift.c +++ b/shared-module/audiodelays/GranularPitchShift.c @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT #include "shared-bindings/audiodelays/GranularPitchShift.h" @@ -18,7 +18,7 @@ void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_ // Basic settings every effect and audio sample has // These are the effect's values, not the source sample(s) self->base.bits_per_sample = bits_per_sample; // Most common is 16, but 8 is also supported in many places - self->base.samples_signed = samples_signed; // Are the samples we provide signed (common is true) + self->base.samples_signed = samples_signed; // Are the samples we provide signed self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects self->base.single_buffer = false; @@ -89,8 +89,7 @@ void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_ // Capture buffer (the delay line grains read from), stored as 16-bit, // planar per channel. Length is grain_size * 2 words per channel so a grain // starting grain_size words behind the write pointer never overruns the live - // write cursor even when reading ahead at a raised pitch (see plan sizing - // notes). + // write cursor even when reading ahead at a raised pitch self->capture_len = self->grain_size * 2; // words per channel uint32_t capture_bytes = self->capture_len * self->base.channel_count * sizeof(int16_t); self->capture_buffer = m_malloc_without_collect(capture_bytes); @@ -102,9 +101,7 @@ void common_hal_audiodelays_granular_pitch_shift_construct(audiodelays_granular_ self->write_index = 0; // Precompute the grain amplitude envelope: a raised-cosine (Hann) window in - // Q15 (0..32767), indexed directly by a grain's phase. Computed once here (a - // little float math at construction is fine; the inner playback loop stays - // integer-only). + // Q15 (0..32767), indexed directly by a grain's phase. self->envelope_len = self->grain_size; uint32_t envelope_bytes = self->envelope_len * sizeof(int16_t); self->envelope_table = m_malloc_without_collect(envelope_bytes); @@ -343,7 +340,7 @@ audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodel int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; // for 16-bit samples int8_t *sample_hsrc = (int8_t *)self->sample_remaining_buffer; // for 8-bit samples - // get the effect values we need from the BlockInput. These may change at run time so you need to do bounds checking if required + // get the effect values we need from the BlockInput. shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); mp_float_t semitones = synthio_block_slot_get(&self->semitones); // Doubled (0.0..2.0) so the crossfade below can hold both dry and wet @@ -365,7 +362,7 @@ audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodel if (self->base.samples_signed) { sample_word = sample_hsrc[i]; } else { - // Be careful here changing from an 8 bit unsigned to signed into a 32-bit signed + // Changing from an 8 bit unsigned to signed into a 32-bit signed sample_word = (int8_t)(((uint8_t)sample_hsrc[i]) ^ 0x80); } } @@ -388,11 +385,11 @@ audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodel uint32_t read_index_fp = self->grains[g].read_index; uint32_t ipart = read_index_fp >> GRANULAR_PITCH_READ_SHIFT; uint32_t frac = read_index_fp & ((1 << GRANULAR_PITCH_READ_SHIFT) - 1); - uint32_t i0 = ipart % self->capture_len; - uint32_t i1 = (ipart + 1) % self->capture_len; - int32_t s0 = capture_buffer[i0 + self->capture_len * buf_offset]; - int32_t s1 = capture_buffer[i1 + self->capture_len * buf_offset]; - int32_t grain_out = s0 + (((s1 - s0) * (int32_t)frac) >> GRANULAR_PITCH_READ_SHIFT); + uint32_t index_lo = ipart % self->capture_len; + uint32_t index_hi = (ipart + 1) % self->capture_len; + int32_t sample_lo = capture_buffer[index_lo + self->capture_len * buf_offset]; + int32_t sample_hi = capture_buffer[index_hi + self->capture_len * buf_offset]; + int32_t grain_out = sample_lo + (((sample_hi - sample_lo) * (int32_t)frac) >> GRANULAR_PITCH_READ_SHIFT); // Apply the grain envelope (Q15). phase < length == envelope_len. int32_t env = self->envelope_table[self->grains[g].phase]; word += (grain_out * env) >> 15; diff --git a/shared-module/audiodelays/GranularPitchShift.h b/shared-module/audiodelays/GranularPitchShift.h index 90579e86c06..26ee4804f36 100644 --- a/shared-module/audiodelays/GranularPitchShift.h +++ b/shared-module/audiodelays/GranularPitchShift.h @@ -1,6 +1,6 @@ // This file is part of the CircuitPython project: https://circuitpython.org // -// SPDX-FileCopyrightText: Copyright (c) 2025 Cooper Dalrymple +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries // // SPDX-License-Identifier: MIT #pragma once From bf454534975dedaa732e3ae9770bac80ca097618 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 14 Jul 2026 16:23:16 -0500 Subject: [PATCH 667/876] add module to coverage unix port list --- ports/unix/variants/coverage/mpconfigvariant.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index 292e4de8169..682fe77459e 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -37,6 +37,7 @@ SRC_BITMAP := \ shared-bindings/audiodelays/Echo.c \ shared-bindings/audiodelays/Chorus.c \ shared-bindings/audiodelays/PitchShift.c \ + shared-bindings/audiodelays/GranularPitchShift.c \ shared-bindings/audiodelays/MultiTapDelay.c \ shared-bindings/audiodelays/__init__.c \ shared-bindings/audiofilters/Distortion.c \ @@ -85,6 +86,7 @@ SRC_BITMAP := \ shared-module/audiodelays/Echo.c \ shared-module/audiodelays/Chorus.c \ shared-module/audiodelays/PitchShift.c \ + shared-module/audiodelays/GranularPitchShift.c \ shared-module/audiodelays/MultiTapDelay.c \ shared-module/audiodelays/__init__.c \ shared-module/audiofilters/Distortion.c \ From 986ff1d692f856d6f91134ee8b5189cc00bf20c9 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 13 Jul 2026 20:11:38 -0700 Subject: [PATCH 668/876] tools: add core1 flash-call checker for rp2 USB host builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On raspberrypi boards with USB host, core1 runs the PIO-USB frame loop behind an MPU region that makes flash inaccessible, so everything core1 reaches must be RAM-resident. The linker script places the entry points in RAM, but nothing verified their callees — which is how #10243 happened: an upstream TinyUSB change added a flash-resident call inside RAM-placed tuh_task_event_ready() and core1 died at first device attach. check_core1_flash_calls.py disassembles the linked ELF, walks the static call graph from core1_main (following linker veneers through their literal-pool targets), and fails if any reachable function lives in flash, printing the offending call chain. Run against current builds it catches the #10243 regression, the Pico-PIO-USB calc_usb_crc16 flash placement (hard-locks the board on any multi-packet OUT transfer, e.g. writing to a USB drive), and a latent flash call chain in the TinyUSB queue mutex contention path. Co-Authored-By: Claude Fable 5 --- tools/check_core1_flash_calls.py | 189 +++++++++++++++++++++++++++++++ 1 file changed, 189 insertions(+) create mode 100644 tools/check_core1_flash_calls.py diff --git a/tools/check_core1_flash_calls.py b/tools/check_core1_flash_calls.py new file mode 100644 index 00000000000..c1392c18538 --- /dev/null +++ b/tools/check_core1_flash_calls.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 +# This file is part of the CircuitPython project: https://circuitpython.org +# +# SPDX-FileCopyrightText: Copyright (c) 2026 Mikey Sklar +# +# SPDX-License-Identifier: MIT +"""Post-link check: core1-executed code must not reach into flash. + +On raspberrypi-port boards with USB host, core1 runs the PIO-USB frame loop +and may only execute (or read) RAM-resident code: core1_main enables an MPU +region that makes flash inaccessible (see common-hal/usb_host/Port.c), and the +linker script deliberately RAM-places tuh_task_event_ready() and the PIO-USB +code. Nothing verified their *callees* stay in RAM, which is how issue #10243 +happened: an upstream TinyUSB change added a flash-resident call inside +RAM-placed tuh_task_event_ready(), core1 faulted at the first device attach, +and USB host went silent. + +This tool disassembles the linked ELF, walks the static call graph from the +core1 entry points, and fails if any reachable function lives in flash. Linker +veneers (long-call trampolines) are followed through their literal-pool +targets, so a flash callee hidden behind a RAM veneer is still detected. + +Usage: + check_core1_flash_calls.py firmware.elf [--root SYMBOL]... [--allow SYMBOL]... + +Default root: core1_main. --allow skips a symbol (and everything only +reachable through it); use it for calls that provably run before the MPU is +enabled. + +Limitation: indirect calls (blx rN / function pointers) cannot be traced +statically. They are counted and reported per function so the gaps are +visible. +""" + +import argparse +import re +import subprocess +import sys +from collections import deque + +OBJDUMP = "arm-none-eabi-objdump" + +FLASH_LO, FLASH_HI = 0x10000000, 0x20000000 + +# Symbols that are reachable from a core1 root but are known to execute only +# before the MPU cuts off flash access. Keep this list short and commented. +DEFAULT_ALLOW = [ + # core1_main calls this while configuring SysTick, before enabling the MPU. + "common_hal_mcu_processor_get_frequency", +] + + +def in_flash(addr): + return FLASH_LO <= addr < FLASH_HI + + +def main(): + parser = argparse.ArgumentParser( + description="Check that core1-reachable code is RAM-resident." + ) + parser.add_argument("elf", help="linked firmware ELF") + parser.add_argument( + "--root", + action="append", + default=[], + help="core1 entry point symbol (default: core1_main)", + ) + parser.add_argument( + "--allow", + action="append", + default=[], + help="symbol to skip (e.g. runs before the MPU is enabled)", + ) + args = parser.parse_args() + roots = args.root or ["core1_main"] + allow = set(DEFAULT_ALLOW) | set(args.allow) + + dis = subprocess.run( + [OBJDUMP, "-d", args.elf], capture_output=True, text=True, check=True + ).stdout + + func_re = re.compile(r"^([0-9a-f]+) <([^>]+)>:$") + # e.g. "10001234: f7ff fffe bl 10005678 " + branch_re = re.compile( + r"^\s*[0-9a-f]+:\s+[0-9a-f ]+\t(bl|blx|b|b\.n|b\.w|" + r"b(?:eq|ne|cs|cc|mi|pl|vs|vc|hi|ls|ge|lt|gt|le)(?:\.n|\.w)?)" + r"\s+([0-9a-f]+)\s<([^>+]+)(\+0x[0-9a-f]+)?>" + ) + indirect_re = re.compile(r"^\s*[0-9a-f]+:\s+[0-9a-f ]+\tblx\s+(r\d+|ip|lr)\b") + # Veneer bodies jump through a literal pool word rather than a branch. + word_re = re.compile(r"^\s*[0-9a-f]+:\s+([0-9a-f]{8})\s+\.word\s") + + funcs = {} # name -> addr + edges = {} # name -> {target name} + veneer_words = {} # veneer name -> {literal addresses} + indirects = {} # name -> count of untraceable indirect calls + cur = None + for line in dis.splitlines(): + m = func_re.match(line) + if m: + cur = m.group(2) + funcs[cur] = int(m.group(1), 16) + edges.setdefault(cur, set()) + indirects.setdefault(cur, 0) + continue + if cur is None: + continue + if cur.endswith("_veneer"): + m = word_re.match(line) + if m: + veneer_words.setdefault(cur, set()).add(int(m.group(1), 16) & ~1) + continue + if indirect_re.match(line): + indirects[cur] += 1 + continue + m = branch_re.match(line) + if m: + target = m.group(3) + if target != cur: # ignore intra-function branches + edges[cur].add(target) + + # Resolve veneer literal addresses to function names. + addr_to_name = {} + for name, addr in funcs.items(): + addr_to_name.setdefault(addr, name) + for veneer, words in veneer_words.items(): + for w in words: + tgt = addr_to_name.get(w) + if tgt is not None: + edges.setdefault(veneer, set()).add(tgt) + + missing = [r for r in roots if r not in funcs] + if missing: + # A board without usb_host has no core1_main; nothing to check. + print(f"{args.elf}: root symbol(s) not present, skipping: {', '.join(missing)}") + return 0 + + # BFS from roots, remembering one call chain per function for reporting. + parent = {r: None for r in roots} + queue = deque(roots) + seen = set(roots) + violations = [] + indirect_notes = [] + while queue: + fn = queue.popleft() + if fn in allow: + continue + addr = funcs.get(fn) + if addr is not None and in_flash(addr): + violations.append(fn) + continue # don't walk further into flash + if indirects.get(fn): + indirect_notes.append((fn, indirects[fn])) + for tgt in sorted(edges.get(fn, ())): + if tgt not in seen and tgt in funcs: + seen.add(tgt) + parent[tgt] = fn + queue.append(tgt) + + def chain(fn): + parts = [] + while fn is not None: + parts.append(fn) + fn = parent[fn] + return " <- ".join(parts) + + print(f"{args.elf}: walked {len(seen)} functions from roots: {', '.join(roots)}") + if indirect_notes: + print( + f"note: {len(indirect_notes)} reachable function(s) make indirect " + f"calls that cannot be traced statically:" + ) + for fn, n in sorted(indirect_notes): + print(f" {fn} ({n} indirect call site(s))") + if violations: + print( + f"\nFAIL: {len(violations)} flash-resident function(s) reachable " + f"from core1:" + ) + for fn in sorted(violations): + print(f" {fn} @ {funcs[fn]:#010x}") + print(f" via: {chain(fn)}") + return 1 + print("PASS: no flash-resident code reachable from core1") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From b5bafa940ce5930ca834b1822eda0146420102b2 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 13 Jul 2026 23:03:59 -0700 Subject: [PATCH 669/876] ruff format Co-Authored-By: Claude Fable 5 --- tools/check_core1_flash_calls.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tools/check_core1_flash_calls.py b/tools/check_core1_flash_calls.py index c1392c18538..ef0b8b06031 100644 --- a/tools/check_core1_flash_calls.py +++ b/tools/check_core1_flash_calls.py @@ -173,10 +173,7 @@ def chain(fn): for fn, n in sorted(indirect_notes): print(f" {fn} ({n} indirect call site(s))") if violations: - print( - f"\nFAIL: {len(violations)} flash-resident function(s) reachable " - f"from core1:" - ) + print(f"\nFAIL: {len(violations)} flash-resident function(s) reachable from core1:") for fn in sorted(violations): print(f" {fn} @ {funcs[fn]:#010x}") print(f" via: {chain(fn)}") From b03cc853c9fc994fb4d6b458a68b135b99cf8f97 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 14 Jul 2026 13:19:11 -0700 Subject: [PATCH 670/876] raspberrypi: run core1 flash-call checker after linking USB host builds Fails the build with the offending call chain if any function reachable from core1 lives in flash. Adds about 2 seconds per board build. Co-Authored-By: Claude Fable 5 --- ports/raspberrypi/Makefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 6d9b557e0ba..b5c0fa3e50c 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -776,6 +776,10 @@ $(BUILD)/firmware.elf: $(OBJ) $(BOARD_LD) link-$(CHIP_VARIANT_LOWER).ld $(Q)echo $(OBJ) > $(BUILD)/firmware.objs $(Q)echo $(PICO_LDFLAGS) > $(BUILD)/firmware.ldflags $(Q)$(CC) -o $@ $(CFLAGS) @$(BUILD)/firmware.ldflags $(LINKER_SCRIPTS) -Wl,--print-memory-usage -Wl,-Map=$@.map -Wl,-cref -Wl,--gc-sections @$(BUILD)/firmware.objs -Wl,-lc +ifeq ($(CIRCUITPY_USB_HOST), 1) + $(STEPECHO) "CHECK core1 flash calls" + $(Q)$(PYTHON) $(TOP)/tools/check_core1_flash_calls.py $@ +endif endif $(BUILD)/firmware.bin: $(BUILD)/firmware.elf From ecddc2170588fe088c0d479944c511fc42272635 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 14 Jul 2026 17:16:02 -0700 Subject: [PATCH 671/876] checker: allow picodvi core1 pre-MPU startup calls The picodvi Framebuffer_RP2040 core1_main calls dvi_register_irqs_this_core and dvi_start before it enables the MPU that blocks flash access, like the usb_host core1_main does with common_hal_mcu_processor_get_frequency. Fixes the 10 RP2040 DVI board build failures. Co-Authored-By: Claude Fable 5 --- tools/check_core1_flash_calls.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/check_core1_flash_calls.py b/tools/check_core1_flash_calls.py index ef0b8b06031..add040bae15 100644 --- a/tools/check_core1_flash_calls.py +++ b/tools/check_core1_flash_calls.py @@ -45,8 +45,13 @@ # Symbols that are reachable from a core1 root but are known to execute only # before the MPU cuts off flash access. Keep this list short and commented. DEFAULT_ALLOW = [ - # core1_main calls this while configuring SysTick, before enabling the MPU. + # usb_host core1_main calls this while configuring SysTick, before + # enabling the MPU. "common_hal_mcu_processor_get_frequency", + # picodvi Framebuffer_RP2040 core1_main calls these during startup, + # before enabling the MPU. + "dvi_register_irqs_this_core", + "dvi_start", ] From 480b99450627367105d478a35882f29f6609c1e8 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 14 Jul 2026 19:11:41 -0400 Subject: [PATCH 672/876] add CIRCUITPY_BLE_WORKFLOW to settings.toml: default false; code cleanups; doc editing --- docs/environment.rst | 91 +++++++----- docs/workflows.md | 100 +++++++------ .../common-hal/microcontroller/Processor.c | 11 +- shared-bindings/supervisor/Runtime.c | 5 +- supervisor/shared/bluetooth/bluetooth.c | 135 +++++++++++------- supervisor/shared/safe_mode.c | 8 +- supervisor/shared/web_workflow/web_workflow.c | 10 +- 7 files changed, 210 insertions(+), 150 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index 2c72b4f1004..962a8fb8159 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -73,13 +73,19 @@ You can also include any other key/value pairs in the file for use with your own Keys that affect CircuitPython behavior ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -CIRCUITPY_BLE_NAME -~~~~~~~~~~~~~~~~~~ +CIRCUITPY_BLE_NAME (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~ If supplied, sets the BLE name the board advertises as, including for the BLE workflow. Otherwise, defaults to ``CIRCUITPYxxxx``, where ``xxxx`` varies per board. -CIRCUITPY_HEAP_START_SIZE -~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_BLE_WORKFLOW (boolean) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If ``true``, enables the BLE workflow. Defaults to ``false``. If ``false``, +changing ``supervisor.runtime.ble_workflow`` has no effect. + + +CIRCUITPY_HEAP_START_SIZE (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the initial size of the python heap, allocated from the outer heap. Must be a multiple of 4. The default is currently 8192. The python heap will grow by doubling and redoubling this initial size until it cannot fit in the outer heap. @@ -87,43 +93,44 @@ Larger values will reserve more RAM for python use and prevent the supervisor an from large allocations of their own. Smaller values will likely grow sooner than large start sizes. -CIRCUITPY_PYSTACK_SIZE -~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_PYSTACK_SIZE (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the size of the python stack. Must be a multiple of 4. The default value is currently 1536. Increasing the stack reduces the size of the heap available to python code. Used to avoid "Pystack exhausted" errors when the code can't be reworked to avoid it. -CIRCUITPY_WEB_API_PASSWORD -~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_WEB_API_PASSWORD (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Password required to make modifications to the board from the Web Workflow. If the password is not specified, the Web Workflow is not enabled. -CIRCUITPY_WEB_API_PORT -~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_WEB_API_PORT (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ TCP port number used for the Web Workflow HTTP API. Defaults to 80 when omitted. -CIRCUITPY_WEB_INSTANCE_NAME -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_WEB_INSTANCE_NAME (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Human-friendly name the board advertises over mDNS for the Web Workflow. Defaults to the human-readable board name if omitted. This is not the hostname. -CIRCUITPY_WIFI_SSID -~~~~~~~~~~~~~~~~~~~ -CIRCUITPY_WIFI_PASSWORD -~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_WIFI_SSID (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CIRCUITPY_WIFI_PASSWORD (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If these values are supplied, connects automatically to a local WiFi network with the specified SSID and password before ``boot.py`` and/or ``code.py`` are run. -CIRCUITPY_WIFI_HOSTNAME -~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_WIFI_HOSTNAME (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If supplied, sets the initial ``wifi.radio.hostname`` to the given value. Otherwise, the default value is ``cpy--``, with some shortening for length if necessary. If the supplied value is an invalid hostname or is too long, it is ignored. -CIRCUITPY_SDCARD_USB -^^^^^^^^^^^^^^^^^^^^ +CIRCUITPY_SDCARD_USB (boolean) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Present a mounted SD card as a USB MSC device. If the board has default pins for an SD card socket, the card is mounted automatically on startup. Only one card can be presented. @@ -135,8 +142,10 @@ so set this to ``false`` if you don't need this feature. Additional board-specific keys ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -CIRCUITPY_DISPLAY_WIDTH (Sunton, MaTouch) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_DISPLAY_WIDTH (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(Sunton, MaTouch boards) + Selects the correct screen resolution (1024x600 or 800x640) for the particular board variant. If the CIRCUITPY_DISPLAY_WIDTH parameter is set to a value of 1024 the display is initialized during power up at 1024x600 otherwise the display will be initialized at a resolution @@ -146,8 +155,8 @@ of 800x480. `Sunton ESP32-2432S028 `_ `Sunton ESP32-2432S024C `_ -CIRCUITPY_DISPLAY_ROTATION -~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_DISPLAY_ROTATION (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Selects the correct screen rotation (0, 90, 180 or 270) for the particular board variant. If the CIRCUITPY_DISPLAY_ROTATION parameter is set the display will be initialized during power up with the selected rotation, otherwise the display will be initialized with @@ -158,8 +167,8 @@ a rotation of 0. Attempting to initialize the screen with a rotation other than `Adafruit Feather RP2350 `_ `Adafruit Metro RP2350 `_ -CIRCUITPY_DISPLAY_FREQUENCY -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_DISPLAY_FREQUENCY (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Allows the entry of a display frequency used during the "dotclock" framebuffer construction. If a valid frequency is not defined the board will initialize the framebuffer with a frequency of 12500000hz (12.5Mhz). The value should be entered as an integer in hertz @@ -169,8 +178,8 @@ display frequency. `Sunton ESP32-8048S050 `_ -CIRCUITPY_PICODVI_ENABLE -~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_PICODVI_ENABLE (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Whether to configure the display at board initialization time, one of the following: .. code-block:: @@ -186,8 +195,16 @@ until it is released by ``displayio.release_displays()``. It does not appear at `Adafruit Feather RP2350 `_ `Adafruit Metro RP2350 `_ -CIRCUITPY_DISPLAY_WIDTH, CIRCUITPY_DISPLAY_HEIGHT, and CIRCUITPY_DISPLAY_COLOR_DEPTH (RP2350 boards with DVI or HSTX connector) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_DISPLAY_WIDTH (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CIRCUITPY_DISPLAY_HEIGHT (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +CIRCUITPY_DISPLAY_COLOR_DEPTH (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(RP2350 boards with DVI or HSTX connector) + Selects the desired resolution and color depth. Supported resolutions are: @@ -213,15 +230,15 @@ Example: Configure the display to 640x480 black and white (1 bit per pixel): `Adafruit Feather RP2350 `_ `Adafruit Metro RP2350 `_ -CIRCUITPY_SAFEMODE_DELAY -~~~~~~~~~~~~~~~~~~~~~~~~ -Wait for the specified amount of time, in seconds (as a float), for the user to press the reset button +CIRCUITPY_SAFEMODE_DELAY (float) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Wait for the specified amount of time, in seconds, for the user to press the reset button to initiate safe mode after a hard reset. The status LED blinks during this time. If not specified, use the default delay, which is one second. -CIRCUITPY_TERMINAL_SCALE -~~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_TERMINAL_SCALE (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Allows the entry of a display scaling factor used during the terminalio console construction. The entered scaling factor only affects the terminalio console and has no impact on the UART, Web Workflow, BLE Workflow, etc consoles. @@ -230,8 +247,8 @@ This feature is not enabled on boards that the CIRCUITPY_SETTINGS_TOML (or CIRCU flag has been set to 0. Currently this is primarily boards with limited flash including some of the Atmel_samd boards based on the SAMD21/M0 microprocessor. -CIRCUITPY_TERMINAL_FONT -~~~~~~~~~~~~~~~~~~~~~~~ +CIRCUITPY_TERMINAL_FONT (string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Specifies a custom font file path to use for the terminalio console instead of the default ``/fonts/terminal.lvfontbin``. This allows users to create and use custom fonts for the CircuitPython console. diff --git a/docs/workflows.md b/docs/workflows.md index 84d7530e2fe..074818903ba 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -4,11 +4,11 @@ Workflows are the process used to 1) manipulate files on the CircuitPython devic with the serial connection to CircuitPython. The serial connection is usually used to access the REPL. -Starting with CircuitPython 3.x we moved to a USB-only workflow. Prior to that, we used the serial -connection alone to do the whole workflow. In CircuitPython 7.x, a BLE workflow was added with the -advantage of working with mobile devices. CircuitPython 8.x added a web workflow that works over the -local network (usually Wi-Fi) and a web browser. Other clients can also use the Web REST API. Boards -should clearly document which workflows are supported. +CircuitPython started with a USB mass storage device workflow for filesystem operations. +CircuitPython 7.x added a BLE workflow with the advantage of working with mobile devices. +CircuitPython 8.x added a web workflow that works over the +local network (usually Wi-Fi) and a web browser. +Other clients can also use the Web REST API. Boards should clearly document which workflows are supported. Code for workflows lives in `supervisor/shared`. @@ -21,7 +21,7 @@ device has been plugged into a host. ### Mass Storage CircuitPython exposes a standard mass storage (MSC) interface to enable file manipulation over a -standard interface. (This is how USB drives work.) This interface works underneath the file system at +standard interface. The board appears as a USB drive. This interface works underneath the file system at the block level so using it excludes other types of workflows from manipulating the file system at the same time. @@ -29,55 +29,69 @@ CircuitPython 10.x adds multiple Logical Units (LUNs) to the mass storage interf multiple drives to be accessed and ejected independently. #### CIRCUITPY drive -The CIRCUITPY drive is the main drive that CircuitPython uses. It is writable by the host by default +The CIRCUITPY drive is the main drive that CircuitPython presents. It is writable by the host by default and read-only to CircuitPython. `storage.remount()` can be used to remount the drive to CircuitPython as read-write. #### CPSAVES drive -The board may also expose a CPSAVES drive. (This is based on the ``CIRCUITPY_SAVES_PARTITION_SIZE`` -setting in ``mpconfigboard.h``.) It is a portion of the main flash that is writable by CircuitPython -by default. It is read-only to the host. `storage.remount()` can be used to remount the drive to the -host as read-write. +The board may also expose a CPSAVES drive. (This is based on the `CIRCUITPY_SAVES_PARTITION_SIZE` +setting in `mpconfigboard.h`.) It is a portion of the main flash that is writable by CircuitPython +by default. The CPSAVES drive becomes visible to the attached host computer after a few seconds. +By default it is read-only to the host, but `storage.remount()` can be used to remount the drive +as read-write to the host #### SD card drive -A few boards have SD card automounting. (This is based on the ``DEFAULT_SD`` settings in -``mpconfigboard.h``.) The card is writable from CircuitPython by default and read-only to the host. +A few boards auomatically mount an SD card, if present, to the `/sd` mount point. +Boards that do this have `DEFAULT_SD` settings in`mpconfigboard.h` which allow detecting the +presence of an SD card, and fixed pin settings for the SD card socket. +The mounted SD card is writable from CircuitPython by default and read-only to the host. `storage.remount()` can be used to remount the drive to the host as read-write. -On most other boards, except for ``atmel-samd`` boards, an SD card mounted in user code -at ``/sd`` will become visible after a few seconds on the attached host computer, as an -additional drive besides CIRCUITPY and (if present) CPSAVES. It will present with the volume -label on the SD card. Depending on the host operating system settings, the drive may or may not be -auto-mounted on the host. Host writes to drives mounted by user code will not trigger a reload. +If `CIRCUITPY_SDCARD_USB` in settings.toml is `true` (the default), +an SD card mounted in user code at `/sd` will become visible on the attached host computer +after a few seconds, as an additional drive besides CIRCUITPY and (if present) CPSAVES. +It will present with the volume label on the SD card. +Depending on the host operating system settings, the drive may or may not be +auto-mounted on the host. +Host writes to drives mounted by user code will not trigger a reload. ### CDC serial -CircuitPython exposes one CDC USB interface for CircuitPython serial. This is a standard serial -USB interface. +CircuitPython exposes a standard serial CDC USB interface for the CircuitPython REPL. +Setting the CDC's baudrate 1200 and disconnecting will reboot the board into a bootloader. +This technique was first used by Arduino boards and the Arduino IDE to trigger a reset into bootloader. -TODO: Document how it designates itself from the user CDC. +A second CDC interface is optionally available for binary data transfer (see `usb_cdc`). -Setting baudrate 1200 and disconnecting will reboot into a bootloader. (Used by Arduino to trigger -a reset into bootloader.) ## BLE -The BLE workflow is enabled for Nordic boards. By default, to prevent malicious access, it is disabled. -To connect to the BLE workflow, press the reset button while the status led blinks blue quickly -after the safe mode blinks. The board will restart and broadcast the file transfer service UUID -(`0xfebb`) along with the board's [Creation IDs](https://github.com/creationid/creators). This -public broadcast is done at a lower transmit level so the devices must be closer. On connection, the -device will need to pair and bond. Once bonded, the device will broadcast whenever disconnected -using a rotating key rather than a static one. Non-bonded devices won't be able to resolve it. After -connection, the central device can discover two default services. One for file transfer and one for -CircuitPython specifically that includes serial characteristics. +The BLE workflow can be enabled for BLE-capable boards by setting `CIRCUITPY_BLE_WORKFLOW=true` +in `settings.toml`. The default is `false`. +This `settings.toml` key and the default of `false` is new in 10.3.0; +previously BLE workflow was available by default. + +To prevent malicious access, even if `CIRCUITPY_BLE_WORKFLOW=true`, +the user must initiate a bonded connection with the host. +To bond, press the reset button when the status led blinks blue quickly after reset, +after the safe mode blinks. +The board will restart and advertise the file transfer service UUID (`0xfebb`) +along with the board's [Creation ID](https://github.com/creationid/creators). +This public advertisement is done at a lower transmit level so the devices must be closer. +On connection, the device will need to pair and bond. +Once bonded, the device will advertise whenever disconnected, +using a rotating key rather than a static one. +Non-bonded devices won't be able to resolve it. + +After connection, will discover two default services: one is for file transfer and +the other provides version information and a serial connection to the CircuitPython REPL. To change the default BLE advertising name without (or before) running user code, the desired name -can be put in the `settings.toml` file. The key is `CIRCUITPY_BLE_NAME`. It's limited to approximately -30 characters depending on the port's settings and will be truncated if longer. +can be put in the `settings.toml` using the `CIRCUITPY_BLE_NAME` key. The name is limited to approximately +30 characters, depending on the port, and will be truncated if longer. ### File Transfer API -CircuitPython uses [an open File Transfer API](https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer) +The file transfer service provides [an open File Transfer API](https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer) to enable file system access. ### CircuitPython Service @@ -87,22 +101,22 @@ replaced by the four specific digits below. The service itself is `0001`. #### TX - `0002` / RX - `0003` -These characteristic work just like the Nordic Uart Service (NUS) but have different UUIDs to prevent -conflicts with user created NUS services. +The TX and RX characteristics for the CircuitPython service work just like the Nordic Uart Service (NUS) +but have different UUIDs to prevent conflicts with user-created NUS services. #### Version - `0100` -Read-only characteristic that returns the UTF-8 encoded version string. +The Version characteristic is read-only and returns the UTF-8 encoded version string. ## Web If the keys `CIRCUITPY_WIFI_SSID` and `CIRCUITPY_WIFI_PASSWORD` are set in `settings.toml`, CircuitPython will automatically connect to the given Wi-Fi network on boot and upon reload. -If `CIRCUITPY_WEB_API_PASSWORD` is set, MDNS and the http server for the web workflow will also start. +If `CIRCUITPY_WEB_API_PASSWORD` is set, MDNS and the HTTP server for the web workflow will also start. -The webserver is on port 80 unless overridden by `CIRCUITPY_WEB_API_PORT`. It also enables MDNS. +The webserver is on port 80 unless overridden by `CIRCUITPY_WEB_API_PORT`. It also enables mDNS. The name of the board as advertised to the network can be overridden by `CIRCUITPY_WEB_INSTANCE_NAME`. -Here is an example `/settings.toml`: +Here is an example `settings.toml`: ```bash # To auto-connect to Wi-Fi @@ -249,7 +263,7 @@ curl -v -u :passw0rd -X PUT -L --location-trusted http://circuitpython.local/fs/ ``` ##### Move -Moves the directory at the given path to ``X-Destination``. Also known as rename. +Moves the directory at the given path to `X-Destination`. Also known as rename. The custom `X-Destination` header stores the destination path of the directory. @@ -335,7 +349,7 @@ curl -v -u :passw0rd -L --location-trusted http://circuitpython.local/fs/lib/hel ##### Move -Moves the file at the given path to the ``X-Destination``. Also known as rename. +Moves the file at the given path to the `X-Destination`. Also known as rename. The custom `X-Destination` header stores the destination path of the file. diff --git a/ports/espressif/common-hal/microcontroller/Processor.c b/ports/espressif/common-hal/microcontroller/Processor.c index 6ee196699a0..72c9845241c 100644 --- a/ports/espressif/common-hal/microcontroller/Processor.c +++ b/ports/espressif/common-hal/microcontroller/Processor.c @@ -185,11 +185,12 @@ mcu_reset_reason_t common_hal_mcu_processor_get_reset_reason(void) { case ESP_RST_DEEPSLEEP: { uint32_t wakeup_causes = esp_sleep_get_wakeup_causes(); - uint32_t alarm_causes = (1 << ESP_SLEEP_WAKEUP_TIMER) | - (1 << ESP_SLEEP_WAKEUP_EXT0) | - (1 << ESP_SLEEP_WAKEUP_EXT1) | - (1 << ESP_SLEEP_WAKEUP_TOUCHPAD) | - (1 << ESP_SLEEP_WAKEUP_ULP); + uint32_t alarm_causes = + BIT(ESP_SLEEP_WAKEUP_TIMER) | + BIT(ESP_SLEEP_WAKEUP_EXT0) | + BIT(ESP_SLEEP_WAKEUP_EXT1) | + BIT(ESP_SLEEP_WAKEUP_TOUCHPAD) | + BIT(ESP_SLEEP_WAKEUP_ULP); if (wakeup_causes & alarm_causes) { return MCU_RESET_REASON_DEEP_SLEEP_ALARM; } diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index 20cfd2e8200..8abcb8b0831 100644 --- a/shared-bindings/supervisor/Runtime.c +++ b/shared-bindings/supervisor/Runtime.c @@ -153,7 +153,10 @@ MP_PROPERTY_GETSET(supervisor_runtime_autoreload_obj, //| ble_workflow: bool //| """Enable/Disable ble workflow until a reset. This prevents BLE advertising outside of the VM and -//| the services used for it.""" +//| the services used for it. +//| If ``CIRCUITPY_BLE_WORKFLOW=false`` is present in ``settings.toml``, setting `ble_workflow` +//| to ``True`` has no effect. +//| """ //| static mp_obj_t supervisor_runtime_get_ble_workflow(mp_obj_t self) { #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_SERIAL_BLE diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 44291d6d749..17a9d9f4602 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -18,6 +18,7 @@ #include "supervisor/port.h" #include "supervisor/shared/serial.h" +#include "supervisor/shared/settings.h" #include "supervisor/shared/status_leds.h" #include "supervisor/shared/tick.h" #include "supervisor/shared/translate/translate.h" @@ -42,25 +43,27 @@ // This standard advertisement advertises the CircuitPython editing service and a CIRCUITPY short name. -const uint8_t public_advertising_data[] = { 0x02, 0x01, 0x06, // 0-2 Flags - 0x02, 0x0a, 0xec, // 3-5 TX power level -20 - #if CIRCUITPY_BLE_FILE_SERVICE - 0x03, 0x02, 0xbb, 0xfe, // 6 - 9 Incomplete service list (File Transfer service) - #endif - 0x0e, 0xff, 0x22, 0x08, // 10 - 13 Adafruit Manufacturer Data - 0x0a, 0x04, 0x00, // 14 - 16 Creator ID / Creation ID - CIRCUITPY_CREATOR_ID & 0xff, // 17 - 20 Creator ID - (CIRCUITPY_CREATOR_ID >> 8) & 0xff, - (CIRCUITPY_CREATOR_ID >> 16) & 0xff, - (CIRCUITPY_CREATOR_ID >> 24) & 0xff, - CIRCUITPY_CREATION_ID & 0xff, // 21 - 24 Creation ID - (CIRCUITPY_CREATION_ID >> 8) & 0xff, - (CIRCUITPY_CREATION_ID >> 16) & 0xff, - (CIRCUITPY_CREATION_ID >> 24) & 0xff, - 0x05, 0x08, 0x43, 0x49, 0x52, 0x43 // 25 - 31 - Short name +const uint8_t public_advertising_data[] = { + 0x02, 0x01, 0x06, // 0-2 Flags + 0x02, 0x0a, 0xec, // 3-5 TX power level -20 + #if CIRCUITPY_BLE_FILE_SERVICE + 0x03, 0x02, 0xbb, 0xfe, // 6 - 9 Incomplete service list (File Transfer service) + #endif + 0x0e, 0xff, 0x22, 0x08, // 10 - 13 Adafruit Manufacturer Data + 0x0a, 0x04, 0x00, // 14 - 16 Creator ID / Creation ID + CIRCUITPY_CREATOR_ID & 0xff, // 17 - 20 Creator ID + (CIRCUITPY_CREATOR_ID >> 8) & 0xff, + (CIRCUITPY_CREATOR_ID >> 16) & 0xff, + (CIRCUITPY_CREATOR_ID >> 24) & 0xff, + CIRCUITPY_CREATION_ID & 0xff, // 21 - 24 Creation ID + (CIRCUITPY_CREATION_ID >> 8) & 0xff, + (CIRCUITPY_CREATION_ID >> 16) & 0xff, + (CIRCUITPY_CREATION_ID >> 24) & 0xff, + 0x05, 0x08, 0x43, 0x49, 0x52, 0x43 // 25 - 31 - Short name }; -const uint8_t private_advertising_data[] = { 0x02, 0x01, 0x06, // 0-2 Flags - 0x02, 0x0a, 0x00 // 3-5 TX power level 0 +const uint8_t private_advertising_data[] = { + 0x02, 0x01, 0x06, // 0-2 Flags + 0x02, 0x0a, 0x00 // 3-5 TX power level 0 }; // This scan response advertises the full device name (if it fits.) uint8_t circuitpython_scan_response_data[31]; @@ -75,6 +78,11 @@ static bool ble_started = false; #define WORKFLOW_ENABLED 1 #define WORKFLOW_DISABLED 2 +// Value of CIRCUITPY_BLE_WORKFLOW in settings.toml. Defaults to false. +static bool ble_workflow_setting = false; + +// Has BLE workflow been enabled, because it was allow and we've bonded to the workflow host? +// Also controlled by supervisor.runtime.ble_workflow. static uint8_t workflow_state = WORKFLOW_UNSET; static bool was_connected = false; @@ -180,6 +188,14 @@ static void supervisor_bluetooth_start_advertising(void) { void supervisor_bluetooth_init(void) { #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + + // Check if the user enabled BLE workflow in settings.toml. The default is that it's off. + ble_workflow_setting = false; + settings_get_bool("CIRCUITPY_BLE_WORKFLOW", &ble_workflow_setting); + if (!ble_workflow_setting) { + return; + } + uint32_t reset_state = port_get_saved_word(); uint32_t ble_mode = 0; if ((reset_state & BLE_DISCOVERY_DATA_GUARD_MASK) == BLE_DISCOVERY_DATA_GUARD) { @@ -187,15 +203,17 @@ void supervisor_bluetooth_init(void) { } const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); boot_in_discovery_mode = false; - if (reset_reason != MCU_RESET_REASON_POWER_ON && - reset_reason != MCU_RESET_REASON_RESET_PIN && - reset_reason != MCU_RESET_REASON_DEEP_SLEEP_ALARM && - reset_reason != MCU_RESET_REASON_UNKNOWN && - reset_reason != MCU_RESET_REASON_SOFTWARE) { + + // These are error resets reflecting a problem and should not initiate discovery mode. + if (reset_reason == MCU_RESET_REASON_BROWNOUT || + reset_reason == MCU_RESET_REASON_WATCHDOG || + reset_reason == MCU_RESET_REASON_RESCUE_DEBUG) { return; } + // Same as what is done by `import _bleio`. common_hal_bleio_init(); + if (ble_mode == 0) { port_set_saved_word(BLE_DISCOVERY_DATA_GUARD | (0x01 << 8)); } @@ -211,40 +229,49 @@ void supervisor_bluetooth_init(void) { reset_state = 0x0; } bool bonded = common_hal_bleio_adapter_is_bonded_to_central(&common_hal_bleio_adapter_obj); - #if !CIRCUITPY_USB_DEVICE - // Boot into discovery if USB isn't available and we aren't bonded already. - // Checking here allows us to have the status LED solidly on even if no button was - // pressed. - bool wifi_workflow_active = false; - #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML - char _api_password[64]; - const size_t api_password_len = sizeof(_api_password) - 1; - settings_err_t result = settings_get_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); - wifi_workflow_active = result == SETTINGS_OK; - #endif - if (!bonded && !wifi_workflow_active) { - boot_in_discovery_mode = true; - } - #endif - while (diff < 1000) { - #if CIRCUITPY_STATUS_LED - // Blink on for 50 and off for 100 - bool led_on = boot_in_discovery_mode || (diff % 150) <= 50; - if (led_on) { - new_status_color(0x0000ff); - } else { - new_status_color(BLACK); - } + + // Don't go into discovery mode when waking from deep sleep. But if we're already bonded, + // BLE workflow can continue after deep sleep. + if (reset_reason != MCU_RESET_REASON_DEEP_SLEEP_ALARM) { + #if !CIRCUITPY_USB_DEVICE + // Boot into discovery if USB isn't available and we aren't bonded already. + // Checking here allows us to have the status LED solidly on even if no button was + // pressed. + + bool wifi_workflow_active = false; + #if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML + char _api_password[64]; + const size_t api_password_len = sizeof(_api_password) - 1; + settings_err_t result = settings_get_str("CIRCUITPY_WEB_API_PASSWORD", _api_password + 1, api_password_len); + wifi_workflow_active = result == SETTINGS_OK; #endif - if (port_boot_button_pressed()) { + + if (!bonded && !wifi_workflow_active) { boot_in_discovery_mode = true; - break; } - diff = supervisor_ticks_ms64() - start_ticks; - } - if (boot_in_discovery_mode) { - common_hal_bleio_adapter_erase_bonding(&common_hal_bleio_adapter_obj); + #endif // !CIRCUITPY_USB_DEVICE + + while (diff < 1000) { + #if CIRCUITPY_STATUS_LED + // Blink on for 50 and off for 100 + bool led_on = boot_in_discovery_mode || (diff % 150) <= 50; + if (led_on) { + new_status_color(0x0000ff); + } else { + new_status_color(BLACK); + } + #endif + if (port_boot_button_pressed()) { + boot_in_discovery_mode = true; + break; + } + diff = supervisor_ticks_ms64() - start_ticks; + } + if (boot_in_discovery_mode) { + common_hal_bleio_adapter_erase_bonding(&common_hal_bleio_adapter_obj); + } } + if (boot_in_discovery_mode || bonded) { workflow_state = WORKFLOW_ENABLED; } else { @@ -342,7 +369,7 @@ void supervisor_stop_bluetooth(void) { void supervisor_bluetooth_enable_workflow(void) { #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE - if (workflow_state == WORKFLOW_DISABLED) { + if (!ble_workflow_setting || workflow_state == WORKFLOW_DISABLED) { return; } workflow_state = WORKFLOW_ENABLED; diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index 0031482ec98..fade06db596 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -54,10 +54,10 @@ safe_mode_t wait_for_safe_mode_reset(void) { } const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); - if (reset_reason != MCU_RESET_REASON_POWER_ON && - reset_reason != MCU_RESET_REASON_RESET_PIN && - reset_reason != MCU_RESET_REASON_UNKNOWN && - reset_reason != MCU_RESET_REASON_SOFTWARE) { + // Skip safe-mode wait if the reset reason was due to a problem. + if (reset_reason == MCU_RESET_REASON_BROWNOUT || + reset_reason == MCU_RESET_REASON_WATCHDOG || + reset_reason == MCU_RESET_REASON_RESCUE_DEBUG) { return SAFE_MODE_NONE; } #if CIRCUITPY_SKIP_SAFE_MODE_WAIT diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index 66b7424b06f..278823676ef 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -337,13 +337,11 @@ bool supervisor_start_web_workflow(void) { } #endif - // Skip starting the workflow if we're not starting from power on or reset. + // Skip starting the workflow if the reset reason reflects a problem. const mcu_reset_reason_t reset_reason = common_hal_mcu_processor_get_reset_reason(); - if (reset_reason != MCU_RESET_REASON_POWER_ON && - reset_reason != MCU_RESET_REASON_RESET_PIN && - reset_reason != MCU_RESET_REASON_DEEP_SLEEP_ALARM && - reset_reason != MCU_RESET_REASON_UNKNOWN && - reset_reason != MCU_RESET_REASON_SOFTWARE) { + if (reset_reason == MCU_RESET_REASON_BROWNOUT || + reset_reason == MCU_RESET_REASON_WATCHDOG || + reset_reason == MCU_RESET_REASON_RESCUE_DEBUG) { return false; } From ddff85fb7a8fa9ecc51c8a1b448e65c1d0d945e8 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 15 Jul 2026 08:37:40 -0500 Subject: [PATCH 673/876] disable bitmaptools on archi --- ports/raspberrypi/boards/archi/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/boards/archi/mpconfigboard.mk b/ports/raspberrypi/boards/archi/mpconfigboard.mk index 1189e6879b9..9281e371348 100644 --- a/ports/raspberrypi/boards/archi/mpconfigboard.mk +++ b/ports/raspberrypi/boards/archi/mpconfigboard.mk @@ -10,6 +10,7 @@ EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_PICODVI = 1 +CIRCUITPY_BITMAPTOOLS = 0 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_MPU6050 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Pixel_Framebuf From 8c8f28195c4f11cf61179e7e373443e4215c9c73 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 15 Jul 2026 09:41:45 -0500 Subject: [PATCH 674/876] 02 optimization flag for archi --- ports/raspberrypi/boards/archi/mpconfigboard.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/archi/mpconfigboard.mk b/ports/raspberrypi/boards/archi/mpconfigboard.mk index 9281e371348..faf9833da62 100644 --- a/ports/raspberrypi/boards/archi/mpconfigboard.mk +++ b/ports/raspberrypi/boards/archi/mpconfigboard.mk @@ -10,7 +10,6 @@ EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ" CIRCUITPY__EVE = 1 CIRCUITPY_PICODVI = 1 -CIRCUITPY_BITMAPTOOLS = 0 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_MPU6050 FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Pixel_Framebuf @@ -21,3 +20,5 @@ FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_seesaw FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_framebuf FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SimpleIO + +OPTIMIZATION_FLAGS = -O2 From c8b26f701acd97183cf955f6d9f6616209a2db71 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 15 Jul 2026 11:06:38 -0400 Subject: [PATCH 675/876] Turn on settings.toml for nRF52833; rename CIRCUITPY_SERIAL_BLE to CIRCUITPY_BLE_SERIAL_SERVICE --- .../espressif/common-hal/_bleio/ble_events.c | 6 ++-- ports/espressif/mpconfigport.mk | 2 +- ports/nordic/bluetooth/ble_drv.c | 6 ++-- ports/nordic/mpconfigport.mk | 8 ++--- py/circuitpy_mpconfig.mk | 4 +-- shared-bindings/supervisor/Runtime.c | 4 +-- supervisor/shared/bluetooth/bluetooth.c | 32 +++++++++++-------- supervisor/shared/serial.c | 10 +++--- supervisor/shared/status_bar.c | 6 ++-- supervisor/shared/workflow.c | 4 +-- supervisor/supervisor.mk | 2 +- 11 files changed, 44 insertions(+), 40 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/ble_events.c b/ports/espressif/common-hal/_bleio/ble_events.c index 5b9eb649c97..b57362fe007 100644 --- a/ports/espressif/common-hal/_bleio/ble_events.c +++ b/ports/espressif/common-hal/_bleio/ble_events.c @@ -16,7 +16,7 @@ #include "py/mpstate.h" #include "py/runtime.h" -#if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE #include "supervisor/shared/bluetooth/serial.h" #endif @@ -85,7 +85,7 @@ void ble_event_remove_handler(ble_gap_event_fn *func, void *param) { } int ble_event_run_handlers(struct ble_gap_event *event) { - #if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE ble_serial_disable(); #endif @@ -101,7 +101,7 @@ int ble_event_run_handlers(struct ble_gap_event *event) { done = it->func(event, it->param) || done; it = next; } - #if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE ble_serial_enable(); #endif return 0; diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 0b027333b97..cb95b573cc2 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -395,7 +395,7 @@ CIRCUITPY_JPEGIO ?= $(CIRCUITPY_DISPLAYIO) CIRCUITPY_QRIO ?= $(CIRCUITPY_ESPCAMERA) CIRCUITPY_BLE_FILE_SERVICE ?= $(CIRCUITPY_BLEIO_NATIVE) -CIRCUITPY_SERIAL_BLE ?= $(CIRCUITPY_BLEIO_NATIVE) +CIRCUITPY_BLE_SERIAL_SERVICE ?= $(CIRCUITPY_BLEIO_NATIVE) # Features dependent on other features ifneq ($(CIRCUITPY_USB_DEVICE),0) diff --git a/ports/nordic/bluetooth/ble_drv.c b/ports/nordic/bluetooth/ble_drv.c index 35d577f117c..7085aa477b5 100644 --- a/ports/nordic/bluetooth/ble_drv.c +++ b/ports/nordic/bluetooth/ble_drv.c @@ -20,7 +20,7 @@ #include "py/mpstate.h" #include "mpconfigport.h" -#if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE #include "supervisor/shared/bluetooth/serial.h" #endif @@ -229,7 +229,7 @@ void SD_EVT_IRQHandler(void) { } } - #if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE ble_serial_disable(); #endif while (1) { @@ -270,7 +270,7 @@ void SD_EVT_IRQHandler(void) { } #endif } - #if CIRCUITPY_SERIAL_BLE && CIRCUITPY_VERBOSE_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE && CIRCUITPY_VERBOSE_BLE ble_serial_enable(); #endif } diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index 0316e904b38..028ceca9fcd 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -41,6 +41,8 @@ CIRCUITPY_I2CTARGET = 0 CIRCUITPY_RTC ?= 1 +CIRCUITPY_SETTINGS_TOML ?= 1 + # frequencyio not yet implemented CIRCUITPY_FREQUENCYIO = 0 @@ -49,11 +51,9 @@ CIRCUITPY_ROTARYIO_SOFTENCODER = 1 # Sleep and Wakeup CIRCUITPY_ALARM ?= 1 -# Turn on the BLE file service +# Turn on the BLE file and serial services for BLE workflow CIRCUITPY_BLE_FILE_SERVICE ?= 1 - -# Turn on the BLE serial service -CIRCUITPY_SERIAL_BLE ?= 1 +CIRCUITPY_BLE_SERIAL_SERVICE ?= 1 CIRCUITPY_COMPUTED_GOTO_SAVE_SPACE ?= 1 diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index ed0f5e5f1f2..9f9fd4856d1 100644 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -544,8 +544,8 @@ CFLAGS += -DCIRCUITPY_SDCARDIO=$(CIRCUITPY_SDCARDIO) CIRCUITPY_SDIOIO ?= 0 CFLAGS += -DCIRCUITPY_SDIOIO=$(CIRCUITPY_SDIOIO) -CIRCUITPY_SERIAL_BLE ?= 0 -CFLAGS += -DCIRCUITPY_SERIAL_BLE=$(CIRCUITPY_SERIAL_BLE) +CIRCUITPY_BLE_SERIAL_SERVICE ?= 0 +CFLAGS += -DCIRCUITPY_BLE_SERIAL_SERVICE=$(CIRCUITPY_BLE_SERIAL_SERVICE) CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY?= 0 CFLAGS += -DCIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY=$(CIRCUITPY_SETTABLE_PROCESSOR_FREQUENCY) diff --git a/shared-bindings/supervisor/Runtime.c b/shared-bindings/supervisor/Runtime.c index 8abcb8b0831..5b2885f26c0 100644 --- a/shared-bindings/supervisor/Runtime.c +++ b/shared-bindings/supervisor/Runtime.c @@ -159,7 +159,7 @@ MP_PROPERTY_GETSET(supervisor_runtime_autoreload_obj, //| """ //| static mp_obj_t supervisor_runtime_get_ble_workflow(mp_obj_t self) { - #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_BLE_SERIAL_SERVICE return mp_obj_new_bool(supervisor_bluetooth_workflow_is_enabled()); #else return mp_const_false; @@ -168,7 +168,7 @@ static mp_obj_t supervisor_runtime_get_ble_workflow(mp_obj_t self) { MP_DEFINE_CONST_FUN_OBJ_1(supervisor_runtime_get_ble_workflow_obj, supervisor_runtime_get_ble_workflow); static mp_obj_t supervisor_runtime_set_ble_workflow(mp_obj_t self, mp_obj_t state_in) { - #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE && CIRCUITPY_BLE_SERIAL_SERVICE if (mp_obj_is_true(state_in)) { supervisor_bluetooth_enable_workflow(); } else { diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 17a9d9f4602..19b84aca4ab 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -18,7 +18,6 @@ #include "supervisor/port.h" #include "supervisor/shared/serial.h" -#include "supervisor/shared/settings.h" #include "supervisor/shared/status_leds.h" #include "supervisor/shared/tick.h" #include "supervisor/shared/translate/translate.h" @@ -29,7 +28,7 @@ #include "supervisor/shared/bluetooth/file_transfer.h" #endif -#if CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE #include "supervisor/shared/bluetooth/serial.h" #endif @@ -37,7 +36,7 @@ #include "supervisor/shared/status_bar.h" #endif -#if CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI && CIRCUITPY_SETTINGS_TOML +#if (CIRCUITPY_BLE_FILE_SERVICE || (CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI)) && CIRCUITPY_SETTINGS_TOML #include "supervisor/shared/settings.h" #endif @@ -68,7 +67,7 @@ const uint8_t private_advertising_data[] = { // This scan response advertises the full device name (if it fits.) uint8_t circuitpython_scan_response_data[31]; -#if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE static bool boot_in_discovery_mode = false; static bool advertising = false; static bool _private_advertising = false; @@ -181,20 +180,25 @@ static void supervisor_bluetooth_start_advertising(void) { advertising = status == 0; } -#endif // CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE +#endif // CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE #define BLE_DISCOVERY_DATA_GUARD 0xbb0000bb #define BLE_DISCOVERY_DATA_GUARD_MASK 0xff0000ff void supervisor_bluetooth_init(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if (CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE) + #if CIRCUITPY_SETTINGS_TOML // Check if the user enabled BLE workflow in settings.toml. The default is that it's off. ble_workflow_setting = false; settings_get_bool("CIRCUITPY_BLE_WORKFLOW", &ble_workflow_setting); if (!ble_workflow_setting) { return; } + #else + // If settings.toml isn't enabled, turn on CIRCUITPY_BLE_WORKFLOW by default. + ble_workflow_setting = true; + #endif // CIRCUITPY_SETTINGS_TOML uint32_t reset_state = port_get_saved_word(); uint32_t ble_mode = 0; @@ -286,7 +290,7 @@ void supervisor_bluetooth_init(void) { } void supervisor_bluetooth_background(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE if (!ble_started) { return; } @@ -318,7 +322,7 @@ void supervisor_bluetooth_background(void) { } void supervisor_start_bluetooth(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE if (workflow_state != WORKFLOW_ENABLED || ble_started) { return; @@ -330,7 +334,7 @@ void supervisor_start_bluetooth(void) { supervisor_start_bluetooth_file_transfer(); #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE supervisor_start_bluetooth_serial(); #endif @@ -348,7 +352,7 @@ void supervisor_start_bluetooth(void) { } void supervisor_stop_bluetooth(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE if (!ble_started && workflow_state != WORKFLOW_ENABLED) { return; @@ -360,7 +364,7 @@ void supervisor_stop_bluetooth(void) { supervisor_stop_bluetooth_file_transfer(); #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE supervisor_stop_bluetooth_serial(); #endif @@ -368,7 +372,7 @@ void supervisor_stop_bluetooth(void) { } void supervisor_bluetooth_enable_workflow(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE if (!ble_workflow_setting || workflow_state == WORKFLOW_DISABLED) { return; } @@ -377,13 +381,13 @@ void supervisor_bluetooth_enable_workflow(void) { } void supervisor_bluetooth_disable_workflow(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE workflow_state = WORKFLOW_DISABLED; #endif } bool supervisor_bluetooth_workflow_is_enabled(void) { - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE if (workflow_state == WORKFLOW_ENABLED) { return true; } diff --git a/supervisor/shared/serial.c b/supervisor/shared/serial.c index 5728a95e08f..1bfb8d73b3c 100644 --- a/supervisor/shared/serial.c +++ b/supervisor/shared/serial.c @@ -17,7 +17,7 @@ #include "supervisor/shared/serial.h" #include "shared-bindings/microcontroller/Pin.h" -#if CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE #include "supervisor/shared/bluetooth/serial.h" #endif @@ -229,7 +229,7 @@ bool serial_connected(void) { return true; #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE if (ble_serial_connected()) { return true; } @@ -290,7 +290,7 @@ char serial_read(void) { } #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE if (ble_serial_available() > 0) { return ble_serial_read_char(); } @@ -348,7 +348,7 @@ uint32_t serial_bytes_available(void) { count += common_hal_busio_uart_rx_characters_available(&console_uart); #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE count += ble_serial_available(); #endif @@ -409,7 +409,7 @@ uint32_t serial_write_substring(const char *text, uint32_t length) { length_sent = console_uart_write(text, length); #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE ble_serial_write(text, length); #endif diff --git a/supervisor/shared/status_bar.c b/supervisor/shared/status_bar.c index 8e32eee033e..3b6e00ef561 100644 --- a/supervisor/shared/status_bar.c +++ b/supervisor/shared/status_bar.c @@ -21,7 +21,7 @@ #include "supervisor/shared/web_workflow/web_workflow.h" #endif -#if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE #include "supervisor/shared/bluetooth/bluetooth.h" #endif @@ -88,7 +88,7 @@ void supervisor_status_bar_update(void) { serial_write(" | "); #endif - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE supervisor_bluetooth_status(); serial_write(" | "); #endif @@ -119,7 +119,7 @@ static void status_bar_background(void *data) { dirty = dirty || supervisor_web_workflow_status_dirty(); #endif - #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE dirty = dirty || supervisor_bluetooth_status_dirty(); #endif diff --git a/supervisor/shared/workflow.c b/supervisor/shared/workflow.c index 28ce682efd9..21dd0512eb1 100644 --- a/supervisor/shared/workflow.c +++ b/supervisor/shared/workflow.c @@ -18,7 +18,7 @@ #if CIRCUITPY_BLEIO #include "shared-bindings/_bleio/__init__.h" #include "supervisor/shared/bluetooth/bluetooth.h" -#if CIRCUITPY_SERIAL_BLE +#if CIRCUITPY_BLE_SERIAL_SERVICE #include "supervisor/shared/bluetooth/serial.h" #endif #endif @@ -82,7 +82,7 @@ bool supervisor_workflow_active(void) { return true; } #endif - #if CIRCUITPY_SERIAL_BLE + #if CIRCUITPY_BLE_SERIAL_SERVICE if (ble_serial_connected()) { return true; } diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index e48c2146e7d..95d651c1541 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -51,7 +51,7 @@ ifeq ($(CIRCUITPY_BLEIO),1) ifeq ($(CIRCUITPY_BLE_FILE_SERVICE),1) SRC_SUPERVISOR += supervisor/shared/bluetooth/file_transfer.c endif - ifeq ($(CIRCUITPY_SERIAL_BLE),1) + ifeq ($(CIRCUITPY_BLE_SERIAL_SERVICE),1) SRC_SUPERVISOR += supervisor/shared/bluetooth/serial.c endif endif From 4a850c518ed71876d61f1ac5549bba2a8fba7bf3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 15 Jul 2026 12:29:42 -0400 Subject: [PATCH 676/876] shrink bluemicro833 --- ports/nordic/boards/bluemicro833/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/nordic/boards/bluemicro833/mpconfigboard.mk b/ports/nordic/boards/bluemicro833/mpconfigboard.mk index 3fcb7cdbb07..e1502f09b55 100644 --- a/ports/nordic/boards/bluemicro833/mpconfigboard.mk +++ b/ports/nordic/boards/bluemicro833/mpconfigboard.mk @@ -17,6 +17,7 @@ CIRCUITPY_NVM = 0 CIRCUITPY_ONEWIREIO = 0 CIRCUITPY_PIXELBUF = 1 CIRCUITPY_PIXELMAP = 0 +CIRCUITPY_PULSEIO = 0 CIRCUITPY_TOUCHIO = 0 # Features to disable From be8f4b5c47486a3f443e91a5608d6ede47ef7bdf Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 15 Jul 2026 13:03:22 -0400 Subject: [PATCH 677/876] per PR review, BLE workflow is by default enabled --- docs/environment.rst | 2 +- docs/workflows.md | 7 +++---- supervisor/shared/bluetooth/bluetooth.c | 11 ++++------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index 962a8fb8159..917b54cef8d 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -80,7 +80,7 @@ Otherwise, defaults to ``CIRCUITPYxxxx``, where ``xxxx`` varies per board. CIRCUITPY_BLE_WORKFLOW (boolean) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If ``true``, enables the BLE workflow. Defaults to ``false``. If ``false``, +If ``false``, disable the BLE workflow. Defaults to ``true``. If ``false``, changing ``supervisor.runtime.ble_workflow`` has no effect. diff --git a/docs/workflows.md b/docs/workflows.md index 074818903ba..ad676d5678e 100644 --- a/docs/workflows.md +++ b/docs/workflows.md @@ -65,10 +65,9 @@ A second CDC interface is optionally available for binary data transfer (see `us ## BLE -The BLE workflow can be enabled for BLE-capable boards by setting `CIRCUITPY_BLE_WORKFLOW=true` -in `settings.toml`. The default is `false`. -This `settings.toml` key and the default of `false` is new in 10.3.0; -previously BLE workflow was available by default. +The BLE workflow provides file transfer and REPL access over BLE. +It can be controlled by setting `CIRCUITPY_BLE_WORKFLOW` to be `true` or `false`. +in `settings.toml`. The default is `true`. To prevent malicious access, even if `CIRCUITPY_BLE_WORKFLOW=true`, the user must initiate a bonded connection with the host. diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 19b84aca4ab..7a3ca38de44 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -77,8 +77,8 @@ static bool ble_started = false; #define WORKFLOW_ENABLED 1 #define WORKFLOW_DISABLED 2 -// Value of CIRCUITPY_BLE_WORKFLOW in settings.toml. Defaults to false. -static bool ble_workflow_setting = false; +// Value of CIRCUITPY_BLE_WORKFLOW in settings.toml. Defaults to true. +static bool ble_workflow_setting = true; // Has BLE workflow been enabled, because it was allow and we've bonded to the workflow host? // Also controlled by supervisor.runtime.ble_workflow. @@ -189,15 +189,12 @@ void supervisor_bluetooth_init(void) { #if (CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE) #if CIRCUITPY_SETTINGS_TOML - // Check if the user enabled BLE workflow in settings.toml. The default is that it's off. - ble_workflow_setting = false; + // Check if the user disabled BLE workflow in settings.toml. The default is that it's enabled. + ble_workflow_setting = true; settings_get_bool("CIRCUITPY_BLE_WORKFLOW", &ble_workflow_setting); if (!ble_workflow_setting) { return; } - #else - // If settings.toml isn't enabled, turn on CIRCUITPY_BLE_WORKFLOW by default. - ble_workflow_setting = true; #endif // CIRCUITPY_SETTINGS_TOML uint32_t reset_state = port_get_saved_word(); From 526baa14e9ef47d48ce8c9067d9469911102ef0f Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 15 Jul 2026 10:09:33 -0700 Subject: [PATCH 678/876] raspberrypi: run core1 flash-call checker on RP2040 picodvi builds picodvi on RP2040 also locks flash out via the MPU and runs core1 RAM-only. Check those builds too, rooting the walk at core1_main plus the two entry points reached only through registered pointers: dvi_dma1_irq and core1_scanline_callback. The checker now skips roots absent from a given build instead of skipping the whole check. This immediately flagged libdvi's flash-resident panic() on a "can't happen" queue overflow in the IRQ handler; allow it explicitly since core1 halts either way and the code is vendored. Co-Authored-By: Claude Fable 5 --- ports/raspberrypi/Makefile | 24 ++++++++++++++++++++++-- tools/check_core1_flash_calls.py | 7 +++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index b5c0fa3e50c..9bacf31c80f 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -768,6 +768,26 @@ endif LINKER_SCRIPTS += -Wl,-T,link-$(CHIP_VARIANT_LOWER).ld +# Builds where core1 locks flash out via the MPU and may only execute +# RAM-resident code: USB host (PIO-USB frame loop), and picodvi on RP2040 +# (TMDS encode loop). Check the linked ELF from each core1 entry point. +# picodvi's DMA IRQ handler and scanline callback run on core1 but are +# reached only through registered pointers, so they are extra roots. +CORE1_CHECK_ROOTS := +ifeq ($(CIRCUITPY_USB_HOST),1) +CORE1_CHECK_ROOTS += --root core1_main +endif +ifeq ($(CHIP_VARIANT),RP2040) +ifeq ($(CIRCUITPY_PICODVI),1) +# libdvi's IRQ handler calls flash-resident panic() on a "can't happen" queue +# overflow. With flash locked out that panic would hard fault instead, but +# either way core1 halts, so allow it rather than blocking the build on +# vendored code. +CORE1_CHECK_ROOTS += --root core1_main --root dvi_dma1_irq --root core1_scanline_callback \ + --allow panic +endif +endif + ifeq ($(VALID_BOARD),) $(BUILD)/firmware.elf: invalid-board else @@ -776,9 +796,9 @@ $(BUILD)/firmware.elf: $(OBJ) $(BOARD_LD) link-$(CHIP_VARIANT_LOWER).ld $(Q)echo $(OBJ) > $(BUILD)/firmware.objs $(Q)echo $(PICO_LDFLAGS) > $(BUILD)/firmware.ldflags $(Q)$(CC) -o $@ $(CFLAGS) @$(BUILD)/firmware.ldflags $(LINKER_SCRIPTS) -Wl,--print-memory-usage -Wl,-Map=$@.map -Wl,-cref -Wl,--gc-sections @$(BUILD)/firmware.objs -Wl,-lc -ifeq ($(CIRCUITPY_USB_HOST), 1) +ifneq ($(CORE1_CHECK_ROOTS),) $(STEPECHO) "CHECK core1 flash calls" - $(Q)$(PYTHON) $(TOP)/tools/check_core1_flash_calls.py $@ + $(Q)$(PYTHON) $(TOP)/tools/check_core1_flash_calls.py $@ $(CORE1_CHECK_ROOTS) endif endif diff --git a/tools/check_core1_flash_calls.py b/tools/check_core1_flash_calls.py index add040bae15..7beffa5f907 100644 --- a/tools/check_core1_flash_calls.py +++ b/tools/check_core1_flash_calls.py @@ -77,7 +77,7 @@ def main(): help="symbol to skip (e.g. runs before the MPU is enabled)", ) args = parser.parse_args() - roots = args.root or ["core1_main"] + roots = list(dict.fromkeys(args.root or ["core1_main"])) allow = set(DEFAULT_ALLOW) | set(args.allow) dis = subprocess.run( @@ -134,10 +134,13 @@ def main(): if tgt is not None: edges.setdefault(veneer, set()).add(tgt) + # A root may be absent from a given build (e.g. core1_scanline_callback + # only exists on picodvi builds); check whichever roots are present. missing = [r for r in roots if r not in funcs] if missing: - # A board without usb_host has no core1_main; nothing to check. print(f"{args.elf}: root symbol(s) not present, skipping: {', '.join(missing)}") + roots = [r for r in roots if r in funcs] + if not roots: return 0 # BFS from roots, remembering one call chain per function for reporting. From 65516d11c166d6d228e21a400d0e08d6a3c303b5 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 15 Jul 2026 22:51:40 -0400 Subject: [PATCH 679/876] allow storage.disable_usb_drive() and .enable_usb_drive() after boot.py --- shared-bindings/storage/__init__.c | 39 ++++++++++++++++++++++----- shared-module/storage/__init__.c | 13 ++++++--- supervisor/shared/usb/usb_msc_flash.c | 2 +- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index 14ec16f3096..b1b1c6e6ce8 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -93,7 +93,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(storage_umount_obj, storage_umount); //| ) -> None: //| """Remounts the given path with new parameters. //| -//| This can always be done from boot.py. After boot, it can only be done when the host computer +//| This can always be done from ``boot.py``. After boot, it can only be done when the host computer //| doesn't have write access and CircuitPython isn't currently writing to the filesystem. An //| exception will be raised if this is the case. Some host OSes allow you to eject a drive which //| will allow for remounting. @@ -189,7 +189,27 @@ MP_DEFINE_CONST_FUN_OBJ_KW(storage_erase_filesystem_obj, 0, storage_erase_filesy //| def disable_usb_drive() -> None: //| """Disable presenting ``CIRCUITPY`` as a USB mass storage device. //| By default, the device is enabled and ``CIRCUITPY`` is visible. -//| Can be called in ``boot.py``, before USB is connected.""" +//| If `disable_usb_drive()` is called in ``boot.py``, before USB is connected, +//| the mass storage device is not presented at all. +//| The drive cannot be made available again until the next hard reset; +//| `enable_usb_drive()` is not available. +//| +//| If `disable_usb_drive()` is called after ``code.py`` starts, or from the REPL, +//| the USB drive logical unit (LUN) will report as "not ready", +//| causing the host to unmount it. +//| It can be made ready and available again by calling `enable_usb_drive()`. +//| When `disable_usb_drive` is called after ``code.py`` starts or in the REPL, +//| the call will delay 2.5 seconds before returning, +//| so that host has time to detect that the drive is not ready. +//| The host polls the device approximately every one or two seconds. +//| +//| If `disable_usb_drive()` is called when the host is actively writing CIRCUITPY, +//| filesystem corruption could occur. Be careful to call it when the host is quiescent. +//| +//| When the USB drive is disabled, CIRCUITPY becomes read/write, and can be written +//| from user code or the REPL. This is easier than arranging for a `remount()` in ``boot.py``. +//| Code editors and file uploaders can use this feature to write files via the REPL. +//| """ //| ... //| //| @@ -206,14 +226,21 @@ static mp_obj_t storage_disable_usb_drive(void) { MP_DEFINE_CONST_FUN_OBJ_0(storage_disable_usb_drive_obj, storage_disable_usb_drive); //| def enable_usb_drive() -> None: -//| """Enabled presenting ``CIRCUITPY`` as a USB mass storage device. +//| """Enable presenting ``CIRCUITPY`` as a USB mass storage device. //| By default, the device is enabled and ``CIRCUITPY`` is visible, //| so you do not normally need to call this function. -//| Can be called in ``boot.py``, before USB is connected. +//| You can call `enable_usb_drive()` in ``boot.py``, before USB is connected, +//| to reverse a `disable_usb_drive()` in ``boot.py``. +//| +//| If you call `enable_usb_drive()` after ``code.py`` starts or in the REPL, +//| you can reverse the effect of a previous `disable_usb_drive()`, +//| but only if `disable_usb_drive()` was also called after ``code.py`` started or in the REPL. +//| The CIRCUITPY drive will reappear to the host, and become read-only again +//| if it was previously read-only. //| -//| If you enable too many devices at once, you will run out of USB endpoints. +//| If you enable too many USB devices at once, you will run out of USB endpoints. //| The number of available endpoints varies by microcontroller. -//| CircuitPython will go into safe mode after running boot.py to inform you if +//| CircuitPython will go into safe mode after running ``boot.py`` to inform you if //| not enough endpoints are available. //| """ //| ... diff --git a/shared-module/storage/__init__.c b/shared-module/storage/__init__.c index dedcee1ff23..0877ffdea5e 100644 --- a/shared-module/storage/__init__.c +++ b/shared-module/storage/__init__.c @@ -27,7 +27,7 @@ #include "tusb.h" // Is the MSC device enabled? -bool storage_usb_is_enabled; +static volatile bool storage_usb_is_enabled; void storage_usb_set_defaults(void) { storage_usb_is_enabled = CIRCUITPY_USB_MSC_ENABLED_DEFAULT; @@ -38,12 +38,17 @@ bool storage_usb_enabled(void) { } static bool usb_drive_set_enabled(bool enabled) { - // We can't change the descriptors once we're connected. + // We can't change the descriptors once we're connected, but we can make the LUN be ready or not ready. + storage_usb_is_enabled = enabled; if (tud_connected()) { - return false; + // The TEST UNIT READY callback in usb_msc_flash.c checks the value of storage_usb_is_enabled. + // If it's false, TEST UNIT READY will report "not ready" + // Linux and macOS send a TEST UNIT READY poll about every 1.1 seconds or faster. + // Windows polls every 2.1 seconds or so. + // So wait long enough for host to send a TEST UNIT READY and receive a reply. + mp_hal_delay_ms(2500); } filesystem_set_internal_writable_by_usb(enabled); - storage_usb_is_enabled = enabled; return true; } diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index 6f15b508095..163019b7328 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -404,7 +404,7 @@ bool tud_msc_test_unit_ready_cb(uint8_t lun) { return false; } - if (ejected[lun] || eject_once[lun] + if (ejected[lun] || eject_once[lun] || (lun == 0 && !storage_usb_enabled()) #ifdef SDCARD_LUN || (lun == SDCARD_LUN && !sdcard_usb_enabled()) #endif From 73d77a57d1d7fe6b994de719484f4e1387a61ac2 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 16 Jul 2026 09:57:07 -0700 Subject: [PATCH 680/876] raspberrypi: make panic() safe to call from a flash-locked core1 Core1 with flash MPU-locked (usb_host, picodvi RP2040) could reach the SDK's flash-resident panic(), e.g. libdvi's TMDS queue overflow path, which would hard fault before printing. Wrap panic at link time with a RAM-resident implementation: core0 keeps the SDK behavior (print and exit), core1 halts in RAM via breakpoint + spin since stdio is not usable there. The core1 flash-call checker verifies the RAM path and allows the core0-only print half by name. Co-Authored-By: Claude Fable 5 --- ports/raspberrypi/Makefile | 11 ++++----- ports/raspberrypi/supervisor/port.c | 37 +++++++++++++++++++++++++++++ tools/check_core1_flash_calls.py | 8 +++++-- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 9bacf31c80f..7e13f2428cb 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -229,6 +229,10 @@ DISABLE_WARNINGS = -Wno-cast-align CFLAGS += $(INC) -Wtype-limits -Wall -Werror -std=gnu11 -fshort-enums $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) $(DISABLE_WARNINGS) -Werror=missing-prototypes -Wold-style-definition PICO_LDFLAGS = --specs=nosys.specs --specs=nano.specs +# The SDK's panic() is flash-resident, but core1 may run with flash access +# disabled by the MPU. Route panics to the RAM-resident __wrap_panic in +# supervisor/port.c, which halts safely on core1 and prints on core0. +PICO_LDFLAGS += -Wl,--wrap=panic # Use toolchain libm if we're not using our own. ifndef INTERNAL_LIBM @@ -779,12 +783,7 @@ CORE1_CHECK_ROOTS += --root core1_main endif ifeq ($(CHIP_VARIANT),RP2040) ifeq ($(CIRCUITPY_PICODVI),1) -# libdvi's IRQ handler calls flash-resident panic() on a "can't happen" queue -# overflow. With flash locked out that panic would hard fault instead, but -# either way core1 halts, so allow it rather than blocking the build on -# vendored code. -CORE1_CHECK_ROOTS += --root core1_main --root dvi_dma1_irq --root core1_scanline_callback \ - --allow panic +CORE1_CHECK_ROOTS += --root core1_main --root dvi_dma1_irq --root core1_scanline_callback endif endif diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 6ffd48547d7..f008da05bb9 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -4,9 +4,12 @@ // // SPDX-License-Identifier: MIT +#include #include +#include #include #include +#include #include "supervisor/background_callback.h" #include "supervisor/board.h" @@ -76,6 +79,40 @@ critical_section_t background_queue_lock; +// The SDK's panic() lives in flash, but core1 may run with flash access +// disabled by the MPU (usb_host and picodvi lock it out), where a flash call +// hard faults before anything is printed. -Wl,--wrap=panic routes every +// panic here instead: core0 keeps the SDK behavior, core1 halts from RAM. +// Verified by tools/check_core1_flash_calls.py. +void __wrap_panic(const char *fmt, ...) __attribute__((noreturn, format(printf, 1, 2))); +void panic_core0(const char *fmt, va_list args) __attribute__((noreturn, format(printf, 1, 0))); + +// Flash-resident; only ever called from core0 (see __wrap_panic). Mirrors +// the SDK implementation. noinline keeps the flash-calling code out of the +// RAM-resident wrapper below. +__attribute__((noinline)) void panic_core0(const char *fmt, va_list args) { + puts("\n*** PANIC ***\n"); + if (fmt) { + vprintf(fmt, args); + puts(""); + } + _exit(1); +} + +void __not_in_flash_func(__wrap_panic)(const char *fmt, ...) { + if (get_core_num() == 0) { + va_list args; + va_start(args, fmt); + panic_core0(fmt, args); + } + // Flash may be MPU-locked on this core and stdio is core0-only, so the + // message is unprintable here. Halt in RAM: a debugger stops at the + // breakpoint, otherwise spin. + __breakpoint(); + while (1) { + } +} + extern volatile bool mp_msc_enabled; static void _tick_callback(uint alarm_num); diff --git a/tools/check_core1_flash_calls.py b/tools/check_core1_flash_calls.py index 7beffa5f907..96e3ec8f5cf 100644 --- a/tools/check_core1_flash_calls.py +++ b/tools/check_core1_flash_calls.py @@ -42,8 +42,8 @@ FLASH_LO, FLASH_HI = 0x10000000, 0x20000000 -# Symbols that are reachable from a core1 root but are known to execute only -# before the MPU cuts off flash access. Keep this list short and commented. +# Symbols that are reachable from a core1 root but are known never to execute +# with flash locked out. Keep this list short and commented. DEFAULT_ALLOW = [ # usb_host core1_main calls this while configuring SysTick, before # enabling the MPU. @@ -52,6 +52,10 @@ # before enabling the MPU. "dvi_register_irqs_this_core", "dvi_start", + # The flash-resident print half of the RAM-resident __wrap_panic + # (supervisor/port.c); only called after a get_core_num() == 0 check, + # and core0 never locks flash out. + "panic_core0", ] From 7828aaf88131034c074a69f57f104a450910fcf5 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 16 Jul 2026 14:14:59 -0400 Subject: [PATCH 681/876] split off unsafe_disable_usb_drive() --- shared-bindings/storage/__init__.c | 66 +++++++++++++++++++----------- shared-bindings/storage/__init__.h | 1 + shared-module/storage/__init__.c | 12 ++++++ 3 files changed, 56 insertions(+), 23 deletions(-) diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index b1b1c6e6ce8..4af72d9a864 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -188,34 +188,56 @@ MP_DEFINE_CONST_FUN_OBJ_KW(storage_erase_filesystem_obj, 0, storage_erase_filesy //| def disable_usb_drive() -> None: //| """Disable presenting ``CIRCUITPY`` as a USB mass storage device. +//| By default, the device is enabled and ``CIRCUITPY`` is visible, if USB is available. +//| Must called in ``boot.py``, before USB is connected. +// If you want to disable the USB drive after `boot.py` has run, see `unsafe_disable_usb_drive()`. +//| """ +//| ... +//| +//| +static mp_obj_t storage_disable_usb_drive(void) { + #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_MSC + if (!common_hal_storage_disable_usb_drive()) { + #else + if (true) { + #endif + mp_raise_RuntimeError(MP_ERROR_TEXT("Cannot change USB devices now")); + } + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_0(storage_disable_usb_drive_obj, storage_disable_usb_drive); + +//| def unsafe_disable_usb_drive() -> None: +//| """Disable presenting ``CIRCUITPY`` as a USB mass storage device. //| By default, the device is enabled and ``CIRCUITPY`` is visible. -//| If `disable_usb_drive()` is called in ``boot.py``, before USB is connected, -//| the mass storage device is not presented at all. -//| The drive cannot be made available again until the next hard reset; -//| `enable_usb_drive()` is not available. +//| Unlike `disable_usb_drive()`, `unsafe_disable_usb_drive()` can be called +//| after ``code.py`` starts or from the REPL, after USB has started. //| -//| If `disable_usb_drive()` is called after ``code.py`` starts, or from the REPL, -//| the USB drive logical unit (LUN) will report as "not ready", +//| When `unsafe_disable_usb_drive()` after USB has started, +//| the ``CIRCUITPY`` USB drive logical unit (LUN) will report as "not ready", //| causing the host to unmount it. -//| It can be made ready and available again by calling `enable_usb_drive()`. +//| The drive can be made ready and available again by calling `enable_usb_drive()`. //| When `disable_usb_drive` is called after ``code.py`` starts or in the REPL, //| the call will delay 2.5 seconds before returning, //| so that host has time to detect that the drive is not ready. //| The host polls the device approximately every one or two seconds. //| -//| If `disable_usb_drive()` is called when the host is actively writing CIRCUITPY, +//| Note that if ``unsafe_disable_usb_drive()`` is called when the host is actively writing CIRCUITPY, //| filesystem corruption could occur. Be careful to call it when the host is quiescent. //| //| When the USB drive is disabled, CIRCUITPY becomes read/write, and can be written //| from user code or the REPL. This is easier than arranging for a `remount()` in ``boot.py``. //| Code editors and file uploaders can use this feature to write files via the REPL. +//| +//| If `unsafe_disable_usb_drive()` is called in ``boot.py``, it is identical to calling +//| `disable_usb_drive()`. //| """ //| ... //| //| -static mp_obj_t storage_disable_usb_drive(void) { +static mp_obj_t storage_unsafe_disable_usb_drive(void) { #if CIRCUITPY_USB_DEVICE && CIRCUITPY_USB_MSC - if (!common_hal_storage_disable_usb_drive()) { + if (!common_hal_storage_unsafe_disable_usb_drive()) { #else if (true) { #endif @@ -223,18 +245,15 @@ static mp_obj_t storage_disable_usb_drive(void) { } return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_0(storage_disable_usb_drive_obj, storage_disable_usb_drive); +MP_DEFINE_CONST_FUN_OBJ_0(storage_unsafe_disable_usb_drive_obj, storage_unsafe_disable_usb_drive); //| def enable_usb_drive() -> None: //| """Enable presenting ``CIRCUITPY`` as a USB mass storage device. //| By default, the device is enabled and ``CIRCUITPY`` is visible, -//| so you do not normally need to call this function. -//| You can call `enable_usb_drive()` in ``boot.py``, before USB is connected, -//| to reverse a `disable_usb_drive()` in ``boot.py``. +//| so you do not normally need to call this function in ``boot.py``. //| //| If you call `enable_usb_drive()` after ``code.py`` starts or in the REPL, -//| you can reverse the effect of a previous `disable_usb_drive()`, -//| but only if `disable_usb_drive()` was also called after ``code.py`` started or in the REPL. +//| you can reverse the effect of a previous `unsafe_disable_usb_drive()`. //| The CIRCUITPY drive will reappear to the host, and become read-only again //| if it was previously read-only. //| @@ -261,13 +280,14 @@ MP_DEFINE_CONST_FUN_OBJ_0(storage_enable_usb_drive_obj, storage_enable_usb_drive static const mp_rom_map_elem_t storage_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_storage) }, - { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&storage_mount_obj) }, - { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&storage_umount_obj) }, - { MP_ROM_QSTR(MP_QSTR_remount), MP_ROM_PTR(&storage_remount_obj) }, - { MP_ROM_QSTR(MP_QSTR_getmount), MP_ROM_PTR(&storage_getmount_obj) }, - { MP_ROM_QSTR(MP_QSTR_erase_filesystem), MP_ROM_PTR(&storage_erase_filesystem_obj) }, - { MP_ROM_QSTR(MP_QSTR_disable_usb_drive), MP_ROM_PTR(&storage_disable_usb_drive_obj) }, - { MP_ROM_QSTR(MP_QSTR_enable_usb_drive), MP_ROM_PTR(&storage_enable_usb_drive_obj) }, + { MP_ROM_QSTR(MP_QSTR_mount), MP_ROM_PTR(&storage_mount_obj) }, + { MP_ROM_QSTR(MP_QSTR_umount), MP_ROM_PTR(&storage_umount_obj) }, + { MP_ROM_QSTR(MP_QSTR_remount), MP_ROM_PTR(&storage_remount_obj) }, + { MP_ROM_QSTR(MP_QSTR_getmount), MP_ROM_PTR(&storage_getmount_obj) }, + { MP_ROM_QSTR(MP_QSTR_erase_filesystem), MP_ROM_PTR(&storage_erase_filesystem_obj) }, + { MP_ROM_QSTR(MP_QSTR_disable_usb_drive), MP_ROM_PTR(&storage_disable_usb_drive_obj) }, + { MP_ROM_QSTR(MP_QSTR_enable_usb_drive), MP_ROM_PTR(&storage_enable_usb_drive_obj) }, + { MP_ROM_QSTR(MP_QSTR_unsafe_disable_usb_drive), MP_ROM_PTR(&storage_unsafe_disable_usb_drive_obj) }, //| class VfsFat: //| def __init__(self, block_device: BlockDevice) -> None: diff --git a/shared-bindings/storage/__init__.h b/shared-bindings/storage/__init__.h index 6df60426295..0e53c78b153 100644 --- a/shared-bindings/storage/__init__.h +++ b/shared-bindings/storage/__init__.h @@ -19,4 +19,5 @@ mp_obj_t common_hal_storage_getmount(const char *path); MP_NORETURN void common_hal_storage_erase_filesystem(bool extended); bool common_hal_storage_disable_usb_drive(void); +bool common_hal_storage_unsafe_disable_usb_drive(void); bool common_hal_storage_enable_usb_drive(void); diff --git a/shared-module/storage/__init__.c b/shared-module/storage/__init__.c index 0877ffdea5e..1522136332a 100644 --- a/shared-module/storage/__init__.c +++ b/shared-module/storage/__init__.c @@ -53,6 +53,14 @@ static bool usb_drive_set_enabled(bool enabled) { } bool common_hal_storage_disable_usb_drive(void) { + if (tud_connected()) { + // Complain if already connected. Use `storage.unsafe_disable_usb_drive()` in that case. + return false; + } + return usb_drive_set_enabled(false); +} + +bool common_hal_storage_unsafe_disable_usb_drive(void) { return usb_drive_set_enabled(false); } @@ -64,6 +72,10 @@ bool common_hal_storage_disable_usb_drive(void) { return false; } +bool common_hal_storage_unsafe_disable_usb_drive(void) { + return false; +} + bool common_hal_storage_enable_usb_drive(void) { return false; } From 9f67d78a1d19a9a2673e2ce15e462d0a8625f559 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 16 Jul 2026 16:10:15 -0700 Subject: [PATCH 682/876] usb host: poll report-protocol HID keyboards The host keyboard workflow only started polling boot-protocol keyboards. CircuitPython usb_hid devices use report protocol with report IDs, so their reports were never read and the device raised OSError("USB busy") on the second send_report(). Detect keyboards by report descriptor usage, strip the report ID prefix, and always re-arm reception after each report. Fixes #10721 --- supervisor/shared/usb/host_keyboard.c | 61 ++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/supervisor/shared/usb/host_keyboard.c b/supervisor/shared/usb/host_keyboard.c index f99b1e5c42a..de4f719d175 100644 --- a/supervisor/shared/usb/host_keyboard.c +++ b/supervisor/shared/usb/host_keyboard.c @@ -28,6 +28,14 @@ static uint8_t _buf[16]; static uint8_t _dev_addr; static uint8_t _interface; +// A keyboard interface that is not boot-protocol, detected at mount time from +// its report descriptor. Composite HID devices (CircuitPython's usb_hid among +// them) present bInterfaceProtocol NONE and prefix each report with a report +// ID, so they fail the boot-protocol check in usb_keyboard_attach(). +static uint8_t _report_kbd_dev_addr; +static uint8_t _report_kbd_interface; +static uint8_t _report_kbd_report_id; + #define FLAG_SHIFT (1) #define FLAG_NUMLOCK (2) #define FLAG_CTRL (4) @@ -298,7 +306,12 @@ static void process_event(uint8_t dev_addr, uint8_t instance, const hid_keyboard uint8_t leds = (caps | (num << 1)); if (leds != old_report.reserved) { - tuh_hid_set_report(dev_addr, instance /*idx*/, 0 /*report_id*/, HID_REPORT_TYPE_OUTPUT /*report_type*/, &leds, sizeof(leds)); + // A report-protocol keyboard needs its report ID on the LED output report too. + uint8_t report_id = 0; + if (dev_addr == _report_kbd_dev_addr && instance == _report_kbd_interface) { + report_id = _report_kbd_report_id; + } + tuh_hid_set_report(dev_addr, instance /*idx*/, report_id, HID_REPORT_TYPE_OUTPUT /*report_type*/, &leds, sizeof(leds)); } old_report = *report; old_report.reserved = leds; @@ -326,7 +339,11 @@ void usb_keyboard_attach(uint8_t dev_addr, uint8_t interface) { return; } uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, interface); - if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) { + bool is_boot_keyboard = itf_protocol == HID_ITF_PROTOCOL_KEYBOARD; + // Detected at mount time by tuh_hid_mount_cb(). Device addresses start at + // 1, so a zeroed _report_kbd_dev_addr never matches. + bool is_report_keyboard = dev_addr == _report_kbd_dev_addr && interface == _report_kbd_interface; + if (is_boot_keyboard || is_report_keyboard) { _dev_addr = dev_addr; _interface = interface; tuh_hid_receive_report(dev_addr, interface); @@ -335,20 +352,52 @@ void usb_keyboard_attach(uint8_t dev_addr, uint8_t interface) { } void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t interface, uint8_t const *desc_report, uint16_t desc_len) { + // A non-boot interface can still be a keyboard, using report protocol. + // Find keyboard usage in its report descriptor so that we poll it too. + // Otherwise its interrupt IN endpoint is never drained, and a CircuitPython + // device plugged into us raises OSError("USB busy") on its second + // send_report() (#10721). + if (tuh_hid_interface_protocol(dev_addr, interface) == HID_ITF_PROTOCOL_NONE && + _report_kbd_dev_addr == 0) { + tuh_hid_report_info_t report_info[8]; + uint8_t report_count = + tuh_hid_parse_report_descriptor(report_info, TU_ARRAY_SIZE(report_info), desc_report, desc_len); + for (uint8_t i = 0; i < report_count; i++) { + if (report_info[i].usage_page == HID_USAGE_PAGE_DESKTOP && + report_info[i].usage == HID_USAGE_DESKTOP_KEYBOARD) { + _report_kbd_dev_addr = dev_addr; + _report_kbd_interface = interface; + _report_kbd_report_id = report_info[i].report_id; + break; + } + } + } usb_keyboard_attach(dev_addr, interface); } void tuh_hid_umount_cb(uint8_t dev_addr, uint8_t interface) { + if (dev_addr == _report_kbd_dev_addr && interface == _report_kbd_interface) { + _report_kbd_dev_addr = 0; + _report_kbd_interface = 0; + _report_kbd_report_id = 0; + } usb_keyboard_detach(dev_addr, interface); } void tuh_hid_report_received_cb(uint8_t dev_addr, uint8_t instance, uint8_t const *report, uint16_t len) { - if (len != sizeof(hid_keyboard_report_t)) { - return; - } else { + if (len == sizeof(hid_keyboard_report_t)) { process_event(dev_addr, instance, (hid_keyboard_report_t *)report); + } else if (dev_addr == _report_kbd_dev_addr && instance == _report_kbd_interface && + _report_kbd_report_id != 0 && + len == sizeof(hid_keyboard_report_t) + 1 && + report[0] == _report_kbd_report_id) { + // Report-protocol keyboards prefix the report with its report ID. + process_event(dev_addr, instance, (const hid_keyboard_report_t *)(report + 1)); } - // continue to request to receive report + // Always request the next report, even when this one wasn't a keyboard + // report we understand (a mouse or consumer control report ID from a + // composite device, for instance), so that the device's endpoint keeps + // draining and polling doesn't stop. tuh_hid_receive_report(dev_addr, instance); } From a87250569c8b337dd2d3096889f123fb09114f79 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 17 Jul 2026 19:19:13 -0400 Subject: [PATCH 683/876] update frozen libraries --- frozen/Adafruit_CircuitPython_ImageLoad | 2 +- frozen/Adafruit_CircuitPython_MPU6050 | 2 +- frozen/Adafruit_CircuitPython_SSD1680 | 2 +- frozen/Adafruit_CircuitPython_asyncio | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_ImageLoad b/frozen/Adafruit_CircuitPython_ImageLoad index 3bc5c15c707..11855997455 160000 --- a/frozen/Adafruit_CircuitPython_ImageLoad +++ b/frozen/Adafruit_CircuitPython_ImageLoad @@ -1 +1 @@ -Subproject commit 3bc5c15c7079e076b49f9929bb956de8812c62f8 +Subproject commit 11855997455465bc93670e2a3f92e73bc9f7caee diff --git a/frozen/Adafruit_CircuitPython_MPU6050 b/frozen/Adafruit_CircuitPython_MPU6050 index 928d747a826..d30ee1fa5f4 160000 --- a/frozen/Adafruit_CircuitPython_MPU6050 +++ b/frozen/Adafruit_CircuitPython_MPU6050 @@ -1 +1 @@ -Subproject commit 928d747a826fc8d8c4237ed1b40b53cf723cf1ee +Subproject commit d30ee1fa5f49b62b4df382ea5310a77fa39d6bd9 diff --git a/frozen/Adafruit_CircuitPython_SSD1680 b/frozen/Adafruit_CircuitPython_SSD1680 index 292f58b987d..f17e62d2466 160000 --- a/frozen/Adafruit_CircuitPython_SSD1680 +++ b/frozen/Adafruit_CircuitPython_SSD1680 @@ -1 +1 @@ -Subproject commit 292f58b987db50dd622be5b83722893c58c16ab9 +Subproject commit f17e62d246656b3f956232c368bc05d966988d9a diff --git a/frozen/Adafruit_CircuitPython_asyncio b/frozen/Adafruit_CircuitPython_asyncio index d0d63f113c7..705ae0cbda8 160000 --- a/frozen/Adafruit_CircuitPython_asyncio +++ b/frozen/Adafruit_CircuitPython_asyncio @@ -1 +1 @@ -Subproject commit d0d63f113c7da0852bdc5aa303cd738e45d40fbc +Subproject commit 705ae0cbda87c4bb4d82fb81aa8fb718b5a4b385 From 691004d7b186093d221204be89b9c0c406a1230e Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 17 Jul 2026 18:22:48 -0700 Subject: [PATCH 684/876] raspberrypi: wake core 0 from idle when core 1 posts USB host events Why: on rp2 the TinyUSB host task only runs when core 0 drains the background callback queue. The PIO USB host runs on core 1 and posts its events there, but port_wake_main_task() was a no-op, so core 1 could not wake core 0 out of the WFI in port_idle_until_interrupt(). While a program is in time.sleep(), core 0 stays parked in that WFI for the whole sleep, so host events never get serviced. A device plugged in while a program sleeps can fail to enumerate. What: implement port_wake_main_task() as SEV and idle with WFE instead of WFI, so core 1 can wake core 0. SEVONPEND keeps the old wake on pending interrupt behavior. Shared port.c, so it covers both rp2040 and rp2350. Testing: a program looping "find(); time.sleep(0.5)" with no other USB polling. Plug a device into the host port while it runs. On main it never enumerates (over 50 seconds). With this change it enumerates within one loop iteration. Confirmed on a Fruit Jam (RP2350) and a Feather RP2040 USB Host (RP2040). --- ports/raspberrypi/supervisor/port.c | 35 +++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index f008da05bb9..555269bb962 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -13,6 +13,7 @@ #include "supervisor/background_callback.h" #include "supervisor/board.h" +#include "supervisor/linker.h" #include "supervisor/port.h" #include "bindings/rp2pio/StateMachine.h" @@ -45,6 +46,7 @@ #include "supervisor/shared/stack.h" #include "supervisor/shared/tick.h" +#include "hardware/structs/scb.h" #include "hardware/structs/watchdog.h" #include "hardware/gpio.h" #include "hardware/uart.h" @@ -421,6 +423,16 @@ safe_mode_t port_init(void) { common_hal_rtc_init(); #endif + // Send-event-on-pend, so the WFE in port_idle_until_interrupt wakes on a + // pending interrupt (as WFI did) in addition to waking on SEV — including + // the SEV core 1 sends via port_wake_main_task() when it queues USB host + // work. + #if PICO_RP2040 + scb_hw->scr |= M0PLUS_SCR_SEVONPEND_BITS; + #else + scb_hw->scr |= M33_SCR_SEVONPEND_BITS; + #endif + // For the tick. hardware_alarm_claim(0); hardware_alarm_set_callback(0, _tick_callback); @@ -600,7 +612,11 @@ void port_idle_until_interrupt(void) { if (!background_callback_pending() && !tud_task_event_ready() && !_woken_up) { #endif __DSB(); - __WFI(); + // WFE, not WFI: the event register is sticky, so a SEV from core 1 + // (port_wake_main_task, e.g. a USB host event) that lands between the + // checks above and here still terminates the wait. Pending interrupts + // wake it too, via SEVONPEND (set in port_init). + __wfe(); } common_hal_mcu_enable_interrupts(); #else @@ -619,7 +635,8 @@ void port_idle_until_interrupt(void) { if (!background_callback_pending() && !tud_task_event_ready() && !_woken_up) { #endif __DSB(); - __WFI(); + // WFE, not WFI: see the RP2040 branch above. + __wfe(); } // and restore basepri before reenabling interrupts @@ -630,6 +647,20 @@ void port_idle_until_interrupt(void) { #endif } +// Called whenever a background callback is queued, including from core 1 +// (which runs the PIO-USB host and posts its events here). SEV is broadcast +// to both cores and latches in the event register, so it reliably ends the +// WFE in port_idle_until_interrupt even if it arrives before the WFE starts. +// Without this, core 0 sleeps through host events for the remainder of a +// time.sleep(): device removal processing and enumeration stall until the +// next unrelated wakeup. +// PLACE_IN_ITCM: core 1 runs with flash execute-never, so this must live in +// RAM like its background_callback_add_core caller (__sev inlines to a bare +// instruction). +void PLACE_IN_ITCM(port_wake_main_task)(void) { + __sev(); +} + /** * \brief Default interrupt handler for unused IRQs. */ From 8006740bae462496f7bafe6978a32f85e8203926 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 20 Jul 2026 12:13:53 -0400 Subject: [PATCH 685/876] lower tx_power to 15 for boards with chip antennas --- .../espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h | 3 +++ ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h | 3 +++ ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h | 3 +++ ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h | 3 +++ ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h | 3 +++ ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h | 3 +++ ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h | 3 +++ ports/espressif/boards/lolin_c3_pico/mpconfigboard.h | 3 +++ ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h | 3 +++ .../espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h | 3 +++ ports/espressif/boards/microdev_micro_s2/mpconfigboard.h | 3 +++ ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h | 3 +++ ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h | 3 +++ .../boards/unexpectedmaker_blizzard_s3/mpconfigboard.h | 3 +++ ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h | 3 +++ .../espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h | 3 +++ .../boards/unexpectedmaker_feathers2_neo/mpconfigboard.h | 3 +++ .../unexpectedmaker_feathers2_prerelease/mpconfigboard.h | 3 +++ .../espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h | 3 +++ ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h | 3 +++ ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h | 3 +++ ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h | 3 +++ ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h | 3 +++ .../espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h | 3 +++ .../boards/unexpectedmaker_tinypico_nano/mpconfigboard.h | 3 +++ ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h | 3 +++ ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h | 3 +++ .../boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h | 3 +++ ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h | 3 +++ .../espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h | 3 +++ ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h | 3 +++ ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h | 3 +++ ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h | 3 +++ ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h | 3 +++ ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h | 3 +++ 40 files changed, 120 insertions(+) diff --git a/ports/espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h index 799a53c5c78..a0bc2b9f374 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_qtpy_esp32_pico/mpconfigboard.h @@ -26,3 +26,6 @@ // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h b/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h index c59dbfc81c9..a0c73d0bcdf 100644 --- a/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_qtpy_esp32s2/mpconfigboard.h @@ -25,3 +25,6 @@ #define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO5, .rx = &pin_GPIO16}} #define DOUBLE_TAP_PIN (&pin_GPIO10) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h b/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h index 8f20dc5bfe2..31dba37970c 100644 --- a/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h +++ b/ports/espressif/boards/atmegazero_esp32s2/mpconfigboard.h @@ -22,3 +22,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define MICROPY_HW_NEOPIXEL (&pin_GPIO40) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h b/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h index 44171d1dc4d..65832e3cc9c 100644 --- a/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h +++ b/ports/espressif/boards/cezerio_dev_ESP32C6/mpconfigboard.h @@ -25,3 +25,6 @@ // For entering safe mode, use BOOT button #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h b/ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h index 973e6118393..973e2f5bac2 100644 --- a/ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h +++ b/ports/espressif/boards/circuitart_zero_s3/mpconfigboard.h @@ -32,3 +32,6 @@ #define DEFAULT_TFT_CS (&pin_GPIO39) #define DEFAULT_TFT_DC (&pin_GPIO5) #define DEFAULT_TFT_RST (&pin_GPIO40) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h b/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h index 0edea0bf63b..a987bac317b 100644 --- a/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h +++ b/ports/espressif/boards/lilygo_tdongle_s3/mpconfigboard.h @@ -16,3 +16,6 @@ #define DEFAULT_I2C_BUS_SCL (&pin_GPIO44) #define DEFAULT_I2C_BUS_SDA (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h b/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h index 247e58d916d..382f6e3f598 100644 --- a/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h +++ b/ports/espressif/boards/lilygo_ttgo_t-oi-plus/mpconfigboard.h @@ -16,3 +16,6 @@ #define CIRCUITPY_CONSOLE_UART_RX DEFAULT_UART_BUS_RX #define CIRCUITPY_CONSOLE_UART_TX DEFAULT_UART_BUS_TX + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/lolin_c3_pico/mpconfigboard.h b/ports/espressif/boards/lolin_c3_pico/mpconfigboard.h index 24800307223..6ee4cd4cf95 100644 --- a/ports/espressif/boards/lolin_c3_pico/mpconfigboard.h +++ b/ports/espressif/boards/lolin_c3_pico/mpconfigboard.h @@ -26,3 +26,6 @@ #define CIRCUITPY_BOARD_UART (1) #define CIRCUITPY_BOARD_UART_PIN {{.tx = &pin_GPIO21, .rx = &pin_GPIO20}} + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h b/ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h index 2fe5f4205da..bdbea2d18cb 100644 --- a/ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h +++ b/ports/espressif/boards/lolin_s3_mini_pro/mpconfigboard.h @@ -22,3 +22,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h b/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h index ed8dec14f0a..0d17aef1109 100644 --- a/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h +++ b/ports/espressif/boards/makergo_esp32c6_supermini/mpconfigboard.h @@ -17,3 +17,6 @@ // Default bus pins #define DEFAULT_UART_BUS_TX (&pin_GPIO17) #define DEFAULT_UART_BUS_RX (&pin_GPIO16) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h b/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h index b7b327b23d3..db2d353f998 100644 --- a/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h +++ b/ports/espressif/boards/microdev_micro_s2/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DEFAULT_UART_BUS_RX (&pin_GPIO44) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h b/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h index 6f803cd9c96..6918056cf86 100644 --- a/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h +++ b/ports/espressif/boards/seeed_xiao_esp32c6/mpconfigboard.h @@ -17,3 +17,6 @@ // For entering safe mode, use BOOT button #define CIRCUITPY_BOOT_BUTTON (&pin_GPIO9) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h index 671f714daea..f9aad2c4ba3 100644 --- a/ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_bling/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_blizzard_s3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_blizzard_s3/mpconfigboard.h index dd677dad7b9..86275b0d784 100644 --- a/ports/espressif/boards/unexpectedmaker_blizzard_s3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_blizzard_s3/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h index 27be4ffd1ce..a9271bc1e00 100644 --- a/ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_edges3d/mpconfigboard.h @@ -21,3 +21,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h index d8349cdb58b..1df282a3326 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers2/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h index 1dd6b79a9b9..5141c6d7793 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers2_neo/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h index 1d6c9035ac6..c2f9197fad8 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers2_prerelease/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h index 53157a1ff11..dc48fe3f40f 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers3/mpconfigboard.h @@ -28,3 +28,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h index 022d6f3373e..f59ce34fb6a 100644 --- a/ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_nanos3/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h index 5fd666524c7..5ec5945cdfe 100644 --- a/ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_omgs3/mpconfigboard.h @@ -24,3 +24,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h index bec68c88cb1..dfef3399844 100644 --- a/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_pros3/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h index 3e4995437d5..6f7e84c5c75 100644 --- a/ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinyc6/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO17) #define DEFAULT_UART_BUS_TX (&pin_GPIO16) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h index c03aa8d7fbc..6300506e9e1 100644 --- a/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinypico/mpconfigboard.h @@ -18,3 +18,6 @@ // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.h index 2ab781f1a2e..6b01e2c2e13 100644 --- a/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinypico_nano/mpconfigboard.h @@ -18,3 +18,6 @@ // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h index d7c87bfdba2..07c453cb7bc 100644 --- a/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinys2/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h index 2556e714d67..066dd00386c 100644 --- a/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinys3/mpconfigboard.h @@ -25,3 +25,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h index 6f0181c4acb..309c2e2e702 100644 --- a/ports/espressif/boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_tinywatch_s3/mpconfigboard.h @@ -21,3 +21,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h index c74499cf80a..638eb0390d8 100644 --- a/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s2_pico_lcd/mpconfigboard.h @@ -20,3 +20,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h index 9ac461ee61d..7a67f925ab1 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_amoled_241/mpconfigboard.h @@ -32,3 +32,6 @@ // Default UART bus #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h index 87ac391f5a0..adb5a1c3af7 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_geek/mpconfigboard.h @@ -20,3 +20,6 @@ #define CIRCUITPY_BOARD_SPI (2) #define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO12, .mosi = &pin_GPIO11}, \ {.clock = &pin_GPIO36, .mosi = &pin_GPIO35, .miso = &pin_GPIO37}} + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h index 1999b7c9614..47d03fe9554 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_47/mpconfigboard.h @@ -20,3 +20,6 @@ #define CIRCUITPY_BOARD_SPI (2) #define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO40, .mosi = &pin_GPIO45}, \ {.clock = &pin_GPIO14, .mosi = &pin_GPIO15, .miso = &pin_GPIO16}} + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h index 63595cb559e..c6c68e8336f 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_matrix/mpconfigboard.h @@ -13,3 +13,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h index 90ef06f2a12..2b95643a41e 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_pico/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) #define DEFAULT_SPI_BUS_MOSI (&pin_GPIO35) #define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h index fb33519370c..1785cc4486a 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny/mpconfigboard.h @@ -17,3 +17,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO19) #define DEFAULT_UART_BUS_TX (&pin_GPIO20) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h index 296d751ab25..590b0fc5c5c 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_tiny_n8r8/mpconfigboard.h @@ -17,3 +17,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO19) #define DEFAULT_UART_BUS_TX (&pin_GPIO20) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h index 0dc2ad4a661..7fed8626501 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_1_47/mpconfigboard.h @@ -20,3 +20,6 @@ #define CIRCUITPY_BOARD_SPI (2) #define CIRCUITPY_BOARD_SPI_PIN {{.clock = &pin_GPIO38, .mosi = &pin_GPIO39}, /* for LCD display */ \ {.clock = &pin_GPIO16, .mosi = &pin_GPIO15, .miso = &pin_GPIO17} /* for SD Card */} + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h index da6b7a8a855..f0a19c0e290 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_zero/mpconfigboard.h @@ -16,3 +16,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h index 2888af9184a..5875725a00f 100644 --- a/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32s2_pico/mpconfigboard.h @@ -23,3 +23,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h b/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h index 6a9f0357156..fa0ed02f676 100644 --- a/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h +++ b/ports/espressif/boards/wemos_lolin32_lite/mpconfigboard.h @@ -20,3 +20,6 @@ // UART pins attached to the USB-serial converter chip #define CIRCUITPY_CONSOLE_UART_TX (&pin_GPIO1) #define CIRCUITPY_CONSOLE_UART_RX (&pin_GPIO3) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) From 612ce005ae00fc9c87bc921f196a24bf70659e23 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 20 Jul 2026 13:42:55 -0400 Subject: [PATCH 686/876] lower tx_power to 15 for more boards with chip antennas Boards identified by mikeysklar. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../boards/unexpectedmaker_feathers3_neo/mpconfigboard.h | 3 +++ .../boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h | 3 +++ ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h | 3 +++ .../boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h | 3 +++ 7 files changed, 21 insertions(+) diff --git a/ports/espressif/boards/unexpectedmaker_feathers3_neo/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_feathers3_neo/mpconfigboard.h index 037190d9aa8..18f2513e6af 100644 --- a/ports/espressif/boards/unexpectedmaker_feathers3_neo/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_feathers3_neo/mpconfigboard.h @@ -27,3 +27,6 @@ #define DEFAULT_UART_BUS_TX (&pin_GPIO43) // #define DOUBLE_TAP_PIN (&pin_GPIO47) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h b/ports/espressif/boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h index 2cf95fa9a6d..b0bbcd2d457 100644 --- a/ports/espressif/boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h +++ b/ports/espressif/boards/unexpectedmaker_rgbtouch_mini/mpconfigboard.h @@ -17,3 +17,6 @@ #define DEFAULT_I2C_BUS_SCL (&pin_GPIO9) #define DEFAULT_I2C_BUS_SDA (&pin_GPIO8) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h index 322acaf84b8..d745d366562 100644 --- a/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_c6_lcd_1_47/mpconfigboard.h @@ -31,3 +31,6 @@ // Explanation of how a user got into safe mode #define BOARD_USER_SAFE_MODE_ACTION MP_ERROR_TEXT("You pressed the BOOT button at start up.") + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h index 037fa18c0be..5630a162798 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_eth/mpconfigboard.h @@ -15,3 +15,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h index 1e1acbdd9f8..f19baae3c46 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_lcd_1_28/mpconfigboard.h @@ -23,3 +23,6 @@ #define CIRCUITPY_CONSOLE_UART_RX DEFAULT_UART_BUS_RX #define CIRCUITPY_CONSOLE_UART_TX DEFAULT_UART_BUS_TX + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h index b4009fdfd7f..d6b66bffafa 100644 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2/mpconfigboard.h @@ -17,3 +17,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) diff --git a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h index 3e0db8bf494..a04002de73f 100755 --- a/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h +++ b/ports/espressif/boards/waveshare_esp32_s3_touch_lcd_2_8/mpconfigboard.h @@ -17,3 +17,6 @@ #define DEFAULT_UART_BUS_RX (&pin_GPIO44) #define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +// Reduce wifi.radio.tx_power due to the antenna design of this board +#define CIRCUITPY_WIFI_DEFAULT_TX_POWER (15) From eafed60ee244e7da6aa435ca36c037412012c0c8 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 21 Jul 2026 14:49:04 -0400 Subject: [PATCH 687/876] update documentation per review --- docs/environment.rst | 2 +- docs/troubleshooting.rst | 14 +++---- ports/espressif/README.rst | 2 +- shared-bindings/dualbank/__init__.c | 2 +- shared-bindings/storage/__init__.c | 61 ++++++++++++++++++++--------- 5 files changed, 52 insertions(+), 29 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index 7d0e41727d3..f4ceaf9a9cb 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -4,7 +4,7 @@ Environment Variables CircuitPython provides support for environment variables. These values can be examined by user code, and are also used as settings by CircuitPython during startup. -CircuitPython looks for a file called ``settings.toml`` at the ``CIRCUITPY`` drive root +CircuitPython looks for a file called ``settings.toml`` at the **CIRCUITPY** drive root to find the values of environment variables, The file format is a subset of the `TOML config file language `__. diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 7fad2aac181..d505ff09ef0 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -7,22 +7,22 @@ variety of errors that can happen, what they mean and how to fix them. File system issues ------------------ -If your host computer starts complaining that your ``CIRCUITPY`` drive is corrupted +If your host computer starts complaining that your **CIRCUITPY** drive is corrupted or files cannot be overwritten or deleted, then you will have to erase it completely. -When CircuitPython restarts it will create a fresh empty ``CIRCUITPY`` filesystem. +When CircuitPython restarts it will create a fresh empty **CIRCUITPY** filesystem. -Corruption often happens on Windows when the ``CIRCUITPY`` disk is not safely ejected +Corruption often happens on Windows when the **CIRCUITPY** disk is not safely ejected before being reset by the button or being disconnected from USB. This can also happen on Linux and Mac OSX but it's less likely. -.. caution:: To erase and re-create ``CIRCUITPY`` (for example, to correct a corrupted filesystem), +.. caution:: To erase and re-create **CIRCUITPY** (for example, to correct a corrupted filesystem), follow one of the procedures below. It's important to note that **any files stored on the** - ``CIRCUITPY`` **drive will be erased. Back up your code if possible before continuing!** + **CIRCUITPY** **drive will be erased. Back up your code if possible before continuing!** REPL Erase Method ^^^^^^^^^^^^^^^^^ This is the recommended method of erasing your board. If you are having trouble accessing the -``CIRCUITPY`` drive or the REPL, consider first putting your board into +**CIRCUITPY** drive or the REPL, consider first putting your board into `safe mode `_. **To erase any board if you have access to the REPL:** @@ -30,7 +30,7 @@ This is the recommended method of erasing your board. If you are having trouble #. Connect to the CircuitPython REPL using a terminal program. #. Type ``import storage`` into the REPL. #. Then, type ``storage.erase_filesystem()`` into the REPL. -#. The ``CIRCUITPY`` drive will be erased and the board will restart with an empty ``CIRCUITPY`` drive. +#. The **CIRCUITPY** drive will be erased and the board will restart with an empty **CIRCUITPY** drive. Erase File Method ^^^^^^^^^^^^^^^^^ diff --git a/ports/espressif/README.rst b/ports/espressif/README.rst index fe5542aafe4..5af91591f7e 100644 --- a/ports/espressif/README.rst +++ b/ports/espressif/README.rst @@ -41,7 +41,7 @@ Connecting to the ESP32-C3 **USB Connection:** -On ESP32-C3 REV3 chips, a USB Serial/JTAG Controller is available. Note: This USB connection cannot be used for a ``CIRCUITPY`` drive. +On ESP32-C3 REV3 chips, a USB Serial/JTAG Controller is available. Note: This USB connection cannot be used for a **CIRCUITPY** drive. Depending on the board you have, the USB port may or may not be connected to native USB. diff --git a/shared-bindings/dualbank/__init__.c b/shared-bindings/dualbank/__init__.c index 2c00a5b0100..160ce4947a7 100644 --- a/shared-bindings/dualbank/__init__.c +++ b/shared-bindings/dualbank/__init__.c @@ -34,7 +34,7 @@ //| This module is unavailable as the flash is only large enough for one app partition. //| //| Boards with flash ``>2MB``: -//| This module is enabled/disabled at runtime based on whether the ``CIRCUITPY`` drive +//| This module is enabled/disabled at runtime based on whether the **CIRCUITPY** drive //| is extended or not. See `storage.erase_filesystem()` for more information. //| //| .. code-block:: python diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index 4af72d9a864..8bd43686694 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -140,24 +140,24 @@ static mp_obj_t storage_getmount(const mp_obj_t mnt_in) { MP_DEFINE_CONST_FUN_OBJ_1(storage_getmount_obj, storage_getmount); //| def erase_filesystem(extended: Optional[bool] = None) -> None: -//| """Erase and re-create the ``CIRCUITPY`` filesystem. +//| """Erase and re-create the **CIRCUITPY** filesystem. //| -//| On boards that present USB-visible ``CIRCUITPY`` drive (e.g., SAMD21 and SAMD51), +//| On boards that present USB-visible **CIRCUITPY** drive (e.g., SAMD21 and SAMD51), //| then call `microcontroller.reset()` to restart CircuitPython and have the -//| host computer remount CIRCUITPY. +//| host computer remount **CIRCUITPY**. //| -//| This function can be called from the REPL when ``CIRCUITPY`` +//| This function can be called from the REPL when **CIRCUITPY** //| has become corrupted. //| //| :param bool extended: On boards that support ``dualbank`` module -//| and the ``extended`` parameter, the ``CIRCUITPY`` storage can be +//| and the ``extended`` parameter, the **CIRCUITPY** storage can be //| extended by setting this to `True`. If this isn't provided or //| set to `None` (default), the existing configuration will be used. //| //| .. note:: New firmware starts with storage extended. In case of an existing //| filesystem (e.g. uf2 load), the existing extension setting is preserved. //| -//| .. warning:: All the data on ``CIRCUITPY`` will be lost, and +//| .. warning:: All the data on **CIRCUITPY** will be lost, and //| CircuitPython will restart on certain boards.""" //| ... //| @@ -187,8 +187,8 @@ static mp_obj_t storage_erase_filesystem(size_t n_args, const mp_obj_t *pos_args MP_DEFINE_CONST_FUN_OBJ_KW(storage_erase_filesystem_obj, 0, storage_erase_filesystem); //| def disable_usb_drive() -> None: -//| """Disable presenting ``CIRCUITPY`` as a USB mass storage device. -//| By default, the device is enabled and ``CIRCUITPY`` is visible, if USB is available. +//| """Disable presenting **CIRCUITPY** as a USB mass storage device. +//| By default, the device is enabled and **CIRCUITPY** is visible, if USB is available. //| Must called in ``boot.py``, before USB is connected. // If you want to disable the USB drive after `boot.py` has run, see `unsafe_disable_usb_drive()`. //| """ @@ -208,13 +208,39 @@ static mp_obj_t storage_disable_usb_drive(void) { MP_DEFINE_CONST_FUN_OBJ_0(storage_disable_usb_drive_obj, storage_disable_usb_drive); //| def unsafe_disable_usb_drive() -> None: -//| """Disable presenting ``CIRCUITPY`` as a USB mass storage device. -//| By default, the device is enabled and ``CIRCUITPY`` is visible. +//| """Disable presenting **CIRCUITPY** as a USB mass storage device. +//| By default, the device is enabled and **CIRCUITPY** is visible. +//| After the call, **CIRCUITPY** will be read/write to your code or from the REPL. +//| //| Unlike `disable_usb_drive()`, `unsafe_disable_usb_drive()` can be called //| after ``code.py`` starts or from the REPL, after USB has started. //| -//| When `unsafe_disable_usb_drive()` after USB has started, -//| the ``CIRCUITPY`` USB drive logical unit (LUN) will report as "not ready", +//| .. warning:: If ``unsafe_disable_usb_drive()`` is called when the host is actively writing **CIRCUITPY**, +//| filesystem corruption can occur. +//| It is similar to the sudden physical removal of a USB drive. +//| Before calling ``unsafe_disable_usb_drive()``, +//| make sure the host has finished any writes to **CIRCUITPY**. +//| +//| * On Windows, do one of these: +//| +//| * Eject ("Safely Remove") the **CIRCUITPY** drive. +//| * Use a "sync" program, such as `Sysinternals Sync `__. +//| * Programmatically call ``_commit()`` or ``_flushall()`` or similar. +//| +//| * On Linux or macOS, do one of these: +//| +//| * Eject (unmount) the **CIRCUITPY** drive. +//| * Type ``sync`` in a terminal. +//| * Programmatically call ``sync()`` or ``fsync()``. +//| +//| * If none of the above are possible or convenient, wait several seconds to allow any writes to complete. +//| This can be unreliable, as the interval to wait depends on the host operating system +//| and how the drive is mounted. +//| In some operating systems, you can specify that the drive be mounted as "sync on write", +//| so that all writes happen immediately. +//| +//| When `unsafe_disable_usb_drive()` is called after USB has started, +//| the **CIRCUITPY** USB drive logical unit (LUN) will report as "not ready", //| causing the host to unmount it. //| The drive can be made ready and available again by calling `enable_usb_drive()`. //| When `disable_usb_drive` is called after ``code.py`` starts or in the REPL, @@ -222,10 +248,7 @@ MP_DEFINE_CONST_FUN_OBJ_0(storage_disable_usb_drive_obj, storage_disable_usb_dri //| so that host has time to detect that the drive is not ready. //| The host polls the device approximately every one or two seconds. //| -//| Note that if ``unsafe_disable_usb_drive()`` is called when the host is actively writing CIRCUITPY, -//| filesystem corruption could occur. Be careful to call it when the host is quiescent. -//| -//| When the USB drive is disabled, CIRCUITPY becomes read/write, and can be written +//| When the USB drive is disabled, **CIRCUITPY** becomes read/write, and can be written //| from user code or the REPL. This is easier than arranging for a `remount()` in ``boot.py``. //| Code editors and file uploaders can use this feature to write files via the REPL. //| @@ -248,13 +271,13 @@ static mp_obj_t storage_unsafe_disable_usb_drive(void) { MP_DEFINE_CONST_FUN_OBJ_0(storage_unsafe_disable_usb_drive_obj, storage_unsafe_disable_usb_drive); //| def enable_usb_drive() -> None: -//| """Enable presenting ``CIRCUITPY`` as a USB mass storage device. -//| By default, the device is enabled and ``CIRCUITPY`` is visible, +//| """Enable presenting **CIRCUITPY** as a USB mass storage device. +//| By default, the device is enabled and **CIRCUITPY** is visible, //| so you do not normally need to call this function in ``boot.py``. //| //| If you call `enable_usb_drive()` after ``code.py`` starts or in the REPL, //| you can reverse the effect of a previous `unsafe_disable_usb_drive()`. -//| The CIRCUITPY drive will reappear to the host, and become read-only again +//| The **CIRCUITPY** drive will reappear to the host, and become read-only again //| if it was previously read-only. //| //| If you enable too many USB devices at once, you will run out of USB endpoints. From ee34f8a1e69a3a9e9d1d20998daf4cd9c1493436 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 22 Jul 2026 13:00:39 -0400 Subject: [PATCH 688/876] Apply suggestions from code review Co-authored-by: Scott Shawcroft --- shared-bindings/storage/__init__.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/shared-bindings/storage/__init__.c b/shared-bindings/storage/__init__.c index 8bd43686694..b5f19529be1 100644 --- a/shared-bindings/storage/__init__.c +++ b/shared-bindings/storage/__init__.c @@ -208,14 +208,14 @@ static mp_obj_t storage_disable_usb_drive(void) { MP_DEFINE_CONST_FUN_OBJ_0(storage_disable_usb_drive_obj, storage_disable_usb_drive); //| def unsafe_disable_usb_drive() -> None: -//| """Disable presenting **CIRCUITPY** as a USB mass storage device. +//| """Disable presenting **CIRCUITPY** as a USB mass storage device even if in use. //| By default, the device is enabled and **CIRCUITPY** is visible. -//| After the call, **CIRCUITPY** will be read/write to your code or from the REPL. +//| After the call, **CIRCUITPY** will be read/write to your code and from the REPL but not appear over USB. //| //| Unlike `disable_usb_drive()`, `unsafe_disable_usb_drive()` can be called //| after ``code.py`` starts or from the REPL, after USB has started. //| -//| .. warning:: If ``unsafe_disable_usb_drive()`` is called when the host is actively writing **CIRCUITPY**, +//| .. warning:: If ``unsafe_disable_usb_drive()`` is called when the host is in the middle of writing **CIRCUITPY**, //| filesystem corruption can occur. //| It is similar to the sudden physical removal of a USB drive. //| Before calling ``unsafe_disable_usb_drive()``, From 355a5b402c3317747493364259fbb09a6c5109df Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 23 Jul 2026 09:32:49 -0500 Subject: [PATCH 689/876] implement duplex I2S, add TE EP-2350 ting board def, Chorus docs example improvement --- locale/circuitpython.pot | 14 +- .../atmel-samd/common-hal/audiobusio/I2SOut.c | 6 +- .../espressif/common-hal/audiobusio/I2SOut.c | 6 +- ports/espressif/common-hal/audioi2sin/I2SIn.c | 14 +- .../mimxrt10xx/common-hal/audiobusio/I2SOut.c | 6 +- ports/nordic/common-hal/audiobusio/I2SOut.c | 6 +- .../boards/teenage_engineering_ep2350/board.c | 48 ++++++ .../mpconfigboard.h | 20 +++ .../mpconfigboard.mk | 20 +++ .../pico-sdk-configboard.h | 7 + .../boards/teenage_engineering_ep2350/pins.c | 115 ++++++++++++++ .../common-hal/audiobusio/I2SOut.c | 106 ++++++++++++- .../common-hal/audiobusio/I2SOut.h | 1 + .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 147 ++++++++++++++++-- .../raspberrypi/common-hal/audioi2sin/I2SIn.h | 1 + .../common-hal/audioi2sin/i2sin.pio | 8 +- .../common-hal/audioi2sin/i2sin_32.pio | 8 +- .../common-hal/audioi2sin/i2sin_left.pio | 2 +- .../common-hal/audioi2sin/i2sin_left_32.pio | 2 +- .../common-hal/audioi2sin/i2sin_swap.pio | 2 +- .../common-hal/audioi2sin/i2sin_swap_32.pio | 2 +- .../common-hal/audioi2sin/i2sin_swap_left.pio | 2 +- .../audioi2sin/i2sin_swap_left_32.pio | 2 +- .../common-hal/rp2pio/StateMachine.c | 119 +++++++++++--- .../common-hal/rp2pio/StateMachine.h | 1 + .../zephyr-cp/common-hal/audiobusio/I2SOut.c | 6 +- shared-bindings/audiobusio/I2SOut.c | 29 +++- shared-bindings/audiobusio/I2SOut.h | 2 +- shared-bindings/audiodelays/Chorus.c | 2 +- shared-bindings/audioi2sin/I2SIn.c | 65 +++++++- shared-bindings/audioi2sin/I2SIn.h | 5 +- 31 files changed, 697 insertions(+), 77 deletions(-) create mode 100644 ports/raspberrypi/boards/teenage_engineering_ep2350/board.c create mode 100644 ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.h create mode 100644 ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.mk create mode 100644 ports/raspberrypi/boards/teenage_engineering_ep2350/pico-sdk-configboard.h create mode 100644 ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index bc0286dfe61..8640ff1078c 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1843,6 +1843,12 @@ msgstr "" msgid "Touch alarms not available" msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "" + #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" @@ -1998,10 +2004,6 @@ msgstr "" msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" - #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" msgstr "" @@ -3741,6 +3743,10 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q requires %q" +msgstr "" + #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" diff --git a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c index 178db2f07d0..a1e7f00dd0f 100644 --- a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c +++ b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c @@ -77,7 +77,11 @@ void i2sout_reset(void) { // Caller validates that pins are free. void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool clock_follower) { + if (clock_follower) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + } if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } diff --git a/ports/espressif/common-hal/audiobusio/I2SOut.c b/ports/espressif/common-hal/audiobusio/I2SOut.c index adfc081389a..67b9300b57c 100644 --- a/ports/espressif/common-hal/audiobusio/I2SOut.c +++ b/ports/espressif/common-hal/audiobusio/I2SOut.c @@ -28,7 +28,11 @@ // Caller validates that pins are free. void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool clock_follower) { + if (clock_follower) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + } port_i2s_allocate_init(&self->i2s, left_justified); i2s_std_config_t i2s_config = { diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index ef8e908e2de..d3c89958a4d 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -24,7 +24,11 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, - bool mono, bool left_justified, bool samples_signed) { + bool mono, bool left_justified, bool samples_signed, + bool clock_follower, bool invert_bit_clock) { + if (clock_follower) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + } i2s_data_bit_width_t bit_width = (i2s_data_bit_width_t)bit_depth; @@ -320,6 +324,14 @@ bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self return self->samples_signed; } +// Always false here: this port hands the capture ring to the IDF driver, which +// drops frames internally without telling us. Detecting it would require +// registering an on_recv_q_ovf callback on the channel. +bool common_hal_audioi2sin_i2sin_get_overflow(audioi2sin_i2sin_obj_t *self) { + (void)self; + return false; +} + // Write `count` silence samples at output depth starting at sample index `idx`. // For signed PCM silence is 0; for unsigned (WAV) it is mid-scale. static void i2sin_fill_silence(void *buffer, uint32_t idx, uint32_t count, diff --git a/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c b/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c index c785f4e090e..b5d308fa896 100644 --- a/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c +++ b/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c @@ -53,7 +53,11 @@ static void config_periph_pin(const mcu_periph_obj_t *periph) { // Caller validates that pins are free. void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool clock_follower) { + if (clock_follower) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + } int instance = -1; const mcu_periph_obj_t *bclk_periph = find_pin_function(mcu_i2s_tx_bclk_list, bit_clock, &instance, MP_QSTR_bit_clock); diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.c b/ports/nordic/common-hal/audiobusio/I2SOut.c index 00b34e17e82..d70653059a9 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.c +++ b/ports/nordic/common-hal/audiobusio/I2SOut.c @@ -189,7 +189,11 @@ static void i2s_buffer_fill(audiobusio_i2sout_obj_t *self) { void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool clock_follower) { + if (clock_follower) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + } if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/board.c b/ports/raspberrypi/boards/teenage_engineering_ep2350/board.c new file mode 100644 index 00000000000..982ebb6deb1 --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/board.c @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +#include "mpconfigboard.h" +#include "common-hal/microcontroller/Pin.h" +#include "hardware/gpio.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. + +static void assert_power_hold(void) { + // Doing this (rather than gpio_init()) in this specific order ensures no + // glitch if the pin was already configured as a high output. gpio_init() + // temporarily configures the pin as an input, which would release the + // latch and power the board off. + gpio_put(MICROPY_HW_POWER_HOLD_PIN_NUMBER, 1); + gpio_set_dir(MICROPY_HW_POWER_HOLD_PIN_NUMBER, GPIO_OUT); + gpio_set_function(MICROPY_HW_POWER_HOLD_PIN_NUMBER, GPIO_FUNC_SIO); +} + +// Forward declaration to satisfy -Wmissing-prototypes +static void preinit_power_hold(void) __attribute__((constructor(101))); + +// Runs before main(), so the latch is set as early as it can possibly be. +static void preinit_power_hold(void) { + assert_power_hold(); +} + +// The EP-2350 has no power switch: pressing the handle applies power directly, +// and firmware must set the power hold latch on GPIO2 before the handle is +// released or the unit dies. The latch is a true set/reset latch, so a single +// high pulse is enough, but the pin must never be left low. +// +// reset_all_pins() runs this for every pin at startup and again on every soft +// reload, so the latch is re-asserted instead of being reset to an input. The +// pin is deliberately not claimed with never_reset(), so user code can still +// take board.POWER_HOLD and drive it low to power the unit off. +bool board_reset_pin_number(uint8_t pin_number) { + if (pin_number == MICROPY_HW_POWER_HOLD_PIN_NUMBER) { + assert_power_hold(); + return true; + } + return false; +} diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.h b/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.h new file mode 100644 index 00000000000..fc3ad16bdc2 --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.h @@ -0,0 +1,20 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +#define MICROPY_HW_BOARD_NAME "Teenage Engineering ting fx EP-2350" +#define MICROPY_HW_MCU_NAME "rp2350a" + +// Top white LED. Also available as board.LED_WHITE1. +#define MICROPY_HW_LED_STATUS (&pin_GPIO0) + +// GPIO2 is the power hold latch: high keeps the unit powered, low powers it +// off immediately. It is asserted in board_reset_pin_number() so that it +// survives every pin reset. +#define MICROPY_HW_POWER_HOLD_PIN_NUMBER (2) + +// Codec (0x1b) and accelerometer (0x18) share I2C1. External pull-ups. +#define CIRCUITPY_BOARD_I2C (1) +#define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO15, .sda = &pin_GPIO14}} diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.mk b/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.mk new file mode 100644 index 00000000000..704edf815e6 --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/mpconfigboard.mk @@ -0,0 +1,20 @@ +USB_VID = 0x239A +USB_PID = 0x8176 +USB_PRODUCT = "ting fx EP-2350" +USB_MANUFACTURER = "Teenage Engineering" + +CHIP_VARIANT = RP2350 +CHIP_PACKAGE = A +CHIP_FAMILY = rp2 + +# Winbond W25Q16JV, 2MB (16Mbit) on CS0, nothing on CS1. +EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" + +# Only 2MB of flash: firmware gets the default 1020kB and the CIRCUITPY drive +# gets the rest (~1MB). + +# GPIO12-19 are needed for picodvi, but they are all in use here (I2S, I2C, +# LEDs, handle switches) and no pins are broken out. +CIRCUITPY_PICODVI = 0 + +CIRCUITPY__EVE = 1 diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/pico-sdk-configboard.h b/ports/raspberrypi/boards/teenage_engineering_ep2350/pico-sdk-configboard.h new file mode 100644 index 00000000000..f72de7902c9 --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/pico-sdk-configboard.h @@ -0,0 +1,7 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +// Put board-specific pico-sdk definitions here. This file must exist. diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c new file mode 100644 index 00000000000..0468c52e5fe --- /dev/null +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c @@ -0,0 +1,115 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + // LEDs, one dedicated GPIO each, active high. + // Two columns of four, numbered top (nearest the handle) to bottom. + // Note: GP0 and GP16 share a PWM slice/channel, so the their LEDs + // cannot be PWM-dimmed independently. + { MP_ROM_QSTR(MP_QSTR_GP0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LED_WHITE1), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_GP6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_LED_WHITE2), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_GP4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_LED_WHITE3), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_GP5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_LED_WHITE4), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_GP16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_LED_RED1), MP_ROM_PTR(&pin_GPIO16) }, + + { MP_ROM_QSTR(MP_QSTR_GP24), MP_ROM_PTR(&pin_GPIO24) }, + { MP_ROM_QSTR(MP_QSTR_LED_RED2), MP_ROM_PTR(&pin_GPIO24) }, + + { MP_ROM_QSTR(MP_QSTR_GP18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_LED_RED3), MP_ROM_PTR(&pin_GPIO18) }, + + { MP_ROM_QSTR(MP_QSTR_GP17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_LED_RED4), MP_ROM_PTR(&pin_GPIO17) }, + + // Side buttons. Switches to ground, no external pull-ups: use Pull.UP, + // pressed reads False. + { MP_ROM_QSTR(MP_QSTR_GP21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_TOP), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_GP3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_MIDDLE), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_GP1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BUTTON_BOTTOM), MP_ROM_PTR(&pin_GPIO1) }, + + // Handle: a two-stage switch. HANDLE_IN reads False when the handle is + // fully seated; HANDLE_HELD reads True as soon as the handle is moved. + { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_HANDLE_IN), MP_ROM_PTR(&pin_GPIO19) }, + + { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_HANDLE_HELD), MP_ROM_PTR(&pin_GPIO20) }, + + // Power hold latch. Held high by the board so the unit stays powered once + // the handle is released. Driving it low powers the unit off immediately. + { MP_ROM_QSTR(MP_QSTR_GP2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_POWER_HOLD), MP_ROM_PTR(&pin_GPIO2) }, + + // I2C1: NAU88L21 codec at 0x1b, accelerometer at 0x18. External pull-ups. + { MP_ROM_QSTR(MP_QSTR_GP14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO14) }, + + { MP_ROM_QSTR(MP_QSTR_GP15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO15) }, + + // I2S to the codec. The codec is the I2S clock source (it drives BCLK and + // LRCLK); the MCU only supplies MCLK. + { MP_ROM_QSTR(MP_QSTR_GP8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DIN), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_GP9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_I2S_DOUT), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_ROM_PTR(&pin_GPIO10) }, + + { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_ROM_PTR(&pin_GPIO11) }, + + { MP_ROM_QSTR(MP_QSTR_GP12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_I2S_MCLK), MP_ROM_PTR(&pin_GPIO12) }, + + // Unidentified / unconnected. + { MP_ROM_QSTR(MP_QSTR_GP7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_GP13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_GP22), MP_ROM_PTR(&pin_GPIO22) }, + { MP_ROM_QSTR(MP_QSTR_GP23), MP_ROM_PTR(&pin_GPIO23) }, + { MP_ROM_QSTR(MP_QSTR_GP25), MP_ROM_PTR(&pin_GPIO25) }, + + // Analog. GP26/GP27 are unconnected. + { MP_ROM_QSTR(MP_QSTR_GP26), MP_ROM_PTR(&pin_GPIO26) }, + { MP_ROM_QSTR(MP_QSTR_A0), MP_ROM_PTR(&pin_GPIO26) }, + + { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, + { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, + + // Rail sense through a resistive divider (VSYS/VBAT / 2). + { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO28) }, + + // Volume potentiometer wiper, full scale 0 - 3.3V. + { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_A3), MP_ROM_PTR(&pin_GPIO29) }, + { MP_ROM_QSTR(MP_QSTR_VOLUME), MP_ROM_PTR(&pin_GPIO29) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c index d29f50b06b8..7646cec9c27 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c @@ -167,21 +167,100 @@ const uint16_t i2s_program_left_justified_swap[] = { 0x6201, // 9: out pins, 1 side 0 [2] }; +// Clock-follower TX. BCLK and WS are inputs driven by something +// else, so the state machine side-sets nothing and waits on the two clocks +// instead. `wait gpio` encodes an absolute pin index, so unlike the clock-source +// programs above this one cannot be a static table: it is assembled at +// construct time with the pin numbers patched in. +// +// 0: wait 0 gpio W +// 1: wait 1 gpio W ; right channel starts (WS changes on a BCLK fall) +// .wrap_target +// 2: pull noblock ; refills OSR from X on underflow, as the clock-source program does +// 3: mov x, osr +// 4: set y, 31 +// 5: wait 1 gpio B +// 6: wait 0 gpio B ; drive on the falling edge; receiver latches on rising +// 7: out pins, 1 +// 8: jmp y--, 5 +// .wrap +// +// Left-justified moves the `out` ahead of the two waits, which drives the MSB +// on the same falling edge WS changed on. The first loop iteration's `wait 1` +// otherwise lands on the Philips delay bit, so no pre-roll is needed. +// +// One 32-bit FIFO word covers a whole 16-bit stereo frame; at 24/32 bits the +// frame is two words (right then left). Same layout the clock-source programs use. +#define I2S_FOLLOWER_PROGRAM_LEN (9) +#define I2S_FOLLOWER_WRAP_TARGET (2) +#define I2S_FOLLOWER_WRAP (8) + +static void build_i2sout_follower_program(uint16_t *prog, uint8_t bclk, uint8_t ws, bool left_justified) { + const uint16_t wait_0_bclk = 0x2000 | bclk; + const uint16_t wait_1_bclk = 0x2080 | bclk; + prog[0] = 0x2000 | ws; // wait 0 gpio W + prog[1] = 0x2080 | ws; // wait 1 gpio W + prog[2] = 0x8080; // pull noblock + prog[3] = 0xa027; // mov x, osr + prog[4] = 0xe05f; // set y, 31 + if (left_justified) { + prog[5] = 0x6001; // out pins, 1 + prog[6] = wait_1_bclk; + prog[7] = wait_0_bclk; + } else { + prog[5] = wait_1_bclk; + prog[6] = wait_0_bclk; + prog[7] = 0x6001; // out pins, 1 + } + prog[8] = 0x0080 | 5; // jmp y--, 5 +} + +// `wait gpio` indices are relative to the PIO's GPIO base, which +// rp2pio_statemachine_construct picks the same way. +static uint8_t i2s_wait_gpio_index(const mcu_pin_obj_t *pin, uint8_t gpio_offset) { + if (pin->number < gpio_offset) { + mp_raise_ValueError(MP_ERROR_TEXT("Cannot use GPIO0..15 together with GPIO32..47")); + } + return pin->number - gpio_offset; +} + void i2sout_reset(void) { } // Caller validates that pins are free. void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool clock_follower) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } const mcu_pin_obj_t *sideset_pin = NULL; const uint16_t *program = NULL; size_t program_len = 0; - - if (bit_clock->number == word_select->number - 1) { + uint16_t follower_program[I2S_FOLLOWER_PROGRAM_LEN]; + pio_pinmask_t wait_gpio_mask = PIO_PINMASK_NONE; + + self->clock_follower = clock_follower; + + if (clock_follower) { + // As a clock follower the clocks are `wait gpio` targets, so they + // need not be sequential GPIOs. + uint8_t gpio_offset = 0; + #if NUM_BANK0_GPIOS > 32 + if (bit_clock->number >= 32 || word_select->number >= 32 || data->number >= 32) { + gpio_offset = 16; + } + #endif + build_i2sout_follower_program(follower_program, + i2s_wait_gpio_index(bit_clock, gpio_offset), + i2s_wait_gpio_index(word_select, gpio_offset), + left_justified); + program = follower_program; + program_len = I2S_FOLLOWER_PROGRAM_LEN; + wait_gpio_mask = PIO_PINMASK_OR(PIO_PINMASK_FROM_PIN(bit_clock->number), + PIO_PINMASK_FROM_PIN(word_select->number)); + } else if (bit_clock->number == word_select->number - 1) { sideset_pin = bit_clock; if (left_justified) { @@ -211,23 +290,28 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, common_hal_rp2pio_statemachine_construct( &self->state_machine, program, program_len, - 44100 * 32 * 6, // Clock at 44.1 khz to warm the DAC up. + // Clock at 44.1 khz to warm the DAC up. As a clock follower the SM + // is driven by the waits, not the clock divider, so run it at sysclk. + clock_follower ? 0 : 44100 * 32 * 6, NULL, 0, // init NULL, 0, // may_exec data, 1, PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // out pin NULL, 0, // in pins PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // in pulls NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // set pins - sideset_pin, 2, false, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // sideset pins + sideset_pin, sideset_pin == NULL ? 0 : 2, false, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // sideset pins false, // No sideset enable NULL, PULL_NONE, // jump pin - PIO_PINMASK_NONE, // wait gpio pins + wait_gpio_mask, // wait gpio pins + // The clocks are shared through wait_gpio_mask, which _check_gpio_mask_free + // already allows to be shared; the data pin stays exclusively ours. true, // exclusive pin use false, 32, false, // shift out left to start with MSB false, // Wait for txstall false, 32, false, // in settings false, // Not user-interruptible. - 0, -1, // wrap settings + clock_follower ? I2S_FOLLOWER_WRAP_TARGET : 0, + clock_follower ? I2S_FOLLOWER_WRAP : -1, // wrap settings PIO_ANY_OFFSET, PIO_FIFO_TYPE_DEFAULT, PIO_MOV_STATUS_DEFAULT, @@ -278,7 +362,13 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, mp_raise_ValueError(MP_ERROR_TEXT("Too many channels in sample.")); } - common_hal_rp2pio_statemachine_set_frequency(&self->state_machine, clocks_per_bit * frequency); + // An external clock can't be retimed: the sample rate has to match whatever + // the outside world is running WS at, or the pitch is wrong. The restart + // still matters -- it re-execs the program at its offset, so every play() + // re-syncs to WS. + if (!self->clock_follower) { + common_hal_rp2pio_statemachine_set_frequency(&self->state_machine, clocks_per_bit * frequency); + } common_hal_rp2pio_statemachine_restart(&self->state_machine); // On the RP2040, output registers are always written with a 32-bit write. diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.h b/ports/raspberrypi/common-hal/audiobusio/I2SOut.h index 2996640dc2d..1ac277958de 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.h +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.h @@ -18,6 +18,7 @@ typedef struct { rp2pio_statemachine_obj_t state_machine; audio_dma_t dma; bool left_justified; + bool clock_follower; bool playing; } audiobusio_i2sout_obj_t; diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 8bdc4cfeb3b..33ad3e6840b 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -31,14 +31,14 @@ // MEMS mics (SPH0645LM4H, INMP441, ICS-43434) transmit their 24 valid bits // left-justified inside a 32-bit slot. // -// `in pins 1` runs on a cycle where side-set drives BCLK high. The slave -// updates the data line on the BCLK falling edge, so by the rising edge it +// `in pins 1` runs on a cycle where side-set drives BCLK high. The follower +// device updates the data line on the BCLK falling edge, so by the rising edge it // has settled and is safe to sample. Sampling at BCLK low (the previous, // incorrect arrangement) catches the data mid-transition and the result is // effectively noise. #define PIO_CLOCKS_PER_BIT (6) -// Master-mode RX, regular pin order (BCLK = WS - 1), Philips alignment. +// Clock-source RX, regular pin order (BCLK = WS - 1), Philips alignment. static const uint16_t i2sin_program[] = { 0xb842, // 0: nop side 3 // .wrap_target @@ -57,7 +57,7 @@ static const uint16_t i2sin_program[] = { // .wrap }; -// Master-mode RX, regular pin order, left-justified. +// Clock-source RX, regular pin order, left-justified. static const uint16_t i2sin_program_left_justified[] = { 0xa842, // 0: nop side 1 // .wrap_target @@ -76,7 +76,7 @@ static const uint16_t i2sin_program_left_justified[] = { // .wrap }; -// Master-mode RX, swapped pin order (BCLK = WS + 1), Philips alignment. +// Clock-source RX, swapped pin order (BCLK = WS + 1), Philips alignment. static const uint16_t i2sin_program_swap[] = { 0xb842, // 0: nop side 3 // .wrap_target @@ -95,7 +95,7 @@ static const uint16_t i2sin_program_swap[] = { // .wrap }; -// Master-mode RX, swapped pin order, left-justified. +// Clock-source RX, swapped pin order, left-justified. static const uint16_t i2sin_program_left_justified_swap[] = { 0xb042, // 0: nop side 2 // .wrap_target @@ -189,12 +189,80 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { // .wrap }; +// Clock-follower RX. BCLK and WS are inputs driven by something +// else -- another I2S object or the codec -- so the state machine side-sets +// nothing and waits on the two clocks instead. `wait gpio` encodes an absolute +// pin index, so unlike the clock-source programs above this one is assembled at +// construct time with the pin numbers patched in. +// +// 0: wait 0 gpio W ; resync: find a WS rising edge, i.e. the start +// 1: wait 1 gpio W ; of the RIGHT channel (matches word order) +// .wrap_target +// 2: set y, 31 +// 3: wait 0 gpio B ; data changes here +// 4: wait 1 gpio B ; ...and is settled here +// 5: in pins, 1 +// 6: jmp y--, 3 +// .wrap +// +// `set y, 31` + `jmp y--` runs the loop exactly 32 times, so with auto-push at +// 32 and shift-left this pushes one 32-bit word per 32 BCLK, MSB first -- +// identical to what the clock-source programs produce, so record_to_buffer and +// fill_buffer need no changes. One template covers every bit_depth: at 16 bits +// a 32-BCLK frame is one push (right<<16 | left), at 24/32 a 64-BCLK frame is +// two pushes (right then left). +// +// The resync's own `wait 0/1 gpio B` already lands on the first data bit, so +// against a CircuitPython clock source this program recovers the transmitted word +// bit-exactly with no instruction for the Philips delay bit. The +// `left_justified` variant is that program plus one more BCLK of skew, +// the other of the two possible alignments; +// +// Free-running after the initial sync: the external frame must be exactly +// 2 x bits_per_channel BCLKs, the same assumption clock-source mode already bakes +// in. If sync is lost it stays lost. +#define I2SIN_FOLLOWER_MAX_PROGRAM_LEN (8) +// The bit loop is the last 5 instructions; everything before it is one-shot sync. +#define I2SIN_FOLLOWER_WRAP_TARGET(len) ((int)(len) - 5) + +static size_t build_i2sin_follower_program(uint16_t *prog, uint8_t bclk, uint8_t ws, + bool left_justified, bool invert_bit_clock) { + // Sampling on the falling edge of BCLK is the same program with the + // polarity of every BCLK wait flipped. + const uint16_t invert = invert_bit_clock ? 0x0080 : 0x0000; + const uint16_t wait_0_bclk = (0x2000 | bclk) ^ invert; + const uint16_t wait_1_bclk = (0x2080 | bclk) ^ invert; + size_t len = 0; + prog[len++] = 0x2000 | ws; // wait 0 gpio W + prog[len++] = 0x2080 | ws; // wait 1 gpio W + if (left_justified) { + prog[len++] = wait_1_bclk; // one more BCLK of skew + } + const size_t bitloop = len + 1; + prog[len++] = 0xe05f; // set y, 31 + prog[len++] = wait_0_bclk; + prog[len++] = wait_1_bclk; + prog[len++] = 0x4001; // in pins, 1 + prog[len++] = 0x0080 | bitloop; // jmp y--, bitloop + return len; +} + +// `wait gpio` indices are relative to the PIO's GPIO base, which +// rp2pio_statemachine_construct picks the same way. +static uint8_t i2s_wait_gpio_index(const mcu_pin_obj_t *pin, uint8_t gpio_offset) { + if (pin->number < gpio_offset) { + mp_raise_ValueError(MP_ERROR_TEXT("Cannot use GPIO0..15 together with GPIO32..47")); + } + return pin->number - gpio_offset; +} + // Caller validates that pins are free. void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, - bool mono, bool left_justified, bool samples_signed) { + bool mono, bool left_justified, bool samples_signed, + bool clock_follower, bool invert_bit_clock) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); @@ -212,8 +280,26 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *sideset_pin = NULL; const uint16_t *program = NULL; size_t program_len = 0; - - if (bit_clock->number == word_select->number - 1) { + uint16_t follower_program[I2SIN_FOLLOWER_MAX_PROGRAM_LEN]; + pio_pinmask_t wait_gpio_mask = PIO_PINMASK_NONE; + + if (clock_follower) { + // As a clock follower the clocks are `wait gpio` targets, so they + // need not be sequential GPIOs. + uint8_t gpio_offset = 0; + #if NUM_BANK0_GPIOS > 32 + if (bit_clock->number >= 32 || word_select->number >= 32 || data->number >= 32) { + gpio_offset = 16; + } + #endif + program_len = build_i2sin_follower_program(follower_program, + i2s_wait_gpio_index(bit_clock, gpio_offset), + i2s_wait_gpio_index(word_select, gpio_offset), + left_justified, invert_bit_clock); + program = follower_program; + wait_gpio_mask = PIO_PINMASK_OR(PIO_PINMASK_FROM_PIN(bit_clock->number), + PIO_PINMASK_FROM_PIN(word_select->number)); + } else if (bit_clock->number == word_select->number - 1) { sideset_pin = bit_clock; if (left_justified) { program = wide ? i2sin_program_left_justified_32 : i2sin_program_left_justified; @@ -242,34 +328,45 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, common_hal_rp2pio_statemachine_construct( &self->state_machine, program, program_len, - sample_rate * pio_clocks_per_frame, + // As a clock follower the SM is driven by the waits, not the clock + // divider, so run it at sysclk. + clock_follower ? 0 : sample_rate *pio_clocks_per_frame, NULL, 0, // init NULL, 0, // may_exec NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // out pin data, 1, // in pins PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // in pulls NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // set pins - sideset_pin, 2, false, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // sideset pins + sideset_pin, sideset_pin == NULL ? 0 : 2, false, PIO_PINMASK32_NONE, PIO_PINMASK32_FROM_VALUE(0x1f), // sideset pins false, // No sideset enable NULL, PULL_NONE, // jump pin - PIO_PINMASK_NONE, // wait gpio pins + wait_gpio_mask, // wait gpio pins + // The clocks are shared through wait_gpio_mask, which _check_gpio_mask_free + // already allows to be shared; the data pin stays exclusively ours. true, // exclusive pin use false, 32, false, // out settings (unused) false, // Wait for txstall true, 32, false, // in settings: auto-push at 32 bits, shift left (MSB first) false, // Not user-interruptible. - 1, -1, // wrap settings + clock_follower ? I2SIN_FOLLOWER_WRAP_TARGET(program_len) : 1, + clock_follower ? (int)program_len - 1 : -1, // wrap settings PIO_ANY_OFFSET, PIO_FIFO_TYPE_DEFAULT, PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); - uint32_t actual_frequency = common_hal_rp2pio_statemachine_get_frequency(&self->state_machine); - self->sample_rate = actual_frequency / pio_clocks_per_frame; + // As a clock follower the SM runs at sysclk and the real rate is + // whatever the outside world drives WS at, so `sample_rate` is a + // declaration rather than a measurement. A mismatch shows up as the same + // slow drift the underrun-pad / overflow-drop paths in fill_buffer absorb. + self->sample_rate = clock_follower + ? sample_rate + : common_hal_rp2pio_statemachine_get_frequency(&self->state_machine) / pio_clocks_per_frame; self->bit_depth = bit_depth; self->mono = mono; self->samples_signed = samples_signed; self->left_justified = left_justified; + self->clock_follower = clock_follower; self->settled = false; self->ring = NULL; self->ring_size = 0; @@ -369,6 +466,15 @@ bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self return self->samples_signed; } +// The flag latches when record_to_buffer or fill_buffer finds the DMA more than +// a half-buffer ahead of the read cursor and has to skip forward. Reading clears +// it so a streaming consumer can attribute each report to a known interval. +bool common_hal_audioi2sin_i2sin_get_overflow(audioi2sin_i2sin_obj_t *self) { + bool overflow = self->overflow; + self->overflow = false; + return overflow; +} + // In 16-bit mode, each PIO frame produces a single 32-bit FIFO word with bits // 31..16 = right channel and bits 15..0 = left channel (both MSB-first signed // 16-bit). In 24/32-bit mode each frame produces two FIFO words: right first, @@ -709,6 +815,17 @@ void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, } } self->output_index = 0; + // A clock-follower SM free-runs a 32-BCLK counter from the WS edge it + // synced to at construct time, so anything that disturbs the frame leaves + // it locked to the wrong half-frame or the wrong bit for good. Re-exec the + // program here so playback always begins from a fresh WS sync. A clock source + // generates its own clocks and has nothing to sync to, so leave it alone. + if (self->clock_follower) { + common_hal_rp2pio_statemachine_restart(&self->state_machine); + // restart() clears the shift counters but not the RX FIFO, and the + // words still sitting in it were captured with the old alignment. + pio_sm_clear_fifos(self->state_machine.pio, self->state_machine.state_machine); + } // Resync to live audio: snap the read cursor just behind the DMA write head // (frame-aligned) and re-settle so playback begins on fresh samples. size_t write_pos = i2sin_write_pos(self); diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h index bd5cdea577e..d09def91cc1 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -27,6 +27,7 @@ typedef struct { bool mono; bool samples_signed; bool left_justified; + bool clock_follower; bool settled; rp2pio_statemachine_obj_t state_machine; // Background DMA ring buffer. The state machine alternates DMA writes diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio index 97dc9c7f7e9..ec8906bbd2c 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio @@ -7,11 +7,11 @@ .program i2sin .side_set 2 -; Master-mode I2S RX. Generates BCLK and LRCLK via side-set and samples the -; data pin. The slave updates `data` on BCLK falling edge, so the master -; samples on the rising edge: every `in pins 1` runs on a side-set value +; Clock-source I2S RX. Generates BCLK and LRCLK via side-set and samples the +; data pin. The follower device updates `data` on BCLK falling edge, so this +; program samples on the rising edge: every `in pins 1` runs on a side-set value ; with BCLK=1, and the loop/transition instructions hold BCLK=0 so the -; slave has time to settle the next bit. +; follower has time to settle the next bit. ; /--- LRCLK ; |/-- BCLK ; || diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio index f09a02a85c2..ab59688defd 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio @@ -7,12 +7,12 @@ .program i2sin_32 .side_set 2 -; Master-mode I2S RX, 32 bits per channel (also used for 24-bit mics that +; Clock-source I2S RX, 32 bits per channel (also used for 24-bit mics that ; transmit data left-justified in a 32-bit slot). Generates BCLK and LRCLK -; via side-set and samples the data pin. The slave updates `data` on BCLK -; falling edge, so the master samples on the rising edge: every `in pins 1` +; via side-set and samples the data pin. The follower device updates `data` on +; BCLK falling edge, so this program samples on the rising edge: every `in pins 1` ; runs on a side-set value with BCLK=1, and the preceding nop holds BCLK=0 -; so the slave has time to settle the next bit. +; so the follower has time to settle the next bit. ; /--- LRCLK ; |/-- BCLK ; || diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio index 8926d178635..f0480a67ba1 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio @@ -7,7 +7,7 @@ .program i2sin_left .side_set 2 -; Master-mode I2S RX, left-justified. Mirrors the timing of i2s_left.pio. +; Clock-source I2S RX, left-justified. Mirrors the timing of i2s_left.pio. ; /--- LRCLK ; |/-- BCLK ; || diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio index 86fcf79a876..ecb7134fcb0 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio @@ -7,7 +7,7 @@ .program i2sin_left_32 .side_set 2 -; Master-mode I2S RX, 32 bits per channel, left-justified. +; Clock-source I2S RX, 32 bits per channel, left-justified. ; /--- LRCLK ; |/-- BCLK ; || diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio index 8b718ebae65..40cf9108421 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio @@ -7,7 +7,7 @@ .program i2sin_swap .side_set 2 -; Master-mode I2S RX with the LRCLK and BCLK pin order swapped (BCLK is the +; Clock-source I2S RX with the LRCLK and BCLK pin order swapped (BCLK is the ; higher-numbered GPIO). ; /--- BCLK ; |/-- LRCLK diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio index 8ac65a20f90..b13c722e6d2 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio @@ -7,7 +7,7 @@ .program i2sin_swap_32 .side_set 2 -; Master-mode I2S RX, 32 bits per channel, with the LRCLK and BCLK pin order +; Clock-source I2S RX, 32 bits per channel, with the LRCLK and BCLK pin order ; swapped (BCLK is the higher-numbered GPIO). ; /--- BCLK ; |/-- LRCLK diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio index f6adc3d5bb8..dfcdfcf7482 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio @@ -7,7 +7,7 @@ .program i2sin_swap_left .side_set 2 -; Master-mode I2S RX, left-justified, with the LRCLK and BCLK pin order +; Clock-source I2S RX, left-justified, with the LRCLK and BCLK pin order ; swapped (BCLK is the higher-numbered GPIO). ; /--- BCLK ; |/-- LRCLK diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio index ae0ef8b8afb..80d549c9c1b 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio @@ -7,7 +7,7 @@ .program i2sin_swap_left_32 .side_set 2 -; Master-mode I2S RX, 32 bits per channel, left-justified, with the LRCLK and +; Clock-source I2S RX, 32 bits per channel, left-justified, with the LRCLK and ; BCLK pin order swapped (BCLK is the higher-numbered GPIO). ; /--- BCLK ; |/-- LRCLK diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c index 407c2c94b73..2f815cd2ee0 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.c +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.c @@ -232,6 +232,24 @@ static pio_pinmask_t _check_pins_free(const mcu_pin_obj_t *first_pin, uint8_t pi return pins_we_use; } +// Same as _check_pins_free but over an explicit GPIO mask, for pins a program +// only waits on. Sharing with another state machine is always allowed for +// these; the caller isn't driving them. +static void _check_gpio_mask_free(pio_pinmask_t mask) { + for (size_t pin_number = 0; pin_number < NUM_BANK0_GPIOS; pin_number++) { + if (!PIO_PINMASK_IS_SET(mask, pin_number)) { + continue; + } + const mcu_pin_obj_t *pin = mcu_get_pin_by_number(pin_number); + if (!pin) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q in use"), MP_QSTR_Pin); + } + if (_pin_reference_count[pin_number] == 0) { + assert_pin_free(pin); + } + } +} + static enum pio_fifo_join compute_fifo_type(int fifo_type_in, bool rx_fifo, bool tx_fifo) { if (fifo_type_in != PIO_FIFO_JOIN_AUTO) { return fifo_type_in; @@ -273,18 +291,60 @@ static bool is_gpio_compatible(PIO pio, uint32_t used_gpio_ranges) { #endif } -static bool use_existing_program(PIO *pio_out, int *sm_out, int *offset_inout, uint32_t program_id, size_t program_len, uint gpio_base, uint gpio_count) { - uint32_t required_gpio_ranges; - if (gpio_count) { - required_gpio_ranges = (1u << (gpio_base >> 4)) | - (1u << ((gpio_base + gpio_count - 1) >> 4)); - } else { - required_gpio_ranges = 0; +static uint32_t required_gpio_ranges(uint gpio_base, uint gpio_count) { + if (!gpio_count) { + return 0; } + return (1u << (gpio_base >> 4)) | + (1u << ((gpio_base + gpio_count - 1) >> 4)); +} +// Look for a PIO that already uses some of the pins we need. The cross-PIO +// overlap check in rp2pio_statemachine_construct fails a construct outright +// when its pins live on another PIO, so a generic claim can hand us a PIO that +// can't work while a usable one sits idle. +static bool use_pio_owning_pins(PIO *pio_out, int *sm_out, int *offset_inout, pio_program_t *program_struct, pio_pinmask_t pins_we_use, uint gpio_base, uint gpio_count) { + if (PIO_PINMASK_VALUE(pins_we_use) == 0) { + return false; + } + uint32_t ranges = required_gpio_ranges(gpio_base, gpio_count); for (size_t i = 0; i < NUM_PIOS; i++) { PIO pio = pio_get_instance(i); - if (!is_gpio_compatible(pio, required_gpio_ranges)) { + if (PIO_PINMASK_VALUE(PIO_PINMASK_AND(_current_pins[i], pins_we_use)) == 0) { + continue; + } + if (!is_gpio_compatible(pio, ranges) || !pio_can_add_program(pio, program_struct)) { + continue; + } + int sm = pio_claim_unused_sm(pio, false); + if (sm < 0) { + continue; + } + *pio_out = pio; + *sm_out = sm; + *offset_inout = pio_add_program(pio, program_struct); + return true; + } + return false; +} + +// FNV-1a over the instruction words. Never returns 0, which _current_program_id +// uses to mean "no program". +static uint32_t program_hash(const uint16_t *program, size_t program_len) { + uint32_t hash = 0x811c9dc5; + for (size_t i = 0; i < program_len; i++) { + hash = (hash ^ (program[i] & 0xff)) * 0x01000193; + hash = (hash ^ (program[i] >> 8)) * 0x01000193; + } + return hash == 0 ? 1 : hash; +} + +static bool use_existing_program(PIO *pio_out, int *sm_out, int *offset_inout, uint32_t program_id, size_t program_len, uint gpio_base, uint gpio_count) { + uint32_t ranges = required_gpio_ranges(gpio_base, gpio_count); + + for (size_t i = 0; i < NUM_PIOS; i++) { + PIO pio = pio_get_instance(i); + if (!is_gpio_compatible(pio, ranges)) { continue; } for (size_t j = 0; j < NUM_PIO_STATE_MACHINES; j++) { @@ -326,8 +386,14 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, int fifo_type, int mov_status_type, int mov_status_n ) { - // Create a program id that isn't the pointer so we can store it without storing the original object. - uint32_t program_id = ~((uint32_t)program); + // Create a program id we can store without storing the original object. + // This has to hash the instructions rather than the pointer: programs that + // encode absolute pin numbers (`wait gpio`) are assembled into a caller's + // stack buffer, so two different programs can share an address, and + // use_existing_program() would then hand the second one the first one's + // already-loaded instructions. Hashing the contents also lets identical + // programs from different arrays share a single copy in instruction memory. + uint32_t program_id = program_hash(program, program_len); uint gpio_base = 0, gpio_count = 0; #if NUM_BANK0_GPIOS > 32 @@ -361,7 +427,11 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, int state_machine; bool added = false; - if (!use_existing_program(&pio, &state_machine, &offset, program_id, program_len, gpio_base, gpio_count)) { + if (use_existing_program(&pio, &state_machine, &offset, program_id, program_len, gpio_base, gpio_count)) { + // Program is already loaded and shareable; nothing to add. + } else if (use_pio_owning_pins(&pio, &state_machine, &offset, &program_struct, pins_we_use, gpio_base, gpio_count)) { + added = true; + } else { uint program_offset; bool r = pio_claim_free_sm_and_add_program_for_gpio_range(&program_struct, &pio, (uint *)&state_machine, &program_offset, gpio_base, gpio_count, true); if (!r) { @@ -398,9 +468,20 @@ bool rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, _current_sm_pins[pio_index][state_machine] = pins_we_use; PIO_PINMASK_MERGE(_current_pins[pio_index], pins_we_use); - pio_sm_set_pins_with_mask64(self->pio, state_machine, PIO_PINMASK_VALUE(initial_pin_state), PIO_PINMASK_VALUE(pins_we_use)); - pio_sm_set_pindirs_with_mask64(self->pio, state_machine, PIO_PINMASK_VALUE(initial_pin_direction), PIO_PINMASK_VALUE(pins_we_use)); - rp2pio_statemachine_set_pull(pull_pin_up, pull_pin_down, pins_we_use); + // Only configure the pins no other state machine has claimed yet. A shared + // pin that this state machine doesn't drive (a clock it only waits on, say) + // would otherwise be forced back to input, clobbering its owner's setup. + pio_pinmask_t pins_we_own = PIO_PINMASK_NONE; + for (size_t pin_number = 0; pin_number < NUM_BANK0_GPIOS; pin_number++) { + if (PIO_PINMASK_IS_SET(pins_we_use, pin_number) && _pin_reference_count[pin_number] == 0) { + PIO_PINMASK_SET(pins_we_own, pin_number); + } + } + self->pins_we_own = pins_we_own; + + pio_sm_set_pins_with_mask64(self->pio, state_machine, PIO_PINMASK_VALUE(initial_pin_state), PIO_PINMASK_VALUE(pins_we_own)); + pio_sm_set_pindirs_with_mask64(self->pio, state_machine, PIO_PINMASK_VALUE(initial_pin_direction), PIO_PINMASK_VALUE(pins_we_own)); + rp2pio_statemachine_set_pull(pull_pin_up, pull_pin_down, pins_we_own); self->initial_pin_state = initial_pin_state; self->initial_pin_direction = initial_pin_direction; self->pull_pin_up = pull_pin_up; @@ -683,6 +764,7 @@ void common_hal_rp2pio_statemachine_construct(rp2pio_statemachine_obj_t *self, common_hal_rp2pio_statemachine_mark_deinit(self); // First, check that all pins are free OR already in use by any PIO if exclusive_pin_use is false. + _check_gpio_mask_free(wait_gpio_mask); pio_pinmask_t pins_we_use = wait_gpio_mask; PIO_PINMASK_MERGE(pins_we_use, _check_pins_free(first_out_pin, out_pin_count, exclusive_pin_use)); PIO_PINMASK_MERGE(pins_we_use, _check_pins_free(first_in_pin, in_pin_count, exclusive_pin_use)); @@ -809,11 +891,10 @@ void common_hal_rp2pio_statemachine_restart(rp2pio_statemachine_obj_t *self) { // the desired offset, so we can just use self->offset. pio_sm_exec(self->pio, self->state_machine, self->offset); pio_sm_restart(self->pio, self->state_machine); - uint8_t pio_index = pio_get_index(self->pio); - pio_pinmask_t pins_we_use = _current_sm_pins[pio_index][self->state_machine]; - pio_sm_set_pins_with_mask64(self->pio, self->state_machine, PIO_PINMASK_VALUE(self->initial_pin_state), PIO_PINMASK_VALUE(pins_we_use)); - pio_sm_set_pindirs_with_mask64(self->pio, self->state_machine, PIO_PINMASK_VALUE(self->initial_pin_direction), PIO_PINMASK_VALUE(pins_we_use)); - rp2pio_statemachine_set_pull(self->pull_pin_up, self->pull_pin_down, pins_we_use); + pio_pinmask_t pins_we_own = self->pins_we_own; + pio_sm_set_pins_with_mask64(self->pio, self->state_machine, PIO_PINMASK_VALUE(self->initial_pin_state), PIO_PINMASK_VALUE(pins_we_own)); + pio_sm_set_pindirs_with_mask64(self->pio, self->state_machine, PIO_PINMASK_VALUE(self->initial_pin_direction), PIO_PINMASK_VALUE(pins_we_own)); + rp2pio_statemachine_set_pull(self->pull_pin_up, self->pull_pin_down, pins_we_own); common_hal_rp2pio_statemachine_run(self, self->init, self->init_len); pio_sm_set_enabled(self->pio, self->state_machine, true); } diff --git a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h index eae1247d6f4..c2007ca1905 100644 --- a/ports/raspberrypi/common-hal/rp2pio/StateMachine.h +++ b/ports/raspberrypi/common-hal/rp2pio/StateMachine.h @@ -105,6 +105,7 @@ typedef struct { PIO pio; const uint16_t *init; size_t init_len; + pio_pinmask_t pins_we_own; // Subset of pins that no other state machine had already claimed. pio_pinmask_t initial_pin_state; pio_pinmask_t initial_pin_direction; pio_pinmask_t pull_pin_up; diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c index e159b4fcc10..04d61a6dc20 100644 --- a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -45,7 +45,11 @@ mp_obj_t common_hal_audiobusio_i2sout_construct_from_device(audiobusio_i2sout_ob // Standard audiobusio construct - not used in Zephyr port (devices come from device tree) void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, - const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified) { + const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, + bool clock_follower) { + if (clock_follower) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + } mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_I2S); } diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c index 952a00e2903..80764fa3c53 100644 --- a/shared-bindings/audiobusio/I2SOut.c +++ b/shared-bindings/audiobusio/I2SOut.c @@ -25,6 +25,7 @@ //| *, //| main_clock: Optional[microcontroller.Pin] = None, //| left_justified: bool = False, +//| clock_follower: bool = False, //| ) -> None: //| """Create a I2SOut object associated with the given pins. //| @@ -34,6 +35,15 @@ //| :param ~microcontroller.Pin main_clock: The main clock pin //| :param bool left_justified: True when data bits are aligned with the word select clock. False //| when they are shifted by one to match classic I2S protocol. +//| :param bool clock_follower: True when this object follows an externally supplied clock: +//| ``bit_clock`` and ``word_select`` are inputs driven by something else, another I2S +//| object (the clock source), or a codec, rather than generated by this object. Not +//| supported on all ports. +//| +//| As a clock follower ``bit_clock`` and ``word_select`` do not have to be sequential +//| GPIOs, and they may be shared with another I2S object. `play` cannot retime the bus, so +//| the sample's ``sample_rate`` must equal the external frame rate or the pitch will be +//| wrong. If the incoming clock stops, output stalls with its last sample held. //| //| Simple 8ksps 440 Hz sine wave on `Metro M0 Express `_ //| using `UDA1334 Breakout `_:: @@ -82,24 +92,35 @@ static mp_obj_t audiobusio_i2sout_make_new(const mp_obj_type_t *type, size_t n_a mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_I2SOut); return NULL; // Not reachable. #else - enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_left_justified }; + enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_left_justified, ARG_clock_follower }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bit_clock, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_word_select, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_main_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_left_justified, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_clock_follower, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const mcu_pin_obj_t *bit_clock = validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); - const mcu_pin_obj_t *word_select = validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); + bool clock_follower = args[ARG_clock_follower].u_bool; + + // As a clock follower the clock pins are only read, so they may already + // be owned by whatever is driving them; let the port decide if the sharing + // is legal. + const mcu_pin_obj_t *bit_clock = clock_follower + ? validate_obj_is_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock) + : validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); + const mcu_pin_obj_t *word_select = clock_follower + ? validate_obj_is_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select) + : validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj, MP_QSTR_data); const mcu_pin_obj_t *main_clock = validate_obj_is_free_pin_or_none(args[ARG_main_clock].u_obj, MP_QSTR_main_clock); audiobusio_i2sout_obj_t *self = mp_obj_malloc_with_finaliser(audiobusio_i2sout_obj_t, &audiobusio_i2sout_type); - common_hal_audiobusio_i2sout_construct(self, bit_clock, word_select, data, main_clock, args[ARG_left_justified].u_bool); + common_hal_audiobusio_i2sout_construct(self, bit_clock, word_select, data, main_clock, + args[ARG_left_justified].u_bool, clock_follower); return MP_OBJ_FROM_PTR(self); #endif diff --git a/shared-bindings/audiobusio/I2SOut.h b/shared-bindings/audiobusio/I2SOut.h index a53997ef91b..d99f901fc1e 100644 --- a/shared-bindings/audiobusio/I2SOut.h +++ b/shared-bindings/audiobusio/I2SOut.h @@ -16,7 +16,7 @@ extern const mp_obj_type_t audiobusio_i2sout_type; void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, - const mcu_pin_obj_t *main_clock, bool left_justified); + const mcu_pin_obj_t *main_clock, bool left_justified, bool clock_follower); void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self); bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t *self); diff --git a/shared-bindings/audiodelays/Chorus.c b/shared-bindings/audiodelays/Chorus.c index 87922ff110b..41bcbb7ef93 100644 --- a/shared-bindings/audiodelays/Chorus.c +++ b/shared-bindings/audiodelays/Chorus.c @@ -58,7 +58,7 @@ //| //| audio = audiobusio.I2SOut(bit_clock=board.GP20, word_select=board.GP21, data=board.GP22) //| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) -//| chorus = audiodelays.Chorus(max_delay_ms=50, delay_ms=5, buffer_size=1024, channel_count=1, sample_rate=44100) +//| chorus = audiodelays.Chorus(max_delay_ms=50, voices=4, delay_ms=5, buffer_size=1024, channel_count=1, sample_rate=44100) //| chorus.play(synth) //| audio.play(chorus) //| diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 056aa859abe..3ab5a02bd8b 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -34,6 +34,8 @@ //| mono: bool = True, //| left_justified: bool = False, //| samples_signed: bool = True, +//| clock_follower: bool = False, +//| invert_bit_clock: bool = False, //| ) -> None: //| """Create an I2SIn object associated with the given pins. This allows you to //| record audio signals from an external I2S source (e.g. an I2S MEMS microphone @@ -83,6 +85,19 @@ //| :param bool samples_signed: Samples are signed (True) or unsigned (False). I2S mics deliver signed //| two's-complement PCM natively; set False to have the recorded samples converted to unsigned PCM //| (the top/sign bit is flipped, matching the WAV convention for unsigned samples). +//| :param bool clock_follower: True when this object follows an externally supplied clock: +//| ``bit_clock`` and ``word_select`` are inputs driven by something else. Like an +//| `audiobusio.I2SOut` object (the clock source), or a codec, rather than generated by +//| this object. Not supported on all ports. +//| +//| As a clock follower ``bit_clock`` and ``word_select`` do not have to be sequential +//| GPIOs, and they may be shared with another I2S object. ``sample_rate`` becomes a +//| declaration rather than a measurement: the real rate is whatever the external word select +//| runs at, and `sample_rate` still reports the declared value. If the incoming clock stops, +//| `record` blocks (interruptible with Ctrl-C). +//| :param bool invert_bit_clock: Sample ``data`` on the falling edge of ``bit_clock`` instead of +//| the rising edge. Needed when the external clock source drives its data on the rising edge. +//| Only valid together with ``clock_follower``. //| //| Example, recording 16-bit mono samples from an INMP441:: //| @@ -105,7 +120,8 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar #else enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_sample_rate, ARG_bit_depth, ARG_output_bit_depth, - ARG_mono, ARG_left_justified, ARG_samples_signed }; + ARG_mono, ARG_left_justified, ARG_samples_signed, + ARG_clock_follower, ARG_invert_bit_clock }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bit_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_word_select, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -117,12 +133,28 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_left_justified, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_samples_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_clock_follower, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_invert_bit_clock, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - const mcu_pin_obj_t *bit_clock = validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); - const mcu_pin_obj_t *word_select = validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); + bool clock_follower = args[ARG_clock_follower].u_bool; + bool invert_bit_clock = args[ARG_invert_bit_clock].u_bool; + if (invert_bit_clock && !clock_follower) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("%q requires %q"), + MP_QSTR_invert_bit_clock, MP_QSTR_clock_follower); + } + + // As a clock follower the clock pins are only read, so they may already + // be owned by whatever is driving them; let the port decide if the sharing + // is legal. + const mcu_pin_obj_t *bit_clock = clock_follower + ? validate_obj_is_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock) + : validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); + const mcu_pin_obj_t *word_select = clock_follower + ? validate_obj_is_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select) + : validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj, MP_QSTR_data); const mcu_pin_obj_t *main_clock = validate_obj_is_free_pin_or_none(args[ARG_main_clock].u_obj, MP_QSTR_main_clock); @@ -148,7 +180,8 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar audioi2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audioi2sin_i2sin_obj_t, &audioi2sin_i2sin_type); common_hal_audioi2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, - sample_rate, bit_depth, output_bit_depth, mono, left_justified, samples_signed); + sample_rate, bit_depth, output_bit_depth, mono, left_justified, samples_signed, + clock_follower, invert_bit_clock); return MP_OBJ_FROM_PTR(self); #endif @@ -281,6 +314,29 @@ MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_samples_signed_obj, audioi2sin_i2 MP_PROPERTY_GETTER(audioi2sin_i2sin_samples_signed_obj, (mp_obj_t)&audioi2sin_i2sin_get_samples_signed_obj); + +//| overflow: bool +//| """True if samples were dropped because they were not read fast enough, +//| since the last time this was checked. (read-only) +//| +//| Reading this clears the flag, so it reports whether an overflow happened +//| in the interval since the previous read rather than at any time in the +//| past. `record` and streaming playback both set it; a streaming consumer +//| has no other way to notice it is falling behind. +//| +//| Not all ports can detect overflow; those report False always.""" +//| +//| +static mp_obj_t audioi2sin_i2sin_obj_get_overflow(mp_obj_t self_in) { + audioi2sin_i2sin_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audioi2sin_i2sin_get_overflow(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audioi2sin_i2sin_get_overflow_obj, audioi2sin_i2sin_obj_get_overflow); + +MP_PROPERTY_GETTER(audioi2sin_i2sin_overflow_obj, + (mp_obj_t)&audioi2sin_i2sin_get_overflow_obj); + static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioi2sin_i2sin_deinit_obj) }, @@ -292,6 +348,7 @@ static const mp_rom_map_elem_t audioi2sin_i2sin_locals_dict_table[] = { AUDIOSAMPLE_FIELDS, { MP_ROM_QSTR(MP_QSTR_bit_depth), MP_ROM_PTR(&audioi2sin_i2sin_bit_depth_obj) }, { MP_ROM_QSTR(MP_QSTR_samples_signed), MP_ROM_PTR(&audioi2sin_i2sin_samples_signed_obj) }, + { MP_ROM_QSTR(MP_QSTR_overflow), MP_ROM_PTR(&audioi2sin_i2sin_overflow_obj) }, }; static MP_DEFINE_CONST_DICT(audioi2sin_i2sin_locals_dict, audioi2sin_i2sin_locals_dict_table); diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h index c0fc48a6d09..8c4d9d27a12 100644 --- a/shared-bindings/audioi2sin/I2SIn.h +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -20,7 +20,8 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, - bool mono, bool left_justified, bool samples_signed); + bool mono, bool left_justified, bool samples_signed, + bool clock_follower, bool invert_bit_clock); void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, @@ -28,6 +29,8 @@ uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *se uint8_t common_hal_audioi2sin_i2sin_get_bit_depth(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_get_sample_rate(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_get_samples_signed(audioi2sin_i2sin_obj_t *self); +// Reads and clears the sticky "samples were dropped" flag. +bool common_hal_audioi2sin_i2sin_get_overflow(audioi2sin_i2sin_obj_t *self); // audiosample protocol: streaming source support. fill_buffer converts the // frames currently available from the live mic into `buffer` (output depth, From b396a24f5c28000b2f30b3a98f348c676accc760 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 23 Jul 2026 18:32:48 -0400 Subject: [PATCH 690/876] audio: validate sample with audiosample_check() in all play paths The various play() entry points passed the user-supplied object straight to the non-validating audiosample getters (audiosample_get_sample_rate(), audiosample_get_bits_per_sample(), etc.), which cast the object without checking it implements the audiosample protocol. Passing a non-sample object dereferenced arbitrary memory instead of raising. Add audiosample_check() as the first statement in each affected common-hal play path so a bad object raises cleanly, matching the existing RP2040 audiobusio.I2SOut fix. Co-Authored-By: Claude Opus 4.8 (1M context) --- ports/atmel-samd/common-hal/audiobusio/I2SOut.c | 3 +++ ports/atmel-samd/common-hal/audioio/AudioOut.c | 3 +++ ports/espressif/common-hal/audiobusio/__init__.c | 1 + ports/espressif/common-hal/audioio/AudioOut.c | 2 ++ ports/mimxrt10xx/common-hal/audiobusio/__init__.c | 1 + ports/nordic/common-hal/audiobusio/I2SOut.c | 2 ++ ports/nordic/common-hal/audiopwmio/PWMAudioOut.c | 3 +++ ports/raspberrypi/common-hal/audiobusio/I2SOut.c | 2 ++ ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c | 2 ++ ports/raspberrypi/common-hal/mcp4822/MCP4822.c | 2 ++ ports/stm/common-hal/audiopwmio/PWMAudioOut.c | 3 +++ ports/zephyr-cp/common-hal/audiobusio/I2SOut.c | 2 ++ 12 files changed, 26 insertions(+) diff --git a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c index 178db2f07d0..12818628eec 100644 --- a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c +++ b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c @@ -211,6 +211,9 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, if (common_hal_audiobusio_i2sout_get_playing(self)) { common_hal_audiobusio_i2sout_stop(self); } + + audiosample_check(sample); + #ifdef SAMD21 if ((I2S->CTRLA.vec.CKEN & (1 << self->clock_unit)) == 1) { mp_raise_RuntimeError(MP_ERROR_TEXT("Clock unit in use")); diff --git a/ports/atmel-samd/common-hal/audioio/AudioOut.c b/ports/atmel-samd/common-hal/audioio/AudioOut.c index f7af5e292a7..9bff11fa6b4 100644 --- a/ports/atmel-samd/common-hal/audioio/AudioOut.c +++ b/ports/atmel-samd/common-hal/audioio/AudioOut.c @@ -331,6 +331,9 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, if (common_hal_audioio_audioout_get_playing(self)) { common_hal_audioio_audioout_stop(self); } + + audiosample_check(sample); + audio_dma_result result = AUDIO_DMA_OK; uint32_t sample_rate = audiosample_get_sample_rate(sample); #ifdef SAMD21 diff --git a/ports/espressif/common-hal/audiobusio/__init__.c b/ports/espressif/common-hal/audiobusio/__init__.c index 4aff753325f..dae711100d3 100644 --- a/ports/espressif/common-hal/audiobusio/__init__.c +++ b/ports/espressif/common-hal/audiobusio/__init__.c @@ -157,6 +157,7 @@ void port_i2s_deinit(i2s_t *self) { } void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { + audiosample_check(sample); // Pause to disable the I2S channel so we can adjust the clock. port_i2s_pause(self); self->sample = sample; diff --git a/ports/espressif/common-hal/audioio/AudioOut.c b/ports/espressif/common-hal/audioio/AudioOut.c index fb8c862ba07..e6aed580e27 100644 --- a/ports/espressif/common-hal/audioio/AudioOut.c +++ b/ports/espressif/common-hal/audioio/AudioOut.c @@ -573,6 +573,8 @@ void common_hal_audioio_audioout_play(audioio_audioout_obj_t *self, mp_raise_RuntimeError(MP_ERROR_TEXT("already playing")); } + audiosample_check(sample); + size_t samples_size; uint8_t channel_count; bool samples_signed; diff --git a/ports/mimxrt10xx/common-hal/audiobusio/__init__.c b/ports/mimxrt10xx/common-hal/audiobusio/__init__.c index f1030bfcd84..d51ea773acb 100644 --- a/ports/mimxrt10xx/common-hal/audiobusio/__init__.c +++ b/ports/mimxrt10xx/common-hal/audiobusio/__init__.c @@ -372,6 +372,7 @@ static void set_sai_clocking_for_sample_rate(uint32_t sample_rate) { } void port_i2s_play(i2s_t *self, mp_obj_t sample, bool loop) { + audiosample_check(sample); self->sample = sample; self->loop = loop; self->bytes_per_sample = audiosample_get_bits_per_sample(sample) / 8; diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.c b/ports/nordic/common-hal/audiobusio/I2SOut.c index 00b34e17e82..b89f30901cc 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.c +++ b/ports/nordic/common-hal/audiobusio/I2SOut.c @@ -245,6 +245,8 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, common_hal_audiobusio_i2sout_stop(self); } + audiosample_check(sample); + self->sample = sample; self->loop = loop; uint32_t sample_rate = audiosample_get_sample_rate(sample); diff --git a/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c b/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c index b48a03e09c6..75df88e4416 100644 --- a/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/nordic/common-hal/audiopwmio/PWMAudioOut.c @@ -236,6 +236,9 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, if (common_hal_audiopwmio_pwmaudioout_get_playing(self)) { common_hal_audiopwmio_pwmaudioout_stop(self); } + + audiosample_check(sample); + self->sample = sample; self->loop = loop; diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c index d29f50b06b8..a51430c1baa 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c @@ -262,6 +262,8 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, common_hal_audiobusio_i2sout_stop(self); } + audiosample_check(sample); + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); // Make sure we transmit a minimum of 16 bits. // TODO: Maybe we need an intermediate object to upsample instead. This is diff --git a/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c b/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c index 6fa5bf02c14..3ab8eb814a1 100644 --- a/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/raspberrypi/common-hal/audiopwmio/PWMAudioOut.c @@ -160,6 +160,8 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, common_hal_audiopwmio_pwmaudioout_stop(self); } + audiosample_check(sample); + // TODO: Share pacing timers based on frequency. size_t pacing_timer = NUM_DMA_TIMERS; for (size_t i = 0; i < NUM_DMA_TIMERS; i++) { diff --git a/ports/raspberrypi/common-hal/mcp4822/MCP4822.c b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c index 7a8ad7d4df2..ba4a39b11d8 100644 --- a/ports/raspberrypi/common-hal/mcp4822/MCP4822.c +++ b/ports/raspberrypi/common-hal/mcp4822/MCP4822.c @@ -216,6 +216,8 @@ void common_hal_mcp4822_mcp4822_play(mcp4822_mcp4822_obj_t *self, common_hal_mcp4822_mcp4822_stop(self); } + audiosample_check(sample); + uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); if (bits_per_sample < 16) { bits_per_sample = 16; diff --git a/ports/stm/common-hal/audiopwmio/PWMAudioOut.c b/ports/stm/common-hal/audiopwmio/PWMAudioOut.c index a5cc11965fa..08ab7eb9bc7 100644 --- a/ports/stm/common-hal/audiopwmio/PWMAudioOut.c +++ b/ports/stm/common-hal/audiopwmio/PWMAudioOut.c @@ -255,6 +255,9 @@ void common_hal_audiopwmio_pwmaudioout_play(audiopwmio_pwmaudioout_obj_t *self, if (active_audio) { mp_raise_RuntimeError(MP_ERROR_TEXT("Another PWMAudioOut is already active")); // TODO } + + audiosample_check(sample); + self->sample = sample; self->loop = loop; diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c index e159b4fcc10..3dd4fcdd906 100644 --- a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -149,6 +149,8 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, common_hal_audiobusio_i2sout_stop(self); } + audiosample_check(sample); + // Get sample information uint8_t bits_per_sample = audiosample_get_bits_per_sample(sample); uint32_t sample_rate = audiosample_get_sample_rate(sample); From f2094872318ce429c8b0a13b29687d6ba599d31d Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 24 Jul 2026 08:23:18 -0500 Subject: [PATCH 691/876] use HANDLE_OUT instead of HANDLE_HELD for pin name. --- ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c index 0468c52e5fe..7d479fa82b4 100644 --- a/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c @@ -50,12 +50,12 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_BUTTON_BOTTOM), MP_ROM_PTR(&pin_GPIO1) }, // Handle: a two-stage switch. HANDLE_IN reads False when the handle is - // fully seated; HANDLE_HELD reads True as soon as the handle is moved. + // fully seated; HANDLE_OUT reads True as soon as the handle is moved. { MP_ROM_QSTR(MP_QSTR_GP19), MP_ROM_PTR(&pin_GPIO19) }, { MP_ROM_QSTR(MP_QSTR_HANDLE_IN), MP_ROM_PTR(&pin_GPIO19) }, { MP_ROM_QSTR(MP_QSTR_GP20), MP_ROM_PTR(&pin_GPIO20) }, - { MP_ROM_QSTR(MP_QSTR_HANDLE_HELD), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_HANDLE_OUT), MP_ROM_PTR(&pin_GPIO20) }, // Power hold latch. Held high by the board so the unit stays powered once // the handle is released. Driving it low powers the unit off immediately. From 3339f2209d87b3275a909ce9ee7d582e89d2e85b Mon Sep 17 00:00:00 2001 From: foamyguy Date: Fri, 24 Jul 2026 10:25:10 -0500 Subject: [PATCH 692/876] use I2S_WS instead of I2S_WORD_SELECT --- ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c index 7d479fa82b4..035a8aa2acd 100644 --- a/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c @@ -78,7 +78,7 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2S_DOUT), MP_ROM_PTR(&pin_GPIO9) }, { MP_ROM_QSTR(MP_QSTR_GP10), MP_ROM_PTR(&pin_GPIO10) }, - { MP_ROM_QSTR(MP_QSTR_I2S_WORD_SELECT), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_I2S_WS), MP_ROM_PTR(&pin_GPIO10) }, { MP_ROM_QSTR(MP_QSTR_GP11), MP_ROM_PTR(&pin_GPIO11) }, { MP_ROM_QSTR(MP_QSTR_I2S_BIT_CLOCK), MP_ROM_PTR(&pin_GPIO11) }, From ce508f47a9d22dd220a55e1705ea35dcd7ddbb67 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Thu, 23 Jul 2026 14:38:48 +0000 Subject: [PATCH 693/876] usb.core: add raise_on_timeout=False option to Device.read Polling an interrupt IN endpoint every frame (a HID gamepad in a game loop) treats "no new report yet" as a normal outcome, but read() can only express it by raising USBTimeoutError. Each raise allocates an exception instance, which adds up to measurable GC pressure on small heaps: a 30 fps game polling one gamepad measured ~1-1.5 KB/s of transient garbage from these exceptions alone (RP2350 Fruit Jam). With raise_on_timeout=False (keyword-only, default True keeps the pyusb-compatible behavior), an elapsed timeout returns 0 instead of raising, so a per-frame poll allocates nothing. A timeout can be detected either by TinyUSB or by CircuitPython's own deadline; with the flag set, both paths return 0 after the usual transfer abort and buffer cleanup, instead of raising. --- shared-bindings/usb/core/Device.c | 18 +++++++++++++++--- shared-bindings/usb/core/Device.h | 2 +- shared-module/usb/core/Device.c | 31 ++++++++++++++++++++++--------- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/shared-bindings/usb/core/Device.c b/shared-bindings/usb/core/Device.c index 683115a8421..bc6c6296899 100644 --- a/shared-bindings/usb/core/Device.c +++ b/shared-bindings/usb/core/Device.c @@ -226,23 +226,35 @@ MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_write_obj, 2, usb_core_device_write); //| def read( -//| self, endpoint: int, size_or_buffer: array.array, timeout: Optional[int] = None +//| self, +//| endpoint: int, +//| size_or_buffer: array.array, +//| timeout: Optional[int] = None, +//| *, +//| raise_on_timeout: bool = True, //| ) -> int: //| """Read data from the endpoint. //| //| :param int endpoint: the bEndpointAddress you want to communicate with. //| :param array.array size_or_buffer: the array to read data into. PyUSB also allows size but CircuitPython only support array to force deliberate memory use. //| :param int timeout: Time to wait specified in milliseconds. (Different from most CircuitPython!) +//| :param bool raise_on_timeout: when False, an elapsed timeout returns ``0`` +//| instead of raising `usb.core.USBTimeoutError`. Polling an interrupt +//| endpoint every frame (e.g. a HID gamepad in a game loop) treats "no +//| new report yet" as a normal outcome; the exception object each such +//| poll would otherwise allocate is measurable garbage-collector +//| pressure on small heaps. //| :returns: the number of bytes read //| """ //| ... //| static mp_obj_t usb_core_device_read(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_endpoint, ARG_size_or_buffer, ARG_timeout }; + enum { ARG_endpoint, ARG_size_or_buffer, ARG_timeout, ARG_raise_on_timeout }; static const mp_arg_t allowed_args[] = { { MP_QSTR_endpoint, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_size_or_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_timeout, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_raise_on_timeout, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, }; usb_core_device_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); check_for_deinit(self); @@ -252,7 +264,7 @@ static mp_obj_t usb_core_device_read(size_t n_args, const mp_obj_t *pos_args, mp mp_buffer_info_t bufinfo; mp_get_buffer_raise(args[ARG_size_or_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); - return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_read(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int)); + return MP_OBJ_NEW_SMALL_INT(common_hal_usb_core_device_read(self, args[ARG_endpoint].u_int, bufinfo.buf, bufinfo.len, args[ARG_timeout].u_int, args[ARG_raise_on_timeout].u_bool)); } MP_DEFINE_CONST_FUN_OBJ_KW(usb_core_device_read_obj, 2, usb_core_device_read); diff --git a/shared-bindings/usb/core/Device.h b/shared-bindings/usb/core/Device.h index 28c2cfbe198..51338f61228 100644 --- a/shared-bindings/usb/core/Device.h +++ b/shared-bindings/usb/core/Device.h @@ -26,7 +26,7 @@ mp_int_t common_hal_usb_core_device_get_speed(usb_core_device_obj_t *self); void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, mp_int_t configuration); mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t endpoint, const uint8_t *buffer, mp_int_t len, mp_int_t timeout); -mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout); +mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout, bool raise_on_timeout); mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, mp_int_t bmRequestType, mp_int_t bRequest, mp_int_t wValue, mp_int_t wIndex, diff --git a/shared-module/usb/core/Device.c b/shared-module/usb/core/Device.c index 53c87de180a..a3bb449e87e 100644 --- a/shared-module/usb/core/Device.c +++ b/shared-module/usb/core/Device.c @@ -175,7 +175,7 @@ static void _abort_transfer(tuh_xfer_t *xfer) { } // Only frees the transfer buffer on error. -static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer) { +static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer, bool raise_on_timeout) { if (xfer == NULL) { mp_raise_usb_core_USBError(NULL); return 0; @@ -196,7 +196,14 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout // Handle transfer result code from TinyUSB xfer_result_t result = _xfer_result; _xfer_result = XFER_RESULT_INVALID; - if (our_buffer && result != XFER_RESULT_SUCCESS && result != XFER_RESULT_INVALID) { + // Free the bounce buffer only on paths that raise: raising unwinds past + // the caller's cleanup, so it must be freed here. Paths that return + // normally leave ownership with the caller, which copies out of and + // frees the buffer itself (freeing on both sides would be a double free). + bool will_raise = result == XFER_RESULT_ABORTED || result == XFER_RESULT_FAILED || + result == XFER_RESULT_STALLED || + (result == XFER_RESULT_TIMEOUT && raise_on_timeout); + if (our_buffer && will_raise) { port_free(xfer->buffer); } switch (result) { @@ -212,12 +219,18 @@ static size_t _handle_timed_transfer_callback(tuh_xfer_t *xfer, mp_int_t timeout case XFER_RESULT_TIMEOUT: // This timeout comes from TinyUSB, so assume that it has stopped the // transfer (note: timeout logic may be unimplemented on TinyUSB side) + if (!raise_on_timeout) { + return 0; + } mp_raise_usb_core_USBTimeoutError(); break; case XFER_RESULT_INVALID: // This timeout comes from CircuitPython, not TinyUSB, so tell TinyUSB - // to stop the transfer and then wait to free the buffer. + // to stop the transfer. _abort_transfer(xfer); + if (!raise_on_timeout) { + return 0; // the caller owns (and frees) the buffer + } if (our_buffer) { port_free(xfer->buffer); } @@ -385,7 +398,7 @@ void common_hal_usb_core_device_set_configuration(usb_core_device_obj_t *self, m } // Raises an exception on failure. Returns the number of bytes transferred (maybe zero) on success. -static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer) { +static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer, bool raise_on_timeout) { _prepare_for_transfer(); xfer->complete_cb = _transfer_done_cb; if (!tuh_edpt_xfer(xfer)) { @@ -395,7 +408,7 @@ static size_t _xfer(tuh_xfer_t *xfer, mp_int_t timeout, bool our_buffer) { mp_raise_usb_core_USBError(NULL); return 0; } - return _handle_timed_transfer_callback(xfer, timeout, our_buffer); + return _handle_timed_transfer_callback(xfer, timeout, our_buffer, raise_on_timeout); } static bool _open_endpoint(usb_core_device_obj_t *self, mp_int_t endpoint) { @@ -469,7 +482,7 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t xfer.ep_addr = endpoint; xfer.buffer = dma_buffer; xfer.buflen = len; - size_t result = _xfer(&xfer, timeout, dma_buffer != buffer); + size_t result = _xfer(&xfer, timeout, dma_buffer != buffer, true); #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE if (dma_buffer != buffer) { port_free(dma_buffer); @@ -478,7 +491,7 @@ mp_int_t common_hal_usb_core_device_write(usb_core_device_obj_t *self, mp_int_t return result; } -mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout) { +mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t endpoint, uint8_t *buffer, mp_int_t len, mp_int_t timeout, bool raise_on_timeout) { if (!_open_endpoint(self, endpoint)) { mp_raise_usb_core_USBError(NULL); return 0; @@ -500,7 +513,7 @@ mp_int_t common_hal_usb_core_device_read(usb_core_device_obj_t *self, mp_int_t e xfer.ep_addr = endpoint; xfer.buffer = dma_buffer; xfer.buflen = len; - mp_int_t result = _xfer(&xfer, timeout, dma_buffer != buffer); + mp_int_t result = _xfer(&xfer, timeout, dma_buffer != buffer, raise_on_timeout); #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE // Copy data back to original buffer if needed @@ -556,7 +569,7 @@ mp_int_t common_hal_usb_core_device_ctrl_transfer(usb_core_device_obj_t *self, mp_raise_usb_core_USBError(NULL); return 0; } - mp_int_t result = (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout, dma_buffer != buffer); + mp_int_t result = (mp_int_t)_handle_timed_transfer_callback(&xfer, timeout, dma_buffer != buffer, true); #if !CIRCUITPY_ALL_MEMORY_DMA_CAPABLE if (dma_buffer != buffer) { From 58206fefeb5634b0d1ad385ab158544d4101aa31 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 28 Jul 2026 08:16:02 -0500 Subject: [PATCH 694/876] rename to external_clock --- .../atmel-samd/common-hal/audiobusio/I2SOut.c | 6 +- .../espressif/common-hal/audiobusio/I2SOut.c | 6 +- ports/espressif/common-hal/audioi2sin/I2SIn.c | 6 +- .../mimxrt10xx/common-hal/audiobusio/I2SOut.c | 6 +- ports/nordic/common-hal/audiobusio/I2SOut.c | 6 +- .../common-hal/audiobusio/I2SOut.c | 42 ++++++------- .../common-hal/audiobusio/I2SOut.h | 2 +- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 59 ++++++++++--------- .../raspberrypi/common-hal/audioi2sin/I2SIn.h | 2 +- .../common-hal/audioi2sin/i2sin.pio | 6 +- .../common-hal/audioi2sin/i2sin_32.pio | 6 +- .../common-hal/audioi2sin/i2sin_left.pio | 2 +- .../common-hal/audioi2sin/i2sin_left_32.pio | 2 +- .../common-hal/audioi2sin/i2sin_swap.pio | 2 +- .../common-hal/audioi2sin/i2sin_swap_32.pio | 2 +- .../common-hal/audioi2sin/i2sin_swap_left.pio | 2 +- .../audioi2sin/i2sin_swap_left_32.pio | 2 +- .../zephyr-cp/common-hal/audiobusio/I2SOut.c | 6 +- shared-bindings/audiobusio/I2SOut.c | 20 +++---- shared-bindings/audiobusio/I2SOut.h | 2 +- shared-bindings/audioi2sin/I2SIn.c | 26 ++++---- shared-bindings/audioi2sin/I2SIn.h | 2 +- 22 files changed, 108 insertions(+), 107 deletions(-) diff --git a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c index a1e7f00dd0f..d294ebc2c10 100644 --- a/ports/atmel-samd/common-hal/audiobusio/I2SOut.c +++ b/ports/atmel-samd/common-hal/audiobusio/I2SOut.c @@ -78,9 +78,9 @@ void i2sout_reset(void) { void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, - bool clock_follower) { - if (clock_follower) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); } if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); diff --git a/ports/espressif/common-hal/audiobusio/I2SOut.c b/ports/espressif/common-hal/audiobusio/I2SOut.c index 67b9300b57c..21b4aa829b3 100644 --- a/ports/espressif/common-hal/audiobusio/I2SOut.c +++ b/ports/espressif/common-hal/audiobusio/I2SOut.c @@ -29,9 +29,9 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, - bool clock_follower) { - if (clock_follower) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); } port_i2s_allocate_init(&self->i2s, left_justified); diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index d3c89958a4d..6da790d9736 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -25,9 +25,9 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, bool mono, bool left_justified, bool samples_signed, - bool clock_follower, bool invert_bit_clock) { - if (clock_follower) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + bool external_clock, bool invert_bit_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); } i2s_data_bit_width_t bit_width = (i2s_data_bit_width_t)bit_depth; diff --git a/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c b/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c index b5d308fa896..b844325a00a 100644 --- a/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c +++ b/ports/mimxrt10xx/common-hal/audiobusio/I2SOut.c @@ -54,9 +54,9 @@ static void config_periph_pin(const mcu_periph_obj_t *periph) { void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, - bool clock_follower) { - if (clock_follower) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); } int instance = -1; diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.c b/ports/nordic/common-hal/audiobusio/I2SOut.c index d70653059a9..04a6b800636 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.c +++ b/ports/nordic/common-hal/audiobusio/I2SOut.c @@ -190,9 +190,9 @@ static void i2s_buffer_fill(audiobusio_i2sout_obj_t *self) { void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, - bool clock_follower) { - if (clock_follower) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); } if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c index 7646cec9c27..e7d770197fc 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.c +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.c @@ -167,16 +167,16 @@ const uint16_t i2s_program_left_justified_swap[] = { 0x6201, // 9: out pins, 1 side 0 [2] }; -// Clock-follower TX. BCLK and WS are inputs driven by something +// External-clock TX. BCLK and WS are inputs driven by something // else, so the state machine side-sets nothing and waits on the two clocks -// instead. `wait gpio` encodes an absolute pin index, so unlike the clock-source +// instead. `wait gpio` encodes an absolute pin index, so unlike the internal-clock // programs above this one cannot be a static table: it is assembled at // construct time with the pin numbers patched in. // // 0: wait 0 gpio W // 1: wait 1 gpio W ; right channel starts (WS changes on a BCLK fall) // .wrap_target -// 2: pull noblock ; refills OSR from X on underflow, as the clock-source program does +// 2: pull noblock ; refills OSR from X on underflow, as the internal-clock program does // 3: mov x, osr // 4: set y, 31 // 5: wait 1 gpio B @@ -190,12 +190,12 @@ const uint16_t i2s_program_left_justified_swap[] = { // otherwise lands on the Philips delay bit, so no pre-roll is needed. // // One 32-bit FIFO word covers a whole 16-bit stereo frame; at 24/32 bits the -// frame is two words (right then left). Same layout the clock-source programs use. -#define I2S_FOLLOWER_PROGRAM_LEN (9) -#define I2S_FOLLOWER_WRAP_TARGET (2) -#define I2S_FOLLOWER_WRAP (8) +// frame is two words (right then left). Same layout the internal-clock programs use. +#define I2S_EXT_CLOCK_PROGRAM_LEN (9) +#define I2S_EXT_CLOCK_WRAP_TARGET (2) +#define I2S_EXT_CLOCK_WRAP (8) -static void build_i2sout_follower_program(uint16_t *prog, uint8_t bclk, uint8_t ws, bool left_justified) { +static void build_i2sout_ext_clock_program(uint16_t *prog, uint8_t bclk, uint8_t ws, bool left_justified) { const uint16_t wait_0_bclk = 0x2000 | bclk; const uint16_t wait_1_bclk = 0x2080 | bclk; prog[0] = 0x2000 | ws; // wait 0 gpio W @@ -231,20 +231,20 @@ void i2sout_reset(void) { void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, - bool clock_follower) { + bool external_clock) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } const mcu_pin_obj_t *sideset_pin = NULL; const uint16_t *program = NULL; size_t program_len = 0; - uint16_t follower_program[I2S_FOLLOWER_PROGRAM_LEN]; + uint16_t ext_clock_program[I2S_EXT_CLOCK_PROGRAM_LEN]; pio_pinmask_t wait_gpio_mask = PIO_PINMASK_NONE; - self->clock_follower = clock_follower; + self->external_clock = external_clock; - if (clock_follower) { - // As a clock follower the clocks are `wait gpio` targets, so they + if (external_clock) { + // In external clock mode the clocks are `wait gpio` targets, so they // need not be sequential GPIOs. uint8_t gpio_offset = 0; #if NUM_BANK0_GPIOS > 32 @@ -252,12 +252,12 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, gpio_offset = 16; } #endif - build_i2sout_follower_program(follower_program, + build_i2sout_ext_clock_program(ext_clock_program, i2s_wait_gpio_index(bit_clock, gpio_offset), i2s_wait_gpio_index(word_select, gpio_offset), left_justified); - program = follower_program; - program_len = I2S_FOLLOWER_PROGRAM_LEN; + program = ext_clock_program; + program_len = I2S_EXT_CLOCK_PROGRAM_LEN; wait_gpio_mask = PIO_PINMASK_OR(PIO_PINMASK_FROM_PIN(bit_clock->number), PIO_PINMASK_FROM_PIN(word_select->number)); } else if (bit_clock->number == word_select->number - 1) { @@ -290,9 +290,9 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, common_hal_rp2pio_statemachine_construct( &self->state_machine, program, program_len, - // Clock at 44.1 khz to warm the DAC up. As a clock follower the SM + // Clock at 44.1 khz to warm the DAC up. In external clock mode the SM // is driven by the waits, not the clock divider, so run it at sysclk. - clock_follower ? 0 : 44100 * 32 * 6, + external_clock ? 0 : 44100 * 32 * 6, NULL, 0, // init NULL, 0, // may_exec data, 1, PIO_PINMASK32_NONE, PIO_PINMASK32_ALL, // out pin @@ -310,8 +310,8 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, false, // Wait for txstall false, 32, false, // in settings false, // Not user-interruptible. - clock_follower ? I2S_FOLLOWER_WRAP_TARGET : 0, - clock_follower ? I2S_FOLLOWER_WRAP : -1, // wrap settings + external_clock ? I2S_EXT_CLOCK_WRAP_TARGET : 0, + external_clock ? I2S_EXT_CLOCK_WRAP : -1, // wrap settings PIO_ANY_OFFSET, PIO_FIFO_TYPE_DEFAULT, PIO_MOV_STATUS_DEFAULT, @@ -366,7 +366,7 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, // the outside world is running WS at, or the pitch is wrong. The restart // still matters -- it re-execs the program at its offset, so every play() // re-syncs to WS. - if (!self->clock_follower) { + if (!self->external_clock) { common_hal_rp2pio_statemachine_set_frequency(&self->state_machine, clocks_per_bit * frequency); } common_hal_rp2pio_statemachine_restart(&self->state_machine); diff --git a/ports/raspberrypi/common-hal/audiobusio/I2SOut.h b/ports/raspberrypi/common-hal/audiobusio/I2SOut.h index 1ac277958de..def66225bf3 100644 --- a/ports/raspberrypi/common-hal/audiobusio/I2SOut.h +++ b/ports/raspberrypi/common-hal/audiobusio/I2SOut.h @@ -18,7 +18,7 @@ typedef struct { rp2pio_statemachine_obj_t state_machine; audio_dma_t dma; bool left_justified; - bool clock_follower; + bool external_clock; bool playing; } audiobusio_i2sout_obj_t; diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 33ad3e6840b..7bcfcb88ac7 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -31,14 +31,14 @@ // MEMS mics (SPH0645LM4H, INMP441, ICS-43434) transmit their 24 valid bits // left-justified inside a 32-bit slot. // -// `in pins 1` runs on a cycle where side-set drives BCLK high. The follower +// `in pins 1` runs on a cycle where side-set drives BCLK high. The attached // device updates the data line on the BCLK falling edge, so by the rising edge it // has settled and is safe to sample. Sampling at BCLK low (the previous, // incorrect arrangement) catches the data mid-transition and the result is // effectively noise. #define PIO_CLOCKS_PER_BIT (6) -// Clock-source RX, regular pin order (BCLK = WS - 1), Philips alignment. +// Internal-clock RX, regular pin order (BCLK = WS - 1), Philips alignment. static const uint16_t i2sin_program[] = { 0xb842, // 0: nop side 3 // .wrap_target @@ -57,7 +57,7 @@ static const uint16_t i2sin_program[] = { // .wrap }; -// Clock-source RX, regular pin order, left-justified. +// Internal-clock RX, regular pin order, left-justified. static const uint16_t i2sin_program_left_justified[] = { 0xa842, // 0: nop side 1 // .wrap_target @@ -76,7 +76,7 @@ static const uint16_t i2sin_program_left_justified[] = { // .wrap }; -// Clock-source RX, swapped pin order (BCLK = WS + 1), Philips alignment. +// Internal-clock RX, swapped pin order (BCLK = WS + 1), Philips alignment. static const uint16_t i2sin_program_swap[] = { 0xb842, // 0: nop side 3 // .wrap_target @@ -95,7 +95,7 @@ static const uint16_t i2sin_program_swap[] = { // .wrap }; -// Clock-source RX, swapped pin order, left-justified. +// Internal-clock RX, swapped pin order, left-justified. static const uint16_t i2sin_program_left_justified_swap[] = { 0xb042, // 0: nop side 2 // .wrap_target @@ -189,10 +189,10 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { // .wrap }; -// Clock-follower RX. BCLK and WS are inputs driven by something +// External-clock RX. BCLK and WS are inputs driven by something // else -- another I2S object or the codec -- so the state machine side-sets // nothing and waits on the two clocks instead. `wait gpio` encodes an absolute -// pin index, so unlike the clock-source programs above this one is assembled at +// pin index, so unlike the internal-clock programs above this one is assembled at // construct time with the pin numbers patched in. // // 0: wait 0 gpio W ; resync: find a WS rising edge, i.e. the start @@ -207,7 +207,7 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { // // `set y, 31` + `jmp y--` runs the loop exactly 32 times, so with auto-push at // 32 and shift-left this pushes one 32-bit word per 32 BCLK, MSB first -- -// identical to what the clock-source programs produce, so record_to_buffer and +// identical to what the internal-clock programs produce, so record_to_buffer and // fill_buffer need no changes. One template covers every bit_depth: at 16 bits // a 32-BCLK frame is one push (right<<16 | left), at 24/32 a 64-BCLK frame is // two pushes (right then left). @@ -219,13 +219,13 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { // the other of the two possible alignments; // // Free-running after the initial sync: the external frame must be exactly -// 2 x bits_per_channel BCLKs, the same assumption clock-source mode already bakes +// 2 x bits_per_channel BCLKs, the same assumption internal clock mode already bakes // in. If sync is lost it stays lost. -#define I2SIN_FOLLOWER_MAX_PROGRAM_LEN (8) +#define I2SIN_EXT_CLOCK_MAX_PROGRAM_LEN (8) // The bit loop is the last 5 instructions; everything before it is one-shot sync. -#define I2SIN_FOLLOWER_WRAP_TARGET(len) ((int)(len) - 5) +#define I2SIN_EXT_CLOCK_WRAP_TARGET(len) ((int)(len) - 5) -static size_t build_i2sin_follower_program(uint16_t *prog, uint8_t bclk, uint8_t ws, +static size_t build_i2sin_ext_clock_program(uint16_t *prog, uint8_t bclk, uint8_t ws, bool left_justified, bool invert_bit_clock) { // Sampling on the falling edge of BCLK is the same program with the // polarity of every BCLK wait flipped. @@ -262,7 +262,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, bool mono, bool left_justified, bool samples_signed, - bool clock_follower, bool invert_bit_clock) { + bool external_clock, bool invert_bit_clock) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); @@ -280,11 +280,11 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *sideset_pin = NULL; const uint16_t *program = NULL; size_t program_len = 0; - uint16_t follower_program[I2SIN_FOLLOWER_MAX_PROGRAM_LEN]; + uint16_t ext_clock_program[I2SIN_EXT_CLOCK_MAX_PROGRAM_LEN]; pio_pinmask_t wait_gpio_mask = PIO_PINMASK_NONE; - if (clock_follower) { - // As a clock follower the clocks are `wait gpio` targets, so they + if (external_clock) { + // In external clock mode the clocks are `wait gpio` targets, so they // need not be sequential GPIOs. uint8_t gpio_offset = 0; #if NUM_BANK0_GPIOS > 32 @@ -292,11 +292,11 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, gpio_offset = 16; } #endif - program_len = build_i2sin_follower_program(follower_program, + program_len = build_i2sin_ext_clock_program(ext_clock_program, i2s_wait_gpio_index(bit_clock, gpio_offset), i2s_wait_gpio_index(word_select, gpio_offset), left_justified, invert_bit_clock); - program = follower_program; + program = ext_clock_program; wait_gpio_mask = PIO_PINMASK_OR(PIO_PINMASK_FROM_PIN(bit_clock->number), PIO_PINMASK_FROM_PIN(word_select->number)); } else if (bit_clock->number == word_select->number - 1) { @@ -328,9 +328,9 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, common_hal_rp2pio_statemachine_construct( &self->state_machine, program, program_len, - // As a clock follower the SM is driven by the waits, not the clock + // In external clock mode the SM is driven by the waits, not the clock // divider, so run it at sysclk. - clock_follower ? 0 : sample_rate *pio_clocks_per_frame, + external_clock ? 0 : sample_rate *pio_clocks_per_frame, NULL, 0, // init NULL, 0, // may_exec NULL, 0, PIO_PINMASK32_NONE, PIO_PINMASK32_NONE, // out pin @@ -348,25 +348,25 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, false, // Wait for txstall true, 32, false, // in settings: auto-push at 32 bits, shift left (MSB first) false, // Not user-interruptible. - clock_follower ? I2SIN_FOLLOWER_WRAP_TARGET(program_len) : 1, - clock_follower ? (int)program_len - 1 : -1, // wrap settings + external_clock ? I2SIN_EXT_CLOCK_WRAP_TARGET(program_len) : 1, + external_clock ? (int)program_len - 1 : -1, // wrap settings PIO_ANY_OFFSET, PIO_FIFO_TYPE_DEFAULT, PIO_MOV_STATUS_DEFAULT, PIO_MOV_N_DEFAULT); - // As a clock follower the SM runs at sysclk and the real rate is + // In external clock mode the SM runs at sysclk and the real rate is // whatever the outside world drives WS at, so `sample_rate` is a // declaration rather than a measurement. A mismatch shows up as the same // slow drift the underrun-pad / overflow-drop paths in fill_buffer absorb. - self->sample_rate = clock_follower + self->sample_rate = external_clock ? sample_rate : common_hal_rp2pio_statemachine_get_frequency(&self->state_machine) / pio_clocks_per_frame; self->bit_depth = bit_depth; self->mono = mono; self->samples_signed = samples_signed; self->left_justified = left_justified; - self->clock_follower = clock_follower; + self->external_clock = external_clock; self->settled = false; self->ring = NULL; self->ring_size = 0; @@ -815,12 +815,13 @@ void common_hal_audioi2sin_i2sin_reset_buffer(audioi2sin_i2sin_obj_t *self, } } self->output_index = 0; - // A clock-follower SM free-runs a 32-BCLK counter from the WS edge it + // An external-clock SM free-runs a 32-BCLK counter from the WS edge it // synced to at construct time, so anything that disturbs the frame leaves // it locked to the wrong half-frame or the wrong bit for good. Re-exec the - // program here so playback always begins from a fresh WS sync. A clock source - // generates its own clocks and has nothing to sync to, so leave it alone. - if (self->clock_follower) { + // program here so playback always begins from a fresh WS sync. An + // internal-clock SM generates its own clocks and has nothing to sync to, + // so leave it alone. + if (self->external_clock) { common_hal_rp2pio_statemachine_restart(&self->state_machine); // restart() clears the shift counters but not the RX FIFO, and the // words still sitting in it were captured with the old alignment. diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h index d09def91cc1..594a9fccb02 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.h @@ -27,7 +27,7 @@ typedef struct { bool mono; bool samples_signed; bool left_justified; - bool clock_follower; + bool external_clock; bool settled; rp2pio_statemachine_obj_t state_machine; // Background DMA ring buffer. The state machine alternates DMA writes diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio index ec8906bbd2c..b9d7c9ee28e 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin.pio @@ -7,11 +7,11 @@ .program i2sin .side_set 2 -; Clock-source I2S RX. Generates BCLK and LRCLK via side-set and samples the -; data pin. The follower device updates `data` on BCLK falling edge, so this +; Internal-clock I2S RX. Generates BCLK and LRCLK via side-set and samples the +; data pin. The attached device updates `data` on BCLK falling edge, so this ; program samples on the rising edge: every `in pins 1` runs on a side-set value ; with BCLK=1, and the loop/transition instructions hold BCLK=0 so the -; follower has time to settle the next bit. +; device has time to settle the next bit. ; /--- LRCLK ; |/-- BCLK ; || diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio index ab59688defd..4d79a179668 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_32.pio @@ -7,12 +7,12 @@ .program i2sin_32 .side_set 2 -; Clock-source I2S RX, 32 bits per channel (also used for 24-bit mics that +; Internal-clock I2S RX, 32 bits per channel (also used for 24-bit mics that ; transmit data left-justified in a 32-bit slot). Generates BCLK and LRCLK -; via side-set and samples the data pin. The follower device updates `data` on +; via side-set and samples the data pin. The attached device updates `data` on ; BCLK falling edge, so this program samples on the rising edge: every `in pins 1` ; runs on a side-set value with BCLK=1, and the preceding nop holds BCLK=0 -; so the follower has time to settle the next bit. +; so the device has time to settle the next bit. ; /--- LRCLK ; |/-- BCLK ; || diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio index f0480a67ba1..a5b8cf15970 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left.pio @@ -7,7 +7,7 @@ .program i2sin_left .side_set 2 -; Clock-source I2S RX, left-justified. Mirrors the timing of i2s_left.pio. +; Internal-clock I2S RX, left-justified. Mirrors the timing of i2s_left.pio. ; /--- LRCLK ; |/-- BCLK ; || diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio index ecb7134fcb0..c7c18073c0d 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_left_32.pio @@ -7,7 +7,7 @@ .program i2sin_left_32 .side_set 2 -; Clock-source I2S RX, 32 bits per channel, left-justified. +; Internal-clock I2S RX, 32 bits per channel, left-justified. ; /--- LRCLK ; |/-- BCLK ; || diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio index 40cf9108421..8ff2e468c0c 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap.pio @@ -7,7 +7,7 @@ .program i2sin_swap .side_set 2 -; Clock-source I2S RX with the LRCLK and BCLK pin order swapped (BCLK is the +; Internal-clock I2S RX with the LRCLK and BCLK pin order swapped (BCLK is the ; higher-numbered GPIO). ; /--- BCLK ; |/-- LRCLK diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio index b13c722e6d2..05d92ab019f 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_32.pio @@ -7,7 +7,7 @@ .program i2sin_swap_32 .side_set 2 -; Clock-source I2S RX, 32 bits per channel, with the LRCLK and BCLK pin order +; Internal-clock I2S RX, 32 bits per channel, with the LRCLK and BCLK pin order ; swapped (BCLK is the higher-numbered GPIO). ; /--- BCLK ; |/-- LRCLK diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio index dfcdfcf7482..79fb1bd7a6a 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left.pio @@ -7,7 +7,7 @@ .program i2sin_swap_left .side_set 2 -; Clock-source I2S RX, left-justified, with the LRCLK and BCLK pin order +; Internal-clock I2S RX, left-justified, with the LRCLK and BCLK pin order ; swapped (BCLK is the higher-numbered GPIO). ; /--- BCLK ; |/-- LRCLK diff --git a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio index 80d549c9c1b..0228fa729dd 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio +++ b/ports/raspberrypi/common-hal/audioi2sin/i2sin_swap_left_32.pio @@ -7,7 +7,7 @@ .program i2sin_swap_left_32 .side_set 2 -; Clock-source I2S RX, 32 bits per channel, left-justified, with the LRCLK and +; Internal-clock I2S RX, 32 bits per channel, left-justified, with the LRCLK and ; BCLK pin order swapped (BCLK is the higher-numbered GPIO). ; /--- BCLK ; |/-- LRCLK diff --git a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c index 04d61a6dc20..6c4227acbda 100644 --- a/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c +++ b/ports/zephyr-cp/common-hal/audiobusio/I2SOut.c @@ -46,9 +46,9 @@ mp_obj_t common_hal_audiobusio_i2sout_construct_from_device(audiobusio_i2sout_ob void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, - bool clock_follower) { - if (clock_follower) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_clock_follower); + bool external_clock) { + if (external_clock) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); } mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("Use device tree to define %q devices"), MP_QSTR_I2S); } diff --git a/shared-bindings/audiobusio/I2SOut.c b/shared-bindings/audiobusio/I2SOut.c index 80764fa3c53..a104b20b9da 100644 --- a/shared-bindings/audiobusio/I2SOut.c +++ b/shared-bindings/audiobusio/I2SOut.c @@ -25,7 +25,7 @@ //| *, //| main_clock: Optional[microcontroller.Pin] = None, //| left_justified: bool = False, -//| clock_follower: bool = False, +//| external_clock: bool = False, //| ) -> None: //| """Create a I2SOut object associated with the given pins. //| @@ -35,12 +35,12 @@ //| :param ~microcontroller.Pin main_clock: The main clock pin //| :param bool left_justified: True when data bits are aligned with the word select clock. False //| when they are shifted by one to match classic I2S protocol. -//| :param bool clock_follower: True when this object follows an externally supplied clock: +//| :param bool external_clock: True when this object follows an externally supplied clock: //| ``bit_clock`` and ``word_select`` are inputs driven by something else, another I2S //| object (the clock source), or a codec, rather than generated by this object. Not //| supported on all ports. //| -//| As a clock follower ``bit_clock`` and ``word_select`` do not have to be sequential +//| In external clock mode ``bit_clock`` and ``word_select`` do not have to be sequential //| GPIOs, and they may be shared with another I2S object. `play` cannot retime the bus, so //| the sample's ``sample_rate`` must equal the external frame rate or the pitch will be //| wrong. If the incoming clock stops, output stalls with its last sample held. @@ -92,27 +92,27 @@ static mp_obj_t audiobusio_i2sout_make_new(const mp_obj_type_t *type, size_t n_a mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_I2SOut); return NULL; // Not reachable. #else - enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_left_justified, ARG_clock_follower }; + enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_left_justified, ARG_external_clock }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bit_clock, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_word_select, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_data, MP_ARG_OBJ | MP_ARG_REQUIRED }, { MP_QSTR_main_clock, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = mp_const_none} }, { MP_QSTR_left_justified, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_bool = false} }, - { MP_QSTR_clock_follower, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_external_clock, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - bool clock_follower = args[ARG_clock_follower].u_bool; + bool external_clock = args[ARG_external_clock].u_bool; - // As a clock follower the clock pins are only read, so they may already + // In external clock mode the clock pins are only read, so they may already // be owned by whatever is driving them; let the port decide if the sharing // is legal. - const mcu_pin_obj_t *bit_clock = clock_follower + const mcu_pin_obj_t *bit_clock = external_clock ? validate_obj_is_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock) : validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); - const mcu_pin_obj_t *word_select = clock_follower + const mcu_pin_obj_t *word_select = external_clock ? validate_obj_is_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select) : validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj, MP_QSTR_data); @@ -120,7 +120,7 @@ static mp_obj_t audiobusio_i2sout_make_new(const mp_obj_type_t *type, size_t n_a audiobusio_i2sout_obj_t *self = mp_obj_malloc_with_finaliser(audiobusio_i2sout_obj_t, &audiobusio_i2sout_type); common_hal_audiobusio_i2sout_construct(self, bit_clock, word_select, data, main_clock, - args[ARG_left_justified].u_bool, clock_follower); + args[ARG_left_justified].u_bool, external_clock); return MP_OBJ_FROM_PTR(self); #endif diff --git a/shared-bindings/audiobusio/I2SOut.h b/shared-bindings/audiobusio/I2SOut.h index d99f901fc1e..bc3c944b08d 100644 --- a/shared-bindings/audiobusio/I2SOut.h +++ b/shared-bindings/audiobusio/I2SOut.h @@ -16,7 +16,7 @@ extern const mp_obj_type_t audiobusio_i2sout_type; void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, - const mcu_pin_obj_t *main_clock, bool left_justified, bool clock_follower); + const mcu_pin_obj_t *main_clock, bool left_justified, bool external_clock); void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self); bool common_hal_audiobusio_i2sout_deinited(audiobusio_i2sout_obj_t *self); diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index 3ab5a02bd8b..ad369574c68 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -34,7 +34,7 @@ //| mono: bool = True, //| left_justified: bool = False, //| samples_signed: bool = True, -//| clock_follower: bool = False, +//| external_clock: bool = False, //| invert_bit_clock: bool = False, //| ) -> None: //| """Create an I2SIn object associated with the given pins. This allows you to @@ -85,19 +85,19 @@ //| :param bool samples_signed: Samples are signed (True) or unsigned (False). I2S mics deliver signed //| two's-complement PCM natively; set False to have the recorded samples converted to unsigned PCM //| (the top/sign bit is flipped, matching the WAV convention for unsigned samples). -//| :param bool clock_follower: True when this object follows an externally supplied clock: +//| :param bool external_clock: True when this object follows an externally supplied clock: //| ``bit_clock`` and ``word_select`` are inputs driven by something else. Like an //| `audiobusio.I2SOut` object (the clock source), or a codec, rather than generated by //| this object. Not supported on all ports. //| -//| As a clock follower ``bit_clock`` and ``word_select`` do not have to be sequential +//| In external clock mode ``bit_clock`` and ``word_select`` do not have to be sequential //| GPIOs, and they may be shared with another I2S object. ``sample_rate`` becomes a //| declaration rather than a measurement: the real rate is whatever the external word select //| runs at, and `sample_rate` still reports the declared value. If the incoming clock stops, //| `record` blocks (interruptible with Ctrl-C). //| :param bool invert_bit_clock: Sample ``data`` on the falling edge of ``bit_clock`` instead of //| the rising edge. Needed when the external clock source drives its data on the rising edge. -//| Only valid together with ``clock_follower``. +//| Only valid together with ``external_clock``. //| //| Example, recording 16-bit mono samples from an INMP441:: //| @@ -121,7 +121,7 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_sample_rate, ARG_bit_depth, ARG_output_bit_depth, ARG_mono, ARG_left_justified, ARG_samples_signed, - ARG_clock_follower, ARG_invert_bit_clock }; + ARG_external_clock, ARG_invert_bit_clock }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bit_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_word_select, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -133,26 +133,26 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar { MP_QSTR_mono, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_left_justified, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_samples_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - { MP_QSTR_clock_follower, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_external_clock, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_invert_bit_clock, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - bool clock_follower = args[ARG_clock_follower].u_bool; + bool external_clock = args[ARG_external_clock].u_bool; bool invert_bit_clock = args[ARG_invert_bit_clock].u_bool; - if (invert_bit_clock && !clock_follower) { + if (invert_bit_clock && !external_clock) { mp_raise_ValueError_varg(MP_ERROR_TEXT("%q requires %q"), - MP_QSTR_invert_bit_clock, MP_QSTR_clock_follower); + MP_QSTR_invert_bit_clock, MP_QSTR_external_clock); } - // As a clock follower the clock pins are only read, so they may already + // In external clock mode the clock pins are only read, so they may already // be owned by whatever is driving them; let the port decide if the sharing // is legal. - const mcu_pin_obj_t *bit_clock = clock_follower + const mcu_pin_obj_t *bit_clock = external_clock ? validate_obj_is_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock) : validate_obj_is_free_pin(args[ARG_bit_clock].u_obj, MP_QSTR_bit_clock); - const mcu_pin_obj_t *word_select = clock_follower + const mcu_pin_obj_t *word_select = external_clock ? validate_obj_is_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select) : validate_obj_is_free_pin(args[ARG_word_select].u_obj, MP_QSTR_word_select); const mcu_pin_obj_t *data = validate_obj_is_free_pin(args[ARG_data].u_obj, MP_QSTR_data); @@ -181,7 +181,7 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar audioi2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audioi2sin_i2sin_obj_t, &audioi2sin_i2sin_type); common_hal_audioi2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, sample_rate, bit_depth, output_bit_depth, mono, left_justified, samples_signed, - clock_follower, invert_bit_clock); + external_clock, invert_bit_clock); return MP_OBJ_FROM_PTR(self); #endif diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h index 8c4d9d27a12..7877653858f 100644 --- a/shared-bindings/audioi2sin/I2SIn.h +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -21,7 +21,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, bool mono, bool left_justified, bool samples_signed, - bool clock_follower, bool invert_bit_clock); + bool external_clock, bool invert_bit_clock); void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, From 4e142b62f08e1edfc9a2e836b8cbc30fa0e64564 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 28 Jul 2026 19:12:07 +0200 Subject: [PATCH 695/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 24 ++++++++++++++++++++---- locale/el.po | 24 ++++++++++++++++++++---- locale/hi.po | 24 ++++++++++++++++++++---- locale/ko.po | 24 ++++++++++++++++++++---- locale/ru.po | 24 ++++++++++++++++++++---- locale/tr.po | 24 ++++++++++++++++++++---- 6 files changed, 120 insertions(+), 24 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 611b42f2746..114d346243d 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1254,6 +1254,7 @@ msgid "Not connected" msgstr "Nepřipojený" #: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Already in progress" msgstr "" @@ -1855,6 +1856,12 @@ msgstr "Elementy v bufferu musí být <= 4 bajty" msgid "Touch alarms not available" msgstr "Touch alarmy nejsou dostupné" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "" + #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" @@ -2010,10 +2017,6 @@ msgstr "Chybí first_out_pin. %q[%u] zapisuje do pinu(ů)" msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "Chybí first_in_pin. %q[%u] čte z pinu(ů)" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" - #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" msgstr "Program provedl IN bez načtení ISR" @@ -3743,6 +3746,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c #: shared-bindings/audiofilters/Distortion.c @@ -3759,6 +3763,10 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q requires %q" +msgstr "" + #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4273,6 +4281,14 @@ msgstr "" msgid "%q in %q must be of type %q or %q, not %q" msgstr "" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" + +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate decoder" msgstr "Dekodér nelze přiřadit" diff --git a/locale/el.po b/locale/el.po index af3339e612a..b5dddad0aeb 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1257,6 +1257,7 @@ msgid "Not connected" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Already in progress" msgstr "" @@ -1854,6 +1855,12 @@ msgstr "" msgid "Touch alarms not available" msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "" + #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" @@ -2009,10 +2016,6 @@ msgstr "" msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" - #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" msgstr "" @@ -3742,6 +3745,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c #: shared-bindings/audiofilters/Distortion.c @@ -3758,6 +3762,10 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q requires %q" +msgstr "" + #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4273,6 +4281,14 @@ msgstr "" msgid "%q in %q must be of type %q or %q, not %q" msgstr "" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" + +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate decoder" msgstr "Δεν μπόρεσε να δεσμευτεί decoder" diff --git a/locale/hi.po b/locale/hi.po index e8d82a20db4..40c0531e778 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1248,6 +1248,7 @@ msgid "Not connected" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Already in progress" msgstr "" @@ -1844,6 +1845,12 @@ msgstr "" msgid "Touch alarms not available" msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "" + #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" @@ -1999,10 +2006,6 @@ msgstr "" msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" - #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" msgstr "" @@ -3725,6 +3728,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c #: shared-bindings/audiofilters/Distortion.c @@ -3741,6 +3745,10 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q requires %q" +msgstr "" + #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4254,6 +4262,14 @@ msgstr "" msgid "%q in %q must be of type %q or %q, not %q" msgstr "" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" + +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate decoder" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 0d363de683f..57ab628b0a2 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1262,6 +1262,7 @@ msgid "Not connected" msgstr "연결되지 않았습니다" #: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Already in progress" msgstr "" @@ -1870,6 +1871,12 @@ msgstr "버퍼 내 요소 길이는 <= 4여야 합니다" msgid "Touch alarms not available" msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "" + #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" @@ -2034,10 +2041,6 @@ msgstr "first_out_pin이 누락되었습니다. %q[%u]는 pin(s)에 씁니다" msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "first_in_pin이 누락되어 있습니다. %q[%u]이 pin(s)을 읽습니다" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "" - #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" msgstr "프로그램이 ISR을 로드하지 않고 IN을 실행했습니다" @@ -3781,6 +3784,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c #: shared-bindings/audiofilters/Distortion.c @@ -3797,6 +3801,10 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q requires %q" +msgstr "" + #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4316,6 +4324,14 @@ msgstr "" msgid "%q in %q must be of type %q or %q, not %q" msgstr "" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" + +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate decoder" msgstr "디코더를 할당할 수 없습니다" diff --git a/locale/ru.po b/locale/ru.po index b0a6e3ef710..bc7dd96ac7f 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1261,6 +1261,7 @@ msgid "Not connected" msgstr "Не подключено" #: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Already in progress" msgstr "Уже в процессе" @@ -1870,6 +1871,12 @@ msgstr "Элементы буфера должны быть длиной <= 4 б msgid "Touch alarms not available" msgstr "Сенсорные сигналы недоступны" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "Невозможно использовать GPIO0..15 вместе с GPIO32..47" + #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" @@ -2025,10 +2032,6 @@ msgstr "Отсутствует first_out_pin. %q[%u] записывает выв msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "Отсутствует first_in_pin. %q[%u] читает выводы" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "Невозможно использовать GPIO0..15 вместе с GPIO32..47" - #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" msgstr "Программа выполняет IN без загрузки ISR" @@ -3784,6 +3787,7 @@ msgid "file must be a file opened in byte mode" msgstr "Файл должен быть файлом, открытым в байтовом режиме" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c #: shared-bindings/audiofilters/Distortion.c @@ -3800,6 +3804,10 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q requires %q" +msgstr "" + #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4334,6 +4342,14 @@ msgstr "%q образца не совпадает" msgid "%q in %q must be of type %q or %q, not %q" msgstr "" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" + +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate decoder" msgstr "Не удалось выделить место для декодера" diff --git a/locale/tr.po b/locale/tr.po index 39a25055e11..5f7ce87baee 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1258,6 +1258,7 @@ msgid "Not connected" msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c +#: shared-module/audiofilewriter/AudioFileWriter.c msgid "Already in progress" msgstr "Zaten işlemde" @@ -1860,6 +1861,12 @@ msgstr "Buffer öğeleri <=4 bayt uzunluğunda olmalı" msgid "Touch alarms not available" msgstr "" +#: ports/raspberrypi/common-hal/audiobusio/I2SOut.c +#: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c +msgid "Cannot use GPIO0..15 together with GPIO32..47" +msgstr "GPIO0..15, GPIO32..47 ile birlikte kullanılamaz" + #: ports/raspberrypi/common-hal/audiobusio/I2SOut.c #: ports/raspberrypi/common-hal/audioi2sin/I2SIn.c msgid "Bit clock and word select must be sequential GPIO pins" @@ -2015,10 +2022,6 @@ msgstr "" msgid "Missing first_in_pin. %q[%u] reads pin(s)" msgstr "" -#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c -msgid "Cannot use GPIO0..15 together with GPIO32..47" -msgstr "GPIO0..15, GPIO32..47 ile birlikte kullanılamaz" - #: ports/raspberrypi/common-hal/rp2pio/StateMachine.c msgid "Program does IN without loading ISR" msgstr "" @@ -3743,6 +3746,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c #: shared-bindings/audiofilters/Distortion.c @@ -3759,6 +3763,10 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" +#: shared-bindings/audioi2sin/I2SIn.c +msgid "%q requires %q" +msgstr "" + #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4276,6 +4284,14 @@ msgstr "" msgid "%q in %q must be of type %q or %q, not %q" msgstr "%q'nün içindeki %q, %q veya %q tipi olmalıdır, %q değil" +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "Only 8/16-bit mono/stereo is supported" +msgstr "" + +#: shared-module/audiofilewriter/AudioFileWriter.c +msgid "buffer_size too small for source" +msgstr "" + #: shared-module/audiomp3/MP3Decoder.c msgid "Couldn't allocate decoder" msgstr "Deşifre edici tahsis edilemedi" From a7703b5fabb3050d092d24d5f79d2b3c3f298f80 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 28 Jul 2026 15:39:44 -0400 Subject: [PATCH 696/876] Handle SAME51 boards properly --- ports/atmel-samd/mpconfigport.h | 2 ++ ports/atmel-samd/mpconfigport.mk | 33 ++++---------------------------- 2 files changed, 6 insertions(+), 29 deletions(-) diff --git a/ports/atmel-samd/mpconfigport.h b/ports/atmel-samd/mpconfigport.h index 087e0bc7d68..d6d21c35817 100644 --- a/ports/atmel-samd/mpconfigport.h +++ b/ports/atmel-samd/mpconfigport.h @@ -66,6 +66,8 @@ #define CIRCUITPY_MCU_FAMILY samd51 #ifdef SAMD51 #define MICROPY_PY_SYS_PLATFORM "MicroChip SAMD51" +#elif defined(SAME51) +#define MICROPY_PY_SYS_PLATFORM "MicroChip SAME51" #elif defined(SAME54) #define MICROPY_PY_SYS_PLATFORM "MicroChip SAME54" #endif diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index b0947ea6f25..e252d42968f 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -95,11 +95,11 @@ endif # samd21 ###################################################################### ###################################################################### -# Put samd51-only choices here. +# Put samd51/same51-only choices here. -ifeq ($(CHIP_FAMILY),samd51) +ifneq ($(filter $(CHIP_FAMILY),samd51 same51),) -# No native touchio on SAMD51. +# No native touchio on SAMx51. CIRCUITPY_TOUCHIO_USE_NATIVE = 0 ifeq ($(CIRCUITPY_FULL_BUILD),0) @@ -135,32 +135,7 @@ ifeq ($(CHIP_VARIANT),SAMD51G19A) CIRCUITPY_AUDIOBUSIO = 0 endif -endif # samd51 -###################################################################### - -###################################################################### -# Put same51-only choices here. - -ifeq ($(CHIP_FAMILY),same51) - -# No native touchio on SAME51. -CIRCUITPY_TOUCHIO_USE_NATIVE = 0 - -ifeq ($(CIRCUITPY_FULL_BUILD),0) -CIRCUITPY_LTO_PARTITION ?= one -endif - -# The ?='s allow overriding in mpconfigboard.mk. - -CIRCUITPY_ALARM ?= 1 -CIRCUITPY_PS2IO ?= 1 -CIRCUITPY_SAMD ?= 1 -CIRCUITPY_FLOPPYIO ?= $(CIRCUITPY_FULL_BUILD) -CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD) -CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO) -CIRCUITPY_ULAB_OPTIMIZE_SIZE ?= 1 - -endif # same51 +endif # samd51 / same51 ###################################################################### CIRCUITPY_BUILD_EXTENSIONS ?= uf2 From 536d52fa8f480ec010bbdacbcfaaf508a53e27c0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 28 Jul 2026 16:38:50 -0400 Subject: [PATCH 697/876] treat same54 like same51 in mpconfigprot.mk --- ports/atmel-samd/mpconfigport.mk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/atmel-samd/mpconfigport.mk b/ports/atmel-samd/mpconfigport.mk index e252d42968f..f846f490aa4 100644 --- a/ports/atmel-samd/mpconfigport.mk +++ b/ports/atmel-samd/mpconfigport.mk @@ -95,11 +95,11 @@ endif # samd21 ###################################################################### ###################################################################### -# Put samd51/same51-only choices here. +# Put samx5x-only choices here. -ifneq ($(filter $(CHIP_FAMILY),samd51 same51),) +ifneq ($(filter $(CHIP_FAMILY),samd51 same51 same54),) -# No native touchio on SAMx51. +# No native touchio on SAMx5x. CIRCUITPY_TOUCHIO_USE_NATIVE = 0 ifeq ($(CIRCUITPY_FULL_BUILD),0) @@ -135,7 +135,7 @@ ifeq ($(CHIP_VARIANT),SAMD51G19A) CIRCUITPY_AUDIOBUSIO = 0 endif -endif # samd51 / same51 +endif # samx5x ###################################################################### CIRCUITPY_BUILD_EXTENSIONS ?= uf2 From 95fcfc6dcc6d13befbaefd3065cb281dfe9ae94e Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 28 Jul 2026 17:01:49 -0400 Subject: [PATCH 698/876] dotclockframebuffer: remove obsolete doc re CIRCUITPY_RESERVED_PSRAM --- shared-bindings/dotclockframebuffer/DotClockFramebuffer.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/shared-bindings/dotclockframebuffer/DotClockFramebuffer.c b/shared-bindings/dotclockframebuffer/DotClockFramebuffer.c index faa0c21b097..beee1f07a5b 100644 --- a/shared-bindings/dotclockframebuffer/DotClockFramebuffer.c +++ b/shared-bindings/dotclockframebuffer/DotClockFramebuffer.c @@ -54,13 +54,6 @@ //| When a board has dedicated dot clock framebuffer pins and/or timings, they are intended to be used in the constructor with ``**`` dictionary unpacking like so: //| ``DotClockFramebuffer(**board.TFT_PINS, **board.TFT_TIMINGS)`` //| -//| On Espressif-family microcontrollers, this driver requires that the -//| ``CIRCUITPY_RESERVED_PSRAM`` in ``settings.toml`` be large enough to hold the -//| framebuffer. Generally, boards with built-in displays or display connectors -//| will have a default setting that is large enough for typical use. If the -//| constructor raises a MemoryError or an IDFError, this probably indicates the -//| setting is too small and should be increased. -//| //| TFT connection parameters: //| //| :param microcontroller.Pin de: The "data enable" input to the display From c0f0b5b84cc86acba74df92531da9bb866f2cebb Mon Sep 17 00:00:00 2001 From: Anne Jan Brouwer Date: Wed, 29 Jul 2026 03:24:55 +0200 Subject: [PATCH 699/876] ble_hci: fill in the handle and error code of an ATT Error Response send_error() takes a handle and an error code and then ignored both: the initialiser only set the two opcodes, so every Error Response the device sent carried handle 0x0000 and error code 0x00. 0x00 is not a valid ATT error code, and a client may treat such a response as malformed. BlueZ does. During service discovery it reads Server Supported Features (0x2B3A), no attribute matches, the malformed error comes back, and it abandons the ATT bearer and finishes with an empty database. The peripheral then appears to have no services at all, even though its Read By Group Type Responses were correct. Found on an nRF52840 talking to BlueZ, by reading the ATT exchange over SWD. With the fields filled in, that read is answered with Attribute Not Found, discovery proceeds, and the client sees every service and characteristic. --- devices/ble_hci/common-hal/_bleio/att.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/devices/ble_hci/common-hal/_bleio/att.c b/devices/ble_hci/common-hal/_bleio/att.c index 930b4793161..7e4a43aee97 100644 --- a/devices/ble_hci/common-hal/_bleio/att.c +++ b/devices/ble_hci/common-hal/_bleio/att.c @@ -136,6 +136,8 @@ static void send_error(uint16_t conn_handle, uint8_t opcode, uint16_t handle, ui .code = BT_ATT_OP_ERROR_RSP, }, { .request = opcode, + .handle = handle, + .error = code, }}; hci_send_acl_pkt(conn_handle, BT_L2CAP_CID_ATT, sizeof(rsp), (uint8_t *)&rsp); From 5f8d6309996583350a020caf37e80c1b4248ea83 Mon Sep 17 00:00:00 2001 From: Anne Jan Brouwer Date: Wed, 29 Jul 2026 03:29:29 +0200 Subject: [PATCH 700/876] supervisor: include settings.h when only the BLE serial service is enabled supervisor_bluetooth_init() calls settings_get_bool() under #if (CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE) #if CIRCUITPY_SETTINGS_TOML but the include of settings.h is guarded by a condition that leaves CIRCUITPY_BLE_SERIAL_SERVICE out. Building with the serial service enabled and the file service disabled therefore fails: error: implicit declaration of function 'settings_get_bool' error: nested extern declaration of 'settings_get_bool' Add the missing symbol to the include condition so the two agree. No board in tree currently selects that combination, so nothing is broken today; this only bites when enabling the BLE serial service on its own. --- supervisor/shared/bluetooth/bluetooth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 7a3ca38de44..263aba7cbc9 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -36,7 +36,7 @@ #include "supervisor/shared/status_bar.h" #endif -#if (CIRCUITPY_BLE_FILE_SERVICE || (CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI)) && CIRCUITPY_SETTINGS_TOML +#if (CIRCUITPY_BLE_FILE_SERVICE || CIRCUITPY_BLE_SERIAL_SERVICE || (CIRCUITPY_WEB_WORKFLOW && CIRCUITPY_WIFI)) && CIRCUITPY_SETTINGS_TOML #include "supervisor/shared/settings.h" #endif From b19662d447e269a8018a67d22b2c90c2c181ca99 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 29 Jul 2026 09:59:00 -0500 Subject: [PATCH 701/876] update ep-2350 handle pot pin --- ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c index 035a8aa2acd..ed448aa4def 100644 --- a/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c +++ b/ports/raspberrypi/boards/teenage_engineering_ep2350/pins.c @@ -100,10 +100,13 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_GP27), MP_ROM_PTR(&pin_GPIO27) }, { MP_ROM_QSTR(MP_QSTR_A1), MP_ROM_PTR(&pin_GPIO27) }, - // Rail sense through a resistive divider (VSYS/VBAT / 2). + // Handle position potentiometer: how far the handle has been pressed in. + // Continuous and monotonic over the travel, but it only swings across a + // narrow part of the range, roughly 32370 counts (1.63 V) with the + // handle at rest down to 29850 counts { MP_ROM_QSTR(MP_QSTR_GP28), MP_ROM_PTR(&pin_GPIO28) }, { MP_ROM_QSTR(MP_QSTR_A2), MP_ROM_PTR(&pin_GPIO28) }, - { MP_ROM_QSTR(MP_QSTR_VOLTAGE_MONITOR), MP_ROM_PTR(&pin_GPIO28) }, + { MP_ROM_QSTR(MP_QSTR_HANDLE_POSITION), MP_ROM_PTR(&pin_GPIO28) }, // Volume potentiometer wiper, full scale 0 - 3.3V. { MP_ROM_QSTR(MP_QSTR_GP29), MP_ROM_PTR(&pin_GPIO29) }, From 09a2b49185a33933ac50a624b987edcef75e1f0b Mon Sep 17 00:00:00 2001 From: CDarius Date: Wed, 29 Jul 2026 17:20:23 +0200 Subject: [PATCH 702/876] Fix M5Stack CoreS3 display bus definition --- ports/espressif/boards/m5stack_cores3/mpconfigboard.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/espressif/boards/m5stack_cores3/mpconfigboard.h b/ports/espressif/boards/m5stack_cores3/mpconfigboard.h index 9af6ccf2fb4..74f6ad304ed 100644 --- a/ports/espressif/boards/m5stack_cores3/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_cores3/mpconfigboard.h @@ -17,7 +17,10 @@ #define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) #define DEFAULT_SPI_BUS_MOSI (&pin_GPIO37) -#define DEFAULT_SPI_BUS_MISO (&pin_GPIO35) +// GPIO35 is shared between the TF card MISO and the TFT D/C signal. The display +// claims it as D/C during board_init(), so board.SPI() must not also claim it. +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} #define DEFAULT_UART_BUS_RX (&pin_GPIO18) #define DEFAULT_UART_BUS_TX (&pin_GPIO17) From 53c3273e3c044acf6809e110082397d843087712 Mon Sep 17 00:00:00 2001 From: CDarius Date: Wed, 29 Jul 2026 17:21:31 +0200 Subject: [PATCH 703/876] Fix M5Stack CoreS3 SE display bus definition --- ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h index 070ccf9195e..44b09c6199d 100644 --- a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h @@ -19,7 +19,10 @@ #define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) #define DEFAULT_SPI_BUS_MOSI (&pin_GPIO37) -#define DEFAULT_SPI_BUS_MISO (&pin_GPIO35) +// GPIO35 is shared between the TF card MISO and the TFT D/C signal. The display +// claims it as D/C during board_init(), so board.SPI() must not also claim it. +#define CIRCUITPY_BOARD_SPI (1) +#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} #define DEFAULT_UART_BUS_RX (&pin_GPIO18) #define DEFAULT_UART_BUS_TX (&pin_GPIO17) From 86d9c1bca4c8c4d873bffd00d3a741a28b610332 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 29 Jul 2026 10:23:24 -0500 Subject: [PATCH 704/876] fix crash from deinit'd sample objects --- shared-module/audiocore/__init__.c | 19 +++++++++++++++++++ shared-module/audiodelays/Chorus.c | 14 +++++++++++--- shared-module/audiodelays/Echo.c | 14 +++++++++++--- .../audiodelays/GranularPitchShift.c | 14 +++++++++++--- shared-module/audiodelays/MultiTapDelay.c | 14 +++++++++++--- shared-module/audiodelays/PitchShift.c | 14 +++++++++++--- shared-module/audiofilters/Distortion.c | 14 +++++++++++--- shared-module/audiofilters/Filter.c | 14 +++++++++++--- shared-module/audiofilters/Phaser.c | 14 +++++++++++--- shared-module/audiofreeverb/Freeverb.c | 14 +++++++++++--- shared-module/audiomixer/Mixer.c | 8 ++++++++ 11 files changed, 126 insertions(+), 27 deletions(-) diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 3a80d6b6f42..9edb60dffaa 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -8,6 +8,7 @@ #include "py/obj.h" #include "py/runtime.h" +#include "shared-bindings/audiocore/__init__.h" #include "shared-bindings/audiocore/RawSample.h" #include "shared-bindings/audiocore/WaveFile.h" #include "shared-module/audiocore/RawSample.h" @@ -20,8 +21,17 @@ #include "shared-bindings/audiomixer/Mixer.h" #include "shared-module/audiomixer/Mixer.h" +// Need to confirm that a sample is not deinited before using it, otherwise we +// we read and write through NULL points and fault +static bool audiosample_dispatch_ok(mp_obj_t sample_obj) { + return !audiosample_deinited((const audiosample_base_t *)MP_OBJ_TO_PTR(sample_obj)); +} + void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel_output, uint8_t audio_channel) { const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); + if (!audiosample_dispatch_ok(sample_obj)) { + return; + } proto->reset_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel_output, audio_channel); } @@ -30,6 +40,11 @@ audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); + if (!audiosample_dispatch_ok(sample_obj)) { + *buffer = NULL; + *buffer_length = 0; + return GET_BUFFER_ERROR; + } return proto->get_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel_output, channel, buffer, buffer_length); } @@ -202,6 +217,10 @@ void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool allow_mono_to_stereo) { const audiosample_base_t *other = audiosample_check(other_in); + // Attaching a sample that has already been deinited would leave the caller + // playing something that can never produce audio. + audiosample_check_for_deinit(other); + #if !CIRCUITPY_AUDIOSPEED if (other->sample_rate != self->sample_rate) { #else diff --git a/shared-module/audiodelays/Chorus.c b/shared-module/audiodelays/Chorus.c index 3c35b902189..3331e478f4e 100644 --- a/shared-module/audiodelays/Chorus.c +++ b/shared-module/audiodelays/Chorus.c @@ -218,9 +218,17 @@ audioio_get_buffer_result_t audiodelays_chorus_get_buffer(audiodelays_chorus_obj if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index 0ca5fc8a750..66f2f9a27fa 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -259,9 +259,17 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiodelays/GranularPitchShift.c b/shared-module/audiodelays/GranularPitchShift.c index d439270b48a..f5cebaa7a7d 100644 --- a/shared-module/audiodelays/GranularPitchShift.c +++ b/shared-module/audiodelays/GranularPitchShift.c @@ -308,9 +308,17 @@ audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodel if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiodelays/MultiTapDelay.c b/shared-module/audiodelays/MultiTapDelay.c index 9c33a5eaee7..ddbc5b633a2 100644 --- a/shared-module/audiodelays/MultiTapDelay.c +++ b/shared-module/audiodelays/MultiTapDelay.c @@ -348,9 +348,17 @@ audioio_get_buffer_result_t audiodelays_multi_tap_delay_get_buffer(audiodelays_m if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiodelays/PitchShift.c b/shared-module/audiodelays/PitchShift.c index 3b8c1a07c7b..15c4587f4fa 100644 --- a/shared-module/audiodelays/PitchShift.c +++ b/shared-module/audiodelays/PitchShift.c @@ -205,9 +205,17 @@ audioio_get_buffer_result_t audiodelays_pitch_shift_get_buffer(audiodelays_pitch if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiofilters/Distortion.c b/shared-module/audiofilters/Distortion.c index c4b6b7566ad..ba61506a686 100644 --- a/shared-module/audiofilters/Distortion.c +++ b/shared-module/audiofilters/Distortion.c @@ -192,9 +192,17 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index f9c899e2995..060aef8960a 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -195,9 +195,17 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c index 01b938c3a00..5e2425d40cd 100644 --- a/shared-module/audiofilters/Phaser.c +++ b/shared-module/audiofilters/Phaser.c @@ -182,9 +182,17 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiofreeverb/Freeverb.c b/shared-module/audiofreeverb/Freeverb.c index b57e82cdca2..65d6a27bef0 100644 --- a/shared-module/audiofreeverb/Freeverb.c +++ b/shared-module/audiofreeverb/Freeverb.c @@ -241,9 +241,17 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free if (self->sample) { // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); - // Track length in terms of words. - self->sample_buffer_length /= (self->base.bits_per_sample / 8); - self->more_data = result == GET_BUFFER_MORE_DATA; + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while we were playing it. + self->sample = NULL; + self->sample_buffer_length = 0; + self->more_data = false; + } else { + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } } diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index b6cb3318e54..0faa6d86196 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -192,6 +192,14 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (voice->sample) { // Load another buffer audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t **)&voice->remaining_buffer, &voice->buffer_length); + if (result == GET_BUFFER_ERROR) { + // The sample cannot be read from any more, it was + // deinited while this voice was playing it. Stop the voice. + voice->sample = NULL; + voice->buffer_length = 0; + voice->more_data = false; + break; + } // Track length in terms of words. voice->buffer_length /= sizeof(uint32_t); voice->more_data = result == GET_BUFFER_MORE_DATA; From 3f258b4664ffbf85bb59a4b1e546b937066bafd0 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 29 Jul 2026 11:30:16 -0500 Subject: [PATCH 705/876] refactor audiosample_cast_obj() and remove comments --- shared-module/audiocore/__init__.c | 13 ++----------- shared-module/audiocore/__init__.h | 2 ++ shared-module/audiodelays/Chorus.c | 2 -- shared-module/audiodelays/Echo.c | 2 -- shared-module/audiodelays/GranularPitchShift.c | 2 -- shared-module/audiodelays/MultiTapDelay.c | 2 -- shared-module/audiodelays/PitchShift.c | 2 -- shared-module/audiofilters/Distortion.c | 2 -- shared-module/audiofilters/Filter.c | 2 -- shared-module/audiofilters/Phaser.c | 2 -- shared-module/audiofreeverb/Freeverb.c | 2 -- shared-module/audiomixer/Mixer.c | 2 -- 12 files changed, 4 insertions(+), 31 deletions(-) diff --git a/shared-module/audiocore/__init__.c b/shared-module/audiocore/__init__.c index 9edb60dffaa..9cd561208f3 100644 --- a/shared-module/audiocore/__init__.c +++ b/shared-module/audiocore/__init__.c @@ -21,15 +21,9 @@ #include "shared-bindings/audiomixer/Mixer.h" #include "shared-module/audiomixer/Mixer.h" -// Need to confirm that a sample is not deinited before using it, otherwise we -// we read and write through NULL points and fault -static bool audiosample_dispatch_ok(mp_obj_t sample_obj) { - return !audiosample_deinited((const audiosample_base_t *)MP_OBJ_TO_PTR(sample_obj)); -} - void audiosample_reset_buffer(mp_obj_t sample_obj, bool single_channel_output, uint8_t audio_channel) { const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); - if (!audiosample_dispatch_ok(sample_obj)) { + if (audiosample_deinited(audiosample_cast_obj(sample_obj))) { return; } proto->reset_buffer(MP_OBJ_TO_PTR(sample_obj), single_channel_output, audio_channel); @@ -40,7 +34,7 @@ audioio_get_buffer_result_t audiosample_get_buffer(mp_obj_t sample_obj, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { const audiosample_p_t *proto = mp_proto_get_or_throw(MP_QSTR_protocol_audiosample, sample_obj); - if (!audiosample_dispatch_ok(sample_obj)) { + if (audiosample_deinited(audiosample_cast_obj(sample_obj))) { *buffer = NULL; *buffer_length = 0; return GET_BUFFER_ERROR; @@ -217,10 +211,7 @@ void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, void audiosample_must_match(audiosample_base_t *self, mp_obj_t other_in, bool allow_mono_to_stereo) { const audiosample_base_t *other = audiosample_check(other_in); - // Attaching a sample that has already been deinited would leave the caller - // playing something that can never produce audio. audiosample_check_for_deinit(other); - #if !CIRCUITPY_AUDIOSPEED if (other->sample_rate != self->sample_rate) { #else diff --git a/shared-module/audiocore/__init__.h b/shared-module/audiocore/__init__.h index 920fe752c38..d135ee6c9e9 100644 --- a/shared-module/audiocore/__init__.h +++ b/shared-module/audiocore/__init__.h @@ -114,3 +114,5 @@ void audiosample_convert_u16m_u8s(uint8_t *buffer_out, const uint16_t *buffer_in void audiosample_convert_u16s_u8s(uint8_t *buffer_out, const uint16_t *buffer_in, size_t nframes); void audiosample_convert_s16m_u8s(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes); void audiosample_convert_s16s_u8s(uint8_t *buffer_out, const int16_t *buffer_in, size_t nframes); + +#define audiosample_cast_obj(obj) ((audiosample_base_t *)MP_OBJ_TO_PTR(obj)) diff --git a/shared-module/audiodelays/Chorus.c b/shared-module/audiodelays/Chorus.c index 3331e478f4e..f9dd627c375 100644 --- a/shared-module/audiodelays/Chorus.c +++ b/shared-module/audiodelays/Chorus.c @@ -219,8 +219,6 @@ audioio_get_buffer_result_t audiodelays_chorus_get_buffer(audiodelays_chorus_obj // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index 66f2f9a27fa..b2501b7d01e 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -260,8 +260,6 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiodelays/GranularPitchShift.c b/shared-module/audiodelays/GranularPitchShift.c index f5cebaa7a7d..0408dd45b27 100644 --- a/shared-module/audiodelays/GranularPitchShift.c +++ b/shared-module/audiodelays/GranularPitchShift.c @@ -309,8 +309,6 @@ audioio_get_buffer_result_t audiodelays_granular_pitch_shift_get_buffer(audiodel // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiodelays/MultiTapDelay.c b/shared-module/audiodelays/MultiTapDelay.c index ddbc5b633a2..39887832764 100644 --- a/shared-module/audiodelays/MultiTapDelay.c +++ b/shared-module/audiodelays/MultiTapDelay.c @@ -349,8 +349,6 @@ audioio_get_buffer_result_t audiodelays_multi_tap_delay_get_buffer(audiodelays_m // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiodelays/PitchShift.c b/shared-module/audiodelays/PitchShift.c index 15c4587f4fa..2c5d646aafb 100644 --- a/shared-module/audiodelays/PitchShift.c +++ b/shared-module/audiodelays/PitchShift.c @@ -206,8 +206,6 @@ audioio_get_buffer_result_t audiodelays_pitch_shift_get_buffer(audiodelays_pitch // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiofilters/Distortion.c b/shared-module/audiofilters/Distortion.c index ba61506a686..cf7125c5cee 100644 --- a/shared-module/audiofilters/Distortion.c +++ b/shared-module/audiofilters/Distortion.c @@ -193,8 +193,6 @@ audioio_get_buffer_result_t audiofilters_distortion_get_buffer(audiofilters_dist // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index 060aef8960a..57a763629fa 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -196,8 +196,6 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiofilters/Phaser.c b/shared-module/audiofilters/Phaser.c index 5e2425d40cd..368824b4b43 100644 --- a/shared-module/audiofilters/Phaser.c +++ b/shared-module/audiofilters/Phaser.c @@ -183,8 +183,6 @@ audioio_get_buffer_result_t audiofilters_phaser_get_buffer(audiofilters_phaser_o // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiofreeverb/Freeverb.c b/shared-module/audiofreeverb/Freeverb.c index 65d6a27bef0..d0f1aeaa546 100644 --- a/shared-module/audiofreeverb/Freeverb.c +++ b/shared-module/audiofreeverb/Freeverb.c @@ -242,8 +242,6 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free // Load another sample buffer to play audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while we were playing it. self->sample = NULL; self->sample_buffer_length = 0; self->more_data = false; diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 0faa6d86196..f3111b8dc6f 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -193,8 +193,6 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, // Load another buffer audioio_get_buffer_result_t result = audiosample_get_buffer(voice->sample, false, 0, (uint8_t **)&voice->remaining_buffer, &voice->buffer_length); if (result == GET_BUFFER_ERROR) { - // The sample cannot be read from any more, it was - // deinited while this voice was playing it. Stop the voice. voice->sample = NULL; voice->buffer_length = 0; voice->more_data = false; From 15fd5bb2bf70fa13c2ba5ef4bb00b20beefcc511 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 29 Jul 2026 12:33:47 -0400 Subject: [PATCH 706/876] shrink feather_m4_can --- ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk index ee414b6e214..206716c6879 100644 --- a/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk +++ b/ports/atmel-samd/boards/feather_m4_can/mpconfigboard.mk @@ -19,6 +19,7 @@ CIRCUITPY_I2CTARGET = 0 CIRCUITPY_JPEGIO = 0 CIRCUITPY_PS2IO = 0 CIRCUITPY_SYNTHIO = 0 +CIRCUITPY_VECTORIO = 0 CIRCUITPY_LTO_PARTITION = one From eba2973be2265b120d90836a760e5494fe302bd0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 29 Jul 2026 12:34:42 -0400 Subject: [PATCH 707/876] shrink pimoroni_pico_dv_base_w --- .../raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk index 1eee6ce8e10..016dd0d7269 100644 --- a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk @@ -20,6 +20,7 @@ CIRCUITPY_WIFI = 1 CIRCUITPY_PICODVI = 1 CIRCUITPY_AUDIOFILEWRITER = 0 +CIRCUITPY_BLEIO_HCI = 0 # No room: this board fills FLASH_FIRMWARE. Frees ~9kB. Not the board's I2S # line-out/HDMI audio, which audiobusio still provides. From 152a5f241083de8c1e6a1c3232a7a3c74dc251fc Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 29 Jul 2026 16:05:43 -0400 Subject: [PATCH 708/876] Update lib/mbedtls from 2.28.3 to 4.2.0 Fixes TLS verification against servers addressed by IP: 2.28.3's x509_crt_check_san() matches only dNSName, so iPAddress fell through to "unrecognized type" and any such connection failed with MBEDTLS_ERR_X509_CERT_VERIFY_FAILED on raspberrypi. mbedtls 4.x moves crypto into the nested tf-psa-crypto submodule and splits the configuration in two: MBEDTLS_CONFIG_FILE now covers only TLS and X.509, while algorithms are requested with PSA_WANT_* from TF_PSA_CRYPTO_CONFIG_FILE. The legacy mbedtls_sha256_*() headers also became private. - tools/ci_fetch_deps.py initializes tf-psa-crypto and framework by name rather than with --recursive, which would also pull mldsa-native. - ports/raspberrypi/Makefile generates the PSA driver wrappers with tf-psa-crypto's jinja templates, adding jsonschema to requirements-dev.txt, and globs the source directories instead of listing files. - Randomness comes from the port TRNG via MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG, since 4.x dropped MBEDTLS_ENTROPY_HARDWARE_ALT. This also keeps entropy.c and ctr_drbg.c out of the build. - hashlib uses the public mbedtls_md_*() interface. hashlib.Hash gains a finaliser because mbedtls_md_setup() allocates its digest context. - Protocol versions and crypto are kept in line with espressif, which is already on 4.0.0: TLS 1.2 only, no P-521. ChaCha20-Poly1305 is enabled here and not there, because RP2 has no AES accelerator. - Removes the MBEDTLS_VERSION_MAJOR == 3 branches, which no port ever built. Co-Authored-By: Claude Opus 5 (1M context) --- .gitmodules | 2 +- lib/mbedtls | 2 +- lib/mbedtls_config/crt_bundle.c | 21 - lib/mbedtls_config/hashlib_psa_port.c | 32 + lib/mbedtls_config/mbedtls_config.h | 212 +++--- lib/mbedtls_config/mbedtls_port.c | 64 +- lib/mbedtls_config/tf_psa_crypto_config.h | 133 ++++ .../tf_psa_crypto_config_hashlib.h | 48 ++ lib/mbedtls_errors/do-mp.sh | 13 +- lib/mbedtls_errors/error.fmt | 7 +- lib/mbedtls_errors/generate_errors.diff | 16 +- lib/mbedtls_errors/mp_mbedtls_errors.c | 603 +++--------------- locale/circuitpython.pot | 2 +- ports/raspberrypi/Makefile | 150 ++--- ports/raspberrypi/supervisor/port.c | 4 + py/circuitpy_defns.mk | 59 +- py/circuitpy_mpconfig.h | 4 +- requirements-dev.txt | 3 + shared-module/hashlib/Hash.c | 62 -- shared-module/hashlib/Hash.h | 21 - shared-module/hashlib/__init__.c | 44 +- shared-module/hashlib/__init__.h | 13 - shared-module/ssl/SSLContext.c | 8 + shared-module/ssl/SSLSocket.c | 51 +- shared-module/ssl/SSLSocket.h | 9 - tools/ci_fetch_deps.py | 16 + 26 files changed, 612 insertions(+), 987 deletions(-) create mode 100644 lib/mbedtls_config/hashlib_psa_port.c create mode 100644 lib/mbedtls_config/tf_psa_crypto_config.h create mode 100644 lib/mbedtls_config/tf_psa_crypto_config_hashlib.h diff --git a/.gitmodules b/.gitmodules index a7b67b8d860..f241a4c7eae 100644 --- a/.gitmodules +++ b/.gitmodules @@ -316,7 +316,7 @@ branch = circuitpython9 [submodule "lib/mbedtls"] path = lib/mbedtls - url = https://github.com/ARMmbed/mbedtls.git + url = https://github.com/Mbed-TLS/mbedtls.git [submodule "frozen/Adafruit_CircuitPython_UC8151D"] path = frozen/Adafruit_CircuitPython_UC8151D url = https://github.com/adafruit/Adafruit_CircuitPython_UC8151D diff --git a/lib/mbedtls b/lib/mbedtls index 981743de6fc..ece41aa84d7 160000 --- a/lib/mbedtls +++ b/lib/mbedtls @@ -1 +1 @@ -Subproject commit 981743de6fcdbe672e482b6fd724d31d0a0d2476 +Subproject commit ece41aa84d7879d7e55c59e955a5884b541f7f3b diff --git a/lib/mbedtls_config/crt_bundle.c b/lib/mbedtls_config/crt_bundle.c index 4a8836fb586..01bb497f655 100644 --- a/lib/mbedtls_config/crt_bundle.c +++ b/lib/mbedtls_config/crt_bundle.c @@ -56,10 +56,6 @@ static crt_bundle_t s_crt_bundle; static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len); -#if MBEDTLS_VERSION_MAJOR < 3 -#define MBEDTLS_PRIVATE(x) x -#endif - static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len) { int ret = 0; mbedtls_x509_crt parent; @@ -74,33 +70,16 @@ static int crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_b } - #if MBEDTLS_VERSION_MAJOR < 4 - // Fast check to avoid expensive computations when not necessary - if (!mbedtls_pk_can_do(&parent.pk, child->MBEDTLS_PRIVATE(sig_pk))) { - LOGE(TAG, "Simple compare failed"); - ret = -1; - goto cleanup; - } - #endif - md_info = mbedtls_md_info_from_type(child->MBEDTLS_PRIVATE(sig_md)); if ((ret = mbedtls_md(md_info, child->tbs.p, child->tbs.len, hash)) != 0) { LOGE(TAG, "Internal mbedTLS error %X", ret); goto cleanup; } - #if MBEDTLS_VERSION_MAJOR >= 4 if ((ret = mbedtls_pk_verify_ext( child->MBEDTLS_PRIVATE(sig_pk), &parent.pk, child->MBEDTLS_PRIVATE(sig_md), hash, mbedtls_md_get_size(md_info), child->MBEDTLS_PRIVATE(sig).p, child->MBEDTLS_PRIVATE(sig).len)) != 0) { - #else - if ((ret = mbedtls_pk_verify_ext( - child->MBEDTLS_PRIVATE(sig_pk), child->MBEDTLS_PRIVATE(sig_opts), &parent.pk, - child->MBEDTLS_PRIVATE(sig_md), hash, mbedtls_md_get_size(md_info), - child->MBEDTLS_PRIVATE(sig).p, child->MBEDTLS_PRIVATE(sig).len)) != 0) { - #endif - LOGE(TAG, "PK verify failed with error %X", ret); goto cleanup; } diff --git a/lib/mbedtls_config/hashlib_psa_port.c b/lib/mbedtls_config/hashlib_psa_port.c new file mode 100644 index 00000000000..88a3b96adba --- /dev/null +++ b/lib/mbedtls_config/hashlib_psa_port.c @@ -0,0 +1,32 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Platform glue for ports that build the PSA crypto core for hashlib but not for ssl. +// The ssl equivalent is mbedtls_port.c; the two are mutually exclusive, because +// CIRCUITPY_HASHLIB_MBEDTLS_ONLY means hashlib without ssl. + +#include + +#if CIRCUITPY_HASHLIB_MBEDTLS_ONLY + +#include "psa/crypto.h" + +#include "shared-bindings/os/__init__.h" + +// Required by MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. psa_crypto_init() initializes the RNG +// subsystem even in a build that only ever hashes, so this has to exist. +psa_status_t mbedtls_psa_external_get_random( + mbedtls_psa_external_random_context_t *context, + uint8_t *output, size_t output_size, size_t *output_length) { + (void)context; + if (!common_hal_os_urandom(output, output_size)) { + return PSA_ERROR_INSUFFICIENT_ENTROPY; + } + *output_length = output_size; + return PSA_SUCCESS; +} + +#endif diff --git a/lib/mbedtls_config/mbedtls_config.h b/lib/mbedtls_config/mbedtls_config.h index 7943994e157..062ad11ff17 100644 --- a/lib/mbedtls_config/mbedtls_config.h +++ b/lib/mbedtls_config/mbedtls_config.h @@ -1,130 +1,102 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2018-2019 Damien P. George - * - * 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. - */ -#ifndef MICROPY_INCLUDED_MBEDTLS_CONFIG_H -#define MICROPY_INCLUDED_MBEDTLS_CONFIG_H - -// If you want to debug MBEDTLS uncomment the following and -// Pass 3 to mbedtls_debug_set_threshold in socket_new +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018-2019 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// mbedtls TLS and X.509 configuration, selected with MBEDTLS_CONFIG_FILE. +// +// As of mbedtls 4.0 this file covers only TLS and X.509. Everything cryptographic -- +// algorithms, key types, the platform hooks and the RNG -- is configured in +// tf_psa_crypto_config.h next to this file, and selected with +// TF_PSA_CRYPTO_CONFIG_FILE. + +#pragma once + +// If you want to debug mbedtls, uncomment the following. SSLSocket.c raises the debug +// threshold to 4 when it is set. // #define MBEDTLS_DEBUG_C -// Set mbedtls configuration -#define MBEDTLS_PLATFORM_MEMORY -#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS -#define MBEDTLS_DEPRECATED_REMOVED -#define MBEDTLS_ENTROPY_HARDWARE_ALT -#define MBEDTLS_AES_ROM_TABLES -#define MBEDTLS_CIPHER_MODE_CBC -#define MBEDTLS_ECP_DP_SECP192R1_ENABLED -#define MBEDTLS_ECP_DP_SECP224R1_ENABLED -#define MBEDTLS_ECP_DP_SECP256R1_ENABLED -#define MBEDTLS_ECP_DP_SECP384R1_ENABLED -#define MBEDTLS_ECP_DP_SECP521R1_ENABLED -#define MBEDTLS_ECP_DP_SECP192K1_ENABLED -#define MBEDTLS_ECP_DP_SECP224K1_ENABLED -#define MBEDTLS_ECP_DP_SECP256K1_ENABLED -#define MBEDTLS_ECP_DP_BP256R1_ENABLED -#define MBEDTLS_ECP_DP_BP384R1_ENABLED -#define MBEDTLS_ECP_DP_BP512R1_ENABLED -#define MBEDTLS_ECP_DP_CURVE25519_ENABLED -#define MBEDTLS_ECP_NIST_OPTIM -#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED -#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED -#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED -#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED -#define MBEDTLS_NO_PLATFORM_ENTROPY -#define MBEDTLS_PKCS1_V15 -#define MBEDTLS_SHA256_SMALLER -#define MBEDTLS_SSL_PROTO_TLS1 -#define MBEDTLS_SSL_PROTO_TLS1_1 +// Protocol versions + +// TLS 1.0 and 1.1 were removed in mbedtls 3.0, and were obsolete long before that. +// +// TLS 1.3 is available in 4.x but is turned off, to match espressif +// It also cost 25648 bytes on Pico W, which has only ~50 KB of firmware +// space left. Enabling it here would also require enabling +// MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED, and PSA_WANT_ALG_HKDF* in +// tf_psa_crypto_config.h for the 1.3 key schedule. #define MBEDTLS_SSL_PROTO_TLS1_2 + +// DTLS is deliberately off: common_hal_ssl_sslcontext_wrap_socket() rejects anything +// that is not SOCKETPOOL_SOCK_STREAM, so it could never be reached. + +#define MBEDTLS_SSL_CLI_C +#define MBEDTLS_SSL_SRV_C +#define MBEDTLS_SSL_TLS_C + +// Key exchanges. Without at least one of these there are no TLS 1.2 ciphersuites at +// all, the ClientHello offers nothing, and the server answers with a fatal +// handshake_failure alert. These two are what espressif enables +// (CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_{RSA,ECDSA}) and cover the public web. The PSK +// and ECJPAKE exchanges that 4.x also still offers are not reachable from the ssl +// module, and the static-RSA and DHE exchanges the mbedtls 2.28 config enabled are +// gone from 4.x upstream. +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +// Extensions + #define MBEDTLS_SSL_SERVER_NAME_INDICATION +#define MBEDTLS_SSL_KEEP_PEER_CERTIFICATE +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +// Buffers -// Use a smaller output buffer to reduce size of SSL context +// Accept a full-size record inbound, since we do not control what the peer sends, +// but use a smaller outbound buffer to reduce the SSL context size. #define MBEDTLS_SSL_MAX_CONTENT_LEN (16384) #define MBEDTLS_SSL_IN_CONTENT_LEN (MBEDTLS_SSL_MAX_CONTENT_LEN) #define MBEDTLS_SSL_OUT_CONTENT_LEN (4096) -// Enable mbedtls modules -#define MBEDTLS_AES_C -#define MBEDTLS_ASN1_PARSE_C -#define MBEDTLS_ASN1_WRITE_C -#define MBEDTLS_BASE64_C -#define MBEDTLS_BIGNUM_C -#define MBEDTLS_CIPHER_C -#define MBEDTLS_CTR_DRBG_C -#define MBEDTLS_ECDH_C -#define MBEDTLS_ECDSA_C -#define MBEDTLS_ECP_C -#define MBEDTLS_ENTROPY_C -#define MBEDTLS_ERROR_C -#define MBEDTLS_GCM_C -#define MBEDTLS_MD_C -#define MBEDTLS_MD5_C -#define MBEDTLS_OID_C -#define MBEDTLS_PKCS5_C -#define MBEDTLS_PEM_PARSE_C -#define MBEDTLS_PK_C -#define MBEDTLS_PK_HAVE_ECC_KEYS -#define MBEDTLS_PK_PARSE_C -#define MBEDTLS_PLATFORM_C -#define MBEDTLS_RSA_C -#define MBEDTLS_SHA1_C -#define MBEDTLS_SHA256_C -#define MBEDTLS_SHA512_C -#define MBEDTLS_SSL_CLI_C -#define MBEDTLS_SSL_PROTO_DTLS -#define MBEDTLS_SSL_SRV_C -#define MBEDTLS_SSL_TLS_C -#define MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_KEY_EXCHANGE -#define MBEDTLS_X509_CRT_PARSE_C +// X.509 + #define MBEDTLS_X509_USE_C -#define MBEDTLS_HAVE_TIME -#define MBEDTLS_DHM_C // needed by DHE_PSK -#undef MBEDTLS_HAVE_TIME_DATE - -// Memory allocation hooks -#include -#include -void *m_tracked_calloc(size_t nmemb, size_t size); -void m_tracked_free(void *ptr); -#define MBEDTLS_PLATFORM_STD_CALLOC m_tracked_calloc -#define MBEDTLS_PLATFORM_STD_FREE m_tracked_free -#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf - -// Time hook -#include -time_t rp2_rtctime_seconds(time_t *timer); -#define MBEDTLS_PLATFORM_TIME_MACRO rp2_rtctime_seconds - -#include "mbedtls/check_config.h" - -#endif /* MICROPY_INCLUDED_MBEDTLS_CONFIG_H */ +#define MBEDTLS_X509_CRT_PARSE_C +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +// MBEDTLS_HAVE_TIME_DATE is deliberately left off, so certificate notBefore/notAfter +// are not checked (see the BADCERT_EXPIRED/BADCERT_FUTURE tests in x509_crt.c, which +// are compiled out without it). CircuitPython does not know the wall clock time unless +// the program sets it explicitly, which often does not happen; with an unset clock, +// checking the dates would reject valid certificates rather than catch expired ones. +// espressif does not set CONFIG_MBEDTLS_HAVE_TIME_DATE either. +// +// Nothing else we enable consumes time -- no session tickets, no context +// serialization, no DTLS, no TLS 1.3 -- so MBEDTLS_HAVE_TIME is off as well, and +// mbedtls_port.c needs neither a wall clock nor mbedtls_ms_time(). + +// Error strings + +// SSLSocket.c keys off MBEDTLS_ERROR_C to decide whether to put a message on the +// OSError it raises. mbedtls's own error.c is not built; lib/mbedtls_errors supplies +// a smaller mbedtls_strerror() instead. +#define MBEDTLS_ERROR_C + +// Sanity checks +// +// mbedtls's own mbedtls_check_config.h only validates the prerequisites of options +// that are enabled, so it says nothing when a whole category is missing. This is where +// TF_PSA_CRYPTO_CONFIG_FILE replacing psa/crypto_config.h rather than overlaying it +// bites: every default we rely on has to be restated here, and forgetting one produces +// a build that compiles and links but cannot complete a handshake. +#if !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#error "No MBEDTLS_KEY_EXCHANGE_* enabled: ciphersuite_definitions[] would be empty, " \ + "so the ClientHello would offer nothing and every TLS 1.2 handshake would fail." +#endif diff --git a/lib/mbedtls_config/mbedtls_port.c b/lib/mbedtls_config/mbedtls_port.c index b7e8ceae5de..cc29145e803 100644 --- a/lib/mbedtls_config/mbedtls_port.c +++ b/lib/mbedtls_config/mbedtls_port.c @@ -1,53 +1,29 @@ -/* - * This file is part of the MicroPython project, http://micropython.org/ - * - * The MIT License (MIT) - * - * Copyright (c) 2019 Damien P. George - * - * 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 +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018-2019 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries + +#include "py/mpconfig.h" #if CIRCUITPY_SSL_MBEDTLS -#include "py/runtime.h" -#include "mbedtls_config.h" -#include "mbedtls/entropy_poll.h" +#include "psa/crypto.h" -#include "shared/timeutils/timeutils.h" #include "shared-bindings/os/__init__.h" -#include "shared-bindings/time/__init__.h" - -extern uint8_t rosc_random_u8(size_t cycles); - -int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen) { - *olen = len; - common_hal_os_urandom(data, len); - return 0; -} -time_t rp2_rtctime_seconds(time_t *timer) { - mp_obj_t datetime = mp_load_attr(MP_STATE_VM(rtc_time_source), MP_QSTR_datetime); - timeutils_struct_time_t tm; - struct_time_to_tm(datetime, &tm); - return timeutils_seconds_since_epoch(tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); +// The RNG behind MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG. mbedtls asks for randomness through +// this instead of seeding its own entropy accumulator and CTR-DRBG, so the port's TRNG +// is the only source. `context` is unused; mbedtls initializes it to 0 and we keep no +// state of our own. +psa_status_t mbedtls_psa_external_get_random( + mbedtls_psa_external_random_context_t *context, + uint8_t *output, size_t output_size, size_t *output_length) { + (void)context; + if (!common_hal_os_urandom(output, output_size)) { + return PSA_ERROR_INSUFFICIENT_ENTROPY; + } + *output_length = output_size; + return PSA_SUCCESS; } #endif diff --git a/lib/mbedtls_config/tf_psa_crypto_config.h b/lib/mbedtls_config/tf_psa_crypto_config.h new file mode 100644 index 00000000000..72e69ba5f63 --- /dev/null +++ b/lib/mbedtls_config/tf_psa_crypto_config.h @@ -0,0 +1,133 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018-2019 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// TF-PSA-Crypto configuration, selected with TF_PSA_CRYPTO_CONFIG_FILE. +// +// mbedtls 4.0 split its configuration in two: MBEDTLS_CONFIG_FILE now covers only +// TLS and X.509 (see mbedtls_config.h next to this file), and everything +// cryptographic moved here. Algorithms and key types are requested with PSA_WANT_* +// rather than the old MBEDTLS__C module switches; the builtin implementations +// they need are derived from those by tf-psa-crypto's own config_adjust headers. + +#pragma once + +// Platform integration /////////////////////////////////////////////////////// + +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_DEPRECATED_REMOVED + +// Memory allocation hooks, so mbedtls allocations are tracked like the rest of the +// VM's. +#include +#include +void *m_tracked_calloc(size_t nmemb, size_t size); +void m_tracked_free(void *ptr); +#define MBEDTLS_PLATFORM_STD_CALLOC m_tracked_calloc +#define MBEDTLS_PLATFORM_STD_FREE m_tracked_free +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf + +// Randomness ///////////////////////////////////////////////////////////////// + +// Take randomness straight from the port's TRNG rather than seeding mbedtls's own +// entropy accumulator and CTR-DRBG. mbedtls 4.x dropped MBEDTLS_ENTROPY_HARDWARE_ALT, +// which is how this was wired before, and going direct also keeps entropy.c and +// ctr_drbg.c out of the build. mbedtls_psa_external_get_random() is in +// mbedtls_port.c. +#define MBEDTLS_PSA_CRYPTO_C +#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + +// Size/speed tradeoffs /////////////////////////////////////////////////////// + +#define MBEDTLS_AES_ROM_TABLES +#define MBEDTLS_SHA256_SMALLER +#define MBEDTLS_ECP_NIST_OPTIM + +// Hashes ///////////////////////////////////////////////////////////////////// + +// SHA-1 is still needed to parse certificates that sign with it, and is what +// hashlib exposes as "sha1". +#define PSA_WANT_ALG_SHA_1 +#define PSA_WANT_ALG_SHA_224 +#define PSA_WANT_ALG_SHA_256 +#define PSA_WANT_ALG_SHA_384 +#define PSA_WANT_ALG_SHA_512 +#define PSA_WANT_ALG_HMAC +#define PSA_WANT_KEY_TYPE_HMAC + +// Key derivation ///////////////////////////////////////////////////////////// + +// The TLS 1.2 key schedule. HKDF is deliberately absent: it is the TLS 1.3 key +// schedule, and mbedtls_config.h enables TLS 1.2 only. +#define PSA_WANT_ALG_TLS12_PRF +#define PSA_WANT_ALG_TLS12_PSK_TO_MS +#define PSA_WANT_KEY_TYPE_DERIVE +#define PSA_WANT_KEY_TYPE_RAW_DATA + +// Bulk ciphers /////////////////////////////////////////////////////////////// + +#define PSA_WANT_KEY_TYPE_AES +#define PSA_WANT_ALG_GCM +#define PSA_WANT_ALG_CCM +#define PSA_WANT_ALG_CBC_NO_PADDING +#define PSA_WANT_ALG_CBC_PKCS7 +#define PSA_WANT_ALG_ECB_NO_PADDING + +// RP2 has no AES accelerator, so ChaCha20-Poly1305 is 40-70% faster than AES-GCM here, +// measured over HTTPS on Pico W and Pico 2 W. mbedtls offers it ahead of AES-GCM, and +// real-world CDNs do negotiate it. Costs about 6 kB. espressif leaves it off, since +// ESP32 has AES hardware. +#define PSA_WANT_KEY_TYPE_CHACHA20 +#define PSA_WANT_ALG_CHACHA20_POLY1305 + +// Public key ///////////////////////////////////////////////////////////////// + +#define PSA_WANT_ALG_RSA_PKCS1V15_CRYPT +#define PSA_WANT_ALG_RSA_PKCS1V15_SIGN +#define PSA_WANT_ALG_RSA_PSS +#define PSA_WANT_KEY_TYPE_RSA_PUBLIC_KEY +#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_BASIC +#define PSA_WANT_KEY_TYPE_RSA_KEY_PAIR_IMPORT + +#define PSA_WANT_ALG_ECDH +#define PSA_WANT_ALG_ECDSA +#define PSA_WANT_ALG_DETERMINISTIC_ECDSA +#define PSA_WANT_KEY_TYPE_ECC_PUBLIC_KEY +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_BASIC +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_IMPORT +// An ECDHE handshake generates an ephemeral key pair, sends its public part, then +// runs the key agreement, so it needs GENERATE, EXPORT and DERIVE as well as the two +// above. Without them psa_generate_key() fails and the TLS 1.2 client reports +// MBEDTLS_ERR_SSL_HW_ACCEL_FAILED -- a legacy name that in 4.x just means a PSA call +// failed. See ssl_tls12_client.c. +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_GENERATE +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_EXPORT +#define PSA_WANT_KEY_TYPE_ECC_KEY_PAIR_DERIVE + +// P-256 and P-384 cover essentially every public CA. Curve25519 is here for x25519 +// ECDHE, which servers commonly prefer (RFC 8422). Deliberately absent: +// - P-521: no public CA issues from it, and it cost 5792 bytes on Pico W. +// - Brainpool and secp256k1: unused on the public web. espressif enables secp256k1 +// only because ESP-IDF defaults it on. +// The 192- and 224-bit curves the mbedtls 2.28 config enabled are gone from 4.x +// upstream; there is no PSA_WANT_ECC_SECP_R1_192/_224 to select. +#define PSA_WANT_ECC_SECP_R1_256 +#define PSA_WANT_ECC_SECP_R1_384 +#define PSA_WANT_ECC_MONTGOMERY_255 + +// Key and certificate parsing //////////////////////////////////////////////// + +#define MBEDTLS_PK_C +#define MBEDTLS_PK_PARSE_C +#define MBEDTLS_PK_WRITE_C +#define MBEDTLS_MD_C +#define MBEDTLS_PEM_PARSE_C +#define MBEDTLS_BASE64_C +#define MBEDTLS_PKCS5_C +#define MBEDTLS_ASN1_PARSE_C +#define MBEDTLS_ASN1_WRITE_C diff --git a/lib/mbedtls_config/tf_psa_crypto_config_hashlib.h b/lib/mbedtls_config/tf_psa_crypto_config_hashlib.h new file mode 100644 index 00000000000..0dbf9b13542 --- /dev/null +++ b/lib/mbedtls_config/tf_psa_crypto_config_hashlib.h @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018-2019 Damien P. George +// SPDX-FileCopyrightText: Copyright (c) 2026 Dan Halbert for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// TF-PSA-Crypto configuration for ports that want hashlib but not ssl, selected with +// TF_PSA_CRYPTO_CONFIG_FILE when CIRCUITPY_HASHLIB_MBEDTLS_ONLY is set. +// +// Only the crypto config is needed here: nothing on this path includes +// mbedtls/build_info.h, so no TLS/X.509 configuration is required. +// +// The PSA core is enabled so that hashlib can use the same psa_hash_*() interface on +// every port. It also means PSA_WANT_* behaves as documented: tf-psa-crypto/build_info.h +// only derives the builtin implementations from PSA_WANT_* when MBEDTLS_PSA_CRYPTO_C is +// set, so without it PSA_WANT_ALG_SHA_256 would silently select nothing. + +#pragma once + +#define MBEDTLS_PLATFORM_C +#define MBEDTLS_PLATFORM_MEMORY +#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define MBEDTLS_DEPRECATED_REMOVED + +#undef MBEDTLS_HAVE_TIME +#undef MBEDTLS_HAVE_TIME_DATE + +// The digests hashlib exposes. +#define PSA_WANT_ALG_SHA_1 +#define PSA_WANT_ALG_SHA_256 + +// psa_crypto_init() initializes the RNG subsystem even in a build that only hashes, so +// a random generator has to be available. Take it straight from the port TRNG, which +// keeps entropy.c and ctr_drbg.c out of the build; see hashlib_psa_port.c. +#define MBEDTLS_PSA_CRYPTO_C +#define MBEDTLS_PSA_CRYPTO_EXTERNAL_RNG + +#define MBEDTLS_SHA256_SMALLER + +// Memory allocation hooks +#include +#include +void *m_tracked_calloc(size_t nmemb, size_t size); +void m_tracked_free(void *ptr); +#define MBEDTLS_PLATFORM_STD_CALLOC m_tracked_calloc +#define MBEDTLS_PLATFORM_STD_FREE m_tracked_free +#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf diff --git a/lib/mbedtls_errors/do-mp.sh b/lib/mbedtls_errors/do-mp.sh index 5c6b9711794..3713b0087a7 100755 --- a/lib/mbedtls_errors/do-mp.sh +++ b/lib/mbedtls_errors/do-mp.sh @@ -1,4 +1,15 @@ #! /bin/bash -e # Generate mp_mbedtls_errors.c for inclusion in ports that use $MPY/lib/mbedtls +# +# As of mbedtls 4.0 the error #defines live in two trees: TLS and X.509 in +# mbedtls/include/mbedtls, and the legacy crypto modules in tf-psa-crypto, so +# generate_errors.pl now takes the crypto include directory as well. patch -o mp_generate_errors.pl ../mbedtls/scripts/generate_errors.pl -#if defined(MBEDTLS_AES_C) -#include "mbedtls/aes.h" +#if defined(MBEDTLS_NET_C) +#include "mbedtls/net_sockets.h" #endif -#if defined(MBEDTLS_ARC4_C) -#include "mbedtls/arc4.h" +#if defined(MBEDTLS_PKCS7_C) +#include "mbedtls/pkcs7.h" #endif -#if defined(MBEDTLS_ARIA_C) -#include "mbedtls/aria.h" +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl.h" #endif -#if defined(MBEDTLS_ASN1_PARSE_C) -#include "mbedtls/asn1.h" +#if defined(MBEDTLS_X509_USE_C) || \ + defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" #endif -#if defined(MBEDTLS_BASE64_C) -#include "mbedtls/base64.h" +#if defined(MBEDTLS_AES_C) +#include "mbedtls/private/aes.h" #endif -#if defined(MBEDTLS_BIGNUM_C) -#include "mbedtls/bignum.h" +#if defined(MBEDTLS_ARIA_C) +#include "mbedtls/private/aria.h" #endif -#if defined(MBEDTLS_BLOWFISH_C) -#include "mbedtls/blowfish.h" +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/private/bignum.h" #endif #if defined(MBEDTLS_CAMELLIA_C) -#include "mbedtls/camellia.h" -#endif - -#if defined(MBEDTLS_CCM_C) -#include "mbedtls/ccm.h" -#endif - -#if defined(MBEDTLS_CHACHA20_C) -#include "mbedtls/chacha20.h" +#include "mbedtls/private/camellia.h" #endif #if defined(MBEDTLS_CHACHAPOLY_C) -#include "mbedtls/chachapoly.h" +#include "mbedtls/private/chachapoly.h" #endif #if defined(MBEDTLS_CIPHER_C) -#include "mbedtls/cipher.h" -#endif - -#if defined(MBEDTLS_CMAC_C) -#include "mbedtls/cmac.h" +#include "mbedtls/private/cipher.h" #endif #if defined(MBEDTLS_CTR_DRBG_C) -#include "mbedtls/ctr_drbg.h" -#endif - -#if defined(MBEDTLS_DES_C) -#include "mbedtls/des.h" -#endif - -#if defined(MBEDTLS_DHM_C) -#include "mbedtls/dhm.h" +#include "mbedtls/private/ctr_drbg.h" #endif #if defined(MBEDTLS_ECP_C) -#include "mbedtls/ecp.h" +#include "mbedtls/private/ecp.h" #endif #if defined(MBEDTLS_ENTROPY_C) -#include "mbedtls/entropy.h" -#endif - -#if defined(MBEDTLS_ERROR_C) -#include "mbedtls/error.h" -#endif - -#if defined(MBEDTLS_GCM_C) -#include "mbedtls/gcm.h" -#endif - -#if defined(MBEDTLS_HKDF_C) -#include "mbedtls/hkdf.h" +#include "mbedtls/private/entropy.h" #endif #if defined(MBEDTLS_HMAC_DRBG_C) -#include "mbedtls/hmac_drbg.h" -#endif - -#if defined(MBEDTLS_MD_C) -#include "mbedtls/md.h" -#endif - -#if defined(MBEDTLS_MD2_C) -#include "mbedtls/md2.h" -#endif - -#if defined(MBEDTLS_MD4_C) -#include "mbedtls/md4.h" -#endif - -#if defined(MBEDTLS_MD5_C) -#include "mbedtls/md5.h" -#endif - -#if defined(MBEDTLS_NET_C) -#include "mbedtls/net_sockets.h" -#endif - -#if defined(MBEDTLS_OID_C) -#include "mbedtls/oid.h" -#endif - -#if defined(MBEDTLS_PADLOCK_C) -#if defined(MBEDTLS_PADLOCK_FILE) -#include MBEDTLS_PADLOCK_FILE -#else -#include "mbedtls/padlock.h" -#endif -#endif - -#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) -#include "mbedtls/pem.h" -#endif - -#if defined(MBEDTLS_PK_C) -#include "mbedtls/pk.h" -#endif - -#if defined(MBEDTLS_PKCS12_C) -#include "mbedtls/pkcs12.h" +#include "mbedtls/private/hmac_drbg.h" #endif #if defined(MBEDTLS_PKCS5_C) -#include "mbedtls/pkcs5.h" -#endif - -#if defined(MBEDTLS_PLATFORM_C) -#include "mbedtls/platform.h" -#endif - -#if defined(MBEDTLS_POLY1305_C) -#include "mbedtls/poly1305.h" -#endif - -#if defined(MBEDTLS_RIPEMD160_C) -#include "mbedtls/ripemd160.h" +#include "mbedtls/private/pkcs5.h" #endif #if defined(MBEDTLS_RSA_C) -#include "mbedtls/rsa.h" -#endif - -#if defined(MBEDTLS_SHA1_C) -#include "mbedtls/sha1.h" -#endif - -#if defined(MBEDTLS_SHA256_C) -#include "mbedtls/sha256.h" -#endif - -#if defined(MBEDTLS_SHA512_C) -#include "mbedtls/sha512.h" -#endif - -#if defined(MBEDTLS_SSL_TLS_C) -#include "mbedtls/ssl.h" -#endif - -#if defined(MBEDTLS_THREADING_C) -#include "mbedtls/threading.h" -#endif - -#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) -#include "mbedtls/x509.h" -#endif - -#if defined(MBEDTLS_XTEA_C) -#include "mbedtls/xtea.h" +#include "mbedtls/private/rsa.h" #endif @@ -231,197 +112,44 @@ struct ssl_errs { // Table of high level error codes static const struct ssl_errs mbedtls_high_level_error_tab[] = { // BEGIN generated code -#if defined(MBEDTLS_CIPHER_C) - { -(MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE), "CIPHER_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA), "CIPHER_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_CIPHER_ALLOC_FAILED), "CIPHER_ALLOC_FAILED" }, - { -(MBEDTLS_ERR_CIPHER_INVALID_PADDING), "CIPHER_INVALID_PADDING" }, - { -(MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED), "CIPHER_FULL_BLOCK_EXPECTED" }, - { -(MBEDTLS_ERR_CIPHER_AUTH_FAILED), "CIPHER_AUTH_FAILED" }, - { -(MBEDTLS_ERR_CIPHER_INVALID_CONTEXT), "CIPHER_INVALID_CONTEXT" }, -#if defined(MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_CIPHER_HW_ACCEL_FAILED), "CIPHER_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_CIPHER_C */ - -#if defined(MBEDTLS_DHM_C) - { -(MBEDTLS_ERR_DHM_BAD_INPUT_DATA), "DHM_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED), "DHM_READ_PARAMS_FAILED" }, - { -(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED), "DHM_MAKE_PARAMS_FAILED" }, - { -(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED), "DHM_READ_PUBLIC_FAILED" }, - { -(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED), "DHM_MAKE_PUBLIC_FAILED" }, - { -(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED), "DHM_CALC_SECRET_FAILED" }, - { -(MBEDTLS_ERR_DHM_INVALID_FORMAT), "DHM_INVALID_FORMAT" }, - { -(MBEDTLS_ERR_DHM_ALLOC_FAILED), "DHM_ALLOC_FAILED" }, - { -(MBEDTLS_ERR_DHM_FILE_IO_ERROR), "DHM_FILE_IO_ERROR" }, - { -(MBEDTLS_ERR_DHM_HW_ACCEL_FAILED), "DHM_HW_ACCEL_FAILED" }, - { -(MBEDTLS_ERR_DHM_SET_GROUP_FAILED), "DHM_SET_GROUP_FAILED" }, -#endif /* MBEDTLS_DHM_C */ - -#if defined(MBEDTLS_ECP_C) - { -(MBEDTLS_ERR_ECP_BAD_INPUT_DATA), "ECP_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL), "ECP_BUFFER_TOO_SMALL" }, - { -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE), "ECP_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_ECP_VERIFY_FAILED), "ECP_VERIFY_FAILED" }, - { -(MBEDTLS_ERR_ECP_ALLOC_FAILED), "ECP_ALLOC_FAILED" }, - { -(MBEDTLS_ERR_ECP_RANDOM_FAILED), "ECP_RANDOM_FAILED" }, - { -(MBEDTLS_ERR_ECP_INVALID_KEY), "ECP_INVALID_KEY" }, - { -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH), "ECP_SIG_LEN_MISMATCH" }, -#if defined(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_ECP_HW_ACCEL_FAILED), "ECP_HW_ACCEL_FAILED" }, -#endif - { -(MBEDTLS_ERR_ECP_IN_PROGRESS), "ECP_IN_PROGRESS" }, -#endif /* MBEDTLS_ECP_C */ - -#if defined(MBEDTLS_MD_C) - { -(MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE), "MD_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_MD_BAD_INPUT_DATA), "MD_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_MD_ALLOC_FAILED), "MD_ALLOC_FAILED" }, - { -(MBEDTLS_ERR_MD_FILE_IO_ERROR), "MD_FILE_IO_ERROR" }, -#if defined(MBEDTLS_ERR_MD_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_MD_HW_ACCEL_FAILED), "MD_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_MD_C */ - -#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) - { -(MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT), "PEM_NO_HEADER_FOOTER_PRESENT" }, - { -(MBEDTLS_ERR_PEM_INVALID_DATA), "PEM_INVALID_DATA" }, - { -(MBEDTLS_ERR_PEM_ALLOC_FAILED), "PEM_ALLOC_FAILED" }, - { -(MBEDTLS_ERR_PEM_INVALID_ENC_IV), "PEM_INVALID_ENC_IV" }, - { -(MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG), "PEM_UNKNOWN_ENC_ALG" }, - { -(MBEDTLS_ERR_PEM_PASSWORD_REQUIRED), "PEM_PASSWORD_REQUIRED" }, - { -(MBEDTLS_ERR_PEM_PASSWORD_MISMATCH), "PEM_PASSWORD_MISMATCH" }, - { -(MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE), "PEM_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_PEM_BAD_INPUT_DATA), "PEM_BAD_INPUT_DATA" }, -#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ - -#if defined(MBEDTLS_PK_C) - { -(MBEDTLS_ERR_PK_ALLOC_FAILED), "PK_ALLOC_FAILED" }, - { -(MBEDTLS_ERR_PK_TYPE_MISMATCH), "PK_TYPE_MISMATCH" }, - { -(MBEDTLS_ERR_PK_BAD_INPUT_DATA), "PK_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_PK_FILE_IO_ERROR), "PK_FILE_IO_ERROR" }, - { -(MBEDTLS_ERR_PK_KEY_INVALID_VERSION), "PK_KEY_INVALID_VERSION" }, - { -(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT), "PK_KEY_INVALID_FORMAT" }, - { -(MBEDTLS_ERR_PK_UNKNOWN_PK_ALG), "PK_UNKNOWN_PK_ALG" }, - { -(MBEDTLS_ERR_PK_PASSWORD_REQUIRED), "PK_PASSWORD_REQUIRED" }, - { -(MBEDTLS_ERR_PK_PASSWORD_MISMATCH), "PK_PASSWORD_MISMATCH" }, - { -(MBEDTLS_ERR_PK_INVALID_PUBKEY), "PK_INVALID_PUBKEY" }, - { -(MBEDTLS_ERR_PK_INVALID_ALG), "PK_INVALID_ALG" }, - { -(MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE), "PK_UNKNOWN_NAMED_CURVE" }, - { -(MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE), "PK_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_PK_SIG_LEN_MISMATCH), "PK_SIG_LEN_MISMATCH" }, -#if defined(MBEDTLS_ERR_PK_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_PK_HW_ACCEL_FAILED), "PK_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_PK_C */ - -#if defined(MBEDTLS_PKCS12_C) - { -(MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA), "PKCS12_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE), "PKCS12_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT), "PKCS12_PBE_INVALID_FORMAT" }, - { -(MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH), "PKCS12_PASSWORD_MISMATCH" }, -#endif /* MBEDTLS_PKCS12_C */ - -#if defined(MBEDTLS_PKCS5_C) - { -(MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA), "PKCS5_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_PKCS5_INVALID_FORMAT), "PKCS5_INVALID_FORMAT" }, - { -(MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE), "PKCS5_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH), "PKCS5_PASSWORD_MISMATCH" }, -#endif /* MBEDTLS_PKCS5_C */ - -#if defined(MBEDTLS_RSA_C) - { -(MBEDTLS_ERR_RSA_BAD_INPUT_DATA), "RSA_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_RSA_INVALID_PADDING), "RSA_INVALID_PADDING" }, - { -(MBEDTLS_ERR_RSA_KEY_GEN_FAILED), "RSA_KEY_GEN_FAILED" }, - { -(MBEDTLS_ERR_RSA_KEY_CHECK_FAILED), "RSA_KEY_CHECK_FAILED" }, - { -(MBEDTLS_ERR_RSA_PUBLIC_FAILED), "RSA_PUBLIC_FAILED" }, - { -(MBEDTLS_ERR_RSA_PRIVATE_FAILED), "RSA_PRIVATE_FAILED" }, - { -(MBEDTLS_ERR_RSA_VERIFY_FAILED), "RSA_VERIFY_FAILED" }, - { -(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE), "RSA_OUTPUT_TOO_LARGE" }, - { -(MBEDTLS_ERR_RSA_RNG_FAILED), "RSA_RNG_FAILED" }, -#if defined(MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION) - { -(MBEDTLS_ERR_RSA_UNSUPPORTED_OPERATION), "RSA_UNSUPPORTED_OPERATION" }, -#endif -#if defined(MBEDTLS_ERR_RSA_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_RSA_HW_ACCEL_FAILED), "RSA_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_PKCS7_C) + { -(MBEDTLS_ERR_PKCS7_INVALID_FORMAT), "PKCS7_INVALID_FORMAT" }, + { -(MBEDTLS_ERR_PKCS7_FEATURE_UNAVAILABLE), "PKCS7_FEATURE_UNAVAILABLE" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_VERSION), "PKCS7_INVALID_VERSION" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_CONTENT_INFO), "PKCS7_INVALID_CONTENT_INFO" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_ALG), "PKCS7_INVALID_ALG" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_CERT), "PKCS7_INVALID_CERT" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_SIGNATURE), "PKCS7_INVALID_SIGNATURE" }, + { -(MBEDTLS_ERR_PKCS7_INVALID_SIGNER_INFO), "PKCS7_INVALID_SIGNER_INFO" }, + { -(MBEDTLS_ERR_PKCS7_CERT_DATE_INVALID), "PKCS7_CERT_DATE_INVALID" }, +#endif /* MBEDTLS_PKCS7_C */ #if defined(MBEDTLS_SSL_TLS_C) + { -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS), "SSL_CRYPTO_IN_PROGRESS" }, { -(MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE), "SSL_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_SSL_BAD_INPUT_DATA), "SSL_BAD_INPUT_DATA" }, { -(MBEDTLS_ERR_SSL_INVALID_MAC), "SSL_INVALID_MAC" }, { -(MBEDTLS_ERR_SSL_INVALID_RECORD), "SSL_INVALID_RECORD" }, { -(MBEDTLS_ERR_SSL_CONN_EOF), "SSL_CONN_EOF" }, -#if defined(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER) - { -(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER), "SSL_UNKNOWN_CIPHER" }, -#endif -#if defined(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) - { -(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN), "SSL_NO_CIPHER_CHOSEN" }, -#endif + { -(MBEDTLS_ERR_SSL_DECODE_ERROR), "SSL_DECODE_ERROR" }, { -(MBEDTLS_ERR_SSL_NO_RNG), "SSL_NO_RNG" }, { -(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE), "SSL_NO_CLIENT_CERTIFICATE" }, -#if defined(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE) - { -(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE), "SSL_CERTIFICATE_TOO_LARGE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED) - { -(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED), "SSL_CERTIFICATE_REQUIRED" }, -#endif + { -(MBEDTLS_ERR_SSL_UNSUPPORTED_EXTENSION), "SSL_UNSUPPORTED_EXTENSION" }, + { -(MBEDTLS_ERR_SSL_NO_APPLICATION_PROTOCOL), "SSL_NO_APPLICATION_PROTOCOL" }, { -(MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED), "SSL_PRIVATE_KEY_REQUIRED" }, { -(MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED), "SSL_CA_CHAIN_REQUIRED" }, { -(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE), "SSL_UNEXPECTED_MESSAGE" }, -#if defined(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED) - { -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED), "SSL_PEER_VERIFY_FAILED" }, -#endif + { -(MBEDTLS_ERR_SSL_UNRECOGNIZED_NAME), "SSL_UNRECOGNIZED_NAME" }, { -(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY), "SSL_PEER_CLOSE_NOTIFY" }, -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) - { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO), "SSL_BAD_HS_CLIENT_HELLO" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO) - { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO), "SSL_BAD_HS_SERVER_HELLO" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE) - { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE), "SSL_BAD_HS_CERTIFICATE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST) - { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST), "SSL_BAD_HS_CERTIFICATE_REQUEST" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE) - { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE), "SSL_BAD_HS_SERVER_KEY_EXCHANGE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE) - { -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE), "SSL_BAD_HS_SERVER_HELLO_DONE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) - { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP) - { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS) - { -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS), "SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY) - { -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY), "SSL_BAD_HS_CERTIFICATE_VERIFY" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC) - { -(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC), "SSL_BAD_HS_CHANGE_CIPHER_SPEC" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_FINISHED) - { -(MBEDTLS_ERR_SSL_BAD_HS_FINISHED), "SSL_BAD_HS_FINISHED" }, -#endif - { -(MBEDTLS_ERR_SSL_ALLOC_FAILED), "SSL_ALLOC_FAILED" }, + { -(MBEDTLS_ERR_SSL_BAD_CERTIFICATE), "SSL_BAD_CERTIFICATE" }, + { -(MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET), "SSL_RECEIVED_NEW_SESSION_TICKET" }, + { -(MBEDTLS_ERR_SSL_CANNOT_READ_EARLY_DATA), "SSL_CANNOT_READ_EARLY_DATA" }, + { -(MBEDTLS_ERR_SSL_RECEIVED_EARLY_DATA), "SSL_RECEIVED_EARLY_DATA" }, + { -(MBEDTLS_ERR_SSL_CANNOT_WRITE_EARLY_DATA), "SSL_CANNOT_WRITE_EARLY_DATA" }, + { -(MBEDTLS_ERR_SSL_CACHE_ENTRY_NOT_FOUND), "SSL_CACHE_ENTRY_NOT_FOUND" }, { -(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED), "SSL_HW_ACCEL_FAILED" }, { -(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH), "SSL_HW_ACCEL_FALLTHROUGH" }, -#if defined(MBEDTLS_ERR_SSL_COMPRESSION_FAILED) - { -(MBEDTLS_ERR_SSL_COMPRESSION_FAILED), "SSL_COMPRESSION_FAILED" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) - { -(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION), "SSL_BAD_HS_PROTOCOL_VERSION" }, -#endif -#if defined(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET) - { -(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET), "SSL_BAD_HS_NEW_SESSION_TICKET" }, -#endif + { -(MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION), "SSL_BAD_PROTOCOL_VERSION" }, + { -(MBEDTLS_ERR_SSL_HANDSHAKE_FAILURE), "SSL_HANDSHAKE_FAILURE" }, { -(MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED), "SSL_SESSION_TICKET_EXPIRED" }, { -(MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH), "SSL_PK_TYPE_MISMATCH" }, { -(MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY), "SSL_UNKNOWN_IDENTITY" }, @@ -429,29 +157,24 @@ static const struct ssl_errs mbedtls_high_level_error_tab[] = { { -(MBEDTLS_ERR_SSL_COUNTER_WRAPPING), "SSL_COUNTER_WRAPPING" }, { -(MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO), "SSL_WAITING_SERVER_HELLO_RENEGO" }, { -(MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED), "SSL_HELLO_VERIFY_REQUIRED" }, - { -(MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL), "SSL_BUFFER_TOO_SMALL" }, -#if defined(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) - { -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE), "SSL_NO_USABLE_CIPHERSUITE" }, -#endif { -(MBEDTLS_ERR_SSL_WANT_READ), "SSL_WANT_READ" }, { -(MBEDTLS_ERR_SSL_WANT_WRITE), "SSL_WANT_WRITE" }, { -(MBEDTLS_ERR_SSL_TIMEOUT), "SSL_TIMEOUT" }, { -(MBEDTLS_ERR_SSL_CLIENT_RECONNECT), "SSL_CLIENT_RECONNECT" }, { -(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD), "SSL_UNEXPECTED_RECORD" }, { -(MBEDTLS_ERR_SSL_NON_FATAL), "SSL_NON_FATAL" }, -#if defined(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) - { -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH), "SSL_INVALID_VERIFY_HASH" }, -#endif + { -(MBEDTLS_ERR_SSL_ILLEGAL_PARAMETER), "SSL_ILLEGAL_PARAMETER" }, { -(MBEDTLS_ERR_SSL_CONTINUE_PROCESSING), "SSL_CONTINUE_PROCESSING" }, { -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS), "SSL_ASYNC_IN_PROGRESS" }, { -(MBEDTLS_ERR_SSL_EARLY_MESSAGE), "SSL_EARLY_MESSAGE" }, { -(MBEDTLS_ERR_SSL_UNEXPECTED_CID), "SSL_UNEXPECTED_CID" }, { -(MBEDTLS_ERR_SSL_VERSION_MISMATCH), "SSL_VERSION_MISMATCH" }, - { -(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS), "SSL_CRYPTO_IN_PROGRESS" }, { -(MBEDTLS_ERR_SSL_BAD_CONFIG), "SSL_BAD_CONFIG" }, + { -(MBEDTLS_ERR_SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME), "SSL_CERTIFICATE_VERIFICATION_WITHOUT_HOSTNAME" }, #endif /* MBEDTLS_SSL_TLS_C */ -#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#if defined(MBEDTLS_X509_USE_C) || \ + defined(MBEDTLS_X509_CREATE_C) { -(MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE), "X509_FEATURE_UNAVAILABLE" }, { -(MBEDTLS_ERR_X509_UNKNOWN_OID), "X509_UNKNOWN_OID" }, { -(MBEDTLS_ERR_X509_INVALID_FORMAT), "X509_INVALID_FORMAT" }, @@ -468,11 +191,34 @@ static const struct ssl_errs mbedtls_high_level_error_tab[] = { { -(MBEDTLS_ERR_X509_CERT_VERIFY_FAILED), "X509_CERT_VERIFY_FAILED" }, { -(MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT), "X509_CERT_UNKNOWN_FORMAT" }, { -(MBEDTLS_ERR_X509_BAD_INPUT_DATA), "X509_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_X509_ALLOC_FAILED), "X509_ALLOC_FAILED" }, { -(MBEDTLS_ERR_X509_FILE_IO_ERROR), "X509_FILE_IO_ERROR" }, - { -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL), "X509_BUFFER_TOO_SMALL" }, { -(MBEDTLS_ERR_X509_FATAL_ERROR), "X509_FATAL_ERROR" }, -#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ +#endif /* MBEDTLS_X509_USE_C || + MBEDTLS_X509_CREATE_C */ + +#if defined(MBEDTLS_CIPHER_C) + { -(MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE), "CIPHER_FEATURE_UNAVAILABLE" }, + { -(MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED), "CIPHER_FULL_BLOCK_EXPECTED" }, + { -(MBEDTLS_ERR_CIPHER_INVALID_CONTEXT), "CIPHER_INVALID_CONTEXT" }, +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_ECP_C) + { -(MBEDTLS_ERR_ECP_INVALID_KEY), "ECP_INVALID_KEY" }, +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_PKCS5_C) + { -(MBEDTLS_ERR_PKCS5_INVALID_FORMAT), "PKCS5_INVALID_FORMAT" }, + { -(MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE), "PKCS5_FEATURE_UNAVAILABLE" }, + { -(MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH), "PKCS5_PASSWORD_MISMATCH" }, +#endif /* MBEDTLS_PKCS5_C */ + +#if defined(MBEDTLS_RSA_C) + { -(MBEDTLS_ERR_RSA_KEY_GEN_FAILED), "RSA_KEY_GEN_FAILED" }, + { -(MBEDTLS_ERR_RSA_KEY_CHECK_FAILED), "RSA_KEY_CHECK_FAILED" }, + { -(MBEDTLS_ERR_RSA_PUBLIC_FAILED), "RSA_PUBLIC_FAILED" }, + { -(MBEDTLS_ERR_RSA_PRIVATE_FAILED), "RSA_PRIVATE_FAILED" }, + { -(MBEDTLS_ERR_RSA_RNG_FAILED), "RSA_RNG_FAILED" }, +#endif /* MBEDTLS_RSA_C */ // END generated code }; @@ -480,98 +226,46 @@ static const struct ssl_errs mbedtls_low_level_error_tab[] = { // Low level error codes // // BEGIN generated code +#if defined(MBEDTLS_NET_C) + { -(MBEDTLS_ERR_NET_SOCKET_FAILED), "NET_SOCKET_FAILED" }, + { -(MBEDTLS_ERR_NET_CONNECT_FAILED), "NET_CONNECT_FAILED" }, + { -(MBEDTLS_ERR_NET_BIND_FAILED), "NET_BIND_FAILED" }, + { -(MBEDTLS_ERR_NET_LISTEN_FAILED), "NET_LISTEN_FAILED" }, + { -(MBEDTLS_ERR_NET_ACCEPT_FAILED), "NET_ACCEPT_FAILED" }, + { -(MBEDTLS_ERR_NET_RECV_FAILED), "NET_RECV_FAILED" }, + { -(MBEDTLS_ERR_NET_SEND_FAILED), "NET_SEND_FAILED" }, + { -(MBEDTLS_ERR_NET_CONN_RESET), "NET_CONN_RESET" }, + { -(MBEDTLS_ERR_NET_UNKNOWN_HOST), "NET_UNKNOWN_HOST" }, + { -(MBEDTLS_ERR_NET_INVALID_CONTEXT), "NET_INVALID_CONTEXT" }, + { -(MBEDTLS_ERR_NET_POLL_FAILED), "NET_POLL_FAILED" }, + { -(MBEDTLS_ERR_NET_BAD_INPUT_DATA), "NET_BAD_INPUT_DATA" }, +#endif /* MBEDTLS_NET_C */ + #if defined(MBEDTLS_AES_C) { -(MBEDTLS_ERR_AES_INVALID_KEY_LENGTH), "AES_INVALID_KEY_LENGTH" }, { -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH), "AES_INVALID_INPUT_LENGTH" }, - { -(MBEDTLS_ERR_AES_BAD_INPUT_DATA), "AES_BAD_INPUT_DATA" }, -#if defined(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE) - { -(MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE), "AES_FEATURE_UNAVAILABLE" }, -#endif -#if defined(MBEDTLS_ERR_AES_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_AES_HW_ACCEL_FAILED), "AES_HW_ACCEL_FAILED" }, -#endif #endif /* MBEDTLS_AES_C */ -#if defined(MBEDTLS_ARC4_C) - { -(MBEDTLS_ERR_ARC4_HW_ACCEL_FAILED), "ARC4_HW_ACCEL_FAILED" }, -#endif /* MBEDTLS_ARC4_C */ - #if defined(MBEDTLS_ARIA_C) - { -(MBEDTLS_ERR_ARIA_BAD_INPUT_DATA), "ARIA_BAD_INPUT_DATA" }, { -(MBEDTLS_ERR_ARIA_INVALID_INPUT_LENGTH), "ARIA_INVALID_INPUT_LENGTH" }, -#if defined(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE) - { -(MBEDTLS_ERR_ARIA_FEATURE_UNAVAILABLE), "ARIA_FEATURE_UNAVAILABLE" }, -#endif -#if defined(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_ARIA_HW_ACCEL_FAILED), "ARIA_HW_ACCEL_FAILED" }, -#endif #endif /* MBEDTLS_ARIA_C */ -#if defined(MBEDTLS_ASN1_PARSE_C) - { -(MBEDTLS_ERR_ASN1_OUT_OF_DATA), "ASN1_OUT_OF_DATA" }, - { -(MBEDTLS_ERR_ASN1_UNEXPECTED_TAG), "ASN1_UNEXPECTED_TAG" }, - { -(MBEDTLS_ERR_ASN1_INVALID_LENGTH), "ASN1_INVALID_LENGTH" }, - { -(MBEDTLS_ERR_ASN1_LENGTH_MISMATCH), "ASN1_LENGTH_MISMATCH" }, - { -(MBEDTLS_ERR_ASN1_INVALID_DATA), "ASN1_INVALID_DATA" }, - { -(MBEDTLS_ERR_ASN1_ALLOC_FAILED), "ASN1_ALLOC_FAILED" }, - { -(MBEDTLS_ERR_ASN1_BUF_TOO_SMALL), "ASN1_BUF_TOO_SMALL" }, -#endif /* MBEDTLS_ASN1_PARSE_C */ - -#if defined(MBEDTLS_BASE64_C) - { -(MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL), "BASE64_BUFFER_TOO_SMALL" }, - { -(MBEDTLS_ERR_BASE64_INVALID_CHARACTER), "BASE64_INVALID_CHARACTER" }, -#endif /* MBEDTLS_BASE64_C */ - #if defined(MBEDTLS_BIGNUM_C) { -(MBEDTLS_ERR_MPI_FILE_IO_ERROR), "MPI_FILE_IO_ERROR" }, - { -(MBEDTLS_ERR_MPI_BAD_INPUT_DATA), "MPI_BAD_INPUT_DATA" }, { -(MBEDTLS_ERR_MPI_INVALID_CHARACTER), "MPI_INVALID_CHARACTER" }, - { -(MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL), "MPI_BUFFER_TOO_SMALL" }, { -(MBEDTLS_ERR_MPI_NEGATIVE_VALUE), "MPI_NEGATIVE_VALUE" }, { -(MBEDTLS_ERR_MPI_DIVISION_BY_ZERO), "MPI_DIVISION_BY_ZERO" }, { -(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE), "MPI_NOT_ACCEPTABLE" }, - { -(MBEDTLS_ERR_MPI_ALLOC_FAILED), "MPI_ALLOC_FAILED" }, #endif /* MBEDTLS_BIGNUM_C */ -#if defined(MBEDTLS_BLOWFISH_C) - { -(MBEDTLS_ERR_BLOWFISH_BAD_INPUT_DATA), "BLOWFISH_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH), "BLOWFISH_INVALID_INPUT_LENGTH" }, - { -(MBEDTLS_ERR_BLOWFISH_HW_ACCEL_FAILED), "BLOWFISH_HW_ACCEL_FAILED" }, -#endif /* MBEDTLS_BLOWFISH_C */ - #if defined(MBEDTLS_CAMELLIA_C) - { -(MBEDTLS_ERR_CAMELLIA_BAD_INPUT_DATA), "CAMELLIA_BAD_INPUT_DATA" }, { -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH), "CAMELLIA_INVALID_INPUT_LENGTH" }, - { -(MBEDTLS_ERR_CAMELLIA_HW_ACCEL_FAILED), "CAMELLIA_HW_ACCEL_FAILED" }, #endif /* MBEDTLS_CAMELLIA_C */ -#if defined(MBEDTLS_CCM_C) - { -(MBEDTLS_ERR_CCM_BAD_INPUT), "CCM_BAD_INPUT" }, - { -(MBEDTLS_ERR_CCM_AUTH_FAILED), "CCM_AUTH_FAILED" }, -#if defined(MBEDTLS_ERR_CCM_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_CCM_HW_ACCEL_FAILED), "CCM_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_CCM_C */ - -#if defined(MBEDTLS_CHACHA20_C) - { -(MBEDTLS_ERR_CHACHA20_BAD_INPUT_DATA), "CHACHA20_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_CHACHA20_FEATURE_UNAVAILABLE), "CHACHA20_FEATURE_UNAVAILABLE" }, -#if defined(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_CHACHA20_HW_ACCEL_FAILED), "CHACHA20_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_CHACHA20_C */ - #if defined(MBEDTLS_CHACHAPOLY_C) { -(MBEDTLS_ERR_CHACHAPOLY_BAD_STATE), "CHACHAPOLY_BAD_STATE" }, - { -(MBEDTLS_ERR_CHACHAPOLY_AUTH_FAILED), "CHACHAPOLY_AUTH_FAILED" }, #endif /* MBEDTLS_CHACHAPOLY_C */ -#if defined(MBEDTLS_CMAC_C) -#if defined(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_CMAC_HW_ACCEL_FAILED), "CMAC_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_CMAC_C */ - #if defined(MBEDTLS_CTR_DRBG_C) { -(MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED), "CTR_DRBG_ENTROPY_SOURCE_FAILED" }, { -(MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG), "CTR_DRBG_REQUEST_TOO_BIG" }, @@ -579,128 +273,19 @@ static const struct ssl_errs mbedtls_low_level_error_tab[] = { { -(MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR), "CTR_DRBG_FILE_IO_ERROR" }, #endif /* MBEDTLS_CTR_DRBG_C */ -#if defined(MBEDTLS_DES_C) - { -(MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH), "DES_INVALID_INPUT_LENGTH" }, - { -(MBEDTLS_ERR_DES_HW_ACCEL_FAILED), "DES_HW_ACCEL_FAILED" }, -#endif /* MBEDTLS_DES_C */ - #if defined(MBEDTLS_ENTROPY_C) - { -(MBEDTLS_ERR_ENTROPY_SOURCE_FAILED), "ENTROPY_SOURCE_FAILED" }, { -(MBEDTLS_ERR_ENTROPY_MAX_SOURCES), "ENTROPY_MAX_SOURCES" }, { -(MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED), "ENTROPY_NO_SOURCES_DEFINED" }, { -(MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE), "ENTROPY_NO_STRONG_SOURCE" }, { -(MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR), "ENTROPY_FILE_IO_ERROR" }, #endif /* MBEDTLS_ENTROPY_C */ -#if defined(MBEDTLS_ERROR_C) - { -(MBEDTLS_ERR_ERROR_GENERIC_ERROR), "ERROR_GENERIC_ERROR" }, - { -(MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED), "ERROR_CORRUPTION_DETECTED" }, -#endif /* MBEDTLS_ERROR_C */ - -#if defined(MBEDTLS_GCM_C) - { -(MBEDTLS_ERR_GCM_AUTH_FAILED), "GCM_AUTH_FAILED" }, -#if defined(MBEDTLS_ERR_GCM_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_GCM_HW_ACCEL_FAILED), "GCM_HW_ACCEL_FAILED" }, -#endif - { -(MBEDTLS_ERR_GCM_BAD_INPUT), "GCM_BAD_INPUT" }, -#endif /* MBEDTLS_GCM_C */ - -#if defined(MBEDTLS_HKDF_C) - { -(MBEDTLS_ERR_HKDF_BAD_INPUT_DATA), "HKDF_BAD_INPUT_DATA" }, -#endif /* MBEDTLS_HKDF_C */ - #if defined(MBEDTLS_HMAC_DRBG_C) { -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG), "HMAC_DRBG_REQUEST_TOO_BIG" }, { -(MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG), "HMAC_DRBG_INPUT_TOO_BIG" }, { -(MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR), "HMAC_DRBG_FILE_IO_ERROR" }, { -(MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED), "HMAC_DRBG_ENTROPY_SOURCE_FAILED" }, #endif /* MBEDTLS_HMAC_DRBG_C */ - -#if defined(MBEDTLS_MD2_C) - { -(MBEDTLS_ERR_MD2_HW_ACCEL_FAILED), "MD2_HW_ACCEL_FAILED" }, -#endif /* MBEDTLS_MD2_C */ - -#if defined(MBEDTLS_MD4_C) - { -(MBEDTLS_ERR_MD4_HW_ACCEL_FAILED), "MD4_HW_ACCEL_FAILED" }, -#endif /* MBEDTLS_MD4_C */ - -#if defined(MBEDTLS_MD5_C) -#if defined(MBEDTLS_ERR_MD5_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_MD5_HW_ACCEL_FAILED), "MD5_HW_ACCEL_FAILED" }, -#endif -#endif /* MBEDTLS_MD5_C */ - -#if defined(MBEDTLS_NET_C) - { -(MBEDTLS_ERR_NET_SOCKET_FAILED), "NET_SOCKET_FAILED" }, - { -(MBEDTLS_ERR_NET_CONNECT_FAILED), "NET_CONNECT_FAILED" }, - { -(MBEDTLS_ERR_NET_BIND_FAILED), "NET_BIND_FAILED" }, - { -(MBEDTLS_ERR_NET_LISTEN_FAILED), "NET_LISTEN_FAILED" }, - { -(MBEDTLS_ERR_NET_ACCEPT_FAILED), "NET_ACCEPT_FAILED" }, - { -(MBEDTLS_ERR_NET_RECV_FAILED), "NET_RECV_FAILED" }, - { -(MBEDTLS_ERR_NET_SEND_FAILED), "NET_SEND_FAILED" }, - { -(MBEDTLS_ERR_NET_CONN_RESET), "NET_CONN_RESET" }, - { -(MBEDTLS_ERR_NET_UNKNOWN_HOST), "NET_UNKNOWN_HOST" }, - { -(MBEDTLS_ERR_NET_BUFFER_TOO_SMALL), "NET_BUFFER_TOO_SMALL" }, - { -(MBEDTLS_ERR_NET_INVALID_CONTEXT), "NET_INVALID_CONTEXT" }, - { -(MBEDTLS_ERR_NET_POLL_FAILED), "NET_POLL_FAILED" }, - { -(MBEDTLS_ERR_NET_BAD_INPUT_DATA), "NET_BAD_INPUT_DATA" }, -#endif /* MBEDTLS_NET_C */ - -#if defined(MBEDTLS_OID_C) - { -(MBEDTLS_ERR_OID_NOT_FOUND), "OID_NOT_FOUND" }, - { -(MBEDTLS_ERR_OID_BUF_TOO_SMALL), "OID_BUF_TOO_SMALL" }, -#endif /* MBEDTLS_OID_C */ - -#if defined(MBEDTLS_PADLOCK_C) - { -(MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED), "PADLOCK_DATA_MISALIGNED" }, -#endif /* MBEDTLS_PADLOCK_C */ - -#if defined(MBEDTLS_PLATFORM_C) - { -(MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED), "PLATFORM_HW_ACCEL_FAILED" }, - { -(MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED), "PLATFORM_FEATURE_UNSUPPORTED" }, -#endif /* MBEDTLS_PLATFORM_C */ - -#if defined(MBEDTLS_POLY1305_C) - { -(MBEDTLS_ERR_POLY1305_BAD_INPUT_DATA), "POLY1305_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_POLY1305_FEATURE_UNAVAILABLE), "POLY1305_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_POLY1305_HW_ACCEL_FAILED), "POLY1305_HW_ACCEL_FAILED" }, -#endif /* MBEDTLS_POLY1305_C */ - -#if defined(MBEDTLS_RIPEMD160_C) - { -(MBEDTLS_ERR_RIPEMD160_HW_ACCEL_FAILED), "RIPEMD160_HW_ACCEL_FAILED" }, -#endif /* MBEDTLS_RIPEMD160_C */ - -#if defined(MBEDTLS_SHA1_C) -#if defined(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED), "SHA1_HW_ACCEL_FAILED" }, -#endif - { -(MBEDTLS_ERR_SHA1_BAD_INPUT_DATA), "SHA1_BAD_INPUT_DATA" }, -#endif /* MBEDTLS_SHA1_C */ - -#if defined(MBEDTLS_SHA256_C) -#if defined(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED), "SHA256_HW_ACCEL_FAILED" }, -#endif - { -(MBEDTLS_ERR_SHA256_BAD_INPUT_DATA), "SHA256_BAD_INPUT_DATA" }, -#endif /* MBEDTLS_SHA256_C */ - -#if defined(MBEDTLS_SHA512_C) -#if defined(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED) - { -(MBEDTLS_ERR_SHA512_HW_ACCEL_FAILED), "SHA512_HW_ACCEL_FAILED" }, -#endif - { -(MBEDTLS_ERR_SHA512_BAD_INPUT_DATA), "SHA512_BAD_INPUT_DATA" }, -#endif /* MBEDTLS_SHA512_C */ - -#if defined(MBEDTLS_THREADING_C) - { -(MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE), "THREADING_FEATURE_UNAVAILABLE" }, - { -(MBEDTLS_ERR_THREADING_BAD_INPUT_DATA), "THREADING_BAD_INPUT_DATA" }, - { -(MBEDTLS_ERR_THREADING_MUTEX_ERROR), "THREADING_MUTEX_ERROR" }, -#endif /* MBEDTLS_THREADING_C */ - -#if defined(MBEDTLS_XTEA_C) - { -(MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH), "XTEA_INVALID_INPUT_LENGTH" }, - { -(MBEDTLS_ERR_XTEA_HW_ACCEL_FAILED), "XTEA_HW_ACCEL_FAILED" }, -#endif /* MBEDTLS_XTEA_C */ // END generated code }; diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 8640ff1078c..dbd6d902194 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -715,7 +715,7 @@ msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c msgid "%q init failed" msgstr "" diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 7e13f2428cb..5dc7768c2cf 100644 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -607,89 +607,89 @@ $(BUILD)/common-hal/sdioio/sdfat_pio/SdCard/PioSdio/PioSdioCard.o: CXXFLAGS += - endif ifeq ($(CIRCUITPY_SSL),1) -CFLAGS += -isystem $(TOP)/mbedtls/include -SRC_MBEDTLS := $(addprefix lib/mbedtls/library/, \ - aes.c \ - aesni.c \ - arc4.c \ - asn1parse.c \ - asn1write.c \ - base64.c \ - bignum.c \ - blowfish.c \ - camellia.c \ - ccm.c \ - certs.c \ - chacha20.c \ - chachapoly.c \ - cipher.c \ - cipher_wrap.c \ - cmac.c \ - constant_time.c \ - ctr_drbg.c \ - debug.c \ - des.c \ - dhm.c \ - ecdh.c \ - ecdsa.c \ - ecjpake.c \ - ecp.c \ - ecp_curves.c \ - entropy.c \ - entropy_poll.c \ - gcm.c \ - havege.c \ - hmac_drbg.c \ - md2.c \ - md4.c \ - md5.c \ - md.c \ - oid.c \ - padlock.c \ - pem.c \ - pk.c \ - pkcs11.c \ - pkcs12.c \ - pkcs5.c \ - pkparse.c \ - pk_wrap.c \ - pkwrite.c \ - platform.c \ - platform_util.c \ - poly1305.c \ - ripemd160.c \ - rsa.c \ - rsa_internal.c \ - sha1.c \ - sha256.c \ - sha512.c \ - ssl_cache.c \ - ssl_ciphersuites.c \ - ssl_cli.c \ - ssl_cookie.c \ - ssl_msg.c \ - ssl_srv.c \ - ssl_ticket.c \ - ssl_tls.c \ - timing.c \ - x509.c \ - x509_create.c \ - x509_crl.c \ - x509_crt.c \ - x509_csr.c \ - x509write_crt.c \ - x509write_csr.c \ - xtea.c \ - ) +# mbedtls 4.x keeps only TLS and X.509 in library/; crypto lives in the tf-psa-crypto +# submodule, split across core/, drivers/builtin/src/, extras/, platform/ and +# utilities/. +# +# Deliberately excluded: +# - mbedtls_config.c, tf_psa_crypto_config.c: pure config-validation translation +# units that #include generated *_config_check_*.h headers. Skipping them is what +# lets us skip that second code generator. +# - net_sockets.c: CircuitPython drives the socket through socketpool callbacks. +# - pkcs7.c: unused, and MBEDTLS_PKCS7_C is off. +# - psa_its_file.c: filesystem-backed PSA key storage; we have no persistent keys. +# - drivers/{everest,p256-m,pqcp}: alternative curve and ML-DSA implementations. +mbedtls_sources = $(patsubst $(TOP)/%,%,$(filter-out $(2),$(wildcard $(TOP)/$(1)/*.c))) + +SRC_MBEDTLS := \ + $(call mbedtls_sources,lib/mbedtls/library,\ + $(TOP)/lib/mbedtls/library/mbedtls_config.c \ + $(TOP)/lib/mbedtls/library/net_sockets.c \ + $(TOP)/lib/mbedtls/library/pkcs7.c) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/core,\ + $(TOP)/lib/mbedtls/tf-psa-crypto/core/psa_its_file.c \ + $(TOP)/lib/mbedtls/tf-psa-crypto/core/tf_psa_crypto_config.c) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/drivers/builtin/src) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/extras) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/platform) \ + $(call mbedtls_sources,lib/mbedtls/tf-psa-crypto/utilities) SRC_C += $(SRC_MBEDTLS) lib/mbedtls_config/mbedtls_port.c lib/mbedtls_config/crt_bundle.c +# Public headers of mbedtls and of tf-psa-crypto, then the internal ones. mbedtls 4.x +# still reaches into tf-psa-crypto's internals, so upstream compiles the TLS layer +# with both; see TF_PSA_CRYPTO_LIBRARY_{PUBLIC,PRIVATE}_INCLUDE in +# lib/mbedtls/tf-psa-crypto/scripts/crypto-common.make. CFLAGS += \ -isystem $(TOP)/lib/mbedtls/include \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/include \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/drivers/builtin/include \ + -isystem $(TOP)/lib/mbedtls/library \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/core \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/dispatch \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/drivers/builtin/src \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/extras \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/platform \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/utilities \ -DMBEDTLS_CONFIG_FILE='"$(TOP)/lib/mbedtls_config/mbedtls_config.h"' \ + -DTF_PSA_CRYPTO_CONFIG_FILE='"$(TOP)/lib/mbedtls_config/tf_psa_crypto_config.h"' \ $(BUILD)/x509_crt_bundle.S: $(TOP)/lib/certificates/data/roots-full.pem $(TOP)/tools/gen_crt_bundle.py $(Q)$(PYTHON) $(TOP)/tools/gen_crt_bundle.py -i $< -o $@ --asm OBJ_MBEDTLS := $(BUILD)/x509_crt_bundle.o -$(patsubst %.c,$(BUILD)/%.o,$(SRC_MBEDTLS))): CFLAGS += -Wno-suggest-attribute=format + +# mbedtls 4.x dispatches PSA crypto through a wrapper layer that is generated from +# jinja templates rather than shipped in the repo, so build it. +# It is the same each time, so we could save it, but this makes updating mbedtls easier. +# +# generate_driver_wrappers.py resolves `mbedtls_framework` relative to its own tree, +# which would mean initializing a third nested submodule (tf-psa-crypto/framework). +# Point PYTHONPATH at the top-level framework submodule instead; mbedtls pins both to +# the same commit. +MBEDTLS_GEN := $(BUILD)/tf-psa-crypto +MBEDTLS_WRAPPERS_H := $(MBEDTLS_GEN)/psa_crypto_driver_wrappers.h +MBEDTLS_WRAPPERS_C := $(MBEDTLS_GEN)/psa_crypto_driver_wrappers_no_static.c + +# The script writes both files at once. Naming both as targets of one rule would run +# it twice; see the same workaround in py/py.mk. +$(MBEDTLS_WRAPPERS_C): $(MBEDTLS_WRAPPERS_H) + @true + +$(MBEDTLS_WRAPPERS_H): $(TOP)/lib/mbedtls/tf-psa-crypto/scripts/generate_driver_wrappers.py + $(STEPECHO) "GEN $@" + $(Q)mkdir -p $(MBEDTLS_GEN) + $(Q)PYTHONPATH=$(TOP)/lib/mbedtls/framework/scripts $(PYTHON) $< $(MBEDTLS_GEN) + +OBJ_MBEDTLS += $(MBEDTLS_WRAPPERS_C:.c=.o) +CFLAGS += -I$(MBEDTLS_GEN) + +# psa_crypto.c and friends #include the generated header, so it has to exist before +# any of them compile. +$(patsubst %.c,$(BUILD)/%.o,$(SRC_MBEDTLS)) $(OBJ_MBEDTLS): $(MBEDTLS_WRAPPERS_H) +# Vendored third-party code, so don't hold it to CircuitPython's warning settings. The +# unused-but-set variables are real but harmless: they are in key-exchange paths that +# are compiled out. +$(patsubst %.c,$(BUILD)/%.o,$(SRC_MBEDTLS)) $(OBJ_MBEDTLS): CFLAGS += \ + -Wno-suggest-attribute=format \ + -Wno-unused-but-set-variable else OBJ_MBEDTLS := endif diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 555269bb962..617d05f99e5 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -29,6 +29,7 @@ #if CIRCUITPY_SSL #include "shared-module/ssl/__init__.h" +#include "psa/crypto.h" #endif #if CIRCUITPY_WIFI @@ -500,6 +501,9 @@ void reset_port(void) { #if CIRCUITPY_SSL ssl_reset(); + + // Done separately from ssl_reset() because ESP-IDF has its own PSA setup. + mbedtls_psa_crypto_free(); #endif #if CIRCUITPY_WATCHDOG diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 7dfb9ae7c7d..955d872c751 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -944,15 +944,58 @@ $(BUILD)/lib/tjpgd/src/tjpgd.o: CFLAGS += -Wno-shadow -Wno-cast-align endif ifeq ($(CIRCUITPY_HASHLIB_MBEDTLS_ONLY),1) -SRC_MOD += $(addprefix lib/mbedtls/library/, \ - sha1.c \ - sha256.c \ - sha512.c \ - platform_util.c \ - ) +# mbedtls 4.x moved the crypto implementations out of lib/mbedtls/library into the +# tf-psa-crypto submodule and made the legacy mbedtls_sha256_*() headers private, so +# hashlib goes through the PSA hash API. That needs the PSA core, whose driver dispatch +# layer is generated rather than shipped -- see the same rule in ports/raspberrypi/Makefile. +SRC_MOD += \ + $(addprefix lib/mbedtls/tf-psa-crypto/core/, \ + psa_crypto.c \ + psa_crypto_client.c \ + psa_crypto_slot_management.c \ + psa_util.c \ + ) \ + $(addprefix lib/mbedtls/tf-psa-crypto/drivers/builtin/src/, \ + psa_crypto_hash.c \ + psa_util_internal.c \ + sha1.c \ + sha256.c \ + ) \ + $(addprefix lib/mbedtls/tf-psa-crypto/platform/, \ + platform.c \ + platform_util.c \ + ) \ + lib/mbedtls/tf-psa-crypto/utilities/constant_time.c \ + lib/mbedtls_config/hashlib_psa_port.c + +MBEDTLS_HASHLIB_GEN := $(BUILD)/tf-psa-crypto +MBEDTLS_HASHLIB_WRAPPERS_H := $(MBEDTLS_HASHLIB_GEN)/psa_crypto_driver_wrappers.h +MBEDTLS_HASHLIB_WRAPPERS_C := $(MBEDTLS_HASHLIB_GEN)/psa_crypto_driver_wrappers_no_static.c +SRC_MOD += $(MBEDTLS_HASHLIB_WRAPPERS_C:$(BUILD)/%=%) + +# The script writes both files at once; naming both as targets would run it twice. +$(MBEDTLS_HASHLIB_WRAPPERS_C): $(MBEDTLS_HASHLIB_WRAPPERS_H) + @true + +$(MBEDTLS_HASHLIB_WRAPPERS_H): $(TOP)/lib/mbedtls/tf-psa-crypto/scripts/generate_driver_wrappers.py + $(STEPECHO) "GEN $@" + $(Q)mkdir -p $(MBEDTLS_HASHLIB_GEN) + $(Q)PYTHONPATH=$(TOP)/lib/mbedtls/framework/scripts $(PYTHON) $< $(MBEDTLS_HASHLIB_GEN) + +# psa_crypto.c and friends #include the generated header. +$(addprefix $(BUILD)/, $(SRC_MOD:.c=.o)): $(MBEDTLS_HASHLIB_WRAPPERS_H) + CFLAGS += \ - -isystem $(TOP)/lib/mbedtls/include \ - -DMBEDTLS_CONFIG_FILE='"$(TOP)/lib/mbedtls_config/mbedtls_config_hashlib.h"' \ + -I$(MBEDTLS_HASHLIB_GEN) \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/include \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/drivers/builtin/include \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/drivers/builtin/src \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/core \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/dispatch \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/extras \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/platform \ + -isystem $(TOP)/lib/mbedtls/tf-psa-crypto/utilities \ + -DTF_PSA_CRYPTO_CONFIG_FILE='"$(TOP)/lib/mbedtls_config/tf_psa_crypto_config_hashlib.h"' \ endif diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 381cb9538e4..58d7fe74ea6 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -78,7 +78,9 @@ extern void common_hal_mcu_enable_interrupts(void); #define MICROPY_ENABLE_SELECTIVE_COLLECT (1) #define MICROPY_ENABLE_GC (1) #define MICROPY_ENABLE_PYSTACK (1) -#define MICROPY_TRACKED_ALLOC (CIRCUITPY_SSL_MBEDTLS) +// mbedtls allocates through m_tracked_calloc/m_tracked_free. hashlib-only ports need +// them too as of mbedtls 4.x: hashlib uses mbedtls_md_*(), which allocates on the heap. +#define MICROPY_TRACKED_ALLOC (CIRCUITPY_SSL_MBEDTLS || CIRCUITPY_HASHLIB_MBEDTLS_ONLY) #define MICROPY_ENABLE_SOURCE_LINE (1) #define MICROPY_EPOCH_IS_1970 (1) #define MICROPY_ERROR_REPORTING (CIRCUITPY_FULL_BUILD ? MICROPY_ERROR_REPORTING_NORMAL : MICROPY_ERROR_REPORTING_TERSE) diff --git a/requirements-dev.txt b/requirements-dev.txt index aca235d6346..a6fedc4b4af 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -3,6 +3,9 @@ cascadetoml jinja2 typer +# for generating mbedtls's PSA driver wrappers (jinja2, above, is also required) +jsonschema + sh click<8.2.0 cpp-coveralls diff --git a/shared-module/hashlib/Hash.c b/shared-module/hashlib/Hash.c index 64fcf2d941f..4b46198ac5d 100644 --- a/shared-module/hashlib/Hash.c +++ b/shared-module/hashlib/Hash.c @@ -7,10 +7,6 @@ #include "shared-bindings/hashlib/Hash.h" #include "shared-module/hashlib/__init__.h" -#include "mbedtls/version.h" - -#if MBEDTLS_VERSION_MAJOR >= 4 - #include "psa/crypto.h" void common_hal_hashlib_hash_update(hashlib_hash_obj_t *self, const uint8_t *data, size_t datalen) { @@ -31,61 +27,3 @@ void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, siz size_t common_hal_hashlib_hash_get_digest_size(hashlib_hash_obj_t *self) { return PSA_HASH_LENGTH(self->hash_alg); } - -#else - -#include "mbedtls/ssl.h" - -// In mbedtls 2.x, the _ret suffix functions are the recommended API. -// In mbedtls 3.x, the _ret suffix was removed and the base names return int. -#if MBEDTLS_VERSION_MAJOR < 3 -#define SHA1_UPDATE mbedtls_sha1_update_ret -#define SHA1_FINISH mbedtls_sha1_finish_ret -#define SHA256_UPDATE mbedtls_sha256_update_ret -#define SHA256_FINISH mbedtls_sha256_finish_ret -#else -#define SHA1_UPDATE mbedtls_sha1_update -#define SHA1_FINISH mbedtls_sha1_finish -#define SHA256_UPDATE mbedtls_sha256_update -#define SHA256_FINISH mbedtls_sha256_finish -#endif - -void common_hal_hashlib_hash_update(hashlib_hash_obj_t *self, const uint8_t *data, size_t datalen) { - if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { - SHA1_UPDATE(&self->sha1, data, datalen); - return; - } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { - SHA256_UPDATE(&self->sha256, data, datalen); - return; - } -} - -void common_hal_hashlib_hash_digest(hashlib_hash_obj_t *self, uint8_t *data, size_t datalen) { - if (datalen < common_hal_hashlib_hash_get_digest_size(self)) { - return; - } - if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { - // We copy the sha1 state so we can continue to update if needed or get - // the digest a second time. - mbedtls_sha1_context copy; - mbedtls_sha1_clone(©, &self->sha1); - SHA1_FINISH(&self->sha1, data); - mbedtls_sha1_clone(&self->sha1, ©); - } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { - mbedtls_sha256_context copy; - mbedtls_sha256_clone(©, &self->sha256); - SHA256_FINISH(&self->sha256, data); - mbedtls_sha256_clone(&self->sha256, ©); - } -} - -size_t common_hal_hashlib_hash_get_digest_size(hashlib_hash_obj_t *self) { - if (self->hash_type == MBEDTLS_SSL_HASH_SHA1) { - return 20; - } else if (self->hash_type == MBEDTLS_SSL_HASH_SHA256) { - return 32; - } - return 0; -} - -#endif diff --git a/shared-module/hashlib/Hash.h b/shared-module/hashlib/Hash.h index 035368e7c2f..961335eea7a 100644 --- a/shared-module/hashlib/Hash.h +++ b/shared-module/hashlib/Hash.h @@ -6,10 +6,6 @@ #pragma once -#include "mbedtls/version.h" - -#if MBEDTLS_VERSION_MAJOR >= 4 - #include "psa/crypto.h" typedef struct { @@ -17,20 +13,3 @@ typedef struct { psa_hash_operation_t hash_op; psa_algorithm_t hash_alg; } hashlib_hash_obj_t; - -#else - -#include "mbedtls/sha1.h" -#include "mbedtls/sha256.h" - -typedef struct { - mp_obj_base_t base; - union { - mbedtls_sha1_context sha1; - mbedtls_sha256_context sha256; - }; - // Of MBEDTLS_SSL_HASH_* - uint8_t hash_type; -} hashlib_hash_obj_t; - -#endif diff --git a/shared-module/hashlib/__init__.c b/shared-module/hashlib/__init__.c index d2a19386431..50477a4dc2d 100644 --- a/shared-module/hashlib/__init__.c +++ b/shared-module/hashlib/__init__.c @@ -7,10 +7,6 @@ #include "shared-bindings/hashlib/__init__.h" #include "shared-module/hashlib/__init__.h" -#include "mbedtls/version.h" - -#if MBEDTLS_VERSION_MAJOR >= 4 - #include "psa/crypto.h" bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { @@ -21,38 +17,12 @@ bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { } else { return false; } - self->hash_op = psa_hash_operation_init(); - psa_hash_setup(&self->hash_op, self->hash_alg); - return true; -} - -#else - -#include "mbedtls/ssl.h" - -// In mbedtls 2.x, the _ret suffix functions are the recommended API. -// In mbedtls 3.x, the _ret suffix was removed and the base names return int. -#if MBEDTLS_VERSION_MAJOR < 3 -#define SHA1_STARTS mbedtls_sha1_starts_ret -#define SHA256_STARTS mbedtls_sha256_starts_ret -#else -#define SHA1_STARTS mbedtls_sha1_starts -#define SHA256_STARTS mbedtls_sha256_starts -#endif - -bool common_hal_hashlib_new(hashlib_hash_obj_t *self, const char *algorithm) { - if (strcmp(algorithm, "sha1") == 0) { - self->hash_type = MBEDTLS_SSL_HASH_SHA1; - mbedtls_sha1_init(&self->sha1); - SHA1_STARTS(&self->sha1); - return true; - } else if (strcmp(algorithm, "sha256") == 0) { - self->hash_type = MBEDTLS_SSL_HASH_SHA256; - mbedtls_sha256_init(&self->sha256); - SHA256_STARTS(&self->sha256, 0); - return true; + // PSA has to be initialized before any of it is used. OK to psa_crypto_init() + // multiple times. On espressif, ESP-IDF has already done this during its own system + // init and this call is a no-op. + if (psa_crypto_init() != PSA_SUCCESS) { + return false; } - return false; + self->hash_op = psa_hash_operation_init(); + return psa_hash_setup(&self->hash_op, self->hash_alg) == PSA_SUCCESS; } - -#endif diff --git a/shared-module/hashlib/__init__.h b/shared-module/hashlib/__init__.h index 847bd8a8347..2088d352f20 100644 --- a/shared-module/hashlib/__init__.h +++ b/shared-module/hashlib/__init__.h @@ -6,16 +6,3 @@ // SPDX-License-Identifier: MIT #pragma once - -#include "mbedtls/version.h" - -#if MBEDTLS_VERSION_NUMBER < 0x02070000 || MBEDTLS_VERSION_NUMBER >= 0x03000000 -#define mbedtls_sha1_starts_ret mbedtls_sha1_starts -#define mbedtls_sha1_update_ret mbedtls_sha1_update -#define mbedtls_sha1_finish_ret mbedtls_sha1_finish - -#define mbedtls_sha256_starts_ret mbedtls_sha256_starts -#define mbedtls_sha256_update_ret mbedtls_sha256_update -#define mbedtls_sha256_finish_ret mbedtls_sha256_finish - -#endif diff --git a/shared-module/ssl/SSLContext.c b/shared-module/ssl/SSLContext.c index e58074ea3ea..47e8b9f3149 100644 --- a/shared-module/ssl/SSLContext.c +++ b/shared-module/ssl/SSLContext.c @@ -12,7 +12,15 @@ #include "lib/mbedtls_config/crt_bundle.h" +#include "psa/crypto.h" + void common_hal_ssl_sslcontext_construct(ssl_sslcontext_obj_t *self) { + // TLS is built on PSA crypto, which has to be initialized before any of it is + // used. OK to psa_crypto_init() multiple times. On espressif, ESP-IDF has already done this during + // its own system init and this call is a no-op. + if (psa_crypto_init() != PSA_SUCCESS) { + mp_raise_RuntimeError_varg(MP_ERROR_TEXT("%q init failed"), MP_QSTR_ssl); + } common_hal_ssl_sslcontext_set_default_verify_paths(self); } diff --git a/shared-module/ssl/SSLSocket.c b/shared-module/ssl/SSLSocket.c index 70275945803..0c374da771f 100644 --- a/shared-module/ssl/SSLSocket.c +++ b/shared-module/ssl/SSLSocket.c @@ -28,10 +28,6 @@ #include "../../lib/mbedtls_errors/mp_mbedtls_errors.c" #endif -#if MBEDTLS_VERSION_MAJOR >= 3 -#include "shared-bindings/os/__init__.h" -#endif - #ifdef MBEDTLS_DEBUG_C #include "mbedtls/debug.h" static void mbedtls_debug(void *ctx, int level, const char *file, int line, const char *str) { @@ -200,16 +196,6 @@ static int _mbedtls_ssl_recv(void *ctx, byte *buf, size_t len) { } -#if MBEDTLS_VERSION_MAJOR == 3 -static int urandom_adapter(void *unused, unsigned char *buf, size_t n) { - int result = common_hal_os_urandom(buf, n); - if (result) { - return 0; - } - return MBEDTLS_ERR_SSL_INTERNAL_ERROR; -} -#endif - ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t *self, mp_obj_t socket, bool server_side, const char *server_hostname) { @@ -238,26 +224,12 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t mbedtls_x509_crt_init(&o->cacert); mbedtls_x509_crt_init(&o->cert); mbedtls_pk_init(&o->pkey); - #if MBEDTLS_VERSION_MAJOR < 4 - mbedtls_ctr_drbg_init(&o->ctr_drbg); - #endif #ifdef MBEDTLS_DEBUG_C // Debug level (0-4) 1=warning, 2=info, 3=debug, 4=verbose mbedtls_debug_set_threshold(4); #endif - #if MBEDTLS_VERSION_MAJOR < 4 - mbedtls_entropy_init(&o->entropy); - const byte seed[] = "upy"; - int ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); - if (ret != 0) { - goto cleanup; - } - #else - int ret; - #endif - - ret = mbedtls_ssl_config_defaults(&o->conf, + int ret = mbedtls_ssl_config_defaults(&o->conf, server_side ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); @@ -279,9 +251,6 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t } else { mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); } - #if MBEDTLS_VERSION_MAJOR < 4 - mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); - #endif #ifdef MBEDTLS_DEBUG_C mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); #endif @@ -301,13 +270,7 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t mbedtls_ssl_set_bio(&o->ssl, o, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); if (self->cert_buf.buf != NULL) { - #if MBEDTLS_VERSION_MAJOR >= 4 - ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0); - #elif MBEDTLS_VERSION_MAJOR >= 3 - ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0, urandom_adapter, NULL); - #else ret = mbedtls_pk_parse_key(&o->pkey, self->key_buf.buf, self->key_buf.len + 1, NULL, 0); - #endif if (ret != 0) { goto cleanup; } @@ -328,10 +291,6 @@ ssl_sslsocket_obj_t *common_hal_ssl_sslcontext_wrap_socket(ssl_sslcontext_obj_t mbedtls_x509_crt_free(&o->cacert); mbedtls_ssl_free(&o->ssl); mbedtls_ssl_config_free(&o->conf); - #if MBEDTLS_VERSION_MAJOR < 4 - mbedtls_ctr_drbg_free(&o->ctr_drbg); - mbedtls_entropy_free(&o->entropy); - #endif if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_type(&mp_type_MemoryError); @@ -394,10 +353,6 @@ void common_hal_ssl_sslsocket_close(ssl_sslsocket_obj_t *self) { mbedtls_x509_crt_free(&self->cacert); mbedtls_ssl_free(&self->ssl); mbedtls_ssl_config_free(&self->conf); - #if MBEDTLS_VERSION_MAJOR < 4 - mbedtls_ctr_drbg_free(&self->ctr_drbg); - mbedtls_entropy_free(&self->entropy); - #endif } static void do_handshake(ssl_sslsocket_obj_t *self) { @@ -422,10 +377,6 @@ static void do_handshake(ssl_sslsocket_obj_t *self) { mbedtls_x509_crt_free(&self->cacert); mbedtls_ssl_free(&self->ssl); mbedtls_ssl_config_free(&self->conf); - #if MBEDTLS_VERSION_MAJOR < 4 - mbedtls_ctr_drbg_free(&self->ctr_drbg); - mbedtls_entropy_free(&self->entropy); - #endif if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_type(&mp_type_MemoryError); diff --git a/shared-module/ssl/SSLSocket.h b/shared-module/ssl/SSLSocket.h index 9373734d27c..f3bb858a00d 100644 --- a/shared-module/ssl/SSLSocket.h +++ b/shared-module/ssl/SSLSocket.h @@ -15,20 +15,11 @@ #include "mbedtls/ssl.h" #include "mbedtls/x509_crt.h" #include "mbedtls/pk.h" -#include "mbedtls/version.h" -#if MBEDTLS_VERSION_MAJOR < 4 -#include "mbedtls/entropy.h" -#include "mbedtls/ctr_drbg.h" -#endif typedef struct ssl_sslsocket_obj { mp_obj_base_t base; mp_obj_t sock_obj; ssl_sslcontext_obj_t *ssl_context; - #if MBEDTLS_VERSION_MAJOR < 4 - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; - #endif mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt cacert; diff --git a/tools/ci_fetch_deps.py b/tools/ci_fetch_deps.py index 05559ac2d12..8994e54c338 100644 --- a/tools/ci_fetch_deps.py +++ b/tools/ci_fetch_deps.py @@ -144,6 +144,22 @@ def fetch(where): for s in matching_submodules([w for w in where if w.startswith("frozen")]): run(f"Ensure tags exist in {s}", "git fetch --tags --depth 1", cwd=TOP / s) + # mbedtls 4.x keeps its crypto in a nested tf-psa-crypto submodule, and the PSA + # driver-wrapper generator needs the framework submodule. Init them by name rather + # than with --recursive, which would also pull tf-psa-crypto's own framework copy + # and drivers/pqcp/mldsa-native. Those are not needed to build. + # Keyed off the checkout rather than off `where`, because the targets that pull + # lib/mbedtls name it several different ways ("lib/mbedtls/", "lib/", or "." for + # the `all` target). + mbedtls = TOP / "lib" / "mbedtls" + if (mbedtls / ".gitmodules").exists(): + depth_maybe = "" if clone_supports_filter else "--depth 1" + run( + "Init mbedtls nested submodules", + f"git submodule update --init {filter_maybe} {depth_maybe} tf-psa-crypto framework", + cwd=mbedtls, + ) + def set_output(name, value): if "GITHUB_OUTPUT" in os.environ: From b9a6ed5c86615d1c879b995312b34c63a9cc9f51 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 30 Jul 2026 09:07:11 -0400 Subject: [PATCH 709/876] shrink one board; add jsonschema to windows build --- .github/workflows/build.yml | 2 +- ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bd803a5eb6b..832a4d6097e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -258,7 +258,7 @@ jobs: pip install --break-system-packages wheel # requirements-dev.txt doesn't install on windows. (with msys2 python) # instead, pick a subset for what we want to do - pip install --break-system-packages cascadetoml jinja2 typer click intelhex + pip install --break-system-packages cascadetoml jinja2 typer click intelhex jsonschema # check that installed packages work....? which python; python --version; python -c "import cascadetoml" which python3; python3 --version; python3 -c "import cascadetoml" diff --git a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk index 1c3801edaac..8a364e4b840 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk @@ -9,6 +9,8 @@ CHIP_FAMILY = rp2 EXTERNAL_FLASH_DEVICES = "W25Q16JVxQ" +CIRCUITPY_USB_HOST = 0 + CIRCUITPY_KEYPAD = 1 CIRCUITPY_STAGE = 1 CIRCUITPY_AUDIOIO = 1 From a09920aeabdd6f2a844653d42c1e41219d18d59b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 30 Jul 2026 10:09:12 -0400 Subject: [PATCH 710/876] Pin jsonschema<4.18 for the windows build jsonschema 4.18+ pulls in rpds-py, which has no wheel for msys2 python and cannot be built from source there. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/build.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 832a4d6097e..f28591e4f56 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -258,7 +258,12 @@ jobs: pip install --break-system-packages wheel # requirements-dev.txt doesn't install on windows. (with msys2 python) # instead, pick a subset for what we want to do - pip install --break-system-packages cascadetoml jinja2 typer click intelhex jsonschema + # jsonschema is needed by mbedtls' generate_driver_wrappers.py. Pin it below 4.18: + # 4.18 and later depend on rpds-py, a Rust extension with no wheel for msys2 python + # (SOABI cpython-3xx-x86_64-cygwin), and maturin refuses to build it from source + # ("Unsupported platform: x86_64-cygwin"). 4.17.3 uses attrs and pyrsistent instead, + # both of which install without a Rust toolchain. + pip install --break-system-packages cascadetoml jinja2 typer click intelhex 'jsonschema<4.18' # check that installed packages work....? which python; python --version; python -c "import cascadetoml" which python3; python3 --version; python3 -c "import cascadetoml" From 598b18988d503acb1cf2d37d63112d50a96f0e10 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 30 Jul 2026 11:36:03 -0400 Subject: [PATCH 711/876] Fix UART flow control condition for CTS --- ports/espressif/common-hal/busio/UART.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/common-hal/busio/UART.c b/ports/espressif/common-hal/busio/UART.c index ad5e6fcef1b..01c8321843a 100644 --- a/ports/espressif/common-hal/busio/UART.c +++ b/ports/espressif/common-hal/busio/UART.c @@ -140,7 +140,7 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, uart_config.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS; } else if (have_rts) { uart_config.flow_ctrl = UART_HW_FLOWCTRL_RTS; - } else if (have_rts) { + } else if (have_cts) { uart_config.flow_ctrl = UART_HW_FLOWCTRL_CTS; } From 5bd36ea2d39a0f7c4b56bc2fa73c11664fe98f29 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 30 Jul 2026 13:34:26 -0400 Subject: [PATCH 712/876] clarify comment for mbedtls_psa_crypto_free() call --- ports/raspberrypi/supervisor/port.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 617d05f99e5..23a318454ed 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -502,7 +502,12 @@ void reset_port(void) { #if CIRCUITPY_SSL ssl_reset(); - // Done separately from ssl_reset() because ESP-IDF has its own PSA setup. + // For raspberrypi, we must free PSA crypto, because there are GC-heap objects + // in the key slots. We can't put this call in ssl_reset() because that's a + // shared-module implementation. Unlike raspberrypi, espressif ESP-IDF inits PSA + // once at boot and would never re-init it. + // common_hal_ssl_sslcontext_construct() re-inits PSA on demand. + // So for raspberrypi, we must call mbedtls_psa_crypto_free() explicitly. mbedtls_psa_crypto_free(); #endif From fbdadc2f483044779b0c3a68a718798da123123e Mon Sep 17 00:00:00 2001 From: Liz Date: Thu, 30 Jul 2026 16:20:53 -0400 Subject: [PATCH 713/876] adding alpstuga --- .../boards/ikea_alpstuga_esp32_s3/board.c | 12 ++++++ .../ikea_alpstuga_esp32_s3/mpconfigboard.h | 21 ++++++++++ .../ikea_alpstuga_esp32_s3/mpconfigboard.mk | 14 +++++++ .../boards/ikea_alpstuga_esp32_s3/pins.c | 38 +++++++++++++++++++ .../boards/ikea_alpstuga_esp32_s3/sdkconfig | 14 +++++++ 5 files changed, 99 insertions(+) create mode 100644 ports/espressif/boards/ikea_alpstuga_esp32_s3/board.c create mode 100644 ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.h create mode 100644 ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk create mode 100644 ports/espressif/boards/ikea_alpstuga_esp32_s3/pins.c create mode 100644 ports/espressif/boards/ikea_alpstuga_esp32_s3/sdkconfig diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/board.c b/ports/espressif/boards/ikea_alpstuga_esp32_s3/board.c new file mode 100644 index 00000000000..6d735a9b031 --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/board.c @@ -0,0 +1,12 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" +#include "mpconfigboard.h" +#include "shared-bindings/microcontroller/Pin.h" +#include "driver/gpio.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.h b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.h new file mode 100644 index 00000000000..9a826047351 --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Ikea Alpstuga Drop-In ESP32S3 4MB Flash 2MB PSRAM" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO33) + +#define MICROPY_HW_LED_STATUS (&pin_GPIO9) + +#define DEFAULT_I2C_BUS_SCL (&pin_GPIO4) +#define DEFAULT_I2C_BUS_SDA (&pin_GPIO3) + +#define DOUBLE_TAP_PIN (&pin_GPIO34) diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk new file mode 100644 index 00000000000..07ecfc693b3 --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x239A +USB_PID = 0x811C +USB_PRODUCT = "Ikea Alpstuga Drop-In ESP32S3 4MB Flash 2MB PSRAM" +USB_MANUFACTURER = "Adafruit" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_SIZE = 4MB +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 2MB +CIRCUITPY_ESP_PSRAM_MODE = qio +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/pins.c b/ports/espressif/boards/ikea_alpstuga_esp32_s3/pins.c new file mode 100644 index 00000000000..20991f032bd --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/pins.c @@ -0,0 +1,38 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BUTTON), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_BOOT0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_D0), MP_ROM_PTR(&pin_GPIO0) }, + + { MP_ROM_QSTR(MP_QSTR_SDA), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_D3), MP_ROM_PTR(&pin_GPIO3) }, + + { MP_ROM_QSTR(MP_QSTR_SCL), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_D4), MP_ROM_PTR(&pin_GPIO4) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_D9), MP_ROM_PTR(&pin_GPIO9) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_1), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_D5), MP_ROM_PTR(&pin_GPIO5) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_2), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_D6), MP_ROM_PTR(&pin_GPIO6) }, + + { MP_ROM_QSTR(MP_QSTR_BUTTON_3), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_D8), MP_ROM_PTR(&pin_GPIO8) }, + + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO33) }, + + { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/sdkconfig b/ports/espressif/boards/ikea_alpstuga_esp32_s3/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration From d84ff6118fa3df96c8df1cc1c1be522fa564907c Mon Sep 17 00:00:00 2001 From: Liz <23021834+BlitzCityDIY@users.noreply.github.com> Date: Thu, 30 Jul 2026 16:32:30 -0400 Subject: [PATCH 714/876] update PID --- ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk index 07ecfc693b3..fbfb0f1ed3f 100644 --- a/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk +++ b/ports/espressif/boards/ikea_alpstuga_esp32_s3/mpconfigboard.mk @@ -1,5 +1,5 @@ USB_VID = 0x239A -USB_PID = 0x811C +USB_PID = 0x8178 USB_PRODUCT = "Ikea Alpstuga Drop-In ESP32S3 4MB Flash 2MB PSRAM" USB_MANUFACTURER = "Adafruit" From affff488efb93273cf995c04f052663dd3ba92cc Mon Sep 17 00:00:00 2001 From: CDarius Date: Fri, 31 Jul 2026 15:35:44 +0200 Subject: [PATCH 715/876] Remove SPI bus definition from pins.c and board python module --- ports/espressif/boards/m5stack_cores3/board.c | 4 +++- ports/espressif/boards/m5stack_cores3_se/pins.c | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ports/espressif/boards/m5stack_cores3/board.c b/ports/espressif/boards/m5stack_cores3/board.c index 629472da526..e4e178ee3c9 100644 --- a/ports/espressif/boards/m5stack_cores3/board.c +++ b/ports/espressif/boards/m5stack_cores3/board.c @@ -38,8 +38,10 @@ uint8_t display_init_sequence[] = { }; static bool display_init(void) { - busio_spi_obj_t *spi = common_hal_board_create_spi(0); fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO37, NULL, false); + common_hal_busio_spi_never_reset(spi); bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct( diff --git a/ports/espressif/boards/m5stack_cores3_se/pins.c b/ports/espressif/boards/m5stack_cores3_se/pins.c index f0e20926bfa..f003b74e122 100644 --- a/ports/espressif/boards/m5stack_cores3_se/pins.c +++ b/ports/espressif/boards/m5stack_cores3_se/pins.c @@ -13,10 +13,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS // M5 Bus (except I2S) - { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, - { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, - { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, - + // The SPI bus MISO is also used for the TFT D/C signal, so it is not available for general use + // therefore the SPI bus is not listed on the M5 Bus { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, @@ -69,6 +67,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2S_MASTER_CLOCK), MP_ROM_PTR(&pin_GPIO0) }, // Display + { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO36) }, { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO35) }, @@ -79,7 +79,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_PORTA_I2C), MP_ROM_PTR(&board_porta_i2c_obj) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} From 2dd41c2f2b85e4742daf047cd370f3b52dfce027 Mon Sep 17 00:00:00 2001 From: CDarius Date: Fri, 31 Jul 2026 15:57:18 +0200 Subject: [PATCH 716/876] Remove SPI bus definition from pins.c and board python module for CoreS3 SE and also add a missing file from the previous commit --- ports/espressif/boards/m5stack_cores3/pins.c | 9 ++++----- ports/espressif/boards/m5stack_cores3_se/board.c | 4 +++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ports/espressif/boards/m5stack_cores3/pins.c b/ports/espressif/boards/m5stack_cores3/pins.c index 8b40d9e8484..11357d79a72 100644 --- a/ports/espressif/boards/m5stack_cores3/pins.c +++ b/ports/espressif/boards/m5stack_cores3/pins.c @@ -29,10 +29,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS // M5 Bus (except I2S) - { MP_ROM_QSTR(MP_QSTR_MOSI), MP_ROM_PTR(&pin_GPIO37) }, - { MP_ROM_QSTR(MP_QSTR_MISO), MP_ROM_PTR(&pin_GPIO35) }, - { MP_ROM_QSTR(MP_QSTR_SCK), MP_ROM_PTR(&pin_GPIO36) }, - + // The SPI bus MISO is also used for the TFT D/C signal, so it is not available for general use + // therefore the SPI bus is not listed on the M5 Bus { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, { MP_ROM_QSTR(MP_QSTR_D44), MP_ROM_PTR(&pin_GPIO44) }, @@ -99,6 +97,8 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_CAMERA_XCLK), MP_ROM_PTR(&pin_GPIO2) }, // Display + { MP_ROM_QSTR(MP_QSTR_TFT_MOSI), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_TFT_SCK), MP_ROM_PTR(&pin_GPIO36) }, { MP_ROM_QSTR(MP_QSTR_TFT_CS), MP_ROM_PTR(&pin_GPIO3) }, { MP_ROM_QSTR(MP_QSTR_TFT_DC), MP_ROM_PTR(&pin_GPIO35) }, @@ -109,7 +109,6 @@ static const mp_rom_map_elem_t board_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR_I2C), MP_ROM_PTR(&board_i2c_obj) }, { MP_ROM_QSTR(MP_QSTR_PORTA_I2C), MP_ROM_PTR(&board_porta_i2c_obj) }, - { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, { MP_ROM_QSTR(MP_QSTR_DISPLAY), MP_ROM_PTR(&displays[0].display)} diff --git a/ports/espressif/boards/m5stack_cores3_se/board.c b/ports/espressif/boards/m5stack_cores3_se/board.c index 623fe29f98f..cb0ed4aea06 100644 --- a/ports/espressif/boards/m5stack_cores3_se/board.c +++ b/ports/espressif/boards/m5stack_cores3_se/board.c @@ -39,8 +39,10 @@ uint8_t display_init_sequence[] = { }; static bool display_init(void) { - busio_spi_obj_t *spi = common_hal_board_create_spi(0); fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus; + busio_spi_obj_t *spi = &bus->inline_bus; + common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO37, NULL, false); + common_hal_busio_spi_never_reset(spi); bus->base.type = &fourwire_fourwire_type; common_hal_fourwire_fourwire_construct( From f1e4662360cef51d745487c2284a367396a87875 Mon Sep 17 00:00:00 2001 From: CDarius Date: Fri, 31 Jul 2026 16:11:47 +0200 Subject: [PATCH 717/876] Remove default SPI definition from mpconfigboard.h for both: CoreS3 and CoreS3 SE --- ports/espressif/boards/m5stack_cores3/mpconfigboard.h | 7 ------- ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h | 7 ------- 2 files changed, 14 deletions(-) diff --git a/ports/espressif/boards/m5stack_cores3/mpconfigboard.h b/ports/espressif/boards/m5stack_cores3/mpconfigboard.h index 74f6ad304ed..0e5e136e3ea 100644 --- a/ports/espressif/boards/m5stack_cores3/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_cores3/mpconfigboard.h @@ -15,12 +15,5 @@ #define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO11, .sda = &pin_GPIO12}, \ {.scl = &pin_GPIO1, .sda = &pin_GPIO2}} -#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) -#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO37) -// GPIO35 is shared between the TF card MISO and the TFT D/C signal. The display -// claims it as D/C during board_init(), so board.SPI() must not also claim it. -#define CIRCUITPY_BOARD_SPI (1) -#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} - #define DEFAULT_UART_BUS_RX (&pin_GPIO18) #define DEFAULT_UART_BUS_TX (&pin_GPIO17) diff --git a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h index 44b09c6199d..edfcbb3c91b 100644 --- a/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h +++ b/ports/espressif/boards/m5stack_cores3_se/mpconfigboard.h @@ -17,12 +17,5 @@ #define CIRCUITPY_BOARD_I2C_PIN {{.scl = &pin_GPIO11, .sda = &pin_GPIO12}, \ {.scl = &pin_GPIO1, .sda = &pin_GPIO2}} -#define DEFAULT_SPI_BUS_SCK (&pin_GPIO36) -#define DEFAULT_SPI_BUS_MOSI (&pin_GPIO37) -// GPIO35 is shared between the TF card MISO and the TFT D/C signal. The display -// claims it as D/C during board_init(), so board.SPI() must not also claim it. -#define CIRCUITPY_BOARD_SPI (1) -#define CIRCUITPY_BOARD_SPI_PIN {{.clock = DEFAULT_SPI_BUS_SCK, .mosi = DEFAULT_SPI_BUS_MOSI, .miso = NULL}} - #define DEFAULT_UART_BUS_RX (&pin_GPIO18) #define DEFAULT_UART_BUS_TX (&pin_GPIO17) From b9f0517d7fc9240daf28d93d939b370d2f4bc764 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Fri, 31 Jul 2026 19:56:05 +0200 Subject: [PATCH 718/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 2 +- locale/el.po | 2 +- locale/hi.po | 2 +- locale/ko.po | 2 +- locale/ru.po | 2 +- locale/tr.po | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 114d346243d..20ecba5b49b 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -723,7 +723,7 @@ msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c msgid "%q init failed" msgstr "Inicializace %q selhala" diff --git a/locale/el.po b/locale/el.po index b5dddad0aeb..83d329b7a41 100644 --- a/locale/el.po +++ b/locale/el.po @@ -726,7 +726,7 @@ msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c msgid "%q init failed" msgstr "%q εκκίνηση απέτυχε" diff --git a/locale/hi.po b/locale/hi.po index 40c0531e778..483002dfde2 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -717,7 +717,7 @@ msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c msgid "%q init failed" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 57ab628b0a2..22f39814a90 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -722,7 +722,7 @@ msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c msgid "%q init failed" msgstr "%q 초기화 실패" diff --git a/locale/ru.po b/locale/ru.po index bc7dd96ac7f..0e632d919c8 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -730,7 +730,7 @@ msgstr "Мягкая перезагрузка\n" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c msgid "%q init failed" msgstr "Инициализация %q не удалась" diff --git a/locale/tr.po b/locale/tr.po index 5f7ce87baee..d04687334d2 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -726,7 +726,7 @@ msgstr "" #: ports/analog/common-hal/busio/SPI.c ports/analog/common-hal/busio/UART.c #: ports/stm/common-hal/audioio/AudioOut.c #: shared-bindings/digitalio/DigitalInOutProtocol.c -#: shared-module/busdisplay/BusDisplay.c +#: shared-module/busdisplay/BusDisplay.c shared-module/ssl/SSLContext.c msgid "%q init failed" msgstr "%q init başarısız oldu" From 14005893f6f630e30b4e4c65205b192e1b178e19 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 30 Jul 2026 12:27:40 -0700 Subject: [PATCH 719/876] Add more nRF54 board defs * nRF54LM20DK * nRF54L15Tag Default kconfig is reworked so that things like BLE are enabled by default and boards can override them. (Instead of needing explicit opt-in). Switch to hex to load with nRF Connect for Desktop. Also updates the autogen board info and fixes RA8 USB defines --- ports/zephyr-cp/Kconfig | 83 ++++++++++++ .../autogen_board_info.toml | 5 +- .../autogen_board_info.toml | 5 +- .../autogen_board_info.toml | 3 + ...t_feather_nrf52840_nrf52840_sense_uf2.conf | 7 - .../boards/adafruit_feather_nrf52840_uf2.conf | 7 - ports/zephyr-cp/boards/board_aliases.cmake | 2 + ports/zephyr-cp/boards/ek_ra8d1.conf | 9 ++ ports/zephyr-cp/boards/frdm_rw612.conf | 20 +-- .../native/native_sim/autogen_board_info.toml | 3 + .../nrf5340bsim/autogen_board_info.toml | 3 + ports/zephyr-cp/boards/native_sim.conf | 3 + .../nordic/nrf5340dk/autogen_board_info.toml | 3 + .../nordic/nrf5340dk/circuitpython.toml | 2 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 3 + .../nordic/nrf54h20dk/circuitpython.toml | 2 +- .../nordic/nrf54l15dk/autogen_board_info.toml | 5 +- .../nordic/nrf54l15dk/circuitpython.toml | 2 +- .../nrf54l15tag/autogen_board_info.toml | 123 ++++++++++++++++++ .../nordic/nrf54l15tag/circuitpython.toml | 1 + .../nrf54lm20dk/autogen_board_info.toml | 123 ++++++++++++++++++ .../nordic/nrf54lm20dk/circuitpython.toml | 1 + .../nordic/nrf7002dk/autogen_board_info.toml | 3 + .../nordic/nrf7002dk/circuitpython.toml | 2 +- .../boards/nrf5340dk_nrf5340_cpuapp.conf | 20 --- .../boards/nrf54h20dk_nrf54h20_cpuapp.conf | 3 + .../boards/nrf54l15dk_nrf54l15_cpuapp.overlay | 29 ++++- .../boards/nrf54l15tag_nrf54l15_cpuapp.conf | 4 + .../nrf54l15tag_nrf54l15_cpuapp.overlay | 39 ++++++ ...onf => nrf54lm20dk_nrf54lm20a_cpuapp.conf} | 0 .../nrf54lm20dk_nrf54lm20a_cpuapp.overlay | 45 +++++++ .../boards/nrf7002dk_nrf5340_cpuapp.conf | 11 -- .../nxp/frdm_mcxn947/autogen_board_info.toml | 3 + .../nxp/frdm_rw612/autogen_board_info.toml | 3 + .../mimxrt1170_evk/autogen_board_info.toml | 3 + .../autogen_board_info.toml | 3 + .../rpi_pico2_zephyr/autogen_board_info.toml | 3 + .../rpi_pico_w_zephyr/autogen_board_info.toml | 3 + .../rpi_pico_zephyr/autogen_board_info.toml | 3 + .../da14695_dk_usb/autogen_board_info.toml | 3 + .../renesas/ek_ra6m5/autogen_board_info.toml | 3 + .../renesas/ek_ra8d1/autogen_board_info.toml | 3 + .../boards/renesas_da14695_dk_usb.conf | 20 --- .../nucleo_n657x0_q/autogen_board_info.toml | 3 + .../nucleo_u575zi_q/autogen_board_info.toml | 3 + .../st/stm32h750b_dk/autogen_board_info.toml | 3 + .../st/stm32h7b3i_dk/autogen_board_info.toml | 3 + .../stm32wba65i_dk1/autogen_board_info.toml | 5 +- .../st/stm32wba65i_dk1/circuitpython.toml | 1 + ports/zephyr-cp/cptools/compat2driver.py | 1 + ports/zephyr-cp/prj.conf | 8 -- 51 files changed, 547 insertions(+), 101 deletions(-) create mode 100644 ports/zephyr-cp/Kconfig create mode 100644 ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/nordic/nrf54l15tag/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/nordic/nrf54lm20dk/circuitpython.toml delete mode 100644 ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf create mode 100644 ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.conf create mode 100644 ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.overlay rename ports/zephyr-cp/boards/{da14695_dk_usb.conf => nrf54lm20dk_nrf54lm20a_cpuapp.conf} (100%) create mode 100644 ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay delete mode 100644 ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf diff --git a/ports/zephyr-cp/Kconfig b/ports/zephyr-cp/Kconfig new file mode 100644 index 00000000000..8cce3c242fc --- /dev/null +++ b/ports/zephyr-cp/Kconfig @@ -0,0 +1,83 @@ +# CircuitPython Zephyr port — application Kconfig +# +# Sources Zephyr's main Kconfig, then adds CircuitPython-specific defaults. +# Boards can override any of these in their boards/.conf file. + +osource "$(ZEPHYR_BASE)/Kconfig.zephyr" + +# ===== Peripheral defaults — enabled by default, boards can disable ===== + +config I2C + default y + +config SPI + default y + +config SPI_ASYNC + default y + +config I2S + default y + +config UART_LINE_CTRL + default y + +config ENTROPY_GENERATOR + default y + +# ===== Bluetooth defaults ===== + +# Use a variable for the chosen name so the comma isn't parsed as an argument separator +DT_BT_HCI_CHOSEN := zephyr,bt-hci + +config BT + default $(dt_chosen_enabled,$(DT_BT_HCI_CHOSEN)) + +config BT_PERIPHERAL + default y + +config BT_CENTRAL + default y + +config BT_BROADCASTER + default y + +config BT_OBSERVER + default y + +config BT_EXT_ADV + default y + +config BT_DEVICE_APPEARANCE_DYNAMIC + default y + +config BT_DEVICE_NAME_DYNAMIC + default y + +config BT_DEVICE_NAME_MAX + default 28 + +config BT_L2CAP_TX_MTU + default 253 + +# BT Buffers +config BT_BUF_CMD_TX_SIZE + default 255 + +config BT_BUF_EVT_RX_COUNT + default 16 + +config BT_BUF_EVT_RX_SIZE + default 255 + +config BT_BUF_ACL_TX_COUNT + default 3 + +config BT_BUF_ACL_TX_SIZE + default 251 + +config BT_BUF_ACL_RX_COUNT_EXTRA + default 1 + +config BT_BUF_ACL_RX_SIZE + default 255 diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml index d6aca312226..f0e267fbde6 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -3,7 +3,7 @@ name = "Adafruit Industries LLC Feather Bluefruit Sense" [modules] __future__ = true -_bleio = false +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index dafe7811779..a7dcae5448b 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -3,7 +3,7 @@ name = "Adafruit Industries LLC Feather nRF52840 Express" [modules] __future__ = true -_bleio = false +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index cecf8e55a83..73bc9bd92e8 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf index 20176b34be0..6d7299ec6e6 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf @@ -1,10 +1,3 @@ -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y - CONFIG_USE_DT_CODE_PARTITION=y CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf index 20176b34be0..6d7299ec6e6 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf @@ -1,10 +1,3 @@ -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y - CONFIG_USE_DT_CODE_PARTITION=y CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index ad0c1b5a57a..6a7c357ab9d 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -36,6 +36,8 @@ cp_board_alias(renesas_da14695_dk_usb da14695_dk_usb) cp_board_alias(native_native_sim native_sim/native) cp_board_alias(native_nrf5340bsim nrf5340bsim/nrf5340/cpuapp) cp_board_alias(nordic_nrf54l15dk nrf54l15dk/nrf54l15/cpuapp) +cp_board_alias(nordic_nrf54l15tag nrf54l15tag/nrf54l15/cpuapp) +cp_board_alias(nordic_nrf54lm20dk nrf54lm20dk/nrf54lm20a/cpuapp) cp_board_alias(nordic_nrf54h20dk nrf54h20dk/nrf54h20/cpuapp) cp_board_alias(nordic_nrf5340dk nrf5340dk/nrf5340/cpuapp) cp_board_alias(nordic_nrf7002dk nrf7002dk/nrf5340/cpuapp) diff --git a/ports/zephyr-cp/boards/ek_ra8d1.conf b/ports/zephyr-cp/boards/ek_ra8d1.conf index f979d31e751..451f4199116 100644 --- a/ports/zephyr-cp/boards/ek_ra8d1.conf +++ b/ports/zephyr-cp/boards/ek_ra8d1.conf @@ -1,3 +1,12 @@ # Enable Zephyr display subsystem so DT chosen zephyr,display creates a device. CONFIG_DISPLAY=y + +# RA8 USB can generate bursts of UDC/USBD events (especially with HS + MSC). +# Keep queues/buffers larger to avoid dropped events that can desynchronize +# control-transfer state (e.g. "udc: Cannot determine the next stage"). +CONFIG_UDC_RENESAS_RA_MAX_QMESSAGES=32 +CONFIG_USBD_MAX_UDC_MSG=32 +CONFIG_USBD_MSG_SLAB_COUNT=32 +CONFIG_UDC_BUF_COUNT=32 +CONFIG_UDC_BUF_POOL_SIZE=2048 diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf index c06f78ae830..761c2cc4513 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.conf +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -18,25 +18,7 @@ CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y CONFIG_MBEDTLS_ENTROPY_C=y CONFIG_MBEDTLS_CTR_DRBG_C=y -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y - -CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_MAX=28 -CONFIG_BT_L2CAP_TX_MTU=253 - -# BT Buffers -CONFIG_BT_BUF_CMD_TX_SIZE=255 -CONFIG_BT_BUF_EVT_RX_COUNT=16 -CONFIG_BT_BUF_EVT_RX_SIZE=255 +# Override bt.conf default CONFIG_BT_BUF_ACL_TX_COUNT=8 -CONFIG_BT_BUF_ACL_TX_SIZE=251 -CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 -CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_UDC_WORKQUEUE_STACK_SIZE=1024 diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index b565e8b139f..bedaad4370d 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = true # Zephyr board has audiobusio audiocore = true # Zephyr board has audiobusio audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false audiofilters = true # Zephyr board has audiobusio audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false audioio = false audiomixer = true # Zephyr board has audiobusio audiomp3 = true # Zephyr board has audiobusio @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = false usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index aa723b53f64..34dacd251dc 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = false usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native_sim.conf index 00af0d01ac6..6ae4c35110b 100644 --- a/ports/zephyr-cp/boards/native_sim.conf +++ b/ports/zephyr-cp/boards/native_sim.conf @@ -1,3 +1,6 @@ +# No Bluetooth hardware on native_sim +CONFIG_BT=n + CONFIG_EMUL=y CONFIG_GPIO=y CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME=n diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index ee20efa6fee..e7864b79ddc 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = true # Zephyr board has audiobusio audiocore = true # Zephyr board has audiobusio audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false audiofilters = true # Zephyr board has audiobusio audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false audioio = false audiomixer = true # Zephyr board has audiobusio audiomp3 = true # Zephyr board has audiobusio @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/circuitpython.toml index bf17d26d91b..cc7e3ae8c4a 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/circuitpython.toml @@ -1,3 +1,3 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] USB_VID=0x239A USB_PID=0x8166 diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index ca2c90ceb0b..56b281cbf1d 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml index 415c471b3d4..7cf2501b2b1 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/circuitpython.toml @@ -1,2 +1,2 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "hex"] DISABLED_MODULES=["jpegio", "gifio", "tilepalettemapper"] diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 69fdc2da903..78267407579 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -3,7 +3,7 @@ name = "Nordic Semiconductor nRF54L15 DK" [modules] __future__ = true -_bleio = false +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = false usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/circuitpython.toml index 3272dd4c5f3..00c797b1dad 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/circuitpython.toml @@ -1 +1 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["elf", "hex"] diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml new file mode 100644 index 00000000000..7a0a3a145db --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml @@ -0,0 +1,123 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Nordic Semiconductor nRF54L15 TAG" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15tag/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54l15tag/circuitpython.toml new file mode 100644 index 00000000000..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54l15tag/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml new file mode 100644 index 00000000000..f3b6554194e --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml @@ -0,0 +1,123 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Nordic Semiconductor nRF54LM20 DK" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/circuitpython.toml new file mode 100644 index 00000000000..83e6bcd39c4 --- /dev/null +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index e0b759e01ce..d7b4b28b4d6 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index 761d2631477..54f84efe09b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -1,4 +1,4 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["hex"] USB_VID=0x239A USB_PID=0x8168 BLOBS=["nrf_wifi"] diff --git a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf deleted file mode 100644 index 145a9393407..00000000000 --- a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.conf +++ /dev/null @@ -1,20 +0,0 @@ -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y - -CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_MAX=28 -CONFIG_BT_L2CAP_TX_MTU=253 - -# BT Buffers -CONFIG_BT_BUF_CMD_TX_SIZE=255 -CONFIG_BT_BUF_EVT_RX_COUNT=16 -CONFIG_BT_BUF_EVT_RX_SIZE=255 -CONFIG_BT_BUF_ACL_TX_COUNT=3 -CONFIG_BT_BUF_ACL_TX_SIZE=251 -CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 -CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf index a55b90c50e7..3aca8d77007 100644 --- a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf @@ -1,5 +1,8 @@ CONFIG_FLASH_MSPI_NOR_LAYOUT_PAGE_SIZE=4096 +# BLE overflows flash on this board. +CONFIG_BT=n + # Reduce flash usage for this board. CONFIG_LOG=y CONFIG_LOG_MAX_LEVEL=2 diff --git a/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay index 39db1e981af..7ffd2dec4d6 100644 --- a/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -1 +1,28 @@ -// No app.overlay because it doesn't have USB. +// nRF54L15 DK doesn't have USB, so no app.overlay for CDC ACM. + +// I2C bus on P1.8 (SDA) and P1.10 (SCL). +&pinctrl { + i2c21_default: i2c21_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; + + i2c21_sleep: i2c21_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&i2c21 { + clock-frequency = ; + pinctrl-0 = <&i2c21_default>; + pinctrl-1 = <&i2c21_sleep>; + pinctrl-names = "default", "sleep"; + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.conf b/ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.conf new file mode 100644 index 00000000000..2627ebe2e5f --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.conf @@ -0,0 +1,4 @@ +# Enable UART console (not enabled in the Zephyr board defconfig) +CONFIG_SERIAL=y +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y diff --git a/ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..ddf5c8f7e8f --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.overlay @@ -0,0 +1,39 @@ +// No app.overlay because it doesn't have USB. + +// The nrf54l15tag Zephyr board doesn't enable a UART or set zephyr,console, +// unlike the nrf54l15dk. Set up UART30 as the console using available pins. +&uart30 { + status = "okay"; + current-speed = <115200>; + pinctrl-0 = <&uart30_default>; + pinctrl-1 = <&uart30_sleep>; + pinctrl-names = "default", "sleep"; +}; + +&pinctrl { + uart30_default: uart30_default { + group1 { + psels = ; + }; + group2 { + psels = ; + bias-pull-up; + }; + }; + + uart30_sleep: uart30_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +/ { + chosen { + zephyr,console = &uart30; + zephyr,shell-uart = &uart30; + zephyr,uart-mcumgr = &uart30; + }; +}; diff --git a/ports/zephyr-cp/boards/da14695_dk_usb.conf b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf similarity index 100% rename from ports/zephyr-cp/boards/da14695_dk_usb.conf rename to ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf diff --git a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay new file mode 100644 index 00000000000..837b8b6ad0a --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay @@ -0,0 +1,45 @@ +// nRF54LM20 DK has USB. Include the main app overlay for USB CDC ACM console and data. +#include "../app.overlay" + +// Enable the external MX25R6435F 8MB QSPI flash (connected via SPIM00). +&mx25r64 { + status = "okay"; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_M(8)>; + }; + }; +}; + +// I2C bus on P1.13 (SDA) and P1.23 (SCL). +&pinctrl { + i2c21_default: i2c21_default { + group1 { + psels = , + ; + bias-pull-up; + }; + }; + + i2c21_sleep: i2c21_sleep { + group1 { + psels = , + ; + low-power-enable; + }; + }; +}; + +&i2c21 { + clock-frequency = ; + pinctrl-0 = <&i2c21_default>; + pinctrl-1 = <&i2c21_sleep>; + pinctrl-names = "default", "sleep"; + status = "okay"; +}; diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index 91c956fa676..679e7ae76f3 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -3,17 +3,6 @@ CONFIG_WIFI=y CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y -CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_MAX=28 - -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y - CONFIG_LOG=n CONFIG_ASSERT=n CONFIG_TEST_RANDOM_GENERATOR=y diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index b8e2c0601aa..258448a3e11 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = true # Zephyr board has audiobusio audiocore = true # Zephyr board has audiobusio audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false audiofilters = true # Zephyr board has audiobusio audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false audioio = false audiomixer = true # Zephyr board has audiobusio audiomp3 = true # Zephyr board has audiobusio @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 557b4f0448f..9a7c60fd6f7 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index ee43ef86e8c..90ebfee6da5 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = true # Zephyr board has audiobusio audiocore = true # Zephyr board has audiobusio audiodelays = true # Zephyr board has audiobusio +audiofilewriter = false audiofilters = true # Zephyr board has audiobusio audiofreeverb = true # Zephyr board has audiobusio +audioi2sin = false audioio = false audiomixer = true # Zephyr board has audiobusio audiomp3 = true # Zephyr board has audiobusio @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index 2215bcf4135..f71b1f11f0d 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index 61324042092..98b8133dd1b 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index 203f5fd7048..49b1f58b87f 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index 13c77bf2928..c3174075c89 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index e596ea1aebc..251385b99d8 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 7751ec96715..b31333b9067 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 42bef11db0c..f6bfd40c0e7 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf b/ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf deleted file mode 100644 index 145a9393407..00000000000 --- a/ports/zephyr-cp/boards/renesas_da14695_dk_usb.conf +++ /dev/null @@ -1,20 +0,0 @@ -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y - -CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_MAX=28 -CONFIG_BT_L2CAP_TX_MTU=253 - -# BT Buffers -CONFIG_BT_BUF_CMD_TX_SIZE=255 -CONFIG_BT_BUF_EVT_RX_COUNT=16 -CONFIG_BT_BUF_EVT_RX_SIZE=255 -CONFIG_BT_BUF_ACL_TX_COUNT=3 -CONFIG_BT_BUF_ACL_TX_SIZE=251 -CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 -CONFIG_BT_BUF_ACL_RX_SIZE=255 diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 7ad9c4f2111..5963859bcaf 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 2796f76782f..11f10b2590d 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index 2d5385d90b2..f2dc207a69c 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = false usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 7f158d6f278..993afe00a32 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 19141f30065..b3866957c88 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -3,7 +3,7 @@ name = "STMicroelectronics STM32WBA65I Discovery kit" [modules] __future__ = true -_bleio = false +_bleio = true # Zephyr board has _bleio _eve = false _pew = false _pixelmap = false @@ -18,8 +18,10 @@ atexit = false audiobusio = false audiocore = false audiodelays = false +audiofilewriter = false audiofilters = false audiofreeverb = false +audioi2sin = false audioio = false audiomixer = false audiomp3 = false @@ -105,6 +107,7 @@ touchio = false traceback = true uheap = false usb = false +usb_audio = false usb_cdc = true usb_hid = false usb_host = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml index 83e6bcd39c4..fb3dfea6867 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/circuitpython.toml @@ -1 +1,2 @@ CIRCUITPY_BUILD_EXTENSIONS = ["hex"] +BLOBS=["hal_stm32"] diff --git a/ports/zephyr-cp/cptools/compat2driver.py b/ports/zephyr-cp/cptools/compat2driver.py index 7da74ffcf18..8cd3c248265 100644 --- a/ports/zephyr-cp/cptools/compat2driver.py +++ b/ports/zephyr-cp/cptools/compat2driver.py @@ -183,6 +183,7 @@ "zephyr_bt_hci_spi": "bluetooth/hci", "zephyr_bt_hci_uart": "bluetooth/hci", "zephyr_bt_hci_userchan": "bluetooth/hci", + "zephyr_bt_hci_ll_sw_split": "bluetooth/hci", # # cache "bflb_l1c": "cache", diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 765132742bb..f60e4c45bc3 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -24,19 +24,12 @@ CONFIG_USBD_MSC_LUNS_PER_INSTANCE=1 CONFIG_HWINFO=y CONFIG_REBOOT=y -CONFIG_ENTROPY_GENERATOR=y - CONFIG_ASSERT=n CONFIG_LOG_BLOCK_IN_THREAD=n CONFIG_EVENTS=y CONFIG_SERIAL=y -CONFIG_UART_LINE_CTRL=y - -CONFIG_I2C=y -CONFIG_SPI=y -CONFIG_SPI_ASYNC=y CONFIG_LOG=y CONFIG_LOG_MAX_LEVEL=2 @@ -46,7 +39,6 @@ CONFIG_NET_HOSTNAME_ENABLE=y CONFIG_NET_HOSTNAME_DYNAMIC=y CONFIG_NET_HOSTNAME="circuitpython" -CONFIG_I2S=y CONFIG_DYNAMIC_THREAD=y CONFIG_DYNAMIC_THREAD_ALLOC=y CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y From 260a10a1dfc0968cdd493dd86e6478a512fadc59 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 3 Aug 2026 09:06:56 -0400 Subject: [PATCH 720/876] nordic/common-hal/busio/UART.c: support two stop bits --- ports/nordic/common-hal/busio/UART.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ports/nordic/common-hal/busio/UART.c b/ports/nordic/common-hal/busio/UART.c index 6939486a5e6..7a4219a9728 100644 --- a/ports/nordic/common-hal/busio/UART.c +++ b/ports/nordic/common-hal/busio/UART.c @@ -182,7 +182,8 @@ void common_hal_busio_uart_construct(busio_uart_obj_t *self, .interrupt_priority = NRFX_UARTE_DEFAULT_CONFIG_IRQ_PRIORITY, .hal_cfg = { .hwfc = hwfc ? NRF_UARTE_HWFC_ENABLED : NRF_UARTE_HWFC_DISABLED, - .parity = (parity == BUSIO_UART_PARITY_NONE) ? NRF_UARTE_PARITY_EXCLUDED : NRF_UARTE_PARITY_INCLUDED + .parity = (parity == BUSIO_UART_PARITY_NONE) ? NRF_UARTE_PARITY_EXCLUDED : NRF_UARTE_PARITY_INCLUDED, + .stop = (stop == 2 ? NRF_UARTE_STOP_TWO : NRF_UARTE_STOP_ONE), } }; From c5dfd54ab8a6b1d005dff739363a9dd8680201c3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 3 Aug 2026 10:26:35 -0400 Subject: [PATCH 721/876] shrink pca10100 --- ports/nordic/boards/pca10100/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/nordic/boards/pca10100/mpconfigboard.mk b/ports/nordic/boards/pca10100/mpconfigboard.mk index a081a0db479..34bcc47cf9f 100644 --- a/ports/nordic/boards/pca10100/mpconfigboard.mk +++ b/ports/nordic/boards/pca10100/mpconfigboard.mk @@ -9,3 +9,4 @@ INTERNAL_FLASH_FILESYSTEM = 1 CIRCUITPY_ONEWIREIO = 0 CIRCUITPY_AUDIOMIXER = 0 +CIRCUITPY_RAINBOWIO = 0 From 00ad96a72e49a217b57266a49848de26b2a985e8 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 3 Aug 2026 11:00:47 -0700 Subject: [PATCH 722/876] Fix wba65 --- ports/zephyr-cp/boards/stm32wba65i_dk1.overlay | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay index 3b72ffc9984..14bd9c92d9a 100644 --- a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay +++ b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay @@ -58,4 +58,16 @@ zephyr_udc0: &usbotg_hs { status = "okay"; }; +&bt_hci_wba { + /* Use HASH IRQ to allocate Radio SW Low Process (Warning HASH is not used) */ + interrupts = <66 0>, <61 14>; + interrupt-names = "radio", "radio-sw-low"; +}; + +&ieee802154 { + /* Use HASH IRQ to allocate Radio SW Low Process (Warning HASH is not used) */ + interrupts = <66 0>, <61 14>; + interrupt-names = "radio", "radio-sw-low"; +}; + #include "../app.overlay" From d54e765e5d0bbb7acff0464480f58ccafddecaf8 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 3 Aug 2026 13:11:41 -0500 Subject: [PATCH 723/876] Fix left justified implementation on I2SIn with external clock --- ports/raspberrypi/common-hal/audioi2sin/I2SIn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 7bcfcb88ac7..0032e6fd7be 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -235,7 +235,7 @@ static size_t build_i2sin_ext_clock_program(uint16_t *prog, uint8_t bclk, uint8_ size_t len = 0; prog[len++] = 0x2000 | ws; // wait 0 gpio W prog[len++] = 0x2080 | ws; // wait 1 gpio W - if (left_justified) { + if (!left_justified) { prog[len++] = wait_1_bclk; // one more BCLK of skew } const size_t bitloop = len + 1; From 411b84ee4532d8c125b58d2ae731b84f633ce37c Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 3 Aug 2026 13:08:40 -0700 Subject: [PATCH 724/876] Update to latest zephyr --- .../adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay | 3 +++ ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay | 3 +++ ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay | 5 ++++- ports/zephyr-cp/boards/da14695_dk_usb.overlay | 1 + ports/zephyr-cp/boards/frdm_rw612.conf | 1 + ports/zephyr-cp/boards/frdm_rw612.overlay | 1 + ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay | 1 + ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay | 1 + ports/zephyr-cp/boards/native_sim.overlay | 3 ++- ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay | 2 +- ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf | 1 + ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay | 4 +++- ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf | 1 + ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay | 4 +++- ports/zephyr-cp/boards/rpi_pico_rp2040.overlay | 5 ++++- ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf | 1 + ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay | 5 ++++- .../boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay | 1 + ports/zephyr-cp/boards/stm32wba65i_dk1.overlay | 5 ++++- ports/zephyr-cp/common-hal/busio/UART.c | 4 +--- ports/zephyr-cp/prj.conf | 2 +- ports/zephyr-cp/sysbuild.cmake | 4 ++-- ports/zephyr-cp/sysbuild/hci_ipc.conf | 3 +++ ports/zephyr-cp/zephyr-config/west.yml | 2 +- 24 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 ports/zephyr-cp/sysbuild/hci_ipc.conf diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay index e01ebd6df1f..405b65ec8eb 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay @@ -23,16 +23,19 @@ &flash0 { partitions { code_partition: partition@26000 { + compatible = "zephyr,mapped-partition"; label = "Application"; reg = <0x00026000 0x000c4000>; }; storage_partition: partition@ea000 { + compatible = "zephyr,mapped-partition"; label = "storage"; reg = <0x000ea000 0x00008000>; }; nvm_partition: partition@f2000 { + compatible = "zephyr,mapped-partition"; label = "nvm"; reg = <0x000f2000 0x00002000>; }; diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay index e01ebd6df1f..405b65ec8eb 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay +++ b/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay @@ -23,16 +23,19 @@ &flash0 { partitions { code_partition: partition@26000 { + compatible = "zephyr,mapped-partition"; label = "Application"; reg = <0x00026000 0x000c4000>; }; storage_partition: partition@ea000 { + compatible = "zephyr,mapped-partition"; label = "storage"; reg = <0x000ea000 0x00008000>; }; nvm_partition: partition@f2000 { + compatible = "zephyr,mapped-partition"; label = "nvm"; reg = <0x000f2000 0x00002000>; }; diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay index af7295ffe35..3cc026389f4 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay +++ b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay @@ -2,29 +2,32 @@ /delete-node/ partitions; partitions { - compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; /* Reserved memory for the second stage bootloader */ second_stage_bootloader: partition@0 { + compatible = "zephyr,mapped-partition"; label = "second_stage_bootloader"; reg = <0x00000000 0x100>; read-only; }; code_partition: partition@100 { + compatible = "zephyr,mapped-partition"; label = "code-partition"; reg = <0x100 (0x180000 - 0x100)>; read-only; }; nvm_partition: partition@180000 { + compatible = "zephyr,mapped-partition"; label = "nvm"; reg = <0x180000 0x1000>; }; circuitpy_partition: partition@181000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x181000 (DT_SIZE_M(8) - 0x181000)>; }; diff --git a/ports/zephyr-cp/boards/da14695_dk_usb.overlay b/ports/zephyr-cp/boards/da14695_dk_usb.overlay index fbc1817c759..8ad8198db0a 100644 --- a/ports/zephyr-cp/boards/da14695_dk_usb.overlay +++ b/ports/zephyr-cp/boards/da14695_dk_usb.overlay @@ -1,6 +1,7 @@ &flash0 { partitions{ circuitpy_partition: partition@118000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x118000 (DT_SIZE_M(4) - DT_SIZE_K(1120))>; }; diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf index 761c2cc4513..2f7f43dcbef 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.conf +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -4,6 +4,7 @@ CONFIG_NET_DHCPV4=y CONFIG_NET_SOCKETS=y CONFIG_WIFI=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n CONFIG_NET_L2_WIFI_MGMT=y CONFIG_NET_MGMT_EVENT=y CONFIG_NET_MGMT_EVENT_INFO=y diff --git a/ports/zephyr-cp/boards/frdm_rw612.overlay b/ports/zephyr-cp/boards/frdm_rw612.overlay index c6a021d9999..741d0702e03 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.overlay +++ b/ports/zephyr-cp/boards/frdm_rw612.overlay @@ -2,6 +2,7 @@ partitions { /delete-node/ partition@620000; circuitpy_partition: partition@620000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; }; diff --git a/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay index 9c517e43255..5a4d840c446 100644 --- a/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay +++ b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay @@ -2,6 +2,7 @@ partitions { /delete-node/ storage_partition; circuitpy_partition: partition@620000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; }; diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay index ac6fdd8654e..6a0ed82182e 100644 --- a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay +++ b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -2,6 +2,7 @@ partitions { /delete-node/ partition@e20000; circuitpy_partition: partition@e20000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x00e20000 (DT_SIZE_M(2) - DT_SIZE_K(128))>; }; diff --git a/ports/zephyr-cp/boards/native_sim.overlay b/ports/zephyr-cp/boards/native_sim.overlay index aee9d17f9d0..18dfa816107 100644 --- a/ports/zephyr-cp/boards/native_sim.overlay +++ b/ports/zephyr-cp/boards/native_sim.overlay @@ -25,16 +25,17 @@ &flash0 { /delete-node/ partitions; partitions { - compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; circuitpy_partition: partition@0 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x00000000 DT_SIZE_K(2040)>; }; nvm_partition: partition@1fe000 { + compatible = "zephyr,mapped-partition"; label = "nvm"; reg = <0x001fe000 0x00002000>; }; diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay index eeb043c6f3c..8f575d30475 100644 --- a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay @@ -14,11 +14,11 @@ &flash0 { /delete-node/ partitions; partitions { - compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; circuitpy_partition: partition@0 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x00000000 DT_SIZE_K(1024)>; }; diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index 679e7ae76f3..da7789578ff 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -1,5 +1,6 @@ CONFIG_NETWORKING=y CONFIG_WIFI=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay index eb94fe7de67..a3c2a9911c0 100644 --- a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay @@ -1,21 +1,23 @@ &flash0 { partitions { - compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; code_partition: partition@0 { + compatible = "zephyr,mapped-partition"; label = "code-partition"; reg = <0x0 0x180000>; read-only; }; nvm_partition: partition@180000 { + compatible = "zephyr,mapped-partition"; label = "nvm"; reg = <0x180000 0x1000>; }; circuitpy_partition: partition@181000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x181000 (DT_SIZE_M(4) - 0x181000)>; }; diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf index d75b1cd20a9..8fcc1c0b9ae 100644 --- a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf @@ -4,6 +4,7 @@ CONFIG_NET_DHCPV4=y CONFIG_NET_SOCKETS=y CONFIG_WIFI=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n CONFIG_NET_L2_WIFI_MGMT=y CONFIG_NET_MGMT_EVENT=y CONFIG_NET_MGMT_EVENT_INFO=y diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay index eb94fe7de67..a3c2a9911c0 100644 --- a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay @@ -1,21 +1,23 @@ &flash0 { partitions { - compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; code_partition: partition@0 { + compatible = "zephyr,mapped-partition"; label = "code-partition"; reg = <0x0 0x180000>; read-only; }; nvm_partition: partition@180000 { + compatible = "zephyr,mapped-partition"; label = "nvm"; reg = <0x180000 0x1000>; }; circuitpy_partition: partition@181000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x181000 (DT_SIZE_M(4) - 0x181000)>; }; diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay index ce9083dd62d..d3ff27ddc74 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay @@ -2,29 +2,32 @@ /delete-node/ partitions; partitions { - compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; /* Reserved memory for the second stage bootloader */ second_stage_bootloader: partition@0 { + compatible = "zephyr,mapped-partition"; label = "second_stage_bootloader"; reg = <0x00000000 0x100>; read-only; }; code_partition: partition@100 { + compatible = "zephyr,mapped-partition"; label = "code-partition"; reg = <0x100 (0x180000 - 0x100)>; read-only; }; nvm_partition: partition@180000 { + compatible = "zephyr,mapped-partition"; label = "nvm"; reg = <0x180000 0x1000>; }; circuitpy_partition: partition@181000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; }; diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf index 975d6bfd6e1..1e2d7ae1cd2 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf @@ -4,6 +4,7 @@ CONFIG_NET_DHCPV4=y CONFIG_NET_SOCKETS=y CONFIG_WIFI=y +CONFIG_WIFI_NM_WPA_SUPPLICANT_LEGACY_CRYPTO=n CONFIG_NET_L2_WIFI_MGMT=y CONFIG_NET_MGMT_EVENT=y CONFIG_NET_MGMT_EVENT_INFO=y diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay index ce9083dd62d..d3ff27ddc74 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay @@ -2,29 +2,32 @@ /delete-node/ partitions; partitions { - compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; /* Reserved memory for the second stage bootloader */ second_stage_bootloader: partition@0 { + compatible = "zephyr,mapped-partition"; label = "second_stage_bootloader"; reg = <0x00000000 0x100>; read-only; }; code_partition: partition@100 { + compatible = "zephyr,mapped-partition"; label = "code-partition"; reg = <0x100 (0x180000 - 0x100)>; read-only; }; nvm_partition: partition@180000 { + compatible = "zephyr,mapped-partition"; label = "nvm"; reg = <0x180000 0x1000>; }; circuitpy_partition: partition@181000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x181000 (DT_SIZE_M(2) - 0x181000)>; }; diff --git a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay index fdb4960477b..c1d22c6261e 100644 --- a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay +++ b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay @@ -3,6 +3,7 @@ /delete-node/ partition@7800000; circuitpy_partition: partition@7800000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x7800000 DT_SIZE_M(8)>; }; diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay index 14bd9c92d9a..25ef6321eab 100644 --- a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay +++ b/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay @@ -2,26 +2,29 @@ /delete-node/ partitions; partitions { - compatible = "fixed-partitions"; #address-cells = <1>; #size-cells = <1>; boot_partition: partition@0 { + compatible = "zephyr,mapped-partition"; label = "mcuboot"; reg = <0x00000000 DT_SIZE_K(64)>; }; slot0_partition: partition@10000 { + compatible = "zephyr,mapped-partition"; label = "image-0"; reg = <0x00010000 DT_SIZE_K(928)>; }; storage_partition: partition@f80000 { + compatible = "zephyr,mapped-partition"; label = "storage"; reg = <0x001e0000 DT_SIZE_K(64)>; }; circuitpy_partition: partition@108000 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; reg = <0x00108000 DT_SIZE_K(992)>; }; diff --git a/ports/zephyr-cp/common-hal/busio/UART.c b/ports/zephyr-cp/common-hal/busio/UART.c index 9940853da50..af1de0e9023 100644 --- a/ports/zephyr-cp/common-hal/busio/UART.c +++ b/ports/zephyr-cp/common-hal/busio/UART.c @@ -30,9 +30,7 @@ static void serial_cb(const struct device *dev, void *user_data) { uint8_t c; - if (!uart_irq_update(dev)) { - return; - } + uart_irq_update(dev); if (!uart_irq_rx_ready(dev)) { return; diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index f60e4c45bc3..801ea354816 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -45,6 +45,6 @@ CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y CONFIG_MBEDTLS=y CONFIG_MBEDTLS_BUILTIN=y -CONFIG_MBEDTLS_PSA_CRYPTO_C=y +CONFIG_PSA_CRYPTO=y CONFIG_PSA_WANT_ALG_SHA_1=y CONFIG_PSA_WANT_ALG_SHA_256=y diff --git a/ports/zephyr-cp/sysbuild.cmake b/ports/zephyr-cp/sysbuild.cmake index 3c3acf0a803..bea5c588a2a 100644 --- a/ports/zephyr-cp/sysbuild.cmake +++ b/ports/zephyr-cp/sysbuild.cmake @@ -13,8 +13,8 @@ if(SB_CONFIG_NET_CORE_IMAGE_HCI_IPC) BOARD ${SB_CONFIG_NET_CORE_BOARD} ) - set(${NET_APP}_CONF_FILE - ${NET_APP_SRC_DIR}/nrf5340_cpunet_iso-bt_ll_sw_split.conf + set(${NET_APP}_OVERLAY_CONFIG + ${NET_APP_SRC_DIR}/extra-cis-bt_ll_sw_split.conf CACHE INTERNAL "" ) diff --git a/ports/zephyr-cp/sysbuild/hci_ipc.conf b/ports/zephyr-cp/sysbuild/hci_ipc.conf new file mode 100644 index 00000000000..20dc067f3e4 --- /dev/null +++ b/ports/zephyr-cp/sysbuild/hci_ipc.conf @@ -0,0 +1,3 @@ +# Enable dynamic TX power control so that BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL +# is supported by the controller. +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 4401481f966..241ca53aceb 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -8,6 +8,6 @@ manifest: path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: e1dc85052bc8928572fdb972997c65eeb96f555b + revision: 63f054c88ee158a3d755bd59a26ef874f650efa2 clone-depth: 100 import: true From 3d738312bd354eba5425f15bb76f0d3fa9cf9d06 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 3 Aug 2026 22:41:02 -0400 Subject: [PATCH 725/876] .github: remove Windows builds --- .github/actions/deps/external/action.yml | 1 - .github/workflows/build.yml | 108 ----------------------- 2 files changed, 109 deletions(-) diff --git a/.github/actions/deps/external/action.yml b/.github/actions/deps/external/action.yml index 81e73f871ef..15a3aeb5084 100644 --- a/.github/actions/deps/external/action.yml +++ b/.github/actions/deps/external/action.yml @@ -26,7 +26,6 @@ runs: inputs.port != 'zephyr-cp' uses: carlosperate/arm-none-eabi-gcc-action@v1 with: - # When changing this update what Windows grabs too! release: '15.2.Rel1' # espressif diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f28591e4f56..47b19a8fa7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,6 @@ jobs: outputs: docs: ${{ steps.set-matrix.outputs.docs }} ports: ${{ steps.set-matrix.outputs.ports }} - windows: ${{ steps.set-matrix.outputs.windows }} cp-version: ${{ steps.set-up-submodules.outputs.version }} steps: - name: Dump GitHub context @@ -214,113 +213,6 @@ jobs: [ -z "$TWINE_USERNAME" ] || echo "Uploading dev release to PyPi" [ -z "$TWINE_USERNAME" ] || twine upload circuitpython-stubs/dist/* - windows: - runs-on: windows-2022 - needs: scheduler - if: needs.scheduler.outputs.windows == 'True' - env: - CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} - defaults: - run: - # We define a custom shell script here, although `msys2.cmd` does neither exist nor is it available in the PATH yet - shell: msys2 {0} - steps: - # We want to change the configuration of the git command that actions/checkout will be using - # (since it is not possible to set autocrlf through the action yet, see actions/checkout#226). - - run: git config --global core.autocrlf input - shell: bash - - name: Check python coding (cmd) - run: python -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))" - shell: cmd - # We use a JS Action, which calls the system terminal or other custom terminals directly, if required - - uses: msys2/setup-msys2@v2 - with: - install: base-devel git wget unzip gcc python-pip - # The goal of this was to test how things worked when the default file encoding (locale.getpreferedencoding()) - # was not UTF-8. However, msys2 python does use utf-8 as the preferred file encoding, and using actions/setup-python - # python3.8 gave a broken build, so we're not really testing what we wanted to test. - # However, commandline length limits are being tested so that does some good. - - name: Check python coding (msys2) - run: | - locale -v - which python; python --version - python -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))" - which python3; python3 --version - python3 -c "import sys, locale; print(sys.getdefaultencoding(), locale.getpreferredencoding(False))" - - name: Install dependencies - run: | - wget --no-verbose -O gcc-arm.zip https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-mingw-w64-i686-arm-none-eabi.zip - unzip -q -d /tmp/arm-gnu-toolchain gcc-arm.zip - tar -C /tmp/arm-gnu-toolchain -cf - . | tar -C /usr/local -xf - - # We could use a venv instead, but that requires entering the venv on each run step - # that runs in its own shell. There are some actions that help with that, but not for msys2 - # that I can find. (dhalbert) - pip install --break-system-packages wheel - # requirements-dev.txt doesn't install on windows. (with msys2 python) - # instead, pick a subset for what we want to do - # jsonschema is needed by mbedtls' generate_driver_wrappers.py. Pin it below 4.18: - # 4.18 and later depend on rpds-py, a Rust extension with no wheel for msys2 python - # (SOABI cpython-3xx-x86_64-cygwin), and maturin refuses to build it from source - # ("Unsupported platform: x86_64-cygwin"). 4.17.3 uses attrs and pyrsistent instead, - # both of which install without a Rust toolchain. - pip install --break-system-packages cascadetoml jinja2 typer click intelhex 'jsonschema<4.18' - # check that installed packages work....? - which python; python --version; python -c "import cascadetoml" - which python3; python3 --version; python3 -c "import cascadetoml" - - name: Set up repository - uses: actions/checkout@v6 - with: - submodules: false - show-progress: false - fetch-depth: 1 - persist-credentials: false - - name: Set up submodules - uses: ./.github/actions/deps/submodules - - name: build mpy-cross - run: make -j4 -C mpy-cross - - name: build rp2040 - run: make -j4 -C ports/raspberrypi BOARD=adafruit_feather_rp2040 TRANSLATION=de_DE - - name: build samd21 - run: make -j4 -C ports/atmel-samd BOARD=feather_m0_express TRANSLATION=zh_Latn_pinyin - - name: build samd51 - run: make -j4 -C ports/atmel-samd BOARD=feather_m4_express TRANSLATION=es - - name: build nordic - run: make -j4 -C ports/nordic BOARD=feather_nrf52840_express TRANSLATION=fr - - name: build stm - run: make -j4 -C ports/stm BOARD=feather_stm32f405_express TRANSLATION=pt_BR - # I gave up trying to do esp builds on windows when I saw - # ERROR: Platform MINGW64_NT-10.0-17763-x86_64 appears to be unsupported - # https://github.com/espressif/esp-idf/issues/7062 - - windows-zephyr: - strategy: - matrix: - os: [windows-2022, windows-2025] - runs-on: ${{ matrix.os }} - needs: scheduler - if: needs.scheduler.outputs.windows == 'True' - env: - CP_VERSION: ${{ needs.scheduler.outputs.cp-version }} - steps: - - name: Set up repository - uses: actions/checkout@v6 - with: - submodules: false - show-progress: false - fetch-depth: 1 - persist-credentials: false - - uses: actions/setup-python@v6 - with: - python-version: '3.13' - - name: Set up Zephyr - uses: ./.github/actions/deps/ports/zephyr-cp - - name: Set up submodules - uses: ./.github/actions/deps/submodules - - name: build mpy-cross - run: make -j4 -C mpy-cross - - name: build ek_ra8d1 - run: make -j4 -C ports/zephyr-cp BOARD=renesas_ek_ra8d1 - ports: needs: [scheduler, mpy-cross, tests] if: needs.scheduler.outputs.ports != '{}' From 2cc37347eb15e1b5aa56c6812bfdc7f153491558 Mon Sep 17 00:00:00 2001 From: Daniil Mordanov Date: Tue, 4 Aug 2026 21:43:24 +0700 Subject: [PATCH 726/876] ports/raspberrypi/socketpool: Add multicast TTL support. Signed-off-by: Daniil Mordanov --- ports/raspberrypi/common-hal/socketpool/Socket.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ports/raspberrypi/common-hal/socketpool/Socket.c b/ports/raspberrypi/common-hal/socketpool/Socket.c index 0543fd53dc3..840558d1ac3 100644 --- a/ports/raspberrypi/common-hal/socketpool/Socket.c +++ b/ports/raspberrypi/common-hal/socketpool/Socket.c @@ -1226,6 +1226,20 @@ int common_hal_socketpool_socket_setsockopt(socketpool_socket_obj_t *self, int l bool enable = optlen == sizeof(&zero) && memcmp(value, &zero, optlen); switch (level) { + case SOCKETPOOL_IPPROTO_IP: + switch (optname) { + case SOCKETPOOL_IP_MULTICAST_TTL: + if (self->type != SOCKETPOOL_SOCK_DGRAM) { + return -MP_EOPNOTSUPP; + } + if (self->pcb.udp == NULL || optlen < sizeof(uint8_t)) { + return -MP_EINVAL; + } + udp_set_multicast_ttl(self->pcb.udp, *(const uint8_t *)value); + return 0; + } + break; + case SOCKETPOOL_IPPROTO_TCP: switch (optname) { case SOCKETPOOL_TCP_NODELAY: From be0e817c6a379f7ab9c1b061df633d61461db910 Mon Sep 17 00:00:00 2001 From: Daniil Mordanov Date: Tue, 4 Aug 2026 22:32:31 +0700 Subject: [PATCH 727/876] ci: rerun flaky native test From 7d1fa89a78a214099f07f969c3397154e63d9e30 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 4 Aug 2026 10:33:40 -0500 Subject: [PATCH 728/876] audio Flanger FX --- py/circuitpy_defns.mk | 1 + shared-bindings/audiodelays/Flanger.c | 373 ++++++++++++++++++++++ shared-bindings/audiodelays/Flanger.h | 41 +++ shared-bindings/audiodelays/__init__.c | 2 + shared-module/audiodelays/Flanger.c | 408 +++++++++++++++++++++++++ shared-module/audiodelays/Flanger.h | 62 ++++ 6 files changed, 887 insertions(+) create mode 100644 shared-bindings/audiodelays/Flanger.c create mode 100644 shared-bindings/audiodelays/Flanger.h create mode 100644 shared-module/audiodelays/Flanger.c create mode 100644 shared-module/audiodelays/Flanger.h diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index 7dfb9ae7c7d..b40efc561a1 100644 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -712,6 +712,7 @@ SRC_SHARED_MODULE_ALL = \ audiospeed/__init__.c \ audiodelays/Echo.c \ audiodelays/Chorus.c \ + audiodelays/Flanger.c \ audiodelays/PitchShift.c \ audiodelays/GranularPitchShift.c \ audiodelays/MultiTapDelay.c \ diff --git a/shared-bindings/audiodelays/Flanger.c b/shared-bindings/audiodelays/Flanger.c new file mode 100644 index 00000000000..e582a1ecf0d --- /dev/null +++ b/shared-bindings/audiodelays/Flanger.c @@ -0,0 +1,373 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared-bindings/audiodelays/Flanger.h" +#include "shared-module/audiodelays/Flanger.h" +#include "shared-bindings/audiocore/__init__.h" + +#include "shared/runtime/context_manager_helpers.h" +#include "py/binary.h" +#include "py/objproperty.h" +#include "py/runtime.h" +#include "shared-bindings/util.h" +#include "shared-module/synthio/block.h" + +//| class Flanger: +//| """A Flanger effect""" +//| +//| def __init__( +//| self, +//| max_delay_ms: int = 10, +//| delay_ms: synthio.BlockInput = 1.0, +//| rate: synthio.BlockInput = 0.5, +//| depth: synthio.BlockInput = 0.5, +//| feedback: synthio.BlockInput = 0.5, +//| mix: synthio.BlockInput = 0.5, +//| invert: bool = False, +//| buffer_size: int = 512, +//| sample_rate: int = 8000, +//| bits_per_sample: int = 16, +//| samples_signed: bool = True, +//| channel_count: int = 1, +//| ) -> None: +//| """Create a Flanger effect by mixing the sample with a copy of itself taken from a very +//| short delay whose length is continuously swept up and down by an internal low frequency +//| oscillator. The moving delay creates a comb filter whose notches sweep through the +//| spectrum, and the ``feedback`` path routes the delayed signal back into the delay line +//| to sharpen those notches into resonant peaks. +//| +//| The delay is swept upwards from ``delay_ms`` towards ``max_delay_ms``:: +//| +//| sweep_top = delay_ms + depth * (max_delay_ms - delay_ms) +//| current_delay = delay_ms + triangle_lfo() * (sweep_top - delay_ms) +//| +//| where ``triangle_lfo()`` ranges from 0.0 to 1.0 at ``rate`` Hz. Because the sweep runs +//| upwards from a floor rather than around a centre, no combination of ``delay_ms`` and +//| ``depth`` can push the delay outside of the buffer. +//| +//| +//| :param int max_delay_ms: The maximum delay the flanger can sweep to in milliseconds, valid range is 1-100. +//| :param synthio.BlockInput delay_ms: The shortest delay of the sweep in milliseconds. Clamped between the length of one sample and max_delay_ms. +//| :param synthio.BlockInput rate: The frequency of the sweep in hertz. Clamped between 0.0 and 20.0. A rate of 0.0 holds the delay still. +//| :param synthio.BlockInput depth: How much of the range above delay_ms is swept, from 0.0 to 1.0. +//| :param synthio.BlockInput feedback: How much of the delayed signal is fed back into the delay line, from -0.95 to 0.95. Negative values invert the polarity of the feedback. +//| :param synthio.BlockInput mix: How much of the wet audio to include along with the original signal, from 0.0 to 1.0. +//| :param bool invert: Subtract the wet signal from the dry signal instead of adding it, which flips which frequencies cancel. +//| :param int buffer_size: The total size in bytes of each of the two playback buffers to use +//| :param int sample_rate: The sample rate to be used +//| :param int channel_count: The number of channels the source samples contain. 1 = mono; 2 = stereo. +//| :param int bits_per_sample: The bits per sample of the effect +//| :param bool samples_signed: Effect is signed (True) or unsigned (False) +//| +//| Adding a flanger to a synth:: +//| +//| import time +//| import board +//| import audiobusio +//| import synthio +//| import audiodelays +//| +//| audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WS, board.I2S_DOUT) +//| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) +//| flanger = audiodelays.Flanger(max_delay_ms=10, delay_ms=1.0, rate=0.3, depth=0.8, +//| feedback=0.7, mix=1.0, buffer_size=1024, +//| channel_count=1, sample_rate=44100) +//| audio.play(flanger.play(synth)) +//| +//| note = synthio.Note(261) +//| while True: +//| synth.press(note) +//| time.sleep(3) +//| synth.release(note) +//| time.sleep(1)""" +//| ... +//| +static mp_obj_t audiodelays_flanger_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_max_delay_ms, ARG_delay_ms, ARG_rate, ARG_depth, ARG_feedback, ARG_mix, ARG_invert, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_max_delay_ms, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 10 } }, + { MP_QSTR_delay_ms, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_rate, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_depth, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_feedback, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_invert, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, + { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, + { MP_QSTR_bits_per_sample, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 16} }, + { MP_QSTR_samples_signed, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + { MP_QSTR_channel_count, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 1 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t max_delay_ms = mp_arg_validate_int_range(args[ARG_max_delay_ms].u_int, 1, 100, MP_QSTR_max_delay_ms); + + mp_int_t channel_count = mp_arg_validate_int_range(args[ARG_channel_count].u_int, 1, 2, MP_QSTR_channel_count); + mp_int_t sample_rate = mp_arg_validate_int_min(args[ARG_sample_rate].u_int, 1, MP_QSTR_sample_rate); + mp_int_t bits_per_sample = args[ARG_bits_per_sample].u_int; + if (bits_per_sample != 8 && bits_per_sample != 16) { + mp_raise_ValueError(MP_ERROR_TEXT("bits_per_sample must be 8 or 16")); + } + + audiodelays_flanger_obj_t *self = mp_obj_malloc(audiodelays_flanger_obj_t, &audiodelays_flanger_type); + common_hal_audiodelays_flanger_construct(self, max_delay_ms, args[ARG_delay_ms].u_obj, args[ARG_rate].u_obj, args[ARG_depth].u_obj, args[ARG_feedback].u_obj, args[ARG_mix].u_obj, args[ARG_invert].u_bool, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + + return MP_OBJ_FROM_PTR(self); +} + +//| def deinit(self) -> None: +//| """Deinitialises the Flanger.""" +//| ... +//| +static mp_obj_t audiodelays_flanger_deinit(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_deinit(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_deinit_obj, audiodelays_flanger_deinit); + +static void check_for_deinit(audiodelays_flanger_obj_t *self) { + audiosample_check_for_deinit(&self->base); +} + +//| def __enter__(self) -> Flanger: +//| """No-op used by Context Managers.""" +//| ... +//| +// Provided by context manager helper. + +//| def __exit__(self) -> None: +//| """Automatically deinitializes when exiting a context. See +//| :ref:`lifetime-and-contextmanagers` for more info.""" +//| ... +//| +static mp_obj_t audiodelays_flanger_obj___exit__(size_t n_args, const mp_obj_t *args) { + (void)n_args; + common_hal_audiodelays_flanger_deinit(args[0]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiodelays_flanger___exit___obj, 4, 4, audiodelays_flanger_obj___exit__); + + +//| delay_ms: synthio.BlockInput +//| """The shortest delay of the sweep in milliseconds. This is the floor that the sweep runs +//| upwards from. Clamped between the length of a single sample and ``max_delay_ms``.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_delay_ms(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + + return common_hal_audiodelays_flanger_get_delay_ms(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_delay_ms_obj, audiodelays_flanger_obj_get_delay_ms); + +static mp_obj_t audiodelays_flanger_obj_set_delay_ms(mp_obj_t self_in, mp_obj_t delay_ms_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_delay_ms(self, delay_ms_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_delay_ms_obj, audiodelays_flanger_obj_set_delay_ms); + +MP_PROPERTY_GETSET(audiodelays_flanger_delay_ms_obj, + (mp_obj_t)&audiodelays_flanger_get_delay_ms_obj, + (mp_obj_t)&audiodelays_flanger_set_delay_ms_obj); + +//| rate: synthio.BlockInput +//| """The frequency of the delay sweep in hertz. Clamped between 0.0 and 20.0. A rate of 0.0 +//| holds the delay still, which leaves a fixed comb filter.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_rate(mp_obj_t self_in) { + return common_hal_audiodelays_flanger_get_rate(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_rate_obj, audiodelays_flanger_obj_get_rate); + +static mp_obj_t audiodelays_flanger_obj_set_rate(mp_obj_t self_in, mp_obj_t rate_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_rate(self, rate_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_rate_obj, audiodelays_flanger_obj_set_rate); + +MP_PROPERTY_GETSET(audiodelays_flanger_rate_obj, + (mp_obj_t)&audiodelays_flanger_get_rate_obj, + (mp_obj_t)&audiodelays_flanger_set_rate_obj); + +//| depth: synthio.BlockInput +//| """How much of the range between ``delay_ms`` and ``max_delay_ms`` the sweep covers, from +//| 0.0 to 1.0. A depth of 0.0 leaves a static short delay.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_depth(mp_obj_t self_in) { + return common_hal_audiodelays_flanger_get_depth(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_depth_obj, audiodelays_flanger_obj_get_depth); + +static mp_obj_t audiodelays_flanger_obj_set_depth(mp_obj_t self_in, mp_obj_t depth_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_depth(self, depth_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_depth_obj, audiodelays_flanger_obj_set_depth); + +MP_PROPERTY_GETSET(audiodelays_flanger_depth_obj, + (mp_obj_t)&audiodelays_flanger_get_depth_obj, + (mp_obj_t)&audiodelays_flanger_set_depth_obj); + +//| feedback: synthio.BlockInput +//| """How much of the delayed signal is fed back into the delay line, clamped between -0.95 and +//| 0.95. Larger magnitudes give a more resonant, ringing sweep. Negative values invert the +//| polarity of the feedback for the hollower variant.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_feedback(mp_obj_t self_in) { + return common_hal_audiodelays_flanger_get_feedback(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_feedback_obj, audiodelays_flanger_obj_get_feedback); + +static mp_obj_t audiodelays_flanger_obj_set_feedback(mp_obj_t self_in, mp_obj_t feedback_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_feedback(self, feedback_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_feedback_obj, audiodelays_flanger_obj_set_feedback); + +MP_PROPERTY_GETSET(audiodelays_flanger_feedback_obj, + (mp_obj_t)&audiodelays_flanger_get_feedback_obj, + (mp_obj_t)&audiodelays_flanger_set_feedback_obj); + +//| mix: synthio.BlockInput +//| """How much of the wet audio to include along with the original signal, clamped between 0.0 +//| and 1.0 where 0.0 is only the sample and 1.0 is the full effect.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_mix(mp_obj_t self_in) { + return common_hal_audiodelays_flanger_get_mix(self_in); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_mix_obj, audiodelays_flanger_obj_get_mix); + +static mp_obj_t audiodelays_flanger_obj_set_mix(mp_obj_t self_in, mp_obj_t mix_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_mix(self, mix_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_mix_obj, audiodelays_flanger_obj_set_mix); + +MP_PROPERTY_GETSET(audiodelays_flanger_mix_obj, + (mp_obj_t)&audiodelays_flanger_get_mix_obj, + (mp_obj_t)&audiodelays_flanger_set_mix_obj); + +//| invert: bool +//| """Whether the wet signal is subtracted from the dry signal instead of added to it. This +//| flips which frequencies the comb filter cancels, the same as the polarity switch on a +//| flanger pedal.""" +//| +static mp_obj_t audiodelays_flanger_obj_get_invert(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_bool(common_hal_audiodelays_flanger_get_invert(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_invert_obj, audiodelays_flanger_obj_get_invert); + +static mp_obj_t audiodelays_flanger_obj_set_invert(mp_obj_t self_in, mp_obj_t invert_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_flanger_set_invert(self, mp_obj_is_true(invert_in)); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_invert_obj, audiodelays_flanger_obj_set_invert); + +MP_PROPERTY_GETSET(audiodelays_flanger_invert_obj, + (mp_obj_t)&audiodelays_flanger_get_invert_obj, + (mp_obj_t)&audiodelays_flanger_set_invert_obj); + +//| playing: bool +//| """True when the effect is playing a sample. (read-only)""" +//| +static mp_obj_t audiodelays_flanger_obj_get_playing(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_bool(common_hal_audiodelays_flanger_get_playing(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_playing_obj, audiodelays_flanger_obj_get_playing); + +MP_PROPERTY_GETTER(audiodelays_flanger_playing_obj, + (mp_obj_t)&audiodelays_flanger_get_playing_obj); + +//| def play(self, sample: circuitpython_typing.AudioSample, *, loop: bool = False) -> Flanger: +//| """Plays the sample once when loop=False and continuously when loop=True. +//| Does not block. Use `playing` to block. +//| +//| The sample must match the encoding settings given in the constructor. +//| +//| :return: The effect object itself. Can be used for chaining, ie: +//| ``audio.play(effect.play(sample))``. +//| :rtype: Flanger""" +//| ... +//| +static mp_obj_t audiodelays_flanger_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sample, ARG_loop }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sample, MP_ARG_OBJ | MP_ARG_REQUIRED, {} }, + { MP_QSTR_loop, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} }, + }; + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + check_for_deinit(self); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + + mp_obj_t sample = args[ARG_sample].u_obj; + common_hal_audiodelays_flanger_play(self, sample, args[ARG_loop].u_bool); + + return MP_OBJ_FROM_PTR(self); +} +MP_DEFINE_CONST_FUN_OBJ_KW(audiodelays_flanger_play_obj, 1, audiodelays_flanger_obj_play); + +//| def stop(self) -> None: +//| """Stops playback of the sample.""" +//| ... +//| +//| +static mp_obj_t audiodelays_flanger_obj_stop(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + + common_hal_audiodelays_flanger_stop(self); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_stop_obj, audiodelays_flanger_obj_stop); + +static const mp_rom_map_elem_t audiodelays_flanger_locals_dict_table[] = { + // Methods + { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audiodelays_flanger_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) }, + { MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audiodelays_flanger___exit___obj) }, + { MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audiodelays_flanger_play_obj) }, + { MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audiodelays_flanger_stop_obj) }, + + // Properties + { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_flanger_playing_obj) }, + { MP_ROM_QSTR(MP_QSTR_delay_ms), MP_ROM_PTR(&audiodelays_flanger_delay_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiodelays_flanger_rate_obj) }, + { MP_ROM_QSTR(MP_QSTR_depth), MP_ROM_PTR(&audiodelays_flanger_depth_obj) }, + { MP_ROM_QSTR(MP_QSTR_feedback), MP_ROM_PTR(&audiodelays_flanger_feedback_obj) }, + { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_flanger_mix_obj) }, + { MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&audiodelays_flanger_invert_obj) }, + AUDIOSAMPLE_FIELDS, +}; +static MP_DEFINE_CONST_DICT(audiodelays_flanger_locals_dict, audiodelays_flanger_locals_dict_table); + +static const audiosample_p_t audiodelays_flanger_proto = { + MP_PROTO_IMPLEMENT(MP_QSTR_protocol_audiosample) + .reset_buffer = (audiosample_reset_buffer_fun)audiodelays_flanger_reset_buffer, + .get_buffer = (audiosample_get_buffer_fun)audiodelays_flanger_get_buffer, +}; + +MP_DEFINE_CONST_OBJ_TYPE( + audiodelays_flanger_type, + MP_QSTR_Flanger, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, audiodelays_flanger_make_new, + locals_dict, &audiodelays_flanger_locals_dict, + protocol, &audiodelays_flanger_proto + ); diff --git a/shared-bindings/audiodelays/Flanger.h b/shared-bindings/audiodelays/Flanger.h new file mode 100644 index 00000000000..859beff714a --- /dev/null +++ b/shared-bindings/audiodelays/Flanger.h @@ -0,0 +1,41 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/audiodelays/Flanger.h" + +extern const mp_obj_type_t audiodelays_flanger_type; + +void common_hal_audiodelays_flanger_construct(audiodelays_flanger_obj_t *self, uint32_t max_delay_ms, + mp_obj_t delay_ms, mp_obj_t rate, mp_obj_t depth, mp_obj_t feedback, mp_obj_t mix, bool invert, + uint32_t buffer_size, uint8_t bits_per_sample, + bool samples_signed, uint8_t channel_count, uint32_t sample_rate); + +void common_hal_audiodelays_flanger_deinit(audiodelays_flanger_obj_t *self); +bool common_hal_audiodelays_flanger_deinited(audiodelays_flanger_obj_t *self); + +mp_obj_t common_hal_audiodelays_flanger_get_delay_ms(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_delay_ms(audiodelays_flanger_obj_t *self, mp_obj_t delay_ms); + +mp_obj_t common_hal_audiodelays_flanger_get_rate(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_rate(audiodelays_flanger_obj_t *self, mp_obj_t rate); + +mp_obj_t common_hal_audiodelays_flanger_get_depth(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_depth(audiodelays_flanger_obj_t *self, mp_obj_t depth); + +mp_obj_t common_hal_audiodelays_flanger_get_feedback(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_feedback(audiodelays_flanger_obj_t *self, mp_obj_t feedback); + +mp_obj_t common_hal_audiodelays_flanger_get_mix(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_mix(audiodelays_flanger_obj_t *self, mp_obj_t arg); + +bool common_hal_audiodelays_flanger_get_invert(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_invert(audiodelays_flanger_obj_t *self, bool invert); + +bool common_hal_audiodelays_flanger_get_playing(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_play(audiodelays_flanger_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_audiodelays_flanger_stop(audiodelays_flanger_obj_t *self); diff --git a/shared-bindings/audiodelays/__init__.c b/shared-bindings/audiodelays/__init__.c index 2125aa54683..6ee7a82ab79 100644 --- a/shared-bindings/audiodelays/__init__.c +++ b/shared-bindings/audiodelays/__init__.c @@ -12,6 +12,7 @@ #include "shared-bindings/audiodelays/__init__.h" #include "shared-bindings/audiodelays/Echo.h" #include "shared-bindings/audiodelays/Chorus.h" +#include "shared-bindings/audiodelays/Flanger.h" #include "shared-bindings/audiodelays/PitchShift.h" #include "shared-bindings/audiodelays/GranularPitchShift.h" #include "shared-bindings/audiodelays/MultiTapDelay.h" @@ -26,6 +27,7 @@ static const mp_rom_map_elem_t audiodelays_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audiodelays) }, { MP_ROM_QSTR(MP_QSTR_Echo), MP_ROM_PTR(&audiodelays_echo_type) }, { MP_ROM_QSTR(MP_QSTR_Chorus), MP_ROM_PTR(&audiodelays_chorus_type) }, + { MP_ROM_QSTR(MP_QSTR_Flanger), MP_ROM_PTR(&audiodelays_flanger_type) }, { MP_ROM_QSTR(MP_QSTR_PitchShift), MP_ROM_PTR(&audiodelays_pitch_shift_type) }, { MP_ROM_QSTR(MP_QSTR_GranularPitchShift), MP_ROM_PTR(&audiodelays_granular_pitch_shift_type) }, { MP_ROM_QSTR(MP_QSTR_MultiTapDelay), MP_ROM_PTR(&audiodelays_multi_tap_delay_type) }, diff --git a/shared-module/audiodelays/Flanger.c b/shared-module/audiodelays/Flanger.c new file mode 100644 index 00000000000..25a0a598543 --- /dev/null +++ b/shared-module/audiodelays/Flanger.c @@ -0,0 +1,408 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#include "shared-bindings/audiodelays/Flanger.h" +#include "shared-bindings/audiocore/__init__.h" + +#include +#include "py/runtime.h" + +// The largest delay we will ever read, in frames. +#define FLANGER_MAX_DELAY_FRAMES (65535u) + +// Convert a delay in milliseconds to a Q16.16 count of frames, clamped so that both interpolation +// taps always land inside the delay line. +static uint32_t flanger_ms_to_frames_q16(audiodelays_flanger_obj_t *self, mp_float_t ms) { + mp_float_t frames = ms * self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0); + mp_float_t max_frames = (mp_float_t)MIN(self->delay_buffer_frames - 2, FLANGER_MAX_DELAY_FRAMES); + + // A delay of less than one frame would read the frame we are about to overwrite + frames = MIN(MAX(frames, MICROPY_FLOAT_CONST(1.0)), max_frames); + + return (uint32_t)(frames * MICROPY_FLOAT_CONST(65536.0)); +} + +void common_hal_audiodelays_flanger_construct(audiodelays_flanger_obj_t *self, uint32_t max_delay_ms, + mp_obj_t delay_ms, mp_obj_t rate, mp_obj_t depth, mp_obj_t feedback, mp_obj_t mix, bool invert, + uint32_t buffer_size, uint8_t bits_per_sample, + bool samples_signed, uint8_t channel_count, uint32_t sample_rate) { + + // Basic format settings every effect and audio sample has + self->base.bits_per_sample = bits_per_sample; + self->base.samples_signed = samples_signed; // Are the samples we provide signed (common is true) + self->base.channel_count = channel_count; // Channels can be 1 for mono or 2 for stereo + self->base.sample_rate = sample_rate; // Sample rate for the effect, this generally needs to match all audio objects + self->base.single_buffer = false; + self->base.max_buffer_length = buffer_size; + + // To smooth things out as CircuitPython is doing other tasks most audio objects have a buffer + // A double buffer is set up here so the audio output can use DMA on buffer 1 while we + // write to and create buffer 2. + // This buffer is what is passed to the audio component that plays the effect. + // Samples are set sequentially. For stereo audio they are passed L/R/L/R/... + self->buffer_len = buffer_size; // in bytes + + self->buffer[0] = m_malloc_maybe(self->buffer_len); + if (self->buffer[0] == NULL) { + common_hal_audiodelays_flanger_deinit(self); + m_malloc_fail(self->buffer_len); + } + memset(self->buffer[0], 0, self->buffer_len); + + self->buffer[1] = m_malloc_maybe(self->buffer_len); + if (self->buffer[1] == NULL) { + common_hal_audiodelays_flanger_deinit(self); + m_malloc_fail(self->buffer_len); + } + memset(self->buffer[1], 0, self->buffer_len); + + self->last_buf_idx = 1; // Which buffer to use first, toggle between 0 and 1 + + // Initialize other values most effects will need. + self->sample = NULL; // The current playing sample + self->sample_remaining_buffer = NULL; // Pointer to the start of the sample buffer we have not played + self->sample_buffer_length = 0; // How many samples do we have left to play (these may be 16 bit!) + self->loop = false; // When the sample is done do we loop to the start again or stop (e.g. in a wav file) + self->more_data = false; // Is there still more data to read from the sample or did we finish + + // The below section sets up the flanger effect's starting values. + + // If we did not receive a BlockInput we need to create a default float value + if (delay_ms == MP_OBJ_NULL) { + delay_ms = mp_obj_new_float(MICROPY_FLOAT_CONST(1.0)); + } + synthio_block_assign_slot(delay_ms, &self->delay_ms, MP_QSTR_delay_ms); + + if (rate == MP_OBJ_NULL) { + rate = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); + } + synthio_block_assign_slot(rate, &self->rate, MP_QSTR_rate); + + if (depth == MP_OBJ_NULL) { + depth = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); + } + synthio_block_assign_slot(depth, &self->depth, MP_QSTR_depth); + + if (feedback == MP_OBJ_NULL) { + feedback = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); + } + synthio_block_assign_slot(feedback, &self->feedback, MP_QSTR_feedback); + + if (mix == MP_OBJ_NULL) { + mix = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); + } + synthio_block_assign_slot(mix, &self->mix, MP_QSTR_mix); + + self->invert = invert; + self->max_delay_ms = max_delay_ms; + + // calculate the length of a single sample in milliseconds + self->sample_ms = MICROPY_FLOAT_CONST(1000.0) / self->base.sample_rate; + + // Allocate the delay line for the largest delay we can sweep to. It is always 16-bit and each + // channel gets its own contiguous region. The two extra frames are interpolation headroom: at + // the top of the sweep the two taps sit at the far end of the line and without the extra room + // the older of the two would alias onto the frame we are about to write. + self->delay_buffer_frames = (uint32_t)(self->base.sample_rate / MICROPY_FLOAT_CONST(1000.0) * max_delay_ms) + 2; + size_t delay_buffer_size = self->delay_buffer_frames * self->base.channel_count * sizeof(int16_t); + self->delay_buffer = m_malloc_maybe(delay_buffer_size); + if (self->delay_buffer == NULL) { + common_hal_audiodelays_flanger_deinit(self); + m_malloc_fail(delay_buffer_size); + } + memset(self->delay_buffer, 0, delay_buffer_size); + + self->delay_buffer_pos[0] = self->delay_buffer_pos[1] = 0; + self->lfo_phase[0] = self->lfo_phase[1] = 0; + self->lfo_phase_inc = 0; +} + +bool common_hal_audiodelays_flanger_deinited(audiodelays_flanger_obj_t *self) { + if (self->delay_buffer == NULL) { + return true; + } + return false; +} + +void common_hal_audiodelays_flanger_deinit(audiodelays_flanger_obj_t *self) { + audiosample_mark_deinit(&self->base); + self->delay_buffer = NULL; + self->buffer[0] = NULL; + self->buffer[1] = NULL; +} + +mp_obj_t common_hal_audiodelays_flanger_get_delay_ms(audiodelays_flanger_obj_t *self) { + return self->delay_ms.obj; +} + +void common_hal_audiodelays_flanger_set_delay_ms(audiodelays_flanger_obj_t *self, mp_obj_t delay_ms) { + synthio_block_assign_slot(delay_ms, &self->delay_ms, MP_QSTR_delay_ms); +} + +mp_obj_t common_hal_audiodelays_flanger_get_rate(audiodelays_flanger_obj_t *self) { + return self->rate.obj; +} + +void common_hal_audiodelays_flanger_set_rate(audiodelays_flanger_obj_t *self, mp_obj_t rate) { + synthio_block_assign_slot(rate, &self->rate, MP_QSTR_rate); +} + +mp_obj_t common_hal_audiodelays_flanger_get_depth(audiodelays_flanger_obj_t *self) { + return self->depth.obj; +} + +void common_hal_audiodelays_flanger_set_depth(audiodelays_flanger_obj_t *self, mp_obj_t depth) { + synthio_block_assign_slot(depth, &self->depth, MP_QSTR_depth); +} + +mp_obj_t common_hal_audiodelays_flanger_get_feedback(audiodelays_flanger_obj_t *self) { + return self->feedback.obj; +} + +void common_hal_audiodelays_flanger_set_feedback(audiodelays_flanger_obj_t *self, mp_obj_t feedback) { + synthio_block_assign_slot(feedback, &self->feedback, MP_QSTR_feedback); +} + +mp_obj_t common_hal_audiodelays_flanger_get_mix(audiodelays_flanger_obj_t *self) { + return self->mix.obj; +} + +void common_hal_audiodelays_flanger_set_mix(audiodelays_flanger_obj_t *self, mp_obj_t arg) { + synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); +} + +bool common_hal_audiodelays_flanger_get_invert(audiodelays_flanger_obj_t *self) { + return self->invert; +} + +void common_hal_audiodelays_flanger_set_invert(audiodelays_flanger_obj_t *self, bool invert) { + self->invert = invert; +} + +void audiodelays_flanger_reset_buffer(audiodelays_flanger_obj_t *self, + bool single_channel_output, + uint8_t channel) { + + memset(self->buffer[0], 0, self->buffer_len); + memset(self->buffer[1], 0, self->buffer_len); + memset(self->delay_buffer, 0, self->delay_buffer_frames * self->base.channel_count * sizeof(int16_t)); + self->delay_buffer_pos[0] = self->delay_buffer_pos[1] = 0; + self->lfo_phase[0] = self->lfo_phase[1] = 0; +} + +bool common_hal_audiodelays_flanger_get_playing(audiodelays_flanger_obj_t *self) { + return self->sample != NULL; +} + +void common_hal_audiodelays_flanger_play(audiodelays_flanger_obj_t *self, mp_obj_t sample, bool loop) { + audiosample_must_match(&self->base, sample, false); + + self->sample = sample; + self->loop = loop; + + audiosample_reset_buffer(self->sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + + // Track remaining sample length in terms of bytes per sample + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + // Store if we have more data in the sample to retrieve + self->more_data = result == GET_BUFFER_MORE_DATA; + + return; +} + +void common_hal_audiodelays_flanger_stop(audiodelays_flanger_obj_t *self) { + self->sample = NULL; + return; +} + +audioio_get_buffer_result_t audiodelays_flanger_get_buffer(audiodelays_flanger_obj_t *self, bool single_channel_output, uint8_t channel, + uint8_t **buffer, uint32_t *buffer_length) { + + if (!single_channel_output) { + channel = 0; + } + + // Switch our buffers to the other buffer + self->last_buf_idx = !self->last_buf_idx; + + // If we are using 16 bit samples we need a 16 bit pointer, 8 bit needs an 8 bit pointer + int16_t *word_buffer = (int16_t *)self->buffer[self->last_buf_idx]; + int8_t *hword_buffer = self->buffer[self->last_buf_idx]; + uint32_t length = self->buffer_len / (self->base.bits_per_sample / 8); + + uint8_t channel_count = self->base.channel_count; + uint32_t frames = self->delay_buffer_frames; + + // For single channel output every word in this call belongs to `channel`. Otherwise the + // channels are interleaved and alternate with every word. + bool single_right = single_channel_output && channel == 1 && channel_count == 2; + + // Loop over the entire length of our buffer to fill it, this may require several calls to get data from the sample + while (length != 0) { + // Check if there is no more sample to play, we will either load more data, reset the sample if loop is on or clear the sample + if (self->sample_buffer_length == 0) { + if (!self->more_data) { // The sample has indicated it has no more data to play + if (self->loop && self->sample) { // If we are supposed to loop reset the sample to the start + audiosample_reset_buffer(self->sample, false, 0); + } else { // If we were not supposed to loop the sample, stop playing it + self->sample = NULL; + } + } + if (self->sample) { + // Load another sample buffer to play + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->sample_remaining_buffer, &self->sample_buffer_length); + // Track length in terms of words. + self->sample_buffer_length /= (self->base.bits_per_sample / 8); + self->more_data = result == GET_BUFFER_MORE_DATA; + } + } + + if (self->sample == NULL) { + // tick all block inputs so that anything attached to them stays in sync + shared_bindings_synthio_lfo_tick(self->base.sample_rate, length / channel_count); + (void)synthio_block_slot_get(&self->delay_ms); + (void)synthio_block_slot_get(&self->rate); + (void)synthio_block_slot_get(&self->depth); + (void)synthio_block_slot_get(&self->feedback); + (void)synthio_block_slot_get(&self->mix); + + if (self->base.samples_signed) { + memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); + } else { + // For unsigned samples set to the middle which is "quiet" + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + uint16_t *uword_buffer = (uint16_t *)word_buffer; + while (length--) { + *uword_buffer++ = 32768; + } + } else { + memset(hword_buffer, 128, length * (self->base.bits_per_sample / 8)); + } + } + + length = 0; + } else { + // we have a sample to play and flange + // Determine how many bytes we can process to our buffer, the less of the sample we have left and our buffer remaining + uint32_t num_bytes = MIN(MIN(self->sample_buffer_length, length), SYNTHIO_MAX_DUR * channel_count); + + int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; // for 16-bit samples + int8_t *sample_hsrc = (int8_t *)self->sample_remaining_buffer; // for 8-bit samples + + // get the effect values we need from the BlockInput + shared_bindings_synthio_lfo_tick(self->base.sample_rate, num_bytes / channel_count); + mp_float_t f_delay_ms = synthio_block_slot_get_limited(&self->delay_ms, self->sample_ms, (mp_float_t)self->max_delay_ms); + mp_float_t f_rate = synthio_block_slot_get_limited(&self->rate, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(20.0)); + mp_float_t f_depth = synthio_block_slot_get_limited(&self->depth, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); + int32_t feedback = (int32_t)(synthio_block_slot_get_limited(&self->feedback, MICROPY_FLOAT_CONST(-0.95), MICROPY_FLOAT_CONST(0.95)) * 32767); + int32_t mix = (int32_t)(synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * 32767); + + // The sweep runs upward from delay_ms towards max_delay_ms rather than around a + // centre, so no combination of delay_ms and depth can push it out of the delay line. + mp_float_t sweep_top_ms = f_delay_ms + f_depth * ((mp_float_t)self->max_delay_ms - f_delay_ms); + uint32_t delay_min_q16 = flanger_ms_to_frames_q16(self, f_delay_ms); + uint32_t delay_span_q16 = flanger_ms_to_frames_q16(self, sweep_top_ms) - delay_min_q16; + + // How far the LFO advances each frame. A rate at or above half the sample rate is + // meaningless, and clamping there also keeps the conversion inside a uint32_t. + mp_float_t phase_inc = MIN(f_rate / self->base.sample_rate, MICROPY_FLOAT_CONST(0.5)); + self->lfo_phase_inc = (uint32_t)(phase_inc * MICROPY_FLOAT_CONST(4294967296.0)); + + for (uint32_t i = 0; i < num_bytes; i++) { + bool right_channel = single_channel_output ? single_right : ((i % channel_count) == 1); + + int32_t sample_word = 0; + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + sample_word = sample_src[i]; + } else { + if (self->base.samples_signed) { + sample_word = sample_hsrc[i]; + } else { + // changing from an 8 bit unsigned to signed into a 32-bit signed + sample_word = (int8_t)(((uint8_t)sample_hsrc[i]) ^ 0x80); + } + } + + // Advance this channel's LFO by one frame. Each channel has its own accumulator so + // that the sweep runs at `rate` whether the channels arrive interleaved (both + // accumulators step once per frame) or one channel per call. + self->lfo_phase[right_channel] += self->lfo_phase_inc; + + // Fold the sawtooth phase into a triangle in the range 0 to 65535 + uint32_t tri = self->lfo_phase[right_channel] >> 15; + if (tri > 65535) { + tri = 131071 - tri; + } + + // The delay for this frame, in Q16.16 frames + uint32_t delay_q16 = delay_min_q16 + (uint32_t)(((uint64_t)delay_span_q16 * tri) >> 16); + uint32_t delay_int = delay_q16 >> 16; + uint32_t delay_frac = delay_q16 & 0xffff; + + int16_t *line = self->delay_buffer + (right_channel ? frames : 0); + uint32_t w = self->delay_buffer_pos[right_channel]; + + // Two taps straddling the fractional delay, counted back from the write head. + // delay_int is at most frames - 2 so neither index can escape the region. + uint32_t r0 = w + frames - delay_int; + if (r0 >= frames) { + r0 -= frames; + } + uint32_t r1 = r0 ? r0 - 1 : frames - 1; + + // Linear interpolation between them + int32_t s0 = line[r0]; + int32_t s1 = line[r1]; + int32_t wet = s0 + (((s1 - s0) * (int32_t)delay_frac) >> 16); + + // Write the input plus the regenerated signal back into the line + line[w] = synthio_sat16(sample_word + synthio_sat16(wet * feedback, 15), 0); + self->delay_buffer_pos[right_channel] = (w + 1 == frames) ? 0 : w + 1; + + int32_t word; + if (mix <= 328) { // if mix is zero (0.01 in fixed point), pure sample only + // Note that we still ran the delay line above. + word = sample_word; + } else { + int32_t wet_word = synthio_sat16(wet * mix, 15); + // Add (or, inverted, subtract) original sample + effect + word = self->invert ? sample_word - wet_word : sample_word + wet_word; + word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); + } + + if (MP_LIKELY(self->base.bits_per_sample == 16)) { + word_buffer[i] = word; + if (!self->base.samples_signed) { + word_buffer[i] ^= 0x8000; + } + } else { + // 8-bit samples have no headroom for synthio_mix_down_sample to work with, so + // clamp instead or the sum of the dry and wet signals wraps around + int8_t out = MIN(MAX(word, -128), 127); + if (self->base.samples_signed) { + hword_buffer[i] = out; + } else { + hword_buffer[i] = (uint8_t)out ^ 0x80; + } + } + } + + // Update the remaining length and the buffer positions based on how much we wrote into our buffer + length -= num_bytes; + word_buffer += num_bytes; + hword_buffer += num_bytes; + self->sample_remaining_buffer += (num_bytes * (self->base.bits_per_sample / 8)); + self->sample_buffer_length -= num_bytes; + } + } + + // Finally pass our buffer and length to the calling audio function + *buffer = (uint8_t *)self->buffer[self->last_buf_idx]; + *buffer_length = self->buffer_len; + + // Flanger always returns more data but some effects may return GET_BUFFER_DONE or GET_BUFFER_ERROR (see audiocore/__init__.h) + return GET_BUFFER_MORE_DATA; +} diff --git a/shared-module/audiodelays/Flanger.h b/shared-module/audiodelays/Flanger.h new file mode 100644 index 00000000000..825f56d077b --- /dev/null +++ b/shared-module/audiodelays/Flanger.h @@ -0,0 +1,62 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Tim Cocks for Adafruit Industries +// +// SPDX-License-Identifier: MIT +#pragma once + +#include "py/obj.h" + +#include "shared-module/audiocore/__init__.h" +#include "shared-module/synthio/block.h" + +extern const mp_obj_type_t audiodelays_flanger_type; + +typedef struct { + audiosample_base_t base; + + // Effect parameters. + synthio_block_slot_t delay_ms; // floor of the sweep + synthio_block_slot_t rate; // LFO frequency in Hz + synthio_block_slot_t depth; // 0 to 1, portion of the available range swept + synthio_block_slot_t feedback; // -0.95 to 0.95, regeneration + synthio_block_slot_t mix; // 0 to 1, dry to wet + + uint32_t max_delay_ms; + mp_float_t sample_ms; // length of a single sample in milliseconds + + bool invert; // subtract the wet signal instead of adding it + + int8_t *buffer[2]; + uint8_t last_buf_idx; + uint32_t buffer_len; // max buffer in bytes + + uint8_t *sample_remaining_buffer; + uint32_t sample_buffer_length; + + bool loop; + bool more_data; + + // The delay line is always 16-bit and is split into one contiguous region per channel so + // that read/write positions are plain frame counts and wrapping is a single modulo. + int16_t *delay_buffer; + uint32_t delay_buffer_frames; // frames in each per channel region + uint32_t delay_buffer_pos[2]; // write position in frames, per channel + + // Internal LFO. One phase accumulator per channel so that the sweep advances once per frame + // whether the channels are interleaved in one call or requested one channel at a time. + uint32_t lfo_phase[2]; // Q0.32, wraps naturally + uint32_t lfo_phase_inc; // Q0.32 step per frame, recalculated per chunk from rate + + mp_obj_t sample; +} audiodelays_flanger_obj_t; + +void audiodelays_flanger_reset_buffer(audiodelays_flanger_obj_t *self, + bool single_channel_output, + uint8_t channel); + +audioio_get_buffer_result_t audiodelays_flanger_get_buffer(audiodelays_flanger_obj_t *self, + bool single_channel_output, + uint8_t channel, + uint8_t **buffer, + uint32_t *buffer_length); // length in bytes From d6b0cb29199c4ef7698b939cf3dd8f45c25ae5c1 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 4 Aug 2026 10:47:50 -0500 Subject: [PATCH 729/876] fix unix port build --- ports/unix/variants/coverage/mpconfigvariant.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ports/unix/variants/coverage/mpconfigvariant.mk b/ports/unix/variants/coverage/mpconfigvariant.mk index 682fe77459e..0dd93b25cf4 100644 --- a/ports/unix/variants/coverage/mpconfigvariant.mk +++ b/ports/unix/variants/coverage/mpconfigvariant.mk @@ -39,6 +39,7 @@ SRC_BITMAP := \ shared-bindings/audiodelays/PitchShift.c \ shared-bindings/audiodelays/GranularPitchShift.c \ shared-bindings/audiodelays/MultiTapDelay.c \ + shared-bindings/audiodelays/Flanger.c \ shared-bindings/audiodelays/__init__.c \ shared-bindings/audiofilters/Distortion.c \ shared-bindings/audiofilters/Filter.c \ @@ -88,6 +89,7 @@ SRC_BITMAP := \ shared-module/audiodelays/PitchShift.c \ shared-module/audiodelays/GranularPitchShift.c \ shared-module/audiodelays/MultiTapDelay.c \ + shared-module/audiodelays/Flanger.c \ shared-module/audiodelays/__init__.c \ shared-module/audiofilters/Distortion.c \ shared-module/audiofilters/Filter.c \ From ebb7b0d4e310f37eac41bf652d2eaee8666f03d1 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Tue, 4 Aug 2026 09:19:19 +0000 Subject: [PATCH 730/876] Add CIRCUITPY_HEAP_SRAM_SIZE: opt-in internal-RAM heap start segment On boards whose python heap defaults to external PSRAM (#10240), all python allocations pay external-memory latency. Measured on an Adafruit Fruit Jam (RP2350 + 8 MB PSRAM): span writes reach ~8.7 MB/s vs ~64+ MB/s in internal SRAM; clearing/filling a 38 KB RGB565 buffer takes 4.2 ms from PSRAM vs 0.23 ms from SRAM (18x), and a bytecode-heavy program's frame time improved ~10% overall with its early allocations in SRAM - the interpreter working set (module bytecode, young objects) pays the PSRAM tax too. This answers the open review question on #10240 about how much the PSRAM heap costs. Since the heap is already segmented (start segment + auto-grown splits), a minimal opt-in helps a lot: the new settings.toml key allocates just the START segment from the internal (dma-capable) pool, while growth segments keep coming from PSRAM - allocations made early in a program run at internal-RAM speed and everything else spills over transparently. Unset (default) keeps today's behavior. An oversized request simply fails the internal allocation and falls back to the PSRAM path. The documented tradeoff: the internal pool is shared with display/audio DMA buffers, so a large segment can prevent later large DMA allocations on that board - an explicit per-device choice. --- docs/environment.rst | 18 ++++++++++++++++++ main.c | 20 +++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/docs/environment.rst b/docs/environment.rst index 4bf89bf774a..dcdf7fe886f 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -93,6 +93,24 @@ Larger values will reserve more RAM for python use and prevent the supervisor an from large allocations of their own. Smaller values will likely grow sooner than large start sizes. +CIRCUITPY_HEAP_SRAM_SIZE (integer) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +On boards where the python heap is normally placed in external PSRAM, allocate the heap's +*initial* segment (of this many bytes) from internal RAM instead. Later heap growth still +comes from PSRAM, so allocations made early in a program run at internal-RAM speed while +the total capacity is unchanged. If the requested size does not fit, the setting is +ignored and the heap starts in PSRAM as usual. Unset by default. + +When this setting is satisfied it fully defines the initial segment and +``CIRCUITPY_HEAP_START_SIZE`` is not consulted; ``CIRCUITPY_HEAP_START_SIZE`` applies +only when this setting is unset or its internal-RAM allocation fails. + +The internal pool is shared with DMA buffers (displays, audio). Buffers allocated at boot +coexist with this setting, but *re-allocating* a large buffer later (for example switching +a framebuffer display to a higher resolution at runtime) may fail, because the freed space +cannot merge across the live heap segment. With this setting, choose such sizes at boot +(e.g. via ``CIRCUITPY_DISPLAY_WIDTH``/``HEIGHT``) rather than switching at runtime. + CIRCUITPY_PYSTACK_SIZE (integer) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the size of the python stack. Must be a multiple of 4. The default value is currently 1536. diff --git a/main.c b/main.c index 2020cb8c307..f3c8148ac65 100644 --- a/main.c +++ b/main.c @@ -197,7 +197,25 @@ static void start_mp(safe_mode_t safe_mode) { #if MICROPY_ENABLE_GC size_t heap_size = 0; - _heap = _allocate_memory(safe_mode, "CIRCUITPY_HEAP_START_SIZE", CIRCUITPY_HEAP_START_SIZE, &heap_size); + // If CIRCUITPY_HEAP_SRAM_SIZE is set, try to place the heap's START segment in the + // internal (dma-capable) pool. On boards whose default heap lives in external PSRAM + // this puts early/hot allocations in fast RAM, while the heap still grows into PSRAM + // via MP_PLAT_ALLOC_HEAP. Unset (the default) keeps the current behavior; if the + // requested size does not fit the internal pool, we fall back to it as well. + #if CIRCUITPY_SETTINGS_TOML + if (safe_mode == SAFE_MODE_NONE) { + mp_int_t sram_size; + if (settings_get_int("CIRCUITPY_HEAP_SRAM_SIZE", &sram_size) == SETTINGS_OK && sram_size > 0) { + _heap = port_malloc((size_t)sram_size, true); + if (_heap != NULL) { + heap_size = (size_t)sram_size; + } + } + } + #endif + if (_heap == NULL) { + _heap = _allocate_memory(safe_mode, "CIRCUITPY_HEAP_START_SIZE", CIRCUITPY_HEAP_START_SIZE, &heap_size); + } gc_init(_heap, _heap + heap_size); #endif mp_init(); From eb61df20edcfdd7a30c47a4af4a17919ee60848f Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Tue, 4 Aug 2026 16:13:04 +0000 Subject: [PATCH 731/876] picodvi: add Framebuffer.wait_for_vblank() for tear-free full repaints (RP2350) The DMA frame-boundary IRQ now increments a frame counter, and a new Framebuffer.wait_for_vblank() blocks until the next frame boundary (bounded by a 30 ms timeout so an absent/stopped DVI signal cannot hang the caller). Call it right before a full-framebuffer repaint so the repaint starts at the top of scanout and races ahead of the beam, avoiding mid-screen tearing without a second 150 KiB framebuffer. RUN_BACKGROUND_TASKS runs inside the wait so USB host / other background work is not starved during the up-to-~16 ms spin. Opt-in (a plain method, not folded into refresh()) so it can be toggled for A/B measurement and adds nothing to the normal path; refresh() stays a no-op, so construction does not block. No-op on the RP2040 PIO-DVI backend. --- .../bindings/picodvi/Framebuffer.c | 18 ++++++++++++++ .../bindings/picodvi/Framebuffer.h | 1 + .../common-hal/picodvi/Framebuffer_RP2040.c | 5 ++++ .../common-hal/picodvi/Framebuffer_RP2350.c | 24 +++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/ports/raspberrypi/bindings/picodvi/Framebuffer.c b/ports/raspberrypi/bindings/picodvi/Framebuffer.c index 9cd66ad7e2a..e80ffea470c 100644 --- a/ports/raspberrypi/bindings/picodvi/Framebuffer.c +++ b/ports/raspberrypi/bindings/picodvi/Framebuffer.c @@ -189,9 +189,27 @@ MP_DEFINE_CONST_FUN_OBJ_1(picodvi_framebuffer_get_color_depth_obj, picodvi_frame MP_PROPERTY_GETTER(picodvi_framebuffer_color_depth_obj, (mp_obj_t)&picodvi_framebuffer_get_color_depth_obj); +//| def wait_for_vblank(self) -> None: +//| """Block until the next frame boundary (vertical blank), then return. Call this right +//| before a full-framebuffer repaint so the repaint starts at the top of scanout and races +//| ahead of the beam, avoiding tearing without a second framebuffer. The repaint must +//| complete faster than one scanout sweep (~16 ms at 60 Hz) to stay ahead of the beam; +//| if it cannot (e.g. a full 640x480 ``displayio`` refresh), use a lower resolution or +//| repaint a smaller area. Bounded by a short timeout, so it is safe even if no DVI +//| signal is active. No-op on the RP2040 PIO-DVI path.""" +//| ... +static mp_obj_t picodvi_framebuffer_wait_for_vblank(mp_obj_t self_in) { + picodvi_framebuffer_obj_t *self = (picodvi_framebuffer_obj_t *)self_in; + check_for_deinit(self); + common_hal_picodvi_framebuffer_wait_for_vblank(self); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picodvi_framebuffer_wait_for_vblank_obj, picodvi_framebuffer_wait_for_vblank); + static const mp_rom_map_elem_t picodvi_framebuffer_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&picodvi_framebuffer_deinit_obj) }, + { MP_ROM_QSTR(MP_QSTR_wait_for_vblank), MP_ROM_PTR(&picodvi_framebuffer_wait_for_vblank_obj) }, { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&picodvi_framebuffer_width_obj) }, { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&picodvi_framebuffer_height_obj) }, diff --git a/ports/raspberrypi/bindings/picodvi/Framebuffer.h b/ports/raspberrypi/bindings/picodvi/Framebuffer.h index 7eb7780ee49..d5f59fe84c3 100644 --- a/ports/raspberrypi/bindings/picodvi/Framebuffer.h +++ b/ports/raspberrypi/bindings/picodvi/Framebuffer.h @@ -25,6 +25,7 @@ void common_hal_picodvi_framebuffer_construct(picodvi_framebuffer_obj_t *self, void common_hal_picodvi_framebuffer_deinit(picodvi_framebuffer_obj_t *self); bool common_hal_picodvi_framebuffer_deinited(picodvi_framebuffer_obj_t *self); void common_hal_picodvi_framebuffer_refresh(picodvi_framebuffer_obj_t *self); +void common_hal_picodvi_framebuffer_wait_for_vblank(picodvi_framebuffer_obj_t *self); int common_hal_picodvi_framebuffer_get_width(picodvi_framebuffer_obj_t *self); int common_hal_picodvi_framebuffer_get_height(picodvi_framebuffer_obj_t *self); int common_hal_picodvi_framebuffer_get_row_stride(picodvi_framebuffer_obj_t *self); diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c index 8dddb451d96..53ed37cefbe 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2040.c @@ -364,6 +364,11 @@ bool common_hal_picodvi_framebuffer_deinited(picodvi_framebuffer_obj_t *self) { void common_hal_picodvi_framebuffer_refresh(picodvi_framebuffer_obj_t *self) { } +void common_hal_picodvi_framebuffer_wait_for_vblank(picodvi_framebuffer_obj_t *self) { + // No frame-boundary counter on the RP2040 PIO-DVI path; vblank sync is a no-op here (the + // tear-free full-repaint path is RP2350/HSTX, e.g. Fruit Jam). Present so the binding links. +} + int common_hal_picodvi_framebuffer_get_width(picodvi_framebuffer_obj_t *self) { return self->width; } diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c index 2dc19558314..3e1ea51ecb7 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c @@ -29,6 +29,7 @@ #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/time/__init__.h" +#include "supervisor/background_callback.h" #include "supervisor/port.h" #include "pico/stdlib.h" @@ -160,6 +161,11 @@ static uint32_t vactive_line720[VACTIVE_LEN] = { picodvi_framebuffer_obj_t *active_picodvi = NULL; +// Incremented once per completed frame by the DMA frame-boundary IRQ, so refresh() can block +// until the next frame starts (vblank sync). A full-framebuffer repaint that begins right after a +// frame boundary then races ahead of scanout, avoiding tearing without a second framebuffer. +static volatile uint32_t framebuffer_frame_count = 0; + static void __not_in_flash_func(dma_irq_handler)(void) { if (active_picodvi == NULL) { return; @@ -171,6 +177,7 @@ static void __not_in_flash_func(dma_irq_handler)(void) { // will trigger the pixel channel). dma_channel_hw_t *ch = &dma_hw->ch[active_picodvi->dma_command_channel]; ch->al3_read_addr_trig = (uintptr_t)active_picodvi->dma_commands; + framebuffer_frame_count++; // frame boundary: scanout has wrapped back to the top } bool common_hal_picodvi_framebuffer_preflight( @@ -625,6 +632,23 @@ bool common_hal_picodvi_framebuffer_deinited(picodvi_framebuffer_obj_t *self) { void common_hal_picodvi_framebuffer_refresh(picodvi_framebuffer_obj_t *self) { } +void common_hal_picodvi_framebuffer_wait_for_vblank(picodvi_framebuffer_obj_t *self) { + // Block until the next frame boundary (vblank). A full-framebuffer repaint issued right after + // this returns starts at the top of scanout and stays ahead of the beam, so it does not tear + // mid-screen. Bounded by a timeout so a stopped or absent DVI signal can never hang the caller. + if (self != active_picodvi) { + return; + } + uint32_t start = framebuffer_frame_count; + uint64_t deadline = common_hal_time_monotonic_ms() + 30; // ~2 frames @ 60 Hz + while (framebuffer_frame_count == start) { + RUN_BACKGROUND_TASKS; // don't starve USB host / other tasks during the ~<16 ms wait + if (common_hal_time_monotonic_ms() >= deadline) { + break; + } + } +} + int common_hal_picodvi_framebuffer_get_width(picodvi_framebuffer_obj_t *self) { return self->width; } From 073858384bd1ad383ae41d590e66fcaade4736a9 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 4 Aug 2026 12:27:17 -0500 Subject: [PATCH 732/876] disable audioeffects for pico_dv_base_w --- .../raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk index 016dd0d7269..02cbe3b69b7 100644 --- a/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_pico_dv_base_w/mpconfigboard.mk @@ -19,6 +19,7 @@ CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 CIRCUITPY_PICODVI = 1 +CIRCUITPY_AUDIOEFFECTS = 0 CIRCUITPY_AUDIOFILEWRITER = 0 CIRCUITPY_BLEIO_HCI = 0 From 5525ae9036835b0cd531841a38002d387c7ca9d7 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 4 Aug 2026 11:41:08 -0700 Subject: [PATCH 733/876] Use the zephyr specific non blocking value. libc values vary between glibc and picolibc --- ports/zephyr-cp/common-hal/socketpool/Socket.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/ports/zephyr-cp/common-hal/socketpool/Socket.c b/ports/zephyr-cp/common-hal/socketpool/Socket.c index ca8ba419839..dd2c94b0147 100644 --- a/ports/zephyr-cp/common-hal/socketpool/Socket.c +++ b/ports/zephyr-cp/common-hal/socketpool/Socket.c @@ -165,7 +165,7 @@ static bool _socketpool_socket(socketpool_socketpool_obj_t *self, } // Sockets should be nonblocking in most cases. - if (zsock_fcntl(socknum, F_SETFL, O_NONBLOCK) < 0) { + if (zsock_fcntl(socknum, F_SETFL, ZVFS_O_NONBLOCK) < 0) { // Ignore if non-blocking is unsupported. } @@ -217,15 +217,6 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, timed_out = supervisor_ticks_ms64() - start_ticks >= self->timeout_ms; } RUN_BACKGROUND_TASKS; - #if CIRCUITPY_HOSTNETWORK - if (self->timeout_ms == 0) { - struct zsock_timeval tv = { - .tv_sec = 0, - .tv_usec = 1000, - }; - zsock_setsockopt(self->num, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); - } - #endif newsoc = zsock_accept(self->num, (struct sockaddr *)&peer_addr, &socklen); // In non-blocking mode, fail instead of timing out if (newsoc == -1 && (self->timeout_ms == 0 || mp_hal_is_interrupted())) { @@ -245,7 +236,7 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, mp_obj_t *peer_out, } // We got a socket. New client socket will not be non-blocking by default, so make it non-blocking. - if (zsock_fcntl(newsoc, F_SETFL, O_NONBLOCK) < 0) { + if (zsock_fcntl(newsoc, F_SETFL, ZVFS_O_NONBLOCK) < 0) { // Ignore if non-blocking is unsupported. } From 89f7ec4536584bf89d3f1fdd9c2215ef5132456f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 4 Aug 2026 15:57:57 -0500 Subject: [PATCH 734/876] fix for usb_audio mono, descriptors, and endpoints --- shared-module/usb_audio/USBMicrophone.c | 56 +++++----- shared-module/usb_audio/USBSpeaker.c | 75 ++++++++----- shared-module/usb_audio/__init__.c | 101 +++++++++--------- .../usb_audio/usb_audio_descriptors.h | 5 + 4 files changed, 130 insertions(+), 107 deletions(-) diff --git a/shared-module/usb_audio/USBMicrophone.c b/shared-module/usb_audio/USBMicrophone.c index 9d2a46b7985..26a185ff0e9 100644 --- a/shared-module/usb_audio/USBMicrophone.c +++ b/shared-module/usb_audio/USBMicrophone.c @@ -102,24 +102,6 @@ bool common_hal_usb_audio_usbmicrophone_get_paused(usb_audio_usbmicrophone_obj_t return self->playing && self->paused; } -static inline uint32_t copy16lsb(uint32_t val) { - #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) - return __PKHBT(val, val, 16); - #else - val &= 0x0000ffff; - return val | (val << 16); - #endif -} - -static inline uint32_t copy16msb(uint32_t val) { - #if (defined(__ARM_ARCH_7EM__) && (__ARM_ARCH_7EM__ == 1)) - return __PKHTB(val, val, 16); - #else - val &= 0xffff0000; - return val | (val >> 16); - #endif -} - size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { usb_audio_usbmicrophone_obj_t *self = active_microphone; if (self == NULL || !self->playing || self->paused || self->sample == MP_OBJ_NULL) { @@ -157,23 +139,35 @@ size_t usb_audio_usbmicrophone_background_fill(uint8_t *out, size_t max_bytes) { } } - size_t n; + // Bytes written to out, and bytes consumed from the sample's chunk. They + // differ when a mono sample feeds the always-stereo USB stream. + size_t written; + size_t consumed; if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { - n = MIN(self->buffer_length, max_bytes - filled); - memcpy(out + filled, self->buffer, n); + written = consumed = MIN(self->buffer_length, max_bytes - filled); + memcpy(out + filled, self->buffer, written); } else { - n = MIN(self->buffer_length << 1, max_bytes - filled); - uint32_t *word_buffer = (uint32_t *)self->buffer; - uint32_t *word_out = (uint32_t *)(out + filled); - for (size_t i = 0; i < n / sizeof(uint32_t); i += 2) { - uint32_t v = word_buffer[i >> 1]; - word_out[i] = copy16lsb(v); - word_out[i + 1] = copy16msb(v); + // Mono source: duplicate each sample into both USB channels. Work in + // whole stereo frames so a partial frame can never be emitted, and + // cap by both what the chunk holds and what still fits in out. + size_t frames = MIN(self->buffer_length / USB_AUDIO_N_BYTES_PER_SAMPLE, + (max_bytes - filled) / USB_AUDIO_BYTES_PER_FRAME); + const int16_t *in = (const int16_t *)(const void *)self->buffer; + int16_t *dest = (int16_t *)(void *)(out + filled); + for (size_t i = 0; i < frames; i++) { + dest[2 * i] = dest[2 * i + 1] = in[i]; } + written = frames * USB_AUDIO_BYTES_PER_FRAME; + consumed = frames * USB_AUDIO_N_BYTES_PER_SAMPLE; + } + if (written == 0) { + // Less than one whole frame of room left in out (or nothing to copy): + // stop rather than spin. The caller pads the remainder with silence. + break; } - self->buffer += n; - self->buffer_length -= n; - filled += n; + self->buffer += consumed; + self->buffer_length -= consumed; + filled += written; } return filled; diff --git a/shared-module/usb_audio/USBSpeaker.c b/shared-module/usb_audio/USBSpeaker.c index 310eb3cd7d2..c04ee9b280d 100644 --- a/shared-module/usb_audio/USBSpeaker.c +++ b/shared-module/usb_audio/USBSpeaker.c @@ -37,7 +37,7 @@ void common_hal_usb_audio_usbspeaker_construct(usb_audio_usbspeaker_obj_t *self) self->base.samples_signed = true; self->base.single_buffer = false; self->base.max_buffer_length = USB_AUDIO_SPEAKER_OUTPUT_BUFFER_SIZE; - + self->ring_head = 0; self->ring_tail = 0; self->ring_count = 0; @@ -148,25 +148,43 @@ uint32_t common_hal_usb_audio_usbspeaker_read(usb_audio_usbspeaker_obj_t *self, // guard) this runs in VM/task context and can be preempted by the USB // producer, so it brackets its read-modify-write with interrupts disabled, // mirroring usb_audio_usbspeaker_background_drain(). - size_t bytes_per_frame = (self->base.bits_per_sample / 8) * self->base.channel_count; - size_t want = (size_t)length * bytes_per_frame; + // The ring holds wire-format frames (always USB_AUDIO_N_CHANNELS channels). + // `length` and the return value count entries in `buffer`, i.e. 16-bit + // samples: a stereo speaker writes one per channel of each frame, a mono one + // keeps only each frame's left channel. + bool mono = usb_audio_channel_count != USB_AUDIO_N_CHANNELS; + size_t samples_per_frame = mono ? 1 : USB_AUDIO_N_CHANNELS; + size_t want = (size_t)(length / samples_per_frame) * USB_AUDIO_BYTES_PER_FRAME; common_hal_mcu_disable_interrupts(); size_t to_copy = MIN(self->ring_count, want); // Never split a frame across calls (the ring always holds whole UAC2 frames, // but stay defensive so the returned count is always a whole number). - to_copy -= to_copy % bytes_per_frame; + to_copy -= to_copy % USB_AUDIO_BYTES_PER_FRAME; size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); - memcpy(buffer, &self->ring[self->ring_tail], first); - if (to_copy > first) { - memcpy((uint8_t *)buffer + first, &self->ring[0], to_copy - first); + if (MP_LIKELY(!mono)) { + memcpy(buffer, &self->ring[self->ring_tail], first); + if (to_copy > first) { + memcpy((uint8_t *)buffer + first, &self->ring[0], to_copy - first); + } + } else { + int16_t *word_out = (int16_t *)buffer; + const int16_t *word_ring = (const int16_t *)(const void *)self->ring; + size_t base = self->ring_tail / USB_AUDIO_N_BYTES_PER_SAMPLE; + size_t written = 0; + for (size_t i = 0; i < first / USB_AUDIO_N_BYTES_PER_SAMPLE; i += USB_AUDIO_N_CHANNELS) { + word_out[written++] = word_ring[base + i]; + } + for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_N_BYTES_PER_SAMPLE; i += USB_AUDIO_N_CHANNELS) { + word_out[written++] = word_ring[i]; + } } self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; self->ring_count -= to_copy; common_hal_mcu_enable_interrupts(); - return to_copy / bytes_per_frame; + return to_copy / USB_AUDIO_BYTES_PER_FRAME * samples_per_frame; } // --------------------------------------------------------------------+ @@ -193,42 +211,47 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker uint32_t half = self->base.max_buffer_length / 2; uint8_t *out = self->output_buffer + half * self->output_index; - int16_t *word_out = (int16_t *)out; - int16_t *word_ring = (int16_t *)self->ring; self->output_index = 1 - self->output_index; // Consumer side of the SPSC ring (runs in the output backend's refill ISR). // It is never preempted by the producer, so no interrupt guard is required. size_t to_copy = MIN(self->ring_count, (size_t)half); + // Bytes produced in out. The ring always holds wire-format (stereo) frames; + // a mono sample keeps only the left channel of each, so it produces half. + bool mono = usb_audio_channel_count != USB_AUDIO_N_CHANNELS; + size_t produced = mono ? to_copy / 2 : to_copy; + size_t first = MIN(to_copy, USB_AUDIO_SPEAKER_RING_SIZE - self->ring_tail); - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { + if (MP_LIKELY(!mono)) { memcpy(out, &self->ring[self->ring_tail], first); if (to_copy > first) { memcpy(out + first, &self->ring[0], to_copy - first); } } else { - for (size_t i = self->ring_tail / USB_AUDIO_N_BYTES_PER_SAMPLE; i < first / USB_AUDIO_N_BYTES_PER_SAMPLE; i += 2) { - word_out[i >> 1] = word_ring[i]; + // Take the left sample of each stereo frame, across up to two ring + // segments. Indices are in int16 units, counted from the segment start. + int16_t *word_out = (int16_t *)(void *)out; + const int16_t *word_ring = (const int16_t *)(const void *)self->ring; + size_t base = self->ring_tail / USB_AUDIO_N_BYTES_PER_SAMPLE; + size_t written = 0; + for (size_t i = 0; i < first / USB_AUDIO_N_BYTES_PER_SAMPLE; i += USB_AUDIO_N_CHANNELS) { + word_out[written++] = word_ring[base + i]; } - if (to_copy > first) { - for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_N_BYTES_PER_SAMPLE; i += 2) { - word_out[(first / USB_AUDIO_N_BYTES_PER_SAMPLE) + (i >> 1)] = word_ring[i]; - } + for (size_t i = 0; i < (to_copy - first) / USB_AUDIO_N_BYTES_PER_SAMPLE; i += USB_AUDIO_N_CHANNELS) { + word_out[written++] = word_ring[i]; } } self->ring_tail = (self->ring_tail + to_copy) % USB_AUDIO_SPEAKER_RING_SIZE; self->ring_count -= to_copy; - if (to_copy < half) { + // Bytes the caller will be handed, which is all a mono sample can fill. + uint32_t out_length = mono ? half / 2 : half; + if (produced < out_length) { // Underrun: pad the remainder with silence. Samples are signed, so // silence is 0. This is the consume-side of the pacing failure mode // tracked in the usb-audio-artifact-pacing memory: we never spin. - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { - memset(out + to_copy, 0, half - to_copy); - } else { - memset(out + (to_copy >> 1), 0, (half - to_copy) >> 1); - } + memset(out + produced, 0, out_length - produced); } // Computed the same way as audiocore.RawSample so stereo (interleaved ring) @@ -238,11 +261,7 @@ audioio_get_buffer_result_t usb_audio_usbspeaker_get_buffer(usb_audio_usbspeaker } *buffer = out; - if (MP_LIKELY(usb_audio_channel_count == USB_AUDIO_N_CHANNELS)) { - *buffer_length = half; - } else { - *buffer_length = half >> 1; - } + *buffer_length = out_length; // A live USB stream is infinite; never report DONE or the backend would stop. return GET_BUFFER_MORE_DATA; } diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 2a5948bb74f..2c7eda15d81 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -20,8 +20,14 @@ #include "supervisor/shared/tick.h" #include "tusb.h" -int16_t *usb_audio_mic_samples; -size_t usb_audio_mic_samples_len; +// Scratch chunk the microphone task hands to TinyUSB. It is written from the USB +// background task for as long as the device is enabled, which outlives every VM, +// so it must not live on the MicroPython heap. Statically sized for +// 1 ms at the highest rate enable() accepts, in the wire format (always +// USB_AUDIO_N_CHANNELS channels); usb_audio_mic_samples_len is the part of it +// actually used at the negotiated rate. +static int16_t usb_audio_mic_samples[USB_AUDIO_MAX_SAMPLE_RATE / 1000 * USB_AUDIO_N_CHANNELS]; +static size_t usb_audio_mic_samples_len; static bool usb_audio_is_enabled = false; @@ -53,12 +59,7 @@ bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count // One scratch chunk (1 ms at the sample rate); we loop until the FIFO reaches // the setpoint. - usb_audio_mic_samples_len = sample_rate / 1000 * channel_count * USB_AUDIO_N_BYTES_PER_SAMPLE; - usb_audio_mic_samples = (int16_t *)m_malloc_without_collect(usb_audio_mic_samples_len); - if (usb_audio_mic_samples == NULL) { - m_malloc_fail(usb_audio_mic_samples_len); - return false; - } + usb_audio_mic_samples_len = sample_rate / 1000 * USB_AUDIO_BYTES_PER_FRAME; memset(usb_audio_mic_samples, 0, usb_audio_mic_samples_len); usb_audio_sample_rate = sample_rate; @@ -179,34 +180,34 @@ void usb_audio_setup_singletons(void) { // the streaming alt-setting declares a single IN endpoint (_nEPs = 0x00). Async // feedback for true clock matching is a later step. #define USB_AUDIO_MIC_DESCRIPTOR(_itfnum, _stridx, _nBytesPerSample, _nBitsUsedPerSample, _epin, _epsize) \ - /* Standard Interface Association Descriptor (IAD) */ \ - TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ - /* Standard AC Interface Descriptor(4.7.1) */ \ - TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ - /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ - TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN + TUD_AUDIO20_DESC_INPUT_TERM_LEN + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ - /* Clock Source Descriptor(4.7.2.1) */ \ - TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ - /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ - TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ - /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ - TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ - /* Feature Unit Descriptor(4.7.2.8) */ \ - TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ - /* Standard AS Interface Descriptor(4.9.1) */ \ - /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ - TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00),\ - /* Standard AS Interface Descriptor(4.9.1) */ \ - /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ - TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00),\ - /* Class-Specific AS Interface Descriptor(4.9.2) */ \ - TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00),\ - /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ - TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ - /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ - TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t) ((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ - /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ - TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) + /* Standard Interface Association Descriptor (IAD) */ \ + TUD_AUDIO20_DESC_IAD(/*_firstitf*/ _itfnum, /*_nitfs*/ 0x02, /*_stridx*/ 0x00), \ + /* Standard AC Interface Descriptor(4.7.1) */ \ + TUD_AUDIO20_DESC_STD_AC(/*_itfnum*/ _itfnum, /*_nEPs*/ 0x00, /*_stridx*/ _stridx), \ + /* Class-Specific AC Interface Header Descriptor(4.7.2) */ \ + TUD_AUDIO20_DESC_CS_AC(/*_bcdADC*/ 0x0200, /*_category*/ AUDIO20_FUNC_MICROPHONE, /*_totallen*/ TUD_AUDIO20_DESC_CLK_SRC_LEN + TUD_AUDIO20_DESC_INPUT_TERM_LEN + TUD_AUDIO20_DESC_OUTPUT_TERM_LEN + TUD_AUDIO20_DESC_FEATURE_UNIT_LEN(2), /*_ctrl*/ AUDIO20_CS_AS_INTERFACE_CTRL_LATENCY_POS), \ + /* Clock Source Descriptor(4.7.2.1) */ \ + TUD_AUDIO20_DESC_CLK_SRC(/*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_attr*/ AUDIO20_CLOCK_SOURCE_ATT_INT_FIX_CLK, /*_ctrl*/ (AUDIO20_CTRL_R << AUDIO20_CLOCK_SOURCE_CTRL_CLK_FRQ_POS), /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00), \ + /* Input Terminal Descriptor(4.7.2.4) -- microphone */ \ + TUD_AUDIO20_DESC_INPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_IN_GENERIC_MIC, /*_assocTerm*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_nchannelslogical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_idxchannelnames*/ 0x00, /*_ctrl*/ AUDIO20_CTRL_R << AUDIO20_IN_TERM_CTRL_CONNECTOR_POS, /*_stridx*/ 0x00), \ + /* Output Terminal Descriptor(4.7.2.5) -- USB streaming */ \ + TUD_AUDIO20_DESC_OUTPUT_TERM(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_termtype*/ AUDIO_TERM_TYPE_USB_STREAMING, /*_assocTerm*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_srcid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_clkid*/ USB_AUDIO_ENTITY_CLOCK_SOURCE, /*_ctrl*/ 0x0000, /*_stridx*/ 0x00), \ + /* Feature Unit Descriptor(4.7.2.8) */ \ + TUD_AUDIO20_DESC_FEATURE_UNIT(/*_unitid*/ USB_AUDIO_ENTITY_FEATURE_UNIT, /*_srcid*/ USB_AUDIO_ENTITY_INPUT_TERMINAL, /*_stridx*/ 0x00, /*_ctrlch0master*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch1*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS, /*_ctrlch2*/ AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_MUTE_POS | AUDIO20_CTRL_RW << AUDIO20_FEATURE_UNIT_CTRL_VOLUME_POS), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 0 - default alternate setting with 0 bandwidth */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x00, /*_nEPs*/ 0x00, /*_stridx*/ 0x00), \ + /* Standard AS Interface Descriptor(4.9.1) */ \ + /* Interface 1, Alternate 1 - alternate interface for data streaming */ \ + TUD_AUDIO20_DESC_STD_AS_INT(/*_itfnum*/ (uint8_t)((_itfnum) + 1), /*_altset*/ 0x01, /*_nEPs*/ 0x01, /*_stridx*/ 0x00), \ + /* Class-Specific AS Interface Descriptor(4.9.2) */ \ + TUD_AUDIO20_DESC_CS_AS_INT(/*_termid*/ USB_AUDIO_ENTITY_OUTPUT_TERMINAL, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_formattype*/ AUDIO20_FORMAT_TYPE_I, /*_formats*/ AUDIO20_DATA_FORMAT_TYPE_I_PCM, /*_nchannelsphysical*/ USB_AUDIO_N_CHANNELS, /*_channelcfg*/ AUDIO20_CHANNEL_CONFIG_NON_PREDEFINED, /*_stridx*/ 0x00), \ + /* Type I Format Type Descriptor(2.3.1.6 - Audio Formats) */ \ + TUD_AUDIO20_DESC_TYPE_I_FORMAT(_nBytesPerSample, _nBitsUsedPerSample), \ + /* Standard AS Isochronous Audio Data Endpoint Descriptor(4.10.1.1) */ \ + TUD_AUDIO20_DESC_STD_AS_ISO_EP(/*_ep*/ _epin, /*_attr*/ (uint8_t)((uint8_t)TUSB_XFER_ISOCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_ASYNCHRONOUS | (uint8_t)TUSB_ISO_EP_ATT_DATA), /*_maxEPsize*/ _epsize, /*_interval*/ 0x01), \ + /* Class-Specific AS Isochronous Audio Data Endpoint Descriptor(4.10.1.2) */ \ + TUD_AUDIO20_DESC_CS_AS_ISO_EP(/*_attr*/ AUDIO20_CS_AS_ISO_DATA_EP_ATT_NON_MAX_PACKETS_OK, /*_ctrl*/ AUDIO20_CTRL_NONE, /*_lockdelayunit*/ AUDIO20_CS_AS_ISO_DATA_EP_LOCK_DELAY_UNIT_UNDEFINED, /*_lockdelay*/ 0x0000) // Hand-rolled UAC2 headset (microphone + speaker both enabled): one audio function // presenting both a speaker (host -> board OUT) and a microphone (board -> host @@ -314,7 +315,7 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de const uint8_t ep_in = descriptor_counts->current_endpoint + 1; usb_add_interface_string(*current_interface_string, "CircuitPython Headset"); - + const uint8_t usb_audio_descriptor[] = { USB_AUDIO_HEADSET_DESCRIPTOR( /*_itfnum*/ descriptor_counts->current_interface, @@ -331,12 +332,14 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de usb_audio_mic_as_itf = descriptor_counts->current_interface + 2; (*current_interface_string)++; - // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus - // two OUT and two IN endpoints. + // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus a + // single isochronous endpoint in each direction. The two directions take + // separate endpoint numbers (ep_out and ep_in above), so this consumes two + // of the port's endpoint pairs. descriptor_counts->current_interface += 3; - descriptor_counts->num_out_endpoints += USB_AUDIO_N_CHANNELS; - descriptor_counts->num_in_endpoints += USB_AUDIO_N_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS * 2; + descriptor_counts->num_out_endpoints += 1; + descriptor_counts->num_in_endpoints += 1; + descriptor_counts->current_endpoint += 2; memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -360,11 +363,12 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de }; (*current_interface_string)++; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two OUT endpoints. + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus a + // single isochronous OUT endpoint. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { - descriptor_counts->num_out_endpoints += USB_AUDIO_N_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS; + descriptor_counts->num_out_endpoints += 1; + descriptor_counts->current_endpoint += 1; } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); @@ -388,11 +392,12 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de }; (*current_interface_string)++; - // One IAD wrapping an AudioControl + an AudioStreaming interface, plus two IN endpoints. + // One IAD wrapping an AudioControl + an AudioStreaming interface, plus a + // single isochronous IN endpoint. descriptor_counts->current_interface += 2; if (!forced_iso_ep) { - descriptor_counts->num_in_endpoints += USB_AUDIO_N_CHANNELS; - descriptor_counts->current_endpoint += USB_AUDIO_N_CHANNELS; + descriptor_counts->num_in_endpoints += 1; + descriptor_counts->current_endpoint += 1; } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); diff --git a/shared-module/usb_audio/usb_audio_descriptors.h b/shared-module/usb_audio/usb_audio_descriptors.h index 40691a17529..8fba956a2a6 100644 --- a/shared-module/usb_audio/usb_audio_descriptors.h +++ b/shared-module/usb_audio/usb_audio_descriptors.h @@ -32,6 +32,11 @@ size_t usb_audio_descriptor_length(void); #define USB_AUDIO_N_BYTES_PER_SAMPLE (2) #define USB_AUDIO_BITS_PER_SAMPLE (USB_AUDIO_N_BYTES_PER_SAMPLE * 8) +// Bytes per audio frame on the wire. The descriptors always declare +// USB_AUDIO_N_CHANNELS channels, whatever channel_count the sample has, so this +// is the granularity every buffer handed to/from TinyUSB must be a multiple of. +#define USB_AUDIO_BYTES_PER_FRAME (USB_AUDIO_N_BYTES_PER_SAMPLE * USB_AUDIO_N_CHANNELS) + // Endpoint number for the single isochronous audio data endpoint. Most device // controllers accept an ISO endpoint on any number, so the descriptor builder // just takes the next sequential one (signalled by 0 here). The nRF52 USBD, From bbe4ec62ca99524e7ead5029016d9224315e0128 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 5 Aug 2026 09:11:54 -0500 Subject: [PATCH 735/876] rename delay_ms to min_delay_ms, remove unneeded returns --- shared-bindings/audiodelays/Flanger.c | 46 +++++++++++++-------------- shared-bindings/audiodelays/Flanger.h | 6 ++-- shared-module/audiodelays/Flanger.c | 31 ++++++++---------- shared-module/audiodelays/Flanger.h | 2 +- 4 files changed, 41 insertions(+), 44 deletions(-) diff --git a/shared-bindings/audiodelays/Flanger.c b/shared-bindings/audiodelays/Flanger.c index e582a1ecf0d..2a6a4775a40 100644 --- a/shared-bindings/audiodelays/Flanger.c +++ b/shared-bindings/audiodelays/Flanger.c @@ -23,7 +23,7 @@ //| def __init__( //| self, //| max_delay_ms: int = 10, -//| delay_ms: synthio.BlockInput = 1.0, +//| min_delay_ms: synthio.BlockInput = 1.0, //| rate: synthio.BlockInput = 0.5, //| depth: synthio.BlockInput = 0.5, //| feedback: synthio.BlockInput = 0.5, @@ -41,20 +41,20 @@ //| spectrum, and the ``feedback`` path routes the delayed signal back into the delay line //| to sharpen those notches into resonant peaks. //| -//| The delay is swept upwards from ``delay_ms`` towards ``max_delay_ms``:: +//| The delay is swept upwards from ``min_delay_ms`` towards ``max_delay_ms``:: //| -//| sweep_top = delay_ms + depth * (max_delay_ms - delay_ms) -//| current_delay = delay_ms + triangle_lfo() * (sweep_top - delay_ms) +//| sweep_top = min_delay_ms + depth * (max_delay_ms - min_delay_ms) +//| current_delay = min_delay_ms + triangle_lfo() * (sweep_top - min_delay_ms) //| //| where ``triangle_lfo()`` ranges from 0.0 to 1.0 at ``rate`` Hz. Because the sweep runs -//| upwards from a floor rather than around a centre, no combination of ``delay_ms`` and +//| upwards from a floor rather than around a centre, no combination of ``min_delay_ms`` and //| ``depth`` can push the delay outside of the buffer. //| //| //| :param int max_delay_ms: The maximum delay the flanger can sweep to in milliseconds, valid range is 1-100. -//| :param synthio.BlockInput delay_ms: The shortest delay of the sweep in milliseconds. Clamped between the length of one sample and max_delay_ms. +//| :param synthio.BlockInput min_delay_ms: The shortest delay of the sweep in milliseconds. Clamped between the length of one sample and max_delay_ms. //| :param synthio.BlockInput rate: The frequency of the sweep in hertz. Clamped between 0.0 and 20.0. A rate of 0.0 holds the delay still. -//| :param synthio.BlockInput depth: How much of the range above delay_ms is swept, from 0.0 to 1.0. +//| :param synthio.BlockInput depth: How much of the range above min_delay_ms is swept, from 0.0 to 1.0. //| :param synthio.BlockInput feedback: How much of the delayed signal is fed back into the delay line, from -0.95 to 0.95. Negative values invert the polarity of the feedback. //| :param synthio.BlockInput mix: How much of the wet audio to include along with the original signal, from 0.0 to 1.0. //| :param bool invert: Subtract the wet signal from the dry signal instead of adding it, which flips which frequencies cancel. @@ -74,7 +74,7 @@ //| //| audio = audiobusio.I2SOut(board.I2S_BIT_CLOCK, board.I2S_WS, board.I2S_DOUT) //| synth = synthio.Synthesizer(channel_count=1, sample_rate=44100) -//| flanger = audiodelays.Flanger(max_delay_ms=10, delay_ms=1.0, rate=0.3, depth=0.8, +//| flanger = audiodelays.Flanger(max_delay_ms=10, min_delay_ms=1.0, rate=0.3, depth=0.8, //| feedback=0.7, mix=1.0, buffer_size=1024, //| channel_count=1, sample_rate=44100) //| audio.play(flanger.play(synth)) @@ -88,10 +88,10 @@ //| ... //| static mp_obj_t audiodelays_flanger_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_max_delay_ms, ARG_delay_ms, ARG_rate, ARG_depth, ARG_feedback, ARG_mix, ARG_invert, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + enum { ARG_max_delay_ms, ARG_min_delay_ms, ARG_rate, ARG_depth, ARG_feedback, ARG_mix, ARG_invert, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_max_delay_ms, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 10 } }, - { MP_QSTR_delay_ms, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_min_delay_ms, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_rate, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_depth, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_feedback, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, @@ -117,7 +117,7 @@ static mp_obj_t audiodelays_flanger_make_new(const mp_obj_type_t *type, size_t n } audiodelays_flanger_obj_t *self = mp_obj_malloc(audiodelays_flanger_obj_t, &audiodelays_flanger_type); - common_hal_audiodelays_flanger_construct(self, max_delay_ms, args[ARG_delay_ms].u_obj, args[ARG_rate].u_obj, args[ARG_depth].u_obj, args[ARG_feedback].u_obj, args[ARG_mix].u_obj, args[ARG_invert].u_bool, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + common_hal_audiodelays_flanger_construct(self, max_delay_ms, args[ARG_min_delay_ms].u_obj, args[ARG_rate].u_obj, args[ARG_depth].u_obj, args[ARG_feedback].u_obj, args[ARG_mix].u_obj, args[ARG_invert].u_bool, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); return MP_OBJ_FROM_PTR(self); } @@ -156,27 +156,27 @@ static mp_obj_t audiodelays_flanger_obj___exit__(size_t n_args, const mp_obj_t * static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audiodelays_flanger___exit___obj, 4, 4, audiodelays_flanger_obj___exit__); -//| delay_ms: synthio.BlockInput +//| min_delay_ms: synthio.BlockInput //| """The shortest delay of the sweep in milliseconds. This is the floor that the sweep runs //| upwards from. Clamped between the length of a single sample and ``max_delay_ms``.""" //| -static mp_obj_t audiodelays_flanger_obj_get_delay_ms(mp_obj_t self_in) { +static mp_obj_t audiodelays_flanger_obj_get_min_delay_ms(mp_obj_t self_in) { audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); - return common_hal_audiodelays_flanger_get_delay_ms(self); + return common_hal_audiodelays_flanger_get_min_delay_ms(self); } -MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_delay_ms_obj, audiodelays_flanger_obj_get_delay_ms); +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_min_delay_ms_obj, audiodelays_flanger_obj_get_min_delay_ms); -static mp_obj_t audiodelays_flanger_obj_set_delay_ms(mp_obj_t self_in, mp_obj_t delay_ms_in) { +static mp_obj_t audiodelays_flanger_obj_set_min_delay_ms(mp_obj_t self_in, mp_obj_t min_delay_ms_in) { audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_audiodelays_flanger_set_delay_ms(self, delay_ms_in); + common_hal_audiodelays_flanger_set_min_delay_ms(self, min_delay_ms_in); return mp_const_none; } -MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_delay_ms_obj, audiodelays_flanger_obj_set_delay_ms); +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_flanger_set_min_delay_ms_obj, audiodelays_flanger_obj_set_min_delay_ms); -MP_PROPERTY_GETSET(audiodelays_flanger_delay_ms_obj, - (mp_obj_t)&audiodelays_flanger_get_delay_ms_obj, - (mp_obj_t)&audiodelays_flanger_set_delay_ms_obj); +MP_PROPERTY_GETSET(audiodelays_flanger_min_delay_ms_obj, + (mp_obj_t)&audiodelays_flanger_get_min_delay_ms_obj, + (mp_obj_t)&audiodelays_flanger_set_min_delay_ms_obj); //| rate: synthio.BlockInput //| """The frequency of the delay sweep in hertz. Clamped between 0.0 and 20.0. A rate of 0.0 @@ -199,7 +199,7 @@ MP_PROPERTY_GETSET(audiodelays_flanger_rate_obj, (mp_obj_t)&audiodelays_flanger_set_rate_obj); //| depth: synthio.BlockInput -//| """How much of the range between ``delay_ms`` and ``max_delay_ms`` the sweep covers, from +//| """How much of the range between ``min_delay_ms`` and ``max_delay_ms`` the sweep covers, from //| 0.0 to 1.0. A depth of 0.0 leaves a static short delay.""" //| static mp_obj_t audiodelays_flanger_obj_get_depth(mp_obj_t self_in) { @@ -347,7 +347,7 @@ static const mp_rom_map_elem_t audiodelays_flanger_locals_dict_table[] = { // Properties { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_flanger_playing_obj) }, - { MP_ROM_QSTR(MP_QSTR_delay_ms), MP_ROM_PTR(&audiodelays_flanger_delay_ms_obj) }, + { MP_ROM_QSTR(MP_QSTR_min_delay_ms), MP_ROM_PTR(&audiodelays_flanger_min_delay_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_rate), MP_ROM_PTR(&audiodelays_flanger_rate_obj) }, { MP_ROM_QSTR(MP_QSTR_depth), MP_ROM_PTR(&audiodelays_flanger_depth_obj) }, { MP_ROM_QSTR(MP_QSTR_feedback), MP_ROM_PTR(&audiodelays_flanger_feedback_obj) }, diff --git a/shared-bindings/audiodelays/Flanger.h b/shared-bindings/audiodelays/Flanger.h index 859beff714a..aecc9bb7b17 100644 --- a/shared-bindings/audiodelays/Flanger.h +++ b/shared-bindings/audiodelays/Flanger.h @@ -11,15 +11,15 @@ extern const mp_obj_type_t audiodelays_flanger_type; void common_hal_audiodelays_flanger_construct(audiodelays_flanger_obj_t *self, uint32_t max_delay_ms, - mp_obj_t delay_ms, mp_obj_t rate, mp_obj_t depth, mp_obj_t feedback, mp_obj_t mix, bool invert, + mp_obj_t min_delay_ms, mp_obj_t rate, mp_obj_t depth, mp_obj_t feedback, mp_obj_t mix, bool invert, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate); void common_hal_audiodelays_flanger_deinit(audiodelays_flanger_obj_t *self); bool common_hal_audiodelays_flanger_deinited(audiodelays_flanger_obj_t *self); -mp_obj_t common_hal_audiodelays_flanger_get_delay_ms(audiodelays_flanger_obj_t *self); -void common_hal_audiodelays_flanger_set_delay_ms(audiodelays_flanger_obj_t *self, mp_obj_t delay_ms); +mp_obj_t common_hal_audiodelays_flanger_get_min_delay_ms(audiodelays_flanger_obj_t *self); +void common_hal_audiodelays_flanger_set_min_delay_ms(audiodelays_flanger_obj_t *self, mp_obj_t min_delay_ms); mp_obj_t common_hal_audiodelays_flanger_get_rate(audiodelays_flanger_obj_t *self); void common_hal_audiodelays_flanger_set_rate(audiodelays_flanger_obj_t *self, mp_obj_t rate); diff --git a/shared-module/audiodelays/Flanger.c b/shared-module/audiodelays/Flanger.c index 25a0a598543..d77acf71daa 100644 --- a/shared-module/audiodelays/Flanger.c +++ b/shared-module/audiodelays/Flanger.c @@ -25,7 +25,7 @@ static uint32_t flanger_ms_to_frames_q16(audiodelays_flanger_obj_t *self, mp_flo } void common_hal_audiodelays_flanger_construct(audiodelays_flanger_obj_t *self, uint32_t max_delay_ms, - mp_obj_t delay_ms, mp_obj_t rate, mp_obj_t depth, mp_obj_t feedback, mp_obj_t mix, bool invert, + mp_obj_t min_delay_ms, mp_obj_t rate, mp_obj_t depth, mp_obj_t feedback, mp_obj_t mix, bool invert, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate) { @@ -70,10 +70,10 @@ void common_hal_audiodelays_flanger_construct(audiodelays_flanger_obj_t *self, u // The below section sets up the flanger effect's starting values. // If we did not receive a BlockInput we need to create a default float value - if (delay_ms == MP_OBJ_NULL) { - delay_ms = mp_obj_new_float(MICROPY_FLOAT_CONST(1.0)); + if (min_delay_ms == MP_OBJ_NULL) { + min_delay_ms = mp_obj_new_float(MICROPY_FLOAT_CONST(1.0)); } - synthio_block_assign_slot(delay_ms, &self->delay_ms, MP_QSTR_delay_ms); + synthio_block_assign_slot(min_delay_ms, &self->min_delay_ms, MP_QSTR_min_delay_ms); if (rate == MP_OBJ_NULL) { rate = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); @@ -133,12 +133,12 @@ void common_hal_audiodelays_flanger_deinit(audiodelays_flanger_obj_t *self) { self->buffer[1] = NULL; } -mp_obj_t common_hal_audiodelays_flanger_get_delay_ms(audiodelays_flanger_obj_t *self) { - return self->delay_ms.obj; +mp_obj_t common_hal_audiodelays_flanger_get_min_delay_ms(audiodelays_flanger_obj_t *self) { + return self->min_delay_ms.obj; } -void common_hal_audiodelays_flanger_set_delay_ms(audiodelays_flanger_obj_t *self, mp_obj_t delay_ms) { - synthio_block_assign_slot(delay_ms, &self->delay_ms, MP_QSTR_delay_ms); +void common_hal_audiodelays_flanger_set_min_delay_ms(audiodelays_flanger_obj_t *self, mp_obj_t min_delay_ms) { + synthio_block_assign_slot(min_delay_ms, &self->min_delay_ms, MP_QSTR_min_delay_ms); } mp_obj_t common_hal_audiodelays_flanger_get_rate(audiodelays_flanger_obj_t *self) { @@ -209,13 +209,10 @@ void common_hal_audiodelays_flanger_play(audiodelays_flanger_obj_t *self, mp_obj self->sample_buffer_length /= (self->base.bits_per_sample / 8); // Store if we have more data in the sample to retrieve self->more_data = result == GET_BUFFER_MORE_DATA; - - return; } void common_hal_audiodelays_flanger_stop(audiodelays_flanger_obj_t *self) { self->sample = NULL; - return; } audioio_get_buffer_result_t audiodelays_flanger_get_buffer(audiodelays_flanger_obj_t *self, bool single_channel_output, uint8_t channel, @@ -263,7 +260,7 @@ audioio_get_buffer_result_t audiodelays_flanger_get_buffer(audiodelays_flanger_o if (self->sample == NULL) { // tick all block inputs so that anything attached to them stays in sync shared_bindings_synthio_lfo_tick(self->base.sample_rate, length / channel_count); - (void)synthio_block_slot_get(&self->delay_ms); + (void)synthio_block_slot_get(&self->min_delay_ms); (void)synthio_block_slot_get(&self->rate); (void)synthio_block_slot_get(&self->depth); (void)synthio_block_slot_get(&self->feedback); @@ -294,16 +291,16 @@ audioio_get_buffer_result_t audiodelays_flanger_get_buffer(audiodelays_flanger_o // get the effect values we need from the BlockInput shared_bindings_synthio_lfo_tick(self->base.sample_rate, num_bytes / channel_count); - mp_float_t f_delay_ms = synthio_block_slot_get_limited(&self->delay_ms, self->sample_ms, (mp_float_t)self->max_delay_ms); + mp_float_t f_min_delay_ms = synthio_block_slot_get_limited(&self->min_delay_ms, self->sample_ms, (mp_float_t)self->max_delay_ms); mp_float_t f_rate = synthio_block_slot_get_limited(&self->rate, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(20.0)); mp_float_t f_depth = synthio_block_slot_get_limited(&self->depth, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); int32_t feedback = (int32_t)(synthio_block_slot_get_limited(&self->feedback, MICROPY_FLOAT_CONST(-0.95), MICROPY_FLOAT_CONST(0.95)) * 32767); int32_t mix = (int32_t)(synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)) * 32767); - // The sweep runs upward from delay_ms towards max_delay_ms rather than around a - // centre, so no combination of delay_ms and depth can push it out of the delay line. - mp_float_t sweep_top_ms = f_delay_ms + f_depth * ((mp_float_t)self->max_delay_ms - f_delay_ms); - uint32_t delay_min_q16 = flanger_ms_to_frames_q16(self, f_delay_ms); + // The sweep runs upward from min_delay_ms towards max_delay_ms rather than around a + // centre, so no combination of min_delay_ms and depth can push it out of the delay line. + mp_float_t sweep_top_ms = f_min_delay_ms + f_depth * ((mp_float_t)self->max_delay_ms - f_min_delay_ms); + uint32_t delay_min_q16 = flanger_ms_to_frames_q16(self, f_min_delay_ms); uint32_t delay_span_q16 = flanger_ms_to_frames_q16(self, sweep_top_ms) - delay_min_q16; // How far the LFO advances each frame. A rate at or above half the sample rate is diff --git a/shared-module/audiodelays/Flanger.h b/shared-module/audiodelays/Flanger.h index 825f56d077b..6e8a37f51e2 100644 --- a/shared-module/audiodelays/Flanger.h +++ b/shared-module/audiodelays/Flanger.h @@ -16,7 +16,7 @@ typedef struct { audiosample_base_t base; // Effect parameters. - synthio_block_slot_t delay_ms; // floor of the sweep + synthio_block_slot_t min_delay_ms; // floor of the sweep synthio_block_slot_t rate; // LFO frequency in Hz synthio_block_slot_t depth; // 0 to 1, portion of the available range swept synthio_block_slot_t feedback; // -0.95 to 0.95, regeneration From 305dfe168f19f639de8d1d38fa839d58f0b55062 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 5 Aug 2026 09:45:32 -0500 Subject: [PATCH 736/876] lfo_value property --- shared-bindings/audiodelays/Flanger.c | 16 ++++++++++++++++ shared-bindings/audiodelays/Flanger.h | 2 ++ shared-module/audiodelays/Flanger.c | 19 ++++++++++++++----- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/shared-bindings/audiodelays/Flanger.c b/shared-bindings/audiodelays/Flanger.c index 2a6a4775a40..7c16e164944 100644 --- a/shared-bindings/audiodelays/Flanger.c +++ b/shared-bindings/audiodelays/Flanger.c @@ -281,6 +281,21 @@ MP_PROPERTY_GETSET(audiodelays_flanger_invert_obj, (mp_obj_t)&audiodelays_flanger_get_invert_obj, (mp_obj_t)&audiodelays_flanger_set_invert_obj); +//| lfo_value: float +//| """The current value of the internal LFO that sweeps the delay time, from 0.0 at +//| `min_delay_ms` to 1.0 at the top of the sweep. The LFO only advances while audio is being +//| played. (read-only)""" +//| +static mp_obj_t audiodelays_flanger_obj_get_lfo_value(mp_obj_t self_in) { + audiodelays_flanger_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return mp_obj_new_float(common_hal_audiodelays_flanger_get_lfo_value(self)); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_flanger_get_lfo_value_obj, audiodelays_flanger_obj_get_lfo_value); + +MP_PROPERTY_GETTER(audiodelays_flanger_lfo_value_obj, + (mp_obj_t)&audiodelays_flanger_get_lfo_value_obj); + //| playing: bool //| """True when the effect is playing a sample. (read-only)""" //| @@ -353,6 +368,7 @@ static const mp_rom_map_elem_t audiodelays_flanger_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_feedback), MP_ROM_PTR(&audiodelays_flanger_feedback_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_flanger_mix_obj) }, { MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&audiodelays_flanger_invert_obj) }, + { MP_ROM_QSTR(MP_QSTR_lfo_value), MP_ROM_PTR(&audiodelays_flanger_lfo_value_obj) }, AUDIOSAMPLE_FIELDS, }; static MP_DEFINE_CONST_DICT(audiodelays_flanger_locals_dict, audiodelays_flanger_locals_dict_table); diff --git a/shared-bindings/audiodelays/Flanger.h b/shared-bindings/audiodelays/Flanger.h index aecc9bb7b17..f139e842dbd 100644 --- a/shared-bindings/audiodelays/Flanger.h +++ b/shared-bindings/audiodelays/Flanger.h @@ -33,6 +33,8 @@ void common_hal_audiodelays_flanger_set_feedback(audiodelays_flanger_obj_t *self mp_obj_t common_hal_audiodelays_flanger_get_mix(audiodelays_flanger_obj_t *self); void common_hal_audiodelays_flanger_set_mix(audiodelays_flanger_obj_t *self, mp_obj_t arg); +mp_float_t common_hal_audiodelays_flanger_get_lfo_value(audiodelays_flanger_obj_t *self); + bool common_hal_audiodelays_flanger_get_invert(audiodelays_flanger_obj_t *self); void common_hal_audiodelays_flanger_set_invert(audiodelays_flanger_obj_t *self, bool invert); diff --git a/shared-module/audiodelays/Flanger.c b/shared-module/audiodelays/Flanger.c index d77acf71daa..f0d1bb1e33f 100644 --- a/shared-module/audiodelays/Flanger.c +++ b/shared-module/audiodelays/Flanger.c @@ -173,6 +173,19 @@ void common_hal_audiodelays_flanger_set_mix(audiodelays_flanger_obj_t *self, mp_ synthio_block_assign_slot(arg, &self->mix, MP_QSTR_mix); } +// Fold the sawtooth phase accumulator into a triangle in the range 0 to 65535 +static uint32_t flanger_phase_to_triangle(uint32_t phase) { + uint32_t tri = phase >> 15; + if (tri > 65535) { + tri = 131071 - tri; + } + return tri; +} + +mp_float_t common_hal_audiodelays_flanger_get_lfo_value(audiodelays_flanger_obj_t *self) { + return (mp_float_t)flanger_phase_to_triangle(self->lfo_phase[0]) / MICROPY_FLOAT_CONST(65535.0); +} + bool common_hal_audiodelays_flanger_get_invert(audiodelays_flanger_obj_t *self) { return self->invert; } @@ -328,11 +341,7 @@ audioio_get_buffer_result_t audiodelays_flanger_get_buffer(audiodelays_flanger_o // accumulators step once per frame) or one channel per call. self->lfo_phase[right_channel] += self->lfo_phase_inc; - // Fold the sawtooth phase into a triangle in the range 0 to 65535 - uint32_t tri = self->lfo_phase[right_channel] >> 15; - if (tri > 65535) { - tri = 131071 - tri; - } + uint32_t tri = flanger_phase_to_triangle(self->lfo_phase[right_channel]); // The delay for this frame, in Q16.16 frames uint32_t delay_q16 = delay_min_q16 + (uint32_t)(((uint64_t)delay_span_q16 * tri) >> 16); From abb6a8b9fa3bbefad17a624ce629e4fc7ccda6d0 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 5 Aug 2026 10:31:55 -0500 Subject: [PATCH 737/876] remove i2sin invert_bit_clock argument, update comment for left_justified change --- ports/espressif/common-hal/audioi2sin/I2SIn.c | 2 +- .../raspberrypi/common-hal/audioi2sin/I2SIn.c | 22 ++++++++----------- shared-bindings/audioi2sin/I2SIn.c | 14 ++---------- shared-bindings/audioi2sin/I2SIn.h | 2 +- 4 files changed, 13 insertions(+), 27 deletions(-) diff --git a/ports/espressif/common-hal/audioi2sin/I2SIn.c b/ports/espressif/common-hal/audioi2sin/I2SIn.c index 6da790d9736..9a85d11f493 100644 --- a/ports/espressif/common-hal/audioi2sin/I2SIn.c +++ b/ports/espressif/common-hal/audioi2sin/I2SIn.c @@ -25,7 +25,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, bool mono, bool left_justified, bool samples_signed, - bool external_clock, bool invert_bit_clock) { + bool external_clock) { if (external_clock) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); } diff --git a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c index 0032e6fd7be..bb0b0204111 100644 --- a/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c +++ b/ports/raspberrypi/common-hal/audioi2sin/I2SIn.c @@ -212,11 +212,10 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { // a 32-BCLK frame is one push (right<<16 | left), at 24/32 a 64-BCLK frame is // two pushes (right then left). // -// The resync's own `wait 0/1 gpio B` already lands on the first data bit, so -// against a CircuitPython clock source this program recovers the transmitted word -// bit-exactly with no instruction for the Philips delay bit. The -// `left_justified` variant is that program plus one more BCLK of skew, -// the other of the two possible alignments; +// The WS resync lands on the first data bit, so the program above is +// the `left_justified` alignment: data starts on the WS edge and no instruction +// is spent on a delay bit. The default (Philips) alignment is that program plus +// one more BCLK of skew, the other of the two possible alignments. // // Free-running after the initial sync: the external frame must be exactly // 2 x bits_per_channel BCLKs, the same assumption internal clock mode already bakes @@ -226,12 +225,9 @@ static const uint16_t i2sin_program_left_justified_swap_32[] = { #define I2SIN_EXT_CLOCK_WRAP_TARGET(len) ((int)(len) - 5) static size_t build_i2sin_ext_clock_program(uint16_t *prog, uint8_t bclk, uint8_t ws, - bool left_justified, bool invert_bit_clock) { - // Sampling on the falling edge of BCLK is the same program with the - // polarity of every BCLK wait flipped. - const uint16_t invert = invert_bit_clock ? 0x0080 : 0x0000; - const uint16_t wait_0_bclk = (0x2000 | bclk) ^ invert; - const uint16_t wait_1_bclk = (0x2080 | bclk) ^ invert; + bool left_justified) { + const uint16_t wait_0_bclk = 0x2000 | bclk; + const uint16_t wait_1_bclk = 0x2080 | bclk; size_t len = 0; prog[len++] = 0x2000 | ws; // wait 0 gpio W prog[len++] = 0x2080 | ws; // wait 1 gpio W @@ -262,7 +258,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, bool mono, bool left_justified, bool samples_signed, - bool external_clock, bool invert_bit_clock) { + bool external_clock) { if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); @@ -295,7 +291,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, program_len = build_i2sin_ext_clock_program(ext_clock_program, i2s_wait_gpio_index(bit_clock, gpio_offset), i2s_wait_gpio_index(word_select, gpio_offset), - left_justified, invert_bit_clock); + left_justified); program = ext_clock_program; wait_gpio_mask = PIO_PINMASK_OR(PIO_PINMASK_FROM_PIN(bit_clock->number), PIO_PINMASK_FROM_PIN(word_select->number)); diff --git a/shared-bindings/audioi2sin/I2SIn.c b/shared-bindings/audioi2sin/I2SIn.c index ad369574c68..22f1fb2aaad 100644 --- a/shared-bindings/audioi2sin/I2SIn.c +++ b/shared-bindings/audioi2sin/I2SIn.c @@ -35,7 +35,6 @@ //| left_justified: bool = False, //| samples_signed: bool = True, //| external_clock: bool = False, -//| invert_bit_clock: bool = False, //| ) -> None: //| """Create an I2SIn object associated with the given pins. This allows you to //| record audio signals from an external I2S source (e.g. an I2S MEMS microphone @@ -95,9 +94,6 @@ //| declaration rather than a measurement: the real rate is whatever the external word select //| runs at, and `sample_rate` still reports the declared value. If the incoming clock stops, //| `record` blocks (interruptible with Ctrl-C). -//| :param bool invert_bit_clock: Sample ``data`` on the falling edge of ``bit_clock`` instead of -//| the rising edge. Needed when the external clock source drives its data on the rising edge. -//| Only valid together with ``external_clock``. //| //| Example, recording 16-bit mono samples from an INMP441:: //| @@ -121,7 +117,7 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar enum { ARG_bit_clock, ARG_word_select, ARG_data, ARG_main_clock, ARG_sample_rate, ARG_bit_depth, ARG_output_bit_depth, ARG_mono, ARG_left_justified, ARG_samples_signed, - ARG_external_clock, ARG_invert_bit_clock }; + ARG_external_clock }; static const mp_arg_t allowed_args[] = { { MP_QSTR_bit_clock, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_word_select, MP_ARG_REQUIRED | MP_ARG_OBJ }, @@ -134,17 +130,11 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar { MP_QSTR_left_justified, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_samples_signed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, { MP_QSTR_external_clock, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_invert_bit_clock, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, }; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); bool external_clock = args[ARG_external_clock].u_bool; - bool invert_bit_clock = args[ARG_invert_bit_clock].u_bool; - if (invert_bit_clock && !external_clock) { - mp_raise_ValueError_varg(MP_ERROR_TEXT("%q requires %q"), - MP_QSTR_invert_bit_clock, MP_QSTR_external_clock); - } // In external clock mode the clock pins are only read, so they may already // be owned by whatever is driving them; let the port decide if the sharing @@ -181,7 +171,7 @@ static mp_obj_t audioi2sin_i2sin_make_new(const mp_obj_type_t *type, size_t n_ar audioi2sin_i2sin_obj_t *self = mp_obj_malloc_with_finaliser(audioi2sin_i2sin_obj_t, &audioi2sin_i2sin_type); common_hal_audioi2sin_i2sin_construct(self, bit_clock, word_select, data, main_clock, sample_rate, bit_depth, output_bit_depth, mono, left_justified, samples_signed, - external_clock, invert_bit_clock); + external_clock); return MP_OBJ_FROM_PTR(self); #endif diff --git a/shared-bindings/audioi2sin/I2SIn.h b/shared-bindings/audioi2sin/I2SIn.h index 7877653858f..25f5489015d 100644 --- a/shared-bindings/audioi2sin/I2SIn.h +++ b/shared-bindings/audioi2sin/I2SIn.h @@ -21,7 +21,7 @@ void common_hal_audioi2sin_i2sin_construct(audioi2sin_i2sin_obj_t *self, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, uint32_t sample_rate, uint8_t bit_depth, uint8_t output_bit_depth, bool mono, bool left_justified, bool samples_signed, - bool external_clock, bool invert_bit_clock); + bool external_clock); void common_hal_audioi2sin_i2sin_deinit(audioi2sin_i2sin_obj_t *self); bool common_hal_audioi2sin_i2sin_deinited(audioi2sin_i2sin_obj_t *self); uint32_t common_hal_audioi2sin_i2sin_record_to_buffer(audioi2sin_i2sin_obj_t *self, From c4f7bd08400b0a18805ff4d9f252917a07083d6f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 5 Aug 2026 15:12:08 -0700 Subject: [PATCH 738/876] Enable more extmods --- .../autogen_board_info.toml | 6 ++++ .../autogen_board_info.toml | 6 ++++ .../autogen_board_info.toml | 6 ++++ .../native/native_sim/autogen_board_info.toml | 6 ++++ .../nrf5340bsim/autogen_board_info.toml | 6 ++++ .../nordic/nrf5340dk/autogen_board_info.toml | 6 ++++ .../nordic/nrf54h20dk/autogen_board_info.toml | 6 ++++ .../nordic/nrf54l15dk/autogen_board_info.toml | 6 ++++ .../nrf54l15tag/autogen_board_info.toml | 6 ++++ .../nrf54lm20dk/autogen_board_info.toml | 6 ++++ .../nordic/nrf7002dk/autogen_board_info.toml | 6 ++++ .../boards/nrf54h20dk_nrf54h20_cpuapp.overlay | 8 ++++++ .../nxp/frdm_mcxn947/autogen_board_info.toml | 6 ++++ .../nxp/frdm_rw612/autogen_board_info.toml | 6 ++++ .../mimxrt1170_evk/autogen_board_info.toml | 6 ++++ .../autogen_board_info.toml | 6 ++++ .../rpi_pico2_zephyr/autogen_board_info.toml | 6 ++++ .../rpi_pico_w_zephyr/autogen_board_info.toml | 6 ++++ .../rpi_pico_zephyr/autogen_board_info.toml | 6 ++++ .../da14695_dk_usb/autogen_board_info.toml | 6 ++++ .../renesas/ek_ra6m5/autogen_board_info.toml | 6 ++++ .../renesas/ek_ra8d1/autogen_board_info.toml | 6 ++++ .../nucleo_n657x0_q/autogen_board_info.toml | 6 ++++ .../nucleo_u575zi_q/autogen_board_info.toml | 6 ++++ .../st/stm32h750b_dk/autogen_board_info.toml | 6 ++++ .../st/stm32h7b3i_dk/autogen_board_info.toml | 6 ++++ .../stm32wba65i_dk1/autogen_board_info.toml | 6 ++++ .../zephyr-cp/cptools/build_circuitpython.py | 28 ++++++++++++++++++- 28 files changed, 191 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml index f0e267fbde6..eef096756e7 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index a7dcae5448b..187017cb12e 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index 73bc9bd92e8..41c4c1dda5e 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index bedaad4370d..1f0486920fb 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index 34dacd251dc..dc9608542f6 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index e7864b79ddc..4d4ce0fce98 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 56b281cbf1d..6fdd16a7732 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml index 78267407579..51551341199 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15dk/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml index 7a0a3a145db..8c19b7801b5 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54l15tag/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml index f3b6554194e..58a5074f733 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index d7b4b28b4d6..b76316687f6 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false zlib = false +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay index a70eede551e..10df6b9f282 100644 --- a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay @@ -44,4 +44,12 @@ status = "okay"; }; +/* Remove slot1 (OTA), expand slot0 to use the space. + * CircuitPython doesn't use OTA updates. */ +&slot0_partition { + reg = <0x40000 DT_SIZE_K(656)>; +}; + +/delete-node/ &slot1_partition; + #include "../app.overlay" diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 258448a3e11..05233a43246 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 9a7c60fd6f7..13d5bdf8971 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index 90ebfee6da5..ba521087358 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index f71b1f11f0d..8f89598c426 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index 98b8133dd1b..a536de71e7b 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index 49b1f58b87f..5a156b1c37b 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = true # Zephyr board has wifi zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index c3174075c89..1a3912156b9 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index 251385b99d8..ef56e12139a 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index b31333b9067..390fc8a3925 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index f6bfd40c0e7..93ddc67c013 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 5963859bcaf..92cdc6137f5 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 11f10b2590d..199909fbd6d 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml index f2dc207a69c..3f83a46ec58 100644 --- a/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h750b_dk/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index 993afe00a32..eb808e08111 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = true # Zephyr board has zephyr_display zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index b3866957c88..11136930e27 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index b7334402b74..4d446596651 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -67,10 +67,18 @@ "adafruit_bus_device", "getpass", "storage", + "binascii", + "re", + "asyncio", + "select", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] +# extmod-based modules that should appear in the autogen list even though they +# don't have shared-bindings/ or bindings/ directories. +EXTMOD_MODULES = ["asyncio", "binascii", "json", "re", "select"] + # List of other modules (the value) that can be enabled when another one (the key) is. REVERSE_DEPENDENCIES = { "audiobusio": ["audiocore"], @@ -343,7 +351,7 @@ def determine_enabled_modules(board_info, portdir, srcdir): return enabled_modules, module_reasons -async def build_circuitpython(): +async def build_circuitpython(): # noqa: C901 circuitpython_flags = ["-DCIRCUITPY"] port_flags = [] enable_mpy_native = False @@ -362,6 +370,10 @@ async def build_circuitpython(): circuitpython_flags.append(f"-DCIRCUITPY_ENABLE_MPY_NATIVE={1 if enable_mpy_native else 0}") circuitpython_flags.append(f"-DCIRCUITPY_FULL_BUILD={1 if full_build else 0}") circuitpython_flags.append(f"-DCIRCUITPY_SETTINGS_TOML={1 if full_build else 0}") + circuitpython_flags.append(f"-DMICROPY_PY_ASYNC_AWAIT={1 if full_build else 0}") + circuitpython_flags.append(f"-DMICROPY_PY_ASYNCIO={1 if full_build else 0}") + circuitpython_flags.append(f"-DMICROPY_PY_SELECT={1 if full_build else 0}") + circuitpython_flags.append(f"-DMICROPY_PY_SELECT_SELECT={1 if full_build else 0}") circuitpython_flags.append("-DCIRCUITPY_STATUS_BAR=1") circuitpython_flags.append(f"-DCIRCUITPY_USB_HOST={1 if usb_host else 0}") circuitpython_flags.append(f"-DCIRCUITPY_BOARD_ID='\"{board}\"'") @@ -434,6 +446,10 @@ async def build_circuitpython(): supervisor_source = [ "main.c", "extmod/modjson.c", + "extmod/modbinascii.c", + "extmod/modre.c", + "extmod/modasyncio.c", + "extmod/modselect.c", "extmod/vfs_fat.c", "lib/tlsf/tlsf.c", portdir / "background.c", @@ -592,6 +608,16 @@ async def build_circuitpython(): logger.warning( f"autogen_board_info.toml is missing or out of date. Please run `make BOARD={board}` locally and commit {autogen_board_info_fn}." ) + autogen_modules.add(tomlkit.comment("extmod modules shared with MicroPython")) + for extmod_module in EXTMOD_MODULES: + enabled = extmod_module in enabled_modules + v = tomlkit.item(enabled) + if extmod_module in module_reasons: + v.comment(module_reasons[extmod_module]) + autogen_modules.add(extmod_module, v) + flag_name = MODULE_FLAG_NAMES.get(extmod_module, extmod_module.upper()) + circuitpython_flags.append(f"-DCIRCUITPY_{flag_name}={1 if enabled else 0}") + if autogen_board_info_fn.parent.exists(): autogen_board_info_fn.write_text(tomlkit.dumps(autogen_board_info)) From ed691eb644f7d703e44c35d15e1e4b6346bcd229 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 4 Mar 2026 10:20:52 -0800 Subject: [PATCH 739/876] Implement GATT for Zephyr _bleio Tested with BSIM and on nRF54LM20DK. CharacteristicBuffer and PacketBuffer are implemented as well. This hasn't been tested for BLE workflow so it may need allocation tweaks. Includes many other small fixes: * bsim tests are done with nRF54LM20bsim too. * bsim exe binaries are saved. * nRF7002DK loses bleio because it doesn't have space. * Other boards have their slot1 removed in favor of slot0 growing. * Fix UUID length and byte order issues. * Remove extra common_hal function for remote services. Code gen by DeepSeek V4 Pro. All prompted and reviewed by me. This is a bunch of work towards #9904, implementing _bleio. Pairing and bonding remains. --- locale/circuitpython.pot | 6 + ports/zephyr-cp/Kconfig | 6 + ports/zephyr-cp/boards/board_aliases.cmake | 1 + ports/zephyr-cp/boards/da14695_dk_usb.overlay | 8 + ports/zephyr-cp/boards/frdm_rw612.conf | 2 +- .../native/native_sim/circuitpython.toml | 2 +- .../native/nrf5340bsim/circuitpython.toml | 2 +- .../nrf54lm20bsim/autogen_board_info.toml | 123 +++ .../native/nrf54lm20bsim/circuitpython.toml | 1 + .../nordic/nrf7002dk/autogen_board_info.toml | 2 +- .../boards/nrf5340bsim_nrf5340_cpuapp.conf | 19 +- .../boards/nrf5340dk_nrf5340_cpuapp.overlay | 8 + .../nrf54lm20bsim_nrf54lm20a_cpuapp.conf | 19 + .../nrf54lm20bsim_nrf54lm20a_cpuapp.overlay | 30 + .../boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf | 21 +- .../nrf54lm20dk_nrf54lm20a_cpuapp.overlay | 7 + .../boards/nrf7002dk_nrf5340_cpuapp.conf | 1 + .../boards/nrf7002dk_nrf5340_cpuapp.overlay | 14 + ports/zephyr-cp/boards/stm32wba65i_dk1.conf | 18 +- ports/zephyr-cp/common-hal/_bleio/Adapter.c | 1 - .../common-hal/_bleio/Characteristic.c | 341 +++++++- .../common-hal/_bleio/Characteristic.h | 23 + .../common-hal/_bleio/CharacteristicBuffer.c | 127 ++- .../common-hal/_bleio/CharacteristicBuffer.h | 12 +- .../zephyr-cp/common-hal/_bleio/Connection.c | 478 ++++++++++- .../zephyr-cp/common-hal/_bleio/Descriptor.c | 89 +- .../zephyr-cp/common-hal/_bleio/Descriptor.h | 7 + .../common-hal/_bleio/PacketBuffer.c | 388 ++++++++- .../common-hal/_bleio/PacketBuffer.h | 27 +- ports/zephyr-cp/common-hal/_bleio/Service.c | 232 +++++- ports/zephyr-cp/common-hal/_bleio/Service.h | 9 + ports/zephyr-cp/common-hal/_bleio/UUID.c | 30 +- ports/zephyr-cp/common-hal/_bleio/UUID.h | 5 +- ports/zephyr-cp/common-hal/_bleio/__init__.c | 133 ++- ports/zephyr-cp/common-hal/_bleio/__init__.h | 34 +- .../zephyr-cp/cptools/build_circuitpython.py | 2 +- ports/zephyr-cp/debug.conf | 10 +- ports/zephyr-cp/prj.conf | 8 +- ports/zephyr-cp/tests/bsim/__init__.py | 3 - ports/zephyr-cp/tests/bsim/conftest.py | 68 +- .../central_battery_client/CMakeLists.txt | 9 + .../samples/central_battery_client/prj.conf | 4 + .../samples/central_battery_client/src/main.c | 212 +++++ .../samples/central_nus_client/CMakeLists.txt | 9 + .../bsim/samples/central_nus_client/prj.conf | 4 + .../samples/central_nus_client/src/main.c | 302 +++++++ .../zephyr-cp/tests/bsim/test_bsim_basics.py | 34 +- .../tests/bsim/test_bsim_ble_adapter.py | 140 ++++ .../tests/bsim/test_bsim_ble_advertising.py | 12 +- .../tests/bsim/test_bsim_ble_connect.py | 3 +- .../tests/bsim/test_bsim_ble_descriptor.py | 131 +++ .../tests/bsim/test_bsim_ble_name.py | 3 +- .../zephyr-cp/tests/bsim/test_bsim_ble_nus.py | 177 ++++ .../tests/bsim/test_bsim_ble_packet_buffer.py | 785 ++++++++++++++++++ .../tests/bsim/test_bsim_ble_peripheral.py | 3 +- .../tests/bsim/test_bsim_ble_scan.py | 77 +- .../tests/bsim/test_bsim_ble_service.py | 710 ++++++++++++++++ .../tests/bsim/test_bsim_ble_uuid.py | 331 ++++++++ ports/zephyr-cp/tests/conftest.py | 21 +- shared-bindings/_bleio/__init__.h | 1 - 60 files changed, 5070 insertions(+), 215 deletions(-) create mode 100644 ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/native/nrf54lm20bsim/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf create mode 100644 ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay create mode 100644 ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.overlay create mode 100644 ports/zephyr-cp/tests/bsim/samples/central_battery_client/CMakeLists.txt create mode 100644 ports/zephyr-cp/tests/bsim/samples/central_battery_client/prj.conf create mode 100644 ports/zephyr-cp/tests/bsim/samples/central_battery_client/src/main.c create mode 100644 ports/zephyr-cp/tests/bsim/samples/central_nus_client/CMakeLists.txt create mode 100644 ports/zephyr-cp/tests/bsim/samples/central_nus_client/prj.conf create mode 100644 ports/zephyr-cp/tests/bsim/samples/central_nus_client/src/main.c create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_adapter.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_uuid.py diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index dbd6d902194..38d498312ad 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1200,6 +1200,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c msgid "No CCCD for this Characteristic" msgstr "" @@ -1222,11 +1223,13 @@ msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Writes not supported on Characteristic" msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Total data to write is larger than %q" msgstr "" @@ -1241,6 +1244,9 @@ msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" msgstr "" diff --git a/ports/zephyr-cp/Kconfig b/ports/zephyr-cp/Kconfig index 8cce3c242fc..498d2d92abf 100644 --- a/ports/zephyr-cp/Kconfig +++ b/ports/zephyr-cp/Kconfig @@ -81,3 +81,9 @@ config BT_BUF_ACL_RX_COUNT_EXTRA config BT_BUF_ACL_RX_SIZE default 255 + +config BT_GATT_DYNAMIC_DB + default y + +config BT_GATT_CLIENT + default y diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index 6a7c357ab9d..548070279c2 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -35,6 +35,7 @@ cp_board_alias(renesas_ek_ra8d1 ek_ra8d1) cp_board_alias(renesas_da14695_dk_usb da14695_dk_usb) cp_board_alias(native_native_sim native_sim/native) cp_board_alias(native_nrf5340bsim nrf5340bsim/nrf5340/cpuapp) +cp_board_alias(native_nrf54lm20bsim nrf54lm20bsim/nrf54lm20a/cpuapp) cp_board_alias(nordic_nrf54l15dk nrf54l15dk/nrf54l15/cpuapp) cp_board_alias(nordic_nrf54l15tag nrf54l15tag/nrf54l15/cpuapp) cp_board_alias(nordic_nrf54lm20dk nrf54lm20dk/nrf54lm20a/cpuapp) diff --git a/ports/zephyr-cp/boards/da14695_dk_usb.overlay b/ports/zephyr-cp/boards/da14695_dk_usb.overlay index 8ad8198db0a..cc3b33ec447 100644 --- a/ports/zephyr-cp/boards/da14695_dk_usb.overlay +++ b/ports/zephyr-cp/boards/da14695_dk_usb.overlay @@ -1,3 +1,11 @@ +/* Remove slot1 (OTA), expand slot0 to use the space. + * CircuitPython doesn't use OTA updates. */ +&slot0_partition { + reg = <0x00010000 DT_SIZE_K(1024)>; +}; + +/delete-node/ &slot1_partition; + &flash0 { partitions{ circuitpy_partition: partition@118000 { diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/frdm_rw612.conf index 2f7f43dcbef..f8d1dfa0ad6 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.conf +++ b/ports/zephyr-cp/boards/frdm_rw612.conf @@ -19,7 +19,7 @@ CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y CONFIG_MBEDTLS_ENTROPY_C=y CONFIG_MBEDTLS_CTR_DRBG_C=y -# Override bt.conf default +# Override Kconfig default (3) CONFIG_BT_BUF_ACL_TX_COUNT=8 CONFIG_UDC_WORKQUEUE_STACK_SIZE=1024 diff --git a/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml index fbda7c563b8..7177c825f17 100644 --- a/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml +++ b/ports/zephyr-cp/boards/native/native_sim/circuitpython.toml @@ -1 +1 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf", "exe"] +CIRCUITPY_BUILD_EXTENSIONS = ["exe"] diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml index 3272dd4c5f3..7177c825f17 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/circuitpython.toml @@ -1 +1 @@ -CIRCUITPY_BUILD_EXTENSIONS = ["elf"] +CIRCUITPY_BUILD_EXTENSIONS = ["exe"] diff --git a/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml new file mode 100644 index 00000000000..6a3ea5b39d5 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml @@ -0,0 +1,123 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "POSIX/Native Boards nRF54LM20 simulated boards (BabbleSim)" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = false +zephyr_kernel = false +zlib = true diff --git a/ports/zephyr-cp/boards/native/nrf54lm20bsim/circuitpython.toml b/ports/zephyr-cp/boards/native/nrf54lm20bsim/circuitpython.toml new file mode 100644 index 00000000000..7177c825f17 --- /dev/null +++ b/ports/zephyr-cp/boards/native/nrf54lm20bsim/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["exe"] diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index b76316687f6..3f72b515853 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -3,7 +3,7 @@ name = "Nordic Semiconductor nRF7002 DK" [modules] __future__ = true -_bleio = true # Zephyr board has _bleio +_bleio = false _eve = false _pew = false _pixelmap = false diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf index 57628a61e20..2579bf28d67 100644 --- a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf @@ -4,26 +4,11 @@ CONFIG_GPIO=y # Enable Bluetooth stack - bsim is for BT simulation -CONFIG_BT=y CONFIG_BT_HCI=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_BROADCASTER=y - -CONFIG_BT_L2CAP_TX_MTU=253 -CONFIG_BT_BUF_CMD_TX_COUNT=2 -CONFIG_BT_BUF_CMD_TX_SIZE=255 CONFIG_BT_HCI_VS=y -CONFIG_BT_BUF_EVT_RX_COUNT=16 -CONFIG_BT_BUF_EVT_RX_SIZE=255 -CONFIG_BT_BUF_ACL_TX_COUNT=3 -CONFIG_BT_BUF_ACL_TX_SIZE=251 -CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 -CONFIG_BT_BUF_ACL_RX_SIZE=255 -CONFIG_BT_DEVICE_NAME_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_MAX=28 +# Override Kconfig default +CONFIG_BT_BUF_CMD_TX_COUNT=2 # Ensure the network core image starts when using native simulator CONFIG_NATIVE_SIMULATOR_AUTOSTART_MCU=y diff --git a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay index eb899df8cc9..180d6a23568 100644 --- a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay @@ -21,4 +21,12 @@ i2s_rxtx: &i2s0 { clock-source = "ACLK"; }; +/* Remove slot1 (OTA), expand slot0 to use the space. + * CircuitPython doesn't use OTA updates. */ +&slot0_partition { + reg = <0x00010000 0x000E0000>; +}; + +/delete-node/ &slot1_partition; + #include "../app.overlay" diff --git a/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf b/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf new file mode 100644 index 00000000000..784cb782b4d --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf @@ -0,0 +1,19 @@ +# Configuration for nrf54lm20bsim simulated board + +CONFIG_GPIO=y + +# Enable Bluetooth stack - bsim is for BT simulation +CONFIG_BT_HCI=y +CONFIG_BT_HCI_VS=y + +# Match nrf54lm20dk hardware: support dynamic TX power control +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y + +# Override Kconfig default +CONFIG_BT_BUF_CMD_TX_COUNT=2 + +CONFIG_TRACING=y +CONFIG_TRACING_PERFETTO=y +CONFIG_TRACING_SYNC=y +CONFIG_TRACING_BACKEND_POSIX=y +CONFIG_TRACING_GPIO=y diff --git a/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay new file mode 100644 index 00000000000..fb74a6313f3 --- /dev/null +++ b/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/ { + sram0: memory@20000000 { + device_type = "memory"; + compatible = "zephyr,memory-region", "mmio-sram"; + reg = <0x20000000 DT_SIZE_K(511)>; + zephyr,memory-region = "SRAM"; + }; + + chosen { + zephyr,sram = &sram0; + }; +}; + +&cpuapp_rram { + /delete-node/ partitions; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + circuitpy_partition: partition@0 { + label = "circuitpy"; + reg = <0x00000000 DT_SIZE_K(512)>; + }; + }; +}; + +/* Note: bsim doesn't have USB, so we don't include app.overlay */ diff --git a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf index 145a9393407..e6749ae6399 100644 --- a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf @@ -1,20 +1 @@ -CONFIG_BT=y -CONFIG_BT_PERIPHERAL=y -CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y - -CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_MAX=28 -CONFIG_BT_L2CAP_TX_MTU=253 - -# BT Buffers -CONFIG_BT_BUF_CMD_TX_SIZE=255 -CONFIG_BT_BUF_EVT_RX_COUNT=16 -CONFIG_BT_BUF_EVT_RX_SIZE=255 -CONFIG_BT_BUF_ACL_TX_COUNT=3 -CONFIG_BT_BUF_ACL_TX_SIZE=251 -CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 -CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y diff --git a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay index 837b8b6ad0a..c1ebea74a70 100644 --- a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay @@ -1,6 +1,13 @@ // nRF54LM20 DK has USB. Include the main app overlay for USB CDC ACM console and data. #include "../app.overlay" +// Link application starting at 0x0 instead of slot0_partition (no mcuboot yet). +/ { + chosen { + zephyr,code-partition = &cpuapp_rram; + }; +}; + // Enable the external MX25R6435F 8MB QSPI flash (connected via SPIM00). &mx25r64 { status = "okay"; diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index da7789578ff..2255bd760d3 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -7,3 +7,4 @@ CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y CONFIG_LOG=n CONFIG_ASSERT=n CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_BT=n diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.overlay new file mode 100644 index 00000000000..a02349aa7ad --- /dev/null +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.overlay @@ -0,0 +1,14 @@ +/* Remove slot1 (OTA), expand slot0 to use the space. + * CircuitPython doesn't use OTA updates. */ +&slot0_partition { + /* Shrink mcuboot to 48KB, absorb slot1 + gap before storage */ + reg = <0x0000C000 0x000EC000>; +}; + +&boot_partition { + reg = <0x00000000 0x0000C000>; +}; + +/delete-node/ &slot1_partition; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.conf b/ports/zephyr-cp/boards/stm32wba65i_dk1.conf index 55d951959e6..d83be8dddb5 100644 --- a/ports/zephyr-cp/boards/stm32wba65i_dk1.conf +++ b/ports/zephyr-cp/boards/stm32wba65i_dk1.conf @@ -5,20 +5,6 @@ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC=32000000 # CONFIG_BT=y # CONFIG_BT_PERIPHERAL=y # CONFIG_BT_CENTRAL=y -CONFIG_BT_BROADCASTER=y -CONFIG_BT_OBSERVER=y -CONFIG_BT_EXT_ADV=y -CONFIG_BT_STM32WBA_USE_TEMP_BASED_CALIB=n - -CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_DYNAMIC=y -CONFIG_BT_DEVICE_NAME_MAX=28 -CONFIG_BT_L2CAP_TX_MTU=253 -# BT Buffers -CONFIG_BT_BUF_CMD_TX_SIZE=255 -CONFIG_BT_BUF_EVT_RX_COUNT=16 -CONFIG_BT_BUF_EVT_RX_SIZE=255 -CONFIG_BT_BUF_ACL_TX_SIZE=251 -CONFIG_BT_BUF_ACL_RX_COUNT_EXTRA=1 -CONFIG_BT_BUF_ACL_RX_SIZE=255 +# Board-specific BT calibration +CONFIG_BT_STM32WBA_USE_TEMP_BASED_CALIB=n diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index d1410f02e1b..59813f9ad89 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -218,7 +218,6 @@ static size_t bleio_parse_adv_data(const uint8_t *raw, size_t raw_len, struct bt uint8_t data_len = field_len - 1; if (offset + field_len + 1 > raw_len || count >= out_len || - field_len < 1 || storage_offset + data_len > storage_len) { mp_raise_ValueError(MP_ERROR_TEXT("Invalid advertising data")); } diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.c b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c index 386be6004d2..af315f9f6b0 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Characteristic.c +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c @@ -5,10 +5,129 @@ // // SPDX-License-Identifier: MIT +#include + +#include +#include +#include + #include "py/runtime.h" +#include "bindings/zephyr_kernel/__init__.h" +#include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Descriptor.h" #include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/CharacteristicBuffer.h" +#include "common-hal/_bleio/Connection.h" +#include "common-hal/_bleio/UUID.h" +#include "common-hal/_bleio/PacketBuffer.h" +#include "shared-bindings/_bleio/CharacteristicBuffer.h" +#include "shared-bindings/_bleio/PacketBuffer.h" +#include "supervisor/port_heap.h" + +// CCCD write callback — captures the subscribing connection for PacketBuffer. +ssize_t bleio_ccc_write_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, uint16_t value) { + struct bt_gatt_ccc_managed_user_data *ccc_data = + (struct bt_gatt_ccc_managed_user_data *)attr->user_data; + bleio_characteristic_obj_t *characteristic = + (bleio_characteristic_obj_t *)((char *)ccc_data + - offsetof(bleio_characteristic_obj_t, zephyr_ccc)); + + if (characteristic->observer != mp_const_none && + mp_obj_is_type(characteristic->observer, &bleio_packet_buffer_type)) { + bleio_packet_buffer_set_conn( + MP_OBJ_TO_PTR(characteristic->observer), + value != 0 ? conn : NULL); + } + return sizeof(value); +} + +uint16_t bleio_security_to_zephyr_perm( + bleio_attribute_security_mode_t read_perm, + bleio_attribute_security_mode_t write_perm, + bleio_characteristic_properties_t props) { + uint16_t perm = 0; + + if (props & CHAR_PROP_READ) { + switch (read_perm) { + case SECURITY_MODE_OPEN: + perm |= BT_GATT_PERM_READ; + break; + case SECURITY_MODE_ENC_NO_MITM: + perm |= BT_GATT_PERM_READ_ENCRYPT; + break; + case SECURITY_MODE_ENC_WITH_MITM: + perm |= BT_GATT_PERM_READ_AUTHEN; + break; + case SECURITY_MODE_LESC_ENC_WITH_MITM: + perm |= BT_GATT_PERM_READ_LESC; + break; + default: + break; + } + } + + if (props & (CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE)) { + switch (write_perm) { + case SECURITY_MODE_OPEN: + perm |= BT_GATT_PERM_WRITE; + break; + case SECURITY_MODE_ENC_NO_MITM: + perm |= BT_GATT_PERM_WRITE_ENCRYPT; + break; + case SECURITY_MODE_ENC_WITH_MITM: + perm |= BT_GATT_PERM_WRITE_AUTHEN; + break; + case SECURITY_MODE_LESC_ENC_WITH_MITM: + perm |= BT_GATT_PERM_WRITE_LESC; + break; + default: + break; + } + } + + return perm; +} + +ssize_t bleio_char_read_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { + bleio_characteristic_obj_t *self = attr->user_data; + return bt_gatt_attr_read(conn, attr, buf, len, offset, + self->current_value, self->current_value_len); +} + +ssize_t bleio_char_write_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, const void *buf, uint16_t len, + uint16_t offset, uint8_t flags) { + bleio_characteristic_obj_t *self = attr->user_data; + if (offset + len > self->max_length) { + return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); + } + memcpy(self->current_value + offset, buf, len); + if (offset + len > self->current_value_len) { + self->current_value_len = offset + len; + } + + // Notify any observer (e.g., CharacteristicBuffer, PacketBuffer) of the write. + if (self->observer != mp_const_none) { + if (mp_obj_is_type(self->observer, &bleio_characteristic_buffer_type)) { + bleio_characteristic_buffer_extend(MP_OBJ_TO_PTR(self->observer), buf, len); + } else if (mp_obj_is_type(self->observer, &bleio_packet_buffer_type)) { + bleio_packet_buffer_extend(MP_OBJ_TO_PTR(self->observer), conn, buf, len); + } + } + + return len; +} + +void bleio_ccc_changed_cb(const struct bt_gatt_attr *attr, uint16_t value) { + // Track subscription state if needed in the future. + (void)attr; + (void)value; +} bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties(bleio_characteristic_obj_t *self) { return self->props; @@ -31,15 +150,95 @@ size_t common_hal_bleio_characteristic_get_max_length(bleio_characteristic_obj_t } size_t common_hal_bleio_characteristic_get_value(bleio_characteristic_obj_t *self, uint8_t *buf, size_t len) { - mp_raise_NotImplementedError(NULL); -} + if (self->service != NULL && self->service->is_remote) { + // Remote characteristic: read via GATT client + bleio_connection_obj_t *connection = MP_OBJ_TO_PTR(self->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + return bleio_gattc_read_sync(connection->connection->conn, + self->handle, buf, len); + } -void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) { - mp_raise_NotImplementedError(NULL); + // Local characteristic + size_t copy_len = self->current_value_len; + if (copy_len > len) { + copy_len = len; + } + memcpy(buf, self->current_value, copy_len); + return copy_len; } -void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, bleio_characteristic_properties_t props, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo, const char *user_description) { - mp_raise_NotImplementedError(NULL); +void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, + bleio_service_obj_t *service, uint16_t handle, bleio_uuid_obj_t *uuid, + bleio_characteristic_properties_t props, + bleio_attribute_security_mode_t read_perm, + bleio_attribute_security_mode_t write_perm, + mp_int_t max_length, bool fixed_length, + mp_buffer_info_t *initial_value_bufinfo, + const char *user_description) { + + self->service = service; + self->uuid = uuid; + self->handle = handle; + self->props = props; + self->read_perm = read_perm; + self->write_perm = write_perm; + self->max_length = max_length; + self->fixed_length = fixed_length; + self->observer = mp_const_none; + self->descriptor_list = mp_obj_new_list(0, NULL); + + // Allocate value buffer + self->current_value = m_malloc(max_length); + memset(self->current_value, 0, max_length); + self->current_value_alloc = max_length; + self->current_value_len = 0; + + // Copy initial value if provided + if (initial_value_bufinfo != NULL && initial_value_bufinfo->len > 0) { + size_t len = initial_value_bufinfo->len; + if (len > (size_t)max_length) { + len = max_length; + } + memcpy(self->current_value, initial_value_bufinfo->buf, len); + self->current_value_len = len; + } + + // Convert UUID to Zephyr format + bleio_uuid_to_zephyr(uuid, &self->zephyr_uuid); + + if (service->is_remote) { + // Remote characteristic: just add to the service's list + mp_obj_list_append(MP_OBJ_FROM_PTR(service->characteristic_list), + MP_OBJ_FROM_PTR(self)); + } else { + common_hal_bleio_service_add_characteristic(service, self, + initial_value_bufinfo, user_description); + + // Create a Descriptor object for user_description (CUD 0x2901) + if (user_description != NULL && user_description[0] != '\0') { + bleio_uuid_obj_t *desc_uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); + common_hal_bleio_uuid_construct(desc_uuid, 0x2901, NULL); + + bleio_descriptor_obj_t *descriptor = mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type); + + size_t desc_len = strlen(user_description); + mp_buffer_info_t desc_bufinfo = { + .buf = (void *)user_description, + .len = desc_len, + }; + + common_hal_bleio_descriptor_construct( + descriptor, self, desc_uuid, + SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, + desc_len, false, &desc_bufinfo); + + common_hal_bleio_characteristic_add_descriptor(self, descriptor); + } + } } bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) { @@ -47,15 +246,139 @@ bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) } void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) { - // Nothing to do + // Nothing to do - service handles unregistration +} + +// Struct for tracking GATT notification subscriptions on remote characteristics. +typedef struct { + struct bt_gatt_subscribe_params params; + uint16_t value_handle; + uint16_t ccc_handle; + bleio_characteristic_obj_t *characteristic; + volatile bool subscribed; +} zephyr_subscription_t; + +static uint8_t on_gattc_notify(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { + zephyr_subscription_t *sub = CONTAINER_OF(params, zephyr_subscription_t, params); + if (sub->characteristic != NULL && + sub->characteristic->observer != mp_const_none) { + if (mp_obj_is_type(sub->characteristic->observer, &bleio_characteristic_buffer_type)) { + bleio_characteristic_buffer_extend( + MP_OBJ_TO_PTR(sub->characteristic->observer), data, length); + } else if (mp_obj_is_type(sub->characteristic->observer, &bleio_packet_buffer_type)) { + bleio_packet_buffer_extend( + MP_OBJ_TO_PTR(sub->characteristic->observer), conn, data, length); + } + } + return BT_GATT_ITER_CONTINUE; } void common_hal_bleio_characteristic_set_cccd(bleio_characteristic_obj_t *self, bool notify, bool indicate) { - mp_raise_NotImplementedError(NULL); + // Only valid for remote characteristics (client-side). + if (self->service == NULL || !self->service->is_remote) { + return; + } + + bleio_connection_obj_t *connection_obj = MP_OBJ_TO_PTR(self->service->connection); + if (connection_obj == NULL || connection_obj->connection == NULL || + connection_obj->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + struct bt_conn *conn = connection_obj->connection->conn; + + if (!notify && !indicate) { + // Unsubscribe from any existing subscription. + // We don't track subscriptions per-characteristic yet, + // so just return for now. + return; + } + + if (self->cccd_handle == 0) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("No CCCD for this Characteristic")); + } + + // Allocate subscription tracking from port heap (won't move on GC). + // Note: Simplified - we allocate a new subscription each time. + // A production implementation would track and reuse subscriptions. + zephyr_subscription_t *sub = port_malloc(sizeof(zephyr_subscription_t), false); + if (sub == NULL) { + mp_raise_msg(&mp_type_MemoryError, NULL); + } + + // Zero-initialize the entire structure so that unset fields + // (subscribe, flags, discover_params, work_q, node) are NULL/0 + // rather than garbage from the heap. bt_gatt_subscribe checks + // subscribe==NULL to decide whether to do a synchronous write. + memset(sub, 0, sizeof(zephyr_subscription_t)); + + sub->characteristic = self; + sub->value_handle = self->handle; + sub->ccc_handle = self->cccd_handle; + sub->subscribed = false; + + sub->params.notify = on_gattc_notify; + sub->params.value_handle = self->handle; + sub->params.ccc_handle = self->cccd_handle; + sub->params.value = notify ? BT_GATT_CCC_NOTIFY : BT_GATT_CCC_INDICATE; + + int err = bt_gatt_subscribe(conn, &sub->params); + if (err != 0) { + port_free(sub); + raise_zephyr_error(err); + } + sub->subscribed = true; } void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, mp_buffer_info_t *bufinfo) { - mp_raise_NotImplementedError(NULL); + if (self->service != NULL && self->service->is_remote) { + // Remote characteristic: write via GATT client + bleio_connection_obj_t *connection = MP_OBJ_TO_PTR(self->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + if (self->props & CHAR_PROP_WRITE_NO_RESPONSE) { + int err = bt_gatt_write_without_response( + connection->connection->conn, + self->handle, + bufinfo->buf, bufinfo->len, false); + if (err != 0) { + raise_zephyr_error(err); + } + } else { + bleio_gattc_write_sync(connection->connection->conn, + self->handle, bufinfo->buf, bufinfo->len); + } + return; + } + + // Local characteristic + size_t len = bufinfo->len; + if (len > self->max_length) { + len = self->max_length; + } + memcpy(self->current_value, bufinfo->buf, len); + self->current_value_len = len; + + // If NOTIFY and service is registered, send notification + if ((self->props & CHAR_PROP_NOTIFY) && self->service != NULL && + self->service->registered) { + bt_gatt_notify(NULL, &self->service->attrs[self->value_attr_index], + self->current_value, self->current_value_len); + } +} + +void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, + bleio_descriptor_obj_t *descriptor) { + mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list), + MP_OBJ_FROM_PTR(descriptor)); + // Descriptors added after characteristic construction would need + // service re-registration; for now the common case is handled by + // Service.add_characteristic which adds descriptors at registration time. } void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer) { diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.h b/ports/zephyr-cp/common-hal/_bleio/Characteristic.h index b710a9f2662..f4a578c888a 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Characteristic.h +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.h @@ -7,6 +7,8 @@ #pragma once +#include + #include "py/obj.h" #include "py/objlist.h" #include "shared-bindings/_bleio/Attribute.h" @@ -34,7 +36,28 @@ typedef struct _bleio_characteristic_obj { uint16_t cccd_handle; uint16_t sccd_handle; bool fixed_length; + // Zephyr GATT server fields: + struct bt_gatt_chrc zephyr_chrc; + struct bt_uuid_128 zephyr_uuid; + struct bt_gatt_ccc_managed_user_data zephyr_ccc; + size_t value_attr_index; // index in service attrs for notify } bleio_characteristic_obj_t; void bleio_characteristic_set_observer(bleio_characteristic_obj_t *self, mp_obj_t observer); void bleio_characteristic_clear_observer(bleio_characteristic_obj_t *self); + +// Callbacks used by Service.c when building GATT attr table +ssize_t bleio_char_read_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset); +ssize_t bleio_char_write_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, const void *buf, uint16_t len, + uint16_t offset, uint8_t flags); +void bleio_ccc_changed_cb(const struct bt_gatt_attr *attr, uint16_t value); +ssize_t bleio_ccc_write_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, uint16_t value); + +// Permission mapping helper +uint16_t bleio_security_to_zephyr_perm( + bleio_attribute_security_mode_t read_perm, + bleio_attribute_security_mode_t write_perm, + bleio_characteristic_properties_t props); diff --git a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c index 17e000e905e..9ce48ac97c4 100644 --- a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.c @@ -5,69 +5,132 @@ // // SPDX-License-Identifier: MIT -#include "py/mperrno.h" +#include +#include + +#include + #include "py/runtime.h" +#include "py/stream.h" + +#include "shared/runtime/interrupt_char.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/CharacteristicBuffer.h" +#include "supervisor/shared/tick.h" + +#include "common-hal/_bleio/CharacteristicBuffer.h" +#include "common-hal/_bleio/Characteristic.h" + +// Zephyr's ring_buf is safe for single-producer/single-consumer without +// locks. The GATT callbacks (system workqueue) are the sole producer; +// the CircuitPython VM (main thread) is the sole consumer. + +// Called from Zephyr GATT callbacks (system workqueue context). +void bleio_characteristic_buffer_extend(bleio_characteristic_buffer_obj_t *self, + const uint8_t *data, size_t len) { + if (self->watch_for_interrupt_char) { + for (size_t i = 0; i < len; i++) { + if (data[i] == mp_interrupt_char) { + mp_sched_keyboard_interrupt(); + ring_buf_reset(&self->ringbuf); + } else { + ring_buf_put(&self->ringbuf, &data[i], 1); + } + } + } else { + ring_buf_put(&self->ringbuf, data, len); + } +} + void _common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_float_t timeout, uint8_t *buffer, size_t buffer_size, void *static_handler_entry, bool watch_for_interrupt_char) { - (void)self; - (void)characteristic; - (void)timeout; - (void)buffer; - (void)buffer_size; - (void)static_handler_entry; - (void)watch_for_interrupt_char; - mp_raise_NotImplementedError(NULL); + + self->characteristic = characteristic; + self->timeout_ms = timeout * 1000; + self->watch_for_interrupt_char = watch_for_interrupt_char; + self->ringbuf_data = buffer; + ring_buf_init(&self->ringbuf, buffer_size, buffer); + + // Set ourselves as the characteristic's observer so we receive + // incoming writes (local) and notifications (remote). + bleio_characteristic_set_observer(characteristic, MP_OBJ_FROM_PTR(self)); } +// Assumes that timeout and buffer_size have been validated before call. void common_hal_bleio_characteristic_buffer_construct(bleio_characteristic_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_float_t timeout, size_t buffer_size) { - (void)self; - (void)characteristic; - (void)timeout; - (void)buffer_size; - mp_raise_NotImplementedError(NULL); + uint8_t *buffer = m_malloc_without_collect(buffer_size); + _common_hal_bleio_characteristic_buffer_construct(self, characteristic, timeout, + buffer, buffer_size, NULL, false); } -uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, uint8_t *data, size_t len, int *errcode) { - (void)self; - (void)data; - (void)len; - if (errcode != NULL) { - *errcode = MP_EAGAIN; +uint32_t common_hal_bleio_characteristic_buffer_read(bleio_characteristic_buffer_obj_t *self, + uint8_t *data, size_t len, int *errcode) { + uint64_t start_ticks = supervisor_ticks_ms64(); + + // Wait for all bytes received or timeout + while ((ring_buf_size_get(&self->ringbuf) < len) && + (supervisor_ticks_ms64() - start_ticks < self->timeout_ms)) { + RUN_BACKGROUND_TASKS; + // Allow user to break out of a timeout with a KeyboardInterrupt. + if (mp_hal_is_interrupted()) { + return 0; + } } - mp_raise_NotImplementedError(NULL); + + return ring_buf_get(&self->ringbuf, data, len); } -uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available(bleio_characteristic_buffer_obj_t *self) { - (void)self; - mp_raise_NotImplementedError(NULL); +uint32_t common_hal_bleio_characteristic_buffer_rx_characters_available( + bleio_characteristic_buffer_obj_t *self) { + return ring_buf_size_get(&self->ringbuf); } -void common_hal_bleio_characteristic_buffer_clear_rx_buffer(bleio_characteristic_buffer_obj_t *self) { - (void)self; - mp_raise_NotImplementedError(NULL); +void common_hal_bleio_characteristic_buffer_clear_rx_buffer( + bleio_characteristic_buffer_obj_t *self) { + ring_buf_reset(&self->ringbuf); } bool common_hal_bleio_characteristic_buffer_deinited(bleio_characteristic_buffer_obj_t *self) { - return self->deinited; + return self->characteristic == NULL; } void common_hal_bleio_characteristic_buffer_deinit(bleio_characteristic_buffer_obj_t *self) { - if (self == NULL) { + if (common_hal_bleio_characteristic_buffer_deinited(self)) { return; } - self->deinited = true; + bleio_characteristic_clear_observer(self->characteristic); + self->characteristic = NULL; + // ringbuf_data was allocated with m_malloc_without_collect; free it. + m_free(self->ringbuf_data); + self->ringbuf_data = NULL; } bool common_hal_bleio_characteristic_buffer_connected(bleio_characteristic_buffer_obj_t *self) { - (void)self; - return false; + bleio_characteristic_obj_t *characteristic = self->characteristic; + if (characteristic == NULL || characteristic->service == NULL) { + return false; + } + + if (!characteristic->service->is_remote) { + // Local service: we're always "connected" as long as the service exists. + return true; + } + + // Remote service: check if the connection is still active. + if (characteristic->service->connection == mp_const_none) { + return false; + } + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(characteristic->service->connection); + return common_hal_bleio_connection_get_connected(connection); } diff --git a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h index 91ea262945a..85a5d253be2 100644 --- a/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h +++ b/ports/zephyr-cp/common-hal/_bleio/CharacteristicBuffer.h @@ -9,11 +9,21 @@ #include +#include + #include "py/obj.h" #include "shared-bindings/_bleio/Characteristic.h" typedef struct { mp_obj_base_t base; bleio_characteristic_obj_t *characteristic; - bool deinited; + uint32_t timeout_ms; + struct ring_buf ringbuf; + uint8_t *ringbuf_data; + bool watch_for_interrupt_char; } bleio_characteristic_buffer_obj_t; + +// Called from GATT callbacks (system workqueue context) to push +// data into the CharacteristicBuffer ring buffer. +void bleio_characteristic_buffer_extend(bleio_characteristic_buffer_obj_t *self, + const uint8_t *data, size_t len); diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.c b/ports/zephyr-cp/common-hal/_bleio/Connection.c index 938359c79ca..ecc5f23a525 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.c +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -6,14 +6,384 @@ // SPDX-License-Identifier: MIT #include +#include #include #include +#include +#include #include "py/runtime.h" #include "bindings/zephyr_kernel/__init__.h" #include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Connection.h" +#include "shared-bindings/_bleio/Descriptor.h" +#include "shared-bindings/_bleio/Service.h" +#include "shared-bindings/_bleio/UUID.h" +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/Characteristic.h" +#include "supervisor/port_heap.h" +#include "supervisor/shared/tick.h" + +// Discovery context passed through Zephyr callbacks. +typedef struct { + volatile bool done; + volatile int err; +} discovery_context_t; + +// Convert a Zephyr bt_uuid to a CircuitPython bleio UUID object. +// Must be called OUTSIDE Zephyr callback context. +static bleio_uuid_obj_t *bleio_uuid_from_zephyr(const struct bt_uuid *zuuid) { + bleio_uuid_obj_t *uuid = mp_obj_malloc(bleio_uuid_obj_t, &bleio_uuid_type); + if (zuuid->type == BT_UUID_TYPE_16) { + common_hal_bleio_uuid_construct(uuid, BT_UUID_16(zuuid)->val, NULL); + } else { + // Both Zephyr and CP store UUID bytes in little-endian order. + const struct bt_uuid_128 *uuid128 = BT_UUID_128(zuuid); + common_hal_bleio_uuid_construct(uuid, + (uuid128->val[13] << 8) | uuid128->val[12], uuid128->val); + } + return uuid; +} + +// Temporary storage for discovered services before creating CP objects. +// Each node is port_malloc'd in the callback and appended to a sys_slist. +typedef struct { + sys_snode_t node; + struct bt_uuid_128 uuid; + uint16_t start_handle; + uint16_t end_handle; +} discovered_service_t; + +// Temporary storage for discovered characteristics before creating CP objects. +typedef struct { + sys_snode_t node; + struct bt_uuid_128 uuid; + uint16_t value_handle; + uint16_t decl_handle; + uint8_t properties; +} discovered_char_t; + +// Temporary storage for discovered descriptors. +typedef struct { + sys_snode_t node; + struct bt_uuid_128 uuid; + uint16_t handle; +} discovered_desc_t; + +// File-scope discovery state for synchronous blocking. +static discovery_context_t *active_discovery_ctx; +static sys_slist_t discovered_list; +static struct bt_gatt_discover_params discovery_params; + +static uint8_t on_service_discovered(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + discovery_context_t *ctx = active_discovery_ctx; + + if (attr == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + discovered_service_t *ds = port_malloc(sizeof(discovered_service_t), false); + if (ds == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + struct bt_gatt_service_val *svc_val = (struct bt_gatt_service_val *)attr->user_data; + ds->start_handle = attr->handle; + ds->end_handle = svc_val->end_handle; + + // Copy UUID into our storage + if (svc_val->uuid->type == BT_UUID_TYPE_16) { + ds->uuid.uuid.type = BT_UUID_TYPE_16; + ((struct bt_uuid_16 *)&ds->uuid)->val = BT_UUID_16(svc_val->uuid)->val; + } else { + memcpy(&ds->uuid, svc_val->uuid, sizeof(struct bt_uuid_128)); + } + + sys_slist_append(&discovered_list, &ds->node); + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t on_characteristic_discovered(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + discovery_context_t *ctx = active_discovery_ctx; + + if (attr == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + discovered_char_t *dc = port_malloc(sizeof(discovered_char_t), false); + if (dc == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; + dc->value_handle = chrc->value_handle; + dc->decl_handle = attr->handle; + dc->properties = chrc->properties; + + // Copy UUID into our storage + if (chrc->uuid->type == BT_UUID_TYPE_16) { + dc->uuid.uuid.type = BT_UUID_TYPE_16; + ((struct bt_uuid_16 *)&dc->uuid)->val = BT_UUID_16(chrc->uuid)->val; + } else { + memcpy(&dc->uuid, chrc->uuid, sizeof(struct bt_uuid_128)); + } + + sys_slist_append(&discovered_list, &dc->node); + + return BT_GATT_ITER_CONTINUE; +} + +// Pairing: characteristic pointer with its declaration handle for descriptor discovery. +typedef struct { + bleio_characteristic_obj_t *characteristic; + uint16_t decl_handle; +} char_with_decl_t; + +// Forward declaration for use by descriptor discovery. +static void free_discovered_list(void); + +// Callback for descriptor discovery. +static uint8_t on_descriptor_discovered(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + discovery_context_t *ctx = active_discovery_ctx; + + if (attr == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + discovered_desc_t *dd = port_malloc(sizeof(discovered_desc_t), false); + if (dd == NULL) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + dd->handle = attr->handle; + + // Copy UUID into our storage + if (attr->uuid->type == BT_UUID_TYPE_16) { + dd->uuid.uuid.type = BT_UUID_TYPE_16; + ((struct bt_uuid_16 *)&dd->uuid)->val = BT_UUID_16(attr->uuid)->val; + } else { + memcpy(&dd->uuid, attr->uuid, sizeof(struct bt_uuid_128)); + } + + sys_slist_append(&discovered_list, &dd->node); + + return BT_GATT_ITER_CONTINUE; +} + +// Create descriptors from discovered_list and add them to the characteristic. +// Called OUTSIDE the Zephyr callback context. Drains and frees all nodes. +static void create_descriptors_from_discovered(bleio_characteristic_obj_t *characteristic) { + sys_snode_t *node; + while ((node = sys_slist_get(&discovered_list)) != NULL) { + discovered_desc_t *dd = CONTAINER_OF(node, discovered_desc_t, node); + + bleio_uuid_obj_t *uuid = bleio_uuid_from_zephyr(&dd->uuid.uuid); + + // Remember handles for certain well-known descriptors. + if (dd->uuid.uuid.type == BT_UUID_TYPE_16) { + switch (((struct bt_uuid_16 *)&dd->uuid)->val) { + case 0x2902: + characteristic->cccd_handle = dd->handle; + break; + case 0x2903: + characteristic->sccd_handle = dd->handle; + break; + case 0x2901: + characteristic->user_desc_handle = dd->handle; + break; + default: + break; + } + } + + bleio_descriptor_obj_t *descriptor = + mp_obj_malloc(bleio_descriptor_obj_t, &bleio_descriptor_type); + + // Remote descriptors: set characteristic and UUID only. + // Reads/writes go over GATT via the handle. + descriptor->characteristic = characteristic; + descriptor->uuid = uuid; + descriptor->handle = dd->handle; + descriptor->read_perm = SECURITY_MODE_OPEN; + descriptor->write_perm = SECURITY_MODE_OPEN; + descriptor->max_length = 20; + descriptor->fixed_length = false; + descriptor->value = m_malloc(20); + memset(descriptor->value, 0, 20); + descriptor->value_length = 0; + + common_hal_bleio_characteristic_add_descriptor(characteristic, descriptor); + + port_free(dd); + } +} + +// Discover descriptors for a single characteristic. +static void discover_descriptors_for_characteristic(struct bt_conn *conn, + discovery_context_t *ctx, bleio_characteristic_obj_t *characteristic, + uint16_t end_handle) { + uint16_t start = characteristic->handle + 1; + if (start > end_handle) { + return; + } + + sys_slist_init(&discovered_list); + ctx->done = false; + ctx->err = 0; + + memset(&discovery_params, 0, sizeof(discovery_params)); + discovery_params.uuid = NULL; + discovery_params.start_handle = start; + discovery_params.end_handle = end_handle; + discovery_params.type = BT_GATT_DISCOVER_DESCRIPTOR; + discovery_params.func = on_descriptor_discovered; + + int err = bt_gatt_discover(conn, &discovery_params); + if (err != 0) { + free_discovered_list(); + if (err == -ENOENT) { + return; + } + raise_zephyr_error(err); + } + + while (!ctx->done) { + RUN_BACKGROUND_TASKS; + } + + create_descriptors_from_discovered(characteristic); +} + +// Create CircuitPython characteristic objects from the discovered_list. +// Called OUTSIDE the Zephyr callback context so MP allocations are safe. +// Drains and frees all nodes from the list. +// Returns the number of characteristics created and fills the chars_out array +// (which must be large enough). +static size_t create_characteristics_from_discovered(bleio_service_obj_t *service, + char_with_decl_t *chars_out, size_t max_chars) { + size_t count = 0; + sys_snode_t *node; + while ((node = sys_slist_get(&discovered_list)) != NULL) { + discovered_char_t *dc = CONTAINER_OF(node, discovered_char_t, node); + + bleio_uuid_obj_t *uuid = bleio_uuid_from_zephyr(&dc->uuid.uuid); + + bleio_characteristic_properties_t props = 0; + if (dc->properties & BT_GATT_CHRC_BROADCAST) { + props |= CHAR_PROP_BROADCAST; + } + if (dc->properties & BT_GATT_CHRC_READ) { + props |= CHAR_PROP_READ; + } + if (dc->properties & BT_GATT_CHRC_WRITE_WITHOUT_RESP) { + props |= CHAR_PROP_WRITE_NO_RESPONSE; + } + if (dc->properties & BT_GATT_CHRC_WRITE) { + props |= CHAR_PROP_WRITE; + } + if (dc->properties & BT_GATT_CHRC_NOTIFY) { + props |= CHAR_PROP_NOTIFY; + } + if (dc->properties & BT_GATT_CHRC_INDICATE) { + props |= CHAR_PROP_INDICATE; + } + + bleio_characteristic_obj_t *characteristic = + mp_obj_malloc(bleio_characteristic_obj_t, &bleio_characteristic_type); + + // Use max_length=20 for remote chars - reads go over the wire. + common_hal_bleio_characteristic_construct( + characteristic, service, + dc->value_handle, uuid, props, + SECURITY_MODE_OPEN, SECURITY_MODE_OPEN, + 20, false, NULL, NULL); + + if (count < max_chars) { + chars_out[count].characteristic = characteristic; + chars_out[count].decl_handle = dc->decl_handle; + } + count++; + + port_free(dc); + } + return count; +} + +// Helper to drain and free all nodes from the discovered_list. +static void free_discovered_list(void) { + sys_snode_t *node; + while ((node = sys_slist_get(&discovered_list)) != NULL) { + port_free(node); + } +} + +// Discover characteristics for a single remote service. +static void discover_characteristics_for_service(struct bt_conn *conn, + discovery_context_t *ctx, bleio_service_obj_t *service) { + // Need at least 2 handles: one for the service declaration, one for a characteristic + if (service->end_handle <= service->start_handle) { + return; + } + + sys_slist_init(&discovered_list); + ctx->done = false; + ctx->err = 0; + + memset(&discovery_params, 0, sizeof(discovery_params)); + discovery_params.uuid = NULL; + discovery_params.start_handle = service->start_handle + 1; + discovery_params.end_handle = service->end_handle; + discovery_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + discovery_params.func = on_characteristic_discovered; + + int err = bt_gatt_discover(conn, &discovery_params); + if (err != 0) { + free_discovered_list(); + // -ENOENT means no characteristics found in the range, which is fine. + if (err == -ENOENT) { + return; + } + raise_zephyr_error(err); + } + + while (!ctx->done) { + RUN_BACKGROUND_TASKS; + } + + // Create CP objects outside of callback context where MP allocations are safe. + // This drains and frees the list nodes. + char_with_decl_t chars[16]; + size_t num_chars = create_characteristics_from_discovered(service, chars, 16); + + // Discover descriptors for each characteristic. + // The descriptor range for char[i] is from char[i].handle+1 to + // char[i+1].decl_handle-1 (or service.end_handle for the last). + for (size_t i = 0; i < num_chars && i < 16; i++) { + uint16_t desc_end; + if (i + 1 < num_chars) { + desc_end = chars[i + 1].decl_handle - 1; + } else { + desc_end = service->end_handle; + } + discover_descriptors_for_characteristic(conn, ctx, + chars[i].characteristic, desc_end); + } +} void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) { mp_raise_NotImplementedError(NULL); @@ -68,7 +438,113 @@ bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { } mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist) { - mp_raise_NotImplementedError(NULL); + bleio_connection_internal_t *connection = self->connection; + if (connection == NULL || connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + discovery_context_t ctx; + ctx.done = false; + ctx.err = 0; + + active_discovery_ctx = &ctx; + sys_slist_init(&discovered_list); + + // Create the result list for service objects. + mp_obj_list_t *service_list = mp_obj_new_list(0, NULL); + + // Discover primary services (callback appends nodes to discovered_list). + // When a whitelist is given, pass each UUID to Zephyr so filtering happens + // on the remote device — only matching services are returned. + if (service_uuids_whitelist == mp_const_none) { + memset(&discovery_params, 0, sizeof(discovery_params)); + discovery_params.uuid = NULL; + discovery_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discovery_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discovery_params.type = BT_GATT_DISCOVER_PRIMARY; + discovery_params.func = on_service_discovered; + + int err = bt_gatt_discover(connection->conn, &discovery_params); + if (err != 0) { + free_discovered_list(); + active_discovery_ctx = NULL; + raise_zephyr_error(err); + } + + while (!ctx.done) { + RUN_BACKGROUND_TASKS; + } + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); + mp_obj_t uuid_obj; + while ((uuid_obj = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + bleio_uuid_obj_t *cp_uuid = mp_arg_validate_type(uuid_obj, &bleio_uuid_type, MP_QSTR_uuid); + + memset(&discovery_params, 0, sizeof(discovery_params)); + discovery_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discovery_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discovery_params.type = BT_GATT_DISCOVER_PRIMARY; + discovery_params.func = on_service_discovered; + + // Set the Zephyr UUID filter. Stack variables are safe because + // bt_gatt_discover is synchronous (we spin until ctx.done). + union { + struct bt_uuid_16 u16; + struct bt_uuid_128 u128; + } z_uuid; + if (cp_uuid->size == BT_UUID_SIZE_16) { + z_uuid.u16.uuid.type = BT_UUID_TYPE_16; + z_uuid.u16.val = cp_uuid->uuid16; + discovery_params.uuid = &z_uuid.u16.uuid; + } else { + z_uuid.u128.uuid.type = BT_UUID_TYPE_128; + memcpy(z_uuid.u128.val, cp_uuid->uuid128, 16); + discovery_params.uuid = &z_uuid.u128.uuid; + } + + ctx.done = false; + ctx.err = 0; + + int err = bt_gatt_discover(connection->conn, &discovery_params); + if (err != 0) { + free_discovered_list(); + active_discovery_ctx = NULL; + raise_zephyr_error(err); + } + + while (!ctx.done) { + RUN_BACKGROUND_TASKS; + } + } + } + + // Create CP service objects outside callback context where MP allocations are safe. + // Drain and free the discovered service nodes. + mp_obj_list_t *result_list = service_list; + sys_snode_t *snode; + while ((snode = sys_slist_get(&discovered_list)) != NULL) { + discovered_service_t *ds = CONTAINER_OF(snode, discovered_service_t, node); + bleio_uuid_obj_t *uuid = bleio_uuid_from_zephyr(&ds->uuid.uuid); + bleio_service_obj_t *service = mp_obj_malloc(bleio_service_obj_t, &bleio_service_type); + common_hal_bleio_service_from_remote_service(service, self, uuid, false); + service->start_handle = ds->start_handle; + service->end_handle = ds->end_handle; + mp_obj_list_append(MP_OBJ_FROM_PTR(service_list), MP_OBJ_FROM_PTR(service)); + port_free(ds); + } + + // Discover characteristics for each service + for (size_t i = 0; i < result_list->len; i++) { + bleio_service_obj_t *svc = MP_OBJ_TO_PTR(result_list->items[i]); + if (svc->start_handle < svc->end_handle) { + discover_characteristics_for_service(connection->conn, &ctx, svc); + } + } + + active_discovery_ctx = NULL; + + return mp_obj_new_tuple(result_list->len, result_list->items); } mp_float_t common_hal_bleio_connection_get_connection_interval(bleio_connection_internal_t *self) { diff --git a/ports/zephyr-cp/common-hal/_bleio/Descriptor.c b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c index a3e65a5e006..a2219d8b5cd 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Descriptor.c +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.c @@ -5,12 +5,48 @@ // // SPDX-License-Identifier: MIT +#include + #include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Descriptor.h" #include "shared-bindings/_bleio/Characteristic.h" +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/Characteristic.h" +#include "common-hal/_bleio/Connection.h" +#include "supervisor/port_heap.h" + +void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, + bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, + bleio_attribute_security_mode_t read_perm, + bleio_attribute_security_mode_t write_perm, + mp_int_t max_length, bool fixed_length, + mp_buffer_info_t *initial_value_bufinfo) { + + self->characteristic = characteristic; + self->uuid = uuid; + self->read_perm = read_perm; + self->write_perm = write_perm; + self->max_length = max_length; + self->fixed_length = fixed_length; -void common_hal_bleio_descriptor_construct(bleio_descriptor_obj_t *self, bleio_characteristic_obj_t *characteristic, bleio_uuid_obj_t *uuid, bleio_attribute_security_mode_t read_perm, bleio_attribute_security_mode_t write_perm, mp_int_t max_length, bool fixed_length, mp_buffer_info_t *initial_value_bufinfo) { - mp_raise_NotImplementedError(NULL); + // Allocate value buffer + self->value = m_malloc(max_length); + memset(self->value, 0, max_length); + self->value_length = 0; + + // Copy initial value if provided + if (initial_value_bufinfo != NULL && initial_value_bufinfo->len > 0) { + size_t len = initial_value_bufinfo->len; + if (len > (size_t)max_length) { + len = max_length; + } + memcpy(self->value, initial_value_bufinfo->buf, len); + self->value_length = len; + } + + // Convert UUID to Zephyr format + bleio_uuid_to_zephyr(uuid, &self->zephyr_uuid); } bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *self) { @@ -18,13 +54,56 @@ bleio_uuid_obj_t *common_hal_bleio_descriptor_get_uuid(bleio_descriptor_obj_t *s } bleio_characteristic_obj_t *common_hal_bleio_descriptor_get_characteristic(bleio_descriptor_obj_t *self) { - mp_raise_NotImplementedError(NULL); + return (bleio_characteristic_obj_t *)self->characteristic; +} + +static bool descriptor_is_remote(bleio_descriptor_obj_t *self) { + return self->characteristic != NULL && + self->characteristic->service != NULL && + self->characteristic->service->is_remote; } size_t common_hal_bleio_descriptor_get_value(bleio_descriptor_obj_t *self, uint8_t *buf, size_t len) { - mp_raise_NotImplementedError(NULL); + if (descriptor_is_remote(self)) { + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(self->characteristic->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + return bleio_gattc_read_sync(connection->connection->conn, + self->handle, buf, len); + } + + // Local descriptor + size_t copy_len = self->value_length; + if (copy_len > len) { + copy_len = len; + } + memcpy(buf, self->value, copy_len); + return copy_len; } void common_hal_bleio_descriptor_set_value(bleio_descriptor_obj_t *self, mp_buffer_info_t *bufinfo) { - mp_raise_NotImplementedError(NULL); + if (descriptor_is_remote(self)) { + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(self->characteristic->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + bleio_gattc_write_sync(connection->connection->conn, + self->handle, bufinfo->buf, bufinfo->len); + return; + } + + // Local descriptor + size_t len = bufinfo->len; + if (len > self->max_length) { + len = self->max_length; + } + memcpy(self->value, bufinfo->buf, len); + self->value_length = len; } diff --git a/ports/zephyr-cp/common-hal/_bleio/Descriptor.h b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h index 1d29cb27a50..b6d3ab4452e 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Descriptor.h +++ b/ports/zephyr-cp/common-hal/_bleio/Descriptor.h @@ -7,10 +7,15 @@ #pragma once +#include + #include "py/obj.h" #include "shared-bindings/_bleio/Attribute.h" #include "common-hal/_bleio/UUID.h" +// Forward declaration to break circular dependency +struct _bleio_characteristic_obj; + typedef struct _bleio_descriptor_obj { mp_obj_base_t base; bleio_uuid_obj_t *uuid; @@ -21,4 +26,6 @@ typedef struct _bleio_descriptor_obj { bool fixed_length; uint8_t *value; uint16_t value_length; + struct _bleio_characteristic_obj *characteristic; + struct bt_uuid_128 zephyr_uuid; } bleio_descriptor_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c index 82fe8a3d176..02e593fabfe 100644 --- a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c @@ -5,62 +5,398 @@ // // SPDX-License-Identifier: MIT +#include + +#include +#include +#include + #include "py/runtime.h" +#include "py/stream.h" + +#include "shared/runtime/interrupt_char.h" + +#include "shared-bindings/_bleio/__init__.h" +#include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/PacketBuffer.h" +#include "supervisor/shared/tick.h" + +#include "common-hal/_bleio/Characteristic.h" +#include "common-hal/_bleio/PacketBuffer.h" + +// Zephyr's ring_buf is safe for single-producer/single-consumer without +// locks. The GATT callbacks (system workqueue) are the sole producer; +// the CircuitPython VM (main thread) is the sole consumer. + +// Forward declarations. +static bool conn_is_valid(bleio_packet_buffer_obj_t *self); +static bool send_pending(bleio_packet_buffer_obj_t *self); + +// Called from Zephyr GATT callbacks (system workqueue context). +// Wraps incoming data with a uint16_t length prefix and pushes into ringbuf. +// Tracks the first connection so notifications target the right peer. +void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, + struct bt_conn *conn, const uint8_t *data, size_t len) { + // Track the first/current connection for notifications. + if (conn != NULL) { + conn_is_valid(self); // clear stale conn if needed + if (self->conn == NULL) { + self->conn = conn; + } + } + if (len > UINT16_MAX) { + return; + } + + uint16_t packet_len = (uint16_t)len; + size_t total = sizeof(uint16_t) + len; + + // If the packet doesn't fit, drop oldest packets to make room. + while (ring_buf_space_get(&self->ringbuf) < total) { + uint16_t old_len; + if (ring_buf_size_get(&self->ringbuf) < sizeof(uint16_t)) { + // Not enough data for a length prefix, just reset. + ring_buf_reset(&self->ringbuf); + break; + } + uint32_t peeked = ring_buf_peek(&self->ringbuf, (uint8_t *)&old_len, sizeof(uint16_t)); + if (peeked < sizeof(uint16_t)) { + ring_buf_reset(&self->ringbuf); + break; + } + // Discard the length prefix + ring_buf_get(&self->ringbuf, (uint8_t *)&old_len, sizeof(uint16_t)); + // Discard the packet data + size_t to_discard = old_len; + if (to_discard > ring_buf_size_get(&self->ringbuf)) { + to_discard = ring_buf_size_get(&self->ringbuf); + } + uint8_t discard_buf[32]; + while (to_discard > 0) { + size_t chunk = to_discard > sizeof(discard_buf) ? sizeof(discard_buf) : to_discard; + ring_buf_get(&self->ringbuf, discard_buf, chunk); + to_discard -= chunk; + } + } + + ring_buf_put(&self->ringbuf, (uint8_t *)&packet_len, sizeof(uint16_t)); + ring_buf_put(&self->ringbuf, data, len); +} + +void bleio_packet_buffer_set_conn(bleio_packet_buffer_obj_t *self, + struct bt_conn *conn) { + self->conn = conn; +} + +// Completion callback for bt_gatt_notify_cb — called when the PDU has been +// sent (or the buffer freed). Drains any accumulated pending data. +static void notify_complete_cb(struct bt_conn *conn, void *user_data) { + bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *)user_data; + self->packet_queued = false; + send_pending(self); +} + +// Returns true if the tracked connection is still connected. +// Clears self->conn if the connection is stale. +static bool conn_is_valid(bleio_packet_buffer_obj_t *self) { + if (self->conn == NULL) { + return false; + } + struct bt_conn_info info; + if (bt_conn_get_info(self->conn, &info) != 0 || + info.state == BT_CONN_STATE_DISCONNECTED) { + self->conn = NULL; + return false; + } + return true; +} + +// Send the pending outgoing buffer via GATT notify. +// Returns true if sent successfully (or terminal failure). +static bool send_pending(bleio_packet_buffer_obj_t *self) { + if (self->pending_size == 0) { + return true; + } + if (self->characteristic == NULL || + self->characteristic->service == NULL || + self->characteristic->service->is_remote) { + self->pending_size = 0; + return true; + } + + bleio_characteristic_obj_t *c = self->characteristic; + if (!(c->props & CHAR_PROP_NOTIFY) || !c->service->registered) { + self->pending_size = 0; + return true; + } + + struct bt_gatt_notify_params params = { + .attr = &c->service->attrs[c->value_attr_index], + .data = self->outgoing_buffer, + .len = self->pending_size, + .func = notify_complete_cb, + .user_data = self, + }; + + // If the tracked connection is stale, clear it. + conn_is_valid(self); + + int err = bt_gatt_notify_cb(self->conn, ¶ms); + if (err == 0) { + self->pending_size = 0; + self->packet_queued = true; + return true; + } + if (err == -ENOTCONN) { + // Peer disconnected — clear tracking, discard pending. + self->conn = NULL; + self->pending_size = 0; + return true; + } + // -ENOMEM (no TX buffer) — leave pending, caller will retry. + return false; +} + void common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, size_t buffer_size, size_t max_packet_size) { + + self->characteristic = characteristic; + self->timeout_ms = 0; + self->max_packet_size = max_packet_size; + self->conn = NULL; + self->client = (characteristic->service != NULL && characteristic->service->is_remote); + self->pending_size = 0; + self->packet_queued = false; + + // Allocate ring buffer: buffer_size packets, each with 2-byte length prefix + self->ringbuf_size = buffer_size * (sizeof(uint16_t) + max_packet_size); + self->ringbuf_data = m_malloc_without_collect(self->ringbuf_size); + ring_buf_init(&self->ringbuf, self->ringbuf_size, self->ringbuf_data); + + // Allocate outgoing buffer for pending writes + bleio_characteristic_properties_t props = + common_hal_bleio_characteristic_get_properties(characteristic); + if (self->client) { + // Client-side: we write to remote characteristic + self->outgoing_buffer = m_malloc_without_collect(max_packet_size); + } else { + // Server-side: we notify via local characteristic + if (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { + self->outgoing_buffer = m_malloc_without_collect(max_packet_size); + } else { + self->outgoing_buffer = NULL; + } + } + + // Set ourselves as the characteristic's observer + bleio_characteristic_set_observer(characteristic, MP_OBJ_FROM_PTR(self)); + + // For client-side characteristics with NOTIFY/INDICATE, subscribe to notifications + if (self->client && (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE))) { + bool do_notify = (props & CHAR_PROP_NOTIFY) != 0; + bool do_indicate = (props & CHAR_PROP_INDICATE) != 0; + common_hal_bleio_characteristic_set_cccd(characteristic, do_notify, do_indicate); + } +} + +// Allocation-free version for BLE workflow use (not yet implemented for Zephyr). +void _common_hal_bleio_packet_buffer_construct( + bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, + uint32_t *incoming_buffer, size_t incoming_buffer_size, + uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, + ble_event_handler_t *static_handler_entry) { (void)self; (void)characteristic; - (void)buffer_size; + (void)incoming_buffer; + (void)incoming_buffer_size; + (void)outgoing_buffer1; + (void)outgoing_buffer2; (void)max_packet_size; + (void)static_handler_entry; mp_raise_NotImplementedError(NULL); } -mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, const uint8_t *data, size_t len, uint8_t *header, size_t header_len) { - (void)self; - (void)data; - (void)len; - (void)header; - (void)header_len; - mp_raise_NotImplementedError(NULL); +mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, + uint8_t *data, size_t len) { + // Need at least 2 bytes for the length prefix + if (ring_buf_size_get(&self->ringbuf) < sizeof(uint16_t)) { + return 0; + } + + // Peek at the packet length (don't consume yet) + uint16_t packet_length; + uint32_t peeked = ring_buf_peek(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); + if (peeked < sizeof(uint16_t)) { + return 0; + } + + mp_int_t ret; + if (packet_length > len) { + // Packet is longer than requested. Return negative of overrun value. + ret = len - packet_length; + // Discard the packet + ring_buf_get(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); + if (packet_length <= ring_buf_size_get(&self->ringbuf)) { + // Discard data in chunks + uint8_t discard[32]; + size_t remaining = packet_length; + while (remaining > 0) { + size_t chunk = remaining > sizeof(discard) ? sizeof(discard) : remaining; + ring_buf_get(&self->ringbuf, discard, chunk); + remaining -= chunk; + } + } + } else { + // Consume the length prefix + ring_buf_get(&self->ringbuf, (uint8_t *)&packet_length, sizeof(uint16_t)); + // Read packet data + ring_buf_get(&self->ringbuf, data, packet_length); + ret = packet_length; + } + + return ret; } -mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, uint8_t *data, size_t len) { - (void)self; - (void)data; - (void)len; - mp_raise_NotImplementedError(NULL); +mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, + const uint8_t *data, size_t len, uint8_t *header, size_t header_len) { + if (self->outgoing_buffer == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Writes not supported on Characteristic")); + } + + mp_int_t outgoing_packet_length = + common_hal_bleio_packet_buffer_get_outgoing_packet_length(self); + if (outgoing_packet_length < 0) { + return -1; + } + + mp_int_t total_len = len + header_len; + if (total_len > outgoing_packet_length) { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("Total data to write is larger than %q"), + MP_QSTR_outgoing_packet_length); + } + if (total_len > (mp_int_t)self->max_packet_size) { + mp_raise_ValueError_varg( + MP_ERROR_TEXT("Total data to write is larger than %q"), + MP_QSTR_max_packet_size); + } + + // If no room to append, wait until pending is sent. + if (len + self->pending_size > (size_t)outgoing_packet_length) { + while (self->pending_size != 0 && + !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + } + } + if (mp_hal_is_interrupted()) { + return -1; + } + + size_t num_bytes_written = 0; + + if (self->pending_size == 0) { + memcpy(self->outgoing_buffer, header, header_len); + self->pending_size += header_len; + num_bytes_written += header_len; + } + memcpy(self->outgoing_buffer + self->pending_size, data, len); + self->pending_size += len; + num_bytes_written += len; + + // Send immediately if no write is queued. + if (!self->packet_queued) { + send_pending(self); + } + return num_bytes_written; } -mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length(bleio_packet_buffer_obj_t *self) { - (void)self; - mp_raise_NotImplementedError(NULL); +mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length( + bleio_packet_buffer_obj_t *self) { + if (self->characteristic == NULL) { + return -1; + } + + if (self->characteristic->service != NULL && + self->characteristic->service->is_remote && + self->characteristic->service->connection != mp_const_none && + (common_hal_bleio_characteristic_get_properties(self->characteristic) & + (CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) { + // We are receiving from a remote service via NOTIFY/INDICATE. + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(self->characteristic->service->connection); + if (connection != NULL && connection->connection != NULL && + common_hal_bleio_connection_get_connected(connection)) { + return common_hal_bleio_connection_get_max_packet_length(connection->connection); + } + return -1; + } + return self->characteristic->max_length; } -mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length(bleio_packet_buffer_obj_t *self) { - (void)self; - mp_raise_NotImplementedError(NULL); +mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length( + bleio_packet_buffer_obj_t *self) { + if (self->characteristic == NULL) { + return -1; + } + + if (self->characteristic->service != NULL && + !self->characteristic->service->is_remote && + (common_hal_bleio_characteristic_get_properties(self->characteristic) & + (CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) { + // We are sending to a client via NOTIFY/INDICATE. + // Use max_packet_size since we don't track MTU dynamically here. + return MIN(self->max_packet_size, self->characteristic->max_length); + } + // Writing to remote characteristic or local without NOTIFY + return MIN(self->characteristic->max_length, self->max_packet_size); } void common_hal_bleio_packet_buffer_flush(bleio_packet_buffer_obj_t *self) { - (void)self; - mp_raise_NotImplementedError(NULL); + // With the completion callback, writes drain automatically. + // flush() just waits for any queued data to be sent. + while (self->pending_size > 0 && + !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + if (!send_pending(self)) { + // Couldn't send — wait and retry. + RUN_BACKGROUND_TASKS; + } + } } bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { - return self->deinited; + return self->characteristic == NULL; } void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { - if (self == NULL) { + if (common_hal_bleio_packet_buffer_deinited(self)) { return; } - self->deinited = true; + bleio_characteristic_clear_observer(self->characteristic); + self->characteristic = NULL; + // Free ringbuf_data allocated with m_malloc_without_collect + m_free(self->ringbuf_data); + self->ringbuf_data = NULL; + // Free outgoing buffer + m_free(self->outgoing_buffer); + self->outgoing_buffer = NULL; } bool common_hal_bleio_packet_buffer_connected(bleio_packet_buffer_obj_t *self) { - (void)self; - return false; + if (common_hal_bleio_packet_buffer_deinited(self)) { + return false; + } + // Check if the characteristic's connection is still active. + if (self->characteristic->service != NULL && + self->characteristic->service->is_remote) { + if (self->characteristic->service->connection == mp_const_none) { + return false; + } + bleio_connection_obj_t *connection = + MP_OBJ_TO_PTR(self->characteristic->service->connection); + return common_hal_bleio_connection_get_connected(connection); + } + return true; } diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h index c8cd763fd61..491852ec5fd 100644 --- a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h @@ -9,13 +9,36 @@ #include +#include + #include "py/obj.h" +#include "shared-bindings/_bleio/Characteristic.h" -typedef struct _bleio_characteristic_obj bleio_characteristic_obj_t; +struct bt_conn; typedef void *ble_event_handler_t; typedef struct { mp_obj_base_t base; - bool deinited; + bleio_characteristic_obj_t *characteristic; + uint32_t timeout_ms; + struct ring_buf ringbuf; + uint8_t *ringbuf_data; + size_t ringbuf_size; + size_t max_packet_size; + // Outgoing pending buffer + uint8_t *outgoing_buffer; + uint16_t pending_size; + bool packet_queued; + struct bt_conn *conn; + bool client; } bleio_packet_buffer_obj_t; + +// Called from GATT callbacks (system workqueue context) to push +// data into the PacketBuffer ring buffer with length-prefix framing. +void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, + struct bt_conn *conn, const uint8_t *data, size_t len); + +// Called from CCCD write callback to record the subscribing connection. +void bleio_packet_buffer_set_conn(bleio_packet_buffer_obj_t *self, + struct bt_conn *conn); diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.c b/ports/zephyr-cp/common-hal/_bleio/Service.c index cefc85b6df6..ee8cf35deee 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Service.c +++ b/ports/zephyr-cp/common-hal/_bleio/Service.c @@ -5,24 +5,122 @@ // // SPDX-License-Identifier: MIT +// GATT server service implementation for Zephyr. +// +// Each bleio Service owns a dynamically-allocated array of bt_gatt_attr +// (the Zephyr GATT attribute table). When a Characteristic is added, we +// append 2-4 attrs (declaration, value, optional CCC, optional CUD) and +// (re-)register the service with bt_gatt_service_register(). +// +// IMPORTANT: Zephyr's BT_UUID_GATT_PRIMARY / BT_UUID_GATT_CHRC / … macros +// expand to compound-literal pointers. Inside a function those have automatic +// storage duration and become dangling once the function returns. We therefore +// declare file-scope static const UUIDs (_uuid_primary, _uuid_chrc, …) and +// reference those from every bt_gatt_attr we build. + +#include +#include + +#include + +#include "py/gc.h" #include "py/runtime.h" -#include "shared-bindings/_bleio/Service.h" +#include "bindings/zephyr_kernel/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" +#include "shared-bindings/_bleio/Service.h" +#include "common-hal/_bleio/__init__.h" +#include "common-hal/_bleio/Characteristic.h" + +#define INITIAL_ATTR_CAPACITY 16 + +// Standard GATT UUIDs with static storage duration. +// BT_UUID_GATT_PRIMARY etc. expand to compound literals which have automatic +// storage when used inside functions - the resulting pointers dangle after the +// function returns. These static constants persist for the lifetime of the +// program. +static const struct bt_uuid_16 _uuid_primary = BT_UUID_INIT_16(BT_UUID_GATT_PRIMARY_VAL); +static const struct bt_uuid_16 _uuid_secondary = BT_UUID_INIT_16(BT_UUID_GATT_SECONDARY_VAL); +static const struct bt_uuid_16 _uuid_chrc = BT_UUID_INIT_16(BT_UUID_GATT_CHRC_VAL); +static const struct bt_uuid_16 _uuid_ccc = BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL); +static const struct bt_uuid_16 _uuid_cud = BT_UUID_INIT_16(BT_UUID_GATT_CUD_VAL); + +static void service_ensure_capacity(bleio_service_obj_t *self, size_t needed) { + if (self->attr_count + needed <= self->attr_capacity) { + return; + } + size_t new_capacity = self->attr_capacity; + while (new_capacity < self->attr_count + needed) { + new_capacity *= 2; + } + struct bt_gatt_attr *new_attrs = m_realloc(self->attrs, + new_capacity * sizeof(struct bt_gatt_attr)); + self->attrs = new_attrs; + self->attr_capacity = new_capacity; +} + +uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, + bleio_uuid_obj_t *uuid, bool is_secondary, + mp_obj_list_t *characteristic_list) { + self->uuid = uuid; + self->is_secondary = is_secondary; + self->is_remote = false; + self->connection = mp_const_none; + self->characteristic_list = characteristic_list; + self->start_handle = 0; + self->end_handle = 0; + self->registered = false; + + // Convert UUID to Zephyr format + bleio_uuid_to_zephyr(uuid, &self->zephyr_uuid); + + // Allocate attrs array + self->attr_capacity = INITIAL_ATTR_CAPACITY; + self->attrs = m_malloc(self->attr_capacity * sizeof(struct bt_gatt_attr)); + memset(self->attrs, 0, self->attr_capacity * sizeof(struct bt_gatt_attr)); + self->attr_count = 0; -uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary, mp_obj_list_t *characteristic_list) { - mp_raise_NotImplementedError(NULL); + // Add primary/secondary service declaration at index 0 + const struct bt_uuid *svc_type_uuid = is_secondary + ? (const struct bt_uuid *)&_uuid_secondary + : (const struct bt_uuid *)&_uuid_primary; + self->attrs[0] = (struct bt_gatt_attr) { + .uuid = svc_type_uuid, + .perm = BT_GATT_PERM_READ, + .read = bt_gatt_attr_read_service, + .user_data = (void *)&self->zephyr_uuid, + }; + self->attr_count = 1; + + return 0; } -void common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uuid_obj_t *uuid, bool is_secondary) { - mp_raise_NotImplementedError(NULL); +void common_hal_bleio_service_construct(bleio_service_obj_t *self, + bleio_uuid_obj_t *uuid, bool is_secondary) { + mp_obj_list_t *char_list = mp_obj_new_list(0, NULL); + _common_hal_bleio_service_construct(self, uuid, is_secondary, char_list); } void common_hal_bleio_service_deinit(bleio_service_obj_t *self) { - // Nothing to do + if (self->registered) { + bt_gatt_service_unregister(&self->zephyr_service); + self->registered = false; + } } -void common_hal_bleio_service_from_remote_service(bleio_service_obj_t *self, bleio_connection_obj_t *connection, bleio_uuid_obj_t *uuid, bool is_secondary) { - mp_raise_NotImplementedError(NULL); +void common_hal_bleio_service_from_remote_service(bleio_service_obj_t *self, + bleio_connection_obj_t *connection, bleio_uuid_obj_t *uuid, bool is_secondary) { + self->uuid = uuid; + self->is_secondary = is_secondary; + self->is_remote = true; + self->connection = MP_OBJ_FROM_PTR(connection); + self->characteristic_list = mp_obj_new_list(0, NULL); + self->start_handle = 0; + self->end_handle = 0; + self->registered = false; + self->attrs = NULL; + self->attr_count = 0; + self->attr_capacity = 0; + bleio_uuid_to_zephyr(uuid, &self->zephyr_uuid); } bleio_uuid_obj_t *common_hal_bleio_service_get_uuid(bleio_service_obj_t *self) { @@ -41,6 +139,120 @@ bool common_hal_bleio_service_get_is_secondary(bleio_service_obj_t *self) { return self->is_secondary; } -void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, bleio_characteristic_obj_t *characteristic, mp_buffer_info_t *initial_value_bufinfo, const char *user_description) { - mp_raise_NotImplementedError(NULL); +void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, + bleio_characteristic_obj_t *characteristic, + mp_buffer_info_t *initial_value_bufinfo, + const char *user_description) { + + if (self->registered) { + bt_gatt_service_unregister(&self->zephyr_service); + self->registered = false; + } + + // Calculate how many attrs we need: + // 1 = characteristic declaration, 1 = value attr + // +1 if NOTIFY|INDICATE (CCC descriptor) + // +1 if user_description + size_t attrs_needed = 2; + bool needs_ccc = (characteristic->props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) != 0; + bool needs_user_desc = (user_description != NULL && user_description[0] != '\0'); + if (needs_ccc) { + attrs_needed++; + } + if (needs_user_desc) { + attrs_needed++; + } + + service_ensure_capacity(self, attrs_needed); + + // Map CP properties to Zephyr BT spec properties + uint8_t zephyr_props = 0; + if (characteristic->props & CHAR_PROP_BROADCAST) { + zephyr_props |= BT_GATT_CHRC_BROADCAST; + } + if (characteristic->props & CHAR_PROP_READ) { + zephyr_props |= BT_GATT_CHRC_READ; + } + if (characteristic->props & CHAR_PROP_WRITE_NO_RESPONSE) { + zephyr_props |= BT_GATT_CHRC_WRITE_WITHOUT_RESP; + } + if (characteristic->props & CHAR_PROP_WRITE) { + zephyr_props |= BT_GATT_CHRC_WRITE; + } + if (characteristic->props & CHAR_PROP_NOTIFY) { + zephyr_props |= BT_GATT_CHRC_NOTIFY; + } + if (characteristic->props & CHAR_PROP_INDICATE) { + zephyr_props |= BT_GATT_CHRC_INDICATE; + } + + // Set up the Zephyr chrc struct in the characteristic + characteristic->zephyr_chrc.uuid = &characteristic->zephyr_uuid.uuid; + characteristic->zephyr_chrc.value_handle = 0; + characteristic->zephyr_chrc.properties = zephyr_props; + + // Map permissions + uint16_t perm = bleio_security_to_zephyr_perm( + characteristic->read_perm, characteristic->write_perm, characteristic->props); + + // Attr: characteristic declaration + size_t idx = self->attr_count; + self->attrs[idx] = (struct bt_gatt_attr) { + .uuid = (const struct bt_uuid *)&_uuid_chrc, + .perm = BT_GATT_PERM_READ, + .read = bt_gatt_attr_read_chrc, + .user_data = &characteristic->zephyr_chrc, + }; + idx++; + + // Attr: characteristic value (UUID points into characteristic, which persists) + characteristic->value_attr_index = idx; + self->attrs[idx] = (struct bt_gatt_attr) { + .uuid = &characteristic->zephyr_uuid.uuid, + .perm = perm, + .read = (characteristic->props & CHAR_PROP_READ) ? bleio_char_read_cb : NULL, + .write = (characteristic->props & (CHAR_PROP_WRITE | CHAR_PROP_WRITE_NO_RESPONSE)) ? bleio_char_write_cb : NULL, + .user_data = characteristic, + }; + idx++; + + // Attr: CCC descriptor (for NOTIFY/INDICATE) + if (needs_ccc) { + characteristic->zephyr_ccc = (struct bt_gatt_ccc_managed_user_data) + BT_GATT_CCC_MANAGED_USER_DATA_INIT(bleio_ccc_changed_cb, bleio_ccc_write_cb, NULL); + self->attrs[idx] = (struct bt_gatt_attr) { + .uuid = (const struct bt_uuid *)&_uuid_ccc, + .perm = BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, + .read = bt_gatt_attr_read_ccc, + .write = bt_gatt_attr_write_ccc, + .user_data = &characteristic->zephyr_ccc, + }; + idx++; + } + + // Attr: user description descriptor + if (needs_user_desc) { + self->attrs[idx] = (struct bt_gatt_attr) { + .uuid = (const struct bt_uuid *)&_uuid_cud, + .perm = BT_GATT_PERM_READ, + .read = bt_gatt_attr_read_cud, + .user_data = (void *)user_description, + }; + idx++; + } + + self->attr_count = idx; + + // Add characteristic to list + mp_obj_list_append(MP_OBJ_FROM_PTR(self->characteristic_list), + MP_OBJ_FROM_PTR(characteristic)); + + // Register the service + self->zephyr_service.attrs = self->attrs; + self->zephyr_service.attr_count = self->attr_count; + int err = bt_gatt_service_register(&self->zephyr_service); + if (err != 0) { + raise_zephyr_error(err); + } + self->registered = true; } diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.h b/ports/zephyr-cp/common-hal/_bleio/Service.h index 86727d3b0f7..8c820fd204e 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Service.h +++ b/ports/zephyr-cp/common-hal/_bleio/Service.h @@ -7,6 +7,8 @@ #pragma once +#include + #include "py/obj.h" #include "py/objlist.h" #include "common-hal/_bleio/UUID.h" @@ -20,4 +22,11 @@ typedef struct bleio_service_obj { uint16_t end_handle; bool is_remote; bool is_secondary; + // Zephyr GATT server fields: + struct bt_gatt_service zephyr_service; + struct bt_gatt_attr *attrs; + size_t attr_count; + size_t attr_capacity; + struct bt_uuid_128 zephyr_uuid; + bool registered; } bleio_service_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/UUID.c b/ports/zephyr-cp/common-hal/_bleio/UUID.c index 916eedb2c47..9e963b1b0bc 100644 --- a/ports/zephyr-cp/common-hal/_bleio/UUID.c +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.c @@ -11,27 +11,25 @@ #include "shared-bindings/_bleio/UUID.h" void common_hal_bleio_uuid_construct(bleio_uuid_obj_t *self, mp_int_t uuid16, const uint8_t uuid128[16]) { - if (uuid16 != 0) { - // 16-bit UUID - self->size = 16; - // Convert 16-bit UUID to 128-bit - // Bluetooth Base UUID: 00000000-0000-1000-8000-00805F9B34FB - const uint8_t base_uuid[16] = {0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - memcpy(self->uuid128, base_uuid, 16); - self->uuid128[12] = (uuid16 & 0xff); + self->uuid16 = (uint16_t)uuid16; + if (uuid128 == NULL) { + // 16-bit UUID — only bytes 12-13 matter; rest is zero (matching ble_hci). + self->size = BT_UUID_SIZE_16; + memset(self->uuid128, 0, 16); + self->uuid128[12] = uuid16 & 0xff; self->uuid128[13] = (uuid16 >> 8) & 0xff; } else { - // 128-bit UUID - self->size = 128; + // 128-bit UUID — uuid128 has bytes 12-13 zeroed, uuid16 is extracted from them + self->size = BT_UUID_SIZE_128; memcpy(self->uuid128, uuid128, 16); + // Restore the 16-bit portion from uuid16 into bytes 12-13 (little-endian). + self->uuid128[12] = uuid16 & 0xff; + self->uuid128[13] = uuid16 >> 8; } } uint32_t common_hal_bleio_uuid_get_uuid16(bleio_uuid_obj_t *self) { - if (self->size == 16) { - return (self->uuid128[13] << 8) | self->uuid128[12]; - } - return 0; + return self->uuid16; } void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[16]) { @@ -39,11 +37,11 @@ void common_hal_bleio_uuid_get_uuid128(bleio_uuid_obj_t *self, uint8_t uuid128[1 } uint32_t common_hal_bleio_uuid_get_size(bleio_uuid_obj_t *self) { - return self->size; + return self->size == BT_UUID_SIZE_16 ? 16 : 128; } void common_hal_bleio_uuid_pack_into(bleio_uuid_obj_t *self, uint8_t *buf) { - if (self->size == 16) { + if (self->size == BT_UUID_SIZE_16) { buf[0] = self->uuid128[12]; buf[1] = self->uuid128[13]; } else { diff --git a/ports/zephyr-cp/common-hal/_bleio/UUID.h b/ports/zephyr-cp/common-hal/_bleio/UUID.h index 386f5a7b8b9..9a0743a1b60 100644 --- a/ports/zephyr-cp/common-hal/_bleio/UUID.h +++ b/ports/zephyr-cp/common-hal/_bleio/UUID.h @@ -7,10 +7,13 @@ #pragma once +#include + #include "py/obj.h" typedef struct { mp_obj_base_t base; uint8_t uuid128[16]; - uint8_t size; + uint8_t size; // BT_UUID_SIZE_16 (2) or BT_UUID_SIZE_128 (16) + uint16_t uuid16; } bleio_uuid_obj_t; diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.c b/ports/zephyr-cp/common-hal/_bleio/__init__.c index 719564c1cd4..2dfe5af0060 100644 --- a/ports/zephyr-cp/common-hal/_bleio/__init__.c +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.c @@ -9,7 +9,10 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Adapter.h" #include "common-hal/_bleio/Adapter.h" +#include "common-hal/_bleio/__init__.h" +#include "bindings/zephyr_kernel/__init__.h" #include "supervisor/shared/bluetooth/bluetooth.h" +#include "supervisor/shared/tick.h" // The singleton _bleio.Adapter object bleio_adapter_obj_t common_hal_bleio_adapter_obj; @@ -46,6 +49,132 @@ void common_hal_bleio_gc_collect(void) { bleio_adapter_gc_collect(&common_hal_bleio_adapter_obj); } -void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist) { - mp_raise_NotImplementedError(NULL); +// ======================================================================= +// Shared synchronous GATT helpers +// ======================================================================= + +typedef struct { + uint8_t *buf; + size_t buf_len; + size_t read_len; + volatile bool done; + volatile int err; +} gattc_read_ctx_t; + +typedef struct { + volatile bool done; + volatile int err; +} gattc_write_ctx_t; + +static gattc_read_ctx_t *active_read_ctx; +static gattc_write_ctx_t *active_write_ctx; +static struct bt_gatt_read_params read_params; +static struct bt_gatt_write_params write_params; + +static uint8_t on_gattc_read(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) { + gattc_read_ctx_t *ctx = active_read_ctx; + if (ctx == NULL) { + return BT_GATT_ITER_STOP; + } + + if (err) { + ctx->err = err; + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + if (data == NULL || length == 0) { + ctx->done = true; + return BT_GATT_ITER_STOP; + } + + size_t copy_len = length; + if (ctx->read_len + copy_len > ctx->buf_len) { + copy_len = ctx->buf_len - ctx->read_len; + } + if (copy_len > 0) { + memcpy(ctx->buf + ctx->read_len, data, copy_len); + ctx->read_len += copy_len; + } + + ctx->done = true; + return BT_GATT_ITER_STOP; +} + +static void on_gattc_write(struct bt_conn *conn, uint8_t err, + struct bt_gatt_write_params *params) { + gattc_write_ctx_t *ctx = active_write_ctx; + if (ctx == NULL) { + return; + } + ctx->err = err; + ctx->done = true; +} + +size_t bleio_gattc_read_sync(struct bt_conn *conn, uint16_t handle, + uint8_t *buf, size_t len) { + gattc_read_ctx_t ctx = { + .buf = buf, + .buf_len = len, + .read_len = 0, + .done = false, + .err = 0, + }; + active_read_ctx = &ctx; + + memset(&read_params, 0, sizeof(read_params)); + read_params.func = on_gattc_read; + read_params.handle_count = 1; + read_params.single.handle = handle; + read_params.single.offset = 0; + + int err = bt_gatt_read(conn, &read_params); + if (err != 0) { + active_read_ctx = NULL; + raise_zephyr_error(err); + } + + while (!ctx.done) { + RUN_BACKGROUND_TASKS; + } + active_read_ctx = NULL; + + if (ctx.err != 0) { + raise_zephyr_error(ctx.err); + } + + return ctx.read_len; +} + +void bleio_gattc_write_sync(struct bt_conn *conn, uint16_t handle, + const uint8_t *data, size_t len) { + gattc_write_ctx_t ctx = { + .done = false, + .err = 0, + }; + active_write_ctx = &ctx; + + memset(&write_params, 0, sizeof(write_params)); + write_params.func = on_gattc_write; + write_params.handle = handle; + write_params.offset = 0; + write_params.data = data; + write_params.length = len; + + int err = bt_gatt_write(conn, &write_params); + if (err != 0) { + active_write_ctx = NULL; + raise_zephyr_error(err); + } + + while (!ctx.done) { + RUN_BACKGROUND_TASKS; + } + active_write_ctx = NULL; + + if (ctx.err != 0) { + raise_zephyr_error(ctx.err); + } } diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.h b/ports/zephyr-cp/common-hal/_bleio/__init__.h index 1502767c615..63eec415311 100644 --- a/ports/zephyr-cp/common-hal/_bleio/__init__.h +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.h @@ -7,4 +7,36 @@ #pragma once -// Placeholder for Zephyr-specific BLE defines +#include + +#include +#include +#include + +#include "common-hal/_bleio/UUID.h" + +// Convert a CircuitPython bleio UUID to a Zephyr bt_uuid stored in caller- +// provided bt_uuid_128 storage. For 16-bit UUIDs we reinterpret the storage +// as bt_uuid_16 and write .val (at offset 2, matching Zephyr's struct layout). +// For 128-bit UUIDs the 16-byte value is copied directly into bt_uuid_128.val. +// The result can be used as `&out->uuid` wherever a `const struct bt_uuid *` +// is needed; Zephyr dispatches on the .type field at runtime. +static inline void bleio_uuid_to_zephyr(const bleio_uuid_obj_t *cp_uuid, + struct bt_uuid_128 *out) { + if (cp_uuid->size == BT_UUID_SIZE_16) { + out->uuid.type = BT_UUID_TYPE_16; + ((struct bt_uuid_16 *)out)->val = + (cp_uuid->uuid128[13] << 8) | cp_uuid->uuid128[12]; + } else { + out->uuid.type = BT_UUID_TYPE_128; + // Both CP and Zephyr store UUID bytes in little-endian order. + memcpy(out->val, cp_uuid->uuid128, 16); + } +} + +// Shared synchronous GATT helpers — wrap Zephyr's async bt_gatt_read/write +// into a blocking call with RUN_BACKGROUND_TASKS spinning. +size_t bleio_gattc_read_sync(struct bt_conn *conn, uint16_t handle, + uint8_t *buf, size_t len); +void bleio_gattc_write_sync(struct bt_conn *conn, uint16_t handle, + const uint8_t *data, size_t len); diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 4d446596651..72c9071bd81 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -73,7 +73,7 @@ "select", ] # Flags that don't match with with a *bindings module. Some used by adafruit_requests -MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math"] +MPCONFIG_FLAGS = ["array", "errno", "io", "json", "math", "binascii"] # extmod-based modules that should appear in the autogen list even though they # don't have shared-bindings/ or bindings/ directories. diff --git a/ports/zephyr-cp/debug.conf b/ports/zephyr-cp/debug.conf index 90c1f52d4db..9d1e3d5c0cd 100644 --- a/ports/zephyr-cp/debug.conf +++ b/ports/zephyr-cp/debug.conf @@ -4,7 +4,6 @@ CONFIG_LOG_MAX_LEVEL=4 CONFIG_STACK_SENTINEL=y CONFIG_DEBUG_THREAD_INFO=y -CONFIG_DEBUG_INFO=y CONFIG_EXCEPTION_STACK_TRACE=y CONFIG_ASSERT=y @@ -13,3 +12,12 @@ CONFIG_FRAME_POINTER=y CONFIG_FLASH_LOG_LEVEL_DBG=y CONFIG_LOG_MODE_IMMEDIATE=y + +# Bump stacks for debug build - verbose logging consumes more stack. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 +CONFIG_MAIN_STACK_SIZE=32768 +CONFIG_ISR_STACK_SIZE=4096 +CONFIG_UDC_DWC2_STACK_SIZE=4096 +CONFIG_USBD_THREAD_STACK_SIZE=4096 +CONFIG_USBD_MSC_STACK_SIZE=4096 +CONFIG_IDLE_STACK_SIZE=1024 diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index 801ea354816..a54df43e82f 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -1,6 +1,7 @@ CONFIG_SYS_HEAP_RUNTIME_STATS=n CONFIG_FLASH=y CONFIG_FLASH_MAP=y +CONFIG_USE_DT_CODE_PARTITION=y CONFIG_DYNAMIC_INTERRUPTS=y CONFIG_UART_INTERRUPT_DRIVEN=y @@ -25,7 +26,7 @@ CONFIG_USBD_MSC_LUNS_PER_INSTANCE=1 CONFIG_HWINFO=y CONFIG_REBOOT=y CONFIG_ASSERT=n -CONFIG_LOG_BLOCK_IN_THREAD=n +CONFIG_LOG_BLOCK_IN_THREAD=y CONFIG_EVENTS=y @@ -43,7 +44,12 @@ CONFIG_DYNAMIC_THREAD=y CONFIG_DYNAMIC_THREAD_ALLOC=y CONFIG_DYNAMIC_THREAD_PREFER_ALLOC=y +CONFIG_FPU=y + CONFIG_MBEDTLS=y + +# Override Kconfig default not taking effect +CONFIG_BT_BUF_ACL_RX_SIZE=255 CONFIG_MBEDTLS_BUILTIN=y CONFIG_PSA_CRYPTO=y CONFIG_PSA_WANT_ALG_SHA_1=y diff --git a/ports/zephyr-cp/tests/bsim/__init__.py b/ports/zephyr-cp/tests/bsim/__init__.py index 75136bccf43..e69de29bb2d 100644 --- a/ports/zephyr-cp/tests/bsim/__init__.py +++ b/ports/zephyr-cp/tests/bsim/__init__.py @@ -1,3 +0,0 @@ -import pytest - -pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") diff --git a/ports/zephyr-cp/tests/bsim/conftest.py b/ports/zephyr-cp/tests/bsim/conftest.py index 493f4c92b3b..a0c2c9fca27 100644 --- a/ports/zephyr-cp/tests/bsim/conftest.py +++ b/ports/zephyr-cp/tests/bsim/conftest.py @@ -16,9 +16,6 @@ logger = logging.getLogger(__name__) ZEPHYR_CP = Path(__file__).resolve().parents[2] -BSIM_BUILD_DIR = ZEPHYR_CP / "build-native_nrf5340bsim" -BSIM_SYSBUILD_BINARY = BSIM_BUILD_DIR / "zephyr/zephyr.exe" -BSIM_BINARY = BSIM_BUILD_DIR / "zephyr-cp/zephyr/zephyr.exe" BSIM_ROOT = ZEPHYR_CP / "tools/bsim" BSIM_PHY_BINARY = BSIM_ROOT / "bin/bs_2G4_phy_v1" @@ -34,14 +31,14 @@ def native_sim_env() -> dict[str, str]: return env -@pytest.fixture -def bsim_binary(): - """Return path to nrf5340bsim binary, skip if not built.""" - if BSIM_SYSBUILD_BINARY.exists(): - return BSIM_SYSBUILD_BINARY - if not BSIM_BINARY.exists(): - pytest.skip(f"nrf5340bsim not built: {BSIM_BINARY}") - return BSIM_BINARY +@pytest.fixture(params=["native_nrf5340bsim", "native_nrf54lm20bsim"]) +def board(request): + """Parametrized board fixture for bsim tests. + + Overrides the parent conftest's board fixture to run each test on both + bsim boards. + """ + return request.param @pytest.fixture @@ -177,6 +174,8 @@ def zephyr_sample(request, bsim_phy, native_sim_env, sim_id): sample_rel = str(sample).removeprefix("zephyr/samples/") source_dir = ZEPHYR_CP / "zephyr/samples" / sample_rel + if not source_dir.exists(): + source_dir = ZEPHYR_CP / sample # port-local sample if not source_dir.exists(): pytest.skip(f"Zephyr sample not found: {source_dir}") @@ -184,7 +183,21 @@ def zephyr_sample(request, bsim_phy, native_sim_env, sim_id): build_dir = ZEPHYR_CP / build_name binary = build_dir / "zephyr/zephyr.exe" + needs_rebuild = False if not binary.exists(): + needs_rebuild = True + else: + # Rebuild if any source file is newer than the binary. + binary_mtime = binary.stat().st_mtime + for root, _dirs, files in os.walk(source_dir): + for f in files: + if Path(root, f).stat().st_mtime > binary_mtime: + needs_rebuild = True + break + if needs_rebuild: + break + + if needs_rebuild: try: binary = _build_zephyr_sample(build_dir, source_dir, board) except (subprocess.CalledProcessError, RuntimeError) as exc: @@ -215,6 +228,39 @@ def zephyr_sample(request, bsim_phy, native_sim_env, sim_id): print(sample_proc.serial.all_output) +FROZEN_ROOT = (ZEPHYR_CP / "../../frozen").resolve() + + +def get_library_files(name: str) -> dict[str, str]: + """Return a dict mapping CIRCUITPY paths to file contents for all + .py files in a frozen library, suitable for circuitpy_drive. + + Looks up ``name`` under the ``frozen/`` directory (e.g. + ``get_library_files("adafruit_ble")`` walks + ``frozen/Adafruit_CircuitPython_BLE/adafruit_ble/``). + """ + files: dict[str, str] = {} + + # Try directory-style library: *//**/*.py + py_files = sorted(FROZEN_ROOT.glob(f"*/{name}/**/*.py")) + if py_files: + repo_dir = py_files[0].relative_to(FROZEN_ROOT).parts[0] + lib_parent = FROZEN_ROOT / repo_dir + for py_file in py_files: + rel = py_file.relative_to(lib_parent) + files[str(rel)] = py_file.read_text(encoding="utf-8") + return files + + # Try single-file module: */.py + py_files = list(FROZEN_ROOT.glob(f"*/{name}.py")) + if py_files: + py_file = py_files[0] + files[name + ".py"] = py_file.read_text(encoding="utf-8") + return files + + raise FileNotFoundError(f"Library {name!r} not found under {FROZEN_ROOT}") + + # pytest markers are defined inside out meaning the bottom one is first in the # list and the top is last. So use negative indices to reverse them. @pytest.fixture diff --git a/ports/zephyr-cp/tests/bsim/samples/central_battery_client/CMakeLists.txt b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/CMakeLists.txt new file mode 100644 index 00000000000..d3635c95059 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(central_battery_client) + +target_sources(app PRIVATE + src/main.c +) diff --git a/ports/zephyr-cp/tests/bsim/samples/central_battery_client/prj.conf b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/prj.conf new file mode 100644 index 00000000000..56a790677be --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/prj.conf @@ -0,0 +1,4 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_GATT_CLIENT=y +CONFIG_LOG=y diff --git a/ports/zephyr-cp/tests/bsim/samples/central_battery_client/src/main.c b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/src/main.c new file mode 100644 index 00000000000..34ed2fa09b9 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_battery_client/src/main.c @@ -0,0 +1,212 @@ +/* + * SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries + * SPDX-License-Identifier: MIT + * + * Zephyr BLE central that connects to a device named "CPSVC", + * discovers Battery Service (0x180F), reads Battery Level (0x2A19), + * prints the value, and disconnects. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +static struct bt_conn *default_conn; +static struct bt_gatt_discover_params discover_params; +static struct bt_gatt_read_params read_params; + +/* Battery Service UUID: 0x180F */ +static struct bt_uuid_16 bas_uuid = BT_UUID_INIT_16(0x180F); +/* Battery Level Characteristic UUID: 0x2A19 */ +static struct bt_uuid_16 bat_level_uuid = BT_UUID_INIT_16(0x2A19); + +static uint16_t bat_level_handle; + +static void start_scan(void); + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) { + if (default_conn) { + return; + } + + /* Only interested in connectable devices */ + if (type != BT_GAP_ADV_TYPE_ADV_IND && + type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + return; + } + + /* Clone ad data so we can parse it without affecting the original */ + struct net_buf_simple ad_copy; + uint8_t ad_buf[64]; + size_t copy_len = ad->len < sizeof(ad_buf) ? ad->len : sizeof(ad_buf); + memcpy(ad_buf, ad->data, copy_len); + net_buf_simple_init_with_data(&ad_copy, ad_buf, copy_len); + + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Found CPSVC device: %s (RSSI %d)\n", addr_str, rssi); + + if (bt_le_scan_stop()) { + return; + } + + int err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); + if (err) { + printk("Create conn failed (%d)\n", err); + start_scan(); + } +} + +static void start_scan(void) { + int err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + printk("Scanning started\n"); +} + +static uint8_t read_battery_level_cb(struct bt_conn *conn, uint8_t err, + struct bt_gatt_read_params *params, + const void *data, uint16_t length) { + if (err) { + printk("Read failed (err %d)\n", err); + } else if (data && length >= 1) { + uint8_t level = ((const uint8_t *)data)[0]; + printk("Battery Level: %d\n", level); + } else { + printk("Read returned no data\n"); + } + + /* Disconnect after reading */ + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + + return BT_GATT_ITER_STOP; +} + +static uint8_t discover_char_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + printk("Characteristic discovery complete\n"); + return BT_GATT_ITER_STOP; + } + + struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; + + if (bt_uuid_cmp(chrc->uuid, &bat_level_uuid.uuid) == 0) { + bat_level_handle = chrc->value_handle; + printk("Found Battery Level characteristic, handle: %u\n", bat_level_handle); + + /* Read the battery level */ + read_params.func = read_battery_level_cb; + read_params.handle_count = 1; + read_params.single.handle = bat_level_handle; + read_params.single.offset = 0; + + int err = bt_gatt_read(conn, &read_params); + if (err) { + printk("Read request failed (err %d)\n", err); + } + return BT_GATT_ITER_STOP; + } + + return BT_GATT_ITER_CONTINUE; +} + +static uint8_t discover_service_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + printk("Service discovery complete, BAS not found\n"); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + return BT_GATT_ITER_STOP; + } + + printk("Found Battery Service, handle: %u\n", attr->handle); + + /* Now discover characteristics within this service */ + discover_params.uuid = &bat_level_uuid.uuid; + discover_params.start_handle = attr->handle + 1; + discover_params.end_handle = 0xFFFF; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + discover_params.func = discover_char_cb; + + int err = bt_gatt_discover(conn, &discover_params); + if (err) { + printk("Characteristic discovery failed (err %d)\n", err); + } + + return BT_GATT_ITER_STOP; +} + +static void connected(struct bt_conn *conn, uint8_t err) { + char addr[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err) { + printk("Failed to connect to %s (%u)\n", addr, err); + bt_conn_unref(default_conn); + default_conn = NULL; + start_scan(); + return; + } + + if (conn != default_conn) { + return; + } + + printk("Connected: %s\n", addr); + + /* Discover Battery Service */ + discover_params.uuid = &bas_uuid.uuid; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + discover_params.func = discover_service_cb; + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + printk("Service discovery failed (err %d)\n", err); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != default_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(default_conn); + default_conn = NULL; +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +int main(void) { + int err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + printk("Bluetooth initialized\n"); + start_scan(); + return 0; +} diff --git a/ports/zephyr-cp/tests/bsim/samples/central_nus_client/CMakeLists.txt b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/CMakeLists.txt new file mode 100644 index 00000000000..d5deacef980 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: MIT + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(central_nus_client) + +target_sources(app PRIVATE + src/main.c +) diff --git a/ports/zephyr-cp/tests/bsim/samples/central_nus_client/prj.conf b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/prj.conf new file mode 100644 index 00000000000..56a790677be --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/prj.conf @@ -0,0 +1,4 @@ +CONFIG_BT=y +CONFIG_BT_CENTRAL=y +CONFIG_BT_GATT_CLIENT=y +CONFIG_LOG=y diff --git a/ports/zephyr-cp/tests/bsim/samples/central_nus_client/src/main.c b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/src/main.c new file mode 100644 index 00000000000..9825a3e7a5e --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/central_nus_client/src/main.c @@ -0,0 +1,302 @@ +/* + * SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries + * SPDX-License-Identifier: MIT + * + * Zephyr BLE central that connects to a device named "CPNUS", + * discovers Nordic UART Service (NUS), writes to the RX characteristic, + * subscribes to TX notifications, receives data, and disconnects. + * + * NUS UUIDs: + * Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E + * TX (peripheral→central, notify): 6E400003-B5A3-F393-E0A9-E50E24DCCA9E + * RX (central→peripheral, write): 6E400002-B5A3-F393-E0A9-E50E24DCCA9E + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +static struct bt_conn *default_conn; +static struct bt_gatt_discover_params discover_params; + +/* Real NUS 128-bit UUIDs in little-endian byte order. + * These match the standard Nordic UART Service UUIDs: + * Service: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E + * TX: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E + * RX: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E + */ +static struct bt_uuid_128 nus_service_uuid = BT_UUID_INIT_128( + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E); +static struct bt_uuid_128 nus_tx_uuid = BT_UUID_INIT_128( + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x03, 0x00, 0x40, 0x6E); +static struct bt_uuid_128 nus_rx_uuid = BT_UUID_INIT_128( + 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, + 0x93, 0xF3, 0xA3, 0xB5, 0x02, 0x00, 0x40, 0x6E); + +static uint16_t tx_handle; +static uint16_t rx_handle; +static bool tx_notify_enabled; +static bool rx_written; +static bool received; +static uint8_t received_data[32]; +static uint16_t received_len; + +static void start_scan(void); + +/* Check if advertisement data contains a name */ +static bool ad_has_name(struct net_buf_simple *ad, const char *name) { + size_t name_len = strlen(name); + + while (ad->len > 1) { + uint8_t field_len = net_buf_simple_pull_u8(ad); + if (field_len == 0 || field_len > ad->len) { + break; + } + uint8_t type = net_buf_simple_pull_u8(ad); + field_len--; + + if ((type == BT_DATA_NAME_COMPLETE || type == BT_DATA_NAME_SHORTENED) && + field_len == name_len && + memcmp(ad->data, name, name_len) == 0) { + return true; + } + net_buf_simple_pull(ad, field_len); + } + return false; +} + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) { + if (default_conn) { + return; + } + + /* Only interested in connectable devices */ + if (type != BT_GAP_ADV_TYPE_ADV_IND && + type != BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { + return; + } + + /* Clone ad data so we can parse it */ + struct net_buf_simple ad_copy; + uint8_t ad_buf[64]; + size_t copy_len = ad->len < sizeof(ad_buf) ? ad->len : sizeof(ad_buf); + memcpy(ad_buf, ad->data, copy_len); + net_buf_simple_init_with_data(&ad_copy, ad_buf, copy_len); + + if (!ad_has_name(&ad_copy, "CPNUS")) { + return; + } + + char addr_str[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(addr, addr_str, sizeof(addr_str)); + printk("Found CPNUS device: %s (RSSI %d)\n", addr_str, rssi); + + if (bt_le_scan_stop()) { + return; + } + + int err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, + BT_LE_CONN_PARAM_DEFAULT, &default_conn); + if (err) { + printk("Create conn failed (%d)\n", err); + start_scan(); + } +} + +static void start_scan(void) { + int err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found); + if (err) { + printk("Scanning failed to start (err %d)\n", err); + return; + } + printk("Scanning started\n"); +} + +/* TX notification callback */ +static uint8_t on_tx_notify(struct bt_conn *conn, + struct bt_gatt_subscribe_params *params, + const void *data, uint16_t length) { + if (data) { + memcpy(received_data, data, length < sizeof(received_data) ? + length : sizeof(received_data)); + received_len = length; + received = true; + printk("NUS: received '"); + for (uint16_t i = 0; i < received_len; i++) { + printk("%c", received_data[i]); + } + printk("'\n"); + + /* Disconnect after receiving response */ + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } + return BT_GATT_ITER_CONTINUE; +} + +static struct bt_gatt_subscribe_params tx_subscribe_params; + +/* Step 5: Subscribe to TX notifications */ +static void subscribe_tx(struct bt_conn *conn) { + tx_subscribe_params.notify = on_tx_notify; + tx_subscribe_params.value = BT_GATT_CCC_NOTIFY; + tx_subscribe_params.value_handle = tx_handle; + tx_subscribe_params.ccc_handle = tx_handle + 1; + + int err = bt_gatt_subscribe(conn, &tx_subscribe_params); + if (err) { + printk("TX subscribe failed (err %d)\n", err); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + } else { + tx_notify_enabled = true; + printk("TX notify enabled\n"); + } +} + +/* Step 4: Write to RX characteristic (central→peripheral) using write-without-response */ +static void write_rx(struct bt_conn *conn) { + static uint8_t data[] = "Hello"; + + int err = bt_gatt_write_without_response(conn, rx_handle, + data, 5, false); + if (err) { + printk("RX write request failed (err %d)\n", err); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + return; + } + rx_written = true; + printk("RX write complete\n"); + + /* Now subscribe to TX to receive the response */ + subscribe_tx(conn); +} + +/* Step 3: Discover characteristics to find TX and RX handles */ +static uint8_t discover_char_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + printk("Characteristic discovery complete\n"); + if (rx_handle == 0 || tx_handle == 0) { + printk("NUS characteristics not found\n"); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + return BT_GATT_ITER_STOP; + } + if (rx_handle) { + printk("Writing to RX...\n"); + write_rx(conn); + } + return BT_GATT_ITER_STOP; + } + + struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data; + + if (bt_uuid_cmp(chrc->uuid, &nus_rx_uuid.uuid) == 0) { + rx_handle = chrc->value_handle; + printk("Found NUS RX, handle: %u\n", rx_handle); + } else if (bt_uuid_cmp(chrc->uuid, &nus_tx_uuid.uuid) == 0) { + tx_handle = chrc->value_handle; + printk("Found NUS TX, handle: %u\n", tx_handle); + } + + return BT_GATT_ITER_CONTINUE; +} + +/* Step 2: Discover characteristics within the NUS service */ +static uint8_t discover_service_cb(struct bt_conn *conn, + const struct bt_gatt_attr *attr, + struct bt_gatt_discover_params *params) { + if (!attr) { + printk("Service discovery complete, NUS not found\n"); + bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); + return BT_GATT_ITER_STOP; + } + + printk("Found NUS, handle: %u\n", attr->handle); + + /* Discover characteristics within this service */ + discover_params.uuid = NULL; + discover_params.start_handle = attr->handle + 1; + discover_params.end_handle = 0xFFFF; + discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; + discover_params.func = discover_char_cb; + + int err = bt_gatt_discover(conn, &discover_params); + if (err) { + printk("Char discovery failed (err %d)\n", err); + } + + return BT_GATT_ITER_STOP; +} + +/* Step 1: Connected - discover NUS */ +static void connected(struct bt_conn *conn, uint8_t err) { + char addr[BT_ADDR_LE_STR_LEN]; + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + + if (err) { + printk("Failed to connect to %s (%u)\n", addr, err); + bt_conn_unref(default_conn); + default_conn = NULL; + start_scan(); + return; + } + + if (conn != default_conn) { + return; + } + + printk("Connected: %s\n", addr); + + /* Discover NUS */ + discover_params.uuid = &nus_service_uuid.uuid; + discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE; + discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE; + discover_params.type = BT_GATT_DISCOVER_PRIMARY; + discover_params.func = discover_service_cb; + + err = bt_gatt_discover(conn, &discover_params); + if (err) { + printk("Service discovery failed (err %d)\n", err); + } +} + +static void disconnected(struct bt_conn *conn, uint8_t reason) { + char addr[BT_ADDR_LE_STR_LEN]; + + if (conn != default_conn) { + return; + } + + bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); + printk("Disconnected: %s (reason 0x%02x)\n", addr, reason); + + bt_conn_unref(default_conn); + default_conn = NULL; +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = connected, + .disconnected = disconnected, +}; + +int main(void) { + int err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + printk("Bluetooth initialized\n"); + start_scan(); + return 0; +} diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py index 477292ddd54..96f40a86b40 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py @@ -1,11 +1,11 @@ # SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""Basic BabbleSim connectivity tests for nrf5340bsim.""" +"""Basic BabbleSim connectivity tests for bsim.""" import pytest -pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") +from .conftest import get_library_files BSIM_CODE = """\ print("bsim ready") @@ -15,7 +15,7 @@ @pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) @pytest.mark.duration(3) -def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2): +def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2, board): """Run two bsim instances on the same sim id and verify UART output.""" # Wait for both devices to complete before checking output. @@ -25,7 +25,31 @@ def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2): output0 = circuitpython1.serial.all_output output1 = circuitpython2.serial.all_output - assert "Board ID:native_nrf5340bsim" in output0 - assert "Board ID:native_nrf5340bsim" in output1 + assert f"Board ID:{board}" in output0 + assert f"Board ID:{board}" in output1 assert "bsim ready" in output0 assert "bsim ready" in output1 + + +# --- adafruit_ble library import --- + +BSIM_BLE_IMPORT_CODE = """\ +import adafruit_ble + +print("adafruit_ble version", adafruit_ble.__version__) +print("adafruit_ble repo", adafruit_ble.__repo__) +print("done") +""" + + +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_BLE_IMPORT_CODE, **get_library_files("adafruit_ble")} +) +def test_bsim_ble_library_import(bsim_phy, circuitpython): + """Import adafruit_ble from CIRCUITPY and verify basic attributes.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "adafruit_ble version" in output + assert "adafruit_ble repo" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_adapter.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_adapter.py new file mode 100644 index 00000000000..5a15bb03d74 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_adapter.py @@ -0,0 +1,140 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE adapter state tests for bsim.""" + +import pytest + + +# --- Enable/disable cycle --- + +BSIM_ENABLE_DISABLE_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +# Check initial state (should be enabled after boot) +print("enabled start", adapter.enabled) + +# Disable +adapter.enabled = False +print("enabled false", adapter.enabled) + +# Re-enable +adapter.enabled = True +print("enabled true", adapter.enabled) + +# Verify it reports as enabled +print("enabled final", adapter.enabled) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_ENABLE_DISABLE_CODE}) +def test_bsim_adapter_enable_disable(bsim_phy, circuitpython): + """Toggle adapter.enabled and verify state.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "enabled start True" in output + assert "enabled false False" in output + assert "enabled true True" in output + assert "enabled final True" in output + assert "done" in output + + +# --- Disable stops advertising --- + +BSIM_DISABLE_STOPS_ADV_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +name = b"CPADV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +adapter.start_advertising(advertisement, connectable=False) +print("advertising", adapter.advertising) + +adapter.enabled = False +print("advertising after disable", adapter.advertising) + +adapter.enabled = True +print("advertising after enable", adapter.advertising) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_DISABLE_STOPS_ADV_CODE}) +def test_bsim_adapter_disable_stops_advertising(bsim_phy, circuitpython): + """Disabling the adapter stops advertising.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "advertising True" in output + assert "advertising after disable False" in output + assert "advertising after enable False" in output + assert "done" in output + + +# --- Adapter state across soft reload --- + +BSIM_ENABLE_RELOAD_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +print("enabled", adapter.enabled) +print("advertising", adapter.advertising) +print("connected", adapter.connected) +print("done") +""" + + +@pytest.mark.code_py_runs(2) +@pytest.mark.circuitpy_drive({"code.py": BSIM_ENABLE_RELOAD_CODE}) +def test_bsim_adapter_state_after_reload(bsim_phy, circuitpython): + """Adapter state is clean after soft reload.""" + circuitpython.serial.wait_for("done") + circuitpython.serial.wait_for("Press any key to enter the REPL") + circuitpython.serial.write("\x04") + + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert output.count("enabled True") >= 2 + assert output.count("advertising False") >= 2 + assert output.count("connected False") >= 2 + + +# --- Adapter name truncation --- + +BSIM_NAME_TRUNCATION_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +# Set a very long name +long_name = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%" +adapter.name = long_name + +# Read back — should be truncated to fit CONFIG_BT_DEVICE_NAME_MAX +name = adapter.name +print("name len", len(name)) +print("name", name) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_NAME_TRUNCATION_CODE}) +def test_bsim_adapter_name_truncation(bsim_phy, circuitpython): + """Very long adapter.name is truncated to fit Zephyr limit.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "name len" in output + # Should be truncated — length must be less than input (72 chars) + name_line = [l for l in output.split("\n") if "name len" in l][0] + name_len = int(name_line.split()[-1]) + assert name_len < 72 + assert "done" in output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py index 33680fe2506..a3b00b0b055 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -1,14 +1,13 @@ # SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""BLE advertising tests for nrf5340bsim.""" +"""BLE advertising tests for bsim.""" import logging import re import pytest -pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") logger = logging.getLogger(__name__) @@ -128,7 +127,7 @@ def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): @pytest.mark.zephyr_sample("bluetooth/observer") @pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_DEFAULT_CODE}) -def test_bsim_tx_power_default_rssi(bsim_phy, circuitpython, zephyr_sample): +def test_bsim_tx_power_default_rssi(board, bsim_phy, circuitpython, zephyr_sample): """Verify default TX power produces expected RSSI.""" observer = zephyr_sample @@ -142,13 +141,16 @@ def test_bsim_tx_power_default_rssi(bsim_phy, circuitpython, zephyr_sample): # Observer: "Device found: (RSSI ), type , AD data len " # Advertisement is 12 bytes: flags (3) + name (9). - # With 40 dB channel attenuation and 0 dBm TX → RSSI ~ -39 + # With 40 dB channel attenuation and 0 dBm TX → RSSI ~ -39. + # nRF54l bsim model has a TXPOWER register mapping discrepancy that + # reads 0 dBm as 2 dBm, giving RSSI ~ -37 instead. + expected_rssi = -37 if "nrf54" in board else -39 rssi_pattern = re.compile(r"RSSI (-?\d+)\), type \d+, AD data len 12") all_rssi = [int(m.group(1)) for m in rssi_pattern.finditer(obs_output)] logger.info("RSSI values: %s", all_rssi) assert len(all_rssi) > 0, "Observer saw no advertisements" - assert all_rssi[0] == -39, f"Expected RSSI -39 (0 dBm TX), got {all_rssi[0]}" + assert all_rssi[0] == expected_rssi, f"Expected RSSI {expected_rssi}, got {all_rssi[0]}" @pytest.mark.zephyr_sample("bluetooth/observer") diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py index 21cfeaf79da..8d3c1f2594a 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_connect.py @@ -1,11 +1,10 @@ # SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""BLE central connection tests for nrf5340bsim.""" +"""BLE central connection tests for bsim.""" import pytest -pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") BSIM_CONNECT_CODE = """\ import _bleio diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py new file mode 100644 index 00000000000..d1b07859133 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py @@ -0,0 +1,131 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE descriptor tests for bsim.""" + +import pytest + +# =================================================================== +# Server: characteristic with user_description +# =================================================================== + +BSIM_DESC_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0x180F)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0x2A19), + properties=_bleio.Characteristic.READ, + read_perm=_bleio.Attribute.OPEN, + write_perm=_bleio.Attribute.NO_ACCESS, + max_length=1, fixed_length=True, initial_value=bytes([75]), + user_description="Battery Level", +) +print("service created") + +# Check local descriptors list +descs = char.descriptors +print("num descriptors", len(descs)) +for d in descs: + print("desc uuid", d.uuid.uuid16) + print("desc value", list(d.value)) + +name = b"CPDESC" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +# =================================================================== +# Client: connects and reads the remote user description +# =================================================================== + +BSIM_DESC_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("client start") +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPDESC" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0x180F)]) +char = services[0].characteristics[0] + +print("char value", list(char.value)) + +descs = char.descriptors +print("num descriptors", len(descs)) +for d in descs: + print("desc uuid", hex(d.uuid.uuid16)) + print("desc value", list(d.value)) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_DESC_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_DESC_CLIENT_CODE}) +def test_bsim_descriptor_user_description(bsim_phy, circuitpython1, circuitpython2): + """Server creates a characteristic with user_description; + client discovers the service and reads the descriptor.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + # Server: user_description creates a CUD descriptor (0x2901) on the characteristic + assert "service created" in server_output + assert "num descriptors 1" in server_output + assert "desc uuid 10497" in server_output # 0x2901 + assert ( + "desc value [66, 97, 116, 116, 101, 114, 121, 32, 76, 101, 118, 101, 108]" in server_output + ) + assert "connected True" in server_output + + # Client: discovers and reads the remote descriptor + assert "found server" in client_output + assert "char value [75]" in client_output + assert "num descriptors 1" in client_output + assert "desc uuid 0x2901" in client_output + assert ( + "desc value [66, 97, 116, 116, 101, 114, 121, 32, 76, 101, 118, 101, 108]" in client_output + ) + assert "done" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py index 69435d38256..c5d2edce123 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py @@ -1,11 +1,10 @@ # SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""BLE name tests for nrf5340bsim.""" +"""BLE name tests for bsim.""" import pytest -pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") BSIM_NAME_CODE = """\ import _bleio diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py new file mode 100644 index 00000000000..bb589cf9d90 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py @@ -0,0 +1,177 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Nordic UART Service (NUS) tests for bsim — using adafruit_ble library.""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") + +# ---- Test 1: CP peripheral hosts NUS, Zephyr central writes and reads ---- + +BSIM_NUS_PERIPHERAL_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.services.nordic import UARTService + +ble = BLERadio() +uart = UARTService() +print("service created") + +advertisement = ProvideServicesAdvertisement(uart) +advertisement.complete_name = "CPNUS" +ble.start_advertising(advertisement) +print("advertising") + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +# Wait for data to arrive from central +data = uart.read(5) +print("received", data) + +# Send a response back +uart.write(b"World") +print("sent response") + +time.sleep(1.0) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.zephyr_sample("tests/bsim/samples/central_nus_client") +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_NUS_PERIPHERAL_CODE, **_ADAFRUIT_BLE}) +def test_bsim_nus_peripheral(bsim_phy, circuitpython, zephyr_sample): + """CP hosts NUS peripheral; Zephyr central writes to RX, reads TX notifications.""" + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + sample_output = zephyr_sample.serial.all_output + + assert "service created" in cp_output + assert "connected True" in cp_output + assert "received" in cp_output + assert "sent response" in cp_output + assert "NUS: received 'World'" in sample_output + + +# ---- Test 2: CP-to-CP NUS (peripheral + central) ---- + +BSIM_NUS_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.services.nordic import UARTService + +ble = BLERadio() +uart = UARTService() +print("service created") + +advertisement = ProvideServicesAdvertisement(uart) +advertisement.complete_name = "CP2CP" +ble.start_advertising(advertisement) +print("advertising") + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +# Read incoming data from central +data = uart.read(6) +print("received", data) + +# Respond back +uart.write(b"OK!") +print("sent response") + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_NUS_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.services.nordic import UARTService + +ble = BLERadio() + +print("client start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=8.0): + if adv.connectable and adv.complete_name == "CP2CP": + target = adv + print("found server") + break +ble.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) +print("connected", connection.connected) + +uart = connection[UARTService] +print("discovered services", 1) + +# Write to server +uart.write(b"Hello!") +print("wrote to rx") + +data = uart.read(3) +print("received", data) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_NUS_SERVER_CODE, **_ADAFRUIT_BLE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_NUS_CLIENT_CODE, **_ADAFRUIT_BLE}) +def test_bsim_nus_cp_to_cp(bsim_phy, circuitpython1, circuitpython2): + """CP peripheral hosts NUS; CP central writes to RX, reads TX via notifications.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "received" in server_output + assert "sent response" in server_output + + assert "client start" in client_output + assert "found server" in client_output + assert "have target True" in client_output + assert "connected True" in client_output + assert "discovered services 1" in client_output + assert "wrote to rx" in client_output + assert "received b'OK!'" in client_output + assert "done" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py new file mode 100644 index 00000000000..efda0637aa3 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py @@ -0,0 +1,785 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""PacketBuffer tests for bsim.""" + +import pytest + + +# ---- Test 1: Server-side PacketBuffer incoming (WRITE characteristic) ---- + +BSIM_PB_SERVER_IN_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +# Wrap in PacketBuffer for incoming packets +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBIN" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Read first incoming packet +data = bytearray(20) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("packet1", data[:n]) + +# Read second incoming packet +n2 = 0 +deadline2 = time.monotonic() + 5.0 +while n2 == 0 and time.monotonic() < deadline2: + n2 = pb.readinto(data) + if n2 == 0: + time.sleep(0.05) +print("packet2", data[:n2]) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_CLIENT_IN_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBIN" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +print("discovered services", len(services)) + +remote_char = services[0].characteristics[0] +print("found char") + +# Write two packets +remote_char.value = bytes([0x01, 0x02, 0x03, 0x04]) +print("wrote packet1") + +time.sleep(0.3) + +remote_char.value = bytes([0xAA, 0xBB, 0xCC, 0xDD, 0xEE]) +print("wrote packet2") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_SERVER_IN_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_IN_CODE}) +def test_bsim_packet_buffer_server_incoming(bsim_phy, circuitpython1, circuitpython2): + """PacketBuffer on server-side WRITE characteristic receives framed packets.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "packet1" in server_output + assert "packet2" in server_output + assert "done" in server_output + + assert "found server" in client_output + assert "wrote packet1" in client_output + assert "wrote packet2" in client_output + + +# ---- Test 2: Server-side PacketBuffer write/flush (NOTIFY response) ---- + +BSIM_PB_BIDI_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +# Wrap in PacketBuffer for incoming packets and outgoing notifications +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBBI" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Read incoming packet from client +data = bytearray(20) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("received", data[:n]) + +# Write response back (via NOTIFY) — sends immediately via completion callback +pb.write(bytes([0x52, 0x45, 0x53, 0x50])) # "RESP" +print("sent response") + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_BIDI_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBBI" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +print("discovered services", len(services)) + +remote_char = services[0].characteristics[0] +print("found char, props", remote_char.properties) + +# Write a packet to the server +remote_char.value = bytes([0x48, 0x45, 0x4C, 0x4C, 0x4F]) # "HELLO" +print("wrote hello") + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_BIDI_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_BIDI_CLIENT_CODE}) +def test_bsim_packet_buffer_bidirectional(bsim_phy, circuitpython1, circuitpython2): + """Bidirectional PacketBuffer: server receives WRITE, sends NOTIFY response.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "received" in server_output + assert "sent response" in server_output + assert "done" in server_output + + assert "found server" in client_output + assert "wrote hello" in client_output + assert "done" in client_output + + +# ---- Test 3: PacketBuffer with multiple queued incoming packets ---- + +BSIM_PB_QUEUE_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +# Small buffer: only 1 packet, small max_packet_size +pb = _bleio.PacketBuffer(char, buffer_size=1, max_packet_size=10) +print("service created") + +name = b"CPPBQU" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Wait for client to send all packets +time.sleep(1.0) + +# Read packets - with buffer_size=1, oldest packets are dropped +data = bytearray(20) + +n1 = pb.readinto(data) +print("pkt1", data[:n1]) + +n2 = pb.readinto(data) +print("pkt2", data[:n2]) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_QUEUE_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBQU" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write 3 packets quickly (buffer only holds 2, so oldest should be dropped) +remote_char.value = bytes([0x01, 0x02, 0x03]) +print("wrote pkt1") + +time.sleep(0.1) + +remote_char.value = bytes([0x04, 0x05, 0x06]) +print("wrote pkt2") + +time.sleep(0.1) + +remote_char.value = bytes([0x07, 0x08, 0x09]) +print("wrote pkt3") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_QUEUE_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_QUEUE_CLIENT_CODE}) +def test_bsim_packet_buffer_queue(bsim_phy, circuitpython1, circuitpython2): + """PacketBuffer queues multiple packets; oldest dropped when buffer full.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + # With buffer_size=1, only the last packet(s) remain + assert "pkt1" in server_output + assert "pkt2" in server_output + assert "done" in server_output + + assert "wrote pkt1" in client_output + assert "wrote pkt2" in client_output + assert "wrote pkt3" in client_output + + +# ---- Test 4: readinto with buffer too small returns negative ---- + +BSIM_PB_OVERFLOW_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBOV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Try to read a 5-byte packet into a 3-byte buffer -> ValueError +try: + data = bytearray(3) + n = 0 + deadline = time.monotonic() + 5.0 + while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) + print("unexpected success", n) +except ValueError as e: + print("valueerror", e) + +time.sleep(0.5) +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_OVERFLOW_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBOV" in entry.advertisement_bytes: + target = entry.address + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write a 5-byte packet, but server only has a 3-byte read buffer +remote_char.value = bytes([0x01, 0x02, 0x03, 0x04, 0x05]) +print("wrote 5 bytes") + +time.sleep(0.5) +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_OVERFLOW_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_OVERFLOW_CLIENT_CODE}) +def test_bsim_packet_buffer_readinto_overflow(bsim_phy, circuitpython1, circuitpython2): + """readinto returns negative when packet is larger than buffer.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "valueerror" in server_output + + assert "wrote 5 bytes" in client_output + + +# ---- Test 5: write() with header kwarg ---- + +BSIM_PB_HEADER_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBHD" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Read an incoming packet +data = bytearray(20) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("received", data[:n]) + +# Response: write body with a header — header goes at start of packet +pb.write(bytes([0x42, 0x4F, 0x44, 0x59]), header=bytes([0x48, 0x44])) # "HD" + "BODY" +print("sent with header") + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_HEADER_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBHD" in entry.advertisement_bytes: + target = entry.address + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write a packet to trigger the server's response +remote_char.value = bytes([0x47, 0x4F]) +print("wrote trigger") + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_HEADER_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_HEADER_CLIENT_CODE}) +def test_bsim_packet_buffer_write_header(bsim_phy, circuitpython1, circuitpython2): + """write() header kwarg prepends to packet body.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "received" in server_output + assert "sent with header" in server_output + + assert "wrote trigger" in client_output + + +# ---- Test 6: incoming_packet_length / outgoing_packet_length ---- + +BSIM_PB_LENGTHS_CODE = """\ +import _bleio + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +pb = _bleio.PacketBuffer(char, buffer_size=2, max_packet_size=15) + +# incoming_packet_length reflects the max we can receive (characteristic max_length) +print("incoming", pb.incoming_packet_length) +# outgoing_packet_length is capped by max_packet_size +print("outgoing", pb.outgoing_packet_length) +print("done") +""" + + +@pytest.mark.duration(5) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_LENGTHS_CODE}) +def test_bsim_packet_buffer_packet_lengths(bsim_phy, circuitpython): + """incoming_packet_length and outgoing_packet_length properties.""" + circuitpython.wait_until_done() + output = circuitpython.serial.all_output + + # Server-side local characteristic: + # incoming = max_length = 20 + # outgoing = min(max_packet_size, max_length) = min(15, 20) = 15 + assert "incoming 20" in output + assert "outgoing 15" in output + assert "done" in output + + +# ---- Test 7: disconnect / reconnect, conn tracking ---- + +BSIM_PB_RECONNECT_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBRC" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) + +# First connection +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected1", adapter.connected) + +# Read first packet +data = bytearray(20) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("packet1", data[:n]) + +# Send a response to confirm the tracked conn works +pb.write(bytes([0x41, 0x43, 0x4B])) # "ACK" +print("sent ack1") + +# Wait for disconnect +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("disconnected") + +# Start advertising again for second connection +adapter.start_advertising(advertisement, connectable=True) + +# Second connection +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected2", adapter.connected) + +# Read second packet (should track new conn) +n2 = 0 +deadline2 = time.monotonic() + 5.0 +while n2 == 0 and time.monotonic() < deadline2: + n2 = pb.readinto(data) + if n2 == 0: + time.sleep(0.05) +print("packet2", data[:n2]) + +pb.write(bytes([0x41, 0x43, 0x4B])) # "ACK" +print("sent ack2") + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_RECONNECT_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +# First connection +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBRC" in entry.advertisement_bytes: + target = entry.address + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected1", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write first packet +remote_char.value = bytes([0x46, 0x49, 0x52, 0x53, 0x54]) # "FIRST" +print("wrote first") + +time.sleep(0.5) + +# Disconnect +connection.disconnect() +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("disconnected") + +# Wait for server to re-advertise +time.sleep(0.5) + +# Second connection +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBRC" in entry.advertisement_bytes: + target = entry.address + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected2", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] + +# Write second packet +remote_char.value = bytes([0x53, 0x45, 0x43, 0x4E, 0x44]) # "SECOND" +print("wrote second") + +time.sleep(0.5) +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_RECONNECT_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_RECONNECT_CLIENT_CODE}) +def test_bsim_packet_buffer_reconnect(bsim_phy, circuitpython1, circuitpython2): + """PacketBuffer tracks conn through disconnect / reconnect.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected1 True" in server_output + assert "packet1" in server_output + assert "sent ack1" in server_output + assert "disconnected" in server_output + assert "connected2 True" in server_output + assert "packet2" in server_output + assert "sent ack2" in server_output + + assert "wrote first" in client_output + assert "wrote second" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py index 7a4bbfaecd9..89088fb9f87 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py @@ -1,11 +1,10 @@ # SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""BLE peripheral connection tests for nrf5340bsim.""" +"""BLE peripheral connection tests for bsim.""" import pytest -pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") BSIM_PERIPHERAL_CODE = """\ import _bleio diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py index 19455b7bfa3..a2618a851f2 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -1,11 +1,10 @@ # SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""BLE scanning tests for nrf5340bsim.""" +"""BLE scanning tests for bsim.""" import pytest -pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") BSIM_SCAN_CODE = """\ import _bleio @@ -56,6 +55,45 @@ print("scan run done", found) """ +BSIM_SCAN_ENTRY_PROPS_CODE = """\ +import _bleio + +adapter = _bleio.adapter +print("scan start") +found = None +for entry in adapter.start_scan(timeout=4.0, active=True): + if b"zephyrproject" in entry.advertisement_bytes: + found = entry + break +adapter.stop_scan() + +if found is not None: + print("rssi", found.rssi <= 0 and found.rssi > -100) + print("connectable", found.connectable) + print("scan_response", found.scan_response) + print("address_bytes", len(found.address.address_bytes)) + print("address_type", found.address.type in (0, 1, 2, 3)) + print("adv_bytes_type", isinstance(found.advertisement_bytes, bytes)) +else: + print("no entry found") +print("done") +""" + +BSIM_SCAN_PASSIVE_CODE = """\ +import _bleio + +adapter = _bleio.adapter +print("scan passive start") +found = False +for entry in adapter.start_scan(timeout=4.0, active=False): + if b"zephyrproject" in entry.advertisement_bytes: + print("found beacon passive") + found = True + break +adapter.stop_scan() +print("scan passive done", found) +""" + @pytest.mark.zephyr_sample("bluetooth/beacon") @pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_CODE}) @@ -91,22 +129,33 @@ def test_bsim_scan_zephyr_beacon_reload(bsim_phy, circuitpython, zephyr_sample): assert output.count("scan run done True") >= 2 -@pytest.mark.xfail(strict=False, reason="scan without stop_scan may fail on reload") @pytest.mark.zephyr_sample("bluetooth/beacon") -@pytest.mark.code_py_runs(2) -@pytest.mark.duration(8) -@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_NO_STOP_CODE}) -def test_bsim_scan_zephyr_beacon_reload_no_stop(bsim_phy, circuitpython, zephyr_sample): - """Scan for Zephyr beacon without explicit stop, soft reload, and scan again.""" +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_ENTRY_PROPS_CODE}) +def test_bsim_scan_entry_properties(bsim_phy, circuitpython, zephyr_sample): + """Verify ScanEntry properties: rssi, connectable, scan_response, address, advertisement_bytes.""" _ = zephyr_sample - circuitpython.serial.wait_for("scan run done") - circuitpython.serial.wait_for("Press any key to enter the REPL") - circuitpython.serial.write("\x04") + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "rssi True" in output + assert "connectable False" in output # beacon is non-connectable + assert "scan_response False" in output + assert "address_bytes 6" in output + assert "address_type True" in output + assert "adv_bytes_type True" in output + assert "done" in output + + +@pytest.mark.zephyr_sample("bluetooth/beacon") +@pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_PASSIVE_CODE}) +def test_bsim_scan_passive(bsim_phy, circuitpython, zephyr_sample): + """Passive scan finds Zephyr beacon.""" + _ = zephyr_sample circuitpython.wait_until_done() output = circuitpython.serial.all_output - assert output.count("scan run start") >= 2 - assert output.count("found beacon run") >= 2 - assert output.count("scan run done True") >= 2 + assert "scan passive start" in output + assert "found beacon passive" in output + assert "scan passive done True" in output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py new file mode 100644 index 00000000000..eb83c016b3a --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py @@ -0,0 +1,710 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE GATT service tests for bsim.""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") + +# --------------------------------------------------------------------------- +# Shared service libraries +# --------------------------------------------------------------------------- + +BATTERY_LIB = """ +from adafruit_ble.services import Service +from adafruit_ble.characteristics import Characteristic, Attribute +from adafruit_ble.uuid import StandardUUID + + +class BatteryService(Service): + uuid = StandardUUID(0x180F) + level = Characteristic( + uuid=StandardUUID(0x2A19), + properties=Characteristic.READ | Characteristic.WRITE, + read_perm=Attribute.OPEN, + write_perm=Attribute.OPEN, + max_length=1, + fixed_length=True, + initial_value=bytes([75]), + )""" + +HEART_RATE_LIB = """ +from adafruit_ble.services import Service +from adafruit_ble.characteristics import Characteristic, Attribute +from adafruit_ble.uuid import StandardUUID + + +class HeartRateService(Service): + uuid = StandardUUID(0x180D) + measurement = Characteristic( + uuid=StandardUUID(0x2A37), + properties=Characteristic.READ, + read_perm=Attribute.OPEN, + write_perm=Attribute.NO_ACCESS, + max_length=2, + fixed_length=True, + initial_value=bytes([0, 72]), + )""" + +# =================================================================== +# Test 1: Battery Service (Zephyr central) +# =================================================================== + +BSIM_SERVICE_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService + +ble = BLERadio() +svc = BatteryService() +print("service created") + +advertisement = ProvideServicesAdvertisement(svc) +ble.start_advertising(advertisement) +print("advertising") + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.zephyr_sample("tests/bsim/samples/central_battery_client") +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_SERVICE_CODE, "battery_service.py": BATTERY_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_battery(bsim_phy, circuitpython, zephyr_sample): + """CP hosts BatteryService; Zephyr central reads battery level.""" + circuitpython.wait_until_done() + + cp_output = circuitpython.serial.all_output + sample_output = zephyr_sample.serial.all_output + + assert "service created" in cp_output + assert "connected True" in cp_output + assert "Battery Level: 75" in sample_output + + +# =================================================================== +# Test 2: CP client reads/writes CP peripheral +# =================================================================== + +BSIM_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService + +ble = BLERadio() +svc = BatteryService() +print("service created") + +advertisement = ProvideServicesAdvertisement(svc) +ble.start_advertising(advertisement) +print("advertising") + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) + +print("final value", list(svc.level)) +print("done") +""" + +BSIM_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService + +ble = BLERadio() + +print("client start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + print("found server") + break +ble.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) +print("connected", connection.connected) + +svc = connection[BatteryService] +print("discovered services", 1) +print("discovered chars", 1) # BatteryService has one characteristic + +print("battery level", list(svc.level)) + +# Write a new value +svc.level = bytes([42]) +print("wrote new value") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("disconnected", not connection.connected) +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_SERVER_CODE, "battery_service.py": BATTERY_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CLIENT_CODE, "battery_service.py": BATTERY_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_cp_client(bsim_phy, circuitpython1, circuitpython2): + """CP peripheral hosts BatteryService; CP central discovers, reads, and writes.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "final value [42]" in server_output + + assert "client start" in client_output + assert "found server" in client_output + assert "discovered services 1" in client_output + assert "discovered chars 1" in client_output + assert "battery level [75]" in client_output + assert "wrote new value" in client_output + assert "disconnected True" in client_output + + +# =================================================================== +# Test 3: Discover all services (no whitelist) +# =================================================================== + +BSIM_DISCOVER_ALL_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService +from heart_rate import HeartRateService + +ble = BLERadio() +bas = BatteryService() +hrs = HeartRateService() +print("services created") + +advertisement = ProvideServicesAdvertisement(bas, hrs) +ble.start_advertising(advertisement) + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_DISCOVER_ALL_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from battery_service import BatteryService +from heart_rate import HeartRateService + +ble = BLERadio() + +print("client start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=8.0): + if adv.connectable: + target = adv + print("found server") + break +ble.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) +print("connected", connection.connected) + +# Discover ALL services (no whitelist) — use _bleio directly. +all_services = connection._bleio_connection.discover_remote_services() +print("total services", len(all_services)) + +# Filter to our two known UUIDs (ignore GATT/GAP services the stack may expose) +user_svcs = [s for s in all_services if s.uuid.uuid16 in (0x180F, 0x180D)] +print("user services", len(user_svcs)) + +uuids = sorted([s.uuid.uuid16 for s in user_svcs]) +print("service uuids", uuids) + +# Now read characteristics via adafruit_ble Service bindings. +if BatteryService in connection: + bas = connection[BatteryService] + print("char", hex(0x2a19), list(bas.level)) + +if HeartRateService in connection: + hrs = connection[HeartRateService] + print("char", hex(0x2a37), list(hrs.measurement)) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_DISCOVER_ALL_SERVER_CODE, + "battery_service.py": BATTERY_LIB, + "heart_rate.py": HEART_RATE_LIB, + **_ADAFRUIT_BLE, + } +) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_DISCOVER_ALL_CLIENT_CODE, + "battery_service.py": BATTERY_LIB, + "heart_rate.py": HEART_RATE_LIB, + **_ADAFRUIT_BLE, + } +) +def test_bsim_service_discover_all(bsim_phy, circuitpython1, circuitpython2): + """Discover all services without a UUID whitelist, verify two user services found.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + client_output = client.serial.all_output + + assert "user services 2" in client_output + assert "service uuids [6157, 6159]" in client_output # 0x180D=6157, 0x180F=6159 + assert "char 0x2a37 [0, 72]" in client_output + assert "char 0x2a19 [75]" in client_output + + +# =================================================================== +# Test 4: Write-no-response (uses MultiService from multi_service module) +# =================================================================== + +MULTI_LIB = """ +from adafruit_ble.services import Service +from adafruit_ble.characteristics import Characteristic, Attribute +from adafruit_ble.uuid import StandardUUID + + +class MultiService(Service): + uuid = StandardUUID(0x180F) + char_a = Characteristic( + uuid=StandardUUID(0x2A19), + properties=Characteristic.READ, + read_perm=Attribute.OPEN, + write_perm=Attribute.NO_ACCESS, + max_length=1, + fixed_length=True, + initial_value=bytes([10]), + ) + char_b = Characteristic( + uuid=StandardUUID(0x2A1A), + properties=Characteristic.READ | Characteristic.WRITE_NO_RESPONSE, + read_perm=Attribute.OPEN, + write_perm=Attribute.OPEN, + max_length=1, + fixed_length=True, + initial_value=bytes([20]), + ) + char_c = Characteristic( + uuid=StandardUUID(0x2A1B), + properties=Characteristic.READ, + read_perm=Attribute.OPEN, + write_perm=Attribute.NO_ACCESS, + max_length=1, + fixed_length=True, + initial_value=bytes([30]), + )""" + + +BSIM_MULTI_CHAR_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from multi_service import MultiService + +ble = BLERadio() +svc = MultiService() +# Force binding +svc.char_a +svc.char_b +svc.char_c +print("service created") + +advertisement = ProvideServicesAdvertisement(svc) +ble.start_advertising(advertisement) + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) + +print("char_b final", list(svc.char_b)) +print("done") +""" + +BSIM_WRITE_NR_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from multi_service import MultiService + +ble = BLERadio() + +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + break +ble.stop_scan() + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) + +svc = connection[MultiService] + +print("initial", list(svc.char_b)) + +# Write-no-response +svc.char_b = bytes([99]) +print("wrote wnr") + +# Give the server time to process the write +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_MULTI_CHAR_SERVER_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_WRITE_NR_CLIENT_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_write_no_response(bsim_phy, circuitpython1, circuitpython2): + """Client writes a characteristic using WRITE_NO_RESPONSE.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "char_b final [99]" in server_output + assert "initial [20]" in client_output + assert "wrote wnr" in client_output + + +# =================================================================== +# Test 5: Multiple characteristics on one service +# =================================================================== + +BSIM_MULTI_CHAR_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from multi_service import MultiService + +ble = BLERadio() + +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + break +ble.stop_scan() + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) + +svc = connection[MultiService] +print("num chars", 3) + +# Read each characteristic +print("char", hex(0x2A19), list(svc.char_a)) +print("char", hex(0x2A1A), list(svc.char_b)) +print("char", hex(0x2A1B), list(svc.char_c)) + +# Write to the second characteristic +svc.char_b = bytes([77]) +print("wrote 0x2a1a") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_MULTI_CHAR_SERVER_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_MULTI_CHAR_CLIENT_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_multi_char(bsim_phy, circuitpython1, circuitpython2): + """Service with three characteristics: discover all, read each, write one.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "num chars 3" in client_output + assert "char 0x2a19 [10]" in client_output + assert "char 0x2a1a [20]" in client_output + assert "char 0x2a1b [30]" in client_output + assert "wrote 0x2a1a" in client_output + assert "char_b final [77]" in server_output + + +# =================================================================== +# Test 6: 128-bit custom UUID +# =================================================================== + +CUSTOM_LIB = """ +from adafruit_ble.services import Service +from adafruit_ble.characteristics import Characteristic, Attribute +from adafruit_ble.uuid import VendorUUID + + +class CustomService(Service): + uuid = VendorUUID("12345678-1234-5678-1234-56789abcdef0") + data = Characteristic( + uuid=VendorUUID("12345678-1234-5678-1234-56789abcdef1"), + properties=Characteristic.READ | Characteristic.WRITE, + read_perm=Attribute.OPEN, + write_perm=Attribute.OPEN, + max_length=4, + fixed_length=False, + initial_value=bytes([0xDE, 0xAD]), + )""" + +BSIM_CUSTOM_UUID_SERVER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from custom_service import CustomService + +ble = BLERadio() +svc = CustomService() +print("service created") + +advertisement = ProvideServicesAdvertisement(svc) +ble.start_advertising(advertisement) + +for _ in range(80): + if ble.connected: + break + time.sleep(0.1) +print("connected", ble.connected) + +for _ in range(80): + if not ble.connected: + break + time.sleep(0.1) + +print("final value", list(svc.data)) +print("done") +""" + +BSIM_CUSTOM_UUID_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from custom_service import CustomService + +ble = BLERadio() + +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + break +ble.stop_scan() + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) + +svc = connection[CustomService] +print("discovered services", 1) + +print("char value", list(svc.data)) + +svc.data = bytes([0xBE, 0xEF]) +print("wrote custom") + +time.sleep(0.5) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CUSTOM_UUID_SERVER_CODE, "custom_service.py": CUSTOM_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CUSTOM_UUID_CLIENT_CODE, "custom_service.py": CUSTOM_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_custom_uuid(bsim_phy, circuitpython1, circuitpython2): + """128-bit custom UUID service: discover, read, and write.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "discovered services 1" in client_output + assert "char value [222, 173]" in client_output # 0xDE, 0xAD + assert "wrote custom" in client_output + assert "final value [190, 239]" in server_output # 0xBE, 0xEF + + +# =================================================================== +# Test 7: Empty discovery result +# =================================================================== + +BSIM_EMPTY_DISC_CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from heart_rate import HeartRateService + +ble = BLERadio() + +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=6.0): + if adv.connectable: + target = adv + print("found server") + break +ble.stop_scan() +print("have target", target is not None) + +if target is None: + raise RuntimeError("No server found") + +connection = ble.connect(target, timeout=5.0) +print("connected", connection.connected) + +# Ask for Heart Rate Service which doesn't exist on this server +found = HeartRateService in connection +print("found services", 1 if found else 0) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(14) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CUSTOM_UUID_SERVER_CODE, "custom_service.py": CUSTOM_LIB, **_ADAFRUIT_BLE} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_EMPTY_DISC_CLIENT_CODE, "heart_rate.py": HEART_RATE_LIB, **_ADAFRUIT_BLE} +) +def test_bsim_service_empty_discovery(bsim_phy, circuitpython1, circuitpython2): + """Filter for a UUID that doesn't exist, verify empty tuple returned.""" + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + client_output = client.serial.all_output + + assert "found services 0" in client_output + assert "done" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_uuid.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_uuid.py new file mode 100644 index 00000000000..9dcf3b13847 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_uuid.py @@ -0,0 +1,331 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE UUID tests for bsim.""" + +import pytest + + +# --- 16-bit UUIDs --- + +BSIM_UUID_16BIT_CODE = """\ +import _bleio + +u16 = _bleio.UUID(0x180F) +print("uuid16", u16.uuid16) +print("size", u16.size) +print("str", str(u16)) +print("repr", repr(u16)) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_CODE}) +def test_bsim_uuid_16bit_basic(bsim_phy, circuitpython): + """Construct a 16-bit UUID and verify all properties.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "uuid16 6159" in output # 0x180F = 6159 + assert "size 16" in output + assert "UUID(0x180f)" in output + assert "done" in output + + +BSIM_UUID_16BIT_EQ_CODE = """\ +import _bleio + +a = _bleio.UUID(0x180F) +b = _bleio.UUID(0x180F) +c = _bleio.UUID(0x180D) + +print("eq_same", a == b) +print("eq_diff", a == c) +print("neq_diff", a != c) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_EQ_CODE}) +def test_bsim_uuid_16bit_equality(bsim_phy, circuitpython): + """16-bit UUID equality: same value is equal, different values are not.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "eq_same True" in output + assert "eq_diff False" in output + assert "neq_diff True" in output + assert "done" in output + + +BSIM_UUID_16BIT_HASH_CODE = """\ +import _bleio + +a = _bleio.UUID(0x180F) +b = _bleio.UUID(0x180F) + +# Same UUID should hash the same +print("hash_same", hash(a) == hash(b)) + +# Can be used as dict keys +d = {a: "battery"} +print("dict_lookup", d[_bleio.UUID(0x180F)]) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_HASH_CODE}) +def test_bsim_uuid_16bit_hash(bsim_phy, circuitpython): + """16-bit UUID can be hashed and used as dict keys.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "hash_same True" in output + assert "dict_lookup battery" in output + assert "done" in output + + +BSIM_UUID_16BIT_PACK_CODE = """\ +import _bleio + +u16 = _bleio.UUID(0x180F) +buf = bytearray(4) +u16.pack_into(buf) +print("packed", list(buf[:2])) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_PACK_CODE}) +def test_bsim_uuid_16bit_pack_into(bsim_phy, circuitpython): + """pack_into for 16-bit UUID writes 2 bytes in little-endian.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # 0x180F in little-endian: byte[0]=0x0F, byte[1]=0x18 + assert "packed [15, 24]" in output # 0x0F=15, 0x18=24 + assert "done" in output + + +BSIM_UUID_16BIT_PACK_OFFSET_CODE = """\ +import _bleio + +u16 = _bleio.UUID(0x2A19) +buf = bytearray(6) +u16.pack_into(buf, offset=4) +print("packed", list(buf)) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_PACK_OFFSET_CODE}) +def test_bsim_uuid_16bit_pack_into_offset(bsim_phy, circuitpython): + """pack_into with offset writes at the correct position.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + # 0x2A19 = 10777, little-endian: [0x19, 0x2A] = [25, 42] + assert "packed [0, 0, 0, 0, 25, 42]" in output + assert "done" in output + + +# --- 128-bit UUID string parsing --- + +BSIM_UUID_128BIT_STR_CODE = """\ +import _bleio + +u128 = _bleio.UUID("12345678-1234-5678-1234-56789abcdef0") +print("uuid16", u128.uuid16) +print("size", u128.size) +print("uuid128_len", len(u128.uuid128)) +# Bytes 12-13 are zeroed by shared-bindings (extracted as uuid16) +# First 4 bytes of uuid128 are [f0, de, bc, 9a] in LE +print("bytes_0_3", list(u128.uuid128[:4])) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_128BIT_STR_CODE}) +def test_bsim_uuid_128bit_string(bsim_phy, circuitpython): + """Construct a 128-bit UUID from a hex string.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 128" in output + # uuid16 extracted from bytes 12-13: 0x5678 = 22136 + assert "uuid16 22136" in output + assert "uuid128_len 16" in output + # Bytes 12-13 are restored from uuid16 by common_hal_bleio_uuid_construct + # First 4 bytes of uuid128 are [f0, de, bc, 9a] in LE + assert "bytes_0_3 [240, 222, 188, 154]" in output + assert "done" in output + + +# --- 128-bit UUID bytes construction --- + +BSIM_UUID_128BIT_BYTES_CODE = """\ +import _bleio + +raw = bytes([0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12, + 0x34, 0x12, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56]) +u128 = _bleio.UUID(raw) +print("size", u128.size) +# uuid16 extracted from raw[12:14] = [0x34, 0x12] → 0x1234 = 4660 +print("uuid16", u128.uuid16) +print("uuid128_len", len(u128.uuid128)) +# Bytes 12-13 are restored from uuid16 by common_hal_bleio_uuid_construct +print("bytes_12_13", list(u128.uuid128[12:14])) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_128BIT_BYTES_CODE}) +def test_bsim_uuid_128bit_bytes(bsim_phy, circuitpython): + """Construct a 128-bit UUID from a 16-byte buffer.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 128" in output + assert "uuid16 4660" in output + assert "uuid128_len 16" in output + # Bytes 12-13 restored from uuid16: 0x1234 → [0x34, 0x12] = [52, 18] + assert "bytes_12_13 [52, 18]" in output + assert "done" in output + + +# --- 128-bit UUID equality --- + +BSIM_UUID_128BIT_EQ_CODE = """\ +import _bleio + +a = _bleio.UUID("12345678-1234-5678-1234-56789abcdef0") +b = _bleio.UUID("12345678-1234-5678-1234-56789abcdef0") +c = _bleio.UUID("00000000-0000-1000-8000-00805f9b34fb") + +print("eq_same", a == b) +print("eq_diff", a == c) +print("neq_diff", a != c) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_128BIT_EQ_CODE}) +def test_bsim_uuid_128bit_equality(bsim_phy, circuitpython): + """128-bit UUID equality: same bytes equal, different not.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "eq_same True" in output + assert "eq_diff False" in output + assert "neq_diff True" in output + assert "done" in output + + +# --- 16-bit vs 128-bit UUID equality (should not be equal even if same value) --- + +BSIM_UUID_CROSS_SIZE_EQ_CODE = """\ +import _bleio + +# 0x180F as 16-bit +u16 = _bleio.UUID(0x180F) + +# 0x180F expanded to 128-bit base UUID +# Bluetooth base: 00000000-0000-1000-8000-00805F9B34FB +# With 0x180F: 0000180F-0000-1000-8000-00805F9B34FB +u128 = _bleio.UUID("0000180f-0000-1000-8000-00805f9b34fb") + +print("size_16", u16.size) +print("size_128", u128.size) +# Per spec, 16-bit and 128-bit are NOT equal even if values match +print("cross_eq", u16 == u128) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_CROSS_SIZE_EQ_CODE}) +def test_bsim_uuid_cross_size_equality(bsim_phy, circuitpython): + """16-bit and 128-bit UUIDs are not equal even with same value.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size_16 16" in output + assert "size_128 128" in output + assert "cross_eq False" in output + assert "done" in output + + +# --- Invalid UUID string --- + +BSIM_UUID_INVALID_STR_CODE = """\ +import _bleio + +try: + u = _bleio.UUID("not-a-uuid") + print("should not reach") +except ValueError as e: + print("value_error", "not" in str(e) or "UUID" in str(e)) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_INVALID_STR_CODE}) +def test_bsim_uuid_invalid_string(bsim_phy, circuitpython): + """Invalid UUID string raises ValueError.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "value_error True" in output + assert "done" in output + + +# --- UUID 128-bit: uuid128 property works, uuid16 returns 16-bit part --- + +BSIM_UUID_128BIT_PROPS_CODE = """\ +import _bleio + +u128 = _bleio.UUID("12345678-1234-5678-1234-56789abcdef0") +print("size", u128.size) +# uuid128 returns 16 bytes (bytes 12-13 are restored from uuid16) +b = u128.uuid128 +print("uuid128_len", len(b)) +# uuid16 is the 16-bit part from bytes 12-13, extracted and then restored +print("uuid16", u128.uuid16) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_128BIT_PROPS_CODE}) +def test_bsim_uuid_128bit_properties(bsim_phy, circuitpython): + """128-bit UUID exposes uuid128 bytes and uuid16 from bytes 12-13.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "size 128" in output + assert "uuid128_len 16" in output + assert "uuid16 22136" in output + assert "done" in output + + +# --- 16-bit uuid128 raises AttributeError --- + +BSIM_UUID_16BIT_NO_UUID128_CODE = """\ +import _bleio + +u16 = _bleio.UUID(0x180F) +try: + _ = u16.uuid128 + print("should not reach") +except AttributeError: + print("attr_error ok") +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_UUID_16BIT_NO_UUID128_CODE}) +def test_bsim_uuid_16bit_no_uuid128(bsim_phy, circuitpython): + """Accessing uuid128 on a 16-bit UUID raises AttributeError.""" + circuitpython.wait_until_done() + + output = circuitpython.serial.all_output + assert "attr_error ok" in output + assert "done" in output diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index 03451048324..0efe3bcc3fe 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -289,26 +289,41 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp tmp_drive = tmp_path / f"drive{i}" tmp_drive.mkdir(exist_ok=True) + fat_dirs_created = set() for name, content in files.items(): src = tmp_drive / name + src.parent.mkdir(parents=True, exist_ok=True) if isinstance(content, bytes): src.write_bytes(content) else: src.write_text(content) + # Create parent directories on the FAT image. + fat_dir = Path(name).parent + for fat_part in [*reversed(fat_dir.parents), fat_dir]: + if fat_part == Path("."): + continue + fat_path = "::" + str(fat_part) + if fat_path not in fat_dirs_created: + subprocess.run(["mmd", "-i", str(flash), fat_path], check=True) + fat_dirs_created.add(fat_path) subprocess.run(["mcopy", "-i", str(flash), str(src), f"::{name}"], check=True) trace_file = tmp_path / f"trace-{i}.perfetto" if "bsim" in board: - cmd = [str(native_sim_binary), f"--flash_app={flash}"] + # nRF54 bsim boards use RRAMC (--flash), others use NVMC (--flash_app) + flash_arg = "--flash" if "nrf54" in board else "--flash_app" + cmd = [str(native_sim_binary), f"{flash_arg}={flash}"] if instance_count > 1: cmd.append("-disconnect_on_exit=1") + # nRF54 bsim boards: console UART is SERIAL20 (bsim instance 1), others use instance 0 + uart_n = "1" if "nrf54" in board else "0" cmd.extend( ( f"-s={sim_id}", f"-d={i}", - "-uart0_pty", - "-uart0_pty_wait_for_readers", + f"-uart{uart_n}_pty", + f"-uart{uart_n}_pty_wait_for_readers", "-uart_pty_wait", f"--vm-runs={code_py_runs + 1}", ) diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index 0c5a5fec06b..b55db201f2e 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -50,6 +50,5 @@ MP_NORETURN void mp_raise_bleio_RoleError(mp_rom_error_text_t msg); MP_NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t msg, ...); bleio_adapter_obj_t *common_hal_bleio_allocate_adapter_or_raise(void); -void common_hal_bleio_device_discover_remote_services(mp_obj_t device, mp_obj_t service_uuids_whitelist); void common_hal_bleio_gc_collect(void); From 88868528466e8c774c2ddc10a85c86aba341795b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 6 Aug 2026 10:27:00 -0400 Subject: [PATCH 740/876] Fix mdns object lifetimes: don't hold pointers we don't own mdns.RemoteService and mdns.Server both stored borrowed pointers whose owners could die first. Copy the data out instead. RemoteService held an IDF mdns_result_t allocated on the IDF heap. GC finalisers run in heap-address order, and the Server is allocated before the RemoteServices that find() returns, so at VM teardown the Server's __del__ ran first: mdns_free() deletes _mdns_service_semaphore, and the subsequent mdns_query_results_free() then called xSemaphoreTake(NULL) and hard faulted. Copy the fields we expose into the object at find() time and free the IDF results immediately, mirroring what raspberrypi already did. RemoteService then needs no finaliser at all, so the ordering problem stops existing rather than being worked around. mdns_server_obj_t stored the hostname and instance_name pointers handed to it by mp_obj_str_get_str(). Those point into the GC heap, which is recycled on VM reset while the web workflow's static mdns_server_obj_t lives on, so /cp/version.json served whatever landed in that memory next -- often fragments of REPL input. Store fixed-size copies instead. On raspberrypi, advertise_service() stashed borrowed txt_records pointers that lwip dereferences later from srv_txt_cb() at packet-build time, so a collection between advertising and being queried published freed memory. Pack owned copies into a single buffer. TXT records can only arrive through the Python binding, so the GC heap is necessarily available; assign_txt_records() carries a warning explaining what would break that assumption. Also make both ports reject TXT records they can't honour instead of silently truncating: more than 32 raises ValueError on raspberrypi, and espressif raises NotImplementedError rather than accepting and discarding them. Fix the advertise_service docstring signature, which omitted txt_records even though the parameter list documented it. --- .../espressif/common-hal/mdns/RemoteService.c | 46 ++--------- .../espressif/common-hal/mdns/RemoteService.h | 10 ++- ports/espressif/common-hal/mdns/Server.c | 81 +++++++++++++------ ports/espressif/common-hal/mdns/Server.h | 7 +- .../common-hal/mdns/RemoteService.c | 3 - ports/raspberrypi/common-hal/mdns/Server.c | 65 ++++++++++++--- ports/raspberrypi/common-hal/mdns/Server.h | 11 ++- shared-bindings/mdns/RemoteService.c | 14 ---- shared-bindings/mdns/RemoteService.h | 1 - shared-bindings/mdns/Server.c | 13 ++- supervisor/shared/web_workflow/web_workflow.c | 1 - 11 files changed, 149 insertions(+), 103 deletions(-) diff --git a/ports/espressif/common-hal/mdns/RemoteService.c b/ports/espressif/common-hal/mdns/RemoteService.c index 515a3f7bf02..3d80199397e 100644 --- a/ports/espressif/common-hal/mdns/RemoteService.c +++ b/ports/espressif/common-hal/mdns/RemoteService.c @@ -9,56 +9,27 @@ #include "shared-bindings/ipaddress/IPv4Address.h" const char *common_hal_mdns_remoteservice_get_service_type(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return ""; - } - return self->result->service_type; + return self->service_name; } const char *common_hal_mdns_remoteservice_get_protocol(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return ""; - } - return self->result->proto; + return self->protocol; } const char *common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return ""; - } - return self->result->instance_name; + return self->instance_name; } const char *common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return ""; - } - return self->result->hostname; + return self->hostname; } mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self) { - if (self->result == NULL) { - return 0; - } - return self->result->port; + return self->port; } uint32_t mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self) { - if (self->result == NULL || - self->result->ip_protocol != MDNS_IP_PROTOCOL_V4 || - self->result->addr == NULL) { - return 0; - } - mdns_ip_addr_t *cur = self->result->addr; - while (cur != NULL) { - if (cur->addr.type == ESP_IPADDR_TYPE_V4) { - return cur->addr.u_addr.ip4.addr; - } - - cur = cur->next; - } - - return 0; + return self->ipv4_address; } mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self) { @@ -68,8 +39,3 @@ mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t } return common_hal_ipaddress_new_ipv4address(addr); } - -void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self) { - mdns_query_results_free(self->result); - self->result = NULL; -} diff --git a/ports/espressif/common-hal/mdns/RemoteService.h b/ports/espressif/common-hal/mdns/RemoteService.h index 6fb3000c7d1..89ff69be29d 100644 --- a/ports/espressif/common-hal/mdns/RemoteService.h +++ b/ports/espressif/common-hal/mdns/RemoteService.h @@ -8,7 +8,15 @@ #include "mdns.h" +// The IDF's mdns_result_t lives on the IDF heap and is only valid while mdns +// is inited. Copy what we need into the object instead so that the object's +// lifetime is independent of the mdns.Server's. typedef struct { mp_obj_base_t base; - mdns_result_t *result; + uint32_t ipv4_address; + uint16_t port; + char protocol[5]; // RFC 6763 Section 7.2 - 4 bytes + 1 for NUL + char service_name[17]; // RFC 6763 Section 7.2 - 16 bytes + 1 for NUL + char instance_name[64]; // RFC 6763 Section 7.2 - 63 bytes + 1 for NUL + char hostname[64]; // RFC 6762 Appendix A - 63 bytes for label + 1 for NUL } mdns_remoteservice_obj_t; diff --git a/ports/espressif/common-hal/mdns/Server.c b/ports/espressif/common-hal/mdns/Server.c index e8c34ee0885..7eaa9a442a2 100644 --- a/ports/espressif/common-hal/mdns/Server.c +++ b/ports/espressif/common-hal/mdns/Server.c @@ -6,6 +6,8 @@ #include "shared-bindings/mdns/Server.h" +#include + #include "py/gc.h" #include "py/runtime.h" #include "shared-bindings/mdns/RemoteService.h" @@ -18,6 +20,13 @@ // could be created.) static mdns_server_obj_t *_active_object = NULL; +// strlcpy(), but a NULL src yields an empty string instead of undefined +// behavior. The IDF leaves mdns_result_t fields NULL when a query didn't +// resolve them. +static void strlcpy_or_empty(char *dest, const char *src, size_t dest_len) { + strlcpy(dest, src == NULL ? "" : src, dest_len); +} + void mdns_server_construct(mdns_server_obj_t *self, bool workflow) { if (_active_object != NULL) { if (self == _active_object) { @@ -33,9 +42,12 @@ void mdns_server_construct(mdns_server_obj_t *self, bool workflow) { } _active_object = self; + self->instance_name[0] = '\0'; + // Match the netif hostname set when `import wifi` was called. - esp_netif_get_hostname(common_hal_wifi_radio_obj.netif, &self->hostname); - common_hal_mdns_server_set_hostname(self, self->hostname); + const char *netif_hostname; + esp_netif_get_hostname(common_hal_wifi_radio_obj.netif, &netif_hostname); + common_hal_mdns_server_set_hostname(self, netif_hostname); self->inited = true; @@ -95,11 +107,11 @@ void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *ho while (!mdns_hostname_exists(hostname)) { RUN_BACKGROUND_TASKS; } - self->hostname = hostname; + strlcpy_or_empty(self->hostname, hostname, sizeof(self->hostname)); } const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) { - if (self->instance_name == NULL) { + if (self->instance_name[0] == '\0') { return self->hostname; } return self->instance_name; @@ -107,7 +119,28 @@ const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) { void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name) { mdns_instance_name_set(instance_name); - self->instance_name = instance_name; + strlcpy_or_empty(self->instance_name, instance_name, sizeof(self->instance_name)); +} + +// Copy everything we expose out of the IDF's result so that the RemoteService +// no longer references IDF-owned memory. The caller is responsible for freeing +// the result itself. +static void copy_data_into_remote_service(mdns_result_t *result, mdns_remoteservice_obj_t *out) { + out->base.type = &mdns_remoteservice_type; + out->port = result->port; + out->ipv4_address = 0; + if (result->ip_protocol == MDNS_IP_PROTOCOL_V4) { + for (mdns_ip_addr_t *cur = result->addr; cur != NULL; cur = cur->next) { + if (cur->addr.type == ESP_IPADDR_TYPE_V4) { + out->ipv4_address = cur->addr.u_addr.ip4.addr; + break; + } + } + } + strlcpy_or_empty(out->protocol, result->proto, sizeof(out->protocol)); + strlcpy_or_empty(out->service_name, result->service_type, sizeof(out->service_name)); + strlcpy_or_empty(out->instance_name, result->instance_name, sizeof(out->instance_name)); + strlcpy_or_empty(out->hostname, result->hostname, sizeof(out->hostname)); } size_t mdns_server_find(mdns_server_obj_t *self, const char *service_type, const char *protocol, @@ -123,23 +156,15 @@ size_t mdns_server_find(mdns_server_obj_t *self, const char *service_type, const } mdns_query_async_delete(search); mdns_result_t *next = results; - // Don't error if we're out of memory. Instead, truncate the tuple. - uint8_t added = 0; + // Truncate if we don't have space for everything the IDF found. + size_t added = 0; while (next != NULL && added < out_len) { - mdns_remoteservice_obj_t *service = &out[added]; - - service->result = next; - service->base.type = &mdns_remoteservice_type; + copy_data_into_remote_service(next, &out[added]); next = next->next; - // Break the linked list so we free each result separately. - service->result->next = NULL; added++; } - if (added < out_len) { - // Free the remaining results from the IDF because we don't have - // enough space in Python. - mdns_query_results_free(next); - } + // We've copied out everything we need, so release the IDF's copy. + mdns_query_results_free(results); return num_results; } @@ -158,36 +183,40 @@ mp_obj_t common_hal_mdns_server_find(mdns_server_obj_t *self, const char *servic // The empty tuple object is shared and stored in flash so return early if // we got it. Without this we'll crash when trying to set len below. if (num_results == 0) { + mdns_query_results_free(results); return MP_OBJ_FROM_PTR(tuple); } mdns_result_t *next = results; // Don't error if we're out of memory. Instead, truncate the tuple. uint8_t added = 0; while (next != NULL) { - mdns_remoteservice_obj_t *service = gc_alloc(sizeof(mdns_remoteservice_obj_t), GC_ALLOC_FLAG_HAS_FINALISER); + mdns_remoteservice_obj_t *service = m_malloc_maybe(sizeof(mdns_remoteservice_obj_t)); if (service == NULL) { if (added == 0) { + mdns_query_results_free(results); m_malloc_fail(sizeof(mdns_remoteservice_obj_t)); } - // Free the remaining results from the IDF because we don't have - // enough space in Python. - mdns_query_results_free(next); break; } - service->result = next; - service->base.type = &mdns_remoteservice_type; + copy_data_into_remote_service(next, service); next = next->next; - // Break the linked list so we free each result separately. - service->result->next = NULL; tuple->items[added] = MP_OBJ_FROM_PTR(service); added++; } tuple->len = added; + // We've copied out everything we need, so release the IDF's copy. + mdns_query_results_free(results); + return MP_OBJ_FROM_PTR(tuple); } void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port, const char *txt_records[], size_t num_txt_records) { + // Reject rather than silently drop them. See the TODO below. + if (num_txt_records > 0) { + mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_txt_records); + } + if (mdns_service_exists(service_type, protocol, NULL)) { mdns_service_port_set(service_type, protocol, port); } else { diff --git a/ports/espressif/common-hal/mdns/Server.h b/ports/espressif/common-hal/mdns/Server.h index f364a539c91..e7bfabb9528 100644 --- a/ports/espressif/common-hal/mdns/Server.h +++ b/ports/espressif/common-hal/mdns/Server.h @@ -10,8 +10,11 @@ typedef struct { mp_obj_base_t base; - const char *hostname; - const char *instance_name; + // Store copies rather than the caller's pointers. The setters are handed + // GC-heap strings, which are recycled when the VM resets while this object + // (and the web workflow's static one) lives on. + char hostname[64]; // RFC 6762 Appendix A - 63 bytes for label + 1 for NUL + char instance_name[64]; // RFC 6763 Section 7.2 - 63 bytes + 1 for NUL // Track if this object owns access to the underlying MDNS service. bool inited; } mdns_server_obj_t; diff --git a/ports/raspberrypi/common-hal/mdns/RemoteService.c b/ports/raspberrypi/common-hal/mdns/RemoteService.c index 650e86da9d9..3d80199397e 100644 --- a/ports/raspberrypi/common-hal/mdns/RemoteService.c +++ b/ports/raspberrypi/common-hal/mdns/RemoteService.c @@ -39,6 +39,3 @@ mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t } return common_hal_ipaddress_new_ipv4address(addr); } - -void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self) { -} diff --git a/ports/raspberrypi/common-hal/mdns/Server.c b/ports/raspberrypi/common-hal/mdns/Server.c index ac0c73389b1..41ab0d3dc3b 100644 --- a/ports/raspberrypi/common-hal/mdns/Server.c +++ b/ports/raspberrypi/common-hal/mdns/Server.c @@ -42,10 +42,15 @@ void mdns_server_construct(mdns_server_obj_t *self, bool workflow) { } self->inited = true; + self->instance_name[0] = '\0'; + self->num_txt_records = 0; + self->txt_storage = NULL; + uint8_t mac[6]; wifi_radio_get_mac_address(&common_hal_wifi_radio_obj, mac); - snprintf(self->default_hostname, sizeof(self->default_hostname), "cpy-%02x%02x%02x", mac[3], mac[4], mac[5]); - common_hal_mdns_server_set_hostname(self, self->default_hostname); + char default_hostname[sizeof("cpy-XXXXXX")]; + snprintf(default_hostname, sizeof(default_hostname), "cpy-%02x%02x%02x", mac[3], mac[4], mac[5]); + common_hal_mdns_server_set_hostname(self, default_hostname); if (workflow) { // Add a second host entry to respond to "circuitpython.local" queries as well. @@ -91,15 +96,18 @@ void common_hal_mdns_server_set_hostname(mdns_server_obj_t *self, const char *ho mdns_resp_add_netif(NETIF_STA, hostname); } - self->hostname = hostname; + strlcpy(self->hostname, hostname, sizeof(self->hostname)); } const char *common_hal_mdns_server_get_instance_name(mdns_server_obj_t *self) { + if (self->instance_name[0] == '\0') { + return self->hostname; + } return self->instance_name; } void common_hal_mdns_server_set_instance_name(mdns_server_obj_t *self, const char *instance_name) { - self->instance_name = instance_name; + strlcpy(self->instance_name, instance_name, sizeof(self->instance_name)); } typedef struct { @@ -288,15 +296,54 @@ static void srv_txt_cb(struct mdns_service *service, void *ptr) { } } +// Take our own copies of the TXT records. lwip only stores srv_txt_cb and this +// object, and calls back at packet-build time, so the caller's strings must +// outlive the call -- and the caller hands us pointers into GC-heap strings. +// +// WARNING: the copies live on the GC heap, which is only safe because TXT +// records can reach us solely through the Python binding, so the VM is +// necessarily running and this object is itself a GC object that dies with the +// same heap. The supervisor's static mdns_server_obj_t never gets TXT records +// (web_workflow.c passes NULL, 0). If supervisor code ever needs to advertise +// TXT records, this must move off the GC heap first -- an inline pool in +// mdns_server_obj_t, or port_malloc -- or the records will dangle after the +// first VM reset. static void assign_txt_records(mdns_server_obj_t *self, const char *txt_records[], size_t num_txt_records) { - size_t allowed_num_txt_records = MDNS_MAX_TXT_RECORDS < num_txt_records ? MDNS_MAX_TXT_RECORDS : num_txt_records; - self->num_txt_records = allowed_num_txt_records; - for (size_t i = 0; i < allowed_num_txt_records; i++) { - self->txt_records[i] = txt_records[i]; + // Stop the callback from reading the old records while we swap them out. + self->num_txt_records = 0; + self->txt_storage = NULL; + + size_t total = 0; + for (size_t i = 0; i < num_txt_records; i++) { + total += strlen(txt_records[i]) + 1; + } + if (total == 0) { + return; } + + // Dropping the old storage is enough; the GC reclaims it. Freeing it here + // could pull it out from under an in-flight srv_txt_cb. + char *storage = m_malloc_maybe(total); + if (storage == NULL) { + m_malloc_fail(total); + } + char *next = storage; + for (size_t i = 0; i < num_txt_records; i++) { + size_t size = strlen(txt_records[i]) + 1; + memcpy(next, txt_records[i], size); + self->txt_records[i] = next; + next += size; + } + + self->txt_storage = storage; + self->num_txt_records = num_txt_records; } void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port, const char *txt_records[], size_t num_txt_records) { + // Check before touching any state, so a rejected call leaves the existing + // advertisement alone. + mp_arg_validate_length_max(num_txt_records, MDNS_MAX_TXT_RECORDS, MP_QSTR_txt_records); + enum mdns_sd_proto proto = DNSSD_PROTO_UDP; if (strcmp(protocol, "_tcp") == 0) { proto = DNSSD_PROTO_TCP; @@ -316,7 +363,7 @@ void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const cha } assign_txt_records(self, txt_records, num_txt_records); - int8_t slot = mdns_resp_add_service(NETIF_STA, self->instance_name, service_type, proto, port, srv_txt_cb, self); + int8_t slot = mdns_resp_add_service(NETIF_STA, common_hal_mdns_server_get_instance_name(self), service_type, proto, port, srv_txt_cb, self); if (slot < 0) { mp_raise_RuntimeError(MP_ERROR_TEXT("Out of MDNS service slots")); return; diff --git a/ports/raspberrypi/common-hal/mdns/Server.h b/ports/raspberrypi/common-hal/mdns/Server.h index 620e201c897..041add08818 100644 --- a/ports/raspberrypi/common-hal/mdns/Server.h +++ b/ports/raspberrypi/common-hal/mdns/Server.h @@ -14,11 +14,16 @@ typedef struct { mp_obj_base_t base; - const char *hostname; - const char *instance_name; - char default_hostname[sizeof("cpy-XXXXXX")]; + // Store copies rather than the caller's pointers. The setters are handed + // GC-heap strings, which are recycled when the VM resets while this object + // (and the web workflow's static one) lives on. + char hostname[64]; // RFC 6762 Appendix A - 63 bytes for label + 1 for NUL + char instance_name[64]; // RFC 6763 Section 7.2 - 63 bytes + 1 for NUL const char *service_type[MDNS_MAX_SERVICES]; size_t num_txt_records; + // Owned copies of the TXT records, packed NUL-separated into txt_storage, + // which lives on the GC heap. See the warning on assign_txt_records(). + char *txt_storage; const char *txt_records[MDNS_MAX_TXT_RECORDS]; // Track if this object owns access to the underlying MDNS service. bool inited; diff --git a/shared-bindings/mdns/RemoteService.c b/shared-bindings/mdns/RemoteService.c index b3ee3d7f7b7..b00313729fc 100644 --- a/shared-bindings/mdns/RemoteService.c +++ b/shared-bindings/mdns/RemoteService.c @@ -93,18 +93,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_get_ipv4_address_obj, _mdns_remotes MP_PROPERTY_GETTER(mdns_remoteservice_ipv4_address_obj, (mp_obj_t)&mdns_remoteservice_get_ipv4_address_obj); -//| def __del__(self) -> None: -//| """Deletes the RemoteService object.""" -//| ... -//| -//| -static mp_obj_t mdns_remoteservice_obj_deinit(mp_obj_t self_in) { - mdns_remoteservice_obj_t *self = MP_OBJ_TO_PTR(self_in); - common_hal_mdns_remoteservice_deinit(self); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(mdns_remoteservice_deinit_obj, mdns_remoteservice_obj_deinit); - static const mp_rom_map_elem_t mdns_remoteservice_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_hostname), MP_ROM_PTR(&mdns_remoteservice_hostname_obj) }, { MP_ROM_QSTR(MP_QSTR_instance_name), MP_ROM_PTR(&mdns_remoteservice_instance_name_obj) }, @@ -112,8 +100,6 @@ static const mp_rom_map_elem_t mdns_remoteservice_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_protocol), MP_ROM_PTR(&mdns_remoteservice_protocol_obj) }, { MP_ROM_QSTR(MP_QSTR_port), MP_ROM_PTR(&mdns_remoteservice_port_obj) }, { MP_ROM_QSTR(MP_QSTR_ipv4_address), MP_ROM_PTR(&mdns_remoteservice_ipv4_address_obj) }, - - { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mdns_remoteservice_deinit_obj) }, }; static MP_DEFINE_CONST_DICT(mdns_remoteservice_locals_dict, mdns_remoteservice_locals_dict_table); diff --git a/shared-bindings/mdns/RemoteService.h b/shared-bindings/mdns/RemoteService.h index a5ffe897e4e..c7efa64083d 100644 --- a/shared-bindings/mdns/RemoteService.h +++ b/shared-bindings/mdns/RemoteService.h @@ -19,7 +19,6 @@ const char *common_hal_mdns_remoteservice_get_instance_name(mdns_remoteservice_o const char *common_hal_mdns_remoteservice_get_hostname(mdns_remoteservice_obj_t *self); mp_int_t common_hal_mdns_remoteservice_get_port(mdns_remoteservice_obj_t *self); mp_obj_t common_hal_mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self); -void common_hal_mdns_remoteservice_deinit(mdns_remoteservice_obj_t *self); // For internal use. uint32_t mdns_remoteservice_get_ipv4_address(mdns_remoteservice_obj_t *self); diff --git a/shared-bindings/mdns/Server.c b/shared-bindings/mdns/Server.c index 86fb2eb6d7a..1c16348d425 100644 --- a/shared-bindings/mdns/Server.c +++ b/shared-bindings/mdns/Server.c @@ -150,7 +150,14 @@ static mp_obj_t _mdns_server_find(mp_uint_t n_args, const mp_obj_t *pos_args, mp } static MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_find_obj, 1, _mdns_server_find); -//| def advertise_service(self, *, service_type: str, protocol: str, port: int) -> None: +//| def advertise_service( +//| self, +//| *, +//| service_type: str, +//| protocol: str, +//| port: int, +//| txt_records: Optional[Sequence[str]] = None, +//| ) -> None: //| """Respond to queries for the given service with the given port. //| //| ``service_type`` and ``protocol`` can only occur on one port. Any call after the first @@ -158,8 +165,8 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(mdns_server_find_obj, 1, _mdns_server_find); //| //| If web workflow is active, the port it uses can't also be used to advertise a service. //| -//| **Limitations**: Publishing up to 32 TXT records is only supported on the RP2040 Pico W board at -//| this time. +//| **Limitations**: Publishing TXT records (up to 32) is supported only on RP2xxx. +//| There is currently no TXT record support on Espressif boards. //| //| :param str service_type: The service type such as "_http" //| :param str protocol: The service protocol such as "_tcp" diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index 278823676ef..f88e3322e23 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -884,7 +884,6 @@ static void _reply_with_devices_json(socketpool_socket_obj_t *socket, _request * "\"instance_name\": \"%s\", " "\"port\": %d, " "\"ip\": \"%d.%d.%d.%d\"}", hostname, instance_name, port, octets[0], octets[1], octets[2], octets[3]); - common_hal_mdns_remoteservice_deinit(&found_devices[i]); } #endif _send_chunk(socket, "]}"); From 64a5e8d4a053c81cd95e5265e4d074d9cd2770a0 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 6 Aug 2026 14:02:51 -0400 Subject: [PATCH 741/876] Hold the lwip lock while swapping mdns TXT records srv_txt_cb() runs from the lwip IRQ -- raspberrypi builds cyw43_arch_threadsafe_background -- so it can preempt the VM thread part way through reading self->txt_records[]. Zeroing num_txt_records first doesn't help a callback that already loaded a nonzero count. Build the replacement buffer first, so the allocation and any MemoryError stay outside the lock, then swap the pointers under MICROPY_PY_LWIP_ENTER/EXIT and free the old storage once nothing can reference it. Dropping the reference and leaving it to the GC, as before, did not avoid that hazard -- it only deferred the free to an unpredictable moment. --- ports/raspberrypi/common-hal/mdns/Server.c | 46 +++++++++++++--------- 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/ports/raspberrypi/common-hal/mdns/Server.c b/ports/raspberrypi/common-hal/mdns/Server.c index 41ab0d3dc3b..1afccf4eb48 100644 --- a/ports/raspberrypi/common-hal/mdns/Server.c +++ b/ports/raspberrypi/common-hal/mdns/Server.c @@ -309,34 +309,44 @@ static void srv_txt_cb(struct mdns_service *service, void *ptr) { // mdns_server_obj_t, or port_malloc -- or the records will dangle after the // first VM reset. static void assign_txt_records(mdns_server_obj_t *self, const char *txt_records[], size_t num_txt_records) { - // Stop the callback from reading the old records while we swap them out. - self->num_txt_records = 0; - self->txt_storage = NULL; - size_t total = 0; for (size_t i = 0; i < num_txt_records; i++) { total += strlen(txt_records[i]) + 1; } - if (total == 0) { - return; - } - // Dropping the old storage is enough; the GC reclaims it. Freeing it here - // could pull it out from under an in-flight srv_txt_cb. - char *storage = m_malloc_maybe(total); - if (storage == NULL) { - m_malloc_fail(total); + // Build the replacement before touching self, so that the allocation, and + // any MemoryError it raises, happens outside the lwip lock below. + char *storage = NULL; + const char *records[MDNS_MAX_TXT_RECORDS]; + if (total > 0) { + storage = m_malloc_maybe(total); + if (storage == NULL) { + m_malloc_fail(total); + } + char *next = storage; + for (size_t i = 0; i < num_txt_records; i++) { + size_t size = strlen(txt_records[i]) + 1; + memcpy(next, txt_records[i], size); + records[i] = next; + next += size; + } } - char *next = storage; + + // srv_txt_cb reads these from the lwip IRQ, so hold lwip off while they + // change. Otherwise a callback already part way through the old records + // keeps pointers into storage we are about to release. + MICROPY_PY_LWIP_ENTER + char *old_storage = self->txt_storage; for (size_t i = 0; i < num_txt_records; i++) { - size_t size = strlen(txt_records[i]) + 1; - memcpy(next, txt_records[i], size); - self->txt_records[i] = next; - next += size; + self->txt_records[i] = records[i]; } - self->txt_storage = storage; self->num_txt_records = num_txt_records; + MICROPY_PY_LWIP_EXIT + + // Nothing can be holding pointers into it now, so release it here rather + // than leaving the GC to do it at an unpredictable time. + m_free(old_storage); } void common_hal_mdns_server_advertise_service(mdns_server_obj_t *self, const char *service_type, const char *protocol, mp_int_t port, const char *txt_records[], size_t num_txt_records) { From d5487d04462627fd44d1b805d302c1e612dd5d35 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 6 Aug 2026 20:24:30 -0400 Subject: [PATCH 742/876] Name the certificate verification failures in ssl OSErrors A failed handshake reported only MBEDTLS_ERR_X509_CERT_VERIFY_FAILED (-9984), discarding the MBEDTLS_X509_BADCERT_* bitmask that records which check actually failed. Read mbedtls_ssl_get_verify_result() in do_handshake() before mbedtls_ssl_free() frees the session it lives in, and name each set bit with mbedtls_x509_crt_verify_info(): OSError: (-9984, 'MBEDTLS_ERR_X509_CERT_VERIFY_FAILED; The certificate Common Name (CN) does not match with the expected CN') Several bits are commonly set at once, since mbedtls ors together the flags of every certificate in the chain, so ask for one bit at a time and append each name to a vstr. verify_info() writes all of its output or none of it, so requesting the whole mask at once would drop the entire list when it did not fit. All ones is mbedtls's "nothing to report" sentinel: it poisons the flags when a verify callback fails, and mbedtls_ssl_get_verify_result() returns 0xFFFFFFFF with no session. Screen for it, and only ask for the flags on MBEDTLS_ERR_X509_CERT_VERIFY_FAILED, so those cases report the error name alone rather than the entire table. Turn on CONFIG_MBEDTLS_ERROR_STRINGS for espressif so it gets error names at all; the other mbedtls ports already set MBEDTLS_ERROR_C. Co-Authored-By: Claude Opus 5 --- .../esp-idf-config/sdkconfig.defaults | 2 +- shared-module/ssl/SSLSocket.c | 96 ++++++++++++++----- 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/ports/espressif/esp-idf-config/sdkconfig.defaults b/ports/espressif/esp-idf-config/sdkconfig.defaults index 941f879ed42..9859e5e94a8 100644 --- a/ports/espressif/esp-idf-config/sdkconfig.defaults +++ b/ports/espressif/esp-idf-config/sdkconfig.defaults @@ -120,7 +120,7 @@ CONFIG_MBEDTLS_SSL_PROTO_DTLS=y # CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED is not set # CONFIG_MBEDTLS_ECP_FIXED_POINT_OPTIM is not set -# CONFIG_MBEDTLS_ERROR_STRINGS is not set +CONFIG_MBEDTLS_ERROR_STRINGS=y # end of mbedTLS # diff --git a/shared-module/ssl/SSLSocket.c b/shared-module/ssl/SSLSocket.c index 0c374da771f..a9969505509 100644 --- a/shared-module/ssl/SSLSocket.c +++ b/shared-module/ssl/SSLSocket.c @@ -13,7 +13,7 @@ #include "shared/netutils/netutils.h" #include "py/mperrno.h" #include "py/mphal.h" -#include "py/objstr.h" +#include "py/objarray.h" #include "py/runtime.h" #include "py/stream.h" #include "supervisor/shared/tick.h" @@ -40,7 +40,9 @@ static void mbedtls_debug(void *ctx, int level, const char *file, int line, cons #define DEBUG_PRINT(...) do {} while (0) #endif -static MP_NORETURN void mbedtls_raise_error(int err) { +// Raise an OSError for an mbedtls error code. +// `flags` is a bitmask from mbedtls_ssl_get_verify_result(), or 0 if not a verify error. +static MP_NORETURN void mbedtls_raise_error_flags(int err, uint32_t flags) { // _mbedtls_ssl_send and _mbedtls_ssl_recv (below) turn positive error codes from the // underlying socket into negative codes to pass them through mbedtls. Here we turn them // positive again so they get interpreted as the OSError they really are. The @@ -53,37 +55,78 @@ static MP_NORETURN void mbedtls_raise_error(int err) { mp_raise_OSError(MP_EWOULDBLOCK); } + // All ones means mbedtls says it has nothing to report: it set to all ones + // when a verify callback fails, and mbedtls_ssl_get_verify_result() returns + // this when there is no session at all. + if (flags == UINT32_MAX) { + flags = 0; + } + #if defined(MBEDTLS_ERROR_C) // Including mbedtls_strerror takes about 1.5KB due to the error strings. // MBEDTLS_ERROR_C is the define used by mbedtls to conditionally include mbedtls_strerror. // It is set/unset in the MBEDTLS_CONFIG_FILE which is defined in the Makefile. - // Try to allocate memory for the message - #define ERR_STR_MAX 80 // mbedtls_strerror truncates if it doesn't fit - mp_obj_str_t *o_str = m_new_obj_maybe(mp_obj_str_t); - byte *o_str_buf = m_malloc_without_collect(ERR_STR_MAX); - if (o_str == NULL || o_str_buf == NULL) { + // Large enough for the longest mbedtls_strerror() output, which is about 100 + // characters when it joins a high-level and a low-level name with '+', and for + // the longest certificate verification failure name, which is 81 characters. + #define ERR_STR_MAX 128 // mbedtls_strerror truncates if it doesn't fit + // One byte larger than the bound passed to mbedtls_strerror(), so that the + // strncpy() inside it has a bound smaller than the size of buf. Truncation + // there is safe and deliberate, but an equal bound trips -Wstringop-truncation. + char buf[ERR_STR_MAX + 1]; + + // Assemble the error message in a vstr. + // If we run out of heap, catch the MemoryError and fall back to just the error number. + mp_obj_t exc; + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + vstr_t vstr; + vstr_init(&vstr, ERR_STR_MAX); + + mbedtls_strerror(err, buf, ERR_STR_MAX); + vstr_add_str(&vstr, buf); + + #if !defined(MBEDTLS_X509_REMOVE_INFO) + // Call mbedtls_x509_crt_verify_info() to get the error string + // for each individual verify error bit. + // This allows for easier string management. + // Several verify errorbits are often set at once: + // mbedtls or's together the error flags of every certificate in the chain. + // For instance, a cert served under the wrong name and signed by an + // unknown CA reports CN_MISMATCH and NOT_TRUSTED together. + for (uint32_t bit = 1; bit != 0; bit <<= 1) { + if ((flags & bit) == 0) { + continue; + } + // The prefix is added to the beginning of the message. + // We drop the supplied trailing newline. + int info_len = mbedtls_x509_crt_verify_info(buf, ERR_STR_MAX, "; ", bit); + if (info_len > 1) { + // -1 to drop the newline. + vstr_add_strn(&vstr, buf, info_len - 1); + } + } + #endif + + mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), mp_obj_new_str_from_utf8_vstr(&vstr) }; + exc = mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args); + nlr_pop(); + } else { + // Could not build the message, so report the number by itself. mp_raise_OSError(err); } - - // print the error message into the allocated buffer - mbedtls_strerror(err, (char *)o_str_buf, ERR_STR_MAX); - size_t len = strlen((char *)o_str_buf); - - // Put the exception object together - o_str->base.type = &mp_type_str; - o_str->data = o_str_buf; - o_str->len = len; - o_str->hash = qstr_compute_hash(o_str->data, o_str->len); - // raise - mp_obj_t args[2] = { MP_OBJ_NEW_SMALL_INT(err), MP_OBJ_FROM_PTR(o_str)}; - nlr_raise(mp_obj_exception_make_new(&mp_type_OSError, 2, 0, args)); + nlr_raise(exc); #else - // mbedtls is compiled without error strings so we simply return the err number + // mbedtls is compiled without error strings, so just return the err number mp_raise_OSError(err); // err is typically a large negative number #endif } +static MP_NORETURN void mbedtls_raise_error(int err) { + mbedtls_raise_error_flags(err, 0); +} + // Because ssl_socket_send and ssl_socket_recv_into are callbacks from mbedtls code, // it is not OK to exit them by raising an exception (nlr_jump'ing through // foreign code is not permitted). Instead, preserve the error number of any OSError @@ -372,6 +415,15 @@ static void do_handshake(ssl_sslsocket_obj_t *self) { cleanup: self->closed = true; + + // Verification flags are only valid for CERT_VERIFY_FAILED. + // Read them before mbedtls_ssl_free() below: they live in the ssl context's + // session_negotiate and are gone once it is freed. + uint32_t verify_flags = 0; + if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { + verify_flags = mbedtls_ssl_get_verify_result(&self->ssl); + } + mbedtls_pk_free(&self->pkey); mbedtls_x509_crt_free(&self->cert); mbedtls_x509_crt_free(&self->cacert); @@ -385,7 +437,7 @@ static void do_handshake(ssl_sslsocket_obj_t *self) { } else if (ret == MBEDTLS_ERR_X509_BAD_INPUT_DATA) { mp_raise_ValueError(MP_ERROR_TEXT("invalid cert")); } else { - mbedtls_raise_error(ret); + mbedtls_raise_error_flags(ret, verify_flags); } } From b650e4901bce45b90932ba17940bcb5a069c57f7 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Fri, 7 Aug 2026 05:17:55 +0000 Subject: [PATCH 743/876] Revert "Add CIRCUITPY_HEAP_SRAM_SIZE: opt-in internal-RAM heap start segment" Superseded by the allocation-policy change that follows: per review discussion, make internal RAM the default for all port_malloc allocations instead of adding an opt-in setting. This reverts commit ebb7b0d4e3897e35b30d1e5c40573bff45a86773. --- docs/environment.rst | 18 ------------------ main.c | 20 +------------------- 2 files changed, 1 insertion(+), 37 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index dcdf7fe886f..4bf89bf774a 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -93,24 +93,6 @@ Larger values will reserve more RAM for python use and prevent the supervisor an from large allocations of their own. Smaller values will likely grow sooner than large start sizes. -CIRCUITPY_HEAP_SRAM_SIZE (integer) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -On boards where the python heap is normally placed in external PSRAM, allocate the heap's -*initial* segment (of this many bytes) from internal RAM instead. Later heap growth still -comes from PSRAM, so allocations made early in a program run at internal-RAM speed while -the total capacity is unchanged. If the requested size does not fit, the setting is -ignored and the heap starts in PSRAM as usual. Unset by default. - -When this setting is satisfied it fully defines the initial segment and -``CIRCUITPY_HEAP_START_SIZE`` is not consulted; ``CIRCUITPY_HEAP_START_SIZE`` applies -only when this setting is unset or its internal-RAM allocation fails. - -The internal pool is shared with DMA buffers (displays, audio). Buffers allocated at boot -coexist with this setting, but *re-allocating* a large buffer later (for example switching -a framebuffer display to a higher resolution at runtime) may fail, because the freed space -cannot merge across the live heap segment. With this setting, choose such sizes at boot -(e.g. via ``CIRCUITPY_DISPLAY_WIDTH``/``HEIGHT``) rather than switching at runtime. - CIRCUITPY_PYSTACK_SIZE (integer) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Sets the size of the python stack. Must be a multiple of 4. The default value is currently 1536. diff --git a/main.c b/main.c index f3c8148ac65..2020cb8c307 100644 --- a/main.c +++ b/main.c @@ -197,25 +197,7 @@ static void start_mp(safe_mode_t safe_mode) { #if MICROPY_ENABLE_GC size_t heap_size = 0; - // If CIRCUITPY_HEAP_SRAM_SIZE is set, try to place the heap's START segment in the - // internal (dma-capable) pool. On boards whose default heap lives in external PSRAM - // this puts early/hot allocations in fast RAM, while the heap still grows into PSRAM - // via MP_PLAT_ALLOC_HEAP. Unset (the default) keeps the current behavior; if the - // requested size does not fit the internal pool, we fall back to it as well. - #if CIRCUITPY_SETTINGS_TOML - if (safe_mode == SAFE_MODE_NONE) { - mp_int_t sram_size; - if (settings_get_int("CIRCUITPY_HEAP_SRAM_SIZE", &sram_size) == SETTINGS_OK && sram_size > 0) { - _heap = port_malloc((size_t)sram_size, true); - if (_heap != NULL) { - heap_size = (size_t)sram_size; - } - } - } - #endif - if (_heap == NULL) { - _heap = _allocate_memory(safe_mode, "CIRCUITPY_HEAP_START_SIZE", CIRCUITPY_HEAP_START_SIZE, &heap_size); - } + _heap = _allocate_memory(safe_mode, "CIRCUITPY_HEAP_START_SIZE", CIRCUITPY_HEAP_START_SIZE, &heap_size); gc_init(_heap, _heap + heap_size); #endif mp_init(); From 72fc03045e92b3dba6693e60c0d03c92871dc797 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Thu, 6 Aug 2026 18:03:36 +0000 Subject: [PATCH 744/876] raspberrypi: prefer internal RAM for all port_malloc allocations On boards with PSRAM the python heap and other non-DMA allocations went PSRAM-first, so everything paid external-memory latency even while most of internal SRAM sat unused. Try the internal pool first for every allocation and use PSRAM as spillover capacity for non-dma_capable requests that no longer fit. DMA-capable requests are internal-only as before. Measured on an Adafruit Fruit Jam: bulk copies within the heap 6.1 -> 108.9 MB/s, Bitmap.fill 6.8x, gc.collect 3.6x, ulab FFT (8192 pt) 14.6x, animated GIF playback 24 -> 56 fps, json.loads 1.26x. Working sets that fit the 16 KB XIP cache were already fast (a hot bytecode loop measures 1.00x); the win is on data larger than the cache. Boot-time DMA consumers (the display framebuffer) allocate before the heap grows, so they are unaffected. DMA buffers allocated at runtime (audio bounce buffers) now compete with a grown heap for internal RAM and can spill a program into MemoryError where they did not before - accepted for pre-release experimentation per review discussion. --- ports/raspberrypi/supervisor/port.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 23a318454ed..8a8b9fb052c 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -307,17 +307,17 @@ void port_heap_init(void) { } void *port_malloc(size_t size, bool dma_capable) { - if (!dma_capable && _psram_size > 0) { - common_hal_mcu_disable_interrupts(); - void *block = tlsf_malloc(_psram_heap, size); - common_hal_mcu_enable_interrupts(); - if (block) { - return block; - } - } + // Prefer internal RAM for everything: it is much faster than PSRAM + // (data there skips the external bus and the shared XIP cache). PSRAM, when + // present, serves as spillover capacity for allocations that don't need DMA. common_hal_mcu_disable_interrupts(); void *block = tlsf_malloc(_heap, size); common_hal_mcu_enable_interrupts(); + if (block == NULL && !dma_capable && _psram_size > 0) { + common_hal_mcu_disable_interrupts(); + block = tlsf_malloc(_psram_heap, size); + common_hal_mcu_enable_interrupts(); + } return block; } @@ -332,7 +332,11 @@ void port_free(void *ptr) { } void *port_realloc(void *ptr, size_t size, bool dma_capable) { - if (_psram_size > 0 && ((ptr != NULL && ((size_t)ptr) < SRAM_BASE) || (ptr == NULL && !dma_capable))) { + if (ptr == NULL) { + // Fresh allocation: same internal-first policy as port_malloc. + return port_malloc(size, dma_capable); + } + if (_psram_size > 0 && ((size_t)ptr) < SRAM_BASE) { common_hal_mcu_disable_interrupts(); void *block = tlsf_realloc(_psram_heap, ptr, size); common_hal_mcu_enable_interrupts(); From 7acc46b2caa6b4b8d6c831c4a3d6665c692603b3 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 7 Aug 2026 09:53:39 -0400 Subject: [PATCH 745/876] cxd56: make os.urandom() raise NotImplementedError --- ports/cxd56/common-hal/os/__init__.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/ports/cxd56/common-hal/os/__init__.c b/ports/cxd56/common-hal/os/__init__.c index e1024108b07..902228f1db0 100644 --- a/ports/cxd56/common-hal/os/__init__.c +++ b/ports/cxd56/common-hal/os/__init__.c @@ -10,17 +10,7 @@ #include "py/objstr.h" #include "py/objtuple.h" +// No HW TRNG. bool common_hal_os_urandom(uint8_t *buffer, mp_uint_t length) { - uint32_t i = 0; - - while (i < length) { - uint32_t new_random = rand(); - for (int j = 0; j < 4 && i < length; j++) { - buffer[i] = new_random & 0xff; - i++; - new_random >>= 8; - } - } - - return true; + return false; } From 2f3c98b3b8afbf19586643ef0a4b36283d518f93 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 7 Aug 2026 18:35:25 -0400 Subject: [PATCH 746/876] bring nvm.toml up to date for PR --- data/nvm.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/nvm.toml b/data/nvm.toml index 3f3921f351a..a2a0c03c221 160000 --- a/data/nvm.toml +++ b/data/nvm.toml @@ -1 +1 @@ -Subproject commit 3f3921f351ab206e729ad965c857b80a7ece8198 +Subproject commit a2a0c03c221a9bc37992147b5d4ad785a6e467fe From f76fbd66c1d6cc7ff69f5dfad457452e37eb6fb2 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 8 Aug 2026 00:37:22 +0200 Subject: [PATCH 747/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 6 ++++++ locale/el.po | 6 ++++++ locale/hi.po | 6 ++++++ locale/ko.po | 6 ++++++ locale/ru.po | 6 ++++++ locale/tr.po | 6 ++++++ 6 files changed, 36 insertions(+) diff --git a/locale/cs.po b/locale/cs.po index 20ecba5b49b..a7e3493b360 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1208,6 +1208,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c msgid "No CCCD for this Characteristic" msgstr "Žádné CCCD pro tuto charakteristiku" @@ -1230,11 +1231,13 @@ msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Writes not supported on Characteristic" msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Total data to write is larger than %q" msgstr "Velikost dat k zápisu je větší než %q" @@ -1249,6 +1252,9 @@ msgstr "Chybný BLE parametr" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" msgstr "Nepřipojený" diff --git a/locale/el.po b/locale/el.po index 83d329b7a41..c446385317d 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1211,6 +1211,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c msgid "No CCCD for this Characteristic" msgstr "" @@ -1233,11 +1234,13 @@ msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Writes not supported on Characteristic" msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Total data to write is larger than %q" msgstr "" @@ -1252,6 +1255,9 @@ msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index 483002dfde2..ead0359e102 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1202,6 +1202,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c msgid "No CCCD for this Characteristic" msgstr "" @@ -1224,11 +1225,13 @@ msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Writes not supported on Characteristic" msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Total data to write is larger than %q" msgstr "" @@ -1243,6 +1246,9 @@ msgstr "" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index 22f39814a90..7c37326dcaa 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1215,6 +1215,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c msgid "No CCCD for this Characteristic" msgstr "이 특성에 대한 CCCD가 없습니다" @@ -1237,11 +1238,13 @@ msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Writes not supported on Characteristic" msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Total data to write is larger than %q" msgstr "" @@ -1257,6 +1260,9 @@ msgstr "잘못된 BLE 파라미터" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" msgstr "연결되지 않았습니다" diff --git a/locale/ru.po b/locale/ru.po index 0e632d919c8..39a3dcbdc6a 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1215,6 +1215,7 @@ msgstr "Слишком много дескрипторов" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c msgid "No CCCD for this Characteristic" msgstr "Для этой характеристики нет CCCD" @@ -1237,11 +1238,13 @@ msgstr "максимальная_длина должна быть 0-%d когд #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Writes not supported on Characteristic" msgstr "Запись не поддерживается в Характеристика" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Total data to write is larger than %q" msgstr "Общее количество данных для записи превышает %q" @@ -1256,6 +1259,9 @@ msgstr "Недопустимый параметр BLE" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" msgstr "Не подключено" diff --git a/locale/tr.po b/locale/tr.po index d04687334d2..a77f902bf49 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1212,6 +1212,7 @@ msgstr "" #: ports/espressif/common-hal/_bleio/Characteristic.c #: ports/nordic/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c msgid "No CCCD for this Characteristic" msgstr "" @@ -1234,11 +1235,13 @@ msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Writes not supported on Characteristic" msgstr "" #: ports/espressif/common-hal/_bleio/PacketBuffer.c #: ports/nordic/common-hal/_bleio/PacketBuffer.c +#: ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c msgid "Total data to write is larger than %q" msgstr "" @@ -1253,6 +1256,9 @@ msgstr "Geçersiz BLE parametresi" #: ports/espressif/common-hal/_bleio/__init__.c #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Characteristic.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c +#: ports/zephyr-cp/common-hal/_bleio/Descriptor.c #: shared-bindings/_bleio/CharacteristicBuffer.c msgid "Not connected" msgstr "" From dca3aa660f6d889d2b6ff4c41fb9441f85d911bf Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Tue, 11 Aug 2026 14:29:39 +0000 Subject: [PATCH 748/876] shared-module/busdisplay: merge overlapping dirty rectangles Merge dirty rectangles whose bounding box is smaller than the two areas summed, so shared pixels are not sent twice. displayio does not merge them today, so it sends the overlap once per rectangle. Merging never sends more pixels than before. Fixes #10687 --- shared-module/busdisplay/BusDisplay.c | 60 +++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 01e0f7a7896..23ce331753a 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -34,6 +34,10 @@ #define DELAY 0x80 +// Max dirty rectangles held while merging overlapping ones before a refresh. More than this (rare) +// falls back to refreshing the raw list unmerged. +#define MAX_MERGE_AREAS 16 + void common_hal_busdisplay_busdisplay_construct(busdisplay_busdisplay_obj_t *self, mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, @@ -327,9 +331,59 @@ static void _refresh_display(busdisplay_busdisplay_obj_t *self) { } const displayio_area_t *current_area = _get_refresh_areas(self); - while (current_area != NULL) { - _refresh_area(self, current_area); - current_area = current_area->next; + + // Merge overlapping dirty rectangles so shared pixels are computed and sent once. displayio does + // not merge them, so overlapping/nested areas get their common pixels recomputed and retransmitted + // per rectangle (and drawn as separate, visibly sequential passes). A changing text label is the + // common case: it dirties the whole label area AND each glyph, so the glyph rectangles sit inside + // the label rectangle and nearly double the work. Copy the clipped areas into a scratch array and + // greedily fuse any pair whose bounding-box area is smaller than the two areas summed - i.e. they + // overlap enough that one rectangle sends fewer pixels than two. Distant / non-overlapping + // rectangles are left separate (their bounding box would be larger). The result is never more + // pixels than the unmerged list. If there are more areas than the scratch holds, fall back to + // refreshing the raw list unmerged. + displayio_area_t merged[MAX_MERGE_AREAS]; + size_t count = 0; + bool overflow = false; + for (const displayio_area_t *a = current_area; a != NULL; a = a->next) { + displayio_area_t clipped; + if (!displayio_display_core_clip_area(&self->core, a, &clipped)) { + continue; + } + if (count >= MAX_MERGE_AREAS) { + overflow = true; + break; + } + merged[count] = clipped; + count++; + } + if (overflow) { + while (current_area != NULL) { + _refresh_area(self, current_area); + current_area = current_area->next; + } + displayio_display_core_finish_refresh(&self->core); + return; + } + bool changed = true; + while (changed) { + changed = false; + for (size_t i = 0; i < count && !changed; i++) { + for (size_t j = i + 1; j < count; j++) { + displayio_area_t u; + displayio_area_union(&merged[i], &merged[j], &u); + if (displayio_area_size(&u) < displayio_area_size(&merged[i]) + displayio_area_size(&merged[j])) { + merged[i] = u; // fuse j into i + merged[j] = merged[count - 1]; // swap-remove j + count--; + changed = true; + break; + } + } + } + } + for (size_t i = 0; i < count; i++) { + _refresh_area(self, &merged[i]); } displayio_display_core_finish_refresh(&self->core); } From 1505fbd70b523c3912b2cb903185e3ece3000358 Mon Sep 17 00:00:00 2001 From: mikeysklar Date: Tue, 11 Aug 2026 13:42:57 -0700 Subject: [PATCH 749/876] usb_audio: support headset on ports with a dedicated ISO endpoint The combined microphone+speaker case allocated two sequential endpoint numbers in all cases. On ports that pin isochronous transfers to a dedicated endpoint number (USB_AUDIO_ISO_EP_NUM, currently nRF52) those numbers are not ISO-capable, so the device enumerated with correct descriptors but the stream never opened and no data was transferred. The nRF52 constraint is the endpoint number, not the direction: the USBD has a separate ISOIN and ISOOUT on endpoint 8, and TinyUSB splits the ISO buffer (ISOSPLIT = HalfIN) when both are open. Use the dedicated number for both directions on those ports, and do not consume sequential endpoint numbers, matching what the single-direction branches already do. Sequential-allocation ports are unaffected. Tested on Feather nRF52840 Express: microphone+speaker now enumerates on 0x08/0x88 and streams in both directions at once, verified by recording and playing simultaneously. Metro RP2040 unchanged on 0x06/0x87 with identical capture results. --- shared-module/usb_audio/__init__.c | 39 ++++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 2c7eda15d81..88bf9cd636d 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -303,16 +303,20 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de if (usb_audio_direction_is_input_output()) { // Combined headset: a speaker AudioStreaming interface (OUT) and a mic - // AudioStreaming interface (IN) under one AudioControl interface. This - // needs two isochronous endpoints, so it cannot be served by ports that - // pin ISO to a single dedicated endpoint number (forced_iso_ep, e.g. - // nRF52, which has only one ISO-capable endpoint). On those ports the - // sequential numbers below will not match the hardware's required ISO - // endpoint and the stream will not open; INPUT_OUTPUT is effectively - // unsupported there. The sequential-allocation ports (e.g. RP2) take a - // distinct number for each direction. - const uint8_t ep_out = descriptor_counts->current_endpoint; - const uint8_t ep_in = descriptor_counts->current_endpoint + 1; + // AudioStreaming interface (IN) under one AudioControl interface, so one + // isochronous endpoint in each direction. + // + // Sequential-allocation ports (e.g. RP2) take a distinct number for each + // direction. Ports that pin ISO to a dedicated endpoint number + // (forced_iso_ep, e.g. nRF52) use that one number for BOTH directions: + // the constraint there is the endpoint *number*, not the direction. The + // nRF52 USBD has a separate ISOIN and ISOOUT on endpoint 8, and TinyUSB + // splits the ISO buffer (ISOSPLIT = HalfIN) when both are open, so 0x08 + // and 0x88 can run at the same time. As in the single-direction branches + // below, the dedicated ISO endpoint is separate hardware and must not + // consume the sequential endpoint numbers the other interfaces draw from. + const uint8_t ep_out = forced_iso_ep ? iso_ep_num : descriptor_counts->current_endpoint; + const uint8_t ep_in = forced_iso_ep ? iso_ep_num : (descriptor_counts->current_endpoint + 1); usb_add_interface_string(*current_interface_string, "CircuitPython Headset"); @@ -333,13 +337,16 @@ size_t usb_audio_add_descriptor(uint8_t *descriptor_buf, descriptor_counts_t *de (*current_interface_string)++; // One IAD wrapping an AudioControl + two AudioStreaming interfaces, plus a - // single isochronous endpoint in each direction. The two directions take - // separate endpoint numbers (ep_out and ep_in above), so this consumes two - // of the port's endpoint pairs. + // single isochronous endpoint in each direction. On sequential-allocation + // ports the two directions take separate endpoint numbers, consuming two of + // the port's endpoint pairs. On forced_iso_ep ports both directions share + // the dedicated ISO endpoint, which is separate hardware and consumes none. descriptor_counts->current_interface += 3; - descriptor_counts->num_out_endpoints += 1; - descriptor_counts->num_in_endpoints += 1; - descriptor_counts->current_endpoint += 2; + if (!forced_iso_ep) { + descriptor_counts->num_out_endpoints += 1; + descriptor_counts->num_in_endpoints += 1; + descriptor_counts->current_endpoint += 2; + } memcpy(descriptor_buf, usb_audio_descriptor, sizeof(usb_audio_descriptor)); From bf828d83d7ab747763c870d0770d61e1c3e579f0 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 12 Aug 2026 08:00:43 -0500 Subject: [PATCH 750/876] Remove `bits_per_sample` from docstrings --- shared-bindings/usb_audio/USBSpeaker.c | 2 +- shared-bindings/usb_audio/__init__.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/shared-bindings/usb_audio/USBSpeaker.c b/shared-bindings/usb_audio/USBSpeaker.c index d9302886c64..78c5e6099b9 100644 --- a/shared-bindings/usb_audio/USBSpeaker.c +++ b/shared-bindings/usb_audio/USBSpeaker.c @@ -33,7 +33,7 @@ //| //| # boot.py //| import usb_audio -//| usb_audio.enable(sample_rate=16000, channel_count=1, bits_per_sample=16, +//| usb_audio.enable(sample_rate=16000, channel_count=1, //| microphone=False, speaker=True) //| //| .. code-block:: py diff --git a/shared-bindings/usb_audio/__init__.c b/shared-bindings/usb_audio/__init__.c index 00ec82f10ae..31d3ab549fd 100644 --- a/shared-bindings/usb_audio/__init__.c +++ b/shared-bindings/usb_audio/__init__.c @@ -32,7 +32,7 @@ //| //| # boot.py //| import usb_audio -//| usb_audio.enable(sample_rate=16000, bits_per_sample=16) +//| usb_audio.enable(sample_rate=16000) //| //| .. code-block:: py //| @@ -92,7 +92,6 @@ //| //| :param int sample_rate: Samples per second of the streamed audio. //| :param int channel_count: Number of channels. Either mono (1) or stereo (2) is supported. -//| :param int bits_per_sample: Bits per signed PCM sample. Only 16 is supported initially. //| :param bool microphone: Present a microphone (audio flows board -> host). Enabled by default. //| :param bool speaker: Present a speaker (audio flows host -> board). //| From cf2fae8f5f925ae9837c6474e7378961eb666b4a Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 12 Aug 2026 10:07:51 -0500 Subject: [PATCH 751/876] Fix note panning calculation to match `audiomixer.Mixer` --- shared-module/synthio/Note.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/shared-module/synthio/Note.c b/shared-module/synthio/Note.c index c8c307bb415..01c7e4ba487 100644 --- a/shared-module/synthio/Note.c +++ b/shared-module/synthio/Note.c @@ -196,13 +196,11 @@ static uint32_t pitch_bend(uint32_t frequency_scaled, int32_t bend_value) { uint32_t synthio_note_step(synthio_note_obj_t *self, int32_t sample_rate, int16_t dur, int16_t loudness[2]) { int panning = synthio_block_slot_get_scaled(&self->panning, -ALMOST_ONE, ALMOST_ONE); - int left_panning_scaled, right_panning_scaled; + int left_panning_scaled = 32768, right_panning_scaled = 32768; if (panning >= 0) { - left_panning_scaled = 32768; - right_panning_scaled = 32767 - panning; + left_panning_scaled = 32767 - panning; } else { - right_panning_scaled = 32768; - left_panning_scaled = 32767 + panning; + right_panning_scaled = 32767 + panning; } int amplitude = synthio_block_slot_get_scaled(&self->amplitude, -ALMOST_ONE, ALMOST_ONE); From dfa5515c3e906f0f188c0749db7fe873ad3703ce Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Wed, 12 Aug 2026 10:08:13 -0500 Subject: [PATCH 752/876] Add note panning test --- tests/circuitpython/synth_note_panning.py | 10 + tests/circuitpython/synth_note_panning.py.exp | 16128 ++++++++++++++++ 2 files changed, 16138 insertions(+) create mode 100644 tests/circuitpython/synth_note_panning.py create mode 100644 tests/circuitpython/synth_note_panning.py.exp diff --git a/tests/circuitpython/synth_note_panning.py b/tests/circuitpython/synth_note_panning.py new file mode 100644 index 00000000000..3968f2dfddb --- /dev/null +++ b/tests/circuitpython/synth_note_panning.py @@ -0,0 +1,10 @@ +from synthnotehelper import * + + +@synth_test(channel_count=2) +def gen(synth): + l = LFO(sine, offset=0.0, scale=1.0, rate=2) + yield [l] + n = Note(8, panning=l) + synth.press(n) + yield 2 diff --git a/tests/circuitpython/synth_note_panning.py.exp b/tests/circuitpython/synth_note_panning.py.exp new file mode 100644 index 00000000000..7b6bd871424 --- /dev/null +++ b/tests/circuitpython/synth_note_panning.py.exp @@ -0,0 +1,16128 @@ +0.0 0.0 0.0 0.391339111328125 +0.000125 0.003173828125 0.005218505859375 0.391339111328125 +0.00025 0.003173828125 0.005218505859375 0.391339111328125 +0.000375 0.00634765625 0.01043701171875 0.391339111328125 +0.0005 0.009552001953125 0.01568603515625 0.391339111328125 +0.000625 0.009552001953125 0.01568603515625 0.391339111328125 +0.00075 0.012725830078125 0.020904541015625 0.391339111328125 +0.000875 0.012725830078125 0.020904541015625 0.391339111328125 +0.001 0.015899658203125 0.026123046875 0.391339111328125 +0.0011250000000000002 0.019073486328125 0.0313720703125 0.391339111328125 +0.00125 0.019073486328125 0.0313720703125 0.391339111328125 +0.001375 0.022247314453125 0.036590576171875 0.391339111328125 +0.0015 0.022247314453125 0.036590576171875 0.391339111328125 +0.0016250000000000002 0.02545166015625 0.04180908203125 0.391339111328125 +0.00175 0.02862548828125 0.047027587890625 0.391339111328125 +0.001875 0.02862548828125 0.047027587890625 0.391339111328125 +0.002 0.03179931640625 0.05224609375 0.391339111328125 +0.002125 0.03179931640625 0.05224609375 0.391339111328125 +0.0022500000000000004 0.034942626953125 0.05743408203125 0.391339111328125 +0.002375 0.038116455078125 0.0626220703125 0.391339111328125 +0.0025 0.038116455078125 0.0626220703125 0.391339111328125 +0.002625 0.041259765625 0.06781005859375 0.391339111328125 +0.00275 0.041259765625 0.06781005859375 0.391339111328125 +0.002875 0.04443359375 0.072998046875 0.391339111328125 +0.003 0.047576904296875 0.07818603515625 0.391339111328125 +0.003125 0.047576904296875 0.07818603515625 0.391339111328125 +0.0032500000000000004 0.05072021484375 0.083343505859375 0.391339111328125 +0.003375 0.05072021484375 0.083343505859375 0.391339111328125 +0.0035 0.053863525390625 0.0885009765625 0.391339111328125 +0.003625 0.0570068359375 0.093658447265625 0.391339111328125 +0.00375 0.0570068359375 0.093658447265625 0.391339111328125 +0.003875 0.06011962890625 0.098785400390625 0.391339111328125 +0.004 0.06011962890625 0.098785400390625 0.391339111328125 +0.004125 0.063232421875 0.103912353515625 0.391339111328125 +0.00425 0.06634521484375 0.109039306640625 0.391339111328125 +0.004375 0.06634521484375 0.109039306640625 0.391339111328125 +0.0045000000000000006 0.0694580078125 0.1141357421875 0.391339111328125 +0.004625 0.0694580078125 0.1141357421875 0.391339111328125 +0.00475 0.07257080078125 0.119232177734375 0.391339111328125 +0.004875 0.075653076171875 0.124298095703125 0.391339111328125 +0.005 0.075653076171875 0.124298095703125 0.391339111328125 +0.005125 0.0787353515625 0.129364013671875 0.391339111328125 +0.00525 0.0787353515625 0.129364013671875 0.391339111328125 +0.0053750000000000008 0.081817626953125 0.134429931640625 0.391339111328125 +0.0055 0.084869384765625 0.13946533203125 0.391339111328125 +0.005625 0.084869384765625 0.13946533203125 0.391339111328125 +0.00575 0.087921142578125 0.14447021484375 0.391339111328125 +0.005875 0.087921142578125 0.14447021484375 0.391339111328125 +0.006 0.090972900390625 0.14947509765625 0.391339111328125 +0.006125 0.093994140625 0.15447998046875 0.391339111328125 +0.00625 0.093994140625 0.15447998046875 0.391339111328125 +0.0063750000000000008 0.0970458984375 0.159454345703125 0.391339111328125 +0.006500000000000001 0.0970458984375 0.159454345703125 0.391339111328125 +0.006625 0.10003662109375 0.164398193359375 0.391339111328125 +0.00675 0.103057861328125 0.169342041015625 0.391339111328125 +0.006875 0.103057861328125 0.169342041015625 0.391339111328125 +0.007 0.106048583984375 0.17425537109375 0.391339111328125 +0.007125 0.106048583984375 0.17425537109375 0.391339111328125 +0.00725 0.1090087890625 0.17913818359375 0.391339111328125 +0.00737500000000000064 0.11199951171875 0.18402099609375 0.391339111328125 +0.0075 0.11199951171875 0.18402099609375 0.391339111328125 +0.007625 0.114959716796875 0.188873291015625 0.391339111328125 +0.00775 0.114959716796875 0.188873291015625 0.391339111328125 +0.007875 0.117889404296875 0.1937255859375 0.391339111328125 +0.008 0.120819091796875 0.19854736328125 0.391339111328125 +0.008125 0.120819091796875 0.19854736328125 0.391339111328125 +0.00825 0.123748779296875 0.203338623046875 0.391339111328125 +0.008375 0.123748779296875 0.203338623046875 0.391339111328125 +0.008500000000000001 0.12664794921875 0.208099365234375 0.391339111328125 +0.008625000000000001 0.129547119140625 0.212860107421875 0.391339111328125 +0.008750000000000001 0.129547119140625 0.212860107421875 0.391339111328125 +0.008875000000000001 0.132415771484375 0.21759033203125 0.391339111328125 +0.009000000000000001 0.132415771484375 0.21759033203125 0.391339111328125 +0.009125 0.135284423828125 0.2222900390625 0.391339111328125 +0.00925 0.13812255859375 0.226959228515625 0.391339111328125 +0.009375 0.13812255859375 0.226959228515625 0.391339111328125 +0.0095 0.140960693359375 0.231597900390625 0.391339111328125 +0.009625 0.140960693359375 0.231597900390625 0.391339111328125 +0.00975 0.143768310546875 0.236236572265625 0.391339111328125 +0.009875 0.146575927734375 0.2408447265625 0.391339111328125 +0.01 0.146575927734375 0.2408447265625 0.391339111328125 +0.010125 0.14935302734375 0.24542236328125 0.391339111328125 +0.01025 0.14935302734375 0.24542236328125 0.391339111328125 +0.010375 0.152130126953125 0.249969482421875 0.391339111328125 +0.0105 0.154876708984375 0.25445556640625 0.391339111328125 +0.010625 0.154876708984375 0.25445556640625 0.391339111328125 +0.0107500000000000016 0.157623291015625 0.25897216796875 0.391339111328125 +0.0108750000000000016 0.157623291015625 0.25897216796875 0.391339111328125 +0.011 0.160308837890625 0.263427734375 0.391339111328125 +0.011125 0.16302490234375 0.267852783203125 0.391339111328125 +0.01125 0.16302490234375 0.267852783203125 0.391339111328125 +0.011375 0.16571044921875 0.27227783203125 0.391339111328125 +0.0115 0.16571044921875 0.27227783203125 0.391339111328125 +0.011625 0.168365478515625 0.276641845703125 0.391339111328125 +0.01175 0.1710205078125 0.280975341796875 0.391339111328125 +0.011875 0.1710205078125 0.280975341796875 0.391339111328125 +0.012 0.17364501953125 0.285308837890625 0.391339111328125 +0.012125 0.17364501953125 0.285308837890625 0.391339111328125 +0.01225 0.176239013671875 0.289581298828125 0.391339111328125 +0.012375 0.1788330078125 0.2938232421875 0.391339111328125 +0.0125 0.1788330078125 0.2938232421875 0.391339111328125 +0.012625 0.181396484375 0.298065185546875 0.391339111328125 +0.0127500000000000016 0.181396484375 0.298065185546875 0.391339111328125 +0.0128750000000000016 0.1839599609375 0.30224609375 0.391339111328125 +0.013000000000000002 0.186492919921875 0.306396484375 0.391339111328125 +0.013125 0.186492919921875 0.306396484375 0.391339111328125 +0.01325 0.188995361328125 0.310516357421875 0.391339111328125 +0.013375 0.188995361328125 0.310516357421875 0.391339111328125 +0.0135 0.19146728515625 0.314605712890625 0.391339111328125 +0.013625 0.193939208984375 0.31866455078125 0.391339111328125 +0.01375 0.193939208984375 0.31866455078125 0.391339111328125 +0.013875 0.196380615234375 0.322662353515625 0.391339111328125 +0.014 0.196380615234375 0.322662353515625 0.391339111328125 +0.014125 0.19879150390625 0.32666015625 0.391339111328125 +0.01425 0.201202392578125 0.330596923828125 0.391339111328125 +0.014375 0.201202392578125 0.330596923828125 0.391339111328125 +0.0145 0.203582763671875 0.334503173828125 0.391339111328125 +0.014625 0.203582763671875 0.334503173828125 0.391339111328125 +0.0147500000000000016 0.2059326171875 0.33837890625 0.391339111328125 +0.0148750000000000013 0.208282470703125 0.34222412109375 0.391339111328125 +0.015 0.208282470703125 0.34222412109375 0.391339111328125 +0.015125 0.210601806640625 0.34600830078125 0.391339111328125 +0.01525 0.210601806640625 0.34600830078125 0.391339111328125 +0.015375 0.212860107421875 0.349761962890625 0.391339111328125 +0.0155 0.21514892578125 0.353485107421875 0.391339111328125 +0.015625 0.21514892578125 0.353485107421875 0.391339111328125 +0.01575 0.217376708984375 0.357177734375 0.391339111328125 +0.015875 0.217376708984375 0.357177734375 0.391339111328125 +0.016 0.2196044921875 0.360809326171875 0.391339111328125 +0.016125 0.2218017578125 0.36444091796875 0.391339111328125 +0.01625 0.2218017578125 0.36444091796875 0.391339111328125 +0.016375 0.223968505859375 0.36798095703125 0.391339111328125 +0.0165 0.223968505859375 0.36798095703125 0.391339111328125 +0.016625 0.226104736328125 0.37152099609375 0.391339111328125 +0.01675 0.22821044921875 0.375 0.391339111328125 +0.016875 0.22821044921875 0.375 0.391339111328125 +0.017 0.230316162109375 0.378448486328125 0.391339111328125 +0.017125 0.230316162109375 0.378448486328125 0.391339111328125 +0.01725 0.232391357421875 0.3818359375 0.391339111328125 +0.017375 0.23443603515625 0.38519287109375 0.391339111328125 +0.0175 0.23443603515625 0.38519287109375 0.391339111328125 +0.017625000000000002 0.2364501953125 0.388519287109375 0.391339111328125 +0.017750000000000002 0.2364501953125 0.388519287109375 0.391339111328125 +0.017875000000000002 0.238433837890625 0.39178466796875 0.391339111328125 +0.018000000000000002 0.24041748046875 0.39501953125 0.391339111328125 +0.018125 0.24041748046875 0.39501953125 0.391339111328125 +0.01825 0.242340087890625 0.398193359375 0.391339111328125 +0.018375 0.242340087890625 0.398193359375 0.391339111328125 +0.0185 0.2442626953125 0.401336669921875 0.391339111328125 +0.018625 0.24615478515625 0.404449462890625 0.391339111328125 +0.01875 0.24615478515625 0.404449462890625 0.391339111328125 +0.018875 0.248016357421875 0.407501220703125 0.391339111328125 +0.019 0.248016357421875 0.407501220703125 0.391339111328125 +0.019125 0.249847412109375 0.4105224609375 0.391339111328125 +0.01925 0.25164794921875 0.413482666015625 0.391339111328125 +0.019375 0.25164794921875 0.413482666015625 0.391339111328125 +0.0195 0.25341796875 0.416412353515625 0.391339111328125 +0.019625 0.25341796875 0.416412353515625 0.391339111328125 +0.01975 0.255157470703125 0.419281005859375 0.391339111328125 +0.019875 0.25689697265625 0.422119140625 0.391339111328125 +0.02 0.25689697265625 0.422119140625 0.391339111328125 +0.020125 0.258575439453125 0.424896240234375 0.391339111328125 +0.02025 0.258575439453125 0.424896240234375 0.391339111328125 +0.020375 0.26025390625 0.4276123046875 0.391339111328125 +0.0205 0.261871337890625 0.4302978515625 0.391339111328125 +0.020625 0.261871337890625 0.4302978515625 0.391339111328125 +0.02075 0.26348876953125 0.432952880859375 0.391339111328125 +0.020875 0.26348876953125 0.432952880859375 0.391339111328125 +0.021 0.26507568359375 0.435546875 0.391339111328125 +0.021125 0.266632080078125 0.438079833984375 0.391339111328125 +0.02125 0.266632080078125 0.438079833984375 0.391339111328125 +0.021375 0.268157958984375 0.440582275390625 0.391339111328125 +0.0215000000000000032 0.268157958984375 0.440582275390625 0.391339111328125 +0.0216250000000000032 0.269622802734375 0.44305419921875 0.391339111328125 +0.0217500000000000032 0.271087646484375 0.4454345703125 0.391339111328125 +0.0218750000000000032 0.271087646484375 0.4454345703125 0.391339111328125 +0.022 0.27252197265625 0.447784423828125 0.391339111328125 +0.022125 0.27252197265625 0.447784423828125 0.391339111328125 +0.02225 0.27392578125 0.450103759765625 0.391339111328125 +0.022375 0.275299072265625 0.452362060546875 0.391339111328125 +0.0225 0.275299072265625 0.452362060546875 0.391339111328125 +0.022625 0.276641845703125 0.454559326171875 0.391339111328125 +0.02275 0.276641845703125 0.454559326171875 0.391339111328125 +0.022875 0.2779541015625 0.45672607421875 0.391339111328125 +0.023 0.27923583984375 0.458831787109375 0.391339111328125 +0.023125 0.27923583984375 0.458831787109375 0.391339111328125 +0.02325 0.280487060546875 0.46087646484375 0.391339111328125 +0.023375 0.280487060546875 0.46087646484375 0.391339111328125 +0.0235 0.281707763671875 0.462890625 0.391339111328125 +0.023625 0.28289794921875 0.464813232421875 0.391339111328125 +0.02375 0.28289794921875 0.464813232421875 0.391339111328125 +0.023875 0.2840576171875 0.46673583984375 0.391339111328125 +0.024 0.2840576171875 0.46673583984375 0.391339111328125 +0.024125 0.285186767578125 0.46856689453125 0.391339111328125 +0.02425 0.2862548828125 0.470367431640625 0.391339111328125 +0.024375 0.2862548828125 0.470367431640625 0.391339111328125 +0.0245 0.287322998046875 0.472137451171875 0.391339111328125 +0.024625 0.287322998046875 0.472137451171875 0.391339111328125 +0.02475 0.288360595703125 0.47381591796875 0.391339111328125 +0.024875 0.28936767578125 0.4754638671875 0.391339111328125 +0.025 0.28936767578125 0.4754638671875 0.391339111328125 +0.025125 0.29034423828125 0.47705078125 0.391339111328125 +0.02525 0.29034423828125 0.47705078125 0.391339111328125 +0.025375 0.291259765625 0.478607177734375 0.391339111328125 +0.0255000000000000032 0.29217529296875 0.480072021484375 0.391339111328125 +0.0256250000000000032 0.29217529296875 0.480072021484375 0.391339111328125 +0.0257500000000000032 0.293060302734375 0.48150634765625 0.391339111328125 +0.0258750000000000032 0.293060302734375 0.48150634765625 0.391339111328125 +0.026000000000000004 0.29388427734375 0.48291015625 0.391339111328125 +0.026125 0.294708251953125 0.484222412109375 0.391339111328125 +0.02625 0.294708251953125 0.484222412109375 0.391339111328125 +0.026375 0.29547119140625 0.485504150390625 0.391339111328125 +0.0265 0.29547119140625 0.485504150390625 0.391339111328125 +0.026625 0.296234130859375 0.486724853515625 0.391339111328125 +0.02675 0.29693603515625 0.487884521484375 0.391339111328125 +0.026875 0.29693603515625 0.487884521484375 0.391339111328125 +0.027 0.297607421875 0.489013671875 0.391339111328125 +0.027125 0.297607421875 0.489013671875 0.391339111328125 +0.02725 0.298248291015625 0.490081787109375 0.391339111328125 +0.027375 0.298858642578125 0.4910888671875 0.391339111328125 +0.0275 0.298858642578125 0.4910888671875 0.391339111328125 +0.027625 0.299468994140625 0.492034912109375 0.391339111328125 +0.02775 0.299468994140625 0.492034912109375 0.391339111328125 +0.027875 0.300018310546875 0.492950439453125 0.391339111328125 +0.028 0.300506591796875 0.4937744140625 0.391339111328125 +0.028125 0.300506591796875 0.4937744140625 0.391339111328125 +0.02825 0.300994873046875 0.49456787109375 0.391339111328125 +0.028375 0.300994873046875 0.49456787109375 0.391339111328125 +0.0285 0.30145263671875 0.49530029296875 0.391339111328125 +0.028625 0.301849365234375 0.496002197265625 0.391339111328125 +0.02875 0.301849365234375 0.496002197265625 0.391339111328125 +0.028875 0.30224609375 0.496612548828125 0.391339111328125 +0.029 0.30224609375 0.496612548828125 0.391339111328125 +0.029125 0.302581787109375 0.4971923828125 0.391339111328125 +0.02925 0.30291748046875 0.497711181640625 0.391339111328125 +0.0293750000000000032 0.30291748046875 0.497711181640625 0.391339111328125 +0.0295000000000000032 0.303192138671875 0.498199462890625 0.391339111328125 +0.0296250000000000026 0.303192138671875 0.498199462890625 0.391339111328125 +0.0297500000000000026 0.303436279296875 0.49859619140625 0.391339111328125 +0.0298750000000000026 0.30364990234375 0.49896240234375 0.391339111328125 +0.03 0.30364990234375 0.49896240234375 0.391339111328125 +0.030125 0.303863525390625 0.499267578125 0.391339111328125 +0.03025 0.303863525390625 0.499267578125 0.391339111328125 +0.030375 0.303985595703125 0.49951171875 0.391339111328125 +0.0305 0.304107666015625 0.49969482421875 0.391339111328125 +0.030625 0.304107666015625 0.49969482421875 0.391339111328125 +0.03075 0.30419921875 0.49981689453125 0.391339111328125 +0.030875 0.30419921875 0.49981689453125 0.391339111328125 +0.031 0.30426025390625 0.499908447265625 0.391339111328125 +0.031125 0.30426025390625 0.49993896484375 0.391339111328125 +0.03125 0.30426025390625 0.49993896484375 0.391339111328125 +0.031375 0.30426025390625 0.499908447265625 0.391339111328125 +0.0315 0.30426025390625 0.499908447265625 0.391339111328125 +0.031625 0.30419921875 0.49981689453125 0.391339111328125 +0.03175 0.304107666015625 0.49969482421875 0.391339111328125 +0.031875 0.304107666015625 0.49969482421875 0.391339111328125 +0.032 0.139678955078125 0.49951171875 0.7202575683593749 +0.032125 0.139678955078125 0.49951171875 0.7202575683593749 +0.03225 0.139617919921875 0.499267578125 0.7202575683593749 +0.032375 0.1395263671875 0.49896240234375 0.7202575683593749 +0.0325 0.1395263671875 0.49896240234375 0.7202575683593749 +0.032625 0.139434814453125 0.49859619140625 0.7202575683593749 +0.03275 0.139434814453125 0.49859619140625 0.7202575683593749 +0.032875 0.139312744140625 0.498199462890625 0.7202575683593749 +0.033 0.139190673828125 0.497711181640625 0.7202575683593749 +0.033125 0.139190673828125 0.497711181640625 0.7202575683593749 +0.03325 0.1390380859375 0.4971923828125 0.7202575683593749 +0.033375 0.1390380859375 0.4971923828125 0.7202575683593749 +0.0335 0.138885498046875 0.496612548828125 0.7202575683593749 +0.033625 0.138702392578125 0.496002197265625 0.7202575683593749 +0.03375 0.138702392578125 0.496002197265625 0.7202575683593749 +0.033875 0.138519287109375 0.49530029296875 0.7202575683593749 +0.034 0.138519287109375 0.49530029296875 0.7202575683593749 +0.034125 0.1383056640625 0.49456787109375 0.7202575683593749 +0.03425 0.138092041015625 0.4937744140625 0.7202575683593749 +0.034375 0.138092041015625 0.4937744140625 0.7202575683593749 +0.0345 0.137847900390625 0.492950439453125 0.7202575683593749 +0.034625 0.137847900390625 0.492950439453125 0.7202575683593749 +0.03475 0.137603759765625 0.492034912109375 0.7202575683593749 +0.034875 0.1373291015625 0.4910888671875 0.7202575683593749 +0.035 0.1373291015625 0.4910888671875 0.7202575683593749 +0.035125 0.137054443359375 0.490081787109375 0.7202575683593749 +0.035250000000000004 0.137054443359375 0.490081787109375 0.7202575683593749 +0.035375000000000004 0.136749267578125 0.489013671875 0.7202575683593749 +0.035500000000000004 0.136444091796875 0.487884521484375 0.7202575683593749 +0.035625000000000004 0.136444091796875 0.487884521484375 0.7202575683593749 +0.035750000000000004 0.1361083984375 0.486724853515625 0.7202575683593749 +0.035875000000000004 0.1361083984375 0.486724853515625 0.7202575683593749 +0.036000000000000004 0.135772705078125 0.485504150390625 0.7202575683593749 +0.036125 0.135406494140625 0.484222412109375 0.7202575683593749 +0.03625 0.135406494140625 0.484222412109375 0.7202575683593749 +0.036375 0.135040283203125 0.48291015625 0.7202575683593749 +0.0365 0.135040283203125 0.48291015625 0.7202575683593749 +0.036625 0.1346435546875 0.48150634765625 0.7202575683593749 +0.03675 0.134246826171875 0.480072021484375 0.7202575683593749 +0.036875 0.134246826171875 0.480072021484375 0.7202575683593749 +0.037 0.13385009765625 0.478607177734375 0.7202575683593749 +0.037125 0.13385009765625 0.478607177734375 0.7202575683593749 +0.03725 0.1334228515625 0.47705078125 0.7202575683593749 +0.037375 0.132965087890625 0.4754638671875 0.7202575683593749 +0.0375 0.132965087890625 0.4754638671875 0.7202575683593749 +0.037625 0.13250732421875 0.47381591796875 0.7202575683593749 +0.03775 0.13250732421875 0.47381591796875 0.7202575683593749 +0.037875 0.13201904296875 0.472137451171875 0.7202575683593749 +0.038 0.13153076171875 0.470367431640625 0.7202575683593749 +0.038125 0.13153076171875 0.470367431640625 0.7202575683593749 +0.03825 0.13104248046875 0.46856689453125 0.7202575683593749 +0.038375 0.13104248046875 0.46856689453125 0.7202575683593749 +0.0385 0.130523681640625 0.46673583984375 0.7202575683593749 +0.038625 0.129974365234375 0.464813232421875 0.7202575683593749 +0.03875 0.129974365234375 0.464813232421875 0.7202575683593749 +0.038875 0.12945556640625 0.462890625 0.7202575683593749 +0.039 0.12945556640625 0.462890625 0.7202575683593749 +0.039125 0.128875732421875 0.46087646484375 0.7202575683593749 +0.03925 0.128326416015625 0.458831787109375 0.7202575683593749 +0.039375 0.128326416015625 0.458831787109375 0.7202575683593749 +0.0395 0.127716064453125 0.45672607421875 0.7202575683593749 +0.039625 0.127716064453125 0.45672607421875 0.7202575683593749 +0.03975 0.127105712890625 0.454559326171875 0.7202575683593749 +0.039875 0.126495361328125 0.452362060546875 0.7202575683593749 +0.04 0.126495361328125 0.452362060546875 0.7202575683593749 +0.040125 0.125885009765625 0.450103759765625 0.7202575683593749 +0.04025 0.125885009765625 0.450103759765625 0.7202575683593749 +0.040375 0.125213623046875 0.447784423828125 0.7202575683593749 +0.0405 0.12457275390625 0.4454345703125 0.7202575683593749 +0.040625 0.12457275390625 0.4454345703125 0.7202575683593749 +0.04075 0.1239013671875 0.44305419921875 0.7202575683593749 +0.040875 0.1239013671875 0.44305419921875 0.7202575683593749 +0.041 0.123199462890625 0.440582275390625 0.7202575683593749 +0.041125 0.12249755859375 0.438079833984375 0.7202575683593749 +0.04125 0.12249755859375 0.438079833984375 0.7202575683593749 +0.041375 0.121795654296875 0.435546875 0.7202575683593749 +0.0415 0.121795654296875 0.435546875 0.7202575683593749 +0.041625 0.121063232421875 0.432952880859375 0.7202575683593749 +0.04175 0.120330810546875 0.4302978515625 0.7202575683593749 +0.041875 0.120330810546875 0.4302978515625 0.7202575683593749 +0.042 0.119598388671875 0.4276123046875 0.7202575683593749 +0.042125 0.119598388671875 0.4276123046875 0.7202575683593749 +0.04225 0.11883544921875 0.424896240234375 0.7202575683593749 +0.042375 0.1180419921875 0.422119140625 0.7202575683593749 +0.0425 0.1180419921875 0.422119140625 0.7202575683593749 +0.042625 0.11724853515625 0.419281005859375 0.7202575683593749 +0.04275 0.11724853515625 0.419281005859375 0.7202575683593749 +0.042875 0.116455078125 0.416412353515625 0.7202575683593749 +0.0430000000000000036 0.115631103515625 0.413482666015625 0.7202575683593749 +0.0431250000000000036 0.115631103515625 0.413482666015625 0.7202575683593749 +0.0432500000000000036 0.11480712890625 0.4105224609375 0.7202575683593749 +0.0433750000000000036 0.11480712890625 0.4105224609375 0.7202575683593749 +0.0435000000000000036 0.11395263671875 0.407501220703125 0.7202575683593749 +0.0436250000000000036 0.11309814453125 0.404449462890625 0.7202575683593749 +0.0437500000000000036 0.11309814453125 0.404449462890625 0.7202575683593749 +0.0438750000000000036 0.11224365234375 0.401336669921875 0.7202575683593749 +0.044 0.11224365234375 0.401336669921875 0.7202575683593749 +0.044125 0.111358642578125 0.398193359375 0.7202575683593749 +0.04425 0.1104736328125 0.39501953125 0.7202575683593749 +0.044375 0.1104736328125 0.39501953125 0.7202575683593749 +0.0445 0.10955810546875 0.39178466796875 0.7202575683593749 +0.044625 0.10955810546875 0.39178466796875 0.7202575683593749 +0.04475 0.108642578125 0.388519287109375 0.7202575683593749 +0.044875 0.10772705078125 0.38519287109375 0.7202575683593749 +0.045 0.10772705078125 0.38519287109375 0.7202575683593749 +0.045125 0.106781005859375 0.3818359375 0.7202575683593749 +0.04525 0.106781005859375 0.3818359375 0.7202575683593749 +0.045375 0.1058349609375 0.378448486328125 0.7202575683593749 +0.0455 0.1048583984375 0.375 0.7202575683593749 +0.045625 0.1048583984375 0.375 0.7202575683593749 +0.04575 0.1038818359375 0.37152099609375 0.7202575683593749 +0.045875 0.1038818359375 0.37152099609375 0.7202575683593749 +0.046 0.1029052734375 0.36798095703125 0.7202575683593749 +0.046125 0.1019287109375 0.36444091796875 0.7202575683593749 +0.04625 0.1019287109375 0.36444091796875 0.7202575683593749 +0.046375 0.10089111328125 0.360809326171875 0.7202575683593749 +0.0465 0.10089111328125 0.360809326171875 0.7202575683593749 +0.046625 0.099884033203125 0.357177734375 0.7202575683593749 +0.04675 0.098846435546875 0.353485107421875 0.7202575683593749 +0.046875 0.098846435546875 0.353485107421875 0.7202575683593749 +0.047 0.097808837890625 0.349761962890625 0.7202575683593749 +0.047125 0.097808837890625 0.349761962890625 0.7202575683593749 +0.04725 0.096771240234375 0.34600830078125 0.7202575683593749 +0.047375 0.095703125 0.34222412109375 0.7202575683593749 +0.0475 0.095703125 0.34222412109375 0.7202575683593749 +0.047625 0.094635009765625 0.33837890625 0.7202575683593749 +0.04775 0.094635009765625 0.33837890625 0.7202575683593749 +0.047875 0.093536376953125 0.334503173828125 0.7202575683593749 +0.048 0.09246826171875 0.330596923828125 0.7202575683593749 +0.048125 0.09246826171875 0.330596923828125 0.7202575683593749 +0.04825 0.091339111328125 0.32666015625 0.7202575683593749 +0.048375 0.091339111328125 0.32666015625 0.7202575683593749 +0.0485 0.090240478515625 0.322662353515625 0.7202575683593749 +0.048625 0.089111328125 0.31866455078125 0.7202575683593749 +0.04875 0.089111328125 0.31866455078125 0.7202575683593749 +0.048875 0.087982177734375 0.314605712890625 0.7202575683593749 +0.049 0.087982177734375 0.314605712890625 0.7202575683593749 +0.049125 0.086822509765625 0.310516357421875 0.7202575683593749 +0.04925 0.085693359375 0.306396484375 0.7202575683593749 +0.049375 0.085693359375 0.306396484375 0.7202575683593749 +0.0495 0.08453369140625 0.30224609375 0.7202575683593749 +0.049625 0.08453369140625 0.30224609375 0.7202575683593749 +0.04975 0.083343505859375 0.298065185546875 0.7202575683593749 +0.049875 0.082183837890625 0.2938232421875 0.7202575683593749 +0.05 0.082183837890625 0.2938232421875 0.7202575683593749 +0.050125 0.08099365234375 0.289581298828125 0.7202575683593749 +0.05025 0.08099365234375 0.289581298828125 0.7202575683593749 +0.050375 0.07977294921875 0.285308837890625 0.7202575683593749 +0.0505 0.078582763671875 0.280975341796875 0.7202575683593749 +0.050625 0.078582763671875 0.280975341796875 0.7202575683593749 +0.05075 0.077362060546875 0.276641845703125 0.7202575683593749 +0.0508750000000000064 0.077362060546875 0.276641845703125 0.7202575683593749 +0.0510000000000000064 0.076141357421875 0.27227783203125 0.7202575683593749 +0.0511250000000000064 0.074920654296875 0.267852783203125 0.7202575683593749 +0.0512500000000000064 0.074920654296875 0.267852783203125 0.7202575683593749 +0.0513750000000000064 0.07366943359375 0.263427734375 0.7202575683593749 +0.0515000000000000064 0.07366943359375 0.263427734375 0.7202575683593749 +0.0516250000000000064 0.072418212890625 0.25897216796875 0.7202575683593749 +0.0517500000000000064 0.0711669921875 0.25445556640625 0.7202575683593749 +0.0518750000000000064 0.0711669921875 0.25445556640625 0.7202575683593749 +0.052000000000000008 0.06988525390625 0.249969482421875 0.7202575683593749 +0.052125 0.06988525390625 0.249969482421875 0.7202575683593749 +0.05225 0.068634033203125 0.24542236328125 0.7202575683593749 +0.052375 0.067352294921875 0.2408447265625 0.7202575683593749 +0.0525 0.067352294921875 0.2408447265625 0.7202575683593749 +0.052625 0.066070556640625 0.236236572265625 0.7202575683593749 +0.05275 0.066070556640625 0.236236572265625 0.7202575683593749 +0.052875 0.06475830078125 0.231597900390625 0.7202575683593749 +0.053 0.063446044921875 0.226959228515625 0.7202575683593749 +0.053125 0.063446044921875 0.226959228515625 0.7202575683593749 +0.05325 0.062164306640625 0.2222900390625 0.7202575683593749 +0.053375 0.062164306640625 0.2222900390625 0.7202575683593749 +0.0535 0.06085205078125 0.21759033203125 0.7202575683593749 +0.053625 0.05950927734375 0.212860107421875 0.7202575683593749 +0.05375 0.05950927734375 0.212860107421875 0.7202575683593749 +0.053875 0.058197021484375 0.208099365234375 0.7202575683593749 +0.054 0.058197021484375 0.208099365234375 0.7202575683593749 +0.054125 0.056854248046875 0.203338623046875 0.7202575683593749 +0.05425 0.055511474609375 0.19854736328125 0.7202575683593749 +0.054375 0.055511474609375 0.19854736328125 0.7202575683593749 +0.0545 0.054168701171875 0.1937255859375 0.7202575683593749 +0.054625 0.054168701171875 0.1937255859375 0.7202575683593749 +0.05475 0.052825927734375 0.188873291015625 0.7202575683593749 +0.054875 0.05145263671875 0.18402099609375 0.7202575683593749 +0.055 0.05145263671875 0.18402099609375 0.7202575683593749 +0.055125 0.050079345703125 0.17913818359375 0.7202575683593749 +0.05525 0.050079345703125 0.17913818359375 0.7202575683593749 +0.055375 0.048736572265625 0.17425537109375 0.7202575683593749 +0.0555 0.047332763671875 0.169342041015625 0.7202575683593749 +0.055625 0.047332763671875 0.169342041015625 0.7202575683593749 +0.05575 0.04595947265625 0.164398193359375 0.7202575683593749 +0.055875 0.04595947265625 0.164398193359375 0.7202575683593749 +0.056 0.044586181640625 0.159454345703125 0.7202575683593749 +0.056125 0.043182373046875 0.15447998046875 0.7202575683593749 +0.05625 0.043182373046875 0.15447998046875 0.7202575683593749 +0.056375 0.04180908203125 0.14947509765625 0.7202575683593749 +0.0565 0.04180908203125 0.14947509765625 0.7202575683593749 +0.056625 0.0404052734375 0.14447021484375 0.7202575683593749 +0.05675 0.03900146484375 0.13946533203125 0.7202575683593749 +0.056875 0.03900146484375 0.13946533203125 0.7202575683593749 +0.057 0.03759765625 0.134429931640625 0.7202575683593749 +0.057125 0.03759765625 0.134429931640625 0.7202575683593749 +0.05725 0.036163330078125 0.129364013671875 0.7202575683593749 +0.057375 0.034759521484375 0.124298095703125 0.7202575683593749 +0.0575 0.034759521484375 0.124298095703125 0.7202575683593749 +0.057625 0.0333251953125 0.119232177734375 0.7202575683593749 +0.05775 0.0333251953125 0.119232177734375 0.7202575683593749 +0.057875 0.03192138671875 0.1141357421875 0.7202575683593749 +0.058 0.030487060546875 0.109039306640625 0.7202575683593749 +0.058125 0.030487060546875 0.109039306640625 0.7202575683593749 +0.05825 0.029052734375 0.103912353515625 0.7202575683593749 +0.058375 0.029052734375 0.103912353515625 0.7202575683593749 +0.0585 0.027618408203125 0.098785400390625 0.7202575683593749 +0.0586250000000000064 0.02618408203125 0.093658447265625 0.7202575683593749 +0.0587500000000000064 0.02618408203125 0.093658447265625 0.7202575683593749 +0.0588750000000000064 0.024749755859375 0.0885009765625 0.7202575683593749 +0.0590000000000000064 0.024749755859375 0.0885009765625 0.7202575683593749 +0.0591250000000000064 0.0233154296875 0.083343505859375 0.7202575683593749 +0.0592500000000000052 0.0218505859375 0.07818603515625 0.7202575683593749 +0.0593750000000000052 0.0218505859375 0.07818603515625 0.7202575683593749 +0.0595000000000000052 0.020416259765625 0.072998046875 0.7202575683593749 +0.0596250000000000052 0.020416259765625 0.072998046875 0.7202575683593749 +0.0597500000000000052 0.018951416015625 0.06781005859375 0.7202575683593749 +0.059875000000000008 0.01751708984375 0.0626220703125 0.7202575683593749 +0.06 0.01751708984375 0.0626220703125 0.7202575683593749 +0.060125 0.01605224609375 0.05743408203125 0.7202575683593749 +0.06025 0.01605224609375 0.05743408203125 0.7202575683593749 +0.060375 0.01458740234375 0.05224609375 0.7202575683593749 +0.0605 0.013153076171875 0.047027587890625 0.7202575683593749 +0.060625 0.013153076171875 0.047027587890625 0.7202575683593749 +0.06075 0.011688232421875 0.04180908203125 0.7202575683593749 +0.060875 0.011688232421875 0.04180908203125 0.7202575683593749 +0.061 0.010223388671875 0.036590576171875 0.7202575683593749 +0.061125 0.008758544921875 0.0313720703125 0.7202575683593749 +0.06125 0.008758544921875 0.0313720703125 0.7202575683593749 +0.061375 0.007293701171875 0.026123046875 0.7202575683593749 +0.0615 0.007293701171875 0.026123046875 0.7202575683593749 +0.061625 0.005828857421875 0.020904541015625 0.7202575683593749 +0.06175 0.004364013671875 0.01568603515625 0.7202575683593749 +0.061875 0.004364013671875 0.01568603515625 0.7202575683593749 +0.062 0.002899169921875 0.01043701171875 0.7202575683593749 +0.062125 0.002899169921875 0.01043701171875 0.7202575683593749 +0.06225 0.001434326171875 0.005218505859375 0.7202575683593749 +0.062375 0.0 0.0 0.7202575683593749 +0.0625 0.0 0.0 0.7202575683593749 +0.062625 -0.001434326171875 -0.005218505859375 0.7202575683593749 +0.06275 -0.001434326171875 -0.005218505859375 0.7202575683593749 +0.062875 -0.002899169921875 -0.01043701171875 0.7202575683593749 +0.063 -0.004364013671875 -0.01568603515625 0.7202575683593749 +0.063125 -0.004364013671875 -0.01568603515625 0.7202575683593749 +0.06325 -0.005828857421875 -0.020904541015625 0.7202575683593749 +0.063375 -0.005828857421875 -0.020904541015625 0.7202575683593749 +0.0635 -0.007293701171875 -0.026123046875 0.7202575683593749 +0.063625 -0.008758544921875 -0.0313720703125 0.7202575683593749 +0.06375 -0.008758544921875 -0.0313720703125 0.7202575683593749 +0.063875 -0.010223388671875 -0.036590576171875 0.7202575683593749 +0.064 -0.00238037109375 -0.036590576171875 0.934271240234375 +0.064125 -0.002716064453125 -0.04180908203125 0.934271240234375 +0.06425 -0.003082275390625 -0.047027587890625 0.934271240234375 +0.064375 -0.003082275390625 -0.047027587890625 0.934271240234375 +0.0645 -0.00341796875 -0.05224609375 0.934271240234375 +0.064625 -0.00341796875 -0.05224609375 0.934271240234375 +0.06475 -0.003753662109375 -0.05743408203125 0.934271240234375 +0.064875 -0.00408935546875 -0.0626220703125 0.934271240234375 +0.065 -0.00408935546875 -0.0626220703125 0.934271240234375 +0.065125 -0.004425048828125 -0.06781005859375 0.934271240234375 +0.06525 -0.004425048828125 -0.06781005859375 0.934271240234375 +0.065375 -0.004791259765625 -0.072998046875 0.934271240234375 +0.0655 -0.005126953125 -0.07818603515625 0.934271240234375 +0.065625 -0.005126953125 -0.07818603515625 0.934271240234375 +0.06575 -0.005462646484375 -0.083343505859375 0.934271240234375 +0.065875 -0.005462646484375 -0.083343505859375 0.934271240234375 +0.066 -0.00579833984375 -0.0885009765625 0.934271240234375 +0.066125 -0.006134033203125 -0.093658447265625 0.934271240234375 +0.06625 -0.006134033203125 -0.093658447265625 0.934271240234375 +0.066375 -0.0064697265625 -0.098785400390625 0.934271240234375 +0.0665 -0.0064697265625 -0.098785400390625 0.934271240234375 +0.066625 -0.006805419921875 -0.103912353515625 0.934271240234375 +0.06675 -0.00714111328125 -0.109039306640625 0.934271240234375 +0.066875 -0.00714111328125 -0.109039306640625 0.934271240234375 +0.067 -0.007476806640625 -0.1141357421875 0.934271240234375 +0.067125 -0.007476806640625 -0.1141357421875 0.934271240234375 +0.06725 -0.0078125 -0.119232177734375 0.934271240234375 +0.067375 -0.008148193359375 -0.124298095703125 0.934271240234375 +0.0675 -0.008148193359375 -0.124298095703125 0.934271240234375 +0.067625 -0.00848388671875 -0.129364013671875 0.934271240234375 +0.06775 -0.00848388671875 -0.129364013671875 0.934271240234375 +0.067875 -0.008819580078125 -0.134429931640625 0.934271240234375 +0.068 -0.0091552734375 -0.13946533203125 0.934271240234375 +0.068125 -0.0091552734375 -0.13946533203125 0.934271240234375 +0.06825000000000001 -0.00946044921875 -0.14447021484375 0.934271240234375 +0.06837500000000001 -0.00946044921875 -0.14447021484375 0.934271240234375 +0.06850000000000001 -0.009796142578125 -0.14947509765625 0.934271240234375 +0.06862500000000001 -0.0101318359375 -0.15447998046875 0.934271240234375 +0.06875000000000001 -0.0101318359375 -0.15447998046875 0.934271240234375 +0.06887500000000001 -0.010467529296875 -0.159454345703125 0.934271240234375 +0.06900000000000001 -0.010467529296875 -0.159454345703125 0.934271240234375 +0.06912500000000001 -0.010772705078125 -0.164398193359375 0.934271240234375 +0.06925000000000001 -0.0111083984375 -0.169342041015625 0.934271240234375 +0.06937500000000001 -0.0111083984375 -0.169342041015625 0.934271240234375 +0.06950000000000001 -0.01141357421875 -0.17425537109375 0.934271240234375 +0.06962500000000001 -0.01141357421875 -0.17425537109375 0.934271240234375 +0.06975000000000001 -0.011749267578125 -0.17913818359375 0.934271240234375 +0.06987500000000001 -0.012054443359375 -0.18402099609375 0.934271240234375 +0.07000000000000001 -0.012054443359375 -0.18402099609375 0.934271240234375 +0.07012500000000001 -0.01239013671875 -0.188873291015625 0.934271240234375 +0.07025000000000001 -0.01239013671875 -0.188873291015625 0.934271240234375 +0.07037500000000001 -0.0126953125 -0.1937255859375 0.934271240234375 +0.07050000000000001 -0.013031005859375 -0.19854736328125 0.934271240234375 +0.07062500000000001 -0.013031005859375 -0.19854736328125 0.934271240234375 +0.07075000000000001 -0.013336181640625 -0.203338623046875 0.934271240234375 +0.07087500000000001 -0.013336181640625 -0.203338623046875 0.934271240234375 +0.07100000000000001 -0.013641357421875 -0.208099365234375 0.934271240234375 +0.07112500000000001 -0.013946533203125 -0.212860107421875 0.934271240234375 +0.07125000000000001 -0.013946533203125 -0.212860107421875 0.934271240234375 +0.07137500000000001 -0.0142822265625 -0.21759033203125 0.934271240234375 +0.07150000000000001 -0.0142822265625 -0.21759033203125 0.934271240234375 +0.07162500000000001 -0.01458740234375 -0.2222900390625 0.934271240234375 +0.07175000000000001 -0.014892578125 -0.226959228515625 0.934271240234375 +0.07187500000000001 -0.014892578125 -0.226959228515625 0.934271240234375 +0.07200000000000001 -0.01519775390625 -0.231597900390625 0.934271240234375 +0.072125 -0.01519775390625 -0.231597900390625 0.934271240234375 +0.07225 -0.0155029296875 -0.236236572265625 0.934271240234375 +0.072375 -0.01580810546875 -0.2408447265625 0.934271240234375 +0.0725 -0.01580810546875 -0.2408447265625 0.934271240234375 +0.072625 -0.016082763671875 -0.24542236328125 0.934271240234375 +0.07275 -0.016082763671875 -0.24542236328125 0.934271240234375 +0.072875 -0.016387939453125 -0.249969482421875 0.934271240234375 +0.073 -0.016693115234375 -0.25445556640625 0.934271240234375 +0.073125 -0.016693115234375 -0.25445556640625 0.934271240234375 +0.07325 -0.016998291015625 -0.25897216796875 0.934271240234375 +0.073375 -0.016998291015625 -0.25897216796875 0.934271240234375 +0.0735 -0.01727294921875 -0.263427734375 0.934271240234375 +0.073625 -0.017578125 -0.267852783203125 0.934271240234375 +0.07375 -0.017578125 -0.267852783203125 0.934271240234375 +0.073875 -0.017852783203125 -0.27227783203125 0.934271240234375 +0.074 -0.017852783203125 -0.27227783203125 0.934271240234375 +0.074125 -0.018157958984375 -0.276641845703125 0.934271240234375 +0.07425 -0.0184326171875 -0.280975341796875 0.934271240234375 +0.074375 -0.0184326171875 -0.280975341796875 0.934271240234375 +0.0745 -0.018707275390625 -0.285308837890625 0.934271240234375 +0.074625 -0.018707275390625 -0.285308837890625 0.934271240234375 +0.07475 -0.01898193359375 -0.289581298828125 0.934271240234375 +0.074875 -0.019287109375 -0.2938232421875 0.934271240234375 +0.075 -0.019287109375 -0.2938232421875 0.934271240234375 +0.075125 -0.019561767578125 -0.298065185546875 0.934271240234375 +0.07525 -0.019561767578125 -0.298065185546875 0.934271240234375 +0.075375 -0.01983642578125 -0.30224609375 0.934271240234375 +0.0755 -0.020111083984375 -0.306396484375 0.934271240234375 +0.075625 -0.020111083984375 -0.306396484375 0.934271240234375 +0.07575 -0.0203857421875 -0.310516357421875 0.934271240234375 +0.075875 -0.0203857421875 -0.310516357421875 0.934271240234375 +0.076 -0.0206298828125 -0.314605712890625 0.934271240234375 +0.076125 -0.020904541015625 -0.31866455078125 0.934271240234375 +0.07625 -0.020904541015625 -0.31866455078125 0.934271240234375 +0.076375 -0.02117919921875 -0.322662353515625 0.934271240234375 +0.0765 -0.02117919921875 -0.322662353515625 0.934271240234375 +0.076625 -0.02142333984375 -0.32666015625 0.934271240234375 +0.07675 -0.021697998046875 -0.330596923828125 0.934271240234375 +0.076875 -0.021697998046875 -0.330596923828125 0.934271240234375 +0.077 -0.021942138671875 -0.334503173828125 0.934271240234375 +0.077125 -0.021942138671875 -0.334503173828125 0.934271240234375 +0.07725 -0.022186279296875 -0.33837890625 0.934271240234375 +0.077375 -0.0224609375 -0.34222412109375 0.934271240234375 +0.0775 -0.0224609375 -0.34222412109375 0.934271240234375 +0.077625 -0.022705078125 -0.34600830078125 0.934271240234375 +0.07775 -0.022705078125 -0.34600830078125 0.934271240234375 +0.077875 -0.02294921875 -0.349761962890625 0.934271240234375 +0.078 -0.023193359375 -0.353485107421875 0.934271240234375 +0.078125 -0.023193359375 -0.353485107421875 0.934271240234375 +0.07825 -0.0234375 -0.357177734375 0.934271240234375 +0.078375 -0.0234375 -0.357177734375 0.934271240234375 +0.0785 -0.023681640625 -0.360809326171875 0.934271240234375 +0.078625 -0.023895263671875 -0.36444091796875 0.934271240234375 +0.07875 -0.023895263671875 -0.36444091796875 0.934271240234375 +0.078875 -0.024139404296875 -0.36798095703125 0.934271240234375 +0.079 -0.024139404296875 -0.36798095703125 0.934271240234375 +0.079125 -0.024383544921875 -0.37152099609375 0.934271240234375 +0.07925 -0.02459716796875 -0.375 0.934271240234375 +0.079375 -0.02459716796875 -0.375 0.934271240234375 +0.0795 -0.02484130859375 -0.378448486328125 0.934271240234375 +0.079625 -0.02484130859375 -0.378448486328125 0.934271240234375 +0.07975 -0.025054931640625 -0.3818359375 0.934271240234375 +0.079875 -0.0252685546875 -0.38519287109375 0.934271240234375 +0.08 -0.0252685546875 -0.38519287109375 0.934271240234375 +0.080125 -0.025482177734375 -0.388519287109375 0.934271240234375 +0.08025 -0.025482177734375 -0.388519287109375 0.934271240234375 +0.080375 -0.02569580078125 -0.39178466796875 0.934271240234375 +0.0805 -0.025909423828125 -0.39501953125 0.934271240234375 +0.080625 -0.025909423828125 -0.39501953125 0.934271240234375 +0.08075 -0.026123046875 -0.398193359375 0.934271240234375 +0.080875 -0.026123046875 -0.398193359375 0.934271240234375 +0.081 -0.026336669921875 -0.401336669921875 0.934271240234375 +0.081125 -0.02655029296875 -0.404449462890625 0.934271240234375 +0.08125 -0.02655029296875 -0.404449462890625 0.934271240234375 +0.081375 -0.0267333984375 -0.407501220703125 0.934271240234375 +0.0815 -0.0267333984375 -0.407501220703125 0.934271240234375 +0.081625 -0.026947021484375 -0.4105224609375 0.934271240234375 +0.08175 -0.027130126953125 -0.413482666015625 0.934271240234375 +0.081875 -0.027130126953125 -0.413482666015625 0.934271240234375 +0.082 -0.027313232421875 -0.416412353515625 0.934271240234375 +0.082125 -0.027313232421875 -0.416412353515625 0.934271240234375 +0.08225 -0.027496337890625 -0.419281005859375 0.934271240234375 +0.082375 -0.0277099609375 -0.422119140625 0.934271240234375 +0.0825 -0.0277099609375 -0.422119140625 0.934271240234375 +0.082625 -0.02789306640625 -0.424896240234375 0.934271240234375 +0.08275 -0.02789306640625 -0.424896240234375 0.934271240234375 +0.082875 -0.028045654296875 -0.4276123046875 0.934271240234375 +0.083 -0.028228759765625 -0.4302978515625 0.934271240234375 +0.083125 -0.028228759765625 -0.4302978515625 0.934271240234375 +0.08325 -0.028411865234375 -0.432952880859375 0.934271240234375 +0.083375 -0.028411865234375 -0.432952880859375 0.934271240234375 +0.0835 -0.028564453125 -0.435546875 0.934271240234375 +0.083625 -0.02874755859375 -0.438079833984375 0.934271240234375 +0.08375 -0.02874755859375 -0.438079833984375 0.934271240234375 +0.08387500000000001 -0.028900146484375 -0.440582275390625 0.934271240234375 +0.08400000000000001 -0.028900146484375 -0.440582275390625 0.934271240234375 +0.08412500000000001 -0.029083251953125 -0.44305419921875 0.934271240234375 +0.08425000000000001 -0.02923583984375 -0.4454345703125 0.934271240234375 +0.08437500000000001 -0.02923583984375 -0.4454345703125 0.934271240234375 +0.08450000000000001 -0.029388427734375 -0.447784423828125 0.934271240234375 +0.08462500000000001 -0.029388427734375 -0.447784423828125 0.934271240234375 +0.08475000000000001 -0.029541015625 -0.450103759765625 0.934271240234375 +0.08487500000000001 -0.029693603515625 -0.452362060546875 0.934271240234375 +0.08500000000000001 -0.029693603515625 -0.452362060546875 0.934271240234375 +0.08512500000000001 -0.029815673828125 -0.454559326171875 0.934271240234375 +0.08525000000000001 -0.029815673828125 -0.454559326171875 0.934271240234375 +0.08537500000000001 -0.02996826171875 -0.45672607421875 0.934271240234375 +0.08550000000000001 -0.030120849609375 -0.458831787109375 0.934271240234375 +0.08562500000000001 -0.030120849609375 -0.458831787109375 0.934271240234375 +0.08575000000000001 -0.030242919921875 -0.46087646484375 0.934271240234375 +0.08587500000000001 -0.030242919921875 -0.46087646484375 0.934271240234375 +0.08600000000000001 -0.030364990234375 -0.462890625 0.934271240234375 +0.08612500000000001 -0.030487060546875 -0.464813232421875 0.934271240234375 +0.08625000000000001 -0.030487060546875 -0.464813232421875 0.934271240234375 +0.08637500000000001 -0.0306396484375 -0.46673583984375 0.934271240234375 +0.08650000000000001 -0.0306396484375 -0.46673583984375 0.934271240234375 +0.08662500000000001 -0.030731201171875 -0.46856689453125 0.934271240234375 +0.08675000000000001 -0.030853271484375 -0.470367431640625 0.934271240234375 +0.08687500000000001 -0.030853271484375 -0.470367431640625 0.934271240234375 +0.08700000000000001 -0.030975341796875 -0.472137451171875 0.934271240234375 +0.08712500000000001 -0.030975341796875 -0.472137451171875 0.934271240234375 +0.08725000000000001 -0.031097412109375 -0.47381591796875 0.934271240234375 +0.08737500000000001 -0.03118896484375 -0.4754638671875 0.934271240234375 +0.08750000000000001 -0.03118896484375 -0.4754638671875 0.934271240234375 +0.08762500000000001 -0.03131103515625 -0.47705078125 0.934271240234375 +0.08775000000000001 -0.03131103515625 -0.47705078125 0.934271240234375 +0.08787500000000001 -0.031402587890625 -0.478607177734375 0.934271240234375 +0.088 -0.031494140625 -0.480072021484375 0.934271240234375 +0.088125 -0.031494140625 -0.480072021484375 0.934271240234375 +0.08825 -0.031585693359375 -0.48150634765625 0.934271240234375 +0.088375 -0.031585693359375 -0.48150634765625 0.934271240234375 +0.0885 -0.03167724609375 -0.48291015625 0.934271240234375 +0.088625 -0.031768798828125 -0.484222412109375 0.934271240234375 +0.08875 -0.031768798828125 -0.484222412109375 0.934271240234375 +0.088875 -0.0318603515625 -0.485504150390625 0.934271240234375 +0.089 -0.0318603515625 -0.485504150390625 0.934271240234375 +0.089125 -0.031951904296875 -0.486724853515625 0.934271240234375 +0.08925 -0.032012939453125 -0.487884521484375 0.934271240234375 +0.089375 -0.032012939453125 -0.487884521484375 0.934271240234375 +0.0895 -0.032073974609375 -0.489013671875 0.934271240234375 +0.089625 -0.032073974609375 -0.489013671875 0.934271240234375 +0.08975 -0.03216552734375 -0.490081787109375 0.934271240234375 +0.089875 -0.0322265625 -0.4910888671875 0.934271240234375 +0.09 -0.0322265625 -0.4910888671875 0.934271240234375 +0.090125 -0.03228759765625 -0.492034912109375 0.934271240234375 +0.09025 -0.03228759765625 -0.492034912109375 0.934271240234375 +0.090375 -0.0323486328125 -0.492950439453125 0.934271240234375 +0.0905 -0.03240966796875 -0.4937744140625 0.934271240234375 +0.090625 -0.03240966796875 -0.4937744140625 0.934271240234375 +0.09075 -0.032440185546875 -0.49456787109375 0.934271240234375 +0.090875 -0.032440185546875 -0.49456787109375 0.934271240234375 +0.091 -0.032501220703125 -0.49530029296875 0.934271240234375 +0.091125 -0.03253173828125 -0.496002197265625 0.934271240234375 +0.09125 -0.03253173828125 -0.496002197265625 0.934271240234375 +0.091375 -0.0325927734375 -0.496612548828125 0.934271240234375 +0.0915 -0.0325927734375 -0.496612548828125 0.934271240234375 +0.091625 -0.032623291015625 -0.4971923828125 0.934271240234375 +0.09175 -0.03265380859375 -0.497711181640625 0.934271240234375 +0.091875 -0.03265380859375 -0.497711181640625 0.934271240234375 +0.092 -0.032684326171875 -0.498199462890625 0.934271240234375 +0.092125 -0.032684326171875 -0.498199462890625 0.934271240234375 +0.09225 -0.03271484375 -0.49859619140625 0.934271240234375 +0.092375 -0.032745361328125 -0.49896240234375 0.934271240234375 +0.0925 -0.032745361328125 -0.49896240234375 0.934271240234375 +0.092625 -0.032745361328125 -0.499267578125 0.934271240234375 +0.09275 -0.032745361328125 -0.499267578125 0.934271240234375 +0.092875 -0.03277587890625 -0.49951171875 0.934271240234375 +0.093 -0.03277587890625 -0.49969482421875 0.934271240234375 +0.093125 -0.03277587890625 -0.49969482421875 0.934271240234375 +0.09325 -0.032806396484375 -0.49981689453125 0.934271240234375 +0.093375 -0.032806396484375 -0.49981689453125 0.934271240234375 +0.0935 -0.032806396484375 -0.499908447265625 0.934271240234375 +0.093625 -0.032806396484375 -0.49993896484375 0.934271240234375 +0.09375 -0.032806396484375 -0.49993896484375 0.934271240234375 +0.093875 -0.032806396484375 -0.499908447265625 0.934271240234375 +0.094 -0.032806396484375 -0.499908447265625 0.934271240234375 +0.094125 -0.032806396484375 -0.49981689453125 0.934271240234375 +0.09425 -0.03277587890625 -0.49969482421875 0.934271240234375 +0.094375 -0.03277587890625 -0.49969482421875 0.934271240234375 +0.0945 -0.03277587890625 -0.49951171875 0.934271240234375 +0.094625 -0.03277587890625 -0.49951171875 0.934271240234375 +0.09475 -0.032745361328125 -0.499267578125 0.934271240234375 +0.094875 -0.032745361328125 -0.49896240234375 0.934271240234375 +0.095 -0.032745361328125 -0.49896240234375 0.934271240234375 +0.095125 -0.03271484375 -0.49859619140625 0.934271240234375 +0.09525 -0.03271484375 -0.49859619140625 0.934271240234375 +0.095375 -0.032684326171875 -0.498199462890625 0.934271240234375 +0.0955 -0.03265380859375 -0.497711181640625 0.934271240234375 +0.095625 -0.03265380859375 -0.497711181640625 0.934271240234375 +0.09575 -0.032623291015625 -0.4971923828125 0.934271240234375 +0.095875 -0.032623291015625 -0.4971923828125 0.934271240234375 +0.096 -0.00030517578125 -0.496612548828125 0.99923095703125 +0.096125 -0.00030517578125 -0.496002197265625 0.99923095703125 +0.09625 -0.00030517578125 -0.496002197265625 0.99923095703125 +0.096375 -0.00030517578125 -0.49530029296875 0.99923095703125 +0.0965 -0.00030517578125 -0.49530029296875 0.99923095703125 +0.096625 -0.00030517578125 -0.49456787109375 0.99923095703125 +0.09675 -0.00030517578125 -0.4937744140625 0.99923095703125 +0.096875 -0.00030517578125 -0.4937744140625 0.99923095703125 +0.097 -0.00030517578125 -0.492950439453125 0.99923095703125 +0.097125 -0.00030517578125 -0.492950439453125 0.99923095703125 +0.09725 -0.00030517578125 -0.492034912109375 0.99923095703125 +0.097375 -0.00030517578125 -0.4910888671875 0.99923095703125 +0.0975 -0.00030517578125 -0.4910888671875 0.99923095703125 +0.097625 -0.00030517578125 -0.490081787109375 0.99923095703125 +0.09775 -0.00030517578125 -0.490081787109375 0.99923095703125 +0.097875 -0.00030517578125 -0.489013671875 0.99923095703125 +0.098 -0.00030517578125 -0.487884521484375 0.99923095703125 +0.098125 -0.00030517578125 -0.487884521484375 0.99923095703125 +0.09825 -0.00030517578125 -0.486724853515625 0.99923095703125 +0.098375 -0.00030517578125 -0.486724853515625 0.99923095703125 +0.0985 -0.00030517578125 -0.485504150390625 0.99923095703125 +0.098625 -0.00030517578125 -0.484222412109375 0.99923095703125 +0.09875 -0.00030517578125 -0.484222412109375 0.99923095703125 +0.098875 -0.00030517578125 -0.48291015625 0.99923095703125 +0.099 -0.00030517578125 -0.48291015625 0.99923095703125 +0.099125 -0.00030517578125 -0.48150634765625 0.99923095703125 +0.09925 -0.00030517578125 -0.480072021484375 0.99923095703125 +0.099375 -0.00030517578125 -0.480072021484375 0.99923095703125 +0.0995 -0.00030517578125 -0.478607177734375 0.99923095703125 +0.099625 -0.00030517578125 -0.478607177734375 0.99923095703125 +0.09975 -0.00030517578125 -0.47705078125 0.99923095703125 +0.099875 -0.00030517578125 -0.4754638671875 0.99923095703125 +0.1 -0.00030517578125 -0.4754638671875 0.99923095703125 +0.100125 -0.00030517578125 -0.47381591796875 0.99923095703125 +0.10025 -0.00030517578125 -0.47381591796875 0.99923095703125 +0.100375 -0.00030517578125 -0.472137451171875 0.99923095703125 +0.1005 -0.00030517578125 -0.470367431640625 0.99923095703125 +0.100625 -0.00030517578125 -0.470367431640625 0.99923095703125 +0.10075 -0.00030517578125 -0.46856689453125 0.99923095703125 +0.100875 -0.00030517578125 -0.46856689453125 0.99923095703125 +0.101 -0.00030517578125 -0.46673583984375 0.99923095703125 +0.101125 -0.00030517578125 -0.464813232421875 0.99923095703125 +0.10125 -0.00030517578125 -0.464813232421875 0.99923095703125 +0.101375 -0.00030517578125 -0.462890625 0.99923095703125 +0.1015 -0.00030517578125 -0.462890625 0.99923095703125 +0.1016250000000000128 -0.00030517578125 -0.46087646484375 0.99923095703125 +0.1017500000000000128 -0.00030517578125 -0.458831787109375 0.99923095703125 +0.1018750000000000128 -0.00030517578125 -0.458831787109375 0.99923095703125 +0.1020000000000000128 -0.00030517578125 -0.45672607421875 0.99923095703125 +0.1021250000000000128 -0.00030517578125 -0.45672607421875 0.99923095703125 +0.1022500000000000128 -0.00030517578125 -0.454559326171875 0.99923095703125 +0.1023750000000000128 -0.000274658203125 -0.452362060546875 0.99923095703125 +0.1025000000000000128 -0.000274658203125 -0.452362060546875 0.99923095703125 +0.1026250000000000128 -0.000274658203125 -0.450103759765625 0.99923095703125 +0.1027500000000000128 -0.000274658203125 -0.450103759765625 0.99923095703125 +0.1028750000000000128 -0.000274658203125 -0.447784423828125 0.99923095703125 +0.1030000000000000128 -0.000274658203125 -0.4454345703125 0.99923095703125 +0.1031250000000000128 -0.000274658203125 -0.4454345703125 0.99923095703125 +0.1032500000000000128 -0.000274658203125 -0.44305419921875 0.99923095703125 +0.1033750000000000128 -0.000274658203125 -0.44305419921875 0.99923095703125 +0.1035000000000000128 -0.000274658203125 -0.440582275390625 0.99923095703125 +0.1036250000000000128 -0.000274658203125 -0.438079833984375 0.99923095703125 +0.1037500000000000128 -0.000274658203125 -0.438079833984375 0.99923095703125 +0.1038750000000000128 -0.000274658203125 -0.435546875 0.99923095703125 +0.104000000000000016 -0.000274658203125 -0.435546875 0.99923095703125 +0.104125 -0.000274658203125 -0.432952880859375 0.99923095703125 +0.10425 -0.000274658203125 -0.4302978515625 0.99923095703125 +0.104375 -0.000274658203125 -0.4302978515625 0.99923095703125 +0.1045 -0.000274658203125 -0.4276123046875 0.99923095703125 +0.104625 -0.000274658203125 -0.4276123046875 0.99923095703125 +0.10475 -0.000274658203125 -0.424896240234375 0.99923095703125 +0.104875 -0.000274658203125 -0.422119140625 0.99923095703125 +0.105 -0.000274658203125 -0.422119140625 0.99923095703125 +0.105125 -0.000274658203125 -0.419281005859375 0.99923095703125 +0.10525 -0.000274658203125 -0.419281005859375 0.99923095703125 +0.105375 -0.000274658203125 -0.416412353515625 0.99923095703125 +0.1055 -0.000274658203125 -0.413482666015625 0.99923095703125 +0.105625 -0.000274658203125 -0.413482666015625 0.99923095703125 +0.10575 -0.000274658203125 -0.4105224609375 0.99923095703125 +0.105875 -0.000274658203125 -0.4105224609375 0.99923095703125 +0.106 -0.000244140625 -0.407501220703125 0.99923095703125 +0.106125 -0.000244140625 -0.404449462890625 0.99923095703125 +0.10625 -0.000244140625 -0.404449462890625 0.99923095703125 +0.106375 -0.000244140625 -0.401336669921875 0.99923095703125 +0.1065 -0.000244140625 -0.401336669921875 0.99923095703125 +0.106625 -0.000244140625 -0.398193359375 0.99923095703125 +0.10675 -0.000244140625 -0.39501953125 0.99923095703125 +0.106875 -0.000244140625 -0.39501953125 0.99923095703125 +0.107 -0.000244140625 -0.39178466796875 0.99923095703125 +0.107125 -0.000244140625 -0.39178466796875 0.99923095703125 +0.10725 -0.000244140625 -0.388519287109375 0.99923095703125 +0.107375 -0.000244140625 -0.38519287109375 0.99923095703125 +0.1075 -0.000244140625 -0.38519287109375 0.99923095703125 +0.107625 -0.000244140625 -0.3818359375 0.99923095703125 +0.10775 -0.000244140625 -0.3818359375 0.99923095703125 +0.107875 -0.000244140625 -0.378448486328125 0.99923095703125 +0.108 -0.000244140625 -0.375 0.99923095703125 +0.108125 -0.000244140625 -0.375 0.99923095703125 +0.10825 -0.000244140625 -0.37152099609375 0.99923095703125 +0.108375 -0.000244140625 -0.37152099609375 0.99923095703125 +0.1085 -0.000244140625 -0.36798095703125 0.99923095703125 +0.108625 -0.000244140625 -0.36444091796875 0.99923095703125 +0.10875 -0.000244140625 -0.36444091796875 0.99923095703125 +0.108875 -0.000213623046875 -0.360809326171875 0.99923095703125 +0.109 -0.000213623046875 -0.360809326171875 0.99923095703125 +0.109125 -0.000213623046875 -0.357177734375 0.99923095703125 +0.10925 -0.000213623046875 -0.353485107421875 0.99923095703125 +0.109375 -0.000213623046875 -0.353485107421875 0.99923095703125 +0.1095 -0.000213623046875 -0.349761962890625 0.99923095703125 +0.109625 -0.000213623046875 -0.349761962890625 0.99923095703125 +0.10975 -0.000213623046875 -0.34600830078125 0.99923095703125 +0.109875 -0.000213623046875 -0.34222412109375 0.99923095703125 +0.11 -0.000213623046875 -0.34222412109375 0.99923095703125 +0.110125 -0.000213623046875 -0.33837890625 0.99923095703125 +0.11025 -0.000213623046875 -0.33837890625 0.99923095703125 +0.110375 -0.000213623046875 -0.334503173828125 0.99923095703125 +0.1105 -0.000213623046875 -0.330596923828125 0.99923095703125 +0.110625 -0.000213623046875 -0.330596923828125 0.99923095703125 +0.11075 -0.000213623046875 -0.32666015625 0.99923095703125 +0.110875 -0.000213623046875 -0.32666015625 0.99923095703125 +0.111 -0.000213623046875 -0.322662353515625 0.99923095703125 +0.111125 -0.000213623046875 -0.31866455078125 0.99923095703125 +0.11125 -0.000213623046875 -0.31866455078125 0.99923095703125 +0.111375 -0.00018310546875 -0.314605712890625 0.99923095703125 +0.1115 -0.00018310546875 -0.314605712890625 0.99923095703125 +0.111625 -0.00018310546875 -0.310516357421875 0.99923095703125 +0.11175 -0.00018310546875 -0.306396484375 0.99923095703125 +0.111875 -0.00018310546875 -0.306396484375 0.99923095703125 +0.112 -0.00018310546875 -0.30224609375 0.99923095703125 +0.112125 -0.00018310546875 -0.30224609375 0.99923095703125 +0.11225 -0.00018310546875 -0.298065185546875 0.99923095703125 +0.112375 -0.00018310546875 -0.2938232421875 0.99923095703125 +0.1125 -0.00018310546875 -0.2938232421875 0.99923095703125 +0.112625 -0.00018310546875 -0.289581298828125 0.99923095703125 +0.11275 -0.00018310546875 -0.289581298828125 0.99923095703125 +0.112875 -0.00018310546875 -0.285308837890625 0.99923095703125 +0.113 -0.00018310546875 -0.280975341796875 0.99923095703125 +0.113125 -0.00018310546875 -0.280975341796875 0.99923095703125 +0.11325 -0.00018310546875 -0.276641845703125 0.99923095703125 +0.113375 -0.00018310546875 -0.276641845703125 0.99923095703125 +0.1135 -0.000152587890625 -0.27227783203125 0.99923095703125 +0.113625 -0.000152587890625 -0.267852783203125 0.99923095703125 +0.11375 -0.000152587890625 -0.267852783203125 0.99923095703125 +0.113875 -0.000152587890625 -0.263427734375 0.99923095703125 +0.114 -0.000152587890625 -0.263427734375 0.99923095703125 +0.114125 -0.000152587890625 -0.25897216796875 0.99923095703125 +0.11425 -0.000152587890625 -0.25445556640625 0.99923095703125 +0.114375 -0.000152587890625 -0.25445556640625 0.99923095703125 +0.1145 -0.000152587890625 -0.249969482421875 0.99923095703125 +0.114625 -0.000152587890625 -0.249969482421875 0.99923095703125 +0.11475 -0.000152587890625 -0.24542236328125 0.99923095703125 +0.114875 -0.000152587890625 -0.2408447265625 0.99923095703125 +0.115 -0.000152587890625 -0.2408447265625 0.99923095703125 +0.115125 -0.000152587890625 -0.236236572265625 0.99923095703125 +0.11525 -0.000152587890625 -0.236236572265625 0.99923095703125 +0.115375 -0.000152587890625 -0.231597900390625 0.99923095703125 +0.1155 -0.0001220703125 -0.226959228515625 0.99923095703125 +0.115625 -0.0001220703125 -0.226959228515625 0.99923095703125 +0.11575 -0.0001220703125 -0.2222900390625 0.99923095703125 +0.115875 -0.0001220703125 -0.2222900390625 0.99923095703125 +0.116 -0.0001220703125 -0.21759033203125 0.99923095703125 +0.116125 -0.0001220703125 -0.212860107421875 0.99923095703125 +0.11625 -0.0001220703125 -0.212860107421875 0.99923095703125 +0.116375 -0.0001220703125 -0.208099365234375 0.99923095703125 +0.1165 -0.0001220703125 -0.208099365234375 0.99923095703125 +0.116625 -0.0001220703125 -0.203338623046875 0.99923095703125 +0.11675 -0.0001220703125 -0.19854736328125 0.99923095703125 +0.116875 -0.0001220703125 -0.19854736328125 0.99923095703125 +0.117 -0.0001220703125 -0.1937255859375 0.99923095703125 +0.117125 -0.0001220703125 -0.1937255859375 0.99923095703125 +0.117250000000000013 -0.0001220703125 -0.188873291015625 0.99923095703125 +0.117375000000000013 -0.0001220703125 -0.18402099609375 0.99923095703125 +0.117500000000000013 -0.0001220703125 -0.18402099609375 0.99923095703125 +0.117625000000000013 -9.1552734375e-05 -0.17913818359375 0.99923095703125 +0.117750000000000013 -9.1552734375e-05 -0.17913818359375 0.99923095703125 +0.117875000000000013 -9.1552734375e-05 -0.17425537109375 0.99923095703125 +0.118000000000000013 -9.1552734375e-05 -0.169342041015625 0.99923095703125 +0.118125000000000013 -9.1552734375e-05 -0.169342041015625 0.99923095703125 +0.118250000000000013 -9.1552734375e-05 -0.164398193359375 0.99923095703125 +0.118375000000000013 -9.1552734375e-05 -0.164398193359375 0.99923095703125 +0.118500000000000013 -9.1552734375e-05 -0.159454345703125 0.99923095703125 +0.118625000000000013 -9.1552734375e-05 -0.15447998046875 0.99923095703125 +0.118750000000000013 -9.1552734375e-05 -0.15447998046875 0.99923095703125 +0.118875000000000013 -9.1552734375e-05 -0.14947509765625 0.99923095703125 +0.119000000000000013 -9.1552734375e-05 -0.14947509765625 0.99923095703125 +0.119125000000000013 -9.1552734375e-05 -0.14447021484375 0.99923095703125 +0.119250000000000013 -9.1552734375e-05 -0.13946533203125 0.99923095703125 +0.119375000000000013 -9.1552734375e-05 -0.13946533203125 0.99923095703125 +0.119500000000000013 -6.103515625e-05 -0.134429931640625 0.99923095703125 +0.119625000000000016 -6.103515625e-05 -0.134429931640625 0.99923095703125 +0.119750000000000016 -6.103515625e-05 -0.129364013671875 0.99923095703125 +0.119875000000000016 -6.103515625e-05 -0.124298095703125 0.99923095703125 +0.12 -6.103515625e-05 -0.124298095703125 0.99923095703125 +0.120125 -6.103515625e-05 -0.119232177734375 0.99923095703125 +0.12025 -6.103515625e-05 -0.119232177734375 0.99923095703125 +0.120375 -6.103515625e-05 -0.1141357421875 0.99923095703125 +0.1205 -6.103515625e-05 -0.109039306640625 0.99923095703125 +0.120625 -6.103515625e-05 -0.109039306640625 0.99923095703125 +0.12075 -6.103515625e-05 -0.103912353515625 0.99923095703125 +0.120875 -6.103515625e-05 -0.103912353515625 0.99923095703125 +0.121 -6.103515625e-05 -0.098785400390625 0.99923095703125 +0.121125 -6.103515625e-05 -0.093658447265625 0.99923095703125 +0.12125 -6.103515625e-05 -0.093658447265625 0.99923095703125 +0.121375 -3.0517578125e-05 -0.0885009765625 0.99923095703125 +0.1215 -3.0517578125e-05 -0.0885009765625 0.99923095703125 +0.121625 -3.0517578125e-05 -0.083343505859375 0.99923095703125 +0.12175 -3.0517578125e-05 -0.07818603515625 0.99923095703125 +0.121875 -3.0517578125e-05 -0.07818603515625 0.99923095703125 +0.122 -3.0517578125e-05 -0.072998046875 0.99923095703125 +0.122125 -3.0517578125e-05 -0.072998046875 0.99923095703125 +0.12225 -3.0517578125e-05 -0.06781005859375 0.99923095703125 +0.122375 -3.0517578125e-05 -0.0626220703125 0.99923095703125 +0.1225 -3.0517578125e-05 -0.0626220703125 0.99923095703125 +0.122625 -3.0517578125e-05 -0.05743408203125 0.99923095703125 +0.12275 -3.0517578125e-05 -0.05743408203125 0.99923095703125 +0.122875 -3.0517578125e-05 -0.05224609375 0.99923095703125 +0.123 -3.0517578125e-05 -0.047027587890625 0.99923095703125 +0.123125 -3.0517578125e-05 -0.047027587890625 0.99923095703125 +0.12325 0.0 -0.04180908203125 0.99923095703125 +0.123375 0.0 -0.04180908203125 0.99923095703125 +0.1235 0.0 -0.036590576171875 0.99923095703125 +0.123625 0.0 -0.0313720703125 0.99923095703125 +0.12375 0.0 -0.0313720703125 0.99923095703125 +0.123875 0.0 -0.026123046875 0.99923095703125 +0.124 0.0 -0.026123046875 0.99923095703125 +0.124125 0.0 -0.020904541015625 0.99923095703125 +0.12425 0.0 -0.01568603515625 0.99923095703125 +0.124375 0.0 -0.01568603515625 0.99923095703125 +0.1245 0.0 -0.01043701171875 0.99923095703125 +0.124625 0.0 -0.01043701171875 0.99923095703125 +0.12475 0.0 -0.005218505859375 0.99923095703125 +0.124875 0.0 0.0 0.99923095703125 +0.125 0.0 0.0 0.99923095703125 +0.12512500000000002 0.0 0.005218505859375 0.99923095703125 +0.12525 0.0 0.005218505859375 0.99923095703125 +0.12537500000000002 0.0 0.01043701171875 0.99923095703125 +0.1255 0.0 0.01568603515625 0.99923095703125 +0.12562500000000002 0.0 0.01568603515625 0.99923095703125 +0.12575 0.0 0.020904541015625 0.99923095703125 +0.12587500000000002 0.0 0.020904541015625 0.99923095703125 +0.126 0.0 0.026123046875 0.99923095703125 +0.12612500000000002 0.0 0.0313720703125 0.99923095703125 +0.12625 0.0 0.0313720703125 0.99923095703125 +0.12637500000000002 0.0 0.036590576171875 0.99923095703125 +0.1265 0.0 0.036590576171875 0.99923095703125 +0.12662500000000002 0.0 0.04180908203125 0.99923095703125 +0.12675 3.0517578125e-05 0.047027587890625 0.99923095703125 +0.12687500000000002 3.0517578125e-05 0.047027587890625 0.99923095703125 +0.127 3.0517578125e-05 0.05224609375 0.99923095703125 +0.12712500000000002 3.0517578125e-05 0.05224609375 0.99923095703125 +0.12725 3.0517578125e-05 0.05743408203125 0.99923095703125 +0.12737500000000002 3.0517578125e-05 0.0626220703125 0.99923095703125 +0.1275 3.0517578125e-05 0.0626220703125 0.99923095703125 +0.12762500000000002 3.0517578125e-05 0.06781005859375 0.99923095703125 +0.12775 3.0517578125e-05 0.06781005859375 0.99923095703125 +0.12787500000000002 3.0517578125e-05 0.072998046875 0.99923095703125 +0.128 0.007415771484375 0.07818603515625 0.90478515625 +0.128125 0.007415771484375 0.07818603515625 0.90478515625 +0.12825 0.007904052734375 0.083343505859375 0.90478515625 +0.128375 0.007904052734375 0.083343505859375 0.90478515625 +0.1285 0.008392333984375 0.0885009765625 0.90478515625 +0.128625 0.008880615234375 0.093658447265625 0.90478515625 +0.12875 0.008880615234375 0.093658447265625 0.90478515625 +0.128875 0.0093994140625 0.098785400390625 0.90478515625 +0.129 0.0093994140625 0.098785400390625 0.90478515625 +0.129125 0.009857177734375 0.103912353515625 0.90478515625 +0.12925 0.010345458984375 0.109039306640625 0.90478515625 +0.129375 0.010345458984375 0.109039306640625 0.90478515625 +0.1295 0.010833740234375 0.1141357421875 0.90478515625 +0.129625 0.010833740234375 0.1141357421875 0.90478515625 +0.12975 0.011322021484375 0.119232177734375 0.90478515625 +0.129875 0.011810302734375 0.124298095703125 0.90478515625 +0.13 0.011810302734375 0.124298095703125 0.90478515625 +0.130125 0.012298583984375 0.129364013671875 0.90478515625 +0.13025 0.012298583984375 0.129364013671875 0.90478515625 +0.130375 0.012786865234375 0.134429931640625 0.90478515625 +0.1305 0.01324462890625 0.13946533203125 0.90478515625 +0.130625 0.01324462890625 0.13946533203125 0.90478515625 +0.13075 0.01373291015625 0.14447021484375 0.90478515625 +0.130875 0.01373291015625 0.14447021484375 0.90478515625 +0.131 0.01422119140625 0.14947509765625 0.90478515625 +0.131125 0.014678955078125 0.15447998046875 0.90478515625 +0.13125 0.014678955078125 0.15447998046875 0.90478515625 +0.131375 0.015167236328125 0.159454345703125 0.90478515625 +0.1315 0.015167236328125 0.159454345703125 0.90478515625 +0.131625 0.015625 0.164398193359375 0.90478515625 +0.13175 0.016082763671875 0.169342041015625 0.90478515625 +0.131875 0.016082763671875 0.169342041015625 0.90478515625 +0.132 0.016571044921875 0.17425537109375 0.90478515625 +0.132125 0.016571044921875 0.17425537109375 0.90478515625 +0.13225 0.01702880859375 0.17913818359375 0.90478515625 +0.132375 0.017486572265625 0.18402099609375 0.90478515625 +0.1325 0.017486572265625 0.18402099609375 0.90478515625 +0.132625 0.0179443359375 0.188873291015625 0.90478515625 +0.13275 0.0179443359375 0.188873291015625 0.90478515625 +0.132875 0.018402099609375 0.1937255859375 0.90478515625 +0.133 0.01885986328125 0.19854736328125 0.90478515625 +0.133125 0.01885986328125 0.19854736328125 0.90478515625 +0.13325 0.019317626953125 0.203338623046875 0.90478515625 +0.133375 0.019317626953125 0.203338623046875 0.90478515625 +0.1335 0.019775390625 0.208099365234375 0.90478515625 +0.133625 0.020233154296875 0.212860107421875 0.90478515625 +0.13375 0.020233154296875 0.212860107421875 0.90478515625 +0.133875 0.02069091796875 0.21759033203125 0.90478515625 +0.134 0.02069091796875 0.21759033203125 0.90478515625 +0.134125 0.0211181640625 0.2222900390625 0.90478515625 +0.13425 0.021575927734375 0.226959228515625 0.90478515625 +0.134375 0.021575927734375 0.226959228515625 0.90478515625 +0.1345 0.022003173828125 0.231597900390625 0.90478515625 +0.134625 0.022003173828125 0.231597900390625 0.90478515625 +0.13475 0.0224609375 0.236236572265625 0.90478515625 +0.134875 0.02288818359375 0.2408447265625 0.90478515625 +0.135 0.02288818359375 0.2408447265625 0.90478515625 +0.135125 0.023345947265625 0.24542236328125 0.90478515625 +0.13525 0.023345947265625 0.24542236328125 0.90478515625 +0.135375 0.023773193359375 0.249969482421875 0.90478515625 +0.1355 0.024200439453125 0.25445556640625 0.90478515625 +0.135625 0.024200439453125 0.25445556640625 0.90478515625 +0.13575 0.024627685546875 0.25897216796875 0.90478515625 +0.135875 0.024627685546875 0.25897216796875 0.90478515625 +0.136 0.025054931640625 0.263427734375 0.90478515625 +0.136125 0.025482177734375 0.267852783203125 0.90478515625 +0.13625 0.025482177734375 0.267852783203125 0.90478515625 +0.136375 0.02587890625 0.27227783203125 0.90478515625 +0.1365 0.02587890625 0.27227783203125 0.90478515625 +0.136625 0.02630615234375 0.276641845703125 0.90478515625 +0.13675 0.026702880859375 0.280975341796875 0.90478515625 +0.136875 0.026702880859375 0.280975341796875 0.90478515625 +0.137 0.027130126953125 0.285308837890625 0.90478515625 +0.137125 0.027130126953125 0.285308837890625 0.90478515625 +0.13725 0.02752685546875 0.289581298828125 0.90478515625 +0.137375 0.027923583984375 0.2938232421875 0.90478515625 +0.1375 0.027923583984375 0.2938232421875 0.90478515625 +0.137625 0.028350830078125 0.298065185546875 0.90478515625 +0.13775 0.028350830078125 0.298065185546875 0.90478515625 +0.137875 0.02874755859375 0.30224609375 0.90478515625 +0.138 0.029144287109375 0.306396484375 0.90478515625 +0.138125 0.029144287109375 0.306396484375 0.90478515625 +0.13825 0.029541015625 0.310516357421875 0.90478515625 +0.138375 0.029541015625 0.310516357421875 0.90478515625 +0.1385 0.0299072265625 0.314605712890625 0.90478515625 +0.138625 0.030303955078125 0.31866455078125 0.90478515625 +0.13875 0.030303955078125 0.31866455078125 0.90478515625 +0.138875 0.030670166015625 0.322662353515625 0.90478515625 +0.139 0.030670166015625 0.322662353515625 0.90478515625 +0.139125 0.03106689453125 0.32666015625 0.90478515625 +0.13925 0.03143310546875 0.330596923828125 0.90478515625 +0.139375 0.03143310546875 0.330596923828125 0.90478515625 +0.1395 0.03179931640625 0.334503173828125 0.90478515625 +0.139625 0.03179931640625 0.334503173828125 0.90478515625 +0.13975 0.03216552734375 0.33837890625 0.90478515625 +0.139875 0.03253173828125 0.34222412109375 0.90478515625 +0.14 0.03253173828125 0.34222412109375 0.90478515625 +0.140125 0.03289794921875 0.34600830078125 0.90478515625 +0.14025 0.03289794921875 0.34600830078125 0.90478515625 +0.140375 0.03326416015625 0.349761962890625 0.90478515625 +0.1405 0.033599853515625 0.353485107421875 0.90478515625 +0.140625 0.033599853515625 0.353485107421875 0.90478515625 +0.14075000000000002 0.033966064453125 0.357177734375 0.90478515625 +0.140875 0.033966064453125 0.357177734375 0.90478515625 +0.14100000000000002 0.0343017578125 0.360809326171875 0.90478515625 +0.141125 0.03466796875 0.36444091796875 0.90478515625 +0.14125000000000002 0.03466796875 0.36444091796875 0.90478515625 +0.141375 0.035003662109375 0.36798095703125 0.90478515625 +0.14150000000000002 0.035003662109375 0.36798095703125 0.90478515625 +0.141625 0.03533935546875 0.37152099609375 0.90478515625 +0.14175000000000002 0.03564453125 0.375 0.90478515625 +0.141875 0.03564453125 0.375 0.90478515625 +0.14200000000000002 0.035980224609375 0.378448486328125 0.90478515625 +0.142125 0.035980224609375 0.378448486328125 0.90478515625 +0.14225000000000002 0.03631591796875 0.3818359375 0.90478515625 +0.142375 0.03662109375 0.38519287109375 0.90478515625 +0.14250000000000002 0.03662109375 0.38519287109375 0.90478515625 +0.142625 0.036956787109375 0.388519287109375 0.90478515625 +0.14275000000000002 0.036956787109375 0.388519287109375 0.90478515625 +0.142875 0.037261962890625 0.39178466796875 0.90478515625 +0.14300000000000002 0.037567138671875 0.39501953125 0.90478515625 +0.143125 0.037567138671875 0.39501953125 0.90478515625 +0.14325000000000002 0.037872314453125 0.398193359375 0.90478515625 +0.143375 0.037872314453125 0.398193359375 0.90478515625 +0.14350000000000002 0.038177490234375 0.401336669921875 0.90478515625 +0.143625 0.0384521484375 0.404449462890625 0.90478515625 +0.14375000000000002 0.0384521484375 0.404449462890625 0.90478515625 +0.143875 0.03875732421875 0.407501220703125 0.90478515625 +0.14400000000000002 0.03875732421875 0.407501220703125 0.90478515625 +0.144125 0.039031982421875 0.4105224609375 0.90478515625 +0.14425 0.039306640625 0.413482666015625 0.90478515625 +0.144375 0.039306640625 0.413482666015625 0.90478515625 +0.1445 0.03961181640625 0.416412353515625 0.90478515625 +0.144625 0.03961181640625 0.416412353515625 0.90478515625 +0.14475 0.03985595703125 0.419281005859375 0.90478515625 +0.144875 0.040130615234375 0.422119140625 0.90478515625 +0.145 0.040130615234375 0.422119140625 0.90478515625 +0.145125 0.0404052734375 0.424896240234375 0.90478515625 +0.14525 0.0404052734375 0.424896240234375 0.90478515625 +0.145375 0.040679931640625 0.4276123046875 0.90478515625 +0.1455 0.040924072265625 0.4302978515625 0.90478515625 +0.145625 0.040924072265625 0.4302978515625 0.90478515625 +0.14575 0.041168212890625 0.432952880859375 0.90478515625 +0.145875 0.041168212890625 0.432952880859375 0.90478515625 +0.146 0.041412353515625 0.435546875 0.90478515625 +0.146125 0.041656494140625 0.438079833984375 0.90478515625 +0.14625 0.041656494140625 0.438079833984375 0.90478515625 +0.146375 0.041900634765625 0.440582275390625 0.90478515625 +0.1465 0.041900634765625 0.440582275390625 0.90478515625 +0.146625 0.042144775390625 0.44305419921875 0.90478515625 +0.14675 0.0423583984375 0.4454345703125 0.90478515625 +0.146875 0.0423583984375 0.4454345703125 0.90478515625 +0.147 0.042572021484375 0.447784423828125 0.90478515625 +0.147125 0.042572021484375 0.447784423828125 0.90478515625 +0.14725 0.042816162109375 0.450103759765625 0.90478515625 +0.147375 0.04302978515625 0.452362060546875 0.90478515625 +0.1475 0.04302978515625 0.452362060546875 0.90478515625 +0.147625 0.043212890625 0.454559326171875 0.90478515625 +0.14775 0.043212890625 0.454559326171875 0.90478515625 +0.147875 0.043426513671875 0.45672607421875 0.90478515625 +0.148 0.04364013671875 0.458831787109375 0.90478515625 +0.148125 0.04364013671875 0.458831787109375 0.90478515625 +0.14825 0.0438232421875 0.46087646484375 0.90478515625 +0.148375 0.0438232421875 0.46087646484375 0.90478515625 +0.1485 0.04400634765625 0.462890625 0.90478515625 +0.148625 0.044189453125 0.464813232421875 0.90478515625 +0.14875 0.044189453125 0.464813232421875 0.90478515625 +0.148875 0.04437255859375 0.46673583984375 0.90478515625 +0.149 0.04437255859375 0.46673583984375 0.90478515625 +0.149125 0.0445556640625 0.46856689453125 0.90478515625 +0.14925 0.04473876953125 0.470367431640625 0.90478515625 +0.149375 0.04473876953125 0.470367431640625 0.90478515625 +0.1495 0.044891357421875 0.472137451171875 0.90478515625 +0.149625 0.044891357421875 0.472137451171875 0.90478515625 +0.14975 0.045074462890625 0.47381591796875 0.90478515625 +0.149875 0.04522705078125 0.4754638671875 0.90478515625 +0.15 0.04522705078125 0.4754638671875 0.90478515625 +0.150125 0.045379638671875 0.47705078125 0.90478515625 +0.15025 0.045379638671875 0.47705078125 0.90478515625 +0.150375 0.045501708984375 0.478607177734375 0.90478515625 +0.1505 0.045654296875 0.480072021484375 0.90478515625 +0.150625 0.045654296875 0.480072021484375 0.90478515625 +0.15075 0.0457763671875 0.48150634765625 0.90478515625 +0.150875 0.0457763671875 0.48150634765625 0.90478515625 +0.151 0.045928955078125 0.48291015625 0.90478515625 +0.151125 0.046051025390625 0.484222412109375 0.90478515625 +0.15125 0.046051025390625 0.484222412109375 0.90478515625 +0.151375 0.046173095703125 0.485504150390625 0.90478515625 +0.1515 0.046173095703125 0.485504150390625 0.90478515625 +0.151625 0.046295166015625 0.486724853515625 0.90478515625 +0.15175 0.04638671875 0.487884521484375 0.90478515625 +0.151875 0.04638671875 0.487884521484375 0.90478515625 +0.152 0.0465087890625 0.489013671875 0.90478515625 +0.152125 0.0465087890625 0.489013671875 0.90478515625 +0.15225 0.046600341796875 0.490081787109375 0.90478515625 +0.152375 0.04669189453125 0.4910888671875 0.90478515625 +0.1525 0.04669189453125 0.4910888671875 0.90478515625 +0.152625 0.046783447265625 0.492034912109375 0.90478515625 +0.15275 0.046783447265625 0.492034912109375 0.90478515625 +0.152875 0.046875 0.492950439453125 0.90478515625 +0.153 0.046966552734375 0.4937744140625 0.90478515625 +0.153125 0.046966552734375 0.4937744140625 0.90478515625 +0.15325 0.047027587890625 0.49456787109375 0.90478515625 +0.153375 0.047027587890625 0.49456787109375 0.90478515625 +0.1535 0.047088623046875 0.49530029296875 0.90478515625 +0.153625 0.04718017578125 0.496002197265625 0.90478515625 +0.15375 0.04718017578125 0.496002197265625 0.90478515625 +0.153875 0.0472412109375 0.496612548828125 0.90478515625 +0.154 0.0472412109375 0.496612548828125 0.90478515625 +0.154125 0.047271728515625 0.4971923828125 0.90478515625 +0.15425 0.047332763671875 0.497711181640625 0.90478515625 +0.154375 0.047332763671875 0.497711181640625 0.90478515625 +0.1545 0.04736328125 0.498199462890625 0.90478515625 +0.154625 0.04736328125 0.498199462890625 0.90478515625 +0.15475 0.04742431640625 0.49859619140625 0.90478515625 +0.154875 0.047454833984375 0.49896240234375 0.90478515625 +0.155 0.047454833984375 0.49896240234375 0.90478515625 +0.155125 0.0474853515625 0.499267578125 0.90478515625 +0.15525 0.0474853515625 0.499267578125 0.90478515625 +0.155375 0.047515869140625 0.49951171875 0.90478515625 +0.1555 0.047515869140625 0.49969482421875 0.90478515625 +0.155625 0.047515869140625 0.49969482421875 0.90478515625 +0.15575 0.04754638671875 0.49981689453125 0.90478515625 +0.155875 0.04754638671875 0.49981689453125 0.90478515625 +0.156 0.04754638671875 0.499908447265625 0.90478515625 +0.156125 0.04754638671875 0.49993896484375 0.90478515625 +0.15625 0.04754638671875 0.49993896484375 0.90478515625 +0.15637500000000002 0.04754638671875 0.499908447265625 0.90478515625 +0.1565 0.04754638671875 0.499908447265625 0.90478515625 +0.15662500000000002 0.04754638671875 0.49981689453125 0.90478515625 +0.15675 0.047515869140625 0.49969482421875 0.90478515625 +0.15687500000000002 0.047515869140625 0.49969482421875 0.90478515625 +0.157 0.047515869140625 0.49951171875 0.90478515625 +0.15712500000000002 0.047515869140625 0.49951171875 0.90478515625 +0.15725 0.0474853515625 0.499267578125 0.90478515625 +0.15737500000000002 0.047454833984375 0.49896240234375 0.90478515625 +0.1575 0.047454833984375 0.49896240234375 0.90478515625 +0.15762500000000002 0.04742431640625 0.49859619140625 0.90478515625 +0.15775 0.04742431640625 0.49859619140625 0.90478515625 +0.15787500000000002 0.04736328125 0.498199462890625 0.90478515625 +0.158 0.047332763671875 0.497711181640625 0.90478515625 +0.15812500000000002 0.047332763671875 0.497711181640625 0.90478515625 +0.15825 0.047271728515625 0.4971923828125 0.90478515625 +0.15837500000000002 0.047271728515625 0.4971923828125 0.90478515625 +0.1585 0.0472412109375 0.496612548828125 0.90478515625 +0.15862500000000002 0.04718017578125 0.496002197265625 0.90478515625 +0.15875 0.04718017578125 0.496002197265625 0.90478515625 +0.15887500000000002 0.047088623046875 0.49530029296875 0.90478515625 +0.159 0.047088623046875 0.49530029296875 0.90478515625 +0.15912500000000002 0.047027587890625 0.49456787109375 0.90478515625 +0.15925 0.046966552734375 0.4937744140625 0.90478515625 +0.15937500000000002 0.046966552734375 0.4937744140625 0.90478515625 +0.1595 0.046875 0.492950439453125 0.90478515625 +0.15962500000000002 0.046875 0.492950439453125 0.90478515625 +0.15975 0.046783447265625 0.492034912109375 0.90478515625 +0.15987500000000002 0.04669189453125 0.4910888671875 0.90478515625 +0.16 0.163970947265625 0.4910888671875 0.665972900390625 +0.160125 0.16363525390625 0.490081787109375 0.665972900390625 +0.16025 0.16363525390625 0.490081787109375 0.665972900390625 +0.160375 0.163299560546875 0.489013671875 0.665972900390625 +0.1605 0.16290283203125 0.487884521484375 0.665972900390625 +0.160625 0.16290283203125 0.487884521484375 0.665972900390625 +0.16075 0.16253662109375 0.486724853515625 0.665972900390625 +0.160875 0.16253662109375 0.486724853515625 0.665972900390625 +0.161 0.162109375 0.485504150390625 0.665972900390625 +0.161125 0.16168212890625 0.484222412109375 0.665972900390625 +0.16125 0.16168212890625 0.484222412109375 0.665972900390625 +0.161375 0.1612548828125 0.48291015625 0.665972900390625 +0.1615 0.1612548828125 0.48291015625 0.665972900390625 +0.161625 0.160797119140625 0.48150634765625 0.665972900390625 +0.16175 0.160308837890625 0.480072021484375 0.665972900390625 +0.161875 0.160308837890625 0.480072021484375 0.665972900390625 +0.162 0.159820556640625 0.478607177734375 0.665972900390625 +0.162125 0.159820556640625 0.478607177734375 0.665972900390625 +0.16225 0.1593017578125 0.47705078125 0.665972900390625 +0.162375 0.158782958984375 0.4754638671875 0.665972900390625 +0.1625 0.158782958984375 0.4754638671875 0.665972900390625 +0.162625 0.158203125 0.47381591796875 0.665972900390625 +0.16275 0.158203125 0.47381591796875 0.665972900390625 +0.162875 0.15765380859375 0.472137451171875 0.665972900390625 +0.163 0.157073974609375 0.470367431640625 0.665972900390625 +0.163125 0.157073974609375 0.470367431640625 0.665972900390625 +0.16325 0.156463623046875 0.46856689453125 0.665972900390625 +0.163375 0.156463623046875 0.46856689453125 0.665972900390625 +0.1635 0.155853271484375 0.46673583984375 0.665972900390625 +0.163625 0.15521240234375 0.464813232421875 0.665972900390625 +0.16375 0.15521240234375 0.464813232421875 0.665972900390625 +0.163875 0.154571533203125 0.462890625 0.665972900390625 +0.164 0.154571533203125 0.462890625 0.665972900390625 +0.164125 0.153900146484375 0.46087646484375 0.665972900390625 +0.16425 0.1531982421875 0.458831787109375 0.665972900390625 +0.164375 0.1531982421875 0.458831787109375 0.665972900390625 +0.1645 0.152496337890625 0.45672607421875 0.665972900390625 +0.164625 0.152496337890625 0.45672607421875 0.665972900390625 +0.16475 0.15179443359375 0.454559326171875 0.665972900390625 +0.164875 0.15106201171875 0.452362060546875 0.665972900390625 +0.165 0.15106201171875 0.452362060546875 0.665972900390625 +0.165125 0.150299072265625 0.450103759765625 0.665972900390625 +0.16525 0.150299072265625 0.450103759765625 0.665972900390625 +0.165375 0.1495361328125 0.447784423828125 0.665972900390625 +0.1655 0.14874267578125 0.4454345703125 0.665972900390625 +0.165625 0.14874267578125 0.4454345703125 0.665972900390625 +0.16575 0.14794921875 0.44305419921875 0.665972900390625 +0.165875 0.14794921875 0.44305419921875 0.665972900390625 +0.166 0.147125244140625 0.440582275390625 0.665972900390625 +0.166125 0.146270751953125 0.438079833984375 0.665972900390625 +0.16625 0.146270751953125 0.438079833984375 0.665972900390625 +0.166375 0.14544677734375 0.435546875 0.665972900390625 +0.1665 0.14544677734375 0.435546875 0.665972900390625 +0.166625 0.144561767578125 0.432952880859375 0.665972900390625 +0.16675 0.1436767578125 0.4302978515625 0.665972900390625 +0.166875 0.1436767578125 0.4302978515625 0.665972900390625 +0.167 0.142791748046875 0.4276123046875 0.665972900390625 +0.167125 0.142791748046875 0.4276123046875 0.665972900390625 +0.16725 0.141876220703125 0.424896240234375 0.665972900390625 +0.167375 0.140960693359375 0.422119140625 0.665972900390625 +0.1675 0.140960693359375 0.422119140625 0.665972900390625 +0.167625 0.1400146484375 0.419281005859375 0.665972900390625 +0.16775 0.1400146484375 0.419281005859375 0.665972900390625 +0.167875 0.1390380859375 0.416412353515625 0.665972900390625 +0.168 0.1380615234375 0.413482666015625 0.665972900390625 +0.168125 0.1380615234375 0.413482666015625 0.665972900390625 +0.16825 0.1370849609375 0.4105224609375 0.665972900390625 +0.168375 0.1370849609375 0.4105224609375 0.665972900390625 +0.1685 0.136077880859375 0.407501220703125 0.665972900390625 +0.168625 0.135040283203125 0.404449462890625 0.665972900390625 +0.16875 0.135040283203125 0.404449462890625 0.665972900390625 +0.168875 0.134002685546875 0.401336669921875 0.665972900390625 +0.169 0.134002685546875 0.401336669921875 0.665972900390625 +0.169125 0.132965087890625 0.398193359375 0.665972900390625 +0.16925 0.13189697265625 0.39501953125 0.665972900390625 +0.169375 0.13189697265625 0.39501953125 0.665972900390625 +0.1695 0.130828857421875 0.39178466796875 0.665972900390625 +0.169625 0.130828857421875 0.39178466796875 0.665972900390625 +0.16975 0.129730224609375 0.388519287109375 0.665972900390625 +0.169875 0.128631591796875 0.38519287109375 0.665972900390625 +0.17 0.128631591796875 0.38519287109375 0.665972900390625 +0.170125 0.12750244140625 0.3818359375 0.665972900390625 +0.17025 0.12750244140625 0.3818359375 0.665972900390625 +0.170375 0.126373291015625 0.378448486328125 0.665972900390625 +0.1705 0.125213623046875 0.375 0.665972900390625 +0.170625 0.125213623046875 0.375 0.665972900390625 +0.17075 0.124053955078125 0.37152099609375 0.665972900390625 +0.170875 0.124053955078125 0.37152099609375 0.665972900390625 +0.171 0.12286376953125 0.36798095703125 0.665972900390625 +0.171125 0.1217041015625 0.36444091796875 0.665972900390625 +0.17125 0.1217041015625 0.36444091796875 0.665972900390625 +0.171375 0.1204833984375 0.360809326171875 0.665972900390625 +0.1715 0.1204833984375 0.360809326171875 0.665972900390625 +0.171625 0.1192626953125 0.357177734375 0.665972900390625 +0.17175 0.1180419921875 0.353485107421875 0.665972900390625 +0.171875 0.1180419921875 0.353485107421875 0.665972900390625 +0.17200000000000002 0.116790771484375 0.349761962890625 0.665972900390625 +0.172125 0.116790771484375 0.349761962890625 0.665972900390625 +0.17225000000000002 0.11553955078125 0.34600830078125 0.665972900390625 +0.172375 0.1142578125 0.34222412109375 0.665972900390625 +0.17250000000000002 0.1142578125 0.34222412109375 0.665972900390625 +0.172625 0.113006591796875 0.33837890625 0.665972900390625 +0.17275000000000002 0.113006591796875 0.33837890625 0.665972900390625 +0.172875 0.1116943359375 0.334503173828125 0.665972900390625 +0.17300000000000002 0.110382080078125 0.330596923828125 0.665972900390625 +0.173125 0.110382080078125 0.330596923828125 0.665972900390625 +0.17325000000000002 0.10906982421875 0.32666015625 0.665972900390625 +0.173375 0.10906982421875 0.32666015625 0.665972900390625 +0.17350000000000002 0.107757568359375 0.322662353515625 0.665972900390625 +0.173625 0.106414794921875 0.31866455078125 0.665972900390625 +0.17375000000000002 0.106414794921875 0.31866455078125 0.665972900390625 +0.173875 0.10504150390625 0.314605712890625 0.665972900390625 +0.17400000000000002 0.10504150390625 0.314605712890625 0.665972900390625 +0.174125 0.10369873046875 0.310516357421875 0.665972900390625 +0.17425000000000002 0.102325439453125 0.306396484375 0.665972900390625 +0.174375 0.102325439453125 0.306396484375 0.665972900390625 +0.17450000000000002 0.100921630859375 0.30224609375 0.665972900390625 +0.174625 0.100921630859375 0.30224609375 0.665972900390625 +0.17475000000000002 0.099517822265625 0.298065185546875 0.665972900390625 +0.174875 0.098114013671875 0.2938232421875 0.665972900390625 +0.17500000000000002 0.098114013671875 0.2938232421875 0.665972900390625 +0.175125 0.096710205078125 0.289581298828125 0.665972900390625 +0.17525000000000002 0.096710205078125 0.289581298828125 0.665972900390625 +0.175375 0.09527587890625 0.285308837890625 0.665972900390625 +0.17550000000000002 0.09381103515625 0.280975341796875 0.665972900390625 +0.175625 0.09381103515625 0.280975341796875 0.665972900390625 +0.17575000000000002 0.092376708984375 0.276641845703125 0.665972900390625 +0.175875 0.092376708984375 0.276641845703125 0.665972900390625 +0.176 0.090911865234375 0.27227783203125 0.665972900390625 +0.176125 0.089447021484375 0.267852783203125 0.665972900390625 +0.17625 0.089447021484375 0.267852783203125 0.665972900390625 +0.176375 0.08795166015625 0.263427734375 0.665972900390625 +0.1765 0.08795166015625 0.263427734375 0.665972900390625 +0.176625 0.08648681640625 0.25897216796875 0.665972900390625 +0.17675 0.0849609375 0.25445556640625 0.665972900390625 +0.176875 0.0849609375 0.25445556640625 0.665972900390625 +0.177 0.083465576171875 0.249969482421875 0.665972900390625 +0.177125 0.083465576171875 0.249969482421875 0.665972900390625 +0.17725 0.081939697265625 0.24542236328125 0.665972900390625 +0.177375 0.080413818359375 0.2408447265625 0.665972900390625 +0.1775 0.080413818359375 0.2408447265625 0.665972900390625 +0.177625 0.078887939453125 0.236236572265625 0.665972900390625 +0.17775 0.078887939453125 0.236236572265625 0.665972900390625 +0.177875 0.07733154296875 0.231597900390625 0.665972900390625 +0.178 0.075775146484375 0.226959228515625 0.665972900390625 +0.178125 0.075775146484375 0.226959228515625 0.665972900390625 +0.17825 0.07421875 0.2222900390625 0.665972900390625 +0.178375 0.07421875 0.2222900390625 0.665972900390625 +0.1785 0.072662353515625 0.21759033203125 0.665972900390625 +0.178625 0.071075439453125 0.212860107421875 0.665972900390625 +0.17875 0.071075439453125 0.212860107421875 0.665972900390625 +0.178875 0.069488525390625 0.208099365234375 0.665972900390625 +0.179 0.069488525390625 0.208099365234375 0.665972900390625 +0.179125 0.067901611328125 0.203338623046875 0.665972900390625 +0.17925 0.0662841796875 0.19854736328125 0.665972900390625 +0.179375 0.0662841796875 0.19854736328125 0.665972900390625 +0.1795 0.064666748046875 0.1937255859375 0.665972900390625 +0.179625 0.064666748046875 0.1937255859375 0.665972900390625 +0.17975 0.06304931640625 0.188873291015625 0.665972900390625 +0.179875 0.061431884765625 0.18402099609375 0.665972900390625 +0.18 0.061431884765625 0.18402099609375 0.665972900390625 +0.180125 0.059814453125 0.17913818359375 0.665972900390625 +0.18025 0.059814453125 0.17913818359375 0.665972900390625 +0.180375 0.05816650390625 0.17425537109375 0.665972900390625 +0.1805 0.056549072265625 0.169342041015625 0.665972900390625 +0.180625 0.056549072265625 0.169342041015625 0.665972900390625 +0.18075 0.054901123046875 0.164398193359375 0.665972900390625 +0.180875 0.054901123046875 0.164398193359375 0.665972900390625 +0.181 0.05322265625 0.159454345703125 0.665972900390625 +0.181125 0.05157470703125 0.15447998046875 0.665972900390625 +0.18125 0.05157470703125 0.15447998046875 0.665972900390625 +0.181375 0.049896240234375 0.14947509765625 0.665972900390625 +0.1815 0.049896240234375 0.14947509765625 0.665972900390625 +0.181625 0.048248291015625 0.14447021484375 0.665972900390625 +0.18175 0.04656982421875 0.13946533203125 0.665972900390625 +0.181875 0.04656982421875 0.13946533203125 0.665972900390625 +0.182 0.044891357421875 0.134429931640625 0.665972900390625 +0.182125 0.044891357421875 0.134429931640625 0.665972900390625 +0.18225 0.043182373046875 0.129364013671875 0.665972900390625 +0.182375 0.04150390625 0.124298095703125 0.665972900390625 +0.1825 0.04150390625 0.124298095703125 0.665972900390625 +0.182625 0.039794921875 0.119232177734375 0.665972900390625 +0.18275 0.039794921875 0.119232177734375 0.665972900390625 +0.182875 0.038116455078125 0.1141357421875 0.665972900390625 +0.183 0.036407470703125 0.109039306640625 0.665972900390625 +0.183125 0.036407470703125 0.109039306640625 0.665972900390625 +0.18325 0.034698486328125 0.103912353515625 0.665972900390625 +0.183375 0.034698486328125 0.103912353515625 0.665972900390625 +0.1835 0.032989501953125 0.098785400390625 0.665972900390625 +0.183625 0.03125 0.093658447265625 0.665972900390625 +0.18375 0.03125 0.093658447265625 0.665972900390625 +0.183875 0.029541015625 0.0885009765625 0.665972900390625 +0.184 0.029541015625 0.0885009765625 0.665972900390625 +0.184125 0.02783203125 0.083343505859375 0.665972900390625 +0.18425 0.026092529296875 0.07818603515625 0.665972900390625 +0.184375 0.026092529296875 0.07818603515625 0.665972900390625 +0.1845 0.024383544921875 0.072998046875 0.665972900390625 +0.184625 0.024383544921875 0.072998046875 0.665972900390625 +0.18475 0.02264404296875 0.06781005859375 0.665972900390625 +0.184875 0.020904541015625 0.0626220703125 0.665972900390625 +0.185 0.020904541015625 0.0626220703125 0.665972900390625 +0.185125 0.0191650390625 0.05743408203125 0.665972900390625 +0.18525 0.0191650390625 0.05743408203125 0.665972900390625 +0.185375 0.017425537109375 0.05224609375 0.665972900390625 +0.1855 0.01568603515625 0.047027587890625 0.665972900390625 +0.185625 0.01568603515625 0.047027587890625 0.665972900390625 +0.18575 0.013946533203125 0.04180908203125 0.665972900390625 +0.185875 0.013946533203125 0.04180908203125 0.665972900390625 +0.186 0.01220703125 0.036590576171875 0.665972900390625 +0.186125 0.010467529296875 0.0313720703125 0.665972900390625 +0.18625 0.010467529296875 0.0313720703125 0.665972900390625 +0.186375 0.00872802734375 0.026123046875 0.665972900390625 +0.1865 0.00872802734375 0.026123046875 0.665972900390625 +0.186625 0.006988525390625 0.020904541015625 0.665972900390625 +0.18675 0.005218505859375 0.01568603515625 0.665972900390625 +0.186875 0.005218505859375 0.01568603515625 0.665972900390625 +0.187 0.00347900390625 0.01043701171875 0.665972900390625 +0.187125 0.00347900390625 0.01043701171875 0.665972900390625 +0.18725 0.001739501953125 0.005218505859375 0.665972900390625 +0.187375 0.0 0.0 0.665972900390625 +0.1875 0.0 0.0 0.665972900390625 +0.1876250000000000256 -0.001739501953125 -0.005218505859375 0.665972900390625 +0.18775 -0.001739501953125 -0.005218505859375 0.665972900390625 +0.1878750000000000256 -0.00347900390625 -0.01043701171875 0.665972900390625 +0.188 -0.005218505859375 -0.01568603515625 0.665972900390625 +0.1881250000000000256 -0.005218505859375 -0.01568603515625 0.665972900390625 +0.18825 -0.006988525390625 -0.020904541015625 0.665972900390625 +0.1883750000000000256 -0.006988525390625 -0.020904541015625 0.665972900390625 +0.1885 -0.00872802734375 -0.026123046875 0.665972900390625 +0.1886250000000000256 -0.010467529296875 -0.0313720703125 0.665972900390625 +0.18875 -0.010467529296875 -0.0313720703125 0.665972900390625 +0.1888750000000000256 -0.01220703125 -0.036590576171875 0.665972900390625 +0.189 -0.01220703125 -0.036590576171875 0.665972900390625 +0.1891250000000000256 -0.013946533203125 -0.04180908203125 0.665972900390625 +0.18925 -0.01568603515625 -0.047027587890625 0.665972900390625 +0.1893750000000000256 -0.01568603515625 -0.047027587890625 0.665972900390625 +0.1895 -0.017425537109375 -0.05224609375 0.665972900390625 +0.1896250000000000256 -0.017425537109375 -0.05224609375 0.665972900390625 +0.18975 -0.0191650390625 -0.05743408203125 0.665972900390625 +0.1898750000000000256 -0.020904541015625 -0.0626220703125 0.665972900390625 +0.19 -0.020904541015625 -0.0626220703125 0.665972900390625 +0.1901250000000000256 -0.02264404296875 -0.06781005859375 0.665972900390625 +0.19025 -0.02264404296875 -0.06781005859375 0.665972900390625 +0.1903750000000000256 -0.024383544921875 -0.072998046875 0.665972900390625 +0.1905 -0.026092529296875 -0.07818603515625 0.665972900390625 +0.1906250000000000256 -0.026092529296875 -0.07818603515625 0.665972900390625 +0.19075 -0.02783203125 -0.083343505859375 0.665972900390625 +0.1908750000000000256 -0.02783203125 -0.083343505859375 0.665972900390625 +0.191 -0.029541015625 -0.0885009765625 0.665972900390625 +0.1911250000000000256 -0.03125 -0.093658447265625 0.665972900390625 +0.19125 -0.03125 -0.093658447265625 0.665972900390625 +0.1913750000000000256 -0.032989501953125 -0.098785400390625 0.665972900390625 +0.1915 -0.032989501953125 -0.098785400390625 0.665972900390625 +0.1916250000000000256 -0.034698486328125 -0.103912353515625 0.665972900390625 +0.19175 -0.036407470703125 -0.109039306640625 0.665972900390625 +0.1918750000000000256 -0.036407470703125 -0.109039306640625 0.665972900390625 +0.192 -0.0775146484375 -0.1141357421875 0.3209167480468749 +0.192125 -0.0775146484375 -0.1141357421875 0.3209167480468749 +0.19225 -0.080963134765625 -0.119232177734375 0.3209167480468749 +0.192375 -0.08441162109375 -0.124298095703125 0.3209167480468749 +0.1925 -0.08441162109375 -0.124298095703125 0.3209167480468749 +0.192625 -0.08782958984375 -0.129364013671875 0.3209167480468749 +0.19275 -0.08782958984375 -0.129364013671875 0.3209167480468749 +0.192875 -0.091278076171875 -0.134429931640625 0.3209167480468749 +0.193 -0.094696044921875 -0.13946533203125 0.3209167480468749 +0.193125 -0.094696044921875 -0.13946533203125 0.3209167480468749 +0.19325 -0.09808349609375 -0.14447021484375 0.3209167480468749 +0.193375 -0.09808349609375 -0.14447021484375 0.3209167480468749 +0.1935 -0.10150146484375 -0.14947509765625 0.3209167480468749 +0.193625 -0.104888916015625 -0.15447998046875 0.3209167480468749 +0.19375 -0.104888916015625 -0.15447998046875 0.3209167480468749 +0.193875 -0.1082763671875 -0.159454345703125 0.3209167480468749 +0.194 -0.1082763671875 -0.159454345703125 0.3209167480468749 +0.194125 -0.11163330078125 -0.164398193359375 0.3209167480468749 +0.19425 -0.114990234375 -0.169342041015625 0.3209167480468749 +0.194375 -0.114990234375 -0.169342041015625 0.3209167480468749 +0.1945 -0.118316650390625 -0.17425537109375 0.3209167480468749 +0.194625 -0.118316650390625 -0.17425537109375 0.3209167480468749 +0.19475 -0.12164306640625 -0.17913818359375 0.3209167480468749 +0.194875 -0.12493896484375 -0.18402099609375 0.3209167480468749 +0.195 -0.12493896484375 -0.18402099609375 0.3209167480468749 +0.195125 -0.12823486328125 -0.188873291015625 0.3209167480468749 +0.19525 -0.12823486328125 -0.188873291015625 0.3209167480468749 +0.195375 -0.13153076171875 -0.1937255859375 0.3209167480468749 +0.1955 -0.134796142578125 -0.19854736328125 0.3209167480468749 +0.195625 -0.134796142578125 -0.19854736328125 0.3209167480468749 +0.19575 -0.1380615234375 -0.203338623046875 0.3209167480468749 +0.195875 -0.1380615234375 -0.203338623046875 0.3209167480468749 +0.196 -0.14129638671875 -0.208099365234375 0.3209167480468749 +0.196125 -0.14453125 -0.212860107421875 0.3209167480468749 +0.19625 -0.14453125 -0.212860107421875 0.3209167480468749 +0.196375 -0.147735595703125 -0.21759033203125 0.3209167480468749 +0.1965 -0.147735595703125 -0.21759033203125 0.3209167480468749 +0.196625 -0.15093994140625 -0.2222900390625 0.3209167480468749 +0.19675 -0.154083251953125 -0.226959228515625 0.3209167480468749 +0.196875 -0.154083251953125 -0.226959228515625 0.3209167480468749 +0.197 -0.157257080078125 -0.231597900390625 0.3209167480468749 +0.197125 -0.157257080078125 -0.231597900390625 0.3209167480468749 +0.19725 -0.160400390625 -0.236236572265625 0.3209167480468749 +0.197375 -0.16351318359375 -0.2408447265625 0.3209167480468749 +0.1975 -0.16351318359375 -0.2408447265625 0.3209167480468749 +0.197625 -0.1666259765625 -0.24542236328125 0.3209167480468749 +0.19775 -0.1666259765625 -0.24542236328125 0.3209167480468749 +0.197875 -0.169708251953125 -0.249969482421875 0.3209167480468749 +0.198 -0.17279052734375 -0.25445556640625 0.3209167480468749 +0.198125 -0.17279052734375 -0.25445556640625 0.3209167480468749 +0.19825 -0.17584228515625 -0.25897216796875 0.3209167480468749 +0.198375 -0.17584228515625 -0.25897216796875 0.3209167480468749 +0.1985 -0.178863525390625 -0.263427734375 0.3209167480468749 +0.198625 -0.181884765625 -0.267852783203125 0.3209167480468749 +0.19875 -0.181884765625 -0.267852783203125 0.3209167480468749 +0.198875 -0.18487548828125 -0.27227783203125 0.3209167480468749 +0.199 -0.18487548828125 -0.27227783203125 0.3209167480468749 +0.199125 -0.187835693359375 -0.276641845703125 0.3209167480468749 +0.19925 -0.1907958984375 -0.280975341796875 0.3209167480468749 +0.199375 -0.1907958984375 -0.280975341796875 0.3209167480468749 +0.1995 -0.1937255859375 -0.285308837890625 0.3209167480468749 +0.199625 -0.1937255859375 -0.285308837890625 0.3209167480468749 +0.19975 -0.196624755859375 -0.289581298828125 0.3209167480468749 +0.199875 -0.19952392578125 -0.2938232421875 0.3209167480468749 +0.2 -0.19952392578125 -0.2938232421875 0.3209167480468749 +0.200125 -0.202392578125 -0.298065185546875 0.3209167480468749 +0.20025 -0.202392578125 -0.298065185546875 0.3209167480468749 +0.200375 -0.205230712890625 -0.30224609375 0.3209167480468749 +0.2005 -0.20806884765625 -0.306396484375 0.3209167480468749 +0.200625 -0.20806884765625 -0.306396484375 0.3209167480468749 +0.20075 -0.210845947265625 -0.310516357421875 0.3209167480468749 +0.200875 -0.210845947265625 -0.310516357421875 0.3209167480468749 +0.201 -0.213623046875 -0.314605712890625 0.3209167480468749 +0.201125 -0.21636962890625 -0.31866455078125 0.3209167480468749 +0.20125 -0.21636962890625 -0.31866455078125 0.3209167480468749 +0.201375 -0.219085693359375 -0.322662353515625 0.3209167480468749 +0.2015 -0.219085693359375 -0.322662353515625 0.3209167480468749 +0.201625 -0.2218017578125 -0.32666015625 0.3209167480468749 +0.20175 -0.2244873046875 -0.330596923828125 0.3209167480468749 +0.201875 -0.2244873046875 -0.330596923828125 0.3209167480468749 +0.202 -0.227142333984375 -0.334503173828125 0.3209167480468749 +0.202125 -0.227142333984375 -0.334503173828125 0.3209167480468749 +0.20225 -0.229766845703125 -0.33837890625 0.3209167480468749 +0.202375 -0.23236083984375 -0.34222412109375 0.3209167480468749 +0.2025 -0.23236083984375 -0.34222412109375 0.3209167480468749 +0.202625 -0.234954833984375 -0.34600830078125 0.3209167480468749 +0.20275 -0.234954833984375 -0.34600830078125 0.3209167480468749 +0.202875 -0.23748779296875 -0.349761962890625 0.3209167480468749 +0.203 -0.240020751953125 -0.353485107421875 0.3209167480468749 +0.203125 -0.240020751953125 -0.353485107421875 0.3209167480468749 +0.2032500000000000256 -0.242523193359375 -0.357177734375 0.3209167480468749 +0.203375 -0.242523193359375 -0.357177734375 0.3209167480468749 +0.2035000000000000256 -0.2449951171875 -0.360809326171875 0.3209167480468749 +0.203625 -0.247467041015625 -0.36444091796875 0.3209167480468749 +0.2037500000000000256 -0.247467041015625 -0.36444091796875 0.3209167480468749 +0.203875 -0.2498779296875 -0.36798095703125 0.3209167480468749 +0.2040000000000000256 -0.2498779296875 -0.36798095703125 0.3209167480468749 +0.204125 -0.25225830078125 -0.37152099609375 0.3209167480468749 +0.2042500000000000256 -0.254638671875 -0.375 0.3209167480468749 +0.204375 -0.254638671875 -0.375 0.3209167480468749 +0.2045000000000000256 -0.2569580078125 -0.378448486328125 0.3209167480468749 +0.204625 -0.2569580078125 -0.378448486328125 0.3209167480468749 +0.2047500000000000256 -0.25927734375 -0.3818359375 0.3209167480468749 +0.204875 -0.261566162109375 -0.38519287109375 0.3209167480468749 +0.2050000000000000256 -0.261566162109375 -0.38519287109375 0.3209167480468749 +0.205125 -0.2637939453125 -0.388519287109375 0.3209167480468749 +0.2052500000000000256 -0.2637939453125 -0.388519287109375 0.3209167480468749 +0.205375 -0.266021728515625 -0.39178466796875 0.3209167480468749 +0.2055000000000000256 -0.268218994140625 -0.39501953125 0.3209167480468749 +0.205625 -0.268218994140625 -0.39501953125 0.3209167480468749 +0.2057500000000000256 -0.2703857421875 -0.398193359375 0.3209167480468749 +0.205875 -0.2703857421875 -0.398193359375 0.3209167480468749 +0.2060000000000000256 -0.27252197265625 -0.401336669921875 0.3209167480468749 +0.206125 -0.274627685546875 -0.404449462890625 0.3209167480468749 +0.2062500000000000256 -0.274627685546875 -0.404449462890625 0.3209167480468749 +0.206375 -0.276702880859375 -0.407501220703125 0.3209167480468749 +0.2065000000000000256 -0.276702880859375 -0.407501220703125 0.3209167480468749 +0.206625 -0.27874755859375 -0.4105224609375 0.3209167480468749 +0.2067500000000000256 -0.28076171875 -0.413482666015625 0.3209167480468749 +0.206875 -0.28076171875 -0.413482666015625 0.3209167480468749 +0.2070000000000000256 -0.282745361328125 -0.416412353515625 0.3209167480468749 +0.207125 -0.282745361328125 -0.416412353515625 0.3209167480468749 +0.2072500000000000256 -0.284698486328125 -0.419281005859375 0.3209167480468749 +0.207375 -0.28662109375 -0.422119140625 0.3209167480468749 +0.2075000000000000256 -0.28662109375 -0.422119140625 0.3209167480468749 +0.207625 -0.28851318359375 -0.424896240234375 0.3209167480468749 +0.2077500000000000256 -0.28851318359375 -0.424896240234375 0.3209167480468749 +0.207875 -0.29034423828125 -0.4276123046875 0.3209167480468749 +0.208000000000000032 -0.29217529296875 -0.4302978515625 0.3209167480468749 +0.208125 -0.29217529296875 -0.4302978515625 0.3209167480468749 +0.20825 -0.293975830078125 -0.432952880859375 0.3209167480468749 +0.208375 -0.293975830078125 -0.432952880859375 0.3209167480468749 +0.2085 -0.295745849609375 -0.435546875 0.3209167480468749 +0.208625 -0.297454833984375 -0.438079833984375 0.3209167480468749 +0.20875 -0.297454833984375 -0.438079833984375 0.3209167480468749 +0.208875 -0.299163818359375 -0.440582275390625 0.3209167480468749 +0.209 -0.299163818359375 -0.440582275390625 0.3209167480468749 +0.209125 -0.30084228515625 -0.44305419921875 0.3209167480468749 +0.20925 -0.302459716796875 -0.4454345703125 0.3209167480468749 +0.209375 -0.302459716796875 -0.4454345703125 0.3209167480468749 +0.2095 -0.304046630859375 -0.447784423828125 0.3209167480468749 +0.209625 -0.304046630859375 -0.447784423828125 0.3209167480468749 +0.20975 -0.305633544921875 -0.450103759765625 0.3209167480468749 +0.209875 -0.307159423828125 -0.452362060546875 0.3209167480468749 +0.21 -0.307159423828125 -0.452362060546875 0.3209167480468749 +0.210125 -0.30865478515625 -0.454559326171875 0.3209167480468749 +0.21025 -0.30865478515625 -0.454559326171875 0.3209167480468749 +0.210375 -0.31011962890625 -0.45672607421875 0.3209167480468749 +0.2105 -0.311553955078125 -0.458831787109375 0.3209167480468749 +0.210625 -0.311553955078125 -0.458831787109375 0.3209167480468749 +0.21075 -0.31292724609375 -0.46087646484375 0.3209167480468749 +0.210875 -0.31292724609375 -0.46087646484375 0.3209167480468749 +0.211 -0.314300537109375 -0.462890625 0.3209167480468749 +0.211125 -0.31561279296875 -0.464813232421875 0.3209167480468749 +0.21125 -0.31561279296875 -0.464813232421875 0.3209167480468749 +0.211375 -0.316925048828125 -0.46673583984375 0.3209167480468749 +0.2115 -0.316925048828125 -0.46673583984375 0.3209167480468749 +0.211625 -0.31817626953125 -0.46856689453125 0.3209167480468749 +0.21175 -0.31939697265625 -0.470367431640625 0.3209167480468749 +0.211875 -0.31939697265625 -0.470367431640625 0.3209167480468749 +0.212 -0.320587158203125 -0.472137451171875 0.3209167480468749 +0.212125 -0.320587158203125 -0.472137451171875 0.3209167480468749 +0.21225 -0.32171630859375 -0.47381591796875 0.3209167480468749 +0.212375 -0.322845458984375 -0.4754638671875 0.3209167480468749 +0.2125 -0.322845458984375 -0.4754638671875 0.3209167480468749 +0.212625 -0.32391357421875 -0.47705078125 0.3209167480468749 +0.21275 -0.32391357421875 -0.47705078125 0.3209167480468749 +0.212875 -0.324981689453125 -0.478607177734375 0.3209167480468749 +0.213 -0.32598876953125 -0.480072021484375 0.3209167480468749 +0.213125 -0.32598876953125 -0.480072021484375 0.3209167480468749 +0.21325 -0.32696533203125 -0.48150634765625 0.3209167480468749 +0.213375 -0.32696533203125 -0.48150634765625 0.3209167480468749 +0.2135 -0.327880859375 -0.48291015625 0.3209167480468749 +0.213625 -0.32879638671875 -0.484222412109375 0.3209167480468749 +0.21375 -0.32879638671875 -0.484222412109375 0.3209167480468749 +0.213875 -0.329681396484375 -0.485504150390625 0.3209167480468749 +0.214 -0.329681396484375 -0.485504150390625 0.3209167480468749 +0.214125 -0.33050537109375 -0.486724853515625 0.3209167480468749 +0.21425 -0.331268310546875 -0.487884521484375 0.3209167480468749 +0.214375 -0.331268310546875 -0.487884521484375 0.3209167480468749 +0.2145 -0.33203125 -0.489013671875 0.3209167480468749 +0.214625 -0.33203125 -0.489013671875 0.3209167480468749 +0.21475 -0.332763671875 -0.490081787109375 0.3209167480468749 +0.214875 -0.33343505859375 -0.4910888671875 0.3209167480468749 +0.215 -0.33343505859375 -0.4910888671875 0.3209167480468749 +0.215125 -0.3341064453125 -0.492034912109375 0.3209167480468749 +0.21525 -0.3341064453125 -0.492034912109375 0.3209167480468749 +0.215375 -0.334716796875 -0.492950439453125 0.3209167480468749 +0.2155 -0.335296630859375 -0.4937744140625 0.3209167480468749 +0.215625 -0.335296630859375 -0.4937744140625 0.3209167480468749 +0.21575 -0.3358154296875 -0.49456787109375 0.3209167480468749 +0.215875 -0.3358154296875 -0.49456787109375 0.3209167480468749 +0.216 -0.3363037109375 -0.49530029296875 0.3209167480468749 +0.216125 -0.3367919921875 -0.496002197265625 0.3209167480468749 +0.21625 -0.3367919921875 -0.496002197265625 0.3209167480468749 +0.216375 -0.33721923828125 -0.496612548828125 0.3209167480468749 +0.2165 -0.33721923828125 -0.496612548828125 0.3209167480468749 +0.216625 -0.337615966796875 -0.4971923828125 0.3209167480468749 +0.21675 -0.33795166015625 -0.497711181640625 0.3209167480468749 +0.216875 -0.33795166015625 -0.497711181640625 0.3209167480468749 +0.217 -0.338287353515625 -0.498199462890625 0.3209167480468749 +0.217125 -0.338287353515625 -0.498199462890625 0.3209167480468749 +0.21725 -0.33856201171875 -0.49859619140625 0.3209167480468749 +0.217375 -0.33880615234375 -0.49896240234375 0.3209167480468749 +0.2175 -0.33880615234375 -0.49896240234375 0.3209167480468749 +0.217625 -0.3389892578125 -0.499267578125 0.3209167480468749 +0.21775 -0.3389892578125 -0.499267578125 0.3209167480468749 +0.217875 -0.33917236328125 -0.49951171875 0.3209167480468749 +0.218 -0.33929443359375 -0.49969482421875 0.3209167480468749 +0.218125 -0.33929443359375 -0.49969482421875 0.3209167480468749 +0.21825 -0.339385986328125 -0.49981689453125 0.3209167480468749 +0.218375 -0.339385986328125 -0.49981689453125 0.3209167480468749 +0.2185 -0.339447021484375 -0.499908447265625 0.3209167480468749 +0.218625 -0.3394775390625 -0.49993896484375 0.3209167480468749 +0.21875 -0.3394775390625 -0.49993896484375 0.3209167480468749 +0.2188750000000000256 -0.339447021484375 -0.499908447265625 0.3209167480468749 +0.219 -0.339447021484375 -0.499908447265625 0.3209167480468749 +0.2191250000000000256 -0.339385986328125 -0.49981689453125 0.3209167480468749 +0.21925 -0.33929443359375 -0.49969482421875 0.3209167480468749 +0.2193750000000000256 -0.33929443359375 -0.49969482421875 0.3209167480468749 +0.2195 -0.33917236328125 -0.49951171875 0.3209167480468749 +0.2196250000000000256 -0.33917236328125 -0.49951171875 0.3209167480468749 +0.21975 -0.3389892578125 -0.499267578125 0.3209167480468749 +0.2198750000000000256 -0.33880615234375 -0.49896240234375 0.3209167480468749 +0.22 -0.33880615234375 -0.49896240234375 0.3209167480468749 +0.2201250000000000256 -0.33856201171875 -0.49859619140625 0.3209167480468749 +0.22025 -0.33856201171875 -0.49859619140625 0.3209167480468749 +0.2203750000000000256 -0.338287353515625 -0.498199462890625 0.3209167480468749 +0.2205 -0.33795166015625 -0.497711181640625 0.3209167480468749 +0.2206250000000000256 -0.33795166015625 -0.497711181640625 0.3209167480468749 +0.22075 -0.337615966796875 -0.4971923828125 0.3209167480468749 +0.2208750000000000256 -0.337615966796875 -0.4971923828125 0.3209167480468749 +0.221 -0.33721923828125 -0.496612548828125 0.3209167480468749 +0.2211250000000000256 -0.3367919921875 -0.496002197265625 0.3209167480468749 +0.22125 -0.3367919921875 -0.496002197265625 0.3209167480468749 +0.2213750000000000256 -0.3363037109375 -0.49530029296875 0.3209167480468749 +0.2215 -0.3363037109375 -0.49530029296875 0.3209167480468749 +0.2216250000000000256 -0.3358154296875 -0.49456787109375 0.3209167480468749 +0.22175 -0.335296630859375 -0.4937744140625 0.3209167480468749 +0.2218750000000000256 -0.335296630859375 -0.4937744140625 0.3209167480468749 +0.222 -0.334716796875 -0.492950439453125 0.3209167480468749 +0.2221250000000000256 -0.334716796875 -0.492950439453125 0.3209167480468749 +0.22225 -0.3341064453125 -0.492034912109375 0.3209167480468749 +0.2223750000000000256 -0.33343505859375 -0.4910888671875 0.3209167480468749 +0.2225 -0.33343505859375 -0.4910888671875 0.3209167480468749 +0.2226250000000000256 -0.332763671875 -0.490081787109375 0.3209167480468749 +0.22275 -0.332763671875 -0.490081787109375 0.3209167480468749 +0.2228750000000000256 -0.33203125 -0.489013671875 0.3209167480468749 +0.223 -0.331268310546875 -0.487884521484375 0.3209167480468749 +0.2231250000000000256 -0.331268310546875 -0.487884521484375 0.3209167480468749 +0.22325 -0.33050537109375 -0.486724853515625 0.3209167480468749 +0.2233750000000000256 -0.33050537109375 -0.486724853515625 0.3209167480468749 +0.2235 -0.329681396484375 -0.485504150390625 0.3209167480468749 +0.223625000000000032 -0.32879638671875 -0.484222412109375 0.3209167480468749 +0.22375 -0.32879638671875 -0.484222412109375 0.3209167480468749 +0.223875000000000032 -0.327880859375 -0.48291015625 0.3209167480468749 +0.224 -0.48291015625 -0.446533203125 -0.07529907226562488 +0.224125 -0.48150634765625 -0.44525146484375 -0.07529907226562488 +0.22425 -0.480072021484375 -0.44390869140625 -0.07529907226562488 +0.224375 -0.480072021484375 -0.44390869140625 -0.07529907226562488 +0.2245 -0.478607177734375 -0.442535400390625 -0.07529907226562488 +0.224625 -0.478607177734375 -0.442535400390625 -0.07529907226562488 +0.22475 -0.47705078125 -0.441131591796875 -0.07529907226562488 +0.224875 -0.4754638671875 -0.43963623046875 -0.07529907226562488 +0.225 -0.4754638671875 -0.43963623046875 -0.07529907226562488 +0.225125 -0.47381591796875 -0.438140869140625 -0.07529907226562488 +0.22525 -0.47381591796875 -0.438140869140625 -0.07529907226562488 +0.225375 -0.472137451171875 -0.436553955078125 -0.07529907226562488 +0.2255 -0.470367431640625 -0.4349365234375 -0.07529907226562488 +0.225625 -0.470367431640625 -0.4349365234375 -0.07529907226562488 +0.22575 -0.46856689453125 -0.43328857421875 -0.07529907226562488 +0.225875 -0.46856689453125 -0.43328857421875 -0.07529907226562488 +0.226 -0.46673583984375 -0.43157958984375 -0.07529907226562488 +0.226125 -0.464813232421875 -0.4298095703125 -0.07529907226562488 +0.22625 -0.464813232421875 -0.4298095703125 -0.07529907226562488 +0.226375 -0.462890625 -0.428009033203125 -0.07529907226562488 +0.2265 -0.462890625 -0.428009033203125 -0.07529907226562488 +0.226625 -0.46087646484375 -0.4261474609375 -0.07529907226562488 +0.22675 -0.458831787109375 -0.42425537109375 -0.07529907226562488 +0.226875 -0.458831787109375 -0.42425537109375 -0.07529907226562488 +0.227 -0.45672607421875 -0.42230224609375 -0.07529907226562488 +0.227125 -0.45672607421875 -0.42230224609375 -0.07529907226562488 +0.22725 -0.454559326171875 -0.420318603515625 -0.07529907226562488 +0.227375 -0.452362060546875 -0.41827392578125 -0.07529907226562488 +0.2275 -0.452362060546875 -0.41827392578125 -0.07529907226562488 +0.227625 -0.450103759765625 -0.41619873046875 -0.07529907226562488 +0.22775 -0.450103759765625 -0.41619873046875 -0.07529907226562488 +0.227875 -0.447784423828125 -0.4140625 -0.07529907226562488 +0.228 -0.4454345703125 -0.411895751953125 -0.07529907226562488 +0.228125 -0.4454345703125 -0.411895751953125 -0.07529907226562488 +0.22825 -0.44305419921875 -0.40966796875 -0.07529907226562488 +0.228375 -0.44305419921875 -0.40966796875 -0.07529907226562488 +0.2285 -0.440582275390625 -0.40740966796875 -0.07529907226562488 +0.228625 -0.438079833984375 -0.40509033203125 -0.07529907226562488 +0.22875 -0.438079833984375 -0.40509033203125 -0.07529907226562488 +0.228875 -0.435546875 -0.402740478515625 -0.07529907226562488 +0.229 -0.435546875 -0.402740478515625 -0.07529907226562488 +0.229125 -0.432952880859375 -0.40032958984375 -0.07529907226562488 +0.22925 -0.4302978515625 -0.39788818359375 -0.07529907226562488 +0.229375 -0.4302978515625 -0.39788818359375 -0.07529907226562488 +0.2295 -0.4276123046875 -0.395416259765625 -0.07529907226562488 +0.229625 -0.4276123046875 -0.395416259765625 -0.07529907226562488 +0.22975 -0.424896240234375 -0.39288330078125 -0.07529907226562488 +0.229875 -0.422119140625 -0.39031982421875 -0.07529907226562488 +0.23 -0.422119140625 -0.39031982421875 -0.07529907226562488 +0.230125 -0.419281005859375 -0.3876953125 -0.07529907226562488 +0.23025 -0.419281005859375 -0.3876953125 -0.07529907226562488 +0.230375 -0.416412353515625 -0.385040283203125 -0.07529907226562488 +0.2305 -0.413482666015625 -0.38232421875 -0.07529907226562488 +0.230625 -0.413482666015625 -0.38232421875 -0.07529907226562488 +0.23075 -0.4105224609375 -0.37957763671875 -0.07529907226562488 +0.230875 -0.4105224609375 -0.37957763671875 -0.07529907226562488 +0.231 -0.407501220703125 -0.376800537109375 -0.07529907226562488 +0.231125 -0.404449462890625 -0.373992919921875 -0.07529907226562488 +0.23125 -0.404449462890625 -0.373992919921875 -0.07529907226562488 +0.231375 -0.401336669921875 -0.371124267578125 -0.07529907226562488 +0.2315 -0.401336669921875 -0.371124267578125 -0.07529907226562488 +0.231625 -0.398193359375 -0.368194580078125 -0.07529907226562488 +0.23175 -0.39501953125 -0.365264892578125 -0.07529907226562488 +0.231875 -0.39501953125 -0.365264892578125 -0.07529907226562488 +0.232 -0.39178466796875 -0.362274169921875 -0.07529907226562488 +0.232125 -0.39178466796875 -0.362274169921875 -0.07529907226562488 +0.23225 -0.388519287109375 -0.3592529296875 -0.07529907226562488 +0.232375 -0.38519287109375 -0.356170654296875 -0.07529907226562488 +0.2325 -0.38519287109375 -0.356170654296875 -0.07529907226562488 +0.232625 -0.3818359375 -0.35308837890625 -0.07529907226562488 +0.23275 -0.3818359375 -0.35308837890625 -0.07529907226562488 +0.232875 -0.378448486328125 -0.349945068359375 -0.07529907226562488 +0.233 -0.375 -0.34674072265625 -0.07529907226562488 +0.233125 -0.375 -0.34674072265625 -0.07529907226562488 +0.23325 -0.37152099609375 -0.343536376953125 -0.07529907226562488 +0.233375 -0.37152099609375 -0.343536376953125 -0.07529907226562488 +0.2335 -0.36798095703125 -0.34027099609375 -0.07529907226562488 +0.233625 -0.36444091796875 -0.33697509765625 -0.07529907226562488 +0.23375 -0.36444091796875 -0.33697509765625 -0.07529907226562488 +0.233875 -0.360809326171875 -0.333648681640625 -0.07529907226562488 +0.234 -0.360809326171875 -0.333648681640625 -0.07529907226562488 +0.234125 -0.357177734375 -0.330291748046875 -0.07529907226562488 +0.23425 -0.353485107421875 -0.326873779296875 -0.07529907226562488 +0.234375 -0.353485107421875 -0.326873779296875 -0.07529907226562488 +0.234500000000000026 -0.349761962890625 -0.32342529296875 -0.07529907226562488 +0.234625 -0.349761962890625 -0.32342529296875 -0.07529907226562488 +0.234750000000000026 -0.34600830078125 -0.3199462890625 -0.07529907226562488 +0.234875 -0.34222412109375 -0.316436767578125 -0.07529907226562488 +0.235000000000000026 -0.34222412109375 -0.316436767578125 -0.07529907226562488 +0.235125 -0.33837890625 -0.312896728515625 -0.07529907226562488 +0.235250000000000026 -0.33837890625 -0.312896728515625 -0.07529907226562488 +0.235375 -0.334503173828125 -0.309326171875 -0.07529907226562488 +0.235500000000000026 -0.330596923828125 -0.305694580078125 -0.07529907226562488 +0.235625 -0.330596923828125 -0.305694580078125 -0.07529907226562488 +0.235750000000000026 -0.32666015625 -0.30206298828125 -0.07529907226562488 +0.235875 -0.32666015625 -0.30206298828125 -0.07529907226562488 +0.236000000000000026 -0.322662353515625 -0.298370361328125 -0.07529907226562488 +0.236125 -0.31866455078125 -0.294647216796875 -0.07529907226562488 +0.236250000000000026 -0.31866455078125 -0.294647216796875 -0.07529907226562488 +0.236375 -0.314605712890625 -0.2908935546875 -0.07529907226562488 +0.236500000000000026 -0.314605712890625 -0.2908935546875 -0.07529907226562488 +0.236625 -0.310516357421875 -0.287139892578125 -0.07529907226562488 +0.236750000000000026 -0.306396484375 -0.2833251953125 -0.07529907226562488 +0.236875 -0.306396484375 -0.2833251953125 -0.07529907226562488 +0.237000000000000026 -0.30224609375 -0.27947998046875 -0.07529907226562488 +0.237125 -0.30224609375 -0.27947998046875 -0.07529907226562488 +0.237250000000000026 -0.298065185546875 -0.275604248046875 -0.07529907226562488 +0.237375 -0.2938232421875 -0.271697998046875 -0.07529907226562488 +0.237500000000000026 -0.2938232421875 -0.271697998046875 -0.07529907226562488 +0.237625 -0.289581298828125 -0.267791748046875 -0.07529907226562488 +0.237750000000000026 -0.289581298828125 -0.267791748046875 -0.07529907226562488 +0.237875 -0.285308837890625 -0.263824462890625 -0.07529907226562488 +0.238000000000000026 -0.280975341796875 -0.25982666015625 -0.07529907226562488 +0.238125 -0.280975341796875 -0.25982666015625 -0.07529907226562488 +0.238250000000000026 -0.276641845703125 -0.25579833984375 -0.07529907226562488 +0.238375 -0.276641845703125 -0.25579833984375 -0.07529907226562488 +0.238500000000000026 -0.27227783203125 -0.25177001953125 -0.07529907226562488 +0.238625 -0.267852783203125 -0.2476806640625 -0.07529907226562488 +0.238750000000000026 -0.267852783203125 -0.2476806640625 -0.07529907226562488 +0.238875 -0.263427734375 -0.24359130859375 -0.07529907226562488 +0.239000000000000026 -0.263427734375 -0.24359130859375 -0.07529907226562488 +0.239125 -0.25897216796875 -0.239471435546875 -0.07529907226562488 +0.239250000000000032 -0.25445556640625 -0.23529052734375 -0.07529907226562488 +0.239375 -0.25445556640625 -0.23529052734375 -0.07529907226562488 +0.239500000000000032 -0.249969482421875 -0.23114013671875 -0.07529907226562488 +0.239625 -0.249969482421875 -0.23114013671875 -0.07529907226562488 +0.239750000000000032 -0.24542236328125 -0.2269287109375 -0.07529907226562488 +0.239875 -0.2408447265625 -0.222686767578125 -0.07529907226562488 +0.24 -0.2408447265625 -0.222686767578125 -0.07529907226562488 +0.240125 -0.236236572265625 -0.21844482421875 -0.07529907226562488 +0.24025 -0.236236572265625 -0.21844482421875 -0.07529907226562488 +0.240375 -0.231597900390625 -0.214141845703125 -0.07529907226562488 +0.2405 -0.226959228515625 -0.2098388671875 -0.07529907226562488 +0.240625 -0.226959228515625 -0.2098388671875 -0.07529907226562488 +0.24075 -0.2222900390625 -0.205535888671875 -0.07529907226562488 +0.240875 -0.2222900390625 -0.205535888671875 -0.07529907226562488 +0.241 -0.21759033203125 -0.201202392578125 -0.07529907226562488 +0.241125 -0.212860107421875 -0.196807861328125 -0.07529907226562488 +0.24125 -0.212860107421875 -0.196807861328125 -0.07529907226562488 +0.241375 -0.208099365234375 -0.192413330078125 -0.07529907226562488 +0.2415 -0.208099365234375 -0.192413330078125 -0.07529907226562488 +0.241625 -0.203338623046875 -0.188018798828125 -0.07529907226562488 +0.24175 -0.19854736328125 -0.18359375 -0.07529907226562488 +0.241875 -0.19854736328125 -0.18359375 -0.07529907226562488 +0.242 -0.1937255859375 -0.179107666015625 -0.07529907226562488 +0.242125 -0.1937255859375 -0.179107666015625 -0.07529907226562488 +0.24225 -0.188873291015625 -0.174652099609375 -0.07529907226562488 +0.242375 -0.18402099609375 -0.170166015625 -0.07529907226562488 +0.2425 -0.18402099609375 -0.170166015625 -0.07529907226562488 +0.242625 -0.17913818359375 -0.1656494140625 -0.07529907226562488 +0.24275 -0.17913818359375 -0.1656494140625 -0.07529907226562488 +0.242875 -0.17425537109375 -0.1611328125 -0.07529907226562488 +0.243 -0.169342041015625 -0.156585693359375 -0.07529907226562488 +0.243125 -0.169342041015625 -0.156585693359375 -0.07529907226562488 +0.24325 -0.164398193359375 -0.152008056640625 -0.07529907226562488 +0.243375 -0.164398193359375 -0.152008056640625 -0.07529907226562488 +0.2435 -0.159454345703125 -0.147430419921875 -0.07529907226562488 +0.243625 -0.15447998046875 -0.142822265625 -0.07529907226562488 +0.24375 -0.15447998046875 -0.142822265625 -0.07529907226562488 +0.243875 -0.14947509765625 -0.138214111328125 -0.07529907226562488 +0.244 -0.14947509765625 -0.138214111328125 -0.07529907226562488 +0.244125 -0.14447021484375 -0.13360595703125 -0.07529907226562488 +0.24425 -0.13946533203125 -0.128936767578125 -0.07529907226562488 +0.244375 -0.13946533203125 -0.128936767578125 -0.07529907226562488 +0.2445 -0.134429931640625 -0.124298095703125 -0.07529907226562488 +0.244625 -0.134429931640625 -0.124298095703125 -0.07529907226562488 +0.24475 -0.129364013671875 -0.11962890625 -0.07529907226562488 +0.244875 -0.124298095703125 -0.11492919921875 -0.07529907226562488 +0.245 -0.124298095703125 -0.11492919921875 -0.07529907226562488 +0.245125 -0.119232177734375 -0.110260009765625 -0.07529907226562488 +0.24525 -0.119232177734375 -0.110260009765625 -0.07529907226562488 +0.245375 -0.1141357421875 -0.105560302734375 -0.07529907226562488 +0.2455 -0.109039306640625 -0.100830078125 -0.07529907226562488 +0.245625 -0.109039306640625 -0.100830078125 -0.07529907226562488 +0.24575 -0.103912353515625 -0.096099853515625 -0.07529907226562488 +0.245875 -0.103912353515625 -0.096099853515625 -0.07529907226562488 +0.246 -0.098785400390625 -0.091339111328125 -0.07529907226562488 +0.246125 -0.093658447265625 -0.08660888671875 -0.07529907226562488 +0.24625 -0.093658447265625 -0.08660888671875 -0.07529907226562488 +0.246375 -0.0885009765625 -0.08184814453125 -0.07529907226562488 +0.2465 -0.0885009765625 -0.08184814453125 -0.07529907226562488 +0.246625 -0.083343505859375 -0.07708740234375 -0.07529907226562488 +0.24675 -0.07818603515625 -0.072296142578125 -0.07529907226562488 +0.246875 -0.07818603515625 -0.072296142578125 -0.07529907226562488 +0.247 -0.072998046875 -0.0675048828125 -0.07529907226562488 +0.247125 -0.072998046875 -0.0675048828125 -0.07529907226562488 +0.24725 -0.06781005859375 -0.062713623046875 -0.07529907226562488 +0.247375 -0.0626220703125 -0.05792236328125 -0.07529907226562488 +0.2475 -0.0626220703125 -0.05792236328125 -0.07529907226562488 +0.247625 -0.05743408203125 -0.053131103515625 -0.07529907226562488 +0.24775 -0.05743408203125 -0.053131103515625 -0.07529907226562488 +0.247875 -0.05224609375 -0.048309326171875 -0.07529907226562488 +0.248 -0.047027587890625 -0.043487548828125 -0.07529907226562488 +0.248125 -0.047027587890625 -0.043487548828125 -0.07529907226562488 +0.24825 -0.04180908203125 -0.038665771484375 -0.07529907226562488 +0.248375 -0.04180908203125 -0.038665771484375 -0.07529907226562488 +0.2485 -0.036590576171875 -0.033843994140625 -0.07529907226562488 +0.248625 -0.0313720703125 -0.02899169921875 -0.07529907226562488 +0.24875 -0.0313720703125 -0.02899169921875 -0.07529907226562488 +0.248875 -0.026123046875 -0.024169921875 -0.07529907226562488 +0.249 -0.026123046875 -0.024169921875 -0.07529907226562488 +0.249125 -0.020904541015625 -0.01934814453125 -0.07529907226562488 +0.24925 -0.01568603515625 -0.014495849609375 -0.07529907226562488 +0.249375 -0.01568603515625 -0.014495849609375 -0.07529907226562488 +0.2495 -0.01043701171875 -0.009674072265625 -0.07529907226562488 +0.249625 -0.01043701171875 -0.009674072265625 -0.07529907226562488 +0.24975 -0.005218505859375 -0.00482177734375 -0.07529907226562488 +0.249875 0.0 0.0 -0.07529907226562488 +0.25 0.0 0.0 -0.07529907226562488 +0.250125 0.005218505859375 0.00482177734375 -0.07529907226562488 +0.25025000000000004 0.005218505859375 0.00482177734375 -0.07529907226562488 +0.250375 0.01043701171875 0.009674072265625 -0.07529907226562488 +0.2505 0.01568603515625 0.014495849609375 -0.07529907226562488 +0.250625 0.01568603515625 0.014495849609375 -0.07529907226562488 +0.25075000000000004 0.020904541015625 0.01934814453125 -0.07529907226562488 +0.250875 0.020904541015625 0.01934814453125 -0.07529907226562488 +0.251 0.026123046875 0.024169921875 -0.07529907226562488 +0.251125 0.0313720703125 0.02899169921875 -0.07529907226562488 +0.25125000000000004 0.0313720703125 0.02899169921875 -0.07529907226562488 +0.251375 0.036590576171875 0.033843994140625 -0.07529907226562488 +0.2515 0.036590576171875 0.033843994140625 -0.07529907226562488 +0.251625 0.04180908203125 0.038665771484375 -0.07529907226562488 +0.25175000000000004 0.047027587890625 0.043487548828125 -0.07529907226562488 +0.251875 0.047027587890625 0.043487548828125 -0.07529907226562488 +0.252 0.05224609375 0.048309326171875 -0.07529907226562488 +0.252125 0.05224609375 0.048309326171875 -0.07529907226562488 +0.25225000000000004 0.05743408203125 0.053131103515625 -0.07529907226562488 +0.252375 0.0626220703125 0.05792236328125 -0.07529907226562488 +0.2525 0.0626220703125 0.05792236328125 -0.07529907226562488 +0.252625 0.06781005859375 0.062713623046875 -0.07529907226562488 +0.25275000000000004 0.06781005859375 0.062713623046875 -0.07529907226562488 +0.252875 0.072998046875 0.0675048828125 -0.07529907226562488 +0.253 0.07818603515625 0.072296142578125 -0.07529907226562488 +0.253125 0.07818603515625 0.072296142578125 -0.07529907226562488 +0.25325000000000004 0.083343505859375 0.07708740234375 -0.07529907226562488 +0.253375 0.083343505859375 0.07708740234375 -0.07529907226562488 +0.2535 0.0885009765625 0.08184814453125 -0.07529907226562488 +0.253625 0.093658447265625 0.08660888671875 -0.07529907226562488 +0.25375000000000004 0.093658447265625 0.08660888671875 -0.07529907226562488 +0.253875 0.098785400390625 0.091339111328125 -0.07529907226562488 +0.254 0.098785400390625 0.091339111328125 -0.07529907226562488 +0.254125 0.103912353515625 0.096099853515625 -0.07529907226562488 +0.25425000000000004 0.109039306640625 0.100830078125 -0.07529907226562488 +0.254375 0.109039306640625 0.100830078125 -0.07529907226562488 +0.2545 0.1141357421875 0.105560302734375 -0.07529907226562488 +0.254625 0.1141357421875 0.105560302734375 -0.07529907226562488 +0.25475000000000004 0.119232177734375 0.110260009765625 -0.07529907226562488 +0.254875 0.124298095703125 0.11492919921875 -0.07529907226562488 +0.255 0.124298095703125 0.11492919921875 -0.07529907226562488 +0.255125 0.129364013671875 0.11962890625 -0.07529907226562488 +0.25525000000000004 0.129364013671875 0.11962890625 -0.07529907226562488 +0.255375 0.134429931640625 0.124298095703125 -0.07529907226562488 +0.2555 0.13946533203125 0.128936767578125 -0.07529907226562488 +0.255625 0.13946533203125 0.128936767578125 -0.07529907226562488 +0.25575000000000004 0.14447021484375 0.13360595703125 -0.07529907226562488 +0.255875 0.14447021484375 0.13360595703125 -0.07529907226562488 +0.256 0.14947509765625 0.080780029296875 -0.4595336914062502 +0.256125 0.15447998046875 0.083465576171875 -0.4595336914062502 +0.25625 0.15447998046875 0.083465576171875 -0.4595336914062502 +0.256375 0.159454345703125 0.086151123046875 -0.4595336914062502 +0.2565 0.159454345703125 0.086151123046875 -0.4595336914062502 +0.256625 0.164398193359375 0.088836669921875 -0.4595336914062502 +0.25675 0.169342041015625 0.09149169921875 -0.4595336914062502 +0.256875 0.169342041015625 0.09149169921875 -0.4595336914062502 +0.257 0.17425537109375 0.094146728515625 -0.4595336914062502 +0.257125 0.17425537109375 0.094146728515625 -0.4595336914062502 +0.25725 0.17913818359375 0.0968017578125 -0.4595336914062502 +0.257375 0.18402099609375 0.099456787109375 -0.4595336914062502 +0.2575 0.18402099609375 0.099456787109375 -0.4595336914062502 +0.257625 0.188873291015625 0.10205078125 -0.4595336914062502 +0.25775 0.188873291015625 0.10205078125 -0.4595336914062502 +0.257875 0.1937255859375 0.10467529296875 -0.4595336914062502 +0.258 0.19854736328125 0.107269287109375 -0.4595336914062502 +0.258125 0.19854736328125 0.107269287109375 -0.4595336914062502 +0.25825 0.203338623046875 0.10986328125 -0.4595336914062502 +0.258375 0.203338623046875 0.10986328125 -0.4595336914062502 +0.2585 0.208099365234375 0.112457275390625 -0.4595336914062502 +0.258625 0.212860107421875 0.115020751953125 -0.4595336914062502 +0.25875 0.212860107421875 0.115020751953125 -0.4595336914062502 +0.258875 0.21759033203125 0.117584228515625 -0.4595336914062502 +0.259 0.21759033203125 0.117584228515625 -0.4595336914062502 +0.259125 0.2222900390625 0.1201171875 -0.4595336914062502 +0.25925 0.226959228515625 0.122650146484375 -0.4595336914062502 +0.259375 0.226959228515625 0.122650146484375 -0.4595336914062502 +0.2595 0.231597900390625 0.125152587890625 -0.4595336914062502 +0.259625 0.231597900390625 0.125152587890625 -0.4595336914062502 +0.25975 0.236236572265625 0.127655029296875 -0.4595336914062502 +0.259875 0.2408447265625 0.130126953125 -0.4595336914062502 +0.26 0.2408447265625 0.130126953125 -0.4595336914062502 +0.260125 0.24542236328125 0.132598876953125 -0.4595336914062502 +0.26025 0.24542236328125 0.132598876953125 -0.4595336914062502 +0.260375 0.249969482421875 0.13507080078125 -0.4595336914062502 +0.2605 0.25445556640625 0.13751220703125 -0.4595336914062502 +0.260625 0.25445556640625 0.13751220703125 -0.4595336914062502 +0.26075 0.25897216796875 0.13995361328125 -0.4595336914062502 +0.260875 0.25897216796875 0.13995361328125 -0.4595336914062502 +0.261 0.263427734375 0.142364501953125 -0.4595336914062502 +0.261125 0.267852783203125 0.144744873046875 -0.4595336914062502 +0.26125 0.267852783203125 0.144744873046875 -0.4595336914062502 +0.261375 0.27227783203125 0.147125244140625 -0.4595336914062502 +0.2615 0.27227783203125 0.147125244140625 -0.4595336914062502 +0.261625 0.276641845703125 0.149505615234375 -0.4595336914062502 +0.26175 0.280975341796875 0.15185546875 -0.4595336914062502 +0.261875 0.280975341796875 0.15185546875 -0.4595336914062502 +0.262 0.285308837890625 0.1541748046875 -0.4595336914062502 +0.262125 0.285308837890625 0.1541748046875 -0.4595336914062502 +0.26225 0.289581298828125 0.156494140625 -0.4595336914062502 +0.262375 0.2938232421875 0.158782958984375 -0.4595336914062502 +0.2625 0.2938232421875 0.158782958984375 -0.4595336914062502 +0.262625 0.298065185546875 0.16107177734375 -0.4595336914062502 +0.26275 0.298065185546875 0.16107177734375 -0.4595336914062502 +0.262875 0.30224609375 0.163330078125 -0.4595336914062502 +0.263 0.306396484375 0.16558837890625 -0.4595336914062502 +0.263125 0.306396484375 0.16558837890625 -0.4595336914062502 +0.26325 0.310516357421875 0.167816162109375 -0.4595336914062502 +0.263375 0.310516357421875 0.167816162109375 -0.4595336914062502 +0.2635 0.314605712890625 0.170013427734375 -0.4595336914062502 +0.263625 0.31866455078125 0.172210693359375 -0.4595336914062502 +0.26375 0.31866455078125 0.172210693359375 -0.4595336914062502 +0.263875 0.322662353515625 0.17437744140625 -0.4595336914062502 +0.264 0.322662353515625 0.17437744140625 -0.4595336914062502 +0.264125 0.32666015625 0.176513671875 -0.4595336914062502 +0.26425 0.330596923828125 0.17864990234375 -0.4595336914062502 +0.264375 0.330596923828125 0.17864990234375 -0.4595336914062502 +0.2645 0.334503173828125 0.180755615234375 -0.4595336914062502 +0.264625 0.334503173828125 0.180755615234375 -0.4595336914062502 +0.26475 0.33837890625 0.182861328125 -0.4595336914062502 +0.264875 0.34222412109375 0.1849365234375 -0.4595336914062502 +0.265 0.34222412109375 0.1849365234375 -0.4595336914062502 +0.265125 0.34600830078125 0.186981201171875 -0.4595336914062502 +0.26525 0.34600830078125 0.186981201171875 -0.4595336914062502 +0.265375 0.349761962890625 0.18902587890625 -0.4595336914062502 +0.2655 0.353485107421875 0.191009521484375 -0.4595336914062502 +0.265625 0.353485107421875 0.191009521484375 -0.4595336914062502 +0.26575 0.357177734375 0.193023681640625 -0.4595336914062502 +0.26587500000000004 0.357177734375 0.193023681640625 -0.4595336914062502 +0.266 0.360809326171875 0.194976806640625 -0.4595336914062502 +0.266125 0.36444091796875 0.196929931640625 -0.4595336914062502 +0.26625 0.36444091796875 0.196929931640625 -0.4595336914062502 +0.26637500000000004 0.36798095703125 0.1988525390625 -0.4595336914062502 +0.2665 0.36798095703125 0.1988525390625 -0.4595336914062502 +0.266625 0.37152099609375 0.200775146484375 -0.4595336914062502 +0.26675 0.375 0.20263671875 -0.4595336914062502 +0.26687500000000004 0.375 0.20263671875 -0.4595336914062502 +0.267 0.378448486328125 0.204498291015625 -0.4595336914062502 +0.267125 0.378448486328125 0.204498291015625 -0.4595336914062502 +0.26725 0.3818359375 0.206329345703125 -0.4595336914062502 +0.26737500000000004 0.38519287109375 0.208160400390625 -0.4595336914062502 +0.2675 0.38519287109375 0.208160400390625 -0.4595336914062502 +0.267625 0.388519287109375 0.2099609375 -0.4595336914062502 +0.26775 0.388519287109375 0.2099609375 -0.4595336914062502 +0.26787500000000004 0.39178466796875 0.21173095703125 -0.4595336914062502 +0.268 0.39501953125 0.213470458984375 -0.4595336914062502 +0.268125 0.39501953125 0.213470458984375 -0.4595336914062502 +0.26825 0.398193359375 0.215179443359375 -0.4595336914062502 +0.26837500000000004 0.398193359375 0.215179443359375 -0.4595336914062502 +0.2685 0.401336669921875 0.216888427734375 -0.4595336914062502 +0.268625 0.404449462890625 0.21856689453125 -0.4595336914062502 +0.26875 0.404449462890625 0.21856689453125 -0.4595336914062502 +0.26887500000000004 0.407501220703125 0.22021484375 -0.4595336914062502 +0.269 0.407501220703125 0.22021484375 -0.4595336914062502 +0.269125 0.4105224609375 0.221832275390625 -0.4595336914062502 +0.26925 0.413482666015625 0.22344970703125 -0.4595336914062502 +0.26937500000000004 0.413482666015625 0.22344970703125 -0.4595336914062502 +0.2695 0.416412353515625 0.225006103515625 -0.4595336914062502 +0.269625 0.416412353515625 0.225006103515625 -0.4595336914062502 +0.26975 0.419281005859375 0.2265625 -0.4595336914062502 +0.26987500000000004 0.422119140625 0.228118896484375 -0.4595336914062502 +0.27 0.422119140625 0.228118896484375 -0.4595336914062502 +0.270125 0.424896240234375 0.2296142578125 -0.4595336914062502 +0.27025 0.424896240234375 0.2296142578125 -0.4595336914062502 +0.27037500000000004 0.4276123046875 0.2310791015625 -0.4595336914062502 +0.2705 0.4302978515625 0.2325439453125 -0.4595336914062502 +0.270625 0.4302978515625 0.2325439453125 -0.4595336914062502 +0.27075 0.432952880859375 0.233978271484375 -0.4595336914062502 +0.27087500000000004 0.432952880859375 0.233978271484375 -0.4595336914062502 +0.271 0.435546875 0.235382080078125 -0.4595336914062502 +0.271125 0.438079833984375 0.236724853515625 -0.4595336914062502 +0.27125 0.438079833984375 0.236724853515625 -0.4595336914062502 +0.27137500000000004 0.440582275390625 0.23809814453125 -0.4595336914062502 +0.2715 0.440582275390625 0.23809814453125 -0.4595336914062502 +0.271625 0.44305419921875 0.239410400390625 -0.4595336914062502 +0.27175 0.4454345703125 0.24072265625 -0.4595336914062502 +0.27187500000000004 0.4454345703125 0.24072265625 -0.4595336914062502 +0.272 0.447784423828125 0.241973876953125 -0.4595336914062502 +0.272125 0.447784423828125 0.241973876953125 -0.4595336914062502 +0.27225 0.450103759765625 0.24322509765625 -0.4595336914062502 +0.272375 0.452362060546875 0.24444580078125 -0.4595336914062502 +0.2725 0.452362060546875 0.24444580078125 -0.4595336914062502 +0.272625 0.454559326171875 0.245635986328125 -0.4595336914062502 +0.27275 0.454559326171875 0.245635986328125 -0.4595336914062502 +0.272875 0.45672607421875 0.246795654296875 -0.4595336914062502 +0.273 0.458831787109375 0.247955322265625 -0.4595336914062502 +0.273125 0.458831787109375 0.247955322265625 -0.4595336914062502 +0.27325 0.46087646484375 0.249053955078125 -0.4595336914062502 +0.273375 0.46087646484375 0.249053955078125 -0.4595336914062502 +0.2735 0.462890625 0.2501220703125 -0.4595336914062502 +0.273625 0.464813232421875 0.251190185546875 -0.4595336914062502 +0.27375 0.464813232421875 0.251190185546875 -0.4595336914062502 +0.273875 0.46673583984375 0.252227783203125 -0.4595336914062502 +0.274 0.46673583984375 0.252227783203125 -0.4595336914062502 +0.274125 0.46856689453125 0.253204345703125 -0.4595336914062502 +0.27425 0.470367431640625 0.254180908203125 -0.4595336914062502 +0.274375 0.470367431640625 0.254180908203125 -0.4595336914062502 +0.2745 0.472137451171875 0.255126953125 -0.4595336914062502 +0.274625 0.472137451171875 0.255126953125 -0.4595336914062502 +0.27475 0.47381591796875 0.25604248046875 -0.4595336914062502 +0.274875 0.4754638671875 0.256927490234375 -0.4595336914062502 +0.275 0.4754638671875 0.256927490234375 -0.4595336914062502 +0.275125 0.47705078125 0.257781982421875 -0.4595336914062502 +0.27525 0.47705078125 0.257781982421875 -0.4595336914062502 +0.275375 0.478607177734375 0.258636474609375 -0.4595336914062502 +0.2755 0.480072021484375 0.259429931640625 -0.4595336914062502 +0.275625 0.480072021484375 0.259429931640625 -0.4595336914062502 +0.27575 0.48150634765625 0.26019287109375 -0.4595336914062502 +0.275875 0.48150634765625 0.26019287109375 -0.4595336914062502 +0.276 0.48291015625 0.260955810546875 -0.4595336914062502 +0.276125 0.484222412109375 0.26165771484375 -0.4595336914062502 +0.27625 0.484222412109375 0.26165771484375 -0.4595336914062502 +0.276375 0.485504150390625 0.262359619140625 -0.4595336914062502 +0.2765 0.485504150390625 0.262359619140625 -0.4595336914062502 +0.276625 0.486724853515625 0.263031005859375 -0.4595336914062502 +0.27675 0.487884521484375 0.263641357421875 -0.4595336914062502 +0.276875 0.487884521484375 0.263641357421875 -0.4595336914062502 +0.277 0.489013671875 0.264251708984375 -0.4595336914062502 +0.277125 0.489013671875 0.264251708984375 -0.4595336914062502 +0.27725 0.490081787109375 0.26483154296875 -0.4595336914062502 +0.277375 0.4910888671875 0.265380859375 -0.4595336914062502 +0.2775 0.4910888671875 0.265380859375 -0.4595336914062502 +0.277625 0.492034912109375 0.265899658203125 -0.4595336914062502 +0.27775 0.492034912109375 0.265899658203125 -0.4595336914062502 +0.277875 0.492950439453125 0.266387939453125 -0.4595336914062502 +0.278 0.4937744140625 0.266845703125 -0.4595336914062502 +0.278125 0.4937744140625 0.266845703125 -0.4595336914062502 +0.27825 0.49456787109375 0.26727294921875 -0.4595336914062502 +0.278375 0.49456787109375 0.26727294921875 -0.4595336914062502 +0.2785 0.49530029296875 0.267669677734375 -0.4595336914062502 +0.278625 0.496002197265625 0.268035888671875 -0.4595336914062502 +0.27875 0.496002197265625 0.268035888671875 -0.4595336914062502 +0.278875 0.496612548828125 0.26837158203125 -0.4595336914062502 +0.279 0.496612548828125 0.26837158203125 -0.4595336914062502 +0.279125 0.4971923828125 0.2686767578125 -0.4595336914062502 +0.27925 0.497711181640625 0.268951416015625 -0.4595336914062502 +0.279375 0.497711181640625 0.268951416015625 -0.4595336914062502 +0.2795 0.498199462890625 0.26922607421875 -0.4595336914062502 +0.279625 0.498199462890625 0.26922607421875 -0.4595336914062502 +0.27975 0.49859619140625 0.269439697265625 -0.4595336914062502 +0.279875 0.49896240234375 0.269622802734375 -0.4595336914062502 +0.28 0.49896240234375 0.269622802734375 -0.4595336914062502 +0.280125 0.499267578125 0.269805908203125 -0.4595336914062502 +0.28025 0.499267578125 0.269805908203125 -0.4595336914062502 +0.280375 0.49951171875 0.269927978515625 -0.4595336914062502 +0.2805 0.49969482421875 0.27001953125 -0.4595336914062502 +0.280625 0.49969482421875 0.27001953125 -0.4595336914062502 +0.28075 0.49981689453125 0.270111083984375 -0.4595336914062502 +0.280875 0.49981689453125 0.270111083984375 -0.4595336914062502 +0.281 0.499908447265625 0.2701416015625 -0.4595336914062502 +0.281125 0.49993896484375 0.270172119140625 -0.4595336914062502 +0.28125 0.49993896484375 0.270172119140625 -0.4595336914062502 +0.281375 0.499908447265625 0.2701416015625 -0.4595336914062502 +0.28150000000000004 0.499908447265625 0.2701416015625 -0.4595336914062502 +0.281625 0.49981689453125 0.270111083984375 -0.4595336914062502 +0.28175 0.49969482421875 0.27001953125 -0.4595336914062502 +0.281875 0.49969482421875 0.27001953125 -0.4595336914062502 +0.28200000000000004 0.49951171875 0.269927978515625 -0.4595336914062502 +0.282125 0.49951171875 0.269927978515625 -0.4595336914062502 +0.28225 0.499267578125 0.269805908203125 -0.4595336914062502 +0.282375 0.49896240234375 0.269622802734375 -0.4595336914062502 +0.28250000000000004 0.49896240234375 0.269622802734375 -0.4595336914062502 +0.282625 0.49859619140625 0.269439697265625 -0.4595336914062502 +0.28275 0.49859619140625 0.269439697265625 -0.4595336914062502 +0.282875 0.498199462890625 0.26922607421875 -0.4595336914062502 +0.28300000000000004 0.497711181640625 0.268951416015625 -0.4595336914062502 +0.283125 0.497711181640625 0.268951416015625 -0.4595336914062502 +0.28325 0.4971923828125 0.2686767578125 -0.4595336914062502 +0.283375 0.4971923828125 0.2686767578125 -0.4595336914062502 +0.28350000000000004 0.496612548828125 0.26837158203125 -0.4595336914062502 +0.283625 0.496002197265625 0.268035888671875 -0.4595336914062502 +0.28375 0.496002197265625 0.268035888671875 -0.4595336914062502 +0.283875 0.49530029296875 0.267669677734375 -0.4595336914062502 +0.28400000000000004 0.49530029296875 0.267669677734375 -0.4595336914062502 +0.284125 0.49456787109375 0.26727294921875 -0.4595336914062502 +0.28425 0.4937744140625 0.266845703125 -0.4595336914062502 +0.284375 0.4937744140625 0.266845703125 -0.4595336914062502 +0.28450000000000004 0.492950439453125 0.266387939453125 -0.4595336914062502 +0.284625 0.492950439453125 0.266387939453125 -0.4595336914062502 +0.28475 0.492034912109375 0.265899658203125 -0.4595336914062502 +0.284875 0.4910888671875 0.265380859375 -0.4595336914062502 +0.28500000000000004 0.4910888671875 0.265380859375 -0.4595336914062502 +0.285125 0.490081787109375 0.26483154296875 -0.4595336914062502 +0.28525 0.490081787109375 0.26483154296875 -0.4595336914062502 +0.285375 0.489013671875 0.264251708984375 -0.4595336914062502 +0.28550000000000004 0.487884521484375 0.263641357421875 -0.4595336914062502 +0.285625 0.487884521484375 0.263641357421875 -0.4595336914062502 +0.28575 0.486724853515625 0.263031005859375 -0.4595336914062502 +0.285875 0.486724853515625 0.263031005859375 -0.4595336914062502 +0.28600000000000004 0.485504150390625 0.262359619140625 -0.4595336914062502 +0.286125 0.484222412109375 0.26165771484375 -0.4595336914062502 +0.28625 0.484222412109375 0.26165771484375 -0.4595336914062502 +0.286375 0.48291015625 0.260955810546875 -0.4595336914062502 +0.28650000000000004 0.48291015625 0.260955810546875 -0.4595336914062502 +0.286625 0.48150634765625 0.26019287109375 -0.4595336914062502 +0.28675 0.480072021484375 0.259429931640625 -0.4595336914062502 +0.286875 0.480072021484375 0.259429931640625 -0.4595336914062502 +0.28700000000000004 0.478607177734375 0.258636474609375 -0.4595336914062502 +0.287125 0.478607177734375 0.258636474609375 -0.4595336914062502 +0.28725 0.47705078125 0.257781982421875 -0.4595336914062502 +0.287375 0.4754638671875 0.256927490234375 -0.4595336914062502 +0.28750000000000004 0.4754638671875 0.256927490234375 -0.4595336914062502 +0.287625 0.47381591796875 0.25604248046875 -0.4595336914062502 +0.28775 0.47381591796875 0.25604248046875 -0.4595336914062502 +0.287875 0.472137451171875 0.255126953125 -0.4595336914062502 +0.28800000000000004 0.470367431640625 0.10791015625 -0.7704772949218753 +0.288125 0.470367431640625 0.10791015625 -0.7704772949218753 +0.28825 0.46856689453125 0.107513427734375 -0.7704772949218753 +0.288375 0.46856689453125 0.107513427734375 -0.7704772949218753 +0.2885 0.46673583984375 0.107086181640625 -0.7704772949218753 +0.288625 0.464813232421875 0.10662841796875 -0.7704772949218753 +0.28875 0.464813232421875 0.10662841796875 -0.7704772949218753 +0.288875 0.462890625 0.106201171875 -0.7704772949218753 +0.289 0.462890625 0.106201171875 -0.7704772949218753 +0.289125 0.46087646484375 0.105743408203125 -0.7704772949218753 +0.28925 0.458831787109375 0.105255126953125 -0.7704772949218753 +0.289375 0.458831787109375 0.105255126953125 -0.7704772949218753 +0.2895 0.45672607421875 0.104766845703125 -0.7704772949218753 +0.289625 0.45672607421875 0.104766845703125 -0.7704772949218753 +0.28975 0.454559326171875 0.104278564453125 -0.7704772949218753 +0.289875 0.452362060546875 0.103790283203125 -0.7704772949218753 +0.29 0.452362060546875 0.103790283203125 -0.7704772949218753 +0.290125 0.450103759765625 0.103271484375 -0.7704772949218753 +0.29025 0.450103759765625 0.103271484375 -0.7704772949218753 +0.290375 0.447784423828125 0.10272216796875 -0.7704772949218753 +0.2905 0.4454345703125 0.102203369140625 -0.7704772949218753 +0.290625 0.4454345703125 0.102203369140625 -0.7704772949218753 +0.29075 0.44305419921875 0.101654052734375 -0.7704772949218753 +0.290875 0.44305419921875 0.101654052734375 -0.7704772949218753 +0.291 0.440582275390625 0.10107421875 -0.7704772949218753 +0.291125 0.438079833984375 0.100494384765625 -0.7704772949218753 +0.29125 0.438079833984375 0.100494384765625 -0.7704772949218753 +0.291375 0.435546875 0.09991455078125 -0.7704772949218753 +0.2915 0.435546875 0.09991455078125 -0.7704772949218753 +0.291625 0.432952880859375 0.099334716796875 -0.7704772949218753 +0.29175 0.4302978515625 0.098724365234375 -0.7704772949218753 +0.291875 0.4302978515625 0.098724365234375 -0.7704772949218753 +0.292 0.4276123046875 0.098114013671875 -0.7704772949218753 +0.292125 0.4276123046875 0.098114013671875 -0.7704772949218753 +0.29225 0.424896240234375 0.09747314453125 -0.7704772949218753 +0.292375 0.422119140625 0.096832275390625 -0.7704772949218753 +0.2925 0.422119140625 0.096832275390625 -0.7704772949218753 +0.292625 0.419281005859375 0.09619140625 -0.7704772949218753 +0.29275 0.419281005859375 0.09619140625 -0.7704772949218753 +0.292875 0.416412353515625 0.09552001953125 -0.7704772949218753 +0.293 0.413482666015625 0.0948486328125 -0.7704772949218753 +0.293125 0.413482666015625 0.0948486328125 -0.7704772949218753 +0.29325 0.4105224609375 0.09417724609375 -0.7704772949218753 +0.293375 0.4105224609375 0.09417724609375 -0.7704772949218753 +0.2935 0.407501220703125 0.093475341796875 -0.7704772949218753 +0.293625 0.404449462890625 0.0927734375 -0.7704772949218753 +0.29375 0.404449462890625 0.0927734375 -0.7704772949218753 +0.293875 0.401336669921875 0.092071533203125 -0.7704772949218753 +0.294 0.401336669921875 0.092071533203125 -0.7704772949218753 +0.294125 0.398193359375 0.091339111328125 -0.7704772949218753 +0.29425 0.39501953125 0.09063720703125 -0.7704772949218753 +0.294375 0.39501953125 0.09063720703125 -0.7704772949218753 +0.2945 0.39178466796875 0.089874267578125 -0.7704772949218753 +0.294625 0.39178466796875 0.089874267578125 -0.7704772949218753 +0.29475 0.388519287109375 0.089141845703125 -0.7704772949218753 +0.294875 0.38519287109375 0.08837890625 -0.7704772949218753 +0.295 0.38519287109375 0.08837890625 -0.7704772949218753 +0.295125 0.3818359375 0.08758544921875 -0.7704772949218753 +0.29525 0.3818359375 0.08758544921875 -0.7704772949218753 +0.295375 0.378448486328125 0.086822509765625 -0.7704772949218753 +0.2955 0.375 0.086029052734375 -0.7704772949218753 +0.295625 0.375 0.086029052734375 -0.7704772949218753 +0.29575 0.37152099609375 0.085235595703125 -0.7704772949218753 +0.295875 0.37152099609375 0.085235595703125 -0.7704772949218753 +0.296 0.36798095703125 0.08441162109375 -0.7704772949218753 +0.296125 0.36444091796875 0.0836181640625 -0.7704772949218753 +0.29625 0.36444091796875 0.0836181640625 -0.7704772949218753 +0.296375 0.360809326171875 0.082763671875 -0.7704772949218753 +0.2965 0.360809326171875 0.082763671875 -0.7704772949218753 +0.296625 0.357177734375 0.081939697265625 -0.7704772949218753 +0.29675 0.353485107421875 0.081085205078125 -0.7704772949218753 +0.296875 0.353485107421875 0.081085205078125 -0.7704772949218753 +0.297 0.349761962890625 0.080230712890625 -0.7704772949218753 +0.29712500000000004 0.349761962890625 0.080230712890625 -0.7704772949218753 +0.29725 0.34600830078125 0.079376220703125 -0.7704772949218753 +0.297375 0.34222412109375 0.078521728515625 -0.7704772949218753 +0.2975 0.34222412109375 0.078521728515625 -0.7704772949218753 +0.29762500000000004 0.33837890625 0.07763671875 -0.7704772949218753 +0.29775 0.33837890625 0.07763671875 -0.7704772949218753 +0.297875 0.334503173828125 0.076751708984375 -0.7704772949218753 +0.298 0.330596923828125 0.075836181640625 -0.7704772949218753 +0.29812500000000004 0.330596923828125 0.075836181640625 -0.7704772949218753 +0.29825 0.32666015625 0.074951171875 -0.7704772949218753 +0.298375 0.32666015625 0.074951171875 -0.7704772949218753 +0.2985 0.322662353515625 0.07403564453125 -0.7704772949218753 +0.29862500000000004 0.31866455078125 0.073089599609375 -0.7704772949218753 +0.29875 0.31866455078125 0.073089599609375 -0.7704772949218753 +0.298875 0.314605712890625 0.072174072265625 -0.7704772949218753 +0.299 0.314605712890625 0.072174072265625 -0.7704772949218753 +0.29912500000000004 0.310516357421875 0.07122802734375 -0.7704772949218753 +0.29925 0.306396484375 0.070281982421875 -0.7704772949218753 +0.299375 0.306396484375 0.070281982421875 -0.7704772949218753 +0.2995 0.30224609375 0.0693359375 -0.7704772949218753 +0.29962500000000004 0.30224609375 0.0693359375 -0.7704772949218753 +0.29975 0.298065185546875 0.068389892578125 -0.7704772949218753 +0.299875 0.2938232421875 0.067413330078125 -0.7704772949218753 +0.3 0.2938232421875 0.067413330078125 -0.7704772949218753 +0.30012500000000004 0.289581298828125 0.066436767578125 -0.7704772949218753 +0.30025 0.289581298828125 0.066436767578125 -0.7704772949218753 +0.300375 0.285308837890625 0.065460205078125 -0.7704772949218753 +0.3005 0.280975341796875 0.064453125 -0.7704772949218753 +0.30062500000000004 0.280975341796875 0.064453125 -0.7704772949218753 +0.30075 0.276641845703125 0.0634765625 -0.7704772949218753 +0.300875 0.276641845703125 0.0634765625 -0.7704772949218753 +0.301 0.27227783203125 0.062469482421875 -0.7704772949218753 +0.30112500000000004 0.267852783203125 0.06146240234375 -0.7704772949218753 +0.30125 0.267852783203125 0.06146240234375 -0.7704772949218753 +0.301375 0.263427734375 0.0604248046875 -0.7704772949218753 +0.3015 0.263427734375 0.0604248046875 -0.7704772949218753 +0.30162500000000004 0.25897216796875 0.059417724609375 -0.7704772949218753 +0.30175 0.25445556640625 0.058380126953125 -0.7704772949218753 +0.301875 0.25445556640625 0.058380126953125 -0.7704772949218753 +0.302 0.249969482421875 0.057342529296875 -0.7704772949218753 +0.30212500000000004 0.249969482421875 0.057342529296875 -0.7704772949218753 +0.30225 0.24542236328125 0.056304931640625 -0.7704772949218753 +0.302375 0.2408447265625 0.05523681640625 -0.7704772949218753 +0.3025 0.2408447265625 0.05523681640625 -0.7704772949218753 +0.30262500000000004 0.236236572265625 0.05419921875 -0.7704772949218753 +0.30275 0.236236572265625 0.05419921875 -0.7704772949218753 +0.302875 0.231597900390625 0.053131103515625 -0.7704772949218753 +0.303 0.226959228515625 0.05206298828125 -0.7704772949218753 +0.30312500000000004 0.226959228515625 0.05206298828125 -0.7704772949218753 +0.30325 0.2222900390625 0.050994873046875 -0.7704772949218753 +0.303375 0.2222900390625 0.050994873046875 -0.7704772949218753 +0.3035 0.21759033203125 0.049896240234375 -0.7704772949218753 +0.30362500000000004 0.212860107421875 0.048828125 -0.7704772949218753 +0.30375 0.212860107421875 0.048828125 -0.7704772949218753 +0.303875 0.208099365234375 0.0477294921875 -0.7704772949218753 +0.304 0.208099365234375 0.0477294921875 -0.7704772949218753 +0.304125 0.203338623046875 0.046630859375 -0.7704772949218753 +0.30425 0.19854736328125 0.0455322265625 -0.7704772949218753 +0.304375 0.19854736328125 0.0455322265625 -0.7704772949218753 +0.3045 0.1937255859375 0.04443359375 -0.7704772949218753 +0.304625 0.1937255859375 0.04443359375 -0.7704772949218753 +0.30475 0.188873291015625 0.0433349609375 -0.7704772949218753 +0.304875 0.18402099609375 0.042205810546875 -0.7704772949218753 +0.305 0.18402099609375 0.042205810546875 -0.7704772949218753 +0.305125 0.17913818359375 0.04107666015625 -0.7704772949218753 +0.30525 0.17913818359375 0.04107666015625 -0.7704772949218753 +0.305375 0.17425537109375 0.03997802734375 -0.7704772949218753 +0.3055 0.169342041015625 0.038848876953125 -0.7704772949218753 +0.305625 0.169342041015625 0.038848876953125 -0.7704772949218753 +0.30575 0.164398193359375 0.0377197265625 -0.7704772949218753 +0.305875 0.164398193359375 0.0377197265625 -0.7704772949218753 +0.306 0.159454345703125 0.03656005859375 -0.7704772949218753 +0.306125 0.15447998046875 0.035430908203125 -0.7704772949218753 +0.30625 0.15447998046875 0.035430908203125 -0.7704772949218753 +0.306375 0.14947509765625 0.034271240234375 -0.7704772949218753 +0.3065 0.14947509765625 0.034271240234375 -0.7704772949218753 +0.306625 0.14447021484375 0.03314208984375 -0.7704772949218753 +0.30675 0.13946533203125 0.031982421875 -0.7704772949218753 +0.306875 0.13946533203125 0.031982421875 -0.7704772949218753 +0.307 0.134429931640625 0.03082275390625 -0.7704772949218753 +0.307125 0.134429931640625 0.03082275390625 -0.7704772949218753 +0.30725 0.129364013671875 0.0296630859375 -0.7704772949218753 +0.307375 0.124298095703125 0.02850341796875 -0.7704772949218753 +0.3075 0.124298095703125 0.02850341796875 -0.7704772949218753 +0.307625 0.119232177734375 0.02734375 -0.7704772949218753 +0.30775 0.119232177734375 0.02734375 -0.7704772949218753 +0.307875 0.1141357421875 0.02618408203125 -0.7704772949218753 +0.308 0.109039306640625 0.024993896484375 -0.7704772949218753 +0.308125 0.109039306640625 0.024993896484375 -0.7704772949218753 +0.30825 0.103912353515625 0.023834228515625 -0.7704772949218753 +0.308375 0.103912353515625 0.023834228515625 -0.7704772949218753 +0.3085 0.098785400390625 0.02264404296875 -0.7704772949218753 +0.308625 0.093658447265625 0.021484375 -0.7704772949218753 +0.30875 0.093658447265625 0.021484375 -0.7704772949218753 +0.308875 0.0885009765625 0.020294189453125 -0.7704772949218753 +0.309 0.0885009765625 0.020294189453125 -0.7704772949218753 +0.309125 0.083343505859375 0.01910400390625 -0.7704772949218753 +0.30925 0.07818603515625 0.017913818359375 -0.7704772949218753 +0.309375 0.07818603515625 0.017913818359375 -0.7704772949218753 +0.3095 0.072998046875 0.016754150390625 -0.7704772949218753 +0.309625 0.072998046875 0.016754150390625 -0.7704772949218753 +0.30975 0.06781005859375 0.01556396484375 -0.7704772949218753 +0.309875 0.0626220703125 0.014373779296875 -0.7704772949218753 +0.31 0.0626220703125 0.014373779296875 -0.7704772949218753 +0.310125 0.05743408203125 0.01318359375 -0.7704772949218753 +0.31025 0.05743408203125 0.01318359375 -0.7704772949218753 +0.310375 0.05224609375 0.011962890625 -0.7704772949218753 +0.3105 0.047027587890625 0.010772705078125 -0.7704772949218753 +0.310625 0.047027587890625 0.010772705078125 -0.7704772949218753 +0.31075 0.04180908203125 0.00958251953125 -0.7704772949218753 +0.310875 0.04180908203125 0.00958251953125 -0.7704772949218753 +0.311 0.036590576171875 0.008392333984375 -0.7704772949218753 +0.311125 0.0313720703125 0.007171630859375 -0.7704772949218753 +0.31125 0.0313720703125 0.007171630859375 -0.7704772949218753 +0.311375 0.026123046875 0.0059814453125 -0.7704772949218753 +0.3115 0.026123046875 0.0059814453125 -0.7704772949218753 +0.311625 0.020904541015625 0.004791259765625 -0.7704772949218753 +0.31175 0.01568603515625 0.00360107421875 -0.7704772949218753 +0.311875 0.01568603515625 0.00360107421875 -0.7704772949218753 +0.312 0.01043701171875 0.00238037109375 -0.7704772949218753 +0.312125 0.01043701171875 0.00238037109375 -0.7704772949218753 +0.31225 0.005218505859375 0.001190185546875 -0.7704772949218753 +0.312375 0.0 0.0 -0.7704772949218753 +0.3125 0.0 0.0 -0.7704772949218753 +0.312625 -0.005218505859375 -0.001190185546875 -0.7704772949218753 +0.31275000000000004 -0.005218505859375 -0.001190185546875 -0.7704772949218753 +0.312875 -0.01043701171875 -0.00238037109375 -0.7704772949218753 +0.313 -0.01568603515625 -0.00360107421875 -0.7704772949218753 +0.313125 -0.01568603515625 -0.00360107421875 -0.7704772949218753 +0.31325000000000004 -0.020904541015625 -0.004791259765625 -0.7704772949218753 +0.313375 -0.020904541015625 -0.004791259765625 -0.7704772949218753 +0.3135 -0.026123046875 -0.0059814453125 -0.7704772949218753 +0.313625 -0.0313720703125 -0.007171630859375 -0.7704772949218753 +0.31375000000000004 -0.0313720703125 -0.007171630859375 -0.7704772949218753 +0.313875 -0.036590576171875 -0.008392333984375 -0.7704772949218753 +0.314 -0.036590576171875 -0.008392333984375 -0.7704772949218753 +0.314125 -0.04180908203125 -0.00958251953125 -0.7704772949218753 +0.31425000000000004 -0.047027587890625 -0.010772705078125 -0.7704772949218753 +0.314375 -0.047027587890625 -0.010772705078125 -0.7704772949218753 +0.3145 -0.05224609375 -0.011962890625 -0.7704772949218753 +0.314625 -0.05224609375 -0.011962890625 -0.7704772949218753 +0.31475000000000004 -0.05743408203125 -0.01318359375 -0.7704772949218753 +0.314875 -0.0626220703125 -0.014373779296875 -0.7704772949218753 +0.315 -0.0626220703125 -0.014373779296875 -0.7704772949218753 +0.315125 -0.06781005859375 -0.01556396484375 -0.7704772949218753 +0.31525000000000004 -0.06781005859375 -0.01556396484375 -0.7704772949218753 +0.315375 -0.072998046875 -0.016754150390625 -0.7704772949218753 +0.3155 -0.07818603515625 -0.017913818359375 -0.7704772949218753 +0.315625 -0.07818603515625 -0.017913818359375 -0.7704772949218753 +0.31575000000000004 -0.083343505859375 -0.01910400390625 -0.7704772949218753 +0.315875 -0.083343505859375 -0.01910400390625 -0.7704772949218753 +0.316 -0.0885009765625 -0.020294189453125 -0.7704772949218753 +0.316125 -0.093658447265625 -0.021484375 -0.7704772949218753 +0.31625000000000004 -0.093658447265625 -0.021484375 -0.7704772949218753 +0.316375 -0.098785400390625 -0.02264404296875 -0.7704772949218753 +0.3165 -0.098785400390625 -0.02264404296875 -0.7704772949218753 +0.316625 -0.103912353515625 -0.023834228515625 -0.7704772949218753 +0.31675000000000004 -0.109039306640625 -0.024993896484375 -0.7704772949218753 +0.316875 -0.109039306640625 -0.024993896484375 -0.7704772949218753 +0.317 -0.1141357421875 -0.02618408203125 -0.7704772949218753 +0.317125 -0.1141357421875 -0.02618408203125 -0.7704772949218753 +0.31725000000000004 -0.119232177734375 -0.02734375 -0.7704772949218753 +0.317375 -0.124298095703125 -0.02850341796875 -0.7704772949218753 +0.3175 -0.124298095703125 -0.02850341796875 -0.7704772949218753 +0.317625 -0.129364013671875 -0.0296630859375 -0.7704772949218753 +0.31775000000000004 -0.129364013671875 -0.0296630859375 -0.7704772949218753 +0.317875 -0.134429931640625 -0.03082275390625 -0.7704772949218753 +0.318 -0.13946533203125 -0.031982421875 -0.7704772949218753 +0.318125 -0.13946533203125 -0.031982421875 -0.7704772949218753 +0.31825000000000004 -0.14447021484375 -0.03314208984375 -0.7704772949218753 +0.318375 -0.14447021484375 -0.03314208984375 -0.7704772949218753 +0.3185 -0.14947509765625 -0.034271240234375 -0.7704772949218753 +0.318625 -0.15447998046875 -0.035430908203125 -0.7704772949218753 +0.31875000000000004 -0.15447998046875 -0.035430908203125 -0.7704772949218753 +0.318875 -0.159454345703125 -0.03656005859375 -0.7704772949218753 +0.319 -0.159454345703125 -0.03656005859375 -0.7704772949218753 +0.319125 -0.164398193359375 -0.0377197265625 -0.7704772949218753 +0.31925000000000004 -0.169342041015625 -0.038848876953125 -0.7704772949218753 +0.319375 -0.169342041015625 -0.038848876953125 -0.7704772949218753 +0.3195 -0.17425537109375 -0.03997802734375 -0.7704772949218753 +0.319625 -0.17425537109375 -0.03997802734375 -0.7704772949218753 +0.31975000000000004 -0.17913818359375 -0.04107666015625 -0.7704772949218753 +0.319875 -0.18402099609375 -0.042205810546875 -0.7704772949218753 +0.32 -0.18402099609375 -0.007598876953125 -0.9584594726562502912 +0.320125 -0.188873291015625 -0.0078125 -0.9584594726562502912 +0.32025 -0.188873291015625 -0.0078125 -0.9584594726562502912 +0.320375 -0.1937255859375 -0.008026123046875 -0.9584594726562502912 +0.3205 -0.19854736328125 -0.008209228515625 -0.9584594726562502912 +0.320625 -0.19854736328125 -0.008209228515625 -0.9584594726562502912 +0.32075 -0.203338623046875 -0.0084228515625 -0.9584594726562502912 +0.320875 -0.203338623046875 -0.0084228515625 -0.9584594726562502912 +0.321 -0.208099365234375 -0.00860595703125 -0.9584594726562502912 +0.321125 -0.212860107421875 -0.008819580078125 -0.9584594726562502912 +0.32125 -0.212860107421875 -0.008819580078125 -0.9584594726562502912 +0.321375 -0.21759033203125 -0.009002685546875 -0.9584594726562502912 +0.3215 -0.21759033203125 -0.009002685546875 -0.9584594726562502912 +0.321625 -0.2222900390625 -0.009185791015625 -0.9584594726562502912 +0.32175 -0.226959228515625 -0.0093994140625 -0.9584594726562502912 +0.321875 -0.226959228515625 -0.0093994140625 -0.9584594726562502912 +0.322 -0.231597900390625 -0.00958251953125 -0.9584594726562502912 +0.322125 -0.231597900390625 -0.00958251953125 -0.9584594726562502912 +0.32225 -0.236236572265625 -0.009765625 -0.9584594726562502912 +0.322375 -0.2408447265625 -0.009979248046875 -0.9584594726562502912 +0.3225 -0.2408447265625 -0.009979248046875 -0.9584594726562502912 +0.322625 -0.24542236328125 -0.010162353515625 -0.9584594726562502912 +0.32275 -0.24542236328125 -0.010162353515625 -0.9584594726562502912 +0.322875 -0.249969482421875 -0.010345458984375 -0.9584594726562502912 +0.323 -0.25445556640625 -0.010528564453125 -0.9584594726562502912 +0.323125 -0.25445556640625 -0.010528564453125 -0.9584594726562502912 +0.32325 -0.25897216796875 -0.010711669921875 -0.9584594726562502912 +0.323375 -0.25897216796875 -0.010711669921875 -0.9584594726562502912 +0.3235 -0.263427734375 -0.010894775390625 -0.9584594726562502912 +0.323625 -0.267852783203125 -0.011077880859375 -0.9584594726562502912 +0.32375 -0.267852783203125 -0.011077880859375 -0.9584594726562502912 +0.323875 -0.27227783203125 -0.011260986328125 -0.9584594726562502912 +0.324 -0.27227783203125 -0.011260986328125 -0.9584594726562502912 +0.324125 -0.276641845703125 -0.011444091796875 -0.9584594726562502912 +0.32425 -0.280975341796875 -0.011627197265625 -0.9584594726562502912 +0.324375 -0.280975341796875 -0.011627197265625 -0.9584594726562502912 +0.3245 -0.285308837890625 -0.011810302734375 -0.9584594726562502912 +0.324625 -0.285308837890625 -0.011810302734375 -0.9584594726562502912 +0.32475 -0.289581298828125 -0.011993408203125 -0.9584594726562502912 +0.324875 -0.2938232421875 -0.012176513671875 -0.9584594726562502912 +0.325 -0.2938232421875 -0.012176513671875 -0.9584594726562502912 +0.325125 -0.298065185546875 -0.0123291015625 -0.9584594726562502912 +0.32525 -0.298065185546875 -0.0123291015625 -0.9584594726562502912 +0.325375 -0.30224609375 -0.01251220703125 -0.9584594726562502912 +0.3255 -0.306396484375 -0.0126953125 -0.9584594726562502912 +0.325625 -0.306396484375 -0.0126953125 -0.9584594726562502912 +0.32575 -0.310516357421875 -0.012847900390625 -0.9584594726562502912 +0.325875 -0.310516357421875 -0.012847900390625 -0.9584594726562502912 +0.326 -0.314605712890625 -0.013031005859375 -0.9584594726562502912 +0.326125 -0.31866455078125 -0.01318359375 -0.9584594726562502912 +0.32625 -0.31866455078125 -0.01318359375 -0.9584594726562502912 +0.326375 -0.322662353515625 -0.01336669921875 -0.9584594726562502912 +0.3265 -0.322662353515625 -0.01336669921875 -0.9584594726562502912 +0.326625 -0.32666015625 -0.013519287109375 -0.9584594726562502912 +0.32675 -0.330596923828125 -0.013702392578125 -0.9584594726562502912 +0.326875 -0.330596923828125 -0.013702392578125 -0.9584594726562502912 +0.327 -0.334503173828125 -0.01385498046875 -0.9584594726562502912 +0.327125 -0.334503173828125 -0.01385498046875 -0.9584594726562502912 +0.32725 -0.33837890625 -0.014007568359375 -0.9584594726562502912 +0.327375 -0.34222412109375 -0.01416015625 -0.9584594726562502912 +0.3275 -0.34222412109375 -0.01416015625 -0.9584594726562502912 +0.327625 -0.34600830078125 -0.014312744140625 -0.9584594726562502912 +0.32775 -0.34600830078125 -0.014312744140625 -0.9584594726562502912 +0.327875 -0.349761962890625 -0.014495849609375 -0.9584594726562502912 +0.328 -0.353485107421875 -0.0146484375 -0.9584594726562502912 +0.328125 -0.353485107421875 -0.0146484375 -0.9584594726562502912 +0.32825 -0.357177734375 -0.014801025390625 -0.9584594726562502912 +0.32837500000000004 -0.357177734375 -0.014801025390625 -0.9584594726562502912 +0.3285 -0.360809326171875 -0.01495361328125 -0.9584594726562502912 +0.328625 -0.36444091796875 -0.01507568359375 -0.9584594726562502912 +0.32875 -0.36444091796875 -0.01507568359375 -0.9584594726562502912 +0.32887500000000004 -0.36798095703125 -0.015228271484375 -0.9584594726562502912 +0.329 -0.36798095703125 -0.015228271484375 -0.9584594726562502912 +0.329125 -0.37152099609375 -0.015380859375 -0.9584594726562502912 +0.32925 -0.375 -0.015533447265625 -0.9584594726562502912 +0.32937500000000004 -0.375 -0.015533447265625 -0.9584594726562502912 +0.3295 -0.378448486328125 -0.015655517578125 -0.9584594726562502912 +0.329625 -0.378448486328125 -0.015655517578125 -0.9584594726562502912 +0.32975 -0.3818359375 -0.01580810546875 -0.9584594726562502912 +0.32987500000000004 -0.38519287109375 -0.015960693359375 -0.9584594726562502912 +0.33 -0.38519287109375 -0.015960693359375 -0.9584594726562502912 +0.330125 -0.388519287109375 -0.016082763671875 -0.9584594726562502912 +0.33025 -0.388519287109375 -0.016082763671875 -0.9584594726562502912 +0.33037500000000004 -0.39178466796875 -0.0162353515625 -0.9584594726562502912 +0.3305 -0.39501953125 -0.016357421875 -0.9584594726562502912 +0.330625 -0.39501953125 -0.016357421875 -0.9584594726562502912 +0.33075 -0.398193359375 -0.0164794921875 -0.9584594726562502912 +0.33087500000000004 -0.398193359375 -0.0164794921875 -0.9584594726562502912 +0.331 -0.401336669921875 -0.016632080078125 -0.9584594726562502912 +0.331125 -0.404449462890625 -0.016754150390625 -0.9584594726562502912 +0.33125 -0.404449462890625 -0.016754150390625 -0.9584594726562502912 +0.33137500000000004 -0.407501220703125 -0.016876220703125 -0.9584594726562502912 +0.3315 -0.407501220703125 -0.016876220703125 -0.9584594726562502912 +0.331625 -0.4105224609375 -0.016998291015625 -0.9584594726562502912 +0.33175 -0.413482666015625 -0.017120361328125 -0.9584594726562502912 +0.33187500000000004 -0.413482666015625 -0.017120361328125 -0.9584594726562502912 +0.332 -0.416412353515625 -0.017242431640625 -0.9584594726562502912 +0.332125 -0.416412353515625 -0.017242431640625 -0.9584594726562502912 +0.33225 -0.419281005859375 -0.017364501953125 -0.9584594726562502912 +0.33237500000000004 -0.422119140625 -0.017486572265625 -0.9584594726562502912 +0.3325 -0.422119140625 -0.017486572265625 -0.9584594726562502912 +0.332625 -0.424896240234375 -0.017608642578125 -0.9584594726562502912 +0.33275 -0.424896240234375 -0.017608642578125 -0.9584594726562502912 +0.33287500000000004 -0.4276123046875 -0.0177001953125 -0.9584594726562502912 +0.333 -0.4302978515625 -0.017822265625 -0.9584594726562502912 +0.333125 -0.4302978515625 -0.017822265625 -0.9584594726562502912 +0.33325 -0.432952880859375 -0.0179443359375 -0.9584594726562502912 +0.33337500000000004 -0.432952880859375 -0.0179443359375 -0.9584594726562502912 +0.3335 -0.435546875 -0.018035888671875 -0.9584594726562502912 +0.333625 -0.438079833984375 -0.01812744140625 -0.9584594726562502912 +0.33375 -0.438079833984375 -0.01812744140625 -0.9584594726562502912 +0.33387500000000004 -0.440582275390625 -0.01824951171875 -0.9584594726562502912 +0.334 -0.440582275390625 -0.01824951171875 -0.9584594726562502912 +0.334125 -0.44305419921875 -0.018341064453125 -0.9584594726562502912 +0.33425 -0.4454345703125 -0.0184326171875 -0.9584594726562502912 +0.33437500000000004 -0.4454345703125 -0.0184326171875 -0.9584594726562502912 +0.3345 -0.447784423828125 -0.0185546875 -0.9584594726562502912 +0.334625 -0.447784423828125 -0.0185546875 -0.9584594726562502912 +0.33475 -0.450103759765625 -0.018646240234375 -0.9584594726562502912 +0.33487500000000004 -0.452362060546875 -0.01873779296875 -0.9584594726562502912 +0.335 -0.452362060546875 -0.01873779296875 -0.9584594726562502912 +0.335125 -0.454559326171875 -0.018829345703125 -0.9584594726562502912 +0.33525 -0.454559326171875 -0.018829345703125 -0.9584594726562502912 +0.33537500000000004 -0.45672607421875 -0.0189208984375 -0.9584594726562502912 +0.3355 -0.458831787109375 -0.019012451171875 -0.9584594726562502912 +0.335625 -0.458831787109375 -0.019012451171875 -0.9584594726562502912 +0.33575 -0.46087646484375 -0.019073486328125 -0.9584594726562502912 +0.33587500000000004 -0.46087646484375 -0.019073486328125 -0.9584594726562502912 +0.336 -0.462890625 -0.0191650390625 -0.9584594726562502912 +0.336125 -0.464813232421875 -0.019256591796875 -0.9584594726562502912 +0.33625 -0.464813232421875 -0.019256591796875 -0.9584594726562502912 +0.336375 -0.46673583984375 -0.019317626953125 -0.9584594726562502912 +0.3365 -0.46673583984375 -0.019317626953125 -0.9584594726562502912 +0.336625 -0.46856689453125 -0.0194091796875 -0.9584594726562502912 +0.33675 -0.470367431640625 -0.01947021484375 -0.9584594726562502912 +0.336875 -0.470367431640625 -0.01947021484375 -0.9584594726562502912 +0.337 -0.472137451171875 -0.019561767578125 -0.9584594726562502912 +0.337125 -0.472137451171875 -0.019561767578125 -0.9584594726562502912 +0.33725 -0.47381591796875 -0.019622802734375 -0.9584594726562502912 +0.337375 -0.4754638671875 -0.019683837890625 -0.9584594726562502912 +0.3375 -0.4754638671875 -0.019683837890625 -0.9584594726562502912 +0.337625 -0.47705078125 -0.019744873046875 -0.9584594726562502912 +0.33775 -0.47705078125 -0.019744873046875 -0.9584594726562502912 +0.337875 -0.478607177734375 -0.019805908203125 -0.9584594726562502912 +0.338 -0.480072021484375 -0.019866943359375 -0.9584594726562502912 +0.338125 -0.480072021484375 -0.019866943359375 -0.9584594726562502912 +0.33825 -0.48150634765625 -0.019927978515625 -0.9584594726562502912 +0.338375 -0.48150634765625 -0.019927978515625 -0.9584594726562502912 +0.3385 -0.48291015625 -0.019989013671875 -0.9584594726562502912 +0.338625 -0.484222412109375 -0.020050048828125 -0.9584594726562502912 +0.33875 -0.484222412109375 -0.020050048828125 -0.9584594726562502912 +0.338875 -0.485504150390625 -0.020111083984375 -0.9584594726562502912 +0.339 -0.485504150390625 -0.020111083984375 -0.9584594726562502912 +0.339125 -0.486724853515625 -0.020172119140625 -0.9584594726562502912 +0.33925 -0.487884521484375 -0.02020263671875 -0.9584594726562502912 +0.339375 -0.487884521484375 -0.02020263671875 -0.9584594726562502912 +0.3395 -0.489013671875 -0.020263671875 -0.9584594726562502912 +0.339625 -0.489013671875 -0.020263671875 -0.9584594726562502912 +0.33975 -0.490081787109375 -0.020294189453125 -0.9584594726562502912 +0.339875 -0.4910888671875 -0.02032470703125 -0.9584594726562502912 +0.34 -0.4910888671875 -0.02032470703125 -0.9584594726562502912 +0.340125 -0.492034912109375 -0.0203857421875 -0.9584594726562502912 +0.34025 -0.492034912109375 -0.0203857421875 -0.9584594726562502912 +0.340375 -0.492950439453125 -0.020416259765625 -0.9584594726562502912 +0.3405 -0.4937744140625 -0.02044677734375 -0.9584594726562502912 +0.340625 -0.4937744140625 -0.02044677734375 -0.9584594726562502912 +0.34075 -0.49456787109375 -0.020477294921875 -0.9584594726562502912 +0.340875 -0.49456787109375 -0.020477294921875 -0.9584594726562502912 +0.341 -0.49530029296875 -0.0205078125 -0.9584594726562502912 +0.341125 -0.496002197265625 -0.020538330078125 -0.9584594726562502912 +0.34125 -0.496002197265625 -0.020538330078125 -0.9584594726562502912 +0.341375 -0.496612548828125 -0.02056884765625 -0.9584594726562502912 +0.3415 -0.496612548828125 -0.02056884765625 -0.9584594726562502912 +0.341625 -0.4971923828125 -0.020599365234375 -0.9584594726562502912 +0.34175 -0.497711181640625 -0.020599365234375 -0.9584594726562502912 +0.341875 -0.497711181640625 -0.020599365234375 -0.9584594726562502912 +0.342 -0.498199462890625 -0.0206298828125 -0.9584594726562502912 +0.342125 -0.498199462890625 -0.0206298828125 -0.9584594726562502912 +0.34225 -0.49859619140625 -0.020660400390625 -0.9584594726562502912 +0.342375 -0.49896240234375 -0.020660400390625 -0.9584594726562502912 +0.3425 -0.49896240234375 -0.020660400390625 -0.9584594726562502912 +0.342625 -0.499267578125 -0.02069091796875 -0.9584594726562502912 +0.34275 -0.499267578125 -0.02069091796875 -0.9584594726562502912 +0.342875 -0.49951171875 -0.02069091796875 -0.9584594726562502912 +0.343 -0.49969482421875 -0.02069091796875 -0.9584594726562502912 +0.343125 -0.49969482421875 -0.02069091796875 -0.9584594726562502912 +0.34325 -0.49981689453125 -0.02069091796875 -0.9584594726562502912 +0.343375 -0.49981689453125 -0.02069091796875 -0.9584594726562502912 +0.3435 -0.499908447265625 -0.02069091796875 -0.9584594726562502912 +0.343625 -0.49993896484375 -0.02069091796875 -0.9584594726562502912 +0.34375 -0.49993896484375 -0.02069091796875 -0.9584594726562502912 +0.343875 -0.499908447265625 -0.02069091796875 -0.9584594726562502912 +0.34400000000000004 -0.499908447265625 -0.02069091796875 -0.9584594726562502912 +0.344125 -0.49981689453125 -0.02069091796875 -0.9584594726562502912 +0.34425 -0.49969482421875 -0.02069091796875 -0.9584594726562502912 +0.344375 -0.49969482421875 -0.02069091796875 -0.9584594726562502912 +0.34450000000000004 -0.49951171875 -0.02069091796875 -0.9584594726562502912 +0.344625 -0.49951171875 -0.02069091796875 -0.9584594726562502912 +0.34475 -0.499267578125 -0.02069091796875 -0.9584594726562502912 +0.344875 -0.49896240234375 -0.020660400390625 -0.9584594726562502912 +0.34500000000000004 -0.49896240234375 -0.020660400390625 -0.9584594726562502912 +0.345125 -0.49859619140625 -0.020660400390625 -0.9584594726562502912 +0.34525 -0.49859619140625 -0.020660400390625 -0.9584594726562502912 +0.345375 -0.498199462890625 -0.0206298828125 -0.9584594726562502912 +0.34550000000000004 -0.497711181640625 -0.020599365234375 -0.9584594726562502912 +0.345625 -0.497711181640625 -0.020599365234375 -0.9584594726562502912 +0.34575 -0.4971923828125 -0.020599365234375 -0.9584594726562502912 +0.345875 -0.4971923828125 -0.020599365234375 -0.9584594726562502912 +0.34600000000000004 -0.496612548828125 -0.02056884765625 -0.9584594726562502912 +0.346125 -0.496002197265625 -0.020538330078125 -0.9584594726562502912 +0.34625 -0.496002197265625 -0.020538330078125 -0.9584594726562502912 +0.346375 -0.49530029296875 -0.0205078125 -0.9584594726562502912 +0.34650000000000004 -0.49530029296875 -0.0205078125 -0.9584594726562502912 +0.346625 -0.49456787109375 -0.020477294921875 -0.9584594726562502912 +0.34675 -0.4937744140625 -0.02044677734375 -0.9584594726562502912 +0.346875 -0.4937744140625 -0.02044677734375 -0.9584594726562502912 +0.34700000000000004 -0.492950439453125 -0.020416259765625 -0.9584594726562502912 +0.347125 -0.492950439453125 -0.020416259765625 -0.9584594726562502912 +0.34725 -0.492034912109375 -0.0203857421875 -0.9584594726562502912 +0.347375 -0.4910888671875 -0.02032470703125 -0.9584594726562502912 +0.34750000000000004 -0.4910888671875 -0.02032470703125 -0.9584594726562502912 +0.347625 -0.490081787109375 -0.020294189453125 -0.9584594726562502912 +0.34775 -0.490081787109375 -0.020294189453125 -0.9584594726562502912 +0.347875 -0.489013671875 -0.020263671875 -0.9584594726562502912 +0.34800000000000004 -0.487884521484375 -0.02020263671875 -0.9584594726562502912 +0.348125 -0.487884521484375 -0.02020263671875 -0.9584594726562502912 +0.34825 -0.486724853515625 -0.020172119140625 -0.9584594726562502912 +0.348375 -0.486724853515625 -0.020172119140625 -0.9584594726562502912 +0.34850000000000004 -0.485504150390625 -0.020111083984375 -0.9584594726562502912 +0.348625 -0.484222412109375 -0.020050048828125 -0.9584594726562502912 +0.34875 -0.484222412109375 -0.020050048828125 -0.9584594726562502912 +0.348875 -0.48291015625 -0.019989013671875 -0.9584594726562502912 +0.34900000000000004 -0.48291015625 -0.019989013671875 -0.9584594726562502912 +0.349125 -0.48150634765625 -0.019927978515625 -0.9584594726562502912 +0.34925 -0.480072021484375 -0.019866943359375 -0.9584594726562502912 +0.349375 -0.480072021484375 -0.019866943359375 -0.9584594726562502912 +0.34950000000000004 -0.478607177734375 -0.019805908203125 -0.9584594726562502912 +0.349625 -0.478607177734375 -0.019805908203125 -0.9584594726562502912 +0.34975 -0.47705078125 -0.019744873046875 -0.9584594726562502912 +0.349875 -0.4754638671875 -0.019683837890625 -0.9584594726562502912 +0.35000000000000004 -0.4754638671875 -0.019683837890625 -0.9584594726562502912 +0.350125 -0.47381591796875 -0.019622802734375 -0.9584594726562502912 +0.35025 -0.47381591796875 -0.019622802734375 -0.9584594726562502912 +0.350375 -0.472137451171875 -0.019561767578125 -0.9584594726562502912 +0.35050000000000004 -0.470367431640625 -0.01947021484375 -0.9584594726562502912 +0.350625 -0.470367431640625 -0.01947021484375 -0.9584594726562502912 +0.35075 -0.46856689453125 -0.0194091796875 -0.9584594726562502912 +0.350875 -0.46856689453125 -0.0194091796875 -0.9584594726562502912 +0.35100000000000004 -0.46673583984375 -0.019317626953125 -0.9584594726562502912 +0.351125 -0.464813232421875 -0.019256591796875 -0.9584594726562502912 +0.35125 -0.464813232421875 -0.019256591796875 -0.9584594726562502912 +0.351375 -0.462890625 -0.0191650390625 -0.9584594726562502912 +0.35150000000000004 -0.462890625 -0.0191650390625 -0.9584594726562502912 +0.351625 -0.46087646484375 -0.019073486328125 -0.9584594726562502912 +0.35175 -0.458831787109375 -0.019012451171875 -0.9584594726562502912 +0.351875 -0.458831787109375 -0.019012451171875 -0.9584594726562502912 +0.352 -0.45672607421875 -0.002899169921875 -0.9935485839843748 +0.352125 -0.45672607421875 -0.002899169921875 -0.9935485839843748 +0.35225 -0.454559326171875 -0.00286865234375 -0.9935485839843748 +0.352375 -0.452362060546875 -0.00286865234375 -0.9935485839843748 +0.3525 -0.452362060546875 -0.00286865234375 -0.9935485839843748 +0.352625 -0.450103759765625 -0.002838134765625 -0.9935485839843748 +0.35275 -0.450103759765625 -0.002838134765625 -0.9935485839843748 +0.352875 -0.447784423828125 -0.002838134765625 -0.9935485839843748 +0.353 -0.4454345703125 -0.0028076171875 -0.9935485839843748 +0.353125 -0.4454345703125 -0.0028076171875 -0.9935485839843748 +0.35325 -0.44305419921875 -0.0028076171875 -0.9935485839843748 +0.353375 -0.44305419921875 -0.0028076171875 -0.9935485839843748 +0.3535 -0.440582275390625 -0.002777099609375 -0.9935485839843748 +0.353625 -0.438079833984375 -0.002777099609375 -0.9935485839843748 +0.35375 -0.438079833984375 -0.002777099609375 -0.9935485839843748 +0.353875 -0.435546875 -0.00274658203125 -0.9935485839843748 +0.354 -0.435546875 -0.00274658203125 -0.9935485839843748 +0.354125 -0.432952880859375 -0.00274658203125 -0.9935485839843748 +0.35425 -0.4302978515625 -0.002716064453125 -0.9935485839843748 +0.354375 -0.4302978515625 -0.002716064453125 -0.9935485839843748 +0.3545 -0.4276123046875 -0.002685546875 -0.9935485839843748 +0.354625 -0.4276123046875 -0.002685546875 -0.9935485839843748 +0.35475 -0.424896240234375 -0.002685546875 -0.9935485839843748 +0.354875 -0.422119140625 -0.002655029296875 -0.9935485839843748 +0.355 -0.422119140625 -0.002655029296875 -0.9935485839843748 +0.355125 -0.419281005859375 -0.002655029296875 -0.9935485839843748 +0.35525 -0.419281005859375 -0.002655029296875 -0.9935485839843748 +0.355375 -0.416412353515625 -0.00262451171875 -0.9935485839843748 +0.3555 -0.413482666015625 -0.00262451171875 -0.9935485839843748 +0.355625 -0.413482666015625 -0.00262451171875 -0.9935485839843748 +0.35575 -0.4105224609375 -0.002593994140625 -0.9935485839843748 +0.355875 -0.4105224609375 -0.002593994140625 -0.9935485839843748 +0.356 -0.407501220703125 -0.0025634765625 -0.9935485839843748 +0.356125 -0.404449462890625 -0.0025634765625 -0.9935485839843748 +0.35625 -0.404449462890625 -0.0025634765625 -0.9935485839843748 +0.356375 -0.401336669921875 -0.002532958984375 -0.9935485839843748 +0.3565 -0.401336669921875 -0.002532958984375 -0.9935485839843748 +0.356625 -0.398193359375 -0.00250244140625 -0.9935485839843748 +0.35675 -0.39501953125 -0.00250244140625 -0.9935485839843748 +0.356875 -0.39501953125 -0.00250244140625 -0.9935485839843748 +0.357 -0.39178466796875 -0.002471923828125 -0.9935485839843748 +0.357125 -0.39178466796875 -0.002471923828125 -0.9935485839843748 +0.35725 -0.388519287109375 -0.00244140625 -0.9935485839843748 +0.357375 -0.38519287109375 -0.00244140625 -0.9935485839843748 +0.3575 -0.38519287109375 -0.00244140625 -0.9935485839843748 +0.357625 -0.3818359375 -0.002410888671875 -0.9935485839843748 +0.35775 -0.3818359375 -0.002410888671875 -0.9935485839843748 +0.357875 -0.378448486328125 -0.00238037109375 -0.9935485839843748 +0.358 -0.375 -0.00238037109375 -0.9935485839843748 +0.358125 -0.375 -0.00238037109375 -0.9935485839843748 +0.35825 -0.37152099609375 -0.002349853515625 -0.9935485839843748 +0.358375 -0.37152099609375 -0.002349853515625 -0.9935485839843748 +0.3585 -0.36798095703125 -0.0023193359375 -0.9935485839843748 +0.358625 -0.36444091796875 -0.002288818359375 -0.9935485839843748 +0.35875 -0.36444091796875 -0.002288818359375 -0.9935485839843748 +0.358875 -0.360809326171875 -0.002288818359375 -0.9935485839843748 +0.359 -0.360809326171875 -0.002288818359375 -0.9935485839843748 +0.359125 -0.357177734375 -0.00225830078125 -0.9935485839843748 +0.35925 -0.353485107421875 -0.002227783203125 -0.9935485839843748 +0.359375 -0.353485107421875 -0.002227783203125 -0.9935485839843748 +0.3595 -0.349761962890625 -0.002197265625 -0.9935485839843748 +0.35962500000000004 -0.349761962890625 -0.002197265625 -0.9935485839843748 +0.35975 -0.34600830078125 -0.002166748046875 -0.9935485839843748 +0.359875 -0.34222412109375 -0.002166748046875 -0.9935485839843748 +0.36 -0.34222412109375 -0.002166748046875 -0.9935485839843748 +0.36012500000000004 -0.33837890625 -0.00213623046875 -0.9935485839843748 +0.36025 -0.33837890625 -0.00213623046875 -0.9935485839843748 +0.360375 -0.334503173828125 -0.002105712890625 -0.9935485839843748 +0.3605 -0.330596923828125 -0.0020751953125 -0.9935485839843748 +0.3606250000000000512 -0.330596923828125 -0.0020751953125 -0.9935485839843748 +0.36075 -0.32666015625 -0.002044677734375 -0.9935485839843748 +0.360875 -0.32666015625 -0.002044677734375 -0.9935485839843748 +0.361 -0.322662353515625 -0.002044677734375 -0.9935485839843748 +0.3611250000000000512 -0.31866455078125 -0.00201416015625 -0.9935485839843748 +0.36125 -0.31866455078125 -0.00201416015625 -0.9935485839843748 +0.361375 -0.314605712890625 -0.001983642578125 -0.9935485839843748 +0.3615 -0.314605712890625 -0.001983642578125 -0.9935485839843748 +0.3616250000000000512 -0.310516357421875 -0.001953125 -0.9935485839843748 +0.36175 -0.306396484375 -0.001922607421875 -0.9935485839843748 +0.361875 -0.306396484375 -0.001922607421875 -0.9935485839843748 +0.362 -0.30224609375 -0.00189208984375 -0.9935485839843748 +0.3621250000000000512 -0.30224609375 -0.00189208984375 -0.9935485839843748 +0.36225 -0.298065185546875 -0.00189208984375 -0.9935485839843748 +0.362375 -0.2938232421875 -0.001861572265625 -0.9935485839843748 +0.3625 -0.2938232421875 -0.001861572265625 -0.9935485839843748 +0.3626250000000000512 -0.289581298828125 -0.0018310546875 -0.9935485839843748 +0.36275 -0.289581298828125 -0.0018310546875 -0.9935485839843748 +0.362875 -0.285308837890625 -0.001800537109375 -0.9935485839843748 +0.363 -0.280975341796875 -0.00177001953125 -0.9935485839843748 +0.3631250000000000512 -0.280975341796875 -0.00177001953125 -0.9935485839843748 +0.36325 -0.276641845703125 -0.001739501953125 -0.9935485839843748 +0.363375 -0.276641845703125 -0.001739501953125 -0.9935485839843748 +0.3635 -0.27227783203125 -0.001708984375 -0.9935485839843748 +0.3636250000000000512 -0.267852783203125 -0.001678466796875 -0.9935485839843748 +0.36375 -0.267852783203125 -0.001678466796875 -0.9935485839843748 +0.363875 -0.263427734375 -0.00164794921875 -0.9935485839843748 +0.364 -0.263427734375 -0.00164794921875 -0.9935485839843748 +0.3641250000000000512 -0.25897216796875 -0.001617431640625 -0.9935485839843748 +0.36425 -0.25445556640625 -0.0015869140625 -0.9935485839843748 +0.364375 -0.25445556640625 -0.0015869140625 -0.9935485839843748 +0.3645 -0.249969482421875 -0.001556396484375 -0.9935485839843748 +0.3646250000000000512 -0.249969482421875 -0.001556396484375 -0.9935485839843748 +0.36475 -0.24542236328125 -0.001556396484375 -0.9935485839843748 +0.364875 -0.2408447265625 -0.00152587890625 -0.9935485839843748 +0.365 -0.2408447265625 -0.00152587890625 -0.9935485839843748 +0.3651250000000000512 -0.236236572265625 -0.001495361328125 -0.9935485839843748 +0.36525 -0.236236572265625 -0.001495361328125 -0.9935485839843748 +0.365375 -0.231597900390625 -0.00146484375 -0.9935485839843748 +0.3655 -0.226959228515625 -0.001434326171875 -0.9935485839843748 +0.3656250000000000512 -0.226959228515625 -0.001434326171875 -0.9935485839843748 +0.36575 -0.2222900390625 -0.00140380859375 -0.9935485839843748 +0.365875 -0.2222900390625 -0.00140380859375 -0.9935485839843748 +0.366 -0.21759033203125 -0.001373291015625 -0.9935485839843748 +0.3661250000000000512 -0.212860107421875 -0.0013427734375 -0.9935485839843748 +0.36625 -0.212860107421875 -0.0013427734375 -0.9935485839843748 +0.366375 -0.208099365234375 -0.001312255859375 -0.9935485839843748 +0.3665 -0.208099365234375 -0.001312255859375 -0.9935485839843748 +0.3666250000000000512 -0.203338623046875 -0.00128173828125 -0.9935485839843748 +0.36675 -0.19854736328125 -0.001251220703125 -0.9935485839843748 +0.366875 -0.19854736328125 -0.001251220703125 -0.9935485839843748 +0.367 -0.1937255859375 -0.001220703125 -0.9935485839843748 +0.3671250000000000512 -0.1937255859375 -0.001220703125 -0.9935485839843748 +0.36725 -0.188873291015625 -0.001190185546875 -0.9935485839843748 +0.367375 -0.18402099609375 -0.00115966796875 -0.9935485839843748 +0.3675 -0.18402099609375 -0.00115966796875 -0.9935485839843748 +0.3676250000000000512 -0.17913818359375 -0.001129150390625 -0.9935485839843748 +0.36775 -0.17913818359375 -0.001129150390625 -0.9935485839843748 +0.367875 -0.17425537109375 -0.0010986328125 -0.9935485839843748 +0.368 -0.169342041015625 -0.001068115234375 -0.9935485839843748 +0.368125 -0.169342041015625 -0.001068115234375 -0.9935485839843748 +0.36825 -0.164398193359375 -0.00103759765625 -0.9935485839843748 +0.368375 -0.164398193359375 -0.00103759765625 -0.9935485839843748 +0.3685 -0.159454345703125 -0.001007080078125 -0.9935485839843748 +0.368625 -0.15447998046875 -0.0009765625 -0.9935485839843748 +0.36875 -0.15447998046875 -0.0009765625 -0.9935485839843748 +0.368875 -0.14947509765625 -0.000946044921875 -0.9935485839843748 +0.369 -0.14947509765625 -0.000946044921875 -0.9935485839843748 +0.369125 -0.14447021484375 -0.00091552734375 -0.9935485839843748 +0.36925 -0.13946533203125 -0.000885009765625 -0.9935485839843748 +0.369375 -0.13946533203125 -0.000885009765625 -0.9935485839843748 +0.3695 -0.134429931640625 -0.000823974609375 -0.9935485839843748 +0.369625 -0.134429931640625 -0.000823974609375 -0.9935485839843748 +0.36975 -0.129364013671875 -0.00079345703125 -0.9935485839843748 +0.369875 -0.124298095703125 -0.000762939453125 -0.9935485839843748 +0.37 -0.124298095703125 -0.000762939453125 -0.9935485839843748 +0.370125 -0.119232177734375 -0.000732421875 -0.9935485839843748 +0.37025 -0.119232177734375 -0.000732421875 -0.9935485839843748 +0.370375 -0.1141357421875 -0.000701904296875 -0.9935485839843748 +0.3705 -0.109039306640625 -0.00067138671875 -0.9935485839843748 +0.370625 -0.109039306640625 -0.00067138671875 -0.9935485839843748 +0.37075 -0.103912353515625 -0.000640869140625 -0.9935485839843748 +0.370875 -0.103912353515625 -0.000640869140625 -0.9935485839843748 +0.371 -0.098785400390625 -0.0006103515625 -0.9935485839843748 +0.371125 -0.093658447265625 -0.000579833984375 -0.9935485839843748 +0.37125 -0.093658447265625 -0.000579833984375 -0.9935485839843748 +0.371375 -0.0885009765625 -0.00054931640625 -0.9935485839843748 +0.3715 -0.0885009765625 -0.00054931640625 -0.9935485839843748 +0.371625 -0.083343505859375 -0.000518798828125 -0.9935485839843748 +0.37175 -0.07818603515625 -0.00048828125 -0.9935485839843748 +0.371875 -0.07818603515625 -0.00048828125 -0.9935485839843748 +0.372 -0.072998046875 -0.000457763671875 -0.9935485839843748 +0.372125 -0.072998046875 -0.000457763671875 -0.9935485839843748 +0.37225 -0.06781005859375 -0.00042724609375 -0.9935485839843748 +0.372375 -0.0626220703125 -0.000396728515625 -0.9935485839843748 +0.3725 -0.0626220703125 -0.000396728515625 -0.9935485839843748 +0.372625 -0.05743408203125 -0.000335693359375 -0.9935485839843748 +0.37275 -0.05743408203125 -0.000335693359375 -0.9935485839843748 +0.372875 -0.05224609375 -0.00030517578125 -0.9935485839843748 +0.373 -0.047027587890625 -0.000274658203125 -0.9935485839843748 +0.373125 -0.047027587890625 -0.000274658203125 -0.9935485839843748 +0.37325 -0.04180908203125 -0.000244140625 -0.9935485839843748 +0.373375 -0.04180908203125 -0.000244140625 -0.9935485839843748 +0.3735 -0.036590576171875 -0.000213623046875 -0.9935485839843748 +0.373625 -0.0313720703125 -0.00018310546875 -0.9935485839843748 +0.37375 -0.0313720703125 -0.00018310546875 -0.9935485839843748 +0.373875 -0.026123046875 -0.000152587890625 -0.9935485839843748 +0.374 -0.026123046875 -0.000152587890625 -0.9935485839843748 +0.374125 -0.020904541015625 -0.0001220703125 -0.9935485839843748 +0.37425 -0.01568603515625 -9.1552734375e-05 -0.9935485839843748 +0.374375 -0.01568603515625 -9.1552734375e-05 -0.9935485839843748 +0.3745 -0.01043701171875 -6.103515625e-05 -0.9935485839843748 +0.374625 -0.01043701171875 -6.103515625e-05 -0.9935485839843748 +0.37475 -0.005218505859375 -3.0517578125e-05 -0.9935485839843748 +0.374875 0.0 0.0 -0.9935485839843748 +0.375 0.0 0.0 -0.9935485839843748 +0.375125 0.005218505859375 3.0517578125e-05 -0.9935485839843748 +0.3752500000000000512 0.005218505859375 3.0517578125e-05 -0.9935485839843748 +0.375375 0.01043701171875 6.103515625e-05 -0.9935485839843748 +0.3755 0.01568603515625 9.1552734375e-05 -0.9935485839843748 +0.375625 0.01568603515625 9.1552734375e-05 -0.9935485839843748 +0.3757500000000000512 0.020904541015625 0.0001220703125 -0.9935485839843748 +0.375875 0.020904541015625 0.0001220703125 -0.9935485839843748 +0.376 0.026123046875 0.000152587890625 -0.9935485839843748 +0.376125 0.0313720703125 0.00018310546875 -0.9935485839843748 +0.3762500000000000512 0.0313720703125 0.00018310546875 -0.9935485839843748 +0.376375 0.036590576171875 0.000213623046875 -0.9935485839843748 +0.3765 0.036590576171875 0.000213623046875 -0.9935485839843748 +0.376625 0.04180908203125 0.000244140625 -0.9935485839843748 +0.3767500000000000512 0.047027587890625 0.000274658203125 -0.9935485839843748 +0.376875 0.047027587890625 0.000274658203125 -0.9935485839843748 +0.377 0.05224609375 0.00030517578125 -0.9935485839843748 +0.377125 0.05224609375 0.00030517578125 -0.9935485839843748 +0.3772500000000000512 0.05743408203125 0.000335693359375 -0.9935485839843748 +0.377375 0.0626220703125 0.000396728515625 -0.9935485839843748 +0.3775 0.0626220703125 0.000396728515625 -0.9935485839843748 +0.377625 0.06781005859375 0.00042724609375 -0.9935485839843748 +0.3777500000000000512 0.06781005859375 0.00042724609375 -0.9935485839843748 +0.377875 0.072998046875 0.000457763671875 -0.9935485839843748 +0.378 0.07818603515625 0.00048828125 -0.9935485839843748 +0.378125 0.07818603515625 0.00048828125 -0.9935485839843748 +0.3782500000000000512 0.083343505859375 0.000518798828125 -0.9935485839843748 +0.378375 0.083343505859375 0.000518798828125 -0.9935485839843748 +0.3785 0.0885009765625 0.00054931640625 -0.9935485839843748 +0.378625 0.093658447265625 0.000579833984375 -0.9935485839843748 +0.3787500000000000512 0.093658447265625 0.000579833984375 -0.9935485839843748 +0.378875 0.098785400390625 0.0006103515625 -0.9935485839843748 +0.379 0.098785400390625 0.0006103515625 -0.9935485839843748 +0.379125 0.103912353515625 0.000640869140625 -0.9935485839843748 +0.3792500000000000512 0.109039306640625 0.00067138671875 -0.9935485839843748 +0.379375 0.109039306640625 0.00067138671875 -0.9935485839843748 +0.3795 0.1141357421875 0.000701904296875 -0.9935485839843748 +0.379625 0.1141357421875 0.000701904296875 -0.9935485839843748 +0.3797500000000000512 0.119232177734375 0.000732421875 -0.9935485839843748 +0.379875 0.124298095703125 0.000762939453125 -0.9935485839843748 +0.38 0.124298095703125 0.000762939453125 -0.9935485839843748 +0.380125 0.129364013671875 0.00079345703125 -0.9935485839843748 +0.3802500000000000512 0.129364013671875 0.00079345703125 -0.9935485839843748 +0.380375 0.134429931640625 0.000823974609375 -0.9935485839843748 +0.3805 0.13946533203125 0.000885009765625 -0.9935485839843748 +0.380625 0.13946533203125 0.000885009765625 -0.9935485839843748 +0.3807500000000000512 0.14447021484375 0.00091552734375 -0.9935485839843748 +0.380875 0.14447021484375 0.00091552734375 -0.9935485839843748 +0.381 0.14947509765625 0.000946044921875 -0.9935485839843748 +0.381125 0.15447998046875 0.0009765625 -0.9935485839843748 +0.3812500000000000512 0.15447998046875 0.0009765625 -0.9935485839843748 +0.381375 0.159454345703125 0.001007080078125 -0.9935485839843748 +0.3815 0.159454345703125 0.001007080078125 -0.9935485839843748 +0.381625 0.164398193359375 0.00103759765625 -0.9935485839843748 +0.3817500000000000512 0.169342041015625 0.001068115234375 -0.9935485839843748 +0.381875 0.169342041015625 0.001068115234375 -0.9935485839843748 +0.382 0.17425537109375 0.0010986328125 -0.9935485839843748 +0.382125 0.17425537109375 0.0010986328125 -0.9935485839843748 +0.3822500000000000512 0.17913818359375 0.001129150390625 -0.9935485839843748 +0.382375 0.18402099609375 0.00115966796875 -0.9935485839843748 +0.3825 0.18402099609375 0.00115966796875 -0.9935485839843748 +0.382625 0.188873291015625 0.001190185546875 -0.9935485839843748 +0.3827500000000000512 0.188873291015625 0.001190185546875 -0.9935485839843748 +0.382875 0.1937255859375 0.001220703125 -0.9935485839843748 +0.383 0.19854736328125 0.001251220703125 -0.9935485839843748 +0.383125 0.19854736328125 0.001251220703125 -0.9935485839843748 +0.3832500000000000512 0.203338623046875 0.00128173828125 -0.9935485839843748 +0.383375 0.203338623046875 0.00128173828125 -0.9935485839843748 +0.3835 0.208099365234375 0.001312255859375 -0.9935485839843748 +0.383625 0.212860107421875 0.0013427734375 -0.9935485839843748 +0.3837500000000000512 0.212860107421875 0.0013427734375 -0.9935485839843748 +0.383875 0.21759033203125 0.001373291015625 -0.9935485839843748 +0.384 0.21759033203125 0.028228759765625 -0.8701477050781241 +0.384125 0.2222900390625 0.028839111328125 -0.8701477050781241 +0.38425 0.226959228515625 0.029449462890625 -0.8701477050781241 +0.384375 0.226959228515625 0.029449462890625 -0.8701477050781241 +0.3845 0.231597900390625 0.030029296875 -0.8701477050781241 +0.384625 0.231597900390625 0.030029296875 -0.8701477050781241 +0.38475 0.236236572265625 0.0306396484375 -0.8701477050781241 +0.384875 0.2408447265625 0.03125 -0.8701477050781241 +0.385 0.2408447265625 0.03125 -0.8701477050781241 +0.385125 0.24542236328125 0.031829833984375 -0.8701477050781241 +0.38525 0.24542236328125 0.031829833984375 -0.8701477050781241 +0.385375 0.249969482421875 0.03240966796875 -0.8701477050781241 +0.3855 0.25445556640625 0.03302001953125 -0.8701477050781241 +0.385625 0.25445556640625 0.03302001953125 -0.8701477050781241 +0.38575 0.25897216796875 0.033599853515625 -0.8701477050781241 +0.385875 0.25897216796875 0.033599853515625 -0.8701477050781241 +0.386 0.263427734375 0.0341796875 -0.8701477050781241 +0.386125 0.267852783203125 0.034759521484375 -0.8701477050781241 +0.38625 0.267852783203125 0.034759521484375 -0.8701477050781241 +0.386375 0.27227783203125 0.035308837890625 -0.8701477050781241 +0.3865 0.27227783203125 0.035308837890625 -0.8701477050781241 +0.386625 0.276641845703125 0.035888671875 -0.8701477050781241 +0.38675 0.280975341796875 0.03643798828125 -0.8701477050781241 +0.386875 0.280975341796875 0.03643798828125 -0.8701477050781241 +0.387 0.285308837890625 0.037017822265625 -0.8701477050781241 +0.387125 0.285308837890625 0.037017822265625 -0.8701477050781241 +0.38725 0.289581298828125 0.037567138671875 -0.8701477050781241 +0.387375 0.2938232421875 0.038116455078125 -0.8701477050781241 +0.3875 0.2938232421875 0.038116455078125 -0.8701477050781241 +0.387625 0.298065185546875 0.038665771484375 -0.8701477050781241 +0.38775 0.298065185546875 0.038665771484375 -0.8701477050781241 +0.387875 0.30224609375 0.039215087890625 -0.8701477050781241 +0.388 0.306396484375 0.03973388671875 -0.8701477050781241 +0.388125 0.306396484375 0.03973388671875 -0.8701477050781241 +0.38825 0.310516357421875 0.040283203125 -0.8701477050781241 +0.388375 0.310516357421875 0.040283203125 -0.8701477050781241 +0.3885 0.314605712890625 0.040802001953125 -0.8701477050781241 +0.388625 0.31866455078125 0.041351318359375 -0.8701477050781241 +0.38875 0.31866455078125 0.041351318359375 -0.8701477050781241 +0.388875 0.322662353515625 0.0418701171875 -0.8701477050781241 +0.389 0.322662353515625 0.0418701171875 -0.8701477050781241 +0.389125 0.32666015625 0.042388916015625 -0.8701477050781241 +0.38925 0.330596923828125 0.042877197265625 -0.8701477050781241 +0.389375 0.330596923828125 0.042877197265625 -0.8701477050781241 +0.3895 0.334503173828125 0.04339599609375 -0.8701477050781241 +0.389625 0.334503173828125 0.04339599609375 -0.8701477050781241 +0.38975 0.33837890625 0.04388427734375 -0.8701477050781241 +0.389875 0.34222412109375 0.044403076171875 -0.8701477050781241 +0.39 0.34222412109375 0.044403076171875 -0.8701477050781241 +0.390125 0.34600830078125 0.044891357421875 -0.8701477050781241 +0.39025 0.34600830078125 0.044891357421875 -0.8701477050781241 +0.390375 0.349761962890625 0.045379638671875 -0.8701477050781241 +0.3905 0.353485107421875 0.045867919921875 -0.8701477050781241 +0.390625 0.353485107421875 0.045867919921875 -0.8701477050781241 +0.39075 0.357177734375 0.04632568359375 -0.8701477050781241 +0.3908750000000000512 0.357177734375 0.04632568359375 -0.8701477050781241 +0.391 0.360809326171875 0.04681396484375 -0.8701477050781241 +0.391125 0.36444091796875 0.047271728515625 -0.8701477050781241 +0.39125 0.36444091796875 0.047271728515625 -0.8701477050781241 +0.3913750000000000512 0.36798095703125 0.0477294921875 -0.8701477050781241 +0.3915 0.36798095703125 0.0477294921875 -0.8701477050781241 +0.391625 0.37152099609375 0.048187255859375 -0.8701477050781241 +0.39175 0.375 0.04864501953125 -0.8701477050781241 +0.3918750000000000512 0.375 0.04864501953125 -0.8701477050781241 +0.392 0.378448486328125 0.049102783203125 -0.8701477050781241 +0.392125 0.378448486328125 0.049102783203125 -0.8701477050781241 +0.39225 0.3818359375 0.049530029296875 -0.8701477050781241 +0.3923750000000000512 0.38519287109375 0.04998779296875 -0.8701477050781241 +0.3925 0.38519287109375 0.04998779296875 -0.8701477050781241 +0.392625 0.388519287109375 0.0504150390625 -0.8701477050781241 +0.39275 0.388519287109375 0.0504150390625 -0.8701477050781241 +0.3928750000000000512 0.39178466796875 0.05084228515625 -0.8701477050781241 +0.393 0.39501953125 0.051239013671875 -0.8701477050781241 +0.393125 0.39501953125 0.051239013671875 -0.8701477050781241 +0.39325 0.398193359375 0.051666259765625 -0.8701477050781241 +0.3933750000000000512 0.398193359375 0.051666259765625 -0.8701477050781241 +0.3935 0.401336669921875 0.05206298828125 -0.8701477050781241 +0.393625 0.404449462890625 0.052459716796875 -0.8701477050781241 +0.39375 0.404449462890625 0.052459716796875 -0.8701477050781241 +0.3938750000000000512 0.407501220703125 0.0528564453125 -0.8701477050781241 +0.394 0.407501220703125 0.0528564453125 -0.8701477050781241 +0.394125 0.4105224609375 0.053253173828125 -0.8701477050781241 +0.39425 0.413482666015625 0.05364990234375 -0.8701477050781241 +0.3943750000000000512 0.413482666015625 0.05364990234375 -0.8701477050781241 +0.3945 0.416412353515625 0.05401611328125 -0.8701477050781241 +0.394625 0.416412353515625 0.05401611328125 -0.8701477050781241 +0.39475 0.419281005859375 0.05438232421875 -0.8701477050781241 +0.3948750000000000512 0.422119140625 0.05474853515625 -0.8701477050781241 +0.395 0.422119140625 0.05474853515625 -0.8701477050781241 +0.395125 0.424896240234375 0.05511474609375 -0.8701477050781241 +0.39525 0.424896240234375 0.05511474609375 -0.8701477050781241 +0.3953750000000000512 0.4276123046875 0.05548095703125 -0.8701477050781241 +0.3955 0.4302978515625 0.055816650390625 -0.8701477050781241 +0.395625 0.4302978515625 0.055816650390625 -0.8701477050781241 +0.39575 0.432952880859375 0.056182861328125 -0.8701477050781241 +0.3958750000000000512 0.432952880859375 0.056182861328125 -0.8701477050781241 +0.396 0.435546875 0.0565185546875 -0.8701477050781241 +0.396125 0.438079833984375 0.05682373046875 -0.8701477050781241 +0.39625 0.438079833984375 0.05682373046875 -0.8701477050781241 +0.3963750000000000512 0.440582275390625 0.057159423828125 -0.8701477050781241 +0.3965 0.440582275390625 0.057159423828125 -0.8701477050781241 +0.396625 0.44305419921875 0.057464599609375 -0.8701477050781241 +0.39675 0.4454345703125 0.05780029296875 -0.8701477050781241 +0.3968750000000000512 0.4454345703125 0.05780029296875 -0.8701477050781241 +0.397 0.447784423828125 0.05810546875 -0.8701477050781241 +0.397125 0.447784423828125 0.05810546875 -0.8701477050781241 +0.39725 0.450103759765625 0.058380126953125 -0.8701477050781241 +0.3973750000000000512 0.452362060546875 0.058685302734375 -0.8701477050781241 +0.3975 0.452362060546875 0.058685302734375 -0.8701477050781241 +0.397625 0.454559326171875 0.0589599609375 -0.8701477050781241 +0.39775 0.454559326171875 0.0589599609375 -0.8701477050781241 +0.3978750000000000512 0.45672607421875 0.05926513671875 -0.8701477050781241 +0.398 0.458831787109375 0.059539794921875 -0.8701477050781241 +0.398125 0.458831787109375 0.059539794921875 -0.8701477050781241 +0.39825 0.46087646484375 0.059783935546875 -0.8701477050781241 +0.3983750000000000512 0.46087646484375 0.059783935546875 -0.8701477050781241 +0.3985 0.462890625 0.06005859375 -0.8701477050781241 +0.398625 0.464813232421875 0.060302734375 -0.8701477050781241 +0.39875 0.464813232421875 0.060302734375 -0.8701477050781241 +0.3988750000000000512 0.46673583984375 0.060546875 -0.8701477050781241 +0.399 0.46673583984375 0.060546875 -0.8701477050781241 +0.399125 0.46856689453125 0.060791015625 -0.8701477050781241 +0.39925 0.470367431640625 0.06103515625 -0.8701477050781241 +0.3993750000000000512 0.470367431640625 0.06103515625 -0.8701477050781241 +0.3995 0.472137451171875 0.061248779296875 -0.8701477050781241 +0.399625 0.472137451171875 0.061248779296875 -0.8701477050781241 +0.39975 0.47381591796875 0.06146240234375 -0.8701477050781241 +0.3998750000000000512 0.4754638671875 0.061676025390625 -0.8701477050781241 +0.4 0.4754638671875 0.061676025390625 -0.8701477050781241 +0.400125 0.47705078125 0.0618896484375 -0.8701477050781241 +0.40025 0.47705078125 0.0618896484375 -0.8701477050781241 +0.400375 0.478607177734375 0.062103271484375 -0.8701477050781241 +0.4005 0.480072021484375 0.062286376953125 -0.8701477050781241 +0.400625 0.480072021484375 0.062286376953125 -0.8701477050781241 +0.40075 0.48150634765625 0.062469482421875 -0.8701477050781241 +0.400875 0.48150634765625 0.062469482421875 -0.8701477050781241 +0.401 0.48291015625 0.062652587890625 -0.8701477050781241 +0.401125 0.484222412109375 0.062835693359375 -0.8701477050781241 +0.40125 0.484222412109375 0.062835693359375 -0.8701477050781241 +0.401375 0.485504150390625 0.06298828125 -0.8701477050781241 +0.4015 0.485504150390625 0.06298828125 -0.8701477050781241 +0.401625 0.486724853515625 0.063140869140625 -0.8701477050781241 +0.40175 0.487884521484375 0.06329345703125 -0.8701477050781241 +0.401875 0.487884521484375 0.06329345703125 -0.8701477050781241 +0.402 0.489013671875 0.063446044921875 -0.8701477050781241 +0.402125 0.489013671875 0.063446044921875 -0.8701477050781241 +0.40225 0.490081787109375 0.063568115234375 -0.8701477050781241 +0.402375 0.4910888671875 0.063720703125 -0.8701477050781241 +0.4025 0.4910888671875 0.063720703125 -0.8701477050781241 +0.402625 0.492034912109375 0.0638427734375 -0.8701477050781241 +0.40275 0.492034912109375 0.0638427734375 -0.8701477050781241 +0.402875 0.492950439453125 0.06396484375 -0.8701477050781241 +0.403 0.4937744140625 0.064056396484375 -0.8701477050781241 +0.403125 0.4937744140625 0.064056396484375 -0.8701477050781241 +0.40325 0.49456787109375 0.064178466796875 -0.8701477050781241 +0.403375 0.49456787109375 0.064178466796875 -0.8701477050781241 +0.4035 0.49530029296875 0.06427001953125 -0.8701477050781241 +0.403625 0.496002197265625 0.064361572265625 -0.8701477050781241 +0.40375 0.496002197265625 0.064361572265625 -0.8701477050781241 +0.403875 0.496612548828125 0.064422607421875 -0.8701477050781241 +0.404 0.496612548828125 0.064422607421875 -0.8701477050781241 +0.404125 0.4971923828125 0.06451416015625 -0.8701477050781241 +0.40425 0.497711181640625 0.0645751953125 -0.8701477050781241 +0.404375 0.497711181640625 0.0645751953125 -0.8701477050781241 +0.4045 0.498199462890625 0.06463623046875 -0.8701477050781241 +0.404625 0.498199462890625 0.06463623046875 -0.8701477050781241 +0.40475 0.49859619140625 0.064697265625 -0.8701477050781241 +0.404875 0.49896240234375 0.064727783203125 -0.8701477050781241 +0.405 0.49896240234375 0.064727783203125 -0.8701477050781241 +0.405125 0.499267578125 0.064788818359375 -0.8701477050781241 +0.40525 0.499267578125 0.064788818359375 -0.8701477050781241 +0.405375 0.49951171875 0.0648193359375 -0.8701477050781241 +0.4055 0.49969482421875 0.0648193359375 -0.8701477050781241 +0.405625 0.49969482421875 0.0648193359375 -0.8701477050781241 +0.40575 0.49981689453125 0.064849853515625 -0.8701477050781241 +0.405875 0.49981689453125 0.064849853515625 -0.8701477050781241 +0.406 0.499908447265625 0.064849853515625 -0.8701477050781241 +0.406125 0.49993896484375 0.064849853515625 -0.8701477050781241 +0.40625 0.49993896484375 0.064849853515625 -0.8701477050781241 +0.406375 0.499908447265625 0.064849853515625 -0.8701477050781241 +0.4065000000000000512 0.499908447265625 0.064849853515625 -0.8701477050781241 +0.406625 0.49981689453125 0.064849853515625 -0.8701477050781241 +0.40675 0.49969482421875 0.0648193359375 -0.8701477050781241 +0.406875 0.49969482421875 0.0648193359375 -0.8701477050781241 +0.4070000000000000512 0.49951171875 0.0648193359375 -0.8701477050781241 +0.407125 0.49951171875 0.0648193359375 -0.8701477050781241 +0.40725 0.499267578125 0.064788818359375 -0.8701477050781241 +0.407375 0.49896240234375 0.064727783203125 -0.8701477050781241 +0.4075000000000000512 0.49896240234375 0.064727783203125 -0.8701477050781241 +0.407625 0.49859619140625 0.064697265625 -0.8701477050781241 +0.40775 0.49859619140625 0.064697265625 -0.8701477050781241 +0.407875 0.498199462890625 0.06463623046875 -0.8701477050781241 +0.4080000000000000512 0.497711181640625 0.0645751953125 -0.8701477050781241 +0.408125 0.497711181640625 0.0645751953125 -0.8701477050781241 +0.40825 0.4971923828125 0.06451416015625 -0.8701477050781241 +0.408375 0.4971923828125 0.06451416015625 -0.8701477050781241 +0.4085000000000000512 0.496612548828125 0.064422607421875 -0.8701477050781241 +0.408625 0.496002197265625 0.064361572265625 -0.8701477050781241 +0.40875 0.496002197265625 0.064361572265625 -0.8701477050781241 +0.408875 0.49530029296875 0.06427001953125 -0.8701477050781241 +0.4090000000000000512 0.49530029296875 0.06427001953125 -0.8701477050781241 +0.409125 0.49456787109375 0.064178466796875 -0.8701477050781241 +0.40925 0.4937744140625 0.064056396484375 -0.8701477050781241 +0.409375 0.4937744140625 0.064056396484375 -0.8701477050781241 +0.4095000000000000512 0.492950439453125 0.06396484375 -0.8701477050781241 +0.409625 0.492950439453125 0.06396484375 -0.8701477050781241 +0.40975 0.492034912109375 0.0638427734375 -0.8701477050781241 +0.409875 0.4910888671875 0.063720703125 -0.8701477050781241 +0.4100000000000000512 0.4910888671875 0.063720703125 -0.8701477050781241 +0.410125 0.490081787109375 0.063568115234375 -0.8701477050781241 +0.41025 0.490081787109375 0.063568115234375 -0.8701477050781241 +0.410375 0.489013671875 0.063446044921875 -0.8701477050781241 +0.4105000000000000512 0.487884521484375 0.06329345703125 -0.8701477050781241 +0.410625 0.487884521484375 0.06329345703125 -0.8701477050781241 +0.41075 0.486724853515625 0.063140869140625 -0.8701477050781241 +0.410875 0.486724853515625 0.063140869140625 -0.8701477050781241 +0.4110000000000000512 0.485504150390625 0.06298828125 -0.8701477050781241 +0.411125 0.484222412109375 0.062835693359375 -0.8701477050781241 +0.41125 0.484222412109375 0.062835693359375 -0.8701477050781241 +0.411375 0.48291015625 0.062652587890625 -0.8701477050781241 +0.4115000000000000512 0.48291015625 0.062652587890625 -0.8701477050781241 +0.411625 0.48150634765625 0.062469482421875 -0.8701477050781241 +0.41175 0.480072021484375 0.062286376953125 -0.8701477050781241 +0.411875 0.480072021484375 0.062286376953125 -0.8701477050781241 +0.4120000000000000512 0.478607177734375 0.062103271484375 -0.8701477050781241 +0.412125 0.478607177734375 0.062103271484375 -0.8701477050781241 +0.41225 0.47705078125 0.0618896484375 -0.8701477050781241 +0.412375 0.4754638671875 0.061676025390625 -0.8701477050781241 +0.4125000000000000512 0.4754638671875 0.061676025390625 -0.8701477050781241 +0.412625 0.47381591796875 0.06146240234375 -0.8701477050781241 +0.41275 0.47381591796875 0.06146240234375 -0.8701477050781241 +0.412875 0.472137451171875 0.061248779296875 -0.8701477050781241 +0.4130000000000000512 0.470367431640625 0.06103515625 -0.8701477050781241 +0.413125 0.470367431640625 0.06103515625 -0.8701477050781241 +0.41325 0.46856689453125 0.060791015625 -0.8701477050781241 +0.413375 0.46856689453125 0.060791015625 -0.8701477050781241 +0.4135000000000000512 0.46673583984375 0.060546875 -0.8701477050781241 +0.413625 0.464813232421875 0.060302734375 -0.8701477050781241 +0.41375 0.464813232421875 0.060302734375 -0.8701477050781241 +0.413875 0.462890625 0.06005859375 -0.8701477050781241 +0.4140000000000000512 0.462890625 0.06005859375 -0.8701477050781241 +0.414125 0.46087646484375 0.059783935546875 -0.8701477050781241 +0.41425 0.458831787109375 0.059539794921875 -0.8701477050781241 +0.414375 0.458831787109375 0.059539794921875 -0.8701477050781241 +0.4145000000000000512 0.45672607421875 0.05926513671875 -0.8701477050781241 +0.414625 0.45672607421875 0.05926513671875 -0.8701477050781241 +0.41475 0.454559326171875 0.0589599609375 -0.8701477050781241 +0.414875 0.452362060546875 0.058685302734375 -0.8701477050781241 +0.4150000000000000512 0.452362060546875 0.058685302734375 -0.8701477050781241 +0.415125 0.450103759765625 0.058380126953125 -0.8701477050781241 +0.41525 0.450103759765625 0.058380126953125 -0.8701477050781241 +0.415375 0.447784423828125 0.05810546875 -0.8701477050781241 +0.4155000000000000512 0.4454345703125 0.05780029296875 -0.8701477050781241 +0.415625 0.4454345703125 0.05780029296875 -0.8701477050781241 +0.41575 0.44305419921875 0.057464599609375 -0.8701477050781241 +0.415875 0.44305419921875 0.057464599609375 -0.8701477050781241 +0.416000000000000036 0.440582275390625 0.1727294921875 -0.6078857421874979 +0.416125 0.438079833984375 0.1717529296875 -0.6078857421874979 +0.41625 0.438079833984375 0.1717529296875 -0.6078857421874979 +0.416375 0.435546875 0.170745849609375 -0.6078857421874979 +0.4165 0.435546875 0.170745849609375 -0.6078857421874979 +0.416625 0.432952880859375 0.16973876953125 -0.6078857421874979 +0.41675 0.4302978515625 0.168701171875 -0.6078857421874979 +0.416875 0.4302978515625 0.168701171875 -0.6078857421874979 +0.417 0.4276123046875 0.167633056640625 -0.6078857421874979 +0.417125 0.4276123046875 0.167633056640625 -0.6078857421874979 +0.41725 0.424896240234375 0.16656494140625 -0.6078857421874979 +0.417375 0.422119140625 0.16546630859375 -0.6078857421874979 +0.4175 0.422119140625 0.16546630859375 -0.6078857421874979 +0.417625 0.419281005859375 0.16436767578125 -0.6078857421874979 +0.41775 0.419281005859375 0.16436767578125 -0.6078857421874979 +0.417875 0.416412353515625 0.163238525390625 -0.6078857421874979 +0.418 0.413482666015625 0.162078857421875 -0.6078857421874979 +0.418125 0.413482666015625 0.162078857421875 -0.6078857421874979 +0.41825 0.4105224609375 0.160919189453125 -0.6078857421874979 +0.418375 0.4105224609375 0.160919189453125 -0.6078857421874979 +0.4185 0.407501220703125 0.159759521484375 -0.6078857421874979 +0.418625 0.404449462890625 0.1585693359375 -0.6078857421874979 +0.41875 0.404449462890625 0.1585693359375 -0.6078857421874979 +0.418875 0.401336669921875 0.1573486328125 -0.6078857421874979 +0.419 0.401336669921875 0.1573486328125 -0.6078857421874979 +0.419125 0.398193359375 0.156097412109375 -0.6078857421874979 +0.41925 0.39501953125 0.154876708984375 -0.6078857421874979 +0.419375 0.39501953125 0.154876708984375 -0.6078857421874979 +0.4195 0.39178466796875 0.153594970703125 -0.6078857421874979 +0.419625 0.39178466796875 0.153594970703125 -0.6078857421874979 +0.41975 0.388519287109375 0.152313232421875 -0.6078857421874979 +0.419875 0.38519287109375 0.1510009765625 -0.6078857421874979 +0.42 0.38519287109375 0.1510009765625 -0.6078857421874979 +0.420125 0.3818359375 0.149688720703125 -0.6078857421874979 +0.42025 0.3818359375 0.149688720703125 -0.6078857421874979 +0.420375 0.378448486328125 0.148345947265625 -0.6078857421874979 +0.4205 0.375 0.147003173828125 -0.6078857421874979 +0.420625 0.375 0.147003173828125 -0.6078857421874979 +0.42075 0.37152099609375 0.1456298828125 -0.6078857421874979 +0.420875 0.37152099609375 0.1456298828125 -0.6078857421874979 +0.421 0.36798095703125 0.144256591796875 -0.6078857421874979 +0.421125 0.36444091796875 0.14288330078125 -0.6078857421874979 +0.42125 0.36444091796875 0.14288330078125 -0.6078857421874979 +0.421375 0.360809326171875 0.141448974609375 -0.6078857421874979 +0.4215 0.360809326171875 0.141448974609375 -0.6078857421874979 +0.421625 0.357177734375 0.1400146484375 -0.6078857421874979 +0.42175 0.353485107421875 0.138580322265625 -0.6078857421874979 +0.421875 0.353485107421875 0.138580322265625 -0.6078857421874979 +0.422 0.349761962890625 0.137115478515625 -0.6078857421874979 +0.4221250000000000512 0.349761962890625 0.137115478515625 -0.6078857421874979 +0.42225 0.34600830078125 0.135650634765625 -0.6078857421874979 +0.422375 0.34222412109375 0.1341552734375 -0.6078857421874979 +0.4225 0.34222412109375 0.1341552734375 -0.6078857421874979 +0.4226250000000000512 0.33837890625 0.132659912109375 -0.6078857421874979 +0.42275 0.33837890625 0.132659912109375 -0.6078857421874979 +0.422875 0.334503173828125 0.131134033203125 -0.6078857421874979 +0.423 0.330596923828125 0.129608154296875 -0.6078857421874979 +0.4231250000000000512 0.330596923828125 0.129608154296875 -0.6078857421874979 +0.42325 0.32666015625 0.1280517578125 -0.6078857421874979 +0.423375 0.32666015625 0.1280517578125 -0.6078857421874979 +0.4235 0.322662353515625 0.126495361328125 -0.6078857421874979 +0.4236250000000000512 0.31866455078125 0.124908447265625 -0.6078857421874979 +0.42375 0.31866455078125 0.124908447265625 -0.6078857421874979 +0.423875 0.314605712890625 0.123321533203125 -0.6078857421874979 +0.424 0.314605712890625 0.123321533203125 -0.6078857421874979 +0.4241250000000000512 0.310516357421875 0.121734619140625 -0.6078857421874979 +0.42425 0.306396484375 0.1201171875 -0.6078857421874979 +0.424375 0.306396484375 0.1201171875 -0.6078857421874979 +0.4245 0.30224609375 0.118499755859375 -0.6078857421874979 +0.4246250000000000512 0.30224609375 0.118499755859375 -0.6078857421874979 +0.42475 0.298065185546875 0.116851806640625 -0.6078857421874979 +0.424875 0.2938232421875 0.115203857421875 -0.6078857421874979 +0.425 0.2938232421875 0.115203857421875 -0.6078857421874979 +0.4251250000000000512 0.289581298828125 0.113525390625 -0.6078857421874979 +0.42525 0.289581298828125 0.113525390625 -0.6078857421874979 +0.425375 0.285308837890625 0.111846923828125 -0.6078857421874979 +0.4255 0.280975341796875 0.110137939453125 -0.6078857421874979 +0.4256250000000000512 0.280975341796875 0.110137939453125 -0.6078857421874979 +0.42575 0.276641845703125 0.10845947265625 -0.6078857421874979 +0.425875 0.276641845703125 0.10845947265625 -0.6078857421874979 +0.426 0.27227783203125 0.10675048828125 -0.6078857421874979 +0.4261250000000000512 0.267852783203125 0.105010986328125 -0.6078857421874979 +0.42625 0.267852783203125 0.105010986328125 -0.6078857421874979 +0.426375 0.263427734375 0.103271484375 -0.6078857421874979 +0.4265 0.263427734375 0.103271484375 -0.6078857421874979 +0.4266250000000000512 0.25897216796875 0.101531982421875 -0.6078857421874979 +0.42675 0.25445556640625 0.099761962890625 -0.6078857421874979 +0.426875 0.25445556640625 0.099761962890625 -0.6078857421874979 +0.427 0.249969482421875 0.097991943359375 -0.6078857421874979 +0.4271250000000000512 0.249969482421875 0.097991943359375 -0.6078857421874979 +0.42725 0.24542236328125 0.09619140625 -0.6078857421874979 +0.427375 0.2408447265625 0.09442138671875 -0.6078857421874979 +0.4275 0.2408447265625 0.09442138671875 -0.6078857421874979 +0.4276250000000000512 0.236236572265625 0.092620849609375 -0.6078857421874979 +0.42775 0.236236572265625 0.092620849609375 -0.6078857421874979 +0.427875 0.231597900390625 0.090789794921875 -0.6078857421874979 +0.428 0.226959228515625 0.088958740234375 -0.6078857421874979 +0.4281250000000000512 0.226959228515625 0.088958740234375 -0.6078857421874979 +0.42825 0.2222900390625 0.087127685546875 -0.6078857421874979 +0.428375 0.2222900390625 0.087127685546875 -0.6078857421874979 +0.4285 0.21759033203125 0.085296630859375 -0.6078857421874979 +0.4286250000000000512 0.212860107421875 0.08343505859375 -0.6078857421874979 +0.42875 0.212860107421875 0.08343505859375 -0.6078857421874979 +0.428875 0.208099365234375 0.081573486328125 -0.6078857421874979 +0.429 0.208099365234375 0.081573486328125 -0.6078857421874979 +0.4291250000000000512 0.203338623046875 0.0797119140625 -0.6078857421874979 +0.42925 0.19854736328125 0.07781982421875 -0.6078857421874979 +0.429375 0.19854736328125 0.07781982421875 -0.6078857421874979 +0.4295 0.1937255859375 0.075927734375 -0.6078857421874979 +0.4296250000000000512 0.1937255859375 0.075927734375 -0.6078857421874979 +0.42975 0.188873291015625 0.07403564453125 -0.6078857421874979 +0.429875 0.18402099609375 0.0721435546875 -0.6078857421874979 +0.43 0.18402099609375 0.0721435546875 -0.6078857421874979 +0.4301250000000000512 0.17913818359375 0.070220947265625 -0.6078857421874979 +0.43025 0.17913818359375 0.070220947265625 -0.6078857421874979 +0.430375 0.17425537109375 0.06829833984375 -0.6078857421874979 +0.4305 0.169342041015625 0.066375732421875 -0.6078857421874979 +0.4306250000000000512 0.169342041015625 0.066375732421875 -0.6078857421874979 +0.43075 0.164398193359375 0.064453125 -0.6078857421874979 +0.430875 0.164398193359375 0.064453125 -0.6078857421874979 +0.431 0.159454345703125 0.0625 -0.6078857421874979 +0.4311250000000000512 0.15447998046875 0.060546875 -0.6078857421874979 +0.43125 0.15447998046875 0.060546875 -0.6078857421874979 +0.431375 0.14947509765625 0.05859375 -0.6078857421874979 +0.4315 0.14947509765625 0.05859375 -0.6078857421874979 +0.431625000000000036 0.14447021484375 0.056640625 -0.6078857421874979 +0.43175 0.13946533203125 0.054656982421875 -0.6078857421874979 +0.431875 0.13946533203125 0.054656982421875 -0.6078857421874979 +0.432 0.134429931640625 0.052703857421875 -0.6078857421874979 +0.432125 0.134429931640625 0.052703857421875 -0.6078857421874979 +0.43225 0.129364013671875 0.05072021484375 -0.6078857421874979 +0.432375 0.124298095703125 0.048736572265625 -0.6078857421874979 +0.4325 0.124298095703125 0.048736572265625 -0.6078857421874979 +0.432625 0.119232177734375 0.0467529296875 -0.6078857421874979 +0.43275 0.119232177734375 0.0467529296875 -0.6078857421874979 +0.432875 0.1141357421875 0.04473876953125 -0.6078857421874979 +0.433 0.109039306640625 0.042724609375 -0.6078857421874979 +0.433125 0.109039306640625 0.042724609375 -0.6078857421874979 +0.43325 0.103912353515625 0.040740966796875 -0.6078857421874979 +0.433375 0.103912353515625 0.040740966796875 -0.6078857421874979 +0.4335 0.098785400390625 0.038726806640625 -0.6078857421874979 +0.433625 0.093658447265625 0.036712646484375 -0.6078857421874979 +0.43375 0.093658447265625 0.036712646484375 -0.6078857421874979 +0.433875 0.0885009765625 0.034698486328125 -0.6078857421874979 +0.434 0.0885009765625 0.034698486328125 -0.6078857421874979 +0.434125 0.083343505859375 0.032684326171875 -0.6078857421874979 +0.43425 0.07818603515625 0.0306396484375 -0.6078857421874979 +0.434375 0.07818603515625 0.0306396484375 -0.6078857421874979 +0.4345 0.072998046875 0.02862548828125 -0.6078857421874979 +0.434625 0.072998046875 0.02862548828125 -0.6078857421874979 +0.43475 0.06781005859375 0.026580810546875 -0.6078857421874979 +0.434875 0.0626220703125 0.0245361328125 -0.6078857421874979 +0.435 0.0626220703125 0.0245361328125 -0.6078857421874979 +0.435125 0.05743408203125 0.02252197265625 -0.6078857421874979 +0.43525 0.05743408203125 0.02252197265625 -0.6078857421874979 +0.435375 0.05224609375 0.020477294921875 -0.6078857421874979 +0.4355 0.047027587890625 0.0184326171875 -0.6078857421874979 +0.435625 0.047027587890625 0.0184326171875 -0.6078857421874979 +0.43575 0.04180908203125 0.016387939453125 -0.6078857421874979 +0.435875 0.04180908203125 0.016387939453125 -0.6078857421874979 +0.436 0.036590576171875 0.01434326171875 -0.6078857421874979 +0.436125 0.0313720703125 0.012298583984375 -0.6078857421874979 +0.43625 0.0313720703125 0.012298583984375 -0.6078857421874979 +0.436375 0.026123046875 0.010223388671875 -0.6078857421874979 +0.4365 0.026123046875 0.010223388671875 -0.6078857421874979 +0.436625 0.020904541015625 0.0081787109375 -0.6078857421874979 +0.43675 0.01568603515625 0.006134033203125 -0.6078857421874979 +0.436875 0.01568603515625 0.006134033203125 -0.6078857421874979 +0.437 0.01043701171875 0.00408935546875 -0.6078857421874979 +0.437125 0.01043701171875 0.00408935546875 -0.6078857421874979 +0.43725 0.005218505859375 0.002044677734375 -0.6078857421874979 +0.437375 0.0 0.0 -0.6078857421874979 +0.4375 0.0 0.0 -0.6078857421874979 +0.437625 -0.005218505859375 -0.002044677734375 -0.6078857421874979 +0.4377500000000000512 -0.005218505859375 -0.002044677734375 -0.6078857421874979 +0.437875 -0.01043701171875 -0.00408935546875 -0.6078857421874979 +0.438 -0.01568603515625 -0.006134033203125 -0.6078857421874979 +0.438125 -0.01568603515625 -0.006134033203125 -0.6078857421874979 +0.4382500000000000512 -0.020904541015625 -0.0081787109375 -0.6078857421874979 +0.438375 -0.020904541015625 -0.0081787109375 -0.6078857421874979 +0.4385 -0.026123046875 -0.010223388671875 -0.6078857421874979 +0.438625 -0.0313720703125 -0.012298583984375 -0.6078857421874979 +0.4387500000000000512 -0.0313720703125 -0.012298583984375 -0.6078857421874979 +0.438875 -0.036590576171875 -0.01434326171875 -0.6078857421874979 +0.439 -0.036590576171875 -0.01434326171875 -0.6078857421874979 +0.439125 -0.04180908203125 -0.016387939453125 -0.6078857421874979 +0.4392500000000000512 -0.047027587890625 -0.0184326171875 -0.6078857421874979 +0.439375 -0.047027587890625 -0.0184326171875 -0.6078857421874979 +0.4395 -0.05224609375 -0.020477294921875 -0.6078857421874979 +0.439625 -0.05224609375 -0.020477294921875 -0.6078857421874979 +0.4397500000000000512 -0.05743408203125 -0.02252197265625 -0.6078857421874979 +0.439875 -0.0626220703125 -0.0245361328125 -0.6078857421874979 +0.44 -0.0626220703125 -0.0245361328125 -0.6078857421874979 +0.440125 -0.06781005859375 -0.026580810546875 -0.6078857421874979 +0.4402500000000000512 -0.06781005859375 -0.026580810546875 -0.6078857421874979 +0.440375 -0.072998046875 -0.02862548828125 -0.6078857421874979 +0.4405 -0.07818603515625 -0.0306396484375 -0.6078857421874979 +0.440625 -0.07818603515625 -0.0306396484375 -0.6078857421874979 +0.4407500000000000512 -0.083343505859375 -0.032684326171875 -0.6078857421874979 +0.440875 -0.083343505859375 -0.032684326171875 -0.6078857421874979 +0.441 -0.0885009765625 -0.034698486328125 -0.6078857421874979 +0.441125 -0.093658447265625 -0.036712646484375 -0.6078857421874979 +0.4412500000000000512 -0.093658447265625 -0.036712646484375 -0.6078857421874979 +0.441375 -0.098785400390625 -0.038726806640625 -0.6078857421874979 +0.4415 -0.098785400390625 -0.038726806640625 -0.6078857421874979 +0.441625 -0.103912353515625 -0.040740966796875 -0.6078857421874979 +0.4417500000000000512 -0.109039306640625 -0.042724609375 -0.6078857421874979 +0.441875 -0.109039306640625 -0.042724609375 -0.6078857421874979 +0.442 -0.1141357421875 -0.04473876953125 -0.6078857421874979 +0.442125 -0.1141357421875 -0.04473876953125 -0.6078857421874979 +0.4422500000000000512 -0.119232177734375 -0.0467529296875 -0.6078857421874979 +0.442375 -0.124298095703125 -0.048736572265625 -0.6078857421874979 +0.4425 -0.124298095703125 -0.048736572265625 -0.6078857421874979 +0.442625 -0.129364013671875 -0.05072021484375 -0.6078857421874979 +0.4427500000000000512 -0.129364013671875 -0.05072021484375 -0.6078857421874979 +0.442875 -0.134429931640625 -0.052703857421875 -0.6078857421874979 +0.443 -0.13946533203125 -0.054656982421875 -0.6078857421874979 +0.443125 -0.13946533203125 -0.054656982421875 -0.6078857421874979 +0.4432500000000000512 -0.14447021484375 -0.056640625 -0.6078857421874979 +0.443375 -0.14447021484375 -0.056640625 -0.6078857421874979 +0.4435 -0.14947509765625 -0.05859375 -0.6078857421874979 +0.443625 -0.15447998046875 -0.060546875 -0.6078857421874979 +0.4437500000000000512 -0.15447998046875 -0.060546875 -0.6078857421874979 +0.443875 -0.159454345703125 -0.0625 -0.6078857421874979 +0.444 -0.159454345703125 -0.0625 -0.6078857421874979 +0.444125 -0.164398193359375 -0.064453125 -0.6078857421874979 +0.4442500000000000512 -0.169342041015625 -0.066375732421875 -0.6078857421874979 +0.444375 -0.169342041015625 -0.066375732421875 -0.6078857421874979 +0.4445 -0.17425537109375 -0.06829833984375 -0.6078857421874979 +0.444625 -0.17425537109375 -0.06829833984375 -0.6078857421874979 +0.4447500000000000512 -0.17913818359375 -0.070220947265625 -0.6078857421874979 +0.444875 -0.18402099609375 -0.0721435546875 -0.6078857421874979 +0.445 -0.18402099609375 -0.0721435546875 -0.6078857421874979 +0.445125 -0.188873291015625 -0.07403564453125 -0.6078857421874979 +0.4452500000000000512 -0.188873291015625 -0.07403564453125 -0.6078857421874979 +0.445375 -0.1937255859375 -0.075927734375 -0.6078857421874979 +0.4455 -0.19854736328125 -0.07781982421875 -0.6078857421874979 +0.445625 -0.19854736328125 -0.07781982421875 -0.6078857421874979 +0.4457500000000000512 -0.203338623046875 -0.0797119140625 -0.6078857421874979 +0.445875 -0.203338623046875 -0.0797119140625 -0.6078857421874979 +0.446 -0.208099365234375 -0.081573486328125 -0.6078857421874979 +0.446125 -0.212860107421875 -0.08343505859375 -0.6078857421874979 +0.4462500000000000512 -0.212860107421875 -0.08343505859375 -0.6078857421874979 +0.446375 -0.21759033203125 -0.085296630859375 -0.6078857421874979 +0.4465 -0.21759033203125 -0.085296630859375 -0.6078857421874979 +0.446625 -0.2222900390625 -0.087127685546875 -0.6078857421874979 +0.4467500000000000512 -0.226959228515625 -0.088958740234375 -0.6078857421874979 +0.446875 -0.226959228515625 -0.088958740234375 -0.6078857421874979 +0.447 -0.231597900390625 -0.090789794921875 -0.6078857421874979 +0.447125 -0.231597900390625 -0.090789794921875 -0.6078857421874979 +0.447250000000000036 -0.236236572265625 -0.092620849609375 -0.6078857421874979 +0.447375 -0.2408447265625 -0.09442138671875 -0.6078857421874979 +0.4475 -0.2408447265625 -0.09442138671875 -0.6078857421874979 +0.447625 -0.24542236328125 -0.09619140625 -0.6078857421874979 +0.447750000000000036 -0.24542236328125 -0.09619140625 -0.6078857421874979 +0.447875 -0.249969482421875 -0.097991943359375 -0.6078857421874979 +0.448 -0.25445556640625 -0.191192626953125 -0.2486572265624977 +0.448125 -0.25445556640625 -0.191192626953125 -0.2486572265624977 +0.44825 -0.25897216796875 -0.194549560546875 -0.2486572265624977 +0.448375 -0.25897216796875 -0.194549560546875 -0.2486572265624977 +0.4485 -0.263427734375 -0.197906494140625 -0.2486572265624977 +0.448625 -0.267852783203125 -0.20123291015625 -0.2486572265624977 +0.44875 -0.267852783203125 -0.20123291015625 -0.2486572265624977 +0.448875 -0.27227783203125 -0.204559326171875 -0.2486572265624977 +0.449 -0.27227783203125 -0.204559326171875 -0.2486572265624977 +0.449125 -0.276641845703125 -0.20782470703125 -0.2486572265624977 +0.44925 -0.280975341796875 -0.211090087890625 -0.2486572265624977 +0.449375 -0.280975341796875 -0.211090087890625 -0.2486572265624977 +0.4495 -0.285308837890625 -0.21435546875 -0.2486572265624977 +0.449625 -0.285308837890625 -0.21435546875 -0.2486572265624977 +0.44975 -0.289581298828125 -0.217559814453125 -0.2486572265624977 +0.449875 -0.2938232421875 -0.22076416015625 -0.2486572265624977 +0.45 -0.2938232421875 -0.22076416015625 -0.2486572265624977 +0.450125 -0.298065185546875 -0.22393798828125 -0.2486572265624977 +0.45025 -0.298065185546875 -0.22393798828125 -0.2486572265624977 +0.450375 -0.30224609375 -0.227081298828125 -0.2486572265624977 +0.4505 -0.306396484375 -0.230194091796875 -0.2486572265624977 +0.450625 -0.306396484375 -0.230194091796875 -0.2486572265624977 +0.45075 -0.310516357421875 -0.233306884765625 -0.2486572265624977 +0.450875 -0.310516357421875 -0.233306884765625 -0.2486572265624977 +0.451 -0.314605712890625 -0.236358642578125 -0.2486572265624977 +0.451125 -0.31866455078125 -0.239410400390625 -0.2486572265624977 +0.45125 -0.31866455078125 -0.239410400390625 -0.2486572265624977 +0.451375 -0.322662353515625 -0.242431640625 -0.2486572265624977 +0.4515 -0.322662353515625 -0.242431640625 -0.2486572265624977 +0.451625 -0.32666015625 -0.24542236328125 -0.2486572265624977 +0.45175 -0.330596923828125 -0.248382568359375 -0.2486572265624977 +0.451875 -0.330596923828125 -0.248382568359375 -0.2486572265624977 +0.452 -0.334503173828125 -0.251312255859375 -0.2486572265624977 +0.452125 -0.334503173828125 -0.251312255859375 -0.2486572265624977 +0.45225 -0.33837890625 -0.254241943359375 -0.2486572265624977 +0.452375 -0.34222412109375 -0.257110595703125 -0.2486572265624977 +0.4525 -0.34222412109375 -0.257110595703125 -0.2486572265624977 +0.452625 -0.34600830078125 -0.25994873046875 -0.2486572265624977 +0.45275 -0.34600830078125 -0.25994873046875 -0.2486572265624977 +0.452875 -0.349761962890625 -0.262786865234375 -0.2486572265624977 +0.453 -0.353485107421875 -0.26556396484375 -0.2486572265624977 +0.453125 -0.353485107421875 -0.26556396484375 -0.2486572265624977 +0.45325 -0.357177734375 -0.268341064453125 -0.2486572265624977 +0.4533750000000000512 -0.357177734375 -0.268341064453125 -0.2486572265624977 +0.4535 -0.360809326171875 -0.271087646484375 -0.2486572265624977 +0.453625 -0.36444091796875 -0.2738037109375 -0.2486572265624977 +0.45375 -0.36444091796875 -0.2738037109375 -0.2486572265624977 +0.4538750000000000512 -0.36798095703125 -0.276458740234375 -0.2486572265624977 +0.454 -0.36798095703125 -0.276458740234375 -0.2486572265624977 +0.454125 -0.37152099609375 -0.27911376953125 -0.2486572265624977 +0.45425 -0.375 -0.28173828125 -0.2486572265624977 +0.4543750000000000512 -0.375 -0.28173828125 -0.2486572265624977 +0.4545 -0.378448486328125 -0.284332275390625 -0.2486572265624977 +0.454625 -0.378448486328125 -0.284332275390625 -0.2486572265624977 +0.45475 -0.3818359375 -0.286865234375 -0.2486572265624977 +0.4548750000000000512 -0.38519287109375 -0.289398193359375 -0.2486572265624977 +0.455 -0.38519287109375 -0.289398193359375 -0.2486572265624977 +0.455125 -0.388519287109375 -0.2918701171875 -0.2486572265624977 +0.45525 -0.388519287109375 -0.2918701171875 -0.2486572265624977 +0.4553750000000000512 -0.39178466796875 -0.294342041015625 -0.2486572265624977 +0.4555 -0.39501953125 -0.296783447265625 -0.2486572265624977 +0.455625 -0.39501953125 -0.296783447265625 -0.2486572265624977 +0.45575 -0.398193359375 -0.299163818359375 -0.2486572265624977 +0.4558750000000000512 -0.398193359375 -0.299163818359375 -0.2486572265624977 +0.456 -0.401336669921875 -0.301513671875 -0.2486572265624977 +0.456125 -0.404449462890625 -0.303863525390625 -0.2486572265624977 +0.45625 -0.404449462890625 -0.303863525390625 -0.2486572265624977 +0.4563750000000000512 -0.407501220703125 -0.30615234375 -0.2486572265624977 +0.4565 -0.407501220703125 -0.30615234375 -0.2486572265624977 +0.456625 -0.4105224609375 -0.30841064453125 -0.2486572265624977 +0.45675 -0.413482666015625 -0.310638427734375 -0.2486572265624977 +0.4568750000000000512 -0.413482666015625 -0.310638427734375 -0.2486572265624977 +0.457 -0.416412353515625 -0.312835693359375 -0.2486572265624977 +0.457125 -0.416412353515625 -0.312835693359375 -0.2486572265624977 +0.45725 -0.419281005859375 -0.31500244140625 -0.2486572265624977 +0.4573750000000000512 -0.422119140625 -0.317138671875 -0.2486572265624977 +0.4575 -0.422119140625 -0.317138671875 -0.2486572265624977 +0.457625 -0.424896240234375 -0.3192138671875 -0.2486572265624977 +0.45775 -0.424896240234375 -0.3192138671875 -0.2486572265624977 +0.4578750000000000512 -0.4276123046875 -0.321258544921875 -0.2486572265624977 +0.458 -0.4302978515625 -0.323272705078125 -0.2486572265624977 +0.458125 -0.4302978515625 -0.323272705078125 -0.2486572265624977 +0.45825 -0.432952880859375 -0.325286865234375 -0.2486572265624977 +0.4583750000000000512 -0.432952880859375 -0.325286865234375 -0.2486572265624977 +0.4585 -0.435546875 -0.32720947265625 -0.2486572265624977 +0.458625 -0.438079833984375 -0.329132080078125 -0.2486572265624977 +0.45875 -0.438079833984375 -0.329132080078125 -0.2486572265624977 +0.4588750000000000512 -0.440582275390625 -0.33099365234375 -0.2486572265624977 +0.459 -0.440582275390625 -0.33099365234375 -0.2486572265624977 +0.459125 -0.44305419921875 -0.332855224609375 -0.2486572265624977 +0.45925 -0.4454345703125 -0.33465576171875 -0.2486572265624977 +0.4593750000000000512 -0.4454345703125 -0.33465576171875 -0.2486572265624977 +0.4595 -0.447784423828125 -0.33642578125 -0.2486572265624977 +0.459625 -0.447784423828125 -0.33642578125 -0.2486572265624977 +0.45975 -0.450103759765625 -0.338134765625 -0.2486572265624977 +0.4598750000000000512 -0.452362060546875 -0.33984375 -0.2486572265624977 +0.46 -0.452362060546875 -0.33984375 -0.2486572265624977 +0.460125 -0.454559326171875 -0.34149169921875 -0.2486572265624977 +0.46025 -0.454559326171875 -0.34149169921875 -0.2486572265624977 +0.4603750000000000512 -0.45672607421875 -0.343109130859375 -0.2486572265624977 +0.4605 -0.458831787109375 -0.344696044921875 -0.2486572265624977 +0.460625 -0.458831787109375 -0.344696044921875 -0.2486572265624977 +0.46075 -0.46087646484375 -0.34625244140625 -0.2486572265624977 +0.4608750000000000512 -0.46087646484375 -0.34625244140625 -0.2486572265624977 +0.461 -0.462890625 -0.347747802734375 -0.2486572265624977 +0.461125 -0.464813232421875 -0.349212646484375 -0.2486572265624977 +0.46125 -0.464813232421875 -0.349212646484375 -0.2486572265624977 +0.461375000000000052 -0.46673583984375 -0.35064697265625 -0.2486572265624977 +0.4615 -0.46673583984375 -0.35064697265625 -0.2486572265624977 +0.461625 -0.46856689453125 -0.352020263671875 -0.2486572265624977 +0.46175 -0.470367431640625 -0.3533935546875 -0.2486572265624977 +0.461875000000000052 -0.470367431640625 -0.3533935546875 -0.2486572265624977 +0.462 -0.472137451171875 -0.354705810546875 -0.2486572265624977 +0.462125 -0.472137451171875 -0.354705810546875 -0.2486572265624977 +0.46225 -0.47381591796875 -0.355987548828125 -0.2486572265624977 +0.462375000000000052 -0.4754638671875 -0.357208251953125 -0.2486572265624977 +0.4625 -0.4754638671875 -0.357208251953125 -0.2486572265624977 +0.462625 -0.47705078125 -0.3583984375 -0.2486572265624977 +0.46275 -0.47705078125 -0.3583984375 -0.2486572265624977 +0.462875000000000064 -0.478607177734375 -0.35955810546875 -0.2486572265624977 +0.463 -0.480072021484375 -0.360687255859375 -0.2486572265624977 +0.463125 -0.480072021484375 -0.360687255859375 -0.2486572265624977 +0.46325 -0.48150634765625 -0.36175537109375 -0.2486572265624977 +0.463375000000000064 -0.48150634765625 -0.36175537109375 -0.2486572265624977 +0.4635 -0.48291015625 -0.36279296875 -0.2486572265624977 +0.463625 -0.484222412109375 -0.363800048828125 -0.2486572265624977 +0.46375 -0.484222412109375 -0.363800048828125 -0.2486572265624977 +0.463875000000000064 -0.485504150390625 -0.36474609375 -0.2486572265624977 +0.464 -0.485504150390625 -0.36474609375 -0.2486572265624977 +0.464125 -0.486724853515625 -0.36566162109375 -0.2486572265624977 +0.46425 -0.487884521484375 -0.366546630859375 -0.2486572265624977 +0.464375 -0.487884521484375 -0.366546630859375 -0.2486572265624977 +0.4645 -0.489013671875 -0.36737060546875 -0.2486572265624977 +0.464625 -0.489013671875 -0.36737060546875 -0.2486572265624977 +0.46475 -0.490081787109375 -0.368194580078125 -0.2486572265624977 +0.464875 -0.4910888671875 -0.368927001953125 -0.2486572265624977 +0.465 -0.4910888671875 -0.368927001953125 -0.2486572265624977 +0.465125 -0.492034912109375 -0.369659423828125 -0.2486572265624977 +0.46525 -0.492034912109375 -0.369659423828125 -0.2486572265624977 +0.465375 -0.492950439453125 -0.370330810546875 -0.2486572265624977 +0.4655 -0.4937744140625 -0.3709716796875 -0.2486572265624977 +0.465625 -0.4937744140625 -0.3709716796875 -0.2486572265624977 +0.46575 -0.49456787109375 -0.371551513671875 -0.2486572265624977 +0.465875 -0.49456787109375 -0.371551513671875 -0.2486572265624977 +0.466 -0.49530029296875 -0.372100830078125 -0.2486572265624977 +0.466125 -0.496002197265625 -0.37261962890625 -0.2486572265624977 +0.46625 -0.496002197265625 -0.37261962890625 -0.2486572265624977 +0.466375 -0.496612548828125 -0.37310791015625 -0.2486572265624977 +0.4665 -0.496612548828125 -0.37310791015625 -0.2486572265624977 +0.466625 -0.4971923828125 -0.37353515625 -0.2486572265624977 +0.46675 -0.497711181640625 -0.373931884765625 -0.2486572265624977 +0.466875 -0.497711181640625 -0.373931884765625 -0.2486572265624977 +0.467 -0.498199462890625 -0.374267578125 -0.2486572265624977 +0.467125 -0.498199462890625 -0.374267578125 -0.2486572265624977 +0.46725 -0.49859619140625 -0.374603271484375 -0.2486572265624977 +0.467375 -0.49896240234375 -0.374847412109375 -0.2486572265624977 +0.4675 -0.49896240234375 -0.374847412109375 -0.2486572265624977 +0.467625 -0.499267578125 -0.375091552734375 -0.2486572265624977 +0.46775 -0.499267578125 -0.375091552734375 -0.2486572265624977 +0.467875 -0.49951171875 -0.375274658203125 -0.2486572265624977 +0.468 -0.49969482421875 -0.375396728515625 -0.2486572265624977 +0.468125 -0.49969482421875 -0.375396728515625 -0.2486572265624977 +0.46825 -0.49981689453125 -0.375518798828125 -0.2486572265624977 +0.468375 -0.49981689453125 -0.375518798828125 -0.2486572265624977 +0.4685 -0.499908447265625 -0.375579833984375 -0.2486572265624977 +0.468625 -0.49993896484375 -0.3756103515625 -0.2486572265624977 +0.46875 -0.49993896484375 -0.3756103515625 -0.2486572265624977 +0.468875 -0.499908447265625 -0.375579833984375 -0.2486572265624977 +0.469000000000000052 -0.499908447265625 -0.375579833984375 -0.2486572265624977 +0.469125 -0.49981689453125 -0.375518798828125 -0.2486572265624977 +0.46925 -0.49969482421875 -0.375396728515625 -0.2486572265624977 +0.469375 -0.49969482421875 -0.375396728515625 -0.2486572265624977 +0.469500000000000052 -0.49951171875 -0.375274658203125 -0.2486572265624977 +0.469625 -0.49951171875 -0.375274658203125 -0.2486572265624977 +0.46975 -0.499267578125 -0.375091552734375 -0.2486572265624977 +0.469875 -0.49896240234375 -0.374847412109375 -0.2486572265624977 +0.470000000000000052 -0.49896240234375 -0.374847412109375 -0.2486572265624977 +0.470125 -0.49859619140625 -0.374603271484375 -0.2486572265624977 +0.47025 -0.49859619140625 -0.374603271484375 -0.2486572265624977 +0.470375 -0.498199462890625 -0.374267578125 -0.2486572265624977 +0.470500000000000052 -0.497711181640625 -0.373931884765625 -0.2486572265624977 +0.470625 -0.497711181640625 -0.373931884765625 -0.2486572265624977 +0.47075 -0.4971923828125 -0.37353515625 -0.2486572265624977 +0.470875 -0.4971923828125 -0.37353515625 -0.2486572265624977 +0.471000000000000052 -0.496612548828125 -0.37310791015625 -0.2486572265624977 +0.471125 -0.496002197265625 -0.37261962890625 -0.2486572265624977 +0.47125 -0.496002197265625 -0.37261962890625 -0.2486572265624977 +0.471375 -0.49530029296875 -0.372100830078125 -0.2486572265624977 +0.471500000000000052 -0.49530029296875 -0.372100830078125 -0.2486572265624977 +0.471625 -0.49456787109375 -0.371551513671875 -0.2486572265624977 +0.47175 -0.4937744140625 -0.3709716796875 -0.2486572265624977 +0.471875 -0.4937744140625 -0.3709716796875 -0.2486572265624977 +0.472000000000000052 -0.492950439453125 -0.370330810546875 -0.2486572265624977 +0.472125 -0.492950439453125 -0.370330810546875 -0.2486572265624977 +0.47225 -0.492034912109375 -0.369659423828125 -0.2486572265624977 +0.472375 -0.4910888671875 -0.368927001953125 -0.2486572265624977 +0.472500000000000052 -0.4910888671875 -0.368927001953125 -0.2486572265624977 +0.472625 -0.490081787109375 -0.368194580078125 -0.2486572265624977 +0.47275 -0.490081787109375 -0.368194580078125 -0.2486572265624977 +0.472875 -0.489013671875 -0.36737060546875 -0.2486572265624977 +0.473000000000000052 -0.487884521484375 -0.366546630859375 -0.2486572265624977 +0.473125 -0.487884521484375 -0.366546630859375 -0.2486572265624977 +0.47325 -0.486724853515625 -0.36566162109375 -0.2486572265624977 +0.473375 -0.486724853515625 -0.36566162109375 -0.2486572265624977 +0.473500000000000052 -0.485504150390625 -0.36474609375 -0.2486572265624977 +0.473625 -0.484222412109375 -0.363800048828125 -0.2486572265624977 +0.47375 -0.484222412109375 -0.363800048828125 -0.2486572265624977 +0.473875 -0.48291015625 -0.36279296875 -0.2486572265624977 +0.474000000000000052 -0.48291015625 -0.36279296875 -0.2486572265624977 +0.474125 -0.48150634765625 -0.36175537109375 -0.2486572265624977 +0.47425 -0.480072021484375 -0.360687255859375 -0.2486572265624977 +0.474375 -0.480072021484375 -0.360687255859375 -0.2486572265624977 +0.474500000000000052 -0.478607177734375 -0.35955810546875 -0.2486572265624977 +0.474625 -0.478607177734375 -0.35955810546875 -0.2486572265624977 +0.47475 -0.47705078125 -0.3583984375 -0.2486572265624977 +0.474875 -0.4754638671875 -0.357208251953125 -0.2486572265624977 +0.475000000000000052 -0.4754638671875 -0.357208251953125 -0.2486572265624977 +0.475125 -0.47381591796875 -0.355987548828125 -0.2486572265624977 +0.47525 -0.47381591796875 -0.355987548828125 -0.2486572265624977 +0.475375 -0.472137451171875 -0.354705810546875 -0.2486572265624977 +0.475500000000000052 -0.470367431640625 -0.3533935546875 -0.2486572265624977 +0.475625 -0.470367431640625 -0.3533935546875 -0.2486572265624977 +0.47575 -0.46856689453125 -0.352020263671875 -0.2486572265624977 +0.475875 -0.46856689453125 -0.352020263671875 -0.2486572265624977 +0.476000000000000052 -0.46673583984375 -0.35064697265625 -0.2486572265624977 +0.476125 -0.464813232421875 -0.349212646484375 -0.2486572265624977 +0.47625 -0.464813232421875 -0.349212646484375 -0.2486572265624977 +0.476375 -0.462890625 -0.347747802734375 -0.2486572265624977 +0.476500000000000052 -0.462890625 -0.347747802734375 -0.2486572265624977 +0.476625 -0.46087646484375 -0.34625244140625 -0.2486572265624977 +0.47675 -0.458831787109375 -0.344696044921875 -0.2486572265624977 +0.476875 -0.458831787109375 -0.344696044921875 -0.2486572265624977 +0.477000000000000052 -0.45672607421875 -0.343109130859375 -0.2486572265624977 +0.477125 -0.45672607421875 -0.343109130859375 -0.2486572265624977 +0.47725 -0.454559326171875 -0.34149169921875 -0.2486572265624977 +0.477375 -0.452362060546875 -0.33984375 -0.2486572265624977 +0.477500000000000052 -0.452362060546875 -0.33984375 -0.2486572265624977 +0.477625 -0.450103759765625 -0.338134765625 -0.2486572265624977 +0.47775 -0.450103759765625 -0.338134765625 -0.2486572265624977 +0.477875 -0.447784423828125 -0.33642578125 -0.2486572265624977 +0.478000000000000052 -0.4454345703125 -0.33465576171875 -0.2486572265624977 +0.478125 -0.4454345703125 -0.33465576171875 -0.2486572265624977 +0.47825 -0.44305419921875 -0.332855224609375 -0.2486572265624977 +0.478375 -0.44305419921875 -0.332855224609375 -0.2486572265624977 +0.478500000000000064 -0.440582275390625 -0.33099365234375 -0.2486572265624977 +0.478625 -0.438079833984375 -0.329132080078125 -0.2486572265624977 +0.47875 -0.438079833984375 -0.329132080078125 -0.2486572265624977 +0.478875 -0.435546875 -0.32720947265625 -0.2486572265624977 +0.479000000000000064 -0.435546875 -0.32720947265625 -0.2486572265624977 +0.479125 -0.432952880859375 -0.325286865234375 -0.2486572265624977 +0.47925 -0.4302978515625 -0.323272705078125 -0.2486572265624977 +0.479375 -0.4302978515625 -0.323272705078125 -0.2486572265624977 +0.479500000000000064 -0.4276123046875 -0.321258544921875 -0.2486572265624977 +0.479625 -0.4276123046875 -0.321258544921875 -0.2486572265624977 +0.47975 -0.424896240234375 -0.3192138671875 -0.2486572265624977 +0.479875 -0.422119140625 -0.317138671875 -0.2486572265624977 +0.48 -0.358673095703125 -0.422119140625 0.1501953125000029 +0.480125 -0.35626220703125 -0.419281005859375 0.1501953125000029 +0.48025 -0.35626220703125 -0.419281005859375 0.1501953125000029 +0.480375 -0.353851318359375 -0.416412353515625 0.1501953125000029 +0.4805 -0.351348876953125 -0.413482666015625 0.1501953125000029 +0.480625 -0.351348876953125 -0.413482666015625 0.1501953125000029 +0.48075 -0.348846435546875 -0.4105224609375 0.1501953125000029 +0.480875 -0.348846435546875 -0.4105224609375 0.1501953125000029 +0.481 -0.346282958984375 -0.407501220703125 0.1501953125000029 +0.481125 -0.34368896484375 -0.404449462890625 0.1501953125000029 +0.48125 -0.34368896484375 -0.404449462890625 0.1501953125000029 +0.481375 -0.341033935546875 -0.401336669921875 0.1501953125000029 +0.4815 -0.341033935546875 -0.401336669921875 0.1501953125000029 +0.481625 -0.33837890625 -0.398193359375 0.1501953125000029 +0.48175 -0.335662841796875 -0.39501953125 0.1501953125000029 +0.481875 -0.335662841796875 -0.39501953125 0.1501953125000029 +0.482 -0.332916259765625 -0.39178466796875 0.1501953125000029 +0.482125 -0.332916259765625 -0.39178466796875 0.1501953125000029 +0.48225 -0.33013916015625 -0.388519287109375 0.1501953125000029 +0.482375 -0.32733154296875 -0.38519287109375 0.1501953125000029 +0.4825 -0.32733154296875 -0.38519287109375 0.1501953125000029 +0.482625 -0.324462890625 -0.3818359375 0.1501953125000029 +0.48275 -0.324462890625 -0.3818359375 0.1501953125000029 +0.482875 -0.321563720703125 -0.378448486328125 0.1501953125000029 +0.483 -0.318634033203125 -0.375 0.1501953125000029 +0.483125 -0.318634033203125 -0.375 0.1501953125000029 +0.48325 -0.315704345703125 -0.37152099609375 0.1501953125000029 +0.483375 -0.315704345703125 -0.37152099609375 0.1501953125000029 +0.4835 -0.31268310546875 -0.36798095703125 0.1501953125000029 +0.483625 -0.309661865234375 -0.36444091796875 0.1501953125000029 +0.48375 -0.309661865234375 -0.36444091796875 0.1501953125000029 +0.483875 -0.306610107421875 -0.360809326171875 0.1501953125000029 +0.484 -0.306610107421875 -0.360809326171875 0.1501953125000029 +0.484125 -0.30352783203125 -0.357177734375 0.1501953125000029 +0.48425 -0.300384521484375 -0.353485107421875 0.1501953125000029 +0.484375 -0.300384521484375 -0.353485107421875 0.1501953125000029 +0.4845 -0.297210693359375 -0.349761962890625 0.1501953125000029 +0.484625000000000052 -0.297210693359375 -0.349761962890625 0.1501953125000029 +0.48475 -0.294036865234375 -0.34600830078125 0.1501953125000029 +0.484875 -0.290802001953125 -0.34222412109375 0.1501953125000029 +0.485 -0.290802001953125 -0.34222412109375 0.1501953125000029 +0.485125000000000052 -0.28753662109375 -0.33837890625 0.1501953125000029 +0.48525 -0.28753662109375 -0.33837890625 0.1501953125000029 +0.485375 -0.28424072265625 -0.334503173828125 0.1501953125000029 +0.4855 -0.28094482421875 -0.330596923828125 0.1501953125000029 +0.485625000000000052 -0.28094482421875 -0.330596923828125 0.1501953125000029 +0.48575 -0.277587890625 -0.32666015625 0.1501953125000029 +0.485875 -0.277587890625 -0.32666015625 0.1501953125000029 +0.486 -0.274200439453125 -0.322662353515625 0.1501953125000029 +0.486125000000000052 -0.270782470703125 -0.31866455078125 0.1501953125000029 +0.48625 -0.270782470703125 -0.31866455078125 0.1501953125000029 +0.486375 -0.267333984375 -0.314605712890625 0.1501953125000029 +0.4865 -0.267333984375 -0.314605712890625 0.1501953125000029 +0.486625000000000052 -0.26385498046875 -0.310516357421875 0.1501953125000029 +0.48675 -0.2603759765625 -0.306396484375 0.1501953125000029 +0.486875 -0.2603759765625 -0.306396484375 0.1501953125000029 +0.487 -0.2568359375 -0.30224609375 0.1501953125000029 +0.487125000000000052 -0.2568359375 -0.30224609375 0.1501953125000029 +0.48725 -0.253265380859375 -0.298065185546875 0.1501953125000029 +0.487375 -0.24969482421875 -0.2938232421875 0.1501953125000029 +0.4875 -0.24969482421875 -0.2938232421875 0.1501953125000029 +0.487625000000000052 -0.24609375 -0.289581298828125 0.1501953125000029 +0.48775 -0.24609375 -0.289581298828125 0.1501953125000029 +0.487875 -0.242431640625 -0.285308837890625 0.1501953125000029 +0.488 -0.23876953125 -0.280975341796875 0.1501953125000029 +0.488125000000000052 -0.23876953125 -0.280975341796875 0.1501953125000029 +0.48825 -0.235076904296875 -0.276641845703125 0.1501953125000029 +0.488375 -0.235076904296875 -0.276641845703125 0.1501953125000029 +0.4885 -0.231353759765625 -0.27227783203125 0.1501953125000029 +0.488625000000000052 -0.227630615234375 -0.267852783203125 0.1501953125000029 +0.48875 -0.227630615234375 -0.267852783203125 0.1501953125000029 +0.488875 -0.223846435546875 -0.263427734375 0.1501953125000029 +0.489 -0.223846435546875 -0.263427734375 0.1501953125000029 +0.489125000000000052 -0.220062255859375 -0.25897216796875 0.1501953125000029 +0.48925 -0.21624755859375 -0.25445556640625 0.1501953125000029 +0.489375 -0.21624755859375 -0.25445556640625 0.1501953125000029 +0.4895 -0.21240234375 -0.249969482421875 0.1501953125000029 +0.489625000000000052 -0.21240234375 -0.249969482421875 0.1501953125000029 +0.48975 -0.208526611328125 -0.24542236328125 0.1501953125000029 +0.489875 -0.20465087890625 -0.2408447265625 0.1501953125000029 +0.49 -0.20465087890625 -0.2408447265625 0.1501953125000029 +0.490125000000000052 -0.20074462890625 -0.236236572265625 0.1501953125000029 +0.49025 -0.20074462890625 -0.236236572265625 0.1501953125000029 +0.490375 -0.196807861328125 -0.231597900390625 0.1501953125000029 +0.4905 -0.192840576171875 -0.226959228515625 0.1501953125000029 +0.490625000000000052 -0.192840576171875 -0.226959228515625 0.1501953125000029 +0.49075 -0.188873291015625 -0.2222900390625 0.1501953125000029 +0.490875 -0.188873291015625 -0.2222900390625 0.1501953125000029 +0.491 -0.18487548828125 -0.21759033203125 0.1501953125000029 +0.491125000000000052 -0.180877685546875 -0.212860107421875 0.1501953125000029 +0.49125 -0.180877685546875 -0.212860107421875 0.1501953125000029 +0.491375 -0.17681884765625 -0.208099365234375 0.1501953125000029 +0.4915 -0.17681884765625 -0.208099365234375 0.1501953125000029 +0.491625000000000052 -0.172760009765625 -0.203338623046875 0.1501953125000029 +0.49175 -0.168701171875 -0.19854736328125 0.1501953125000029 +0.491875 -0.168701171875 -0.19854736328125 0.1501953125000029 +0.492 -0.16461181640625 -0.1937255859375 0.1501953125000029 +0.492125000000000052 -0.16461181640625 -0.1937255859375 0.1501953125000029 +0.49225 -0.160491943359375 -0.188873291015625 0.1501953125000029 +0.492375 -0.1563720703125 -0.18402099609375 0.1501953125000029 +0.4925 -0.1563720703125 -0.18402099609375 0.1501953125000029 +0.492625000000000052 -0.1522216796875 -0.17913818359375 0.1501953125000029 +0.49275 -0.1522216796875 -0.17913818359375 0.1501953125000029 +0.492875 -0.1480712890625 -0.17425537109375 0.1501953125000029 +0.493 -0.143890380859375 -0.169342041015625 0.1501953125000029 +0.493125000000000052 -0.143890380859375 -0.169342041015625 0.1501953125000029 +0.49325 -0.139678955078125 -0.164398193359375 0.1501953125000029 +0.493375 -0.139678955078125 -0.164398193359375 0.1501953125000029 +0.4935 -0.135498046875 -0.159454345703125 0.1501953125000029 +0.493625000000000052 -0.131256103515625 -0.15447998046875 0.1501953125000029 +0.49375 -0.131256103515625 -0.15447998046875 0.1501953125000029 +0.493875 -0.12701416015625 -0.14947509765625 0.1501953125000029 +0.494 -0.12701416015625 -0.14947509765625 0.1501953125000029 +0.494125000000000064 -0.122772216796875 -0.14447021484375 0.1501953125000029 +0.49425 -0.118499755859375 -0.13946533203125 0.1501953125000029 +0.494375 -0.118499755859375 -0.13946533203125 0.1501953125000029 +0.4945 -0.114227294921875 -0.134429931640625 0.1501953125000029 +0.494625000000000064 -0.114227294921875 -0.134429931640625 0.1501953125000029 +0.49475 -0.10992431640625 -0.129364013671875 0.1501953125000029 +0.494875 -0.105621337890625 -0.124298095703125 0.1501953125000029 +0.495 -0.105621337890625 -0.124298095703125 0.1501953125000029 +0.495125000000000064 -0.101318359375 -0.119232177734375 0.1501953125000029 +0.49525 -0.101318359375 -0.119232177734375 0.1501953125000029 +0.495375 -0.09698486328125 -0.1141357421875 0.1501953125000029 +0.4955 -0.0926513671875 -0.109039306640625 0.1501953125000029 +0.495625000000000064 -0.0926513671875 -0.109039306640625 0.1501953125000029 +0.49575 -0.08831787109375 -0.103912353515625 0.1501953125000029 +0.495875 -0.08831787109375 -0.103912353515625 0.1501953125000029 +0.496 -0.083953857421875 -0.098785400390625 0.1501953125000029 +0.496125 -0.07958984375 -0.093658447265625 0.1501953125000029 +0.49625 -0.07958984375 -0.093658447265625 0.1501953125000029 +0.496375 -0.0751953125 -0.0885009765625 0.1501953125000029 +0.4965 -0.0751953125 -0.0885009765625 0.1501953125000029 +0.496625 -0.070831298828125 -0.083343505859375 0.1501953125000029 +0.49675 -0.066436767578125 -0.07818603515625 0.1501953125000029 +0.496875 -0.066436767578125 -0.07818603515625 0.1501953125000029 +0.497 -0.062042236328125 -0.072998046875 0.1501953125000029 +0.497125 -0.062042236328125 -0.072998046875 0.1501953125000029 +0.49725 -0.0576171875 -0.06781005859375 0.1501953125000029 +0.497375 -0.05322265625 -0.0626220703125 0.1501953125000029 +0.4975 -0.05322265625 -0.0626220703125 0.1501953125000029 +0.497625 -0.048797607421875 -0.05743408203125 0.1501953125000029 +0.49775 -0.048797607421875 -0.05743408203125 0.1501953125000029 +0.497875 -0.044403076171875 -0.05224609375 0.1501953125000029 +0.498 -0.039947509765625 -0.047027587890625 0.1501953125000029 +0.498125 -0.039947509765625 -0.047027587890625 0.1501953125000029 +0.49825 -0.0355224609375 -0.04180908203125 0.1501953125000029 +0.498375 -0.0355224609375 -0.04180908203125 0.1501953125000029 +0.4985 -0.031097412109375 -0.036590576171875 0.1501953125000029 +0.498625 -0.026641845703125 -0.0313720703125 0.1501953125000029 +0.49875 -0.026641845703125 -0.0313720703125 0.1501953125000029 +0.498875 -0.022216796875 -0.026123046875 0.1501953125000029 +0.499 -0.022216796875 -0.026123046875 0.1501953125000029 +0.499125 -0.01776123046875 -0.020904541015625 0.1501953125000029 +0.49925 -0.013336181640625 -0.01568603515625 0.1501953125000029 +0.499375 -0.013336181640625 -0.01568603515625 0.1501953125000029 +0.4995 -0.008880615234375 -0.01043701171875 0.1501953125000029 +0.499625 -0.008880615234375 -0.01043701171875 0.1501953125000029 +0.49975 -0.004425048828125 -0.005218505859375 0.1501953125000029 +0.499875 0.0 0.0 0.1501953125000029 +0.5 0.0 0.0 0.1501953125000029 +0.500125 0.004425048828125 0.005218505859375 0.1501953125000029 +0.50025 0.004425048828125 0.005218505859375 0.1501953125000029 +0.500375 0.008880615234375 0.01043701171875 0.1501953125000029 +0.5005000000000001 0.013336181640625 0.01568603515625 0.1501953125000029 +0.500625 0.013336181640625 0.01568603515625 0.1501953125000029 +0.50075 0.01776123046875 0.020904541015625 0.1501953125000029 +0.500875 0.01776123046875 0.020904541015625 0.1501953125000029 +0.501 0.022216796875 0.026123046875 0.1501953125000029 +0.501125 0.026641845703125 0.0313720703125 0.1501953125000029 +0.50125 0.026641845703125 0.0313720703125 0.1501953125000029 +0.501375 0.031097412109375 0.036590576171875 0.1501953125000029 +0.5015000000000001 0.031097412109375 0.036590576171875 0.1501953125000029 +0.501625 0.0355224609375 0.04180908203125 0.1501953125000029 +0.50175 0.039947509765625 0.047027587890625 0.1501953125000029 +0.501875 0.039947509765625 0.047027587890625 0.1501953125000029 +0.502 0.044403076171875 0.05224609375 0.1501953125000029 +0.502125 0.044403076171875 0.05224609375 0.1501953125000029 +0.50225 0.048797607421875 0.05743408203125 0.1501953125000029 +0.502375 0.05322265625 0.0626220703125 0.1501953125000029 +0.5025000000000001 0.05322265625 0.0626220703125 0.1501953125000029 +0.502625 0.0576171875 0.06781005859375 0.1501953125000029 +0.50275 0.0576171875 0.06781005859375 0.1501953125000029 +0.502875 0.062042236328125 0.072998046875 0.1501953125000029 +0.503 0.066436767578125 0.07818603515625 0.1501953125000029 +0.503125 0.066436767578125 0.07818603515625 0.1501953125000029 +0.50325 0.070831298828125 0.083343505859375 0.1501953125000029 +0.503375 0.070831298828125 0.083343505859375 0.1501953125000029 +0.5035000000000001 0.0751953125 0.0885009765625 0.1501953125000029 +0.503625 0.07958984375 0.093658447265625 0.1501953125000029 +0.50375 0.07958984375 0.093658447265625 0.1501953125000029 +0.503875 0.083953857421875 0.098785400390625 0.1501953125000029 +0.504 0.083953857421875 0.098785400390625 0.1501953125000029 +0.504125 0.08831787109375 0.103912353515625 0.1501953125000029 +0.50425 0.0926513671875 0.109039306640625 0.1501953125000029 +0.504375 0.0926513671875 0.109039306640625 0.1501953125000029 +0.5045000000000001 0.09698486328125 0.1141357421875 0.1501953125000029 +0.504625 0.09698486328125 0.1141357421875 0.1501953125000029 +0.50475 0.101318359375 0.119232177734375 0.1501953125000029 +0.504875 0.105621337890625 0.124298095703125 0.1501953125000029 +0.505 0.105621337890625 0.124298095703125 0.1501953125000029 +0.505125 0.10992431640625 0.129364013671875 0.1501953125000029 +0.50525 0.10992431640625 0.129364013671875 0.1501953125000029 +0.505375 0.114227294921875 0.134429931640625 0.1501953125000029 +0.5055000000000001 0.118499755859375 0.13946533203125 0.1501953125000029 +0.505625 0.118499755859375 0.13946533203125 0.1501953125000029 +0.50575 0.122772216796875 0.14447021484375 0.1501953125000029 +0.505875 0.122772216796875 0.14447021484375 0.1501953125000029 +0.506 0.12701416015625 0.14947509765625 0.1501953125000029 +0.506125 0.131256103515625 0.15447998046875 0.1501953125000029 +0.50625 0.131256103515625 0.15447998046875 0.1501953125000029 +0.506375 0.135498046875 0.159454345703125 0.1501953125000029 +0.5065000000000001 0.135498046875 0.159454345703125 0.1501953125000029 +0.506625 0.139678955078125 0.164398193359375 0.1501953125000029 +0.50675 0.143890380859375 0.169342041015625 0.1501953125000029 +0.506875 0.143890380859375 0.169342041015625 0.1501953125000029 +0.507 0.1480712890625 0.17425537109375 0.1501953125000029 +0.507125 0.1480712890625 0.17425537109375 0.1501953125000029 +0.50725 0.1522216796875 0.17913818359375 0.1501953125000029 +0.507375 0.1563720703125 0.18402099609375 0.1501953125000029 +0.5075000000000001 0.1563720703125 0.18402099609375 0.1501953125000029 +0.507625 0.160491943359375 0.188873291015625 0.1501953125000029 +0.50775 0.160491943359375 0.188873291015625 0.1501953125000029 +0.507875 0.16461181640625 0.1937255859375 0.1501953125000029 +0.508 0.168701171875 0.19854736328125 0.1501953125000029 +0.508125 0.168701171875 0.19854736328125 0.1501953125000029 +0.50825 0.172760009765625 0.203338623046875 0.1501953125000029 +0.508375 0.172760009765625 0.203338623046875 0.1501953125000029 +0.5085000000000001 0.17681884765625 0.208099365234375 0.1501953125000029 +0.508625 0.180877685546875 0.212860107421875 0.1501953125000029 +0.50875 0.180877685546875 0.212860107421875 0.1501953125000029 +0.508875 0.18487548828125 0.21759033203125 0.1501953125000029 +0.509 0.18487548828125 0.21759033203125 0.1501953125000029 +0.509125 0.188873291015625 0.2222900390625 0.1501953125000029 +0.50925 0.192840576171875 0.226959228515625 0.1501953125000029 +0.509375 0.192840576171875 0.226959228515625 0.1501953125000029 +0.5095000000000001 0.196807861328125 0.231597900390625 0.1501953125000029 +0.509625 0.196807861328125 0.231597900390625 0.1501953125000029 +0.50975 0.20074462890625 0.236236572265625 0.1501953125000029 +0.509875 0.20465087890625 0.2408447265625 0.1501953125000029 +0.51 0.20465087890625 0.2408447265625 0.1501953125000029 +0.5101250000000001 0.208526611328125 0.24542236328125 0.1501953125000029 +0.51025 0.208526611328125 0.24542236328125 0.1501953125000029 +0.510375 0.21240234375 0.249969482421875 0.1501953125000029 +0.5105000000000001 0.21624755859375 0.25445556640625 0.1501953125000029 +0.510625 0.21624755859375 0.25445556640625 0.1501953125000029 +0.51075 0.220062255859375 0.25897216796875 0.1501953125000029 +0.510875 0.220062255859375 0.25897216796875 0.1501953125000029 +0.511 0.223846435546875 0.263427734375 0.1501953125000029 +0.5111250000000001 0.227630615234375 0.267852783203125 0.1501953125000029 +0.51125 0.227630615234375 0.267852783203125 0.1501953125000029 +0.511375 0.231353759765625 0.27227783203125 0.1501953125000029 +0.5115000000000001 0.231353759765625 0.27227783203125 0.1501953125000029 +0.511625 0.235076904296875 0.276641845703125 0.1501953125000029 +0.51175 0.23876953125 0.280975341796875 0.1501953125000029 +0.511875 0.23876953125 0.280975341796875 0.1501953125000029 +0.512 0.135467529296875 0.285308837890625 0.5251342773437525 +0.5121250000000001 0.135467529296875 0.285308837890625 0.5251342773437525 +0.51225 0.137481689453125 0.289581298828125 0.5251342773437525 +0.512375 0.139495849609375 0.2938232421875 0.5251342773437525 +0.5125 0.139495849609375 0.2938232421875 0.5251342773437525 +0.512625 0.141510009765625 0.298065185546875 0.5251342773437525 +0.51275 0.141510009765625 0.298065185546875 0.5251342773437525 +0.512875 0.14349365234375 0.30224609375 0.5251342773437525 +0.513 0.145477294921875 0.306396484375 0.5251342773437525 +0.5131250000000001 0.145477294921875 0.306396484375 0.5251342773437525 +0.51325 0.147430419921875 0.310516357421875 0.5251342773437525 +0.513375 0.147430419921875 0.310516357421875 0.5251342773437525 +0.5135 0.14935302734375 0.314605712890625 0.5251342773437525 +0.513625 0.151275634765625 0.31866455078125 0.5251342773437525 +0.51375 0.151275634765625 0.31866455078125 0.5251342773437525 +0.513875 0.1531982421875 0.322662353515625 0.5251342773437525 +0.514 0.1531982421875 0.322662353515625 0.5251342773437525 +0.5141250000000001 0.15509033203125 0.32666015625 0.5251342773437525 +0.51425 0.156951904296875 0.330596923828125 0.5251342773437525 +0.514375 0.156951904296875 0.330596923828125 0.5251342773437525 +0.5145 0.1588134765625 0.334503173828125 0.5251342773437525 +0.514625 0.1588134765625 0.334503173828125 0.5251342773437525 +0.51475 0.16064453125 0.33837890625 0.5251342773437525 +0.514875 0.1624755859375 0.34222412109375 0.5251342773437525 +0.515 0.1624755859375 0.34222412109375 0.5251342773437525 +0.5151250000000001 0.164276123046875 0.34600830078125 0.5251342773437525 +0.51525 0.164276123046875 0.34600830078125 0.5251342773437525 +0.515375 0.166046142578125 0.349761962890625 0.5251342773437525 +0.5155 0.167816162109375 0.353485107421875 0.5251342773437525 +0.515625 0.167816162109375 0.353485107421875 0.5251342773437525 +0.51575 0.169586181640625 0.357177734375 0.5251342773437525 +0.515875 0.169586181640625 0.357177734375 0.5251342773437525 +0.516 0.171295166015625 0.360809326171875 0.5251342773437525 +0.5161250000000001 0.17303466796875 0.36444091796875 0.5251342773437525 +0.51625 0.17303466796875 0.36444091796875 0.5251342773437525 +0.516375 0.174713134765625 0.36798095703125 0.5251342773437525 +0.5165 0.174713134765625 0.36798095703125 0.5251342773437525 +0.516625 0.1763916015625 0.37152099609375 0.5251342773437525 +0.51675 0.17803955078125 0.375 0.5251342773437525 +0.516875 0.17803955078125 0.375 0.5251342773437525 +0.517 0.179656982421875 0.378448486328125 0.5251342773437525 +0.5171250000000001 0.179656982421875 0.378448486328125 0.5251342773437525 +0.51725 0.1812744140625 0.3818359375 0.5251342773437525 +0.517375 0.182891845703125 0.38519287109375 0.5251342773437525 +0.5175 0.182891845703125 0.38519287109375 0.5251342773437525 +0.517625 0.1844482421875 0.388519287109375 0.5251342773437525 +0.51775 0.1844482421875 0.388519287109375 0.5251342773437525 +0.517875 0.186004638671875 0.39178466796875 0.5251342773437525 +0.518 0.18756103515625 0.39501953125 0.5251342773437525 +0.5181250000000001 0.18756103515625 0.39501953125 0.5251342773437525 +0.51825 0.189056396484375 0.398193359375 0.5251342773437525 +0.518375 0.189056396484375 0.398193359375 0.5251342773437525 +0.5185 0.1905517578125 0.401336669921875 0.5251342773437525 +0.518625 0.1920166015625 0.404449462890625 0.5251342773437525 +0.51875 0.1920166015625 0.404449462890625 0.5251342773437525 +0.518875 0.1934814453125 0.407501220703125 0.5251342773437525 +0.519 0.1934814453125 0.407501220703125 0.5251342773437525 +0.5191250000000001 0.19488525390625 0.4105224609375 0.5251342773437525 +0.51925 0.196319580078125 0.413482666015625 0.5251342773437525 +0.519375 0.196319580078125 0.413482666015625 0.5251342773437525 +0.5195 0.19769287109375 0.416412353515625 0.5251342773437525 +0.519625 0.19769287109375 0.416412353515625 0.5251342773437525 +0.51975 0.199066162109375 0.419281005859375 0.5251342773437525 +0.519875 0.200408935546875 0.422119140625 0.5251342773437525 +0.52 0.200408935546875 0.422119140625 0.5251342773437525 +0.5201250000000001 0.20172119140625 0.424896240234375 0.5251342773437525 +0.52025 0.20172119140625 0.424896240234375 0.5251342773437525 +0.520375 0.203033447265625 0.4276123046875 0.5251342773437525 +0.5205 0.20428466796875 0.4302978515625 0.5251342773437525 +0.520625 0.20428466796875 0.4302978515625 0.5251342773437525 +0.52075 0.20556640625 0.432952880859375 0.5251342773437525 +0.520875 0.20556640625 0.432952880859375 0.5251342773437525 +0.521 0.206787109375 0.435546875 0.5251342773437525 +0.5211250000000001 0.207977294921875 0.438079833984375 0.5251342773437525 +0.52125 0.207977294921875 0.438079833984375 0.5251342773437525 +0.521375 0.20916748046875 0.440582275390625 0.5251342773437525 +0.5215 0.20916748046875 0.440582275390625 0.5251342773437525 +0.521625 0.210357666015625 0.44305419921875 0.5251342773437525 +0.52175 0.21148681640625 0.4454345703125 0.5251342773437525 +0.521875 0.21148681640625 0.4454345703125 0.5251342773437525 +0.522 0.21258544921875 0.447784423828125 0.5251342773437525 +0.5221250000000001 0.21258544921875 0.447784423828125 0.5251342773437525 +0.52225 0.21368408203125 0.450103759765625 0.5251342773437525 +0.522375 0.214752197265625 0.452362060546875 0.5251342773437525 +0.5225 0.214752197265625 0.452362060546875 0.5251342773437525 +0.522625 0.2158203125 0.454559326171875 0.5251342773437525 +0.52275 0.2158203125 0.454559326171875 0.5251342773437525 +0.522875 0.216827392578125 0.45672607421875 0.5251342773437525 +0.523 0.21783447265625 0.458831787109375 0.5251342773437525 +0.5231250000000001 0.21783447265625 0.458831787109375 0.5251342773437525 +0.52325 0.21881103515625 0.46087646484375 0.5251342773437525 +0.523375 0.21881103515625 0.46087646484375 0.5251342773437525 +0.5235 0.219757080078125 0.462890625 0.5251342773437525 +0.523625 0.220672607421875 0.464813232421875 0.5251342773437525 +0.52375 0.220672607421875 0.464813232421875 0.5251342773437525 +0.523875 0.221588134765625 0.46673583984375 0.5251342773437525 +0.524 0.221588134765625 0.46673583984375 0.5251342773437525 +0.5241250000000001 0.22247314453125 0.46856689453125 0.5251342773437525 +0.52425 0.22332763671875 0.470367431640625 0.5251342773437525 +0.524375 0.22332763671875 0.470367431640625 0.5251342773437525 +0.5245 0.224151611328125 0.472137451171875 0.5251342773437525 +0.524625 0.224151611328125 0.472137451171875 0.5251342773437525 +0.52475 0.224945068359375 0.47381591796875 0.5251342773437525 +0.524875 0.225738525390625 0.4754638671875 0.5251342773437525 +0.525 0.225738525390625 0.4754638671875 0.5251342773437525 +0.5251250000000001 0.22650146484375 0.47705078125 0.5251342773437525 +0.52525 0.22650146484375 0.47705078125 0.5251342773437525 +0.525375 0.22723388671875 0.478607177734375 0.5251342773437525 +0.5255 0.227935791015625 0.480072021484375 0.5251342773437525 +0.525625 0.227935791015625 0.480072021484375 0.5251342773437525 +0.5257500000000001 0.228607177734375 0.48150634765625 0.5251342773437525 +0.525875 0.228607177734375 0.48150634765625 0.5251342773437525 +0.526 0.229278564453125 0.48291015625 0.5251342773437525 +0.5261250000000001 0.229888916015625 0.484222412109375 0.5251342773437525 +0.52625 0.229888916015625 0.484222412109375 0.5251342773437525 +0.526375 0.230499267578125 0.485504150390625 0.5251342773437525 +0.5265 0.230499267578125 0.485504150390625 0.5251342773437525 +0.526625 0.2310791015625 0.486724853515625 0.5251342773437525 +0.5267500000000001 0.23162841796875 0.487884521484375 0.5251342773437525 +0.526875 0.23162841796875 0.487884521484375 0.5251342773437525 +0.527 0.232177734375 0.489013671875 0.5251342773437525 +0.5271250000000001 0.232177734375 0.489013671875 0.5251342773437525 +0.52725 0.232666015625 0.490081787109375 0.5251342773437525 +0.527375 0.233154296875 0.4910888671875 0.5251342773437525 +0.5275 0.233154296875 0.4910888671875 0.5251342773437525 +0.527625 0.233612060546875 0.492034912109375 0.5251342773437525 +0.5277500000000001 0.233612060546875 0.492034912109375 0.5251342773437525 +0.527875 0.234039306640625 0.492950439453125 0.5251342773437525 +0.528 0.23443603515625 0.4937744140625 0.5251342773437525 +0.528125 0.23443603515625 0.4937744140625 0.5251342773437525 +0.52825 0.23480224609375 0.49456787109375 0.5251342773437525 +0.528375 0.23480224609375 0.49456787109375 0.5251342773437525 +0.5285 0.23516845703125 0.49530029296875 0.5251342773437525 +0.528625 0.2354736328125 0.496002197265625 0.5251342773437525 +0.5287500000000001 0.2354736328125 0.496002197265625 0.5251342773437525 +0.528875 0.23577880859375 0.496612548828125 0.5251342773437525 +0.529 0.23577880859375 0.496612548828125 0.5251342773437525 +0.529125 0.236053466796875 0.4971923828125 0.5251342773437525 +0.52925 0.236297607421875 0.497711181640625 0.5251342773437525 +0.529375 0.236297607421875 0.497711181640625 0.5251342773437525 +0.5295 0.23651123046875 0.498199462890625 0.5251342773437525 +0.529625 0.23651123046875 0.498199462890625 0.5251342773437525 +0.5297500000000001 0.236724853515625 0.49859619140625 0.5251342773437525 +0.529875 0.23687744140625 0.49896240234375 0.5251342773437525 +0.53 0.23687744140625 0.49896240234375 0.5251342773437525 +0.530125 0.237030029296875 0.499267578125 0.5251342773437525 +0.53025 0.237030029296875 0.499267578125 0.5251342773437525 +0.530375 0.237152099609375 0.49951171875 0.5251342773437525 +0.5305 0.23724365234375 0.49969482421875 0.5251342773437525 +0.530625 0.23724365234375 0.49969482421875 0.5251342773437525 +0.5307500000000001 0.2373046875 0.49981689453125 0.5251342773437525 +0.530875 0.2373046875 0.49981689453125 0.5251342773437525 +0.531 0.237335205078125 0.499908447265625 0.5251342773437525 +0.531125 0.23736572265625 0.49993896484375 0.5251342773437525 +0.53125 0.23736572265625 0.49993896484375 0.5251342773437525 +0.531375 0.237335205078125 0.499908447265625 0.5251342773437525 +0.5315 0.237335205078125 0.499908447265625 0.5251342773437525 +0.531625 0.2373046875 0.49981689453125 0.5251342773437525 +0.5317500000000001 0.23724365234375 0.49969482421875 0.5251342773437525 +0.531875 0.23724365234375 0.49969482421875 0.5251342773437525 +0.532 0.237152099609375 0.49951171875 0.5251342773437525 +0.532125 0.237152099609375 0.49951171875 0.5251342773437525 +0.53225 0.237030029296875 0.499267578125 0.5251342773437525 +0.532375 0.23687744140625 0.49896240234375 0.5251342773437525 +0.5325 0.23687744140625 0.49896240234375 0.5251342773437525 +0.532625 0.236724853515625 0.49859619140625 0.5251342773437525 +0.5327500000000001 0.236724853515625 0.49859619140625 0.5251342773437525 +0.532875 0.23651123046875 0.498199462890625 0.5251342773437525 +0.533 0.236297607421875 0.497711181640625 0.5251342773437525 +0.533125 0.236297607421875 0.497711181640625 0.5251342773437525 +0.53325 0.236053466796875 0.4971923828125 0.5251342773437525 +0.533375 0.236053466796875 0.4971923828125 0.5251342773437525 +0.5335 0.23577880859375 0.496612548828125 0.5251342773437525 +0.533625 0.2354736328125 0.496002197265625 0.5251342773437525 +0.5337500000000001 0.2354736328125 0.496002197265625 0.5251342773437525 +0.533875 0.23516845703125 0.49530029296875 0.5251342773437525 +0.534 0.23516845703125 0.49530029296875 0.5251342773437525 +0.534125 0.23480224609375 0.49456787109375 0.5251342773437525 +0.53425 0.23443603515625 0.4937744140625 0.5251342773437525 +0.534375 0.23443603515625 0.4937744140625 0.5251342773437525 +0.5345 0.234039306640625 0.492950439453125 0.5251342773437525 +0.534625 0.234039306640625 0.492950439453125 0.5251342773437525 +0.5347500000000001 0.233612060546875 0.492034912109375 0.5251342773437525 +0.534875 0.233154296875 0.4910888671875 0.5251342773437525 +0.535 0.233154296875 0.4910888671875 0.5251342773437525 +0.535125 0.232666015625 0.490081787109375 0.5251342773437525 +0.53525 0.232666015625 0.490081787109375 0.5251342773437525 +0.535375 0.232177734375 0.489013671875 0.5251342773437525 +0.5355 0.23162841796875 0.487884521484375 0.5251342773437525 +0.535625 0.23162841796875 0.487884521484375 0.5251342773437525 +0.5357500000000001 0.2310791015625 0.486724853515625 0.5251342773437525 +0.535875 0.2310791015625 0.486724853515625 0.5251342773437525 +0.536 0.230499267578125 0.485504150390625 0.5251342773437525 +0.536125 0.229888916015625 0.484222412109375 0.5251342773437525 +0.53625 0.229888916015625 0.484222412109375 0.5251342773437525 +0.536375 0.229278564453125 0.48291015625 0.5251342773437525 +0.5365 0.229278564453125 0.48291015625 0.5251342773437525 +0.536625 0.228607177734375 0.48150634765625 0.5251342773437525 +0.5367500000000001 0.227935791015625 0.480072021484375 0.5251342773437525 +0.536875 0.227935791015625 0.480072021484375 0.5251342773437525 +0.537 0.22723388671875 0.478607177734375 0.5251342773437525 +0.537125 0.22723388671875 0.478607177734375 0.5251342773437525 +0.53725 0.22650146484375 0.47705078125 0.5251342773437525 +0.537375 0.225738525390625 0.4754638671875 0.5251342773437525 +0.5375 0.225738525390625 0.4754638671875 0.5251342773437525 +0.537625 0.224945068359375 0.47381591796875 0.5251342773437525 +0.5377500000000001 0.224945068359375 0.47381591796875 0.5251342773437525 +0.537875 0.224151611328125 0.472137451171875 0.5251342773437525 +0.538 0.22332763671875 0.470367431640625 0.5251342773437525 +0.538125 0.22332763671875 0.470367431640625 0.5251342773437525 +0.53825 0.22247314453125 0.46856689453125 0.5251342773437525 +0.538375 0.22247314453125 0.46856689453125 0.5251342773437525 +0.5385 0.221588134765625 0.46673583984375 0.5251342773437525 +0.538625 0.220672607421875 0.464813232421875 0.5251342773437525 +0.5387500000000001 0.220672607421875 0.464813232421875 0.5251342773437525 +0.538875 0.219757080078125 0.462890625 0.5251342773437525 +0.539 0.219757080078125 0.462890625 0.5251342773437525 +0.539125 0.21881103515625 0.46087646484375 0.5251342773437525 +0.53925 0.21783447265625 0.458831787109375 0.5251342773437525 +0.539375 0.21783447265625 0.458831787109375 0.5251342773437525 +0.5395 0.216827392578125 0.45672607421875 0.5251342773437525 +0.539625 0.216827392578125 0.45672607421875 0.5251342773437525 +0.5397500000000001 0.2158203125 0.454559326171875 0.5251342773437525 +0.539875 0.214752197265625 0.452362060546875 0.5251342773437525 +0.54 0.214752197265625 0.452362060546875 0.5251342773437525 +0.540125 0.21368408203125 0.450103759765625 0.5251342773437525 +0.54025 0.21368408203125 0.450103759765625 0.5251342773437525 +0.540375 0.21258544921875 0.447784423828125 0.5251342773437525 +0.5405 0.21148681640625 0.4454345703125 0.5251342773437525 +0.540625 0.21148681640625 0.4454345703125 0.5251342773437525 +0.5407500000000001 0.210357666015625 0.44305419921875 0.5251342773437525 +0.540875 0.210357666015625 0.44305419921875 0.5251342773437525 +0.541 0.20916748046875 0.440582275390625 0.5251342773437525 +0.541125 0.207977294921875 0.438079833984375 0.5251342773437525 +0.54125 0.207977294921875 0.438079833984375 0.5251342773437525 +0.5413750000000001 0.206787109375 0.435546875 0.5251342773437525 +0.5415 0.206787109375 0.435546875 0.5251342773437525 +0.541625 0.20556640625 0.432952880859375 0.5251342773437525 +0.5417500000000001 0.20428466796875 0.4302978515625 0.5251342773437525 +0.541875 0.20428466796875 0.4302978515625 0.5251342773437525 +0.542 0.203033447265625 0.4276123046875 0.5251342773437525 +0.542125 0.203033447265625 0.4276123046875 0.5251342773437525 +0.54225 0.20172119140625 0.424896240234375 0.5251342773437525 +0.5423750000000001 0.200408935546875 0.422119140625 0.5251342773437525 +0.5425 0.200408935546875 0.422119140625 0.5251342773437525 +0.542625 0.199066162109375 0.419281005859375 0.5251342773437525 +0.5427500000000001 0.199066162109375 0.419281005859375 0.5251342773437525 +0.542875 0.19769287109375 0.416412353515625 0.5251342773437525 +0.543 0.196319580078125 0.413482666015625 0.5251342773437525 +0.543125 0.196319580078125 0.413482666015625 0.5251342773437525 +0.54325 0.19488525390625 0.4105224609375 0.5251342773437525 +0.5433750000000001 0.19488525390625 0.4105224609375 0.5251342773437525 +0.5435 0.1934814453125 0.407501220703125 0.5251342773437525 +0.543625 0.1920166015625 0.404449462890625 0.5251342773437525 +0.5437500000000001 0.1920166015625 0.404449462890625 0.5251342773437525 +0.543875 0.1905517578125 0.401336669921875 0.5251342773437525 +0.544 0.073699951171875 0.401336669921875 0.8162963867187517 +0.544125 0.0731201171875 0.398193359375 0.8162963867187517 +0.54425 0.072540283203125 0.39501953125 0.8162963867187517 +0.5443750000000001 0.072540283203125 0.39501953125 0.8162963867187517 +0.5445 0.071929931640625 0.39178466796875 0.8162963867187517 +0.544625 0.071929931640625 0.39178466796875 0.8162963867187517 +0.54475 0.071319580078125 0.388519287109375 0.8162963867187517 +0.544875 0.070709228515625 0.38519287109375 0.8162963867187517 +0.545 0.070709228515625 0.38519287109375 0.8162963867187517 +0.545125 0.070098876953125 0.3818359375 0.8162963867187517 +0.54525 0.070098876953125 0.3818359375 0.8162963867187517 +0.5453750000000001 0.069488525390625 0.378448486328125 0.8162963867187517 +0.5455 0.06884765625 0.375 0.8162963867187517 +0.545625 0.06884765625 0.375 0.8162963867187517 +0.54575 0.068206787109375 0.37152099609375 0.8162963867187517 +0.545875 0.068206787109375 0.37152099609375 0.8162963867187517 +0.546 0.06756591796875 0.36798095703125 0.8162963867187517 +0.546125 0.066925048828125 0.36444091796875 0.8162963867187517 +0.54625 0.066925048828125 0.36444091796875 0.8162963867187517 +0.5463750000000001 0.066253662109375 0.360809326171875 0.8162963867187517 +0.5465 0.066253662109375 0.360809326171875 0.8162963867187517 +0.546625 0.065582275390625 0.357177734375 0.8162963867187517 +0.54675 0.064910888671875 0.353485107421875 0.8162963867187517 +0.546875 0.064910888671875 0.353485107421875 0.8162963867187517 +0.547 0.064208984375 0.349761962890625 0.8162963867187517 +0.547125 0.064208984375 0.349761962890625 0.8162963867187517 +0.54725 0.06353759765625 0.34600830078125 0.8162963867187517 +0.5473750000000001 0.062835693359375 0.34222412109375 0.8162963867187517 +0.5475 0.062835693359375 0.34222412109375 0.8162963867187517 +0.547625 0.0621337890625 0.33837890625 0.8162963867187517 +0.54775 0.0621337890625 0.33837890625 0.8162963867187517 +0.547875 0.0614013671875 0.334503173828125 0.8162963867187517 +0.548 0.060699462890625 0.330596923828125 0.8162963867187517 +0.548125 0.060699462890625 0.330596923828125 0.8162963867187517 +0.54825 0.059967041015625 0.32666015625 0.8162963867187517 +0.5483750000000001 0.059967041015625 0.32666015625 0.8162963867187517 +0.5485 0.059234619140625 0.322662353515625 0.8162963867187517 +0.548625 0.058502197265625 0.31866455078125 0.8162963867187517 +0.54875 0.058502197265625 0.31866455078125 0.8162963867187517 +0.548875 0.057769775390625 0.314605712890625 0.8162963867187517 +0.549 0.057769775390625 0.314605712890625 0.8162963867187517 +0.549125 0.0570068359375 0.310516357421875 0.8162963867187517 +0.54925 0.056243896484375 0.306396484375 0.8162963867187517 +0.5493750000000001 0.056243896484375 0.306396484375 0.8162963867187517 +0.5495 0.05548095703125 0.30224609375 0.8162963867187517 +0.549625 0.05548095703125 0.30224609375 0.8162963867187517 +0.54975 0.054718017578125 0.298065185546875 0.8162963867187517 +0.549875 0.053955078125 0.2938232421875 0.8162963867187517 +0.55 0.053955078125 0.2938232421875 0.8162963867187517 +0.550125 0.05316162109375 0.289581298828125 0.8162963867187517 +0.55025 0.05316162109375 0.289581298828125 0.8162963867187517 +0.5503750000000001 0.0523681640625 0.285308837890625 0.8162963867187517 +0.5505 0.05157470703125 0.280975341796875 0.8162963867187517 +0.550625 0.05157470703125 0.280975341796875 0.8162963867187517 +0.55075 0.05078125 0.276641845703125 0.8162963867187517 +0.550875 0.05078125 0.276641845703125 0.8162963867187517 +0.551 0.04998779296875 0.27227783203125 0.8162963867187517 +0.551125 0.049163818359375 0.267852783203125 0.8162963867187517 +0.55125 0.049163818359375 0.267852783203125 0.8162963867187517 +0.5513750000000001 0.048370361328125 0.263427734375 0.8162963867187517 +0.5515 0.048370361328125 0.263427734375 0.8162963867187517 +0.551625 0.04754638671875 0.25897216796875 0.8162963867187517 +0.55175 0.046722412109375 0.25445556640625 0.8162963867187517 +0.551875 0.046722412109375 0.25445556640625 0.8162963867187517 +0.552 0.0458984375 0.249969482421875 0.8162963867187517 +0.552125 0.0458984375 0.249969482421875 0.8162963867187517 +0.55225 0.0450439453125 0.24542236328125 0.8162963867187517 +0.5523750000000001 0.044219970703125 0.2408447265625 0.8162963867187517 +0.5525 0.044219970703125 0.2408447265625 0.8162963867187517 +0.552625 0.043365478515625 0.236236572265625 0.8162963867187517 +0.55275 0.043365478515625 0.236236572265625 0.8162963867187517 +0.552875 0.042510986328125 0.231597900390625 0.8162963867187517 +0.553 0.041656494140625 0.226959228515625 0.8162963867187517 +0.553125 0.041656494140625 0.226959228515625 0.8162963867187517 +0.55325 0.040802001953125 0.2222900390625 0.8162963867187517 +0.5533750000000001 0.040802001953125 0.2222900390625 0.8162963867187517 +0.5535 0.039947509765625 0.21759033203125 0.8162963867187517 +0.553625 0.0390625 0.212860107421875 0.8162963867187517 +0.55375 0.0390625 0.212860107421875 0.8162963867187517 +0.553875 0.0382080078125 0.208099365234375 0.8162963867187517 +0.554 0.0382080078125 0.208099365234375 0.8162963867187517 +0.554125 0.037322998046875 0.203338623046875 0.8162963867187517 +0.55425 0.03643798828125 0.19854736328125 0.8162963867187517 +0.5543750000000001 0.03643798828125 0.19854736328125 0.8162963867187517 +0.5545 0.035552978515625 0.1937255859375 0.8162963867187517 +0.554625 0.035552978515625 0.1937255859375 0.8162963867187517 +0.55475 0.03466796875 0.188873291015625 0.8162963867187517 +0.554875 0.033782958984375 0.18402099609375 0.8162963867187517 +0.555 0.033782958984375 0.18402099609375 0.8162963867187517 +0.555125 0.03289794921875 0.17913818359375 0.8162963867187517 +0.55525 0.03289794921875 0.17913818359375 0.8162963867187517 +0.5553750000000001 0.031982421875 0.17425537109375 0.8162963867187517 +0.5555 0.031097412109375 0.169342041015625 0.8162963867187517 +0.555625 0.031097412109375 0.169342041015625 0.8162963867187517 +0.55575 0.030181884765625 0.164398193359375 0.8162963867187517 +0.555875 0.030181884765625 0.164398193359375 0.8162963867187517 +0.556 0.029266357421875 0.159454345703125 0.8162963867187517 +0.556125 0.028350830078125 0.15447998046875 0.8162963867187517 +0.55625 0.028350830078125 0.15447998046875 0.8162963867187517 +0.5563750000000001 0.027435302734375 0.14947509765625 0.8162963867187517 +0.5565 0.027435302734375 0.14947509765625 0.8162963867187517 +0.556625 0.026519775390625 0.14447021484375 0.8162963867187517 +0.55675 0.025604248046875 0.13946533203125 0.8162963867187517 +0.556875 0.025604248046875 0.13946533203125 0.8162963867187517 +0.5570000000000001 0.024658203125 0.134429931640625 0.8162963867187517 +0.557125 0.024658203125 0.134429931640625 0.8162963867187517 +0.55725 0.02374267578125 0.129364013671875 0.8162963867187517 +0.5573750000000001 0.0228271484375 0.124298095703125 0.8162963867187517 +0.5575 0.0228271484375 0.124298095703125 0.8162963867187517 +0.557625 0.021881103515625 0.119232177734375 0.8162963867187517 +0.55775 0.021881103515625 0.119232177734375 0.8162963867187517 +0.557875 0.02093505859375 0.1141357421875 0.8162963867187517 +0.5580000000000001 0.02001953125 0.109039306640625 0.8162963867187517 +0.558125 0.02001953125 0.109039306640625 0.8162963867187517 +0.55825 0.019073486328125 0.103912353515625 0.8162963867187517 +0.5583750000000001 0.019073486328125 0.103912353515625 0.8162963867187517 +0.5585 0.01812744140625 0.098785400390625 0.8162963867187517 +0.558625 0.017181396484375 0.093658447265625 0.8162963867187517 +0.55875 0.017181396484375 0.093658447265625 0.8162963867187517 +0.558875 0.0162353515625 0.0885009765625 0.8162963867187517 +0.5590000000000001 0.0162353515625 0.0885009765625 0.8162963867187517 +0.559125 0.015289306640625 0.083343505859375 0.8162963867187517 +0.55925 0.01434326171875 0.07818603515625 0.8162963867187517 +0.5593750000000001 0.01434326171875 0.07818603515625 0.8162963867187517 +0.5595 0.013397216796875 0.072998046875 0.8162963867187517 +0.559625 0.013397216796875 0.072998046875 0.8162963867187517 +0.55975 0.012451171875 0.06781005859375 0.8162963867187517 +0.559875 0.011474609375 0.0626220703125 0.8162963867187517 +0.5600000000000001 0.011474609375 0.0626220703125 0.8162963867187517 +0.560125 0.010528564453125 0.05743408203125 0.8162963867187517 +0.56025 0.010528564453125 0.05743408203125 0.8162963867187517 +0.560375 0.00958251953125 0.05224609375 0.8162963867187517 +0.5605 0.008636474609375 0.047027587890625 0.8162963867187517 +0.560625 0.008636474609375 0.047027587890625 0.8162963867187517 +0.56075 0.007659912109375 0.04180908203125 0.8162963867187517 +0.560875 0.007659912109375 0.04180908203125 0.8162963867187517 +0.5610000000000001 0.0067138671875 0.036590576171875 0.8162963867187517 +0.561125 0.0057373046875 0.0313720703125 0.8162963867187517 +0.56125 0.0057373046875 0.0313720703125 0.8162963867187517 +0.561375 0.004791259765625 0.026123046875 0.8162963867187517 +0.5615 0.004791259765625 0.026123046875 0.8162963867187517 +0.561625 0.003814697265625 0.020904541015625 0.8162963867187517 +0.56175 0.00286865234375 0.01568603515625 0.8162963867187517 +0.561875 0.00286865234375 0.01568603515625 0.8162963867187517 +0.5620000000000001 0.00189208984375 0.01043701171875 0.8162963867187517 +0.562125 0.00189208984375 0.01043701171875 0.8162963867187517 +0.56225 0.000946044921875 0.005218505859375 0.8162963867187517 +0.562375 0.0 0.0 0.8162963867187517 +0.5625 0.0 0.0 0.8162963867187517 +0.562625 -0.000946044921875 -0.005218505859375 0.8162963867187517 +0.56275 -0.000946044921875 -0.005218505859375 0.8162963867187517 +0.562875 -0.00189208984375 -0.01043701171875 0.8162963867187517 +0.5630000000000001 -0.00286865234375 -0.01568603515625 0.8162963867187517 +0.563125 -0.00286865234375 -0.01568603515625 0.8162963867187517 +0.56325 -0.003814697265625 -0.020904541015625 0.8162963867187517 +0.563375 -0.003814697265625 -0.020904541015625 0.8162963867187517 +0.5635 -0.004791259765625 -0.026123046875 0.8162963867187517 +0.563625 -0.0057373046875 -0.0313720703125 0.8162963867187517 +0.56375 -0.0057373046875 -0.0313720703125 0.8162963867187517 +0.563875 -0.0067138671875 -0.036590576171875 0.8162963867187517 +0.5640000000000001 -0.0067138671875 -0.036590576171875 0.8162963867187517 +0.564125 -0.007659912109375 -0.04180908203125 0.8162963867187517 +0.56425 -0.008636474609375 -0.047027587890625 0.8162963867187517 +0.564375 -0.008636474609375 -0.047027587890625 0.8162963867187517 +0.5645 -0.00958251953125 -0.05224609375 0.8162963867187517 +0.564625 -0.00958251953125 -0.05224609375 0.8162963867187517 +0.56475 -0.010528564453125 -0.05743408203125 0.8162963867187517 +0.564875 -0.011474609375 -0.0626220703125 0.8162963867187517 +0.5650000000000001 -0.011474609375 -0.0626220703125 0.8162963867187517 +0.565125 -0.012451171875 -0.06781005859375 0.8162963867187517 +0.56525 -0.012451171875 -0.06781005859375 0.8162963867187517 +0.565375 -0.013397216796875 -0.072998046875 0.8162963867187517 +0.5655 -0.01434326171875 -0.07818603515625 0.8162963867187517 +0.565625 -0.01434326171875 -0.07818603515625 0.8162963867187517 +0.56575 -0.015289306640625 -0.083343505859375 0.8162963867187517 +0.565875 -0.015289306640625 -0.083343505859375 0.8162963867187517 +0.5660000000000001 -0.0162353515625 -0.0885009765625 0.8162963867187517 +0.566125 -0.017181396484375 -0.093658447265625 0.8162963867187517 +0.56625 -0.017181396484375 -0.093658447265625 0.8162963867187517 +0.566375 -0.01812744140625 -0.098785400390625 0.8162963867187517 +0.5665 -0.01812744140625 -0.098785400390625 0.8162963867187517 +0.566625 -0.019073486328125 -0.103912353515625 0.8162963867187517 +0.56675 -0.02001953125 -0.109039306640625 0.8162963867187517 +0.566875 -0.02001953125 -0.109039306640625 0.8162963867187517 +0.5670000000000001 -0.02093505859375 -0.1141357421875 0.8162963867187517 +0.567125 -0.02093505859375 -0.1141357421875 0.8162963867187517 +0.56725 -0.021881103515625 -0.119232177734375 0.8162963867187517 +0.567375 -0.0228271484375 -0.124298095703125 0.8162963867187517 +0.5675 -0.0228271484375 -0.124298095703125 0.8162963867187517 +0.567625 -0.02374267578125 -0.129364013671875 0.8162963867187517 +0.56775 -0.02374267578125 -0.129364013671875 0.8162963867187517 +0.567875 -0.024658203125 -0.134429931640625 0.8162963867187517 +0.5680000000000001 -0.025604248046875 -0.13946533203125 0.8162963867187517 +0.568125 -0.025604248046875 -0.13946533203125 0.8162963867187517 +0.56825 -0.026519775390625 -0.14447021484375 0.8162963867187517 +0.568375 -0.026519775390625 -0.14447021484375 0.8162963867187517 +0.5685 -0.027435302734375 -0.14947509765625 0.8162963867187517 +0.568625 -0.028350830078125 -0.15447998046875 0.8162963867187517 +0.56875 -0.028350830078125 -0.15447998046875 0.8162963867187517 +0.568875 -0.029266357421875 -0.159454345703125 0.8162963867187517 +0.5690000000000001 -0.029266357421875 -0.159454345703125 0.8162963867187517 +0.569125 -0.030181884765625 -0.164398193359375 0.8162963867187517 +0.56925 -0.031097412109375 -0.169342041015625 0.8162963867187517 +0.569375 -0.031097412109375 -0.169342041015625 0.8162963867187517 +0.5695 -0.031982421875 -0.17425537109375 0.8162963867187517 +0.569625 -0.031982421875 -0.17425537109375 0.8162963867187517 +0.56975 -0.03289794921875 -0.17913818359375 0.8162963867187517 +0.569875 -0.033782958984375 -0.18402099609375 0.8162963867187517 +0.5700000000000001 -0.033782958984375 -0.18402099609375 0.8162963867187517 +0.570125 -0.03466796875 -0.188873291015625 0.8162963867187517 +0.57025 -0.03466796875 -0.188873291015625 0.8162963867187517 +0.570375 -0.035552978515625 -0.1937255859375 0.8162963867187517 +0.5705 -0.03643798828125 -0.19854736328125 0.8162963867187517 +0.570625 -0.03643798828125 -0.19854736328125 0.8162963867187517 +0.57075 -0.037322998046875 -0.203338623046875 0.8162963867187517 +0.570875 -0.037322998046875 -0.203338623046875 0.8162963867187517 +0.5710000000000001 -0.0382080078125 -0.208099365234375 0.8162963867187517 +0.571125 -0.0390625 -0.212860107421875 0.8162963867187517 +0.57125 -0.0390625 -0.212860107421875 0.8162963867187517 +0.571375 -0.039947509765625 -0.21759033203125 0.8162963867187517 +0.5715 -0.039947509765625 -0.21759033203125 0.8162963867187517 +0.571625 -0.040802001953125 -0.2222900390625 0.8162963867187517 +0.57175 -0.041656494140625 -0.226959228515625 0.8162963867187517 +0.571875 -0.041656494140625 -0.226959228515625 0.8162963867187517 +0.5720000000000001 -0.042510986328125 -0.231597900390625 0.8162963867187517 +0.572125 -0.042510986328125 -0.231597900390625 0.8162963867187517 +0.57225 -0.043365478515625 -0.236236572265625 0.8162963867187517 +0.572375 -0.044219970703125 -0.2408447265625 0.8162963867187517 +0.5725 -0.044219970703125 -0.2408447265625 0.8162963867187517 +0.5726250000000001 -0.0450439453125 -0.24542236328125 0.8162963867187517 +0.57275 -0.0450439453125 -0.24542236328125 0.8162963867187517 +0.572875 -0.0458984375 -0.249969482421875 0.8162963867187517 +0.5730000000000001 -0.046722412109375 -0.25445556640625 0.8162963867187517 +0.573125 -0.046722412109375 -0.25445556640625 0.8162963867187517 +0.57325 -0.04754638671875 -0.25897216796875 0.8162963867187517 +0.573375 -0.04754638671875 -0.25897216796875 0.8162963867187517 +0.5735 -0.048370361328125 -0.263427734375 0.8162963867187517 +0.5736250000000001 -0.049163818359375 -0.267852783203125 0.8162963867187517 +0.57375 -0.049163818359375 -0.267852783203125 0.8162963867187517 +0.573875 -0.04998779296875 -0.27227783203125 0.8162963867187517 +0.5740000000000001 -0.04998779296875 -0.27227783203125 0.8162963867187517 +0.574125 -0.05078125 -0.276641845703125 0.8162963867187517 +0.57425 -0.05157470703125 -0.280975341796875 0.8162963867187517 +0.574375 -0.05157470703125 -0.280975341796875 0.8162963867187517 +0.5745 -0.0523681640625 -0.285308837890625 0.8162963867187517 +0.5746250000000001 -0.0523681640625 -0.285308837890625 0.8162963867187517 +0.57475 -0.05316162109375 -0.289581298828125 0.8162963867187517 +0.574875 -0.053955078125 -0.2938232421875 0.8162963867187517 +0.5750000000000001 -0.053955078125 -0.2938232421875 0.8162963867187517 +0.575125 -0.054718017578125 -0.298065185546875 0.8162963867187517 +0.57525 -0.054718017578125 -0.298065185546875 0.8162963867187517 +0.575375 -0.05548095703125 -0.30224609375 0.8162963867187517 +0.5755 -0.056243896484375 -0.306396484375 0.8162963867187517 +0.5756250000000001 -0.056243896484375 -0.306396484375 0.8162963867187517 +0.57575 -0.0570068359375 -0.310516357421875 0.8162963867187517 +0.575875 -0.0570068359375 -0.310516357421875 0.8162963867187517 +0.5760000000000001 -0.00714111328125 -0.314605712890625 0.9771972656250006 +0.576125 -0.007232666015625 -0.31866455078125 0.9771972656250006 +0.57625 -0.007232666015625 -0.31866455078125 0.9771972656250006 +0.576375 -0.00732421875 -0.322662353515625 0.9771972656250006 +0.5765 -0.00732421875 -0.322662353515625 0.9771972656250006 +0.5766250000000001 -0.007415771484375 -0.32666015625 0.9771972656250006 +0.57675 -0.007476806640625 -0.330596923828125 0.9771972656250006 +0.576875 -0.007476806640625 -0.330596923828125 0.9771972656250006 +0.577 -0.007568359375 -0.334503173828125 0.9771972656250006 +0.577125 -0.007568359375 -0.334503173828125 0.9771972656250006 +0.57725 -0.007659912109375 -0.33837890625 0.9771972656250006 +0.577375 -0.00775146484375 -0.34222412109375 0.9771972656250006 +0.5775 -0.00775146484375 -0.34222412109375 0.9771972656250006 +0.5776250000000001 -0.007843017578125 -0.34600830078125 0.9771972656250006 +0.57775 -0.007843017578125 -0.34600830078125 0.9771972656250006 +0.577875 -0.0079345703125 -0.349761962890625 0.9771972656250006 +0.578 -0.008026123046875 -0.353485107421875 0.9771972656250006 +0.578125 -0.008026123046875 -0.353485107421875 0.9771972656250006 +0.57825 -0.008087158203125 -0.357177734375 0.9771972656250006 +0.578375 -0.008087158203125 -0.357177734375 0.9771972656250006 +0.5785 -0.0081787109375 -0.360809326171875 0.9771972656250006 +0.5786250000000001 -0.008270263671875 -0.36444091796875 0.9771972656250006 +0.57875 -0.008270263671875 -0.36444091796875 0.9771972656250006 +0.578875 -0.008331298828125 -0.36798095703125 0.9771972656250006 +0.579 -0.008331298828125 -0.36798095703125 0.9771972656250006 +0.579125 -0.0084228515625 -0.37152099609375 0.9771972656250006 +0.57925 -0.008514404296875 -0.375 0.9771972656250006 +0.579375 -0.008514404296875 -0.375 0.9771972656250006 +0.5795 -0.008575439453125 -0.378448486328125 0.9771972656250006 +0.5796250000000001 -0.008575439453125 -0.378448486328125 0.9771972656250006 +0.57975 -0.0086669921875 -0.3818359375 0.9771972656250006 +0.579875 -0.00872802734375 -0.38519287109375 0.9771972656250006 +0.58 -0.00872802734375 -0.38519287109375 0.9771972656250006 +0.580125 -0.008819580078125 -0.388519287109375 0.9771972656250006 +0.58025 -0.008819580078125 -0.388519287109375 0.9771972656250006 +0.580375 -0.008880615234375 -0.39178466796875 0.9771972656250006 +0.5805 -0.008941650390625 -0.39501953125 0.9771972656250006 +0.5806250000000001 -0.008941650390625 -0.39501953125 0.9771972656250006 +0.58075 -0.009033203125 -0.398193359375 0.9771972656250006 +0.580875 -0.009033203125 -0.398193359375 0.9771972656250006 +0.581 -0.00909423828125 -0.401336669921875 0.9771972656250006 +0.581125 -0.0091552734375 -0.404449462890625 0.9771972656250006 +0.58125 -0.0091552734375 -0.404449462890625 0.9771972656250006 +0.581375 -0.009246826171875 -0.407501220703125 0.9771972656250006 +0.5815 -0.009246826171875 -0.407501220703125 0.9771972656250006 +0.5816250000000001 -0.009307861328125 -0.4105224609375 0.9771972656250006 +0.58175 -0.009368896484375 -0.413482666015625 0.9771972656250006 +0.581875 -0.009368896484375 -0.413482666015625 0.9771972656250006 +0.582 -0.009429931640625 -0.416412353515625 0.9771972656250006 +0.582125 -0.009429931640625 -0.416412353515625 0.9771972656250006 +0.58225 -0.009490966796875 -0.419281005859375 0.9771972656250006 +0.582375 -0.00958251953125 -0.422119140625 0.9771972656250006 +0.5825 -0.00958251953125 -0.422119140625 0.9771972656250006 +0.5826250000000001 -0.0096435546875 -0.424896240234375 0.9771972656250006 +0.58275 -0.0096435546875 -0.424896240234375 0.9771972656250006 +0.582875 -0.00970458984375 -0.4276123046875 0.9771972656250006 +0.583 -0.009765625 -0.4302978515625 0.9771972656250006 +0.583125 -0.009765625 -0.4302978515625 0.9771972656250006 +0.58325 -0.00982666015625 -0.432952880859375 0.9771972656250006 +0.583375 -0.00982666015625 -0.432952880859375 0.9771972656250006 +0.5835 -0.0098876953125 -0.435546875 0.9771972656250006 +0.5836250000000001 -0.009918212890625 -0.438079833984375 0.9771972656250006 +0.58375 -0.009918212890625 -0.438079833984375 0.9771972656250006 +0.583875 -0.009979248046875 -0.440582275390625 0.9771972656250006 +0.584 -0.009979248046875 -0.440582275390625 0.9771972656250006 +0.584125 -0.010040283203125 -0.44305419921875 0.9771972656250006 +0.58425 -0.010101318359375 -0.4454345703125 0.9771972656250006 +0.584375 -0.010101318359375 -0.4454345703125 0.9771972656250006 +0.5845 -0.010162353515625 -0.447784423828125 0.9771972656250006 +0.5846250000000001 -0.010162353515625 -0.447784423828125 0.9771972656250006 +0.58475 -0.01019287109375 -0.450103759765625 0.9771972656250006 +0.584875 -0.01025390625 -0.452362060546875 0.9771972656250006 +0.585 -0.01025390625 -0.452362060546875 0.9771972656250006 +0.585125 -0.01031494140625 -0.454559326171875 0.9771972656250006 +0.58525 -0.01031494140625 -0.454559326171875 0.9771972656250006 +0.585375 -0.010345458984375 -0.45672607421875 0.9771972656250006 +0.5855 -0.010406494140625 -0.458831787109375 0.9771972656250006 +0.5856250000000001 -0.010406494140625 -0.458831787109375 0.9771972656250006 +0.58575 -0.01043701171875 -0.46087646484375 0.9771972656250006 +0.585875 -0.01043701171875 -0.46087646484375 0.9771972656250006 +0.586 -0.010498046875 -0.462890625 0.9771972656250006 +0.586125 -0.010528564453125 -0.464813232421875 0.9771972656250006 +0.58625 -0.010528564453125 -0.464813232421875 0.9771972656250006 +0.586375 -0.010589599609375 -0.46673583984375 0.9771972656250006 +0.5865 -0.010589599609375 -0.46673583984375 0.9771972656250006 +0.5866250000000001 -0.0106201171875 -0.46856689453125 0.9771972656250006 +0.58675 -0.010650634765625 -0.470367431640625 0.9771972656250006 +0.586875 -0.010650634765625 -0.470367431640625 0.9771972656250006 +0.587 -0.010711669921875 -0.472137451171875 0.9771972656250006 +0.587125 -0.010711669921875 -0.472137451171875 0.9771972656250006 +0.58725 -0.0107421875 -0.47381591796875 0.9771972656250006 +0.587375 -0.010772705078125 -0.4754638671875 0.9771972656250006 +0.5875 -0.010772705078125 -0.4754638671875 0.9771972656250006 +0.5876250000000001 -0.01080322265625 -0.47705078125 0.9771972656250006 +0.58775 -0.01080322265625 -0.47705078125 0.9771972656250006 +0.587875 -0.0108642578125 -0.478607177734375 0.9771972656250006 +0.588 -0.010894775390625 -0.480072021484375 0.9771972656250006 +0.588125 -0.010894775390625 -0.480072021484375 0.9771972656250006 +0.5882500000000001 -0.01092529296875 -0.48150634765625 0.9771972656250006 +0.588375 -0.01092529296875 -0.48150634765625 0.9771972656250006 +0.5885 -0.010955810546875 -0.48291015625 0.9771972656250006 +0.5886250000000001 -0.010986328125 -0.484222412109375 0.9771972656250006 +0.58875 -0.010986328125 -0.484222412109375 0.9771972656250006 +0.588875 -0.011016845703125 -0.485504150390625 0.9771972656250006 +0.589 -0.011016845703125 -0.485504150390625 0.9771972656250006 +0.589125 -0.01104736328125 -0.486724853515625 0.9771972656250006 +0.5892500000000001 -0.011077880859375 -0.487884521484375 0.9771972656250006 +0.589375 -0.011077880859375 -0.487884521484375 0.9771972656250006 +0.5895 -0.011077880859375 -0.489013671875 0.9771972656250006 +0.5896250000000001 -0.011077880859375 -0.489013671875 0.9771972656250006 +0.58975 -0.0111083984375 -0.490081787109375 0.9771972656250006 +0.589875 -0.011138916015625 -0.4910888671875 0.9771972656250006 +0.59 -0.011138916015625 -0.4910888671875 0.9771972656250006 +0.590125 -0.01116943359375 -0.492034912109375 0.9771972656250006 +0.5902500000000001 -0.01116943359375 -0.492034912109375 0.9771972656250006 +0.590375 -0.01116943359375 -0.492950439453125 0.9771972656250006 +0.5905 -0.011199951171875 -0.4937744140625 0.9771972656250006 +0.5906250000000001 -0.011199951171875 -0.4937744140625 0.9771972656250006 +0.59075 -0.011199951171875 -0.49456787109375 0.9771972656250006 +0.590875 -0.011199951171875 -0.49456787109375 0.9771972656250006 +0.591 -0.01123046875 -0.49530029296875 0.9771972656250006 +0.591125 -0.011260986328125 -0.496002197265625 0.9771972656250006 +0.5912500000000001 -0.011260986328125 -0.496002197265625 0.9771972656250006 +0.591375 -0.011260986328125 -0.496612548828125 0.9771972656250006 +0.5915 -0.011260986328125 -0.496612548828125 0.9771972656250006 +0.5916250000000001 -0.011260986328125 -0.4971923828125 0.9771972656250006 +0.59175 -0.01129150390625 -0.497711181640625 0.9771972656250006 +0.591875 -0.01129150390625 -0.497711181640625 0.9771972656250006 +0.592 -0.01129150390625 -0.498199462890625 0.9771972656250006 +0.592125 -0.01129150390625 -0.498199462890625 0.9771972656250006 +0.5922500000000001 -0.01129150390625 -0.49859619140625 0.9771972656250006 +0.592375 -0.011322021484375 -0.49896240234375 0.9771972656250006 +0.5925 -0.011322021484375 -0.49896240234375 0.9771972656250006 +0.592625 -0.011322021484375 -0.499267578125 0.9771972656250006 +0.59275 -0.011322021484375 -0.499267578125 0.9771972656250006 +0.592875 -0.011322021484375 -0.49951171875 0.9771972656250006 +0.593 -0.011322021484375 -0.49969482421875 0.9771972656250006 +0.593125 -0.011322021484375 -0.49969482421875 0.9771972656250006 +0.5932500000000001 -0.011322021484375 -0.49981689453125 0.9771972656250006 +0.593375 -0.011322021484375 -0.49981689453125 0.9771972656250006 +0.5935 -0.011322021484375 -0.499908447265625 0.9771972656250006 +0.593625 -0.011322021484375 -0.49993896484375 0.9771972656250006 +0.59375 -0.011322021484375 -0.49993896484375 0.9771972656250006 +0.593875 -0.011322021484375 -0.499908447265625 0.9771972656250006 +0.594 -0.011322021484375 -0.499908447265625 0.9771972656250006 +0.594125 -0.011322021484375 -0.49981689453125 0.9771972656250006 +0.5942500000000001 -0.011322021484375 -0.49969482421875 0.9771972656250006 +0.594375 -0.011322021484375 -0.49969482421875 0.9771972656250006 +0.5945 -0.011322021484375 -0.49951171875 0.9771972656250006 +0.594625 -0.011322021484375 -0.49951171875 0.9771972656250006 +0.59475 -0.011322021484375 -0.499267578125 0.9771972656250006 +0.594875 -0.011322021484375 -0.49896240234375 0.9771972656250006 +0.595 -0.011322021484375 -0.49896240234375 0.9771972656250006 +0.595125 -0.01129150390625 -0.49859619140625 0.9771972656250006 +0.5952500000000001 -0.01129150390625 -0.49859619140625 0.9771972656250006 +0.595375 -0.01129150390625 -0.498199462890625 0.9771972656250006 +0.5955 -0.01129150390625 -0.497711181640625 0.9771972656250006 +0.595625 -0.01129150390625 -0.497711181640625 0.9771972656250006 +0.59575 -0.011260986328125 -0.4971923828125 0.9771972656250006 +0.595875 -0.011260986328125 -0.4971923828125 0.9771972656250006 +0.596 -0.011260986328125 -0.496612548828125 0.9771972656250006 +0.596125 -0.011260986328125 -0.496002197265625 0.9771972656250006 +0.5962500000000001 -0.011260986328125 -0.496002197265625 0.9771972656250006 +0.596375 -0.01123046875 -0.49530029296875 0.9771972656250006 +0.5965 -0.01123046875 -0.49530029296875 0.9771972656250006 +0.596625 -0.011199951171875 -0.49456787109375 0.9771972656250006 +0.59675 -0.011199951171875 -0.4937744140625 0.9771972656250006 +0.596875 -0.011199951171875 -0.4937744140625 0.9771972656250006 +0.597 -0.01116943359375 -0.492950439453125 0.9771972656250006 +0.597125 -0.01116943359375 -0.492950439453125 0.9771972656250006 +0.5972500000000001 -0.01116943359375 -0.492034912109375 0.9771972656250006 +0.597375 -0.011138916015625 -0.4910888671875 0.9771972656250006 +0.5975 -0.011138916015625 -0.4910888671875 0.9771972656250006 +0.597625 -0.0111083984375 -0.490081787109375 0.9771972656250006 +0.59775 -0.0111083984375 -0.490081787109375 0.9771972656250006 +0.597875 -0.011077880859375 -0.489013671875 0.9771972656250006 +0.598 -0.011077880859375 -0.487884521484375 0.9771972656250006 +0.598125 -0.011077880859375 -0.487884521484375 0.9771972656250006 +0.5982500000000001 -0.01104736328125 -0.486724853515625 0.9771972656250006 +0.598375 -0.01104736328125 -0.486724853515625 0.9771972656250006 +0.5985 -0.011016845703125 -0.485504150390625 0.9771972656250006 +0.598625 -0.010986328125 -0.484222412109375 0.9771972656250006 +0.59875 -0.010986328125 -0.484222412109375 0.9771972656250006 +0.598875 -0.010955810546875 -0.48291015625 0.9771972656250006 +0.599 -0.010955810546875 -0.48291015625 0.9771972656250006 +0.599125 -0.01092529296875 -0.48150634765625 0.9771972656250006 +0.5992500000000001 -0.010894775390625 -0.480072021484375 0.9771972656250006 +0.599375 -0.010894775390625 -0.480072021484375 0.9771972656250006 +0.5995 -0.0108642578125 -0.478607177734375 0.9771972656250006 +0.599625 -0.0108642578125 -0.478607177734375 0.9771972656250006 +0.59975 -0.01080322265625 -0.47705078125 0.9771972656250006 +0.599875 -0.010772705078125 -0.4754638671875 0.9771972656250006 +0.6 -0.010772705078125 -0.4754638671875 0.9771972656250006 +0.600125 -0.0107421875 -0.47381591796875 0.9771972656250006 +0.6002500000000001 -0.0107421875 -0.47381591796875 0.9771972656250006 +0.600375 -0.010711669921875 -0.472137451171875 0.9771972656250006 +0.6005 -0.010650634765625 -0.470367431640625 0.9771972656250006 +0.600625 -0.010650634765625 -0.470367431640625 0.9771972656250006 +0.60075 -0.0106201171875 -0.46856689453125 0.9771972656250006 +0.600875 -0.0106201171875 -0.46856689453125 0.9771972656250006 +0.601 -0.010589599609375 -0.46673583984375 0.9771972656250006 +0.601125 -0.010528564453125 -0.464813232421875 0.9771972656250006 +0.6012500000000001 -0.010528564453125 -0.464813232421875 0.9771972656250006 +0.601375 -0.010498046875 -0.462890625 0.9771972656250006 +0.6015 -0.010498046875 -0.462890625 0.9771972656250006 +0.601625 -0.01043701171875 -0.46087646484375 0.9771972656250006 +0.60175 -0.010406494140625 -0.458831787109375 0.9771972656250006 +0.601875 -0.010406494140625 -0.458831787109375 0.9771972656250006 +0.602 -0.010345458984375 -0.45672607421875 0.9771972656250006 +0.602125 -0.010345458984375 -0.45672607421875 0.9771972656250006 +0.6022500000000001 -0.01031494140625 -0.454559326171875 0.9771972656250006 +0.602375 -0.01025390625 -0.452362060546875 0.9771972656250006 +0.6025 -0.01025390625 -0.452362060546875 0.9771972656250006 +0.602625 -0.01019287109375 -0.450103759765625 0.9771972656250006 +0.60275 -0.01019287109375 -0.450103759765625 0.9771972656250006 +0.602875 -0.010162353515625 -0.447784423828125 0.9771972656250006 +0.603 -0.010101318359375 -0.4454345703125 0.9771972656250006 +0.603125 -0.010101318359375 -0.4454345703125 0.9771972656250006 +0.6032500000000001 -0.010040283203125 -0.44305419921875 0.9771972656250006 +0.603375 -0.010040283203125 -0.44305419921875 0.9771972656250006 +0.6035 -0.009979248046875 -0.440582275390625 0.9771972656250006 +0.603625 -0.009918212890625 -0.438079833984375 0.9771972656250006 +0.60375 -0.009918212890625 -0.438079833984375 0.9771972656250006 +0.6038750000000001 -0.0098876953125 -0.435546875 0.9771972656250006 +0.604 -0.0098876953125 -0.435546875 0.9771972656250006 +0.604125 -0.00982666015625 -0.432952880859375 0.9771972656250006 +0.6042500000000001 -0.009765625 -0.4302978515625 0.9771972656250006 +0.604375 -0.009765625 -0.4302978515625 0.9771972656250006 +0.6045 -0.00970458984375 -0.4276123046875 0.9771972656250006 +0.604625 -0.00970458984375 -0.4276123046875 0.9771972656250006 +0.60475 -0.0096435546875 -0.424896240234375 0.9771972656250006 +0.6048750000000001 -0.00958251953125 -0.422119140625 0.9771972656250006 +0.605 -0.00958251953125 -0.422119140625 0.9771972656250006 +0.605125 -0.009490966796875 -0.419281005859375 0.9771972656250006 +0.6052500000000001 -0.009490966796875 -0.419281005859375 0.9771972656250006 +0.605375 -0.009429931640625 -0.416412353515625 0.9771972656250006 +0.6055 -0.009368896484375 -0.413482666015625 0.9771972656250006 +0.605625 -0.009368896484375 -0.413482666015625 0.9771972656250006 +0.60575 -0.009307861328125 -0.4105224609375 0.9771972656250006 +0.6058750000000001 -0.009307861328125 -0.4105224609375 0.9771972656250006 +0.606 -0.009246826171875 -0.407501220703125 0.9771972656250006 +0.606125 -0.0091552734375 -0.404449462890625 0.9771972656250006 +0.6062500000000001 -0.0091552734375 -0.404449462890625 0.9771972656250006 +0.606375 -0.00909423828125 -0.401336669921875 0.9771972656250006 +0.6065 -0.00909423828125 -0.401336669921875 0.9771972656250006 +0.606625 -0.009033203125 -0.398193359375 0.9771972656250006 +0.60675 -0.008941650390625 -0.39501953125 0.9771972656250006 +0.6068750000000001 -0.008941650390625 -0.39501953125 0.9771972656250006 +0.607 -0.008880615234375 -0.39178466796875 0.9771972656250006 +0.607125 -0.008880615234375 -0.39178466796875 0.9771972656250006 +0.6072500000000001 -0.008819580078125 -0.388519287109375 0.9771972656250006 +0.607375 -0.00872802734375 -0.38519287109375 0.9771972656250006 +0.6075 -0.00872802734375 -0.38519287109375 0.9771972656250006 +0.607625 -0.0086669921875 -0.3818359375 0.9771972656250006 +0.60775 -0.0086669921875 -0.3818359375 0.9771972656250006 +0.6078750000000001 -0.008575439453125 -0.378448486328125 0.9771972656250006 +0.608 -0.006622314453125 -0.375 0.9822387695312494 +0.608125 -0.006622314453125 -0.375 0.9822387695312494 +0.60825 -0.006561279296875 -0.37152099609375 0.9822387695312494 +0.608375 -0.006561279296875 -0.37152099609375 0.9822387695312494 +0.6085 -0.006500244140625 -0.36798095703125 0.9822387695312494 +0.608625 -0.006439208984375 -0.36444091796875 0.9822387695312494 +0.60875 -0.006439208984375 -0.36444091796875 0.9822387695312494 +0.6088750000000001 -0.00634765625 -0.360809326171875 0.9822387695312494 +0.609 -0.00634765625 -0.360809326171875 0.9822387695312494 +0.609125 -0.00628662109375 -0.357177734375 0.9822387695312494 +0.60925 -0.0062255859375 -0.353485107421875 0.9822387695312494 +0.609375 -0.0062255859375 -0.353485107421875 0.9822387695312494 +0.6095 -0.00616455078125 -0.349761962890625 0.9822387695312494 +0.609625 -0.00616455078125 -0.349761962890625 0.9822387695312494 +0.60975 -0.006103515625 -0.34600830078125 0.9822387695312494 +0.6098750000000001 -0.00604248046875 -0.34222412109375 0.9822387695312494 +0.61 -0.00604248046875 -0.34222412109375 0.9822387695312494 +0.610125 -0.005950927734375 -0.33837890625 0.9822387695312494 +0.61025 -0.005950927734375 -0.33837890625 0.9822387695312494 +0.610375 -0.005889892578125 -0.334503173828125 0.9822387695312494 +0.6105 -0.005828857421875 -0.330596923828125 0.9822387695312494 +0.610625 -0.005828857421875 -0.330596923828125 0.9822387695312494 +0.61075 -0.005767822265625 -0.32666015625 0.9822387695312494 +0.6108750000000001 -0.005767822265625 -0.32666015625 0.9822387695312494 +0.611 -0.00567626953125 -0.322662353515625 0.9822387695312494 +0.611125 -0.005615234375 -0.31866455078125 0.9822387695312494 +0.61125 -0.005615234375 -0.31866455078125 0.9822387695312494 +0.611375 -0.00555419921875 -0.314605712890625 0.9822387695312494 +0.6115 -0.00555419921875 -0.314605712890625 0.9822387695312494 +0.611625 -0.005462646484375 -0.310516357421875 0.9822387695312494 +0.61175 -0.005401611328125 -0.306396484375 0.9822387695312494 +0.6118750000000001 -0.005401611328125 -0.306396484375 0.9822387695312494 +0.612 -0.005340576171875 -0.30224609375 0.9822387695312494 +0.612125 -0.005340576171875 -0.30224609375 0.9822387695312494 +0.61225 -0.0052490234375 -0.298065185546875 0.9822387695312494 +0.612375 -0.00518798828125 -0.2938232421875 0.9822387695312494 +0.6125 -0.00518798828125 -0.2938232421875 0.9822387695312494 +0.612625 -0.005096435546875 -0.289581298828125 0.9822387695312494 +0.61275 -0.005096435546875 -0.289581298828125 0.9822387695312494 +0.6128750000000001 -0.005035400390625 -0.285308837890625 0.9822387695312494 +0.613 -0.00494384765625 -0.280975341796875 0.9822387695312494 +0.613125 -0.00494384765625 -0.280975341796875 0.9822387695312494 +0.61325 -0.0048828125 -0.276641845703125 0.9822387695312494 +0.613375 -0.0048828125 -0.276641845703125 0.9822387695312494 +0.6135 -0.004791259765625 -0.27227783203125 0.9822387695312494 +0.613625 -0.004730224609375 -0.267852783203125 0.9822387695312494 +0.61375 -0.004730224609375 -0.267852783203125 0.9822387695312494 +0.6138750000000001 -0.004638671875 -0.263427734375 0.9822387695312494 +0.614 -0.004638671875 -0.263427734375 0.9822387695312494 +0.614125 -0.004547119140625 -0.25897216796875 0.9822387695312494 +0.61425 -0.004486083984375 -0.25445556640625 0.9822387695312494 +0.614375 -0.004486083984375 -0.25445556640625 0.9822387695312494 +0.6145 -0.00439453125 -0.249969482421875 0.9822387695312494 +0.614625 -0.00439453125 -0.249969482421875 0.9822387695312494 +0.61475 -0.00433349609375 -0.24542236328125 0.9822387695312494 +0.6148750000000001 -0.004241943359375 -0.2408447265625 0.9822387695312494 +0.615 -0.004241943359375 -0.2408447265625 0.9822387695312494 +0.615125 -0.004150390625 -0.236236572265625 0.9822387695312494 +0.61525 -0.004150390625 -0.236236572265625 0.9822387695312494 +0.615375 -0.00408935546875 -0.231597900390625 0.9822387695312494 +0.6155 -0.003997802734375 -0.226959228515625 0.9822387695312494 +0.615625 -0.003997802734375 -0.226959228515625 0.9822387695312494 +0.61575 -0.00390625 -0.2222900390625 0.9822387695312494 +0.6158750000000001 -0.00390625 -0.2222900390625 0.9822387695312494 +0.616 -0.003814697265625 -0.21759033203125 0.9822387695312494 +0.616125 -0.003753662109375 -0.212860107421875 0.9822387695312494 +0.61625 -0.003753662109375 -0.212860107421875 0.9822387695312494 +0.616375 -0.003662109375 -0.208099365234375 0.9822387695312494 +0.6165 -0.003662109375 -0.208099365234375 0.9822387695312494 +0.616625 -0.003570556640625 -0.203338623046875 0.9822387695312494 +0.61675 -0.00347900390625 -0.19854736328125 0.9822387695312494 +0.6168750000000001 -0.00347900390625 -0.19854736328125 0.9822387695312494 +0.617 -0.00341796875 -0.1937255859375 0.9822387695312494 +0.617125 -0.00341796875 -0.1937255859375 0.9822387695312494 +0.61725 -0.003326416015625 -0.188873291015625 0.9822387695312494 +0.617375 -0.00323486328125 -0.18402099609375 0.9822387695312494 +0.6175 -0.00323486328125 -0.18402099609375 0.9822387695312494 +0.617625 -0.003143310546875 -0.17913818359375 0.9822387695312494 +0.61775 -0.003143310546875 -0.17913818359375 0.9822387695312494 +0.6178750000000001 -0.0030517578125 -0.17425537109375 0.9822387695312494 +0.618 -0.00299072265625 -0.169342041015625 0.9822387695312494 +0.618125 -0.00299072265625 -0.169342041015625 0.9822387695312494 +0.61825 -0.002899169921875 -0.164398193359375 0.9822387695312494 +0.618375 -0.002899169921875 -0.164398193359375 0.9822387695312494 +0.6185 -0.0028076171875 -0.159454345703125 0.9822387695312494 +0.618625 -0.002716064453125 -0.15447998046875 0.9822387695312494 +0.61875 -0.002716064453125 -0.15447998046875 0.9822387695312494 +0.6188750000000001 -0.00262451171875 -0.14947509765625 0.9822387695312494 +0.619 -0.00262451171875 -0.14947509765625 0.9822387695312494 +0.619125 -0.002532958984375 -0.14447021484375 0.9822387695312494 +0.61925 -0.00244140625 -0.13946533203125 0.9822387695312494 +0.619375 -0.00244140625 -0.13946533203125 0.9822387695312494 +0.6195000000000001 -0.002349853515625 -0.134429931640625 0.9822387695312494 +0.619625 -0.002349853515625 -0.134429931640625 0.9822387695312494 +0.61975 -0.00225830078125 -0.129364013671875 0.9822387695312494 +0.6198750000000001 -0.002166748046875 -0.124298095703125 0.9822387695312494 +0.62 -0.002166748046875 -0.124298095703125 0.9822387695312494 +0.620125 -0.002105712890625 -0.119232177734375 0.9822387695312494 +0.62025 -0.002105712890625 -0.119232177734375 0.9822387695312494 +0.620375 -0.00201416015625 -0.1141357421875 0.9822387695312494 +0.6205000000000001 -0.001922607421875 -0.109039306640625 0.9822387695312494 +0.620625 -0.001922607421875 -0.109039306640625 0.9822387695312494 +0.62075 -0.0018310546875 -0.103912353515625 0.9822387695312494 +0.6208750000000001 -0.0018310546875 -0.103912353515625 0.9822387695312494 +0.621 -0.001739501953125 -0.098785400390625 0.9822387695312494 +0.621125 -0.00164794921875 -0.093658447265625 0.9822387695312494 +0.62125 -0.00164794921875 -0.093658447265625 0.9822387695312494 +0.621375 -0.001556396484375 -0.0885009765625 0.9822387695312494 +0.6215000000000001 -0.001556396484375 -0.0885009765625 0.9822387695312494 +0.621625 -0.00146484375 -0.083343505859375 0.9822387695312494 +0.62175 -0.001373291015625 -0.07818603515625 0.9822387695312494 +0.6218750000000001 -0.001373291015625 -0.07818603515625 0.9822387695312494 +0.622 -0.00128173828125 -0.072998046875 0.9822387695312494 +0.622125 -0.00128173828125 -0.072998046875 0.9822387695312494 +0.62225 -0.001190185546875 -0.06781005859375 0.9822387695312494 +0.622375 -0.0010986328125 -0.0626220703125 0.9822387695312494 +0.6225000000000001 -0.0010986328125 -0.0626220703125 0.9822387695312494 +0.622625 -0.001007080078125 -0.05743408203125 0.9822387695312494 +0.62275 -0.001007080078125 -0.05743408203125 0.9822387695312494 +0.6228750000000001 -0.00091552734375 -0.05224609375 0.9822387695312494 +0.623 -0.000823974609375 -0.047027587890625 0.9822387695312494 +0.623125 -0.000823974609375 -0.047027587890625 0.9822387695312494 +0.62325 -0.000732421875 -0.04180908203125 0.9822387695312494 +0.623375 -0.000732421875 -0.04180908203125 0.9822387695312494 +0.6235000000000001 -0.000640869140625 -0.036590576171875 0.9822387695312494 +0.623625 -0.00054931640625 -0.0313720703125 0.9822387695312494 +0.62375 -0.00054931640625 -0.0313720703125 0.9822387695312494 +0.6238750000000001 -0.000457763671875 -0.026123046875 0.9822387695312494 +0.624 -0.000457763671875 -0.026123046875 0.9822387695312494 +0.624125 -0.0003662109375 -0.020904541015625 0.9822387695312494 +0.62425 -0.000274658203125 -0.01568603515625 0.9822387695312494 +0.624375 -0.000274658203125 -0.01568603515625 0.9822387695312494 +0.6245000000000001 -0.00018310546875 -0.01043701171875 0.9822387695312494 +0.624625 -0.00018310546875 -0.01043701171875 0.9822387695312494 +0.62475 -9.1552734375e-05 -0.005218505859375 0.9822387695312494 +0.624875 0.0 0.0 0.9822387695312494 +0.625 0.0 0.0 0.9822387695312494 +0.625125 9.1552734375e-05 0.005218505859375 0.9822387695312494 +0.62525 9.1552734375e-05 0.005218505859375 0.9822387695312494 +0.625375 0.00018310546875 0.01043701171875 0.9822387695312494 +0.6255000000000001 0.000274658203125 0.01568603515625 0.9822387695312494 +0.625625 0.000274658203125 0.01568603515625 0.9822387695312494 +0.62575 0.0003662109375 0.020904541015625 0.9822387695312494 +0.625875 0.0003662109375 0.020904541015625 0.9822387695312494 +0.626 0.000457763671875 0.026123046875 0.9822387695312494 +0.626125 0.00054931640625 0.0313720703125 0.9822387695312494 +0.62625 0.00054931640625 0.0313720703125 0.9822387695312494 +0.626375 0.000640869140625 0.036590576171875 0.9822387695312494 +0.6265000000000001 0.000640869140625 0.036590576171875 0.9822387695312494 +0.626625 0.000732421875 0.04180908203125 0.9822387695312494 +0.62675 0.000823974609375 0.047027587890625 0.9822387695312494 +0.626875 0.000823974609375 0.047027587890625 0.9822387695312494 +0.627 0.00091552734375 0.05224609375 0.9822387695312494 +0.627125 0.00091552734375 0.05224609375 0.9822387695312494 +0.62725 0.001007080078125 0.05743408203125 0.9822387695312494 +0.627375 0.0010986328125 0.0626220703125 0.9822387695312494 +0.6275000000000001 0.0010986328125 0.0626220703125 0.9822387695312494 +0.627625 0.001190185546875 0.06781005859375 0.9822387695312494 +0.62775 0.001190185546875 0.06781005859375 0.9822387695312494 +0.627875 0.00128173828125 0.072998046875 0.9822387695312494 +0.628 0.001373291015625 0.07818603515625 0.9822387695312494 +0.628125 0.001373291015625 0.07818603515625 0.9822387695312494 +0.62825 0.00146484375 0.083343505859375 0.9822387695312494 +0.628375 0.00146484375 0.083343505859375 0.9822387695312494 +0.6285000000000001 0.001556396484375 0.0885009765625 0.9822387695312494 +0.628625 0.00164794921875 0.093658447265625 0.9822387695312494 +0.62875 0.00164794921875 0.093658447265625 0.9822387695312494 +0.628875 0.001739501953125 0.098785400390625 0.9822387695312494 +0.629 0.001739501953125 0.098785400390625 0.9822387695312494 +0.629125 0.0018310546875 0.103912353515625 0.9822387695312494 +0.62925 0.001922607421875 0.109039306640625 0.9822387695312494 +0.629375 0.001922607421875 0.109039306640625 0.9822387695312494 +0.6295000000000001 0.00201416015625 0.1141357421875 0.9822387695312494 +0.629625 0.00201416015625 0.1141357421875 0.9822387695312494 +0.62975 0.002105712890625 0.119232177734375 0.9822387695312494 +0.629875 0.002166748046875 0.124298095703125 0.9822387695312494 +0.63 0.002166748046875 0.124298095703125 0.9822387695312494 +0.630125 0.00225830078125 0.129364013671875 0.9822387695312494 +0.63025 0.00225830078125 0.129364013671875 0.9822387695312494 +0.630375 0.002349853515625 0.134429931640625 0.9822387695312494 +0.6305000000000001 0.00244140625 0.13946533203125 0.9822387695312494 +0.630625 0.00244140625 0.13946533203125 0.9822387695312494 +0.63075 0.002532958984375 0.14447021484375 0.9822387695312494 +0.630875 0.002532958984375 0.14447021484375 0.9822387695312494 +0.631 0.00262451171875 0.14947509765625 0.9822387695312494 +0.631125 0.002716064453125 0.15447998046875 0.9822387695312494 +0.63125 0.002716064453125 0.15447998046875 0.9822387695312494 +0.631375 0.0028076171875 0.159454345703125 0.9822387695312494 +0.6315000000000001 0.0028076171875 0.159454345703125 0.9822387695312494 +0.631625 0.002899169921875 0.164398193359375 0.9822387695312494 +0.63175 0.00299072265625 0.169342041015625 0.9822387695312494 +0.631875 0.00299072265625 0.169342041015625 0.9822387695312494 +0.632 0.0030517578125 0.17425537109375 0.9822387695312494 +0.632125 0.0030517578125 0.17425537109375 0.9822387695312494 +0.63225 0.003143310546875 0.17913818359375 0.9822387695312494 +0.632375 0.00323486328125 0.18402099609375 0.9822387695312494 +0.6325000000000001 0.00323486328125 0.18402099609375 0.9822387695312494 +0.632625 0.003326416015625 0.188873291015625 0.9822387695312494 +0.63275 0.003326416015625 0.188873291015625 0.9822387695312494 +0.632875 0.00341796875 0.1937255859375 0.9822387695312494 +0.633 0.00347900390625 0.19854736328125 0.9822387695312494 +0.633125 0.00347900390625 0.19854736328125 0.9822387695312494 +0.63325 0.003570556640625 0.203338623046875 0.9822387695312494 +0.633375 0.003570556640625 0.203338623046875 0.9822387695312494 +0.6335000000000001 0.003662109375 0.208099365234375 0.9822387695312494 +0.633625 0.003753662109375 0.212860107421875 0.9822387695312494 +0.63375 0.003753662109375 0.212860107421875 0.9822387695312494 +0.633875 0.003814697265625 0.21759033203125 0.9822387695312494 +0.634 0.003814697265625 0.21759033203125 0.9822387695312494 +0.634125 0.00390625 0.2222900390625 0.9822387695312494 +0.63425 0.003997802734375 0.226959228515625 0.9822387695312494 +0.634375 0.003997802734375 0.226959228515625 0.9822387695312494 +0.6345000000000001 0.00408935546875 0.231597900390625 0.9822387695312494 +0.634625 0.00408935546875 0.231597900390625 0.9822387695312494 +0.63475 0.004150390625 0.236236572265625 0.9822387695312494 +0.634875 0.004241943359375 0.2408447265625 0.9822387695312494 +0.635 0.004241943359375 0.2408447265625 0.9822387695312494 +0.6351250000000001 0.00433349609375 0.24542236328125 0.9822387695312494 +0.63525 0.00433349609375 0.24542236328125 0.9822387695312494 +0.635375 0.00439453125 0.249969482421875 0.9822387695312494 +0.6355000000000001 0.004486083984375 0.25445556640625 0.9822387695312494 +0.635625 0.004486083984375 0.25445556640625 0.9822387695312494 +0.63575 0.004547119140625 0.25897216796875 0.9822387695312494 +0.635875 0.004547119140625 0.25897216796875 0.9822387695312494 +0.636 0.004638671875 0.263427734375 0.9822387695312494 +0.6361250000000001 0.004730224609375 0.267852783203125 0.9822387695312494 +0.63625 0.004730224609375 0.267852783203125 0.9822387695312494 +0.636375 0.004791259765625 0.27227783203125 0.9822387695312494 +0.6365000000000001 0.004791259765625 0.27227783203125 0.9822387695312494 +0.636625 0.0048828125 0.276641845703125 0.9822387695312494 +0.63675 0.00494384765625 0.280975341796875 0.9822387695312494 +0.636875 0.00494384765625 0.280975341796875 0.9822387695312494 +0.637 0.005035400390625 0.285308837890625 0.9822387695312494 +0.6371250000000001 0.005035400390625 0.285308837890625 0.9822387695312494 +0.63725 0.005096435546875 0.289581298828125 0.9822387695312494 +0.637375 0.00518798828125 0.2938232421875 0.9822387695312494 +0.6375000000000001 0.00518798828125 0.2938232421875 0.9822387695312494 +0.637625 0.0052490234375 0.298065185546875 0.9822387695312494 +0.63775 0.0052490234375 0.298065185546875 0.9822387695312494 +0.637875 0.005340576171875 0.30224609375 0.9822387695312494 +0.638 0.005401611328125 0.306396484375 0.9822387695312494 +0.6381250000000001 0.005401611328125 0.306396484375 0.9822387695312494 +0.63825 0.005462646484375 0.310516357421875 0.9822387695312494 +0.638375 0.005462646484375 0.310516357421875 0.9822387695312494 +0.6385000000000001 0.00555419921875 0.314605712890625 0.9822387695312494 +0.638625 0.005615234375 0.31866455078125 0.9822387695312494 +0.63875 0.005615234375 0.31866455078125 0.9822387695312494 +0.638875 0.00567626953125 0.322662353515625 0.9822387695312494 +0.639 0.00567626953125 0.322662353515625 0.9822387695312494 +0.6391250000000001 0.005767822265625 0.32666015625 0.9822387695312494 +0.63925 0.005828857421875 0.330596923828125 0.9822387695312494 +0.639375 0.005828857421875 0.330596923828125 0.9822387695312494 +0.6395000000000001 0.005889892578125 0.334503173828125 0.9822387695312494 +0.639625 0.005889892578125 0.334503173828125 0.9822387695312494 +0.63975 0.005950927734375 0.33837890625 0.9822387695312494 +0.639875 0.00604248046875 0.34222412109375 0.9822387695312494 +0.64 0.057952880859375 0.34222412109375 0.8305419921874982 +0.6401250000000001 0.05859375 0.34600830078125 0.8305419921874982 +0.64025 0.05859375 0.34600830078125 0.8305419921874982 +0.640375 0.059234619140625 0.349761962890625 0.8305419921874982 +0.6405 0.05987548828125 0.353485107421875 0.8305419921874982 +0.640625 0.05987548828125 0.353485107421875 0.8305419921874982 +0.64075 0.06048583984375 0.357177734375 0.8305419921874982 +0.640875 0.06048583984375 0.357177734375 0.8305419921874982 +0.641 0.06109619140625 0.360809326171875 0.8305419921874982 +0.6411250000000001 0.06170654296875 0.36444091796875 0.8305419921874982 +0.64125 0.06170654296875 0.36444091796875 0.8305419921874982 +0.641375 0.06231689453125 0.36798095703125 0.8305419921874982 +0.6415 0.06231689453125 0.36798095703125 0.8305419921874982 +0.641625 0.06292724609375 0.37152099609375 0.8305419921874982 +0.64175 0.063507080078125 0.375 0.8305419921874982 +0.641875 0.063507080078125 0.375 0.8305419921874982 +0.642 0.0640869140625 0.378448486328125 0.8305419921874982 +0.6421250000000001 0.0640869140625 0.378448486328125 0.8305419921874982 +0.64225 0.064666748046875 0.3818359375 0.8305419921874982 +0.642375 0.06524658203125 0.38519287109375 0.8305419921874982 +0.6425 0.06524658203125 0.38519287109375 0.8305419921874982 +0.642625 0.0657958984375 0.388519287109375 0.8305419921874982 +0.64275 0.0657958984375 0.388519287109375 0.8305419921874982 +0.642875 0.06634521484375 0.39178466796875 0.8305419921874982 +0.643 0.06689453125 0.39501953125 0.8305419921874982 +0.6431250000000001 0.06689453125 0.39501953125 0.8305419921874982 +0.64325 0.06744384765625 0.398193359375 0.8305419921874982 +0.643375 0.06744384765625 0.398193359375 0.8305419921874982 +0.6435 0.067962646484375 0.401336669921875 0.8305419921874982 +0.643625 0.0684814453125 0.404449462890625 0.8305419921874982 +0.64375 0.0684814453125 0.404449462890625 0.8305419921874982 +0.643875 0.069000244140625 0.407501220703125 0.8305419921874982 +0.644 0.069000244140625 0.407501220703125 0.8305419921874982 +0.6441250000000001 0.06951904296875 0.4105224609375 0.8305419921874982 +0.64425 0.07000732421875 0.413482666015625 0.8305419921874982 +0.644375 0.07000732421875 0.413482666015625 0.8305419921874982 +0.6445 0.070526123046875 0.416412353515625 0.8305419921874982 +0.644625 0.070526123046875 0.416412353515625 0.8305419921874982 +0.64475 0.071014404296875 0.419281005859375 0.8305419921874982 +0.644875 0.07147216796875 0.422119140625 0.8305419921874982 +0.645 0.07147216796875 0.422119140625 0.8305419921874982 +0.6451250000000001 0.07196044921875 0.424896240234375 0.8305419921874982 +0.64525 0.07196044921875 0.424896240234375 0.8305419921874982 +0.645375 0.072418212890625 0.4276123046875 0.8305419921874982 +0.6455 0.0728759765625 0.4302978515625 0.8305419921874982 +0.645625 0.0728759765625 0.4302978515625 0.8305419921874982 +0.64575 0.073333740234375 0.432952880859375 0.8305419921874982 +0.645875 0.073333740234375 0.432952880859375 0.8305419921874982 +0.646 0.073760986328125 0.435546875 0.8305419921874982 +0.6461250000000001 0.074188232421875 0.438079833984375 0.8305419921874982 +0.64625 0.074188232421875 0.438079833984375 0.8305419921874982 +0.646375 0.074615478515625 0.440582275390625 0.8305419921874982 +0.6465 0.074615478515625 0.440582275390625 0.8305419921874982 +0.646625 0.075042724609375 0.44305419921875 0.8305419921874982 +0.64675 0.075439453125 0.4454345703125 0.8305419921874982 +0.646875 0.075439453125 0.4454345703125 0.8305419921874982 +0.647 0.075836181640625 0.447784423828125 0.8305419921874982 +0.6471250000000001 0.075836181640625 0.447784423828125 0.8305419921874982 +0.64725 0.07623291015625 0.450103759765625 0.8305419921874982 +0.647375 0.07659912109375 0.452362060546875 0.8305419921874982 +0.6475 0.07659912109375 0.452362060546875 0.8305419921874982 +0.647625 0.07696533203125 0.454559326171875 0.8305419921874982 +0.64775 0.07696533203125 0.454559326171875 0.8305419921874982 +0.647875 0.07733154296875 0.45672607421875 0.8305419921874982 +0.648 0.07769775390625 0.458831787109375 0.8305419921874982 +0.6481250000000001 0.07769775390625 0.458831787109375 0.8305419921874982 +0.64825 0.07806396484375 0.46087646484375 0.8305419921874982 +0.648375 0.07806396484375 0.46087646484375 0.8305419921874982 +0.6485 0.078399658203125 0.462890625 0.8305419921874982 +0.648625 0.078704833984375 0.464813232421875 0.8305419921874982 +0.64875 0.078704833984375 0.464813232421875 0.8305419921874982 +0.648875 0.07904052734375 0.46673583984375 0.8305419921874982 +0.649 0.07904052734375 0.46673583984375 0.8305419921874982 +0.6491250000000001 0.079345703125 0.46856689453125 0.8305419921874982 +0.64925 0.07965087890625 0.470367431640625 0.8305419921874982 +0.649375 0.07965087890625 0.470367431640625 0.8305419921874982 +0.6495 0.0799560546875 0.472137451171875 0.8305419921874982 +0.649625 0.0799560546875 0.472137451171875 0.8305419921874982 +0.64975 0.080230712890625 0.47381591796875 0.8305419921874982 +0.649875 0.080535888671875 0.4754638671875 0.8305419921874982 +0.65 0.080535888671875 0.4754638671875 0.8305419921874982 +0.6501250000000001 0.080780029296875 0.47705078125 0.8305419921874982 +0.65025 0.080780029296875 0.47705078125 0.8305419921874982 +0.650375 0.0810546875 0.478607177734375 0.8305419921874982 +0.6505 0.081298828125 0.480072021484375 0.8305419921874982 +0.650625 0.081298828125 0.480072021484375 0.8305419921874982 +0.6507500000000001 0.08154296875 0.48150634765625 0.8305419921874982 +0.650875 0.08154296875 0.48150634765625 0.8305419921874982 +0.651 0.081787109375 0.48291015625 0.8305419921874982 +0.6511250000000001 0.082000732421875 0.484222412109375 0.8305419921874982 +0.65125 0.082000732421875 0.484222412109375 0.8305419921874982 +0.651375 0.08221435546875 0.485504150390625 0.8305419921874982 +0.6515 0.08221435546875 0.485504150390625 0.8305419921874982 +0.651625 0.082427978515625 0.486724853515625 0.8305419921874982 +0.6517500000000001 0.0826416015625 0.487884521484375 0.8305419921874982 +0.651875 0.0826416015625 0.487884521484375 0.8305419921874982 +0.652 0.08282470703125 0.489013671875 0.8305419921874982 +0.6521250000000001 0.08282470703125 0.489013671875 0.8305419921874982 +0.65225 0.0830078125 0.490081787109375 0.8305419921874982 +0.652375 0.083160400390625 0.4910888671875 0.8305419921874982 +0.6525 0.083160400390625 0.4910888671875 0.8305419921874982 +0.652625 0.083343505859375 0.492034912109375 0.8305419921874982 +0.6527500000000001 0.083343505859375 0.492034912109375 0.8305419921874982 +0.652875 0.08349609375 0.492950439453125 0.8305419921874982 +0.653 0.0836181640625 0.4937744140625 0.8305419921874982 +0.6531250000000001 0.0836181640625 0.4937744140625 0.8305419921874982 +0.65325 0.083770751953125 0.49456787109375 0.8305419921874982 +0.653375 0.083770751953125 0.49456787109375 0.8305419921874982 +0.6535 0.083892822265625 0.49530029296875 0.8305419921874982 +0.653625 0.083984375 0.496002197265625 0.8305419921874982 +0.6537500000000001 0.083984375 0.496002197265625 0.8305419921874982 +0.653875 0.0841064453125 0.496612548828125 0.8305419921874982 +0.654 0.0841064453125 0.496612548828125 0.8305419921874982 +0.6541250000000001 0.084197998046875 0.4971923828125 0.8305419921874982 +0.65425 0.08428955078125 0.497711181640625 0.8305419921874982 +0.654375 0.08428955078125 0.497711181640625 0.8305419921874982 +0.6545 0.084381103515625 0.498199462890625 0.8305419921874982 +0.654625 0.084381103515625 0.498199462890625 0.8305419921874982 +0.6547500000000001 0.084442138671875 0.49859619140625 0.8305419921874982 +0.654875 0.084503173828125 0.49896240234375 0.8305419921874982 +0.655 0.084503173828125 0.49896240234375 0.8305419921874982 +0.6551250000000001 0.084564208984375 0.499267578125 0.8305419921874982 +0.65525 0.084564208984375 0.499267578125 0.8305419921874982 +0.655375 0.0845947265625 0.49951171875 0.8305419921874982 +0.6555 0.084625244140625 0.49969482421875 0.8305419921874982 +0.655625 0.084625244140625 0.49969482421875 0.8305419921874982 +0.6557500000000001 0.08465576171875 0.49981689453125 0.8305419921874982 +0.655875 0.08465576171875 0.49981689453125 0.8305419921874982 +0.656 0.08465576171875 0.499908447265625 0.8305419921874982 +0.656125 0.08465576171875 0.49993896484375 0.8305419921874982 +0.65625 0.08465576171875 0.49993896484375 0.8305419921874982 +0.656375 0.08465576171875 0.499908447265625 0.8305419921874982 +0.6565 0.08465576171875 0.499908447265625 0.8305419921874982 +0.656625 0.08465576171875 0.49981689453125 0.8305419921874982 +0.6567500000000001 0.084625244140625 0.49969482421875 0.8305419921874982 +0.656875 0.084625244140625 0.49969482421875 0.8305419921874982 +0.657 0.0845947265625 0.49951171875 0.8305419921874982 +0.657125 0.0845947265625 0.49951171875 0.8305419921874982 +0.65725 0.084564208984375 0.499267578125 0.8305419921874982 +0.657375 0.084503173828125 0.49896240234375 0.8305419921874982 +0.6575 0.084503173828125 0.49896240234375 0.8305419921874982 +0.657625 0.084442138671875 0.49859619140625 0.8305419921874982 +0.6577500000000001 0.084442138671875 0.49859619140625 0.8305419921874982 +0.657875 0.084381103515625 0.498199462890625 0.8305419921874982 +0.658 0.08428955078125 0.497711181640625 0.8305419921874982 +0.658125 0.08428955078125 0.497711181640625 0.8305419921874982 +0.65825 0.084197998046875 0.4971923828125 0.8305419921874982 +0.658375 0.084197998046875 0.4971923828125 0.8305419921874982 +0.6585 0.0841064453125 0.496612548828125 0.8305419921874982 +0.658625 0.083984375 0.496002197265625 0.8305419921874982 +0.6587500000000001 0.083984375 0.496002197265625 0.8305419921874982 +0.658875 0.083892822265625 0.49530029296875 0.8305419921874982 +0.659 0.083892822265625 0.49530029296875 0.8305419921874982 +0.659125 0.083770751953125 0.49456787109375 0.8305419921874982 +0.65925 0.0836181640625 0.4937744140625 0.8305419921874982 +0.659375 0.0836181640625 0.4937744140625 0.8305419921874982 +0.6595 0.08349609375 0.492950439453125 0.8305419921874982 +0.659625 0.08349609375 0.492950439453125 0.8305419921874982 +0.6597500000000001 0.083343505859375 0.492034912109375 0.8305419921874982 +0.659875 0.083160400390625 0.4910888671875 0.8305419921874982 +0.66 0.083160400390625 0.4910888671875 0.8305419921874982 +0.660125 0.0830078125 0.490081787109375 0.8305419921874982 +0.66025 0.0830078125 0.490081787109375 0.8305419921874982 +0.660375 0.08282470703125 0.489013671875 0.8305419921874982 +0.6605 0.0826416015625 0.487884521484375 0.8305419921874982 +0.660625 0.0826416015625 0.487884521484375 0.8305419921874982 +0.6607500000000001 0.082427978515625 0.486724853515625 0.8305419921874982 +0.660875 0.082427978515625 0.486724853515625 0.8305419921874982 +0.661 0.08221435546875 0.485504150390625 0.8305419921874982 +0.661125 0.082000732421875 0.484222412109375 0.8305419921874982 +0.66125 0.082000732421875 0.484222412109375 0.8305419921874982 +0.661375 0.081787109375 0.48291015625 0.8305419921874982 +0.6615 0.081787109375 0.48291015625 0.8305419921874982 +0.661625 0.08154296875 0.48150634765625 0.8305419921874982 +0.6617500000000001 0.081298828125 0.480072021484375 0.8305419921874982 +0.661875 0.081298828125 0.480072021484375 0.8305419921874982 +0.662 0.0810546875 0.478607177734375 0.8305419921874982 +0.662125 0.0810546875 0.478607177734375 0.8305419921874982 +0.66225 0.080780029296875 0.47705078125 0.8305419921874982 +0.662375 0.080535888671875 0.4754638671875 0.8305419921874982 +0.6625 0.080535888671875 0.4754638671875 0.8305419921874982 +0.662625 0.080230712890625 0.47381591796875 0.8305419921874982 +0.6627500000000001 0.080230712890625 0.47381591796875 0.8305419921874982 +0.662875 0.0799560546875 0.472137451171875 0.8305419921874982 +0.663 0.07965087890625 0.470367431640625 0.8305419921874982 +0.663125 0.07965087890625 0.470367431640625 0.8305419921874982 +0.66325 0.079345703125 0.46856689453125 0.8305419921874982 +0.663375 0.079345703125 0.46856689453125 0.8305419921874982 +0.6635 0.07904052734375 0.46673583984375 0.8305419921874982 +0.663625 0.078704833984375 0.464813232421875 0.8305419921874982 +0.6637500000000001 0.078704833984375 0.464813232421875 0.8305419921874982 +0.663875 0.078399658203125 0.462890625 0.8305419921874982 +0.664 0.078399658203125 0.462890625 0.8305419921874982 +0.664125 0.07806396484375 0.46087646484375 0.8305419921874982 +0.66425 0.07769775390625 0.458831787109375 0.8305419921874982 +0.664375 0.07769775390625 0.458831787109375 0.8305419921874982 +0.6645 0.07733154296875 0.45672607421875 0.8305419921874982 +0.664625 0.07733154296875 0.45672607421875 0.8305419921874982 +0.6647500000000001 0.07696533203125 0.454559326171875 0.8305419921874982 +0.664875 0.07659912109375 0.452362060546875 0.8305419921874982 +0.665 0.07659912109375 0.452362060546875 0.8305419921874982 +0.665125 0.07623291015625 0.450103759765625 0.8305419921874982 +0.66525 0.07623291015625 0.450103759765625 0.8305419921874982 +0.665375 0.075836181640625 0.447784423828125 0.8305419921874982 +0.6655 0.075439453125 0.4454345703125 0.8305419921874982 +0.665625 0.075439453125 0.4454345703125 0.8305419921874982 +0.6657500000000001 0.075042724609375 0.44305419921875 0.8305419921874982 +0.665875 0.075042724609375 0.44305419921875 0.8305419921874982 +0.666 0.074615478515625 0.440582275390625 0.8305419921874982 +0.666125 0.074188232421875 0.438079833984375 0.8305419921874982 +0.66625 0.074188232421875 0.438079833984375 0.8305419921874982 +0.6663750000000001 0.073760986328125 0.435546875 0.8305419921874982 +0.6665 0.073760986328125 0.435546875 0.8305419921874982 +0.666625 0.073333740234375 0.432952880859375 0.8305419921874982 +0.6667500000000001 0.0728759765625 0.4302978515625 0.8305419921874982 +0.666875 0.0728759765625 0.4302978515625 0.8305419921874982 +0.667 0.072418212890625 0.4276123046875 0.8305419921874982 +0.667125 0.072418212890625 0.4276123046875 0.8305419921874982 +0.66725 0.07196044921875 0.424896240234375 0.8305419921874982 +0.6673750000000001 0.07147216796875 0.422119140625 0.8305419921874982 +0.6675 0.07147216796875 0.422119140625 0.8305419921874982 +0.667625 0.071014404296875 0.419281005859375 0.8305419921874982 +0.6677500000000001 0.071014404296875 0.419281005859375 0.8305419921874982 +0.667875 0.070526123046875 0.416412353515625 0.8305419921874982 +0.668 0.07000732421875 0.413482666015625 0.8305419921874982 +0.668125 0.07000732421875 0.413482666015625 0.8305419921874982 +0.66825 0.06951904296875 0.4105224609375 0.8305419921874982 +0.6683750000000001 0.06951904296875 0.4105224609375 0.8305419921874982 +0.6685 0.069000244140625 0.407501220703125 0.8305419921874982 +0.668625 0.0684814453125 0.404449462890625 0.8305419921874982 +0.6687500000000001 0.0684814453125 0.404449462890625 0.8305419921874982 +0.668875 0.067962646484375 0.401336669921875 0.8305419921874982 +0.669 0.067962646484375 0.401336669921875 0.8305419921874982 +0.669125 0.06744384765625 0.398193359375 0.8305419921874982 +0.66925 0.06689453125 0.39501953125 0.8305419921874982 +0.6693750000000001 0.06689453125 0.39501953125 0.8305419921874982 +0.6695 0.06634521484375 0.39178466796875 0.8305419921874982 +0.669625 0.06634521484375 0.39178466796875 0.8305419921874982 +0.6697500000000001 0.0657958984375 0.388519287109375 0.8305419921874982 +0.669875 0.06524658203125 0.38519287109375 0.8305419921874982 +0.67 0.06524658203125 0.38519287109375 0.8305419921874982 +0.670125 0.064666748046875 0.3818359375 0.8305419921874982 +0.67025 0.064666748046875 0.3818359375 0.8305419921874982 +0.6703750000000001 0.0640869140625 0.378448486328125 0.8305419921874982 +0.6705 0.063507080078125 0.375 0.8305419921874982 +0.670625 0.063507080078125 0.375 0.8305419921874982 +0.6707500000000001 0.06292724609375 0.37152099609375 0.8305419921874982 +0.670875 0.06292724609375 0.37152099609375 0.8305419921874982 +0.671 0.06231689453125 0.36798095703125 0.8305419921874982 +0.671125 0.06170654296875 0.36444091796875 0.8305419921874982 +0.67125 0.06170654296875 0.36444091796875 0.8305419921874982 +0.6713750000000001 0.06109619140625 0.360809326171875 0.8305419921874982 +0.6715 0.06109619140625 0.360809326171875 0.8305419921874982 +0.671625 0.06048583984375 0.357177734375 0.8305419921874982 +0.6717500000000001 0.05987548828125 0.353485107421875 0.8305419921874982 +0.671875 0.05987548828125 0.353485107421875 0.8305419921874982 +0.672 0.15863037109375 0.349761962890625 0.5463623046874974 +0.672125 0.15863037109375 0.349761962890625 0.5463623046874974 +0.67225 0.156951904296875 0.34600830078125 0.5463623046874974 +0.6723750000000001 0.15521240234375 0.34222412109375 0.5463623046874974 +0.6725 0.15521240234375 0.34222412109375 0.5463623046874974 +0.672625 0.153472900390625 0.33837890625 0.5463623046874974 +0.67275 0.153472900390625 0.33837890625 0.5463623046874974 +0.672875 0.1517333984375 0.334503173828125 0.5463623046874974 +0.673 0.14996337890625 0.330596923828125 0.5463623046874974 +0.673125 0.14996337890625 0.330596923828125 0.5463623046874974 +0.67325 0.148162841796875 0.32666015625 0.5463623046874974 +0.6733750000000001 0.148162841796875 0.32666015625 0.5463623046874974 +0.6735 0.1463623046875 0.322662353515625 0.5463623046874974 +0.673625 0.14453125 0.31866455078125 0.5463623046874974 +0.67375 0.14453125 0.31866455078125 0.5463623046874974 +0.673875 0.1427001953125 0.314605712890625 0.5463623046874974 +0.674 0.1427001953125 0.314605712890625 0.5463623046874974 +0.674125 0.140838623046875 0.310516357421875 0.5463623046874974 +0.67425 0.13897705078125 0.306396484375 0.5463623046874974 +0.6743750000000001 0.13897705078125 0.306396484375 0.5463623046874974 +0.6745 0.1370849609375 0.30224609375 0.5463623046874974 +0.674625 0.1370849609375 0.30224609375 0.5463623046874974 +0.67475 0.13519287109375 0.298065185546875 0.5463623046874974 +0.674875 0.133270263671875 0.2938232421875 0.5463623046874974 +0.675 0.133270263671875 0.2938232421875 0.5463623046874974 +0.675125 0.13134765625 0.289581298828125 0.5463623046874974 +0.67525 0.13134765625 0.289581298828125 0.5463623046874974 +0.6753750000000001 0.12939453125 0.285308837890625 0.5463623046874974 +0.6755 0.12744140625 0.280975341796875 0.5463623046874974 +0.675625 0.12744140625 0.280975341796875 0.5463623046874974 +0.67575 0.125457763671875 0.276641845703125 0.5463623046874974 +0.675875 0.125457763671875 0.276641845703125 0.5463623046874974 +0.676 0.123504638671875 0.27227783203125 0.5463623046874974 +0.676125 0.121490478515625 0.267852783203125 0.5463623046874974 +0.67625 0.121490478515625 0.267852783203125 0.5463623046874974 +0.6763750000000001 0.119476318359375 0.263427734375 0.5463623046874974 +0.6765 0.119476318359375 0.263427734375 0.5463623046874974 +0.676625 0.117462158203125 0.25897216796875 0.5463623046874974 +0.67675 0.11541748046875 0.25445556640625 0.5463623046874974 +0.676875 0.11541748046875 0.25445556640625 0.5463623046874974 +0.677 0.113372802734375 0.249969482421875 0.5463623046874974 +0.677125 0.113372802734375 0.249969482421875 0.5463623046874974 +0.67725 0.111297607421875 0.24542236328125 0.5463623046874974 +0.6773750000000001 0.109222412109375 0.2408447265625 0.5463623046874974 +0.6775 0.109222412109375 0.2408447265625 0.5463623046874974 +0.677625 0.107147216796875 0.236236572265625 0.5463623046874974 +0.67775 0.107147216796875 0.236236572265625 0.5463623046874974 +0.677875 0.10504150390625 0.231597900390625 0.5463623046874974 +0.678 0.102935791015625 0.226959228515625 0.5463623046874974 +0.678125 0.102935791015625 0.226959228515625 0.5463623046874974 +0.67825 0.100799560546875 0.2222900390625 0.5463623046874974 +0.6783750000000001 0.100799560546875 0.2222900390625 0.5463623046874974 +0.6785 0.09869384765625 0.21759033203125 0.5463623046874974 +0.678625 0.096527099609375 0.212860107421875 0.5463623046874974 +0.67875 0.096527099609375 0.212860107421875 0.5463623046874974 +0.678875 0.094390869140625 0.208099365234375 0.5463623046874974 +0.679 0.094390869140625 0.208099365234375 0.5463623046874974 +0.679125 0.09222412109375 0.203338623046875 0.5463623046874974 +0.67925 0.090057373046875 0.19854736328125 0.5463623046874974 +0.6793750000000001 0.090057373046875 0.19854736328125 0.5463623046874974 +0.6795 0.087860107421875 0.1937255859375 0.5463623046874974 +0.679625 0.087860107421875 0.1937255859375 0.5463623046874974 +0.67975 0.085662841796875 0.188873291015625 0.5463623046874974 +0.679875 0.083465576171875 0.18402099609375 0.5463623046874974 +0.68 0.083465576171875 0.18402099609375 0.5463623046874974 +0.680125 0.08123779296875 0.17913818359375 0.5463623046874974 +0.68025 0.08123779296875 0.17913818359375 0.5463623046874974 +0.6803750000000001 0.07904052734375 0.17425537109375 0.5463623046874974 +0.6805 0.0767822265625 0.169342041015625 0.5463623046874974 +0.680625 0.0767822265625 0.169342041015625 0.5463623046874974 +0.68075 0.074554443359375 0.164398193359375 0.5463623046874974 +0.680875 0.074554443359375 0.164398193359375 0.5463623046874974 +0.681 0.07232666015625 0.159454345703125 0.5463623046874974 +0.681125 0.070068359375 0.15447998046875 0.5463623046874974 +0.68125 0.070068359375 0.15447998046875 0.5463623046874974 +0.6813750000000001 0.067779541015625 0.14947509765625 0.5463623046874974 +0.6815 0.067779541015625 0.14947509765625 0.5463623046874974 +0.681625 0.065521240234375 0.14447021484375 0.5463623046874974 +0.68175 0.063232421875 0.13946533203125 0.5463623046874974 +0.681875 0.063232421875 0.13946533203125 0.5463623046874974 +0.6820000000000001 0.06097412109375 0.134429931640625 0.5463623046874974 +0.682125 0.06097412109375 0.134429931640625 0.5463623046874974 +0.68225 0.058685302734375 0.129364013671875 0.5463623046874974 +0.6823750000000001 0.056365966796875 0.124298095703125 0.5463623046874974 +0.6825 0.056365966796875 0.124298095703125 0.5463623046874974 +0.682625 0.0540771484375 0.119232177734375 0.5463623046874974 +0.68275 0.0540771484375 0.119232177734375 0.5463623046874974 +0.682875 0.0517578125 0.1141357421875 0.5463623046874974 +0.6830000000000001 0.0494384765625 0.109039306640625 0.5463623046874974 +0.683125 0.0494384765625 0.109039306640625 0.5463623046874974 +0.68325 0.047119140625 0.103912353515625 0.5463623046874974 +0.6833750000000001 0.047119140625 0.103912353515625 0.5463623046874974 +0.6835 0.0447998046875 0.098785400390625 0.5463623046874974 +0.683625 0.04248046875 0.093658447265625 0.5463623046874974 +0.68375 0.04248046875 0.093658447265625 0.5463623046874974 +0.683875 0.040130615234375 0.0885009765625 0.5463623046874974 +0.6840000000000001 0.040130615234375 0.0885009765625 0.5463623046874974 +0.684125 0.037811279296875 0.083343505859375 0.5463623046874974 +0.68425 0.03546142578125 0.07818603515625 0.5463623046874974 +0.6843750000000001 0.03546142578125 0.07818603515625 0.5463623046874974 +0.6845 0.033111572265625 0.072998046875 0.5463623046874974 +0.684625 0.033111572265625 0.072998046875 0.5463623046874974 +0.68475 0.03076171875 0.06781005859375 0.5463623046874974 +0.684875 0.028411865234375 0.0626220703125 0.5463623046874974 +0.6850000000000001 0.028411865234375 0.0626220703125 0.5463623046874974 +0.685125 0.02606201171875 0.05743408203125 0.5463623046874974 +0.68525 0.02606201171875 0.05743408203125 0.5463623046874974 +0.6853750000000001 0.023681640625 0.05224609375 0.5463623046874974 +0.6855 0.021331787109375 0.047027587890625 0.5463623046874974 +0.685625 0.021331787109375 0.047027587890625 0.5463623046874974 +0.68575 0.018951416015625 0.04180908203125 0.5463623046874974 +0.685875 0.018951416015625 0.04180908203125 0.5463623046874974 +0.6860000000000001 0.0166015625 0.036590576171875 0.5463623046874974 +0.686125 0.01422119140625 0.0313720703125 0.5463623046874974 +0.68625 0.01422119140625 0.0313720703125 0.5463623046874974 +0.6863750000000001 0.0118408203125 0.026123046875 0.5463623046874974 +0.6865 0.0118408203125 0.026123046875 0.5463623046874974 +0.686625 0.009490966796875 0.020904541015625 0.5463623046874974 +0.68675 0.007110595703125 0.01568603515625 0.5463623046874974 +0.686875 0.007110595703125 0.01568603515625 0.5463623046874974 +0.6870000000000001 0.004730224609375 0.01043701171875 0.5463623046874974 +0.687125 0.004730224609375 0.01043701171875 0.5463623046874974 +0.68725 0.002349853515625 0.005218505859375 0.5463623046874974 +0.6873750000000001 0.0 0.0 0.5463623046874974 +0.6875 0.0 0.0 0.5463623046874974 +0.687625 -0.002349853515625 -0.005218505859375 0.5463623046874974 +0.68775 -0.002349853515625 -0.005218505859375 0.5463623046874974 +0.687875 -0.004730224609375 -0.01043701171875 0.5463623046874974 +0.6880000000000001 -0.007110595703125 -0.01568603515625 0.5463623046874974 +0.688125 -0.007110595703125 -0.01568603515625 0.5463623046874974 +0.68825 -0.009490966796875 -0.020904541015625 0.5463623046874974 +0.688375 -0.009490966796875 -0.020904541015625 0.5463623046874974 +0.6885 -0.0118408203125 -0.026123046875 0.5463623046874974 +0.688625 -0.01422119140625 -0.0313720703125 0.5463623046874974 +0.68875 -0.01422119140625 -0.0313720703125 0.5463623046874974 +0.688875 -0.0166015625 -0.036590576171875 0.5463623046874974 +0.6890000000000001 -0.0166015625 -0.036590576171875 0.5463623046874974 +0.689125 -0.018951416015625 -0.04180908203125 0.5463623046874974 +0.68925 -0.021331787109375 -0.047027587890625 0.5463623046874974 +0.689375 -0.021331787109375 -0.047027587890625 0.5463623046874974 +0.6895 -0.023681640625 -0.05224609375 0.5463623046874974 +0.689625 -0.023681640625 -0.05224609375 0.5463623046874974 +0.68975 -0.02606201171875 -0.05743408203125 0.5463623046874974 +0.689875 -0.028411865234375 -0.0626220703125 0.5463623046874974 +0.6900000000000001 -0.028411865234375 -0.0626220703125 0.5463623046874974 +0.690125 -0.03076171875 -0.06781005859375 0.5463623046874974 +0.69025 -0.03076171875 -0.06781005859375 0.5463623046874974 +0.690375 -0.033111572265625 -0.072998046875 0.5463623046874974 +0.6905 -0.03546142578125 -0.07818603515625 0.5463623046874974 +0.690625 -0.03546142578125 -0.07818603515625 0.5463623046874974 +0.69075 -0.037811279296875 -0.083343505859375 0.5463623046874974 +0.690875 -0.037811279296875 -0.083343505859375 0.5463623046874974 +0.6910000000000001 -0.040130615234375 -0.0885009765625 0.5463623046874974 +0.691125 -0.04248046875 -0.093658447265625 0.5463623046874974 +0.69125 -0.04248046875 -0.093658447265625 0.5463623046874974 +0.691375 -0.0447998046875 -0.098785400390625 0.5463623046874974 +0.6915 -0.0447998046875 -0.098785400390625 0.5463623046874974 +0.691625 -0.047119140625 -0.103912353515625 0.5463623046874974 +0.69175 -0.0494384765625 -0.109039306640625 0.5463623046874974 +0.691875 -0.0494384765625 -0.109039306640625 0.5463623046874974 +0.6920000000000001 -0.0517578125 -0.1141357421875 0.5463623046874974 +0.692125 -0.0517578125 -0.1141357421875 0.5463623046874974 +0.69225 -0.0540771484375 -0.119232177734375 0.5463623046874974 +0.692375 -0.056365966796875 -0.124298095703125 0.5463623046874974 +0.6925 -0.056365966796875 -0.124298095703125 0.5463623046874974 +0.692625 -0.058685302734375 -0.129364013671875 0.5463623046874974 +0.69275 -0.058685302734375 -0.129364013671875 0.5463623046874974 +0.692875 -0.06097412109375 -0.134429931640625 0.5463623046874974 +0.6930000000000001 -0.063232421875 -0.13946533203125 0.5463623046874974 +0.693125 -0.063232421875 -0.13946533203125 0.5463623046874974 +0.69325 -0.065521240234375 -0.14447021484375 0.5463623046874974 +0.693375 -0.065521240234375 -0.14447021484375 0.5463623046874974 +0.6935 -0.067779541015625 -0.14947509765625 0.5463623046874974 +0.693625 -0.070068359375 -0.15447998046875 0.5463623046874974 +0.69375 -0.070068359375 -0.15447998046875 0.5463623046874974 +0.693875 -0.07232666015625 -0.159454345703125 0.5463623046874974 +0.6940000000000001 -0.07232666015625 -0.159454345703125 0.5463623046874974 +0.694125 -0.074554443359375 -0.164398193359375 0.5463623046874974 +0.69425 -0.0767822265625 -0.169342041015625 0.5463623046874974 +0.694375 -0.0767822265625 -0.169342041015625 0.5463623046874974 +0.6945 -0.07904052734375 -0.17425537109375 0.5463623046874974 +0.694625 -0.07904052734375 -0.17425537109375 0.5463623046874974 +0.69475 -0.08123779296875 -0.17913818359375 0.5463623046874974 +0.694875 -0.083465576171875 -0.18402099609375 0.5463623046874974 +0.6950000000000001 -0.083465576171875 -0.18402099609375 0.5463623046874974 +0.695125 -0.085662841796875 -0.188873291015625 0.5463623046874974 +0.69525 -0.085662841796875 -0.188873291015625 0.5463623046874974 +0.695375 -0.087860107421875 -0.1937255859375 0.5463623046874974 +0.6955 -0.090057373046875 -0.19854736328125 0.5463623046874974 +0.695625 -0.090057373046875 -0.19854736328125 0.5463623046874974 +0.69575 -0.09222412109375 -0.203338623046875 0.5463623046874974 +0.695875 -0.09222412109375 -0.203338623046875 0.5463623046874974 +0.6960000000000001 -0.094390869140625 -0.208099365234375 0.5463623046874974 +0.696125 -0.096527099609375 -0.212860107421875 0.5463623046874974 +0.69625 -0.096527099609375 -0.212860107421875 0.5463623046874974 +0.696375 -0.09869384765625 -0.21759033203125 0.5463623046874974 +0.6965 -0.09869384765625 -0.21759033203125 0.5463623046874974 +0.696625 -0.100799560546875 -0.2222900390625 0.5463623046874974 +0.69675 -0.102935791015625 -0.226959228515625 0.5463623046874974 +0.696875 -0.102935791015625 -0.226959228515625 0.5463623046874974 +0.6970000000000001 -0.10504150390625 -0.231597900390625 0.5463623046874974 +0.697125 -0.10504150390625 -0.231597900390625 0.5463623046874974 +0.69725 -0.107147216796875 -0.236236572265625 0.5463623046874974 +0.697375 -0.109222412109375 -0.2408447265625 0.5463623046874974 +0.6975 -0.109222412109375 -0.2408447265625 0.5463623046874974 +0.6976250000000001 -0.111297607421875 -0.24542236328125 0.5463623046874974 +0.69775 -0.111297607421875 -0.24542236328125 0.5463623046874974 +0.697875 -0.113372802734375 -0.249969482421875 0.5463623046874974 +0.6980000000000001 -0.11541748046875 -0.25445556640625 0.5463623046874974 +0.698125 -0.11541748046875 -0.25445556640625 0.5463623046874974 +0.69825 -0.117462158203125 -0.25897216796875 0.5463623046874974 +0.698375 -0.117462158203125 -0.25897216796875 0.5463623046874974 +0.6985 -0.119476318359375 -0.263427734375 0.5463623046874974 +0.6986250000000001 -0.121490478515625 -0.267852783203125 0.5463623046874974 +0.69875 -0.121490478515625 -0.267852783203125 0.5463623046874974 +0.698875 -0.123504638671875 -0.27227783203125 0.5463623046874974 +0.6990000000000001 -0.123504638671875 -0.27227783203125 0.5463623046874974 +0.699125 -0.125457763671875 -0.276641845703125 0.5463623046874974 +0.69925 -0.12744140625 -0.280975341796875 0.5463623046874974 +0.699375 -0.12744140625 -0.280975341796875 0.5463623046874974 +0.6995 -0.12939453125 -0.285308837890625 0.5463623046874974 +0.6996250000000001 -0.12939453125 -0.285308837890625 0.5463623046874974 +0.69975 -0.13134765625 -0.289581298828125 0.5463623046874974 +0.699875 -0.133270263671875 -0.2938232421875 0.5463623046874974 +0.7000000000000001 -0.133270263671875 -0.2938232421875 0.5463623046874974 +0.700125 -0.13519287109375 -0.298065185546875 0.5463623046874974 +0.70025 -0.13519287109375 -0.298065185546875 0.5463623046874974 +0.700375 -0.1370849609375 -0.30224609375 0.5463623046874974 +0.7005 -0.13897705078125 -0.306396484375 0.5463623046874974 +0.7006250000000001 -0.13897705078125 -0.306396484375 0.5463623046874974 +0.70075 -0.140838623046875 -0.310516357421875 0.5463623046874974 +0.700875 -0.140838623046875 -0.310516357421875 0.5463623046874974 +0.7010000000000001 -0.1427001953125 -0.314605712890625 0.5463623046874974 +0.701125 -0.14453125 -0.31866455078125 0.5463623046874974 +0.70125 -0.14453125 -0.31866455078125 0.5463623046874974 +0.701375 -0.1463623046875 -0.322662353515625 0.5463623046874974 +0.7015 -0.1463623046875 -0.322662353515625 0.5463623046874974 +0.7016250000000001 -0.148162841796875 -0.32666015625 0.5463623046874974 +0.70175 -0.14996337890625 -0.330596923828125 0.5463623046874974 +0.701875 -0.14996337890625 -0.330596923828125 0.5463623046874974 +0.7020000000000001 -0.1517333984375 -0.334503173828125 0.5463623046874974 +0.702125 -0.1517333984375 -0.334503173828125 0.5463623046874974 +0.70225 -0.153472900390625 -0.33837890625 0.5463623046874974 +0.702375 -0.15521240234375 -0.34222412109375 0.5463623046874974 +0.7025 -0.15521240234375 -0.34222412109375 0.5463623046874974 +0.7026250000000001 -0.156951904296875 -0.34600830078125 0.5463623046874974 +0.70275 -0.156951904296875 -0.34600830078125 0.5463623046874974 +0.702875 -0.15863037109375 -0.349761962890625 0.5463623046874974 +0.7030000000000001 -0.16033935546875 -0.353485107421875 0.5463623046874974 +0.703125 -0.16033935546875 -0.353485107421875 0.5463623046874974 +0.70325 -0.162017822265625 -0.357177734375 0.5463623046874974 +0.703375 -0.162017822265625 -0.357177734375 0.5463623046874974 +0.7035 -0.163665771484375 -0.360809326171875 0.5463623046874974 +0.7036250000000001 -0.165283203125 -0.36444091796875 0.5463623046874974 +0.70375 -0.165283203125 -0.36444091796875 0.5463623046874974 +0.703875 -0.166900634765625 -0.36798095703125 0.5463623046874974 +0.704 -0.3035888671875 -0.36798095703125 0.17499999999999718 +0.704125 -0.306488037109375 -0.37152099609375 0.17499999999999718 +0.70425 -0.309356689453125 -0.375 0.17499999999999718 +0.704375 -0.309356689453125 -0.375 0.17499999999999718 +0.7045 -0.31219482421875 -0.378448486328125 0.17499999999999718 +0.7046250000000001 -0.31219482421875 -0.378448486328125 0.17499999999999718 +0.70475 -0.31500244140625 -0.3818359375 0.17499999999999718 +0.704875 -0.317779541015625 -0.38519287109375 0.17499999999999718 +0.705 -0.317779541015625 -0.38519287109375 0.17499999999999718 +0.705125 -0.32049560546875 -0.388519287109375 0.17499999999999718 +0.70525 -0.32049560546875 -0.388519287109375 0.17499999999999718 +0.705375 -0.323211669921875 -0.39178466796875 0.17499999999999718 +0.7055 -0.325897216796875 -0.39501953125 0.17499999999999718 +0.7056250000000001 -0.325897216796875 -0.39501953125 0.17499999999999718 +0.70575 -0.3284912109375 -0.398193359375 0.17499999999999718 +0.705875 -0.3284912109375 -0.398193359375 0.17499999999999718 +0.706 -0.331085205078125 -0.401336669921875 0.17499999999999718 +0.706125 -0.333648681640625 -0.404449462890625 0.17499999999999718 +0.70625 -0.333648681640625 -0.404449462890625 0.17499999999999718 +0.706375 -0.336181640625 -0.407501220703125 0.17499999999999718 +0.7065 -0.336181640625 -0.407501220703125 0.17499999999999718 +0.7066250000000001 -0.338653564453125 -0.4105224609375 0.17499999999999718 +0.70675 -0.341094970703125 -0.413482666015625 0.17499999999999718 +0.706875 -0.341094970703125 -0.413482666015625 0.17499999999999718 +0.707 -0.343505859375 -0.416412353515625 0.17499999999999718 +0.707125 -0.343505859375 -0.416412353515625 0.17499999999999718 +0.70725 -0.34588623046875 -0.419281005859375 0.17499999999999718 +0.707375 -0.348236083984375 -0.422119140625 0.17499999999999718 +0.7075 -0.348236083984375 -0.422119140625 0.17499999999999718 +0.7076250000000001 -0.35052490234375 -0.424896240234375 0.17499999999999718 +0.70775 -0.35052490234375 -0.424896240234375 0.17499999999999718 +0.707875 -0.352783203125 -0.4276123046875 0.17499999999999718 +0.708 -0.35498046875 -0.4302978515625 0.17499999999999718 +0.708125 -0.35498046875 -0.4302978515625 0.17499999999999718 +0.70825 -0.357177734375 -0.432952880859375 0.17499999999999718 +0.708375 -0.357177734375 -0.432952880859375 0.17499999999999718 +0.7085 -0.35931396484375 -0.435546875 0.17499999999999718 +0.7086250000000001 -0.36138916015625 -0.438079833984375 0.17499999999999718 +0.70875 -0.36138916015625 -0.438079833984375 0.17499999999999718 +0.708875 -0.36346435546875 -0.440582275390625 0.17499999999999718 +0.709 -0.36346435546875 -0.440582275390625 0.17499999999999718 +0.709125 -0.365509033203125 -0.44305419921875 0.17499999999999718 +0.70925 -0.367462158203125 -0.4454345703125 0.17499999999999718 +0.709375 -0.367462158203125 -0.4454345703125 0.17499999999999718 +0.7095 -0.369415283203125 -0.447784423828125 0.17499999999999718 +0.7096250000000001 -0.369415283203125 -0.447784423828125 0.17499999999999718 +0.70975 -0.371307373046875 -0.450103759765625 0.17499999999999718 +0.709875 -0.3731689453125 -0.452362060546875 0.17499999999999718 +0.71 -0.3731689453125 -0.452362060546875 0.17499999999999718 +0.710125 -0.375 -0.454559326171875 0.17499999999999718 +0.71025 -0.375 -0.454559326171875 0.17499999999999718 +0.710375 -0.37677001953125 -0.45672607421875 0.17499999999999718 +0.7105 -0.378509521484375 -0.458831787109375 0.17499999999999718 +0.7106250000000001 -0.378509521484375 -0.458831787109375 0.17499999999999718 +0.71075 -0.38018798828125 -0.46087646484375 0.17499999999999718 +0.710875 -0.38018798828125 -0.46087646484375 0.17499999999999718 +0.711 -0.381866455078125 -0.462890625 0.17499999999999718 +0.711125 -0.383453369140625 -0.464813232421875 0.17499999999999718 +0.71125 -0.383453369140625 -0.464813232421875 0.17499999999999718 +0.711375 -0.385040283203125 -0.46673583984375 0.17499999999999718 +0.7115 -0.385040283203125 -0.46673583984375 0.17499999999999718 +0.7116250000000001 -0.386566162109375 -0.46856689453125 0.17499999999999718 +0.71175 -0.388031005859375 -0.470367431640625 0.17499999999999718 +0.711875 -0.388031005859375 -0.470367431640625 0.17499999999999718 +0.712 -0.389495849609375 -0.472137451171875 0.17499999999999718 +0.712125 -0.389495849609375 -0.472137451171875 0.17499999999999718 +0.71225 -0.390869140625 -0.47381591796875 0.17499999999999718 +0.712375 -0.392242431640625 -0.4754638671875 0.17499999999999718 +0.7125 -0.392242431640625 -0.4754638671875 0.17499999999999718 +0.7126250000000001 -0.3935546875 -0.47705078125 0.17499999999999718 +0.71275 -0.3935546875 -0.47705078125 0.17499999999999718 +0.712875 -0.39483642578125 -0.478607177734375 0.17499999999999718 +0.713 -0.39605712890625 -0.480072021484375 0.17499999999999718 +0.713125 -0.39605712890625 -0.480072021484375 0.17499999999999718 +0.7132500000000001 -0.397216796875 -0.48150634765625 0.17499999999999718 +0.713375 -0.397216796875 -0.48150634765625 0.17499999999999718 +0.7135 -0.39837646484375 -0.48291015625 0.17499999999999718 +0.7136250000000001 -0.39947509765625 -0.484222412109375 0.17499999999999718 +0.71375 -0.39947509765625 -0.484222412109375 0.17499999999999718 +0.713875 -0.4005126953125 -0.485504150390625 0.17499999999999718 +0.714 -0.4005126953125 -0.485504150390625 0.17499999999999718 +0.714125 -0.401519775390625 -0.486724853515625 0.17499999999999718 +0.7142500000000001 -0.402496337890625 -0.487884521484375 0.17499999999999718 +0.714375 -0.402496337890625 -0.487884521484375 0.17499999999999718 +0.7145 -0.403411865234375 -0.489013671875 0.17499999999999718 +0.7146250000000001 -0.403411865234375 -0.489013671875 0.17499999999999718 +0.71475 -0.404296875 -0.490081787109375 0.17499999999999718 +0.714875 -0.405120849609375 -0.4910888671875 0.17499999999999718 +0.715 -0.405120849609375 -0.4910888671875 0.17499999999999718 +0.715125 -0.405914306640625 -0.492034912109375 0.17499999999999718 +0.7152500000000001 -0.405914306640625 -0.492034912109375 0.17499999999999718 +0.715375 -0.406646728515625 -0.492950439453125 0.17499999999999718 +0.7155 -0.4073486328125 -0.4937744140625 0.17499999999999718 +0.7156250000000001 -0.4073486328125 -0.4937744140625 0.17499999999999718 +0.71575 -0.407989501953125 -0.49456787109375 0.17499999999999718 +0.715875 -0.407989501953125 -0.49456787109375 0.17499999999999718 +0.716 -0.408599853515625 -0.49530029296875 0.17499999999999718 +0.716125 -0.4091796875 -0.496002197265625 0.17499999999999718 +0.7162500000000001 -0.4091796875 -0.496002197265625 0.17499999999999718 +0.716375 -0.409698486328125 -0.496612548828125 0.17499999999999718 +0.7165 -0.409698486328125 -0.496612548828125 0.17499999999999718 +0.7166250000000001 -0.41015625 -0.4971923828125 0.17499999999999718 +0.71675 -0.41058349609375 -0.497711181640625 0.17499999999999718 +0.716875 -0.41058349609375 -0.497711181640625 0.17499999999999718 +0.717 -0.410980224609375 -0.498199462890625 0.17499999999999718 +0.717125 -0.410980224609375 -0.498199462890625 0.17499999999999718 +0.7172500000000001 -0.41131591796875 -0.49859619140625 0.17499999999999718 +0.717375 -0.41162109375 -0.49896240234375 0.17499999999999718 +0.7175 -0.41162109375 -0.49896240234375 0.17499999999999718 +0.7176250000000001 -0.411865234375 -0.499267578125 0.17499999999999718 +0.71775 -0.411865234375 -0.499267578125 0.17499999999999718 +0.717875 -0.412078857421875 -0.49951171875 0.17499999999999718 +0.718 -0.4122314453125 -0.49969482421875 0.17499999999999718 +0.718125 -0.4122314453125 -0.49969482421875 0.17499999999999718 +0.7182500000000001 -0.412322998046875 -0.49981689453125 0.17499999999999718 +0.718375 -0.412322998046875 -0.49981689453125 0.17499999999999718 +0.7185 -0.41241455078125 -0.499908447265625 0.17499999999999718 +0.7186250000000001 -0.412445068359375 -0.49993896484375 0.17499999999999718 +0.71875 -0.412445068359375 -0.49993896484375 0.17499999999999718 +0.718875 -0.41241455078125 -0.499908447265625 0.17499999999999718 +0.719 -0.41241455078125 -0.499908447265625 0.17499999999999718 +0.719125 -0.412322998046875 -0.49981689453125 0.17499999999999718 +0.7192500000000001 -0.4122314453125 -0.49969482421875 0.17499999999999718 +0.719375 -0.4122314453125 -0.49969482421875 0.17499999999999718 +0.7195 -0.412078857421875 -0.49951171875 0.17499999999999718 +0.7196250000000001 -0.412078857421875 -0.49951171875 0.17499999999999718 +0.71975 -0.411865234375 -0.499267578125 0.17499999999999718 +0.719875 -0.41162109375 -0.49896240234375 0.17499999999999718 +0.72 -0.41162109375 -0.49896240234375 0.17499999999999718 +0.720125 -0.41131591796875 -0.49859619140625 0.17499999999999718 +0.7202500000000001 -0.41131591796875 -0.49859619140625 0.17499999999999718 +0.720375 -0.410980224609375 -0.498199462890625 0.17499999999999718 +0.7205 -0.41058349609375 -0.497711181640625 0.17499999999999718 +0.720625 -0.41058349609375 -0.497711181640625 0.17499999999999718 +0.72075 -0.41015625 -0.4971923828125 0.17499999999999718 +0.720875 -0.41015625 -0.4971923828125 0.17499999999999718 +0.721 -0.409698486328125 -0.496612548828125 0.17499999999999718 +0.721125 -0.4091796875 -0.496002197265625 0.17499999999999718 +0.7212500000000001 -0.4091796875 -0.496002197265625 0.17499999999999718 +0.721375 -0.408599853515625 -0.49530029296875 0.17499999999999718 +0.7215 -0.408599853515625 -0.49530029296875 0.17499999999999718 +0.721625 -0.407989501953125 -0.49456787109375 0.17499999999999718 +0.72175 -0.4073486328125 -0.4937744140625 0.17499999999999718 +0.721875 -0.4073486328125 -0.4937744140625 0.17499999999999718 +0.722 -0.406646728515625 -0.492950439453125 0.17499999999999718 +0.722125 -0.406646728515625 -0.492950439453125 0.17499999999999718 +0.7222500000000001 -0.405914306640625 -0.492034912109375 0.17499999999999718 +0.722375 -0.405120849609375 -0.4910888671875 0.17499999999999718 +0.7225 -0.405120849609375 -0.4910888671875 0.17499999999999718 +0.722625 -0.404296875 -0.490081787109375 0.17499999999999718 +0.72275 -0.404296875 -0.490081787109375 0.17499999999999718 +0.722875 -0.403411865234375 -0.489013671875 0.17499999999999718 +0.723 -0.402496337890625 -0.487884521484375 0.17499999999999718 +0.723125 -0.402496337890625 -0.487884521484375 0.17499999999999718 +0.7232500000000001 -0.401519775390625 -0.486724853515625 0.17499999999999718 +0.723375 -0.401519775390625 -0.486724853515625 0.17499999999999718 +0.7235 -0.4005126953125 -0.485504150390625 0.17499999999999718 +0.723625 -0.39947509765625 -0.484222412109375 0.17499999999999718 +0.72375 -0.39947509765625 -0.484222412109375 0.17499999999999718 +0.723875 -0.39837646484375 -0.48291015625 0.17499999999999718 +0.724 -0.39837646484375 -0.48291015625 0.17499999999999718 +0.724125 -0.397216796875 -0.48150634765625 0.17499999999999718 +0.7242500000000001 -0.39605712890625 -0.480072021484375 0.17499999999999718 +0.724375 -0.39605712890625 -0.480072021484375 0.17499999999999718 +0.7245 -0.39483642578125 -0.478607177734375 0.17499999999999718 +0.724625 -0.39483642578125 -0.478607177734375 0.17499999999999718 +0.72475 -0.3935546875 -0.47705078125 0.17499999999999718 +0.724875 -0.392242431640625 -0.4754638671875 0.17499999999999718 +0.725 -0.392242431640625 -0.4754638671875 0.17499999999999718 +0.725125 -0.390869140625 -0.47381591796875 0.17499999999999718 +0.7252500000000001 -0.390869140625 -0.47381591796875 0.17499999999999718 +0.725375 -0.389495849609375 -0.472137451171875 0.17499999999999718 +0.7255 -0.388031005859375 -0.470367431640625 0.17499999999999718 +0.725625 -0.388031005859375 -0.470367431640625 0.17499999999999718 +0.72575 -0.386566162109375 -0.46856689453125 0.17499999999999718 +0.725875 -0.386566162109375 -0.46856689453125 0.17499999999999718 +0.726 -0.385040283203125 -0.46673583984375 0.17499999999999718 +0.726125 -0.383453369140625 -0.464813232421875 0.17499999999999718 +0.7262500000000001 -0.383453369140625 -0.464813232421875 0.17499999999999718 +0.726375 -0.381866455078125 -0.462890625 0.17499999999999718 +0.7265 -0.381866455078125 -0.462890625 0.17499999999999718 +0.726625 -0.38018798828125 -0.46087646484375 0.17499999999999718 +0.72675 -0.378509521484375 -0.458831787109375 0.17499999999999718 +0.726875 -0.378509521484375 -0.458831787109375 0.17499999999999718 +0.727 -0.37677001953125 -0.45672607421875 0.17499999999999718 +0.727125 -0.37677001953125 -0.45672607421875 0.17499999999999718 +0.7272500000000001 -0.375 -0.454559326171875 0.17499999999999718 +0.727375 -0.3731689453125 -0.452362060546875 0.17499999999999718 +0.7275 -0.3731689453125 -0.452362060546875 0.17499999999999718 +0.727625 -0.371307373046875 -0.450103759765625 0.17499999999999718 +0.72775 -0.371307373046875 -0.450103759765625 0.17499999999999718 +0.727875 -0.369415283203125 -0.447784423828125 0.17499999999999718 +0.728 -0.367462158203125 -0.4454345703125 0.17499999999999718 +0.728125 -0.367462158203125 -0.4454345703125 0.17499999999999718 +0.7282500000000001 -0.365509033203125 -0.44305419921875 0.17499999999999718 +0.728375 -0.365509033203125 -0.44305419921875 0.17499999999999718 +0.7285 -0.36346435546875 -0.440582275390625 0.17499999999999718 +0.728625 -0.36138916015625 -0.438079833984375 0.17499999999999718 +0.72875 -0.36138916015625 -0.438079833984375 0.17499999999999718 +0.7288750000000001 -0.35931396484375 -0.435546875 0.17499999999999718 +0.729 -0.35931396484375 -0.435546875 0.17499999999999718 +0.729125 -0.357177734375 -0.432952880859375 0.17499999999999718 +0.7292500000000001 -0.35498046875 -0.4302978515625 0.17499999999999718 +0.729375 -0.35498046875 -0.4302978515625 0.17499999999999718 +0.7295 -0.352783203125 -0.4276123046875 0.17499999999999718 +0.729625 -0.352783203125 -0.4276123046875 0.17499999999999718 +0.72975 -0.35052490234375 -0.424896240234375 0.17499999999999718 +0.7298750000000001 -0.348236083984375 -0.422119140625 0.17499999999999718 +0.73 -0.348236083984375 -0.422119140625 0.17499999999999718 +0.730125 -0.34588623046875 -0.419281005859375 0.17499999999999718 +0.7302500000000001 -0.34588623046875 -0.419281005859375 0.17499999999999718 +0.730375 -0.343505859375 -0.416412353515625 0.17499999999999718 +0.7305 -0.341094970703125 -0.413482666015625 0.17499999999999718 +0.730625 -0.341094970703125 -0.413482666015625 0.17499999999999718 +0.73075 -0.338653564453125 -0.4105224609375 0.17499999999999718 +0.7308750000000001 -0.338653564453125 -0.4105224609375 0.17499999999999718 +0.731 -0.336181640625 -0.407501220703125 0.17499999999999718 +0.731125 -0.333648681640625 -0.404449462890625 0.17499999999999718 +0.7312500000000001 -0.333648681640625 -0.404449462890625 0.17499999999999718 +0.731375 -0.331085205078125 -0.401336669921875 0.17499999999999718 +0.7315 -0.331085205078125 -0.401336669921875 0.17499999999999718 +0.731625 -0.3284912109375 -0.398193359375 0.17499999999999718 +0.73175 -0.325897216796875 -0.39501953125 0.17499999999999718 +0.7318750000000001 -0.325897216796875 -0.39501953125 0.17499999999999718 +0.732 -0.323211669921875 -0.39178466796875 0.17499999999999718 +0.732125 -0.323211669921875 -0.39178466796875 0.17499999999999718 +0.7322500000000001 -0.32049560546875 -0.388519287109375 0.17499999999999718 +0.732375 -0.317779541015625 -0.38519287109375 0.17499999999999718 +0.7325 -0.317779541015625 -0.38519287109375 0.17499999999999718 +0.732625 -0.31500244140625 -0.3818359375 0.17499999999999718 +0.73275 -0.31500244140625 -0.3818359375 0.17499999999999718 +0.7328750000000001 -0.31219482421875 -0.378448486328125 0.17499999999999718 +0.733 -0.309356689453125 -0.375 0.17499999999999718 +0.733125 -0.309356689453125 -0.375 0.17499999999999718 +0.7332500000000001 -0.306488037109375 -0.37152099609375 0.17499999999999718 +0.733375 -0.306488037109375 -0.37152099609375 0.17499999999999718 +0.7335 -0.3035888671875 -0.36798095703125 0.17499999999999718 +0.733625 -0.3006591796875 -0.36444091796875 0.17499999999999718 +0.73375 -0.3006591796875 -0.36444091796875 0.17499999999999718 +0.7338750000000001 -0.29766845703125 -0.360809326171875 0.17499999999999718 +0.734 -0.29766845703125 -0.360809326171875 0.17499999999999718 +0.734125 -0.294677734375 -0.357177734375 0.17499999999999718 +0.7342500000000001 -0.2916259765625 -0.353485107421875 0.17499999999999718 +0.734375 -0.2916259765625 -0.353485107421875 0.17499999999999718 +0.7345 -0.288543701171875 -0.349761962890625 0.17499999999999718 +0.734625 -0.288543701171875 -0.349761962890625 0.17499999999999718 +0.73475 -0.28546142578125 -0.34600830078125 0.17499999999999718 +0.7348750000000001 -0.282318115234375 -0.34222412109375 0.17499999999999718 +0.735 -0.282318115234375 -0.34222412109375 0.17499999999999718 +0.735125 -0.279144287109375 -0.33837890625 0.17499999999999718 +0.7352500000000001 -0.279144287109375 -0.33837890625 0.17499999999999718 +0.735375 -0.275970458984375 -0.334503173828125 0.17499999999999718 +0.7355 -0.272735595703125 -0.330596923828125 0.17499999999999718 +0.735625 -0.272735595703125 -0.330596923828125 0.17499999999999718 +0.73575 -0.26947021484375 -0.32666015625 0.17499999999999718 +0.7358750000000001 -0.26947021484375 -0.32666015625 0.17499999999999718 +0.736 -0.322662353515625 -0.25030517578125 -0.224243164062503132 +0.736125 -0.31866455078125 -0.2471923828125 -0.224243164062503132 +0.73625 -0.31866455078125 -0.2471923828125 -0.224243164062503132 +0.736375 -0.314605712890625 -0.244049072265625 -0.224243164062503132 +0.7365 -0.314605712890625 -0.244049072265625 -0.224243164062503132 +0.736625 -0.310516357421875 -0.240875244140625 -0.224243164062503132 +0.73675 -0.306396484375 -0.2376708984375 -0.224243164062503132 +0.7368750000000001 -0.306396484375 -0.2376708984375 -0.224243164062503132 +0.737 -0.30224609375 -0.23443603515625 -0.224243164062503132 +0.737125 -0.30224609375 -0.23443603515625 -0.224243164062503132 +0.73725 -0.298065185546875 -0.231201171875 -0.224243164062503132 +0.737375 -0.2938232421875 -0.227935791015625 -0.224243164062503132 +0.7375 -0.2938232421875 -0.227935791015625 -0.224243164062503132 +0.737625 -0.289581298828125 -0.224639892578125 -0.224243164062503132 +0.73775 -0.289581298828125 -0.224639892578125 -0.224243164062503132 +0.7378750000000001 -0.285308837890625 -0.2213134765625 -0.224243164062503132 +0.738 -0.280975341796875 -0.21795654296875 -0.224243164062503132 +0.738125 -0.280975341796875 -0.21795654296875 -0.224243164062503132 +0.73825 -0.276641845703125 -0.214599609375 -0.224243164062503132 +0.738375 -0.276641845703125 -0.214599609375 -0.224243164062503132 +0.7385 -0.27227783203125 -0.211212158203125 -0.224243164062503132 +0.738625 -0.267852783203125 -0.207794189453125 -0.224243164062503132 +0.73875 -0.267852783203125 -0.207794189453125 -0.224243164062503132 +0.7388750000000001 -0.263427734375 -0.204345703125 -0.224243164062503132 +0.739 -0.263427734375 -0.204345703125 -0.224243164062503132 +0.739125 -0.25897216796875 -0.200897216796875 -0.224243164062503132 +0.73925 -0.25445556640625 -0.1973876953125 -0.224243164062503132 +0.739375 -0.25445556640625 -0.1973876953125 -0.224243164062503132 +0.7395 -0.249969482421875 -0.193878173828125 -0.224243164062503132 +0.739625 -0.249969482421875 -0.193878173828125 -0.224243164062503132 +0.73975 -0.24542236328125 -0.19036865234375 -0.224243164062503132 +0.7398750000000001 -0.2408447265625 -0.186798095703125 -0.224243164062503132 +0.74 -0.2408447265625 -0.186798095703125 -0.224243164062503132 +0.740125 -0.236236572265625 -0.183258056640625 -0.224243164062503132 +0.74025 -0.236236572265625 -0.183258056640625 -0.224243164062503132 +0.740375 -0.231597900390625 -0.179656982421875 -0.224243164062503132 +0.7405 -0.226959228515625 -0.176055908203125 -0.224243164062503132 +0.740625 -0.226959228515625 -0.176055908203125 -0.224243164062503132 +0.74075 -0.2222900390625 -0.17242431640625 -0.224243164062503132 +0.7408750000000001 -0.2222900390625 -0.17242431640625 -0.224243164062503132 +0.741 -0.21759033203125 -0.16876220703125 -0.224243164062503132 +0.741125 -0.212860107421875 -0.16510009765625 -0.224243164062503132 +0.74125 -0.212860107421875 -0.16510009765625 -0.224243164062503132 +0.741375 -0.208099365234375 -0.16143798828125 -0.224243164062503132 +0.7415 -0.208099365234375 -0.16143798828125 -0.224243164062503132 +0.741625 -0.203338623046875 -0.15771484375 -0.224243164062503132 +0.74175 -0.19854736328125 -0.15399169921875 -0.224243164062503132 +0.7418750000000001 -0.19854736328125 -0.15399169921875 -0.224243164062503132 +0.742 -0.1937255859375 -0.1502685546875 -0.224243164062503132 +0.742125 -0.1937255859375 -0.1502685546875 -0.224243164062503132 +0.74225 -0.188873291015625 -0.146514892578125 -0.224243164062503132 +0.742375 -0.18402099609375 -0.14276123046875 -0.224243164062503132 +0.7425 -0.18402099609375 -0.14276123046875 -0.224243164062503132 +0.742625 -0.17913818359375 -0.138946533203125 -0.224243164062503132 +0.74275 -0.17913818359375 -0.138946533203125 -0.224243164062503132 +0.7428750000000001 -0.17425537109375 -0.135162353515625 -0.224243164062503132 +0.743 -0.169342041015625 -0.13134765625 -0.224243164062503132 +0.743125 -0.169342041015625 -0.13134765625 -0.224243164062503132 +0.74325 -0.164398193359375 -0.12750244140625 -0.224243164062503132 +0.743375 -0.164398193359375 -0.12750244140625 -0.224243164062503132 +0.7435 -0.159454345703125 -0.123687744140625 -0.224243164062503132 +0.743625 -0.15447998046875 -0.11981201171875 -0.224243164062503132 +0.74375 -0.15447998046875 -0.11981201171875 -0.224243164062503132 +0.7438750000000001 -0.14947509765625 -0.115936279296875 -0.224243164062503132 +0.744 -0.14947509765625 -0.115936279296875 -0.224243164062503132 +0.744125 -0.14447021484375 -0.112060546875 -0.224243164062503132 +0.74425 -0.13946533203125 -0.108184814453125 -0.224243164062503132 +0.744375 -0.13946533203125 -0.108184814453125 -0.224243164062503132 +0.7445000000000001 -0.134429931640625 -0.104278564453125 -0.224243164062503132 +0.744625 -0.134429931640625 -0.104278564453125 -0.224243164062503132 +0.74475 -0.129364013671875 -0.100341796875 -0.224243164062503132 +0.7448750000000001 -0.124298095703125 -0.096435546875 -0.224243164062503132 +0.745 -0.124298095703125 -0.096435546875 -0.224243164062503132 +0.745125 -0.119232177734375 -0.092498779296875 -0.224243164062503132 +0.74525 -0.119232177734375 -0.092498779296875 -0.224243164062503132 +0.745375 -0.1141357421875 -0.088531494140625 -0.224243164062503132 +0.7455000000000001 -0.109039306640625 -0.084564208984375 -0.224243164062503132 +0.745625 -0.109039306640625 -0.084564208984375 -0.224243164062503132 +0.74575 -0.103912353515625 -0.080596923828125 -0.224243164062503132 +0.7458750000000001 -0.103912353515625 -0.080596923828125 -0.224243164062503132 +0.746 -0.098785400390625 -0.076629638671875 -0.224243164062503132 +0.746125 -0.093658447265625 -0.0726318359375 -0.224243164062503132 +0.74625 -0.093658447265625 -0.0726318359375 -0.224243164062503132 +0.746375 -0.0885009765625 -0.06866455078125 -0.224243164062503132 +0.7465000000000001 -0.0885009765625 -0.06866455078125 -0.224243164062503132 +0.746625 -0.083343505859375 -0.064666748046875 -0.224243164062503132 +0.74675 -0.07818603515625 -0.060638427734375 -0.224243164062503132 +0.7468750000000001 -0.07818603515625 -0.060638427734375 -0.224243164062503132 +0.747 -0.072998046875 -0.056640625 -0.224243164062503132 +0.747125 -0.072998046875 -0.056640625 -0.224243164062503132 +0.74725 -0.06781005859375 -0.0526123046875 -0.224243164062503132 +0.747375 -0.0626220703125 -0.048583984375 -0.224243164062503132 +0.7475000000000001 -0.0626220703125 -0.048583984375 -0.224243164062503132 +0.747625 -0.05743408203125 -0.0445556640625 -0.224243164062503132 +0.74775 -0.05743408203125 -0.0445556640625 -0.224243164062503132 +0.7478750000000001 -0.05224609375 -0.04052734375 -0.224243164062503132 +0.748 -0.047027587890625 -0.036468505859375 -0.224243164062503132 +0.748125 -0.047027587890625 -0.036468505859375 -0.224243164062503132 +0.74825 -0.04180908203125 -0.032440185546875 -0.224243164062503132 +0.748375 -0.04180908203125 -0.032440185546875 -0.224243164062503132 +0.7485000000000001 -0.036590576171875 -0.02838134765625 -0.224243164062503132 +0.748625 -0.0313720703125 -0.024322509765625 -0.224243164062503132 +0.74875 -0.0313720703125 -0.024322509765625 -0.224243164062503132 +0.7488750000000001 -0.026123046875 -0.020263671875 -0.224243164062503132 +0.749 -0.026123046875 -0.020263671875 -0.224243164062503132 +0.749125 -0.020904541015625 -0.0162353515625 -0.224243164062503132 +0.74925 -0.01568603515625 -0.012176513671875 -0.224243164062503132 +0.749375 -0.01568603515625 -0.012176513671875 -0.224243164062503132 +0.7495000000000001 -0.01043701171875 -0.00811767578125 -0.224243164062503132 +0.749625 -0.01043701171875 -0.00811767578125 -0.224243164062503132 +0.74975 -0.005218505859375 -0.004058837890625 -0.224243164062503132 +0.7498750000000001 0.0 0.0 -0.224243164062503132 +0.75 0.0 0.0 -0.224243164062503132 +0.750125 0.005218505859375 0.004058837890625 -0.224243164062503132 +0.75025 0.005218505859375 0.004058837890625 -0.224243164062503132 +0.750375 0.01043701171875 0.00811767578125 -0.224243164062503132 +0.7505000000000001 0.01568603515625 0.012176513671875 -0.224243164062503132 +0.750625 0.01568603515625 0.012176513671875 -0.224243164062503132 +0.75075 0.020904541015625 0.0162353515625 -0.224243164062503132 +0.7508750000000001 0.020904541015625 0.0162353515625 -0.224243164062503132 +0.751 0.026123046875 0.020263671875 -0.224243164062503132 +0.751125 0.0313720703125 0.024322509765625 -0.224243164062503132 +0.75125 0.0313720703125 0.024322509765625 -0.224243164062503132 +0.751375 0.036590576171875 0.02838134765625 -0.224243164062503132 +0.7515000000000001 0.036590576171875 0.02838134765625 -0.224243164062503132 +0.751625 0.04180908203125 0.032440185546875 -0.224243164062503132 +0.75175 0.047027587890625 0.036468505859375 -0.224243164062503132 +0.7518750000000001 0.047027587890625 0.036468505859375 -0.224243164062503132 +0.752 0.05224609375 0.04052734375 -0.224243164062503132 +0.752125 0.05224609375 0.04052734375 -0.224243164062503132 +0.75225 0.05743408203125 0.0445556640625 -0.224243164062503132 +0.752375 0.0626220703125 0.048583984375 -0.224243164062503132 +0.7525000000000001 0.0626220703125 0.048583984375 -0.224243164062503132 +0.752625 0.06781005859375 0.0526123046875 -0.224243164062503132 +0.75275 0.06781005859375 0.0526123046875 -0.224243164062503132 +0.752875 0.072998046875 0.056640625 -0.224243164062503132 +0.753 0.07818603515625 0.060638427734375 -0.224243164062503132 +0.753125 0.07818603515625 0.060638427734375 -0.224243164062503132 +0.75325 0.083343505859375 0.064666748046875 -0.224243164062503132 +0.753375 0.083343505859375 0.064666748046875 -0.224243164062503132 +0.7535000000000001 0.0885009765625 0.06866455078125 -0.224243164062503132 +0.753625 0.093658447265625 0.0726318359375 -0.224243164062503132 +0.75375 0.093658447265625 0.0726318359375 -0.224243164062503132 +0.753875 0.098785400390625 0.076629638671875 -0.224243164062503132 +0.754 0.098785400390625 0.076629638671875 -0.224243164062503132 +0.754125 0.103912353515625 0.080596923828125 -0.224243164062503132 +0.75425 0.109039306640625 0.084564208984375 -0.224243164062503132 +0.754375 0.109039306640625 0.084564208984375 -0.224243164062503132 +0.7545000000000001 0.1141357421875 0.088531494140625 -0.224243164062503132 +0.754625 0.1141357421875 0.088531494140625 -0.224243164062503132 +0.75475 0.119232177734375 0.092498779296875 -0.224243164062503132 +0.754875 0.124298095703125 0.096435546875 -0.224243164062503132 +0.755 0.124298095703125 0.096435546875 -0.224243164062503132 +0.755125 0.129364013671875 0.100341796875 -0.224243164062503132 +0.75525 0.129364013671875 0.100341796875 -0.224243164062503132 +0.755375 0.134429931640625 0.104278564453125 -0.224243164062503132 +0.7555000000000001 0.13946533203125 0.108184814453125 -0.224243164062503132 +0.755625 0.13946533203125 0.108184814453125 -0.224243164062503132 +0.75575 0.14447021484375 0.112060546875 -0.224243164062503132 +0.755875 0.14447021484375 0.112060546875 -0.224243164062503132 +0.756 0.14947509765625 0.115936279296875 -0.224243164062503132 +0.756125 0.15447998046875 0.11981201171875 -0.224243164062503132 +0.75625 0.15447998046875 0.11981201171875 -0.224243164062503132 +0.756375 0.159454345703125 0.123687744140625 -0.224243164062503132 +0.7565000000000001 0.159454345703125 0.123687744140625 -0.224243164062503132 +0.756625 0.164398193359375 0.12750244140625 -0.224243164062503132 +0.75675 0.169342041015625 0.13134765625 -0.224243164062503132 +0.756875 0.169342041015625 0.13134765625 -0.224243164062503132 +0.757 0.17425537109375 0.135162353515625 -0.224243164062503132 +0.757125 0.17425537109375 0.135162353515625 -0.224243164062503132 +0.75725 0.17913818359375 0.138946533203125 -0.224243164062503132 +0.757375 0.18402099609375 0.14276123046875 -0.224243164062503132 +0.7575000000000001 0.18402099609375 0.14276123046875 -0.224243164062503132 +0.757625 0.188873291015625 0.146514892578125 -0.224243164062503132 +0.75775 0.188873291015625 0.146514892578125 -0.224243164062503132 +0.757875 0.1937255859375 0.1502685546875 -0.224243164062503132 +0.758 0.19854736328125 0.15399169921875 -0.224243164062503132 +0.758125 0.19854736328125 0.15399169921875 -0.224243164062503132 +0.75825 0.203338623046875 0.15771484375 -0.224243164062503132 +0.758375 0.203338623046875 0.15771484375 -0.224243164062503132 +0.7585000000000001 0.208099365234375 0.16143798828125 -0.224243164062503132 +0.758625 0.212860107421875 0.16510009765625 -0.224243164062503132 +0.75875 0.212860107421875 0.16510009765625 -0.224243164062503132 +0.758875 0.21759033203125 0.16876220703125 -0.224243164062503132 +0.759 0.21759033203125 0.16876220703125 -0.224243164062503132 +0.759125 0.2222900390625 0.17242431640625 -0.224243164062503132 +0.75925 0.226959228515625 0.176055908203125 -0.224243164062503132 +0.759375 0.226959228515625 0.176055908203125 -0.224243164062503132 +0.7595000000000001 0.231597900390625 0.179656982421875 -0.224243164062503132 +0.759625 0.231597900390625 0.179656982421875 -0.224243164062503132 +0.75975 0.236236572265625 0.183258056640625 -0.224243164062503132 +0.759875 0.2408447265625 0.186798095703125 -0.224243164062503132 +0.76 0.2408447265625 0.186798095703125 -0.224243164062503132 +0.7601250000000001 0.24542236328125 0.19036865234375 -0.224243164062503132 +0.76025 0.24542236328125 0.19036865234375 -0.224243164062503132 +0.760375 0.249969482421875 0.193878173828125 -0.224243164062503132 +0.7605000000000001 0.25445556640625 0.1973876953125 -0.224243164062503132 +0.760625 0.25445556640625 0.1973876953125 -0.224243164062503132 +0.76075 0.25897216796875 0.200897216796875 -0.224243164062503132 +0.760875 0.25897216796875 0.200897216796875 -0.224243164062503132 +0.761 0.263427734375 0.204345703125 -0.224243164062503132 +0.7611250000000001 0.267852783203125 0.207794189453125 -0.224243164062503132 +0.76125 0.267852783203125 0.207794189453125 -0.224243164062503132 +0.761375 0.27227783203125 0.211212158203125 -0.224243164062503132 +0.7615000000000001 0.27227783203125 0.211212158203125 -0.224243164062503132 +0.761625 0.276641845703125 0.214599609375 -0.224243164062503132 +0.76175 0.280975341796875 0.21795654296875 -0.224243164062503132 +0.761875 0.280975341796875 0.21795654296875 -0.224243164062503132 +0.762 0.285308837890625 0.2213134765625 -0.224243164062503132 +0.7621250000000001 0.285308837890625 0.2213134765625 -0.224243164062503132 +0.76225 0.289581298828125 0.224639892578125 -0.224243164062503132 +0.762375 0.2938232421875 0.227935791015625 -0.224243164062503132 +0.7625000000000001 0.2938232421875 0.227935791015625 -0.224243164062503132 +0.762625 0.298065185546875 0.231201171875 -0.224243164062503132 +0.76275 0.298065185546875 0.231201171875 -0.224243164062503132 +0.762875 0.30224609375 0.23443603515625 -0.224243164062503132 +0.763 0.306396484375 0.2376708984375 -0.224243164062503132 +0.7631250000000001 0.306396484375 0.2376708984375 -0.224243164062503132 +0.76325 0.310516357421875 0.240875244140625 -0.224243164062503132 +0.763375 0.310516357421875 0.240875244140625 -0.224243164062503132 +0.7635000000000001 0.314605712890625 0.244049072265625 -0.224243164062503132 +0.763625 0.31866455078125 0.2471923828125 -0.224243164062503132 +0.76375 0.31866455078125 0.2471923828125 -0.224243164062503132 +0.763875 0.322662353515625 0.25030517578125 -0.224243164062503132 +0.764 0.322662353515625 0.25030517578125 -0.224243164062503132 +0.7641250000000001 0.32666015625 0.253387451171875 -0.224243164062503132 +0.76425 0.330596923828125 0.256439208984375 -0.224243164062503132 +0.764375 0.330596923828125 0.256439208984375 -0.224243164062503132 +0.7645000000000001 0.334503173828125 0.259490966796875 -0.224243164062503132 +0.764625 0.334503173828125 0.259490966796875 -0.224243164062503132 +0.76475 0.33837890625 0.262481689453125 -0.224243164062503132 +0.764875 0.34222412109375 0.265472412109375 -0.224243164062503132 +0.765 0.34222412109375 0.265472412109375 -0.224243164062503132 +0.7651250000000001 0.34600830078125 0.268402099609375 -0.224243164062503132 +0.76525 0.34600830078125 0.268402099609375 -0.224243164062503132 +0.765375 0.349761962890625 0.271331787109375 -0.224243164062503132 +0.7655000000000001 0.353485107421875 0.274200439453125 -0.224243164062503132 +0.765625 0.353485107421875 0.274200439453125 -0.224243164062503132 +0.76575 0.357177734375 0.277069091796875 -0.224243164062503132 +0.765875 0.357177734375 0.277069091796875 -0.224243164062503132 +0.766 0.360809326171875 0.279876708984375 -0.224243164062503132 +0.7661250000000001 0.36444091796875 0.282684326171875 -0.224243164062503132 +0.76625 0.36444091796875 0.282684326171875 -0.224243164062503132 +0.766375 0.36798095703125 0.28546142578125 -0.224243164062503132 +0.7665000000000001 0.36798095703125 0.28546142578125 -0.224243164062503132 +0.766625 0.37152099609375 0.288177490234375 -0.224243164062503132 +0.76675 0.375 0.2908935546875 -0.224243164062503132 +0.766875 0.375 0.2908935546875 -0.224243164062503132 +0.767 0.378448486328125 0.293548583984375 -0.224243164062503132 +0.7671250000000001 0.378448486328125 0.293548583984375 -0.224243164062503132 +0.76725 0.3818359375 0.29620361328125 -0.224243164062503132 +0.767375 0.38519287109375 0.298797607421875 -0.224243164062503132 +0.7675000000000001 0.38519287109375 0.298797607421875 -0.224243164062503132 +0.767625 0.388519287109375 0.301361083984375 -0.224243164062503132 +0.76775 0.388519287109375 0.301361083984375 -0.224243164062503132 +0.767875 0.39178466796875 0.303924560546875 -0.224243164062503132 +0.768 0.39501953125 0.162811279296875 -0.5877380371093779 +0.7681250000000001 0.39501953125 0.162811279296875 -0.5877380371093779 +0.76825 0.398193359375 0.16412353515625 -0.5877380371093779 +0.768375 0.398193359375 0.16412353515625 -0.5877380371093779 +0.7685 0.401336669921875 0.165435791015625 -0.5877380371093779 +0.768625 0.404449462890625 0.166717529296875 -0.5877380371093779 +0.76875 0.404449462890625 0.166717529296875 -0.5877380371093779 +0.768875 0.407501220703125 0.16796875 -0.5877380371093779 +0.769 0.407501220703125 0.16796875 -0.5877380371093779 +0.7691250000000001 0.4105224609375 0.169189453125 -0.5877380371093779 +0.76925 0.413482666015625 0.17041015625 -0.5877380371093779 +0.769375 0.413482666015625 0.17041015625 -0.5877380371093779 +0.7695 0.416412353515625 0.171630859375 -0.5877380371093779 +0.769625 0.416412353515625 0.171630859375 -0.5877380371093779 +0.76975 0.419281005859375 0.172821044921875 -0.5877380371093779 +0.769875 0.422119140625 0.173980712890625 -0.5877380371093779 +0.77 0.422119140625 0.173980712890625 -0.5877380371093779 +0.7701250000000001 0.424896240234375 0.175140380859375 -0.5877380371093779 +0.77025 0.424896240234375 0.175140380859375 -0.5877380371093779 +0.770375 0.4276123046875 0.176239013671875 -0.5877380371093779 +0.7705 0.4302978515625 0.1773681640625 -0.5877380371093779 +0.770625 0.4302978515625 0.1773681640625 -0.5877380371093779 +0.77075 0.432952880859375 0.178466796875 -0.5877380371093779 +0.770875 0.432952880859375 0.178466796875 -0.5877380371093779 +0.771 0.435546875 0.179534912109375 -0.5877380371093779 +0.7711250000000001 0.438079833984375 0.180572509765625 -0.5877380371093779 +0.77125 0.438079833984375 0.180572509765625 -0.5877380371093779 +0.771375 0.440582275390625 0.181610107421875 -0.5877380371093779 +0.7715 0.440582275390625 0.181610107421875 -0.5877380371093779 +0.771625 0.44305419921875 0.1826171875 -0.5877380371093779 +0.77175 0.4454345703125 0.18359375 -0.5877380371093779 +0.771875 0.4454345703125 0.18359375 -0.5877380371093779 +0.772 0.447784423828125 0.1845703125 -0.5877380371093779 +0.7721250000000001 0.447784423828125 0.1845703125 -0.5877380371093779 +0.77225 0.450103759765625 0.185516357421875 -0.5877380371093779 +0.772375 0.452362060546875 0.18646240234375 -0.5877380371093779 +0.7725 0.452362060546875 0.18646240234375 -0.5877380371093779 +0.772625 0.454559326171875 0.187347412109375 -0.5877380371093779 +0.77275 0.454559326171875 0.187347412109375 -0.5877380371093779 +0.772875 0.45672607421875 0.188232421875 -0.5877380371093779 +0.773 0.458831787109375 0.189117431640625 -0.5877380371093779 +0.7731250000000001 0.458831787109375 0.189117431640625 -0.5877380371093779 +0.77325 0.46087646484375 0.189971923828125 -0.5877380371093779 +0.773375 0.46087646484375 0.189971923828125 -0.5877380371093779 +0.7735 0.462890625 0.1907958984375 -0.5877380371093779 +0.773625 0.464813232421875 0.19158935546875 -0.5877380371093779 +0.77375 0.464813232421875 0.19158935546875 -0.5877380371093779 +0.773875 0.46673583984375 0.1923828125 -0.5877380371093779 +0.774 0.46673583984375 0.1923828125 -0.5877380371093779 +0.7741250000000001 0.46856689453125 0.193145751953125 -0.5877380371093779 +0.77425 0.470367431640625 0.193878173828125 -0.5877380371093779 +0.774375 0.470367431640625 0.193878173828125 -0.5877380371093779 +0.7745 0.472137451171875 0.194610595703125 -0.5877380371093779 +0.774625 0.472137451171875 0.194610595703125 -0.5877380371093779 +0.77475 0.47381591796875 0.195281982421875 -0.5877380371093779 +0.774875 0.4754638671875 0.19598388671875 -0.5877380371093779 +0.775 0.4754638671875 0.19598388671875 -0.5877380371093779 +0.7751250000000001 0.47705078125 0.196624755859375 -0.5877380371093779 +0.77525 0.47705078125 0.196624755859375 -0.5877380371093779 +0.775375 0.478607177734375 0.197265625 -0.5877380371093779 +0.7755 0.480072021484375 0.1978759765625 -0.5877380371093779 +0.775625 0.480072021484375 0.1978759765625 -0.5877380371093779 +0.7757500000000001 0.48150634765625 0.198455810546875 -0.5877380371093779 +0.775875 0.48150634765625 0.198455810546875 -0.5877380371093779 +0.776 0.48291015625 0.19903564453125 -0.5877380371093779 +0.7761250000000001 0.484222412109375 0.1995849609375 -0.5877380371093779 +0.77625 0.484222412109375 0.1995849609375 -0.5877380371093779 +0.776375 0.485504150390625 0.200103759765625 -0.5877380371093779 +0.7765 0.485504150390625 0.200103759765625 -0.5877380371093779 +0.776625 0.486724853515625 0.20062255859375 -0.5877380371093779 +0.7767500000000001 0.487884521484375 0.201080322265625 -0.5877380371093779 +0.776875 0.487884521484375 0.201080322265625 -0.5877380371093779 +0.777 0.489013671875 0.201568603515625 -0.5877380371093779 +0.7771250000000001 0.489013671875 0.201568603515625 -0.5877380371093779 +0.77725 0.490081787109375 0.201995849609375 -0.5877380371093779 +0.777375 0.4910888671875 0.202423095703125 -0.5877380371093779 +0.7775 0.4910888671875 0.202423095703125 -0.5877380371093779 +0.777625 0.492034912109375 0.20281982421875 -0.5877380371093779 +0.7777500000000001 0.492034912109375 0.20281982421875 -0.5877380371093779 +0.777875 0.492950439453125 0.20318603515625 -0.5877380371093779 +0.778 0.4937744140625 0.203521728515625 -0.5877380371093779 +0.7781250000000001 0.4937744140625 0.203521728515625 -0.5877380371093779 +0.77825 0.49456787109375 0.203857421875 -0.5877380371093779 +0.778375 0.49456787109375 0.203857421875 -0.5877380371093779 +0.7785 0.49530029296875 0.20416259765625 -0.5877380371093779 +0.778625 0.496002197265625 0.204437255859375 -0.5877380371093779 +0.7787500000000001 0.496002197265625 0.204437255859375 -0.5877380371093779 +0.778875 0.496612548828125 0.204681396484375 -0.5877380371093779 +0.779 0.496612548828125 0.204681396484375 -0.5877380371093779 +0.7791250000000001 0.4971923828125 0.204925537109375 -0.5877380371093779 +0.77925 0.497711181640625 0.20513916015625 -0.5877380371093779 +0.779375 0.497711181640625 0.20513916015625 -0.5877380371093779 +0.7795 0.498199462890625 0.205352783203125 -0.5877380371093779 +0.779625 0.498199462890625 0.205352783203125 -0.5877380371093779 +0.7797500000000001 0.49859619140625 0.20550537109375 -0.5877380371093779 +0.779875 0.49896240234375 0.205657958984375 -0.5877380371093779 +0.78 0.49896240234375 0.205657958984375 -0.5877380371093779 +0.7801250000000001 0.499267578125 0.205780029296875 -0.5877380371093779 +0.78025 0.499267578125 0.205780029296875 -0.5877380371093779 +0.780375 0.49951171875 0.20587158203125 -0.5877380371093779 +0.7805 0.49969482421875 0.205963134765625 -0.5877380371093779 +0.780625 0.49969482421875 0.205963134765625 -0.5877380371093779 +0.7807500000000001 0.49981689453125 0.206024169921875 -0.5877380371093779 +0.780875 0.49981689453125 0.206024169921875 -0.5877380371093779 +0.781 0.499908447265625 0.2060546875 -0.5877380371093779 +0.7811250000000001 0.49993896484375 0.2060546875 -0.5877380371093779 +0.78125 0.49993896484375 0.2060546875 -0.5877380371093779 +0.781375 0.499908447265625 0.2060546875 -0.5877380371093779 +0.7815 0.499908447265625 0.2060546875 -0.5877380371093779 +0.781625 0.49981689453125 0.206024169921875 -0.5877380371093779 +0.7817500000000001 0.49969482421875 0.205963134765625 -0.5877380371093779 +0.781875 0.49969482421875 0.205963134765625 -0.5877380371093779 +0.782 0.49951171875 0.20587158203125 -0.5877380371093779 +0.7821250000000001 0.49951171875 0.20587158203125 -0.5877380371093779 +0.78225 0.499267578125 0.205780029296875 -0.5877380371093779 +0.782375 0.49896240234375 0.205657958984375 -0.5877380371093779 +0.7825 0.49896240234375 0.205657958984375 -0.5877380371093779 +0.782625 0.49859619140625 0.20550537109375 -0.5877380371093779 +0.7827500000000001 0.49859619140625 0.20550537109375 -0.5877380371093779 +0.782875 0.498199462890625 0.205352783203125 -0.5877380371093779 +0.783 0.497711181640625 0.20513916015625 -0.5877380371093779 +0.7831250000000001 0.497711181640625 0.20513916015625 -0.5877380371093779 +0.78325 0.4971923828125 0.204925537109375 -0.5877380371093779 +0.783375 0.4971923828125 0.204925537109375 -0.5877380371093779 +0.7835 0.496612548828125 0.204681396484375 -0.5877380371093779 +0.783625 0.496002197265625 0.204437255859375 -0.5877380371093779 +0.7837500000000001 0.496002197265625 0.204437255859375 -0.5877380371093779 +0.783875 0.49530029296875 0.20416259765625 -0.5877380371093779 +0.784 0.49530029296875 0.20416259765625 -0.5877380371093779 +0.784125 0.49456787109375 0.203857421875 -0.5877380371093779 +0.78425 0.4937744140625 0.203521728515625 -0.5877380371093779 +0.784375 0.4937744140625 0.203521728515625 -0.5877380371093779 +0.7845 0.492950439453125 0.20318603515625 -0.5877380371093779 +0.784625 0.492950439453125 0.20318603515625 -0.5877380371093779 +0.7847500000000001 0.492034912109375 0.20281982421875 -0.5877380371093779 +0.784875 0.4910888671875 0.202423095703125 -0.5877380371093779 +0.785 0.4910888671875 0.202423095703125 -0.5877380371093779 +0.785125 0.490081787109375 0.201995849609375 -0.5877380371093779 +0.78525 0.490081787109375 0.201995849609375 -0.5877380371093779 +0.785375 0.489013671875 0.201568603515625 -0.5877380371093779 +0.7855 0.487884521484375 0.201080322265625 -0.5877380371093779 +0.785625 0.487884521484375 0.201080322265625 -0.5877380371093779 +0.7857500000000001 0.486724853515625 0.20062255859375 -0.5877380371093779 +0.785875 0.486724853515625 0.20062255859375 -0.5877380371093779 +0.786 0.485504150390625 0.200103759765625 -0.5877380371093779 +0.786125 0.484222412109375 0.1995849609375 -0.5877380371093779 +0.78625 0.484222412109375 0.1995849609375 -0.5877380371093779 +0.786375 0.48291015625 0.19903564453125 -0.5877380371093779 +0.7865 0.48291015625 0.19903564453125 -0.5877380371093779 +0.786625 0.48150634765625 0.198455810546875 -0.5877380371093779 +0.7867500000000001 0.480072021484375 0.1978759765625 -0.5877380371093779 +0.786875 0.480072021484375 0.1978759765625 -0.5877380371093779 +0.787 0.478607177734375 0.197265625 -0.5877380371093779 +0.787125 0.478607177734375 0.197265625 -0.5877380371093779 +0.78725 0.47705078125 0.196624755859375 -0.5877380371093779 +0.787375 0.4754638671875 0.19598388671875 -0.5877380371093779 +0.7875 0.4754638671875 0.19598388671875 -0.5877380371093779 +0.787625 0.47381591796875 0.195281982421875 -0.5877380371093779 +0.7877500000000001 0.47381591796875 0.195281982421875 -0.5877380371093779 +0.787875 0.472137451171875 0.194610595703125 -0.5877380371093779 +0.788 0.470367431640625 0.193878173828125 -0.5877380371093779 +0.788125 0.470367431640625 0.193878173828125 -0.5877380371093779 +0.78825 0.46856689453125 0.193145751953125 -0.5877380371093779 +0.788375 0.46856689453125 0.193145751953125 -0.5877380371093779 +0.7885 0.46673583984375 0.1923828125 -0.5877380371093779 +0.788625 0.464813232421875 0.19158935546875 -0.5877380371093779 +0.7887500000000001 0.464813232421875 0.19158935546875 -0.5877380371093779 +0.788875 0.462890625 0.1907958984375 -0.5877380371093779 +0.789 0.462890625 0.1907958984375 -0.5877380371093779 +0.789125 0.46087646484375 0.189971923828125 -0.5877380371093779 +0.78925 0.458831787109375 0.189117431640625 -0.5877380371093779 +0.789375 0.458831787109375 0.189117431640625 -0.5877380371093779 +0.7895 0.45672607421875 0.188232421875 -0.5877380371093779 +0.789625 0.45672607421875 0.188232421875 -0.5877380371093779 +0.7897500000000001 0.454559326171875 0.187347412109375 -0.5877380371093779 +0.789875 0.452362060546875 0.18646240234375 -0.5877380371093779 +0.79 0.452362060546875 0.18646240234375 -0.5877380371093779 +0.790125 0.450103759765625 0.185516357421875 -0.5877380371093779 +0.79025 0.450103759765625 0.185516357421875 -0.5877380371093779 +0.790375 0.447784423828125 0.1845703125 -0.5877380371093779 +0.7905 0.4454345703125 0.18359375 -0.5877380371093779 +0.790625 0.4454345703125 0.18359375 -0.5877380371093779 +0.7907500000000001 0.44305419921875 0.1826171875 -0.5877380371093779 +0.790875 0.44305419921875 0.1826171875 -0.5877380371093779 +0.791 0.440582275390625 0.181610107421875 -0.5877380371093779 +0.791125 0.438079833984375 0.180572509765625 -0.5877380371093779 +0.79125 0.438079833984375 0.180572509765625 -0.5877380371093779 +0.7913750000000001 0.435546875 0.179534912109375 -0.5877380371093779 +0.7915 0.435546875 0.179534912109375 -0.5877380371093779 +0.791625 0.432952880859375 0.178466796875 -0.5877380371093779 +0.7917500000000001 0.4302978515625 0.1773681640625 -0.5877380371093779 +0.791875 0.4302978515625 0.1773681640625 -0.5877380371093779 +0.792 0.4276123046875 0.176239013671875 -0.5877380371093779 +0.792125 0.4276123046875 0.176239013671875 -0.5877380371093779 +0.79225 0.424896240234375 0.175140380859375 -0.5877380371093779 +0.7923750000000001 0.422119140625 0.173980712890625 -0.5877380371093779 +0.7925 0.422119140625 0.173980712890625 -0.5877380371093779 +0.792625 0.419281005859375 0.172821044921875 -0.5877380371093779 +0.7927500000000001 0.419281005859375 0.172821044921875 -0.5877380371093779 +0.792875 0.416412353515625 0.171630859375 -0.5877380371093779 +0.793 0.413482666015625 0.17041015625 -0.5877380371093779 +0.793125 0.413482666015625 0.17041015625 -0.5877380371093779 +0.79325 0.4105224609375 0.169189453125 -0.5877380371093779 +0.7933750000000001 0.4105224609375 0.169189453125 -0.5877380371093779 +0.7935 0.407501220703125 0.16796875 -0.5877380371093779 +0.793625 0.404449462890625 0.166717529296875 -0.5877380371093779 +0.7937500000000001 0.404449462890625 0.166717529296875 -0.5877380371093779 +0.793875 0.401336669921875 0.165435791015625 -0.5877380371093779 +0.794 0.401336669921875 0.165435791015625 -0.5877380371093779 +0.794125 0.398193359375 0.16412353515625 -0.5877380371093779 +0.79425 0.39501953125 0.162811279296875 -0.5877380371093779 +0.7943750000000001 0.39501953125 0.162811279296875 -0.5877380371093779 +0.7945 0.39178466796875 0.1614990234375 -0.5877380371093779 +0.794625 0.39178466796875 0.1614990234375 -0.5877380371093779 +0.7947500000000001 0.388519287109375 0.160125732421875 -0.5877380371093779 +0.794875 0.38519287109375 0.158782958984375 -0.5877380371093779 +0.795 0.38519287109375 0.158782958984375 -0.5877380371093779 +0.795125 0.3818359375 0.157379150390625 -0.5877380371093779 +0.79525 0.3818359375 0.157379150390625 -0.5877380371093779 +0.7953750000000001 0.378448486328125 0.155975341796875 -0.5877380371093779 +0.7955 0.375 0.154571533203125 -0.5877380371093779 +0.795625 0.375 0.154571533203125 -0.5877380371093779 +0.7957500000000001 0.37152099609375 0.15313720703125 -0.5877380371093779 +0.795875 0.37152099609375 0.15313720703125 -0.5877380371093779 +0.796 0.36798095703125 0.15167236328125 -0.5877380371093779 +0.796125 0.36444091796875 0.15020751953125 -0.5877380371093779 +0.79625 0.36444091796875 0.15020751953125 -0.5877380371093779 +0.7963750000000001 0.360809326171875 0.148712158203125 -0.5877380371093779 +0.7965 0.360809326171875 0.148712158203125 -0.5877380371093779 +0.796625 0.357177734375 0.147216796875 -0.5877380371093779 +0.7967500000000001 0.353485107421875 0.14569091796875 -0.5877380371093779 +0.796875 0.353485107421875 0.14569091796875 -0.5877380371093779 +0.797 0.349761962890625 0.1441650390625 -0.5877380371093779 +0.797125 0.349761962890625 0.1441650390625 -0.5877380371093779 +0.79725 0.34600830078125 0.142608642578125 -0.5877380371093779 +0.7973750000000001 0.34222412109375 0.14105224609375 -0.5877380371093779 +0.7975 0.34222412109375 0.14105224609375 -0.5877380371093779 +0.797625 0.33837890625 0.13946533203125 -0.5877380371093779 +0.7977500000000001 0.33837890625 0.13946533203125 -0.5877380371093779 +0.797875 0.334503173828125 0.13787841796875 -0.5877380371093779 +0.798 0.330596923828125 0.136260986328125 -0.5877380371093779 +0.798125 0.330596923828125 0.136260986328125 -0.5877380371093779 +0.79825 0.32666015625 0.1346435546875 -0.5877380371093779 +0.7983750000000001 0.32666015625 0.1346435546875 -0.5877380371093779 +0.7985 0.322662353515625 0.13299560546875 -0.5877380371093779 +0.798625 0.31866455078125 0.13134765625 -0.5877380371093779 +0.7987500000000001 0.31866455078125 0.13134765625 -0.5877380371093779 +0.798875 0.314605712890625 0.129669189453125 -0.5877380371093779 +0.799 0.314605712890625 0.129669189453125 -0.5877380371093779 +0.799125 0.310516357421875 0.12799072265625 -0.5877380371093779 +0.79925 0.306396484375 0.12628173828125 -0.5877380371093779 +0.7993750000000001 0.306396484375 0.12628173828125 -0.5877380371093779 +0.7995 0.30224609375 0.12457275390625 -0.5877380371093779 +0.799625 0.30224609375 0.12457275390625 -0.5877380371093779 +0.7997500000000001 0.298065185546875 0.12286376953125 -0.5877380371093779 +0.799875 0.2938232421875 0.12109375 -0.5877380371093779 +0.8 0.2938232421875 0.041839599609375 -0.857464599609377 +0.800125 0.289581298828125 0.041229248046875 -0.857464599609377 +0.80025 0.289581298828125 0.041229248046875 -0.857464599609377 +0.8003750000000001 0.285308837890625 0.040618896484375 -0.857464599609377 +0.8005 0.280975341796875 0.040008544921875 -0.857464599609377 +0.800625 0.280975341796875 0.040008544921875 -0.857464599609377 +0.80075 0.276641845703125 0.039398193359375 -0.857464599609377 +0.800875 0.276641845703125 0.039398193359375 -0.857464599609377 +0.801 0.27227783203125 0.038787841796875 -0.857464599609377 +0.801125 0.267852783203125 0.03814697265625 -0.857464599609377 +0.80125 0.267852783203125 0.03814697265625 -0.857464599609377 +0.8013750000000001 0.263427734375 0.037506103515625 -0.857464599609377 +0.8015 0.263427734375 0.037506103515625 -0.857464599609377 +0.801625 0.25897216796875 0.036895751953125 -0.857464599609377 +0.80175 0.25445556640625 0.0362548828125 -0.857464599609377 +0.801875 0.25445556640625 0.0362548828125 -0.857464599609377 +0.802 0.249969482421875 0.03558349609375 -0.857464599609377 +0.802125 0.249969482421875 0.03558349609375 -0.857464599609377 +0.80225 0.24542236328125 0.034942626953125 -0.857464599609377 +0.8023750000000001 0.2408447265625 0.0343017578125 -0.857464599609377 +0.8025 0.2408447265625 0.0343017578125 -0.857464599609377 +0.802625 0.236236572265625 0.03363037109375 -0.857464599609377 +0.80275 0.236236572265625 0.03363037109375 -0.857464599609377 +0.802875 0.231597900390625 0.032989501953125 -0.857464599609377 +0.803 0.226959228515625 0.032318115234375 -0.857464599609377 +0.803125 0.226959228515625 0.032318115234375 -0.857464599609377 +0.80325 0.2222900390625 0.031646728515625 -0.857464599609377 +0.8033750000000001 0.2222900390625 0.031646728515625 -0.857464599609377 +0.8035 0.21759033203125 0.030975341796875 -0.857464599609377 +0.803625 0.212860107421875 0.030303955078125 -0.857464599609377 +0.80375 0.212860107421875 0.030303955078125 -0.857464599609377 +0.803875 0.208099365234375 0.029632568359375 -0.857464599609377 +0.804 0.208099365234375 0.029632568359375 -0.857464599609377 +0.804125 0.203338623046875 0.028961181640625 -0.857464599609377 +0.80425 0.19854736328125 0.02825927734375 -0.857464599609377 +0.8043750000000001 0.19854736328125 0.02825927734375 -0.857464599609377 +0.8045 0.1937255859375 0.027587890625 -0.857464599609377 +0.804625 0.1937255859375 0.027587890625 -0.857464599609377 +0.80475 0.188873291015625 0.026885986328125 -0.857464599609377 +0.804875 0.18402099609375 0.026214599609375 -0.857464599609377 +0.805 0.18402099609375 0.026214599609375 -0.857464599609377 +0.805125 0.17913818359375 0.0255126953125 -0.857464599609377 +0.80525 0.17913818359375 0.0255126953125 -0.857464599609377 +0.8053750000000001 0.17425537109375 0.024810791015625 -0.857464599609377 +0.8055 0.169342041015625 0.02410888671875 -0.857464599609377 +0.805625 0.169342041015625 0.02410888671875 -0.857464599609377 +0.80575 0.164398193359375 0.023406982421875 -0.857464599609377 +0.805875 0.164398193359375 0.023406982421875 -0.857464599609377 +0.806 0.159454345703125 0.022705078125 -0.857464599609377 +0.806125 0.15447998046875 0.022003173828125 -0.857464599609377 +0.80625 0.15447998046875 0.022003173828125 -0.857464599609377 +0.8063750000000001 0.14947509765625 0.021270751953125 -0.857464599609377 +0.8065 0.14947509765625 0.021270751953125 -0.857464599609377 +0.806625 0.14447021484375 0.02056884765625 -0.857464599609377 +0.80675 0.13946533203125 0.019866943359375 -0.857464599609377 +0.806875 0.13946533203125 0.019866943359375 -0.857464599609377 +0.8070000000000001 0.134429931640625 0.019134521484375 -0.857464599609377 +0.807125 0.134429931640625 0.019134521484375 -0.857464599609377 +0.80725 0.129364013671875 0.0184326171875 -0.857464599609377 +0.8073750000000001 0.124298095703125 0.0177001953125 -0.857464599609377 +0.8075 0.124298095703125 0.0177001953125 -0.857464599609377 +0.807625 0.119232177734375 0.0169677734375 -0.857464599609377 +0.80775 0.119232177734375 0.0169677734375 -0.857464599609377 +0.807875 0.1141357421875 0.0162353515625 -0.857464599609377 +0.8080000000000001 0.109039306640625 0.015533447265625 -0.857464599609377 +0.808125 0.109039306640625 0.015533447265625 -0.857464599609377 +0.80825 0.103912353515625 0.014801025390625 -0.857464599609377 +0.8083750000000001 0.103912353515625 0.014801025390625 -0.857464599609377 +0.8085 0.098785400390625 0.014068603515625 -0.857464599609377 +0.808625 0.093658447265625 0.013336181640625 -0.857464599609377 +0.80875 0.093658447265625 0.013336181640625 -0.857464599609377 +0.808875 0.0885009765625 0.012603759765625 -0.857464599609377 +0.8090000000000001 0.0885009765625 0.012603759765625 -0.857464599609377 +0.809125 0.083343505859375 0.011871337890625 -0.857464599609377 +0.80925 0.07818603515625 0.011138916015625 -0.857464599609377 +0.8093750000000001 0.07818603515625 0.011138916015625 -0.857464599609377 +0.8095 0.072998046875 0.0103759765625 -0.857464599609377 +0.809625 0.072998046875 0.0103759765625 -0.857464599609377 +0.80975 0.06781005859375 0.0096435546875 -0.857464599609377 +0.809875 0.0626220703125 0.0089111328125 -0.857464599609377 +0.8100000000000001 0.0626220703125 0.0089111328125 -0.857464599609377 +0.810125 0.05743408203125 0.0081787109375 -0.857464599609377 +0.81025 0.05743408203125 0.0081787109375 -0.857464599609377 +0.8103750000000001 0.05224609375 0.007415771484375 -0.857464599609377 +0.8105 0.047027587890625 0.006683349609375 -0.857464599609377 +0.810625 0.047027587890625 0.006683349609375 -0.857464599609377 +0.81075 0.04180908203125 0.005950927734375 -0.857464599609377 +0.810875 0.04180908203125 0.005950927734375 -0.857464599609377 +0.8110000000000001 0.036590576171875 0.00518798828125 -0.857464599609377 +0.811125 0.0313720703125 0.00445556640625 -0.857464599609377 +0.81125 0.0313720703125 0.00445556640625 -0.857464599609377 +0.8113750000000001 0.026123046875 0.00372314453125 -0.857464599609377 +0.8115 0.026123046875 0.00372314453125 -0.857464599609377 +0.811625 0.020904541015625 0.002960205078125 -0.857464599609377 +0.81175 0.01568603515625 0.002227783203125 -0.857464599609377 +0.811875 0.01568603515625 0.002227783203125 -0.857464599609377 +0.8120000000000001 0.01043701171875 0.00146484375 -0.857464599609377 +0.812125 0.01043701171875 0.00146484375 -0.857464599609377 +0.81225 0.005218505859375 0.000732421875 -0.857464599609377 +0.8123750000000001 0.0 0.0 -0.857464599609377 +0.8125 0.0 0.0 -0.857464599609377 +0.812625 -0.005218505859375 -0.000732421875 -0.857464599609377 +0.81275 -0.005218505859375 -0.000732421875 -0.857464599609377 +0.812875 -0.01043701171875 -0.00146484375 -0.857464599609377 +0.8130000000000001 -0.01568603515625 -0.002227783203125 -0.857464599609377 +0.813125 -0.01568603515625 -0.002227783203125 -0.857464599609377 +0.81325 -0.020904541015625 -0.002960205078125 -0.857464599609377 +0.8133750000000001 -0.020904541015625 -0.002960205078125 -0.857464599609377 +0.8135 -0.026123046875 -0.00372314453125 -0.857464599609377 +0.813625 -0.0313720703125 -0.00445556640625 -0.857464599609377 +0.81375 -0.0313720703125 -0.00445556640625 -0.857464599609377 +0.813875 -0.036590576171875 -0.00518798828125 -0.857464599609377 +0.8140000000000001 -0.036590576171875 -0.00518798828125 -0.857464599609377 +0.814125 -0.04180908203125 -0.005950927734375 -0.857464599609377 +0.81425 -0.047027587890625 -0.006683349609375 -0.857464599609377 +0.8143750000000001 -0.047027587890625 -0.006683349609375 -0.857464599609377 +0.8145 -0.05224609375 -0.007415771484375 -0.857464599609377 +0.814625 -0.05224609375 -0.007415771484375 -0.857464599609377 +0.81475 -0.05743408203125 -0.0081787109375 -0.857464599609377 +0.814875 -0.0626220703125 -0.0089111328125 -0.857464599609377 +0.8150000000000001 -0.0626220703125 -0.0089111328125 -0.857464599609377 +0.815125 -0.06781005859375 -0.0096435546875 -0.857464599609377 +0.81525 -0.06781005859375 -0.0096435546875 -0.857464599609377 +0.8153750000000001 -0.072998046875 -0.0103759765625 -0.857464599609377 +0.8155 -0.07818603515625 -0.011138916015625 -0.857464599609377 +0.815625 -0.07818603515625 -0.011138916015625 -0.857464599609377 +0.81575 -0.083343505859375 -0.011871337890625 -0.857464599609377 +0.815875 -0.083343505859375 -0.011871337890625 -0.857464599609377 +0.8160000000000001 -0.0885009765625 -0.012603759765625 -0.857464599609377 +0.816125 -0.093658447265625 -0.013336181640625 -0.857464599609377 +0.81625 -0.093658447265625 -0.013336181640625 -0.857464599609377 +0.816375 -0.098785400390625 -0.014068603515625 -0.857464599609377 +0.8165 -0.098785400390625 -0.014068603515625 -0.857464599609377 +0.816625 -0.103912353515625 -0.014801025390625 -0.857464599609377 +0.81675 -0.109039306640625 -0.015533447265625 -0.857464599609377 +0.816875 -0.109039306640625 -0.015533447265625 -0.857464599609377 +0.8170000000000001 -0.1141357421875 -0.0162353515625 -0.857464599609377 +0.817125 -0.1141357421875 -0.0162353515625 -0.857464599609377 +0.81725 -0.119232177734375 -0.0169677734375 -0.857464599609377 +0.817375 -0.124298095703125 -0.0177001953125 -0.857464599609377 +0.8175 -0.124298095703125 -0.0177001953125 -0.857464599609377 +0.817625 -0.129364013671875 -0.0184326171875 -0.857464599609377 +0.81775 -0.129364013671875 -0.0184326171875 -0.857464599609377 +0.817875 -0.134429931640625 -0.019134521484375 -0.857464599609377 +0.8180000000000001 -0.13946533203125 -0.019866943359375 -0.857464599609377 +0.818125 -0.13946533203125 -0.019866943359375 -0.857464599609377 +0.81825 -0.14447021484375 -0.02056884765625 -0.857464599609377 +0.818375 -0.14447021484375 -0.02056884765625 -0.857464599609377 +0.8185 -0.14947509765625 -0.021270751953125 -0.857464599609377 +0.818625 -0.15447998046875 -0.022003173828125 -0.857464599609377 +0.81875 -0.15447998046875 -0.022003173828125 -0.857464599609377 +0.818875 -0.159454345703125 -0.022705078125 -0.857464599609377 +0.8190000000000001 -0.159454345703125 -0.022705078125 -0.857464599609377 +0.819125 -0.164398193359375 -0.023406982421875 -0.857464599609377 +0.81925 -0.169342041015625 -0.02410888671875 -0.857464599609377 +0.819375 -0.169342041015625 -0.02410888671875 -0.857464599609377 +0.8195 -0.17425537109375 -0.024810791015625 -0.857464599609377 +0.819625 -0.17425537109375 -0.024810791015625 -0.857464599609377 +0.81975 -0.17913818359375 -0.0255126953125 -0.857464599609377 +0.819875 -0.18402099609375 -0.026214599609375 -0.857464599609377 +0.8200000000000001 -0.18402099609375 -0.026214599609375 -0.857464599609377 +0.820125 -0.188873291015625 -0.026885986328125 -0.857464599609377 +0.82025 -0.188873291015625 -0.026885986328125 -0.857464599609377 +0.820375 -0.1937255859375 -0.027587890625 -0.857464599609377 +0.8205 -0.19854736328125 -0.02825927734375 -0.857464599609377 +0.820625 -0.19854736328125 -0.02825927734375 -0.857464599609377 +0.82075 -0.203338623046875 -0.028961181640625 -0.857464599609377 +0.820875 -0.203338623046875 -0.028961181640625 -0.857464599609377 +0.8210000000000001 -0.208099365234375 -0.029632568359375 -0.857464599609377 +0.821125 -0.212860107421875 -0.030303955078125 -0.857464599609377 +0.82125 -0.212860107421875 -0.030303955078125 -0.857464599609377 +0.821375 -0.21759033203125 -0.030975341796875 -0.857464599609377 +0.8215 -0.21759033203125 -0.030975341796875 -0.857464599609377 +0.821625 -0.2222900390625 -0.031646728515625 -0.857464599609377 +0.82175 -0.226959228515625 -0.032318115234375 -0.857464599609377 +0.821875 -0.226959228515625 -0.032318115234375 -0.857464599609377 +0.8220000000000001 -0.231597900390625 -0.032989501953125 -0.857464599609377 +0.822125 -0.231597900390625 -0.032989501953125 -0.857464599609377 +0.82225 -0.236236572265625 -0.03363037109375 -0.857464599609377 +0.822375 -0.2408447265625 -0.0343017578125 -0.857464599609377 +0.8225 -0.2408447265625 -0.0343017578125 -0.857464599609377 +0.8226250000000001 -0.24542236328125 -0.034942626953125 -0.857464599609377 +0.82275 -0.24542236328125 -0.034942626953125 -0.857464599609377 +0.822875 -0.249969482421875 -0.03558349609375 -0.857464599609377 +0.8230000000000001 -0.25445556640625 -0.0362548828125 -0.857464599609377 +0.823125 -0.25445556640625 -0.0362548828125 -0.857464599609377 +0.82325 -0.25897216796875 -0.036895751953125 -0.857464599609377 +0.823375 -0.25897216796875 -0.036895751953125 -0.857464599609377 +0.8235 -0.263427734375 -0.037506103515625 -0.857464599609377 +0.8236250000000001 -0.267852783203125 -0.03814697265625 -0.857464599609377 +0.82375 -0.267852783203125 -0.03814697265625 -0.857464599609377 +0.823875 -0.27227783203125 -0.038787841796875 -0.857464599609377 +0.8240000000000001 -0.27227783203125 -0.038787841796875 -0.857464599609377 +0.824125 -0.276641845703125 -0.039398193359375 -0.857464599609377 +0.82425 -0.280975341796875 -0.040008544921875 -0.857464599609377 +0.824375 -0.280975341796875 -0.040008544921875 -0.857464599609377 +0.8245 -0.285308837890625 -0.040618896484375 -0.857464599609377 +0.8246250000000001 -0.285308837890625 -0.040618896484375 -0.857464599609377 +0.82475 -0.289581298828125 -0.041229248046875 -0.857464599609377 +0.824875 -0.2938232421875 -0.041839599609375 -0.857464599609377 +0.8250000000000001 -0.2938232421875 -0.041839599609375 -0.857464599609377 +0.825125 -0.298065185546875 -0.042449951171875 -0.857464599609377 +0.82525 -0.298065185546875 -0.042449951171875 -0.857464599609377 +0.825375 -0.30224609375 -0.043060302734375 -0.857464599609377 +0.8255 -0.306396484375 -0.04364013671875 -0.857464599609377 +0.8256250000000001 -0.306396484375 -0.04364013671875 -0.857464599609377 +0.82575 -0.310516357421875 -0.044219970703125 -0.857464599609377 +0.825875 -0.310516357421875 -0.044219970703125 -0.857464599609377 +0.8260000000000001 -0.314605712890625 -0.0447998046875 -0.857464599609377 +0.826125 -0.31866455078125 -0.045379638671875 -0.857464599609377 +0.82625 -0.31866455078125 -0.045379638671875 -0.857464599609377 +0.826375 -0.322662353515625 -0.04595947265625 -0.857464599609377 +0.8265 -0.322662353515625 -0.04595947265625 -0.857464599609377 +0.8266250000000001 -0.32666015625 -0.0465087890625 -0.857464599609377 +0.82675 -0.330596923828125 -0.047088623046875 -0.857464599609377 +0.826875 -0.330596923828125 -0.047088623046875 -0.857464599609377 +0.8270000000000001 -0.334503173828125 -0.047637939453125 -0.857464599609377 +0.827125 -0.334503173828125 -0.047637939453125 -0.857464599609377 +0.82725 -0.33837890625 -0.048187255859375 -0.857464599609377 +0.827375 -0.34222412109375 -0.048736572265625 -0.857464599609377 +0.8275 -0.34222412109375 -0.048736572265625 -0.857464599609377 +0.8276250000000001 -0.34600830078125 -0.049285888671875 -0.857464599609377 +0.82775 -0.34600830078125 -0.049285888671875 -0.857464599609377 +0.827875 -0.349761962890625 -0.0498046875 -0.857464599609377 +0.8280000000000001 -0.353485107421875 -0.05035400390625 -0.857464599609377 +0.828125 -0.353485107421875 -0.05035400390625 -0.857464599609377 +0.82825 -0.357177734375 -0.050872802734375 -0.857464599609377 +0.828375 -0.357177734375 -0.050872802734375 -0.857464599609377 +0.8285 -0.360809326171875 -0.0513916015625 -0.857464599609377 +0.8286250000000001 -0.36444091796875 -0.051910400390625 -0.857464599609377 +0.82875 -0.36444091796875 -0.051910400390625 -0.857464599609377 +0.828875 -0.36798095703125 -0.052398681640625 -0.857464599609377 +0.8290000000000001 -0.36798095703125 -0.052398681640625 -0.857464599609377 +0.829125 -0.37152099609375 -0.05291748046875 -0.857464599609377 +0.82925 -0.375 -0.05340576171875 -0.857464599609377 +0.829375 -0.375 -0.05340576171875 -0.857464599609377 +0.8295 -0.378448486328125 -0.05389404296875 -0.857464599609377 +0.8296250000000001 -0.378448486328125 -0.05389404296875 -0.857464599609377 +0.82975 -0.3818359375 -0.05438232421875 -0.857464599609377 +0.829875 -0.38519287109375 -0.05487060546875 -0.857464599609377 +0.8300000000000001 -0.38519287109375 -0.05487060546875 -0.857464599609377 +0.830125 -0.388519287109375 -0.055328369140625 -0.857464599609377 +0.83025 -0.388519287109375 -0.055328369140625 -0.857464599609377 +0.830375 -0.39178466796875 -0.055816650390625 -0.857464599609377 +0.8305 -0.39501953125 -0.0562744140625 -0.857464599609377 +0.8306250000000001 -0.39501953125 -0.0562744140625 -0.857464599609377 +0.83075 -0.398193359375 -0.05670166015625 -0.857464599609377 +0.830875 -0.398193359375 -0.05670166015625 -0.857464599609377 +0.8310000000000001 -0.401336669921875 -0.057159423828125 -0.857464599609377 +0.831125 -0.404449462890625 -0.0576171875 -0.857464599609377 +0.83125 -0.404449462890625 -0.0576171875 -0.857464599609377 +0.831375 -0.407501220703125 -0.05804443359375 -0.857464599609377 +0.8315 -0.407501220703125 -0.05804443359375 -0.857464599609377 +0.8316250000000001 -0.4105224609375 -0.0584716796875 -0.857464599609377 +0.83175 -0.413482666015625 -0.05889892578125 -0.857464599609377 +0.831875 -0.413482666015625 -0.05889892578125 -0.857464599609377 +0.8320000000000001 -0.416412353515625 -0.003936767578125 -0.9903991699218756 +0.832125 -0.416412353515625 -0.003936767578125 -0.9903991699218756 +0.83225 -0.419281005859375 -0.00396728515625 -0.9903991699218756 +0.832375 -0.422119140625 -0.003997802734375 -0.9903991699218756 +0.8325 -0.422119140625 -0.003997802734375 -0.9903991699218756 +0.8326250000000001 -0.424896240234375 -0.0040283203125 -0.9903991699218756 +0.83275 -0.424896240234375 -0.0040283203125 -0.9903991699218756 +0.832875 -0.4276123046875 -0.004058837890625 -0.9903991699218756 +0.833 -0.4302978515625 -0.00408935546875 -0.9903991699218756 +0.833125 -0.4302978515625 -0.00408935546875 -0.9903991699218756 +0.83325 -0.432952880859375 -0.004119873046875 -0.9903991699218756 +0.833375 -0.432952880859375 -0.004119873046875 -0.9903991699218756 +0.8335 -0.435546875 -0.004119873046875 -0.9903991699218756 +0.8336250000000001 -0.438079833984375 -0.004150390625 -0.9903991699218756 +0.83375 -0.438079833984375 -0.004150390625 -0.9903991699218756 +0.833875 -0.440582275390625 -0.004180908203125 -0.9903991699218756 +0.834 -0.440582275390625 -0.004180908203125 -0.9903991699218756 +0.834125 -0.44305419921875 -0.00421142578125 -0.9903991699218756 +0.83425 -0.4454345703125 -0.00421142578125 -0.9903991699218756 +0.834375 -0.4454345703125 -0.00421142578125 -0.9903991699218756 +0.8345 -0.447784423828125 -0.004241943359375 -0.9903991699218756 +0.8346250000000001 -0.447784423828125 -0.004241943359375 -0.9903991699218756 +0.83475 -0.450103759765625 -0.0042724609375 -0.9903991699218756 +0.834875 -0.452362060546875 -0.004302978515625 -0.9903991699218756 +0.835 -0.452362060546875 -0.004302978515625 -0.9903991699218756 +0.835125 -0.454559326171875 -0.004302978515625 -0.9903991699218756 +0.83525 -0.454559326171875 -0.004302978515625 -0.9903991699218756 +0.835375 -0.45672607421875 -0.00433349609375 -0.9903991699218756 +0.8355 -0.458831787109375 -0.004364013671875 -0.9903991699218756 +0.8356250000000001 -0.458831787109375 -0.004364013671875 -0.9903991699218756 +0.83575 -0.46087646484375 -0.004364013671875 -0.9903991699218756 +0.835875 -0.46087646484375 -0.004364013671875 -0.9903991699218756 +0.836 -0.462890625 -0.00439453125 -0.9903991699218756 +0.836125 -0.464813232421875 -0.004425048828125 -0.9903991699218756 +0.83625 -0.464813232421875 -0.004425048828125 -0.9903991699218756 +0.836375 -0.46673583984375 -0.004425048828125 -0.9903991699218756 +0.8365 -0.46673583984375 -0.004425048828125 -0.9903991699218756 +0.8366250000000001 -0.46856689453125 -0.00445556640625 -0.9903991699218756 +0.83675 -0.470367431640625 -0.00445556640625 -0.9903991699218756 +0.836875 -0.470367431640625 -0.00445556640625 -0.9903991699218756 +0.837 -0.472137451171875 -0.004486083984375 -0.9903991699218756 +0.837125 -0.472137451171875 -0.004486083984375 -0.9903991699218756 +0.83725 -0.47381591796875 -0.004486083984375 -0.9903991699218756 +0.837375 -0.4754638671875 -0.0045166015625 -0.9903991699218756 +0.8375 -0.4754638671875 -0.0045166015625 -0.9903991699218756 +0.8376250000000001 -0.47705078125 -0.0045166015625 -0.9903991699218756 +0.83775 -0.47705078125 -0.0045166015625 -0.9903991699218756 +0.837875 -0.478607177734375 -0.004547119140625 -0.9903991699218756 +0.838 -0.480072021484375 -0.004547119140625 -0.9903991699218756 +0.838125 -0.480072021484375 -0.004547119140625 -0.9903991699218756 +0.8382500000000001 -0.48150634765625 -0.00457763671875 -0.9903991699218756 +0.838375 -0.48150634765625 -0.00457763671875 -0.9903991699218756 +0.8385 -0.48291015625 -0.00457763671875 -0.9903991699218756 +0.8386250000000001 -0.484222412109375 -0.004608154296875 -0.9903991699218756 +0.83875 -0.484222412109375 -0.004608154296875 -0.9903991699218756 +0.838875 -0.485504150390625 -0.004608154296875 -0.9903991699218756 +0.839 -0.485504150390625 -0.004608154296875 -0.9903991699218756 +0.839125 -0.486724853515625 -0.004608154296875 -0.9903991699218756 +0.8392500000000001 -0.487884521484375 -0.004638671875 -0.9903991699218756 +0.839375 -0.487884521484375 -0.004638671875 -0.9903991699218756 +0.8395 -0.489013671875 -0.004638671875 -0.9903991699218756 +0.8396250000000001 -0.489013671875 -0.004638671875 -0.9903991699218756 +0.83975 -0.490081787109375 -0.004638671875 -0.9903991699218756 +0.839875 -0.4910888671875 -0.004669189453125 -0.9903991699218756 +0.84 -0.4910888671875 -0.004669189453125 -0.9903991699218756 +0.840125 -0.492034912109375 -0.004669189453125 -0.9903991699218756 +0.8402500000000001 -0.492034912109375 -0.004669189453125 -0.9903991699218756 +0.840375 -0.492950439453125 -0.004669189453125 -0.9903991699218756 +0.8405 -0.4937744140625 -0.00469970703125 -0.9903991699218756 +0.8406250000000001 -0.4937744140625 -0.00469970703125 -0.9903991699218756 +0.84075 -0.49456787109375 -0.00469970703125 -0.9903991699218756 +0.840875 -0.49456787109375 -0.00469970703125 -0.9903991699218756 +0.841 -0.49530029296875 -0.00469970703125 -0.9903991699218756 +0.841125 -0.496002197265625 -0.00469970703125 -0.9903991699218756 +0.8412500000000001 -0.496002197265625 -0.00469970703125 -0.9903991699218756 +0.841375 -0.496612548828125 -0.00469970703125 -0.9903991699218756 +0.8415 -0.496612548828125 -0.00469970703125 -0.9903991699218756 +0.8416250000000001 -0.4971923828125 -0.004730224609375 -0.9903991699218756 +0.84175 -0.497711181640625 -0.004730224609375 -0.9903991699218756 +0.841875 -0.497711181640625 -0.004730224609375 -0.9903991699218756 +0.842 -0.498199462890625 -0.004730224609375 -0.9903991699218756 +0.842125 -0.498199462890625 -0.004730224609375 -0.9903991699218756 +0.8422500000000001 -0.49859619140625 -0.004730224609375 -0.9903991699218756 +0.842375 -0.49896240234375 -0.004730224609375 -0.9903991699218756 +0.8425 -0.49896240234375 -0.004730224609375 -0.9903991699218756 +0.8426250000000001 -0.499267578125 -0.004730224609375 -0.9903991699218756 +0.84275 -0.499267578125 -0.004730224609375 -0.9903991699218756 +0.842875 -0.49951171875 -0.004730224609375 -0.9903991699218756 +0.843 -0.49969482421875 -0.004730224609375 -0.9903991699218756 +0.843125 -0.49969482421875 -0.004730224609375 -0.9903991699218756 +0.8432500000000001 -0.49981689453125 -0.004730224609375 -0.9903991699218756 +0.843375 -0.49981689453125 -0.004730224609375 -0.9903991699218756 +0.8435 -0.499908447265625 -0.004730224609375 -0.9903991699218756 +0.8436250000000001 -0.49993896484375 -0.004730224609375 -0.9903991699218756 +0.84375 -0.49993896484375 -0.004730224609375 -0.9903991699218756 +0.843875 -0.499908447265625 -0.004730224609375 -0.9903991699218756 +0.844 -0.499908447265625 -0.004730224609375 -0.9903991699218756 +0.844125 -0.49981689453125 -0.004730224609375 -0.9903991699218756 +0.8442500000000001 -0.49969482421875 -0.004730224609375 -0.9903991699218756 +0.844375 -0.49969482421875 -0.004730224609375 -0.9903991699218756 +0.8445 -0.49951171875 -0.004730224609375 -0.9903991699218756 +0.8446250000000001 -0.49951171875 -0.004730224609375 -0.9903991699218756 +0.84475 -0.499267578125 -0.004730224609375 -0.9903991699218756 +0.844875 -0.49896240234375 -0.004730224609375 -0.9903991699218756 +0.845 -0.49896240234375 -0.004730224609375 -0.9903991699218756 +0.845125 -0.49859619140625 -0.004730224609375 -0.9903991699218756 +0.8452500000000001 -0.49859619140625 -0.004730224609375 -0.9903991699218756 +0.845375 -0.498199462890625 -0.004730224609375 -0.9903991699218756 +0.8455 -0.497711181640625 -0.004730224609375 -0.9903991699218756 +0.8456250000000001 -0.497711181640625 -0.004730224609375 -0.9903991699218756 +0.84575 -0.4971923828125 -0.004730224609375 -0.9903991699218756 +0.845875 -0.4971923828125 -0.004730224609375 -0.9903991699218756 +0.846 -0.496612548828125 -0.00469970703125 -0.9903991699218756 +0.846125 -0.496002197265625 -0.00469970703125 -0.9903991699218756 +0.8462500000000001 -0.496002197265625 -0.00469970703125 -0.9903991699218756 +0.846375 -0.49530029296875 -0.00469970703125 -0.9903991699218756 +0.8465 -0.49530029296875 -0.00469970703125 -0.9903991699218756 +0.8466250000000001 -0.49456787109375 -0.00469970703125 -0.9903991699218756 +0.84675 -0.4937744140625 -0.00469970703125 -0.9903991699218756 +0.846875 -0.4937744140625 -0.00469970703125 -0.9903991699218756 +0.847 -0.492950439453125 -0.004669189453125 -0.9903991699218756 +0.847125 -0.492950439453125 -0.004669189453125 -0.9903991699218756 +0.8472500000000001 -0.492034912109375 -0.004669189453125 -0.9903991699218756 +0.847375 -0.4910888671875 -0.004669189453125 -0.9903991699218756 +0.8475 -0.4910888671875 -0.004669189453125 -0.9903991699218756 +0.8476250000000001 -0.490081787109375 -0.004638671875 -0.9903991699218756 +0.84775 -0.490081787109375 -0.004638671875 -0.9903991699218756 +0.847875 -0.489013671875 -0.004638671875 -0.9903991699218756 +0.848 -0.487884521484375 -0.004638671875 -0.9903991699218756 +0.848125 -0.487884521484375 -0.004638671875 -0.9903991699218756 +0.8482500000000001 -0.486724853515625 -0.004608154296875 -0.9903991699218756 +0.848375 -0.486724853515625 -0.004608154296875 -0.9903991699218756 +0.8485 -0.485504150390625 -0.004608154296875 -0.9903991699218756 +0.848625 -0.484222412109375 -0.004608154296875 -0.9903991699218756 +0.84875 -0.484222412109375 -0.004608154296875 -0.9903991699218756 +0.848875 -0.48291015625 -0.00457763671875 -0.9903991699218756 +0.849 -0.48291015625 -0.00457763671875 -0.9903991699218756 +0.849125 -0.48150634765625 -0.00457763671875 -0.9903991699218756 +0.8492500000000001 -0.480072021484375 -0.004547119140625 -0.9903991699218756 +0.849375 -0.480072021484375 -0.004547119140625 -0.9903991699218756 +0.8495 -0.478607177734375 -0.004547119140625 -0.9903991699218756 +0.849625 -0.478607177734375 -0.004547119140625 -0.9903991699218756 +0.84975 -0.47705078125 -0.0045166015625 -0.9903991699218756 +0.849875 -0.4754638671875 -0.0045166015625 -0.9903991699218756 +0.85 -0.4754638671875 -0.0045166015625 -0.9903991699218756 +0.850125 -0.47381591796875 -0.004486083984375 -0.9903991699218756 +0.8502500000000001 -0.47381591796875 -0.004486083984375 -0.9903991699218756 +0.850375 -0.472137451171875 -0.004486083984375 -0.9903991699218756 +0.8505 -0.470367431640625 -0.00445556640625 -0.9903991699218756 +0.850625 -0.470367431640625 -0.00445556640625 -0.9903991699218756 +0.85075 -0.46856689453125 -0.00445556640625 -0.9903991699218756 +0.850875 -0.46856689453125 -0.00445556640625 -0.9903991699218756 +0.851 -0.46673583984375 -0.004425048828125 -0.9903991699218756 +0.851125 -0.464813232421875 -0.004425048828125 -0.9903991699218756 +0.8512500000000001 -0.464813232421875 -0.004425048828125 -0.9903991699218756 +0.851375 -0.462890625 -0.00439453125 -0.9903991699218756 +0.8515 -0.462890625 -0.00439453125 -0.9903991699218756 +0.851625 -0.46087646484375 -0.004364013671875 -0.9903991699218756 +0.85175 -0.458831787109375 -0.004364013671875 -0.9903991699218756 +0.851875 -0.458831787109375 -0.004364013671875 -0.9903991699218756 +0.852 -0.45672607421875 -0.00433349609375 -0.9903991699218756 +0.852125 -0.45672607421875 -0.00433349609375 -0.9903991699218756 +0.8522500000000001 -0.454559326171875 -0.004302978515625 -0.9903991699218756 +0.852375 -0.452362060546875 -0.004302978515625 -0.9903991699218756 +0.8525 -0.452362060546875 -0.004302978515625 -0.9903991699218756 +0.852625 -0.450103759765625 -0.0042724609375 -0.9903991699218756 +0.85275 -0.450103759765625 -0.0042724609375 -0.9903991699218756 +0.852875 -0.447784423828125 -0.004241943359375 -0.9903991699218756 +0.853 -0.4454345703125 -0.00421142578125 -0.9903991699218756 +0.853125 -0.4454345703125 -0.00421142578125 -0.9903991699218756 +0.8532500000000001 -0.44305419921875 -0.00421142578125 -0.9903991699218756 +0.853375 -0.44305419921875 -0.00421142578125 -0.9903991699218756 +0.8535 -0.440582275390625 -0.004180908203125 -0.9903991699218756 +0.853625 -0.438079833984375 -0.004150390625 -0.9903991699218756 +0.85375 -0.438079833984375 -0.004150390625 -0.9903991699218756 +0.8538750000000001 -0.435546875 -0.004119873046875 -0.9903991699218756 +0.854 -0.435546875 -0.004119873046875 -0.9903991699218756 +0.854125 -0.432952880859375 -0.004119873046875 -0.9903991699218756 +0.8542500000000001 -0.4302978515625 -0.00408935546875 -0.9903991699218756 +0.854375 -0.4302978515625 -0.00408935546875 -0.9903991699218756 +0.8545 -0.4276123046875 -0.004058837890625 -0.9903991699218756 +0.854625 -0.4276123046875 -0.004058837890625 -0.9903991699218756 +0.85475 -0.424896240234375 -0.0040283203125 -0.9903991699218756 +0.8548750000000001 -0.422119140625 -0.003997802734375 -0.9903991699218756 +0.855 -0.422119140625 -0.003997802734375 -0.9903991699218756 +0.855125 -0.419281005859375 -0.00396728515625 -0.9903991699218756 +0.8552500000000001 -0.419281005859375 -0.00396728515625 -0.9903991699218756 +0.855375 -0.416412353515625 -0.003936767578125 -0.9903991699218756 +0.8555 -0.413482666015625 -0.003936767578125 -0.9903991699218756 +0.855625 -0.413482666015625 -0.003936767578125 -0.9903991699218756 +0.85575 -0.4105224609375 -0.00390625 -0.9903991699218756 +0.8558750000000001 -0.4105224609375 -0.00390625 -0.9903991699218756 +0.856 -0.407501220703125 -0.003875732421875 -0.9903991699218756 +0.856125 -0.404449462890625 -0.00384521484375 -0.9903991699218756 +0.8562500000000001 -0.404449462890625 -0.00384521484375 -0.9903991699218756 +0.856375 -0.401336669921875 -0.003814697265625 -0.9903991699218756 +0.8565 -0.401336669921875 -0.003814697265625 -0.9903991699218756 +0.856625 -0.398193359375 -0.0037841796875 -0.9903991699218756 +0.85675 -0.39501953125 -0.003753662109375 -0.9903991699218756 +0.8568750000000001 -0.39501953125 -0.003753662109375 -0.9903991699218756 +0.857 -0.39178466796875 -0.00372314453125 -0.9903991699218756 +0.857125 -0.39178466796875 -0.00372314453125 -0.9903991699218756 +0.8572500000000001 -0.388519287109375 -0.003692626953125 -0.9903991699218756 +0.857375 -0.38519287109375 -0.003662109375 -0.9903991699218756 +0.8575 -0.38519287109375 -0.003662109375 -0.9903991699218756 +0.857625 -0.3818359375 -0.003631591796875 -0.9903991699218756 +0.85775 -0.3818359375 -0.003631591796875 -0.9903991699218756 +0.8578750000000001 -0.378448486328125 -0.00360107421875 -0.9903991699218756 +0.858 -0.375 -0.003570556640625 -0.9903991699218756 +0.858125 -0.375 -0.003570556640625 -0.9903991699218756 +0.8582500000000001 -0.37152099609375 -0.003509521484375 -0.9903991699218756 +0.858375 -0.37152099609375 -0.003509521484375 -0.9903991699218756 +0.8585 -0.36798095703125 -0.00347900390625 -0.9903991699218756 +0.858625 -0.36444091796875 -0.003448486328125 -0.9903991699218756 +0.85875 -0.36444091796875 -0.003448486328125 -0.9903991699218756 +0.8588750000000001 -0.360809326171875 -0.00341796875 -0.9903991699218756 +0.859 -0.360809326171875 -0.00341796875 -0.9903991699218756 +0.859125 -0.357177734375 -0.003387451171875 -0.9903991699218756 +0.8592500000000001 -0.353485107421875 -0.00335693359375 -0.9903991699218756 +0.859375 -0.353485107421875 -0.00335693359375 -0.9903991699218756 +0.8595 -0.349761962890625 -0.003326416015625 -0.9903991699218756 +0.859625 -0.349761962890625 -0.003326416015625 -0.9903991699218756 +0.85975 -0.34600830078125 -0.003265380859375 -0.9903991699218756 +0.8598750000000001 -0.34222412109375 -0.00323486328125 -0.9903991699218756 +0.86 -0.34222412109375 -0.00323486328125 -0.9903991699218756 +0.860125 -0.33837890625 -0.003204345703125 -0.9903991699218756 +0.8602500000000001 -0.33837890625 -0.003204345703125 -0.9903991699218756 +0.860375 -0.334503173828125 -0.003173828125 -0.9903991699218756 +0.8605 -0.330596923828125 -0.003143310546875 -0.9903991699218756 +0.860625 -0.330596923828125 -0.003143310546875 -0.9903991699218756 +0.86075 -0.32666015625 -0.003082275390625 -0.9903991699218756 +0.8608750000000001 -0.32666015625 -0.003082275390625 -0.9903991699218756 +0.861 -0.322662353515625 -0.0030517578125 -0.9903991699218756 +0.861125 -0.31866455078125 -0.003021240234375 -0.9903991699218756 +0.8612500000000001 -0.31866455078125 -0.003021240234375 -0.9903991699218756 +0.861375 -0.314605712890625 -0.00299072265625 -0.9903991699218756 +0.8615 -0.314605712890625 -0.00299072265625 -0.9903991699218756 +0.861625 -0.310516357421875 -0.0029296875 -0.9903991699218756 +0.86175 -0.306396484375 -0.002899169921875 -0.9903991699218756 +0.8618750000000001 -0.306396484375 -0.002899169921875 -0.9903991699218756 +0.862 -0.30224609375 -0.00286865234375 -0.9903991699218756 +0.862125 -0.30224609375 -0.00286865234375 -0.9903991699218756 +0.8622500000000001 -0.298065185546875 -0.002838134765625 -0.9903991699218756 +0.862375 -0.2938232421875 -0.002777099609375 -0.9903991699218756 +0.8625 -0.2938232421875 -0.002777099609375 -0.9903991699218756 +0.862625 -0.289581298828125 -0.00274658203125 -0.9903991699218756 +0.86275 -0.289581298828125 -0.00274658203125 -0.9903991699218756 +0.8628750000000001 -0.285308837890625 -0.002716064453125 -0.9903991699218756 +0.863 -0.280975341796875 -0.002655029296875 -0.9903991699218756 +0.863125 -0.280975341796875 -0.002655029296875 -0.9903991699218756 +0.8632500000000001 -0.276641845703125 -0.00262451171875 -0.9903991699218756 +0.863375 -0.276641845703125 -0.00262451171875 -0.9903991699218756 +0.8635 -0.27227783203125 -0.0025634765625 -0.9903991699218756 +0.863625 -0.267852783203125 -0.002532958984375 -0.9903991699218756 +0.86375 -0.267852783203125 -0.002532958984375 -0.9903991699218756 +0.8638750000000001 -0.263427734375 -0.00250244140625 -0.9903991699218756 +0.864 -0.263427734375 -0.00909423828125 -0.9653259277343738 +0.864125 -0.25897216796875 -0.008941650390625 -0.9653259277343738 +0.86425 -0.25445556640625 -0.0087890625 -0.9653259277343738 +0.864375 -0.25445556640625 -0.0087890625 -0.9653259277343738 +0.8645 -0.249969482421875 -0.008636474609375 -0.9653259277343738 +0.864625 -0.249969482421875 -0.008636474609375 -0.9653259277343738 +0.86475 -0.24542236328125 -0.00848388671875 -0.9653259277343738 +0.8648750000000001 -0.2408447265625 -0.00830078125 -0.9653259277343738 +0.865 -0.2408447265625 -0.00830078125 -0.9653259277343738 +0.865125 -0.236236572265625 -0.008148193359375 -0.9653259277343738 +0.86525 -0.236236572265625 -0.008148193359375 -0.9653259277343738 +0.865375 -0.231597900390625 -0.00799560546875 -0.9653259277343738 +0.8655 -0.226959228515625 -0.007843017578125 -0.9653259277343738 +0.865625 -0.226959228515625 -0.007843017578125 -0.9653259277343738 +0.86575 -0.2222900390625 -0.007659912109375 -0.9653259277343738 +0.8658750000000001 -0.2222900390625 -0.007659912109375 -0.9653259277343738 +0.866 -0.21759033203125 -0.00750732421875 -0.9653259277343738 +0.866125 -0.212860107421875 -0.007354736328125 -0.9653259277343738 +0.86625 -0.212860107421875 -0.007354736328125 -0.9653259277343738 +0.866375 -0.208099365234375 -0.007171630859375 -0.9653259277343738 +0.8665 -0.208099365234375 -0.007171630859375 -0.9653259277343738 +0.866625 -0.203338623046875 -0.00701904296875 -0.9653259277343738 +0.86675 -0.19854736328125 -0.0068359375 -0.9653259277343738 +0.8668750000000001 -0.19854736328125 -0.0068359375 -0.9653259277343738 +0.867 -0.1937255859375 -0.006683349609375 -0.9653259277343738 +0.867125 -0.1937255859375 -0.006683349609375 -0.9653259277343738 +0.86725 -0.188873291015625 -0.00653076171875 -0.9653259277343738 +0.867375 -0.18402099609375 -0.00634765625 -0.9653259277343738 +0.8675 -0.18402099609375 -0.00634765625 -0.9653259277343738 +0.867625 -0.17913818359375 -0.00616455078125 -0.9653259277343738 +0.86775 -0.17913818359375 -0.00616455078125 -0.9653259277343738 +0.8678750000000001 -0.17425537109375 -0.006011962890625 -0.9653259277343738 +0.868 -0.169342041015625 -0.005828857421875 -0.9653259277343738 +0.868125 -0.169342041015625 -0.005828857421875 -0.9653259277343738 +0.86825 -0.164398193359375 -0.00567626953125 -0.9653259277343738 +0.868375 -0.164398193359375 -0.00567626953125 -0.9653259277343738 +0.8685 -0.159454345703125 -0.0054931640625 -0.9653259277343738 +0.868625 -0.15447998046875 -0.005340576171875 -0.9653259277343738 +0.86875 -0.15447998046875 -0.005340576171875 -0.9653259277343738 +0.8688750000000001 -0.14947509765625 -0.005157470703125 -0.9653259277343738 +0.869 -0.14947509765625 -0.005157470703125 -0.9653259277343738 +0.869125 -0.14447021484375 -0.004974365234375 -0.9653259277343738 +0.86925 -0.13946533203125 -0.00482177734375 -0.9653259277343738 +0.869375 -0.13946533203125 -0.00482177734375 -0.9653259277343738 +0.8695000000000001 -0.134429931640625 -0.004638671875 -0.9653259277343738 +0.869625 -0.134429931640625 -0.004638671875 -0.9653259277343738 +0.86975 -0.129364013671875 -0.00445556640625 -0.9653259277343738 +0.8698750000000001 -0.124298095703125 -0.0042724609375 -0.9653259277343738 +0.87 -0.124298095703125 -0.0042724609375 -0.9653259277343738 +0.870125 -0.119232177734375 -0.004119873046875 -0.9653259277343738 +0.87025 -0.119232177734375 -0.004119873046875 -0.9653259277343738 +0.870375 -0.1141357421875 -0.003936767578125 -0.9653259277343738 +0.8705000000000001 -0.109039306640625 -0.003753662109375 -0.9653259277343738 +0.870625 -0.109039306640625 -0.003753662109375 -0.9653259277343738 +0.87075 -0.103912353515625 -0.003570556640625 -0.9653259277343738 +0.8708750000000001 -0.103912353515625 -0.003570556640625 -0.9653259277343738 +0.871 -0.098785400390625 -0.003387451171875 -0.9653259277343738 +0.871125 -0.093658447265625 -0.00323486328125 -0.9653259277343738 +0.87125 -0.093658447265625 -0.00323486328125 -0.9653259277343738 +0.871375 -0.0885009765625 -0.0030517578125 -0.9653259277343738 +0.8715000000000001 -0.0885009765625 -0.0030517578125 -0.9653259277343738 +0.871625 -0.083343505859375 -0.00286865234375 -0.9653259277343738 +0.87175 -0.07818603515625 -0.002685546875 -0.9653259277343738 +0.8718750000000001 -0.07818603515625 -0.002685546875 -0.9653259277343738 +0.872 -0.072998046875 -0.00250244140625 -0.9653259277343738 +0.872125 -0.072998046875 -0.00250244140625 -0.9653259277343738 +0.87225 -0.06781005859375 -0.0023193359375 -0.9653259277343738 +0.872375 -0.0626220703125 -0.00213623046875 -0.9653259277343738 +0.8725000000000001 -0.0626220703125 -0.00213623046875 -0.9653259277343738 +0.872625 -0.05743408203125 -0.001983642578125 -0.9653259277343738 +0.87275 -0.05743408203125 -0.001983642578125 -0.9653259277343738 +0.8728750000000001 -0.05224609375 -0.001800537109375 -0.9653259277343738 +0.873 -0.047027587890625 -0.001617431640625 -0.9653259277343738 +0.873125 -0.047027587890625 -0.001617431640625 -0.9653259277343738 +0.87325 -0.04180908203125 -0.001434326171875 -0.9653259277343738 +0.873375 -0.04180908203125 -0.001434326171875 -0.9653259277343738 +0.8735000000000001 -0.036590576171875 -0.001251220703125 -0.9653259277343738 +0.873625 -0.0313720703125 -0.001068115234375 -0.9653259277343738 +0.87375 -0.0313720703125 -0.001068115234375 -0.9653259277343738 +0.8738750000000001 -0.026123046875 -0.000885009765625 -0.9653259277343738 +0.874 -0.026123046875 -0.000885009765625 -0.9653259277343738 +0.874125 -0.020904541015625 -0.000701904296875 -0.9653259277343738 +0.87425 -0.01568603515625 -0.000518798828125 -0.9653259277343738 +0.874375 -0.01568603515625 -0.000518798828125 -0.9653259277343738 +0.8745000000000001 -0.01043701171875 -0.000335693359375 -0.9653259277343738 +0.874625 -0.01043701171875 -0.000335693359375 -0.9653259277343738 +0.87475 -0.005218505859375 -0.000152587890625 -0.9653259277343738 +0.8748750000000001 0.0 0.0 -0.9653259277343738 +0.875 0.0 0.0 -0.9653259277343738 +0.875125 0.005218505859375 0.000152587890625 -0.9653259277343738 +0.87525 0.005218505859375 0.000152587890625 -0.9653259277343738 +0.875375 0.01043701171875 0.000335693359375 -0.9653259277343738 +0.8755000000000001 0.01568603515625 0.000518798828125 -0.9653259277343738 +0.875625 0.01568603515625 0.000518798828125 -0.9653259277343738 +0.87575 0.020904541015625 0.000701904296875 -0.9653259277343738 +0.8758750000000001 0.020904541015625 0.000701904296875 -0.9653259277343738 +0.876 0.026123046875 0.000885009765625 -0.9653259277343738 +0.876125 0.0313720703125 0.001068115234375 -0.9653259277343738 +0.87625 0.0313720703125 0.001068115234375 -0.9653259277343738 +0.876375 0.036590576171875 0.001251220703125 -0.9653259277343738 +0.8765000000000001 0.036590576171875 0.001251220703125 -0.9653259277343738 +0.876625 0.04180908203125 0.001434326171875 -0.9653259277343738 +0.87675 0.047027587890625 0.001617431640625 -0.9653259277343738 +0.8768750000000001 0.047027587890625 0.001617431640625 -0.9653259277343738 +0.877 0.05224609375 0.001800537109375 -0.9653259277343738 +0.877125 0.05224609375 0.001800537109375 -0.9653259277343738 +0.87725 0.05743408203125 0.001983642578125 -0.9653259277343738 +0.877375 0.0626220703125 0.00213623046875 -0.9653259277343738 +0.8775000000000001 0.0626220703125 0.00213623046875 -0.9653259277343738 +0.877625 0.06781005859375 0.0023193359375 -0.9653259277343738 +0.87775 0.06781005859375 0.0023193359375 -0.9653259277343738 +0.8778750000000001 0.072998046875 0.00250244140625 -0.9653259277343738 +0.878 0.07818603515625 0.002685546875 -0.9653259277343738 +0.878125 0.07818603515625 0.002685546875 -0.9653259277343738 +0.87825 0.083343505859375 0.00286865234375 -0.9653259277343738 +0.878375 0.083343505859375 0.00286865234375 -0.9653259277343738 +0.8785000000000001 0.0885009765625 0.0030517578125 -0.9653259277343738 +0.878625 0.093658447265625 0.00323486328125 -0.9653259277343738 +0.87875 0.093658447265625 0.00323486328125 -0.9653259277343738 +0.8788750000000001 0.098785400390625 0.003387451171875 -0.9653259277343738 +0.879 0.098785400390625 0.003387451171875 -0.9653259277343738 +0.879125 0.103912353515625 0.003570556640625 -0.9653259277343738 +0.87925 0.109039306640625 0.003753662109375 -0.9653259277343738 +0.879375 0.109039306640625 0.003753662109375 -0.9653259277343738 +0.8795000000000001 0.1141357421875 0.003936767578125 -0.9653259277343738 +0.879625 0.1141357421875 0.003936767578125 -0.9653259277343738 +0.87975 0.119232177734375 0.004119873046875 -0.9653259277343738 +0.8798750000000001 0.124298095703125 0.0042724609375 -0.9653259277343738 +0.88 0.124298095703125 0.0042724609375 -0.9653259277343738 +0.880125 0.129364013671875 0.00445556640625 -0.9653259277343738 +0.88025 0.129364013671875 0.00445556640625 -0.9653259277343738 +0.880375 0.134429931640625 0.004638671875 -0.9653259277343738 +0.8805000000000001 0.13946533203125 0.00482177734375 -0.9653259277343738 +0.880625 0.13946533203125 0.00482177734375 -0.9653259277343738 +0.88075 0.14447021484375 0.004974365234375 -0.9653259277343738 +0.880875 0.14447021484375 0.004974365234375 -0.9653259277343738 +0.881 0.14947509765625 0.005157470703125 -0.9653259277343738 +0.881125 0.15447998046875 0.005340576171875 -0.9653259277343738 +0.88125 0.15447998046875 0.005340576171875 -0.9653259277343738 +0.881375 0.159454345703125 0.0054931640625 -0.9653259277343738 +0.8815000000000001 0.159454345703125 0.0054931640625 -0.9653259277343738 +0.881625 0.164398193359375 0.00567626953125 -0.9653259277343738 +0.88175 0.169342041015625 0.005828857421875 -0.9653259277343738 +0.881875 0.169342041015625 0.005828857421875 -0.9653259277343738 +0.882 0.17425537109375 0.006011962890625 -0.9653259277343738 +0.882125 0.17425537109375 0.006011962890625 -0.9653259277343738 +0.88225 0.17913818359375 0.00616455078125 -0.9653259277343738 +0.882375 0.18402099609375 0.00634765625 -0.9653259277343738 +0.8825000000000001 0.18402099609375 0.00634765625 -0.9653259277343738 +0.882625 0.188873291015625 0.00653076171875 -0.9653259277343738 +0.88275 0.188873291015625 0.00653076171875 -0.9653259277343738 +0.882875 0.1937255859375 0.006683349609375 -0.9653259277343738 +0.883 0.19854736328125 0.0068359375 -0.9653259277343738 +0.883125 0.19854736328125 0.0068359375 -0.9653259277343738 +0.88325 0.203338623046875 0.00701904296875 -0.9653259277343738 +0.883375 0.203338623046875 0.00701904296875 -0.9653259277343738 +0.8835000000000001 0.208099365234375 0.007171630859375 -0.9653259277343738 +0.883625 0.212860107421875 0.007354736328125 -0.9653259277343738 +0.88375 0.212860107421875 0.007354736328125 -0.9653259277343738 +0.883875 0.21759033203125 0.00750732421875 -0.9653259277343738 +0.884 0.21759033203125 0.00750732421875 -0.9653259277343738 +0.884125 0.2222900390625 0.007659912109375 -0.9653259277343738 +0.88425 0.226959228515625 0.007843017578125 -0.9653259277343738 +0.884375 0.226959228515625 0.007843017578125 -0.9653259277343738 +0.8845000000000001 0.231597900390625 0.00799560546875 -0.9653259277343738 +0.884625 0.231597900390625 0.00799560546875 -0.9653259277343738 +0.88475 0.236236572265625 0.008148193359375 -0.9653259277343738 +0.884875 0.2408447265625 0.00830078125 -0.9653259277343738 +0.885 0.2408447265625 0.00830078125 -0.9653259277343738 +0.8851250000000001 0.24542236328125 0.00848388671875 -0.9653259277343738 +0.88525 0.24542236328125 0.00848388671875 -0.9653259277343738 +0.885375 0.249969482421875 0.008636474609375 -0.9653259277343738 +0.8855000000000001 0.25445556640625 0.0087890625 -0.9653259277343738 +0.885625 0.25445556640625 0.0087890625 -0.9653259277343738 +0.88575 0.25897216796875 0.008941650390625 -0.9653259277343738 +0.885875 0.25897216796875 0.008941650390625 -0.9653259277343738 +0.886 0.263427734375 0.00909423828125 -0.9653259277343738 +0.8861250000000001 0.267852783203125 0.009246826171875 -0.9653259277343738 +0.88625 0.267852783203125 0.009246826171875 -0.9653259277343738 +0.886375 0.27227783203125 0.0093994140625 -0.9653259277343738 +0.8865000000000001 0.27227783203125 0.0093994140625 -0.9653259277343738 +0.886625 0.276641845703125 0.009552001953125 -0.9653259277343738 +0.88675 0.280975341796875 0.00970458984375 -0.9653259277343738 +0.886875 0.280975341796875 0.00970458984375 -0.9653259277343738 +0.887 0.285308837890625 0.009857177734375 -0.9653259277343738 +0.8871250000000001 0.285308837890625 0.009857177734375 -0.9653259277343738 +0.88725 0.289581298828125 0.010009765625 -0.9653259277343738 +0.887375 0.2938232421875 0.0101318359375 -0.9653259277343738 +0.8875000000000001 0.2938232421875 0.0101318359375 -0.9653259277343738 +0.887625 0.298065185546875 0.010284423828125 -0.9653259277343738 +0.88775 0.298065185546875 0.010284423828125 -0.9653259277343738 +0.887875 0.30224609375 0.01043701171875 -0.9653259277343738 +0.888 0.306396484375 0.010589599609375 -0.9653259277343738 +0.8881250000000001 0.306396484375 0.010589599609375 -0.9653259277343738 +0.88825 0.310516357421875 0.010711669921875 -0.9653259277343738 +0.888375 0.310516357421875 0.010711669921875 -0.9653259277343738 +0.8885000000000001 0.314605712890625 0.0108642578125 -0.9653259277343738 +0.888625 0.31866455078125 0.011016845703125 -0.9653259277343738 +0.88875 0.31866455078125 0.011016845703125 -0.9653259277343738 +0.888875 0.322662353515625 0.011138916015625 -0.9653259277343738 +0.889 0.322662353515625 0.011138916015625 -0.9653259277343738 +0.8891250000000001 0.32666015625 0.01129150390625 -0.9653259277343738 +0.88925 0.330596923828125 0.01141357421875 -0.9653259277343738 +0.889375 0.330596923828125 0.01141357421875 -0.9653259277343738 +0.8895000000000001 0.334503173828125 0.011566162109375 -0.9653259277343738 +0.889625 0.334503173828125 0.011566162109375 -0.9653259277343738 +0.88975 0.33837890625 0.011688232421875 -0.9653259277343738 +0.889875 0.34222412109375 0.011810302734375 -0.9653259277343738 +0.89 0.34222412109375 0.011810302734375 -0.9653259277343738 +0.8901250000000001 0.34600830078125 0.011962890625 -0.9653259277343738 +0.89025 0.34600830078125 0.011962890625 -0.9653259277343738 +0.890375 0.349761962890625 0.0120849609375 -0.9653259277343738 +0.8905000000000001 0.353485107421875 0.01220703125 -0.9653259277343738 +0.890625 0.353485107421875 0.01220703125 -0.9653259277343738 +0.89075 0.357177734375 0.0123291015625 -0.9653259277343738 +0.890875 0.357177734375 0.0123291015625 -0.9653259277343738 +0.891 0.360809326171875 0.012451171875 -0.9653259277343738 +0.8911250000000001 0.36444091796875 0.0125732421875 -0.9653259277343738 +0.89125 0.36444091796875 0.0125732421875 -0.9653259277343738 +0.891375 0.36798095703125 0.0126953125 -0.9653259277343738 +0.8915000000000001 0.36798095703125 0.0126953125 -0.9653259277343738 +0.891625 0.37152099609375 0.0128173828125 -0.9653259277343738 +0.89175 0.375 0.012939453125 -0.9653259277343738 +0.891875 0.375 0.012939453125 -0.9653259277343738 +0.892 0.378448486328125 0.0130615234375 -0.9653259277343738 +0.8921250000000001 0.378448486328125 0.0130615234375 -0.9653259277343738 +0.89225 0.3818359375 0.01318359375 -0.9653259277343738 +0.892375 0.38519287109375 0.0133056640625 -0.9653259277343738 +0.8925000000000001 0.38519287109375 0.0133056640625 -0.9653259277343738 +0.892625 0.388519287109375 0.013427734375 -0.9653259277343738 +0.89275 0.388519287109375 0.013427734375 -0.9653259277343738 +0.892875 0.39178466796875 0.013519287109375 -0.9653259277343738 +0.893 0.39501953125 0.013641357421875 -0.9653259277343738 +0.8931250000000001 0.39501953125 0.013641357421875 -0.9653259277343738 +0.89325 0.398193359375 0.013763427734375 -0.9653259277343738 +0.893375 0.398193359375 0.013763427734375 -0.9653259277343738 +0.8935000000000001 0.401336669921875 0.01385498046875 -0.9653259277343738 +0.893625 0.404449462890625 0.01397705078125 -0.9653259277343738 +0.89375 0.404449462890625 0.01397705078125 -0.9653259277343738 +0.893875 0.407501220703125 0.014068603515625 -0.9653259277343738 +0.894 0.407501220703125 0.014068603515625 -0.9653259277343738 +0.8941250000000001 0.4105224609375 0.014190673828125 -0.9653259277343738 +0.89425 0.413482666015625 0.0142822265625 -0.9653259277343738 +0.894375 0.413482666015625 0.0142822265625 -0.9653259277343738 +0.8945000000000001 0.416412353515625 0.014373779296875 -0.9653259277343738 +0.894625 0.416412353515625 0.014373779296875 -0.9653259277343738 +0.89475 0.419281005859375 0.014495849609375 -0.9653259277343738 +0.894875 0.422119140625 0.01458740234375 -0.9653259277343738 +0.895 0.422119140625 0.01458740234375 -0.9653259277343738 +0.8951250000000001 0.424896240234375 0.014678955078125 -0.9653259277343738 +0.89525 0.424896240234375 0.014678955078125 -0.9653259277343738 +0.895375 0.4276123046875 0.0147705078125 -0.9653259277343738 +0.8955000000000001 0.4302978515625 0.014862060546875 -0.9653259277343738 +0.895625 0.4302978515625 0.014862060546875 -0.9653259277343738 +0.89575 0.432952880859375 0.01495361328125 -0.9653259277343738 +0.895875 0.432952880859375 0.01495361328125 -0.9653259277343738 +0.896 0.435546875 0.093048095703125 -0.7862487792968719 +0.8961250000000001 0.438079833984375 0.093597412109375 -0.7862487792968719 +0.89625 0.438079833984375 0.093597412109375 -0.7862487792968719 +0.896375 0.440582275390625 0.0941162109375 -0.7862487792968719 +0.8965 0.440582275390625 0.0941162109375 -0.7862487792968719 +0.896625 0.44305419921875 0.09466552734375 -0.7862487792968719 +0.89675 0.4454345703125 0.09515380859375 -0.7862487792968719 +0.896875 0.4454345703125 0.09515380859375 -0.7862487792968719 +0.897 0.447784423828125 0.095672607421875 -0.7862487792968719 +0.8971250000000001 0.447784423828125 0.095672607421875 -0.7862487792968719 +0.89725 0.450103759765625 0.096160888671875 -0.7862487792968719 +0.897375 0.452362060546875 0.096649169921875 -0.7862487792968719 +0.8975 0.452362060546875 0.096649169921875 -0.7862487792968719 +0.897625 0.454559326171875 0.09710693359375 -0.7862487792968719 +0.89775 0.454559326171875 0.09710693359375 -0.7862487792968719 +0.897875 0.45672607421875 0.097564697265625 -0.7862487792968719 +0.898 0.458831787109375 0.0980224609375 -0.7862487792968719 +0.8981250000000001 0.458831787109375 0.0980224609375 -0.7862487792968719 +0.89825 0.46087646484375 0.09844970703125 -0.7862487792968719 +0.898375 0.46087646484375 0.09844970703125 -0.7862487792968719 +0.8985 0.462890625 0.098876953125 -0.7862487792968719 +0.898625 0.464813232421875 0.09930419921875 -0.7862487792968719 +0.89875 0.464813232421875 0.09930419921875 -0.7862487792968719 +0.898875 0.46673583984375 0.099700927734375 -0.7862487792968719 +0.899 0.46673583984375 0.099700927734375 -0.7862487792968719 +0.8991250000000001 0.46856689453125 0.10009765625 -0.7862487792968719 +0.89925 0.470367431640625 0.100494384765625 -0.7862487792968719 +0.899375 0.470367431640625 0.100494384765625 -0.7862487792968719 +0.8995 0.472137451171875 0.100860595703125 -0.7862487792968719 +0.899625 0.472137451171875 0.100860595703125 -0.7862487792968719 +0.89975 0.47381591796875 0.101226806640625 -0.7862487792968719 +0.899875 0.4754638671875 0.101593017578125 -0.7862487792968719 +0.9 0.4754638671875 0.101593017578125 -0.7862487792968719 +0.9001250000000001 0.47705078125 0.1019287109375 -0.7862487792968719 +0.90025 0.47705078125 0.1019287109375 -0.7862487792968719 +0.900375 0.478607177734375 0.10223388671875 -0.7862487792968719 +0.9005 0.480072021484375 0.102569580078125 -0.7862487792968719 +0.900625 0.480072021484375 0.102569580078125 -0.7862487792968719 +0.90075 0.48150634765625 0.102874755859375 -0.7862487792968719 +0.900875 0.48150634765625 0.102874755859375 -0.7862487792968719 +0.901 0.48291015625 0.103179931640625 -0.7862487792968719 +0.9011250000000000768 0.484222412109375 0.10345458984375 -0.7862487792968719 +0.90125 0.484222412109375 0.10345458984375 -0.7862487792968719 +0.901375 0.485504150390625 0.103729248046875 -0.7862487792968719 +0.9015 0.485504150390625 0.103729248046875 -0.7862487792968719 +0.901625 0.486724853515625 0.103973388671875 -0.7862487792968719 +0.90175 0.487884521484375 0.104248046875 -0.7862487792968719 +0.901875 0.487884521484375 0.104248046875 -0.7862487792968719 +0.902 0.489013671875 0.104461669921875 -0.7862487792968719 +0.9021250000000000768 0.489013671875 0.104461669921875 -0.7862487792968719 +0.90225 0.490081787109375 0.104705810546875 -0.7862487792968719 +0.902375 0.4910888671875 0.10491943359375 -0.7862487792968719 +0.9025 0.4910888671875 0.10491943359375 -0.7862487792968719 +0.902625 0.492034912109375 0.105133056640625 -0.7862487792968719 +0.90275 0.492034912109375 0.105133056640625 -0.7862487792968719 +0.902875 0.492950439453125 0.105316162109375 -0.7862487792968719 +0.903 0.4937744140625 0.105499267578125 -0.7862487792968719 +0.9031250000000000768 0.4937744140625 0.105499267578125 -0.7862487792968719 +0.90325 0.49456787109375 0.10565185546875 -0.7862487792968719 +0.903375 0.49456787109375 0.10565185546875 -0.7862487792968719 +0.9035 0.49530029296875 0.105804443359375 -0.7862487792968719 +0.903625 0.496002197265625 0.10595703125 -0.7862487792968719 +0.90375 0.496002197265625 0.10595703125 -0.7862487792968719 +0.903875 0.496612548828125 0.106109619140625 -0.7862487792968719 +0.904 0.496612548828125 0.106109619140625 -0.7862487792968719 +0.9041250000000000768 0.4971923828125 0.106231689453125 -0.7862487792968719 +0.90425 0.497711181640625 0.1063232421875 -0.7862487792968719 +0.904375 0.497711181640625 0.1063232421875 -0.7862487792968719 +0.9045 0.498199462890625 0.1064453125 -0.7862487792968719 +0.904625 0.498199462890625 0.1064453125 -0.7862487792968719 +0.90475 0.49859619140625 0.10650634765625 -0.7862487792968719 +0.904875 0.49896240234375 0.106597900390625 -0.7862487792968719 +0.905 0.49896240234375 0.106597900390625 -0.7862487792968719 +0.9051250000000000768 0.499267578125 0.106658935546875 -0.7862487792968719 +0.90525 0.499267578125 0.106658935546875 -0.7862487792968719 +0.905375 0.49951171875 0.106719970703125 -0.7862487792968719 +0.9055 0.49969482421875 0.10675048828125 -0.7862487792968719 +0.905625 0.49969482421875 0.10675048828125 -0.7862487792968719 +0.90575 0.49981689453125 0.106781005859375 -0.7862487792968719 +0.905875 0.49981689453125 0.106781005859375 -0.7862487792968719 +0.906 0.499908447265625 0.1068115234375 -0.7862487792968719 +0.9061250000000000768 0.49993896484375 0.1068115234375 -0.7862487792968719 +0.90625 0.49993896484375 0.1068115234375 -0.7862487792968719 +0.906375 0.499908447265625 0.1068115234375 -0.7862487792968719 +0.9065 0.499908447265625 0.1068115234375 -0.7862487792968719 +0.906625 0.49981689453125 0.106781005859375 -0.7862487792968719 +0.9067500000000000768 0.49969482421875 0.10675048828125 -0.7862487792968719 +0.906875 0.49969482421875 0.10675048828125 -0.7862487792968719 +0.907 0.49951171875 0.106719970703125 -0.7862487792968719 +0.9071250000000000768 0.49951171875 0.106719970703125 -0.7862487792968719 +0.90725 0.499267578125 0.106658935546875 -0.7862487792968719 +0.907375 0.49896240234375 0.106597900390625 -0.7862487792968719 +0.9075 0.49896240234375 0.106597900390625 -0.7862487792968719 +0.907625 0.49859619140625 0.10650634765625 -0.7862487792968719 +0.9077500000000000768 0.49859619140625 0.10650634765625 -0.7862487792968719 +0.907875 0.498199462890625 0.1064453125 -0.7862487792968719 +0.908 0.497711181640625 0.1063232421875 -0.7862487792968719 +0.9081250000000000768 0.497711181640625 0.1063232421875 -0.7862487792968719 +0.90825 0.4971923828125 0.106231689453125 -0.7862487792968719 +0.908375 0.4971923828125 0.106231689453125 -0.7862487792968719 +0.9085 0.496612548828125 0.106109619140625 -0.7862487792968719 +0.908625 0.496002197265625 0.10595703125 -0.7862487792968719 +0.9087500000000000768 0.496002197265625 0.10595703125 -0.7862487792968719 +0.908875 0.49530029296875 0.105804443359375 -0.7862487792968719 +0.909 0.49530029296875 0.105804443359375 -0.7862487792968719 +0.9091250000000000768 0.49456787109375 0.10565185546875 -0.7862487792968719 +0.90925 0.4937744140625 0.105499267578125 -0.7862487792968719 +0.909375 0.4937744140625 0.105499267578125 -0.7862487792968719 +0.9095 0.492950439453125 0.105316162109375 -0.7862487792968719 +0.909625 0.492950439453125 0.105316162109375 -0.7862487792968719 +0.9097500000000000768 0.492034912109375 0.105133056640625 -0.7862487792968719 +0.909875 0.4910888671875 0.10491943359375 -0.7862487792968719 +0.91 0.4910888671875 0.10491943359375 -0.7862487792968719 +0.910125000000000096 0.490081787109375 0.104705810546875 -0.7862487792968719 +0.91025 0.490081787109375 0.104705810546875 -0.7862487792968719 +0.910375 0.489013671875 0.104461669921875 -0.7862487792968719 +0.9105 0.487884521484375 0.104248046875 -0.7862487792968719 +0.910625 0.487884521484375 0.104248046875 -0.7862487792968719 +0.9107500000000000768 0.486724853515625 0.103973388671875 -0.7862487792968719 +0.910875 0.486724853515625 0.103973388671875 -0.7862487792968719 +0.911 0.485504150390625 0.103729248046875 -0.7862487792968719 +0.911125000000000096 0.484222412109375 0.10345458984375 -0.7862487792968719 +0.91125 0.484222412109375 0.10345458984375 -0.7862487792968719 +0.911375 0.48291015625 0.103179931640625 -0.7862487792968719 +0.9115 0.48291015625 0.103179931640625 -0.7862487792968719 +0.911625 0.48150634765625 0.102874755859375 -0.7862487792968719 +0.9117500000000000768 0.480072021484375 0.102569580078125 -0.7862487792968719 +0.911875 0.480072021484375 0.102569580078125 -0.7862487792968719 +0.912 0.478607177734375 0.10223388671875 -0.7862487792968719 +0.912125 0.478607177734375 0.10223388671875 -0.7862487792968719 +0.91225 0.47705078125 0.1019287109375 -0.7862487792968719 +0.912375 0.4754638671875 0.101593017578125 -0.7862487792968719 +0.9125 0.4754638671875 0.101593017578125 -0.7862487792968719 +0.912625 0.47381591796875 0.101226806640625 -0.7862487792968719 +0.9127500000000000768 0.47381591796875 0.101226806640625 -0.7862487792968719 +0.912875 0.472137451171875 0.100860595703125 -0.7862487792968719 +0.913 0.470367431640625 0.100494384765625 -0.7862487792968719 +0.913125 0.470367431640625 0.100494384765625 -0.7862487792968719 +0.91325 0.46856689453125 0.10009765625 -0.7862487792968719 +0.913375 0.46856689453125 0.10009765625 -0.7862487792968719 +0.9135 0.46673583984375 0.099700927734375 -0.7862487792968719 +0.913625 0.464813232421875 0.09930419921875 -0.7862487792968719 +0.9137500000000000768 0.464813232421875 0.09930419921875 -0.7862487792968719 +0.913875 0.462890625 0.098876953125 -0.7862487792968719 +0.914 0.462890625 0.098876953125 -0.7862487792968719 +0.914125 0.46087646484375 0.09844970703125 -0.7862487792968719 +0.91425 0.458831787109375 0.0980224609375 -0.7862487792968719 +0.914375 0.458831787109375 0.0980224609375 -0.7862487792968719 +0.9145 0.45672607421875 0.097564697265625 -0.7862487792968719 +0.914625 0.45672607421875 0.097564697265625 -0.7862487792968719 +0.9147500000000000768 0.454559326171875 0.09710693359375 -0.7862487792968719 +0.914875 0.452362060546875 0.096649169921875 -0.7862487792968719 +0.915 0.452362060546875 0.096649169921875 -0.7862487792968719 +0.915125 0.450103759765625 0.096160888671875 -0.7862487792968719 +0.91525 0.450103759765625 0.096160888671875 -0.7862487792968719 +0.915375 0.447784423828125 0.095672607421875 -0.7862487792968719 +0.9155 0.4454345703125 0.09515380859375 -0.7862487792968719 +0.915625 0.4454345703125 0.09515380859375 -0.7862487792968719 +0.9157500000000000768 0.44305419921875 0.09466552734375 -0.7862487792968719 +0.915875 0.44305419921875 0.09466552734375 -0.7862487792968719 +0.916 0.440582275390625 0.0941162109375 -0.7862487792968719 +0.916125 0.438079833984375 0.093597412109375 -0.7862487792968719 +0.91625 0.438079833984375 0.093597412109375 -0.7862487792968719 +0.916375 0.435546875 0.093048095703125 -0.7862487792968719 +0.9165 0.435546875 0.093048095703125 -0.7862487792968719 +0.916625 0.432952880859375 0.092498779296875 -0.7862487792968719 +0.9167500000000000768 0.4302978515625 0.0919189453125 -0.7862487792968719 +0.916875 0.4302978515625 0.0919189453125 -0.7862487792968719 +0.917 0.4276123046875 0.09136962890625 -0.7862487792968719 +0.917125 0.4276123046875 0.09136962890625 -0.7862487792968719 +0.91725 0.424896240234375 0.09075927734375 -0.7862487792968719 +0.917375 0.422119140625 0.090179443359375 -0.7862487792968719 +0.9175 0.422119140625 0.090179443359375 -0.7862487792968719 +0.917625 0.419281005859375 0.089569091796875 -0.7862487792968719 +0.9177500000000000768 0.419281005859375 0.089569091796875 -0.7862487792968719 +0.917875 0.416412353515625 0.088958740234375 -0.7862487792968719 +0.918 0.413482666015625 0.088348388671875 -0.7862487792968719 +0.918125 0.413482666015625 0.088348388671875 -0.7862487792968719 +0.91825 0.4105224609375 0.08770751953125 -0.7862487792968719 +0.918375 0.4105224609375 0.08770751953125 -0.7862487792968719 +0.9185 0.407501220703125 0.087066650390625 -0.7862487792968719 +0.918625 0.404449462890625 0.086395263671875 -0.7862487792968719 +0.9187500000000000768 0.404449462890625 0.086395263671875 -0.7862487792968719 +0.918875 0.401336669921875 0.08575439453125 -0.7862487792968719 +0.919 0.401336669921875 0.08575439453125 -0.7862487792968719 +0.919125 0.398193359375 0.0850830078125 -0.7862487792968719 +0.91925 0.39501953125 0.084381103515625 -0.7862487792968719 +0.919375 0.39501953125 0.084381103515625 -0.7862487792968719 +0.9195 0.39178466796875 0.083709716796875 -0.7862487792968719 +0.919625 0.39178466796875 0.083709716796875 -0.7862487792968719 +0.9197500000000000768 0.388519287109375 0.0830078125 -0.7862487792968719 +0.919875 0.38519287109375 0.082305908203125 -0.7862487792968719 +0.92 0.38519287109375 0.082305908203125 -0.7862487792968719 +0.920125 0.3818359375 0.081573486328125 -0.7862487792968719 +0.92025 0.3818359375 0.081573486328125 -0.7862487792968719 +0.920375 0.378448486328125 0.080841064453125 -0.7862487792968719 +0.9205 0.375 0.080108642578125 -0.7862487792968719 +0.920625 0.375 0.080108642578125 -0.7862487792968719 +0.9207500000000000768 0.37152099609375 0.079376220703125 -0.7862487792968719 +0.920875 0.37152099609375 0.079376220703125 -0.7862487792968719 +0.921 0.36798095703125 0.07861328125 -0.7862487792968719 +0.921125 0.36444091796875 0.077850341796875 -0.7862487792968719 +0.92125 0.36444091796875 0.077850341796875 -0.7862487792968719 +0.921375 0.360809326171875 0.07708740234375 -0.7862487792968719 +0.9215 0.360809326171875 0.07708740234375 -0.7862487792968719 +0.921625 0.357177734375 0.0762939453125 -0.7862487792968719 +0.9217500000000000768 0.353485107421875 0.075531005859375 -0.7862487792968719 +0.921875 0.353485107421875 0.075531005859375 -0.7862487792968719 +0.922 0.349761962890625 0.074737548828125 -0.7862487792968719 +0.922125 0.349761962890625 0.074737548828125 -0.7862487792968719 +0.92225 0.34600830078125 0.07391357421875 -0.7862487792968719 +0.922375000000000096 0.34222412109375 0.0731201171875 -0.7862487792968719 +0.9225 0.34222412109375 0.0731201171875 -0.7862487792968719 +0.922625 0.33837890625 0.072296142578125 -0.7862487792968719 +0.922750000000000096 0.33837890625 0.072296142578125 -0.7862487792968719 +0.922875 0.334503173828125 0.07147216796875 -0.7862487792968719 +0.923 0.330596923828125 0.07061767578125 -0.7862487792968719 +0.923125 0.330596923828125 0.07061767578125 -0.7862487792968719 +0.92325 0.32666015625 0.069793701171875 -0.7862487792968719 +0.923375000000000096 0.32666015625 0.069793701171875 -0.7862487792968719 +0.9235 0.322662353515625 0.068939208984375 -0.7862487792968719 +0.923625 0.31866455078125 0.068084716796875 -0.7862487792968719 +0.923750000000000096 0.31866455078125 0.068084716796875 -0.7862487792968719 +0.923875 0.314605712890625 0.06719970703125 -0.7862487792968719 +0.924 0.314605712890625 0.06719970703125 -0.7862487792968719 +0.924125 0.310516357421875 0.06634521484375 -0.7862487792968719 +0.92425 0.306396484375 0.065460205078125 -0.7862487792968719 +0.924375000000000096 0.306396484375 0.065460205078125 -0.7862487792968719 +0.9245 0.30224609375 0.0645751953125 -0.7862487792968719 +0.924625 0.30224609375 0.0645751953125 -0.7862487792968719 +0.924750000000000096 0.298065185546875 0.06365966796875 -0.7862487792968719 +0.924875 0.2938232421875 0.062774658203125 -0.7862487792968719 +0.925 0.2938232421875 0.062774658203125 -0.7862487792968719 +0.925125 0.289581298828125 0.061859130859375 -0.7862487792968719 +0.92525 0.289581298828125 0.061859130859375 -0.7862487792968719 +0.925375000000000096 0.285308837890625 0.060943603515625 -0.7862487792968719 +0.9255 0.280975341796875 0.060028076171875 -0.7862487792968719 +0.925625 0.280975341796875 0.060028076171875 -0.7862487792968719 +0.925750000000000096 0.276641845703125 0.05908203125 -0.7862487792968719 +0.925875 0.276641845703125 0.05908203125 -0.7862487792968719 +0.926 0.27227783203125 0.05816650390625 -0.7862487792968719 +0.926125 0.267852783203125 0.057220458984375 -0.7862487792968719 +0.92625 0.267852783203125 0.057220458984375 -0.7862487792968719 +0.926375000000000096 0.263427734375 0.0562744140625 -0.7862487792968719 +0.9265 0.263427734375 0.0562744140625 -0.7862487792968719 +0.926625 0.25897216796875 0.055328369140625 -0.7862487792968719 +0.926750000000000096 0.25445556640625 0.054351806640625 -0.7862487792968719 +0.926875 0.25445556640625 0.054351806640625 -0.7862487792968719 +0.927 0.249969482421875 0.05340576171875 -0.7862487792968719 +0.927125 0.249969482421875 0.05340576171875 -0.7862487792968719 +0.92725 0.24542236328125 0.05242919921875 -0.7862487792968719 +0.927375000000000096 0.2408447265625 0.05145263671875 -0.7862487792968719 +0.9275 0.2408447265625 0.05145263671875 -0.7862487792968719 +0.927625 0.236236572265625 0.05047607421875 -0.7862487792968719 +0.927750000000000096 0.236236572265625 0.05047607421875 -0.7862487792968719 +0.927875 0.231597900390625 0.049468994140625 -0.7862487792968719 +0.928 0.226959228515625 0.11761474609375 -0.481719970703120832 +0.928125 0.226959228515625 0.11761474609375 -0.481719970703120832 +0.92825 0.2222900390625 0.11517333984375 -0.481719970703120832 +0.928375000000000096 0.2222900390625 0.11517333984375 -0.481719970703120832 +0.9285 0.21759033203125 0.11273193359375 -0.481719970703120832 +0.928625 0.212860107421875 0.11029052734375 -0.481719970703120832 +0.92875 0.212860107421875 0.11029052734375 -0.481719970703120832 +0.928875 0.208099365234375 0.10784912109375 -0.481719970703120832 +0.929 0.208099365234375 0.10784912109375 -0.481719970703120832 +0.929125 0.203338623046875 0.1053466796875 -0.481719970703120832 +0.92925 0.19854736328125 0.102874755859375 -0.481719970703120832 +0.929375000000000096 0.19854736328125 0.102874755859375 -0.481719970703120832 +0.9295 0.1937255859375 0.100372314453125 -0.481719970703120832 +0.929625 0.1937255859375 0.100372314453125 -0.481719970703120832 +0.92975 0.188873291015625 0.097869873046875 -0.481719970703120832 +0.929875 0.18402099609375 0.095367431640625 -0.481719970703120832 +0.93 0.18402099609375 0.095367431640625 -0.481719970703120832 +0.930125 0.17913818359375 0.09283447265625 -0.481719970703120832 +0.93025 0.17913818359375 0.09283447265625 -0.481719970703120832 +0.930375000000000096 0.17425537109375 0.090301513671875 -0.481719970703120832 +0.9305 0.169342041015625 0.087738037109375 -0.481719970703120832 +0.930625 0.169342041015625 0.087738037109375 -0.481719970703120832 +0.93075 0.164398193359375 0.085174560546875 -0.481719970703120832 +0.930875 0.164398193359375 0.085174560546875 -0.481719970703120832 +0.931 0.159454345703125 0.082611083984375 -0.481719970703120832 +0.931125 0.15447998046875 0.080047607421875 -0.481719970703120832 +0.93125 0.15447998046875 0.080047607421875 -0.481719970703120832 +0.931375000000000096 0.14947509765625 0.07745361328125 -0.481719970703120832 +0.9315 0.14947509765625 0.07745361328125 -0.481719970703120832 +0.931625 0.14447021484375 0.074859619140625 -0.481719970703120832 +0.93175 0.13946533203125 0.072265625 -0.481719970703120832 +0.931875 0.13946533203125 0.072265625 -0.481719970703120832 +0.932 0.134429931640625 0.06964111328125 -0.481719970703120832 +0.932125 0.134429931640625 0.06964111328125 -0.481719970703120832 +0.93225 0.129364013671875 0.067047119140625 -0.481719970703120832 +0.932375000000000096 0.124298095703125 0.064422607421875 -0.481719970703120832 +0.9325 0.124298095703125 0.064422607421875 -0.481719970703120832 +0.932625 0.119232177734375 0.061798095703125 -0.481719970703120832 +0.93275 0.119232177734375 0.061798095703125 -0.481719970703120832 +0.932875 0.1141357421875 0.05914306640625 -0.481719970703120832 +0.933 0.109039306640625 0.056488037109375 -0.481719970703120832 +0.933125 0.109039306640625 0.056488037109375 -0.481719970703120832 +0.93325 0.103912353515625 0.0538330078125 -0.481719970703120832 +0.933375000000000096 0.103912353515625 0.0538330078125 -0.481719970703120832 +0.9335 0.098785400390625 0.051177978515625 -0.481719970703120832 +0.933625 0.093658447265625 0.04852294921875 -0.481719970703120832 +0.93375 0.093658447265625 0.04852294921875 -0.481719970703120832 +0.933875 0.0885009765625 0.045867919921875 -0.481719970703120832 +0.934 0.0885009765625 0.045867919921875 -0.481719970703120832 +0.934125 0.083343505859375 0.043182373046875 -0.481719970703120832 +0.93425 0.07818603515625 0.040496826171875 -0.481719970703120832 +0.934375000000000096 0.07818603515625 0.040496826171875 -0.481719970703120832 +0.9345 0.072998046875 0.037841796875 -0.481719970703120832 +0.934625 0.072998046875 0.037841796875 -0.481719970703120832 +0.93475 0.06781005859375 0.035125732421875 -0.481719970703120832 +0.934875 0.0626220703125 0.032440185546875 -0.481719970703120832 +0.935 0.0626220703125 0.032440185546875 -0.481719970703120832 +0.935125 0.05743408203125 0.029754638671875 -0.481719970703120832 +0.93525 0.05743408203125 0.029754638671875 -0.481719970703120832 +0.935375000000000096 0.05224609375 0.027069091796875 -0.481719970703120832 +0.9355 0.047027587890625 0.02435302734375 -0.481719970703120832 +0.935625 0.047027587890625 0.02435302734375 -0.481719970703120832 +0.93575 0.04180908203125 0.02166748046875 -0.481719970703120832 +0.935875 0.04180908203125 0.02166748046875 -0.481719970703120832 +0.936 0.036590576171875 0.018951416015625 -0.481719970703120832 +0.936125 0.0313720703125 0.0162353515625 -0.481719970703120832 +0.93625 0.0313720703125 0.0162353515625 -0.481719970703120832 +0.936375000000000096 0.026123046875 0.0135498046875 -0.481719970703120832 +0.9365 0.026123046875 0.0135498046875 -0.481719970703120832 +0.936625 0.020904541015625 0.010833740234375 -0.481719970703120832 +0.93675 0.01568603515625 0.00811767578125 -0.481719970703120832 +0.936875 0.01568603515625 0.00811767578125 -0.481719970703120832 +0.937 0.01043701171875 0.005401611328125 -0.481719970703120832 +0.937125 0.01043701171875 0.005401611328125 -0.481719970703120832 +0.93725 0.005218505859375 0.002685546875 -0.481719970703120832 +0.937375000000000096 0.0 0.0 -0.481719970703120832 +0.9375 0.0 0.0 -0.481719970703120832 +0.937625 -0.005218505859375 -0.002685546875 -0.481719970703120832 +0.93775 -0.005218505859375 -0.002685546875 -0.481719970703120832 +0.937875 -0.01043701171875 -0.005401611328125 -0.481719970703120832 +0.938000000000000096 -0.01568603515625 -0.00811767578125 -0.481719970703120832 +0.938125 -0.01568603515625 -0.00811767578125 -0.481719970703120832 +0.93825 -0.020904541015625 -0.010833740234375 -0.481719970703120832 +0.938375000000000096 -0.020904541015625 -0.010833740234375 -0.481719970703120832 +0.9385 -0.026123046875 -0.0135498046875 -0.481719970703120832 +0.938625 -0.0313720703125 -0.0162353515625 -0.481719970703120832 +0.93875 -0.0313720703125 -0.0162353515625 -0.481719970703120832 +0.938875 -0.036590576171875 -0.018951416015625 -0.481719970703120832 +0.939000000000000096 -0.036590576171875 -0.018951416015625 -0.481719970703120832 +0.939125 -0.04180908203125 -0.02166748046875 -0.481719970703120832 +0.93925 -0.047027587890625 -0.02435302734375 -0.481719970703120832 +0.939375000000000096 -0.047027587890625 -0.02435302734375 -0.481719970703120832 +0.9395 -0.05224609375 -0.027069091796875 -0.481719970703120832 +0.939625 -0.05224609375 -0.027069091796875 -0.481719970703120832 +0.93975 -0.05743408203125 -0.029754638671875 -0.481719970703120832 +0.939875 -0.0626220703125 -0.032440185546875 -0.481719970703120832 +0.940000000000000096 -0.0626220703125 -0.032440185546875 -0.481719970703120832 +0.940125 -0.06781005859375 -0.035125732421875 -0.481719970703120832 +0.94025 -0.06781005859375 -0.035125732421875 -0.481719970703120832 +0.940375000000000096 -0.072998046875 -0.037841796875 -0.481719970703120832 +0.9405 -0.07818603515625 -0.040496826171875 -0.481719970703120832 +0.940625 -0.07818603515625 -0.040496826171875 -0.481719970703120832 +0.94075 -0.083343505859375 -0.043182373046875 -0.481719970703120832 +0.940875 -0.083343505859375 -0.043182373046875 -0.481719970703120832 +0.941000000000000096 -0.0885009765625 -0.045867919921875 -0.481719970703120832 +0.941125 -0.093658447265625 -0.04852294921875 -0.481719970703120832 +0.94125 -0.093658447265625 -0.04852294921875 -0.481719970703120832 +0.941375000000000096 -0.098785400390625 -0.051177978515625 -0.481719970703120832 +0.9415 -0.098785400390625 -0.051177978515625 -0.481719970703120832 +0.941625 -0.103912353515625 -0.0538330078125 -0.481719970703120832 +0.94175 -0.109039306640625 -0.056488037109375 -0.481719970703120832 +0.941875 -0.109039306640625 -0.056488037109375 -0.481719970703120832 +0.942000000000000096 -0.1141357421875 -0.05914306640625 -0.481719970703120832 +0.942125 -0.1141357421875 -0.05914306640625 -0.481719970703120832 +0.94225 -0.119232177734375 -0.061798095703125 -0.481719970703120832 +0.942375000000000096 -0.124298095703125 -0.064422607421875 -0.481719970703120832 +0.9425 -0.124298095703125 -0.064422607421875 -0.481719970703120832 +0.942625 -0.129364013671875 -0.067047119140625 -0.481719970703120832 +0.94275 -0.129364013671875 -0.067047119140625 -0.481719970703120832 +0.942875 -0.134429931640625 -0.06964111328125 -0.481719970703120832 +0.943000000000000096 -0.13946533203125 -0.072265625 -0.481719970703120832 +0.943125 -0.13946533203125 -0.072265625 -0.481719970703120832 +0.94325 -0.14447021484375 -0.074859619140625 -0.481719970703120832 +0.943375000000000096 -0.14447021484375 -0.074859619140625 -0.481719970703120832 +0.9435 -0.14947509765625 -0.07745361328125 -0.481719970703120832 +0.943625 -0.15447998046875 -0.080047607421875 -0.481719970703120832 +0.94375 -0.15447998046875 -0.080047607421875 -0.481719970703120832 +0.943875 -0.159454345703125 -0.082611083984375 -0.481719970703120832 +0.944000000000000096 -0.159454345703125 -0.082611083984375 -0.481719970703120832 +0.944125 -0.164398193359375 -0.085174560546875 -0.481719970703120832 +0.94425 -0.169342041015625 -0.087738037109375 -0.481719970703120832 +0.944375 -0.169342041015625 -0.087738037109375 -0.481719970703120832 +0.9445 -0.17425537109375 -0.090301513671875 -0.481719970703120832 +0.944625 -0.17425537109375 -0.090301513671875 -0.481719970703120832 +0.94475 -0.17913818359375 -0.09283447265625 -0.481719970703120832 +0.944875 -0.18402099609375 -0.095367431640625 -0.481719970703120832 +0.945000000000000096 -0.18402099609375 -0.095367431640625 -0.481719970703120832 +0.945125 -0.188873291015625 -0.097869873046875 -0.481719970703120832 +0.94525 -0.188873291015625 -0.097869873046875 -0.481719970703120832 +0.945375 -0.1937255859375 -0.100372314453125 -0.481719970703120832 +0.9455 -0.19854736328125 -0.102874755859375 -0.481719970703120832 +0.945625 -0.19854736328125 -0.102874755859375 -0.481719970703120832 +0.94575 -0.203338623046875 -0.1053466796875 -0.481719970703120832 +0.945875 -0.203338623046875 -0.1053466796875 -0.481719970703120832 +0.946000000000000096 -0.208099365234375 -0.10784912109375 -0.481719970703120832 +0.946125 -0.212860107421875 -0.11029052734375 -0.481719970703120832 +0.94625 -0.212860107421875 -0.11029052734375 -0.481719970703120832 +0.946375 -0.21759033203125 -0.11273193359375 -0.481719970703120832 +0.9465 -0.21759033203125 -0.11273193359375 -0.481719970703120832 +0.946625 -0.2222900390625 -0.11517333984375 -0.481719970703120832 +0.94675 -0.226959228515625 -0.11761474609375 -0.481719970703120832 +0.946875 -0.226959228515625 -0.11761474609375 -0.481719970703120832 +0.947000000000000096 -0.231597900390625 -0.120025634765625 -0.481719970703120832 +0.947125 -0.231597900390625 -0.120025634765625 -0.481719970703120832 +0.94725 -0.236236572265625 -0.122406005859375 -0.481719970703120832 +0.947375 -0.2408447265625 -0.124786376953125 -0.481719970703120832 +0.9475 -0.2408447265625 -0.124786376953125 -0.481719970703120832 +0.947625 -0.24542236328125 -0.127166748046875 -0.481719970703120832 +0.94775 -0.24542236328125 -0.127166748046875 -0.481719970703120832 +0.947875 -0.249969482421875 -0.1295166015625 -0.481719970703120832 +0.948000000000000096 -0.25445556640625 -0.131866455078125 -0.481719970703120832 +0.948125 -0.25445556640625 -0.131866455078125 -0.481719970703120832 +0.94825 -0.25897216796875 -0.134185791015625 -0.481719970703120832 +0.948375 -0.25897216796875 -0.134185791015625 -0.481719970703120832 +0.9485 -0.263427734375 -0.136505126953125 -0.481719970703120832 +0.948625 -0.267852783203125 -0.1387939453125 -0.481719970703120832 +0.94875 -0.267852783203125 -0.1387939453125 -0.481719970703120832 +0.948875 -0.27227783203125 -0.141082763671875 -0.481719970703120832 +0.949000000000000096 -0.27227783203125 -0.141082763671875 -0.481719970703120832 +0.949125 -0.276641845703125 -0.143341064453125 -0.481719970703120832 +0.94925 -0.280975341796875 -0.145599365234375 -0.481719970703120832 +0.949375 -0.280975341796875 -0.145599365234375 -0.481719970703120832 +0.9495 -0.285308837890625 -0.147857666015625 -0.481719970703120832 +0.949625 -0.285308837890625 -0.147857666015625 -0.481719970703120832 +0.94975 -0.289581298828125 -0.150054931640625 -0.481719970703120832 +0.949875 -0.2938232421875 -0.152252197265625 -0.481719970703120832 +0.950000000000000096 -0.2938232421875 -0.152252197265625 -0.481719970703120832 +0.950125 -0.298065185546875 -0.154449462890625 -0.481719970703120832 +0.95025 -0.298065185546875 -0.154449462890625 -0.481719970703120832 +0.950375 -0.30224609375 -0.1566162109375 -0.481719970703120832 +0.9505 -0.306396484375 -0.158782958984375 -0.481719970703120832 +0.950625 -0.306396484375 -0.158782958984375 -0.481719970703120832 +0.95075 -0.310516357421875 -0.160919189453125 -0.481719970703120832 +0.950875 -0.310516357421875 -0.160919189453125 -0.481719970703120832 +0.951000000000000096 -0.314605712890625 -0.16302490234375 -0.481719970703120832 +0.951125 -0.31866455078125 -0.165130615234375 -0.481719970703120832 +0.95125 -0.31866455078125 -0.165130615234375 -0.481719970703120832 +0.951375 -0.322662353515625 -0.167205810546875 -0.481719970703120832 +0.9515 -0.322662353515625 -0.167205810546875 -0.481719970703120832 +0.951625 -0.32666015625 -0.169281005859375 -0.481719970703120832 +0.95175 -0.330596923828125 -0.17132568359375 -0.481719970703120832 +0.951875 -0.330596923828125 -0.17132568359375 -0.481719970703120832 +0.952000000000000096 -0.334503173828125 -0.17333984375 -0.481719970703120832 +0.952125 -0.334503173828125 -0.17333984375 -0.481719970703120832 +0.95225 -0.33837890625 -0.17535400390625 -0.481719970703120832 +0.952375 -0.34222412109375 -0.177337646484375 -0.481719970703120832 +0.9525 -0.34222412109375 -0.177337646484375 -0.481719970703120832 +0.952625 -0.34600830078125 -0.179290771484375 -0.481719970703120832 +0.95275 -0.34600830078125 -0.179290771484375 -0.481719970703120832 +0.952875 -0.349761962890625 -0.181243896484375 -0.481719970703120832 +0.953000000000000096 -0.353485107421875 -0.18316650390625 -0.481719970703120832 +0.953125 -0.353485107421875 -0.18316650390625 -0.481719970703120832 +0.95325 -0.357177734375 -0.185089111328125 -0.481719970703120832 +0.953375 -0.357177734375 -0.185089111328125 -0.481719970703120832 +0.9535 -0.360809326171875 -0.186981201171875 -0.481719970703120832 +0.953625000000000096 -0.36444091796875 -0.1888427734375 -0.481719970703120832 +0.95375 -0.36444091796875 -0.1888427734375 -0.481719970703120832 +0.953875 -0.36798095703125 -0.190704345703125 -0.481719970703120832 +0.954000000000000096 -0.36798095703125 -0.190704345703125 -0.481719970703120832 +0.954125 -0.37152099609375 -0.1925048828125 -0.481719970703120832 +0.95425 -0.375 -0.1943359375 -0.481719970703120832 +0.954375 -0.375 -0.1943359375 -0.481719970703120832 +0.9545 -0.378448486328125 -0.19610595703125 -0.481719970703120832 +0.954625000000000096 -0.378448486328125 -0.19610595703125 -0.481719970703120832 +0.95475 -0.3818359375 -0.1978759765625 -0.481719970703120832 +0.954875 -0.38519287109375 -0.199615478515625 -0.481719970703120832 +0.955000000000000096 -0.38519287109375 -0.199615478515625 -0.481719970703120832 +0.955125 -0.388519287109375 -0.201324462890625 -0.481719970703120832 +0.95525 -0.388519287109375 -0.201324462890625 -0.481719970703120832 +0.955375 -0.39178466796875 -0.203033447265625 -0.481719970703120832 +0.9555 -0.39501953125 -0.2047119140625 -0.481719970703120832 +0.955625000000000096 -0.39501953125 -0.2047119140625 -0.481719970703120832 +0.95575 -0.398193359375 -0.20635986328125 -0.481719970703120832 +0.955875 -0.398193359375 -0.20635986328125 -0.481719970703120832 +0.956000000000000096 -0.401336669921875 -0.207977294921875 -0.481719970703120832 +0.956125 -0.404449462890625 -0.2095947265625 -0.481719970703120832 +0.95625 -0.404449462890625 -0.2095947265625 -0.481719970703120832 +0.956375 -0.407501220703125 -0.211181640625 -0.481719970703120832 +0.9565 -0.407501220703125 -0.211181640625 -0.481719970703120832 +0.956625000000000096 -0.4105224609375 -0.212738037109375 -0.481719970703120832 +0.95675 -0.413482666015625 -0.214263916015625 -0.481719970703120832 +0.956875 -0.413482666015625 -0.214263916015625 -0.481719970703120832 +0.957000000000000096 -0.416412353515625 -0.215789794921875 -0.481719970703120832 +0.957125 -0.416412353515625 -0.215789794921875 -0.481719970703120832 +0.95725 -0.419281005859375 -0.217254638671875 -0.481719970703120832 +0.957375 -0.422119140625 -0.21875 -0.481719970703120832 +0.9575 -0.422119140625 -0.21875 -0.481719970703120832 +0.957625000000000096 -0.424896240234375 -0.220184326171875 -0.481719970703120832 +0.95775 -0.424896240234375 -0.220184326171875 -0.481719970703120832 +0.957875 -0.4276123046875 -0.221588134765625 -0.481719970703120832 +0.958000000000000096 -0.4302978515625 -0.222991943359375 -0.481719970703120832 +0.958125 -0.4302978515625 -0.222991943359375 -0.481719970703120832 +0.95825 -0.432952880859375 -0.224365234375 -0.481719970703120832 +0.958375 -0.432952880859375 -0.224365234375 -0.481719970703120832 +0.9585 -0.435546875 -0.2257080078125 -0.481719970703120832 +0.958625000000000096 -0.438079833984375 -0.227020263671875 -0.481719970703120832 +0.95875 -0.438079833984375 -0.227020263671875 -0.481719970703120832 +0.958875 -0.440582275390625 -0.228302001953125 -0.481719970703120832 +0.959000000000000096 -0.440582275390625 -0.228302001953125 -0.481719970703120832 +0.959125 -0.44305419921875 -0.229583740234375 -0.481719970703120832 +0.95925 -0.4454345703125 -0.2308349609375 -0.481719970703120832 +0.959375 -0.4454345703125 -0.2308349609375 -0.481719970703120832 +0.9595 -0.447784423828125 -0.2320556640625 -0.481719970703120832 +0.959625000000000096 -0.447784423828125 -0.2320556640625 -0.481719970703120832 +0.95975 -0.450103759765625 -0.233245849609375 -0.481719970703120832 +0.959875 -0.452362060546875 -0.234405517578125 -0.481719970703120832 +0.96 -0.452362060546875 -0.406951904296875 -0.1003479003906193 +0.960125 -0.454559326171875 -0.408905029296875 -0.1003479003906193 +0.96025 -0.454559326171875 -0.408905029296875 -0.1003479003906193 +0.960375 -0.45672607421875 -0.410858154296875 -0.1003479003906193 +0.9605 -0.458831787109375 -0.412750244140625 -0.1003479003906193 +0.960625000000000096 -0.458831787109375 -0.412750244140625 -0.1003479003906193 +0.96075 -0.46087646484375 -0.41461181640625 -0.1003479003906193 +0.960875 -0.46087646484375 -0.41461181640625 -0.1003479003906193 +0.961 -0.462890625 -0.416412353515625 -0.1003479003906193 +0.961125 -0.464813232421875 -0.41815185546875 -0.1003479003906193 +0.96125 -0.464813232421875 -0.41815185546875 -0.1003479003906193 +0.961375 -0.46673583984375 -0.41986083984375 -0.1003479003906193 +0.9615 -0.46673583984375 -0.41986083984375 -0.1003479003906193 +0.961625000000000096 -0.46856689453125 -0.421539306640625 -0.1003479003906193 +0.96175 -0.470367431640625 -0.42315673828125 -0.1003479003906193 +0.961875 -0.470367431640625 -0.42315673828125 -0.1003479003906193 +0.962 -0.472137451171875 -0.42474365234375 -0.1003479003906193 +0.962125 -0.472137451171875 -0.42474365234375 -0.1003479003906193 +0.96225 -0.47381591796875 -0.42626953125 -0.1003479003906193 +0.962375 -0.4754638671875 -0.427734375 -0.1003479003906193 +0.9625 -0.4754638671875 -0.427734375 -0.1003479003906193 +0.962625000000000096 -0.47705078125 -0.429168701171875 -0.1003479003906193 +0.96275 -0.47705078125 -0.429168701171875 -0.1003479003906193 +0.962875 -0.478607177734375 -0.4305419921875 -0.1003479003906193 +0.963 -0.480072021484375 -0.431884765625 -0.1003479003906193 +0.963125 -0.480072021484375 -0.431884765625 -0.1003479003906193 +0.96325 -0.48150634765625 -0.43316650390625 -0.1003479003906193 +0.963375 -0.48150634765625 -0.43316650390625 -0.1003479003906193 +0.9635 -0.48291015625 -0.434417724609375 -0.1003479003906193 +0.963625000000000096 -0.484222412109375 -0.43560791015625 -0.1003479003906193 +0.96375 -0.484222412109375 -0.43560791015625 -0.1003479003906193 +0.963875 -0.485504150390625 -0.436767578125 -0.1003479003906193 +0.964 -0.485504150390625 -0.436767578125 -0.1003479003906193 +0.964125 -0.486724853515625 -0.4378662109375 -0.1003479003906193 +0.96425 -0.487884521484375 -0.43890380859375 -0.1003479003906193 +0.964375 -0.487884521484375 -0.43890380859375 -0.1003479003906193 +0.9645 -0.489013671875 -0.439910888671875 -0.1003479003906193 +0.964625000000000096 -0.489013671875 -0.439910888671875 -0.1003479003906193 +0.96475 -0.490081787109375 -0.440887451171875 -0.1003479003906193 +0.964875 -0.4910888671875 -0.4417724609375 -0.1003479003906193 +0.965 -0.4910888671875 -0.4417724609375 -0.1003479003906193 +0.965125 -0.492034912109375 -0.442657470703125 -0.1003479003906193 +0.96525 -0.492034912109375 -0.442657470703125 -0.1003479003906193 +0.965375 -0.492950439453125 -0.443450927734375 -0.1003479003906193 +0.9655 -0.4937744140625 -0.4442138671875 -0.1003479003906193 +0.965625000000000096 -0.4937744140625 -0.4442138671875 -0.1003479003906193 +0.96575 -0.49456787109375 -0.444915771484375 -0.1003479003906193 +0.965875 -0.49456787109375 -0.444915771484375 -0.1003479003906193 +0.966 -0.49530029296875 -0.445587158203125 -0.1003479003906193 +0.966125 -0.496002197265625 -0.446197509765625 -0.1003479003906193 +0.96625 -0.496002197265625 -0.446197509765625 -0.1003479003906193 +0.966375 -0.496612548828125 -0.446746826171875 -0.1003479003906193 +0.9665 -0.496612548828125 -0.446746826171875 -0.1003479003906193 +0.966625000000000096 -0.4971923828125 -0.447296142578125 -0.1003479003906193 +0.96675 -0.497711181640625 -0.44775390625 -0.1003479003906193 +0.966875 -0.497711181640625 -0.44775390625 -0.1003479003906193 +0.967 -0.498199462890625 -0.44818115234375 -0.1003479003906193 +0.967125 -0.498199462890625 -0.44818115234375 -0.1003479003906193 +0.96725 -0.49859619140625 -0.44854736328125 -0.1003479003906193 +0.967375 -0.49896240234375 -0.4488525390625 -0.1003479003906193 +0.9675 -0.49896240234375 -0.4488525390625 -0.1003479003906193 +0.967625000000000096 -0.499267578125 -0.449127197265625 -0.1003479003906193 +0.96775 -0.499267578125 -0.449127197265625 -0.1003479003906193 +0.967875 -0.49951171875 -0.449371337890625 -0.1003479003906193 +0.968 -0.49969482421875 -0.44952392578125 -0.1003479003906193 +0.968125 -0.49969482421875 -0.44952392578125 -0.1003479003906193 +0.96825 -0.49981689453125 -0.44964599609375 -0.1003479003906193 +0.968375 -0.49981689453125 -0.44964599609375 -0.1003479003906193 +0.9685 -0.499908447265625 -0.449737548828125 -0.1003479003906193 +0.968625000000000096 -0.49993896484375 -0.44976806640625 -0.1003479003906193 +0.96875 -0.49993896484375 -0.44976806640625 -0.1003479003906193 +0.968875 -0.499908447265625 -0.449737548828125 -0.1003479003906193 +0.969 -0.499908447265625 -0.449737548828125 -0.1003479003906193 +0.969125 -0.49981689453125 -0.44964599609375 -0.1003479003906193 +0.969250000000000096 -0.49969482421875 -0.44952392578125 -0.1003479003906193 +0.969375 -0.49969482421875 -0.44952392578125 -0.1003479003906193 +0.9695 -0.49951171875 -0.449371337890625 -0.1003479003906193 +0.969625000000000096 -0.49951171875 -0.449371337890625 -0.1003479003906193 +0.96975 -0.499267578125 -0.449127197265625 -0.1003479003906193 +0.969875 -0.49896240234375 -0.4488525390625 -0.1003479003906193 +0.97 -0.49896240234375 -0.4488525390625 -0.1003479003906193 +0.970125 -0.49859619140625 -0.44854736328125 -0.1003479003906193 +0.970250000000000096 -0.49859619140625 -0.44854736328125 -0.1003479003906193 +0.970375 -0.498199462890625 -0.44818115234375 -0.1003479003906193 +0.9705 -0.497711181640625 -0.44775390625 -0.1003479003906193 +0.970625000000000096 -0.497711181640625 -0.44775390625 -0.1003479003906193 +0.97075 -0.4971923828125 -0.447296142578125 -0.1003479003906193 +0.970875 -0.4971923828125 -0.447296142578125 -0.1003479003906193 +0.971 -0.496612548828125 -0.446746826171875 -0.1003479003906193 +0.971125 -0.496002197265625 -0.446197509765625 -0.1003479003906193 +0.971250000000000096 -0.496002197265625 -0.446197509765625 -0.1003479003906193 +0.971375 -0.49530029296875 -0.445587158203125 -0.1003479003906193 +0.9715 -0.49530029296875 -0.445587158203125 -0.1003479003906193 +0.971625000000000096 -0.49456787109375 -0.444915771484375 -0.1003479003906193 +0.97175 -0.4937744140625 -0.4442138671875 -0.1003479003906193 +0.971875 -0.4937744140625 -0.4442138671875 -0.1003479003906193 +0.972 -0.492950439453125 -0.443450927734375 -0.1003479003906193 +0.972125 -0.492950439453125 -0.443450927734375 -0.1003479003906193 +0.972250000000000096 -0.492034912109375 -0.442657470703125 -0.1003479003906193 +0.972375 -0.4910888671875 -0.4417724609375 -0.1003479003906193 +0.9725 -0.4910888671875 -0.4417724609375 -0.1003479003906193 +0.972625000000000096 -0.490081787109375 -0.440887451171875 -0.1003479003906193 +0.97275 -0.490081787109375 -0.440887451171875 -0.1003479003906193 +0.972875 -0.489013671875 -0.439910888671875 -0.1003479003906193 +0.973 -0.487884521484375 -0.43890380859375 -0.1003479003906193 +0.973125 -0.487884521484375 -0.43890380859375 -0.1003479003906193 +0.973250000000000096 -0.486724853515625 -0.4378662109375 -0.1003479003906193 +0.973375 -0.486724853515625 -0.4378662109375 -0.1003479003906193 +0.9735 -0.485504150390625 -0.436767578125 -0.1003479003906193 +0.973625000000000096 -0.484222412109375 -0.43560791015625 -0.1003479003906193 +0.97375 -0.484222412109375 -0.43560791015625 -0.1003479003906193 +0.973875 -0.48291015625 -0.434417724609375 -0.1003479003906193 +0.974 -0.48291015625 -0.434417724609375 -0.1003479003906193 +0.974125 -0.48150634765625 -0.43316650390625 -0.1003479003906193 +0.974250000000000096 -0.480072021484375 -0.431884765625 -0.1003479003906193 +0.974375 -0.480072021484375 -0.431884765625 -0.1003479003906193 +0.9745 -0.478607177734375 -0.4305419921875 -0.1003479003906193 +0.974625000000000096 -0.478607177734375 -0.4305419921875 -0.1003479003906193 +0.97475 -0.47705078125 -0.429168701171875 -0.1003479003906193 +0.974875 -0.4754638671875 -0.427734375 -0.1003479003906193 +0.975 -0.4754638671875 -0.427734375 -0.1003479003906193 +0.975125 -0.47381591796875 -0.42626953125 -0.1003479003906193 +0.975250000000000096 -0.47381591796875 -0.42626953125 -0.1003479003906193 +0.975375 -0.472137451171875 -0.42474365234375 -0.1003479003906193 +0.9755 -0.470367431640625 -0.42315673828125 -0.1003479003906193 +0.975625000000000096 -0.470367431640625 -0.42315673828125 -0.1003479003906193 +0.97575 -0.46856689453125 -0.421539306640625 -0.1003479003906193 +0.975875 -0.46856689453125 -0.421539306640625 -0.1003479003906193 +0.976 -0.46673583984375 -0.41986083984375 -0.1003479003906193 +0.976125 -0.464813232421875 -0.41815185546875 -0.1003479003906193 +0.976250000000000096 -0.464813232421875 -0.41815185546875 -0.1003479003906193 +0.976375 -0.462890625 -0.416412353515625 -0.1003479003906193 +0.9765 -0.462890625 -0.416412353515625 -0.1003479003906193 +0.976625 -0.46087646484375 -0.41461181640625 -0.1003479003906193 +0.97675 -0.458831787109375 -0.412750244140625 -0.1003479003906193 +0.976875 -0.458831787109375 -0.412750244140625 -0.1003479003906193 +0.977 -0.45672607421875 -0.410858154296875 -0.1003479003906193 +0.977125 -0.45672607421875 -0.410858154296875 -0.1003479003906193 +0.977250000000000096 -0.454559326171875 -0.408905029296875 -0.1003479003906193 +0.977375 -0.452362060546875 -0.406951904296875 -0.1003479003906193 +0.9775 -0.452362060546875 -0.406951904296875 -0.1003479003906193 +0.977625 -0.450103759765625 -0.4049072265625 -0.1003479003906193 +0.97775 -0.450103759765625 -0.4049072265625 -0.1003479003906193 +0.977875 -0.447784423828125 -0.40283203125 -0.1003479003906193 +0.978 -0.4454345703125 -0.400726318359375 -0.1003479003906193 +0.978125 -0.4454345703125 -0.400726318359375 -0.1003479003906193 +0.978250000000000096 -0.44305419921875 -0.3985595703125 -0.1003479003906193 +0.978375 -0.44305419921875 -0.3985595703125 -0.1003479003906193 +0.9785 -0.440582275390625 -0.3963623046875 -0.1003479003906193 +0.978625 -0.438079833984375 -0.39410400390625 -0.1003479003906193 +0.97875 -0.438079833984375 -0.39410400390625 -0.1003479003906193 +0.978875 -0.435546875 -0.391815185546875 -0.1003479003906193 +0.979 -0.435546875 -0.391815185546875 -0.1003479003906193 +0.979125 -0.432952880859375 -0.389495849609375 -0.1003479003906193 +0.979250000000000096 -0.4302978515625 -0.387115478515625 -0.1003479003906193 +0.979375 -0.4302978515625 -0.387115478515625 -0.1003479003906193 +0.9795 -0.4276123046875 -0.38470458984375 -0.1003479003906193 +0.979625 -0.4276123046875 -0.38470458984375 -0.1003479003906193 +0.97975 -0.424896240234375 -0.382232666015625 -0.1003479003906193 +0.979875 -0.422119140625 -0.379730224609375 -0.1003479003906193 +0.98 -0.422119140625 -0.379730224609375 -0.1003479003906193 +0.980125 -0.419281005859375 -0.377197265625 -0.1003479003906193 +0.980250000000000096 -0.419281005859375 -0.377197265625 -0.1003479003906193 +0.980375 -0.416412353515625 -0.374603271484375 -0.1003479003906193 +0.9805 -0.413482666015625 -0.371978759765625 -0.1003479003906193 +0.980625 -0.413482666015625 -0.371978759765625 -0.1003479003906193 +0.98075 -0.4105224609375 -0.369293212890625 -0.1003479003906193 +0.980875 -0.4105224609375 -0.369293212890625 -0.1003479003906193 +0.981 -0.407501220703125 -0.366607666015625 -0.1003479003906193 +0.981125 -0.404449462890625 -0.363861083984375 -0.1003479003906193 +0.981250000000000096 -0.404449462890625 -0.363861083984375 -0.1003479003906193 +0.981375 -0.401336669921875 -0.361053466796875 -0.1003479003906193 +0.9815 -0.401336669921875 -0.361053466796875 -0.1003479003906193 +0.981625 -0.398193359375 -0.35821533203125 -0.1003479003906193 +0.98175 -0.39501953125 -0.355377197265625 -0.1003479003906193 +0.981875 -0.39501953125 -0.355377197265625 -0.1003479003906193 +0.982 -0.39178466796875 -0.352447509765625 -0.1003479003906193 +0.982125 -0.39178466796875 -0.352447509765625 -0.1003479003906193 +0.982250000000000096 -0.388519287109375 -0.349517822265625 -0.1003479003906193 +0.982375 -0.38519287109375 -0.346527099609375 -0.1003479003906193 +0.9825 -0.38519287109375 -0.346527099609375 -0.1003479003906193 +0.982625 -0.3818359375 -0.343505859375 -0.1003479003906193 +0.98275 -0.3818359375 -0.343505859375 -0.1003479003906193 +0.982875 -0.378448486328125 -0.3404541015625 -0.1003479003906193 +0.983 -0.375 -0.33734130859375 -0.1003479003906193 +0.983125 -0.375 -0.33734130859375 -0.1003479003906193 +0.983250000000000096 -0.37152099609375 -0.334228515625 -0.1003479003906193 +0.983375 -0.37152099609375 -0.334228515625 -0.1003479003906193 +0.9835 -0.36798095703125 -0.3310546875 -0.1003479003906193 +0.983625 -0.36444091796875 -0.327850341796875 -0.1003479003906193 +0.98375 -0.36444091796875 -0.327850341796875 -0.1003479003906193 +0.983875 -0.360809326171875 -0.3245849609375 -0.1003479003906193 +0.984 -0.360809326171875 -0.3245849609375 -0.1003479003906193 +0.984125 -0.357177734375 -0.321319580078125 -0.1003479003906193 +0.984250000000000096 -0.353485107421875 -0.318023681640625 -0.1003479003906193 +0.984375 -0.353485107421875 -0.318023681640625 -0.1003479003906193 +0.9845 -0.349761962890625 -0.314666748046875 -0.1003479003906193 +0.984625 -0.349761962890625 -0.314666748046875 -0.1003479003906193 +0.98475 -0.34600830078125 -0.311279296875 -0.1003479003906193 +0.984875000000000096 -0.34222412109375 -0.307861328125 -0.1003479003906193 +0.985 -0.34222412109375 -0.307861328125 -0.1003479003906193 +0.985125 -0.33837890625 -0.304412841796875 -0.1003479003906193 +0.985250000000000096 -0.33837890625 -0.304412841796875 -0.1003479003906193 +0.985375 -0.334503173828125 -0.300933837890625 -0.1003479003906193 +0.9855 -0.330596923828125 -0.29742431640625 -0.1003479003906193 +0.985625 -0.330596923828125 -0.29742431640625 -0.1003479003906193 +0.98575 -0.32666015625 -0.293853759765625 -0.1003479003906193 +0.985875000000000096 -0.32666015625 -0.293853759765625 -0.1003479003906193 +0.986 -0.322662353515625 -0.290283203125 -0.1003479003906193 +0.986125 -0.31866455078125 -0.28668212890625 -0.1003479003906193 +0.986250000000000096 -0.31866455078125 -0.28668212890625 -0.1003479003906193 +0.986375 -0.314605712890625 -0.28302001953125 -0.1003479003906193 +0.9865 -0.314605712890625 -0.28302001953125 -0.1003479003906193 +0.986625 -0.310516357421875 -0.27935791015625 -0.1003479003906193 +0.98675 -0.306396484375 -0.275634765625 -0.1003479003906193 +0.986875000000000096 -0.306396484375 -0.275634765625 -0.1003479003906193 +0.987 -0.30224609375 -0.27191162109375 -0.1003479003906193 +0.987125 -0.30224609375 -0.27191162109375 -0.1003479003906193 +0.987250000000000096 -0.298065185546875 -0.26812744140625 -0.1003479003906193 +0.987375 -0.2938232421875 -0.26434326171875 -0.1003479003906193 +0.9875 -0.2938232421875 -0.26434326171875 -0.1003479003906193 +0.987625 -0.289581298828125 -0.260528564453125 -0.1003479003906193 +0.98775 -0.289581298828125 -0.260528564453125 -0.1003479003906193 +0.987875000000000096 -0.285308837890625 -0.25665283203125 -0.1003479003906193 +0.988 -0.280975341796875 -0.252777099609375 -0.1003479003906193 +0.988125 -0.280975341796875 -0.252777099609375 -0.1003479003906193 +0.988250000000000096 -0.276641845703125 -0.248870849609375 -0.1003479003906193 +0.988375 -0.276641845703125 -0.248870849609375 -0.1003479003906193 +0.9885 -0.27227783203125 -0.24493408203125 -0.1003479003906193 +0.988625 -0.267852783203125 -0.240966796875 -0.1003479003906193 +0.98875 -0.267852783203125 -0.240966796875 -0.1003479003906193 +0.988875000000000096 -0.263427734375 -0.236968994140625 -0.1003479003906193 +0.989 -0.263427734375 -0.236968994140625 -0.1003479003906193 +0.989125 -0.25897216796875 -0.23297119140625 -0.1003479003906193 +0.989250000000000096 -0.25445556640625 -0.228912353515625 -0.1003479003906193 +0.989375 -0.25445556640625 -0.228912353515625 -0.1003479003906193 +0.9895 -0.249969482421875 -0.224853515625 -0.1003479003906193 +0.989625 -0.249969482421875 -0.224853515625 -0.1003479003906193 +0.98975 -0.24542236328125 -0.22076416015625 -0.1003479003906193 +0.989875000000000096 -0.2408447265625 -0.216644287109375 -0.1003479003906193 +0.99 -0.2408447265625 -0.216644287109375 -0.1003479003906193 +0.990125 -0.236236572265625 -0.2125244140625 -0.1003479003906193 +0.990250000000000096 -0.236236572265625 -0.2125244140625 -0.1003479003906193 +0.990375 -0.231597900390625 -0.208343505859375 -0.1003479003906193 +0.9905 -0.226959228515625 -0.20416259765625 -0.1003479003906193 +0.990625 -0.226959228515625 -0.20416259765625 -0.1003479003906193 +0.99075 -0.2222900390625 -0.199951171875 -0.1003479003906193 +0.990875000000000096 -0.2222900390625 -0.199951171875 -0.1003479003906193 +0.991 -0.21759033203125 -0.19573974609375 -0.1003479003906193 +0.991125 -0.212860107421875 -0.19146728515625 -0.1003479003906193 +0.991250000000000096 -0.212860107421875 -0.19146728515625 -0.1003479003906193 +0.991375 -0.208099365234375 -0.187225341796875 -0.1003479003906193 +0.9915 -0.208099365234375 -0.187225341796875 -0.1003479003906193 +0.991625 -0.203338623046875 -0.18292236328125 -0.1003479003906193 +0.99175 -0.19854736328125 -0.178619384765625 -0.1003479003906193 +0.991875000000000096 -0.19854736328125 -0.178619384765625 -0.1003479003906193 +0.992 -0.13616943359375 -0.1937255859375 0.2970092773437556 +0.992125 -0.13616943359375 -0.1937255859375 0.2970092773437556 +0.99225 -0.132781982421875 -0.188873291015625 0.2970092773437556 +0.992375 -0.129364013671875 -0.18402099609375 0.2970092773437556 +0.9925 -0.129364013671875 -0.18402099609375 0.2970092773437556 +0.992625 -0.12591552734375 -0.17913818359375 0.2970092773437556 +0.99275 -0.12591552734375 -0.17913818359375 0.2970092773437556 +0.992875000000000096 -0.122467041015625 -0.17425537109375 0.2970092773437556 +0.993 -0.1190185546875 -0.169342041015625 0.2970092773437556 +0.993125 -0.1190185546875 -0.169342041015625 0.2970092773437556 +0.99325 -0.11553955078125 -0.164398193359375 0.2970092773437556 +0.993375 -0.11553955078125 -0.164398193359375 0.2970092773437556 +0.9935 -0.112091064453125 -0.159454345703125 0.2970092773437556 +0.993625 -0.10858154296875 -0.15447998046875 0.2970092773437556 +0.99375 -0.10858154296875 -0.15447998046875 0.2970092773437556 +0.993875000000000096 -0.105072021484375 -0.14947509765625 0.2970092773437556 +0.994 -0.105072021484375 -0.14947509765625 0.2970092773437556 +0.994125 -0.1015625 -0.14447021484375 0.2970092773437556 +0.99425 -0.0980224609375 -0.13946533203125 0.2970092773437556 +0.994375 -0.0980224609375 -0.13946533203125 0.2970092773437556 +0.9945 -0.094482421875 -0.134429931640625 0.2970092773437556 +0.994625 -0.094482421875 -0.134429931640625 0.2970092773437556 +0.99475 -0.0909423828125 -0.129364013671875 0.2970092773437556 +0.994875000000000096 -0.087371826171875 -0.124298095703125 0.2970092773437556 +0.995 -0.087371826171875 -0.124298095703125 0.2970092773437556 +0.995125 -0.08380126953125 -0.119232177734375 0.2970092773437556 +0.99525 -0.08380126953125 -0.119232177734375 0.2970092773437556 +0.995375 -0.080230712890625 -0.1141357421875 0.2970092773437556 +0.9955 -0.076629638671875 -0.109039306640625 0.2970092773437556 +0.995625 -0.076629638671875 -0.109039306640625 0.2970092773437556 +0.99575 -0.07305908203125 -0.103912353515625 0.2970092773437556 +0.995875000000000096 -0.07305908203125 -0.103912353515625 0.2970092773437556 +0.996 -0.0694580078125 -0.098785400390625 0.2970092773437556 +0.996125 -0.065826416015625 -0.093658447265625 0.2970092773437556 +0.99625 -0.065826416015625 -0.093658447265625 0.2970092773437556 +0.996375 -0.062225341796875 -0.0885009765625 0.2970092773437556 +0.9965 -0.062225341796875 -0.0885009765625 0.2970092773437556 +0.996625 -0.05859375 -0.083343505859375 0.2970092773437556 +0.99675 -0.054962158203125 -0.07818603515625 0.2970092773437556 +0.996875000000000096 -0.054962158203125 -0.07818603515625 0.2970092773437556 +0.997 -0.05133056640625 -0.072998046875 0.2970092773437556 +0.997125 -0.05133056640625 -0.072998046875 0.2970092773437556 +0.99725 -0.04766845703125 -0.06781005859375 0.2970092773437556 +0.997375 -0.044036865234375 -0.0626220703125 0.2970092773437556 +0.9975 -0.044036865234375 -0.0626220703125 0.2970092773437556 +0.997625 -0.040374755859375 -0.05743408203125 0.2970092773437556 +0.99775 -0.040374755859375 -0.05743408203125 0.2970092773437556 +0.997875000000000096 -0.036712646484375 -0.05224609375 0.2970092773437556 +0.998 -0.033050537109375 -0.047027587890625 0.2970092773437556 +0.998125 -0.033050537109375 -0.047027587890625 0.2970092773437556 +0.99825 -0.029388427734375 -0.04180908203125 0.2970092773437556 +0.998375 -0.029388427734375 -0.04180908203125 0.2970092773437556 +0.9985 -0.025726318359375 -0.036590576171875 0.2970092773437556 +0.998625 -0.02203369140625 -0.0313720703125 0.2970092773437556 +0.99875 -0.02203369140625 -0.0313720703125 0.2970092773437556 +0.998875000000000096 -0.01837158203125 -0.026123046875 0.2970092773437556 +0.999 -0.01837158203125 -0.026123046875 0.2970092773437556 +0.999125 -0.01470947265625 -0.020904541015625 0.2970092773437556 +0.99925 -0.011016845703125 -0.01568603515625 0.2970092773437556 +0.999375 -0.011016845703125 -0.01568603515625 0.2970092773437556 +0.9995 -0.007354736328125 -0.01043701171875 0.2970092773437556 +0.999625 -0.007354736328125 -0.01043701171875 0.2970092773437556 +0.99975 -0.003662109375 -0.005218505859375 0.2970092773437556 +0.999875000000000096 0.0 0.0 0.2970092773437556 +1.0 0.0 0.0 0.2970092773437556 +1.000125 0.003662109375 0.005218505859375 0.2970092773437556 +1.00025 0.003662109375 0.005218505859375 0.2970092773437556 +1.000375 0.007354736328125 0.01043701171875 0.2970092773437556 +1.0005 0.011016845703125 0.01568603515625 0.2970092773437556 +1.000625 0.011016845703125 0.01568603515625 0.2970092773437556 +1.00075 0.01470947265625 0.020904541015625 0.2970092773437556 +1.000875 0.01470947265625 0.020904541015625 0.2970092773437556 +1.0010000000000002 0.01837158203125 0.026123046875 0.2970092773437556 +1.001125 0.02203369140625 0.0313720703125 0.2970092773437556 +1.00125 0.02203369140625 0.0313720703125 0.2970092773437556 +1.0013750000000002 0.025726318359375 0.036590576171875 0.2970092773437556 +1.0015 0.025726318359375 0.036590576171875 0.2970092773437556 +1.001625 0.029388427734375 0.04180908203125 0.2970092773437556 +1.00175 0.033050537109375 0.047027587890625 0.2970092773437556 +1.001875 0.033050537109375 0.047027587890625 0.2970092773437556 +1.002 0.036712646484375 0.05224609375 0.2970092773437556 +1.002125 0.036712646484375 0.05224609375 0.2970092773437556 +1.00225 0.040374755859375 0.05743408203125 0.2970092773437556 +1.002375 0.044036865234375 0.0626220703125 0.2970092773437556 +1.0025 0.044036865234375 0.0626220703125 0.2970092773437556 +1.002625 0.04766845703125 0.06781005859375 0.2970092773437556 +1.00275 0.04766845703125 0.06781005859375 0.2970092773437556 +1.002875 0.05133056640625 0.072998046875 0.2970092773437556 +1.0030000000000002 0.054962158203125 0.07818603515625 0.2970092773437556 +1.003125 0.054962158203125 0.07818603515625 0.2970092773437556 +1.00325 0.05859375 0.083343505859375 0.2970092773437556 +1.0033750000000002 0.05859375 0.083343505859375 0.2970092773437556 +1.0035 0.062225341796875 0.0885009765625 0.2970092773437556 +1.003625 0.065826416015625 0.093658447265625 0.2970092773437556 +1.00375 0.065826416015625 0.093658447265625 0.2970092773437556 +1.003875 0.0694580078125 0.098785400390625 0.2970092773437556 +1.004 0.0694580078125 0.098785400390625 0.2970092773437556 +1.004125 0.07305908203125 0.103912353515625 0.2970092773437556 +1.00425 0.076629638671875 0.109039306640625 0.2970092773437556 +1.004375 0.076629638671875 0.109039306640625 0.2970092773437556 +1.0045 0.080230712890625 0.1141357421875 0.2970092773437556 +1.004625 0.080230712890625 0.1141357421875 0.2970092773437556 +1.00475 0.08380126953125 0.119232177734375 0.2970092773437556 +1.004875 0.087371826171875 0.124298095703125 0.2970092773437556 +1.0050000000000002 0.087371826171875 0.124298095703125 0.2970092773437556 +1.005125 0.0909423828125 0.129364013671875 0.2970092773437556 +1.00525 0.0909423828125 0.129364013671875 0.2970092773437556 +1.0053750000000002 0.094482421875 0.134429931640625 0.2970092773437556 +1.0055 0.0980224609375 0.13946533203125 0.2970092773437556 +1.005625 0.0980224609375 0.13946533203125 0.2970092773437556 +1.00575 0.1015625 0.14447021484375 0.2970092773437556 +1.005875 0.1015625 0.14447021484375 0.2970092773437556 +1.006 0.105072021484375 0.14947509765625 0.2970092773437556 +1.006125 0.10858154296875 0.15447998046875 0.2970092773437556 +1.00625 0.10858154296875 0.15447998046875 0.2970092773437556 +1.006375 0.112091064453125 0.159454345703125 0.2970092773437556 +1.0065 0.112091064453125 0.159454345703125 0.2970092773437556 +1.006625 0.11553955078125 0.164398193359375 0.2970092773437556 +1.00675 0.1190185546875 0.169342041015625 0.2970092773437556 +1.006875 0.1190185546875 0.169342041015625 0.2970092773437556 +1.0070000000000002 0.122467041015625 0.17425537109375 0.2970092773437556 +1.007125 0.122467041015625 0.17425537109375 0.2970092773437556 +1.00725 0.12591552734375 0.17913818359375 0.2970092773437556 +1.0073750000000002 0.129364013671875 0.18402099609375 0.2970092773437556 +1.0075 0.129364013671875 0.18402099609375 0.2970092773437556 +1.007625 0.132781982421875 0.188873291015625 0.2970092773437556 +1.00775 0.132781982421875 0.188873291015625 0.2970092773437556 +1.007875 0.13616943359375 0.1937255859375 0.2970092773437556 +1.008 0.139556884765625 0.19854736328125 0.2970092773437556 +1.008125 0.139556884765625 0.19854736328125 0.2970092773437556 +1.00825 0.142913818359375 0.203338623046875 0.2970092773437556 +1.008375 0.142913818359375 0.203338623046875 0.2970092773437556 +1.0085 0.146270751953125 0.208099365234375 0.2970092773437556 +1.008625 0.149627685546875 0.212860107421875 0.2970092773437556 +1.00875 0.149627685546875 0.212860107421875 0.2970092773437556 +1.008875 0.1529541015625 0.21759033203125 0.2970092773437556 +1.0090000000000002 0.1529541015625 0.21759033203125 0.2970092773437556 +1.009125 0.15625 0.2222900390625 0.2970092773437556 +1.00925 0.159515380859375 0.226959228515625 0.2970092773437556 +1.009375 0.159515380859375 0.226959228515625 0.2970092773437556 +1.0095 0.162811279296875 0.231597900390625 0.2970092773437556 +1.009625 0.162811279296875 0.231597900390625 0.2970092773437556 +1.00975 0.166046142578125 0.236236572265625 0.2970092773437556 +1.009875 0.169281005859375 0.2408447265625 0.2970092773437556 +1.01 0.169281005859375 0.2408447265625 0.2970092773437556 +1.010125 0.172515869140625 0.24542236328125 0.2970092773437556 +1.01025 0.172515869140625 0.24542236328125 0.2970092773437556 +1.010375 0.175689697265625 0.249969482421875 0.2970092773437556 +1.0105 0.178863525390625 0.25445556640625 0.2970092773437556 +1.010625 0.178863525390625 0.25445556640625 0.2970092773437556 +1.01075 0.182037353515625 0.25897216796875 0.2970092773437556 +1.010875 0.182037353515625 0.25897216796875 0.2970092773437556 +1.0110000000000002 0.1851806640625 0.263427734375 0.2970092773437556 +1.011125 0.18829345703125 0.267852783203125 0.2970092773437556 +1.01125 0.18829345703125 0.267852783203125 0.2970092773437556 +1.011375 0.19140625 0.27227783203125 0.2970092773437556 +1.0115 0.19140625 0.27227783203125 0.2970092773437556 +1.011625 0.1944580078125 0.276641845703125 0.2970092773437556 +1.01175 0.197509765625 0.280975341796875 0.2970092773437556 +1.011875 0.197509765625 0.280975341796875 0.2970092773437556 +1.012 0.2005615234375 0.285308837890625 0.2970092773437556 +1.012125 0.2005615234375 0.285308837890625 0.2970092773437556 +1.01225 0.20355224609375 0.289581298828125 0.2970092773437556 +1.012375 0.20654296875 0.2938232421875 0.2970092773437556 +1.0125 0.20654296875 0.2938232421875 0.2970092773437556 +1.012625 0.20953369140625 0.298065185546875 0.2970092773437556 +1.01275 0.20953369140625 0.298065185546875 0.2970092773437556 +1.012875 0.21246337890625 0.30224609375 0.2970092773437556 +1.0130000000000002 0.21539306640625 0.306396484375 0.2970092773437556 +1.013125 0.21539306640625 0.306396484375 0.2970092773437556 +1.01325 0.218292236328125 0.310516357421875 0.2970092773437556 +1.013375 0.218292236328125 0.310516357421875 0.2970092773437556 +1.0135 0.221160888671875 0.314605712890625 0.2970092773437556 +1.013625 0.2239990234375 0.31866455078125 0.2970092773437556 +1.01375 0.2239990234375 0.31866455078125 0.2970092773437556 +1.013875 0.226806640625 0.322662353515625 0.2970092773437556 +1.014 0.226806640625 0.322662353515625 0.2970092773437556 +1.014125 0.2296142578125 0.32666015625 0.2970092773437556 +1.01425 0.232391357421875 0.330596923828125 0.2970092773437556 +1.014375 0.232391357421875 0.330596923828125 0.2970092773437556 +1.0145 0.235137939453125 0.334503173828125 0.2970092773437556 +1.014625 0.235137939453125 0.334503173828125 0.2970092773437556 +1.01475 0.23785400390625 0.33837890625 0.2970092773437556 +1.014875 0.240570068359375 0.34222412109375 0.2970092773437556 +1.0150000000000002 0.240570068359375 0.34222412109375 0.2970092773437556 +1.015125 0.24322509765625 0.34600830078125 0.2970092773437556 +1.01525 0.24322509765625 0.34600830078125 0.2970092773437556 +1.015375 0.245880126953125 0.349761962890625 0.2970092773437556 +1.0155 0.24847412109375 0.353485107421875 0.2970092773437556 +1.015625 0.24847412109375 0.353485107421875 0.2970092773437556 +1.01575 0.251068115234375 0.357177734375 0.2970092773437556 +1.015875 0.251068115234375 0.357177734375 0.2970092773437556 +1.016 0.253631591796875 0.360809326171875 0.2970092773437556 +1.016125 0.25616455078125 0.36444091796875 0.2970092773437556 +1.01625 0.25616455078125 0.36444091796875 0.2970092773437556 +1.016375 0.2586669921875 0.36798095703125 0.2970092773437556 +1.0165 0.2586669921875 0.36798095703125 0.2970092773437556 +1.0166250000000002 0.261138916015625 0.37152099609375 0.2970092773437556 +1.01675 0.26361083984375 0.375 0.2970092773437556 +1.016875 0.26361083984375 0.375 0.2970092773437556 +1.0170000000000002 0.266021728515625 0.378448486328125 0.2970092773437556 +1.017125 0.266021728515625 0.378448486328125 0.2970092773437556 +1.01725 0.268402099609375 0.3818359375 0.2970092773437556 +1.017375 0.270782470703125 0.38519287109375 0.2970092773437556 +1.0175 0.270782470703125 0.38519287109375 0.2970092773437556 +1.017625 0.273101806640625 0.388519287109375 0.2970092773437556 +1.01775 0.273101806640625 0.388519287109375 0.2970092773437556 +1.017875 0.275421142578125 0.39178466796875 0.2970092773437556 +1.018 0.277679443359375 0.39501953125 0.2970092773437556 +1.018125 0.277679443359375 0.39501953125 0.2970092773437556 +1.01825 0.2799072265625 0.398193359375 0.2970092773437556 +1.018375 0.2799072265625 0.398193359375 0.2970092773437556 +1.0185 0.282135009765625 0.401336669921875 0.2970092773437556 +1.0186250000000002 0.2843017578125 0.404449462890625 0.2970092773437556 +1.01875 0.2843017578125 0.404449462890625 0.2970092773437556 +1.018875 0.286468505859375 0.407501220703125 0.2970092773437556 +1.0190000000000002 0.286468505859375 0.407501220703125 0.2970092773437556 +1.019125 0.28857421875 0.4105224609375 0.2970092773437556 +1.01925 0.2906494140625 0.413482666015625 0.2970092773437556 +1.019375 0.2906494140625 0.413482666015625 0.2970092773437556 +1.0195 0.292694091796875 0.416412353515625 0.2970092773437556 +1.019625 0.292694091796875 0.416412353515625 0.2970092773437556 +1.01975 0.29473876953125 0.419281005859375 0.2970092773437556 +1.019875 0.296722412109375 0.422119140625 0.2970092773437556 +1.02 0.296722412109375 0.422119140625 0.2970092773437556 +1.020125 0.298675537109375 0.424896240234375 0.2970092773437556 +1.02025 0.298675537109375 0.424896240234375 0.2970092773437556 +1.020375 0.30059814453125 0.4276123046875 0.2970092773437556 +1.0205 0.302490234375 0.4302978515625 0.2970092773437556 +1.0206250000000002 0.302490234375 0.4302978515625 0.2970092773437556 +1.02075 0.304351806640625 0.432952880859375 0.2970092773437556 +1.020875 0.304351806640625 0.432952880859375 0.2970092773437556 +1.0210000000000002 0.306182861328125 0.435546875 0.2970092773437556 +1.021125 0.307952880859375 0.438079833984375 0.2970092773437556 +1.02125 0.307952880859375 0.438079833984375 0.2970092773437556 +1.021375 0.3096923828125 0.440582275390625 0.2970092773437556 +1.0215 0.3096923828125 0.440582275390625 0.2970092773437556 +1.021625 0.311431884765625 0.44305419921875 0.2970092773437556 +1.02175 0.3131103515625 0.4454345703125 0.2970092773437556 +1.021875 0.3131103515625 0.4454345703125 0.2970092773437556 +1.022 0.31475830078125 0.447784423828125 0.2970092773437556 +1.022125 0.31475830078125 0.447784423828125 0.2970092773437556 +1.02225 0.316375732421875 0.450103759765625 0.2970092773437556 +1.022375 0.317962646484375 0.452362060546875 0.2970092773437556 +1.0225 0.317962646484375 0.452362060546875 0.2970092773437556 +1.0226250000000002 0.31951904296875 0.454559326171875 0.2970092773437556 +1.02275 0.31951904296875 0.454559326171875 0.2970092773437556 +1.022875 0.321044921875 0.45672607421875 0.2970092773437556 +1.0230000000000002 0.322509765625 0.458831787109375 0.2970092773437556 +1.023125 0.322509765625 0.458831787109375 0.2970092773437556 +1.02325 0.323974609375 0.46087646484375 0.2970092773437556 +1.023375 0.323974609375 0.46087646484375 0.2970092773437556 +1.0235 0.32537841796875 0.462890625 0.2970092773437556 +1.023625 0.326751708984375 0.464813232421875 0.2970092773437556 +1.02375 0.326751708984375 0.464813232421875 0.2970092773437556 +1.023875 0.328094482421875 0.46673583984375 0.2970092773437556 +1.024 0.164703369140625 0.46673583984375 0.6470092773437545 +1.024125 0.165374755859375 0.46856689453125 0.6470092773437545 +1.02425 0.165985107421875 0.470367431640625 0.6470092773437545 +1.024375 0.165985107421875 0.470367431640625 0.6470092773437545 +1.0245 0.1666259765625 0.472137451171875 0.6470092773437545 +1.0246250000000002 0.1666259765625 0.472137451171875 0.6470092773437545 +1.02475 0.167205810546875 0.47381591796875 0.6470092773437545 +1.024875 0.16778564453125 0.4754638671875 0.6470092773437545 +1.025 0.16778564453125 0.4754638671875 0.6470092773437545 +1.025125 0.168365478515625 0.47705078125 0.6470092773437545 +1.02525 0.168365478515625 0.47705078125 0.6470092773437545 +1.025375 0.16888427734375 0.478607177734375 0.6470092773437545 +1.0255 0.16943359375 0.480072021484375 0.6470092773437545 +1.025625 0.16943359375 0.480072021484375 0.6470092773437545 +1.02575 0.169921875 0.48150634765625 0.6470092773437545 +1.025875 0.169921875 0.48150634765625 0.6470092773437545 +1.026 0.17041015625 0.48291015625 0.6470092773437545 +1.026125 0.1708984375 0.484222412109375 0.6470092773437545 +1.02625 0.1708984375 0.484222412109375 0.6470092773437545 +1.026375 0.17132568359375 0.485504150390625 0.6470092773437545 +1.0265 0.17132568359375 0.485504150390625 0.6470092773437545 +1.0266250000000002 0.171783447265625 0.486724853515625 0.6470092773437545 +1.02675 0.17218017578125 0.487884521484375 0.6470092773437545 +1.026875 0.17218017578125 0.487884521484375 0.6470092773437545 +1.027 0.172576904296875 0.489013671875 0.6470092773437545 +1.027125 0.172576904296875 0.489013671875 0.6470092773437545 +1.02725 0.172943115234375 0.490081787109375 0.6470092773437545 +1.027375 0.173309326171875 0.4910888671875 0.6470092773437545 +1.0275 0.173309326171875 0.4910888671875 0.6470092773437545 +1.027625 0.17364501953125 0.492034912109375 0.6470092773437545 +1.02775 0.17364501953125 0.492034912109375 0.6470092773437545 +1.027875 0.1739501953125 0.492950439453125 0.6470092773437545 +1.028 0.17425537109375 0.4937744140625 0.6470092773437545 +1.028125 0.17425537109375 0.4937744140625 0.6470092773437545 +1.02825 0.174530029296875 0.49456787109375 0.6470092773437545 +1.028375 0.174530029296875 0.49456787109375 0.6470092773437545 +1.0285 0.1748046875 0.49530029296875 0.6470092773437545 +1.0286250000000002 0.175048828125 0.496002197265625 0.6470092773437545 +1.02875 0.175048828125 0.496002197265625 0.6470092773437545 +1.028875 0.175262451171875 0.496612548828125 0.6470092773437545 +1.029 0.175262451171875 0.496612548828125 0.6470092773437545 +1.029125 0.17547607421875 0.4971923828125 0.6470092773437545 +1.02925 0.1756591796875 0.497711181640625 0.6470092773437545 +1.029375 0.1756591796875 0.497711181640625 0.6470092773437545 +1.0295 0.175811767578125 0.498199462890625 0.6470092773437545 +1.029625 0.175811767578125 0.498199462890625 0.6470092773437545 +1.02975 0.17596435546875 0.49859619140625 0.6470092773437545 +1.029875 0.17608642578125 0.49896240234375 0.6470092773437545 +1.03 0.17608642578125 0.49896240234375 0.6470092773437545 +1.030125 0.176177978515625 0.499267578125 0.6470092773437545 +1.03025 0.176177978515625 0.499267578125 0.6470092773437545 +1.030375 0.17626953125 0.49951171875 0.6470092773437545 +1.0305 0.17633056640625 0.49969482421875 0.6470092773437545 +1.0306250000000002 0.17633056640625 0.49969482421875 0.6470092773437545 +1.03075 0.1763916015625 0.49981689453125 0.6470092773437545 +1.030875 0.1763916015625 0.49981689453125 0.6470092773437545 +1.031 0.176422119140625 0.499908447265625 0.6470092773437545 +1.031125 0.176422119140625 0.49993896484375 0.6470092773437545 +1.03125 0.176422119140625 0.49993896484375 0.6470092773437545 +1.031375 0.176422119140625 0.499908447265625 0.6470092773437545 +1.0315 0.176422119140625 0.499908447265625 0.6470092773437545 +1.031625 0.1763916015625 0.49981689453125 0.6470092773437545 +1.03175 0.17633056640625 0.49969482421875 0.6470092773437545 +1.031875 0.17633056640625 0.49969482421875 0.6470092773437545 +1.032 0.17626953125 0.49951171875 0.6470092773437545 +1.032125 0.17626953125 0.49951171875 0.6470092773437545 +1.0322500000000002 0.176177978515625 0.499267578125 0.6470092773437545 +1.032375 0.17608642578125 0.49896240234375 0.6470092773437545 +1.0325 0.17608642578125 0.49896240234375 0.6470092773437545 +1.0326250000000002 0.17596435546875 0.49859619140625 0.6470092773437545 +1.03275 0.17596435546875 0.49859619140625 0.6470092773437545 +1.032875 0.175811767578125 0.498199462890625 0.6470092773437545 +1.033 0.1756591796875 0.497711181640625 0.6470092773437545 +1.033125 0.1756591796875 0.497711181640625 0.6470092773437545 +1.03325 0.17547607421875 0.4971923828125 0.6470092773437545 +1.033375 0.17547607421875 0.4971923828125 0.6470092773437545 +1.0335 0.175262451171875 0.496612548828125 0.6470092773437545 +1.033625 0.175048828125 0.496002197265625 0.6470092773437545 +1.03375 0.175048828125 0.496002197265625 0.6470092773437545 +1.033875 0.1748046875 0.49530029296875 0.6470092773437545 +1.034 0.1748046875 0.49530029296875 0.6470092773437545 +1.034125 0.174530029296875 0.49456787109375 0.6470092773437545 +1.0342500000000002 0.17425537109375 0.4937744140625 0.6470092773437545 +1.034375 0.17425537109375 0.4937744140625 0.6470092773437545 +1.0345 0.1739501953125 0.492950439453125 0.6470092773437545 +1.0346250000000002 0.1739501953125 0.492950439453125 0.6470092773437545 +1.03475 0.17364501953125 0.492034912109375 0.6470092773437545 +1.034875 0.173309326171875 0.4910888671875 0.6470092773437545 +1.035 0.173309326171875 0.4910888671875 0.6470092773437545 +1.035125 0.172943115234375 0.490081787109375 0.6470092773437545 +1.03525 0.172943115234375 0.490081787109375 0.6470092773437545 +1.035375 0.172576904296875 0.489013671875 0.6470092773437545 +1.0355 0.17218017578125 0.487884521484375 0.6470092773437545 +1.035625 0.17218017578125 0.487884521484375 0.6470092773437545 +1.03575 0.171783447265625 0.486724853515625 0.6470092773437545 +1.035875 0.171783447265625 0.486724853515625 0.6470092773437545 +1.036 0.17132568359375 0.485504150390625 0.6470092773437545 +1.036125 0.1708984375 0.484222412109375 0.6470092773437545 +1.0362500000000002 0.1708984375 0.484222412109375 0.6470092773437545 +1.036375 0.17041015625 0.48291015625 0.6470092773437545 +1.0365 0.17041015625 0.48291015625 0.6470092773437545 +1.0366250000000002 0.169921875 0.48150634765625 0.6470092773437545 +1.03675 0.16943359375 0.480072021484375 0.6470092773437545 +1.036875 0.16943359375 0.480072021484375 0.6470092773437545 +1.037 0.16888427734375 0.478607177734375 0.6470092773437545 +1.037125 0.16888427734375 0.478607177734375 0.6470092773437545 +1.03725 0.168365478515625 0.47705078125 0.6470092773437545 +1.037375 0.16778564453125 0.4754638671875 0.6470092773437545 +1.0375 0.16778564453125 0.4754638671875 0.6470092773437545 +1.037625 0.167205810546875 0.47381591796875 0.6470092773437545 +1.03775 0.167205810546875 0.47381591796875 0.6470092773437545 +1.037875 0.1666259765625 0.472137451171875 0.6470092773437545 +1.038 0.165985107421875 0.470367431640625 0.6470092773437545 +1.038125 0.165985107421875 0.470367431640625 0.6470092773437545 +1.0382500000000002 0.165374755859375 0.46856689453125 0.6470092773437545 +1.038375 0.165374755859375 0.46856689453125 0.6470092773437545 +1.0385 0.164703369140625 0.46673583984375 0.6470092773437545 +1.0386250000000002 0.164031982421875 0.464813232421875 0.6470092773437545 +1.03875 0.164031982421875 0.464813232421875 0.6470092773437545 +1.038875 0.163360595703125 0.462890625 0.6470092773437545 +1.039 0.163360595703125 0.462890625 0.6470092773437545 +1.039125 0.162628173828125 0.46087646484375 0.6470092773437545 +1.03925 0.16192626953125 0.458831787109375 0.6470092773437545 +1.039375 0.16192626953125 0.458831787109375 0.6470092773437545 +1.0395 0.161163330078125 0.45672607421875 0.6470092773437545 +1.039625 0.161163330078125 0.45672607421875 0.6470092773437545 +1.03975 0.160400390625 0.454559326171875 0.6470092773437545 +1.039875 0.159637451171875 0.452362060546875 0.6470092773437545 +1.04 0.159637451171875 0.452362060546875 0.6470092773437545 +1.040125 0.158843994140625 0.450103759765625 0.6470092773437545 +1.0402500000000002 0.158843994140625 0.450103759765625 0.6470092773437545 +1.040375 0.15802001953125 0.447784423828125 0.6470092773437545 +1.0405 0.157196044921875 0.4454345703125 0.6470092773437545 +1.040625 0.157196044921875 0.4454345703125 0.6470092773437545 +1.04075 0.156341552734375 0.44305419921875 0.6470092773437545 +1.040875 0.156341552734375 0.44305419921875 0.6470092773437545 +1.041 0.155487060546875 0.440582275390625 0.6470092773437545 +1.041125 0.15460205078125 0.438079833984375 0.6470092773437545 +1.04125 0.15460205078125 0.438079833984375 0.6470092773437545 +1.041375 0.153717041015625 0.435546875 0.6470092773437545 +1.0415 0.153717041015625 0.435546875 0.6470092773437545 +1.041625 0.152801513671875 0.432952880859375 0.6470092773437545 +1.04175 0.15185546875 0.4302978515625 0.6470092773437545 +1.041875 0.15185546875 0.4302978515625 0.6470092773437545 +1.042 0.150909423828125 0.4276123046875 0.6470092773437545 +1.042125 0.150909423828125 0.4276123046875 0.6470092773437545 +1.0422500000000002 0.149932861328125 0.424896240234375 0.6470092773437545 +1.042375 0.148956298828125 0.422119140625 0.6470092773437545 +1.0425 0.148956298828125 0.422119140625 0.6470092773437545 +1.042625 0.14794921875 0.419281005859375 0.6470092773437545 +1.04275 0.14794921875 0.419281005859375 0.6470092773437545 +1.042875 0.146942138671875 0.416412353515625 0.6470092773437545 +1.043 0.145904541015625 0.413482666015625 0.6470092773437545 +1.043125 0.145904541015625 0.413482666015625 0.6470092773437545 +1.04325 0.144866943359375 0.4105224609375 0.6470092773437545 +1.043375 0.144866943359375 0.4105224609375 0.6470092773437545 +1.0435 0.143798828125 0.407501220703125 0.6470092773437545 +1.043625 0.142730712890625 0.404449462890625 0.6470092773437545 +1.04375 0.142730712890625 0.404449462890625 0.6470092773437545 +1.043875 0.141632080078125 0.401336669921875 0.6470092773437545 +1.044 0.141632080078125 0.401336669921875 0.6470092773437545 +1.044125 0.140533447265625 0.398193359375 0.6470092773437545 +1.0442500000000002 0.139404296875 0.39501953125 0.6470092773437545 +1.044375 0.139404296875 0.39501953125 0.6470092773437545 +1.0445 0.138275146484375 0.39178466796875 0.6470092773437545 +1.044625 0.138275146484375 0.39178466796875 0.6470092773437545 +1.04475 0.137115478515625 0.388519287109375 0.6470092773437545 +1.044875 0.13592529296875 0.38519287109375 0.6470092773437545 +1.045 0.13592529296875 0.38519287109375 0.6470092773437545 +1.045125 0.134765625 0.3818359375 0.6470092773437545 +1.04525 0.134765625 0.3818359375 0.6470092773437545 +1.045375 0.133544921875 0.378448486328125 0.6470092773437545 +1.0455 0.13232421875 0.375 0.6470092773437545 +1.045625 0.13232421875 0.375 0.6470092773437545 +1.04575 0.131103515625 0.37152099609375 0.6470092773437545 +1.045875 0.131103515625 0.37152099609375 0.6470092773437545 +1.046 0.129852294921875 0.36798095703125 0.6470092773437545 +1.046125 0.12860107421875 0.36444091796875 0.6470092773437545 +1.0462500000000002 0.12860107421875 0.36444091796875 0.6470092773437545 +1.046375 0.1273193359375 0.360809326171875 0.6470092773437545 +1.0465 0.1273193359375 0.360809326171875 0.6470092773437545 +1.046625 0.12603759765625 0.357177734375 0.6470092773437545 +1.04675 0.124755859375 0.353485107421875 0.6470092773437545 +1.046875 0.124755859375 0.353485107421875 0.6470092773437545 +1.047 0.123443603515625 0.349761962890625 0.6470092773437545 +1.047125 0.123443603515625 0.349761962890625 0.6470092773437545 +1.04725 0.122100830078125 0.34600830078125 0.6470092773437545 +1.047375 0.120758056640625 0.34222412109375 0.6470092773437545 +1.0475 0.120758056640625 0.34222412109375 0.6470092773437545 +1.047625 0.119415283203125 0.33837890625 0.6470092773437545 +1.04775 0.119415283203125 0.33837890625 0.6470092773437545 +1.0478750000000002 0.1180419921875 0.334503173828125 0.6470092773437545 +1.048 0.116668701171875 0.330596923828125 0.6470092773437545 +1.048125 0.116668701171875 0.330596923828125 0.6470092773437545 +1.0482500000000002 0.115264892578125 0.32666015625 0.6470092773437545 +1.048375 0.115264892578125 0.32666015625 0.6470092773437545 +1.0485 0.113861083984375 0.322662353515625 0.6470092773437545 +1.048625 0.112457275390625 0.31866455078125 0.6470092773437545 +1.04875 0.112457275390625 0.31866455078125 0.6470092773437545 +1.048875 0.11102294921875 0.314605712890625 0.6470092773437545 +1.049 0.11102294921875 0.314605712890625 0.6470092773437545 +1.049125 0.109588623046875 0.310516357421875 0.6470092773437545 +1.04925 0.108123779296875 0.306396484375 0.6470092773437545 +1.049375 0.108123779296875 0.306396484375 0.6470092773437545 +1.0495 0.106658935546875 0.30224609375 0.6470092773437545 +1.049625 0.106658935546875 0.30224609375 0.6470092773437545 +1.04975 0.105194091796875 0.298065185546875 0.6470092773437545 +1.0498750000000002 0.10369873046875 0.2938232421875 0.6470092773437545 +1.05 0.10369873046875 0.2938232421875 0.6470092773437545 +1.050125 0.102203369140625 0.289581298828125 0.6470092773437545 +1.0502500000000002 0.102203369140625 0.289581298828125 0.6470092773437545 +1.050375 0.100677490234375 0.285308837890625 0.6470092773437545 +1.0505 0.099151611328125 0.280975341796875 0.6470092773437545 +1.050625 0.099151611328125 0.280975341796875 0.6470092773437545 +1.05075 0.097625732421875 0.276641845703125 0.6470092773437545 +1.050875 0.097625732421875 0.276641845703125 0.6470092773437545 +1.051 0.0960693359375 0.27227783203125 0.6470092773437545 +1.051125 0.094512939453125 0.267852783203125 0.6470092773437545 +1.05125 0.094512939453125 0.267852783203125 0.6470092773437545 +1.051375 0.09295654296875 0.263427734375 0.6470092773437545 +1.0515 0.09295654296875 0.263427734375 0.6470092773437545 +1.051625 0.091400146484375 0.25897216796875 0.6470092773437545 +1.05175 0.089813232421875 0.25445556640625 0.6470092773437545 +1.0518750000000002 0.089813232421875 0.25445556640625 0.6470092773437545 +1.052 0.08819580078125 0.249969482421875 0.6470092773437545 +1.052125 0.08819580078125 0.249969482421875 0.6470092773437545 +1.0522500000000002 0.08660888671875 0.24542236328125 0.6470092773437545 +1.052375 0.084991455078125 0.2408447265625 0.6470092773437545 +1.0525 0.084991455078125 0.2408447265625 0.6470092773437545 +1.052625 0.0833740234375 0.236236572265625 0.6470092773437545 +1.05275 0.0833740234375 0.236236572265625 0.6470092773437545 +1.052875 0.08172607421875 0.231597900390625 0.6470092773437545 +1.053 0.080078125 0.226959228515625 0.6470092773437545 +1.053125 0.080078125 0.226959228515625 0.6470092773437545 +1.05325 0.07843017578125 0.2222900390625 0.6470092773437545 +1.053375 0.07843017578125 0.2222900390625 0.6470092773437545 +1.0535 0.0767822265625 0.21759033203125 0.6470092773437545 +1.053625 0.075103759765625 0.212860107421875 0.6470092773437545 +1.05375 0.075103759765625 0.212860107421875 0.6470092773437545 +1.0538750000000002 0.07342529296875 0.208099365234375 0.6470092773437545 +1.054 0.07342529296875 0.208099365234375 0.6470092773437545 +1.054125 0.071746826171875 0.203338623046875 0.6470092773437545 +1.0542500000000002 0.070068359375 0.19854736328125 0.6470092773437545 +1.054375 0.070068359375 0.19854736328125 0.6470092773437545 +1.0545 0.068359375 0.1937255859375 0.6470092773437545 +1.054625 0.068359375 0.1937255859375 0.6470092773437545 +1.05475 0.066650390625 0.188873291015625 0.6470092773437545 +1.054875 0.06494140625 0.18402099609375 0.6470092773437545 +1.055 0.06494140625 0.18402099609375 0.6470092773437545 +1.055125 0.063201904296875 0.17913818359375 0.6470092773437545 +1.05525 0.063201904296875 0.17913818359375 0.6470092773437545 +1.055375 0.061492919921875 0.17425537109375 0.6470092773437545 +1.0555 0.05975341796875 0.169342041015625 0.6470092773437545 +1.055625 0.05975341796875 0.169342041015625 0.6470092773437545 +1.05575 0.058013916015625 0.164398193359375 0.6470092773437545 +1.0558750000000002 0.058013916015625 0.164398193359375 0.6470092773437545 +1.056 0.01690673828125 0.159454345703125 0.8937805175781277 +1.056125 0.016387939453125 0.15447998046875 0.8937805175781277 +1.05625 0.016387939453125 0.15447998046875 0.8937805175781277 +1.056375 0.015838623046875 0.14947509765625 0.8937805175781277 +1.0565 0.015838623046875 0.14947509765625 0.8937805175781277 +1.056625 0.01531982421875 0.14447021484375 0.8937805175781277 +1.05675 0.014801025390625 0.13946533203125 0.8937805175781277 +1.056875 0.014801025390625 0.13946533203125 0.8937805175781277 +1.057 0.014251708984375 0.134429931640625 0.8937805175781277 +1.057125 0.014251708984375 0.134429931640625 0.8937805175781277 +1.05725 0.01373291015625 0.129364013671875 0.8937805175781277 +1.057375 0.01318359375 0.124298095703125 0.8937805175781277 +1.0575 0.01318359375 0.124298095703125 0.8937805175781277 +1.057625 0.01263427734375 0.119232177734375 0.8937805175781277 +1.05775 0.01263427734375 0.119232177734375 0.8937805175781277 +1.0578750000000002 0.012115478515625 0.1141357421875 0.8937805175781277 +1.058 0.011566162109375 0.109039306640625 0.8937805175781277 +1.058125 0.011566162109375 0.109039306640625 0.8937805175781277 +1.05825 0.011016845703125 0.103912353515625 0.8937805175781277 +1.058375 0.011016845703125 0.103912353515625 0.8937805175781277 +1.0585 0.010467529296875 0.098785400390625 0.8937805175781277 +1.058625 0.009918212890625 0.093658447265625 0.8937805175781277 +1.05875 0.009918212890625 0.093658447265625 0.8937805175781277 +1.058875 0.009368896484375 0.0885009765625 0.8937805175781277 +1.059 0.009368896484375 0.0885009765625 0.8937805175781277 +1.059125 0.008819580078125 0.083343505859375 0.8937805175781277 +1.05925 0.008270263671875 0.07818603515625 0.8937805175781277 +1.059375 0.008270263671875 0.07818603515625 0.8937805175781277 +1.0595 0.007720947265625 0.072998046875 0.8937805175781277 +1.059625 0.007720947265625 0.072998046875 0.8937805175781277 +1.05975 0.007171630859375 0.06781005859375 0.8937805175781277 +1.0598750000000002 0.006622314453125 0.0626220703125 0.8937805175781277 +1.06 0.006622314453125 0.0626220703125 0.8937805175781277 +1.060125 0.006072998046875 0.05743408203125 0.8937805175781277 +1.06025 0.006072998046875 0.05743408203125 0.8937805175781277 +1.060375 0.005523681640625 0.05224609375 0.8937805175781277 +1.0605 0.004974365234375 0.047027587890625 0.8937805175781277 +1.060625 0.004974365234375 0.047027587890625 0.8937805175781277 +1.06075 0.004425048828125 0.04180908203125 0.8937805175781277 +1.060875 0.004425048828125 0.04180908203125 0.8937805175781277 +1.061 0.003875732421875 0.036590576171875 0.8937805175781277 +1.061125 0.003326416015625 0.0313720703125 0.8937805175781277 +1.06125 0.003326416015625 0.0313720703125 0.8937805175781277 +1.061375 0.00274658203125 0.026123046875 0.8937805175781277 +1.0615 0.00274658203125 0.026123046875 0.8937805175781277 +1.061625 0.002197265625 0.020904541015625 0.8937805175781277 +1.06175 0.00164794921875 0.01568603515625 0.8937805175781277 +1.0618750000000002 0.00164794921875 0.01568603515625 0.8937805175781277 +1.062 0.0010986328125 0.01043701171875 0.8937805175781277 +1.062125 0.0010986328125 0.01043701171875 0.8937805175781277 +1.06225 0.00054931640625 0.005218505859375 0.8937805175781277 +1.062375 0.0 0.0 0.8937805175781277 +1.0625 0.0 0.0 0.8937805175781277 +1.062625 -0.00054931640625 -0.005218505859375 0.8937805175781277 +1.06275 -0.00054931640625 -0.005218505859375 0.8937805175781277 +1.062875 -0.0010986328125 -0.01043701171875 0.8937805175781277 +1.063 -0.00164794921875 -0.01568603515625 0.8937805175781277 +1.063125 -0.00164794921875 -0.01568603515625 0.8937805175781277 +1.06325 -0.002197265625 -0.020904541015625 0.8937805175781277 +1.063375 -0.002197265625 -0.020904541015625 0.8937805175781277 +1.0635000000000002 -0.00274658203125 -0.026123046875 0.8937805175781277 +1.063625 -0.003326416015625 -0.0313720703125 0.8937805175781277 +1.06375 -0.003326416015625 -0.0313720703125 0.8937805175781277 +1.0638750000000002 -0.003875732421875 -0.036590576171875 0.8937805175781277 +1.064 -0.003875732421875 -0.036590576171875 0.8937805175781277 +1.064125 -0.004425048828125 -0.04180908203125 0.8937805175781277 +1.06425 -0.004974365234375 -0.047027587890625 0.8937805175781277 +1.064375 -0.004974365234375 -0.047027587890625 0.8937805175781277 +1.0645 -0.005523681640625 -0.05224609375 0.8937805175781277 +1.064625 -0.005523681640625 -0.05224609375 0.8937805175781277 +1.06475 -0.006072998046875 -0.05743408203125 0.8937805175781277 +1.064875 -0.006622314453125 -0.0626220703125 0.8937805175781277 +1.065 -0.006622314453125 -0.0626220703125 0.8937805175781277 +1.065125 -0.007171630859375 -0.06781005859375 0.8937805175781277 +1.06525 -0.007171630859375 -0.06781005859375 0.8937805175781277 +1.065375 -0.007720947265625 -0.072998046875 0.8937805175781277 +1.0655000000000002 -0.008270263671875 -0.07818603515625 0.8937805175781277 +1.065625 -0.008270263671875 -0.07818603515625 0.8937805175781277 +1.06575 -0.008819580078125 -0.083343505859375 0.8937805175781277 +1.0658750000000002 -0.008819580078125 -0.083343505859375 0.8937805175781277 +1.066 -0.009368896484375 -0.0885009765625 0.8937805175781277 +1.066125 -0.009918212890625 -0.093658447265625 0.8937805175781277 +1.06625 -0.009918212890625 -0.093658447265625 0.8937805175781277 +1.066375 -0.010467529296875 -0.098785400390625 0.8937805175781277 +1.0665 -0.010467529296875 -0.098785400390625 0.8937805175781277 +1.066625 -0.011016845703125 -0.103912353515625 0.8937805175781277 +1.06675 -0.011566162109375 -0.109039306640625 0.8937805175781277 +1.066875 -0.011566162109375 -0.109039306640625 0.8937805175781277 +1.067 -0.012115478515625 -0.1141357421875 0.8937805175781277 +1.067125 -0.012115478515625 -0.1141357421875 0.8937805175781277 +1.06725 -0.01263427734375 -0.119232177734375 0.8937805175781277 +1.067375 -0.01318359375 -0.124298095703125 0.8937805175781277 +1.0675000000000002 -0.01318359375 -0.124298095703125 0.8937805175781277 +1.067625 -0.01373291015625 -0.129364013671875 0.8937805175781277 +1.06775 -0.01373291015625 -0.129364013671875 0.8937805175781277 +1.0678750000000002 -0.014251708984375 -0.134429931640625 0.8937805175781277 +1.068 -0.014801025390625 -0.13946533203125 0.8937805175781277 +1.068125 -0.014801025390625 -0.13946533203125 0.8937805175781277 +1.06825 -0.01531982421875 -0.14447021484375 0.8937805175781277 +1.068375 -0.01531982421875 -0.14447021484375 0.8937805175781277 +1.0685 -0.015838623046875 -0.14947509765625 0.8937805175781277 +1.068625 -0.016387939453125 -0.15447998046875 0.8937805175781277 +1.06875 -0.016387939453125 -0.15447998046875 0.8937805175781277 +1.068875 -0.01690673828125 -0.159454345703125 0.8937805175781277 +1.069 -0.01690673828125 -0.159454345703125 0.8937805175781277 +1.069125 -0.017425537109375 -0.164398193359375 0.8937805175781277 +1.06925 -0.017974853515625 -0.169342041015625 0.8937805175781277 +1.069375 -0.017974853515625 -0.169342041015625 0.8937805175781277 +1.0695000000000002 -0.01849365234375 -0.17425537109375 0.8937805175781277 +1.069625 -0.01849365234375 -0.17425537109375 0.8937805175781277 +1.06975 -0.019012451171875 -0.17913818359375 0.8937805175781277 +1.0698750000000002 -0.01953125 -0.18402099609375 0.8937805175781277 +1.07 -0.01953125 -0.18402099609375 0.8937805175781277 +1.070125 -0.020050048828125 -0.188873291015625 0.8937805175781277 +1.07025 -0.020050048828125 -0.188873291015625 0.8937805175781277 +1.070375 -0.020538330078125 -0.1937255859375 0.8937805175781277 +1.0705 -0.02105712890625 -0.19854736328125 0.8937805175781277 +1.070625 -0.02105712890625 -0.19854736328125 0.8937805175781277 +1.07075 -0.021575927734375 -0.203338623046875 0.8937805175781277 +1.070875 -0.021575927734375 -0.203338623046875 0.8937805175781277 +1.071 -0.022064208984375 -0.208099365234375 0.8937805175781277 +1.071125 -0.0225830078125 -0.212860107421875 0.8937805175781277 +1.07125 -0.0225830078125 -0.212860107421875 0.8937805175781277 +1.071375 -0.0230712890625 -0.21759033203125 0.8937805175781277 +1.0715000000000002 -0.0230712890625 -0.21759033203125 0.8937805175781277 +1.071625 -0.023590087890625 -0.2222900390625 0.8937805175781277 +1.07175 -0.024078369140625 -0.226959228515625 0.8937805175781277 +1.0718750000000002 -0.024078369140625 -0.226959228515625 0.8937805175781277 +1.072 -0.024566650390625 -0.231597900390625 0.8937805175781277 +1.072125 -0.024566650390625 -0.231597900390625 0.8937805175781277 +1.07225 -0.025054931640625 -0.236236572265625 0.8937805175781277 +1.072375 -0.025543212890625 -0.2408447265625 0.8937805175781277 +1.0725 -0.025543212890625 -0.2408447265625 0.8937805175781277 +1.072625 -0.026031494140625 -0.24542236328125 0.8937805175781277 +1.07275 -0.026031494140625 -0.24542236328125 0.8937805175781277 +1.072875 -0.026519775390625 -0.249969482421875 0.8937805175781277 +1.073 -0.027008056640625 -0.25445556640625 0.8937805175781277 +1.073125 -0.027008056640625 -0.25445556640625 0.8937805175781277 +1.07325 -0.0274658203125 -0.25897216796875 0.8937805175781277 +1.073375 -0.0274658203125 -0.25897216796875 0.8937805175781277 +1.0735000000000002 -0.0279541015625 -0.263427734375 0.8937805175781277 +1.073625 -0.028411865234375 -0.267852783203125 0.8937805175781277 +1.07375 -0.028411865234375 -0.267852783203125 0.8937805175781277 +1.073875 -0.028900146484375 -0.27227783203125 0.8937805175781277 +1.074 -0.028900146484375 -0.27227783203125 0.8937805175781277 +1.074125 -0.02935791015625 -0.276641845703125 0.8937805175781277 +1.07425 -0.029815673828125 -0.280975341796875 0.8937805175781277 +1.074375 -0.029815673828125 -0.280975341796875 0.8937805175781277 +1.0745 -0.0302734375 -0.285308837890625 0.8937805175781277 +1.074625 -0.0302734375 -0.285308837890625 0.8937805175781277 +1.07475 -0.030731201171875 -0.289581298828125 0.8937805175781277 +1.074875 -0.03118896484375 -0.2938232421875 0.8937805175781277 +1.075 -0.03118896484375 -0.2938232421875 0.8937805175781277 +1.075125 -0.0316162109375 -0.298065185546875 0.8937805175781277 +1.07525 -0.0316162109375 -0.298065185546875 0.8937805175781277 +1.075375 -0.032073974609375 -0.30224609375 0.8937805175781277 +1.0755000000000002 -0.032501220703125 -0.306396484375 0.8937805175781277 +1.075625 -0.032501220703125 -0.306396484375 0.8937805175781277 +1.07575 -0.032958984375 -0.310516357421875 0.8937805175781277 +1.075875 -0.032958984375 -0.310516357421875 0.8937805175781277 +1.076 -0.03338623046875 -0.314605712890625 0.8937805175781277 +1.076125 -0.0338134765625 -0.31866455078125 0.8937805175781277 +1.07625 -0.0338134765625 -0.31866455078125 0.8937805175781277 +1.076375 -0.03424072265625 -0.322662353515625 0.8937805175781277 +1.0765 -0.03424072265625 -0.322662353515625 0.8937805175781277 +1.076625 -0.03466796875 -0.32666015625 0.8937805175781277 +1.07675 -0.035064697265625 -0.330596923828125 0.8937805175781277 +1.076875 -0.035064697265625 -0.330596923828125 0.8937805175781277 +1.077 -0.035491943359375 -0.334503173828125 0.8937805175781277 +1.077125 -0.035491943359375 -0.334503173828125 0.8937805175781277 +1.07725 -0.035919189453125 -0.33837890625 0.8937805175781277 +1.077375 -0.03631591796875 -0.34222412109375 0.8937805175781277 +1.0775000000000002 -0.03631591796875 -0.34222412109375 0.8937805175781277 +1.077625 -0.036712646484375 -0.34600830078125 0.8937805175781277 +1.07775 -0.036712646484375 -0.34600830078125 0.8937805175781277 +1.077875 -0.037109375 -0.349761962890625 0.8937805175781277 +1.078 -0.037506103515625 -0.353485107421875 0.8937805175781277 +1.078125 -0.037506103515625 -0.353485107421875 0.8937805175781277 +1.07825 -0.03790283203125 -0.357177734375 0.8937805175781277 +1.078375 -0.03790283203125 -0.357177734375 0.8937805175781277 +1.0785 -0.038299560546875 -0.360809326171875 0.8937805175781277 +1.078625 -0.038665771484375 -0.36444091796875 0.8937805175781277 +1.07875 -0.038665771484375 -0.36444091796875 0.8937805175781277 +1.078875 -0.039031982421875 -0.36798095703125 0.8937805175781277 +1.079 -0.039031982421875 -0.36798095703125 0.8937805175781277 +1.0791250000000002 -0.0394287109375 -0.37152099609375 0.8937805175781277 +1.07925 -0.039794921875 -0.375 0.8937805175781277 +1.079375 -0.039794921875 -0.375 0.8937805175781277 +1.0795000000000002 -0.0401611328125 -0.378448486328125 0.8937805175781277 +1.079625 -0.0401611328125 -0.378448486328125 0.8937805175781277 +1.07975 -0.04052734375 -0.3818359375 0.8937805175781277 +1.079875 -0.040863037109375 -0.38519287109375 0.8937805175781277 +1.08 -0.040863037109375 -0.38519287109375 0.8937805175781277 +1.080125 -0.041229248046875 -0.388519287109375 0.8937805175781277 +1.08025 -0.041229248046875 -0.388519287109375 0.8937805175781277 +1.080375 -0.04156494140625 -0.39178466796875 0.8937805175781277 +1.0805 -0.04193115234375 -0.39501953125 0.8937805175781277 +1.080625 -0.04193115234375 -0.39501953125 0.8937805175781277 +1.08075 -0.042266845703125 -0.398193359375 0.8937805175781277 +1.080875 -0.042266845703125 -0.398193359375 0.8937805175781277 +1.081 -0.0426025390625 -0.401336669921875 0.8937805175781277 +1.0811250000000002 -0.04290771484375 -0.404449462890625 0.8937805175781277 +1.08125 -0.04290771484375 -0.404449462890625 0.8937805175781277 +1.081375 -0.043243408203125 -0.407501220703125 0.8937805175781277 +1.0815000000000002 -0.043243408203125 -0.407501220703125 0.8937805175781277 +1.081625 -0.043548583984375 -0.4105224609375 0.8937805175781277 +1.08175 -0.04388427734375 -0.413482666015625 0.8937805175781277 +1.081875 -0.04388427734375 -0.413482666015625 0.8937805175781277 +1.082 -0.044189453125 -0.416412353515625 0.8937805175781277 +1.082125 -0.044189453125 -0.416412353515625 0.8937805175781277 +1.08225 -0.04449462890625 -0.419281005859375 0.8937805175781277 +1.082375 -0.0447998046875 -0.422119140625 0.8937805175781277 +1.0825 -0.0447998046875 -0.422119140625 0.8937805175781277 +1.082625 -0.045074462890625 -0.424896240234375 0.8937805175781277 +1.08275 -0.045074462890625 -0.424896240234375 0.8937805175781277 +1.082875 -0.045379638671875 -0.4276123046875 0.8937805175781277 +1.083 -0.045654296875 -0.4302978515625 0.8937805175781277 +1.0831250000000002 -0.045654296875 -0.4302978515625 0.8937805175781277 +1.08325 -0.045928955078125 -0.432952880859375 0.8937805175781277 +1.083375 -0.045928955078125 -0.432952880859375 0.8937805175781277 +1.0835000000000002 -0.04620361328125 -0.435546875 0.8937805175781277 +1.083625 -0.046478271484375 -0.438079833984375 0.8937805175781277 +1.08375 -0.046478271484375 -0.438079833984375 0.8937805175781277 +1.083875 -0.0467529296875 -0.440582275390625 0.8937805175781277 +1.084 -0.0467529296875 -0.440582275390625 0.8937805175781277 +1.084125 -0.047027587890625 -0.44305419921875 0.8937805175781277 +1.08425 -0.047271728515625 -0.4454345703125 0.8937805175781277 +1.084375 -0.047271728515625 -0.4454345703125 0.8937805175781277 +1.0845 -0.047515869140625 -0.447784423828125 0.8937805175781277 +1.084625 -0.047515869140625 -0.447784423828125 0.8937805175781277 +1.08475 -0.047760009765625 -0.450103759765625 0.8937805175781277 +1.084875 -0.048004150390625 -0.452362060546875 0.8937805175781277 +1.085 -0.048004150390625 -0.452362060546875 0.8937805175781277 +1.0851250000000002 -0.048248291015625 -0.454559326171875 0.8937805175781277 +1.08525 -0.048248291015625 -0.454559326171875 0.8937805175781277 +1.085375 -0.0484619140625 -0.45672607421875 0.8937805175781277 +1.0855000000000002 -0.048675537109375 -0.458831787109375 0.8937805175781277 +1.085625 -0.048675537109375 -0.458831787109375 0.8937805175781277 +1.08575 -0.048919677734375 -0.46087646484375 0.8937805175781277 +1.085875 -0.048919677734375 -0.46087646484375 0.8937805175781277 +1.086 -0.04913330078125 -0.462890625 0.8937805175781277 +1.086125 -0.04931640625 -0.464813232421875 0.8937805175781277 +1.08625 -0.04931640625 -0.464813232421875 0.8937805175781277 +1.086375 -0.049530029296875 -0.46673583984375 0.8937805175781277 +1.0865 -0.049530029296875 -0.46673583984375 0.8937805175781277 +1.086625 -0.049713134765625 -0.46856689453125 0.8937805175781277 +1.08675 -0.0499267578125 -0.470367431640625 0.8937805175781277 +1.086875 -0.0499267578125 -0.470367431640625 0.8937805175781277 +1.087 -0.05010986328125 -0.472137451171875 0.8937805175781277 +1.0871250000000002 -0.05010986328125 -0.472137451171875 0.8937805175781277 +1.08725 -0.05029296875 -0.47381591796875 0.8937805175781277 +1.087375 -0.050445556640625 -0.4754638671875 0.8937805175781277 +1.0875000000000002 -0.050445556640625 -0.4754638671875 0.8937805175781277 +1.087625 -0.050628662109375 -0.47705078125 0.8937805175781277 +1.08775 -0.050628662109375 -0.47705078125 0.8937805175781277 +1.087875 -0.05078125 -0.478607177734375 0.8937805175781277 +1.088 -0.00091552734375 -0.480072021484375 0.9979858398437503488 +1.088125 -0.00091552734375 -0.480072021484375 0.9979858398437503488 +1.08825 -0.00091552734375 -0.48150634765625 0.9979858398437503488 +1.088375 -0.00091552734375 -0.48150634765625 0.9979858398437503488 +1.0885 -0.00091552734375 -0.48291015625 0.9979858398437503488 +1.088625 -0.00091552734375 -0.484222412109375 0.9979858398437503488 +1.08875 -0.00091552734375 -0.484222412109375 0.9979858398437503488 +1.088875 -0.00091552734375 -0.485504150390625 0.9979858398437503488 +1.089 -0.00091552734375 -0.485504150390625 0.9979858398437503488 +1.0891250000000002 -0.00091552734375 -0.486724853515625 0.9979858398437503488 +1.08925 -0.00091552734375 -0.487884521484375 0.9979858398437503488 +1.089375 -0.00091552734375 -0.487884521484375 0.9979858398437503488 +1.0895 -0.00091552734375 -0.489013671875 0.9979858398437503488 +1.089625 -0.00091552734375 -0.489013671875 0.9979858398437503488 +1.08975 -0.00091552734375 -0.490081787109375 0.9979858398437503488 +1.089875 -0.00091552734375 -0.4910888671875 0.9979858398437503488 +1.09 -0.00091552734375 -0.4910888671875 0.9979858398437503488 +1.090125 -0.000946044921875 -0.492034912109375 0.9979858398437503488 +1.09025 -0.000946044921875 -0.492034912109375 0.9979858398437503488 +1.090375 -0.000946044921875 -0.492950439453125 0.9979858398437503488 +1.0905 -0.000946044921875 -0.4937744140625 0.9979858398437503488 +1.090625 -0.000946044921875 -0.4937744140625 0.9979858398437503488 +1.09075 -0.000946044921875 -0.49456787109375 0.9979858398437503488 +1.090875 -0.000946044921875 -0.49456787109375 0.9979858398437503488 +1.091 -0.000946044921875 -0.49530029296875 0.9979858398437503488 +1.0911250000000002 -0.000946044921875 -0.496002197265625 0.9979858398437503488 +1.09125 -0.000946044921875 -0.496002197265625 0.9979858398437503488 +1.091375 -0.000946044921875 -0.496612548828125 0.9979858398437503488 +1.0915 -0.000946044921875 -0.496612548828125 0.9979858398437503488 +1.091625 -0.000946044921875 -0.4971923828125 0.9979858398437503488 +1.09175 -0.000946044921875 -0.497711181640625 0.9979858398437503488 +1.091875 -0.000946044921875 -0.497711181640625 0.9979858398437503488 +1.092 -0.000946044921875 -0.498199462890625 0.9979858398437503488 +1.092125 -0.000946044921875 -0.498199462890625 0.9979858398437503488 +1.09225 -0.000946044921875 -0.49859619140625 0.9979858398437503488 +1.092375 -0.000946044921875 -0.49896240234375 0.9979858398437503488 +1.0925 -0.000946044921875 -0.49896240234375 0.9979858398437503488 +1.092625 -0.000946044921875 -0.499267578125 0.9979858398437503488 +1.09275 -0.000946044921875 -0.499267578125 0.9979858398437503488 +1.092875 -0.000946044921875 -0.49951171875 0.9979858398437503488 +1.093 -0.000946044921875 -0.49969482421875 0.9979858398437503488 +1.0931250000000002 -0.000946044921875 -0.49969482421875 0.9979858398437503488 +1.09325 -0.000946044921875 -0.49981689453125 0.9979858398437503488 +1.093375 -0.000946044921875 -0.49981689453125 0.9979858398437503488 +1.0935 -0.000946044921875 -0.499908447265625 0.9979858398437503488 +1.093625 -0.000946044921875 -0.49993896484375 0.9979858398437503488 +1.09375 -0.000946044921875 -0.49993896484375 0.9979858398437503488 +1.093875 -0.000946044921875 -0.499908447265625 0.9979858398437503488 +1.094 -0.000946044921875 -0.499908447265625 0.9979858398437503488 +1.094125 -0.000946044921875 -0.49981689453125 0.9979858398437503488 +1.09425 -0.000946044921875 -0.49969482421875 0.9979858398437503488 +1.094375 -0.000946044921875 -0.49969482421875 0.9979858398437503488 +1.0945 -0.000946044921875 -0.49951171875 0.9979858398437503488 +1.094625 -0.000946044921875 -0.49951171875 0.9979858398437503488 +1.0947500000000002 -0.000946044921875 -0.499267578125 0.9979858398437503488 +1.094875 -0.000946044921875 -0.49896240234375 0.9979858398437503488 +1.095 -0.000946044921875 -0.49896240234375 0.9979858398437503488 +1.0951250000000002 -0.000946044921875 -0.49859619140625 0.9979858398437503488 +1.09525 -0.000946044921875 -0.49859619140625 0.9979858398437503488 +1.095375 -0.000946044921875 -0.498199462890625 0.9979858398437503488 +1.0955 -0.000946044921875 -0.497711181640625 0.9979858398437503488 +1.095625 -0.000946044921875 -0.497711181640625 0.9979858398437503488 +1.09575 -0.000946044921875 -0.4971923828125 0.9979858398437503488 +1.095875 -0.000946044921875 -0.4971923828125 0.9979858398437503488 +1.096 -0.000946044921875 -0.496612548828125 0.9979858398437503488 +1.096125 -0.000946044921875 -0.496002197265625 0.9979858398437503488 +1.09625 -0.000946044921875 -0.496002197265625 0.9979858398437503488 +1.096375 -0.000946044921875 -0.49530029296875 0.9979858398437503488 +1.0965 -0.000946044921875 -0.49530029296875 0.9979858398437503488 +1.096625 -0.000946044921875 -0.49456787109375 0.9979858398437503488 +1.0967500000000002 -0.000946044921875 -0.4937744140625 0.9979858398437503488 +1.096875 -0.000946044921875 -0.4937744140625 0.9979858398437503488 +1.097 -0.000946044921875 -0.492950439453125 0.9979858398437503488 +1.0971250000000002 -0.000946044921875 -0.492950439453125 0.9979858398437503488 +1.09725 -0.000946044921875 -0.492034912109375 0.9979858398437503488 +1.097375 -0.00091552734375 -0.4910888671875 0.9979858398437503488 +1.0975 -0.00091552734375 -0.4910888671875 0.9979858398437503488 +1.097625 -0.00091552734375 -0.490081787109375 0.9979858398437503488 +1.09775 -0.00091552734375 -0.490081787109375 0.9979858398437503488 +1.097875 -0.00091552734375 -0.489013671875 0.9979858398437503488 +1.098 -0.00091552734375 -0.487884521484375 0.9979858398437503488 +1.098125 -0.00091552734375 -0.487884521484375 0.9979858398437503488 +1.09825 -0.00091552734375 -0.486724853515625 0.9979858398437503488 +1.098375 -0.00091552734375 -0.486724853515625 0.9979858398437503488 +1.0985 -0.00091552734375 -0.485504150390625 0.9979858398437503488 +1.098625 -0.00091552734375 -0.484222412109375 0.9979858398437503488 +1.0987500000000002 -0.00091552734375 -0.484222412109375 0.9979858398437503488 +1.098875 -0.00091552734375 -0.48291015625 0.9979858398437503488 +1.099 -0.00091552734375 -0.48291015625 0.9979858398437503488 +1.0991250000000002 -0.00091552734375 -0.48150634765625 0.9979858398437503488 +1.09925 -0.00091552734375 -0.480072021484375 0.9979858398437503488 +1.099375 -0.00091552734375 -0.480072021484375 0.9979858398437503488 +1.0995 -0.00091552734375 -0.478607177734375 0.9979858398437503488 +1.099625 -0.00091552734375 -0.478607177734375 0.9979858398437503488 +1.09975 -0.00091552734375 -0.47705078125 0.9979858398437503488 +1.099875 -0.000885009765625 -0.4754638671875 0.9979858398437503488 +1.1 -0.000885009765625 -0.4754638671875 0.9979858398437503488 +1.100125 -0.000885009765625 -0.47381591796875 0.9979858398437503488 +1.10025 -0.000885009765625 -0.47381591796875 0.9979858398437503488 +1.100375 -0.000885009765625 -0.472137451171875 0.9979858398437503488 +1.1005 -0.000885009765625 -0.470367431640625 0.9979858398437503488 +1.100625 -0.000885009765625 -0.470367431640625 0.9979858398437503488 +1.1007500000000002 -0.000885009765625 -0.46856689453125 0.9979858398437503488 +1.100875 -0.000885009765625 -0.46856689453125 0.9979858398437503488 +1.101 -0.000885009765625 -0.46673583984375 0.9979858398437503488 +1.1011250000000002 -0.000885009765625 -0.464813232421875 0.9979858398437503488 +1.10125 -0.000885009765625 -0.464813232421875 0.9979858398437503488 +1.101375 -0.000885009765625 -0.462890625 0.9979858398437503488 +1.1015 -0.000885009765625 -0.462890625 0.9979858398437503488 +1.101625 -0.000885009765625 -0.46087646484375 0.9979858398437503488 +1.10175 -0.0008544921875 -0.458831787109375 0.9979858398437503488 +1.101875 -0.0008544921875 -0.458831787109375 0.9979858398437503488 +1.102 -0.0008544921875 -0.45672607421875 0.9979858398437503488 +1.102125 -0.0008544921875 -0.45672607421875 0.9979858398437503488 +1.10225 -0.0008544921875 -0.454559326171875 0.9979858398437503488 +1.102375 -0.0008544921875 -0.452362060546875 0.9979858398437503488 +1.1025 -0.0008544921875 -0.452362060546875 0.9979858398437503488 +1.102625 -0.0008544921875 -0.450103759765625 0.9979858398437503488 +1.1027500000000002 -0.0008544921875 -0.450103759765625 0.9979858398437503488 +1.102875 -0.0008544921875 -0.447784423828125 0.9979858398437503488 +1.103 -0.0008544921875 -0.4454345703125 0.9979858398437503488 +1.1031250000000002 -0.0008544921875 -0.4454345703125 0.9979858398437503488 +1.10325 -0.000823974609375 -0.44305419921875 0.9979858398437503488 +1.103375 -0.000823974609375 -0.44305419921875 0.9979858398437503488 +1.1035 -0.000823974609375 -0.440582275390625 0.9979858398437503488 +1.103625 -0.000823974609375 -0.438079833984375 0.9979858398437503488 +1.10375 -0.000823974609375 -0.438079833984375 0.9979858398437503488 +1.103875 -0.000823974609375 -0.435546875 0.9979858398437503488 +1.104 -0.000823974609375 -0.435546875 0.9979858398437503488 +1.104125 -0.000823974609375 -0.432952880859375 0.9979858398437503488 +1.10425 -0.000823974609375 -0.4302978515625 0.9979858398437503488 +1.104375 -0.000823974609375 -0.4302978515625 0.9979858398437503488 +1.1045 -0.00079345703125 -0.4276123046875 0.9979858398437503488 +1.104625 -0.00079345703125 -0.4276123046875 0.9979858398437503488 +1.1047500000000002 -0.00079345703125 -0.424896240234375 0.9979858398437503488 +1.104875 -0.00079345703125 -0.422119140625 0.9979858398437503488 +1.105 -0.00079345703125 -0.422119140625 0.9979858398437503488 +1.105125 -0.00079345703125 -0.419281005859375 0.9979858398437503488 +1.10525 -0.00079345703125 -0.419281005859375 0.9979858398437503488 +1.105375 -0.00079345703125 -0.416412353515625 0.9979858398437503488 +1.1055 -0.00079345703125 -0.413482666015625 0.9979858398437503488 +1.105625 -0.00079345703125 -0.413482666015625 0.9979858398437503488 +1.10575 -0.000762939453125 -0.4105224609375 0.9979858398437503488 +1.105875 -0.000762939453125 -0.4105224609375 0.9979858398437503488 +1.106 -0.000762939453125 -0.407501220703125 0.9979858398437503488 +1.106125 -0.000762939453125 -0.404449462890625 0.9979858398437503488 +1.10625 -0.000762939453125 -0.404449462890625 0.9979858398437503488 +1.106375 -0.000762939453125 -0.401336669921875 0.9979858398437503488 +1.1065 -0.000762939453125 -0.401336669921875 0.9979858398437503488 +1.106625 -0.000762939453125 -0.398193359375 0.9979858398437503488 +1.1067500000000002 -0.000732421875 -0.39501953125 0.9979858398437503488 +1.106875 -0.000732421875 -0.39501953125 0.9979858398437503488 +1.107 -0.000732421875 -0.39178466796875 0.9979858398437503488 +1.107125 -0.000732421875 -0.39178466796875 0.9979858398437503488 +1.10725 -0.000732421875 -0.388519287109375 0.9979858398437503488 +1.107375 -0.000732421875 -0.38519287109375 0.9979858398437503488 +1.1075 -0.000732421875 -0.38519287109375 0.9979858398437503488 +1.107625 -0.000732421875 -0.3818359375 0.9979858398437503488 +1.10775 -0.000732421875 -0.3818359375 0.9979858398437503488 +1.107875 -0.000701904296875 -0.378448486328125 0.9979858398437503488 +1.108 -0.000701904296875 -0.375 0.9979858398437503488 +1.108125 -0.000701904296875 -0.375 0.9979858398437503488 +1.10825 -0.000701904296875 -0.37152099609375 0.9979858398437503488 +1.108375 -0.000701904296875 -0.37152099609375 0.9979858398437503488 +1.1085 -0.000701904296875 -0.36798095703125 0.9979858398437503488 +1.108625 -0.00067138671875 -0.36444091796875 0.9979858398437503488 +1.1087500000000002 -0.00067138671875 -0.36444091796875 0.9979858398437503488 +1.108875 -0.00067138671875 -0.360809326171875 0.9979858398437503488 +1.109 -0.00067138671875 -0.360809326171875 0.9979858398437503488 +1.109125 -0.00067138671875 -0.357177734375 0.9979858398437503488 +1.10925 -0.00067138671875 -0.353485107421875 0.9979858398437503488 +1.109375 -0.00067138671875 -0.353485107421875 0.9979858398437503488 +1.1095 -0.00067138671875 -0.349761962890625 0.9979858398437503488 +1.109625 -0.00067138671875 -0.349761962890625 0.9979858398437503488 +1.10975 -0.000640869140625 -0.34600830078125 0.9979858398437503488 +1.109875 -0.000640869140625 -0.34222412109375 0.9979858398437503488 +1.11 -0.000640869140625 -0.34222412109375 0.9979858398437503488 +1.110125 -0.000640869140625 -0.33837890625 0.9979858398437503488 +1.11025 -0.000640869140625 -0.33837890625 0.9979858398437503488 +1.1103750000000002 -0.000640869140625 -0.334503173828125 0.9979858398437503488 +1.1105 -0.0006103515625 -0.330596923828125 0.9979858398437503488 +1.110625 -0.0006103515625 -0.330596923828125 0.9979858398437503488 +1.1107500000000002 -0.0006103515625 -0.32666015625 0.9979858398437503488 +1.110875 -0.0006103515625 -0.32666015625 0.9979858398437503488 +1.111 -0.0006103515625 -0.322662353515625 0.9979858398437503488 +1.111125 -0.0006103515625 -0.31866455078125 0.9979858398437503488 +1.11125 -0.0006103515625 -0.31866455078125 0.9979858398437503488 +1.111375 -0.000579833984375 -0.314605712890625 0.9979858398437503488 +1.1115 -0.000579833984375 -0.314605712890625 0.9979858398437503488 +1.111625 -0.000579833984375 -0.310516357421875 0.9979858398437503488 +1.11175 -0.000579833984375 -0.306396484375 0.9979858398437503488 +1.111875 -0.000579833984375 -0.306396484375 0.9979858398437503488 +1.112 -0.000579833984375 -0.30224609375 0.9979858398437503488 +1.112125 -0.000579833984375 -0.30224609375 0.9979858398437503488 +1.11225 -0.00054931640625 -0.298065185546875 0.9979858398437503488 +1.1123750000000002 -0.00054931640625 -0.2938232421875 0.9979858398437503488 +1.1125 -0.00054931640625 -0.2938232421875 0.9979858398437503488 +1.112625 -0.00054931640625 -0.289581298828125 0.9979858398437503488 +1.1127500000000002 -0.00054931640625 -0.289581298828125 0.9979858398437503488 +1.112875 -0.000518798828125 -0.285308837890625 0.9979858398437503488 +1.113 -0.000518798828125 -0.280975341796875 0.9979858398437503488 +1.113125 -0.000518798828125 -0.280975341796875 0.9979858398437503488 +1.11325 -0.000518798828125 -0.276641845703125 0.9979858398437503488 +1.113375 -0.000518798828125 -0.276641845703125 0.9979858398437503488 +1.1135 -0.000518798828125 -0.27227783203125 0.9979858398437503488 +1.113625 -0.00048828125 -0.267852783203125 0.9979858398437503488 +1.11375 -0.00048828125 -0.267852783203125 0.9979858398437503488 +1.113875 -0.00048828125 -0.263427734375 0.9979858398437503488 +1.114 -0.00048828125 -0.263427734375 0.9979858398437503488 +1.114125 -0.00048828125 -0.25897216796875 0.9979858398437503488 +1.11425 -0.00048828125 -0.25445556640625 0.9979858398437503488 +1.1143750000000002 -0.00048828125 -0.25445556640625 0.9979858398437503488 +1.1145 -0.000457763671875 -0.249969482421875 0.9979858398437503488 +1.114625 -0.000457763671875 -0.249969482421875 0.9979858398437503488 +1.1147500000000002 -0.000457763671875 -0.24542236328125 0.9979858398437503488 +1.114875 -0.000457763671875 -0.2408447265625 0.9979858398437503488 +1.115 -0.000457763671875 -0.2408447265625 0.9979858398437503488 +1.115125 -0.00042724609375 -0.236236572265625 0.9979858398437503488 +1.11525 -0.00042724609375 -0.236236572265625 0.9979858398437503488 +1.115375 -0.00042724609375 -0.231597900390625 0.9979858398437503488 +1.1155 -0.00042724609375 -0.226959228515625 0.9979858398437503488 +1.115625 -0.00042724609375 -0.226959228515625 0.9979858398437503488 +1.11575 -0.00042724609375 -0.2222900390625 0.9979858398437503488 +1.115875 -0.00042724609375 -0.2222900390625 0.9979858398437503488 +1.116 -0.000396728515625 -0.21759033203125 0.9979858398437503488 +1.116125 -0.000396728515625 -0.212860107421875 0.9979858398437503488 +1.11625 -0.000396728515625 -0.212860107421875 0.9979858398437503488 +1.1163750000000002 -0.000396728515625 -0.208099365234375 0.9979858398437503488 +1.1165 -0.000396728515625 -0.208099365234375 0.9979858398437503488 +1.116625 -0.0003662109375 -0.203338623046875 0.9979858398437503488 +1.1167500000000002 -0.0003662109375 -0.19854736328125 0.9979858398437503488 +1.116875 -0.0003662109375 -0.19854736328125 0.9979858398437503488 +1.117 -0.0003662109375 -0.1937255859375 0.9979858398437503488 +1.117125 -0.0003662109375 -0.1937255859375 0.9979858398437503488 +1.11725 -0.000335693359375 -0.188873291015625 0.9979858398437503488 +1.117375 -0.000335693359375 -0.18402099609375 0.9979858398437503488 +1.1175 -0.000335693359375 -0.18402099609375 0.9979858398437503488 +1.117625 -0.000335693359375 -0.17913818359375 0.9979858398437503488 +1.11775 -0.000335693359375 -0.17913818359375 0.9979858398437503488 +1.117875 -0.00030517578125 -0.17425537109375 0.9979858398437503488 +1.118 -0.00030517578125 -0.169342041015625 0.9979858398437503488 +1.118125 -0.00030517578125 -0.169342041015625 0.9979858398437503488 +1.11825 -0.00030517578125 -0.164398193359375 0.9979858398437503488 +1.1183750000000002 -0.00030517578125 -0.164398193359375 0.9979858398437503488 +1.1185 -0.00030517578125 -0.159454345703125 0.9979858398437503488 +1.118625 -0.000274658203125 -0.15447998046875 0.9979858398437503488 +1.1187500000000002 -0.000274658203125 -0.15447998046875 0.9979858398437503488 +1.118875 -0.000274658203125 -0.14947509765625 0.9979858398437503488 +1.119 -0.000274658203125 -0.14947509765625 0.9979858398437503488 +1.119125 -0.000274658203125 -0.14447021484375 0.9979858398437503488 +1.11925 -0.000244140625 -0.13946533203125 0.9979858398437503488 +1.119375 -0.000244140625 -0.13946533203125 0.9979858398437503488 +1.1195 -0.000244140625 -0.134429931640625 0.9979858398437503488 +1.119625 -0.000244140625 -0.134429931640625 0.9979858398437503488 +1.11975 -0.000244140625 -0.129364013671875 0.9979858398437503488 +1.119875 -0.000213623046875 -0.124298095703125 0.9979858398437503488 +1.12 -0.007080078125 -0.124298095703125 0.942932128906248 +1.120125 -0.00677490234375 -0.119232177734375 0.942932128906248 +1.12025 -0.00677490234375 -0.119232177734375 0.942932128906248 +1.1203750000000002 -0.006500244140625 -0.1141357421875 0.942932128906248 +1.1205 -0.006195068359375 -0.109039306640625 0.942932128906248 +1.120625 -0.006195068359375 -0.109039306640625 0.942932128906248 +1.12075 -0.00592041015625 -0.103912353515625 0.942932128906248 +1.120875 -0.00592041015625 -0.103912353515625 0.942932128906248 +1.121 -0.005615234375 -0.098785400390625 0.942932128906248 +1.121125 -0.00531005859375 -0.093658447265625 0.942932128906248 +1.12125 -0.00531005859375 -0.093658447265625 0.942932128906248 +1.121375 -0.005035400390625 -0.0885009765625 0.942932128906248 +1.1215 -0.005035400390625 -0.0885009765625 0.942932128906248 +1.121625 -0.004730224609375 -0.083343505859375 0.942932128906248 +1.12175 -0.00445556640625 -0.07818603515625 0.942932128906248 +1.121875 -0.00445556640625 -0.07818603515625 0.942932128906248 +1.122 -0.004150390625 -0.072998046875 0.942932128906248 +1.122125 -0.004150390625 -0.072998046875 0.942932128906248 +1.12225 -0.00384521484375 -0.06781005859375 0.942932128906248 +1.1223750000000002 -0.0035400390625 -0.0626220703125 0.942932128906248 +1.1225 -0.0035400390625 -0.0626220703125 0.942932128906248 +1.122625 -0.003265380859375 -0.05743408203125 0.942932128906248 +1.12275 -0.003265380859375 -0.05743408203125 0.942932128906248 +1.122875 -0.002960205078125 -0.05224609375 0.942932128906248 +1.123 -0.002655029296875 -0.047027587890625 0.942932128906248 +1.123125 -0.002655029296875 -0.047027587890625 0.942932128906248 +1.12325 -0.00238037109375 -0.04180908203125 0.942932128906248 +1.123375 -0.00238037109375 -0.04180908203125 0.942932128906248 +1.1235 -0.0020751953125 -0.036590576171875 0.942932128906248 +1.123625 -0.00177001953125 -0.0313720703125 0.942932128906248 +1.12375 -0.00177001953125 -0.0313720703125 0.942932128906248 +1.123875 -0.00146484375 -0.026123046875 0.942932128906248 +1.124 -0.00146484375 -0.026123046875 0.942932128906248 +1.124125 -0.001190185546875 -0.020904541015625 0.942932128906248 +1.12425 -0.000885009765625 -0.01568603515625 0.942932128906248 +1.1243750000000002 -0.000885009765625 -0.01568603515625 0.942932128906248 +1.1245 -0.000579833984375 -0.01043701171875 0.942932128906248 +1.124625 -0.000579833984375 -0.01043701171875 0.942932128906248 +1.12475 -0.000274658203125 -0.005218505859375 0.942932128906248 +1.124875 0.0 0.0 0.942932128906248 +1.125 0.0 0.0 0.942932128906248 +1.125125 0.000274658203125 0.005218505859375 0.942932128906248 +1.12525 0.000274658203125 0.005218505859375 0.942932128906248 +1.125375 0.000579833984375 0.01043701171875 0.942932128906248 +1.1255 0.000885009765625 0.01568603515625 0.942932128906248 +1.125625 0.000885009765625 0.01568603515625 0.942932128906248 +1.12575 0.001190185546875 0.020904541015625 0.942932128906248 +1.125875 0.001190185546875 0.020904541015625 0.942932128906248 +1.1260000000000002 0.00146484375 0.026123046875 0.942932128906248 +1.126125 0.00177001953125 0.0313720703125 0.942932128906248 +1.12625 0.00177001953125 0.0313720703125 0.942932128906248 +1.1263750000000002 0.0020751953125 0.036590576171875 0.942932128906248 +1.1265 0.0020751953125 0.036590576171875 0.942932128906248 +1.126625 0.00238037109375 0.04180908203125 0.942932128906248 +1.12675 0.002655029296875 0.047027587890625 0.942932128906248 +1.126875 0.002655029296875 0.047027587890625 0.942932128906248 +1.127 0.002960205078125 0.05224609375 0.942932128906248 +1.127125 0.002960205078125 0.05224609375 0.942932128906248 +1.12725 0.003265380859375 0.05743408203125 0.942932128906248 +1.127375 0.0035400390625 0.0626220703125 0.942932128906248 +1.1275 0.0035400390625 0.0626220703125 0.942932128906248 +1.127625 0.00384521484375 0.06781005859375 0.942932128906248 +1.12775 0.00384521484375 0.06781005859375 0.942932128906248 +1.127875 0.004150390625 0.072998046875 0.942932128906248 +1.1280000000000002 0.00445556640625 0.07818603515625 0.942932128906248 +1.128125 0.00445556640625 0.07818603515625 0.942932128906248 +1.12825 0.004730224609375 0.083343505859375 0.942932128906248 +1.1283750000000002 0.004730224609375 0.083343505859375 0.942932128906248 +1.1285 0.005035400390625 0.0885009765625 0.942932128906248 +1.128625 0.00531005859375 0.093658447265625 0.942932128906248 +1.12875 0.00531005859375 0.093658447265625 0.942932128906248 +1.128875 0.005615234375 0.098785400390625 0.942932128906248 +1.129 0.005615234375 0.098785400390625 0.942932128906248 +1.129125 0.00592041015625 0.103912353515625 0.942932128906248 +1.12925 0.006195068359375 0.109039306640625 0.942932128906248 +1.129375 0.006195068359375 0.109039306640625 0.942932128906248 +1.1295 0.006500244140625 0.1141357421875 0.942932128906248 +1.129625 0.006500244140625 0.1141357421875 0.942932128906248 +1.12975 0.00677490234375 0.119232177734375 0.942932128906248 +1.129875 0.007080078125 0.124298095703125 0.942932128906248 +1.1300000000000002 0.007080078125 0.124298095703125 0.942932128906248 +1.130125 0.007354736328125 0.129364013671875 0.942932128906248 +1.13025 0.007354736328125 0.129364013671875 0.942932128906248 +1.1303750000000002 0.007659912109375 0.134429931640625 0.942932128906248 +1.1305 0.0079345703125 0.13946533203125 0.942932128906248 +1.130625 0.0079345703125 0.13946533203125 0.942932128906248 +1.13075 0.008209228515625 0.14447021484375 0.942932128906248 +1.130875 0.008209228515625 0.14447021484375 0.942932128906248 +1.131 0.008514404296875 0.14947509765625 0.942932128906248 +1.131125 0.0087890625 0.15447998046875 0.942932128906248 +1.13125 0.0087890625 0.15447998046875 0.942932128906248 +1.131375 0.009063720703125 0.159454345703125 0.942932128906248 +1.1315 0.009063720703125 0.159454345703125 0.942932128906248 +1.131625 0.00933837890625 0.164398193359375 0.942932128906248 +1.13175 0.0096435546875 0.169342041015625 0.942932128906248 +1.131875 0.0096435546875 0.169342041015625 0.942932128906248 +1.1320000000000002 0.009918212890625 0.17425537109375 0.942932128906248 +1.132125 0.009918212890625 0.17425537109375 0.942932128906248 +1.13225 0.01019287109375 0.17913818359375 0.942932128906248 +1.1323750000000002 0.010467529296875 0.18402099609375 0.942932128906248 +1.1325 0.010467529296875 0.18402099609375 0.942932128906248 +1.132625 0.0107421875 0.188873291015625 0.942932128906248 +1.13275 0.0107421875 0.188873291015625 0.942932128906248 +1.132875 0.011016845703125 0.1937255859375 0.942932128906248 +1.133 0.01129150390625 0.19854736328125 0.942932128906248 +1.133125 0.01129150390625 0.19854736328125 0.942932128906248 +1.13325 0.011566162109375 0.203338623046875 0.942932128906248 +1.133375 0.011566162109375 0.203338623046875 0.942932128906248 +1.1335 0.0118408203125 0.208099365234375 0.942932128906248 +1.133625 0.012115478515625 0.212860107421875 0.942932128906248 +1.13375 0.012115478515625 0.212860107421875 0.942932128906248 +1.133875 0.01239013671875 0.21759033203125 0.942932128906248 +1.1340000000000002 0.01239013671875 0.21759033203125 0.942932128906248 +1.134125 0.012664794921875 0.2222900390625 0.942932128906248 +1.13425 0.012908935546875 0.226959228515625 0.942932128906248 +1.1343750000000002 0.012908935546875 0.226959228515625 0.942932128906248 +1.1345 0.01318359375 0.231597900390625 0.942932128906248 +1.134625 0.01318359375 0.231597900390625 0.942932128906248 +1.13475 0.013458251953125 0.236236572265625 0.942932128906248 +1.134875 0.013702392578125 0.2408447265625 0.942932128906248 +1.135 0.013702392578125 0.2408447265625 0.942932128906248 +1.135125 0.01397705078125 0.24542236328125 0.942932128906248 +1.13525 0.01397705078125 0.24542236328125 0.942932128906248 +1.135375 0.01422119140625 0.249969482421875 0.942932128906248 +1.1355 0.014495849609375 0.25445556640625 0.942932128906248 +1.135625 0.014495849609375 0.25445556640625 0.942932128906248 +1.13575 0.014739990234375 0.25897216796875 0.942932128906248 +1.135875 0.014739990234375 0.25897216796875 0.942932128906248 +1.1360000000000002 0.014984130859375 0.263427734375 0.942932128906248 +1.136125 0.0152587890625 0.267852783203125 0.942932128906248 +1.13625 0.0152587890625 0.267852783203125 0.942932128906248 +1.136375 0.0155029296875 0.27227783203125 0.942932128906248 +1.1365 0.0155029296875 0.27227783203125 0.942932128906248 +1.136625 0.0157470703125 0.276641845703125 0.942932128906248 +1.13675 0.0159912109375 0.280975341796875 0.942932128906248 +1.136875 0.0159912109375 0.280975341796875 0.942932128906248 +1.137 0.0162353515625 0.285308837890625 0.942932128906248 +1.137125 0.0162353515625 0.285308837890625 0.942932128906248 +1.13725 0.0164794921875 0.289581298828125 0.942932128906248 +1.137375 0.0167236328125 0.2938232421875 0.942932128906248 +1.1375 0.0167236328125 0.2938232421875 0.942932128906248 +1.137625 0.0169677734375 0.298065185546875 0.942932128906248 +1.13775 0.0169677734375 0.298065185546875 0.942932128906248 +1.137875 0.0172119140625 0.30224609375 0.942932128906248 +1.1380000000000002 0.0174560546875 0.306396484375 0.942932128906248 +1.138125 0.0174560546875 0.306396484375 0.942932128906248 +1.13825 0.017669677734375 0.310516357421875 0.942932128906248 +1.138375 0.017669677734375 0.310516357421875 0.942932128906248 +1.1385 0.017913818359375 0.314605712890625 0.942932128906248 +1.138625 0.018157958984375 0.31866455078125 0.942932128906248 +1.13875 0.018157958984375 0.31866455078125 0.942932128906248 +1.138875 0.01837158203125 0.322662353515625 0.942932128906248 +1.139 0.01837158203125 0.322662353515625 0.942932128906248 +1.139125 0.018585205078125 0.32666015625 0.942932128906248 +1.13925 0.018829345703125 0.330596923828125 0.942932128906248 +1.139375 0.018829345703125 0.330596923828125 0.942932128906248 +1.1395 0.01904296875 0.334503173828125 0.942932128906248 +1.139625 0.01904296875 0.334503173828125 0.942932128906248 +1.13975 0.019256591796875 0.33837890625 0.942932128906248 +1.139875 0.01947021484375 0.34222412109375 0.942932128906248 +1.1400000000000002 0.01947021484375 0.34222412109375 0.942932128906248 +1.140125 0.01971435546875 0.34600830078125 0.942932128906248 +1.14025 0.01971435546875 0.34600830078125 0.942932128906248 +1.140375 0.019927978515625 0.349761962890625 0.942932128906248 +1.1405 0.0201416015625 0.353485107421875 0.942932128906248 +1.140625 0.0201416015625 0.353485107421875 0.942932128906248 +1.14075 0.02032470703125 0.357177734375 0.942932128906248 +1.140875 0.02032470703125 0.357177734375 0.942932128906248 +1.141 0.020538330078125 0.360809326171875 0.942932128906248 +1.141125 0.020751953125 0.36444091796875 0.942932128906248 +1.14125 0.020751953125 0.36444091796875 0.942932128906248 +1.141375 0.020965576171875 0.36798095703125 0.942932128906248 +1.1415 0.020965576171875 0.36798095703125 0.942932128906248 +1.1416250000000002 0.021148681640625 0.37152099609375 0.942932128906248 +1.14175 0.0213623046875 0.375 0.942932128906248 +1.141875 0.0213623046875 0.375 0.942932128906248 +1.1420000000000002 0.02154541015625 0.378448486328125 0.942932128906248 +1.142125 0.02154541015625 0.378448486328125 0.942932128906248 +1.14225 0.021728515625 0.3818359375 0.942932128906248 +1.142375 0.021942138671875 0.38519287109375 0.942932128906248 +1.1425 0.021942138671875 0.38519287109375 0.942932128906248 +1.142625 0.022125244140625 0.388519287109375 0.942932128906248 +1.14275 0.022125244140625 0.388519287109375 0.942932128906248 +1.142875 0.022308349609375 0.39178466796875 0.942932128906248 +1.143 0.022491455078125 0.39501953125 0.942932128906248 +1.143125 0.022491455078125 0.39501953125 0.942932128906248 +1.14325 0.022674560546875 0.398193359375 0.942932128906248 +1.143375 0.022674560546875 0.398193359375 0.942932128906248 +1.1435 0.022857666015625 0.401336669921875 0.942932128906248 +1.1436250000000002 0.023040771484375 0.404449462890625 0.942932128906248 +1.14375 0.023040771484375 0.404449462890625 0.942932128906248 +1.143875 0.023193359375 0.407501220703125 0.942932128906248 +1.1440000000000002 0.023193359375 0.407501220703125 0.942932128906248 +1.144125 0.02337646484375 0.4105224609375 0.942932128906248 +1.14425 0.0235595703125 0.413482666015625 0.942932128906248 +1.144375 0.0235595703125 0.413482666015625 0.942932128906248 +1.1445 0.023712158203125 0.416412353515625 0.942932128906248 +1.144625 0.023712158203125 0.416412353515625 0.942932128906248 +1.14475 0.02386474609375 0.419281005859375 0.942932128906248 +1.144875 0.0240478515625 0.422119140625 0.942932128906248 +1.145 0.0240478515625 0.422119140625 0.942932128906248 +1.145125 0.024200439453125 0.424896240234375 0.942932128906248 +1.14525 0.024200439453125 0.424896240234375 0.942932128906248 +1.145375 0.02435302734375 0.4276123046875 0.942932128906248 +1.1455 0.024505615234375 0.4302978515625 0.942932128906248 +1.1456250000000002 0.024505615234375 0.4302978515625 0.942932128906248 +1.14575 0.024658203125 0.432952880859375 0.942932128906248 +1.145875 0.024658203125 0.432952880859375 0.942932128906248 +1.1460000000000002 0.024810791015625 0.435546875 0.942932128906248 +1.146125 0.024932861328125 0.438079833984375 0.942932128906248 +1.14625 0.024932861328125 0.438079833984375 0.942932128906248 +1.146375 0.02508544921875 0.440582275390625 0.942932128906248 +1.1465 0.02508544921875 0.440582275390625 0.942932128906248 +1.146625 0.025238037109375 0.44305419921875 0.942932128906248 +1.14675 0.025360107421875 0.4454345703125 0.942932128906248 +1.146875 0.025360107421875 0.4454345703125 0.942932128906248 +1.147 0.0255126953125 0.447784423828125 0.942932128906248 +1.147125 0.0255126953125 0.447784423828125 0.942932128906248 +1.14725 0.025634765625 0.450103759765625 0.942932128906248 +1.147375 0.0257568359375 0.452362060546875 0.942932128906248 +1.1475 0.0257568359375 0.452362060546875 0.942932128906248 +1.1476250000000002 0.02587890625 0.454559326171875 0.942932128906248 +1.14775 0.02587890625 0.454559326171875 0.942932128906248 +1.147875 0.0260009765625 0.45672607421875 0.942932128906248 +1.1480000000000002 0.026123046875 0.458831787109375 0.942932128906248 +1.148125 0.026123046875 0.458831787109375 0.942932128906248 +1.14825 0.0262451171875 0.46087646484375 0.942932128906248 +1.148375 0.0262451171875 0.46087646484375 0.942932128906248 +1.1485 0.0263671875 0.462890625 0.942932128906248 +1.148625 0.026458740234375 0.464813232421875 0.942932128906248 +1.14875 0.026458740234375 0.464813232421875 0.942932128906248 +1.148875 0.026580810546875 0.46673583984375 0.942932128906248 +1.149 0.026580810546875 0.46673583984375 0.942932128906248 +1.149125 0.02667236328125 0.46856689453125 0.942932128906248 +1.14925 0.02679443359375 0.470367431640625 0.942932128906248 +1.149375 0.02679443359375 0.470367431640625 0.942932128906248 +1.1495 0.026885986328125 0.472137451171875 0.942932128906248 +1.1496250000000002 0.026885986328125 0.472137451171875 0.942932128906248 +1.14975 0.0269775390625 0.47381591796875 0.942932128906248 +1.149875 0.027069091796875 0.4754638671875 0.942932128906248 +1.1500000000000002 0.027069091796875 0.4754638671875 0.942932128906248 +1.150125 0.02716064453125 0.47705078125 0.942932128906248 +1.15025 0.02716064453125 0.47705078125 0.942932128906248 +1.150375 0.027252197265625 0.478607177734375 0.942932128906248 +1.1505 0.02734375 0.480072021484375 0.942932128906248 +1.150625 0.02734375 0.480072021484375 0.942932128906248 +1.15075 0.027435302734375 0.48150634765625 0.942932128906248 +1.150875 0.027435302734375 0.48150634765625 0.942932128906248 +1.151 0.027496337890625 0.48291015625 0.942932128906248 +1.151125 0.027587890625 0.484222412109375 0.942932128906248 +1.15125 0.027587890625 0.484222412109375 0.942932128906248 +1.151375 0.02764892578125 0.485504150390625 0.942932128906248 +1.1515 0.02764892578125 0.485504150390625 0.942932128906248 +1.1516250000000002 0.0277099609375 0.486724853515625 0.942932128906248 +1.15175 0.02777099609375 0.487884521484375 0.942932128906248 +1.151875 0.02777099609375 0.487884521484375 0.942932128906248 +1.1520000000000002 0.128326416015625 0.489013671875 0.737463378906246 +1.152125 0.128326416015625 0.489013671875 0.737463378906246 +1.15225 0.12860107421875 0.490081787109375 0.737463378906246 +1.152375 0.128875732421875 0.4910888671875 0.737463378906246 +1.1525 0.128875732421875 0.4910888671875 0.737463378906246 +1.152625 0.129119873046875 0.492034912109375 0.737463378906246 +1.15275 0.129119873046875 0.492034912109375 0.737463378906246 +1.152875 0.129364013671875 0.492950439453125 0.737463378906246 +1.153 0.12957763671875 0.4937744140625 0.737463378906246 +1.153125 0.12957763671875 0.4937744140625 0.737463378906246 +1.15325 0.129791259765625 0.49456787109375 0.737463378906246 +1.153375 0.129791259765625 0.49456787109375 0.737463378906246 +1.1535 0.129974365234375 0.49530029296875 0.737463378906246 +1.1536250000000002 0.130157470703125 0.496002197265625 0.737463378906246 +1.15375 0.130157470703125 0.496002197265625 0.737463378906246 +1.153875 0.130340576171875 0.496612548828125 0.737463378906246 +1.154 0.130340576171875 0.496612548828125 0.737463378906246 +1.154125 0.1304931640625 0.4971923828125 0.737463378906246 +1.15425 0.130615234375 0.497711181640625 0.737463378906246 +1.154375 0.130615234375 0.497711181640625 0.737463378906246 +1.1545 0.1307373046875 0.498199462890625 0.737463378906246 +1.154625 0.1307373046875 0.498199462890625 0.737463378906246 +1.15475 0.130859375 0.49859619140625 0.737463378906246 +1.154875 0.130950927734375 0.49896240234375 0.737463378906246 +1.155 0.130950927734375 0.49896240234375 0.737463378906246 +1.155125 0.131011962890625 0.499267578125 0.737463378906246 +1.15525 0.131011962890625 0.499267578125 0.737463378906246 +1.155375 0.131103515625 0.49951171875 0.737463378906246 +1.1555 0.131134033203125 0.49969482421875 0.737463378906246 +1.1556250000000002 0.131134033203125 0.49969482421875 0.737463378906246 +1.15575 0.13116455078125 0.49981689453125 0.737463378906246 +1.155875 0.13116455078125 0.49981689453125 0.737463378906246 +1.156 0.131195068359375 0.499908447265625 0.737463378906246 +1.156125 0.131195068359375 0.49993896484375 0.737463378906246 +1.15625 0.131195068359375 0.49993896484375 0.737463378906246 +1.156375 0.131195068359375 0.499908447265625 0.737463378906246 +1.1565 0.131195068359375 0.499908447265625 0.737463378906246 +1.156625 0.13116455078125 0.49981689453125 0.737463378906246 +1.15675 0.131134033203125 0.49969482421875 0.737463378906246 +1.156875 0.131134033203125 0.49969482421875 0.737463378906246 +1.157 0.131103515625 0.49951171875 0.737463378906246 +1.157125 0.131103515625 0.49951171875 0.737463378906246 +1.1572500000000002 0.131011962890625 0.499267578125 0.737463378906246 +1.157375 0.130950927734375 0.49896240234375 0.737463378906246 +1.1575 0.130950927734375 0.49896240234375 0.737463378906246 +1.1576250000000002 0.130859375 0.49859619140625 0.737463378906246 +1.15775 0.130859375 0.49859619140625 0.737463378906246 +1.157875 0.1307373046875 0.498199462890625 0.737463378906246 +1.158 0.130615234375 0.497711181640625 0.737463378906246 +1.158125 0.130615234375 0.497711181640625 0.737463378906246 +1.15825 0.1304931640625 0.4971923828125 0.737463378906246 +1.158375 0.1304931640625 0.4971923828125 0.737463378906246 +1.1585 0.130340576171875 0.496612548828125 0.737463378906246 +1.158625 0.130157470703125 0.496002197265625 0.737463378906246 +1.15875 0.130157470703125 0.496002197265625 0.737463378906246 +1.158875 0.129974365234375 0.49530029296875 0.737463378906246 +1.159 0.129974365234375 0.49530029296875 0.737463378906246 +1.159125 0.129791259765625 0.49456787109375 0.737463378906246 +1.1592500000000002 0.12957763671875 0.4937744140625 0.737463378906246 +1.159375 0.12957763671875 0.4937744140625 0.737463378906246 +1.1595 0.129364013671875 0.492950439453125 0.737463378906246 +1.1596250000000002 0.129364013671875 0.492950439453125 0.737463378906246 +1.15975 0.129119873046875 0.492034912109375 0.737463378906246 +1.159875 0.128875732421875 0.4910888671875 0.737463378906246 +1.16 0.128875732421875 0.4910888671875 0.737463378906246 +1.160125 0.12860107421875 0.490081787109375 0.737463378906246 +1.16025 0.12860107421875 0.490081787109375 0.737463378906246 +1.160375 0.128326416015625 0.489013671875 0.737463378906246 +1.1605 0.1280517578125 0.487884521484375 0.737463378906246 +1.160625 0.1280517578125 0.487884521484375 0.737463378906246 +1.16075 0.12774658203125 0.486724853515625 0.737463378906246 +1.160875 0.12774658203125 0.486724853515625 0.737463378906246 +1.161 0.127410888671875 0.485504150390625 0.737463378906246 +1.161125 0.1270751953125 0.484222412109375 0.737463378906246 +1.1612500000000002 0.1270751953125 0.484222412109375 0.737463378906246 +1.161375 0.126739501953125 0.48291015625 0.737463378906246 +1.1615 0.126739501953125 0.48291015625 0.737463378906246 +1.1616250000000002 0.126373291015625 0.48150634765625 0.737463378906246 +1.16175 0.126007080078125 0.480072021484375 0.737463378906246 +1.161875 0.126007080078125 0.480072021484375 0.737463378906246 +1.162 0.1256103515625 0.478607177734375 0.737463378906246 +1.162125 0.1256103515625 0.478607177734375 0.737463378906246 +1.16225 0.125213623046875 0.47705078125 0.737463378906246 +1.162375 0.124786376953125 0.4754638671875 0.737463378906246 +1.1625 0.124786376953125 0.4754638671875 0.737463378906246 +1.162625 0.124359130859375 0.47381591796875 0.737463378906246 +1.16275 0.124359130859375 0.47381591796875 0.737463378906246 +1.162875 0.1239013671875 0.472137451171875 0.737463378906246 +1.163 0.123443603515625 0.470367431640625 0.737463378906246 +1.163125 0.123443603515625 0.470367431640625 0.737463378906246 +1.1632500000000002 0.12298583984375 0.46856689453125 0.737463378906246 +1.163375 0.12298583984375 0.46856689453125 0.737463378906246 +1.1635 0.12249755859375 0.46673583984375 0.737463378906246 +1.1636250000000002 0.121978759765625 0.464813232421875 0.737463378906246 +1.16375 0.121978759765625 0.464813232421875 0.737463378906246 +1.163875 0.121490478515625 0.462890625 0.737463378906246 +1.164 0.121490478515625 0.462890625 0.737463378906246 +1.164125 0.120941162109375 0.46087646484375 0.737463378906246 +1.16425 0.12042236328125 0.458831787109375 0.737463378906246 +1.164375 0.12042236328125 0.458831787109375 0.737463378906246 +1.1645 0.119873046875 0.45672607421875 0.737463378906246 +1.164625 0.119873046875 0.45672607421875 0.737463378906246 +1.16475 0.119293212890625 0.454559326171875 0.737463378906246 +1.164875 0.11871337890625 0.452362060546875 0.737463378906246 +1.165 0.11871337890625 0.452362060546875 0.737463378906246 +1.165125 0.118133544921875 0.450103759765625 0.737463378906246 +1.1652500000000002 0.118133544921875 0.450103759765625 0.737463378906246 +1.165375 0.117523193359375 0.447784423828125 0.737463378906246 +1.1655 0.116912841796875 0.4454345703125 0.737463378906246 +1.1656250000000002 0.116912841796875 0.4454345703125 0.737463378906246 +1.16575 0.11627197265625 0.44305419921875 0.737463378906246 +1.165875 0.11627197265625 0.44305419921875 0.737463378906246 +1.166 0.115631103515625 0.440582275390625 0.737463378906246 +1.166125 0.114959716796875 0.438079833984375 0.737463378906246 +1.16625 0.114959716796875 0.438079833984375 0.737463378906246 +1.166375 0.11431884765625 0.435546875 0.737463378906246 +1.1665 0.11431884765625 0.435546875 0.737463378906246 +1.166625 0.113616943359375 0.432952880859375 0.737463378906246 +1.16675 0.1129150390625 0.4302978515625 0.737463378906246 +1.166875 0.1129150390625 0.4302978515625 0.737463378906246 +1.167 0.112213134765625 0.4276123046875 0.737463378906246 +1.167125 0.112213134765625 0.4276123046875 0.737463378906246 +1.1672500000000002 0.11151123046875 0.424896240234375 0.737463378906246 +1.167375 0.11077880859375 0.422119140625 0.737463378906246 +1.1675 0.11077880859375 0.422119140625 0.737463378906246 +1.1676250000000002 0.11004638671875 0.419281005859375 0.737463378906246 +1.16775 0.11004638671875 0.419281005859375 0.737463378906246 +1.167875 0.109283447265625 0.416412353515625 0.737463378906246 +1.168 0.1085205078125 0.413482666015625 0.737463378906246 +1.168125 0.1085205078125 0.413482666015625 0.737463378906246 +1.16825 0.10772705078125 0.4105224609375 0.737463378906246 +1.168375 0.10772705078125 0.4105224609375 0.737463378906246 +1.1685 0.10693359375 0.407501220703125 0.737463378906246 +1.168625 0.10614013671875 0.404449462890625 0.737463378906246 +1.16875 0.10614013671875 0.404449462890625 0.737463378906246 +1.168875 0.105316162109375 0.401336669921875 0.737463378906246 +1.169 0.105316162109375 0.401336669921875 0.737463378906246 +1.169125 0.1044921875 0.398193359375 0.737463378906246 +1.1692500000000002 0.103668212890625 0.39501953125 0.737463378906246 +1.169375 0.103668212890625 0.39501953125 0.737463378906246 +1.1695 0.102813720703125 0.39178466796875 0.737463378906246 +1.169625 0.102813720703125 0.39178466796875 0.737463378906246 +1.16975 0.101959228515625 0.388519287109375 0.737463378906246 +1.169875 0.101104736328125 0.38519287109375 0.737463378906246 +1.17 0.101104736328125 0.38519287109375 0.737463378906246 +1.170125 0.1002197265625 0.3818359375 0.737463378906246 +1.17025 0.1002197265625 0.3818359375 0.737463378906246 +1.170375 0.09930419921875 0.378448486328125 0.737463378906246 +1.1705 0.098419189453125 0.375 0.737463378906246 +1.170625 0.098419189453125 0.375 0.737463378906246 +1.17075 0.097503662109375 0.37152099609375 0.737463378906246 +1.170875 0.097503662109375 0.37152099609375 0.737463378906246 +1.171 0.096588134765625 0.36798095703125 0.737463378906246 +1.171125 0.09564208984375 0.36444091796875 0.737463378906246 +1.1712500000000002 0.09564208984375 0.36444091796875 0.737463378906246 +1.171375 0.094696044921875 0.360809326171875 0.737463378906246 +1.1715 0.094696044921875 0.360809326171875 0.737463378906246 +1.171625 0.09375 0.357177734375 0.737463378906246 +1.17175 0.0927734375 0.353485107421875 0.737463378906246 +1.171875 0.0927734375 0.353485107421875 0.737463378906246 +1.172 0.091796875 0.349761962890625 0.737463378906246 +1.172125 0.091796875 0.349761962890625 0.737463378906246 +1.17225 0.0908203125 0.34600830078125 0.737463378906246 +1.172375 0.089813232421875 0.34222412109375 0.737463378906246 +1.1725 0.089813232421875 0.34222412109375 0.737463378906246 +1.172625 0.08880615234375 0.33837890625 0.737463378906246 +1.17275 0.08880615234375 0.33837890625 0.737463378906246 +1.1728750000000002 0.087799072265625 0.334503173828125 0.737463378906246 +1.173 0.086761474609375 0.330596923828125 0.737463378906246 +1.173125 0.086761474609375 0.330596923828125 0.737463378906246 +1.1732500000000002 0.085723876953125 0.32666015625 0.737463378906246 +1.173375 0.085723876953125 0.32666015625 0.737463378906246 +1.1735 0.084686279296875 0.322662353515625 0.737463378906246 +1.173625 0.0836181640625 0.31866455078125 0.737463378906246 +1.17375 0.0836181640625 0.31866455078125 0.737463378906246 +1.173875 0.082550048828125 0.314605712890625 0.737463378906246 +1.174 0.082550048828125 0.314605712890625 0.737463378906246 +1.174125 0.08148193359375 0.310516357421875 0.737463378906246 +1.17425 0.080413818359375 0.306396484375 0.737463378906246 +1.174375 0.080413818359375 0.306396484375 0.737463378906246 +1.1745 0.079315185546875 0.30224609375 0.737463378906246 +1.174625 0.079315185546875 0.30224609375 0.737463378906246 +1.17475 0.078216552734375 0.298065185546875 0.737463378906246 +1.1748750000000002 0.077117919921875 0.2938232421875 0.737463378906246 +1.175 0.077117919921875 0.2938232421875 0.737463378906246 +1.175125 0.07598876953125 0.289581298828125 0.737463378906246 +1.1752500000000002 0.07598876953125 0.289581298828125 0.737463378906246 +1.175375 0.074859619140625 0.285308837890625 0.737463378906246 +1.1755 0.07373046875 0.280975341796875 0.737463378906246 +1.175625 0.07373046875 0.280975341796875 0.737463378906246 +1.17575 0.072601318359375 0.276641845703125 0.737463378906246 +1.175875 0.072601318359375 0.276641845703125 0.737463378906246 +1.176 0.071441650390625 0.27227783203125 0.737463378906246 +1.176125 0.070281982421875 0.267852783203125 0.737463378906246 +1.17625 0.070281982421875 0.267852783203125 0.737463378906246 +1.176375 0.069122314453125 0.263427734375 0.737463378906246 +1.1765 0.069122314453125 0.263427734375 0.737463378906246 +1.176625 0.067962646484375 0.25897216796875 0.737463378906246 +1.17675 0.0667724609375 0.25445556640625 0.737463378906246 +1.1768750000000002 0.0667724609375 0.25445556640625 0.737463378906246 +1.177 0.065582275390625 0.249969482421875 0.737463378906246 +1.177125 0.065582275390625 0.249969482421875 0.737463378906246 +1.1772500000000002 0.06439208984375 0.24542236328125 0.737463378906246 +1.177375 0.063201904296875 0.2408447265625 0.737463378906246 +1.1775 0.063201904296875 0.2408447265625 0.737463378906246 +1.177625 0.061981201171875 0.236236572265625 0.737463378906246 +1.17775 0.061981201171875 0.236236572265625 0.737463378906246 +1.177875 0.060791015625 0.231597900390625 0.737463378906246 +1.178 0.059539794921875 0.226959228515625 0.737463378906246 +1.178125 0.059539794921875 0.226959228515625 0.737463378906246 +1.17825 0.058319091796875 0.2222900390625 0.737463378906246 +1.178375 0.058319091796875 0.2222900390625 0.737463378906246 +1.1785 0.057098388671875 0.21759033203125 0.737463378906246 +1.178625 0.05584716796875 0.212860107421875 0.737463378906246 +1.17875 0.05584716796875 0.212860107421875 0.737463378906246 +1.1788750000000002 0.054595947265625 0.208099365234375 0.737463378906246 +1.179 0.054595947265625 0.208099365234375 0.737463378906246 +1.179125 0.0533447265625 0.203338623046875 0.737463378906246 +1.1792500000000002 0.052093505859375 0.19854736328125 0.737463378906246 +1.179375 0.052093505859375 0.19854736328125 0.737463378906246 +1.1795 0.05084228515625 0.1937255859375 0.737463378906246 +1.179625 0.05084228515625 0.1937255859375 0.737463378906246 +1.17975 0.049560546875 0.188873291015625 0.737463378906246 +1.179875 0.04827880859375 0.18402099609375 0.737463378906246 +1.18 0.04827880859375 0.18402099609375 0.737463378906246 +1.180125 0.0469970703125 0.17913818359375 0.737463378906246 +1.18025 0.0469970703125 0.17913818359375 0.737463378906246 +1.180375 0.04571533203125 0.17425537109375 0.737463378906246 +1.1805 0.04443359375 0.169342041015625 0.737463378906246 +1.180625 0.04443359375 0.169342041015625 0.737463378906246 +1.18075 0.043121337890625 0.164398193359375 0.737463378906246 +1.1808750000000002 0.043121337890625 0.164398193359375 0.737463378906246 +1.181 0.041839599609375 0.159454345703125 0.737463378906246 +1.181125 0.04052734375 0.15447998046875 0.737463378906246 +1.1812500000000002 0.04052734375 0.15447998046875 0.737463378906246 +1.181375 0.039215087890625 0.14947509765625 0.737463378906246 +1.1815 0.039215087890625 0.14947509765625 0.737463378906246 +1.181625 0.03790283203125 0.14447021484375 0.737463378906246 +1.18175 0.036590576171875 0.13946533203125 0.737463378906246 +1.181875 0.036590576171875 0.13946533203125 0.737463378906246 +1.182 0.0352783203125 0.134429931640625 0.737463378906246 +1.182125 0.0352783203125 0.134429931640625 0.737463378906246 +1.18225 0.033935546875 0.129364013671875 0.737463378906246 +1.182375 0.032623291015625 0.124298095703125 0.737463378906246 +1.1825 0.032623291015625 0.124298095703125 0.737463378906246 +1.182625 0.031280517578125 0.119232177734375 0.737463378906246 +1.18275 0.031280517578125 0.119232177734375 0.737463378906246 +1.1828750000000002 0.029937744140625 0.1141357421875 0.737463378906246 +1.183 0.028594970703125 0.109039306640625 0.737463378906246 +1.183125 0.028594970703125 0.109039306640625 0.737463378906246 +1.1832500000000002 0.027252197265625 0.103912353515625 0.737463378906246 +1.183375 0.027252197265625 0.103912353515625 0.737463378906246 +1.1835 0.025909423828125 0.098785400390625 0.737463378906246 +1.183625 0.024566650390625 0.093658447265625 0.737463378906246 +1.18375 0.024566650390625 0.093658447265625 0.737463378906246 +1.183875 0.023223876953125 0.0885009765625 0.737463378906246 +1.184 0.05181884765625 0.0885009765625 0.41434936523436966 +1.184125 0.048797607421875 0.083343505859375 0.41434936523436966 +1.18425 0.0457763671875 0.07818603515625 0.41434936523436966 +1.184375 0.0457763671875 0.07818603515625 0.41434936523436966 +1.1845 0.042755126953125 0.072998046875 0.41434936523436966 +1.184625 0.042755126953125 0.072998046875 0.41434936523436966 +1.18475 0.039703369140625 0.06781005859375 0.41434936523436966 +1.1848750000000002 0.03668212890625 0.0626220703125 0.41434936523436966 +1.185 0.03668212890625 0.0626220703125 0.41434936523436966 +1.185125 0.03363037109375 0.05743408203125 0.41434936523436966 +1.18525 0.03363037109375 0.05743408203125 0.41434936523436966 +1.185375 0.03057861328125 0.05224609375 0.41434936523436966 +1.1855 0.02752685546875 0.047027587890625 0.41434936523436966 +1.185625 0.02752685546875 0.047027587890625 0.41434936523436966 +1.18575 0.02447509765625 0.04180908203125 0.41434936523436966 +1.185875 0.02447509765625 0.04180908203125 0.41434936523436966 +1.186 0.02142333984375 0.036590576171875 0.41434936523436966 +1.186125 0.01837158203125 0.0313720703125 0.41434936523436966 +1.18625 0.01837158203125 0.0313720703125 0.41434936523436966 +1.186375 0.015289306640625 0.026123046875 0.41434936523436966 +1.1865 0.015289306640625 0.026123046875 0.41434936523436966 +1.186625 0.012237548828125 0.020904541015625 0.41434936523436966 +1.18675 0.009185791015625 0.01568603515625 0.41434936523436966 +1.1868750000000002 0.009185791015625 0.01568603515625 0.41434936523436966 +1.187 0.006103515625 0.01043701171875 0.41434936523436966 +1.187125 0.006103515625 0.01043701171875 0.41434936523436966 +1.18725 0.0030517578125 0.005218505859375 0.41434936523436966 +1.187375 0.0 0.0 0.41434936523436966 +1.1875 0.0 0.0 0.41434936523436966 +1.187625 -0.0030517578125 -0.005218505859375 0.41434936523436966 +1.18775 -0.0030517578125 -0.005218505859375 0.41434936523436966 +1.187875 -0.006103515625 -0.01043701171875 0.41434936523436966 +1.188 -0.009185791015625 -0.01568603515625 0.41434936523436966 +1.188125 -0.009185791015625 -0.01568603515625 0.41434936523436966 +1.18825 -0.012237548828125 -0.020904541015625 0.41434936523436966 +1.188375 -0.012237548828125 -0.020904541015625 0.41434936523436966 +1.1885000000000002 -0.015289306640625 -0.026123046875 0.41434936523436966 +1.188625 -0.01837158203125 -0.0313720703125 0.41434936523436966 +1.18875 -0.01837158203125 -0.0313720703125 0.41434936523436966 +1.1888750000000002 -0.02142333984375 -0.036590576171875 0.41434936523436966 +1.189 -0.02142333984375 -0.036590576171875 0.41434936523436966 +1.189125 -0.02447509765625 -0.04180908203125 0.41434936523436966 +1.18925 -0.02752685546875 -0.047027587890625 0.41434936523436966 +1.189375 -0.02752685546875 -0.047027587890625 0.41434936523436966 +1.1895 -0.03057861328125 -0.05224609375 0.41434936523436966 +1.189625 -0.03057861328125 -0.05224609375 0.41434936523436966 +1.18975 -0.03363037109375 -0.05743408203125 0.41434936523436966 +1.189875 -0.03668212890625 -0.0626220703125 0.41434936523436966 +1.19 -0.03668212890625 -0.0626220703125 0.41434936523436966 +1.190125 -0.039703369140625 -0.06781005859375 0.41434936523436966 +1.19025 -0.039703369140625 -0.06781005859375 0.41434936523436966 +1.190375 -0.042755126953125 -0.072998046875 0.41434936523436966 +1.1905000000000002 -0.0457763671875 -0.07818603515625 0.41434936523436966 +1.190625 -0.0457763671875 -0.07818603515625 0.41434936523436966 +1.19075 -0.048797607421875 -0.083343505859375 0.41434936523436966 +1.1908750000000002 -0.048797607421875 -0.083343505859375 0.41434936523436966 +1.191 -0.05181884765625 -0.0885009765625 0.41434936523436966 +1.191125 -0.054840087890625 -0.093658447265625 0.41434936523436966 +1.19125 -0.054840087890625 -0.093658447265625 0.41434936523436966 +1.191375 -0.057861328125 -0.098785400390625 0.41434936523436966 +1.1915 -0.057861328125 -0.098785400390625 0.41434936523436966 +1.191625 -0.06085205078125 -0.103912353515625 0.41434936523436966 +1.19175 -0.0638427734375 -0.109039306640625 0.41434936523436966 +1.191875 -0.0638427734375 -0.109039306640625 0.41434936523436966 +1.192 -0.06683349609375 -0.1141357421875 0.41434936523436966 +1.192125 -0.06683349609375 -0.1141357421875 0.41434936523436966 +1.19225 -0.06982421875 -0.119232177734375 0.41434936523436966 +1.192375 -0.072784423828125 -0.124298095703125 0.41434936523436966 +1.1925000000000002 -0.072784423828125 -0.124298095703125 0.41434936523436966 +1.192625 -0.07574462890625 -0.129364013671875 0.41434936523436966 +1.19275 -0.07574462890625 -0.129364013671875 0.41434936523436966 +1.1928750000000002 -0.078704833984375 -0.134429931640625 0.41434936523436966 +1.193 -0.0816650390625 -0.13946533203125 0.41434936523436966 +1.193125 -0.0816650390625 -0.13946533203125 0.41434936523436966 +1.19325 -0.0845947265625 -0.14447021484375 0.41434936523436966 +1.193375 -0.0845947265625 -0.14447021484375 0.41434936523436966 +1.1935 -0.0875244140625 -0.14947509765625 0.41434936523436966 +1.193625 -0.0904541015625 -0.15447998046875 0.41434936523436966 +1.19375 -0.0904541015625 -0.15447998046875 0.41434936523436966 +1.193875 -0.093353271484375 -0.159454345703125 0.41434936523436966 +1.194 -0.093353271484375 -0.159454345703125 0.41434936523436966 +1.194125 -0.09625244140625 -0.164398193359375 0.41434936523436966 +1.19425 -0.099151611328125 -0.169342041015625 0.41434936523436966 +1.194375 -0.099151611328125 -0.169342041015625 0.41434936523436966 +1.1945000000000002 -0.102020263671875 -0.17425537109375 0.41434936523436966 +1.194625 -0.102020263671875 -0.17425537109375 0.41434936523436966 +1.19475 -0.104888916015625 -0.17913818359375 0.41434936523436966 +1.1948750000000002 -0.107757568359375 -0.18402099609375 0.41434936523436966 +1.195 -0.107757568359375 -0.18402099609375 0.41434936523436966 +1.195125 -0.110595703125 -0.188873291015625 0.41434936523436966 +1.19525 -0.110595703125 -0.188873291015625 0.41434936523436966 +1.195375 -0.113433837890625 -0.1937255859375 0.41434936523436966 +1.1955 -0.11627197265625 -0.19854736328125 0.41434936523436966 +1.195625 -0.11627197265625 -0.19854736328125 0.41434936523436966 +1.19575 -0.119049072265625 -0.203338623046875 0.41434936523436966 +1.195875 -0.119049072265625 -0.203338623046875 0.41434936523436966 +1.196 -0.121856689453125 -0.208099365234375 0.41434936523436966 +1.196125 -0.1246337890625 -0.212860107421875 0.41434936523436966 +1.19625 -0.1246337890625 -0.212860107421875 0.41434936523436966 +1.196375 -0.127410888671875 -0.21759033203125 0.41434936523436966 +1.1965000000000002 -0.127410888671875 -0.21759033203125 0.41434936523436966 +1.196625 -0.130157470703125 -0.2222900390625 0.41434936523436966 +1.19675 -0.132904052734375 -0.226959228515625 0.41434936523436966 +1.1968750000000002 -0.132904052734375 -0.226959228515625 0.41434936523436966 +1.197 -0.1356201171875 -0.231597900390625 0.41434936523436966 +1.197125 -0.1356201171875 -0.231597900390625 0.41434936523436966 +1.19725 -0.138336181640625 -0.236236572265625 0.41434936523436966 +1.197375 -0.141021728515625 -0.2408447265625 0.41434936523436966 +1.1975 -0.141021728515625 -0.2408447265625 0.41434936523436966 +1.197625 -0.143707275390625 -0.24542236328125 0.41434936523436966 +1.19775 -0.143707275390625 -0.24542236328125 0.41434936523436966 +1.197875 -0.1463623046875 -0.249969482421875 0.41434936523436966 +1.198 -0.149017333984375 -0.25445556640625 0.41434936523436966 +1.198125 -0.149017333984375 -0.25445556640625 0.41434936523436966 +1.19825 -0.151641845703125 -0.25897216796875 0.41434936523436966 +1.198375 -0.151641845703125 -0.25897216796875 0.41434936523436966 +1.1985000000000002 -0.154266357421875 -0.263427734375 0.41434936523436966 +1.198625 -0.1568603515625 -0.267852783203125 0.41434936523436966 +1.19875 -0.1568603515625 -0.267852783203125 0.41434936523436966 +1.1988750000000002 -0.159454345703125 -0.27227783203125 0.41434936523436966 +1.199 -0.159454345703125 -0.27227783203125 0.41434936523436966 +1.199125 -0.1619873046875 -0.276641845703125 0.41434936523436966 +1.19925 -0.16455078125 -0.280975341796875 0.41434936523436966 +1.199375 -0.16455078125 -0.280975341796875 0.41434936523436966 +1.1995 -0.167083740234375 -0.285308837890625 0.41434936523436966 +1.199625 -0.167083740234375 -0.285308837890625 0.41434936523436966 +1.19975 -0.169586181640625 -0.289581298828125 0.41434936523436966 +1.199875 -0.17205810546875 -0.2938232421875 0.41434936523436966 +1.2 -0.17205810546875 -0.2938232421875 0.41434936523436966 +1.200125 -0.174530029296875 -0.298065185546875 0.41434936523436966 +1.20025 -0.174530029296875 -0.298065185546875 0.41434936523436966 +1.200375 -0.177001953125 -0.30224609375 0.41434936523436966 +1.2005000000000002 -0.179443359375 -0.306396484375 0.41434936523436966 +1.200625 -0.179443359375 -0.306396484375 0.41434936523436966 +1.20075 -0.181854248046875 -0.310516357421875 0.41434936523436966 +1.200875 -0.181854248046875 -0.310516357421875 0.41434936523436966 +1.201 -0.184234619140625 -0.314605712890625 0.41434936523436966 +1.201125 -0.186614990234375 -0.31866455078125 0.41434936523436966 +1.20125 -0.186614990234375 -0.31866455078125 0.41434936523436966 +1.201375 -0.18896484375 -0.322662353515625 0.41434936523436966 +1.2015 -0.18896484375 -0.322662353515625 0.41434936523436966 +1.201625 -0.1912841796875 -0.32666015625 0.41434936523436966 +1.20175 -0.193603515625 -0.330596923828125 0.41434936523436966 +1.201875 -0.193603515625 -0.330596923828125 0.41434936523436966 +1.202 -0.195892333984375 -0.334503173828125 0.41434936523436966 +1.202125 -0.195892333984375 -0.334503173828125 0.41434936523436966 +1.20225 -0.198150634765625 -0.33837890625 0.41434936523436966 +1.202375 -0.200408935546875 -0.34222412109375 0.41434936523436966 +1.2025000000000002 -0.200408935546875 -0.34222412109375 0.41434936523436966 +1.202625 -0.20263671875 -0.34600830078125 0.41434936523436966 +1.20275 -0.20263671875 -0.34600830078125 0.41434936523436966 +1.202875 -0.204833984375 -0.349761962890625 0.41434936523436966 +1.203 -0.207000732421875 -0.353485107421875 0.41434936523436966 +1.203125 -0.207000732421875 -0.353485107421875 0.41434936523436966 +1.20325 -0.20916748046875 -0.357177734375 0.41434936523436966 +1.203375 -0.20916748046875 -0.357177734375 0.41434936523436966 +1.2035 -0.2113037109375 -0.360809326171875 0.41434936523436966 +1.203625 -0.213409423828125 -0.36444091796875 0.41434936523436966 +1.20375 -0.213409423828125 -0.36444091796875 0.41434936523436966 +1.203875 -0.215484619140625 -0.36798095703125 0.41434936523436966 +1.204 -0.215484619140625 -0.36798095703125 0.41434936523436966 +1.2041250000000002 -0.217559814453125 -0.37152099609375 0.41434936523436966 +1.20425 -0.2196044921875 -0.375 0.41434936523436966 +1.204375 -0.2196044921875 -0.375 0.41434936523436966 +1.2045000000000002 -0.22161865234375 -0.378448486328125 0.41434936523436966 +1.204625 -0.22161865234375 -0.378448486328125 0.41434936523436966 +1.20475 -0.223602294921875 -0.3818359375 0.41434936523436966 +1.204875 -0.225555419921875 -0.38519287109375 0.41434936523436966 +1.205 -0.225555419921875 -0.38519287109375 0.41434936523436966 +1.205125 -0.227508544921875 -0.388519287109375 0.41434936523436966 +1.20525 -0.227508544921875 -0.388519287109375 0.41434936523436966 +1.205375 -0.22943115234375 -0.39178466796875 0.41434936523436966 +1.2055 -0.2313232421875 -0.39501953125 0.41434936523436966 +1.205625 -0.2313232421875 -0.39501953125 0.41434936523436966 +1.20575 -0.233184814453125 -0.398193359375 0.41434936523436966 +1.205875 -0.233184814453125 -0.398193359375 0.41434936523436966 +1.206 -0.235015869140625 -0.401336669921875 0.41434936523436966 +1.2061250000000002 -0.236846923828125 -0.404449462890625 0.41434936523436966 +1.20625 -0.236846923828125 -0.404449462890625 0.41434936523436966 +1.206375 -0.2386474609375 -0.407501220703125 0.41434936523436966 +1.2065000000000002 -0.2386474609375 -0.407501220703125 0.41434936523436966 +1.206625 -0.240386962890625 -0.4105224609375 0.41434936523436966 +1.20675 -0.24212646484375 -0.413482666015625 0.41434936523436966 +1.206875 -0.24212646484375 -0.413482666015625 0.41434936523436966 +1.207 -0.24383544921875 -0.416412353515625 0.41434936523436966 +1.207125 -0.24383544921875 -0.416412353515625 0.41434936523436966 +1.20725 -0.245513916015625 -0.419281005859375 0.41434936523436966 +1.207375 -0.2471923828125 -0.422119140625 0.41434936523436966 +1.2075 -0.2471923828125 -0.422119140625 0.41434936523436966 +1.207625 -0.248809814453125 -0.424896240234375 0.41434936523436966 +1.20775 -0.248809814453125 -0.424896240234375 0.41434936523436966 +1.207875 -0.250396728515625 -0.4276123046875 0.41434936523436966 +1.208 -0.251983642578125 -0.4302978515625 0.41434936523436966 +1.2081250000000002 -0.251983642578125 -0.4302978515625 0.41434936523436966 +1.20825 -0.2535400390625 -0.432952880859375 0.41434936523436966 +1.208375 -0.2535400390625 -0.432952880859375 0.41434936523436966 +1.2085000000000002 -0.25506591796875 -0.435546875 0.41434936523436966 +1.208625 -0.25653076171875 -0.438079833984375 0.41434936523436966 +1.20875 -0.25653076171875 -0.438079833984375 0.41434936523436966 +1.208875 -0.25799560546875 -0.440582275390625 0.41434936523436966 +1.209 -0.25799560546875 -0.440582275390625 0.41434936523436966 +1.209125 -0.259429931640625 -0.44305419921875 0.41434936523436966 +1.20925 -0.260833740234375 -0.4454345703125 0.41434936523436966 +1.209375 -0.260833740234375 -0.4454345703125 0.41434936523436966 +1.2095 -0.26220703125 -0.447784423828125 0.41434936523436966 +1.209625 -0.26220703125 -0.447784423828125 0.41434936523436966 +1.20975 -0.263580322265625 -0.450103759765625 0.41434936523436966 +1.209875 -0.264892578125 -0.452362060546875 0.41434936523436966 +1.21 -0.264892578125 -0.452362060546875 0.41434936523436966 +1.2101250000000002 -0.26617431640625 -0.454559326171875 0.41434936523436966 +1.21025 -0.26617431640625 -0.454559326171875 0.41434936523436966 +1.210375 -0.2674560546875 -0.45672607421875 0.41434936523436966 +1.2105000000000002 -0.2686767578125 -0.458831787109375 0.41434936523436966 +1.210625 -0.2686767578125 -0.458831787109375 0.41434936523436966 +1.21075 -0.269866943359375 -0.46087646484375 0.41434936523436966 +1.210875 -0.269866943359375 -0.46087646484375 0.41434936523436966 +1.211 -0.27105712890625 -0.462890625 0.41434936523436966 +1.211125 -0.272186279296875 -0.464813232421875 0.41434936523436966 +1.21125 -0.272186279296875 -0.464813232421875 0.41434936523436966 +1.211375 -0.2733154296875 -0.46673583984375 0.41434936523436966 +1.2115 -0.2733154296875 -0.46673583984375 0.41434936523436966 +1.211625 -0.274383544921875 -0.46856689453125 0.41434936523436966 +1.21175 -0.27545166015625 -0.470367431640625 0.41434936523436966 +1.211875 -0.27545166015625 -0.470367431640625 0.41434936523436966 +1.212 -0.276458740234375 -0.472137451171875 0.41434936523436966 +1.2121250000000002 -0.276458740234375 -0.472137451171875 0.41434936523436966 +1.21225 -0.2774658203125 -0.47381591796875 0.41434936523436966 +1.212375 -0.2784423828125 -0.4754638671875 0.41434936523436966 +1.2125000000000002 -0.2784423828125 -0.4754638671875 0.41434936523436966 +1.212625 -0.27935791015625 -0.47705078125 0.41434936523436966 +1.21275 -0.27935791015625 -0.47705078125 0.41434936523436966 +1.212875 -0.2802734375 -0.478607177734375 0.41434936523436966 +1.213 -0.2811279296875 -0.480072021484375 0.41434936523436966 +1.213125 -0.2811279296875 -0.480072021484375 0.41434936523436966 +1.21325 -0.281982421875 -0.48150634765625 0.41434936523436966 +1.213375 -0.281982421875 -0.48150634765625 0.41434936523436966 +1.2135 -0.28277587890625 -0.48291015625 0.41434936523436966 +1.213625 -0.2835693359375 -0.484222412109375 0.41434936523436966 +1.21375 -0.2835693359375 -0.484222412109375 0.41434936523436966 +1.213875 -0.2843017578125 -0.485504150390625 0.41434936523436966 +1.214 -0.2843017578125 -0.485504150390625 0.41434936523436966 +1.2141250000000002 -0.2850341796875 -0.486724853515625 0.41434936523436966 +1.21425 -0.28570556640625 -0.487884521484375 0.41434936523436966 +1.214375 -0.28570556640625 -0.487884521484375 0.41434936523436966 +1.2145000000000002 -0.286346435546875 -0.489013671875 0.41434936523436966 +1.214625 -0.286346435546875 -0.489013671875 0.41434936523436966 +1.21475 -0.2869873046875 -0.490081787109375 0.41434936523436966 +1.214875 -0.287567138671875 -0.4910888671875 0.41434936523436966 +1.215 -0.287567138671875 -0.4910888671875 0.41434936523436966 +1.215125 -0.28814697265625 -0.492034912109375 0.41434936523436966 +1.21525 -0.28814697265625 -0.492034912109375 0.41434936523436966 +1.215375 -0.288665771484375 -0.492950439453125 0.41434936523436966 +1.2155 -0.289154052734375 -0.4937744140625 0.41434936523436966 +1.215625 -0.289154052734375 -0.4937744140625 0.41434936523436966 +1.21575 -0.28961181640625 -0.49456787109375 0.41434936523436966 +1.215875 -0.28961181640625 -0.49456787109375 0.41434936523436966 +1.216 -0.48284912109375 -0.49530029296875 0.025122070312493812 +1.2161250000000002 -0.4835205078125 -0.496002197265625 0.025122070312493812 +1.21625 -0.4835205078125 -0.496002197265625 0.025122070312493812 +1.216375 -0.484130859375 -0.496612548828125 0.025122070312493812 +1.2165 -0.484130859375 -0.496612548828125 0.025122070312493812 +1.216625 -0.48468017578125 -0.4971923828125 0.025122070312493812 +1.21675 -0.485198974609375 -0.497711181640625 0.025122070312493812 +1.216875 -0.485198974609375 -0.497711181640625 0.025122070312493812 +1.217 -0.48565673828125 -0.498199462890625 0.025122070312493812 +1.217125 -0.48565673828125 -0.498199462890625 0.025122070312493812 +1.21725 -0.486053466796875 -0.49859619140625 0.025122070312493812 +1.217375 -0.48638916015625 -0.49896240234375 0.025122070312493812 +1.2175 -0.48638916015625 -0.49896240234375 0.025122070312493812 +1.217625 -0.4866943359375 -0.499267578125 0.025122070312493812 +1.21775 -0.4866943359375 -0.499267578125 0.025122070312493812 +1.217875 -0.4869384765625 -0.49951171875 0.025122070312493812 +1.218 -0.48712158203125 -0.49969482421875 0.025122070312493812 +1.2181250000000002 -0.48712158203125 -0.49969482421875 0.025122070312493812 +1.21825 -0.48724365234375 -0.49981689453125 0.025122070312493812 +1.218375 -0.48724365234375 -0.49981689453125 0.025122070312493812 +1.2185 -0.487335205078125 -0.499908447265625 0.025122070312493812 +1.218625 -0.48736572265625 -0.49993896484375 0.025122070312493812 +1.21875 -0.48736572265625 -0.49993896484375 0.025122070312493812 +1.218875 -0.487335205078125 -0.499908447265625 0.025122070312493812 +1.219 -0.487335205078125 -0.499908447265625 0.025122070312493812 +1.219125 -0.48724365234375 -0.49981689453125 0.025122070312493812 +1.21925 -0.48712158203125 -0.49969482421875 0.025122070312493812 +1.219375 -0.48712158203125 -0.49969482421875 0.025122070312493812 +1.2195 -0.4869384765625 -0.49951171875 0.025122070312493812 +1.219625 -0.4869384765625 -0.49951171875 0.025122070312493812 +1.2197500000000002 -0.4866943359375 -0.499267578125 0.025122070312493812 +1.219875 -0.48638916015625 -0.49896240234375 0.025122070312493812 +1.22 -0.48638916015625 -0.49896240234375 0.025122070312493812 +1.2201250000000002 -0.486053466796875 -0.49859619140625 0.025122070312493812 +1.22025 -0.486053466796875 -0.49859619140625 0.025122070312493812 +1.220375 -0.48565673828125 -0.498199462890625 0.025122070312493812 +1.2205 -0.485198974609375 -0.497711181640625 0.025122070312493812 +1.220625 -0.485198974609375 -0.497711181640625 0.025122070312493812 +1.22075 -0.48468017578125 -0.4971923828125 0.025122070312493812 +1.220875 -0.48468017578125 -0.4971923828125 0.025122070312493812 +1.221 -0.484130859375 -0.496612548828125 0.025122070312493812 +1.221125 -0.4835205078125 -0.496002197265625 0.025122070312493812 +1.22125 -0.4835205078125 -0.496002197265625 0.025122070312493812 +1.221375 -0.48284912109375 -0.49530029296875 0.025122070312493812 +1.2215 -0.48284912109375 -0.49530029296875 0.025122070312493812 +1.221625 -0.48211669921875 -0.49456787109375 0.025122070312493812 +1.2217500000000002 -0.481353759765625 -0.4937744140625 0.025122070312493812 +1.221875 -0.481353759765625 -0.4937744140625 0.025122070312493812 +1.222 -0.48052978515625 -0.492950439453125 0.025122070312493812 +1.2221250000000002 -0.48052978515625 -0.492950439453125 0.025122070312493812 +1.22225 -0.47967529296875 -0.492034912109375 0.025122070312493812 +1.222375 -0.478729248046875 -0.4910888671875 0.025122070312493812 +1.2225 -0.478729248046875 -0.4910888671875 0.025122070312493812 +1.222625 -0.477752685546875 -0.490081787109375 0.025122070312493812 +1.22275 -0.477752685546875 -0.490081787109375 0.025122070312493812 +1.222875 -0.476715087890625 -0.489013671875 0.025122070312493812 +1.223 -0.475616455078125 -0.487884521484375 0.025122070312493812 +1.223125 -0.475616455078125 -0.487884521484375 0.025122070312493812 +1.22325 -0.4744873046875 -0.486724853515625 0.025122070312493812 +1.223375 -0.4744873046875 -0.486724853515625 0.025122070312493812 +1.2235 -0.473297119140625 -0.485504150390625 0.025122070312493812 +1.223625 -0.4720458984375 -0.484222412109375 0.025122070312493812 +1.2237500000000002 -0.4720458984375 -0.484222412109375 0.025122070312493812 +1.223875 -0.47076416015625 -0.48291015625 0.025122070312493812 +1.224 -0.47076416015625 -0.48291015625 0.025122070312493812 +1.2241250000000002 -0.469390869140625 -0.48150634765625 0.025122070312493812 +1.22425 -0.467987060546875 -0.480072021484375 0.025122070312493812 +1.224375 -0.467987060546875 -0.480072021484375 0.025122070312493812 +1.2245 -0.466552734375 -0.478607177734375 0.025122070312493812 +1.224625 -0.466552734375 -0.478607177734375 0.025122070312493812 +1.22475 -0.465057373046875 -0.47705078125 0.025122070312493812 +1.224875 -0.4635009765625 -0.4754638671875 0.025122070312493812 +1.225 -0.4635009765625 -0.4754638671875 0.025122070312493812 +1.225125 -0.4619140625 -0.47381591796875 0.025122070312493812 +1.22525 -0.4619140625 -0.47381591796875 0.025122070312493812 +1.225375 -0.460235595703125 -0.472137451171875 0.025122070312493812 +1.2255 -0.458526611328125 -0.470367431640625 0.025122070312493812 +1.225625 -0.458526611328125 -0.470367431640625 0.025122070312493812 +1.2257500000000002 -0.456787109375 -0.46856689453125 0.025122070312493812 +1.225875 -0.456787109375 -0.46856689453125 0.025122070312493812 +1.226 -0.454986572265625 -0.46673583984375 0.025122070312493812 +1.2261250000000002 -0.453125 -0.464813232421875 0.025122070312493812 +1.22625 -0.453125 -0.464813232421875 0.025122070312493812 +1.226375 -0.45123291015625 -0.462890625 0.025122070312493812 +1.2265 -0.45123291015625 -0.462890625 0.025122070312493812 +1.226625 -0.44927978515625 -0.46087646484375 0.025122070312493812 +1.22675 -0.447265625 -0.458831787109375 0.025122070312493812 +1.226875 -0.447265625 -0.458831787109375 0.025122070312493812 +1.227 -0.445220947265625 -0.45672607421875 0.025122070312493812 +1.227125 -0.445220947265625 -0.45672607421875 0.025122070312493812 +1.22725 -0.443115234375 -0.454559326171875 0.025122070312493812 +1.227375 -0.44097900390625 -0.452362060546875 0.025122070312493812 +1.2275 -0.44097900390625 -0.452362060546875 0.025122070312493812 +1.227625 -0.43878173828125 -0.450103759765625 0.025122070312493812 +1.2277500000000002 -0.43878173828125 -0.450103759765625 0.025122070312493812 +1.227875 -0.4365234375 -0.447784423828125 0.025122070312493812 +1.228 -0.434234619140625 -0.4454345703125 0.025122070312493812 +1.2281250000000002 -0.434234619140625 -0.4454345703125 0.025122070312493812 +1.22825 -0.431915283203125 -0.44305419921875 0.025122070312493812 +1.228375 -0.431915283203125 -0.44305419921875 0.025122070312493812 +1.2285 -0.42950439453125 -0.440582275390625 0.025122070312493812 +1.228625 -0.42706298828125 -0.438079833984375 0.025122070312493812 +1.22875 -0.42706298828125 -0.438079833984375 0.025122070312493812 +1.228875 -0.424591064453125 -0.435546875 0.025122070312493812 +1.229 -0.424591064453125 -0.435546875 0.025122070312493812 +1.229125 -0.42205810546875 -0.432952880859375 0.025122070312493812 +1.22925 -0.41949462890625 -0.4302978515625 0.025122070312493812 +1.229375 -0.41949462890625 -0.4302978515625 0.025122070312493812 +1.2295 -0.4168701171875 -0.4276123046875 0.025122070312493812 +1.229625 -0.4168701171875 -0.4276123046875 0.025122070312493812 +1.2297500000000002 -0.414215087890625 -0.424896240234375 0.025122070312493812 +1.229875 -0.4114990234375 -0.422119140625 0.025122070312493812 +1.23 -0.4114990234375 -0.422119140625 0.025122070312493812 +1.2301250000000002 -0.408721923828125 -0.419281005859375 0.025122070312493812 +1.23025 -0.408721923828125 -0.419281005859375 0.025122070312493812 +1.230375 -0.40594482421875 -0.416412353515625 0.025122070312493812 +1.2305 -0.403076171875 -0.413482666015625 0.025122070312493812 +1.230625 -0.403076171875 -0.413482666015625 0.025122070312493812 +1.23075 -0.400177001953125 -0.4105224609375 0.025122070312493812 +1.230875 -0.400177001953125 -0.4105224609375 0.025122070312493812 +1.231 -0.397247314453125 -0.407501220703125 0.025122070312493812 +1.231125 -0.394287109375 -0.404449462890625 0.025122070312493812 +1.23125 -0.394287109375 -0.404449462890625 0.025122070312493812 +1.231375 -0.3912353515625 -0.401336669921875 0.025122070312493812 +1.2315 -0.3912353515625 -0.401336669921875 0.025122070312493812 +1.231625 -0.38818359375 -0.398193359375 0.025122070312493812 +1.2317500000000002 -0.385101318359375 -0.39501953125 0.025122070312493812 +1.231875 -0.385101318359375 -0.39501953125 0.025122070312493812 +1.232 -0.381927490234375 -0.39178466796875 0.025122070312493812 +1.232125 -0.381927490234375 -0.39178466796875 0.025122070312493812 +1.23225 -0.378753662109375 -0.388519287109375 0.025122070312493812 +1.232375 -0.375518798828125 -0.38519287109375 0.025122070312493812 +1.2325 -0.375518798828125 -0.38519287109375 0.025122070312493812 +1.232625 -0.37225341796875 -0.3818359375 0.025122070312493812 +1.23275 -0.37225341796875 -0.3818359375 0.025122070312493812 +1.232875 -0.368927001953125 -0.378448486328125 0.025122070312493812 +1.233 -0.365570068359375 -0.375 0.025122070312493812 +1.233125 -0.365570068359375 -0.375 0.025122070312493812 +1.23325 -0.3621826171875 -0.37152099609375 0.025122070312493812 +1.233375 -0.3621826171875 -0.37152099609375 0.025122070312493812 +1.2335 -0.358734130859375 -0.36798095703125 0.025122070312493812 +1.233625 -0.355255126953125 -0.36444091796875 0.025122070312493812 +1.2337500000000002 -0.355255126953125 -0.36444091796875 0.025122070312493812 +1.233875 -0.35174560546875 -0.360809326171875 0.025122070312493812 +1.234 -0.35174560546875 -0.360809326171875 0.025122070312493812 +1.234125 -0.34820556640625 -0.357177734375 0.025122070312493812 +1.23425 -0.3446044921875 -0.353485107421875 0.025122070312493812 +1.234375 -0.3446044921875 -0.353485107421875 0.025122070312493812 +1.2345 -0.340972900390625 -0.349761962890625 0.025122070312493812 +1.234625 -0.340972900390625 -0.349761962890625 0.025122070312493812 +1.23475 -0.337310791015625 -0.34600830078125 0.025122070312493812 +1.234875 -0.3336181640625 -0.34222412109375 0.025122070312493812 +1.235 -0.3336181640625 -0.34222412109375 0.025122070312493812 +1.235125 -0.329864501953125 -0.33837890625 0.025122070312493812 +1.23525 -0.329864501953125 -0.33837890625 0.025122070312493812 +1.2353750000000002 -0.32611083984375 -0.334503173828125 0.025122070312493812 +1.2355 -0.322296142578125 -0.330596923828125 0.025122070312493812 +1.235625 -0.322296142578125 -0.330596923828125 0.025122070312493812 +1.2357500000000002 -0.318450927734375 -0.32666015625 0.025122070312493812 +1.235875 -0.318450927734375 -0.32666015625 0.025122070312493812 +1.236 -0.314544677734375 -0.322662353515625 0.025122070312493812 +1.236125 -0.310638427734375 -0.31866455078125 0.025122070312493812 +1.23625 -0.310638427734375 -0.31866455078125 0.025122070312493812 +1.236375 -0.30670166015625 -0.314605712890625 0.025122070312493812 +1.2365 -0.30670166015625 -0.314605712890625 0.025122070312493812 +1.236625 -0.302703857421875 -0.310516357421875 0.025122070312493812 +1.23675 -0.2987060546875 -0.306396484375 0.025122070312493812 +1.236875 -0.2987060546875 -0.306396484375 0.025122070312493812 +1.237 -0.294647216796875 -0.30224609375 0.025122070312493812 +1.237125 -0.294647216796875 -0.30224609375 0.025122070312493812 +1.23725 -0.290557861328125 -0.298065185546875 0.025122070312493812 +1.2373750000000002 -0.28643798828125 -0.2938232421875 0.025122070312493812 +1.2375 -0.28643798828125 -0.2938232421875 0.025122070312493812 +1.237625 -0.282318115234375 -0.289581298828125 0.025122070312493812 +1.2377500000000002 -0.282318115234375 -0.289581298828125 0.025122070312493812 +1.237875 -0.27813720703125 -0.285308837890625 0.025122070312493812 +1.238 -0.27392578125 -0.280975341796875 0.025122070312493812 +1.238125 -0.27392578125 -0.280975341796875 0.025122070312493812 +1.23825 -0.269683837890625 -0.276641845703125 0.025122070312493812 +1.238375 -0.269683837890625 -0.276641845703125 0.025122070312493812 +1.2385 -0.26544189453125 -0.27227783203125 0.025122070312493812 +1.238625 -0.261138916015625 -0.267852783203125 0.025122070312493812 +1.23875 -0.261138916015625 -0.267852783203125 0.025122070312493812 +1.238875 -0.256805419921875 -0.263427734375 0.025122070312493812 +1.239 -0.256805419921875 -0.263427734375 0.025122070312493812 +1.239125 -0.252471923828125 -0.25897216796875 0.025122070312493812 +1.23925 -0.248077392578125 -0.25445556640625 0.025122070312493812 +1.2393750000000002 -0.248077392578125 -0.25445556640625 0.025122070312493812 +1.2395 -0.243682861328125 -0.249969482421875 0.025122070312493812 +1.239625 -0.243682861328125 -0.249969482421875 0.025122070312493812 +1.2397500000000002 -0.239227294921875 -0.24542236328125 0.025122070312493812 +1.239875 -0.234771728515625 -0.2408447265625 0.025122070312493812 +1.24 -0.234771728515625 -0.2408447265625 0.025122070312493812 +1.240125 -0.23028564453125 -0.236236572265625 0.025122070312493812 +1.24025 -0.23028564453125 -0.236236572265625 0.025122070312493812 +1.240375 -0.22576904296875 -0.231597900390625 0.025122070312493812 +1.2405 -0.22125244140625 -0.226959228515625 0.025122070312493812 +1.240625 -0.22125244140625 -0.226959228515625 0.025122070312493812 +1.24075 -0.2166748046875 -0.2222900390625 0.025122070312493812 +1.240875 -0.2166748046875 -0.2222900390625 0.025122070312493812 +1.241 -0.21209716796875 -0.21759033203125 0.025122070312493812 +1.241125 -0.207489013671875 -0.212860107421875 0.025122070312493812 +1.24125 -0.207489013671875 -0.212860107421875 0.025122070312493812 +1.2413750000000002 -0.202880859375 -0.208099365234375 0.025122070312493812 +1.2415 -0.202880859375 -0.208099365234375 0.025122070312493812 +1.241625 -0.198211669921875 -0.203338623046875 0.025122070312493812 +1.2417500000000002 -0.19354248046875 -0.19854736328125 0.025122070312493812 +1.241875 -0.19354248046875 -0.19854736328125 0.025122070312493812 +1.242 -0.1888427734375 -0.1937255859375 0.025122070312493812 +1.242125 -0.1888427734375 -0.1937255859375 0.025122070312493812 +1.24225 -0.184112548828125 -0.188873291015625 0.025122070312493812 +1.242375 -0.17938232421875 -0.18402099609375 0.025122070312493812 +1.2425 -0.17938232421875 -0.18402099609375 0.025122070312493812 +1.242625 -0.174652099609375 -0.17913818359375 0.025122070312493812 +1.24275 -0.174652099609375 -0.17913818359375 0.025122070312493812 +1.242875 -0.16986083984375 -0.17425537109375 0.025122070312493812 +1.243 -0.165069580078125 -0.169342041015625 0.025122070312493812 +1.243125 -0.165069580078125 -0.169342041015625 0.025122070312493812 +1.24325 -0.160247802734375 -0.164398193359375 0.025122070312493812 +1.2433750000000002 -0.160247802734375 -0.164398193359375 0.025122070312493812 +1.2435 -0.155426025390625 -0.159454345703125 0.025122070312493812 +1.243625 -0.15057373046875 -0.15447998046875 0.025122070312493812 +1.2437500000000002 -0.15057373046875 -0.15447998046875 0.025122070312493812 +1.243875 -0.145721435546875 -0.14947509765625 0.025122070312493812 +1.244 -0.145721435546875 -0.14947509765625 0.025122070312493812 +1.244125 -0.140838623046875 -0.14447021484375 0.025122070312493812 +1.24425 -0.135955810546875 -0.13946533203125 0.025122070312493812 +1.244375 -0.135955810546875 -0.13946533203125 0.025122070312493812 +1.2445 -0.13104248046875 -0.134429931640625 0.025122070312493812 +1.244625 -0.13104248046875 -0.134429931640625 0.025122070312493812 +1.24475 -0.126129150390625 -0.129364013671875 0.025122070312493812 +1.244875 -0.121185302734375 -0.124298095703125 0.025122070312493812 +1.245 -0.121185302734375 -0.124298095703125 0.025122070312493812 +1.245125 -0.116241455078125 -0.119232177734375 0.025122070312493812 +1.24525 -0.116241455078125 -0.119232177734375 0.025122070312493812 +1.2453750000000002 -0.11126708984375 -0.1141357421875 0.025122070312493812 +1.2455 -0.106292724609375 -0.109039306640625 0.025122070312493812 +1.245625 -0.106292724609375 -0.109039306640625 0.025122070312493812 +1.2457500000000002 -0.101318359375 -0.103912353515625 0.025122070312493812 +1.245875 -0.101318359375 -0.103912353515625 0.025122070312493812 +1.246 -0.0963134765625 -0.098785400390625 0.025122070312493812 +1.246125 -0.09130859375 -0.093658447265625 0.025122070312493812 +1.24625 -0.09130859375 -0.093658447265625 0.025122070312493812 +1.246375 -0.086273193359375 -0.0885009765625 0.025122070312493812 +1.2465 -0.086273193359375 -0.0885009765625 0.025122070312493812 +1.246625 -0.081268310546875 -0.083343505859375 0.025122070312493812 +1.24675 -0.076202392578125 -0.07818603515625 0.025122070312493812 +1.246875 -0.076202392578125 -0.07818603515625 0.025122070312493812 +1.247 -0.0711669921875 -0.072998046875 0.025122070312493812 +1.247125 -0.0711669921875 -0.072998046875 0.025122070312493812 +1.24725 -0.06610107421875 -0.06781005859375 0.025122070312493812 +1.2473750000000002 -0.061065673828125 -0.0626220703125 0.025122070312493812 +1.2475 -0.061065673828125 -0.0626220703125 0.025122070312493812 +1.247625 -0.055999755859375 -0.05743408203125 0.025122070312493812 +1.2477500000000002 -0.055999755859375 -0.05743408203125 0.025122070312493812 +1.247875 -0.050933837890625 -0.05224609375 0.025122070312493812 +1.248 -0.047027587890625 -0.029693603515625 -0.3681030273437555 +1.248125 -0.047027587890625 -0.029693603515625 -0.3681030273437555 +1.24825 -0.04180908203125 -0.026397705078125 -0.3681030273437555 +1.248375 -0.04180908203125 -0.026397705078125 -0.3681030273437555 +1.2485 -0.036590576171875 -0.023101806640625 -0.3681030273437555 +1.248625 -0.0313720703125 -0.019805908203125 -0.3681030273437555 +1.24875 -0.0313720703125 -0.019805908203125 -0.3681030273437555 +1.248875 -0.026123046875 -0.016510009765625 -0.3681030273437555 +1.249 -0.026123046875 -0.016510009765625 -0.3681030273437555 +1.249125 -0.020904541015625 -0.013214111328125 -0.3681030273437555 +1.24925 -0.01568603515625 -0.009918212890625 -0.3681030273437555 +1.2493750000000002 -0.01568603515625 -0.009918212890625 -0.3681030273437555 +1.2495 -0.01043701171875 -0.006591796875 -0.3681030273437555 +1.249625 -0.01043701171875 -0.006591796875 -0.3681030273437555 +1.24975 -0.005218505859375 -0.0032958984375 -0.3681030273437555 +1.249875 0.0 0.0 -0.3681030273437555 +1.25 0.0 0.0 -0.3681030273437555 +1.250125 0.005218505859375 0.0032958984375 -0.3681030273437555 +1.25025 0.005218505859375 0.0032958984375 -0.3681030273437555 +1.250375 0.01043701171875 0.006591796875 -0.3681030273437555 +1.2505 0.01568603515625 0.009918212890625 -0.3681030273437555 +1.250625 0.01568603515625 0.009918212890625 -0.3681030273437555 +1.25075 0.020904541015625 0.013214111328125 -0.3681030273437555 +1.250875 0.020904541015625 0.013214111328125 -0.3681030273437555 +1.2510000000000002 0.026123046875 0.016510009765625 -0.3681030273437555 +1.251125 0.0313720703125 0.019805908203125 -0.3681030273437555 +1.25125 0.0313720703125 0.019805908203125 -0.3681030273437555 +1.2513750000000002 0.036590576171875 0.023101806640625 -0.3681030273437555 +1.2515 0.036590576171875 0.023101806640625 -0.3681030273437555 +1.251625 0.04180908203125 0.026397705078125 -0.3681030273437555 +1.25175 0.047027587890625 0.029693603515625 -0.3681030273437555 +1.251875 0.047027587890625 0.029693603515625 -0.3681030273437555 +1.252 0.05224609375 0.032989501953125 -0.3681030273437555 +1.252125 0.05224609375 0.032989501953125 -0.3681030273437555 +1.25225 0.05743408203125 0.036285400390625 -0.3681030273437555 +1.252375 0.0626220703125 0.039581298828125 -0.3681030273437555 +1.2525 0.0626220703125 0.039581298828125 -0.3681030273437555 +1.252625 0.06781005859375 0.0428466796875 -0.3681030273437555 +1.25275 0.06781005859375 0.0428466796875 -0.3681030273437555 +1.252875 0.072998046875 0.046112060546875 -0.3681030273437555 +1.2530000000000002 0.07818603515625 0.049407958984375 -0.3681030273437555 +1.253125 0.07818603515625 0.049407958984375 -0.3681030273437555 +1.25325 0.083343505859375 0.05267333984375 -0.3681030273437555 +1.2533750000000002 0.083343505859375 0.05267333984375 -0.3681030273437555 +1.2535 0.0885009765625 0.055908203125 -0.3681030273437555 +1.253625 0.093658447265625 0.059173583984375 -0.3681030273437555 +1.25375 0.093658447265625 0.059173583984375 -0.3681030273437555 +1.253875 0.098785400390625 0.062408447265625 -0.3681030273437555 +1.254 0.098785400390625 0.062408447265625 -0.3681030273437555 +1.254125 0.103912353515625 0.065643310546875 -0.3681030273437555 +1.25425 0.109039306640625 0.068878173828125 -0.3681030273437555 +1.254375 0.109039306640625 0.068878173828125 -0.3681030273437555 +1.2545 0.1141357421875 0.072113037109375 -0.3681030273437555 +1.254625 0.1141357421875 0.072113037109375 -0.3681030273437555 +1.25475 0.119232177734375 0.075347900390625 -0.3681030273437555 +1.254875 0.124298095703125 0.078521728515625 -0.3681030273437555 +1.2550000000000002 0.124298095703125 0.078521728515625 -0.3681030273437555 +1.255125 0.129364013671875 0.08172607421875 -0.3681030273437555 +1.25525 0.129364013671875 0.08172607421875 -0.3681030273437555 +1.2553750000000002 0.134429931640625 0.084930419921875 -0.3681030273437555 +1.2555 0.13946533203125 0.088104248046875 -0.3681030273437555 +1.255625 0.13946533203125 0.088104248046875 -0.3681030273437555 +1.25575 0.14447021484375 0.091278076171875 -0.3681030273437555 +1.255875 0.14447021484375 0.091278076171875 -0.3681030273437555 +1.256 0.14947509765625 0.094451904296875 -0.3681030273437555 +1.256125 0.15447998046875 0.09759521484375 -0.3681030273437555 +1.25625 0.15447998046875 0.09759521484375 -0.3681030273437555 +1.256375 0.159454345703125 0.100738525390625 -0.3681030273437555 +1.2565 0.159454345703125 0.100738525390625 -0.3681030273437555 +1.256625 0.164398193359375 0.103851318359375 -0.3681030273437555 +1.25675 0.169342041015625 0.10699462890625 -0.3681030273437555 +1.256875 0.169342041015625 0.10699462890625 -0.3681030273437555 +1.2570000000000002 0.17425537109375 0.110076904296875 -0.3681030273437555 +1.257125 0.17425537109375 0.110076904296875 -0.3681030273437555 +1.25725 0.17913818359375 0.113189697265625 -0.3681030273437555 +1.2573750000000002 0.18402099609375 0.11627197265625 -0.3681030273437555 +1.2575 0.18402099609375 0.11627197265625 -0.3681030273437555 +1.257625 0.188873291015625 0.11932373046875 -0.3681030273437555 +1.25775 0.188873291015625 0.11932373046875 -0.3681030273437555 +1.257875 0.1937255859375 0.122406005859375 -0.3681030273437555 +1.258 0.19854736328125 0.12542724609375 -0.3681030273437555 +1.258125 0.19854736328125 0.12542724609375 -0.3681030273437555 +1.25825 0.203338623046875 0.12847900390625 -0.3681030273437555 +1.258375 0.203338623046875 0.12847900390625 -0.3681030273437555 +1.2585 0.208099365234375 0.1314697265625 -0.3681030273437555 +1.258625 0.212860107421875 0.134490966796875 -0.3681030273437555 +1.25875 0.212860107421875 0.134490966796875 -0.3681030273437555 +1.258875 0.21759033203125 0.137481689453125 -0.3681030273437555 +1.2590000000000002 0.21759033203125 0.137481689453125 -0.3681030273437555 +1.259125 0.2222900390625 0.14044189453125 -0.3681030273437555 +1.25925 0.226959228515625 0.143402099609375 -0.3681030273437555 +1.2593750000000002 0.226959228515625 0.143402099609375 -0.3681030273437555 +1.2595 0.231597900390625 0.146331787109375 -0.3681030273437555 +1.259625 0.231597900390625 0.146331787109375 -0.3681030273437555 +1.25975 0.236236572265625 0.149261474609375 -0.3681030273437555 +1.259875 0.2408447265625 0.15216064453125 -0.3681030273437555 +1.26 0.2408447265625 0.15216064453125 -0.3681030273437555 +1.260125 0.24542236328125 0.155059814453125 -0.3681030273437555 +1.26025 0.24542236328125 0.155059814453125 -0.3681030273437555 +1.260375 0.249969482421875 0.157928466796875 -0.3681030273437555 +1.2605 0.25445556640625 0.1607666015625 -0.3681030273437555 +1.260625 0.25445556640625 0.1607666015625 -0.3681030273437555 +1.26075 0.25897216796875 0.16363525390625 -0.3681030273437555 +1.260875 0.25897216796875 0.16363525390625 -0.3681030273437555 +1.2610000000000002 0.263427734375 0.16644287109375 -0.3681030273437555 +1.261125 0.267852783203125 0.16925048828125 -0.3681030273437555 +1.26125 0.267852783203125 0.16925048828125 -0.3681030273437555 +1.2613750000000002 0.27227783203125 0.172027587890625 -0.3681030273437555 +1.2615 0.27227783203125 0.172027587890625 -0.3681030273437555 +1.261625 0.276641845703125 0.174774169921875 -0.3681030273437555 +1.26175 0.280975341796875 0.177520751953125 -0.3681030273437555 +1.261875 0.280975341796875 0.177520751953125 -0.3681030273437555 +1.262 0.285308837890625 0.180267333984375 -0.3681030273437555 +1.262125 0.285308837890625 0.180267333984375 -0.3681030273437555 +1.26225 0.289581298828125 0.1829833984375 -0.3681030273437555 +1.262375 0.2938232421875 0.185638427734375 -0.3681030273437555 +1.2625 0.2938232421875 0.185638427734375 -0.3681030273437555 +1.262625 0.298065185546875 0.188323974609375 -0.3681030273437555 +1.26275 0.298065185546875 0.188323974609375 -0.3681030273437555 +1.262875 0.30224609375 0.19097900390625 -0.3681030273437555 +1.2630000000000002 0.306396484375 0.193603515625 -0.3681030273437555 +1.263125 0.306396484375 0.193603515625 -0.3681030273437555 +1.26325 0.310516357421875 0.196197509765625 -0.3681030273437555 +1.2633750000000002 0.310516357421875 0.196197509765625 -0.3681030273437555 +1.2635 0.314605712890625 0.198760986328125 -0.3681030273437555 +1.263625 0.31866455078125 0.201324462890625 -0.3681030273437555 +1.26375 0.31866455078125 0.201324462890625 -0.3681030273437555 +1.263875 0.322662353515625 0.203887939453125 -0.3681030273437555 +1.264 0.322662353515625 0.203887939453125 -0.3681030273437555 +1.264125 0.32666015625 0.206390380859375 -0.3681030273437555 +1.26425 0.330596923828125 0.208892822265625 -0.3681030273437555 +1.264375 0.330596923828125 0.208892822265625 -0.3681030273437555 +1.2645 0.334503173828125 0.21136474609375 -0.3681030273437555 +1.264625 0.334503173828125 0.21136474609375 -0.3681030273437555 +1.26475 0.33837890625 0.21380615234375 -0.3681030273437555 +1.264875 0.34222412109375 0.216217041015625 -0.3681030273437555 +1.2650000000000002 0.34222412109375 0.216217041015625 -0.3681030273437555 +1.265125 0.34600830078125 0.2186279296875 -0.3681030273437555 +1.26525 0.34600830078125 0.2186279296875 -0.3681030273437555 +1.265375 0.349761962890625 0.22100830078125 -0.3681030273437555 +1.2655 0.353485107421875 0.223358154296875 -0.3681030273437555 +1.265625 0.353485107421875 0.223358154296875 -0.3681030273437555 +1.26575 0.357177734375 0.225677490234375 -0.3681030273437555 +1.265875 0.357177734375 0.225677490234375 -0.3681030273437555 +1.266 0.360809326171875 0.22796630859375 -0.3681030273437555 +1.266125 0.36444091796875 0.230255126953125 -0.3681030273437555 +1.26625 0.36444091796875 0.230255126953125 -0.3681030273437555 +1.266375 0.36798095703125 0.232513427734375 -0.3681030273437555 +1.2665 0.36798095703125 0.232513427734375 -0.3681030273437555 +1.2666250000000002 0.37152099609375 0.2347412109375 -0.3681030273437555 +1.26675 0.375 0.2369384765625 -0.3681030273437555 +1.266875 0.375 0.2369384765625 -0.3681030273437555 +1.2670000000000002 0.378448486328125 0.239105224609375 -0.3681030273437555 +1.267125 0.378448486328125 0.239105224609375 -0.3681030273437555 +1.26725 0.3818359375 0.24127197265625 -0.3681030273437555 +1.267375 0.38519287109375 0.243377685546875 -0.3681030273437555 +1.2675 0.38519287109375 0.243377685546875 -0.3681030273437555 +1.267625 0.388519287109375 0.2454833984375 -0.3681030273437555 +1.26775 0.388519287109375 0.2454833984375 -0.3681030273437555 +1.267875 0.39178466796875 0.24755859375 -0.3681030273437555 +1.268 0.39501953125 0.249603271484375 -0.3681030273437555 +1.268125 0.39501953125 0.249603271484375 -0.3681030273437555 +1.26825 0.398193359375 0.2515869140625 -0.3681030273437555 +1.268375 0.398193359375 0.2515869140625 -0.3681030273437555 +1.2685 0.401336669921875 0.253570556640625 -0.3681030273437555 +1.2686250000000002 0.404449462890625 0.25555419921875 -0.3681030273437555 +1.26875 0.404449462890625 0.25555419921875 -0.3681030273437555 +1.268875 0.407501220703125 0.257476806640625 -0.3681030273437555 +1.2690000000000002 0.407501220703125 0.257476806640625 -0.3681030273437555 +1.269125 0.4105224609375 0.259368896484375 -0.3681030273437555 +1.26925 0.413482666015625 0.26123046875 -0.3681030273437555 +1.269375 0.413482666015625 0.26123046875 -0.3681030273437555 +1.2695 0.416412353515625 0.263092041015625 -0.3681030273437555 +1.269625 0.416412353515625 0.263092041015625 -0.3681030273437555 +1.26975 0.419281005859375 0.264923095703125 -0.3681030273437555 +1.269875 0.422119140625 0.266693115234375 -0.3681030273437555 +1.27 0.422119140625 0.266693115234375 -0.3681030273437555 +1.270125 0.424896240234375 0.268463134765625 -0.3681030273437555 +1.27025 0.424896240234375 0.268463134765625 -0.3681030273437555 +1.270375 0.4276123046875 0.270172119140625 -0.3681030273437555 +1.2705 0.4302978515625 0.271881103515625 -0.3681030273437555 +1.2706250000000002 0.4302978515625 0.271881103515625 -0.3681030273437555 +1.27075 0.432952880859375 0.2735595703125 -0.3681030273437555 +1.270875 0.432952880859375 0.2735595703125 -0.3681030273437555 +1.2710000000000002 0.435546875 0.27520751953125 -0.3681030273437555 +1.271125 0.438079833984375 0.27679443359375 -0.3681030273437555 +1.27125 0.438079833984375 0.27679443359375 -0.3681030273437555 +1.271375 0.440582275390625 0.27838134765625 -0.3681030273437555 +1.2715 0.440582275390625 0.27838134765625 -0.3681030273437555 +1.271625 0.44305419921875 0.279937744140625 -0.3681030273437555 +1.27175 0.4454345703125 0.28143310546875 -0.3681030273437555 +1.271875 0.4454345703125 0.28143310546875 -0.3681030273437555 +1.272 0.447784423828125 0.282928466796875 -0.3681030273437555 +1.272125 0.447784423828125 0.282928466796875 -0.3681030273437555 +1.27225 0.450103759765625 0.284393310546875 -0.3681030273437555 +1.272375 0.452362060546875 0.285797119140625 -0.3681030273437555 +1.2725 0.452362060546875 0.285797119140625 -0.3681030273437555 +1.2726250000000002 0.454559326171875 0.287200927734375 -0.3681030273437555 +1.27275 0.454559326171875 0.287200927734375 -0.3681030273437555 +1.272875 0.45672607421875 0.28857421875 -0.3681030273437555 +1.2730000000000002 0.458831787109375 0.289886474609375 -0.3681030273437555 +1.273125 0.458831787109375 0.289886474609375 -0.3681030273437555 +1.27325 0.46087646484375 0.29119873046875 -0.3681030273437555 +1.273375 0.46087646484375 0.29119873046875 -0.3681030273437555 +1.2735 0.462890625 0.292449951171875 -0.3681030273437555 +1.273625 0.464813232421875 0.293670654296875 -0.3681030273437555 +1.27375 0.464813232421875 0.293670654296875 -0.3681030273437555 +1.273875 0.46673583984375 0.294891357421875 -0.3681030273437555 +1.274 0.46673583984375 0.294891357421875 -0.3681030273437555 +1.274125 0.46856689453125 0.296051025390625 -0.3681030273437555 +1.27425 0.470367431640625 0.29718017578125 -0.3681030273437555 +1.274375 0.470367431640625 0.29718017578125 -0.3681030273437555 +1.2745 0.472137451171875 0.298309326171875 -0.3681030273437555 +1.2746250000000002 0.472137451171875 0.298309326171875 -0.3681030273437555 +1.27475 0.47381591796875 0.29937744140625 -0.3681030273437555 +1.274875 0.4754638671875 0.3004150390625 -0.3681030273437555 +1.2750000000000002 0.4754638671875 0.3004150390625 -0.3681030273437555 +1.275125 0.47705078125 0.301422119140625 -0.3681030273437555 +1.27525 0.47705078125 0.301422119140625 -0.3681030273437555 +1.275375 0.478607177734375 0.302398681640625 -0.3681030273437555 +1.2755 0.480072021484375 0.303314208984375 -0.3681030273437555 +1.275625 0.480072021484375 0.303314208984375 -0.3681030273437555 +1.27575 0.48150634765625 0.304229736328125 -0.3681030273437555 +1.275875 0.48150634765625 0.304229736328125 -0.3681030273437555 +1.276 0.48291015625 0.30511474609375 -0.3681030273437555 +1.276125 0.484222412109375 0.305938720703125 -0.3681030273437555 +1.27625 0.484222412109375 0.305938720703125 -0.3681030273437555 +1.276375 0.485504150390625 0.3067626953125 -0.3681030273437555 +1.2765 0.485504150390625 0.3067626953125 -0.3681030273437555 +1.2766250000000002 0.486724853515625 0.307525634765625 -0.3681030273437555 +1.27675 0.487884521484375 0.308258056640625 -0.3681030273437555 +1.276875 0.487884521484375 0.308258056640625 -0.3681030273437555 +1.2770000000000002 0.489013671875 0.3089599609375 -0.3681030273437555 +1.277125 0.489013671875 0.3089599609375 -0.3681030273437555 +1.27725 0.490081787109375 0.30963134765625 -0.3681030273437555 +1.277375 0.4910888671875 0.310272216796875 -0.3681030273437555 +1.2775 0.4910888671875 0.310272216796875 -0.3681030273437555 +1.277625 0.492034912109375 0.310882568359375 -0.3681030273437555 +1.27775 0.492034912109375 0.310882568359375 -0.3681030273437555 +1.277875 0.492950439453125 0.31146240234375 -0.3681030273437555 +1.278 0.4937744140625 0.311981201171875 -0.3681030273437555 +1.278125 0.4937744140625 0.311981201171875 -0.3681030273437555 +1.27825 0.49456787109375 0.312469482421875 -0.3681030273437555 +1.278375 0.49456787109375 0.312469482421875 -0.3681030273437555 +1.2785 0.49530029296875 0.312957763671875 -0.3681030273437555 +1.2786250000000002 0.496002197265625 0.313385009765625 -0.3681030273437555 +1.27875 0.496002197265625 0.313385009765625 -0.3681030273437555 +1.278875 0.496612548828125 0.31378173828125 -0.3681030273437555 +1.2790000000000002 0.496612548828125 0.31378173828125 -0.3681030273437555 +1.279125 0.4971923828125 0.31414794921875 -0.3681030273437555 +1.27925 0.497711181640625 0.314483642578125 -0.3681030273437555 +1.279375 0.497711181640625 0.314483642578125 -0.3681030273437555 +1.2795 0.498199462890625 0.31475830078125 -0.3681030273437555 +1.279625 0.498199462890625 0.31475830078125 -0.3681030273437555 +1.27975 0.49859619140625 0.315032958984375 -0.3681030273437555 +1.279875 0.49896240234375 0.31524658203125 -0.3681030273437555 +1.28 0.49896240234375 0.148345947265625 -0.7025939941406295 +1.280125 0.499267578125 0.1484375 -0.7025939941406295 +1.28025 0.499267578125 0.1484375 -0.7025939941406295 +1.280375 0.49951171875 0.14849853515625 -0.7025939941406295 +1.2805 0.49969482421875 0.1485595703125 -0.7025939941406295 +1.2806250000000002 0.49969482421875 0.1485595703125 -0.7025939941406295 +1.28075 0.49981689453125 0.148590087890625 -0.7025939941406295 +1.280875 0.49981689453125 0.148590087890625 -0.7025939941406295 +1.281 0.499908447265625 0.14862060546875 -0.7025939941406295 +1.281125 0.49993896484375 0.14862060546875 -0.7025939941406295 +1.28125 0.49993896484375 0.14862060546875 -0.7025939941406295 +1.281375 0.499908447265625 0.14862060546875 -0.7025939941406295 +1.2815 0.499908447265625 0.14862060546875 -0.7025939941406295 +1.281625 0.49981689453125 0.148590087890625 -0.7025939941406295 +1.28175 0.49969482421875 0.1485595703125 -0.7025939941406295 +1.281875 0.49969482421875 0.1485595703125 -0.7025939941406295 +1.282 0.49951171875 0.14849853515625 -0.7025939941406295 +1.282125 0.49951171875 0.14849853515625 -0.7025939941406295 +1.2822500000000002 0.499267578125 0.1484375 -0.7025939941406295 +1.282375 0.49896240234375 0.148345947265625 -0.7025939941406295 +1.2825 0.49896240234375 0.148345947265625 -0.7025939941406295 +1.2826250000000002 0.49859619140625 0.148223876953125 -0.7025939941406295 +1.28275 0.49859619140625 0.148223876953125 -0.7025939941406295 +1.282875 0.498199462890625 0.148101806640625 -0.7025939941406295 +1.283 0.497711181640625 0.147979736328125 -0.7025939941406295 +1.283125 0.497711181640625 0.147979736328125 -0.7025939941406295 +1.28325 0.4971923828125 0.1478271484375 -0.7025939941406295 +1.283375 0.4971923828125 0.1478271484375 -0.7025939941406295 +1.2835 0.496612548828125 0.14764404296875 -0.7025939941406295 +1.283625 0.496002197265625 0.1474609375 -0.7025939941406295 +1.28375 0.496002197265625 0.1474609375 -0.7025939941406295 +1.283875 0.49530029296875 0.147247314453125 -0.7025939941406295 +1.284 0.49530029296875 0.147247314453125 -0.7025939941406295 +1.284125 0.49456787109375 0.14703369140625 -0.7025939941406295 +1.2842500000000002 0.4937744140625 0.14678955078125 -0.7025939941406295 +1.284375 0.4937744140625 0.14678955078125 -0.7025939941406295 +1.2845 0.492950439453125 0.14654541015625 -0.7025939941406295 +1.2846250000000002 0.492950439453125 0.14654541015625 -0.7025939941406295 +1.28475 0.492034912109375 0.146270751953125 -0.7025939941406295 +1.284875 0.4910888671875 0.14599609375 -0.7025939941406295 +1.285 0.4910888671875 0.14599609375 -0.7025939941406295 +1.285125 0.490081787109375 0.14569091796875 -0.7025939941406295 +1.28525 0.490081787109375 0.14569091796875 -0.7025939941406295 +1.285375 0.489013671875 0.1453857421875 -0.7025939941406295 +1.2855 0.487884521484375 0.145050048828125 -0.7025939941406295 +1.285625 0.487884521484375 0.145050048828125 -0.7025939941406295 +1.28575 0.486724853515625 0.14471435546875 -0.7025939941406295 +1.285875 0.486724853515625 0.14471435546875 -0.7025939941406295 +1.286 0.485504150390625 0.14434814453125 -0.7025939941406295 +1.286125 0.484222412109375 0.143951416015625 -0.7025939941406295 +1.2862500000000002 0.484222412109375 0.143951416015625 -0.7025939941406295 +1.286375 0.48291015625 0.1435546875 -0.7025939941406295 +1.2865 0.48291015625 0.1435546875 -0.7025939941406295 +1.2866250000000002 0.48150634765625 0.143157958984375 -0.7025939941406295 +1.28675 0.480072021484375 0.142730712890625 -0.7025939941406295 +1.286875 0.480072021484375 0.142730712890625 -0.7025939941406295 +1.287 0.478607177734375 0.14227294921875 -0.7025939941406295 +1.287125 0.478607177734375 0.14227294921875 -0.7025939941406295 +1.28725 0.47705078125 0.141815185546875 -0.7025939941406295 +1.287375 0.4754638671875 0.141357421875 -0.7025939941406295 +1.2875 0.4754638671875 0.141357421875 -0.7025939941406295 +1.287625 0.47381591796875 0.140869140625 -0.7025939941406295 +1.28775 0.47381591796875 0.140869140625 -0.7025939941406295 +1.287875 0.472137451171875 0.140350341796875 -0.7025939941406295 +1.288 0.470367431640625 0.13983154296875 -0.7025939941406295 +1.288125 0.470367431640625 0.13983154296875 -0.7025939941406295 +1.2882500000000002 0.46856689453125 0.139312744140625 -0.7025939941406295 +1.288375 0.46856689453125 0.139312744140625 -0.7025939941406295 +1.2885 0.46673583984375 0.138763427734375 -0.7025939941406295 +1.2886250000000002 0.464813232421875 0.13818359375 -0.7025939941406295 +1.28875 0.464813232421875 0.13818359375 -0.7025939941406295 +1.288875 0.462890625 0.137603759765625 -0.7025939941406295 +1.289 0.462890625 0.137603759765625 -0.7025939941406295 +1.289125 0.46087646484375 0.13702392578125 -0.7025939941406295 +1.28925 0.458831787109375 0.13641357421875 -0.7025939941406295 +1.289375 0.458831787109375 0.13641357421875 -0.7025939941406295 +1.2895 0.45672607421875 0.135772705078125 -0.7025939941406295 +1.289625 0.45672607421875 0.135772705078125 -0.7025939941406295 +1.28975 0.454559326171875 0.1351318359375 -0.7025939941406295 +1.289875 0.452362060546875 0.134490966796875 -0.7025939941406295 +1.29 0.452362060546875 0.134490966796875 -0.7025939941406295 +1.290125 0.450103759765625 0.133819580078125 -0.7025939941406295 +1.2902500000000002 0.450103759765625 0.133819580078125 -0.7025939941406295 +1.290375 0.447784423828125 0.13311767578125 -0.7025939941406295 +1.2905 0.4454345703125 0.132415771484375 -0.7025939941406295 +1.2906250000000002 0.4454345703125 0.132415771484375 -0.7025939941406295 +1.29075 0.44305419921875 0.1317138671875 -0.7025939941406295 +1.290875 0.44305419921875 0.1317138671875 -0.7025939941406295 +1.291 0.440582275390625 0.1309814453125 -0.7025939941406295 +1.291125 0.438079833984375 0.1302490234375 -0.7025939941406295 +1.29125 0.438079833984375 0.1302490234375 -0.7025939941406295 +1.291375 0.435546875 0.129486083984375 -0.7025939941406295 +1.2915 0.435546875 0.129486083984375 -0.7025939941406295 +1.291625 0.432952880859375 0.12872314453125 -0.7025939941406295 +1.29175 0.4302978515625 0.1279296875 -0.7025939941406295 +1.291875 0.4302978515625 0.1279296875 -0.7025939941406295 +1.292 0.4276123046875 0.12713623046875 -0.7025939941406295 +1.292125 0.4276123046875 0.12713623046875 -0.7025939941406295 +1.2922500000000002 0.424896240234375 0.126312255859375 -0.7025939941406295 +1.292375 0.422119140625 0.12548828125 -0.7025939941406295 +1.2925 0.422119140625 0.12548828125 -0.7025939941406295 +1.2926250000000002 0.419281005859375 0.1246337890625 -0.7025939941406295 +1.29275 0.419281005859375 0.1246337890625 -0.7025939941406295 +1.292875 0.416412353515625 0.123779296875 -0.7025939941406295 +1.293 0.413482666015625 0.1229248046875 -0.7025939941406295 +1.293125 0.413482666015625 0.1229248046875 -0.7025939941406295 +1.29325 0.4105224609375 0.122039794921875 -0.7025939941406295 +1.293375 0.4105224609375 0.122039794921875 -0.7025939941406295 +1.2935 0.407501220703125 0.12115478515625 -0.7025939941406295 +1.293625 0.404449462890625 0.1202392578125 -0.7025939941406295 +1.29375 0.404449462890625 0.1202392578125 -0.7025939941406295 +1.293875 0.401336669921875 0.11932373046875 -0.7025939941406295 +1.294 0.401336669921875 0.11932373046875 -0.7025939941406295 +1.294125 0.398193359375 0.118377685546875 -0.7025939941406295 +1.2942500000000002 0.39501953125 0.117431640625 -0.7025939941406295 +1.294375 0.39501953125 0.117431640625 -0.7025939941406295 +1.2945 0.39178466796875 0.116485595703125 -0.7025939941406295 +1.2946250000000002 0.39178466796875 0.116485595703125 -0.7025939941406295 +1.29475 0.388519287109375 0.115509033203125 -0.7025939941406295 +1.294875 0.38519287109375 0.114501953125 -0.7025939941406295 +1.295 0.38519287109375 0.114501953125 -0.7025939941406295 +1.295125 0.3818359375 0.113525390625 -0.7025939941406295 +1.29525 0.3818359375 0.113525390625 -0.7025939941406295 +1.295375 0.378448486328125 0.112518310546875 -0.7025939941406295 +1.2955 0.375 0.111480712890625 -0.7025939941406295 +1.295625 0.375 0.111480712890625 -0.7025939941406295 +1.29575 0.37152099609375 0.110443115234375 -0.7025939941406295 +1.295875 0.37152099609375 0.110443115234375 -0.7025939941406295 +1.296 0.36798095703125 0.109405517578125 -0.7025939941406295 +1.296125 0.36444091796875 0.10833740234375 -0.7025939941406295 +1.2962500000000002 0.36444091796875 0.10833740234375 -0.7025939941406295 +1.296375 0.360809326171875 0.107269287109375 -0.7025939941406295 +1.2965 0.360809326171875 0.107269287109375 -0.7025939941406295 +1.296625 0.357177734375 0.106201171875 -0.7025939941406295 +1.29675 0.353485107421875 0.1051025390625 -0.7025939941406295 +1.296875 0.353485107421875 0.1051025390625 -0.7025939941406295 +1.297 0.349761962890625 0.103973388671875 -0.7025939941406295 +1.297125 0.349761962890625 0.103973388671875 -0.7025939941406295 +1.29725 0.34600830078125 0.102874755859375 -0.7025939941406295 +1.297375 0.34222412109375 0.10174560546875 -0.7025939941406295 +1.2975 0.34222412109375 0.10174560546875 -0.7025939941406295 +1.297625 0.33837890625 0.1005859375 -0.7025939941406295 +1.29775 0.33837890625 0.1005859375 -0.7025939941406295 +1.2978750000000002 0.334503173828125 0.099456787109375 -0.7025939941406295 +1.298 0.330596923828125 0.098297119140625 -0.7025939941406295 +1.298125 0.330596923828125 0.098297119140625 -0.7025939941406295 +1.2982500000000002 0.32666015625 0.09710693359375 -0.7025939941406295 +1.298375 0.32666015625 0.09710693359375 -0.7025939941406295 +1.2985 0.322662353515625 0.095916748046875 -0.7025939941406295 +1.298625 0.31866455078125 0.0947265625 -0.7025939941406295 +1.29875 0.31866455078125 0.0947265625 -0.7025939941406295 +1.298875 0.314605712890625 0.093536376953125 -0.7025939941406295 +1.299 0.314605712890625 0.093536376953125 -0.7025939941406295 +1.299125 0.310516357421875 0.092315673828125 -0.7025939941406295 +1.29925 0.306396484375 0.091094970703125 -0.7025939941406295 +1.299375 0.306396484375 0.091094970703125 -0.7025939941406295 +1.2995 0.30224609375 0.08984375 -0.7025939941406295 +1.299625 0.30224609375 0.08984375 -0.7025939941406295 +1.29975 0.298065185546875 0.088623046875 -0.7025939941406295 +1.2998750000000002 0.2938232421875 0.08734130859375 -0.7025939941406295 +1.3 0.2938232421875 0.08734130859375 -0.7025939941406295 +1.300125 0.289581298828125 0.086090087890625 -0.7025939941406295 +1.3002500000000002 0.289581298828125 0.086090087890625 -0.7025939941406295 +1.300375 0.285308837890625 0.084808349609375 -0.7025939941406295 +1.3005 0.280975341796875 0.083526611328125 -0.7025939941406295 +1.300625 0.280975341796875 0.083526611328125 -0.7025939941406295 +1.30075 0.276641845703125 0.082244873046875 -0.7025939941406295 +1.300875 0.276641845703125 0.082244873046875 -0.7025939941406295 +1.301 0.27227783203125 0.0809326171875 -0.7025939941406295 +1.301125 0.267852783203125 0.079620361328125 -0.7025939941406295 +1.30125 0.267852783203125 0.079620361328125 -0.7025939941406295 +1.301375 0.263427734375 0.07830810546875 -0.7025939941406295 +1.3015 0.263427734375 0.07830810546875 -0.7025939941406295 +1.301625 0.25897216796875 0.076995849609375 -0.7025939941406295 +1.30175 0.25445556640625 0.075653076171875 -0.7025939941406295 +1.3018750000000002 0.25445556640625 0.075653076171875 -0.7025939941406295 +1.302 0.249969482421875 0.074310302734375 -0.7025939941406295 +1.302125 0.249969482421875 0.074310302734375 -0.7025939941406295 +1.3022500000000002 0.24542236328125 0.072967529296875 -0.7025939941406295 +1.302375 0.2408447265625 0.07159423828125 -0.7025939941406295 +1.3025 0.2408447265625 0.07159423828125 -0.7025939941406295 +1.302625 0.236236572265625 0.070220947265625 -0.7025939941406295 +1.30275 0.236236572265625 0.070220947265625 -0.7025939941406295 +1.302875 0.231597900390625 0.06884765625 -0.7025939941406295 +1.303 0.226959228515625 0.067474365234375 -0.7025939941406295 +1.303125 0.226959228515625 0.067474365234375 -0.7025939941406295 +1.30325 0.2222900390625 0.066070556640625 -0.7025939941406295 +1.303375 0.2222900390625 0.066070556640625 -0.7025939941406295 +1.3035 0.21759033203125 0.064666748046875 -0.7025939941406295 +1.303625 0.212860107421875 0.063262939453125 -0.7025939941406295 +1.30375 0.212860107421875 0.063262939453125 -0.7025939941406295 +1.3038750000000002 0.208099365234375 0.061859130859375 -0.7025939941406295 +1.304 0.208099365234375 0.061859130859375 -0.7025939941406295 +1.304125 0.203338623046875 0.060455322265625 -0.7025939941406295 +1.3042500000000002 0.19854736328125 0.05902099609375 -0.7025939941406295 +1.304375 0.19854736328125 0.05902099609375 -0.7025939941406295 +1.3045 0.1937255859375 0.057586669921875 -0.7025939941406295 +1.304625 0.1937255859375 0.057586669921875 -0.7025939941406295 +1.30475 0.188873291015625 0.05615234375 -0.7025939941406295 +1.304875 0.18402099609375 0.054718017578125 -0.7025939941406295 +1.305 0.18402099609375 0.054718017578125 -0.7025939941406295 +1.305125 0.17913818359375 0.053253173828125 -0.7025939941406295 +1.30525 0.17913818359375 0.053253173828125 -0.7025939941406295 +1.305375 0.17425537109375 0.051788330078125 -0.7025939941406295 +1.3055 0.169342041015625 0.050323486328125 -0.7025939941406295 +1.305625 0.169342041015625 0.050323486328125 -0.7025939941406295 +1.30575 0.164398193359375 0.048858642578125 -0.7025939941406295 +1.3058750000000002 0.164398193359375 0.048858642578125 -0.7025939941406295 +1.306 0.159454345703125 0.047393798828125 -0.7025939941406295 +1.306125 0.15447998046875 0.045928955078125 -0.7025939941406295 +1.3062500000000002 0.15447998046875 0.045928955078125 -0.7025939941406295 +1.306375 0.14947509765625 0.04443359375 -0.7025939941406295 +1.3065 0.14947509765625 0.04443359375 -0.7025939941406295 +1.306625 0.14447021484375 0.042938232421875 -0.7025939941406295 +1.30675 0.13946533203125 0.04144287109375 -0.7025939941406295 +1.306875 0.13946533203125 0.04144287109375 -0.7025939941406295 +1.307 0.134429931640625 0.039947509765625 -0.7025939941406295 +1.307125 0.134429931640625 0.039947509765625 -0.7025939941406295 +1.30725 0.129364013671875 0.0384521484375 -0.7025939941406295 +1.307375 0.124298095703125 0.036956787109375 -0.7025939941406295 +1.3075 0.124298095703125 0.036956787109375 -0.7025939941406295 +1.307625 0.119232177734375 0.035430908203125 -0.7025939941406295 +1.30775 0.119232177734375 0.035430908203125 -0.7025939941406295 +1.3078750000000002 0.1141357421875 0.033935546875 -0.7025939941406295 +1.308 0.109039306640625 0.03240966796875 -0.7025939941406295 +1.308125 0.109039306640625 0.03240966796875 -0.7025939941406295 +1.3082500000000002 0.103912353515625 0.0308837890625 -0.7025939941406295 +1.308375 0.103912353515625 0.0308837890625 -0.7025939941406295 +1.3085 0.098785400390625 0.02935791015625 -0.7025939941406295 +1.308625 0.093658447265625 0.02783203125 -0.7025939941406295 +1.30875 0.093658447265625 0.02783203125 -0.7025939941406295 +1.308875 0.0885009765625 0.02630615234375 -0.7025939941406295 +1.309 0.0885009765625 0.02630615234375 -0.7025939941406295 +1.309125 0.083343505859375 0.0247802734375 -0.7025939941406295 +1.30925 0.07818603515625 0.023223876953125 -0.7025939941406295 +1.309375 0.07818603515625 0.023223876953125 -0.7025939941406295 +1.3095 0.072998046875 0.021697998046875 -0.7025939941406295 +1.309625 0.072998046875 0.021697998046875 -0.7025939941406295 +1.30975 0.06781005859375 0.0201416015625 -0.7025939941406295 +1.3098750000000002 0.0626220703125 0.01861572265625 -0.7025939941406295 +1.31 0.0626220703125 0.01861572265625 -0.7025939941406295 +1.310125 0.05743408203125 0.017059326171875 -0.7025939941406295 +1.3102500000000002 0.05743408203125 0.017059326171875 -0.7025939941406295 +1.310375 0.05224609375 0.015533447265625 -0.7025939941406295 +1.3105 0.047027587890625 0.01397705078125 -0.7025939941406295 +1.310625 0.047027587890625 0.01397705078125 -0.7025939941406295 +1.31075 0.04180908203125 0.012420654296875 -0.7025939941406295 +1.310875 0.04180908203125 0.012420654296875 -0.7025939941406295 +1.311 0.036590576171875 0.0108642578125 -0.7025939941406295 +1.311125 0.0313720703125 0.009307861328125 -0.7025939941406295 +1.31125 0.0313720703125 0.009307861328125 -0.7025939941406295 +1.311375 0.026123046875 0.00775146484375 -0.7025939941406295 +1.3115 0.026123046875 0.00775146484375 -0.7025939941406295 +1.311625 0.020904541015625 0.006195068359375 -0.7025939941406295 +1.31175 0.01568603515625 0.004638671875 -0.7025939941406295 +1.3118750000000002 0.01568603515625 0.004638671875 -0.7025939941406295 +1.312 0.01043701171875 0.000762939453125 -0.9250366210937526 +1.312125 0.01043701171875 0.000762939453125 -0.9250366210937526 +1.31225 0.005218505859375 0.0003662109375 -0.9250366210937526 +1.312375 0.0 0.0 -0.9250366210937526 +1.3125 0.0 0.0 -0.9250366210937526 +1.312625 -0.005218505859375 -0.0003662109375 -0.9250366210937526 +1.31275 -0.005218505859375 -0.0003662109375 -0.9250366210937526 +1.312875 -0.01043701171875 -0.000762939453125 -0.9250366210937526 +1.313 -0.01568603515625 -0.00115966796875 -0.9250366210937526 +1.313125 -0.01568603515625 -0.00115966796875 -0.9250366210937526 +1.31325 -0.020904541015625 -0.001556396484375 -0.9250366210937526 +1.313375 -0.020904541015625 -0.001556396484375 -0.9250366210937526 +1.3135000000000002 -0.026123046875 -0.001953125 -0.9250366210937526 +1.313625 -0.0313720703125 -0.0023193359375 -0.9250366210937526 +1.31375 -0.0313720703125 -0.0023193359375 -0.9250366210937526 +1.3138750000000002 -0.036590576171875 -0.002716064453125 -0.9250366210937526 +1.314 -0.036590576171875 -0.002716064453125 -0.9250366210937526 +1.314125 -0.04180908203125 -0.00311279296875 -0.9250366210937526 +1.31425 -0.047027587890625 -0.003509521484375 -0.9250366210937526 +1.314375 -0.047027587890625 -0.003509521484375 -0.9250366210937526 +1.3145 -0.05224609375 -0.00390625 -0.9250366210937526 +1.314625 -0.05224609375 -0.00390625 -0.9250366210937526 +1.31475 -0.05743408203125 -0.0042724609375 -0.9250366210937526 +1.314875 -0.0626220703125 -0.004669189453125 -0.9250366210937526 +1.315 -0.0626220703125 -0.004669189453125 -0.9250366210937526 +1.315125 -0.06781005859375 -0.00506591796875 -0.9250366210937526 +1.31525 -0.06781005859375 -0.00506591796875 -0.9250366210937526 +1.315375 -0.072998046875 -0.005462646484375 -0.9250366210937526 +1.3155000000000002 -0.07818603515625 -0.005828857421875 -0.9250366210937526 +1.315625 -0.07818603515625 -0.005828857421875 -0.9250366210937526 +1.31575 -0.083343505859375 -0.0062255859375 -0.9250366210937526 +1.3158750000000002 -0.083343505859375 -0.0062255859375 -0.9250366210937526 +1.316 -0.0885009765625 -0.006622314453125 -0.9250366210937526 +1.316125 -0.093658447265625 -0.006988525390625 -0.9250366210937526 +1.31625 -0.093658447265625 -0.006988525390625 -0.9250366210937526 +1.316375 -0.098785400390625 -0.00738525390625 -0.9250366210937526 +1.3165 -0.098785400390625 -0.00738525390625 -0.9250366210937526 +1.316625 -0.103912353515625 -0.00775146484375 -0.9250366210937526 +1.31675 -0.109039306640625 -0.008148193359375 -0.9250366210937526 +1.316875 -0.109039306640625 -0.008148193359375 -0.9250366210937526 +1.317 -0.1141357421875 -0.008544921875 -0.9250366210937526 +1.317125 -0.1141357421875 -0.008544921875 -0.9250366210937526 +1.31725 -0.119232177734375 -0.0089111328125 -0.9250366210937526 +1.317375 -0.124298095703125 -0.00927734375 -0.9250366210937526 +1.3175000000000002 -0.124298095703125 -0.00927734375 -0.9250366210937526 +1.317625 -0.129364013671875 -0.009674072265625 -0.9250366210937526 +1.31775 -0.129364013671875 -0.009674072265625 -0.9250366210937526 +1.3178750000000002 -0.134429931640625 -0.010040283203125 -0.9250366210937526 +1.318 -0.13946533203125 -0.01043701171875 -0.9250366210937526 +1.318125 -0.13946533203125 -0.01043701171875 -0.9250366210937526 +1.31825 -0.14447021484375 -0.01080322265625 -0.9250366210937526 +1.318375 -0.14447021484375 -0.01080322265625 -0.9250366210937526 +1.3185 -0.14947509765625 -0.01116943359375 -0.9250366210937526 +1.318625 -0.15447998046875 -0.01153564453125 -0.9250366210937526 +1.31875 -0.15447998046875 -0.01153564453125 -0.9250366210937526 +1.318875 -0.159454345703125 -0.011932373046875 -0.9250366210937526 +1.319 -0.159454345703125 -0.011932373046875 -0.9250366210937526 +1.319125 -0.164398193359375 -0.012298583984375 -0.9250366210937526 +1.31925 -0.169342041015625 -0.012664794921875 -0.9250366210937526 +1.319375 -0.169342041015625 -0.012664794921875 -0.9250366210937526 +1.3195000000000002 -0.17425537109375 -0.013031005859375 -0.9250366210937526 +1.319625 -0.17425537109375 -0.013031005859375 -0.9250366210937526 +1.31975 -0.17913818359375 -0.013397216796875 -0.9250366210937526 +1.3198750000000002 -0.18402099609375 -0.013763427734375 -0.9250366210937526 +1.32 -0.18402099609375 -0.013763427734375 -0.9250366210937526 +1.320125 -0.188873291015625 -0.014129638671875 -0.9250366210937526 +1.32025 -0.188873291015625 -0.014129638671875 -0.9250366210937526 +1.320375 -0.1937255859375 -0.014495849609375 -0.9250366210937526 +1.3205 -0.19854736328125 -0.014862060546875 -0.9250366210937526 +1.320625 -0.19854736328125 -0.014862060546875 -0.9250366210937526 +1.32075 -0.203338623046875 -0.01519775390625 -0.9250366210937526 +1.320875 -0.203338623046875 -0.01519775390625 -0.9250366210937526 +1.321 -0.208099365234375 -0.01556396484375 -0.9250366210937526 +1.321125 -0.212860107421875 -0.01593017578125 -0.9250366210937526 +1.32125 -0.212860107421875 -0.01593017578125 -0.9250366210937526 +1.321375 -0.21759033203125 -0.016265869140625 -0.9250366210937526 +1.3215000000000002 -0.21759033203125 -0.016265869140625 -0.9250366210937526 +1.321625 -0.2222900390625 -0.016632080078125 -0.9250366210937526 +1.32175 -0.226959228515625 -0.0169677734375 -0.9250366210937526 +1.3218750000000002 -0.226959228515625 -0.0169677734375 -0.9250366210937526 +1.322 -0.231597900390625 -0.017333984375 -0.9250366210937526 +1.322125 -0.231597900390625 -0.017333984375 -0.9250366210937526 +1.32225 -0.236236572265625 -0.017669677734375 -0.9250366210937526 +1.322375 -0.2408447265625 -0.01800537109375 -0.9250366210937526 +1.3225 -0.2408447265625 -0.01800537109375 -0.9250366210937526 +1.322625 -0.24542236328125 -0.01837158203125 -0.9250366210937526 +1.32275 -0.24542236328125 -0.01837158203125 -0.9250366210937526 +1.322875 -0.249969482421875 -0.018707275390625 -0.9250366210937526 +1.323 -0.25445556640625 -0.01904296875 -0.9250366210937526 +1.323125 -0.25445556640625 -0.01904296875 -0.9250366210937526 +1.32325 -0.25897216796875 -0.019378662109375 -0.9250366210937526 +1.323375 -0.25897216796875 -0.019378662109375 -0.9250366210937526 +1.3235000000000002 -0.263427734375 -0.01971435546875 -0.9250366210937526 +1.323625 -0.267852783203125 -0.020050048828125 -0.9250366210937526 +1.32375 -0.267852783203125 -0.020050048828125 -0.9250366210937526 +1.3238750000000002 -0.27227783203125 -0.020355224609375 -0.9250366210937526 +1.324 -0.27227783203125 -0.020355224609375 -0.9250366210937526 +1.324125 -0.276641845703125 -0.02069091796875 -0.9250366210937526 +1.32425 -0.280975341796875 -0.021026611328125 -0.9250366210937526 +1.324375 -0.280975341796875 -0.021026611328125 -0.9250366210937526 +1.3245 -0.285308837890625 -0.021331787109375 -0.9250366210937526 +1.324625 -0.285308837890625 -0.021331787109375 -0.9250366210937526 +1.32475 -0.289581298828125 -0.02166748046875 -0.9250366210937526 +1.324875 -0.2938232421875 -0.02197265625 -0.9250366210937526 +1.325 -0.2938232421875 -0.02197265625 -0.9250366210937526 +1.325125 -0.298065185546875 -0.022308349609375 -0.9250366210937526 +1.32525 -0.298065185546875 -0.022308349609375 -0.9250366210937526 +1.325375 -0.30224609375 -0.022613525390625 -0.9250366210937526 +1.3255000000000002 -0.306396484375 -0.022918701171875 -0.9250366210937526 +1.325625 -0.306396484375 -0.022918701171875 -0.9250366210937526 +1.32575 -0.310516357421875 -0.023223876953125 -0.9250366210937526 +1.3258750000000002 -0.310516357421875 -0.023223876953125 -0.9250366210937526 +1.326 -0.314605712890625 -0.023529052734375 -0.9250366210937526 +1.326125 -0.31866455078125 -0.023834228515625 -0.9250366210937526 +1.32625 -0.31866455078125 -0.023834228515625 -0.9250366210937526 +1.326375 -0.322662353515625 -0.024139404296875 -0.9250366210937526 +1.3265 -0.322662353515625 -0.024139404296875 -0.9250366210937526 +1.326625 -0.32666015625 -0.024444580078125 -0.9250366210937526 +1.32675 -0.330596923828125 -0.024749755859375 -0.9250366210937526 +1.326875 -0.330596923828125 -0.024749755859375 -0.9250366210937526 +1.327 -0.334503173828125 -0.0250244140625 -0.9250366210937526 +1.327125 -0.334503173828125 -0.0250244140625 -0.9250366210937526 +1.32725 -0.33837890625 -0.02532958984375 -0.9250366210937526 +1.327375 -0.34222412109375 -0.025604248046875 -0.9250366210937526 +1.3275000000000002 -0.34222412109375 -0.025604248046875 -0.9250366210937526 +1.327625 -0.34600830078125 -0.02587890625 -0.9250366210937526 +1.32775 -0.34600830078125 -0.02587890625 -0.9250366210937526 +1.3278750000000002 -0.349761962890625 -0.02618408203125 -0.9250366210937526 +1.328 -0.353485107421875 -0.026458740234375 -0.9250366210937526 +1.328125 -0.353485107421875 -0.026458740234375 -0.9250366210937526 +1.32825 -0.357177734375 -0.0267333984375 -0.9250366210937526 +1.328375 -0.357177734375 -0.0267333984375 -0.9250366210937526 +1.3285 -0.360809326171875 -0.027008056640625 -0.9250366210937526 +1.328625 -0.36444091796875 -0.02728271484375 -0.9250366210937526 +1.32875 -0.36444091796875 -0.02728271484375 -0.9250366210937526 +1.328875 -0.36798095703125 -0.02752685546875 -0.9250366210937526 +1.329 -0.36798095703125 -0.02752685546875 -0.9250366210937526 +1.3291250000000002 -0.37152099609375 -0.027801513671875 -0.9250366210937526 +1.32925 -0.375 -0.028045654296875 -0.9250366210937526 +1.329375 -0.375 -0.028045654296875 -0.9250366210937526 +1.3295000000000002 -0.378448486328125 -0.0283203125 -0.9250366210937526 +1.329625 -0.378448486328125 -0.0283203125 -0.9250366210937526 +1.32975 -0.3818359375 -0.028564453125 -0.9250366210937526 +1.329875 -0.38519287109375 -0.02880859375 -0.9250366210937526 +1.33 -0.38519287109375 -0.02880859375 -0.9250366210937526 +1.330125 -0.388519287109375 -0.029083251953125 -0.9250366210937526 +1.33025 -0.388519287109375 -0.029083251953125 -0.9250366210937526 +1.330375 -0.39178466796875 -0.029327392578125 -0.9250366210937526 +1.3305 -0.39501953125 -0.029571533203125 -0.9250366210937526 +1.330625 -0.39501953125 -0.029571533203125 -0.9250366210937526 +1.33075 -0.398193359375 -0.02978515625 -0.9250366210937526 +1.330875 -0.398193359375 -0.02978515625 -0.9250366210937526 +1.331 -0.401336669921875 -0.030029296875 -0.9250366210937526 +1.3311250000000002 -0.404449462890625 -0.0302734375 -0.9250366210937526 +1.33125 -0.404449462890625 -0.0302734375 -0.9250366210937526 +1.331375 -0.407501220703125 -0.030487060546875 -0.9250366210937526 +1.3315000000000002 -0.407501220703125 -0.030487060546875 -0.9250366210937526 +1.331625 -0.4105224609375 -0.030731201171875 -0.9250366210937526 +1.33175 -0.413482666015625 -0.03094482421875 -0.9250366210937526 +1.331875 -0.413482666015625 -0.03094482421875 -0.9250366210937526 +1.332 -0.416412353515625 -0.031158447265625 -0.9250366210937526 +1.332125 -0.416412353515625 -0.031158447265625 -0.9250366210937526 +1.33225 -0.419281005859375 -0.0313720703125 -0.9250366210937526 +1.332375 -0.422119140625 -0.031585693359375 -0.9250366210937526 +1.3325 -0.422119140625 -0.031585693359375 -0.9250366210937526 +1.332625 -0.424896240234375 -0.03179931640625 -0.9250366210937526 +1.33275 -0.424896240234375 -0.03179931640625 -0.9250366210937526 +1.332875 -0.4276123046875 -0.032012939453125 -0.9250366210937526 +1.333 -0.4302978515625 -0.032196044921875 -0.9250366210937526 +1.3331250000000002 -0.4302978515625 -0.032196044921875 -0.9250366210937526 +1.33325 -0.432952880859375 -0.03240966796875 -0.9250366210937526 +1.333375 -0.432952880859375 -0.03240966796875 -0.9250366210937526 +1.3335000000000002 -0.435546875 -0.0325927734375 -0.9250366210937526 +1.333625 -0.438079833984375 -0.03277587890625 -0.9250366210937526 +1.33375 -0.438079833984375 -0.03277587890625 -0.9250366210937526 +1.333875 -0.440582275390625 -0.032958984375 -0.9250366210937526 +1.334 -0.440582275390625 -0.032958984375 -0.9250366210937526 +1.334125 -0.44305419921875 -0.03314208984375 -0.9250366210937526 +1.33425 -0.4454345703125 -0.0333251953125 -0.9250366210937526 +1.334375 -0.4454345703125 -0.0333251953125 -0.9250366210937526 +1.3345 -0.447784423828125 -0.03350830078125 -0.9250366210937526 +1.334625 -0.447784423828125 -0.03350830078125 -0.9250366210937526 +1.33475 -0.450103759765625 -0.03369140625 -0.9250366210937526 +1.334875 -0.452362060546875 -0.033843994140625 -0.9250366210937526 +1.335 -0.452362060546875 -0.033843994140625 -0.9250366210937526 +1.3351250000000002 -0.454559326171875 -0.034027099609375 -0.9250366210937526 +1.33525 -0.454559326171875 -0.034027099609375 -0.9250366210937526 +1.335375 -0.45672607421875 -0.0341796875 -0.9250366210937526 +1.3355000000000002 -0.458831787109375 -0.034332275390625 -0.9250366210937526 +1.335625 -0.458831787109375 -0.034332275390625 -0.9250366210937526 +1.33575 -0.46087646484375 -0.03448486328125 -0.9250366210937526 +1.335875 -0.46087646484375 -0.03448486328125 -0.9250366210937526 +1.336 -0.462890625 -0.034637451171875 -0.9250366210937526 +1.336125 -0.464813232421875 -0.0347900390625 -0.9250366210937526 +1.33625 -0.464813232421875 -0.0347900390625 -0.9250366210937526 +1.336375 -0.46673583984375 -0.034912109375 -0.9250366210937526 +1.3365 -0.46673583984375 -0.034912109375 -0.9250366210937526 +1.336625 -0.46856689453125 -0.035064697265625 -0.9250366210937526 +1.33675 -0.470367431640625 -0.035186767578125 -0.9250366210937526 +1.336875 -0.470367431640625 -0.035186767578125 -0.9250366210937526 +1.337 -0.472137451171875 -0.03533935546875 -0.9250366210937526 +1.3371250000000002 -0.472137451171875 -0.03533935546875 -0.9250366210937526 +1.33725 -0.47381591796875 -0.03546142578125 -0.9250366210937526 +1.337375 -0.4754638671875 -0.03558349609375 -0.9250366210937526 +1.3375000000000002 -0.4754638671875 -0.03558349609375 -0.9250366210937526 +1.337625 -0.47705078125 -0.03570556640625 -0.9250366210937526 +1.33775 -0.47705078125 -0.03570556640625 -0.9250366210937526 +1.337875 -0.478607177734375 -0.03582763671875 -0.9250366210937526 +1.338 -0.480072021484375 -0.035919189453125 -0.9250366210937526 +1.338125 -0.480072021484375 -0.035919189453125 -0.9250366210937526 +1.33825 -0.48150634765625 -0.036041259765625 -0.9250366210937526 +1.338375 -0.48150634765625 -0.036041259765625 -0.9250366210937526 +1.3385 -0.48291015625 -0.0361328125 -0.9250366210937526 +1.338625 -0.484222412109375 -0.036224365234375 -0.9250366210937526 +1.33875 -0.484222412109375 -0.036224365234375 -0.9250366210937526 +1.338875 -0.485504150390625 -0.036346435546875 -0.9250366210937526 +1.339 -0.485504150390625 -0.036346435546875 -0.9250366210937526 +1.3391250000000002 -0.486724853515625 -0.03643798828125 -0.9250366210937526 +1.33925 -0.487884521484375 -0.0364990234375 -0.9250366210937526 +1.339375 -0.487884521484375 -0.0364990234375 -0.9250366210937526 +1.3395000000000002 -0.489013671875 -0.036590576171875 -0.9250366210937526 +1.339625 -0.489013671875 -0.036590576171875 -0.9250366210937526 +1.33975 -0.490081787109375 -0.03668212890625 -0.9250366210937526 +1.339875 -0.4910888671875 -0.0367431640625 -0.9250366210937526 +1.34 -0.4910888671875 -0.0367431640625 -0.9250366210937526 +1.340125 -0.492034912109375 -0.036834716796875 -0.9250366210937526 +1.34025 -0.492034912109375 -0.036834716796875 -0.9250366210937526 +1.340375 -0.492950439453125 -0.036895751953125 -0.9250366210937526 +1.3405 -0.4937744140625 -0.036956787109375 -0.9250366210937526 +1.340625 -0.4937744140625 -0.036956787109375 -0.9250366210937526 +1.34075 -0.49456787109375 -0.037017822265625 -0.9250366210937526 +1.340875 -0.49456787109375 -0.037017822265625 -0.9250366210937526 +1.341 -0.49530029296875 -0.037078857421875 -0.9250366210937526 +1.3411250000000002 -0.496002197265625 -0.037109375 -0.9250366210937526 +1.34125 -0.496002197265625 -0.037109375 -0.9250366210937526 +1.341375 -0.496612548828125 -0.03717041015625 -0.9250366210937526 +1.3415000000000002 -0.496612548828125 -0.03717041015625 -0.9250366210937526 +1.341625 -0.4971923828125 -0.037200927734375 -0.9250366210937526 +1.34175 -0.497711181640625 -0.0372314453125 -0.9250366210937526 +1.341875 -0.497711181640625 -0.0372314453125 -0.9250366210937526 +1.342 -0.498199462890625 -0.03729248046875 -0.9250366210937526 +1.342125 -0.498199462890625 -0.03729248046875 -0.9250366210937526 +1.34225 -0.49859619140625 -0.037322998046875 -0.9250366210937526 +1.342375 -0.49896240234375 -0.037353515625 -0.9250366210937526 +1.3425 -0.49896240234375 -0.037353515625 -0.9250366210937526 +1.342625 -0.499267578125 -0.037353515625 -0.9250366210937526 +1.34275 -0.499267578125 -0.037353515625 -0.9250366210937526 +1.342875 -0.49951171875 -0.037384033203125 -0.9250366210937526 +1.343 -0.49969482421875 -0.037384033203125 -0.9250366210937526 +1.3431250000000002 -0.49969482421875 -0.037384033203125 -0.9250366210937526 +1.34325 -0.49981689453125 -0.03741455078125 -0.9250366210937526 +1.343375 -0.49981689453125 -0.03741455078125 -0.9250366210937526 +1.3435000000000002 -0.499908447265625 -0.03741455078125 -0.9250366210937526 +1.343625 -0.49993896484375 -0.03741455078125 -0.9250366210937526 +1.34375 -0.49993896484375 -0.03741455078125 -0.9250366210937526 +1.343875 -0.499908447265625 -0.03741455078125 -0.9250366210937526 +1.344 -0.499908447265625 0.0 -0.99987182617187488 +1.344125 -0.49981689453125 0.0 -0.99987182617187488 +1.34425 -0.49969482421875 0.0 -0.99987182617187488 +1.344375 -0.49969482421875 0.0 -0.99987182617187488 +1.3445 -0.49951171875 0.0 -0.99987182617187488 +1.344625 -0.49951171875 0.0 -0.99987182617187488 +1.3447500000000002 -0.499267578125 0.0 -0.99987182617187488 +1.344875 -0.49896240234375 0.0 -0.99987182617187488 +1.345 -0.49896240234375 0.0 -0.99987182617187488 +1.3451250000000002 -0.49859619140625 0.0 -0.99987182617187488 +1.34525 -0.49859619140625 0.0 -0.99987182617187488 +1.345375 -0.498199462890625 0.0 -0.99987182617187488 +1.3455 -0.497711181640625 0.0 -0.99987182617187488 +1.345625 -0.497711181640625 0.0 -0.99987182617187488 +1.34575 -0.4971923828125 0.0 -0.99987182617187488 +1.345875 -0.4971923828125 0.0 -0.99987182617187488 +1.346 -0.496612548828125 0.0 -0.99987182617187488 +1.346125 -0.496002197265625 0.0 -0.99987182617187488 +1.34625 -0.496002197265625 0.0 -0.99987182617187488 +1.346375 -0.49530029296875 0.0 -0.99987182617187488 +1.3465 -0.49530029296875 0.0 -0.99987182617187488 +1.346625 -0.49456787109375 0.0 -0.99987182617187488 +1.3467500000000002 -0.4937744140625 0.0 -0.99987182617187488 +1.346875 -0.4937744140625 0.0 -0.99987182617187488 +1.347 -0.492950439453125 0.0 -0.99987182617187488 +1.3471250000000002 -0.492950439453125 0.0 -0.99987182617187488 +1.34725 -0.492034912109375 0.0 -0.99987182617187488 +1.347375 -0.4910888671875 0.0 -0.99987182617187488 +1.3475 -0.4910888671875 0.0 -0.99987182617187488 +1.347625 -0.490081787109375 0.0 -0.99987182617187488 +1.34775 -0.490081787109375 0.0 -0.99987182617187488 +1.347875 -0.489013671875 0.0 -0.99987182617187488 +1.348 -0.487884521484375 0.0 -0.99987182617187488 +1.348125 -0.487884521484375 0.0 -0.99987182617187488 +1.34825 -0.486724853515625 0.0 -0.99987182617187488 +1.348375 -0.486724853515625 0.0 -0.99987182617187488 +1.3485 -0.485504150390625 0.0 -0.99987182617187488 +1.348625 -0.484222412109375 0.0 -0.99987182617187488 +1.3487500000000002 -0.484222412109375 0.0 -0.99987182617187488 +1.348875 -0.48291015625 0.0 -0.99987182617187488 +1.349 -0.48291015625 0.0 -0.99987182617187488 +1.3491250000000002 -0.48150634765625 0.0 -0.99987182617187488 +1.34925 -0.480072021484375 0.0 -0.99987182617187488 +1.349375 -0.480072021484375 0.0 -0.99987182617187488 +1.3495 -0.478607177734375 0.0 -0.99987182617187488 +1.349625 -0.478607177734375 0.0 -0.99987182617187488 +1.34975 -0.47705078125 0.0 -0.99987182617187488 +1.349875 -0.4754638671875 0.0 -0.99987182617187488 +1.35 -0.4754638671875 0.0 -0.99987182617187488 +1.350125 -0.47381591796875 0.0 -0.99987182617187488 +1.35025 -0.47381591796875 0.0 -0.99987182617187488 +1.350375 -0.472137451171875 0.0 -0.99987182617187488 +1.3505 -0.470367431640625 0.0 -0.99987182617187488 +1.350625 -0.470367431640625 0.0 -0.99987182617187488 +1.3507500000000002 -0.46856689453125 0.0 -0.99987182617187488 +1.350875 -0.46856689453125 0.0 -0.99987182617187488 +1.351 -0.46673583984375 0.0 -0.99987182617187488 +1.3511250000000002 -0.464813232421875 0.0 -0.99987182617187488 +1.35125 -0.464813232421875 0.0 -0.99987182617187488 +1.351375 -0.462890625 0.0 -0.99987182617187488 +1.3515 -0.462890625 0.0 -0.99987182617187488 +1.351625 -0.46087646484375 0.0 -0.99987182617187488 +1.35175 -0.458831787109375 0.0 -0.99987182617187488 +1.351875 -0.458831787109375 0.0 -0.99987182617187488 +1.352 -0.45672607421875 0.0 -0.99987182617187488 +1.352125 -0.45672607421875 0.0 -0.99987182617187488 +1.35225 -0.454559326171875 0.0 -0.99987182617187488 +1.352375 -0.452362060546875 0.0 -0.99987182617187488 +1.3525 -0.452362060546875 0.0 -0.99987182617187488 +1.352625 -0.450103759765625 0.0 -0.99987182617187488 +1.3527500000000002 -0.450103759765625 0.0 -0.99987182617187488 +1.352875 -0.447784423828125 0.0 -0.99987182617187488 +1.353 -0.4454345703125 0.0 -0.99987182617187488 +1.3531250000000002 -0.4454345703125 0.0 -0.99987182617187488 +1.35325 -0.44305419921875 0.0 -0.99987182617187488 +1.353375 -0.44305419921875 0.0 -0.99987182617187488 +1.3535 -0.440582275390625 0.0 -0.99987182617187488 +1.353625 -0.438079833984375 0.0 -0.99987182617187488 +1.35375 -0.438079833984375 0.0 -0.99987182617187488 +1.353875 -0.435546875 0.0 -0.99987182617187488 +1.354 -0.435546875 0.0 -0.99987182617187488 +1.354125 -0.432952880859375 0.0 -0.99987182617187488 +1.35425 -0.4302978515625 0.0 -0.99987182617187488 +1.354375 -0.4302978515625 0.0 -0.99987182617187488 +1.3545 -0.4276123046875 0.0 -0.99987182617187488 +1.354625 -0.4276123046875 0.0 -0.99987182617187488 +1.3547500000000002 -0.424896240234375 0.0 -0.99987182617187488 +1.354875 -0.422119140625 0.0 -0.99987182617187488 +1.355 -0.422119140625 0.0 -0.99987182617187488 +1.3551250000000002 -0.419281005859375 0.0 -0.99987182617187488 +1.35525 -0.419281005859375 0.0 -0.99987182617187488 +1.355375 -0.416412353515625 0.0 -0.99987182617187488 +1.3555 -0.413482666015625 0.0 -0.99987182617187488 +1.355625 -0.413482666015625 0.0 -0.99987182617187488 +1.35575 -0.4105224609375 0.0 -0.99987182617187488 +1.355875 -0.4105224609375 0.0 -0.99987182617187488 +1.356 -0.407501220703125 0.0 -0.99987182617187488 +1.356125 -0.404449462890625 0.0 -0.99987182617187488 +1.35625 -0.404449462890625 0.0 -0.99987182617187488 +1.356375 -0.401336669921875 0.0 -0.99987182617187488 +1.3565 -0.401336669921875 0.0 -0.99987182617187488 +1.356625 -0.398193359375 0.0 -0.99987182617187488 +1.3567500000000002 -0.39501953125 0.0 -0.99987182617187488 +1.356875 -0.39501953125 0.0 -0.99987182617187488 +1.357 -0.39178466796875 0.0 -0.99987182617187488 +1.3571250000000002 -0.39178466796875 0.0 -0.99987182617187488 +1.35725 -0.388519287109375 0.0 -0.99987182617187488 +1.357375 -0.38519287109375 0.0 -0.99987182617187488 +1.3575 -0.38519287109375 0.0 -0.99987182617187488 +1.357625 -0.3818359375 0.0 -0.99987182617187488 +1.35775 -0.3818359375 0.0 -0.99987182617187488 +1.357875 -0.378448486328125 0.0 -0.99987182617187488 +1.358 -0.375 0.0 -0.99987182617187488 +1.358125 -0.375 0.0 -0.99987182617187488 +1.35825 -0.37152099609375 0.0 -0.99987182617187488 +1.358375 -0.37152099609375 0.0 -0.99987182617187488 +1.3585 -0.36798095703125 0.0 -0.99987182617187488 +1.358625 -0.36444091796875 0.0 -0.99987182617187488 +1.3587500000000002 -0.36444091796875 0.0 -0.99987182617187488 +1.358875 -0.360809326171875 0.0 -0.99987182617187488 +1.359 -0.360809326171875 0.0 -0.99987182617187488 +1.3591250000000002 -0.357177734375 0.0 -0.99987182617187488 +1.35925 -0.353485107421875 0.0 -0.99987182617187488 +1.359375 -0.353485107421875 0.0 -0.99987182617187488 +1.3595 -0.349761962890625 0.0 -0.99987182617187488 +1.359625 -0.349761962890625 0.0 -0.99987182617187488 +1.35975 -0.34600830078125 0.0 -0.99987182617187488 +1.359875 -0.34222412109375 0.0 -0.99987182617187488 +1.36 -0.34222412109375 0.0 -0.99987182617187488 +1.360125 -0.33837890625 0.0 -0.99987182617187488 +1.36025 -0.33837890625 0.0 -0.99987182617187488 +1.3603750000000002 -0.334503173828125 0.0 -0.99987182617187488 +1.3605 -0.330596923828125 0.0 -0.99987182617187488 +1.360625 -0.330596923828125 0.0 -0.99987182617187488 +1.3607500000000002 -0.32666015625 0.0 -0.99987182617187488 +1.360875 -0.32666015625 0.0 -0.99987182617187488 +1.361 -0.322662353515625 0.0 -0.99987182617187488 +1.361125 -0.31866455078125 0.0 -0.99987182617187488 +1.36125 -0.31866455078125 0.0 -0.99987182617187488 +1.361375 -0.314605712890625 0.0 -0.99987182617187488 +1.3615 -0.314605712890625 0.0 -0.99987182617187488 +1.361625 -0.310516357421875 0.0 -0.99987182617187488 +1.36175 -0.306396484375 0.0 -0.99987182617187488 +1.361875 -0.306396484375 0.0 -0.99987182617187488 +1.362 -0.30224609375 0.0 -0.99987182617187488 +1.362125 -0.30224609375 0.0 -0.99987182617187488 +1.36225 -0.298065185546875 0.0 -0.99987182617187488 +1.3623750000000002 -0.2938232421875 0.0 -0.99987182617187488 +1.3625 -0.2938232421875 0.0 -0.99987182617187488 +1.362625 -0.289581298828125 0.0 -0.99987182617187488 +1.3627500000000002 -0.289581298828125 0.0 -0.99987182617187488 +1.362875 -0.285308837890625 0.0 -0.99987182617187488 +1.363 -0.280975341796875 0.0 -0.99987182617187488 +1.363125 -0.280975341796875 0.0 -0.99987182617187488 +1.36325 -0.276641845703125 0.0 -0.99987182617187488 +1.363375 -0.276641845703125 0.0 -0.99987182617187488 +1.3635 -0.27227783203125 0.0 -0.99987182617187488 +1.363625 -0.267852783203125 0.0 -0.99987182617187488 +1.36375 -0.267852783203125 0.0 -0.99987182617187488 +1.363875 -0.263427734375 0.0 -0.99987182617187488 +1.364 -0.263427734375 0.0 -0.99987182617187488 +1.364125 -0.25897216796875 0.0 -0.99987182617187488 +1.36425 -0.25445556640625 0.0 -0.99987182617187488 +1.3643750000000002 -0.25445556640625 0.0 -0.99987182617187488 +1.3645 -0.249969482421875 0.0 -0.99987182617187488 +1.364625 -0.249969482421875 0.0 -0.99987182617187488 +1.3647500000000002 -0.24542236328125 0.0 -0.99987182617187488 +1.364875 -0.2408447265625 0.0 -0.99987182617187488 +1.365 -0.2408447265625 0.0 -0.99987182617187488 +1.365125 -0.236236572265625 0.0 -0.99987182617187488 +1.36525 -0.236236572265625 0.0 -0.99987182617187488 +1.365375 -0.231597900390625 0.0 -0.99987182617187488 +1.3655 -0.226959228515625 0.0 -0.99987182617187488 +1.365625 -0.226959228515625 0.0 -0.99987182617187488 +1.36575 -0.2222900390625 0.0 -0.99987182617187488 +1.365875 -0.2222900390625 0.0 -0.99987182617187488 +1.366 -0.21759033203125 0.0 -0.99987182617187488 +1.366125 -0.212860107421875 0.0 -0.99987182617187488 +1.36625 -0.212860107421875 0.0 -0.99987182617187488 +1.3663750000000002 -0.208099365234375 0.0 -0.99987182617187488 +1.3665 -0.208099365234375 0.0 -0.99987182617187488 +1.366625 -0.203338623046875 0.0 -0.99987182617187488 +1.3667500000000002 -0.19854736328125 0.0 -0.99987182617187488 +1.366875 -0.19854736328125 0.0 -0.99987182617187488 +1.367 -0.1937255859375 0.0 -0.99987182617187488 +1.367125 -0.1937255859375 0.0 -0.99987182617187488 +1.36725 -0.188873291015625 0.0 -0.99987182617187488 +1.367375 -0.18402099609375 0.0 -0.99987182617187488 +1.3675 -0.18402099609375 0.0 -0.99987182617187488 +1.367625 -0.17913818359375 0.0 -0.99987182617187488 +1.36775 -0.17913818359375 0.0 -0.99987182617187488 +1.367875 -0.17425537109375 0.0 -0.99987182617187488 +1.368 -0.169342041015625 0.0 -0.99987182617187488 +1.368125 -0.169342041015625 0.0 -0.99987182617187488 +1.36825 -0.164398193359375 0.0 -0.99987182617187488 +1.3683750000000002 -0.164398193359375 0.0 -0.99987182617187488 +1.3685 -0.159454345703125 0.0 -0.99987182617187488 +1.368625 -0.15447998046875 0.0 -0.99987182617187488 +1.3687500000000002 -0.15447998046875 0.0 -0.99987182617187488 +1.368875 -0.14947509765625 0.0 -0.99987182617187488 +1.369 -0.14947509765625 0.0 -0.99987182617187488 +1.369125 -0.14447021484375 0.0 -0.99987182617187488 +1.36925 -0.13946533203125 0.0 -0.99987182617187488 +1.369375 -0.13946533203125 0.0 -0.99987182617187488 +1.3695 -0.134429931640625 0.0 -0.99987182617187488 +1.369625 -0.134429931640625 0.0 -0.99987182617187488 +1.36975 -0.129364013671875 0.0 -0.99987182617187488 +1.369875 -0.124298095703125 0.0 -0.99987182617187488 +1.37 -0.124298095703125 0.0 -0.99987182617187488 +1.370125 -0.119232177734375 0.0 -0.99987182617187488 +1.37025 -0.119232177734375 0.0 -0.99987182617187488 +1.3703750000000002 -0.1141357421875 0.0 -0.99987182617187488 +1.3705 -0.109039306640625 0.0 -0.99987182617187488 +1.370625 -0.109039306640625 0.0 -0.99987182617187488 +1.3707500000000002 -0.103912353515625 0.0 -0.99987182617187488 +1.370875 -0.103912353515625 0.0 -0.99987182617187488 +1.371 -0.098785400390625 0.0 -0.99987182617187488 +1.371125 -0.093658447265625 0.0 -0.99987182617187488 +1.37125 -0.093658447265625 0.0 -0.99987182617187488 +1.371375 -0.0885009765625 0.0 -0.99987182617187488 +1.3715 -0.0885009765625 0.0 -0.99987182617187488 +1.371625 -0.083343505859375 0.0 -0.99987182617187488 +1.37175 -0.07818603515625 0.0 -0.99987182617187488 +1.371875 -0.07818603515625 0.0 -0.99987182617187488 +1.372 -0.072998046875 0.0 -0.99987182617187488 +1.372125 -0.072998046875 0.0 -0.99987182617187488 +1.37225 -0.06781005859375 0.0 -0.99987182617187488 +1.3723750000000002 -0.0626220703125 0.0 -0.99987182617187488 +1.3725 -0.0626220703125 0.0 -0.99987182617187488 +1.372625 -0.05743408203125 0.0 -0.99987182617187488 +1.3727500000000002 -0.05743408203125 0.0 -0.99987182617187488 +1.372875 -0.05224609375 0.0 -0.99987182617187488 +1.373 -0.047027587890625 0.0 -0.99987182617187488 +1.373125 -0.047027587890625 0.0 -0.99987182617187488 +1.37325 -0.04180908203125 0.0 -0.99987182617187488 +1.373375 -0.04180908203125 0.0 -0.99987182617187488 +1.3735 -0.036590576171875 0.0 -0.99987182617187488 +1.373625 -0.0313720703125 0.0 -0.99987182617187488 +1.37375 -0.0313720703125 0.0 -0.99987182617187488 +1.373875 -0.026123046875 0.0 -0.99987182617187488 +1.374 -0.026123046875 0.0 -0.99987182617187488 +1.374125 -0.020904541015625 0.0 -0.99987182617187488 +1.37425 -0.01568603515625 0.0 -0.99987182617187488 +1.3743750000000002 -0.01568603515625 0.0 -0.99987182617187488 +1.3745 -0.01043701171875 0.0 -0.99987182617187488 +1.374625 -0.01043701171875 0.0 -0.99987182617187488 +1.3747500000000002 -0.005218505859375 0.0 -0.99987182617187488 +1.374875 0.0 0.0 -0.99987182617187488 +1.375 0.0 0.0 -0.99987182617187488 +1.375125 0.005218505859375 0.0 -0.99987182617187488 +1.37525 0.005218505859375 0.0 -0.99987182617187488 +1.375375 0.01043701171875 0.0 -0.99987182617187488 +1.3755 0.01568603515625 0.0 -0.99987182617187488 +1.375625 0.01568603515625 0.0 -0.99987182617187488 +1.37575 0.020904541015625 0.0 -0.99987182617187488 +1.375875 0.020904541015625 0.0 -0.99987182617187488 +1.3760000000000002 0.026123046875 0.002197265625 -0.915197753906247 +1.376125 0.0313720703125 0.002655029296875 -0.915197753906247 +1.37625 0.0313720703125 0.002655029296875 -0.915197753906247 +1.3763750000000002 0.036590576171875 0.003082275390625 -0.915197753906247 +1.3765 0.036590576171875 0.003082275390625 -0.915197753906247 +1.376625 0.04180908203125 0.0035400390625 -0.915197753906247 +1.37675 0.047027587890625 0.00396728515625 -0.915197753906247 +1.376875 0.047027587890625 0.00396728515625 -0.915197753906247 +1.377 0.05224609375 0.004425048828125 -0.915197753906247 +1.377125 0.05224609375 0.004425048828125 -0.915197753906247 +1.37725 0.05743408203125 0.004852294921875 -0.915197753906247 +1.377375 0.0626220703125 0.005279541015625 -0.915197753906247 +1.3775 0.0626220703125 0.005279541015625 -0.915197753906247 +1.377625 0.06781005859375 0.0057373046875 -0.915197753906247 +1.37775 0.06781005859375 0.0057373046875 -0.915197753906247 +1.377875 0.072998046875 0.00616455078125 -0.915197753906247 +1.3780000000000002 0.07818603515625 0.006622314453125 -0.915197753906247 +1.378125 0.07818603515625 0.006622314453125 -0.915197753906247 +1.37825 0.083343505859375 0.007049560546875 -0.915197753906247 +1.3783750000000002 0.083343505859375 0.007049560546875 -0.915197753906247 +1.3785 0.0885009765625 0.007476806640625 -0.915197753906247 +1.378625 0.093658447265625 0.0079345703125 -0.915197753906247 +1.37875 0.093658447265625 0.0079345703125 -0.915197753906247 +1.378875 0.098785400390625 0.00836181640625 -0.915197753906247 +1.379 0.098785400390625 0.00836181640625 -0.915197753906247 +1.379125 0.103912353515625 0.0087890625 -0.915197753906247 +1.37925 0.109039306640625 0.00921630859375 -0.915197753906247 +1.379375 0.109039306640625 0.00921630859375 -0.915197753906247 +1.3795 0.1141357421875 0.0096435546875 -0.915197753906247 +1.379625 0.1141357421875 0.0096435546875 -0.915197753906247 +1.37975 0.119232177734375 0.010101318359375 -0.915197753906247 +1.379875 0.124298095703125 0.010528564453125 -0.915197753906247 +1.3800000000000002 0.124298095703125 0.010528564453125 -0.915197753906247 +1.380125 0.129364013671875 0.010955810546875 -0.915197753906247 +1.38025 0.129364013671875 0.010955810546875 -0.915197753906247 +1.3803750000000002 0.134429931640625 0.011383056640625 -0.915197753906247 +1.3805 0.13946533203125 0.011810302734375 -0.915197753906247 +1.380625 0.13946533203125 0.011810302734375 -0.915197753906247 +1.38075 0.14447021484375 0.012237548828125 -0.915197753906247 +1.380875 0.14447021484375 0.012237548828125 -0.915197753906247 +1.381 0.14947509765625 0.012664794921875 -0.915197753906247 +1.381125 0.15447998046875 0.0130615234375 -0.915197753906247 +1.38125 0.15447998046875 0.0130615234375 -0.915197753906247 +1.381375 0.159454345703125 0.01348876953125 -0.915197753906247 +1.3815 0.159454345703125 0.01348876953125 -0.915197753906247 +1.381625 0.164398193359375 0.013916015625 -0.915197753906247 +1.38175 0.169342041015625 0.01434326171875 -0.915197753906247 +1.381875 0.169342041015625 0.01434326171875 -0.915197753906247 +1.3820000000000002 0.17425537109375 0.014739990234375 -0.915197753906247 +1.382125 0.17425537109375 0.014739990234375 -0.915197753906247 +1.38225 0.17913818359375 0.015167236328125 -0.915197753906247 +1.3823750000000002 0.18402099609375 0.01556396484375 -0.915197753906247 +1.3825 0.18402099609375 0.01556396484375 -0.915197753906247 +1.382625 0.188873291015625 0.0159912109375 -0.915197753906247 +1.38275 0.188873291015625 0.0159912109375 -0.915197753906247 +1.382875 0.1937255859375 0.016387939453125 -0.915197753906247 +1.383 0.19854736328125 0.016815185546875 -0.915197753906247 +1.383125 0.19854736328125 0.016815185546875 -0.915197753906247 +1.38325 0.203338623046875 0.0172119140625 -0.915197753906247 +1.383375 0.203338623046875 0.0172119140625 -0.915197753906247 +1.3835 0.208099365234375 0.017608642578125 -0.915197753906247 +1.383625 0.212860107421875 0.01800537109375 -0.915197753906247 +1.38375 0.212860107421875 0.01800537109375 -0.915197753906247 +1.383875 0.21759033203125 0.0184326171875 -0.915197753906247 +1.3840000000000002 0.21759033203125 0.0184326171875 -0.915197753906247 +1.384125 0.2222900390625 0.018829345703125 -0.915197753906247 +1.38425 0.226959228515625 0.01922607421875 -0.915197753906247 +1.3843750000000002 0.226959228515625 0.01922607421875 -0.915197753906247 +1.3845 0.231597900390625 0.019622802734375 -0.915197753906247 +1.384625 0.231597900390625 0.019622802734375 -0.915197753906247 +1.38475 0.236236572265625 0.019989013671875 -0.915197753906247 +1.384875 0.2408447265625 0.0203857421875 -0.915197753906247 +1.385 0.2408447265625 0.0203857421875 -0.915197753906247 +1.385125 0.24542236328125 0.020782470703125 -0.915197753906247 +1.38525 0.24542236328125 0.020782470703125 -0.915197753906247 +1.385375 0.249969482421875 0.021148681640625 -0.915197753906247 +1.3855 0.25445556640625 0.02154541015625 -0.915197753906247 +1.385625 0.25445556640625 0.02154541015625 -0.915197753906247 +1.38575 0.25897216796875 0.02191162109375 -0.915197753906247 +1.385875 0.25897216796875 0.02191162109375 -0.915197753906247 +1.3860000000000002 0.263427734375 0.022308349609375 -0.915197753906247 +1.386125 0.267852783203125 0.022674560546875 -0.915197753906247 +1.38625 0.267852783203125 0.022674560546875 -0.915197753906247 +1.3863750000000002 0.27227783203125 0.023040771484375 -0.915197753906247 +1.3865 0.27227783203125 0.023040771484375 -0.915197753906247 +1.386625 0.276641845703125 0.0234375 -0.915197753906247 +1.38675 0.280975341796875 0.0238037109375 -0.915197753906247 +1.386875 0.280975341796875 0.0238037109375 -0.915197753906247 +1.387 0.285308837890625 0.024169921875 -0.915197753906247 +1.387125 0.285308837890625 0.024169921875 -0.915197753906247 +1.38725 0.289581298828125 0.0245361328125 -0.915197753906247 +1.387375 0.2938232421875 0.024871826171875 -0.915197753906247 +1.3875 0.2938232421875 0.024871826171875 -0.915197753906247 +1.387625 0.298065185546875 0.025238037109375 -0.915197753906247 +1.38775 0.298065185546875 0.025238037109375 -0.915197753906247 +1.387875 0.30224609375 0.025604248046875 -0.915197753906247 +1.3880000000000002 0.306396484375 0.02593994140625 -0.915197753906247 +1.388125 0.306396484375 0.02593994140625 -0.915197753906247 +1.38825 0.310516357421875 0.02630615234375 -0.915197753906247 +1.3883750000000002 0.310516357421875 0.02630615234375 -0.915197753906247 +1.3885 0.314605712890625 0.026641845703125 -0.915197753906247 +1.388625 0.31866455078125 0.0269775390625 -0.915197753906247 +1.38875 0.31866455078125 0.0269775390625 -0.915197753906247 +1.388875 0.322662353515625 0.027313232421875 -0.915197753906247 +1.389 0.322662353515625 0.027313232421875 -0.915197753906247 +1.389125 0.32666015625 0.02764892578125 -0.915197753906247 +1.38925 0.330596923828125 0.027984619140625 -0.915197753906247 +1.389375 0.330596923828125 0.027984619140625 -0.915197753906247 +1.3895 0.334503173828125 0.0283203125 -0.915197753906247 +1.389625 0.334503173828125 0.0283203125 -0.915197753906247 +1.38975 0.33837890625 0.028656005859375 -0.915197753906247 +1.389875 0.34222412109375 0.02899169921875 -0.915197753906247 +1.3900000000000002 0.34222412109375 0.02899169921875 -0.915197753906247 +1.390125 0.34600830078125 0.029296875 -0.915197753906247 +1.39025 0.34600830078125 0.029296875 -0.915197753906247 +1.3903750000000002 0.349761962890625 0.029632568359375 -0.915197753906247 +1.3905 0.353485107421875 0.029937744140625 -0.915197753906247 +1.390625 0.353485107421875 0.029937744140625 -0.915197753906247 +1.39075 0.357177734375 0.030242919921875 -0.915197753906247 +1.390875 0.357177734375 0.030242919921875 -0.915197753906247 +1.391 0.360809326171875 0.030548095703125 -0.915197753906247 +1.391125 0.36444091796875 0.030853271484375 -0.915197753906247 +1.39125 0.36444091796875 0.030853271484375 -0.915197753906247 +1.391375 0.36798095703125 0.031158447265625 -0.915197753906247 +1.3915 0.36798095703125 0.031158447265625 -0.915197753906247 +1.3916250000000002 0.37152099609375 0.031463623046875 -0.915197753906247 +1.39175 0.375 0.031768798828125 -0.915197753906247 +1.391875 0.375 0.031768798828125 -0.915197753906247 +1.3920000000000002 0.378448486328125 0.03204345703125 -0.915197753906247 +1.392125 0.378448486328125 0.03204345703125 -0.915197753906247 +1.39225 0.3818359375 0.0323486328125 -0.915197753906247 +1.392375 0.38519287109375 0.032623291015625 -0.915197753906247 +1.3925 0.38519287109375 0.032623291015625 -0.915197753906247 +1.392625 0.388519287109375 0.03289794921875 -0.915197753906247 +1.39275 0.388519287109375 0.03289794921875 -0.915197753906247 +1.392875 0.39178466796875 0.033172607421875 -0.915197753906247 +1.393 0.39501953125 0.033447265625 -0.915197753906247 +1.393125 0.39501953125 0.033447265625 -0.915197753906247 +1.39325 0.398193359375 0.033721923828125 -0.915197753906247 +1.393375 0.398193359375 0.033721923828125 -0.915197753906247 +1.3935 0.401336669921875 0.03399658203125 -0.915197753906247 +1.3936250000000002 0.404449462890625 0.03424072265625 -0.915197753906247 +1.39375 0.404449462890625 0.03424072265625 -0.915197753906247 +1.393875 0.407501220703125 0.034515380859375 -0.915197753906247 +1.3940000000000002 0.407501220703125 0.034515380859375 -0.915197753906247 +1.394125 0.4105224609375 0.034759521484375 -0.915197753906247 +1.39425 0.413482666015625 0.035003662109375 -0.915197753906247 +1.394375 0.413482666015625 0.035003662109375 -0.915197753906247 +1.3945 0.416412353515625 0.0352783203125 -0.915197753906247 +1.394625 0.416412353515625 0.0352783203125 -0.915197753906247 +1.39475 0.419281005859375 0.0355224609375 -0.915197753906247 +1.394875 0.422119140625 0.035736083984375 -0.915197753906247 +1.395 0.422119140625 0.035736083984375 -0.915197753906247 +1.395125 0.424896240234375 0.035980224609375 -0.915197753906247 +1.39525 0.424896240234375 0.035980224609375 -0.915197753906247 +1.395375 0.4276123046875 0.036224365234375 -0.915197753906247 +1.3955 0.4302978515625 0.03643798828125 -0.915197753906247 +1.3956250000000002 0.4302978515625 0.03643798828125 -0.915197753906247 +1.39575 0.432952880859375 0.03668212890625 -0.915197753906247 +1.395875 0.432952880859375 0.03668212890625 -0.915197753906247 +1.3960000000000002 0.435546875 0.036895751953125 -0.915197753906247 +1.396125 0.438079833984375 0.037109375 -0.915197753906247 +1.39625 0.438079833984375 0.037109375 -0.915197753906247 +1.396375 0.440582275390625 0.037322998046875 -0.915197753906247 +1.3965 0.440582275390625 0.037322998046875 -0.915197753906247 +1.396625 0.44305419921875 0.03753662109375 -0.915197753906247 +1.39675 0.4454345703125 0.0377197265625 -0.915197753906247 +1.396875 0.4454345703125 0.0377197265625 -0.915197753906247 +1.397 0.447784423828125 0.037933349609375 -0.915197753906247 +1.397125 0.447784423828125 0.037933349609375 -0.915197753906247 +1.39725 0.450103759765625 0.038116455078125 -0.915197753906247 +1.397375 0.452362060546875 0.038299560546875 -0.915197753906247 +1.3975 0.452362060546875 0.038299560546875 -0.915197753906247 +1.3976250000000002 0.454559326171875 0.038482666015625 -0.915197753906247 +1.39775 0.454559326171875 0.038482666015625 -0.915197753906247 +1.397875 0.45672607421875 0.038665771484375 -0.915197753906247 +1.3980000000000002 0.458831787109375 0.038848876953125 -0.915197753906247 +1.398125 0.458831787109375 0.038848876953125 -0.915197753906247 +1.39825 0.46087646484375 0.039031982421875 -0.915197753906247 +1.398375 0.46087646484375 0.039031982421875 -0.915197753906247 +1.3985 0.462890625 0.039215087890625 -0.915197753906247 +1.398625 0.464813232421875 0.03936767578125 -0.915197753906247 +1.39875 0.464813232421875 0.03936767578125 -0.915197753906247 +1.398875 0.46673583984375 0.039520263671875 -0.915197753906247 +1.399 0.46673583984375 0.039520263671875 -0.915197753906247 +1.399125 0.46856689453125 0.0396728515625 -0.915197753906247 +1.39925 0.470367431640625 0.039825439453125 -0.915197753906247 +1.399375 0.470367431640625 0.039825439453125 -0.915197753906247 +1.3995 0.472137451171875 0.03997802734375 -0.915197753906247 +1.3996250000000002 0.472137451171875 0.03997802734375 -0.915197753906247 +1.39975 0.47381591796875 0.040130615234375 -0.915197753906247 +1.399875 0.4754638671875 0.040283203125 -0.915197753906247 +1.4000000000000002 0.4754638671875 0.040283203125 -0.915197753906247 +1.400125 0.47705078125 0.0404052734375 -0.915197753906247 +1.40025 0.47705078125 0.0404052734375 -0.915197753906247 +1.400375 0.478607177734375 0.04052734375 -0.915197753906247 +1.4005 0.480072021484375 0.0406494140625 -0.915197753906247 +1.400625 0.480072021484375 0.0406494140625 -0.915197753906247 +1.40075 0.48150634765625 0.040771484375 -0.915197753906247 +1.400875 0.48150634765625 0.040771484375 -0.915197753906247 +1.401 0.48291015625 0.0408935546875 -0.915197753906247 +1.401125 0.484222412109375 0.041015625 -0.915197753906247 +1.40125 0.484222412109375 0.041015625 -0.915197753906247 +1.401375 0.485504150390625 0.041107177734375 -0.915197753906247 +1.4015 0.485504150390625 0.041107177734375 -0.915197753906247 +1.4016250000000002 0.486724853515625 0.041229248046875 -0.915197753906247 +1.40175 0.487884521484375 0.04132080078125 -0.915197753906247 +1.401875 0.487884521484375 0.04132080078125 -0.915197753906247 +1.4020000000000002 0.489013671875 0.041412353515625 -0.915197753906247 +1.402125 0.489013671875 0.041412353515625 -0.915197753906247 +1.40225 0.490081787109375 0.04150390625 -0.915197753906247 +1.402375 0.4910888671875 0.041595458984375 -0.915197753906247 +1.4025 0.4910888671875 0.041595458984375 -0.915197753906247 +1.402625 0.492034912109375 0.04168701171875 -0.915197753906247 +1.40275 0.492034912109375 0.04168701171875 -0.915197753906247 +1.402875 0.492950439453125 0.041748046875 -0.915197753906247 +1.403 0.4937744140625 0.04180908203125 -0.915197753906247 +1.403125 0.4937744140625 0.04180908203125 -0.915197753906247 +1.40325 0.49456787109375 0.041900634765625 -0.915197753906247 +1.403375 0.49456787109375 0.041900634765625 -0.915197753906247 +1.4035 0.49530029296875 0.041961669921875 -0.915197753906247 +1.4036250000000002 0.496002197265625 0.0419921875 -0.915197753906247 +1.40375 0.496002197265625 0.0419921875 -0.915197753906247 +1.403875 0.496612548828125 0.04205322265625 -0.915197753906247 +1.4040000000000002 0.496612548828125 0.04205322265625 -0.915197753906247 +1.404125 0.4971923828125 0.0421142578125 -0.915197753906247 +1.40425 0.497711181640625 0.042144775390625 -0.915197753906247 +1.404375 0.497711181640625 0.042144775390625 -0.915197753906247 +1.4045 0.498199462890625 0.042205810546875 -0.915197753906247 +1.404625 0.498199462890625 0.042205810546875 -0.915197753906247 +1.40475 0.49859619140625 0.042236328125 -0.915197753906247 +1.404875 0.49896240234375 0.042266845703125 -0.915197753906247 +1.405 0.49896240234375 0.042266845703125 -0.915197753906247 +1.405125 0.499267578125 0.04229736328125 -0.915197753906247 +1.40525 0.499267578125 0.04229736328125 -0.915197753906247 +1.405375 0.49951171875 0.04229736328125 -0.915197753906247 +1.4055 0.49969482421875 0.042327880859375 -0.915197753906247 +1.4056250000000002 0.49969482421875 0.042327880859375 -0.915197753906247 +1.40575 0.49981689453125 0.042327880859375 -0.915197753906247 +1.405875 0.49981689453125 0.042327880859375 -0.915197753906247 +1.4060000000000002 0.499908447265625 0.042327880859375 -0.915197753906247 +1.406125 0.49993896484375 0.042327880859375 -0.915197753906247 +1.40625 0.49993896484375 0.042327880859375 -0.915197753906247 +1.406375 0.499908447265625 0.042327880859375 -0.915197753906247 +1.4065 0.499908447265625 0.042327880859375 -0.915197753906247 +1.406625 0.49981689453125 0.042327880859375 -0.915197753906247 +1.40675 0.49969482421875 0.042327880859375 -0.915197753906247 +1.406875 0.49969482421875 0.042327880859375 -0.915197753906247 +1.407 0.49951171875 0.04229736328125 -0.915197753906247 +1.407125 0.49951171875 0.04229736328125 -0.915197753906247 +1.4072500000000002 0.499267578125 0.04229736328125 -0.915197753906247 +1.407375 0.49896240234375 0.042266845703125 -0.915197753906247 +1.4075 0.49896240234375 0.042266845703125 -0.915197753906247 +1.4076250000000002 0.49859619140625 0.042236328125 -0.915197753906247 +1.40775 0.49859619140625 0.042236328125 -0.915197753906247 +1.407875 0.498199462890625 0.042205810546875 -0.915197753906247 +1.408 0.497711181640625 0.156982421875 -0.6845092773437448 +1.408125 0.497711181640625 0.156982421875 -0.6845092773437448 +1.40825 0.4971923828125 0.15679931640625 -0.6845092773437448 +1.408375 0.4971923828125 0.15679931640625 -0.6845092773437448 +1.4085 0.496612548828125 0.1566162109375 -0.6845092773437448 +1.408625 0.496002197265625 0.15643310546875 -0.6845092773437448 +1.40875 0.496002197265625 0.15643310546875 -0.6845092773437448 +1.408875 0.49530029296875 0.156219482421875 -0.6845092773437448 +1.409 0.49530029296875 0.156219482421875 -0.6845092773437448 +1.409125 0.49456787109375 0.155975341796875 -0.6845092773437448 +1.4092500000000002 0.4937744140625 0.155731201171875 -0.6845092773437448 +1.409375 0.4937744140625 0.155731201171875 -0.6845092773437448 +1.4095 0.492950439453125 0.15545654296875 -0.6845092773437448 +1.4096250000000002 0.492950439453125 0.15545654296875 -0.6845092773437448 +1.40975 0.492034912109375 0.155181884765625 -0.6845092773437448 +1.409875 0.4910888671875 0.154876708984375 -0.6845092773437448 +1.41 0.4910888671875 0.154876708984375 -0.6845092773437448 +1.410125 0.490081787109375 0.154571533203125 -0.6845092773437448 +1.41025 0.490081787109375 0.154571533203125 -0.6845092773437448 +1.410375 0.489013671875 0.15423583984375 -0.6845092773437448 +1.4105 0.487884521484375 0.15386962890625 -0.6845092773437448 +1.410625 0.487884521484375 0.15386962890625 -0.6845092773437448 +1.41075 0.486724853515625 0.15350341796875 -0.6845092773437448 +1.410875 0.486724853515625 0.15350341796875 -0.6845092773437448 +1.411 0.485504150390625 0.15313720703125 -0.6845092773437448 +1.411125 0.484222412109375 0.1527099609375 -0.6845092773437448 +1.4112500000000002 0.484222412109375 0.1527099609375 -0.6845092773437448 +1.411375 0.48291015625 0.152313232421875 -0.6845092773437448 +1.4115 0.48291015625 0.152313232421875 -0.6845092773437448 +1.4116250000000002 0.48150634765625 0.15185546875 -0.6845092773437448 +1.41175 0.480072021484375 0.15142822265625 -0.6845092773437448 +1.411875 0.480072021484375 0.15142822265625 -0.6845092773437448 +1.412 0.478607177734375 0.15093994140625 -0.6845092773437448 +1.412125 0.478607177734375 0.15093994140625 -0.6845092773437448 +1.41225 0.47705078125 0.15045166015625 -0.6845092773437448 +1.412375 0.4754638671875 0.14996337890625 -0.6845092773437448 +1.4125 0.4754638671875 0.14996337890625 -0.6845092773437448 +1.412625 0.47381591796875 0.149444580078125 -0.6845092773437448 +1.41275 0.47381591796875 0.149444580078125 -0.6845092773437448 +1.412875 0.472137451171875 0.148895263671875 -0.6845092773437448 +1.413 0.470367431640625 0.148345947265625 -0.6845092773437448 +1.413125 0.470367431640625 0.148345947265625 -0.6845092773437448 +1.4132500000000002 0.46856689453125 0.147796630859375 -0.6845092773437448 +1.413375 0.46856689453125 0.147796630859375 -0.6845092773437448 +1.4135 0.46673583984375 0.147216796875 -0.6845092773437448 +1.4136250000000002 0.464813232421875 0.1466064453125 -0.6845092773437448 +1.41375 0.464813232421875 0.1466064453125 -0.6845092773437448 +1.413875 0.462890625 0.14599609375 -0.6845092773437448 +1.414 0.462890625 0.14599609375 -0.6845092773437448 +1.414125 0.46087646484375 0.145355224609375 -0.6845092773437448 +1.41425 0.458831787109375 0.14471435546875 -0.6845092773437448 +1.414375 0.458831787109375 0.14471435546875 -0.6845092773437448 +1.4145 0.45672607421875 0.14404296875 -0.6845092773437448 +1.414625 0.45672607421875 0.14404296875 -0.6845092773437448 +1.41475 0.454559326171875 0.14337158203125 -0.6845092773437448 +1.414875 0.452362060546875 0.142669677734375 -0.6845092773437448 +1.415 0.452362060546875 0.142669677734375 -0.6845092773437448 +1.415125 0.450103759765625 0.1419677734375 -0.6845092773437448 +1.4152500000000002 0.450103759765625 0.1419677734375 -0.6845092773437448 +1.415375 0.447784423828125 0.1412353515625 -0.6845092773437448 +1.4155 0.4454345703125 0.1405029296875 -0.6845092773437448 +1.4156250000000002 0.4454345703125 0.1405029296875 -0.6845092773437448 +1.41575 0.44305419921875 0.139739990234375 -0.6845092773437448 +1.415875 0.44305419921875 0.139739990234375 -0.6845092773437448 +1.416 0.440582275390625 0.138946533203125 -0.6845092773437448 +1.416125 0.438079833984375 0.13818359375 -0.6845092773437448 +1.41625 0.438079833984375 0.13818359375 -0.6845092773437448 +1.416375 0.435546875 0.137359619140625 -0.6845092773437448 +1.4165 0.435546875 0.137359619140625 -0.6845092773437448 +1.416625 0.432952880859375 0.136566162109375 -0.6845092773437448 +1.41675 0.4302978515625 0.135711669921875 -0.6845092773437448 +1.416875 0.4302978515625 0.135711669921875 -0.6845092773437448 +1.417 0.4276123046875 0.134857177734375 -0.6845092773437448 +1.417125 0.4276123046875 0.134857177734375 -0.6845092773437448 +1.4172500000000002 0.424896240234375 0.134002685546875 -0.6845092773437448 +1.417375 0.422119140625 0.13311767578125 -0.6845092773437448 +1.4175 0.422119140625 0.13311767578125 -0.6845092773437448 +1.4176250000000002 0.419281005859375 0.132232666015625 -0.6845092773437448 +1.41775 0.419281005859375 0.132232666015625 -0.6845092773437448 +1.417875 0.416412353515625 0.131317138671875 -0.6845092773437448 +1.418 0.413482666015625 0.130401611328125 -0.6845092773437448 +1.418125 0.413482666015625 0.130401611328125 -0.6845092773437448 +1.41825 0.4105224609375 0.129486083984375 -0.6845092773437448 +1.418375 0.4105224609375 0.129486083984375 -0.6845092773437448 +1.4185 0.407501220703125 0.128509521484375 -0.6845092773437448 +1.418625 0.404449462890625 0.1275634765625 -0.6845092773437448 +1.41875 0.404449462890625 0.1275634765625 -0.6845092773437448 +1.418875 0.401336669921875 0.1265869140625 -0.6845092773437448 +1.419 0.401336669921875 0.1265869140625 -0.6845092773437448 +1.419125 0.398193359375 0.125579833984375 -0.6845092773437448 +1.4192500000000002 0.39501953125 0.12457275390625 -0.6845092773437448 +1.419375 0.39501953125 0.12457275390625 -0.6845092773437448 +1.4195 0.39178466796875 0.123565673828125 -0.6845092773437448 +1.4196250000000002 0.39178466796875 0.123565673828125 -0.6845092773437448 +1.41975 0.388519287109375 0.122528076171875 -0.6845092773437448 +1.419875 0.38519287109375 0.121490478515625 -0.6845092773437448 +1.42 0.38519287109375 0.121490478515625 -0.6845092773437448 +1.420125 0.3818359375 0.12042236328125 -0.6845092773437448 +1.42025 0.3818359375 0.12042236328125 -0.6845092773437448 +1.420375 0.378448486328125 0.119354248046875 -0.6845092773437448 +1.4205 0.375 0.118255615234375 -0.6845092773437448 +1.420625 0.375 0.118255615234375 -0.6845092773437448 +1.42075 0.37152099609375 0.117156982421875 -0.6845092773437448 +1.420875 0.37152099609375 0.117156982421875 -0.6845092773437448 +1.421 0.36798095703125 0.116058349609375 -0.6845092773437448 +1.421125 0.36444091796875 0.11492919921875 -0.6845092773437448 +1.4212500000000002 0.36444091796875 0.11492919921875 -0.6845092773437448 +1.421375 0.360809326171875 0.113800048828125 -0.6845092773437448 +1.4215 0.360809326171875 0.113800048828125 -0.6845092773437448 +1.4216250000000002 0.357177734375 0.112640380859375 -0.6845092773437448 +1.42175 0.353485107421875 0.111480712890625 -0.6845092773437448 +1.421875 0.353485107421875 0.111480712890625 -0.6845092773437448 +1.422 0.349761962890625 0.110321044921875 -0.6845092773437448 +1.422125 0.349761962890625 0.110321044921875 -0.6845092773437448 +1.42225 0.34600830078125 0.109130859375 -0.6845092773437448 +1.422375 0.34222412109375 0.107940673828125 -0.6845092773437448 +1.4225 0.34222412109375 0.107940673828125 -0.6845092773437448 +1.422625 0.33837890625 0.106719970703125 -0.6845092773437448 +1.42275 0.33837890625 0.106719970703125 -0.6845092773437448 +1.4228750000000002 0.334503173828125 0.105499267578125 -0.6845092773437448 +1.423 0.330596923828125 0.104278564453125 -0.6845092773437448 +1.423125 0.330596923828125 0.104278564453125 -0.6845092773437448 +1.4232500000000002 0.32666015625 0.10302734375 -0.6845092773437448 +1.423375 0.32666015625 0.10302734375 -0.6845092773437448 +1.4235 0.322662353515625 0.101776123046875 -0.6845092773437448 +1.4236250000000002 0.31866455078125 0.100494384765625 -0.6845092773437448 +1.42375 0.31866455078125 0.100494384765625 -0.6845092773437448 +1.423875 0.314605712890625 0.099212646484375 -0.6845092773437448 +1.424 0.314605712890625 0.099212646484375 -0.6845092773437448 +1.424125 0.310516357421875 0.097930908203125 -0.6845092773437448 +1.42425 0.306396484375 0.096649169921875 -0.6845092773437448 +1.424375 0.306396484375 0.096649169921875 -0.6845092773437448 +1.4245 0.30224609375 0.0953369140625 -0.6845092773437448 +1.424625 0.30224609375 0.0953369140625 -0.6845092773437448 +1.42475 0.298065185546875 0.093994140625 -0.6845092773437448 +1.4248750000000002 0.2938232421875 0.092681884765625 -0.6845092773437448 +1.425 0.2938232421875 0.092681884765625 -0.6845092773437448 +1.425125 0.289581298828125 0.091339111328125 -0.6845092773437448 +1.4252500000000002 0.289581298828125 0.091339111328125 -0.6845092773437448 +1.425375 0.285308837890625 0.0899658203125 -0.6845092773437448 +1.4255 0.280975341796875 0.088623046875 -0.6845092773437448 +1.425625 0.280975341796875 0.088623046875 -0.6845092773437448 +1.42575 0.276641845703125 0.087249755859375 -0.6845092773437448 +1.425875 0.276641845703125 0.087249755859375 -0.6845092773437448 +1.426 0.27227783203125 0.08587646484375 -0.6845092773437448 +1.426125 0.267852783203125 0.08447265625 -0.6845092773437448 +1.42625 0.267852783203125 0.08447265625 -0.6845092773437448 +1.426375 0.263427734375 0.08306884765625 -0.6845092773437448 +1.4265 0.263427734375 0.08306884765625 -0.6845092773437448 +1.426625 0.25897216796875 0.0816650390625 -0.6845092773437448 +1.42675 0.25445556640625 0.08026123046875 -0.6845092773437448 +1.4268750000000002 0.25445556640625 0.08026123046875 -0.6845092773437448 +1.427 0.249969482421875 0.078826904296875 -0.6845092773437448 +1.427125 0.249969482421875 0.078826904296875 -0.6845092773437448 +1.4272500000000002 0.24542236328125 0.077392578125 -0.6845092773437448 +1.427375 0.2408447265625 0.075958251953125 -0.6845092773437448 +1.4275 0.2408447265625 0.075958251953125 -0.6845092773437448 +1.427625 0.236236572265625 0.074493408203125 -0.6845092773437448 +1.42775 0.236236572265625 0.074493408203125 -0.6845092773437448 +1.427875 0.231597900390625 0.073028564453125 -0.6845092773437448 +1.428 0.226959228515625 0.071563720703125 -0.6845092773437448 +1.428125 0.226959228515625 0.071563720703125 -0.6845092773437448 +1.42825 0.2222900390625 0.070098876953125 -0.6845092773437448 +1.428375 0.2222900390625 0.070098876953125 -0.6845092773437448 +1.4285 0.21759033203125 0.068603515625 -0.6845092773437448 +1.428625 0.212860107421875 0.067138671875 -0.6845092773437448 +1.42875 0.212860107421875 0.067138671875 -0.6845092773437448 +1.4288750000000002 0.208099365234375 0.065643310546875 -0.6845092773437448 +1.429 0.208099365234375 0.065643310546875 -0.6845092773437448 +1.429125 0.203338623046875 0.064117431640625 -0.6845092773437448 +1.4292500000000002 0.19854736328125 0.0626220703125 -0.6845092773437448 +1.429375 0.19854736328125 0.0626220703125 -0.6845092773437448 +1.4295 0.1937255859375 0.06109619140625 -0.6845092773437448 +1.429625 0.1937255859375 0.06109619140625 -0.6845092773437448 +1.42975 0.188873291015625 0.0595703125 -0.6845092773437448 +1.429875 0.18402099609375 0.05804443359375 -0.6845092773437448 +1.43 0.18402099609375 0.05804443359375 -0.6845092773437448 +1.430125 0.17913818359375 0.056488037109375 -0.6845092773437448 +1.43025 0.17913818359375 0.056488037109375 -0.6845092773437448 +1.430375 0.17425537109375 0.054962158203125 -0.6845092773437448 +1.4305 0.169342041015625 0.05340576171875 -0.6845092773437448 +1.430625 0.169342041015625 0.05340576171875 -0.6845092773437448 +1.43075 0.164398193359375 0.051849365234375 -0.6845092773437448 +1.4308750000000002 0.164398193359375 0.051849365234375 -0.6845092773437448 +1.431 0.159454345703125 0.05029296875 -0.6845092773437448 +1.431125 0.15447998046875 0.0487060546875 -0.6845092773437448 +1.4312500000000002 0.15447998046875 0.0487060546875 -0.6845092773437448 +1.431375 0.14947509765625 0.047149658203125 -0.6845092773437448 +1.4315 0.14947509765625 0.047149658203125 -0.6845092773437448 +1.431625 0.14447021484375 0.045562744140625 -0.6845092773437448 +1.43175 0.13946533203125 0.043975830078125 -0.6845092773437448 +1.431875 0.13946533203125 0.043975830078125 -0.6845092773437448 +1.432 0.134429931640625 0.042388916015625 -0.6845092773437448 +1.432125 0.134429931640625 0.042388916015625 -0.6845092773437448 +1.43225 0.129364013671875 0.040802001953125 -0.6845092773437448 +1.432375 0.124298095703125 0.0391845703125 -0.6845092773437448 +1.4325 0.124298095703125 0.0391845703125 -0.6845092773437448 +1.432625 0.119232177734375 0.03759765625 -0.6845092773437448 +1.43275 0.119232177734375 0.03759765625 -0.6845092773437448 +1.4328750000000002 0.1141357421875 0.035980224609375 -0.6845092773437448 +1.433 0.109039306640625 0.034393310546875 -0.6845092773437448 +1.433125 0.109039306640625 0.034393310546875 -0.6845092773437448 +1.4332500000000002 0.103912353515625 0.03277587890625 -0.6845092773437448 +1.433375 0.103912353515625 0.03277587890625 -0.6845092773437448 +1.4335 0.098785400390625 0.031158447265625 -0.6845092773437448 +1.433625 0.093658447265625 0.029541015625 -0.6845092773437448 +1.43375 0.093658447265625 0.029541015625 -0.6845092773437448 +1.433875 0.0885009765625 0.02789306640625 -0.6845092773437448 +1.434 0.0885009765625 0.02789306640625 -0.6845092773437448 +1.434125 0.083343505859375 0.026275634765625 -0.6845092773437448 +1.43425 0.07818603515625 0.024658203125 -0.6845092773437448 +1.434375 0.07818603515625 0.024658203125 -0.6845092773437448 +1.4345 0.072998046875 0.02301025390625 -0.6845092773437448 +1.434625 0.072998046875 0.02301025390625 -0.6845092773437448 +1.43475 0.06781005859375 0.021392822265625 -0.6845092773437448 +1.4348750000000002 0.0626220703125 0.019744873046875 -0.6845092773437448 +1.435 0.0626220703125 0.019744873046875 -0.6845092773437448 +1.435125 0.05743408203125 0.018096923828125 -0.6845092773437448 +1.4352500000000002 0.05743408203125 0.018096923828125 -0.6845092773437448 +1.435375 0.05224609375 0.0164794921875 -0.6845092773437448 +1.4355 0.047027587890625 0.01483154296875 -0.6845092773437448 +1.435625 0.047027587890625 0.01483154296875 -0.6845092773437448 +1.43575 0.04180908203125 0.01318359375 -0.6845092773437448 +1.435875 0.04180908203125 0.01318359375 -0.6845092773437448 +1.436 0.036590576171875 0.01153564453125 -0.6845092773437448 +1.436125 0.0313720703125 0.0098876953125 -0.6845092773437448 +1.43625 0.0313720703125 0.0098876953125 -0.6845092773437448 +1.436375 0.026123046875 0.00823974609375 -0.6845092773437448 +1.4365 0.026123046875 0.00823974609375 -0.6845092773437448 +1.436625 0.020904541015625 0.006591796875 -0.6845092773437448 +1.43675 0.01568603515625 0.00494384765625 -0.6845092773437448 +1.4368750000000002 0.01568603515625 0.00494384765625 -0.6845092773437448 +1.437 0.01043701171875 0.0032958984375 -0.6845092773437448 +1.437125 0.01043701171875 0.0032958984375 -0.6845092773437448 +1.4372500000000002 0.005218505859375 0.00164794921875 -0.6845092773437448 +1.437375 0.0 0.0 -0.6845092773437448 +1.4375 0.0 0.0 -0.6845092773437448 +1.437625 -0.005218505859375 -0.00164794921875 -0.6845092773437448 +1.43775 -0.005218505859375 -0.00164794921875 -0.6845092773437448 +1.437875 -0.01043701171875 -0.0032958984375 -0.6845092773437448 +1.438 -0.01568603515625 -0.00494384765625 -0.6845092773437448 +1.438125 -0.01568603515625 -0.00494384765625 -0.6845092773437448 +1.43825 -0.020904541015625 -0.006591796875 -0.6845092773437448 +1.438375 -0.020904541015625 -0.006591796875 -0.6845092773437448 +1.4385000000000002 -0.026123046875 -0.00823974609375 -0.6845092773437448 +1.438625 -0.0313720703125 -0.0098876953125 -0.6845092773437448 +1.43875 -0.0313720703125 -0.0098876953125 -0.6845092773437448 +1.4388750000000002 -0.036590576171875 -0.01153564453125 -0.6845092773437448 +1.439 -0.036590576171875 -0.01153564453125 -0.6845092773437448 +1.439125 -0.04180908203125 -0.01318359375 -0.6845092773437448 +1.4392500000000002 -0.047027587890625 -0.01483154296875 -0.6845092773437448 +1.439375 -0.047027587890625 -0.01483154296875 -0.6845092773437448 +1.4395 -0.05224609375 -0.0164794921875 -0.6845092773437448 +1.439625 -0.05224609375 -0.0164794921875 -0.6845092773437448 +1.43975 -0.05743408203125 -0.018096923828125 -0.6845092773437448 +1.439875 -0.0626220703125 -0.019744873046875 -0.6845092773437448 +1.44 -0.0626220703125 -0.041046142578125 -0.3446105957031174 +1.440125 -0.06781005859375 -0.04443359375 -0.3446105957031174 +1.44025 -0.06781005859375 -0.04443359375 -0.3446105957031174 +1.440375 -0.072998046875 -0.0478515625 -0.3446105957031174 +1.4405000000000002 -0.07818603515625 -0.051239013671875 -0.3446105957031174 +1.440625 -0.07818603515625 -0.051239013671875 -0.3446105957031174 +1.44075 -0.083343505859375 -0.05462646484375 -0.3446105957031174 +1.4408750000000002 -0.083343505859375 -0.05462646484375 -0.3446105957031174 +1.441 -0.0885009765625 -0.058013916015625 -0.3446105957031174 +1.441125 -0.093658447265625 -0.061370849609375 -0.3446105957031174 +1.44125 -0.093658447265625 -0.061370849609375 -0.3446105957031174 +1.441375 -0.098785400390625 -0.064727783203125 -0.3446105957031174 +1.4415 -0.098785400390625 -0.064727783203125 -0.3446105957031174 +1.441625 -0.103912353515625 -0.068084716796875 -0.3446105957031174 +1.44175 -0.109039306640625 -0.071441650390625 -0.3446105957031174 +1.441875 -0.109039306640625 -0.071441650390625 -0.3446105957031174 +1.442 -0.1141357421875 -0.074798583984375 -0.3446105957031174 +1.442125 -0.1141357421875 -0.074798583984375 -0.3446105957031174 +1.44225 -0.119232177734375 -0.078125 -0.3446105957031174 +1.442375 -0.124298095703125 -0.081451416015625 -0.3446105957031174 +1.4425000000000002 -0.124298095703125 -0.081451416015625 -0.3446105957031174 +1.442625 -0.129364013671875 -0.08477783203125 -0.3446105957031174 +1.44275 -0.129364013671875 -0.08477783203125 -0.3446105957031174 +1.4428750000000002 -0.134429931640625 -0.08807373046875 -0.3446105957031174 +1.443 -0.13946533203125 -0.091400146484375 -0.3446105957031174 +1.443125 -0.13946533203125 -0.091400146484375 -0.3446105957031174 +1.44325 -0.14447021484375 -0.09466552734375 -0.3446105957031174 +1.443375 -0.14447021484375 -0.09466552734375 -0.3446105957031174 +1.4435 -0.14947509765625 -0.09796142578125 -0.3446105957031174 +1.443625 -0.15447998046875 -0.101226806640625 -0.3446105957031174 +1.44375 -0.15447998046875 -0.101226806640625 -0.3446105957031174 +1.443875 -0.159454345703125 -0.1044921875 -0.3446105957031174 +1.444 -0.159454345703125 -0.1044921875 -0.3446105957031174 +1.444125 -0.164398193359375 -0.10772705078125 -0.3446105957031174 +1.44425 -0.169342041015625 -0.1109619140625 -0.3446105957031174 +1.444375 -0.169342041015625 -0.1109619140625 -0.3446105957031174 +1.4445000000000002 -0.17425537109375 -0.11419677734375 -0.3446105957031174 +1.444625 -0.17425537109375 -0.11419677734375 -0.3446105957031174 +1.44475 -0.17913818359375 -0.117401123046875 -0.3446105957031174 +1.4448750000000002 -0.18402099609375 -0.12060546875 -0.3446105957031174 +1.445 -0.18402099609375 -0.12060546875 -0.3446105957031174 +1.445125 -0.188873291015625 -0.123779296875 -0.3446105957031174 +1.44525 -0.188873291015625 -0.123779296875 -0.3446105957031174 +1.445375 -0.1937255859375 -0.126953125 -0.3446105957031174 +1.4455 -0.19854736328125 -0.130096435546875 -0.3446105957031174 +1.445625 -0.19854736328125 -0.130096435546875 -0.3446105957031174 +1.44575 -0.203338623046875 -0.13323974609375 -0.3446105957031174 +1.445875 -0.203338623046875 -0.13323974609375 -0.3446105957031174 +1.446 -0.208099365234375 -0.136383056640625 -0.3446105957031174 +1.446125 -0.212860107421875 -0.139495849609375 -0.3446105957031174 +1.44625 -0.212860107421875 -0.139495849609375 -0.3446105957031174 +1.446375 -0.21759033203125 -0.142578125 -0.3446105957031174 +1.4465000000000002 -0.21759033203125 -0.142578125 -0.3446105957031174 +1.446625 -0.2222900390625 -0.145660400390625 -0.3446105957031174 +1.44675 -0.226959228515625 -0.148712158203125 -0.3446105957031174 +1.4468750000000002 -0.226959228515625 -0.148712158203125 -0.3446105957031174 +1.447 -0.231597900390625 -0.151763916015625 -0.3446105957031174 +1.447125 -0.231597900390625 -0.151763916015625 -0.3446105957031174 +1.44725 -0.236236572265625 -0.154815673828125 -0.3446105957031174 +1.447375 -0.2408447265625 -0.157806396484375 -0.3446105957031174 +1.4475 -0.2408447265625 -0.157806396484375 -0.3446105957031174 +1.447625 -0.24542236328125 -0.16082763671875 -0.3446105957031174 +1.44775 -0.24542236328125 -0.16082763671875 -0.3446105957031174 +1.447875 -0.249969482421875 -0.163787841796875 -0.3446105957031174 +1.448 -0.25445556640625 -0.166748046875 -0.3446105957031174 +1.448125 -0.25445556640625 -0.166748046875 -0.3446105957031174 +1.44825 -0.25897216796875 -0.169708251953125 -0.3446105957031174 +1.448375 -0.25897216796875 -0.169708251953125 -0.3446105957031174 +1.4485000000000002 -0.263427734375 -0.172637939453125 -0.3446105957031174 +1.448625 -0.267852783203125 -0.175537109375 -0.3446105957031174 +1.44875 -0.267852783203125 -0.175537109375 -0.3446105957031174 +1.4488750000000002 -0.27227783203125 -0.178436279296875 -0.3446105957031174 +1.449 -0.27227783203125 -0.178436279296875 -0.3446105957031174 +1.449125 -0.276641845703125 -0.1812744140625 -0.3446105957031174 +1.44925 -0.280975341796875 -0.18414306640625 -0.3446105957031174 +1.449375 -0.280975341796875 -0.18414306640625 -0.3446105957031174 +1.4495 -0.285308837890625 -0.186981201171875 -0.3446105957031174 +1.449625 -0.285308837890625 -0.186981201171875 -0.3446105957031174 +1.44975 -0.289581298828125 -0.189788818359375 -0.3446105957031174 +1.449875 -0.2938232421875 -0.19256591796875 -0.3446105957031174 +1.45 -0.2938232421875 -0.19256591796875 -0.3446105957031174 +1.450125 -0.298065185546875 -0.195343017578125 -0.3446105957031174 +1.45025 -0.298065185546875 -0.195343017578125 -0.3446105957031174 +1.450375 -0.30224609375 -0.19805908203125 -0.3446105957031174 +1.4505000000000002 -0.306396484375 -0.2008056640625 -0.3446105957031174 +1.450625 -0.306396484375 -0.2008056640625 -0.3446105957031174 +1.45075 -0.310516357421875 -0.2034912109375 -0.3446105957031174 +1.4508750000000002 -0.310516357421875 -0.2034912109375 -0.3446105957031174 +1.451 -0.314605712890625 -0.2061767578125 -0.3446105957031174 +1.451125 -0.31866455078125 -0.208831787109375 -0.3446105957031174 +1.45125 -0.31866455078125 -0.208831787109375 -0.3446105957031174 +1.451375 -0.322662353515625 -0.211456298828125 -0.3446105957031174 +1.4515 -0.322662353515625 -0.211456298828125 -0.3446105957031174 +1.451625 -0.32666015625 -0.214080810546875 -0.3446105957031174 +1.45175 -0.330596923828125 -0.216644287109375 -0.3446105957031174 +1.451875 -0.330596923828125 -0.216644287109375 -0.3446105957031174 +1.452 -0.334503173828125 -0.219207763671875 -0.3446105957031174 +1.452125 -0.334503173828125 -0.219207763671875 -0.3446105957031174 +1.45225 -0.33837890625 -0.22174072265625 -0.3446105957031174 +1.452375 -0.34222412109375 -0.224273681640625 -0.3446105957031174 +1.4525000000000002 -0.34222412109375 -0.224273681640625 -0.3446105957031174 +1.452625 -0.34600830078125 -0.22674560546875 -0.3446105957031174 +1.45275 -0.34600830078125 -0.22674560546875 -0.3446105957031174 +1.4528750000000002 -0.349761962890625 -0.229217529296875 -0.3446105957031174 +1.453 -0.353485107421875 -0.231658935546875 -0.3446105957031174 +1.453125 -0.353485107421875 -0.231658935546875 -0.3446105957031174 +1.45325 -0.357177734375 -0.23406982421875 -0.3446105957031174 +1.453375 -0.357177734375 -0.23406982421875 -0.3446105957031174 +1.4535 -0.360809326171875 -0.2364501953125 -0.3446105957031174 +1.453625 -0.36444091796875 -0.23883056640625 -0.3446105957031174 +1.45375 -0.36444091796875 -0.23883056640625 -0.3446105957031174 +1.453875 -0.36798095703125 -0.24114990234375 -0.3446105957031174 +1.454 -0.36798095703125 -0.24114990234375 -0.3446105957031174 +1.4541250000000002 -0.37152099609375 -0.24346923828125 -0.3446105957031174 +1.45425 -0.375 -0.245758056640625 -0.3446105957031174 +1.454375 -0.375 -0.245758056640625 -0.3446105957031174 +1.4545000000000002 -0.378448486328125 -0.248016357421875 -0.3446105957031174 +1.454625 -0.378448486328125 -0.248016357421875 -0.3446105957031174 +1.45475 -0.3818359375 -0.250244140625 -0.3446105957031174 +1.4548750000000002 -0.38519287109375 -0.25244140625 -0.3446105957031174 +1.455 -0.38519287109375 -0.25244140625 -0.3446105957031174 +1.455125 -0.388519287109375 -0.254608154296875 -0.3446105957031174 +1.45525 -0.388519287109375 -0.254608154296875 -0.3446105957031174 +1.455375 -0.39178466796875 -0.256744384765625 -0.3446105957031174 +1.4555 -0.39501953125 -0.258880615234375 -0.3446105957031174 +1.455625 -0.39501953125 -0.258880615234375 -0.3446105957031174 +1.45575 -0.398193359375 -0.260955810546875 -0.3446105957031174 +1.455875 -0.398193359375 -0.260955810546875 -0.3446105957031174 +1.456 -0.401336669921875 -0.26300048828125 -0.3446105957031174 +1.4561250000000002 -0.404449462890625 -0.265045166015625 -0.3446105957031174 +1.45625 -0.404449462890625 -0.265045166015625 -0.3446105957031174 +1.456375 -0.407501220703125 -0.267059326171875 -0.3446105957031174 +1.4565000000000002 -0.407501220703125 -0.267059326171875 -0.3446105957031174 +1.456625 -0.4105224609375 -0.269012451171875 -0.3446105957031174 +1.45675 -0.413482666015625 -0.270965576171875 -0.3446105957031174 +1.456875 -0.413482666015625 -0.270965576171875 -0.3446105957031174 +1.457 -0.416412353515625 -0.27288818359375 -0.3446105957031174 +1.457125 -0.416412353515625 -0.27288818359375 -0.3446105957031174 +1.45725 -0.419281005859375 -0.274749755859375 -0.3446105957031174 +1.457375 -0.422119140625 -0.276611328125 -0.3446105957031174 +1.4575 -0.422119140625 -0.276611328125 -0.3446105957031174 +1.457625 -0.424896240234375 -0.2784423828125 -0.3446105957031174 +1.45775 -0.424896240234375 -0.2784423828125 -0.3446105957031174 +1.457875 -0.4276123046875 -0.280242919921875 -0.3446105957031174 +1.458 -0.4302978515625 -0.281982421875 -0.3446105957031174 +1.4581250000000002 -0.4302978515625 -0.281982421875 -0.3446105957031174 +1.45825 -0.432952880859375 -0.283721923828125 -0.3446105957031174 +1.458375 -0.432952880859375 -0.283721923828125 -0.3446105957031174 +1.4585000000000002 -0.435546875 -0.285430908203125 -0.3446105957031174 +1.458625 -0.438079833984375 -0.287078857421875 -0.3446105957031174 +1.45875 -0.438079833984375 -0.287078857421875 -0.3446105957031174 +1.458875 -0.440582275390625 -0.288726806640625 -0.3446105957031174 +1.459 -0.440582275390625 -0.288726806640625 -0.3446105957031174 +1.459125 -0.44305419921875 -0.29034423828125 -0.3446105957031174 +1.45925 -0.4454345703125 -0.291900634765625 -0.3446105957031174 +1.459375 -0.4454345703125 -0.291900634765625 -0.3446105957031174 +1.4595 -0.447784423828125 -0.29345703125 -0.3446105957031174 +1.459625 -0.447784423828125 -0.29345703125 -0.3446105957031174 +1.45975 -0.450103759765625 -0.294952392578125 -0.3446105957031174 +1.459875 -0.452362060546875 -0.29644775390625 -0.3446105957031174 +1.46 -0.452362060546875 -0.29644775390625 -0.3446105957031174 +1.4601250000000002 -0.454559326171875 -0.297882080078125 -0.3446105957031174 +1.46025 -0.454559326171875 -0.297882080078125 -0.3446105957031174 +1.460375 -0.45672607421875 -0.299285888671875 -0.3446105957031174 +1.4605000000000002 -0.458831787109375 -0.300689697265625 -0.3446105957031174 +1.460625 -0.458831787109375 -0.300689697265625 -0.3446105957031174 +1.46075 -0.46087646484375 -0.302032470703125 -0.3446105957031174 +1.460875 -0.46087646484375 -0.302032470703125 -0.3446105957031174 +1.461 -0.462890625 -0.3033447265625 -0.3446105957031174 +1.461125 -0.464813232421875 -0.304595947265625 -0.3446105957031174 +1.46125 -0.464813232421875 -0.304595947265625 -0.3446105957031174 +1.461375 -0.46673583984375 -0.30584716796875 -0.3446105957031174 +1.4615 -0.46673583984375 -0.30584716796875 -0.3446105957031174 +1.461625 -0.46856689453125 -0.30706787109375 -0.3446105957031174 +1.46175 -0.470367431640625 -0.308258056640625 -0.3446105957031174 +1.461875 -0.470367431640625 -0.308258056640625 -0.3446105957031174 +1.462 -0.472137451171875 -0.30938720703125 -0.3446105957031174 +1.4621250000000002 -0.472137451171875 -0.30938720703125 -0.3446105957031174 +1.46225 -0.47381591796875 -0.310516357421875 -0.3446105957031174 +1.462375 -0.4754638671875 -0.31158447265625 -0.3446105957031174 +1.4625000000000002 -0.4754638671875 -0.31158447265625 -0.3446105957031174 +1.462625 -0.47705078125 -0.3126220703125 -0.3446105957031174 +1.46275 -0.47705078125 -0.3126220703125 -0.3446105957031174 +1.462875 -0.478607177734375 -0.313629150390625 -0.3446105957031174 +1.463 -0.480072021484375 -0.314605712890625 -0.3446105957031174 +1.463125 -0.480072021484375 -0.314605712890625 -0.3446105957031174 +1.46325 -0.48150634765625 -0.3155517578125 -0.3446105957031174 +1.463375 -0.48150634765625 -0.3155517578125 -0.3446105957031174 +1.4635 -0.48291015625 -0.31646728515625 -0.3446105957031174 +1.463625 -0.484222412109375 -0.31732177734375 -0.3446105957031174 +1.46375 -0.484222412109375 -0.31732177734375 -0.3446105957031174 +1.463875 -0.485504150390625 -0.31817626953125 -0.3446105957031174 +1.464 -0.485504150390625 -0.31817626953125 -0.3446105957031174 +1.4641250000000002 -0.486724853515625 -0.3189697265625 -0.3446105957031174 +1.46425 -0.487884521484375 -0.319732666015625 -0.3446105957031174 +1.464375 -0.487884521484375 -0.319732666015625 -0.3446105957031174 +1.4645000000000002 -0.489013671875 -0.320465087890625 -0.3446105957031174 +1.464625 -0.489013671875 -0.320465087890625 -0.3446105957031174 +1.46475 -0.490081787109375 -0.3211669921875 -0.3446105957031174 +1.464875 -0.4910888671875 -0.321807861328125 -0.3446105957031174 +1.465 -0.4910888671875 -0.321807861328125 -0.3446105957031174 +1.465125 -0.492034912109375 -0.32244873046875 -0.3446105957031174 +1.46525 -0.492034912109375 -0.32244873046875 -0.3446105957031174 +1.465375 -0.492950439453125 -0.323028564453125 -0.3446105957031174 +1.4655 -0.4937744140625 -0.323577880859375 -0.3446105957031174 +1.465625 -0.4937744140625 -0.323577880859375 -0.3446105957031174 +1.46575 -0.49456787109375 -0.3240966796875 -0.3446105957031174 +1.465875 -0.49456787109375 -0.3240966796875 -0.3446105957031174 +1.466 -0.49530029296875 -0.3245849609375 -0.3446105957031174 +1.4661250000000002 -0.496002197265625 -0.325042724609375 -0.3446105957031174 +1.46625 -0.496002197265625 -0.325042724609375 -0.3446105957031174 +1.466375 -0.496612548828125 -0.325439453125 -0.3446105957031174 +1.4665000000000002 -0.496612548828125 -0.325439453125 -0.3446105957031174 +1.466625 -0.4971923828125 -0.325836181640625 -0.3446105957031174 +1.46675 -0.497711181640625 -0.326171875 -0.3446105957031174 +1.466875 -0.497711181640625 -0.326171875 -0.3446105957031174 +1.467 -0.498199462890625 -0.32647705078125 -0.3446105957031174 +1.467125 -0.498199462890625 -0.32647705078125 -0.3446105957031174 +1.46725 -0.49859619140625 -0.326751708984375 -0.3446105957031174 +1.467375 -0.49896240234375 -0.32696533203125 -0.3446105957031174 +1.4675 -0.49896240234375 -0.32696533203125 -0.3446105957031174 +1.467625 -0.499267578125 -0.327178955078125 -0.3446105957031174 +1.46775 -0.499267578125 -0.327178955078125 -0.3446105957031174 +1.467875 -0.49951171875 -0.32733154296875 -0.3446105957031174 +1.468 -0.49969482421875 -0.32745361328125 -0.3446105957031174 +1.4681250000000002 -0.49969482421875 -0.32745361328125 -0.3446105957031174 +1.46825 -0.49981689453125 -0.327545166015625 -0.3446105957031174 +1.468375 -0.49981689453125 -0.327545166015625 -0.3446105957031174 +1.4685000000000002 -0.499908447265625 -0.327606201171875 -0.3446105957031174 +1.468625 -0.49993896484375 -0.32763671875 -0.3446105957031174 +1.46875 -0.49993896484375 -0.32763671875 -0.3446105957031174 +1.468875 -0.499908447265625 -0.327606201171875 -0.3446105957031174 +1.469 -0.499908447265625 -0.327606201171875 -0.3446105957031174 +1.469125 -0.49981689453125 -0.327545166015625 -0.3446105957031174 +1.46925 -0.49969482421875 -0.32745361328125 -0.3446105957031174 +1.469375 -0.49969482421875 -0.32745361328125 -0.3446105957031174 +1.4695 -0.49951171875 -0.32733154296875 -0.3446105957031174 +1.469625 -0.49951171875 -0.32733154296875 -0.3446105957031174 +1.4697500000000002 -0.499267578125 -0.327178955078125 -0.3446105957031174 +1.469875 -0.49896240234375 -0.32696533203125 -0.3446105957031174 +1.47 -0.49896240234375 -0.32696533203125 -0.3446105957031174 +1.4701250000000002 -0.49859619140625 -0.326751708984375 -0.3446105957031174 +1.47025 -0.49859619140625 -0.326751708984375 -0.3446105957031174 +1.470375 -0.498199462890625 -0.32647705078125 -0.3446105957031174 +1.4705000000000002 -0.497711181640625 -0.326171875 -0.3446105957031174 +1.470625 -0.497711181640625 -0.326171875 -0.3446105957031174 +1.47075 -0.4971923828125 -0.325836181640625 -0.3446105957031174 +1.470875 -0.4971923828125 -0.325836181640625 -0.3446105957031174 +1.471 -0.496612548828125 -0.325439453125 -0.3446105957031174 +1.471125 -0.496002197265625 -0.325042724609375 -0.3446105957031174 +1.47125 -0.496002197265625 -0.325042724609375 -0.3446105957031174 +1.471375 -0.49530029296875 -0.3245849609375 -0.3446105957031174 +1.4715 -0.49530029296875 -0.3245849609375 -0.3446105957031174 +1.471625 -0.49456787109375 -0.3240966796875 -0.3446105957031174 +1.4717500000000002 -0.4937744140625 -0.323577880859375 -0.3446105957031174 +1.471875 -0.4937744140625 -0.323577880859375 -0.3446105957031174 +1.472 -0.468170166015625 -0.492950439453125 0.050219726562508388 +1.4721250000000002 -0.468170166015625 -0.492950439453125 0.050219726562508388 +1.47225 -0.467315673828125 -0.492034912109375 0.050219726562508388 +1.472375 -0.466400146484375 -0.4910888671875 0.050219726562508388 +1.4725 -0.466400146484375 -0.4910888671875 0.050219726562508388 +1.472625 -0.465423583984375 -0.490081787109375 0.050219726562508388 +1.47275 -0.465423583984375 -0.490081787109375 0.050219726562508388 +1.472875 -0.46441650390625 -0.489013671875 0.050219726562508388 +1.473 -0.463348388671875 -0.487884521484375 0.050219726562508388 +1.473125 -0.463348388671875 -0.487884521484375 0.050219726562508388 +1.47325 -0.462249755859375 -0.486724853515625 0.050219726562508388 +1.473375 -0.462249755859375 -0.486724853515625 0.050219726562508388 +1.4735 -0.461090087890625 -0.485504150390625 0.050219726562508388 +1.473625 -0.459869384765625 -0.484222412109375 0.050219726562508388 +1.4737500000000002 -0.459869384765625 -0.484222412109375 0.050219726562508388 +1.473875 -0.4586181640625 -0.48291015625 0.050219726562508388 +1.474 -0.4586181640625 -0.48291015625 0.050219726562508388 +1.4741250000000002 -0.457305908203125 -0.48150634765625 0.050219726562508388 +1.47425 -0.4559326171875 -0.480072021484375 0.050219726562508388 +1.474375 -0.4559326171875 -0.480072021484375 0.050219726562508388 +1.4745 -0.45452880859375 -0.478607177734375 0.050219726562508388 +1.474625 -0.45452880859375 -0.478607177734375 0.050219726562508388 +1.47475 -0.45306396484375 -0.47705078125 0.050219726562508388 +1.474875 -0.451568603515625 -0.4754638671875 0.050219726562508388 +1.475 -0.451568603515625 -0.4754638671875 0.050219726562508388 +1.475125 -0.45001220703125 -0.47381591796875 0.050219726562508388 +1.47525 -0.45001220703125 -0.47381591796875 0.050219726562508388 +1.475375 -0.448394775390625 -0.472137451171875 0.050219726562508388 +1.4755 -0.44671630859375 -0.470367431640625 0.050219726562508388 +1.475625 -0.44671630859375 -0.470367431640625 0.050219726562508388 +1.4757500000000002 -0.44500732421875 -0.46856689453125 0.050219726562508388 +1.475875 -0.44500732421875 -0.46856689453125 0.050219726562508388 +1.476 -0.443267822265625 -0.46673583984375 0.050219726562508388 +1.4761250000000002 -0.441436767578125 -0.464813232421875 0.050219726562508388 +1.47625 -0.441436767578125 -0.464813232421875 0.050219726562508388 +1.476375 -0.439605712890625 -0.462890625 0.050219726562508388 +1.4765 -0.439605712890625 -0.462890625 0.050219726562508388 +1.476625 -0.43768310546875 -0.46087646484375 0.050219726562508388 +1.47675 -0.435760498046875 -0.458831787109375 0.050219726562508388 +1.476875 -0.435760498046875 -0.458831787109375 0.050219726562508388 +1.477 -0.433746337890625 -0.45672607421875 0.050219726562508388 +1.477125 -0.433746337890625 -0.45672607421875 0.050219726562508388 +1.47725 -0.43170166015625 -0.454559326171875 0.050219726562508388 +1.477375 -0.42962646484375 -0.452362060546875 0.050219726562508388 +1.4775 -0.42962646484375 -0.452362060546875 0.050219726562508388 +1.477625 -0.427459716796875 -0.450103759765625 0.050219726562508388 +1.4777500000000002 -0.427459716796875 -0.450103759765625 0.050219726562508388 +1.477875 -0.42529296875 -0.447784423828125 0.050219726562508388 +1.478 -0.42303466796875 -0.4454345703125 0.050219726562508388 +1.4781250000000002 -0.42303466796875 -0.4454345703125 0.050219726562508388 +1.47825 -0.4207763671875 -0.44305419921875 0.050219726562508388 +1.478375 -0.4207763671875 -0.44305419921875 0.050219726562508388 +1.4785 -0.418426513671875 -0.440582275390625 0.050219726562508388 +1.478625 -0.41607666015625 -0.438079833984375 0.050219726562508388 +1.47875 -0.41607666015625 -0.438079833984375 0.050219726562508388 +1.478875 -0.413665771484375 -0.435546875 0.050219726562508388 +1.479 -0.413665771484375 -0.435546875 0.050219726562508388 +1.479125 -0.41119384765625 -0.432952880859375 0.050219726562508388 +1.47925 -0.408660888671875 -0.4302978515625 0.050219726562508388 +1.479375 -0.408660888671875 -0.4302978515625 0.050219726562508388 +1.4795 -0.4061279296875 -0.4276123046875 0.050219726562508388 +1.479625 -0.4061279296875 -0.4276123046875 0.050219726562508388 +1.4797500000000002 -0.403533935546875 -0.424896240234375 0.050219726562508388 +1.479875 -0.40087890625 -0.422119140625 0.050219726562508388 +1.48 -0.40087890625 -0.422119140625 0.050219726562508388 +1.4801250000000002 -0.398193359375 -0.419281005859375 0.050219726562508388 +1.48025 -0.398193359375 -0.419281005859375 0.050219726562508388 +1.480375 -0.395477294921875 -0.416412353515625 0.050219726562508388 +1.4805 -0.3927001953125 -0.413482666015625 0.050219726562508388 +1.480625 -0.3927001953125 -0.413482666015625 0.050219726562508388 +1.48075 -0.389862060546875 -0.4105224609375 0.050219726562508388 +1.480875 -0.389862060546875 -0.4105224609375 0.050219726562508388 +1.481 -0.38702392578125 -0.407501220703125 0.050219726562508388 +1.481125 -0.384124755859375 -0.404449462890625 0.050219726562508388 +1.48125 -0.384124755859375 -0.404449462890625 0.050219726562508388 +1.481375 -0.38116455078125 -0.401336669921875 0.050219726562508388 +1.4815 -0.38116455078125 -0.401336669921875 0.050219726562508388 +1.481625 -0.378173828125 -0.398193359375 0.050219726562508388 +1.4817500000000002 -0.37518310546875 -0.39501953125 0.050219726562508388 +1.481875 -0.37518310546875 -0.39501953125 0.050219726562508388 +1.482 -0.372100830078125 -0.39178466796875 0.050219726562508388 +1.4821250000000002 -0.372100830078125 -0.39178466796875 0.050219726562508388 +1.48225 -0.368988037109375 -0.388519287109375 0.050219726562508388 +1.482375 -0.3658447265625 -0.38519287109375 0.050219726562508388 +1.4825 -0.3658447265625 -0.38519287109375 0.050219726562508388 +1.482625 -0.362640380859375 -0.3818359375 0.050219726562508388 +1.48275 -0.362640380859375 -0.3818359375 0.050219726562508388 +1.482875 -0.359405517578125 -0.378448486328125 0.050219726562508388 +1.483 -0.35614013671875 -0.375 0.050219726562508388 +1.483125 -0.35614013671875 -0.375 0.050219726562508388 +1.48325 -0.35284423828125 -0.37152099609375 0.050219726562508388 +1.483375 -0.35284423828125 -0.37152099609375 0.050219726562508388 +1.4835 -0.3494873046875 -0.36798095703125 0.050219726562508388 +1.483625 -0.346099853515625 -0.36444091796875 0.050219726562508388 +1.4837500000000002 -0.346099853515625 -0.36444091796875 0.050219726562508388 +1.483875 -0.342681884765625 -0.360809326171875 0.050219726562508388 +1.484 -0.342681884765625 -0.360809326171875 0.050219726562508388 +1.4841250000000002 -0.3392333984375 -0.357177734375 0.050219726562508388 +1.48425 -0.335723876953125 -0.353485107421875 0.050219726562508388 +1.484375 -0.335723876953125 -0.353485107421875 0.050219726562508388 +1.4845 -0.332183837890625 -0.349761962890625 0.050219726562508388 +1.484625 -0.332183837890625 -0.349761962890625 0.050219726562508388 +1.48475 -0.32861328125 -0.34600830078125 0.050219726562508388 +1.484875 -0.32501220703125 -0.34222412109375 0.050219726562508388 +1.485 -0.32501220703125 -0.34222412109375 0.050219726562508388 +1.485125 -0.321380615234375 -0.33837890625 0.050219726562508388 +1.48525 -0.321380615234375 -0.33837890625 0.050219726562508388 +1.4853750000000002 -0.31768798828125 -0.334503173828125 0.050219726562508388 +1.4855 -0.313995361328125 -0.330596923828125 0.050219726562508388 +1.485625 -0.313995361328125 -0.330596923828125 0.050219726562508388 +1.4857500000000002 -0.31024169921875 -0.32666015625 0.050219726562508388 +1.485875 -0.31024169921875 -0.32666015625 0.050219726562508388 +1.486 -0.30645751953125 -0.322662353515625 0.050219726562508388 +1.4861250000000002 -0.302642822265625 -0.31866455078125 0.050219726562508388 +1.48625 -0.302642822265625 -0.31866455078125 0.050219726562508388 +1.486375 -0.298797607421875 -0.314605712890625 0.050219726562508388 +1.4865 -0.298797607421875 -0.314605712890625 0.050219726562508388 +1.486625 -0.294921875 -0.310516357421875 0.050219726562508388 +1.48675 -0.291015625 -0.306396484375 0.050219726562508388 +1.486875 -0.291015625 -0.306396484375 0.050219726562508388 +1.487 -0.28704833984375 -0.30224609375 0.050219726562508388 +1.487125 -0.28704833984375 -0.30224609375 0.050219726562508388 +1.48725 -0.2830810546875 -0.298065185546875 0.050219726562508388 +1.4873750000000002 -0.279052734375 -0.2938232421875 0.050219726562508388 +1.4875 -0.279052734375 -0.2938232421875 0.050219726562508388 +1.487625 -0.2750244140625 -0.289581298828125 0.050219726562508388 +1.4877500000000002 -0.2750244140625 -0.289581298828125 0.050219726562508388 +1.487875 -0.270965576171875 -0.285308837890625 0.050219726562508388 +1.488 -0.266876220703125 -0.280975341796875 0.050219726562508388 +1.488125 -0.266876220703125 -0.280975341796875 0.050219726562508388 +1.48825 -0.262725830078125 -0.276641845703125 0.050219726562508388 +1.488375 -0.262725830078125 -0.276641845703125 0.050219726562508388 +1.4885 -0.258575439453125 -0.27227783203125 0.050219726562508388 +1.488625 -0.25439453125 -0.267852783203125 0.050219726562508388 +1.48875 -0.25439453125 -0.267852783203125 0.050219726562508388 +1.488875 -0.25018310546875 -0.263427734375 0.050219726562508388 +1.489 -0.25018310546875 -0.263427734375 0.050219726562508388 +1.489125 -0.245941162109375 -0.25897216796875 0.050219726562508388 +1.48925 -0.241668701171875 -0.25445556640625 0.050219726562508388 +1.4893750000000002 -0.241668701171875 -0.25445556640625 0.050219726562508388 +1.4895 -0.237396240234375 -0.249969482421875 0.050219726562508388 +1.489625 -0.237396240234375 -0.249969482421875 0.050219726562508388 +1.4897500000000002 -0.233062744140625 -0.24542236328125 0.050219726562508388 +1.489875 -0.228729248046875 -0.2408447265625 0.050219726562508388 +1.49 -0.228729248046875 -0.2408447265625 0.050219726562508388 +1.490125 -0.224365234375 -0.236236572265625 0.050219726562508388 +1.49025 -0.224365234375 -0.236236572265625 0.050219726562508388 +1.490375 -0.219970703125 -0.231597900390625 0.050219726562508388 +1.4905 -0.215545654296875 -0.226959228515625 0.050219726562508388 +1.490625 -0.215545654296875 -0.226959228515625 0.050219726562508388 +1.49075 -0.211090087890625 -0.2222900390625 0.050219726562508388 +1.490875 -0.211090087890625 -0.2222900390625 0.050219726562508388 +1.491 -0.206634521484375 -0.21759033203125 0.050219726562508388 +1.491125 -0.2021484375 -0.212860107421875 0.050219726562508388 +1.49125 -0.2021484375 -0.212860107421875 0.050219726562508388 +1.4913750000000002 -0.1976318359375 -0.208099365234375 0.050219726562508388 +1.4915 -0.1976318359375 -0.208099365234375 0.050219726562508388 +1.491625 -0.193115234375 -0.203338623046875 0.050219726562508388 +1.4917500000000002 -0.188568115234375 -0.19854736328125 0.050219726562508388 +1.491875 -0.188568115234375 -0.19854736328125 0.050219726562508388 +1.492 -0.183990478515625 -0.1937255859375 0.050219726562508388 +1.492125 -0.183990478515625 -0.1937255859375 0.050219726562508388 +1.49225 -0.17938232421875 -0.188873291015625 0.050219726562508388 +1.492375 -0.174774169921875 -0.18402099609375 0.050219726562508388 +1.4925 -0.174774169921875 -0.18402099609375 0.050219726562508388 +1.492625 -0.170135498046875 -0.17913818359375 0.050219726562508388 +1.49275 -0.170135498046875 -0.17913818359375 0.050219726562508388 +1.492875 -0.165496826171875 -0.17425537109375 0.050219726562508388 +1.493 -0.16082763671875 -0.169342041015625 0.050219726562508388 +1.493125 -0.16082763671875 -0.169342041015625 0.050219726562508388 +1.49325 -0.1561279296875 -0.164398193359375 0.050219726562508388 +1.4933750000000002 -0.1561279296875 -0.164398193359375 0.050219726562508388 +1.4935 -0.15142822265625 -0.159454345703125 0.050219726562508388 +1.493625 -0.146697998046875 -0.15447998046875 0.050219726562508388 +1.4937500000000002 -0.146697998046875 -0.15447998046875 0.050219726562508388 +1.493875 -0.1419677734375 -0.14947509765625 0.050219726562508388 +1.494 -0.1419677734375 -0.14947509765625 0.050219726562508388 +1.494125 -0.13720703125 -0.14447021484375 0.050219726562508388 +1.49425 -0.1324462890625 -0.13946533203125 0.050219726562508388 +1.494375 -0.1324462890625 -0.13946533203125 0.050219726562508388 +1.4945 -0.127655029296875 -0.134429931640625 0.050219726562508388 +1.494625 -0.127655029296875 -0.134429931640625 0.050219726562508388 +1.49475 -0.12286376953125 -0.129364013671875 0.050219726562508388 +1.494875 -0.1180419921875 -0.124298095703125 0.050219726562508388 +1.495 -0.1180419921875 -0.124298095703125 0.050219726562508388 +1.495125 -0.113250732421875 -0.119232177734375 0.050219726562508388 +1.49525 -0.113250732421875 -0.119232177734375 0.050219726562508388 +1.4953750000000002 -0.1083984375 -0.1141357421875 0.050219726562508388 +1.4955 -0.103546142578125 -0.109039306640625 0.050219726562508388 +1.495625 -0.103546142578125 -0.109039306640625 0.050219726562508388 +1.4957500000000002 -0.09869384765625 -0.103912353515625 0.050219726562508388 +1.495875 -0.09869384765625 -0.103912353515625 0.050219726562508388 +1.496 -0.093841552734375 -0.098785400390625 0.050219726562508388 +1.496125 -0.088958740234375 -0.093658447265625 0.050219726562508388 +1.49625 -0.088958740234375 -0.093658447265625 0.050219726562508388 +1.496375 -0.084075927734375 -0.0885009765625 0.050219726562508388 +1.4965 -0.084075927734375 -0.0885009765625 0.050219726562508388 +1.496625 -0.07916259765625 -0.083343505859375 0.050219726562508388 +1.49675 -0.074249267578125 -0.07818603515625 0.050219726562508388 +1.496875 -0.074249267578125 -0.07818603515625 0.050219726562508388 +1.497 -0.0693359375 -0.072998046875 0.050219726562508388 +1.497125 -0.0693359375 -0.072998046875 0.050219726562508388 +1.49725 -0.064422607421875 -0.06781005859375 0.050219726562508388 +1.4973750000000002 -0.059478759765625 -0.0626220703125 0.050219726562508388 +1.4975 -0.059478759765625 -0.0626220703125 0.050219726562508388 +1.497625 -0.0545654296875 -0.05743408203125 0.050219726562508388 +1.4977500000000002 -0.0545654296875 -0.05743408203125 0.050219726562508388 +1.497875 -0.04962158203125 -0.05224609375 0.050219726562508388 +1.498 -0.044647216796875 -0.047027587890625 0.050219726562508388 +1.498125 -0.044647216796875 -0.047027587890625 0.050219726562508388 +1.49825 -0.039703369140625 -0.04180908203125 0.050219726562508388 +1.498375 -0.039703369140625 -0.04180908203125 0.050219726562508388 +1.4985 -0.034759521484375 -0.036590576171875 0.050219726562508388 +1.498625 -0.02978515625 -0.0313720703125 0.050219726562508388 +1.49875 -0.02978515625 -0.0313720703125 0.050219726562508388 +1.498875 -0.024810791015625 -0.026123046875 0.050219726562508388 +1.499 -0.024810791015625 -0.026123046875 0.050219726562508388 +1.499125 -0.019866943359375 -0.020904541015625 0.050219726562508388 +1.49925 -0.014892578125 -0.01568603515625 0.050219726562508388 +1.4993750000000002 -0.014892578125 -0.01568603515625 0.050219726562508388 +1.4995 -0.009918212890625 -0.01043701171875 0.050219726562508388 +1.499625 -0.009918212890625 -0.01043701171875 0.050219726562508388 +1.4997500000000002 -0.00494384765625 -0.005218505859375 0.050219726562508388 +1.499875 0.0 0.0 0.050219726562508388 +1.5 0.0 0.0 0.050219726562508388 +1.500125 0.00494384765625 0.005218505859375 0.050219726562508388 +1.50025 0.00494384765625 0.005218505859375 0.050219726562508388 +1.500375 0.009918212890625 0.01043701171875 0.050219726562508388 +1.5005 0.014892578125 0.01568603515625 0.050219726562508388 +1.500625 0.014892578125 0.01568603515625 0.050219726562508388 +1.50075 0.019866943359375 0.020904541015625 0.050219726562508388 +1.500875 0.019866943359375 0.020904541015625 0.050219726562508388 +1.5010000000000002 0.024810791015625 0.026123046875 0.050219726562508388 +1.501125 0.02978515625 0.0313720703125 0.050219726562508388 +1.50125 0.02978515625 0.0313720703125 0.050219726562508388 +1.5013750000000002 0.034759521484375 0.036590576171875 0.050219726562508388 +1.5015 0.034759521484375 0.036590576171875 0.050219726562508388 +1.501625 0.039703369140625 0.04180908203125 0.050219726562508388 +1.5017500000000002 0.044647216796875 0.047027587890625 0.050219726562508388 +1.501875 0.044647216796875 0.047027587890625 0.050219726562508388 +1.502 0.04962158203125 0.05224609375 0.050219726562508388 +1.502125 0.04962158203125 0.05224609375 0.050219726562508388 +1.50225 0.0545654296875 0.05743408203125 0.050219726562508388 +1.502375 0.059478759765625 0.0626220703125 0.050219726562508388 +1.5025 0.059478759765625 0.0626220703125 0.050219726562508388 +1.502625 0.064422607421875 0.06781005859375 0.050219726562508388 +1.50275 0.064422607421875 0.06781005859375 0.050219726562508388 +1.502875 0.0693359375 0.072998046875 0.050219726562508388 +1.5030000000000002 0.074249267578125 0.07818603515625 0.050219726562508388 +1.503125 0.074249267578125 0.07818603515625 0.050219726562508388 +1.50325 0.07916259765625 0.083343505859375 0.050219726562508388 +1.5033750000000002 0.07916259765625 0.083343505859375 0.050219726562508388 +1.5035 0.084075927734375 0.0885009765625 0.050219726562508388 +1.503625 0.088958740234375 0.093658447265625 0.050219726562508388 +1.5037500000000002 0.088958740234375 0.093658447265625 0.050219726562508388 +1.503875 0.093841552734375 0.098785400390625 0.050219726562508388 +1.504 0.05560302734375 0.098785400390625 0.43709106445313256 +1.504125 0.0584716796875 0.103912353515625 0.43709106445313256 +1.50425 0.061370849609375 0.109039306640625 0.43709106445313256 +1.504375 0.061370849609375 0.109039306640625 0.43709106445313256 +1.5045 0.064239501953125 0.1141357421875 0.43709106445313256 +1.504625 0.064239501953125 0.1141357421875 0.43709106445313256 +1.50475 0.067108154296875 0.119232177734375 0.43709106445313256 +1.504875 0.0699462890625 0.124298095703125 0.43709106445313256 +1.5050000000000002 0.0699462890625 0.124298095703125 0.43709106445313256 +1.505125 0.07281494140625 0.129364013671875 0.43709106445313256 +1.50525 0.07281494140625 0.129364013671875 0.43709106445313256 +1.5053750000000002 0.075653076171875 0.134429931640625 0.43709106445313256 +1.5055 0.0784912109375 0.13946533203125 0.43709106445313256 +1.505625 0.0784912109375 0.13946533203125 0.43709106445313256 +1.50575 0.081298828125 0.14447021484375 0.43709106445313256 +1.505875 0.081298828125 0.14447021484375 0.43709106445313256 +1.506 0.084136962890625 0.14947509765625 0.43709106445313256 +1.506125 0.086944580078125 0.15447998046875 0.43709106445313256 +1.50625 0.086944580078125 0.15447998046875 0.43709106445313256 +1.506375 0.0897216796875 0.159454345703125 0.43709106445313256 +1.5065 0.0897216796875 0.159454345703125 0.43709106445313256 +1.506625 0.092529296875 0.164398193359375 0.43709106445313256 +1.50675 0.095306396484375 0.169342041015625 0.43709106445313256 +1.506875 0.095306396484375 0.169342041015625 0.43709106445313256 +1.5070000000000002 0.098052978515625 0.17425537109375 0.43709106445313256 +1.507125 0.098052978515625 0.17425537109375 0.43709106445313256 +1.50725 0.100830078125 0.17913818359375 0.43709106445313256 +1.5073750000000002 0.10357666015625 0.18402099609375 0.43709106445313256 +1.5075 0.10357666015625 0.18402099609375 0.43709106445313256 +1.507625 0.106292724609375 0.188873291015625 0.43709106445313256 +1.50775 0.106292724609375 0.188873291015625 0.43709106445313256 +1.507875 0.1090087890625 0.1937255859375 0.43709106445313256 +1.508 0.111724853515625 0.19854736328125 0.43709106445313256 +1.508125 0.111724853515625 0.19854736328125 0.43709106445313256 +1.50825 0.11444091796875 0.203338623046875 0.43709106445313256 +1.508375 0.11444091796875 0.203338623046875 0.43709106445313256 +1.5085 0.11712646484375 0.208099365234375 0.43709106445313256 +1.508625 0.119781494140625 0.212860107421875 0.43709106445313256 +1.50875 0.119781494140625 0.212860107421875 0.43709106445313256 +1.508875 0.122467041015625 0.21759033203125 0.43709106445313256 +1.5090000000000002 0.122467041015625 0.21759033203125 0.43709106445313256 +1.509125 0.125091552734375 0.2222900390625 0.43709106445313256 +1.50925 0.127716064453125 0.226959228515625 0.43709106445313256 +1.5093750000000002 0.127716064453125 0.226959228515625 0.43709106445313256 +1.5095 0.130340576171875 0.231597900390625 0.43709106445313256 +1.509625 0.130340576171875 0.231597900390625 0.43709106445313256 +1.50975 0.132965087890625 0.236236572265625 0.43709106445313256 +1.509875 0.135528564453125 0.2408447265625 0.43709106445313256 +1.51 0.135528564453125 0.2408447265625 0.43709106445313256 +1.510125 0.13812255859375 0.24542236328125 0.43709106445313256 +1.51025 0.13812255859375 0.24542236328125 0.43709106445313256 +1.510375 0.14068603515625 0.249969482421875 0.43709106445313256 +1.5105 0.143218994140625 0.25445556640625 0.43709106445313256 +1.510625 0.143218994140625 0.25445556640625 0.43709106445313256 +1.51075 0.145751953125 0.25897216796875 0.43709106445313256 +1.510875 0.145751953125 0.25897216796875 0.43709106445313256 +1.5110000000000002 0.14825439453125 0.263427734375 0.43709106445313256 +1.511125 0.1507568359375 0.267852783203125 0.43709106445313256 +1.51125 0.1507568359375 0.267852783203125 0.43709106445313256 +1.5113750000000002 0.153228759765625 0.27227783203125 0.43709106445313256 +1.5115 0.153228759765625 0.27227783203125 0.43709106445313256 +1.511625 0.15570068359375 0.276641845703125 0.43709106445313256 +1.51175 0.15814208984375 0.280975341796875 0.43709106445313256 +1.511875 0.15814208984375 0.280975341796875 0.43709106445313256 +1.512 0.16058349609375 0.285308837890625 0.43709106445313256 +1.512125 0.16058349609375 0.285308837890625 0.43709106445313256 +1.51225 0.162994384765625 0.289581298828125 0.43709106445313256 +1.512375 0.165374755859375 0.2938232421875 0.43709106445313256 +1.5125 0.165374755859375 0.2938232421875 0.43709106445313256 +1.512625 0.167755126953125 0.298065185546875 0.43709106445313256 +1.51275 0.167755126953125 0.298065185546875 0.43709106445313256 +1.512875 0.17010498046875 0.30224609375 0.43709106445313256 +1.5130000000000002 0.172454833984375 0.306396484375 0.43709106445313256 +1.513125 0.172454833984375 0.306396484375 0.43709106445313256 +1.51325 0.174774169921875 0.310516357421875 0.43709106445313256 +1.5133750000000002 0.174774169921875 0.310516357421875 0.43709106445313256 +1.5135 0.17706298828125 0.314605712890625 0.43709106445313256 +1.513625 0.179351806640625 0.31866455078125 0.43709106445313256 +1.51375 0.179351806640625 0.31866455078125 0.43709106445313256 +1.513875 0.181610107421875 0.322662353515625 0.43709106445313256 +1.514 0.181610107421875 0.322662353515625 0.43709106445313256 +1.514125 0.183837890625 0.32666015625 0.43709106445313256 +1.51425 0.186065673828125 0.330596923828125 0.43709106445313256 +1.514375 0.186065673828125 0.330596923828125 0.43709106445313256 +1.5145 0.188262939453125 0.334503173828125 0.43709106445313256 +1.514625 0.188262939453125 0.334503173828125 0.43709106445313256 +1.51475 0.190460205078125 0.33837890625 0.43709106445313256 +1.514875 0.192596435546875 0.34222412109375 0.43709106445313256 +1.5150000000000002 0.192596435546875 0.34222412109375 0.43709106445313256 +1.515125 0.194732666015625 0.34600830078125 0.43709106445313256 +1.51525 0.194732666015625 0.34600830078125 0.43709106445313256 +1.5153750000000002 0.196868896484375 0.349761962890625 0.43709106445313256 +1.5155 0.198944091796875 0.353485107421875 0.43709106445313256 +1.515625 0.198944091796875 0.353485107421875 0.43709106445313256 +1.51575 0.201019287109375 0.357177734375 0.43709106445313256 +1.515875 0.201019287109375 0.357177734375 0.43709106445313256 +1.516 0.20306396484375 0.360809326171875 0.43709106445313256 +1.516125 0.205108642578125 0.36444091796875 0.43709106445313256 +1.51625 0.205108642578125 0.36444091796875 0.43709106445313256 +1.516375 0.207122802734375 0.36798095703125 0.43709106445313256 +1.5165 0.207122802734375 0.36798095703125 0.43709106445313256 +1.5166250000000002 0.2091064453125 0.37152099609375 0.43709106445313256 +1.51675 0.2110595703125 0.375 0.43709106445313256 +1.516875 0.2110595703125 0.375 0.43709106445313256 +1.5170000000000002 0.212982177734375 0.378448486328125 0.43709106445313256 +1.517125 0.212982177734375 0.378448486328125 0.43709106445313256 +1.51725 0.21490478515625 0.3818359375 0.43709106445313256 +1.5173750000000002 0.216796875 0.38519287109375 0.43709106445313256 +1.5175 0.216796875 0.38519287109375 0.43709106445313256 +1.517625 0.218658447265625 0.388519287109375 0.43709106445313256 +1.51775 0.218658447265625 0.388519287109375 0.43709106445313256 +1.517875 0.22052001953125 0.39178466796875 0.43709106445313256 +1.518 0.222320556640625 0.39501953125 0.43709106445313256 +1.518125 0.222320556640625 0.39501953125 0.43709106445313256 +1.51825 0.22412109375 0.398193359375 0.43709106445313256 +1.518375 0.22412109375 0.398193359375 0.43709106445313256 +1.5185 0.22589111328125 0.401336669921875 0.43709106445313256 +1.5186250000000002 0.227630615234375 0.404449462890625 0.43709106445313256 +1.51875 0.227630615234375 0.404449462890625 0.43709106445313256 +1.518875 0.229339599609375 0.407501220703125 0.43709106445313256 +1.5190000000000002 0.229339599609375 0.407501220703125 0.43709106445313256 +1.519125 0.231048583984375 0.4105224609375 0.43709106445313256 +1.51925 0.23272705078125 0.413482666015625 0.43709106445313256 +1.5193750000000002 0.23272705078125 0.413482666015625 0.43709106445313256 +1.5195 0.234375 0.416412353515625 0.43709106445313256 +1.519625 0.234375 0.416412353515625 0.43709106445313256 +1.51975 0.2359619140625 0.419281005859375 0.43709106445313256 +1.519875 0.237579345703125 0.422119140625 0.43709106445313256 +1.52 0.237579345703125 0.422119140625 0.43709106445313256 +1.520125 0.2391357421875 0.424896240234375 0.43709106445313256 +1.52025 0.2391357421875 0.424896240234375 0.43709106445313256 +1.520375 0.24066162109375 0.4276123046875 0.43709106445313256 +1.5205 0.2421875 0.4302978515625 0.43709106445313256 +1.5206250000000002 0.2421875 0.4302978515625 0.43709106445313256 +1.52075 0.243682861328125 0.432952880859375 0.43709106445313256 +1.520875 0.243682861328125 0.432952880859375 0.43709106445313256 +1.5210000000000002 0.245147705078125 0.435546875 0.43709106445313256 +1.521125 0.246551513671875 0.438079833984375 0.43709106445313256 +1.52125 0.246551513671875 0.438079833984375 0.43709106445313256 +1.521375 0.24798583984375 0.440582275390625 0.43709106445313256 +1.5215 0.24798583984375 0.440582275390625 0.43709106445313256 +1.521625 0.249359130859375 0.44305419921875 0.43709106445313256 +1.52175 0.250701904296875 0.4454345703125 0.43709106445313256 +1.521875 0.250701904296875 0.4454345703125 0.43709106445313256 +1.522 0.25201416015625 0.447784423828125 0.43709106445313256 +1.522125 0.25201416015625 0.447784423828125 0.43709106445313256 +1.52225 0.253326416015625 0.450103759765625 0.43709106445313256 +1.522375 0.254608154296875 0.452362060546875 0.43709106445313256 +1.5225 0.254608154296875 0.452362060546875 0.43709106445313256 +1.5226250000000002 0.255828857421875 0.454559326171875 0.43709106445313256 +1.52275 0.255828857421875 0.454559326171875 0.43709106445313256 +1.522875 0.257049560546875 0.45672607421875 0.43709106445313256 +1.5230000000000002 0.25823974609375 0.458831787109375 0.43709106445313256 +1.523125 0.25823974609375 0.458831787109375 0.43709106445313256 +1.52325 0.2593994140625 0.46087646484375 0.43709106445313256 +1.523375 0.2593994140625 0.46087646484375 0.43709106445313256 +1.5235 0.260528564453125 0.462890625 0.43709106445313256 +1.523625 0.2615966796875 0.464813232421875 0.43709106445313256 +1.52375 0.2615966796875 0.464813232421875 0.43709106445313256 +1.523875 0.2626953125 0.46673583984375 0.43709106445313256 +1.524 0.2626953125 0.46673583984375 0.43709106445313256 +1.524125 0.26373291015625 0.46856689453125 0.43709106445313256 +1.52425 0.264739990234375 0.470367431640625 0.43709106445313256 +1.524375 0.264739990234375 0.470367431640625 0.43709106445313256 +1.5245 0.265716552734375 0.472137451171875 0.43709106445313256 +1.5246250000000002 0.265716552734375 0.472137451171875 0.43709106445313256 +1.52475 0.26666259765625 0.47381591796875 0.43709106445313256 +1.524875 0.267608642578125 0.4754638671875 0.43709106445313256 +1.5250000000000002 0.267608642578125 0.4754638671875 0.43709106445313256 +1.525125 0.26849365234375 0.47705078125 0.43709106445313256 +1.52525 0.26849365234375 0.47705078125 0.43709106445313256 +1.525375 0.269378662109375 0.478607177734375 0.43709106445313256 +1.5255 0.27020263671875 0.480072021484375 0.43709106445313256 +1.525625 0.27020263671875 0.480072021484375 0.43709106445313256 +1.52575 0.27099609375 0.48150634765625 0.43709106445313256 +1.525875 0.27099609375 0.48150634765625 0.43709106445313256 +1.526 0.27178955078125 0.48291015625 0.43709106445313256 +1.526125 0.27252197265625 0.484222412109375 0.43709106445313256 +1.52625 0.27252197265625 0.484222412109375 0.43709106445313256 +1.526375 0.27325439453125 0.485504150390625 0.43709106445313256 +1.5265 0.27325439453125 0.485504150390625 0.43709106445313256 +1.5266250000000002 0.273956298828125 0.486724853515625 0.43709106445313256 +1.52675 0.27459716796875 0.487884521484375 0.43709106445313256 +1.526875 0.27459716796875 0.487884521484375 0.43709106445313256 +1.5270000000000002 0.27520751953125 0.489013671875 0.43709106445313256 +1.527125 0.27520751953125 0.489013671875 0.43709106445313256 +1.52725 0.27581787109375 0.490081787109375 0.43709106445313256 +1.527375 0.276397705078125 0.4910888671875 0.43709106445313256 +1.5275 0.276397705078125 0.4910888671875 0.43709106445313256 +1.527625 0.27691650390625 0.492034912109375 0.43709106445313256 +1.52775 0.27691650390625 0.492034912109375 0.43709106445313256 +1.527875 0.277435302734375 0.492950439453125 0.43709106445313256 +1.528 0.277923583984375 0.4937744140625 0.43709106445313256 +1.528125 0.277923583984375 0.4937744140625 0.43709106445313256 +1.52825 0.278350830078125 0.49456787109375 0.43709106445313256 +1.528375 0.278350830078125 0.49456787109375 0.43709106445313256 +1.5285 0.278778076171875 0.49530029296875 0.43709106445313256 +1.5286250000000002 0.279144287109375 0.496002197265625 0.43709106445313256 +1.52875 0.279144287109375 0.496002197265625 0.43709106445313256 +1.528875 0.279510498046875 0.496612548828125 0.43709106445313256 +1.5290000000000002 0.279510498046875 0.496612548828125 0.43709106445313256 +1.529125 0.27984619140625 0.4971923828125 0.43709106445313256 +1.52925 0.280120849609375 0.497711181640625 0.43709106445313256 +1.529375 0.280120849609375 0.497711181640625 0.43709106445313256 +1.5295 0.2803955078125 0.498199462890625 0.43709106445313256 +1.529625 0.2803955078125 0.498199462890625 0.43709106445313256 +1.52975 0.280609130859375 0.49859619140625 0.43709106445313256 +1.529875 0.28082275390625 0.49896240234375 0.43709106445313256 +1.53 0.28082275390625 0.49896240234375 0.43709106445313256 +1.530125 0.281005859375 0.499267578125 0.43709106445313256 +1.53025 0.281005859375 0.499267578125 0.43709106445313256 +1.530375 0.2811279296875 0.49951171875 0.43709106445313256 +1.5305 0.281219482421875 0.49969482421875 0.43709106445313256 +1.5306250000000002 0.281219482421875 0.49969482421875 0.43709106445313256 +1.53075 0.28131103515625 0.49981689453125 0.43709106445313256 +1.530875 0.28131103515625 0.49981689453125 0.43709106445313256 +1.5310000000000002 0.2813720703125 0.499908447265625 0.43709106445313256 +1.531125 0.2813720703125 0.49993896484375 0.43709106445313256 +1.53125 0.2813720703125 0.49993896484375 0.43709106445313256 +1.531375 0.2813720703125 0.499908447265625 0.43709106445313256 +1.5315 0.2813720703125 0.499908447265625 0.43709106445313256 +1.531625 0.28131103515625 0.49981689453125 0.43709106445313256 +1.53175 0.281219482421875 0.49969482421875 0.43709106445313256 +1.531875 0.281219482421875 0.49969482421875 0.43709106445313256 +1.532 0.2811279296875 0.49951171875 0.43709106445313256 +1.532125 0.2811279296875 0.49951171875 0.43709106445313256 +1.5322500000000002 0.281005859375 0.499267578125 0.43709106445313256 +1.532375 0.28082275390625 0.49896240234375 0.43709106445313256 +1.5325 0.28082275390625 0.49896240234375 0.43709106445313256 +1.5326250000000002 0.280609130859375 0.49859619140625 0.43709106445313256 +1.53275 0.280609130859375 0.49859619140625 0.43709106445313256 +1.532875 0.2803955078125 0.498199462890625 0.43709106445313256 +1.5330000000000002 0.280120849609375 0.497711181640625 0.43709106445313256 +1.533125 0.280120849609375 0.497711181640625 0.43709106445313256 +1.53325 0.27984619140625 0.4971923828125 0.43709106445313256 +1.533375 0.27984619140625 0.4971923828125 0.43709106445313256 +1.5335 0.279510498046875 0.496612548828125 0.43709106445313256 +1.533625 0.279144287109375 0.496002197265625 0.43709106445313256 +1.53375 0.279144287109375 0.496002197265625 0.43709106445313256 +1.533875 0.278778076171875 0.49530029296875 0.43709106445313256 +1.534 0.278778076171875 0.49530029296875 0.43709106445313256 +1.534125 0.278350830078125 0.49456787109375 0.43709106445313256 +1.5342500000000002 0.277923583984375 0.4937744140625 0.43709106445313256 +1.534375 0.277923583984375 0.4937744140625 0.43709106445313256 +1.5345 0.277435302734375 0.492950439453125 0.43709106445313256 +1.5346250000000002 0.277435302734375 0.492950439453125 0.43709106445313256 +1.53475 0.27691650390625 0.492034912109375 0.43709106445313256 +1.534875 0.276397705078125 0.4910888671875 0.43709106445313256 +1.5350000000000002 0.276397705078125 0.4910888671875 0.43709106445313256 +1.535125 0.27581787109375 0.490081787109375 0.43709106445313256 +1.53525 0.27581787109375 0.490081787109375 0.43709106445313256 +1.535375 0.27520751953125 0.489013671875 0.43709106445313256 +1.5355 0.27459716796875 0.487884521484375 0.43709106445313256 +1.535625 0.27459716796875 0.487884521484375 0.43709106445313256 +1.53575 0.273956298828125 0.486724853515625 0.43709106445313256 +1.535875 0.273956298828125 0.486724853515625 0.43709106445313256 +1.536 0.119293212890625 0.485504150390625 0.7541992187500055 +1.536125 0.11895751953125 0.484222412109375 0.7541992187500055 +1.5362500000000002 0.11895751953125 0.484222412109375 0.7541992187500055 +1.536375 0.11865234375 0.48291015625 0.7541992187500055 +1.5365 0.11865234375 0.48291015625 0.7541992187500055 +1.5366250000000002 0.1182861328125 0.48150634765625 0.7541992187500055 +1.53675 0.117950439453125 0.480072021484375 0.7541992187500055 +1.536875 0.117950439453125 0.480072021484375 0.7541992187500055 +1.537 0.117584228515625 0.478607177734375 0.7541992187500055 +1.537125 0.117584228515625 0.478607177734375 0.7541992187500055 +1.53725 0.117218017578125 0.47705078125 0.7541992187500055 +1.537375 0.1168212890625 0.4754638671875 0.7541992187500055 +1.5375 0.1168212890625 0.4754638671875 0.7541992187500055 +1.537625 0.116424560546875 0.47381591796875 0.7541992187500055 +1.53775 0.116424560546875 0.47381591796875 0.7541992187500055 +1.537875 0.115997314453125 0.472137451171875 0.7541992187500055 +1.538 0.115570068359375 0.470367431640625 0.7541992187500055 +1.538125 0.115570068359375 0.470367431640625 0.7541992187500055 +1.5382500000000002 0.1151123046875 0.46856689453125 0.7541992187500055 +1.538375 0.1151123046875 0.46856689453125 0.7541992187500055 +1.5385 0.114654541015625 0.46673583984375 0.7541992187500055 +1.5386250000000002 0.11419677734375 0.464813232421875 0.7541992187500055 +1.53875 0.11419677734375 0.464813232421875 0.7541992187500055 +1.538875 0.11370849609375 0.462890625 0.7541992187500055 +1.539 0.11370849609375 0.462890625 0.7541992187500055 +1.539125 0.11322021484375 0.46087646484375 0.7541992187500055 +1.53925 0.11273193359375 0.458831787109375 0.7541992187500055 +1.539375 0.11273193359375 0.458831787109375 0.7541992187500055 +1.5395 0.112213134765625 0.45672607421875 0.7541992187500055 +1.539625 0.112213134765625 0.45672607421875 0.7541992187500055 +1.53975 0.111663818359375 0.454559326171875 0.7541992187500055 +1.539875 0.11114501953125 0.452362060546875 0.7541992187500055 +1.54 0.11114501953125 0.452362060546875 0.7541992187500055 +1.540125 0.110595703125 0.450103759765625 0.7541992187500055 +1.5402500000000002 0.110595703125 0.450103759765625 0.7541992187500055 +1.540375 0.110015869140625 0.447784423828125 0.7541992187500055 +1.5405 0.10943603515625 0.4454345703125 0.7541992187500055 +1.5406250000000002 0.10943603515625 0.4454345703125 0.7541992187500055 +1.54075 0.108856201171875 0.44305419921875 0.7541992187500055 +1.540875 0.108856201171875 0.44305419921875 0.7541992187500055 +1.541 0.108245849609375 0.440582275390625 0.7541992187500055 +1.541125 0.107635498046875 0.438079833984375 0.7541992187500055 +1.54125 0.107635498046875 0.438079833984375 0.7541992187500055 +1.541375 0.10699462890625 0.435546875 0.7541992187500055 +1.5415 0.10699462890625 0.435546875 0.7541992187500055 +1.541625 0.10638427734375 0.432952880859375 0.7541992187500055 +1.54175 0.105712890625 0.4302978515625 0.7541992187500055 +1.541875 0.105712890625 0.4302978515625 0.7541992187500055 +1.542 0.105072021484375 0.4276123046875 0.7541992187500055 +1.542125 0.105072021484375 0.4276123046875 0.7541992187500055 +1.5422500000000002 0.104400634765625 0.424896240234375 0.7541992187500055 +1.542375 0.10369873046875 0.422119140625 0.7541992187500055 +1.5425 0.10369873046875 0.422119140625 0.7541992187500055 +1.5426250000000002 0.102996826171875 0.419281005859375 0.7541992187500055 +1.54275 0.102996826171875 0.419281005859375 0.7541992187500055 +1.542875 0.102294921875 0.416412353515625 0.7541992187500055 +1.543 0.101593017578125 0.413482666015625 0.7541992187500055 +1.543125 0.101593017578125 0.413482666015625 0.7541992187500055 +1.54325 0.100860595703125 0.4105224609375 0.7541992187500055 +1.543375 0.100860595703125 0.4105224609375 0.7541992187500055 +1.5435 0.100128173828125 0.407501220703125 0.7541992187500055 +1.543625 0.099365234375 0.404449462890625 0.7541992187500055 +1.54375 0.099365234375 0.404449462890625 0.7541992187500055 +1.543875 0.098602294921875 0.401336669921875 0.7541992187500055 +1.544 0.098602294921875 0.401336669921875 0.7541992187500055 +1.544125 0.09783935546875 0.398193359375 0.7541992187500055 +1.5442500000000002 0.0970458984375 0.39501953125 0.7541992187500055 +1.544375 0.0970458984375 0.39501953125 0.7541992187500055 +1.5445 0.09625244140625 0.39178466796875 0.7541992187500055 +1.5446250000000002 0.09625244140625 0.39178466796875 0.7541992187500055 +1.54475 0.095458984375 0.388519287109375 0.7541992187500055 +1.544875 0.094635009765625 0.38519287109375 0.7541992187500055 +1.545 0.094635009765625 0.38519287109375 0.7541992187500055 +1.545125 0.09381103515625 0.3818359375 0.7541992187500055 +1.54525 0.09381103515625 0.3818359375 0.7541992187500055 +1.545375 0.092987060546875 0.378448486328125 0.7541992187500055 +1.5455 0.092132568359375 0.375 0.7541992187500055 +1.545625 0.092132568359375 0.375 0.7541992187500055 +1.54575 0.091278076171875 0.37152099609375 0.7541992187500055 +1.545875 0.091278076171875 0.37152099609375 0.7541992187500055 +1.546 0.09039306640625 0.36798095703125 0.7541992187500055 +1.546125 0.08953857421875 0.36444091796875 0.7541992187500055 +1.5462500000000002 0.08953857421875 0.36444091796875 0.7541992187500055 +1.546375 0.088653564453125 0.360809326171875 0.7541992187500055 +1.5465 0.088653564453125 0.360809326171875 0.7541992187500055 +1.5466250000000002 0.0877685546875 0.357177734375 0.7541992187500055 +1.54675 0.08685302734375 0.353485107421875 0.7541992187500055 +1.546875 0.08685302734375 0.353485107421875 0.7541992187500055 +1.547 0.0859375 0.349761962890625 0.7541992187500055 +1.547125 0.0859375 0.349761962890625 0.7541992187500055 +1.54725 0.08502197265625 0.34600830078125 0.7541992187500055 +1.547375 0.084075927734375 0.34222412109375 0.7541992187500055 +1.5475 0.084075927734375 0.34222412109375 0.7541992187500055 +1.547625 0.0831298828125 0.33837890625 0.7541992187500055 +1.54775 0.0831298828125 0.33837890625 0.7541992187500055 +1.5478750000000002 0.082183837890625 0.334503173828125 0.7541992187500055 +1.548 0.08123779296875 0.330596923828125 0.7541992187500055 +1.548125 0.08123779296875 0.330596923828125 0.7541992187500055 +1.5482500000000002 0.08026123046875 0.32666015625 0.7541992187500055 +1.548375 0.08026123046875 0.32666015625 0.7541992187500055 +1.5485 0.07928466796875 0.322662353515625 0.7541992187500055 +1.5486250000000002 0.078277587890625 0.31866455078125 0.7541992187500055 +1.54875 0.078277587890625 0.31866455078125 0.7541992187500055 +1.548875 0.077301025390625 0.314605712890625 0.7541992187500055 +1.549 0.077301025390625 0.314605712890625 0.7541992187500055 +1.549125 0.0762939453125 0.310516357421875 0.7541992187500055 +1.54925 0.075286865234375 0.306396484375 0.7541992187500055 +1.549375 0.075286865234375 0.306396484375 0.7541992187500055 +1.5495 0.074249267578125 0.30224609375 0.7541992187500055 +1.549625 0.074249267578125 0.30224609375 0.7541992187500055 +1.54975 0.073211669921875 0.298065185546875 0.7541992187500055 +1.5498750000000002 0.072174072265625 0.2938232421875 0.7541992187500055 +1.55 0.072174072265625 0.2938232421875 0.7541992187500055 +1.550125 0.071136474609375 0.289581298828125 0.7541992187500055 +1.5502500000000002 0.071136474609375 0.289581298828125 0.7541992187500055 +1.550375 0.070098876953125 0.285308837890625 0.7541992187500055 +1.5505 0.06903076171875 0.280975341796875 0.7541992187500055 +1.5506250000000002 0.06903076171875 0.280975341796875 0.7541992187500055 +1.55075 0.067962646484375 0.276641845703125 0.7541992187500055 +1.550875 0.067962646484375 0.276641845703125 0.7541992187500055 +1.551 0.06689453125 0.27227783203125 0.7541992187500055 +1.551125 0.0657958984375 0.267852783203125 0.7541992187500055 +1.55125 0.0657958984375 0.267852783203125 0.7541992187500055 +1.551375 0.064727783203125 0.263427734375 0.7541992187500055 +1.5515 0.064727783203125 0.263427734375 0.7541992187500055 +1.551625 0.063629150390625 0.25897216796875 0.7541992187500055 +1.55175 0.0625 0.25445556640625 0.7541992187500055 +1.5518750000000002 0.0625 0.25445556640625 0.7541992187500055 +1.552 0.0614013671875 0.249969482421875 0.7541992187500055 +1.552125 0.0614013671875 0.249969482421875 0.7541992187500055 +1.5522500000000002 0.060302734375 0.24542236328125 0.7541992187500055 +1.552375 0.059173583984375 0.2408447265625 0.7541992187500055 +1.5525 0.059173583984375 0.2408447265625 0.7541992187500055 +1.552625 0.05804443359375 0.236236572265625 0.7541992187500055 +1.55275 0.05804443359375 0.236236572265625 0.7541992187500055 +1.552875 0.056884765625 0.231597900390625 0.7541992187500055 +1.553 0.055755615234375 0.226959228515625 0.7541992187500055 +1.553125 0.055755615234375 0.226959228515625 0.7541992187500055 +1.55325 0.054595947265625 0.2222900390625 0.7541992187500055 +1.553375 0.054595947265625 0.2222900390625 0.7541992187500055 +1.5535 0.053436279296875 0.21759033203125 0.7541992187500055 +1.553625 0.052276611328125 0.212860107421875 0.7541992187500055 +1.55375 0.052276611328125 0.212860107421875 0.7541992187500055 +1.5538750000000002 0.051116943359375 0.208099365234375 0.7541992187500055 +1.554 0.051116943359375 0.208099365234375 0.7541992187500055 +1.554125 0.049957275390625 0.203338623046875 0.7541992187500055 +1.5542500000000002 0.04876708984375 0.19854736328125 0.7541992187500055 +1.554375 0.04876708984375 0.19854736328125 0.7541992187500055 +1.5545 0.047576904296875 0.1937255859375 0.7541992187500055 +1.554625 0.047576904296875 0.1937255859375 0.7541992187500055 +1.55475 0.04638671875 0.188873291015625 0.7541992187500055 +1.554875 0.045196533203125 0.18402099609375 0.7541992187500055 +1.555 0.045196533203125 0.18402099609375 0.7541992187500055 +1.555125 0.04400634765625 0.17913818359375 0.7541992187500055 +1.55525 0.04400634765625 0.17913818359375 0.7541992187500055 +1.555375 0.042816162109375 0.17425537109375 0.7541992187500055 +1.5555 0.041595458984375 0.169342041015625 0.7541992187500055 +1.555625 0.041595458984375 0.169342041015625 0.7541992187500055 +1.55575 0.040374755859375 0.164398193359375 0.7541992187500055 +1.5558750000000002 0.040374755859375 0.164398193359375 0.7541992187500055 +1.556 0.039154052734375 0.159454345703125 0.7541992187500055 +1.556125 0.037933349609375 0.15447998046875 0.7541992187500055 +1.5562500000000002 0.037933349609375 0.15447998046875 0.7541992187500055 +1.556375 0.036712646484375 0.14947509765625 0.7541992187500055 +1.5565 0.036712646484375 0.14947509765625 0.7541992187500055 +1.556625 0.035491943359375 0.14447021484375 0.7541992187500055 +1.55675 0.03424072265625 0.13946533203125 0.7541992187500055 +1.556875 0.03424072265625 0.13946533203125 0.7541992187500055 +1.557 0.03302001953125 0.134429931640625 0.7541992187500055 +1.557125 0.03302001953125 0.134429931640625 0.7541992187500055 +1.55725 0.031768798828125 0.129364013671875 0.7541992187500055 +1.557375 0.030517578125 0.124298095703125 0.7541992187500055 +1.5575 0.030517578125 0.124298095703125 0.7541992187500055 +1.557625 0.029296875 0.119232177734375 0.7541992187500055 +1.55775 0.029296875 0.119232177734375 0.7541992187500055 +1.5578750000000002 0.028045654296875 0.1141357421875 0.7541992187500055 +1.558 0.026763916015625 0.109039306640625 0.7541992187500055 +1.558125 0.026763916015625 0.109039306640625 0.7541992187500055 +1.5582500000000002 0.0255126953125 0.103912353515625 0.7541992187500055 +1.558375 0.0255126953125 0.103912353515625 0.7541992187500055 +1.5585 0.024261474609375 0.098785400390625 0.7541992187500055 +1.558625 0.02301025390625 0.093658447265625 0.7541992187500055 +1.55875 0.02301025390625 0.093658447265625 0.7541992187500055 +1.558875 0.021728515625 0.0885009765625 0.7541992187500055 +1.559 0.021728515625 0.0885009765625 0.7541992187500055 +1.559125 0.020477294921875 0.083343505859375 0.7541992187500055 +1.55925 0.019195556640625 0.07818603515625 0.7541992187500055 +1.559375 0.019195556640625 0.07818603515625 0.7541992187500055 +1.5595 0.017913818359375 0.072998046875 0.7541992187500055 +1.559625 0.017913818359375 0.072998046875 0.7541992187500055 +1.55975 0.01666259765625 0.06781005859375 0.7541992187500055 +1.5598750000000002 0.015380859375 0.0626220703125 0.7541992187500055 +1.56 0.015380859375 0.0626220703125 0.7541992187500055 +1.560125 0.01409912109375 0.05743408203125 0.7541992187500055 +1.5602500000000002 0.01409912109375 0.05743408203125 0.7541992187500055 +1.560375 0.0128173828125 0.05224609375 0.7541992187500055 +1.5605 0.01153564453125 0.047027587890625 0.7541992187500055 +1.560625 0.01153564453125 0.047027587890625 0.7541992187500055 +1.56075 0.01025390625 0.04180908203125 0.7541992187500055 +1.560875 0.01025390625 0.04180908203125 0.7541992187500055 +1.561 0.00897216796875 0.036590576171875 0.7541992187500055 +1.561125 0.0076904296875 0.0313720703125 0.7541992187500055 +1.56125 0.0076904296875 0.0313720703125 0.7541992187500055 +1.561375 0.00640869140625 0.026123046875 0.7541992187500055 +1.5615 0.00640869140625 0.026123046875 0.7541992187500055 +1.561625 0.005126953125 0.020904541015625 0.7541992187500055 +1.56175 0.00384521484375 0.01568603515625 0.7541992187500055 +1.5618750000000002 0.00384521484375 0.01568603515625 0.7541992187500055 +1.562 0.0025634765625 0.01043701171875 0.7541992187500055 +1.562125 0.0025634765625 0.01043701171875 0.7541992187500055 +1.5622500000000002 0.00128173828125 0.005218505859375 0.7541992187500055 +1.562375 0.0 0.0 0.7541992187500055 +1.5625 0.0 0.0 0.7541992187500055 +1.562625 -0.00128173828125 -0.005218505859375 0.7541992187500055 +1.56275 -0.00128173828125 -0.005218505859375 0.7541992187500055 +1.562875 -0.0025634765625 -0.01043701171875 0.7541992187500055 +1.563 -0.00384521484375 -0.01568603515625 0.7541992187500055 +1.563125 -0.00384521484375 -0.01568603515625 0.7541992187500055 +1.56325 -0.005126953125 -0.020904541015625 0.7541992187500055 +1.563375 -0.005126953125 -0.020904541015625 0.7541992187500055 +1.5635000000000002 -0.00640869140625 -0.026123046875 0.7541992187500055 +1.563625 -0.0076904296875 -0.0313720703125 0.7541992187500055 +1.56375 -0.0076904296875 -0.0313720703125 0.7541992187500055 +1.5638750000000002 -0.00897216796875 -0.036590576171875 0.7541992187500055 +1.564 -0.00897216796875 -0.036590576171875 0.7541992187500055 +1.564125 -0.01025390625 -0.04180908203125 0.7541992187500055 +1.5642500000000002 -0.01153564453125 -0.047027587890625 0.7541992187500055 +1.564375 -0.01153564453125 -0.047027587890625 0.7541992187500055 +1.5645 -0.0128173828125 -0.05224609375 0.7541992187500055 +1.564625 -0.0128173828125 -0.05224609375 0.7541992187500055 +1.56475 -0.01409912109375 -0.05743408203125 0.7541992187500055 +1.564875 -0.015380859375 -0.0626220703125 0.7541992187500055 +1.565 -0.015380859375 -0.0626220703125 0.7541992187500055 +1.565125 -0.01666259765625 -0.06781005859375 0.7541992187500055 +1.56525 -0.01666259765625 -0.06781005859375 0.7541992187500055 +1.565375 -0.017913818359375 -0.072998046875 0.7541992187500055 +1.5655000000000002 -0.019195556640625 -0.07818603515625 0.7541992187500055 +1.565625 -0.019195556640625 -0.07818603515625 0.7541992187500055 +1.56575 -0.020477294921875 -0.083343505859375 0.7541992187500055 +1.5658750000000002 -0.020477294921875 -0.083343505859375 0.7541992187500055 +1.566 -0.021728515625 -0.0885009765625 0.7541992187500055 +1.566125 -0.02301025390625 -0.093658447265625 0.7541992187500055 +1.5662500000000002 -0.02301025390625 -0.093658447265625 0.7541992187500055 +1.566375 -0.024261474609375 -0.098785400390625 0.7541992187500055 +1.5665 -0.024261474609375 -0.098785400390625 0.7541992187500055 +1.566625 -0.0255126953125 -0.103912353515625 0.7541992187500055 +1.56675 -0.026763916015625 -0.109039306640625 0.7541992187500055 +1.566875 -0.026763916015625 -0.109039306640625 0.7541992187500055 +1.567 -0.028045654296875 -0.1141357421875 0.7541992187500055 +1.567125 -0.028045654296875 -0.1141357421875 0.7541992187500055 +1.56725 -0.029296875 -0.119232177734375 0.7541992187500055 +1.567375 -0.030517578125 -0.124298095703125 0.7541992187500055 +1.5675000000000002 -0.030517578125 -0.124298095703125 0.7541992187500055 +1.567625 -0.031768798828125 -0.129364013671875 0.7541992187500055 +1.56775 -0.031768798828125 -0.129364013671875 0.7541992187500055 +1.5678750000000002 -0.03302001953125 -0.134429931640625 0.7541992187500055 +1.568 -0.006805419921875 -0.13946533203125 0.9510192871093776 +1.568125 -0.006805419921875 -0.13946533203125 0.9510192871093776 +1.56825 -0.007049560546875 -0.14447021484375 0.9510192871093776 +1.568375 -0.007049560546875 -0.14447021484375 0.9510192871093776 +1.5685 -0.007293701171875 -0.14947509765625 0.9510192871093776 +1.568625 -0.007537841796875 -0.15447998046875 0.9510192871093776 +1.56875 -0.007537841796875 -0.15447998046875 0.9510192871093776 +1.568875 -0.007781982421875 -0.159454345703125 0.9510192871093776 +1.569 -0.007781982421875 -0.159454345703125 0.9510192871093776 +1.569125 -0.008026123046875 -0.164398193359375 0.9510192871093776 +1.56925 -0.008270263671875 -0.169342041015625 0.9510192871093776 +1.569375 -0.008270263671875 -0.169342041015625 0.9510192871093776 +1.5695000000000002 -0.008514404296875 -0.17425537109375 0.9510192871093776 +1.569625 -0.008514404296875 -0.17425537109375 0.9510192871093776 +1.56975 -0.008758544921875 -0.17913818359375 0.9510192871093776 +1.5698750000000002 -0.00897216796875 -0.18402099609375 0.9510192871093776 +1.57 -0.00897216796875 -0.18402099609375 0.9510192871093776 +1.570125 -0.00921630859375 -0.188873291015625 0.9510192871093776 +1.57025 -0.00921630859375 -0.188873291015625 0.9510192871093776 +1.570375 -0.00946044921875 -0.1937255859375 0.9510192871093776 +1.5705 -0.00970458984375 -0.19854736328125 0.9510192871093776 +1.570625 -0.00970458984375 -0.19854736328125 0.9510192871093776 +1.57075 -0.009918212890625 -0.203338623046875 0.9510192871093776 +1.570875 -0.009918212890625 -0.203338623046875 0.9510192871093776 +1.571 -0.010162353515625 -0.208099365234375 0.9510192871093776 +1.571125 -0.010406494140625 -0.212860107421875 0.9510192871093776 +1.57125 -0.010406494140625 -0.212860107421875 0.9510192871093776 +1.571375 -0.0106201171875 -0.21759033203125 0.9510192871093776 +1.5715000000000002 -0.0106201171875 -0.21759033203125 0.9510192871093776 +1.571625 -0.0108642578125 -0.2222900390625 0.9510192871093776 +1.57175 -0.011077880859375 -0.226959228515625 0.9510192871093776 +1.5718750000000002 -0.011077880859375 -0.226959228515625 0.9510192871093776 +1.572 -0.011322021484375 -0.231597900390625 0.9510192871093776 +1.572125 -0.011322021484375 -0.231597900390625 0.9510192871093776 +1.57225 -0.01153564453125 -0.236236572265625 0.9510192871093776 +1.572375 -0.011749267578125 -0.2408447265625 0.9510192871093776 +1.5725 -0.011749267578125 -0.2408447265625 0.9510192871093776 +1.572625 -0.011993408203125 -0.24542236328125 0.9510192871093776 +1.57275 -0.011993408203125 -0.24542236328125 0.9510192871093776 +1.572875 -0.01220703125 -0.249969482421875 0.9510192871093776 +1.573 -0.012420654296875 -0.25445556640625 0.9510192871093776 +1.573125 -0.012420654296875 -0.25445556640625 0.9510192871093776 +1.57325 -0.01263427734375 -0.25897216796875 0.9510192871093776 +1.573375 -0.01263427734375 -0.25897216796875 0.9510192871093776 +1.5735000000000002 -0.01287841796875 -0.263427734375 0.9510192871093776 +1.573625 -0.013092041015625 -0.267852783203125 0.9510192871093776 +1.57375 -0.013092041015625 -0.267852783203125 0.9510192871093776 +1.5738750000000002 -0.0133056640625 -0.27227783203125 0.9510192871093776 +1.574 -0.0133056640625 -0.27227783203125 0.9510192871093776 +1.574125 -0.013519287109375 -0.276641845703125 0.9510192871093776 +1.57425 -0.01373291015625 -0.280975341796875 0.9510192871093776 +1.574375 -0.01373291015625 -0.280975341796875 0.9510192871093776 +1.5745 -0.013946533203125 -0.285308837890625 0.9510192871093776 +1.574625 -0.013946533203125 -0.285308837890625 0.9510192871093776 +1.57475 -0.014129638671875 -0.289581298828125 0.9510192871093776 +1.574875 -0.01434326171875 -0.2938232421875 0.9510192871093776 +1.575 -0.01434326171875 -0.2938232421875 0.9510192871093776 +1.575125 -0.014556884765625 -0.298065185546875 0.9510192871093776 +1.57525 -0.014556884765625 -0.298065185546875 0.9510192871093776 +1.575375 -0.0147705078125 -0.30224609375 0.9510192871093776 +1.5755000000000002 -0.01495361328125 -0.306396484375 0.9510192871093776 +1.575625 -0.01495361328125 -0.306396484375 0.9510192871093776 +1.57575 -0.015167236328125 -0.310516357421875 0.9510192871093776 +1.5758750000000002 -0.015167236328125 -0.310516357421875 0.9510192871093776 +1.576 -0.015380859375 -0.314605712890625 0.9510192871093776 +1.576125 -0.01556396484375 -0.31866455078125 0.9510192871093776 +1.57625 -0.01556396484375 -0.31866455078125 0.9510192871093776 +1.576375 -0.0157470703125 -0.322662353515625 0.9510192871093776 +1.5765 -0.0157470703125 -0.322662353515625 0.9510192871093776 +1.576625 -0.015960693359375 -0.32666015625 0.9510192871093776 +1.57675 -0.016143798828125 -0.330596923828125 0.9510192871093776 +1.576875 -0.016143798828125 -0.330596923828125 0.9510192871093776 +1.577 -0.016326904296875 -0.334503173828125 0.9510192871093776 +1.577125 -0.016326904296875 -0.334503173828125 0.9510192871093776 +1.57725 -0.01654052734375 -0.33837890625 0.9510192871093776 +1.577375 -0.0167236328125 -0.34222412109375 0.9510192871093776 +1.5775000000000002 -0.0167236328125 -0.34222412109375 0.9510192871093776 +1.577625 -0.01690673828125 -0.34600830078125 0.9510192871093776 +1.57775 -0.01690673828125 -0.34600830078125 0.9510192871093776 +1.5778750000000002 -0.01708984375 -0.349761962890625 0.9510192871093776 +1.578 -0.01727294921875 -0.353485107421875 0.9510192871093776 +1.578125 -0.01727294921875 -0.353485107421875 0.9510192871093776 +1.57825 -0.0174560546875 -0.357177734375 0.9510192871093776 +1.578375 -0.0174560546875 -0.357177734375 0.9510192871093776 +1.5785 -0.01763916015625 -0.360809326171875 0.9510192871093776 +1.578625 -0.017791748046875 -0.36444091796875 0.9510192871093776 +1.57875 -0.017791748046875 -0.36444091796875 0.9510192871093776 +1.578875 -0.017974853515625 -0.36798095703125 0.9510192871093776 +1.579 -0.017974853515625 -0.36798095703125 0.9510192871093776 +1.5791250000000002 -0.018157958984375 -0.37152099609375 0.9510192871093776 +1.57925 -0.018310546875 -0.375 0.9510192871093776 +1.579375 -0.018310546875 -0.375 0.9510192871093776 +1.5795000000000002 -0.01849365234375 -0.378448486328125 0.9510192871093776 +1.579625 -0.01849365234375 -0.378448486328125 0.9510192871093776 +1.57975 -0.018646240234375 -0.3818359375 0.9510192871093776 +1.5798750000000002 -0.018829345703125 -0.38519287109375 0.9510192871093776 +1.58 -0.018829345703125 -0.38519287109375 0.9510192871093776 +1.580125 -0.01898193359375 -0.388519287109375 0.9510192871093776 +1.58025 -0.01898193359375 -0.388519287109375 0.9510192871093776 +1.580375 -0.019134521484375 -0.39178466796875 0.9510192871093776 +1.5805 -0.019287109375 -0.39501953125 0.9510192871093776 +1.580625 -0.019287109375 -0.39501953125 0.9510192871093776 +1.58075 -0.019439697265625 -0.398193359375 0.9510192871093776 +1.580875 -0.019439697265625 -0.398193359375 0.9510192871093776 +1.581 -0.019622802734375 -0.401336669921875 0.9510192871093776 +1.5811250000000002 -0.019775390625 -0.404449462890625 0.9510192871093776 +1.58125 -0.019775390625 -0.404449462890625 0.9510192871093776 +1.581375 -0.0198974609375 -0.407501220703125 0.9510192871093776 +1.5815000000000002 -0.0198974609375 -0.407501220703125 0.9510192871093776 +1.581625 -0.020050048828125 -0.4105224609375 0.9510192871093776 +1.58175 -0.02020263671875 -0.413482666015625 0.9510192871093776 +1.5818750000000002 -0.02020263671875 -0.413482666015625 0.9510192871093776 +1.582 -0.020355224609375 -0.416412353515625 0.9510192871093776 +1.582125 -0.020355224609375 -0.416412353515625 0.9510192871093776 +1.58225 -0.020477294921875 -0.419281005859375 0.9510192871093776 +1.582375 -0.0206298828125 -0.422119140625 0.9510192871093776 +1.5825 -0.0206298828125 -0.422119140625 0.9510192871093776 +1.582625 -0.020751953125 -0.424896240234375 0.9510192871093776 +1.58275 -0.020751953125 -0.424896240234375 0.9510192871093776 +1.582875 -0.020904541015625 -0.4276123046875 0.9510192871093776 +1.583 -0.021026611328125 -0.4302978515625 0.9510192871093776 +1.5831250000000002 -0.021026611328125 -0.4302978515625 0.9510192871093776 +1.58325 -0.021148681640625 -0.432952880859375 0.9510192871093776 +1.583375 -0.021148681640625 -0.432952880859375 0.9510192871093776 +1.5835000000000002 -0.021270751953125 -0.435546875 0.9510192871093776 +1.583625 -0.021392822265625 -0.438079833984375 0.9510192871093776 +1.58375 -0.021392822265625 -0.438079833984375 0.9510192871093776 +1.5838750000000002 -0.021514892578125 -0.440582275390625 0.9510192871093776 +1.584 -0.021514892578125 -0.440582275390625 0.9510192871093776 +1.584125 -0.021636962890625 -0.44305419921875 0.9510192871093776 +1.58425 -0.021759033203125 -0.4454345703125 0.9510192871093776 +1.584375 -0.021759033203125 -0.4454345703125 0.9510192871093776 +1.5845 -0.021881103515625 -0.447784423828125 0.9510192871093776 +1.584625 -0.021881103515625 -0.447784423828125 0.9510192871093776 +1.58475 -0.022003173828125 -0.450103759765625 0.9510192871093776 +1.584875 -0.0220947265625 -0.452362060546875 0.9510192871093776 +1.585 -0.0220947265625 -0.452362060546875 0.9510192871093776 +1.5851250000000002 -0.022216796875 -0.454559326171875 0.9510192871093776 +1.58525 -0.022216796875 -0.454559326171875 0.9510192871093776 +1.585375 -0.022308349609375 -0.45672607421875 0.9510192871093776 +1.5855000000000002 -0.022430419921875 -0.458831787109375 0.9510192871093776 +1.585625 -0.022430419921875 -0.458831787109375 0.9510192871093776 +1.58575 -0.02252197265625 -0.46087646484375 0.9510192871093776 +1.585875 -0.02252197265625 -0.46087646484375 0.9510192871093776 +1.586 -0.022613525390625 -0.462890625 0.9510192871093776 +1.586125 -0.022705078125 -0.464813232421875 0.9510192871093776 +1.58625 -0.022705078125 -0.464813232421875 0.9510192871093776 +1.586375 -0.022796630859375 -0.46673583984375 0.9510192871093776 +1.5865 -0.022796630859375 -0.46673583984375 0.9510192871093776 +1.586625 -0.02288818359375 -0.46856689453125 0.9510192871093776 +1.58675 -0.022979736328125 -0.470367431640625 0.9510192871093776 +1.586875 -0.022979736328125 -0.470367431640625 0.9510192871093776 +1.587 -0.0230712890625 -0.472137451171875 0.9510192871093776 +1.5871250000000002 -0.0230712890625 -0.472137451171875 0.9510192871093776 +1.58725 -0.023162841796875 -0.47381591796875 0.9510192871093776 +1.587375 -0.023223876953125 -0.4754638671875 0.9510192871093776 +1.5875000000000002 -0.023223876953125 -0.4754638671875 0.9510192871093776 +1.587625 -0.0233154296875 -0.47705078125 0.9510192871093776 +1.58775 -0.0233154296875 -0.47705078125 0.9510192871093776 +1.587875 -0.02337646484375 -0.478607177734375 0.9510192871093776 +1.588 -0.023468017578125 -0.480072021484375 0.9510192871093776 +1.588125 -0.023468017578125 -0.480072021484375 0.9510192871093776 +1.58825 -0.023529052734375 -0.48150634765625 0.9510192871093776 +1.588375 -0.023529052734375 -0.48150634765625 0.9510192871093776 +1.5885 -0.023590087890625 -0.48291015625 0.9510192871093776 +1.588625 -0.023651123046875 -0.484222412109375 0.9510192871093776 +1.58875 -0.023651123046875 -0.484222412109375 0.9510192871093776 +1.588875 -0.023712158203125 -0.485504150390625 0.9510192871093776 +1.589 -0.023712158203125 -0.485504150390625 0.9510192871093776 +1.5891250000000002 -0.023773193359375 -0.486724853515625 0.9510192871093776 +1.58925 -0.023834228515625 -0.487884521484375 0.9510192871093776 +1.589375 -0.023834228515625 -0.487884521484375 0.9510192871093776 +1.5895000000000002 -0.023895263671875 -0.489013671875 0.9510192871093776 +1.589625 -0.023895263671875 -0.489013671875 0.9510192871093776 +1.58975 -0.023956298828125 -0.490081787109375 0.9510192871093776 +1.589875 -0.02398681640625 -0.4910888671875 0.9510192871093776 +1.59 -0.02398681640625 -0.4910888671875 0.9510192871093776 +1.590125 -0.0240478515625 -0.492034912109375 0.9510192871093776 +1.59025 -0.0240478515625 -0.492034912109375 0.9510192871093776 +1.590375 -0.024078369140625 -0.492950439453125 0.9510192871093776 +1.5905 -0.024139404296875 -0.4937744140625 0.9510192871093776 +1.590625 -0.024139404296875 -0.4937744140625 0.9510192871093776 +1.59075 -0.024169921875 -0.49456787109375 0.9510192871093776 +1.590875 -0.024169921875 -0.49456787109375 0.9510192871093776 +1.591 -0.024200439453125 -0.49530029296875 0.9510192871093776 +1.5911250000000002 -0.02423095703125 -0.496002197265625 0.9510192871093776 +1.59125 -0.02423095703125 -0.496002197265625 0.9510192871093776 +1.591375 -0.024261474609375 -0.496612548828125 0.9510192871093776 +1.5915000000000002 -0.024261474609375 -0.496612548828125 0.9510192871093776 +1.591625 -0.0242919921875 -0.4971923828125 0.9510192871093776 +1.59175 -0.024322509765625 -0.497711181640625 0.9510192871093776 +1.591875 -0.024322509765625 -0.497711181640625 0.9510192871093776 +1.592 -0.02435302734375 -0.498199462890625 0.9510192871093776 +1.592125 -0.02435302734375 -0.498199462890625 0.9510192871093776 +1.59225 -0.02435302734375 -0.49859619140625 0.9510192871093776 +1.592375 -0.024383544921875 -0.49896240234375 0.9510192871093776 +1.5925 -0.024383544921875 -0.49896240234375 0.9510192871093776 +1.592625 -0.024383544921875 -0.499267578125 0.9510192871093776 +1.59275 -0.024383544921875 -0.499267578125 0.9510192871093776 +1.592875 -0.0244140625 -0.49951171875 0.9510192871093776 +1.593 -0.0244140625 -0.49969482421875 0.9510192871093776 +1.5931250000000002 -0.0244140625 -0.49969482421875 0.9510192871093776 +1.59325 -0.0244140625 -0.49981689453125 0.9510192871093776 +1.593375 -0.0244140625 -0.49981689453125 0.9510192871093776 +1.5935000000000002 -0.0244140625 -0.499908447265625 0.9510192871093776 +1.593625 -0.0244140625 -0.49993896484375 0.9510192871093776 +1.59375 -0.0244140625 -0.49993896484375 0.9510192871093776 +1.593875 -0.0244140625 -0.499908447265625 0.9510192871093776 +1.594 -0.0244140625 -0.499908447265625 0.9510192871093776 +1.594125 -0.0244140625 -0.49981689453125 0.9510192871093776 +1.59425 -0.0244140625 -0.49969482421875 0.9510192871093776 +1.594375 -0.0244140625 -0.49969482421875 0.9510192871093776 +1.5945 -0.0244140625 -0.49951171875 0.9510192871093776 +1.594625 -0.0244140625 -0.49951171875 0.9510192871093776 +1.5947500000000002 -0.024383544921875 -0.499267578125 0.9510192871093776 +1.594875 -0.024383544921875 -0.49896240234375 0.9510192871093776 +1.595 -0.024383544921875 -0.49896240234375 0.9510192871093776 +1.5951250000000002 -0.02435302734375 -0.49859619140625 0.9510192871093776 +1.59525 -0.02435302734375 -0.49859619140625 0.9510192871093776 +1.595375 -0.02435302734375 -0.498199462890625 0.9510192871093776 +1.5955000000000002 -0.024322509765625 -0.497711181640625 0.9510192871093776 +1.595625 -0.024322509765625 -0.497711181640625 0.9510192871093776 +1.59575 -0.0242919921875 -0.4971923828125 0.9510192871093776 +1.595875 -0.0242919921875 -0.4971923828125 0.9510192871093776 +1.596 -0.024261474609375 -0.496612548828125 0.9510192871093776 +1.596125 -0.02423095703125 -0.496002197265625 0.9510192871093776 +1.59625 -0.02423095703125 -0.496002197265625 0.9510192871093776 +1.596375 -0.024200439453125 -0.49530029296875 0.9510192871093776 +1.5965 -0.024200439453125 -0.49530029296875 0.9510192871093776 +1.596625 -0.024169921875 -0.49456787109375 0.9510192871093776 +1.5967500000000002 -0.024139404296875 -0.4937744140625 0.9510192871093776 +1.596875 -0.024139404296875 -0.4937744140625 0.9510192871093776 +1.597 -0.024078369140625 -0.492950439453125 0.9510192871093776 +1.5971250000000002 -0.024078369140625 -0.492950439453125 0.9510192871093776 +1.59725 -0.0240478515625 -0.492034912109375 0.9510192871093776 +1.597375 -0.02398681640625 -0.4910888671875 0.9510192871093776 +1.5975000000000002 -0.02398681640625 -0.4910888671875 0.9510192871093776 +1.597625 -0.023956298828125 -0.490081787109375 0.9510192871093776 +1.59775 -0.023956298828125 -0.490081787109375 0.9510192871093776 +1.597875 -0.023895263671875 -0.489013671875 0.9510192871093776 +1.598 -0.023834228515625 -0.487884521484375 0.9510192871093776 +1.598125 -0.023834228515625 -0.487884521484375 0.9510192871093776 +1.59825 -0.023773193359375 -0.486724853515625 0.9510192871093776 +1.598375 -0.023773193359375 -0.486724853515625 0.9510192871093776 +1.5985 -0.023712158203125 -0.485504150390625 0.9510192871093776 +1.598625 -0.023651123046875 -0.484222412109375 0.9510192871093776 +1.5987500000000002 -0.023651123046875 -0.484222412109375 0.9510192871093776 +1.598875 -0.023590087890625 -0.48291015625 0.9510192871093776 +1.599 -0.023590087890625 -0.48291015625 0.9510192871093776 +1.5991250000000002 -0.023529052734375 -0.48150634765625 0.9510192871093776 +1.59925 -0.023468017578125 -0.480072021484375 0.9510192871093776 +1.599375 -0.023468017578125 -0.480072021484375 0.9510192871093776 +1.5995000000000002 -0.02337646484375 -0.478607177734375 0.9510192871093776 +1.599625 -0.02337646484375 -0.478607177734375 0.9510192871093776 +1.59975 -0.0233154296875 -0.47705078125 0.9510192871093776 +1.599875 -0.023223876953125 -0.4754638671875 0.9510192871093776 +1.6 -0.001800537109375 -0.4754638671875 0.99608154296874928 +1.600125 -0.001800537109375 -0.47381591796875 0.99608154296874928 +1.60025 -0.001800537109375 -0.47381591796875 0.99608154296874928 +1.600375 -0.001800537109375 -0.472137451171875 0.99608154296874928 +1.6005 -0.00177001953125 -0.470367431640625 0.99608154296874928 +1.600625 -0.00177001953125 -0.470367431640625 0.99608154296874928 +1.6007500000000002 -0.00177001953125 -0.46856689453125 0.99608154296874928 +1.600875 -0.00177001953125 -0.46856689453125 0.99608154296874928 +1.601 -0.00177001953125 -0.46673583984375 0.99608154296874928 +1.6011250000000002 -0.00177001953125 -0.464813232421875 0.99608154296874928 +1.60125 -0.00177001953125 -0.464813232421875 0.99608154296874928 +1.601375 -0.001739501953125 -0.462890625 0.99608154296874928 +1.6015 -0.001739501953125 -0.462890625 0.99608154296874928 +1.601625 -0.001739501953125 -0.46087646484375 0.99608154296874928 +1.60175 -0.001739501953125 -0.458831787109375 0.99608154296874928 +1.601875 -0.001739501953125 -0.458831787109375 0.99608154296874928 +1.602 -0.001739501953125 -0.45672607421875 0.99608154296874928 +1.602125 -0.001739501953125 -0.45672607421875 0.99608154296874928 +1.60225 -0.001708984375 -0.454559326171875 0.99608154296874928 +1.602375 -0.001708984375 -0.452362060546875 0.99608154296874928 +1.6025 -0.001708984375 -0.452362060546875 0.99608154296874928 +1.602625 -0.001708984375 -0.450103759765625 0.99608154296874928 +1.6027500000000002 -0.001708984375 -0.450103759765625 0.99608154296874928 +1.602875 -0.001678466796875 -0.447784423828125 0.99608154296874928 +1.603 -0.001678466796875 -0.4454345703125 0.99608154296874928 +1.6031250000000002 -0.001678466796875 -0.4454345703125 0.99608154296874928 +1.60325 -0.001678466796875 -0.44305419921875 0.99608154296874928 +1.603375 -0.001678466796875 -0.44305419921875 0.99608154296874928 +1.6035 -0.001678466796875 -0.440582275390625 0.99608154296874928 +1.603625 -0.00164794921875 -0.438079833984375 0.99608154296874928 +1.60375 -0.00164794921875 -0.438079833984375 0.99608154296874928 +1.603875 -0.00164794921875 -0.435546875 0.99608154296874928 +1.604 -0.00164794921875 -0.435546875 0.99608154296874928 +1.604125 -0.00164794921875 -0.432952880859375 0.99608154296874928 +1.60425 -0.001617431640625 -0.4302978515625 0.99608154296874928 +1.604375 -0.001617431640625 -0.4302978515625 0.99608154296874928 +1.6045 -0.001617431640625 -0.4276123046875 0.99608154296874928 +1.604625 -0.001617431640625 -0.4276123046875 0.99608154296874928 +1.6047500000000002 -0.001617431640625 -0.424896240234375 0.99608154296874928 +1.604875 -0.0015869140625 -0.422119140625 0.99608154296874928 +1.605 -0.0015869140625 -0.422119140625 0.99608154296874928 +1.6051250000000002 -0.0015869140625 -0.419281005859375 0.99608154296874928 +1.60525 -0.0015869140625 -0.419281005859375 0.99608154296874928 +1.605375 -0.0015869140625 -0.416412353515625 0.99608154296874928 +1.6055 -0.001556396484375 -0.413482666015625 0.99608154296874928 +1.605625 -0.001556396484375 -0.413482666015625 0.99608154296874928 +1.60575 -0.001556396484375 -0.4105224609375 0.99608154296874928 +1.605875 -0.001556396484375 -0.4105224609375 0.99608154296874928 +1.606 -0.00152587890625 -0.407501220703125 0.99608154296874928 +1.606125 -0.00152587890625 -0.404449462890625 0.99608154296874928 +1.60625 -0.00152587890625 -0.404449462890625 0.99608154296874928 +1.606375 -0.00152587890625 -0.401336669921875 0.99608154296874928 +1.6065 -0.00152587890625 -0.401336669921875 0.99608154296874928 +1.606625 -0.001495361328125 -0.398193359375 0.99608154296874928 +1.6067500000000002 -0.001495361328125 -0.39501953125 0.99608154296874928 +1.606875 -0.001495361328125 -0.39501953125 0.99608154296874928 +1.607 -0.00146484375 -0.39178466796875 0.99608154296874928 +1.6071250000000002 -0.00146484375 -0.39178466796875 0.99608154296874928 +1.60725 -0.00146484375 -0.388519287109375 0.99608154296874928 +1.607375 -0.00146484375 -0.38519287109375 0.99608154296874928 +1.6075 -0.00146484375 -0.38519287109375 0.99608154296874928 +1.607625 -0.001434326171875 -0.3818359375 0.99608154296874928 +1.60775 -0.001434326171875 -0.3818359375 0.99608154296874928 +1.607875 -0.001434326171875 -0.378448486328125 0.99608154296874928 +1.608 -0.00140380859375 -0.375 0.99608154296874928 +1.608125 -0.00140380859375 -0.375 0.99608154296874928 +1.60825 -0.00140380859375 -0.37152099609375 0.99608154296874928 +1.608375 -0.00140380859375 -0.37152099609375 0.99608154296874928 +1.6085 -0.00140380859375 -0.36798095703125 0.99608154296874928 +1.608625 -0.001373291015625 -0.36444091796875 0.99608154296874928 +1.6087500000000002 -0.001373291015625 -0.36444091796875 0.99608154296874928 +1.608875 -0.001373291015625 -0.360809326171875 0.99608154296874928 +1.609 -0.001373291015625 -0.360809326171875 0.99608154296874928 +1.6091250000000002 -0.0013427734375 -0.357177734375 0.99608154296874928 +1.60925 -0.0013427734375 -0.353485107421875 0.99608154296874928 +1.609375 -0.0013427734375 -0.353485107421875 0.99608154296874928 +1.6095 -0.001312255859375 -0.349761962890625 0.99608154296874928 +1.609625 -0.001312255859375 -0.349761962890625 0.99608154296874928 +1.60975 -0.001312255859375 -0.34600830078125 0.99608154296874928 +1.609875 -0.00128173828125 -0.34222412109375 0.99608154296874928 +1.61 -0.00128173828125 -0.34222412109375 0.99608154296874928 +1.610125 -0.00128173828125 -0.33837890625 0.99608154296874928 +1.61025 -0.00128173828125 -0.33837890625 0.99608154296874928 +1.6103750000000002 -0.001251220703125 -0.334503173828125 0.99608154296874928 +1.6105 -0.001251220703125 -0.330596923828125 0.99608154296874928 +1.610625 -0.001251220703125 -0.330596923828125 0.99608154296874928 +1.6107500000000002 -0.001220703125 -0.32666015625 0.99608154296874928 +1.610875 -0.001220703125 -0.32666015625 0.99608154296874928 +1.611 -0.001220703125 -0.322662353515625 0.99608154296874928 +1.6111250000000002 -0.001190185546875 -0.31866455078125 0.99608154296874928 +1.61125 -0.001190185546875 -0.31866455078125 0.99608154296874928 +1.611375 -0.001190185546875 -0.314605712890625 0.99608154296874928 +1.6115 -0.001190185546875 -0.314605712890625 0.99608154296874928 +1.611625 -0.00115966796875 -0.310516357421875 0.99608154296874928 +1.61175 -0.00115966796875 -0.306396484375 0.99608154296874928 +1.611875 -0.00115966796875 -0.306396484375 0.99608154296874928 +1.612 -0.001129150390625 -0.30224609375 0.99608154296874928 +1.612125 -0.001129150390625 -0.30224609375 0.99608154296874928 +1.61225 -0.001129150390625 -0.298065185546875 0.99608154296874928 +1.6123750000000002 -0.0010986328125 -0.2938232421875 0.99608154296874928 +1.6125 -0.0010986328125 -0.2938232421875 0.99608154296874928 +1.612625 -0.0010986328125 -0.289581298828125 0.99608154296874928 +1.6127500000000002 -0.0010986328125 -0.289581298828125 0.99608154296874928 +1.612875 -0.001068115234375 -0.285308837890625 0.99608154296874928 +1.613 -0.001068115234375 -0.280975341796875 0.99608154296874928 +1.6131250000000002 -0.001068115234375 -0.280975341796875 0.99608154296874928 +1.61325 -0.00103759765625 -0.276641845703125 0.99608154296874928 +1.613375 -0.00103759765625 -0.276641845703125 0.99608154296874928 +1.6135 -0.00103759765625 -0.27227783203125 0.99608154296874928 +1.613625 -0.001007080078125 -0.267852783203125 0.99608154296874928 +1.61375 -0.001007080078125 -0.267852783203125 0.99608154296874928 +1.613875 -0.0009765625 -0.263427734375 0.99608154296874928 +1.614 -0.0009765625 -0.263427734375 0.99608154296874928 +1.614125 -0.0009765625 -0.25897216796875 0.99608154296874928 +1.61425 -0.000946044921875 -0.25445556640625 0.99608154296874928 +1.6143750000000002 -0.000946044921875 -0.25445556640625 0.99608154296874928 +1.6145 -0.000946044921875 -0.249969482421875 0.99608154296874928 +1.614625 -0.000946044921875 -0.249969482421875 0.99608154296874928 +1.6147500000000002 -0.00091552734375 -0.24542236328125 0.99608154296874928 +1.614875 -0.00091552734375 -0.2408447265625 0.99608154296874928 +1.615 -0.00091552734375 -0.2408447265625 0.99608154296874928 +1.6151250000000002 -0.000885009765625 -0.236236572265625 0.99608154296874928 +1.61525 -0.000885009765625 -0.236236572265625 0.99608154296874928 +1.615375 -0.0008544921875 -0.231597900390625 0.99608154296874928 +1.6155 -0.0008544921875 -0.226959228515625 0.99608154296874928 +1.615625 -0.0008544921875 -0.226959228515625 0.99608154296874928 +1.61575 -0.000823974609375 -0.2222900390625 0.99608154296874928 +1.615875 -0.000823974609375 -0.2222900390625 0.99608154296874928 +1.616 -0.000823974609375 -0.21759033203125 0.99608154296874928 +1.616125 -0.00079345703125 -0.212860107421875 0.99608154296874928 +1.61625 -0.00079345703125 -0.212860107421875 0.99608154296874928 +1.6163750000000002 -0.00079345703125 -0.208099365234375 0.99608154296874928 +1.6165 -0.00079345703125 -0.208099365234375 0.99608154296874928 +1.616625 -0.000762939453125 -0.203338623046875 0.99608154296874928 +1.6167500000000002 -0.000732421875 -0.19854736328125 0.99608154296874928 +1.616875 -0.000732421875 -0.19854736328125 0.99608154296874928 +1.617 -0.000732421875 -0.1937255859375 0.99608154296874928 +1.617125 -0.000732421875 -0.1937255859375 0.99608154296874928 +1.61725 -0.000701904296875 -0.188873291015625 0.99608154296874928 +1.617375 -0.000701904296875 -0.18402099609375 0.99608154296874928 +1.6175 -0.000701904296875 -0.18402099609375 0.99608154296874928 +1.617625 -0.00067138671875 -0.17913818359375 0.99608154296874928 +1.61775 -0.00067138671875 -0.17913818359375 0.99608154296874928 +1.617875 -0.000640869140625 -0.17425537109375 0.99608154296874928 +1.618 -0.000640869140625 -0.169342041015625 0.99608154296874928 +1.618125 -0.000640869140625 -0.169342041015625 0.99608154296874928 +1.61825 -0.0006103515625 -0.164398193359375 0.99608154296874928 +1.6183750000000002 -0.0006103515625 -0.164398193359375 0.99608154296874928 +1.6185 -0.000579833984375 -0.159454345703125 0.99608154296874928 +1.618625 -0.000579833984375 -0.15447998046875 0.99608154296874928 +1.6187500000000002 -0.000579833984375 -0.15447998046875 0.99608154296874928 +1.618875 -0.00054931640625 -0.14947509765625 0.99608154296874928 +1.619 -0.00054931640625 -0.14947509765625 0.99608154296874928 +1.619125 -0.00054931640625 -0.14447021484375 0.99608154296874928 +1.61925 -0.000518798828125 -0.13946533203125 0.99608154296874928 +1.619375 -0.000518798828125 -0.13946533203125 0.99608154296874928 +1.6195 -0.00048828125 -0.134429931640625 0.99608154296874928 +1.619625 -0.00048828125 -0.134429931640625 0.99608154296874928 +1.61975 -0.00048828125 -0.129364013671875 0.99608154296874928 +1.619875 -0.000457763671875 -0.124298095703125 0.99608154296874928 +1.62 -0.000457763671875 -0.124298095703125 0.99608154296874928 +1.620125 -0.00042724609375 -0.119232177734375 0.99608154296874928 +1.62025 -0.00042724609375 -0.119232177734375 0.99608154296874928 +1.6203750000000002 -0.00042724609375 -0.1141357421875 0.99608154296874928 +1.6205 -0.000396728515625 -0.109039306640625 0.99608154296874928 +1.620625 -0.000396728515625 -0.109039306640625 0.99608154296874928 +1.6207500000000002 -0.0003662109375 -0.103912353515625 0.99608154296874928 +1.620875 -0.0003662109375 -0.103912353515625 0.99608154296874928 +1.621 -0.0003662109375 -0.098785400390625 0.99608154296874928 +1.621125 -0.000335693359375 -0.093658447265625 0.99608154296874928 +1.62125 -0.000335693359375 -0.093658447265625 0.99608154296874928 +1.621375 -0.000335693359375 -0.0885009765625 0.99608154296874928 +1.6215 -0.000335693359375 -0.0885009765625 0.99608154296874928 +1.621625 -0.00030517578125 -0.083343505859375 0.99608154296874928 +1.62175 -0.000274658203125 -0.07818603515625 0.99608154296874928 +1.621875 -0.000274658203125 -0.07818603515625 0.99608154296874928 +1.622 -0.000274658203125 -0.072998046875 0.99608154296874928 +1.622125 -0.000274658203125 -0.072998046875 0.99608154296874928 +1.62225 -0.000244140625 -0.06781005859375 0.99608154296874928 +1.6223750000000002 -0.000213623046875 -0.0626220703125 0.99608154296874928 +1.6225 -0.000213623046875 -0.0626220703125 0.99608154296874928 +1.622625 -0.000213623046875 -0.05743408203125 0.99608154296874928 +1.6227500000000002 -0.000213623046875 -0.05743408203125 0.99608154296874928 +1.622875 -0.00018310546875 -0.05224609375 0.99608154296874928 +1.623 -0.000152587890625 -0.047027587890625 0.99608154296874928 +1.623125 -0.000152587890625 -0.047027587890625 0.99608154296874928 +1.62325 -0.000152587890625 -0.04180908203125 0.99608154296874928 +1.623375 -0.000152587890625 -0.04180908203125 0.99608154296874928 +1.6235 -0.0001220703125 -0.036590576171875 0.99608154296874928 +1.623625 -9.1552734375e-05 -0.0313720703125 0.99608154296874928 +1.62375 -9.1552734375e-05 -0.0313720703125 0.99608154296874928 +1.623875 -9.1552734375e-05 -0.026123046875 0.99608154296874928 +1.624 -9.1552734375e-05 -0.026123046875 0.99608154296874928 +1.624125 -6.103515625e-05 -0.020904541015625 0.99608154296874928 +1.62425 -3.0517578125e-05 -0.01568603515625 0.99608154296874928 +1.6243750000000002 -3.0517578125e-05 -0.01568603515625 0.99608154296874928 +1.6245 -3.0517578125e-05 -0.01043701171875 0.99608154296874928 +1.624625 -3.0517578125e-05 -0.01043701171875 0.99608154296874928 +1.6247500000000002 0.0 -0.005218505859375 0.99608154296874928 +1.624875 0.0 0.0 0.99608154296874928 +1.625 0.0 0.0 0.99608154296874928 +1.625125 0.0 0.005218505859375 0.99608154296874928 +1.62525 0.0 0.005218505859375 0.99608154296874928 +1.625375 3.0517578125e-05 0.01043701171875 0.99608154296874928 +1.6255 3.0517578125e-05 0.01568603515625 0.99608154296874928 +1.625625 3.0517578125e-05 0.01568603515625 0.99608154296874928 +1.62575 6.103515625e-05 0.020904541015625 0.99608154296874928 +1.625875 6.103515625e-05 0.020904541015625 0.99608154296874928 +1.6260000000000002 9.1552734375e-05 0.026123046875 0.99608154296874928 +1.626125 9.1552734375e-05 0.0313720703125 0.99608154296874928 +1.62625 9.1552734375e-05 0.0313720703125 0.99608154296874928 +1.6263750000000002 0.0001220703125 0.036590576171875 0.99608154296874928 +1.6265 0.0001220703125 0.036590576171875 0.99608154296874928 +1.626625 0.000152587890625 0.04180908203125 0.99608154296874928 +1.6267500000000002 0.000152587890625 0.047027587890625 0.99608154296874928 +1.626875 0.000152587890625 0.047027587890625 0.99608154296874928 +1.627 0.00018310546875 0.05224609375 0.99608154296874928 +1.627125 0.00018310546875 0.05224609375 0.99608154296874928 +1.62725 0.000213623046875 0.05743408203125 0.99608154296874928 +1.627375 0.000213623046875 0.0626220703125 0.99608154296874928 +1.6275 0.000213623046875 0.0626220703125 0.99608154296874928 +1.627625 0.000244140625 0.06781005859375 0.99608154296874928 +1.62775 0.000244140625 0.06781005859375 0.99608154296874928 +1.627875 0.000274658203125 0.072998046875 0.99608154296874928 +1.6280000000000002 0.000274658203125 0.07818603515625 0.99608154296874928 +1.628125 0.000274658203125 0.07818603515625 0.99608154296874928 +1.62825 0.00030517578125 0.083343505859375 0.99608154296874928 +1.6283750000000002 0.00030517578125 0.083343505859375 0.99608154296874928 +1.6285 0.000335693359375 0.0885009765625 0.99608154296874928 +1.628625 0.000335693359375 0.093658447265625 0.99608154296874928 +1.6287500000000002 0.000335693359375 0.093658447265625 0.99608154296874928 +1.628875 0.0003662109375 0.098785400390625 0.99608154296874928 +1.629 0.0003662109375 0.098785400390625 0.99608154296874928 +1.629125 0.0003662109375 0.103912353515625 0.99608154296874928 +1.62925 0.000396728515625 0.109039306640625 0.99608154296874928 +1.629375 0.000396728515625 0.109039306640625 0.99608154296874928 +1.6295 0.00042724609375 0.1141357421875 0.99608154296874928 +1.629625 0.00042724609375 0.1141357421875 0.99608154296874928 +1.62975 0.00042724609375 0.119232177734375 0.99608154296874928 +1.629875 0.000457763671875 0.124298095703125 0.99608154296874928 +1.6300000000000002 0.000457763671875 0.124298095703125 0.99608154296874928 +1.630125 0.00048828125 0.129364013671875 0.99608154296874928 +1.63025 0.00048828125 0.129364013671875 0.99608154296874928 +1.6303750000000002 0.00048828125 0.134429931640625 0.99608154296874928 +1.6305 0.000518798828125 0.13946533203125 0.99608154296874928 +1.630625 0.000518798828125 0.13946533203125 0.99608154296874928 +1.6307500000000002 0.00054931640625 0.14447021484375 0.99608154296874928 +1.630875 0.00054931640625 0.14447021484375 0.99608154296874928 +1.631 0.00054931640625 0.14947509765625 0.99608154296874928 +1.631125 0.000579833984375 0.15447998046875 0.99608154296874928 +1.63125 0.000579833984375 0.15447998046875 0.99608154296874928 +1.631375 0.000579833984375 0.159454345703125 0.99608154296874928 +1.6315 0.000579833984375 0.159454345703125 0.99608154296874928 +1.631625 0.0006103515625 0.164398193359375 0.99608154296874928 +1.63175 0.000640869140625 0.169342041015625 0.99608154296874928 +1.631875 0.000640869140625 0.169342041015625 0.99608154296874928 +1.6320000000000002 0.020477294921875 0.17425537109375 0.882238769531246 +1.632125 0.020477294921875 0.17425537109375 0.882238769531246 +1.63225 0.02105712890625 0.17913818359375 0.882238769531246 +1.6323750000000002 0.021636962890625 0.18402099609375 0.882238769531246 +1.6325 0.021636962890625 0.18402099609375 0.882238769531246 +1.632625 0.022216796875 0.188873291015625 0.882238769531246 +1.63275 0.022216796875 0.188873291015625 0.882238769531246 +1.632875 0.022796630859375 0.1937255859375 0.882238769531246 +1.633 0.023345947265625 0.19854736328125 0.882238769531246 +1.633125 0.023345947265625 0.19854736328125 0.882238769531246 +1.63325 0.02392578125 0.203338623046875 0.882238769531246 +1.633375 0.02392578125 0.203338623046875 0.882238769531246 +1.6335 0.02447509765625 0.208099365234375 0.882238769531246 +1.633625 0.0250244140625 0.212860107421875 0.882238769531246 +1.63375 0.0250244140625 0.212860107421875 0.882238769531246 +1.633875 0.025604248046875 0.21759033203125 0.882238769531246 +1.6340000000000002 0.025604248046875 0.21759033203125 0.882238769531246 +1.634125 0.026153564453125 0.2222900390625 0.882238769531246 +1.63425 0.026702880859375 0.226959228515625 0.882238769531246 +1.6343750000000002 0.026702880859375 0.226959228515625 0.882238769531246 +1.6345 0.027252197265625 0.231597900390625 0.882238769531246 +1.634625 0.027252197265625 0.231597900390625 0.882238769531246 +1.63475 0.027801513671875 0.236236572265625 0.882238769531246 +1.634875 0.0283203125 0.2408447265625 0.882238769531246 +1.635 0.0283203125 0.2408447265625 0.882238769531246 +1.635125 0.02886962890625 0.24542236328125 0.882238769531246 +1.63525 0.02886962890625 0.24542236328125 0.882238769531246 +1.635375 0.029388427734375 0.249969482421875 0.882238769531246 +1.6355 0.029937744140625 0.25445556640625 0.882238769531246 +1.635625 0.029937744140625 0.25445556640625 0.882238769531246 +1.63575 0.03045654296875 0.25897216796875 0.882238769531246 +1.635875 0.03045654296875 0.25897216796875 0.882238769531246 +1.6360000000000002 0.030975341796875 0.263427734375 0.882238769531246 +1.636125 0.031524658203125 0.267852783203125 0.882238769531246 +1.63625 0.031524658203125 0.267852783203125 0.882238769531246 +1.6363750000000002 0.03204345703125 0.27227783203125 0.882238769531246 +1.6365 0.03204345703125 0.27227783203125 0.882238769531246 +1.636625 0.03253173828125 0.276641845703125 0.882238769531246 +1.63675 0.033050537109375 0.280975341796875 0.882238769531246 +1.636875 0.033050537109375 0.280975341796875 0.882238769531246 +1.637 0.0335693359375 0.285308837890625 0.882238769531246 +1.637125 0.0335693359375 0.285308837890625 0.882238769531246 +1.63725 0.0340576171875 0.289581298828125 0.882238769531246 +1.637375 0.034576416015625 0.2938232421875 0.882238769531246 +1.6375 0.034576416015625 0.2938232421875 0.882238769531246 +1.637625 0.035064697265625 0.298065185546875 0.882238769531246 +1.63775 0.035064697265625 0.298065185546875 0.882238769531246 +1.637875 0.035552978515625 0.30224609375 0.882238769531246 +1.6380000000000002 0.036041259765625 0.306396484375 0.882238769531246 +1.638125 0.036041259765625 0.306396484375 0.882238769531246 +1.63825 0.036529541015625 0.310516357421875 0.882238769531246 +1.6383750000000002 0.036529541015625 0.310516357421875 0.882238769531246 +1.6385 0.037017822265625 0.314605712890625 0.882238769531246 +1.638625 0.0374755859375 0.31866455078125 0.882238769531246 +1.63875 0.0374755859375 0.31866455078125 0.882238769531246 +1.638875 0.0379638671875 0.322662353515625 0.882238769531246 +1.639 0.0379638671875 0.322662353515625 0.882238769531246 +1.639125 0.038421630859375 0.32666015625 0.882238769531246 +1.63925 0.03887939453125 0.330596923828125 0.882238769531246 +1.639375 0.03887939453125 0.330596923828125 0.882238769531246 +1.6395 0.03936767578125 0.334503173828125 0.882238769531246 +1.639625 0.03936767578125 0.334503173828125 0.882238769531246 +1.63975 0.039794921875 0.33837890625 0.882238769531246 +1.639875 0.040252685546875 0.34222412109375 0.882238769531246 +1.6400000000000002 0.040252685546875 0.34222412109375 0.882238769531246 +1.640125 0.04071044921875 0.34600830078125 0.882238769531246 +1.64025 0.04071044921875 0.34600830078125 0.882238769531246 +1.6403750000000002 0.0411376953125 0.349761962890625 0.882238769531246 +1.6405 0.041595458984375 0.353485107421875 0.882238769531246 +1.640625 0.041595458984375 0.353485107421875 0.882238769531246 +1.64075 0.042022705078125 0.357177734375 0.882238769531246 +1.640875 0.042022705078125 0.357177734375 0.882238769531246 +1.641 0.042449951171875 0.360809326171875 0.882238769531246 +1.641125 0.042877197265625 0.36444091796875 0.882238769531246 +1.64125 0.042877197265625 0.36444091796875 0.882238769531246 +1.641375 0.043304443359375 0.36798095703125 0.882238769531246 +1.6415 0.043304443359375 0.36798095703125 0.882238769531246 +1.6416250000000002 0.043701171875 0.37152099609375 0.882238769531246 +1.64175 0.04412841796875 0.375 0.882238769531246 +1.641875 0.04412841796875 0.375 0.882238769531246 +1.6420000000000002 0.044525146484375 0.378448486328125 0.882238769531246 +1.642125 0.044525146484375 0.378448486328125 0.882238769531246 +1.64225 0.044921875 0.3818359375 0.882238769531246 +1.6423750000000002 0.045318603515625 0.38519287109375 0.882238769531246 +1.6425 0.045318603515625 0.38519287109375 0.882238769531246 +1.642625 0.04571533203125 0.388519287109375 0.882238769531246 +1.64275 0.04571533203125 0.388519287109375 0.882238769531246 +1.642875 0.04608154296875 0.39178466796875 0.882238769531246 +1.643 0.046478271484375 0.39501953125 0.882238769531246 +1.643125 0.046478271484375 0.39501953125 0.882238769531246 +1.64325 0.046844482421875 0.398193359375 0.882238769531246 +1.643375 0.046844482421875 0.398193359375 0.882238769531246 +1.6435 0.047210693359375 0.401336669921875 0.882238769531246 +1.6436250000000002 0.047576904296875 0.404449462890625 0.882238769531246 +1.64375 0.047576904296875 0.404449462890625 0.882238769531246 +1.643875 0.047943115234375 0.407501220703125 0.882238769531246 +1.6440000000000002 0.047943115234375 0.407501220703125 0.882238769531246 +1.644125 0.048309326171875 0.4105224609375 0.882238769531246 +1.64425 0.04864501953125 0.413482666015625 0.882238769531246 +1.6443750000000002 0.04864501953125 0.413482666015625 0.882238769531246 +1.6445 0.048980712890625 0.416412353515625 0.882238769531246 +1.644625 0.048980712890625 0.416412353515625 0.882238769531246 +1.64475 0.04931640625 0.419281005859375 0.882238769531246 +1.644875 0.049652099609375 0.422119140625 0.882238769531246 +1.645 0.049652099609375 0.422119140625 0.882238769531246 +1.645125 0.04998779296875 0.424896240234375 0.882238769531246 +1.64525 0.04998779296875 0.424896240234375 0.882238769531246 +1.645375 0.050323486328125 0.4276123046875 0.882238769531246 +1.6455 0.050628662109375 0.4302978515625 0.882238769531246 +1.6456250000000002 0.050628662109375 0.4302978515625 0.882238769531246 +1.64575 0.050933837890625 0.432952880859375 0.882238769531246 +1.645875 0.050933837890625 0.432952880859375 0.882238769531246 +1.6460000000000002 0.051239013671875 0.435546875 0.882238769531246 +1.646125 0.051544189453125 0.438079833984375 0.882238769531246 +1.64625 0.051544189453125 0.438079833984375 0.882238769531246 +1.6463750000000002 0.051849365234375 0.440582275390625 0.882238769531246 +1.6465 0.051849365234375 0.440582275390625 0.882238769531246 +1.646625 0.0521240234375 0.44305419921875 0.882238769531246 +1.64675 0.052398681640625 0.4454345703125 0.882238769531246 +1.646875 0.052398681640625 0.4454345703125 0.882238769531246 +1.647 0.05267333984375 0.447784423828125 0.882238769531246 +1.647125 0.05267333984375 0.447784423828125 0.882238769531246 +1.64725 0.052947998046875 0.450103759765625 0.882238769531246 +1.647375 0.05322265625 0.452362060546875 0.882238769531246 +1.6475 0.05322265625 0.452362060546875 0.882238769531246 +1.6476250000000002 0.053466796875 0.454559326171875 0.882238769531246 +1.64775 0.053466796875 0.454559326171875 0.882238769531246 +1.647875 0.053741455078125 0.45672607421875 0.882238769531246 +1.6480000000000002 0.053985595703125 0.458831787109375 0.882238769531246 +1.648125 0.053985595703125 0.458831787109375 0.882238769531246 +1.64825 0.054229736328125 0.46087646484375 0.882238769531246 +1.648375 0.054229736328125 0.46087646484375 0.882238769531246 +1.6485 0.054473876953125 0.462890625 0.882238769531246 +1.648625 0.0546875 0.464813232421875 0.882238769531246 +1.64875 0.0546875 0.464813232421875 0.882238769531246 +1.648875 0.054901123046875 0.46673583984375 0.882238769531246 +1.649 0.054901123046875 0.46673583984375 0.882238769531246 +1.649125 0.05511474609375 0.46856689453125 0.882238769531246 +1.64925 0.055328369140625 0.470367431640625 0.882238769531246 +1.649375 0.055328369140625 0.470367431640625 0.882238769531246 +1.6495 0.0555419921875 0.472137451171875 0.882238769531246 +1.6496250000000002 0.0555419921875 0.472137451171875 0.882238769531246 +1.64975 0.055755615234375 0.47381591796875 0.882238769531246 +1.649875 0.055938720703125 0.4754638671875 0.882238769531246 +1.6500000000000002 0.055938720703125 0.4754638671875 0.882238769531246 +1.650125 0.056121826171875 0.47705078125 0.882238769531246 +1.65025 0.056121826171875 0.47705078125 0.882238769531246 +1.650375 0.056304931640625 0.478607177734375 0.882238769531246 +1.6505 0.056488037109375 0.480072021484375 0.882238769531246 +1.650625 0.056488037109375 0.480072021484375 0.882238769531246 +1.65075 0.056640625 0.48150634765625 0.882238769531246 +1.650875 0.056640625 0.48150634765625 0.882238769531246 +1.651 0.05682373046875 0.48291015625 0.882238769531246 +1.651125 0.056976318359375 0.484222412109375 0.882238769531246 +1.65125 0.056976318359375 0.484222412109375 0.882238769531246 +1.651375 0.05712890625 0.485504150390625 0.882238769531246 +1.6515 0.05712890625 0.485504150390625 0.882238769531246 +1.6516250000000002 0.0572509765625 0.486724853515625 0.882238769531246 +1.65175 0.057403564453125 0.487884521484375 0.882238769531246 +1.651875 0.057403564453125 0.487884521484375 0.882238769531246 +1.6520000000000002 0.057525634765625 0.489013671875 0.882238769531246 +1.652125 0.057525634765625 0.489013671875 0.882238769531246 +1.65225 0.057647705078125 0.490081787109375 0.882238769531246 +1.652375 0.057769775390625 0.4910888671875 0.882238769531246 +1.6525 0.057769775390625 0.4910888671875 0.882238769531246 +1.652625 0.057891845703125 0.492034912109375 0.882238769531246 +1.65275 0.057891845703125 0.492034912109375 0.882238769531246 +1.652875 0.0579833984375 0.492950439453125 0.882238769531246 +1.653 0.05810546875 0.4937744140625 0.882238769531246 +1.653125 0.05810546875 0.4937744140625 0.882238769531246 +1.65325 0.058197021484375 0.49456787109375 0.882238769531246 +1.653375 0.058197021484375 0.49456787109375 0.882238769531246 +1.6535 0.05828857421875 0.49530029296875 0.882238769531246 +1.6536250000000002 0.058349609375 0.496002197265625 0.882238769531246 +1.65375 0.058349609375 0.496002197265625 0.882238769531246 +1.653875 0.058441162109375 0.496612548828125 0.882238769531246 +1.6540000000000002 0.058441162109375 0.496612548828125 0.882238769531246 +1.654125 0.058502197265625 0.4971923828125 0.882238769531246 +1.65425 0.058563232421875 0.497711181640625 0.882238769531246 +1.654375 0.058563232421875 0.497711181640625 0.882238769531246 +1.6545 0.058624267578125 0.498199462890625 0.882238769531246 +1.654625 0.058624267578125 0.498199462890625 0.882238769531246 +1.65475 0.05865478515625 0.49859619140625 0.882238769531246 +1.654875 0.0587158203125 0.49896240234375 0.882238769531246 +1.655 0.0587158203125 0.49896240234375 0.882238769531246 +1.655125 0.058746337890625 0.499267578125 0.882238769531246 +1.65525 0.058746337890625 0.499267578125 0.882238769531246 +1.655375 0.05877685546875 0.49951171875 0.882238769531246 +1.6555 0.05877685546875 0.49969482421875 0.882238769531246 +1.6556250000000002 0.05877685546875 0.49969482421875 0.882238769531246 +1.65575 0.058807373046875 0.49981689453125 0.882238769531246 +1.655875 0.058807373046875 0.49981689453125 0.882238769531246 +1.6560000000000002 0.058807373046875 0.499908447265625 0.882238769531246 +1.656125 0.058807373046875 0.49993896484375 0.882238769531246 +1.65625 0.058807373046875 0.49993896484375 0.882238769531246 +1.656375 0.058807373046875 0.499908447265625 0.882238769531246 +1.6565 0.058807373046875 0.499908447265625 0.882238769531246 +1.656625 0.058807373046875 0.49981689453125 0.882238769531246 +1.65675 0.05877685546875 0.49969482421875 0.882238769531246 +1.656875 0.05877685546875 0.49969482421875 0.882238769531246 +1.657 0.05877685546875 0.49951171875 0.882238769531246 +1.657125 0.05877685546875 0.49951171875 0.882238769531246 +1.6572500000000002 0.058746337890625 0.499267578125 0.882238769531246 +1.657375 0.0587158203125 0.49896240234375 0.882238769531246 +1.6575 0.0587158203125 0.49896240234375 0.882238769531246 +1.6576250000000002 0.05865478515625 0.49859619140625 0.882238769531246 +1.65775 0.05865478515625 0.49859619140625 0.882238769531246 +1.657875 0.058624267578125 0.498199462890625 0.882238769531246 +1.6580000000000002 0.058563232421875 0.497711181640625 0.882238769531246 +1.658125 0.058563232421875 0.497711181640625 0.882238769531246 +1.65825 0.058502197265625 0.4971923828125 0.882238769531246 +1.658375 0.058502197265625 0.4971923828125 0.882238769531246 +1.6585 0.058441162109375 0.496612548828125 0.882238769531246 +1.658625 0.058349609375 0.496002197265625 0.882238769531246 +1.65875 0.058349609375 0.496002197265625 0.882238769531246 +1.658875 0.05828857421875 0.49530029296875 0.882238769531246 +1.659 0.05828857421875 0.49530029296875 0.882238769531246 +1.659125 0.058197021484375 0.49456787109375 0.882238769531246 +1.6592500000000002 0.05810546875 0.4937744140625 0.882238769531246 +1.659375 0.05810546875 0.4937744140625 0.882238769531246 +1.6595 0.0579833984375 0.492950439453125 0.882238769531246 +1.6596250000000002 0.0579833984375 0.492950439453125 0.882238769531246 +1.65975 0.057891845703125 0.492034912109375 0.882238769531246 +1.659875 0.057769775390625 0.4910888671875 0.882238769531246 +1.6600000000000002 0.057769775390625 0.4910888671875 0.882238769531246 +1.660125 0.057647705078125 0.490081787109375 0.882238769531246 +1.66025 0.057647705078125 0.490081787109375 0.882238769531246 +1.660375 0.057525634765625 0.489013671875 0.882238769531246 +1.6605 0.057403564453125 0.487884521484375 0.882238769531246 +1.660625 0.057403564453125 0.487884521484375 0.882238769531246 +1.66075 0.0572509765625 0.486724853515625 0.882238769531246 +1.660875 0.0572509765625 0.486724853515625 0.882238769531246 +1.661 0.05712890625 0.485504150390625 0.882238769531246 +1.661125 0.056976318359375 0.484222412109375 0.882238769531246 +1.6612500000000002 0.056976318359375 0.484222412109375 0.882238769531246 +1.661375 0.05682373046875 0.48291015625 0.882238769531246 +1.6615 0.05682373046875 0.48291015625 0.882238769531246 +1.6616250000000002 0.056640625 0.48150634765625 0.882238769531246 +1.66175 0.056488037109375 0.480072021484375 0.882238769531246 +1.661875 0.056488037109375 0.480072021484375 0.882238769531246 +1.6620000000000002 0.056304931640625 0.478607177734375 0.882238769531246 +1.662125 0.056304931640625 0.478607177734375 0.882238769531246 +1.66225 0.056121826171875 0.47705078125 0.882238769531246 +1.662375 0.055938720703125 0.4754638671875 0.882238769531246 +1.6625 0.055938720703125 0.4754638671875 0.882238769531246 +1.662625 0.055755615234375 0.47381591796875 0.882238769531246 +1.66275 0.055755615234375 0.47381591796875 0.882238769531246 +1.662875 0.0555419921875 0.472137451171875 0.882238769531246 +1.663 0.055328369140625 0.470367431640625 0.882238769531246 +1.663125 0.055328369140625 0.470367431640625 0.882238769531246 +1.6632500000000002 0.05511474609375 0.46856689453125 0.882238769531246 +1.663375 0.05511474609375 0.46856689453125 0.882238769531246 +1.6635 0.054901123046875 0.46673583984375 0.882238769531246 +1.6636250000000002 0.0546875 0.464813232421875 0.882238769531246 +1.66375 0.0546875 0.464813232421875 0.882238769531246 +1.663875 0.054473876953125 0.462890625 0.882238769531246 +1.6640000000000002 0.17230224609375 0.462890625 0.6276428222656184 +1.664125 0.17156982421875 0.46087646484375 0.6276428222656184 +1.66425 0.170806884765625 0.458831787109375 0.6276428222656184 +1.664375 0.170806884765625 0.458831787109375 0.6276428222656184 +1.6645 0.170013427734375 0.45672607421875 0.6276428222656184 +1.664625 0.170013427734375 0.45672607421875 0.6276428222656184 +1.66475 0.169219970703125 0.454559326171875 0.6276428222656184 +1.664875 0.16839599609375 0.452362060546875 0.6276428222656184 +1.665 0.16839599609375 0.452362060546875 0.6276428222656184 +1.665125 0.16754150390625 0.450103759765625 0.6276428222656184 +1.6652500000000002 0.16754150390625 0.450103759765625 0.6276428222656184 +1.665375 0.16668701171875 0.447784423828125 0.6276428222656184 +1.6655 0.165802001953125 0.4454345703125 0.6276428222656184 +1.6656250000000002 0.165802001953125 0.4454345703125 0.6276428222656184 +1.66575 0.1649169921875 0.44305419921875 0.6276428222656184 +1.665875 0.1649169921875 0.44305419921875 0.6276428222656184 +1.666 0.16400146484375 0.440582275390625 0.6276428222656184 +1.666125 0.1630859375 0.438079833984375 0.6276428222656184 +1.66625 0.1630859375 0.438079833984375 0.6276428222656184 +1.666375 0.162139892578125 0.435546875 0.6276428222656184 +1.6665 0.162139892578125 0.435546875 0.6276428222656184 +1.666625 0.161163330078125 0.432952880859375 0.6276428222656184 +1.66675 0.160186767578125 0.4302978515625 0.6276428222656184 +1.666875 0.160186767578125 0.4302978515625 0.6276428222656184 +1.667 0.1591796875 0.4276123046875 0.6276428222656184 +1.667125 0.1591796875 0.4276123046875 0.6276428222656184 +1.6672500000000002 0.158172607421875 0.424896240234375 0.6276428222656184 +1.667375 0.157135009765625 0.422119140625 0.6276428222656184 +1.6675 0.157135009765625 0.422119140625 0.6276428222656184 +1.6676250000000002 0.15606689453125 0.419281005859375 0.6276428222656184 +1.66775 0.15606689453125 0.419281005859375 0.6276428222656184 +1.667875 0.154998779296875 0.416412353515625 0.6276428222656184 +1.668 0.1539306640625 0.413482666015625 0.6276428222656184 +1.668125 0.1539306640625 0.413482666015625 0.6276428222656184 +1.66825 0.152801513671875 0.4105224609375 0.6276428222656184 +1.668375 0.152801513671875 0.4105224609375 0.6276428222656184 +1.6685 0.151702880859375 0.407501220703125 0.6276428222656184 +1.668625 0.15057373046875 0.404449462890625 0.6276428222656184 +1.66875 0.15057373046875 0.404449462890625 0.6276428222656184 +1.668875 0.1494140625 0.401336669921875 0.6276428222656184 +1.669 0.1494140625 0.401336669921875 0.6276428222656184 +1.669125 0.148223876953125 0.398193359375 0.6276428222656184 +1.6692500000000002 0.147064208984375 0.39501953125 0.6276428222656184 +1.669375 0.147064208984375 0.39501953125 0.6276428222656184 +1.6695 0.145843505859375 0.39178466796875 0.6276428222656184 +1.6696250000000002 0.145843505859375 0.39178466796875 0.6276428222656184 +1.66975 0.144622802734375 0.388519287109375 0.6276428222656184 +1.669875 0.143402099609375 0.38519287109375 0.6276428222656184 +1.67 0.143402099609375 0.38519287109375 0.6276428222656184 +1.670125 0.14215087890625 0.3818359375 0.6276428222656184 +1.67025 0.14215087890625 0.3818359375 0.6276428222656184 +1.670375 0.140869140625 0.378448486328125 0.6276428222656184 +1.6705 0.13958740234375 0.375 0.6276428222656184 +1.670625 0.13958740234375 0.375 0.6276428222656184 +1.67075 0.1383056640625 0.37152099609375 0.6276428222656184 +1.670875 0.1383056640625 0.37152099609375 0.6276428222656184 +1.671 0.136993408203125 0.36798095703125 0.6276428222656184 +1.671125 0.135650634765625 0.36444091796875 0.6276428222656184 +1.6712500000000002 0.135650634765625 0.36444091796875 0.6276428222656184 +1.671375 0.134307861328125 0.360809326171875 0.6276428222656184 +1.6715 0.134307861328125 0.360809326171875 0.6276428222656184 +1.6716250000000002 0.132965087890625 0.357177734375 0.6276428222656184 +1.67175 0.131591796875 0.353485107421875 0.6276428222656184 +1.671875 0.131591796875 0.353485107421875 0.6276428222656184 +1.672 0.13018798828125 0.349761962890625 0.6276428222656184 +1.672125 0.13018798828125 0.349761962890625 0.6276428222656184 +1.67225 0.128814697265625 0.34600830078125 0.6276428222656184 +1.672375 0.12738037109375 0.34222412109375 0.6276428222656184 +1.6725 0.12738037109375 0.34222412109375 0.6276428222656184 +1.672625 0.1259765625 0.33837890625 0.6276428222656184 +1.67275 0.1259765625 0.33837890625 0.6276428222656184 +1.6728750000000002 0.12451171875 0.334503173828125 0.6276428222656184 +1.673 0.123077392578125 0.330596923828125 0.6276428222656184 +1.673125 0.123077392578125 0.330596923828125 0.6276428222656184 +1.6732500000000002 0.12158203125 0.32666015625 0.6276428222656184 +1.673375 0.12158203125 0.32666015625 0.6276428222656184 +1.6735 0.1201171875 0.322662353515625 0.6276428222656184 +1.6736250000000002 0.118621826171875 0.31866455078125 0.6276428222656184 +1.67375 0.118621826171875 0.31866455078125 0.6276428222656184 +1.673875 0.117095947265625 0.314605712890625 0.6276428222656184 +1.674 0.117095947265625 0.314605712890625 0.6276428222656184 +1.674125 0.1156005859375 0.310516357421875 0.6276428222656184 +1.67425 0.114044189453125 0.306396484375 0.6276428222656184 +1.674375 0.114044189453125 0.306396484375 0.6276428222656184 +1.6745 0.112518310546875 0.30224609375 0.6276428222656184 +1.674625 0.112518310546875 0.30224609375 0.6276428222656184 +1.67475 0.1109619140625 0.298065185546875 0.6276428222656184 +1.6748750000000002 0.109375 0.2938232421875 0.6276428222656184 +1.675 0.109375 0.2938232421875 0.6276428222656184 +1.675125 0.1077880859375 0.289581298828125 0.6276428222656184 +1.6752500000000002 0.1077880859375 0.289581298828125 0.6276428222656184 +1.675375 0.106201171875 0.285308837890625 0.6276428222656184 +1.6755 0.104583740234375 0.280975341796875 0.6276428222656184 +1.6756250000000002 0.104583740234375 0.280975341796875 0.6276428222656184 +1.67575 0.10296630859375 0.276641845703125 0.6276428222656184 +1.675875 0.10296630859375 0.276641845703125 0.6276428222656184 +1.676 0.101348876953125 0.27227783203125 0.6276428222656184 +1.676125 0.099700927734375 0.267852783203125 0.6276428222656184 +1.67625 0.099700927734375 0.267852783203125 0.6276428222656184 +1.676375 0.098052978515625 0.263427734375 0.6276428222656184 +1.6765 0.098052978515625 0.263427734375 0.6276428222656184 +1.676625 0.096405029296875 0.25897216796875 0.6276428222656184 +1.67675 0.0947265625 0.25445556640625 0.6276428222656184 +1.6768750000000002 0.0947265625 0.25445556640625 0.6276428222656184 +1.677 0.093048095703125 0.249969482421875 0.6276428222656184 +1.677125 0.093048095703125 0.249969482421875 0.6276428222656184 +1.6772500000000002 0.091339111328125 0.24542236328125 0.6276428222656184 +1.677375 0.08966064453125 0.2408447265625 0.6276428222656184 +1.6775 0.08966064453125 0.2408447265625 0.6276428222656184 +1.6776250000000002 0.087921142578125 0.236236572265625 0.6276428222656184 +1.67775 0.087921142578125 0.236236572265625 0.6276428222656184 +1.677875 0.086212158203125 0.231597900390625 0.6276428222656184 +1.678 0.08447265625 0.226959228515625 0.6276428222656184 +1.678125 0.08447265625 0.226959228515625 0.6276428222656184 +1.67825 0.082733154296875 0.2222900390625 0.6276428222656184 +1.678375 0.082733154296875 0.2222900390625 0.6276428222656184 +1.6785 0.08099365234375 0.21759033203125 0.6276428222656184 +1.678625 0.0792236328125 0.212860107421875 0.6276428222656184 +1.67875 0.0792236328125 0.212860107421875 0.6276428222656184 +1.6788750000000002 0.07745361328125 0.208099365234375 0.6276428222656184 +1.679 0.07745361328125 0.208099365234375 0.6276428222656184 +1.679125 0.07568359375 0.203338623046875 0.6276428222656184 +1.6792500000000002 0.07391357421875 0.19854736328125 0.6276428222656184 +1.679375 0.07391357421875 0.19854736328125 0.6276428222656184 +1.6795 0.072113037109375 0.1937255859375 0.6276428222656184 +1.6796250000000002 0.072113037109375 0.1937255859375 0.6276428222656184 +1.67975 0.0703125 0.188873291015625 0.6276428222656184 +1.679875 0.068511962890625 0.18402099609375 0.6276428222656184 +1.68 0.068511962890625 0.18402099609375 0.6276428222656184 +1.680125 0.066680908203125 0.17913818359375 0.6276428222656184 +1.68025 0.066680908203125 0.17913818359375 0.6276428222656184 +1.680375 0.064849853515625 0.17425537109375 0.6276428222656184 +1.6805 0.063018798828125 0.169342041015625 0.6276428222656184 +1.680625 0.063018798828125 0.169342041015625 0.6276428222656184 +1.68075 0.061187744140625 0.164398193359375 0.6276428222656184 +1.6808750000000002 0.061187744140625 0.164398193359375 0.6276428222656184 +1.681 0.059356689453125 0.159454345703125 0.6276428222656184 +1.681125 0.0574951171875 0.15447998046875 0.6276428222656184 +1.6812500000000002 0.0574951171875 0.15447998046875 0.6276428222656184 +1.681375 0.055633544921875 0.14947509765625 0.6276428222656184 +1.6815 0.055633544921875 0.14947509765625 0.6276428222656184 +1.681625 0.05377197265625 0.14447021484375 0.6276428222656184 +1.68175 0.051910400390625 0.13946533203125 0.6276428222656184 +1.681875 0.051910400390625 0.13946533203125 0.6276428222656184 +1.682 0.050018310546875 0.134429931640625 0.6276428222656184 +1.682125 0.050018310546875 0.134429931640625 0.6276428222656184 +1.68225 0.04815673828125 0.129364013671875 0.6276428222656184 +1.682375 0.0462646484375 0.124298095703125 0.6276428222656184 +1.6825 0.0462646484375 0.124298095703125 0.6276428222656184 +1.682625 0.04437255859375 0.119232177734375 0.6276428222656184 +1.68275 0.04437255859375 0.119232177734375 0.6276428222656184 +1.6828750000000002 0.04248046875 0.1141357421875 0.6276428222656184 +1.683 0.04058837890625 0.109039306640625 0.6276428222656184 +1.683125 0.04058837890625 0.109039306640625 0.6276428222656184 +1.6832500000000002 0.038665771484375 0.103912353515625 0.6276428222656184 +1.683375 0.038665771484375 0.103912353515625 0.6276428222656184 +1.6835 0.036773681640625 0.098785400390625 0.6276428222656184 +1.683625 0.03485107421875 0.093658447265625 0.6276428222656184 +1.68375 0.03485107421875 0.093658447265625 0.6276428222656184 +1.683875 0.032928466796875 0.0885009765625 0.6276428222656184 +1.684 0.032928466796875 0.0885009765625 0.6276428222656184 +1.684125 0.031005859375 0.083343505859375 0.6276428222656184 +1.68425 0.029083251953125 0.07818603515625 0.6276428222656184 +1.684375 0.029083251953125 0.07818603515625 0.6276428222656184 +1.6845 0.02716064453125 0.072998046875 0.6276428222656184 +1.684625 0.02716064453125 0.072998046875 0.6276428222656184 +1.68475 0.025238037109375 0.06781005859375 0.6276428222656184 +1.6848750000000002 0.0233154296875 0.0626220703125 0.6276428222656184 +1.685 0.0233154296875 0.0626220703125 0.6276428222656184 +1.685125 0.0213623046875 0.05743408203125 0.6276428222656184 +1.6852500000000002 0.0213623046875 0.05743408203125 0.6276428222656184 +1.685375 0.019439697265625 0.05224609375 0.6276428222656184 +1.6855 0.017486572265625 0.047027587890625 0.6276428222656184 +1.685625 0.017486572265625 0.047027587890625 0.6276428222656184 +1.68575 0.01556396484375 0.04180908203125 0.6276428222656184 +1.685875 0.01556396484375 0.04180908203125 0.6276428222656184 +1.686 0.01361083984375 0.036590576171875 0.6276428222656184 +1.686125 0.01165771484375 0.0313720703125 0.6276428222656184 +1.68625 0.01165771484375 0.0313720703125 0.6276428222656184 +1.686375 0.009735107421875 0.026123046875 0.6276428222656184 +1.6865 0.009735107421875 0.026123046875 0.6276428222656184 +1.686625 0.007781982421875 0.020904541015625 0.6276428222656184 +1.68675 0.005828857421875 0.01568603515625 0.6276428222656184 +1.6868750000000002 0.005828857421875 0.01568603515625 0.6276428222656184 +1.687 0.003875732421875 0.01043701171875 0.6276428222656184 +1.687125 0.003875732421875 0.01043701171875 0.6276428222656184 +1.6872500000000002 0.001922607421875 0.005218505859375 0.6276428222656184 +1.687375 0.0 0.0 0.6276428222656184 +1.6875 0.0 0.0 0.6276428222656184 +1.687625 -0.001922607421875 -0.005218505859375 0.6276428222656184 +1.68775 -0.001922607421875 -0.005218505859375 0.6276428222656184 +1.687875 -0.003875732421875 -0.01043701171875 0.6276428222656184 +1.688 -0.005828857421875 -0.01568603515625 0.6276428222656184 +1.688125 -0.005828857421875 -0.01568603515625 0.6276428222656184 +1.68825 -0.007781982421875 -0.020904541015625 0.6276428222656184 +1.688375 -0.007781982421875 -0.020904541015625 0.6276428222656184 +1.6885000000000002 -0.009735107421875 -0.026123046875 0.6276428222656184 +1.688625 -0.01165771484375 -0.0313720703125 0.6276428222656184 +1.68875 -0.01165771484375 -0.0313720703125 0.6276428222656184 +1.6888750000000002 -0.01361083984375 -0.036590576171875 0.6276428222656184 +1.689 -0.01361083984375 -0.036590576171875 0.6276428222656184 +1.689125 -0.01556396484375 -0.04180908203125 0.6276428222656184 +1.6892500000000002 -0.017486572265625 -0.047027587890625 0.6276428222656184 +1.689375 -0.017486572265625 -0.047027587890625 0.6276428222656184 +1.6895 -0.019439697265625 -0.05224609375 0.6276428222656184 +1.689625 -0.019439697265625 -0.05224609375 0.6276428222656184 +1.68975 -0.0213623046875 -0.05743408203125 0.6276428222656184 +1.689875 -0.0233154296875 -0.0626220703125 0.6276428222656184 +1.69 -0.0233154296875 -0.0626220703125 0.6276428222656184 +1.690125 -0.025238037109375 -0.06781005859375 0.6276428222656184 +1.69025 -0.025238037109375 -0.06781005859375 0.6276428222656184 +1.690375 -0.02716064453125 -0.072998046875 0.6276428222656184 +1.6905000000000002 -0.029083251953125 -0.07818603515625 0.6276428222656184 +1.690625 -0.029083251953125 -0.07818603515625 0.6276428222656184 +1.69075 -0.031005859375 -0.083343505859375 0.6276428222656184 +1.6908750000000002 -0.031005859375 -0.083343505859375 0.6276428222656184 +1.691 -0.032928466796875 -0.0885009765625 0.6276428222656184 +1.691125 -0.03485107421875 -0.093658447265625 0.6276428222656184 +1.6912500000000002 -0.03485107421875 -0.093658447265625 0.6276428222656184 +1.691375 -0.036773681640625 -0.098785400390625 0.6276428222656184 +1.6915 -0.036773681640625 -0.098785400390625 0.6276428222656184 +1.691625 -0.038665771484375 -0.103912353515625 0.6276428222656184 +1.69175 -0.04058837890625 -0.109039306640625 0.6276428222656184 +1.691875 -0.04058837890625 -0.109039306640625 0.6276428222656184 +1.692 -0.04248046875 -0.1141357421875 0.6276428222656184 +1.692125 -0.04248046875 -0.1141357421875 0.6276428222656184 +1.69225 -0.04437255859375 -0.119232177734375 0.6276428222656184 +1.692375 -0.0462646484375 -0.124298095703125 0.6276428222656184 +1.6925000000000002 -0.0462646484375 -0.124298095703125 0.6276428222656184 +1.692625 -0.04815673828125 -0.129364013671875 0.6276428222656184 +1.69275 -0.04815673828125 -0.129364013671875 0.6276428222656184 +1.6928750000000002 -0.050018310546875 -0.134429931640625 0.6276428222656184 +1.693 -0.051910400390625 -0.13946533203125 0.6276428222656184 +1.693125 -0.051910400390625 -0.13946533203125 0.6276428222656184 +1.6932500000000002 -0.05377197265625 -0.14447021484375 0.6276428222656184 +1.693375 -0.05377197265625 -0.14447021484375 0.6276428222656184 +1.6935 -0.055633544921875 -0.14947509765625 0.6276428222656184 +1.693625 -0.0574951171875 -0.15447998046875 0.6276428222656184 +1.69375 -0.0574951171875 -0.15447998046875 0.6276428222656184 +1.693875 -0.059356689453125 -0.159454345703125 0.6276428222656184 +1.694 -0.059356689453125 -0.159454345703125 0.6276428222656184 +1.694125 -0.061187744140625 -0.164398193359375 0.6276428222656184 +1.69425 -0.063018798828125 -0.169342041015625 0.6276428222656184 +1.694375 -0.063018798828125 -0.169342041015625 0.6276428222656184 +1.6945000000000002 -0.064849853515625 -0.17425537109375 0.6276428222656184 +1.694625 -0.064849853515625 -0.17425537109375 0.6276428222656184 +1.69475 -0.066680908203125 -0.17913818359375 0.6276428222656184 +1.6948750000000002 -0.068511962890625 -0.18402099609375 0.6276428222656184 +1.695 -0.068511962890625 -0.18402099609375 0.6276428222656184 +1.695125 -0.0703125 -0.188873291015625 0.6276428222656184 +1.6952500000000002 -0.0703125 -0.188873291015625 0.6276428222656184 +1.695375 -0.072113037109375 -0.1937255859375 0.6276428222656184 +1.6955 -0.07391357421875 -0.19854736328125 0.6276428222656184 +1.695625 -0.07391357421875 -0.19854736328125 0.6276428222656184 +1.69575 -0.07568359375 -0.203338623046875 0.6276428222656184 +1.695875 -0.07568359375 -0.203338623046875 0.6276428222656184 +1.696 -0.15130615234375 -0.208099365234375 0.2729187011718668 +1.696125 -0.154754638671875 -0.212860107421875 0.2729187011718668 +1.69625 -0.154754638671875 -0.212860107421875 0.2729187011718668 +1.696375 -0.158172607421875 -0.21759033203125 0.2729187011718668 +1.6965000000000002 -0.158172607421875 -0.21759033203125 0.2729187011718668 +1.696625 -0.161590576171875 -0.2222900390625 0.2729187011718668 +1.69675 -0.16497802734375 -0.226959228515625 0.2729187011718668 +1.6968750000000002 -0.16497802734375 -0.226959228515625 0.2729187011718668 +1.697 -0.168365478515625 -0.231597900390625 0.2729187011718668 +1.697125 -0.168365478515625 -0.231597900390625 0.2729187011718668 +1.69725 -0.1717529296875 -0.236236572265625 0.2729187011718668 +1.697375 -0.175079345703125 -0.2408447265625 0.2729187011718668 +1.6975 -0.175079345703125 -0.2408447265625 0.2729187011718668 +1.697625 -0.17840576171875 -0.24542236328125 0.2729187011718668 +1.69775 -0.17840576171875 -0.24542236328125 0.2729187011718668 +1.697875 -0.181732177734375 -0.249969482421875 0.2729187011718668 +1.698 -0.18499755859375 -0.25445556640625 0.2729187011718668 +1.698125 -0.18499755859375 -0.25445556640625 0.2729187011718668 +1.69825 -0.188262939453125 -0.25897216796875 0.2729187011718668 +1.698375 -0.188262939453125 -0.25897216796875 0.2729187011718668 +1.6985000000000002 -0.1915283203125 -0.263427734375 0.2729187011718668 +1.698625 -0.194732666015625 -0.267852783203125 0.2729187011718668 +1.69875 -0.194732666015625 -0.267852783203125 0.2729187011718668 +1.6988750000000002 -0.19793701171875 -0.27227783203125 0.2729187011718668 +1.699 -0.19793701171875 -0.27227783203125 0.2729187011718668 +1.699125 -0.20111083984375 -0.276641845703125 0.2729187011718668 +1.69925 -0.20428466796875 -0.280975341796875 0.2729187011718668 +1.699375 -0.20428466796875 -0.280975341796875 0.2729187011718668 +1.6995 -0.207427978515625 -0.285308837890625 0.2729187011718668 +1.699625 -0.207427978515625 -0.285308837890625 0.2729187011718668 +1.69975 -0.210540771484375 -0.289581298828125 0.2729187011718668 +1.699875 -0.213623046875 -0.2938232421875 0.2729187011718668 +1.7 -0.213623046875 -0.2938232421875 0.2729187011718668 +1.700125 -0.216705322265625 -0.298065185546875 0.2729187011718668 +1.70025 -0.216705322265625 -0.298065185546875 0.2729187011718668 +1.700375 -0.2197265625 -0.30224609375 0.2729187011718668 +1.7005000000000002 -0.2227783203125 -0.306396484375 0.2729187011718668 +1.700625 -0.2227783203125 -0.306396484375 0.2729187011718668 +1.70075 -0.22576904296875 -0.310516357421875 0.2729187011718668 +1.7008750000000002 -0.22576904296875 -0.310516357421875 0.2729187011718668 +1.701 -0.228729248046875 -0.314605712890625 0.2729187011718668 +1.701125 -0.231658935546875 -0.31866455078125 0.2729187011718668 +1.70125 -0.231658935546875 -0.31866455078125 0.2729187011718668 +1.701375 -0.234588623046875 -0.322662353515625 0.2729187011718668 +1.7015 -0.234588623046875 -0.322662353515625 0.2729187011718668 +1.701625 -0.23748779296875 -0.32666015625 0.2729187011718668 +1.70175 -0.2403564453125 -0.330596923828125 0.2729187011718668 +1.701875 -0.2403564453125 -0.330596923828125 0.2729187011718668 +1.702 -0.243194580078125 -0.334503173828125 0.2729187011718668 +1.702125 -0.243194580078125 -0.334503173828125 0.2729187011718668 +1.70225 -0.246002197265625 -0.33837890625 0.2729187011718668 +1.702375 -0.248809814453125 -0.34222412109375 0.2729187011718668 +1.7025000000000002 -0.248809814453125 -0.34222412109375 0.2729187011718668 +1.702625 -0.251556396484375 -0.34600830078125 0.2729187011718668 +1.70275 -0.251556396484375 -0.34600830078125 0.2729187011718668 +1.7028750000000002 -0.254302978515625 -0.349761962890625 0.2729187011718668 +1.703 -0.256988525390625 -0.353485107421875 0.2729187011718668 +1.703125 -0.256988525390625 -0.353485107421875 0.2729187011718668 +1.70325 -0.259674072265625 -0.357177734375 0.2729187011718668 +1.703375 -0.259674072265625 -0.357177734375 0.2729187011718668 +1.7035 -0.2623291015625 -0.360809326171875 0.2729187011718668 +1.703625 -0.26495361328125 -0.36444091796875 0.2729187011718668 +1.70375 -0.26495361328125 -0.36444091796875 0.2729187011718668 +1.703875 -0.267547607421875 -0.36798095703125 0.2729187011718668 +1.704 -0.267547607421875 -0.36798095703125 0.2729187011718668 +1.7041250000000002 -0.270111083984375 -0.37152099609375 0.2729187011718668 +1.70425 -0.272613525390625 -0.375 0.2729187011718668 +1.704375 -0.272613525390625 -0.375 0.2729187011718668 +1.7045000000000002 -0.275146484375 -0.378448486328125 0.2729187011718668 +1.704625 -0.275146484375 -0.378448486328125 0.2729187011718668 +1.70475 -0.277618408203125 -0.3818359375 0.2729187011718668 +1.7048750000000002 -0.280059814453125 -0.38519287109375 0.2729187011718668 +1.705 -0.280059814453125 -0.38519287109375 0.2729187011718668 +1.705125 -0.282470703125 -0.388519287109375 0.2729187011718668 +1.70525 -0.282470703125 -0.388519287109375 0.2729187011718668 +1.705375 -0.28485107421875 -0.39178466796875 0.2729187011718668 +1.7055 -0.287200927734375 -0.39501953125 0.2729187011718668 +1.705625 -0.287200927734375 -0.39501953125 0.2729187011718668 +1.70575 -0.28948974609375 -0.398193359375 0.2729187011718668 +1.705875 -0.28948974609375 -0.398193359375 0.2729187011718668 +1.706 -0.291778564453125 -0.401336669921875 0.2729187011718668 +1.7061250000000002 -0.294036865234375 -0.404449462890625 0.2729187011718668 +1.70625 -0.294036865234375 -0.404449462890625 0.2729187011718668 +1.706375 -0.2962646484375 -0.407501220703125 0.2729187011718668 +1.7065000000000002 -0.2962646484375 -0.407501220703125 0.2729187011718668 +1.706625 -0.2984619140625 -0.4105224609375 0.2729187011718668 +1.70675 -0.30059814453125 -0.413482666015625 0.2729187011718668 +1.7068750000000002 -0.30059814453125 -0.413482666015625 0.2729187011718668 +1.707 -0.302734375 -0.416412353515625 0.2729187011718668 +1.707125 -0.302734375 -0.416412353515625 0.2729187011718668 +1.70725 -0.3048095703125 -0.419281005859375 0.2729187011718668 +1.707375 -0.306884765625 -0.422119140625 0.2729187011718668 +1.7075 -0.306884765625 -0.422119140625 0.2729187011718668 +1.707625 -0.30889892578125 -0.424896240234375 0.2729187011718668 +1.70775 -0.30889892578125 -0.424896240234375 0.2729187011718668 +1.707875 -0.310882568359375 -0.4276123046875 0.2729187011718668 +1.708 -0.312835693359375 -0.4302978515625 0.2729187011718668 +1.7081250000000002 -0.312835693359375 -0.4302978515625 0.2729187011718668 +1.70825 -0.31475830078125 -0.432952880859375 0.2729187011718668 +1.708375 -0.31475830078125 -0.432952880859375 0.2729187011718668 +1.7085000000000002 -0.316650390625 -0.435546875 0.2729187011718668 +1.708625 -0.318511962890625 -0.438079833984375 0.2729187011718668 +1.70875 -0.318511962890625 -0.438079833984375 0.2729187011718668 +1.7088750000000002 -0.3203125 -0.440582275390625 0.2729187011718668 +1.709 -0.3203125 -0.440582275390625 0.2729187011718668 +1.709125 -0.322113037109375 -0.44305419921875 0.2729187011718668 +1.70925 -0.3238525390625 -0.4454345703125 0.2729187011718668 +1.709375 -0.3238525390625 -0.4454345703125 0.2729187011718668 +1.7095 -0.3255615234375 -0.447784423828125 0.2729187011718668 +1.709625 -0.3255615234375 -0.447784423828125 0.2729187011718668 +1.70975 -0.327239990234375 -0.450103759765625 0.2729187011718668 +1.709875 -0.328857421875 -0.452362060546875 0.2729187011718668 +1.71 -0.328857421875 -0.452362060546875 0.2729187011718668 +1.7101250000000002 -0.330474853515625 -0.454559326171875 0.2729187011718668 +1.71025 -0.330474853515625 -0.454559326171875 0.2729187011718668 +1.710375 -0.33203125 -0.45672607421875 0.2729187011718668 +1.7105000000000002 -0.333587646484375 -0.458831787109375 0.2729187011718668 +1.710625 -0.333587646484375 -0.458831787109375 0.2729187011718668 +1.71075 -0.335052490234375 -0.46087646484375 0.2729187011718668 +1.7108750000000002 -0.335052490234375 -0.46087646484375 0.2729187011718668 +1.711 -0.336517333984375 -0.462890625 0.2729187011718668 +1.711125 -0.337921142578125 -0.464813232421875 0.2729187011718668 +1.71125 -0.337921142578125 -0.464813232421875 0.2729187011718668 +1.711375 -0.339324951171875 -0.46673583984375 0.2729187011718668 +1.7115 -0.339324951171875 -0.46673583984375 0.2729187011718668 +1.711625 -0.340667724609375 -0.46856689453125 0.2729187011718668 +1.71175 -0.34197998046875 -0.470367431640625 0.2729187011718668 +1.711875 -0.34197998046875 -0.470367431640625 0.2729187011718668 +1.712 -0.343231201171875 -0.472137451171875 0.2729187011718668 +1.7121250000000002 -0.343231201171875 -0.472137451171875 0.2729187011718668 +1.71225 -0.344482421875 -0.47381591796875 0.2729187011718668 +1.712375 -0.345672607421875 -0.4754638671875 0.2729187011718668 +1.7125000000000002 -0.345672607421875 -0.4754638671875 0.2729187011718668 +1.712625 -0.346832275390625 -0.47705078125 0.2729187011718668 +1.71275 -0.346832275390625 -0.47705078125 0.2729187011718668 +1.712875 -0.34796142578125 -0.478607177734375 0.2729187011718668 +1.713 -0.349029541015625 -0.480072021484375 0.2729187011718668 +1.713125 -0.349029541015625 -0.480072021484375 0.2729187011718668 +1.71325 -0.350067138671875 -0.48150634765625 0.2729187011718668 +1.713375 -0.350067138671875 -0.48150634765625 0.2729187011718668 +1.7135 -0.35107421875 -0.48291015625 0.2729187011718668 +1.713625 -0.35205078125 -0.484222412109375 0.2729187011718668 +1.71375 -0.35205078125 -0.484222412109375 0.2729187011718668 +1.713875 -0.35296630859375 -0.485504150390625 0.2729187011718668 +1.714 -0.35296630859375 -0.485504150390625 0.2729187011718668 +1.7141250000000002 -0.353851318359375 -0.486724853515625 0.2729187011718668 +1.71425 -0.354705810546875 -0.487884521484375 0.2729187011718668 +1.714375 -0.354705810546875 -0.487884521484375 0.2729187011718668 +1.7145000000000002 -0.35552978515625 -0.489013671875 0.2729187011718668 +1.714625 -0.35552978515625 -0.489013671875 0.2729187011718668 +1.71475 -0.356292724609375 -0.490081787109375 0.2729187011718668 +1.714875 -0.357025146484375 -0.4910888671875 0.2729187011718668 +1.715 -0.357025146484375 -0.4910888671875 0.2729187011718668 +1.715125 -0.35772705078125 -0.492034912109375 0.2729187011718668 +1.71525 -0.35772705078125 -0.492034912109375 0.2729187011718668 +1.715375 -0.358367919921875 -0.492950439453125 0.2729187011718668 +1.7155 -0.358978271484375 -0.4937744140625 0.2729187011718668 +1.715625 -0.358978271484375 -0.4937744140625 0.2729187011718668 +1.71575 -0.35955810546875 -0.49456787109375 0.2729187011718668 +1.715875 -0.35955810546875 -0.49456787109375 0.2729187011718668 +1.716 -0.360107421875 -0.49530029296875 0.2729187011718668 +1.7161250000000002 -0.360595703125 -0.496002197265625 0.2729187011718668 +1.71625 -0.360595703125 -0.496002197265625 0.2729187011718668 +1.716375 -0.361053466796875 -0.496612548828125 0.2729187011718668 +1.7165000000000002 -0.361053466796875 -0.496612548828125 0.2729187011718668 +1.716625 -0.361480712890625 -0.4971923828125 0.2729187011718668 +1.71675 -0.361846923828125 -0.497711181640625 0.2729187011718668 +1.716875 -0.361846923828125 -0.497711181640625 0.2729187011718668 +1.717 -0.3621826171875 -0.498199462890625 0.2729187011718668 +1.717125 -0.3621826171875 -0.498199462890625 0.2729187011718668 +1.71725 -0.36248779296875 -0.49859619140625 0.2729187011718668 +1.717375 -0.362762451171875 -0.49896240234375 0.2729187011718668 +1.7175 -0.362762451171875 -0.49896240234375 0.2729187011718668 +1.717625 -0.36297607421875 -0.499267578125 0.2729187011718668 +1.71775 -0.36297607421875 -0.499267578125 0.2729187011718668 +1.717875 -0.3631591796875 -0.49951171875 0.2729187011718668 +1.718 -0.36328125 -0.49969482421875 0.2729187011718668 +1.7181250000000002 -0.36328125 -0.49969482421875 0.2729187011718668 +1.71825 -0.363372802734375 -0.49981689453125 0.2729187011718668 +1.718375 -0.363372802734375 -0.49981689453125 0.2729187011718668 +1.7185000000000002 -0.363433837890625 -0.499908447265625 0.2729187011718668 +1.718625 -0.36346435546875 -0.49993896484375 0.2729187011718668 +1.71875 -0.36346435546875 -0.49993896484375 0.2729187011718668 +1.718875 -0.363433837890625 -0.499908447265625 0.2729187011718668 +1.719 -0.363433837890625 -0.499908447265625 0.2729187011718668 +1.719125 -0.363372802734375 -0.49981689453125 0.2729187011718668 +1.71925 -0.36328125 -0.49969482421875 0.2729187011718668 +1.719375 -0.36328125 -0.49969482421875 0.2729187011718668 +1.7195 -0.3631591796875 -0.49951171875 0.2729187011718668 +1.719625 -0.3631591796875 -0.49951171875 0.2729187011718668 +1.7197500000000002 -0.36297607421875 -0.499267578125 0.2729187011718668 +1.719875 -0.362762451171875 -0.49896240234375 0.2729187011718668 +1.72 -0.362762451171875 -0.49896240234375 0.2729187011718668 +1.7201250000000002 -0.36248779296875 -0.49859619140625 0.2729187011718668 +1.72025 -0.36248779296875 -0.49859619140625 0.2729187011718668 +1.720375 -0.3621826171875 -0.498199462890625 0.2729187011718668 +1.7205000000000002 -0.361846923828125 -0.497711181640625 0.2729187011718668 +1.720625 -0.361846923828125 -0.497711181640625 0.2729187011718668 +1.72075 -0.361480712890625 -0.4971923828125 0.2729187011718668 +1.720875 -0.361480712890625 -0.4971923828125 0.2729187011718668 +1.721 -0.361053466796875 -0.496612548828125 0.2729187011718668 +1.721125 -0.360595703125 -0.496002197265625 0.2729187011718668 +1.72125 -0.360595703125 -0.496002197265625 0.2729187011718668 +1.721375 -0.360107421875 -0.49530029296875 0.2729187011718668 +1.7215 -0.360107421875 -0.49530029296875 0.2729187011718668 +1.721625 -0.35955810546875 -0.49456787109375 0.2729187011718668 +1.7217500000000002 -0.358978271484375 -0.4937744140625 0.2729187011718668 +1.721875 -0.358978271484375 -0.4937744140625 0.2729187011718668 +1.722 -0.358367919921875 -0.492950439453125 0.2729187011718668 +1.7221250000000002 -0.358367919921875 -0.492950439453125 0.2729187011718668 +1.72225 -0.35772705078125 -0.492034912109375 0.2729187011718668 +1.722375 -0.357025146484375 -0.4910888671875 0.2729187011718668 +1.7225000000000002 -0.357025146484375 -0.4910888671875 0.2729187011718668 +1.722625 -0.356292724609375 -0.490081787109375 0.2729187011718668 +1.72275 -0.356292724609375 -0.490081787109375 0.2729187011718668 +1.722875 -0.35552978515625 -0.489013671875 0.2729187011718668 +1.723 -0.354705810546875 -0.487884521484375 0.2729187011718668 +1.723125 -0.354705810546875 -0.487884521484375 0.2729187011718668 +1.72325 -0.353851318359375 -0.486724853515625 0.2729187011718668 +1.723375 -0.353851318359375 -0.486724853515625 0.2729187011718668 +1.7235 -0.35296630859375 -0.485504150390625 0.2729187011718668 +1.723625 -0.35205078125 -0.484222412109375 0.2729187011718668 +1.7237500000000002 -0.35205078125 -0.484222412109375 0.2729187011718668 +1.723875 -0.35107421875 -0.48291015625 0.2729187011718668 +1.724 -0.35107421875 -0.48291015625 0.2729187011718668 +1.7241250000000002 -0.350067138671875 -0.48150634765625 0.2729187011718668 +1.72425 -0.349029541015625 -0.480072021484375 0.2729187011718668 +1.724375 -0.349029541015625 -0.480072021484375 0.2729187011718668 +1.7245000000000002 -0.34796142578125 -0.478607177734375 0.2729187011718668 +1.724625 -0.34796142578125 -0.478607177734375 0.2729187011718668 +1.72475 -0.346832275390625 -0.47705078125 0.2729187011718668 +1.724875 -0.345672607421875 -0.4754638671875 0.2729187011718668 +1.725 -0.345672607421875 -0.4754638671875 0.2729187011718668 +1.725125 -0.344482421875 -0.47381591796875 0.2729187011718668 +1.72525 -0.344482421875 -0.47381591796875 0.2729187011718668 +1.725375 -0.343231201171875 -0.472137451171875 0.2729187011718668 +1.7255 -0.34197998046875 -0.470367431640625 0.2729187011718668 +1.725625 -0.34197998046875 -0.470367431640625 0.2729187011718668 +1.7257500000000002 -0.340667724609375 -0.46856689453125 0.2729187011718668 +1.725875 -0.340667724609375 -0.46856689453125 0.2729187011718668 +1.726 -0.339324951171875 -0.46673583984375 0.2729187011718668 +1.7261250000000002 -0.337921142578125 -0.464813232421875 0.2729187011718668 +1.72625 -0.337921142578125 -0.464813232421875 0.2729187011718668 +1.726375 -0.336517333984375 -0.462890625 0.2729187011718668 +1.7265000000000002 -0.336517333984375 -0.462890625 0.2729187011718668 +1.726625 -0.335052490234375 -0.46087646484375 0.2729187011718668 +1.72675 -0.333587646484375 -0.458831787109375 0.2729187011718668 +1.726875 -0.333587646484375 -0.458831787109375 0.2729187011718668 +1.727 -0.33203125 -0.45672607421875 0.2729187011718668 +1.727125 -0.33203125 -0.45672607421875 0.2729187011718668 +1.72725 -0.330474853515625 -0.454559326171875 0.2729187011718668 +1.727375 -0.328857421875 -0.452362060546875 0.2729187011718668 +1.7275 -0.328857421875 -0.452362060546875 0.2729187011718668 +1.727625 -0.327239990234375 -0.450103759765625 0.2729187011718668 +1.7277500000000002 -0.327239990234375 -0.450103759765625 0.2729187011718668 +1.727875 -0.3255615234375 -0.447784423828125 0.2729187011718668 +1.728 -0.4454345703125 -0.389617919921875 -0.12530517578125826 +1.7281250000000002 -0.4454345703125 -0.389617919921875 -0.12530517578125826 +1.72825 -0.44305419921875 -0.38751220703125 -0.12530517578125826 +1.728375 -0.44305419921875 -0.38751220703125 -0.12530517578125826 +1.7285 -0.440582275390625 -0.385345458984375 -0.12530517578125826 +1.728625 -0.438079833984375 -0.3831787109375 -0.12530517578125826 +1.72875 -0.438079833984375 -0.3831787109375 -0.12530517578125826 +1.728875 -0.435546875 -0.380950927734375 -0.12530517578125826 +1.729 -0.435546875 -0.380950927734375 -0.12530517578125826 +1.729125 -0.432952880859375 -0.378692626953125 -0.12530517578125826 +1.72925 -0.4302978515625 -0.376373291015625 -0.12530517578125826 +1.729375 -0.4302978515625 -0.376373291015625 -0.12530517578125826 +1.7295 -0.4276123046875 -0.3740234375 -0.12530517578125826 +1.729625 -0.4276123046875 -0.3740234375 -0.12530517578125826 +1.7297500000000002 -0.424896240234375 -0.371612548828125 -0.12530517578125826 +1.729875 -0.422119140625 -0.36920166015625 -0.12530517578125826 +1.73 -0.422119140625 -0.36920166015625 -0.12530517578125826 +1.7301250000000002 -0.419281005859375 -0.366729736328125 -0.12530517578125826 +1.73025 -0.419281005859375 -0.366729736328125 -0.12530517578125826 +1.730375 -0.416412353515625 -0.36419677734375 -0.12530517578125826 +1.7305 -0.413482666015625 -0.36163330078125 -0.12530517578125826 +1.730625 -0.413482666015625 -0.36163330078125 -0.12530517578125826 +1.73075 -0.4105224609375 -0.35906982421875 -0.12530517578125826 +1.730875 -0.4105224609375 -0.35906982421875 -0.12530517578125826 +1.731 -0.407501220703125 -0.356414794921875 -0.12530517578125826 +1.731125 -0.404449462890625 -0.353759765625 -0.12530517578125826 +1.73125 -0.404449462890625 -0.353759765625 -0.12530517578125826 +1.731375 -0.401336669921875 -0.351043701171875 -0.12530517578125826 +1.7315 -0.401336669921875 -0.351043701171875 -0.12530517578125826 +1.731625 -0.398193359375 -0.348297119140625 -0.12530517578125826 +1.7317500000000002 -0.39501953125 -0.34552001953125 -0.12530517578125826 +1.731875 -0.39501953125 -0.34552001953125 -0.12530517578125826 +1.732 -0.39178466796875 -0.342681884765625 -0.12530517578125826 +1.7321250000000002 -0.39178466796875 -0.342681884765625 -0.12530517578125826 +1.73225 -0.388519287109375 -0.339813232421875 -0.12530517578125826 +1.732375 -0.38519287109375 -0.3369140625 -0.12530517578125826 +1.7325 -0.38519287109375 -0.3369140625 -0.12530517578125826 +1.732625 -0.3818359375 -0.333984375 -0.12530517578125826 +1.73275 -0.3818359375 -0.333984375 -0.12530517578125826 +1.732875 -0.378448486328125 -0.33099365234375 -0.12530517578125826 +1.733 -0.375 -0.327972412109375 -0.12530517578125826 +1.733125 -0.375 -0.327972412109375 -0.12530517578125826 +1.73325 -0.37152099609375 -0.324951171875 -0.12530517578125826 +1.733375 -0.37152099609375 -0.324951171875 -0.12530517578125826 +1.7335 -0.36798095703125 -0.321868896484375 -0.12530517578125826 +1.733625 -0.36444091796875 -0.318756103515625 -0.12530517578125826 +1.7337500000000002 -0.36444091796875 -0.318756103515625 -0.12530517578125826 +1.733875 -0.360809326171875 -0.315582275390625 -0.12530517578125826 +1.734 -0.360809326171875 -0.315582275390625 -0.12530517578125826 +1.7341250000000002 -0.357177734375 -0.312408447265625 -0.12530517578125826 +1.73425 -0.353485107421875 -0.309173583984375 -0.12530517578125826 +1.734375 -0.353485107421875 -0.309173583984375 -0.12530517578125826 +1.7345 -0.349761962890625 -0.305938720703125 -0.12530517578125826 +1.734625 -0.349761962890625 -0.305938720703125 -0.12530517578125826 +1.73475 -0.34600830078125 -0.302642822265625 -0.12530517578125826 +1.734875 -0.34222412109375 -0.29931640625 -0.12530517578125826 +1.735 -0.34222412109375 -0.29931640625 -0.12530517578125826 +1.735125 -0.33837890625 -0.29595947265625 -0.12530517578125826 +1.73525 -0.33837890625 -0.29595947265625 -0.12530517578125826 +1.7353750000000002 -0.334503173828125 -0.292572021484375 -0.12530517578125826 +1.7355 -0.330596923828125 -0.289154052734375 -0.12530517578125826 +1.735625 -0.330596923828125 -0.289154052734375 -0.12530517578125826 +1.7357500000000002 -0.32666015625 -0.28570556640625 -0.12530517578125826 +1.735875 -0.32666015625 -0.28570556640625 -0.12530517578125826 +1.736 -0.322662353515625 -0.2822265625 -0.12530517578125826 +1.7361250000000002 -0.31866455078125 -0.278717041015625 -0.12530517578125826 +1.73625 -0.31866455078125 -0.278717041015625 -0.12530517578125826 +1.736375 -0.314605712890625 -0.275177001953125 -0.12530517578125826 +1.7365 -0.314605712890625 -0.275177001953125 -0.12530517578125826 +1.736625 -0.310516357421875 -0.2716064453125 -0.12530517578125826 +1.73675 -0.306396484375 -0.26800537109375 -0.12530517578125826 +1.736875 -0.306396484375 -0.26800537109375 -0.12530517578125826 +1.737 -0.30224609375 -0.26434326171875 -0.12530517578125826 +1.737125 -0.30224609375 -0.26434326171875 -0.12530517578125826 +1.73725 -0.298065185546875 -0.260711669921875 -0.12530517578125826 +1.7373750000000002 -0.2938232421875 -0.256988525390625 -0.12530517578125826 +1.7375 -0.2938232421875 -0.256988525390625 -0.12530517578125826 +1.737625 -0.289581298828125 -0.2532958984375 -0.12530517578125826 +1.7377500000000002 -0.289581298828125 -0.2532958984375 -0.12530517578125826 +1.737875 -0.285308837890625 -0.249542236328125 -0.12530517578125826 +1.738 -0.280975341796875 -0.245758056640625 -0.12530517578125826 +1.7381250000000002 -0.280975341796875 -0.245758056640625 -0.12530517578125826 +1.73825 -0.276641845703125 -0.241973876953125 -0.12530517578125826 +1.738375 -0.276641845703125 -0.241973876953125 -0.12530517578125826 +1.7385 -0.27227783203125 -0.2381591796875 -0.12530517578125826 +1.738625 -0.267852783203125 -0.234283447265625 -0.12530517578125826 +1.73875 -0.267852783203125 -0.234283447265625 -0.12530517578125826 +1.738875 -0.263427734375 -0.23040771484375 -0.12530517578125826 +1.739 -0.263427734375 -0.23040771484375 -0.12530517578125826 +1.739125 -0.25897216796875 -0.22650146484375 -0.12530517578125826 +1.73925 -0.25445556640625 -0.222564697265625 -0.12530517578125826 +1.7393750000000002 -0.25445556640625 -0.222564697265625 -0.12530517578125826 +1.7395 -0.249969482421875 -0.2186279296875 -0.12530517578125826 +1.739625 -0.249969482421875 -0.2186279296875 -0.12530517578125826 +1.7397500000000002 -0.24542236328125 -0.214630126953125 -0.12530517578125826 +1.739875 -0.2408447265625 -0.21063232421875 -0.12530517578125826 +1.74 -0.2408447265625 -0.21063232421875 -0.12530517578125826 +1.7401250000000002 -0.236236572265625 -0.206634521484375 -0.12530517578125826 +1.74025 -0.236236572265625 -0.206634521484375 -0.12530517578125826 +1.740375 -0.231597900390625 -0.20257568359375 -0.12530517578125826 +1.7405 -0.226959228515625 -0.198486328125 -0.12530517578125826 +1.740625 -0.226959228515625 -0.198486328125 -0.12530517578125826 +1.74075 -0.2222900390625 -0.194427490234375 -0.12530517578125826 +1.740875 -0.2222900390625 -0.194427490234375 -0.12530517578125826 +1.741 -0.21759033203125 -0.1903076171875 -0.12530517578125826 +1.741125 -0.212860107421875 -0.1861572265625 -0.12530517578125826 +1.74125 -0.212860107421875 -0.1861572265625 -0.12530517578125826 +1.7413750000000002 -0.208099365234375 -0.1820068359375 -0.12530517578125826 +1.7415 -0.208099365234375 -0.1820068359375 -0.12530517578125826 +1.741625 -0.203338623046875 -0.177825927734375 -0.12530517578125826 +1.7417500000000002 -0.19854736328125 -0.17364501953125 -0.12530517578125826 +1.741875 -0.19854736328125 -0.17364501953125 -0.12530517578125826 +1.742 -0.1937255859375 -0.16943359375 -0.12530517578125826 +1.7421250000000002 -0.1937255859375 -0.16943359375 -0.12530517578125826 +1.74225 -0.188873291015625 -0.165191650390625 -0.12530517578125826 +1.742375 -0.18402099609375 -0.16094970703125 -0.12530517578125826 +1.7425 -0.18402099609375 -0.16094970703125 -0.12530517578125826 +1.742625 -0.17913818359375 -0.15667724609375 -0.12530517578125826 +1.74275 -0.17913818359375 -0.15667724609375 -0.12530517578125826 +1.742875 -0.17425537109375 -0.15240478515625 -0.12530517578125826 +1.743 -0.169342041015625 -0.148101806640625 -0.12530517578125826 +1.743125 -0.169342041015625 -0.148101806640625 -0.12530517578125826 +1.74325 -0.164398193359375 -0.143768310546875 -0.12530517578125826 +1.7433750000000002 -0.164398193359375 -0.143768310546875 -0.12530517578125826 +1.7435 -0.159454345703125 -0.13946533203125 -0.12530517578125826 +1.743625 -0.15447998046875 -0.135101318359375 -0.12530517578125826 +1.7437500000000002 -0.15447998046875 -0.135101318359375 -0.12530517578125826 +1.743875 -0.14947509765625 -0.1307373046875 -0.12530517578125826 +1.744 -0.14947509765625 -0.1307373046875 -0.12530517578125826 +1.744125 -0.14447021484375 -0.126373291015625 -0.12530517578125826 +1.74425 -0.13946533203125 -0.121978759765625 -0.12530517578125826 +1.744375 -0.13946533203125 -0.121978759765625 -0.12530517578125826 +1.7445 -0.134429931640625 -0.117584228515625 -0.12530517578125826 +1.744625 -0.134429931640625 -0.117584228515625 -0.12530517578125826 +1.74475 -0.129364013671875 -0.1131591796875 -0.12530517578125826 +1.744875 -0.124298095703125 -0.108734130859375 -0.12530517578125826 +1.745 -0.124298095703125 -0.108734130859375 -0.12530517578125826 +1.745125 -0.119232177734375 -0.104278564453125 -0.12530517578125826 +1.74525 -0.119232177734375 -0.104278564453125 -0.12530517578125826 +1.7453750000000002 -0.1141357421875 -0.099822998046875 -0.12530517578125826 +1.7455 -0.109039306640625 -0.095367431640625 -0.12530517578125826 +1.745625 -0.109039306640625 -0.095367431640625 -0.12530517578125826 +1.7457500000000002 -0.103912353515625 -0.09088134765625 -0.12530517578125826 +1.745875 -0.103912353515625 -0.09088134765625 -0.12530517578125826 +1.746 -0.098785400390625 -0.086395263671875 -0.12530517578125826 +1.746125 -0.093658447265625 -0.0819091796875 -0.12530517578125826 +1.74625 -0.093658447265625 -0.0819091796875 -0.12530517578125826 +1.746375 -0.0885009765625 -0.077423095703125 -0.12530517578125826 +1.7465 -0.0885009765625 -0.077423095703125 -0.12530517578125826 +1.746625 -0.083343505859375 -0.072906494140625 -0.12530517578125826 +1.74675 -0.07818603515625 -0.068389892578125 -0.12530517578125826 +1.746875 -0.07818603515625 -0.068389892578125 -0.12530517578125826 +1.747 -0.072998046875 -0.0638427734375 -0.12530517578125826 +1.747125 -0.072998046875 -0.0638427734375 -0.12530517578125826 +1.74725 -0.06781005859375 -0.059326171875 -0.12530517578125826 +1.7473750000000002 -0.0626220703125 -0.054779052734375 -0.12530517578125826 +1.7475 -0.0626220703125 -0.054779052734375 -0.12530517578125826 +1.747625 -0.05743408203125 -0.05023193359375 -0.12530517578125826 +1.7477500000000002 -0.05743408203125 -0.05023193359375 -0.12530517578125826 +1.747875 -0.05224609375 -0.045684814453125 -0.12530517578125826 +1.748 -0.047027587890625 -0.0411376953125 -0.12530517578125826 +1.748125 -0.047027587890625 -0.0411376953125 -0.12530517578125826 +1.74825 -0.04180908203125 -0.03656005859375 -0.12530517578125826 +1.748375 -0.04180908203125 -0.03656005859375 -0.12530517578125826 +1.7485 -0.036590576171875 -0.032012939453125 -0.12530517578125826 +1.748625 -0.0313720703125 -0.027435302734375 -0.12530517578125826 +1.74875 -0.0313720703125 -0.027435302734375 -0.12530517578125826 +1.748875 -0.026123046875 -0.022857666015625 -0.12530517578125826 +1.749 -0.026123046875 -0.022857666015625 -0.12530517578125826 +1.749125 -0.020904541015625 -0.018280029296875 -0.12530517578125826 +1.74925 -0.01568603515625 -0.013702392578125 -0.12530517578125826 +1.7493750000000002 -0.01568603515625 -0.013702392578125 -0.12530517578125826 +1.7495 -0.01043701171875 -0.009124755859375 -0.12530517578125826 +1.749625 -0.01043701171875 -0.009124755859375 -0.12530517578125826 +1.7497500000000002 -0.005218505859375 -0.004547119140625 -0.12530517578125826 +1.749875 0.0 0.0 -0.12530517578125826 +1.75 0.0 0.0 -0.12530517578125826 +1.750125 0.005218505859375 0.004547119140625 -0.12530517578125826 +1.75025 0.005218505859375 0.004547119140625 -0.12530517578125826 +1.750375 0.01043701171875 0.009124755859375 -0.12530517578125826 +1.7505 0.01568603515625 0.013702392578125 -0.12530517578125826 +1.750625 0.01568603515625 0.013702392578125 -0.12530517578125826 +1.75075 0.020904541015625 0.018280029296875 -0.12530517578125826 +1.750875 0.020904541015625 0.018280029296875 -0.12530517578125826 +1.7510000000000002 0.026123046875 0.022857666015625 -0.12530517578125826 +1.751125 0.0313720703125 0.027435302734375 -0.12530517578125826 +1.75125 0.0313720703125 0.027435302734375 -0.12530517578125826 +1.7513750000000002 0.036590576171875 0.032012939453125 -0.12530517578125826 +1.7515 0.036590576171875 0.032012939453125 -0.12530517578125826 +1.751625 0.04180908203125 0.03656005859375 -0.12530517578125826 +1.7517500000000002 0.047027587890625 0.0411376953125 -0.12530517578125826 +1.751875 0.047027587890625 0.0411376953125 -0.12530517578125826 +1.752 0.05224609375 0.045684814453125 -0.12530517578125826 +1.752125 0.05224609375 0.045684814453125 -0.12530517578125826 +1.75225 0.05743408203125 0.05023193359375 -0.12530517578125826 +1.752375 0.0626220703125 0.054779052734375 -0.12530517578125826 +1.7525 0.0626220703125 0.054779052734375 -0.12530517578125826 +1.752625 0.06781005859375 0.059326171875 -0.12530517578125826 +1.75275 0.06781005859375 0.059326171875 -0.12530517578125826 +1.752875 0.072998046875 0.0638427734375 -0.12530517578125826 +1.7530000000000002 0.07818603515625 0.068389892578125 -0.12530517578125826 +1.753125 0.07818603515625 0.068389892578125 -0.12530517578125826 +1.75325 0.083343505859375 0.072906494140625 -0.12530517578125826 +1.7533750000000002 0.083343505859375 0.072906494140625 -0.12530517578125826 +1.7535 0.0885009765625 0.077423095703125 -0.12530517578125826 +1.753625 0.093658447265625 0.0819091796875 -0.12530517578125826 +1.7537500000000002 0.093658447265625 0.0819091796875 -0.12530517578125826 +1.753875 0.098785400390625 0.086395263671875 -0.12530517578125826 +1.754 0.098785400390625 0.086395263671875 -0.12530517578125826 +1.754125 0.103912353515625 0.09088134765625 -0.12530517578125826 +1.75425 0.109039306640625 0.095367431640625 -0.12530517578125826 +1.754375 0.109039306640625 0.095367431640625 -0.12530517578125826 +1.7545 0.1141357421875 0.099822998046875 -0.12530517578125826 +1.754625 0.1141357421875 0.099822998046875 -0.12530517578125826 +1.75475 0.119232177734375 0.104278564453125 -0.12530517578125826 +1.754875 0.124298095703125 0.108734130859375 -0.12530517578125826 +1.7550000000000002 0.124298095703125 0.108734130859375 -0.12530517578125826 +1.755125 0.129364013671875 0.1131591796875 -0.12530517578125826 +1.75525 0.129364013671875 0.1131591796875 -0.12530517578125826 +1.7553750000000002 0.134429931640625 0.117584228515625 -0.12530517578125826 +1.7555 0.13946533203125 0.121978759765625 -0.12530517578125826 +1.755625 0.13946533203125 0.121978759765625 -0.12530517578125826 +1.7557500000000002 0.14447021484375 0.126373291015625 -0.12530517578125826 +1.755875 0.14447021484375 0.126373291015625 -0.12530517578125826 +1.756 0.14947509765625 0.1307373046875 -0.12530517578125826 +1.756125 0.15447998046875 0.135101318359375 -0.12530517578125826 +1.75625 0.15447998046875 0.135101318359375 -0.12530517578125826 +1.756375 0.159454345703125 0.13946533203125 -0.12530517578125826 +1.7565 0.159454345703125 0.13946533203125 -0.12530517578125826 +1.756625 0.164398193359375 0.143768310546875 -0.12530517578125826 +1.75675 0.169342041015625 0.148101806640625 -0.12530517578125826 +1.756875 0.169342041015625 0.148101806640625 -0.12530517578125826 +1.7570000000000002 0.17425537109375 0.15240478515625 -0.12530517578125826 +1.757125 0.17425537109375 0.15240478515625 -0.12530517578125826 +1.75725 0.17913818359375 0.15667724609375 -0.12530517578125826 +1.7573750000000002 0.18402099609375 0.16094970703125 -0.12530517578125826 +1.7575 0.18402099609375 0.16094970703125 -0.12530517578125826 +1.757625 0.188873291015625 0.165191650390625 -0.12530517578125826 +1.7577500000000002 0.188873291015625 0.165191650390625 -0.12530517578125826 +1.757875 0.1937255859375 0.16943359375 -0.12530517578125826 +1.758 0.19854736328125 0.17364501953125 -0.12530517578125826 +1.758125 0.19854736328125 0.17364501953125 -0.12530517578125826 +1.75825 0.203338623046875 0.177825927734375 -0.12530517578125826 +1.758375 0.203338623046875 0.177825927734375 -0.12530517578125826 +1.7585 0.208099365234375 0.1820068359375 -0.12530517578125826 +1.758625 0.212860107421875 0.1861572265625 -0.12530517578125826 +1.75875 0.212860107421875 0.1861572265625 -0.12530517578125826 +1.758875 0.21759033203125 0.1903076171875 -0.12530517578125826 +1.7590000000000002 0.21759033203125 0.1903076171875 -0.12530517578125826 +1.759125 0.2222900390625 0.194427490234375 -0.12530517578125826 +1.75925 0.226959228515625 0.198486328125 -0.12530517578125826 +1.7593750000000002 0.226959228515625 0.198486328125 -0.12530517578125826 +1.7595 0.231597900390625 0.20257568359375 -0.12530517578125826 +1.759625 0.231597900390625 0.20257568359375 -0.12530517578125826 +1.7597500000000002 0.236236572265625 0.206634521484375 -0.12530517578125826 +1.759875 0.2408447265625 0.21063232421875 -0.12530517578125826 +1.76 0.2408447265625 0.119537353515625 -0.5035827636718825 +1.760125 0.24542236328125 0.121795654296875 -0.5035827636718825 +1.76025 0.24542236328125 0.121795654296875 -0.5035827636718825 +1.760375 0.249969482421875 0.124053955078125 -0.5035827636718825 +1.7605 0.25445556640625 0.126312255859375 -0.5035827636718825 +1.760625 0.25445556640625 0.126312255859375 -0.5035827636718825 +1.76075 0.25897216796875 0.1285400390625 -0.5035827636718825 +1.760875 0.25897216796875 0.1285400390625 -0.5035827636718825 +1.7610000000000002 0.263427734375 0.1307373046875 -0.5035827636718825 +1.761125 0.267852783203125 0.132965087890625 -0.5035827636718825 +1.76125 0.267852783203125 0.132965087890625 -0.5035827636718825 +1.7613750000000002 0.27227783203125 0.1351318359375 -0.5035827636718825 +1.7615 0.27227783203125 0.1351318359375 -0.5035827636718825 +1.761625 0.276641845703125 0.137298583984375 -0.5035827636718825 +1.76175 0.280975341796875 0.13946533203125 -0.5035827636718825 +1.761875 0.280975341796875 0.13946533203125 -0.5035827636718825 +1.762 0.285308837890625 0.1416015625 -0.5035827636718825 +1.762125 0.285308837890625 0.1416015625 -0.5035827636718825 +1.76225 0.289581298828125 0.14373779296875 -0.5035827636718825 +1.762375 0.2938232421875 0.145843505859375 -0.5035827636718825 +1.7625 0.2938232421875 0.145843505859375 -0.5035827636718825 +1.762625 0.298065185546875 0.14794921875 -0.5035827636718825 +1.76275 0.298065185546875 0.14794921875 -0.5035827636718825 +1.762875 0.30224609375 0.1500244140625 -0.5035827636718825 +1.7630000000000002 0.306396484375 0.152069091796875 -0.5035827636718825 +1.763125 0.306396484375 0.152069091796875 -0.5035827636718825 +1.76325 0.310516357421875 0.15411376953125 -0.5035827636718825 +1.7633750000000002 0.310516357421875 0.15411376953125 -0.5035827636718825 +1.7635 0.314605712890625 0.156158447265625 -0.5035827636718825 +1.763625 0.31866455078125 0.158172607421875 -0.5035827636718825 +1.76375 0.31866455078125 0.158172607421875 -0.5035827636718825 +1.763875 0.322662353515625 0.16015625 -0.5035827636718825 +1.764 0.322662353515625 0.16015625 -0.5035827636718825 +1.764125 0.32666015625 0.162139892578125 -0.5035827636718825 +1.76425 0.330596923828125 0.164093017578125 -0.5035827636718825 +1.764375 0.330596923828125 0.164093017578125 -0.5035827636718825 +1.7645 0.334503173828125 0.166046142578125 -0.5035827636718825 +1.764625 0.334503173828125 0.166046142578125 -0.5035827636718825 +1.76475 0.33837890625 0.16796875 -0.5035827636718825 +1.764875 0.34222412109375 0.16986083984375 -0.5035827636718825 +1.7650000000000002 0.34222412109375 0.16986083984375 -0.5035827636718825 +1.765125 0.34600830078125 0.1717529296875 -0.5035827636718825 +1.76525 0.34600830078125 0.1717529296875 -0.5035827636718825 +1.7653750000000002 0.349761962890625 0.173614501953125 -0.5035827636718825 +1.7655 0.353485107421875 0.175445556640625 -0.5035827636718825 +1.765625 0.353485107421875 0.175445556640625 -0.5035827636718825 +1.76575 0.357177734375 0.177276611328125 -0.5035827636718825 +1.765875 0.357177734375 0.177276611328125 -0.5035827636718825 +1.766 0.360809326171875 0.1790771484375 -0.5035827636718825 +1.766125 0.36444091796875 0.180877685546875 -0.5035827636718825 +1.76625 0.36444091796875 0.180877685546875 -0.5035827636718825 +1.766375 0.36798095703125 0.182647705078125 -0.5035827636718825 +1.7665 0.36798095703125 0.182647705078125 -0.5035827636718825 +1.7666250000000002 0.37152099609375 0.18438720703125 -0.5035827636718825 +1.76675 0.375 0.186126708984375 -0.5035827636718825 +1.766875 0.375 0.186126708984375 -0.5035827636718825 +1.7670000000000002 0.378448486328125 0.187835693359375 -0.5035827636718825 +1.767125 0.378448486328125 0.187835693359375 -0.5035827636718825 +1.76725 0.3818359375 0.18951416015625 -0.5035827636718825 +1.7673750000000002 0.38519287109375 0.191192626953125 -0.5035827636718825 +1.7675 0.38519287109375 0.191192626953125 -0.5035827636718825 +1.767625 0.388519287109375 0.192840576171875 -0.5035827636718825 +1.76775 0.388519287109375 0.192840576171875 -0.5035827636718825 +1.767875 0.39178466796875 0.1944580078125 -0.5035827636718825 +1.768 0.39501953125 0.196075439453125 -0.5035827636718825 +1.768125 0.39501953125 0.196075439453125 -0.5035827636718825 +1.76825 0.398193359375 0.1976318359375 -0.5035827636718825 +1.768375 0.398193359375 0.1976318359375 -0.5035827636718825 +1.7685 0.401336669921875 0.19921875 -0.5035827636718825 +1.7686250000000002 0.404449462890625 0.20074462890625 -0.5035827636718825 +1.76875 0.404449462890625 0.20074462890625 -0.5035827636718825 +1.768875 0.407501220703125 0.2022705078125 -0.5035827636718825 +1.7690000000000002 0.407501220703125 0.2022705078125 -0.5035827636718825 +1.769125 0.4105224609375 0.203765869140625 -0.5035827636718825 +1.76925 0.413482666015625 0.205230712890625 -0.5035827636718825 +1.7693750000000002 0.413482666015625 0.205230712890625 -0.5035827636718825 +1.7695 0.416412353515625 0.206695556640625 -0.5035827636718825 +1.769625 0.416412353515625 0.206695556640625 -0.5035827636718825 +1.76975 0.419281005859375 0.208099365234375 -0.5035827636718825 +1.769875 0.422119140625 0.209503173828125 -0.5035827636718825 +1.77 0.422119140625 0.209503173828125 -0.5035827636718825 +1.770125 0.424896240234375 0.210906982421875 -0.5035827636718825 +1.77025 0.424896240234375 0.210906982421875 -0.5035827636718825 +1.770375 0.4276123046875 0.212249755859375 -0.5035827636718825 +1.7705 0.4302978515625 0.213592529296875 -0.5035827636718825 +1.7706250000000002 0.4302978515625 0.213592529296875 -0.5035827636718825 +1.77075 0.432952880859375 0.21490478515625 -0.5035827636718825 +1.770875 0.432952880859375 0.21490478515625 -0.5035827636718825 +1.7710000000000002 0.435546875 0.2161865234375 -0.5035827636718825 +1.771125 0.438079833984375 0.217437744140625 -0.5035827636718825 +1.77125 0.438079833984375 0.217437744140625 -0.5035827636718825 +1.7713750000000002 0.440582275390625 0.21868896484375 -0.5035827636718825 +1.7715 0.440582275390625 0.21868896484375 -0.5035827636718825 +1.771625 0.44305419921875 0.21990966796875 -0.5035827636718825 +1.77175 0.4454345703125 0.221099853515625 -0.5035827636718825 +1.771875 0.4454345703125 0.221099853515625 -0.5035827636718825 +1.772 0.447784423828125 0.222259521484375 -0.5035827636718825 +1.772125 0.447784423828125 0.222259521484375 -0.5035827636718825 +1.77225 0.450103759765625 0.223388671875 -0.5035827636718825 +1.772375 0.452362060546875 0.224517822265625 -0.5035827636718825 +1.7725 0.452362060546875 0.224517822265625 -0.5035827636718825 +1.7726250000000002 0.454559326171875 0.225616455078125 -0.5035827636718825 +1.77275 0.454559326171875 0.225616455078125 -0.5035827636718825 +1.772875 0.45672607421875 0.2266845703125 -0.5035827636718825 +1.7730000000000002 0.458831787109375 0.22772216796875 -0.5035827636718825 +1.773125 0.458831787109375 0.22772216796875 -0.5035827636718825 +1.77325 0.46087646484375 0.228759765625 -0.5035827636718825 +1.7733750000000002 0.46087646484375 0.228759765625 -0.5035827636718825 +1.7735 0.462890625 0.229736328125 -0.5035827636718825 +1.773625 0.464813232421875 0.230712890625 -0.5035827636718825 +1.77375 0.464813232421875 0.230712890625 -0.5035827636718825 +1.773875 0.46673583984375 0.231658935546875 -0.5035827636718825 +1.774 0.46673583984375 0.231658935546875 -0.5035827636718825 +1.774125 0.46856689453125 0.232574462890625 -0.5035827636718825 +1.77425 0.470367431640625 0.23345947265625 -0.5035827636718825 +1.774375 0.470367431640625 0.23345947265625 -0.5035827636718825 +1.7745 0.472137451171875 0.234344482421875 -0.5035827636718825 +1.7746250000000002 0.472137451171875 0.234344482421875 -0.5035827636718825 +1.77475 0.47381591796875 0.23516845703125 -0.5035827636718825 +1.774875 0.4754638671875 0.235992431640625 -0.5035827636718825 +1.7750000000000002 0.4754638671875 0.235992431640625 -0.5035827636718825 +1.775125 0.47705078125 0.236785888671875 -0.5035827636718825 +1.77525 0.47705078125 0.236785888671875 -0.5035827636718825 +1.7753750000000002 0.478607177734375 0.237548828125 -0.5035827636718825 +1.7755 0.480072021484375 0.23828125 -0.5035827636718825 +1.775625 0.480072021484375 0.23828125 -0.5035827636718825 +1.77575 0.48150634765625 0.238983154296875 -0.5035827636718825 +1.775875 0.48150634765625 0.238983154296875 -0.5035827636718825 +1.776 0.48291015625 0.23968505859375 -0.5035827636718825 +1.776125 0.484222412109375 0.2403564453125 -0.5035827636718825 +1.77625 0.484222412109375 0.2403564453125 -0.5035827636718825 +1.776375 0.485504150390625 0.240966796875 -0.5035827636718825 +1.7765 0.485504150390625 0.240966796875 -0.5035827636718825 +1.7766250000000002 0.486724853515625 0.2415771484375 -0.5035827636718825 +1.77675 0.487884521484375 0.242156982421875 -0.5035827636718825 +1.776875 0.487884521484375 0.242156982421875 -0.5035827636718825 +1.7770000000000002 0.489013671875 0.242706298828125 -0.5035827636718825 +1.777125 0.489013671875 0.242706298828125 -0.5035827636718825 +1.77725 0.490081787109375 0.243255615234375 -0.5035827636718825 +1.777375 0.4910888671875 0.243743896484375 -0.5035827636718825 +1.7775 0.4910888671875 0.243743896484375 -0.5035827636718825 +1.777625 0.492034912109375 0.244232177734375 -0.5035827636718825 +1.77775 0.492034912109375 0.244232177734375 -0.5035827636718825 +1.777875 0.492950439453125 0.244659423828125 -0.5035827636718825 +1.778 0.4937744140625 0.245086669921875 -0.5035827636718825 +1.778125 0.4937744140625 0.245086669921875 -0.5035827636718825 +1.77825 0.49456787109375 0.2454833984375 -0.5035827636718825 +1.778375 0.49456787109375 0.2454833984375 -0.5035827636718825 +1.7785 0.49530029296875 0.245849609375 -0.5035827636718825 +1.7786250000000002 0.496002197265625 0.246185302734375 -0.5035827636718825 +1.77875 0.496002197265625 0.246185302734375 -0.5035827636718825 +1.778875 0.496612548828125 0.246490478515625 -0.5035827636718825 +1.7790000000000002 0.496612548828125 0.246490478515625 -0.5035827636718825 +1.779125 0.4971923828125 0.246795654296875 -0.5035827636718825 +1.77925 0.497711181640625 0.247039794921875 -0.5035827636718825 +1.779375 0.497711181640625 0.247039794921875 -0.5035827636718825 +1.7795 0.498199462890625 0.247283935546875 -0.5035827636718825 +1.779625 0.498199462890625 0.247283935546875 -0.5035827636718825 +1.77975 0.49859619140625 0.247467041015625 -0.5035827636718825 +1.779875 0.49896240234375 0.247650146484375 -0.5035827636718825 +1.78 0.49896240234375 0.247650146484375 -0.5035827636718825 +1.780125 0.499267578125 0.247802734375 -0.5035827636718825 +1.78025 0.499267578125 0.247802734375 -0.5035827636718825 +1.780375 0.49951171875 0.2479248046875 -0.5035827636718825 +1.7805 0.49969482421875 0.248016357421875 -0.5035827636718825 +1.7806250000000002 0.49969482421875 0.248016357421875 -0.5035827636718825 +1.78075 0.49981689453125 0.248077392578125 -0.5035827636718825 +1.780875 0.49981689453125 0.248077392578125 -0.5035827636718825 +1.7810000000000002 0.499908447265625 0.248138427734375 -0.5035827636718825 +1.781125 0.49993896484375 0.248138427734375 -0.5035827636718825 +1.78125 0.49993896484375 0.248138427734375 -0.5035827636718825 +1.781375 0.499908447265625 0.248138427734375 -0.5035827636718825 +1.7815 0.499908447265625 0.248138427734375 -0.5035827636718825 +1.781625 0.49981689453125 0.248077392578125 -0.5035827636718825 +1.78175 0.49969482421875 0.248016357421875 -0.5035827636718825 +1.781875 0.49969482421875 0.248016357421875 -0.5035827636718825 +1.782 0.49951171875 0.2479248046875 -0.5035827636718825 +1.782125 0.49951171875 0.2479248046875 -0.5035827636718825 +1.7822500000000002 0.499267578125 0.247802734375 -0.5035827636718825 +1.782375 0.49896240234375 0.247650146484375 -0.5035827636718825 +1.7825 0.49896240234375 0.247650146484375 -0.5035827636718825 +1.7826250000000002 0.49859619140625 0.247467041015625 -0.5035827636718825 +1.78275 0.49859619140625 0.247467041015625 -0.5035827636718825 +1.782875 0.498199462890625 0.247283935546875 -0.5035827636718825 +1.7830000000000002 0.497711181640625 0.247039794921875 -0.5035827636718825 +1.783125 0.497711181640625 0.247039794921875 -0.5035827636718825 +1.78325 0.4971923828125 0.246795654296875 -0.5035827636718825 +1.783375 0.4971923828125 0.246795654296875 -0.5035827636718825 +1.7835 0.496612548828125 0.246490478515625 -0.5035827636718825 +1.783625 0.496002197265625 0.246185302734375 -0.5035827636718825 +1.78375 0.496002197265625 0.246185302734375 -0.5035827636718825 +1.783875 0.49530029296875 0.245849609375 -0.5035827636718825 +1.784 0.49530029296875 0.245849609375 -0.5035827636718825 +1.784125 0.49456787109375 0.2454833984375 -0.5035827636718825 +1.7842500000000002 0.4937744140625 0.245086669921875 -0.5035827636718825 +1.784375 0.4937744140625 0.245086669921875 -0.5035827636718825 +1.7845 0.492950439453125 0.244659423828125 -0.5035827636718825 +1.7846250000000002 0.492950439453125 0.244659423828125 -0.5035827636718825 +1.78475 0.492034912109375 0.244232177734375 -0.5035827636718825 +1.784875 0.4910888671875 0.243743896484375 -0.5035827636718825 +1.7850000000000002 0.4910888671875 0.243743896484375 -0.5035827636718825 +1.785125 0.490081787109375 0.243255615234375 -0.5035827636718825 +1.78525 0.490081787109375 0.243255615234375 -0.5035827636718825 +1.785375 0.489013671875 0.242706298828125 -0.5035827636718825 +1.7855 0.487884521484375 0.242156982421875 -0.5035827636718825 +1.785625 0.487884521484375 0.242156982421875 -0.5035827636718825 +1.78575 0.486724853515625 0.2415771484375 -0.5035827636718825 +1.785875 0.486724853515625 0.2415771484375 -0.5035827636718825 +1.786 0.485504150390625 0.240966796875 -0.5035827636718825 +1.786125 0.484222412109375 0.2403564453125 -0.5035827636718825 +1.7862500000000002 0.484222412109375 0.2403564453125 -0.5035827636718825 +1.786375 0.48291015625 0.23968505859375 -0.5035827636718825 +1.7865 0.48291015625 0.23968505859375 -0.5035827636718825 +1.7866250000000002 0.48150634765625 0.238983154296875 -0.5035827636718825 +1.78675 0.480072021484375 0.23828125 -0.5035827636718825 +1.786875 0.480072021484375 0.23828125 -0.5035827636718825 +1.7870000000000002 0.478607177734375 0.237548828125 -0.5035827636718825 +1.787125 0.478607177734375 0.237548828125 -0.5035827636718825 +1.78725 0.47705078125 0.236785888671875 -0.5035827636718825 +1.787375 0.4754638671875 0.235992431640625 -0.5035827636718825 +1.7875 0.4754638671875 0.235992431640625 -0.5035827636718825 +1.787625 0.47381591796875 0.23516845703125 -0.5035827636718825 +1.78775 0.47381591796875 0.23516845703125 -0.5035827636718825 +1.787875 0.472137451171875 0.234344482421875 -0.5035827636718825 +1.788 0.470367431640625 0.23345947265625 -0.5035827636718825 +1.788125 0.470367431640625 0.23345947265625 -0.5035827636718825 +1.7882500000000002 0.46856689453125 0.232574462890625 -0.5035827636718825 +1.788375 0.46856689453125 0.232574462890625 -0.5035827636718825 +1.7885 0.46673583984375 0.231658935546875 -0.5035827636718825 +1.7886250000000002 0.464813232421875 0.230712890625 -0.5035827636718825 +1.78875 0.464813232421875 0.230712890625 -0.5035827636718825 +1.788875 0.462890625 0.229736328125 -0.5035827636718825 +1.7890000000000002 0.462890625 0.229736328125 -0.5035827636718825 +1.789125 0.46087646484375 0.228759765625 -0.5035827636718825 +1.78925 0.458831787109375 0.22772216796875 -0.5035827636718825 +1.789375 0.458831787109375 0.22772216796875 -0.5035827636718825 +1.7895 0.45672607421875 0.2266845703125 -0.5035827636718825 +1.789625 0.45672607421875 0.2266845703125 -0.5035827636718825 +1.78975 0.454559326171875 0.225616455078125 -0.5035827636718825 +1.789875 0.452362060546875 0.224517822265625 -0.5035827636718825 +1.79 0.452362060546875 0.224517822265625 -0.5035827636718825 +1.790125 0.450103759765625 0.223388671875 -0.5035827636718825 +1.7902500000000002 0.450103759765625 0.223388671875 -0.5035827636718825 +1.790375 0.447784423828125 0.222259521484375 -0.5035827636718825 +1.7905 0.4454345703125 0.221099853515625 -0.5035827636718825 +1.7906250000000002 0.4454345703125 0.221099853515625 -0.5035827636718825 +1.79075 0.44305419921875 0.21990966796875 -0.5035827636718825 +1.790875 0.44305419921875 0.21990966796875 -0.5035827636718825 +1.7910000000000002 0.440582275390625 0.21868896484375 -0.5035827636718825 +1.791125 0.438079833984375 0.217437744140625 -0.5035827636718825 +1.79125 0.438079833984375 0.217437744140625 -0.5035827636718825 +1.791375 0.435546875 0.2161865234375 -0.5035827636718825 +1.7915 0.435546875 0.2161865234375 -0.5035827636718825 +1.791625 0.432952880859375 0.21490478515625 -0.5035827636718825 +1.79175 0.4302978515625 0.213592529296875 -0.5035827636718825 +1.791875 0.4302978515625 0.213592529296875 -0.5035827636718825 +1.792 0.4276123046875 0.0848388671875 -0.8015075683593804 +1.792125 0.4276123046875 0.0848388671875 -0.8015075683593804 +1.7922500000000002 0.424896240234375 0.08428955078125 -0.8015075683593804 +1.792375 0.422119140625 0.083740234375 -0.8015075683593804 +1.7925 0.422119140625 0.083740234375 -0.8015075683593804 +1.7926250000000002 0.419281005859375 0.083160400390625 -0.8015075683593804 +1.79275 0.419281005859375 0.083160400390625 -0.8015075683593804 +1.792875 0.416412353515625 0.082611083984375 -0.8015075683593804 +1.793 0.413482666015625 0.08203125 -0.8015075683593804 +1.793125 0.413482666015625 0.08203125 -0.8015075683593804 +1.79325 0.4105224609375 0.081451416015625 -0.8015075683593804 +1.793375 0.4105224609375 0.081451416015625 -0.8015075683593804 +1.7935 0.407501220703125 0.080841064453125 -0.8015075683593804 +1.793625 0.404449462890625 0.080230712890625 -0.8015075683593804 +1.79375 0.404449462890625 0.080230712890625 -0.8015075683593804 +1.793875 0.401336669921875 0.079620361328125 -0.8015075683593804 +1.794 0.401336669921875 0.079620361328125 -0.8015075683593804 +1.794125 0.398193359375 0.0789794921875 -0.8015075683593804 +1.7942500000000002 0.39501953125 0.078369140625 -0.8015075683593804 +1.794375 0.39501953125 0.078369140625 -0.8015075683593804 +1.7945 0.39178466796875 0.077728271484375 -0.8015075683593804 +1.7946250000000002 0.39178466796875 0.077728271484375 -0.8015075683593804 +1.79475 0.388519287109375 0.077056884765625 -0.8015075683593804 +1.794875 0.38519287109375 0.076416015625 -0.8015075683593804 +1.795 0.38519287109375 0.076416015625 -0.8015075683593804 +1.795125 0.3818359375 0.07574462890625 -0.8015075683593804 +1.79525 0.3818359375 0.07574462890625 -0.8015075683593804 +1.795375 0.378448486328125 0.0750732421875 -0.8015075683593804 +1.7955 0.375 0.07440185546875 -0.8015075683593804 +1.795625 0.375 0.07440185546875 -0.8015075683593804 +1.79575 0.37152099609375 0.073699951171875 -0.8015075683593804 +1.795875 0.37152099609375 0.073699951171875 -0.8015075683593804 +1.796 0.36798095703125 0.072998046875 -0.8015075683593804 +1.796125 0.36444091796875 0.072296142578125 -0.8015075683593804 +1.7962500000000002 0.36444091796875 0.072296142578125 -0.8015075683593804 +1.796375 0.360809326171875 0.071563720703125 -0.8015075683593804 +1.7965 0.360809326171875 0.071563720703125 -0.8015075683593804 +1.7966250000000002 0.357177734375 0.07086181640625 -0.8015075683593804 +1.79675 0.353485107421875 0.07012939453125 -0.8015075683593804 +1.796875 0.353485107421875 0.07012939453125 -0.8015075683593804 +1.797 0.349761962890625 0.06939697265625 -0.8015075683593804 +1.797125 0.349761962890625 0.06939697265625 -0.8015075683593804 +1.79725 0.34600830078125 0.068634033203125 -0.8015075683593804 +1.797375 0.34222412109375 0.06787109375 -0.8015075683593804 +1.7975 0.34222412109375 0.06787109375 -0.8015075683593804 +1.797625 0.33837890625 0.067138671875 -0.8015075683593804 +1.79775 0.33837890625 0.067138671875 -0.8015075683593804 +1.7978750000000002 0.334503173828125 0.06634521484375 -0.8015075683593804 +1.798 0.330596923828125 0.065582275390625 -0.8015075683593804 +1.798125 0.330596923828125 0.065582275390625 -0.8015075683593804 +1.7982500000000002 0.32666015625 0.064788818359375 -0.8015075683593804 +1.798375 0.32666015625 0.064788818359375 -0.8015075683593804 +1.7985 0.322662353515625 0.063995361328125 -0.8015075683593804 +1.7986250000000002 0.31866455078125 0.063201904296875 -0.8015075683593804 +1.79875 0.31866455078125 0.063201904296875 -0.8015075683593804 +1.798875 0.314605712890625 0.062408447265625 -0.8015075683593804 +1.799 0.314605712890625 0.062408447265625 -0.8015075683593804 +1.799125 0.310516357421875 0.06158447265625 -0.8015075683593804 +1.79925 0.306396484375 0.060791015625 -0.8015075683593804 +1.799375 0.306396484375 0.060791015625 -0.8015075683593804 +1.7995 0.30224609375 0.059967041015625 -0.8015075683593804 +1.799625 0.30224609375 0.059967041015625 -0.8015075683593804 +1.79975 0.298065185546875 0.059112548828125 -0.8015075683593804 +1.7998750000000002 0.2938232421875 0.05828857421875 -0.8015075683593804 +1.8 0.2938232421875 0.05828857421875 -0.8015075683593804 +1.800125 0.289581298828125 0.05743408203125 -0.8015075683593804 +1.8002500000000002 0.289581298828125 0.05743408203125 -0.8015075683593804 +1.800375 0.285308837890625 0.05657958984375 -0.8015075683593804 +1.8005 0.280975341796875 0.05572509765625 -0.8015075683593804 +1.8006250000000002 0.280975341796875 0.05572509765625 -0.8015075683593804 +1.80075 0.276641845703125 0.05487060546875 -0.8015075683593804 +1.800875 0.276641845703125 0.05487060546875 -0.8015075683593804 +1.801 0.27227783203125 0.05401611328125 -0.8015075683593804 +1.801125 0.267852783203125 0.053131103515625 -0.8015075683593804 +1.80125 0.267852783203125 0.053131103515625 -0.8015075683593804 +1.801375 0.263427734375 0.05224609375 -0.8015075683593804 +1.8015 0.263427734375 0.05224609375 -0.8015075683593804 +1.801625 0.25897216796875 0.051361083984375 -0.8015075683593804 +1.80175 0.25445556640625 0.05047607421875 -0.8015075683593804 +1.80187500000000016 0.25445556640625 0.05047607421875 -0.8015075683593804 +1.802 0.249969482421875 0.049591064453125 -0.8015075683593804 +1.802125 0.249969482421875 0.049591064453125 -0.8015075683593804 +1.80225000000000016 0.24542236328125 0.048675537109375 -0.8015075683593804 +1.802375 0.2408447265625 0.047760009765625 -0.8015075683593804 +1.8025 0.2408447265625 0.047760009765625 -0.8015075683593804 +1.80262500000000016 0.236236572265625 0.046844482421875 -0.8015075683593804 +1.80275 0.236236572265625 0.046844482421875 -0.8015075683593804 +1.802875 0.231597900390625 0.045928955078125 -0.8015075683593804 +1.803 0.226959228515625 0.045013427734375 -0.8015075683593804 +1.803125 0.226959228515625 0.045013427734375 -0.8015075683593804 +1.80325 0.2222900390625 0.044097900390625 -0.8015075683593804 +1.803375 0.2222900390625 0.044097900390625 -0.8015075683593804 +1.8035 0.21759033203125 0.04315185546875 -0.8015075683593804 +1.803625 0.212860107421875 0.042205810546875 -0.8015075683593804 +1.80375 0.212860107421875 0.042205810546875 -0.8015075683593804 +1.80387500000000016 0.208099365234375 0.041290283203125 -0.8015075683593804 +1.804 0.208099365234375 0.041290283203125 -0.8015075683593804 +1.804125 0.203338623046875 0.04034423828125 -0.8015075683593804 +1.80425000000000016 0.19854736328125 0.03936767578125 -0.8015075683593804 +1.804375 0.19854736328125 0.03936767578125 -0.8015075683593804 +1.8045 0.1937255859375 0.038421630859375 -0.8015075683593804 +1.804625000000000256 0.1937255859375 0.038421630859375 -0.8015075683593804 +1.80475 0.188873291015625 0.0374755859375 -0.8015075683593804 +1.804875 0.18402099609375 0.0364990234375 -0.8015075683593804 +1.805 0.18402099609375 0.0364990234375 -0.8015075683593804 +1.805125 0.17913818359375 0.0355224609375 -0.8015075683593804 +1.80525 0.17913818359375 0.0355224609375 -0.8015075683593804 +1.805375 0.17425537109375 0.0345458984375 -0.8015075683593804 +1.8055 0.169342041015625 0.0335693359375 -0.8015075683593804 +1.805625 0.169342041015625 0.0335693359375 -0.8015075683593804 +1.80575 0.164398193359375 0.0325927734375 -0.8015075683593804 +1.80587500000000016 0.164398193359375 0.0325927734375 -0.8015075683593804 +1.806 0.159454345703125 0.0316162109375 -0.8015075683593804 +1.806125 0.15447998046875 0.0306396484375 -0.8015075683593804 +1.80625000000000016 0.15447998046875 0.0306396484375 -0.8015075683593804 +1.806375 0.14947509765625 0.029632568359375 -0.8015075683593804 +1.8065 0.14947509765625 0.029632568359375 -0.8015075683593804 +1.806625000000000256 0.14447021484375 0.028656005859375 -0.8015075683593804 +1.80675 0.13946533203125 0.02764892578125 -0.8015075683593804 +1.806875 0.13946533203125 0.02764892578125 -0.8015075683593804 +1.807 0.134429931640625 0.02667236328125 -0.8015075683593804 +1.807125 0.134429931640625 0.02667236328125 -0.8015075683593804 +1.80725 0.129364013671875 0.025665283203125 -0.8015075683593804 +1.807375 0.124298095703125 0.024658203125 -0.8015075683593804 +1.8075 0.124298095703125 0.024658203125 -0.8015075683593804 +1.807625 0.119232177734375 0.023651123046875 -0.8015075683593804 +1.80775 0.119232177734375 0.023651123046875 -0.8015075683593804 +1.80787500000000016 0.1141357421875 0.02264404296875 -0.8015075683593804 +1.808 0.109039306640625 0.0216064453125 -0.8015075683593804 +1.808125 0.109039306640625 0.0216064453125 -0.8015075683593804 +1.80825000000000016 0.103912353515625 0.020599365234375 -0.8015075683593804 +1.808375 0.103912353515625 0.020599365234375 -0.8015075683593804 +1.8085 0.098785400390625 0.01959228515625 -0.8015075683593804 +1.808625 0.093658447265625 0.0185546875 -0.8015075683593804 +1.80875 0.093658447265625 0.0185546875 -0.8015075683593804 +1.808875 0.0885009765625 0.017547607421875 -0.8015075683593804 +1.809 0.0885009765625 0.017547607421875 -0.8015075683593804 +1.809125 0.083343505859375 0.01654052734375 -0.8015075683593804 +1.80925 0.07818603515625 0.0155029296875 -0.8015075683593804 +1.809375 0.07818603515625 0.0155029296875 -0.8015075683593804 +1.8095 0.072998046875 0.01446533203125 -0.8015075683593804 +1.809625 0.072998046875 0.01446533203125 -0.8015075683593804 +1.80975 0.06781005859375 0.013458251953125 -0.8015075683593804 +1.80987500000000016 0.0626220703125 0.012420654296875 -0.8015075683593804 +1.81 0.0626220703125 0.012420654296875 -0.8015075683593804 +1.810125 0.05743408203125 0.011383056640625 -0.8015075683593804 +1.81025000000000016 0.05743408203125 0.011383056640625 -0.8015075683593804 +1.810375 0.05224609375 0.010345458984375 -0.8015075683593804 +1.8105 0.047027587890625 0.009307861328125 -0.8015075683593804 +1.810625 0.047027587890625 0.009307861328125 -0.8015075683593804 +1.81075 0.04180908203125 0.008270263671875 -0.8015075683593804 +1.810875 0.04180908203125 0.008270263671875 -0.8015075683593804 +1.811 0.036590576171875 0.007232666015625 -0.8015075683593804 +1.811125 0.0313720703125 0.0062255859375 -0.8015075683593804 +1.81125 0.0313720703125 0.0062255859375 -0.8015075683593804 +1.811375 0.026123046875 0.00518798828125 -0.8015075683593804 +1.8115 0.026123046875 0.00518798828125 -0.8015075683593804 +1.811625 0.020904541015625 0.004150390625 -0.8015075683593804 +1.81175 0.01568603515625 0.00311279296875 -0.8015075683593804 +1.81187500000000016 0.01568603515625 0.00311279296875 -0.8015075683593804 +1.812 0.01043701171875 0.0020751953125 -0.8015075683593804 +1.812125 0.01043701171875 0.0020751953125 -0.8015075683593804 +1.81225000000000016 0.005218505859375 0.00103759765625 -0.8015075683593804 +1.812375 0.0 0.0 -0.8015075683593804 +1.8125 0.0 0.0 -0.8015075683593804 +1.812625 -0.005218505859375 -0.00103759765625 -0.8015075683593804 +1.81275 -0.005218505859375 -0.00103759765625 -0.8015075683593804 +1.812875 -0.01043701171875 -0.0020751953125 -0.8015075683593804 +1.813 -0.01568603515625 -0.00311279296875 -0.8015075683593804 +1.813125 -0.01568603515625 -0.00311279296875 -0.8015075683593804 +1.81325 -0.020904541015625 -0.004150390625 -0.8015075683593804 +1.813375 -0.020904541015625 -0.004150390625 -0.8015075683593804 +1.81350000000000016 -0.026123046875 -0.00518798828125 -0.8015075683593804 +1.813625 -0.0313720703125 -0.0062255859375 -0.8015075683593804 +1.81375 -0.0313720703125 -0.0062255859375 -0.8015075683593804 +1.81387500000000016 -0.036590576171875 -0.007232666015625 -0.8015075683593804 +1.814 -0.036590576171875 -0.007232666015625 -0.8015075683593804 +1.814125 -0.04180908203125 -0.008270263671875 -0.8015075683593804 +1.81425000000000016 -0.047027587890625 -0.009307861328125 -0.8015075683593804 +1.814375 -0.047027587890625 -0.009307861328125 -0.8015075683593804 +1.8145 -0.05224609375 -0.010345458984375 -0.8015075683593804 +1.814625 -0.05224609375 -0.010345458984375 -0.8015075683593804 +1.81475 -0.05743408203125 -0.011383056640625 -0.8015075683593804 +1.814875 -0.0626220703125 -0.012420654296875 -0.8015075683593804 +1.815 -0.0626220703125 -0.012420654296875 -0.8015075683593804 +1.815125 -0.06781005859375 -0.013458251953125 -0.8015075683593804 +1.81525 -0.06781005859375 -0.013458251953125 -0.8015075683593804 +1.815375 -0.072998046875 -0.01446533203125 -0.8015075683593804 +1.81550000000000016 -0.07818603515625 -0.0155029296875 -0.8015075683593804 +1.815625 -0.07818603515625 -0.0155029296875 -0.8015075683593804 +1.81575 -0.083343505859375 -0.01654052734375 -0.8015075683593804 +1.81587500000000016 -0.083343505859375 -0.01654052734375 -0.8015075683593804 +1.816 -0.0885009765625 -0.017547607421875 -0.8015075683593804 +1.816125 -0.093658447265625 -0.0185546875 -0.8015075683593804 +1.81625000000000016 -0.093658447265625 -0.0185546875 -0.8015075683593804 +1.816375 -0.098785400390625 -0.01959228515625 -0.8015075683593804 +1.8165 -0.098785400390625 -0.01959228515625 -0.8015075683593804 +1.816625 -0.103912353515625 -0.020599365234375 -0.8015075683593804 +1.81675 -0.109039306640625 -0.0216064453125 -0.8015075683593804 +1.816875 -0.109039306640625 -0.0216064453125 -0.8015075683593804 +1.817 -0.1141357421875 -0.02264404296875 -0.8015075683593804 +1.817125 -0.1141357421875 -0.02264404296875 -0.8015075683593804 +1.81725 -0.119232177734375 -0.023651123046875 -0.8015075683593804 +1.817375 -0.124298095703125 -0.024658203125 -0.8015075683593804 +1.81750000000000016 -0.124298095703125 -0.024658203125 -0.8015075683593804 +1.817625 -0.129364013671875 -0.025665283203125 -0.8015075683593804 +1.81775 -0.129364013671875 -0.025665283203125 -0.8015075683593804 +1.81787500000000016 -0.134429931640625 -0.02667236328125 -0.8015075683593804 +1.818 -0.13946533203125 -0.02764892578125 -0.8015075683593804 +1.818125 -0.13946533203125 -0.02764892578125 -0.8015075683593804 +1.81825000000000016 -0.14447021484375 -0.028656005859375 -0.8015075683593804 +1.818375 -0.14447021484375 -0.028656005859375 -0.8015075683593804 +1.8185 -0.14947509765625 -0.029632568359375 -0.8015075683593804 +1.818625 -0.15447998046875 -0.0306396484375 -0.8015075683593804 +1.81875 -0.15447998046875 -0.0306396484375 -0.8015075683593804 +1.818875 -0.159454345703125 -0.0316162109375 -0.8015075683593804 +1.819 -0.159454345703125 -0.0316162109375 -0.8015075683593804 +1.819125 -0.164398193359375 -0.0325927734375 -0.8015075683593804 +1.81925 -0.169342041015625 -0.0335693359375 -0.8015075683593804 +1.819375 -0.169342041015625 -0.0335693359375 -0.8015075683593804 +1.81950000000000016 -0.17425537109375 -0.0345458984375 -0.8015075683593804 +1.819625 -0.17425537109375 -0.0345458984375 -0.8015075683593804 +1.81975 -0.17913818359375 -0.0355224609375 -0.8015075683593804 +1.81987500000000016 -0.18402099609375 -0.0364990234375 -0.8015075683593804 +1.82 -0.18402099609375 -0.0364990234375 -0.8015075683593804 +1.820125 -0.188873291015625 -0.0374755859375 -0.8015075683593804 +1.820250000000000256 -0.188873291015625 -0.0374755859375 -0.8015075683593804 +1.820375 -0.1937255859375 -0.038421630859375 -0.8015075683593804 +1.8205 -0.19854736328125 -0.03936767578125 -0.8015075683593804 +1.820625 -0.19854736328125 -0.03936767578125 -0.8015075683593804 +1.82075 -0.203338623046875 -0.04034423828125 -0.8015075683593804 +1.820875 -0.203338623046875 -0.04034423828125 -0.8015075683593804 +1.821 -0.208099365234375 -0.041290283203125 -0.8015075683593804 +1.821125 -0.212860107421875 -0.042205810546875 -0.8015075683593804 +1.82125 -0.212860107421875 -0.042205810546875 -0.8015075683593804 +1.821375 -0.21759033203125 -0.04315185546875 -0.8015075683593804 +1.82150000000000016 -0.21759033203125 -0.04315185546875 -0.8015075683593804 +1.821625 -0.2222900390625 -0.044097900390625 -0.8015075683593804 +1.82175 -0.226959228515625 -0.045013427734375 -0.8015075683593804 +1.82187500000000016 -0.226959228515625 -0.045013427734375 -0.8015075683593804 +1.822 -0.231597900390625 -0.045928955078125 -0.8015075683593804 +1.822125 -0.231597900390625 -0.045928955078125 -0.8015075683593804 +1.822250000000000256 -0.236236572265625 -0.046844482421875 -0.8015075683593804 +1.822375 -0.2408447265625 -0.047760009765625 -0.8015075683593804 +1.8225 -0.2408447265625 -0.047760009765625 -0.8015075683593804 +1.822625 -0.24542236328125 -0.048675537109375 -0.8015075683593804 +1.82275 -0.24542236328125 -0.048675537109375 -0.8015075683593804 +1.822875 -0.249969482421875 -0.049591064453125 -0.8015075683593804 +1.823 -0.25445556640625 -0.05047607421875 -0.8015075683593804 +1.823125 -0.25445556640625 -0.05047607421875 -0.8015075683593804 +1.82325 -0.25897216796875 -0.051361083984375 -0.8015075683593804 +1.823375 -0.25897216796875 -0.051361083984375 -0.8015075683593804 +1.82350000000000016 -0.263427734375 -0.05224609375 -0.8015075683593804 +1.823625 -0.267852783203125 -0.053131103515625 -0.8015075683593804 +1.82375 -0.267852783203125 -0.053131103515625 -0.8015075683593804 +1.82387500000000016 -0.27227783203125 -0.05401611328125 -0.8015075683593804 +1.824 -0.27227783203125 -0.0076904296875 -0.9715881347656272 +1.824125 -0.276641845703125 -0.0078125 -0.9715881347656272 +1.82425 -0.280975341796875 -0.0079345703125 -0.9715881347656272 +1.824375 -0.280975341796875 -0.0079345703125 -0.9715881347656272 +1.8245 -0.285308837890625 -0.008056640625 -0.9715881347656272 +1.824625 -0.285308837890625 -0.008056640625 -0.9715881347656272 +1.82475 -0.289581298828125 -0.0081787109375 -0.9715881347656272 +1.824875 -0.2938232421875 -0.00830078125 -0.9715881347656272 +1.825 -0.2938232421875 -0.00830078125 -0.9715881347656272 +1.825125 -0.298065185546875 -0.0084228515625 -0.9715881347656272 +1.82525 -0.298065185546875 -0.0084228515625 -0.9715881347656272 +1.825375 -0.30224609375 -0.008544921875 -0.9715881347656272 +1.82550000000000016 -0.306396484375 -0.0086669921875 -0.9715881347656272 +1.825625 -0.306396484375 -0.0086669921875 -0.9715881347656272 +1.82575 -0.310516357421875 -0.0087890625 -0.9715881347656272 +1.82587500000000016 -0.310516357421875 -0.0087890625 -0.9715881347656272 +1.826 -0.314605712890625 -0.008880615234375 -0.9715881347656272 +1.826125 -0.31866455078125 -0.009002685546875 -0.9715881347656272 +1.82625 -0.31866455078125 -0.009002685546875 -0.9715881347656272 +1.826375 -0.322662353515625 -0.009124755859375 -0.9715881347656272 +1.8265 -0.322662353515625 -0.009124755859375 -0.9715881347656272 +1.826625 -0.32666015625 -0.009246826171875 -0.9715881347656272 +1.82675 -0.330596923828125 -0.00933837890625 -0.9715881347656272 +1.826875 -0.330596923828125 -0.00933837890625 -0.9715881347656272 +1.827 -0.334503173828125 -0.00946044921875 -0.9715881347656272 +1.827125 -0.334503173828125 -0.00946044921875 -0.9715881347656272 +1.82725 -0.33837890625 -0.00958251953125 -0.9715881347656272 +1.827375 -0.34222412109375 -0.009674072265625 -0.9715881347656272 +1.82750000000000016 -0.34222412109375 -0.009674072265625 -0.9715881347656272 +1.827625 -0.34600830078125 -0.009796142578125 -0.9715881347656272 +1.82775 -0.34600830078125 -0.009796142578125 -0.9715881347656272 +1.82787500000000016 -0.349761962890625 -0.0098876953125 -0.9715881347656272 +1.828 -0.353485107421875 -0.010009765625 -0.9715881347656272 +1.828125 -0.353485107421875 -0.010009765625 -0.9715881347656272 +1.82825 -0.357177734375 -0.010101318359375 -0.9715881347656272 +1.828375 -0.357177734375 -0.010101318359375 -0.9715881347656272 +1.8285 -0.360809326171875 -0.01019287109375 -0.9715881347656272 +1.828625 -0.36444091796875 -0.01031494140625 -0.9715881347656272 +1.82875 -0.36444091796875 -0.01031494140625 -0.9715881347656272 +1.828875 -0.36798095703125 -0.010406494140625 -0.9715881347656272 +1.829 -0.36798095703125 -0.010406494140625 -0.9715881347656272 +1.82912500000000016 -0.37152099609375 -0.010498046875 -0.9715881347656272 +1.82925 -0.375 -0.0106201171875 -0.9715881347656272 +1.829375 -0.375 -0.0106201171875 -0.9715881347656272 +1.82950000000000016 -0.378448486328125 -0.010711669921875 -0.9715881347656272 +1.829625 -0.378448486328125 -0.010711669921875 -0.9715881347656272 +1.82975 -0.3818359375 -0.01080322265625 -0.9715881347656272 +1.82987500000000016 -0.38519287109375 -0.010894775390625 -0.9715881347656272 +1.83 -0.38519287109375 -0.010894775390625 -0.9715881347656272 +1.830125 -0.388519287109375 -0.010986328125 -0.9715881347656272 +1.83025 -0.388519287109375 -0.010986328125 -0.9715881347656272 +1.830375 -0.39178466796875 -0.011077880859375 -0.9715881347656272 +1.8305 -0.39501953125 -0.01116943359375 -0.9715881347656272 +1.830625 -0.39501953125 -0.01116943359375 -0.9715881347656272 +1.83075 -0.398193359375 -0.011260986328125 -0.9715881347656272 +1.830875 -0.398193359375 -0.011260986328125 -0.9715881347656272 +1.831 -0.401336669921875 -0.0113525390625 -0.9715881347656272 +1.83112500000000016 -0.404449462890625 -0.011444091796875 -0.9715881347656272 +1.83125 -0.404449462890625 -0.011444091796875 -0.9715881347656272 +1.831375 -0.407501220703125 -0.01153564453125 -0.9715881347656272 +1.83150000000000016 -0.407501220703125 -0.01153564453125 -0.9715881347656272 +1.831625 -0.4105224609375 -0.0115966796875 -0.9715881347656272 +1.83175 -0.413482666015625 -0.011688232421875 -0.9715881347656272 +1.83187500000000016 -0.413482666015625 -0.011688232421875 -0.9715881347656272 +1.832 -0.416412353515625 -0.01177978515625 -0.9715881347656272 +1.832125 -0.416412353515625 -0.01177978515625 -0.9715881347656272 +1.83225 -0.419281005859375 -0.011871337890625 -0.9715881347656272 +1.832375 -0.422119140625 -0.011932373046875 -0.9715881347656272 +1.8325 -0.422119140625 -0.011932373046875 -0.9715881347656272 +1.832625 -0.424896240234375 -0.01202392578125 -0.9715881347656272 +1.83275 -0.424896240234375 -0.01202392578125 -0.9715881347656272 +1.832875 -0.4276123046875 -0.0120849609375 -0.9715881347656272 +1.833 -0.4302978515625 -0.012176513671875 -0.9715881347656272 +1.83312500000000016 -0.4302978515625 -0.012176513671875 -0.9715881347656272 +1.83325 -0.432952880859375 -0.012237548828125 -0.9715881347656272 +1.833375 -0.432952880859375 -0.012237548828125 -0.9715881347656272 +1.83350000000000016 -0.435546875 -0.0123291015625 -0.9715881347656272 +1.833625 -0.438079833984375 -0.01239013671875 -0.9715881347656272 +1.83375 -0.438079833984375 -0.01239013671875 -0.9715881347656272 +1.83387500000000016 -0.440582275390625 -0.012451171875 -0.9715881347656272 +1.834 -0.440582275390625 -0.012451171875 -0.9715881347656272 +1.834125 -0.44305419921875 -0.012542724609375 -0.9715881347656272 +1.83425 -0.4454345703125 -0.012603759765625 -0.9715881347656272 +1.834375 -0.4454345703125 -0.012603759765625 -0.9715881347656272 +1.8345 -0.447784423828125 -0.012664794921875 -0.9715881347656272 +1.834625 -0.447784423828125 -0.012664794921875 -0.9715881347656272 +1.83475 -0.450103759765625 -0.012725830078125 -0.9715881347656272 +1.834875 -0.452362060546875 -0.012786865234375 -0.9715881347656272 +1.835 -0.452362060546875 -0.012786865234375 -0.9715881347656272 +1.83512500000000016 -0.454559326171875 -0.012847900390625 -0.9715881347656272 +1.83525 -0.454559326171875 -0.012847900390625 -0.9715881347656272 +1.835375 -0.45672607421875 -0.012908935546875 -0.9715881347656272 +1.83550000000000016 -0.458831787109375 -0.012969970703125 -0.9715881347656272 +1.835625 -0.458831787109375 -0.012969970703125 -0.9715881347656272 +1.83575 -0.46087646484375 -0.013031005859375 -0.9715881347656272 +1.835875000000000256 -0.46087646484375 -0.013031005859375 -0.9715881347656272 +1.836 -0.462890625 -0.013092041015625 -0.9715881347656272 +1.836125 -0.464813232421875 -0.013153076171875 -0.9715881347656272 +1.83625 -0.464813232421875 -0.013153076171875 -0.9715881347656272 +1.836375 -0.46673583984375 -0.013214111328125 -0.9715881347656272 +1.8365 -0.46673583984375 -0.013214111328125 -0.9715881347656272 +1.836625 -0.46856689453125 -0.01324462890625 -0.9715881347656272 +1.83675 -0.470367431640625 -0.0133056640625 -0.9715881347656272 +1.836875 -0.470367431640625 -0.0133056640625 -0.9715881347656272 +1.837 -0.472137451171875 -0.01336669921875 -0.9715881347656272 +1.83712500000000016 -0.472137451171875 -0.01336669921875 -0.9715881347656272 +1.83725 -0.47381591796875 -0.013397216796875 -0.9715881347656272 +1.837375 -0.4754638671875 -0.013458251953125 -0.9715881347656272 +1.83750000000000016 -0.4754638671875 -0.013458251953125 -0.9715881347656272 +1.837625 -0.47705078125 -0.01348876953125 -0.9715881347656272 +1.83775 -0.47705078125 -0.01348876953125 -0.9715881347656272 +1.837875000000000256 -0.478607177734375 -0.0135498046875 -0.9715881347656272 +1.838 -0.480072021484375 -0.013580322265625 -0.9715881347656272 +1.838125 -0.480072021484375 -0.013580322265625 -0.9715881347656272 +1.83825 -0.48150634765625 -0.01361083984375 -0.9715881347656272 +1.838375 -0.48150634765625 -0.01361083984375 -0.9715881347656272 +1.8385 -0.48291015625 -0.013671875 -0.9715881347656272 +1.838625 -0.484222412109375 -0.013702392578125 -0.9715881347656272 +1.83875 -0.484222412109375 -0.013702392578125 -0.9715881347656272 +1.838875 -0.485504150390625 -0.01373291015625 -0.9715881347656272 +1.839 -0.485504150390625 -0.01373291015625 -0.9715881347656272 +1.83912500000000016 -0.486724853515625 -0.013763427734375 -0.9715881347656272 +1.83925 -0.487884521484375 -0.0137939453125 -0.9715881347656272 +1.839375 -0.487884521484375 -0.0137939453125 -0.9715881347656272 +1.83950000000000016 -0.489013671875 -0.013824462890625 -0.9715881347656272 +1.839625 -0.489013671875 -0.013824462890625 -0.9715881347656272 +1.83975 -0.490081787109375 -0.01385498046875 -0.9715881347656272 +1.839875000000000256 -0.4910888671875 -0.013885498046875 -0.9715881347656272 +1.84 -0.4910888671875 -0.013885498046875 -0.9715881347656272 +1.840125 -0.492034912109375 -0.013916015625 -0.9715881347656272 +1.84025 -0.492034912109375 -0.013916015625 -0.9715881347656272 +1.840375 -0.492950439453125 -0.013946533203125 -0.9715881347656272 +1.8405 -0.4937744140625 -0.01397705078125 -0.9715881347656272 +1.840625 -0.4937744140625 -0.01397705078125 -0.9715881347656272 +1.84075 -0.49456787109375 -0.014007568359375 -0.9715881347656272 +1.840875 -0.49456787109375 -0.014007568359375 -0.9715881347656272 +1.841 -0.49530029296875 -0.014007568359375 -0.9715881347656272 +1.84112500000000016 -0.496002197265625 -0.0140380859375 -0.9715881347656272 +1.84125 -0.496002197265625 -0.0140380859375 -0.9715881347656272 +1.841375 -0.496612548828125 -0.0140380859375 -0.9715881347656272 +1.84150000000000016 -0.496612548828125 -0.0140380859375 -0.9715881347656272 +1.841625 -0.4971923828125 -0.014068603515625 -0.9715881347656272 +1.84175 -0.497711181640625 -0.014068603515625 -0.9715881347656272 +1.841875 -0.497711181640625 -0.014068603515625 -0.9715881347656272 +1.842 -0.498199462890625 -0.01409912109375 -0.9715881347656272 +1.842125 -0.498199462890625 -0.01409912109375 -0.9715881347656272 +1.84225 -0.49859619140625 -0.01409912109375 -0.9715881347656272 +1.842375 -0.49896240234375 -0.014129638671875 -0.9715881347656272 +1.8425 -0.49896240234375 -0.014129638671875 -0.9715881347656272 +1.842625 -0.499267578125 -0.014129638671875 -0.9715881347656272 +1.84275 -0.499267578125 -0.014129638671875 -0.9715881347656272 +1.842875 -0.49951171875 -0.014129638671875 -0.9715881347656272 +1.843 -0.49969482421875 -0.014129638671875 -0.9715881347656272 +1.84312500000000016 -0.49969482421875 -0.014129638671875 -0.9715881347656272 +1.84325 -0.49981689453125 -0.014129638671875 -0.9715881347656272 +1.843375 -0.49981689453125 -0.014129638671875 -0.9715881347656272 +1.84350000000000016 -0.499908447265625 -0.014129638671875 -0.9715881347656272 +1.843625 -0.49993896484375 -0.014129638671875 -0.9715881347656272 +1.84375 -0.49993896484375 -0.014129638671875 -0.9715881347656272 +1.843875 -0.499908447265625 -0.014129638671875 -0.9715881347656272 +1.844 -0.499908447265625 -0.014129638671875 -0.9715881347656272 +1.844125 -0.49981689453125 -0.014129638671875 -0.9715881347656272 +1.84425 -0.49969482421875 -0.014129638671875 -0.9715881347656272 +1.844375 -0.49969482421875 -0.014129638671875 -0.9715881347656272 +1.8445 -0.49951171875 -0.014129638671875 -0.9715881347656272 +1.844625 -0.49951171875 -0.014129638671875 -0.9715881347656272 +1.84475000000000016 -0.499267578125 -0.014129638671875 -0.9715881347656272 +1.844875 -0.49896240234375 -0.014129638671875 -0.9715881347656272 +1.845 -0.49896240234375 -0.014129638671875 -0.9715881347656272 +1.84512500000000016 -0.49859619140625 -0.01409912109375 -0.9715881347656272 +1.84525 -0.49859619140625 -0.01409912109375 -0.9715881347656272 +1.845375 -0.498199462890625 -0.01409912109375 -0.9715881347656272 +1.84550000000000016 -0.497711181640625 -0.014068603515625 -0.9715881347656272 +1.845625 -0.497711181640625 -0.014068603515625 -0.9715881347656272 +1.84575 -0.4971923828125 -0.014068603515625 -0.9715881347656272 +1.845875 -0.4971923828125 -0.014068603515625 -0.9715881347656272 +1.846 -0.496612548828125 -0.0140380859375 -0.9715881347656272 +1.846125 -0.496002197265625 -0.0140380859375 -0.9715881347656272 +1.84625 -0.496002197265625 -0.0140380859375 -0.9715881347656272 +1.846375 -0.49530029296875 -0.014007568359375 -0.9715881347656272 +1.8465 -0.49530029296875 -0.014007568359375 -0.9715881347656272 +1.846625 -0.49456787109375 -0.014007568359375 -0.9715881347656272 +1.84675000000000016 -0.4937744140625 -0.01397705078125 -0.9715881347656272 +1.846875 -0.4937744140625 -0.01397705078125 -0.9715881347656272 +1.847 -0.492950439453125 -0.013946533203125 -0.9715881347656272 +1.84712500000000016 -0.492950439453125 -0.013946533203125 -0.9715881347656272 +1.84725 -0.492034912109375 -0.013916015625 -0.9715881347656272 +1.847375 -0.4910888671875 -0.013885498046875 -0.9715881347656272 +1.84750000000000016 -0.4910888671875 -0.013885498046875 -0.9715881347656272 +1.847625 -0.490081787109375 -0.01385498046875 -0.9715881347656272 +1.84775 -0.490081787109375 -0.01385498046875 -0.9715881347656272 +1.847875 -0.489013671875 -0.013824462890625 -0.9715881347656272 +1.848 -0.487884521484375 -0.0137939453125 -0.9715881347656272 +1.848125 -0.487884521484375 -0.0137939453125 -0.9715881347656272 +1.84825 -0.486724853515625 -0.013763427734375 -0.9715881347656272 +1.848375 -0.486724853515625 -0.013763427734375 -0.9715881347656272 +1.8485 -0.485504150390625 -0.01373291015625 -0.9715881347656272 +1.848625 -0.484222412109375 -0.013702392578125 -0.9715881347656272 +1.84875000000000016 -0.484222412109375 -0.013702392578125 -0.9715881347656272 +1.848875 -0.48291015625 -0.013671875 -0.9715881347656272 +1.849 -0.48291015625 -0.013671875 -0.9715881347656272 +1.84912500000000016 -0.48150634765625 -0.01361083984375 -0.9715881347656272 +1.84925 -0.480072021484375 -0.013580322265625 -0.9715881347656272 +1.849375 -0.480072021484375 -0.013580322265625 -0.9715881347656272 +1.84950000000000016 -0.478607177734375 -0.0135498046875 -0.9715881347656272 +1.849625 -0.478607177734375 -0.0135498046875 -0.9715881347656272 +1.84975 -0.47705078125 -0.01348876953125 -0.9715881347656272 +1.849875 -0.4754638671875 -0.013458251953125 -0.9715881347656272 +1.85 -0.4754638671875 -0.013458251953125 -0.9715881347656272 +1.850125 -0.47381591796875 -0.013397216796875 -0.9715881347656272 +1.85025 -0.47381591796875 -0.013397216796875 -0.9715881347656272 +1.850375 -0.472137451171875 -0.01336669921875 -0.9715881347656272 +1.8505 -0.470367431640625 -0.0133056640625 -0.9715881347656272 +1.850625 -0.470367431640625 -0.0133056640625 -0.9715881347656272 +1.85075000000000016 -0.46856689453125 -0.01324462890625 -0.9715881347656272 +1.850875 -0.46856689453125 -0.01324462890625 -0.9715881347656272 +1.851 -0.46673583984375 -0.013214111328125 -0.9715881347656272 +1.85112500000000016 -0.464813232421875 -0.013153076171875 -0.9715881347656272 +1.85125 -0.464813232421875 -0.013153076171875 -0.9715881347656272 +1.851375 -0.462890625 -0.013092041015625 -0.9715881347656272 +1.851500000000000256 -0.462890625 -0.013092041015625 -0.9715881347656272 +1.851625 -0.46087646484375 -0.013031005859375 -0.9715881347656272 +1.85175 -0.458831787109375 -0.012969970703125 -0.9715881347656272 +1.851875 -0.458831787109375 -0.012969970703125 -0.9715881347656272 +1.852 -0.45672607421875 -0.012908935546875 -0.9715881347656272 +1.852125 -0.45672607421875 -0.012908935546875 -0.9715881347656272 +1.85225 -0.454559326171875 -0.012847900390625 -0.9715881347656272 +1.852375 -0.452362060546875 -0.012786865234375 -0.9715881347656272 +1.8525 -0.452362060546875 -0.012786865234375 -0.9715881347656272 +1.852625 -0.450103759765625 -0.012725830078125 -0.9715881347656272 +1.85275000000000016 -0.450103759765625 -0.012725830078125 -0.9715881347656272 +1.852875 -0.447784423828125 -0.012664794921875 -0.9715881347656272 +1.853 -0.4454345703125 -0.012603759765625 -0.9715881347656272 +1.85312500000000016 -0.4454345703125 -0.012603759765625 -0.9715881347656272 +1.85325 -0.44305419921875 -0.012542724609375 -0.9715881347656272 +1.853375 -0.44305419921875 -0.012542724609375 -0.9715881347656272 +1.853500000000000256 -0.440582275390625 -0.012451171875 -0.9715881347656272 +1.853625 -0.438079833984375 -0.01239013671875 -0.9715881347656272 +1.85375 -0.438079833984375 -0.01239013671875 -0.9715881347656272 +1.853875 -0.435546875 -0.0123291015625 -0.9715881347656272 +1.854 -0.435546875 -0.0123291015625 -0.9715881347656272 +1.854125 -0.432952880859375 -0.012237548828125 -0.9715881347656272 +1.85425 -0.4302978515625 -0.012176513671875 -0.9715881347656272 +1.854375 -0.4302978515625 -0.012176513671875 -0.9715881347656272 +1.8545 -0.4276123046875 -0.0120849609375 -0.9715881347656272 +1.854625 -0.4276123046875 -0.0120849609375 -0.9715881347656272 +1.85475000000000016 -0.424896240234375 -0.01202392578125 -0.9715881347656272 +1.854875 -0.422119140625 -0.011932373046875 -0.9715881347656272 +1.855 -0.422119140625 -0.011932373046875 -0.9715881347656272 +1.85512500000000016 -0.419281005859375 -0.011871337890625 -0.9715881347656272 +1.85525 -0.419281005859375 -0.011871337890625 -0.9715881347656272 +1.855375 -0.416412353515625 -0.01177978515625 -0.9715881347656272 +1.855500000000000256 -0.413482666015625 -0.011688232421875 -0.9715881347656272 +1.855625 -0.413482666015625 -0.011688232421875 -0.9715881347656272 +1.85575 -0.4105224609375 -0.0115966796875 -0.9715881347656272 +1.855875 -0.4105224609375 -0.0115966796875 -0.9715881347656272 +1.856 -0.407501220703125 -0.005401611328125 -0.9866333007812484 +1.856125 -0.404449462890625 -0.005340576171875 -0.9866333007812484 +1.85625 -0.404449462890625 -0.005340576171875 -0.9866333007812484 +1.856375 -0.401336669921875 -0.00531005859375 -0.9866333007812484 +1.8565 -0.401336669921875 -0.00531005859375 -0.9866333007812484 +1.856625 -0.398193359375 -0.005279541015625 -0.9866333007812484 +1.85675000000000016 -0.39501953125 -0.005218505859375 -0.9866333007812484 +1.856875 -0.39501953125 -0.005218505859375 -0.9866333007812484 +1.857 -0.39178466796875 -0.00518798828125 -0.9866333007812484 +1.85712500000000016 -0.39178466796875 -0.00518798828125 -0.9866333007812484 +1.85725 -0.388519287109375 -0.005157470703125 -0.9866333007812484 +1.857375 -0.38519287109375 -0.005096435546875 -0.9866333007812484 +1.8575 -0.38519287109375 -0.005096435546875 -0.9866333007812484 +1.857625 -0.3818359375 -0.00506591796875 -0.9866333007812484 +1.85775 -0.3818359375 -0.00506591796875 -0.9866333007812484 +1.857875 -0.378448486328125 -0.0050048828125 -0.9866333007812484 +1.858 -0.375 -0.004974365234375 -0.9866333007812484 +1.858125 -0.375 -0.004974365234375 -0.9866333007812484 +1.85825 -0.37152099609375 -0.004913330078125 -0.9866333007812484 +1.858375 -0.37152099609375 -0.004913330078125 -0.9866333007812484 +1.8585 -0.36798095703125 -0.0048828125 -0.9866333007812484 +1.858625 -0.36444091796875 -0.00482177734375 -0.9866333007812484 +1.85875000000000016 -0.36444091796875 -0.00482177734375 -0.9866333007812484 +1.858875 -0.360809326171875 -0.0047607421875 -0.9866333007812484 +1.859 -0.360809326171875 -0.0047607421875 -0.9866333007812484 +1.85912500000000016 -0.357177734375 -0.004730224609375 -0.9866333007812484 +1.85925 -0.353485107421875 -0.004669189453125 -0.9866333007812484 +1.859375 -0.353485107421875 -0.004669189453125 -0.9866333007812484 +1.8595 -0.349761962890625 -0.004638671875 -0.9866333007812484 +1.859625 -0.349761962890625 -0.004638671875 -0.9866333007812484 +1.85975 -0.34600830078125 -0.00457763671875 -0.9866333007812484 +1.859875 -0.34222412109375 -0.0045166015625 -0.9866333007812484 +1.86 -0.34222412109375 -0.0045166015625 -0.9866333007812484 +1.860125 -0.33837890625 -0.004486083984375 -0.9866333007812484 +1.86025 -0.33837890625 -0.004486083984375 -0.9866333007812484 +1.86037500000000016 -0.334503173828125 -0.004425048828125 -0.9866333007812484 +1.8605 -0.330596923828125 -0.004364013671875 -0.9866333007812484 +1.860625 -0.330596923828125 -0.004364013671875 -0.9866333007812484 +1.86075000000000016 -0.32666015625 -0.00433349609375 -0.9866333007812484 +1.860875 -0.32666015625 -0.00433349609375 -0.9866333007812484 +1.861 -0.322662353515625 -0.0042724609375 -0.9866333007812484 +1.86112500000000016 -0.31866455078125 -0.00421142578125 -0.9866333007812484 +1.86125 -0.31866455078125 -0.00421142578125 -0.9866333007812484 +1.861375 -0.314605712890625 -0.004150390625 -0.9866333007812484 +1.8615 -0.314605712890625 -0.004150390625 -0.9866333007812484 +1.861625 -0.310516357421875 -0.004119873046875 -0.9866333007812484 +1.86175 -0.306396484375 -0.004058837890625 -0.9866333007812484 +1.861875 -0.306396484375 -0.004058837890625 -0.9866333007812484 +1.862 -0.30224609375 -0.003997802734375 -0.9866333007812484 +1.862125 -0.30224609375 -0.003997802734375 -0.9866333007812484 +1.86225 -0.298065185546875 -0.003936767578125 -0.9866333007812484 +1.86237500000000016 -0.2938232421875 -0.003875732421875 -0.9866333007812484 +1.8625 -0.2938232421875 -0.003875732421875 -0.9866333007812484 +1.862625 -0.289581298828125 -0.003814697265625 -0.9866333007812484 +1.86275000000000016 -0.289581298828125 -0.003814697265625 -0.9866333007812484 +1.862875 -0.285308837890625 -0.0037841796875 -0.9866333007812484 +1.863 -0.280975341796875 -0.00372314453125 -0.9866333007812484 +1.86312500000000016 -0.280975341796875 -0.00372314453125 -0.9866333007812484 +1.86325 -0.276641845703125 -0.003662109375 -0.9866333007812484 +1.863375 -0.276641845703125 -0.003662109375 -0.9866333007812484 +1.8635 -0.27227783203125 -0.00360107421875 -0.9866333007812484 +1.863625 -0.267852783203125 -0.0035400390625 -0.9866333007812484 +1.86375 -0.267852783203125 -0.0035400390625 -0.9866333007812484 +1.863875 -0.263427734375 -0.00347900390625 -0.9866333007812484 +1.864 -0.263427734375 -0.00347900390625 -0.9866333007812484 +1.864125 -0.25897216796875 -0.00341796875 -0.9866333007812484 +1.86425 -0.25445556640625 -0.00335693359375 -0.9866333007812484 +1.86437500000000016 -0.25445556640625 -0.00335693359375 -0.9866333007812484 +1.8645 -0.249969482421875 -0.0032958984375 -0.9866333007812484 +1.864625 -0.249969482421875 -0.0032958984375 -0.9866333007812484 +1.86475000000000016 -0.24542236328125 -0.00323486328125 -0.9866333007812484 +1.864875 -0.2408447265625 -0.003173828125 -0.9866333007812484 +1.865 -0.2408447265625 -0.003173828125 -0.9866333007812484 +1.86512500000000016 -0.236236572265625 -0.00311279296875 -0.9866333007812484 +1.86525 -0.236236572265625 -0.00311279296875 -0.9866333007812484 +1.865375 -0.231597900390625 -0.0030517578125 -0.9866333007812484 +1.8655 -0.226959228515625 -0.00299072265625 -0.9866333007812484 +1.865625 -0.226959228515625 -0.00299072265625 -0.9866333007812484 +1.86575 -0.2222900390625 -0.0029296875 -0.9866333007812484 +1.865875 -0.2222900390625 -0.0029296875 -0.9866333007812484 +1.866 -0.21759033203125 -0.00286865234375 -0.9866333007812484 +1.866125 -0.212860107421875 -0.0028076171875 -0.9866333007812484 +1.86625 -0.212860107421875 -0.0028076171875 -0.9866333007812484 +1.86637500000000016 -0.208099365234375 -0.00274658203125 -0.9866333007812484 +1.8665 -0.208099365234375 -0.00274658203125 -0.9866333007812484 +1.866625 -0.203338623046875 -0.002685546875 -0.9866333007812484 +1.86675000000000016 -0.19854736328125 -0.00262451171875 -0.9866333007812484 +1.866875 -0.19854736328125 -0.00262451171875 -0.9866333007812484 +1.867 -0.1937255859375 -0.0025634765625 -0.9866333007812484 +1.867125000000000256 -0.1937255859375 -0.0025634765625 -0.9866333007812484 +1.86725 -0.188873291015625 -0.00250244140625 -0.9866333007812484 +1.867375 -0.18402099609375 -0.00244140625 -0.9866333007812484 +1.8675 -0.18402099609375 -0.00244140625 -0.9866333007812484 +1.867625 -0.17913818359375 -0.002349853515625 -0.9866333007812484 +1.86775 -0.17913818359375 -0.002349853515625 -0.9866333007812484 +1.867875 -0.17425537109375 -0.002288818359375 -0.9866333007812484 +1.868 -0.169342041015625 -0.002227783203125 -0.9866333007812484 +1.868125 -0.169342041015625 -0.002227783203125 -0.9866333007812484 +1.86825 -0.164398193359375 -0.002166748046875 -0.9866333007812484 +1.86837500000000016 -0.164398193359375 -0.002166748046875 -0.9866333007812484 +1.8685 -0.159454345703125 -0.002105712890625 -0.9866333007812484 +1.868625 -0.15447998046875 -0.002044677734375 -0.9866333007812484 +1.86875000000000016 -0.15447998046875 -0.002044677734375 -0.9866333007812484 +1.868875 -0.14947509765625 -0.001983642578125 -0.9866333007812484 +1.869 -0.14947509765625 -0.001983642578125 -0.9866333007812484 +1.869125000000000256 -0.14447021484375 -0.00189208984375 -0.9866333007812484 +1.86925 -0.13946533203125 -0.0018310546875 -0.9866333007812484 +1.869375 -0.13946533203125 -0.0018310546875 -0.9866333007812484 +1.8695 -0.134429931640625 -0.00177001953125 -0.9866333007812484 +1.869625 -0.134429931640625 -0.00177001953125 -0.9866333007812484 +1.86975 -0.129364013671875 -0.001708984375 -0.9866333007812484 +1.869875 -0.124298095703125 -0.00164794921875 -0.9866333007812484 +1.87 -0.124298095703125 -0.00164794921875 -0.9866333007812484 +1.870125 -0.119232177734375 -0.001556396484375 -0.9866333007812484 +1.87025 -0.119232177734375 -0.001556396484375 -0.9866333007812484 +1.87037500000000016 -0.1141357421875 -0.001495361328125 -0.9866333007812484 +1.8705 -0.109039306640625 -0.001434326171875 -0.9866333007812484 +1.870625 -0.109039306640625 -0.001434326171875 -0.9866333007812484 +1.87075000000000016 -0.103912353515625 -0.001373291015625 -0.9866333007812484 +1.870875 -0.103912353515625 -0.001373291015625 -0.9866333007812484 +1.871 -0.098785400390625 -0.00128173828125 -0.9866333007812484 +1.871125000000000256 -0.093658447265625 -0.001220703125 -0.9866333007812484 +1.87125 -0.093658447265625 -0.001220703125 -0.9866333007812484 +1.871375 -0.0885009765625 -0.00115966796875 -0.9866333007812484 +1.8715 -0.0885009765625 -0.00115966796875 -0.9866333007812484 +1.871625 -0.083343505859375 -0.0010986328125 -0.9866333007812484 +1.87175 -0.07818603515625 -0.00103759765625 -0.9866333007812484 +1.871875 -0.07818603515625 -0.00103759765625 -0.9866333007812484 +1.872 -0.072998046875 -0.000946044921875 -0.9866333007812484 +1.872125 -0.072998046875 -0.000946044921875 -0.9866333007812484 +1.87225 -0.06781005859375 -0.000885009765625 -0.9866333007812484 +1.87237500000000016 -0.0626220703125 -0.000823974609375 -0.9866333007812484 +1.8725 -0.0626220703125 -0.000823974609375 -0.9866333007812484 +1.872625 -0.05743408203125 -0.000732421875 -0.9866333007812484 +1.87275000000000016 -0.05743408203125 -0.000732421875 -0.9866333007812484 +1.872875 -0.05224609375 -0.00067138671875 -0.9866333007812484 +1.873 -0.047027587890625 -0.0006103515625 -0.9866333007812484 +1.873125 -0.047027587890625 -0.0006103515625 -0.9866333007812484 +1.87325 -0.04180908203125 -0.00054931640625 -0.9866333007812484 +1.873375 -0.04180908203125 -0.00054931640625 -0.9866333007812484 +1.8735 -0.036590576171875 -0.000457763671875 -0.9866333007812484 +1.873625 -0.0313720703125 -0.000396728515625 -0.9866333007812484 +1.87375 -0.0313720703125 -0.000396728515625 -0.9866333007812484 +1.873875 -0.026123046875 -0.000335693359375 -0.9866333007812484 +1.874 -0.026123046875 -0.000335693359375 -0.9866333007812484 +1.874125 -0.020904541015625 -0.000274658203125 -0.9866333007812484 +1.87425 -0.01568603515625 -0.00018310546875 -0.9866333007812484 +1.87437500000000016 -0.01568603515625 -0.00018310546875 -0.9866333007812484 +1.8745 -0.01043701171875 -0.0001220703125 -0.9866333007812484 +1.874625 -0.01043701171875 -0.0001220703125 -0.9866333007812484 +1.87475000000000016 -0.005218505859375 -6.103515625e-05 -0.9866333007812484 +1.874875 0.0 0.0 -0.9866333007812484 +1.875 0.0 0.0 -0.9866333007812484 +1.875125 0.005218505859375 6.103515625e-05 -0.9866333007812484 +1.87525 0.005218505859375 6.103515625e-05 -0.9866333007812484 +1.875375 0.01043701171875 0.0001220703125 -0.9866333007812484 +1.8755 0.01568603515625 0.00018310546875 -0.9866333007812484 +1.875625 0.01568603515625 0.00018310546875 -0.9866333007812484 +1.87575 0.020904541015625 0.000274658203125 -0.9866333007812484 +1.875875 0.020904541015625 0.000274658203125 -0.9866333007812484 +1.87600000000000016 0.026123046875 0.000335693359375 -0.9866333007812484 +1.876125 0.0313720703125 0.000396728515625 -0.9866333007812484 +1.87625 0.0313720703125 0.000396728515625 -0.9866333007812484 +1.87637500000000016 0.036590576171875 0.000457763671875 -0.9866333007812484 +1.8765 0.036590576171875 0.000457763671875 -0.9866333007812484 +1.876625 0.04180908203125 0.00054931640625 -0.9866333007812484 +1.87675000000000016 0.047027587890625 0.0006103515625 -0.9866333007812484 +1.876875 0.047027587890625 0.0006103515625 -0.9866333007812484 +1.877 0.05224609375 0.00067138671875 -0.9866333007812484 +1.877125 0.05224609375 0.00067138671875 -0.9866333007812484 +1.87725 0.05743408203125 0.000732421875 -0.9866333007812484 +1.877375 0.0626220703125 0.000823974609375 -0.9866333007812484 +1.8775 0.0626220703125 0.000823974609375 -0.9866333007812484 +1.877625 0.06781005859375 0.000885009765625 -0.9866333007812484 +1.87775 0.06781005859375 0.000885009765625 -0.9866333007812484 +1.877875 0.072998046875 0.000946044921875 -0.9866333007812484 +1.87800000000000016 0.07818603515625 0.00103759765625 -0.9866333007812484 +1.878125 0.07818603515625 0.00103759765625 -0.9866333007812484 +1.87825 0.083343505859375 0.0010986328125 -0.9866333007812484 +1.87837500000000016 0.083343505859375 0.0010986328125 -0.9866333007812484 +1.8785 0.0885009765625 0.00115966796875 -0.9866333007812484 +1.878625 0.093658447265625 0.001220703125 -0.9866333007812484 +1.87875000000000016 0.093658447265625 0.001220703125 -0.9866333007812484 +1.878875 0.098785400390625 0.00128173828125 -0.9866333007812484 +1.879 0.098785400390625 0.00128173828125 -0.9866333007812484 +1.879125 0.103912353515625 0.001373291015625 -0.9866333007812484 +1.87925 0.109039306640625 0.001434326171875 -0.9866333007812484 +1.879375 0.109039306640625 0.001434326171875 -0.9866333007812484 +1.8795 0.1141357421875 0.001495361328125 -0.9866333007812484 +1.879625 0.1141357421875 0.001495361328125 -0.9866333007812484 +1.87975 0.119232177734375 0.001556396484375 -0.9866333007812484 +1.879875 0.124298095703125 0.00164794921875 -0.9866333007812484 +1.88000000000000016 0.124298095703125 0.00164794921875 -0.9866333007812484 +1.880125 0.129364013671875 0.001708984375 -0.9866333007812484 +1.88025 0.129364013671875 0.001708984375 -0.9866333007812484 +1.88037500000000016 0.134429931640625 0.00177001953125 -0.9866333007812484 +1.8805 0.13946533203125 0.0018310546875 -0.9866333007812484 +1.880625 0.13946533203125 0.0018310546875 -0.9866333007812484 +1.88075000000000016 0.14447021484375 0.00189208984375 -0.9866333007812484 +1.880875 0.14447021484375 0.00189208984375 -0.9866333007812484 +1.881 0.14947509765625 0.001983642578125 -0.9866333007812484 +1.881125 0.15447998046875 0.002044677734375 -0.9866333007812484 +1.88125 0.15447998046875 0.002044677734375 -0.9866333007812484 +1.881375 0.159454345703125 0.002105712890625 -0.9866333007812484 +1.8815 0.159454345703125 0.002105712890625 -0.9866333007812484 +1.881625 0.164398193359375 0.002166748046875 -0.9866333007812484 +1.88175 0.169342041015625 0.002227783203125 -0.9866333007812484 +1.881875 0.169342041015625 0.002227783203125 -0.9866333007812484 +1.88200000000000016 0.17425537109375 0.002288818359375 -0.9866333007812484 +1.882125 0.17425537109375 0.002288818359375 -0.9866333007812484 +1.88225 0.17913818359375 0.002349853515625 -0.9866333007812484 +1.88237500000000016 0.18402099609375 0.00244140625 -0.9866333007812484 +1.8825 0.18402099609375 0.00244140625 -0.9866333007812484 +1.882625 0.188873291015625 0.00250244140625 -0.9866333007812484 +1.882750000000000256 0.188873291015625 0.00250244140625 -0.9866333007812484 +1.882875 0.1937255859375 0.0025634765625 -0.9866333007812484 +1.883 0.19854736328125 0.00262451171875 -0.9866333007812484 +1.883125 0.19854736328125 0.00262451171875 -0.9866333007812484 +1.88325 0.203338623046875 0.002685546875 -0.9866333007812484 +1.883375 0.203338623046875 0.002685546875 -0.9866333007812484 +1.8835 0.208099365234375 0.00274658203125 -0.9866333007812484 +1.883625 0.212860107421875 0.0028076171875 -0.9866333007812484 +1.88375 0.212860107421875 0.0028076171875 -0.9866333007812484 +1.883875 0.21759033203125 0.00286865234375 -0.9866333007812484 +1.88400000000000016 0.21759033203125 0.00286865234375 -0.9866333007812484 +1.884125 0.2222900390625 0.0029296875 -0.9866333007812484 +1.88425 0.226959228515625 0.00299072265625 -0.9866333007812484 +1.88437500000000016 0.226959228515625 0.00299072265625 -0.9866333007812484 +1.8845 0.231597900390625 0.0030517578125 -0.9866333007812484 +1.884625 0.231597900390625 0.0030517578125 -0.9866333007812484 +1.884750000000000256 0.236236572265625 0.00311279296875 -0.9866333007812484 +1.884875 0.2408447265625 0.003173828125 -0.9866333007812484 +1.885 0.2408447265625 0.003173828125 -0.9866333007812484 +1.885125 0.24542236328125 0.00323486328125 -0.9866333007812484 +1.88525 0.24542236328125 0.00323486328125 -0.9866333007812484 +1.885375 0.249969482421875 0.0032958984375 -0.9866333007812484 +1.8855 0.25445556640625 0.00335693359375 -0.9866333007812484 +1.885625 0.25445556640625 0.00335693359375 -0.9866333007812484 +1.88575 0.25897216796875 0.00341796875 -0.9866333007812484 +1.885875 0.25897216796875 0.00341796875 -0.9866333007812484 +1.88600000000000016 0.263427734375 0.00347900390625 -0.9866333007812484 +1.886125 0.267852783203125 0.0035400390625 -0.9866333007812484 +1.88625 0.267852783203125 0.0035400390625 -0.9866333007812484 +1.88637500000000016 0.27227783203125 0.00360107421875 -0.9866333007812484 +1.8865 0.27227783203125 0.00360107421875 -0.9866333007812484 +1.886625 0.276641845703125 0.003662109375 -0.9866333007812484 +1.886750000000000256 0.280975341796875 0.00372314453125 -0.9866333007812484 +1.886875 0.280975341796875 0.00372314453125 -0.9866333007812484 +1.887 0.285308837890625 0.0037841796875 -0.9866333007812484 +1.887125 0.285308837890625 0.0037841796875 -0.9866333007812484 +1.88725 0.289581298828125 0.003814697265625 -0.9866333007812484 +1.887375 0.2938232421875 0.003875732421875 -0.9866333007812484 +1.8875 0.2938232421875 0.003875732421875 -0.9866333007812484 +1.887625 0.298065185546875 0.003936767578125 -0.9866333007812484 +1.88775 0.298065185546875 0.003936767578125 -0.9866333007812484 +1.887875 0.30224609375 0.003997802734375 -0.9866333007812484 +1.88800000000000016 0.306396484375 0.04766845703125 -0.8442993164062446 +1.888125 0.306396484375 0.04766845703125 -0.8442993164062446 +1.88825 0.310516357421875 0.048309326171875 -0.8442993164062446 +1.88837500000000016 0.310516357421875 0.048309326171875 -0.8442993164062446 +1.8885 0.314605712890625 0.0489501953125 -0.8442993164062446 +1.888625 0.31866455078125 0.049591064453125 -0.8442993164062446 +1.88875 0.31866455078125 0.049591064453125 -0.8442993164062446 +1.888875 0.322662353515625 0.050201416015625 -0.8442993164062446 +1.889 0.322662353515625 0.050201416015625 -0.8442993164062446 +1.889125 0.32666015625 0.050811767578125 -0.8442993164062446 +1.88925 0.330596923828125 0.051422119140625 -0.8442993164062446 +1.889375 0.330596923828125 0.051422119140625 -0.8442993164062446 +1.8895 0.334503173828125 0.052032470703125 -0.8442993164062446 +1.889625 0.334503173828125 0.052032470703125 -0.8442993164062446 +1.88975 0.33837890625 0.052642822265625 -0.8442993164062446 +1.889875 0.34222412109375 0.053253173828125 -0.8442993164062446 +1.89000000000000016 0.34222412109375 0.053253173828125 -0.8442993164062446 +1.890125 0.34600830078125 0.0538330078125 -0.8442993164062446 +1.89025 0.34600830078125 0.0538330078125 -0.8442993164062446 +1.89037500000000016 0.349761962890625 0.054412841796875 -0.8442993164062446 +1.8905 0.353485107421875 0.05499267578125 -0.8442993164062446 +1.890625 0.353485107421875 0.05499267578125 -0.8442993164062446 +1.89075 0.357177734375 0.055572509765625 -0.8442993164062446 +1.890875 0.357177734375 0.055572509765625 -0.8442993164062446 +1.891 0.360809326171875 0.05615234375 -0.8442993164062446 +1.891125 0.36444091796875 0.05670166015625 -0.8442993164062446 +1.89125 0.36444091796875 0.05670166015625 -0.8442993164062446 +1.891375 0.36798095703125 0.0572509765625 -0.8442993164062446 +1.8915 0.36798095703125 0.0572509765625 -0.8442993164062446 +1.89162500000000016 0.37152099609375 0.05780029296875 -0.8442993164062446 +1.89175 0.375 0.058349609375 -0.8442993164062446 +1.891875 0.375 0.058349609375 -0.8442993164062446 +1.89200000000000016 0.378448486328125 0.058868408203125 -0.8442993164062446 +1.892125 0.378448486328125 0.058868408203125 -0.8442993164062446 +1.89225 0.3818359375 0.059417724609375 -0.8442993164062446 +1.89237500000000016 0.38519287109375 0.0599365234375 -0.8442993164062446 +1.8925 0.38519287109375 0.0599365234375 -0.8442993164062446 +1.892625 0.388519287109375 0.060455322265625 -0.8442993164062446 +1.89275 0.388519287109375 0.060455322265625 -0.8442993164062446 +1.892875 0.39178466796875 0.060943603515625 -0.8442993164062446 +1.893 0.39501953125 0.06146240234375 -0.8442993164062446 +1.893125 0.39501953125 0.06146240234375 -0.8442993164062446 +1.89325 0.398193359375 0.06195068359375 -0.8442993164062446 +1.893375 0.398193359375 0.06195068359375 -0.8442993164062446 +1.8935 0.401336669921875 0.06243896484375 -0.8442993164062446 +1.89362500000000016 0.404449462890625 0.06292724609375 -0.8442993164062446 +1.89375 0.404449462890625 0.06292724609375 -0.8442993164062446 +1.893875 0.407501220703125 0.06341552734375 -0.8442993164062446 +1.89400000000000016 0.407501220703125 0.06341552734375 -0.8442993164062446 +1.894125 0.4105224609375 0.063873291015625 -0.8442993164062446 +1.89425 0.413482666015625 0.0643310546875 -0.8442993164062446 +1.89437500000000016 0.413482666015625 0.0643310546875 -0.8442993164062446 +1.8945 0.416412353515625 0.064788818359375 -0.8442993164062446 +1.894625 0.416412353515625 0.064788818359375 -0.8442993164062446 +1.89475 0.419281005859375 0.06524658203125 -0.8442993164062446 +1.894875 0.422119140625 0.065673828125 -0.8442993164062446 +1.895 0.422119140625 0.065673828125 -0.8442993164062446 +1.895125 0.424896240234375 0.06610107421875 -0.8442993164062446 +1.89525 0.424896240234375 0.06610107421875 -0.8442993164062446 +1.895375 0.4276123046875 0.0665283203125 -0.8442993164062446 +1.8955 0.4302978515625 0.06695556640625 -0.8442993164062446 +1.89562500000000016 0.4302978515625 0.06695556640625 -0.8442993164062446 +1.89575 0.432952880859375 0.067352294921875 -0.8442993164062446 +1.895875 0.432952880859375 0.067352294921875 -0.8442993164062446 +1.89600000000000016 0.435546875 0.067779541015625 -0.8442993164062446 +1.896125 0.438079833984375 0.06817626953125 -0.8442993164062446 +1.89625 0.438079833984375 0.06817626953125 -0.8442993164062446 +1.89637500000000016 0.440582275390625 0.06854248046875 -0.8442993164062446 +1.8965 0.440582275390625 0.06854248046875 -0.8442993164062446 +1.896625 0.44305419921875 0.068939208984375 -0.8442993164062446 +1.89675 0.4454345703125 0.069305419921875 -0.8442993164062446 +1.896875 0.4454345703125 0.069305419921875 -0.8442993164062446 +1.897 0.447784423828125 0.069671630859375 -0.8442993164062446 +1.897125 0.447784423828125 0.069671630859375 -0.8442993164062446 +1.89725 0.450103759765625 0.070037841796875 -0.8442993164062446 +1.897375 0.452362060546875 0.07037353515625 -0.8442993164062446 +1.8975 0.452362060546875 0.07037353515625 -0.8442993164062446 +1.89762500000000016 0.454559326171875 0.070709228515625 -0.8442993164062446 +1.89775 0.454559326171875 0.070709228515625 -0.8442993164062446 +1.897875 0.45672607421875 0.071075439453125 -0.8442993164062446 +1.89800000000000016 0.458831787109375 0.071380615234375 -0.8442993164062446 +1.898125 0.458831787109375 0.071380615234375 -0.8442993164062446 +1.89825 0.46087646484375 0.07171630859375 -0.8442993164062446 +1.898375000000000256 0.46087646484375 0.07171630859375 -0.8442993164062446 +1.8985 0.462890625 0.072021484375 -0.8442993164062446 +1.898625 0.464813232421875 0.07232666015625 -0.8442993164062446 +1.89875 0.464813232421875 0.07232666015625 -0.8442993164062446 +1.898875 0.46673583984375 0.0726318359375 -0.8442993164062446 +1.899 0.46673583984375 0.0726318359375 -0.8442993164062446 +1.899125 0.46856689453125 0.072906494140625 -0.8442993164062446 +1.89925 0.470367431640625 0.07318115234375 -0.8442993164062446 +1.899375 0.470367431640625 0.07318115234375 -0.8442993164062446 +1.8995 0.472137451171875 0.073455810546875 -0.8442993164062446 +1.89962500000000016 0.472137451171875 0.073455810546875 -0.8442993164062446 +1.89975 0.47381591796875 0.07373046875 -0.8442993164062446 +1.899875 0.4754638671875 0.073974609375 -0.8442993164062446 +1.90000000000000016 0.4754638671875 0.073974609375 -0.8442993164062446 +1.900125 0.47705078125 0.07421875 -0.8442993164062446 +1.90025 0.47705078125 0.07421875 -0.8442993164062446 +1.900375000000000256 0.478607177734375 0.074462890625 -0.8442993164062446 +1.9005 0.480072021484375 0.07470703125 -0.8442993164062446 +1.900625 0.480072021484375 0.07470703125 -0.8442993164062446 +1.90075 0.48150634765625 0.074920654296875 -0.8442993164062446 +1.900875 0.48150634765625 0.074920654296875 -0.8442993164062446 +1.901 0.48291015625 0.07513427734375 -0.8442993164062446 +1.901125 0.484222412109375 0.075347900390625 -0.8442993164062446 +1.90125 0.484222412109375 0.075347900390625 -0.8442993164062446 +1.901375 0.485504150390625 0.075531005859375 -0.8442993164062446 +1.9015 0.485504150390625 0.075531005859375 -0.8442993164062446 +1.90162500000000016 0.486724853515625 0.07574462890625 -0.8442993164062446 +1.90175 0.487884521484375 0.075897216796875 -0.8442993164062446 +1.901875 0.487884521484375 0.075897216796875 -0.8442993164062446 +1.90200000000000016 0.489013671875 0.076080322265625 -0.8442993164062446 +1.902125 0.489013671875 0.076080322265625 -0.8442993164062446 +1.90225 0.490081787109375 0.076263427734375 -0.8442993164062446 +1.902375000000000256 0.4910888671875 0.076416015625 -0.8442993164062446 +1.9025 0.4910888671875 0.076416015625 -0.8442993164062446 +1.902625 0.492034912109375 0.076568603515625 -0.8442993164062446 +1.90275 0.492034912109375 0.076568603515625 -0.8442993164062446 +1.902875 0.492950439453125 0.076690673828125 -0.8442993164062446 +1.903 0.4937744140625 0.076812744140625 -0.8442993164062446 +1.903125 0.4937744140625 0.076812744140625 -0.8442993164062446 +1.90325 0.49456787109375 0.07696533203125 -0.8442993164062446 +1.903375 0.49456787109375 0.07696533203125 -0.8442993164062446 +1.9035 0.49530029296875 0.077056884765625 -0.8442993164062446 +1.90362500000000016 0.496002197265625 0.077178955078125 -0.8442993164062446 +1.90375 0.496002197265625 0.077178955078125 -0.8442993164062446 +1.903875 0.496612548828125 0.0772705078125 -0.8442993164062446 +1.90400000000000016 0.496612548828125 0.0772705078125 -0.8442993164062446 +1.904125 0.4971923828125 0.077362060546875 -0.8442993164062446 +1.90425 0.497711181640625 0.07745361328125 -0.8442993164062446 +1.904375 0.497711181640625 0.07745361328125 -0.8442993164062446 +1.9045 0.498199462890625 0.0775146484375 -0.8442993164062446 +1.904625 0.498199462890625 0.0775146484375 -0.8442993164062446 +1.90475 0.49859619140625 0.07757568359375 -0.8442993164062446 +1.904875 0.49896240234375 0.07763671875 -0.8442993164062446 +1.905 0.49896240234375 0.07763671875 -0.8442993164062446 +1.905125 0.499267578125 0.077667236328125 -0.8442993164062446 +1.90525 0.499267578125 0.077667236328125 -0.8442993164062446 +1.905375 0.49951171875 0.077728271484375 -0.8442993164062446 +1.9055 0.49969482421875 0.0777587890625 -0.8442993164062446 +1.90562500000000016 0.49969482421875 0.0777587890625 -0.8442993164062446 +1.90575 0.49981689453125 0.0777587890625 -0.8442993164062446 +1.905875 0.49981689453125 0.0777587890625 -0.8442993164062446 +1.90600000000000016 0.499908447265625 0.077789306640625 -0.8442993164062446 +1.906125 0.49993896484375 0.077789306640625 -0.8442993164062446 +1.90625 0.49993896484375 0.077789306640625 -0.8442993164062446 +1.906375 0.499908447265625 0.077789306640625 -0.8442993164062446 +1.9065 0.499908447265625 0.077789306640625 -0.8442993164062446 +1.906625 0.49981689453125 0.0777587890625 -0.8442993164062446 +1.90675 0.49969482421875 0.0777587890625 -0.8442993164062446 +1.906875 0.49969482421875 0.0777587890625 -0.8442993164062446 +1.907 0.49951171875 0.077728271484375 -0.8442993164062446 +1.907125 0.49951171875 0.077728271484375 -0.8442993164062446 +1.90725000000000016 0.499267578125 0.077667236328125 -0.8442993164062446 +1.907375 0.49896240234375 0.07763671875 -0.8442993164062446 +1.9075 0.49896240234375 0.07763671875 -0.8442993164062446 +1.90762500000000016 0.49859619140625 0.07757568359375 -0.8442993164062446 +1.90775 0.49859619140625 0.07757568359375 -0.8442993164062446 +1.907875 0.498199462890625 0.0775146484375 -0.8442993164062446 +1.90800000000000016 0.497711181640625 0.07745361328125 -0.8442993164062446 +1.908125 0.497711181640625 0.07745361328125 -0.8442993164062446 +1.90825 0.4971923828125 0.077362060546875 -0.8442993164062446 +1.908375 0.4971923828125 0.077362060546875 -0.8442993164062446 +1.9085 0.496612548828125 0.0772705078125 -0.8442993164062446 +1.908625 0.496002197265625 0.077178955078125 -0.8442993164062446 +1.90875 0.496002197265625 0.077178955078125 -0.8442993164062446 +1.908875 0.49530029296875 0.077056884765625 -0.8442993164062446 +1.909 0.49530029296875 0.077056884765625 -0.8442993164062446 +1.909125 0.49456787109375 0.07696533203125 -0.8442993164062446 +1.90925000000000016 0.4937744140625 0.076812744140625 -0.8442993164062446 +1.909375 0.4937744140625 0.076812744140625 -0.8442993164062446 +1.9095 0.492950439453125 0.076690673828125 -0.8442993164062446 +1.90962500000000016 0.492950439453125 0.076690673828125 -0.8442993164062446 +1.90975 0.492034912109375 0.076568603515625 -0.8442993164062446 +1.909875 0.4910888671875 0.076416015625 -0.8442993164062446 +1.91000000000000016 0.4910888671875 0.076416015625 -0.8442993164062446 +1.910125 0.490081787109375 0.076263427734375 -0.8442993164062446 +1.91025 0.490081787109375 0.076263427734375 -0.8442993164062446 +1.910375 0.489013671875 0.076080322265625 -0.8442993164062446 +1.9105 0.487884521484375 0.075897216796875 -0.8442993164062446 +1.910625 0.487884521484375 0.075897216796875 -0.8442993164062446 +1.91075 0.486724853515625 0.07574462890625 -0.8442993164062446 +1.910875 0.486724853515625 0.07574462890625 -0.8442993164062446 +1.911 0.485504150390625 0.075531005859375 -0.8442993164062446 +1.911125 0.484222412109375 0.075347900390625 -0.8442993164062446 +1.91125000000000016 0.484222412109375 0.075347900390625 -0.8442993164062446 +1.911375 0.48291015625 0.07513427734375 -0.8442993164062446 +1.9115 0.48291015625 0.07513427734375 -0.8442993164062446 +1.91162500000000016 0.48150634765625 0.074920654296875 -0.8442993164062446 +1.91175 0.480072021484375 0.07470703125 -0.8442993164062446 +1.911875 0.480072021484375 0.07470703125 -0.8442993164062446 +1.91200000000000016 0.478607177734375 0.074462890625 -0.8442993164062446 +1.912125 0.478607177734375 0.074462890625 -0.8442993164062446 +1.91225 0.47705078125 0.07421875 -0.8442993164062446 +1.912375 0.4754638671875 0.073974609375 -0.8442993164062446 +1.9125 0.4754638671875 0.073974609375 -0.8442993164062446 +1.912625 0.47381591796875 0.07373046875 -0.8442993164062446 +1.91275 0.47381591796875 0.07373046875 -0.8442993164062446 +1.912875 0.472137451171875 0.073455810546875 -0.8442993164062446 +1.913 0.470367431640625 0.07318115234375 -0.8442993164062446 +1.913125 0.470367431640625 0.07318115234375 -0.8442993164062446 +1.91325000000000016 0.46856689453125 0.072906494140625 -0.8442993164062446 +1.913375 0.46856689453125 0.072906494140625 -0.8442993164062446 +1.9135 0.46673583984375 0.0726318359375 -0.8442993164062446 +1.91362500000000016 0.464813232421875 0.07232666015625 -0.8442993164062446 +1.91375 0.464813232421875 0.07232666015625 -0.8442993164062446 +1.913875 0.462890625 0.072021484375 -0.8442993164062446 +1.914000000000000256 0.462890625 0.072021484375 -0.8442993164062446 +1.914125 0.46087646484375 0.07171630859375 -0.8442993164062446 +1.91425 0.458831787109375 0.071380615234375 -0.8442993164062446 +1.914375 0.458831787109375 0.071380615234375 -0.8442993164062446 +1.9145 0.45672607421875 0.071075439453125 -0.8442993164062446 +1.914625 0.45672607421875 0.071075439453125 -0.8442993164062446 +1.91475 0.454559326171875 0.070709228515625 -0.8442993164062446 +1.914875 0.452362060546875 0.07037353515625 -0.8442993164062446 +1.915 0.452362060546875 0.07037353515625 -0.8442993164062446 +1.915125 0.450103759765625 0.070037841796875 -0.8442993164062446 +1.91525000000000016 0.450103759765625 0.070037841796875 -0.8442993164062446 +1.915375 0.447784423828125 0.069671630859375 -0.8442993164062446 +1.9155 0.4454345703125 0.069305419921875 -0.8442993164062446 +1.91562500000000016 0.4454345703125 0.069305419921875 -0.8442993164062446 +1.91575 0.44305419921875 0.068939208984375 -0.8442993164062446 +1.915875 0.44305419921875 0.068939208984375 -0.8442993164062446 +1.916000000000000256 0.440582275390625 0.06854248046875 -0.8442993164062446 +1.916125 0.438079833984375 0.06817626953125 -0.8442993164062446 +1.91625 0.438079833984375 0.06817626953125 -0.8442993164062446 +1.916375 0.435546875 0.067779541015625 -0.8442993164062446 +1.9165 0.435546875 0.067779541015625 -0.8442993164062446 +1.916625 0.432952880859375 0.067352294921875 -0.8442993164062446 +1.91675 0.4302978515625 0.06695556640625 -0.8442993164062446 +1.916875 0.4302978515625 0.06695556640625 -0.8442993164062446 +1.917 0.4276123046875 0.0665283203125 -0.8442993164062446 +1.917125 0.4276123046875 0.0665283203125 -0.8442993164062446 +1.91725000000000016 0.424896240234375 0.06610107421875 -0.8442993164062446 +1.917375 0.422119140625 0.065673828125 -0.8442993164062446 +1.9175 0.422119140625 0.065673828125 -0.8442993164062446 +1.91762500000000016 0.419281005859375 0.06524658203125 -0.8442993164062446 +1.91775 0.419281005859375 0.06524658203125 -0.8442993164062446 +1.917875 0.416412353515625 0.064788818359375 -0.8442993164062446 +1.918000000000000256 0.413482666015625 0.0643310546875 -0.8442993164062446 +1.918125 0.413482666015625 0.0643310546875 -0.8442993164062446 +1.91825 0.4105224609375 0.063873291015625 -0.8442993164062446 +1.918375 0.4105224609375 0.063873291015625 -0.8442993164062446 +1.9185 0.407501220703125 0.06341552734375 -0.8442993164062446 +1.918625 0.404449462890625 0.06292724609375 -0.8442993164062446 +1.91875 0.404449462890625 0.06292724609375 -0.8442993164062446 +1.918875 0.401336669921875 0.06243896484375 -0.8442993164062446 +1.919 0.401336669921875 0.06243896484375 -0.8442993164062446 +1.919125 0.398193359375 0.06195068359375 -0.8442993164062446 +1.91925000000000016 0.39501953125 0.06146240234375 -0.8442993164062446 +1.919375 0.39501953125 0.06146240234375 -0.8442993164062446 +1.9195 0.39178466796875 0.060943603515625 -0.8442993164062446 +1.91962500000000016 0.39178466796875 0.060943603515625 -0.8442993164062446 +1.91975 0.388519287109375 0.060455322265625 -0.8442993164062446 +1.919875 0.38519287109375 0.0599365234375 -0.8442993164062446 +1.92 0.38519287109375 0.166656494140625 -0.5672241210937414 +1.920125 0.3818359375 0.16522216796875 -0.5672241210937414 +1.92025 0.3818359375 0.16522216796875 -0.5672241210937414 +1.920375 0.378448486328125 0.16375732421875 -0.5672241210937414 +1.9205 0.375 0.162261962890625 -0.5672241210937414 +1.920625 0.375 0.162261962890625 -0.5672241210937414 +1.92075 0.37152099609375 0.160736083984375 -0.5672241210937414 +1.920875 0.37152099609375 0.160736083984375 -0.5672241210937414 +1.921 0.36798095703125 0.159210205078125 -0.5672241210937414 +1.921125 0.36444091796875 0.157684326171875 -0.5672241210937414 +1.92125000000000016 0.36444091796875 0.157684326171875 -0.5672241210937414 +1.921375 0.360809326171875 0.1561279296875 -0.5672241210937414 +1.9215 0.360809326171875 0.1561279296875 -0.5672241210937414 +1.92162500000000016 0.357177734375 0.154541015625 -0.5672241210937414 +1.92175 0.353485107421875 0.1529541015625 -0.5672241210937414 +1.921875 0.353485107421875 0.1529541015625 -0.5672241210937414 +1.922 0.349761962890625 0.151336669921875 -0.5672241210937414 +1.922125 0.349761962890625 0.151336669921875 -0.5672241210937414 +1.92225 0.34600830078125 0.14971923828125 -0.5672241210937414 +1.922375 0.34222412109375 0.1480712890625 -0.5672241210937414 +1.9225 0.34222412109375 0.1480712890625 -0.5672241210937414 +1.922625 0.33837890625 0.14642333984375 -0.5672241210937414 +1.92275 0.33837890625 0.14642333984375 -0.5672241210937414 +1.92287500000000016 0.334503173828125 0.144744873046875 -0.5672241210937414 +1.923 0.330596923828125 0.143035888671875 -0.5672241210937414 +1.923125 0.330596923828125 0.143035888671875 -0.5672241210937414 +1.92325000000000016 0.32666015625 0.141326904296875 -0.5672241210937414 +1.923375 0.32666015625 0.141326904296875 -0.5672241210937414 +1.9235 0.322662353515625 0.139617919921875 -0.5672241210937414 +1.92362500000000016 0.31866455078125 0.13787841796875 -0.5672241210937414 +1.92375 0.31866455078125 0.13787841796875 -0.5672241210937414 +1.923875 0.314605712890625 0.1361083984375 -0.5672241210937414 +1.924 0.314605712890625 0.1361083984375 -0.5672241210937414 +1.924125 0.310516357421875 0.134368896484375 -0.5672241210937414 +1.92425 0.306396484375 0.132568359375 -0.5672241210937414 +1.924375 0.306396484375 0.132568359375 -0.5672241210937414 +1.9245 0.30224609375 0.130767822265625 -0.5672241210937414 +1.924625 0.30224609375 0.130767822265625 -0.5672241210937414 +1.92475 0.298065185546875 0.12896728515625 -0.5672241210937414 +1.92487500000000016 0.2938232421875 0.12713623046875 -0.5672241210937414 +1.925 0.2938232421875 0.12713623046875 -0.5672241210937414 +1.925125 0.289581298828125 0.12530517578125 -0.5672241210937414 +1.92525000000000016 0.289581298828125 0.12530517578125 -0.5672241210937414 +1.925375 0.285308837890625 0.123443603515625 -0.5672241210937414 +1.9255 0.280975341796875 0.12158203125 -0.5672241210937414 +1.92562500000000016 0.280975341796875 0.12158203125 -0.5672241210937414 +1.92575 0.276641845703125 0.11968994140625 -0.5672241210937414 +1.925875 0.276641845703125 0.11968994140625 -0.5672241210937414 +1.926 0.27227783203125 0.1177978515625 -0.5672241210937414 +1.926125 0.267852783203125 0.11590576171875 -0.5672241210937414 +1.92625 0.267852783203125 0.11590576171875 -0.5672241210937414 +1.926375 0.263427734375 0.113983154296875 -0.5672241210937414 +1.9265 0.263427734375 0.113983154296875 -0.5672241210937414 +1.926625 0.25897216796875 0.112060546875 -0.5672241210937414 +1.92675 0.25445556640625 0.110107421875 -0.5672241210937414 +1.92687500000000016 0.25445556640625 0.110107421875 -0.5672241210937414 +1.927 0.249969482421875 0.108154296875 -0.5672241210937414 +1.927125 0.249969482421875 0.108154296875 -0.5672241210937414 +1.92725000000000016 0.24542236328125 0.106170654296875 -0.5672241210937414 +1.927375 0.2408447265625 0.10418701171875 -0.5672241210937414 +1.9275 0.2408447265625 0.10418701171875 -0.5672241210937414 +1.92762500000000016 0.236236572265625 0.102203369140625 -0.5672241210937414 +1.92775 0.236236572265625 0.102203369140625 -0.5672241210937414 +1.927875 0.231597900390625 0.1002197265625 -0.5672241210937414 +1.928 0.226959228515625 0.09820556640625 -0.5672241210937414 +1.928125 0.226959228515625 0.09820556640625 -0.5672241210937414 +1.92825 0.2222900390625 0.096160888671875 -0.5672241210937414 +1.928375 0.2222900390625 0.096160888671875 -0.5672241210937414 +1.9285 0.21759033203125 0.094146728515625 -0.5672241210937414 +1.928625 0.212860107421875 0.09210205078125 -0.5672241210937414 +1.92875 0.212860107421875 0.09210205078125 -0.5672241210937414 +1.92887500000000016 0.208099365234375 0.09002685546875 -0.5672241210937414 +1.929 0.208099365234375 0.09002685546875 -0.5672241210937414 +1.929125 0.203338623046875 0.087982177734375 -0.5672241210937414 +1.92925000000000016 0.19854736328125 0.085906982421875 -0.5672241210937414 +1.929375 0.19854736328125 0.085906982421875 -0.5672241210937414 +1.9295 0.1937255859375 0.08380126953125 -0.5672241210937414 +1.929625000000000256 0.1937255859375 0.08380126953125 -0.5672241210937414 +1.92975 0.188873291015625 0.08172607421875 -0.5672241210937414 +1.929875 0.18402099609375 0.079620361328125 -0.5672241210937414 +1.93 0.18402099609375 0.079620361328125 -0.5672241210937414 +1.930125 0.17913818359375 0.0775146484375 -0.5672241210937414 +1.93025 0.17913818359375 0.0775146484375 -0.5672241210937414 +1.930375 0.17425537109375 0.07537841796875 -0.5672241210937414 +1.9305 0.169342041015625 0.073272705078125 -0.5672241210937414 +1.930625 0.169342041015625 0.073272705078125 -0.5672241210937414 +1.93075 0.164398193359375 0.071136474609375 -0.5672241210937414 +1.93087500000000016 0.164398193359375 0.071136474609375 -0.5672241210937414 +1.931 0.159454345703125 0.0689697265625 -0.5672241210937414 +1.931125 0.15447998046875 0.06683349609375 -0.5672241210937414 +1.93125000000000016 0.15447998046875 0.06683349609375 -0.5672241210937414 +1.931375 0.14947509765625 0.064666748046875 -0.5672241210937414 +1.9315 0.14947509765625 0.064666748046875 -0.5672241210937414 +1.931625000000000256 0.14447021484375 0.0625 -0.5672241210937414 +1.93175 0.13946533203125 0.060333251953125 -0.5672241210937414 +1.931875 0.13946533203125 0.060333251953125 -0.5672241210937414 +1.932 0.134429931640625 0.05816650390625 -0.5672241210937414 +1.932125 0.134429931640625 0.05816650390625 -0.5672241210937414 +1.93225 0.129364013671875 0.05596923828125 -0.5672241210937414 +1.932375 0.124298095703125 0.05377197265625 -0.5672241210937414 +1.9325 0.124298095703125 0.05377197265625 -0.5672241210937414 +1.932625 0.119232177734375 0.05157470703125 -0.5672241210937414 +1.93275 0.119232177734375 0.05157470703125 -0.5672241210937414 +1.93287500000000016 0.1141357421875 0.04937744140625 -0.5672241210937414 +1.933 0.109039306640625 0.04718017578125 -0.5672241210937414 +1.933125 0.109039306640625 0.04718017578125 -0.5672241210937414 +1.93325000000000016 0.103912353515625 0.044952392578125 -0.5672241210937414 +1.933375 0.103912353515625 0.044952392578125 -0.5672241210937414 +1.9335 0.098785400390625 0.042755126953125 -0.5672241210937414 +1.933625000000000256 0.093658447265625 0.04052734375 -0.5672241210937414 +1.93375 0.093658447265625 0.04052734375 -0.5672241210937414 +1.933875 0.0885009765625 0.038299560546875 -0.5672241210937414 +1.934 0.0885009765625 0.038299560546875 -0.5672241210937414 +1.934125 0.083343505859375 0.03607177734375 -0.5672241210937414 +1.93425 0.07818603515625 0.0338134765625 -0.5672241210937414 +1.934375 0.07818603515625 0.0338134765625 -0.5672241210937414 +1.9345 0.072998046875 0.031585693359375 -0.5672241210937414 +1.934625 0.072998046875 0.031585693359375 -0.5672241210937414 +1.93475 0.06781005859375 0.029327392578125 -0.5672241210937414 +1.93487500000000016 0.0626220703125 0.027099609375 -0.5672241210937414 +1.935 0.0626220703125 0.027099609375 -0.5672241210937414 +1.935125 0.05743408203125 0.02484130859375 -0.5672241210937414 +1.93525000000000016 0.05743408203125 0.02484130859375 -0.5672241210937414 +1.935375 0.05224609375 0.0225830078125 -0.5672241210937414 +1.9355 0.047027587890625 0.02032470703125 -0.5672241210937414 +1.935625000000000256 0.047027587890625 0.02032470703125 -0.5672241210937414 +1.93575 0.04180908203125 0.01806640625 -0.5672241210937414 +1.935875 0.04180908203125 0.01806640625 -0.5672241210937414 +1.936 0.036590576171875 0.01580810546875 -0.5672241210937414 +1.936125 0.0313720703125 0.013580322265625 -0.5672241210937414 +1.93625 0.0313720703125 0.013580322265625 -0.5672241210937414 +1.936375 0.026123046875 0.01129150390625 -0.5672241210937414 +1.9365 0.026123046875 0.01129150390625 -0.5672241210937414 +1.936625 0.020904541015625 0.009033203125 -0.5672241210937414 +1.93675 0.01568603515625 0.00677490234375 -0.5672241210937414 +1.93687500000000016 0.01568603515625 0.00677490234375 -0.5672241210937414 +1.937 0.01043701171875 0.0045166015625 -0.5672241210937414 +1.937125 0.01043701171875 0.0045166015625 -0.5672241210937414 +1.93725000000000016 0.005218505859375 0.00225830078125 -0.5672241210937414 +1.937375 0.0 0.0 -0.5672241210937414 +1.9375 0.0 0.0 -0.5672241210937414 +1.937625 -0.005218505859375 -0.00225830078125 -0.5672241210937414 +1.93775 -0.005218505859375 -0.00225830078125 -0.5672241210937414 +1.937875 -0.01043701171875 -0.0045166015625 -0.5672241210937414 +1.938 -0.01568603515625 -0.00677490234375 -0.5672241210937414 +1.938125 -0.01568603515625 -0.00677490234375 -0.5672241210937414 +1.93825 -0.020904541015625 -0.009033203125 -0.5672241210937414 +1.938375 -0.020904541015625 -0.009033203125 -0.5672241210937414 +1.93850000000000016 -0.026123046875 -0.01129150390625 -0.5672241210937414 +1.938625 -0.0313720703125 -0.013580322265625 -0.5672241210937414 +1.93875 -0.0313720703125 -0.013580322265625 -0.5672241210937414 +1.93887500000000016 -0.036590576171875 -0.01580810546875 -0.5672241210937414 +1.939 -0.036590576171875 -0.01580810546875 -0.5672241210937414 +1.939125 -0.04180908203125 -0.01806640625 -0.5672241210937414 +1.93925000000000016 -0.047027587890625 -0.02032470703125 -0.5672241210937414 +1.939375 -0.047027587890625 -0.02032470703125 -0.5672241210937414 +1.9395 -0.05224609375 -0.0225830078125 -0.5672241210937414 +1.939625 -0.05224609375 -0.0225830078125 -0.5672241210937414 +1.93975 -0.05743408203125 -0.02484130859375 -0.5672241210937414 +1.939875 -0.0626220703125 -0.027099609375 -0.5672241210937414 +1.94 -0.0626220703125 -0.027099609375 -0.5672241210937414 +1.940125 -0.06781005859375 -0.029327392578125 -0.5672241210937414 +1.94025 -0.06781005859375 -0.029327392578125 -0.5672241210937414 +1.940375 -0.072998046875 -0.031585693359375 -0.5672241210937414 +1.94050000000000016 -0.07818603515625 -0.0338134765625 -0.5672241210937414 +1.940625 -0.07818603515625 -0.0338134765625 -0.5672241210937414 +1.94075 -0.083343505859375 -0.03607177734375 -0.5672241210937414 +1.94087500000000016 -0.083343505859375 -0.03607177734375 -0.5672241210937414 +1.941 -0.0885009765625 -0.038299560546875 -0.5672241210937414 +1.941125 -0.093658447265625 -0.04052734375 -0.5672241210937414 +1.94125000000000016 -0.093658447265625 -0.04052734375 -0.5672241210937414 +1.941375 -0.098785400390625 -0.042755126953125 -0.5672241210937414 +1.9415 -0.098785400390625 -0.042755126953125 -0.5672241210937414 +1.941625 -0.103912353515625 -0.044952392578125 -0.5672241210937414 +1.94175 -0.109039306640625 -0.04718017578125 -0.5672241210937414 +1.941875 -0.109039306640625 -0.04718017578125 -0.5672241210937414 +1.942 -0.1141357421875 -0.04937744140625 -0.5672241210937414 +1.942125 -0.1141357421875 -0.04937744140625 -0.5672241210937414 +1.94225 -0.119232177734375 -0.05157470703125 -0.5672241210937414 +1.942375 -0.124298095703125 -0.05377197265625 -0.5672241210937414 +1.94250000000000016 -0.124298095703125 -0.05377197265625 -0.5672241210937414 +1.942625 -0.129364013671875 -0.05596923828125 -0.5672241210937414 +1.94275 -0.129364013671875 -0.05596923828125 -0.5672241210937414 +1.94287500000000016 -0.134429931640625 -0.05816650390625 -0.5672241210937414 +1.943 -0.13946533203125 -0.060333251953125 -0.5672241210937414 +1.943125 -0.13946533203125 -0.060333251953125 -0.5672241210937414 +1.94325000000000016 -0.14447021484375 -0.0625 -0.5672241210937414 +1.943375 -0.14447021484375 -0.0625 -0.5672241210937414 +1.9435 -0.14947509765625 -0.064666748046875 -0.5672241210937414 +1.943625 -0.15447998046875 -0.06683349609375 -0.5672241210937414 +1.94375 -0.15447998046875 -0.06683349609375 -0.5672241210937414 +1.943875 -0.159454345703125 -0.0689697265625 -0.5672241210937414 +1.944 -0.159454345703125 -0.0689697265625 -0.5672241210937414 +1.944125 -0.164398193359375 -0.071136474609375 -0.5672241210937414 +1.94425 -0.169342041015625 -0.073272705078125 -0.5672241210937414 +1.944375 -0.169342041015625 -0.073272705078125 -0.5672241210937414 +1.94450000000000016 -0.17425537109375 -0.07537841796875 -0.5672241210937414 +1.944625 -0.17425537109375 -0.07537841796875 -0.5672241210937414 +1.94475 -0.17913818359375 -0.0775146484375 -0.5672241210937414 +1.94487500000000016 -0.18402099609375 -0.079620361328125 -0.5672241210937414 +1.945 -0.18402099609375 -0.079620361328125 -0.5672241210937414 +1.945125 -0.188873291015625 -0.08172607421875 -0.5672241210937414 +1.945250000000000256 -0.188873291015625 -0.08172607421875 -0.5672241210937414 +1.945375 -0.1937255859375 -0.08380126953125 -0.5672241210937414 +1.9455 -0.19854736328125 -0.085906982421875 -0.5672241210937414 +1.945625 -0.19854736328125 -0.085906982421875 -0.5672241210937414 +1.94575 -0.203338623046875 -0.087982177734375 -0.5672241210937414 +1.945875 -0.203338623046875 -0.087982177734375 -0.5672241210937414 +1.946 -0.208099365234375 -0.09002685546875 -0.5672241210937414 +1.946125 -0.212860107421875 -0.09210205078125 -0.5672241210937414 +1.94625 -0.212860107421875 -0.09210205078125 -0.5672241210937414 +1.946375 -0.21759033203125 -0.094146728515625 -0.5672241210937414 +1.94650000000000016 -0.21759033203125 -0.094146728515625 -0.5672241210937414 +1.946625 -0.2222900390625 -0.096160888671875 -0.5672241210937414 +1.94675 -0.226959228515625 -0.09820556640625 -0.5672241210937414 +1.94687500000000016 -0.226959228515625 -0.09820556640625 -0.5672241210937414 +1.947 -0.231597900390625 -0.1002197265625 -0.5672241210937414 +1.947125 -0.231597900390625 -0.1002197265625 -0.5672241210937414 +1.947250000000000256 -0.236236572265625 -0.102203369140625 -0.5672241210937414 +1.947375 -0.2408447265625 -0.10418701171875 -0.5672241210937414 +1.9475 -0.2408447265625 -0.10418701171875 -0.5672241210937414 +1.947625 -0.24542236328125 -0.106170654296875 -0.5672241210937414 +1.94775 -0.24542236328125 -0.106170654296875 -0.5672241210937414 +1.947875 -0.249969482421875 -0.108154296875 -0.5672241210937414 +1.948 -0.25445556640625 -0.110107421875 -0.5672241210937414 +1.948125 -0.25445556640625 -0.110107421875 -0.5672241210937414 +1.94825 -0.25897216796875 -0.112060546875 -0.5672241210937414 +1.948375 -0.25897216796875 -0.112060546875 -0.5672241210937414 +1.94850000000000016 -0.263427734375 -0.113983154296875 -0.5672241210937414 +1.948625 -0.267852783203125 -0.11590576171875 -0.5672241210937414 +1.94875 -0.267852783203125 -0.11590576171875 -0.5672241210937414 +1.94887500000000016 -0.27227783203125 -0.1177978515625 -0.5672241210937414 +1.949 -0.27227783203125 -0.1177978515625 -0.5672241210937414 +1.949125 -0.276641845703125 -0.11968994140625 -0.5672241210937414 +1.949250000000000256 -0.280975341796875 -0.12158203125 -0.5672241210937414 +1.949375 -0.280975341796875 -0.12158203125 -0.5672241210937414 +1.9495 -0.285308837890625 -0.123443603515625 -0.5672241210937414 +1.949625 -0.285308837890625 -0.123443603515625 -0.5672241210937414 +1.94975 -0.289581298828125 -0.12530517578125 -0.5672241210937414 +1.949875 -0.2938232421875 -0.12713623046875 -0.5672241210937414 +1.95 -0.2938232421875 -0.12713623046875 -0.5672241210937414 +1.950125 -0.298065185546875 -0.12896728515625 -0.5672241210937414 +1.95025 -0.298065185546875 -0.12896728515625 -0.5672241210937414 +1.950375 -0.30224609375 -0.130767822265625 -0.5672241210937414 +1.95050000000000016 -0.306396484375 -0.132568359375 -0.5672241210937414 +1.950625 -0.306396484375 -0.132568359375 -0.5672241210937414 +1.95075 -0.310516357421875 -0.134368896484375 -0.5672241210937414 +1.95087500000000016 -0.310516357421875 -0.134368896484375 -0.5672241210937414 +1.951 -0.314605712890625 -0.1361083984375 -0.5672241210937414 +1.951125 -0.31866455078125 -0.13787841796875 -0.5672241210937414 +1.951250000000000256 -0.31866455078125 -0.13787841796875 -0.5672241210937414 +1.951375 -0.322662353515625 -0.139617919921875 -0.5672241210937414 +1.9515 -0.322662353515625 -0.139617919921875 -0.5672241210937414 +1.951625 -0.32666015625 -0.141326904296875 -0.5672241210937414 +1.95175 -0.330596923828125 -0.143035888671875 -0.5672241210937414 +1.951875 -0.330596923828125 -0.143035888671875 -0.5672241210937414 +1.952 -0.334503173828125 -0.2677001953125 -0.1996826171874888 +1.952125 -0.334503173828125 -0.2677001953125 -0.1996826171874888 +1.95225 -0.33837890625 -0.27081298828125 -0.1996826171874888 +1.952375 -0.34222412109375 -0.27386474609375 -0.1996826171874888 +1.95250000000000016 -0.34222412109375 -0.27386474609375 -0.1996826171874888 +1.952625 -0.34600830078125 -0.27691650390625 -0.1996826171874888 +1.95275 -0.34600830078125 -0.27691650390625 -0.1996826171874888 +1.95287500000000016 -0.349761962890625 -0.2799072265625 -0.1996826171874888 +1.953 -0.353485107421875 -0.28289794921875 -0.1996826171874888 +1.953125 -0.353485107421875 -0.28289794921875 -0.1996826171874888 +1.95325 -0.357177734375 -0.285858154296875 -0.1996826171874888 +1.953375 -0.357177734375 -0.285858154296875 -0.1996826171874888 +1.9535 -0.360809326171875 -0.28875732421875 -0.1996826171874888 +1.953625 -0.36444091796875 -0.291656494140625 -0.1996826171874888 +1.95375 -0.36444091796875 -0.291656494140625 -0.1996826171874888 +1.953875 -0.36798095703125 -0.29449462890625 -0.1996826171874888 +1.954 -0.36798095703125 -0.29449462890625 -0.1996826171874888 +1.95412500000000016 -0.37152099609375 -0.29730224609375 -0.1996826171874888 +1.95425 -0.375 -0.30010986328125 -0.1996826171874888 +1.954375 -0.375 -0.30010986328125 -0.1996826171874888 +1.95450000000000016 -0.378448486328125 -0.3028564453125 -0.1996826171874888 +1.954625 -0.378448486328125 -0.3028564453125 -0.1996826171874888 +1.95475 -0.3818359375 -0.305572509765625 -0.1996826171874888 +1.95487500000000016 -0.38519287109375 -0.308258056640625 -0.1996826171874888 +1.955 -0.38519287109375 -0.308258056640625 -0.1996826171874888 +1.955125 -0.388519287109375 -0.3109130859375 -0.1996826171874888 +1.95525 -0.388519287109375 -0.3109130859375 -0.1996826171874888 +1.955375 -0.39178466796875 -0.31353759765625 -0.1996826171874888 +1.9555 -0.39501953125 -0.316131591796875 -0.1996826171874888 +1.955625 -0.39501953125 -0.316131591796875 -0.1996826171874888 +1.95575 -0.398193359375 -0.31866455078125 -0.1996826171874888 +1.955875 -0.398193359375 -0.31866455078125 -0.1996826171874888 +1.956 -0.401336669921875 -0.321197509765625 -0.1996826171874888 +1.95612500000000016 -0.404449462890625 -0.32366943359375 -0.1996826171874888 +1.95625 -0.404449462890625 -0.32366943359375 -0.1996826171874888 +1.956375 -0.407501220703125 -0.32611083984375 -0.1996826171874888 +1.95650000000000016 -0.407501220703125 -0.32611083984375 -0.1996826171874888 +1.956625 -0.4105224609375 -0.328521728515625 -0.1996826171874888 +1.95675 -0.413482666015625 -0.330902099609375 -0.1996826171874888 +1.95687500000000016 -0.413482666015625 -0.330902099609375 -0.1996826171874888 +1.957 -0.416412353515625 -0.333221435546875 -0.1996826171874888 +1.957125 -0.416412353515625 -0.333221435546875 -0.1996826171874888 +1.95725 -0.419281005859375 -0.335540771484375 -0.1996826171874888 +1.957375 -0.422119140625 -0.337799072265625 -0.1996826171874888 +1.9575 -0.422119140625 -0.337799072265625 -0.1996826171874888 +1.957625 -0.424896240234375 -0.34002685546875 -0.1996826171874888 +1.95775 -0.424896240234375 -0.34002685546875 -0.1996826171874888 +1.957875 -0.4276123046875 -0.34222412109375 -0.1996826171874888 +1.958 -0.4302978515625 -0.3443603515625 -0.1996826171874888 +1.95812500000000016 -0.4302978515625 -0.3443603515625 -0.1996826171874888 +1.95825 -0.432952880859375 -0.34649658203125 -0.1996826171874888 +1.958375 -0.432952880859375 -0.34649658203125 -0.1996826171874888 +1.95850000000000016 -0.435546875 -0.34857177734375 -0.1996826171874888 +1.958625 -0.438079833984375 -0.3505859375 -0.1996826171874888 +1.95875 -0.438079833984375 -0.3505859375 -0.1996826171874888 +1.95887500000000016 -0.440582275390625 -0.35260009765625 -0.1996826171874888 +1.959 -0.440582275390625 -0.35260009765625 -0.1996826171874888 +1.959125 -0.44305419921875 -0.35455322265625 -0.1996826171874888 +1.95925 -0.4454345703125 -0.356475830078125 -0.1996826171874888 +1.959375 -0.4454345703125 -0.356475830078125 -0.1996826171874888 +1.9595 -0.447784423828125 -0.358367919921875 -0.1996826171874888 +1.959625 -0.447784423828125 -0.358367919921875 -0.1996826171874888 +1.95975 -0.450103759765625 -0.360198974609375 -0.1996826171874888 +1.959875 -0.452362060546875 -0.36199951171875 -0.1996826171874888 +1.96 -0.452362060546875 -0.36199951171875 -0.1996826171874888 +1.96012500000000016 -0.454559326171875 -0.36376953125 -0.1996826171874888 +1.96025 -0.454559326171875 -0.36376953125 -0.1996826171874888 +1.960375 -0.45672607421875 -0.365509033203125 -0.1996826171874888 +1.96050000000000016 -0.458831787109375 -0.3671875 -0.1996826171874888 +1.960625 -0.458831787109375 -0.3671875 -0.1996826171874888 +1.96075 -0.46087646484375 -0.368804931640625 -0.1996826171874888 +1.960875000000000256 -0.46087646484375 -0.368804931640625 -0.1996826171874888 +1.961 -0.462890625 -0.37042236328125 -0.1996826171874888 +1.961125 -0.464813232421875 -0.371978759765625 -0.1996826171874888 +1.96125 -0.464813232421875 -0.371978759765625 -0.1996826171874888 +1.961375 -0.46673583984375 -0.373504638671875 -0.1996826171874888 +1.9615 -0.46673583984375 -0.373504638671875 -0.1996826171874888 +1.961625 -0.46856689453125 -0.374969482421875 -0.1996826171874888 +1.96175 -0.470367431640625 -0.376434326171875 -0.1996826171874888 +1.961875 -0.470367431640625 -0.376434326171875 -0.1996826171874888 +1.962 -0.472137451171875 -0.377838134765625 -0.1996826171874888 +1.96212500000000016 -0.472137451171875 -0.377838134765625 -0.1996826171874888 +1.96225 -0.47381591796875 -0.379180908203125 -0.1996826171874888 +1.962375 -0.4754638671875 -0.3804931640625 -0.1996826171874888 +1.96250000000000016 -0.4754638671875 -0.3804931640625 -0.1996826171874888 +1.962625 -0.47705078125 -0.38177490234375 -0.1996826171874888 +1.96275 -0.47705078125 -0.38177490234375 -0.1996826171874888 +1.962875000000000256 -0.478607177734375 -0.38299560546875 -0.1996826171874888 +1.963 -0.480072021484375 -0.384185791015625 -0.1996826171874888 +1.963125 -0.480072021484375 -0.384185791015625 -0.1996826171874888 +1.96325 -0.48150634765625 -0.385345458984375 -0.1996826171874888 +1.963375 -0.48150634765625 -0.385345458984375 -0.1996826171874888 +1.9635 -0.48291015625 -0.386444091796875 -0.1996826171874888 +1.963625 -0.484222412109375 -0.38751220703125 -0.1996826171874888 +1.96375 -0.484222412109375 -0.38751220703125 -0.1996826171874888 +1.963875 -0.485504150390625 -0.3885498046875 -0.1996826171874888 +1.964 -0.485504150390625 -0.3885498046875 -0.1996826171874888 +1.96412500000000016 -0.486724853515625 -0.3895263671875 -0.1996826171874888 +1.96425 -0.487884521484375 -0.39044189453125 -0.1996826171874888 +1.964375 -0.487884521484375 -0.39044189453125 -0.1996826171874888 +1.96450000000000016 -0.489013671875 -0.391326904296875 -0.1996826171874888 +1.964625 -0.489013671875 -0.391326904296875 -0.1996826171874888 +1.96475 -0.490081787109375 -0.392181396484375 -0.1996826171874888 +1.964875000000000256 -0.4910888671875 -0.39300537109375 -0.1996826171874888 +1.965 -0.4910888671875 -0.39300537109375 -0.1996826171874888 +1.965125 -0.492034912109375 -0.393768310546875 -0.1996826171874888 +1.96525 -0.492034912109375 -0.393768310546875 -0.1996826171874888 +1.965375 -0.492950439453125 -0.39447021484375 -0.1996826171874888 +1.9655 -0.4937744140625 -0.3951416015625 -0.1996826171874888 +1.965625 -0.4937744140625 -0.3951416015625 -0.1996826171874888 +1.96575 -0.49456787109375 -0.395782470703125 -0.1996826171874888 +1.965875 -0.49456787109375 -0.395782470703125 -0.1996826171874888 +1.966 -0.49530029296875 -0.3963623046875 -0.1996826171874888 +1.96612500000000016 -0.496002197265625 -0.39691162109375 -0.1996826171874888 +1.96625 -0.496002197265625 -0.39691162109375 -0.1996826171874888 +1.966375 -0.496612548828125 -0.397430419921875 -0.1996826171874888 +1.96650000000000016 -0.496612548828125 -0.397430419921875 -0.1996826171874888 +1.966625 -0.4971923828125 -0.39788818359375 -0.1996826171874888 +1.96675 -0.497711181640625 -0.3983154296875 -0.1996826171874888 +1.966875000000000256 -0.497711181640625 -0.3983154296875 -0.1996826171874888 +1.967 -0.498199462890625 -0.398681640625 -0.1996826171874888 +1.967125 -0.498199462890625 -0.398681640625 -0.1996826171874888 +1.96725 -0.49859619140625 -0.399017333984375 -0.1996826171874888 +1.967375 -0.49896240234375 -0.3992919921875 -0.1996826171874888 +1.9675 -0.49896240234375 -0.3992919921875 -0.1996826171874888 +1.967625 -0.499267578125 -0.3995361328125 -0.1996826171874888 +1.96775 -0.499267578125 -0.3995361328125 -0.1996826171874888 +1.967875 -0.49951171875 -0.39971923828125 -0.1996826171874888 +1.968 -0.49969482421875 -0.399871826171875 -0.1996826171874888 +1.96812500000000016 -0.49969482421875 -0.399871826171875 -0.1996826171874888 +1.96825 -0.49981689453125 -0.399993896484375 -0.1996826171874888 +1.968375 -0.49981689453125 -0.399993896484375 -0.1996826171874888 +1.96850000000000016 -0.499908447265625 -0.400054931640625 -0.1996826171874888 +1.968625 -0.49993896484375 -0.40008544921875 -0.1996826171874888 +1.96875 -0.49993896484375 -0.40008544921875 -0.1996826171874888 +1.968875 -0.499908447265625 -0.400054931640625 -0.1996826171874888 +1.969 -0.499908447265625 -0.400054931640625 -0.1996826171874888 +1.969125 -0.49981689453125 -0.399993896484375 -0.1996826171874888 +1.96925 -0.49969482421875 -0.399871826171875 -0.1996826171874888 +1.969375 -0.49969482421875 -0.399871826171875 -0.1996826171874888 +1.9695 -0.49951171875 -0.39971923828125 -0.1996826171874888 +1.969625 -0.49951171875 -0.39971923828125 -0.1996826171874888 +1.96975000000000016 -0.499267578125 -0.3995361328125 -0.1996826171874888 +1.969875 -0.49896240234375 -0.3992919921875 -0.1996826171874888 +1.97 -0.49896240234375 -0.3992919921875 -0.1996826171874888 +1.97012500000000016 -0.49859619140625 -0.399017333984375 -0.1996826171874888 +1.97025 -0.49859619140625 -0.399017333984375 -0.1996826171874888 +1.970375 -0.498199462890625 -0.398681640625 -0.1996826171874888 +1.97050000000000016 -0.497711181640625 -0.3983154296875 -0.1996826171874888 +1.970625 -0.497711181640625 -0.3983154296875 -0.1996826171874888 +1.97075 -0.4971923828125 -0.39788818359375 -0.1996826171874888 +1.970875 -0.4971923828125 -0.39788818359375 -0.1996826171874888 +1.971 -0.496612548828125 -0.397430419921875 -0.1996826171874888 +1.971125 -0.496002197265625 -0.39691162109375 -0.1996826171874888 +1.97125 -0.496002197265625 -0.39691162109375 -0.1996826171874888 +1.971375 -0.49530029296875 -0.3963623046875 -0.1996826171874888 +1.9715 -0.49530029296875 -0.3963623046875 -0.1996826171874888 +1.971625 -0.49456787109375 -0.395782470703125 -0.1996826171874888 +1.97175000000000016 -0.4937744140625 -0.3951416015625 -0.1996826171874888 +1.971875 -0.4937744140625 -0.3951416015625 -0.1996826171874888 +1.972 -0.492950439453125 -0.39447021484375 -0.1996826171874888 +1.97212500000000016 -0.492950439453125 -0.39447021484375 -0.1996826171874888 +1.97225 -0.492034912109375 -0.393768310546875 -0.1996826171874888 +1.972375 -0.4910888671875 -0.39300537109375 -0.1996826171874888 +1.97250000000000016 -0.4910888671875 -0.39300537109375 -0.1996826171874888 +1.972625 -0.490081787109375 -0.392181396484375 -0.1996826171874888 +1.97275 -0.490081787109375 -0.392181396484375 -0.1996826171874888 +1.972875 -0.489013671875 -0.391326904296875 -0.1996826171874888 +1.973 -0.487884521484375 -0.39044189453125 -0.1996826171874888 +1.973125 -0.487884521484375 -0.39044189453125 -0.1996826171874888 +1.97325 -0.486724853515625 -0.3895263671875 -0.1996826171874888 +1.973375 -0.486724853515625 -0.3895263671875 -0.1996826171874888 +1.9735 -0.485504150390625 -0.3885498046875 -0.1996826171874888 +1.973625 -0.484222412109375 -0.38751220703125 -0.1996826171874888 +1.97375000000000016 -0.484222412109375 -0.38751220703125 -0.1996826171874888 +1.973875 -0.48291015625 -0.386444091796875 -0.1996826171874888 +1.974 -0.48291015625 -0.386444091796875 -0.1996826171874888 +1.97412500000000016 -0.48150634765625 -0.385345458984375 -0.1996826171874888 +1.97425 -0.480072021484375 -0.384185791015625 -0.1996826171874888 +1.974375 -0.480072021484375 -0.384185791015625 -0.1996826171874888 +1.97450000000000016 -0.478607177734375 -0.38299560546875 -0.1996826171874888 +1.974625 -0.478607177734375 -0.38299560546875 -0.1996826171874888 +1.97475 -0.47705078125 -0.38177490234375 -0.1996826171874888 +1.974875 -0.4754638671875 -0.3804931640625 -0.1996826171874888 +1.975 -0.4754638671875 -0.3804931640625 -0.1996826171874888 +1.975125 -0.47381591796875 -0.379180908203125 -0.1996826171874888 +1.97525 -0.47381591796875 -0.379180908203125 -0.1996826171874888 +1.975375 -0.472137451171875 -0.377838134765625 -0.1996826171874888 +1.9755 -0.470367431640625 -0.376434326171875 -0.1996826171874888 +1.975625 -0.470367431640625 -0.376434326171875 -0.1996826171874888 +1.97575000000000016 -0.46856689453125 -0.374969482421875 -0.1996826171874888 +1.975875 -0.46856689453125 -0.374969482421875 -0.1996826171874888 +1.976 -0.46673583984375 -0.373504638671875 -0.1996826171874888 +1.97612500000000016 -0.464813232421875 -0.371978759765625 -0.1996826171874888 +1.97625 -0.464813232421875 -0.371978759765625 -0.1996826171874888 +1.976375 -0.462890625 -0.37042236328125 -0.1996826171874888 +1.976500000000000256 -0.462890625 -0.37042236328125 -0.1996826171874888 +1.976625 -0.46087646484375 -0.368804931640625 -0.1996826171874888 +1.97675 -0.458831787109375 -0.3671875 -0.1996826171874888 +1.976875 -0.458831787109375 -0.3671875 -0.1996826171874888 +1.977 -0.45672607421875 -0.365509033203125 -0.1996826171874888 +1.977125 -0.45672607421875 -0.365509033203125 -0.1996826171874888 +1.97725 -0.454559326171875 -0.36376953125 -0.1996826171874888 +1.977375 -0.452362060546875 -0.36199951171875 -0.1996826171874888 +1.9775 -0.452362060546875 -0.36199951171875 -0.1996826171874888 +1.977625 -0.450103759765625 -0.360198974609375 -0.1996826171874888 +1.97775000000000016 -0.450103759765625 -0.360198974609375 -0.1996826171874888 +1.977875 -0.447784423828125 -0.358367919921875 -0.1996826171874888 +1.978 -0.4454345703125 -0.356475830078125 -0.1996826171874888 +1.97812500000000016 -0.4454345703125 -0.356475830078125 -0.1996826171874888 +1.97825 -0.44305419921875 -0.35455322265625 -0.1996826171874888 +1.978375 -0.44305419921875 -0.35455322265625 -0.1996826171874888 +1.978500000000000256 -0.440582275390625 -0.35260009765625 -0.1996826171874888 +1.978625 -0.438079833984375 -0.3505859375 -0.1996826171874888 +1.97875 -0.438079833984375 -0.3505859375 -0.1996826171874888 +1.978875 -0.435546875 -0.34857177734375 -0.1996826171874888 +1.979 -0.435546875 -0.34857177734375 -0.1996826171874888 +1.979125 -0.432952880859375 -0.34649658203125 -0.1996826171874888 +1.97925 -0.4302978515625 -0.3443603515625 -0.1996826171874888 +1.979375 -0.4302978515625 -0.3443603515625 -0.1996826171874888 +1.9795 -0.4276123046875 -0.34222412109375 -0.1996826171874888 +1.979625 -0.4276123046875 -0.34222412109375 -0.1996826171874888 +1.97975000000000016 -0.424896240234375 -0.34002685546875 -0.1996826171874888 +1.979875 -0.422119140625 -0.337799072265625 -0.1996826171874888 +1.98 -0.422119140625 -0.337799072265625 -0.1996826171874888 +1.98012500000000016 -0.419281005859375 -0.335540771484375 -0.1996826171874888 +1.98025 -0.419281005859375 -0.335540771484375 -0.1996826171874888 +1.980375 -0.416412353515625 -0.333221435546875 -0.1996826171874888 +1.980500000000000256 -0.413482666015625 -0.330902099609375 -0.1996826171874888 +1.980625 -0.413482666015625 -0.330902099609375 -0.1996826171874888 +1.98075 -0.4105224609375 -0.328521728515625 -0.1996826171874888 +1.980875 -0.4105224609375 -0.328521728515625 -0.1996826171874888 +1.981 -0.407501220703125 -0.32611083984375 -0.1996826171874888 +1.981125 -0.404449462890625 -0.32366943359375 -0.1996826171874888 +1.98125 -0.404449462890625 -0.32366943359375 -0.1996826171874888 +1.981375 -0.401336669921875 -0.321197509765625 -0.1996826171874888 +1.9815 -0.401336669921875 -0.321197509765625 -0.1996826171874888 +1.981625 -0.398193359375 -0.31866455078125 -0.1996826171874888 +1.98175000000000016 -0.39501953125 -0.316131591796875 -0.1996826171874888 +1.981875 -0.39501953125 -0.316131591796875 -0.1996826171874888 +1.982 -0.39178466796875 -0.31353759765625 -0.1996826171874888 +1.98212500000000016 -0.39178466796875 -0.31353759765625 -0.1996826171874888 +1.98225 -0.388519287109375 -0.3109130859375 -0.1996826171874888 +1.982375 -0.38519287109375 -0.308258056640625 -0.1996826171874888 +1.982500000000000256 -0.38519287109375 -0.308258056640625 -0.1996826171874888 +1.982625 -0.3818359375 -0.305572509765625 -0.1996826171874888 +1.98275 -0.3818359375 -0.305572509765625 -0.1996826171874888 +1.982875 -0.378448486328125 -0.3028564453125 -0.1996826171874888 +1.983 -0.375 -0.30010986328125 -0.1996826171874888 +1.983125 -0.375 -0.30010986328125 -0.1996826171874888 +1.98325 -0.37152099609375 -0.29730224609375 -0.1996826171874888 +1.983375 -0.37152099609375 -0.29730224609375 -0.1996826171874888 +1.9835 -0.36798095703125 -0.29449462890625 -0.1996826171874888 +1.983625 -0.36444091796875 -0.291656494140625 -0.1996826171874888 +1.98375000000000016 -0.36444091796875 -0.291656494140625 -0.1996826171874888 +1.983875 -0.360809326171875 -0.28875732421875 -0.1996826171874888 +1.984 -0.28875732421875 -0.360809326171875 0.1996826171875111 +1.98412500000000016 -0.285858154296875 -0.357177734375 0.1996826171875111 +1.98425 -0.28289794921875 -0.353485107421875 0.1996826171875111 +1.984375 -0.28289794921875 -0.353485107421875 0.1996826171875111 +1.9845 -0.2799072265625 -0.349761962890625 0.1996826171875111 +1.984625 -0.2799072265625 -0.349761962890625 0.1996826171875111 +1.98475 -0.27691650390625 -0.34600830078125 0.1996826171875111 +1.984875 -0.27386474609375 -0.34222412109375 0.1996826171875111 +1.985 -0.27386474609375 -0.34222412109375 0.1996826171875111 +1.985125 -0.27081298828125 -0.33837890625 0.1996826171875111 +1.98525 -0.27081298828125 -0.33837890625 0.1996826171875111 +1.98537500000000016 -0.2677001953125 -0.334503173828125 0.1996826171875111 +1.9855 -0.26458740234375 -0.330596923828125 0.1996826171875111 +1.985625 -0.26458740234375 -0.330596923828125 0.1996826171875111 +1.98575000000000016 -0.26141357421875 -0.32666015625 0.1996826171875111 +1.985875 -0.26141357421875 -0.32666015625 0.1996826171875111 +1.986 -0.25823974609375 -0.322662353515625 0.1996826171875111 +1.98612500000000016 -0.2550048828125 -0.31866455078125 0.1996826171875111 +1.98625 -0.2550048828125 -0.31866455078125 0.1996826171875111 +1.986375 -0.25177001953125 -0.314605712890625 0.1996826171875111 +1.9865 -0.25177001953125 -0.314605712890625 0.1996826171875111 +1.986625 -0.248504638671875 -0.310516357421875 0.1996826171875111 +1.98675 -0.245208740234375 -0.306396484375 0.1996826171875111 +1.986875 -0.245208740234375 -0.306396484375 0.1996826171875111 +1.987 -0.24188232421875 -0.30224609375 0.1996826171875111 +1.987125 -0.24188232421875 -0.30224609375 0.1996826171875111 +1.98725 -0.238525390625 -0.298065185546875 0.1996826171875111 +1.98737500000000016 -0.235137939453125 -0.2938232421875 0.1996826171875111 +1.9875 -0.235137939453125 -0.2938232421875 0.1996826171875111 +1.987625 -0.23175048828125 -0.289581298828125 0.1996826171875111 +1.98775000000000016 -0.23175048828125 -0.289581298828125 0.1996826171875111 +1.987875 -0.22833251953125 -0.285308837890625 0.1996826171875111 +1.988 -0.224853515625 -0.280975341796875 0.1996826171875111 +1.98812500000000016 -0.224853515625 -0.280975341796875 0.1996826171875111 +1.98825 -0.22137451171875 -0.276641845703125 0.1996826171875111 +1.988375 -0.22137451171875 -0.276641845703125 0.1996826171875111 +1.9885 -0.2178955078125 -0.27227783203125 0.1996826171875111 +1.988625 -0.21435546875 -0.267852783203125 0.1996826171875111 +1.98875 -0.21435546875 -0.267852783203125 0.1996826171875111 +1.988875 -0.2108154296875 -0.263427734375 0.1996826171875111 +1.989 -0.2108154296875 -0.263427734375 0.1996826171875111 +1.989125 -0.207244873046875 -0.25897216796875 0.1996826171875111 +1.98925 -0.203643798828125 -0.25445556640625 0.1996826171875111 +1.98937500000000016 -0.203643798828125 -0.25445556640625 0.1996826171875111 +1.9895 -0.200042724609375 -0.249969482421875 0.1996826171875111 +1.989625 -0.200042724609375 -0.249969482421875 0.1996826171875111 +1.98975000000000016 -0.196380615234375 -0.24542236328125 0.1996826171875111 +1.989875 -0.192718505859375 -0.2408447265625 0.1996826171875111 +1.99 -0.192718505859375 -0.2408447265625 0.1996826171875111 +1.99012500000000016 -0.189056396484375 -0.236236572265625 0.1996826171875111 +1.99025 -0.189056396484375 -0.236236572265625 0.1996826171875111 +1.990375 -0.185333251953125 -0.231597900390625 0.1996826171875111 +1.9905 -0.181610107421875 -0.226959228515625 0.1996826171875111 +1.990625 -0.181610107421875 -0.226959228515625 0.1996826171875111 +1.99075 -0.177886962890625 -0.2222900390625 0.1996826171875111 +1.990875 -0.177886962890625 -0.2222900390625 0.1996826171875111 +1.991 -0.17413330078125 -0.21759033203125 0.1996826171875111 +1.991125 -0.17034912109375 -0.212860107421875 0.1996826171875111 +1.99125 -0.17034912109375 -0.212860107421875 0.1996826171875111 +1.99137500000000016 -0.166534423828125 -0.208099365234375 0.1996826171875111 +1.9915 -0.166534423828125 -0.208099365234375 0.1996826171875111 +1.991625 -0.1627197265625 -0.203338623046875 0.1996826171875111 +1.99175000000000016 -0.15887451171875 -0.19854736328125 0.1996826171875111 +1.991875 -0.15887451171875 -0.19854736328125 0.1996826171875111 +1.992 -0.155029296875 -0.1937255859375 0.1996826171875111 +1.992125000000000256 -0.155029296875 -0.1937255859375 0.1996826171875111 +1.99225 -0.151153564453125 -0.188873291015625 0.1996826171875111 +1.992375 -0.14727783203125 -0.18402099609375 0.1996826171875111 +1.9925 -0.14727783203125 -0.18402099609375 0.1996826171875111 +1.992625 -0.14337158203125 -0.17913818359375 0.1996826171875111 +1.99275 -0.14337158203125 -0.17913818359375 0.1996826171875111 +1.992875 -0.139434814453125 -0.17425537109375 0.1996826171875111 +1.993 -0.135498046875 -0.169342041015625 0.1996826171875111 +1.993125 -0.135498046875 -0.169342041015625 0.1996826171875111 +1.99325 -0.131561279296875 -0.164398193359375 0.1996826171875111 +1.99337500000000016 -0.131561279296875 -0.164398193359375 0.1996826171875111 +1.9935 -0.127593994140625 -0.159454345703125 0.1996826171875111 +1.993625 -0.123626708984375 -0.15447998046875 0.1996826171875111 +1.99375000000000016 -0.123626708984375 -0.15447998046875 0.1996826171875111 +1.993875 -0.11962890625 -0.14947509765625 0.1996826171875111 +1.994 -0.11962890625 -0.14947509765625 0.1996826171875111 +1.994125000000000256 -0.115631103515625 -0.14447021484375 0.1996826171875111 +1.99425 -0.111602783203125 -0.13946533203125 0.1996826171875111 +1.994375 -0.111602783203125 -0.13946533203125 0.1996826171875111 +1.9945 -0.107574462890625 -0.134429931640625 0.1996826171875111 +1.994625 -0.107574462890625 -0.134429931640625 0.1996826171875111 +1.99475 -0.103515625 -0.129364013671875 0.1996826171875111 +1.994875 -0.0994873046875 -0.124298095703125 0.1996826171875111 +1.995 -0.0994873046875 -0.124298095703125 0.1996826171875111 +1.995125 -0.095428466796875 -0.119232177734375 0.1996826171875111 +1.99525 -0.095428466796875 -0.119232177734375 0.1996826171875111 +1.99537500000000016 -0.091339111328125 -0.1141357421875 0.1996826171875111 +1.9955 -0.087249755859375 -0.109039306640625 0.1996826171875111 +1.995625 -0.087249755859375 -0.109039306640625 0.1996826171875111 +1.99575000000000016 -0.083160400390625 -0.103912353515625 0.1996826171875111 +1.995875 -0.083160400390625 -0.103912353515625 0.1996826171875111 +1.996 -0.079071044921875 -0.098785400390625 0.1996826171875111 +1.996125000000000256 -0.074951171875 -0.093658447265625 0.1996826171875111 +1.99625 -0.074951171875 -0.093658447265625 0.1996826171875111 +1.996375 -0.070831298828125 -0.0885009765625 0.1996826171875111 +1.9965 -0.070831298828125 -0.0885009765625 0.1996826171875111 +1.996625 -0.06671142578125 -0.083343505859375 0.1996826171875111 +1.99675 -0.06256103515625 -0.07818603515625 0.1996826171875111 +1.996875 -0.06256103515625 -0.07818603515625 0.1996826171875111 +1.997 -0.05841064453125 -0.072998046875 0.1996826171875111 +1.997125 -0.05841064453125 -0.072998046875 0.1996826171875111 +1.99725 -0.05426025390625 -0.06781005859375 0.1996826171875111 +1.99737500000000016 -0.05010986328125 -0.0626220703125 0.1996826171875111 +1.9975 -0.05010986328125 -0.0626220703125 0.1996826171875111 +1.997625 -0.04595947265625 -0.05743408203125 0.1996826171875111 +1.99775000000000016 -0.04595947265625 -0.05743408203125 0.1996826171875111 +1.997875 -0.04180908203125 -0.05224609375 0.1996826171875111 +1.998 -0.037628173828125 -0.047027587890625 0.1996826171875111 +1.998125000000000256 -0.037628173828125 -0.047027587890625 0.1996826171875111 +1.99825 -0.033447265625 -0.04180908203125 0.1996826171875111 +1.998375 -0.033447265625 -0.04180908203125 0.1996826171875111 +1.9985 -0.029266357421875 -0.036590576171875 0.1996826171875111 +1.998625 -0.025115966796875 -0.0313720703125 0.1996826171875111 +1.99875 -0.025115966796875 -0.0313720703125 0.1996826171875111 +1.998875 -0.020904541015625 -0.026123046875 0.1996826171875111 +1.999 -0.020904541015625 -0.026123046875 0.1996826171875111 +1.999125 -0.0167236328125 -0.020904541015625 0.1996826171875111 +1.99925 -0.012542724609375 -0.01568603515625 0.1996826171875111 +1.99937500000000016 -0.012542724609375 -0.01568603515625 0.1996826171875111 +1.9995 -0.00836181640625 -0.01043701171875 0.1996826171875111 +1.999625 -0.00836181640625 -0.01043701171875 0.1996826171875111 +1.99975000000000016 -0.004180908203125 -0.005218505859375 0.1996826171875111 +1.999875 0.0 0.0 0.1996826171875111 +2.0 0.0 0.0 0.1996826171875111 +2.000125 0.004180908203125 0.005218505859375 0.1996826171875111 +2.00025 0.004180908203125 0.005218505859375 0.1996826171875111 +2.000375 0.00836181640625 0.01043701171875 0.1996826171875111 +2.0005 0.012542724609375 0.01568603515625 0.1996826171875111 +2.000625 0.012542724609375 0.01568603515625 0.1996826171875111 +2.00075 0.0167236328125 0.020904541015625 0.1996826171875111 +2.000875 0.0167236328125 0.020904541015625 0.1996826171875111 +2.001 0.020904541015625 0.026123046875 0.1996826171875111 +2.001125 0.025115966796875 0.0313720703125 0.1996826171875111 +2.00125 0.025115966796875 0.0313720703125 0.1996826171875111 +2.001375 0.029266357421875 0.036590576171875 0.1996826171875111 +2.0015 0.029266357421875 0.036590576171875 0.1996826171875111 +2.001625 0.033447265625 0.04180908203125 0.1996826171875111 +2.00175 0.037628173828125 0.047027587890625 0.1996826171875111 +2.001875 0.037628173828125 0.047027587890625 0.1996826171875111 +2.0020000000000004 0.04180908203125 0.05224609375 0.1996826171875111 +2.002125 0.04180908203125 0.05224609375 0.1996826171875111 +2.00225 0.04595947265625 0.05743408203125 0.1996826171875111 +2.0023750000000004 0.05010986328125 0.0626220703125 0.1996826171875111 +2.0025 0.05010986328125 0.0626220703125 0.1996826171875111 +2.002625 0.05426025390625 0.06781005859375 0.1996826171875111 +2.0027500000000004 0.05426025390625 0.06781005859375 0.1996826171875111 +2.002875 0.05841064453125 0.072998046875 0.1996826171875111 +2.003 0.06256103515625 0.07818603515625 0.1996826171875111 +2.003125 0.06256103515625 0.07818603515625 0.1996826171875111 +2.00325 0.06671142578125 0.083343505859375 0.1996826171875111 +2.003375 0.06671142578125 0.083343505859375 0.1996826171875111 +2.0035 0.070831298828125 0.0885009765625 0.1996826171875111 +2.003625 0.074951171875 0.093658447265625 0.1996826171875111 +2.00375 0.074951171875 0.093658447265625 0.1996826171875111 +2.003875 0.079071044921875 0.098785400390625 0.1996826171875111 +2.004 0.079071044921875 0.098785400390625 0.1996826171875111 +2.004125 0.083160400390625 0.103912353515625 0.1996826171875111 +2.00425 0.087249755859375 0.109039306640625 0.1996826171875111 +2.004375 0.087249755859375 0.109039306640625 0.1996826171875111 +2.0045 0.091339111328125 0.1141357421875 0.1996826171875111 +2.004625 0.091339111328125 0.1141357421875 0.1996826171875111 +2.00475 0.095428466796875 0.119232177734375 0.1996826171875111 +2.004875 0.0994873046875 0.124298095703125 0.1996826171875111 +2.005 0.0994873046875 0.124298095703125 0.1996826171875111 +2.005125 0.103515625 0.129364013671875 0.1996826171875111 +2.00525 0.103515625 0.129364013671875 0.1996826171875111 +2.005375 0.107574462890625 0.134429931640625 0.1996826171875111 +2.0055 0.111602783203125 0.13946533203125 0.1996826171875111 +2.005625 0.111602783203125 0.13946533203125 0.1996826171875111 +2.00575 0.115631103515625 0.14447021484375 0.1996826171875111 +2.005875 0.115631103515625 0.14447021484375 0.1996826171875111 +2.0060000000000004 0.11962890625 0.14947509765625 0.1996826171875111 +2.006125 0.123626708984375 0.15447998046875 0.1996826171875111 +2.00625 0.123626708984375 0.15447998046875 0.1996826171875111 +2.0063750000000004 0.127593994140625 0.159454345703125 0.1996826171875111 +2.0065 0.127593994140625 0.159454345703125 0.1996826171875111 +2.006625 0.131561279296875 0.164398193359375 0.1996826171875111 +2.0067500000000004 0.135498046875 0.169342041015625 0.1996826171875111 +2.006875 0.135498046875 0.169342041015625 0.1996826171875111 +2.007 0.139434814453125 0.17425537109375 0.1996826171875111 +2.007125 0.139434814453125 0.17425537109375 0.1996826171875111 +2.00725 0.14337158203125 0.17913818359375 0.1996826171875111 +2.007375 0.14727783203125 0.18402099609375 0.1996826171875111 +2.0075 0.14727783203125 0.18402099609375 0.1996826171875111 +2.007625 0.151153564453125 0.188873291015625 0.1996826171875111 +2.00775 0.151153564453125 0.188873291015625 0.1996826171875111 +2.007875 0.155029296875 0.1937255859375 0.1996826171875111 +2.008 0.15887451171875 0.19854736328125 0.1996826171875111 +2.008125 0.15887451171875 0.19854736328125 0.1996826171875111 +2.00825 0.1627197265625 0.203338623046875 0.1996826171875111 +2.008375 0.1627197265625 0.203338623046875 0.1996826171875111 +2.0085 0.166534423828125 0.208099365234375 0.1996826171875111 +2.008625 0.17034912109375 0.212860107421875 0.1996826171875111 +2.00875 0.17034912109375 0.212860107421875 0.1996826171875111 +2.008875 0.17413330078125 0.21759033203125 0.1996826171875111 +2.009 0.17413330078125 0.21759033203125 0.1996826171875111 +2.009125 0.177886962890625 0.2222900390625 0.1996826171875111 +2.00925 0.181610107421875 0.226959228515625 0.1996826171875111 +2.009375 0.181610107421875 0.226959228515625 0.1996826171875111 +2.0095 0.185333251953125 0.231597900390625 0.1996826171875111 +2.009625 0.185333251953125 0.231597900390625 0.1996826171875111 +2.00975 0.189056396484375 0.236236572265625 0.1996826171875111 +2.009875 0.192718505859375 0.2408447265625 0.1996826171875111 +2.0100000000000004 0.192718505859375 0.2408447265625 0.1996826171875111 +2.010125 0.196380615234375 0.24542236328125 0.1996826171875111 +2.01025 0.196380615234375 0.24542236328125 0.1996826171875111 +2.0103750000000004 0.200042724609375 0.249969482421875 0.1996826171875111 +2.0105 0.203643798828125 0.25445556640625 0.1996826171875111 +2.010625 0.203643798828125 0.25445556640625 0.1996826171875111 +2.0107500000000004 0.207244873046875 0.25897216796875 0.1996826171875111 +2.010875 0.207244873046875 0.25897216796875 0.1996826171875111 +2.011 0.2108154296875 0.263427734375 0.1996826171875111 +2.011125 0.21435546875 0.267852783203125 0.1996826171875111 +2.01125 0.21435546875 0.267852783203125 0.1996826171875111 +2.011375 0.2178955078125 0.27227783203125 0.1996826171875111 +2.0115 0.2178955078125 0.27227783203125 0.1996826171875111 +2.011625 0.22137451171875 0.276641845703125 0.1996826171875111 +2.01175 0.224853515625 0.280975341796875 0.1996826171875111 +2.011875 0.224853515625 0.280975341796875 0.1996826171875111 +2.012 0.22833251953125 0.285308837890625 0.1996826171875111 +2.012125 0.22833251953125 0.285308837890625 0.1996826171875111 +2.01225 0.23175048828125 0.289581298828125 0.1996826171875111 +2.012375 0.235137939453125 0.2938232421875 0.1996826171875111 +2.0125 0.235137939453125 0.2938232421875 0.1996826171875111 +2.012625 0.238525390625 0.298065185546875 0.1996826171875111 +2.01275 0.238525390625 0.298065185546875 0.1996826171875111 +2.012875 0.24188232421875 0.30224609375 0.1996826171875111 +2.013 0.245208740234375 0.306396484375 0.1996826171875111 +2.013125 0.245208740234375 0.306396484375 0.1996826171875111 +2.01325 0.248504638671875 0.310516357421875 0.1996826171875111 +2.013375 0.248504638671875 0.310516357421875 0.1996826171875111 +2.0135 0.25177001953125 0.314605712890625 0.1996826171875111 +2.013625 0.2550048828125 0.31866455078125 0.1996826171875111 +2.01375 0.2550048828125 0.31866455078125 0.1996826171875111 +2.013875 0.25823974609375 0.322662353515625 0.1996826171875111 +2.0140000000000004 0.25823974609375 0.322662353515625 0.1996826171875111 +2.014125 0.26141357421875 0.32666015625 0.1996826171875111 +2.01425 0.26458740234375 0.330596923828125 0.1996826171875111 +2.0143750000000004 0.26458740234375 0.330596923828125 0.1996826171875111 +2.0145 0.2677001953125 0.334503173828125 0.1996826171875111 +2.014625 0.2677001953125 0.334503173828125 0.1996826171875111 +2.0147500000000004 0.27081298828125 0.33837890625 0.1996826171875111 +2.014875 0.27386474609375 0.34222412109375 0.1996826171875111 +2.015 0.27386474609375 0.34222412109375 0.1996826171875111 +2.015125 0.27691650390625 0.34600830078125 0.1996826171875111 +2.01525 0.27691650390625 0.34600830078125 0.1996826171875111 +2.015375 0.2799072265625 0.349761962890625 0.1996826171875111 +2.0155 0.28289794921875 0.353485107421875 0.1996826171875111 +2.015625 0.28289794921875 0.353485107421875 0.1996826171875111 +2.01575 0.285858154296875 0.357177734375 0.1996826171875111 +2.015875 0.285858154296875 0.357177734375 0.1996826171875111 From 9224ee99c26a088f51f42be6dbe4ab4a04cb7b87 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 12 Aug 2026 08:53:22 -0700 Subject: [PATCH 753/876] Add ESP32-S3-DevKitC-1-N32R16 board NeoPixel is on GPIO38 on this board, not GPIO48. Also adds sdkconfig-psram-16MB.defaults, which did not exist yet. Co-Authored-By: Claude Opus 5 (1M context) --- .../board.c | 9 +++ .../mpconfigboard.h | 21 +++++++ .../mpconfigboard.mk | 14 +++++ .../espressif_esp32s3_devkitc_1_n32r16/pins.c | 55 +++++++++++++++++++ .../sdkconfig | 14 +++++ .../sdkconfig-psram-16MB.defaults | 5 ++ 6 files changed, 118 insertions(+) create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/board.c create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.h create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.mk create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/pins.c create mode 100644 ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/sdkconfig create mode 100644 ports/espressif/esp-idf-config/sdkconfig-psram-16MB.defaults diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/board.c b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/board.c new file mode 100644 index 00000000000..a3a9eec0471 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "supervisor/board.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.h b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.h new file mode 100644 index 00000000000..9df0ebcdb40 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.h @@ -0,0 +1,21 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "ESP32-S3-DevKitC-1-N32R16" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_NEOPIXEL (&pin_GPIO38) + +#define CIRCUITPY_BOOT_BUTTON (&pin_GPIO0) + +#define DEFAULT_UART_BUS_RX (&pin_GPIO44) +#define DEFAULT_UART_BUS_TX (&pin_GPIO43) + +#define AUTORESET_DELAY_MS 500 diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.mk b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.mk new file mode 100644 index 00000000000..15fcf8697fc --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/mpconfigboard.mk @@ -0,0 +1,14 @@ +USB_VID = 0x303A +USB_PID = 0x7003 +USB_PRODUCT = "ESP32-S3-DevKitC-1-N32R16" +USB_MANUFACTURER = "Espressif" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_SIZE = 32MB +CIRCUITPY_ESP_FLASH_MODE = opi +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_SIZE = 16MB +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_FREQ = 80m diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/pins.c b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/pins.c new file mode 100644 index 00000000000..e77a3813e94 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/pins.c @@ -0,0 +1,55 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_IO0), MP_ROM_PTR(&pin_GPIO0) }, + { MP_ROM_QSTR(MP_QSTR_IO1), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_IO2), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_IO3), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_IO4), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_IO5), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_IO6), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_IO7), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_IO8), MP_ROM_PTR(&pin_GPIO8) }, + { MP_ROM_QSTR(MP_QSTR_IO9), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_IO10), MP_ROM_PTR(&pin_GPIO10) }, + { MP_ROM_QSTR(MP_QSTR_IO11), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_IO12), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_IO13), MP_ROM_PTR(&pin_GPIO13) }, + { MP_ROM_QSTR(MP_QSTR_IO14), MP_ROM_PTR(&pin_GPIO14) }, + { MP_ROM_QSTR(MP_QSTR_IO15), MP_ROM_PTR(&pin_GPIO15) }, + { MP_ROM_QSTR(MP_QSTR_IO16), MP_ROM_PTR(&pin_GPIO16) }, + { MP_ROM_QSTR(MP_QSTR_IO17), MP_ROM_PTR(&pin_GPIO17) }, + { MP_ROM_QSTR(MP_QSTR_IO18), MP_ROM_PTR(&pin_GPIO18) }, + { MP_ROM_QSTR(MP_QSTR_IO19), MP_ROM_PTR(&pin_GPIO19) }, + { MP_ROM_QSTR(MP_QSTR_IO20), MP_ROM_PTR(&pin_GPIO20) }, + { MP_ROM_QSTR(MP_QSTR_IO21), MP_ROM_PTR(&pin_GPIO21) }, + { MP_ROM_QSTR(MP_QSTR_IO35), MP_ROM_PTR(&pin_GPIO35) }, + { MP_ROM_QSTR(MP_QSTR_IO36), MP_ROM_PTR(&pin_GPIO36) }, + { MP_ROM_QSTR(MP_QSTR_IO37), MP_ROM_PTR(&pin_GPIO37) }, + { MP_ROM_QSTR(MP_QSTR_IO38), MP_ROM_PTR(&pin_GPIO38) }, + { MP_ROM_QSTR(MP_QSTR_IO39), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_IO40), MP_ROM_PTR(&pin_GPIO40) }, + { MP_ROM_QSTR(MP_QSTR_IO41), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_IO42), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_IO43), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_IO44), MP_ROM_PTR(&pin_GPIO44) }, + { MP_ROM_QSTR(MP_QSTR_IO45), MP_ROM_PTR(&pin_GPIO45) }, + { MP_ROM_QSTR(MP_QSTR_IO46), MP_ROM_PTR(&pin_GPIO46) }, + { MP_ROM_QSTR(MP_QSTR_IO47), MP_ROM_PTR(&pin_GPIO47) }, + { MP_ROM_QSTR(MP_QSTR_IO48), MP_ROM_PTR(&pin_GPIO48) }, + { MP_ROM_QSTR(MP_QSTR_NEOPIXEL), MP_ROM_PTR(&pin_GPIO38) }, + + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/sdkconfig b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/sdkconfig new file mode 100644 index 00000000000..e9628662160 --- /dev/null +++ b/ports/espressif/boards/espressif_esp32s3_devkitc_1_n32r16/sdkconfig @@ -0,0 +1,14 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# LWIP +# +# end of LWIP + +# end of Component config + +# end of Espressif IoT Development Framework Configuration diff --git a/ports/espressif/esp-idf-config/sdkconfig-psram-16MB.defaults b/ports/espressif/esp-idf-config/sdkconfig-psram-16MB.defaults new file mode 100644 index 00000000000..f3f2fc60bc6 --- /dev/null +++ b/ports/espressif/esp-idf-config/sdkconfig-psram-16MB.defaults @@ -0,0 +1,5 @@ +# CONFIG_SPIRAM_TYPE_AUTO is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM16 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM32 is not set +# CONFIG_SPIRAM_TYPE_ESPPSRAM64 is not set +CONFIG_SPIRAM_TYPE_AUTO=y From 763e414c16819e0d57870dfeca448c36cfeae1f5 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 12 Aug 2026 10:00:06 -0700 Subject: [PATCH 754/876] Add n32r16 to the shared DevKitC-1 VID/PID cluster All ESP32-S3-DevKitC-1 variants share 0x303A:0x7003. Co-Authored-By: Claude Opus 5 (1M context) --- tools/ci_check_duplicate_usb_vid_pid.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci_check_duplicate_usb_vid_pid.py b/tools/ci_check_duplicate_usb_vid_pid.py index 38cce0f28be..66a9fb4c5a3 100644 --- a/tools/ci_check_duplicate_usb_vid_pid.py +++ b/tools/ci_check_duplicate_usb_vid_pid.py @@ -58,6 +58,7 @@ "espressif_esp32s3_devkitc_1_n8r8_hacktablet", "espressif_esp32s3_devkitc_1_n16", "espressif_esp32s3_devkitc_1_n32r8", + "espressif_esp32s3_devkitc_1_n32r16", ], "0x303A:0x7009": [ "espressif_esp32s2_devkitc_1_n4", From 17810ad057876dcf54c2c36f762f79ff0c91538d Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 09:48:34 -0500 Subject: [PATCH 755/876] Only change loudness on zero crossing for both `audiomixer.Mixer` and `synthio.Synthesizer` --- shared-module/audiomixer/Mixer.c | 97 ++++++++++++++++++++------- shared-module/audiomixer/MixerVoice.h | 2 + shared-module/synthio/__init__.c | 28 ++++++-- shared-module/synthio/__init__.h | 1 + 4 files changed, 99 insertions(+), 29 deletions(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index f3111b8dc6f..6ce291d26cb 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -173,6 +173,18 @@ static inline uint32_t copy16msb(uint32_t val) { #endif } +static inline void assignmul(uint32_t word, uint32_t *last_word, int32_t *voice_lomul, int32_t *voice_himul, int32_t lomul, int32_t himul) { + if (MP_LIKELY(*voice_lomul == lomul) && MP_LIKELY(*voice_himul == himul)) { + return; + } + if (word == 0 || (*last_word != 0 && ((*last_word) & 0x80008000) != (word & 0x80008000))) { + *voice_lomul = lomul; + *voice_himul = himul; + } else { + *last_word = word; + } +} + #define ALMOST_ONE (MICROPY_FLOAT_CONST(32767.) / 32768) static void mix_down_one_voice(audiomixer_mixer_obj_t *self, @@ -245,35 +257,49 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, hi_level = (right_panning_scaled * hi_level) >> 15; } + int32_t voice_lo_level = voice->lo_level; + int32_t voice_hi_level = voice->hi_level; + uint32_t last_word = 0; + // First active voice gets copied over verbatim. if (!voices_active) { if (MP_LIKELY(self->base.bits_per_sample == 16)) { if (MP_LIKELY(self->base.samples_signed)) { if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { - uint32_t v = src[i]; - word_buffer[i] = mult16signed(v, lo_level, hi_level); + uint32_t word = src[i]; + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i] = mult16signed(word, voice_lo_level, voice_hi_level); } } else { for (uint32_t i = 0; i < n; i += 2) { - uint32_t v = src[i >> 1]; - word_buffer[i] = mult16signed(copy16lsb(v), lo_level, hi_level); - word_buffer[i + 1] = mult16signed(copy16msb(v), lo_level, hi_level); + uint32_t word = src[i >> 1]; + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i] = mult16signed(word_lsb, voice_lo_level, voice_hi_level); + word = copy16msb(word); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i + 1] = mult16signed(word, voice_lo_level, voice_hi_level); } } } else { if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { - uint32_t v = src[i]; - v = tosigned16(v); - word_buffer[i] = mult16signed(v, lo_level, hi_level); + uint32_t word = src[i]; + word = tosigned16(word); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i] = mult16signed(word, voice_lo_level, voice_hi_level); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { - uint32_t v = src[i >> 1]; - v = tosigned16(v); - word_buffer[i] = mult16signed(copy16lsb(v), lo_level, hi_level); - word_buffer[i + 1] = mult16signed(copy16msb(v), lo_level, hi_level); + uint32_t word = src[i >> 1]; + word = tosigned16(word); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i] = mult16signed(word_lsb, voice_lo_level, voice_hi_level); + word = copy16msb(word); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i + 1] = mult16signed(word, voice_lo_level, voice_hi_level); } } } @@ -286,7 +312,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - word = mult16signed(word, lo_level, hi_level); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word = mult16signed(word, voice_lo_level, voice_hi_level); hword_buffer[i] = pack8(word); } } else { @@ -295,8 +322,12 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - hword_buffer[i] = pack8(mult16signed(copy16lsb(word), lo_level, hi_level)); - hword_buffer[i + 1] = pack8(mult16signed(copy16msb(word), lo_level, hi_level)); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + hword_buffer[i] = pack8(mult16signed(word_lsb, voice_lo_level, voice_hi_level)); + word = copy16msb(word); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + hword_buffer[i + 1] = pack8(mult16signed(word, voice_lo_level, voice_hi_level)); } } } @@ -306,13 +337,18 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; - word_buffer[i] = add16signed(mult16signed(word, lo_level, hi_level), word_buffer[i]); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i] = add16signed(mult16signed(word, voice_lo_level, voice_hi_level), word_buffer[i]); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; - word_buffer[i] = add16signed(mult16signed(copy16lsb(word), lo_level, hi_level), word_buffer[i]); - word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), lo_level, hi_level), word_buffer[i + 1]); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i] = add16signed(mult16signed(word_lsb, voice_lo_level, voice_hi_level), word_buffer[i]); + word = copy16msb(word); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i + 1] = add16signed(mult16signed(word, voice_lo_level, voice_hi_level), word_buffer[i + 1]); } } } else { @@ -320,14 +356,19 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; word = tosigned16(word); - word_buffer[i] = add16signed(mult16signed(word, lo_level, hi_level), word_buffer[i]); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i] = add16signed(mult16signed(word, voice_lo_level, voice_hi_level), word_buffer[i]); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; word = tosigned16(word); - word_buffer[i] = add16signed(mult16signed(copy16lsb(word), lo_level, hi_level), word_buffer[i]); - word_buffer[i + 1] = add16signed(mult16signed(copy16msb(word), lo_level, hi_level), word_buffer[i + 1]); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i] = add16signed(mult16signed(word_lsb, voice_lo_level, voice_hi_level), word_buffer[i]); + word = copy16msb(word); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word_buffer[i + 1] = add16signed(mult16signed(word, voice_lo_level, voice_hi_level), word_buffer[i + 1]); } } } @@ -340,7 +381,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - word = mult16signed(word, lo_level, hi_level); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + word = mult16signed(word, voice_lo_level, voice_hi_level); word = add16signed(word, unpack8(hword_buffer[i])); hword_buffer[i] = pack8(word); } @@ -350,8 +392,12 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - hword_buffer[i] = pack8(add16signed(mult16signed(copy16lsb(word), lo_level, hi_level), unpack8(hword_buffer[i]))); - hword_buffer[i + 1] = pack8(add16signed(mult16signed(copy16msb(word), lo_level, hi_level), unpack8(hword_buffer[i + 1]))); + uint32_t word_lsb = copy16lsb(word); + assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + hword_buffer[i] = pack8(add16signed(mult16signed(word_lsb, voice_lo_level, voice_hi_level), unpack8(hword_buffer[i]))); + word = copy16msb(word); + assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); + hword_buffer[i + 1] = pack8(add16signed(mult16signed(word, voice_lo_level, voice_hi_level), unpack8(hword_buffer[i + 1]))); } } } @@ -365,6 +411,9 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, voice->remaining_buffer += n >> 1; voice->buffer_length -= n >> 1; } + + voice->lo_level = voice_lo_level; + voice->hi_level = voice_hi_level; } if (length && !voices_active) { diff --git a/shared-module/audiomixer/MixerVoice.h b/shared-module/audiomixer/MixerVoice.h index 75e7d47faa3..d683e9cb091 100644 --- a/shared-module/audiomixer/MixerVoice.h +++ b/shared-module/audiomixer/MixerVoice.h @@ -28,4 +28,6 @@ typedef struct { uint16_t level; int16_t panning; #endif + int32_t lo_level; + int32_t hi_level; } audiomixer_mixervoice_obj_t; diff --git a/shared-module/synthio/__init__.c b/shared-module/synthio/__init__.c index db0c449bfab..a3a9103d578 100644 --- a/shared-module/synthio/__init__.c +++ b/shared-module/synthio/__init__.c @@ -289,15 +289,33 @@ static mp_obj_t synthio_synth_get_note_filter(mp_obj_t note_obj) { return mp_const_none; } -static void sum_with_loudness(int32_t *out_buffer32, int32_t *tmp_buffer32, int16_t loudness[2], size_t dur, int synth_chan) { +static inline void assign_loudness(int32_t word, int32_t *last_word, int16_t note_loudness[2], int16_t loudness[2]) { + if (MP_LIKELY(note_loudness[0] == loudness[0]) && MP_LIKELY(note_loudness[1] == loudness[1])) { + return; + } + if (word == 0 || (*last_word != 0 && ((*last_word > 0) == (word < 0) || (*last_word < 0) == (word > 0)))) { + note_loudness[0] = loudness[0]; + note_loudness[1] = loudness[1]; + } else { + *last_word = word; + } +} + +static void sum_with_loudness(int32_t *out_buffer32, int32_t *tmp_buffer32, int16_t note_loudness[2], int16_t loudness[2], size_t dur, int synth_chan) { + int32_t word, last_word = 0; if (synth_chan == 1) { for (size_t i = 0; i < dur; i++) { - *out_buffer32++ += synthio_sat16((*tmp_buffer32++ *loudness[0]), 16); + word = *tmp_buffer32++; + assign_loudness(word, &last_word, note_loudness, loudness); + *out_buffer32++ += synthio_sat16((word * note_loudness[0]), 16); } } else { for (size_t i = 0; i < dur; i++) { - *out_buffer32++ += synthio_sat16((*tmp_buffer32 * loudness[0]), 16); - *out_buffer32++ += synthio_sat16((*tmp_buffer32++ *loudness[1]), 16); + word = *tmp_buffer32; + assign_loudness(word, &last_word, note_loudness, loudness); + *out_buffer32++ += synthio_sat16((word * note_loudness[0]), 16); + *out_buffer32++ += synthio_sat16((word * note_loudness[1]), 16); + tmp_buffer32++; } } } @@ -351,7 +369,7 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t } // adjust loudness by envelope - sum_with_loudness(out_buffer32, tmp_buffer32, loudness, dur, synth->base.channel_count); + sum_with_loudness(out_buffer32, tmp_buffer32, synth->loudness[chan], loudness, dur, synth->base.channel_count); } int16_t *out_buffer16 = (int16_t *)(void *)synth->buffers[synth->buffer_index]; diff --git a/shared-module/synthio/__init__.h b/shared-module/synthio/__init__.h index 5162b49fd55..4154553fb70 100644 --- a/shared-module/synthio/__init__.h +++ b/shared-module/synthio/__init__.h @@ -55,6 +55,7 @@ typedef struct synthio_synth { uint32_t accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; uint32_t ring_accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; synthio_envelope_state_t envelope_state[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; + int16_t loudness[CIRCUITPY_SYNTHIO_MAX_CHANNELS][2]; } synthio_synth_t; typedef struct { From 7e65486d5ea14fb3b7ad28df1d7850b15c6a939f Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 10:17:47 -0500 Subject: [PATCH 756/876] Force volume updates within `SYNTHIO_MAX_DUR` --- shared-module/audiomixer/Mixer.c | 4 ++-- shared-module/synthio/__init__.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 6ce291d26cb..1b7f49d534c 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -412,8 +412,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, voice->buffer_length -= n >> 1; } - voice->lo_level = voice_lo_level; - voice->hi_level = voice_hi_level; + voice->lo_level = lo_level; + voice->hi_level = hi_level; } if (length && !voices_active) { diff --git a/shared-module/synthio/__init__.c b/shared-module/synthio/__init__.c index a3a9103d578..7e60d8820d2 100644 --- a/shared-module/synthio/__init__.c +++ b/shared-module/synthio/__init__.c @@ -318,6 +318,8 @@ static void sum_with_loudness(int32_t *out_buffer32, int32_t *tmp_buffer32, int1 tmp_buffer32++; } } + note_loudness[0] = loudness[0]; + note_loudness[1] = loudness[1]; } void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) { From dfcd882e89c5c1aaa388dbb1439b732c40af0801 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 13 Aug 2026 09:05:08 -0700 Subject: [PATCH 757/876] usb_audio: refill the mic FIFO from tud_audio_tx_done_isr() TinyUSB services audio transfer completions in ISR context, so they never queue a USB event. On ports that pump the optional class tasks from a task loop sitting behind tud_task() (espressif), tud_task() blocks on a permanently empty queue and usb_audio_task() never runs. The mic FIFO is filled once, drains in a few frames, and the device emits zero length packets until the host gives up. Refill from tud_audio_tx_done_isr() instead, which TinyUSB invokes from the transfer complete path. usb_background_schedule() uses background_callback_add(), which is ISR safe and already called from usb_irq_handler() on other ports. No port changes are needed. Also enable usb_audio by default on esp32s3. The descriptor is gated on usb_audio_enabled(), so compiling it in claims no endpoints until enable() is called from boot.py. Tested on Metro ESP32-S3 and Metro ESP32-S2. --- ports/espressif/mpconfigport.mk | 8 ++++++++ shared-module/usb_audio/__init__.c | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 488591dd120..497dea28cfb 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -417,5 +417,13 @@ endif USB_NUM_ENDPOINT_PAIRS = 7 USB_NUM_IN_ENDPOINTS = 5 +# usb_audio is compiled in on the S3 but claims no endpoints until +# usb_audio.enable() is called from boot.py, so enabling it by default does not +# affect existing boards. Freeing one IN endpoint (usb_hid.disable()) is then the +# only thing a user needs, with no custom build. +ifeq ($(IDF_TARGET),esp32s3) +CIRCUITPY_USB_AUDIO ?= 1 +endif + # Usually lots of flash space available CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1 diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index cac47bbc5fe..397254cc7da 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -18,6 +18,7 @@ #include "py/mphal.h" #include "py/runtime.h" #include "supervisor/shared/tick.h" +#include "supervisor/usb.h" #include "tusb.h" static bool usb_audio_is_enabled = false; @@ -465,10 +466,33 @@ bool tud_audio_set_itf_cb(uint8_t rhport, tusb_control_request_t const *p_reques usb_audio_usbspeaker_streaming_reset(); } else if (itf == usb_audio_mic_as_itf) { usb_audio_mic_streaming = streaming; + if (streaming) { + // Prime the FIFO for the first frame; after that each completed + // transfer schedules the next refill via tud_audio_tx_done_isr(). + usb_background_schedule(); + } } return true; } +// Invoked from the audio class transfer-complete path once the next packet has +// been loaded into the EP IN buffer. TinyUSB services audio completions in ISR +// context, so they never queue a USB event. A port that pumps the optional class +// tasks from a task loop sitting behind tud_task() therefore never refills the +// microphone FIFO. Scheduling the refill here keeps usb_audio independent of how +// a port drives TinyUSB. +bool tud_audio_tx_done_isr(uint8_t rhport, uint16_t n_bytes_sent, uint8_t func_id, + uint8_t ep_in, uint8_t cur_alt_setting) { + (void)rhport; + (void)n_bytes_sent; + (void)func_id; + (void)ep_in; + (void)cur_alt_setting; + + usb_background_schedule(); + return true; +} + bool tud_audio_set_itf_close_ep_cb(uint8_t rhport, tusb_control_request_t const *p_request) { (void)rhport; uint8_t const itf = (uint8_t)tu_u16_low(p_request->wIndex); From e6106193e36ac0d454252a7fedd10c6ffc3d0264 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 13 Aug 2026 12:46:22 -0700 Subject: [PATCH 758/876] usb_audio: allocate the mic scratch buffer from the port heap Scott suggested port_malloc() for this in review. It replaces the static int16_t[USB_AUDIO_MAX_SAMPLE_RATE / 1000 * USB_AUDIO_N_CHANNELS] with an allocation sized by enable() for 1 ms at the negotiated rate, so a board that never calls enable() pays nothing for it. On Metro RP2040 .bss drops 188 bytes, the 192 freed less 4 for the pointer, against 32 bytes of added text. enable() can be called more than once, so it releases any chunk sized for a previous rate before taking a new one, and disable() frees as well. Tested 4 s at 48 kHz stereo, 1 kHz left and 3 kHz right, on Metro RP2040, Metro RP2350 and Feather nRF52840. All three write 768044 bytes with full channel separation, matching the static buffer exactly. The nRF52840 keeps both directions on endpoint 8. Co-Authored-By: Claude Opus 5 (1M context) --- shared-module/usb_audio/__init__.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/shared-module/usb_audio/__init__.c b/shared-module/usb_audio/__init__.c index 88bf9cd636d..281f60dba86 100644 --- a/shared-module/usb_audio/__init__.c +++ b/shared-module/usb_audio/__init__.c @@ -17,16 +17,17 @@ #include "py/misc.h" #include "py/mphal.h" #include "py/runtime.h" +#include "supervisor/port.h" #include "supervisor/shared/tick.h" #include "tusb.h" // Scratch chunk the microphone task hands to TinyUSB. It is written from the USB // background task for as long as the device is enabled, which outlives every VM, -// so it must not live on the MicroPython heap. Statically sized for -// 1 ms at the highest rate enable() accepts, in the wire format (always -// USB_AUDIO_N_CHANNELS channels); usb_audio_mic_samples_len is the part of it -// actually used at the negotiated rate. -static int16_t usb_audio_mic_samples[USB_AUDIO_MAX_SAMPLE_RATE / 1000 * USB_AUDIO_N_CHANNELS]; +// so it comes from the port heap rather than the MicroPython heap. Sized by +// enable() for 1 ms at the negotiated rate, in the wire format (always +// USB_AUDIO_N_CHANNELS channels), so a board that never calls enable() pays +// nothing for it. +static int16_t *usb_audio_mic_samples; static size_t usb_audio_mic_samples_len; static bool usb_audio_is_enabled = false; @@ -58,9 +59,15 @@ bool shared_module_usb_audio_enable(mp_int_t sample_rate, mp_int_t channel_count } // One scratch chunk (1 ms at the sample rate); we loop until the FIFO reaches - // the setpoint. + // the setpoint. enable() may be called more than once, so release any chunk + // sized for a previous rate before taking a new one. + port_free(usb_audio_mic_samples); usb_audio_mic_samples_len = sample_rate / 1000 * USB_AUDIO_BYTES_PER_FRAME; - memset(usb_audio_mic_samples, 0, usb_audio_mic_samples_len); + usb_audio_mic_samples = port_malloc_zero(usb_audio_mic_samples_len, false); + if (usb_audio_mic_samples == NULL) { + usb_audio_mic_samples_len = 0; + return false; + } usb_audio_sample_rate = sample_rate; usb_audio_channel_count = channel_count; @@ -76,6 +83,9 @@ bool shared_module_usb_audio_disable(void) { return false; } usb_audio_is_enabled = false; + port_free(usb_audio_mic_samples); + usb_audio_mic_samples = NULL; + usb_audio_mic_samples_len = 0; return true; } From 8378f65439f586871ec8782feb00915301fac34f Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 15:06:51 -0500 Subject: [PATCH 759/876] Remove inline from zero cross loudness functions --- shared-module/audiomixer/Mixer.c | 2 +- shared-module/synthio/__init__.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 1b7f49d534c..72e7ece6574 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -173,7 +173,7 @@ static inline uint32_t copy16msb(uint32_t val) { #endif } -static inline void assignmul(uint32_t word, uint32_t *last_word, int32_t *voice_lomul, int32_t *voice_himul, int32_t lomul, int32_t himul) { +static void assignmul(uint32_t word, uint32_t *last_word, int32_t *voice_lomul, int32_t *voice_himul, int32_t lomul, int32_t himul) { if (MP_LIKELY(*voice_lomul == lomul) && MP_LIKELY(*voice_himul == himul)) { return; } diff --git a/shared-module/synthio/__init__.c b/shared-module/synthio/__init__.c index 7e60d8820d2..01e90e847b4 100644 --- a/shared-module/synthio/__init__.c +++ b/shared-module/synthio/__init__.c @@ -289,7 +289,7 @@ static mp_obj_t synthio_synth_get_note_filter(mp_obj_t note_obj) { return mp_const_none; } -static inline void assign_loudness(int32_t word, int32_t *last_word, int16_t note_loudness[2], int16_t loudness[2]) { +static void assign_loudness(int32_t word, int32_t *last_word, int16_t note_loudness[2], int16_t loudness[2]) { if (MP_LIKELY(note_loudness[0] == loudness[0]) && MP_LIKELY(note_loudness[1] == loudness[1])) { return; } From 04b790ac6465e79299c00443144130034c8d8692 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 15:13:55 -0500 Subject: [PATCH 760/876] Increase clarity of active and pending loudness --- shared-module/audiomixer/Mixer.c | 96 +++++++++++++-------------- shared-module/audiomixer/MixerVoice.h | 4 +- shared-module/synthio/__init__.c | 26 ++++---- shared-module/synthio/__init__.h | 2 +- 4 files changed, 64 insertions(+), 64 deletions(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 72e7ece6574..ed152bf7142 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -173,13 +173,13 @@ static inline uint32_t copy16msb(uint32_t val) { #endif } -static void assignmul(uint32_t word, uint32_t *last_word, int32_t *voice_lomul, int32_t *voice_himul, int32_t lomul, int32_t himul) { - if (MP_LIKELY(*voice_lomul == lomul) && MP_LIKELY(*voice_himul == himul)) { +static void assignmul(uint32_t word, uint32_t *last_word, int32_t *active_lomul, int32_t *active_himul, int32_t pending_lomul, int32_t pending_himul) { + if (MP_LIKELY(*active_lomul == pending_lomul) && MP_LIKELY(*active_himul == pending_himul)) { return; } if (word == 0 || (*last_word != 0 && ((*last_word) & 0x80008000) != (word & 0x80008000))) { - *voice_lomul = lomul; - *voice_himul = himul; + *active_lomul = pending_lomul; + *active_himul = pending_himul; } else { *last_word = word; } @@ -250,15 +250,15 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, } } - int32_t lo_level = level; - int32_t hi_level = level; + int32_t pending_lo_level = level; + int32_t pending_hi_level = level; if (MP_LIKELY(self->base.channel_count == 2)) { - lo_level = (left_panning_scaled * lo_level) >> 15; - hi_level = (right_panning_scaled * hi_level) >> 15; + pending_lo_level = (left_panning_scaled * pending_lo_level) >> 15; + pending_hi_level = (right_panning_scaled * pending_hi_level) >> 15; } - int32_t voice_lo_level = voice->lo_level; - int32_t voice_hi_level = voice->hi_level; + int32_t active_lo_level = voice->active_lo_level; + int32_t active_hi_level = voice->active_hi_level; uint32_t last_word = 0; // First active voice gets copied over verbatim. @@ -268,18 +268,18 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i] = mult16signed(word, voice_lo_level, voice_hi_level); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = mult16signed(word, active_lo_level, active_hi_level); } } else { for (uint32_t i = 0; i < n; i += 2) { uint32_t word = src[i >> 1]; uint32_t word_lsb = copy16lsb(word); - assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i] = mult16signed(word_lsb, voice_lo_level, voice_hi_level); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = mult16signed(word_lsb, active_lo_level, active_hi_level); word = copy16msb(word); - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i + 1] = mult16signed(word, voice_lo_level, voice_hi_level); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i + 1] = mult16signed(word, active_lo_level, active_hi_level); } } } else { @@ -287,19 +287,19 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; word = tosigned16(word); - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i] = mult16signed(word, voice_lo_level, voice_hi_level); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = mult16signed(word, active_lo_level, active_hi_level); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; word = tosigned16(word); uint32_t word_lsb = copy16lsb(word); - assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i] = mult16signed(word_lsb, voice_lo_level, voice_hi_level); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = mult16signed(word_lsb, active_lo_level, active_hi_level); word = copy16msb(word); - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i + 1] = mult16signed(word, voice_lo_level, voice_hi_level); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i + 1] = mult16signed(word, active_lo_level, active_hi_level); } } } @@ -312,8 +312,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word = mult16signed(word, voice_lo_level, voice_hi_level); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word = mult16signed(word, active_lo_level, active_hi_level); hword_buffer[i] = pack8(word); } } else { @@ -323,11 +323,11 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, word = tosigned16(word); } uint32_t word_lsb = copy16lsb(word); - assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - hword_buffer[i] = pack8(mult16signed(word_lsb, voice_lo_level, voice_hi_level)); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + hword_buffer[i] = pack8(mult16signed(word_lsb, active_lo_level, active_hi_level)); word = copy16msb(word); - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - hword_buffer[i + 1] = pack8(mult16signed(word, voice_lo_level, voice_hi_level)); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + hword_buffer[i + 1] = pack8(mult16signed(word, active_lo_level, active_hi_level)); } } } @@ -337,18 +337,18 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(self->base.channel_count == sample->channel_count)) { for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i] = add16signed(mult16signed(word, voice_lo_level, voice_hi_level), word_buffer[i]); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = add16signed(mult16signed(word, active_lo_level, active_hi_level), word_buffer[i]); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; uint32_t word_lsb = copy16lsb(word); - assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i] = add16signed(mult16signed(word_lsb, voice_lo_level, voice_hi_level), word_buffer[i]); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = add16signed(mult16signed(word_lsb, active_lo_level, active_hi_level), word_buffer[i]); word = copy16msb(word); - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i + 1] = add16signed(mult16signed(word, voice_lo_level, voice_hi_level), word_buffer[i + 1]); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i + 1] = add16signed(mult16signed(word, active_lo_level, active_hi_level), word_buffer[i + 1]); } } } else { @@ -356,19 +356,19 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, for (uint32_t i = 0; i < n; i++) { uint32_t word = src[i]; word = tosigned16(word); - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i] = add16signed(mult16signed(word, voice_lo_level, voice_hi_level), word_buffer[i]); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = add16signed(mult16signed(word, active_lo_level, active_hi_level), word_buffer[i]); } } else { for (uint32_t i = 0; i + 1 < n; i += 2) { uint32_t word = src[i >> 1]; word = tosigned16(word); uint32_t word_lsb = copy16lsb(word); - assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i] = add16signed(mult16signed(word_lsb, voice_lo_level, voice_hi_level), word_buffer[i]); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i] = add16signed(mult16signed(word_lsb, active_lo_level, active_hi_level), word_buffer[i]); word = copy16msb(word); - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word_buffer[i + 1] = add16signed(mult16signed(word, voice_lo_level, voice_hi_level), word_buffer[i + 1]); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word_buffer[i + 1] = add16signed(mult16signed(word, active_lo_level, active_hi_level), word_buffer[i + 1]); } } } @@ -381,8 +381,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, if (MP_LIKELY(!self->base.samples_signed)) { word = tosigned16(word); } - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - word = mult16signed(word, voice_lo_level, voice_hi_level); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + word = mult16signed(word, active_lo_level, active_hi_level); word = add16signed(word, unpack8(hword_buffer[i])); hword_buffer[i] = pack8(word); } @@ -393,11 +393,11 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, word = tosigned16(word); } uint32_t word_lsb = copy16lsb(word); - assignmul(word_lsb, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - hword_buffer[i] = pack8(add16signed(mult16signed(word_lsb, voice_lo_level, voice_hi_level), unpack8(hword_buffer[i]))); + assignmul(word_lsb, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + hword_buffer[i] = pack8(add16signed(mult16signed(word_lsb, active_lo_level, active_hi_level), unpack8(hword_buffer[i]))); word = copy16msb(word); - assignmul(word, &last_word, &voice_lo_level, &voice_hi_level, lo_level, hi_level); - hword_buffer[i + 1] = pack8(add16signed(mult16signed(word, voice_lo_level, voice_hi_level), unpack8(hword_buffer[i + 1]))); + assignmul(word, &last_word, &active_lo_level, &active_hi_level, pending_lo_level, pending_hi_level); + hword_buffer[i + 1] = pack8(add16signed(mult16signed(word, active_lo_level, active_hi_level), unpack8(hword_buffer[i + 1]))); } } } @@ -412,8 +412,8 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, voice->buffer_length -= n >> 1; } - voice->lo_level = lo_level; - voice->hi_level = hi_level; + voice->active_lo_level = pending_lo_level; + voice->active_hi_level = pending_hi_level; } if (length && !voices_active) { diff --git a/shared-module/audiomixer/MixerVoice.h b/shared-module/audiomixer/MixerVoice.h index d683e9cb091..db5cac1ca27 100644 --- a/shared-module/audiomixer/MixerVoice.h +++ b/shared-module/audiomixer/MixerVoice.h @@ -28,6 +28,6 @@ typedef struct { uint16_t level; int16_t panning; #endif - int32_t lo_level; - int32_t hi_level; + int32_t active_lo_level; + int32_t active_hi_level; } audiomixer_mixervoice_obj_t; diff --git a/shared-module/synthio/__init__.c b/shared-module/synthio/__init__.c index 01e90e847b4..6cf4f31a011 100644 --- a/shared-module/synthio/__init__.c +++ b/shared-module/synthio/__init__.c @@ -289,37 +289,37 @@ static mp_obj_t synthio_synth_get_note_filter(mp_obj_t note_obj) { return mp_const_none; } -static void assign_loudness(int32_t word, int32_t *last_word, int16_t note_loudness[2], int16_t loudness[2]) { - if (MP_LIKELY(note_loudness[0] == loudness[0]) && MP_LIKELY(note_loudness[1] == loudness[1])) { +static void assign_loudness(int32_t word, int32_t *last_word, int16_t active_loudness[2], int16_t pending_loudness[2]) { + if (MP_LIKELY(active_loudness[0] == pending_loudness[0]) && MP_LIKELY(active_loudness[1] == pending_loudness[1])) { return; } if (word == 0 || (*last_word != 0 && ((*last_word > 0) == (word < 0) || (*last_word < 0) == (word > 0)))) { - note_loudness[0] = loudness[0]; - note_loudness[1] = loudness[1]; + active_loudness[0] = pending_loudness[0]; + active_loudness[1] = pending_loudness[1]; } else { *last_word = word; } } -static void sum_with_loudness(int32_t *out_buffer32, int32_t *tmp_buffer32, int16_t note_loudness[2], int16_t loudness[2], size_t dur, int synth_chan) { +static void sum_with_loudness(int32_t *out_buffer32, int32_t *tmp_buffer32, int16_t active_loudness[2], int16_t pending_loudness[2], size_t dur, int synth_chan) { int32_t word, last_word = 0; if (synth_chan == 1) { for (size_t i = 0; i < dur; i++) { word = *tmp_buffer32++; - assign_loudness(word, &last_word, note_loudness, loudness); - *out_buffer32++ += synthio_sat16((word * note_loudness[0]), 16); + assign_loudness(word, &last_word, active_loudness, pending_loudness); + *out_buffer32++ += synthio_sat16((word * active_loudness[0]), 16); } } else { for (size_t i = 0; i < dur; i++) { word = *tmp_buffer32; - assign_loudness(word, &last_word, note_loudness, loudness); - *out_buffer32++ += synthio_sat16((word * note_loudness[0]), 16); - *out_buffer32++ += synthio_sat16((word * note_loudness[1]), 16); + assign_loudness(word, &last_word, active_loudness, pending_loudness); + *out_buffer32++ += synthio_sat16((word * active_loudness[0]), 16); + *out_buffer32++ += synthio_sat16((word * active_loudness[1]), 16); tmp_buffer32++; } } - note_loudness[0] = loudness[0]; - note_loudness[1] = loudness[1]; + active_loudness[0] = pending_loudness[0]; + active_loudness[1] = pending_loudness[1]; } void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t *buffer_length, uint8_t channel) { @@ -371,7 +371,7 @@ void synthio_synth_synthesize(synthio_synth_t *synth, uint8_t **bufptr, uint32_t } // adjust loudness by envelope - sum_with_loudness(out_buffer32, tmp_buffer32, synth->loudness[chan], loudness, dur, synth->base.channel_count); + sum_with_loudness(out_buffer32, tmp_buffer32, synth->active_loudness[chan], loudness, dur, synth->base.channel_count); } int16_t *out_buffer16 = (int16_t *)(void *)synth->buffers[synth->buffer_index]; diff --git a/shared-module/synthio/__init__.h b/shared-module/synthio/__init__.h index 4154553fb70..0335831f80f 100644 --- a/shared-module/synthio/__init__.h +++ b/shared-module/synthio/__init__.h @@ -55,7 +55,7 @@ typedef struct synthio_synth { uint32_t accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; uint32_t ring_accum[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; synthio_envelope_state_t envelope_state[CIRCUITPY_SYNTHIO_MAX_CHANNELS]; - int16_t loudness[CIRCUITPY_SYNTHIO_MAX_CHANNELS][2]; + int16_t active_loudness[CIRCUITPY_SYNTHIO_MAX_CHANNELS][2]; } synthio_synth_t; typedef struct { From 8ca9f0925e0c86c4ccda37433263ce8cf9e51b7f Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 15:31:32 -0500 Subject: [PATCH 761/876] Add comments to zero crossing detection --- shared-module/audiomixer/Mixer.c | 18 ++++++++++++++++++ shared-module/synthio/__init__.c | 17 +++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index ed152bf7142..88c842fcebc 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -173,14 +173,29 @@ static inline uint32_t copy16msb(uint32_t val) { #endif } +// Rather than immediately changing the loudness of audio playback, we keep a separate buffer of +// the "active" loudness and wait until we meet the conditions of a "zero crossing". A zero crossing +// occurs when either the current value is 0 or the value changes from negative to positive or +// vice-versa. This is detected by keeping a copy of the previous frame of audio data and checking +// to see if the sign of the value has changed. By only changing loudness during zero crossings, we +// avoid audible pops/clicks which can be unpleasant. static void assignmul(uint32_t word, uint32_t *last_word, int32_t *active_lomul, int32_t *active_himul, int32_t pending_lomul, int32_t pending_himul) { + // If the active loudness already matches the pending loudness, exit early. if (MP_LIKELY(*active_lomul == pending_lomul) && MP_LIKELY(*active_himul == pending_himul)) { return; } + + // Check for a zero crossing: current value is 0 or has changed sign from the previous value. + // We check for the sign change by bitmasking only the top bits of each 16-bit signed value + // packed into the 32-bit word (two's complement). If either bit doesn't match the previous + // value, a sign change has occurred on either the left or right channel. if (word == 0 || (*last_word != 0 && ((*last_word) & 0x80008000) != (word & 0x80008000))) { + // Copy over our pending loudness. Will cause future calls to `assignmul` to exit early. *active_lomul = pending_lomul; *active_himul = pending_himul; } else { + // Update our copy of the previous word for future comparisons (an initial value of 0 is + // ignored). *last_word = word; } } @@ -412,6 +427,9 @@ static void mix_down_one_voice(audiomixer_mixer_obj_t *self, voice->buffer_length -= n >> 1; } + // Force the active level to match the pending level in the case that the conditions of a + // zero crossing weren't met within the last `SYNTHIO_MAX_DUR` frames. Will ensure minimal + // delay in level or panning changes at the potential expensive of an audible pop. voice->active_lo_level = pending_lo_level; voice->active_hi_level = pending_hi_level; } diff --git a/shared-module/synthio/__init__.c b/shared-module/synthio/__init__.c index 6cf4f31a011..b30b5f35b5f 100644 --- a/shared-module/synthio/__init__.c +++ b/shared-module/synthio/__init__.c @@ -289,14 +289,27 @@ static mp_obj_t synthio_synth_get_note_filter(mp_obj_t note_obj) { return mp_const_none; } +// Rather than immediately changing the loudness of audio playback, we keep a separate buffer of +// the "active" loudness and wait until we meet the conditions of a "zero crossing". A zero crossing +// occurs when either the current value is 0 or the value changes from negative to positive or +// vice-versa. This is detected by keeping a copy of the previous frame of audio data and checking +// to see if the sign of the value has changed. By only changing loudness during zero crossings, we +// avoid audible pops/clicks which can be unpleasant. static void assign_loudness(int32_t word, int32_t *last_word, int16_t active_loudness[2], int16_t pending_loudness[2]) { + // If the active loudness already matches the pending loudness, exit early. if (MP_LIKELY(active_loudness[0] == pending_loudness[0]) && MP_LIKELY(active_loudness[1] == pending_loudness[1])) { return; } + + // Check for a zero crossing: current value is 0 or has changed sign from the previous value. if (word == 0 || (*last_word != 0 && ((*last_word > 0) == (word < 0) || (*last_word < 0) == (word > 0)))) { + // Copy over our pending loudness. Will cause future calls to `assign_loudness` to exit + // early. active_loudness[0] = pending_loudness[0]; active_loudness[1] = pending_loudness[1]; } else { + // Update our copy of the previous word for future comparisons (an initial value of 0 is + // ignored). *last_word = word; } } @@ -318,6 +331,10 @@ static void sum_with_loudness(int32_t *out_buffer32, int32_t *tmp_buffer32, int1 tmp_buffer32++; } } + + // Force the active loudness to match the pending loudness just in case the conditions of a + // zero crossing weren't met within the last `SYNTHIO_MAX_DUR` frames. Will ensure minimal + // delay in amplitude or panning changes at the potential expensive of an audible pop. active_loudness[0] = pending_loudness[0]; active_loudness[1] = pending_loudness[1]; } From 93591cc742ee83854ce15e8e846e6fbb6629498b Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Thu, 13 Aug 2026 20:31:53 +0000 Subject: [PATCH 762/876] picodvi: rename deadline to timeout per review --- ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c index 3e1ea51ecb7..8c846ffc440 100644 --- a/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c +++ b/ports/raspberrypi/common-hal/picodvi/Framebuffer_RP2350.c @@ -640,10 +640,10 @@ void common_hal_picodvi_framebuffer_wait_for_vblank(picodvi_framebuffer_obj_t *s return; } uint32_t start = framebuffer_frame_count; - uint64_t deadline = common_hal_time_monotonic_ms() + 30; // ~2 frames @ 60 Hz + uint64_t timeout = common_hal_time_monotonic_ms() + 30; // ~2 frames @ 60 Hz while (framebuffer_frame_count == start) { RUN_BACKGROUND_TASKS; // don't starve USB host / other tasks during the ~<16 ms wait - if (common_hal_time_monotonic_ms() >= deadline) { + if (common_hal_time_monotonic_ms() >= timeout) { break; } } From fccfdbb8a6ddb2400f5991eb7a762b1f1b54ef8d Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 15:32:23 -0500 Subject: [PATCH 763/876] Check left and right channels independently for zero value --- shared-module/audiomixer/Mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 88c842fcebc..1177b6e0015 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -189,7 +189,7 @@ static void assignmul(uint32_t word, uint32_t *last_word, int32_t *active_lomul, // We check for the sign change by bitmasking only the top bits of each 16-bit signed value // packed into the 32-bit word (two's complement). If either bit doesn't match the previous // value, a sign change has occurred on either the left or right channel. - if (word == 0 || (*last_word != 0 && ((*last_word) & 0x80008000) != (word & 0x80008000))) { + if ((word & 0xffff0000) == 0 || (word & 0x0000ffff) == 0 || (*last_word != 0 && ((*last_word) & 0x80008000) != (word & 0x80008000))) { // Copy over our pending loudness. Will cause future calls to `assignmul` to exit early. *active_lomul = pending_lomul; *active_himul = pending_himul; From aaa4441c9c46391817c5273be03d5a2249efdce7 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 20:44:35 -0500 Subject: [PATCH 764/876] Add filter to `audiodelays.Echo` --- shared-bindings/audiodelays/Echo.c | 31 ++++++++++- shared-bindings/audiodelays/Echo.h | 5 +- shared-module/audiodelays/Echo.c | 89 +++++++++++++++++++++++++++--- shared-module/audiodelays/Echo.h | 6 ++ shared-module/synthio/Biquad.c | 19 ++++++- shared-module/synthio/Biquad.h | 1 + 6 files changed, 140 insertions(+), 11 deletions(-) diff --git a/shared-bindings/audiodelays/Echo.c b/shared-bindings/audiodelays/Echo.c index dbb496c61b9..f1c79de0e13 100644 --- a/shared-bindings/audiodelays/Echo.c +++ b/shared-bindings/audiodelays/Echo.c @@ -25,6 +25,7 @@ //| max_delay_ms: int = 500, //| delay_ms: synthio.BlockInput = 250.0, //| decay: synthio.BlockInput = 0.7, +//| filter: Optional[synthio.Biquad | Tuple[synthio.Biquad]] = None, //| mix: synthio.BlockInput = 0.25, //| buffer_size: int = 512, //| sample_rate: int = 8000, @@ -45,6 +46,7 @@ //| :param int max_delay_ms: The maximum time the echo can be in milliseconds //| :param synthio.BlockInput delay_ms: The current time of the echo delay in milliseconds. Must be less the max_delay_ms //| :param synthio.BlockInput decay: The rate the echo fades. 0.0 = instant; 1.0 = never. +//| :param Optional[synthio.Biquad|Tuple[synthio.Biquad]] filter: A normalized biquad filter object or tuple of normalized biquad filter objects. A copy of the samples are processed sequentially by each filter before writing into the echo buffer. The original samples are not affected by this argument. //| :param synthio.BlockInput mix: The mix as a ratio of the sample (0.0) to the effect (1.0). //| :param int buffer_size: The total size in bytes of each of the two playback buffers to use //| :param int sample_rate: The sample rate to be used @@ -76,11 +78,12 @@ //| ... //| static mp_obj_t audiodelays_echo_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_max_delay_ms, ARG_delay_ms, ARG_decay, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, ARG_freq_shift, }; + enum { ARG_max_delay_ms, ARG_delay_ms, ARG_decay, ARG_filter, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, ARG_freq_shift, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_max_delay_ms, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 500 } }, { MP_QSTR_delay_ms, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_decay, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } }, { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, @@ -103,7 +106,7 @@ static mp_obj_t audiodelays_echo_make_new(const mp_obj_type_t *type, size_t n_ar } audiodelays_echo_obj_t *self = mp_obj_malloc(audiodelays_echo_obj_t, &audiodelays_echo_type); - common_hal_audiodelays_echo_construct(self, max_delay_ms, args[ARG_delay_ms].u_obj, args[ARG_decay].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate, args[ARG_freq_shift].u_bool); + common_hal_audiodelays_echo_construct(self, max_delay_ms, args[ARG_delay_ms].u_obj, args[ARG_decay].u_obj, args[ARG_filter].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate, args[ARG_freq_shift].u_bool); return MP_OBJ_FROM_PTR(self); } @@ -177,6 +180,29 @@ MP_PROPERTY_GETSET(audiodelays_echo_decay_obj, (mp_obj_t)&audiodelays_echo_get_decay_obj, (mp_obj_t)&audiodelays_echo_set_decay_obj); + +//| filter: synthio.Biquad | Tuple[synthio.Biquad] | None +//| """A normalized biquad filter object or tuple of normalized biquad filter objects. A copy of the samples are processed sequentially by each filter before writing into the echo buffer. The original samples are not affected by this property.""" +//| +static mp_obj_t audiodelays_echo_obj_get_filter(mp_obj_t self_in) { + audiodelays_echo_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_audiodelays_echo_get_filter(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiodelays_echo_get_filter_obj, audiodelays_echo_obj_get_filter); + +static mp_obj_t audiodelays_echo_obj_set_filter(mp_obj_t self_in, mp_obj_t filter_in) { + audiodelays_echo_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiodelays_echo_set_filter(self, filter_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiodelays_echo_set_filter_obj, audiodelays_echo_obj_set_filter); + +MP_PROPERTY_GETSET(audiodelays_echo_filter_obj, + (mp_obj_t)&audiodelays_echo_get_filter_obj, + (mp_obj_t)&audiodelays_echo_set_filter_obj); + + //| mix: synthio.BlockInput //| """The rate the echo mix between 0 and 1 where 0 is only sample, 0.5 is an equal mix of the sample and the effect and 1 is all effect.""" static mp_obj_t audiodelays_echo_obj_get_mix(mp_obj_t self_in) { @@ -285,6 +311,7 @@ static const mp_rom_map_elem_t audiodelays_echo_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiodelays_echo_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_delay_ms), MP_ROM_PTR(&audiodelays_echo_delay_ms_obj) }, { MP_ROM_QSTR(MP_QSTR_decay), MP_ROM_PTR(&audiodelays_echo_decay_obj) }, + { MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&audiodelays_echo_filter_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiodelays_echo_mix_obj) }, { MP_ROM_QSTR(MP_QSTR_freq_shift), MP_ROM_PTR(&audiodelays_echo_freq_shift_obj) }, AUDIOSAMPLE_FIELDS, diff --git a/shared-bindings/audiodelays/Echo.h b/shared-bindings/audiodelays/Echo.h index 83d454ed05c..67b7436b896 100644 --- a/shared-bindings/audiodelays/Echo.h +++ b/shared-bindings/audiodelays/Echo.h @@ -11,7 +11,7 @@ extern const mp_obj_type_t audiodelays_echo_type; void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_t max_delay_ms, - mp_obj_t delay_ms, mp_obj_t decay, mp_obj_t mix, + mp_obj_t delay_ms, mp_obj_t decay, mp_obj_t filter, mp_obj_t mix, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate, bool freq_shift); @@ -26,6 +26,9 @@ void common_hal_audiodelays_echo_set_freq_shift(audiodelays_echo_obj_t *self, bo mp_obj_t common_hal_audiodelays_echo_get_decay(audiodelays_echo_obj_t *self); void common_hal_audiodelays_echo_set_decay(audiodelays_echo_obj_t *self, mp_obj_t decay); +mp_obj_t common_hal_audiodelays_echo_get_filter(audiodelays_echo_obj_t *self); +void common_hal_audiodelays_echo_set_filter(audiodelays_echo_obj_t *self, mp_obj_t arg); + mp_obj_t common_hal_audiodelays_echo_get_mix(audiodelays_echo_obj_t *self); void common_hal_audiodelays_echo_set_mix(audiodelays_echo_obj_t *self, mp_obj_t arg); diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index b2501b7d01e..243fd365f4a 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -11,7 +11,7 @@ #include void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_t max_delay_ms, - mp_obj_t delay_ms, mp_obj_t decay, mp_obj_t mix, + mp_obj_t delay_ms, mp_obj_t decay, mp_obj_t filter, mp_obj_t mix, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate, bool freq_shift) { @@ -59,6 +59,8 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_ // The below section sets up the echo effect's starting values. For a different effect this section will change + common_hal_audiodelays_echo_set_filter(self, filter); + // If we did not receive a BlockInput we need to create a default float value if (decay == MP_OBJ_NULL) { decay = mp_obj_new_float(MICROPY_FLOAT_CONST(0.7)); @@ -109,6 +111,8 @@ void common_hal_audiodelays_echo_deinit(audiodelays_echo_obj_t *self) { self->echo_buffer = NULL; self->buffer[0] = NULL; self->buffer[1] = NULL; + self->filter = mp_const_none; + self->filter_states = NULL; } mp_obj_t common_hal_audiodelays_echo_get_delay_ms(audiodelays_echo_obj_t *self) { @@ -166,6 +170,55 @@ void common_hal_audiodelays_echo_set_decay(audiodelays_echo_obj_t *self, mp_obj_ synthio_block_assign_slot(decay, &self->decay, MP_QSTR_decay); } +mp_obj_t common_hal_audiodelays_echo_get_filter(audiodelays_echo_obj_t *self) { + return self->filter; +} + +void common_hal_audiodelays_echo_set_filter(audiodelays_echo_obj_t *self, mp_obj_t filter_in) { + size_t n_items; + mp_obj_t *items; + mp_obj_t *filter_objs; + + if (filter_in == mp_const_none) { + n_items = 0; + filter_objs = NULL; + } else if (MP_OBJ_TYPE_HAS_SLOT(mp_obj_get_type(filter_in), iter)) { + // convert object to tuple if it wasn't before + filter_in = MP_OBJ_TYPE_GET_SLOT(&mp_type_tuple, make_new)( + &mp_type_tuple, 1, 0, &filter_in); + mp_obj_tuple_get(filter_in, &n_items, &items); + for (size_t i = 0; i < n_items; i++) { + if (!mp_obj_is_type(items[i], &synthio_biquad_type_obj)) { + mp_raise_TypeError_varg( + MP_ERROR_TEXT("%q in %q must be of type %q, not %q"), + MP_QSTR_object, + MP_QSTR_filter, + MP_QSTR_Biquad, + mp_obj_get_type(items[i])->name); + } + } + filter_objs = items; + } else { + n_items = 1; + if (!mp_obj_is_type(filter_in, &synthio_biquad_type_obj)) { + mp_raise_TypeError_varg( + MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_filter, MP_QSTR_Biquad, MP_QSTR_iterable, mp_obj_get_type(filter_in)->name); + } + filter_objs = &self->filter; + } + + // everything has been checked, so we can do the following without fear + + self->filter = filter_in; + self->filter_objs = filter_objs; + self->filter_states = m_renew(biquad_filter_state, + self->filter_states, + self->filter_objs_len * self->base.channel_count, + n_items * self->base.channel_count); + self->filter_objs_len = n_items; +} + mp_obj_t common_hal_audiodelays_echo_get_mix(audiodelays_echo_obj_t *self) { return self->mix.obj; } @@ -197,6 +250,12 @@ void audiodelays_echo_reset_buffer(audiodelays_echo_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); memset(self->echo_buffer, 0, self->max_echo_buffer_len); + + if (self->filter_states) { + for (uint8_t i = 0; i < self->filter_objs_len * self->base.channel_count; i++) { + synthio_biquad_filter_reset(&self->filter_states[i]); + } + } } bool common_hal_audiodelays_echo_get_playing(audiodelays_echo_obj_t *self) { @@ -227,6 +286,17 @@ void common_hal_audiodelays_echo_stop(audiodelays_echo_obj_t *self) { return; } +static int32_t process_biquad_filters(audiodelays_echo_obj_t *self, uint8_t channel, int32_t word) { + // Process biquad filters + for (uint8_t j = 0; j < self->filter_objs_len; j++) { + mp_obj_t filter_obj = self->filter_objs[j]; + for (uint8_t k = 0; k < self->base.channel_count; k++) { + word = synthio_biquad_filter_sample(filter_obj, &self->filter_states[j * self->base.channel_count + channel], word); + } + } + return word; +} + audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *self, bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { @@ -289,6 +359,11 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * recalculate_delay(self, f_delay_ms); } + // Tick biquad filters + for (uint8_t j = 0; j < self->filter_objs_len; j++) { + common_hal_synthio_biquad_tick(self->filter_objs[j]); + } + uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint16_t); uint32_t max_echo_buf_len = (self->max_echo_buffer_len >> (self->base.channel_count - 1)) / sizeof(uint16_t); @@ -324,12 +399,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int16_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = word; + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)process_biquad_filters(self, !!echo_buffer_offset, word); } } else { echo = echo_buffer[echo_buffer_pos + echo_buffer_offset]; word = (int16_t)(echo * decay); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)process_biquad_filters(self, !!echo_buffer_offset, word); } word = (int16_t)(echo * MIN(mix, MICROPY_FLOAT_CONST(1.0))); @@ -409,11 +484,11 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)word; + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)process_biquad_filters(self, !!echo_buffer_offset, word); } } else { word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)process_biquad_filters(self, !!echo_buffer_offset, word); } } else { if (self->freq_shift) { @@ -421,12 +496,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)word; + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)process_biquad_filters(self, !!echo_buffer_offset, word); } } else { // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)word; + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)process_biquad_filters(self, !!echo_buffer_offset, word); } } diff --git a/shared-module/audiodelays/Echo.h b/shared-module/audiodelays/Echo.h index cc37f7030be..94c9ee4d2de 100644 --- a/shared-module/audiodelays/Echo.h +++ b/shared-module/audiodelays/Echo.h @@ -10,6 +10,7 @@ #include "shared-module/audiocore/__init__.h" #include "shared-module/synthio/__init__.h" #include "shared-module/synthio/block.h" +#include "shared-module/synthio/Biquad.h" extern const mp_obj_type_t audiodelays_echo_type; @@ -20,8 +21,13 @@ typedef struct { mp_float_t current_delay_ms; mp_float_t sample_ms; synthio_block_slot_t decay; + mp_obj_t filter; synthio_block_slot_t mix; + mp_obj_t *filter_objs; + size_t filter_objs_len; + biquad_filter_state *filter_states; + int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes diff --git a/shared-module/synthio/Biquad.c b/shared-module/synthio/Biquad.c index 08aab81a7bf..edefd071403 100644 --- a/shared-module/synthio/Biquad.c +++ b/shared-module/synthio/Biquad.c @@ -197,6 +197,10 @@ void synthio_biquad_filter_reset(biquad_filter_state *st) { memset(&st->x, 0, 4 * sizeof(int16_t)); } +static inline int32_t biquad_filter_sample(int32_t input, int32_t a1, int32_t a2, int32_t b0, int32_t b1, int32_t b2, int32_t x0, int32_t x1, int32_t y0, int32_t y1) { + return synthio_sat16((b0 * input + b1 * x0 + b2 * x1 - a1 * y0 - a2 * y1 + (1 << (BIQUAD_SHIFT - 1))), BIQUAD_SHIFT); +} + void synthio_biquad_filter_samples(mp_obj_t self_in, biquad_filter_state *st, int32_t *buffer, size_t n_samples) { synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in); @@ -213,7 +217,7 @@ void synthio_biquad_filter_samples(mp_obj_t self_in, biquad_filter_state *st, in for (size_t n = n_samples; n; --n, ++buffer) { int32_t input = *buffer; - int32_t output = synthio_sat16((b0 * input + b1 * x0 + b2 * x1 - a1 * y0 - a2 * y1 + (1 << (BIQUAD_SHIFT - 1))), BIQUAD_SHIFT); + int32_t output = biquad_filter_sample(input, a1, a2, b0, b1, b2, x0, x1, y0, y1); x1 = x0; x0 = input; @@ -226,3 +230,16 @@ void synthio_biquad_filter_samples(mp_obj_t self_in, biquad_filter_state *st, in st->y[0] = y0; st->y[1] = y1; } + +int32_t synthio_biquad_filter_sample(mp_obj_t self_in, biquad_filter_state *st, int32_t input) { + synthio_biquad_t *self = MP_OBJ_TO_PTR(self_in); + + int32_t output = biquad_filter_sample(input, self->a1, self->a2, self->b0, self->b1, self->b2, st->x[0], st->x[1], st->y[0], st->y[1]); + + st->x[1] = st->x[0]; + st->x[0] = input; + st->y[1] = st->y[0]; + st->y[0] = output; + + return output; +} diff --git a/shared-module/synthio/Biquad.h b/shared-module/synthio/Biquad.h index 3b9920ed92f..cc9b4f53b0e 100644 --- a/shared-module/synthio/Biquad.h +++ b/shared-module/synthio/Biquad.h @@ -27,3 +27,4 @@ typedef struct { void common_hal_synthio_biquad_tick(mp_obj_t self_in); void synthio_biquad_filter_reset(biquad_filter_state *st); void synthio_biquad_filter_samples(mp_obj_t self_in, biquad_filter_state *st, int32_t *buffer, size_t n_samples); +int32_t synthio_biquad_filter_sample(mp_obj_t self_in, biquad_filter_state *st, int32_t input); From f10f561cd79848fa456785efef954e375f34ca2b Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 23:17:48 -0500 Subject: [PATCH 765/876] Share filter object functionality --- shared-module/audiodelays/Echo.c | 77 ++++----------------------- shared-module/audiofilters/Filter.c | 57 +++----------------- shared-module/audiofilters/__init__.c | 68 +++++++++++++++++++++++ shared-module/audiofilters/__init__.h | 8 +++ 4 files changed, 92 insertions(+), 118 deletions(-) diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index 243fd365f4a..cdf34541972 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -5,6 +5,7 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/audiodelays/Echo.h" #include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiofilters/__init__.h" #include #include "py/runtime.h" @@ -175,48 +176,7 @@ mp_obj_t common_hal_audiodelays_echo_get_filter(audiodelays_echo_obj_t *self) { } void common_hal_audiodelays_echo_set_filter(audiodelays_echo_obj_t *self, mp_obj_t filter_in) { - size_t n_items; - mp_obj_t *items; - mp_obj_t *filter_objs; - - if (filter_in == mp_const_none) { - n_items = 0; - filter_objs = NULL; - } else if (MP_OBJ_TYPE_HAS_SLOT(mp_obj_get_type(filter_in), iter)) { - // convert object to tuple if it wasn't before - filter_in = MP_OBJ_TYPE_GET_SLOT(&mp_type_tuple, make_new)( - &mp_type_tuple, 1, 0, &filter_in); - mp_obj_tuple_get(filter_in, &n_items, &items); - for (size_t i = 0; i < n_items; i++) { - if (!mp_obj_is_type(items[i], &synthio_biquad_type_obj)) { - mp_raise_TypeError_varg( - MP_ERROR_TEXT("%q in %q must be of type %q, not %q"), - MP_QSTR_object, - MP_QSTR_filter, - MP_QSTR_Biquad, - mp_obj_get_type(items[i])->name); - } - } - filter_objs = items; - } else { - n_items = 1; - if (!mp_obj_is_type(filter_in, &synthio_biquad_type_obj)) { - mp_raise_TypeError_varg( - MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), - MP_QSTR_filter, MP_QSTR_Biquad, MP_QSTR_iterable, mp_obj_get_type(filter_in)->name); - } - filter_objs = &self->filter; - } - - // everything has been checked, so we can do the following without fear - - self->filter = filter_in; - self->filter_objs = filter_objs; - self->filter_states = m_renew(biquad_filter_state, - self->filter_states, - self->filter_objs_len * self->base.channel_count, - n_items * self->base.channel_count); - self->filter_objs_len = n_items; + audiofilters_assign_filters(filter_in, &self->filter, &self->filter_objs, &self->filter_objs_len, &self->filter_states, self->base.channel_count); } mp_obj_t common_hal_audiodelays_echo_get_mix(audiodelays_echo_obj_t *self) { @@ -251,11 +211,7 @@ void audiodelays_echo_reset_buffer(audiodelays_echo_obj_t *self, memset(self->buffer[1], 0, self->buffer_len); memset(self->echo_buffer, 0, self->max_echo_buffer_len); - if (self->filter_states) { - for (uint8_t i = 0; i < self->filter_objs_len * self->base.channel_count; i++) { - synthio_biquad_filter_reset(&self->filter_states[i]); - } - } + audiofilters_reset_filters(self->filter_states, self->filter_objs_len, self->base.channel_count); } bool common_hal_audiodelays_echo_get_playing(audiodelays_echo_obj_t *self) { @@ -286,17 +242,6 @@ void common_hal_audiodelays_echo_stop(audiodelays_echo_obj_t *self) { return; } -static int32_t process_biquad_filters(audiodelays_echo_obj_t *self, uint8_t channel, int32_t word) { - // Process biquad filters - for (uint8_t j = 0; j < self->filter_objs_len; j++) { - mp_obj_t filter_obj = self->filter_objs[j]; - for (uint8_t k = 0; k < self->base.channel_count; k++) { - word = synthio_biquad_filter_sample(filter_obj, &self->filter_states[j * self->base.channel_count + channel], word); - } - } - return word; -} - audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t *self, bool single_channel_output, uint8_t channel, uint8_t **buffer, uint32_t *buffer_length) { @@ -360,9 +305,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * } // Tick biquad filters - for (uint8_t j = 0; j < self->filter_objs_len; j++) { - common_hal_synthio_biquad_tick(self->filter_objs[j]); - } + audiofilters_tick_filters(self->filter_objs, self->filter_objs_len); uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint16_t); uint32_t max_echo_buf_len = (self->max_echo_buffer_len >> (self->base.channel_count - 1)) / sizeof(uint16_t); @@ -399,12 +342,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int16_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)process_biquad_filters(self, !!echo_buffer_offset, word); + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); } } else { echo = echo_buffer[echo_buffer_pos + echo_buffer_offset]; word = (int16_t)(echo * decay); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)process_biquad_filters(self, !!echo_buffer_offset, word); + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); } word = (int16_t)(echo * MIN(mix, MICROPY_FLOAT_CONST(1.0))); @@ -484,11 +427,11 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)process_biquad_filters(self, !!echo_buffer_offset, word); + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); } } else { word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)process_biquad_filters(self, !!echo_buffer_offset, word); + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); } } else { if (self->freq_shift) { @@ -496,12 +439,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)process_biquad_filters(self, !!echo_buffer_offset, word); + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); } } else { // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)process_biquad_filters(self, !!echo_buffer_offset, word); + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); } } diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index 57a763629fa..5ccd7c8a936 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -5,8 +5,9 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/audiofilters/Filter.h" #include "shared-bindings/audiocore/__init__.h" - +#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/Biquad.h" + #include #include "py/runtime.h" @@ -67,48 +68,7 @@ void common_hal_audiofilters_filter_deinit(audiofilters_filter_obj_t *self) { } void common_hal_audiofilters_filter_set_filter(audiofilters_filter_obj_t *self, mp_obj_t filter_in) { - size_t n_items; - mp_obj_t *items; - mp_obj_t *filter_objs; - - if (filter_in == mp_const_none) { - n_items = 0; - filter_objs = NULL; - } else if (MP_OBJ_TYPE_HAS_SLOT(mp_obj_get_type(filter_in), iter)) { - // convert object to tuple if it wasn't before - filter_in = MP_OBJ_TYPE_GET_SLOT(&mp_type_tuple, make_new)( - &mp_type_tuple, 1, 0, &filter_in); - mp_obj_tuple_get(filter_in, &n_items, &items); - for (size_t i = 0; i < n_items; i++) { - if (!mp_obj_is_type(items[i], &synthio_biquad_type_obj)) { - mp_raise_TypeError_varg( - MP_ERROR_TEXT("%q in %q must be of type %q, not %q"), - MP_QSTR_object, - MP_QSTR_filter, - MP_QSTR_Biquad, - mp_obj_get_type(items[i])->name); - } - } - filter_objs = items; - } else { - n_items = 1; - if (!mp_obj_is_type(filter_in, &synthio_biquad_type_obj)) { - mp_raise_TypeError_varg( - MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), - MP_QSTR_filter, MP_QSTR_Biquad, MP_QSTR_iterable, mp_obj_get_type(filter_in)->name); - } - filter_objs = &self->filter; - } - - // everything has been checked, so we can do the following without fear - - self->filter = filter_in; - self->filter_objs = filter_objs; - self->filter_states = m_renew(biquad_filter_state, - self->filter_states, - self->filter_objs_len * self->base.channel_count, - n_items * self->base.channel_count); - self->filter_objs_len = n_items; + audiofilters_assign_filters(filter_in, &self->filter, &self->filter_objs, &self->filter_objs_len, &self->filter_states, self->base.channel_count); } mp_obj_t common_hal_audiofilters_filter_get_filter(audiofilters_filter_obj_t *self) { @@ -131,11 +91,7 @@ void audiofilters_filter_reset_buffer(audiofilters_filter_obj_t *self, memset(self->buffer[1], 0, self->buffer_len); memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * self->base.channel_count * sizeof(int32_t)); - if (self->filter_states) { - for (uint8_t i = 0; i < self->filter_objs_len * self->base.channel_count; i++) { - synthio_biquad_filter_reset(&self->filter_states[i]); - } - } + audiofilters_reset_filters(self->filter_states, self->filter_objs_len, self->base.channel_count); } bool common_hal_audiofilters_filter_get_playing(audiofilters_filter_obj_t *self) { @@ -213,9 +169,8 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o (void)synthio_block_slot_get(&self->mix); // Tick biquad filters - for (uint8_t j = 0; j < self->filter_objs_len; j++) { - common_hal_synthio_biquad_tick(self->filter_objs[j]); - } + audiofilters_tick_filters(self->filter_objs, self->filter_objs_len); + if (self->base.samples_signed) { memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); } else { diff --git a/shared-module/audiofilters/__init__.c b/shared-module/audiofilters/__init__.c index 83929b4c4fb..6435ec36e36 100644 --- a/shared-module/audiofilters/__init__.c +++ b/shared-module/audiofilters/__init__.c @@ -3,3 +3,71 @@ // SPDX-FileCopyrightText: Copyright (c) 2024 Cooper Dalrymple // // SPDX-License-Identifier: MIT + +#include "shared-module/audiofilters/__init__.h" + +void audiofilters_assign_filters(mp_obj_t filter_in, mp_obj_t *filter_out, mp_obj_t **filter_objs, size_t *filter_objs_len, biquad_filter_state **filter_states, uint8_t channel_count) { + size_t n_items; + mp_obj_t *items; + + if (filter_in == mp_const_none) { + n_items = 0; + *filter_objs = NULL; + } else if (MP_OBJ_TYPE_HAS_SLOT(mp_obj_get_type(filter_in), iter)) { + // convert object to tuple if it wasn't before + filter_in = MP_OBJ_TYPE_GET_SLOT(&mp_type_tuple, make_new)( + &mp_type_tuple, 1, 0, &filter_in); + mp_obj_tuple_get(filter_in, &n_items, &items); + for (size_t i = 0; i < n_items; i++) { + if (!mp_obj_is_type(items[i], &synthio_biquad_type_obj)) { + mp_raise_TypeError_varg( + MP_ERROR_TEXT("%q in %q must be of type %q, not %q"), + MP_QSTR_object, + MP_QSTR_filter, + MP_QSTR_Biquad, + mp_obj_get_type(items[i])->name); + } + } + *filter_objs = items; + } else { + n_items = 1; + if (!mp_obj_is_type(filter_in, &synthio_biquad_type_obj)) { + mp_raise_TypeError_varg( + MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_filter, MP_QSTR_Biquad, MP_QSTR_iterable, mp_obj_get_type(filter_in)->name); + } + *filter_objs = filter_out; + } + + // everything has been checked, so we can do the following without fear + + *filter_out = filter_in; + *filter_states = m_renew(biquad_filter_state, + *filter_states, + *filter_objs_len * channel_count, + n_items * channel_count); + *filter_objs_len = n_items; +} + +void audiofilters_reset_filters(biquad_filter_state *filter_states, size_t filter_objs_len, uint8_t channel_count) { + if (filter_states) { + for (uint8_t i = 0; i < filter_objs_len * channel_count; i++) { + synthio_biquad_filter_reset(&filter_states[i]); + } + } +} + +void audiofilters_tick_filters(mp_obj_t *filter_objs, size_t filter_objs_len) { + for (uint8_t j = 0; j < filter_objs_len; j++) { + common_hal_synthio_biquad_tick(filter_objs[j]); + } +} + +int32_t audiofilters_process_filters(mp_obj_t *filter_objs, size_t filter_objs_len, biquad_filter_state *filter_states, uint8_t channel_count, uint8_t channel, int32_t word) { + // Process biquad filters + for (uint8_t j = 0; j < filter_objs_len; j++) { + mp_obj_t filter_obj = filter_objs[j]; + word = synthio_biquad_filter_sample(filter_obj, &filter_states[j * channel_count + channel], word); + } + return word; +} diff --git a/shared-module/audiofilters/__init__.h b/shared-module/audiofilters/__init__.h index 29d2f672655..067d04ef209 100644 --- a/shared-module/audiofilters/__init__.h +++ b/shared-module/audiofilters/__init__.h @@ -5,3 +5,11 @@ // SPDX-License-Identifier: MIT #pragma once + +#include "py/obj.h" +#include "shared-module/synthio/Biquad.h" + +void audiofilters_assign_filters(mp_obj_t filter_in, mp_obj_t *filter_out, mp_obj_t **filter_objs, size_t *filter_objs_len, biquad_filter_state **filter_states, uint8_t channel_count); +void audiofilters_reset_filters(biquad_filter_state *filter_states, size_t filter_objs_len, uint8_t channel_count); +void audiofilters_tick_filters(mp_obj_t *filter_objs, size_t filter_objs_len); +int32_t audiofilters_process_filters(mp_obj_t *filter_objs, size_t filter_objs_len, biquad_filter_state *filter_states, uint8_t channel_count, uint8_t channel, int32_t word); From 4eab9125c39c44cfb8b81a28a30f5aee3965fc19 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Thu, 13 Aug 2026 23:18:01 -0500 Subject: [PATCH 766/876] Add pre and post filters to Freeverb --- shared-bindings/audiofreeverb/Freeverb.c | 57 +++++++++++++++++++++++- shared-bindings/audiofreeverb/Freeverb.h | 8 +++- shared-module/audiofreeverb/Freeverb.c | 41 ++++++++++++++++- shared-module/audiofreeverb/Freeverb.h | 11 +++++ 4 files changed, 112 insertions(+), 5 deletions(-) diff --git a/shared-bindings/audiofreeverb/Freeverb.c b/shared-bindings/audiofreeverb/Freeverb.c index 12eb7ef70ab..83c9eb7c01f 100644 --- a/shared-bindings/audiofreeverb/Freeverb.c +++ b/shared-bindings/audiofreeverb/Freeverb.c @@ -24,6 +24,8 @@ //| self, //| roomsize: synthio.BlockInput = 0.5, //| damp: synthio.BlockInput = 0.5, +//| pre_filter: Optional[synthio.Biquad | Tuple[synthio.Biquad]] = None, +//| post_filter: Optional[synthio.Biquad | Tuple[synthio.Biquad]] = None, //| mix: synthio.BlockInput = 0.5, //| buffer_size: int = 512, //| sample_rate: int = 8000, @@ -40,6 +42,8 @@ //| //| :param synthio.BlockInput roomsize: The size of the room. 0.0 = smallest; 1.0 = largest. //| :param synthio.BlockInput damp: How much the walls absorb. 0.0 = least; 1.0 = most. +//| :param Optional[synthio.Biquad|Tuple[synthio.Biquad]] pre_filter: A normalized biquad filter object or tuple of normalized biquad filter objects. The sample is processed sequentially by each "Pre-EQ" filter before being fed to the reverb effect. +//| :param Optional[synthio.Biquad|Tuple[synthio.Biquad]] post_filter: A normalized biquad filter object or tuple of normalized biquad filter objects. The output of the reverb effect is processed sequentially by each "Post-EQ" filter before being mixed with the original sample. //| :param synthio.BlockInput mix: The mix as a ratio of the sample (0.0) to the effect (1.0). //| :param int buffer_size: The total size in bytes of each of the two playback buffers to use //| :param int sample_rate: The sample rate to be used @@ -70,10 +74,12 @@ //| ... //| static mp_obj_t audiofreeverb_freeverb_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_roomsize, ARG_damp, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; + enum { ARG_roomsize, ARG_damp, ARG_pre_filter, ARG_post_filter, ARG_mix, ARG_buffer_size, ARG_sample_rate, ARG_bits_per_sample, ARG_samples_signed, ARG_channel_count, }; static const mp_arg_t allowed_args[] = { { MP_QSTR_roomsize, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_damp, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_pre_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } }, + { MP_QSTR_post_filter, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_ROM_NONE } }, { MP_QSTR_mix, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, { MP_QSTR_buffer_size, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 512} }, { MP_QSTR_sample_rate, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 8000} }, @@ -96,7 +102,7 @@ static mp_obj_t audiofreeverb_freeverb_make_new(const mp_obj_type_t *type, size_ } audiofreeverb_freeverb_obj_t *self = mp_obj_malloc(audiofreeverb_freeverb_obj_t, &audiofreeverb_freeverb_type); - common_hal_audiofreeverb_freeverb_construct(self, args[ARG_roomsize].u_obj, args[ARG_damp].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); + common_hal_audiofreeverb_freeverb_construct(self, args[ARG_roomsize].u_obj, args[ARG_damp].u_obj, args[ARG_pre_filter].u_obj, args[ARG_post_filter].u_obj, args[ARG_mix].u_obj, args[ARG_buffer_size].u_int, bits_per_sample, args[ARG_samples_signed].u_bool, channel_count, sample_rate); return MP_OBJ_FROM_PTR(self); } @@ -165,6 +171,51 @@ MP_PROPERTY_GETSET(audiofreeverb_freeverb_damp_obj, (mp_obj_t)&audiofreeverb_freeverb_get_damp_obj, (mp_obj_t)&audiofreeverb_freeverb_set_damp_obj); + +//| pre_filter: synthio.Biquad | Tuple[synthio.Biquad] | None +//| """A normalized biquad filter object or tuple of normalized biquad filter objects. The sample is processed sequentially by each "Pre-EQ" filter before being fed to the reverb effect.""" +//| +static mp_obj_t audiofreeverb_freeverb_obj_get_pre_filter(mp_obj_t self_in) { + audiofreeverb_freeverb_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_audiofreeverb_freeverb_get_pre_filter(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofreeverb_freeverb_get_pre_filter_obj, audiofreeverb_freeverb_obj_get_pre_filter); + +static mp_obj_t audiofreeverb_freeverb_obj_set_pre_filter(mp_obj_t self_in, mp_obj_t filter_in) { + audiofreeverb_freeverb_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofreeverb_freeverb_set_pre_filter(self, filter_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiofreeverb_freeverb_set_pre_filter_obj, audiofreeverb_freeverb_obj_set_pre_filter); + +MP_PROPERTY_GETSET(audiofreeverb_freeverb_pre_filter_obj, + (mp_obj_t)&audiofreeverb_freeverb_get_pre_filter_obj, + (mp_obj_t)&audiofreeverb_freeverb_set_pre_filter_obj); + + +//| post_filter: synthio.Biquad | Tuple[synthio.Biquad] | None +//| """A normalized biquad filter object or tuple of normalized biquad filter objects. The output of the reverb effect is processed sequentially by each "Post-EQ" filter before being mixed with the original sample.""" +//| +static mp_obj_t audiofreeverb_freeverb_obj_get_post_filter(mp_obj_t self_in) { + audiofreeverb_freeverb_obj_t *self = MP_OBJ_TO_PTR(self_in); + check_for_deinit(self); + return common_hal_audiofreeverb_freeverb_get_post_filter(self); +} +MP_DEFINE_CONST_FUN_OBJ_1(audiofreeverb_freeverb_get_post_filter_obj, audiofreeverb_freeverb_obj_get_post_filter); + +static mp_obj_t audiofreeverb_freeverb_obj_set_post_filter(mp_obj_t self_in, mp_obj_t filter_in) { + audiofreeverb_freeverb_obj_t *self = MP_OBJ_TO_PTR(self_in); + common_hal_audiofreeverb_freeverb_set_post_filter(self, filter_in); + return mp_const_none; +} +MP_DEFINE_CONST_FUN_OBJ_2(audiofreeverb_freeverb_set_post_filter_obj, audiofreeverb_freeverb_obj_set_post_filter); + +MP_PROPERTY_GETSET(audiofreeverb_freeverb_post_filter_obj, + (mp_obj_t)&audiofreeverb_freeverb_get_post_filter_obj, + (mp_obj_t)&audiofreeverb_freeverb_set_post_filter_obj); + + //| mix: synthio.BlockInput //| """The rate the reverb mix between 0 and 1 where 0 is only sample and 1 is all effect.""" static mp_obj_t audiofreeverb_freeverb_obj_get_mix(mp_obj_t self_in) { @@ -251,6 +302,8 @@ static const mp_rom_map_elem_t audiofreeverb_freeverb_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audiofreeverb_freeverb_playing_obj) }, { MP_ROM_QSTR(MP_QSTR_roomsize), MP_ROM_PTR(&audiofreeverb_freeverb_roomsize_obj) }, { MP_ROM_QSTR(MP_QSTR_damp), MP_ROM_PTR(&audiofreeverb_freeverb_damp_obj) }, + { MP_ROM_QSTR(MP_QSTR_pre_filter), MP_ROM_PTR(&audiofreeverb_freeverb_pre_filter_obj) }, + { MP_ROM_QSTR(MP_QSTR_post_filter), MP_ROM_PTR(&audiofreeverb_freeverb_post_filter_obj) }, { MP_ROM_QSTR(MP_QSTR_mix), MP_ROM_PTR(&audiofreeverb_freeverb_mix_obj) }, AUDIOSAMPLE_FIELDS, }; diff --git a/shared-bindings/audiofreeverb/Freeverb.h b/shared-bindings/audiofreeverb/Freeverb.h index bde6cfffda7..7eed9775006 100644 --- a/shared-bindings/audiofreeverb/Freeverb.h +++ b/shared-bindings/audiofreeverb/Freeverb.h @@ -11,7 +11,7 @@ extern const mp_obj_type_t audiofreeverb_freeverb_type; void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *self, - mp_obj_t roomsize, mp_obj_t damp, mp_obj_t mix, + mp_obj_t roomsize, mp_obj_t damp, mp_obj_t pre_filter, mp_obj_t post_filter, mp_obj_t mix, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate); @@ -24,6 +24,12 @@ void common_hal_audiofreeverb_freeverb_set_roomsize(audiofreeverb_freeverb_obj_t mp_obj_t common_hal_audiofreeverb_freeverb_get_damp(audiofreeverb_freeverb_obj_t *self); void common_hal_audiofreeverb_freeverb_set_damp(audiofreeverb_freeverb_obj_t *self, mp_obj_t damp); +mp_obj_t common_hal_audiofreeverb_freeverb_get_pre_filter(audiofreeverb_freeverb_obj_t *self); +void common_hal_audiofreeverb_freeverb_set_pre_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t arg); + +mp_obj_t common_hal_audiofreeverb_freeverb_get_post_filter(audiofreeverb_freeverb_obj_t *self); +void common_hal_audiofreeverb_freeverb_set_post_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t arg); + mp_obj_t common_hal_audiofreeverb_freeverb_get_mix(audiofreeverb_freeverb_obj_t *self); void common_hal_audiofreeverb_freeverb_set_mix(audiofreeverb_freeverb_obj_t *self, mp_obj_t mix); diff --git a/shared-module/audiofreeverb/Freeverb.c b/shared-module/audiofreeverb/Freeverb.c index d0f1aeaa546..4bea25e9807 100644 --- a/shared-module/audiofreeverb/Freeverb.c +++ b/shared-module/audiofreeverb/Freeverb.c @@ -9,13 +9,14 @@ // #include "shared-bindings/audiofreeverb/Freeverb.h" #include "shared-bindings/audiocore/__init__.h" +#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/__init__.h" #include #include "py/runtime.h" #include -void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *self, mp_obj_t roomsize, mp_obj_t damp, mp_obj_t mix, +void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *self, mp_obj_t roomsize, mp_obj_t damp, mp_obj_t pre_filter, mp_obj_t post_filter, mp_obj_t mix, uint32_t buffer_size, uint8_t bits_per_sample, bool samples_signed, uint8_t channel_count, uint32_t sample_rate) { @@ -59,6 +60,9 @@ void common_hal_audiofreeverb_freeverb_construct(audiofreeverb_freeverb_obj_t *s self->more_data = false; // Is there still more data to read from the sample or did we finish // The below section sets up the reverb effect's starting values. For a different effect this section will change + common_hal_audiofreeverb_freeverb_set_pre_filter(self, pre_filter); + common_hal_audiofreeverb_freeverb_set_post_filter(self, post_filter); + if (roomsize == MP_OBJ_NULL) { roomsize = mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)); } @@ -128,6 +132,10 @@ void common_hal_audiofreeverb_freeverb_deinit(audiofreeverb_freeverb_obj_t *self audiosample_mark_deinit(&self->base); self->buffer[0] = NULL; self->buffer[1] = NULL; + self->pre_filter = mp_const_none; + self->pre_filter_states = NULL; + self->post_filter = mp_const_none; + self->post_filter_states = NULL; } mp_obj_t common_hal_audiofreeverb_freeverb_get_roomsize(audiofreeverb_freeverb_obj_t *self) { @@ -167,6 +175,22 @@ void audiofreeverb_freeverb_get_damp_fixedpoint(mp_float_t n, int16_t *damp1, in *damp2 = (int16_t)(32768 - *damp1); // inverse of x1 damp2 = 1.0 - damp1 } +mp_obj_t common_hal_audiofreeverb_freeverb_get_pre_filter(audiofreeverb_freeverb_obj_t *self) { + return self->pre_filter; +} + +void common_hal_audiofreeverb_freeverb_set_pre_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t filter_in) { + audiofilters_assign_filters(filter_in, &self->pre_filter, &self->pre_filter_objs, &self->pre_filter_objs_len, &self->pre_filter_states, self->base.channel_count); +} + +mp_obj_t common_hal_audiofreeverb_freeverb_get_post_filter(audiofreeverb_freeverb_obj_t *self) { + return self->post_filter; +} + +void common_hal_audiofreeverb_freeverb_set_post_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t filter_in) { + audiofilters_assign_filters(filter_in, &self->post_filter, &self->post_filter_objs, &self->post_filter_objs_len, &self->post_filter_states, self->base.channel_count); +} + mp_obj_t common_hal_audiofreeverb_freeverb_get_mix(audiofreeverb_freeverb_obj_t *self) { return self->mix.obj; } @@ -187,6 +211,9 @@ void audiofreeverb_freeverb_reset_buffer(audiofreeverb_freeverb_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); + + audiofilters_reset_filters(self->pre_filter_states, self->pre_filter_objs_len, self->base.channel_count); + audiofilters_reset_filters(self->post_filter_states, self->post_filter_objs_len, self->base.channel_count); } bool common_hal_audiofreeverb_freeverb_get_playing(audiofreeverb_freeverb_obj_t *self) { @@ -274,6 +301,10 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free mp_float_t roomsize = synthio_block_slot_get_limited(&self->roomsize, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); int16_t feedback = audiofreeverb_freeverb_get_roomsize_fixedpoint(roomsize); + // Tick biquad filters + audiofilters_tick_filters(self->pre_filter_objs, self->pre_filter_objs_len); + audiofilters_tick_filters(self->post_filter_objs, self->post_filter_objs_len); + int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; for (uint32_t i = 0; i < n; i++) { @@ -286,7 +317,10 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free int16_t input, bufout, output; uint32_t channel_comb_offset = 0, channel_allpass_offset = 0; - input = synthio_sat16(sample_word * 8738, 17); // Initial input scaled down so we can add reverb + // Apply filters as Pre-EQ + input = (int16_t)audiofilters_process_filters(self->pre_filter_objs, self->pre_filter_objs_len, self->pre_filter_states, self->base.channel_count, n % self->base.channel_count, sample_word); + + input = synthio_sat16((int32_t)input * 8738, 17); // Initial input scaled down so we can add reverb sum = 0; // Calculate each of the 8 comb buffers @@ -312,6 +346,9 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free } } + // Apply filters as Post-EQ + output = (int16_t)audiofilters_process_filters(self->post_filter_objs, self->post_filter_objs_len, self->post_filter_states, self->base.channel_count, n % self->base.channel_count, (int32_t)output); + word = output * 30; // Add some volume back don't have to saturate as next step will word = synthio_sat16(sample_word * mix_sample, 15) + synthio_sat16(word * mix_effect, 15); diff --git a/shared-module/audiofreeverb/Freeverb.h b/shared-module/audiofreeverb/Freeverb.h index 44747f0fc95..79a11e3490e 100644 --- a/shared-module/audiofreeverb/Freeverb.h +++ b/shared-module/audiofreeverb/Freeverb.h @@ -10,6 +10,7 @@ #include "shared-module/audiocore/__init__.h" #include "shared-module/synthio/__init__.h" #include "shared-module/synthio/block.h" +#include "shared-module/synthio/Biquad.h" extern const mp_obj_type_t audiofreeverb_freeverb_type; @@ -17,8 +18,18 @@ typedef struct { audiosample_base_t base; synthio_block_slot_t roomsize; synthio_block_slot_t damp; + mp_obj_t pre_filter; + mp_obj_t post_filter; synthio_block_slot_t mix; + mp_obj_t *pre_filter_objs; + size_t pre_filter_objs_len; + biquad_filter_state *pre_filter_states; + + mp_obj_t *post_filter_objs; + size_t post_filter_objs_len; + biquad_filter_state *post_filter_states; + int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes From e9c6fb8a0aa1634a4e4f22d9b39812349afde74d Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Fri, 14 Aug 2026 05:34:18 +0000 Subject: [PATCH 767/876] displayio: share the dirty-rectangle merge across display types Move the overlap merge from busdisplay into shared code: displayio_area_array_merge_overlapping() in area.c does the greedy fuse, displayio_display_core_merge_refresh_areas() clips and collects the list (raw-list fallback past DISPLAYIO_MAX_MERGE_AREAS), and busdisplay, framebufferio and epaperdisplay all use it. --- shared-module/busdisplay/BusDisplay.c | 60 +++---------------- shared-module/displayio/area.c | 25 ++++++++ shared-module/displayio/area.h | 2 + shared-module/displayio/display_core.c | 27 +++++++++ shared-module/displayio/display_core.h | 5 ++ shared-module/epaperdisplay/EPaperDisplay.c | 17 +++++- .../framebufferio/FramebufferDisplay.c | 17 +++++- 7 files changed, 96 insertions(+), 57 deletions(-) diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index 23ce331753a..db730e6fd9f 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -34,10 +34,6 @@ #define DELAY 0x80 -// Max dirty rectangles held while merging overlapping ones before a refresh. More than this (rare) -// falls back to refreshing the raw list unmerged. -#define MAX_MERGE_AREAS 16 - void common_hal_busdisplay_busdisplay_construct(busdisplay_busdisplay_obj_t *self, mp_obj_t bus, uint16_t width, uint16_t height, int16_t colstart, int16_t rowstart, uint16_t rotation, uint16_t color_depth, bool grayscale, bool pixels_in_byte_share_row, @@ -332,58 +328,20 @@ static void _refresh_display(busdisplay_busdisplay_obj_t *self) { const displayio_area_t *current_area = _get_refresh_areas(self); - // Merge overlapping dirty rectangles so shared pixels are computed and sent once. displayio does - // not merge them, so overlapping/nested areas get their common pixels recomputed and retransmitted - // per rectangle (and drawn as separate, visibly sequential passes). A changing text label is the - // common case: it dirties the whole label area AND each glyph, so the glyph rectangles sit inside - // the label rectangle and nearly double the work. Copy the clipped areas into a scratch array and - // greedily fuse any pair whose bounding-box area is smaller than the two areas summed - i.e. they - // overlap enough that one rectangle sends fewer pixels than two. Distant / non-overlapping - // rectangles are left separate (their bounding box would be larger). The result is never more - // pixels than the unmerged list. If there are more areas than the scratch holds, fall back to - // refreshing the raw list unmerged. - displayio_area_t merged[MAX_MERGE_AREAS]; - size_t count = 0; - bool overflow = false; - for (const displayio_area_t *a = current_area; a != NULL; a = a->next) { - displayio_area_t clipped; - if (!displayio_display_core_clip_area(&self->core, a, &clipped)) { - continue; - } - if (count >= MAX_MERGE_AREAS) { - overflow = true; - break; + // Merge overlapping dirty rectangles so shared pixels are computed and sent once + // (see displayio_display_core_merge_refresh_areas). + displayio_area_t merged[DISPLAYIO_MAX_MERGE_AREAS]; + size_t merged_count; + if (displayio_display_core_merge_refresh_areas(&self->core, current_area, merged, + DISPLAYIO_MAX_MERGE_AREAS, &merged_count)) { + for (size_t i = 0; i < merged_count; i++) { + _refresh_area(self, &merged[i]); } - merged[count] = clipped; - count++; - } - if (overflow) { + } else { while (current_area != NULL) { _refresh_area(self, current_area); current_area = current_area->next; } - displayio_display_core_finish_refresh(&self->core); - return; - } - bool changed = true; - while (changed) { - changed = false; - for (size_t i = 0; i < count && !changed; i++) { - for (size_t j = i + 1; j < count; j++) { - displayio_area_t u; - displayio_area_union(&merged[i], &merged[j], &u); - if (displayio_area_size(&u) < displayio_area_size(&merged[i]) + displayio_area_size(&merged[j])) { - merged[i] = u; // fuse j into i - merged[j] = merged[count - 1]; // swap-remove j - count--; - changed = true; - break; - } - } - } - } - for (size_t i = 0; i < count; i++) { - _refresh_area(self, &merged[i]); } displayio_display_core_finish_refresh(&self->core); } diff --git a/shared-module/displayio/area.c b/shared-module/displayio/area.c index 6a79e2aeeea..fb2e1e5712c 100644 --- a/shared-module/displayio/area.c +++ b/shared-module/displayio/area.c @@ -104,6 +104,31 @@ uint32_t displayio_area_size(const displayio_area_t *area) { return displayio_area_width(area) * displayio_area_height(area); } +// Greedily fuse any pair of areas whose bounding box is smaller than the two areas summed - +// i.e. they overlap enough that one rectangle covers fewer pixels than two. Distant and +// merely touching rectangles are left separate (their bounding box would not be smaller), so +// the result never covers more pixels than the input. Runs in place; returns the new count. +size_t displayio_area_array_merge_overlapping(displayio_area_t *areas, size_t count) { + bool changed = true; + while (changed) { + changed = false; + for (size_t i = 0; i < count && !changed; i++) { + for (size_t j = i + 1; j < count; j++) { + displayio_area_t u; + displayio_area_union(&areas[i], &areas[j], &u); + if (displayio_area_size(&u) < displayio_area_size(&areas[i]) + displayio_area_size(&areas[j])) { + areas[i] = u; // fuse j into i + areas[j] = areas[count - 1]; // swap-remove j + count--; + changed = true; + break; + } + } + } + } + return count; +} + bool displayio_area_equal(const displayio_area_t *a, const displayio_area_t *b) { return a->x1 == b->x1 && a->y1 == b->y1 && diff --git a/shared-module/displayio/area.h b/shared-module/displayio/area.h index eed54613a5a..93e427035ad 100644 --- a/shared-module/displayio/area.h +++ b/shared-module/displayio/area.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include @@ -50,6 +51,7 @@ bool displayio_area_compute_overlap(const displayio_area_t *a, uint16_t displayio_area_width(const displayio_area_t *area); uint16_t displayio_area_height(const displayio_area_t *area); uint32_t displayio_area_size(const displayio_area_t *area); +size_t displayio_area_array_merge_overlapping(displayio_area_t *areas, size_t count); bool displayio_area_equal(const displayio_area_t *a, const displayio_area_t *b); void displayio_area_transform_within(bool mirror_x, bool mirror_y, bool transpose_xy, const displayio_area_t *original, diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index dfcddde7796..70cdb0b3607 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -203,3 +203,30 @@ bool displayio_display_core_clip_area(displayio_display_core_t *self, const disp } return true; } + +// Clip the collected refresh areas and merge the overlapping ones so shared pixels are +// computed and sent once. displayio does not merge areas as it collects them, so +// overlapping/nested ones get their common pixels reprocessed per rectangle (and drawn as +// separate, visibly sequential passes). A changing text label is the common case: it +// dirties the whole label area AND each glyph, so the glyph rectangles sit inside the +// label rectangle and nearly double the work. Only pairs whose bounding box is smaller +// than the two areas summed are fused, so the result never covers more pixels than the +// unmerged list. Returns false when there are more areas than `max_areas` (rare) - the +// caller should then refresh the raw list unmerged. +bool displayio_display_core_merge_refresh_areas(displayio_display_core_t *self, + const displayio_area_t *areas, displayio_area_t *merged, size_t max_areas, size_t *count_out) { + size_t count = 0; + for (const displayio_area_t *a = areas; a != NULL; a = a->next) { + displayio_area_t clipped; + if (!displayio_display_core_clip_area(self, a, &clipped)) { + continue; + } + if (count >= max_areas) { + return false; + } + merged[count] = clipped; + count++; + } + *count_out = displayio_area_array_merge_overlapping(merged, count); + return true; +} diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index f3fe2023636..fd93c617657 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -51,3 +51,8 @@ void displayio_display_core_collect_ptrs(displayio_display_core_t *self); bool displayio_display_core_fill_area(displayio_display_core_t *self, displayio_area_t *area, uint32_t *mask, uint32_t *buffer); bool displayio_display_core_clip_area(displayio_display_core_t *self, const displayio_area_t *area, displayio_area_t *clipped); + +// Scratch size for displayio_display_core_merge_refresh_areas(). +#define DISPLAYIO_MAX_MERGE_AREAS 16 +bool displayio_display_core_merge_refresh_areas(displayio_display_core_t *self, + const displayio_area_t *areas, displayio_area_t *merged, size_t max_areas, size_t *count_out); diff --git a/shared-module/epaperdisplay/EPaperDisplay.c b/shared-module/epaperdisplay/EPaperDisplay.c index d34be9d5c7c..327df929c19 100644 --- a/shared-module/epaperdisplay/EPaperDisplay.c +++ b/shared-module/epaperdisplay/EPaperDisplay.c @@ -458,9 +458,20 @@ bool common_hal_epaperdisplay_epaperdisplay_refresh(epaperdisplay_epaperdisplay_ } epaperdisplay_epaperdisplay_start_refresh(self); - while (current_area != NULL) { - epaperdisplay_epaperdisplay_refresh_area(self, current_area); - current_area = current_area->next; + // Merge overlapping dirty rectangles so shared pixels are only written once + // (see displayio_display_core_merge_refresh_areas). + displayio_area_t merged[DISPLAYIO_MAX_MERGE_AREAS]; + size_t merged_count; + if (displayio_display_core_merge_refresh_areas(&self->core, current_area, merged, + DISPLAYIO_MAX_MERGE_AREAS, &merged_count)) { + for (size_t i = 0; i < merged_count; i++) { + epaperdisplay_epaperdisplay_refresh_area(self, &merged[i]); + } + } else { + while (current_area != NULL) { + epaperdisplay_epaperdisplay_refresh_area(self, current_area); + current_area = current_area->next; + } } epaperdisplay_epaperdisplay_finish_refresh(self); return true; diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 8116f4b0347..691fb310730 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -228,9 +228,20 @@ static void _refresh_display(framebufferio_framebufferdisplay_obj_t *self) { uint8_t dirty_row_bitmask[(row_count + 7) / 8]; memset(dirty_row_bitmask, 0, sizeof(dirty_row_bitmask)); self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); - while (current_area != NULL) { - _refresh_area(self, current_area, dirty_row_bitmask); - current_area = current_area->next; + // Merge overlapping dirty rectangles so shared pixels are only rendered once + // (see displayio_display_core_merge_refresh_areas). + displayio_area_t merged[DISPLAYIO_MAX_MERGE_AREAS]; + size_t merged_count; + if (displayio_display_core_merge_refresh_areas(&self->core, current_area, merged, + DISPLAYIO_MAX_MERGE_AREAS, &merged_count)) { + for (size_t i = 0; i < merged_count; i++) { + _refresh_area(self, &merged[i], dirty_row_bitmask); + } + } else { + while (current_area != NULL) { + _refresh_area(self, current_area, dirty_row_bitmask); + current_area = current_area->next; + } } self->framebuffer_protocol->swapbuffers(self->framebuffer, dirty_row_bitmask); } From 31158c0837417e15bf6567452cef2f7558e44554 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Fri, 14 Aug 2026 09:40:51 -0500 Subject: [PATCH 768/876] Removing trailing whitespace --- shared-module/audiofilters/Filter.c | 2 +- shared-module/audiofreeverb/Freeverb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index 5ccd7c8a936..b98aa0aa887 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -170,7 +170,7 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o // Tick biquad filters audiofilters_tick_filters(self->filter_objs, self->filter_objs_len); - + if (self->base.samples_signed) { memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); } else { diff --git a/shared-module/audiofreeverb/Freeverb.c b/shared-module/audiofreeverb/Freeverb.c index 4bea25e9807..3d41eb0ab3f 100644 --- a/shared-module/audiofreeverb/Freeverb.c +++ b/shared-module/audiofreeverb/Freeverb.c @@ -319,7 +319,7 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free // Apply filters as Pre-EQ input = (int16_t)audiofilters_process_filters(self->pre_filter_objs, self->pre_filter_objs_len, self->pre_filter_states, self->base.channel_count, n % self->base.channel_count, sample_word); - + input = synthio_sat16((int32_t)input * 8738, 17); // Initial input scaled down so we can add reverb sum = 0; From faa9d777d0443ad158efef14bf35cf6d52f64fa9 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 13 Aug 2026 11:32:41 -0700 Subject: [PATCH 769/876] usb_audio: only default it on where its dependencies are on The port-level default for esp32s3 now checks the settings usb_audio needs, so a board that turns off the TinyUSB device stack or audiocore keeps it off. Six S3 boards use a CH340C or CP2102 serial chip and set CIRCUITPY_USB_DEVICE = 0, and adafruit_esp32s3_camera sets CIRCUITPY_AUDIOBUSIO = 0, which leaves CIRCUITPY_AUDIOCORE at 0 since the S3 has no AUDIOIO or AUDIOPWMIO. --- ports/espressif/mpconfigport.mk | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ports/espressif/mpconfigport.mk b/ports/espressif/mpconfigport.mk index 497dea28cfb..98fe3224a49 100644 --- a/ports/espressif/mpconfigport.mk +++ b/ports/espressif/mpconfigport.mk @@ -422,8 +422,13 @@ USB_NUM_IN_ENDPOINTS = 5 # affect existing boards. Freeing one IN endpoint (usb_hid.disable()) is then the # only thing a user needs, with no custom build. ifeq ($(IDF_TARGET),esp32s3) +# It needs the TinyUSB device stack and audiocore, so leave it off for boards +# that turn either off. The S3 has no AUDIOIO and no AUDIOPWMIO, so audiocore +# follows CIRCUITPY_AUDIOBUSIO here. +ifeq ($(filter 0,$(CIRCUITPY_USB_DEVICE) $(CIRCUITPY_AUDIOCORE) $(CIRCUITPY_AUDIOBUSIO)),) CIRCUITPY_USB_AUDIO ?= 1 endif +endif # Usually lots of flash space available CIRCUITPY_MESSAGE_COMPRESSION_LEVEL ?= 1 From e92d79eb4517d8ff421c590bdcb636684acedda5 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Fri, 14 Aug 2026 18:11:17 +0000 Subject: [PATCH 770/876] Add the picogame game engine module Retained-mode 2D engine for writing games in CircuitPython: a Scene with dirty-rect rendering over Sprite/Tilemap/Canvas/StripDraw/ Particles/Triangles layers, plus collision, noise and text helpers - and enough pseudo-3D primitives (project, raycast, mode-7, triangle batches) for simple 3D games. Renders portably through any BusDisplay; optional port backends add an async-DMA SPI path (raspberrypi, espressif) and a RAM-framebuffer target for DVI/HSTX scanout boards. Gated by CIRCUITPY_PICOGAME (off by default); enabled on pajenicko_picopad and adafruit_fruit_jam. --- locale/circuitpython.pot | 98 +- ports/espressif/common-hal/picogame/Display.c | 153 ++ ports/espressif/common-hal/picogame/Display.h | 33 + ports/raspberrypi/Makefile | 7 + .../adafruit_fruit_jam/mpconfigboard.mk | 3 + .../boards/pajenicko_picopad/mpconfigboard.mk | 15 +- .../raspberrypi/common-hal/picogame/Display.c | 165 ++ .../raspberrypi/common-hal/picogame/Display.h | 33 + .../raspberrypi/common-hal/picogame/interp.c | 54 + py/circuitpy_defns.mk | 14 + py/circuitpy_mpconfig.mk | 22 + shared-bindings/picogame/Bitmap.h | 11 + shared-bindings/picogame/Canvas.c | 541 +++++ shared-bindings/picogame/Canvas.h | 11 + shared-bindings/picogame/Display.c | 125 ++ shared-bindings/picogame/Display.h | 11 + shared-bindings/picogame/Framebuffer.h | 13 + shared-bindings/picogame/Particles.c | 127 ++ shared-bindings/picogame/Particles.h | 11 + shared-bindings/picogame/Scene.c | 532 +++++ shared-bindings/picogame/Scene.h | 11 + shared-bindings/picogame/Sprite.h | 11 + shared-bindings/picogame/Tilemap.c | 230 ++ shared-bindings/picogame/Tilemap.h | 11 + shared-bindings/picogame/__init__.c | 1940 +++++++++++++++++ shared-bindings/picogame/__init__.h | 15 + shared-module/picogame/Bitmap.h | 35 + shared-module/picogame/Canvas.c | 623 ++++++ shared-module/picogame/Canvas.h | 69 + shared-module/picogame/Particles.c | 163 ++ shared-module/picogame/Particles.h | 45 + shared-module/picogame/Scene.c | 226 ++ shared-module/picogame/Scene.h | 80 + shared-module/picogame/Sprite.h | 48 + shared-module/picogame/Tilemap.c | 100 + shared-module/picogame/Tilemap.h | 44 + shared-module/picogame/__init__.c | 1254 +++++++++++ shared-module/picogame/__init__.h | 308 +++ shared-module/picogame/pg_compat.h | 64 + 39 files changed, 7224 insertions(+), 32 deletions(-) create mode 100644 ports/espressif/common-hal/picogame/Display.c create mode 100644 ports/espressif/common-hal/picogame/Display.h create mode 100644 ports/raspberrypi/common-hal/picogame/Display.c create mode 100644 ports/raspberrypi/common-hal/picogame/Display.h create mode 100644 ports/raspberrypi/common-hal/picogame/interp.c create mode 100644 shared-bindings/picogame/Bitmap.h create mode 100644 shared-bindings/picogame/Canvas.c create mode 100644 shared-bindings/picogame/Canvas.h create mode 100644 shared-bindings/picogame/Display.c create mode 100644 shared-bindings/picogame/Display.h create mode 100644 shared-bindings/picogame/Framebuffer.h create mode 100644 shared-bindings/picogame/Particles.c create mode 100644 shared-bindings/picogame/Particles.h create mode 100644 shared-bindings/picogame/Scene.c create mode 100644 shared-bindings/picogame/Scene.h create mode 100644 shared-bindings/picogame/Sprite.h create mode 100644 shared-bindings/picogame/Tilemap.c create mode 100644 shared-bindings/picogame/Tilemap.h create mode 100644 shared-bindings/picogame/__init__.c create mode 100644 shared-bindings/picogame/__init__.h create mode 100644 shared-module/picogame/Bitmap.h create mode 100644 shared-module/picogame/Canvas.c create mode 100644 shared-module/picogame/Canvas.h create mode 100644 shared-module/picogame/Particles.c create mode 100644 shared-module/picogame/Particles.h create mode 100644 shared-module/picogame/Scene.c create mode 100644 shared-module/picogame/Scene.h create mode 100644 shared-module/picogame/Sprite.h create mode 100644 shared-module/picogame/Tilemap.c create mode 100644 shared-module/picogame/Tilemap.h create mode 100644 shared-module/picogame/__init__.c create mode 100644 shared-module/picogame/__init__.h create mode 100644 shared-module/picogame/pg_compat.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 38d498312ad..9a080633d34 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1041,7 +1041,7 @@ msgstr "" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format msgid "Buffer must be a multiple of %d bytes" msgstr "" @@ -1476,6 +1476,7 @@ msgid "Requested resource not found" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c msgid "Operation or feature not supported" msgstr "" @@ -1570,6 +1571,14 @@ msgstr "" msgid "Number of data_pins must be %d or %d, not %d" msgstr "" +#: ports/espressif/common-hal/picogame/Display.c +msgid "rgb444 fast Display not supported on this port yet" +msgstr "" + +#: ports/espressif/common-hal/picogame/Display.c +msgid "fast Display needs a FourWire SPI display" +msgstr "" + #: ports/espressif/common-hal/pulseio/PulseIn.c msgid "pop from an empty PulseIn" msgstr "" @@ -1682,7 +1691,8 @@ msgstr "" msgid "Only IPv4 addresses supported" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" msgstr "" @@ -1813,9 +1823,9 @@ msgstr "" #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/__init__.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/Filter.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" msgstr "" @@ -1844,6 +1854,17 @@ msgstr "" msgid "In-buffer elements must be <= 4 bytes long" msgstr "" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "" + +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" @@ -1958,6 +1979,13 @@ msgstr "" msgid "All timers for this pin are in use" msgstr "" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "" + #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "" @@ -2292,7 +2320,7 @@ msgid "extra keyword arguments given" msgstr "" #: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c msgid "argument num/types mismatch" msgstr "" @@ -2313,12 +2341,6 @@ msgstr "" msgid "%q must be <= %d" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "" - #: py/argcheck.c msgid "%q length must be %d-%d" msgstr "" @@ -2868,7 +2890,9 @@ msgstr "" msgid "schedule queue full" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c +#: py/modstruct.c shared-bindings/picogame/Canvas.c +#: shared-bindings/picogame/__init__.c shared-module/picogame/__init__.c +#: shared-module/struct/__init__.c msgid "buffer too small" msgstr "" @@ -3732,6 +3756,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c #: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c @@ -3749,10 +3774,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -3762,15 +3783,6 @@ msgstr "" msgid "%q and %q must be different" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " @@ -4088,6 +4100,36 @@ msgstr "" msgid "Specify exactly one of data0 or data_pins" msgstr "" +#: shared-bindings/picogame/Display.c shared-bindings/picogame/Scene.c +#: shared-bindings/picogame/__init__.c +msgid "expected a BusDisplay" +msgstr "" + +#: shared-bindings/picogame/Scene.c +msgid "scene full" +msgstr "" + +#: shared-bindings/picogame/Scene.c +msgid "item not in scene" +msgstr "" + +#: shared-bindings/picogame/__init__.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "" + +#: shared-bindings/picogame/__init__.c +msgid "PAL8 needs a palette" +msgstr "" + +#: shared-bindings/picogame/__init__.c +msgid "palette is empty" +msgstr "" + +#: shared-bindings/picogame/__init__.c +msgid "expected a Sprite, Tilemap, Particles, Canvas, StripDraw or Triangles" +msgstr "" + #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." msgstr "" @@ -4407,10 +4449,6 @@ msgstr "" msgid "no default packer" msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "" - #: shared-module/paralleldisplaybus/ParallelBus.c msgid "" "This microcontroller only supports data0=, not data_pins=, because it " diff --git a/ports/espressif/common-hal/picogame/Display.c b/ports/espressif/common-hal/picogame/Display.c new file mode 100644 index 00000000000..1c7f834f76d --- /dev/null +++ b/ports/espressif/common-hal/picogame/Display.c @@ -0,0 +1,153 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "common-hal/picogame/Display.h" + +#include + +#include "py/runtime.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/displayio/display_core.h" +#include "shared-bindings/displayio/__init__.h" +#include "shared-bindings/fourwire/FourWire.h" +#include "common-hal/busio/SPI.h" + +#include "driver/spi_master.h" + +// The esp-idf SPI device queue holds MAX_SPI_TRANSACTIONS (10) outstanding +// transactions. We keep up to two strips in flight (current transferring while +// the next is blitted), so each strip may use at most this many DMA chunks and +// still leave room: 2 * 5 <= 10. Strips needing more chunks fall back to a +// blocking send (correct, just no overlap for that strip). +#define PICOGAME_MAX_STRIP_CHUNKS 5 + +void common_hal_picogame_display_construct(picogame_display_obj_t *self, + busdisplay_busdisplay_obj_t *display, bool rgb444) { + self->display = display; + // RGB444 strip packing isn't implemented on this backend yet. Raise rather than silently + // ignore it: a no-op would leave the panel in RGB565 while the caller expects 444 (garbled + // output / wrong byte count). The rpi backend implements it; until this one does, fail loud. + if (rgb444) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("rgb444 fast Display not supported on this port yet")); + } + self->rgb444 = false; + + // The fast path queues raw DMA on the display's SPI device; only FourWire + // SPI buses expose one. + if (!mp_obj_is_type(display->bus.bus, &fourwire_fourwire_type)) { + mp_raise_ValueError(MP_ERROR_TEXT("fast Display needs a FourWire SPI display")); + } + fourwire_fourwire_obj_t *fw = MP_OBJ_TO_PTR(display->bus.bus); + self->spi = common_hal_busio_spi_get_device_handle(fw->bus); +} + +// Retrieve all outstanding results for *count queued chunks, then zero the count. +static void drain(spi_device_handle_t spi, int *count) { + spi_transaction_t *rtrans; + while (*count > 0) { + spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY); + (*count)--; + } +} + +// Queue one strip (nbytes from buf) as up to PICOGAME_MAX_STRIP_CHUNKS DMA +// transactions. Returns the chunk count, or -1 if it would need more chunks. +static int queue_strip(spi_device_handle_t spi, spi_transaction_t *trans, + const uint16_t *buf, size_t nbytes) { + int needed = (int)((nbytes + SPI_MAX_DMA_LEN - 1) / SPI_MAX_DMA_LEN); + if (needed > PICOGAME_MAX_STRIP_CHUNKS) { + return -1; + } + const uint8_t *p = (const uint8_t *)buf; + size_t off = 0; + int n = 0; + while (off < nbytes) { + size_t chunk = nbytes - off; + if (chunk > SPI_MAX_DMA_LEN) { + chunk = SPI_MAX_DMA_LEN; + } + memset(&trans[n], 0, sizeof(spi_transaction_t)); + trans[n].length = chunk * 8; // in bits + trans[n].tx_buffer = p + off; + spi_device_queue_trans(spi, &trans[n], portMAX_DELAY); + off += chunk; + n++; + } + return n; +} + +void common_hal_picogame_display_render(picogame_display_obj_t *self, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buf_a, uint16_t *buf_b, size_t buf_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t background, + int ox, int oy) { + + busdisplay_busdisplay_obj_t *display = self->display; + spi_device_handle_t spi = self->spi; + + // Open the GRAM window (set region, begin transaction, RAMWR). After the + // first DATA send raises DC, DC stays high for the raw queued strips that + // follow, and CS stays low until end_transaction. + int region_w, strip_h; + int cx0 = x0, cy0 = y0, cx1 = x1, cy1 = y1; // strip_begin clamps these to the panel in place + if (!picogame_strip_begin(display, &cx0, &cy0, &cx1, &cy1, buf_pixels, ®ion_w, &strip_h)) { + return; + } + + uint16_t *bufs[2] = { buf_a, buf_b }; + spi_transaction_t trans[2][PICOGAME_MAX_STRIP_CHUNKS]; + int inflight[2] = { 0, 0 }; // chunks queued from bufs[i], awaiting result + + // A StripDraw callback may latch a BaseException (Ctrl-C / auto-reload). Like the portable + // renderer and the RP backend, re-raise it -- but only AFTER the queued transfers drain and + // the bus transaction closes, so hold it here and propagate below. + mp_obj_t pending = MP_OBJ_NULL; + + int cur = 0; + bool first = true; + for (int sy = cy0; sy < cy1; sy += strip_h) { + int sh = picogame_imin(strip_h, cy1 - sy); + size_t nbytes = (size_t)region_w * sh * 2; + uint16_t *buf = bufs[cur]; + + // This buffer must be free before we overwrite it. + drain(spi, &inflight[cur]); + + // Blit this strip. If the OTHER buffer has a strip in flight, its DMA + // transfer overlaps this CPU work -- the whole point of the fast path. + pending = picogame_blit_strip_layers(buf, region_w, sy, sh, cx0, items, kinds, n, + background, ox, oy); + + int nch; + if (first) { + // First DATA send goes through the busdisplay so it raises DC. + display->bus.send(display->bus.bus, DISPLAY_DATA, + CHIP_SELECT_UNTOUCHED, (uint8_t *)buf, nbytes); + first = false; + } else if ((nch = queue_strip(spi, trans[cur], buf, nbytes)) >= 0) { + inflight[cur] = nch; + } else { + // Strip too large to keep two in flight: drain everything and send + // it blocking (DC already high, CS untouched). + drain(spi, &inflight[cur ^ 1]); + display->bus.send(display->bus.bus, DISPLAY_DATA, + CHIP_SELECT_UNTOUCHED, (uint8_t *)buf, nbytes); + } + cur ^= 1; + if (pending != MP_OBJ_NULL) { // callback interrupted: this strip is queued, now stop + flush + break; + } + } + + drain(spi, &inflight[0]); + drain(spi, &inflight[1]); + + displayio_display_bus_end_transaction(&display->bus); + + if (pending != MP_OBJ_NULL) { // bus now closed -> safe to re-raise (Ctrl-C / reload) + nlr_raise(MP_OBJ_TO_PTR(pending)); + } +} diff --git a/ports/espressif/common-hal/picogame/Display.h b/ports/espressif/common-hal/picogame/Display.h new file mode 100644 index 00000000000..b4487e5ee55 --- /dev/null +++ b/ports/espressif/common-hal/picogame/Display.h @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// Fast display backend (espressif): wraps an existing busdisplay and streams +// pixels with the esp-idf SPI master's queued DMA, double-buffered so the CPU +// blits the next strip while the current one transfers. Reuses the busdisplay's +// SPI device, window opcodes and dimensions -- controller/resolution agnostic. + +#pragma once + +#include "py/obj.h" +#include "driver/spi_master.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/picogame/Sprite.h" + +typedef struct { + mp_obj_base_t base; + busdisplay_busdisplay_obj_t *display; + spi_device_handle_t spi; // the busdisplay's SPI device (raw DMA queueing) + bool rgb444; // RGB444 strip packing (not yet implemented on this backend) +} picogame_display_obj_t; + +void common_hal_picogame_display_construct(picogame_display_obj_t *self, + busdisplay_busdisplay_obj_t *display, bool rgb444); + +void common_hal_picogame_display_render(picogame_display_obj_t *self, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buf_a, uint16_t *buf_b, size_t buf_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t background, + int ox, int oy); diff --git a/ports/raspberrypi/Makefile b/ports/raspberrypi/Makefile index 603121e059f..1c13d538e51 100755 --- a/ports/raspberrypi/Makefile +++ b/ports/raspberrypi/Makefile @@ -507,6 +507,13 @@ endif SRC_C += shared/runtime/gchelper_native.c +ifeq ($(CIRCUITPY_PICOGAME),1) +# SIO interpolator fast path for the picogame mode7 inner row (RP2040 + RP2350). +# Portable C remains the fallback on other ports. +SRC_C += common-hal/picogame/interp.c +CFLAGS += -DPICOGAME_HAS_INTERP=1 +endif + SRC_SDK := \ src/common/hardware_claim/claim.c \ src/common/pico_sync/critical_section.c \ diff --git a/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk index 086c823adb4..8c46cc0713b 100644 --- a/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_fruit_jam/mpconfigboard.mk @@ -11,5 +11,8 @@ EXTERNAL_FLASH_DEVICES = "W25Q128JVxQ" CIRCUITPY_SDIOIO = 1 +CIRCUITPY_PICOGAME = 1 +CIRCUITPY_PICOGAME_FRAMEBUFFER = 1 + # CIRCUITPY_DISPLAY_FONT = $(TOP)/tools/fonts/unifont-16.0.02-all.bdf # CIRCUITPY_FONT_EXTRA_CHARACTERS = "🖮🖱️" diff --git a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk index 8a364e4b840..b5df0e6ecb5 100644 --- a/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pajenicko_picopad/mpconfigboard.mk @@ -13,10 +13,17 @@ CIRCUITPY_USB_HOST = 0 CIRCUITPY_KEYPAD = 1 CIRCUITPY_STAGE = 1 +CIRCUITPY_PICOGAME = 1 +CIRCUITPY_PICOGAME_FAST_DISPLAY = 1 +CIRCUITPY_PICOGAME_RGB444 = 1 CIRCUITPY_AUDIOIO = 1 CIRCUITPY_AUDIOEFFECTS = 0 -CIRCUITPY__EVE = 1 +# Peripherals this board physically lacks: no FT8xx EVE display, no camera for the +# qrio QR *decoder* (QR generation = pure-Python adafruit_miniqr, unaffected), and no +# DVI/HDMI connector. Dropping them frees flash for the picogame engine. +CIRCUITPY__EVE = 0 +CIRCUITPY_QRIO = 0 CIRCUITPY_CYW43 = 1 CIRCUITPY_SSL = 1 @@ -26,7 +33,6 @@ CIRCUITPY_MDNS = 1 CIRCUITPY_SOCKETPOOL = 1 CIRCUITPY_WIFI = 1 -CIRCUITPY_PICODVI = 1 # Pimoroni PicoSystem peripherals are compatible, we can use of existing ugame.py FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/picosystem @@ -44,3 +50,8 @@ CFLAGS += \ # Must be accompanied by a linker script change CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' + +# The rp2 port default is -O3; on this Cortex-M0+ (no SIMD/FPU, 16 KB XIP cache) -O2 plus +# these five loop passes measures within +-1% of -O3 across the picogame render kernels +# while using ~150 KB less flash (gc.o/vm.o stay -O3 via SUPEROPT regardless). +OPTIMIZATION_FLAGS = -O2 -funswitch-loops -fpredictive-commoning -fgcse-after-reload -ftree-partial-pre -fsplit-paths diff --git a/ports/raspberrypi/common-hal/picogame/Display.c b/ports/raspberrypi/common-hal/picogame/Display.c new file mode 100644 index 00000000000..9c0fcd17011 --- /dev/null +++ b/ports/raspberrypi/common-hal/picogame/Display.c @@ -0,0 +1,165 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "common-hal/picogame/Display.h" + +#include "py/runtime.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/displayio/display_core.h" +#include "shared-bindings/displayio/__init__.h" +#include "shared-bindings/fourwire/FourWire.h" + +#include "hardware/spi.h" +#include "hardware/dma.h" + +// Claimed once and REUSED across every Display construct (incl. across soft resets / each game +// launched via supervisor.set_next_code_file). We claim via the raw pico-sdk, which CircuitPython +// does NOT release on a soft reset -- so claiming per-construct leaked a channel every game until +// "*** PANIC *** No DMA channels available" (and starved board.DISPLAY's own DMA, halving FPS). +// A C static survives a soft reset, so we remember and reuse our one channel; a hard reset frees it. +static int s_picogame_dma_chan = -1; + +void common_hal_picogame_display_construct(picogame_display_obj_t *self, + busdisplay_busdisplay_obj_t *display, bool rgb444) { + self->display = display; + #if CIRCUITPY_PICOGAME_RGB444 + self->rgb444 = rgb444; + #else + if (rgb444) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("Operation or feature not supported")); + } + self->rgb444 = false; + #endif + + // The fast path needs raw SPI access; only FourWire SPI buses are supported. + if (!mp_obj_is_type(display->bus.bus, &fourwire_fourwire_type)) { + mp_raise_TypeError_varg(MP_ERROR_TEXT("%q must be of type %q, not %q"), + MP_QSTR_display, MP_QSTR_FourWire, mp_obj_get_type(display->bus.bus)->name); + } + fourwire_fourwire_obj_t *fw = MP_OBJ_TO_PTR(display->bus.bus); + self->spi = fw->bus->peripheral; + + #if CIRCUITPY_PICOGAME_RGB444 + // Tell the panel which pixel format we'll send (COLMOD). Asserting it here also recovers from + // a previous program that left the panel in the other format (the setting survives soft reset). + picogame_set_pixel_format(display, rgb444); + #endif + + if (s_picogame_dma_chan < 0) { + s_picogame_dma_chan = dma_claim_unused_channel(true); + } + self->dma_chan = s_picogame_dma_chan; + + // Configure the channel ONCE (dreq, 8-bit, read-incr, write addr = SPI data reg). Per-strip we + // then only set the read address + transfer count and trigger -- no per-strip reconfiguration. + dma_channel_config c = dma_channel_get_default_config(self->dma_chan); + channel_config_set_transfer_data_size(&c, DMA_SIZE_8); + channel_config_set_dreq(&c, spi_get_dreq((spi_inst_t *)self->spi, true)); + channel_config_set_read_increment(&c, true); + channel_config_set_write_increment(&c, false); + dma_channel_configure(self->dma_chan, &c, + &spi_get_hw((spi_inst_t *)self->spi)->dr, NULL, 0, false); +} + +// Kick off an asynchronous TX-only DMA of `nbytes` from `buf` to the SPI FIFO (channel already +// configured in construct; just point it at `buf`, set the count, and trigger). +static void dma_start(int chan, const uint16_t *buf, size_t nbytes) { + dma_channel_set_read_addr(chan, buf, false); + dma_channel_set_trans_count(chan, nbytes, true); // true = trigger +} + +void common_hal_picogame_display_render(picogame_display_obj_t *self, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buf_a, uint16_t *buf_b, size_t buf_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t background, + int ox, int oy) { + + busdisplay_busdisplay_obj_t *display = self->display; + spi_inst_t *spi = (spi_inst_t *)self->spi; + + // RGB444 packs 2 px into 3 bytes, so each strip row must be an even number of pixels + // (whole bytes). Widen the region to even bounds; the extra <=1 px per side just repaints. + #if CIRCUITPY_PICOGAME_RGB444 + if (self->rgb444) { + x0 &= ~1; + x1 = (x1 + 1) & ~1; + if (x1 > display->core.width) { + x1 = display->core.width; + } + } + #endif + + // Compute geometry + open the GRAM window (set region, begin transaction, + // RAMWR). DC stays high for data after the first DATA send below, so the + // raw-DMA strips that follow need no DC toggling. + int region_w, strip_h; + int cx0 = x0, cy0 = y0, cx1 = x1, cy1 = y1; // strip_begin clamps these to the panel in place + if (!picogame_strip_begin(display, &cx0, &cy0, &cx1, &cy1, buf_pixels, ®ion_w, &strip_h)) { + return; + } + + uint16_t *bufs[2] = { buf_a, buf_b }; + int cur = 0; + bool first = true; + bool dma_inflight = false; + #if CIRCUITPY_PICOGAME_RGB444 + const bool rgb444 = self->rgb444; // hoist: invariant across all strips + #endif + + // A StripDraw callback may latch a BaseException (Ctrl-C / auto-reload). Like the portable + // picogame_render_region, we must re-raise it -- but only AFTER the in-flight DMA finishes and + // the bus transaction closes, so hold it here and propagate below (see the end of the function). + mp_obj_t pending = MP_OBJ_NULL; + + for (int sy = cy0; sy < cy1; sy += strip_h) { + int sh = picogame_imin(strip_h, cy1 - sy); + uint16_t *buf = bufs[cur]; + + // Blit this strip. When a DMA is in flight it transfers the *other* + // buffer, so this CPU work overlaps the SPI transfer. + pending = picogame_blit_strip_layers(buf, region_w, sy, sh, cx0, items, kinds, n, background, ox, oy); + + // RGB444: pack the just-blitted RGB565 strip in place (2 px -> 3 bytes) before sending. + // The pack overlaps the previous strip's DMA (we're transfer-bound), so it's ~free. + #if CIRCUITPY_PICOGAME_RGB444 + size_t nbytes = rgb444 + ? picogame_pack_rgb444(buf, (size_t)region_w * sh) + : (size_t)region_w * sh * 2; + #else + size_t nbytes = (size_t)region_w * sh * 2; + #endif + + if (first) { + // First strip goes through busdisplay: it drives DC high for data, + // which then stays high for the subsequent raw-DMA strips. + display->bus.send(display->bus.bus, DISPLAY_DATA, + CHIP_SELECT_UNTOUCHED, (uint8_t *)buf, nbytes); + first = false; + } else { + if (dma_inflight) { + dma_channel_wait_for_finish_blocking(self->dma_chan); + } + dma_start(self->dma_chan, buf, nbytes); + dma_inflight = true; + } + cur ^= 1; + if (pending != MP_OBJ_NULL) { // callback interrupted: this strip is queued, now stop + flush + break; + } + } + + if (dma_inflight) { + dma_channel_wait_for_finish_blocking(self->dma_chan); + } + while (spi_is_busy(spi)) { + // wait for the last bytes to leave the shift register before releasing CS + } + displayio_display_bus_end_transaction(&display->bus); + + if (pending != MP_OBJ_NULL) { // bus now closed -> safe to re-raise (Ctrl-C / reload) + nlr_raise(MP_OBJ_TO_PTR(pending)); + } +} diff --git a/ports/raspberrypi/common-hal/picogame/Display.h b/ports/raspberrypi/common-hal/picogame/Display.h new file mode 100644 index 00000000000..aaca229260f --- /dev/null +++ b/ports/raspberrypi/common-hal/picogame/Display.h @@ -0,0 +1,33 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// Fast display backend (RP2040): wraps an existing busdisplay and pushes pixels +// with asynchronous, double-buffered DMA so the CPU can blit the next strip +// while the current strip transfers over SPI. Reuses the busdisplay's SPI +// peripheral, window opcodes and dimensions - controller/resolution agnostic. + +#pragma once + +#include "py/obj.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/picogame/Sprite.h" + +typedef struct { + mp_obj_base_t base; + busdisplay_busdisplay_obj_t *display; + void *spi; // spi_inst_t* (kept opaque to avoid pico-sdk in this header) + int dma_chan; + bool rgb444; // pack strips to 12-bit RGB444 before sending (~25% less SPI traffic) +} picogame_display_obj_t; + +void common_hal_picogame_display_construct(picogame_display_obj_t *self, + busdisplay_busdisplay_obj_t *display, bool rgb444); + +void common_hal_picogame_display_render(picogame_display_obj_t *self, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buf_a, uint16_t *buf_b, size_t buf_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t background, + int ox, int oy); diff --git a/ports/raspberrypi/common-hal/picogame/interp.c b/ports/raspberrypi/common-hal/picogame/interp.c new file mode 100644 index 00000000000..78cc8581cbb --- /dev/null +++ b/ports/raspberrypi/common-hal/picogame/interp.c @@ -0,0 +1,54 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +// Mode-7 inner row via the SIO INTERPOLATOR (RP2040 + RP2350). The interpolator does the +// whole per-pixel texture walk in hardware: lane0 = (fx >> shx) & (tw-1), lane1 = +// ((fy >> shy) & (th-1)) << log2(tw), POP_FULL = texture_base + lane0 + lane1 = the texel +// ADDRESS, and (ADD_RAW) both accumulators advance by their full-precision steps on the +// same pop. That replaces ~8 shift/mask/mul/add ops per pixel with one SIO read. +// +// Per-CORE hardware: each core has its own interp0, so this stays safe even if rows are +// ever split across cores (each configures its own). The engine claims no SDK +// lane locks: CircuitPython core does not use the interpolators, and the config is +// rewritten per row call anyway. +// +// Fast path constraints (the caller guards): PAL8 texture, no transparency, stride == tw, +// log2(tw)+log2(th) <= 16 (mode7 textures are 64..256 pow2 - always true there). + +#include "py/mpconfig.h" + +#if CIRCUITPY_PICOGAME + +#include +#include "hardware/interp.h" +#include "shared-module/picogame/__init__.h" // the prototype (PICOGAME_HAS_INTERP) + +void picogame_mode7_row_interp(uint16_t *dst, int n, + const uint8_t *tex, const uint16_t *pal, + uint32_t fx, uint32_t fy, int32_t stepx, int32_t stepy, + int shx, int shy, int ltw, int lth) { + interp_config c0 = interp_default_config(); + interp_config_set_shift(&c0, (uint)shx); + interp_config_set_mask(&c0, 0, (uint)(ltw - 1)); + interp_config_set_add_raw(&c0, true); // accumulator advances by the RAW step + interp_set_config(interp0, 0, &c0); + interp_config c1 = interp_default_config(); + interp_config_set_shift(&c1, (uint)(shy - ltw)); + interp_config_set_mask(&c1, (uint)ltw, (uint)(ltw + lth - 1)); + interp_config_set_add_raw(&c1, true); + interp_set_config(interp0, 1, &c1); + interp0->base[0] = (uint32_t)stepx; + interp0->base[1] = (uint32_t)stepy; + interp0->base[2] = (uint32_t)(uintptr_t)tex; + interp0->accum[0] = fx; + interp0->accum[1] = fy; + for (int i = 0; i < n; i++) { + const uint8_t *p = (const uint8_t *)interp0->pop[2]; + dst[i] = pal[*p]; + } +} + +#endif diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index b50ab1ee633..bf24b737c19 100755 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -405,6 +405,9 @@ endif ifeq ($(CIRCUITPY_STAGE),1) SRC_PATTERNS += _stage/% endif +ifeq ($(CIRCUITPY_PICOGAME),1) +SRC_PATTERNS += picogame/% +endif ifeq ($(CIRCUITPY_STORAGE),1) SRC_PATTERNS += storage/% endif @@ -606,6 +609,12 @@ SRC_COMMON_HAL_ALL = \ wifi/ScannedNetworks.c \ wifi/__init__.c \ +# The fast Display backend is the only common-hal picogame source; include it +# only on ports that provide it (others use the portable bus.send renderer). +ifeq ($(CIRCUITPY_PICOGAME_FAST_DISPLAY),1) +SRC_COMMON_HAL_ALL += picogame/Display.c +endif + SRC_COMMON_HAL = $(filter $(SRC_PATTERNS), $(SRC_COMMON_HAL_ALL)) ifeq ($(CIRCUITPY_BLEIO_HCI),1) @@ -704,6 +713,11 @@ SRC_SHARED_MODULE_ALL = \ _stage/Layer.c \ _stage/Text.c \ _stage/__init__.c \ + picogame/__init__.c \ + picogame/Scene.c \ + picogame/Tilemap.c \ + picogame/Particles.c \ + picogame/Canvas.c \ aesio/__init__.c \ aesio/aes.c \ atexit/__init__.c \ diff --git a/py/circuitpy_mpconfig.mk b/py/circuitpy_mpconfig.mk index e4e01fcecc8..855d40de40e 100755 --- a/py/circuitpy_mpconfig.mk +++ b/py/circuitpy_mpconfig.mk @@ -583,6 +583,28 @@ CFLAGS += -DCIRCUITPY_SSL_MBEDTLS=$(CIRCUITPY_SSL_MBEDTLS) CIRCUITPY_STAGE ?= 0 CFLAGS += -DCIRCUITPY_STAGE=$(CIRCUITPY_STAGE) +# PicoPad 2D game engine (off by default). +CIRCUITPY_PICOGAME ?= 0 +CFLAGS += -DCIRCUITPY_PICOGAME=$(CIRCUITPY_PICOGAME) +# Fast async-DMA Display backend: needs a port-specific common-hal (the raspberrypi and +# espressif ports provide one). Boards without it use the portable bus.send renderer. +CIRCUITPY_PICOGAME_FAST_DISPLAY ?= 0 +CFLAGS += -DCIRCUITPY_PICOGAME_FAST_DISPLAY=$(CIRCUITPY_PICOGAME_FAST_DISPLAY) +# Does this board's panel controller support 12-bit RGB444 (COLMOD)? A capability flag the +# board declares (ST7789/ST7735 = 1, ILI9341 = 0); exposed as picogame.RGB444_SUPPORTED so +# a game can enable Display(rgb444=...) only where it works. Default 0 (safe RGB565). +CIRCUITPY_PICOGAME_RGB444 ?= 0 +CFLAGS += -DCIRCUITPY_PICOGAME_RGB444=$(CIRCUITPY_PICOGAME_RGB444) +# Full-frame RAM-framebuffer render backend for scanout-buffer platforms (RP2350 DVI/HSTX +# boards like the Fruit Jam). Off by default so flash-tight SPI-only boards don't carry it. +CIRCUITPY_PICOGAME_FRAMEBUFFER ?= 0 +CFLAGS += -DCIRCUITPY_PICOGAME_FRAMEBUFFER=$(CIRCUITPY_PICOGAME_FRAMEBUFFER) +# Float vs 16.16 fixed path for the 3D helpers: the default follows the architecture +# (see shared-module/picogame/__init__.h); set 0/1 here only to override for a board. +ifneq ($(CIRCUITPY_PICOGAME_FPU),) +CFLAGS += -DCIRCUITPY_PICOGAME_FPU=$(CIRCUITPY_PICOGAME_FPU) +endif + CIRCUITPY_STATUS_BAR ?= 1 CFLAGS += -DCIRCUITPY_STATUS_BAR=$(CIRCUITPY_STATUS_BAR) diff --git a/shared-bindings/picogame/Bitmap.h b/shared-bindings/picogame/Bitmap.h new file mode 100644 index 00000000000..44e2a2fb1aa --- /dev/null +++ b/shared-bindings/picogame/Bitmap.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Bitmap.h" + +extern const mp_obj_type_t picogame_bitmap_type; diff --git a/shared-bindings/picogame/Canvas.c b/shared-bindings/picogame/Canvas.c new file mode 100644 index 00000000000..eaad4232901 --- /dev/null +++ b/shared-bindings/picogame/Canvas.c @@ -0,0 +1,541 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/fontio/BuiltinFont.h" +#include "shared-module/picogame/Canvas.h" + +//| class Canvas: +//| """A RAM drawing surface (any size) composited as a Scene layer. Draw +//| primitives into it; only redrawn areas repaint. Colors are wire-order +//| (use picogame.rgb565).""" +//| +//| def __init__( +//| self, +//| width: int, +//| height: int, +//| *, +//| transparent: Optional[int] = None, +//| buffer: Optional[WriteableBuffer] = None, +//| ) -> None: +//| """If ``buffer`` is given (>= width*height*2 bytes, e.g. a memoryview from +//| picogame_arena), the Canvas draws into it instead of allocating its own - +//| lets you pre-allocate big surfaces once and dodge heap fragmentation.""" +//| ... +//| +static mp_obj_t picogame_canvas_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_width, ARG_height, ARG_transparent, ARG_buffer }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_buffer, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t w = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 1024, MP_QSTR_width); + mp_int_t h = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 1024, MP_QSTR_height); + + picogame_canvas_obj_t *self = mp_obj_malloc(picogame_canvas_obj_t, type); + self->w = w; + self->h = h; + self->x = 0; + self->y = 0; + if (args[ARG_buffer].u_obj != mp_const_none) { + // external buffer (e.g. an arena slice) - draw into it, don't allocate/own it + mp_buffer_info_t bi; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bi, MP_BUFFER_RW); + if (bi.len < (size_t)w * h * 2) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + if ((uintptr_t)bi.buf & 1) { // odd byte address -> uint16 pixel stores fault on Cortex-M0+ + mp_raise_ValueError_varg(MP_ERROR_TEXT("Buffer must be a multiple of %d bytes"), 2); + } + self->data = bi.buf; + self->data_obj = args[ARG_buffer].u_obj; // keep the backing object alive (GC-traced) + } else { + // Pure pixel data, no Python pointers -> exempt from the conservative GC scan + // (shorter gc.collect() pauses; a 150x60 canvas is 18 KB the mark phase can skip). + self->data = m_malloc_without_collect((size_t)w * h * sizeof(uint16_t)); + self->data_obj = MP_OBJ_NULL; + } + if (args[ARG_transparent].u_obj != mp_const_none) { + self->transparent = mp_obj_get_int(args[ARG_transparent].u_obj); + self->has_transparent = true; + } else { + self->transparent = 0; + self->has_transparent = false; + } + uint16_t fill = self->has_transparent ? self->transparent : 0; + for (size_t i = 0; i < (size_t)w * h; i++) { + self->data[i] = fill; + } + picogame_canvas_dirty_reset(self); + return MP_OBJ_FROM_PTR(self); +} + +static picogame_canvas_obj_t *cv_self(mp_obj_t o) { + return MP_OBJ_TO_PTR(o); +} + +// Shared int-arg unpacker for the plain drawing trampolines below: every one of them is +// "self + N ints -> void", and the inlined per-wrapper mp_obj_get_int runs cost ~70-120 B +// each at -Os. One loop here + a tiny per-wrapper stub keeps the flash cost per method at +// ~2 calls. n comes from the VAR_BETWEEN exact arity, so v[] is always fully written. +static picogame_canvas_obj_t *cv_args(const mp_obj_t *a, size_t n, int *v) { + for (size_t i = 1; i < n; i++) { + v[i - 1] = mp_obj_get_int(a[i]); + } + return cv_self(a[0]); +} + +//| def clear(self, color: int) -> None: ... +//| +static mp_obj_t canvas_clear(mp_obj_t self_in, mp_obj_t color) { + picogame_canvas_clear(cv_self(self_in), mp_obj_get_int(color)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(canvas_clear_obj, canvas_clear); + +//| +//| def pixel(self, x: int, y: int, color: int) -> None: ... +//| +static mp_obj_t canvas_pixel(size_t n, const mp_obj_t *a) { + int v[3]; + picogame_canvas_pixel(cv_args(a, n, v), v[0], v[1], v[2]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_pixel_obj, 4, 4, canvas_pixel); + +//| +//| def fill_rect(self, x: int, y: int, w: int, h: int, color: int) -> None: ... +//| +static mp_obj_t canvas_fill_rect(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_fill_rect(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_rect_obj, 6, 6, canvas_fill_rect); + +//| +//| def blit( +//| self, +//| bitmap: Bitmap, +//| x: int, +//| y: int, +//| frame: int = 0, +//| flip_x: bool = False, +//| flip_y: bool = False, +//| ) -> None: +//| """Stamp frame ``frame`` of ``bitmap`` into the canvas at (x, y), honouring its transparent +//| key. The retained way to bake an image (icon, portrait, rendered text) into a panel.""" +//| ... +//| +static mp_obj_t canvas_blit(size_t n, const mp_obj_t *a) { + picogame_bitmap_obj_t *bm = MP_OBJ_TO_PTR( + mp_arg_validate_type(a[1], &picogame_bitmap_type, MP_QSTR_bitmap)); + // Same domain as Sprite.frame (uint8): a negative frame would survive the blitter's + // wrap (C % keeps the sign) and read before the sheet data. + int frame = (n > 4) ? (int)mp_arg_validate_int_range(mp_obj_get_int(a[4]), 0, 255, MP_QSTR_frame) : 0; + bool fx = (n > 5) ? mp_obj_is_true(a[5]) : false; + bool fy = (n > 6) ? mp_obj_is_true(a[6]) : false; + picogame_canvas_blit(cv_self(a[0]), bm, mp_obj_get_int(a[2]), mp_obj_get_int(a[3]), frame, fx, fy); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_blit_obj, 4, 7, canvas_blit); + +//| def mode7( +//| self, +//| texture: Bitmap, +//| horizon: int, +//| y_off: int, +//| z: int, +//| rx0: int, +//| ry0: int, +//| rsx: int, +//| rsy: int, +//| cam_x: int, +//| cam_y: int, +//| ) -> None: +//| """Fill rows below ``horizon`` with a perspective ground plane (Mode-7) of +//| ``texture`` (power-of-2 dims). The int args are 16.16 fixed-point camera +//| terms; use the picogame_mode7 helper to compute them from angle/pos/fov.""" +//| ... +//| +static mp_obj_t canvas_mode7(size_t n, const mp_obj_t *a) { + picogame_bitmap_obj_t *tex = MP_OBJ_TO_PTR( + mp_arg_validate_type(a[1], &picogame_bitmap_type, MP_QSTR_texture)); + picogame_canvas_mode7(cv_self(a[0]), tex, + mp_obj_get_int(a[2]), mp_obj_get_int(a[3]), mp_obj_get_int(a[4]), + mp_obj_get_int(a[5]), mp_obj_get_int(a[6]), mp_obj_get_int(a[7]), + mp_obj_get_int(a[8]), mp_obj_get_int(a[9]), mp_obj_get_int(a[10])); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_mode7_obj, 11, 11, canvas_mode7); + +//| def fill_triangles( +//| self, +//| verts: ReadableBuffer, +//| colors: ReadableBuffer, +//| n: int, +//| x_off: int = 0, +//| y_off: int = 0, +//| ) -> None: +//| """Fill ``n`` triangles in ONE call: ``verts`` = int16 x0,y0,x1,y1,x2,y2 per triangle, +//| ``colors`` = uint16 wire RGB565 per triangle. Same rasteriser as fill_triangle, but the +//| whole batch crosses the Python/C boundary once - the win for many small triangles +//| (blocky 3D, low-poly meshes) where the ~10 us per-call overhead otherwise dominates. +//| ``x_off``/``y_off`` translate every vertex before clipping - pass the negated strip +//| origin (``y_off=-vy``) to replay one screen-space batch into each StripDraw view; +//| triangles fully outside the band are rejected with three compares, so the +//| per-strip re-submission stays cheap.""" +//| ... +//| +static mp_obj_t canvas_fill_triangles(size_t na, const mp_obj_t *a) { + picogame_canvas_obj_t *cv = cv_self(a[0]); + mp_buffer_info_t vi, ci; + mp_get_buffer_raise(a[1], &vi, MP_BUFFER_READ); + mp_get_buffer_raise(a[2], &ci, MP_BUFFER_READ); + int n = mp_obj_get_int(a[3]); + int xo = na > 4 ? mp_obj_get_int(a[4]) : 0; + int yo = na > 5 ? mp_obj_get_int(a[5]) : 0; + const int16_t *v = vi.buf; + const uint16_t *col = ci.buf; + int cap_v = (int)(vi.len / 12); // 6 int16 = 12 bytes per triangle + int cap_c = (int)(ci.len >> 1); + if (n > cap_v) { + n = cap_v; + } + if (n > cap_c) { + n = cap_c; + } + picogame_fill_triangle_batch(cv, v, col, n, xo, yo); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_triangles_obj, 4, 6, canvas_fill_triangles); + +//| def vspans( +//| self, +//| x0s: ReadableBuffer, +//| x1s: ReadableBuffer, +//| tops: ReadableBuffer, +//| bots: ReadableBuffer, +//| colors: ReadableBuffer, +//| n: int, +//| x_off: int = 0, +//| y_off: int = 0, +//| ) -> None: +//| """Fill ``n`` vertical colour spans in ONE call: span i covers x0s[i]..x1s[i] (exclusive) +//| by tops[i]..bots[i] (exclusive) in colour colors[i] - all five are uint16 arrays. +//| The batch primitive for column renderers (a raycaster's merged wall runs): the whole +//| span list crosses the Python/C boundary once per strip instead of once per span. +//| ``x_off``/``y_off`` translate every span before clipping - pass the negated strip origin +//| (x_off=-vx, y_off=-vy) to replay one screen-space batch into each StripDraw view; +//| spans outside the band are rejected with two compares.""" +//| ... +//| +static mp_obj_t canvas_vspans(size_t na, const mp_obj_t *a) { + picogame_canvas_obj_t *cv = cv_self(a[0]); + // five equal-shape uint16 arrays in a row: fetch + shortest-length fold in one loop + mp_buffer_info_t bi5[5]; + size_t cap = (size_t)-1; + for (int i = 0; i < 5; i++) { + mp_get_buffer_raise(a[1 + i], &bi5[i], MP_BUFFER_READ); + if (bi5[i].len < cap) { + cap = bi5[i].len; + } + } + int n = mp_obj_get_int(a[6]); + int xo = na > 7 ? mp_obj_get_int(a[7]) : 0; + int yo = na > 8 ? mp_obj_get_int(a[8]) : 0; + if (n > (int)(cap >> 1)) { + n = (int)(cap >> 1); // never read past the shortest array + } + const uint16_t *x0s = bi5[0].buf; + const uint16_t *x1s = bi5[1].buf; + const uint16_t *tops = bi5[2].buf; + const uint16_t *bots = bi5[3].buf; + const uint16_t *cols = bi5[4].buf; + int cw = cv->w, ch = cv->h; + for (int i = 0; i < n; i++) { + int t = tops[i] + yo, b = bots[i] + yo; + if (b <= 0 || t >= ch || b <= t) { + continue; // span outside this band + } + int x0 = x0s[i] + xo, x1 = x1s[i] + xo; + if (x1 <= 0 || x0 >= cw || x1 <= x0) { + continue; + } + picogame_canvas_fill_rect(cv, x0, t, x1 - x0, b - t, cols[i]); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_vspans_obj, 7, 9, canvas_vspans); + +//| def road( +//| self, +//| ri0: int, +//| tab: ReadableBuffer, +//| rl: ReadableBuffer, +//| rr: ReadableBuffer, +//| d05_q8: int, +//| d07_q8: int, +//| colors: ReadableBuffer, +//| ) -> None: +//| """Draw one racing-road strip (OutRun-style) from precomputed tables - the whole +//| per-scanline loop in one call. ri0 = road-table row of this surface's row 0 (may be +//| negative = sky rows). tab = int16 rows of {edge_w, dash_hw, wb05_q8, wb07_q8, flags}; +//| rl/rr = int16 per-row edges (see picogame.road_edges); d05/d07 = Q8 scroll phases; +//| colors = 6x uint16 {sky, road_a, road_b, rumble_a, rumble_b, dash}.""" +//| ... +//| +static mp_obj_t canvas_road(size_t n, const mp_obj_t *a) { + mp_buffer_info_t tabi, rli, rri, coli; + mp_get_buffer_raise(a[2], &tabi, MP_BUFFER_READ); + mp_get_buffer_raise(a[3], &rli, MP_BUFFER_READ); + mp_get_buffer_raise(a[4], &rri, MP_BUFFER_READ); + mp_get_buffer_raise(a[7], &coli, MP_BUFFER_READ); + int ntab = (int)(tabi.len / (5 * 2)); + int nedge = (int)(rli.len < rri.len ? rli.len : rri.len) / 2; + if (nedge < ntab) { + ntab = nedge; // never read past the shorter per-frame arrays + } + if (ntab <= 0 || coli.len < 6 * 2) { + return mp_const_none; + } + picogame_canvas_road(cv_self(a[0]), mp_obj_get_int(a[1]), + (const int16_t *)tabi.buf, ntab, (const int16_t *)rli.buf, (const int16_t *)rri.buf, + mp_obj_get_int(a[5]), mp_obj_get_int(a[6]), (const uint16_t *)coli.buf); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_road_obj, 8, 8, canvas_road); + +//| def rect(self, x: int, y: int, w: int, h: int, color: int) -> None: ... +//| +static mp_obj_t canvas_rect(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_rect(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_rect_obj, 6, 6, canvas_rect); + +//| +//| def line(self, x0: int, y0: int, x1: int, y1: int, color: int) -> None: ... +//| +static mp_obj_t canvas_line(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_line(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_line_obj, 6, 6, canvas_line); + +//| +//| def fill_circle(self, cx: int, cy: int, r: int, color: int) -> None: ... +//| +static mp_obj_t canvas_fill_circle(size_t n, const mp_obj_t *a) { + int v[4]; + picogame_canvas_fill_circle(cv_args(a, n, v), v[0], v[1], v[2], v[3]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_circle_obj, 5, 5, canvas_fill_circle); + +//| +//| def circle(self, cx: int, cy: int, r: int, color: int) -> None: ... +//| +static mp_obj_t canvas_circle(size_t n, const mp_obj_t *a) { + int v[4]; + picogame_canvas_circle(cv_args(a, n, v), v[0], v[1], v[2], v[3]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_circle_obj, 5, 5, canvas_circle); + +//| +//| def ring(self, cx: int, cy: int, r: int, thickness: int, color: int) -> None: ... +//| +static mp_obj_t canvas_ring(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_ring(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_ring_obj, 6, 6, canvas_ring); + +//| +//| def triangle( +//| self, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int +//| ) -> None: ... +//| +static mp_obj_t canvas_triangle(size_t n, const mp_obj_t *a) { + int v[7]; + picogame_canvas_triangle(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4], v[5], v[6]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_triangle_obj, 8, 8, canvas_triangle); + +//| +//| def fill_triangle( +//| self, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int +//| ) -> None: ... +//| +static mp_obj_t canvas_fill_triangle(size_t n, const mp_obj_t *a) { + int v[7]; + picogame_canvas_fill_triangle(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4], v[5], v[6]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_triangle_obj, 8, 8, canvas_fill_triangle); + +//| +//| def ellipse(self, cx: int, cy: int, rx: int, ry: int, color: int) -> None: ... +//| +static mp_obj_t canvas_ellipse(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_ellipse(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_ellipse_obj, 6, 6, canvas_ellipse); + +//| +//| def fill_ellipse(self, cx: int, cy: int, rx: int, ry: int, color: int) -> None: ... +//| +static mp_obj_t canvas_fill_ellipse(size_t n, const mp_obj_t *a) { + int v[5]; + picogame_canvas_fill_ellipse(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_ellipse_obj, 6, 6, canvas_fill_ellipse); + +//| +//| def fill_round_rect(self, x: int, y: int, w: int, h: int, r: int, color: int) -> None: ... +//| +static mp_obj_t canvas_fill_round_rect(size_t n, const mp_obj_t *a) { + int v[6]; + picogame_canvas_fill_round_rect(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4], v[5]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_round_rect_obj, 7, 7, canvas_fill_round_rect); + +//| +//| def frame3d(self, x: int, y: int, w: int, h: int, light: int, dark: int) -> None: ... +//| +static mp_obj_t canvas_frame3d(size_t n, const mp_obj_t *a) { + int v[6]; + picogame_canvas_frame3d(cv_args(a, n, v), v[0], v[1], v[2], v[3], v[4], v[5]); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_frame3d_obj, 7, 7, canvas_frame3d); + +//| +//| def text( +//| self, x: int, y: int, s: str, fg: int, font: fontio.BuiltinFont, bg: int | None = None +//| ) -> None: +//| """Composite ``s`` into the surface in C, rasterizing each glyph from ``font`` on the fly - +//| no Python glyph cache, no per-call Bitmap/Sprite (zero retained text RAM, no fragmentation). +//| If ``bg`` is given the glyph background is filled too; otherwise it is transparent. Inside a +//| StripDraw callback the ``view`` is a Canvas pointing at the live strip, so ``view.text(...)`` +//| draws immediate-mode HUD/screen text straight into the frame.""" +//| +static mp_obj_t canvas_text(size_t n, const mp_obj_t *a) { + const char *s = mp_obj_str_get_str(a[3]); + mp_int_t fg = mp_obj_get_int(a[4]); + const void *font = MP_OBJ_TO_PTR(mp_arg_validate_type(a[5], &fontio_builtinfont_type, MP_QSTR_font)); + bool has_bg = (n >= 7) && (a[6] != mp_const_none); + uint16_t bg = has_bg ? (uint16_t)mp_obj_get_int(a[6]) : 0; + picogame_canvas_text(cv_self(a[0]), mp_obj_get_int(a[1]), mp_obj_get_int(a[2]), + s, (uint16_t)fg, bg, has_bg, font); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_text_obj, 6, 7, canvas_text); + +//| def move(self, x: int, y: int) -> None: ... +//| +static mp_obj_t canvas_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + picogame_canvas_obj_t *self = cv_self(self_in); + int nx = mp_obj_get_int(x_in), ny = mp_obj_get_int(y_in); + if (nx == self->x && ny == self->y) { + return mp_const_none; // unchanged -> avoid an avoidable repaint + } + // dirty old + new extents so the move repaints both + picogame_canvas_dirty_union(self, self->x, self->y, self->x + self->w, self->y + self->h); + self->x = nx; + self->y = ny; + picogame_canvas_dirty_union(self, self->x, self->y, self->x + self->w, self->y + self->h); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(canvas_move_obj, canvas_move); + +//| +//| x: int +//| y: int +//| """Current pixel position of the canvas top-left (read-only; set with move()).""" +//| width: int +//| height: int +//| """Surface size in pixels (read-only).""" +//| +//| +static mp_obj_t canvas_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(cv_self(self_in)->x); +} +static MP_DEFINE_CONST_FUN_OBJ_1(canvas_get_x_obj, canvas_get_x); +MP_PROPERTY_GETTER(canvas_x_obj, (mp_obj_t)&canvas_get_x_obj); + +static mp_obj_t canvas_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(cv_self(self_in)->y); +} +static MP_DEFINE_CONST_FUN_OBJ_1(canvas_get_y_obj, canvas_get_y); +MP_PROPERTY_GETTER(canvas_y_obj, (mp_obj_t)&canvas_get_y_obj); + +static mp_obj_t canvas_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(cv_self(self_in)->w); +} +static MP_DEFINE_CONST_FUN_OBJ_1(canvas_get_width_obj, canvas_get_width); +MP_PROPERTY_GETTER(canvas_width_obj, (mp_obj_t)&canvas_get_width_obj); + +static mp_obj_t canvas_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(cv_self(self_in)->h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(canvas_get_height_obj, canvas_get_height); +MP_PROPERTY_GETTER(canvas_height_obj, (mp_obj_t)&canvas_get_height_obj); + +static const mp_rom_map_elem_t picogame_canvas_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&canvas_clear_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&canvas_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&canvas_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&canvas_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&canvas_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_pixel), MP_ROM_PTR(&canvas_pixel_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_rect), MP_ROM_PTR(&canvas_fill_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_blit), MP_ROM_PTR(&canvas_blit_obj) }, + { MP_ROM_QSTR(MP_QSTR_mode7), MP_ROM_PTR(&canvas_mode7_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_triangles), MP_ROM_PTR(&canvas_fill_triangles_obj) }, + { MP_ROM_QSTR(MP_QSTR_vspans), MP_ROM_PTR(&canvas_vspans_obj) }, + { MP_ROM_QSTR(MP_QSTR_road), MP_ROM_PTR(&canvas_road_obj) }, + { MP_ROM_QSTR(MP_QSTR_rect), MP_ROM_PTR(&canvas_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&canvas_line_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_circle), MP_ROM_PTR(&canvas_fill_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_circle), MP_ROM_PTR(&canvas_circle_obj) }, + { MP_ROM_QSTR(MP_QSTR_ring), MP_ROM_PTR(&canvas_ring_obj) }, + { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&canvas_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_triangle), MP_ROM_PTR(&canvas_fill_triangle_obj) }, + { MP_ROM_QSTR(MP_QSTR_ellipse), MP_ROM_PTR(&canvas_ellipse_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_ellipse), MP_ROM_PTR(&canvas_fill_ellipse_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill_round_rect), MP_ROM_PTR(&canvas_fill_round_rect_obj) }, + { MP_ROM_QSTR(MP_QSTR_frame3d), MP_ROM_PTR(&canvas_frame3d_obj) }, + { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&canvas_text_obj) }, + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&canvas_move_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_canvas_locals_dict, picogame_canvas_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_canvas_type, + MP_QSTR_Canvas, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_canvas_make_new, + locals_dict, &picogame_canvas_locals_dict + ); diff --git a/shared-bindings/picogame/Canvas.h b/shared-bindings/picogame/Canvas.h new file mode 100644 index 00000000000..fb37aa9f898 --- /dev/null +++ b/shared-bindings/picogame/Canvas.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Canvas.h" + +extern const mp_obj_type_t picogame_canvas_type; diff --git a/shared-bindings/picogame/Display.c b/shared-bindings/picogame/Display.c new file mode 100644 index 00000000000..276608a8c77 --- /dev/null +++ b/shared-bindings/picogame/Display.c @@ -0,0 +1,125 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" // brings in the board config (CIRCUITPY_PICOGAME_FAST_DISPLAY) + +// The fast DMA Display backend is port-specific (needs a common-hal). Ports without it +// (e.g. ESP32) build picogame with this whole type compiled out and use Scene's portable +// bus.send renderer instead - so picogame stays buildable on any CircuitPython port. +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" +#include "shared-bindings/picogame/Sprite.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/picogame/__init__.h" +#include "common-hal/picogame/Display.h" + +//| class Display: +//| """Fast display backend: wraps an existing ``busdisplay.BusDisplay`` and +//| pushes pixels with asynchronous double-buffered DMA, overlapping the CPU +//| blit of the next strip with the SPI transfer of the current one. +//| +//| Controller- and resolution-agnostic: reuses the busdisplay's SPI bus, +//| window commands and dimensions.""" +//| +//| def __init__(self, display: busdisplay.BusDisplay, *, rgb444: bool = False) -> None: +//| """rgb444=True drives the panel in 12-bit RGB444 instead of 16-bit RGB565: ~25% less +//| SPI traffic (and thus more FPS on full-screen / scrolling, transfer-bound scenes), at +//| 4096 colours instead of 65536 - which PAL8 art doesn't notice. The panel controller +//| must support COLMOD 12-bit (ST7789/ST7735 do; ILI9341 does NOT).""" +//| ... +//| +static mp_obj_t picogame_display_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_display, ARG_rgb444 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_display, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_rgb444, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t native = mp_obj_cast_to_native_base(args[ARG_display].u_obj, &busdisplay_busdisplay_type); + if (!mp_obj_is_type(native, &busdisplay_busdisplay_type)) { + mp_raise_TypeError(MP_ERROR_TEXT("expected a BusDisplay")); + } + picogame_display_obj_t *self = mp_obj_malloc(picogame_display_obj_t, type); + common_hal_picogame_display_construct(self, MP_OBJ_TO_PTR(native), args[ARG_rgb444].u_bool); + return MP_OBJ_FROM_PTR(self); +} + +//| def render( +//| self, +//| sprites: List[Sprite], +//| buffer_a: WriteableBuffer, +//| buffer_b: WriteableBuffer, +//| x0: int, +//| y0: int, +//| x1: int, +//| y1: int, +//| *, +//| background: int = 0, +//| ) -> None: +//| """Render ``sprites`` into region [x0,x1) x [y0,y1) and push via async +//| DMA. ``buffer_a``/``buffer_b`` are two equal strip buffers used for +//| double buffering (each >= region_width*2 bytes). +//| +//| SPRITES ONLY (unlike module-level ``picogame.render()``, which also accepts +//| StripDraw/Canvas/Tilemap/Particles): this is the low-level double-buffered +//| sprite push. For mixed layer kinds use a ``Scene`` or ``picogame.render()``.""" +//| ... +//| +//| +static mp_obj_t picogame_display_render(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_sprites, ARG_buffer_a, ARG_buffer_b, ARG_x0, ARG_y0, ARG_x1, ARG_y1, ARG_background }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sprites, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer_a, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer_b, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x0, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y0, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_background, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + }; + picogame_display_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + size_t n = 0; + mp_obj_t *items; + mp_obj_get_array(args[ARG_sprites].u_obj, &n, &items); + for (size_t i = 0; i < n; i++) { + mp_arg_validate_type(items[i], &picogame_sprite_type, MP_QSTR_sprite); + } + + mp_buffer_info_t ba, bb; + mp_get_buffer_raise(args[ARG_buffer_a].u_obj, &ba, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[ARG_buffer_b].u_obj, &bb, MP_BUFFER_WRITE); + size_t buf_pixels = (ba.len < bb.len ? ba.len : bb.len) / 2; + + // kinds == NULL: every item is a sprite (the layered path handles this). + common_hal_picogame_display_render(self, items, NULL, n, + (uint16_t *)ba.buf, (uint16_t *)bb.buf, buf_pixels, + args[ARG_x0].u_int, args[ARG_y0].u_int, args[ARG_x1].u_int, args[ARG_y1].u_int, + args[ARG_background].u_int, 0, 0); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_display_render_obj, 8, picogame_display_render); + +static const mp_rom_map_elem_t picogame_display_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&picogame_display_render_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_display_locals_dict, picogame_display_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_display_type, + MP_QSTR_Display, + MP_TYPE_FLAG_NONE, + make_new, picogame_display_make_new, + locals_dict, &picogame_display_locals_dict + ); + +#endif // CIRCUITPY_PICOGAME_FAST_DISPLAY diff --git a/shared-bindings/picogame/Display.h b/shared-bindings/picogame/Display.h new file mode 100644 index 00000000000..1edcf137d91 --- /dev/null +++ b/shared-bindings/picogame/Display.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "common-hal/picogame/Display.h" + +extern const mp_obj_type_t picogame_display_type; diff --git a/shared-bindings/picogame/Framebuffer.h b/shared-bindings/picogame/Framebuffer.h new file mode 100644 index 00000000000..fd248bfff13 --- /dev/null +++ b/shared-bindings/picogame/Framebuffer.h @@ -0,0 +1,13 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/__init__.h" // picogame_framebuffer_obj_t + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +extern const mp_obj_type_t picogame_framebuffer_type; +#endif diff --git a/shared-bindings/picogame/Particles.c b/shared-bindings/picogame/Particles.c new file mode 100644 index 00000000000..9f95050506f --- /dev/null +++ b/shared-bindings/picogame/Particles.c @@ -0,0 +1,127 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-module/picogame/Particles.h" + +static void reset_dirty(picogame_particles_obj_t *self) { + // INT32 sentinels (not int16): bbox fields are int32 + positions 24.8, so a big-world emitter past + // +-32767 px must still accumulate. (Matches picogame_dirty_reset; update()/clear() use it too.) + self->cx1 = self->px1 = 0x7fffffff; + self->cy1 = self->py1 = 0x7fffffff; + self->cx2 = self->px2 = -0x7fffffff - 1; + self->cy2 = self->py2 = -0x7fffffff - 1; +} + +//| class Particles: +//| """A pooled particle layer (small moving dots), drawn as one Scene layer. +//| Add it to a Scene, ``emit()`` bursts, and call ``tick()`` each frame.""" +//| +//| def __init__( +//| self, capacity: int, *, size: int = 1, gravity: float = 0.0, fade: bool = False +//| ) -> None: ... +//| +static mp_obj_t picogame_particles_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_capacity, ARG_size, ARG_gravity, ARG_fade }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_capacity, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_size, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_gravity, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_fade, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_int_t cap = mp_arg_validate_int_range(args[ARG_capacity].u_int, 1, 4096, MP_QSTR_capacity); + mp_int_t size = mp_arg_validate_int_range(args[ARG_size].u_int, 1, 8, MP_QSTR_size); + mp_float_t gravity = (args[ARG_gravity].u_obj == mp_const_none) + ? 0.0f : mp_obj_get_float(args[ARG_gravity].u_obj); + if (gravity > 127.99f) { // clamp to the int16 8.8 range: gravity*256 must fit + gravity = 127.99f; // [-32768, 32767]; |g|>=128 would flip the sign + } else if (gravity < -128.0f) { + gravity = -128.0f; + } + + picogame_particles_obj_t *self = mp_obj_malloc(picogame_particles_obj_t, type); + self->cap = cap; + self->count = 0; + self->size = size; + self->gravity = (int16_t)(gravity * 256); + self->fade = args[ARG_fade].u_bool; + // Pure numeric arrays, no Python pointers -> exempt from the conservative GC scan + // (shorter gc.collect() pauses; fixed at construction, never m_renew'd). + self->px = m_malloc_without_collect(cap * sizeof(int32_t)); + self->py = m_malloc_without_collect(cap * sizeof(int32_t)); + self->vx = m_malloc_without_collect(cap * sizeof(int16_t)); + self->vy = m_malloc_without_collect(cap * sizeof(int16_t)); + self->life = m_malloc_without_collect(cap * sizeof(uint16_t)); + self->life0 = m_malloc_without_collect(cap * sizeof(uint16_t)); + self->color = m_malloc_without_collect(cap * sizeof(uint16_t)); + reset_dirty(self); + return MP_OBJ_FROM_PTR(self); +} + +//| +//| def emit( +//| self, x: int, y: int, count: int, speed: int = 1, life: int = 30, color: int = 0xFFFF +//| ) -> None: +//| """Spawn ``count`` particles at (x, y) with random velocity up to ``speed`` +//| px/tick, living ``life`` ticks, in wire-order ``color``.""" +//| ... +//| +static mp_obj_t picogame_particles_emit_fun(size_t n_args, const mp_obj_t *args) { + picogame_particles_obj_t *self = MP_OBJ_TO_PTR(args[0]); + int x = mp_obj_get_int(args[1]); + int y = mp_obj_get_int(args[2]); + int count = mp_arg_validate_int_min(mp_obj_get_int(args[3]), 0, MP_QSTR_count); + // speed*256 must fit the int16_t velocity (8.8) -> cap 127; life is stored as uint16_t. + int speed = (n_args > 4) ? mp_arg_validate_int_range(mp_obj_get_int(args[4]), 0, 127, MP_QSTR_speed) : 1; + int life = (n_args > 5) ? mp_arg_validate_int_range(mp_obj_get_int(args[5]), 1, 65535, MP_QSTR_life) : 30; + uint16_t color = (n_args > 6) + ? mp_arg_validate_int_range(mp_obj_get_int(args[6]), 0, 0xFFFF, MP_QSTR_color) : 0xFFFF; + picogame_particles_emit(self, x, y, count, speed, life, color); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_particles_emit_obj, 4, 7, picogame_particles_emit_fun); + +//| def tick(self) -> None: +//| """Advance all particles one step (move, gravity, ageing).""" +//| ... +//| +static mp_obj_t picogame_particles_tick(mp_obj_t self_in) { + picogame_particles_update(MP_OBJ_TO_PTR(self_in)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_particles_tick_obj, picogame_particles_tick); + +//| def clear(self) -> None: +//| """Remove all particles.""" +//| ... +//| +//| +static mp_obj_t picogame_particles_clear_method(mp_obj_t self_in) { + picogame_particles_clear(MP_OBJ_TO_PTR(self_in)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_particles_clear_obj, picogame_particles_clear_method); + +static const mp_rom_map_elem_t picogame_particles_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_emit), MP_ROM_PTR(&picogame_particles_emit_obj) }, + { MP_ROM_QSTR(MP_QSTR_tick), MP_ROM_PTR(&picogame_particles_tick_obj) }, + { MP_ROM_QSTR(MP_QSTR_clear), MP_ROM_PTR(&picogame_particles_clear_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_particles_locals_dict, picogame_particles_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_particles_type, + MP_QSTR_Particles, + MP_TYPE_FLAG_NONE, + make_new, picogame_particles_make_new, + locals_dict, &picogame_particles_locals_dict + ); diff --git a/shared-bindings/picogame/Particles.h b/shared-bindings/picogame/Particles.h new file mode 100644 index 00000000000..8f8b37ab819 --- /dev/null +++ b/shared-bindings/picogame/Particles.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Particles.h" + +extern const mp_obj_type_t picogame_particles_type; diff --git a/shared-bindings/picogame/Scene.c b/shared-bindings/picogame/Scene.c new file mode 100644 index 00000000000..2793e7cbe5d --- /dev/null +++ b/shared-bindings/picogame/Scene.c @@ -0,0 +1,532 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include +#include "shared-module/picogame/pg_compat.h" +#include "py/objtuple.h" +#include "py/objlist.h" +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Sprite.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" +#endif +#include "shared-module/picogame/Scene.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Tilemap.h" +#include "shared-module/picogame/Particles.h" +#include "shared-module/picogame/Canvas.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "common-hal/picogame/Display.h" +#endif + +#define SCENE_INIT_CAP 8 +#define PICOGAME_MAX_DIRTY_RECTS 6 // separate regions repainted per refresh + +// Classify the `display` arg into a render backend and return the object Scene should +// store: a fast picogame.Display (DMA), a picogame.Framebuffer (RAM scanout buffer, when +// built in), or a plain busdisplay (portable bus.send). Sets *fast / *fb_target +// accordingly; for a busdisplay it accepts a SUBCLASS (e.g. adafruit_st7789.ST7789) by +// casting to its native base and returns that. Raises TypeError otherwise. This is where +// the flag-gated type checks live, so the constructor body stays clean. +static mp_obj_t scene_resolve_target(mp_obj_t disp, bool *fast, bool *fb_target) { + *fast = false; + *fb_target = false; + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + if (mp_obj_is_type(disp, &picogame_display_type)) { + *fast = true; + return disp; + } + #endif + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + if (mp_obj_is_type(disp, &picogame_framebuffer_type)) { + *fb_target = true; // refresh() composites dirty rects straight into its RAM buffer + return disp; + } + #endif + // Plain busdisplay: accept a subclass by casting to its native base; the portable + // renderer treats self->display as a busdisplay_busdisplay_obj_t directly. + mp_obj_t native = mp_obj_cast_to_native_base(disp, &busdisplay_busdisplay_type); + if (!mp_obj_is_type(native, &busdisplay_busdisplay_type)) { + mp_raise_TypeError(MP_ERROR_TEXT("expected a BusDisplay")); + } + return native; +} + +//| class Scene: +//| """Retained-mode scene with dirty-rectangle rendering. Add sprites and +//| tilemaps once (tilemaps first = bottom layer), mutate them each frame, +//| then call :py:meth:`refresh` - only the changed region is repainted. +//| Backed by a fast :py:class:`Display`.""" +//| +//| def __init__( +//| self, +//| display: Display, +//| buffer_a: WriteableBuffer, +//| buffer_b: WriteableBuffer, +//| *, +//| background: int = 0, +//| ) -> None: ... +//| +static mp_obj_t picogame_scene_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_display, ARG_buffer_a, ARG_buffer_b, ARG_background, + ARG_top, ARG_bottom, ARG_left, ARG_right }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_display, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer_a, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer_b, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_background, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_top, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // reserved border insets: + { MP_QSTR_bottom, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // the scene renders only the + { MP_QSTR_left, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // inner play rect; the app + { MP_QSTR_right, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // owns the border around it + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Resolve the render backend (fast Display / Framebuffer / busdisplay) - all the + // flag-gated type checks are concentrated in scene_resolve_target(). + bool fast, fb_target; + mp_obj_t disp = scene_resolve_target(args[ARG_display].u_obj, &fast, &fb_target); + + // The framebuffer path composites directly into the target, so it needs no strip + // buffers; the SPI/DMA paths do. Validate them only when they'll be used. (When + // CIRCUITPY_PICOGAME_FRAMEBUFFER is off, fb_target is always false -> always validated, + // as before.) + if (!fb_target) { + mp_buffer_info_t tmp; + mp_get_buffer_raise(args[ARG_buffer_a].u_obj, &tmp, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[ARG_buffer_b].u_obj, &tmp, MP_BUFFER_WRITE); + } + + picogame_scene_obj_t *self = mp_obj_malloc(picogame_scene_obj_t, type); + self->display = disp; + self->fast = fast; + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + self->fb_target = fb_target; + #endif + self->buf_a = args[ARG_buffer_a].u_obj; + self->buf_b = args[ARG_buffer_b].u_obj; + self->background = args[ARG_background].u_int; + self->count = 0; + self->cap = SCENE_INIT_CAP; + self->items = m_new(mp_obj_t, SCENE_INIT_CAP); + self->kinds = m_new(uint8_t, SCENE_INIT_CAP); + self->snap = m_new(picogame_snapshot_t, SCENE_INIT_CAP); + self->cleared = false; + self->ox = 0; + self->oy = 0; + self->top = args[ARG_top].u_int; + self->bottom = args[ARG_bottom].u_int; + self->left = args[ARG_left].u_int; + self->right = args[ARG_right].u_int; + mp_obj_t zeros[4] = { + MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(0), + MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(0), + }; + self->dirty_rect = mp_obj_new_list(4, zeros); // reused every refresh + return MP_OBJ_FROM_PTR(self); +} + +// On a full repaint, sync sprite snapshots to current and drain the layer +// dirties (tilemap/particles/canvas) so they don't re-report a stale region. +static void snapshot_sync(picogame_scene_obj_t *self) { + int a, b, c, d; + for (uint16_t i = 0; i < self->count; i++) { + uint8_t kind = self->kinds[i] & PICOGAME_KIND_MASK; + if (kind == PICOGAME_KIND_TILEMAP) { + picogame_tilemap_take_dirty(MP_OBJ_TO_PTR(self->items[i]), &a, &b, &c, &d); + } else if (kind == PICOGAME_KIND_PARTICLES) { + picogame_particles_take_dirty(MP_OBJ_TO_PTR(self->items[i]), &a, &b, &c, &d); + } else if (kind == PICOGAME_KIND_CANVAS) { + picogame_canvas_take_dirty(MP_OBJ_TO_PTR(self->items[i]), &a, &b, &c, &d); + } else if (kind == PICOGAME_KIND_STRIPDRAW) { + // Immediate-mode layer: no retained state to snapshot/drain. + } else if (kind == PICOGAME_KIND_TRIANGLES) { + // Screen-space batch: drain the count-set dirty so it doesn't re-report. + int e, f, g, hh; + picogame_dirty_take(&((picogame_triangles_obj_t *)MP_OBJ_TO_PTR(self->items[i]))->dx1, + &e, &f, &g, &hh); + } else { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self->items[i]); + picogame_bitmap_obj_t *bm = s->bitmap; + int ax1, ay1, ax2, ay2; + picogame_sprite_aabb(s, &ax1, &ay1, &ax2, &ay2); + self->snap[i].x = ax1; + self->snap[i].y = ay1; + self->snap[i].w = ax2 - ax1; + self->snap[i].h = ay2 - ay1; + self->snap[i].bitmap = (void *)bm; + self->snap[i].frame = s->frame; + self->snap[i].flags = s->flags; + self->snap[i].scale = s->scale; + self->snap[i].angle = s->angle; + self->snap[i].seq = s->seq; + self->snap[i].dither = s->dither; + self->snap[i].flash_color = s->flash_color; + } + } +} + +//| +//| def add( +//| self, item: Union[Sprite, Tilemap], *, fixed: bool = False +//| ) -> Union[Sprite, Tilemap]: +//| """Add a sprite/tilemap/particles/canvas (drawn next refresh; insertion +//| order is bottom-to-top). fixed=True pins the item to the screen (it ignores +//| the view offset) - use it for HUD / score / dialog over a scrolling world. +//| Returns the added item, so you can write ``spr = scene.add(Sprite(...))``.""" +//| ... +//| +static void scene_add_one(picogame_scene_obj_t *self, mp_obj_t item_in, bool fixed) { + uint8_t kind; + kind = picogame_kind_of(item_in); + if (fixed) { + kind |= PICOGAME_KIND_FIXED; + } + if (self->count >= self->cap) { + if (self->cap >= 0x8000) { // next doubling overflows uint16_t -> m_renew(0) shrink + mp_raise_RuntimeError(MP_ERROR_TEXT("scene full")); + } + uint16_t new_cap = self->cap * 2; + self->items = m_renew(mp_obj_t, self->items, self->cap, new_cap); + self->kinds = m_renew(uint8_t, self->kinds, self->cap, new_cap); + self->snap = m_renew(picogame_snapshot_t, self->snap, self->cap, new_cap); + self->cap = new_cap; + } + self->items[self->count] = item_in; + self->kinds[self->count] = kind; + // Snapshot starts all-zero ("invisible", nothing diffed against garbage - m_renew doesn't + // zero), so a newly added layer is detected as changed and drawn on the next refresh. + memset(&self->snap[self->count], 0, sizeof(picogame_snapshot_t)); + self->count++; + // Honour "drawn on the next refresh" for EVERY kind: the zeroed snapshot covers sprites, + // but a re-add()ed Canvas/Tilemap whose dirty flag was already consumed would otherwise + // stay invisible until some other change. add() is a cold path -> force a full repaint. + self->cleared = false; +} + +static mp_obj_t picogame_scene_add(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_item, ARG_fixed }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_item, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_fixed, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + scene_add_one(MP_OBJ_TO_PTR(pos_args[0]), args[ARG_item].u_obj, args[ARG_fixed].u_bool); + return args[ARG_item].u_obj; // constructive: return the added item for `x = scene.add(...)` +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_scene_add_obj, 2, picogame_scene_add); + +//| def add_all(self, items: Iterable[Union[Sprite, Tilemap]]) -> None: +//| """Add several sprites/tilemaps at once (bottom-to-top in order).""" +//| ... +//| +static mp_obj_t picogame_scene_add_all(mp_obj_t self_in, mp_obj_t iterable) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t iter = mp_getiter(iterable, NULL); + mp_obj_t item; + while ((item = mp_iternext(iter)) != MP_OBJ_STOP_ITERATION) { + scene_add_one(self, item, false); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_scene_add_all_obj, picogame_scene_add_all); + +//| def remove(self, item: Union[Sprite, Tilemap]) -> None: +//| """Remove a previously add()ed item (draw order of the rest is unchanged). +//| The next refresh repaints over where it was (a full repaint, like +//| :py:meth:`invalidate`), so it leaves no ghost. The item itself is untouched - +//| keep a reference and add() it again later to bring it back. Raises +//| ValueError if the item is not in the scene (e.g. already removed).""" +//| ... +//| +static mp_obj_t picogame_scene_remove(mp_obj_t self_in, mp_obj_t item_in) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + for (uint16_t i = 0; i < self->count; i++) { + if (self->items[i] != item_in) { + continue; + } + self->count--; + for (uint16_t j = i; j < self->count; j++) { // keep draw order: shift the tail down + self->items[j] = self->items[j + 1]; + self->kinds[j] = self->kinds[j + 1]; + self->snap[j] = self->snap[j + 1]; + } + self->items[self->count] = mp_const_none; // release the GC reference + self->cleared = false; // full repaint next refresh: background covers where it was + return mp_const_none; + } + mp_raise_ValueError(MP_ERROR_TEXT("item not in scene")); +} +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_scene_remove_obj, picogame_scene_remove); + +//| def invalidate(self) -> None: +//| """Force a full-screen repaint on the next refresh (e.g. on scene change).""" +//| ... +//| +static mp_obj_t picogame_scene_invalidate(mp_obj_t self_in) { + ((picogame_scene_obj_t *)MP_OBJ_TO_PTR(self_in))->cleared = false; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_invalidate_obj, picogame_scene_invalidate); + +//| def set_view(self, ox: int, oy: int) -> None: +//| """Set the view offset = screen position of the scene origin. Use a +//| constant offset to centre a small game, or update it each frame to +//| scroll (which repaints the whole screen).""" +//| ... +//| +static mp_obj_t picogame_scene_set_view(mp_obj_t self_in, mp_obj_t ox_in, mp_obj_t oy_in) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + int ox = mp_obj_get_int(ox_in); + int oy = mp_obj_get_int(oy_in); + if (ox != self->ox || oy != self->oy) { + self->ox = ox; + self->oy = oy; + self->cleared = false; // the whole view shifted -> full repaint next refresh + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(picogame_scene_set_view_obj, picogame_scene_set_view); + +//| view: Tuple[int, int] +//| """The current view offset (ox, oy) as set by set_view() (read-only).""" +static mp_obj_t picogame_scene_get_view(mp_obj_t self_in) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t t[2] = { MP_OBJ_NEW_SMALL_INT(self->ox), MP_OBJ_NEW_SMALL_INT(self->oy) }; + return mp_obj_new_tuple(2, t); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_get_view_obj, picogame_scene_get_view); +MP_PROPERTY_GETTER(picogame_scene_view_obj, (mp_obj_t)&picogame_scene_get_view_obj); + +//| display: Union[Display, busdisplay.BusDisplay] +//| """The backend this Scene was built with (a picogame.Display or a busdisplay), +//| read-only - handy for one-off picogame.render() / Display.render() calls.""" +//| +static mp_obj_t picogame_scene_get_display(mp_obj_t self_in) { + return ((picogame_scene_obj_t *)MP_OBJ_TO_PTR(self_in))->display; +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_get_display_obj, picogame_scene_get_display); +MP_PROPERTY_GETTER(picogame_scene_display_obj, (mp_obj_t)&picogame_scene_get_display_obj); + +// Compute the frame's dirty rectangles for a WxH target, clipped to the play rect +// [left, w-right) x [top, h-bottom). On the first refresh (or after invalidate) this is +// a single full-screen rect + a snapshot sync; afterwards it diffs against the previous +// frame. Returns the rect count written to `rects` (0 = nothing to repaint). +// Backend-agnostic, so the SPI/fast and framebuffer paths share the exact dirty logic. +static int scene_collect_dirty_rects(picogame_scene_obj_t *self, int w, int h, picogame_rect_t *rects) { + int nr; + if (self->cleared) { + nr = picogame_scene_compute_dirty_rects(self->items, self->kinds, self->snap, + self->count, w, h, self->ox, self->oy, rects, PICOGAME_MAX_DIRTY_RECTS); + if (nr == 0) { + return 0; + } + } else { + rects[0].x1 = 0; + rects[0].y1 = 0; + rects[0].x2 = w; + rects[0].y2 = h; + nr = 1; + snapshot_sync(self); + // NOTE: cleared flips to true only after the RENDER completes (see the callers) - + // the snapshots are already advanced here, so an exception mid-render would + // otherwise leave a partially painted frame that no later refresh repairs. + } + + // Clip every dirty rect to the play rect [left, w-right) x [top, h-bottom); the + // reserved border is the app's, so the scene never paints into it. Drop empty rects. + int pa_x1 = self->left; + int pa_x2 = w - self->right; + int pa_y1 = self->top; + int pa_y2 = h - self->bottom; + int kept = 0; + for (int i = 0; i < nr; i++) { + int rx1 = rects[i].x1 < pa_x1 ? pa_x1 : rects[i].x1; + int rx2 = rects[i].x2 > pa_x2 ? pa_x2 : rects[i].x2; + int ry1 = rects[i].y1 < pa_y1 ? pa_y1 : rects[i].y1; + int ry2 = rects[i].y2 > pa_y2 ? pa_y2 : rects[i].y2; + if (rx1 >= rx2 || ry1 >= ry2) { + continue; + } + rects[kept].x1 = rx1; + rects[kept].y1 = ry1; + rects[kept].x2 = rx2; + rects[kept].y2 = ry2; + kept++; + } + return kept; +} + +// Store the bounding union of `nr` rects into the reusable dirty_rect list (no per-frame +// tuple allocation) and return it. Shared by both refresh backends. +static mp_obj_t scene_store_dirty(picogame_scene_obj_t *self, const picogame_rect_t *rects, int nr, int w, int h) { + int ux1 = w, uy1 = h, ux2 = 0, uy2 = 0; + for (int i = 0; i < nr; i++) { + if (rects[i].x1 < ux1) { + ux1 = rects[i].x1; + } + if (rects[i].y1 < uy1) { + uy1 = rects[i].y1; + } + if (rects[i].x2 > ux2) { + ux2 = rects[i].x2; + } + if (rects[i].y2 > uy2) { + uy2 = rects[i].y2; + } + } + mp_obj_list_store(self->dirty_rect, MP_OBJ_NEW_SMALL_INT(0), MP_OBJ_NEW_SMALL_INT(ux1)); + mp_obj_list_store(self->dirty_rect, MP_OBJ_NEW_SMALL_INT(1), MP_OBJ_NEW_SMALL_INT(uy1)); + mp_obj_list_store(self->dirty_rect, MP_OBJ_NEW_SMALL_INT(2), MP_OBJ_NEW_SMALL_INT(ux2)); + mp_obj_list_store(self->dirty_rect, MP_OBJ_NEW_SMALL_INT(3), MP_OBJ_NEW_SMALL_INT(uy2)); + return self->dirty_rect; +} + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Retained-mode refresh against a RAM framebuffer target (scanout-buffer platforms: +// WASM playground, desktop sim, FruitJam DVI/HSTX). Same dirty-rect logic as the SPI +// path (via the shared helpers), but each rect is composited straight into the target +// with picogame_render_framebuffer - no strip buffers, no bus transaction. A latched +// StripDraw BaseException is re-raised (no bus to close). Self-contained here so +// picogame_scene_refresh() keeps its original SPI/fast shape. +static mp_obj_t scene_refresh_fb(picogame_scene_obj_t *self) { + picogame_framebuffer_obj_t *fbt = MP_OBJ_TO_PTR(self->display); + int w = fbt->width; + int h = fbt->height; + + // Emulated invert (pg.invert on a Framebuffer) just toggled -> recomposite the WHOLE frame so the + // negative flip covers the whole screen, not only this frame's dirty rects (like a panel INVON). + if (picogame_fb_take_invert_dirty()) { + self->cleared = false; + } + + picogame_rect_t rects[PICOGAME_MAX_DIRTY_RECTS]; + int nr = scene_collect_dirty_rects(self, w, h, rects); + if (nr == 0) { + return mp_const_none; + } + + // Snapshots are already advanced; stay in the needs-full-repaint state until the + // render completes, so a BaseException mid-render (Ctrl-C in a StripDraw) leaves a + // scene whose NEXT refresh repaints everything instead of keeping a torn frame. + self->cleared = false; + for (int i = 0; i < nr; i++) { + mp_obj_t exc = picogame_render_framebuffer(fbt->fb, fbt->width, fbt->height, fbt->fmt, + fbt->scratch, fbt->scratch_rows, + self->items, self->kinds, self->count, + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2, + self->background, self->ox, self->oy); + if (exc != MP_OBJ_NULL) { + nlr_raise(MP_OBJ_TO_PTR(exc)); // cleared stays false -> full repaint next refresh + } + } + self->cleared = true; + return scene_store_dirty(self, rects, nr, w, h); +} +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER + +//| def refresh(self) -> Optional[list]: +//| """Diff against the previous frame and repaint only the changed region(s). +//| Returns the bounding dirty rect as a REUSED list [x1, y1, x2, y2] (read it +//| immediately; it's overwritten next call), or None if nothing changed.""" +//| ... +//| +//| +static mp_obj_t picogame_scene_refresh(mp_obj_t self_in) { + picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); + + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + if (self->fb_target) { + return scene_refresh_fb(self); + } + #endif + + // Resolve the underlying busdisplay from either backend. + busdisplay_busdisplay_obj_t *bd; + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + picogame_display_obj_t *disp = NULL; + if (self->fast) { + disp = MP_OBJ_TO_PTR(self->display); + bd = disp->display; + } else + #endif + { + bd = MP_OBJ_TO_PTR(self->display); + } + int w = bd->core.width; + int h = bd->core.height; + + picogame_rect_t rects[PICOGAME_MAX_DIRTY_RECTS]; + int nr = scene_collect_dirty_rects(self, w, h, rects); + if (nr == 0) { + return mp_const_none; + } + + mp_buffer_info_t a, b; + mp_get_buffer_raise(self->buf_a, &a, MP_BUFFER_WRITE); + mp_get_buffer_raise(self->buf_b, &b, MP_BUFFER_WRITE); + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + size_t buf_pixels = (a.len < b.len ? a.len : b.len) / 2; // fast path double-buffers + #endif + + // Render each dirty rect independently; return their bounding union (kept for + // the existing "dirty WxH" debug prints). + // Snapshots are already advanced; stay in the needs-full-repaint state until the + // render completes, so a BaseException mid-render (Ctrl-C in a StripDraw) leaves a + // scene whose NEXT refresh repaints everything instead of keeping a torn frame. + self->cleared = false; + for (int i = 0; i < nr; i++) { + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + if (self->fast) { + common_hal_picogame_display_render(disp, self->items, self->kinds, self->count, + (uint16_t *)a.buf, (uint16_t *)b.buf, buf_pixels, + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2, + self->background, self->ox, self->oy); + } else + #endif + { + // Portable single-buffer bus.send path (any CircuitPython port). + picogame_render_region(bd, self->items, self->kinds, self->count, + (uint16_t *)a.buf, a.len / 2, + rects[i].x1, rects[i].y1, rects[i].x2, rects[i].y2, + self->background, self->ox, self->oy); + } + } + self->cleared = true; + + return scene_store_dirty(self, rects, nr, w, h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_refresh_obj, picogame_scene_refresh); + +static const mp_rom_map_elem_t picogame_scene_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_add), MP_ROM_PTR(&picogame_scene_add_obj) }, + { MP_ROM_QSTR(MP_QSTR_add_all), MP_ROM_PTR(&picogame_scene_add_all_obj) }, + { MP_ROM_QSTR(MP_QSTR_remove), MP_ROM_PTR(&picogame_scene_remove_obj) }, + { MP_ROM_QSTR(MP_QSTR_refresh), MP_ROM_PTR(&picogame_scene_refresh_obj) }, + { MP_ROM_QSTR(MP_QSTR_invalidate), MP_ROM_PTR(&picogame_scene_invalidate_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_view), MP_ROM_PTR(&picogame_scene_set_view_obj) }, + { MP_ROM_QSTR(MP_QSTR_view), MP_ROM_PTR(&picogame_scene_view_obj) }, + { MP_ROM_QSTR(MP_QSTR_display), MP_ROM_PTR(&picogame_scene_display_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_scene_locals_dict, picogame_scene_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_scene_type, + MP_QSTR_Scene, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_scene_make_new, + locals_dict, &picogame_scene_locals_dict + ); diff --git a/shared-bindings/picogame/Scene.h b/shared-bindings/picogame/Scene.h new file mode 100644 index 00000000000..733968b06ca --- /dev/null +++ b/shared-bindings/picogame/Scene.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Scene.h" + +extern const mp_obj_type_t picogame_scene_type; diff --git a/shared-bindings/picogame/Sprite.h b/shared-bindings/picogame/Sprite.h new file mode 100644 index 00000000000..97c38c8b762 --- /dev/null +++ b/shared-bindings/picogame/Sprite.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Sprite.h" + +extern const mp_obj_type_t picogame_sprite_type; diff --git a/shared-bindings/picogame/Tilemap.c b/shared-bindings/picogame/Tilemap.c new file mode 100644 index 00000000000..a850831032f --- /dev/null +++ b/shared-bindings/picogame/Tilemap.c @@ -0,0 +1,230 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-module/picogame/Tilemap.h" + +//| class Tilemap: +//| """A grid of tile indices into a tileset Bitmap (each frame = one tile). +//| Add it to a Scene as a background layer; setting tiles or moving the map +//| marks only the affected area dirty.""" +//| +//| def __init__(self, tileset: Bitmap, cols: int, rows: int) -> None: +//| """A map ``cols`` tiles wide by ``rows`` tiles tall (each cell indexes a +//| frame of ``tileset``).""" +//| ... +//| +static mp_obj_t picogame_tilemap_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_tileset, ARG_cols, ARG_rows }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_tileset, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_cols, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_rows, MP_ARG_REQUIRED | MP_ARG_INT }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_obj_t tileset_obj = mp_arg_validate_type(args[ARG_tileset].u_obj, &picogame_bitmap_type, MP_QSTR_tileset); + // Cap cols/rows (not just floor): an unbounded cols*rows overflows the size_t map/orient + // allocation on a 32-bit port, desyncing alloc size from the index space (same family as the + // Bitmap width*frames guard). 1024 each -> product <= 1M, far below SIZE_MAX; oversize maps + // MemoryError at alloc (safe). + mp_int_t map_w = mp_arg_validate_int_range(args[ARG_cols].u_int, 1, 1024, MP_QSTR_cols); + mp_int_t map_h = mp_arg_validate_int_range(args[ARG_rows].u_int, 1, 1024, MP_QSTR_rows); + + mp_obj_t map_obj = mp_obj_new_bytearray_of_zeros((size_t)map_w * map_h); + mp_buffer_info_t mi; + mp_get_buffer_raise(map_obj, &mi, MP_BUFFER_RW); + + picogame_tilemap_obj_t *self = mp_obj_malloc(picogame_tilemap_obj_t, type); + self->tileset = MP_OBJ_TO_PTR(tileset_obj); + self->tileset_obj = tileset_obj; + self->map = mi.buf; + self->map_obj = map_obj; + self->orient = NULL; // orientation plane allocated lazily on first flipped/rotated tile + self->orient_obj = mp_const_none; + self->map_w = map_w; + self->map_h = map_h; + self->x = 0; + self->y = 0; + picogame_tilemap_dirty_reset(self); + return MP_OBJ_FROM_PTR(self); +} + +//| def tile( +//| self, +//| tx: int, +//| ty: int, +//| value: Optional[int] = None, +//| *, +//| flip_x: bool = False, +//| flip_y: bool = False, +//| transpose: bool = False, +//| ) -> Optional[int]: +//| """Get the tile at (tx, ty) -> int; with ``value``, set it (and mark dirty) -> None. +//| The optional keyword ``flip_x``/``flip_y``/``transpose`` flags orient the tile - together +//| they give all 8 orientations (4 rotations x mirror) for free at draw time; use them +//| with a deduplicated tileset (png2picogame --dedup REMAP). Out-of-range reads as 0, +//| ignores writes.""" +//| ... +//| +static mp_obj_t picogame_tilemap_tile(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_tx, ARG_ty, ARG_value, ARG_flip_x, ARG_flip_y, ARG_transpose }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_tx, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_ty, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_value, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_flip_x, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_flip_y, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_transpose, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + int tx = args[ARG_tx].u_int; + int ty = args[ARG_ty].u_int; + bool oob = (tx < 0 || ty < 0 || tx >= self->map_w || ty >= self->map_h); + if (args[ARG_value].u_obj != mp_const_none) { + if (!oob) { + size_t off = (size_t)ty * self->map_w + tx; + uint8_t v = mp_obj_get_int(args[ARG_value].u_obj) & 0xff; + uint8_t o = 0; + if (args[ARG_flip_x].u_bool) { + o |= 1; + } + if (args[ARG_flip_y].u_bool) { + o |= 2; + } + if (args[ARG_transpose].u_bool) { + o |= 4; + } + // Allocate the orientation plane lazily - only maps that actually use flips/rotation + // pay the RAM (1 byte/cell). + if (o != 0 && self->orient == NULL) { + mp_obj_t ob = mp_obj_new_bytearray_of_zeros((size_t)self->map_w * self->map_h); + mp_buffer_info_t oi; + mp_get_buffer_raise(ob, &oi, MP_BUFFER_RW); + self->orient = oi.buf; + self->orient_obj = ob; + } + uint8_t old_o = self->orient ? self->orient[off] : 0; + if (self->map[off] != v || old_o != o) { + self->map[off] = v; + if (self->orient) { + self->orient[off] = o; + } + int tw = self->tileset ? self->tileset->width : 0; + int th = self->tileset ? self->tileset->height : 0; + int sx = self->x + tx * tw; + int sy = self->y + ty * th; + picogame_tilemap_dirty_union(self, sx, sy, sx + tw, sy + th); + } + } + return mp_const_none; + } + if (oob) { + return MP_OBJ_NEW_SMALL_INT(0); + } + return MP_OBJ_NEW_SMALL_INT(self->map[(size_t)ty * self->map_w + tx]); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_tilemap_tile_obj, 3, picogame_tilemap_tile); + +//| def move(self, x: int, y: int) -> None: +//| """Move the whole map to pixel (x, y).""" +//| ... +//| +static mp_obj_t picogame_tilemap_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(self_in); + int nx = mp_obj_get_int(x_in), ny = mp_obj_get_int(y_in); + if (nx == self->x && ny == self->y) { + return mp_const_none; // unchanged -> avoid a full-tilemap repaint + } + int ox1, oy1, ox2, oy2; + picogame_tilemap_extent(self, &ox1, &oy1, &ox2, &oy2); + self->x = nx; + self->y = ny; + int nx1, ny1, nx2, ny2; + picogame_tilemap_extent(self, &nx1, &ny1, &nx2, &ny2); + picogame_tilemap_dirty_union(self, ox1, oy1, ox2, oy2); + picogame_tilemap_dirty_union(self, nx1, ny1, nx2, ny2); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(picogame_tilemap_move_obj, picogame_tilemap_move); + +//| def fill(self, value: int) -> None: +//| """Set every tile to ``value``.""" +//| ... +//| +static mp_obj_t picogame_tilemap_fill(mp_obj_t self_in, mp_obj_t value_in) { + picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint8_t v = mp_obj_get_int(value_in) & 0xff; + size_t total = (size_t)self->map_w * self->map_h; + for (size_t i = 0; i < total; i++) { + self->map[i] = v; + if (self->orient) { + self->orient[i] = 0; // a plain fill clears any per-cell orientation + } + } + int x1, y1, x2, y2; + picogame_tilemap_extent(self, &x1, &y1, &x2, &y2); + picogame_tilemap_dirty_union(self, x1, y1, x2, y2); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_tilemap_fill_obj, picogame_tilemap_fill); + +//| x: int +//| y: int +//| """Current pixel position of the map's top-left (read-only; set with move()).""" +//| cols: int +//| rows: int +//| """Map size in tiles (read-only).""" +//| +//| +static mp_obj_t tilemap_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_tilemap_obj_t *)MP_OBJ_TO_PTR(self_in))->x); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_x_obj, tilemap_get_x); +MP_PROPERTY_GETTER(tilemap_x_obj, (mp_obj_t)&tilemap_get_x_obj); + +static mp_obj_t tilemap_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_tilemap_obj_t *)MP_OBJ_TO_PTR(self_in))->y); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_y_obj, tilemap_get_y); +MP_PROPERTY_GETTER(tilemap_y_obj, (mp_obj_t)&tilemap_get_y_obj); + +static mp_obj_t tilemap_get_cols(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_tilemap_obj_t *)MP_OBJ_TO_PTR(self_in))->map_w); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_cols_obj, tilemap_get_cols); +MP_PROPERTY_GETTER(tilemap_cols_obj, (mp_obj_t)&tilemap_get_cols_obj); + +static mp_obj_t tilemap_get_rows(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_tilemap_obj_t *)MP_OBJ_TO_PTR(self_in))->map_h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_rows_obj, tilemap_get_rows); +MP_PROPERTY_GETTER(tilemap_rows_obj, (mp_obj_t)&tilemap_get_rows_obj); + +static const mp_rom_map_elem_t picogame_tilemap_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_tile), MP_ROM_PTR(&picogame_tilemap_tile_obj) }, + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&picogame_tilemap_move_obj) }, + { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&picogame_tilemap_fill_obj) }, + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&tilemap_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&tilemap_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_cols), MP_ROM_PTR(&tilemap_cols_obj) }, + { MP_ROM_QSTR(MP_QSTR_rows), MP_ROM_PTR(&tilemap_rows_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_tilemap_locals_dict, picogame_tilemap_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_tilemap_type, + MP_QSTR_Tilemap, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_tilemap_make_new, + locals_dict, &picogame_tilemap_locals_dict + ); diff --git a/shared-bindings/picogame/Tilemap.h b/shared-bindings/picogame/Tilemap.h new file mode 100644 index 00000000000..9c1308f9eaa --- /dev/null +++ b/shared-bindings/picogame/Tilemap.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/picogame/Tilemap.h" + +extern const mp_obj_type_t picogame_tilemap_type; diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c new file mode 100644 index 00000000000..273439468de --- /dev/null +++ b/shared-bindings/picogame/__init__.c @@ -0,0 +1,1940 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame: 2D game engine bindings for the PicoPad and similar boards. +// Type definitions are consolidated here so the module has a single +// shared-bindings/shared-module .c pair (CircuitPython build convention). + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// --------------------------------------------------------------------------- +// Bitmap +// --------------------------------------------------------------------------- + +//| class Bitmap: +//| """An image atlas of one or more equal-size frames, of arbitrary size. +//| +//| Unlike ``_stage`` (fixed 16x16 tiles), frames may be any width/height. +//| Pixel data and palette entries must be in the display's wire byte order +//| (use :py:func:`picogame.rgb565` to build colors).""" +//| +//| def __init__( +//| self, +//| data: ReadableBuffer, +//| width: int, +//| height: int, +//| *, +//| format: int = RGB565, +//| palette: Optional[ReadableBuffer] = None, +//| frames: int = 1, +//| stride: int = 0, +//| transparent: Optional[int] = None, +//| ) -> None: ... +//| +// Int pixel/scale -> 24.8 fixed-point. Shift through unsigned so a wild coordinate (e.g. 100_000_000, +// in 32-bit mp_int range but not after <<8) wraps modularly instead of hitting signed-overflow UB. +// Costs nothing over a plain shift; for any real on-screen coordinate the result is identical. +static int32_t pg_int_to_fp8(mp_int_t v) { + return (int32_t)((uint32_t)v << 8); +} + +static mp_obj_t picogame_bitmap_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_data, ARG_width, ARG_height, ARG_format, ARG_palette, ARG_frames, ARG_stride, ARG_transparent }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PICOGAME_FMT_RGB565} }, + { MP_QSTR_palette, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_frames, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_stride, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // bound BEFORE any arithmetic: an unbounded width could overflow width*frames (int32) and wrap + // small, slipping past the size guards below into an undersized buffer (OOB read in the blitter). + mp_int_t width = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 65535, MP_QSTR_width); + mp_int_t height = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 65535, MP_QSTR_height); + mp_int_t frames = mp_arg_validate_int_range(args[ARG_frames].u_int, 1, 255, MP_QSTR_frames); + mp_int_t format = args[ARG_format].u_int; + if (format != PICOGAME_FMT_RGB565 && format != PICOGAME_FMT_PAL8) { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid format")); + } + mp_int_t stride = args[ARG_stride].u_int; + if (stride <= 0) { + stride = width * frames; + } + // stride must hold the whole horizontal atlas, and the dims must fit the uint16_t fields, + // or blits index past a row / the stored stride truncates. + mp_arg_validate_int_max(width * frames, 65535, MP_QSTR_width); + mp_arg_validate_int_max(stride, 65535, MP_QSTR_stride); + mp_arg_validate_int_min(stride, width * frames, MP_QSTR_stride); + + mp_buffer_info_t data_info; + mp_get_buffer_raise(args[ARG_data].u_obj, &data_info, MP_BUFFER_READ); + + const uint16_t *palette = NULL; + mp_obj_t palette_obj = MP_OBJ_NULL; + size_t pal_len = 0; + if (format == PICOGAME_FMT_PAL8) { + if (args[ARG_palette].u_obj == mp_const_none) { + mp_raise_ValueError(MP_ERROR_TEXT("PAL8 needs a palette")); + } + mp_buffer_info_t pal_info; + mp_get_buffer_raise(args[ARG_palette].u_obj, &pal_info, MP_BUFFER_READ); + palette = pal_info.buf; + palette_obj = args[ARG_palette].u_obj; + pal_len = pal_info.len; + } + + size_t bpp = (format == PICOGAME_FMT_PAL8) ? 1 : 2; + // 64-bit: stride*height*bpp can exceed 32 bits (stride,height <= 65535) and wrap small in a 32-bit + // size_t, letting a tiny buffer pass this check -> OOB read in the blitter. Compute + compare wide. + uint64_t need = (uint64_t)stride * (uint64_t)height * (uint64_t)bpp; + if ((uint64_t)data_info.len < need) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + if (format == PICOGAME_FMT_PAL8 && pal_len < 2) { + // Need >=1 entry so pal[0] is valid. Contract (see blitter): PAL8 indices MUST be < palette + // length. The caller may write indices into the (mutable) `data` buffer directly, so we cannot + // validate once here. An out-of-range index is undefined behaviour (reads past the palette: + // usually a garbage colour, but it may fault on some platforms). Per-pixel clamping was dropped + // for speed - see the "restore full bounds-safety" note in the PAL8 blit loop if it's needed. + mp_raise_ValueError(MP_ERROR_TEXT("palette is empty")); + } + + picogame_bitmap_obj_t *self = mp_obj_malloc(picogame_bitmap_obj_t, type); + self->data_obj = args[ARG_data].u_obj; + self->palette_obj = palette_obj; + self->data = data_info.buf; + self->palette = palette; + self->width = width; + self->height = height; + self->stride = stride; + self->frames = frames; + self->format = format; + // palette length in entries (informational; blitter assumes indices < this - see blit contract). + self->pal_entries = (uint16_t)((pal_len / 2) > 65535 ? 65535 : (pal_len / 2)); + if (args[ARG_transparent].u_obj != mp_const_none) { + self->transparent = mp_obj_get_int(args[ARG_transparent].u_obj); + self->has_transparent = true; + } else { + self->transparent = 0; + self->has_transparent = false; + } + return MP_OBJ_FROM_PTR(self); +} + +//| +//| width: int +//| height: int +//| frames: int +//| """Frame dimensions and frame count (read-only).""" +static mp_obj_t bitmap_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->width); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_width_obj, bitmap_get_width); +MP_PROPERTY_GETTER(bitmap_width_obj, (mp_obj_t)&bitmap_get_width_obj); + +static mp_obj_t bitmap_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->height); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_height_obj, bitmap_get_height); +MP_PROPERTY_GETTER(bitmap_height_obj, (mp_obj_t)&bitmap_get_height_obj); + +static mp_obj_t bitmap_get_frames(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->frames); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_frames_obj, bitmap_get_frames); +MP_PROPERTY_GETTER(bitmap_frames_obj, (mp_obj_t)&bitmap_get_frames_obj); + +//| format: int +//| """RGB565 or PAL8 (read-only).""" +static mp_obj_t bitmap_get_format(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->format); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_format_obj, bitmap_get_format); +MP_PROPERTY_GETTER(bitmap_format_obj, (mp_obj_t)&bitmap_get_format_obj); + +//| stride: int +//| """Row stride in pixels (read-only).""" +static mp_obj_t bitmap_get_stride(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->stride); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_stride_obj, bitmap_get_stride); +MP_PROPERTY_GETTER(bitmap_stride_obj, (mp_obj_t)&bitmap_get_stride_obj); + +//| palette: Optional[ReadableBuffer] +//| """The PAL8 palette buffer this Bitmap was built with, or None for RGB565 +//| (read-only). Lets palette helpers read it back instead of holding a sidecar ref.""" +static mp_obj_t bitmap_get_palette(mp_obj_t self_in) { + picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); + return (self->palette_obj == MP_OBJ_NULL) ? mp_const_none : self->palette_obj; +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_palette_obj, bitmap_get_palette); +MP_PROPERTY_GETTER(bitmap_palette_obj, (mp_obj_t)&bitmap_get_palette_obj); + +//| transparent: Optional[int] +//| """The transparent color/index, or None if the Bitmap is fully opaque (read-only).""" +//| +//| +static mp_obj_t bitmap_get_transparent(mp_obj_t self_in) { + picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->has_transparent ? MP_OBJ_NEW_SMALL_INT(self->transparent) : mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_transparent_obj, bitmap_get_transparent); +MP_PROPERTY_GETTER(bitmap_transparent_obj, (mp_obj_t)&bitmap_get_transparent_obj); + +static const mp_rom_map_elem_t picogame_bitmap_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&bitmap_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&bitmap_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_frames), MP_ROM_PTR(&bitmap_frames_obj) }, + { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&bitmap_format_obj) }, + { MP_ROM_QSTR(MP_QSTR_stride), MP_ROM_PTR(&bitmap_stride_obj) }, + { MP_ROM_QSTR(MP_QSTR_palette), MP_ROM_PTR(&bitmap_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_transparent), MP_ROM_PTR(&bitmap_transparent_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_bitmap_locals_dict, picogame_bitmap_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_bitmap_type, + MP_QSTR_Bitmap, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_bitmap_make_new, + locals_dict, &picogame_bitmap_locals_dict + ); + +// --------------------------------------------------------------------------- +// Sprite +// --------------------------------------------------------------------------- + +//| class Sprite: +//| """A positioned, animatable instance of a :py:class:`Bitmap`.""" +//| +//| def __init__( +//| self, +//| bitmap: Bitmap, +//| x: int = 0, +//| y: int = 0, +//| *, +//| frame: int = 0, +//| visible: bool = True, +//| flip_x: bool = False, +//| flip_y: bool = False, +//| ) -> None: ... +//| +static mp_obj_t picogame_sprite_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_bitmap, ARG_x, ARG_y, ARG_frame, ARG_visible, ARG_flip_x, ARG_flip_y }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_frame, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_visible, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_flip_x, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_flip_y, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t bitmap_obj = mp_arg_validate_type(args[ARG_bitmap].u_obj, &picogame_bitmap_type, MP_QSTR_bitmap); + + picogame_sprite_obj_t *self = mp_obj_malloc(picogame_sprite_obj_t, type); + self->bitmap = MP_OBJ_TO_PTR(bitmap_obj); + self->x = pg_int_to_fp8(args[ARG_x].u_int); // pixel -> 24.8 fixed-point (overflow-clamped) + self->y = pg_int_to_fp8(args[ARG_y].u_int); + self->frame = args[ARG_frame].u_int; + self->flags = (args[ARG_visible].u_bool ? PICOGAME_SPR_VISIBLE : 0) + | (args[ARG_flip_x].u_bool ? PICOGAME_SPR_FLIP_X : 0) + | (args[ARG_flip_y].u_bool ? PICOGAME_SPR_FLIP_Y : 0); + self->anchor_x = 0; // default pivot = top-left (0, 0) + self->anchor_y = 0; + self->scale = 256; // 8.8 fixed-point: 256 = 1.0x (no scaling) + self->angle = 0; // no rotation -> axis-aligned fast path + self->flash_color = 0; + self->dither = 0; + self->data = mp_const_none; + self->seq = 0; // dirty-rect change counter (mp_obj_malloc zeroes anyway; explicit) + return MP_OBJ_FROM_PTR(self); +} + +static void set_flag(picogame_sprite_obj_t *self, uint8_t flag, bool on) { + if (on) { + self->flags |= flag; + } else { + self->flags &= ~flag; + } +} + +// shadow / flash / dither are mutually exclusive (one blit effect at a time); setting one ON +// clears the others, so "the last effect you set wins". Turning one OFF clears ONLY its own flag, +// so clearing an effect you never enabled (e.g. spr.flash = 0) can't wipe a different active one. +#define PICOGAME_SPR_FX_MASK (PICOGAME_SPR_SHADOW | PICOGAME_SPR_FLASH | PICOGAME_SPR_DITHER | PICOGAME_SPR_TINT) +static void set_effect(picogame_sprite_obj_t *self, uint8_t flag, bool on) { + if (on) { + self->flags = (uint8_t)((self->flags & ~PICOGAME_SPR_FX_MASK) | flag); + } else { + self->flags &= (uint8_t) ~flag; + } +} + +// Round a float to 24.8 fixed-point (shared by the position/scale/anchor setters so the soft-float +// round sequence is emitted once, not per call site). +static int32_t pg_round_fp8(mp_float_t f) { + return (int32_t)(f * 256 + (f >= 0 ? (mp_float_t)0.5 : (mp_float_t)-0.5)); +} + +// Cast a (possibly subclassed) BusDisplay arg to its native object, raising if it isn't one. +// Also accepts the pg.Display fast-DMA wrapper (unwrapped to its underlying busdisplay - the +// portable send path): any handle that identifies the panel works wherever a display is +// expected, so the same object a Scene renders through also works for render()/invert(). +// Without this, code holding the wrapper (custom setup, rgb444) worked on ports WITHOUT the +// fast backend and TypeError'd on ports WITH it. +static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + if (mp_obj_is_type(obj, &picogame_display_type)) { + return ((picogame_display_obj_t *)MP_OBJ_TO_PTR(obj))->display; + } + #endif + mp_obj_t native = mp_obj_cast_to_native_base(obj, &busdisplay_busdisplay_type); + if (!mp_obj_is_type(native, &busdisplay_busdisplay_type)) { + mp_raise_TypeError(MP_ERROR_TEXT("expected a BusDisplay")); + } + return MP_OBJ_TO_PTR(native); +} + +// Accept an int or float and store as 24.8 fixed-point (rounded). Integer fast path avoids +// software float on RP2040 - game code sets x/y (via move/setters) every frame, usually with ints. +static int32_t obj_to_fp(mp_obj_t o) { + if (mp_obj_is_int(o)) { + return pg_int_to_fp8(mp_obj_get_int(o)); + } + mp_float_t f = mp_obj_get_float(o); + return pg_round_fp8(f); +} + +//| +//| x: int +//| y: int +//| """Integer pixel position (scene coords). Setting accepts a float for +//| sub-pixel placement; reading returns the floored pixel.""" +//| fx: float +//| fy: float +//| """Sub-pixel position (use for smooth physics: e.g. ``sprite.fx += 2.4``).""" +// FLASH NOTE (property objects vs. a single `attr` handler): Sprite (and the other property-dense +// types) expose each attribute as its own getter/setter + MP_PROPERTY object below - the standard +// CircuitPython shared-bindings idiom (~423 such uses across CP). Collapsing these onto ONE `attr` +// load/store function per type (a qstr switch, like py/objcomplex.c's complex_attr for .real/.imag) +// would save ~3-4 KB of flash across the whole binding layer (Sprite alone ~1.5-2.5 KB). It is a +// valid MicroPython mechanism and would NOT break the .pyi stubs (those are generated from the //| +// comments, not the C property objects). We deliberately KEEP property objects: they are the +// idiomatic, most readable shared-bindings form and keep every type's definition uniform. Revisit +// only if flash becomes critical (then convert Sprite first - the densest cluster - not every type). +static mp_obj_t sprite_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x >> 8); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_x_obj, sprite_get_x); +static mp_obj_t sprite_set_x(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x = obj_to_fp(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_x_obj, sprite_set_x); +MP_PROPERTY_GETSET(sprite_x_obj, (mp_obj_t)&sprite_get_x_obj, (mp_obj_t)&sprite_set_x_obj); + +static mp_obj_t sprite_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y >> 8); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_y_obj, sprite_get_y); +static mp_obj_t sprite_set_y(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y = obj_to_fp(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_y_obj, sprite_set_y); +MP_PROPERTY_GETSET(sprite_y_obj, (mp_obj_t)&sprite_get_y_obj, (mp_obj_t)&sprite_set_y_obj); + +static mp_obj_t sprite_get_fx(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_fx_obj, sprite_get_fx); +// set_fx is byte-identical to set_x (both store obj_to_fp(v) into ->x) -> reuse set_x's fun obj. +MP_PROPERTY_GETSET(sprite_fx_obj, (mp_obj_t)&sprite_get_fx_obj, (mp_obj_t)&sprite_set_x_obj); + +static mp_obj_t sprite_get_fy(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_fy_obj, sprite_get_fy); +// set_fy is byte-identical to set_y -> reuse set_y's fun obj. +MP_PROPERTY_GETSET(sprite_fy_obj, (mp_obj_t)&sprite_get_fy_obj, (mp_obj_t)&sprite_set_y_obj); + +static mp_obj_t sprite_get_frame(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->frame); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_frame_obj, sprite_get_frame); +static mp_obj_t sprite_set_frame(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->frame = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_frame_obj, sprite_set_frame); +MP_PROPERTY_GETSET(sprite_frame_obj, (mp_obj_t)&sprite_get_frame_obj, (mp_obj_t)&sprite_set_frame_obj); + +static mp_obj_t sprite_get_visible(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_VISIBLE) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_visible_obj, sprite_get_visible); +static mp_obj_t sprite_set_visible(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_VISIBLE, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_visible_obj, sprite_set_visible); +MP_PROPERTY_GETSET(sprite_visible_obj, (mp_obj_t)&sprite_get_visible_obj, (mp_obj_t)&sprite_set_visible_obj); + +static mp_obj_t sprite_get_flip_x(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_FLIP_X) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flip_x_obj, sprite_get_flip_x); +static mp_obj_t sprite_set_flip_x(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_FLIP_X, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_x_obj, sprite_set_flip_x); +MP_PROPERTY_GETSET(sprite_flip_x_obj, (mp_obj_t)&sprite_get_flip_x_obj, (mp_obj_t)&sprite_set_flip_x_obj); + +static mp_obj_t sprite_get_flip_y(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_FLIP_Y) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flip_y_obj, sprite_get_flip_y); +static mp_obj_t sprite_set_flip_y(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_FLIP_Y, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_y_obj, sprite_set_flip_y); +MP_PROPERTY_GETSET(sprite_flip_y_obj, (mp_obj_t)&sprite_get_flip_y_obj, (mp_obj_t)&sprite_set_flip_y_obj); + +//| scale: float +//| """Uniform draw scale (nearest-neighbour). 1.0 = native (fast path); 2.0 = double +//| size, fractional values are allowed (e.g. a powerup grow tween). Anchor stays put.""" +static mp_obj_t sprite_get_scale(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->scale * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_scale_obj, sprite_get_scale); +static mp_obj_t sprite_set_scale(mp_obj_t self_in, mp_obj_t v) { + int q; + if (mp_obj_is_int(v)) { // int fast path (no software float on RP2040) + q = pg_int_to_fp8(mp_obj_get_int(v)); // overflow-clamped <<8 + } else { + mp_float_t f = mp_obj_get_float(v); + q = pg_round_fp8(f); + } + if (q < 1) { + q = 1; + } + if (q > 65535) { + q = 65535; + } + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->scale = (uint16_t)q; + self->xf_valid = 0; // affine cache depends on scale + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_scale_obj, sprite_set_scale); +MP_PROPERTY_GETSET(sprite_scale_obj, (mp_obj_t)&sprite_get_scale_obj, (mp_obj_t)&sprite_set_scale_obj); + +//| angle: float +//| """Rotation in degrees about the anchor (0 = none, the fast path). Nearest-neighbour, +//| so integer scales stay crisp; rotation shimmers slightly (pixel-art trade-off).""" +static mp_obj_t sprite_get_angle(mp_obj_t self_in) { + return mp_obj_new_float((mp_float_t)((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->angle); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_angle_obj, sprite_get_angle); +static mp_obj_t sprite_set_angle(mp_obj_t self_in, mp_obj_t v) { + int a; + if (mp_obj_is_int(v)) { // int fast path (no software float on RP2040) + a = mp_obj_get_int(v); + } else { + mp_float_t f = mp_obj_get_float(v); + a = (int)(f + (f >= 0 ? (mp_float_t)0.5 : (mp_float_t)-0.5)); + } + a %= 360; + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->angle = (int16_t)a; + self->xf_valid = 0; // affine cache depends on angle + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_angle_obj, sprite_set_angle); +MP_PROPERTY_GETSET(sprite_angle_obj, (mp_obj_t)&sprite_get_angle_obj, (mp_obj_t)&sprite_set_angle_obj); + +//| shadow: bool +//| """Draw opaque pixels as a darkened destination instead of colour - a drop-shadow +//| silhouette (offset copy below the sprite) or a dim overlay (a solid sprite scaled +//| over a dialog/pause area).""" +static mp_obj_t sprite_get_shadow(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_SHADOW) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_shadow_obj, sprite_get_shadow); +static mp_obj_t sprite_set_shadow(mp_obj_t self_in, mp_obj_t v) { + set_effect(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_SHADOW, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_shadow_obj, sprite_set_shadow); +MP_PROPERTY_GETSET(sprite_shadow_obj, (mp_obj_t)&sprite_get_shadow_obj, (mp_obj_t)&sprite_set_shadow_obj); + +//| flash: int +//| """Draw opaque pixels as a solid colour (a wire-order RGB565 int from rgb565) instead +//| of their own colour - a hit-flash or tint. Set to a colour to enable, 0/False to turn +//| off. Pulse it for 1-3 frames on impact. Mutually exclusive with shadow/dither.""" +static mp_obj_t sprite_get_flash(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_FLASH) ? s->flash_color : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flash_obj, sprite_get_flash); +static mp_obj_t sprite_set_flash(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + // Falsy (None / False / 0) turns flash OFF. A non-zero colour enables it. (You can't flash + // pure black - use a near-black colour if you ever need that; off is the common case.) + if (!mp_obj_is_true(v)) { + set_effect(s, PICOGAME_SPR_FLASH, false); + } else { + s->flash_color = (uint16_t)mp_obj_get_int(v); + set_effect(s, PICOGAME_SPR_FLASH, true); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flash_obj, sprite_set_flash); +MP_PROPERTY_GETSET(sprite_flash_obj, (mp_obj_t)&sprite_get_flash_obj, (mp_obj_t)&sprite_set_flash_obj); + +//| dither: int +//| """Fake transparency via an ordered (Bayer) dither, no alpha blending: 0 = opaque +//| (off), 8 = ~50% see-through, 16 = invisible. A classic 1-bit look - for ghosts, +//| fading/spawning enemies, fog, force fields. Mutually exclusive with shadow/flash.""" +static mp_obj_t sprite_get_dither(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_DITHER) ? s->dither : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_dither_obj, sprite_get_dither); +static mp_obj_t sprite_set_dither(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + int lv = mp_obj_get_int(v); + if (lv < 0) { + lv = 0; + } + if (lv > 16) { + lv = 16; + } + s->dither = (uint8_t)lv; + set_effect(s, PICOGAME_SPR_DITHER, lv > 0); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_dither_obj, sprite_set_dither); +MP_PROPERTY_GETSET(sprite_dither_obj, (mp_obj_t)&sprite_get_dither_obj, (mp_obj_t)&sprite_set_dither_obj); + +//| tint: int +//| """Multiply opaque pixels by a colour (wire-order RGB565 from rgb565), keeping the +//| sprite's shading - coloured lighting, a red damage flush, a blue freeze, a power-up +//| glow. Unlike ``flash`` (flat replace) ``tint`` preserves detail. 0/False = off. Mutually +//| exclusive with shadow/flash/dither.""" +static mp_obj_t sprite_get_tint(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_TINT) ? s->flash_color : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_tint_obj, sprite_get_tint); +static mp_obj_t sprite_set_tint(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + if (!mp_obj_is_true(v)) { + set_effect(s, PICOGAME_SPR_TINT, false); + } else { + s->flash_color = (uint16_t)mp_obj_get_int(v); // shared colour field with flash + set_effect(s, PICOGAME_SPR_TINT, true); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_tint_obj, sprite_set_tint); +MP_PROPERTY_GETSET(sprite_tint_obj, (mp_obj_t)&sprite_get_tint_obj, (mp_obj_t)&sprite_set_tint_obj); + +//| transpose: bool +//| """Swap the sprite's X/Y axes - a cheap 90deg turn (no shimmer, unlike ``angle``). +//| Combined with ``flip_x``/``flip_y`` it gives all 8 orientations for free. Only on the fast +//| path (scale 1.0, angle 0); for rotation WITH scaling use ``angle``. The drawn footprint +//| swaps width/height.""" +static mp_obj_t sprite_get_transpose(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_TRANSPOSE) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_transpose_obj, sprite_get_transpose); +static mp_obj_t sprite_set_transpose(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_TRANSPOSE, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_transpose_obj, sprite_set_transpose); +MP_PROPERTY_GETSET(sprite_transpose_obj, (mp_obj_t)&sprite_get_transpose_obj, (mp_obj_t)&sprite_set_transpose_obj); + +//| data: Any +//| """Arbitrary per-sprite user payload for game state (default None).""" +static mp_obj_t sprite_get_data(mp_obj_t self_in) { + return ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->data; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_data_obj, sprite_get_data); +static mp_obj_t sprite_set_data(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->data = v; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_data_obj, sprite_set_data); +MP_PROPERTY_GETSET(sprite_data_obj, (mp_obj_t)&sprite_get_data_obj, (mp_obj_t)&sprite_set_data_obj); + +//| bitmap: Bitmap +//| """The sprite's source bitmap. Assigning a new one swaps graphics and may +//| change size; the scene repaints both the old and new bounds next refresh +//| (e.g. powerups, resizable HUD bars, text labels).""" +static mp_obj_t sprite_get_bitmap(mp_obj_t self_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->bitmap != NULL ? MP_OBJ_FROM_PTR(self->bitmap) : mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_bitmap_obj, sprite_get_bitmap); +static mp_obj_t sprite_set_bitmap(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t bm = mp_arg_validate_type(v, &picogame_bitmap_type, MP_QSTR_bitmap); + self->bitmap = MP_OBJ_TO_PTR(bm); + self->xf_valid = 0; // affine cache depends on bitmap dims + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_bitmap_obj, sprite_set_bitmap); +MP_PROPERTY_GETSET(sprite_bitmap_obj, (mp_obj_t)&sprite_get_bitmap_obj, (mp_obj_t)&sprite_set_bitmap_obj); + +//| anchor: Tuple[float, float] +//| """Pivot as fractions of the bitmap size: ``(0, 0)`` = top-left (default), +//| ``(0.5, 0.5)`` = center, ``(0.5, 1.0)`` = bottom-center. ``x``/``y`` then +//| refer to this point, so rotating frames or swapping to a different size +//| stays aligned. Stored in 1/256 steps.""" +//| +static mp_obj_t sprite_get_anchor(mp_obj_t self_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t t[2] = { + mp_obj_new_float(self->anchor_x * (mp_float_t)(1.0 / 256.0)), + mp_obj_new_float(self->anchor_y * (mp_float_t)(1.0 / 256.0)), + }; + return mp_obj_new_tuple(2, t); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_anchor_obj, sprite_get_anchor); +static int anchor_to_fp(mp_obj_t o) { + mp_float_t f = mp_obj_get_float(o); + int v = pg_round_fp8(f); + return v < 0 ? 0 : (v > 256 ? 256 : v); +} +static mp_obj_t sprite_set_anchor(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t len; + mp_obj_t *items; + mp_obj_get_array(v, &len, &items); + mp_arg_validate_length(len, 2, MP_QSTR_anchor); + self->anchor_x = anchor_to_fp(items[0]); + self->anchor_y = anchor_to_fp(items[1]); + self->xf_valid = 0; // affine cache depends on the pivot + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_anchor_obj, sprite_set_anchor); +MP_PROPERTY_GETSET(sprite_anchor_obj, (mp_obj_t)&sprite_get_anchor_obj, (mp_obj_t)&sprite_set_anchor_obj); + +//| def move(self, x: int, y: int) -> None: +//| """Set the sprite position.""" +//| ... +//| +static mp_obj_t sprite_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->x = obj_to_fp(x_in); + self->y = obj_to_fp(y_in); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(sprite_move_obj, sprite_move); + +//| def touch(self) -> None: +//| """Force this sprite to repaint on the next ``Scene.refresh()`` even though none +//| of its tracked properties (position, frame, scale, angle, bitmap) changed. Call +//| it after mutating the sprite's bitmap pixels IN PLACE (e.g. streaming a new frame +//| into the same buffer), which the dirty-rect tracker can't otherwise detect.""" +//| ... +//| +static mp_obj_t sprite_touch(mp_obj_t self_in) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->seq++; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_touch_obj, sprite_touch); + +// Fill (x1,y1,x2,y2) from a Sprite (its drawn aabb), a (x,y) point, or a (x1,y1,x2,y2) rect. +static void pg_obj_to_box(mp_obj_t o, int *x1, int *y1, int *x2, int *y2) { + if (mp_obj_is_type(o, &picogame_sprite_type)) { + picogame_sprite_aabb(MP_OBJ_TO_PTR(o), x1, y1, x2, y2); + return; + } + if (mp_obj_is_type(o, &mp_type_tuple) || mp_obj_is_type(o, &mp_type_list)) { + size_t len; + mp_obj_t *items; + mp_obj_get_array(o, &len, &items); + if (len == 2) { // a point -> a zero-size box + *x1 = *x2 = mp_obj_get_int(items[0]); + *y1 = *y2 = mp_obj_get_int(items[1]); + return; + } + if (len == 4) { // a rect + *x1 = mp_obj_get_int(items[0]); + *y1 = mp_obj_get_int(items[1]); + *x2 = mp_obj_get_int(items[2]); + *y2 = mp_obj_get_int(items[3]); + return; + } + } + mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(o)->name); +} + +//| def overlaps(self, other: "Sprite | tuple", inset: int = 0) -> bool: +//| """True if this sprite's drawn box overlaps ``other`` - an inclusive AABB, so they +//| collide the moment they touch. ``other`` may be another Sprite, a point ``(x, y)``, +//| or a rect ``(x1, y1, x2, y2)`` (e.g. a trigger zone or the screen for culling). +//| The box is anchor/scale/rotation aware. ``inset`` shrinks THIS sprite's box by N px +//| on each side, for a fair hitbox smaller than the art.""" +//| ... +//| +static mp_obj_t sprite_overlaps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_other, ARG_inset }; + static const mp_arg_t allowed[] = { + { MP_QSTR_other, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_inset, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed), allowed, args); + int ax1, ay1, ax2, ay2, bx1, by1, bx2, by2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(pos_args[0]), &ax1, &ay1, &ax2, &ay2); + pg_obj_to_box(args[ARG_other].u_obj, &bx1, &by1, &bx2, &by2); + int in = args[ARG_inset].u_int; // inset shrinks the CALLER's box (kw or positional) + bool hit = ((ax1 + in) <= bx2) && ((ax2 - in) >= bx1) && + ((ay1 + in) <= by2) && ((ay2 - in) >= by1); + return mp_obj_new_bool(hit); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(sprite_overlaps_obj, 2, sprite_overlaps); + +//| def near(self, other: "Sprite | tuple", r: int) -> bool: +//| """True if this sprite's centre is within ``r`` pixels of ``other``'s centre (squared +//| distance, no sqrt) - the round/forgiving test for bullets, pickups, explosions. +//| ``other`` may be a Sprite or a point ``(x, y)``. Centres come from the drawn box, so +//| it is anchor aware.""" +//| ... +//| +//| +static mp_obj_t sprite_near(mp_obj_t self_in, mp_obj_t other_in, mp_obj_t r_in) { + int ax1, ay1, ax2, ay2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(self_in), &ax1, &ay1, &ax2, &ay2); + int acx = (ax1 + ax2) / 2, acy = (ay1 + ay2) / 2, bcx, bcy; + if (mp_obj_is_type(other_in, &picogame_sprite_type)) { + int bx1, by1, bx2, by2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(other_in), &bx1, &by1, &bx2, &by2); + bcx = (bx1 + bx2) / 2; + bcy = (by1 + by2) / 2; + } else { + size_t len; + mp_obj_t *items; + mp_obj_get_array(other_in, &len, &items); + if (len != 2) { + mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(other_in)->name); + } + bcx = mp_obj_get_int(items[0]); + bcy = mp_obj_get_int(items[1]); + } + mp_int_t r = mp_obj_get_int(r_in), dx = acx - bcx, dy = acy - bcy; + return mp_obj_new_bool(dx * dx + dy * dy < r * r); +} +static MP_DEFINE_CONST_FUN_OBJ_3(sprite_near_obj, sprite_near); + +static const mp_rom_map_elem_t picogame_sprite_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&sprite_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&sprite_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_fx), MP_ROM_PTR(&sprite_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_fy), MP_ROM_PTR(&sprite_fy_obj) }, + { MP_ROM_QSTR(MP_QSTR_frame), MP_ROM_PTR(&sprite_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_visible), MP_ROM_PTR(&sprite_visible_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip_x), MP_ROM_PTR(&sprite_flip_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip_y), MP_ROM_PTR(&sprite_flip_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&sprite_scale_obj) }, + { MP_ROM_QSTR(MP_QSTR_angle), MP_ROM_PTR(&sprite_angle_obj) }, + { MP_ROM_QSTR(MP_QSTR_shadow), MP_ROM_PTR(&sprite_shadow_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash), MP_ROM_PTR(&sprite_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&sprite_dither_obj) }, + { MP_ROM_QSTR(MP_QSTR_tint), MP_ROM_PTR(&sprite_tint_obj) }, + { MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&sprite_transpose_obj) }, + { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&sprite_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&sprite_bitmap_obj) }, + { MP_ROM_QSTR(MP_QSTR_anchor), MP_ROM_PTR(&sprite_anchor_obj) }, + { MP_ROM_QSTR(MP_QSTR_overlaps), MP_ROM_PTR(&sprite_overlaps_obj) }, + { MP_ROM_QSTR(MP_QSTR_near), MP_ROM_PTR(&sprite_near_obj) }, + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&sprite_move_obj) }, + { MP_ROM_QSTR(MP_QSTR_touch), MP_ROM_PTR(&sprite_touch_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_sprite_locals_dict, picogame_sprite_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_sprite_type, + MP_QSTR_Sprite, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_sprite_make_new, + locals_dict, &picogame_sprite_locals_dict + ); + +// --------------------------------------------------------------------------- +// StripDraw (immediate-mode draw layer; struct in shared-module/picogame/__init__.h) +// --------------------------------------------------------------------------- + +//| class StripDraw: +//| """An immediate-mode draw layer that holds NO pixel buffer. Each refresh, for +//| every render strip overlapping its rect, ``callback(view, vx, vy, vw, vh)`` is +//| called with a :py:class:`Canvas` ``view`` pointing straight at the live strip +//| buffer - so you draw primitives directly into the frame (zero RAM, vs a Canvas +//| which costs width*height*2 bytes). The view's local (0, 0) is screen pixel +//| (vx, vy); (vw, vh) is the strip size. Draw only the rows in [vy, vy+vh) for +//| speed (anything outside the view is clipped anyway). The rect is repainted every +//| frame, so use it for animated / scanline content (pseudo-3D, gradients, +//| procedural backgrounds), not static art (use Canvas for that). +//| +//| COORDINATE CONTRACT: ``vx`` is the RENDER REGION's origin (NOT this layer's x), and the +//| view spans the FULL region WIDTH (the layer's rect only gates which ROWS run). So draw at +//| ABSOLUTE screen coords minus (vx, vy), and fill only your own rect with ``fill_rect`` - +//| ``view.clear()`` fills the whole region width. (When you render a StripDraw via +//| ``picogame.render([sd], buf, x,y,x+w,y+h)`` the region == the rect, so vx == x.) +//| Text via ``Canvas.text`` is ASCII (the built-in font); non-ASCII has no glyph.""" +//| +//| def __init__( +//| self, +//| callback: Callable[[Canvas, int, int, int, int], None], +//| x: int = 0, +//| y: int = 0, +//| width: int = 0, +//| height: int = 0, +//| ) -> None: ... +//| +static mp_obj_t picogame_stripdraw_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_callback, ARG_x, ARG_y, ARG_width, ARG_height, ARG_always_dirty }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_width, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_height, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_always_dirty, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + picogame_stripdraw_obj_t *self = mp_obj_malloc(picogame_stripdraw_obj_t, type); + self->callback = args[ARG_callback].u_obj; + self->x = args[ARG_x].u_int; + self->y = args[ARG_y].u_int; + self->w = args[ARG_width].u_int; + self->h = args[ARG_height].u_int; + self->faulted = false; + self->always_dirty = args[ARG_always_dirty].u_bool; + picogame_dirty_reset(&self->dx1); // render once on first refresh (even when always_dirty=False) + picogame_dirty_union(&self->dx1, self->x, self->y, self->x + self->w, self->y + self->h); + // A buffer-less Canvas reused as the per-strip drawing view: its `data` is + // repointed at the live strip each blit, so no surface RAM is allocated here. + picogame_canvas_obj_t *view = mp_obj_malloc(picogame_canvas_obj_t, &picogame_canvas_type); + view->data = NULL; + view->data_obj = MP_OBJ_NULL; + view->w = 0; + view->h = 0; + view->x = 0; + view->y = 0; + view->transparent = 0; + view->has_transparent = false; + picogame_canvas_dirty_reset(view); + self->view = MP_OBJ_FROM_PTR(view); + return MP_OBJ_FROM_PTR(self); +} + +//| +//| x: int +//| y: int +//| width: int +//| height: int +//| """The screen rect repainted each refresh (read/write). Move or resize the layer +//| by assigning these. Shrinking the rect leaves stale pixels behind - follow a +//| shrink with ``scene.invalidate()`` for a clean repaint (as the fx helpers do).""" +static mp_obj_t sd_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_x_obj, sd_get_x); +static mp_obj_t sd_set_x(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_x_obj, sd_set_x); +MP_PROPERTY_GETSET(sd_x_obj, (mp_obj_t)&sd_get_x_obj, (mp_obj_t)&sd_set_x_obj); + +static mp_obj_t sd_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->y); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_y_obj, sd_get_y); +static mp_obj_t sd_set_y(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->y = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_y_obj, sd_set_y); +MP_PROPERTY_GETSET(sd_y_obj, (mp_obj_t)&sd_get_y_obj, (mp_obj_t)&sd_set_y_obj); + +static mp_obj_t sd_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->w); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_width_obj, sd_get_width); +static mp_obj_t sd_set_width(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->w = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_width_obj, sd_set_width); +MP_PROPERTY_GETSET(sd_width_obj, (mp_obj_t)&sd_get_width_obj, (mp_obj_t)&sd_set_width_obj); + +static mp_obj_t sd_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_height_obj, sd_get_height); +static mp_obj_t sd_set_height(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->h = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_height_obj, sd_set_height); +MP_PROPERTY_GETSET(sd_height_obj, (mp_obj_t)&sd_get_height_obj, (mp_obj_t)&sd_set_height_obj); + +//| always_dirty: bool +//| """True (default): repaint every frame - for animated content (pseudo-3D, gradients). False: +//| repaint only after an ``invalidate()`` call (or when overlapped by another dirty layer) - for on-change UI, +//| so a static panel doesn't re-rasterize+re-push every frame. With False you MUST invalidate() on +//| every content/visibility change (it's invisible until you do).""" +//| +static mp_obj_t sd_get_always_dirty(mp_obj_t self_in) { + return mp_obj_new_bool(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_always_dirty_obj, sd_get_always_dirty); +static mp_obj_t sd_set_always_dirty(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty = mp_obj_is_true(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_always_dirty_obj, sd_set_always_dirty); +MP_PROPERTY_GETSET(sd_always_dirty_obj, (mp_obj_t)&sd_get_always_dirty_obj, (mp_obj_t)&sd_set_always_dirty_obj); + +//| def invalidate(self, x: int = 0, y: int = 0, w: int = 0, h: int = 0) -> None: +//| """Mark dirty so the layer repaints on the next refresh (only needed when +//| ``always_dirty=False``). With no args, the whole layer repaints. Pass a rect in +//| VIEW-LOCAL coordinates (the same (0,0)-at-``(vx, vy)`` space the draw callback uses) to +//| repaint only that region - like Canvas/Tilemap, the Scene then recomposites and pushes just +//| those rows. Repeated calls union; the rect is clamped to the layer.""" +//| +//| +static mp_obj_t sd_invalidate(size_t n_args, const mp_obj_t *args) { + picogame_stripdraw_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args >= 5) { // (x, y, w, h) in view-local coords -> clamped scene rect + int x1 = self->x + mp_obj_get_int(args[1]); + int y1 = self->y + mp_obj_get_int(args[2]); + int x2 = x1 + mp_obj_get_int(args[3]); + int y2 = y1 + mp_obj_get_int(args[4]); + if (x1 < self->x) { + x1 = self->x; + } + if (y1 < self->y) { + y1 = self->y; + } + if (x2 > self->x + self->w) { + x2 = self->x + self->w; + } + if (y2 > self->y + self->h) { + y2 = self->y + self->h; + } + if (x2 > x1 && y2 > y1) { + picogame_dirty_union(&self->dx1, x1, y1, x2, y2); + } + } else { // whole layer + picogame_dirty_union(&self->dx1, self->x, self->y, self->x + self->w, self->y + self->h); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sd_invalidate_obj, 1, 5, sd_invalidate); + +static const mp_rom_map_elem_t picogame_stripdraw_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&sd_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&sd_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&sd_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&sd_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_always_dirty), MP_ROM_PTR(&sd_always_dirty_obj) }, + { MP_ROM_QSTR(MP_QSTR_invalidate), MP_ROM_PTR(&sd_invalidate_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_stripdraw_locals_dict, picogame_stripdraw_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_stripdraw_type, + MP_QSTR_StripDraw, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_stripdraw_make_new, + locals_dict, &picogame_stripdraw_locals_dict + ); + +//| class Triangles: +//| def __init__(self, verts: ReadableBuffer, colors: ReadableBuffer) -> None: +//| """A retained SCREEN-SPACE triangle batch drawn entirely in C by the compositor: +//| ``verts`` = int16 x0,y0,x1,y1,x2,y2 per triangle, ``colors`` = uint16 wire RGB565 per +//| triangle - both CALLER-OWNED (fill them in place each frame). Set ``count`` to how +//| many triangles should draw; the assignment marks the layer dirty (full screen). +//| Unlike a StripDraw callback this runs no Python per strip, and unlike a Canvas it +//| holds no pixel buffer - the batch rasterises straight into each render strip with +//| a cheap band reject. The 3D-scene layer: pg.project into the arrays, painter's-order +//| the faces, set count, scene.refresh().""" +//| ... +//| +static mp_obj_t picogame_triangles_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + mp_arg_check_num(n_args, n_kw, 2, 2, false); + picogame_triangles_obj_t *self = mp_obj_malloc(picogame_triangles_obj_t, type); + mp_buffer_info_t vi, ci; + mp_get_buffer_raise(all_args[0], &vi, MP_BUFFER_READ); + mp_get_buffer_raise(all_args[1], &ci, MP_BUFFER_READ); + self->verts_obj = all_args[0]; + self->colors_obj = all_args[1]; + self->verts = (const int16_t *)vi.buf; + self->colors = (const uint16_t *)ci.buf; + size_t cap_v = vi.len / 12; // 6 int16 = 12 bytes per triangle + size_t cap_c = ci.len >> 1; + self->cap = (uint16_t)(cap_v < cap_c ? cap_v : cap_c); + self->count = 0; + picogame_dirty_reset(&self->dx1); + return MP_OBJ_FROM_PTR(self); +} + +//| count: int +//| """How many triangles of the batch draw next refresh (clamped to the buffer +//| capacity). Assigning marks the layer dirty for a full repaint.""" +//| +//| +static mp_obj_t tri_get_count(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_triangles_obj_t *)MP_OBJ_TO_PTR(self_in))->count); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tri_get_count_obj, tri_get_count); +static mp_obj_t tri_set_count(mp_obj_t self_in, mp_obj_t v) { + picogame_triangles_obj_t *self = MP_OBJ_TO_PTR(self_in); + int n = mp_obj_get_int(v); + if (n < 0) { + n = 0; + } + if (n > self->cap) { + n = self->cap; + } + self->count = (uint16_t)n; + picogame_dirty_union(&self->dx1, 0, 0, 32767, 32767); // clipped to the play rect later + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(tri_set_count_obj, tri_set_count); +MP_PROPERTY_GETSET(tri_count_obj, (mp_obj_t)&tri_get_count_obj, (mp_obj_t)&tri_set_count_obj); + +static const mp_rom_map_elem_t picogame_triangles_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&tri_count_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_triangles_locals_dict, picogame_triangles_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_triangles_type, + MP_QSTR_Triangles, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_triangles_make_new, + locals_dict, &picogame_triangles_locals_dict + ); + +// --------------------------------------------------------------------------- +// Module-level functions +// --------------------------------------------------------------------------- + +//| """2D game engine for the PicoPad and similar boards. +//| +//| Draws arbitrary-size sprites (unlike ``_stage``'s fixed 16x16 tiles) to a +//| ``busdisplay`` through a reusable strip buffer, with a dirty-rect scene, +//| tilemaps, particles, a drawing canvas and camera/effects.""" +//| +//| RGB565: int +//| """16-bit color bitmap format (wire byte order).""" +//| PAL8: int +//| """8-bit paletted bitmap format.""" +//| +//| +//| def rgb565(r: int, g: int, b: int) -> int: +//| """Build a display wire-order RGB565 color from 8-bit components.""" +//| ... +//| +//| +static mp_obj_t picogame_rgb565(mp_obj_t r_in, mp_obj_t g_in, mp_obj_t b_in) { + int r = mp_obj_get_int(r_in) & 0xff; + int g = mp_obj_get_int(g_in) & 0xff; + int b = mp_obj_get_int(b_in) & 0xff; + uint16_t c = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | (b >> 3); + uint16_t wire = (uint16_t)((c >> 8) | (c << 8)); + return MP_OBJ_NEW_SMALL_INT(wire); +} +static MP_DEFINE_CONST_FUN_OBJ_3(picogame_rgb565_obj, picogame_rgb565); + +// raycast(map, mw, mh, posx, posy, lrx, lry, srx, sry, sh, stride, ncols, wcolors, top, bot, col, dist) +// C DDA wall raycaster for picogame_ray.Raycaster - INTEGER ONLY (16.16 fixed-point, no FPU; the paint, +// temporal invalidate, pose-cache and billboard math stay in Python; Python does the once-per-frame +// trig and passes Q16 ray params). map: read-only bytes, mw*mh wall types (0 = empty). pos*, l*x/l*y +// (leftRay, column 0), s*x/s*y (rayStep per column) are all 16.16. wcolors: uint16[(maxtype+1)*2] - +// [t*2] near, [t*2+1] side colour. top/bot/col: uint16 write buffers (len>=ncols); dist: int32 write +// buffer (perpendicular distance, 16.16). The int64 divides/muls are ONLY the per-column setup +// (O(ncols)); the DDA step loop is pure 32-bit. Mirrors the Python float fallback closely. +// Optional arg 17 (runs - ONE uint16 write buffer, len>=5*ncols, laid out as five ncols-long +// planes [x0s | x1s | tops | bots | colors]): also emit the RLE-MERGED wall runs (adjacent equal +// columns fused; x in PIXELS = column*stride) and return the run count. The planes feed +// Canvas.vspans directly as memoryview slices. This hoists picogame_ray's per-frame Python merge +// loop into the same C pass (measured 2-6.5 ms/frame of interpreted merge at stride=1 on RP2040). +// Callers clamp the LAST run's x1 to the screen width (stride rounding can overshoot by = 18) { // run outputs requested + mp_buffer_info_t q; + mp_get_buffer_raise(args[17], &q, MP_BUFFER_WRITE); + int cap = (int)(q.len / 10); // five uint16 planes + if (ncols > cap) { + ncols = cap; // never write past the run planes + } + r0 = q.buf; + r1 = r0 + cap; + rt = r1 + cap; + rb = rt + cap; + rcol = rb + cap; + } + const uint8_t *map = mi.buf; + const uint16_t *wc = wi.buf; + int wc_types = (int)(wi.len >> 2); + uint16_t *top = ti.buf; + uint16_t *bot = bi.buf; + uint16_t *col = ci.buf; + int32_t *dist_out = di.buf; // perpendicular distance, 16.16 + int half = sh >> 1; + int imapx0 = posx >> 16; + int imapy0 = posy >> 16; + int32_t fracx = posx & 0xFFFF; // fractional part of pos, 16.16 + int32_t fracy = posy & 0xFFFF; + const int32_t DD_CAP = (int32_t)1 << 24; // cap deltaDist so a 64-step accumulation stays in int32 + if (ncols > (int)(ti.len >> 1)) { + ncols = (int)(ti.len >> 1); + } + for (int c = 0; c < ncols; c++) { + int mapx = imapx0; + int mapy = imapy0; + int32_t ax = rdx < 0 ? -rdx : rdx; + int32_t ay = rdy < 0 ? -rdy : rdy; + // deltaDist = |1/rayDir| in 16.16 = (1<<32)/|rayDir_q16| (int64; per-column setup, not per-step) + int64_t ddx64 = ax ? (((int64_t)1 << 32) / ax) : (int64_t)DD_CAP; + int64_t ddy64 = ay ? (((int64_t)1 << 32) / ay) : (int64_t)DD_CAP; + int32_t ddx = ddx64 > DD_CAP ? DD_CAP : (int32_t)ddx64; + int32_t ddy = ddy64 > DD_CAP ? DD_CAP : (int32_t)ddy64; + int stepx, stepy; + int32_t sidex, sidey; + // sideDist to the first grid line = (fractional distance) * deltaDist, 16.16 (int64 mul, setup only) + if (rdx < 0) { + stepx = -1; + sidex = (int32_t)(((int64_t)fracx * ddx) >> 16); + } else { + stepx = 1; + sidex = (int32_t)(((int64_t)(65536 - fracx) * ddx) >> 16); + } + if (rdy < 0) { + stepy = -1; + sidey = (int32_t)(((int64_t)fracy * ddy) >> 16); + } else { + stepy = 1; + sidey = (int32_t)(((int64_t)(65536 - fracy) * ddy) >> 16); + } + int side = 0; + int cell = 1; + for (int i = 0; i < 64; i++) { // DDA - pure 32-bit + if (sidex < sidey) { + sidex += ddx; + mapx += stepx; + side = 0; + } else { + sidey += ddy; + mapy += stepy; + side = 1; + } + cell = (mapx >= 0 && mapx < mw && mapy >= 0 && mapy < mh) ? map[mapy * mw + mapx] : 1; + if (cell) { + break; + } + } + int32_t perp = (side == 0) ? (sidex - ddx) : (sidey - ddy); // perpWallDist, 16.16 + if (perp < 655) { + perp = 655; // ~0.01 in 16.16 + } + int lh = (int)(((int32_t)sh << 16) / perp); // sh / perpWallDist (px); 32-bit (sh<<16 <= ~15.7M) + int t = half - (lh >> 1); + int b = t + lh; + if (t < 0) { + t = 0; + } + if (b > sh) { + b = sh; + } + top[c] = (uint16_t)t; + bot[c] = (uint16_t)b; + int ct = (cell < wc_types) ? cell : 1; // unknown type -> type 1 (matches Python default) + col[c] = wc[ct * 2 + side]; + dist_out[c] = perp; + rdx += srx; // accumulate ray direction for the next column (no overflow) + rdy += sry; + } + if (r0 && ncols > 0) { + // post-pass RLE over the just-written (cache-hot) column arrays: one flush point + int nr = 0; + int rstart = 0; + for (int c = 1; c <= ncols; c++) { + if (c == ncols || top[c] != top[rstart] || bot[c] != bot[rstart] || col[c] != col[rstart]) { + r0[nr] = (uint16_t)(rstart * stride); + r1[nr] = (uint16_t)(c * stride); + rt[nr] = top[rstart]; + rb[nr] = bot[rstart]; + rcol[nr] = col[rstart]; + nr++; + rstart = c; + } + } + return MP_OBJ_NEW_SMALL_INT(nr); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_raycast_obj, 17, 18, picogame_raycast); + +// road_edges(rl, rr, hw, n, cx0, dist, cfg) - one racing-road frame's curve accumulator + integer +// edges in one call (the OutRun-genre compute_road loop; core + cfg layout documented in +// shared-module). rl/rr = int16 out, hw = int32 Q16 half-widths, cx0 = Q16 screen centre +// (incl. lateral), dist = integer world distance, cfg = int32[7]. +static mp_obj_t picogame_road_edges_fn(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t rli, rri, hwi, cfgi; + mp_get_buffer_raise(args[0], &rli, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[1], &rri, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[2], &hwi, MP_BUFFER_READ); + mp_get_buffer_raise(args[6], &cfgi, MP_BUFFER_READ); + int n = mp_obj_get_int(args[3]); + int cap = (int)(rli.len < rri.len ? rli.len : rri.len) / 2; + if (n > cap) { + n = cap; + } + if (n > (int)(hwi.len / 4)) { + n = (int)(hwi.len / 4); + } + if (n <= 0 || cfgi.len < 7 * 4) { + return mp_const_none; + } + picogame_road_edges((int16_t *)rli.buf, (int16_t *)rri.buf, (const int32_t *)hwi.buf, n, + mp_obj_get_int(args[4]), mp_obj_get_int(args[5]), (const int32_t *)cfgi.buf); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_road_edges_obj, 7, 7, picogame_road_edges_fn); + +// project(cam, pts, n, out_sx, out_sy) - batch perspective projection of `n` 3D points to screen. +// cam = 15 camera params: ex,ey,ez, rx,rz, ux,uy,uz, fx,fy,fz, focal, cx0, cy0, near +// pts = n*3 world coords (x,y,z per point) +// out_sx/out_sy = int16 screen coords; a point behind the near plane gets sentinel -32768 +// On an FPU board (CIRCUITPY_PICOGAME_FPU) cam/pts are float32; else they are 16.16 fixed int32. +// This is the shared hot path for blocky pseudo-3D (project the 8 corners of each box, then fill). +static mp_obj_t picogame_project(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t ci, pi, xi, yi; + mp_get_buffer_raise(args[0], &ci, MP_BUFFER_READ); + mp_get_buffer_raise(args[1], &pi, MP_BUFFER_READ); + int n = mp_obj_get_int(args[2]); + mp_get_buffer_raise(args[3], &xi, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[4], &yi, MP_BUFFER_WRITE); + int16_t *osx = xi.buf; + int16_t *osy = yi.buf; + if (n > (int)(xi.len >> 1)) { + n = (int)(xi.len >> 1); + } + #if CIRCUITPY_PICOGAME_FPU + const float *cam = ci.buf; + const float *pts = pi.buf; + float ex = cam[0], ey = cam[1], ez = cam[2]; + float rx = cam[3], rz = cam[4]; + float ux = cam[5], uy = cam[6], uz = cam[7]; + float fx = cam[8], fy = cam[9], fz = cam[10]; + float focal = cam[11], cx0 = cam[12], cy0 = cam[13], near = cam[14]; + for (int i = 0; i < n; i++) { + float X = pts[i * 3] - ex, Y = pts[i * 3 + 1] - ey, Z = pts[i * 3 + 2] - ez; + float cz = X * fx + Y * fy + Z * fz; + if (cz < near) { + osx[i] = -32768; + osy[i] = -32768; + continue; + } + float k = focal / cz; // hardware divide on an FPU part + osx[i] = (int16_t)(cx0 + (X * rx + Z * rz) * k); + osy[i] = (int16_t)(cy0 - (X * ux + Y * uy + Z * uz) * k); + } + #else + const int32_t *cam = ci.buf; // all values 16.16 + const int32_t *pts = pi.buf; + int32_t ex = cam[0], ey = cam[1], ez = cam[2]; + int32_t rx = cam[3], rz = cam[4]; + int32_t ux = cam[5], uy = cam[6], uz = cam[7]; + int32_t fx = cam[8], fy = cam[9], fz = cam[10]; + int32_t focal = cam[11], cx0 = cam[12], cy0 = cam[13], near = cam[14]; + // Full-precision Q16 dot products (int64 mul per term). A Q8-prescaled-basis/MULS variant was + // ~30% faster, but its error grows with |coord| (~0.2%/axis) and k = focal/cz AMPLIFIES it near + // the near plane - host-measured 23-34 px warps on close fly-bys at a file-browser world scale + // (walls visibly broke). Correctness first: Q16 keeps the worst error a few px at any cz >= near, + // for coords up to +-32k units; still ~4-5x faster than the same math in Python on the M0+. + #define FMUL(a, b) ((int32_t)(((int64_t)(a) * (b)) >> 16)) + for (int i = 0; i < n; i++) { + int32_t X = pts[i * 3] - ex, Y = pts[i * 3 + 1] - ey, Z = pts[i * 3 + 2] - ez; + int32_t cz = FMUL(X, fx) + FMUL(Y, fy) + FMUL(Z, fz); + if (cz < near) { + osx[i] = -32768; + osy[i] = -32768; + continue; + } + // focal/cz in 16.16. A 32-bit divide (focal<<8 = Q24, cz>>8 = Q8 -> Q16) is ~4x cheaper than + // an int64 divide on the M0+ (no HW divide) and the lost cz precision costs <0.02 px (host- + // measured). Needs FOCAL < ~250 (focal<<8 in uint32) and near >= 1/256 (cz>>8 nonzero). + int32_t k = (int32_t)(((uint32_t)focal << 8) / (uint32_t)(cz >> 8)); + int32_t rr = FMUL(X, rx) + FMUL(Z, rz); + int32_t uu = FMUL(X, ux) + FMUL(Y, uy) + FMUL(Z, uz); + osx[i] = (int16_t)((cx0 + FMUL(rr, k)) >> 16); + osy[i] = (int16_t)((cy0 - FMUL(uu, k)) >> 16); + } +#undef FMUL + #endif + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_project_obj, 5, 5, picogame_project); + +//| def invert(display: busdisplay.BusDisplay, on: bool) -> None: +//| """Toggle the panel's hardware colour inversion (INVON/INVOFF). Instant and sends NO +//| pixel data, so a brief invert is a FREE full-screen flash (a 1-bit negative 'hit' look) +//| - cheaper than a Fade overlay. ST7789/ST7735 support it.""" +//| ... +//| +//| +static mp_obj_t picogame_invert(mp_obj_t display_in, mp_obj_t on_in) { + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + // A Framebuffer target (RP2350 DVI, the WASM playground) has no hardware INVON/INVOFF - + // emulate the flash by XORing the composite (mirrors the Scene/render Framebuffer handling). + if (mp_obj_is_type(display_in, &picogame_framebuffer_type)) { + picogame_fb_set_invert(mp_obj_is_true(on_in)); + return mp_const_none; + } + #endif + picogame_set_invert(pg_get_display(display_in), mp_obj_is_true(on_in)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_invert_obj, picogame_invert); + +//| def render( +//| display: busdisplay.BusDisplay, +//| sprites: List[Sprite], +//| buffer: WriteableBuffer, +//| x0: int, +//| y0: int, +//| x1: int, +//| y1: int, +//| *, +//| background: int = 0, +//| ) -> None: +//| """Render ``sprites`` into the screen region [x0,x1) x [y0,y1) and push it +//| to ``display``. ``buffer`` is a reusable strip buffer (>= region_width*2 bytes).""" +//| ... +//| +//| + +// Map a layer object to its PICOGAME_KIND_*, or raise the one shared TypeError. Both +// Scene.add() and pg.render() classify through here (one type chain, one message). +uint8_t picogame_kind_of(mp_obj_t o) { + if (mp_obj_is_type(o, &picogame_sprite_type)) { + return PICOGAME_KIND_SPRITE; + } + if (mp_obj_is_type(o, &picogame_stripdraw_type)) { + return PICOGAME_KIND_STRIPDRAW; + } + if (mp_obj_is_type(o, &picogame_tilemap_type)) { + return PICOGAME_KIND_TILEMAP; + } + if (mp_obj_is_type(o, &picogame_particles_type)) { + return PICOGAME_KIND_PARTICLES; + } + if (mp_obj_is_type(o, &picogame_canvas_type)) { + return PICOGAME_KIND_CANVAS; + } + if (mp_obj_is_type(o, &picogame_triangles_type)) { + return PICOGAME_KIND_TRIANGLES; + } + mp_raise_TypeError(MP_ERROR_TEXT("expected a Sprite, Tilemap, Particles, Canvas, StripDraw or Triangles")); +} + +static mp_obj_t picogame_render_fun(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_display, ARG_sprites, ARG_buffer, ARG_x0, ARG_y0, ARG_x1, ARG_y1, ARG_background }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_display, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_sprites, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x0, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y0, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_x1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y1, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_background, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // Accept a picogame.Framebuffer (RAM scanout buffer) as the target too, when built + // in: immediate render composites straight into it (no strip buffer, no bus), so + // pg.render(board.DISPLAY, ...) works when board.DISPLAY is a Framebuffer - the HUD / + // HudBar / immediate-mode path on scanout-buffer platforms. Mirrors the Scene change. + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + picogame_framebuffer_obj_t *fbt = + mp_obj_is_type(args[ARG_display].u_obj, &picogame_framebuffer_type) + ? MP_OBJ_TO_PTR(args[ARG_display].u_obj) : NULL; + busdisplay_busdisplay_obj_t *display = fbt ? NULL : pg_get_display(args[ARG_display].u_obj); + #else + busdisplay_busdisplay_obj_t *display = pg_get_display(args[ARG_display].u_obj); + #endif + + size_t n = 0; + mp_obj_t *items; + mp_obj_get_array(args[ARG_sprites].u_obj, &n, &items); + + // Classify items into layer kinds. All-Sprite lists stay on the NULL-kinds fast path (no alloc - + // the common case). Any non-Sprite layer (StripDraw/Canvas/Tilemap/Particles) builds a small kinds + // array so immediate render uses the SAME multi-layer blitter the Scene does - e.g. a StripDraw + // composited straight into the strip with `view.text()` = 0-RAM immediate HUD / text screen. + uint8_t kbuf[16]; + uint8_t *kinds = NULL; + for (size_t i = 0; i < n; i++) { + if (!mp_obj_is_type(items[i], &picogame_sprite_type)) { + kinds = (n <= MP_ARRAY_SIZE(kbuf)) ? kbuf : m_new(uint8_t, n); + break; + } + } + if (kinds != NULL) { + for (size_t i = 0; i < n; i++) { + // (an unknown type raises from kind_of; the GC reclaims a heap `kinds`) + kinds[i] = picogame_kind_of(items[i]); + } + } + + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + if (fbt != NULL) { + // Framebuffer target: composite the region straight into it (no strip buffer, no + // bus). Same compositor as the SPI path; re-raise a latched StripDraw exception. + mp_obj_t exc = picogame_render_framebuffer(fbt->fb, fbt->width, fbt->height, fbt->fmt, + fbt->scratch, fbt->scratch_rows, + items, kinds, n, + args[ARG_x0].u_int, args[ARG_y0].u_int, args[ARG_x1].u_int, args[ARG_y1].u_int, + args[ARG_background].u_int, 0, 0); + if (kinds != NULL && n > MP_ARRAY_SIZE(kbuf)) { + m_del(uint8_t, kinds, n); + } + if (exc != MP_OBJ_NULL) { + nlr_raise(MP_OBJ_TO_PTR(exc)); + } + return mp_const_none; + } + #endif + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bufinfo, MP_BUFFER_WRITE); + + if (kinds == NULL) { + picogame_render(display, items, n, + (uint16_t *)bufinfo.buf, bufinfo.len / 2, + args[ARG_x0].u_int, args[ARG_y0].u_int, args[ARG_x1].u_int, args[ARG_y1].u_int, + args[ARG_background].u_int); + } else { + picogame_render_region(display, items, kinds, n, + (uint16_t *)bufinfo.buf, bufinfo.len / 2, + args[ARG_x0].u_int, args[ARG_y0].u_int, args[ARG_x1].u_int, args[ARG_y1].u_int, + args[ARG_background].u_int, 0, 0); + if (n > MP_ARRAY_SIZE(kbuf)) { + m_del(uint8_t, kinds, n); + } + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_render_obj, 7, picogame_render_fun); + +//| def collide( +//| x1: int, y1: int, x2: int, y2: int, ax1: int, ay1: int, ax2: int = ..., ay2: int = ... +//| ) -> bool: +//| """AABB overlap test with INCLUSIVE bounds - both corners are part of the box, so two +//| boxes collide the moment they TOUCH (no visible overlap, no gap). Pass sprite hitboxes +//| as (x, y, x+w, y+h): collision fires on contact, the usual game feel. With 8 args: box +//| (x1,y1,x2,y2) vs box (ax1,ay1,ax2,ay2). With 6 args: box vs point (ax1, ay1). +//| NOTE: this is intentionally inclusive, unlike render's half-open [x0,x1) pixel ranges - +//| render is about pixels, collide is about game hitboxes (touch = hit).""" +//| ... +//| +//| +static mp_obj_t picogame_collide(size_t n_args, const mp_obj_t *args) { + int x1 = mp_obj_get_int(args[0]); + int y1 = mp_obj_get_int(args[1]); + int x2 = mp_obj_get_int(args[2]); + int y2 = mp_obj_get_int(args[3]); + bool hit; + if (n_args == 8) { + int bx1 = mp_obj_get_int(args[4]); + int by1 = mp_obj_get_int(args[5]); + int bx2 = mp_obj_get_int(args[6]); + int by2 = mp_obj_get_int(args[7]); + hit = (x1 <= bx2) && (x2 >= bx1) && (y1 <= by2) && (y2 >= by1); + } else if (n_args == 6) { + int px = mp_obj_get_int(args[4]); + int py = mp_obj_get_int(args[5]); + hit = (px >= x1) && (px <= x2) && (py >= y1) && (py <= y2); + } else { + mp_raise_TypeError(MP_ERROR_TEXT("argument num/types mismatch")); + } + return mp_obj_new_bool(hit); +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_collide_obj, 6, 8, picogame_collide); + +// ---- procedural value-noise in C (the desktop simulator sim/picogame.py mirrors it) ---- +// The CANONICAL implementation is FIXED-POINT (Q16.16 coords, Q0.16 values), exposed +// under the plain names value2d/value1d/fbm2d/fbm1d (see further down). It benchmarked +// ~1.8x faster than float on-device (0.649 s vs 1.186 s / 5000 fbm2d), so the float +// version was retired (2026-06-18) to free flash for future engine features. +// The float reference is preserved but DISABLED in the `#if 0` below (cf. PicoLibSDK's +// own Noise2D, which is likewise float) - revive by flipping it to `#if 1` and pointing +// the module table at the *_obj names instead of the *_fx_obj ones. +#if 0 // float reference implementation - superseded by the fixed-point path below +static inline float pg_nhash(int32_t x, int32_t y, int32_t seed) { + uint32_t h = (uint32_t)x * 374761393u + (uint32_t)y * 668265263u + (uint32_t)seed * 362437u; + h = (h ^ (h >> 13)) * 1274126177u; + h = h ^ (h >> 16); + return (float)(h & 0xFFFFu) / 65535.0f; +} +static inline float pg_nsmooth(float t) { + return t * t * (3.0f - 2.0f * t); +} +static inline int32_t pg_ifloor(float x) { + int32_t i = (int32_t)x; + return (x < (float)i) ? i - 1 : i; +} +static float pg_value2d(float x, float y, int32_t seed) { + int32_t xi = pg_ifloor(x), yi = pg_ifloor(y); + float xf = x - (float)xi, yf = y - (float)yi; + float a = pg_nhash(xi, yi, seed), b = pg_nhash(xi + 1, yi, seed); + float c = pg_nhash(xi, yi + 1, seed), d = pg_nhash(xi + 1, yi + 1, seed); + float u = pg_nsmooth(xf), v = pg_nsmooth(yf); + return (a * (1.0f - u) + b * u) * (1.0f - v) + (c * (1.0f - u) + d * u) * v; +} +static float pg_value1d(float x, int32_t seed) { + int32_t xi = pg_ifloor(x); + float xf = x - (float)xi; + float a = pg_nhash(xi, 0, seed), b = pg_nhash(xi + 1, 0, seed); + return a + (b - a) * pg_nsmooth(xf); +} + +//| def value2d(x: float, y: float, *, seed: int = 0) -> float: +//| """Smooth 2-D value noise in 0..1 (fast C).""" +//| ... +//| +//| +static mp_obj_t picogame_value2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_seed, MP_ARG_INT, {.u_int = 0}} }; + mp_arg_val_t a[3]; + mp_arg_parse_all(n_args, pos, kw, 3, spec, a); + return mp_obj_new_float(pg_value2d(mp_obj_get_float(a[0].u_obj), mp_obj_get_float(a[1].u_obj), a[2].u_int)); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value2d_obj, 2, picogame_value2d); + +//| def value1d(x: float, *, seed: int = 0) -> float: ... +static mp_obj_t picogame_value1d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_seed, MP_ARG_INT, {.u_int = 0}} }; + mp_arg_val_t a[2]; + mp_arg_parse_all(n_args, pos, kw, 2, spec, a); + return mp_obj_new_float(pg_value1d(mp_obj_get_float(a[0].u_obj), a[1].u_int)); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value1d_obj, 1, picogame_value1d); +#endif // float value2d / value1d + +// Shared arg spec for both fbm2d (disabled float) and fbm2d_fx (active fixed-point). +static const mp_arg_t pg_fbm2d_args[] = { + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_octaves, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 4} }, + { MP_QSTR_seed, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, + { MP_QSTR_lacunarity, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, + { MP_QSTR_gain, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL} }, +}; + +#if 0 // float reference fbm - superseded by the fixed-point path below +//| def fbm2d(x, y, *, octaves=4, seed=0, lacunarity=2.0, gain=0.5) -> float: ... +static mp_obj_t picogame_fbm2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + mp_arg_val_t a[6]; + mp_arg_parse_all(n_args, pos, kw, 6, pg_fbm2d_args, a); + float x = mp_obj_get_float(a[0].u_obj), y = mp_obj_get_float(a[1].u_obj); + int octaves = a[2].u_int; + int32_t seed = a[3].u_int; + float lac = (a[4].u_obj == MP_OBJ_NULL) ? 2.0f : mp_obj_get_float(a[4].u_obj); + float gain = (a[5].u_obj == MP_OBJ_NULL) ? 0.5f : mp_obj_get_float(a[5].u_obj); + float total = 0.0f, amp = 1.0f, freq = 1.0f, norm = 0.0f; + for (int i = 0; i < octaves; i++) { + total += amp * pg_value2d(x * freq, y * freq, seed); + norm += amp; + amp *= gain; + freq *= lac; + } + return mp_obj_new_float(norm > 0.0f ? total / norm : 0.0f); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm2d_obj, 2, picogame_fbm2d); + +//| def fbm1d(x, *, octaves=4, seed=0, lacunarity=2.0, gain=0.5) -> float: ... +//| +//| +static mp_obj_t picogame_fbm1d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_octaves, MP_ARG_INT, {.u_int = 4}}, {MP_QSTR_seed, MP_ARG_INT, {.u_int = 0}}, + {MP_QSTR_lacunarity, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_gain, MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}} }; + mp_arg_val_t a[5]; + mp_arg_parse_all(n_args, pos, kw, 5, spec, a); + float x = mp_obj_get_float(a[0].u_obj); + int octaves = a[1].u_int; + int32_t seed = a[2].u_int; + float lac = (a[3].u_obj == MP_OBJ_NULL) ? 2.0f : mp_obj_get_float(a[3].u_obj); + float gain = (a[4].u_obj == MP_OBJ_NULL) ? 0.5f : mp_obj_get_float(a[4].u_obj); + float total = 0.0f, amp = 1.0f, freq = 1.0f, norm = 0.0f; + for (int i = 0; i < octaves; i++) { + total += amp * pg_value1d(x * freq, seed); + norm += amp; + amp *= gain; + freq *= lac; + } + return mp_obj_new_float(norm > 0.0f ? total / norm : 0.0f); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm1d_obj, 1, picogame_fbm1d); +#endif // float fbm2d / fbm1d + +// ---- fixed-point (Q16.16 coords, Q0.16 values) noise: the CANONICAL value-noise impl, +// exposed under the plain names value2d/value1d/fbm2d/fbm1d. The inner math is integer +// (float only at the Python boundary); ~1.8x faster than the retired float path. ---- +static inline uint32_t pg_nhash_raw(int32_t x, int32_t y, int32_t seed) { + uint32_t h = (uint32_t)x * 374761393u + (uint32_t)y * 668265263u + (uint32_t)seed * 362437u; + h = (h ^ (h >> 13)) * 1274126177u; + return (h ^ (h >> 16)) & 0xFFFFu; // Q0.16 in [0,1) +} +static inline uint32_t pg_smooth16(uint32_t t) { // t,result Q0.16: t*t*(3-2t) + uint32_t t2 = (t * t) >> 16; + uint32_t e = (3u << 16) - 2u * t; + return (uint32_t)(((uint64_t)t2 * e) >> 16); +} +static inline uint32_t pg_lerp16(uint32_t a, uint32_t b, uint32_t u) { + return (uint32_t)((int32_t)a + (int32_t)(((int64_t)((int32_t)b - (int32_t)a) * (int32_t)u) >> 16)); +} +static uint32_t pg_value2d_fx(int32_t X, int32_t Y, int32_t seed) { // X,Y Q16.16 -> Q0.16 + int32_t xi = X >> 16, yi = Y >> 16; + uint32_t xf = (uint32_t)(X - (xi << 16)), yf = (uint32_t)(Y - (yi << 16)); + uint32_t a = pg_nhash_raw(xi, yi, seed), b = pg_nhash_raw(xi + 1, yi, seed); + uint32_t c = pg_nhash_raw(xi, yi + 1, seed), d = pg_nhash_raw(xi + 1, yi + 1, seed); + uint32_t u = pg_smooth16(xf), v = pg_smooth16(yf); + return pg_lerp16(pg_lerp16(a, b, u), pg_lerp16(c, d, u), v); +} +// (1-D value noise == the 2-D sampler at Y=0, bit for bit: v = smooth16(0) = 0 makes the +// outer lerp return its first argument, which is exactly lerp(hash(xi,0), hash(xi+1,0), u). +// So the 1-D entry points below just call pg_value2d_fx(X, 0, seed) - no separate kernel.) +#define PG_Q16(f) ((int32_t)((f) * 65536.0f)) + +static mp_obj_t picogame_value2d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_seed, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0}} }; + mp_arg_val_t a[3]; + mp_arg_parse_all(n_args, pos, kw, 3, spec, a); + int32_t v = pg_value2d_fx(PG_Q16(mp_obj_get_float(a[0].u_obj)), PG_Q16(mp_obj_get_float(a[1].u_obj)), a[2].u_int); + return mp_obj_new_float((float)v * (1.0f / 65536.0f)); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value2d_fx_obj, 2, picogame_value2d_fx); + +static mp_obj_t picogame_value1d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_seed, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0}} }; + mp_arg_val_t a[2]; + mp_arg_parse_all(n_args, pos, kw, 2, spec, a); + int32_t v = pg_value2d_fx(PG_Q16(mp_obj_get_float(a[0].u_obj)), 0, a[1].u_int); + return mp_obj_new_float((float)v * (1.0f / 65536.0f)); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value1d_fx_obj, 1, picogame_value1d_fx); + +// Shared fBm octave accumulator (the 1-D entry passes Y=0; sy is then 0 every octave, +// which the value sampler maps to the exact 1-D lattice - see the note above). +static mp_obj_t pg_fbm_eval(int32_t X, int32_t Y, int octaves, int32_t seed, + const mp_arg_val_t *lac, const mp_arg_val_t *gain) { + int32_t lacq = (lac->u_obj == MP_OBJ_NULL) ? (2 << 16) : PG_Q16(mp_obj_get_float(lac->u_obj)); + int32_t gainq = (gain->u_obj == MP_OBJ_NULL) ? (1 << 15) : PG_Q16(mp_obj_get_float(gain->u_obj)); + int32_t amp = 1 << 16, freq = 1 << 16; + int64_t total = 0, norm = 0; + for (int i = 0; i < octaves; i++) { + int32_t sx = (int32_t)(((int64_t)X * freq) >> 16), sy = (int32_t)(((int64_t)Y * freq) >> 16); + total += ((int64_t)amp * pg_value2d_fx(sx, sy, seed)) >> 16; + norm += amp; + amp = (int32_t)(((int64_t)amp * gainq) >> 16); + freq = (int32_t)(((int64_t)freq * lacq) >> 16); + } + return mp_obj_new_float(norm ? (float)total / (float)norm : 0.0f); +} + +static mp_obj_t picogame_fbm2d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + mp_arg_val_t a[6]; + mp_arg_parse_all(n_args, pos, kw, 6, pg_fbm2d_args, a); + return pg_fbm_eval(PG_Q16(mp_obj_get_float(a[0].u_obj)), PG_Q16(mp_obj_get_float(a[1].u_obj)), + a[2].u_int, a[3].u_int, &a[4], &a[5]); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm2d_fx_obj, 2, picogame_fbm2d_fx); + +static mp_obj_t picogame_fbm1d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { + static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, + {MP_QSTR_octaves, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 4}}, {MP_QSTR_seed, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0}}, + {MP_QSTR_lacunarity, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_gain, MP_ARG_OBJ | MP_ARG_KW_ONLY, {.u_obj = MP_OBJ_NULL}} }; + mp_arg_val_t a[5]; + mp_arg_parse_all(n_args, pos, kw, 5, spec, a); + return pg_fbm_eval(PG_Q16(mp_obj_get_float(a[0].u_obj)), 0, + a[1].u_int, a[2].u_int, &a[3], &a[4]); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm1d_fx_obj, 1, picogame_fbm1d_fx); + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// --------------------------------------------------------------------------- +// Framebuffer (a RAM render target used in place of a BusDisplay; scanout-buffer +// platforms - WASM playground, desktop sim, FruitJam DVI/HSTX) +// --------------------------------------------------------------------------- +//| class Framebuffer: +//| """A RAM framebuffer render target that a Scene or :py:func:`render` can draw +//| into instead of a BusDisplay. ``buffer`` must be a writable buffer of at least +//| ``width*height*2`` bytes (``width*height`` for ``rgb332=True``); the caller owns it +//| (a ``bytearray`` in the browser, the DVI scanout buffer on FruitJam). By default the +//| pixels are wire-order RGB565 (the engine's internal format); ``native_rgb565=True`` +//| byte-swaps each finished region to NATIVE RGB565 - the format 16-bit picodvi / +//| canvas scanout targets expect; ``rgb332=True`` quantizes each finished region to +//| RGB332 bytes - the format of 8-bit picodvi scanout (FruitJam 640x480, which the +//| hardware only offers at 8bpp). Assets, palettes and ``rgb565()`` stay wire-order +//| RGB565 throughout regardless of the output format.""" +//| +//| def __init__( +//| self, +//| buffer: WriteableBuffer, +//| width: int, +//| height: int, +//| *, +//| native_rgb565: bool = False, +//| rgb332: bool = False, +//| ) -> None: ... +//| +//| +// Static SRAM compose strip (see the scratch comment in make_new). 640*16*2 = 20 KB .bss, +// only on CIRCUITPY_PICOGAME_FRAMEBUFFER builds (fb boards have the SRAM to spare). +#define PICOGAME_FB_SCRATCH_MAX_W 640 +static uint16_t picogame_fb_scratch_sram[PICOGAME_FB_SCRATCH_MAX_W * PICOGAME_FB_SCRATCH_H]; + +static mp_obj_t picogame_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_buffer, ARG_width, ARG_height, ARG_native_rgb565, ARG_rgb332 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_native_rgb565, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_rgb332, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_int_t width = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 4096, MP_QSTR_width); + mp_int_t height = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 4096, MP_QSTR_height); + if (args[ARG_native_rgb565].u_bool && args[ARG_rgb332].u_bool) { + mp_arg_error_invalid(MP_QSTR_format); // native_rgb565 and rgb332 are exclusive + } + bool rgb332 = args[ARG_rgb332].u_bool; + + mp_buffer_info_t bi; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bi, MP_BUFFER_WRITE); + uint64_t need = (uint64_t)width * (uint64_t)height * (rgb332 ? 1u : 2u); + if ((uint64_t)bi.len < need) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + + picogame_framebuffer_obj_t *self = mp_obj_malloc(picogame_framebuffer_obj_t, type); + self->buffer = args[ARG_buffer].u_obj; + self->fb = (uint16_t *)bi.buf; + self->width = width; + self->height = height; + self->fmt = rgb332 ? PICOGAME_FB_RGB332 + : (args[ARG_native_rgb565].u_bool ? PICOGAME_FB_NATIVE565 : PICOGAME_FB_WIRE565); + // A LIVE scanout buffer (picodvi/HDMI) is read continuously, so picogame_render_framebuffer + // composes each band into this PRIVATE strip and only memcpys the FINISHED band into the fb. + // That serves BOTH targets: (a) native -> also byte-swap the strip so the fb never holds wire + // (no pink); (b) wire -> no swap, but the off-screen compose still stops the beam from sampling + // a half-composited region (background filled, sprite not yet drawn) = no sprite/HUD flicker. + // Always allocated for the FB target; the WASM/sim path (read out after present, not live) just + // pays a small strip + one memcpy. See PICOGAME_FB_SCRATCH_H. + // + // The scratch must be FAST memory: on a PSRAM-heap board (Fruit Jam) a heap bytearray + // lands in external PSRAM and every compose write pays QSPI latency (measured 8.7 vs + // 64+ MB/s SRAM; a full-res StripDraw frame ballooned refresh to ~30-38 ms). One static + // SRAM strip serves every Framebuffer (compose is synchronous) up to 640 px wide; wider + // targets fall back to the heap. + self->scratch_buf = mp_const_none; + self->scratch = NULL; + self->scratch_rows = 0; + { + int rows = PICOGAME_FB_SCRATCH_H; + if (rows > height) { + rows = height; + } + if (width <= PICOGAME_FB_SCRATCH_MAX_W) { + self->scratch = picogame_fb_scratch_sram; + } else { + mp_obj_t sb = mp_obj_new_bytearray_of_zeros((size_t)width * (size_t)rows * 2u); + mp_buffer_info_t sbi; + mp_get_buffer_raise(sb, &sbi, MP_BUFFER_WRITE); + self->scratch_buf = sb; + self->scratch = (uint16_t *)sbi.buf; + } + self->scratch_rows = rows; + } + return MP_OBJ_FROM_PTR(self); +} + +static mp_obj_t picogame_framebuffer_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_framebuffer_obj_t *)MP_OBJ_TO_PTR(self_in))->width); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_framebuffer_get_width_obj, picogame_framebuffer_get_width); +MP_PROPERTY_GETTER(picogame_framebuffer_width_obj, (mp_obj_t)&picogame_framebuffer_get_width_obj); + +static mp_obj_t picogame_framebuffer_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_framebuffer_obj_t *)MP_OBJ_TO_PTR(self_in))->height); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_framebuffer_get_height_obj, picogame_framebuffer_get_height); +MP_PROPERTY_GETTER(picogame_framebuffer_height_obj, (mp_obj_t)&picogame_framebuffer_get_height_obj); + +static const mp_rom_map_elem_t picogame_framebuffer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&picogame_framebuffer_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&picogame_framebuffer_height_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_framebuffer_locals_dict, picogame_framebuffer_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_framebuffer_type, + MP_QSTR_Framebuffer, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_framebuffer_make_new, + locals_dict, &picogame_framebuffer_locals_dict + ); +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER + +static const mp_rom_map_elem_t picogame_module_globals_table[] = { + { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picogame) }, + { MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&picogame_bitmap_type) }, + { MP_ROM_QSTR(MP_QSTR_Sprite), MP_ROM_PTR(&picogame_sprite_type) }, + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&picogame_display_type) }, + #endif + { MP_ROM_QSTR(MP_QSTR_Scene), MP_ROM_PTR(&picogame_scene_type) }, + { MP_ROM_QSTR(MP_QSTR_Tilemap), MP_ROM_PTR(&picogame_tilemap_type) }, + { MP_ROM_QSTR(MP_QSTR_Particles), MP_ROM_PTR(&picogame_particles_type) }, + { MP_ROM_QSTR(MP_QSTR_Canvas), MP_ROM_PTR(&picogame_canvas_type) }, + { MP_ROM_QSTR(MP_QSTR_StripDraw), MP_ROM_PTR(&picogame_stripdraw_type) }, + { MP_ROM_QSTR(MP_QSTR_Triangles), MP_ROM_PTR(&picogame_triangles_type) }, + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + { MP_ROM_QSTR(MP_QSTR_Framebuffer), MP_ROM_PTR(&picogame_framebuffer_type) }, + #endif + { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&picogame_render_obj) }, + { MP_ROM_QSTR(MP_QSTR_raycast), MP_ROM_PTR(&picogame_raycast_obj) }, + { MP_ROM_QSTR(MP_QSTR_road_edges), MP_ROM_PTR(&picogame_road_edges_obj) }, + { MP_ROM_QSTR(MP_QSTR_project), MP_ROM_PTR(&picogame_project_obj) }, + // True when the pseudo-3D/math primitives use the hardware-float path (FPU board). Python packs + // camera/point buffers as float32 when this is set, else as 16.16 fixed int32. + { MP_ROM_QSTR(MP_QSTR_FPU), MP_ROM_INT(CIRCUITPY_PICOGAME_FPU) }, + { MP_ROM_QSTR(MP_QSTR_invert), MP_ROM_PTR(&picogame_invert_obj) }, + { MP_ROM_QSTR(MP_QSTR_collide), MP_ROM_PTR(&picogame_collide_obj) }, + // Canonical noise = the fixed-point implementation (float retired; see `#if 0` above). + { MP_ROM_QSTR(MP_QSTR_value2d), MP_ROM_PTR(&picogame_value2d_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_value1d), MP_ROM_PTR(&picogame_value1d_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_fbm2d), MP_ROM_PTR(&picogame_fbm2d_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_fbm1d), MP_ROM_PTR(&picogame_fbm1d_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_rgb565), MP_ROM_PTR(&picogame_rgb565_obj) }, + { MP_ROM_QSTR(MP_QSTR_RGB565), MP_ROM_INT(PICOGAME_FMT_RGB565) }, + { MP_ROM_QSTR(MP_QSTR_PAL8), MP_ROM_INT(PICOGAME_FMT_PAL8) }, + // Engine API level: bump by 1 whenever the PYTHON-VISIBLE surface grows (new method/property/ + // module function/constant), so picogame-libs can diagnose a too-old firmware up front + // ("needs API_LEVEL >= N") instead of failing later with a random missing attribute. + // Level 1 = the 2026-07 surface (post API-freeze + Canvas.text/Framebuffer/StripDraw + // always_dirty). Older firmwares have no attribute at all -> getattr(pg, "API_LEVEL", 0). + { MP_ROM_QSTR(MP_QSTR_API_LEVEL), MP_ROM_INT(1) }, + // Build-time capability flag: does THIS board's panel controller support 12-bit RGB444 + // (COLMOD)? The board declares it (it knows its controller); a game reads it to enable + // Display(rgb444=...) only where it works - one codebase runs on ST7789 AND ILI9341. + #if CIRCUITPY_PICOGAME_RGB444 + { MP_ROM_QSTR(MP_QSTR_RGB444_SUPPORTED), MP_ROM_TRUE }, + #else + { MP_ROM_QSTR(MP_QSTR_RGB444_SUPPORTED), MP_ROM_FALSE }, + #endif + // Build-time default render-strip height (rows). picogame_game.setup() uses it when strip_h is + // None; games can override per call; a board can override the default in mpconfigboard.h. + // MEASURED (RP2040): with async DMA double-buffering, SMALL strips overlap render+transfer best -> + // 8 is both fastest and least RAM (the two w*strip_h*2 buffers shrink). WITHOUT the DMA backend + // there's no overlap, so a blocking send per strip makes LARGER strips win -> 24. + #ifndef PICOGAME_STRIP_H + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + #define PICOGAME_STRIP_H 8 + #else + #define PICOGAME_STRIP_H 24 + #endif + #endif + { MP_ROM_QSTR(MP_QSTR_STRIP_H), MP_ROM_INT(PICOGAME_STRIP_H) }, +}; +static MP_DEFINE_CONST_DICT(picogame_module_globals, picogame_module_globals_table); + +const mp_obj_module_t picogame_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t *)&picogame_module_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_picogame, picogame_module); diff --git a/shared-bindings/picogame/__init__.h b/shared-bindings/picogame/__init__.h new file mode 100644 index 00000000000..8b8047f44dc --- /dev/null +++ b/shared-bindings/picogame/__init__.h @@ -0,0 +1,15 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +// Defined in shared-bindings/picogame/__init__.c (consolidated with Bitmap/Sprite). +extern const mp_obj_type_t picogame_stripdraw_type; +extern const mp_obj_type_t picogame_triangles_type; + +uint8_t picogame_kind_of(mp_obj_t o); diff --git a/shared-module/picogame/Bitmap.h b/shared-module/picogame/Bitmap.h new file mode 100644 index 00000000000..887d904b203 --- /dev/null +++ b/shared-module/picogame/Bitmap.h @@ -0,0 +1,35 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame: 2D game engine for the PicoPad and similar boards. +// Bitmap = an image atlas of one or more equal-size frames, arbitrary width/height. + +#pragma once + +#include +#include +#include "py/obj.h" + +enum { + PICOGAME_FMT_RGB565 = 0, // 2 bytes/pixel, values in display wire order + PICOGAME_FMT_PAL8 = 1, // 1 byte/pixel index into palette (wire-order RGB565) +}; + +typedef struct { + mp_obj_base_t base; + mp_obj_t data_obj; // keep the source buffer alive + mp_obj_t palette_obj; // keep the palette buffer alive (MP_OBJ_NULL for RGB565) + const uint8_t *data; // pixel data + const uint16_t *palette; // wire-order RGB565 entries (PAL8), else NULL + uint16_t width, height; // size of a single frame + uint16_t stride; // atlas width in pixels (>= width * frames for a horizontal atlas) + uint16_t transparent; // transparent key: palette index (PAL8) or wire color (RGB565) + uint16_t pal_entries; // palette length in entries (PAL8; 0 for RGB565). Informational: the + // blitter does NOT clamp - indices must be < this (see PAL8 blit contract). + uint8_t format; // PICOGAME_FMT_* + uint8_t frames; + bool has_transparent; +} picogame_bitmap_obj_t; diff --git a/shared-module/picogame/Canvas.c b/shared-module/picogame/Canvas.c new file mode 100644 index 00000000000..87482192124 --- /dev/null +++ b/shared-module/picogame/Canvas.c @@ -0,0 +1,623 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include + +#include "shared-module/picogame/Canvas.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/fontio/BuiltinFont.h" +#include "shared-bindings/displayio/Bitmap.h" + +// Thin wrappers over the shared int32 accumulator (dx1,dy1,dx2,dy2 are contiguous int32 at the +// struct tail). See picogame_dirty_* in __init__.c. +void picogame_canvas_dirty_reset(picogame_canvas_obj_t *cv) { + picogame_dirty_reset(&cv->dx1); +} + +void picogame_canvas_dirty_union(picogame_canvas_obj_t *cv, int x1, int y1, int x2, int y2) { + picogame_dirty_union(&cv->dx1, x1, y1, x2, y2); +} + +bool picogame_canvas_take_dirty(picogame_canvas_obj_t *cv, int *x1, int *y1, int *x2, int *y2) { + return picogame_dirty_take(&cv->dx1, x1, y1, x2, y2); +} + +// Union a canvas-local rect (clamped to the surface) into the dirty rect (scene coords). +static void mark(picogame_canvas_obj_t *cv, int lx1, int ly1, int lx2, int ly2) { + if (lx1 < 0) { + lx1 = 0; + } + if (ly1 < 0) { + ly1 = 0; + } + if (lx2 > cv->w) { + lx2 = cv->w; + } + if (ly2 > cv->h) { + ly2 = cv->h; + } + if (lx1 >= lx2 || ly1 >= ly2) { + return; + } + picogame_dirty_union(&cv->dx1, cv->x + lx1, cv->y + ly1, cv->x + lx2, cv->y + ly2); +} + +// NOT inlined on purpose: the shape primitives call put() many times (circle = +// 8 calls/iteration). Inlining bloated them (circle was ~1.4 KB); a real call keeps +// them small. Shapes aren't the hot path (the sprite/tilemap blits don't use put). +static __attribute__((noinline)) void put(picogame_canvas_obj_t *cv, int x, int y, uint16_t c) { + if (x >= 0 && y >= 0 && x < cv->w && y < cv->h) { + cv->data[y * cv->w + x] = c; + } +} + +// Fill `n` RGB565 pixels at `p` with `color`, word-filling two pixels per store (half the writes of +// a 16-bit loop); memset for the common 0 case. Handles a leading odd (2-byte-but-not-4-byte) address +// so it stays safe on Cortex-M0+ (RP2040), which faults on an unaligned 32-bit access - a StripDraw +// view's rows into the render strip can start on an odd pixel. This is the per-frame path for +// view.clear / Sky / HUD-bar / Fade fills, so the word-fill is worth it. +static void fill565(uint16_t *p, int n, uint16_t color) { + if (n <= 0) { + return; + } + if (color == 0) { + memset(p, 0, (size_t)n * 2); + return; + } + if ((uintptr_t)p & 3) { // align to 4 bytes: one leading pixel + *p++ = color; + n--; + } + uint32_t w = (uint32_t)color | ((uint32_t)color << 16); + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + uint32_t *w32 = (uint32_t *)p; // now 4-byte aligned + #pragma GCC diagnostic pop + int nw = n >> 1; + for (int i = 0; i < nw; i++) { + w32[i] = w; + } + if (n & 1) { // trailing odd pixel + p[n - 1] = color; + } +} + +// Defined with the filled shapes below; forward-declared for picogame_canvas_road. +static void span565(picogame_canvas_obj_t *cv, int y, int xs, int xe, uint16_t color); + +void picogame_canvas_clear(picogame_canvas_obj_t *cv, uint16_t color) { + fill565(cv->data, cv->w * cv->h, color); + mark(cv, 0, 0, cv->w, cv->h); +} + +void picogame_canvas_pixel(picogame_canvas_obj_t *cv, int x, int y, uint16_t color) { + put(cv, x, y, color); + mark(cv, x, y, x + 1, y + 1); +} + +void picogame_canvas_fill_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t color) { + int x2 = x + w, y2 = y + h; + int cx1 = x < 0 ? 0 : x, cy1 = y < 0 ? 0 : y; + int cx2 = x2 > cv->w ? cv->w : x2, cy2 = y2 > cv->h ? cv->h : y2; + for (int yy = cy1; yy < cy2; yy++) { + fill565(cv->data + yy * cv->w + cx1, cx2 - cx1, color); + } + mark(cv, x, y, x2, y2); +} + +void picogame_canvas_blit(picogame_canvas_obj_t *cv, picogame_bitmap_obj_t *bm, + int x, int y, int frame, bool flip_x, bool flip_y) { + // Composite a bitmap FRAME into the canvas buffer (honours the bitmap's transparent key). + // Reuses the sprite blit path, targeting the canvas's own RGB565 surface instead of a strip. + picogame_blit_bitmap(cv->data, cv->w, cv->h, 0, 0, bm, x, y, frame, flip_x, flip_y, false, NULL); + mark(cv, x, y, x + bm->width, y + bm->height); +} + +// Number of low zero bits (log2 for a power of 2; 0 for non-pow2, caught by caller). +static int log2_pow2(unsigned v) { + int n = 0; + while ((v & 1) == 0 && v > 1) { + v >>= 1; + n++; + } + return n; +} + +// One racing-road strip, all rows in one call (the OutRun-genre "draw_road" scanline loop - profiled +// at ~20-25 ms of Python on picobike: ~4 fill_rect boundary crossings + an int(float) phase per row). +// ri0 = the road-table row of THIS surface's row 0 (vy - horizon_base); negative rows are sky. +// tab = int16[ntab][5]: {edge_w, dash_hw, wb05_q8, wb07_q8, flags(bit0 = dashes allowed)} - static per +// game. rl/rr = per-frame integer road edges (road_edges output). d05/d07 = the frame's scrolling +// stripe/dash phases in Q8; the row's band parity is ((d05+wb05)>>8)&1, matching the Python +// int(d05f + wb05f) & 1 (both non-negative). colors = uint16[6]: {sky, road_a, road_b, rumble_a, +// rumble_b, dash}. Grass underneath and the finish-line chequer stay the caller's job (one fill_rect +// per strip / a few rows near the lap line - no reason to carry them in C). +void picogame_canvas_road(picogame_canvas_obj_t *cv, int ri0, + const int16_t *tab, int ntab, const int16_t *rl, const int16_t *rr, + int32_t d05_q8, int32_t d07_q8, const uint16_t *colors) { + int w = cv->w; + for (int ly = 0; ly < cv->h; ly++) { + int ri = ri0 + ly; + if (ri < 0) { // above the horizon: sky + fill565(&cv->data[ly * w], w, colors[0]); + continue; + } + if (ri >= ntab) { + ri = ntab - 1; + } + const int16_t *t = tab + ri * 5; + int band = (int)(((d05_q8 + t[2]) >> 8) & 1); + uint16_t road = band ? colors[1] : colors[2]; + uint16_t rumble = band ? colors[3] : colors[4]; + int l = rl[ri], r = rr[ri]; + if (r <= l) { + continue; + } + span565(cv, ly, l, r - 1, road); // fill_rect(l, w=r-l) covers l..r-1 + int ew = t[0]; + span565(cv, ly, l, l + ew - 1, rumble); + span565(cv, ly, r - ew, r - 1, rumble); + if ((t[4] & 1) && (((d07_q8 + t[3]) >> 8) & 1)) { + int mid = (l + r) >> 1, dw = t[1]; + span565(cv, ly, mid - dw, mid + dw - 1, colors[5]); + } + } + mark(cv, 0, 0, w, cv->h); +} + +// Context + row walker for the mode7 loop (each row derives rowdist/steps from its own sy). +typedef struct { + picogame_canvas_obj_t *cv; + const uint8_t *data; + const uint16_t *pal; + int fmt, stride, shx, shy, mx, my, horizon, y_off; + int32_t z, rx0, ry0, rsx, rsy, cam_x, cam_y; + bool transp; + uint16_t key; +} mode7_ctx_t; + +static void mode7_rows(void *arg, int lo, int hi) { + mode7_ctx_t *c = arg; + picogame_canvas_obj_t *cv = c->cv; + int w = cv->w; + #if defined(PICOGAME_HAS_INTERP) + int ltw = 16 - c->shx; + int lth = 16 - c->shy; + bool use_interp = (c->fmt == PICOGAME_FMT_PAL8) && !c->transp && c->pal != NULL + && c->stride == c->mx + 1 + && ltw >= 1 && lth >= 1 && ltw + lth <= 16; // lane1 shift = shy-ltw must be >= 0 + #endif + for (int sy = lo; sy < hi; sy++) { + int denom = (sy + c->y_off) - c->horizon; + if (denom <= 0) { + continue; + } + // 32-bit throughout (no 64-bit mul helper on the M0+): rowdist*coeff stays + // within int32 for sane camera params - the Python helper keeps z and the + // ray deltas small; extreme values degrade to wrong pixels, never a crash. + int32_t rowdist = c->z / denom; + int32_t stepx = (rowdist * c->rsx) >> 16; + int32_t stepy = (rowdist * c->rsy) >> 16; + int32_t fx = c->cam_x + ((rowdist * c->rx0) >> 16); + int32_t fy = c->cam_y + ((rowdist * c->ry0) >> 16); + uint16_t *drow = cv->data + sy * w; + #if defined(PICOGAME_HAS_INTERP) + if (use_interp) { + picogame_mode7_row_interp(drow, w, c->data, c->pal, + (uint32_t)fx, (uint32_t)fy, stepx, stepy, c->shx, c->shy, ltw, lth); + continue; + } + #endif + for (int sx = 0; sx < w; sx++) { + int tx = (fx >> c->shx) & c->mx, ty = (fy >> c->shy) & c->my; + uint16_t val; + if (src_pixel_s(c->fmt, c->data, c->pal, c->transp, c->key, ty * c->stride + tx, &val)) { + drow[sx] = val; + } + fx += stepx; + fy += stepy; + } + } +} + +void picogame_canvas_mode7(picogame_canvas_obj_t *cv, picogame_bitmap_obj_t *tex, + int horizon, int y_off, int32_t z, int32_t rx0, int32_t ry0, int32_t rsx, int32_t rsy, + int32_t cam_x, int32_t cam_y) { + // Perspective ground plane (Mode-7 / floorcaster). For each screen row below + // `horizon`, distance = z / (row - horizon) (16.16); the texture-space coord + // of the left edge is cam + distance*ray0, stepping by distance*rayDelta per + // pixel; sample `tex` (power-of-2, so wrap = a mask, and world 1.0 = one tile + // via a shift, no multiply). Integer throughout - no FPU needed (RP2040). + if (tex == NULL) { + return; + } + int tw = tex->width, th = tex->height; + if ((tw & (tw - 1)) || (th & (th - 1))) { // require power-of-2 dims + return; + } + int shx = 16 - log2_pow2((unsigned)tw); // world(1.0) -> one full tile + int shy = 16 - log2_pow2((unsigned)th); + int mx = tw - 1, my = th - 1, stride = tex->stride; + int fmt = tex->format; + const uint8_t *data = tex->data; + const uint16_t *pal = tex->palette; + bool transp = tex->has_transparent; + uint16_t key = tex->transparent; + // sy is a row WITHIN this surface (a StripDraw view is a Canvas onto one strip); + // the absolute screen row is sy + y_off, so the horizon test uses that. y_off = 0 + // for a full-screen Canvas, = the strip's screen y for a StripDraw view (0-RAM floor). + int y0 = horizon - y_off + 1; + if (y0 < 0) { + y0 = 0; + } + mode7_ctx_t ctx = { + cv, data, pal, fmt, stride, shx, shy, mx, my, horizon, y_off, + z, rx0, ry0, rsx, rsy, cam_x, cam_y, transp, key + }; + mode7_rows(&ctx, y0, cv->h); + mark(cv, 0, y0, cv->w, cv->h); +} + +void picogame_canvas_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t color) { + picogame_canvas_fill_rect(cv, x, y, w, 1, color); + picogame_canvas_fill_rect(cv, x, y + h - 1, w, 1, color); + picogame_canvas_fill_rect(cv, x, y, 1, h, color); + picogame_canvas_fill_rect(cv, x + w - 1, y, 1, h, color); +} + +void picogame_canvas_line(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int y1, uint16_t color) { + int dx = x1 - x0, dy = y1 - y0; + int adx = dx < 0 ? -dx : dx; + int ady = dy < 0 ? -dy : dy; + int sx = dx < 0 ? -1 : 1; + int sy = dy < 0 ? -1 : 1; + int err = adx - ady; + int x = x0, y = y0; + while (true) { + put(cv, x, y, color); + if (x == x1 && y == y1) { + break; + } + int e2 = 2 * err; + if (e2 > -ady) { + err -= ady; + x += sx; + } + if (e2 < adx) { + err += adx; + y += sy; + } + } + int lx1 = x0 < x1 ? x0 : x1, ly1 = y0 < y1 ? y0 : y1; + int lx2 = (x0 > x1 ? x0 : x1) + 1, ly2 = (y0 > y1 ? y0 : y1) + 1; + mark(cv, lx1, ly1, lx2, ly2); +} + +// Clamp a row span to the surface and word-fill it (the span-pass idiom shared by the filled +// shapes; the per-pixel put() loops it replaced clipped and indexed every pixel). +static void span565(picogame_canvas_obj_t *cv, int y, int xs, int xe, uint16_t color) { + if (y < 0 || y >= cv->h) { + return; + } + if (xs < 0) { + xs = 0; + } + if (xe >= cv->w) { + xe = cv->w - 1; + } + if (xs <= xe) { + fill565(&cv->data[y * cv->w + xs], xe - xs + 1, color); + } +} + +void picogame_canvas_fill_circle(picogame_canvas_obj_t *cv, int cx, int cy, int r, uint16_t color) { + // A filled circle IS fill_ellipse(r, r) - the ellipse row condition s^2*ry2 <= rr - dy^2*rx2 + // collapses to s^2 <= r^2 - dy^2 (host-proven byte-exact over 36k cases). Same delegation the + // OUTLINE circle already does; only r == 0 needs care (the ellipse rejects rx <= 0, a zero-radius + // circle is one pixel). Flash: this replaced a ~320 B twin of the ellipse body. + if (r < 0) { + return; + } + if (r == 0) { + picogame_canvas_pixel(cv, cx, cy, color); + return; + } + picogame_canvas_fill_ellipse(cv, cx, cy, r, r, color); +} + +void picogame_canvas_circle(picogame_canvas_obj_t *cv, int cx, int cy, int r, uint16_t color) { + picogame_canvas_ellipse(cv, cx, cy, r, r, color); // a circle is an ellipse with rx == ry +} + +void picogame_canvas_ring(picogame_canvas_obj_t *cv, int cx, int cy, int r, int thick, uint16_t color) { + if (r < 0) { + return; + } + int inner = r - thick; + if (inner < 0) { + inner = 0; + } + // Mirrored rows + decremental outer/inner widths, two word-filled spans per row - see fill_circle. + int out = r, ins = inner; + for (int dy = 0; dy <= r; dy++) { + long rr = (long)r * r - (long)dy * dy; // long (like ellipse): int r*r overflows at big radii + while ((long)out * out > rr) { + out--; + } + int two_seg = dy <= inner; + if (two_seg) { + int ri = inner * inner - dy * dy; + while (ins * ins > ri) { + ins--; + } + } + for (int half = 0; half < (dy ? 2 : 1); half++) { + int y = half ? cy - dy : cy + dy; + if (two_seg) { + span565(cv, y, cx - out, cx - ins - 1, color); + span565(cv, y, cx + ins + 1, cx + out, color); + } else { + span565(cv, y, cx - out, cx + out, color); + } + } + } + mark(cv, cx - r, cy - r, cx + r + 1, cy + r + 1); +} + +void picogame_canvas_triangle(picogame_canvas_obj_t *cv, + int x0, int y0, int x1, int y1, int x2, int y2, uint16_t color) { + picogame_canvas_line(cv, x0, y0, x1, y1, color); + picogame_canvas_line(cv, x1, y1, x2, y2, color); + picogame_canvas_line(cv, x2, y2, x0, y0, color); +} + +void picogame_canvas_fill_triangle(picogame_canvas_obj_t *cv, + int x0, int y0, int x1, int y1, int x2, int y2, uint16_t color) { + int X[3] = { x0, x1, x2 }, Y[3] = { y0, y1, y2 }; + for (int i = 0; i < 2; i++) { + for (int j = i + 1; j < 3; j++) { + if (Y[j] < Y[i]) { + int t = Y[i]; + Y[i] = Y[j]; + Y[j] = t; + t = X[i]; + X[i] = X[j]; + X[j] = t; + } + } + } + // Scanline fill via 16.16 edge DDA + word-filled spans. One 64-bit divide per EDGE replaces two + // 32-bit divides per ROW (M0+ has no HW divide, ~75 cyc each; a 20-row wall paid ~40 divides), + // and each row goes through fill565 (word stores) instead of a per-pixel clipped put(). Rows and + // spans clamp to the canvas up front, so a mostly off-screen triangle costs only its visible rows + // (the old loop walked EVERY row of huge triangles and clipped per pixel - quadratic blowup). + // Edge x differs from the old divide by at most 1 px (trunc vs floor; host-verified over 100k + // triangles), and convex quads - the box faces the 3D demos draw - stay seam-hole-free. + int w = cv->w, h = cv->h; + if (Y[0] < h && Y[2] >= 0) { + int64_t sAC = (Y[2] != Y[0]) ? (((int64_t)(X[2] - X[0]) << 16) / (Y[2] - Y[0])) : 0; + int64_t sAB = (Y[1] != Y[0]) ? (((int64_t)(X[1] - X[0]) << 16) / (Y[1] - Y[0])) : 0; + int64_t sBC = (Y[2] != Y[1]) ? (((int64_t)(X[2] - X[1]) << 16) / (Y[2] - Y[1])) : 0; + uint16_t *data = cv->data; + // top half: rows [Y0, Y1) walk edges A->C and A->B + int ys = Y[0] < 0 ? 0 : Y[0]; + int ye = (Y[1] - 1) < (h - 1) ? (Y[1] - 1) : (h - 1); + int64_t accAC = ((int64_t)X[0] << 16) + sAC * (ys - Y[0]); + int64_t acc2 = ((int64_t)X[0] << 16) + sAB * (ys - Y[0]); + for (int y = ys; y <= ye; y++) { + int xac = (int)(accAC >> 16); + int xsh = (int)(acc2 >> 16); + int xs = xac < xsh ? xac : xsh, xe = xac < xsh ? xsh : xac; + if (xs < 0) { + xs = 0; + } + if (xe >= w) { + xe = w - 1; + } + if (xs <= xe) { + fill565(&data[y * w + xs], xe - xs + 1, color); + } + accAC += sAC; + acc2 += sAB; + } + // bottom half: rows [Y1, Y2] walk edges A->C and B->C (a flat bottom degenerates to sBC=0) + ys = Y[1] < 0 ? 0 : Y[1]; + ye = Y[2] < (h - 1) ? Y[2] : (h - 1); + accAC = ((int64_t)X[0] << 16) + sAC * (ys - Y[0]); + acc2 = ((int64_t)X[1] << 16) + sBC * (ys - Y[1]); + for (int y = ys; y <= ye; y++) { + int xac = (int)(accAC >> 16); + int xsh = (int)(acc2 >> 16); + int xs = xac < xsh ? xac : xsh, xe = xac < xsh ? xsh : xac; + if (xs < 0) { + xs = 0; + } + if (xe >= w) { + xe = w - 1; + } + if (xs <= xe) { + fill565(&data[y * w + xs], xe - xs + 1, color); + } + accAC += sAC; + acc2 += sBC; + } + } + int mnx = X[0] < X[1] ? X[0] : X[1]; + mnx = mnx < X[2] ? mnx : X[2]; + int mxx = X[0] > X[1] ? X[0] : X[1]; + mxx = mxx > X[2] ? mxx : X[2]; + mark(cv, mnx, Y[0], mxx + 1, Y[2] + 1); +} + +void picogame_canvas_ellipse(picogame_canvas_obj_t *cv, int cx, int cy, int rx, int ry, uint16_t color) { + if (rx <= 0 || ry <= 0) { + return; + } + // 32-bit `long`: rx2*ry2 stays in range while rx*ry <= 46340 (both radii <~210 px). That covers any + // canvas that fits in RAM on this target. A larger ellipse (only reachable on a big-RAM board with an + // oversized canvas) renders a wrong shape - never a fault, since put() clips every pixel to the canvas. + long rx2 = (long)rx * rx, ry2 = (long)ry * ry, rr = rx2 * ry2; + for (int dy = -ry; dy <= ry; dy++) { + int s = 0; + while ((long)(s + 1) * (s + 1) * ry2 + (long)dy * dy * rx2 <= rr) { + s++; + } + put(cv, cx - s, cy + dy, color); + put(cv, cx + s, cy + dy, color); + } + for (int dx = -rx; dx <= rx; dx++) { + int s = 0; + while ((long)(s + 1) * (s + 1) * rx2 + (long)dx * dx * ry2 <= rr) { + s++; + } + put(cv, cx + dx, cy - s, color); + put(cv, cx + dx, cy + s, color); + } + mark(cv, cx - rx, cy - ry, cx + rx + 1, cy + ry + 1); +} + +void picogame_canvas_fill_ellipse(picogame_canvas_obj_t *cv, int cx, int cy, int rx, int ry, uint16_t color) { + if (rx <= 0 || ry <= 0) { + return; + } + // 32-bit `long`: rx2*ry2 stays in range while rx*ry <= 46340 (both radii <~210 px). That covers any + // canvas that fits in RAM on this target. A larger ellipse (only reachable on a big-RAM board with an + // oversized canvas) renders a wrong shape - never a fault, since put() clips every pixel to the canvas. + long rx2 = (long)rx * rx, ry2 = (long)ry * ry, rr = rx2 * ry2; + // Mirrored rows + decremental width, spans word-filled - see fill_circle. + int s = rx; + for (int dy = 0; dy <= ry; dy++) { + long lim = rr - (long)dy * dy * rx2; // s*s*ry2 <= lim <=> the old (s+1)-increment bound + while ((long)s * s * ry2 > lim) { + s--; + } + span565(cv, cy + dy, cx - s, cx + s, color); + if (dy) { + span565(cv, cy - dy, cx - s, cx + s, color); + } + } + mark(cv, cx - rx, cy - ry, cx + rx + 1, cy + ry + 1); +} + +void picogame_canvas_fill_round_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, int r, uint16_t color) { + if (r > w / 2) { + r = w / 2; + } + if (r > h / 2) { + r = h / 2; + } + if (r < 0) { + r = 0; + } + picogame_canvas_fill_rect(cv, x + r, y, w - 2 * r, h, color); + picogame_canvas_fill_rect(cv, x, y + r, r, h - 2 * r, color); + picogame_canvas_fill_rect(cv, x + w - r, y + r, r, h - 2 * r, color); + picogame_canvas_fill_circle(cv, x + r, y + r, r, color); + picogame_canvas_fill_circle(cv, x + w - r - 1, y + r, r, color); + picogame_canvas_fill_circle(cv, x + r, y + h - r - 1, r, color); + picogame_canvas_fill_circle(cv, x + w - r - 1, y + h - r - 1, r, color); +} + +void picogame_canvas_frame3d(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t light, uint16_t dark) { + picogame_canvas_fill_rect(cv, x, y, w, 1, light); + picogame_canvas_fill_rect(cv, x, y, 1, h, light); + picogame_canvas_fill_rect(cv, x, y + h - 1, w, 1, dark); + picogame_canvas_fill_rect(cv, x + w - 1, y, 1, h, dark); +} + +void picogame_blit_canvas( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_canvas_obj_t *cv, int ox, int oy) { + // Reuse the bitmap blitter by viewing the canvas as a 1-frame RGB565 bitmap. + picogame_bitmap_obj_t bm; + bm.data = (const uint8_t *)cv->data; + bm.palette = NULL; + bm.width = cv->w; + bm.height = cv->h; + bm.stride = cv->w; + bm.transparent = cv->transparent; + bm.format = PICOGAME_FMT_RGB565; + bm.frames = 1; + bm.has_transparent = cv->has_transparent; + picogame_blit_bitmap(buf, region_w, strip_h, x0, strip_top, &bm, + cv->x + ox, cv->y + oy, 0, false, false, false, NULL); +} + +// Composite a string's glyphs straight into the surface in C: rasterize each glyph from the +// font's 1-bit atlas on the fly (no Python glyph cache, no per-call Bitmap/Sprite). Because the +// StripDraw `view` is a Canvas pointing at the live strip buffer, view.text() draws immediate-mode +// text into the frame with zero retained RAM - the same primitive serves retained Canvas screens. +void picogame_canvas_text(picogame_canvas_obj_t *cv, int x, int y, const char *text, + uint16_t fg, uint16_t bg, bool has_bg, const void *font) { + const fontio_builtinfont_t *f = font; + displayio_bitmap_t *sheet = (displayio_bitmap_t *)f->bitmap; + int fw = f->width, fh = f->height; + int tpr = sheet->width / fw; // glyph tiles per atlas row + int x0 = x; + // Hoist the canvas target + read the 1-bpp glyph atlas DIRECTLY (no per-pixel get_pixel/put calls). + // Clip each glyph rect to the canvas ONCE, then the inner loop is atlas-bit -> direct store. This is + // the per-frame path for StripDraw HUD text (repainted every frame), so it's worth the directness. + uint16_t *cdata = cv->data; + int cw = cv->w, ch = cv->h; + bool onebit = (sheet->bits_per_value == 1); // terminalio.FONT is 1-bpp; other fonts take the fallback + const uint8_t *sdata = (const uint8_t *)sheet->data; + int sstride_b = sheet->stride * 4; // atlas row stride in BYTES (stride counts uint32) + for (const uint8_t *p = (const uint8_t *)text; *p; p++) { + uint8_t gi = fontio_builtinfont_get_glyph_index(f, *p); + if (gi != 0xff) { // 0xff = no glyph -> blank advance + int tx = (gi % tpr) * fw, ty = (gi / tpr) * fh; + int gx0 = (x < 0) ? -x : 0; // clip the glyph rect to the canvas once + int gx1 = (x + fw > cw) ? cw - x : fw; + int gy0 = (y < 0) ? -y : 0; + int gy1 = (y + fh > ch) ? ch - y : fh; + for (int gy = gy0; gy < gy1; gy++) { + uint16_t *drow = cdata + (y + gy) * cw + x; // dst; index by gx (x+gx is in-bounds) + int sy = ty + gy; + if (onebit) { + const uint8_t *srow = sdata + (size_t)sy * sstride_b; + for (int gx = gx0; gx < gx1; gx++) { + int sx = tx + gx; + if ((srow[sx >> sheet->x_shift] >> (sheet->x_mask - (sx & sheet->x_mask))) & sheet->bitmask) { + drow[gx] = fg; + } else if (has_bg) { + drow[gx] = bg; + } + } + } else { + for (int gx = gx0; gx < gx1; gx++) { + if (common_hal_displayio_bitmap_get_pixel(sheet, tx + gx, sy)) { + drow[gx] = fg; + } else if (has_bg) { + drow[gx] = bg; + } + } + } + } + } + x += fw; + } + mark(cv, x0, y, x, y + fh); +} + +// Fill a screen-space triangle batch with per-triangle band reject - shared by the +// Canvas.fill_triangles binding and the compositor's Triangles layer (one loop, one place). +void picogame_fill_triangle_batch(picogame_canvas_obj_t *cv, const int16_t *v, + const uint16_t *col, int n, int xo, int yo) { + int cw = cv->w, ch = cv->h; + for (int i = 0; i < n; i++) { + const int16_t *p = v + i * 6; + int y0 = p[1] + yo, y1 = p[3] + yo, y2 = p[5] + yo; + if ((y0 < 0 && y1 < 0 && y2 < 0) || (y0 >= ch && y1 >= ch && y2 >= ch)) { + continue; + } + int x0 = p[0] + xo, x1 = p[2] + xo, x2 = p[4] + xo; + if ((x0 < 0 && x1 < 0 && x2 < 0) || (x0 >= cw && x1 >= cw && x2 >= cw)) { + continue; + } + picogame_canvas_fill_triangle(cv, x0, y0, x1, y1, x2, y2, col[i]); + } +} diff --git a/shared-module/picogame/Canvas.h b/shared-module/picogame/Canvas.h new file mode 100644 index 00000000000..45c73e43326 --- /dev/null +++ b/shared-module/picogame/Canvas.h @@ -0,0 +1,69 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame Canvas: a RAM RGB565 surface (any size) you draw primitives into, +// composited as a Scene layer. The general home for shapes (fill_rect, line, +// circle, pixel) - accumulates a dirty rect (scene coords) so only redrawn +// areas repaint. Colors are wire-order (picogame.rgb565). + +#pragma once + +#include +#include +#include "py/obj.h" +#include "shared-module/picogame/Bitmap.h" + +typedef struct { + mp_obj_base_t base; + uint16_t *data; // w*h wire-order RGB565 + mp_obj_t data_obj; // backing buffer kept alive (MP_OBJ_NULL if m_new'd) + uint16_t w, h; + int32_t x, y; // scene position (int32: a canvas can sit past +-32767 px in a big world) + uint16_t transparent; + bool has_transparent; + int32_t dx1, dy1, dx2, dy2; // accumulated dirty rect (scene coords; int32, see x/y) +} picogame_canvas_obj_t; + +void picogame_canvas_dirty_reset(picogame_canvas_obj_t *cv); +// Grow the dirty rect to also cover a scene-coord rect (no surface clamping). +void picogame_canvas_dirty_union(picogame_canvas_obj_t *cv, int x1, int y1, int x2, int y2); +bool picogame_canvas_take_dirty(picogame_canvas_obj_t *cv, int *x1, int *y1, int *x2, int *y2); + +void picogame_canvas_clear(picogame_canvas_obj_t *cv, uint16_t color); +void picogame_canvas_pixel(picogame_canvas_obj_t *cv, int x, int y, uint16_t color); +void picogame_canvas_fill_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t color); +void picogame_canvas_blit(picogame_canvas_obj_t *cv, picogame_bitmap_obj_t *bm, int x, int y, int frame, bool flip_x, bool flip_y); +void picogame_canvas_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t color); +void picogame_canvas_line(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int y1, uint16_t color); +void picogame_canvas_fill_circle(picogame_canvas_obj_t *cv, int cx, int cy, int r, uint16_t color); +void picogame_canvas_circle(picogame_canvas_obj_t *cv, int cx, int cy, int r, uint16_t color); +void picogame_canvas_ring(picogame_canvas_obj_t *cv, int cx, int cy, int r, int thick, uint16_t color); +void picogame_canvas_triangle(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int y1, int x2, int y2, uint16_t color); +void picogame_canvas_fill_triangle(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int y1, int x2, int y2, uint16_t color); +void picogame_canvas_ellipse(picogame_canvas_obj_t *cv, int cx, int cy, int rx, int ry, uint16_t color); +void picogame_canvas_fill_ellipse(picogame_canvas_obj_t *cv, int cx, int cy, int rx, int ry, uint16_t color); +void picogame_canvas_fill_round_rect(picogame_canvas_obj_t *cv, int x, int y, int w, int h, int r, uint16_t color); +void picogame_canvas_frame3d(picogame_canvas_obj_t *cv, int x, int y, int w, int h, uint16_t light, uint16_t dark); +void picogame_canvas_text(picogame_canvas_obj_t *cv, int x, int y, const char *text, + uint16_t fg, uint16_t bg, bool has_bg, const void *font); +// Mode-7 perspective ground plane: fill rows below `horizon` with a receding view +// of `tex` (power-of-2 dims). Args are 16.16 fixed-point (a Python helper computes +// them from camera angle/pos/fov). See picogame_canvas_mode7 for the exact math. +// One racing-road strip: per-row spans (road/rumbles/dashes/sky) from precomputed tables. +void picogame_canvas_road(picogame_canvas_obj_t *cv, int ri0, + const int16_t *tab, int ntab, const int16_t *rl, const int16_t *rr, + int32_t d05_q8, int32_t d07_q8, const uint16_t *colors); + +void picogame_canvas_mode7(picogame_canvas_obj_t *cv, picogame_bitmap_obj_t *tex, + int horizon, int y_off, int32_t z, int32_t rx0, int32_t ry0, int32_t rsx, int32_t rsy, + int32_t cam_x, int32_t cam_y); + +void picogame_blit_canvas( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_canvas_obj_t *cv, int ox, int oy); + +void picogame_fill_triangle_batch(picogame_canvas_obj_t *cv, const int16_t *v, + const uint16_t *col, int n, int xo, int yo); diff --git a/shared-module/picogame/Particles.c b/shared-module/picogame/Particles.c new file mode 100644 index 00000000000..87e6917f479 --- /dev/null +++ b/shared-module/picogame/Particles.c @@ -0,0 +1,163 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "shared-module/picogame/Particles.h" +#include "shared-module/picogame/__init__.h" + +static uint32_t s_prng = 0x1234abcdu; + +static int32_t prng_range(int32_t lo, int32_t hi) { + s_prng ^= s_prng << 13; + s_prng ^= s_prng >> 17; + s_prng ^= s_prng << 5; + if (hi <= lo) { + return lo; + } + return lo + (int32_t)(s_prng % (uint32_t)(hi - lo + 1)); +} + +static void swap_remove(picogame_particles_obj_t *ps, int i) { + int last = ps->count - 1; + ps->px[i] = ps->px[last]; + ps->py[i] = ps->py[last]; + ps->vx[i] = ps->vx[last]; + ps->vy[i] = ps->vy[last]; + ps->life[i] = ps->life[last]; + ps->life0[i] = ps->life0[last]; + ps->color[i] = ps->color[last]; + ps->count--; +} + +// Dim a wire-order RGB565 color to num/den of its brightness (per channel). +static inline uint16_t scale_wire565(uint16_t wire, int num, int den) { + uint16_t c = (uint16_t)((wire >> 8) | (wire << 8)); // wire -> native + int r = ((c >> 11) & 0x1F) * num / den; + int g = ((c >> 5) & 0x3F) * num / den; + int b = (c & 0x1F) * num / den; + uint16_t out = (uint16_t)((r << 11) | (g << 5) | b); + return (uint16_t)((out >> 8) | (out << 8)); // native -> wire +} + +void picogame_particles_emit(picogame_particles_obj_t *ps, int x, int y, + int count, int speed, int life, uint16_t color) { + int sp = speed * 256; // px/tick -> 8.8 + for (int k = 0; k < count && ps->count < ps->cap; k++) { + int i = ps->count++; + ps->px[i] = x << 8; + ps->py[i] = y << 8; + ps->vx[i] = (int16_t)prng_range(-sp, sp); + ps->vy[i] = (int16_t)prng_range(-sp, sp); + ps->life[i] = life; + ps->life0[i] = (uint16_t)(life > 0 ? life : 1); + ps->color[i] = color; + } +} + +void picogame_particles_update(picogame_particles_obj_t *ps) { + int16_t g = ps->gravity; + int x1 = 0x7fffffff, y1 = 0x7fffffff, x2 = -0x7fffffff - 1, y2 = -0x7fffffff - 1; // INT32: big-world + int sz = ps->size; + int i = 0; + while (i < ps->count) { + ps->px[i] += ps->vx[i]; + ps->py[i] += ps->vy[i]; + ps->vy[i] += g; + if (ps->life[i] == 0) { + swap_remove(ps, i); + continue; // re-process the swapped-in particle + } + ps->life[i]--; + int sx = ps->px[i] >> 8; + int sy = ps->py[i] >> 8; + if (sx < x1) { + x1 = sx; + } + if (sy < y1) { + y1 = sy; + } + if (sx + sz > x2) { + x2 = sx + sz; + } + if (sy + sz > y2) { + y2 = sy + sz; + } + i++; + } + // current-frame bbox becomes "previous" on the next take_dirty + ps->px1 = ps->cx1; + ps->py1 = ps->cy1; + ps->px2 = ps->cx2; + ps->py2 = ps->cy2; + if (ps->count > 0) { + ps->cx1 = x1; + ps->cy1 = y1; + ps->cx2 = x2; + ps->cy2 = y2; + } else { + picogame_dirty_reset(&ps->cx1); // empty -> INT32 sentinels (cx1,cy1,cx2,cy2 are contiguous) + } +} + +bool picogame_particles_take_dirty(picogame_particles_obj_t *ps, + int *x1, int *y1, int *x2, int *y2) { + int ax1 = ps->cx1 < ps->px1 ? ps->cx1 : ps->px1; + int ay1 = ps->cy1 < ps->py1 ? ps->cy1 : ps->py1; + int ax2 = ps->cx2 > ps->px2 ? ps->cx2 : ps->px2; + int ay2 = ps->cy2 > ps->py2 ? ps->cy2 : ps->py2; + // consume the previous box so a static system stops reporting dirty + ps->px1 = ps->cx1; + ps->py1 = ps->cy1; + ps->px2 = ps->cx2; + ps->py2 = ps->cy2; + if (ax1 >= ax2 || ay1 >= ay2) { + return false; + } + *x1 = ax1; + *y1 = ay1; + *x2 = ax2; + *y2 = ay2; + return true; +} + +void picogame_particles_clear(picogame_particles_obj_t *ps) { + // Move the currently-drawn region into "previous" and empty "current", so the next + // take_dirty reports the old pixels ONCE (erasing the cleared particles) then goes quiet. + ps->px1 = ps->cx1; + ps->py1 = ps->cy1; + ps->px2 = ps->cx2; + ps->py2 = ps->cy2; + picogame_dirty_reset(&ps->cx1); // empty -> INT32 sentinels (cx1,cy1,cx2,cy2 are contiguous) + ps->count = 0; +} + +void picogame_blit_particles( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_particles_obj_t *ps, int ox, int oy) { + int sz = ps->size; + int rx2 = x0 + region_w; + int ry2 = strip_top + strip_h; + for (int i = 0; i < ps->count; i++) { + int sx = (ps->px[i] >> 8) + ox; + int sy = (ps->py[i] >> 8) + oy; + int xs = picogame_imax(sx, x0); + int ys = picogame_imax(sy, strip_top); + int xe = picogame_imin(sx + sz, rx2); + int ye = picogame_imin(sy + sz, ry2); + if (xs >= xe || ys >= ye) { + continue; + } + uint16_t c = ps->color[i]; + if (ps->fade) { + c = scale_wire565(c, ps->life[i], ps->life0[i]); + } + for (int y = ys; y < ye; y++) { + uint16_t *dst = buf + (y - strip_top) * region_w + (xs - x0); + for (int x = xs; x < xe; x++) { + *dst++ = c; + } + } + } +} diff --git a/shared-module/picogame/Particles.h b/shared-module/picogame/Particles.h new file mode 100644 index 00000000000..faaf7a4989b --- /dev/null +++ b/shared-module/picogame/Particles.h @@ -0,0 +1,45 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame particle system: a pooled set of small moving dots rendered as one +// Scene layer (individual sprites would be far too heavy). Positions/velocities +// are 24.8 / 8.8 fixed-point for sub-pixel motion. Tracks a dirty rect spanning +// the previous and current frames so moving particles leave no trails. + +#pragma once + +#include +#include +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + int32_t *px, *py; // position, 24.8 fixed-point, scene coords + int16_t *vx, *vy; // velocity, 8.8 fixed-point per tick + uint16_t *life; // ticks remaining + uint16_t *life0; // life at spawn (for the fade ramp) + uint16_t *color; // wire-order RGB565 + uint16_t cap, count; + int16_t gravity; // 8.8, added to vy each tick + uint8_t size; // particle size in pixels + bool fade; // dim each particle toward black as it ages + // dirty bounding boxes (scene coords): previous frame and current frame. + // int32 (not int16): positions are 24.8 in int32, so emitters past +-32767 px would truncate. + int32_t cx1, cy1, cx2, cy2; + int32_t px1, py1, px2, py2; +} picogame_particles_obj_t; + +void picogame_particles_emit(picogame_particles_obj_t *ps, int x, int y, + int count, int speed, int life, uint16_t color); +void picogame_particles_update(picogame_particles_obj_t *ps); +// Remove all particles, marking their last-drawn region dirty once so they get erased. +void picogame_particles_clear(picogame_particles_obj_t *ps); +// Returns true + the dirty rect (scene coords) spanning last+current frames. +bool picogame_particles_take_dirty(picogame_particles_obj_t *ps, + int *x1, int *y1, int *x2, int *y2); +void picogame_blit_particles( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_particles_obj_t *ps, int ox, int oy); diff --git a/shared-module/picogame/Scene.c b/shared-module/picogame/Scene.c new file mode 100644 index 00000000000..0d9e31c6fbc --- /dev/null +++ b/shared-module/picogame/Scene.c @@ -0,0 +1,226 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "shared-module/picogame/Scene.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Tilemap.h" +#include "shared-module/picogame/Particles.h" +#include "shared-module/picogame/Canvas.h" + +// Raw change rects collected before merging. Caps how many disjoint changes we +// track in one frame; on overflow we safely fall back to a full-screen repaint. +#define PICOGAME_RAW_RECTS 64 + +static inline bool rects_overlap(const picogame_rect_t *a, const picogame_rect_t *b) { + return a->x1 < b->x2 && b->x1 < a->x2 && a->y1 < b->y2 && b->y1 < a->y2; +} + +static inline void rect_merge(picogame_rect_t *a, const picogame_rect_t *b) { + if (b->x1 < a->x1) { + a->x1 = b->x1; + } + if (b->y1 < a->y1) { + a->y1 = b->y1; + } + if (b->x2 > a->x2) { + a->x2 = b->x2; + } + if (b->y2 > a->y2) { + a->y2 = b->y2; + } +} + +static inline long rect_area(const picogame_rect_t *r) { + return (long)(r->x2 - r->x1) * (long)(r->y2 - r->y1); +} + +// Compute up to `max_rects` mostly-disjoint dirty rectangles (screen coords) and +// update the per-sprite snapshots. Returns the rect count (0 = nothing changed). +// Collecting per-change rects (instead of one union) means scattered movers no +// longer inflate the repaint to the whole screen. +// Out-of-line rect append for compute_dirty_rects below: the old macro expanded ~30 B +// four times; a real (noinline) call keeps each site at argument setup only. +static __attribute__((noinline)) void add_rect(picogame_rect_t *raw, int *nr, bool *overflow, + int x1, int y1, int x2, int y2) { + if (*nr < PICOGAME_RAW_RECTS) { + raw[*nr].x1 = x1; + raw[*nr].y1 = y1; + raw[*nr].x2 = x2; + raw[*nr].y2 = y2; + (*nr)++; + } else { + *overflow = true; + } +} + +int picogame_scene_compute_dirty_rects( + mp_obj_t *items, uint8_t *kinds, picogame_snapshot_t *snap, size_t n, + int screen_w, int screen_h, int ox, int oy, + picogame_rect_t *out, int max_rects) { + + picogame_rect_t raw[PICOGAME_RAW_RECTS]; + int nr = 0; + bool overflow = false; + + // Rects are stored in SCREEN coords: non-fixed items get the view offset added + // here (per item), fixed (HUD) items don't - so no uniform offset at the end. + #define ADD_RECT(ax, ay, bx, by) \ + add_rect(raw, &nr, &overflow, (ax) + iox, (ay) + ioy, (bx) + iox, (by) + ioy) + + for (size_t i = 0; i < n; i++) { + uint8_t rawk = kinds[i]; + uint8_t kind = rawk & PICOGAME_KIND_MASK; + int iox = (rawk & PICOGAME_KIND_FIXED) ? 0 : ox; + int ioy = (rawk & PICOGAME_KIND_FIXED) ? 0 : oy; + if (kind != PICOGAME_KIND_SPRITE) { + int tx1, ty1, tx2, ty2; + bool d = false; + if (kind == PICOGAME_KIND_TILEMAP) { + d = picogame_tilemap_take_dirty(MP_OBJ_TO_PTR(items[i]), &tx1, &ty1, &tx2, &ty2); + } else if (kind == PICOGAME_KIND_PARTICLES) { + d = picogame_particles_take_dirty(MP_OBJ_TO_PTR(items[i]), &tx1, &ty1, &tx2, &ty2); + } else if (kind == PICOGAME_KIND_CANVAS) { + d = picogame_canvas_take_dirty(MP_OBJ_TO_PTR(items[i]), &tx1, &ty1, &tx2, &ty2); + } else if (kind == PICOGAME_KIND_STRIPDRAW) { + // No retained pixels to diff. always_dirty -> repaint the whole rect every frame + // (animated content). Otherwise repaint only the accumulated invalidate() rect - the + // same take_dirty contract as Canvas/Tilemap, so on-change UI repaints just its region + // (and still re-runs when another layer's dirty rect overlaps it). + picogame_stripdraw_obj_t *sd = MP_OBJ_TO_PTR(items[i]); + if (sd->always_dirty) { + tx1 = sd->x; + ty1 = sd->y; + tx2 = sd->x + sd->w; + ty2 = sd->y + sd->h; + d = true; + } else { + d = picogame_dirty_take(&sd->dx1, &tx1, &ty1, &tx2, &ty2); + } + } else if (kind == PICOGAME_KIND_TRIANGLES) { + // Screen-space batch: count-set marked a full-screen dirty (clipped later). + picogame_triangles_obj_t *t = MP_OBJ_TO_PTR(items[i]); + d = picogame_dirty_take(&t->dx1, &tx1, &ty1, &tx2, &ty2); + } + if (d) { + ADD_RECT(tx1, ty1, tx2, ty2); + } + continue; + } + + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(items[i]); + picogame_snapshot_t *sn = &snap[i]; + + // Snapshot tracks the drawn screen AABB (already includes scale + rotation), + // so position/anchor/size/scale/angle/bitmap changes are all detected. + int ax1, ay1, ax2, ay2; + picogame_sprite_aabb(s, &ax1, &ay1, &ax2, &ay2); + picogame_bitmap_obj_t *bm = s->bitmap; + bool changed = (ax1 != sn->x) || (ay1 != sn->y) || + ((ax2 - ax1) != sn->w) || ((ay2 - ay1) != sn->h) || + (s->frame != sn->frame) || (s->flags != sn->flags) || + (s->scale != sn->scale) || (s->angle != sn->angle) || + (s->seq != sn->seq) || // touch(): in-place bitmap content change + (s->dither != sn->dither) || // translucency level animation + (s->flash_color != sn->flash_color) || // flash/tint colour-only change (flag stays set) + ((void *)bm != sn->bitmap); + if (!changed) { + continue; + } + + // Old rect = previous AABB (snapshot); new rect = current AABB. + if (sn->flags & PICOGAME_SPR_VISIBLE) { + ADD_RECT(sn->x, sn->y, sn->x + sn->w, sn->y + sn->h); + } + if (s->flags & PICOGAME_SPR_VISIBLE) { + ADD_RECT(ax1, ay1, ax2, ay2); + } + + sn->x = ax1; + sn->y = ay1; + sn->w = ax2 - ax1; + sn->h = ay2 - ay1; + sn->bitmap = (void *)bm; + sn->frame = s->frame; + sn->flags = s->flags; + sn->scale = s->scale; + sn->angle = s->angle; + sn->seq = s->seq; + sn->dither = s->dither; + sn->flash_color = s->flash_color; + } +#undef ADD_RECT + + if (nr == 0) { + return 0; + } + // Too many changes to track individually -> one full-screen repaint is both + // correct and likely cheaper than dozens of windows. + if (overflow) { + out[0].x1 = 0; + out[0].y1 = 0; + out[0].x2 = screen_w; + out[0].y2 = screen_h; + return 1; + } + + // Merge overlapping rects (avoids painting the same pixels twice) until stable. + bool again = true; + while (again) { + again = false; + for (int i = 0; i < nr; i++) { + for (int j = i + 1; j < nr; j++) { + if (rects_overlap(&raw[i], &raw[j])) { + rect_merge(&raw[i], &raw[j]); + raw[j] = raw[nr - 1]; + nr--; + again = true; + j--; + } + } + } + } + + // Cap the count by repeatedly merging the pair that wastes the fewest pixels. + while (nr > max_rects) { + int bi = 0, bj = 1; + long best = -1; + for (int i = 0; i < nr; i++) { + long area_i = rect_area(&raw[i]); // loop-invariant in j -> hoist out + for (int j = i + 1; j < nr; j++) { + picogame_rect_t u = raw[i]; + rect_merge(&u, &raw[j]); + long waste = rect_area(&u) - area_i - rect_area(&raw[j]); + if (best < 0 || waste < best) { + best = waste; + bi = i; + bj = j; + } + } + } + rect_merge(&raw[bi], &raw[bj]); + raw[bj] = raw[nr - 1]; + nr--; + } + + // Rects are already in screen coords (offset applied per item). Clip + drop empties. + int outn = 0; + for (int i = 0; i < nr; i++) { + int x1 = picogame_imax(raw[i].x1, 0); + int y1 = picogame_imax(raw[i].y1, 0); + int x2 = picogame_imin(raw[i].x2, screen_w); + int y2 = picogame_imin(raw[i].y2, screen_h); + if (x1 >= x2 || y1 >= y2) { + continue; + } + out[outn].x1 = x1; + out[outn].y1 = y1; + out[outn].x2 = x2; + out[outn].y2 = y2; + outn++; + } + return outn; +} diff --git a/shared-module/picogame/Scene.h b/shared-module/picogame/Scene.h new file mode 100644 index 00000000000..bd1e83937e3 --- /dev/null +++ b/shared-module/picogame/Scene.h @@ -0,0 +1,80 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame retained-mode scene with dirty-rectangle tracking. The scene owns a +// list of sprites and a snapshot of their state from the previous frame; each +// refresh diffs against the snapshot to compute the changed regions and repaints +// only those: up to PICOGAME_MAX_DIRTY_RECTS (6) mostly-disjoint rectangles, each +// rendered into its own clamped SPI window, so several separated moving objects +// stay cheap; beyond that they merge toward a fuller redraw. + +#pragma once + +#include +#include +#include +#include "py/obj.h" +#include "shared-module/picogame/Sprite.h" + +typedef struct { + int32_t x, y; + int32_t w, h; // drawn SCENE-space AABB (top-left + size) when last drawn - already accounts + // for scale + rotation, so it is the old-rect on any change. int32 (not int16): + // sprite coords are 24.8 in int32, so a big scrolling world exceeds +-32767 px + void *bitmap; // bitmap identity when last drawn (detect graphic swaps); never + // dereferenced - compared for inequality only, so it is safe + // even if the previous bitmap has since been freed + uint16_t scale; // draw scale (8.8) when last drawn - detect scale changes + int16_t angle; // rotation when last drawn - detect rotation changes + uint8_t frame; + uint8_t flags; + uint8_t seq; // sprite.seq when last drawn - detect touch() (in-place content change) + uint8_t dither; // dither level when last drawn - detect translucency animation + uint16_t flash_color; // flash/tint colour when last drawn - detect a colour-only change + // (the effect flag stays set, so without this red->blue wouldn't repaint) +} picogame_snapshot_t; + +typedef struct { + int x1, y1, x2, y2; // screen-space dirty rectangle [x1,x2) x [y1,y2) +} picogame_rect_t; + +typedef struct { + mp_obj_base_t base; + mp_obj_t display; // picogame.Display (transport; also kept alive) + mp_obj_t buf_a; // strip buffer A (kept alive) + mp_obj_t buf_b; // strip buffer B (kept alive) + mp_obj_t *items; // sprite / tilemap objects (GC-scanned -> stay alive) + uint8_t *kinds; // PICOGAME_KIND_* per item + picogame_snapshot_t *snap; // previous-frame state; snap[i] is unused when + // kinds[i] == TILEMAP (tilemaps track their own dirty rect) + uint16_t count; + uint16_t cap; + uint16_t background; + int32_t ox, oy; // view offset: screen position of scene origin (camera/centering); int32 so a + // large-world camera can scroll past +-32767 px without truncating the offset + int16_t top, bottom, left, right; // reserved insets (px): the scene renders only the + // play rect [left, w-right) x [top, h-bottom) and never touches the + // border around it - the app owns it (HUD bars, side panels, frame). + bool cleared; // false until the first full-screen paint (covers stale pixels) + bool fast; // true: display is a fast picogame.Display (DMA); false: a plain + // busdisplay rendered via the portable bus.send fallback + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + bool fb_target; // true: self->display is a picogame.Framebuffer (RAM scanout buffer); + // refresh() composites dirty rects straight into it, no bus. Mutually + // exclusive with `fast` and the busdisplay path. + #endif + mp_obj_t dirty_rect; // reusable [x1,y1,x2,y2] list returned by refresh() (no + // per-frame tuple allocation / GC churn) +} picogame_scene_obj_t; + +// Diff items against snapshots and produce up to `max_rects` mostly-disjoint +// dirty rectangles (screen coords), updating snapshots / draining layer dirties. +// Returns the rect count (0 = nothing changed). Scattered movers yield several +// small rects instead of one screen-spanning union. +int picogame_scene_compute_dirty_rects( + mp_obj_t *items, uint8_t *kinds, picogame_snapshot_t *snap, size_t n, + int screen_w, int screen_h, int ox, int oy, + picogame_rect_t *out, int max_rects); diff --git a/shared-module/picogame/Sprite.h b/shared-module/picogame/Sprite.h new file mode 100644 index 00000000000..157b94e652b --- /dev/null +++ b/shared-module/picogame/Sprite.h @@ -0,0 +1,48 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame: a positioned, animatable instance of a Bitmap. + +#pragma once + +#include +#include "py/obj.h" +#include "shared-module/picogame/Bitmap.h" + +enum { + PICOGAME_SPR_VISIBLE = 1 << 0, + PICOGAME_SPR_FLIP_X = 1 << 1, + PICOGAME_SPR_FLIP_Y = 1 << 2, + PICOGAME_SPR_SHADOW = 1 << 3, // draw opaque pixels as a darkened destination (shadow/dim) + PICOGAME_SPR_FLASH = 1 << 4, // draw opaque pixels as a solid colour (hit-flash) + PICOGAME_SPR_DITHER = 1 << 5, // skip pixels via a Bayer pattern -> fake transparency + PICOGAME_SPR_TINT = 1 << 6, // multiply opaque pixels by a colour (keeps shading) + PICOGAME_SPR_TRANSPOSE = 1 << 7, // swap x/y -> cheap 90deg (with flips = all 8 orientations) +}; + +typedef struct { + mp_obj_base_t base; + picogame_bitmap_obj_t *bitmap; + mp_obj_t data; // arbitrary user payload (game state); GC-scanned + int32_t x, y; // position, 24.8 fixed-point (1/256 px), scene coords + uint16_t anchor_x; // pivot as a 1/256 fraction of width: 0=left, 128~=center, 256=right + uint16_t anchor_y; // pivot as a 1/256 fraction of height: 0=top, 128~=center, 256=bottom + uint16_t scale; // uniform draw scale, 8.8 fixed-point (256 = 1.0x); nearest-neighbour + int16_t angle; // rotation about the anchor, whole degrees (0 = axis-aligned fast path) + uint16_t flash_color; // FLASH mode: wire-order RGB565 that replaces opaque pixels + uint8_t frame; + uint8_t flags; + uint8_t seq; // bumped by touch() to force a repaint after an in-place bitmap mutation + uint8_t dither; // DITHER mode: transparency level 0..16 (0=opaque, 16=invisible) + // ---- affine transform cache (angle != 0 path). Filled lazily on first use, invalidated + // by the scale/angle/bitmap/anchor setters (xf_valid = 0). POSITION-INDEPENDENT: the bbox + // is relative to the sprite's integer position, ic/is are the 16.16 inverse-map steps. + // Saves the trig LUT + 4-corner bbox + two software divides that otherwise re-run once per + // STRIP the sprite touches (~6x/frame at strip_h=8) plus once for the dirty-rect AABB. + uint8_t xf_valid; + int16_t xf_minx, xf_miny, xf_maxx, xf_maxy; // corners bbox relative to (x>>8, y>>8) + int32_t xf_ic, xf_is; // inverse-map steps (16.16) +} picogame_sprite_obj_t; diff --git a/shared-module/picogame/Tilemap.c b/shared-module/picogame/Tilemap.c new file mode 100644 index 00000000000..5be8efb1c37 --- /dev/null +++ b/shared-module/picogame/Tilemap.c @@ -0,0 +1,100 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#include "shared-module/picogame/Tilemap.h" +#include "shared-module/picogame/__init__.h" + +// Floor division for b > 0. +static inline int floordiv(int a, int b) { + return (a >= 0) ? (a / b) : -(((-a) + b - 1) / b); +} + +// log2 of a power-of-2 (small tile dims), without a __ctzsi2 lib call on the M0+ (no CLZ/RBIT). +static inline int pow2_shift(unsigned v) { + int n = 0; + while (v > 1u) { + v >>= 1; + n++; + } + return n; +} + +// Thin wrappers over the shared int32 accumulator (dx1,dy1,dx2,dy2 are contiguous int32 at the +// struct tail). See picogame_dirty_* in __init__.c. +void picogame_tilemap_dirty_reset(picogame_tilemap_obj_t *tm) { + picogame_dirty_reset(&tm->dx1); +} + +void picogame_tilemap_dirty_union(picogame_tilemap_obj_t *tm, int x1, int y1, int x2, int y2) { + picogame_dirty_union(&tm->dx1, x1, y1, x2, y2); +} + +bool picogame_tilemap_take_dirty(picogame_tilemap_obj_t *tm, int *x1, int *y1, int *x2, int *y2) { + return picogame_dirty_take(&tm->dx1, x1, y1, x2, y2); +} + +void picogame_tilemap_extent(picogame_tilemap_obj_t *tm, int *x1, int *y1, int *x2, int *y2) { + int tw = tm->tileset ? tm->tileset->width : 0; + int th = tm->tileset ? tm->tileset->height : 0; + *x1 = tm->x; + *y1 = tm->y; + *x2 = tm->x + (int)tm->map_w * tw; + *y2 = tm->y + (int)tm->map_h * th; +} + +void picogame_blit_tilemap( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_tilemap_obj_t *tm, int ox, int oy) { + picogame_bitmap_obj_t *ts = tm->tileset; + if (ts == NULL) { + return; + } + int tw = ts->width; + int th = ts->height; + int nframes = ts->frames; + + // Tilemap origin in screen coords (scene position + view offset). + int tmx = tm->x + ox; + int tmy = tm->y + oy; + + // Region in screen coords. + int rx1 = x0, ry1 = strip_top; + int rx2 = x0 + region_w, ry2 = strip_top + strip_h; + + // Tile index range overlapping the region. Tile dims are almost always powers of two (8, 16), + // where floor division is an arithmetic shift (signed >> floors toward -inf, exactly what + // floordiv does) - which skips 4 idiv per strip on the tilemap background. Non-pow2 tiles fall + // back to floordiv. (shx>=0 signals the pow2 fast path; the ctz runs twice per call, not per tile.) + int shx = (tw & (tw - 1)) ? -1 : pow2_shift((unsigned)tw); + int shy = (th & (th - 1)) ? -1 : pow2_shift((unsigned)th); + int tx_lo = (shx >= 0) ? ((rx1 - tmx) >> shx) : floordiv(rx1 - tmx, tw); + int tx_hi = (shx >= 0) ? ((rx2 - 1 - tmx) >> shx) : floordiv(rx2 - 1 - tmx, tw); + int ty_lo = (shy >= 0) ? ((ry1 - tmy) >> shy) : floordiv(ry1 - tmy, th); + int ty_hi = (shy >= 0) ? ((ry2 - 1 - tmy) >> shy) : floordiv(ry2 - 1 - tmy, th); + tx_lo = picogame_imax(tx_lo, 0); + ty_lo = picogame_imax(ty_lo, 0); + tx_hi = picogame_imin(tx_hi, (int)tm->map_w - 1); + ty_hi = picogame_imin(ty_hi, (int)tm->map_h - 1); + + const uint8_t *map = tm->map; // hoist per-tile decode invariants out of the inner loop + const uint8_t *orient = tm->orient; + int map_w = (int)tm->map_w; + for (int ty = ty_lo; ty <= ty_hi; ty++) { + int dy = tmy + ty * th; + size_t row = (size_t)ty * map_w; + for (int tx = tx_lo; tx <= tx_hi; tx++) { + size_t cell = row + tx; + uint8_t idx = map[cell]; + if (idx >= nframes) { + continue; + } + uint8_t o = orient ? orient[cell] : 0; + int dx = tmx + tx * tw; + picogame_blit_bitmap(buf, region_w, strip_h, x0, strip_top, + ts, dx, dy, idx, (o & 1) != 0, (o & 2) != 0, (o & 4) != 0, NULL); + } + } +} diff --git a/shared-module/picogame/Tilemap.h b/shared-module/picogame/Tilemap.h new file mode 100644 index 00000000000..e06e0a626b1 --- /dev/null +++ b/shared-module/picogame/Tilemap.h @@ -0,0 +1,44 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame Tilemap: a grid of tile indices into a tileset Bitmap (each tile = one +// frame of the bitmap). Rendered as a Scene layer; maintains an accumulated dirty +// rectangle (screen coords) so only changed tiles/areas are repainted. + +#pragma once + +#include +#include +#include "py/obj.h" +#include "shared-module/picogame/Bitmap.h" + +typedef struct { + mp_obj_base_t base; + picogame_bitmap_obj_t *tileset; // each frame is a tile (tileset->width x height) + mp_obj_t tileset_obj; // keep alive + uint8_t *map; // map_w*map_h tile indices + mp_obj_t map_obj; // keep alive + uint8_t *orient; // map_w*map_h orientation bits (bit0 flipX, bit1 flipY, + // bit2 transpose); NULL until a tile sets an orientation + mp_obj_t orient_obj; // keep alive (lazily allocated) + uint16_t map_w, map_h; + int32_t x, y; // pixel position of tile (0,0) (int32: big maps scroll past +-32767) + int32_t dx1, dy1, dx2, dy2; // accumulated dirty rect (scene coords; int32, see x/y); x1>=x2 => empty +} picogame_tilemap_obj_t; + +void picogame_tilemap_dirty_reset(picogame_tilemap_obj_t *tm); +void picogame_tilemap_dirty_union(picogame_tilemap_obj_t *tm, int x1, int y1, int x2, int y2); +// Returns true and fills the dirty rect if non-empty, then resets it. +bool picogame_tilemap_take_dirty(picogame_tilemap_obj_t *tm, int *x1, int *y1, int *x2, int *y2); + +// On-screen bounding box of the whole map. +void picogame_tilemap_extent(picogame_tilemap_obj_t *tm, int *x1, int *y1, int *x2, int *y2); + +// Blit the tiles intersecting the strip region into buf. (ox, oy) is the view +// offset added to the tilemap position (scene space -> screen space). +void picogame_blit_tilemap( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + picogame_tilemap_obj_t *tm, int ox, int oy); diff --git a/shared-module/picogame/__init__.c b/shared-module/picogame/__init__.c new file mode 100644 index 00000000000..282c4d0b64f --- /dev/null +++ b/shared-module/picogame/__init__.c @@ -0,0 +1,1254 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame portable render core: strip-based, arbitrary-size blitting. +// Painter's order: clear strip to background, draw layers/sprites bottom-to-top. + +#include +#include +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Tilemap.h" +#include "shared-module/picogame/Particles.h" +#include "shared-module/picogame/Canvas.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/displayio/display_core.h" +#include "shared-bindings/displayio/__init__.h" + +// Shared dirty-rect accumulator over a contiguous int32 [x1,y1,x2,y2]. Canvas and Tilemap both end in +// `int32_t dx1,dy1,dx2,dy2`, so their public dirty fns are thin wrappers passing &self->dx1 here. +// Sentinels are the INT32 extremes (not int16) so a big-world scene coord past +-32767 px still +// accumulates correctly. +void picogame_dirty_reset(int32_t *r) { + r[0] = 0x7fffffff; + r[1] = 0x7fffffff; + r[2] = -0x7fffffff - 1; + r[3] = -0x7fffffff - 1; +} + +void picogame_dirty_union(int32_t *r, int x1, int y1, int x2, int y2) { + if (x1 < r[0]) { + r[0] = x1; + } + if (y1 < r[1]) { + r[1] = y1; + } + if (x2 > r[2]) { + r[2] = x2; + } + if (y2 > r[3]) { + r[3] = y2; + } +} + +bool picogame_dirty_take(int32_t *r, int *x1, int *y1, int *x2, int *y2) { + bool dirty = (r[0] < r[2]) && (r[1] < r[3]); + if (dirty) { + *x1 = r[0]; + *y1 = r[1]; + *x2 = r[2]; + *y2 = r[3]; + } + picogame_dirty_reset(r); + return dirty; +} + +// Halve each RGB565 channel of a wire-order pixel (50% darken, for shadow mode). +static inline uint16_t picogame_darken(uint16_t wire) { + uint16_t c = (uint16_t)((wire >> 8) | (wire << 8)); // wire -> native RGB565 + // Halve all three channels at once: >>1 shifts every channel right; the 0x7BEF mask clears the two + // bits that would bleed across channel boundaries (R's LSB into G's MSB, G's LSB into B's MSB) + + // R's now-0 top bit. Bit-identical to the per-channel r>>1/g>>1/b>>1 above, ~half the instructions. + uint16_t o = (uint16_t)((c >> 1) & 0x7BEF); + return (uint16_t)((o >> 8) | (o << 8)); // native -> wire +} + +// 4x4 ordered (Bayer) dither thresholds, 0..15. +static const uint8_t picogame_bayer4[4][4] = { + { 0, 8, 2, 10 }, + { 12, 4, 14, 6 }, + { 3, 11, 1, 9 }, + { 15, 7, 13, 5 }, +}; + +// Multiply two wire-order RGB565 pixels per channel (TINT: colour the source, keep its shading). +static inline uint16_t picogame_mul565(uint16_t a, uint16_t b) { + uint16_t ca = (uint16_t)((a >> 8) | (a << 8)); + uint16_t cb = (uint16_t)((b >> 8) | (b << 8)); + // /31 and /63 via reciprocal-multiply (bit-identical over the full product domain 0..961 / 0..3969): + // avoids a soft-divide per tinted pixel on M0+ (no HW divide); pure integer, fine on every MCU. + uint16_t r = (uint16_t)((((ca >> 11) & 0x1f) * ((cb >> 11) & 0x1f) * 529) >> 14); + uint16_t g = (uint16_t)((((ca >> 5) & 0x3f) * ((cb >> 5) & 0x3f) * 2081) >> 17); + uint16_t bl = (uint16_t)(((ca & 0x1f) * (cb & 0x1f) * 529) >> 14); + uint16_t o = (uint16_t)((r << 11) | (g << 5) | bl); + return (uint16_t)((o >> 8) | (o << 8)); +} + +// Write one opaque source pixel through the effect. (x, y) are screen coords (for DITHER). +static inline void picogame_fx_put(uint16_t *dst, uint16_t src, int x, int y, const picogame_fx_t *fx) { + if (fx == NULL) { + *dst = src; + return; + } + switch (fx->mode) { + case PICOGAME_FX_SHADOW: + *dst = picogame_darken(*dst); + break; + case PICOGAME_FX_FLASH: + *dst = fx->color; + break; + case PICOGAME_FX_TINT: + *dst = picogame_mul565(src, fx->color); // colour the sprite, keep its shading + break; + case PICOGAME_FX_DITHER: + if (picogame_bayer4[y & 3][x & 3] >= fx->level) { + *dst = src; // else: pixel skipped -> shows through + } + break; + default: + *dst = src; + break; + } +} + +// Fetch one source pixel from HOISTED scalars: the caller lifts format/data/palette/transparency +// out of the bitmap struct ONCE before its loop, so this does no per-pixel reload of bm fields (a +// `*dst` uint16_t store would otherwise force GCC to reload bm's uint16_t members every pixel). `idx` +// is the linear source offset (srow + sx). Returns false on the transparent key. Used by the scaled / +// affine / transpose paths; the unscaled fast path inlines the read directly. + +void picogame_blit_bitmap( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int dx0, int dy0, int frame, bool fx, bool fy, + bool transpose, const picogame_fx_t *fxm) { + if (bm == NULL) { + return; + } + // Point fxm at a stack copy: its fields (uint16_t color) can't then alias the *dst stores, so the + // effect params stay in registers across the pixel loop instead of reloading every pixel. + picogame_fx_t fxl; + if (fxm != NULL) { + fxl = *fxm; + fxm = &fxl; + } + int sw = bm->width; + int sh = bm->height; + + // Guard the frame index: sprite.frame is a free uint8_t, so an out-of-range + // value (bad wrap / overflow in game code) would read past the sheet data. + // Wrap into [0, frames) - cheap and animation-friendly. + if (bm->frames > 1) { + if (frame >= bm->frames) { // common case is in range: pay a compare, not a divide + frame %= bm->frames; + } + } else { + frame = 0; + } + + int frame_col0 = frame * sw; + int stride0 = bm->stride; + + // Transpose path: swap source x/y (a cheap 90deg rotate when combined with flips -> all 8 + // orientations, no cos/sin/affine). The drawn footprint swaps to sh x sw. Per-pixel sampling + // (no per-row srow precompute), used only when requested; flips + fx still apply. + if (transpose) { + int dw = sh, dh = sw; // footprint swaps + int xs = picogame_imax(dx0, ox), ys = picogame_imax(dy0, oy); + int xe = picogame_imin(dx0 + dw, ox + bw), ye = picogame_imin(dy0 + dh, oy + bh); + if (xs >= xe || ys >= ye) { + return; + } + int t_fmt = bm->format; // hoist bm fields once (see src_pixel_s) + const uint8_t *t_data = bm->data; + const uint16_t *t_pal = bm->palette; + bool t_transp = bm->has_transparent; + uint16_t t_key = bm->transparent; + for (int y = ys; y < ye; y++) { + int ly = y - dy0; // -> source X (0..sw-1) + int su = fx ? sw - 1 - ly : ly; // per-row: source column is constant across the row + uint16_t *dst = buf + (y - oy) * bw + (xs - ox); + int lx = xs - dx0; + int sv = fy ? sh - 1 - lx : lx; // source row: step it, no per-pixel ternary + int svstep = fy ? -1 : 1; + for (int x = xs; x < xe; x++) { + uint16_t val; + if (src_pixel_s(t_fmt, t_data, t_pal, t_transp, t_key, + sv * stride0 + frame_col0 + su, &val)) { + picogame_fx_put(dst, val, x, y, fxm); + } + dst++; + sv += svstep; + } + } + return; + } + + int x_start = picogame_imax(dx0, ox); + int y_start = picogame_imax(dy0, oy); + int x_end = picogame_imin(dx0 + sw, ox + bw); + int y_end = picogame_imin(dy0 + sh, oy + bh); + if (x_start >= x_end || y_start >= y_end) { + return; + } + + int frame_col = frame * sw; + int stride = bm->stride; + bool transp = bm->has_transparent; + + if (bm->format == PICOGAME_FMT_PAL8) { + const uint8_t *data = bm->data; + const uint16_t *pal = bm->palette; + uint8_t key = (uint8_t)bm->transparent; + // Contract: PAL8 indices MUST be < palette length (caller's responsibility). An out-of-range + // index is undefined behaviour: it reads past the palette - usually a garbage colour, but on + // some heap layouts / platforms (e.g. ESP32-S3 heap_caps regions) it CAN fault. We deliberately + // do NOT clamp per pixel: that cost ~3 cyc/px (cmp+sbcs+ands) here, ~8% on blit-bound frames. + // + // TO RESTORE FULL BOUNDS-SAFETY (at that cost) reinstate the clamp - add `unsigned pe = + // bm->pal_entries;` here and `if (idx >= pe) { idx = 0; }` after each `idx = data[...]` in BOTH + // loops below, and the matching guard in src_pixel() (search "blit contract"). + for (int y = y_start; y < y_end; y++) { + int sy = y - dy0; + if (fy) { + sy = sh - 1 - sy; + } + int srow = sy * stride + frame_col; + uint16_t *dst = buf + (y - oy) * bw + (x_start - ox); + int sx = x_start - dx0, xstep = 1; // hoist flip_x: walk sx +/-1, no per-pixel test + if (fx) { + sx = sw - 1 - sx; + xstep = -1; + } + if (fxm == NULL) { // plain copy (most sprites): no per-pixel fx branch/call + #pragma GCC unroll 4 // hot path: unrolling the plain sprite blit is ~6% faster on M0+ (measured), +0.6KB + for (int x = x_start; x < x_end; x++) { + uint8_t idx = data[srow + sx]; + if (!transp || idx != key) { + *dst = pal[idx]; + } + dst++; + sx += xstep; + } + } else { + for (int x = x_start; x < x_end; x++) { + uint8_t idx = data[srow + sx]; + if (!transp || idx != key) { + picogame_fx_put(dst, pal[idx], x, y, fxm); + } + dst++; + sx += xstep; + } + } + } + } else { // PICOGAME_FMT_RGB565 + // bm->data is a GC-allocated Python buffer (>=4-byte aligned), so the 16-bit + // view is safe; xtensa's -Wcast-align can't see that, so silence it here. + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + const uint16_t *data = (const uint16_t *)bm->data; + #pragma GCC diagnostic pop + uint16_t key = bm->transparent; + for (int y = y_start; y < y_end; y++) { + int sy = y - dy0; + if (fy) { + sy = sh - 1 - sy; + } + int srow = sy * stride + frame_col; + uint16_t *dst = buf + (y - oy) * bw + (x_start - ox); + int sx = x_start - dx0, xstep = 1; // hoist flip_x: walk sx +/-1, no per-pixel test + if (fx) { + sx = sw - 1 - sx; + xstep = -1; + } + if (fxm == NULL) { // plain copy (most sprites): no per-pixel fx branch/call + if (!transp && !fx) { // opaque + not x-flipped: the row is contiguous in + // both src and dst -> one memcpy (dst may be 2-byte aligned; memcpy handles that). + memcpy(dst, &data[srow + sx], (size_t)(x_end - x_start) * 2u); + continue; + } + #pragma GCC unroll 4 // hot path: unrolling the plain sprite blit is ~6% faster on M0+ (measured), +0.6KB + for (int x = x_start; x < x_end; x++) { + uint16_t v = data[srow + sx]; + if (!transp || v != key) { + *dst = v; + } + dst++; + sx += xstep; + } + } else { + for (int x = x_start; x < x_end; x++) { + uint16_t v = data[srow + sx]; + if (!transp || v != key) { + picogame_fx_put(dst, v, x, y, fxm); + } + dst++; + sx += xstep; + } + } + } + } +} + + +void picogame_blit_bitmap_scaled( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int dx0, int dy0, int frame, bool fx, bool fy, + uint16_t scale, const picogame_fx_t *fxm) { + if (bm == NULL || scale == 0) { + return; + } + picogame_fx_t fxl; // stack copy: fields don't alias *dst (see blit_bitmap) + if (fxm != NULL) { + fxl = *fxm; + fxm = &fxl; + } + int sw = bm->width, sh = bm->height; + if (bm->frames > 1) { + if (frame >= bm->frames) { // common case is in range: pay a compare, not a divide + frame %= bm->frames; + } + } else { + frame = 0; + } + int dw = (sw * scale) >> 8, dh = (sh * scale) >> 8; + if (dw <= 0 || dh <= 0) { + return; + } + int x_start = picogame_imax(dx0, ox), y_start = picogame_imax(dy0, oy); + int x_end = picogame_imin(dx0 + dw, ox + bw), y_end = picogame_imin(dy0 + dh, oy + bh); + if (x_start >= x_end || y_start >= y_end) { + return; + } + int frame_col = frame * sw, stride = bm->stride; + int s_fmt = bm->format; // hoist bm fields once (see src_pixel_s) + const uint8_t *s_data = bm->data; + const uint16_t *s_pal = bm->palette; + bool s_transp = bm->has_transparent; + uint16_t s_key = bm->transparent; + if (scale == 512 && !fx && !fy && fxm == NULL && !s_transp && s_fmt == PICOGAME_FMT_RGB565 + && (((uintptr_t)s_data & 1) == 0)) { + // 2x integer upscale fast path - the half-res-canvas genre's per-frame blit (a full-screen + // RGB565 bitmap shown through a scale-2 sprite). At scale 512 the DDA step is exactly 2^15, + // so sampling collapses to (rel >> 1): write each source pixel twice, and when two dest rows + // share a source row, memcpy the second from the first (half the reads). Byte-exact vs the + // generic loop (host-verified over 300k random windows/clips/parities). + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + const uint16_t *sd16 = (const uint16_t *)s_data; + #pragma GCC diagnostic pop + int prev_sy = -1; + uint16_t *prev_row = NULL; + int nwin = x_end - x_start; + for (int y = y_start; y < y_end; y++) { + int sy = (y - dy0) >> 1; + uint16_t *drow = buf + (y - oy) * bw + (x_start - ox); + if (sy == prev_sy && prev_row != NULL) { + memcpy(drow, prev_row, (size_t)nwin * 2); + } else { + const uint16_t *srow = sd16 + sy * stride + frame_col; + int rel = x_start - dx0; + uint16_t *d = drow; + int n = nwin; + if (rel & 1) { // leading odd dest column + *d++ = srow[rel >> 1]; + rel++; + n--; + } + const uint16_t *sp = srow + (rel >> 1); + while (n >= 2) { + uint16_t v = *sp++; + d[0] = v; + d[1] = v; + d += 2; + n -= 2; + } + if (n) { + *d = *sp; + } + } + prev_sy = sy; + prev_row = drow; + } + return; + } + uint32_t step = ((uint32_t)1 << 24) / scale; // source px per dest px, 16.16 + // No per-row sy>=sh / per-pixel sx>=sw clamp: with dw=(sd*scale)>>8 and step=floor(2^24/scale), + // the sampled index ((dw-1)*step)>>16 provably never reaches the source dimension (exhaustively + // verified over the ENTIRE uint16 x uint16 (scale, dim) domain, 0 violations), and xacc> 16); + if (fy) { + sy = sh - 1 - sy; + } + int srow = sy * stride + frame_col; + uint16_t *drow = buf + (y - oy) * bw; + uint32_t xacc = (uint32_t)(x_start - dx0) * step; + for (int x = x_start; x < x_end; x++) { + int sx = (int)(xacc >> 16); + xacc += step; + if (fx) { + sx = sw - 1 - sx; + } + uint16_t val; + if (src_pixel_s(s_fmt, s_data, s_pal, s_transp, s_key, srow + sx, &val)) { + picogame_fx_put(&drow[x - ox], val, x, y, fxm); + } + } + } +} + +// Quarter-wave Q15 sine table (0..90 deg) -> fixed-point trig for the rotation setup, so the +// affine path needs no float `sinf`/`cosf` (RP2040 has no FPU). cos(d) = sin(d+90). +static const int16_t pg_sin_q15_quad[91] = { + 0, 572, 1144, 1715, 2286, 2856, 3425, 3993, 4560, 5126, + 5690, 6252, 6813, 7371, 7927, 8481, 9032, 9580, 10126, 10668, + 11207, 11743, 12275, 12803, 13328, 13848, 14364, 14876, 15383, 15886, + 16383, 16876, 17364, 17846, 18323, 18794, 19260, 19720, 20173, 20621, + 21062, 21497, 21925, 22347, 22762, 23170, 23571, 23964, 24351, 24730, + 25101, 25465, 25821, 26169, 26509, 26841, 27165, 27481, 27788, 28087, + 28377, 28659, 28932, 29196, 29451, 29697, 29934, 30162, 30381, 30591, + 30791, 30982, 31163, 31335, 31498, 31650, 31794, 31927, 32051, 32165, + 32269, 32364, 32448, 32523, 32587, 32642, 32687, 32722, 32747, 32762, + 32767, +}; +static int32_t pg_sin_q15(int deg) { + deg %= 360; + if (deg < 0) { + deg += 360; + } + if (deg <= 90) { + return pg_sin_q15_quad[deg]; + } + if (deg <= 180) { + return pg_sin_q15_quad[180 - deg]; + } + if (deg <= 270) { + return -pg_sin_q15_quad[deg - 180]; + } + return -pg_sin_q15_quad[360 - deg]; +} +static int32_t pg_cos_q15(int deg) { + return pg_sin_q15(deg + 90); +} + +// sin of a Q16 degree angle: lerp between whole-degree LUT entries. The racing-road curvature is +// DOUBLE-integrated over ~170 rows, which amplifies whole-degree quantization into visible pixels +// (host-measured 9 px); one lerp per curvature eval brings the road within 1 px of the float original. +static int32_t pg_sin_q15_lerp(int64_t deg_q16) { + int d0 = (int)(deg_q16 >> 16); + int32_t frac = (int32_t)(deg_q16 & 0xFFFF); + int32_t a = pg_sin_q15(d0); + return a + (int32_t)(((int64_t)(pg_sin_q15(d0 + 1) - a) * frac) >> 16); +} + +// One racing-road frame's curve pass: the bottom-up curvature accumulator + per-row integer edges +// (the OutRun-genre "compute_road" loop - profiled at ~8-10 ms of Python on picobike; this is the +// batch-boundary rule in action: one C call does the frame's whole row loop). Fixed-point throughout: +// cx/ddx accumulate in Q16, curvature = two LUT sines of the world distance. cfg (int32[7]): +// [f1_q20, f2_q20, amp1k_q16, amp2k_q16, world_step, curve_step, d_row_off] - frequencies in +// Q20 degrees/world-unit (Q16 phase-drifts over a long run), amplitudes premultiplied by the +// per-row gain k, curvature re-evaluated every curve_step rows (it varies slowly). Edge stores use +// trunc-toward-zero to match the Python original's int(). Host-proven <=1 px absolute AND row-delta +// smoothness vs the float reference over 8k+ frames (road_edges_test.c). +void picogame_road_edges(int16_t *rl, int16_t *rr, const int32_t *hw_q16, int n, + int32_t cx_q16, int32_t dist, const int32_t *cfg) { + int32_t f1 = cfg[0], f2 = cfg[1], a1k = cfg[2], a2k = cfg[3]; + int32_t wstep = cfg[4], cstep = cfg[5], drow = cfg[6]; + int32_t cx = cx_q16, ddx = 0, ck = 0; + int cnt = 0; + for (int i = n - 1; i >= 0; i--) { + if (cnt == 0) { + int32_t d = dist + (drow - i) * wstep; + ck = (int32_t)(((int64_t)pg_sin_q15_lerp(((int64_t)d * f1) >> 4) * a1k) >> 15) + + (int32_t)(((int64_t)pg_sin_q15_lerp(((int64_t)d * f2) >> 4) * a2k) >> 15); + cnt = cstep; + } + cnt--; + ddx += ck; + cx += ddx; + int32_t vl = cx - hw_q16[i], vr = cx + hw_q16[i]; + rl[i] = (int16_t)(vl >= 0 ? (vl >> 16) : -((-vl) >> 16)); + rr[i] = (int16_t)(vr >= 0 ? (vr >> 16) : -((-vr) >> 16)); + } +} + + +// Forward-transform a w*h rect's 4 corners through (integer pivot, 8.8 scale, Q15 rotation) and +// return the screen-space AABB. INTEGER (Q16) - measured ~40x faster than the old float version on +// the M0+ flagship (soft-float), and faster on every target (measured affine_q16 vs affine_float). +// Runs once per rotated sprite (not per pixel). Each corner is FLOORED (arithmetic >>23 = /(256*32768)), +// so the returned box is <= the true min and the callers' +1/+2 keep the box CONTAINING the sprite +// (the affine blitter clips per pixel anyway, so a >=1px-too-large box only repaints, never clips). +static void corners_bbox(int sw, int sh, int px, int py, int pivx, int pivy, + int32_t scale, int32_t cos_q, int32_t sin_q, int *minx, int *miny, int *maxx, int *maxy) { + int nx = 1 << 30, xx = -(1 << 30), ny = 1 << 30, xy = -(1 << 30); + int cxs[4] = { 0, sw, 0, sw }, cys[4] = { 0, 0, sh, sh }; + for (int k = 0; k < 4; k++) { + int64_t du = (int64_t)(cxs[k] - pivx) * scale; // (corner - pivot) in pixels<<8 + int64_t dv = (int64_t)(cys[k] - pivy) * scale; + int X = px + (int)((du * cos_q - dv * sin_q) >> 23); // >>23 = /(256 * 32768): drop the 8.8 + Q15 + int Y = py + (int)((du * sin_q + dv * cos_q) >> 23); + if (X < nx) { + nx = X; + } + if (X > xx) { + xx = X; + } + if (Y < ny) { + ny = Y; + } + if (Y > xy) { + xy = Y; + } + } + *minx = nx; + *miny = ny; + *maxx = xx; + *maxy = xy; +} + +// Fill the sprite's affine cache (position-relative bbox + 16.16 inverse-map steps) if stale. +// The trig LUT, the 4-corner bbox and the TWO SOFTWARE DIVIDES below used to re-run once per +// strip a rotated sprite touched (~6x/frame at strip_h=8) plus once for the dirty-rect AABB; +// now once per angle/scale/bitmap/anchor change (those setters clear xf_valid). +static void sprite_xform_fill(picogame_sprite_obj_t *s) { + if (s->xf_valid) { + return; + } + int w = (s->bitmap != NULL) ? s->bitmap->width : 0; + int h = (s->bitmap != NULL) ? s->bitmap->height : 0; + int pivx = ((int)s->anchor_x * w) >> 8, pivy = ((int)s->anchor_y * h) >> 8; + int32_t cos_q = pg_cos_q15(s->angle), sin_q = pg_sin_q15(s->angle); // Q15 LUT trig + int minx, miny, maxx, maxy; + corners_bbox(w, h, 0, 0, pivx, pivy, (int32_t)s->scale, cos_q, sin_q, + &minx, &miny, &maxx, &maxy); + // Saturate into the int16 cache fields: an extreme scale x size (public scale allows + // ~256x) could exceed +-32767; a saturated bbox only over/under-covers the clip - the + // blitter clips per strip anyway - instead of wrapping into a wrong-sign rect. + s->xf_minx = (int16_t)(minx < -32768 ? -32768 : (minx > 32767 ? 32767 : minx)); + s->xf_miny = (int16_t)(miny < -32768 ? -32768 : (miny > 32767 ? 32767 : miny)); + s->xf_maxx = (int16_t)(maxx < -32768 ? -32768 : (maxx > 32767 ? 32767 : maxx)); + s->xf_maxy = (int16_t)(maxy < -32768 ? -32768 : (maxy > 32767 ? 32767 : maxy)); + // inverse map (16.16 fixed-point): u = pivx + (ic*(X-px) + is*(Y-py)); + // v = pivy + (-is*(X-px) + ic*(Y-py)) + // ic = (cs/sf)*65536 = cos_q15 * 512 / scale - computed in pure integer (no float). + int32_t nic = cos_q * 512, nis = sin_q * 512; + int sc = (int)s->scale; + if (sc < 1) { + sc = 1; // scale is setter-clamped >= 1; belt for a zeroed struct + } + s->xf_ic = (nic >= 0 ? nic + sc / 2 : nic - sc / 2) / sc; + s->xf_is = (nis >= 0 ? nis + sc / 2 : nis - sc / 2) / sc; + s->xf_valid = 1; +} + +void picogame_blit_bitmap_affine( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int px, int py, int pivx, int pivy, + int frame, bool fx, bool fy, + int minx, int miny, int maxx, int maxy, int32_t ic, int32_t is, + const picogame_fx_t *fxm) { + if (bm == NULL) { + return; + } + picogame_fx_t fxl; // stack copy: fields don't alias *dst (see blit_bitmap) + if (fxm != NULL) { + fxl = *fxm; + fxm = &fxl; + } + int sw = bm->width, sh = bm->height; + if (bm->frames > 1) { + if (frame >= bm->frames) { // common case is in range: pay a compare, not a divide + frame %= bm->frames; + } + } else { + frame = 0; + } + int frame_col = frame * sw, stride = bm->stride; + int a_fmt = bm->format; // hoist bm fields once (see src_pixel_s) + const uint8_t *a_data = bm->data; + const uint16_t *a_pal = bm->palette; + bool a_transp = bm->has_transparent; + uint16_t a_key = bm->transparent; + int x_start = picogame_imax(minx, ox), y_start = picogame_imax(miny, oy); + int x_end = picogame_imin(maxx + 1, ox + bw), y_end = picogame_imin(maxy + 1, oy + bh); + if (x_start >= x_end || y_start >= y_end) { + return; + } + // Fold flip_x/flip_y into the inverse map ONCE, so the inner loop samples the FINAL source coord + // directly - no per-pixel `sw-1-iu`/`sh-1-iv` and no fx/fy branch (one loop variant, fewer live + // values -> fewer register spills). Exact: mirroring u is u'=(sw-1)-u; through the 16.16 floor that + // is `((sw-1-pivx)<<16 + 0xFFFF) - (ic*dxf + is*dyf)`, i.e. negate the u steps + bias the pivot by + // 0xFFFF (so floor(u') == (sw-1) - floor(u) for every in-range pixel). Bit-identical output. + int32_t uxc = ic, uyc = is, upiv = (int32_t)pivx << 16; // u = upiv + uxc*dxf + uyc*dyf + int32_t vxc = -is, vyc = ic, vpiv = (int32_t)pivy << 16; // v = vpiv + vxc*dxf + vyc*dyf + if (fx) { + uxc = -ic; + uyc = -is; + upiv = ((int32_t)(sw - 1 - pivx) << 16) + 0xFFFF; + } + if (fy) { + vxc = is; + vyc = -ic; + vpiv = ((int32_t)(sh - 1 - pivy) << 16) + 0xFFFF; + } + // 32-bit 16.16 accumulators (cheaper than 64-bit on the M0+). Peak magnitude stays well within + // int32 for any sane sprite on a handheld screen. The bounds check keeps an out-of-range sample + // memory-safe (at worst a skipped pixel), never a crash. + for (int y = y_start; y < y_end; y++) { + int dyf = y - py; + int dxf = x_start - px; + int32_t uacc = upiv + uxc * dxf + uyc * dyf; + int32_t vacc = vpiv + vxc * dxf + vyc * dyf; + uint16_t *drow = buf + (y - oy) * bw; + for (int x = x_start; x < x_end; x++) { + int su = uacc >> 16, sv = vacc >> 16; // already the flipped source coords + uacc += uxc; + vacc += vxc; + if (su >= 0 && su < sw && sv >= 0 && sv < sh) { + uint16_t val; + if (src_pixel_s(a_fmt, a_data, a_pal, a_transp, a_key, + sv * stride + frame_col + su, &val)) { + picogame_fx_put(&drow[x - ox], val, x, y, fxm); + } + } + } + } +} + +void picogame_sprite_aabb(const picogame_sprite_obj_t *s, int *x1, int *y1, int *x2, int *y2) { + int w = (s->bitmap != NULL) ? s->bitmap->width : 0; + int h = (s->bitmap != NULL) ? s->bitmap->height : 0; + if (s->angle == 0) { + int sw = (w * s->scale) >> 8, sh = (h * s->scale) >> 8; + if ((s->flags & PICOGAME_SPR_TRANSPOSE) && s->scale == 256) { // transpose only on the fast + int t = sw; // path (scale==256); scaled blitter ignores it, so + sw = sh; // swapping here for scale!=256 would mistrack -> trail + sh = t; + } + int tx = (s->x >> 8) - ((int)s->anchor_x * sw >> 8); + int ty = (s->y >> 8) - ((int)s->anchor_y * sh >> 8); + *x1 = tx; + *y1 = ty; + *x2 = tx + sw; + *y2 = ty + sh; + return; + } + // cache-fill mutates only the derived xf_* fields - logically const for callers + sprite_xform_fill((picogame_sprite_obj_t *)s); + int px = s->x >> 8, py = s->y >> 8; + *x1 = px + s->xf_minx - 1; + *y1 = py + s->xf_miny - 1; + *x2 = px + s->xf_maxx + 2; + *y2 = py + s->xf_maxy + 2; +} + +// TINT on a PAL8 sprite is baked into a stack palette (see blit_sprite) when the palette fits this +// cap, else it falls back to the per-pixel tint. 64 entries = 128 B of transient stack. +#define PICOGAME_TINT_PAL_CAP 64 + +// clip_x/clip_y = the strip buffer's screen origin; vx/vy = view offset added to +// the sprite's scene position to get its screen position. +static void blit_sprite(uint16_t *buf, int bw, int bh, int clip_x, int clip_y, + picogame_sprite_obj_t *spr, int vx, int vy) { + bool fx = (spr->flags & PICOGAME_SPR_FLIP_X) != 0; + bool fy = (spr->flags & PICOGAME_SPR_FLIP_Y) != 0; + bool tr = (spr->flags & PICOGAME_SPR_TRANSPOSE) != 0; // 90deg transpose (fast path only) + // One effect at a time (dither > flash > tint > shadow priority); NULL = no effect (fast path). + picogame_fx_t fxm = { PICOGAME_FX_NONE, 0, 0 }; + if (spr->flags & PICOGAME_SPR_DITHER) { + fxm.mode = PICOGAME_FX_DITHER; + fxm.level = spr->dither; + } else if (spr->flags & PICOGAME_SPR_FLASH) { + fxm.mode = PICOGAME_FX_FLASH; + fxm.color = spr->flash_color; + } else if (spr->flags & PICOGAME_SPR_TINT) { + fxm.mode = PICOGAME_FX_TINT; + fxm.color = spr->flash_color; // shared colour field (flash/tint exclusive) + } else if (spr->flags & PICOGAME_SPR_SHADOW) { + fxm.mode = PICOGAME_FX_SHADOW; + } + const picogame_fx_t *fxp = (fxm.mode == PICOGAME_FX_NONE) ? NULL : &fxm; + // TINT of a PAL8 sprite is a pure function of the palette index -> bake it into a stack palette + // ONCE and blit plain, instead of picogame_mul565 per pixel (~4x on tinted PAL8 sprites; the + // dominant sprite format). Small palettes only; larger ones keep the per-pixel tint. Transparency + // is keyed on the INDEX before the palette lookup, so the (unused) tinted key entry is harmless. + picogame_bitmap_obj_t *bmuse = spr->bitmap; + picogame_bitmap_obj_t bmtint; + uint16_t tpal[PICOGAME_TINT_PAL_CAP]; + if (fxp != NULL && fxm.mode == PICOGAME_FX_TINT && bmuse != NULL && + bmuse->format == PICOGAME_FMT_PAL8 && bmuse->pal_entries <= PICOGAME_TINT_PAL_CAP) { + for (int i = 0; i < bmuse->pal_entries; i++) { + tpal[i] = picogame_mul565(bmuse->palette[i], fxm.color); + } + bmtint = *bmuse; // shallow copy; override only the palette + bmtint.palette = tpal; + bmuse = &bmtint; + fxp = NULL; // tint now baked in -> plain (fast) blit + } + if (spr->angle == 0 && spr->scale == 256) { + int tx, ty; + picogame_sprite_topleft(spr, &tx, &ty); + picogame_blit_bitmap(buf, bw, bh, clip_x, clip_y, bmuse, + tx + vx, ty + vy, spr->frame, fx, fy, tr, fxp); + } else if (spr->angle == 0) { + int tx, ty; + picogame_sprite_topleft(spr, &tx, &ty); + picogame_blit_bitmap_scaled(buf, bw, bh, clip_x, clip_y, bmuse, + tx + vx, ty + vy, spr->frame, fx, fy, spr->scale, fxp); + } else { + sprite_xform_fill(spr); // once per angle/scale change, not per strip + int w = (spr->bitmap != NULL) ? spr->bitmap->width : 0; + int h = (spr->bitmap != NULL) ? spr->bitmap->height : 0; + int pivx = ((int)spr->anchor_x * w) >> 8, pivy = ((int)spr->anchor_y * h) >> 8; + int px = (spr->x >> 8) + vx, py = (spr->y >> 8) + vy; + picogame_blit_bitmap_affine(buf, bw, bh, clip_x, clip_y, bmuse, + px, py, pivx, pivy, spr->frame, fx, fy, + px + spr->xf_minx, py + spr->xf_miny, px + spr->xf_maxx, py + spr->xf_maxy, + spr->xf_ic, spr->xf_is, fxp); + } +} + +mp_obj_t picogame_blit_strip_layers( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + mp_obj_t *items, uint8_t *kinds, size_t n, uint16_t background, int ox, int oy) { + mp_obj_t pending = MP_OBJ_NULL; // a BaseException latched from a StripDraw callback + int npix = region_w * strip_h; + if (background == 0) { + memset(buf, 0, (size_t)npix * 2); // common case (black/clear) -> fast bulk clear + } else { + // word-fill: two packed pixels per uint32 (half the stores). CAUTION: this composites into + // BOTH a GC strip buffer (SPI path, >=4-byte aligned) AND, on framebuffer targets, a raw row + // pointer fb + sy*stride + x0 that starts at an ODD pixel when x0 is odd -> only 2-byte + // aligned. GCC lowers the fill to STRD/STM, which raise an unaligned UsageFault on Cortex-M + // even with CCR.UNALIGN_TRP clear (STRD/STM always require word alignment). So peel one + // leading pixel to reach 4-byte alignment (mirrors picogame_fb_to_native), bulk word-fill, + // then an odd trailing pixel. + uint32_t w = (uint32_t)background | ((uint32_t)background << 16); + int i = 0; + if (npix > 0 && ((uintptr_t)buf & 2u) != 0) { + buf[0] = background; + i = 1; + } + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + uint32_t *w32 = (uint32_t *)(buf + i); // now 4-byte aligned + #pragma GCC diagnostic pop + int nw = (npix - i) >> 1; + for (int k = 0; k < nw; k++) { + w32[k] = w; + } + i += nw << 1; + if (i < npix) { // odd trailing pixel + buf[i] = background; + } + } + for (size_t i = 0; i < n; i++) { + uint8_t raw = (kinds != NULL) ? kinds[i] : PICOGAME_KIND_SPRITE; + uint8_t kind = raw & PICOGAME_KIND_MASK; + // Fixed (HUD) items are drawn in screen space -> no view offset. + int iox = (raw & PICOGAME_KIND_FIXED) ? 0 : ox; + int ioy = (raw & PICOGAME_KIND_FIXED) ? 0 : oy; + if (kind == PICOGAME_KIND_TILEMAP) { + picogame_blit_tilemap(buf, region_w, strip_top, strip_h, x0, + MP_OBJ_TO_PTR(items[i]), iox, ioy); + } else if (kind == PICOGAME_KIND_PARTICLES) { + picogame_blit_particles(buf, region_w, strip_top, strip_h, x0, + MP_OBJ_TO_PTR(items[i]), iox, ioy); + } else if (kind == PICOGAME_KIND_CANVAS) { + picogame_blit_canvas(buf, region_w, strip_top, strip_h, x0, + MP_OBJ_TO_PTR(items[i]), iox, ioy); + } else if (kind == PICOGAME_KIND_STRIPDRAW) { + // Immediate mode: hand the callback a view of the part of THIS strip that + // overlaps the layer's rect (so it can only paint within its rect - a + // full-view fill stays inside it). Skip strips the rect doesn't touch. + picogame_stripdraw_obj_t *sd = MP_OBJ_TO_PTR(items[i]); + int ry0 = sd->y, ry1 = sd->y + sd->h; + int s0 = strip_top > ry0 ? strip_top : ry0; // first screen row to draw + int st_end = strip_top + strip_h; + int s1 = st_end < ry1 ? st_end : ry1; // one past last screen row + if (s0 >= s1) { + continue; // strip is outside the layer + } + picogame_canvas_obj_t *v = MP_OBJ_TO_PTR(sd->view); + v->data = buf + (s0 - strip_top) * region_w; // view row 0 == screen row s0 + v->w = region_w; + v->h = s1 - s0; + v->x = 0; + v->y = 0; + v->has_transparent = false; + mp_obj_t cbargs[5] = { + sd->view, + MP_OBJ_NEW_SMALL_INT(x0), + MP_OBJ_NEW_SMALL_INT(s0), + MP_OBJ_NEW_SMALL_INT(region_w), + MP_OBJ_NEW_SMALL_INT(s1 - s0), + }; + // We're inside an open display bus transaction here, so a raised + // exception must NOT unwind past it (that would wedge the bus / leave a + // DMA running). Catch it, keep the transaction intact, and latch so the + // traceback prints once instead of every strip every frame. + nlr_buf_t nlr; + if (nlr_push(&nlr) == 0) { + mp_call_function_n_kw(sd->callback, 5, 0, cbargs); + nlr_pop(); + } else { + mp_obj_t exc = MP_OBJ_FROM_PTR(nlr.ret_val); + if (!mp_obj_is_subclass_fast(MP_OBJ_FROM_PTR(mp_obj_get_type(exc)), + MP_OBJ_FROM_PTR(&mp_type_Exception))) { + // A BaseException (KeyboardInterrupt / ReloadException / SystemExit) must reach the + // supervisor - latch it and stop; the caller re-raises it once the display + // transaction has safely closed, so Ctrl-C and USB auto-reload actually work. + pending = exc; + break; + } + if (!sd->faulted) { + sd->faulted = true; + mp_obj_print_exception(&mp_plat_print, exc); + } + } + } else if (kind == PICOGAME_KIND_TRIANGLES) { + // Retained screen-space triangle batch: pure C per strip (no Python callback, + // so this path needs no Python re-entry mid-compose). Cheap band + // reject vs THIS strip, then the Canvas rasteriser through a stack view over + // the strip buffer. Screen-space by design: the view offset is not applied. + picogame_triangles_obj_t *t = MP_OBJ_TO_PTR(items[i]); + picogame_canvas_obj_t v; + v.data = buf; + v.data_obj = MP_OBJ_NULL; + v.w = region_w; + v.h = strip_h; + v.x = 0; + v.y = 0; + v.transparent = 0; + v.has_transparent = false; + picogame_canvas_dirty_reset(&v); + int xo = -x0; + int yo = -strip_top; + picogame_fill_triangle_batch(&v, t->verts, t->colors, t->count, xo, yo); + } else { + picogame_sprite_obj_t *spr = MP_OBJ_TO_PTR(items[i]); + if (!(spr->flags & PICOGAME_SPR_VISIBLE)) { + continue; + } + blit_sprite(buf, region_w, strip_h, x0, strip_top, spr, iox, ioy); + } + } + return pending; +} + +bool picogame_strip_begin( + picogame_output_t *display, + int *x0p, int *y0p, int *x1p, int *y1p, size_t buffer_pixels, + int *region_w, int *strip_h) { + // Clamp the window to the panel (post-rotation w/h): an out-of-range region makes the controller + // wrap/garble rows. Callers usually pass clamped dirty rects, but StripDraw / direct render_region + // can hand us a rect that runs off the panel. Clamp AND write back through the pointers so the + // caller's strip loop + blit origin use the SAME clamped bounds (else only the GRAM window is + // clamped while the data loop still pushes off-panel rows -> the wrap/garble we're preventing). + int pw = display->core.width, ph = display->core.height; + int x0 = *x0p, y0 = *y0p, x1 = *x1p, y1 = *y1p; + if (x0 < 0) { + x0 = 0; + } + if (y0 < 0) { + y0 = 0; + } + if (x1 > pw) { + x1 = pw; + } + if (y1 > ph) { + y1 = ph; + } + *x0p = x0; + *y0p = y0; + *x1p = x1; + *y1p = y1; + int rw = x1 - x0; + int rh = y1 - y0; + if (rw <= 0 || rh <= 0) { + return false; + } + int sh = (int)(buffer_pixels / (size_t)rw); + if (sh < 1) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + if (sh > rh) { + sh = rh; + } + + displayio_area_t area; + area.x1 = x0; + area.y1 = y0; + area.x2 = x1; + area.y2 = y1; + area.next = NULL; + displayio_display_bus_set_region_to_update(&display->bus, &display->core, &area); + + while (!displayio_display_bus_begin_transaction(&display->bus)) { + RUN_BACKGROUND_TASKS; + } + display->bus.send(display->bus.bus, DISPLAY_COMMAND, + CHIP_SELECT_TOGGLE_EVERY_BYTE, &display->write_ram_command, 1); + + *region_w = rw; + *strip_h = sh; + return true; +} + +// --- output transport seam (busdisplay backend): the ONLY per-strip display ops the generic +// picogame_render_region orchestrator below touches, so a non-CircuitPython port (MicroPython +// framebuf/SPI) swaps just strip_begin + these two + set_invert/set_pixel_format. See __init__.h. +static inline void picogame_out_strip_send(picogame_output_t *display, const uint8_t *data, size_t nbytes) { + display->bus.send(display->bus.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, data, nbytes); +} +static inline void picogame_out_strip_end(picogame_output_t *display) { + displayio_display_bus_end_transaction(&display->bus); +} + +void picogame_render_region( + picogame_output_t *display, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buffer, size_t buffer_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t background, int ox, int oy) { + + int region_w, strip_h; + int cx0 = x0, cy0 = y0, cx1 = x1, cy1 = y1; // strip_begin clamps these to the panel in place + if (!picogame_strip_begin(display, &cx0, &cy0, &cx1, &cy1, buffer_pixels, ®ion_w, &strip_h)) { + return; + } + for (int sy = cy0; sy < cy1; sy += strip_h) { + int sh = picogame_imin(strip_h, cy1 - sy); + mp_obj_t exc = picogame_blit_strip_layers(buffer, region_w, sy, sh, cx0, items, kinds, n, background, ox, oy); + picogame_out_strip_send(display, (uint8_t *)buffer, region_w * sh * 2); + if (exc != MP_OBJ_NULL) { // a StripDraw callback raised a BaseException: close the + picogame_out_strip_end(display); // bus, then re-raise (Ctrl-C / reload) + nlr_raise(MP_OBJ_TO_PTR(exc)); + } + } + picogame_out_strip_end(display); +} + +// Toggle the panel's hardware colour inversion (INVON 0x21 / INVOFF 0x20). Instant, sends NO +// pixel data - a brief invert is a free full-screen "flash" (a 1-bit negative hit look). +void picogame_set_invert(picogame_output_t *display, bool on) { + uint8_t cmd = on ? 0x21 : 0x20; + while (!displayio_display_bus_begin_transaction(&display->bus)) { + RUN_BACKGROUND_TASKS; + } + display->bus.send(display->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &cmd, 1); + displayio_display_bus_end_transaction(&display->bus); +} + +#if CIRCUITPY_PICOGAME_RGB444 +// The RGB444 machinery (this + pack_rgb444 + the Display rgb444 path) is compiled in ONLY when a +// board sets CIRCUITPY_PICOGAME_RGB444=1. It is a transfer-bound-only win (on a CPU-balanced panel +// like the PicoPad's the pack ~= the SPI byte saving, so it loses); default off (port ?= 0) until +// multi-platform experience justifies flipping the default. See pack_rgb444's measured-optimal note. +// Set the panel pixel format (COLMOD 0x3A): rgb444 -> 12-bit RGB444 (0x53), else 16-bit RGB565 +// (0x55). Asserting it on every Display construct also recovers from a previous program that left +// the panel in the other format (survives soft reset). +void picogame_set_pixel_format(picogame_output_t *display, bool rgb444) { + uint8_t cmd = 0x3A; + uint8_t param = rgb444 ? 0x53 : 0x55; + while (!displayio_display_bus_begin_transaction(&display->bus)) { + RUN_BACKGROUND_TASKS; + } + display->bus.send(display->bus.bus, DISPLAY_COMMAND, CHIP_SELECT_TOGGLE_EVERY_BYTE, &cmd, 1); + display->bus.send(display->bus.bus, DISPLAY_DATA, CHIP_SELECT_UNTOUCHED, ¶m, 1); + displayio_display_bus_end_transaction(&display->bus); +} + +// Pack a strip of `npix` (must be even) WIRE-order RGB565 pixels IN-PLACE to ST7789 12-bit RGB444 +// (2 px -> 3 bytes): R0G0 / B0R1 / G1B1. Returns the packed byte count. Cuts SPI traffic ~25%. +// In-place is safe: the write offset (1.5*i) always trails the read offset (2*i). +size_t picogame_pack_rgb444(uint16_t *buf, size_t npix) { + // Pack wire RGB565 -> ST7789 12-bit RGB444 (2 px -> 3 bytes) in place; the write offset (1.5*i) + // always trails the read offset (2*i). NB: the byte-swap to native order is LOAD-BEARING, not + // waste - it nibble-aligns the channels so each extracts in ~2 ops; extracting straight from the + // wire value makes GREEN (split across the byte boundary) cost ~5 ops and is SLOWER on device + // (measured, M0+). Likewise do NOT wide-unroll (8 registers -> spills). This tight form is the + // measured-optimal pack; RGB444 still loses to RGB565 on a CPU-balanced panel (pack ~= the SPI + // byte saving), so it is a transfer-bound-only option (default off). + uint8_t *out = (uint8_t *)buf; + size_t o = 0; + for (size_t i = 0; i + 1 < npix; i += 2) { + uint32_t w0 = buf[i], w1 = buf[i + 1]; + uint32_t n0 = (w0 >> 8) | (w0 << 8); // wire -> native RGB565 + uint32_t n1 = (w1 >> 8) | (w1 << 8); + uint8_t r0 = (n0 >> 12) & 0xF, g0 = (n0 >> 7) & 0xF, b0 = (n0 >> 1) & 0xF; + uint8_t r1 = (n1 >> 12) & 0xF, g1 = (n1 >> 7) & 0xF, b1 = (n1 >> 1) & 0xF; + out[o++] = (r0 << 4) | g0; + out[o++] = (b0 << 4) | r1; + out[o++] = (g1 << 4) | b1; + } + return o; +} +#endif // CIRCUITPY_PICOGAME_RGB444 + +void picogame_render( + picogame_output_t *display, + mp_obj_t *items, size_t n, + uint16_t *buffer, size_t buffer_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t background) { + picogame_render_region(display, items, NULL, n, buffer, buffer_pixels, + x0, y0, x1, y1, background, 0, 0); +} + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Full-frame RAM-framebuffer backend. Same layered compositor as the SPI strip path +// (picogame_blit_strip_layers -> identical kinds dispatch, view offset, StripDraw), +// but the destination is a caller-owned framebuffer instead of a bus window - no +// transaction, no strip transfer. This is the shared render target for scanout-buffer +// platforms (RP2350 DVI/HSTX, the desktop sim, the WASM playground): the framebuffer +// IS the composite surface, so a region is composited straight into fb in place. +// +// fb : destination, wire-order RGB565, fb_stride*fb_h pixels (caller-owned). +// fb_stride : framebuffer row stride in pixels (>= x1); rows may be wider than x1. +// items/kinds/n, background, ox/oy : the scene layer list, as picogame_render_region. +// [x0,y0,x1,y1): the framebuffer region to (re)composite - a dirty rect, or the frame. +// Bounds are clamped to [0,fb_stride) x [0,fb_h); an empty region is a no-op. +// Returns a latched BaseException raised by a StripDraw callback (the caller re-raises +// it), or MP_OBJ_NULL - the SAME contract as the strip path, minus the bus to close. +// Convert a contiguous run of `n` pixels in place from wire-order to native RGB565. +// `((v&0x00ff00ff)<<8)|((v&0xff00ff00)>>8)` byte-swaps both halfwords of a 32-bit word at once +// (GCC lowers it to a single Cortex REV16), so two pixels per word; unrolled x4 (8 px/iter) so the +// ldr/str stream pipelines on zero-wait SRAM. A run may start at an odd x (partial dirty rect), so +// peel one leading pixel to keep the word accesses 4-byte aligned (unaligned faults on M0+). +// Portable + little-endian, so it also serves the WASM native565 canvas target. +// Emulated full-screen invert for framebuffer targets (RP2350 DVI, the WASM playground) that lack a +// panel's hardware INVON/INVOFF: a flag XORed into the wire->native conversion below, so composited +// pixels come out as their negative. Toggling it (picogame_fb_set_invert) latches a one-shot "the +// whole frame must recomposite" so the flip covers the ENTIRE screen, not just the current dirty +// rects - mirroring a panel INVON, which flips everything already scanned out. The XOR folds into the +// existing REV16 byte-swap for ~free (one extra op per word). +static bool s_fb_invert = false; +static bool s_fb_invert_dirty = false; + +void picogame_fb_set_invert(bool on) { + if (on != s_fb_invert) { + s_fb_invert = on; + s_fb_invert_dirty = true; // one full-frame recomposite so the flip is global, then latch off + } +} + +bool picogame_fb_take_invert_dirty(void) { + bool d = s_fb_invert_dirty; + s_fb_invert_dirty = false; + return d; +} + +static void picogame_fb_to_native(uint16_t *px, int n) { + uint32_t inv = s_fb_invert ? 0xFFFFFFFFu : 0u; // emulated negative flash (0 = normal pass) + int i = 0; + if (n > 0 && ((uintptr_t)px & 2u) != 0) { + px[0] = (uint16_t)(__builtin_bswap16(px[0]) ^ (uint16_t)inv); + i = 1; + } + int pairs = (n - i) >> 1; + uint32_t *w = (uint32_t *)(px + i); + int p = 0; + for (; p + 4 <= pairs; p += 4) { + uint32_t v0 = w[p], v1 = w[p + 1], v2 = w[p + 2], v3 = w[p + 3]; + w[p] = (((v0 & 0x00ff00ffu) << 8) | ((v0 & 0xff00ff00u) >> 8)) ^ inv; + w[p + 1] = (((v1 & 0x00ff00ffu) << 8) | ((v1 & 0xff00ff00u) >> 8)) ^ inv; + w[p + 2] = (((v2 & 0x00ff00ffu) << 8) | ((v2 & 0xff00ff00u) >> 8)) ^ inv; + w[p + 3] = (((v3 & 0x00ff00ffu) << 8) | ((v3 & 0xff00ff00u) >> 8)) ^ inv; + } + for (; p < pairs; p++) { + uint32_t v = w[p]; + w[p] = (((v & 0x00ff00ffu) << 8) | ((v & 0xff00ff00u) >> 8)) ^ inv; + } + i += pairs << 1; + if (i < n) { + px[i] = (uint16_t)(__builtin_bswap16(px[i]) ^ (uint16_t)inv); + } +} + +// Fused wire->native byte-swap AND copy in one pass: read `n` wire pixels from `src`, write them +// NATIVE to `dst` (folding in the emulated invert XOR). Saves the separate in-place swap + memcpy +// (one whole band read+write) on the full-width publish path. REQUIRES src AND dst 4-byte aligned +// (the caller uses it only for a contiguous full-width band, where both are). +static void picogame_fb_to_native_copy(uint16_t *dst, const uint16_t *src, int n) { + uint32_t inv = s_fb_invert ? 0xFFFFFFFFu : 0u; + int pairs = n >> 1; + const uint32_t *s = (const uint32_t *)src; + uint32_t *d = (uint32_t *)dst; + int p = 0; + for (; p + 4 <= pairs; p += 4) { + uint32_t v0 = s[p], v1 = s[p + 1], v2 = s[p + 2], v3 = s[p + 3]; + d[p] = (((v0 & 0x00ff00ffu) << 8) | ((v0 & 0xff00ff00u) >> 8)) ^ inv; + d[p + 1] = (((v1 & 0x00ff00ffu) << 8) | ((v1 & 0xff00ff00u) >> 8)) ^ inv; + d[p + 2] = (((v2 & 0x00ff00ffu) << 8) | ((v2 & 0xff00ff00u) >> 8)) ^ inv; + d[p + 3] = (((v3 & 0x00ff00ffu) << 8) | ((v3 & 0xff00ff00u) >> 8)) ^ inv; + } + for (; p < pairs; p++) { + uint32_t v = s[p]; + d[p] = (((v & 0x00ff00ffu) << 8) | ((v & 0xff00ff00u) >> 8)) ^ inv; + } + if (n & 1) { + dst[n - 1] = (uint16_t)(__builtin_bswap16(src[n - 1]) ^ (uint16_t)inv); + } +} + +// Wire-order RGB565 -> RGB332 publish copy for 8-bit picodvi scanout targets (RRRGGGBB, +// the same quantization displayio's ColorConverter uses), folding in the emulated invert. +// A wire pixel w holds native v byte-swapped: hi(v) = low byte of w, lo(v) = high byte. +// R3 = top 3 of R5 = hi & 0xE0; G3 = top 3 of G6 = (hi & 0x07) << 2; +// B2 = top 2 of B5 = (lo >> 3) & 0x03 +static void picogame_fb_to_rgb332_copy(uint8_t *dst, const uint16_t *src, int n) { + uint8_t inv = s_fb_invert ? 0xFF : 0x00; + for (int i = 0; i < n; i++) { + uint16_t w = src[i]; + uint8_t hi = (uint8_t)w; // wire low byte = native high byte + uint8_t lo = (uint8_t)(w >> 8); + dst[i] = (uint8_t)((hi & 0xE0u) | ((hi & 0x07u) << 2) | ((lo >> 3) & 0x03u)) ^ inv; + } +} + +// Publish-copy context for one framebuffer region: just what fb_publish_band needs. +typedef struct { + uint16_t *fb; + int fb_stride, fmt; + int x0, region_w; + bool full_width; +} fb_bands_arg_t; + +// Publish one FINISHED band from a scratch strip into the fb (wire/native/RGB332, +// full- or partial-width). Shared by the serial loop and both cores of the split. +static void fb_publish_band(const fb_bands_arg_t *a, uint16_t *scratch, int by, int bh) { + uint16_t *fb = a->fb; + int fb_stride = a->fb_stride; + int region_w = a->region_w; + int fmt = a->fmt; + if (a->full_width) { + size_t npix = (size_t)region_w * (size_t)bh; + if (fmt == PICOGAME_FB_RGB332) { + picogame_fb_to_rgb332_copy( + (uint8_t *)fb + (size_t)by * (size_t)fb_stride, scratch, (int)npix); + } else if (fmt == PICOGAME_FB_NATIVE565) { + // Fold the wire->native byte-swap INTO the publish copy (no separate in-place swap). + picogame_fb_to_native_copy(fb + (size_t)by * (size_t)fb_stride, scratch, (int)npix); + } else { + memcpy(fb + (size_t)by * (size_t)fb_stride, scratch, npix * 2u); // wire: HW reads as-is + } + } else if (fmt == PICOGAME_FB_RGB332) { + // Partial-width 8-bit: quantize row by row straight into the byte fb (strided). + for (int r = 0; r < bh; r++) { + picogame_fb_to_rgb332_copy( + (uint8_t *)fb + (size_t)(by + r) * (size_t)fb_stride + a->x0, + scratch + (size_t)r * region_w, region_w); + } + } else { + // Partial-width: swap the scratch in place (NATIVE), then copy row by row (strided). + if (fmt == PICOGAME_FB_NATIVE565) { + picogame_fb_to_native(scratch, region_w * bh); + } + for (int r = 0; r < bh; r++) { + memcpy(fb + (size_t)(by + r) * fb_stride + a->x0, + scratch + (size_t)r * region_w, (size_t)region_w * 2u); + } + } +} + +mp_obj_t picogame_render_framebuffer( + uint16_t *fb, int fb_stride, int fb_h, int fmt, + uint16_t *scratch, int scratch_rows, + mp_obj_t *items, uint8_t *kinds, size_t n, + int x0, int y0, int x1, int y1, + uint16_t background, int ox, int oy) { + if (x0 < 0) { + x0 = 0; + } + if (y0 < 0) { + y0 = 0; + } + if (x1 > fb_stride) { + x1 = fb_stride; + } + if (y1 > fb_h) { + y1 = fb_h; + } + if (x1 <= x0 || y1 <= y0) { + return MP_OBJ_NULL; + } + int region_w = x1 - x0; + + // Tear-free NATIVE path: the framebuffer is a LIVE scanout buffer (picodvi/HDMI reads it + // continuously), so it must NEVER transiently hold wire-order pixels - a beam sampling a + // half-composed region would read byte-swapped bytes (R/B swapped -> pink). Compose+byte-swap + // into a PRIVATE scratch strip, then memcpy the finished NATIVE band into the fb; the fb only + // ever receives fully-native runs. Any residual seam is old-vs-new NATIVE content (a plain + // single-buffer tear, no colour shift) - reduced by the caller's optional vblank sync. Bands of + // scratch_rows keep the scratch small. (Wire targets / no scratch fall through to the direct + // path below, which is correct because a wire fb needs no conversion.) + if (scratch != NULL && scratch_rows > 0) { + // Full-width band: rows are contiguous in BOTH scratch and fb, so the whole band publishes in + // one pass with 4-byte-aligned pointers (fb_stride even). Partial-width rows are strided. + fb_bands_arg_t a = { + fb, fb_stride, fmt, x0, region_w, + (x0 == 0 && region_w == fb_stride) + }; + int nbands = (y1 - y0 + scratch_rows - 1) / scratch_rows; + for (int b = 0; b < nbands; b++) { + int by = y0 + b * scratch_rows; + int bh = (y1 - by) < scratch_rows ? (y1 - by) : scratch_rows; + // Compose region_w x bh OFF-SCREEN into the scratch (wire order) so the beam never sees a + // half-composited region (no sprite/HUD flicker), then publish the FINISHED band into the + // fb. Published even on a latched exception so the fb is never left half-updated. + mp_obj_t exc = picogame_blit_strip_layers( + scratch, region_w, by, bh, x0, items, kinds, n, background, ox, oy); + fb_publish_band(&a, scratch, by, bh); + if (exc != MP_OBJ_NULL) { + return exc; // StripDraw raised; caller re-raises (cleared stays false -> full repaint) + } + } + return MP_OBJ_NULL; + } + // The compositor (blitters, effects, palettes) works in wire order throughout; a NATIVE + // target is converted in place only after a region is fully composed. On a latched StripDraw + // exception the region was partially composed in wire order - convert it anyway so the fb is + // never left half wire / half native (the Scene keeps cleared=false until its render loop + // finishes, so the refresh after the exception repaints the full frame). + + // Fast path: a FULL-WIDTH region has contiguous rows, so the whole rect IS one valid strip + // buffer. Composite it in a SINGLE strip_layers call (h = the whole band) instead of one call + // per row - this amortizes all the per-row/per-layer setup (tile-blit dispatch, clip tests, + // background fill, and crucially one StripDraw Python callback per band instead of per row) + // over the band, and converts the whole contiguous region in one pass. This is the + // full-repaint / camera-scroll case (set_view -> cleared=false -> a full-screen dirty rect). + // (An RGB332 target never reaches these direct paths: its constructor always allocates + // the scratch strip, and the compositor can only write 16-bit wire pixels - composing + // in place inside a byte framebuffer would corrupt it.) + if (x0 == 0 && x1 == fb_stride) { + uint16_t *base = fb + (size_t)y0 * (size_t)fb_stride; + mp_obj_t exc = picogame_blit_strip_layers( + base, fb_stride, y0, y1 - y0, 0, items, kinds, n, background, ox, oy); + if (fmt == PICOGAME_FB_NATIVE565) { + picogame_fb_to_native(base, (y1 - y0) * fb_stride); + } + return exc; // MP_OBJ_NULL on success, else a latched StripDraw exception + } + + // Partial-width region: rows are non-contiguous, so composite (and convert) row by row. + for (int sy = y0; sy < y1; sy++) { + uint16_t *row = fb + (size_t)sy * (size_t)fb_stride + x0; + mp_obj_t exc = picogame_blit_strip_layers( + row, region_w, sy, 1, x0, items, kinds, n, background, ox, oy); + if (fmt == PICOGAME_FB_NATIVE565) { + picogame_fb_to_native(row, region_w); + } + if (exc != MP_OBJ_NULL) { + return exc; // StripDraw raised a BaseException; caller re-raises (no bus open) + } + } + return MP_OBJ_NULL; +} +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER diff --git a/shared-module/picogame/__init__.h b/shared-module/picogame/__init__.h new file mode 100644 index 00000000000..a4377292219 --- /dev/null +++ b/shared-module/picogame/__init__.h @@ -0,0 +1,308 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include +#include +#include +#include "py/obj.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// Hardware-FPU boards run the pseudo-3D/math primitives (picogame.project) on plain float32 - +// faster than the soft-float-equivalent fixed path and free of 16.16 range limits; no-FPU +// targets (Cortex-M0+) use integer 16.16. Only ONE path is compiled per board. The default +// follows the architecture; a board can override with CIRCUITPY_PICOGAME_FPU=0/1 in its +// mpconfigboard.mk. Python reads `picogame.FPU` to pack camera/point buffers to match. +#ifndef CIRCUITPY_PICOGAME_FPU +#if (defined(__ARM_FP) && (__ARM_FP != 0)) || (defined(__riscv_flen) && (__riscv_flen > 0)) +#define CIRCUITPY_PICOGAME_FPU (1) +#else +#define CIRCUITPY_PICOGAME_FPU (0) +#endif +#endif + +// Sample one texel as wire RGB565; false = transparent (skip). Shared by the sprite/canvas +// blit paths so they inline one copy (see the blit contract: PAL8 indices must be < palette len). +static inline bool src_pixel_s(int format, const uint8_t *data, const uint16_t *pal, + bool transp, uint16_t key, int idx, uint16_t *out) { + if (format == PICOGAME_FMT_PAL8) { + uint8_t i = data[idx]; + if (transp && i == (uint8_t)key) { + return false; + } + *out = pal[i]; // indices must be < palette length (see blit contract) + return true; + } + // GC buffer is >=4-byte aligned; silence xtensa -Wcast-align (see picogame_blit_bitmap). + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + uint16_t v = ((const uint16_t *)data)[idx]; + #pragma GCC diagnostic pop + if (transp && v == key) { + return false; + } + *out = v; + return true; +} + + +// Scene layer kinds (tags stored alongside items so blit/dirty can dispatch +// without cross-referencing shared-bindings type objects). +enum { + PICOGAME_KIND_SPRITE = 0, + PICOGAME_KIND_TILEMAP = 1, + PICOGAME_KIND_PARTICLES = 2, + PICOGAME_KIND_CANVAS = 3, + PICOGAME_KIND_STRIPDRAW = 4, + PICOGAME_KIND_TRIANGLES = 5, + // High bit on a kind = "fixed": the item ignores the scene view offset + // (camera), so HUD / score / dialog stay put while the world scrolls. + PICOGAME_KIND_FIXED = 0x80, + PICOGAME_KIND_MASK = 0x7f, +}; + +// StripDraw: immediate-mode layer. Holds NO pixel buffer - instead its `callback` +// is invoked once per render strip with a Canvas "view" repointed at the live strip +// buffer, so the user draws primitives straight into the strip (zero RAM vs a Canvas, +// which costs w*h*2 bytes). Its rect is repainted every frame (it's for animated / +// scanline content: pseudo-3D, gradients, procedural backgrounds). The view's local +// (0,0) maps to screen (vx, vy) handed to the callback. `faulted` latches after the +// callback raises once, so a buggy callback prints one traceback, not one per strip. +typedef struct { + mp_obj_base_t base; + mp_obj_t callback; // draw(view, vx, vy, vw, vh): vx/vy = screen origin of view (0,0) + mp_obj_t view; // a reused picogame_canvas_obj_t (data repointed each strip) + int32_t x, y, w, h; // scene rect (int32: scene coords, big-world safe) + int32_t dx1, dy1, dx2, dy2; // accumulated dirty rect (scene coords) when !always_dirty - the same + // picogame_dirty_* accumulator Canvas/Tilemap use, so invalidate() can mark + // a sub-rect and the Scene repaints only that region (not the whole layer). + bool faulted; + bool always_dirty; // True: repaint every frame (animated). False: only the dirty rect (on-change UI). +} picogame_stripdraw_obj_t; + +// Triangles: a retained SCREEN-SPACE triangle batch the compositor rasterises entirely +// in C (per strip, band-rejected) - no Python callback per strip, so unlike StripDraw it +// stays composable without re-entering Python mid-frame. verts (int16 x0,y0,x1,y1,x2,y2 per tri) and +// colors (uint16 wire RGB565 per tri) are CALLER-OWNED arrays (refs held for GC; fill +// them in place). Setting `count` selects how many draw and marks the layer dirty +// full-screen (a 3D frame repaints everything anyway). +typedef struct { + mp_obj_base_t base; + mp_obj_t verts_obj, colors_obj; // GC anchors for the caller's arrays + const int16_t *verts; + const uint16_t *colors; + uint16_t count, cap; // cap = what the buffers can hold + int32_t dx1, dy1, dx2, dy2; // dirty accumulator (count-set -> full screen) +} picogame_triangles_obj_t; + +static inline int picogame_imin(int a, int b) { + return a < b ? a : b; +} +static inline int picogame_imax(int a, int b) { + return a > b ? a : b; +} + +// Drawn top-left in scene pixels: the logical position minus the anchor offset +// (anchor is a 1/256 fraction of the bitmap size). Used by BOTH the blitter and +// the dirty-rect tracker so they always agree on where the sprite lands. +static inline void picogame_sprite_topleft(const picogame_sprite_obj_t *s, int *tx, int *ty) { + int w = (s->bitmap != NULL) ? s->bitmap->width : 0; + int h = (s->bitmap != NULL) ? s->bitmap->height : 0; + int sw = (w * s->scale) >> 8; // anchor is a fraction of the SCALED size + int sh = (h * s->scale) >> 8; + // The blitter only honours transpose on the fast path (scale==256); the scaled blitter ignores it. + // Swap the footprint ONLY when scale==256, or aabb/topleft disagree with what's drawn (trailing). + if ((s->flags & PICOGAME_SPR_TRANSPOSE) && s->scale == 256) { // 90deg transpose swaps footprint + int t = sw; // picogame_sprite_aabb, or the blit top-left and the + sw = sh; // tracked dirty rect disagree (sprite trails) + sh = t; + } + *tx = (s->x >> 8) - ((int)s->anchor_x * sw >> 8); + *ty = (s->y >> 8) - ((int)s->anchor_y * sh >> 8); +} + +// Drawn screen-space bounding box of a sprite (accounts for scale + rotation). +// Used by the dirty-rect tracker so it always covers the transformed sprite. +void picogame_sprite_aabb(const picogame_sprite_obj_t *s, int *x1, int *y1, int *x2, int *y2); + +// Per-pixel blit effect, shared by all three blit paths. One mode at a time; a NULL +// pointer means "no effect" (the fast path). SHADOW darkens the destination, FLASH +// replaces opaque pixels with `color`, DITHER skips pixels via a Bayer pattern (0..16 +// transparency) for fake translucency without alpha. +enum { PICOGAME_FX_NONE = 0, PICOGAME_FX_SHADOW, PICOGAME_FX_FLASH, PICOGAME_FX_DITHER, PICOGAME_FX_TINT }; +typedef struct { + uint8_t mode; + uint16_t color; // FLASH: solid colour to write; TINT: colour to multiply by (wire RGB565) + uint8_t level; // DITHER: 0..16 transparency (higher = more pixels skipped) +} picogame_fx_t; + +// Shared dirty-rect accumulator over a contiguous int32 [x1,y1,x2,y2] (Canvas + Tilemap both end in +// dx1,dy1,dx2,dy2). INT32 sentinels so big-world (>32767 px) scene coords still accumulate. +void picogame_dirty_reset(int32_t *r); +void picogame_dirty_union(int32_t *r, int x1, int y1, int x2, int y2); +bool picogame_dirty_take(int32_t *r, int *x1, int *y1, int *x2, int *y2); + +// Blit one frame of a bitmap at screen (dx0, dy0) into the strip buffer that +// covers [ox, ox+bw) x [oy, oy+bh). Shared by sprites and tilemap tiles. +// fxm: per-pixel effect (NULL = plain colour copy). +void picogame_blit_bitmap( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int dx0, int dy0, int frame, bool flip_x, bool flip_y, + bool transpose, const picogame_fx_t *fxm); + +// Nearest-neighbour scaled blit (axis-aligned); scale is 8.8 fixed-point. +void picogame_blit_bitmap_scaled( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int dx0, int dy0, int frame, bool flip_x, bool flip_y, + uint16_t scale, const picogame_fx_t *fxm); + +// Full affine blit (scale + rotation about the anchor); (px,py)=screen anchor point, +// (pivx,pivy)=that anchor in SOURCE pixels. Nearest-neighbour inverse map. The transform is +// PRECOMPUTED by the caller (the sprite's xf_* cache): minx..maxy = the screen-space corner +// bbox, ic/is = the 16.16 inverse-map steps - so a per-strip call does no trig/divides. +void picogame_blit_bitmap_affine( + uint16_t *buf, int bw, int bh, int ox, int oy, + picogame_bitmap_obj_t *bm, int px, int py, int pivx, int pivy, + int frame, bool flip_x, bool flip_y, + int minx, int miny, int maxx, int maxy, int32_t ic, int32_t is, + const picogame_fx_t *fxm); + +// ===== OUTPUT TRANSPORT SEAM ===================================================== +// picogame's compositor (picogame_blit_strip_layers) is OUTPUT-AGNOSTIC: it composites +// scene layers into a plain wire-order RGB565 strip buffer, knowing nothing about the +// destination. A physical display is reached only through the small transport contract +// below, so a non-CircuitPython port (e.g. a MicroPython framebuf/SPI backend) can reuse +// the whole compositor AND the generic picogame_render_region orchestrator and reimplement +// ONLY these few functions. `picogame_output_t` is the opaque display handle they take. +// (A RAM-framebuffer destination is a separate backend: picogame_render_framebuffer.) +// +// Strip-path contract a backend provides: +// picogame_strip_begin - open a window for [x0,y0,x1,y1); return strip geometry +// picogame_out_strip_send - push one composited strip (region_w*sh px, wire RGB565) +// picogame_out_strip_end - close the transaction +// picogame_set_invert - panel hardware colour inversion (a free full-screen flash) +// picogame_set_pixel_format - panel COLMOD (RGB565/RGB444), when CIRCUITPY_PICOGAME_RGB444 +// +// CircuitPython backend: picogame_output_t == busdisplay; the impl lives in __init__.c. +typedef busdisplay_busdisplay_obj_t picogame_output_t; + +// Fill a strip with background, then composite items (sprites and tilemaps) in +// order (items[0] = bottom). kinds[i] selects the type; kinds == NULL means +// every item is a sprite. (ox, oy) is the view offset added to item positions +// (scene space -> screen space) for camera/centering. +// Returns a latched BaseException (Ctrl-C / ReloadException) raised by a StripDraw callback, or +// MP_OBJ_NULL. The caller must re-raise it AFTER closing the display transaction. +#if defined(PICOGAME_HAS_INTERP) +// rp2-port SIO-interpolator mode7 row walker. Fast path only: +// PAL8, opaque, stride == tw, log2(tw)+log2(th) <= 16; the caller guards and falls back. +void picogame_mode7_row_interp(uint16_t *dst, int n, + const uint8_t *tex, const uint16_t *pal, + uint32_t fx, uint32_t fy, int32_t stepx, int32_t stepy, + int shx, int shy, int ltw, int lth); +#endif + +// Racing-road curve pass (see the implementation comment in __init__.c). +void picogame_road_edges(int16_t *rl, int16_t *rr, const int32_t *hw_q16, int n, + int32_t cx_q16, int32_t dist, const int32_t *cfg); + +mp_obj_t picogame_blit_strip_layers( + uint16_t *buf, int region_w, int strip_top, int strip_h, int x0, + mp_obj_t *items, uint8_t *kinds, size_t n, uint16_t background, int ox, int oy); + +// Compute strip geometry and open a render window on the display (set region, +// begin transaction, send RAMWR). Returns false if the region is empty; raises +// if the buffer is too small for the region width. Fills *region_w and *strip_h. +bool picogame_strip_begin( + picogame_output_t *display, + int *x0, int *y0, int *x1, int *y1, size_t buffer_pixels, + int *region_w, int *strip_h); // clamps *x0..*y1 to the panel in place (caller loops on them) + +// Portable backend: strip-render a layered scene region to ANY busdisplay via +// its (blocking) bus.send - single buffer, no DMA. Same layer dispatch as the +// fast path (kinds + view offset), so it is the cross-port fallback for Scene on +// targets without the platform DMA Display. `kinds == NULL` => all sprites. +void picogame_render_region( + picogame_output_t *display, + mp_obj_t *items, uint8_t *kinds, size_t n, + uint16_t *buffer, size_t buffer_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t background, int ox, int oy); + +// Toggle the panel's hardware colour inversion (INVON/INVOFF) - a free full-screen flash. +void picogame_set_invert(picogame_output_t *display, bool on); + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Emulated invert for a picogame.Framebuffer target (no hardware INVON): set the flag (XORed into the +// wire->native conversion) and, via take_invert_dirty(), force one whole-frame recomposite on toggle. +void picogame_fb_set_invert(bool on); +bool picogame_fb_take_invert_dirty(void); +#endif + +#if CIRCUITPY_PICOGAME_RGB444 // compiled in only on boards that opt into RGB444 (default off) +// Set panel pixel format (COLMOD): rgb444 -> 12-bit RGB444, else 16-bit RGB565. +void picogame_set_pixel_format(picogame_output_t *display, bool rgb444); + +// Pack `npix` (even) wire-order RGB565 pixels in `buf` IN-PLACE to 12-bit RGB444; returns bytes. +size_t picogame_pack_rgb444(uint16_t *buf, size_t npix); +#endif + +// Universal sprite-only convenience wrapper over picogame_render_region. +void picogame_render( + picogame_output_t *display, + mp_obj_t *items, size_t n, + uint16_t *buffer, size_t buffer_pixels, + int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t background); + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Rows per compose band for the tear-free NATIVE framebuffer path: composite+byte-swap into a +// private scratch strip, then memcpy the finished NATIVE band into the live scanout buffer - so a +// picodvi/HDMI beam scanning the framebuffer never samples a half-composed WIRE-order region (which +// would read as byte-swapped / pink). Small band = small scratch (width*this*2 bytes). +#define PICOGAME_FB_SCRATCH_H 16 +// A render TARGET that is a caller-owned RAM framebuffer (wire-order RGB565), used in +// place of a BusDisplay for scanout-buffer platforms: the WASM playground (heap +// buffer read out to a canvas), the desktop sim, and FruitJam (the DVI/HSTX scanout +// buffer). Holds a WriteableBuffer alive + a typed view of it; allocation is the +// caller's (a bytearray in WASM, the DVI buffer memoryview on FruitJam), so the engine +// stays platform-neutral. Scene / render can target this instead of a display. +// Output pixel format of a picogame.Framebuffer target. The compositor always works in +// wire-order RGB565; the format only selects the publish conversion. +enum { + PICOGAME_FB_WIRE565 = 0, // no conversion (WASM playground / sim readout) + PICOGAME_FB_NATIVE565 = 1, // byte-swap to native RGB565 (picodvi 16-bit scanout) + PICOGAME_FB_RGB332 = 2, // quantize to RGB332 bytes (picodvi 8-bit scanout, e.g. + // Fruit Jam 640x480 - its max resolution is 8bpp-only) +}; + +typedef struct { + mp_obj_base_t base; + mp_obj_t buffer; // the backing WriteableBuffer (kept alive) + uint16_t *fb; // typed view of buffer.buf: width*height px - RGB565 (2 B/px) for the + // 565 formats; cast to uint8_t* per-pixel bytes for PICOGAME_FB_RGB332 + int width; + int height; + uint8_t fmt; // PICOGAME_FB_* output format (see enum above) + mp_obj_t scratch_buf; // GC-kept bytearray backing `scratch`; mp_const_none if none + uint16_t *scratch; // private compose strip: width*scratch_rows px, or NULL + int scratch_rows; // rows in `scratch` (PICOGAME_FB_SCRATCH_H), 0 if none +} picogame_framebuffer_obj_t; + +// Full-frame RAM-framebuffer backend: same layered compositor as the SPI strip path +// but composited straight into a caller-owned wire-order RGB565 framebuffer (no bus). +// The shared render target for scanout-buffer platforms (RP2350 DVI/HSTX, sim, WASM). +// [x0,y0,x1,y1) is the region to (re)composite (clamped to the framebuffer). Returns a +// latched StripDraw BaseException for the caller to re-raise, or MP_OBJ_NULL. +mp_obj_t picogame_render_framebuffer( + uint16_t *fb, int fb_stride, int fb_h, int fmt, + uint16_t *scratch, int scratch_rows, + mp_obj_t *items, uint8_t *kinds, size_t n, + int x0, int y0, int x1, int y1, + uint16_t background, int ox, int oy); +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER diff --git a/shared-module/picogame/pg_compat.h b/shared-module/picogame/pg_compat.h new file mode 100644 index 00000000000..92c4168f6d8 --- /dev/null +++ b/shared-module/picogame/pg_compat.h @@ -0,0 +1,64 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// pg_compat.h — the small CircuitPython core-API delta the picogame engine relies on, +// OWNED BY THE ENGINE (not injected by a build-level force-`-include`). On CircuitPython +// this is a pure pass-through (every symbol is native); on a bare MicroPython build it +// supplies the ~9-symbol delta CP added over MicroPython. This lets the SAME engine C +// compile on both without a per-build shim impersonating CircuitPython. +// +// Engine TUs `#include "shared-module/picogame/pg_compat.h"` where they use any of these +// (it replaces the former `#include "py/objproperty.h"` in the bindings TUs). The function +// bodies for the MicroPython branch live in pg_compat_mp.c (compiled ONLY on MicroPython). +#pragma once + +#include "py/runtime.h" + +#if defined(CIRCUITPY) +// CircuitPython: everything below is native — pure pass-through. +#include "py/objproperty.h" +#else +// MicroPython: the core-API delta the engine needs that bare MicroPython lacks. +#include "py/obj.h" + +#ifndef RUN_BACKGROUND_TASKS +#define RUN_BACKGROUND_TASKS (mp_handle_pending(MP_HANDLE_PENDING_CALLBACKS_AND_EXCEPTIONS)) +#endif +#ifndef m_malloc_without_collect +#define m_malloc_without_collect(n) m_malloc(n) +#endif +#ifndef mp_raise_RuntimeError +#define mp_raise_RuntimeError(msg) mp_raise_msg(&mp_type_RuntimeError, (msg)) +#endif + +mp_int_t mp_arg_validate_int_min(mp_int_t i, mp_int_t min, qstr arg_name); +mp_int_t mp_arg_validate_int_range(mp_int_t i, mp_int_t min, mp_int_t max, qstr arg_name); +mp_obj_t mp_arg_validate_type(mp_obj_t obj, const mp_obj_type_t *type, qstr arg_name); +NORETURN void mp_raise_ValueError_varg(mp_rom_error_text_t fmt, ...); +NORETURN void mp_raise_TypeError_varg(mp_rom_error_text_t fmt, ...); +mp_obj_t mp_obj_new_bytearray_of_zeros(size_t n); + +// CircuitPython's MP_PROPERTY_GETTER / MP_PROPERTY_GETSET convenience macros. Bare +// MicroPython keeps the property object private to py/objproperty.c; redeclare the +// struct with MP's EXACT layout + the macros in the non-native form (identical to +// CircuitPython's own !MICROPY_PY_OBJ_PROPERTY_NATIVE branch), so the generated +// property objects are ABI-compatible with MP's mp_type_property. +#if MICROPY_PY_BUILTINS_PROPERTY +typedef struct _mp_obj_property_t { + mp_obj_base_t base; + mp_obj_t proxy[3]; // getter, setter, deleter +} mp_obj_property_getset_t; +#ifndef MP_PROPERTY_GETTER +#define MP_PROPERTY_GETTER(P, G) \ + const mp_obj_property_getset_t P = { .base.type = &mp_type_property, .proxy = {G, MP_ROM_NONE, MP_ROM_NONE} } +#endif +#ifndef MP_PROPERTY_GETSET +#define MP_PROPERTY_GETSET(P, G, S) \ + const mp_obj_property_getset_t P = { .base.type = &mp_type_property, .proxy = {G, S, MP_ROM_NONE} } +#endif +#endif // MICROPY_PY_BUILTINS_PROPERTY + +#endif // CIRCUITPY From 536c119404dacb8a739b96bda2bddc9bc8a12bf6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 6 Aug 2026 09:49:08 -0700 Subject: [PATCH 771/876] Add pairing and bonding to Zephyr _bleio Board flash partitioning is changing so back up CIRCUITPY. It may change again when we introduce an MCUBoot bootloader for everything. This updates the nrf bsim models too. --- locale/circuitpython.pot | 30 +- ports/zephyr-cp/Kconfig | 15 + .../boards/adafruit_feather_rp2040.overlay | 8 +- .../boards/frdm_mcxn947_mcxn947_cpu0.overlay | 18 + ports/zephyr-cp/boards/frdm_rw612.overlay | 9 +- .../boards/frdm_rw612_rw612_cpu0.overlay | 9 +- .../mimxrt1170_evk_mimxrt1176_cm7.overlay | 9 +- .../nrf54lm20bsim/autogen_board_info.toml | 6 + ports/zephyr-cp/boards/native_sim.overlay | 8 +- .../boards/nrf5340bsim_nrf5340_cpuapp.overlay | 8 +- .../nrf54lm20bsim_nrf54lm20a_cpuapp.overlay | 9 +- .../boards/rpi_pico2_rp2350a_m33.overlay | 8 +- .../boards/rpi_pico2_rp2350a_m33_w.overlay | 8 +- .../zephyr-cp/boards/rpi_pico_rp2040.overlay | 8 +- .../boards/rpi_pico_rp2040_w.overlay | 8 +- ...h750b_dk_stm32h750xx_ext_flash_app.overlay | 10 +- ports/zephyr-cp/boards/stm32h7b3i_dk.overlay | 16 + ports/zephyr-cp/common-hal/_bleio/Adapter.c | 83 +++- .../zephyr-cp/common-hal/_bleio/Connection.c | 108 +++++- .../zephyr-cp/common-hal/_bleio/Connection.h | 9 + ports/zephyr-cp/common-hal/_bleio/__init__.c | 2 + ports/zephyr-cp/debug.conf | 21 ++ ports/zephyr-cp/prj.conf | 14 + .../tests/bsim/test_bsim_ble_advertising.py | 4 +- .../tests/bsim/test_bsim_ble_pairing.py | 353 ++++++++++++++++++ ports/zephyr-cp/zephyr-config/west.yml | 4 +- 26 files changed, 744 insertions(+), 41 deletions(-) create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 38d498312ad..69b9a62bd78 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1682,7 +1682,8 @@ msgstr "" msgid "Only IPv4 addresses supported" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" msgstr "" @@ -1738,12 +1739,14 @@ msgid "Unknown gatt error: 0x%04x" msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" "Unspecified issue. Can be that the pairing prompt on the other device was " "declined or ignored." msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c #, c-format msgid "Unknown security error: 0x%04x" msgstr "" @@ -1844,6 +1847,17 @@ msgstr "" msgid "In-buffer elements must be <= 4 bytes long" msgstr "" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "" + +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" @@ -3732,6 +3746,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c #: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c @@ -3749,10 +3764,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -3762,15 +3773,6 @@ msgstr "" msgid "%q and %q must be different" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " diff --git a/ports/zephyr-cp/Kconfig b/ports/zephyr-cp/Kconfig index 498d2d92abf..015864100ec 100644 --- a/ports/zephyr-cp/Kconfig +++ b/ports/zephyr-cp/Kconfig @@ -87,3 +87,18 @@ config BT_GATT_DYNAMIC_DB config BT_GATT_CLIENT default y + +config BT_SMP + default y + +config BT_BONDABLE + default y + +config SETTINGS + default y + +config BT_SETTINGS + default y + +config BT_KEYS_OVERWRITE_OLDEST + default y diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay index 3cc026389f4..a19e2a066db 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay +++ b/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay @@ -23,7 +23,13 @@ nvm_partition: partition@180000 { compatible = "zephyr,mapped-partition"; label = "nvm"; - reg = <0x180000 0x1000>; + reg = <0x180000 0x800>; + }; + + storage_partition: partition@180800 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x180800 0x800>; }; circuitpy_partition: partition@181000 { diff --git a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay index 83242201c5b..f1a07471477 100644 --- a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay +++ b/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay @@ -1,5 +1,23 @@ &w25q64jvssiq { /delete-node/ partitions; + + partitions { + #address-cells = <1>; + #size-cells = <1>; + ranges; + + storage_partition: partition@0 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x0 DT_SIZE_K(32)>; + }; + + circuitpy_partition: partition@8000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00008000 (DT_SIZE_M(8) - DT_SIZE_K(32))>; + }; + }; }; #include "../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_rw612.overlay b/ports/zephyr-cp/boards/frdm_rw612.overlay index 741d0702e03..e926394817e 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.overlay +++ b/ports/zephyr-cp/boards/frdm_rw612.overlay @@ -1,10 +1,15 @@ &w25q512jvfiq { partitions { /delete-node/ partition@620000; - circuitpy_partition: partition@620000 { + storage_partition: partition@620000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x00620000 DT_SIZE_K(32)>; + }; + circuitpy_partition: partition@628000 { compatible = "zephyr,mapped-partition"; label = "circuitpy"; - reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; + reg = <0x00628000 (DT_SIZE_M(58) - DT_SIZE_K(128) - DT_SIZE_K(32))>; }; }; }; diff --git a/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay index 5a4d840c446..e57b5b6d331 100644 --- a/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay +++ b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay @@ -1,10 +1,15 @@ &w25q512jvfiq { partitions { /delete-node/ storage_partition; - circuitpy_partition: partition@620000 { + storage_partition: partition@620000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x00620000 DT_SIZE_K(32)>; + }; + circuitpy_partition: partition@628000 { compatible = "zephyr,mapped-partition"; label = "circuitpy"; - reg = <0x00620000 (DT_SIZE_M(58) - DT_SIZE_K(128))>; + reg = <0x00628000 (DT_SIZE_M(58) - DT_SIZE_K(128) - DT_SIZE_K(32))>; }; } diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay index 6a0ed82182e..b8f707dac27 100644 --- a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay +++ b/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay @@ -1,10 +1,15 @@ &is25wp128 { partitions { /delete-node/ partition@e20000; - circuitpy_partition: partition@e20000 { + storage_partition: partition@e20000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x00e20000 DT_SIZE_K(32)>; + }; + circuitpy_partition: partition@e28000 { compatible = "zephyr,mapped-partition"; label = "circuitpy"; - reg = <0x00e20000 (DT_SIZE_M(2) - DT_SIZE_K(128))>; + reg = <0x00e28000 (DT_SIZE_M(2) - DT_SIZE_K(128) - DT_SIZE_K(32))>; }; }; }; diff --git a/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml index 6a3ea5b39d5..6a470b5906b 100644 --- a/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml @@ -121,3 +121,9 @@ wifi = false zephyr_display = false zephyr_kernel = false zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/native_sim.overlay b/ports/zephyr-cp/boards/native_sim.overlay index 18dfa816107..f94f71726a8 100644 --- a/ports/zephyr-cp/boards/native_sim.overlay +++ b/ports/zephyr-cp/boards/native_sim.overlay @@ -31,7 +31,13 @@ circuitpy_partition: partition@0 { compatible = "zephyr,mapped-partition"; label = "circuitpy"; - reg = <0x00000000 DT_SIZE_K(2040)>; + reg = <0x00000000 DT_SIZE_K(2032)>; + }; + + storage_partition: partition@1fc000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x001fc000 DT_SIZE_K(8)>; }; nvm_partition: partition@1fe000 { diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay index 8f575d30475..5f0c9fd7af8 100644 --- a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay @@ -20,7 +20,13 @@ circuitpy_partition: partition@0 { compatible = "zephyr,mapped-partition"; label = "circuitpy"; - reg = <0x00000000 DT_SIZE_K(1024)>; + reg = <0x00000000 DT_SIZE_K(1008)>; + }; + + storage_partition: partition@fc000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x000fc000 DT_SIZE_K(16)>; }; }; }; diff --git a/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay b/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay index fb74a6313f3..ed5831ec5a3 100644 --- a/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay @@ -21,8 +21,15 @@ #size-cells = <1>; circuitpy_partition: partition@0 { + compatible = "zephyr,mapped-partition"; label = "circuitpy"; - reg = <0x00000000 DT_SIZE_K(512)>; + reg = <0x00000000 (DT_SIZE_K(2036) - DT_SIZE_K(32))>; + }; + + storage_partition: partition@1f5000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x001f5000 DT_SIZE_K(32)>; }; }; }; diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay index a3c2a9911c0..ca0400b6645 100644 --- a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay @@ -13,7 +13,13 @@ nvm_partition: partition@180000 { compatible = "zephyr,mapped-partition"; label = "nvm"; - reg = <0x180000 0x1000>; + reg = <0x180000 0x800>; + }; + + storage_partition: partition@180800 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x180800 0x800>; }; circuitpy_partition: partition@181000 { diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay index a3c2a9911c0..ca0400b6645 100644 --- a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay +++ b/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay @@ -13,7 +13,13 @@ nvm_partition: partition@180000 { compatible = "zephyr,mapped-partition"; label = "nvm"; - reg = <0x180000 0x1000>; + reg = <0x180000 0x800>; + }; + + storage_partition: partition@180800 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x180800 0x800>; }; circuitpy_partition: partition@181000 { diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay index d3ff27ddc74..1cdd4ca2033 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay @@ -23,7 +23,13 @@ nvm_partition: partition@180000 { compatible = "zephyr,mapped-partition"; label = "nvm"; - reg = <0x180000 0x1000>; + reg = <0x180000 0x800>; + }; + + storage_partition: partition@180800 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x180800 0x800>; }; circuitpy_partition: partition@181000 { diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay index d3ff27ddc74..1cdd4ca2033 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay @@ -23,7 +23,13 @@ nvm_partition: partition@180000 { compatible = "zephyr,mapped-partition"; label = "nvm"; - reg = <0x180000 0x1000>; + reg = <0x180000 0x800>; + }; + + storage_partition: partition@180800 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x180800 0x800>; }; circuitpy_partition: partition@181000 { diff --git a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay index c1d22c6261e..7e038bb77aa 100644 --- a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay +++ b/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay @@ -2,10 +2,16 @@ partitions { /delete-node/ partition@7800000; - circuitpy_partition: partition@7800000 { + storage_partition: partition@7800000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x7800000 DT_SIZE_K(32)>; + }; + + circuitpy_partition: partition@7808000 { compatible = "zephyr,mapped-partition"; label = "circuitpy"; - reg = <0x7800000 DT_SIZE_M(8)>; + reg = <0x7808000 (DT_SIZE_M(8) - DT_SIZE_K(32))>; }; }; }; diff --git a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay b/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay index c2b5f3129c4..d871e728e0d 100644 --- a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay +++ b/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay @@ -1,5 +1,21 @@ &mx25lm51245 { /delete-node/ partitions; + + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + storage_partition: partition@0 { + label = "storage"; + reg = <0x00000000 DT_SIZE_K(32)>; + }; + + circuitpy_partition: partition@8000 { + label = "circuitpy"; + reg = <0x00008000 (DT_SIZE_M(64) - DT_SIZE_K(32))>; + }; + }; }; &sram5 { diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index 59813f9ad89..ac2b1948eb7 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -14,6 +14,7 @@ #include #include #include +#include #include "py/gc.h" #include "py/runtime.h" @@ -122,6 +123,8 @@ static void bleio_connection_clear(bleio_connection_internal_t *self) { } self->connection_obj = mp_const_none; + self->pair_status = PAIR_NOT_PAIRED; + self->sec_err = 0; } static void bleio_connection_release(bleio_connection_internal_t *connection, uint8_t reason) { @@ -159,13 +162,31 @@ static void bleio_connected_cb(struct bt_conn *conn, uint8_t err) { } static void bleio_disconnected_cb(struct bt_conn *conn, uint8_t reason) { - printk("disconnected %p\n", conn); bleio_connection_release(bleio_connection_find_by_conn(conn), reason); } +static void bleio_security_changed_cb(struct bt_conn *conn, bt_security_t level, + enum bt_security_err err) { + bleio_connection_internal_t *connection = bleio_connection_find_by_conn(conn); + if (connection == NULL) { + return; + } + + if (err == BT_SECURITY_ERR_SUCCESS && level > BT_SECURITY_L1) { + // Security was established (encryption enabled). + // This happens both on first-time pairing and when reconnecting + // with stored bond keys. + connection->pair_status = PAIR_PAIRED; + } else if (err != BT_SECURITY_ERR_SUCCESS) { + connection->pair_status = PAIR_NOT_PAIRED; + connection->sec_err = (uint8_t)err; + } +} + BT_CONN_CB_DEFINE(bleio_connection_callbacks) = { .connected = bleio_connected_cb, .disconnected = bleio_disconnected_cb, + .security_changed = bleio_security_changed_cb, }; static void scan_recv_cb(const struct bt_le_scan_recv_info *info, struct net_buf_simple *buf) { @@ -257,9 +278,15 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable } if (!bt_is_ready()) { int err = bt_enable(NULL); - if (err != 0) { + if (err != 0 && err != -EALREADY) { raise_zephyr_error(err); } + + // bt_init() returns early without setting BT_DEV_READY when + // CONFIG_BT_SETTINGS=y and no identity is loaded yet. + // Load settings so the BT settings handler fires and calls + // bt_finalize_init() which sets BT_DEV_READY. + settings_load(); } ble_adapter_enabled = true; return; @@ -621,11 +648,61 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre return bleio_connection_new_from_internal(connection); } +struct bond_collect_ctx { + bt_addr_le_t *addrs; + size_t *count; + size_t max; +}; + +static void bond_iterator_collect(const struct bt_bond_info *info, void *user_data) { + struct bond_collect_ctx *ctx = (struct bond_collect_ctx *)user_data; + if (*ctx->count < ctx->max) { + bt_addr_le_copy(&ctx->addrs[*ctx->count], &info->addr); + (*ctx->count)++; + } +} + +static void bond_iterator_check(const struct bt_bond_info *info, void *user_data) { + (void)info; + bool *has_bonds = (bool *)user_data; + *has_bonds = true; +} + void common_hal_bleio_adapter_erase_bonding(bleio_adapter_obj_t *self) { - mp_raise_NotImplementedError(NULL); + // Unpair all bonded devices for all local identities. + for (uint8_t id = 0; id < CONFIG_BT_ID_MAX; id++) { + // bt_unpair takes an addr; use bt_foreach_bond to iterate and unpair. + // We need to collect addresses first since we can't unpair during iteration. + bt_addr_le_t addrs[CONFIG_BT_MAX_PAIRED]; + size_t addr_count = 0; + + bt_foreach_bond(id, bond_iterator_collect, &(struct bond_collect_ctx) { + .addrs = addrs, + .count = &addr_count, + .max = CONFIG_BT_MAX_PAIRED + }); + + for (size_t i = 0; i < addr_count; i++) { + bt_unpair(id, &addrs[i]); + } + } + + // Reset pairing state on all connections + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connections[i].pair_status = PAIR_NOT_PAIRED; + bleio_connections[i].sec_err = 0; + } } bool common_hal_bleio_adapter_is_bonded_to_central(bleio_adapter_obj_t *self) { + // Check if any bond exists for identity 0 + for (uint8_t id = 0; id < CONFIG_BT_ID_MAX; id++) { + bool has_bonds = false; + bt_foreach_bond(id, bond_iterator_check, &has_bonds); + if (has_bonds) { + return true; + } + } return false; } diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.c b/ports/zephyr-cp/common-hal/_bleio/Connection.c index ecc5f23a525..336e90e7674 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.c +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -14,6 +14,7 @@ #include #include "py/runtime.h" +#include "shared/runtime/interrupt_char.h" #include "bindings/zephyr_kernel/__init__.h" #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" @@ -24,7 +25,6 @@ #include "common-hal/_bleio/__init__.h" #include "common-hal/_bleio/Characteristic.h" #include "supervisor/port_heap.h" -#include "supervisor/shared/tick.h" // Discovery context passed through Zephyr callbacks. typedef struct { @@ -385,8 +385,107 @@ static void discover_characteristics_for_service(struct bt_conn *conn, } } +// ===== PAIRING / BONDING ===== + +// Auth info callbacks to track pairing completion/failure +static struct bt_conn_auth_info_cb auth_info_cb; +static bool auth_info_cb_registered = false; + +static void on_pairing_complete(struct bt_conn *conn, bool bonded) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn == conn) { + bleio_connections[i].pair_status = PAIR_PAIRED; + bleio_connections[i].sec_err = 0; + break; + } + } +} + +static void on_pairing_failed(struct bt_conn *conn, enum bt_security_err reason) { + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + if (bleio_connections[i].conn == conn) { + bleio_connections[i].pair_status = PAIR_NOT_PAIRED; + bleio_connections[i].sec_err = (uint8_t)reason; + break; + } + } +} + +void bleio_connection_register_auth_callbacks(void) { + if (!auth_info_cb_registered) { + auth_info_cb.pairing_complete = on_pairing_complete; + auth_info_cb.pairing_failed = on_pairing_failed; + bt_conn_auth_info_cb_register(&auth_info_cb); + auth_info_cb_registered = true; + } +} + void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bond) { - mp_raise_NotImplementedError(NULL); + (void)bond; // Bonding is enabled globally via CONFIG_BT_BONDABLE=y + + if (self == NULL || self->conn == NULL) { + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } + + // Already paired? + if (self->pair_status == PAIR_PAIRED) { + return; + } + + // Ensure auth callbacks are registered + bleio_connection_register_auth_callbacks(); + + self->pair_status = PAIR_WAITING; + self->sec_err = 0; + + int err = bt_conn_set_security(self->conn, BT_SECURITY_L2); + if (err != 0) { + self->pair_status = PAIR_NOT_PAIRED; + raise_zephyr_error(err); + } + + // bt_conn_set_security may return 0 immediately if already encrypted + // (e.g., reconnection with stored bond keys). Check current security level. + if (bt_conn_get_security(self->conn) > BT_SECURITY_L1) { + self->pair_status = PAIR_PAIRED; + return; + } + + // Wait for pairing to complete. Zephyr's SMP reports each attempt via + // pairing_failed before auto-restarting security (smp.c), so a stale-bond + // retry shows up as an intermediate BT_SECURITY_ERR_PIN_OR_KEY_MISSING + // followed by a fresh attempt that can succeed. Ride through those and + // rely on Zephyr to signal the end: success (PAIR_PAIRED), SMP_TIMEOUT + // dropping the link (observed as conn == NULL), or a user interrupt. + while (self->pair_status != PAIR_PAIRED + && self->conn != NULL + && !mp_hal_is_interrupted()) { + RUN_BACKGROUND_TASKS; + } + + if (mp_hal_is_interrupted()) { + if (self->conn != NULL) { + bt_conn_auth_cancel(self->conn); + } + self->pair_status = PAIR_NOT_PAIRED; + return; + } + + if (self->pair_status == PAIR_PAIRED) { + return; + } + + // Reuse the messages shared with the nordic _bleio implementation + // (check_sec_status). A dropped link clears sec_err, so it falls through + // to the "unspecified issue" message alongside the explicit UNSPECIFIED + // error code rather than introducing a zephyr-specific "Pairing failed" + // string. + uint8_t sec_err_code = self->sec_err; + if (sec_err_code == BT_SECURITY_ERR_UNSPECIFIED || sec_err_code == 0) { + mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored.")); + } else { + mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unknown security error: 0x%04x"), sec_err_code); + } } void common_hal_bleio_connection_disconnect(bleio_connection_internal_t *self) { @@ -434,7 +533,10 @@ mp_int_t common_hal_bleio_connection_get_max_packet_length(bleio_connection_inte } bool common_hal_bleio_connection_get_paired(bleio_connection_obj_t *self) { - return false; + if (self == NULL || self->connection == NULL) { + return false; + } + return self->connection->pair_status == PAIR_PAIRED; } mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_connection_obj_t *self, mp_obj_t service_uuids_whitelist) { diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.h b/ports/zephyr-cp/common-hal/_bleio/Connection.h index dc14125db5f..323e9393103 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.h +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.h @@ -13,9 +13,17 @@ struct bt_conn; +typedef enum { + PAIR_NOT_PAIRED, + PAIR_WAITING, + PAIR_PAIRED, +} pair_status_t; + typedef struct { struct bt_conn *conn; mp_obj_t connection_obj; + volatile pair_status_t pair_status; + uint8_t sec_err; // Security error code from pairing attempt } bleio_connection_internal_t; typedef struct { @@ -25,3 +33,4 @@ typedef struct { } bleio_connection_obj_t; mp_obj_t bleio_connection_new_from_internal(bleio_connection_internal_t *connection); +void bleio_connection_register_auth_callbacks(void); diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.c b/ports/zephyr-cp/common-hal/_bleio/__init__.c index 2dfe5af0060..e3c208a7d1d 100644 --- a/ports/zephyr-cp/common-hal/_bleio/__init__.c +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.c @@ -11,6 +11,7 @@ #include "common-hal/_bleio/Adapter.h" #include "common-hal/_bleio/__init__.h" #include "bindings/zephyr_kernel/__init__.h" +#include "common-hal/_bleio/Connection.h" #include "supervisor/shared/bluetooth/bluetooth.h" #include "supervisor/shared/tick.h" @@ -20,6 +21,7 @@ bleio_adapter_obj_t common_hal_bleio_adapter_obj; void common_hal_bleio_init(void) { common_hal_bleio_adapter_obj.base.type = &bleio_adapter_type; bleio_adapter_reset(&common_hal_bleio_adapter_obj); + bleio_connection_register_auth_callbacks(); } void bleio_user_reset(void) { diff --git a/ports/zephyr-cp/debug.conf b/ports/zephyr-cp/debug.conf index 9d1e3d5c0cd..625ef45198f 100644 --- a/ports/zephyr-cp/debug.conf +++ b/ports/zephyr-cp/debug.conf @@ -13,6 +13,16 @@ CONFIG_FRAME_POINTER=y CONFIG_FLASH_LOG_LEVEL_DBG=y CONFIG_LOG_MODE_IMMEDIATE=y +# Bluetooth: enable BT host debug logging so success paths print, not just +# LOG_ERR. In particular bt_keys logs "Stored keys for " (LOG_DBG) on a +# successful bt_keys_store(); without this only the failure message +# "Failed to save keys (err -116)" is visible. Also enable the adjacent +# modules (SMP drives pairing, BT_SETTINGS is the NVS backend that returns +# the store err) so the -EALREADY (-116) store-failure context is complete. +CONFIG_BT_KEYS_LOG_LEVEL_DBG=y +CONFIG_BT_SETTINGS_LOG_LEVEL_DBG=y +CONFIG_BT_SMP_LOG_LEVEL_DBG=y + # Bump stacks for debug build - verbose logging consumes more stack. CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 CONFIG_MAIN_STACK_SIZE=32768 @@ -21,3 +31,14 @@ CONFIG_UDC_DWC2_STACK_SIZE=4096 CONFIG_USBD_THREAD_STACK_SIZE=4096 CONFIG_USBD_MSC_STACK_SIZE=4096 CONFIG_IDLE_STACK_SIZE=1024 + +# Bluetooth stacks: debug logging + assertions + LOG_MODE_IMMEDIATE consume +# substantial extra stack in the BT host RX workqueue (runs all event callbacks, +# including SMP/pairing) and the long workqueue (deferred SMP/pairing/crypto + +# NVS bond-key store). Zephyr's own SMP/pairing test app +# (tests/bluetooth/tester/prj.conf) uses 4096 for BT_RX_STACK_SIZE. +# (BT_CTLR_RX_PRIO_STACK_SIZE is bumped in the Zephyr controller Kconfig +# default since it's a hidden symbol. BT_HCI_TX/BT_CTLR_RX are also hidden and +# haven't overflowed — left at their defaults.) +CONFIG_BT_RX_STACK_SIZE=4096 +CONFIG_BT_LONG_WQ_STACK_SIZE=4096 diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index a54df43e82f..31f6623aaaf 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -9,6 +9,11 @@ CONFIG_UART_INTERRUPT_DRIVEN=y CONFIG_FLASH_MAP_LABELS=y CONFIG_MAIN_STACK_SIZE=24288 +# The system workqueue is used by BT settings delayed store (NVS flash writes +# during bond key save). RRAM flash drivers on nRF54L need more than the +# default 1024 bytes to avoid stack overflow. +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=3072 + CONFIG_THREAD_STACK_INFO=y CONFIG_ARCH_POSIX_UPDATE_STACK_INFO=y CONFIG_STACK_SENTINEL=n @@ -50,7 +55,16 @@ CONFIG_MBEDTLS=y # Override Kconfig default not taking effect CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_RX_STACK_SIZE=2048 +CONFIG_BT_LONG_WQ_STACK_SIZE=3072 CONFIG_MBEDTLS_BUILTIN=y CONFIG_PSA_CRYPTO=y CONFIG_PSA_WANT_ALG_SHA_1=y CONFIG_PSA_WANT_ALG_SHA_256=y + +# Settings storage backend for BT bond keys +# SECTOR_COUNT is set high — the init code caps it to what fits in the storage +# partition: min(sector_count, partition_size / sector_size) +CONFIG_NVS=y +CONFIG_SETTINGS_NVS=y +CONFIG_SETTINGS_NVS_SECTOR_COUNT=256 diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py index a3b00b0b055..40b74ee854a 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -142,9 +142,7 @@ def test_bsim_tx_power_default_rssi(board, bsim_phy, circuitpython, zephyr_sampl # Observer: "Device found: (RSSI ), type , AD data len " # Advertisement is 12 bytes: flags (3) + name (9). # With 40 dB channel attenuation and 0 dBm TX → RSSI ~ -39. - # nRF54l bsim model has a TXPOWER register mapping discrepancy that - # reads 0 dBm as 2 dBm, giving RSSI ~ -37 instead. - expected_rssi = -37 if "nrf54" in board else -39 + expected_rssi = -39 rssi_pattern = re.compile(r"RSSI (-?\d+)\), type \d+, AD data len 12") all_rssi = [int(m.group(1)) for m in rssi_pattern.finditer(obs_output)] logger.info("RSSI values: %s", all_rssi) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py new file mode 100644 index 00000000000..75f6875ee2e --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py @@ -0,0 +1,353 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""BLE pairing tests for nrf5340bsim.""" + +import pytest + +# nrf54lm20bsim LE encryption is not yet functional in bsim. Enable it when it +# does. Real hardware works. +pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") + +BSIM_PERIPHERAL_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"PAIRPERIPH" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("peripheral start") +adapter.start_advertising(advertisement, connectable=True) +print("peripheral advertising", adapter.advertising) + +# Wait for connection +timeout = time.monotonic() + 12.0 +while not adapter.connected and time.monotonic() < timeout: + time.sleep(0.01) + +if not adapter.connected: + print("peripheral connect timed out") + raise SystemExit(1) + +print("peripheral connected", adapter.connected) + +# Wait for pairing to complete (central initiates it) +# The peripheral's SMP module responds automatically. +timeout = time.monotonic() + 10.0 +paired = False +while time.monotonic() < timeout: + if adapter.connected and len(adapter.connections) > 0: + conn = adapter.connections[0] + if conn.paired: + paired = True + break + time.sleep(0.1) + +print("peripheral paired", paired) + +# Wait for disconnect +timeout = time.monotonic() + 10.0 +while adapter.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("peripheral disconnected", adapter.connected, len(adapter.connections)) +""" + +BSIM_CENTRAL_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("central start") +target = None +for entry in adapter.start_scan(timeout=8.0, active=True): + if entry.connectable and b"PAIRPERIPH" in entry.advertisement_bytes: + target = entry.address + print("central found target") + break +adapter.stop_scan() +print("central have target", target is not None) + +if target is None: + raise RuntimeError("No connectable target found") + +connection = adapter.connect(target, timeout=5.0) +print("central connected", connection.connected, adapter.connected, len(adapter.connections)) + +# Pair with the peripheral (Just Works pairing) +connection.pair() +print("central paired", connection.paired) + +# Disconnect cleanly +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("central disconnected", connection.connected, adapter.connected, len(adapter.connections)) +""" + + +@pytest.mark.duration(22) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_CODE}) +def test_bsim_pairing_cp_to_cp(bsim_phy, circuitpython1, circuitpython2): + """Two CP instances: device 0 peripheral, device 1 central pairs to it.""" + peripheral = circuitpython1 + central = circuitpython2 + + central.wait_until_done() + peripheral.wait_until_done() + + periph_output = peripheral.serial.all_output + central_output = central.serial.all_output + + # Peripheral assertions + assert "peripheral start" in periph_output + assert "peripheral advertising True" in periph_output + assert "peripheral connected True" in periph_output + assert "peripheral paired True" in periph_output + assert "peripheral disconnected False 0" in periph_output + + # Central assertions + assert "central start" in central_output + assert "central found target" in central_output + assert "central have target True" in central_output + assert "central connected True True 1" in central_output + assert "central paired True" in central_output + assert "central disconnected False False 0" in central_output + + +BSIM_CENTRAL_PAIRED_PROPERTY_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("central start") +target = None +for entry in adapter.start_scan(timeout=8.0, active=True): + if entry.connectable and b"PAIRPERIPH" in entry.advertisement_bytes: + target = entry.address + print("central found target") + break +adapter.stop_scan() + +if target is None: + raise RuntimeError("No connectable target found") + +connection = adapter.connect(target, timeout=5.0) +print("central connected", connection.connected) + +# Check paired is False before pairing +print("central paired before", connection.paired) + +connection.pair() +print("central paired after", connection.paired) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("central disconnected", connection.connected) +""" + + +@pytest.mark.duration(22) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_PAIRED_PROPERTY_CODE}) +def test_bsim_pairing_paired_property(bsim_phy, circuitpython1, circuitpython2): + """Verify connection.paired transitions from False to True after pairing.""" + peripheral = circuitpython1 + central = circuitpython2 + + central.wait_until_done() + peripheral.wait_until_done() + + periph_output = peripheral.serial.all_output + central_output = central.serial.all_output + + assert "peripheral paired True" in periph_output + + assert "central paired before False" in central_output + assert "central paired after True" in central_output + assert "central disconnected False" in central_output + + +BSIM_PERIPHERAL_BOND_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"BONDPERIPH" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +print("peripheral start") + +# First connection - pair +adapter.start_advertising(advertisement, connectable=True) +print("peripheral advertising", adapter.advertising) + +timeout = time.monotonic() + 12.0 +while not adapter.connected and time.monotonic() < timeout: + time.sleep(0.01) + +if not adapter.connected: + print("peripheral connect1 timed out") + raise SystemExit(1) + +print("peripheral connected1", adapter.connected) + +# Wait for pairing +timeout = time.monotonic() + 10.0 +paired = False +while time.monotonic() < timeout: + if adapter.connected and len(adapter.connections) > 0: + conn = adapter.connections[0] + if conn.paired: + paired = True + break + time.sleep(0.1) + +print("peripheral paired1", paired) + +# Wait for disconnect +timeout = time.monotonic() + 10.0 +while adapter.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("peripheral disconnected1", adapter.connected, len(adapter.connections)) + +# Second connection - bond should persist through storage. +# Calling pair() uses the stored bond keys without re-pairing. +time.sleep(0.5) +adapter.start_advertising(advertisement, connectable=True) +print("peripheral advertising2", adapter.advertising) + +timeout = time.monotonic() + 12.0 +while not adapter.connected and time.monotonic() < timeout: + time.sleep(0.01) + +if not adapter.connected: + print("peripheral connect2 timed out") + raise SystemExit(1) + +print("peripheral connected2", adapter.connected) + +# Request security to restore bond encryption +conn = adapter.connections[0] +conn.pair() +print("peripheral paired2", conn.paired) + +# Wait for disconnect +timeout = time.monotonic() + 10.0 +while adapter.connected and time.monotonic() < timeout: + time.sleep(0.1) + +print("peripheral disconnected2", adapter.connected) +""" + +BSIM_CENTRAL_BOND_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +print("central start") +target_addr = None +for entry in adapter.start_scan(timeout=8.0, active=True): + if entry.connectable and b"BONDPERIPH" in entry.advertisement_bytes: + target_addr = entry.address + print("central found target") + break +adapter.stop_scan() +print("central have target", target_addr is not None) + +if target_addr is None: + raise RuntimeError("No connectable target found") + +# First connection - pair +connection = adapter.connect(target_addr, timeout=5.0) +print("central connected1", connection.connected, adapter.connected, len(adapter.connections)) + +print("central paired before1", connection.paired) +connection.pair() +print("central paired after1", connection.paired) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("central disconnected1", connection.connected, adapter.connected) + +# Second connection - bond should be restored from storage. +# Calling pair() uses the stored bond keys without re-pairing. +time.sleep(1.0) +connection2 = adapter.connect(target_addr, timeout=5.0) +print("central connected2", connection2.connected, adapter.connected, len(adapter.connections)) + +connection2.pair() +print("central paired bond", connection2.paired) + +connection2.disconnect() + +timeout = time.monotonic() + 4.0 +while (connection2.connected or adapter.connected) and time.monotonic() < timeout: + time.sleep(0.1) + +print("central disconnected2", connection2.connected, adapter.connected) +""" + + +@pytest.mark.duration(35) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_BOND_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_BOND_CODE}) +def test_bsim_bonding_persistence(bsim_phy, circuitpython1, circuitpython2): + """Verify bonds are saved to storage and survive disconnect/reconnect. + + Central pairs with peripheral, disconnects, then reconnects. + On the second connection the bond should be restored from storage + and connection.paired should be True without calling pair() again. + """ + peripheral = circuitpython1 + central = circuitpython2 + + central.wait_until_done() + peripheral.wait_until_done() + + periph_output = peripheral.serial.all_output + central_output = central.serial.all_output + + # Peripheral assertions - first connection + assert "peripheral start" in periph_output + assert "peripheral advertising True" in periph_output + assert "peripheral connected1 True" in periph_output + assert "peripheral paired1 True" in periph_output + assert "peripheral disconnected1 False 0" in periph_output + # Peripheral - second connection (private advertising, bond restored from storage) + assert "peripheral advertising2 True" in periph_output + assert "peripheral connected2 True" in periph_output + assert "peripheral paired2 True" in periph_output + assert "peripheral disconnected2 False" in periph_output + + # Central assertions - first connection + assert "central start" in central_output + assert "central found target" in central_output + assert "central have target True" in central_output + assert "central connected1 True True 1" in central_output + assert "central paired before1 False" in central_output + assert "central paired after1 True" in central_output + assert "central disconnected1 False False" in central_output + # Central - second connection (bond restored from storage) + assert "central connected2 True True 1" in central_output + assert "central paired bond True" in central_output + assert "central disconnected2 False False" in central_output diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 241ca53aceb..cff4be3993c 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -4,10 +4,10 @@ manifest: projects: - name: nrf_hw_models url: https://github.com/tannewt/ext_nRF_hw_models - revision: c2927847bdf2ee0af9c5459f4155c67f39f6837a + revision: 41cb69cd08848cc31e91ed62d01d397511981919 path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: 63f054c88ee158a3d755bd59a26ef874f650efa2 + revision: 3c402d80bd86628065f2a7d2af4a55a42556b08e clone-depth: 100 import: true From 41270d001dc05b0d213f4e84560f1a84330807ae Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 6 Aug 2026 11:50:49 -0700 Subject: [PATCH 772/876] Implement and enable `usb_hid` on Zephyr --- locale/circuitpython.pot | 12 +- ports/zephyr-cp/app.overlay | 12 + .../autogen_board_info.toml | 2 +- .../autogen_board_info.toml | 2 +- .../autogen_board_info.toml | 2 +- .../nordic/nrf5340dk/autogen_board_info.toml | 2 +- .../nordic/nrf54h20dk/autogen_board_info.toml | 2 +- .../nrf54lm20dk/autogen_board_info.toml | 2 +- .../nordic/nrf7002dk/autogen_board_info.toml | 2 +- .../nxp/frdm_mcxn947/autogen_board_info.toml | 2 +- .../nxp/frdm_rw612/autogen_board_info.toml | 2 +- .../mimxrt1170_evk/autogen_board_info.toml | 2 +- .../autogen_board_info.toml | 2 +- .../rpi_pico2_zephyr/autogen_board_info.toml | 2 +- .../rpi_pico_w_zephyr/autogen_board_info.toml | 2 +- .../rpi_pico_zephyr/autogen_board_info.toml | 2 +- .../da14695_dk_usb/autogen_board_info.toml | 2 +- .../renesas/ek_ra6m5/autogen_board_info.toml | 2 +- .../renesas/ek_ra8d1/autogen_board_info.toml | 2 +- .../nucleo_n657x0_q/autogen_board_info.toml | 2 +- .../nucleo_u575zi_q/autogen_board_info.toml | 2 +- .../st/stm32h7b3i_dk/autogen_board_info.toml | 2 +- .../stm32wba65i_dk1/autogen_board_info.toml | 2 +- ports/zephyr-cp/common-hal/usb_hid/Device.c | 150 +++++++ ports/zephyr-cp/common-hal/usb_hid/__init__.c | 377 ++++++++++++++++++ ports/zephyr-cp/common-hal/usb_hid/__init__.h | 28 ++ .../zephyr-cp/cptools/build_circuitpython.py | 9 + ports/zephyr-cp/prj.conf | 1 + ports/zephyr-cp/supervisor/usb.c | 50 ++- shared-module/usb_hid/Device.c | 88 +--- shared-module/usb_hid/report_descriptors.c | 96 +++++ shared-module/usb_hid/report_descriptors.h | 19 + supervisor/supervisor.mk | 1 + 33 files changed, 768 insertions(+), 117 deletions(-) create mode 100644 ports/zephyr-cp/common-hal/usb_hid/Device.c create mode 100644 ports/zephyr-cp/common-hal/usb_hid/__init__.c create mode 100644 ports/zephyr-cp/common-hal/usb_hid/__init__.h create mode 100644 shared-module/usb_hid/report_descriptors.c create mode 100644 shared-module/usb_hid/report_descriptors.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 38d498312ad..8560ea3b29f 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -2244,6 +2244,10 @@ msgstr "" msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -3749,10 +3753,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4514,10 +4514,6 @@ msgstr "" msgid "USB busy" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "" - #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" diff --git a/ports/zephyr-cp/app.overlay b/ports/zephyr-cp/app.overlay index 0f34d64a80f..bb2be8924f6 100644 --- a/ports/zephyr-cp/app.overlay +++ b/ports/zephyr-cp/app.overlay @@ -8,3 +8,15 @@ label = "CircuitPython Data"; }; }; + +/ { + hid_dev_0: hid_dev_0 { + compatible = "zephyr,hid-device"; + label = "HID0"; + protocol-code = "none"; + in-polling-period-us = <1000>; + in-report-size = <64>; + out-polling-period-us = <1000>; + out-report-size = <64>; + }; +}; diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml index eef096756e7..459ee6a98c2 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml index 187017cb12e..654a6c2e01b 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml index 41c4c1dda5e..17022b4d2c7 100644 --- a/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml index 4d4ce0fce98..366d4cd4cb3 100644 --- a/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml index 6fdd16a7732..b3da39f698c 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml index 58a5074f733..9da6422265e 100644 --- a/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml index 3f72b515853..9f31476b449 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml index 05233a43246..273aff2376d 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml index 13d5bdf8971..6efb741df94 100644 --- a/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml index ba521087358..cf5c0650015 100644 --- a/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml index 8f89598c426..e7d3f4502fd 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml index a536de71e7b..95a2873af70 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml index 5a156b1c37b..e2036293823 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml index 1a3912156b9..3c96b7d4f57 100644 --- a/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml index ef56e12139a..4c396485d66 100644 --- a/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml index 390fc8a3925..d943b17bf26 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra6m5/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml index 93ddc67c013..2291d43c4a1 100644 --- a/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml index 92cdc6137f5..9ee6085d189 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml index 199909fbd6d..59a15de0232 100644 --- a/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/nucleo_u575zi_q/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml index eb808e08111..63fac014f17 100644 --- a/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml index 11136930e27..10c7a39b60a 100644 --- a/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/autogen_board_info.toml @@ -109,7 +109,7 @@ uheap = false usb = false usb_audio = false usb_cdc = true -usb_hid = false +usb_hid = true usb_host = false usb_midi = false usb_video = false diff --git a/ports/zephyr-cp/common-hal/usb_hid/Device.c b/ports/zephyr-cp/common-hal/usb_hid/Device.c new file mode 100644 index 00000000000..ba263d44d74 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_hid/Device.c @@ -0,0 +1,150 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 hathach for Adafruit Industries +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/usb_hid/Device.h" +#include "shared-module/usb_hid/__init__.h" +#include "shared-module/usb_hid/Device.h" +#include "shared-module/usb_hid/report_descriptors.h" +#include "common-hal/usb_hid/__init__.h" +#include "supervisor/shared/tick.h" + +const usb_hid_device_obj_t usb_hid_device_keyboard_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = keyboard_report_descriptor, + .report_descriptor_length = sizeof(keyboard_report_descriptor), + .usage_page = 0x01, + .usage = 0x06, + .num_report_ids = 1, + .report_ids = { 0x01, }, + .in_report_lengths = { 8, }, + .out_report_lengths = { 1, }, +}; + +const usb_hid_device_obj_t usb_hid_device_mouse_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = mouse_report_descriptor, + .report_descriptor_length = sizeof(mouse_report_descriptor), + .usage_page = 0x01, + .usage = 0x02, + .num_report_ids = 1, + .report_ids = { 0x02, }, + .in_report_lengths = { 4, }, + .out_report_lengths = { 0, }, +}; + +const usb_hid_device_obj_t usb_hid_device_consumer_control_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = consumer_control_report_descriptor, + .report_descriptor_length = sizeof(consumer_control_report_descriptor), + .usage_page = 0x0C, + .usage = 0x01, + .num_report_ids = 1, + .report_ids = { 0x03 }, + .in_report_lengths = { 2, }, + .out_report_lengths = { 0, }, +}; + +char *custom_usb_hid_interface_name; + +static size_t get_report_id_idx(usb_hid_device_obj_t *self, size_t report_id) { + for (size_t i = 0; i < self->num_report_ids; i++) { + if (report_id == self->report_ids[i]) { + return i; + } + } + return CIRCUITPY_USB_HID_MAX_REPORT_IDS_PER_DESCRIPTOR; +} + +uint8_t common_hal_usb_hid_device_validate_report_id(usb_hid_device_obj_t *self, mp_int_t report_id_arg) { + if (report_id_arg == -1 && self->num_report_ids == 1) { + return self->report_ids[0]; + } + if (!(report_id_arg >= 0 && + get_report_id_idx(self, (size_t)report_id_arg) < CIRCUITPY_USB_HID_MAX_REPORT_IDS_PER_DESCRIPTOR)) { + mp_arg_error_invalid(MP_QSTR_report_id); + } + return (uint8_t)report_id_arg; +} + +void common_hal_usb_hid_device_construct(usb_hid_device_obj_t *self, mp_obj_t report_descriptor, uint16_t usage_page, uint16_t usage, size_t num_report_ids, uint8_t *report_ids, uint8_t *in_report_lengths, uint8_t *out_report_lengths) { + mp_arg_validate_length_max( + num_report_ids, CIRCUITPY_USB_HID_MAX_REPORT_IDS_PER_DESCRIPTOR, MP_QSTR_report_ids); + + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(report_descriptor, &bufinfo, MP_BUFFER_READ); + self->report_descriptor_length = bufinfo.len; + + uint8_t *descriptor_bytes = gc_alloc(bufinfo.len, false); + memcpy(descriptor_bytes, bufinfo.buf, bufinfo.len); + self->report_descriptor = descriptor_bytes; + + self->usage_page = usage_page; + self->usage = usage; + self->num_report_ids = num_report_ids; + memcpy(self->report_ids, report_ids, num_report_ids); + memcpy(self->in_report_lengths, in_report_lengths, num_report_ids); + memcpy(self->out_report_lengths, out_report_lengths, num_report_ids); +} + +uint16_t common_hal_usb_hid_device_get_usage_page(usb_hid_device_obj_t *self) { + return self->usage_page; +} + +uint16_t common_hal_usb_hid_device_get_usage(usb_hid_device_obj_t *self) { + return self->usage; +} + +void common_hal_usb_hid_device_send_report(usb_hid_device_obj_t *self, uint8_t *report, uint8_t len, uint8_t report_id) { + size_t id_idx = get_report_id_idx(self, report_id); + + mp_arg_validate_length(len, self->in_report_lengths[id_idx], MP_QSTR_report); + + // Wait until interface is ready, timeout = 2 seconds + uint64_t end_ticks = supervisor_ticks_ms64() + 2000; + while ((supervisor_ticks_ms64() < end_ticks) && !usb_hid_ready()) { + RUN_BACKGROUND_TASKS; + } + + if (!usb_hid_submit_report(report_id, report, len)) { + mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("USB error")); + } +} + +mp_obj_t common_hal_usb_hid_device_get_last_received_report(usb_hid_device_obj_t *self, uint8_t report_id) { + size_t id_idx = get_report_id_idx(self, report_id); + if (!self->out_report_buffers_updated[id_idx]) { + return mp_const_none; + } + self->out_report_buffers_updated[id_idx] = false; + return mp_obj_new_bytes(self->out_report_buffers[id_idx], self->out_report_lengths[id_idx]); +} + +void usb_hid_device_create_report_buffers(usb_hid_device_obj_t *self) { + for (size_t i = 0; i < self->num_report_ids; i++) { + self->in_report_buffers[i] = + self->in_report_lengths[i] > 0 + ? gc_alloc(self->in_report_lengths[i], false) + : NULL; + + self->out_report_buffers[i] = + self->out_report_lengths[i] > 0 + ? gc_alloc(self->out_report_lengths[i], false) + : NULL; + } + memset(self->out_report_buffers_updated, 0, sizeof(self->out_report_buffers_updated)); +} diff --git a/ports/zephyr-cp/common-hal/usb_hid/__init__.c b/ports/zephyr-cp/common-hal/usb_hid/__init__.c new file mode 100644 index 00000000000..552a91e102b --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_hid/__init__.c @@ -0,0 +1,377 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include + +#include "py/gc.h" +#include "py/runtime.h" +#include "shared-bindings/usb_hid/__init__.h" +#include "shared-bindings/usb_hid/Device.h" +#include "shared-module/usb_hid/Device.h" +#include "supervisor/port.h" + +#include +#include +#include +#include +#include + +#define MAX_HID_DEVICES 8 + +static usb_hid_device_obj_t hid_devices[MAX_HID_DEVICES]; +// If 0, USB HID is disabled. +static mp_int_t num_hid_devices; +// Which boot device is available? 0: no boot devices, 1: boot keyboard, 2: boot mouse. +static uint8_t hid_boot_device; +// Whether a boot device was requested by a SET_PROTOCOL request from the host. +static bool hid_boot_device_requested; +// This tuple is stored in usb_hid.devices. +static mp_obj_tuple_t *hid_devices_tuple; + +// Whether the HID interface is ready (USB configured). +static bool hid_interface_ready; + +static mp_obj_tuple_t default_hid_devices_tuple = { + .base = { + .type = &mp_type_tuple, + }, + .len = 3, + .items = { + MP_OBJ_FROM_PTR(&usb_hid_device_keyboard_obj), + MP_OBJ_FROM_PTR(&usb_hid_device_mouse_obj), + MP_OBJ_FROM_PTR(&usb_hid_device_consumer_control_obj), + }, +}; + +// These describe the standard descriptors used for boot keyboard and mouse, +// which don't use report IDs. +static const usb_hid_device_obj_t boot_keyboard_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = NULL, + .report_descriptor_length = 0, + .usage_page = 0x01, + .usage = 0x06, + .num_report_ids = 1, + .report_ids = { 0, }, + .in_report_lengths = { 8, }, + .out_report_lengths = { 1, }, +}; + +static const usb_hid_device_obj_t boot_mouse_obj = { + .base = { + .type = &usb_hid_device_type, + }, + .report_descriptor = NULL, + .report_descriptor_length = 0, + .usage_page = 0x01, + .usage = 0x02, + .num_report_ids = 1, + .report_ids = { 0, }, + .in_report_lengths = { 4, }, + .out_report_lengths = { 0, }, +}; + +bool usb_hid_enabled(void) { + return num_hid_devices > 0; +} + +uint8_t usb_hid_boot_device(void) { + return hid_boot_device; +} + +// Returns 1 or 2 if host requested a boot device and boot protocol was enabled. +uint8_t common_hal_usb_hid_get_boot_device(void) { + return hid_boot_device_requested ? hid_boot_device : 0; +} + +void usb_hid_set_defaults(void) { + hid_boot_device = 0; + hid_boot_device_requested = false; + hid_interface_ready = false; + common_hal_usb_hid_enable( + CIRCUITPY_USB_HID_ENABLED_DEFAULT ? &default_hid_devices_tuple : mp_const_empty_tuple, 0); +} + +// Make up a fresh tuple containing the device objects saved in the static +// devices table. Save the tuple in usb_hid.devices. +static void usb_hid_set_devices_from_hid_devices(void) { + mp_obj_t tuple_items[num_hid_devices]; + for (mp_int_t i = 0; i < num_hid_devices; i++) { + tuple_items[i] = &hid_devices[i]; + } + hid_devices_tuple = mp_obj_new_tuple(num_hid_devices, tuple_items); + usb_hid_set_devices(hid_devices_tuple); +} + +bool common_hal_usb_hid_disable(void) { + return common_hal_usb_hid_enable(mp_const_empty_tuple, 0); +} + +bool common_hal_usb_hid_enable(const mp_obj_t devices, uint8_t boot_device) { + // We can't change the devices once USB is connected. + if (hid_interface_ready) { + return false; + } + + const mp_int_t num_devices = MP_OBJ_SMALL_INT_VALUE(mp_obj_len(devices)); + mp_arg_validate_length_max(num_devices, MAX_HID_DEVICES, MP_QSTR_devices); + + num_hid_devices = num_devices; + hid_boot_device = boot_device; + + // Remember the devices in static storage so they live across VMs. + for (mp_int_t i = 0; i < num_hid_devices; i++) { + usb_hid_device_obj_t *device = + MP_OBJ_TO_PTR(mp_obj_subscr(devices, MP_OBJ_NEW_SMALL_INT(i), MP_OBJ_SENTINEL)); + memcpy(&hid_devices[i], device, sizeof(usb_hid_device_obj_t)); + } + + usb_hid_set_devices_from_hid_devices(); + + return true; +} + +// Called when HID devices are ready to be used, when code.py or the REPL starts running. +void usb_hid_setup_devices(void) { + // If the host requested a boot device, replace the current list of devices + // with a single-element tuple containing the proper boot device. + if (hid_boot_device_requested) { + memcpy(&hid_devices[0], + hid_boot_device == 1 ? &boot_keyboard_obj : &boot_mouse_obj, + sizeof(usb_hid_device_obj_t)); + num_hid_devices = 1; + } + + usb_hid_set_devices_from_hid_devices(); + + // Create report buffers on the heap. + for (mp_int_t i = 0; i < num_hid_devices; i++) { + usb_hid_device_create_report_buffers(&hid_devices[i]); + } +} + +// Build the combined HID report descriptor from all devices. +static uint8_t *hid_report_descriptor = NULL; + +size_t usb_hid_report_descriptor_length(void) { + size_t total_hid_report_descriptor_length = 0; + for (mp_int_t i = 0; i < num_hid_devices; i++) { + total_hid_report_descriptor_length += hid_devices[i].report_descriptor_length; + } + return total_hid_report_descriptor_length; +} + +void usb_hid_build_report_descriptor(void) { + if (!usb_hid_enabled()) { + return; + } + size_t report_length = usb_hid_report_descriptor_length(); + hid_report_descriptor = port_malloc(report_length, false); + if (hid_report_descriptor == NULL) { + return; + } + + uint8_t *report_descriptor_start = hid_report_descriptor; + for (mp_int_t i = 0; i < num_hid_devices; i++) { + usb_hid_device_obj_t *device = &hid_devices[i]; + memcpy(report_descriptor_start, device->report_descriptor, device->report_descriptor_length); + report_descriptor_start += device->report_descriptor_length; + // Clear the heap pointer to the bytes of the descriptor. + device->report_descriptor = NULL; + } +} + +void usb_hid_gc_collect(void) { + gc_collect_ptr(hid_devices_tuple); + + for (mp_int_t device_idx = 0; device_idx < num_hid_devices; device_idx++) { + gc_collect_ptr((void *)hid_devices[device_idx].report_descriptor); + + for (size_t id_idx = 0; id_idx < hid_devices[device_idx].num_report_ids; id_idx++) { + gc_collect_ptr(hid_devices[device_idx].in_report_buffers[id_idx]); + gc_collect_ptr(hid_devices[device_idx].out_report_buffers[id_idx]); + } + } +} + +bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t **device_out, size_t *id_idx_out) { + for (uint8_t device_idx = 0; device_idx < num_hid_devices; device_idx++) { + usb_hid_device_obj_t *device = &hid_devices[device_idx]; + for (size_t id_idx = 0; id_idx < device->num_report_ids; id_idx++) { + if (device->report_ids[id_idx] == report_id) { + *device_out = device; + *id_idx_out = id_idx; + return true; + } + } + } + return false; +} + +// ===== Zephyr USBD HID Device Callbacks ===== + +static void hid_iface_ready(const struct device *dev, const bool ready) { + hid_interface_ready = ready; +} + +static int hid_get_report(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, uint8_t *const buf) { + // Support Input Report and Feature Report + if (type != HID_REPORT_TYPE_INPUT && type != HID_REPORT_TYPE_FEATURE) { + return -ENOTSUP; + } + + usb_hid_device_obj_t *hid_device; + size_t id_idx; + if (!usb_hid_get_device_with_report_id(id, &hid_device, &id_idx)) { + return 0; + } + if (!hid_device->in_report_buffers[id_idx]) { + return 0; + } + + uint8_t in_len = hid_device->in_report_lengths[id_idx]; + const uint8_t *src = hid_device->in_report_buffers[id_idx]; + + // When the descriptor uses Report IDs (id != 0), the on-wire report is + // prefixed with the Report ID byte. Zephyr sends the buffer verbatim, so + // prepend the ID here. id == 0 means no Report ID item -> no prefix. + if (id != 0) { + if (len == 0) { + return 0; + } + buf[0] = id; + uint16_t copy_len = len - 1; + if (copy_len > in_len) { + copy_len = in_len; + } + memcpy(&buf[1], src, copy_len); + return 1 + copy_len; + } + + uint16_t copy_len = len; + if (copy_len > in_len) { + copy_len = in_len; + } + memcpy(buf, src, copy_len); + return copy_len; +} + +static int hid_set_report(const struct device *dev, + const uint8_t type, const uint8_t id, + const uint16_t len, const uint8_t *const buf) { + uint8_t report_id = id; + const uint8_t *data = buf; + uint16_t data_len = len; + + if (report_id != 0 && len > 0) { + // Descriptor uses Report IDs: the on-wire SET_REPORT data stage is + // prefixed with the Report ID byte. Zephyr passes the raw payload, so + // strip the leading ID byte (it should match the id from wValue). + if (buf[0] == report_id) { + data = &buf[1]; + data_len = len - 1; + } + } else if (report_id == 0 && len > 0) { + // id==0 normally means no Report ID item (no prefix). But if no device + // has report ID 0 with a matching out length, treat the first byte as a + // report ID (host sent a prefixed report despite id==0). + usb_hid_device_obj_t *hid0 = NULL; + size_t idx0; + if (!(usb_hid_get_device_with_report_id(0, &hid0, &idx0) && + hid0 && hid0->out_report_buffers[idx0] && + hid0->out_report_lengths[idx0] == len)) { + report_id = buf[0]; + data = &buf[1]; + data_len = len - 1; + } + } + + // Look up the device for the resolved report_id. + usb_hid_device_obj_t *hid_device = NULL; + size_t id_idx; + if (!usb_hid_get_device_with_report_id(report_id, &hid_device, &id_idx)) { + return -EINVAL; + } + + if (hid_device->out_report_buffers[id_idx] && + hid_device->out_report_lengths[id_idx] == data_len) { + memcpy(hid_device->out_report_buffers[id_idx], data, data_len); + hid_device->out_report_buffers_updated[id_idx] = true; + return 0; + } + + return -EINVAL; +} + +static void hid_set_protocol(const struct device *dev, const uint8_t proto) { + hid_boot_device_requested = (proto == HID_PROTOCOL_BOOT); +} + +static struct hid_device_ops hid_ops = { + .iface_ready = hid_iface_ready, + .get_report = hid_get_report, + .set_report = hid_set_report, + .set_protocol = hid_set_protocol, +}; + +// ===== HID Device Registration ===== + +// Get the Zephyr HID device for submitting reports +static const struct device *hid_zephyr_dev; + +const struct device *usb_hid_get_zephyr_device(void) { + return hid_zephyr_dev; +} + +void usb_hid_init_devices(void) { + if (!usb_hid_enabled()) { + return; + } + + hid_zephyr_dev = DEVICE_DT_GET_ONE(zephyr_hid_device); + if (!device_is_ready(hid_zephyr_dev)) { + return; + } + + usb_hid_build_report_descriptor(); + if (hid_report_descriptor == NULL) { + return; + } + + int ret = hid_device_register(hid_zephyr_dev, + hid_report_descriptor, + usb_hid_report_descriptor_length(), + &hid_ops); + if (ret != 0) { + return; + } +} + +bool usb_hid_ready(void) { + return hid_zephyr_dev != NULL && hid_interface_ready; +} + +// Submit an input report through Zephyr's HID device. +// Called from common_hal_usb_hid_device_send_report(). +bool usb_hid_submit_report(uint8_t report_id, const uint8_t *report, uint8_t len) { + if (hid_zephyr_dev == NULL || !hid_interface_ready) { + return false; + } + + // Send report_id zero without a prefix + if (report_id == 0) { + return hid_device_submit_report(hid_zephyr_dev, len, report) == 0; + } + + uint8_t __attribute__((aligned(sizeof(void *)))) report_buffer[1 + len]; + report_buffer[0] = report_id; + memcpy(&report_buffer[1], report, len); + return hid_device_submit_report(hid_zephyr_dev, len + 1, report_buffer) == 0; +} diff --git a/ports/zephyr-cp/common-hal/usb_hid/__init__.h b/ports/zephyr-cp/common-hal/usb_hid/__init__.h new file mode 100644 index 00000000000..1985ea29549 --- /dev/null +++ b/ports/zephyr-cp/common-hal/usb_hid/__init__.h @@ -0,0 +1,28 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2025 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "shared-module/usb_hid/Device.h" +#include "supervisor/usb.h" + +extern usb_hid_device_obj_t usb_hid_devices[]; + +bool usb_hid_enabled(void); +uint8_t usb_hid_boot_device(void); +void usb_hid_set_defaults(void); +void usb_hid_setup_devices(void); +size_t usb_hid_report_descriptor_length(void); +void usb_hid_build_report_descriptor(void); +bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t **device_out, size_t *id_idx_out); +void usb_hid_gc_collect(void); + +// For supervisor/usb.c integration +void usb_hid_init_devices(void); + +// For Device.c send_report +bool usb_hid_ready(void); +bool usb_hid_submit_report(uint8_t report_id, const uint8_t *report, uint8_t len); diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 72c9071bd81..55c069a1ddc 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -490,6 +490,11 @@ async def build_circuitpython(): # noqa: C901 if usb_ok: enabled_modules.add("usb_cdc") + enabled_modules.add("usb_hid") + + usb_num_endpoint_pairs = board_info.get("usb_num_endpoint_pairs", 4) + circuitpython_flags.append(f"-DUSB_NUM_ENDPOINT_PAIRS={usb_num_endpoint_pairs}") + circuitpython_flags.append("-DCIRCUITPY_USB_HID_ENABLED_DEFAULT=1") for macro in ("USB_PID", "USB_VID"): print(f"Setting {macro} to {mpconfigboard.get(macro)}") @@ -594,6 +599,10 @@ async def build_circuitpython(): # noqa: C901 # Only include shared-module/*.c if no common-hal/*.c files were found if len(hal_source) == len_before or module.name in SHARED_MODULE_AND_COMMON_HAL: hal_source.extend(top.glob(f"shared-module/{module.name}/**/*.c")) + # The USB HID report descriptors are shared with the TinyUSB ports and + # have no common-hal override, so always compile them. + if module.name == "usb_hid": + hal_source.append(top / "shared-module/usb_hid/report_descriptors.c") hal_source.extend(top.glob(f"shared-bindings/{module.name}/**/*.c")) if module.name in LIBRARY_SOURCE: for library_source in LIBRARY_SOURCE[module.name]: diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index a54df43e82f..eb9cd8c52f6 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -17,6 +17,7 @@ CONFIG_EXCEPTION_STACK_TRACE=n CONFIG_USB_DEVICE_STACK_NEXT=y CONFIG_USBD_CDC_ACM_CLASS=y +CONFIG_USBD_HID_SUPPORT=y CONFIG_USBD_MSC_STACK_SIZE=1536 CONFIG_CDC_ACM_SERIAL_INITIALIZE_AT_BOOT=n diff --git a/ports/zephyr-cp/supervisor/usb.c b/ports/zephyr-cp/supervisor/usb.c index a42a5192f4f..bb7f15f056a 100644 --- a/ports/zephyr-cp/supervisor/usb.c +++ b/ports/zephyr-cp/supervisor/usb.c @@ -3,6 +3,10 @@ #include "shared-bindings/usb_cdc/__init__.h" #include "shared-bindings/usb_cdc/Serial.h" +#if CIRCUITPY_USB_HID +#include "common-hal/usb_hid/__init__.h" +#endif + #include "supervisor/zephyr-cp.h" #include "extmod/vfs.h" @@ -189,22 +193,38 @@ int _zephyr_disk_ioctl(struct disk_info *disk, uint8_t cmd, void *buff) { return 0; } +// Tracks whether the USB host has selected a configuration, i.e. the device has +// enumerated. Written from the USBD message callback (USBD thread or system +// workqueue context) and read from the CircuitPython VM thread, so keep it +// volatile to avoid the compiler caching stale values. +static volatile bool usb_configured = false; + static void _msg_cb(struct usbd_context *const ctx, const struct usbd_msg *msg) { LOG_INF("USBD message: %s", usbd_msg_type_string(msg->type)); if (usbd_can_detect_vbus(ctx)) { if (msg->type == USBD_MSG_VBUS_READY) { + usb_configured = false; if (usbd_enable(ctx)) { LOG_ERR("Failed to enable device support"); } } if (msg->type == USBD_MSG_VBUS_REMOVED) { + usb_configured = false; if (usbd_disable(ctx)) { LOG_ERR("Failed to disable device support"); } } } + + // A non-zero configuration value means the host has enumerated us. + // A value of zero (or a bus reset / VBUS removal) unconfigures us. + if (msg->type == USBD_MSG_CONFIGURATION) { + usb_configured = (msg->status != 0); + } else if (msg->type == USBD_MSG_RESET) { + usb_configured = false; + } } void usb_init(void) { @@ -293,6 +313,17 @@ void usb_init(void) { printk("Registered MSC class for high speed\n"); } + #if CIRCUITPY_USB_HID + if (usb_hid_enabled()) { + printk("Registering High-Speed hid class\n"); + err = usbd_register_class(&main_usbd, "hid_0", USBD_SPEED_HS, 1); + if (err) { + printk("Failed to register HID class (HS) %d\n", err); + return; + } + } + #endif + usbd_device_set_code_triple(&main_usbd, USBD_SPEED_HS, USB_BCC_MISCELLANEOUS, 0x02, 0x01); } @@ -334,6 +365,17 @@ void usb_init(void) { } /* doc functions register end */ + #if CIRCUITPY_USB_HID + if (usb_hid_enabled()) { + printk("Registering Full-Speed hid class\n"); + err = usbd_register_class(&main_usbd, "hid_0", USBD_SPEED_FS, 1); + if (err) { + printk("Failed to register HID class (FS) %d\n", err); + return; + } + } + #endif + usbd_device_set_code_triple(&main_usbd, USBD_SPEED_FS, USB_BCC_MISCELLANEOUS, 0x02, 0x01); printk("Setting self powered\n"); @@ -346,6 +388,11 @@ void usb_init(void) { return; } + #if CIRCUITPY_USB_HID + printk("Initializing HID\n"); + usb_hid_init_devices(); + #endif + printk("usbd_init\n"); err = usbd_init(&main_usbd); if (err) { @@ -366,7 +413,8 @@ void usb_init(void) { } bool usb_connected(void) { - return false; + // Mirrors TinyUSB's tud_ready(): configured (mounted) and not suspended. + return usb_configured && !usbd_is_suspended(&main_usbd); } void usb_disconnect(void) { diff --git a/shared-module/usb_hid/Device.c b/shared-module/usb_hid/Device.c index d6c4697210f..42f5790123e 100644 --- a/shared-module/usb_hid/Device.c +++ b/shared-module/usb_hid/Device.c @@ -12,45 +12,10 @@ #include "shared-bindings/usb_hid/Device.h" #include "shared-module/usb_hid/__init__.h" #include "shared-module/usb_hid/Device.h" +#include "shared-module/usb_hid/report_descriptors.h" #include "supervisor/shared/tick.h" #include "tusb.h" -static const uint8_t keyboard_report_descriptor[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x06, // Usage (Keyboard) - 0xA1, 0x01, // Collection (Application) - 0x85, 0x01, // Report ID (1) - 0x05, 0x07, // Usage Page (Kbrd/Keypad) - 0x19, 0xE0, // Usage Minimum (0xE0) - 0x29, 0xE7, // Usage Maximum (0xE7) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x08, // Report Count (8) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x95, 0x01, // Report Count (1) - 0x75, 0x08, // Report Size (8) - 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x95, 0x05, // Report Count (5) - 0x75, 0x01, // Report Size (1) - 0x05, 0x08, // Usage Page (LEDs) - 0x19, 0x01, // Usage Minimum (Num Lock) - 0x29, 0x05, // Usage Maximum (Kana) - 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x95, 0x01, // Report Count (1) - 0x75, 0x03, // Report Size (3) - 0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - 0x95, 0x06, // Report Count (6) - 0x75, 0x08, // Report Size (8) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x05, 0x07, // Usage Page (Kbrd/Keypad) - 0x19, 0x00, // Usage Minimum (0x00) - 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF) - 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, // End Collection -}; - const usb_hid_device_obj_t usb_hid_device_keyboard_obj = { .base = { .type = &usb_hid_device_type, @@ -65,42 +30,6 @@ const usb_hid_device_obj_t usb_hid_device_keyboard_obj = { .out_report_lengths = { 1, }, }; -static const uint8_t mouse_report_descriptor[] = { - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x02, // Usage (Mouse) - 0xA1, 0x01, // Collection (Application) - 0x09, 0x01, // Usage (Pointer) - 0xA1, 0x00, // Collection (Physical) - 0x85, 0x02, // 10, 11 Report ID (2) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (0x01) - 0x29, 0x05, // Usage Maximum (0x05) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x95, 0x05, // Report Count (5) - 0x75, 0x01, // Report Size (1) - 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x95, 0x01, // Report Count (1) - 0x75, 0x03, // Report Size (3) - 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x15, 0x81, // Logical Minimum (-127) - 0x25, 0x7F, // Logical Maximum (127) - 0x75, 0x08, // Report Size (8) - 0x95, 0x02, // Report Count (2) - 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 0x09, 0x38, // Usage (Wheel) - 0x15, 0x81, // Logical Minimum (-127) - 0x25, 0x7F, // Logical Maximum (127) - 0x75, 0x08, // Report Size (8) - 0x95, 0x01, // Report Count (1) - 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, // End Collection - 0xC0, // End Collection -}; - const usb_hid_device_obj_t usb_hid_device_mouse_obj = { .base = { .type = &usb_hid_device_type, @@ -115,21 +44,6 @@ const usb_hid_device_obj_t usb_hid_device_mouse_obj = { .out_report_lengths = { 0, }, }; -static const uint8_t consumer_control_report_descriptor[] = { - 0x05, 0x0C, // Usage Page (Consumer) - 0x09, 0x01, // Usage (Consumer Control) - 0xA1, 0x01, // Collection (Application) - 0x85, 0x03, // Report ID (3) - 0x75, 0x10, // Report Size (16) - 0x95, 0x01, // Report Count (1) - 0x15, 0x01, // Logical Minimum (1) - 0x26, 0x8C, 0x02, // Logical Maximum (652) - 0x19, 0x01, // Usage Minimum (Consumer Control) - 0x2A, 0x8C, 0x02, // Usage Maximum (AC Send) - 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - 0xC0, // End Collection -}; - const usb_hid_device_obj_t usb_hid_device_consumer_control_obj = { .base = { .type = &usb_hid_device_type, diff --git a/shared-module/usb_hid/report_descriptors.c b/shared-module/usb_hid/report_descriptors.c new file mode 100644 index 00000000000..fe629153c78 --- /dev/null +++ b/shared-module/usb_hid/report_descriptors.c @@ -0,0 +1,96 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 hathach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Standard HID report descriptors shared between ports. + +#include "shared-module/usb_hid/report_descriptors.h" + +const uint8_t keyboard_report_descriptor[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x06, // Usage (Keyboard) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x01, // Report ID (1) + 0x05, 0x07, // Usage Page (Kbrd/Keypad) + 0x19, 0xE0, // Usage Minimum (0xE0) + 0x29, 0xE7, // Usage Maximum (0xE7) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x08, // Report Count (8) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x05, 0x08, // Usage Page (LEDs) + 0x19, 0x01, // Usage Minimum (Num Lock) + 0x29, 0x05, // Usage Maximum (Kana) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x01, // Output (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x05, 0x07, // Usage Page (Kbrd/Keypad) + 0x19, 0x00, // Usage Minimum (0x00) + 0x2A, 0xFF, 0x00, // Usage Maximum (0xFF) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection +}; + +const uint8_t mouse_report_descriptor[] = { + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x02, // Usage (Mouse) + 0xA1, 0x01, // Collection (Application) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Physical) + 0x85, 0x02, // 10, 11 Report ID (2) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x05, // Usage Maximum (0x05) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x02, // Report Count (2) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0x09, 0x38, // Usage (Wheel) + 0x15, 0x81, // Logical Minimum (-127) + 0x25, 0x7F, // Logical Maximum (127) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x81, 0x06, // Input (Data,Var,Rel,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection + 0xC0, // End Collection +}; + +const uint8_t consumer_control_report_descriptor[] = { + 0x05, 0x0C, // Usage Page (Consumer) + 0x09, 0x01, // Usage (Consumer Control) + 0xA1, 0x01, // Collection (Application) + 0x85, 0x03, // Report ID (3) + 0x75, 0x10, // Report Size (16) + 0x95, 0x01, // Report Count (1) + 0x15, 0x01, // Logical Minimum (1) + 0x26, 0x8C, 0x02, // Logical Maximum (652) + 0x19, 0x01, // Usage Minimum (Consumer Control) + 0x2A, 0x8C, 0x02, // Usage Maximum (AC Send) + 0x81, 0x00, // Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0xC0, // End Collection +}; diff --git a/shared-module/usb_hid/report_descriptors.h b/shared-module/usb_hid/report_descriptors.h new file mode 100644 index 00000000000..94a9a752f6a --- /dev/null +++ b/shared-module/usb_hid/report_descriptors.h @@ -0,0 +1,19 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2018 hathach for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +// Standard HID report descriptors shared between ports. These are plain byte +// arrays with no dependencies, so ports using TinyUSB and ports using other +// USB stacks can both use them. They are defined in report_descriptors.c. +// The explicit sizes let callers use sizeof() and are checked by the compiler +// against the definitions. + +#pragma once + +#include + +extern const uint8_t keyboard_report_descriptor[67]; +extern const uint8_t mouse_report_descriptor[64]; +extern const uint8_t consumer_control_report_descriptor[25]; diff --git a/supervisor/supervisor.mk b/supervisor/supervisor.mk index 95d651c1541..2d881dfe070 100644 --- a/supervisor/supervisor.mk +++ b/supervisor/supervisor.mk @@ -148,6 +148,7 @@ ifeq ($(CIRCUITPY_TINYUSB),1) shared-bindings/usb_hid/Device.c \ shared-module/usb_hid/__init__.c \ shared-module/usb_hid/Device.c \ + shared-module/usb_hid/report_descriptors.c \ endif From fe448736810b84e3ff1ebd836d4ee2b5ebd480d4 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 14 Aug 2026 15:58:07 -0700 Subject: [PATCH 773/876] Update error message --- devices/ble_hci/common-hal/_bleio/__init__.c | 2 +- locale/circuitpython.pot | 2 +- ports/nordic/common-hal/_bleio/__init__.c | 2 +- ports/zephyr-cp/common-hal/_bleio/Connection.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index f9fdbc50f64..bfe39888753 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -30,7 +30,7 @@ bool vm_used_ble; // switch (sec_status) { // case BLE_GAP_SEC_STATUS_UNSPECIFIED: -// mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored.")); +// mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. The pairing request on the other device may have been declined or ignored.")); // return; // default: // mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unknown security error: 0x%04x"), sec_status); diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 69b9a62bd78..04e901af82d 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1741,7 +1741,7 @@ msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c #: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " +"Unspecified issue. The pairing request on the other device may have been " "declined or ignored." msgstr "" diff --git a/ports/nordic/common-hal/_bleio/__init__.c b/ports/nordic/common-hal/_bleio/__init__.c index 9dc58d7687c..3d76b93ff15 100644 --- a/ports/nordic/common-hal/_bleio/__init__.c +++ b/ports/nordic/common-hal/_bleio/__init__.c @@ -70,7 +70,7 @@ void check_sec_status(uint8_t sec_status) { switch (sec_status) { case BLE_GAP_SEC_STATUS_UNSPECIFIED: - mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored.")); + mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. The pairing request on the other device may have been declined or ignored.")); return; default: mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unknown security error: 0x%04x"), sec_status); diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.c b/ports/zephyr-cp/common-hal/_bleio/Connection.c index 336e90e7674..8381fe28a24 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.c +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -482,7 +482,7 @@ void common_hal_bleio_connection_pair(bleio_connection_internal_t *self, bool bo // string. uint8_t sec_err_code = self->sec_err; if (sec_err_code == BT_SECURITY_ERR_UNSPECIFIED || sec_err_code == 0) { - mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. Can be that the pairing prompt on the other device was declined or ignored.")); + mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unspecified issue. The pairing request on the other device may have been declined or ignored.")); } else { mp_raise_bleio_SecurityError(MP_ERROR_TEXT("Unknown security error: 0x%04x"), sec_err_code); } From 3ce41e2b89bc494b1542f444d08c9f5c5d97f224 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Fri, 14 Aug 2026 18:05:27 -0500 Subject: [PATCH 774/876] Add optimization flags to bradanlanestudio_explorer_rp2040 --- .../boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk index 14f27c07b99..edb4f3bb3d8 100644 --- a/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/bradanlanestudio_explorer_rp2040/mpconfigboard.mk @@ -15,6 +15,9 @@ EXTERNAL_FLASH_DEVICES = "GD25Q64C" CIRCUITPY__EVE = 1 +# The default is -O3. +OPTIMIZATION_FLAGS = -Os + FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_asyncio FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Bitmap_Font FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Display_Shapes From d8f175b8e9fe2501c1d412029570183d680eef7c Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Fri, 14 Aug 2026 18:06:17 -0500 Subject: [PATCH 775/876] Disable msgpack on meowbit_v121 --- ports/stm/boards/meowbit_v121/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/stm/boards/meowbit_v121/mpconfigboard.mk b/ports/stm/boards/meowbit_v121/mpconfigboard.mk index 419f073b5ea..271c4cd775c 100644 --- a/ports/stm/boards/meowbit_v121/mpconfigboard.mk +++ b/ports/stm/boards/meowbit_v121/mpconfigboard.mk @@ -31,6 +31,7 @@ CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_I2CDISPLAYBUS = 0 CIRCUITPY_KEYPAD_DEMUX = 0 +CIRCUITPY_MSGPACK = 0 CIRCUITPY_PIXELMAP = 0 CIRCUITPY_SHARPDISPLAY = 0 CIRCUITPY_TILEPALETTEMAPPER = 0 From 6168024d17ebd1b1fb5c5cde86375037415e60e2 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Sat, 15 Aug 2026 17:10:35 +0200 Subject: [PATCH 776/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 12 ++++-------- locale/el.po | 12 ++++-------- locale/hi.po | 12 ++++-------- locale/ko.po | 12 ++++-------- locale/ru.po | 12 ++++-------- locale/tr.po | 12 ++++-------- 6 files changed, 24 insertions(+), 48 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index a7e3493b360..93fa2190a0e 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -2258,6 +2258,10 @@ msgstr "" msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "Chyba USB" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -3769,10 +3773,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4536,10 +4536,6 @@ msgstr "Konfigurace není nastavena" msgid "USB busy" msgstr "USB zaneprázdněno" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "Chyba USB" - #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" diff --git a/locale/el.po b/locale/el.po index c446385317d..b804ebdc3d0 100644 --- a/locale/el.po +++ b/locale/el.po @@ -2256,6 +2256,10 @@ msgstr "" msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -3768,10 +3772,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4535,10 +4535,6 @@ msgstr "" msgid "USB busy" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "" - #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" diff --git a/locale/hi.po b/locale/hi.po index ead0359e102..3014ebf7b3f 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -2246,6 +2246,10 @@ msgstr "" msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -3751,10 +3755,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4516,10 +4516,6 @@ msgstr "" msgid "USB busy" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "" - #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" diff --git a/locale/ko.po b/locale/ko.po index 7c37326dcaa..0aa358eae68 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -2287,6 +2287,10 @@ msgstr "" msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -3807,10 +3811,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4582,10 +4582,6 @@ msgstr "구성이 설정되어 있지 않습니다" msgid "USB busy" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "" - #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" diff --git a/locale/ru.po b/locale/ru.po index 39a3dcbdc6a..157b4193cff 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -2278,6 +2278,10 @@ msgstr "" msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "Ошибка USB" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -3810,10 +3814,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4600,10 +4600,6 @@ msgstr "Нет конфигураций" msgid "USB busy" msgstr "USB занят" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "Ошибка USB" - #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" diff --git a/locale/tr.po b/locale/tr.po index a77f902bf49..6606f030a2b 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -2263,6 +2263,10 @@ msgstr "" msgid "SocketPool can only be used with wifi.radio or hostnetwork.HostNetwork" msgstr "" +#: ports/zephyr-cp/common-hal/usb_hid/Device.c shared-module/usb_hid/Device.c +msgid "USB error" +msgstr "" + #: ports/zephyr-cp/common-hal/wifi/Radio.c msgid "Failed to set hostname" msgstr "" @@ -3769,10 +3773,6 @@ msgstr "" msgid "bits_per_sample must be 16" msgstr "" -#: shared-bindings/audioi2sin/I2SIn.c -msgid "%q requires %q" -msgstr "" - #: shared-bindings/audioi2sin/I2SIn.c #, c-format msgid "invalid destination buffer, must be an array of type: %c" @@ -4539,10 +4539,6 @@ msgstr "" msgid "USB busy" msgstr "" -#: shared-module/usb_hid/Device.c -msgid "USB error" -msgstr "" - #: shared-module/vectorio/Circle.c shared-module/vectorio/Polygon.c #: shared-module/vectorio/Rectangle.c msgid "can only have one parent" From 42f4ba116fe5d9f0a7a69faaed40a146121ad846 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Sat, 15 Aug 2026 17:50:31 +0000 Subject: [PATCH 777/876] displayio: drop contained dirty rectangles in Group Reduce the refresh list in displayio_group_get_refresh_areas: unlink every area fully contained in another one, so covered pixels are composited and transmitted once instead of once per rectangle. The recursive list builder becomes a static _impl and the public name wraps it, so the reduction runs once on the root group's list and displays need no changes. Only the .next links are rewritten; the item-owned coordinates are never touched. Measured on an ST7789 BusDisplay changing 2-digit scaled text labels: scale 20 (the reported case) 1.75 -> 3.45 fps, scale 8 10.5 -> 19.8 fps; two stacked full-screen bitmaps 1.05 -> 1.75 fps. --- shared-module/busdisplay/BusDisplay.c | 18 +---- shared-module/displayio/Group.c | 69 ++++++++++++++++++- shared-module/displayio/area.c | 25 ------- shared-module/displayio/area.h | 2 - shared-module/displayio/display_core.c | 27 -------- shared-module/displayio/display_core.h | 5 -- shared-module/epaperdisplay/EPaperDisplay.c | 17 +---- .../framebufferio/FramebufferDisplay.c | 17 +---- 8 files changed, 76 insertions(+), 104 deletions(-) diff --git a/shared-module/busdisplay/BusDisplay.c b/shared-module/busdisplay/BusDisplay.c index db730e6fd9f..01e0f7a7896 100644 --- a/shared-module/busdisplay/BusDisplay.c +++ b/shared-module/busdisplay/BusDisplay.c @@ -327,21 +327,9 @@ static void _refresh_display(busdisplay_busdisplay_obj_t *self) { } const displayio_area_t *current_area = _get_refresh_areas(self); - - // Merge overlapping dirty rectangles so shared pixels are computed and sent once - // (see displayio_display_core_merge_refresh_areas). - displayio_area_t merged[DISPLAYIO_MAX_MERGE_AREAS]; - size_t merged_count; - if (displayio_display_core_merge_refresh_areas(&self->core, current_area, merged, - DISPLAYIO_MAX_MERGE_AREAS, &merged_count)) { - for (size_t i = 0; i < merged_count; i++) { - _refresh_area(self, &merged[i]); - } - } else { - while (current_area != NULL) { - _refresh_area(self, current_area); - current_area = current_area->next; - } + while (current_area != NULL) { + _refresh_area(self, current_area); + current_area = current_area->next; } displayio_display_core_finish_refresh(&self->core); } diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index a2bf685d0f7..fb0ebc18d3d 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -435,7 +435,7 @@ void displayio_group_finish_refresh(displayio_group_t *self) { } } -displayio_area_t *displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t *tail) { +static displayio_area_t *group_get_refresh_areas_impl(displayio_group_t *self, displayio_area_t *tail) { if (self->item_removed) { self->dirty_area.next = tail; tail = &self->dirty_area; @@ -462,10 +462,75 @@ displayio_area_t *displayio_group_get_refresh_areas(displayio_group_t *self, dis layer = mp_obj_cast_to_native_base( self->members->items[i], &displayio_group_type); if (layer != MP_OBJ_NULL) { - tail = displayio_group_get_refresh_areas(layer, tail); + tail = group_get_refresh_areas_impl(layer, tail); continue; } } return tail; } + +// Merge the dirty-rect list by containment: unlink every area that is fully contained +// in another area in the list (a changing text label is the common case - the group +// dirties the whole label region via item_removed plus one area per glyph, and the +// glyph areas all sit inside the label region). Dropping a covered area is lossless: +// the same pixels are refreshed by the survivor, in fewer transfers. +// +// The nodes are OWNED BY THE ITEMS (TileGrid reuses dirty_area as its tile-space dirty +// accumulator between frames, vectorio keeps its current_area, ...), so their +// coordinates must never be modified here. The ONLY mutation is the .next relink, +// which is safe because every provider unconditionally reassigns .next at link time on +// every get_refresh_areas call and never reads it back. +// +// Nodes at and past `tail` belong to the caller, so the sweep uses `tail` as its end +// sentinel and never looks past it (every in-tree caller passes tail == NULL). +// +// One pass suffices: coordinates never change and unlinking preserves the relative +// order of the remaining nodes, so every pair of surviving nodes is examined. Equal +// areas satisfy the containment test in both directions; testing b-inside-a FIRST +// keeps the earlier node and drops the later one - the two tests must stay an else-if +// chain or equal areas would drop BOTH nodes and lose the area entirely. +static displayio_area_t *group_relink_refresh_areas(displayio_area_t *head, + const displayio_area_t *tail) { + displayio_area_t *a_prev = NULL; + displayio_area_t *a = head; + while (a != tail) { + // The casts from the const .next field are safe: every node before `tail` is a + // mutable item-owned struct; only the field's declared type is pointer-to-const. + displayio_area_t *b_prev = a; + displayio_area_t *b = (displayio_area_t *)a->next; + bool a_dropped = false; + while (b != tail) { + if (b->x1 >= a->x1 && b->y1 >= a->y1 && b->x2 <= a->x2 && b->y2 <= a->y2) { + // b is contained in a (equal areas land here): unlink b. + b_prev->next = b->next; + b = (displayio_area_t *)b_prev->next; + } else if (a->x1 >= b->x1 && a->y1 >= b->y1 && a->x2 <= b->x2 && a->y2 <= b->y2) { + // a is strictly contained in the later b: unlink a and move on. + if (a_prev == NULL) { + head = (displayio_area_t *)a->next; + } else { + a_prev->next = a->next; + } + a_dropped = true; + break; + } else { + b_prev = b; + b = (displayio_area_t *)b->next; + } + } + if (a_dropped) { + a = (a_prev == NULL) ? head : (displayio_area_t *)a_prev->next; + } else { + a_prev = a; + a = (displayio_area_t *)a->next; + } + } + return head; +} + +// Public entry point: displays call this once on their root group, so the whole tree's +// list is merged in one place and no display type needs its own copy of the logic. +displayio_area_t *displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t *tail) { + return group_relink_refresh_areas(group_get_refresh_areas_impl(self, tail), tail); +} diff --git a/shared-module/displayio/area.c b/shared-module/displayio/area.c index fb2e1e5712c..6a79e2aeeea 100644 --- a/shared-module/displayio/area.c +++ b/shared-module/displayio/area.c @@ -104,31 +104,6 @@ uint32_t displayio_area_size(const displayio_area_t *area) { return displayio_area_width(area) * displayio_area_height(area); } -// Greedily fuse any pair of areas whose bounding box is smaller than the two areas summed - -// i.e. they overlap enough that one rectangle covers fewer pixels than two. Distant and -// merely touching rectangles are left separate (their bounding box would not be smaller), so -// the result never covers more pixels than the input. Runs in place; returns the new count. -size_t displayio_area_array_merge_overlapping(displayio_area_t *areas, size_t count) { - bool changed = true; - while (changed) { - changed = false; - for (size_t i = 0; i < count && !changed; i++) { - for (size_t j = i + 1; j < count; j++) { - displayio_area_t u; - displayio_area_union(&areas[i], &areas[j], &u); - if (displayio_area_size(&u) < displayio_area_size(&areas[i]) + displayio_area_size(&areas[j])) { - areas[i] = u; // fuse j into i - areas[j] = areas[count - 1]; // swap-remove j - count--; - changed = true; - break; - } - } - } - } - return count; -} - bool displayio_area_equal(const displayio_area_t *a, const displayio_area_t *b) { return a->x1 == b->x1 && a->y1 == b->y1 && diff --git a/shared-module/displayio/area.h b/shared-module/displayio/area.h index 93e427035ad..eed54613a5a 100644 --- a/shared-module/displayio/area.h +++ b/shared-module/displayio/area.h @@ -6,7 +6,6 @@ #pragma once -#include #include #include @@ -51,7 +50,6 @@ bool displayio_area_compute_overlap(const displayio_area_t *a, uint16_t displayio_area_width(const displayio_area_t *area); uint16_t displayio_area_height(const displayio_area_t *area); uint32_t displayio_area_size(const displayio_area_t *area); -size_t displayio_area_array_merge_overlapping(displayio_area_t *areas, size_t count); bool displayio_area_equal(const displayio_area_t *a, const displayio_area_t *b); void displayio_area_transform_within(bool mirror_x, bool mirror_y, bool transpose_xy, const displayio_area_t *original, diff --git a/shared-module/displayio/display_core.c b/shared-module/displayio/display_core.c index 70cdb0b3607..dfcddde7796 100644 --- a/shared-module/displayio/display_core.c +++ b/shared-module/displayio/display_core.c @@ -203,30 +203,3 @@ bool displayio_display_core_clip_area(displayio_display_core_t *self, const disp } return true; } - -// Clip the collected refresh areas and merge the overlapping ones so shared pixels are -// computed and sent once. displayio does not merge areas as it collects them, so -// overlapping/nested ones get their common pixels reprocessed per rectangle (and drawn as -// separate, visibly sequential passes). A changing text label is the common case: it -// dirties the whole label area AND each glyph, so the glyph rectangles sit inside the -// label rectangle and nearly double the work. Only pairs whose bounding box is smaller -// than the two areas summed are fused, so the result never covers more pixels than the -// unmerged list. Returns false when there are more areas than `max_areas` (rare) - the -// caller should then refresh the raw list unmerged. -bool displayio_display_core_merge_refresh_areas(displayio_display_core_t *self, - const displayio_area_t *areas, displayio_area_t *merged, size_t max_areas, size_t *count_out) { - size_t count = 0; - for (const displayio_area_t *a = areas; a != NULL; a = a->next) { - displayio_area_t clipped; - if (!displayio_display_core_clip_area(self, a, &clipped)) { - continue; - } - if (count >= max_areas) { - return false; - } - merged[count] = clipped; - count++; - } - *count_out = displayio_area_array_merge_overlapping(merged, count); - return true; -} diff --git a/shared-module/displayio/display_core.h b/shared-module/displayio/display_core.h index fd93c617657..f3fe2023636 100644 --- a/shared-module/displayio/display_core.h +++ b/shared-module/displayio/display_core.h @@ -51,8 +51,3 @@ void displayio_display_core_collect_ptrs(displayio_display_core_t *self); bool displayio_display_core_fill_area(displayio_display_core_t *self, displayio_area_t *area, uint32_t *mask, uint32_t *buffer); bool displayio_display_core_clip_area(displayio_display_core_t *self, const displayio_area_t *area, displayio_area_t *clipped); - -// Scratch size for displayio_display_core_merge_refresh_areas(). -#define DISPLAYIO_MAX_MERGE_AREAS 16 -bool displayio_display_core_merge_refresh_areas(displayio_display_core_t *self, - const displayio_area_t *areas, displayio_area_t *merged, size_t max_areas, size_t *count_out); diff --git a/shared-module/epaperdisplay/EPaperDisplay.c b/shared-module/epaperdisplay/EPaperDisplay.c index 327df929c19..d34be9d5c7c 100644 --- a/shared-module/epaperdisplay/EPaperDisplay.c +++ b/shared-module/epaperdisplay/EPaperDisplay.c @@ -458,20 +458,9 @@ bool common_hal_epaperdisplay_epaperdisplay_refresh(epaperdisplay_epaperdisplay_ } epaperdisplay_epaperdisplay_start_refresh(self); - // Merge overlapping dirty rectangles so shared pixels are only written once - // (see displayio_display_core_merge_refresh_areas). - displayio_area_t merged[DISPLAYIO_MAX_MERGE_AREAS]; - size_t merged_count; - if (displayio_display_core_merge_refresh_areas(&self->core, current_area, merged, - DISPLAYIO_MAX_MERGE_AREAS, &merged_count)) { - for (size_t i = 0; i < merged_count; i++) { - epaperdisplay_epaperdisplay_refresh_area(self, &merged[i]); - } - } else { - while (current_area != NULL) { - epaperdisplay_epaperdisplay_refresh_area(self, current_area); - current_area = current_area->next; - } + while (current_area != NULL) { + epaperdisplay_epaperdisplay_refresh_area(self, current_area); + current_area = current_area->next; } epaperdisplay_epaperdisplay_finish_refresh(self); return true; diff --git a/shared-module/framebufferio/FramebufferDisplay.c b/shared-module/framebufferio/FramebufferDisplay.c index 691fb310730..8116f4b0347 100644 --- a/shared-module/framebufferio/FramebufferDisplay.c +++ b/shared-module/framebufferio/FramebufferDisplay.c @@ -228,20 +228,9 @@ static void _refresh_display(framebufferio_framebufferdisplay_obj_t *self) { uint8_t dirty_row_bitmask[(row_count + 7) / 8]; memset(dirty_row_bitmask, 0, sizeof(dirty_row_bitmask)); self->framebuffer_protocol->get_bufinfo(self->framebuffer, &self->bufinfo); - // Merge overlapping dirty rectangles so shared pixels are only rendered once - // (see displayio_display_core_merge_refresh_areas). - displayio_area_t merged[DISPLAYIO_MAX_MERGE_AREAS]; - size_t merged_count; - if (displayio_display_core_merge_refresh_areas(&self->core, current_area, merged, - DISPLAYIO_MAX_MERGE_AREAS, &merged_count)) { - for (size_t i = 0; i < merged_count; i++) { - _refresh_area(self, &merged[i], dirty_row_bitmask); - } - } else { - while (current_area != NULL) { - _refresh_area(self, current_area, dirty_row_bitmask); - current_area = current_area->next; - } + while (current_area != NULL) { + _refresh_area(self, current_area, dirty_row_bitmask); + current_area = current_area->next; } self->framebuffer_protocol->swapbuffers(self->framebuffer, dirty_row_bitmask); } From ccb521f883946ae84b8f88af43ab3f66431879d7 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Mon, 17 Aug 2026 18:55:36 +0200 Subject: [PATCH 778/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 28 +++++++++++++++++----------- locale/el.po | 28 +++++++++++++++++----------- locale/hi.po | 28 +++++++++++++++++----------- locale/ko.po | 28 +++++++++++++++++----------- locale/ru.po | 37 ++++++++++++++++++++++++------------- locale/tr.po | 28 +++++++++++++++++----------- 6 files changed, 109 insertions(+), 68 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index 93fa2190a0e..b2bc2f7328e 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1693,7 +1693,8 @@ msgstr "Chyba alokace paměti WiFi" msgid "Only IPv4 addresses supported" msgstr "Pouze IPv4 adresy podporovány" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" msgstr "Musí poskytnout pin MISO nebo MOSI" @@ -1751,12 +1752,14 @@ msgid "Unknown gatt error: 0x%04x" msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " +"Unspecified issue. The pairing request on the other device may have been " "declined or ignored." msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c #, c-format msgid "Unknown security error: 0x%04x" msgstr "Neznámá bezpečnostní chyba: 0x%04x" @@ -1857,6 +1860,17 @@ msgstr "" msgid "In-buffer elements must be <= 4 bytes long" msgstr "Elementy v bufferu musí být <= 4 bajty" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Funkce vyžaduje zámek" + +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" @@ -3756,6 +3770,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c #: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c @@ -3782,15 +3797,6 @@ msgstr "" msgid "%q and %q must be different" msgstr "%q a %q musí být rozdílné" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Funkce vyžaduje zámek" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " diff --git a/locale/el.po b/locale/el.po index b804ebdc3d0..813abeafc43 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1694,7 +1694,8 @@ msgstr "" msgid "Only IPv4 addresses supported" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" msgstr "" @@ -1750,12 +1751,14 @@ msgid "Unknown gatt error: 0x%04x" msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " +"Unspecified issue. The pairing request on the other device may have been " "declined or ignored." msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c #, c-format msgid "Unknown security error: 0x%04x" msgstr "" @@ -1856,6 +1859,17 @@ msgstr "" msgid "In-buffer elements must be <= 4 bytes long" msgstr "" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "" + +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" @@ -3755,6 +3769,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c #: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c @@ -3781,15 +3796,6 @@ msgstr "" msgid "%q and %q must be different" msgstr "%q και %q πρεπει να είναι διαφορετικά" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " diff --git a/locale/hi.po b/locale/hi.po index 3014ebf7b3f..2dbf6c69246 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1684,7 +1684,8 @@ msgstr "" msgid "Only IPv4 addresses supported" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" msgstr "" @@ -1740,12 +1741,14 @@ msgid "Unknown gatt error: 0x%04x" msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " +"Unspecified issue. The pairing request on the other device may have been " "declined or ignored." msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c #, c-format msgid "Unknown security error: 0x%04x" msgstr "" @@ -1846,6 +1849,17 @@ msgstr "" msgid "In-buffer elements must be <= 4 bytes long" msgstr "" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "" + +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" @@ -3738,6 +3752,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c #: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c @@ -3764,15 +3779,6 @@ msgstr "" msgid "%q and %q must be different" msgstr "" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " diff --git a/locale/ko.po b/locale/ko.po index 0aa358eae68..bd5ed5f648c 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1707,7 +1707,8 @@ msgstr "Wifi 메모리 할당에 실패했습니다" msgid "Only IPv4 addresses supported" msgstr "IPv4 주소만 지원됩니다" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" msgstr "MISO 또는 MOSI 핀을 제공해야 합니다" @@ -1765,12 +1766,14 @@ msgid "Unknown gatt error: 0x%04x" msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " +"Unspecified issue. The pairing request on the other device may have been " "declined or ignored." msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c #, c-format msgid "Unknown security error: 0x%04x" msgstr "" @@ -1872,6 +1875,17 @@ msgstr "출력 버퍼 요소의 길이는 <= 4 바이트 여야 합니다" msgid "In-buffer elements must be <= 4 bytes long" msgstr "버퍼 내 요소 길이는 <= 4여야 합니다" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "이 함수에는 잠금이 필요합니다" + +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" @@ -3794,6 +3808,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c #: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c @@ -3820,15 +3835,6 @@ msgstr "" msgid "%q and %q must be different" msgstr "%q와 %q는 달라야 합니다" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "이 함수에는 잠금이 필요합니다" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " diff --git a/locale/ru.po b/locale/ru.po index 157b4193cff..a3d012bef95 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1702,7 +1702,8 @@ msgstr "Не удалось выделить память Wifi" msgid "Only IPv4 addresses supported" msgstr "Поддерживаются только адреса IPv4" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" msgstr "Пин MISO или MOSI должен быть предоставлен" @@ -1760,14 +1761,14 @@ msgid "Unknown gatt error: 0x%04x" msgstr "Неизвестная ошибка gatt: 0x%04x" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " +"Unspecified issue. The pairing request on the other device may have been " "declined or ignored." msgstr "" -"Неуказанная проблема. Возможно, запрос на сопряжение на другом устройстве " -"был отклонен или проигнорирован." #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c #, c-format msgid "Unknown security error: 0x%04x" msgstr "Неизвестная ошибка безопасности: 0x%04x" @@ -1872,6 +1873,17 @@ msgstr "Элементы вне буфера должны иметь длину msgid "In-buffer elements must be <= 4 bytes long" msgstr "Элементы буфера должны быть длиной <= 4 байта" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Функция требует блокировки" + +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "Буферные фрагменты должны быть одинаковой длины" + #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" @@ -3797,6 +3809,7 @@ msgid "file must be a file opened in byte mode" msgstr "Файл должен быть файлом, открытым в байтовом режиме" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c #: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c @@ -3823,15 +3836,6 @@ msgstr "" msgid "%q and %q must be different" msgstr "%q и %q должны быть разными" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Функция требует блокировки" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "Буферные фрагменты должны быть одинаковой длины" - #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " @@ -4750,6 +4754,13 @@ msgstr "выключить" msgid "No IP" msgstr "Нет IP" +#~ msgid "" +#~ "Unspecified issue. Can be that the pairing prompt on the other device was " +#~ "declined or ignored." +#~ msgstr "" +#~ "Неуказанная проблема. Возможно, запрос на сопряжение на другом устройстве " +#~ "был отклонен или проигнорирован." + #, c-format #~ msgid "SDIO Init Error %x" #~ msgstr "Ошибка инициализации SDIO %x" diff --git a/locale/tr.po b/locale/tr.po index 6606f030a2b..55bee1fda23 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1698,7 +1698,8 @@ msgstr "" msgid "Only IPv4 addresses supported" msgstr "" -#: ports/mimxrt10xx/common-hal/busio/SPI.c shared-bindings/busio/SPI.c +#: ports/mimxrt10xx/common-hal/busio/SPI.c +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/busio/SPI.c msgid "Must provide MISO or MOSI pin" msgstr "" @@ -1756,12 +1757,14 @@ msgid "Unknown gatt error: 0x%04x" msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c msgid "" -"Unspecified issue. Can be that the pairing prompt on the other device was " +"Unspecified issue. The pairing request on the other device may have been " "declined or ignored." msgstr "" #: ports/nordic/common-hal/_bleio/__init__.c +#: ports/zephyr-cp/common-hal/_bleio/Connection.c #, c-format msgid "Unknown security error: 0x%04x" msgstr "" @@ -1862,6 +1865,17 @@ msgstr "" msgid "In-buffer elements must be <= 4 bytes long" msgstr "Buffer öğeleri <=4 bayt uzunluğunda olmalı" +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/I2C.c +#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/I2C.c +#: shared-bindings/busio/SPI.c +msgid "Function requires lock" +msgstr "Fonksiyon kilit gerektirir" + +#: ports/raspberrypi/bindings/wiznet/PIO_SPI.c shared-bindings/bitbangio/SPI.c +#: shared-bindings/busio/SPI.c +msgid "buffer slices must be of equal length" +msgstr "" + #: ports/raspberrypi/common-hal/alarm/touch/TouchAlarm.c #: ports/stm/common-hal/alarm/touch/TouchAlarm.c msgid "Touch alarms not available" @@ -3756,6 +3770,7 @@ msgid "file must be a file opened in byte mode" msgstr "" #: shared-bindings/audiodelays/Chorus.c shared-bindings/audiodelays/Echo.c +#: shared-bindings/audiodelays/Flanger.c #: shared-bindings/audiodelays/GranularPitchShift.c #: shared-bindings/audiodelays/MultiTapDelay.c #: shared-bindings/audiodelays/PitchShift.c @@ -3782,15 +3797,6 @@ msgstr "" msgid "%q and %q must be different" msgstr "%q ve %q farklı olmalılar" -#: shared-bindings/bitbangio/I2C.c shared-bindings/bitbangio/SPI.c -#: shared-bindings/busio/I2C.c shared-bindings/busio/SPI.c -msgid "Function requires lock" -msgstr "Fonksiyon kilit gerektirir" - -#: shared-bindings/bitbangio/SPI.c shared-bindings/busio/SPI.c -msgid "buffer slices must be of equal length" -msgstr "" - #: shared-bindings/bitmapfilter/__init__.c msgid "" "weights must be a sequence with an odd square number of elements (usually 9 " From e4c6393f07903e74aee228962eac622d2c2b14cf Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 4 Aug 2026 06:30:37 -0700 Subject: [PATCH 779/876] tools: fix ci_changes_per_commit.py crash on null workflowRun check_suite["workflowRun"] is null for check suites that are not attached to a workflow run, for example one that was deleted or one belonging to an app integration. get_commit_depth_and_check_suite() dereferenced it unconditionally: TypeError: 'NoneType' object is not subscriptable which fails the scheduler job's Get-last-commit-with-checks step. Skip those entries rather than indexing into them. --- tools/ci_changes_per_commit.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/ci_changes_per_commit.py b/tools/ci_changes_per_commit.py index 6cbd475fa95..71cfb36cf27 100644 --- a/tools/ci_changes_per_commit.py +++ b/tools/ci_changes_per_commit.py @@ -155,6 +155,11 @@ def get_commit_depth_and_check_suite(query_commits): check_suites = commit["checkSuites"] if check_suites["totalCount"] > 0: for check_suite in check_suites["nodes"]: + # workflowRun is null for check suites not attached to + # a workflow run, such as one that was deleted or one + # belonging to an app integration. + if check_suite["workflowRun"] is None: + continue if check_suite["workflowRun"]["workflow"]["name"] == "Build CI": return [ {"sha": commit_sha, "depth": commit_depth}, From 740672cec7b5f6637867534fc11be7139f18369c Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Mon, 17 Aug 2026 20:42:16 +0000 Subject: [PATCH 780/876] displayio: name the area filter for what it does Review: filter_out_redundant_areas (no group_ prefix on a static), and the public wrapper reads better with the built list in a named variable. --- shared-module/displayio/Group.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/shared-module/displayio/Group.c b/shared-module/displayio/Group.c index fb0ebc18d3d..84ebffdab6d 100644 --- a/shared-module/displayio/Group.c +++ b/shared-module/displayio/Group.c @@ -470,7 +470,7 @@ static displayio_area_t *group_get_refresh_areas_impl(displayio_group_t *self, d return tail; } -// Merge the dirty-rect list by containment: unlink every area that is fully contained +// Filter the dirty-rect list by containment: unlink every area that is fully contained // in another area in the list (a changing text label is the common case - the group // dirties the whole label region via item_removed plus one area per glyph, and the // glyph areas all sit inside the label region). Dropping a covered area is lossless: @@ -490,7 +490,7 @@ static displayio_area_t *group_get_refresh_areas_impl(displayio_group_t *self, d // areas satisfy the containment test in both directions; testing b-inside-a FIRST // keeps the earlier node and drops the later one - the two tests must stay an else-if // chain or equal areas would drop BOTH nodes and lose the area entirely. -static displayio_area_t *group_relink_refresh_areas(displayio_area_t *head, +static displayio_area_t *filter_out_redundant_areas(displayio_area_t *head, const displayio_area_t *tail) { displayio_area_t *a_prev = NULL; displayio_area_t *a = head; @@ -530,7 +530,8 @@ static displayio_area_t *group_relink_refresh_areas(displayio_area_t *head, } // Public entry point: displays call this once on their root group, so the whole tree's -// list is merged in one place and no display type needs its own copy of the logic. +// list is filtered in one place and no display type needs its own copy of the logic. displayio_area_t *displayio_group_get_refresh_areas(displayio_group_t *self, displayio_area_t *tail) { - return group_relink_refresh_areas(group_get_refresh_areas_impl(self, tail), tail); + displayio_area_t *areas = group_get_refresh_areas_impl(self, tail); + return filter_out_redundant_areas(areas, tail); } From 423a88ec31af125615fc8fd441769309b53ecddc Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Mon, 17 Aug 2026 21:21:26 +0000 Subject: [PATCH 781/876] picogame: one file per type, reuse the core error messages Review feedback. The types that were consolidated in __init__.c (Bitmap, Sprite, StripDraw, Triangles, Framebuffer) each get their own shared-bindings file, matching Canvas/Scene/Tilemap/Particles/Display, so __init__.c is the module level only: its docstring, the module functions and the globals table. The docstring now also says how picogame relates to displayio - same display object, different way to drive it, no retained pixels - which is the first thing a reader of that file should learn. The eight error messages the module added are replaced with ones CircuitPython already ships (mp_arg_validate_type / mp_arg_error_invalid / mp_arg_validate_length_min, and m_malloc_fail for the unreachable scene-cap guard): the module now contributes no new strings to the translations. --- locale/circuitpython.pot | 43 +- ports/espressif/common-hal/picogame/Display.c | 4 +- py/circuitpy_defns.mk | 5 + shared-bindings/picogame/Bitmap.c | 219 +++ shared-bindings/picogame/Display.c | 2 +- shared-bindings/picogame/Framebuffer.c | 158 +++ shared-bindings/picogame/Scene.c | 6 +- shared-bindings/picogame/Sprite.c | 598 +++++++++ shared-bindings/picogame/StripDraw.c | 222 ++++ shared-bindings/picogame/StripDraw.h | 11 + shared-bindings/picogame/Triangles.c | 96 ++ shared-bindings/picogame/Triangles.h | 11 + shared-bindings/picogame/__init__.c | 1179 +---------------- shared-bindings/picogame/__init__.h | 3 - 14 files changed, 1358 insertions(+), 1199 deletions(-) create mode 100644 shared-bindings/picogame/Bitmap.c create mode 100644 shared-bindings/picogame/Framebuffer.c create mode 100644 shared-bindings/picogame/Sprite.c create mode 100644 shared-bindings/picogame/StripDraw.c create mode 100644 shared-bindings/picogame/StripDraw.h create mode 100644 shared-bindings/picogame/Triangles.c create mode 100644 shared-bindings/picogame/Triangles.h diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 9a080633d34..31c7b05789c 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -1571,14 +1571,6 @@ msgstr "" msgid "Number of data_pins must be %d or %d, not %d" msgstr "" -#: ports/espressif/common-hal/picogame/Display.c -msgid "rgb444 fast Display not supported on this port yet" -msgstr "" - -#: ports/espressif/common-hal/picogame/Display.c -msgid "fast Display needs a FourWire SPI display" -msgstr "" - #: ports/espressif/common-hal/pulseio/PulseIn.c msgid "pop from an empty PulseIn" msgstr "" @@ -1823,7 +1815,7 @@ msgstr "" #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/__init__.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c #: shared-bindings/supervisor/__init__.c shared-module/audiofilters/Filter.c #: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" @@ -2890,9 +2882,9 @@ msgstr "" msgid "schedule queue full" msgstr "" -#: py/modstruct.c shared-bindings/picogame/Canvas.c -#: shared-bindings/picogame/__init__.c shared-module/picogame/__init__.c -#: shared-module/struct/__init__.c +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c msgid "buffer too small" msgstr "" @@ -4100,36 +4092,11 @@ msgstr "" msgid "Specify exactly one of data0 or data_pins" msgstr "" -#: shared-bindings/picogame/Display.c shared-bindings/picogame/Scene.c -#: shared-bindings/picogame/__init__.c -msgid "expected a BusDisplay" -msgstr "" - -#: shared-bindings/picogame/Scene.c -msgid "scene full" -msgstr "" - -#: shared-bindings/picogame/Scene.c -msgid "item not in scene" -msgstr "" - -#: shared-bindings/picogame/__init__.c shared-module/msgpack/__init__.c +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c #: supervisor/shared/settings.c msgid "Invalid format" msgstr "" -#: shared-bindings/picogame/__init__.c -msgid "PAL8 needs a palette" -msgstr "" - -#: shared-bindings/picogame/__init__.c -msgid "palette is empty" -msgstr "" - -#: shared-bindings/picogame/__init__.c -msgid "expected a Sprite, Tilemap, Particles, Canvas, StripDraw or Triangles" -msgstr "" - #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." msgstr "" diff --git a/ports/espressif/common-hal/picogame/Display.c b/ports/espressif/common-hal/picogame/Display.c index 1c7f834f76d..635549e5918 100644 --- a/ports/espressif/common-hal/picogame/Display.c +++ b/ports/espressif/common-hal/picogame/Display.c @@ -31,14 +31,14 @@ void common_hal_picogame_display_construct(picogame_display_obj_t *self, // ignore it: a no-op would leave the panel in RGB565 while the caller expects 444 (garbled // output / wrong byte count). The rpi backend implements it; until this one does, fail loud. if (rgb444) { - mp_raise_NotImplementedError(MP_ERROR_TEXT("rgb444 fast Display not supported on this port yet")); + mp_arg_error_invalid(MP_QSTR_rgb444); // not implemented on this port yet } self->rgb444 = false; // The fast path queues raw DMA on the display's SPI device; only FourWire // SPI buses expose one. if (!mp_obj_is_type(display->bus.bus, &fourwire_fourwire_type)) { - mp_raise_ValueError(MP_ERROR_TEXT("fast Display needs a FourWire SPI display")); + mp_arg_error_invalid(MP_QSTR_display); // the fast backend drives a FourWire SPI panel only } fourwire_fourwire_obj_t *fw = MP_OBJ_TO_PTR(display->bus.bus); self->spi = common_hal_busio_spi_get_device_handle(fw->bus); diff --git a/py/circuitpy_defns.mk b/py/circuitpy_defns.mk index bf24b737c19..af7b58111b6 100755 --- a/py/circuitpy_defns.mk +++ b/py/circuitpy_defns.mk @@ -642,6 +642,11 @@ endif # All possible sources are listed here, and are filtered by SRC_PATTERNS. SRC_BINDINGS_ENUMS = \ $(filter $(SRC_PATTERNS), \ + picogame/Bitmap.c \ + picogame/Sprite.c \ + picogame/StripDraw.c \ + picogame/Triangles.c \ + picogame/Framebuffer.c \ _bleio/Address.c \ _bleio/Attribute.c \ _bleio/ScanEntry.c \ diff --git a/shared-bindings/picogame/Bitmap.c b/shared-bindings/picogame/Bitmap.c new file mode 100644 index 00000000000..b1199ed97cb --- /dev/null +++ b/shared-bindings/picogame/Bitmap.c @@ -0,0 +1,219 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.Bitmap: pixel data (PAL8 or RGB565) shared by sprites, tilemaps and blits. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// --------------------------------------------------------------------------- +// Bitmap +// --------------------------------------------------------------------------- + +//| class Bitmap: +//| """An image atlas of one or more equal-size frames, of arbitrary size. +//| +//| Unlike ``_stage`` (fixed 16x16 tiles), frames may be any width/height. +//| Pixel data and palette entries must be in the display's wire byte order +//| (use :py:func:`picogame.rgb565` to build colors).""" +//| +//| def __init__( +//| self, +//| data: ReadableBuffer, +//| width: int, +//| height: int, +//| *, +//| format: int = RGB565, +//| palette: Optional[ReadableBuffer] = None, +//| frames: int = 1, +//| stride: int = 0, +//| transparent: Optional[int] = None, +//| ) -> None: ... +//| +static mp_obj_t picogame_bitmap_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_data, ARG_width, ARG_height, ARG_format, ARG_palette, ARG_frames, ARG_stride, ARG_transparent }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PICOGAME_FMT_RGB565} }, + { MP_QSTR_palette, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_frames, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, + { MP_QSTR_stride, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + // bound BEFORE any arithmetic: an unbounded width could overflow width*frames (int32) and wrap + // small, slipping past the size guards below into an undersized buffer (OOB read in the blitter). + mp_int_t width = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 65535, MP_QSTR_width); + mp_int_t height = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 65535, MP_QSTR_height); + mp_int_t frames = mp_arg_validate_int_range(args[ARG_frames].u_int, 1, 255, MP_QSTR_frames); + mp_int_t format = args[ARG_format].u_int; + if (format != PICOGAME_FMT_RGB565 && format != PICOGAME_FMT_PAL8) { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid format")); + } + mp_int_t stride = args[ARG_stride].u_int; + if (stride <= 0) { + stride = width * frames; + } + // stride must hold the whole horizontal atlas, and the dims must fit the uint16_t fields, + // or blits index past a row / the stored stride truncates. + mp_arg_validate_int_max(width * frames, 65535, MP_QSTR_width); + mp_arg_validate_int_max(stride, 65535, MP_QSTR_stride); + mp_arg_validate_int_min(stride, width * frames, MP_QSTR_stride); + + mp_buffer_info_t data_info; + mp_get_buffer_raise(args[ARG_data].u_obj, &data_info, MP_BUFFER_READ); + + const uint16_t *palette = NULL; + mp_obj_t palette_obj = MP_OBJ_NULL; + size_t pal_len = 0; + if (format == PICOGAME_FMT_PAL8) { + if (args[ARG_palette].u_obj == mp_const_none) { + mp_arg_error_invalid(MP_QSTR_palette); // PAL8 needs one + } + mp_buffer_info_t pal_info; + mp_get_buffer_raise(args[ARG_palette].u_obj, &pal_info, MP_BUFFER_READ); + palette = pal_info.buf; + palette_obj = args[ARG_palette].u_obj; + pal_len = pal_info.len; + } + + size_t bpp = (format == PICOGAME_FMT_PAL8) ? 1 : 2; + // 64-bit: stride*height*bpp can exceed 32 bits (stride,height <= 65535) and wrap small in a 32-bit + // size_t, letting a tiny buffer pass this check -> OOB read in the blitter. Compute + compare wide. + uint64_t need = (uint64_t)stride * (uint64_t)height * (uint64_t)bpp; + if ((uint64_t)data_info.len < need) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + if (format == PICOGAME_FMT_PAL8 && pal_len < 2) { + // Need >=1 entry so pal[0] is valid. Contract (see blitter): PAL8 indices MUST be < palette + // length. The caller may write indices into the (mutable) `data` buffer directly, so we cannot + // validate once here. An out-of-range index is undefined behaviour (reads past the palette: + // usually a garbage colour, but it may fault on some platforms). Per-pixel clamping was dropped + // for speed - see the "restore full bounds-safety" note in the PAL8 blit loop if it's needed. + mp_arg_validate_length_min(pal_len, 1, MP_QSTR_palette); + } + + picogame_bitmap_obj_t *self = mp_obj_malloc(picogame_bitmap_obj_t, type); + self->data_obj = args[ARG_data].u_obj; + self->palette_obj = palette_obj; + self->data = data_info.buf; + self->palette = palette; + self->width = width; + self->height = height; + self->stride = stride; + self->frames = frames; + self->format = format; + // palette length in entries (informational; blitter assumes indices < this - see blit contract). + self->pal_entries = (uint16_t)((pal_len / 2) > 65535 ? 65535 : (pal_len / 2)); + if (args[ARG_transparent].u_obj != mp_const_none) { + self->transparent = mp_obj_get_int(args[ARG_transparent].u_obj); + self->has_transparent = true; + } else { + self->transparent = 0; + self->has_transparent = false; + } + return MP_OBJ_FROM_PTR(self); +} + +//| +//| width: int +//| height: int +//| frames: int +//| """Frame dimensions and frame count (read-only).""" +static mp_obj_t bitmap_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->width); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_width_obj, bitmap_get_width); +MP_PROPERTY_GETTER(bitmap_width_obj, (mp_obj_t)&bitmap_get_width_obj); + +static mp_obj_t bitmap_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->height); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_height_obj, bitmap_get_height); +MP_PROPERTY_GETTER(bitmap_height_obj, (mp_obj_t)&bitmap_get_height_obj); + +static mp_obj_t bitmap_get_frames(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->frames); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_frames_obj, bitmap_get_frames); +MP_PROPERTY_GETTER(bitmap_frames_obj, (mp_obj_t)&bitmap_get_frames_obj); + +//| format: int +//| """RGB565 or PAL8 (read-only).""" +static mp_obj_t bitmap_get_format(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->format); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_format_obj, bitmap_get_format); +MP_PROPERTY_GETTER(bitmap_format_obj, (mp_obj_t)&bitmap_get_format_obj); + +//| stride: int +//| """Row stride in pixels (read-only).""" +static mp_obj_t bitmap_get_stride(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->stride); +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_stride_obj, bitmap_get_stride); +MP_PROPERTY_GETTER(bitmap_stride_obj, (mp_obj_t)&bitmap_get_stride_obj); + +//| palette: Optional[ReadableBuffer] +//| """The PAL8 palette buffer this Bitmap was built with, or None for RGB565 +//| (read-only). Lets palette helpers read it back instead of holding a sidecar ref.""" +static mp_obj_t bitmap_get_palette(mp_obj_t self_in) { + picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); + return (self->palette_obj == MP_OBJ_NULL) ? mp_const_none : self->palette_obj; +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_palette_obj, bitmap_get_palette); +MP_PROPERTY_GETTER(bitmap_palette_obj, (mp_obj_t)&bitmap_get_palette_obj); + +//| transparent: Optional[int] +//| """The transparent color/index, or None if the Bitmap is fully opaque (read-only).""" +//| +//| +static mp_obj_t bitmap_get_transparent(mp_obj_t self_in) { + picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->has_transparent ? MP_OBJ_NEW_SMALL_INT(self->transparent) : mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_transparent_obj, bitmap_get_transparent); +MP_PROPERTY_GETTER(bitmap_transparent_obj, (mp_obj_t)&bitmap_get_transparent_obj); + +static const mp_rom_map_elem_t picogame_bitmap_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&bitmap_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&bitmap_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_frames), MP_ROM_PTR(&bitmap_frames_obj) }, + { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&bitmap_format_obj) }, + { MP_ROM_QSTR(MP_QSTR_stride), MP_ROM_PTR(&bitmap_stride_obj) }, + { MP_ROM_QSTR(MP_QSTR_palette), MP_ROM_PTR(&bitmap_palette_obj) }, + { MP_ROM_QSTR(MP_QSTR_transparent), MP_ROM_PTR(&bitmap_transparent_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_bitmap_locals_dict, picogame_bitmap_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_bitmap_type, + MP_QSTR_Bitmap, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_bitmap_make_new, + locals_dict, &picogame_bitmap_locals_dict + ); diff --git a/shared-bindings/picogame/Display.c b/shared-bindings/picogame/Display.c index 276608a8c77..d0815c78997 100644 --- a/shared-bindings/picogame/Display.c +++ b/shared-bindings/picogame/Display.c @@ -43,7 +43,7 @@ static mp_obj_t picogame_display_make_new(const mp_obj_type_t *type, size_t n_ar mp_obj_t native = mp_obj_cast_to_native_base(args[ARG_display].u_obj, &busdisplay_busdisplay_type); if (!mp_obj_is_type(native, &busdisplay_busdisplay_type)) { - mp_raise_TypeError(MP_ERROR_TEXT("expected a BusDisplay")); + mp_arg_validate_type(native, &busdisplay_busdisplay_type, MP_QSTR_display); } picogame_display_obj_t *self = mp_obj_malloc(picogame_display_obj_t, type); common_hal_picogame_display_construct(self, MP_OBJ_TO_PTR(native), args[ARG_rgb444].u_bool); diff --git a/shared-bindings/picogame/Framebuffer.c b/shared-bindings/picogame/Framebuffer.c new file mode 100644 index 00000000000..569093ee9d3 --- /dev/null +++ b/shared-bindings/picogame/Framebuffer.c @@ -0,0 +1,158 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.Framebuffer: a RAM render target used in place of a BusDisplay. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// --------------------------------------------------------------------------- +// Framebuffer (a RAM render target used in place of a BusDisplay; scanout-buffer +// platforms - WASM playground, desktop sim, FruitJam DVI/HSTX) +// --------------------------------------------------------------------------- +//| class Framebuffer: +//| """A RAM framebuffer render target that a Scene or :py:func:`render` can draw +//| into instead of a BusDisplay. ``buffer`` must be a writable buffer of at least +//| ``width*height*2`` bytes (``width*height`` for ``rgb332=True``); the caller owns it +//| (a ``bytearray`` in the browser, the DVI scanout buffer on FruitJam). By default the +//| pixels are wire-order RGB565 (the engine's internal format); ``native_rgb565=True`` +//| byte-swaps each finished region to NATIVE RGB565 - the format 16-bit picodvi / +//| canvas scanout targets expect; ``rgb332=True`` quantizes each finished region to +//| RGB332 bytes - the format of 8-bit picodvi scanout (FruitJam 640x480, which the +//| hardware only offers at 8bpp). Assets, palettes and ``rgb565()`` stay wire-order +//| RGB565 throughout regardless of the output format.""" +//| +//| def __init__( +//| self, +//| buffer: WriteableBuffer, +//| width: int, +//| height: int, +//| *, +//| native_rgb565: bool = False, +//| rgb332: bool = False, +//| ) -> None: ... +//| +//| width: int +//| height: int +//| """Target size in pixels (read-only).""" +//| +//| +// Static SRAM compose strip (see the scratch comment in make_new). 640*16*2 = 20 KB .bss, +// only on CIRCUITPY_PICOGAME_FRAMEBUFFER builds (fb boards have the SRAM to spare). +#define PICOGAME_FB_SCRATCH_MAX_W 640 +static uint16_t picogame_fb_scratch_sram[PICOGAME_FB_SCRATCH_MAX_W * PICOGAME_FB_SCRATCH_H]; + +static mp_obj_t picogame_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_buffer, ARG_width, ARG_height, ARG_native_rgb565, ARG_rgb332 }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_native_rgb565, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_rgb332, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + mp_int_t width = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 4096, MP_QSTR_width); + mp_int_t height = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 4096, MP_QSTR_height); + if (args[ARG_native_rgb565].u_bool && args[ARG_rgb332].u_bool) { + mp_arg_error_invalid(MP_QSTR_format); // native_rgb565 and rgb332 are exclusive + } + bool rgb332 = args[ARG_rgb332].u_bool; + + mp_buffer_info_t bi; + mp_get_buffer_raise(args[ARG_buffer].u_obj, &bi, MP_BUFFER_WRITE); + uint64_t need = (uint64_t)width * (uint64_t)height * (rgb332 ? 1u : 2u); + if ((uint64_t)bi.len < need) { + mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); + } + + picogame_framebuffer_obj_t *self = mp_obj_malloc(picogame_framebuffer_obj_t, type); + self->buffer = args[ARG_buffer].u_obj; + self->fb = (uint16_t *)bi.buf; + self->width = width; + self->height = height; + self->fmt = rgb332 ? PICOGAME_FB_RGB332 + : (args[ARG_native_rgb565].u_bool ? PICOGAME_FB_NATIVE565 : PICOGAME_FB_WIRE565); + // A LIVE scanout buffer (picodvi/HDMI) is read continuously, so picogame_render_framebuffer + // composes each band into this PRIVATE strip and only memcpys the FINISHED band into the fb. + // That serves BOTH targets: (a) native -> also byte-swap the strip so the fb never holds wire + // (no pink); (b) wire -> no swap, but the off-screen compose still stops the beam from sampling + // a half-composited region (background filled, sprite not yet drawn) = no sprite/HUD flicker. + // Always allocated for the FB target; the WASM/sim path (read out after present, not live) just + // pays a small strip + one memcpy. See PICOGAME_FB_SCRATCH_H. + // + // The scratch must be FAST memory: on a PSRAM-heap board (Fruit Jam) a heap bytearray + // lands in external PSRAM and every compose write pays QSPI latency (measured 8.7 vs + // 64+ MB/s SRAM; a full-res StripDraw frame ballooned refresh to ~30-38 ms). One static + // SRAM strip serves every Framebuffer (compose is synchronous) up to 640 px wide; wider + // targets fall back to the heap. + self->scratch_buf = mp_const_none; + self->scratch = NULL; + self->scratch_rows = 0; + { + int rows = PICOGAME_FB_SCRATCH_H; + if (rows > height) { + rows = height; + } + if (width <= PICOGAME_FB_SCRATCH_MAX_W) { + self->scratch = picogame_fb_scratch_sram; + } else { + mp_obj_t sb = mp_obj_new_bytearray_of_zeros((size_t)width * (size_t)rows * 2u); + mp_buffer_info_t sbi; + mp_get_buffer_raise(sb, &sbi, MP_BUFFER_WRITE); + self->scratch_buf = sb; + self->scratch = (uint16_t *)sbi.buf; + } + self->scratch_rows = rows; + } + return MP_OBJ_FROM_PTR(self); +} + +static mp_obj_t picogame_framebuffer_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_framebuffer_obj_t *)MP_OBJ_TO_PTR(self_in))->width); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_framebuffer_get_width_obj, picogame_framebuffer_get_width); +MP_PROPERTY_GETTER(picogame_framebuffer_width_obj, (mp_obj_t)&picogame_framebuffer_get_width_obj); + +static mp_obj_t picogame_framebuffer_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_framebuffer_obj_t *)MP_OBJ_TO_PTR(self_in))->height); +} +static MP_DEFINE_CONST_FUN_OBJ_1(picogame_framebuffer_get_height_obj, picogame_framebuffer_get_height); +MP_PROPERTY_GETTER(picogame_framebuffer_height_obj, (mp_obj_t)&picogame_framebuffer_get_height_obj); + +static const mp_rom_map_elem_t picogame_framebuffer_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&picogame_framebuffer_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&picogame_framebuffer_height_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_framebuffer_locals_dict, picogame_framebuffer_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_framebuffer_type, + MP_QSTR_Framebuffer, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_framebuffer_make_new, + locals_dict, &picogame_framebuffer_locals_dict + ); +#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER diff --git a/shared-bindings/picogame/Scene.c b/shared-bindings/picogame/Scene.c index 2793e7cbe5d..778e53f0f7c 100644 --- a/shared-bindings/picogame/Scene.c +++ b/shared-bindings/picogame/Scene.c @@ -57,7 +57,7 @@ static mp_obj_t scene_resolve_target(mp_obj_t disp, bool *fast, bool *fb_target) // renderer treats self->display as a busdisplay_busdisplay_obj_t directly. mp_obj_t native = mp_obj_cast_to_native_base(disp, &busdisplay_busdisplay_type); if (!mp_obj_is_type(native, &busdisplay_busdisplay_type)) { - mp_raise_TypeError(MP_ERROR_TEXT("expected a BusDisplay")); + mp_arg_validate_type(native, &busdisplay_busdisplay_type, MP_QSTR_display); } return native; } @@ -196,7 +196,7 @@ static void scene_add_one(picogame_scene_obj_t *self, mp_obj_t item_in, bool fix } if (self->count >= self->cap) { if (self->cap >= 0x8000) { // next doubling overflows uint16_t -> m_renew(0) shrink - mp_raise_RuntimeError(MP_ERROR_TEXT("scene full")); + m_malloc_fail((size_t)self->cap * 2); // next doubling overflows the count type } uint16_t new_cap = self->cap * 2; self->items = m_renew(mp_obj_t, self->items, self->cap, new_cap); @@ -268,7 +268,7 @@ static mp_obj_t picogame_scene_remove(mp_obj_t self_in, mp_obj_t item_in) { self->cleared = false; // full repaint next refresh: background covers where it was return mp_const_none; } - mp_raise_ValueError(MP_ERROR_TEXT("item not in scene")); + mp_arg_error_invalid(MP_QSTR_item); } static MP_DEFINE_CONST_FUN_OBJ_2(picogame_scene_remove_obj, picogame_scene_remove); diff --git a/shared-bindings/picogame/Sprite.c b/shared-bindings/picogame/Sprite.c new file mode 100644 index 00000000000..6893e8c0f04 --- /dev/null +++ b/shared-bindings/picogame/Sprite.c @@ -0,0 +1,598 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.Sprite: a positioned, animatable instance of a Bitmap. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// --------------------------------------------------------------------------- +// Sprite +// --------------------------------------------------------------------------- + +// Int pixel/scale -> 24.8 fixed-point. Shift through unsigned so a wild coordinate (e.g. 100_000_000, +// in 32-bit mp_int range but not after <<8) wraps modularly instead of hitting signed-overflow UB. +// Costs nothing over a plain shift; for any real on-screen coordinate the result is identical. +static int32_t pg_int_to_fp8(mp_int_t v) { + return (int32_t)((uint32_t)v << 8); +} + +//| class Sprite: +//| """A positioned, animatable instance of a :py:class:`Bitmap`.""" +//| +//| def __init__( +//| self, +//| bitmap: Bitmap, +//| x: int = 0, +//| y: int = 0, +//| *, +//| frame: int = 0, +//| visible: bool = True, +//| flip_x: bool = False, +//| flip_y: bool = False, +//| ) -> None: ... +//| +static mp_obj_t picogame_sprite_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_bitmap, ARG_x, ARG_y, ARG_frame, ARG_visible, ARG_flip_x, ARG_flip_y }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_frame, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_visible, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, + { MP_QSTR_flip_x, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + { MP_QSTR_flip_y, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t bitmap_obj = mp_arg_validate_type(args[ARG_bitmap].u_obj, &picogame_bitmap_type, MP_QSTR_bitmap); + + picogame_sprite_obj_t *self = mp_obj_malloc(picogame_sprite_obj_t, type); + self->bitmap = MP_OBJ_TO_PTR(bitmap_obj); + self->x = pg_int_to_fp8(args[ARG_x].u_int); // pixel -> 24.8 fixed-point (overflow-clamped) + self->y = pg_int_to_fp8(args[ARG_y].u_int); + self->frame = args[ARG_frame].u_int; + self->flags = (args[ARG_visible].u_bool ? PICOGAME_SPR_VISIBLE : 0) + | (args[ARG_flip_x].u_bool ? PICOGAME_SPR_FLIP_X : 0) + | (args[ARG_flip_y].u_bool ? PICOGAME_SPR_FLIP_Y : 0); + self->anchor_x = 0; // default pivot = top-left (0, 0) + self->anchor_y = 0; + self->scale = 256; // 8.8 fixed-point: 256 = 1.0x (no scaling) + self->angle = 0; // no rotation -> axis-aligned fast path + self->flash_color = 0; + self->dither = 0; + self->data = mp_const_none; + self->seq = 0; // dirty-rect change counter (mp_obj_malloc zeroes anyway; explicit) + return MP_OBJ_FROM_PTR(self); +} + +static void set_flag(picogame_sprite_obj_t *self, uint8_t flag, bool on) { + if (on) { + self->flags |= flag; + } else { + self->flags &= ~flag; + } +} + +// shadow / flash / dither are mutually exclusive (one blit effect at a time); setting one ON +// clears the others, so "the last effect you set wins". Turning one OFF clears ONLY its own flag, +// so clearing an effect you never enabled (e.g. spr.flash = 0) can't wipe a different active one. +#define PICOGAME_SPR_FX_MASK (PICOGAME_SPR_SHADOW | PICOGAME_SPR_FLASH | PICOGAME_SPR_DITHER | PICOGAME_SPR_TINT) +static void set_effect(picogame_sprite_obj_t *self, uint8_t flag, bool on) { + if (on) { + self->flags = (uint8_t)((self->flags & ~PICOGAME_SPR_FX_MASK) | flag); + } else { + self->flags &= (uint8_t) ~flag; + } +} + +// Round a float to 24.8 fixed-point (shared by the position/scale/anchor setters so the soft-float +// round sequence is emitted once, not per call site). +static int32_t pg_round_fp8(mp_float_t f) { + return (int32_t)(f * 256 + (f >= 0 ? (mp_float_t)0.5 : (mp_float_t)-0.5)); +} + + +// Accept an int or float and store as 24.8 fixed-point (rounded). Integer fast path avoids +// software float on RP2040 - game code sets x/y (via move/setters) every frame, usually with ints. +static int32_t obj_to_fp(mp_obj_t o) { + if (mp_obj_is_int(o)) { + return pg_int_to_fp8(mp_obj_get_int(o)); + } + mp_float_t f = mp_obj_get_float(o); + return pg_round_fp8(f); +} + +//| +//| bitmap: Bitmap +//| """The Bitmap drawn (swap it at runtime to change the art; the frame index is kept).""" +//| frame: int +//| """Which frame of the bitmap's atlas to draw (0-based) - animation = stepping this.""" +//| visible: bool +//| """False hides the sprite (it stays in the scene; the area under it repaints).""" +//| flip_x: bool +//| flip_y: bool +//| """Mirror the frame horizontally / vertically at draw time (free on the fast path).""" +//| x: int +//| y: int +//| """Integer pixel position (scene coords). Setting accepts a float for +//| sub-pixel placement; reading returns the floored pixel.""" +//| fx: float +//| fy: float +//| """Sub-pixel position (use for smooth physics: e.g. ``sprite.fx += 2.4``).""" +// FLASH NOTE (property objects vs. a single `attr` handler): Sprite (and the other property-dense +// types) expose each attribute as its own getter/setter + MP_PROPERTY object below - the standard +// CircuitPython shared-bindings idiom (~423 such uses across CP). Collapsing these onto ONE `attr` +// load/store function per type (a qstr switch, like py/objcomplex.c's complex_attr for .real/.imag) +// would save ~3-4 KB of flash across the whole binding layer (Sprite alone ~1.5-2.5 KB). It is a +// valid MicroPython mechanism and would NOT break the .pyi stubs (those are generated from the //| +// comments, not the C property objects). We deliberately KEEP property objects: they are the +// idiomatic, most readable shared-bindings form and keep every type's definition uniform. Revisit +// only if flash becomes critical (then convert Sprite first - the densest cluster - not every type). +static mp_obj_t sprite_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x >> 8); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_x_obj, sprite_get_x); +static mp_obj_t sprite_set_x(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x = obj_to_fp(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_x_obj, sprite_set_x); +MP_PROPERTY_GETSET(sprite_x_obj, (mp_obj_t)&sprite_get_x_obj, (mp_obj_t)&sprite_set_x_obj); + +static mp_obj_t sprite_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y >> 8); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_y_obj, sprite_get_y); +static mp_obj_t sprite_set_y(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y = obj_to_fp(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_y_obj, sprite_set_y); +MP_PROPERTY_GETSET(sprite_y_obj, (mp_obj_t)&sprite_get_y_obj, (mp_obj_t)&sprite_set_y_obj); + +static mp_obj_t sprite_get_fx(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_fx_obj, sprite_get_fx); +// set_fx is byte-identical to set_x (both store obj_to_fp(v) into ->x) -> reuse set_x's fun obj. +MP_PROPERTY_GETSET(sprite_fx_obj, (mp_obj_t)&sprite_get_fx_obj, (mp_obj_t)&sprite_set_x_obj); + +static mp_obj_t sprite_get_fy(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_fy_obj, sprite_get_fy); +// set_fy is byte-identical to set_y -> reuse set_y's fun obj. +MP_PROPERTY_GETSET(sprite_fy_obj, (mp_obj_t)&sprite_get_fy_obj, (mp_obj_t)&sprite_set_y_obj); + +static mp_obj_t sprite_get_frame(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->frame); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_frame_obj, sprite_get_frame); +static mp_obj_t sprite_set_frame(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->frame = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_frame_obj, sprite_set_frame); +MP_PROPERTY_GETSET(sprite_frame_obj, (mp_obj_t)&sprite_get_frame_obj, (mp_obj_t)&sprite_set_frame_obj); + +static mp_obj_t sprite_get_visible(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_VISIBLE) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_visible_obj, sprite_get_visible); +static mp_obj_t sprite_set_visible(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_VISIBLE, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_visible_obj, sprite_set_visible); +MP_PROPERTY_GETSET(sprite_visible_obj, (mp_obj_t)&sprite_get_visible_obj, (mp_obj_t)&sprite_set_visible_obj); + +static mp_obj_t sprite_get_flip_x(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_FLIP_X) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flip_x_obj, sprite_get_flip_x); +static mp_obj_t sprite_set_flip_x(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_FLIP_X, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_x_obj, sprite_set_flip_x); +MP_PROPERTY_GETSET(sprite_flip_x_obj, (mp_obj_t)&sprite_get_flip_x_obj, (mp_obj_t)&sprite_set_flip_x_obj); + +static mp_obj_t sprite_get_flip_y(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_FLIP_Y) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flip_y_obj, sprite_get_flip_y); +static mp_obj_t sprite_set_flip_y(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_FLIP_Y, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_y_obj, sprite_set_flip_y); +MP_PROPERTY_GETSET(sprite_flip_y_obj, (mp_obj_t)&sprite_get_flip_y_obj, (mp_obj_t)&sprite_set_flip_y_obj); + +//| scale: float +//| """Uniform draw scale (nearest-neighbour). 1.0 = native (fast path); 2.0 = double +//| size, fractional values are allowed (e.g. a powerup grow tween). Anchor stays put.""" +static mp_obj_t sprite_get_scale(mp_obj_t self_in) { + return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->scale * (mp_float_t)(1.0 / 256.0)); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_scale_obj, sprite_get_scale); +static mp_obj_t sprite_set_scale(mp_obj_t self_in, mp_obj_t v) { + int q; + if (mp_obj_is_int(v)) { // int fast path (no software float on RP2040) + q = pg_int_to_fp8(mp_obj_get_int(v)); // overflow-clamped <<8 + } else { + mp_float_t f = mp_obj_get_float(v); + q = pg_round_fp8(f); + } + if (q < 1) { + q = 1; + } + if (q > 65535) { + q = 65535; + } + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->scale = (uint16_t)q; + self->xf_valid = 0; // affine cache depends on scale + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_scale_obj, sprite_set_scale); +MP_PROPERTY_GETSET(sprite_scale_obj, (mp_obj_t)&sprite_get_scale_obj, (mp_obj_t)&sprite_set_scale_obj); + +//| angle: float +//| """Rotation in degrees about the anchor (0 = none, the fast path). Nearest-neighbour, +//| so integer scales stay crisp; rotation shimmers slightly (pixel-art trade-off).""" +static mp_obj_t sprite_get_angle(mp_obj_t self_in) { + return mp_obj_new_float((mp_float_t)((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->angle); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_angle_obj, sprite_get_angle); +static mp_obj_t sprite_set_angle(mp_obj_t self_in, mp_obj_t v) { + int a; + if (mp_obj_is_int(v)) { // int fast path (no software float on RP2040) + a = mp_obj_get_int(v); + } else { + mp_float_t f = mp_obj_get_float(v); + a = (int)(f + (f >= 0 ? (mp_float_t)0.5 : (mp_float_t)-0.5)); + } + a %= 360; + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->angle = (int16_t)a; + self->xf_valid = 0; // affine cache depends on angle + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_angle_obj, sprite_set_angle); +MP_PROPERTY_GETSET(sprite_angle_obj, (mp_obj_t)&sprite_get_angle_obj, (mp_obj_t)&sprite_set_angle_obj); + +//| shadow: bool +//| """Draw opaque pixels as a darkened destination instead of colour - a drop-shadow +//| silhouette (offset copy below the sprite) or a dim overlay (a solid sprite scaled +//| over a dialog/pause area).""" +static mp_obj_t sprite_get_shadow(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_SHADOW) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_shadow_obj, sprite_get_shadow); +static mp_obj_t sprite_set_shadow(mp_obj_t self_in, mp_obj_t v) { + set_effect(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_SHADOW, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_shadow_obj, sprite_set_shadow); +MP_PROPERTY_GETSET(sprite_shadow_obj, (mp_obj_t)&sprite_get_shadow_obj, (mp_obj_t)&sprite_set_shadow_obj); + +//| flash: int +//| """Draw opaque pixels as a solid colour (a wire-order RGB565 int from rgb565) instead +//| of their own colour - a hit-flash or tint. Set to a colour to enable, 0/False to turn +//| off. Pulse it for 1-3 frames on impact. Mutually exclusive with shadow/dither.""" +static mp_obj_t sprite_get_flash(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_FLASH) ? s->flash_color : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flash_obj, sprite_get_flash); +static mp_obj_t sprite_set_flash(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + // Falsy (None / False / 0) turns flash OFF. A non-zero colour enables it. (You can't flash + // pure black - use a near-black colour if you ever need that; off is the common case.) + if (!mp_obj_is_true(v)) { + set_effect(s, PICOGAME_SPR_FLASH, false); + } else { + s->flash_color = (uint16_t)mp_obj_get_int(v); + set_effect(s, PICOGAME_SPR_FLASH, true); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flash_obj, sprite_set_flash); +MP_PROPERTY_GETSET(sprite_flash_obj, (mp_obj_t)&sprite_get_flash_obj, (mp_obj_t)&sprite_set_flash_obj); + +//| dither: int +//| """Fake transparency via an ordered (Bayer) dither, no alpha blending: 0 = opaque +//| (off), 8 = ~50% see-through, 16 = invisible. A classic 1-bit look - for ghosts, +//| fading/spawning enemies, fog, force fields. Mutually exclusive with shadow/flash.""" +static mp_obj_t sprite_get_dither(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_DITHER) ? s->dither : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_dither_obj, sprite_get_dither); +static mp_obj_t sprite_set_dither(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + int lv = mp_obj_get_int(v); + if (lv < 0) { + lv = 0; + } + if (lv > 16) { + lv = 16; + } + s->dither = (uint8_t)lv; + set_effect(s, PICOGAME_SPR_DITHER, lv > 0); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_dither_obj, sprite_set_dither); +MP_PROPERTY_GETSET(sprite_dither_obj, (mp_obj_t)&sprite_get_dither_obj, (mp_obj_t)&sprite_set_dither_obj); + +//| tint: int +//| """Multiply opaque pixels by a colour (wire-order RGB565 from rgb565), keeping the +//| sprite's shading - coloured lighting, a red damage flush, a blue freeze, a power-up +//| glow. Unlike ``flash`` (flat replace) ``tint`` preserves detail. 0/False = off. Mutually +//| exclusive with shadow/flash/dither.""" +static mp_obj_t sprite_get_tint(mp_obj_t self_in) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_TINT) ? s->flash_color : 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_tint_obj, sprite_get_tint); +static mp_obj_t sprite_set_tint(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); + if (!mp_obj_is_true(v)) { + set_effect(s, PICOGAME_SPR_TINT, false); + } else { + s->flash_color = (uint16_t)mp_obj_get_int(v); // shared colour field with flash + set_effect(s, PICOGAME_SPR_TINT, true); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_tint_obj, sprite_set_tint); +MP_PROPERTY_GETSET(sprite_tint_obj, (mp_obj_t)&sprite_get_tint_obj, (mp_obj_t)&sprite_set_tint_obj); + +//| transpose: bool +//| """Swap the sprite's X/Y axes - a cheap 90deg turn (no shimmer, unlike ``angle``). +//| Combined with ``flip_x``/``flip_y`` it gives all 8 orientations for free. Only on the fast +//| path (scale 1.0, angle 0); for rotation WITH scaling use ``angle``. The drawn footprint +//| swaps width/height.""" +static mp_obj_t sprite_get_transpose(mp_obj_t self_in) { + return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_TRANSPOSE) != 0); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_transpose_obj, sprite_get_transpose); +static mp_obj_t sprite_set_transpose(mp_obj_t self_in, mp_obj_t v) { + set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_TRANSPOSE, mp_obj_is_true(v)); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_transpose_obj, sprite_set_transpose); +MP_PROPERTY_GETSET(sprite_transpose_obj, (mp_obj_t)&sprite_get_transpose_obj, (mp_obj_t)&sprite_set_transpose_obj); + +//| data: Any +//| """Arbitrary per-sprite user payload for game state (default None).""" +static mp_obj_t sprite_get_data(mp_obj_t self_in) { + return ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->data; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_data_obj, sprite_get_data); +static mp_obj_t sprite_set_data(mp_obj_t self_in, mp_obj_t v) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->data = v; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_data_obj, sprite_set_data); +MP_PROPERTY_GETSET(sprite_data_obj, (mp_obj_t)&sprite_get_data_obj, (mp_obj_t)&sprite_set_data_obj); + +//| bitmap: Bitmap +//| """The sprite's source bitmap. Assigning a new one swaps graphics and may +//| change size; the scene repaints both the old and new bounds next refresh +//| (e.g. powerups, resizable HUD bars, text labels).""" +static mp_obj_t sprite_get_bitmap(mp_obj_t self_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + return self->bitmap != NULL ? MP_OBJ_FROM_PTR(self->bitmap) : mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_bitmap_obj, sprite_get_bitmap); +static mp_obj_t sprite_set_bitmap(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t bm = mp_arg_validate_type(v, &picogame_bitmap_type, MP_QSTR_bitmap); + self->bitmap = MP_OBJ_TO_PTR(bm); + self->xf_valid = 0; // affine cache depends on bitmap dims + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_bitmap_obj, sprite_set_bitmap); +MP_PROPERTY_GETSET(sprite_bitmap_obj, (mp_obj_t)&sprite_get_bitmap_obj, (mp_obj_t)&sprite_set_bitmap_obj); + +//| anchor: Tuple[float, float] +//| """Pivot as fractions of the bitmap size: ``(0, 0)`` = top-left (default), +//| ``(0.5, 0.5)`` = center, ``(0.5, 1.0)`` = bottom-center. ``x``/``y`` then +//| refer to this point, so rotating frames or swapping to a different size +//| stays aligned. Stored in 1/256 steps.""" +//| +static mp_obj_t sprite_get_anchor(mp_obj_t self_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t t[2] = { + mp_obj_new_float(self->anchor_x * (mp_float_t)(1.0 / 256.0)), + mp_obj_new_float(self->anchor_y * (mp_float_t)(1.0 / 256.0)), + }; + return mp_obj_new_tuple(2, t); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_anchor_obj, sprite_get_anchor); +static int anchor_to_fp(mp_obj_t o) { + mp_float_t f = mp_obj_get_float(o); + int v = pg_round_fp8(f); + return v < 0 ? 0 : (v > 256 ? 256 : v); +} +static mp_obj_t sprite_set_anchor(mp_obj_t self_in, mp_obj_t v) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + size_t len; + mp_obj_t *items; + mp_obj_get_array(v, &len, &items); + mp_arg_validate_length(len, 2, MP_QSTR_anchor); + self->anchor_x = anchor_to_fp(items[0]); + self->anchor_y = anchor_to_fp(items[1]); + self->xf_valid = 0; // affine cache depends on the pivot + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_anchor_obj, sprite_set_anchor); +MP_PROPERTY_GETSET(sprite_anchor_obj, (mp_obj_t)&sprite_get_anchor_obj, (mp_obj_t)&sprite_set_anchor_obj); + +//| def move(self, x: int, y: int) -> None: +//| """Set the sprite position.""" +//| ... +//| +static mp_obj_t sprite_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { + picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); + self->x = obj_to_fp(x_in); + self->y = obj_to_fp(y_in); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_3(sprite_move_obj, sprite_move); + +//| def touch(self) -> None: +//| """Force this sprite to repaint on the next ``Scene.refresh()`` even though none +//| of its tracked properties (position, frame, scale, angle, bitmap) changed. Call +//| it after mutating the sprite's bitmap pixels IN PLACE (e.g. streaming a new frame +//| into the same buffer), which the dirty-rect tracker can't otherwise detect.""" +//| ... +//| +static mp_obj_t sprite_touch(mp_obj_t self_in) { + ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->seq++; + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_1(sprite_touch_obj, sprite_touch); + +// Fill (x1,y1,x2,y2) from a Sprite (its drawn aabb), a (x,y) point, or a (x1,y1,x2,y2) rect. +static void pg_obj_to_box(mp_obj_t o, int *x1, int *y1, int *x2, int *y2) { + if (mp_obj_is_type(o, &picogame_sprite_type)) { + picogame_sprite_aabb(MP_OBJ_TO_PTR(o), x1, y1, x2, y2); + return; + } + if (mp_obj_is_type(o, &mp_type_tuple) || mp_obj_is_type(o, &mp_type_list)) { + size_t len; + mp_obj_t *items; + mp_obj_get_array(o, &len, &items); + if (len == 2) { // a point -> a zero-size box + *x1 = *x2 = mp_obj_get_int(items[0]); + *y1 = *y2 = mp_obj_get_int(items[1]); + return; + } + if (len == 4) { // a rect + *x1 = mp_obj_get_int(items[0]); + *y1 = mp_obj_get_int(items[1]); + *x2 = mp_obj_get_int(items[2]); + *y2 = mp_obj_get_int(items[3]); + return; + } + } + mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(o)->name); +} + +//| def overlaps(self, other: "Sprite | tuple", inset: int = 0) -> bool: +//| """True if this sprite's drawn box overlaps ``other`` - an inclusive AABB, so they +//| collide the moment they touch. ``other`` may be another Sprite, a point ``(x, y)``, +//| or a rect ``(x1, y1, x2, y2)`` (e.g. a trigger zone or the screen for culling). +//| The box is anchor/scale/rotation aware. ``inset`` shrinks THIS sprite's box by N px +//| on each side, for a fair hitbox smaller than the art.""" +//| ... +//| +static mp_obj_t sprite_overlaps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_other, ARG_inset }; + static const mp_arg_t allowed[] = { + { MP_QSTR_other, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_inset, MP_ARG_INT, {.u_int = 0} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed), allowed, args); + int ax1, ay1, ax2, ay2, bx1, by1, bx2, by2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(pos_args[0]), &ax1, &ay1, &ax2, &ay2); + pg_obj_to_box(args[ARG_other].u_obj, &bx1, &by1, &bx2, &by2); + int in = args[ARG_inset].u_int; // inset shrinks the CALLER's box (kw or positional) + bool hit = ((ax1 + in) <= bx2) && ((ax2 - in) >= bx1) && + ((ay1 + in) <= by2) && ((ay2 - in) >= by1); + return mp_obj_new_bool(hit); +} +static MP_DEFINE_CONST_FUN_OBJ_KW(sprite_overlaps_obj, 2, sprite_overlaps); + +//| def near(self, other: "Sprite | tuple", r: int) -> bool: +//| """True if this sprite's centre is within ``r`` pixels of ``other``'s centre (squared +//| distance, no sqrt) - the round/forgiving test for bullets, pickups, explosions. +//| ``other`` may be a Sprite or a point ``(x, y)``. Centres come from the drawn box, so +//| it is anchor aware.""" +//| ... +//| +//| +static mp_obj_t sprite_near(mp_obj_t self_in, mp_obj_t other_in, mp_obj_t r_in) { + int ax1, ay1, ax2, ay2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(self_in), &ax1, &ay1, &ax2, &ay2); + int acx = (ax1 + ax2) / 2, acy = (ay1 + ay2) / 2, bcx, bcy; + if (mp_obj_is_type(other_in, &picogame_sprite_type)) { + int bx1, by1, bx2, by2; + picogame_sprite_aabb(MP_OBJ_TO_PTR(other_in), &bx1, &by1, &bx2, &by2); + bcx = (bx1 + bx2) / 2; + bcy = (by1 + by2) / 2; + } else { + size_t len; + mp_obj_t *items; + mp_obj_get_array(other_in, &len, &items); + if (len != 2) { + mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), + MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(other_in)->name); + } + bcx = mp_obj_get_int(items[0]); + bcy = mp_obj_get_int(items[1]); + } + mp_int_t r = mp_obj_get_int(r_in), dx = acx - bcx, dy = acy - bcy; + return mp_obj_new_bool(dx * dx + dy * dy < r * r); +} +static MP_DEFINE_CONST_FUN_OBJ_3(sprite_near_obj, sprite_near); + +static const mp_rom_map_elem_t picogame_sprite_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&sprite_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&sprite_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_fx), MP_ROM_PTR(&sprite_fx_obj) }, + { MP_ROM_QSTR(MP_QSTR_fy), MP_ROM_PTR(&sprite_fy_obj) }, + { MP_ROM_QSTR(MP_QSTR_frame), MP_ROM_PTR(&sprite_frame_obj) }, + { MP_ROM_QSTR(MP_QSTR_visible), MP_ROM_PTR(&sprite_visible_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip_x), MP_ROM_PTR(&sprite_flip_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_flip_y), MP_ROM_PTR(&sprite_flip_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&sprite_scale_obj) }, + { MP_ROM_QSTR(MP_QSTR_angle), MP_ROM_PTR(&sprite_angle_obj) }, + { MP_ROM_QSTR(MP_QSTR_shadow), MP_ROM_PTR(&sprite_shadow_obj) }, + { MP_ROM_QSTR(MP_QSTR_flash), MP_ROM_PTR(&sprite_flash_obj) }, + { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&sprite_dither_obj) }, + { MP_ROM_QSTR(MP_QSTR_tint), MP_ROM_PTR(&sprite_tint_obj) }, + { MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&sprite_transpose_obj) }, + { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&sprite_data_obj) }, + { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&sprite_bitmap_obj) }, + { MP_ROM_QSTR(MP_QSTR_anchor), MP_ROM_PTR(&sprite_anchor_obj) }, + { MP_ROM_QSTR(MP_QSTR_overlaps), MP_ROM_PTR(&sprite_overlaps_obj) }, + { MP_ROM_QSTR(MP_QSTR_near), MP_ROM_PTR(&sprite_near_obj) }, + { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&sprite_move_obj) }, + { MP_ROM_QSTR(MP_QSTR_touch), MP_ROM_PTR(&sprite_touch_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_sprite_locals_dict, picogame_sprite_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_sprite_type, + MP_QSTR_Sprite, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_sprite_make_new, + locals_dict, &picogame_sprite_locals_dict + ); diff --git a/shared-bindings/picogame/StripDraw.c b/shared-bindings/picogame/StripDraw.c new file mode 100644 index 00000000000..ffd05de9372 --- /dev/null +++ b/shared-bindings/picogame/StripDraw.c @@ -0,0 +1,222 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.StripDraw: an immediate-mode draw layer that holds no pixel buffer. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-bindings/picogame/StripDraw.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +// --------------------------------------------------------------------------- +// StripDraw (immediate-mode draw layer; struct in shared-module/picogame/__init__.h) +// --------------------------------------------------------------------------- + +//| class StripDraw: +//| """An immediate-mode draw layer that holds NO pixel buffer. Each refresh, for +//| every render strip overlapping its rect, ``callback(view, vx, vy, vw, vh)`` is +//| called with a :py:class:`Canvas` ``view`` pointing straight at the live strip +//| buffer - so you draw primitives directly into the frame (zero RAM, vs a Canvas +//| which costs width*height*2 bytes). The view's local (0, 0) is screen pixel +//| (vx, vy); (vw, vh) is the strip size. Draw only the rows in [vy, vy+vh) for +//| speed (anything outside the view is clipped anyway). The rect is repainted every +//| frame, so use it for animated / scanline content (pseudo-3D, gradients, +//| procedural backgrounds), not static art (use Canvas for that). +//| +//| COORDINATE CONTRACT: ``vx`` is the RENDER REGION's origin (NOT this layer's x), and the +//| view spans the FULL region WIDTH (the layer's rect only gates which ROWS run). So draw at +//| ABSOLUTE screen coords minus (vx, vy), and fill only your own rect with ``fill_rect`` - +//| ``view.clear()`` fills the whole region width. (When you render a StripDraw via +//| ``picogame.render([sd], buf, x,y,x+w,y+h)`` the region == the rect, so vx == x.) +//| Text via ``Canvas.text`` is ASCII (the built-in font); non-ASCII has no glyph.""" +//| +//| def __init__( +//| self, +//| callback: Callable[[Canvas, int, int, int, int], None], +//| x: int = 0, +//| y: int = 0, +//| width: int = 0, +//| height: int = 0, +//| ) -> None: ... +//| +static mp_obj_t picogame_stripdraw_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + enum { ARG_callback, ARG_x, ARG_y, ARG_width, ARG_height, ARG_always_dirty }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_width, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_height, MP_ARG_INT, {.u_int = 0} }, + { MP_QSTR_always_dirty, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + picogame_stripdraw_obj_t *self = mp_obj_malloc(picogame_stripdraw_obj_t, type); + self->callback = args[ARG_callback].u_obj; + self->x = args[ARG_x].u_int; + self->y = args[ARG_y].u_int; + self->w = args[ARG_width].u_int; + self->h = args[ARG_height].u_int; + self->faulted = false; + self->always_dirty = args[ARG_always_dirty].u_bool; + picogame_dirty_reset(&self->dx1); // render once on first refresh (even when always_dirty=False) + picogame_dirty_union(&self->dx1, self->x, self->y, self->x + self->w, self->y + self->h); + // A buffer-less Canvas reused as the per-strip drawing view: its `data` is + // repointed at the live strip each blit, so no surface RAM is allocated here. + picogame_canvas_obj_t *view = mp_obj_malloc(picogame_canvas_obj_t, &picogame_canvas_type); + view->data = NULL; + view->data_obj = MP_OBJ_NULL; + view->w = 0; + view->h = 0; + view->x = 0; + view->y = 0; + view->transparent = 0; + view->has_transparent = false; + picogame_canvas_dirty_reset(view); + self->view = MP_OBJ_FROM_PTR(view); + return MP_OBJ_FROM_PTR(self); +} + +//| +//| x: int +//| y: int +//| width: int +//| height: int +//| """The screen rect repainted each refresh (read/write). Move or resize the layer +//| by assigning these. Shrinking the rect leaves stale pixels behind - follow a +//| shrink with ``scene.invalidate()`` for a clean repaint (as the fx helpers do).""" +static mp_obj_t sd_get_x(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_x_obj, sd_get_x); +static mp_obj_t sd_set_x(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_x_obj, sd_set_x); +MP_PROPERTY_GETSET(sd_x_obj, (mp_obj_t)&sd_get_x_obj, (mp_obj_t)&sd_set_x_obj); + +static mp_obj_t sd_get_y(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->y); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_y_obj, sd_get_y); +static mp_obj_t sd_set_y(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->y = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_y_obj, sd_set_y); +MP_PROPERTY_GETSET(sd_y_obj, (mp_obj_t)&sd_get_y_obj, (mp_obj_t)&sd_set_y_obj); + +static mp_obj_t sd_get_width(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->w); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_width_obj, sd_get_width); +static mp_obj_t sd_set_width(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->w = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_width_obj, sd_set_width); +MP_PROPERTY_GETSET(sd_width_obj, (mp_obj_t)&sd_get_width_obj, (mp_obj_t)&sd_set_width_obj); + +static mp_obj_t sd_get_height(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->h); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_height_obj, sd_get_height); +static mp_obj_t sd_set_height(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->h = mp_obj_get_int(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_height_obj, sd_set_height); +MP_PROPERTY_GETSET(sd_height_obj, (mp_obj_t)&sd_get_height_obj, (mp_obj_t)&sd_set_height_obj); + +//| always_dirty: bool +//| """True (default): repaint every frame - for animated content (pseudo-3D, gradients). False: +//| repaint only after an ``invalidate()`` call (or when overlapped by another dirty layer) - for on-change UI, +//| so a static panel doesn't re-rasterize+re-push every frame. With False you MUST invalidate() on +//| every content/visibility change (it's invisible until you do).""" +//| +static mp_obj_t sd_get_always_dirty(mp_obj_t self_in) { + return mp_obj_new_bool(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty); +} +static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_always_dirty_obj, sd_get_always_dirty); +static mp_obj_t sd_set_always_dirty(mp_obj_t self_in, mp_obj_t v) { + ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty = mp_obj_is_true(v); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_always_dirty_obj, sd_set_always_dirty); +MP_PROPERTY_GETSET(sd_always_dirty_obj, (mp_obj_t)&sd_get_always_dirty_obj, (mp_obj_t)&sd_set_always_dirty_obj); + +//| def invalidate(self, x: int = 0, y: int = 0, w: int = 0, h: int = 0) -> None: +//| """Mark dirty so the layer repaints on the next refresh (only needed when +//| ``always_dirty=False``). With no args, the whole layer repaints. Pass a rect in +//| VIEW-LOCAL coordinates (the same (0,0)-at-``(vx, vy)`` space the draw callback uses) to +//| repaint only that region - like Canvas/Tilemap, the Scene then recomposites and pushes just +//| those rows. Repeated calls union; the rect is clamped to the layer.""" +//| +//| +static mp_obj_t sd_invalidate(size_t n_args, const mp_obj_t *args) { + picogame_stripdraw_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args >= 5) { // (x, y, w, h) in view-local coords -> clamped scene rect + int x1 = self->x + mp_obj_get_int(args[1]); + int y1 = self->y + mp_obj_get_int(args[2]); + int x2 = x1 + mp_obj_get_int(args[3]); + int y2 = y1 + mp_obj_get_int(args[4]); + if (x1 < self->x) { + x1 = self->x; + } + if (y1 < self->y) { + y1 = self->y; + } + if (x2 > self->x + self->w) { + x2 = self->x + self->w; + } + if (y2 > self->y + self->h) { + y2 = self->y + self->h; + } + if (x2 > x1 && y2 > y1) { + picogame_dirty_union(&self->dx1, x1, y1, x2, y2); + } + } else { // whole layer + picogame_dirty_union(&self->dx1, self->x, self->y, self->x + self->w, self->y + self->h); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sd_invalidate_obj, 1, 5, sd_invalidate); + +static const mp_rom_map_elem_t picogame_stripdraw_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&sd_x_obj) }, + { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&sd_y_obj) }, + { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&sd_width_obj) }, + { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&sd_height_obj) }, + { MP_ROM_QSTR(MP_QSTR_always_dirty), MP_ROM_PTR(&sd_always_dirty_obj) }, + { MP_ROM_QSTR(MP_QSTR_invalidate), MP_ROM_PTR(&sd_invalidate_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_stripdraw_locals_dict, picogame_stripdraw_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_stripdraw_type, + MP_QSTR_StripDraw, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_stripdraw_make_new, + locals_dict, &picogame_stripdraw_locals_dict + ); diff --git a/shared-bindings/picogame/StripDraw.h b/shared-bindings/picogame/StripDraw.h new file mode 100644 index 00000000000..68c1506bacf --- /dev/null +++ b/shared-bindings/picogame/StripDraw.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t picogame_stripdraw_type; diff --git a/shared-bindings/picogame/Triangles.c b/shared-bindings/picogame/Triangles.c new file mode 100644 index 00000000000..d3b7fea51a7 --- /dev/null +++ b/shared-bindings/picogame/Triangles.c @@ -0,0 +1,96 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT +// +// picogame.Triangles: a retained screen-space triangle batch rasterised in C. + +#include "py/runtime.h" +#include "shared-module/picogame/pg_compat.h" +#include "shared-bindings/busdisplay/BusDisplay.h" +#include "shared-bindings/picogame/__init__.h" +#include "shared-bindings/picogame/Bitmap.h" +#include "shared-bindings/picogame/Sprite.h" +#if CIRCUITPY_PICOGAME_FAST_DISPLAY +#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports +#include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) +#endif +#include "shared-bindings/picogame/Scene.h" +#include "shared-bindings/picogame/Tilemap.h" +#include "shared-bindings/picogame/Particles.h" +#include "shared-bindings/picogame/Canvas.h" +#include "shared-bindings/picogame/Framebuffer.h" +#include "shared-bindings/picogame/Triangles.h" +#include "shared-module/picogame/__init__.h" +#include "shared-module/picogame/Bitmap.h" +#include "shared-module/picogame/Sprite.h" + +//| class Triangles: +//| def __init__(self, verts: ReadableBuffer, colors: ReadableBuffer) -> None: +//| """A retained SCREEN-SPACE triangle batch drawn entirely in C by the compositor: +//| ``verts`` = int16 x0,y0,x1,y1,x2,y2 per triangle, ``colors`` = uint16 wire RGB565 per +//| triangle - both CALLER-OWNED (fill them in place each frame). Set ``count`` to how +//| many triangles should draw; the assignment marks the layer dirty (full screen). +//| Unlike a StripDraw callback this runs no Python per strip, and unlike a Canvas it +//| holds no pixel buffer - the batch rasterises straight into each render strip with +//| a cheap band reject. The 3D-scene layer: pg.project into the arrays, painter's-order +//| the faces, set count, scene.refresh().""" +//| ... +//| +static mp_obj_t picogame_triangles_make_new(const mp_obj_type_t *type, size_t n_args, + size_t n_kw, const mp_obj_t *all_args) { + mp_arg_check_num(n_args, n_kw, 2, 2, false); + picogame_triangles_obj_t *self = mp_obj_malloc(picogame_triangles_obj_t, type); + mp_buffer_info_t vi, ci; + mp_get_buffer_raise(all_args[0], &vi, MP_BUFFER_READ); + mp_get_buffer_raise(all_args[1], &ci, MP_BUFFER_READ); + self->verts_obj = all_args[0]; + self->colors_obj = all_args[1]; + self->verts = (const int16_t *)vi.buf; + self->colors = (const uint16_t *)ci.buf; + size_t cap_v = vi.len / 12; // 6 int16 = 12 bytes per triangle + size_t cap_c = ci.len >> 1; + self->cap = (uint16_t)(cap_v < cap_c ? cap_v : cap_c); + self->count = 0; + picogame_dirty_reset(&self->dx1); + return MP_OBJ_FROM_PTR(self); +} + +//| count: int +//| """How many triangles of the batch draw next refresh (clamped to the buffer +//| capacity). Assigning marks the layer dirty for a full repaint.""" +//| +//| +static mp_obj_t tri_get_count(mp_obj_t self_in) { + return MP_OBJ_NEW_SMALL_INT(((picogame_triangles_obj_t *)MP_OBJ_TO_PTR(self_in))->count); +} +static MP_DEFINE_CONST_FUN_OBJ_1(tri_get_count_obj, tri_get_count); +static mp_obj_t tri_set_count(mp_obj_t self_in, mp_obj_t v) { + picogame_triangles_obj_t *self = MP_OBJ_TO_PTR(self_in); + int n = mp_obj_get_int(v); + if (n < 0) { + n = 0; + } + if (n > self->cap) { + n = self->cap; + } + self->count = (uint16_t)n; + picogame_dirty_union(&self->dx1, 0, 0, 32767, 32767); // clipped to the play rect later + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_2(tri_set_count_obj, tri_set_count); +MP_PROPERTY_GETSET(tri_count_obj, (mp_obj_t)&tri_get_count_obj, (mp_obj_t)&tri_set_count_obj); + +static const mp_rom_map_elem_t picogame_triangles_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&tri_count_obj) }, +}; +static MP_DEFINE_CONST_DICT(picogame_triangles_locals_dict, picogame_triangles_locals_dict_table); + +MP_DEFINE_CONST_OBJ_TYPE( + picogame_triangles_type, + MP_QSTR_Triangles, + MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, + make_new, picogame_triangles_make_new, + locals_dict, &picogame_triangles_locals_dict + ); diff --git a/shared-bindings/picogame/Triangles.h b/shared-bindings/picogame/Triangles.h new file mode 100644 index 00000000000..86175fcea51 --- /dev/null +++ b/shared-bindings/picogame/Triangles.h @@ -0,0 +1,11 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Vladimir Smitka +// +// SPDX-License-Identifier: MIT + +#pragma once + +#include "py/obj.h" + +extern const mp_obj_type_t picogame_triangles_type; diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c index 273439468de..7cfa1dd741c 100644 --- a/shared-bindings/picogame/__init__.c +++ b/shared-bindings/picogame/__init__.c @@ -23,291 +23,16 @@ #include "shared-bindings/picogame/Particles.h" #include "shared-bindings/picogame/Canvas.h" #include "shared-bindings/picogame/Framebuffer.h" +#include "shared-bindings/picogame/StripDraw.h" +#include "shared-bindings/picogame/Triangles.h" #include "shared-module/picogame/__init__.h" #include "shared-module/picogame/Bitmap.h" #include "shared-module/picogame/Sprite.h" // --------------------------------------------------------------------------- -// Bitmap -// --------------------------------------------------------------------------- - -//| class Bitmap: -//| """An image atlas of one or more equal-size frames, of arbitrary size. -//| -//| Unlike ``_stage`` (fixed 16x16 tiles), frames may be any width/height. -//| Pixel data and palette entries must be in the display's wire byte order -//| (use :py:func:`picogame.rgb565` to build colors).""" -//| -//| def __init__( -//| self, -//| data: ReadableBuffer, -//| width: int, -//| height: int, -//| *, -//| format: int = RGB565, -//| palette: Optional[ReadableBuffer] = None, -//| frames: int = 1, -//| stride: int = 0, -//| transparent: Optional[int] = None, -//| ) -> None: ... -//| -// Int pixel/scale -> 24.8 fixed-point. Shift through unsigned so a wild coordinate (e.g. 100_000_000, -// in 32-bit mp_int range but not after <<8) wraps modularly instead of hitting signed-overflow UB. -// Costs nothing over a plain shift; for any real on-screen coordinate the result is identical. -static int32_t pg_int_to_fp8(mp_int_t v) { - return (int32_t)((uint32_t)v << 8); -} - -static mp_obj_t picogame_bitmap_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_data, ARG_width, ARG_height, ARG_format, ARG_palette, ARG_frames, ARG_stride, ARG_transparent }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_data, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_format, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = PICOGAME_FMT_RGB565} }, - { MP_QSTR_palette, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - { MP_QSTR_frames, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1} }, - { MP_QSTR_stride, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_transparent, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = mp_const_none} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - // bound BEFORE any arithmetic: an unbounded width could overflow width*frames (int32) and wrap - // small, slipping past the size guards below into an undersized buffer (OOB read in the blitter). - mp_int_t width = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 65535, MP_QSTR_width); - mp_int_t height = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 65535, MP_QSTR_height); - mp_int_t frames = mp_arg_validate_int_range(args[ARG_frames].u_int, 1, 255, MP_QSTR_frames); - mp_int_t format = args[ARG_format].u_int; - if (format != PICOGAME_FMT_RGB565 && format != PICOGAME_FMT_PAL8) { - mp_raise_ValueError(MP_ERROR_TEXT("Invalid format")); - } - mp_int_t stride = args[ARG_stride].u_int; - if (stride <= 0) { - stride = width * frames; - } - // stride must hold the whole horizontal atlas, and the dims must fit the uint16_t fields, - // or blits index past a row / the stored stride truncates. - mp_arg_validate_int_max(width * frames, 65535, MP_QSTR_width); - mp_arg_validate_int_max(stride, 65535, MP_QSTR_stride); - mp_arg_validate_int_min(stride, width * frames, MP_QSTR_stride); - - mp_buffer_info_t data_info; - mp_get_buffer_raise(args[ARG_data].u_obj, &data_info, MP_BUFFER_READ); - - const uint16_t *palette = NULL; - mp_obj_t palette_obj = MP_OBJ_NULL; - size_t pal_len = 0; - if (format == PICOGAME_FMT_PAL8) { - if (args[ARG_palette].u_obj == mp_const_none) { - mp_raise_ValueError(MP_ERROR_TEXT("PAL8 needs a palette")); - } - mp_buffer_info_t pal_info; - mp_get_buffer_raise(args[ARG_palette].u_obj, &pal_info, MP_BUFFER_READ); - palette = pal_info.buf; - palette_obj = args[ARG_palette].u_obj; - pal_len = pal_info.len; - } - - size_t bpp = (format == PICOGAME_FMT_PAL8) ? 1 : 2; - // 64-bit: stride*height*bpp can exceed 32 bits (stride,height <= 65535) and wrap small in a 32-bit - // size_t, letting a tiny buffer pass this check -> OOB read in the blitter. Compute + compare wide. - uint64_t need = (uint64_t)stride * (uint64_t)height * (uint64_t)bpp; - if ((uint64_t)data_info.len < need) { - mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); - } - if (format == PICOGAME_FMT_PAL8 && pal_len < 2) { - // Need >=1 entry so pal[0] is valid. Contract (see blitter): PAL8 indices MUST be < palette - // length. The caller may write indices into the (mutable) `data` buffer directly, so we cannot - // validate once here. An out-of-range index is undefined behaviour (reads past the palette: - // usually a garbage colour, but it may fault on some platforms). Per-pixel clamping was dropped - // for speed - see the "restore full bounds-safety" note in the PAL8 blit loop if it's needed. - mp_raise_ValueError(MP_ERROR_TEXT("palette is empty")); - } - - picogame_bitmap_obj_t *self = mp_obj_malloc(picogame_bitmap_obj_t, type); - self->data_obj = args[ARG_data].u_obj; - self->palette_obj = palette_obj; - self->data = data_info.buf; - self->palette = palette; - self->width = width; - self->height = height; - self->stride = stride; - self->frames = frames; - self->format = format; - // palette length in entries (informational; blitter assumes indices < this - see blit contract). - self->pal_entries = (uint16_t)((pal_len / 2) > 65535 ? 65535 : (pal_len / 2)); - if (args[ARG_transparent].u_obj != mp_const_none) { - self->transparent = mp_obj_get_int(args[ARG_transparent].u_obj); - self->has_transparent = true; - } else { - self->transparent = 0; - self->has_transparent = false; - } - return MP_OBJ_FROM_PTR(self); -} - -//| -//| width: int -//| height: int -//| frames: int -//| """Frame dimensions and frame count (read-only).""" -static mp_obj_t bitmap_get_width(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->width); -} -static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_width_obj, bitmap_get_width); -MP_PROPERTY_GETTER(bitmap_width_obj, (mp_obj_t)&bitmap_get_width_obj); - -static mp_obj_t bitmap_get_height(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->height); -} -static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_height_obj, bitmap_get_height); -MP_PROPERTY_GETTER(bitmap_height_obj, (mp_obj_t)&bitmap_get_height_obj); - -static mp_obj_t bitmap_get_frames(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->frames); -} -static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_frames_obj, bitmap_get_frames); -MP_PROPERTY_GETTER(bitmap_frames_obj, (mp_obj_t)&bitmap_get_frames_obj); - -//| format: int -//| """RGB565 or PAL8 (read-only).""" -static mp_obj_t bitmap_get_format(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->format); -} -static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_format_obj, bitmap_get_format); -MP_PROPERTY_GETTER(bitmap_format_obj, (mp_obj_t)&bitmap_get_format_obj); - -//| stride: int -//| """Row stride in pixels (read-only).""" -static mp_obj_t bitmap_get_stride(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->stride); -} -static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_stride_obj, bitmap_get_stride); -MP_PROPERTY_GETTER(bitmap_stride_obj, (mp_obj_t)&bitmap_get_stride_obj); - -//| palette: Optional[ReadableBuffer] -//| """The PAL8 palette buffer this Bitmap was built with, or None for RGB565 -//| (read-only). Lets palette helpers read it back instead of holding a sidecar ref.""" -static mp_obj_t bitmap_get_palette(mp_obj_t self_in) { - picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); - return (self->palette_obj == MP_OBJ_NULL) ? mp_const_none : self->palette_obj; -} -static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_palette_obj, bitmap_get_palette); -MP_PROPERTY_GETTER(bitmap_palette_obj, (mp_obj_t)&bitmap_get_palette_obj); - -//| transparent: Optional[int] -//| """The transparent color/index, or None if the Bitmap is fully opaque (read-only).""" -//| -//| -static mp_obj_t bitmap_get_transparent(mp_obj_t self_in) { - picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); - return self->has_transparent ? MP_OBJ_NEW_SMALL_INT(self->transparent) : mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_transparent_obj, bitmap_get_transparent); -MP_PROPERTY_GETTER(bitmap_transparent_obj, (mp_obj_t)&bitmap_get_transparent_obj); - -static const mp_rom_map_elem_t picogame_bitmap_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&bitmap_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&bitmap_height_obj) }, - { MP_ROM_QSTR(MP_QSTR_frames), MP_ROM_PTR(&bitmap_frames_obj) }, - { MP_ROM_QSTR(MP_QSTR_format), MP_ROM_PTR(&bitmap_format_obj) }, - { MP_ROM_QSTR(MP_QSTR_stride), MP_ROM_PTR(&bitmap_stride_obj) }, - { MP_ROM_QSTR(MP_QSTR_palette), MP_ROM_PTR(&bitmap_palette_obj) }, - { MP_ROM_QSTR(MP_QSTR_transparent), MP_ROM_PTR(&bitmap_transparent_obj) }, -}; -static MP_DEFINE_CONST_DICT(picogame_bitmap_locals_dict, picogame_bitmap_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - picogame_bitmap_type, - MP_QSTR_Bitmap, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, picogame_bitmap_make_new, - locals_dict, &picogame_bitmap_locals_dict - ); - -// --------------------------------------------------------------------------- -// Sprite +// Module-level functions // --------------------------------------------------------------------------- -//| class Sprite: -//| """A positioned, animatable instance of a :py:class:`Bitmap`.""" -//| -//| def __init__( -//| self, -//| bitmap: Bitmap, -//| x: int = 0, -//| y: int = 0, -//| *, -//| frame: int = 0, -//| visible: bool = True, -//| flip_x: bool = False, -//| flip_y: bool = False, -//| ) -> None: ... -//| -static mp_obj_t picogame_sprite_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_bitmap, ARG_x, ARG_y, ARG_frame, ARG_visible, ARG_flip_x, ARG_flip_y }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_bitmap, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_frame, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_visible, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = true} }, - { MP_QSTR_flip_x, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_flip_y, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - mp_obj_t bitmap_obj = mp_arg_validate_type(args[ARG_bitmap].u_obj, &picogame_bitmap_type, MP_QSTR_bitmap); - - picogame_sprite_obj_t *self = mp_obj_malloc(picogame_sprite_obj_t, type); - self->bitmap = MP_OBJ_TO_PTR(bitmap_obj); - self->x = pg_int_to_fp8(args[ARG_x].u_int); // pixel -> 24.8 fixed-point (overflow-clamped) - self->y = pg_int_to_fp8(args[ARG_y].u_int); - self->frame = args[ARG_frame].u_int; - self->flags = (args[ARG_visible].u_bool ? PICOGAME_SPR_VISIBLE : 0) - | (args[ARG_flip_x].u_bool ? PICOGAME_SPR_FLIP_X : 0) - | (args[ARG_flip_y].u_bool ? PICOGAME_SPR_FLIP_Y : 0); - self->anchor_x = 0; // default pivot = top-left (0, 0) - self->anchor_y = 0; - self->scale = 256; // 8.8 fixed-point: 256 = 1.0x (no scaling) - self->angle = 0; // no rotation -> axis-aligned fast path - self->flash_color = 0; - self->dither = 0; - self->data = mp_const_none; - self->seq = 0; // dirty-rect change counter (mp_obj_malloc zeroes anyway; explicit) - return MP_OBJ_FROM_PTR(self); -} - -static void set_flag(picogame_sprite_obj_t *self, uint8_t flag, bool on) { - if (on) { - self->flags |= flag; - } else { - self->flags &= ~flag; - } -} - -// shadow / flash / dither are mutually exclusive (one blit effect at a time); setting one ON -// clears the others, so "the last effect you set wins". Turning one OFF clears ONLY its own flag, -// so clearing an effect you never enabled (e.g. spr.flash = 0) can't wipe a different active one. -#define PICOGAME_SPR_FX_MASK (PICOGAME_SPR_SHADOW | PICOGAME_SPR_FLASH | PICOGAME_SPR_DITHER | PICOGAME_SPR_TINT) -static void set_effect(picogame_sprite_obj_t *self, uint8_t flag, bool on) { - if (on) { - self->flags = (uint8_t)((self->flags & ~PICOGAME_SPR_FX_MASK) | flag); - } else { - self->flags &= (uint8_t) ~flag; - } -} - -// Round a float to 24.8 fixed-point (shared by the position/scale/anchor setters so the soft-float -// round sequence is emitted once, not per call site). -static int32_t pg_round_fp8(mp_float_t f) { - return (int32_t)(f * 256 + (f >= 0 ? (mp_float_t)0.5 : (mp_float_t)-0.5)); -} - // Cast a (possibly subclassed) BusDisplay arg to its native object, raising if it isn't one. // Also accepts the pg.Display fast-DMA wrapper (unwrapped to its underlying busdisplay - the // portable send path): any handle that identifies the panel works wherever a display is @@ -322,758 +47,35 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { #endif mp_obj_t native = mp_obj_cast_to_native_base(obj, &busdisplay_busdisplay_type); if (!mp_obj_is_type(native, &busdisplay_busdisplay_type)) { - mp_raise_TypeError(MP_ERROR_TEXT("expected a BusDisplay")); + mp_arg_validate_type(native, &busdisplay_busdisplay_type, MP_QSTR_display); } return MP_OBJ_TO_PTR(native); } -// Accept an int or float and store as 24.8 fixed-point (rounded). Integer fast path avoids -// software float on RP2040 - game code sets x/y (via move/setters) every frame, usually with ints. -static int32_t obj_to_fp(mp_obj_t o) { - if (mp_obj_is_int(o)) { - return pg_int_to_fp8(mp_obj_get_int(o)); - } - mp_float_t f = mp_obj_get_float(o); - return pg_round_fp8(f); -} - -//| -//| x: int -//| y: int -//| """Integer pixel position (scene coords). Setting accepts a float for -//| sub-pixel placement; reading returns the floored pixel.""" -//| fx: float -//| fy: float -//| """Sub-pixel position (use for smooth physics: e.g. ``sprite.fx += 2.4``).""" -// FLASH NOTE (property objects vs. a single `attr` handler): Sprite (and the other property-dense -// types) expose each attribute as its own getter/setter + MP_PROPERTY object below - the standard -// CircuitPython shared-bindings idiom (~423 such uses across CP). Collapsing these onto ONE `attr` -// load/store function per type (a qstr switch, like py/objcomplex.c's complex_attr for .real/.imag) -// would save ~3-4 KB of flash across the whole binding layer (Sprite alone ~1.5-2.5 KB). It is a -// valid MicroPython mechanism and would NOT break the .pyi stubs (those are generated from the //| -// comments, not the C property objects). We deliberately KEEP property objects: they are the -// idiomatic, most readable shared-bindings form and keep every type's definition uniform. Revisit -// only if flash becomes critical (then convert Sprite first - the densest cluster - not every type). -static mp_obj_t sprite_get_x(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x >> 8); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_x_obj, sprite_get_x); -static mp_obj_t sprite_set_x(mp_obj_t self_in, mp_obj_t v) { - ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x = obj_to_fp(v); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_x_obj, sprite_set_x); -MP_PROPERTY_GETSET(sprite_x_obj, (mp_obj_t)&sprite_get_x_obj, (mp_obj_t)&sprite_set_x_obj); - -static mp_obj_t sprite_get_y(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y >> 8); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_y_obj, sprite_get_y); -static mp_obj_t sprite_set_y(mp_obj_t self_in, mp_obj_t v) { - ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y = obj_to_fp(v); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_y_obj, sprite_set_y); -MP_PROPERTY_GETSET(sprite_y_obj, (mp_obj_t)&sprite_get_y_obj, (mp_obj_t)&sprite_set_y_obj); - -static mp_obj_t sprite_get_fx(mp_obj_t self_in) { - return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->x * (mp_float_t)(1.0 / 256.0)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_fx_obj, sprite_get_fx); -// set_fx is byte-identical to set_x (both store obj_to_fp(v) into ->x) -> reuse set_x's fun obj. -MP_PROPERTY_GETSET(sprite_fx_obj, (mp_obj_t)&sprite_get_fx_obj, (mp_obj_t)&sprite_set_x_obj); - -static mp_obj_t sprite_get_fy(mp_obj_t self_in) { - return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->y * (mp_float_t)(1.0 / 256.0)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_fy_obj, sprite_get_fy); -// set_fy is byte-identical to set_y -> reuse set_y's fun obj. -MP_PROPERTY_GETSET(sprite_fy_obj, (mp_obj_t)&sprite_get_fy_obj, (mp_obj_t)&sprite_set_y_obj); - -static mp_obj_t sprite_get_frame(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->frame); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_frame_obj, sprite_get_frame); -static mp_obj_t sprite_set_frame(mp_obj_t self_in, mp_obj_t v) { - ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->frame = mp_obj_get_int(v); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_frame_obj, sprite_set_frame); -MP_PROPERTY_GETSET(sprite_frame_obj, (mp_obj_t)&sprite_get_frame_obj, (mp_obj_t)&sprite_set_frame_obj); - -static mp_obj_t sprite_get_visible(mp_obj_t self_in) { - return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_VISIBLE) != 0); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_visible_obj, sprite_get_visible); -static mp_obj_t sprite_set_visible(mp_obj_t self_in, mp_obj_t v) { - set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_VISIBLE, mp_obj_is_true(v)); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_visible_obj, sprite_set_visible); -MP_PROPERTY_GETSET(sprite_visible_obj, (mp_obj_t)&sprite_get_visible_obj, (mp_obj_t)&sprite_set_visible_obj); - -static mp_obj_t sprite_get_flip_x(mp_obj_t self_in) { - return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_FLIP_X) != 0); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flip_x_obj, sprite_get_flip_x); -static mp_obj_t sprite_set_flip_x(mp_obj_t self_in, mp_obj_t v) { - set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_FLIP_X, mp_obj_is_true(v)); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_x_obj, sprite_set_flip_x); -MP_PROPERTY_GETSET(sprite_flip_x_obj, (mp_obj_t)&sprite_get_flip_x_obj, (mp_obj_t)&sprite_set_flip_x_obj); - -static mp_obj_t sprite_get_flip_y(mp_obj_t self_in) { - return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_FLIP_Y) != 0); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flip_y_obj, sprite_get_flip_y); -static mp_obj_t sprite_set_flip_y(mp_obj_t self_in, mp_obj_t v) { - set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_FLIP_Y, mp_obj_is_true(v)); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_y_obj, sprite_set_flip_y); -MP_PROPERTY_GETSET(sprite_flip_y_obj, (mp_obj_t)&sprite_get_flip_y_obj, (mp_obj_t)&sprite_set_flip_y_obj); - -//| scale: float -//| """Uniform draw scale (nearest-neighbour). 1.0 = native (fast path); 2.0 = double -//| size, fractional values are allowed (e.g. a powerup grow tween). Anchor stays put.""" -static mp_obj_t sprite_get_scale(mp_obj_t self_in) { - return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->scale * (mp_float_t)(1.0 / 256.0)); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_scale_obj, sprite_get_scale); -static mp_obj_t sprite_set_scale(mp_obj_t self_in, mp_obj_t v) { - int q; - if (mp_obj_is_int(v)) { // int fast path (no software float on RP2040) - q = pg_int_to_fp8(mp_obj_get_int(v)); // overflow-clamped <<8 - } else { - mp_float_t f = mp_obj_get_float(v); - q = pg_round_fp8(f); - } - if (q < 1) { - q = 1; - } - if (q > 65535) { - q = 65535; - } - picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); - self->scale = (uint16_t)q; - self->xf_valid = 0; // affine cache depends on scale - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_scale_obj, sprite_set_scale); -MP_PROPERTY_GETSET(sprite_scale_obj, (mp_obj_t)&sprite_get_scale_obj, (mp_obj_t)&sprite_set_scale_obj); - -//| angle: float -//| """Rotation in degrees about the anchor (0 = none, the fast path). Nearest-neighbour, -//| so integer scales stay crisp; rotation shimmers slightly (pixel-art trade-off).""" -static mp_obj_t sprite_get_angle(mp_obj_t self_in) { - return mp_obj_new_float((mp_float_t)((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->angle); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_angle_obj, sprite_get_angle); -static mp_obj_t sprite_set_angle(mp_obj_t self_in, mp_obj_t v) { - int a; - if (mp_obj_is_int(v)) { // int fast path (no software float on RP2040) - a = mp_obj_get_int(v); - } else { - mp_float_t f = mp_obj_get_float(v); - a = (int)(f + (f >= 0 ? (mp_float_t)0.5 : (mp_float_t)-0.5)); - } - a %= 360; - picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); - self->angle = (int16_t)a; - self->xf_valid = 0; // affine cache depends on angle - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_angle_obj, sprite_set_angle); -MP_PROPERTY_GETSET(sprite_angle_obj, (mp_obj_t)&sprite_get_angle_obj, (mp_obj_t)&sprite_set_angle_obj); - -//| shadow: bool -//| """Draw opaque pixels as a darkened destination instead of colour - a drop-shadow -//| silhouette (offset copy below the sprite) or a dim overlay (a solid sprite scaled -//| over a dialog/pause area).""" -static mp_obj_t sprite_get_shadow(mp_obj_t self_in) { - return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_SHADOW) != 0); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_shadow_obj, sprite_get_shadow); -static mp_obj_t sprite_set_shadow(mp_obj_t self_in, mp_obj_t v) { - set_effect(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_SHADOW, mp_obj_is_true(v)); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_shadow_obj, sprite_set_shadow); -MP_PROPERTY_GETSET(sprite_shadow_obj, (mp_obj_t)&sprite_get_shadow_obj, (mp_obj_t)&sprite_set_shadow_obj); - -//| flash: int -//| """Draw opaque pixels as a solid colour (a wire-order RGB565 int from rgb565) instead -//| of their own colour - a hit-flash or tint. Set to a colour to enable, 0/False to turn -//| off. Pulse it for 1-3 frames on impact. Mutually exclusive with shadow/dither.""" -static mp_obj_t sprite_get_flash(mp_obj_t self_in) { - picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_FLASH) ? s->flash_color : 0); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_flash_obj, sprite_get_flash); -static mp_obj_t sprite_set_flash(mp_obj_t self_in, mp_obj_t v) { - picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); - // Falsy (None / False / 0) turns flash OFF. A non-zero colour enables it. (You can't flash - // pure black - use a near-black colour if you ever need that; off is the common case.) - if (!mp_obj_is_true(v)) { - set_effect(s, PICOGAME_SPR_FLASH, false); - } else { - s->flash_color = (uint16_t)mp_obj_get_int(v); - set_effect(s, PICOGAME_SPR_FLASH, true); - } - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flash_obj, sprite_set_flash); -MP_PROPERTY_GETSET(sprite_flash_obj, (mp_obj_t)&sprite_get_flash_obj, (mp_obj_t)&sprite_set_flash_obj); - -//| dither: int -//| """Fake transparency via an ordered (Bayer) dither, no alpha blending: 0 = opaque -//| (off), 8 = ~50% see-through, 16 = invisible. A classic 1-bit look - for ghosts, -//| fading/spawning enemies, fog, force fields. Mutually exclusive with shadow/flash.""" -static mp_obj_t sprite_get_dither(mp_obj_t self_in) { - picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_DITHER) ? s->dither : 0); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_dither_obj, sprite_get_dither); -static mp_obj_t sprite_set_dither(mp_obj_t self_in, mp_obj_t v) { - picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); - int lv = mp_obj_get_int(v); - if (lv < 0) { - lv = 0; - } - if (lv > 16) { - lv = 16; - } - s->dither = (uint8_t)lv; - set_effect(s, PICOGAME_SPR_DITHER, lv > 0); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_dither_obj, sprite_set_dither); -MP_PROPERTY_GETSET(sprite_dither_obj, (mp_obj_t)&sprite_get_dither_obj, (mp_obj_t)&sprite_set_dither_obj); - -//| tint: int -//| """Multiply opaque pixels by a colour (wire-order RGB565 from rgb565), keeping the -//| sprite's shading - coloured lighting, a red damage flush, a blue freeze, a power-up -//| glow. Unlike ``flash`` (flat replace) ``tint`` preserves detail. 0/False = off. Mutually -//| exclusive with shadow/flash/dither.""" -static mp_obj_t sprite_get_tint(mp_obj_t self_in) { - picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); - return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_TINT) ? s->flash_color : 0); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_tint_obj, sprite_get_tint); -static mp_obj_t sprite_set_tint(mp_obj_t self_in, mp_obj_t v) { - picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); - if (!mp_obj_is_true(v)) { - set_effect(s, PICOGAME_SPR_TINT, false); - } else { - s->flash_color = (uint16_t)mp_obj_get_int(v); // shared colour field with flash - set_effect(s, PICOGAME_SPR_TINT, true); - } - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_tint_obj, sprite_set_tint); -MP_PROPERTY_GETSET(sprite_tint_obj, (mp_obj_t)&sprite_get_tint_obj, (mp_obj_t)&sprite_set_tint_obj); - -//| transpose: bool -//| """Swap the sprite's X/Y axes - a cheap 90deg turn (no shimmer, unlike ``angle``). -//| Combined with ``flip_x``/``flip_y`` it gives all 8 orientations for free. Only on the fast -//| path (scale 1.0, angle 0); for rotation WITH scaling use ``angle``. The drawn footprint -//| swaps width/height.""" -static mp_obj_t sprite_get_transpose(mp_obj_t self_in) { - return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_TRANSPOSE) != 0); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_transpose_obj, sprite_get_transpose); -static mp_obj_t sprite_set_transpose(mp_obj_t self_in, mp_obj_t v) { - set_flag(MP_OBJ_TO_PTR(self_in), PICOGAME_SPR_TRANSPOSE, mp_obj_is_true(v)); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_transpose_obj, sprite_set_transpose); -MP_PROPERTY_GETSET(sprite_transpose_obj, (mp_obj_t)&sprite_get_transpose_obj, (mp_obj_t)&sprite_set_transpose_obj); - -//| data: Any -//| """Arbitrary per-sprite user payload for game state (default None).""" -static mp_obj_t sprite_get_data(mp_obj_t self_in) { - return ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->data; -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_data_obj, sprite_get_data); -static mp_obj_t sprite_set_data(mp_obj_t self_in, mp_obj_t v) { - ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->data = v; - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_data_obj, sprite_set_data); -MP_PROPERTY_GETSET(sprite_data_obj, (mp_obj_t)&sprite_get_data_obj, (mp_obj_t)&sprite_set_data_obj); - -//| bitmap: Bitmap -//| """The sprite's source bitmap. Assigning a new one swaps graphics and may -//| change size; the scene repaints both the old and new bounds next refresh -//| (e.g. powerups, resizable HUD bars, text labels).""" -static mp_obj_t sprite_get_bitmap(mp_obj_t self_in) { - picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); - return self->bitmap != NULL ? MP_OBJ_FROM_PTR(self->bitmap) : mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_bitmap_obj, sprite_get_bitmap); -static mp_obj_t sprite_set_bitmap(mp_obj_t self_in, mp_obj_t v) { - picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_t bm = mp_arg_validate_type(v, &picogame_bitmap_type, MP_QSTR_bitmap); - self->bitmap = MP_OBJ_TO_PTR(bm); - self->xf_valid = 0; // affine cache depends on bitmap dims - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_bitmap_obj, sprite_set_bitmap); -MP_PROPERTY_GETSET(sprite_bitmap_obj, (mp_obj_t)&sprite_get_bitmap_obj, (mp_obj_t)&sprite_set_bitmap_obj); - -//| anchor: Tuple[float, float] -//| """Pivot as fractions of the bitmap size: ``(0, 0)`` = top-left (default), -//| ``(0.5, 0.5)`` = center, ``(0.5, 1.0)`` = bottom-center. ``x``/``y`` then -//| refer to this point, so rotating frames or swapping to a different size -//| stays aligned. Stored in 1/256 steps.""" -//| -static mp_obj_t sprite_get_anchor(mp_obj_t self_in) { - picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_obj_t t[2] = { - mp_obj_new_float(self->anchor_x * (mp_float_t)(1.0 / 256.0)), - mp_obj_new_float(self->anchor_y * (mp_float_t)(1.0 / 256.0)), - }; - return mp_obj_new_tuple(2, t); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_get_anchor_obj, sprite_get_anchor); -static int anchor_to_fp(mp_obj_t o) { - mp_float_t f = mp_obj_get_float(o); - int v = pg_round_fp8(f); - return v < 0 ? 0 : (v > 256 ? 256 : v); -} -static mp_obj_t sprite_set_anchor(mp_obj_t self_in, mp_obj_t v) { - picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); - size_t len; - mp_obj_t *items; - mp_obj_get_array(v, &len, &items); - mp_arg_validate_length(len, 2, MP_QSTR_anchor); - self->anchor_x = anchor_to_fp(items[0]); - self->anchor_y = anchor_to_fp(items[1]); - self->xf_valid = 0; // affine cache depends on the pivot - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_anchor_obj, sprite_set_anchor); -MP_PROPERTY_GETSET(sprite_anchor_obj, (mp_obj_t)&sprite_get_anchor_obj, (mp_obj_t)&sprite_set_anchor_obj); - -//| def move(self, x: int, y: int) -> None: -//| """Set the sprite position.""" -//| ... -//| -static mp_obj_t sprite_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { - picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); - self->x = obj_to_fp(x_in); - self->y = obj_to_fp(y_in); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_3(sprite_move_obj, sprite_move); - -//| def touch(self) -> None: -//| """Force this sprite to repaint on the next ``Scene.refresh()`` even though none -//| of its tracked properties (position, frame, scale, angle, bitmap) changed. Call -//| it after mutating the sprite's bitmap pixels IN PLACE (e.g. streaming a new frame -//| into the same buffer), which the dirty-rect tracker can't otherwise detect.""" -//| ... -//| -static mp_obj_t sprite_touch(mp_obj_t self_in) { - ((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->seq++; - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_1(sprite_touch_obj, sprite_touch); - -// Fill (x1,y1,x2,y2) from a Sprite (its drawn aabb), a (x,y) point, or a (x1,y1,x2,y2) rect. -static void pg_obj_to_box(mp_obj_t o, int *x1, int *y1, int *x2, int *y2) { - if (mp_obj_is_type(o, &picogame_sprite_type)) { - picogame_sprite_aabb(MP_OBJ_TO_PTR(o), x1, y1, x2, y2); - return; - } - if (mp_obj_is_type(o, &mp_type_tuple) || mp_obj_is_type(o, &mp_type_list)) { - size_t len; - mp_obj_t *items; - mp_obj_get_array(o, &len, &items); - if (len == 2) { // a point -> a zero-size box - *x1 = *x2 = mp_obj_get_int(items[0]); - *y1 = *y2 = mp_obj_get_int(items[1]); - return; - } - if (len == 4) { // a rect - *x1 = mp_obj_get_int(items[0]); - *y1 = mp_obj_get_int(items[1]); - *x2 = mp_obj_get_int(items[2]); - *y2 = mp_obj_get_int(items[3]); - return; - } - } - mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), - MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(o)->name); -} - -//| def overlaps(self, other: "Sprite | tuple", inset: int = 0) -> bool: -//| """True if this sprite's drawn box overlaps ``other`` - an inclusive AABB, so they -//| collide the moment they touch. ``other`` may be another Sprite, a point ``(x, y)``, -//| or a rect ``(x1, y1, x2, y2)`` (e.g. a trigger zone or the screen for culling). -//| The box is anchor/scale/rotation aware. ``inset`` shrinks THIS sprite's box by N px -//| on each side, for a fair hitbox smaller than the art.""" -//| ... -//| -static mp_obj_t sprite_overlaps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_other, ARG_inset }; - static const mp_arg_t allowed[] = { - { MP_QSTR_other, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_inset, MP_ARG_INT, {.u_int = 0} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed)]; - mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed), allowed, args); - int ax1, ay1, ax2, ay2, bx1, by1, bx2, by2; - picogame_sprite_aabb(MP_OBJ_TO_PTR(pos_args[0]), &ax1, &ay1, &ax2, &ay2); - pg_obj_to_box(args[ARG_other].u_obj, &bx1, &by1, &bx2, &by2); - int in = args[ARG_inset].u_int; // inset shrinks the CALLER's box (kw or positional) - bool hit = ((ax1 + in) <= bx2) && ((ax2 - in) >= bx1) && - ((ay1 + in) <= by2) && ((ay2 - in) >= by1); - return mp_obj_new_bool(hit); -} -static MP_DEFINE_CONST_FUN_OBJ_KW(sprite_overlaps_obj, 2, sprite_overlaps); - -//| def near(self, other: "Sprite | tuple", r: int) -> bool: -//| """True if this sprite's centre is within ``r`` pixels of ``other``'s centre (squared -//| distance, no sqrt) - the round/forgiving test for bullets, pickups, explosions. -//| ``other`` may be a Sprite or a point ``(x, y)``. Centres come from the drawn box, so -//| it is anchor aware.""" -//| ... -//| -//| -static mp_obj_t sprite_near(mp_obj_t self_in, mp_obj_t other_in, mp_obj_t r_in) { - int ax1, ay1, ax2, ay2; - picogame_sprite_aabb(MP_OBJ_TO_PTR(self_in), &ax1, &ay1, &ax2, &ay2); - int acx = (ax1 + ax2) / 2, acy = (ay1 + ay2) / 2, bcx, bcy; - if (mp_obj_is_type(other_in, &picogame_sprite_type)) { - int bx1, by1, bx2, by2; - picogame_sprite_aabb(MP_OBJ_TO_PTR(other_in), &bx1, &by1, &bx2, &by2); - bcx = (bx1 + bx2) / 2; - bcy = (by1 + by2) / 2; - } else { - size_t len; - mp_obj_t *items; - mp_obj_get_array(other_in, &len, &items); - if (len != 2) { - mp_raise_msg_varg(&mp_type_TypeError, MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), - MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(other_in)->name); - } - bcx = mp_obj_get_int(items[0]); - bcy = mp_obj_get_int(items[1]); - } - mp_int_t r = mp_obj_get_int(r_in), dx = acx - bcx, dy = acy - bcy; - return mp_obj_new_bool(dx * dx + dy * dy < r * r); -} -static MP_DEFINE_CONST_FUN_OBJ_3(sprite_near_obj, sprite_near); - -static const mp_rom_map_elem_t picogame_sprite_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&sprite_x_obj) }, - { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&sprite_y_obj) }, - { MP_ROM_QSTR(MP_QSTR_fx), MP_ROM_PTR(&sprite_fx_obj) }, - { MP_ROM_QSTR(MP_QSTR_fy), MP_ROM_PTR(&sprite_fy_obj) }, - { MP_ROM_QSTR(MP_QSTR_frame), MP_ROM_PTR(&sprite_frame_obj) }, - { MP_ROM_QSTR(MP_QSTR_visible), MP_ROM_PTR(&sprite_visible_obj) }, - { MP_ROM_QSTR(MP_QSTR_flip_x), MP_ROM_PTR(&sprite_flip_x_obj) }, - { MP_ROM_QSTR(MP_QSTR_flip_y), MP_ROM_PTR(&sprite_flip_y_obj) }, - { MP_ROM_QSTR(MP_QSTR_scale), MP_ROM_PTR(&sprite_scale_obj) }, - { MP_ROM_QSTR(MP_QSTR_angle), MP_ROM_PTR(&sprite_angle_obj) }, - { MP_ROM_QSTR(MP_QSTR_shadow), MP_ROM_PTR(&sprite_shadow_obj) }, - { MP_ROM_QSTR(MP_QSTR_flash), MP_ROM_PTR(&sprite_flash_obj) }, - { MP_ROM_QSTR(MP_QSTR_dither), MP_ROM_PTR(&sprite_dither_obj) }, - { MP_ROM_QSTR(MP_QSTR_tint), MP_ROM_PTR(&sprite_tint_obj) }, - { MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&sprite_transpose_obj) }, - { MP_ROM_QSTR(MP_QSTR_data), MP_ROM_PTR(&sprite_data_obj) }, - { MP_ROM_QSTR(MP_QSTR_bitmap), MP_ROM_PTR(&sprite_bitmap_obj) }, - { MP_ROM_QSTR(MP_QSTR_anchor), MP_ROM_PTR(&sprite_anchor_obj) }, - { MP_ROM_QSTR(MP_QSTR_overlaps), MP_ROM_PTR(&sprite_overlaps_obj) }, - { MP_ROM_QSTR(MP_QSTR_near), MP_ROM_PTR(&sprite_near_obj) }, - { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&sprite_move_obj) }, - { MP_ROM_QSTR(MP_QSTR_touch), MP_ROM_PTR(&sprite_touch_obj) }, -}; -static MP_DEFINE_CONST_DICT(picogame_sprite_locals_dict, picogame_sprite_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - picogame_sprite_type, - MP_QSTR_Sprite, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, picogame_sprite_make_new, - locals_dict, &picogame_sprite_locals_dict - ); - -// --------------------------------------------------------------------------- -// StripDraw (immediate-mode draw layer; struct in shared-module/picogame/__init__.h) -// --------------------------------------------------------------------------- - -//| class StripDraw: -//| """An immediate-mode draw layer that holds NO pixel buffer. Each refresh, for -//| every render strip overlapping its rect, ``callback(view, vx, vy, vw, vh)`` is -//| called with a :py:class:`Canvas` ``view`` pointing straight at the live strip -//| buffer - so you draw primitives directly into the frame (zero RAM, vs a Canvas -//| which costs width*height*2 bytes). The view's local (0, 0) is screen pixel -//| (vx, vy); (vw, vh) is the strip size. Draw only the rows in [vy, vy+vh) for -//| speed (anything outside the view is clipped anyway). The rect is repainted every -//| frame, so use it for animated / scanline content (pseudo-3D, gradients, -//| procedural backgrounds), not static art (use Canvas for that). -//| -//| COORDINATE CONTRACT: ``vx`` is the RENDER REGION's origin (NOT this layer's x), and the -//| view spans the FULL region WIDTH (the layer's rect only gates which ROWS run). So draw at -//| ABSOLUTE screen coords minus (vx, vy), and fill only your own rect with ``fill_rect`` - -//| ``view.clear()`` fills the whole region width. (When you render a StripDraw via -//| ``picogame.render([sd], buf, x,y,x+w,y+h)`` the region == the rect, so vx == x.) -//| Text via ``Canvas.text`` is ASCII (the built-in font); non-ASCII has no glyph.""" -//| -//| def __init__( -//| self, -//| callback: Callable[[Canvas, int, int, int, int], None], -//| x: int = 0, -//| y: int = 0, -//| width: int = 0, -//| height: int = 0, -//| ) -> None: ... -//| -static mp_obj_t picogame_stripdraw_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_callback, ARG_x, ARG_y, ARG_width, ARG_height, ARG_always_dirty }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_callback, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_x, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_y, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_width, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_height, MP_ARG_INT, {.u_int = 0} }, - { MP_QSTR_always_dirty, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = true} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - - picogame_stripdraw_obj_t *self = mp_obj_malloc(picogame_stripdraw_obj_t, type); - self->callback = args[ARG_callback].u_obj; - self->x = args[ARG_x].u_int; - self->y = args[ARG_y].u_int; - self->w = args[ARG_width].u_int; - self->h = args[ARG_height].u_int; - self->faulted = false; - self->always_dirty = args[ARG_always_dirty].u_bool; - picogame_dirty_reset(&self->dx1); // render once on first refresh (even when always_dirty=False) - picogame_dirty_union(&self->dx1, self->x, self->y, self->x + self->w, self->y + self->h); - // A buffer-less Canvas reused as the per-strip drawing view: its `data` is - // repointed at the live strip each blit, so no surface RAM is allocated here. - picogame_canvas_obj_t *view = mp_obj_malloc(picogame_canvas_obj_t, &picogame_canvas_type); - view->data = NULL; - view->data_obj = MP_OBJ_NULL; - view->w = 0; - view->h = 0; - view->x = 0; - view->y = 0; - view->transparent = 0; - view->has_transparent = false; - picogame_canvas_dirty_reset(view); - self->view = MP_OBJ_FROM_PTR(view); - return MP_OBJ_FROM_PTR(self); -} - -//| -//| x: int -//| y: int -//| width: int -//| height: int -//| """The screen rect repainted each refresh (read/write). Move or resize the layer -//| by assigning these. Shrinking the rect leaves stale pixels behind - follow a -//| shrink with ``scene.invalidate()`` for a clean repaint (as the fx helpers do).""" -static mp_obj_t sd_get_x(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_x_obj, sd_get_x); -static mp_obj_t sd_set_x(mp_obj_t self_in, mp_obj_t v) { - ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x = mp_obj_get_int(v); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_x_obj, sd_set_x); -MP_PROPERTY_GETSET(sd_x_obj, (mp_obj_t)&sd_get_x_obj, (mp_obj_t)&sd_set_x_obj); - -static mp_obj_t sd_get_y(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->y); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_y_obj, sd_get_y); -static mp_obj_t sd_set_y(mp_obj_t self_in, mp_obj_t v) { - ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->y = mp_obj_get_int(v); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_y_obj, sd_set_y); -MP_PROPERTY_GETSET(sd_y_obj, (mp_obj_t)&sd_get_y_obj, (mp_obj_t)&sd_set_y_obj); - -static mp_obj_t sd_get_width(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->w); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_width_obj, sd_get_width); -static mp_obj_t sd_set_width(mp_obj_t self_in, mp_obj_t v) { - ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->w = mp_obj_get_int(v); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_width_obj, sd_set_width); -MP_PROPERTY_GETSET(sd_width_obj, (mp_obj_t)&sd_get_width_obj, (mp_obj_t)&sd_set_width_obj); - -static mp_obj_t sd_get_height(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->h); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_height_obj, sd_get_height); -static mp_obj_t sd_set_height(mp_obj_t self_in, mp_obj_t v) { - ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->h = mp_obj_get_int(v); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_height_obj, sd_set_height); -MP_PROPERTY_GETSET(sd_height_obj, (mp_obj_t)&sd_get_height_obj, (mp_obj_t)&sd_set_height_obj); - -//| always_dirty: bool -//| """True (default): repaint every frame - for animated content (pseudo-3D, gradients). False: -//| repaint only after an ``invalidate()`` call (or when overlapped by another dirty layer) - for on-change UI, -//| so a static panel doesn't re-rasterize+re-push every frame. With False you MUST invalidate() on -//| every content/visibility change (it's invisible until you do).""" -//| -static mp_obj_t sd_get_always_dirty(mp_obj_t self_in) { - return mp_obj_new_bool(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty); -} -static MP_DEFINE_CONST_FUN_OBJ_1(sd_get_always_dirty_obj, sd_get_always_dirty); -static mp_obj_t sd_set_always_dirty(mp_obj_t self_in, mp_obj_t v) { - ((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty = mp_obj_is_true(v); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_always_dirty_obj, sd_set_always_dirty); -MP_PROPERTY_GETSET(sd_always_dirty_obj, (mp_obj_t)&sd_get_always_dirty_obj, (mp_obj_t)&sd_set_always_dirty_obj); - -//| def invalidate(self, x: int = 0, y: int = 0, w: int = 0, h: int = 0) -> None: -//| """Mark dirty so the layer repaints on the next refresh (only needed when -//| ``always_dirty=False``). With no args, the whole layer repaints. Pass a rect in -//| VIEW-LOCAL coordinates (the same (0,0)-at-``(vx, vy)`` space the draw callback uses) to -//| repaint only that region - like Canvas/Tilemap, the Scene then recomposites and pushes just -//| those rows. Repeated calls union; the rect is clamped to the layer.""" -//| -//| -static mp_obj_t sd_invalidate(size_t n_args, const mp_obj_t *args) { - picogame_stripdraw_obj_t *self = MP_OBJ_TO_PTR(args[0]); - if (n_args >= 5) { // (x, y, w, h) in view-local coords -> clamped scene rect - int x1 = self->x + mp_obj_get_int(args[1]); - int y1 = self->y + mp_obj_get_int(args[2]); - int x2 = x1 + mp_obj_get_int(args[3]); - int y2 = y1 + mp_obj_get_int(args[4]); - if (x1 < self->x) { - x1 = self->x; - } - if (y1 < self->y) { - y1 = self->y; - } - if (x2 > self->x + self->w) { - x2 = self->x + self->w; - } - if (y2 > self->y + self->h) { - y2 = self->y + self->h; - } - if (x2 > x1 && y2 > y1) { - picogame_dirty_union(&self->dx1, x1, y1, x2, y2); - } - } else { // whole layer - picogame_dirty_union(&self->dx1, self->x, self->y, self->x + self->w, self->y + self->h); - } - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(sd_invalidate_obj, 1, 5, sd_invalidate); - -static const mp_rom_map_elem_t picogame_stripdraw_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&sd_x_obj) }, - { MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&sd_y_obj) }, - { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&sd_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&sd_height_obj) }, - { MP_ROM_QSTR(MP_QSTR_always_dirty), MP_ROM_PTR(&sd_always_dirty_obj) }, - { MP_ROM_QSTR(MP_QSTR_invalidate), MP_ROM_PTR(&sd_invalidate_obj) }, -}; -static MP_DEFINE_CONST_DICT(picogame_stripdraw_locals_dict, picogame_stripdraw_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - picogame_stripdraw_type, - MP_QSTR_StripDraw, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, picogame_stripdraw_make_new, - locals_dict, &picogame_stripdraw_locals_dict - ); - -//| class Triangles: -//| def __init__(self, verts: ReadableBuffer, colors: ReadableBuffer) -> None: -//| """A retained SCREEN-SPACE triangle batch drawn entirely in C by the compositor: -//| ``verts`` = int16 x0,y0,x1,y1,x2,y2 per triangle, ``colors`` = uint16 wire RGB565 per -//| triangle - both CALLER-OWNED (fill them in place each frame). Set ``count`` to how -//| many triangles should draw; the assignment marks the layer dirty (full screen). -//| Unlike a StripDraw callback this runs no Python per strip, and unlike a Canvas it -//| holds no pixel buffer - the batch rasterises straight into each render strip with -//| a cheap band reject. The 3D-scene layer: pg.project into the arrays, painter's-order -//| the faces, set count, scene.refresh().""" -//| ... -//| -static mp_obj_t picogame_triangles_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *all_args) { - mp_arg_check_num(n_args, n_kw, 2, 2, false); - picogame_triangles_obj_t *self = mp_obj_malloc(picogame_triangles_obj_t, type); - mp_buffer_info_t vi, ci; - mp_get_buffer_raise(all_args[0], &vi, MP_BUFFER_READ); - mp_get_buffer_raise(all_args[1], &ci, MP_BUFFER_READ); - self->verts_obj = all_args[0]; - self->colors_obj = all_args[1]; - self->verts = (const int16_t *)vi.buf; - self->colors = (const uint16_t *)ci.buf; - size_t cap_v = vi.len / 12; // 6 int16 = 12 bytes per triangle - size_t cap_c = ci.len >> 1; - self->cap = (uint16_t)(cap_v < cap_c ? cap_v : cap_c); - self->count = 0; - picogame_dirty_reset(&self->dx1); - return MP_OBJ_FROM_PTR(self); -} - -//| count: int -//| """How many triangles of the batch draw next refresh (clamped to the buffer -//| capacity). Assigning marks the layer dirty for a full repaint.""" -//| -//| -static mp_obj_t tri_get_count(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_triangles_obj_t *)MP_OBJ_TO_PTR(self_in))->count); -} -static MP_DEFINE_CONST_FUN_OBJ_1(tri_get_count_obj, tri_get_count); -static mp_obj_t tri_set_count(mp_obj_t self_in, mp_obj_t v) { - picogame_triangles_obj_t *self = MP_OBJ_TO_PTR(self_in); - int n = mp_obj_get_int(v); - if (n < 0) { - n = 0; - } - if (n > self->cap) { - n = self->cap; - } - self->count = (uint16_t)n; - picogame_dirty_union(&self->dx1, 0, 0, 32767, 32767); // clipped to the play rect later - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(tri_set_count_obj, tri_set_count); -MP_PROPERTY_GETSET(tri_count_obj, (mp_obj_t)&tri_get_count_obj, (mp_obj_t)&tri_set_count_obj); - -static const mp_rom_map_elem_t picogame_triangles_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_count), MP_ROM_PTR(&tri_count_obj) }, -}; -static MP_DEFINE_CONST_DICT(picogame_triangles_locals_dict, picogame_triangles_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - picogame_triangles_type, - MP_QSTR_Triangles, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, picogame_triangles_make_new, - locals_dict, &picogame_triangles_locals_dict - ); - -// --------------------------------------------------------------------------- -// Module-level functions -// --------------------------------------------------------------------------- - //| """2D game engine for the PicoPad and similar boards. //| //| Draws arbitrary-size sprites (unlike ``_stage``'s fixed 16x16 tiles) to a //| ``busdisplay`` through a reusable strip buffer, with a dirty-rect scene, -//| tilemaps, particles, a drawing canvas and camera/effects.""" +//| tilemaps, particles, a drawing canvas and camera/effects. +//| +//| **Relationship to displayio.** picogame does not replace or extend +//| :py:mod:`displayio`; it is a second, game-shaped way to drive the same +//| hardware, and the two do not share a display at the same time. displayio +//| retains a widget tree the supervisor refreshes for you, holds a full +//| :py:class:`~displayio.Bitmap` per image and is the right tool for UI. picogame +//| composites on demand, one horizontal strip at a time, into a buffer the game +//| owns: nothing is retained per pixel, so a scrolling game fits in the RAM a +//| microcontroller actually has, and the game decides when a frame happens +//| (``scene.refresh()``). +//| +//| The seam is the display object. A ``picogame.Scene`` takes the same +//| :py:class:`~busdisplay.BusDisplay` displayio uses - it just talks to it +//| directly instead of through the displayio refresh loop, so set +//| ``display.auto_refresh = False`` (``picogame_game.setup()`` does this) and let +//| the game drive. On boards that scan out of RAM, ``picogame.Framebuffer`` takes +//| that buffer instead. Bitmaps are separate types: displayio's is a mutable +//| indexed surface, picogame's is read-only pixel data (PAL8 or wire RGB565) that +//| may live in flash, so it costs no RAM at all.""" //| //| RGB565: int //| """16-bit color bitmap format (wire byte order).""" @@ -1407,7 +409,7 @@ uint8_t picogame_kind_of(mp_obj_t o) { if (mp_obj_is_type(o, &picogame_triangles_type)) { return PICOGAME_KIND_TRIANGLES; } - mp_raise_TypeError(MP_ERROR_TEXT("expected a Sprite, Tilemap, Particles, Canvas, StripDraw or Triangles")); + mp_arg_error_invalid(MP_QSTR_item); // the accepted layer types are listed in the docs } static mp_obj_t picogame_render_fun(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -1609,7 +611,7 @@ static const mp_arg_t pg_fbm2d_args[] = { }; #if 0 // float reference fbm - superseded by the fixed-point path below -//| def fbm2d(x, y, *, octaves=4, seed=0, lacunarity=2.0, gain=0.5) -> float: ... +//| def fbm2d(x: float, y: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: ... static mp_obj_t picogame_fbm2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { mp_arg_val_t a[6]; mp_arg_parse_all(n_args, pos, kw, 6, pg_fbm2d_args, a); @@ -1629,7 +631,7 @@ static mp_obj_t picogame_fbm2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) } static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm2d_obj, 2, picogame_fbm2d); -//| def fbm1d(x, *, octaves=4, seed=0, lacunarity=2.0, gain=0.5) -> float: ... +//| def fbm1d(x: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: ... //| //| static mp_obj_t picogame_fbm1d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { @@ -1741,133 +743,6 @@ static mp_obj_t picogame_fbm1d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t * } static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm1d_fx_obj, 1, picogame_fbm1d_fx); -#if CIRCUITPY_PICOGAME_FRAMEBUFFER -// --------------------------------------------------------------------------- -// Framebuffer (a RAM render target used in place of a BusDisplay; scanout-buffer -// platforms - WASM playground, desktop sim, FruitJam DVI/HSTX) -// --------------------------------------------------------------------------- -//| class Framebuffer: -//| """A RAM framebuffer render target that a Scene or :py:func:`render` can draw -//| into instead of a BusDisplay. ``buffer`` must be a writable buffer of at least -//| ``width*height*2`` bytes (``width*height`` for ``rgb332=True``); the caller owns it -//| (a ``bytearray`` in the browser, the DVI scanout buffer on FruitJam). By default the -//| pixels are wire-order RGB565 (the engine's internal format); ``native_rgb565=True`` -//| byte-swaps each finished region to NATIVE RGB565 - the format 16-bit picodvi / -//| canvas scanout targets expect; ``rgb332=True`` quantizes each finished region to -//| RGB332 bytes - the format of 8-bit picodvi scanout (FruitJam 640x480, which the -//| hardware only offers at 8bpp). Assets, palettes and ``rgb565()`` stay wire-order -//| RGB565 throughout regardless of the output format.""" -//| -//| def __init__( -//| self, -//| buffer: WriteableBuffer, -//| width: int, -//| height: int, -//| *, -//| native_rgb565: bool = False, -//| rgb332: bool = False, -//| ) -> None: ... -//| -//| -// Static SRAM compose strip (see the scratch comment in make_new). 640*16*2 = 20 KB .bss, -// only on CIRCUITPY_PICOGAME_FRAMEBUFFER builds (fb boards have the SRAM to spare). -#define PICOGAME_FB_SCRATCH_MAX_W 640 -static uint16_t picogame_fb_scratch_sram[PICOGAME_FB_SCRATCH_MAX_W * PICOGAME_FB_SCRATCH_H]; - -static mp_obj_t picogame_framebuffer_make_new(const mp_obj_type_t *type, size_t n_args, - size_t n_kw, const mp_obj_t *all_args) { - enum { ARG_buffer, ARG_width, ARG_height, ARG_native_rgb565, ARG_rgb332 }; - static const mp_arg_t allowed_args[] = { - { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_width, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_height, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_native_rgb565, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - { MP_QSTR_rgb332, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, - }; - mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; - mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); - mp_int_t width = mp_arg_validate_int_range(args[ARG_width].u_int, 1, 4096, MP_QSTR_width); - mp_int_t height = mp_arg_validate_int_range(args[ARG_height].u_int, 1, 4096, MP_QSTR_height); - if (args[ARG_native_rgb565].u_bool && args[ARG_rgb332].u_bool) { - mp_arg_error_invalid(MP_QSTR_format); // native_rgb565 and rgb332 are exclusive - } - bool rgb332 = args[ARG_rgb332].u_bool; - - mp_buffer_info_t bi; - mp_get_buffer_raise(args[ARG_buffer].u_obj, &bi, MP_BUFFER_WRITE); - uint64_t need = (uint64_t)width * (uint64_t)height * (rgb332 ? 1u : 2u); - if ((uint64_t)bi.len < need) { - mp_raise_ValueError(MP_ERROR_TEXT("buffer too small")); - } - - picogame_framebuffer_obj_t *self = mp_obj_malloc(picogame_framebuffer_obj_t, type); - self->buffer = args[ARG_buffer].u_obj; - self->fb = (uint16_t *)bi.buf; - self->width = width; - self->height = height; - self->fmt = rgb332 ? PICOGAME_FB_RGB332 - : (args[ARG_native_rgb565].u_bool ? PICOGAME_FB_NATIVE565 : PICOGAME_FB_WIRE565); - // A LIVE scanout buffer (picodvi/HDMI) is read continuously, so picogame_render_framebuffer - // composes each band into this PRIVATE strip and only memcpys the FINISHED band into the fb. - // That serves BOTH targets: (a) native -> also byte-swap the strip so the fb never holds wire - // (no pink); (b) wire -> no swap, but the off-screen compose still stops the beam from sampling - // a half-composited region (background filled, sprite not yet drawn) = no sprite/HUD flicker. - // Always allocated for the FB target; the WASM/sim path (read out after present, not live) just - // pays a small strip + one memcpy. See PICOGAME_FB_SCRATCH_H. - // - // The scratch must be FAST memory: on a PSRAM-heap board (Fruit Jam) a heap bytearray - // lands in external PSRAM and every compose write pays QSPI latency (measured 8.7 vs - // 64+ MB/s SRAM; a full-res StripDraw frame ballooned refresh to ~30-38 ms). One static - // SRAM strip serves every Framebuffer (compose is synchronous) up to 640 px wide; wider - // targets fall back to the heap. - self->scratch_buf = mp_const_none; - self->scratch = NULL; - self->scratch_rows = 0; - { - int rows = PICOGAME_FB_SCRATCH_H; - if (rows > height) { - rows = height; - } - if (width <= PICOGAME_FB_SCRATCH_MAX_W) { - self->scratch = picogame_fb_scratch_sram; - } else { - mp_obj_t sb = mp_obj_new_bytearray_of_zeros((size_t)width * (size_t)rows * 2u); - mp_buffer_info_t sbi; - mp_get_buffer_raise(sb, &sbi, MP_BUFFER_WRITE); - self->scratch_buf = sb; - self->scratch = (uint16_t *)sbi.buf; - } - self->scratch_rows = rows; - } - return MP_OBJ_FROM_PTR(self); -} - -static mp_obj_t picogame_framebuffer_get_width(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_framebuffer_obj_t *)MP_OBJ_TO_PTR(self_in))->width); -} -static MP_DEFINE_CONST_FUN_OBJ_1(picogame_framebuffer_get_width_obj, picogame_framebuffer_get_width); -MP_PROPERTY_GETTER(picogame_framebuffer_width_obj, (mp_obj_t)&picogame_framebuffer_get_width_obj); - -static mp_obj_t picogame_framebuffer_get_height(mp_obj_t self_in) { - return MP_OBJ_NEW_SMALL_INT(((picogame_framebuffer_obj_t *)MP_OBJ_TO_PTR(self_in))->height); -} -static MP_DEFINE_CONST_FUN_OBJ_1(picogame_framebuffer_get_height_obj, picogame_framebuffer_get_height); -MP_PROPERTY_GETTER(picogame_framebuffer_height_obj, (mp_obj_t)&picogame_framebuffer_get_height_obj); - -static const mp_rom_map_elem_t picogame_framebuffer_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_width), MP_ROM_PTR(&picogame_framebuffer_width_obj) }, - { MP_ROM_QSTR(MP_QSTR_height), MP_ROM_PTR(&picogame_framebuffer_height_obj) }, -}; -static MP_DEFINE_CONST_DICT(picogame_framebuffer_locals_dict, picogame_framebuffer_locals_dict_table); - -MP_DEFINE_CONST_OBJ_TYPE( - picogame_framebuffer_type, - MP_QSTR_Framebuffer, - MP_TYPE_FLAG_HAS_SPECIAL_ACCESSORS, - make_new, picogame_framebuffer_make_new, - locals_dict, &picogame_framebuffer_locals_dict - ); -#endif // CIRCUITPY_PICOGAME_FRAMEBUFFER static const mp_rom_map_elem_t picogame_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picogame) }, diff --git a/shared-bindings/picogame/__init__.h b/shared-bindings/picogame/__init__.h index 8b8047f44dc..9bfca623beb 100644 --- a/shared-bindings/picogame/__init__.h +++ b/shared-bindings/picogame/__init__.h @@ -8,8 +8,5 @@ #include "py/obj.h" -// Defined in shared-bindings/picogame/__init__.c (consolidated with Bitmap/Sprite). -extern const mp_obj_type_t picogame_stripdraw_type; -extern const mp_obj_type_t picogame_triangles_type; uint8_t picogame_kind_of(mp_obj_t o); From 8085a9633cc6c2aa1fb0bbd8193c3abd62cdf9d2 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Mon, 17 Aug 2026 16:45:32 -0500 Subject: [PATCH 782/876] Require that filter object is `None`, `synthio.Biquad` or `tuple` of `synthio.Biquad` (disallow `list`) --- shared-module/audiofilters/__init__.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/shared-module/audiofilters/__init__.c b/shared-module/audiofilters/__init__.c index 6435ec36e36..a663170de88 100644 --- a/shared-module/audiofilters/__init__.c +++ b/shared-module/audiofilters/__init__.c @@ -13,10 +13,7 @@ void audiofilters_assign_filters(mp_obj_t filter_in, mp_obj_t *filter_out, mp_ob if (filter_in == mp_const_none) { n_items = 0; *filter_objs = NULL; - } else if (MP_OBJ_TYPE_HAS_SLOT(mp_obj_get_type(filter_in), iter)) { - // convert object to tuple if it wasn't before - filter_in = MP_OBJ_TYPE_GET_SLOT(&mp_type_tuple, make_new)( - &mp_type_tuple, 1, 0, &filter_in); + } else if (mp_obj_is_type(filter_in, &mp_type_tuple)) { mp_obj_tuple_get(filter_in, &n_items, &items); for (size_t i = 0; i < n_items; i++) { if (!mp_obj_is_type(items[i], &synthio_biquad_type_obj)) { From 30e76fdc120557e422bf1d014c8bbf39607af6d5 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Mon, 17 Aug 2026 14:17:28 -0700 Subject: [PATCH 783/876] Add Clue test build for Zephyr --- .../autogen_board_info.toml | 129 ++++++++++++++++++ .../clue_nrf52840_zephyr/circuitpython.toml | 4 + .../boards/adafruit_clue_nrf52840_uf2.conf | 6 + .../boards/adafruit_clue_nrf52840_uf2.overlay | 49 +++++++ ports/zephyr-cp/boards/board_aliases.cmake | 1 + ports/zephyr-cp/common-hal/_bleio/Adapter.c | 12 ++ ports/zephyr-cp/cptools/zephyr2cp.py | 23 ++++ ports/zephyr-cp/debug.conf | 1 + ports/zephyr-cp/supervisor/usb.c | 39 +++++- ports/zephyr-cp/zephyr-config/west.yml | 2 +- 10 files changed, 262 insertions(+), 4 deletions(-) create mode 100644 ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.conf create mode 100644 ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.overlay diff --git a/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/autogen_board_info.toml b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/autogen_board_info.toml new file mode 100644 index 00000000000..0afea836c10 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/autogen_board_info.toml @@ -0,0 +1,129 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Adafruit Industries LLC CLUE nRF52840 Express" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has displayio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = false +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = true # Zephyr board has nvm +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = false +spitarget = false +ssl = false +storage = true # Zephyr board has flash +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = true +usb_hid = true +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = false +zephyr_display = true # Zephyr board has zephyr_display +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/circuitpython.toml b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/circuitpython.toml new file mode 100644 index 00000000000..2d7b8c3db48 --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/circuitpython.toml @@ -0,0 +1,4 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["hex", "uf2"] +USB_VID=0x239A +USB_PID=0x8072 +NAME="CLUE nRF52840 Express" diff --git a/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.conf b/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.conf new file mode 100644 index 00000000000..cfa31e2fdcf --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.conf @@ -0,0 +1,6 @@ +CONFIG_USE_DT_CODE_PARTITION=y + +CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n + +# Enable the ST7789V TFT via the Zephyr display subsystem +CONFIG_DISPLAY=y diff --git a/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.overlay b/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.overlay new file mode 100644 index 00000000000..405b65ec8eb --- /dev/null +++ b/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.overlay @@ -0,0 +1,49 @@ +/ { + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,uart-mcumgr = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + }; +}; + +&zephyr_udc0 { + /delete-node/ board_cdc_acm_uart; +}; + + +&gd25q16 { + /delete-node/ partitions; +}; + +/delete-node/ &storage_partition; +/delete-node/ &code_partition; + +&flash0 { + partitions { + code_partition: partition@26000 { + compatible = "zephyr,mapped-partition"; + label = "Application"; + reg = <0x00026000 0x000c4000>; + }; + + storage_partition: partition@ea000 { + compatible = "zephyr,mapped-partition"; + label = "storage"; + reg = <0x000ea000 0x00008000>; + }; + + nvm_partition: partition@f2000 { + compatible = "zephyr,mapped-partition"; + label = "nvm"; + reg = <0x000f2000 0x00002000>; + }; + }; +}; + +&uart0 { + status = "okay"; +}; + +#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index 548070279c2..f9eaca45d8c 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -28,6 +28,7 @@ endmacro() cp_board_alias(pca10056 nrf52840dk/nrf52840) cp_board_alias(adafruit_feather_nrf52840_zephyr adafruit_feather_nrf52840/nrf52840/uf2) +cp_board_alias(adafruit_clue_nrf52840_zephyr adafruit_clue_nrf52840/nrf52840/uf2) cp_board_alias(adafruit_feather_nrf52840_sense_zephyr adafruit_feather_nrf52840/nrf52840/sense/uf2) cp_board_alias(adafruit_feather_rp2040_zephyr adafruit_feather_rp2040/rp2040) cp_board_alias(renesas_ek_ra6m5 ek_ra6m5) diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index ac2b1948eb7..44abea55416 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -305,6 +305,7 @@ bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { } mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { + #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) struct bt_hci_cp_vs_read_tx_power_level *cp; struct bt_hci_rp_vs_read_tx_power_level *rp; struct net_buf *buf, *rsp = NULL; @@ -326,9 +327,15 @@ mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { int8_t power = rp->tx_power_level; net_buf_unref(rsp); return power; + #else + // Controller doesn't support dynamic TX power control; return default. + (void)self; + return 0; + #endif } void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { + #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) struct bt_hci_cp_vs_write_tx_power_level *cp; struct net_buf *buf, *rsp = NULL; @@ -347,6 +354,11 @@ void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t t } net_buf_unref(rsp); + #else + // Controller doesn't support dynamic TX power control; silently ignore. + (void)self; + (void)tx_power; + #endif } bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index a9b5ecf6e1d..a39b837e978 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -99,6 +99,29 @@ "D12", "D13", ], + "adafruit-clue": [ + ["P0", "D0", "A2", "RX"], + ["P1", "D1", "A3", "TX"], + ["P2", "D2", "A4"], + ["P3", "D3", "A5"], + ["P4", "D4", "A6"], + ["P5", "D5", "BUTTON_A"], + ["P6", "D6"], + ["P7", "D7"], + ["P8", "D8"], + ["P9", "D9"], + ["P10", "D10", "A7"], + ["P11", "D11", "BUTTON_B"], + ["P12", "D12", "A0"], + ["P13", "D13", "SCK"], + ["P14", "D14", "MISO"], + ["P15", "D15", "MOSI"], + ["P16", "D16", "A1"], + ["P17", "D17", "L", "LED"], + ["P18", "D18", "NEOPIXEL"], + ["P19", "D19", "SCL"], + ["P20", "D20", "SDA"], + ], "nordic,expansion-board-header": [ "P1_04", "P1_05", diff --git a/ports/zephyr-cp/debug.conf b/ports/zephyr-cp/debug.conf index 625ef45198f..ab6ae95d416 100644 --- a/ports/zephyr-cp/debug.conf +++ b/ports/zephyr-cp/debug.conf @@ -28,6 +28,7 @@ CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096 CONFIG_MAIN_STACK_SIZE=32768 CONFIG_ISR_STACK_SIZE=4096 CONFIG_UDC_DWC2_STACK_SIZE=4096 +CONFIG_UDC_NRF_THREAD_STACK_SIZE=4096 CONFIG_USBD_THREAD_STACK_SIZE=4096 CONFIG_USBD_MSC_STACK_SIZE=4096 CONFIG_IDLE_STACK_SIZE=1024 diff --git a/ports/zephyr-cp/supervisor/usb.c b/ports/zephyr-cp/supervisor/usb.c index bb7f15f056a..6d3bf3286dd 100644 --- a/ports/zephyr-cp/supervisor/usb.c +++ b/ports/zephyr-cp/supervisor/usb.c @@ -20,6 +20,9 @@ #include #include #include +#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbd) +#include +#endif #include "shared-module/storage/__init__.h" #include "supervisor/filesystem.h" @@ -396,19 +399,49 @@ void usb_init(void) { printk("usbd_init\n"); err = usbd_init(&main_usbd); if (err) { - LOG_ERR("Failed to initialize device support"); + LOG_ERR("Failed to initialize device support (%d)", err); return; } printk("USB initialized\n"); if (!usbd_can_detect_vbus(&main_usbd)) { + /* No VBUS detection — just enable unconditionally. */ err = usbd_enable(&main_usbd); if (err) { - LOG_ERR("Failed to enable device support"); + LOG_ERR("Failed to enable device support (%d)", err); return; } - printk("usbd enabled\n"); + } else { + #if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbd) + /* + * On nRF52 USBD, the UDC driver enables VBUS detection interrupts + * inside usbd_init(). If USB is already plugged in, the VBUS_READY + * event arrives before usbd_init() sets status.initialized = true, + * causing a __ASSERT in usbd_thread (with CONFIG_ASSERT=y) that kills + * the event-processing thread. Our _msg_cb then never receives + * VBUS_READY, and USB never enumerates. + * + * Work around the race by checking the current VBUS state directly. + * udc_nrf_enable() does not require VBUS to be present, so it's safe + * to call usbd_enable() if VBUS is already up. + */ + nrfx_power_usb_state_t vbus = nrfx_power_usbstatus_get(); + if (vbus != NRFX_POWER_USB_STATE_DISCONNECTED) { + err = usbd_enable(&main_usbd); + if (err) { + LOG_ERR("Failed to enable device support (%d)", err); + return; + } + } + #else + /* + * On nRF54 USBHS, VBUS events arrive via NRFS IPC which has a natural + * startup delay, so the assert race doesn't occur. Additionally, + * udc_enable() blocks until VBUS is ready, so we must NOT call + * usbd_enable() here — let _msg_cb handle it on VBUS_READY. + */ + #endif } } diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index cff4be3993c..32394fe224c 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -8,6 +8,6 @@ manifest: path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: 3c402d80bd86628065f2a7d2af4a55a42556b08e + revision: 62e7a3764b652fff733cee43f23f82217403a51d clone-depth: 100 import: true From d8847b075783a912a1be1c0c116f667e7bb81965 Mon Sep 17 00:00:00 2001 From: Alec Delaney <89490472+tekktrik@users.noreply.github.com> Date: Tue, 18 Aug 2026 13:13:46 -0400 Subject: [PATCH 784/876] Update issue-labeled-ping to v3 --- .github/workflows/notify-on-issue-label.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/notify-on-issue-label.yml b/.github/workflows/notify-on-issue-label.yml index 2b229156811..2465851e35b 100644 --- a/.github/workflows/notify-on-issue-label.yml +++ b/.github/workflows/notify-on-issue-label.yml @@ -10,7 +10,7 @@ jobs: permissions: issues: write steps: - - uses: tekktrik/issue-labeled-ping@v2 + - uses: tekktrik/issue-labeled-ping@v3 with: github-token: ${{ secrets.GITHUB_TOKEN }} user: v923z From 8921d34efc9f6de433528c92920cbe7057207f49 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 18 Aug 2026 15:34:22 -0400 Subject: [PATCH 785/876] shared-bindings/traceback/__init__.c: check args more carefully; enhance doc --- locale/circuitpython.pot | 4 +++ shared-bindings/traceback/__init__.c | 50 ++++++++++++++++----------- tests/circuitpython/traceback_test.py | 16 +++++++++ 3 files changed, 49 insertions(+), 21 deletions(-) diff --git a/locale/circuitpython.pot b/locale/circuitpython.pot index 543a6ecdfa3..130bb695683 100644 --- a/locale/circuitpython.pot +++ b/locale/circuitpython.pot @@ -4189,6 +4189,10 @@ msgstr "" msgid "timestamp out of range for platform time_t" msgstr "" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" +msgstr "" + #: shared-bindings/traceback/__init__.c msgid "file write is not available" msgstr "" diff --git a/shared-bindings/traceback/__init__.c b/shared-bindings/traceback/__init__.c index ca1e6fe976a..651ec2c0142 100644 --- a/shared-bindings/traceback/__init__.c +++ b/shared-bindings/traceback/__init__.c @@ -36,10 +36,18 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t value = args[ARG_value].u_obj; + mp_obj_t tb_obj = args[ARG_tb].u_obj; + + // Both or neither of value and tb must be supplied. + if ((value != MP_OBJ_NULL && tb_obj == MP_OBJ_NULL) || + (value == MP_OBJ_NULL && tb_obj != MP_OBJ_NULL)) { + mp_raise_ValueError_varg(MP_ERROR_TEXT("Supply both or neither of %q and %q"), MP_QSTR_value, MP_QSTR_tb); + } + if (value == MP_OBJ_NULL) { value = args[ARG_exc].u_obj; } - mp_obj_t tb_obj = args[ARG_tb].u_obj; + mp_obj_t limit_obj = args[ARG_limit].u_obj; #if MICROPY_CPYTHON_EXCEPTION_CHAIN bool chain = args[ARG_chain].u_bool; @@ -105,21 +113,21 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin //| def format_exception( //| exc: BaseException | Type[BaseException], //| /, -//| value: Optional[BaseException] = None, +//| value: BaseException, //| tb: Optional[TracebackType] = None, //| limit: Optional[int] = None, //| chain: Optional[bool] = True, //| ) -> List[str]: //| """Format a stack trace and the exception information. //| -//| If the exception value is passed in ``exc``, then this exception value and its -//| associated traceback are used. This is compatible with CPython 3.10 and newer. +//| If the exception value is passed in ``exc``, and ``value`` and ``tb`` are not supplied, +//| then this exception value and its associated traceback are used. +//| This is compatible with CPython 3.10 and newer. //| -//| If the exception value is passed in ``value``, then any value passed in for -//| ``exc`` is ignored. ``value`` is used as the exception value and the -//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is None, -//| no traceback will be shown. This is compatible with CPython 3.5 and -//| newer. +//| If the exception value is passed in ``value``, then both ``value`` and ``tb`` must be supplied. +//| Any value passed in for ``exc`` is *ignored*. ``value`` is used as the exception value and the +//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is `None`, +//| no traceback will be shown. This is compatible with CPython 3.5 and newer. //| //| The arguments have the same meaning as the corresponding arguments //| to print_exception(). The return value is a list of strings, each @@ -128,8 +136,8 @@ static void traceback_exception_common(bool is_print_exception, mp_print_t *prin //| printed as does print_exception(). //| //| :param exc: The exception. Must be an instance of `BaseException`. Unused if value is specified. -//| :param value: If specified, is used in place of ``exc``. -//| :param TracebackType tb: When value is alsp specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed. +//| :param value: If specified, is used in place of ``exc``, and ``tb`` must also be specified. +//| :param tb: When ``value`` is also specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed. //| :param int limit: Print up to limit stack trace entries (starting from the caller’s frame) if limit is positive. //| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed. //| :param bool chain: If `True` then chained exceptions will be printed. @@ -150,7 +158,7 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(traceback_format_exception_obj, 0, traceback_f //| def print_exception( //| exc: BaseException | Type[BaseException], //| /, -//| value: Optional[BaseException] = None, +//| value: BaseException, //| tb: Optional[TracebackType] = None, //| limit: Optional[int] = None, //| file: Optional[io.FileIO] = None, @@ -158,18 +166,18 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(traceback_format_exception_obj, 0, traceback_f //| ) -> None: //| """Prints exception information and stack trace entries. //| -//| If the exception value is passed in ``exc``, then this exception value and its -//| associated traceback are used. This is compatible with CPython 3.10 and newer. +//| If the exception value is passed in ``exc``, and ``value`` and ``tb`` are not supplied, +//| then this exception value and its associated traceback are used. +//| This is compatible with CPython 3.10 and newer. //| -//| If the exception value is passed in ``value``, then any value passed in for -//| ``exc`` is ignored. ``value`` is used as the exception value and the -//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is None, -//| no traceback will be shown. This is compatible with CPython 3.5 and -//| newer. +//| If the exception value is passed in ``value``, then both ``value`` and ``tb`` must be supplied. +//| Any value passed in for ``exc`` is *ignored*. ``value`` is used as the exception value and the +//| traceback in the ``tb`` argument is used. In this case, if ``tb`` is `None`, +//| no traceback will be shown. This is compatible with CPython 3.5 and newer. //| //| :param exc: The exception. Must be an instance of `BaseException`. Unused if value is specified. -//| :param value: If specified, is used in place of ``exc``. -//| :param tb: When value is alsp specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed. +//| :param value: If specified, is used in place of ``exc``, and ``tb`` must also be specified. +//| :param tb: When ``value`` is also specified, ``tb`` is used in place of the exception's own traceback. If `None`, the traceback will not be printed. //| :param int limit: Print up to limit stack trace entries (starting from the caller’s frame) if limit is positive. //| Otherwise, print the last ``abs(limit)`` entries. If limit is omitted or None, all entries are printed. //| :param io.FileIO file: If file is omitted or `None`, the output goes to `sys.stderr`; otherwise it should be an open diff --git a/tests/circuitpython/traceback_test.py b/tests/circuitpython/traceback_test.py index 17c54c857a9..71888437a22 100644 --- a/tests/circuitpython/traceback_test.py +++ b/tests/circuitpython/traceback_test.py @@ -23,6 +23,22 @@ def fun(): print("\nLimit=-1 Trace:") print("".join(traceback.format_exception(None, exc, exc.__traceback__, limit=-1)), end="") +# value and tb must both be supplied or neither +print() +try: + fun() +except Exception as exc: + try: + traceback.print_exception(None, value=exc) + print("Should have raised ValueError for missing tb arg") + except ValueError: + print("ValueError for missing tb arg, as expected") + try: + traceback.print_exception(None, tb=None) + print("Should have raised ValueError for missing value arg") + except ValueError: + print("ValueError for missing value arg, as expected") + class NonNativeException(Exception): pass From 513b9b699dfe00e33bdfbf8fb27f3c02750f40cf Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 18 Aug 2026 12:46:55 -0700 Subject: [PATCH 786/876] Revert TX power changes They don't work on builds with separate controllers like the nRF5340. --- ports/zephyr-cp/common-hal/_bleio/Adapter.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index 44abea55416..ac2b1948eb7 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -305,7 +305,6 @@ bool common_hal_bleio_adapter_get_enabled(bleio_adapter_obj_t *self) { } mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { - #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) struct bt_hci_cp_vs_read_tx_power_level *cp; struct bt_hci_rp_vs_read_tx_power_level *rp; struct net_buf *buf, *rsp = NULL; @@ -327,15 +326,9 @@ mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { int8_t power = rp->tx_power_level; net_buf_unref(rsp); return power; - #else - // Controller doesn't support dynamic TX power control; return default. - (void)self; - return 0; - #endif } void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { - #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) struct bt_hci_cp_vs_write_tx_power_level *cp; struct net_buf *buf, *rsp = NULL; @@ -354,11 +347,6 @@ void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t t } net_buf_unref(rsp); - #else - // Controller doesn't support dynamic TX power control; silently ignore. - (void)self; - (void)tx_power; - #endif } bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { From 06cbba6b6fdc31ee3eb8a3d66a216a9daec845e9 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 18 Aug 2026 14:50:56 -0500 Subject: [PATCH 787/876] Create filter chain struct --- shared-module/audiodelays/Echo.c | 24 ++++++------- shared-module/audiodelays/Echo.h | 7 ++-- shared-module/audiofilters/Filter.c | 21 +++++------ shared-module/audiofilters/Filter.h | 7 ++-- shared-module/audiofilters/__init__.c | 48 +++++++++++++++----------- shared-module/audiofilters/__init__.h | 16 ++++++--- shared-module/audiofreeverb/Freeverb.c | 27 +++++++-------- shared-module/audiofreeverb/Freeverb.h | 13 ++----- 8 files changed, 78 insertions(+), 85 deletions(-) diff --git a/shared-module/audiodelays/Echo.c b/shared-module/audiodelays/Echo.c index cdf34541972..a57ed237c48 100644 --- a/shared-module/audiodelays/Echo.c +++ b/shared-module/audiodelays/Echo.c @@ -5,7 +5,6 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/audiodelays/Echo.h" #include "shared-bindings/audiocore/__init__.h" -#include "shared-module/audiofilters/__init__.h" #include #include "py/runtime.h" @@ -109,11 +108,10 @@ void common_hal_audiodelays_echo_construct(audiodelays_echo_obj_t *self, uint32_ void common_hal_audiodelays_echo_deinit(audiodelays_echo_obj_t *self) { audiosample_mark_deinit(&self->base); + audiofilters_deinit_filter_chain(&self->filter); self->echo_buffer = NULL; self->buffer[0] = NULL; self->buffer[1] = NULL; - self->filter = mp_const_none; - self->filter_states = NULL; } mp_obj_t common_hal_audiodelays_echo_get_delay_ms(audiodelays_echo_obj_t *self) { @@ -172,11 +170,11 @@ void common_hal_audiodelays_echo_set_decay(audiodelays_echo_obj_t *self, mp_obj_ } mp_obj_t common_hal_audiodelays_echo_get_filter(audiodelays_echo_obj_t *self) { - return self->filter; + return self->filter.obj; } void common_hal_audiodelays_echo_set_filter(audiodelays_echo_obj_t *self, mp_obj_t filter_in) { - audiofilters_assign_filters(filter_in, &self->filter, &self->filter_objs, &self->filter_objs_len, &self->filter_states, self->base.channel_count); + audiofilters_assign_filter_chain(&self->filter, filter_in, self->base.channel_count); } mp_obj_t common_hal_audiodelays_echo_get_mix(audiodelays_echo_obj_t *self) { @@ -211,7 +209,7 @@ void audiodelays_echo_reset_buffer(audiodelays_echo_obj_t *self, memset(self->buffer[1], 0, self->buffer_len); memset(self->echo_buffer, 0, self->max_echo_buffer_len); - audiofilters_reset_filters(self->filter_states, self->filter_objs_len, self->base.channel_count); + audiofilters_reset_filter_chain(&self->filter, self->base.channel_count); } bool common_hal_audiodelays_echo_get_playing(audiodelays_echo_obj_t *self) { @@ -305,7 +303,7 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * } // Tick biquad filters - audiofilters_tick_filters(self->filter_objs, self->filter_objs_len); + audiofilters_tick_filter_chain(&self->filter); uint32_t echo_buf_len = self->echo_buffer_len / sizeof(uint16_t); uint32_t max_echo_buf_len = (self->max_echo_buffer_len >> (self->base.channel_count - 1)) / sizeof(uint16_t); @@ -342,12 +340,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int16_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } else { echo = echo_buffer[echo_buffer_pos + echo_buffer_offset]; word = (int16_t)(echo * decay); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } word = (int16_t)(echo * MIN(mix, MICROPY_FLOAT_CONST(1.0))); @@ -427,11 +425,11 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * for (uint32_t j = echo_buffer_pos >> 8; j < next_buffer_pos >> 8; j++) { word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } else { word = synthio_mix_down_sample(word, SYNTHIO_MIX_DOWN_SCALE(2)); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int16_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } else { if (self->freq_shift) { @@ -439,12 +437,12 @@ audioio_get_buffer_result_t audiodelays_echo_get_buffer(audiodelays_echo_obj_t * word = (int32_t)(echo_buffer[(j % echo_buf_len) + echo_buffer_offset] * decay + sample_word); // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); + echo_buffer[(j % echo_buf_len) + echo_buffer_offset] = (int8_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } else { // Do not have mix_down for 8 bit so just hard cap samples into 1 byte word = MIN(MAX(word, -128), 127); - echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)audiofilters_process_filters(self->filter_objs, self->filter_objs_len, self->filter_states, self->base.channel_count, !!echo_buffer_offset, word); + echo_buffer[echo_buffer_pos++ + echo_buffer_offset] = (int8_t)audiofilters_process_filter_chain(&self->filter, self->base.channel_count, !!echo_buffer_offset, word); } } diff --git a/shared-module/audiodelays/Echo.h b/shared-module/audiodelays/Echo.h index 94c9ee4d2de..be01563b85a 100644 --- a/shared-module/audiodelays/Echo.h +++ b/shared-module/audiodelays/Echo.h @@ -8,6 +8,7 @@ #include "py/obj.h" #include "shared-module/audiocore/__init__.h" +#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/__init__.h" #include "shared-module/synthio/block.h" #include "shared-module/synthio/Biquad.h" @@ -21,13 +22,9 @@ typedef struct { mp_float_t current_delay_ms; mp_float_t sample_ms; synthio_block_slot_t decay; - mp_obj_t filter; + audiofilters_filter_chain_t filter; synthio_block_slot_t mix; - mp_obj_t *filter_objs; - size_t filter_objs_len; - biquad_filter_state *filter_states; - int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes diff --git a/shared-module/audiofilters/Filter.c b/shared-module/audiofilters/Filter.c index b98aa0aa887..a5351edecc4 100644 --- a/shared-module/audiofilters/Filter.c +++ b/shared-module/audiofilters/Filter.c @@ -5,7 +5,6 @@ // SPDX-License-Identifier: MIT #include "shared-bindings/audiofilters/Filter.h" #include "shared-bindings/audiocore/__init__.h" -#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/Biquad.h" #include @@ -60,19 +59,17 @@ void common_hal_audiofilters_filter_construct(audiofilters_filter_obj_t *self, void common_hal_audiofilters_filter_deinit(audiofilters_filter_obj_t *self) { audiosample_mark_deinit(&self->base); + audiofilters_deinit_filter_chain(&self->filter); self->buffer[0] = NULL; self->buffer[1] = NULL; - self->filter = mp_const_none; - self->filter_buffer = NULL; - self->filter_states = NULL; } void common_hal_audiofilters_filter_set_filter(audiofilters_filter_obj_t *self, mp_obj_t filter_in) { - audiofilters_assign_filters(filter_in, &self->filter, &self->filter_objs, &self->filter_objs_len, &self->filter_states, self->base.channel_count); + audiofilters_assign_filter_chain(&self->filter, filter_in, self->base.channel_count); } mp_obj_t common_hal_audiofilters_filter_get_filter(audiofilters_filter_obj_t *self) { - return self->filter; + return self->filter.obj; } mp_obj_t common_hal_audiofilters_filter_get_mix(audiofilters_filter_obj_t *self) { @@ -91,7 +88,7 @@ void audiofilters_filter_reset_buffer(audiofilters_filter_obj_t *self, memset(self->buffer[1], 0, self->buffer_len); memset(self->filter_buffer, 0, SYNTHIO_MAX_DUR * self->base.channel_count * sizeof(int32_t)); - audiofilters_reset_filters(self->filter_states, self->filter_objs_len, self->base.channel_count); + audiofilters_reset_filter_chain(&self->filter, self->base.channel_count); } bool common_hal_audiofilters_filter_get_playing(audiofilters_filter_obj_t *self) { @@ -169,7 +166,7 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o (void)synthio_block_slot_get(&self->mix); // Tick biquad filters - audiofilters_tick_filters(self->filter_objs, self->filter_objs_len); + audiofilters_tick_filter_chain(&self->filter); if (self->base.samples_signed) { memset(word_buffer, 0, length * (self->base.bits_per_sample / 8)); @@ -198,7 +195,7 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o shared_bindings_synthio_lfo_tick(self->base.sample_rate, n / self->base.channel_count); mp_float_t mix = synthio_block_slot_get_limited(&self->mix, MICROPY_FLOAT_CONST(0.0), MICROPY_FLOAT_CONST(1.0)); - if (mix <= MICROPY_FLOAT_CONST(0.01) || !self->filter_states) { // if mix is zero pure sample only or no biquad filter objects are provided + if (mix <= MICROPY_FLOAT_CONST(0.01) || !self->filter.states) { // if mix is zero pure sample only or no biquad filter objects are provided for (uint32_t i = 0; i < n; i++) { if (MP_LIKELY(self->base.bits_per_sample == 16)) { word_buffer[i] = sample_src[i]; @@ -228,11 +225,11 @@ audioio_get_buffer_result_t audiofilters_filter_get_buffer(audiofilters_filter_o } // Process biquad filters - for (uint8_t j = 0; j < self->filter_objs_len; j++) { - mp_obj_t filter_obj = self->filter_objs[j]; + for (uint8_t j = 0; j < self->filter.objs_len; j++) { + mp_obj_t filter_obj = self->filter.objs[j]; common_hal_synthio_biquad_tick(filter_obj); for (uint8_t k = 0; k < self->base.channel_count; k++) { - synthio_biquad_filter_samples(filter_obj, &self->filter_states[j * self->base.channel_count + k], self->filter_buffer + k * SYNTHIO_MAX_DUR, n_samples); + synthio_biquad_filter_samples(filter_obj, &self->filter.states[j * self->base.channel_count + k], self->filter_buffer + k * SYNTHIO_MAX_DUR, n_samples); } } diff --git a/shared-module/audiofilters/Filter.h b/shared-module/audiofilters/Filter.h index e24827e44a8..6cb352d4273 100644 --- a/shared-module/audiofilters/Filter.h +++ b/shared-module/audiofilters/Filter.h @@ -9,6 +9,7 @@ #include "shared-bindings/synthio/Biquad.h" #include "shared-module/audiocore/__init__.h" +#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/__init__.h" #include "shared-module/synthio/block.h" #include "shared-module/synthio/Biquad.h" @@ -17,13 +18,9 @@ extern const mp_obj_type_t audiofilters_filter_type; typedef struct { audiosample_base_t base; - mp_obj_t filter; + audiofilters_filter_chain_t filter; synthio_block_slot_t mix; - mp_obj_t *filter_objs; - size_t filter_objs_len; - biquad_filter_state *filter_states; - int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes diff --git a/shared-module/audiofilters/__init__.c b/shared-module/audiofilters/__init__.c index a663170de88..4b2ec0ed063 100644 --- a/shared-module/audiofilters/__init__.c +++ b/shared-module/audiofilters/__init__.c @@ -6,13 +6,13 @@ #include "shared-module/audiofilters/__init__.h" -void audiofilters_assign_filters(mp_obj_t filter_in, mp_obj_t *filter_out, mp_obj_t **filter_objs, size_t *filter_objs_len, biquad_filter_state **filter_states, uint8_t channel_count) { +void audiofilters_assign_filter_chain(audiofilters_filter_chain_t *self, mp_obj_t filter_in, uint8_t channel_count) { size_t n_items; mp_obj_t *items; if (filter_in == mp_const_none) { n_items = 0; - *filter_objs = NULL; + items = NULL; } else if (mp_obj_is_type(filter_in, &mp_type_tuple)) { mp_obj_tuple_get(filter_in, &n_items, &items); for (size_t i = 0; i < n_items; i++) { @@ -25,46 +25,52 @@ void audiofilters_assign_filters(mp_obj_t filter_in, mp_obj_t *filter_out, mp_ob mp_obj_get_type(items[i])->name); } } - *filter_objs = items; } else { n_items = 1; if (!mp_obj_is_type(filter_in, &synthio_biquad_type_obj)) { mp_raise_TypeError_varg( MP_ERROR_TEXT("%q must be of type %q or %q, not %q"), - MP_QSTR_filter, MP_QSTR_Biquad, MP_QSTR_iterable, mp_obj_get_type(filter_in)->name); + MP_QSTR_filter, MP_QSTR_Biquad, MP_QSTR_tuple, mp_obj_get_type(filter_in)->name); } - *filter_objs = filter_out; + items = &self->obj; } // everything has been checked, so we can do the following without fear - *filter_out = filter_in; - *filter_states = m_renew(biquad_filter_state, - *filter_states, - *filter_objs_len * channel_count, + self->obj = filter_in; + self->states = m_renew(biquad_filter_state, + self->states, + self->objs_len * channel_count, n_items * channel_count); - *filter_objs_len = n_items; + self->objs = items; + self->objs_len = n_items; } -void audiofilters_reset_filters(biquad_filter_state *filter_states, size_t filter_objs_len, uint8_t channel_count) { - if (filter_states) { - for (uint8_t i = 0; i < filter_objs_len * channel_count; i++) { - synthio_biquad_filter_reset(&filter_states[i]); +void audiofilters_reset_filter_chain(audiofilters_filter_chain_t *self, uint8_t channel_count) { + if (self->states) { + for (uint8_t i = 0; i < self->objs_len * channel_count; i++) { + synthio_biquad_filter_reset(&self->states[i]); } } } -void audiofilters_tick_filters(mp_obj_t *filter_objs, size_t filter_objs_len) { - for (uint8_t j = 0; j < filter_objs_len; j++) { - common_hal_synthio_biquad_tick(filter_objs[j]); +void audiofilters_tick_filter_chain(audiofilters_filter_chain_t *self) { + for (uint8_t j = 0; j < self->objs_len; j++) { + common_hal_synthio_biquad_tick(self->objs[j]); } } -int32_t audiofilters_process_filters(mp_obj_t *filter_objs, size_t filter_objs_len, biquad_filter_state *filter_states, uint8_t channel_count, uint8_t channel, int32_t word) { +int32_t audiofilters_process_filter_chain(audiofilters_filter_chain_t *self, uint8_t channel_count, uint8_t channel, int32_t word) { // Process biquad filters - for (uint8_t j = 0; j < filter_objs_len; j++) { - mp_obj_t filter_obj = filter_objs[j]; - word = synthio_biquad_filter_sample(filter_obj, &filter_states[j * channel_count + channel], word); + for (uint8_t j = 0; j < self->objs_len; j++) { + word = synthio_biquad_filter_sample(self->objs[j], &self->states[j * channel_count + channel], word); } return word; } + +void audiofilters_deinit_filter_chain(audiofilters_filter_chain_t *self) { + self->obj = mp_const_none; + self->objs = NULL; + self->objs_len = 0; + self->states = NULL; +} diff --git a/shared-module/audiofilters/__init__.h b/shared-module/audiofilters/__init__.h index 067d04ef209..2a5a933d96f 100644 --- a/shared-module/audiofilters/__init__.h +++ b/shared-module/audiofilters/__init__.h @@ -9,7 +9,15 @@ #include "py/obj.h" #include "shared-module/synthio/Biquad.h" -void audiofilters_assign_filters(mp_obj_t filter_in, mp_obj_t *filter_out, mp_obj_t **filter_objs, size_t *filter_objs_len, biquad_filter_state **filter_states, uint8_t channel_count); -void audiofilters_reset_filters(biquad_filter_state *filter_states, size_t filter_objs_len, uint8_t channel_count); -void audiofilters_tick_filters(mp_obj_t *filter_objs, size_t filter_objs_len); -int32_t audiofilters_process_filters(mp_obj_t *filter_objs, size_t filter_objs_len, biquad_filter_state *filter_states, uint8_t channel_count, uint8_t channel, int32_t word); +typedef struct audiofilters_filter_chain { + mp_obj_t obj; + mp_obj_t *objs; + size_t objs_len; + biquad_filter_state *states; +} audiofilters_filter_chain_t; + +void audiofilters_assign_filter_chain(audiofilters_filter_chain_t *filter_chain, mp_obj_t filter_in, uint8_t channel_count); +void audiofilters_reset_filter_chain(audiofilters_filter_chain_t *filter_chain, uint8_t channel_count); +void audiofilters_tick_filter_chain(audiofilters_filter_chain_t *filter_chain); +int32_t audiofilters_process_filter_chain(audiofilters_filter_chain_t *filter_chain, uint8_t channel_count, uint8_t channel, int32_t word); +void audiofilters_deinit_filter_chain(audiofilters_filter_chain_t *self); diff --git a/shared-module/audiofreeverb/Freeverb.c b/shared-module/audiofreeverb/Freeverb.c index 3d41eb0ab3f..85aefb6fc61 100644 --- a/shared-module/audiofreeverb/Freeverb.c +++ b/shared-module/audiofreeverb/Freeverb.c @@ -9,7 +9,6 @@ // #include "shared-bindings/audiofreeverb/Freeverb.h" #include "shared-bindings/audiocore/__init__.h" -#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/__init__.h" #include @@ -130,12 +129,10 @@ bool common_hal_audiofreeverb_freeverb_deinited(audiofreeverb_freeverb_obj_t *se void common_hal_audiofreeverb_freeverb_deinit(audiofreeverb_freeverb_obj_t *self) { audiosample_mark_deinit(&self->base); + audiofilters_deinit_filter_chain(&self->pre_filter); + audiofilters_deinit_filter_chain(&self->post_filter); self->buffer[0] = NULL; self->buffer[1] = NULL; - self->pre_filter = mp_const_none; - self->pre_filter_states = NULL; - self->post_filter = mp_const_none; - self->post_filter_states = NULL; } mp_obj_t common_hal_audiofreeverb_freeverb_get_roomsize(audiofreeverb_freeverb_obj_t *self) { @@ -176,19 +173,19 @@ void audiofreeverb_freeverb_get_damp_fixedpoint(mp_float_t n, int16_t *damp1, in } mp_obj_t common_hal_audiofreeverb_freeverb_get_pre_filter(audiofreeverb_freeverb_obj_t *self) { - return self->pre_filter; + return self->pre_filter.obj; } void common_hal_audiofreeverb_freeverb_set_pre_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t filter_in) { - audiofilters_assign_filters(filter_in, &self->pre_filter, &self->pre_filter_objs, &self->pre_filter_objs_len, &self->pre_filter_states, self->base.channel_count); + audiofilters_assign_filter_chain(&self->pre_filter, filter_in, self->base.channel_count); } mp_obj_t common_hal_audiofreeverb_freeverb_get_post_filter(audiofreeverb_freeverb_obj_t *self) { - return self->post_filter; + return self->post_filter.obj; } void common_hal_audiofreeverb_freeverb_set_post_filter(audiofreeverb_freeverb_obj_t *self, mp_obj_t filter_in) { - audiofilters_assign_filters(filter_in, &self->post_filter, &self->post_filter_objs, &self->post_filter_objs_len, &self->post_filter_states, self->base.channel_count); + audiofilters_assign_filter_chain(&self->post_filter, filter_in, self->base.channel_count); } mp_obj_t common_hal_audiofreeverb_freeverb_get_mix(audiofreeverb_freeverb_obj_t *self) { @@ -212,8 +209,8 @@ void audiofreeverb_freeverb_reset_buffer(audiofreeverb_freeverb_obj_t *self, memset(self->buffer[0], 0, self->buffer_len); memset(self->buffer[1], 0, self->buffer_len); - audiofilters_reset_filters(self->pre_filter_states, self->pre_filter_objs_len, self->base.channel_count); - audiofilters_reset_filters(self->post_filter_states, self->post_filter_objs_len, self->base.channel_count); + audiofilters_reset_filter_chain(&self->pre_filter, self->base.channel_count); + audiofilters_reset_filter_chain(&self->post_filter, self->base.channel_count); } bool common_hal_audiofreeverb_freeverb_get_playing(audiofreeverb_freeverb_obj_t *self) { @@ -302,8 +299,8 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free int16_t feedback = audiofreeverb_freeverb_get_roomsize_fixedpoint(roomsize); // Tick biquad filters - audiofilters_tick_filters(self->pre_filter_objs, self->pre_filter_objs_len); - audiofilters_tick_filters(self->post_filter_objs, self->post_filter_objs_len); + audiofilters_tick_filter_chain(&self->pre_filter); + audiofilters_tick_filter_chain(&self->post_filter); int16_t *sample_src = (int16_t *)self->sample_remaining_buffer; @@ -318,7 +315,7 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free uint32_t channel_comb_offset = 0, channel_allpass_offset = 0; // Apply filters as Pre-EQ - input = (int16_t)audiofilters_process_filters(self->pre_filter_objs, self->pre_filter_objs_len, self->pre_filter_states, self->base.channel_count, n % self->base.channel_count, sample_word); + input = (int16_t)audiofilters_process_filter_chain(&self->pre_filter, self->base.channel_count, n % self->base.channel_count, sample_word); input = synthio_sat16((int32_t)input * 8738, 17); // Initial input scaled down so we can add reverb sum = 0; @@ -347,7 +344,7 @@ audioio_get_buffer_result_t audiofreeverb_freeverb_get_buffer(audiofreeverb_free } // Apply filters as Post-EQ - output = (int16_t)audiofilters_process_filters(self->post_filter_objs, self->post_filter_objs_len, self->post_filter_states, self->base.channel_count, n % self->base.channel_count, (int32_t)output); + output = (int16_t)audiofilters_process_filter_chain(&self->post_filter, self->base.channel_count, n % self->base.channel_count, (int32_t)output); word = output * 30; // Add some volume back don't have to saturate as next step will diff --git a/shared-module/audiofreeverb/Freeverb.h b/shared-module/audiofreeverb/Freeverb.h index 79a11e3490e..1a60a64d39e 100644 --- a/shared-module/audiofreeverb/Freeverb.h +++ b/shared-module/audiofreeverb/Freeverb.h @@ -8,6 +8,7 @@ #include "py/obj.h" #include "shared-module/audiocore/__init__.h" +#include "shared-module/audiofilters/__init__.h" #include "shared-module/synthio/__init__.h" #include "shared-module/synthio/block.h" #include "shared-module/synthio/Biquad.h" @@ -18,18 +19,10 @@ typedef struct { audiosample_base_t base; synthio_block_slot_t roomsize; synthio_block_slot_t damp; - mp_obj_t pre_filter; - mp_obj_t post_filter; + audiofilters_filter_chain_t pre_filter; + audiofilters_filter_chain_t post_filter; synthio_block_slot_t mix; - mp_obj_t *pre_filter_objs; - size_t pre_filter_objs_len; - biquad_filter_state *pre_filter_states; - - mp_obj_t *post_filter_objs; - size_t post_filter_objs_len; - biquad_filter_state *post_filter_states; - int8_t *buffer[2]; uint8_t last_buf_idx; uint32_t buffer_len; // max buffer in bytes From ec5d640a1280c4b281497568180b091c68ade0e4 Mon Sep 17 00:00:00 2001 From: Cooper Dalrymple Date: Tue, 18 Aug 2026 15:35:09 -0500 Subject: [PATCH 788/876] Reset `MixerVoice` buffers rather than sample --- shared-bindings/audiomixer/MixerVoice.h | 1 + shared-module/audiomixer/Mixer.c | 2 +- shared-module/audiomixer/MixerVoice.c | 16 +++++++++++----- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/shared-bindings/audiomixer/MixerVoice.h b/shared-bindings/audiomixer/MixerVoice.h index d60820f7f57..89c87218e7c 100644 --- a/shared-bindings/audiomixer/MixerVoice.h +++ b/shared-bindings/audiomixer/MixerVoice.h @@ -14,6 +14,7 @@ extern const mp_obj_type_t audiomixer_mixervoice_type; void common_hal_audiomixer_mixervoice_construct(audiomixer_mixervoice_obj_t *self); void common_hal_audiomixer_mixervoice_set_parent(audiomixer_mixervoice_obj_t *self, audiomixer_mixer_obj_t *parent); void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp_obj_t sample, bool loop); +void common_hal_audiomixer_mixervoice_reset_buffer(audiomixer_mixervoice_obj_t *self); void common_hal_audiomixer_mixervoice_stop(audiomixer_mixervoice_obj_t *self); void common_hal_audiomixer_mixervoice_end(audiomixer_mixervoice_obj_t *self); mp_obj_t common_hal_audiomixer_mixervoice_get_level(audiomixer_mixervoice_obj_t *self); diff --git a/shared-module/audiomixer/Mixer.c b/shared-module/audiomixer/Mixer.c index 1177b6e0015..a6c4397e8bf 100644 --- a/shared-module/audiomixer/Mixer.c +++ b/shared-module/audiomixer/Mixer.c @@ -66,7 +66,7 @@ void audiomixer_mixer_reset_buffer(audiomixer_mixer_obj_t *self, bool single_channel_output, uint8_t channel) { for (uint8_t i = 0; i < self->voice_count; i++) { - common_hal_audiomixer_mixervoice_stop(self->voice[i]); + common_hal_audiomixer_mixervoice_reset_buffer(self->voice[i]); } } diff --git a/shared-module/audiomixer/MixerVoice.c b/shared-module/audiomixer/MixerVoice.c index 3a598516e7c..af015fc46f1 100644 --- a/shared-module/audiomixer/MixerVoice.c +++ b/shared-module/audiomixer/MixerVoice.c @@ -70,11 +70,17 @@ void common_hal_audiomixer_mixervoice_play(audiomixer_mixervoice_obj_t *self, mp self->sample = sample; self->loop = loop; - audiosample_reset_buffer(sample, false, 0); - audioio_get_buffer_result_t result = audiosample_get_buffer(sample, false, 0, (uint8_t **)&self->remaining_buffer, &self->buffer_length); - // Track length in terms of words. - self->buffer_length /= sizeof(uint32_t); - self->more_data = result == GET_BUFFER_MORE_DATA; + common_hal_audiomixer_mixervoice_reset_buffer(self); +} + +void common_hal_audiomixer_mixervoice_reset_buffer(audiomixer_mixervoice_obj_t *self) { + if (self->sample != NULL) { + audiosample_reset_buffer(self->sample, false, 0); + audioio_get_buffer_result_t result = audiosample_get_buffer(self->sample, false, 0, (uint8_t **)&self->remaining_buffer, &self->buffer_length); + // Track length in terms of words. + self->buffer_length /= sizeof(uint32_t); + self->more_data = result == GET_BUFFER_MORE_DATA; + } } bool common_hal_audiomixer_mixervoice_get_playing(audiomixer_mixervoice_obj_t *self) { From d2a38f58df88ea62c16e69a729ab3377f793cf9a Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 18 Aug 2026 19:12:54 -0700 Subject: [PATCH 789/876] socketpool: let ports raise gaierror with the real error code common_hal_socketpool_socketpool_raise_gaierror_noname() was the only way for a port to raise gaierror, so every getaddrinfo failure surfaced as EAI_NONAME no matter what actually went wrong. A lookup that failed because the resolver was unreachable looked identical to one for a name that does not exist. Add common_hal_socketpool_socketpool_raise_gaierror(int err), which puts the real code in args[0] where callers can act on it, and express the existing _noname() helper in terms of it. Existing callers are unchanged. No new translatable strings. EAI_NONAME keeps "Name or service not known"; anything else uses the existing generic "%q failure: %d" with getaddrinfo. zephyr-cp is the first user. Both of its resolver call sites had the real error in hand and discarded it: getaddrinfo() in SocketPool.c, and the host lookup behind socket.connect() in Socket.c. --- ports/zephyr-cp/common-hal/socketpool/Socket.c | 8 +++++++- .../common-hal/socketpool/SocketPool.c | 6 +++++- shared-bindings/socketpool/SocketPool.c | 18 +++++++++++++++--- shared-bindings/socketpool/SocketPool.h | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/ports/zephyr-cp/common-hal/socketpool/Socket.c b/ports/zephyr-cp/common-hal/socketpool/Socket.c index dd2c94b0147..bb626857a98 100644 --- a/ports/zephyr-cp/common-hal/socketpool/Socket.c +++ b/ports/zephyr-cp/common-hal/socketpool/Socket.c @@ -27,6 +27,7 @@ #include #include +#include #include #define SOCKETPOOL_IP_STR_LEN 48 @@ -82,7 +83,12 @@ static void socketpool_resolve_host_or_throw(int family, int type, const char *h int error = zsock_getaddrinfo(hostname, service_buf, &hints, &result_i); if (error != 0 || result_i == NULL) { - common_hal_socketpool_socketpool_raise_gaierror_noname(); + // Report what the resolver said. A null result with no error is the + // one case that really is "not found". + if (error == 0) { + error = DNS_EAI_NONAME; + } + common_hal_socketpool_socketpool_raise_gaierror(error); } memcpy(addr, result_i->ai_addr, sizeof(struct sockaddr_storage)); diff --git a/ports/zephyr-cp/common-hal/socketpool/SocketPool.c b/ports/zephyr-cp/common-hal/socketpool/SocketPool.c index c9a3f008321..2df1af69187 100644 --- a/ports/zephyr-cp/common-hal/socketpool/SocketPool.c +++ b/ports/zephyr-cp/common-hal/socketpool/SocketPool.c @@ -20,6 +20,7 @@ #include #include +#include void common_hal_socketpool_socketpool_construct(socketpool_socketpool_obj_t *self, mp_obj_t radio) { bool is_wifi = false; @@ -104,7 +105,10 @@ mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *se struct zsock_addrinfo *res = NULL; int err = socketpool_getaddrinfo_common(host, port, &hints, &res); if (err != 0 || res == NULL) { - common_hal_socketpool_socketpool_raise_gaierror_noname(); + if (err == 0) { + err = DNS_EAI_NONAME; + } + common_hal_socketpool_socketpool_raise_gaierror(err); } nlr_buf_t nlr; diff --git a/shared-bindings/socketpool/SocketPool.c b/shared-bindings/socketpool/SocketPool.c index 1fc9e2c3335..f50a7a5fcfe 100644 --- a/shared-bindings/socketpool/SocketPool.c +++ b/shared-bindings/socketpool/SocketPool.c @@ -190,15 +190,27 @@ MP_DEFINE_CONST_OBJ_TYPE( ); MP_WEAK MP_NORETURN -void common_hal_socketpool_socketpool_raise_gaierror_noname(void) { +void common_hal_socketpool_socketpool_raise_gaierror(int err) { vstr_t vstr; mp_print_t print; vstr_init_print(&vstr, 64, &print); - mp_printf(&print, "%S", MP_ERROR_TEXT("Name or service not known")); + // Only EAI_NONAME means the name was not found. Other codes cover + // unrelated failures, such as an unsupported family, so use the generic + // message for those rather than one that would be misleading. + if (err == SOCKETPOOL_EAI_NONAME) { + mp_printf(&print, "%S", MP_ERROR_TEXT("Name or service not known")); + } else { + mp_cprintf(&print, MP_ERROR_TEXT("%q failure: %d"), MP_QSTR_getaddrinfo, err); + } mp_obj_t exc_args[] = { - MP_OBJ_NEW_SMALL_INT(SOCKETPOOL_EAI_NONAME), + MP_OBJ_NEW_SMALL_INT(err), mp_obj_new_str_from_vstr(&vstr), }; nlr_raise(mp_obj_new_exception_args(&mp_type_gaierror, MP_ARRAY_SIZE(exc_args), exc_args)); } + +MP_WEAK MP_NORETURN +void common_hal_socketpool_socketpool_raise_gaierror_noname(void) { + common_hal_socketpool_socketpool_raise_gaierror(SOCKETPOOL_EAI_NONAME); +} diff --git a/shared-bindings/socketpool/SocketPool.h b/shared-bindings/socketpool/SocketPool.h index 60d58372b91..1d0a3bbccff 100644 --- a/shared-bindings/socketpool/SocketPool.h +++ b/shared-bindings/socketpool/SocketPool.h @@ -26,5 +26,6 @@ bool socketpool_socket(socketpool_socketpool_obj_t *self, int proto, socketpool_socket_obj_t *sock); MP_NORETURN void common_hal_socketpool_socketpool_raise_gaierror_noname(void); +MP_NORETURN void common_hal_socketpool_socketpool_raise_gaierror(int err); mp_obj_t common_hal_socketpool_getaddrinfo_raise(socketpool_socketpool_obj_t *self, const char *host, int port, int family, int type, int proto, int flags); From 774505985f7853a97b408c62f09939c2c927c379 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Wed, 19 Aug 2026 20:44:35 +0000 Subject: [PATCH 790/876] picogame: review fixes - stale header, displayio wording, duplicate stub The file header still said the types were consolidated here, which stopped being true when they moved into their own files, and the displayio paragraph now names the shared object instead of calling it "the seam". Splitting Sprite out also left `bitmap` documented twice - once in the attribute summary and again at its property - which mypy rejects, so `make check-stubs` (the docs job) failed. The summary entry is gone; the fuller description at the property stays. --- shared-bindings/picogame/Sprite.c | 2 -- shared-bindings/picogame/__init__.c | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/shared-bindings/picogame/Sprite.c b/shared-bindings/picogame/Sprite.c index 6893e8c0f04..99ac68e417b 100644 --- a/shared-bindings/picogame/Sprite.c +++ b/shared-bindings/picogame/Sprite.c @@ -125,8 +125,6 @@ static int32_t obj_to_fp(mp_obj_t o) { } //| -//| bitmap: Bitmap -//| """The Bitmap drawn (swap it at runtime to change the art; the frame index is kept).""" //| frame: int //| """Which frame of the bitmap's atlas to draw (0-based) - animation = stepping this.""" //| visible: bool diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c index 7cfa1dd741c..ebce4a70719 100644 --- a/shared-bindings/picogame/__init__.c +++ b/shared-bindings/picogame/__init__.c @@ -5,8 +5,6 @@ // SPDX-License-Identifier: MIT // // picogame: 2D game engine bindings for the PicoPad and similar boards. -// Type definitions are consolidated here so the module has a single -// shared-bindings/shared-module .c pair (CircuitPython build convention). #include "py/runtime.h" #include "shared-module/picogame/pg_compat.h" @@ -68,7 +66,7 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { //| microcontroller actually has, and the game decides when a frame happens //| (``scene.refresh()``). //| -//| The seam is the display object. A ``picogame.Scene`` takes the same +//| displayio and picogame share the Display object. A ``picogame.Scene`` takes the same //| :py:class:`~busdisplay.BusDisplay` displayio uses - it just talks to it //| directly instead of through the displayio refresh loop, so set //| ``display.auto_refresh = False`` (``picogame_game.setup()`` does this) and let From 560e142d6aa0b60a07ace666e41c440c7844af3a Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 20 Aug 2026 00:17:29 +0200 Subject: [PATCH 791/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 4 ++++ locale/el.po | 4 ++++ locale/hi.po | 4 ++++ locale/ko.po | 4 ++++ locale/ru.po | 4 ++++ locale/tr.po | 4 ++++ 6 files changed, 24 insertions(+) diff --git a/locale/cs.po b/locale/cs.po index b2bc2f7328e..a3432ce8d7f 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -4209,6 +4209,10 @@ msgstr "Soubor nenalezen" msgid "timestamp out of range for platform time_t" msgstr "" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" +msgstr "" + #: shared-bindings/traceback/__init__.c msgid "file write is not available" msgstr "zápis do souboru není dostupný" diff --git a/locale/el.po b/locale/el.po index 813abeafc43..6598505448c 100644 --- a/locale/el.po +++ b/locale/el.po @@ -4210,6 +4210,10 @@ msgstr "" msgid "timestamp out of range for platform time_t" msgstr "" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" +msgstr "" + #: shared-bindings/traceback/__init__.c msgid "file write is not available" msgstr "" diff --git a/locale/hi.po b/locale/hi.po index 2dbf6c69246..3eb187fcf8e 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -4191,6 +4191,10 @@ msgstr "" msgid "timestamp out of range for platform time_t" msgstr "" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" +msgstr "" + #: shared-bindings/traceback/__init__.c msgid "file write is not available" msgstr "" diff --git a/locale/ko.po b/locale/ko.po index bd5ed5f648c..0ff994e2e18 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -4251,6 +4251,10 @@ msgstr "파일을 찾을 수 없습니다" msgid "timestamp out of range for platform time_t" msgstr "" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" +msgstr "" + #: shared-bindings/traceback/__init__.c msgid "file write is not available" msgstr "" diff --git a/locale/ru.po b/locale/ru.po index a3d012bef95..9dac60be0b9 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -4267,6 +4267,10 @@ msgid "timestamp out of range for platform time_t" msgstr "" "Временная метка выходит за пределы допустимого диапазона для платформы time_t" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" +msgstr "" + #: shared-bindings/traceback/__init__.c msgid "file write is not available" msgstr "Запись файлов недоступна" diff --git a/locale/tr.po b/locale/tr.po index 55bee1fda23..0b4d0026e47 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -4213,6 +4213,10 @@ msgstr "" msgid "timestamp out of range for platform time_t" msgstr "" +#: shared-bindings/traceback/__init__.c +msgid "Supply both or neither of %q and %q" +msgstr "" + #: shared-bindings/traceback/__init__.c msgid "file write is not available" msgstr "" From d8fde3850aae11d7b5d249b568983866e2f7a816 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 20 Aug 2026 10:36:45 -0500 Subject: [PATCH 792/876] mp3decoder inbuf update fix --- shared-module/audiomp3/MP3Decoder.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c index dc22c0be245..baf8ea26554 100644 --- a/shared-module/audiomp3/MP3Decoder.c +++ b/shared-module/audiomp3/MP3Decoder.c @@ -109,6 +109,8 @@ static void stream_set_blocking(audiomp3_mp3file_obj_t *self, bool block_ok) { mp_call_method_n_kw(1, 0, self->settimeout_args); } +static bool mp3file_update_inbuf_always_impl(audiomp3_mp3file_obj_t *self, bool block_ok); + /** Fill the input buffer unconditionally. * * Returns true if the input buffer contains any useful data, @@ -120,6 +122,13 @@ static void stream_set_blocking(audiomp3_mp3file_obj_t *self, bool block_ok) { * Sets self->eof if any read of the file returns 0 bytes */ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block_ok) { + background_callback_prevent(); + bool result = mp3file_update_inbuf_always_impl(self, block_ok); + background_callback_allow(); + return result; +} + +static bool mp3file_update_inbuf_always_impl(audiomp3_mp3file_obj_t *self, bool block_ok) { if (self->eof || INPUT_BUFFER_SPACE(self->inbuf) == 0) { return INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; } @@ -135,7 +144,8 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block self->inbuf.read_off = 0; } - for (size_t to_read; !self->eof && (to_read = INPUT_BUFFER_SPACE(self->inbuf)) > 0;) { + for (size_t to_read; !self->eof && INPUT_BUFFER_SPACE(self->inbuf) > 0 && + (to_read = (size_t)INPUT_BUFFER_SPACE(self->inbuf)) > 0;) { uint8_t *write_ptr = self->inbuf.buf + self->inbuf.write_off; ssize_t n_read = stream_read(self->stream, write_ptr, to_read); From 64fc089445416851281c5940fbfaf87107ff2a79 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 20 Aug 2026 12:06:42 -0500 Subject: [PATCH 793/876] remove extra function layer --- shared-module/audiomp3/MP3Decoder.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c index baf8ea26554..58a4106dd1a 100644 --- a/shared-module/audiomp3/MP3Decoder.c +++ b/shared-module/audiomp3/MP3Decoder.c @@ -109,8 +109,6 @@ static void stream_set_blocking(audiomp3_mp3file_obj_t *self, bool block_ok) { mp_call_method_n_kw(1, 0, self->settimeout_args); } -static bool mp3file_update_inbuf_always_impl(audiomp3_mp3file_obj_t *self, bool block_ok); - /** Fill the input buffer unconditionally. * * Returns true if the input buffer contains any useful data, @@ -123,12 +121,7 @@ static bool mp3file_update_inbuf_always_impl(audiomp3_mp3file_obj_t *self, bool */ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block_ok) { background_callback_prevent(); - bool result = mp3file_update_inbuf_always_impl(self, block_ok); - background_callback_allow(); - return result; -} -static bool mp3file_update_inbuf_always_impl(audiomp3_mp3file_obj_t *self, bool block_ok) { if (self->eof || INPUT_BUFFER_SPACE(self->inbuf) == 0) { return INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; } @@ -170,7 +163,10 @@ static bool mp3file_update_inbuf_always_impl(audiomp3_mp3file_obj_t *self, bool } // Return true iff there are at least some useful bytes in the buffer - return INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; + bool result = INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; + + background_callback_allow(); + return result; } /** Update the inbuf from a background callback. From 8dd3a1b76de5c8498120b18ab9bf3a19927a47bc Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 19 Aug 2026 11:36:15 -0700 Subject: [PATCH 794/876] zephyr-cp: name gpio-keys from zephyr,code when there is no label zephyr_dts_to_cp_board() dereferenced props["label"] unconditionally for gpio-keys, but label is optional and deprecated there. Zephyr's current convention is zephyr,code, so any board whose keys omit label fails board generation with KeyError: 'label'. Guard the lookup the way the gpio-leds handler in the same function already does, and fall back to the name of the key's zephyr,code so the board still gets a usable name instead of none. The codes are read from Zephyr's own include/zephyr/dt-bindings/input/input-event-codes.h. Hit on a Silicon Labs SiWx917-DK2605A, whose gpio-keys come from Zephyr's board .dts with no label. Adafruit's MacroPad RP2040 is the same in Zephyr's tree, as are arduino/giga_r1, arduino/opta and arduino/nano_matter. --- ports/zephyr-cp/cptools/zephyr2cp.py | 38 +++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index a9b5ecf6e1d..ea6c961a50f 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -1,5 +1,6 @@ import logging import pathlib +import re import cpbuild import yaml @@ -451,6 +452,33 @@ def find_ram_regions(device_tree): return rams +# gpio-keys nodes identify a key with `zephyr,code` rather than the optional and +# deprecated `label`, so the code is the only name a modern board gives. +INPUT_KEY_NAMES = {} + + +def _populate_input_key_names(): + header = ( + pathlib.Path(__file__).parent.parent + / "zephyr" + / "include" + / "zephyr" + / "dt-bindings" + / "input" + / "input-event-codes.h" + ) + if not header.exists(): + return + pattern = re.compile(r"^#define\s+INPUT_(?PKEY_\w+)\s+(?P\d+)") + for line in header.read_text().splitlines(): + match = pattern.match(line) + if match: + INPUT_KEY_NAMES.setdefault(int(match.group("code")), match.group("name")) + + +_populate_input_key_names() + + @cpbuild.run_in_thread def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfigboard=None): # noqa: C901 board_dir = builddir / "board" @@ -677,7 +705,15 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig if (ioport, num) not in board_names: board_names[(ioport, num)] = [] - board_names[(ioport, num)].append(props["label"].to_string()) + # `label` is optional and deprecated on gpio-keys. Modern + # boards identify keys with `zephyr,code`, so fall back to the + # name of that code. + if "label" in props: + board_names[(ioport, num)].append(props["label"].to_string()) + elif "zephyr,code" in props: + key_code = props["zephyr,code"].to_num() + if key_code in INPUT_KEY_NAMES: + board_names[(ioport, num)].append(INPUT_KEY_NAMES[key_code]) if key in node2alias: if "sw0" in node2alias[key]: board_names[(ioport, num)].append("BUTTON") From 737c4d3073c0ed76731c26306cc3f672efc2780f Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 20 Aug 2026 12:30:03 -0700 Subject: [PATCH 795/876] zephyr-cp: read the vendor index from the vendor directory zephyr_dts_to_cp_board() took the board directory's parent as the vendor directory and read its index.rst for the vendor name. That holds for boards//, but some vendors group boards a level deeper. Silicon Labs uses boards/silabs/dev_kits/, explorer_kits, radio_boards and starter_kits, so the parent is a category and the vendor name comes out as "Dev Kits and Thunderboards" rather than "Silicon Labs". The name lands in autogen_board_info.toml, which docs/shared_bindings_matrix.py reads for the board's branded name, so the wrong value would be what the website shows. board_yaml["vendor"] is already read a line above, so walk up to the ancestor directory named for it. Flat layouts are unaffected: the first parent matches. --- ports/zephyr-cp/cptools/zephyr2cp.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index a39b837e978..89bcf7ce136 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -517,7 +517,15 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig else: board_yaml = board_yaml["board"] board_info["vendor_id"] = board_yaml["vendor"] - vendor_index = zephyr_board_dir.parent / "index.rst" + # Most vendors put boards directly in boards//, but some group + # them further, like boards/silabs/dev_kits/. Walk up to the directory + # named for the vendor so we read the vendor's index.rst and not a category's. + vendor_dir = zephyr_board_dir.parent + for parent in zephyr_board_dir.parents: + if parent.name == board_info["vendor_id"]: + vendor_dir = parent + break + vendor_index = vendor_dir / "index.rst" if vendor_index.exists(): vendor_index = vendor_index.read_text() vendor_index = vendor_index.split("\n") From 8babf99236589f0288c3dd6c3ebc3061fdc1018b Mon Sep 17 00:00:00 2001 From: foamyguy Date: Thu, 20 Aug 2026 15:07:54 -0500 Subject: [PATCH 796/876] re-allow background tasks on other exit paths --- shared-module/audiomp3/MP3Decoder.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/shared-module/audiomp3/MP3Decoder.c b/shared-module/audiomp3/MP3Decoder.c index 58a4106dd1a..6f0b5d4723f 100644 --- a/shared-module/audiomp3/MP3Decoder.c +++ b/shared-module/audiomp3/MP3Decoder.c @@ -120,10 +120,13 @@ static void stream_set_blocking(audiomp3_mp3file_obj_t *self, bool block_ok) { * Sets self->eof if any read of the file returns 0 bytes */ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block_ok) { + // Every return from this function must be preceded by background_callback_allow(); background_callback_prevent(); if (self->eof || INPUT_BUFFER_SPACE(self->inbuf) == 0) { - return INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; + bool result = INPUT_BUFFER_AVAILABLE(self->inbuf) > 0; + background_callback_allow(); + return result; } stream_set_blocking(self, block_ok); @@ -148,6 +151,7 @@ static bool mp3file_update_inbuf_always(audiomp3_mp3file_obj_t *self, bool block break; } self->eof = true; + background_callback_allow(); mp_raise_OSError(errcode); } From eeb7219b9e61d7beccd9983fc228a640f5f29034 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 20 Aug 2026 22:07:38 -0400 Subject: [PATCH 797/876] Fix BLE serial RX buffer size overstated fourfold `_incoming` is `uint32_t[64]`, so `sizeof(_incoming)` is already 256 bytes. Multiplying by `sizeof(uint32_t)` told the ring buffer it had 1024, letting it write past the array. Co-Authored-By: Claude Opus 5 (1M context) --- supervisor/shared/bluetooth/serial.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/supervisor/shared/bluetooth/serial.c b/supervisor/shared/bluetooth/serial.c index 86ff1738a2a..f35e640e516 100644 --- a/supervisor/shared/bluetooth/serial.c +++ b/supervisor/shared/bluetooth/serial.c @@ -133,7 +133,7 @@ void supervisor_start_bluetooth_serial(void) { _common_hal_bleio_characteristic_buffer_construct(&_rx_buffer, &supervisor_ble_circuitpython_rx_characteristic, 0.1f, - (uint8_t *)_incoming, sizeof(_incoming) * sizeof(uint32_t), + (uint8_t *)_incoming, sizeof(_incoming), &rx_static_handler_entry, true /* watch for interrupt character */); From cf805fa3b1a980a40c6493156bdec76677f8c168 Mon Sep 17 00:00:00 2001 From: bablokb Date: Fri, 21 Aug 2026 06:28:49 +0000 Subject: [PATCH 798/876] add support for SeeedStudio TRMNL 7.5" (OG) DIY-Kit driver board --- .../seeed_xiao_esp32_s3_trmnl_diy_kit/board.c | 9 ++++ .../mpconfigboard.h | 24 ++++++++++ .../mpconfigboard.mk | 32 +++++++++++++ .../seeed_xiao_esp32_s3_trmnl_diy_kit/pins.c | 47 +++++++++++++++++++ .../sdkconfig | 11 +++++ 5 files changed, 123 insertions(+) create mode 100644 ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/board.c create mode 100644 ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.h create mode 100644 ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.mk create mode 100644 ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/pins.c create mode 100644 ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/sdkconfig diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/board.c b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/board.c new file mode 100644 index 00000000000..fea7fe2c300 --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/board.c @@ -0,0 +1,9 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "mpconfigboard.h" + +// Use the MP_WEAK supervisor/shared/board.c versions of routines not defined here. diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.h b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.h new file mode 100644 index 00000000000..79deafd6125 --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.h @@ -0,0 +1,24 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2026 Bernhard Bablok +// +// SPDX-License-Identifier: MIT + +// Micropython setup + +#define MICROPY_HW_BOARD_NAME "Seeed Xiao ESP32-S3 Trmnl DIY Kit" +#define MICROPY_HW_MCU_NAME "ESP32S3" + +#define MICROPY_HW_LED_STATUS (&pin_GPIO21) + +// the unpopulated NFC-header also provides UART +#define CIRCUITPY_BOARD_UART (1) +#define CIRCUITPY_BOARD_UART_PIN {{.rx = &pin_GPIO41, .tx = &pin_GPIO42}} + +// SPI0 is used by the display connector +// SPI1 is used by a two secondary flash chips (one unpopulated) +#define CIRCUITPY_BOARD_SPI (2) +#define CIRCUITPY_BOARD_SPI_PIN \ + {{.clock = &pin_GPIO7, .mosi = &pin_GPIO9}, \ + {.clock = &pin_GPIO13, .mosi = &pin_GPIO11, .miso = &pin_GPIO12} \ + } diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.mk b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.mk new file mode 100644 index 00000000000..9a6b15aa76c --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/mpconfigboard.mk @@ -0,0 +1,32 @@ +USB_VID = 0x2886 +USB_PID = 0x0300 + +USB_PRODUCT = "Seeed Xiao ESP32-S3 Trmnl DIY Kit" +USB_MANUFACTURER = "Seeed Studio" + +IDF_TARGET = esp32s3 + +CIRCUITPY_ESP_FLASH_MODE = qio +CIRCUITPY_ESP_FLASH_SIZE = 16MB +CIRCUITPY_ESP_FLASH_FREQ = 80m + +CIRCUITPY_ESP_PSRAM_MODE = opi +CIRCUITPY_ESP_PSRAM_SIZE = 8MB +CIRCUITPY_ESP_PSRAM_FREQ = 80m + +CIRCUITPY_FREQUENCYIO = 0 +CIRCUITPY_RAINBOWIO = 0 +CIRCUITPY__EVE = 0 +CIRCUITPY_PS2IO = 0 +CIRCUITPY_CANIO = 0 +CIRCUITPY_MAX3421E = 0 +CIRCUITPY_ESPCAMERA = 0 +CIRCUITPY_PARALLELDISPLAYBUS = 0 +CIRCUITPY_COUNTIO = 0 +CIRCUITPY_NEOPIXEL_WRITE = 0 +CIRCUITPY_ROTARYIO = 0 + +CIRCUITPY_AUDIOCORE = 0 +CIRCUITPY_AUDIOBUSIO = 0 +CIRCUITPY_AUDIOBUSIO_PDMIN = 0 +CIRCUITPY_AUDIOI2SIN = 0 diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/pins.c b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/pins.c new file mode 100644 index 00000000000..422f16b787b --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/pins.c @@ -0,0 +1,47 @@ +// This file is part of the CircuitPython project: https://circuitpython.org +// +// SPDX-FileCopyrightText: Copyright (c) 2020 Scott Shawcroft for Adafruit Industries +// +// SPDX-License-Identifier: MIT + +#include "shared-bindings/board/__init__.h" + +static const mp_rom_map_elem_t board_module_globals_table[] = { + CIRCUITPYTHON_BOARD_DICT_STANDARD_ITEMS + + { MP_ROM_QSTR(MP_QSTR_BAT_ADC), MP_ROM_PTR(&pin_GPIO1) }, + { MP_ROM_QSTR(MP_QSTR_BTN1), MP_ROM_PTR(&pin_GPIO2) }, + { MP_ROM_QSTR(MP_QSTR_BTN2), MP_ROM_PTR(&pin_GPIO3) }, + { MP_ROM_QSTR(MP_QSTR_EDP_BUSY), MP_ROM_PTR(&pin_GPIO4) }, + { MP_ROM_QSTR(MP_QSTR_BTN3), MP_ROM_PTR(&pin_GPIO5) }, + { MP_ROM_QSTR(MP_QSTR_ADC_EN), MP_ROM_PTR(&pin_GPIO6) }, + { MP_ROM_QSTR(MP_QSTR_SPI0_CLK), MP_ROM_PTR(&pin_GPIO7) }, + { MP_ROM_QSTR(MP_QSTR_SPI0_MOSI), MP_ROM_PTR(&pin_GPIO9) }, + { MP_ROM_QSTR(MP_QSTR_EDP_DC), MP_ROM_PTR(&pin_GPIO10) }, + + // connected to two additional flash chips (one unpopulated) + { MP_ROM_QSTR(MP_QSTR_SPI1_MOSI), MP_ROM_PTR(&pin_GPIO11) }, + { MP_ROM_QSTR(MP_QSTR_SPI1_MISO), MP_ROM_PTR(&pin_GPIO12) }, + { MP_ROM_QSTR(MP_QSTR_SPI1_CLK), MP_ROM_PTR(&pin_GPIO13) }, + + { MP_ROM_QSTR(MP_QSTR_LED), MP_ROM_PTR(&pin_GPIO21) }, + + { MP_ROM_QSTR(MP_QSTR_EDP_RES), MP_ROM_PTR(&pin_GPIO38) }, + + // connected to two additional flash chips (CS0 unpopulated) + { MP_ROM_QSTR(MP_QSTR_SPI1_CS0), MP_ROM_PTR(&pin_GPIO39) }, + { MP_ROM_QSTR(MP_QSTR_SPI1_CS1), MP_ROM_PTR(&pin_GPIO40) }, + + { MP_ROM_QSTR(MP_QSTR_D14), MP_ROM_PTR(&pin_GPIO41) }, + { MP_ROM_QSTR(MP_QSTR_RX), MP_ROM_PTR(&pin_GPIO41) }, + + { MP_ROM_QSTR(MP_QSTR_D15), MP_ROM_PTR(&pin_GPIO42) }, + { MP_ROM_QSTR(MP_QSTR_TX), MP_ROM_PTR(&pin_GPIO42) }, + + { MP_ROM_QSTR(MP_QSTR_PWR_EN), MP_ROM_PTR(&pin_GPIO43) }, + { MP_ROM_QSTR(MP_QSTR_SPI0_CS), MP_ROM_PTR(&pin_GPIO44) }, + + { MP_ROM_QSTR(MP_QSTR_SPI), MP_ROM_PTR(&board_spi_obj) }, + { MP_ROM_QSTR(MP_QSTR_UART), MP_ROM_PTR(&board_uart_obj) }, +}; +MP_DEFINE_CONST_DICT(board_module_globals, board_module_globals_table); diff --git a/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/sdkconfig b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/sdkconfig new file mode 100644 index 00000000000..ce6696bf50f --- /dev/null +++ b/ports/espressif/boards/seeed_xiao_esp32_s3_trmnl_diy_kit/sdkconfig @@ -0,0 +1,11 @@ +# +# Espressif IoT Development Framework Configuration +# +# +# Component config +# +# +# +# end of Component config + +# end of Espressif IoT Development Framework Configuration From 29d65a2c443208e8ba843f7a89e514acd88f31f7 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2026 16:22:10 -0400 Subject: [PATCH 799/876] Fix zero-iteration disconnect wait in bleio_adapter_reset() any_connected was initialized to false, so the wait loop never ran and the stack was torn down before the disconnect went out. The central then saw a supervision timeout instead of a clean disconnect. Same copied bug in nordic, espressif, and silabs. Co-Authored-By: Claude Fable 5 --- ports/espressif/common-hal/_bleio/Adapter.c | 6 +++--- ports/nordic/common-hal/_bleio/Adapter.c | 6 +++--- ports/silabs/common-hal/_bleio/Adapter.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index 4feb6b2b96b..61abdb219be 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -837,13 +837,13 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { // Wait up to 125 ms (128 ticks) for disconnect to complete. This should be // greater than most connection intervals. - bool any_connected = false; + bool any_connected; uint64_t start_ticks = supervisor_ticks_ms64(); - while (any_connected && supervisor_ticks_ms64() - start_ticks < 128) { + do { any_connected = false; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; any_connected |= connection->conn_handle != BLEIO_HANDLE_INVALID; } - } + } while (any_connected && supervisor_ticks_ms64() - start_ticks < 128); } diff --git a/ports/nordic/common-hal/_bleio/Adapter.c b/ports/nordic/common-hal/_bleio/Adapter.c index 2ca9df89710..a8d6b5e645b 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.c +++ b/ports/nordic/common-hal/_bleio/Adapter.c @@ -998,13 +998,13 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { // Wait up to 125 ms (128 ticks) for disconnect to complete. This should be // greater than most connection intervals. - bool any_connected = false; + bool any_connected; uint64_t start_ticks = supervisor_ticks_ms64(); - while (any_connected && supervisor_ticks_ms64() - start_ticks < 128) { + do { any_connected = false; for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; any_connected |= connection->conn_handle != BLE_CONN_HANDLE_INVALID; } - } + } while (any_connected && supervisor_ticks_ms64() - start_ticks < 128); } diff --git a/ports/silabs/common-hal/_bleio/Adapter.c b/ports/silabs/common-hal/_bleio/Adapter.c index 14b1dac8207..f29e9d54b15 100644 --- a/ports/silabs/common-hal/_bleio/Adapter.c +++ b/ports/silabs/common-hal/_bleio/Adapter.c @@ -640,11 +640,11 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { // Wait up to 125 ms (128 ticks) for disconnect to complete. This should be // greater than most connection intervals. start_ticks = supervisor_ticks_ms64(); - while (any_connected && supervisor_ticks_ms64() - start_ticks < 128) { + do { any_connected = false; for (conn_index = 0; conn_index < BLEIO_TOTAL_CONNECTION_COUNT; conn_index++) { connection = &bleio_connections[conn_index]; any_connected |= connection->conn_handle != BLEIO_HANDLE_INVALID; } - } + } while (any_connected && supervisor_ticks_ms64() - start_ticks < 128); } From edff1a63ff5619402fe9f440691d335762745562 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 21 Aug 2026 07:38:20 -0700 Subject: [PATCH 800/876] zephyr-cp/wifi: subscribe to NET_EVENT_WIFI_SCAN_RESULT The event handler has a NET_EVENT_WIFI_SCAN_RESULT case that queues each AP as it arrives, but that event was never in the subscription mask, so the case never ran and scans always returned zero networks. RAW_SCAN_RESULT is in the mask but is not a substitute. It carries raw beacon frames and only fires when CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS is enabled, which it is not by default. Measured on a Raspberry Pi Pico 2 W running raspberrypi_rpi_pico2_w_zephyr, built from 069144c66 and flashed over SWD with pyOCD: len([1 for n in wifi.radio.start_scanning_networks()]) before 0 after 204 Same board, same probe, same script, with only this change reverted for the before run. --- ports/zephyr-cp/common-hal/wifi/__init__.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 4b967bc2780..81ebdfdc955 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -278,6 +278,7 @@ void common_hal_wifi_init(bool user_initiated) { // self->ap_mode = 0; net_mgmt_init_event_callback(&wifi_cb, _event_handler, + NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE | NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT | From 411df07e46d31f3aef7457034973e1486bdadcbc Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2026 16:22:37 -0400 Subject: [PATCH 801/876] Fix heap handler removal stopping after the first removal ble_drv_remove_event_handler() clears the removed entry's next pointer, so iterating via it->next after removal ended the walk at the first heap handler, leaving the rest pointing into a heap about to be freed. Capture next first. Also remove entries that themselves live on the heap, not just those with a heap param. Same copied bug in nordic ble_drv.c and espressif ble_events.c. Co-Authored-By: Claude Fable 5 --- ports/espressif/common-hal/_bleio/ble_events.c | 9 ++++++--- ports/nordic/bluetooth/ble_drv.c | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/ble_events.c b/ports/espressif/common-hal/_bleio/ble_events.c index b57362fe007..d2474d1e00f 100644 --- a/ports/espressif/common-hal/_bleio/ble_events.c +++ b/ports/espressif/common-hal/_bleio/ble_events.c @@ -28,11 +28,14 @@ void ble_event_reset(void) { void ble_event_remove_heap_handlers(void) { ble_event_handler_entry_t *it = MP_STATE_VM(ble_event_handler_entries); while (it != NULL) { - // If the param is on the heap, then delete the handler. - if (gc_ptr_on_heap(it->param)) { + // Save it->next before removing, because removing clears it. + ble_event_handler_entry_t *next = it->next; + // Remove the handler if the entry or its param is on the heap, which is + // about to go away. + if (gc_ptr_on_heap(it) || gc_ptr_on_heap(it->param)) { ble_event_remove_handler(it->func, it->param); } - it = it->next; + it = next; } } diff --git a/ports/nordic/bluetooth/ble_drv.c b/ports/nordic/bluetooth/ble_drv.c index 7085aa477b5..c2122c8845e 100644 --- a/ports/nordic/bluetooth/ble_drv.c +++ b/ports/nordic/bluetooth/ble_drv.c @@ -141,11 +141,14 @@ void ble_drv_reset(void) { void ble_drv_remove_heap_handlers(void) { ble_drv_evt_handler_entry_t *it = MP_STATE_VM(ble_drv_evt_handler_entries); while (it != NULL) { - // If the param is on the heap, then delete the handler. - if (gc_ptr_on_heap(it->param)) { + // Save it->next before removing, because removing clears it. + ble_drv_evt_handler_entry_t *next = it->next; + // Remove the handler if the entry or its param is on the heap, which is + // about to go away. + if (gc_ptr_on_heap(it) || gc_ptr_on_heap(it->param)) { ble_drv_remove_event_handler(it->func, it->param); } - it = it->next; + it = next; } } From 4b2f077623ea80523c2333002937a2db037a3dfb Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2026 16:23:15 -0400 Subject: [PATCH 802/876] Fix common_hal_bleio_packet_buffer_deinited() never returning true common_hal_bleio_packet_buffer_deinit() left self->characteristic set, so deinited() -- which tests it against NULL -- never reported the buffer as deinited, and guards like the ones in supervisor/shared/bluetooth/serial.c never took effect. Same copied bug in nordic, silabs, and ble_hci. Co-Authored-By: Claude Fable 5 --- devices/ble_hci/common-hal/_bleio/PacketBuffer.c | 2 ++ ports/nordic/common-hal/_bleio/PacketBuffer.c | 2 ++ ports/silabs/common-hal/_bleio/PacketBuffer.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c index 771a1509f39..f29f4dd88a7 100644 --- a/devices/ble_hci/common-hal/_bleio/PacketBuffer.c +++ b/devices/ble_hci/common-hal/_bleio/PacketBuffer.c @@ -245,6 +245,8 @@ void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (!common_hal_bleio_packet_buffer_deinited(self)) { bleio_characteristic_clear_observer(self->characteristic); ringbuf_deinit(&self->ringbuf); + // Mark as deinited, so common_hal_bleio_packet_buffer_deinited() reports it. + self->characteristic = NULL; } } diff --git a/ports/nordic/common-hal/_bleio/PacketBuffer.c b/ports/nordic/common-hal/_bleio/PacketBuffer.c index 6b3e86e3b7a..2d6f5a9e948 100644 --- a/ports/nordic/common-hal/_bleio/PacketBuffer.c +++ b/ports/nordic/common-hal/_bleio/PacketBuffer.c @@ -483,6 +483,8 @@ void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (!common_hal_bleio_packet_buffer_deinited(self)) { ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); ringbuf_deinit(&self->ringbuf); + // Mark as deinited, so common_hal_bleio_packet_buffer_deinited() reports it. + self->characteristic = NULL; } } diff --git a/ports/silabs/common-hal/_bleio/PacketBuffer.c b/ports/silabs/common-hal/_bleio/PacketBuffer.c index 881cf1622eb..291523e0a6d 100644 --- a/ports/silabs/common-hal/_bleio/PacketBuffer.c +++ b/ports/silabs/common-hal/_bleio/PacketBuffer.c @@ -387,6 +387,8 @@ bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (!common_hal_bleio_packet_buffer_deinited(self)) { ringbuf_deinit(&self->ringbuf); + // Mark as deinited, so common_hal_bleio_packet_buffer_deinited() reports it. + self->characteristic = NULL; } } From 17680833b7716e8f177176deaea11a0530f8e888 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2026 16:23:40 -0400 Subject: [PATCH 803/876] Fix nordic packet_buffer_deinit() removing the wrong event handler Registration chooses packet_buffer_on_ble_client_evt or packet_buffer_on_ble_server_evt by self->client, but deinit always removed the client handler, leaving a server packet buffer's handler registered and pointing at a freed buffer. Co-Authored-By: Claude Fable 5 --- ports/nordic/common-hal/_bleio/PacketBuffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ports/nordic/common-hal/_bleio/PacketBuffer.c b/ports/nordic/common-hal/_bleio/PacketBuffer.c index 2d6f5a9e948..5be9896b706 100644 --- a/ports/nordic/common-hal/_bleio/PacketBuffer.c +++ b/ports/nordic/common-hal/_bleio/PacketBuffer.c @@ -481,7 +481,11 @@ bool common_hal_bleio_packet_buffer_deinited(bleio_packet_buffer_obj_t *self) { void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { if (!common_hal_bleio_packet_buffer_deinited(self)) { - ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); + if (self->client) { + ble_drv_remove_event_handler(packet_buffer_on_ble_client_evt, self); + } else { + ble_drv_remove_event_handler(packet_buffer_on_ble_server_evt, self); + } ringbuf_deinit(&self->ringbuf); // Mark as deinited, so common_hal_bleio_packet_buffer_deinited() reports it. self->characteristic = NULL; From a234a6570927e68d4a683e39f5035411509067d9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2026 16:24:28 -0400 Subject: [PATCH 804/876] Fix resolvable private address rotating every second For unlimited advertising (timeout 0), private_addr_cycle_s = timeout + 1 rotated the address every second -- too fast for a central to resolve an address and connect to it before it changed. Use 0, which selects the SoftDevice default cycle of 15 minutes. Co-Authored-By: Claude Fable 5 --- ports/nordic/common-hal/_bleio/Adapter.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ports/nordic/common-hal/_bleio/Adapter.c b/ports/nordic/common-hal/_bleio/Adapter.c index a8d6b5e645b..129ad01d068 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.c +++ b/ports/nordic/common-hal/_bleio/Adapter.c @@ -794,7 +794,13 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, // advertising. This prevents a potential race condition where we // fire off a beacon with the same advertising data but a new MAC // address just as we tear down the connection. - .private_addr_cycle_s = timeout + 1, + // + // For unlimited advertising, timeout + 1 would rotate the address + // every second, too fast for a central to resolve it and connect. + // Zero selects the SoftDevice default cycle of 15 minutes + // (BLE_GAP_DEFAULT_PRIVATE_ADDR_CYCLE_INTERVAL_S). + .private_addr_cycle_s = + timeout == BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED ? 0 : timeout + 1, .p_device_irk = NULL, }; err_code = sd_ble_gap_privacy_set(&privacy); From d85810534b6e1eeb994fecb3e65b66366f353dc9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Fri, 21 Aug 2026 16:24:59 -0400 Subject: [PATCH 805/876] Clear stale bond state when a connection slot is reused On BLE_GAP_EVT_CONNECTED, a recycled slot kept the previous peer's bonding keys, ediv, and pending bond-save flags. The SoftDevice fills in only the keys the new peer distributes, so the leftovers could mix one peer's IRK with another's LTK in a stored bond, or save this connection's bond data under the previous peer's ediv. Co-Authored-By: Claude Fable 5 --- ports/nordic/common-hal/_bleio/Adapter.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ports/nordic/common-hal/_bleio/Adapter.c b/ports/nordic/common-hal/_bleio/Adapter.c index 129ad01d068..05edd832a8b 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.c +++ b/ports/nordic/common-hal/_bleio/Adapter.c @@ -248,6 +248,15 @@ static bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { connection->connection_obj = mp_const_none; connection->pair_status = PAIR_NOT_PAIRED; connection->mtu = 0; + // Clear leftover bond state; connection slots are recycled. The + // SoftDevice fills in only the keys the new peer distributes, so a + // stale keyset could mix the previous peer's keys into this peer's + // stored bond, and a stale ediv or pending-save flag could file + // this connection's bond data under the previous peer's key. + connection->ediv = EDIV_INVALID; + connection->do_bond_cccds = false; + connection->do_bond_keys = false; + bonding_clear_keys(&connection->bonding_keys); ble_drv_add_event_handler_entry(&connection->handler_entry, connection_on_ble_evt, connection); self->connection_objs = NULL; From 422467ea45669a1a717216f957664188ff3abb22 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 21 Aug 2026 14:41:16 -0700 Subject: [PATCH 806/876] zephyr-cp: add the Silicon Labs SiWx917-DK2605A The SiWx917 SoC pairs a Cortex-M4 application core with a separate network processor that owns the Wi-Fi and BLE radios. Firmware is loaded as an .rps container rather than a hex image, so the port's release-artifact rule gains a firmware.rps target and the board declares CIRCUITPY_BUILD_EXTENSIONS = ["rps"]. --- ports/zephyr-cp/Makefile | 3 + ports/zephyr-cp/boards/board_aliases.cmake | 1 + .../siwx917_dk2605a/autogen_board_info.toml | 129 ++++++++++++++++++ .../silabs/siwx917_dk2605a/circuitpython.toml | 1 + ports/zephyr-cp/boards/siwx917_dk2605a.conf | 93 +++++++++++++ .../zephyr-cp/boards/siwx917_dk2605a.overlay | 69 ++++++++++ 6 files changed, 296 insertions(+) create mode 100644 ports/zephyr-cp/boards/silabs/siwx917_dk2605a/autogen_board_info.toml create mode 100644 ports/zephyr-cp/boards/silabs/siwx917_dk2605a/circuitpython.toml create mode 100644 ports/zephyr-cp/boards/siwx917_dk2605a.conf create mode 100644 ports/zephyr-cp/boards/siwx917_dk2605a.overlay diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index ab730a8b339..a587892ed28 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -42,6 +42,9 @@ $(BUILD)/firmware.exe: $(BUILD)/zephyr-cp/zephyr/zephyr.elf $(BUILD)/firmware.uf2: $(BUILD)/zephyr-cp/zephyr/zephyr.elf cp $(BUILD)/zephyr-cp/zephyr/zephyr.uf2 $@ +$(BUILD)/firmware.rps: $(BUILD)/zephyr-cp/zephyr/zephyr.elf + cp $(BUILD)/zephyr-cp/zephyr/zephyr.rps $@ + flash: $(BUILD)/zephyr-cp/zephyr/zephyr.elf west flash -d $(BUILD) diff --git a/ports/zephyr-cp/boards/board_aliases.cmake b/ports/zephyr-cp/boards/board_aliases.cmake index f9eaca45d8c..29ce83ceb5e 100644 --- a/ports/zephyr-cp/boards/board_aliases.cmake +++ b/ports/zephyr-cp/boards/board_aliases.cmake @@ -55,3 +55,4 @@ cp_board_alias(raspberrypi_rpi_pico_w_zephyr rpi_pico/rp2040/w) cp_board_alias(raspberrypi_rpi_pico2_zephyr rpi_pico2/rp2350a/m33) cp_board_alias(raspberrypi_rpi_pico2_w_zephyr rpi_pico2/rp2350a/m33/w) cp_board_alias(st_nucleo_n657x0_q nucleo_n657x0_q/stm32n657xx) +cp_board_alias(silabs_siwx917_dk2605a siwx917_dk2605a) diff --git a/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/autogen_board_info.toml b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/autogen_board_info.toml new file mode 100644 index 00000000000..67701ccc2f6 --- /dev/null +++ b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/autogen_board_info.toml @@ -0,0 +1,129 @@ +# This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. +name = "Silicon Labs SiWx917 Wi-Fi 6 and Bluetooth LE SoC Dev Kit (BRD2605A)" + +[modules] +__future__ = true +_bleio = true # Zephyr board has _bleio +_eve = false +_pew = false +_pixelmap = false +_stage = false +adafruit_bus_device = true +adafruit_pixelbuf = false +aesio = true +alarm = false +analogbufio = false +analogio = false +atexit = false +audiobusio = false +audiocore = false +audiodelays = false +audiofilewriter = false +audiofilters = false +audiofreeverb = false +audioi2sin = false +audioio = false +audiomixer = false +audiomp3 = false +audiopwmio = false +audiospeed = false +aurora_epaper = false +bitbangio = false +bitmapfilter = true # Zephyr board has busio +bitmaptools = true # Zephyr board has busio +bitops = false +board = false +busdisplay = true # Zephyr board has busio +busio = true # Zephyr board has busio +camera = false +canio = false +codeop = false +countio = false +digitalio = true +displayio = true # Zephyr board has busio +dotclockframebuffer = false +dualbank = false +epaperdisplay = true # Zephyr board has busio +floppyio = false +fontio = true # Zephyr board has busio +fourwire = true # Zephyr board has busio +framebufferio = true # Zephyr board has busio +frequencyio = false +getpass = true +gifio = true # Zephyr board has busio +gnss = false +hashlib = true # Zephyr networking enabled +hostnetwork = false +i2cdisplaybus = true # Zephyr board has busio +i2cioexpander = false +i2ctarget = false +imagecapture = false +ipaddress = true # Zephyr networking enabled +is31fl3741 = false +jpegio = true # Zephyr board has busio +keypad = false +keypad_demux = false +locale = false +lvfontio = true # Zephyr board has busio +math = true +max3421e = false +mcp4822 = false +mdns = false +memorymap = false +memorymonitor = false +microcontroller = true +mipidsi = false +msgpack = true +neopixel_write = false +nvm = false +onewireio = false +os = true +paralleldisplaybus = false +ps2io = false +pulseio = false +pwmio = false +qrio = false +qspibus = false +rainbowio = true +random = true +rclcpy = false +rgbmatrix = false +rotaryio = true # Zephyr board has rotaryio +rtc = false +sdcardio = true # Zephyr board has busio +sdioio = false +sharpdisplay = true # Zephyr board has busio +socketpool = true # Zephyr networking enabled +spitarget = false +ssl = true # Zephyr networking enabled +storage = true +struct = true +supervisor = true +synthio = false +terminalio = true # Zephyr board has busio +tilepalettemapper = true # Zephyr board has busio +time = true +touchio = false +traceback = true +uheap = false +usb = false +usb_audio = false +usb_cdc = false +usb_hid = false +usb_host = false +usb_midi = false +usb_video = false +ustack = false +vectorio = true # Zephyr board has busio +warnings = true +watchdog = false +wifi = true # Zephyr board has wifi +zephyr_display = false +zephyr_kernel = false +zlib = true +# extmod modules shared with MicroPython +asyncio = true +binascii = true +json = true +re = true +select = true diff --git a/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/circuitpython.toml b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/circuitpython.toml new file mode 100644 index 00000000000..1f15a6f8349 --- /dev/null +++ b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/circuitpython.toml @@ -0,0 +1 @@ +CIRCUITPY_BUILD_EXTENSIONS = ["rps"] diff --git a/ports/zephyr-cp/boards/siwx917_dk2605a.conf b/ports/zephyr-cp/boards/siwx917_dk2605a.conf new file mode 100644 index 00000000000..0ad2a578ee8 --- /dev/null +++ b/ports/zephyr-cp/boards/siwx917_dk2605a.conf @@ -0,0 +1,93 @@ +# The upstream board defconfig does not enable GPIO, so no gpio device structs +# are instantiated and the generated board.c fails to link. +CONFIG_GPIO=y + +# getaddrinfo() calls k_calloc(), which is compiled out when the kernel heap is +# zero-sized. prj.conf also draws thread stacks from this heap. +CONFIG_HEAP_MEM_POOL_SIZE=16384 + +CONFIG_NETWORKING=y +CONFIG_NET_IPV4=y +CONFIG_NET_DHCPV4=y +CONFIG_NET_SOCKETS=y + +# Not implied by the options above, and the siwx91x driver defaults to the +# native stack. Without it association and DHCP still work, since DHCP is UDP, +# while every SOCK_STREAM socket fails. +CONFIG_NET_TCP=y + +# Every Zephyr socket also takes a zvfs file descriptor, which defaults to 0. +CONFIG_ZVFS_OPEN_MAX=8 + +# Poll slots for the socket-service thread, a separate budget from OPEN_MAX. +# The thread polls one entry beyond the number of registered services, so this +# must be strictly greater than that count. DNS_RESOLVER registers one service +# and MDNS_RESPONDER two, so the Zephyr default of 3 is one short and the +# service thread fails at boot, leaving every socket it owns unread. +CONFIG_ZVFS_POLL_MAX=6 + +# dns_resolve_reconfigure() is additive by default: it fills free slots and +# stops when there are none, then still returns 0. With one server slot held by +# DHCP, assigning to radio.dns would install nothing and report success. This +# makes reconfigure rebuild the list instead, which is the replace semantics +# the binding implies by exposing dns as a settable Sequence[str]. +CONFIG_DNS_RECONFIGURE_CLEANUP=y + +# Incoming connections are bounded by the net_conn array, not the TCP context +# slab. At the default of 8 the web workflow refuses connections during a burst +# because teardown cannot recycle slots fast enough, since each closed +# connection holds its slot for TIME_WAIT. 12 leaves enough headroom, and the +# context slab is raised alongside it so the slab is not the tighter bound. +CONFIG_NET_MAX_CONTEXTS=12 +CONFIG_NET_MAX_CONN=12 + +# Zephyr's console (printk, boot banner, driver logs) goes to SEGGER RTT over +# the existing SWD connection rather than sharing the UART with the REPL, where +# net event printks interleave with and corrupt the REPL stream. CircuitPython's +# REPL is unaffected: supervisor/serial.c takes its device from +# DT_CHOSEN(zephyr_console) and drives it directly. +CONFIG_USE_SEGGER_RTT=y +CONFIG_RTT_CONSOLE=y +CONFIG_UART_CONSOLE=n + +CONFIG_WIFI=y +CONFIG_NET_L2_WIFI_MGMT=y +CONFIG_NET_MGMT_EVENT=y +CONFIG_NET_MGMT_EVENT_INFO=y + +# Answers .local and advertises services registered through +# mdns.Server.advertise_service(). Zephyr's responder is push-only, so +# mdns.Server.find() has nothing to search with yet. +CONFIG_MDNS_RESPONDER=y +CONFIG_DNS_SD=y +CONFIG_MDNS_RESPONDER_DNS_SD=y + +CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y +CONFIG_MBEDTLS_CIPHERSUITE_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256=y +CONFIG_MBEDTLS_ENTROPY_C=y +CONFIG_MBEDTLS_CTR_DRBG_C=y + +# Long writes need at least one prepare slot. Zephyr's unconditional default of +# 0 rejects any write that does not fit a single ATT_WRITE_REQ, and only an +# explicit assignment here overrides it. +CONFIG_BT_ATT_PREPARE_COUNT=2 + +# Zephyr's default preferred supervision timeout is 420ms, which the peripheral +# pushes onto the central shortly into every connection. That is thin on a +# single-antenna part whose network processor shares the radio with Wi-Fi. +# 400 = 4.0s, Apple's accessory guideline value. +CONFIG_BT_PERIPHERAL_PREF_MIN_INT=24 +CONFIG_BT_PERIPHERAL_PREF_MAX_INT=40 +CONFIG_BT_PERIPHERAL_PREF_LATENCY=0 +CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=400 + +# The controller reports 15 ACL TX buffers while the host defaults to 3, which +# it warns about at boot. Match the host to the controller. +CONFIG_BT_BUF_ACL_TX_COUNT=15 + +# DHCP hands us a resolver, but the resolver subsystem has to be present for +# socketpool.getaddrinfo() and radio.ipv4_dns to work. +CONFIG_DNS_RESOLVER=y + +# DMA for the GSPI controller, which serves the breakout pads. +CONFIG_DMA=y diff --git a/ports/zephyr-cp/boards/siwx917_dk2605a.overlay b/ports/zephyr-cp/boards/siwx917_dk2605a.overlay new file mode 100644 index 00000000000..f345c30b9b0 --- /dev/null +++ b/ports/zephyr-cp/boards/siwx917_dk2605a.overlay @@ -0,0 +1,69 @@ +// Replaces the port's app.overlay, which does `&zephyr_udc0 { ... }` to add a +// CDC-ACM console. The SiWG917 has no USB device controller, so the console +// falls back to the Zephyr console on &ulpuart, reaching the host over the +// on-board J-Link VCOM. + +// CIRCUITPY filesystem. +// +// supervisor/flash.c needs a partition labeled `circuitpy_partition`, and the +// whole 8 MB is already partitioned by siwg917m111mgtba.dtsi with no +// unallocated space to claim. The upper region is owned by the network +// processor, which refuses M4 writes there, so CIRCUITPY is carved out of the +// M4's own code_partition, shrunk from 2008K to 1M. Overflowing that fails at +// link time rather than corrupting the filesystem. +&flash0 { + partitions { + code_partition: partition@202000 { + compatible = "zephyr,mapped-partition"; + label = "code_partition"; + reg = <0x00202000 0x00100000>; + }; + + circuitpy_partition: partition@302000 { + compatible = "zephyr,mapped-partition"; + label = "circuitpy"; + reg = <0x00302000 0x000f6000>; + }; + }; +}; + +// GSPI on the breakout pads. The board .dts leaves spi0 disabled and wires +// nothing, so the pin assignment here is taken from the mapping Silicon Labs +// ships for this board in +// zephyr/tests/drivers/spi/spi_loopback/boards/siwx917_dk2605a.overlay: +// CLK on pad 3, MOSI on pad 5, MISO on pad 7, CS on gpiob 12. +// +// spi0 is the SoC's only SPI controller node and is compatible "silabs,gspi". +// The on-board IMU is on a separate ULP SPI bus that has no controller node in +// devicetree, so it is not reachable through this one. +&pinctrl0 { + spi0_default: spi0_default { + out { + pinmux = , ; + }; + + in { + pinmux = ; + }; + }; +}; + +&spi0 { + status = "okay"; + cs-gpios = <&gpiob 12 GPIO_ACTIVE_LOW>; + pinctrl-0 = <&spi0_default>; + pinctrl-names = "default"; + + dmas = <&gpdma 0 11>, <&gpdma 1 10>; + dma-names = "tx", "rx"; +}; + +&gpdma { + status = "okay"; +}; + +// 8 MB of PSRAM on the QSPI2 path. Present in ram_bounds; the Python heap does +// not use it yet. +&psram { + status = "okay"; +}; From 0c4352fb526b4e106dc736b0d1b174c0791f755c Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 21 Aug 2026 07:38:20 -0700 Subject: [PATCH 807/876] zephyr-cp/wifi: subscribe to NET_EVENT_WIFI_SCAN_RESULT The event handler has a NET_EVENT_WIFI_SCAN_RESULT case that queues each AP as it arrives, but that event was never in the subscription mask, so the case never ran and scans always returned zero networks. RAW_SCAN_RESULT is in the mask but is not a substitute. It carries raw beacon frames and only fires when CONFIG_WIFI_MGMT_RAW_SCAN_RESULTS is enabled, which it is not by default. Measured on a Raspberry Pi Pico 2 W running raspberrypi_rpi_pico2_w_zephyr, built from 069144c66 and flashed over SWD with pyOCD: len([1 for n in wifi.radio.start_scanning_networks()]) before 0 after 204 Same board, same probe, same script, with only this change reverted for the before run. --- ports/zephyr-cp/common-hal/wifi/__init__.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 4b967bc2780..81ebdfdc955 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -278,6 +278,7 @@ void common_hal_wifi_init(bool user_initiated) { // self->ap_mode = 0; net_mgmt_init_event_callback(&wifi_cb, _event_handler, + NET_EVENT_WIFI_SCAN_RESULT | NET_EVENT_WIFI_SCAN_DONE | NET_EVENT_WIFI_CONNECT_RESULT | NET_EVENT_WIFI_DISCONNECT_RESULT | From dfe806d68e1a66eddbdde12cbb3b03f37adbfd33 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Sat, 22 Aug 2026 13:57:45 -0700 Subject: [PATCH 808/876] zephyr-cp/wifi: route diagnostic output through the log subsystem The Wi-Fi common-hal printed on every net event with raw printk. That output is unconditional, so it corrupts the serial handshake that raw-REPL tooling relies on, and it cannot be turned down per module. Register a cp_wifi log module and route the existing calls through it, at CONFIG_LOG_DEFAULT_LEVEL as supervisor/usb.c already does. Two printks in start_scanning_networks() only restated the message raised on the following line, so they are dropped rather than converted. Also fixes two defects the conversion exposed: - The unhandled-event print passed a uint64_t mgmt_event to %x, truncating to 32 bits. Since the layer lives in the high bits, every unhandled Wi-Fi event aliased to the same value. - NET_EVENT_IPV4_ADDR_ADD was already subscribed but had no case, so it fell through to the unhandled-event path and the status bar kept reading "No IP" after DHCP bound, while wifi.radio.ipv4_address returned the real lease. --- ports/zephyr-cp/common-hal/wifi/Radio.c | 15 ++-- .../common-hal/wifi/ScannedNetworks.c | 7 +- ports/zephyr-cp/common-hal/wifi/__init__.c | 84 +++++++++++-------- 3 files changed, 61 insertions(+), 45 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 35a0b76a362..9ae19b5392a 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -25,6 +25,7 @@ #include "bindings/zephyr_kernel/__init__.h" #include +#include #include #include #include @@ -33,6 +34,8 @@ #include "common-hal/mdns/Server.h" #endif +LOG_MODULE_DECLARE(cp_wifi); + #define MAC_ADDRESS_LENGTH 6 // static void set_mode_station(wifi_radio_obj_t *self, bool state) { @@ -85,7 +88,7 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { // #if CIRCUITPY_MDNS // mdns_server_deinit_singleton(); // #endif - printk("net_if_down\n"); + LOG_DBG("net_if_down"); int res = net_if_down(self->sta_netif); if (res < 0 && res != -EALREADY) { raise_zephyr_error(res); @@ -94,7 +97,7 @@ void common_hal_wifi_radio_set_enabled(wifi_radio_obj_t *self, bool enabled) { return; } if (!self->started && enabled) { - printk("net_if_up\n"); + LOG_DBG("net_if_up"); int res = net_if_up(self->sta_netif); if (res < 0 && res != -EALREADY) { raise_zephyr_error(res); @@ -214,13 +217,11 @@ void common_hal_wifi_radio_set_mac_address_ap(wifi_radio_obj_t *self, const uint } mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self, uint8_t start_channel, uint8_t stop_channel) { - printk("common_hal_wifi_radio_start_scanning_networks\n"); + LOG_DBG("common_hal_wifi_radio_start_scanning_networks"); if (self->current_scan != NULL) { - printk("Already scanning for wifi networks\n"); mp_raise_RuntimeError(MP_ERROR_TEXT("Already scanning for wifi networks")); } if (!common_hal_wifi_radio_get_enabled(self)) { - printk("WiFi is not enabled\n"); mp_raise_RuntimeError(MP_ERROR_TEXT("WiFi is not enabled")); } @@ -246,12 +247,12 @@ mp_obj_t common_hal_wifi_radio_start_scanning_networks(wifi_radio_obj_t *self, u K_POLL_MODE_NOTIFY_ONLY, &scan->msgq); wifi_scannednetworks_scan_next_channel(scan); - printk("common_hal_wifi_radio_start_scanning_networks done %p\n", scan); + LOG_DBG("common_hal_wifi_radio_start_scanning_networks done %p", scan); return scan; } void common_hal_wifi_radio_stop_scanning_networks(wifi_radio_obj_t *self) { - printk("common_hal_wifi_radio_stop_scanning_networks\n"); + LOG_DBG("common_hal_wifi_radio_stop_scanning_networks"); // Return early if self->current_scan is NULL to avoid hang if (self->current_scan == NULL) { return; diff --git a/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c b/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c index 725bf1fa7cb..d7df14ffa5c 100644 --- a/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c +++ b/ports/zephyr-cp/common-hal/wifi/ScannedNetworks.c @@ -19,12 +19,15 @@ #include "bindings/zephyr_kernel/__init__.h" #include +#include #include +LOG_MODULE_DECLARE(cp_wifi); + void wifi_scannednetworks_scan_result(wifi_scannednetworks_obj_t *self, struct wifi_scan_result *result) { if (k_msgq_put(&self->msgq, result, K_NO_WAIT) != 0) { - printk("Dropping scan result!\n"); + LOG_WRN("Dropping scan result"); } } @@ -104,7 +107,7 @@ void wifi_scannednetworks_scan_next_channel(wifi_scannednetworks_obj_t *self) { } else { int res = net_mgmt(NET_REQUEST_WIFI_SCAN, self->netif, ¶ms, sizeof(params)); if (res != 0) { - printk("Failed to start wifi scan %d\n", res); + LOG_ERR("Failed to start wifi scan %d", res); raise_zephyr_error(res); wifi_scannednetworks_done(self); } else { diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 81ebdfdc955..213ef7f618f 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -31,12 +31,15 @@ wifi_radio_obj_t common_hal_wifi_radio_obj; #endif #include +#include #include #include #define MAC_ADDRESS_LENGTH 6 +LOG_MODULE_REGISTER(cp_wifi, CONFIG_LOG_DEFAULT_LEVEL); + static void schedule_background_on_cp_core(void *arg) { #if CIRCUITPY_STATUS_BAR supervisor_status_bar_request_update(false); @@ -56,7 +59,7 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve switch (mgmt_event) { case NET_EVENT_WIFI_SCAN_RESULT: { - printk("NET_EVENT_WIFI_SCAN_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_SCAN_RESULT"); const struct wifi_scan_result *result = cb->info; if (result != NULL && self->current_scan != NULL) { wifi_scannednetworks_scan_result(self->current_scan, result); @@ -64,7 +67,7 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve break; } case NET_EVENT_WIFI_SCAN_DONE: - printk("NET_EVENT_WIFI_SCAN_DONE (thread: %s prio=%d)\n", + LOG_DBG("NET_EVENT_WIFI_SCAN_DONE (thread: %s prio=%d)", k_thread_name_get(k_current_get()), k_thread_priority_get(k_current_get())); if (self->current_scan != NULL) { @@ -72,46 +75,55 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve } break; case NET_EVENT_WIFI_CONNECT_RESULT: - printk("NET_EVENT_WIFI_CONNECT_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_CONNECT_RESULT"); break; case NET_EVENT_WIFI_DISCONNECT_RESULT: - printk("NET_EVENT_WIFI_DISCONNECT_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_DISCONNECT_RESULT"); break; case NET_EVENT_WIFI_IFACE_STATUS: - printk("NET_EVENT_WIFI_IFACE_STATUS\n"); + LOG_DBG("NET_EVENT_WIFI_IFACE_STATUS"); break; case NET_EVENT_WIFI_TWT: - printk("NET_EVENT_WIFI_TWT\n"); + LOG_DBG("NET_EVENT_WIFI_TWT"); break; case NET_EVENT_WIFI_TWT_SLEEP_STATE: - printk("NET_EVENT_WIFI_TWT_SLEEP_STATE\n"); + LOG_DBG("NET_EVENT_WIFI_TWT_SLEEP_STATE"); break; case NET_EVENT_WIFI_RAW_SCAN_RESULT: - printk("NET_EVENT_WIFI_RAW_SCAN_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_RAW_SCAN_RESULT"); break; case NET_EVENT_WIFI_DISCONNECT_COMPLETE: - printk("NET_EVENT_WIFI_DISCONNECT_COMPLETE\n"); + LOG_DBG("NET_EVENT_WIFI_DISCONNECT_COMPLETE"); break; case NET_EVENT_WIFI_SIGNAL_CHANGE: - printk("NET_EVENT_WIFI_SIGNAL_CHANGE\n"); + LOG_DBG("NET_EVENT_WIFI_SIGNAL_CHANGE"); break; case NET_EVENT_WIFI_NEIGHBOR_REP_COMP: - printk("NET_EVENT_WIFI_NEIGHBOR_REP_COMP\n"); + LOG_DBG("NET_EVENT_WIFI_NEIGHBOR_REP_COMP"); break; case NET_EVENT_WIFI_AP_ENABLE_RESULT: - printk("NET_EVENT_WIFI_AP_ENABLE_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_AP_ENABLE_RESULT"); break; case NET_EVENT_WIFI_AP_DISABLE_RESULT: - printk("NET_EVENT_WIFI_AP_DISABLE_RESULT\n"); + LOG_DBG("NET_EVENT_WIFI_AP_DISABLE_RESULT"); break; case NET_EVENT_WIFI_AP_STA_CONNECTED: - printk("NET_EVENT_WIFI_AP_STA_CONNECTED\n"); + LOG_DBG("NET_EVENT_WIFI_AP_STA_CONNECTED"); break; case NET_EVENT_WIFI_AP_STA_DISCONNECTED: - printk("NET_EVENT_WIFI_AP_STA_DISCONNECTED\n"); + LOG_DBG("NET_EVENT_WIFI_AP_STA_DISCONNECTED"); + break; + case NET_EVENT_IPV4_ADDR_ADD: + // DHCP bound, or a static address was configured. The address is read + // live by the ipv4_address getter, so nothing is stored here; the + // status bar just needs a refresh or it keeps showing "No IP". + LOG_DBG("NET_EVENT_IPV4_ADDR_ADD"); + schedule_background_on_cp_core(NULL); break; default: - printk("unhandled net event %x\n", mgmt_event); + // Print all 64 bits. The layer lives in the high bits, so a 32-bit + // print collapses every unhandled event in a layer to one value. + LOG_DBG("unhandled net event %llx", (unsigned long long)mgmt_event); break; } } @@ -196,7 +208,7 @@ static bool wifi_user_initiated; void common_hal_wifi_init(bool user_initiated) { wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; - printk("common_hal_wifi_init\n"); + LOG_DBG("common_hal_wifi_init"); if (wifi_inited) { if (user_initiated && !wifi_user_initiated) { @@ -223,8 +235,8 @@ void common_hal_wifi_init(bool user_initiated) { // } self->sta_netif = net_if_get_wifi_sta(); self->ap_netif = net_if_get_wifi_sap(); - printk("sta_netif %p\n", self->sta_netif); - printk("ap_netif %p\n", self->ap_netif); + LOG_DBG("sta_netif %p", self->sta_netif); + LOG_DBG("ap_netif %p", self->ap_netif); struct wifi_iface_status status = { 0 }; @@ -232,39 +244,39 @@ void common_hal_wifi_init(bool user_initiated) { CHECK_ZEPHYR_RESULT(net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, self->sta_netif, &status, sizeof(struct wifi_iface_status))); if (net_if_is_up(self->sta_netif)) { - printk("STA is up\n"); + LOG_DBG("STA is up"); } else { - printk("STA is down\n"); + LOG_DBG("STA is down"); } if (net_if_is_carrier_ok(self->sta_netif)) { - printk("STA carrier is ok\n"); + LOG_DBG("STA carrier is ok"); } else { - printk("STA carrier is not ok\n"); + LOG_DBG("STA carrier is not ok"); } if (net_if_is_dormant(self->sta_netif)) { - printk("STA is dormant\n"); + LOG_DBG("STA is dormant"); } else { - printk("STA is not dormant\n"); + LOG_DBG("STA is not dormant"); } } if (self->ap_netif != NULL) { int res = net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, self->ap_netif, &status, sizeof(struct wifi_iface_status)); - printk("AP status request response %d\n", res); + LOG_DBG("AP status request response %d", res); if (net_if_is_up(self->ap_netif)) { - printk("AP is up\n"); + LOG_DBG("AP is up"); } else { - printk("AP is down\n"); + LOG_DBG("AP is down"); } if (net_if_is_carrier_ok(self->ap_netif)) { - printk("AP carrier is ok\n"); + LOG_DBG("AP carrier is ok"); } else { - printk("AP carrier is not ok\n"); + LOG_DBG("AP carrier is not ok"); } if (net_if_is_dormant(self->ap_netif)) { - printk("AP is dormant\n"); + LOG_DBG("AP is dormant"); } else { - printk("AP is not dormant\n"); + LOG_DBG("AP is not dormant"); } } @@ -318,21 +330,21 @@ void common_hal_wifi_init(bool user_initiated) { char cpy_default_hostname[board_len + (MAC_ADDRESS_LENGTH * 2) + 6]; struct net_linkaddr *mac = net_if_get_link_addr(self->sta_netif); if (mac->len < MAC_ADDRESS_LENGTH) { - printk("MAC address too short"); + LOG_ERR("MAC address too short"); } snprintf(cpy_default_hostname, sizeof(cpy_default_hostname), "cpy-%s-%02x%02x%02x%02x%02x%02x", CIRCUITPY_BOARD_ID + board_trim, mac->addr[0], mac->addr[1], mac->addr[2], mac->addr[3], mac->addr[4], mac->addr[5]); CHECK_ZEPHYR_RESULT(net_hostname_set(cpy_default_hostname, strlen(cpy_default_hostname))); } #else - printk("Hostname support disabled in Zephyr config\n"); + LOG_WRN("Hostname support disabled in Zephyr config"); #endif // set station mode to avoid the default SoftAP common_hal_wifi_radio_start_station(self); // start wifi common_hal_wifi_radio_set_enabled(self, true); - printk("common_hal_wifi_init done\n"); + LOG_DBG("common_hal_wifi_init done"); } void wifi_user_reset(void) { @@ -343,7 +355,7 @@ void wifi_user_reset(void) { } void wifi_reset(void) { - printk("wifi_reset\n"); + LOG_DBG("wifi_reset"); if (!wifi_inited) { return; } From e49deacbc001d1e0c4b9630106ce6414dda9f31b Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Sun, 23 Aug 2026 15:24:37 +0000 Subject: [PATCH 809/876] picogame: split Tilemap.tile() into get_tile() and set_tile() Replace the combined getter/setter with two methods, per review. get_tile(tx, ty) is a plain 3-arg binding (no kwarg parsing on the read path); set_tile(tx, ty, value) keeps the flip_x/flip_y/transpose orientation keywords. Out-of-range behavior is unchanged: reads return 0, writes are ignored. --- shared-bindings/picogame/Tilemap.c | 113 ++++++++++++++++------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/shared-bindings/picogame/Tilemap.c b/shared-bindings/picogame/Tilemap.c index a850831032f..849bec01532 100644 --- a/shared-bindings/picogame/Tilemap.c +++ b/shared-bindings/picogame/Tilemap.c @@ -57,29 +57,43 @@ static mp_obj_t picogame_tilemap_make_new(const mp_obj_type_t *type, size_t n_ar return MP_OBJ_FROM_PTR(self); } -//| def tile( +//| def get_tile(self, tx: int, ty: int) -> int: +//| """Return the tile index at (tx, ty). Out-of-range reads as 0.""" +//| ... +//| +static mp_obj_t picogame_tilemap_get_tile(mp_obj_t self_in, mp_obj_t tx_in, mp_obj_t ty_in) { + picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(self_in); + int tx = mp_obj_get_int(tx_in); + int ty = mp_obj_get_int(ty_in); + if (tx < 0 || ty < 0 || tx >= self->map_w || ty >= self->map_h) { + return MP_OBJ_NEW_SMALL_INT(0); + } + return MP_OBJ_NEW_SMALL_INT(self->map[(size_t)ty * self->map_w + tx]); +} +static MP_DEFINE_CONST_FUN_OBJ_3(picogame_tilemap_get_tile_obj, picogame_tilemap_get_tile); + +//| def set_tile( //| self, //| tx: int, //| ty: int, -//| value: Optional[int] = None, +//| value: int, //| *, //| flip_x: bool = False, //| flip_y: bool = False, //| transpose: bool = False, -//| ) -> Optional[int]: -//| """Get the tile at (tx, ty) -> int; with ``value``, set it (and mark dirty) -> None. -//| The optional keyword ``flip_x``/``flip_y``/``transpose`` flags orient the tile - together -//| they give all 8 orientations (4 rotations x mirror) for free at draw time; use them -//| with a deduplicated tileset (png2picogame --dedup REMAP). Out-of-range reads as 0, -//| ignores writes.""" +//| ) -> None: +//| """Set the tile at (tx, ty) and mark it dirty. The keyword ``flip_x``/``flip_y``/ +//| ``transpose`` flags orient the tile - together they give all 8 orientations +//| (4 rotations x mirror) for free at draw time; use them with a deduplicated tileset +//| (png2picogame --dedup REMAP). Out-of-range writes are ignored.""" //| ... //| -static mp_obj_t picogame_tilemap_tile(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +static mp_obj_t picogame_tilemap_set_tile(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { enum { ARG_tx, ARG_ty, ARG_value, ARG_flip_x, ARG_flip_y, ARG_transpose }; static const mp_arg_t allowed_args[] = { { MP_QSTR_tx, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_ty, MP_ARG_REQUIRED | MP_ARG_INT }, - { MP_QSTR_value, MP_ARG_OBJ, {.u_obj = mp_const_none} }, + { MP_QSTR_value, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_flip_x, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_flip_y, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, { MP_QSTR_transpose, MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} }, @@ -89,51 +103,45 @@ static mp_obj_t picogame_tilemap_tile(size_t n_args, const mp_obj_t *pos_args, m picogame_tilemap_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); int tx = args[ARG_tx].u_int; int ty = args[ARG_ty].u_int; - bool oob = (tx < 0 || ty < 0 || tx >= self->map_w || ty >= self->map_h); - if (args[ARG_value].u_obj != mp_const_none) { - if (!oob) { - size_t off = (size_t)ty * self->map_w + tx; - uint8_t v = mp_obj_get_int(args[ARG_value].u_obj) & 0xff; - uint8_t o = 0; - if (args[ARG_flip_x].u_bool) { - o |= 1; - } - if (args[ARG_flip_y].u_bool) { - o |= 2; - } - if (args[ARG_transpose].u_bool) { - o |= 4; - } - // Allocate the orientation plane lazily - only maps that actually use flips/rotation - // pay the RAM (1 byte/cell). - if (o != 0 && self->orient == NULL) { - mp_obj_t ob = mp_obj_new_bytearray_of_zeros((size_t)self->map_w * self->map_h); - mp_buffer_info_t oi; - mp_get_buffer_raise(ob, &oi, MP_BUFFER_RW); - self->orient = oi.buf; - self->orient_obj = ob; - } - uint8_t old_o = self->orient ? self->orient[off] : 0; - if (self->map[off] != v || old_o != o) { - self->map[off] = v; - if (self->orient) { - self->orient[off] = o; - } - int tw = self->tileset ? self->tileset->width : 0; - int th = self->tileset ? self->tileset->height : 0; - int sx = self->x + tx * tw; - int sy = self->y + ty * th; - picogame_tilemap_dirty_union(self, sx, sy, sx + tw, sy + th); - } - } + if (tx < 0 || ty < 0 || tx >= self->map_w || ty >= self->map_h) { return mp_const_none; } - if (oob) { - return MP_OBJ_NEW_SMALL_INT(0); + size_t off = (size_t)ty * self->map_w + tx; + uint8_t v = args[ARG_value].u_int & 0xff; + uint8_t o = 0; + if (args[ARG_flip_x].u_bool) { + o |= 1; } - return MP_OBJ_NEW_SMALL_INT(self->map[(size_t)ty * self->map_w + tx]); + if (args[ARG_flip_y].u_bool) { + o |= 2; + } + if (args[ARG_transpose].u_bool) { + o |= 4; + } + // Allocate the orientation plane lazily - only maps that actually use flips/rotation + // pay the RAM (1 byte/cell). + if (o != 0 && self->orient == NULL) { + mp_obj_t ob = mp_obj_new_bytearray_of_zeros((size_t)self->map_w * self->map_h); + mp_buffer_info_t oi; + mp_get_buffer_raise(ob, &oi, MP_BUFFER_RW); + self->orient = oi.buf; + self->orient_obj = ob; + } + uint8_t old_o = self->orient ? self->orient[off] : 0; + if (self->map[off] != v || old_o != o) { + self->map[off] = v; + if (self->orient) { + self->orient[off] = o; + } + int tw = self->tileset ? self->tileset->width : 0; + int th = self->tileset ? self->tileset->height : 0; + int sx = self->x + tx * tw; + int sy = self->y + ty * th; + picogame_tilemap_dirty_union(self, sx, sy, sx + tw, sy + th); + } + return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_tilemap_tile_obj, 3, picogame_tilemap_tile); +static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_tilemap_set_tile_obj, 4, picogame_tilemap_set_tile); //| def move(self, x: int, y: int) -> None: //| """Move the whole map to pixel (x, y).""" @@ -211,7 +219,8 @@ static MP_DEFINE_CONST_FUN_OBJ_1(tilemap_get_rows_obj, tilemap_get_rows); MP_PROPERTY_GETTER(tilemap_rows_obj, (mp_obj_t)&tilemap_get_rows_obj); static const mp_rom_map_elem_t picogame_tilemap_locals_dict_table[] = { - { MP_ROM_QSTR(MP_QSTR_tile), MP_ROM_PTR(&picogame_tilemap_tile_obj) }, + { MP_ROM_QSTR(MP_QSTR_get_tile), MP_ROM_PTR(&picogame_tilemap_get_tile_obj) }, + { MP_ROM_QSTR(MP_QSTR_set_tile), MP_ROM_PTR(&picogame_tilemap_set_tile_obj) }, { MP_ROM_QSTR(MP_QSTR_move), MP_ROM_PTR(&picogame_tilemap_move_obj) }, { MP_ROM_QSTR(MP_QSTR_fill), MP_ROM_PTR(&picogame_tilemap_fill_obj) }, { MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&tilemap_x_obj) }, From daa24bef0b2f41a9c17e68f9fa4442c3e0a8e40d Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Sun, 23 Aug 2026 16:38:16 +0000 Subject: [PATCH 810/876] picogame: always register Display and Framebuffer Builds without the corresponding backend get a stub type whose constructor raises NotImplementedError (the same core message the unsupported rgb444= path uses), so the module's attributes no longer vary with build flags. Adds FAST_DISPLAY_SUPPORTED and FRAMEBUFFER_SUPPORTED alongside RGB444_SUPPORTED for feature detection. +216 B on RP2040. --- shared-bindings/picogame/Display.h | 2 ++ shared-bindings/picogame/Framebuffer.h | 2 -- shared-bindings/picogame/__init__.c | 30 +++++++++++++++++++++----- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/shared-bindings/picogame/Display.h b/shared-bindings/picogame/Display.h index 1edcf137d91..6034124d88d 100644 --- a/shared-bindings/picogame/Display.h +++ b/shared-bindings/picogame/Display.h @@ -6,6 +6,8 @@ #pragma once +#if CIRCUITPY_PICOGAME_FAST_DISPLAY #include "common-hal/picogame/Display.h" +#endif extern const mp_obj_type_t picogame_display_type; diff --git a/shared-bindings/picogame/Framebuffer.h b/shared-bindings/picogame/Framebuffer.h index fd248bfff13..99112b8fa03 100644 --- a/shared-bindings/picogame/Framebuffer.h +++ b/shared-bindings/picogame/Framebuffer.h @@ -8,6 +8,4 @@ #include "shared-module/picogame/__init__.h" // picogame_framebuffer_obj_t -#if CIRCUITPY_PICOGAME_FRAMEBUFFER extern const mp_obj_type_t picogame_framebuffer_type; -#endif diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c index ebce4a70719..84940e12a6e 100644 --- a/shared-bindings/picogame/__init__.c +++ b/shared-bindings/picogame/__init__.c @@ -12,8 +12,8 @@ #include "shared-bindings/picogame/__init__.h" #include "shared-bindings/picogame/Bitmap.h" #include "shared-bindings/picogame/Sprite.h" +#include "shared-bindings/picogame/Display.h" #if CIRCUITPY_PICOGAME_FAST_DISPLAY -#include "shared-bindings/picogame/Display.h" // fast DMA backend; absent on portable ports #include "common-hal/picogame/Display.h" // its struct (pg_get_display unwraps the wrapper) #endif #include "shared-bindings/picogame/Scene.h" @@ -742,22 +742,32 @@ static mp_obj_t picogame_fbm1d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t * static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm1d_fx_obj, 1, picogame_fbm1d_fx); +// Builds without a given display backend still expose its type: constructing it raises, the same +// way an unsupported rgb444= does, instead of the module changing shape with build flags. +#if !CIRCUITPY_PICOGAME_FAST_DISPLAY || !CIRCUITPY_PICOGAME_FRAMEBUFFER +static mp_obj_t pg_stub_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + mp_raise_NotImplementedError(MP_ERROR_TEXT("Operation or feature not supported")); +} +#endif +#if !CIRCUITPY_PICOGAME_FAST_DISPLAY +MP_DEFINE_CONST_OBJ_TYPE(picogame_display_type, MP_QSTR_Display, MP_TYPE_FLAG_NONE, make_new, pg_stub_make_new); +#endif +#if !CIRCUITPY_PICOGAME_FRAMEBUFFER +MP_DEFINE_CONST_OBJ_TYPE(picogame_framebuffer_type, MP_QSTR_Framebuffer, MP_TYPE_FLAG_NONE, make_new, pg_stub_make_new); +#endif + static const mp_rom_map_elem_t picogame_module_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_picogame) }, { MP_ROM_QSTR(MP_QSTR_Bitmap), MP_ROM_PTR(&picogame_bitmap_type) }, { MP_ROM_QSTR(MP_QSTR_Sprite), MP_ROM_PTR(&picogame_sprite_type) }, - #if CIRCUITPY_PICOGAME_FAST_DISPLAY { MP_ROM_QSTR(MP_QSTR_Display), MP_ROM_PTR(&picogame_display_type) }, - #endif { MP_ROM_QSTR(MP_QSTR_Scene), MP_ROM_PTR(&picogame_scene_type) }, { MP_ROM_QSTR(MP_QSTR_Tilemap), MP_ROM_PTR(&picogame_tilemap_type) }, { MP_ROM_QSTR(MP_QSTR_Particles), MP_ROM_PTR(&picogame_particles_type) }, { MP_ROM_QSTR(MP_QSTR_Canvas), MP_ROM_PTR(&picogame_canvas_type) }, { MP_ROM_QSTR(MP_QSTR_StripDraw), MP_ROM_PTR(&picogame_stripdraw_type) }, { MP_ROM_QSTR(MP_QSTR_Triangles), MP_ROM_PTR(&picogame_triangles_type) }, - #if CIRCUITPY_PICOGAME_FRAMEBUFFER { MP_ROM_QSTR(MP_QSTR_Framebuffer), MP_ROM_PTR(&picogame_framebuffer_type) }, - #endif { MP_ROM_QSTR(MP_QSTR_render), MP_ROM_PTR(&picogame_render_obj) }, { MP_ROM_QSTR(MP_QSTR_raycast), MP_ROM_PTR(&picogame_raycast_obj) }, { MP_ROM_QSTR(MP_QSTR_road_edges), MP_ROM_PTR(&picogame_road_edges_obj) }, @@ -789,6 +799,16 @@ static const mp_rom_map_elem_t picogame_module_globals_table[] = { #else { MP_ROM_QSTR(MP_QSTR_RGB444_SUPPORTED), MP_ROM_FALSE }, #endif + #if CIRCUITPY_PICOGAME_FAST_DISPLAY + { MP_ROM_QSTR(MP_QSTR_FAST_DISPLAY_SUPPORTED), MP_ROM_TRUE }, + #else + { MP_ROM_QSTR(MP_QSTR_FAST_DISPLAY_SUPPORTED), MP_ROM_FALSE }, + #endif + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + { MP_ROM_QSTR(MP_QSTR_FRAMEBUFFER_SUPPORTED), MP_ROM_TRUE }, + #else + { MP_ROM_QSTR(MP_QSTR_FRAMEBUFFER_SUPPORTED), MP_ROM_FALSE }, + #endif // Build-time default render-strip height (rows). picogame_game.setup() uses it when strip_h is // None; games can override per call; a board can override the default in mpconfigboard.h. // MEASURED (RP2040): with async DMA double-buffering, SMALL strips overlap render+transfer best -> From 1b63196a5fc1a3f95123205e98e4086a814a8f78 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Sun, 23 Aug 2026 17:12:39 +0000 Subject: [PATCH 811/876] picogame: rasterizer and scaled-blit fast paths Two measured optimizations from device profiling: - fill_triangles: route the edge-slope divides through a 32-bit path when the deltas fit in 16 bits (they almost always do); the 64-bit soft-divide dominated the rasterizer on M33. - blit_bitmap_scaled: opaque PAL8 sprites at power-of-two scales (2x/4x/8x) skip the generic DDA scaler - one palette lookup per source pixel, repeated rows copied. Measured 1.5x on a full scaled blit (RP2350), byte-identical to the generic path across 200k randomized windows. Powers of two only: at other scales the generic step rounding samples differently, so those keep the existing path. --- shared-module/picogame/Canvas.c | 13 ++++-- shared-module/picogame/__init__.c | 75 +++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/shared-module/picogame/Canvas.c b/shared-module/picogame/Canvas.c index 87482192124..5021dbc95f9 100644 --- a/shared-module/picogame/Canvas.c +++ b/shared-module/picogame/Canvas.c @@ -299,6 +299,13 @@ void picogame_canvas_line(picogame_canvas_obj_t *cv, int x0, int y0, int x1, int // Clamp a row span to the surface and word-fill it (the span-pass idiom shared by the filled // shapes; the per-pixel put() loops it replaced clipped and indexed every pixel). +static inline int64_t edge_slope(int32_t dx, int32_t dy) { + if (dx >= -32768 && dx <= 32767) { + return (int32_t)(dx << 16) / dy; + } + return ((int64_t)dx << 16) / dy; +} + static void span565(picogame_canvas_obj_t *cv, int y, int xs, int xe, uint16_t color) { if (y < 0 || y >= cv->h) { return; @@ -399,9 +406,9 @@ void picogame_canvas_fill_triangle(picogame_canvas_obj_t *cv, // triangles), and convex quads - the box faces the 3D demos draw - stay seam-hole-free. int w = cv->w, h = cv->h; if (Y[0] < h && Y[2] >= 0) { - int64_t sAC = (Y[2] != Y[0]) ? (((int64_t)(X[2] - X[0]) << 16) / (Y[2] - Y[0])) : 0; - int64_t sAB = (Y[1] != Y[0]) ? (((int64_t)(X[1] - X[0]) << 16) / (Y[1] - Y[0])) : 0; - int64_t sBC = (Y[2] != Y[1]) ? (((int64_t)(X[2] - X[1]) << 16) / (Y[2] - Y[1])) : 0; + int64_t sAC = (Y[2] != Y[0]) ? edge_slope(X[2] - X[0], Y[2] - Y[0]) : 0; + int64_t sAB = (Y[1] != Y[0]) ? edge_slope(X[1] - X[0], Y[1] - Y[0]) : 0; + int64_t sBC = (Y[2] != Y[1]) ? edge_slope(X[2] - X[1], Y[2] - Y[1]) : 0; uint16_t *data = cv->data; // top half: rows [Y0, Y1) walk edges A->C and A->B int ys = Y[0] < 0 ? 0 : Y[0]; diff --git a/shared-module/picogame/__init__.c b/shared-module/picogame/__init__.c index 282c4d0b64f..ddd700959ed 100644 --- a/shared-module/picogame/__init__.c +++ b/shared-module/picogame/__init__.c @@ -375,6 +375,81 @@ void picogame_blit_bitmap_scaled( } return; } + if (scale >= 512 && (scale & (scale - 1)) == 0 && !fx && !fy && fxm == NULL && !s_transp + && s_fmt == PICOGAME_FMT_PAL8) { + // Integer upscale, PAL8 - the same idea as the RGB565 2x path above (which exists for the + // half-res-canvas genre), for the format the engine's art actually uses, and for ANY integer + // factor rather than just 2. At an integer scale the DDA collapses: every source pixel maps + // to exactly `nrep` dest pixels and every source row to `nrep` dest rows, so a row is + // rasterized once and its repeats are memcpy'd. + // + // WHY IT MATTERS - it is a RAM technique, not just a speed one: art kept at 1/nrep and + // upscaled costs 1/nrep^2 of the bitmap. A 320x100 PAL8 parallax band is 31.2 kB at 1:1 but + // 7.8 kB at half size, and RP2040 has 25-40 kB of heap. Making the upscale cheap is what + // makes that trade attractive instead of merely possible. + // + // Transparency is deliberately NOT handled here: a skipped pixel must keep ITS OWN row's + // background, so the repeats cannot be memcpy'd, and measurement showed the remaining win + // (0.1-0.2 ms on the small transparent sprites that actually exist) did not justify the flash. + const int nrep = scale >> 8; + const int dy_rel = y_start - dy0, dx_rel = x_start - dx0; + int sy = dy_rel / nrep; + int rem = nrep - (dy_rel % nrep); // dest rows this source row still owns + const int sx0 = dx_rel / nrep, hoff = dx_rel % nrep; + const int nwin = x_end - x_start; + bool draw = true; + uint16_t *rep_from = NULL; + for (int y = y_start; y < y_end; y++) { + uint16_t *drow = buf + (y - oy) * bw + (x_start - ox); + if (draw) { + const uint8_t *sp = s_data + sy * stride + frame_col + sx0; + uint16_t *d = drow; + int n = nwin; + int first = nrep - hoff; // the leading source pixel may be partly clipped + if (first > n) { + first = n; + } + uint16_t c = s_pal[*sp++]; + for (int i = 0; i < first; i++) { + *d++ = c; + } + n -= first; + if (nrep == 2) { // the common case, unrolled: two stores, no counter + while (n >= 2) { + c = s_pal[*sp++]; + d[0] = c; + d[1] = c; + d += 2; + n -= 2; + } + } else { + while (n >= nrep) { + c = s_pal[*sp++]; + for (int i = 0; i < nrep; i++) { + *d++ = c; + } + n -= nrep; + } + } + if (n) { // trailing partial group + c = s_pal[*sp]; + while (n--) { + *d++ = c; + } + } + rep_from = drow; + draw = false; + } else { + memcpy(drow, rep_from, (size_t)nwin * 2); + } + if (--rem == 0) { + sy++; + rem = nrep; + draw = true; + } + } + return; + } uint32_t step = ((uint32_t)1 << 24) / scale; // source px per dest px, 16.16 // No per-row sy>=sh / per-pixel sx>=sw clamp: with dw=(sd*scale)>>8 and step=floor(2^24/scale), // the sampled index ((dw-1)*step)>>16 provably never reaches the source dimension (exhaustively From f1fc0fac53b30cf571a8e0a8d59aa79be496ef63 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 23 Aug 2026 13:25:58 -0400 Subject: [PATCH 812/876] Give boot-button LED feedback; fix press leaking between intervals Now pressing the boot button for safe mode or BLE discovery mode will display a solid yellow or blue for enough time to give feedback to the user. Also, the two button-press intervals ran back to back and both polled the button by level, so a click during the yellow flash was still held down when the discovery interval started -- it entered discovery mode and erased bonding unasked. The discovery interval now requires a release before a press counts. Co-Authored-By: Claude Fable 5 --- supervisor/shared/bluetooth/bluetooth.c | 14 ++++++++++++-- supervisor/shared/safe_mode.c | 19 ++++++++++++------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/supervisor/shared/bluetooth/bluetooth.c b/supervisor/shared/bluetooth/bluetooth.c index 263aba7cbc9..74edcbb46bb 100644 --- a/supervisor/shared/bluetooth/bluetooth.c +++ b/supervisor/shared/bluetooth/bluetooth.c @@ -252,6 +252,11 @@ void supervisor_bluetooth_init(void) { } #endif // !CIRCUITPY_USB_DEVICE + // A press must begin inside this interval. The safe mode interval just before + // this one also uses the boot button, and a press meant for safe mode can + // still be held down when this interval starts; entering discovery mode from + // it would erase bonding unasked. Require a release first. + bool button_released = !port_boot_button_pressed(); while (diff < 1000) { #if CIRCUITPY_STATUS_LED // Blink on for 50 and off for 100 @@ -262,9 +267,14 @@ void supervisor_bluetooth_init(void) { new_status_color(BLACK); } #endif - if (port_boot_button_pressed()) { + if (!port_boot_button_pressed()) { + button_released = true; + } else if (button_released && !boot_in_discovery_mode) { boot_in_discovery_mode = true; - break; + // Restart the interval so the LED shows solid blue for the full + // 1000 ms, as feedback that the press was accepted and bonding + // will be erased. + start_ticks = supervisor_ticks_ms64(); } diff = supervisor_ticks_ms64() - start_ticks; } diff --git a/supervisor/shared/safe_mode.c b/supervisor/shared/safe_mode.c index fade06db596..fba4c0fb37f 100644 --- a/supervisor/shared/safe_mode.c +++ b/supervisor/shared/safe_mode.c @@ -70,11 +70,13 @@ safe_mode_t wait_for_safe_mode_reset(void) { status_led_init(); #endif - uint32_t safe_mode_delay_msecs = 1000; + #define DEFAULT_SAFE_MODE_DELAY_MSECS (1000) + #define DEFAULT_SAFE_MODE_DELAY_SECS (((mp_float_t)DEFAULT_SAFE_MODE_DELAY_MSECS) / 1000.0f) + uint32_t safe_mode_delay_msecs = DEFAULT_SAFE_MODE_DELAY_MSECS; #if CIRCUITPY_SETTINGS_TOML - mp_float_t safe_mode_delay_secs = 1.0f; - // Will update delay_secs if setting is present. + mp_float_t safe_mode_delay_secs = DEFAULT_SAFE_MODE_DELAY_SECS; + // Will update safe_mode_delay_secs if setting is present. settings_get_float("CIRCUITPY_SAFE_MODE_DELAY", &safe_mode_delay_secs); if (safe_mode_delay_secs >= 0.0f && safe_mode_delay_secs <= (mp_float_t)UINT32_MAX) { safe_mode_delay_msecs = safe_mode_delay_secs * 1000; @@ -86,17 +88,20 @@ safe_mode_t wait_for_safe_mode_reset(void) { bool boot_in_safe_mode = false; while (diff < safe_mode_delay_msecs) { #if CIRCUITPY_STATUS_LED - // Blink on for 100, off for 100 - bool led_on = (diff % 250) < 125; + // Blink on for 125, off for 125 + bool led_on = boot_in_safe_mode || (diff % 250) < 125; if (led_on) { new_status_color(SAFE_MODE); } else { new_status_color(BLACK); } #endif - if (port_boot_button_pressed()) { + if (!boot_in_safe_mode && port_boot_button_pressed()) { boot_in_safe_mode = true; - break; + // Show solid yellow as feedback that the press was accepted, for the + // default duration. + start_ticks = supervisor_ticks_ms64(); + safe_mode_delay_msecs = DEFAULT_SAFE_MODE_DELAY_MSECS; } diff = supervisor_ticks_ms64() - start_ticks; } From e14f4d0caddc5dcb49afd9352534a15312b5c257 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Sun, 23 Aug 2026 18:32:01 +0000 Subject: [PATCH 813/876] ports/zephyr-cp: enable LOAD_ATTR_FAST_PATH and MAP_LOOKUP_CACHE The make-based ports get these two interpreter options from py/circuitpy_mpconfig.mk: LOAD_ATTR_FAST_PATH defaults to 1 and MAP_LOOKUP_CACHE to CIRCUITPY_FULL_BUILD. The zephyr-cp port does not include that makefile, so neither macro was ever defined - and py/vm.c and py/map.c test them with #if, where an undefined identifier is 0. Both optimizations were therefore silently off on this port. Define them in build_circuitpython.py next to the other interpreter flags, with the same values the classic ports use. Measured on RP2350 (Fruit Jam): method and attribute access microbenchmarks improve about 25%, closing most of the interpreter gap against ports/raspberrypi. --- ports/zephyr-cp/cptools/build_circuitpython.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 55c069a1ddc..5343a4898d5 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -369,6 +369,12 @@ async def build_circuitpython(): # noqa: C901 lto = cmake_args.get("LTO", "n") == "y" circuitpython_flags.append(f"-DCIRCUITPY_ENABLE_MPY_NATIVE={1 if enable_mpy_native else 0}") circuitpython_flags.append(f"-DCIRCUITPY_FULL_BUILD={1 if full_build else 0}") + # These two are set by py/circuitpy_mpconfig.mk on the make-based ports (LOAD_ATTR_FAST_PATH + # defaults to 1, MAP_LOOKUP_CACHE to CIRCUITPY_FULL_BUILD). This port does not include that + # makefile, so they were never defined - and py/vm.c and py/map.c test them with #if, where an + # undefined identifier is 0. Both interpreter optimisations were therefore off here. + circuitpython_flags.append("-DCIRCUITPY_OPT_LOAD_ATTR_FAST_PATH=1") + circuitpython_flags.append(f"-DCIRCUITPY_OPT_MAP_LOOKUP_CACHE={1 if full_build else 0}") circuitpython_flags.append(f"-DCIRCUITPY_SETTINGS_TOML={1 if full_build else 0}") circuitpython_flags.append(f"-DMICROPY_PY_ASYNC_AWAIT={1 if full_build else 0}") circuitpython_flags.append(f"-DMICROPY_PY_ASYNCIO={1 if full_build else 0}") From 1dac7b3808b6b493cb5b6009b18794de8ed4c4f4 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Sun, 23 Aug 2026 18:42:44 +0000 Subject: [PATCH 814/876] ports/zephyr-cp: add `ranges;` to the rpi_pico flash partitions The overlay redefines &flash0's partitions with flash-relative addresses but without ranges;, so they never translate to the XIP window. Two consequences: CONFIG_RP2_REQUIRES_SECOND_STAGE_BOOT is not selected (its Kconfig tests for a code partition at 0x10000100), so the image ships without a second-stage bootloader; and the generated UF2 targets 0x00000100 instead of 0x10000000. The RP2040 boot ROM will not run the result. Presumably unnoticed because CI and developers flash over SWD, where the ELF loads fine. boards/adafruit/metro_rp2350 upstream in Zephyr uses this exact pattern. Built raspberrypi_rpi_pico_zephyr before and after: the UF2 first block address moves from 0x00000100 to 0x10000000 and RP2_REQUIRES_SECOND_STAGE_BOOT=y gets selected. An RP2040 image built this way boots from UF2 on a PicoPad. --- ports/zephyr-cp/boards/rpi_pico_rp2040.overlay | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay index 1cdd4ca2033..283debbe939 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay @@ -2,6 +2,13 @@ /delete-node/ partitions; partitions { + /* + * Without `ranges;` the addresses below stay flash-relative: the code partition resolves + * to 0x100 instead of 0x10000100, so RP2_REQUIRES_SECOND_STAGE_BOOT is not selected (its + * Kconfig tests for 0x10000100) and the image ships without a second-stage bootloader, + * while the generated UF2 targets 0x00000100. Neither is loadable by the RP2040 boot ROM. + */ + ranges; #address-cells = <1>; #size-cells = <1>; From 14ff34c561f7f72443b2a68a2faa9c0a8ed480ad Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 23 Aug 2026 12:59:03 -0400 Subject: [PATCH 815/876] Require encryption to write the CCCD of an encrypted characteristic (espressif) NimBLE derives the auto-generated CCCD's permissions only from the BLE_GATT_CHR_F_NOTIFY_INDICATE_* flags, which were never set, so the CCCD of an encryption-requiring characteristic was writable on an unencrypted link. An unpaired central could subscribe, nothing ever demanded pairing, and its file transfer commands -- Write Commands, which ATT requires the server to silently ignore when unauthorized -- were dropped with no error, hanging the client forever. Now the CCCD write permission follows the characteristic read permission, as in the nordic port. The central's subscribe attempt gets an ATT insufficient-authentication error, which is what makes it initiate pairing. Co-Authored-By: Claude Fable 5 --- ports/espressif/common-hal/_bleio/Characteristic.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/Characteristic.c b/ports/espressif/common-hal/_bleio/Characteristic.c index ff9ab35c1b9..12180b7bfc9 100644 --- a/ports/espressif/common-hal/_bleio/Characteristic.c +++ b/ports/espressif/common-hal/_bleio/Characteristic.c @@ -62,11 +62,18 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, read_perm == SECURITY_MODE_SIGNED_WITH_MITM || write_perm == SECURITY_MODE_SIGNED_WITH_MITM) { mp_raise_NotImplementedError(MP_ERROR_TEXT("MITM security not supported")); } + // The BLE_GATT_CHR_F_NOTIFY_INDICATE_* flags are set below to require encryption or + // authentication when writing the auto-generated CCCD, if reading the + // characteristic requires it. This matches the nordic port behavior. + // Without the flags, NimBLE registers the CCCD as writable on an unencrypted link, + // so an unpaired central can subscribe and nothing ever requires it to pair. + // + // TODO: This behavior was fixed in NimBLE 1.10.0. ESP-IDF 6.0.1 uses a fork of NimBLE. if (read_perm == SECURITY_MODE_ENC_NO_MITM) { - self->flags |= BLE_GATT_CHR_F_READ_ENC; + self->flags |= BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_NOTIFY_INDICATE_ENC; } if (read_perm == SECURITY_MODE_SIGNED_NO_MITM) { - self->flags |= BLE_GATT_CHR_F_READ_AUTHEN; + self->flags |= BLE_GATT_CHR_F_READ_AUTHEN | BLE_GATT_CHR_F_NOTIFY_INDICATE_AUTHEN; } if (write_perm == SECURITY_MODE_ENC_NO_MITM) { self->flags |= BLE_GATT_CHR_F_WRITE_ENC; From f82022c94134ced09cda84b36d13fb1c751731fd Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Sun, 23 Aug 2026 18:04:20 -0400 Subject: [PATCH 816/876] Accept re-pairing from a bonded peer (espressif) NimBLE reports BLE_GAP_EVENT_REPEAT_PAIRING when a peer we still hold a bond for asks to pair again. Unless the application deletes the old bond and returns BLE_GAP_REPEAT_PAIRING_RETRY, the stack silently ignores the pairing request. The event was unhandled, so a central that had forgotten its side of the bond could not pair again: the board's bonds had to be erased first. Delete the stale bond with ble_store_util_delete_peer() and retry, matching the nordic port, which clears the stored keys when a peer re-pairs. --- ports/espressif/common-hal/_bleio/Connection.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ports/espressif/common-hal/_bleio/Connection.c b/ports/espressif/common-hal/_bleio/Connection.c index 91d2336ee68..a063f3ee1a8 100644 --- a/ports/espressif/common-hal/_bleio/Connection.c +++ b/ports/espressif/common-hal/_bleio/Connection.c @@ -34,6 +34,7 @@ #include "freertos/queue.h" #include "host/ble_att.h" +#include "host/ble_store.h" // Uncomment to turn on debug logging just in this file. // #undef CIRCUITPY_VERBOSE_BLE @@ -81,6 +82,22 @@ int bleio_connection_event_cb(struct ble_gap_event *event, void *connection_in) } break; } + case BLE_GAP_EVENT_REPEAT_PAIRING: { + // The peer is asking to pair even though we still have a bond with it. + // This means it no longer has its own copy of that bond. Discard our bond + // and tell the BLE stack to carry on pairing. Otherwise NimBLE silently + // ignores the request, and a central that has forgotten this device can + // never pair again without erasing the bonds on the board. The + // nordic port likewise replaces the stored keys when a peer re-pairs. + struct ble_gap_conn_desc desc; + if (ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc) != 0) { + return BLE_GAP_REPEAT_PAIRING_IGNORE; + } + ble_store_util_delete_peer(&desc.peer_id_addr); + // The BLE stack checks that the bond is really gone before retrying, and + // reports this event again if it is not. + return BLE_GAP_REPEAT_PAIRING_RETRY; + } case BLE_GAP_EVENT_MTU: { if (event->mtu.conn_handle != connection->conn_handle) { return 0; From d3b04476114b9a23316a6bdd31d26b11312db0c5 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 24 Aug 2026 09:40:01 -0700 Subject: [PATCH 817/876] espressif: read the MAC from efuse in port_boot_info port_boot_info() runs before esp_wifi_init(), so esp_wifi_get_mac() fails with ESP_ERR_WIFI_NOT_INIT and leaves the stack buffer untouched. On the Metro ESP32-S2 that prints MAC:00:00:00:00:00:00 in boot_out.txt. esp_read_mac() reads the factory-burned MAC from efuse and does not require the WiFi driver to be started. Co-Authored-By: Claude Opus 5 (1M context) --- ports/espressif/supervisor/port.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ports/espressif/supervisor/port.c b/ports/espressif/supervisor/port.c index 0d47f7ecd19..34cfba32b7e 100644 --- a/ports/espressif/supervisor/port.c +++ b/ports/espressif/supervisor/port.c @@ -16,6 +16,7 @@ #include "py/mpprint.h" #include "py/runtime.h" +#include "esp_mac.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -521,7 +522,12 @@ void port_idle_until_interrupt(void) { #if CIRCUITPY_WIFI void port_boot_info(void) { uint8_t mac[6]; - esp_wifi_get_mac(WIFI_IF_STA, mac); + // This runs before esp_wifi_init(), so esp_wifi_get_mac() fails with + // ESP_ERR_WIFI_NOT_INIT and leaves mac[] untouched. esp_read_mac() reads + // efuse directly and does not need the WiFi driver started. + if (esp_read_mac(mac, ESP_MAC_WIFI_STA) != ESP_OK) { + return; + } mp_printf(&mp_plat_print, "MAC"); for (int i = 0; i < 6; i++) { mp_printf(&mp_plat_print, ":%02X", mac[i]); From 1e342d3ddbc049419f1a3ad89753537100260760 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Smitka?= Date: Mon, 24 Aug 2026 22:29:43 +0200 Subject: [PATCH 818/876] Update ports/zephyr-cp/cptools/build_circuitpython.py Co-authored-by: Scott Shawcroft --- ports/zephyr-cp/cptools/build_circuitpython.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 5343a4898d5..edc9422377b 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -369,10 +369,6 @@ async def build_circuitpython(): # noqa: C901 lto = cmake_args.get("LTO", "n") == "y" circuitpython_flags.append(f"-DCIRCUITPY_ENABLE_MPY_NATIVE={1 if enable_mpy_native else 0}") circuitpython_flags.append(f"-DCIRCUITPY_FULL_BUILD={1 if full_build else 0}") - # These two are set by py/circuitpy_mpconfig.mk on the make-based ports (LOAD_ATTR_FAST_PATH - # defaults to 1, MAP_LOOKUP_CACHE to CIRCUITPY_FULL_BUILD). This port does not include that - # makefile, so they were never defined - and py/vm.c and py/map.c test them with #if, where an - # undefined identifier is 0. Both interpreter optimisations were therefore off here. circuitpython_flags.append("-DCIRCUITPY_OPT_LOAD_ATTR_FAST_PATH=1") circuitpython_flags.append(f"-DCIRCUITPY_OPT_MAP_LOOKUP_CACHE={1 if full_build else 0}") circuitpython_flags.append(f"-DCIRCUITPY_SETTINGS_TOML={1 if full_build else 0}") From 00054deb5779066fa08369d0afef38a76f0ebf07 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Mon, 24 Aug 2026 20:36:43 +0000 Subject: [PATCH 819/876] picogame: add missing function stubs for the API docs --- shared-bindings/picogame/__init__.c | 73 ++++++++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c index 84940e12a6e..e5116ceec8c 100644 --- a/shared-bindings/picogame/__init__.c +++ b/shared-bindings/picogame/__init__.c @@ -96,7 +96,41 @@ static mp_obj_t picogame_rgb565(mp_obj_t r_in, mp_obj_t g_in, mp_obj_t b_in) { } static MP_DEFINE_CONST_FUN_OBJ_3(picogame_rgb565_obj, picogame_rgb565); -// raycast(map, mw, mh, posx, posy, lrx, lry, srx, sry, sh, stride, ncols, wcolors, top, bot, col, dist) +//| def raycast( +//| map: ReadableBuffer, +//| mw: int, +//| mh: int, +//| posx: int, +//| posy: int, +//| lrx: int, +//| lry: int, +//| srx: int, +//| sry: int, +//| sh: int, +//| stride: int, +//| ncols: int, +//| wcolors: ReadableBuffer, +//| top: WriteableBuffer, +//| bot: WriteableBuffer, +//| col: WriteableBuffer, +//| dist: WriteableBuffer, +//| runs: Optional[WriteableBuffer] = None, +//| ) -> Optional[int]: +//| """Cast one frame of DDA wall rays (the compute core of the ``picogame_ray`` helper). +//| +//| ``map`` holds ``mw*mh`` wall-type bytes (0 = empty). The camera position +//| (``posx``/``posy``), the column-0 ray (``lrx``/``lry``) and the per-column ray step +//| (``srx``/``sry``) are 16.16 fixed-point; ``sh`` is the screen height and ``stride`` +//| the pixel width of one column. For each of the ``ncols`` columns the wall top/bottom +//| rows, the wall colour (near/side pairs from ``wcolors``) and the perpendicular +//| distance (16.16, into ``dist``) are written to the output buffers. +//| +//| With ``runs`` (a ``uint16`` buffer of at least ``5*ncols``, five ``ncols``-long +//| planes: x0s, x1s, tops, bots, colors) adjacent equal columns are merged into wall +//| runs for :py:meth:`Canvas.vspans` and the run count is returned; without it +//| returns ``None``.""" +//| ... +//| // C DDA wall raycaster for picogame_ray.Raycaster - INTEGER ONLY (16.16 fixed-point, no FPU; the paint, // temporal invalidate, pose-cache and billboard math stay in Python; Python does the once-per-frame // trig and passes Q16 ray params). map: read-only bytes, mw*mh wall types (0 = empty). pos*, l*x/l*y @@ -246,6 +280,25 @@ static mp_obj_t picogame_raycast(size_t n_args, const mp_obj_t *args) { } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_raycast_obj, 17, 18, picogame_raycast); +//| def road_edges( +//| rl: WriteableBuffer, +//| rr: WriteableBuffer, +//| hw: ReadableBuffer, +//| n: int, +//| cx0: int, +//| dist: int, +//| cfg: ReadableBuffer, +//| ) -> None: +//| """Compute one racing-road frame's left/right edge columns (the OutRun-style +//| ``compute_road`` loop of the ``picogame_road`` helper). +//| +//| Walks ``n`` screen rows bottom-up, accumulating the road curve, and writes the +//| left/right edge x coordinates into the ``int16`` buffers ``rl``/``rr``. +//| ``hw`` holds per-row half-widths (``int32``, 16.16), ``cx0`` is the 16.16 screen +//| centre including lateral offset, ``dist`` the integer world distance and ``cfg`` +//| seven ``int32`` curve parameters (layout documented in the shared-module core).""" +//| ... +//| // road_edges(rl, rr, hw, n, cx0, dist, cfg) - one racing-road frame's curve accumulator + integer // edges in one call (the OutRun-genre compute_road loop; core + cfg layout documented in // shared-module). rl/rr = int16 out, hw = int32 Q16 half-widths, cx0 = Q16 screen centre @@ -273,6 +326,24 @@ static mp_obj_t picogame_road_edges_fn(size_t n_args, const mp_obj_t *args) { } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_road_edges_obj, 7, 7, picogame_road_edges_fn); +//| def project( +//| cam: ReadableBuffer, +//| pts: ReadableBuffer, +//| n: int, +//| out_sx: WriteableBuffer, +//| out_sy: WriteableBuffer, +//| ) -> None: +//| """Batch-project ``n`` 3D world points to screen coordinates (the shared hot path +//| of the pseudo-3D helpers - project a box's corners, then fill triangles). +//| +//| ``cam`` holds 15 camera parameters (eye x/y/z, right x/z, up x/y/z, +//| forward x/y/z, focal, screen centre x/y, near); ``pts`` holds ``n*3`` world +//| coordinates. Screen x/y land in the ``int16`` buffers ``out_sx``/``out_sy``; +//| a point behind the near plane gets the sentinel ``-32768``. On an FPU build +//| (``picogame.FPU`` is 1) ``cam``/``pts`` are ``float32``, otherwise 16.16 +//| fixed-point ``int32``.""" +//| ... +//| // project(cam, pts, n, out_sx, out_sy) - batch perspective projection of `n` 3D points to screen. // cam = 15 camera params: ex,ey,ez, rx,rz, ux,uy,uz, fx,fy,fz, focal, cx0, cy0, near // pts = n*3 world coords (x,y,z per point) From deda1ee7b196d1845449aa306b71f43d218e85af Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 14 Aug 2026 15:43:10 -0700 Subject: [PATCH 820/876] Fix Zephyr BLE name And factor out the logic so it is shared amongst all BLE implementations. --- devices/ble_hci/common-hal/_bleio/Adapter.c | 45 +------ devices/ble_hci/common-hal/_bleio/Adapter.h | 5 + ports/espressif/common-hal/_bleio/Adapter.c | 46 ++------ ports/espressif/common-hal/_bleio/Adapter.h | 5 + ports/nordic/common-hal/_bleio/Adapter.c | 50 ++------ ports/nordic/common-hal/_bleio/Adapter.h | 5 + ports/silabs/common-hal/_bleio/Adapter.c | 43 +++---- ports/silabs/common-hal/_bleio/Adapter.h | 5 + ports/zephyr-cp/common-hal/_bleio/Adapter.c | 38 +++++- ports/zephyr-cp/common-hal/_bleio/Adapter.h | 5 + .../tests/bsim/test_bsim_ble_name.py | 110 +++++++++++++++++- shared-bindings/_bleio/Adapter.c | 43 ++++++- shared-bindings/_bleio/Adapter.h | 7 ++ shared-bindings/_bleio/Address.c | 22 +--- shared-bindings/_bleio/Address.h | 6 +- shared-module/_bleio/Address.c | 15 ++- shared-module/_bleio/Address.h | 5 +- 17 files changed, 274 insertions(+), 181 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index aaff47f42a6..abeb0824458 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -29,10 +29,6 @@ #include "shared-bindings/_bleio/ScanEntry.h" #include "shared-bindings/time/__init__.h" -#if CIRCUITPY_SETTINGS_TOML -#include "shared-bindings/os/__init__.h" -#endif - #define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION)) #define SEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000000) / (RESOLUTION)) #define UNITS_TO_SEC(TIME, RESOLUTION) (((TIME)*(RESOLUTION)) / 1000000) @@ -247,9 +243,6 @@ static void check_enabled(bleio_adapter_obj_t *adapter) { // return true; // } -// Includes trailing null. -char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0, 0}; - static void _adapter_set_name(bleio_adapter_obj_t *self, mp_obj_str_t *name_obj) { mp_buffer_info_t bufinfo; mp_get_buffer_raise(name_obj, &bufinfo, MP_BUFFER_READ); @@ -261,29 +254,7 @@ static void _adapter_set_name(bleio_adapter_obj_t *self, mp_obj_str_t *name_obj) static void bleio_adapter_hci_init(bleio_adapter_obj_t *self) { self->name = NULL; - mp_int_t name_len = 0; - - #if CIRCUITPY_SETTINGS_TOML - mp_obj_t name = common_hal_os_getenv("CIRCUITPY_BLE_NAME", mp_const_none); - if (name != mp_const_none) { - mp_arg_validate_type_string(name, MP_QSTR_CIRCUITPY_BLE_NAME); - self->name = name; - } - #endif - - if (!self->name) { - name_len = sizeof(default_ble_name) - 1; - bt_addr_t addr; - hci_check_error(hci_read_bd_addr(&addr)); - - default_ble_name[name_len - 4] = nibble_to_hex_lower[addr.val[1] >> 4 & 0xf]; - default_ble_name[name_len - 3] = nibble_to_hex_lower[addr.val[1] & 0xf]; - default_ble_name[name_len - 2] = nibble_to_hex_lower[addr.val[0] >> 4 & 0xf]; - default_ble_name[name_len - 1] = nibble_to_hex_lower[addr.val[0] & 0xf]; - // default_ble_name[name_len] will be zero. - self->name = mp_obj_new_str(default_ble_name, (uint8_t)name_len); - } - _adapter_set_name(self, self->name); + bleio_adapter_reset_name(self); // Get version information. if (hci_read_local_version(&self->hci_version, &self->hci_revision, &self->lmp_version, @@ -396,18 +367,14 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s bt_addr_t addr; hci_check_error(hci_read_bd_addr(&addr)); - bleio_address_obj_t *address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - - common_hal_bleio_address_construct(address, addr.val, BT_ADDR_LE_PUBLIC); - return address; + // The cached address is refreshed on every call. + common_hal_bleio_address_construct(&self->address, addr.val, BT_ADDR_LE_PUBLIC); + self->address.base.type = &bleio_address_type; + return &self->address; } bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { - mp_buffer_info_t bufinfo; - if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) { - return false; - } - return hci_le_set_random_address(bufinfo.buf) == HCI_OK; + return hci_le_set_random_address(address->bytes) == HCI_OK; } mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) { diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.h b/devices/ble_hci/common-hal/_bleio/Adapter.h index fda1c11d6cb..c018c676171 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.h +++ b/devices/ble_hci/common-hal/_bleio/Adapter.h @@ -11,6 +11,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" @@ -65,6 +66,10 @@ typedef struct _bleio_adapter_obj_t { // the service they belong to. This vets that. uint16_t last_added_service_handle; uint16_t last_added_characteristic_handle; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; uint16_t bleio_adapter_add_attribute(bleio_adapter_obj_t *adapter, mp_obj_t *attribute); diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index 4feb6b2b96b..681561adb2b 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -44,10 +44,6 @@ #include "esp_nimble_hci.h" #include "nvs_flash.h" -#if CIRCUITPY_SETTINGS_TOML -#include "supervisor/shared/settings.h" -#endif - // Status variables used while busy-waiting for events. static volatile bool _nimble_sync; static volatile int _connection_status; @@ -70,8 +66,6 @@ static void _on_sync(void) { // All examples have this. It'd make sense in a header. void ble_store_config_init(void); -char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0, 0, 0, 0}; - void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { const bool is_enabled = common_hal_bleio_adapter_get_enabled(self); @@ -105,27 +99,6 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable ble_svc_gatt_init(); ble_svc_ans_init(); - #if CIRCUITPY_SETTINGS_TOML - char ble_name[1 + MYNEWT_VAL_BLE_SVC_GAP_DEVICE_NAME_MAX_LENGTH]; - settings_err_t result = settings_get_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); - if (result == SETTINGS_OK) { - ble_svc_gap_device_name_set(ble_name); - } else - #endif - { - uint8_t mac[6]; - esp_read_mac(mac, ESP_MAC_BT); - mp_int_t len = sizeof(default_ble_name) - 1; - default_ble_name[len - 6] = nibble_to_hex_lower[mac[3] >> 4 & 0xf]; - default_ble_name[len - 5] = nibble_to_hex_lower[mac[3] & 0xf]; - default_ble_name[len - 4] = nibble_to_hex_lower[mac[4] >> 4 & 0xf]; - default_ble_name[len - 3] = nibble_to_hex_lower[mac[4] & 0xf]; - default_ble_name[len - 2] = nibble_to_hex_lower[mac[5] >> 4 & 0xf]; - default_ble_name[len - 1] = nibble_to_hex_lower[mac[5] & 0xf]; - default_ble_name[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings - ble_svc_gap_device_name_set(default_ble_name); - } - // Clear all of the internal connection objects. for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { bleio_connection_internal_t *connection = &bleio_connections[i]; @@ -150,6 +123,8 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable if (!_nimble_sync) { mp_raise_RuntimeError(MP_ERROR_TEXT("Update failed")); } + + bleio_adapter_reset_name(self); } else { int ret = nimble_port_stop(); while (xTaskGetHandle("nimble_host") != NULL && !mp_hal_is_interrupted()) { @@ -175,20 +150,17 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s return NULL; } - bleio_address_obj_t *address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - common_hal_bleio_address_construct(address, address_bytes, BLEIO_ADDRESS_TYPE_RANDOM_STATIC); - return address; + // The cached address is refreshed on every call. + common_hal_bleio_address_construct(&self->address, address_bytes, BLEIO_ADDRESS_TYPE_RANDOM_STATIC); + self->address.base.type = &bleio_address_type; + return &self->address; } bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { if (address->type != BLEIO_ADDRESS_TYPE_RANDOM_STATIC) { return false; } - mp_buffer_info_t bufinfo; - if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) { - return false; - } - int result = ble_hs_id_set_rnd(bufinfo.buf); + int result = ble_hs_id_set_rnd(address->bytes); return result == 0; } @@ -318,9 +290,7 @@ void common_hal_bleio_adapter_stop_scan(bleio_adapter_obj_t *self) { static void _convert_address(const bleio_address_obj_t *address, ble_addr_t *nimble_address) { nimble_address->type = address->type; - mp_buffer_info_t address_buf_info; - mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); - memcpy(nimble_address->val, (uint8_t *)address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); + memcpy(nimble_address->val, address->bytes, NUM_BLEIO_ADDRESS_BYTES); } static int _mtu_reply(uint16_t conn_handle, diff --git a/ports/espressif/common-hal/_bleio/Adapter.h b/ports/espressif/common-hal/_bleio/Adapter.h index 1dbae9946ee..605be032406 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.h +++ b/ports/espressif/common-hal/_bleio/Adapter.h @@ -11,6 +11,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" @@ -31,6 +32,10 @@ typedef struct { mp_obj_tuple_t *connection_objs; background_callback_t background_callback; bool user_advertising; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); diff --git a/ports/nordic/common-hal/_bleio/Adapter.c b/ports/nordic/common-hal/_bleio/Adapter.c index 2ca9df89710..744504b6a11 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.c +++ b/ports/nordic/common-hal/_bleio/Adapter.c @@ -32,10 +32,6 @@ #include "supervisor/usb.h" #endif -#if CIRCUITPY_SETTINGS_TOML -#include "supervisor/shared/settings.h" -#endif - #define BLE_MIN_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_MAX_CONN_INTERVAL MSEC_TO_UNITS(15, UNIT_0_625_MS) #define BLE_SLAVE_LATENCY 0 @@ -310,31 +306,6 @@ static void get_address(bleio_adapter_obj_t *self, ble_gap_addr_t *address) { check_nrf_error(sd_ble_gap_addr_get(address)); } -char default_ble_name[] = { 'C', 'I', 'R', 'C', 'U', 'I', 'T', 'P', 'Y', 0, 0, 0, 0, 0}; - -static void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { - // setup the default name - ble_gap_addr_t addr; // local_address - get_address(self, &addr); - mp_int_t len = sizeof(default_ble_name) - 1; - default_ble_name[len - 4] = nibble_to_hex_lower[addr.addr[1] >> 4 & 0xf]; - default_ble_name[len - 3] = nibble_to_hex_lower[addr.addr[1] & 0xf]; - default_ble_name[len - 2] = nibble_to_hex_lower[addr.addr[0] >> 4 & 0xf]; - default_ble_name[len - 1] = nibble_to_hex_lower[addr.addr[0] & 0xf]; - default_ble_name[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings - - #if CIRCUITPY_SETTINGS_TOML - char ble_name[32]; - - settings_err_t result = settings_get_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); - if (result == SETTINGS_OK) { - common_hal_bleio_adapter_set_name(self, ble_name); - return; - } - #endif - - common_hal_bleio_adapter_set_name(self, (char *)default_ble_name); -} static void bluetooth_adapter_background(void *data) { supervisor_bluetooth_background(); @@ -408,20 +379,19 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s ble_gap_addr_t local_address; get_address(self, &local_address); - bleio_address_obj_t *address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - - common_hal_bleio_address_construct(address, local_address.addr, local_address.addr_type); - return address; + // Return the address cached on the adapter so this can be called before + // the heap is available (e.g. from bleio_adapter_reset_name). The shared + // common_hal_bleio_address_construct() converts the raw address bytes + // into the Address object. The cached address is refreshed on every call. + common_hal_bleio_address_construct(&self->address, local_address.addr, local_address.addr_type); + self->address.base.type = &bleio_address_type; + return &self->address; } bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { ble_gap_addr_t local_address; - mp_buffer_info_t bufinfo; - if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) { - return false; - } local_address.addr_type = address->type; - memcpy(local_address.addr, bufinfo.buf, NUM_BLEIO_ADDRESS_BYTES); + memcpy(local_address.addr, address->bytes, NUM_BLEIO_ADDRESS_BYTES); return sd_ble_gap_addr_set(&local_address) == NRF_SUCCESS; } @@ -610,9 +580,7 @@ static bool connect_on_ble_evt(ble_evt_t *ble_evt, void *info_in) { static void _convert_address(const bleio_address_obj_t *address, ble_gap_addr_t *sd_address) { sd_address->addr_type = address->type; - mp_buffer_info_t address_buf_info; - mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); - memcpy(sd_address->addr, (uint8_t *)address_buf_info.buf, NUM_BLEIO_ADDRESS_BYTES); + memcpy(sd_address->addr, address->bytes, NUM_BLEIO_ADDRESS_BYTES); } mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_address_obj_t *address, mp_float_t timeout) { diff --git a/ports/nordic/common-hal/_bleio/Adapter.h b/ports/nordic/common-hal/_bleio/Adapter.h index 5bc1805d072..96be6eb4a56 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.h +++ b/ports/nordic/common-hal/_bleio/Adapter.h @@ -11,6 +11,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" @@ -38,6 +39,10 @@ typedef struct { ble_drv_evt_handler_entry_t advertising_handler_entry; background_callback_t background_callback; bool user_advertising; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); diff --git a/ports/silabs/common-hal/_bleio/Adapter.c b/ports/silabs/common-hal/_bleio/Adapter.c index 14b1dac8207..213bc43f01c 100644 --- a/ports/silabs/common-hal/_bleio/Adapter.c +++ b/ports/silabs/common-hal/_bleio/Adapter.c @@ -78,31 +78,16 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enabled) { const bool is_enabled = common_hal_bleio_adapter_get_enabled(self); - bd_addr get_address; - uint8_t address_type; uint8_t conn_index; bleio_connection_internal_t *connection; - sl_status_t sc = SL_STATUS_FAIL; - uint8_t device_name[DEVICE_NAME_LEN + 1]; - memset(device_name, 0, DEVICE_NAME_LEN); // Don't enable or disable twice if (is_enabled == enabled) { return; } - sc = sl_bt_system_get_identity_address(&get_address, &address_type); - if (SL_STATUS_OK != sc) { - mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Get address fail.")); - } - snprintf((char *)device_name, DEVICE_NAME_LEN + 1, - "CIRCUITPY-%X%X", get_address.addr[1], get_address.addr[0]); - if (enabled) { - sl_bt_gatt_server_write_attribute_value(gattdb_device_name, - 0, - DEVICE_NAME_LEN, - device_name); + bleio_adapter_reset_name(self); // Clear all of the internal connection objects. for (conn_index = 0; conn_index < BLEIO_TOTAL_CONNECTION_COUNT; conn_index++) { @@ -120,17 +105,17 @@ bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *s bd_addr get_address; uint8_t address_type; sl_status_t sc = SL_STATUS_FAIL; - bleio_address_obj_t *address; sc = sl_bt_system_get_identity_address(&get_address, &address_type); if (SL_STATUS_OK != sc) { return NULL; } - address = mp_obj_malloc(bleio_address_obj_t, &bleio_address_type); - common_hal_bleio_address_construct(address, get_address.addr, + // The cached address is refreshed on every call. + common_hal_bleio_address_construct(&self->address, get_address.addr, BLEIO_ADDRESS_TYPE_RANDOM_STATIC); - return address; + self->address.base.type = &bleio_address_type; + return &self->address; } // Set identity address @@ -138,17 +123,13 @@ bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { sl_status_t sc = SL_STATUS_FAIL; - mp_buffer_info_t bufinfo; bd_addr ble_addr; if (NULL == address) { return false; } - if (!mp_get_buffer(address->bytes, &bufinfo, MP_BUFFER_READ)) { - return false; - } - memcpy(ble_addr.addr, bufinfo.buf, 6); - sl_bt_system_set_identity_address(ble_addr, PUBLIC_ADDRESS); + memcpy(ble_addr.addr, address->bytes, 6); + sc = sl_bt_system_set_identity_address(ble_addr, PUBLIC_ADDRESS); return sc == SL_STATUS_OK; } @@ -172,9 +153,13 @@ mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self) { // Set name of the BLE adapter void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char *name) { + size_t len = strlen(name); + if (len > DEVICE_NAME_LEN) { + len = DEVICE_NAME_LEN; + } sl_bt_gatt_server_write_attribute_value(gattdb_device_name, 0, - DEVICE_NAME_LEN, + len, (const uint8_t *)name); } @@ -453,10 +438,8 @@ bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { // Convert mac address of remote device to connect static void _convert_address(const bleio_address_obj_t *address, bd_addr *sd_address, uint8_t *addr_type) { - mp_buffer_info_t address_buf_info; *addr_type = address->type; - mp_get_buffer_raise(address->bytes, &address_buf_info, MP_BUFFER_READ); - memcpy(sd_address->addr, (uint8_t *)address_buf_info.buf, 6); + memcpy(sd_address->addr, address->bytes, 6); } // Add new connection into connection list diff --git a/ports/silabs/common-hal/_bleio/Adapter.h b/ports/silabs/common-hal/_bleio/Adapter.h index d7f252df330..561785bab3f 100644 --- a/ports/silabs/common-hal/_bleio/Adapter.h +++ b/ports/silabs/common-hal/_bleio/Adapter.h @@ -29,6 +29,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" #include "supervisor/background_callback.h" @@ -54,6 +55,10 @@ typedef struct { bool user_advertising; bool is_enable; uint8_t advertising_handle; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; typedef struct { diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index ac2b1948eb7..7e51cb389fb 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -24,6 +24,7 @@ #include "shared-bindings/_bleio/Address.h" #include "shared-module/_bleio/Address.h" #include "shared-module/_bleio/ScanResults.h" +#include "supervisor/shared/bluetooth/bluetooth.h" #include "supervisor/shared/tick.h" bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; @@ -288,6 +289,18 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable // bt_finalize_init() which sets BT_DEV_READY. settings_load(); } + // Ensure a local identity exists so advertising/connections work and the + // name is stable across reboots. bt_id_create persists the identity when + // CONFIG_BT_SETTINGS is enabled. bleio_adapter_reset_name() reads the + // identity address back via common_hal_bleio_adapter_get_address(). + bt_addr_le_t id_addrs[CONFIG_BT_ID_MAX]; + size_t id_count = CONFIG_BT_ID_MAX; + bt_id_get(id_addrs, &id_count); + if (id_count == 0 || bt_addr_le_eq(&id_addrs[BT_ID_DEFAULT], BT_ADDR_LE_ANY)) { + (void)bt_id_create(NULL, NULL); + bt_id_get(id_addrs, &id_count); + } + bleio_adapter_reset_name(self); ble_adapter_enabled = true; return; } @@ -350,7 +363,25 @@ void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t t } bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { - mp_raise_NotImplementedError(NULL); + // Report the local identity address, which is the same address used to + // derive the default adapter name in common_hal_bleio_adapter_set_enabled. + bt_addr_le_t id_addrs[CONFIG_BT_ID_MAX]; + size_t id_count = CONFIG_BT_ID_MAX; + bt_id_get(id_addrs, &id_count); + if (id_count == 0 || bt_addr_le_eq(&id_addrs[BT_ID_DEFAULT], BT_ADDR_LE_ANY)) { + (void)bt_id_create(NULL, NULL); + bt_id_get(id_addrs, &id_count); + } + + const bt_addr_le_t *addr = &id_addrs[BT_ID_DEFAULT]; + // Cache the address on the adapter so this can be called before the heap + // is available (e.g. from bleio_adapter_reset_name). The shared + // common_hal_bleio_address_construct() converts the raw address bytes + // into the Address object. + common_hal_bleio_address_construct(&self->address, addr->a.val, + bleio_address_type_from_zephyr(addr)); + self->address.base.type = &bleio_address_type; + return &self->address; } bool common_hal_bleio_adapter_set_address(bleio_adapter_obj_t *self, bleio_address_obj_t *address) { @@ -590,13 +621,10 @@ mp_obj_t common_hal_bleio_adapter_connect(bleio_adapter_obj_t *self, bleio_addre const uint16_t timeout_units = bleio_validate_and_convert_timeout(timeout); - mp_buffer_info_t address_bufinfo; - mp_get_buffer_raise(address->bytes, &address_bufinfo, MP_BUFFER_READ); - bt_addr_le_t peer = { .type = bleio_address_type_to_zephyr(address->type), }; - memcpy(peer.a.val, address_bufinfo.buf, NUM_BLEIO_ADDRESS_BYTES); + memcpy(peer.a.val, address->bytes, NUM_BLEIO_ADDRESS_BYTES); struct bt_conn_le_create_param create_params = BT_CONN_LE_CREATE_PARAM_INIT( BT_CONN_LE_OPT_NONE, diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.h b/ports/zephyr-cp/common-hal/_bleio/Adapter.h index c15c698e2a5..c9cc7a03897 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.h +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.h @@ -10,6 +10,7 @@ #include "py/obj.h" #include "py/objtuple.h" +#include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/ScanResults.h" @@ -23,6 +24,10 @@ typedef struct { mp_obj_t name; mp_obj_tuple_t *connection_objs; bool user_advertising; + // Cached local address returned by common_hal_bleio_adapter_get_address(). + // Stored inline so it never needs to allocate, even when read before the + // heap is available (e.g. from bleio_adapter_reset_name). + bleio_address_obj_t address; } bleio_adapter_obj_t; void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py index c5d2edce123..b64fb2125f1 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_name.py @@ -1,24 +1,126 @@ # SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""BLE name tests for bsim.""" +"""BLE adapter name tests for bsim. + +Covers reading the default adapter name (derived from the device address), +setting a custom name and reading it back, and verifying the default name is +re-applied every time the adapter is re-enabled. +""" + +import re import pytest -BSIM_NAME_CODE = """\ +# The address prints as
in big-endian/expected order. +# The default name is "CIRCUITPY" plus the last two octets (ee, ff) concatenated +# without colons, e.g. an address of
-> "CIRCUITPYd224". +ADDRESS_RE = re.compile( + r"
" +) + +# Strip ANSI/OSC escape sequences (e.g. terminal title updates) and carriage +# returns that CircuitPython interleaves with code.py output. +_ANSI_RE = re.compile(r"\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|\x1b\[[0-9;?]*[A-Za-z]") + + +def _clean(output: str) -> str: + return _ANSI_RE.sub("", output).replace("\r", "") + + +def _expected_default_name(address_repr: str) -> str: + m = ADDRESS_RE.search(address_repr) + assert m is not None, f"unexpected address repr: {address_repr!r}" + return "CIRCUITPY" + m.group(5) + m.group(6) + + +# --- Default name is derived from the adapter address --- + +BSIM_DEFAULT_NAME_CODE = """\ +import _bleio + +adapter = _bleio.adapter +adapter.enabled = True +print("default name", adapter.name) +print("address", adapter.address) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_DEFAULT_NAME_CODE}) +def test_bsim_default_name_matches_address(bsim_phy, circuitpython): + """The default name is CIRCUITPY plus the last two address octets.""" + circuitpython.wait_until_done() + + output = _clean(circuitpython.serial.all_output) + name = re.search(r"(?m)^default name (\S+)$", output).group(1) + address_repr = re.search(r"(?m)^address (.+)$", output).group(1).strip() + + assert name == _expected_default_name(address_repr) + assert re.search(r"(?m)^done$", output) is not None + + +# --- Set a custom name and read it back --- + +BSIM_SET_NAME_CODE = """\ import _bleio adapter = _bleio.adapter adapter.enabled = True adapter.name = "CPNAME" print("name", adapter.name) +print("done") """ -@pytest.mark.circuitpy_drive({"code.py": BSIM_NAME_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_SET_NAME_CODE}) def test_bsim_set_name(bsim_phy, circuitpython): """Set the BLE name and read it back on bsim.""" circuitpython.wait_until_done() - assert "name CPNAME" in circuitpython.serial.all_output + output = _clean(circuitpython.serial.all_output) + assert re.search(r"(?m)^name CPNAME$", output) is not None + assert re.search(r"(?m)^done$", output) is not None + + +# --- Re-enabling the adapter restores the default name --- + +BSIM_NAME_RESET_ON_ENABLE_CODE = """\ +import _bleio + +adapter = _bleio.adapter + +adapter.enabled = True +print("default", adapter.name) + +adapter.name = "CUSTOM" +print("custom", adapter.name) + +# Re-enabling re-applies the default name derived from the address. +adapter.enabled = False +adapter.enabled = True +print("reset", adapter.name) +print("address", adapter.address) +print("done") +""" + + +@pytest.mark.circuitpy_drive({"code.py": BSIM_NAME_RESET_ON_ENABLE_CODE}) +def test_bsim_name_resets_on_enable(bsim_phy, circuitpython): + """Disabling and re-enabling the adapter restores the default name.""" + circuitpython.wait_until_done() + + output = _clean(circuitpython.serial.all_output) + default_name = re.search(r"(?m)^default (\S+)$", output).group(1) + assert re.search(r"(?m)^custom CUSTOM$", output) is not None + reset_name = re.search(r"(?m)^reset (\S+)$", output).group(1) + address_repr = re.search(r"(?m)^address (.+)$", output).group(1).strip() + + # The custom name is gone and the address-derived default is back. + assert reset_name != "CUSTOM" + assert reset_name == _expected_default_name(address_repr) + # The re-applied default matches the boot-time default. + assert reset_name == default_name + assert re.search(r"(?m)^done$", output) is not None diff --git a/shared-bindings/_bleio/Adapter.c b/shared-bindings/_bleio/Adapter.c index a1f81a063fd..da8537c931e 100644 --- a/shared-bindings/_bleio/Adapter.c +++ b/shared-bindings/_bleio/Adapter.c @@ -8,11 +8,16 @@ #include #include "py/objproperty.h" +#include "py/objstr.h" #include "py/runtime.h" #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Address.h" #include "shared-bindings/_bleio/Adapter.h" +#if CIRCUITPY_SETTINGS_TOML +#include "supervisor/shared/settings.h" +#endif + #define ADV_INTERVAL_MIN (0.02f) #define ADV_INTERVAL_MIN_STRING "0.02" #define ADV_INTERVAL_MAX (10.24f) @@ -134,8 +139,11 @@ MP_PROPERTY_GETSET(bleio_adapter_address_obj, //| name: str //| """name of the BLE adapter used once connected. -//| The name is "CIRCUITPY" + the last four hex digits of ``adapter.address``, -//| to make it easy to distinguish multiple CircuitPython boards.""" +//| The default name is "CIRCUITPY" plus the last four hex digits of +//| ``adapter.address``, to make it easy to distinguish multiple +//| CircuitPython boards. Set ``CIRCUITPY_BLE_NAME`` in settings.toml to +//| override it. The default is re-applied each time the adapter is +//| enabled.""" //| static mp_obj_t _bleio_adapter_get_name(mp_obj_t self) { return MP_OBJ_FROM_PTR(common_hal_bleio_adapter_get_name(self)); @@ -153,6 +161,37 @@ MP_PROPERTY_GETSET(bleio_adapter_name_obj, (mp_obj_t)&bleio_adapter_get_name_obj, (mp_obj_t)&bleio_adapter_set_name_obj); +void bleio_adapter_reset_name(bleio_adapter_obj_t *self) { + #if CIRCUITPY_SETTINGS_TOML + // Let the user override the default name from settings.toml. Use the + // allocation-free settings_get_str (not os.getenv), because ports call + // this from common_hal_bleio_adapter_set_enabled() which can run before + // the VM/gc heap is initialized. + char ble_name[32]; + settings_err_t result = settings_get_str("CIRCUITPY_BLE_NAME", ble_name, sizeof(ble_name)); + if (result == SETTINGS_OK) { + common_hal_bleio_adapter_set_name(self, ble_name); + return; + } + #endif + + // Default to "CIRCUITPY" plus the last four hex digits of the adapter + // address so multiple boards are distinguishable. The address bytes are + // little-endian, so address[0] is the least-significant byte. If the port + // cannot provide an address, fall back to the literal "CIRCUITPYxxxx". + char default_ble_name[] = "CIRCUITPYxxxx"; + bleio_address_obj_t *address = common_hal_bleio_adapter_get_address(self); + if (address != NULL) { + uint8_t addr_bytes[NUM_BLEIO_ADDRESS_BYTES]; + common_hal_bleio_address_get_bytes(address, addr_bytes); + default_ble_name[ 9] = nibble_to_hex_lower[addr_bytes[1] >> 4 & 0xf]; + default_ble_name[10] = nibble_to_hex_lower[addr_bytes[1] & 0xf]; + default_ble_name[11] = nibble_to_hex_lower[addr_bytes[0] >> 4 & 0xf]; + default_ble_name[12] = nibble_to_hex_lower[addr_bytes[0] & 0xf]; + } + common_hal_bleio_adapter_set_name(self, default_ble_name); +} + //| def start_advertising( //| self, //| data: ReadableBuffer, diff --git a/shared-bindings/_bleio/Adapter.h b/shared-bindings/_bleio/Adapter.h index 0bc6f051ff3..1035461d35a 100644 --- a/shared-bindings/_bleio/Adapter.h +++ b/shared-bindings/_bleio/Adapter.h @@ -35,6 +35,13 @@ uint16_t bleio_adapter_get_name(char *buf, uint16_t len); extern mp_obj_str_t *common_hal_bleio_adapter_get_name(bleio_adapter_obj_t *self); extern void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char *name); +// Resets the adapter's device name to the default: the CIRCUITPY_BLE_NAME setting value if +// set, otherwise "CIRCUITPY" plus the last four hex digits of the adapter's address (read via +// common_hal_bleio_adapter_get_address). Every port calls this from its +// common_hal_bleio_adapter_set_enabled once the controller is ready, so the default name is +// derived the same way everywhere. +void bleio_adapter_reset_name(bleio_adapter_obj_t *self); + // Returns 0 if ok, otherwise a BLE stack specific error code. extern uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool connectable, bool anonymous, uint32_t timeout, float interval, diff --git a/shared-bindings/_bleio/Address.c b/shared-bindings/_bleio/Address.c index 10500bec9cb..ac5c47bec8a 100644 --- a/shared-bindings/_bleio/Address.c +++ b/shared-bindings/_bleio/Address.c @@ -108,10 +108,8 @@ static mp_obj_t bleio_address_binary_op(mp_binary_op_t op, mp_obj_t lhs_in, mp_o bleio_address_obj_t *lhs = MP_OBJ_TO_PTR(lhs_in); bleio_address_obj_t *rhs = MP_OBJ_TO_PTR(rhs_in); return mp_obj_new_bool( - mp_obj_equal(common_hal_bleio_address_get_address_bytes(lhs), - common_hal_bleio_address_get_address_bytes(rhs)) && - common_hal_bleio_address_get_type(lhs) == - common_hal_bleio_address_get_type(rhs)); + lhs->type == rhs->type && + memcmp(lhs->bytes, rhs->bytes, NUM_BLEIO_ADDRESS_BYTES) == 0); } else { return mp_const_false; @@ -130,13 +128,9 @@ static mp_obj_t bleio_address_unary_op(mp_unary_op_t op, mp_obj_t self_in) { switch (op) { // Two Addresses are equal if their address bytes and address_type are equal case MP_UNARY_OP_HASH: { - mp_obj_t bytes = common_hal_bleio_address_get_address_bytes(MP_OBJ_TO_PTR(self_in)); - GET_STR_HASH(bytes, h); - if (h == 0) { - GET_STR_DATA_LEN(bytes, data, len); - h = qstr_compute_hash(data, len); - } - h ^= common_hal_bleio_address_get_type(MP_OBJ_TO_PTR(self_in)); + bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t h = (mp_int_t)qstr_compute_hash(self->bytes, NUM_BLEIO_ADDRESS_BYTES); + h ^= self->type; return MP_OBJ_NEW_SMALL_INT(h); } default: @@ -146,11 +140,7 @@ static mp_obj_t bleio_address_unary_op(mp_unary_op_t op, mp_obj_t self_in) { static void bleio_address_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { bleio_address_obj_t *self = MP_OBJ_TO_PTR(self_in); - mp_buffer_info_t buf_info; - mp_obj_t address_bytes = common_hal_bleio_address_get_address_bytes(self); - mp_get_buffer_raise(address_bytes, &buf_info, MP_BUFFER_READ); - - const uint8_t *buf = (uint8_t *)buf_info.buf; + const uint8_t *buf = self->bytes; mp_printf(print, "
", buf[5], buf[4], buf[3], buf[2], buf[1], buf[0]); } diff --git a/shared-bindings/_bleio/Address.h b/shared-bindings/_bleio/Address.h index c869ccf55cb..a61f28c0369 100644 --- a/shared-bindings/_bleio/Address.h +++ b/shared-bindings/_bleio/Address.h @@ -20,6 +20,10 @@ extern const mp_obj_type_t bleio_address_type; -extern void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type); +extern void common_hal_bleio_address_construct(bleio_address_obj_t *self, const uint8_t *bytes, uint8_t address_type); extern mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self); extern uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self); +// Copies the raw address bytes (little-endian BD_ADDR, NUM_BLEIO_ADDRESS_BYTES) +// into the given buffer. Allocation-free, so it is safe to use before the heap +// is initialized (e.g. when deriving the default adapter name). +extern void common_hal_bleio_address_get_bytes(bleio_address_obj_t *self, uint8_t bytes[NUM_BLEIO_ADDRESS_BYTES]); diff --git a/shared-module/_bleio/Address.c b/shared-module/_bleio/Address.c index b40abb3d560..5a50ba4f28f 100644 --- a/shared-module/_bleio/Address.c +++ b/shared-module/_bleio/Address.c @@ -7,17 +7,24 @@ #include -#include "py/objstr.h" +#include "py/obj.h" #include "shared-bindings/_bleio/Address.h" #include "shared-module/_bleio/Address.h" -void common_hal_bleio_address_construct(bleio_address_obj_t *self, uint8_t *bytes, uint8_t address_type) { - self->bytes = mp_obj_new_bytes(bytes, NUM_BLEIO_ADDRESS_BYTES); +void common_hal_bleio_address_construct(bleio_address_obj_t *self, const uint8_t *bytes, uint8_t address_type) { + memcpy(self->bytes, bytes, NUM_BLEIO_ADDRESS_BYTES); self->type = address_type; } mp_obj_t common_hal_bleio_address_get_address_bytes(bleio_address_obj_t *self) { - return self->bytes; + // Build a bytes object on demand. Address stores its bytes inline, so this + // is only reached from Python (e.g. ``address.address_bytes``) where the + // heap is available. + return mp_obj_new_bytes(self->bytes, NUM_BLEIO_ADDRESS_BYTES); +} + +void common_hal_bleio_address_get_bytes(bleio_address_obj_t *self, uint8_t bytes[NUM_BLEIO_ADDRESS_BYTES]) { + memcpy(bytes, self->bytes, NUM_BLEIO_ADDRESS_BYTES); } uint8_t common_hal_bleio_address_get_type(bleio_address_obj_t *self) { diff --git a/shared-module/_bleio/Address.h b/shared-module/_bleio/Address.h index 76e7a1177fc..55324770375 100644 --- a/shared-module/_bleio/Address.h +++ b/shared-module/_bleio/Address.h @@ -14,5 +14,8 @@ typedef struct { mp_obj_base_t base; uint8_t type; - mp_obj_t bytes; // a bytes() object + // Little-endian BD_ADDR order: bytes[0] is the least-significant byte. + // Stored inline so an Address can live in static storage (e.g. embedded in + // an adapter) without allocating a separate bytes object. + uint8_t bytes[NUM_BLEIO_ADDRESS_BYTES]; } bleio_address_obj_t; From c1ddc43c2d341c951aa52e6fd3e00e0ff5a5b6be Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Mon, 24 Aug 2026 21:12:06 +0000 Subject: [PATCH 821/876] ports/zephyr-cp: drop the ranges comment --- ports/zephyr-cp/boards/rpi_pico_rp2040.overlay | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay index 283debbe939..f7da2fc90ae 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay +++ b/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay @@ -2,12 +2,6 @@ /delete-node/ partitions; partitions { - /* - * Without `ranges;` the addresses below stay flash-relative: the code partition resolves - * to 0x100 instead of 0x10000100, so RP2_REQUIRES_SECOND_STAGE_BOOT is not selected (its - * Kconfig tests for 0x10000100) and the image ships without a second-stage bootloader, - * while the generated UF2 targets 0x00000100. Neither is loadable by the RP2040 boot ROM. - */ ranges; #address-cells = <1>; #size-cells = <1>; From 350efdb729ce0efd36f8ba3cb98172ab3ef794b2 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Sat, 1 Aug 2026 08:38:11 -0700 Subject: [PATCH 822/876] supervisor/web_workflow: check the listener socket calls for failure start_web_workflow() created the listening socket, bound it and called listen() without checking any of them, with an explicit "(Not checking for failures)" comment on the bind. On a port whose network stack can refuse to create a socket, the descriptor stays unset and bind() and listen() then run on -1 and fail with EBADF, but the function still returns true. The caller takes that as success and installs the background callback, so the supervisor polls a socket that was never opened and the board can hang before running code.py. Nothing is ever served, and there is no diagnostic. Observed on a Silicon Labs SiWx917-DK2605A (BRD2605A) running the zephyr-cp port, CircuitPython 10.3.0-alpha.4, where socket() returns ENOTCONN until the interface has an address: socket() ok=0 num=-1 errno=107 ENOTCONN bind port 80 -> 9 errno=9 EBADF listen -> 0 errno=9 closed=1 (returns true) Return false instead of reporting success, and close the socket if bind or listen is the step that failed. Note this is not a retry: the next attempt is the next supervisor_workflow_reset(). Bringing the workflow up once the interface acquires an address later is a separate change. This is not specific to that port. #10054 reports web workflow unreachable after a watchdog reset on several ESP32 boards, and the attempted fix in #10948 moved port 80 from closed to filtered, i.e. bound but never serving, which is the same end state this produces. Co-Authored-By: Claude Opus 5 (1M context) --- supervisor/shared/web_workflow/web_workflow.c | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/supervisor/shared/web_workflow/web_workflow.c b/supervisor/shared/web_workflow/web_workflow.c index f88e3322e23..e0c9ba45095 100644 --- a/supervisor/shared/web_workflow/web_workflow.c +++ b/supervisor/shared/web_workflow/web_workflow.c @@ -398,14 +398,33 @@ bool supervisor_start_web_workflow(void) { if (common_hal_socketpool_socket_get_closed(&listening)) { #if CIRCUITPY_SOCKETPOOL_IPV6 - socketpool_socket(&pool, SOCKETPOOL_AF_INET6, SOCKETPOOL_SOCK_STREAM, 0, &listening); + bool opened = socketpool_socket(&pool, SOCKETPOOL_AF_INET6, SOCKETPOOL_SOCK_STREAM, 0, &listening); #else - socketpool_socket(&pool, SOCKETPOOL_AF_INET, SOCKETPOOL_SOCK_STREAM, 0, &listening); + bool opened = socketpool_socket(&pool, SOCKETPOOL_AF_INET, SOCKETPOOL_SOCK_STREAM, 0, &listening); #endif + // Ports with an offloaded network stack can refuse to create a + // socket until the interface has an address (this board returns + // ENOTCONN before DHCP completes). Binding and listening on the + // unset descriptor then fails with EBADF, and reporting success + // leaves the supervisor polling a socket that was never opened. + // + // Returning false avoids that but is not a retry: the background + // callback never re-enters this function, so the next attempt is + // the next supervisor_workflow_reset(), i.e. a VM restart. A board + // that only gets an address after boot will not bring the workflow + // up on its own until then. + if (!opened) { + return false; + } common_hal_socketpool_socket_settimeout(&listening, 0); - // Bind to any ip. (Not checking for failures) - common_hal_socketpool_socket_bind(&listening, "", 0, web_api_port); - common_hal_socketpool_socket_listen(&listening, 1); + if (common_hal_socketpool_socket_bind(&listening, "", 0, web_api_port) != 0) { + common_hal_socketpool_socket_close(&listening); + return false; + } + if (!common_hal_socketpool_socket_listen(&listening, 1)) { + common_hal_socketpool_socket_close(&listening); + return false; + } } // Wake polling thread (maybe) socketpool_socket_poll_resume(); From be6ad1285d416ab184cd72fdb614dc1e32be30b8 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Fri, 14 Aug 2026 15:43:10 -0700 Subject: [PATCH 823/876] Enable BLE workflow on Zephyr This includes a few fixes: * Add sw0 as the default BOOT button * MTU support on Zephyr * Implement PacketBuffer client writes --- .gitmodules | 3 + .../Adafruit_CircuitPython_BLE_File_Transfer | 1 + .../native/native_sim/autogen_board_info.toml | 2 +- .../nrf5340bsim/autogen_board_info.toml | 2 +- .../nrf54lm20bsim/autogen_board_info.toml | 2 +- .../nrf54lm20bsim_nrf54lm20a_cpuapp.conf | 8 + .../boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf | 9 + ports/zephyr-cp/common-hal/_bleio/Adapter.c | 209 +++++++-- ports/zephyr-cp/common-hal/_bleio/Adapter.h | 4 + .../common-hal/_bleio/Characteristic.c | 27 +- .../zephyr-cp/common-hal/_bleio/Connection.c | 48 +++ .../common-hal/_bleio/PacketBuffer.c | 398 ++++++++++++++---- .../common-hal/_bleio/PacketBuffer.h | 49 ++- ports/zephyr-cp/common-hal/_bleio/Service.c | 13 +- ports/zephyr-cp/common-hal/_bleio/__init__.h | 5 + .../zephyr-cp/cptools/build_circuitpython.py | 10 +- ports/zephyr-cp/cptools/zephyr2cp.py | 25 +- ports/zephyr-cp/debug.conf | 7 + ports/zephyr-cp/prj.conf | 9 +- .../bsim/samples/observer/CMakeLists.txt | 10 + .../tests/bsim/samples/observer/prj.conf | 2 + .../tests/bsim/samples/observer/src/main.c | 28 ++ .../bsim/samples/observer/src/observer.c | 139 ++++++ .../zephyr-cp/tests/bsim/test_bsim_basics.py | 2 +- .../tests/bsim/test_bsim_ble_advertising.py | 93 +++- .../zephyr-cp/tests/bsim/test_bsim_ble_nus.py | 8 +- .../tests/bsim/test_bsim_ble_packet_buffer.py | 368 +++++++++++++++- .../tests/bsim/test_bsim_ble_pairing.py | 39 +- .../tests/bsim/test_bsim_ble_peripheral.py | 4 +- .../tests/bsim/test_bsim_ble_service.py | 7 +- .../test_bsim_ble_workflow_advertising.py | 112 +++++ .../test_bsim_ble_workflow_file_transfer.py | 102 +++++ .../tests/bsim/test_bsim_ble_workflow_nus.py | 146 +++++++ ports/zephyr-cp/tests/conftest.py | 9 + 34 files changed, 1726 insertions(+), 174 deletions(-) create mode 160000 frozen/Adafruit_CircuitPython_BLE_File_Transfer create mode 100644 ports/zephyr-cp/tests/bsim/samples/observer/CMakeLists.txt create mode 100644 ports/zephyr-cp/tests/bsim/samples/observer/prj.conf create mode 100644 ports/zephyr-cp/tests/bsim/samples/observer/src/main.c create mode 100644 ports/zephyr-cp/tests/bsim/samples/observer/src/observer.c create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_advertising.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_file_transfer.py create mode 100644 ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_nus.py diff --git a/.gitmodules b/.gitmodules index f241a4c7eae..5d544b18cce 100644 --- a/.gitmodules +++ b/.gitmodules @@ -421,3 +421,6 @@ [submodule "frozen/CircuitPython_edupico2_paj7620"] path = frozen/CircuitPython_edupico2_paj7620 url = https://github.com/CytronTechnologies/CircuitPython_edupico2_paj7620.git +[submodule "frozen/Adafruit_CircuitPython_BLE_File_Transfer"] + path = frozen/Adafruit_CircuitPython_BLE_File_Transfer + url = https://github.com/adafruit/Adafruit_CircuitPython_BLE_File_Transfer.git diff --git a/frozen/Adafruit_CircuitPython_BLE_File_Transfer b/frozen/Adafruit_CircuitPython_BLE_File_Transfer new file mode 160000 index 00000000000..14c0870bc91 --- /dev/null +++ b/frozen/Adafruit_CircuitPython_BLE_File_Transfer @@ -0,0 +1 @@ +Subproject commit 14c0870bc915aba90cf6e8a4002adeb563bc95fe diff --git a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml index 1f0486920fb..69a8dad30d8 100644 --- a/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/native_sim/autogen_board_info.toml @@ -1,5 +1,5 @@ # This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. -name = "POSIX/Native Boards Native simulator - native_sim" +name = "zephyr Native simulator - native_sim" [modules] __future__ = true diff --git a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml index dc9608542f6..47edeed3b59 100644 --- a/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf5340bsim/autogen_board_info.toml @@ -1,5 +1,5 @@ # This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. -name = "POSIX/Native Boards nRF5340 simulated boards (BabbleSim)" +name = "zephyr nRF5340 simulated boards (BabbleSim)" [modules] __future__ = true diff --git a/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml b/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml index 6a470b5906b..d1feffc835d 100644 --- a/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml +++ b/ports/zephyr-cp/boards/native/nrf54lm20bsim/autogen_board_info.toml @@ -1,5 +1,5 @@ # This file is autogenerated when a board is built. Do not edit. Do commit it to git. Other scripts use its info. -name = "POSIX/Native Boards nRF54LM20 simulated boards (BabbleSim)" +name = "zephyr nRF54LM20 simulated boards (BabbleSim)" [modules] __future__ = true diff --git a/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf b/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf index 784cb782b4d..e2a9595c2a3 100644 --- a/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf @@ -12,6 +12,14 @@ CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y # Override Kconfig default CONFIG_BT_BUF_CMD_TX_COUNT=2 +# The bsim native_sim does not drive the BLE controller ticker time-slot +# mechanism used for radio-synchronized flash operations. With the default +# SOC_FLASH_NRF_RADIO_SYNC_TICKER, flash erase/write waits on a semaphore +# that is never given, hanging for ~34s (FLASH_TIMEOUT_MS) per operation. +# Disable radio sync so flash operations run directly, matching nrf5340bsim +# (which uses an IPC-based controller and so defaults to _NONE). +CONFIG_SOC_FLASH_NRF_RADIO_SYNC_NONE=y + CONFIG_TRACING=y CONFIG_TRACING_PERFETTO=y CONFIG_TRACING_SYNC=y diff --git a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf index e6749ae6399..19f8cea27a2 100644 --- a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf @@ -1 +1,10 @@ CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y + +# Work around a latent bug in soc_flash_nrf_ticker.c: with the default +# NRF_RRAM_WRITE_BUFFER_SIZE=1, FLASH_SLOT_WRITE (500 us) < +# FLASH_SYNC_SWITCHING_TIME (1700 us), so `interval = duration - +# FLASH_SYNC_SWITCHING_TIME` underflows and the next flash slot is scheduled +# ~71 minutes out. Any write larger than a single 16-byte slot then times out +# (-ETIMEDOUT / -116), e.g. persisting bond keys right after pairing. +# See zephyr/tests/boards/nrf/rram/overlay-radio_sync.conf. +CONFIG_NRF_RRAM_WRITE_BUFFER_SIZE=32 diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.c b/ports/zephyr-cp/common-hal/_bleio/Adapter.c index ac2b1948eb7..25b00cbcb4c 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.c +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -20,18 +21,41 @@ #include "py/runtime.h" #include "bindings/zephyr_kernel/__init__.h" #include "shared-bindings/_bleio/__init__.h" +#include "common-hal/_bleio/__init__.h" #include "shared-bindings/_bleio/Adapter.h" #include "shared-bindings/_bleio/Address.h" #include "shared-module/_bleio/Address.h" #include "shared-module/_bleio/ScanResults.h" +#include "supervisor/background_callback.h" +#include "supervisor/shared/bluetooth/bluetooth.h" #include "supervisor/shared/tick.h" bleio_connection_internal_t bleio_connections[BLEIO_TOTAL_CONNECTION_COUNT]; +// Background pump: drains the BLE file-transfer / serial PacketBuffers by +// calling supervisor_bluetooth_background(). Queued from GATT write callbacks +// and connection events so the VM processes incoming data promptly. +static background_callback_t bluetooth_background_cb = {NULL, NULL}; + +static void bluetooth_adapter_background(void *data) { + (void)data; + supervisor_bluetooth_background(); +} + +void bleio_request_bluetooth_background(void) { + if (bluetooth_background_cb.fun != NULL) { + background_callback_add_core(&bluetooth_background_cb); + } +} + static bool scan_callbacks_registered = false; static bleio_scanresults_obj_t *active_scan_results = NULL; static struct bt_le_scan_cb scan_callbacks; static bool ble_advertising = false; +// True when advertising was started by the BLE workflow (supervisor) rather +// than user code. Lets the workflow restart its own adverts without disturbing +// user-initiated advertising. +static bool ble_advertising_internal = false; static bool ble_adapter_enabled = true; #define BLEIO_ADV_MAX_FIELDS 16 @@ -142,27 +166,65 @@ static void bleio_connection_release(bleio_connection_internal_t *connection, ui common_hal_bleio_adapter_obj.connection_objs = NULL; } +// Per-connection ATT MTU exchange parameters. The params struct must persist +// until the exchange callback fires, so it lives for the lifetime of the slot. +static struct bt_gatt_exchange_params mtu_exchange_params[BLEIO_TOTAL_CONNECTION_COUNT]; + +static void on_mtu_exchanged(struct bt_conn *conn, uint8_t err, + struct bt_gatt_exchange_params *params) { + (void)conn; + (void)params; + if (err == 0) { + // Wake the workflow so outgoing_packet_length is recomputed with the + // now-larger negotiated MTU. + bleio_request_bluetooth_background(); + } +} + static void bleio_connected_cb(struct bt_conn *conn, uint8_t err) { if (err != 0) { return; } - if (bleio_connection_track(conn) == NULL) { + bleio_connection_internal_t *connection = bleio_connection_track(conn); + if (connection == NULL) { bt_conn_disconnect(conn, BT_HCI_ERR_CONN_LIMIT_EXCEEDED); return; } + // Initiate an ATT MTU exchange so the negotiated MTU reflects the larger + // payload our stack supports (CONFIG_BT_L2CAP_TX_MTU). Many centrals do + // this themselves, but if they don't we'd be stuck at the default 23-byte + // MTU (20-byte payload). That forces the file-transfer workflow to split + // protocol messages across notifications in ways peers can't reassemble + // (e.g. a listdir_entry whose second fragment begins with a 0x00 flags + // byte is misread as "unknown command 0x00"). bt_gatt_exchange_mtu returns + // -EALREADY if the peer already initiated, so this is safe either way. + size_t idx = (size_t)(connection - bleio_connections); + mtu_exchange_params[idx].func = on_mtu_exchanged; + int mtu_err = bt_gatt_exchange_mtu(conn, &mtu_exchange_params[idx]); + (void)mtu_err; + // When connectable advertising results in a connection, the controller // auto-stops advertising. Clear our flag to match (we cannot call // stop_advertising() here because this callback runs in Zephyr's BT // thread context). ble_advertising = false; + ble_advertising_internal = false; common_hal_bleio_adapter_obj.connection_objs = NULL; + + // Pump the workflow once now, and arm the recurring background callback + // so future GATT writes / events get drained by the VM. + bluetooth_background_cb.fun = bluetooth_adapter_background; + bluetooth_background_cb.data = NULL; + bluetooth_adapter_background(NULL); } static void bleio_disconnected_cb(struct bt_conn *conn, uint8_t reason) { + bleio_connection_discovery_abort(); bleio_connection_release(bleio_connection_find_by_conn(conn), reason); + bleio_request_bluetooth_background(); } static void bleio_security_changed_cb(struct bt_conn *conn, bt_security_t level, @@ -240,7 +302,7 @@ static size_t bleio_parse_adv_data(const uint8_t *raw, size_t raw_len, struct bt if (offset + field_len + 1 > raw_len || count >= out_len || storage_offset + data_len > storage_len) { - mp_raise_ValueError(MP_ERROR_TEXT("Invalid advertising data")); + return 0; } uint8_t type = raw[offset + 1]; memcpy(storage + storage_offset, raw + offset + 2, data_len); @@ -328,13 +390,15 @@ mp_int_t common_hal_bleio_adapter_get_tx_power(bleio_adapter_obj_t *self) { return power; } -void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { +// Non-raising variant of common_hal_bleio_adapter_set_tx_power for use from the +// BLE workflow, which runs outside the VM. Returns 0 on success. +static int bleio_adapter_set_tx_power_noraise(mp_int_t tx_power) { struct bt_hci_cp_vs_write_tx_power_level *cp; struct net_buf *buf, *rsp = NULL; buf = bt_hci_cmd_alloc(K_MSEC(3000)); if (!buf) { - mp_raise_msg(&mp_type_MemoryError, NULL); + return -ENOMEM; } cp = net_buf_add(buf, sizeof(*cp)); cp->handle_type = BT_HCI_VS_LL_HANDLE_TYPE_ADV; @@ -343,10 +407,18 @@ void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t t int err = bt_hci_cmd_send_sync(BT_HCI_OP_VS_WRITE_TX_POWER_LEVEL, buf, &rsp); if (err) { - raise_zephyr_error(err); + return err; } net_buf_unref(rsp); + return 0; +} + +void common_hal_bleio_adapter_set_tx_power(bleio_adapter_obj_t *self, mp_int_t tx_power) { + int err = bleio_adapter_set_tx_power_noraise(tx_power); + if (err) { + raise_zephyr_error(err); + } } bleio_address_obj_t *common_hal_bleio_adapter_get_address(bleio_adapter_obj_t *self) { @@ -380,25 +452,31 @@ void common_hal_bleio_adapter_set_name(bleio_adapter_obj_t *self, const char *na } } -void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, - bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, - mp_buffer_info_t *advertising_data_bufinfo, - mp_buffer_info_t *scan_response_data_bufinfo, +// Internal start_advertising used by the BLE workflow (file transfer + serial +// services). Runs outside the VM, so it must not raise. Returns 0 on success or +// a positive errno on failure. A timeout of 0 means advertise indefinitely. +// This is the core implementation; common_hal_bleio_adapter_start_advertising() +// delegates here and translates errors into exceptions. +uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, + bool connectable, bool anonymous, uint32_t timeout, float interval, + const uint8_t *advertising_data, uint16_t advertising_data_len, + const uint8_t *scan_response_data, uint16_t scan_response_data_len, mp_int_t tx_power, const bleio_address_obj_t *directed_to) { (void)directed_to; (void)interval; + (void)anonymous; + (void)timeout; - if (advertising_data_bufinfo->len > BLEIO_ADV_MAX_DATA_LEN || - scan_response_data_bufinfo->len > BLEIO_ADV_MAX_DATA_LEN) { - mp_raise_NotImplementedError(NULL); - } - - if (timeout != 0) { - mp_raise_NotImplementedError(NULL); + if (advertising_data_len > BLEIO_ADV_MAX_DATA_LEN || + scan_response_data_len > BLEIO_ADV_MAX_DATA_LEN) { + return (uint32_t)EINVAL; } + // Don't disturb advertising that is already active (either user code or the + // workflow's own previous advert). The caller is responsible for stopping + // first if a restart is desired. if (ble_advertising) { - raise_zephyr_error(-EALREADY); + return (uint32_t)EBUSY; } bt_addr_le_t id_addrs[CONFIG_BT_ID_MAX]; @@ -407,30 +485,31 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, if (id_count == 0 || bt_addr_le_eq(&id_addrs[BT_ID_DEFAULT], BT_ADDR_LE_ANY)) { int id = bt_id_create(NULL, NULL); if (id < 0) { - printk("Failed to create identity address: %d\n", id); - raise_zephyr_error(id); + return (uint32_t)(-id); } } - size_t adv_count = bleio_parse_adv_data(advertising_data_bufinfo->buf, - advertising_data_bufinfo->len, + size_t adv_count = bleio_parse_adv_data(advertising_data, + advertising_data_len, adv_data, BLEIO_ADV_MAX_FIELDS, adv_data_storage, sizeof(adv_data_storage)); + if (adv_count == 0) { + return (uint32_t)EINVAL; + } size_t scan_resp_count = 0; - if (scan_response_data_bufinfo->len > 0) { - scan_resp_count = bleio_parse_adv_data(scan_response_data_bufinfo->buf, - scan_response_data_bufinfo->len, + if (scan_response_data_len > 0) { + scan_resp_count = bleio_parse_adv_data(scan_response_data, + scan_response_data_len, scan_resp_data, BLEIO_ADV_MAX_FIELDS, scan_resp_storage, sizeof(scan_resp_storage)); - } - - if (anonymous) { - mp_raise_NotImplementedError(NULL); + if (scan_resp_count == 0) { + return (uint32_t)EINVAL; + } } struct bt_le_adv_param adv_params; @@ -454,15 +533,75 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, NULL); } - common_hal_bleio_adapter_set_tx_power(self, tx_power); + // Best-effort TX power: the vendor HCI command may not exist on all + // controllers, so ignore failures here. + (void)bleio_adapter_set_tx_power_noraise(tx_power); - raise_zephyr_error(bt_le_adv_start(&adv_params, + int err = bt_le_adv_start(&adv_params, adv_data, adv_count, scan_resp_count > 0 ? scan_resp_data : NULL, - scan_resp_count)); + scan_resp_count); + if (err) { + return (uint32_t)(-err); + } ble_advertising = true; + // Default to workflow-owned; the public wrapper overrides this for user code. + ble_advertising_internal = true; + return 0; +} + +void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, + bool connectable, bool anonymous, uint32_t timeout, mp_float_t interval, + mp_buffer_info_t *advertising_data_bufinfo, + mp_buffer_info_t *scan_response_data_bufinfo, + mp_int_t tx_power, const bleio_address_obj_t *directed_to) { + (void)directed_to; + (void)interval; + + if (advertising_data_bufinfo->len > BLEIO_ADV_MAX_DATA_LEN || + scan_response_data_bufinfo->len > BLEIO_ADV_MAX_DATA_LEN) { + mp_raise_ValueError(MP_ERROR_TEXT("Data too large for advertisement packet")); + } + + if (timeout != 0) { + mp_raise_NotImplementedError(NULL); + } + + if (anonymous) { + mp_raise_NotImplementedError(NULL); + } + + if (ble_advertising) { + if (!ble_advertising_internal) { + // User code is already advertising. + raise_zephyr_error(-EALREADY); + } + // The workflow is advertising. Stop it so user code can take over. + common_hal_bleio_adapter_stop_advertising(self); + } + + uint32_t status = _common_hal_bleio_adapter_start_advertising(self, + connectable, + anonymous, + timeout, + interval, + advertising_data_bufinfo->buf, + advertising_data_bufinfo->len, + scan_response_data_bufinfo->buf, + scan_response_data_bufinfo->len, + tx_power, + directed_to); + if (status == (uint32_t)EINVAL) { + mp_raise_ValueError(MP_ERROR_TEXT("Invalid advertising data")); + } + if (status != 0) { + raise_zephyr_error(-(int)status); + } + + // Mark as user-owned so the workflow won't clobber it. + ble_advertising_internal = false; } void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { @@ -472,6 +611,7 @@ void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { } bt_le_adv_stop(); ble_advertising = false; + ble_advertising_internal = false; } bool common_hal_bleio_adapter_get_advertising(bleio_adapter_obj_t *self) { @@ -513,7 +653,11 @@ mp_obj_t common_hal_bleio_adapter_start_scan(bleio_adapter_obj_t *self, uint8_t struct bt_le_scan_param scan_params = { .type = active ? BT_LE_SCAN_TYPE_ACTIVE : BT_LE_SCAN_TYPE_PASSIVE, - .options = BT_LE_SCAN_OPT_FILTER_DUPLICATE, + /* Do not filter duplicates: the application merges advertisement and + * scan-response packets and needs to observe updated advertisements + * from the same device (e.g. when user code replaces the workflow + * advert). */ + .options = 0, .interval = interval_units, .window = window_units, .timeout = (uint16_t)timeout_units, @@ -737,6 +881,7 @@ void bleio_adapter_reset(bleio_adapter_obj_t *adapter) { adapter->connection_objs = NULL; active_scan_results = NULL; ble_advertising = false; + ble_advertising_internal = false; ble_adapter_enabled = bt_is_ready(); } diff --git a/ports/zephyr-cp/common-hal/_bleio/Adapter.h b/ports/zephyr-cp/common-hal/_bleio/Adapter.h index c15c698e2a5..d7411d2950e 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Adapter.h +++ b/ports/zephyr-cp/common-hal/_bleio/Adapter.h @@ -27,3 +27,7 @@ typedef struct { void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); void bleio_adapter_reset(bleio_adapter_obj_t *adapter); + +// Queue a background run of supervisor_bluetooth_background() so the VM drains +// incoming BLE PacketBuffer data. Safe to call from Zephyr BT/workqueue context. +void bleio_request_bluetooth_background(void); diff --git a/ports/zephyr-cp/common-hal/_bleio/Characteristic.c b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c index af315f9f6b0..e1ba8b7349f 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Characteristic.c +++ b/ports/zephyr-cp/common-hal/_bleio/Characteristic.c @@ -12,6 +12,7 @@ #include #include "py/runtime.h" +#include "py/gc.h" #include "bindings/zephyr_kernel/__init__.h" #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" @@ -95,6 +96,7 @@ uint16_t bleio_security_to_zephyr_perm( ssize_t bleio_char_read_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { bleio_characteristic_obj_t *self = attr->user_data; + (void)conn; return bt_gatt_attr_read(conn, attr, buf, len, offset, self->current_value, self->current_value_len); } @@ -103,6 +105,7 @@ ssize_t bleio_char_write_cb(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) { bleio_characteristic_obj_t *self = attr->user_data; + (void)flags; if (offset + len > self->max_length) { return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET); } @@ -134,6 +137,9 @@ bleio_characteristic_properties_t common_hal_bleio_characteristic_get_properties } mp_obj_tuple_t *common_hal_bleio_characteristic_get_descriptors(bleio_characteristic_obj_t *self) { + if (self->descriptor_list == NULL) { + return mp_const_empty_tuple; + } return mp_obj_new_tuple(self->descriptor_list->len, self->descriptor_list->items); } @@ -189,10 +195,18 @@ void common_hal_bleio_characteristic_construct(bleio_characteristic_obj_t *self, self->max_length = max_length; self->fixed_length = fixed_length; self->observer = mp_const_none; - self->descriptor_list = mp_obj_new_list(0, NULL); + // The descriptor list is an mp_obj (GC object). When constructed before + // gc_init() (e.g. the BLE workflow at boot), the GC heap isn't available, + // so leave it NULL and lazily create it on first use. Matches the nordic + // port's handling. + if (gc_alloc_possible()) { + self->descriptor_list = mp_obj_new_list(0, NULL); + } else { + self->descriptor_list = NULL; + } // Allocate value buffer - self->current_value = m_malloc(max_length); + self->current_value = port_malloc(max_length, false); memset(self->current_value, 0, max_length); self->current_value_alloc = max_length; self->current_value_len = 0; @@ -247,6 +261,12 @@ bool common_hal_bleio_characteristic_deinited(bleio_characteristic_obj_t *self) void common_hal_bleio_characteristic_deinit(bleio_characteristic_obj_t *self) { // Nothing to do - service handles unregistration + if (self->current_value != NULL) { + port_free(self->current_value); + self->current_value = NULL; + self->current_value_alloc = 0; + self->current_value_len = 0; + } } // Struct for tracking GATT notification subscriptions on remote characteristics. @@ -374,6 +394,9 @@ void common_hal_bleio_characteristic_set_value(bleio_characteristic_obj_t *self, void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t *self, bleio_descriptor_obj_t *descriptor) { + if (self->descriptor_list == NULL) { + self->descriptor_list = mp_obj_new_list(0, NULL); + } mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list), MP_OBJ_FROM_PTR(descriptor)); // Descriptors added after characteristic construction would need diff --git a/ports/zephyr-cp/common-hal/_bleio/Connection.c b/ports/zephyr-cp/common-hal/_bleio/Connection.c index 8381fe28a24..77942728a5f 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Connection.c +++ b/ports/zephyr-cp/common-hal/_bleio/Connection.c @@ -77,6 +77,18 @@ static discovery_context_t *active_discovery_ctx; static sys_slist_t discovered_list; static struct bt_gatt_discover_params discovery_params; +// Called from the disconnect callback (BT workqueue context) to abort any +// in-flight GATT discovery. Without this the main thread's spin loop would +// hang waiting for a callback that will never come, and the caller would then +// NULL-dereference the now-cleared connection in bt_gatt_discover(). +void bleio_connection_discovery_abort(void) { + discovery_context_t *ctx = active_discovery_ctx; + if (ctx != NULL) { + ctx->err = -ENOTCONN; + ctx->done = true; + } +} + static uint8_t on_service_discovered(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { @@ -152,6 +164,8 @@ typedef struct { // Forward declaration for use by descriptor discovery. static void free_discovered_list(void); +static void bleio_discovery_check_connected(struct bt_conn *conn, + discovery_context_t *ctx); // Callback for descriptor discovery. static uint8_t on_descriptor_discovered(struct bt_conn *conn, @@ -237,6 +251,8 @@ static void create_descriptors_from_discovered(bleio_characteristic_obj_t *chara static void discover_descriptors_for_characteristic(struct bt_conn *conn, discovery_context_t *ctx, bleio_characteristic_obj_t *characteristic, uint16_t end_handle) { + // Bail cleanly if the link dropped before this phase began. + bleio_discovery_check_connected(conn, ctx); uint16_t start = characteristic->handle + 1; if (start > end_handle) { return; @@ -266,6 +282,9 @@ static void discover_descriptors_for_characteristic(struct bt_conn *conn, RUN_BACKGROUND_TASKS; } + // The link may have dropped while we were waiting. + bleio_discovery_check_connected(conn, ctx); + create_descriptors_from_discovered(characteristic); } @@ -332,9 +351,25 @@ static void free_discovered_list(void) { } } +// The link dropped during discovery: the disconnect callback cleared +// connection->conn (so a subsequent bt_gatt_discover() would NULL-deref, since +// CONFIG_ASSERT is off) and/or aborted the active discovery (ctx->err set). +// Stop discovery cleanly with a "Not connected" exception instead of +// crashing or hanging on the spin loop. +static void bleio_discovery_check_connected(struct bt_conn *conn, + discovery_context_t *ctx) { + if (conn == NULL || ctx->err != 0) { + free_discovered_list(); + active_discovery_ctx = NULL; + mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Not connected")); + } +} + // Discover characteristics for a single remote service. static void discover_characteristics_for_service(struct bt_conn *conn, discovery_context_t *ctx, bleio_service_obj_t *service) { + // Bail cleanly if the link dropped before this phase began. + bleio_discovery_check_connected(conn, ctx); // Need at least 2 handles: one for the service declaration, one for a characteristic if (service->end_handle <= service->start_handle) { return; @@ -365,6 +400,9 @@ static void discover_characteristics_for_service(struct bt_conn *conn, RUN_BACKGROUND_TASKS; } + // The link may have dropped while we were waiting. + bleio_discovery_check_connected(conn, ctx); + // Create CP objects outside of callback context where MP allocations are safe. // This drains and frees the list nodes. char_with_decl_t chars[16]; @@ -576,6 +614,9 @@ mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_conne while (!ctx.done) { RUN_BACKGROUND_TASKS; } + + // The link may have dropped during primary discovery. + bleio_discovery_check_connected(connection->conn, &ctx); } else { mp_obj_iter_buf_t iter_buf; mp_obj_t iterable = mp_getiter(service_uuids_whitelist, &iter_buf); @@ -618,6 +659,10 @@ mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_conne while (!ctx.done) { RUN_BACKGROUND_TASKS; } + + // The link may have dropped during this UUID's discovery; stop + // before the next iteration clears ctx.err and crashes on a NULL conn. + bleio_discovery_check_connected(connection->conn, &ctx); } } @@ -640,6 +685,9 @@ mp_obj_tuple_t *common_hal_bleio_connection_discover_remote_services(bleio_conne for (size_t i = 0; i < result_list->len; i++) { bleio_service_obj_t *svc = MP_OBJ_TO_PTR(result_list->items[i]); if (svc->start_handle < svc->end_handle) { + // discover_characteristics_for_service re-checks, but guard here + // too so we don't enter the phase after a mid-loop disconnect. + bleio_discovery_check_connected(connection->conn, &ctx); discover_characteristics_for_service(connection->conn, &ctx, svc); } } diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c index 02e593fabfe..8cdb5fcae76 100644 --- a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.c @@ -19,19 +19,26 @@ #include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Connection.h" #include "shared-bindings/_bleio/PacketBuffer.h" +#include "shared-bindings/microcontroller/__init__.h" #include "supervisor/shared/tick.h" +#include "supervisor/port_heap.h" #include "common-hal/_bleio/Characteristic.h" #include "common-hal/_bleio/PacketBuffer.h" +#include "common-hal/_bleio/Adapter.h" +#include "common-hal/_bleio/Connection.h" +#include "common-hal/_bleio/__init__.h" +#include "bindings/zephyr_kernel/__init__.h" // Zephyr's ring_buf is safe for single-producer/single-consumer without -// locks. The GATT callbacks (system workqueue) are the sole producer; -// the CircuitPython VM (main thread) is the sole consumer. +// locks. The GATT callbacks (system workqueue) are the sole producer of +// incoming data; the CircuitPython VM (main thread) is the sole consumer. // Forward declarations. static bool conn_is_valid(bleio_packet_buffer_obj_t *self); -static bool send_pending(bleio_packet_buffer_obj_t *self); +static void packet_buffer_send_work_handler(struct k_work *work); +static void notify_complete_cb(struct bt_conn *conn, void *user_data); // Called from Zephyr GATT callbacks (system workqueue context). // Wraps incoming data with a uint16_t length prefix and pushes into ringbuf. @@ -82,6 +89,9 @@ void bleio_packet_buffer_extend(bleio_packet_buffer_obj_t *self, ring_buf_put(&self->ringbuf, (uint8_t *)&packet_len, sizeof(uint16_t)); ring_buf_put(&self->ringbuf, data, len); + + // Wake the VM background task so it drains the ring buffer promptly. + bleio_request_bluetooth_background(); } void bleio_packet_buffer_set_conn(bleio_packet_buffer_obj_t *self, @@ -89,14 +99,6 @@ void bleio_packet_buffer_set_conn(bleio_packet_buffer_obj_t *self, self->conn = conn; } -// Completion callback for bt_gatt_notify_cb — called when the PDU has been -// sent (or the buffer freed). Drains any accumulated pending data. -static void notify_complete_cb(struct bt_conn *conn, void *user_data) { - bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *)user_data; - self->packet_queued = false; - send_pending(self); -} - // Returns true if the tracked connection is still connected. // Clears self->conn if the connection is stale. static bool conn_is_valid(bleio_packet_buffer_obj_t *self) { @@ -112,88 +114,139 @@ static bool conn_is_valid(bleio_packet_buffer_obj_t *self) { return true; } -// Send the pending outgoing buffer via GATT notify. -// Returns true if sent successfully (or terminal failure). -static bool send_pending(bleio_packet_buffer_obj_t *self) { - if (self->pending_size == 0) { - return true; +// Completion callback for bt_gatt_notify_cb. Runs on the system workqueue (per +// the Zephyr bt_gatt_notify_cb contract) — the same context send_work runs in +// — so packet_queued is single-threaded here and needs no lock. +static void notify_complete_cb(struct bt_conn *conn, void *user_data) { + (void)conn; + bleio_packet_buffer_obj_t *self = (bleio_packet_buffer_obj_t *)user_data; + self->packet_queued = false; + // Drain the other buffer now that this notify is done. K_NO_WAIT runs + // send_work immediately, cancelling any pending delayed retry. + k_work_reschedule(&self->send_work, K_NO_WAIT); +} + +// The deferred sender. Runs only on the system workqueue (submitted by the VM +// on write/flush and by notify_complete_cb on completion). It is the sole +// caller of bt_gatt_notify_cb, so packet_queued / pending_index / pending_size +// are touched here and in the VM's brief critical section — nowhere else. +static void packet_buffer_send_work_handler(struct k_work *work) { + bleio_packet_buffer_obj_t *self = CONTAINER_OF( + k_work_delayable_from_work(work), bleio_packet_buffer_obj_t, send_work); + + // A notification is awaiting its completion callback; it will resubmit us. + if (self->packet_queued) { + return; } - if (self->characteristic == NULL || - self->characteristic->service == NULL || - self->characteristic->service->is_remote) { - self->pending_size = 0; - return true; + if (self->pending_size == 0) { + return; // nothing staged } + // Server-side notify path only; clients write directly. characteristic is + // NULL after deinit, so bail before touching it (a completion callback can + // resubmit us after teardown). bleio_characteristic_obj_t *c = self->characteristic; - if (!(c->props & CHAR_PROP_NOTIFY) || !c->service->registered) { + if (c == NULL || self->client) { + return; + } + if (!conn_is_valid(self)) { + // Stale connection: drop everything staged. self->pending_size = 0; - return true; + self->packet_queued = false; + return; } + // Staging keeps pending_size <= the negotiated ATT MTU payload, so the + // whole staged packet fits in one notification. struct bt_gatt_notify_params params = { .attr = &c->service->attrs[c->value_attr_index], - .data = self->outgoing_buffer, + .data = self->outgoing[self->pending_index], .len = self->pending_size, .func = notify_complete_cb, .user_data = self, }; - // If the tracked connection is stale, clear it. - conn_is_valid(self); - int err = bt_gatt_notify_cb(self->conn, ¶ms); if (err == 0) { - self->pending_size = 0; + // Accepted by the controller; the payload was copied into a PDU and + // will go out at the next connection event. Hand this buffer off and + // let the VM fill the other one while it's in flight. self->packet_queued = true; - return true; + self->pending_size = 0; + self->pending_index ^= 1; // VM fills the other buffer next + return; } if (err == -ENOTCONN) { - // Peer disconnected — clear tracking, discard pending. + // Peer disconnected — discard everything pending and cancel any + // pending delayed retry. (We're here only when packet_queued is clear, + // so no in-flight completion is owed.) self->conn = NULL; self->pending_size = 0; - return true; + self->packet_queued = false; + k_work_cancel_delayable(&self->send_work); + return; } - // -ENOMEM (no TX buffer) — leave pending, caller will retry. - return false; + // -ENOMEM / -EAGAIN: no ATT TX buffer right now. The ATT TX pool is shared + // across all ATT traffic on all connections, so it can be full from other + // notifies/indications/responses even when we have nothing in flight. + // Running on the workqueue makes the allocator use K_NO_WAIT: it returns + // NULL and the stack returns -ENOMEM *before* copying or queueing a PDU — + // nothing sent, nothing dropped; the bytes are still in + // outgoing[pending_index]. Leave the data staged and reschedule ourselves + // after a short delay so we retry even when the VM is idle (no write/flush + // to drive us). The delay — not an immediate resubmit — keeps the workqueue + // from busy-looping against a full pool. + k_work_reschedule(&self->send_work, K_MSEC(2)); } -void common_hal_bleio_packet_buffer_construct( - bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, - size_t buffer_size, size_t max_packet_size) { +// Shared core for both the Python-facing (allocating) and workflow +// (caller-supplied static buffer) constructors. Wires the ring buffer, the two +// outgoing buffers, the characteristic observer, and (for client-side) CCCD +// subscription. No GC heap allocation happens here. +static void packet_buffer_init_common(bleio_packet_buffer_obj_t *self, + bleio_characteristic_obj_t *characteristic, + uint8_t *ringbuf_data, size_t ringbuf_size, bool owns_ringbuf_data, + uint8_t *outgoing0, uint8_t *outgoing1, + bool owns_outgoing0, bool owns_outgoing1, + size_t max_packet_size) { self->characteristic = characteristic; self->timeout_ms = 0; self->max_packet_size = max_packet_size; self->conn = NULL; self->client = (characteristic->service != NULL && characteristic->service->is_remote); + self->outgoing[0] = outgoing0; + self->outgoing[1] = outgoing1; + self->owns_outgoing[0] = owns_outgoing0; + self->owns_outgoing[1] = owns_outgoing1; + self->pending_index = 0; self->pending_size = 0; self->packet_queued = false; - // Allocate ring buffer: buffer_size packets, each with 2-byte length prefix - self->ringbuf_size = buffer_size * (sizeof(uint16_t) + max_packet_size); - self->ringbuf_data = m_malloc_without_collect(self->ringbuf_size); - ring_buf_init(&self->ringbuf, self->ringbuf_size, self->ringbuf_data); - - // Allocate outgoing buffer for pending writes - bleio_characteristic_properties_t props = - common_hal_bleio_characteristic_get_properties(characteristic); - if (self->client) { - // Client-side: we write to remote characteristic - self->outgoing_buffer = m_malloc_without_collect(max_packet_size); + self->ringbuf_data = ringbuf_data; + self->ringbuf_size = ringbuf_size; + self->owns_ringbuf_data = owns_ringbuf_data; + if (ringbuf_data != NULL && ringbuf_size > 0) { + ring_buf_init(&self->ringbuf, ringbuf_size, ringbuf_data); } else { - // Server-side: we notify via local characteristic - if (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { - self->outgoing_buffer = m_malloc_without_collect(max_packet_size); - } else { - self->outgoing_buffer = NULL; - } + // No incoming buffer (e.g. a server-side NOTIFY-only characteristic). + ring_buf_init(&self->ringbuf, 0, NULL); } - // Set ourselves as the characteristic's observer + // The deferred sender drives server-side notifications. Client-side writes + // go out synchronously and never schedule it, but initializing it always is + // harmless and keeps flush()/deinit() simple. + k_work_init_delayable(&self->send_work, packet_buffer_send_work_handler); + + // Set ourselves as the characteristic's observer so GATT write/notify + // callbacks push incoming data into our ring buffer. bleio_characteristic_set_observer(characteristic, MP_OBJ_FROM_PTR(self)); - // For client-side characteristics with NOTIFY/INDICATE, subscribe to notifications + bleio_characteristic_properties_t props = + common_hal_bleio_characteristic_get_properties(characteristic); + + // For client-side characteristics with NOTIFY/INDICATE, subscribe to + // notifications from the remote peer. if (self->client && (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE))) { bool do_notify = (props & CHAR_PROP_NOTIFY) != 0; bool do_indicate = (props & CHAR_PROP_INDICATE) != 0; @@ -201,21 +254,91 @@ void common_hal_bleio_packet_buffer_construct( } } -// Allocation-free version for BLE workflow use (not yet implemented for Zephyr). +void common_hal_bleio_packet_buffer_construct( + bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, + size_t buffer_size, size_t max_packet_size) { + + bleio_characteristic_properties_t props = + common_hal_bleio_characteristic_get_properties(characteristic); + bool client = (characteristic->service != NULL && characteristic->service->is_remote); + + // Allocate ring buffer: buffer_size packets, each with 2-byte length prefix + size_t ringbuf_size = buffer_size * (sizeof(uint16_t) + max_packet_size); + uint8_t *ringbuf_data = port_malloc(ringbuf_size, false); + + // Allocate outgoing buffers. Client-side writes go out directly and only + // need one scratch buffer. Server-side notifications ping-pong between two + // buffers so the VM can fill one while the other is in flight. + uint8_t *outgoing0 = NULL; + uint8_t *outgoing1 = NULL; + bool owns0 = false; + bool owns1 = false; + if (client) { + outgoing0 = port_malloc(max_packet_size, false); + owns0 = true; + } else if (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { + outgoing0 = port_malloc(max_packet_size, false); + outgoing1 = port_malloc(max_packet_size, false); + owns0 = true; + owns1 = true; + } + + packet_buffer_init_common(self, characteristic, + ringbuf_data, ringbuf_size, true, + outgoing0, outgoing1, owns0, owns1, + max_packet_size); +} + +// Allocation-free version for BLE workflow use. The caller supplies static +// buffers so this can run before gc_init() without touching the GC heap. +// outgoing_buffer1 -> outgoing[0], outgoing_buffer2 -> outgoing[1]. void _common_hal_bleio_packet_buffer_construct( bleio_packet_buffer_obj_t *self, bleio_characteristic_obj_t *characteristic, uint32_t *incoming_buffer, size_t incoming_buffer_size, uint32_t *outgoing_buffer1, uint32_t *outgoing_buffer2, size_t max_packet_size, ble_event_handler_t *static_handler_entry) { - (void)self; - (void)characteristic; - (void)incoming_buffer; - (void)incoming_buffer_size; - (void)outgoing_buffer1; - (void)outgoing_buffer2; - (void)max_packet_size; (void)static_handler_entry; - mp_raise_NotImplementedError(NULL); + + uint8_t *ringbuf_data = (uint8_t *)incoming_buffer; + size_t ringbuf_size = incoming_buffer_size; + + bleio_characteristic_properties_t props = + common_hal_bleio_characteristic_get_properties(characteristic); + bool client = (characteristic->service != NULL && characteristic->service->is_remote); + + uint8_t *outgoing0 = NULL; + uint8_t *outgoing1 = NULL; + bool owns0 = false; + bool owns1 = false; + + if (client) { + // Client-side: one scratch buffer for synchronous writes. + if (outgoing_buffer1 != NULL) { + outgoing0 = (uint8_t *)outgoing_buffer1; + } else { + outgoing0 = port_malloc(max_packet_size, false); + owns0 = true; + } + } else if (props & (CHAR_PROP_NOTIFY | CHAR_PROP_INDICATE)) { + // Server-side: two buffers to ping-pong between. + if (outgoing_buffer1 != NULL) { + outgoing0 = (uint8_t *)outgoing_buffer1; + } else { + outgoing0 = port_malloc(max_packet_size, false); + owns0 = true; + } + if (outgoing_buffer2 != NULL) { + outgoing1 = (uint8_t *)outgoing_buffer2; + } else { + outgoing1 = port_malloc(max_packet_size, false); + owns1 = true; + } + } + + packet_buffer_init_common(self, characteristic, + ringbuf_data, ringbuf_size, false, + outgoing0, outgoing1, owns0, owns1, + max_packet_size); } mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self, @@ -261,7 +384,7 @@ mp_int_t common_hal_bleio_packet_buffer_readinto(bleio_packet_buffer_obj_t *self mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, const uint8_t *data, size_t len, uint8_t *header, size_t header_len) { - if (self->outgoing_buffer == NULL) { + if (self->outgoing[0] == NULL) { mp_raise_bleio_BluetoothError(MP_ERROR_TEXT("Writes not supported on Characteristic")); } @@ -283,33 +406,98 @@ mp_int_t common_hal_bleio_packet_buffer_write(bleio_packet_buffer_obj_t *self, MP_QSTR_max_packet_size); } - // If no room to append, wait until pending is sent. - if (len + self->pending_size > (size_t)outgoing_packet_length) { + // Client-side (remote characteristic): write the request directly to the + // remote GATT server. The server-side path below stages into a double + // buffer and drains it from the system workqueue via send_work, so handle + // client writes separately (and synchronously). + if (self->characteristic != NULL && + self->characteristic->service != NULL && + self->characteristic->service->is_remote) { + bleio_characteristic_obj_t *c = self->characteristic; + bleio_connection_obj_t *connection = MP_OBJ_TO_PTR(c->service->connection); + if (connection == NULL || connection->connection == NULL || + connection->connection->conn == NULL) { + return -1; + } + struct bt_conn *conn = connection->connection->conn; + + // Combine header + data into the outgoing buffer (max_packet_size). + memcpy(self->outgoing[0], header, header_len); + memcpy(self->outgoing[0] + header_len, data, len); + size_t total = header_len + len; + + if (c->props & CHAR_PROP_WRITE_NO_RESPONSE) { + // Fire-and-forget write. Retry on transient "no TX buffer" + // (-EAGAIN) so paced protocols (e.g. BLE file transfer) don't + // silently drop data. + int err; + while ((err = bt_gatt_write_without_response(conn, c->handle, + self->outgoing[0], total, false)) == -EAGAIN) { + RUN_BACKGROUND_TASKS; + } + if (err != 0) { + raise_zephyr_error(err); + } + } else if (c->props & CHAR_PROP_WRITE) { + bleio_gattc_write_sync(conn, c->handle, self->outgoing[0], total); + } else { + // No write property; nothing to send. + return -1; + } + return (mp_int_t)total; + } + + // Server-side notify path: stage header + data into the pending buffer, + // then hand it to send_work on the system workqueue. bt_gatt_notify_cb + // blocks (K_FOREVER) off the workqueue, so we never call it here; send_work + // does, and the completion callback paces us to one notification in flight. + // The header prefixes each packet, so it's only written when the packet is + // empty (pending_size == 0). pending_size counts bytes staged but not yet + // accepted by the controller. + + if (mp_hal_is_interrupted()) { + return -1; + } + + // If this write would overflow the current packet, wait for send_work to + // drain it (which requires the in-flight notification to complete first). + if ((size_t)len + self->pending_size > (size_t)outgoing_packet_length) { while (self->pending_size != 0 && + conn_is_valid(self) && !mp_hal_is_interrupted()) { + k_work_reschedule(&self->send_work, K_NO_WAIT); RUN_BACKGROUND_TASKS; } } - if (mp_hal_is_interrupted()) { + if (!conn_is_valid(self) || mp_hal_is_interrupted()) { return -1; } size_t num_bytes_written = 0; - if (self->pending_size == 0) { - memcpy(self->outgoing_buffer, header, header_len); - self->pending_size += header_len; - num_bytes_written += header_len; + // send_work (system workqueue) may preempt us and modify pending_index / + // pending_size / packet_queued, so guard the append. + common_hal_mcu_disable_interrupts(); + { + uint8_t *pending = self->outgoing[self->pending_index]; + if (self->pending_size == 0 && header_len > 0) { + memcpy(pending, header, header_len); + self->pending_size += header_len; + num_bytes_written += header_len; + } + memcpy(pending + self->pending_size, data, len); + self->pending_size += len; + num_bytes_written += len; } - memcpy(self->outgoing_buffer + self->pending_size, data, len); - self->pending_size += len; - num_bytes_written += len; + common_hal_mcu_enable_interrupts(); - // Send immediately if no write is queued. + // If no notification is in flight, kick the deferred sender to drain what + // we just staged (K_NO_WAIT runs it immediately, cancelling any pending + // delayed retry). If one is in flight, its completion will resubmit. if (!self->packet_queued) { - send_pending(self); + k_work_reschedule(&self->send_work, K_NO_WAIT); } - return num_bytes_written; + return (mp_int_t)num_bytes_written; } mp_int_t common_hal_bleio_packet_buffer_get_incoming_packet_length( @@ -345,24 +533,39 @@ mp_int_t common_hal_bleio_packet_buffer_get_outgoing_packet_length( !self->characteristic->service->is_remote && (common_hal_bleio_characteristic_get_properties(self->characteristic) & (CHAR_PROP_INDICATE | CHAR_PROP_NOTIFY))) { - // We are sending to a client via NOTIFY/INDICATE. - // Use max_packet_size since we don't track MTU dynamically here. - return MIN(self->max_packet_size, self->characteristic->max_length); + // We are sending to a client via NOTIFY/INDICATE. The maximum payload + // per packet is bounded by the negotiated ATT MTU (ATT_MTU - 3 for the + // opcode and handle in a Handle Value Notification PDU). Without a + // current connection we can't know the MTU, so return -1 to signal + // that writes aren't possible yet. + if (!conn_is_valid(self)) { + return -1; + } + uint16_t mtu = bt_gatt_get_mtu(self->conn); + if (mtu < 3) { + return -1; + } + mp_int_t mtu_payload = (mp_int_t)mtu - 3; + return MIN(MIN(mtu_payload, (mp_int_t)self->max_packet_size), + (mp_int_t)self->characteristic->max_length); } // Writing to remote characteristic or local without NOTIFY return MIN(self->characteristic->max_length, self->max_packet_size); } void common_hal_bleio_packet_buffer_flush(bleio_packet_buffer_obj_t *self) { - // With the completion callback, writes drain automatically. - // flush() just waits for any queued data to be sent. - while (self->pending_size > 0 && + // Wait until everything written has been handed to the controller AND its + // completion has fired (we pace to one notification in flight at a time). + // send_work runs on the system workqueue, which is higher priority than + // this thread, so k_work_reschedule(K_NO_WAIT) lets it preempt us; + // RUN_BACKGROUND_TASKS advances simulated time / lets completion callbacks + // fire so packet_queued clears. For client-side writes (synchronous) there + // is nothing pending, so this returns immediately. + while ((self->pending_size != 0 || self->packet_queued) && + conn_is_valid(self) && !mp_hal_is_interrupted()) { + k_work_reschedule(&self->send_work, K_NO_WAIT); RUN_BACKGROUND_TASKS; - if (!send_pending(self)) { - // Couldn't send — wait and retry. - RUN_BACKGROUND_TASKS; - } } } @@ -376,12 +579,21 @@ void common_hal_bleio_packet_buffer_deinit(bleio_packet_buffer_obj_t *self) { } bleio_characteristic_clear_observer(self->characteristic); self->characteristic = NULL; - // Free ringbuf_data allocated with m_malloc_without_collect - m_free(self->ringbuf_data); + // Cancel any pending delayed retry so it can't fire after we free the + // buffers (or after the object is gone). + k_work_cancel_delayable(&self->send_work); + // Free buffers if we own them (port_malloc'd). The BLE workflow path + // supplies static buffers that must not be freed. + if (self->owns_ringbuf_data && self->ringbuf_data != NULL) { + port_free(self->ringbuf_data); + } self->ringbuf_data = NULL; - // Free outgoing buffer - m_free(self->outgoing_buffer); - self->outgoing_buffer = NULL; + for (int i = 0; i < 2; i++) { + if (self->owns_outgoing[i] && self->outgoing[i] != NULL) { + port_free(self->outgoing[i]); + } + self->outgoing[i] = NULL; + } } bool common_hal_bleio_packet_buffer_connected(bleio_packet_buffer_obj_t *self) { diff --git a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h index 491852ec5fd..67216775257 100644 --- a/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h +++ b/ports/zephyr-cp/common-hal/_bleio/PacketBuffer.h @@ -9,6 +9,7 @@ #include +#include #include #include "py/obj.h" @@ -22,16 +23,50 @@ typedef struct { mp_obj_base_t base; bleio_characteristic_obj_t *characteristic; uint32_t timeout_ms; + // Store the connection we are talking to. We expect to talk over a single + // connection at a time. + struct bt_conn *conn; + bool client; + // The current MTU negotiated with the active connection. + size_t max_packet_size; + + // ringbuf to store incoming packets. struct ring_buf ringbuf; uint8_t *ringbuf_data; size_t ringbuf_size; - size_t max_packet_size; - // Outgoing pending buffer - uint8_t *outgoing_buffer; - uint16_t pending_size; - bool packet_queued; - struct bt_conn *conn; - bool client; + + // Outgoing path. Two fixed buffers alternate so the VM can keep filling one + // while the other is in flight with the controller. + // + // outgoing[pending_index] is the buffer the VM is filling (pending_size + // bytes staged, not yet sent). packet_queued means a notification has been + // accepted by the controller and its completion callback hasn't fired yet + // — at most one is in flight at a time. + // + uint8_t *outgoing[2]; + uint8_t pending_index; // which buffer the VM is filling + volatile uint16_t pending_size; // bytes staged in outgoing[pending_index] + volatile bool packet_queued; // a notification is in flight + + // send_work is a delayable work item, the only caller of bt_gatt_notify_cb + // (that API blocks (K_FOREVER) off the workqueue but returns -ENOMEM from + // it). It's rescheduled with K_NO_WAIT to drain after a write/completion, + // and with a short delay on -ENOMEM so it self-retries even when the VM is + // idle and the shared ATT TX pool is full from other traffic. It and the + // completion callback both run on the workqueue (serialized with each + // other); the VM is the only other toucher of these fields and guards its + // read-modify-write with common_hal_mcu_disable_interrupts() (the workqueue + // preempts the VM, so the critical section keeps it out while we append). + // bt_gatt_notify_cb copies the payload into a PDU on success, so the source + // buffer may be reused once the call returns 0; the completion callback + // paces us to one in flight and makes flush() accurate. + struct k_work_delayable send_work; + + // Ownership: true if the buffer was port_malloc'd and should be freed in + // deinit; false if it is a caller-supplied static buffer (the BLE workflow + // path, which runs before gc_init()). + bool owns_ringbuf_data; + bool owns_outgoing[2]; } bleio_packet_buffer_obj_t; // Called from GATT callbacks (system workqueue context) to push diff --git a/ports/zephyr-cp/common-hal/_bleio/Service.c b/ports/zephyr-cp/common-hal/_bleio/Service.c index ee8cf35deee..5f0c7ee268b 100644 --- a/ports/zephyr-cp/common-hal/_bleio/Service.c +++ b/ports/zephyr-cp/common-hal/_bleio/Service.c @@ -25,6 +25,7 @@ #include "py/gc.h" #include "py/runtime.h" +#include "supervisor/port_heap.h" #include "bindings/zephyr_kernel/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Service.h" @@ -52,8 +53,8 @@ static void service_ensure_capacity(bleio_service_obj_t *self, size_t needed) { while (new_capacity < self->attr_count + needed) { new_capacity *= 2; } - struct bt_gatt_attr *new_attrs = m_realloc(self->attrs, - new_capacity * sizeof(struct bt_gatt_attr)); + struct bt_gatt_attr *new_attrs = port_realloc(self->attrs, + new_capacity * sizeof(struct bt_gatt_attr), false); self->attrs = new_attrs; self->attr_capacity = new_capacity; } @@ -75,7 +76,7 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, // Allocate attrs array self->attr_capacity = INITIAL_ATTR_CAPACITY; - self->attrs = m_malloc(self->attr_capacity * sizeof(struct bt_gatt_attr)); + self->attrs = port_malloc(self->attr_capacity * sizeof(struct bt_gatt_attr), false); memset(self->attrs, 0, self->attr_capacity * sizeof(struct bt_gatt_attr)); self->attr_count = 0; @@ -105,6 +106,12 @@ void common_hal_bleio_service_deinit(bleio_service_obj_t *self) { bt_gatt_service_unregister(&self->zephyr_service); self->registered = false; } + if (self->attrs != NULL) { + port_free(self->attrs); + self->attrs = NULL; + self->attr_capacity = 0; + self->attr_count = 0; + } } void common_hal_bleio_service_from_remote_service(bleio_service_obj_t *self, diff --git a/ports/zephyr-cp/common-hal/_bleio/__init__.h b/ports/zephyr-cp/common-hal/_bleio/__init__.h index 63eec415311..72dc249d142 100644 --- a/ports/zephyr-cp/common-hal/_bleio/__init__.h +++ b/ports/zephyr-cp/common-hal/_bleio/__init__.h @@ -40,3 +40,8 @@ size_t bleio_gattc_read_sync(struct bt_conn *conn, uint16_t handle, uint8_t *buf, size_t len); void bleio_gattc_write_sync(struct bt_conn *conn, uint16_t handle, const uint8_t *data, size_t len); + +// Abort any in-flight remote GATT discovery; called from the disconnect +// callback so discover_remote_services() fails cleanly instead of hanging +// or NULL-dereferencing the cleared connection. +void bleio_connection_discovery_abort(void); diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 55c069a1ddc..150a5d81266 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -479,8 +479,16 @@ async def build_circuitpython(): # noqa: C901 supervisor_source = [pathlib.Path(p) for p in supervisor_source] supervisor_source.extend(board_info["source_files"]) supervisor_source.extend(top.glob("supervisor/shared/*.c")) - if "_bleio" in enabled_modules: + ble_workflow_enabled = "_bleio" in enabled_modules + if ble_workflow_enabled: supervisor_source.append(top / "supervisor/shared/bluetooth/bluetooth.c") + # BLE workflow = file transfer + serial services, matching other ports. + supervisor_source.append(top / "supervisor/shared/bluetooth/file_transfer.c") + supervisor_source.append(top / "supervisor/shared/bluetooth/serial.c") + circuitpython_flags.append(f"-DCIRCUITPY_BLE_FILE_SERVICE={1 if ble_workflow_enabled else 0}") + circuitpython_flags.append( + f"-DCIRCUITPY_BLE_SERIAL_SERVICE={1 if ble_workflow_enabled else 0}" + ) supervisor_source.append(top / "supervisor/shared/translate/translate.c") if web_workflow_enabled: supervisor_source.extend(top.glob("supervisor/shared/web_workflow/*.c")) diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index a6e2fa53cdc..9525c312111 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -585,6 +585,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig board_names = {} status_led = None status_led_inverted = False + boot_button = None path2chosen = {} chosen2path = {} @@ -730,7 +731,8 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig if "gpio-keys" in compatible: for key in node.nodes: - props = node.nodes[key].props + key_node = node.nodes[key] + props = key_node.props ioport = props["gpios"]._markers[1][2] num = int.from_bytes(props["gpios"].value[4:8], "big") @@ -745,10 +747,18 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig key_code = props["zephyr,code"].to_num() if key_code in INPUT_KEY_NAMES: board_names[(ioport, num)].append(INPUT_KEY_NAMES[key_code]) - if key in node2alias: - if "sw0" in node2alias[key]: + if key_node in node2alias: + aliases = node2alias[key_node] + if "sw0" in aliases: board_names[(ioport, num)].append("BUTTON") - board_names[(ioport, num)].extend(node2alias[key]) + # The sw0 alias designates the conventional first user + # button, so prefer it as the boot button. + boot_button = (ioport, num) + board_names[(ioport, num)].extend(aliases) + # Default to the first button in device tree order when no sw0 + # alias has designated one yet. + if boot_button is None: + boot_button = (ioport, num) if len(all_ioports) > 1: a, b = all_ioports[:2] @@ -775,6 +785,8 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig pin_object_name = f"P{ioport[len(shared_prefix) :].upper()}_{num:02d}" if status_led and (ioport, num) == status_led: status_led = pin_object_name + if boot_button and (ioport, num) == boot_button: + boot_button = pin_object_name pin_defs.append( f"const mcu_pin_obj_t pin_{pin_object_name} = {{ .base.type = &mcu_pin_type, .port = DEVICE_DT_GET(DT_NODELABEL({ioport})), .number = {num}}};" ) @@ -937,6 +949,10 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig else: status_led = "" status_led_inverted = "" + if boot_button: + boot_button = f"#define CIRCUITPY_BOOT_BUTTON (&pin_{boot_button})\n" + else: + boot_button = "" ram_list = [] ram_externs = [] max_size = 0 @@ -966,6 +982,7 @@ def zephyr_dts_to_cp_board(board_id, portdir, builddir, zephyrbuilddir, mpconfig #define CIRCUITPY_RAM_DEVICE_COUNT {len(rams)} {status_led} {status_led_inverted} +{boot_button} """ if not header.exists() or header.read_text() != new_header_content: header.write_text(new_header_content) diff --git a/ports/zephyr-cp/debug.conf b/ports/zephyr-cp/debug.conf index ab6ae95d416..2f12db119f8 100644 --- a/ports/zephyr-cp/debug.conf +++ b/ports/zephyr-cp/debug.conf @@ -13,6 +13,13 @@ CONFIG_FRAME_POINTER=y CONFIG_FLASH_LOG_LEVEL_DBG=y CONFIG_LOG_MODE_IMMEDIATE=y +# Quiet the UDC device-controller drivers in the debug build. The DWC2 driver +# logs "Prepare RX 0x%02x doeptsiz 0x%x" (LOG_INF) on every OUT endpoint RX +# prepare, which is noisy. Drop UDC_DRIVER to WRN to keep errors/warnings +# while compiling out INF/DBG. (Shared by all udc drivers; only one is active +# per board.) +CONFIG_UDC_DRIVER_LOG_LEVEL_WRN=y + # Bluetooth: enable BT host debug logging so success paths print, not just # LOG_ERR. In particular bt_keys logs "Stored keys for " (LOG_DBG) on a # successful bt_keys_store(); without this only the failure message diff --git a/ports/zephyr-cp/prj.conf b/ports/zephyr-cp/prj.conf index abefcb199b9..864af4c6112 100644 --- a/ports/zephyr-cp/prj.conf +++ b/ports/zephyr-cp/prj.conf @@ -54,8 +54,15 @@ CONFIG_FPU=y CONFIG_MBEDTLS=y -# Override Kconfig default not taking effect +# Override Kconfig default not taking effect. The BLE file-transfer workflow +# packs up to BLEIO_PACKET_BUFFER_MAX_PACKET_SIZE (512) bytes per notification, +# so the L2CAP/ATT MTU must accommodate a 512-byte payload plus the 3-byte +# ATT header (opcode + handle). Without this the default with SMP is only 65, +# and notifications larger than the negotiated MTU fail with +# "No ATT channel for MTU". +CONFIG_BT_L2CAP_TX_MTU=515 CONFIG_BT_BUF_ACL_RX_SIZE=255 +CONFIG_BT_BUF_ACL_TX_SIZE=251 CONFIG_BT_RX_STACK_SIZE=2048 CONFIG_BT_LONG_WQ_STACK_SIZE=3072 CONFIG_MBEDTLS_BUILTIN=y diff --git a/ports/zephyr-cp/tests/bsim/samples/observer/CMakeLists.txt b/ports/zephyr-cp/tests/bsim/samples/observer/CMakeLists.txt new file mode 100644 index 00000000000..59d999d7052 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/observer/CMakeLists.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(observer) + +target_sources(app PRIVATE + src/main.c + src/observer.c +) diff --git a/ports/zephyr-cp/tests/bsim/samples/observer/prj.conf b/ports/zephyr-cp/tests/bsim/samples/observer/prj.conf new file mode 100644 index 00000000000..a328b3700a9 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/observer/prj.conf @@ -0,0 +1,2 @@ +CONFIG_BT=y +CONFIG_BT_OBSERVER=y diff --git a/ports/zephyr-cp/tests/bsim/samples/observer/src/main.c b/ports/zephyr-cp/tests/bsim/samples/observer/src/main.c new file mode 100644 index 00000000000..db8ce6bab95 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/observer/src/main.c @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +int observer_start(void); + +int main(void) { + int err; + + printk("Starting Observer Demo\n"); + + /* Initialize the Bluetooth Subsystem */ + err = bt_enable(NULL); + if (err) { + printk("Bluetooth init failed (err %d)\n", err); + return 0; + } + + (void)observer_start(); + + printk("Exiting %s thread.\n", __func__); + return 0; +} diff --git a/ports/zephyr-cp/tests/bsim/samples/observer/src/observer.c b/ports/zephyr-cp/tests/bsim/samples/observer/src/observer.c new file mode 100644 index 00000000000..fc896bf593d --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/samples/observer/src/observer.c @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022 Nordic Semiconductor ASA + * Copyright (c) 2015-2016 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include + +static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, + struct net_buf_simple *ad) { + printk("Device found: %s (RSSI %d), type %u, AD data len %u\n", + bt_addr_le_str(addr), rssi, type, ad->len); +} + +#if defined(CONFIG_BT_EXT_ADV) +#define NAME_LEN 30 + +static bool data_cb(struct bt_data *data, void *user_data) { + char *name = user_data; + uint8_t len; + + switch (data->type) { + case BT_DATA_NAME_SHORTENED: + case BT_DATA_NAME_COMPLETE: + len = MIN(data->data_len, NAME_LEN - 1); + (void)memcpy(name, data->data, len); + name[len] = '\0'; + return false; + default: + return true; + } +} + +static const char *phy2str(uint8_t phy) { + switch (phy) { + case BT_GAP_LE_PHY_NONE: + return "No packets"; + case BT_GAP_LE_PHY_1M: + return "LE 1M"; + case BT_GAP_LE_PHY_2M: + return "LE 2M"; + case BT_GAP_LE_PHY_CODED: + return "LE Coded"; + default: + return "Unknown"; + } +} + +static void scan_recv(const struct bt_le_scan_recv_info *info, + struct net_buf_simple *buf) { + char name[NAME_LEN]; + uint8_t data_status; + uint16_t data_len; + + (void)memset(name, 0, sizeof(name)); + + data_len = buf->len; + bt_data_parse(buf, data_cb, name); + + data_status = BT_HCI_LE_ADV_EVT_TYPE_DATA_STATUS(info->adv_props); + + printk("[DEVICE]: %s, AD evt type %u, Tx Pwr: %i, RSSI %i " + "Data status: %u, AD data len: %u Name: %s " + "C:%u S:%u D:%u SR:%u E:%u Pri PHY: %s, Sec PHY: %s, " + "Interval: 0x%04x (%u ms), SID: %u\n", + bt_addr_le_str(info->addr), info->adv_type, info->tx_power, info->rssi, + data_status, data_len, name, + (info->adv_props & BT_GAP_ADV_PROP_CONNECTABLE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_SCANNABLE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_DIRECTED) != 0, + (info->adv_props & BT_GAP_ADV_PROP_SCAN_RESPONSE) != 0, + (info->adv_props & BT_GAP_ADV_PROP_EXT_ADV) != 0, + phy2str(info->primary_phy), phy2str(info->secondary_phy), + info->interval, info->interval * 5 / 4, info->sid); +} + +static struct bt_le_scan_cb scan_callbacks = { + .recv = scan_recv, +}; +#endif /* CONFIG_BT_EXT_ADV */ + +static int scan_start(void) { + /* 30 ms continuous active scanning. Duplicate filtering is disabled so + * that updated advertisements from the same device (e.g. when user + * code replaces the workflow advert) are reported again. + */ + struct bt_le_scan_param scan_param = { + .type = BT_LE_SCAN_TYPE_ACTIVE, + .options = 0, + .interval = BT_GAP_SCAN_FAST_INTERVAL_MIN, + .window = BT_GAP_SCAN_FAST_WINDOW, + }; + int err; + + #if defined(CONFIG_BT_EXT_ADV) + scan_param.options |= BT_LE_SCAN_OPT_CODED; + #endif /* CONFIG_BT_EXT_ADV */ + +scan_start_retry: + printk("Starting scanning...\n"); + err = bt_le_scan_start(&scan_param, device_found); + if (err) { + if ((scan_param.options & BT_LE_SCAN_OPT_CODED) != 0U) { + printk("Failed to start scanning with Coded PHY (err %d), retrying " + "without...\n", err); + + scan_param.options &= ~BT_LE_SCAN_OPT_CODED; + + goto scan_start_retry; + } + + printk("Start scanning failed (err %d)\n", err); + + return err; + } + + printk("success.\n"); + + return 0; +} + +int observer_start(void) { + int err; + + #if defined(CONFIG_BT_EXT_ADV) + bt_le_scan_cb_register(&scan_callbacks); + printk("Registered scan callbacks\n"); + #endif /* CONFIG_BT_EXT_ADV */ + + err = scan_start(); + if (err != 0) { + return err; + } + + return 0; +} diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py index 96f40a86b40..3ef22470a38 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py @@ -14,7 +14,7 @@ @pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) -@pytest.mark.duration(3) +@pytest.mark.duration(5) def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2, board): """Run two bsim instances on the same sim id and verify UART output.""" diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py index 40b74ee854a..a46c8163eca 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -77,7 +77,56 @@ """ -@pytest.mark.zephyr_sample("bluetooth/observer") +# Advertiser: primary advert carries a distinctive marker; the scan response +# carries a different marker. If the adapter merges them they'd arrive as one +# entry, but the adapter does not merge — they come as separate ScanEntry +# objects distinguished by `scan_response`. +BSIM_ADVERT_SCAN_RESPONSE_ADV_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +name = b"ADVADV" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name + +sname = b"SCANRSP" +scan_response = bytes((len(sname) + 1, 0x09)) + sname + +print("adv start") +adapter.start_advertising(advertisement, scan_response=scan_response, connectable=True) +time.sleep(10) +adapter.stop_advertising() +print("adv done") +""" + +BSIM_ADVERT_SCAN_RESPONSE_SCAN_CODE = """\ +import _bleio + +adapter = _bleio.adapter +print("scan start") +saw_primary = False +saw_scan_response = False +for entry in adapter.start_scan(active=True, timeout=12.0): + data = entry.advertisement_bytes + if b"ADVADV" in data and not entry.scan_response: + saw_primary = True + print("primary") + if b"SCANRSP" in data and entry.scan_response: + saw_scan_response = True + print("scan_response") + if saw_primary and saw_scan_response: + print("both") + break +adapter.stop_scan() +print("scan done", saw_primary, saw_scan_response) +""" + +# Disable the workflow on the advertiser so only its custom advert is on air. +BSIM_ADVERT_SCAN_RESPONSE_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + + +@pytest.mark.zephyr_sample("tests/bsim/samples/observer") @pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_CODE}) def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): """Advertise from CircuitPython and verify Zephyr observer sees traffic.""" @@ -94,7 +143,7 @@ def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): assert "AD data len 10" in observer_output -@pytest.mark.zephyr_sample("bluetooth/observer") +@pytest.mark.zephyr_sample("tests/bsim/samples/observer") @pytest.mark.code_py_runs(2) @pytest.mark.duration(25) @pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_INTERRUPT_RELOAD_CODE}) @@ -125,7 +174,8 @@ def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): assert "Already advertising" not in cp_output -@pytest.mark.zephyr_sample("bluetooth/observer") +@pytest.mark.zephyr_sample("tests/bsim/samples/observer") +@pytest.mark.duration(20) @pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_DEFAULT_CODE}) def test_bsim_tx_power_default_rssi(board, bsim_phy, circuitpython, zephyr_sample): """Verify default TX power produces expected RSSI.""" @@ -151,7 +201,8 @@ def test_bsim_tx_power_default_rssi(board, bsim_phy, circuitpython, zephyr_sampl assert all_rssi[0] == expected_rssi, f"Expected RSSI {expected_rssi}, got {all_rssi[0]}" -@pytest.mark.zephyr_sample("bluetooth/observer") +@pytest.mark.zephyr_sample("tests/bsim/samples/observer") +@pytest.mark.duration(20) @pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_LOW_CODE}) def test_bsim_tx_power_low_rssi(bsim_phy, circuitpython, zephyr_sample): """Verify low TX power reduces RSSI.""" @@ -172,3 +223,37 @@ def test_bsim_tx_power_low_rssi(bsim_phy, circuitpython, zephyr_sample): assert len(all_rssi) > 0, "Observer saw no advertisements" assert all_rssi[0] < -39, f"Expected lower RSSI with -20 dBm TX, got {all_rssi[0]}" + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_ADVERT_SCAN_RESPONSE_ADV_CODE, + "settings.toml": BSIM_ADVERT_SCAN_RESPONSE_SETTINGS, + } +) +@pytest.mark.circuitpy_drive({"code.py": BSIM_ADVERT_SCAN_RESPONSE_SCAN_CODE}) +def test_bsim_scan_response_not_merged(bsim_phy, circuitpython1, circuitpython2): + """The adapter does not merge advertisement and scan response. + + The advertiser sends a primary advert (marker "ADVADV") and a scan + response (marker "SCANRSP") as separate packets. With duplicate filtering + disabled and no merging in the adapter, the scanner observes them as two + distinct ScanEntry objects: one with scan_response=False (the primary + advert) and one with scan_response=True (the scan response). + """ + scanner = circuitpython2 + + scanner.wait_until_done() + + scanner_output = scanner.serial.all_output + assert "primary" in scanner_output, ( + f"primary advert entry not observed separately: {scanner_output}" + ) + assert "scan_response" in scanner_output, ( + f"scan response entry not observed separately: {scanner_output}" + ) + assert "both" in scanner_output, ( + f"did not observe both advert and scan response: {scanner_output}" + ) + assert "scan done True True" in scanner_output, f"scan did not confirm both: {scanner_output}" diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py index bb589cf9d90..08f93aea517 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py @@ -52,7 +52,13 @@ @pytest.mark.zephyr_sample("tests/bsim/samples/central_nus_client") @pytest.mark.duration(14) -@pytest.mark.circuitpy_drive({"code.py": BSIM_NUS_PERIPHERAL_CODE, **_ADAFRUIT_BLE}) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_NUS_PERIPHERAL_CODE, + "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n", + **_ADAFRUIT_BLE, + } +) def test_bsim_nus_peripheral(bsim_phy, circuitpython, zephyr_sample): """CP hosts NUS peripheral; Zephyr central writes to RX, reads TX notifications.""" circuitpython.wait_until_done() diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py index efda0637aa3..8cf937bd34f 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py @@ -3,6 +3,8 @@ """PacketBuffer tests for bsim.""" +import re + import pytest @@ -592,8 +594,12 @@ def test_bsim_packet_buffer_write_header(bsim_phy, circuitpython1, circuitpython # incoming_packet_length reflects the max we can receive (characteristic max_length) print("incoming", pb.incoming_packet_length) -# outgoing_packet_length is capped by max_packet_size -print("outgoing", pb.outgoing_packet_length) +# outgoing_packet_length requires a connection to know the negotiated ATT MTU, +# so without one it raises ValueError (server-side NOTIFY is MTU-bounded). +try: + print("outgoing", pb.outgoing_packet_length) +except ValueError as e: + print("outgoing valueerror", e) print("done") """ @@ -607,9 +613,9 @@ def test_bsim_packet_buffer_packet_lengths(bsim_phy, circuitpython): # Server-side local characteristic: # incoming = max_length = 20 - # outgoing = min(max_packet_size, max_length) = min(15, 20) = 15 + # outgoing requires a connection to know the ATT MTU, so it raises without one. assert "incoming 20" in output - assert "outgoing 15" in output + assert "outgoing valueerror" in output assert "done" in output @@ -759,8 +765,12 @@ def test_bsim_packet_buffer_packet_lengths(bsim_phy, circuitpython): @pytest.mark.duration(30) -@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_RECONNECT_SERVER_CODE}) -@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_RECONNECT_CLIENT_CODE}) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PB_RECONNECT_SERVER_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PB_RECONNECT_CLIENT_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) def test_bsim_packet_buffer_reconnect(bsim_phy, circuitpython1, circuitpython2): """PacketBuffer tracks conn through disconnect / reconnect.""" server = circuitpython1 @@ -783,3 +793,349 @@ def test_bsim_packet_buffer_reconnect(bsim_phy, circuitpython1, circuitpython2): assert "wrote first" in client_output assert "wrote second" in client_output + + +# ---- Test 8: outgoing_packet_length bounded by negotiated MTU ---- +# +# Regression test for the "No ATT channel for MTU" bug. The server-side +# PacketBuffer's outgoing_packet_length must be bounded by the negotiated +# ATT MTU (ATT_MTU - 3), not just max_packet_size. Without that bounding, +# the workflow packs a notification larger than the MTU and bt_gatt_notify_cb +# fails silently ("No ATT channel for MTU"), so the client never receives it. +# +# The characteristic is configured with max_length=600 and max_packet_size=600, +# deliberately larger than any plausible negotiated ATT MTU (the stack supports +# up to CONFIG_BT_L2CAP_TX_MTU = 515, payload 512). So without the fix, +# outgoing_packet_length returns 600 and the 600-byte notification always +# exceeds the MTU and is dropped — regardless of whether an MTU exchange +# happened. With the fix, outgoing_packet_length is ATT_MTU - 3 (≤ 512) and the +# notification fits and is delivered. + +BSIM_PB_MTU_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.NO_ACCESS, + write_perm=_bleio.Attribute.OPEN, + max_length=600, fixed_length=False, +) + +# max_packet_size deliberately larger than any negotiated ATT MTU so that an +# unbounded outgoing_packet_length always produces an oversized, undeliverable +# notification regardless of MTU-exchange timing. +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=600) +print("service created") + +name = b"CPPBMT" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +# Wait for the client to subscribe (CCCD write) and send a trigger write. +data = bytearray(600) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) +print("trigger", data[:n]) + +# The negotiated ATT MTU determines the largest notification payload. The +# connection's max_packet_length is ATT_MTU - 3. +conn = adapter.connections[0] +mtu_payload = conn.max_packet_length +print("mtu_payload", mtu_payload) + +# outgoing_packet_length must be bounded by the MTU, not max_packet_size. +opl = pb.outgoing_packet_length +print("outgoing", opl) + +# Send a response sized exactly to outgoing_packet_length, like the BLE +# file-transfer workflow does. With the fix this fits the MTU and is delivered. +response = bytes([0xAA]) * opl +pb.write(response) +print("sent", len(response)) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_MTU_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBMT" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +remote_char = services[0].characteristics[0] +print("found char, props", remote_char.properties) + +# Creating a client-side PacketBuffer on a NOTIFY characteristic writes the +# CCCD to subscribe, which gives the server a connection to notify. +client_pb = _bleio.PacketBuffer(remote_char, buffer_size=4, max_packet_size=600) +print("subscribed") + +# Trigger the server's response with a direct write. +remote_char.value = b"GO" +print("wrote trigger") + +# Read the notification response. Without the MTU fix the server sends an +# oversized notification that the ATT layer drops, so this times out. +buf = bytearray(600) +n = 0 +deadline = time.monotonic() + 5.0 +while n == 0 and time.monotonic() < deadline: + n = client_pb.readinto(buf) + if n == 0: + time.sleep(0.05) +if n > 0: + print("received_ok", n, bytes(buf[:n])) +else: + print("received_none") + +time.sleep(0.5) +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_MTU_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_MTU_CLIENT_CODE}) +def test_bsim_packet_buffer_outgoing_mtu_bounded(bsim_phy, circuitpython1, circuitpython2): + """Server-side outgoing_packet_length is bounded by the negotiated ATT MTU. + + Without the fix, outgoing_packet_length returns max_packet_size (200) and + the resulting notification exceeds the bsim default ATT MTU (23), so the + ATT layer drops it ("No ATT channel for MTU") and the client receives + nothing. With the fix, outgoing_packet_length is ATT_MTU - 3 (20) and the + notification is delivered to the client. + """ + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + assert "service created" in server_output + assert "connected True" in server_output + assert "trigger" in server_output + + # outgoing_packet_length must not exceed the connection's MTU-derived + # max_packet_length. Without the fix this is 200 vs 20. + mtu_match = re.search(r"mtu_payload (\d+)", server_output) + outgoing_match = re.search(r"outgoing (\d+)", server_output) + assert mtu_match is not None, f"mtu_payload not printed: {server_output}" + assert outgoing_match is not None, f"outgoing not printed: {server_output}" + mtu_payload = int(mtu_match.group(1)) + outgoing = int(outgoing_match.group(1)) + assert outgoing <= mtu_payload, ( + f"outgoing_packet_length {outgoing} exceeds MTU payload {mtu_payload}; " + "notifications this size would be dropped by the ATT layer" + ) + assert outgoing < 600, f"outgoing_packet_length {outgoing} not bounded below max_packet_size" + + # The notification sized to outgoing_packet_length must actually arrive. + assert "received_ok" in client_output, ( + f"client never received the notification (MTU-bound bug): {client_output}" + ) + assert "received_none" not in client_output + + received_match = re.search(r"received_ok (\d+)", client_output) + assert received_match is not None + received = int(received_match.group(1)) + assert received == outgoing, f"client received {received} bytes, server sent {outgoing}" + + +# ---- Test: client-side PacketBuffer write (remote WRITE_NO_RESPONSE) ---- +# +# Covers the client-side write path in common_hal_bleio_packet_buffer_write +# (the is_remote branch): a CP central wraps a remote characteristic in a +# _bleio.PacketBuffer and writes to it via pb.write(...), which must reach the +# peripheral's server-side PacketBuffer. This mirrors how the BLE file-transfer +# library sends commands (raw.write). It also exercises the header+data combine +# in the client write path via pb.write(data, header=...). +# +# The characteristic uses WRITE_NO_RESPONSE | NOTIFY with open permissions, so +# no pairing is required and the test runs on both bsim boards. + +BSIM_PB_CLIENT_WRITE_SERVER_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +svc = _bleio.Service(_bleio.UUID(0xFFE0)) +char = _bleio.Characteristic.add_to_service( + svc, _bleio.UUID(0xFFE1), + properties=_bleio.Characteristic.WRITE_NO_RESPONSE | _bleio.Characteristic.NOTIFY, + read_perm=_bleio.Attribute.OPEN, + write_perm=_bleio.Attribute.OPEN, + max_length=20, fixed_length=False, +) + +# Server-side PacketBuffer: reads incoming WRITE_NO_RESPONSE, echoes via NOTIFY. +pb = _bleio.PacketBuffer(char, buffer_size=4, max_packet_size=20) +print("service created") + +name = b"CPPBCW" +advertisement = bytes((2, 0x01, 0x06, len(name) + 1, 0x09)) + name +adapter.start_advertising(advertisement, connectable=True) +print("advertising") + +for _ in range(80): + if adapter.connected: + break + time.sleep(0.1) +print("connected", adapter.connected) + +data = bytearray(20) +for _ in range(2): + n = 0 + deadline = time.monotonic() + 5.0 + while n == 0 and time.monotonic() < deadline: + n = pb.readinto(data) + if n == 0: + time.sleep(0.05) + print("received", bytes(data[:n])) + # Echo the packet straight back over NOTIFY. + pb.write(bytes(data[:n])) + print("echoed", bytes(data[:n])) + +for _ in range(80): + if not adapter.connected: + break + time.sleep(0.1) +print("done") +""" + +BSIM_PB_CLIENT_WRITE_CLIENT_CODE = """\ +import _bleio +import time + +adapter = _bleio.adapter + +target = None +for entry in adapter.start_scan(timeout=6.0, active=True): + if entry.connectable and b"CPPBCW" in entry.advertisement_bytes: + target = entry.address + print("found server") + break +adapter.stop_scan() + +connection = adapter.connect(target, timeout=5.0) +print("connected", connection.connected) + +services = connection.discover_remote_services([_bleio.UUID(0xFFE0)]) +print("discovered services", len(services)) + +remote_char = services[0].characteristics[0] +print("found char, props", remote_char.properties) + +# Client-side PacketBuffer on the remote characteristic: subscribes to NOTIFY +# (readinto) and writes to the remote (pb.write -> client-side write path). +cpb = _bleio.PacketBuffer(remote_char, buffer_size=4, max_packet_size=20) + +# Write 1: plain write (no header) — exercises bt_gatt_write_without_response. +cpb.write(b"PING") +print("wrote ping") + +# Write 2: write with a header — exercises the header+data combine in the +# client write path. "B" + "ODY" is sent as a single "BODY" packet. +cpb.write(b"ODY", header=b"B") +print("wrote body with header") + +# Read both NOTIFY echoes back. +buf = bytearray(20) +for _ in range(2): + n = 0 + deadline = time.monotonic() + 5.0 + while n == 0 and time.monotonic() < deadline: + n = cpb.readinto(buf) + if n == 0: + time.sleep(0.05) + print("client received", bytes(buf[:n])) + +connection.disconnect() + +timeout = time.monotonic() + 4.0 +while connection.connected and time.monotonic() < timeout: + time.sleep(0.1) +print("done") +""" + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_WRITE_SERVER_CODE}) +@pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_WRITE_CLIENT_CODE}) +def test_bsim_packet_buffer_client_write(bsim_phy, circuitpython1, circuitpython2): + """A CP central writes to a remote characteristic via a client-side + PacketBuffer (pb.write), and the peripheral echoes it back over NOTIFY. + + Covers the client-side write path (remote WRITE_NO_RESPONSE), including the + header+data combine, mirroring how the BLE file-transfer library sends + commands. + """ + server = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + server.wait_until_done() + + server_output = server.serial.all_output + client_output = client.serial.all_output + + # Server received both client writes (plain + header-combined). + assert "received b'PING'" in server_output, ( + f"server never received the plain client write: {server_output}" + ) + assert "received b'BODY'" in server_output, ( + f"server never received the header-combined client write: {server_output}" + ) + assert "echoed b'PING'" in server_output + assert "echoed b'BODY'" in server_output + assert "done" in server_output + + # Client wrote both and got both echoes back over NOTIFY. + assert "wrote ping" in client_output, f"client plain write did not complete: {client_output}" + assert "wrote body with header" in client_output, ( + f"client header write did not complete: {client_output}" + ) + # Be vague here because PING and BODY may be in separate packets or merged. + assert "b'PING" in client_output, f"client never received the PING echo: {client_output}" + assert "BODY'" in client_output, f"client never received the BODY echo: {client_output}" + assert "done" in client_output diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py index 75f6875ee2e..850b2fc8957 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_pairing.py @@ -1,14 +1,10 @@ # SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries # SPDX-License-Identifier: MIT -"""BLE pairing tests for nrf5340bsim.""" +"""BLE pairing tests for the bsim boards.""" import pytest -# nrf54lm20bsim LE encryption is not yet functional in bsim. Enable it when it -# does. Real hardware works. -pytestmark = pytest.mark.circuitpython_board("native_nrf5340bsim") - BSIM_PERIPHERAL_CODE = """\ import _bleio import time @@ -93,9 +89,13 @@ @pytest.mark.duration(22) -@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) -@pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_CODE}) -def test_bsim_pairing_cp_to_cp(bsim_phy, circuitpython1, circuitpython2): +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PERIPHERAL_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CENTRAL_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +def test_bsim_pairing_cp_to_cp(bsim_phy, board, circuitpython1, circuitpython2): """Two CP instances: device 0 peripheral, device 1 central pairs to it.""" peripheral = circuitpython1 central = circuitpython2 @@ -160,9 +160,16 @@ def test_bsim_pairing_cp_to_cp(bsim_phy, circuitpython1, circuitpython2): @pytest.mark.duration(22) -@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) -@pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_PAIRED_PROPERTY_CODE}) -def test_bsim_pairing_paired_property(bsim_phy, circuitpython1, circuitpython2): +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PERIPHERAL_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +@pytest.mark.circuitpy_drive( + { + "code.py": BSIM_CENTRAL_PAIRED_PROPERTY_CODE, + "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n", + } +) +def test_bsim_pairing_paired_property(bsim_phy, board, circuitpython1, circuitpython2): """Verify connection.paired transitions from False to True after pairing.""" peripheral = circuitpython1 central = circuitpython2 @@ -309,9 +316,13 @@ def test_bsim_pairing_paired_property(bsim_phy, circuitpython1, circuitpython2): @pytest.mark.duration(35) -@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_BOND_CODE}) -@pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_BOND_CODE}) -def test_bsim_bonding_persistence(bsim_phy, circuitpython1, circuitpython2): +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PERIPHERAL_BOND_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_CENTRAL_BOND_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) +def test_bsim_bonding_persistence(bsim_phy, board, circuitpython1, circuitpython2): """Verify bonds are saved to storage and survive disconnect/reconnect. Central pairs with peripheral, disconnects, then reconnects. diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py index 89088fb9f87..a8eb2612b40 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py @@ -73,7 +73,9 @@ @pytest.mark.zephyr_sample("bluetooth/central") @pytest.mark.duration(14) -@pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) +@pytest.mark.circuitpy_drive( + {"code.py": BSIM_PERIPHERAL_CODE, "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n"} +) def test_bsim_peripheral_zephyr_central(bsim_phy, circuitpython, zephyr_sample): """Advertise as connectable from CP; Zephyr central connects and disconnects.""" central = zephyr_sample diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py index eb83c016b3a..8d19dc4d97b 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py @@ -84,7 +84,12 @@ class HeartRateService(Service): @pytest.mark.zephyr_sample("tests/bsim/samples/central_battery_client") @pytest.mark.duration(14) @pytest.mark.circuitpy_drive( - {"code.py": BSIM_SERVICE_CODE, "battery_service.py": BATTERY_LIB, **_ADAFRUIT_BLE} + { + "code.py": BSIM_SERVICE_CODE, + "settings.toml": "CIRCUITPY_BLE_WORKFLOW = false\n", + "battery_service.py": BATTERY_LIB, + **_ADAFRUIT_BLE, + } ) def test_bsim_service_battery(bsim_phy, circuitpython, zephyr_sample): """CP hosts BatteryService; Zephyr central reads battery level.""" diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_advertising.py new file mode 100644 index 00000000000..a6e9bc6e0dd --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_advertising.py @@ -0,0 +1,112 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Advertising test for the supervisor BLE workflow (bsim). + +The supervisor's built-in BLE workflow (file-transfer + serial services and +advertising) starts automatically at boot, independent of user code. One +CircuitPython device runs an idle code.py so its workflow advertises; a second +CircuitPython device scans with the adafruit_ble library and verifies the +workflow's advertisement carries the File Transfer service UUID (0xFEBB) and +the CIRCUITPY device name. + +The second device disables its own workflow via settings.toml so only the +first device advertises. +""" + +import logging +import re + +import pytest + +from .conftest import get_library_files + +logger = logging.getLogger(__name__) + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") + +# Device 1: idle code.py. The supervisor workflow advertises during the sleep. +WORKFLOW_IDLE_CODE = """\ +import time +time.sleep(15) +""" + +# Device 2: scan for the workflow advertisement. The workflow puts the +# File Transfer service UUID (0xFEBB) in the primary advertisement and the full +# "CIRCUITPYxxxx" name in the scan response, so those arrive as separate +# Advertisement objects (service list vs. scan response). +SCANNER_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising import Advertisement +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.uuid import StandardUUID + +ble = BLERadio() +print("scan start") +found_ft = False +found_name = False +ft_rssi = None +for adv in ble.start_scan(ProvideServicesAdvertisement, Advertisement, timeout=15, active=True): + if isinstance(adv, ProvideServicesAdvertisement) and StandardUUID(0xFEBB) in adv.services: + found_ft = True + ft_rssi = adv.rssi + print("ft_uuid febb") + name = adv.complete_name or adv.short_name or "" + if name: + found_name = True + print("cp_name", name) + if found_ft and found_name: + print("workflow found") + print("ft_rssi", ft_rssi) + break +ble.stop_scan() +print("scan done", found_ft, found_name, ft_rssi) +""" + +# Disable the workflow on the scanner so it doesn't advertise alongside device 1. +SCANNER_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + + +@pytest.mark.duration(20) +@pytest.mark.circuitpy_drive({"code.py": WORKFLOW_IDLE_CODE}) +@pytest.mark.circuitpy_drive( + { + "code.py": SCANNER_CODE, + "settings.toml": SCANNER_SETTINGS, + **_ADAFRUIT_BLE, + } +) +def test_bsim_workflow_advertises(bsim_phy, circuitpython1, circuitpython2): + """The supervisor BLE workflow advertises 0xFEBB and the CIRCUITPY name.""" + workflow = circuitpython1 + scanner = circuitpython2 + + scanner.wait_until_done() + + scanner_output = scanner.serial.all_output + assert "ft_uuid febb" in scanner_output, ( + f"File Transfer service UUID 0xFEBB not observed: {scanner_output}" + ) + # The device name currently advertises as the controller default ("Zephyr"); + # the CIRCUITPY name is configured separately, at which point this will + # observe the full "CIRCUITPY..." name. Either way a name must be present. + assert "cp_name" in scanner_output, f"device name not observed: {scanner_output}" + assert "workflow found" in scanner_output, ( + f"workflow advertisement not fully observed: {scanner_output}" + ) + + # The workflow advertises its public advert at reduced TX power (-20 dBm), + # so with the 40 dB channel attenuation the RSSI is ~ -59, well below the + # 0 dBm baseline of -39 seen for user advertisements. + rssi_match = re.search(r"ft_rssi (-?\d+)", scanner_output) + assert rssi_match, f"ft_rssi not observed: {scanner_output}" + ft_rssi = int(rssi_match.group(1)) + logger.info("workflow ft_rssi: %d", ft_rssi) + assert ft_rssi < -39, f"Expected reduced-TX-power RSSI (< -39), got {ft_rssi}" + + # The workflow device should not have entered safe mode. + workflow_output = workflow.serial.all_output + assert "safe mode" not in workflow_output.lower(), ( + f"workflow device entered safe mode: {workflow_output}" + ) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_file_transfer.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_file_transfer.py new file mode 100644 index 00000000000..a7c383febe1 --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_file_transfer.py @@ -0,0 +1,102 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""File Transfer service test for the supervisor BLE workflow (bsim). + +A second CircuitPython device connects to the supervisor's BLE workflow +(advertised with the File Transfer service UUID 0xFEBB), pairs, and uses the +Adafruit_CircuitPython_BLE_File_Transfer library to list the workflow device's +root directory. +""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") +_ADAFRUIT_BLE_FILE_TRANSFER = get_library_files("adafruit_ble_file_transfer") + +# Device 1: idle code.py; its workflow exposes the File Transfer service. +WORKFLOW_IDLE_CODE = """\ +import time +time.sleep(25) +""" + +# Device 2: connect, pair, and listdir("/") over the File Transfer service. +CLIENT_CODE = """\ +import time +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.uuid import StandardUUID +from adafruit_ble_file_transfer import FileTransferService, FileTransferClient + +ble = BLERadio() + +# Wait for the workflow device's file transfer server to finish starting up +# before scanning. +time.sleep(5) +print("scan start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=15, active=True): + if StandardUUID(0xFEBB) in adv.services: + target = adv + print("found workflow") + break +ble.stop_scan() +if target is None: + print("no workflow") + raise SystemExit(1) + +connection = ble.connect(target, timeout=10) +print("connected", connection.connected) +connection.pair() +print("paired", connection.paired) + +service = connection[FileTransferService] +print("ft version", service.version) +client = FileTransferClient(service) + +entries = client.listdir("/") +names = [e[0] for e in entries] +print("ft names", names) +if "code.py" in names: + print("ft code.py listed") +print("ft done") +connection.disconnect() +""" + +CLIENT_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": WORKFLOW_IDLE_CODE}) +@pytest.mark.circuitpy_drive( + { + "code.py": CLIENT_CODE, + "settings.toml": CLIENT_SETTINGS, + **_ADAFRUIT_BLE_FILE_TRANSFER, + **_ADAFRUIT_BLE, + } +) +def test_bsim_workflow_file_transfer(board, bsim_phy, circuitpython1, circuitpython2): + """The supervisor BLE workflow's File Transfer service can list files.""" + workflow = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + + client_output = client.serial.all_output + assert "found workflow" in client_output, f"client never found the workflow: {client_output}" + assert "paired True" in client_output, f"pairing did not succeed: {client_output}" + assert "ft version 4" in client_output, ( + f"File Transfer version characteristic is not 4: {client_output}" + ) + assert "ft code.py listed" in client_output, ( + f"listdir did not include code.py: {client_output}" + ) + assert "ft done" in client_output, f"file transfer did not complete: {client_output}" + + workflow_output = workflow.serial.all_output + assert "safe mode" not in workflow_output.lower(), ( + f"workflow device entered safe mode: {workflow_output}" + ) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_nus.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_nus.py new file mode 100644 index 00000000000..ebc0bbcc69c --- /dev/null +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_workflow_nus.py @@ -0,0 +1,146 @@ +# SPDX-FileCopyrightText: 2026 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Serial (Nordic-UART-style) service test for the supervisor BLE workflow +(bsim). + +The supervisor's BLE workflow exposes a CircuitPython serial service whose RX +characteristic accepts console stdin (write, encrypted) and whose TX +characteristic emits console stdout via notifications (encrypted). One +CircuitPython device runs code.py that reads a line with `input()` and echoes +it back with `print()`; a second CircuitPython device connects, pairs, +subscribes to TX, writes a line to RX, and verifies the echo comes back over TX. +""" + +import pytest + +from .conftest import get_library_files + +_ADAFRUIT_BLE = get_library_files("adafruit_ble") + +# Device 1: read a line from console stdin (BLE RX) and echo it to console +# stdout (mirrored to BLE TX). `input()` blocks until the central writes, so the +# device stays alive for the exchange. +WORKFLOW_CODE = """\ +import time +print("nus ready") +try: + line = input() +except EOFError: + line = "" +print("nus_echo:" + line) +# Keep the VM alive briefly so the BLE TX notification carrying the echo is +# actually transmitted over the link before the device exits. Without this the +# notification is queued but never sent because the process shuts down right +# after code.py finishes. +time.sleep(3) +""" + +# Device 2: connect, pair, discover the CircuitPython serial service, subscribe +# to TX, write a line to RX, and read the echo back over TX. +CLIENT_CODE = """\ +import time +import _bleio +from adafruit_ble import BLERadio +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.uuid import StandardUUID + +ble = BLERadio() + +# Wait for the workflow device's serial service to finish starting up +# before scanning. Connecting too soon after the workflow's BLE init races +# with a Zephyr connection-parameter update and the link drops shortly +# after pairing. +time.sleep(5) +print("scan start") +target = None +for adv in ble.start_scan(ProvideServicesAdvertisement, timeout=15, active=True): + if StandardUUID(0xFEBB) in adv.services: + target = adv + print("found workflow") + break +ble.stop_scan() +if target is None: + print("no workflow") + raise SystemExit(1) + +connection = ble.connect(target, timeout=10) +print("connected", connection.connected) +connection.pair() +print("paired", connection.paired) + +# CircuitPython serial service UUID (128-bit, "nhtyPtiucriC" base + 0x0001). +serial_uuid = _bleio.UUID(b"nhtyPtiucriC\\x01\\x00\\xaf\\xad") +services = connection._bleio_connection.discover_remote_services([serial_uuid]) +svc = services[0] +print("serial service", svc.uuid.uuid16) + +rx_char = None +tx_char = None +for ch in svc.characteristics: + if ch.uuid.uuid16 == 0x0002: + rx_char = ch + elif ch.uuid.uuid16 == 0x0003: + tx_char = ch +print("rx", rx_char is not None, "tx", tx_char is not None) + +# Subscribe to TX notifications (client-side PacketBuffer writes the CCCD). +tx_pb = _bleio.PacketBuffer(tx_char, buffer_size=4, max_packet_size=128) + +# Write a line to RX (console stdin). RX has WRITE_NO_RESPONSE, so `.value =` +# does a GATT write without response. +rx_char.value = b"ZZZ\\r" +print("rx written") + +buf = bytearray(128) +got = b"" +deadline = time.monotonic() + 10 +while time.monotonic() < deadline: + n = tx_pb.readinto(buf) + if n: + got += bytes(buf[:n]) + if b"nus_echo:ZZZ" in got: + print("nus_received nus_echo:ZZZ") + break +print("nus done", b"nus_echo:ZZZ" in got) +connection.disconnect() +""" + +CLIENT_SETTINGS = "CIRCUITPY_BLE_WORKFLOW = false\n" + + +@pytest.mark.duration(30) +@pytest.mark.circuitpy_drive({"code.py": WORKFLOW_CODE}) +@pytest.mark.circuitpy_drive( + { + "code.py": CLIENT_CODE, + "settings.toml": CLIENT_SETTINGS, + **_ADAFRUIT_BLE, + } +) +def test_bsim_workflow_nus(board, bsim_phy, circuitpython1, circuitpython2): + """The supervisor BLE workflow's serial service echoes console I/O over BLE.""" + workflow = circuitpython1 + client = circuitpython2 + + client.wait_until_done() + + client_output = client.serial.all_output + assert "found workflow" in client_output, f"client never found the workflow: {client_output}" + assert "paired True" in client_output, f"pairing did not succeed: {client_output}" + assert "serial service 1" in client_output, ( + f"CircuitPython serial service not discovered: {client_output}" + ) + assert "rx True tx True" in client_output, ( + f"RX/TX characteristics not discovered: {client_output}" + ) + assert "rx written" in client_output, f"RX write failed: {client_output}" + assert "nus_received nus_echo:ZZZ" in client_output, ( + f"echo 'nus_echo:ZZZ' never received over TX: {client_output}" + ) + assert "nus done True" in client_output, f"echo not confirmed: {client_output}" + + workflow_output = workflow.serial.all_output + assert "safe mode" not in workflow_output.lower(), ( + f"workflow device entered safe mode: {workflow_output}" + ) diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index 0efe3bcc3fe..ae796f4da97 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -325,6 +325,15 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp f"-uart{uart_n}_pty", f"-uart{uart_n}_pty_wait_for_readers", "-uart_pty_wait", + # Use the real AES implementation (libCryptov1.so) for the + # link layer instead of BabbleSim's plain-text stand-in. + # The nRF54L HW models route AES through several different + # stand-ins (ECB/CCM copy the data, CRACEN scrambles it), + # which are not consistent with each other, so LE + # encryption only works with real AES. Zephyr's own bsim + # encryption tests pass -RealEncryption=1 for the same + # reason. + "-RealEncryption=1", f"--vm-runs={code_py_runs + 1}", ) ) From 52fc37d59bc9173796a2f40abf49335921a3e9fd Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 24 Aug 2026 22:40:27 -0400 Subject: [PATCH 824/876] turn off CIRCUITPY_I2CIOEXPANDER except on specific boards --- ports/raspberrypi/mpconfigport.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index f4c6e809ba0..02fd6365b68 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -35,7 +35,6 @@ CIRCUITPY_FREQUENCYIO = 0 # Use PWM internally CIRCUITPY_I2CTARGET = 1 -CIRCUITPY_I2CIOEXPANDER = 1 CIRCUITPY_NVM = 1 # Use PIO internally CIRCUITPY_PULSEIO ?= 1 From 2f13cfb4e8931e7ab2c0b1b33a10dda260c7196f Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 18 May 2026 11:54:28 -0700 Subject: [PATCH 825/876] sdcardio: fix card size for SDXC cards > 32 GB The CSD v2.0 C_SIZE field is 22 bits but only the bottom 16 were being read. Cards > 32 GB reported roughly half their actual block count over USB MSC. Fix reads all 22 bits. Co-Authored-By: Claude Sonnet 4.6 (cherry picked from commit b9a43e64d766787427875a848cfc85ab76226535) --- shared-module/sdcardio/SDCard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index 40d09aa99ca..fa789ab4543 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -318,7 +318,7 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { } if (csd_version == 1) { - self->sectors = ((csd[8] << 8 | csd[9]) + 1) * 1024; + self->sectors = (((uint32_t)(csd[7] & 0x3F) << 16 | (uint32_t)csd[8] << 8 | csd[9]) + 1) * 1024; } else { uint32_t block_length = 1 << (csd[5] & 0xF); uint32_t c_size = ((csd[6] & 0x3) << 10) | (csd[7] << 2) | ((csd[8] & 0xC) >> 6); From 630d9246468020e26c96fd927ecfe4df439f7bae Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 19 May 2026 14:21:52 -0400 Subject: [PATCH 826/876] remove unneeded uint32_t casts (cherry picked from commit 26427a2c52d6a22bd33b64b2d8de94b56d3b42f0) --- shared-module/sdcardio/SDCard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/sdcardio/SDCard.c b/shared-module/sdcardio/SDCard.c index fa789ab4543..5c9050f2662 100644 --- a/shared-module/sdcardio/SDCard.c +++ b/shared-module/sdcardio/SDCard.c @@ -318,7 +318,7 @@ static mp_rom_error_text_t init_card(sdcardio_sdcard_obj_t *self) { } if (csd_version == 1) { - self->sectors = (((uint32_t)(csd[7] & 0x3F) << 16 | (uint32_t)csd[8] << 8 | csd[9]) + 1) * 1024; + self->sectors = (((csd[7] & 0x3F) << 16 | csd[8] << 8 | csd[9]) + 1) * 1024; } else { uint32_t block_length = 1 << (csd[5] & 0xF); uint32_t c_size = ((csd[6] & 0x3) << 10) | (csd[7] << 2) | ((csd[8] & 0xC) >> 6); From dbb2603071b1cfbbb308bb219fbe153f246731b9 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 24 Aug 2026 17:22:24 -0700 Subject: [PATCH 827/876] tests: allow a sys.platform containing spaces in detect_test_platform CircuitPythons atmel-samd boards report sys.platform as "Atmel SAMD21" and "MicroChip SAMD51". target_info.py prints it as the first of seven space-separated fields, so split() yields eight and the unpack raises ValueError: too many values to unpack (expected 7), which aborts the run before any test executes. Splitting from the right keeps the platform name intact. Co-Authored-By: Claude Opus 5 (1M context) --- tests/run-tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-tests.py b/tests/run-tests.py index 71570292ce7..d2849efa360 100755 --- a/tests/run-tests.py +++ b/tests/run-tests.py @@ -418,8 +418,9 @@ def detect_test_platform(pyb, args): output = run_feature_check(pyb, args, "target_info.py") if output.endswith(b"CRASH"): raise ValueError("cannot detect platform: {}".format(output)) + # CIRCUITPY-CHANGE: sys.platform is the first field and can contain spaces ("Atmel SAMD21"). platform, arch, arch_flags, build, thread, float_prec, unicode = ( - str(output, "ascii").strip().split() + str(output, "ascii").strip().rsplit(None, 6) ) if arch == "None": arch = None From edb0743611791c5bd2f711a15241830a30942311 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 24 Aug 2026 23:23:43 -0400 Subject: [PATCH 828/876] update frozen libraries for 10.3.0 --- frozen/Adafruit_CircuitPython_Bitmap_Font | 2 +- frozen/Adafruit_CircuitPython_Display_Text | 2 +- frozen/Adafruit_CircuitPython_ESP32SPI | 2 +- frozen/Adafruit_CircuitPython_Motor | 2 +- frozen/Adafruit_CircuitPython_Register | 2 +- frozen/Adafruit_CircuitPython_SSD1680 | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frozen/Adafruit_CircuitPython_Bitmap_Font b/frozen/Adafruit_CircuitPython_Bitmap_Font index fe0cdfd5501..94bec4ba5ee 160000 --- a/frozen/Adafruit_CircuitPython_Bitmap_Font +++ b/frozen/Adafruit_CircuitPython_Bitmap_Font @@ -1 +1 @@ -Subproject commit fe0cdfd5501070f5ca47b3e66dfd15e62c54011e +Subproject commit 94bec4ba5ee9bbc1f9a72281e3085ab10b5efd3a diff --git a/frozen/Adafruit_CircuitPython_Display_Text b/frozen/Adafruit_CircuitPython_Display_Text index eae352b0970..6761a7f0a3c 160000 --- a/frozen/Adafruit_CircuitPython_Display_Text +++ b/frozen/Adafruit_CircuitPython_Display_Text @@ -1 +1 @@ -Subproject commit eae352b09700e57b78507aace7ff682cb1beff5a +Subproject commit 6761a7f0a3ce7549c9887caee2c85bceef739d00 diff --git a/frozen/Adafruit_CircuitPython_ESP32SPI b/frozen/Adafruit_CircuitPython_ESP32SPI index b0e2124a175..64f4695cc44 160000 --- a/frozen/Adafruit_CircuitPython_ESP32SPI +++ b/frozen/Adafruit_CircuitPython_ESP32SPI @@ -1 +1 @@ -Subproject commit b0e2124a175f421bb07ac5cc72b81f6209966a3b +Subproject commit 64f4695cc4457df0718e1a6460082381359c3562 diff --git a/frozen/Adafruit_CircuitPython_Motor b/frozen/Adafruit_CircuitPython_Motor index 20ebf51fe0d..dc0c88c1d7c 160000 --- a/frozen/Adafruit_CircuitPython_Motor +++ b/frozen/Adafruit_CircuitPython_Motor @@ -1 +1 @@ -Subproject commit 20ebf51fe0d2bb48b1780c3c9bd74c16c73bc02e +Subproject commit dc0c88c1d7ca386a434d17c65a1e5efa5fc31a5f diff --git a/frozen/Adafruit_CircuitPython_Register b/frozen/Adafruit_CircuitPython_Register index e168e97a2c9..6ebae944c97 160000 --- a/frozen/Adafruit_CircuitPython_Register +++ b/frozen/Adafruit_CircuitPython_Register @@ -1 +1 @@ -Subproject commit e168e97a2c9713ec0f82cb6171461873dfffd46d +Subproject commit 6ebae944c97ff8f9394ceb2c634a32aef903e5c4 diff --git a/frozen/Adafruit_CircuitPython_SSD1680 b/frozen/Adafruit_CircuitPython_SSD1680 index f17e62d2466..d3eb6f27c0d 160000 --- a/frozen/Adafruit_CircuitPython_SSD1680 +++ b/frozen/Adafruit_CircuitPython_SSD1680 @@ -1 +1 @@ -Subproject commit f17e62d246656b3f956232c368bc05d966988d9a +Subproject commit d3eb6f27c0d89e7e8a08bdaf0c6a6e40f7fc512c From cea4292dca0dbcdae2c56671bfedfad51bb3237f Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 24 Aug 2026 22:13:17 -0400 Subject: [PATCH 829/876] memento: turn off presenting SD card on USB by default --- docs/environment.rst | 3 ++- .../espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h | 4 ++++ py/circuitpy_mpconfig.h | 5 +++++ supervisor/shared/usb/usb_msc_flash.c | 3 ++- 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/environment.rst b/docs/environment.rst index 4bf89bf774a..6ba541ba34c 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -134,7 +134,8 @@ CIRCUITPY_SDCARD_USB (boolean) Present a mounted SD card as a USB MSC device. If the board has default pins for an SD card socket, the card is mounted automatically on startup. Only one card can be presented. -Defaults to ``true``. +Defaults to ``true``, except on the Adafruit Memento board, where it defaults to ``false`` +for now to avoid a bug. SD card presentation can slow down board startup, so set this to ``false`` if you don't need this feature. diff --git a/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h b/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h index 25d08535dd6..771a3275fb4 100644 --- a/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h +++ b/ports/espressif/boards/adafruit_esp32s3_camera/mpconfigboard.h @@ -20,3 +20,7 @@ #define DEFAULT_SPI_BUS_MISO (&pin_GPIO37) #define DOUBLE_TAP_PIN (&pin_GPIO42) + +// Turn off presenting SD card to USB by default. Changes settings.toml default for this setting. +// Workaround for https://github.com/adafruit/circuitpython/issues/11109. +#define CIRCUITPY_SDCARD_USB (false) diff --git a/py/circuitpy_mpconfig.h b/py/circuitpy_mpconfig.h index 58d7fe74ea6..9dd5abc8a3a 100644 --- a/py/circuitpy_mpconfig.h +++ b/py/circuitpy_mpconfig.h @@ -530,6 +530,11 @@ void background_callback_run_all(void); #ifndef CIRCUITPY_SDCARD_USB #if CIRCUITPY_USB_DEVICE #define CIRCUITPY_SDCARD_USB (CIRCUITPY_SDCARDIO && CIRCUITPY_USB_MSC) +// Default value of CIRCUITPY_SDCARD_USB in settings.toml. +#ifndef CIRCUITPY_SDCARD_USB_DEFAULT +// True for most boards. +#define CIRCUITPY_SDCARD_USB_DEFAULT (true) +#endif #else #define CIRCUITPY_SDCARD_USB (0) #endif diff --git a/supervisor/shared/usb/usb_msc_flash.c b/supervisor/shared/usb/usb_msc_flash.c index 163019b7328..e9e36131c13 100644 --- a/supervisor/shared/usb/usb_msc_flash.c +++ b/supervisor/shared/usb/usb_msc_flash.c @@ -379,7 +379,8 @@ static sdcard_usb_setting_state_t _sdcard_usb_setting_state = SDCARD_USB_SETTING // Read only once to save file access time. static bool sdcard_usb_enabled(void) { if (_sdcard_usb_setting_state == SDCARD_USB_SETTING_NOT_YET_READ) { - bool setting = true; + // Can be changed per board. Most boards would leave this as true (default in circuitpy_mpconfig.h). + bool setting = CIRCUITPY_SDCARD_USB_DEFAULT; (void)settings_get_bool("CIRCUITPY_SDCARD_USB", &setting); _sdcard_usb_setting_state = setting ? SDCARD_USB_SETTING_TRUE : SDCARD_USB_SETTING_FALSE; } From ab82ccebc3fbd0aaa8e98fceeca36999087d2774 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Tue, 25 Aug 2026 10:10:13 -0400 Subject: [PATCH 830/876] pimoroni_inky_frame_5_7: remove frozen adafruit_sdcard; not needed --- .../raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk index 69b23a72be7..0a56b55a0c1 100644 --- a/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk +++ b/ports/raspberrypi/boards/pimoroni_inky_frame_5_7/mpconfigboard.mk @@ -36,4 +36,3 @@ CFLAGS += -DCIRCUITPY_FIRMWARE_SIZE='(1536 * 1024)' FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-pcf85063a FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_Register -FROZEN_MPY_DIRS += $(TOP)/frozen/Adafruit_CircuitPython_SD From 3dbb7143fed43f7b18db9c22811b29f365396bb4 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 25 Aug 2026 09:53:07 -0700 Subject: [PATCH 831/876] zephyr-cp: fall back to the WiFi MAC for cpu.uid hwinfo_get_device_id() returns -ENOSYS on any SoC without an hwinfo driver, so cpu.uid, and the web workflow's version.json UID field, read as all zeros. When that happens and the board has WiFi, derive the UID from the WiFi interface link address instead. A link address is per-device, so it is a better answer than nothing. It is also what at least one vendor already means by the part's unique ID: Simplicity Commander reports the siwx91x unique ID as the WiFi MAC zero-extended to eight bytes, and this produces the same value. Unlike a burned-in serial this can generally be reprogrammed by vendor tooling, so cpu.uid must not be relied on as tamper proof where it comes from this path. Boards whose SoC has a real hwinfo driver never reach it. Gated on CONFIG_WIFI, and purely additive: the existing diagnostics still fire on any board where nothing supplies a UID. Verified on two SiWx917-DK2605A boards, each a different die: board A commander 0000c09b9ec2eec8 cpu.uid 0000c09b9ec2eec8 board B commander 0000c09b9ec39910 cpu.uid 0000c09b9ec39910 --- .../common-hal/microcontroller/Processor.c | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ports/zephyr-cp/common-hal/microcontroller/Processor.c b/ports/zephyr-cp/common-hal/microcontroller/Processor.c index 593d73bcc61..61beb470595 100644 --- a/ports/zephyr-cp/common-hal/microcontroller/Processor.c +++ b/ports/zephyr-cp/common-hal/microcontroller/Processor.c @@ -14,6 +14,34 @@ #include #include +#if defined(CONFIG_WIFI) +#include + +// Fallback for SoCs with no hwinfo driver, where hwinfo_get_device_id() returns +// -ENOSYS and cpu.uid would otherwise be all zeros. A WiFi link address is +// per-device, so it is a better answer than nothing, and at least one vendor +// (Silicon Labs, for the siwx91x) defines that part's unique ID as exactly this: +// the WiFi MAC zero-extended to eight bytes. +// +// This is not a burned-in serial. A MAC can generally be reprogrammed by vendor +// tooling, so cpu.uid must not be relied on as tamper proof where it comes from +// here. Boards whose SoC has a real hwinfo driver never reach this path. +static ssize_t uid_from_wifi_mac(uint8_t raw_id[]) { + if (COMMON_HAL_MCU_PROCESSOR_UID_LENGTH < 8) { + return -1; + } + struct net_if *iface = net_if_get_first_wifi(); + struct net_linkaddr *addr = (iface != NULL) ? net_if_get_link_addr(iface) : NULL; + if (addr == NULL || addr->len != 6) { + return -1; + } + raw_id[0] = 0; + raw_id[1] = 0; + memcpy(&raw_id[2], addr->addr, 6); + return 8; +} +#endif + float common_hal_mcu_processor_get_temperature(void) { return 0.0; @@ -34,6 +62,14 @@ float common_hal_mcu_processor_get_voltage(void) { void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { ssize_t len = hwinfo_get_device_id(raw_id, COMMON_HAL_MCU_PROCESSOR_UID_LENGTH); + #if defined(CONFIG_WIFI) + if (len < 0) { + ssize_t mac_len = uid_from_wifi_mac(raw_id); + if (mac_len > 0) { + len = mac_len; + } + } + #endif if (len < 0) { printk("UID retrieval failed: %d\n", len); len = 0; From b7cdd2f039b42eee5a826670dcda6b778698b79e Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 25 Aug 2026 10:04:13 -0700 Subject: [PATCH 832/876] zephyr-cp: build ulab, and let boards opt out zephyr-cp builds without py/circuitpy_mpconfig.mk, so the ulab wiring every other port gets from py/py.mk does not exist here and ulab cannot be built at all. This adds the flags and sources the way py.mk does. ulab is on by default. Boards that cannot spare the flash set CIRCUITPY_ULAB = false in their circuitpython.toml, which nordic_nrf7002dk does here: it has under 3 KB of headroom before this change and ulab costs about 90 KB. Flash cost measured on silabs_siwx917_dk2605a: 799136 to 890168 bytes, 76.21% to 84.89% of 1 MB, with 163 ulab sources compiled. Headroom on the other zephyr-cp boards that report a flash figure is at least 135 KB, so nrf7002dk is the only one that has to opt out. --- .../boards/nordic/nrf7002dk/circuitpython.toml | 4 ++++ ports/zephyr-cp/cptools/build_circuitpython.py | 16 ++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index 54f84efe09b..f37513d252b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -3,3 +3,7 @@ USB_VID=0x239A USB_PID=0x8168 BLOBS=["nrf_wifi"] DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib", "jpegio", "tilepalettemapper", "gifio"] + +# ulab is on by default. This board has under 3 KB of flash headroom, and +# ulab costs about 90 KB, so it opts out. +CIRCUITPY_ULAB = false diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 55c069a1ddc..8cf22ac7c16 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -634,7 +634,23 @@ async def build_circuitpython(): # noqa: C901 enabled = mpflag in DEFAULT_MODULES circuitpython_flags.append(f"-DCIRCUITPY_{mpflag.upper()}={1 if enabled else 0}") + # ulab is on by default and boards that cannot spare the flash set + # CIRCUITPY_ULAB = false in their circuitpython.toml. Flags mirror py/py.mk. + ulab_enabled = mpconfigboard.get("CIRCUITPY_ULAB", True) + circuitpython_flags.append(f"-DCIRCUITPY_ULAB={1 if ulab_enabled else 0}") + if ulab_enabled: + circuitpython_flags.extend( + ( + "-DMODULE_ULAB_ENABLED=1", + "-DULAB_HAS_USER_MODULE=0", + "-iquote", + str(top / "extmod" / "ulab" / "code"), + ) + ) + source_files = supervisor_source + hal_source + ["extmod/vfs.c"] + if ulab_enabled: + source_files.extend(sorted((top / "extmod" / "ulab" / "code").rglob("*.c"))) assembly_files = [] for file in top.glob("py/*.c"): source_files.append(file) From 745461cf30667f9db84b25cd50945db262c48ad8 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 25 Aug 2026 10:05:16 -0700 Subject: [PATCH 833/876] zephyr-cp: keep regions too small for the heap out of ram_bounds zephyr2cp.py already filtered RAM regions by size, but MINIMUM_RAM_SIZE was 1024 and the comparison is >=, so a region of exactly 0x400 bytes passed. The SiWx917 has two of them, /memory@0 (reserved for the network processor) and /memory-dma@24061c00, and both reached ram_bounds. That matters because TLSF sizes its control structure from the maximum heap size rather than from the region it is given: tlsf_create_with_pool() forwards max_bytes to tlsf_create(), which performs both of its size checks against the maximum. With an 8 MB maximum the structure is 2412 bytes, so handing it a 1 KB region overruns that region by 1388 bytes and still returns success. On a SiWx917-DK2605A the result is a kernel panic during port_heap_init(). Raise MINIMUM_RAM_SIZE to 8192 so such regions never enter the list. The build script only sees the devicetree size, while the usable size is DT_REG_ADDR + DT_REG_SIZE minus a linker symbol, so it cannot predict a region the linker has filled. port.c keeps a check for that case, now by testing tlsf_create_with_pool() for NULL rather than assuming it succeeded. Verified on two SiWx917-DK2605A boards: before, ram_bounds carried four regions and the board panicked at boot on current main; after, the two 1 KB regions are gone from the generated board.c and both boards boot to the REPL. --- ports/zephyr-cp/cptools/zephyr2cp.py | 9 ++++++++- ports/zephyr-cp/supervisor/port.c | 8 ++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/cptools/zephyr2cp.py b/ports/zephyr-cp/cptools/zephyr2cp.py index a6e2fa53cdc..8a91c34da65 100644 --- a/ports/zephyr-cp/cptools/zephyr2cp.py +++ b/ports/zephyr-cp/cptools/zephyr2cp.py @@ -13,7 +13,14 @@ # GPIO flags defined here: include/zephyr/dt-bindings/gpio/gpio.h GPIO_ACTIVE_LOW = 1 << 0 -MINIMUM_RAM_SIZE = 1024 +# A region has to be big enough to host TLSF's control structure to be usable as +# the first heap pool, and TLSF sizes that structure from the maximum heap size +# rather than from the region: at an 8 MB maximum it is 2412 bytes. Anything +# smaller than this is not worth adding as a later pool either. The previous +# value of 1024 let through two SiWx917 regions that are exactly 0x400 bytes, +# /memory@0 (reserved for the network processor) and /memory-dma@24061c00, +# neither of which should ever be in the Python heap. +MINIMUM_RAM_SIZE = 8192 MANUAL_COMPAT_TO_DRIVER = { "renesas_ra_nv_flash": "flash", diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 1ecde0b0141..52b5c46f8b1 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -294,6 +294,14 @@ void port_heap_init(void) { // If this crashes, then make sure you've enabled all of the Kconfig needed for the drivers. if (valid_pool_count == 0) { heap = tlsf_create_with_pool(heap_bottom, size, circuitpy_max_ram_size); + if (heap == NULL) { + // Can happen for a region the linker filled almost to the top, + // which the build-time MINIMUM_RAM_SIZE filter cannot predict + // because it only sees the devicetree size. + printk("Heap creation failed at %p; trying the next region\n", heap_bottom); + pools[i] = NULL; + continue; + } pools[i] = tlsf_get_pool(heap); } else { pools[i] = tlsf_add_pool(heap, heap_bottom + 1, size - sizeof(uint32_t)); From 051811bab673f8170925c15799f15e63331e15e6 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 25 Aug 2026 10:39:49 -0700 Subject: [PATCH 834/876] Fix up ble_hci --- devices/ble_hci/common-hal/_bleio/Adapter.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/Adapter.c b/devices/ble_hci/common-hal/_bleio/Adapter.c index abeb0824458..005dd0aeb03 100644 --- a/devices/ble_hci/common-hal/_bleio/Adapter.c +++ b/devices/ble_hci/common-hal/_bleio/Adapter.c @@ -629,11 +629,8 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, // Copy peer address, if supplied. if (directed_to) { - mp_buffer_info_t bufinfo; - if (mp_get_buffer(directed_to->bytes, &bufinfo, MP_BUFFER_READ)) { - peer_addr.type = directed_to->type; - memcpy(&peer_addr.a.val, bufinfo.buf, sizeof(peer_addr.a.val)); - } + peer_addr.type = directed_to->type; + memcpy(&peer_addr.a.val, directed_to->bytes, sizeof(peer_addr.a.val)); } bool extended = From 2e19117dad6eb69691012eece4ec0eaa095e30fd Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 25 Aug 2026 13:02:45 -0500 Subject: [PATCH 835/876] nordic: make the SoftDevice optional A board sets `SD =` (empty) in its mpconfigboard.mk to build without a SoftDevice, reclaiming the MBR + SoftDevice flash and the 56kB of low RAM they reserve. Boards that do not opt out are unaffected. - Makefile: build the bluetooth sources only when SD is set, and link firmware.hex rather than firmware.combined.hex when there is no SoftDevice hex to merge in. Guard the bluetooth_common.mk include with VALID_BOARD so non-board rules such as fetch-port-submodules do not evaluate SoftDevice paths built from an unset MCU_VARIANT. - mpconfigport.mk: force _bleio and the BLE file/serial services off when SD is empty. - mpconfigport.h: without a SoftDevice its headers are not on the include path, so define MBR_SIZE and SD_FLASH_SIZE to 0 locally, and zero both CIRCUITPY_BLE_CONFIG_SIZE (nothing to bond) and SOFTDEVICE_RAM_SIZE. - startup_nrf52840.c: with a SoftDevice the MBR at 0x0 owns the vector table and has already pointed VTOR at ours. Without one, set it. - microcontroller/__init__.c: replace the sd_nvic critical-region calls with PRIMASK save/mask/restore, and write GPREGRET directly. - port.c, PinAlarm.c, neopixel_write, nvm.h: guard SoftDevice headers and calls. port_idle_until_interrupt()'s existing non-SoftDevice path becomes the fallthrough. Built and verified on feather_nrf52840_express (SoftDevice, byte-identical apart from port_idle_until_interrupt), microbit_v2 (nRF52833), and a throwaway SD-less board. --- ports/nordic/Makefile | 20 +++++++++++++++++- ports/nordic/common-hal/alarm/pin/PinAlarm.c | 2 ++ .../common-hal/microcontroller/__init__.c | 20 ++++++++++++++++++ .../common-hal/neopixel_write/__init__.c | 2 ++ ports/nordic/device/nrf52/startup_nrf52840.c | 15 +++++++++++++ ports/nordic/mpconfigport.h | 21 ++++++++++++++++++- ports/nordic/mpconfigport.mk | 7 +++++++ ports/nordic/peripherals/nrf/nvm.h | 6 +++++- ports/nordic/supervisor/port.c | 10 +++++++-- 9 files changed, 98 insertions(+), 5 deletions(-) diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index 1e283fc699c..83c15c5a463 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -6,9 +6,16 @@ include ../../py/circuitpy_mkenv.mk +# The SoftDevice paths are built from MCU_VARIANT and SOFTDEV_VERSION, which +# only exist once boards/$(BOARD)/mpconfigboard.mk has set MCU_CHIP. Skip when +# the rule requested is not board-specific (e.g. fetch-port-submodules), or the +# stack-missing check looks for an unexpanded path and fails on a tree where +# nothing is actually missing. +ifneq ($(VALID_BOARD),) ifneq ($(SD), ) include bluetooth/bluetooth_common.mk endif +endif CROSS_COMPILE = arm-none-eabi- @@ -115,11 +122,16 @@ SRC_C += \ boards/$(BOARD)/board.c \ boards/$(BOARD)/pins.c \ device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).c \ + nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ + +ifneq ($(SD), ) +SRC_C += \ bluetooth/ble_drv.c \ common-hal/_bleio/bonding.c \ - nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ sd_mutex.c \ +endif + SRC_PERIPHERALS := \ peripherals/nrf/cache.c \ peripherals/nrf/clocks.c \ @@ -177,7 +189,13 @@ UF2_FAMILY_ID_nrf52840 = 0xADA52840 UF2_FAMILY_ID_nrf52833 = 0x621E937A +ifneq ($(SD), ) all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 $(BUILD)/firmware.combined.hex +else +# firmware.combined.hex merges in the SoftDevice hex; without one there is +# nothing to combine. +all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 $(BUILD)/firmware.hex +endif ifeq ($(VALID_BOARD),) $(BUILD)/firmware.elf: invalid-board diff --git a/ports/nordic/common-hal/alarm/pin/PinAlarm.c b/ports/nordic/common-hal/alarm/pin/PinAlarm.c index f43eb1ed251..3359faa74e0 100644 --- a/ports/nordic/common-hal/alarm/pin/PinAlarm.c +++ b/ports/nordic/common-hal/alarm/pin/PinAlarm.c @@ -17,7 +17,9 @@ #include "nrfx.h" #include "nrf_gpio.h" #include "nrfx_gpiote.h" +#ifdef BLUETOOTH_SD #include "nrf_soc.h" +#endif #include #define WPIN_UNUSED 0xFF diff --git a/ports/nordic/common-hal/microcontroller/__init__.c b/ports/nordic/common-hal/microcontroller/__init__.c index fbb40afe044..d5752fb46b6 100644 --- a/ports/nordic/common-hal/microcontroller/__init__.c +++ b/ports/nordic/common-hal/microcontroller/__init__.c @@ -24,7 +24,9 @@ #include "supervisor/port.h" #include "supervisor/shared/safe_mode.h" #include "nrfx_glue.h" +#ifdef BLUETOOTH_SD #include "nrf_nvic.h" +#endif #include "nrf_power.h" // This routine should work even when interrupts are disabled. Used by OneWire @@ -45,7 +47,14 @@ void common_hal_mcu_disable_interrupts(void) { // This only disables interrupts of priority 2 through 7; levels 0, 1, // and 4, are exclusive to softdevice and should never be used, so // this limitation is not important. + #ifdef BLUETOOTH_SD sd_nvic_critical_region_enter(&is_nested_critical_region); + #else + // With no SoftDevice to leave room for, mask everything. Record whether + // interrupts were already masked so the matching exit leaves them so. + is_nested_critical_region = __get_PRIMASK() ? 1 : 0; + __disable_irq(); + #endif } __DMB(); nesting_count++; @@ -61,7 +70,13 @@ void common_hal_mcu_enable_interrupts(void) { return; } __DMB(); + #ifdef BLUETOOTH_SD sd_nvic_critical_region_exit(is_nested_critical_region); + #else + if (!is_nested_critical_region) { + __enable_irq(); + } + #endif } void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { @@ -70,11 +85,16 @@ void common_hal_mcu_on_next_reset(mcu_runmode_t runmode) { if (runmode == RUNMODE_BOOTLOADER || runmode == RUNMODE_UF2) { new_value = DFU_MAGIC_UF2_RESET; } + #ifdef BLUETOOTH_SD int err_code = sd_power_gpregret_set(0, DFU_MAGIC_UF2_RESET); if (err_code != NRF_SUCCESS) { // Set it without the soft device if the SD failed. (It may be off.) nrf_power_gpregret_set(NRF_POWER, new_value); } + #else + // No SoftDevice, so write GPREGRET directly. + nrf_power_gpregret_set(NRF_POWER, new_value); + #endif if (runmode == RUNMODE_SAFE_MODE) { safe_mode_on_next_reset(SAFE_MODE_PROGRAMMATIC); } diff --git a/ports/nordic/common-hal/neopixel_write/__init__.c b/ports/nordic/common-hal/neopixel_write/__init__.c index 66a1d70e869..e9f3a0fdacc 100644 --- a/ports/nordic/common-hal/neopixel_write/__init__.c +++ b/ports/nordic/common-hal/neopixel_write/__init__.c @@ -125,7 +125,9 @@ void common_hal_neopixel_write(const digitalio_digitalinout_obj_t *digitalinout, pixels_pattern = (uint16_t *)stack_pixels; } else { uint8_t sd_en = 0; + #ifdef BLUETOOTH_SD (void)sd_softdevice_is_enabled(&sd_en); + #endif if (pixels_pattern_heap_size < pattern_size) { // Current heap buffer is too small. diff --git a/ports/nordic/device/nrf52/startup_nrf52840.c b/ports/nordic/device/nrf52/startup_nrf52840.c index 6b81fac2a9c..f16902fb30a 100644 --- a/ports/nordic/device/nrf52/startup_nrf52840.c +++ b/ports/nordic/device/nrf52/startup_nrf52840.c @@ -27,8 +27,23 @@ void Default_Handler(void) { } } +extern const func __Vectors[]; + +#ifndef BLUETOOTH_SD +// SCB->VTOR, addressed directly so the startup file need not pull in CMSIS. +#define SCB_VTOR (*(volatile uint32_t *)0xE000ED08UL) +#endif + extern void Reset_Handler(void); void Reset_Handler(void) { + #ifndef BLUETOOTH_SD + // With a SoftDevice, the MBR at 0x0 owns the vector table and forwards + // interrupts to us, so VTOR is already pointing at our table by the time we + // run. Without one, nothing has set it. + SCB_VTOR = (uint32_t)&__Vectors[0]; + __asm volatile ("dsb 0xF" ::: "memory"); + #endif + uint32_t *p_src = &_sidata; uint32_t *p_dest = &_sdata; diff --git a/ports/nordic/mpconfigport.h b/ports/nordic/mpconfigport.h index 33fcfa371e0..6ed1ea1f82d 100644 --- a/ports/nordic/mpconfigport.h +++ b/ports/nordic/mpconfigport.h @@ -7,10 +7,18 @@ #pragma once +#ifdef BLUETOOTH_SD #include "ble_drv.h" #include "nrf_mbr.h" // for MBR_SIZE #include "nrf_sdm.h" // for SD_FLASH_SIZE +#else +// No SoftDevice: its headers are not on the include path at all, and neither the +// MBR nor the SoftDevice occupy any flash. +#define MBR_SIZE (0) +#define SD_FLASH_SIZE (0) +#endif + #include "peripherals/nrf/nvm.h" // for FLASH_PAGE_SIZE #define MICROPY_PY_SYS_STDIO_BUFFER (1) @@ -108,9 +116,13 @@ #define CIRCUITPY_INTERNAL_NVM_START_ADDR (CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_START_ADDR - CIRCUITPY_INTERNAL_NVM_SIZE) -// 32kiB for bonding, etc. +// 32kiB for bonding, etc. Nothing to store without a SoftDevice. #ifndef CIRCUITPY_BLE_CONFIG_SIZE +#ifdef BLUETOOTH_SD #define CIRCUITPY_BLE_CONFIG_SIZE (32 * 1024) +#else +#define CIRCUITPY_BLE_CONFIG_SIZE (0) +#endif #endif #define CIRCUITPY_BLE_CONFIG_START_ADDR (CIRCUITPY_INTERNAL_NVM_START_ADDR - CIRCUITPY_BLE_CONFIG_SIZE) @@ -159,7 +171,14 @@ // high enough to work and then check the mutation of the value done by sd_ble_enable(). // See common.template.ld. #ifndef SOFTDEVICE_RAM_SIZE +#ifdef BLUETOOTH_SD #define SOFTDEVICE_RAM_SIZE (56 * 1024) +#else +// No SoftDevice, so none of the low RAM is reserved for it. The SPIM3 buffer +// then sits at the very bottom of RAM, still inside the first 64kB as the +// hardware workaround requires. +#define SOFTDEVICE_RAM_SIZE (0) +#endif #endif diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index 028ceca9fcd..4c669ee1974 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -124,3 +124,10 @@ ifeq ($(INTERNAL_FLASH_FILESYSTEM),1) endif endif endif + +# Cannot have BLEIO without a SoftDevice. +ifeq ($(SD), ) +CIRCUITPY_BLEIO_NATIVE = 0 +CIRCUITPY_BLE_FILE_SERVICE = 0 +CIRCUITPY_BLE_SERIAL_SERVICE = 0 +endif diff --git a/ports/nordic/peripherals/nrf/nvm.h b/ports/nordic/peripherals/nrf/nvm.h index aff98094469..eedd73040d1 100644 --- a/ports/nordic/peripherals/nrf/nvm.h +++ b/ports/nordic/peripherals/nrf/nvm.h @@ -7,9 +7,13 @@ #pragma once +// Without a SoftDevice these do not arrive via nrf_sdm.h's include chain. +#include +#include + #define FLASH_PAGE_SIZE (4096) -#if BLUETOOTH_SD +#ifdef BLUETOOTH_SD bool sd_flash_page_erase_sync(uint32_t page_number); bool sd_flash_write_sync(uint32_t *dest_words, uint32_t *src_words, uint32_t num_words); #endif diff --git a/ports/nordic/supervisor/port.c b/ports/nordic/supervisor/port.c index 1eabfcbe216..a4fae3ce092 100644 --- a/ports/nordic/supervisor/port.c +++ b/ports/nordic/supervisor/port.c @@ -22,7 +22,10 @@ #include "nrf/power.h" #include "nrf/timers.h" +// The SoftDevice headers (nrf_sdm.h / nrf_soc.h) come in via mpconfigport.h. +#ifdef BLUETOOTH_SD #include "nrf_nvic.h" +#endif #include "common-hal/microcontroller/Pin.h" #include "common-hal/alarm/time/TimeAlarm.h" @@ -34,7 +37,6 @@ #include "common-hal/watchdog/WatchDogTimer.h" #include "common-hal/alarm/__init__.h" -#include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/rtc/__init__.h" @@ -323,6 +325,7 @@ void port_idle_until_interrupt(void) { (void)__get_FPSCR(); NVIC_ClearPendingIRQ(FPU_IRQn); } + #ifdef BLUETOOTH_SD uint8_t sd_enabled; sd_softdevice_is_enabled(&sd_enabled); @@ -330,7 +333,10 @@ void port_idle_until_interrupt(void) { if (!background_callback_pending()) { sd_app_evt_wait(); } - } else { + return; + } + #endif + { // Call wait for interrupt ourselves if the SD isn't enabled. // Note that `wfi` should be called with interrupts disabled, // to ensure that the queue is properly drained. The `wfi` From 66dd0b43c1c5e2c270ee05cbb28fa5a55735d862 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Tue, 25 Aug 2026 13:26:16 -0500 Subject: [PATCH 836/876] cleanup comments --- ports/nordic/Makefile | 4 +--- ports/nordic/device/nrf52/startup_nrf52840.c | 2 +- ports/nordic/mpconfigport.h | 2 -- ports/nordic/mpconfigport.mk | 2 +- ports/nordic/supervisor/port.c | 1 - 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index 83c15c5a463..dedc8790b89 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -8,9 +8,7 @@ include ../../py/circuitpy_mkenv.mk # The SoftDevice paths are built from MCU_VARIANT and SOFTDEV_VERSION, which # only exist once boards/$(BOARD)/mpconfigboard.mk has set MCU_CHIP. Skip when -# the rule requested is not board-specific (e.g. fetch-port-submodules), or the -# stack-missing check looks for an unexpanded path and fails on a tree where -# nothing is actually missing. +# the rule requested is not board-specific like fetch-port-submodules. ifneq ($(VALID_BOARD),) ifneq ($(SD), ) include bluetooth/bluetooth_common.mk diff --git a/ports/nordic/device/nrf52/startup_nrf52840.c b/ports/nordic/device/nrf52/startup_nrf52840.c index f16902fb30a..f602a86e079 100644 --- a/ports/nordic/device/nrf52/startup_nrf52840.c +++ b/ports/nordic/device/nrf52/startup_nrf52840.c @@ -39,7 +39,7 @@ void Reset_Handler(void) { #ifndef BLUETOOTH_SD // With a SoftDevice, the MBR at 0x0 owns the vector table and forwards // interrupts to us, so VTOR is already pointing at our table by the time we - // run. Without one, nothing has set it. + // run. SCB_VTOR = (uint32_t)&__Vectors[0]; __asm volatile ("dsb 0xF" ::: "memory"); #endif diff --git a/ports/nordic/mpconfigport.h b/ports/nordic/mpconfigport.h index 6ed1ea1f82d..7c1ba3e9655 100644 --- a/ports/nordic/mpconfigport.h +++ b/ports/nordic/mpconfigport.h @@ -13,8 +13,6 @@ #include "nrf_mbr.h" // for MBR_SIZE #include "nrf_sdm.h" // for SD_FLASH_SIZE #else -// No SoftDevice: its headers are not on the include path at all, and neither the -// MBR nor the SoftDevice occupy any flash. #define MBR_SIZE (0) #define SD_FLASH_SIZE (0) #endif diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index 4c669ee1974..17d9f19d4b1 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -125,7 +125,7 @@ endif endif endif -# Cannot have BLEIO without a SoftDevice. +# no BLEIO without a SoftDevice. ifeq ($(SD), ) CIRCUITPY_BLEIO_NATIVE = 0 CIRCUITPY_BLE_FILE_SERVICE = 0 diff --git a/ports/nordic/supervisor/port.c b/ports/nordic/supervisor/port.c index a4fae3ce092..0bb23364081 100644 --- a/ports/nordic/supervisor/port.c +++ b/ports/nordic/supervisor/port.c @@ -22,7 +22,6 @@ #include "nrf/power.h" #include "nrf/timers.h" -// The SoftDevice headers (nrf_sdm.h / nrf_soc.h) come in via mpconfigport.h. #ifdef BLUETOOTH_SD #include "nrf_nvic.h" #endif From 14a36a1e27d9954a0a6089277735476e512b308f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 25 Aug 2026 11:33:40 -0700 Subject: [PATCH 837/876] Add GD25Q64 fallbacks Newer runs of these boards may use it instead of W25Q64 --- .../boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk | 2 +- ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk | 2 +- .../boards/adafruit_macropad_rp2040/mpconfigboard.mk | 2 +- .../raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk | 2 +- ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk index 965acff2775..781dfe46ad1 100644 --- a/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_itsybitsy_rp2040/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk index f9e1e2cf157..08c85bb3f46 100644 --- a/ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_kb2040/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_macropad_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_macropad_rp2040/mpconfigboard.mk index 4d708bcf794..ea3d5a80fb9 100644 --- a/ports/raspberrypi/boards/adafruit_macropad_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_macropad_rp2040/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk index 5f07632b4f6..4252fafba2e 100644 --- a/ports/raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_qt2040_trinkey/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" diff --git a/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk b/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk index 8258f878336..2b8431454b0 100644 --- a/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk +++ b/ports/raspberrypi/boards/adafruit_qtpy_rp2040/mpconfigboard.mk @@ -6,4 +6,4 @@ USB_MANUFACTURER = "Adafruit" CHIP_VARIANT = RP2040 CHIP_FAMILY = rp2 -EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ" +EXTERNAL_FLASH_DEVICES = "W25Q64JVxQ,GD25Q64C" From aa83082217b845506cc7fb5c8c19ab124bdf05c6 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 25 Aug 2026 12:56:41 -0700 Subject: [PATCH 838/876] zephyr-cp: opt nucleo_n657x0_q out of ulab CI caught this one. The STM32N6 has no internal user flash and executes from RAM, which is already 93% full at 486984 of 523264 bytes, so the roughly 90 KB ulab adds overflows it by 56520 bytes. My earlier headroom survey only looked at FLASH figures and this board reports none, so it was missing from it. Rechecked both regions for every board: this is the only other one that cannot fit, and nordic_nrf7002dk stays out on flash. --- ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml index 83e6bcd39c4..e8de92166db 100644 --- a/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml +++ b/ports/zephyr-cp/boards/st/nucleo_n657x0_q/circuitpython.toml @@ -1 +1,5 @@ CIRCUITPY_BUILD_EXTENSIONS = ["hex"] + +# This part executes from RAM and is already at 93% of it, so it cannot +# absorb the roughly 90 KB ulab adds. +CIRCUITPY_ULAB = false From 60f5f49dcc03e9838caa8477d6285bb1d702f838 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 25 Aug 2026 13:01:06 -0700 Subject: [PATCH 839/876] Extend timeout of basic test --- ports/zephyr-cp/tests/bsim/test_bsim_basics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py index 3ef22470a38..12165750274 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_basics.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_basics.py @@ -14,7 +14,7 @@ @pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_CODE}) -@pytest.mark.duration(5) +@pytest.mark.duration(20) def test_bsim_dual_instance_connect(bsim_phy, circuitpython1, circuitpython2, board): """Run two bsim instances on the same sim id and verify UART output.""" From 09e4b2b5376cb3f864c8e55e03ef93752c1e44ff Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 25 Aug 2026 14:36:20 -0700 Subject: [PATCH 840/876] Support saved word in Zephyr This enables safe mode and maybe double tap to safe mode depending on if the chip clear RAM on reset or not. --- ports/zephyr-cp/supervisor/port.c | 84 +++++++++++++++++++++--- ports/zephyr-cp/tests/__init__.py | 37 +++++++++++ ports/zephyr-cp/tests/conftest.py | 4 ++ ports/zephyr-cp/tests/test_saved_word.py | 42 ++++++++++++ ports/zephyr-cp/zephyr-config/west.yml | 2 +- 5 files changed, 158 insertions(+), 11 deletions(-) create mode 100644 ports/zephyr-cp/tests/test_saved_word.py diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 1ecde0b0141..79fb500ca73 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -22,8 +22,10 @@ #if defined(CONFIG_ARCH_POSIX) #include +#include #include "cmdline.h" +#include "nsi_host_trampolines.h" #include "posix_board_if.h" #include "posix_native_task.h" #endif @@ -65,7 +67,13 @@ static struct k_timer tick_timer; static int32_t native_sim_vm_runs = INT32_MAX; static uint32_t native_sim_reset_port_count = 0; -static struct args_struct_t native_sim_reset_port_args[] = { +// Path to a file used to preserve retained memory across the execv reboot, or +// NULL if disabled. Set with --retained-memory= (see +// cp_saved_word_save/restore()). Currently persists the safe-mode saved word; +// intended to also preserve sleep RAM in the future. +static const char *native_sim_retained_memory; + +static struct args_struct_t native_sim_port_args[] = { { .option = "vm-runs", .name = "count", @@ -74,11 +82,20 @@ static struct args_struct_t native_sim_reset_port_args[] = { .descript = "Exit native_sim after this many VM runs. " "Example: --vm-runs=2" }, + { + .option = "retained-memory", + .name = "path", + .type = 's', + .dest = (void *)&native_sim_retained_memory, + .descript = "File used to preserve retained memory (e.g. the safe-mode " + "saved word) across the process re-exec reboot. " + "Example: --retained-memory=/tmp/cp_retained.bin" + }, ARG_TABLE_ENDMARKER }; static void native_sim_register_cmdline_opts(void) { - native_add_command_line_opts(native_sim_reset_port_args); + native_add_command_line_opts(native_sim_port_args); } NATIVE_TASK(native_sim_register_cmdline_opts, PRE_BOOT_1, 0); @@ -135,7 +152,57 @@ static void _tick_function(struct k_timer *timer_id) { supervisor_tick(); } +// Save and retrieve a word from memory that is preserved over reset. Used for safe mode. +static __noinit uint32_t cp_saved_word; + +void port_set_saved_word(uint32_t value) { + cp_saved_word = value; +} + +uint32_t port_get_saved_word(void) { + return cp_saved_word; +} + +// Save and restore retained memory across the native_sim/bsim reboot. +// Opt in with --retained-memory=. +#if defined(CONFIG_ARCH_POSIX) +static void cp_saved_word_save(void) { + const char *path = native_sim_retained_memory; + if (path == NULL || path[0] == '\0') { + return; + } + int fd = nsi_host_open(path, O_WRONLY | O_CREAT | O_TRUNC); + int fd = nsi_host_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) { + return; + } + uint32_t value = cp_saved_word; + (void)nsi_host_write(fd, &value, sizeof(value)); + (void)nsi_host_close(fd); +} + +static void cp_saved_word_restore(void) { + const char *path = native_sim_retained_memory; + if (path == NULL || path[0] == '\0') { + return; + } + int fd = nsi_host_open(path, O_RDONLY); + if (fd < 0) { + return; // First boot: no save file yet. + } + uint32_t value = 0; + (void)nsi_host_read(fd, &value, sizeof(value)); + (void)nsi_host_close(fd); + cp_saved_word = value; +} +#endif + safe_mode_t port_init(void) { + #if defined(CONFIG_ARCH_POSIX) + // Restore the saved word (if any) before wait_for_safe_mode_reset reads it. + cp_saved_word_restore(); + #endif + // We run CircuitPython at the lowest priority (just higher than idle.) // This allows networking and USB to preempt us. k_thread_priority_set(k_current_get(), CONFIG_NUM_PREEMPT_PRIORITIES - 1); @@ -146,6 +213,11 @@ safe_mode_t port_init(void) { // Reset the microcontroller completely. void reset_cpu(void) { + #if defined(CONFIG_ARCH_POSIX) + // Persist the saved word across the process re-exec reboot. + cp_saved_word_save(); + #endif + // Try a warm reboot first. It won't return if it works but isn't always // implemented. sys_reboot(SYS_REBOOT_WARM); @@ -206,14 +278,6 @@ uint32_t *port_stack_get_top(void) { return (uint32_t *)(stack_info.start + stack_info.size - stack_info.delta); } -// Save and retrieve a word from memory that is preserved over reset. Used for safe mode. -void port_set_saved_word(uint32_t) { - -} -uint32_t port_get_saved_word(void) { - return 0; -} - uint64_t port_get_raw_ticks(uint8_t *subticks) { // Make sure time advances in the simulator. #if defined(CONFIG_ARCH_POSIX) diff --git a/ports/zephyr-cp/tests/__init__.py b/ports/zephyr-cp/tests/__init__.py index e9039dd88b3..c042d744d7d 100644 --- a/ports/zephyr-cp/tests/__init__.py +++ b/ports/zephyr-cp/tests/__init__.py @@ -138,6 +138,43 @@ def __init__(self, cmd, timeout=5, trace_file=None, env=None, flash_file=None): self.debug_serial = SerialSaver( StdSerial(self._proc.stdin, self._proc.stdout), name="debug" ) + # Offset into debug_serial output for finding the next UART PTY path. + self._pty_search_offset = 0 + + def reconnect_serial(self, timeout=30.0): + """Wait for the simulator to reboot (execv) and reopen the UART. + + native_sim/bsim reboot by re-executing the process; the UART PTY master + fd is O_CLOEXEC so it closes on execv and a new PTY is opened. The new + "connected to pseudotty: " line is printed to the process stdout + (which survives execv), so it shows up in debug_serial. This method waits + for that line and reopens ``self.serial`` on the new PTY. + """ + import time + + marker = "connected to pseudotty:" + deadline = time.monotonic() + timeout + while time.monotonic() < deadline: + if self._proc.poll() is not None: + return False + out = self.debug_serial.all_output + idx = out.find(marker, self._pty_search_offset) + newline = out.find("\n", idx) if idx >= 0 else -1 + if idx >= 0 and newline >= 0: + line = out[idx:newline] + pty_path = line.strip().rsplit(":", maxsplit=1)[1].strip() + self._pty_search_offset = newline + 1 + try: + self.serial.close() + except Exception: + pass + self.serial = SerialSaver( + serial.Serial(pty_path, baudrate=115200, timeout=0.05, write_timeout=0), + name="uart0", + ) + return True + time.sleep(0.05) + return False def shutdown(self): if self._proc.poll() is None: diff --git a/ports/zephyr-cp/tests/conftest.py b/ports/zephyr-cp/tests/conftest.py index 0efe3bcc3fe..86261c756aa 100644 --- a/ports/zephyr-cp/tests/conftest.py +++ b/ports/zephyr-cp/tests/conftest.py @@ -342,6 +342,10 @@ def circuitpython(request, board, sim_id, native_sim_binary, native_sim_env, tmp ) ) + # Always preserve retained memory (e.g. the safe-mode saved word) in + # in case of reboot. + cmd.append(f"--retained-memory={tmp_path / f'retained-{i}.bin'}") + if flash_erase_block_size is not None: cmd.append(f"--flash_erase_block_size={flash_erase_block_size}") if flash_write_block_size is not None: diff --git a/ports/zephyr-cp/tests/test_saved_word.py b/ports/zephyr-cp/tests/test_saved_word.py new file mode 100644 index 00000000000..0f93183f8e1 --- /dev/null +++ b/ports/zephyr-cp/tests/test_saved_word.py @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: 2025 Scott Shawcroft for Adafruit Industries +# SPDX-License-Identifier: MIT + +"""Test that the safe-mode saved word survives a hard reboot on native_sim/bsim. + +native_sim and the bsim boards reboot by re-executing the process (execv), +which wipes RAM (including .noinit). supervisor/port.c works around that by +persisting retained memory to a file across the reboot (the --retained-memory +flag); currently that holds the safe-mode saved word. + +The saved word drives safe-mode detection: ``microcontroller.on_next_reset( +RunMode.SAFE_MODE)`` arms the sentinel in the saved word, and a subsequent +``microcontroller.reset()`` reboots. If the word persisted, the next boot reads +the sentinel and enters safe mode (printed as "Running in safe mode!"). +""" + +import pytest + + +SAFE_MODE_RESET_CODE = """\ +import microcontroller +microcontroller.on_next_reset(microcontroller.RunMode.SAFE_MODE) +print("resetting") +microcontroller.reset() +""" + + +@pytest.mark.circuitpy_drive({"code.py": SAFE_MODE_RESET_CODE}) +@pytest.mark.duration(30) +def test_saved_word_survives_reboot_into_safe_mode(circuitpython): + """The saved word persists across a hard reboot and triggers safe mode.""" + circuitpython.serial.wait_for("resetting", timeout=20) + + # microcontroller.reset() re-execs the process; the UART PTY is O_CLOEXEC so + # a new one is opened after reboot. Reconnect to it. + assert circuitpython.reconnect_serial(timeout=20), "simulator did not reboot" + + # The next boot restores the saved word (the SAFE_MODE sentinel) and enters + # safe mode instead of running code.py. + circuitpython.serial.wait_for("Running in safe mode", timeout=20) + + assert "Running in safe mode" in circuitpython.serial.all_output diff --git a/ports/zephyr-cp/zephyr-config/west.yml b/ports/zephyr-cp/zephyr-config/west.yml index 32394fe224c..889580d9f9b 100644 --- a/ports/zephyr-cp/zephyr-config/west.yml +++ b/ports/zephyr-cp/zephyr-config/west.yml @@ -8,6 +8,6 @@ manifest: path: modules/bsim_hw_models/nrf_hw_models - name: zephyr url: https://github.com/adafruit/zephyr - revision: 62e7a3764b652fff733cee43f23f82217403a51d + revision: 499310df6e4da5ca54165c4b4c4c714771acb84c clone-depth: 100 import: true From 9f3be1714157679dbbf868b3121320f3b31f943f Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Tue, 25 Aug 2026 16:10:02 -0700 Subject: [PATCH 841/876] Extend timeout of most tests --- .../tests/bsim/test_bsim_ble_advertising.py | 10 ++++++---- .../zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py | 2 +- ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py | 2 +- .../tests/bsim/test_bsim_ble_packet_buffer.py | 12 ++++++------ ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py | 2 +- ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py | 12 ++++++------ 6 files changed, 21 insertions(+), 19 deletions(-) diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py index a46c8163eca..27fa78a5b7f 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -145,7 +145,7 @@ def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): @pytest.mark.zephyr_sample("tests/bsim/samples/observer") @pytest.mark.code_py_runs(2) -@pytest.mark.duration(25) +@pytest.mark.duration(60) @pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_INTERRUPT_RELOAD_CODE}) def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): """Ensure advertising resumes after Ctrl-C and a reload.""" @@ -156,7 +156,9 @@ def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): observer_count_before = observer.serial.all_output.count("Device found:") circuitpython.serial.write("\x03") - circuitpython.serial.wait_for("KeyboardInterrupt") + # Real AES for the link layer adds CPU overhead that can delay the + # interpreter noticing SIGINT beyond the default wait_for timeout. + circuitpython.serial.wait_for("KeyboardInterrupt", timeout=20) circuitpython.serial.write("\x04") circuitpython.wait_until_done() @@ -175,7 +177,7 @@ def test_bsim_advertise_ctrl_c_reload(bsim_phy, circuitpython, zephyr_sample): @pytest.mark.zephyr_sample("tests/bsim/samples/observer") -@pytest.mark.duration(20) +@pytest.mark.duration(40) @pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_DEFAULT_CODE}) def test_bsim_tx_power_default_rssi(board, bsim_phy, circuitpython, zephyr_sample): """Verify default TX power produces expected RSSI.""" @@ -202,7 +204,7 @@ def test_bsim_tx_power_default_rssi(board, bsim_phy, circuitpython, zephyr_sampl @pytest.mark.zephyr_sample("tests/bsim/samples/observer") -@pytest.mark.duration(20) +@pytest.mark.duration(40) @pytest.mark.circuitpy_drive({"code.py": BSIM_TX_POWER_LOW_CODE}) def test_bsim_tx_power_low_rssi(bsim_phy, circuitpython, zephyr_sample): """Verify low TX power reduces RSSI.""" diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py index d1b07859133..6d5cf418147 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_descriptor.py @@ -96,7 +96,7 @@ """ -@pytest.mark.duration(14) +@pytest.mark.duration(30) @pytest.mark.circuitpy_drive({"code.py": BSIM_DESC_SERVER_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_DESC_CLIENT_CODE}) def test_bsim_descriptor_user_description(bsim_phy, circuitpython1, circuitpython2): diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py index 08f93aea517..1336d37fbd0 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_nus.py @@ -154,7 +154,7 @@ def test_bsim_nus_peripheral(bsim_phy, circuitpython, zephyr_sample): """ -@pytest.mark.duration(14) +@pytest.mark.duration(30) @pytest.mark.circuitpy_drive({"code.py": BSIM_NUS_SERVER_CODE, **_ADAFRUIT_BLE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_NUS_CLIENT_CODE, **_ADAFRUIT_BLE}) def test_bsim_nus_cp_to_cp(bsim_phy, circuitpython1, circuitpython2): diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py index 8cf937bd34f..27bb703f379 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_packet_buffer.py @@ -109,7 +109,7 @@ """ -@pytest.mark.duration(14) +@pytest.mark.duration(25) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_SERVER_IN_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_IN_CODE}) def test_bsim_packet_buffer_server_incoming(bsim_phy, circuitpython1, circuitpython2): @@ -344,7 +344,7 @@ def test_bsim_packet_buffer_bidirectional(bsim_phy, circuitpython1, circuitpytho """ -@pytest.mark.duration(14) +@pytest.mark.duration(30) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_QUEUE_SERVER_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_QUEUE_CLIENT_CODE}) def test_bsim_packet_buffer_queue(bsim_phy, circuitpython1, circuitpython2): @@ -453,7 +453,7 @@ def test_bsim_packet_buffer_queue(bsim_phy, circuitpython1, circuitpython2): """ -@pytest.mark.duration(14) +@pytest.mark.duration(25) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_OVERFLOW_SERVER_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_OVERFLOW_CLIENT_CODE}) def test_bsim_packet_buffer_readinto_overflow(bsim_phy, circuitpython1, circuitpython2): @@ -555,7 +555,7 @@ def test_bsim_packet_buffer_readinto_overflow(bsim_phy, circuitpython1, circuitp """ -@pytest.mark.duration(14) +@pytest.mark.duration(25) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_HEADER_SERVER_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_HEADER_CLIENT_CODE}) def test_bsim_packet_buffer_write_header(bsim_phy, circuitpython1, circuitpython2): @@ -930,7 +930,7 @@ def test_bsim_packet_buffer_reconnect(bsim_phy, circuitpython1, circuitpython2): """ -@pytest.mark.duration(20) +@pytest.mark.duration(30) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_MTU_SERVER_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_MTU_CLIENT_CODE}) def test_bsim_packet_buffer_outgoing_mtu_bounded(bsim_phy, circuitpython1, circuitpython2): @@ -1099,7 +1099,7 @@ def test_bsim_packet_buffer_outgoing_mtu_bounded(bsim_phy, circuitpython1, circu """ -@pytest.mark.duration(20) +@pytest.mark.duration(35) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_WRITE_SERVER_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_PB_CLIENT_WRITE_CLIENT_CODE}) def test_bsim_packet_buffer_client_write(bsim_phy, circuitpython1, circuitpython2): diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py index a2618a851f2..9f58914ade4 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_scan.py @@ -111,7 +111,7 @@ def test_bsim_scan_zephyr_beacon(bsim_phy, circuitpython, zephyr_sample): @pytest.mark.zephyr_sample("bluetooth/beacon") @pytest.mark.code_py_runs(2) -@pytest.mark.duration(4) +@pytest.mark.duration(20) @pytest.mark.circuitpy_drive({"code.py": BSIM_SCAN_RELOAD_CODE}) def test_bsim_scan_zephyr_beacon_reload(bsim_phy, circuitpython, zephyr_sample): """Scan for Zephyr beacon, soft reload, and scan again.""" diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py index 8d19dc4d97b..1d4174835d0 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_service.py @@ -182,7 +182,7 @@ def test_bsim_service_battery(bsim_phy, circuitpython, zephyr_sample): """ -@pytest.mark.duration(14) +@pytest.mark.duration(30) @pytest.mark.circuitpy_drive( {"code.py": BSIM_SERVER_CODE, "battery_service.py": BATTERY_LIB, **_ADAFRUIT_BLE} ) @@ -299,7 +299,7 @@ def test_bsim_service_cp_client(bsim_phy, circuitpython1, circuitpython2): """ -@pytest.mark.duration(14) +@pytest.mark.duration(35) @pytest.mark.circuitpy_drive( { "code.py": BSIM_DISCOVER_ALL_SERVER_CODE, @@ -445,7 +445,7 @@ class MultiService(Service): """ -@pytest.mark.duration(14) +@pytest.mark.duration(25) @pytest.mark.circuitpy_drive( {"code.py": BSIM_MULTI_CHAR_SERVER_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} ) @@ -515,7 +515,7 @@ def test_bsim_service_write_no_response(bsim_phy, circuitpython1, circuitpython2 """ -@pytest.mark.duration(14) +@pytest.mark.duration(25) @pytest.mark.circuitpy_drive( {"code.py": BSIM_MULTI_CHAR_SERVER_CODE, "multi_service.py": MULTI_LIB, **_ADAFRUIT_BLE} ) @@ -630,7 +630,7 @@ class CustomService(Service): """ -@pytest.mark.duration(14) +@pytest.mark.duration(25) @pytest.mark.circuitpy_drive( {"code.py": BSIM_CUSTOM_UUID_SERVER_CODE, "custom_service.py": CUSTOM_LIB, **_ADAFRUIT_BLE} ) @@ -694,7 +694,7 @@ def test_bsim_service_custom_uuid(bsim_phy, circuitpython1, circuitpython2): """ -@pytest.mark.duration(14) +@pytest.mark.duration(30) @pytest.mark.circuitpy_drive( {"code.py": BSIM_CUSTOM_UUID_SERVER_CODE, "custom_service.py": CUSTOM_LIB, **_ADAFRUIT_BLE} ) From b01ccd623604a1a56132af1f7d63ce4cc8436e59 Mon Sep 17 00:00:00 2001 From: ladyada Date: Tue, 25 Aug 2026 19:30:31 -0400 Subject: [PATCH 842/876] raspberrypi: derive QMI PSRAM timings from clk_sys Co-authored-by: Limor Fried --- ports/raspberrypi/supervisor/port.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 8a8b9fb052c..8b858589c65 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -47,6 +47,7 @@ #include "supervisor/shared/stack.h" #include "supervisor/shared/tick.h" +#include "hardware/clocks.h" #include "hardware/structs/scb.h" #include "hardware/structs/watchdog.h" #include "hardware/gpio.h" @@ -152,6 +153,9 @@ static size_t _psram_size = 0; #include "hardware/structs/xip_ctrl.h" static void __no_inline_not_in_flash_func(setup_psram)(void) { + // Read the system clock before QMI goes into direct mode; clock_get_hz() is + // in flash and XIP is reconfigured below. + uint32_t sys_clk_mhz = clock_get_hz(clk_sys) / 1000000; gpio_set_function(CIRCUITPY_PSRAM_CHIP_SELECT->number, GPIO_FUNC_XIP_CS1); _psram_size = 0; common_hal_mcu_disable_interrupts(); @@ -237,13 +241,20 @@ static void __no_inline_not_in_flash_func(setup_psram)(void) { // Disable direct csr. qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS); + // MAX_SELECT is in units of 64 system clock cycles; PSRAM allows 8us max CS + // assertion. Use 7.5us so there is margin at any clk_sys. + uint32_t max_select = (75 * sys_clk_mhz) / 10 / 64; + // MIN_DESELECT is in system clock cycles; PSRAM needs 50ns min CS + // deassertion. Round up so we are never under. + uint32_t min_deselect = (50 * sys_clk_mhz + 999) / 1000; + qmi_hw->m[1].timing = QMI_M0_TIMING_PAGEBREAK_VALUE_1024 << QMI_M0_TIMING_PAGEBREAK_LSB | // Break between pages. 3 << QMI_M0_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles. 1 << QMI_M0_TIMING_COOLDOWN_LSB | 1 << QMI_M0_TIMING_RXDELAY_LSB | - 16 << QMI_M0_TIMING_MAX_SELECT_LSB | // In units of 64 system clock cycles. PSRAM says 8us max. 8 / 0.00752 / 64 = 16.62 - 7 << QMI_M0_TIMING_MIN_DESELECT_LSB | // In units of system clock cycles. PSRAM says 50ns.50 / 7.52 = 6.64 + max_select << QMI_M0_TIMING_MAX_SELECT_LSB | + min_deselect << QMI_M0_TIMING_MIN_DESELECT_LSB | 2 << QMI_M0_TIMING_CLKDIV_LSB; qmi_hw->m[1].rfmt = (QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB | From e73f1745ef5c5d16a215f07153e8e215d37d4ed8 Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 26 Aug 2026 07:56:19 -0500 Subject: [PATCH 843/876] fix nosd build --- ports/nordic/mpconfigport.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ports/nordic/mpconfigport.h b/ports/nordic/mpconfigport.h index 7c1ba3e9655..704e59355dc 100644 --- a/ports/nordic/mpconfigport.h +++ b/ports/nordic/mpconfigport.h @@ -12,9 +12,6 @@ #include "nrf_mbr.h" // for MBR_SIZE #include "nrf_sdm.h" // for SD_FLASH_SIZE -#else -#define MBR_SIZE (0) -#define SD_FLASH_SIZE (0) #endif #include "peripherals/nrf/nvm.h" // for FLASH_PAGE_SIZE @@ -50,6 +47,17 @@ // Definitions that might be overridden by mpconfigboard.h +#ifndef BLUETOOTH_SD + +#ifndef MBR_SIZE +#define MBR_SIZE (0x1000) +#endif + +#ifndef SD_FLASH_SIZE +#define SD_FLASH_SIZE (0) +#endif +#endif + #ifndef CIRCUITPY_INTERNAL_NVM_SIZE #define CIRCUITPY_INTERNAL_NVM_SIZE (8 * 1024) #endif @@ -114,13 +122,8 @@ #define CIRCUITPY_INTERNAL_NVM_START_ADDR (CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_START_ADDR - CIRCUITPY_INTERNAL_NVM_SIZE) -// 32kiB for bonding, etc. Nothing to store without a SoftDevice. #ifndef CIRCUITPY_BLE_CONFIG_SIZE -#ifdef BLUETOOTH_SD #define CIRCUITPY_BLE_CONFIG_SIZE (32 * 1024) -#else -#define CIRCUITPY_BLE_CONFIG_SIZE (0) -#endif #endif #define CIRCUITPY_BLE_CONFIG_START_ADDR (CIRCUITPY_INTERNAL_NVM_START_ADDR - CIRCUITPY_BLE_CONFIG_SIZE) From da608c7b4ae22c41d721d68ab111c9fa702a119e Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 26 Aug 2026 08:04:48 -0500 Subject: [PATCH 844/876] cleanup comments --- ports/nordic/Makefile | 4 +--- ports/nordic/mpconfigport.h | 5 ++--- ports/nordic/peripherals/nrf/nvm.h | 1 - 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index dedc8790b89..bddc1a2ef80 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -6,9 +6,7 @@ include ../../py/circuitpy_mkenv.mk -# The SoftDevice paths are built from MCU_VARIANT and SOFTDEV_VERSION, which -# only exist once boards/$(BOARD)/mpconfigboard.mk has set MCU_CHIP. Skip when -# the rule requested is not board-specific like fetch-port-submodules. +# Skip when the make command is not board-specific i.e. fetch-port-submodules. ifneq ($(VALID_BOARD),) ifneq ($(SD), ) include bluetooth/bluetooth_common.mk diff --git a/ports/nordic/mpconfigport.h b/ports/nordic/mpconfigport.h index 704e59355dc..d926da73596 100644 --- a/ports/nordic/mpconfigport.h +++ b/ports/nordic/mpconfigport.h @@ -122,6 +122,7 @@ #define CIRCUITPY_INTERNAL_NVM_START_ADDR (CIRCUITPY_INTERNAL_FLASH_FILESYSTEM_START_ADDR - CIRCUITPY_INTERNAL_NVM_SIZE) +// 32kiB for bonding, etc. #ifndef CIRCUITPY_BLE_CONFIG_SIZE #define CIRCUITPY_BLE_CONFIG_SIZE (32 * 1024) #endif @@ -175,9 +176,7 @@ #ifdef BLUETOOTH_SD #define SOFTDEVICE_RAM_SIZE (56 * 1024) #else -// No SoftDevice, so none of the low RAM is reserved for it. The SPIM3 buffer -// then sits at the very bottom of RAM, still inside the first 64kB as the -// hardware workaround requires. + #define SOFTDEVICE_RAM_SIZE (0) #endif #endif diff --git a/ports/nordic/peripherals/nrf/nvm.h b/ports/nordic/peripherals/nrf/nvm.h index eedd73040d1..10bf92d90cf 100644 --- a/ports/nordic/peripherals/nrf/nvm.h +++ b/ports/nordic/peripherals/nrf/nvm.h @@ -7,7 +7,6 @@ #pragma once -// Without a SoftDevice these do not arrive via nrf_sdm.h's include chain. #include #include From bc297d097b28b375da0b20e90c405a847aaa385c Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 26 Aug 2026 08:50:12 -0500 Subject: [PATCH 845/876] support external_clock on I2SOut in nordic --- ports/nordic/common-hal/audiobusio/I2SOut.c | 28 ++++++++++++++++----- ports/nordic/common-hal/audiobusio/I2SOut.h | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.c b/ports/nordic/common-hal/audiobusio/I2SOut.c index fbdaa93cfa4..46b9279cbcc 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.c +++ b/ports/nordic/common-hal/audiobusio/I2SOut.c @@ -16,6 +16,8 @@ #include "py/obj.h" #include "py/runtime.h" +#include "nrf_gpio.h" + static audiobusio_i2sout_obj_t *instance; struct { int16_t l, r; @@ -191,9 +193,6 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, const mcu_pin_obj_t *bit_clock, const mcu_pin_obj_t *word_select, const mcu_pin_obj_t *data, const mcu_pin_obj_t *main_clock, bool left_justified, bool external_clock) { - if (external_clock) { - mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_external_clock); - } if (main_clock != NULL) { mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_main_clock); } @@ -206,14 +205,23 @@ void common_hal_audiobusio_i2sout_construct(audiobusio_i2sout_obj_t *self, claim_pin(word_select); claim_pin(data); + self->external_clock = external_clock; + NRF_I2S->PSEL.SCK = self->bit_clock_pin_number = bit_clock->number; NRF_I2S->PSEL.LRCK = self->word_select_pin_number = word_select->number; NRF_I2S->PSEL.SDOUT = self->data_pin_number = data->number; - NRF_I2S->CONFIG.MODE = I2S_CONFIG_MODE_MODE_Master; + if (external_clock) { + nrf_gpio_cfg_input(bit_clock->number, NRF_GPIO_PIN_NOPULL); + nrf_gpio_cfg_input(word_select->number, NRF_GPIO_PIN_NOPULL); + } + + NRF_I2S->CONFIG.MODE = external_clock ? I2S_CONFIG_MODE_MODE_Slave + : I2S_CONFIG_MODE_MODE_Master; NRF_I2S->CONFIG.RXEN = I2S_CONFIG_RXEN_RXEN_Disabled; NRF_I2S->CONFIG.TXEN = I2S_CONFIG_TXEN_TXEN_Enabled; - NRF_I2S->CONFIG.MCKEN = I2S_CONFIG_MCKEN_MCKEN_Enabled; + NRF_I2S->CONFIG.MCKEN = external_clock ? I2S_CONFIG_MCKEN_MCKEN_Disabled + : I2S_CONFIG_MCKEN_MCKEN_Enabled; NRF_I2S->CONFIG.SWIDTH = I2S_CONFIG_SWIDTH_SWIDTH_16Bit; NRF_I2S->CONFIG.ALIGN = I2S_CONFIG_ALIGN_ALIGN_Left; @@ -233,6 +241,10 @@ void common_hal_audiobusio_i2sout_deinit(audiobusio_i2sout_obj_t *self) { } NRF_I2S->TASKS_STOP = 1; NRF_I2S->ENABLE = I2S_ENABLE_ENABLE_Disabled; + if (self->external_clock) { + nrf_gpio_cfg_default(self->bit_clock_pin_number); + nrf_gpio_cfg_default(self->word_select_pin_number); + } reset_pin_number(self->bit_clock_pin_number); self->bit_clock_pin_number = NO_PIN; reset_pin_number(self->word_select_pin_number); @@ -272,7 +284,11 @@ void common_hal_audiobusio_i2sout_play(audiobusio_i2sout_obj_t *self, ? I2S_CONFIG_CHANNELS_CHANNELS_Left : I2S_CONFIG_CHANNELS_CHANNELS_Stereo; - choose_i2s_clocking(self, sample_rate); + if (self->external_clock) { + self->sample_rate = sample_rate; + } else { + choose_i2s_clocking(self, sample_rate); + } /* Allocate buffers based on a maximum duration * This duration was chosen empirically based on what would * cause os.listdir('') to cause stuttering. It seems like a diff --git a/ports/nordic/common-hal/audiobusio/I2SOut.h b/ports/nordic/common-hal/audiobusio/I2SOut.h index 33ec917eb64..27e077c0649 100644 --- a/ports/nordic/common-hal/audiobusio/I2SOut.h +++ b/ports/nordic/common-hal/audiobusio/I2SOut.h @@ -28,6 +28,7 @@ typedef struct { uint8_t bytes_per_sample; bool left_justified : 1; + bool external_clock : 1; bool playing : 1; bool stopping : 1; bool last_buffer : 1; From de881087ee508b92aa19532f8ef3bad13329a65e Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 26 Aug 2026 09:07:13 -0500 Subject: [PATCH 846/876] nordic analogio fix --- ports/nordic/common-hal/analogio/AnalogIn.c | 27 +++++++++++++-------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/ports/nordic/common-hal/analogio/AnalogIn.c b/ports/nordic/common-hal/analogio/AnalogIn.c index e48c9dd2e28..b9e6411a7c4 100644 --- a/ports/nordic/common-hal/analogio/AnalogIn.c +++ b/ports/nordic/common-hal/analogio/AnalogIn.c @@ -23,6 +23,9 @@ void analogin_init(void) { while (nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE) == 0) { } nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_CALIBRATEDONE); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_DONE); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_RESULTDONE); nrf_saadc_disable(NRF_SAADC); } @@ -56,7 +59,8 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { // Something else might have used the ADC in a different way, // so we completely re-initialize it. - nrf_saadc_value_t value = 0; + static volatile nrf_saadc_value_t value __attribute__((aligned(4))); + value = 0; const nrf_saadc_channel_config_t config = { .resistor_p = NRF_SAADC_RESISTOR_DISABLED, @@ -78,7 +82,12 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { nrf_saadc_channel_init(NRF_SAADC, CHANNEL_NO, &config); nrf_saadc_channel_input_set(NRF_SAADC, CHANNEL_NO, self->pin->adc_channel, self->pin->adc_channel); - nrf_saadc_buffer_init(NRF_SAADC, &value, 1); + nrf_saadc_buffer_init(NRF_SAADC, (nrf_saadc_value_t *)&value, 1); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_STARTED); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_END); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_DONE); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_RESULTDONE); + nrf_saadc_event_clear(NRF_SAADC, NRF_SAADC_EVENT_STOPPED); nrf_saadc_task_trigger(NRF_SAADC, NRF_SAADC_TASK_START); while (nrf_saadc_event_check(NRF_SAADC, NRF_SAADC_EVENT_STARTED) == 0) { @@ -100,23 +109,21 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { nrf_saadc_disable(NRF_SAADC); - // Adding the "asm volatile" memory fence here or anywhere after the declaration of `value` - // fixes an issue with gcc13 which causes `value` to always be zero. - // Compiling with gcc10 or gcc12 is fine. - // It can also be fixed by declaring `value` to be static. - // I think I'd like to declare `value` as volatile, but that causes type errors. asm volatile ("" : : : "memory"); // Disconnect ADC from pin. nrf_saadc_channel_input_set(NRF_SAADC, CHANNEL_NO, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); + // Read the DMA'd result exactly once. + int32_t result = value; + // value is signed and might be (slightly) < 0, even on single-ended conversions, so force to 0. - if (value < 0) { - value = 0; + if (result < 0) { + result = 0; } // Stretch 14-bit ADC reading to 16-bit range - return (value << 2) | (value >> 12); + return (result << 2) | (result >> 12); } float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) { From a8bb8c63b5deca2995f7df68874a18353daabbea Mon Sep 17 00:00:00 2001 From: ladyada Date: Wed, 26 Aug 2026 10:33:45 -0400 Subject: [PATCH 847/876] raspberrypi: update PSRAM timing after clock changes Co-authored-by: Limor Fried --- .../common-hal/microcontroller/Processor.c | 36 +++++++++++++++++++ .../common-hal/microcontroller/Processor.h | 4 +++ ports/raspberrypi/supervisor/port.c | 18 ++-------- 3 files changed, 42 insertions(+), 16 deletions(-) diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.c b/ports/raspberrypi/common-hal/microcontroller/Processor.c index c093a964c39..a5f4691c075 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.c +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.c @@ -10,6 +10,7 @@ #include "py/mphal.h" #include "py/runtime.h" #include "common-hal/microcontroller/Processor.h" +#include "shared-bindings/microcontroller/__init__.h" #include "shared-bindings/microcontroller/Processor.h" #include "shared-bindings/microcontroller/ResetReason.h" #include "shared-bindings/time/__init__.h" @@ -20,6 +21,11 @@ #include "hardware/vreg.h" #include "hardware/watchdog.h" +#ifdef CIRCUITPY_PSRAM_CHIP_SELECT +#include "hardware/regs/qmi.h" +#include "hardware/structs/qmi.h" +#endif + #if PICO_RP2040 #include "hardware/regs/vreg_and_chip_reset.h" #include "hardware/structs/vreg_and_chip_reset.h" @@ -50,6 +56,26 @@ uint32_t common_hal_mcu_processor_get_frequency(void) { return clock_get_hz(clk_sys); } +#ifdef CIRCUITPY_PSRAM_CHIP_SELECT +void __no_inline_not_in_flash_func(common_hal_mcu_processor_update_psram_timing)(uint32_t sys_clk_khz) { + // MAX_SELECT is in units of 64 system clock cycles; PSRAM allows 8 us max CS + // assertion. Use 7.5 us so there is margin at any clk_sys. + uint32_t max_select = (75 * sys_clk_khz) / 640000; + // MIN_DESELECT is in system clock cycles; PSRAM needs 50 ns min CS + // deassertion. Round up so we are never under. + uint32_t min_deselect = (sys_clk_khz + 19999) / 20000; + + qmi_hw->m[1].timing = + QMI_M0_TIMING_PAGEBREAK_VALUE_1024 << QMI_M0_TIMING_PAGEBREAK_LSB | // Break between pages. + 3 << QMI_M0_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles. + 1 << QMI_M0_TIMING_COOLDOWN_LSB | + 1 << QMI_M0_TIMING_RXDELAY_LSB | + max_select << QMI_M0_TIMING_MAX_SELECT_LSB | + min_deselect << QMI_M0_TIMING_MIN_DESELECT_LSB | + 2 << QMI_M0_TIMING_CLKDIV_LSB; +} +#endif + void common_hal_mcu_processor_set_frequency(mcu_processor_obj_t *self, uint32_t frequency) { uint vco, postdiv1, postdiv2; uint32_t freq_khz = frequency / 1000; @@ -68,7 +94,17 @@ void common_hal_mcu_processor_set_frequency(mcu_processor_obj_t *self, uint32_t vreg_set_voltage(voltage); // Wait for a stable voltage common_hal_time_delay_ms(10); + + #ifdef CIRCUITPY_PSRAM_CHIP_SELECT + // Prevent interrupt handlers from accessing PSRAM until its timing matches + // the new system clock. + common_hal_mcu_disable_interrupts(); + #endif set_sys_clock_khz(freq_khz, false); + #ifdef CIRCUITPY_PSRAM_CHIP_SELECT + common_hal_mcu_processor_update_psram_timing(freq_khz); + common_hal_mcu_enable_interrupts(); + #endif } void common_hal_mcu_processor_get_uid(uint8_t raw_id[]) { diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.h b/ports/raspberrypi/common-hal/microcontroller/Processor.h index df1e1cf2333..bf3293672b9 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.h +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.h @@ -16,3 +16,7 @@ typedef struct { mp_obj_base_t base; // Stores no state currently. } mcu_processor_obj_t; + +#ifdef CIRCUITPY_PSRAM_CHIP_SELECT +void common_hal_mcu_processor_update_psram_timing(uint32_t sys_clk_khz); +#endif diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 8b858589c65..23917061abd 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -155,7 +155,7 @@ static size_t _psram_size = 0; static void __no_inline_not_in_flash_func(setup_psram)(void) { // Read the system clock before QMI goes into direct mode; clock_get_hz() is // in flash and XIP is reconfigured below. - uint32_t sys_clk_mhz = clock_get_hz(clk_sys) / 1000000; + uint32_t sys_clk_khz = clock_get_hz(clk_sys) / 1000; gpio_set_function(CIRCUITPY_PSRAM_CHIP_SELECT->number, GPIO_FUNC_XIP_CS1); _psram_size = 0; common_hal_mcu_disable_interrupts(); @@ -241,21 +241,7 @@ static void __no_inline_not_in_flash_func(setup_psram)(void) { // Disable direct csr. qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS); - // MAX_SELECT is in units of 64 system clock cycles; PSRAM allows 8us max CS - // assertion. Use 7.5us so there is margin at any clk_sys. - uint32_t max_select = (75 * sys_clk_mhz) / 10 / 64; - // MIN_DESELECT is in system clock cycles; PSRAM needs 50ns min CS - // deassertion. Round up so we are never under. - uint32_t min_deselect = (50 * sys_clk_mhz + 999) / 1000; - - qmi_hw->m[1].timing = - QMI_M0_TIMING_PAGEBREAK_VALUE_1024 << QMI_M0_TIMING_PAGEBREAK_LSB | // Break between pages. - 3 << QMI_M0_TIMING_SELECT_HOLD_LSB | // Delay releasing CS for 3 extra system cycles. - 1 << QMI_M0_TIMING_COOLDOWN_LSB | - 1 << QMI_M0_TIMING_RXDELAY_LSB | - max_select << QMI_M0_TIMING_MAX_SELECT_LSB | - min_deselect << QMI_M0_TIMING_MIN_DESELECT_LSB | - 2 << QMI_M0_TIMING_CLKDIV_LSB; + common_hal_mcu_processor_update_psram_timing(sys_clk_khz); qmi_hw->m[1].rfmt = (QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB | QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB | From c31adb67e5b92cf3a3e08baacdede8a8b8272f7f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 26 Aug 2026 11:32:17 -0500 Subject: [PATCH 848/876] remove asm volatile fence --- ports/nordic/common-hal/analogio/AnalogIn.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ports/nordic/common-hal/analogio/AnalogIn.c b/ports/nordic/common-hal/analogio/AnalogIn.c index b9e6411a7c4..1459c67c08c 100644 --- a/ports/nordic/common-hal/analogio/AnalogIn.c +++ b/ports/nordic/common-hal/analogio/AnalogIn.c @@ -109,7 +109,6 @@ uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) { nrf_saadc_disable(NRF_SAADC); - asm volatile ("" : : : "memory"); // Disconnect ADC from pin. nrf_saadc_channel_input_set(NRF_SAADC, CHANNEL_NO, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED); From 399d2d0d0c1cf9cb78928100c322cacf6928426f Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Sun, 23 Aug 2026 18:50:59 +0000 Subject: [PATCH 849/876] ports/zephyr-cp: pass boards/.overlay and .conf for aliased boards Zephyr looks up boards/.overlay and boards/.conf by the resolved board name, so a board declared through cp_board_alias() never picks up files named after itself. The build succeeds and silently produces a firmware without the board's devicetree and Kconfig fragments. Pass the files as zephyr-cp_EXTRA_DTC_OVERLAY_FILE / _EXTRA_CONF_FILE when they exist. DEBUG=1 appends its fragment to the same list instead of replacing it. Verified with a board aliased to rpi_pico/rp2040 with both files present: zephyr.dts now cites the overlay and .config carries the board's options. Boards without such files are unaffected. --- ports/zephyr-cp/Makefile | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index a587892ed28..fe68fb82324 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -15,10 +15,27 @@ endif WEST_CMAKE_ARGS := -DZEPHYR_BOARD_ALIASES=$(CURDIR)/boards/board_aliases.cmake -Dzephyr-cp_TRANSLATION=$(TRANSLATION) +# Board files named after the CircuitPython board. Zephyr resolves boards/.overlay and +# boards/.conf by the ALIASED board name, so a board declared through cp_board_alias() never +# picks up files named after itself - the build silently produces a different firmware instead of +# warning. Pass them explicitly when they exist. +CP_BOARD_OVERLAY := $(wildcard $(CURDIR)/boards/$(BOARD).overlay) +ifneq ($(CP_BOARD_OVERLAY),) +WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_DTC_OVERLAY_FILE=$(CP_BOARD_OVERLAY) +endif +CP_BOARD_CONF := $(wildcard $(CURDIR)/boards/$(BOARD).conf) + # When DEBUG=1, apply additional Kconfig fragments for debug-friendly settings. DEBUG_CONF_FILE ?= $(CURDIR)/debug.conf ifeq ($(DEBUG),1) -WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_CONF_FILE=$(DEBUG_CONF_FILE) +ifneq ($(CP_BOARD_CONF),) +CP_BOARD_CONF := $(CP_BOARD_CONF);$(DEBUG_CONF_FILE) +else +CP_BOARD_CONF := $(DEBUG_CONF_FILE) +endif +endif +ifneq ($(CP_BOARD_CONF),) +WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_CONF_FILE=$(CP_BOARD_CONF) endif .PHONY: $(BUILD)/zephyr-cp/zephyr/zephyr.elf flash recover debug debug-jlink debugserver attach run run-sim clean menuconfig all clean-all sim clean-sim test fetch-port-submodules From d0f27bfc9754ff122314c3c803bc21faefc5f523 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Tue, 25 Aug 2026 16:05:28 +0000 Subject: [PATCH 850/876] ports/zephyr-cp: keep board overlays and Kconfig fragments in the board folder Each board now keeps board.overlay and board.conf next to its circuitpython.toml in boards///, rather than at the top level where files named after Zephyr boards and files named after CircuitPython boards shared one directory. Now that these files reliably reach the board they belong to, the replace-vs-add distinction starts to matter: the overlay goes through DTC_OVERLAY_FILE rather than EXTRA_DTC_OVERLAY_FILE, because a board overlay replaces app.overlay. That is why the overlays here include app.overlay themselves, and why the nRF54L15 DK, which has no USB, deliberately does not. The Kconfig fragment stays additive, so DEBUG=1 still appends its own. boards/frdm_rw612_rw612_cpu0.overlay is dropped: no build string matches that name, so it was never applied, and its devicetree does not parse. Verified by configuring all 29 boards before and after the move - the generated .config and devicetree are identical for every one. --- ports/zephyr-cp/AGENTS.md | 5 +++-- ports/zephyr-cp/Makefile | 20 ++++++++++++------- .../clue_nrf52840_zephyr/board.conf} | 0 .../clue_nrf52840_zephyr/board.overlay} | 2 +- .../feather_nrf52840_sense_zephyr/board.conf} | 0 .../board.overlay} | 2 +- .../feather_nrf52840_zephyr/board.conf} | 0 .../feather_nrf52840_zephyr/board.overlay} | 2 +- .../feather_rp2040_zephyr/board.conf} | 0 .../feather_rp2040_zephyr/board.overlay} | 2 +- .../boards/frdm_rw612_rw612_cpu0.overlay | 18 ----------------- .../native_sim/board.conf} | 0 .../native_sim/board.overlay} | 2 +- .../nrf5340bsim/board.conf} | 0 .../nrf5340bsim/board.overlay} | 0 .../nrf54lm20bsim/board.conf} | 0 .../nrf54lm20bsim/board.overlay} | 0 .../nrf5340dk/board.overlay} | 2 +- .../nrf54h20dk/board.conf} | 0 .../nrf54h20dk/board.overlay} | 2 +- .../nrf54l15dk/board.overlay} | 0 .../nrf54l15tag/board.conf} | 0 .../nrf54l15tag/board.overlay} | 0 .../nrf54lm20dk/board.conf} | 0 .../nrf54lm20dk/board.overlay} | 2 +- .../nrf7002dk/board.conf} | 0 .../nrf7002dk/board.overlay} | 2 +- .../frdm_mcxn947/board.conf} | 0 .../frdm_mcxn947/board.overlay} | 2 +- .../frdm_rw612/board.conf} | 0 .../frdm_rw612/board.overlay} | 2 +- .../mimxrt1170_evk/board.conf} | 0 .../mimxrt1170_evk/board.overlay} | 2 +- .../rpi_pico2_w_zephyr/board.conf} | 0 .../rpi_pico2_w_zephyr/board.overlay} | 2 +- .../rpi_pico2_zephyr/board.overlay} | 2 +- .../rpi_pico_w_zephyr/board.conf} | 0 .../rpi_pico_w_zephyr/board.overlay} | 2 +- .../rpi_pico_zephyr/board.overlay} | 2 +- .../da14695_dk_usb/board.overlay} | 2 +- .../ek_ra8d1/board.conf} | 0 .../ek_ra8d1/board.overlay} | 2 +- .../siwx917_dk2605a/board.conf} | 0 .../siwx917_dk2605a/board.overlay} | 0 .../stm32h750b_dk/board.conf} | 0 .../stm32h750b_dk/board.overlay} | 0 .../stm32h7b3i_dk/board.conf} | 0 .../stm32h7b3i_dk/board.overlay} | 2 +- .../stm32wba65i_dk1/board.conf} | 0 .../stm32wba65i_dk1/board.overlay} | 2 +- 50 files changed, 36 insertions(+), 47 deletions(-) rename ports/zephyr-cp/boards/{adafruit_clue_nrf52840_uf2.conf => adafruit/clue_nrf52840_zephyr/board.conf} (100%) rename ports/zephyr-cp/boards/{adafruit_clue_nrf52840_uf2.overlay => adafruit/clue_nrf52840_zephyr/board.overlay} (96%) rename ports/zephyr-cp/boards/{adafruit_feather_nrf52840_nrf52840_sense_uf2.conf => adafruit/feather_nrf52840_sense_zephyr/board.conf} (100%) rename ports/zephyr-cp/boards/{adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay => adafruit/feather_nrf52840_sense_zephyr/board.overlay} (96%) rename ports/zephyr-cp/boards/{adafruit_feather_nrf52840_uf2.conf => adafruit/feather_nrf52840_zephyr/board.conf} (100%) rename ports/zephyr-cp/boards/{adafruit_feather_nrf52840_uf2.overlay => adafruit/feather_nrf52840_zephyr/board.overlay} (96%) rename ports/zephyr-cp/boards/{adafruit_feather_rp2040.conf => adafruit/feather_rp2040_zephyr/board.conf} (100%) rename ports/zephyr-cp/boards/{adafruit_feather_rp2040.overlay => adafruit/feather_rp2040_zephyr/board.overlay} (96%) delete mode 100644 ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay rename ports/zephyr-cp/boards/{native_sim.conf => native/native_sim/board.conf} (100%) rename ports/zephyr-cp/boards/{native_sim.overlay => native/native_sim/board.overlay} (97%) rename ports/zephyr-cp/boards/{nrf5340bsim_nrf5340_cpuapp.conf => native/nrf5340bsim/board.conf} (100%) rename ports/zephyr-cp/boards/{nrf5340bsim_nrf5340_cpuapp.overlay => native/nrf5340bsim/board.overlay} (100%) rename ports/zephyr-cp/boards/{nrf54lm20bsim_nrf54lm20a_cpuapp.conf => native/nrf54lm20bsim/board.conf} (100%) rename ports/zephyr-cp/boards/{nrf54lm20bsim_nrf54lm20a_cpuapp.overlay => native/nrf54lm20bsim/board.overlay} (100%) rename ports/zephyr-cp/boards/{nrf5340dk_nrf5340_cpuapp.overlay => nordic/nrf5340dk/board.overlay} (95%) rename ports/zephyr-cp/boards/{nrf54h20dk_nrf54h20_cpuapp.conf => nordic/nrf54h20dk/board.conf} (100%) rename ports/zephyr-cp/boards/{nrf54h20dk_nrf54h20_cpuapp.overlay => nordic/nrf54h20dk/board.overlay} (96%) rename ports/zephyr-cp/boards/{nrf54l15dk_nrf54l15_cpuapp.overlay => nordic/nrf54l15dk/board.overlay} (100%) rename ports/zephyr-cp/boards/{nrf54l15tag_nrf54l15_cpuapp.conf => nordic/nrf54l15tag/board.conf} (100%) rename ports/zephyr-cp/boards/{nrf54l15tag_nrf54l15_cpuapp.overlay => nordic/nrf54l15tag/board.overlay} (100%) rename ports/zephyr-cp/boards/{nrf54lm20dk_nrf54lm20a_cpuapp.conf => nordic/nrf54lm20dk/board.conf} (100%) rename ports/zephyr-cp/boards/{nrf54lm20dk_nrf54lm20a_cpuapp.overlay => nordic/nrf54lm20dk/board.overlay} (97%) rename ports/zephyr-cp/boards/{nrf7002dk_nrf5340_cpuapp.conf => nordic/nrf7002dk/board.conf} (100%) rename ports/zephyr-cp/boards/{nrf7002dk_nrf5340_cpuapp.overlay => nordic/nrf7002dk/board.overlay} (90%) rename ports/zephyr-cp/boards/{frdm_mcxn947_mcxn947_cpu0.conf => nxp/frdm_mcxn947/board.conf} (100%) rename ports/zephyr-cp/boards/{frdm_mcxn947_mcxn947_cpu0.overlay => nxp/frdm_mcxn947/board.overlay} (94%) rename ports/zephyr-cp/boards/{frdm_rw612.conf => nxp/frdm_rw612/board.conf} (100%) rename ports/zephyr-cp/boards/{frdm_rw612.overlay => nxp/frdm_rw612/board.overlay} (93%) rename ports/zephyr-cp/boards/{mimxrt1170_evk_mimxrt1176_cm7.conf => nxp/mimxrt1170_evk/board.conf} (100%) rename ports/zephyr-cp/boards/{mimxrt1170_evk_mimxrt1176_cm7.overlay => nxp/mimxrt1170_evk/board.overlay} (93%) rename ports/zephyr-cp/boards/{rpi_pico2_rp2350a_m33_w.conf => raspberrypi/rpi_pico2_w_zephyr/board.conf} (100%) rename ports/zephyr-cp/boards/{rpi_pico2_rp2350a_m33.overlay => raspberrypi/rpi_pico2_w_zephyr/board.overlay} (95%) rename ports/zephyr-cp/boards/{rpi_pico2_rp2350a_m33_w.overlay => raspberrypi/rpi_pico2_zephyr/board.overlay} (95%) rename ports/zephyr-cp/boards/{rpi_pico_rp2040_w.conf => raspberrypi/rpi_pico_w_zephyr/board.conf} (100%) rename ports/zephyr-cp/boards/{rpi_pico_rp2040_w.overlay => raspberrypi/rpi_pico_w_zephyr/board.overlay} (96%) rename ports/zephyr-cp/boards/{rpi_pico_rp2040.overlay => raspberrypi/rpi_pico_zephyr/board.overlay} (96%) rename ports/zephyr-cp/boards/{da14695_dk_usb.overlay => renesas/da14695_dk_usb/board.overlay} (92%) rename ports/zephyr-cp/boards/{ek_ra8d1.conf => renesas/ek_ra8d1/board.conf} (100%) rename ports/zephyr-cp/boards/{ek_ra8d1.overlay => renesas/ek_ra8d1/board.overlay} (59%) rename ports/zephyr-cp/boards/{siwx917_dk2605a.conf => silabs/siwx917_dk2605a/board.conf} (100%) rename ports/zephyr-cp/boards/{siwx917_dk2605a.overlay => silabs/siwx917_dk2605a/board.overlay} (100%) rename ports/zephyr-cp/boards/{stm32h750b_dk_stm32h750xx_ext_flash_app.conf => st/stm32h750b_dk/board.conf} (100%) rename ports/zephyr-cp/boards/{stm32h750b_dk_stm32h750xx_ext_flash_app.overlay => st/stm32h750b_dk/board.overlay} (100%) rename ports/zephyr-cp/boards/{stm32h7b3i_dk.conf => st/stm32h7b3i_dk/board.conf} (100%) rename ports/zephyr-cp/boards/{stm32h7b3i_dk.overlay => st/stm32h7b3i_dk/board.overlay} (96%) rename ports/zephyr-cp/boards/{stm32wba65i_dk1.conf => st/stm32wba65i_dk1/board.conf} (100%) rename ports/zephyr-cp/boards/{stm32wba65i_dk1.overlay => st/stm32wba65i_dk1/board.overlay} (98%) diff --git a/ports/zephyr-cp/AGENTS.md b/ports/zephyr-cp/AGENTS.md index 58a3912e2ba..e8e240bde80 100644 --- a/ports/zephyr-cp/AGENTS.md +++ b/ports/zephyr-cp/AGENTS.md @@ -1,6 +1,7 @@ - Build a board by doing `make BOARD=_`. -- The corresponding configuration files are in `boards//` -- The files (not folders) in `boards/` directory are used by Zephyr. +- The corresponding configuration files are in `boards//`, including the + board's devicetree overlay (`board.overlay`) and Kconfig fragment (`board.conf`). The Makefile + passes them to Zephyr; the overlay replaces `app.overlay`, so include it if the board wants it. - To flash it on a board do `make BOARD=_ flash`. - Zephyr board docs are at `zephyr/boards//`. - Run zephyr-cp tests with `make test`. diff --git a/ports/zephyr-cp/Makefile b/ports/zephyr-cp/Makefile index fe68fb82324..fbde791afa9 100644 --- a/ports/zephyr-cp/Makefile +++ b/ports/zephyr-cp/Makefile @@ -15,15 +15,21 @@ endif WEST_CMAKE_ARGS := -DZEPHYR_BOARD_ALIASES=$(CURDIR)/boards/board_aliases.cmake -Dzephyr-cp_TRANSLATION=$(TRANSLATION) -# Board files named after the CircuitPython board. Zephyr resolves boards/.overlay and -# boards/.conf by the ALIASED board name, so a board declared through cp_board_alias() never -# picks up files named after itself - the build silently produces a different firmware instead of -# warning. Pass them explicitly when they exist. -CP_BOARD_OVERLAY := $(wildcard $(CURDIR)/boards/$(BOARD).overlay) +# Board files live in the board's own folder as board.overlay / board.conf. Zephyr only auto-applies +# boards/.overlay and boards/.conf named after the RESOLVED Zephyr board, so it finds +# neither those (wrong directory) nor files named after a board declared through cp_board_alias() +# (wrong name) - the build silently produces a different firmware instead of warning. Pass them +# explicitly when they exist. +CP_BOARD_DIR := $(CURDIR)/boards/$(firstword $(subst _, ,$(BOARD)))/$(patsubst $(firstword $(subst _, ,$(BOARD)))_%,%,$(BOARD)) +# DTC_OVERLAY_FILE, not EXTRA_: a board overlay REPLACES app.overlay (Zephyr only falls back to +# app.overlay when no board overlay is found), which is why the board overlays here include it +# themselves - and why one board that has no USB deliberately does not. Adding the overlay instead +# would force app.overlay on every board. socs/ ships .conf only, so nothing else is displaced. +CP_BOARD_OVERLAY := $(wildcard $(CP_BOARD_DIR)/board.overlay) ifneq ($(CP_BOARD_OVERLAY),) -WEST_CMAKE_ARGS += -Dzephyr-cp_EXTRA_DTC_OVERLAY_FILE=$(CP_BOARD_OVERLAY) +WEST_CMAKE_ARGS += -Dzephyr-cp_DTC_OVERLAY_FILE=$(CP_BOARD_OVERLAY) endif -CP_BOARD_CONF := $(wildcard $(CURDIR)/boards/$(BOARD).conf) +CP_BOARD_CONF := $(wildcard $(CP_BOARD_DIR)/board.conf) # When DEBUG=1, apply additional Kconfig fragments for debug-friendly settings. DEBUG_CONF_FILE ?= $(CURDIR)/debug.conf diff --git a/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.conf b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.conf similarity index 100% rename from ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.conf rename to ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.conf diff --git a/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.overlay b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.overlay similarity index 96% rename from ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.overlay rename to ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.overlay index 405b65ec8eb..586165dfe06 100644 --- a/ports/zephyr-cp/boards/adafruit_clue_nrf52840_uf2.overlay +++ b/ports/zephyr-cp/boards/adafruit/clue_nrf52840_zephyr/board.overlay @@ -46,4 +46,4 @@ status = "okay"; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.conf similarity index 100% rename from ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.conf rename to ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.conf diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.overlay similarity index 96% rename from ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay rename to ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.overlay index 405b65ec8eb..586165dfe06 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_nrf52840_sense_uf2.overlay +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_sense_zephyr/board.overlay @@ -46,4 +46,4 @@ status = "okay"; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.conf similarity index 100% rename from ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.conf rename to ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.conf diff --git a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.overlay similarity index 96% rename from ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay rename to ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.overlay index 405b65ec8eb..586165dfe06 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_nrf52840_uf2.overlay +++ b/ports/zephyr-cp/boards/adafruit/feather_nrf52840_zephyr/board.overlay @@ -46,4 +46,4 @@ status = "okay"; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.conf b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.conf similarity index 100% rename from ports/zephyr-cp/boards/adafruit_feather_rp2040.conf rename to ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.conf diff --git a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.overlay similarity index 96% rename from ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay rename to ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.overlay index a19e2a066db..10cc674a66a 100644 --- a/ports/zephyr-cp/boards/adafruit_feather_rp2040.overlay +++ b/ports/zephyr-cp/boards/adafruit/feather_rp2040_zephyr/board.overlay @@ -40,4 +40,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay b/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay deleted file mode 100644 index e57b5b6d331..00000000000 --- a/ports/zephyr-cp/boards/frdm_rw612_rw612_cpu0.overlay +++ /dev/null @@ -1,18 +0,0 @@ -&w25q512jvfiq { - partitions { - /delete-node/ storage_partition; - storage_partition: partition@620000 { - compatible = "zephyr,mapped-partition"; - label = "storage"; - reg = <0x00620000 DT_SIZE_K(32)>; - }; - circuitpy_partition: partition@628000 { - compatible = "zephyr,mapped-partition"; - label = "circuitpy"; - reg = <0x00628000 (DT_SIZE_M(58) - DT_SIZE_K(128) - DT_SIZE_K(32))>; - }; - } - -}; - -#include "../app.overlay" diff --git a/ports/zephyr-cp/boards/native_sim.conf b/ports/zephyr-cp/boards/native/native_sim/board.conf similarity index 100% rename from ports/zephyr-cp/boards/native_sim.conf rename to ports/zephyr-cp/boards/native/native_sim/board.conf diff --git a/ports/zephyr-cp/boards/native_sim.overlay b/ports/zephyr-cp/boards/native/native_sim/board.overlay similarity index 97% rename from ports/zephyr-cp/boards/native_sim.overlay rename to ports/zephyr-cp/boards/native/native_sim/board.overlay index f94f71726a8..d59a13db80d 100644 --- a/ports/zephyr-cp/boards/native_sim.overlay +++ b/ports/zephyr-cp/boards/native/native_sim/board.overlay @@ -60,4 +60,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/native/nrf5340bsim/board.conf similarity index 100% rename from ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.conf rename to ports/zephyr-cp/boards/native/nrf5340bsim/board.conf diff --git a/ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/native/nrf5340bsim/board.overlay similarity index 100% rename from ports/zephyr-cp/boards/nrf5340bsim_nrf5340_cpuapp.overlay rename to ports/zephyr-cp/boards/native/nrf5340bsim/board.overlay diff --git a/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf b/ports/zephyr-cp/boards/native/nrf54lm20bsim/board.conf similarity index 100% rename from ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.conf rename to ports/zephyr-cp/boards/native/nrf54lm20bsim/board.conf diff --git a/ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay b/ports/zephyr-cp/boards/native/nrf54lm20bsim/board.overlay similarity index 100% rename from ports/zephyr-cp/boards/nrf54lm20bsim_nrf54lm20a_cpuapp.overlay rename to ports/zephyr-cp/boards/native/nrf54lm20bsim/board.overlay diff --git a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nordic/nrf5340dk/board.overlay similarity index 95% rename from ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay rename to ports/zephyr-cp/boards/nordic/nrf5340dk/board.overlay index 180d6a23568..6b7ee85de7c 100644 --- a/ports/zephyr-cp/boards/nrf5340dk_nrf5340_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nordic/nrf5340dk/board.overlay @@ -29,4 +29,4 @@ i2s_rxtx: &i2s0 { /delete-node/ &slot1_partition; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf b/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.conf similarity index 100% rename from ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.conf rename to ports/zephyr-cp/boards/nordic/nrf54h20dk/board.conf diff --git a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay b/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.overlay similarity index 96% rename from ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay rename to ports/zephyr-cp/boards/nordic/nrf54h20dk/board.overlay index 10df6b9f282..e557179992b 100644 --- a/ports/zephyr-cp/boards/nrf54h20dk_nrf54h20_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nordic/nrf54h20dk/board.overlay @@ -52,4 +52,4 @@ /delete-node/ &slot1_partition; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/ports/zephyr-cp/boards/nordic/nrf54l15dk/board.overlay similarity index 100% rename from ports/zephyr-cp/boards/nrf54l15dk_nrf54l15_cpuapp.overlay rename to ports/zephyr-cp/boards/nordic/nrf54l15dk/board.overlay diff --git a/ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.conf b/ports/zephyr-cp/boards/nordic/nrf54l15tag/board.conf similarity index 100% rename from ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.conf rename to ports/zephyr-cp/boards/nordic/nrf54l15tag/board.conf diff --git a/ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.overlay b/ports/zephyr-cp/boards/nordic/nrf54l15tag/board.overlay similarity index 100% rename from ports/zephyr-cp/boards/nrf54l15tag_nrf54l15_cpuapp.overlay rename to ports/zephyr-cp/boards/nordic/nrf54l15tag/board.overlay diff --git a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.conf similarity index 100% rename from ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.conf rename to ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.conf diff --git a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.overlay similarity index 97% rename from ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay rename to ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.overlay index c1ebea74a70..0f48a5a5d46 100644 --- a/ports/zephyr-cp/boards/nrf54lm20dk_nrf54lm20a_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nordic/nrf54lm20dk/board.overlay @@ -1,5 +1,5 @@ // nRF54LM20 DK has USB. Include the main app overlay for USB CDC ACM console and data. -#include "../app.overlay" +#include "../../../app.overlay" // Link application starting at 0x0 instead of slot0_partition (no mcuboot yet). / { diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nordic/nrf7002dk/board.conf similarity index 100% rename from ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf rename to ports/zephyr-cp/boards/nordic/nrf7002dk/board.conf diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.overlay b/ports/zephyr-cp/boards/nordic/nrf7002dk/board.overlay similarity index 90% rename from ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.overlay rename to ports/zephyr-cp/boards/nordic/nrf7002dk/board.overlay index a02349aa7ad..30eb519f93b 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.overlay +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/board.overlay @@ -11,4 +11,4 @@ /delete-node/ &slot1_partition; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.conf similarity index 100% rename from ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.conf rename to ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.conf diff --git a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.overlay similarity index 94% rename from ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay rename to ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.overlay index f1a07471477..3eef280f220 100644 --- a/ports/zephyr-cp/boards/frdm_mcxn947_mcxn947_cpu0.overlay +++ b/ports/zephyr-cp/boards/nxp/frdm_mcxn947/board.overlay @@ -20,4 +20,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/frdm_rw612.conf b/ports/zephyr-cp/boards/nxp/frdm_rw612/board.conf similarity index 100% rename from ports/zephyr-cp/boards/frdm_rw612.conf rename to ports/zephyr-cp/boards/nxp/frdm_rw612/board.conf diff --git a/ports/zephyr-cp/boards/frdm_rw612.overlay b/ports/zephyr-cp/boards/nxp/frdm_rw612/board.overlay similarity index 93% rename from ports/zephyr-cp/boards/frdm_rw612.overlay rename to ports/zephyr-cp/boards/nxp/frdm_rw612/board.overlay index e926394817e..9153fd433ab 100644 --- a/ports/zephyr-cp/boards/frdm_rw612.overlay +++ b/ports/zephyr-cp/boards/nxp/frdm_rw612/board.overlay @@ -14,4 +14,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.conf similarity index 100% rename from ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.conf rename to ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.conf diff --git a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.overlay similarity index 93% rename from ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay rename to ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.overlay index b8f707dac27..cd5f0089494 100644 --- a/ports/zephyr-cp/boards/mimxrt1170_evk_mimxrt1176_cm7.overlay +++ b/ports/zephyr-cp/boards/nxp/mimxrt1170_evk/board.overlay @@ -18,4 +18,4 @@ mclk-output; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.conf similarity index 100% rename from ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.conf rename to ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.conf diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.overlay similarity index 95% rename from ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay rename to ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.overlay index ca0400b6645..c35cb42519a 100644 --- a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33.overlay +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_w_zephyr/board.overlay @@ -30,4 +30,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/board.overlay similarity index 95% rename from ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay rename to ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/board.overlay index ca0400b6645..c35cb42519a 100644 --- a/ports/zephyr-cp/boards/rpi_pico2_rp2350a_m33_w.overlay +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico2_zephyr/board.overlay @@ -30,4 +30,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.conf similarity index 100% rename from ports/zephyr-cp/boards/rpi_pico_rp2040_w.conf rename to ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.conf diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.overlay similarity index 96% rename from ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay rename to ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.overlay index 1cdd4ca2033..f1228e10138 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040_w.overlay +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_w_zephyr/board.overlay @@ -40,4 +40,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/board.overlay similarity index 96% rename from ports/zephyr-cp/boards/rpi_pico_rp2040.overlay rename to ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/board.overlay index f7da2fc90ae..16b3251df5a 100644 --- a/ports/zephyr-cp/boards/rpi_pico_rp2040.overlay +++ b/ports/zephyr-cp/boards/raspberrypi/rpi_pico_zephyr/board.overlay @@ -41,4 +41,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/da14695_dk_usb.overlay b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/board.overlay similarity index 92% rename from ports/zephyr-cp/boards/da14695_dk_usb.overlay rename to ports/zephyr-cp/boards/renesas/da14695_dk_usb/board.overlay index cc3b33ec447..6a8343384c9 100644 --- a/ports/zephyr-cp/boards/da14695_dk_usb.overlay +++ b/ports/zephyr-cp/boards/renesas/da14695_dk_usb/board.overlay @@ -16,4 +16,4 @@ }; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/ek_ra8d1.conf b/ports/zephyr-cp/boards/renesas/ek_ra8d1/board.conf similarity index 100% rename from ports/zephyr-cp/boards/ek_ra8d1.conf rename to ports/zephyr-cp/boards/renesas/ek_ra8d1/board.conf diff --git a/ports/zephyr-cp/boards/ek_ra8d1.overlay b/ports/zephyr-cp/boards/renesas/ek_ra8d1/board.overlay similarity index 59% rename from ports/zephyr-cp/boards/ek_ra8d1.overlay rename to ports/zephyr-cp/boards/renesas/ek_ra8d1/board.overlay index c13dfc457f5..416be7b510e 100644 --- a/ports/zephyr-cp/boards/ek_ra8d1.overlay +++ b/ports/zephyr-cp/boards/renesas/ek_ra8d1/board.overlay @@ -2,4 +2,4 @@ /delete-node/ partitions; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/siwx917_dk2605a.conf b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.conf similarity index 100% rename from ports/zephyr-cp/boards/siwx917_dk2605a.conf rename to ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.conf diff --git a/ports/zephyr-cp/boards/siwx917_dk2605a.overlay b/ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.overlay similarity index 100% rename from ports/zephyr-cp/boards/siwx917_dk2605a.overlay rename to ports/zephyr-cp/boards/silabs/siwx917_dk2605a/board.overlay diff --git a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.conf b/ports/zephyr-cp/boards/st/stm32h750b_dk/board.conf similarity index 100% rename from ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.conf rename to ports/zephyr-cp/boards/st/stm32h750b_dk/board.conf diff --git a/ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay b/ports/zephyr-cp/boards/st/stm32h750b_dk/board.overlay similarity index 100% rename from ports/zephyr-cp/boards/stm32h750b_dk_stm32h750xx_ext_flash_app.overlay rename to ports/zephyr-cp/boards/st/stm32h750b_dk/board.overlay diff --git a/ports/zephyr-cp/boards/stm32h7b3i_dk.conf b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.conf similarity index 100% rename from ports/zephyr-cp/boards/stm32h7b3i_dk.conf rename to ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.conf diff --git a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.overlay similarity index 96% rename from ports/zephyr-cp/boards/stm32h7b3i_dk.overlay rename to ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.overlay index d871e728e0d..75e497714c9 100644 --- a/ports/zephyr-cp/boards/stm32h7b3i_dk.overlay +++ b/ports/zephyr-cp/boards/st/stm32h7b3i_dk/board.overlay @@ -42,4 +42,4 @@ zephyr_udc0: &usbotg_hs { status = "okay"; }; -#include "../app.overlay" +#include "../../../app.overlay" diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.conf b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.conf similarity index 100% rename from ports/zephyr-cp/boards/stm32wba65i_dk1.conf rename to ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.conf diff --git a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.overlay similarity index 98% rename from ports/zephyr-cp/boards/stm32wba65i_dk1.overlay rename to ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.overlay index 25ef6321eab..e1fc7f0175e 100644 --- a/ports/zephyr-cp/boards/stm32wba65i_dk1.overlay +++ b/ports/zephyr-cp/boards/st/stm32wba65i_dk1/board.overlay @@ -73,4 +73,4 @@ zephyr_udc0: &usbotg_hs { interrupt-names = "radio", "radio-sw-low"; }; -#include "../app.overlay" +#include "../../../app.overlay" From 5be57b84f44a11bae05a25b153f3461725533c3b Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 24 Aug 2026 17:40:32 -0400 Subject: [PATCH 851/876] Keep the BLE workflow connection alive across VM restarts Typing at the "Press any key to enter the REPL" prompt over BLE workflow serial ended the session after exactly one character: the first byte breaks main.c's wait loop, which calls bleio_reset(), and the full stack disable/enable cycle there drops every connection, the workflow's included. Ctrl-D reloads dropped it the same way. bleio_user_reset() now tears down user BLE state individually on every VM reset: it stops user scanning and advertising (as before), and now also disconnects the connections that user code initiated or accepted with its own advertising. Connections are marked as user-owned when they are created: only user code connects in the central role, and a peripheral connection belongs to whoever started the advertising it answered. The BLE workflow connection is not user-owned and stays up. This does espressif's old "TODO: Don't stop BLE workflow connection." bleio_reset() still runs the full stack cycle, but only when user code created a GATT service, tracked by a flag set in the shared-bindings Service constructor. The cycle exists only to clear user services from the GATT table: the SoftDevice can do that no other way, and espressif for now matches it, though its NimBLE can delete individual services (a possible follow-up). When no user services exist, there is nothing to tear down and the workflow session survives. The supervisor constructs its workflow services through common-hal directly and does not set the flag. Since the full cycle no longer always runs, bleio_user_reset() also clears the adapter's and connections' pointers into the VM heap (connection objects, remote service lists, nordic's advertising data buffers), which the cycle used to clear implicitly. The adapter struct is a GC root, so a pointer left over from a dead heap would be scanned as a live object in the next VM. Also make the Service Changed indication work, so a bonded host discards its cached GATT table when a reload changed the services. nordic sent it only when the bonded system-attribute load succeeded, and the call never worked anyway: sd_ble_gatts_service_changed() rejects handles outside the application-populated attribute range, and it was called with (0xC, 0xFFFF), the error ignored. The populated range is now tracked as attributes are added and indicated on every bonded reconnect. espressif never signaled at all; it now calls ble_svc_gatt_changed() after the cycle rebuilds the table, which indicates connected peers immediately and bonded peers when they reconnect. Verified with btmon on both ports: the indication goes out with the real range, and the host confirms, rediscovers, and resubscribes. Applies to nordic and espressif, the ports that run the BLE workflow. Co-Authored-By: Claude Fable 5 --- main.c | 11 +++-- ports/espressif/common-hal/_bleio/Adapter.c | 12 +++-- .../espressif/common-hal/_bleio/Connection.h | 5 ++ ports/espressif/common-hal/_bleio/__init__.c | 49 +++++++++++++++++-- ports/nordic/common-hal/_bleio/Adapter.c | 11 +++++ ports/nordic/common-hal/_bleio/Adapter.h | 5 ++ .../nordic/common-hal/_bleio/Characteristic.c | 2 + ports/nordic/common-hal/_bleio/Connection.c | 22 ++++++--- ports/nordic/common-hal/_bleio/Connection.h | 5 ++ ports/nordic/common-hal/_bleio/Service.c | 4 ++ ports/nordic/common-hal/_bleio/__init__.c | 37 ++++++++++++++ ports/nordic/common-hal/_bleio/__init__.h | 8 +++ shared-bindings/_bleio/Service.c | 4 ++ shared-bindings/_bleio/__init__.c | 14 ++++++ shared-bindings/_bleio/__init__.h | 15 ++++++ 15 files changed, 186 insertions(+), 18 deletions(-) diff --git a/main.c b/main.c index 2020cb8c307..e2322524ab1 100644 --- a/main.c +++ b/main.c @@ -775,8 +775,10 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s // Done waiting, start the board back up. - // We delay resetting BLE until after the wait in case we're transferring - // more files over. + // Resetting BLE is delayed until here, after the wait, in case files were being + // transferred over the BLE workflow during the wait. The reset cycles the BLE + // stack, dropping the workflow connection, only if user code created GATT + // services; otherwise it is a no-op and the connection continues. #if CIRCUITPY_BLEIO bleio_reset(); #endif @@ -992,8 +994,9 @@ static int run_repl(safe_mode_t safe_mode) { #endif cleanup_after_vm(MP_OBJ_SENTINEL); - // Also reset bleio. The above call omits it in case workflows should continue. In this case, - // we're switching straight to another VM so we want to reset. + // Also reset bleio, which cleanup_after_vm() above omits so workflows can + // continue between VMs. As in run_code_py(), this cycles the BLE stack only if + // user code created GATT services. #if CIRCUITPY_BLEIO bleio_reset(); #endif diff --git a/ports/espressif/common-hal/_bleio/Adapter.c b/ports/espressif/common-hal/_bleio/Adapter.c index 61abdb219be..68be5b082c5 100644 --- a/ports/espressif/common-hal/_bleio/Adapter.c +++ b/ports/espressif/common-hal/_bleio/Adapter.c @@ -339,7 +339,7 @@ static int _mtu_reply(uint16_t conn_handle, return 0; } -static void _new_connection(uint16_t conn_handle) { +static void _new_connection(uint16_t conn_handle, bool user_owned) { // Set the tx_power for the connection higher than the advertisement. esp_ble_tx_power_set(conn_handle, ESP_PWR_LVL_N0); @@ -362,6 +362,7 @@ static void _new_connection(uint16_t conn_handle) { connection->connection_obj = mp_const_none; connection->pair_status = PAIR_NOT_PAIRED; connection->mtu = 0; + connection->user_owned = user_owned; ble_gattc_exchange_mtu(conn_handle, _mtu_reply, connection); @@ -379,7 +380,8 @@ static int _connect_event(struct ble_gap_event *event, void *self_in) { case BLE_GAP_EVENT_CONNECT: if (event->connect.status == 0) { // This triggers an MTU exchange. Its reply will exit the loop waiting for a connection. - _new_connection(event->connect.conn_handle); + // Only user code connects in the central role. + _new_connection(event->connect.conn_handle, true); // Set connections objs back to NULL since we have a new // connection and need a new tuple. self->connection_objs = NULL; @@ -498,7 +500,8 @@ static int _advertising_event(struct ble_gap_event *event, void *self_in) { #if !MYNEWT_VAL(BLE_EXT_ADV) if (event->connect.status == NIMBLE_OK) { - _new_connection(event->connect.conn_handle); + // The connection belongs to whoever started the advertising it answered. + _new_connection(event->connect.conn_handle, self->user_advertising); // Set connections objs back to NULL since we have a new // connection and need a new tuple. self->connection_objs = NULL; @@ -511,7 +514,8 @@ static int _advertising_event(struct ble_gap_event *event, void *self_in) { case BLE_GAP_EVENT_ADV_COMPLETE: #if MYNEWT_VAL(BLE_EXT_ADV) if (event->adv_complete.reason == NIMBLE_OK) { - _new_connection(event->adv_complete.conn_handle); + // The connection belongs to whoever started the advertising it answered. + _new_connection(event->adv_complete.conn_handle, self->user_advertising); // Set connections objs back to NULL since we have a new // connection and need a new tuple. self->connection_objs = NULL; diff --git a/ports/espressif/common-hal/_bleio/Connection.h b/ports/espressif/common-hal/_bleio/Connection.h index 5f33eb43b5d..176ed0ebfe4 100644 --- a/ports/espressif/common-hal/_bleio/Connection.h +++ b/ports/espressif/common-hal/_bleio/Connection.h @@ -31,6 +31,11 @@ typedef enum { typedef struct { uint16_t conn_handle; bool is_central; + // True if user code initiated or accepted this connection: it connected in the + // central role, or a central answered user code's advertising. User-owned + // connections are disconnected when the VM resets; the BLE workflow connection + // is not user-owned and stays up. + bool user_owned; // Remote services discovered when this peripheral is acting as a client. mp_obj_list_t *remote_service_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index 552ba0575b3..7a8fd2f36a5 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -24,6 +24,8 @@ #include "common-hal/_bleio/__init__.h" #include "common-hal/_bleio/ble_events.h" +#include "services/gatt/ble_svc_gatt.h" + #include "nvs_flash.h" static volatile int _completion_status; @@ -35,10 +37,29 @@ void bleio_user_reset(void) { if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { return; } - // Stop any user scanning or advertising, and stop all connections. - // TODO: Don't stop BLE workflow connection. - bleio_adapter_reset(&common_hal_bleio_adapter_obj); + // Stop any user scanning or advertising. + common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); + common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); + + // Disconnect the connections that user code initiated or accepted with its own + // advertising. Keep the BLE workflow connection if present. + // + // Remove each connection's pointers into the VM heap before disconnecting: + // the heap is about to go away, and a disconnect completes asynchronously. + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + connection->connection_obj = mp_const_none; + connection->remote_service_list = NULL; + if (connection->conn_handle != BLEIO_HANDLE_INVALID && connection->user_owned) { + common_hal_bleio_connection_disconnect(connection); + } + } + + // Now clear the adapter's remaining heap pointer, since it will be stale + // when the VM stops. + common_hal_bleio_adapter_obj.connection_objs = NULL; + // Also clean up event handlers that are on the heap. ble_event_remove_heap_handlers(); // Maybe start advertising the BLE workflow. @@ -52,11 +73,33 @@ void bleio_reset(void) { return; } + // The disable/enable cycle below clears user-created services from the GATT + // table, and it drops every connection, the BLE workflow's included. So run it + // only when user code created services. All other user BLE state has already + // been torn down individually by bleio_user_reset(). + // + // ESP-IDF NimBLE can delete individual services (ble_gatts_delete_svc(), used + // in Service.c), so a possible refinement is for bleio_user_reset() to delete + // user services one by one and never cycle the stack at all. For now this port + // matches nordic, whose SoftDevice can only clear services with a full cycle. + if (!bleio_user_services_created()) { + return; + } + bleio_clear_user_services_created(); + supervisor_stop_bluetooth(); ble_event_reset(); bleio_adapter_reset(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); supervisor_start_bluetooth(); + + // The cycle above rebuilt the GATT table, so bonded peers' cached tables are + // stale. Signal Service Changed over the whole handle range: NimBLE indicates + // connected subscribed peers immediately (there are none right after the + // cycle) and records the change for bonded peers, indicating them when they + // reconnect. Without this, a bonded host trusts its cache indefinitely and + // can look up characteristics at stale handles. + ble_svc_gatt_changed(0x0001, 0xffff); } // The singleton _bleio.Adapter object, bound to _bleio.adapter diff --git a/ports/nordic/common-hal/_bleio/Adapter.c b/ports/nordic/common-hal/_bleio/Adapter.c index 05edd832a8b..cd34212192b 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.c +++ b/ports/nordic/common-hal/_bleio/Adapter.c @@ -248,6 +248,10 @@ static bool adapter_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { connection->connection_obj = mp_const_none; connection->pair_status = PAIR_NOT_PAIRED; connection->mtu = 0; + // Only user code connects in the central role, and a peripheral + // connection belongs to whoever started the advertising it answered. + connection->user_owned = connected->role == BLE_GAP_ROLE_CENTRAL || + self->advertising_started_by_user; // Clear leftover bond state; connection slots are recycled. The // SoftDevice fills in only the keys the new peer distributes, so a // stale keyset could mix the previous peer's keys into this peer's @@ -385,6 +389,9 @@ void common_hal_bleio_adapter_set_enabled(bleio_adapter_obj_t *self, bool enable ble_drv_remove_event_handler(connection_on_ble_evt, connection); connection->conn_handle = BLE_CONN_HANDLE_INVALID; } + // The SoftDevice's GATT table is empty after an enable. + bleio_gatts_min_handle = 0xFFFF; + bleio_gatts_max_handle = 0; self->background_callback.fun = bluetooth_adapter_background; self->background_callback.data = self; bleio_adapter_reset_name(self); @@ -748,6 +755,9 @@ uint32_t _common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, if (self->current_advertising_data != NULL && self->current_advertising_data == self->advertising_data) { return NRF_ERROR_BUSY; } + // The supervisor calls this internal function directly; user code arrives via + // common_hal_bleio_adapter_start_advertising(), which overrides this to true. + self->advertising_started_by_user = false; // If the current advertising data isn't owned by the adapter then it must be an internal // advertisement that we should stop. @@ -928,6 +938,7 @@ void common_hal_bleio_adapter_start_advertising(bleio_adapter_obj_t *self, bool tx_power, directed_to)); self->user_advertising = true; + self->advertising_started_by_user = true; } void common_hal_bleio_adapter_stop_advertising(bleio_adapter_obj_t *self) { diff --git a/ports/nordic/common-hal/_bleio/Adapter.h b/ports/nordic/common-hal/_bleio/Adapter.h index 5bc1805d072..22e9e6dbded 100644 --- a/ports/nordic/common-hal/_bleio/Adapter.h +++ b/ports/nordic/common-hal/_bleio/Adapter.h @@ -38,6 +38,11 @@ typedef struct { ble_drv_evt_handler_entry_t advertising_handler_entry; background_callback_t background_callback; bool user_advertising; + // Whether the current (or most recent) advertising was started by user code + // rather than the supervisor. Unlike user_advertising, this is not cleared when + // advertising stops, so the connected-event handler can still read it: the + // advertising event handler runs first and has already stopped the advertising. + bool advertising_started_by_user; } bleio_adapter_obj_t; void bleio_adapter_gc_collect(bleio_adapter_obj_t *adapter); diff --git a/ports/nordic/common-hal/_bleio/Characteristic.c b/ports/nordic/common-hal/_bleio/Characteristic.c index 2e6042e48e7..413c97a3d6e 100644 --- a/ports/nordic/common-hal/_bleio/Characteristic.c +++ b/ports/nordic/common-hal/_bleio/Characteristic.c @@ -240,6 +240,8 @@ void common_hal_bleio_characteristic_add_descriptor(bleio_characteristic_obj_t * }; check_nrf_error(sd_ble_gatts_descriptor_add(self->handle, &desc_attr, &descriptor->handle)); + bleio_gatts_min_handle = MIN(bleio_gatts_min_handle, descriptor->handle); + bleio_gatts_max_handle = MAX(bleio_gatts_max_handle, descriptor->handle); mp_obj_list_append(MP_OBJ_FROM_PTR(self->descriptor_list), MP_OBJ_FROM_PTR(descriptor)); diff --git a/ports/nordic/common-hal/_bleio/Connection.c b/ports/nordic/common-hal/_bleio/Connection.c index f32034582b4..fbd3263b725 100644 --- a/ports/nordic/common-hal/_bleio/Connection.c +++ b/ports/nordic/common-hal/_bleio/Connection.c @@ -289,15 +289,23 @@ bool connection_on_ble_evt(ble_evt_t *ble_evt, void *self_in) { // mode >=1 and/or level >=1 means encryption is set up self->pair_status = PAIR_NOT_PAIRED; } else { - if (bonding_load_cccd_info(self->is_central, self->conn_handle, self->ediv)) { - // Did an sd_ble_gatts_sys_attr_set() with the stored sys_attr values. - // Indicate ATTR table change because we may have reloaded since the peer last - // connected. - sd_ble_gatts_service_changed(self->conn_handle, 0xC, 0xFFFF); - } else { - // No matching bonding found, so use fresh system attributes. + if (!bonding_load_cccd_info(self->is_central, self->conn_handle, self->ediv)) { + // No stored system attributes (CCCD values) found, so use fresh ones. sd_ble_gatts_sys_attr_set(self->conn_handle, NULL, 0, 0); } + if (self->ediv != EDIV_INVALID && bleio_gatts_min_handle <= bleio_gatts_max_handle) { + // The peer reconnected using a stored bond, and the GATT table may + // have changed since it last connected: a reload can add or remove + // user services. Indicate Service Changed so the peer discards its + // cached table. This must not be conditional on the sys-attr load + // above succeeding: a peer that missed the indication would trust a + // stale cache indefinitely, and saved system attributes are the + // less reliable of the two records. The error is ignored if the + // peer hasn't subscribed to indications yet. Both handles must be + // within the application-populated range: the SoftDevice rejects + // 0xFFFF, and also 0xC, which is inside its own GATT service. + (void)sd_ble_gatts_service_changed(self->conn_handle, bleio_gatts_min_handle, bleio_gatts_max_handle); + } self->pair_status = PAIR_PAIRED; } break; diff --git a/ports/nordic/common-hal/_bleio/Connection.h b/ports/nordic/common-hal/_bleio/Connection.h index ea1edf17603..78e2ccd5314 100644 --- a/ports/nordic/common-hal/_bleio/Connection.h +++ b/ports/nordic/common-hal/_bleio/Connection.h @@ -31,6 +31,11 @@ typedef enum { typedef struct { uint16_t conn_handle; bool is_central; + // True if user code initiated or accepted this connection: it connected in the + // central role, or a central answered user code's advertising. User-owned + // connections are disconnected when the VM resets; the BLE workflow connection + // is not user-owned and stays up. + bool user_owned; // Remote services discovered when this peripheral is acting as a client. mp_obj_list_t *remote_service_list; // The advertising data and scan response buffers are held by us, not by the SD, so we must diff --git a/ports/nordic/common-hal/_bleio/Service.c b/ports/nordic/common-hal/_bleio/Service.c index 1bd75f8a481..c187c54178d 100644 --- a/ports/nordic/common-hal/_bleio/Service.c +++ b/ports/nordic/common-hal/_bleio/Service.c @@ -46,6 +46,8 @@ uint32_t _common_hal_bleio_service_construct(bleio_service_obj_t *self, bleio_uu uint32_t result = sd_ble_gatts_service_add(service_type, &nordic_uuid, &self->handle); // Do a service changed indication to all connected peers. if (result == NRF_SUCCESS) { + bleio_gatts_min_handle = MIN(bleio_gatts_min_handle, self->handle); + bleio_gatts_max_handle = MAX(bleio_gatts_max_handle, self->handle); _indicate_service_change(self->handle, self->handle); } @@ -169,6 +171,8 @@ void common_hal_bleio_service_add_characteristic(bleio_service_obj_t *self, _expand_range(char_handles.cccd_handle, &start, &end); _expand_range(char_handles.sccd_handle, &start, &end); _expand_range(char_handles.user_desc_handle, &start, &end); + bleio_gatts_min_handle = MIN(bleio_gatts_min_handle, start); + bleio_gatts_max_handle = MAX(bleio_gatts_max_handle, end); _indicate_service_change(start, end); #if CIRCUITPY_VERBOSE_BLE diff --git a/ports/nordic/common-hal/_bleio/__init__.c b/ports/nordic/common-hal/_bleio/__init__.c index 3d76b93ff15..7928123c173 100644 --- a/ports/nordic/common-hal/_bleio/__init__.c +++ b/ports/nordic/common-hal/_bleio/__init__.c @@ -77,6 +77,9 @@ void check_sec_status(uint8_t sec_status) { } } +uint16_t bleio_gatts_min_handle = 0xFFFF; +uint16_t bleio_gatts_max_handle; + void common_hal_bleio_init(void) { } @@ -85,6 +88,30 @@ void bleio_user_reset(void) { // Stop any user scanning or advertising. common_hal_bleio_adapter_stop_scan(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_stop_advertising(&common_hal_bleio_adapter_obj); + + // Disconnect the connections that user code initiated or accepted with its + // own advertising. The BLE workflow connection is not user-owned and stays up. + // + // Clear each connection's pointers into the VM heap first: the heap is about + // to go away, and a disconnect completes asynchronously, possibly after it + // has. The disconnect event handler dereferences connection_obj unless it is + // mp_const_none. + for (size_t i = 0; i < BLEIO_TOTAL_CONNECTION_COUNT; i++) { + bleio_connection_internal_t *connection = &bleio_connections[i]; + connection->connection_obj = mp_const_none; + connection->remote_service_list = NULL; + if (connection->conn_handle != BLE_CONN_HANDLE_INVALID && connection->user_owned) { + common_hal_bleio_connection_disconnect(connection); + } + } + + // Clear the adapter's remaining pointers into the VM heap. The full stack + // reset in bleio_reset() used to do this implicitly, but it no longer always + // runs. The adapter struct is a GC root, so a pointer left over from this + // heap would be scanned as a live object in the next VM's heap. + common_hal_bleio_adapter_obj.connection_objs = NULL; + common_hal_bleio_adapter_obj.advertising_data = NULL; + common_hal_bleio_adapter_obj.scan_response_data = NULL; } ble_drv_remove_heap_handlers(); @@ -101,6 +128,16 @@ void bleio_reset(void) { return; } + // The SoftDevice cannot remove individual services from its GATT table: the + // disable/enable cycle below is the only way to clear them, and it drops every + // connection, the BLE workflow's included. So run it only when user code created + // services. All other user BLE state has already been torn down individually by + // bleio_user_reset(). + if (!bleio_user_services_created()) { + return; + } + bleio_clear_user_services_created(); + supervisor_stop_bluetooth(); bleio_adapter_reset(&common_hal_bleio_adapter_obj); common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); diff --git a/ports/nordic/common-hal/_bleio/__init__.h b/ports/nordic/common-hal/_bleio/__init__.h index caf287f9204..955c73ad8e5 100644 --- a/ports/nordic/common-hal/_bleio/__init__.h +++ b/ports/nordic/common-hal/_bleio/__init__.h @@ -8,6 +8,14 @@ void bleio_background(void); +// The range of attribute handles the application has populated in the +// SoftDevice's GATT table. Kept because sd_ble_gatts_service_changed() rejects +// handles outside that range (BLE_ERROR_INVALID_ATTR_HANDLE): 0xFFFF is beyond +// it, and handles at or below 0xC are in the SoftDevice's own GAP and GATT +// services, not the application's. +extern uint16_t bleio_gatts_min_handle; +extern uint16_t bleio_gatts_max_handle; + typedef struct { ble_gap_enc_key_t own_enc; ble_gap_enc_key_t peer_enc; diff --git a/shared-bindings/_bleio/Service.c b/shared-bindings/_bleio/Service.c index cea9a68e694..57285dab924 100644 --- a/shared-bindings/_bleio/Service.c +++ b/shared-bindings/_bleio/Service.c @@ -8,6 +8,7 @@ #include "py/objproperty.h" #include "py/runtime.h" +#include "shared-bindings/_bleio/__init__.h" #include "shared-bindings/_bleio/Characteristic.h" #include "shared-bindings/_bleio/Service.h" #include "shared-bindings/_bleio/UUID.h" @@ -45,6 +46,9 @@ static mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, bleio_service_obj_t *service = mp_obj_malloc_with_finaliser(bleio_service_obj_t, &bleio_service_type); common_hal_bleio_service_construct(service, uuid, is_secondary); + // The service is now in the stack's GATT table, and only a full stack reset can + // remove it. bleio_reset() checks this flag to decide whether to do that reset. + bleio_set_user_services_created(); return MP_OBJ_FROM_PTR(service); } diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c index 1ec9fd96e76..bc6b82873c6 100644 --- a/shared-bindings/_bleio/__init__.c +++ b/shared-bindings/_bleio/__init__.c @@ -91,6 +91,20 @@ MP_NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t fmt, ...) { nlr_raise(exception); } +static bool _user_services_created; + +bool bleio_user_services_created(void) { + return _user_services_created; +} + +void bleio_set_user_services_created(void) { + _user_services_created = true; +} + +void bleio_clear_user_services_created(void) { + _user_services_created = false; +} + // Called when _bleio is imported. static mp_obj_t bleio___init__(void) { // HCI cannot be enabled on import, because we need to setup the HCI adapter first. diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index b55db201f2e..ae7d781c550 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -39,6 +39,21 @@ void bleio_user_reset(void); // Completely resets the BLE stack including BLE connections. void bleio_reset(void); +// True if user code created a local GATT service during this VM run. Set by the +// shared-bindings Service constructor; the supervisor constructs its BLE workflow +// services through common-hal directly and does not set it. User-created services +// can only be removed from the stack's GATT table by a full stack reset, so a +// port's bleio_reset() uses this to decide whether that reset, which drops all +// connections, is needed at all. +bool bleio_user_services_created(void); + +// Record that user code created a local GATT service. +void bleio_set_user_services_created(void); + +// Clear the flag reported by bleio_user_services_created(). Call after a full +// stack reset, so the next VM run starts out clean. +void bleio_clear_user_services_created(void); + // Init any state needed before calling any bleio functions including those // having to do with bonding. This doesn't enable the BLE adapter though. void common_hal_bleio_init(void); From 82d2c3e7e034650f823c6cca6489deba668fc460 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 26 Aug 2026 13:35:34 -0400 Subject: [PATCH 852/876] Clean up BLE reset leftovers in main.c, ble_hci, and silabs Delete main.c's reset_devices(), which only handled CIRCUITPY_BLEIO_HCI. At VM cleanup it double-reset those builds, because ble_hci's bleio_user_reset() does a full reset itself; at startup it stood in for HCI initialization, which now happens in common_hal_bleio_init() when user code imports _bleio. HCI is unusable before user code supplies an adapter, so import time is early enough, and bleio_reset() no longer re-creates the CCCD UUID that init now owns. Remove silabs declarations of vm_used_ble and cccd_uuid, copied long ago from ble_hci and never defined or used in that port. Co-Authored-By: Claude Fable 5 --- devices/ble_hci/common-hal/_bleio/__init__.c | 11 +++++++---- main.c | 13 +------------ ports/silabs/common-hal/_bleio/__init__.h | 6 ------ 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/devices/ble_hci/common-hal/_bleio/__init__.c b/devices/ble_hci/common-hal/_bleio/__init__.c index bfe39888753..29078944aaa 100644 --- a/devices/ble_hci/common-hal/_bleio/__init__.c +++ b/devices/ble_hci/common-hal/_bleio/__init__.c @@ -38,6 +38,13 @@ bool vm_used_ble; // } void common_hal_bleio_init(void) { + // Called on every import of _bleio. This is the only initialization HCI gets: + // unlike other ports, nothing runs at board startup, because HCI is unusable + // until user code supplies an adapter (UART, etc.) anyway. + // Create a UUID object for all CCCD's. + cccd_uuid.base.type = &bleio_uuid_type; + common_hal_bleio_uuid_construct(&cccd_uuid, BLE_UUID_CCCD, NULL); + bleio_hci_reset(); } void bleio_user_reset(void) { @@ -47,10 +54,6 @@ void bleio_user_reset(void) { // Turn off BLE on a reset or reload. void bleio_reset(void) { - // Create a UUID object for all CCCD's. - cccd_uuid.base.type = &bleio_uuid_type; - common_hal_bleio_uuid_construct(&cccd_uuid, BLE_UUID_CCCD, NULL); - bleio_hci_reset(); if (!common_hal_bleio_adapter_get_enabled(&common_hal_bleio_adapter_obj)) { diff --git a/main.c b/main.c index e2322524ab1..590bf6a3e4d 100644 --- a/main.c +++ b/main.c @@ -121,12 +121,6 @@ uint8_t value_out = 0; #include "supervisor/shared/settings.h" #endif -static void reset_devices(void) { - #if CIRCUITPY_BLEIO_HCI - bleio_reset(); - #endif -} - static uint8_t *_heap; static uint8_t *_pystack; static volatile bool _vm_is_running = false; @@ -374,9 +368,6 @@ static void cleanup_after_vm(mp_obj_t exception) { } } - // Reset port-independent devices, like CIRCUITPY_BLEIO_HCI. - reset_devices(); - #if CIRCUITPY_ATEXIT atexit_reset(); #endif @@ -390,7 +381,7 @@ static void cleanup_after_vm(mp_obj_t exception) { memorymonitor_reset(); #endif - // Disable user related BLE state that uses the micropython heap. + // Disable user related BLE state that uses the VM heap. Leave BLE workflow running if it's in use. #if CIRCUITPY_BLEIO bleio_user_reset(); #endif @@ -1088,8 +1079,6 @@ int __attribute__((used)) main(void) { // Reset everything and prep MicroPython to run boot.py. reset_port(); - // Port-independent devices, like CIRCUITPY_BLEIO_HCI. - reset_devices(); reset_board(); // displays init after filesystem, since they could share the flash SPI diff --git a/ports/silabs/common-hal/_bleio/__init__.h b/ports/silabs/common-hal/_bleio/__init__.h index 63eda59d84f..4ecd6456b8b 100644 --- a/ports/silabs/common-hal/_bleio/__init__.h +++ b/ports/silabs/common-hal/_bleio/__init__.h @@ -61,12 +61,6 @@ // Maximum length for variable length Attribute Values. #define BLE_GATTS_VAR_ATTR_LEN_MAX (512) -// Track if the user code modified the BLE state -// to know if we need to undo it on reload. -extern bool vm_used_ble; - -// UUID shared by all CCCD's. -extern bleio_uuid_obj_t cccd_uuid; extern void bleio_reset(); extern osMutexId_t bluetooth_connection_mutex_id; From 6afa4b750ec042d4b56c4480c6c716bf7594f62f Mon Sep 17 00:00:00 2001 From: foamyguy Date: Wed, 26 Aug 2026 13:03:27 -0500 Subject: [PATCH 853/876] use CIRCUITPY_BLEIO_NATIVE instead of SD make var --- ports/nordic/Makefile | 6 +++--- ports/nordic/mpconfigport.mk | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ports/nordic/Makefile b/ports/nordic/Makefile index bddc1a2ef80..ec755fac892 100755 --- a/ports/nordic/Makefile +++ b/ports/nordic/Makefile @@ -8,7 +8,7 @@ include ../../py/circuitpy_mkenv.mk # Skip when the make command is not board-specific i.e. fetch-port-submodules. ifneq ($(VALID_BOARD),) -ifneq ($(SD), ) +ifeq ($(CIRCUITPY_BLEIO_NATIVE),1) include bluetooth/bluetooth_common.mk endif endif @@ -120,7 +120,7 @@ SRC_C += \ device/$(MCU_VARIANT)/startup_$(MCU_SUB_VARIANT).c \ nrfx/mdk/system_$(MCU_SUB_VARIANT).c \ -ifneq ($(SD), ) +ifeq ($(CIRCUITPY_BLEIO_NATIVE),1) SRC_C += \ bluetooth/ble_drv.c \ common-hal/_bleio/bonding.c \ @@ -185,7 +185,7 @@ UF2_FAMILY_ID_nrf52840 = 0xADA52840 UF2_FAMILY_ID_nrf52833 = 0x621E937A -ifneq ($(SD), ) +ifeq ($(CIRCUITPY_BLEIO_NATIVE),1) all: $(BUILD)/firmware.bin $(BUILD)/firmware.uf2 $(BUILD)/firmware.combined.hex else # firmware.combined.hex merges in the SoftDevice hex; without one there is diff --git a/ports/nordic/mpconfigport.mk b/ports/nordic/mpconfigport.mk index 17d9f19d4b1..a9299ee60aa 100644 --- a/ports/nordic/mpconfigport.mk +++ b/ports/nordic/mpconfigport.mk @@ -125,9 +125,7 @@ endif endif endif -# no BLEIO without a SoftDevice. -ifeq ($(SD), ) -CIRCUITPY_BLEIO_NATIVE = 0 +ifneq ($(CIRCUITPY_BLEIO_NATIVE),1) CIRCUITPY_BLE_FILE_SERVICE = 0 CIRCUITPY_BLE_SERIAL_SERVICE = 0 endif From 029089f661056808615731b03734e2e1850f14de Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 26 Aug 2026 14:12:48 -0400 Subject: [PATCH 854/876] Clarify reset and Service Changed comments Co-Authored-By: Claude Fable 5 --- main.c | 4 ++-- ports/espressif/common-hal/_bleio/__init__.c | 22 +++++++++----------- ports/nordic/common-hal/_bleio/__init__.h | 8 +++---- shared-bindings/_bleio/Service.c | 4 ++-- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/main.c b/main.c index 590bf6a3e4d..845d55ca21e 100644 --- a/main.c +++ b/main.c @@ -767,7 +767,7 @@ static bool __attribute__((noinline)) run_code_py(safe_mode_t safe_mode, bool *s // Done waiting, start the board back up. // Resetting BLE is delayed until here, after the wait, in case files were being - // transferred over the BLE workflow during the wait. The reset cycles the BLE + // transferred over the BLE workflow during the wait. The reset restarts the BLE // stack, dropping the workflow connection, only if user code created GATT // services; otherwise it is a no-op and the connection continues. #if CIRCUITPY_BLEIO @@ -986,7 +986,7 @@ static int run_repl(safe_mode_t safe_mode) { cleanup_after_vm(MP_OBJ_SENTINEL); // Also reset bleio, which cleanup_after_vm() above omits so workflows can - // continue between VMs. As in run_code_py(), this cycles the BLE stack only if + // continue between VMs. As in run_code_py(), this restarts the BLE stack only if // user code created GATT services. #if CIRCUITPY_BLEIO bleio_reset(); diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index 7a8fd2f36a5..ae2687fa076 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -73,15 +73,15 @@ void bleio_reset(void) { return; } - // The disable/enable cycle below clears user-created services from the GATT - // table, and it drops every connection, the BLE workflow's included. So run it + // The stop/start cycle below clears user-created services from the GATT + // table, and drops every connection, BLE workflow included. So run it // only when user code created services. All other user BLE state has already // been torn down individually by bleio_user_reset(). // - // ESP-IDF NimBLE can delete individual services (ble_gatts_delete_svc(), used - // in Service.c), so a possible refinement is for bleio_user_reset() to delete - // user services one by one and never cycle the stack at all. For now this port - // matches nordic, whose SoftDevice can only clear services with a full cycle. + // TODO: ESP-IDF NimBLE can delete individual services (ble_gatts_delete_svc(), + // used in Service.c), so bleio_user_reset() could delete user services one by + // one and never restart the BLE stack at all. For now this port matches + // nordic, whose SoftDevice can only clear services with a full cycle. if (!bleio_user_services_created()) { return; } @@ -93,12 +93,10 @@ void bleio_reset(void) { common_hal_bleio_adapter_set_enabled(&common_hal_bleio_adapter_obj, false); supervisor_start_bluetooth(); - // The cycle above rebuilt the GATT table, so bonded peers' cached tables are - // stale. Signal Service Changed over the whole handle range: NimBLE indicates - // connected subscribed peers immediately (there are none right after the - // cycle) and records the change for bonded peers, indicating them when they - // reconnect. Without this, a bonded host trusts its cache indefinitely and - // can look up characteristics at stale handles. + // The stop/start above rebuilt the GATT table, so now any bonded peers' cached + // tables are stale. Signal Service Changed over the whole handle range. + // Without Service Changed, a bonded host trusts its cache indefinitely and can + // look up characteristics at stale handles. ble_svc_gatt_changed(0x0001, 0xffff); } diff --git a/ports/nordic/common-hal/_bleio/__init__.h b/ports/nordic/common-hal/_bleio/__init__.h index 955c73ad8e5..eecbc32275f 100644 --- a/ports/nordic/common-hal/_bleio/__init__.h +++ b/ports/nordic/common-hal/_bleio/__init__.h @@ -8,11 +8,9 @@ void bleio_background(void); -// The range of attribute handles the application has populated in the -// SoftDevice's GATT table. Kept because sd_ble_gatts_service_changed() rejects -// handles outside that range (BLE_ERROR_INVALID_ATTR_HANDLE): 0xFFFF is beyond -// it, and handles at or below 0xC are in the SoftDevice's own GAP and GATT -// services, not the application's. +// Remember the range of attribute handles the application has populated in the +// SoftDevice's GATT table. Required to call sd_ble_gatts_service_changed() +// with valid arguments: it fails if the args are outside that range. extern uint16_t bleio_gatts_min_handle; extern uint16_t bleio_gatts_max_handle; diff --git a/shared-bindings/_bleio/Service.c b/shared-bindings/_bleio/Service.c index 57285dab924..920d66a3de2 100644 --- a/shared-bindings/_bleio/Service.c +++ b/shared-bindings/_bleio/Service.c @@ -46,8 +46,8 @@ static mp_obj_t bleio_service_make_new(const mp_obj_type_t *type, size_t n_args, bleio_service_obj_t *service = mp_obj_malloc_with_finaliser(bleio_service_obj_t, &bleio_service_type); common_hal_bleio_service_construct(service, uuid, is_secondary); - // The service is now in the stack's GATT table, and only a full stack reset can - // remove it. bleio_reset() checks this flag to decide whether to do that reset. + // Remember that there are services that were created by the user. + // bleio_reset() needs this to know what kind of reset to do. bleio_set_user_services_created(); return MP_OBJ_FROM_PTR(service); From 650bd9a08ec6a9cd522fbadc2a54225832ce0fe1 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 26 Aug 2026 16:25:00 -0400 Subject: [PATCH 855/876] Rename bleio_user_services_created() to bleio_get_user_services_created() Per review. Co-Authored-By: Claude Fable 5 --- ports/espressif/common-hal/_bleio/__init__.c | 2 +- ports/nordic/common-hal/_bleio/__init__.c | 2 +- shared-bindings/_bleio/__init__.c | 2 +- shared-bindings/_bleio/__init__.h | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ports/espressif/common-hal/_bleio/__init__.c b/ports/espressif/common-hal/_bleio/__init__.c index ae2687fa076..9fe86405498 100644 --- a/ports/espressif/common-hal/_bleio/__init__.c +++ b/ports/espressif/common-hal/_bleio/__init__.c @@ -82,7 +82,7 @@ void bleio_reset(void) { // used in Service.c), so bleio_user_reset() could delete user services one by // one and never restart the BLE stack at all. For now this port matches // nordic, whose SoftDevice can only clear services with a full cycle. - if (!bleio_user_services_created()) { + if (!bleio_get_user_services_created()) { return; } bleio_clear_user_services_created(); diff --git a/ports/nordic/common-hal/_bleio/__init__.c b/ports/nordic/common-hal/_bleio/__init__.c index 7928123c173..554bbf200bc 100644 --- a/ports/nordic/common-hal/_bleio/__init__.c +++ b/ports/nordic/common-hal/_bleio/__init__.c @@ -133,7 +133,7 @@ void bleio_reset(void) { // connection, the BLE workflow's included. So run it only when user code created // services. All other user BLE state has already been torn down individually by // bleio_user_reset(). - if (!bleio_user_services_created()) { + if (!bleio_get_user_services_created()) { return; } bleio_clear_user_services_created(); diff --git a/shared-bindings/_bleio/__init__.c b/shared-bindings/_bleio/__init__.c index bc6b82873c6..202542c3d05 100644 --- a/shared-bindings/_bleio/__init__.c +++ b/shared-bindings/_bleio/__init__.c @@ -93,7 +93,7 @@ MP_NORETURN void mp_raise_bleio_SecurityError(mp_rom_error_text_t fmt, ...) { static bool _user_services_created; -bool bleio_user_services_created(void) { +bool bleio_get_user_services_created(void) { return _user_services_created; } diff --git a/shared-bindings/_bleio/__init__.h b/shared-bindings/_bleio/__init__.h index ae7d781c550..0e8a9212e6b 100644 --- a/shared-bindings/_bleio/__init__.h +++ b/shared-bindings/_bleio/__init__.h @@ -45,12 +45,12 @@ void bleio_reset(void); // can only be removed from the stack's GATT table by a full stack reset, so a // port's bleio_reset() uses this to decide whether that reset, which drops all // connections, is needed at all. -bool bleio_user_services_created(void); +bool bleio_get_user_services_created(void); // Record that user code created a local GATT service. void bleio_set_user_services_created(void); -// Clear the flag reported by bleio_user_services_created(). Call after a full +// Clear the flag reported by bleio_get_user_services_created(). Call after a full // stack reset, so the next VM run starts out clean. void bleio_clear_user_services_created(void); From 4bbbe2a6f2f4507511ed26f817fa509955c55b9a Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 26 Aug 2026 16:37:07 -0400 Subject: [PATCH 856/876] shrink pca10100 --- ports/nordic/boards/pca10100/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/nordic/boards/pca10100/mpconfigboard.mk b/ports/nordic/boards/pca10100/mpconfigboard.mk index 34bcc47cf9f..9997abb8bfe 100644 --- a/ports/nordic/boards/pca10100/mpconfigboard.mk +++ b/ports/nordic/boards/pca10100/mpconfigboard.mk @@ -10,3 +10,4 @@ INTERNAL_FLASH_FILESYSTEM = 1 CIRCUITPY_ONEWIREIO = 0 CIRCUITPY_AUDIOMIXER = 0 CIRCUITPY_RAINBOWIO = 0 +CIRCUITPY_USB_MIDI = 0 From 67517fc147f4b9c07f10f031460fbde839ad986e Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Wed, 26 Aug 2026 14:48:02 -0700 Subject: [PATCH 857/876] Fix open calls --- ports/zephyr-cp/supervisor/port.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ports/zephyr-cp/supervisor/port.c b/ports/zephyr-cp/supervisor/port.c index 79fb500ca73..62028f96a85 100644 --- a/ports/zephyr-cp/supervisor/port.c +++ b/ports/zephyr-cp/supervisor/port.c @@ -171,7 +171,6 @@ static void cp_saved_word_save(void) { if (path == NULL || path[0] == '\0') { return; } - int fd = nsi_host_open(path, O_WRONLY | O_CREAT | O_TRUNC); int fd = nsi_host_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { return; @@ -186,7 +185,7 @@ static void cp_saved_word_restore(void) { if (path == NULL || path[0] == '\0') { return; } - int fd = nsi_host_open(path, O_RDONLY); + int fd = nsi_host_open(path, O_RDONLY, 0 /* unused */); if (fd < 0) { return; // First boot: no save file yet. } From 8267c84f9ecce279000a1882f4a083e5a7cefd3b Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Fri, 31 Jul 2026 13:51:54 -0700 Subject: [PATCH 858/876] zephyr-cp/wifi: implement station connect common_hal_wifi_radio_connect() was a stub: the body was commented-out ESP-IDF code and it returned WIFI_RADIO_ERROR_NONE without attempting anything, so connect() silently "succeeded" while never associating. get_connected() returned a hardcoded false and the IPv4 getters returned None. No zephyr-cp board could join a network. Implement connect() with NET_REQUEST_WIFI_CONNECT: - build wifi_connect_req_params from ssid/password/channel/bssid - wait on a semaphore signalled from CONNECT_RESULT (or DISCONNECT_RESULT, which is how a failed attempt reports), honouring the timeout argument and staying interruptible - map wifi_conn_status to the CircuitPython error codes so a wrong password raises AUTH_FAIL instead of appearing to succeed - start DHCPv4 and wait for an address Also implement get_connected(), get_ipv4_address() and get_ipv4_gateway() from the Zephyr net_if state. get_mac_address() returned an uninitialized stack buffer; read the real address from net_if_get_link_addr() instead. Track the associated SSID so a repeat connect() to the same network returns without tearing down a working link, on both the normal and the -EALREADY path. Security is fixed at WIFI_SECURITY_TYPE_PSK here. Transition-mode APs negotiate up from there; per-network selection follows in the next commit. --- ports/zephyr-cp/common-hal/wifi/Radio.c | 160 +++++++++++++++++++-- ports/zephyr-cp/common-hal/wifi/Radio.h | 12 ++ ports/zephyr-cp/common-hal/wifi/__init__.c | 23 ++- 3 files changed, 176 insertions(+), 19 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 9ae19b5392a..b79085ef021 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -121,8 +122,13 @@ void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *host } mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { - uint8_t mac[MAC_ADDRESS_LENGTH]; - // esp_wifi_get_mac(ESP_IF_WIFI_STA, mac); + uint8_t mac[MAC_ADDRESS_LENGTH] = { 0 }; + if (self->sta_netif != NULL) { + struct net_linkaddr *addr = net_if_get_link_addr(self->sta_netif); + if (addr != NULL && addr->len >= MAC_ADDRESS_LENGTH) { + memcpy(mac, addr->addr, MAC_ADDRESS_LENGTH); + } + } return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } @@ -457,12 +463,128 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t // // We're connected, allow us to retry if we get disconnected. // self->retries_left = self->starting_retries; // } + + struct wifi_connect_req_params params = { 0 }; + + params.ssid = ssid; + params.ssid_length = ssid_len; + params.band = WIFI_FREQ_BAND_2_4_GHZ; + params.channel = channel == 0 ? WIFI_CHANNEL_ANY : channel; + params.mfp = WIFI_MFP_OPTIONAL; + params.timeout = SYS_FOREVER_MS; + + if (password_len > 0) { + params.psk = password; + params.psk_length = password_len; + // WPA2-PSK. Drivers that support a WPA2/WPA3 transition AP will + // negotiate up from here; a WPA3-only network needs + // WIFI_SECURITY_TYPE_SAE, which we cannot infer without a prior scan. + params.security = WIFI_SECURITY_TYPE_PSK; + } else { + params.security = WIFI_SECURITY_TYPE_NONE; + } + + if (bssid_len == WIFI_MAC_ADDR_LEN) { + memcpy(params.bssid, bssid, WIFI_MAC_ADDR_LEN); + } + + // Already associated to the network being asked for: leave the link alone. + // supervisor_start_web_workflow() calls connect() on every invocation, so + // tearing the association down here would churn the link continuously. + if (self->connected && + ssid_len == self->current_ssid_len && + memcmp(ssid, self->current_ssid, ssid_len) == 0) { + return WIFI_RADIO_ERROR_NONE; + } + + // Switching networks. Connecting while associated returns -EALREADY and the + // failure path takes the interface down, so disconnect first. + if (self->connected) { + // A failure here is tolerated on purpose: if the interface really is + // unusable, the connect below returns a proper error to the caller. + (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, self->sta_netif, NULL, 0); + // Give the controller a moment to tear the association down. + for (int i = 0; i < 40 && self->connected; i++) { + k_msleep(50); + } + self->connected = false; + } + + self->connected = false; + self->last_connect_status = -1; + self->last_disconnect_reason = 0; + k_sem_reset(&self->connect_sem); + + int res = net_mgmt(NET_REQUEST_WIFI_CONNECT, self->sta_netif, ¶ms, sizeof(params)); + if (res == -EALREADY) { + // Record the SSID as the success path does, so the early return above + // matches on a later connect() to the same network. + self->connected = true; + self->current_ssid_len = MIN(ssid_len, sizeof(self->current_ssid)); + memcpy(self->current_ssid, ssid, self->current_ssid_len); + return WIFI_RADIO_ERROR_NONE; + } + if (res < 0) { + return WIFI_RADIO_ERROR_UNSPECIFIED; + } + + // Wait for NET_EVENT_WIFI_CONNECT_RESULT (or a DISCONNECT_RESULT standing + // in for a failed attempt), staying responsive to ctrl-C. + mp_float_t timeout_s = timeout <= 0 ? (mp_float_t)10 : timeout; + int64_t deadline = k_uptime_get() + (int64_t)(timeout_s * 1000); + bool signalled = false; + while (k_uptime_get() < deadline) { + if (k_sem_take(&self->connect_sem, K_MSEC(50)) == 0) { + signalled = true; + break; + } + if (mp_hal_is_interrupted()) { + return WIFI_RADIO_ERROR_UNSPECIFIED; + } + } + + if (!signalled) { + return WIFI_RADIO_ERROR_HANDSHAKE_TIMEOUT; + } + if (!self->connected) { + switch (self->last_connect_status) { + case WIFI_STATUS_CONN_WRONG_PASSWORD: + return WIFI_RADIO_ERROR_AUTH_FAIL; + case WIFI_STATUS_CONN_AP_NOT_FOUND: + return WIFI_RADIO_ERROR_NO_AP_FOUND; + case WIFI_STATUS_CONN_TIMEOUT: + return WIFI_RADIO_ERROR_HANDSHAKE_TIMEOUT; + default: + return WIFI_RADIO_ERROR_CONNECTION_FAIL; + } + } + + // Remember which network this association is for, so a later connect() for + // the same SSID can return without disturbing it. + self->current_ssid_len = MIN(ssid_len, sizeof(self->current_ssid)); + memcpy(self->current_ssid, ssid, self->current_ssid_len); + + // Associated. Ask for an address; the AP side of DHCP can take a moment. + #if defined(CONFIG_NET_DHCPV4) + net_dhcpv4_start(self->sta_netif); + int64_t ip_deadline = k_uptime_get() + 15000; + while (k_uptime_get() < ip_deadline) { + if (net_if_ipv4_get_global_addr(self->sta_netif, NET_ADDR_PREFERRED) != NULL) { + break; + } + if (mp_hal_is_interrupted()) { + break; + } + k_msleep(50); + } + #endif + return WIFI_RADIO_ERROR_NONE; } bool common_hal_wifi_radio_get_connected(wifi_radio_obj_t *self) { - // return self->sta_mode && esp_netif_is_netif_up(self->netif); - return false; + return self->connected && self->sta_netif != NULL && + net_if_is_up(self->sta_netif); } mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self) { @@ -500,11 +622,17 @@ mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ipv4_gateway(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - return mp_const_none; - // } - // esp_netif_get_ip_info(self->netif, &self->ip_info); - // return common_hal_ipaddress_new_ipv4address(self->ip_info.gw.addr); + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return mp_const_none; + } + const struct net_if_config *cfg = net_if_get_config(self->sta_netif); + if (cfg == NULL || cfg->ip.ipv4 == NULL) { + return mp_const_none; + } + if (cfg->ip.ipv4->gw.s_addr == 0) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(cfg->ip.ipv4->gw.s_addr); } mp_obj_t common_hal_wifi_radio_get_ipv4_gateway_ap(wifi_radio_obj_t *self) { @@ -582,12 +710,14 @@ uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - // return mp_const_none; - // } - // esp_netif_get_ip_info(self->netif, &self->ip_info); - // return common_hal_ipaddress_new_ipv4address(self->ip_info.ip.addr); - return mp_const_none; + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return mp_const_none; + } + struct in_addr *addr = net_if_ipv4_get_global_addr(self->sta_netif, NET_ADDR_PREFERRED); + if (addr == NULL) { + return mp_const_none; + } + return common_hal_ipaddress_new_ipv4address(addr->s_addr); } mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self) { diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.h b/ports/zephyr-cp/common-hal/wifi/Radio.h index f177f493685..2500079df09 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.h +++ b/ports/zephyr-cp/common-hal/wifi/Radio.h @@ -11,7 +11,9 @@ #include "shared-bindings/wifi/ScannedNetworks.h" #include "shared-bindings/wifi/Network.h" +#include #include +#include // Event bits for the Radio event group. #define WIFI_SCAN_DONE_BIT BIT0 @@ -38,6 +40,16 @@ typedef struct { uint8_t retries_left; uint8_t starting_retries; uint8_t last_disconnect_reason; + // Signalled from the net_mgmt event handler when a connect attempt + // finishes, so common_hal_wifi_radio_connect() can wait on the result. + struct k_sem connect_sem; + // Latest wifi_conn_status from NET_EVENT_WIFI_CONNECT_RESULT. + int last_connect_status; + bool connected; + // SSID of the association that `connected` refers to, so that a connect() + // for the network we are already on can return without touching the link. + uint8_t current_ssid[WIFI_SSID_MAX_LEN]; + size_t current_ssid_len; } wifi_radio_obj_t; extern void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self); diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 213ef7f618f..182ae5a3c30 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -74,12 +74,24 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve k_poll_signal_raise(&self->current_scan->channel_done, 0); } break; - case NET_EVENT_WIFI_CONNECT_RESULT: - LOG_DBG("NET_EVENT_WIFI_CONNECT_RESULT"); + case NET_EVENT_WIFI_CONNECT_RESULT: { + const struct wifi_status *status = cb->info; + self->last_connect_status = status != NULL ? status->status : -1; + self->connected = self->last_connect_status == WIFI_STATUS_CONN_SUCCESS; + LOG_DBG("NET_EVENT_WIFI_CONNECT_RESULT status %d", self->last_connect_status); + k_sem_give(&self->connect_sem); break; - case NET_EVENT_WIFI_DISCONNECT_RESULT: - LOG_DBG("NET_EVENT_WIFI_DISCONNECT_RESULT"); + } + case NET_EVENT_WIFI_DISCONNECT_RESULT: { + const struct wifi_status *status = cb->info; + self->last_disconnect_reason = status != NULL ? (uint8_t)status->status : 0; + self->connected = false; + LOG_DBG("NET_EVENT_WIFI_DISCONNECT_RESULT reason %d", self->last_disconnect_reason); + // A disconnect can also be the failure result of a connect attempt, + // so release any waiter rather than letting it sit until timeout. + k_sem_give(&self->connect_sem); break; + } case NET_EVENT_WIFI_IFACE_STATUS: LOG_DBG("NET_EVENT_WIFI_IFACE_STATUS"); break; @@ -219,6 +231,9 @@ void common_hal_wifi_init(bool user_initiated) { wifi_inited = true; wifi_user_initiated = user_initiated; self->base.type = &wifi_radio_type; + k_sem_init(&self->connect_sem, 0, 1); + self->connected = false; + self->last_connect_status = -1; // struct net_if *default_iface = net_if_get_default(); // printk("default interface %p\n", default_iface); From 5be3e58d61185a972fc6191e1e51d07054d0f5bb Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 3 Aug 2026 17:35:53 -0700 Subject: [PATCH 859/876] zephyr-cp/wifi: per-AP security selection, real authmode, IPv4 getters Security type has to be chosen per network. The SiWx91x driver maps WIFI_SECURITY_TYPE_PSK to SL_WIFI_WPA2 and WPA_AUTO_PERSONAL to SL_WIFI_WPA3_TRANSITION, and neither works everywhere: a WPA2-PSK AP rejects WPA3 transition and a WPA3-SAE AP rejects WPA2, both surfacing identically as "Authentication failure". So cache the most recent scan (24 entries, same-SSID replace) and look the SSID up in connect(), falling back to WPA2-PSK when it was not seen. Known limit: that fallback is silently wrong for a WPA3-only hidden AP. get_authmode() built its mask from a switch that was entirely commented out (ESP-IDF leftover) and always returned an empty list, which reads as an open network. Translate Zephyr's wifi_security_type instead. The EAP and OWE arms are taken from the header and are not exercised on hardware. Adds the ipv4_subnet and ipv4_dns getters alongside the address and gateway getters from the previous commit. Co-Authored-By: Claude Fable 5 --- ports/zephyr-cp/common-hal/wifi/Network.c | 65 ++++++++++-------- ports/zephyr-cp/common-hal/wifi/Radio.c | 78 ++++++++++++++++------ ports/zephyr-cp/common-hal/wifi/__init__.c | 41 +++++++++++- ports/zephyr-cp/common-hal/wifi/__init__.h | 6 ++ 4 files changed, 139 insertions(+), 51 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Network.c b/ports/zephyr-cp/common-hal/wifi/Network.c index 44c049f88c1..510f8b9f5c2 100644 --- a/ports/zephyr-cp/common-hal/wifi/Network.c +++ b/ports/zephyr-cp/common-hal/wifi/Network.c @@ -34,35 +34,44 @@ mp_obj_t common_hal_wifi_network_get_country(wifi_network_obj_t *self) { } mp_obj_t common_hal_wifi_network_get_authmode(wifi_network_obj_t *self) { + // Translate Zephyr's wifi_security_type. An empty list would read as an + // open network to any caller checking for AUTHMODE_OPEN. uint32_t authmode_mask = 0; - // switch (self->record.authmode) { - // case WIFI_AUTH_OPEN: - // authmode_mask = AUTHMODE_OPEN; - // break; - // case WIFI_AUTH_WEP: - // authmode_mask = AUTHMODE_WEP; - // break; - // case WIFI_AUTH_WPA_PSK: - // authmode_mask = AUTHMODE_WPA | AUTHMODE_PSK; - // break; - // case WIFI_AUTH_WPA2_PSK: - // authmode_mask = AUTHMODE_WPA2 | AUTHMODE_PSK; - // break; - // case WIFI_AUTH_WPA_WPA2_PSK: - // authmode_mask = AUTHMODE_WPA | AUTHMODE_WPA2 | AUTHMODE_PSK; - // break; - // case WIFI_AUTH_WPA2_ENTERPRISE: - // authmode_mask = AUTHMODE_WPA2 | AUTHMODE_ENTERPRISE; - // break; - // case WIFI_AUTH_WPA3_PSK: - // authmode_mask = AUTHMODE_WPA3 | AUTHMODE_PSK; - // break; - // case WIFI_AUTH_WPA2_WPA3_PSK: - // authmode_mask = AUTHMODE_WPA2 | AUTHMODE_WPA3 | AUTHMODE_PSK; - // break; - // default: - // break; - // } + switch (self->scan_result.security) { + case WIFI_SECURITY_TYPE_NONE: + authmode_mask = AUTHMODE_OPEN; + break; + case WIFI_SECURITY_TYPE_WEP: + authmode_mask = AUTHMODE_WEP; + break; + case WIFI_SECURITY_TYPE_WPA_PSK: + authmode_mask = AUTHMODE_WPA | AUTHMODE_PSK; + break; + case WIFI_SECURITY_TYPE_PSK: + case WIFI_SECURITY_TYPE_PSK_SHA256: + authmode_mask = AUTHMODE_WPA2 | AUTHMODE_PSK; + break; + case WIFI_SECURITY_TYPE_SAE: // == WIFI_SECURITY_TYPE_SAE_HNP (alias) + case WIFI_SECURITY_TYPE_SAE_H2E: + case WIFI_SECURITY_TYPE_SAE_AUTO: + case WIFI_SECURITY_TYPE_SAE_EXT_KEY: + case WIFI_SECURITY_TYPE_FT_SAE: + authmode_mask = AUTHMODE_WPA3 | AUTHMODE_PSK; + break; + case WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL: + authmode_mask = AUTHMODE_WPA | AUTHMODE_WPA2 | AUTHMODE_WPA3 | AUTHMODE_PSK; + break; + case WIFI_SECURITY_TYPE_EAP: // == WIFI_SECURITY_TYPE_EAP_TLS (alias) + case WIFI_SECURITY_TYPE_EAP_PEAP_MSCHAPV2: + case WIFI_SECURITY_TYPE_EAP_PEAP_GTC: + case WIFI_SECURITY_TYPE_EAP_TTLS_MSCHAPV2: + case WIFI_SECURITY_TYPE_EAP_PEAP_TLS: + case WIFI_SECURITY_TYPE_FT_EAP: + authmode_mask = AUTHMODE_WPA2 | AUTHMODE_ENTERPRISE; + break; + default: + break; + } mp_obj_t authmode_list = mp_obj_new_list(0, NULL); if (authmode_mask != 0) { for (uint8_t i = 0; i < 32; i++) { diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index b79085ef021..f3de72f24bf 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -27,6 +27,8 @@ #include #include #include +// dns_resolve_get_default() for radio.ipv4_dns. +#include #include #include #include @@ -476,10 +478,28 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t if (password_len > 0) { params.psk = password; params.psk_length = password_len; - // WPA2-PSK. Drivers that support a WPA2/WPA3 transition AP will - // negotiate up from here; a WPA3-only network needs - // WIFI_SECURITY_TYPE_SAE, which we cannot infer without a prior scan. + // The security type must match what the AP advertises: this driver maps + // PSK to WPA2 and WPA_AUTO_PERSONAL to WPA3-transition, and rejects the + // wrong one with a generic "Authentication failure". So take it from the + // last scan, falling back to WPA2-PSK when the SSID was not seen. That + // fallback is wrong for a WPA3-only hidden AP. params.security = WIFI_SECURITY_TYPE_PSK; + struct wifi_scan_result *cached = wifi_cached_scan_lookup(ssid, ssid_len); + if (cached != NULL) { + switch (cached->security) { + case WIFI_SECURITY_TYPE_SAE: + case WIFI_SECURITY_TYPE_SAE_H2E: + case WIFI_SECURITY_TYPE_SAE_AUTO: + params.security = WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL; + break; + case WIFI_SECURITY_TYPE_WPA_PSK: + params.security = WIFI_SECURITY_TYPE_WPA_PSK; + break; + default: + params.security = WIFI_SECURITY_TYPE_PSK; + break; + } + } } else { params.security = WIFI_SECURITY_TYPE_NONE; } @@ -644,11 +664,21 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_gateway_ap(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ipv4_subnet(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return mp_const_none; + } + struct net_if_ipv4 *ipv4 = self->sta_netif->config.ip.ipv4; + if (ipv4 == NULL) { + return mp_const_none; + } + for (int i = 0; i < NET_IF_MAX_IPV4_ADDR; i++) { + if (ipv4->unicast[i].ipv4.is_used && + ipv4->unicast[i].ipv4.addr_state == NET_ADDR_PREFERRED) { + return common_hal_ipaddress_new_ipv4address( + ipv4->unicast[i].netmask.s_addr); + } + } return mp_const_none; - // } - // esp_netif_get_ip_info(self->netif, &self->ip_info); - // return common_hal_ipaddress_new_ipv4address(self->ip_info.netmask.addr); } mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) { @@ -730,20 +760,26 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_address_ap(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ipv4_dns(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - // return mp_const_none; - // } - - // esp_netif_get_dns_info(self->netif, ESP_NETIF_DNS_MAIN, &self->dns_info); - - // if (self->dns_info.ip.type != ESP_IPADDR_TYPE_V4) { - // return mp_const_none; - // } - // // dns_info is of type esp_netif_dns_info_t, which is just ever so slightly - // // different than esp_netif_ip_info_t used for - // // common_hal_wifi_radio_get_ipv4_address (includes both ipv4 and 6), - // // so some extra jumping is required to get to the actual address - // return common_hal_ipaddress_new_ipv4address(self->dns_info.ip.u_addr.ip4.addr); + // Zephyr keeps resolver state in the DNS resolve context rather than on + // the interface, so read it there. + #if defined(CONFIG_DNS_RESOLVER) + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return mp_const_none; + } + struct dns_resolve_context *ctx = dns_resolve_get_default(); + if (ctx == NULL) { + return mp_const_none; + } + for (int i = 0; i < CONFIG_DNS_RESOLVER_MAX_SERVERS; i++) { + if (ctx->servers[i].dns_server.sa_family == AF_INET) { + struct sockaddr_in *addr = + (struct sockaddr_in *)&ctx->servers[i].dns_server; + if (addr->sin_addr.s_addr != 0) { + return common_hal_ipaddress_new_ipv4address(addr->sin_addr.s_addr); + } + } + } + #endif return mp_const_none; } diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 182ae5a3c30..33f1ad13ed8 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -4,6 +4,8 @@ // // SPDX-License-Identifier: MIT +#include + #include "common-hal/wifi/__init__.h" #include "shared-bindings/wifi/__init__.h" @@ -53,6 +55,36 @@ static void schedule_background_on_cp_core(void *arg) { static struct net_mgmt_event_callback wifi_cb; static struct net_mgmt_event_callback ipv4_cb; +// Small cache of the most recent scan, used by common_hal_wifi_radio_connect() +// to pick the right security type per AP. +#define WIFI_SCAN_CACHE_LEN 24 +static struct wifi_scan_result scan_cache[WIFI_SCAN_CACHE_LEN]; +static size_t scan_cache_count; + +struct wifi_scan_result *wifi_cached_scan_lookup(const uint8_t *ssid, size_t ssid_len) { + for (size_t i = 0; i < scan_cache_count; i++) { + if (scan_cache[i].ssid_length == ssid_len && + memcmp(scan_cache[i].ssid, ssid, ssid_len) == 0) { + return &scan_cache[i]; + } + } + return NULL; +} + +static void wifi_scan_cache_add(const struct wifi_scan_result *result) { + // Replace an existing entry for the same SSID so the cache tracks the + // latest reading rather than filling up with duplicate BSSIDs. + struct wifi_scan_result *existing = + wifi_cached_scan_lookup(result->ssid, result->ssid_length); + if (existing != NULL) { + *existing = *result; + return; + } + if (scan_cache_count < WIFI_SCAN_CACHE_LEN) { + scan_cache[scan_cache_count++] = *result; + } +} + static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; (void)iface; @@ -61,8 +93,13 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve case NET_EVENT_WIFI_SCAN_RESULT: { LOG_DBG("NET_EVENT_WIFI_SCAN_RESULT"); const struct wifi_scan_result *result = cb->info; - if (result != NULL && self->current_scan != NULL) { - wifi_scannednetworks_scan_result(self->current_scan, result); + if (result != NULL) { + // Remember the authmode so connect() can request the matching + // security type later. + wifi_scan_cache_add(result); + if (self->current_scan != NULL) { + wifi_scannednetworks_scan_result(self->current_scan, result); + } } break; } diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.h b/ports/zephyr-cp/common-hal/wifi/__init__.h index dab519b1a5f..9f730003878 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.h +++ b/ports/zephyr-cp/common-hal/wifi/__init__.h @@ -8,10 +8,16 @@ #include "py/obj.h" +#include + struct sockaddr_storage; void wifi_reset(void); +// Look up an SSID in the cache of the most recent scan. Returns NULL if the +// network was not seen. +struct wifi_scan_result *wifi_cached_scan_lookup(const uint8_t *ssid, size_t ssid_len); + // void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address); // void ipaddress_ipaddress_to_esp_idf_ip4(mp_obj_t ip_address, esp_ip4_addr_t *esp_ip_address); From 7596900b25b54f670ded65941803d791ab275e46 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 3 Aug 2026 20:46:28 -0700 Subject: [PATCH 860/876] zephyr-cp/wifi: fix the "ip" field in version.json wifi_radio_get_ipv4_address(), the raw uint32_t getter that supervisor/shared/web_workflow/web_workflow.c uses for the status bar and for /cp/version.json's "ip" field, was a leftover ESP-IDF stub that returned 0 unconditionally. It is a separate entry point from common_hal_wifi_radio_get_ipv4_address(), the Python-facing getter: one underlying address, two functions, only one of them implemented. board_name and hostname in version.json stay empty, for an unrelated reason: both come from the mDNS responder, and zephyr-cp has no common-hal/mdns, so CIRCUITPY_MDNS never reaches web_workflow.c. That is a new component rather than a bug fix, so it is left out of this series. Co-Authored-By: Claude Sonnet 5 --- ports/zephyr-cp/common-hal/wifi/Radio.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index f3de72f24bf..60df2d55e31 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -731,12 +731,16 @@ mp_obj_t common_hal_wifi_radio_get_addresses_ap(wifi_radio_obj_t *self) { } uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - // return 0; - // } - // esp_netif_get_ip_info(self->netif, &self->ip_info); - // return self->ip_info.ip.addr; - return 0; + // Raw uint32_t sibling of common_hal_wifi_radio_get_ipv4_address(), + // used internally by supervisor/shared/web_workflow/web_workflow.c. + if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { + return 0; + } + struct in_addr *addr = net_if_ipv4_get_global_addr(self->sta_netif, NET_ADDR_PREFERRED); + if (addr == NULL) { + return 0; + } + return addr->s_addr; } mp_obj_t common_hal_wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { From 061391323838cf05f42636c84f19c5508a5c9b1a Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Mon, 3 Aug 2026 20:58:48 -0700 Subject: [PATCH 861/876] zephyr-cp/wifi: fix wifi.radio.addresses common_hal_wifi_radio_get_addresses() returned mp_const_none unconditionally, which is the wrong type in both states for the shared-bindings contract ("addresses: Sequence[str] ... Empty sequence when not connected"): None instead of a tuple when connected, None instead of an empty tuple when not. Reuse wifi_radio_get_ipv4_address() and format it as a string, which is what the espressif and raspberrypi ports return here rather than IPv4Address objects. get_addresses_ap() had the same problem and is corrected to mp_const_empty_tuple, without claiming AP mode works. Co-Authored-By: Claude Sonnet 5 --- ports/zephyr-cp/common-hal/wifi/Radio.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 60df2d55e31..007c90f5b46 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -721,13 +721,24 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_subnet_ap(wifi_radio_obj_t *self) { // } mp_obj_t common_hal_wifi_radio_get_addresses(wifi_radio_obj_t *self) { - // return common_hal_wifi_radio_get_addresses_netif(self, self->netif); - return mp_const_none; + // shared-bindings documents this as Sequence[str], empty when not + // connected, so format as a dotted-quad string rather than returning an + // IPv4Address object. Same address as wifi_radio_get_ipv4_address(). + uint32_t ipv4_address = wifi_radio_get_ipv4_address(self); + if (ipv4_address == 0) { + return mp_const_empty_tuple; + } + uint8_t *octets = (uint8_t *)&ipv4_address; + char buf[16]; + snprintf(buf, sizeof(buf), "%d.%d.%d.%d", octets[0], octets[1], octets[2], octets[3]); + mp_obj_t args[] = { mp_obj_new_str(buf, strlen(buf)) }; + return mp_obj_new_tuple(MP_ARRAY_SIZE(args), args); } mp_obj_t common_hal_wifi_radio_get_addresses_ap(wifi_radio_obj_t *self) { - // return common_hal_wifi_radio_get_addresses_netif(self, self->ap_netif); - return mp_const_none; + // AP mode is unimplemented here, but mp_const_none is still the wrong type + // for the Sequence[str] contract. + return mp_const_empty_tuple; } uint32_t wifi_radio_get_ipv4_address(wifi_radio_obj_t *self) { From 689420cc8b8cb1c876ac1fd1979328b8e41f20f5 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 4 Aug 2026 06:28:11 -0700 Subject: [PATCH 862/876] zephyr-cp/wifi: expose raw MAC getter, guard net_if_ip.ipv4 access wifi_radio_get_mac_address(self, uint8_t *) is declared in shared-bindings/wifi/Radio.h but was never implemented for this port; only the Python-facing common_hal_wifi_radio_get_mac_address() existed. Add the raw helper and have the existing function call it rather than duplicating the netif read. common_hal_wifi_radio_get_ipv4_gateway() and _subnet() read net_if_ip.ipv4 unconditionally, but that struct member only exists when CONFIG_NET_IPV4 is set. This file builds for every Wi-Fi board in the port's CI matrix, and nrf7002dk does not enable IPv4, so the unguarded access breaks that build. Guard both. --- ports/zephyr-cp/common-hal/wifi/Radio.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 007c90f5b46..a615c424259 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -123,14 +123,19 @@ void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *host } } -mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { - uint8_t mac[MAC_ADDRESS_LENGTH] = { 0 }; +void wifi_radio_get_mac_address(wifi_radio_obj_t *self, uint8_t *mac) { + memset(mac, 0, MAC_ADDRESS_LENGTH); if (self->sta_netif != NULL) { struct net_linkaddr *addr = net_if_get_link_addr(self->sta_netif); if (addr != NULL && addr->len >= MAC_ADDRESS_LENGTH) { memcpy(mac, addr->addr, MAC_ADDRESS_LENGTH); } } +} + +mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { + uint8_t mac[MAC_ADDRESS_LENGTH]; + wifi_radio_get_mac_address(self, mac); return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } @@ -645,6 +650,9 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_gateway(wifi_radio_obj_t *self) { if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { return mp_const_none; } + // net_if_ip.ipv4 only exists with CONFIG_NET_IPV4, and this file builds for + // every Wi-Fi board in the port, not just ones that enable it. + #if defined(CONFIG_NET_IPV4) const struct net_if_config *cfg = net_if_get_config(self->sta_netif); if (cfg == NULL || cfg->ip.ipv4 == NULL) { return mp_const_none; @@ -653,6 +661,9 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_gateway(wifi_radio_obj_t *self) { return mp_const_none; } return common_hal_ipaddress_new_ipv4address(cfg->ip.ipv4->gw.s_addr); + #else + return mp_const_none; + #endif } mp_obj_t common_hal_wifi_radio_get_ipv4_gateway_ap(wifi_radio_obj_t *self) { @@ -667,6 +678,8 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_subnet(wifi_radio_obj_t *self) { if (self->sta_netif == NULL || !net_if_is_up(self->sta_netif)) { return mp_const_none; } + // See get_ipv4_gateway: net_if_ip.ipv4 needs CONFIG_NET_IPV4. + #if defined(CONFIG_NET_IPV4) struct net_if_ipv4 *ipv4 = self->sta_netif->config.ip.ipv4; if (ipv4 == NULL) { return mp_const_none; @@ -678,6 +691,7 @@ mp_obj_t common_hal_wifi_radio_get_ipv4_subnet(wifi_radio_obj_t *self) { ipv4->unicast[i].netmask.s_addr); } } + #endif return mp_const_none; } From 090f81938935b9120f0a6a01b4a320d786354b44 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 25 Aug 2026 11:44:10 -0700 Subject: [PATCH 863/876] zephyr-cp/wifi: use WPA_AUTO_PERSONAL and drop the scan cache Review feedback from #11228. The per-AP security cache is gone. Pico W is the closest precedent, since the CYW43 driver needs an explicit auth mode the way Zephyr does, and it just uses password_len ? CYW43_AUTH_WPA2_AES_PSK : CYW43_AUTH_OPEN with no cache at all. Espressif sets no security type and lets the IDF infer it. So a password now means WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL and no password means WIFI_SECURITY_TYPE_NONE. The siwx91x driver maps WPA_AUTO_PERSONAL to SL_WIFI_WPA3_TRANSITION, which an AP in either WPA2 or WPA3 mode accepts, so this also covers the WPA3-only case that Pico W's hardcoded WPA2 does not. WIFI_SECURITY_TYPE_UNKNOWN is not usable here, the driver returns -ENOTSUP. That removes the 24 entry scan cache, its lookup and its insert path, and with it the question of reading a channel back out of it. Also folds wifi_radio_get_mac_address() into its only caller, and runs background tasks in the three waits (disconnect, association, DHCP) the way espressif does. Verified on two SiWx917-DK2605A boards: both associate to a WPA2 AP and take a DHCP lease, 192.168.0.39 and 192.168.0.133. --- ports/zephyr-cp/common-hal/wifi/Radio.c | 39 ++++++---------------- ports/zephyr-cp/common-hal/wifi/__init__.c | 30 ----------------- ports/zephyr-cp/common-hal/wifi/__init__.h | 4 --- 3 files changed, 10 insertions(+), 63 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index a615c424259..7658deac26e 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -123,19 +123,14 @@ void common_hal_wifi_radio_set_hostname(wifi_radio_obj_t *self, const char *host } } -void wifi_radio_get_mac_address(wifi_radio_obj_t *self, uint8_t *mac) { - memset(mac, 0, MAC_ADDRESS_LENGTH); +mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { + uint8_t mac[MAC_ADDRESS_LENGTH] = { 0 }; if (self->sta_netif != NULL) { struct net_linkaddr *addr = net_if_get_link_addr(self->sta_netif); if (addr != NULL && addr->len >= MAC_ADDRESS_LENGTH) { memcpy(mac, addr->addr, MAC_ADDRESS_LENGTH); } } -} - -mp_obj_t common_hal_wifi_radio_get_mac_address(wifi_radio_obj_t *self) { - uint8_t mac[MAC_ADDRESS_LENGTH]; - wifi_radio_get_mac_address(self, mac); return mp_obj_new_bytes(mac, MAC_ADDRESS_LENGTH); } @@ -483,28 +478,11 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t if (password_len > 0) { params.psk = password; params.psk_length = password_len; - // The security type must match what the AP advertises: this driver maps - // PSK to WPA2 and WPA_AUTO_PERSONAL to WPA3-transition, and rejects the - // wrong one with a generic "Authentication failure". So take it from the - // last scan, falling back to WPA2-PSK when the SSID was not seen. That - // fallback is wrong for a WPA3-only hidden AP. - params.security = WIFI_SECURITY_TYPE_PSK; - struct wifi_scan_result *cached = wifi_cached_scan_lookup(ssid, ssid_len); - if (cached != NULL) { - switch (cached->security) { - case WIFI_SECURITY_TYPE_SAE: - case WIFI_SECURITY_TYPE_SAE_H2E: - case WIFI_SECURITY_TYPE_SAE_AUTO: - params.security = WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL; - break; - case WIFI_SECURITY_TYPE_WPA_PSK: - params.security = WIFI_SECURITY_TYPE_WPA_PSK; - break; - default: - params.security = WIFI_SECURITY_TYPE_PSK; - break; - } - } + // WPA_AUTO_PERSONAL lets the driver settle on WPA2 or WPA3 with the AP + // rather than us guessing: it maps to WPA3-transition, which an AP in + // either mode accepts. WIFI_SECURITY_TYPE_UNKNOWN is not an option, the + // driver rejects it with -ENOTSUP. + params.security = WIFI_SECURITY_TYPE_WPA_AUTO_PERSONAL; } else { params.security = WIFI_SECURITY_TYPE_NONE; } @@ -530,6 +508,7 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t (void)net_mgmt(NET_REQUEST_WIFI_DISCONNECT, self->sta_netif, NULL, 0); // Give the controller a moment to tear the association down. for (int i = 0; i < 40 && self->connected; i++) { + RUN_BACKGROUND_TASKS; k_msleep(50); } self->connected = false; @@ -559,6 +538,7 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t int64_t deadline = k_uptime_get() + (int64_t)(timeout_s * 1000); bool signalled = false; while (k_uptime_get() < deadline) { + RUN_BACKGROUND_TASKS; if (k_sem_take(&self->connect_sem, K_MSEC(50)) == 0) { signalled = true; break; @@ -600,6 +580,7 @@ wifi_radio_error_t common_hal_wifi_radio_connect(wifi_radio_obj_t *self, uint8_t if (mp_hal_is_interrupted()) { break; } + RUN_BACKGROUND_TASKS; k_msleep(50); } #endif diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 33f1ad13ed8..427bc78fdf0 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -55,35 +55,6 @@ static void schedule_background_on_cp_core(void *arg) { static struct net_mgmt_event_callback wifi_cb; static struct net_mgmt_event_callback ipv4_cb; -// Small cache of the most recent scan, used by common_hal_wifi_radio_connect() -// to pick the right security type per AP. -#define WIFI_SCAN_CACHE_LEN 24 -static struct wifi_scan_result scan_cache[WIFI_SCAN_CACHE_LEN]; -static size_t scan_cache_count; - -struct wifi_scan_result *wifi_cached_scan_lookup(const uint8_t *ssid, size_t ssid_len) { - for (size_t i = 0; i < scan_cache_count; i++) { - if (scan_cache[i].ssid_length == ssid_len && - memcmp(scan_cache[i].ssid, ssid, ssid_len) == 0) { - return &scan_cache[i]; - } - } - return NULL; -} - -static void wifi_scan_cache_add(const struct wifi_scan_result *result) { - // Replace an existing entry for the same SSID so the cache tracks the - // latest reading rather than filling up with duplicate BSSIDs. - struct wifi_scan_result *existing = - wifi_cached_scan_lookup(result->ssid, result->ssid_length); - if (existing != NULL) { - *existing = *result; - return; - } - if (scan_cache_count < WIFI_SCAN_CACHE_LEN) { - scan_cache[scan_cache_count++] = *result; - } -} static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; @@ -96,7 +67,6 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve if (result != NULL) { // Remember the authmode so connect() can request the matching // security type later. - wifi_scan_cache_add(result); if (self->current_scan != NULL) { wifi_scannednetworks_scan_result(self->current_scan, result); } diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.h b/ports/zephyr-cp/common-hal/wifi/__init__.h index 9f730003878..937ac699021 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.h +++ b/ports/zephyr-cp/common-hal/wifi/__init__.h @@ -14,10 +14,6 @@ struct sockaddr_storage; void wifi_reset(void); -// Look up an SSID in the cache of the most recent scan. Returns NULL if the -// network was not seen. -struct wifi_scan_result *wifi_cached_scan_lookup(const uint8_t *ssid, size_t ssid_len); - // void ipaddress_ipaddress_to_esp_idf(mp_obj_t ip_address, ip_addr_t *esp_ip_address); // void ipaddress_ipaddress_to_esp_idf_ip4(mp_obj_t ip_address, esp_ip4_addr_t *esp_ip_address); From 642923133be2ad906f4fc2357f63b987e09a7fd9 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Wed, 26 Aug 2026 09:57:05 -0700 Subject: [PATCH 864/876] zephyr-cp/wifi: leave the scan result handler alone Review feedback from #11228. The nested if and the comment about remembering the authmode were only there to make room for the scan cache insert. The cache is gone, so this is back to exactly what main has. Drops the include and the blank line that came in with the cache too. Scan and connect still work on two SiWx917-DK2605A boards: 45 and 49 networks with correct RSSI and authmode, and both associate. --- ports/zephyr-cp/common-hal/wifi/__init__.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/__init__.c b/ports/zephyr-cp/common-hal/wifi/__init__.c index 427bc78fdf0..182ae5a3c30 100644 --- a/ports/zephyr-cp/common-hal/wifi/__init__.c +++ b/ports/zephyr-cp/common-hal/wifi/__init__.c @@ -4,8 +4,6 @@ // // SPDX-License-Identifier: MIT -#include - #include "common-hal/wifi/__init__.h" #include "shared-bindings/wifi/__init__.h" @@ -55,7 +53,6 @@ static void schedule_background_on_cp_core(void *arg) { static struct net_mgmt_event_callback wifi_cb; static struct net_mgmt_event_callback ipv4_cb; - static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_event, struct net_if *iface) { wifi_radio_obj_t *self = &common_hal_wifi_radio_obj; (void)iface; @@ -64,12 +61,8 @@ static void _event_handler(struct net_mgmt_event_callback *cb, uint64_t mgmt_eve case NET_EVENT_WIFI_SCAN_RESULT: { LOG_DBG("NET_EVENT_WIFI_SCAN_RESULT"); const struct wifi_scan_result *result = cb->info; - if (result != NULL) { - // Remember the authmode so connect() can request the matching - // security type later. - if (self->current_scan != NULL) { - wifi_scannednetworks_scan_result(self->current_scan, result); - } + if (result != NULL && self->current_scan != NULL) { + wifi_scannednetworks_scan_result(self->current_scan, result); } break; } From 7c3fdeb0a0ee3d161928c89c09504f82853982e4 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Thu, 27 Aug 2026 00:41:37 +0000 Subject: [PATCH 865/876] picogame: rework the API docs to CircuitPython conventions Reviewed against docs/design_guide.rst and the shared-bindings corpus: - parameters move from prose to :param: field lists; buffer APIs state element types, layouts and minimum sizes - every function, constructor and drawing primitive gets a docstring, and the six exported constants (STRIP_H, FPU, API_LEVEL and the three capability flags) get stubs - documented signatures match the runtime: Scene border insets and the target/layer unions, StripDraw always_dirty, float sprite positions - grouped attribute docstrings split so every attribute renders - factual fixes: framebuffer inversion happens during composition, always_dirty=False still renders once initially, near() is strictly less-than, Framebuffer output options are mutually exclusive - external helpers linked once from the module docstring instead of bare names throughout; measured numbers and rationale removed; ALL-CAPS emphasis and British spellings normalized; a module-level example added --- shared-bindings/picogame/Bitmap.c | 42 +++- shared-bindings/picogame/Canvas.c | 190 +++++++++++++----- shared-bindings/picogame/Display.c | 32 +-- shared-bindings/picogame/Framebuffer.c | 36 ++-- shared-bindings/picogame/Particles.c | 18 +- shared-bindings/picogame/Scene.c | 90 +++++---- shared-bindings/picogame/Sprite.c | 112 ++++++----- shared-bindings/picogame/StripDraw.c | 70 ++++--- shared-bindings/picogame/Tilemap.c | 19 +- shared-bindings/picogame/Triangles.c | 26 ++- shared-bindings/picogame/__init__.c | 263 ++++++++++++++++++------- 11 files changed, 608 insertions(+), 290 deletions(-) diff --git a/shared-bindings/picogame/Bitmap.c b/shared-bindings/picogame/Bitmap.c index b1199ed97cb..114e5e136de 100644 --- a/shared-bindings/picogame/Bitmap.c +++ b/shared-bindings/picogame/Bitmap.c @@ -31,10 +31,11 @@ //| class Bitmap: //| """An image atlas of one or more equal-size frames, of arbitrary size. +//| Pixel data and palette entries must be in the display's transfer byte +//| order; use :py:func:`rgb565` to build colors. //| -//| Unlike ``_stage`` (fixed 16x16 tiles), frames may be any width/height. -//| Pixel data and palette entries must be in the display's wire byte order -//| (use :py:func:`picogame.rgb565` to build colors).""" +//| The bitmap references the caller-provided data without copying or modifying +//| it. The backing buffer may live in RAM or in read-only memory.""" //| //| def __init__( //| self, @@ -47,7 +48,25 @@ //| frames: int = 1, //| stride: int = 0, //| transparent: Optional[int] = None, -//| ) -> None: ... +//| ) -> None: +//| """:param ~circuitpython_typing.ReadableBuffer data: pixel data in the +//| display's transfer byte order +//| :param int width: width of one frame in pixels +//| :param int height: height of one frame in pixels +//| :param int format: :py:data:`RGB565` (2 bytes per pixel) or :py:data:`PAL8` +//| (1 byte per pixel, indexing ``palette``) +//| :param ~circuitpython_typing.ReadableBuffer palette: for ``PAL8``, a buffer +//| of transfer-order RGB565 colors, two bytes per entry. Every byte in +//| ``data`` must be a valid palette index, that is, less than +//| ``len(palette) // 2``. +//| :param int frames: number of equal-size frames, laid out left to right in +//| one horizontal atlas +//| :param int stride: distance between two rows in pixels. Defaults to +//| ``width * frames``; set explicitly to reference a sub-region of a +//| wider image. +//| :param int transparent: color (``RGB565``) or index (``PAL8``) that is +//| skipped when drawing. Defaults to `None`, fully opaque.""" +//| ... //| static mp_obj_t picogame_bitmap_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -141,9 +160,11 @@ static mp_obj_t picogame_bitmap_make_new(const mp_obj_type_t *type, size_t n_arg //| //| width: int +//| """Width of one frame in pixels. (read-only)""" //| height: int +//| """Height of one frame in pixels. (read-only)""" //| frames: int -//| """Frame dimensions and frame count (read-only).""" +//| """Number of frames in the atlas. (read-only)""" static mp_obj_t bitmap_get_width(mp_obj_t self_in) { return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->width); } @@ -163,7 +184,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_frames_obj, bitmap_get_frames); MP_PROPERTY_GETTER(bitmap_frames_obj, (mp_obj_t)&bitmap_get_frames_obj); //| format: int -//| """RGB565 or PAL8 (read-only).""" +//| """:py:data:`RGB565` or :py:data:`PAL8`. (read-only)""" static mp_obj_t bitmap_get_format(mp_obj_t self_in) { return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->format); } @@ -171,7 +192,7 @@ static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_format_obj, bitmap_get_format); MP_PROPERTY_GETTER(bitmap_format_obj, (mp_obj_t)&bitmap_get_format_obj); //| stride: int -//| """Row stride in pixels (read-only).""" +//| """Row stride in pixels. (read-only)""" static mp_obj_t bitmap_get_stride(mp_obj_t self_in) { return MP_OBJ_NEW_SMALL_INT(((picogame_bitmap_obj_t *)MP_OBJ_TO_PTR(self_in))->stride); } @@ -179,8 +200,8 @@ static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_stride_obj, bitmap_get_stride); MP_PROPERTY_GETTER(bitmap_stride_obj, (mp_obj_t)&bitmap_get_stride_obj); //| palette: Optional[ReadableBuffer] -//| """The PAL8 palette buffer this Bitmap was built with, or None for RGB565 -//| (read-only). Lets palette helpers read it back instead of holding a sidecar ref.""" +//| """The ``PAL8`` palette buffer this Bitmap was built with, or `None` for +//| ``RGB565``. (read-only)""" static mp_obj_t bitmap_get_palette(mp_obj_t self_in) { picogame_bitmap_obj_t *self = MP_OBJ_TO_PTR(self_in); return (self->palette_obj == MP_OBJ_NULL) ? mp_const_none : self->palette_obj; @@ -189,7 +210,8 @@ static MP_DEFINE_CONST_FUN_OBJ_1(bitmap_get_palette_obj, bitmap_get_palette); MP_PROPERTY_GETTER(bitmap_palette_obj, (mp_obj_t)&bitmap_get_palette_obj); //| transparent: Optional[int] -//| """The transparent color/index, or None if the Bitmap is fully opaque (read-only).""" +//| """The transparent color or index, or `None` if the Bitmap is fully +//| opaque. (read-only)""" //| //| static mp_obj_t bitmap_get_transparent(mp_obj_t self_in) { diff --git a/shared-bindings/picogame/Canvas.c b/shared-bindings/picogame/Canvas.c index eaad4232901..b432bf26bf5 100644 --- a/shared-bindings/picogame/Canvas.c +++ b/shared-bindings/picogame/Canvas.c @@ -12,9 +12,9 @@ #include "shared-module/picogame/Canvas.h" //| class Canvas: -//| """A RAM drawing surface (any size) composited as a Scene layer. Draw -//| primitives into it; only redrawn areas repaint. Colors are wire-order -//| (use picogame.rgb565).""" +//| """A RAM drawing surface of any size, composited as a `Scene` layer. Draw +//| primitives into it; only redrawn areas repaint. Colors come from +//| :py:func:`rgb565`.""" //| //| def __init__( //| self, @@ -24,9 +24,14 @@ //| transparent: Optional[int] = None, //| buffer: Optional[WriteableBuffer] = None, //| ) -> None: -//| """If ``buffer`` is given (>= width*height*2 bytes, e.g. a memoryview from -//| picogame_arena), the Canvas draws into it instead of allocating its own - -//| lets you pre-allocate big surfaces once and dodge heap fragmentation.""" +//| """:param int width: surface width in pixels +//| :param int height: surface height in pixels +//| :param int transparent: color that is skipped when the canvas is +//| composited; `None` makes every pixel opaque +//| :param ~circuitpython_typing.WriteableBuffer buffer: optional caller-owned +//| pixel buffer of at least ``width * height * 2`` bytes (for example a +//| ``bytearray`` or a writable ``memoryview``). The canvas draws into it +//| instead of allocating its own.""" //| ... //| static mp_obj_t picogame_canvas_make_new(const mp_obj_type_t *type, size_t n_args, @@ -97,7 +102,9 @@ static picogame_canvas_obj_t *cv_args(const mp_obj_t *a, size_t n, int *v) { return cv_self(a[0]); } -//| def clear(self, color: int) -> None: ... +//| def clear(self, color: int) -> None: +//| """Fill the whole surface with ``color``.""" +//| ... //| static mp_obj_t canvas_clear(mp_obj_t self_in, mp_obj_t color) { picogame_canvas_clear(cv_self(self_in), mp_obj_get_int(color)); @@ -106,7 +113,9 @@ static mp_obj_t canvas_clear(mp_obj_t self_in, mp_obj_t color) { static MP_DEFINE_CONST_FUN_OBJ_2(canvas_clear_obj, canvas_clear); //| -//| def pixel(self, x: int, y: int, color: int) -> None: ... +//| def pixel(self, x: int, y: int, color: int) -> None: +//| """Set a single pixel.""" +//| ... //| static mp_obj_t canvas_pixel(size_t n, const mp_obj_t *a) { int v[3]; @@ -116,7 +125,9 @@ static mp_obj_t canvas_pixel(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_pixel_obj, 4, 4, canvas_pixel); //| -//| def fill_rect(self, x: int, y: int, w: int, h: int, color: int) -> None: ... +//| def fill_rect(self, x: int, y: int, w: int, h: int, color: int) -> None: +//| """Fill an axis-aligned rectangle.""" +//| ... //| static mp_obj_t canvas_fill_rect(size_t n, const mp_obj_t *a) { int v[5]; @@ -135,8 +146,8 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_rect_obj, 6, 6, canvas_fi //| flip_x: bool = False, //| flip_y: bool = False, //| ) -> None: -//| """Stamp frame ``frame`` of ``bitmap`` into the canvas at (x, y), honouring its transparent -//| key. The retained way to bake an image (icon, portrait, rendered text) into a panel.""" +//| """Stamp frame ``frame`` of ``bitmap`` into the canvas at ``(x, y)``, +//| honoring the bitmap's transparent color.""" //| ... //| static mp_obj_t canvas_blit(size_t n, const mp_obj_t *a) { @@ -165,9 +176,21 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_blit_obj, 4, 7, canvas_blit); //| cam_x: int, //| cam_y: int, //| ) -> None: -//| """Fill rows below ``horizon`` with a perspective ground plane (Mode-7) of -//| ``texture`` (power-of-2 dims). The int args are 16.16 fixed-point camera -//| terms; use the picogame_mode7 helper to compute them from angle/pos/fov.""" +//| """Fill rows below ``horizon`` with a perspective projection of ``texture``. +//| For a higher-level interface see the separately distributed +//| ``picogame_mode7`` helper, which computes the camera terms from an angle, +//| position and field of view. +//| +//| :param Bitmap texture: texture whose width and height are powers of two +//| :param int horizon: first canvas row to fill +//| :param int y_off: vertical offset of the projection, in rows +//| :param int z: camera height (signed 16.16 fixed-point) +//| :param int rx0: ray x at the left column (signed 16.16 fixed-point) +//| :param int ry0: ray y at the left column (signed 16.16 fixed-point) +//| :param int rsx: per-column ray step x (signed 16.16 fixed-point) +//| :param int rsy: per-column ray step y (signed 16.16 fixed-point) +//| :param int cam_x: camera x position (signed 16.16 fixed-point) +//| :param int cam_y: camera y position (signed 16.16 fixed-point)""" //| ... //| static mp_obj_t canvas_mode7(size_t n, const mp_obj_t *a) { @@ -189,14 +212,20 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_mode7_obj, 11, 11, canvas_mode //| x_off: int = 0, //| y_off: int = 0, //| ) -> None: -//| """Fill ``n`` triangles in ONE call: ``verts`` = int16 x0,y0,x1,y1,x2,y2 per triangle, -//| ``colors`` = uint16 wire RGB565 per triangle. Same rasteriser as fill_triangle, but the -//| whole batch crosses the Python/C boundary once - the win for many small triangles -//| (blocky 3D, low-poly meshes) where the ~10 us per-call overhead otherwise dominates. -//| ``x_off``/``y_off`` translate every vertex before clipping - pass the negated strip -//| origin (``y_off=-vy``) to replay one screen-space batch into each StripDraw view; -//| triangles fully outside the band are rejected with three compares, so the -//| per-strip re-submission stays cheap.""" +//| """Fill a batch of triangles in one call, which is faster than repeated +//| :py:meth:`fill_triangle` calls for many triangles. +//| +//| :param ~circuitpython_typing.ReadableBuffer verts: ``6 * n`` ``int16`` +//| values: x0, y0, x1, y1, x2, y2 per triangle +//| :param ~circuitpython_typing.ReadableBuffer colors: ``n`` ``uint16`` colors, +//| one per triangle +//| :param int n: number of triangles +//| :param int x_off: added to every x before clipping +//| :param int y_off: added to every y before clipping +//| +//| The offsets translate the whole batch, so one screen-space batch can be +//| replayed into each `StripDraw` view by passing the negated view origin +//| (``x_off=-vx, y_off=-vy``); triangles outside the view are skipped.""" //| ... //| static mp_obj_t canvas_fill_triangles(size_t na, const mp_obj_t *a) { @@ -233,13 +262,24 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_triangles_obj, 4, 6, canv //| x_off: int = 0, //| y_off: int = 0, //| ) -> None: -//| """Fill ``n`` vertical colour spans in ONE call: span i covers x0s[i]..x1s[i] (exclusive) -//| by tops[i]..bots[i] (exclusive) in colour colors[i] - all five are uint16 arrays. -//| The batch primitive for column renderers (a raycaster's merged wall runs): the whole -//| span list crosses the Python/C boundary once per strip instead of once per span. -//| ``x_off``/``y_off`` translate every span before clipping - pass the negated strip origin -//| (x_off=-vx, y_off=-vy) to replay one screen-space batch into each StripDraw view; -//| spans outside the band are rejected with two compares.""" +//| """Fill a batch of vertical color spans in one call. Span ``i`` covers +//| columns ``x0s[i]`` through ``x1s[i]`` (exclusive) and rows ``tops[i]`` +//| through ``bots[i]`` (exclusive) in color ``colors[i]``. +//| +//| :param ~circuitpython_typing.ReadableBuffer x0s: ``n`` ``uint16`` left edges +//| :param ~circuitpython_typing.ReadableBuffer x1s: ``n`` ``uint16`` exclusive +//| right edges +//| :param ~circuitpython_typing.ReadableBuffer tops: ``n`` ``uint16`` top rows +//| :param ~circuitpython_typing.ReadableBuffer bots: ``n`` ``uint16`` exclusive +//| bottom rows +//| :param ~circuitpython_typing.ReadableBuffer colors: ``n`` ``uint16`` colors +//| :param int n: number of spans +//| :param int x_off: added to every x before clipping +//| :param int y_off: added to every y before clipping +//| +//| The offsets translate the whole batch, so one screen-space batch (for +//| example `raycast` wall runs) can be replayed into each `StripDraw` view by +//| passing the negated view origin; spans outside the view are skipped.""" //| ... //| static mp_obj_t canvas_vspans(size_t na, const mp_obj_t *a) { @@ -290,11 +330,22 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_vspans_obj, 7, 9, canvas_vspan //| d07_q8: int, //| colors: ReadableBuffer, //| ) -> None: -//| """Draw one racing-road strip (OutRun-style) from precomputed tables - the whole -//| per-scanline loop in one call. ri0 = road-table row of this surface's row 0 (may be -//| negative = sky rows). tab = int16 rows of {edge_w, dash_hw, wb05_q8, wb07_q8, flags}; -//| rl/rr = int16 per-row edges (see picogame.road_edges); d05/d07 = Q8 scroll phases; -//| colors = 6x uint16 {sky, road_a, road_b, rumble_a, rumble_b, dash}.""" +//| """Draw one racing-road strip from precomputed tables. This method is +//| intended for use by the separately distributed ``picogame_road`` helper, +//| which builds the tables. +//| +//| :param int ri0: road-table row of this surface's row 0; negative values +//| are sky rows +//| :param ~circuitpython_typing.ReadableBuffer tab: ``int16`` rows of +//| ``edge_w``, ``dash_hw``, ``wb05_q8``, ``wb07_q8``, ``flags`` +//| :param ~circuitpython_typing.ReadableBuffer rl: ``int16`` per-row left +//| edges, as computed by :py:func:`road_edges` +//| :param ~circuitpython_typing.ReadableBuffer rr: ``int16`` per-row right +//| edges +//| :param int d05_q8: scroll phase (Q8 fixed-point) +//| :param int d07_q8: scroll phase (Q8 fixed-point) +//| :param ~circuitpython_typing.ReadableBuffer colors: six ``uint16`` colors, +//| in order: sky, road a, road b, rumble a, rumble b, dash""" //| ... //| static mp_obj_t canvas_road(size_t n, const mp_obj_t *a) { @@ -318,7 +369,9 @@ static mp_obj_t canvas_road(size_t n, const mp_obj_t *a) { } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_road_obj, 8, 8, canvas_road); -//| def rect(self, x: int, y: int, w: int, h: int, color: int) -> None: ... +//| def rect(self, x: int, y: int, w: int, h: int, color: int) -> None: +//| """Draw a one-pixel rectangle outline.""" +//| ... //| static mp_obj_t canvas_rect(size_t n, const mp_obj_t *a) { int v[5]; @@ -328,7 +381,9 @@ static mp_obj_t canvas_rect(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_rect_obj, 6, 6, canvas_rect); //| -//| def line(self, x0: int, y0: int, x1: int, y1: int, color: int) -> None: ... +//| def line(self, x0: int, y0: int, x1: int, y1: int, color: int) -> None: +//| """Draw a one-pixel line between two points.""" +//| ... //| static mp_obj_t canvas_line(size_t n, const mp_obj_t *a) { int v[5]; @@ -338,7 +393,9 @@ static mp_obj_t canvas_line(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_line_obj, 6, 6, canvas_line); //| -//| def fill_circle(self, cx: int, cy: int, r: int, color: int) -> None: ... +//| def fill_circle(self, cx: int, cy: int, r: int, color: int) -> None: +//| """Fill a circle of radius ``r`` centered on ``(cx, cy)``.""" +//| ... //| static mp_obj_t canvas_fill_circle(size_t n, const mp_obj_t *a) { int v[4]; @@ -348,7 +405,9 @@ static mp_obj_t canvas_fill_circle(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_circle_obj, 5, 5, canvas_fill_circle); //| -//| def circle(self, cx: int, cy: int, r: int, color: int) -> None: ... +//| def circle(self, cx: int, cy: int, r: int, color: int) -> None: +//| """Draw a one-pixel circle outline.""" +//| ... //| static mp_obj_t canvas_circle(size_t n, const mp_obj_t *a) { int v[4]; @@ -358,7 +417,9 @@ static mp_obj_t canvas_circle(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_circle_obj, 5, 5, canvas_circle); //| -//| def ring(self, cx: int, cy: int, r: int, thickness: int, color: int) -> None: ... +//| def ring(self, cx: int, cy: int, r: int, thickness: int, color: int) -> None: +//| """Draw a circle outline ``thickness`` pixels wide, grown inwards from radius ``r``.""" +//| ... //| static mp_obj_t canvas_ring(size_t n, const mp_obj_t *a) { int v[5]; @@ -370,7 +431,9 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_ring_obj, 6, 6, canvas_ring); //| //| def triangle( //| self, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int -//| ) -> None: ... +//| ) -> None: +//| """Draw a one-pixel triangle outline through the three points.""" +//| ... //| static mp_obj_t canvas_triangle(size_t n, const mp_obj_t *a) { int v[7]; @@ -382,7 +445,10 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_triangle_obj, 8, 8, canvas_tri //| //| def fill_triangle( //| self, x0: int, y0: int, x1: int, y1: int, x2: int, y2: int, color: int -//| ) -> None: ... +//| ) -> None: +//| """Fill a triangle. See :py:meth:`fill_triangles` to submit a whole batch +//| in one call.""" +//| ... //| static mp_obj_t canvas_fill_triangle(size_t n, const mp_obj_t *a) { int v[7]; @@ -392,7 +458,9 @@ static mp_obj_t canvas_fill_triangle(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_triangle_obj, 8, 8, canvas_fill_triangle); //| -//| def ellipse(self, cx: int, cy: int, rx: int, ry: int, color: int) -> None: ... +//| def ellipse(self, cx: int, cy: int, rx: int, ry: int, color: int) -> None: +//| """Draw a one-pixel ellipse outline with radii ``rx``/``ry``.""" +//| ... //| static mp_obj_t canvas_ellipse(size_t n, const mp_obj_t *a) { int v[5]; @@ -402,7 +470,9 @@ static mp_obj_t canvas_ellipse(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_ellipse_obj, 6, 6, canvas_ellipse); //| -//| def fill_ellipse(self, cx: int, cy: int, rx: int, ry: int, color: int) -> None: ... +//| def fill_ellipse(self, cx: int, cy: int, rx: int, ry: int, color: int) -> None: +//| """Fill an ellipse with radii ``rx``/``ry``.""" +//| ... //| static mp_obj_t canvas_fill_ellipse(size_t n, const mp_obj_t *a) { int v[5]; @@ -412,7 +482,9 @@ static mp_obj_t canvas_fill_ellipse(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_ellipse_obj, 6, 6, canvas_fill_ellipse); //| -//| def fill_round_rect(self, x: int, y: int, w: int, h: int, r: int, color: int) -> None: ... +//| def fill_round_rect(self, x: int, y: int, w: int, h: int, r: int, color: int) -> None: +//| """Fill a rectangle with corners rounded to radius ``r``.""" +//| ... //| static mp_obj_t canvas_fill_round_rect(size_t n, const mp_obj_t *a) { int v[6]; @@ -422,7 +494,10 @@ static mp_obj_t canvas_fill_round_rect(size_t n, const mp_obj_t *a) { static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_round_rect_obj, 7, 7, canvas_fill_round_rect); //| -//| def frame3d(self, x: int, y: int, w: int, h: int, light: int, dark: int) -> None: ... +//| def frame3d(self, x: int, y: int, w: int, h: int, light: int, dark: int) -> None: +//| """Draw a one-pixel bevelled frame: top and left edges in ``light``, bottom and +//| right in ``dark``, giving a raised look (swap the two for a sunken one).""" +//| ... //| static mp_obj_t canvas_frame3d(size_t n, const mp_obj_t *a) { int v[6]; @@ -435,11 +510,12 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_frame3d_obj, 7, 7, canvas_fram //| def text( //| self, x: int, y: int, s: str, fg: int, font: fontio.BuiltinFont, bg: int | None = None //| ) -> None: -//| """Composite ``s`` into the surface in C, rasterizing each glyph from ``font`` on the fly - -//| no Python glyph cache, no per-call Bitmap/Sprite (zero retained text RAM, no fragmentation). -//| If ``bg`` is given the glyph background is filled too; otherwise it is transparent. Inside a -//| StripDraw callback the ``view`` is a Canvas pointing at the live strip, so ``view.text(...)`` -//| draws immediate-mode HUD/screen text straight into the frame.""" +//| """Draw ``s`` into the surface, rasterizing each glyph from ``font`` as it +//| is drawn; no memory is retained between calls. If ``bg`` is given the glyph +//| background is filled with it, otherwise it is transparent. Inside a +//| `StripDraw` callback the view is a Canvas, so ``view.text(...)`` draws +//| text directly into the frame.""" +//| ... //| static mp_obj_t canvas_text(size_t n, const mp_obj_t *a) { const char *s = mp_obj_str_get_str(a[3]); @@ -453,7 +529,9 @@ static mp_obj_t canvas_text(size_t n, const mp_obj_t *a) { } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_text_obj, 6, 7, canvas_text); -//| def move(self, x: int, y: int) -> None: ... +//| def move(self, x: int, y: int) -> None: +//| """Move the surface's top-left corner to (x, y) and mark both the old and new area dirty.""" +//| ... //| static mp_obj_t canvas_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { picogame_canvas_obj_t *self = cv_self(self_in); @@ -472,11 +550,17 @@ static MP_DEFINE_CONST_FUN_OBJ_3(canvas_move_obj, canvas_move); //| //| x: int +//| """Horizontal position of the canvas top-left corner. (read-only) +//| +//| Set with :py:meth:`move`.""" //| y: int -//| """Current pixel position of the canvas top-left (read-only; set with move()).""" +//| """Vertical position of the canvas top-left corner. (read-only) +//| +//| Set with :py:meth:`move`.""" //| width: int +//| """Surface width in pixels. (read-only)""" //| height: int -//| """Surface size in pixels (read-only).""" +//| """Surface height in pixels. (read-only)""" //| //| static mp_obj_t canvas_get_x(mp_obj_t self_in) { diff --git a/shared-bindings/picogame/Display.c b/shared-bindings/picogame/Display.c index d0815c78997..deea95c70b2 100644 --- a/shared-bindings/picogame/Display.c +++ b/shared-bindings/picogame/Display.c @@ -17,18 +17,20 @@ #include "common-hal/picogame/Display.h" //| class Display: -//| """Fast display backend: wraps an existing ``busdisplay.BusDisplay`` and -//| pushes pixels with asynchronous double-buffered DMA, overlapping the CPU -//| blit of the next strip with the SPI transfer of the current one. +//| """An accelerated display backend that wraps an existing +//| :py:class:`~busdisplay.BusDisplay` and sends pixels with asynchronous, +//| double-buffered DMA. It reuses the wrapped display's bus, window commands +//| and dimensions. //| -//| Controller- and resolution-agnostic: reuses the busdisplay's SPI bus, -//| window commands and dimensions.""" +//| Constructing it raises :py:class:`NotImplementedError` when +//| :py:data:`FAST_DISPLAY_SUPPORTED` is `False`.""" //| //| def __init__(self, display: busdisplay.BusDisplay, *, rgb444: bool = False) -> None: -//| """rgb444=True drives the panel in 12-bit RGB444 instead of 16-bit RGB565: ~25% less -//| SPI traffic (and thus more FPS on full-screen / scrolling, transfer-bound scenes), at -//| 4096 colours instead of 65536 - which PAL8 art doesn't notice. The panel controller -//| must support COLMOD 12-bit (ST7789/ST7735 do; ILI9341 does NOT).""" +//| """:param ~busdisplay.BusDisplay display: the display to wrap +//| :param bool rgb444: drive the panel in 12-bit RGB444 instead of 16-bit +//| RGB565, reducing bus traffic at the cost of color depth (4,096 colors +//| instead of 65,536). The panel controller must support 12-bit color; +//| ST7789 and ST7735 do, ILI9341 does not. See :py:data:`RGB444_SUPPORTED`.""" //| ... //| static mp_obj_t picogame_display_make_new(const mp_obj_type_t *type, size_t n_args, @@ -62,13 +64,13 @@ static mp_obj_t picogame_display_make_new(const mp_obj_type_t *type, size_t n_ar //| *, //| background: int = 0, //| ) -> None: -//| """Render ``sprites`` into region [x0,x1) x [y0,y1) and push via async -//| DMA. ``buffer_a``/``buffer_b`` are two equal strip buffers used for -//| double buffering (each >= region_width*2 bytes). +//| """Render ``sprites`` into the screen region from ``(x0, y0)`` up to, but +//| not including, ``(x1, y1)``, and send it with asynchronous DMA. ``buffer_a`` and ``buffer_b`` are two +//| equal strip buffers of at least ``(x1 - x0) * 2`` bytes each, used for +//| double buffering. //| -//| SPRITES ONLY (unlike module-level ``picogame.render()``, which also accepts -//| StripDraw/Canvas/Tilemap/Particles): this is the low-level double-buffered -//| sprite push. For mixed layer kinds use a ``Scene`` or ``picogame.render()``.""" +//| This method accepts sprites only. For mixed layer kinds use a `Scene` or +//| the module-level :py:func:`render`.""" //| ... //| //| diff --git a/shared-bindings/picogame/Framebuffer.c b/shared-bindings/picogame/Framebuffer.c index 569093ee9d3..05b1612f190 100644 --- a/shared-bindings/picogame/Framebuffer.c +++ b/shared-bindings/picogame/Framebuffer.c @@ -31,16 +31,12 @@ // platforms - WASM playground, desktop sim, FruitJam DVI/HSTX) // --------------------------------------------------------------------------- //| class Framebuffer: -//| """A RAM framebuffer render target that a Scene or :py:func:`render` can draw -//| into instead of a BusDisplay. ``buffer`` must be a writable buffer of at least -//| ``width*height*2`` bytes (``width*height`` for ``rgb332=True``); the caller owns it -//| (a ``bytearray`` in the browser, the DVI scanout buffer on FruitJam). By default the -//| pixels are wire-order RGB565 (the engine's internal format); ``native_rgb565=True`` -//| byte-swaps each finished region to NATIVE RGB565 - the format 16-bit picodvi / -//| canvas scanout targets expect; ``rgb332=True`` quantizes each finished region to -//| RGB332 bytes - the format of 8-bit picodvi scanout (FruitJam 640x480, which the -//| hardware only offers at 8bpp). Assets, palettes and ``rgb565()`` stay wire-order -//| RGB565 throughout regardless of the output format.""" +//| """A RAM framebuffer render target that a `Scene` or :py:func:`render` can +//| draw into instead of a :py:class:`~busdisplay.BusDisplay`, for example the +//| scanout buffer of a :py:class:`picodvi.Framebuffer`. +//| +//| Constructing it raises :py:class:`NotImplementedError` when +//| :py:data:`FRAMEBUFFER_SUPPORTED` is `False`.""" //| //| def __init__( //| self, @@ -50,11 +46,27 @@ //| *, //| native_rgb565: bool = False, //| rgb332: bool = False, -//| ) -> None: ... +//| ) -> None: +//| """:param ~circuitpython_typing.WriteableBuffer buffer: caller-owned target +//| buffer of at least ``width * height * 2`` bytes, or ``width * height`` +//| bytes with ``rgb332=True`` +//| :param int width: target width in pixels +//| :param int height: target height in pixels +//| :param bool native_rgb565: fill the buffer with native-endian RGB565, the +//| format 16-bit scanout targets expect. By default the buffer holds +//| transfer-order RGB565. +//| :param bool rgb332: fill the buffer with 8-bit RGB332, the format of 8-bit +//| scanout targets +//| +//| ``native_rgb565`` and ``rgb332`` cannot both be true. Bitmaps, palettes and +//| :py:func:`rgb565` values stay transfer-order RGB565 regardless of the +//| output format.""" +//| ... //| //| width: int +//| """Target width in pixels. (read-only)""" //| height: int -//| """Target size in pixels (read-only).""" +//| """Target height in pixels. (read-only)""" //| //| // Static SRAM compose strip (see the scratch comment in make_new). 640*16*2 = 20 KB .bss, diff --git a/shared-bindings/picogame/Particles.c b/shared-bindings/picogame/Particles.c index 9f95050506f..d9602b307ba 100644 --- a/shared-bindings/picogame/Particles.c +++ b/shared-bindings/picogame/Particles.c @@ -24,7 +24,16 @@ static void reset_dirty(picogame_particles_obj_t *self) { //| //| def __init__( //| self, capacity: int, *, size: int = 1, gravity: float = 0.0, fade: bool = False -//| ) -> None: ... +//| ) -> None: +//| """``capacity`` is how many particles may be alive at once; the pool is +//| allocated once here and never grows, so an ``emit()`` beyond it simply drops the +//| extra particles. +//| +//| ``size`` is the square side of one particle in pixels. ``gravity`` is added to +//| each particle's vertical speed every :py:meth:`tick`. ``fade=True`` dims +//| particles towards the end of their life instead of letting them vanish at full +//| brightness.""" +//| ... //| static mp_obj_t picogame_particles_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -71,8 +80,9 @@ static mp_obj_t picogame_particles_make_new(const mp_obj_type_t *type, size_t n_ //| def emit( //| self, x: int, y: int, count: int, speed: int = 1, life: int = 30, color: int = 0xFFFF //| ) -> None: -//| """Spawn ``count`` particles at (x, y) with random velocity up to ``speed`` -//| px/tick, living ``life`` ticks, in wire-order ``color``.""" +//| """Spawn ``count`` particles at ``(x, y)``, living ``life`` ticks, in +//| ``color``. Each particle's horizontal and vertical velocity is chosen +//| independently from ``-speed`` through ``speed`` pixels per tick.""" //| ... //| static mp_obj_t picogame_particles_emit_fun(size_t n_args, const mp_obj_t *args) { @@ -91,7 +101,7 @@ static mp_obj_t picogame_particles_emit_fun(size_t n_args, const mp_obj_t *args) static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_particles_emit_obj, 4, 7, picogame_particles_emit_fun); //| def tick(self) -> None: -//| """Advance all particles one step (move, gravity, ageing).""" +//| """Advance all particles one step (movement, gravity, aging).""" //| ... //| static mp_obj_t picogame_particles_tick(mp_obj_t self_in) { diff --git a/shared-bindings/picogame/Scene.c b/shared-bindings/picogame/Scene.c index 778e53f0f7c..1f7e7c0d455 100644 --- a/shared-bindings/picogame/Scene.c +++ b/shared-bindings/picogame/Scene.c @@ -63,19 +63,39 @@ static mp_obj_t scene_resolve_target(mp_obj_t disp, bool *fast, bool *fb_target) } //| class Scene: -//| """Retained-mode scene with dirty-rectangle rendering. Add sprites and -//| tilemaps once (tilemaps first = bottom layer), mutate them each frame, -//| then call :py:meth:`refresh` - only the changed region is repainted. -//| Backed by a fast :py:class:`Display`.""" +//| """A retained-mode scene with dirty-rectangle rendering for a `Display`, +//| :py:class:`~busdisplay.BusDisplay` or `Framebuffer` target. Add layers once +//| (insertion order is bottom to top), mutate them each frame, then call +//| :py:meth:`refresh`; only the regions reported changed are repainted.""" //| //| def __init__( //| self, -//| display: Display, -//| buffer_a: WriteableBuffer, -//| buffer_b: WriteableBuffer, +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], +//| buffer_a: Optional[WriteableBuffer], +//| buffer_b: Optional[WriteableBuffer], //| *, //| background: int = 0, -//| ) -> None: ... +//| top: int = 0, +//| bottom: int = 0, +//| left: int = 0, +//| right: int = 0, +//| ) -> None: +//| """:param display: the render target +//| :param ~circuitpython_typing.WriteableBuffer buffer_a: a strip buffer of at +//| least ``display.width * STRIP_H * 2`` bytes. Two buffers let the next +//| strip be composited while the previous one is being sent. On a +//| `Framebuffer` target there are no strips and both may be `None`. +//| :param ~circuitpython_typing.WriteableBuffer buffer_b: the second strip +//| buffer, sized like ``buffer_a`` +//| :param int background: color that exposed areas are cleared to +//| :param int top: rows at the top edge the scene never renders into +//| :param int bottom: rows at the bottom edge the scene never renders into +//| :param int left: columns at the left edge the scene never renders into +//| :param int right: columns at the right edge the scene never renders into +//| +//| The four border insets reserve screen edges for content the application +//| draws itself; the scene renders only the inner rectangle.""" +//| ... //| static mp_obj_t picogame_scene_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -180,12 +200,15 @@ static void snapshot_sync(picogame_scene_obj_t *self) { //| //| def add( -//| self, item: Union[Sprite, Tilemap], *, fixed: bool = False -//| ) -> Union[Sprite, Tilemap]: -//| """Add a sprite/tilemap/particles/canvas (drawn next refresh; insertion -//| order is bottom-to-top). fixed=True pins the item to the screen (it ignores -//| the view offset) - use it for HUD / score / dialog over a scrolling world. -//| Returns the added item, so you can write ``spr = scene.add(Sprite(...))``.""" +//| self, item: Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles], *, fixed: bool = False +//| ) -> Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]: +//| """Add a layer of any kind, drawn starting with the next refresh; insertion +//| order is bottom to top. Returns the added item. +//| +//| ``fixed=True`` pins the item to the screen so it ignores the view offset +//| set by :py:meth:`set_view`, for example for a HUD over a scrolling world. +//| `StripDraw` and `Triangles` layers always draw in screen coordinates and +//| are unaffected by both ``fixed`` and the view offset.""" //| ... //| static void scene_add_one(picogame_scene_obj_t *self, mp_obj_t item_in, bool fixed) { @@ -229,8 +252,8 @@ static mp_obj_t picogame_scene_add(size_t n_args, const mp_obj_t *pos_args, mp_m } static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_scene_add_obj, 2, picogame_scene_add); -//| def add_all(self, items: Iterable[Union[Sprite, Tilemap]]) -> None: -//| """Add several sprites/tilemaps at once (bottom-to-top in order).""" +//| def add_all(self, items: Iterable[Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]]) -> None: +//| """Add several layers at once, bottom to top in iteration order.""" //| ... //| static mp_obj_t picogame_scene_add_all(mp_obj_t self_in, mp_obj_t iterable) { @@ -244,12 +267,11 @@ static mp_obj_t picogame_scene_add_all(mp_obj_t self_in, mp_obj_t iterable) { } static MP_DEFINE_CONST_FUN_OBJ_2(picogame_scene_add_all_obj, picogame_scene_add_all); -//| def remove(self, item: Union[Sprite, Tilemap]) -> None: -//| """Remove a previously add()ed item (draw order of the rest is unchanged). -//| The next refresh repaints over where it was (a full repaint, like -//| :py:meth:`invalidate`), so it leaves no ghost. The item itself is untouched - -//| keep a reference and add() it again later to bring it back. Raises -//| ValueError if the item is not in the scene (e.g. already removed).""" +//| def remove(self, item: Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]) -> None: +//| """Remove a previously added item; the draw order of the rest is unchanged. +//| The next refresh repaints the scene, so the item leaves no ghost. The item +//| itself is untouched and may be added again later. Raises +//| :py:class:`ValueError` if the item is not in the scene.""" //| ... //| static mp_obj_t picogame_scene_remove(mp_obj_t self_in, mp_obj_t item_in) { @@ -273,7 +295,7 @@ static mp_obj_t picogame_scene_remove(mp_obj_t self_in, mp_obj_t item_in) { static MP_DEFINE_CONST_FUN_OBJ_2(picogame_scene_remove_obj, picogame_scene_remove); //| def invalidate(self) -> None: -//| """Force a full-screen repaint on the next refresh (e.g. on scene change).""" +//| """Force the scene's whole render area to repaint on the next refresh.""" //| ... //| static mp_obj_t picogame_scene_invalidate(mp_obj_t self_in) { @@ -283,9 +305,10 @@ static mp_obj_t picogame_scene_invalidate(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_invalidate_obj, picogame_scene_invalidate); //| def set_view(self, ox: int, oy: int) -> None: -//| """Set the view offset = screen position of the scene origin. Use a -//| constant offset to centre a small game, or update it each frame to -//| scroll (which repaints the whole screen).""" +//| """Set the screen position ``(ox, oy)`` of scene coordinate ``(0, 0)``: +//| a scene point ``(x, y)`` is drawn at ``(x + ox, y + oy)``. Use a constant +//| offset to center a small scene, or update it each frame to scroll, which +//| repaints the whole render area.""" //| ... //| static mp_obj_t picogame_scene_set_view(mp_obj_t self_in, mp_obj_t ox_in, mp_obj_t oy_in) { @@ -302,7 +325,7 @@ static mp_obj_t picogame_scene_set_view(mp_obj_t self_in, mp_obj_t ox_in, mp_obj static MP_DEFINE_CONST_FUN_OBJ_3(picogame_scene_set_view_obj, picogame_scene_set_view); //| view: Tuple[int, int] -//| """The current view offset (ox, oy) as set by set_view() (read-only).""" +//| """The current view offset ``(ox, oy)`` as set by :py:meth:`set_view`. (read-only)""" static mp_obj_t picogame_scene_get_view(mp_obj_t self_in) { picogame_scene_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_t t[2] = { MP_OBJ_NEW_SMALL_INT(self->ox), MP_OBJ_NEW_SMALL_INT(self->oy) }; @@ -311,9 +334,8 @@ static mp_obj_t picogame_scene_get_view(mp_obj_t self_in) { static MP_DEFINE_CONST_FUN_OBJ_1(picogame_scene_get_view_obj, picogame_scene_get_view); MP_PROPERTY_GETTER(picogame_scene_view_obj, (mp_obj_t)&picogame_scene_get_view_obj); -//| display: Union[Display, busdisplay.BusDisplay] -//| """The backend this Scene was built with (a picogame.Display or a busdisplay), -//| read-only - handy for one-off picogame.render() / Display.render() calls.""" +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer] +//| """The render target this Scene was built with. (read-only)""" //| static mp_obj_t picogame_scene_get_display(mp_obj_t self_in) { return ((picogame_scene_obj_t *)MP_OBJ_TO_PTR(self_in))->display; @@ -439,9 +461,11 @@ static mp_obj_t scene_refresh_fb(picogame_scene_obj_t *self) { #endif // CIRCUITPY_PICOGAME_FRAMEBUFFER //| def refresh(self) -> Optional[list]: -//| """Diff against the previous frame and repaint only the changed region(s). -//| Returns the bounding dirty rect as a REUSED list [x1, y1, x2, y2] (read it -//| immediately; it's overwritten next call), or None if nothing changed.""" +//| """Repaint the regions reported changed by the scene's layers since the +//| previous refresh. Returns the bounding dirty rectangle as a list +//| ``[x1, y1, x2, y2]`` with exclusive ``x2``/``y2``, or `None` if nothing +//| changed. The returned list object is reused: read it before the next +//| ``refresh()`` call.""" //| ... //| //| diff --git a/shared-bindings/picogame/Sprite.c b/shared-bindings/picogame/Sprite.c index 99ac68e417b..fb3f93dc0bb 100644 --- a/shared-bindings/picogame/Sprite.c +++ b/shared-bindings/picogame/Sprite.c @@ -49,7 +49,14 @@ static int32_t pg_int_to_fp8(mp_int_t v) { //| visible: bool = True, //| flip_x: bool = False, //| flip_y: bool = False, -//| ) -> None: ... +//| ) -> None: +//| """Place frame ``frame`` of ``bitmap`` at (``x``, ``y``) - the top-left corner, in +//| world pixels, so a sprite on a scrolling layer moves with the view. +//| +//| ``visible=False`` creates the sprite without drawing it, for example to +//| pre-allocate a pool of sprites up front. ``flip_x`` and ``flip_y`` mirror +//| the frame at draw time.""" +//| ... //| static mp_obj_t picogame_sprite_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -126,19 +133,25 @@ static int32_t obj_to_fp(mp_obj_t o) { //| //| frame: int -//| """Which frame of the bitmap's atlas to draw (0-based) - animation = stepping this.""" +//| """Which frame of the bitmap's atlas to draw, starting at 0. Stepping this +//| animates the sprite.""" //| visible: bool -//| """False hides the sprite (it stays in the scene; the area under it repaints).""" +//| """`False` hides the sprite. It stays in the scene and the area under it +//| repaints.""" //| flip_x: bool +//| """Mirror the frame horizontally at draw time.""" //| flip_y: bool -//| """Mirror the frame horizontally / vertically at draw time (free on the fast path).""" +//| """Mirror the frame vertically at draw time.""" //| x: int +//| """Horizontal pixel position in scene coordinates. Setting accepts a float +//| for sub-pixel placement; reading returns the floored pixel.""" //| y: int -//| """Integer pixel position (scene coords). Setting accepts a float for -//| sub-pixel placement; reading returns the floored pixel.""" +//| """Vertical pixel position in scene coordinates. Setting accepts a float +//| for sub-pixel placement; reading returns the floored pixel.""" //| fx: float +//| """Horizontal sub-pixel position, for example ``sprite.fx += 2.4``.""" //| fy: float -//| """Sub-pixel position (use for smooth physics: e.g. ``sprite.fx += 2.4``).""" +//| """Vertical sub-pixel position, for example ``sprite.fy += 2.4``.""" // FLASH NOTE (property objects vs. a single `attr` handler): Sprite (and the other property-dense // types) expose each attribute as its own getter/setter + MP_PROPERTY object below - the standard // CircuitPython shared-bindings idiom (~423 such uses across CP). Collapsing these onto ONE `attr` @@ -229,8 +242,8 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flip_y_obj, sprite_set_flip_y); MP_PROPERTY_GETSET(sprite_flip_y_obj, (mp_obj_t)&sprite_get_flip_y_obj, (mp_obj_t)&sprite_set_flip_y_obj); //| scale: float -//| """Uniform draw scale (nearest-neighbour). 1.0 = native (fast path); 2.0 = double -//| size, fractional values are allowed (e.g. a powerup grow tween). Anchor stays put.""" +//| """Uniform draw scale using nearest-neighbor sampling. ``1.0`` is native size; +//| fractional values are allowed. The anchor point stays put.""" static mp_obj_t sprite_get_scale(mp_obj_t self_in) { return mp_obj_new_float(((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->scale * (mp_float_t)(1.0 / 256.0)); } @@ -258,8 +271,8 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_scale_obj, sprite_set_scale); MP_PROPERTY_GETSET(sprite_scale_obj, (mp_obj_t)&sprite_get_scale_obj, (mp_obj_t)&sprite_set_scale_obj); //| angle: float -//| """Rotation in degrees about the anchor (0 = none, the fast path). Nearest-neighbour, -//| so integer scales stay crisp; rotation shimmers slightly (pixel-art trade-off).""" +//| """Rotation in degrees about the anchor; ``0`` is unrotated. Values are stored +//| as whole degrees. Rotation uses nearest-neighbor sampling.""" static mp_obj_t sprite_get_angle(mp_obj_t self_in) { return mp_obj_new_float((mp_float_t)((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->angle); } @@ -282,9 +295,9 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_angle_obj, sprite_set_angle); MP_PROPERTY_GETSET(sprite_angle_obj, (mp_obj_t)&sprite_get_angle_obj, (mp_obj_t)&sprite_set_angle_obj); //| shadow: bool -//| """Draw opaque pixels as a darkened destination instead of colour - a drop-shadow -//| silhouette (offset copy below the sprite) or a dim overlay (a solid sprite scaled -//| over a dialog/pause area).""" +//| """Draw opaque pixels by darkening the destination instead of writing color, +//| producing a shadow silhouette or a dimming overlay. Mutually exclusive with +//| `flash`, `dither` and `tint`.""" static mp_obj_t sprite_get_shadow(mp_obj_t self_in) { return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_SHADOW) != 0); } @@ -297,9 +310,9 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_shadow_obj, sprite_set_shadow); MP_PROPERTY_GETSET(sprite_shadow_obj, (mp_obj_t)&sprite_get_shadow_obj, (mp_obj_t)&sprite_set_shadow_obj); //| flash: int -//| """Draw opaque pixels as a solid colour (a wire-order RGB565 int from rgb565) instead -//| of their own colour - a hit-flash or tint. Set to a colour to enable, 0/False to turn -//| off. Pulse it for 1-3 frames on impact. Mutually exclusive with shadow/dither.""" +//| """Draw opaque pixels as one solid color instead of their own, for example as +//| a brief hit flash. Set to a color from :py:func:`rgb565` to enable, ``0`` to +//| disable. Mutually exclusive with `shadow`, `dither` and `tint`.""" static mp_obj_t sprite_get_flash(mp_obj_t self_in) { picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_FLASH) ? s->flash_color : 0); @@ -321,9 +334,9 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_flash_obj, sprite_set_flash); MP_PROPERTY_GETSET(sprite_flash_obj, (mp_obj_t)&sprite_get_flash_obj, (mp_obj_t)&sprite_set_flash_obj); //| dither: int -//| """Fake transparency via an ordered (Bayer) dither, no alpha blending: 0 = opaque -//| (off), 8 = ~50% see-through, 16 = invisible. A classic 1-bit look - for ghosts, -//| fading/spawning enemies, fog, force fields. Mutually exclusive with shadow/flash.""" +//| """Approximate transparency with an ordered (Bayer) dither pattern; there is +//| no alpha blending. ``0`` is opaque (off), ``8`` is about half transparent and +//| ``16`` is invisible. Mutually exclusive with `shadow`, `flash` and `tint`.""" static mp_obj_t sprite_get_dither(mp_obj_t self_in) { picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_DITHER) ? s->dither : 0); @@ -346,10 +359,9 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_dither_obj, sprite_set_dither); MP_PROPERTY_GETSET(sprite_dither_obj, (mp_obj_t)&sprite_get_dither_obj, (mp_obj_t)&sprite_set_dither_obj); //| tint: int -//| """Multiply opaque pixels by a colour (wire-order RGB565 from rgb565), keeping the -//| sprite's shading - coloured lighting, a red damage flush, a blue freeze, a power-up -//| glow. Unlike ``flash`` (flat replace) ``tint`` preserves detail. 0/False = off. Mutually -//| exclusive with shadow/flash/dither.""" +//| """Multiply opaque pixels by a color from :py:func:`rgb565`, preserving the +//| sprite's shading (unlike `flash`, which replaces it). ``0`` disables. Mutually +//| exclusive with `shadow`, `flash` and `dither`.""" static mp_obj_t sprite_get_tint(mp_obj_t self_in) { picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_TINT) ? s->flash_color : 0); @@ -369,10 +381,11 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_tint_obj, sprite_set_tint); MP_PROPERTY_GETSET(sprite_tint_obj, (mp_obj_t)&sprite_get_tint_obj, (mp_obj_t)&sprite_set_tint_obj); //| transpose: bool -//| """Swap the sprite's X/Y axes - a cheap 90deg turn (no shimmer, unlike ``angle``). -//| Combined with ``flip_x``/``flip_y`` it gives all 8 orientations for free. Only on the fast -//| path (scale 1.0, angle 0); for rotation WITH scaling use ``angle``. The drawn footprint -//| swaps width/height.""" +//| """Swap the sprite's x and y axes, turning the frame by 90 degrees without +//| resampling. Combined with `flip_x` and `flip_y` this yields all 8 +//| orientations. Applies only at ``scale == 1.0`` and ``angle == 0``; for +//| rotation combined with scaling use `angle`. The drawn footprint swaps +//| width and height.""" static mp_obj_t sprite_get_transpose(mp_obj_t self_in) { return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_TRANSPOSE) != 0); } @@ -398,9 +411,9 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_data_obj, sprite_set_data); MP_PROPERTY_GETSET(sprite_data_obj, (mp_obj_t)&sprite_get_data_obj, (mp_obj_t)&sprite_set_data_obj); //| bitmap: Bitmap -//| """The sprite's source bitmap. Assigning a new one swaps graphics and may -//| change size; the scene repaints both the old and new bounds next refresh -//| (e.g. powerups, resizable HUD bars, text labels).""" +//| """The sprite's source bitmap. Assigning a new one swaps the graphics and may +//| change the sprite's size; the scene repaints both the old and new bounds on +//| the next refresh.""" static mp_obj_t sprite_get_bitmap(mp_obj_t self_in) { picogame_sprite_obj_t *self = MP_OBJ_TO_PTR(self_in); return self->bitmap != NULL ? MP_OBJ_FROM_PTR(self->bitmap) : mp_const_none; @@ -450,8 +463,8 @@ static mp_obj_t sprite_set_anchor(mp_obj_t self_in, mp_obj_t v) { static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_anchor_obj, sprite_set_anchor); MP_PROPERTY_GETSET(sprite_anchor_obj, (mp_obj_t)&sprite_get_anchor_obj, (mp_obj_t)&sprite_set_anchor_obj); -//| def move(self, x: int, y: int) -> None: -//| """Set the sprite position.""" +//| def move(self, x: float, y: float) -> None: +//| """Set the sprite position. Accepts floats for sub-pixel placement.""" //| ... //| static mp_obj_t sprite_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { @@ -463,10 +476,10 @@ static mp_obj_t sprite_move(mp_obj_t self_in, mp_obj_t x_in, mp_obj_t y_in) { static MP_DEFINE_CONST_FUN_OBJ_3(sprite_move_obj, sprite_move); //| def touch(self) -> None: -//| """Force this sprite to repaint on the next ``Scene.refresh()`` even though none -//| of its tracked properties (position, frame, scale, angle, bitmap) changed. Call -//| it after mutating the sprite's bitmap pixels IN PLACE (e.g. streaming a new frame -//| into the same buffer), which the dirty-rect tracker can't otherwise detect.""" +//| """Force this sprite to repaint on the next :py:meth:`Scene.refresh` even +//| though none of its tracked properties (position, frame, scale, angle, +//| bitmap) changed. Call it after mutating the bitmap's backing buffer in +//| place, which the dirty-region tracking cannot otherwise detect.""" //| ... //| static mp_obj_t sprite_touch(mp_obj_t self_in) { @@ -502,12 +515,16 @@ static void pg_obj_to_box(mp_obj_t o, int *x1, int *y1, int *x2, int *y2) { MP_QSTR_other, MP_QSTR_Sprite, MP_QSTR_tuple, mp_obj_get_type(o)->name); } -//| def overlaps(self, other: "Sprite | tuple", inset: int = 0) -> bool: -//| """True if this sprite's drawn box overlaps ``other`` - an inclusive AABB, so they -//| collide the moment they touch. ``other`` may be another Sprite, a point ``(x, y)``, -//| or a rect ``(x1, y1, x2, y2)`` (e.g. a trigger zone or the screen for culling). -//| The box is anchor/scale/rotation aware. ``inset`` shrinks THIS sprite's box by N px -//| on each side, for a fair hitbox smaller than the art.""" +//| def overlaps( +//| self, +//| other: Union[Sprite, Tuple[int, int], Tuple[int, int, int, int]], +//| inset: int = 0, +//| ) -> bool: +//| """Return `True` if this sprite's drawn rectangle overlaps ``other``. Bounds +//| are inclusive, so touching edges count as an overlap. ``other`` may be +//| another `Sprite`, a point ``(x, y)`` or a rectangle ``(x1, y1, x2, y2)``. +//| The rectangle accounts for anchor, scale and rotation. ``inset`` shrinks +//| this sprite's rectangle by that many pixels on each side.""" //| ... //| static mp_obj_t sprite_overlaps(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -528,11 +545,10 @@ static mp_obj_t sprite_overlaps(size_t n_args, const mp_obj_t *pos_args, mp_map_ } static MP_DEFINE_CONST_FUN_OBJ_KW(sprite_overlaps_obj, 2, sprite_overlaps); -//| def near(self, other: "Sprite | tuple", r: int) -> bool: -//| """True if this sprite's centre is within ``r`` pixels of ``other``'s centre (squared -//| distance, no sqrt) - the round/forgiving test for bullets, pickups, explosions. -//| ``other`` may be a Sprite or a point ``(x, y)``. Centres come from the drawn box, so -//| it is anchor aware.""" +//| def near(self, other: Union[Sprite, Tuple[int, int]], r: int) -> bool: +//| """Return `True` when the distance between centers is less than ``r`` +//| pixels. ``other`` may be a `Sprite` or a point ``(x, y)``. Centers come +//| from the drawn rectangle, so the test accounts for the anchor.""" //| ... //| //| diff --git a/shared-bindings/picogame/StripDraw.c b/shared-bindings/picogame/StripDraw.c index ffd05de9372..02436a928ca 100644 --- a/shared-bindings/picogame/StripDraw.c +++ b/shared-bindings/picogame/StripDraw.c @@ -31,22 +31,19 @@ // --------------------------------------------------------------------------- //| class StripDraw: -//| """An immediate-mode draw layer that holds NO pixel buffer. Each refresh, for -//| every render strip overlapping its rect, ``callback(view, vx, vy, vw, vh)`` is -//| called with a :py:class:`Canvas` ``view`` pointing straight at the live strip -//| buffer - so you draw primitives directly into the frame (zero RAM, vs a Canvas -//| which costs width*height*2 bytes). The view's local (0, 0) is screen pixel -//| (vx, vy); (vw, vh) is the strip size. Draw only the rows in [vy, vy+vh) for -//| speed (anything outside the view is clipped anyway). The rect is repainted every -//| frame, so use it for animated / scanline content (pseudo-3D, gradients, -//| procedural backgrounds), not static art (use Canvas for that). +//| """An immediate-mode draw layer that holds no pixel buffer. On each refresh, +//| for every render strip overlapping its rectangle, ``callback(view, vx, vy, +//| vw, vh)`` is called with a `Canvas` view of the live strip buffer, so the +//| callback draws primitives directly into the frame. StripDraw layers always +//| draw in screen coordinates and ignore the scene's view offset. //| -//| COORDINATE CONTRACT: ``vx`` is the RENDER REGION's origin (NOT this layer's x), and the -//| view spans the FULL region WIDTH (the layer's rect only gates which ROWS run). So draw at -//| ABSOLUTE screen coords minus (vx, vy), and fill only your own rect with ``fill_rect`` - -//| ``view.clear()`` fills the whole region width. (When you render a StripDraw via -//| ``picogame.render([sd], buf, x,y,x+w,y+h)`` the region == the rect, so vx == x.) -//| Text via ``Canvas.text`` is ASCII (the built-in font); non-ASCII has no glyph.""" +//| ``(vx, vy)`` is the view origin in screen coordinates and ``(vw, vh)`` is +//| its size: to draw a screen point ``(sx, sy)``, draw at ``(sx - vx, sy - vy)`` +//| in ``view``. The view may span the full render-region width even when the +//| layer is narrower (the layer's rectangle only selects which rows run), so +//| fill your own rectangle with :py:meth:`Canvas.fill_rect` rather than +//| ``view.clear()``, which fills the whole width. Text drawn with +//| :py:meth:`Canvas.text` supports ASCII only.""" //| //| def __init__( //| self, @@ -55,7 +52,17 @@ //| y: int = 0, //| width: int = 0, //| height: int = 0, -//| ) -> None: ... +//| *, +//| always_dirty: bool = True, +//| ) -> None: +//| """:param callback: called for each overlapping render strip as +//| ``callback(view, vx, vy, vw, vh)`` +//| :param int x: left edge of the layer's screen rectangle +//| :param int y: top edge of the layer's screen rectangle +//| :param int width: rectangle width in pixels +//| :param int height: rectangle height in pixels +//| :param bool always_dirty: see :py:attr:`always_dirty`""" +//| ... //| static mp_obj_t picogame_stripdraw_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { @@ -99,12 +106,16 @@ static mp_obj_t picogame_stripdraw_make_new(const mp_obj_type_t *type, size_t n_ //| //| x: int +//| """Left edge of the layer's screen rectangle.""" //| y: int +//| """Top edge of the layer's screen rectangle.""" //| width: int +//| """Width of the layer's screen rectangle in pixels.""" //| height: int -//| """The screen rect repainted each refresh (read/write). Move or resize the layer -//| by assigning these. Shrinking the rect leaves stale pixels behind - follow a -//| shrink with ``scene.invalidate()`` for a clean repaint (as the fx helpers do).""" +//| """Height of the layer's screen rectangle in pixels. +//| +//| Moving or resizing the rectangle by assigning any of these can leave the old +//| area stale; call :py:meth:`Scene.invalidate` afterwards for a clean repaint.""" static mp_obj_t sd_get_x(mp_obj_t self_in) { return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x); } @@ -150,10 +161,10 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_height_obj, sd_set_height); MP_PROPERTY_GETSET(sd_height_obj, (mp_obj_t)&sd_get_height_obj, (mp_obj_t)&sd_set_height_obj); //| always_dirty: bool -//| """True (default): repaint every frame - for animated content (pseudo-3D, gradients). False: -//| repaint only after an ``invalidate()`` call (or when overlapped by another dirty layer) - for on-change UI, -//| so a static panel doesn't re-rasterize+re-push every frame. With False you MUST invalidate() on -//| every content/visibility change (it's invisible until you do).""" +//| """When `True` (the default) the rectangle repaints every frame, for animated +//| content. When `False` the layer renders once initially and then repaints only +//| after an :py:meth:`invalidate` call or when overlapped by another dirty +//| layer; call :py:meth:`invalidate` after each content change.""" //| static mp_obj_t sd_get_always_dirty(mp_obj_t self_in) { return mp_obj_new_bool(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->always_dirty); @@ -167,11 +178,14 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sd_set_always_dirty_obj, sd_set_always_dirty); MP_PROPERTY_GETSET(sd_always_dirty_obj, (mp_obj_t)&sd_get_always_dirty_obj, (mp_obj_t)&sd_set_always_dirty_obj); //| def invalidate(self, x: int = 0, y: int = 0, w: int = 0, h: int = 0) -> None: -//| """Mark dirty so the layer repaints on the next refresh (only needed when -//| ``always_dirty=False``). With no args, the whole layer repaints. Pass a rect in -//| VIEW-LOCAL coordinates (the same (0,0)-at-``(vx, vy)`` space the draw callback uses) to -//| repaint only that region - like Canvas/Tilemap, the Scene then recomposites and pushes just -//| those rows. Repeated calls union; the rect is clamped to the layer.""" +//| """Mark the layer dirty so it repaints on the next refresh; only needed +//| when ``always_dirty`` is `False`. +//| +//| With no arguments the whole layer repaints. To repaint one region, pass +//| all four values as a rectangle in the view-local coordinates the draw +//| callback uses; an incomplete rectangle repaints the whole layer. Repeated +//| calls accumulate, and the rectangle is clamped to the layer.""" +//| ... //| //| static mp_obj_t sd_invalidate(size_t n_args, const mp_obj_t *args) { diff --git a/shared-bindings/picogame/Tilemap.c b/shared-bindings/picogame/Tilemap.c index 849bec01532..27b8dfadbc5 100644 --- a/shared-bindings/picogame/Tilemap.c +++ b/shared-bindings/picogame/Tilemap.c @@ -82,10 +82,11 @@ static MP_DEFINE_CONST_FUN_OBJ_3(picogame_tilemap_get_tile_obj, picogame_tilemap //| flip_y: bool = False, //| transpose: bool = False, //| ) -> None: -//| """Set the tile at (tx, ty) and mark it dirty. The keyword ``flip_x``/``flip_y``/ -//| ``transpose`` flags orient the tile - together they give all 8 orientations -//| (4 rotations x mirror) for free at draw time; use them with a deduplicated tileset -//| (png2picogame --dedup REMAP). Out-of-range writes are ignored.""" +//| """Set the tile at ``(tx, ty)`` and mark it dirty. The keyword flags orient +//| the tile at draw time; together they yield all 8 orientations (4 rotations +//| times mirror), so one stored tile can serve as several. The flags can +//| represent the remap table emitted by the separately distributed +//| ``png2picogame.py --dedup`` tool. Out-of-range writes are ignored.""" //| ... //| static mp_obj_t picogame_tilemap_set_tile(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { @@ -187,11 +188,17 @@ static mp_obj_t picogame_tilemap_fill(mp_obj_t self_in, mp_obj_t value_in) { static MP_DEFINE_CONST_FUN_OBJ_2(picogame_tilemap_fill_obj, picogame_tilemap_fill); //| x: int +//| """Horizontal position of the map's top-left corner. (read-only) +//| +//| Set with :py:meth:`move`.""" //| y: int -//| """Current pixel position of the map's top-left (read-only; set with move()).""" +//| """Vertical position of the map's top-left corner. (read-only) +//| +//| Set with :py:meth:`move`.""" //| cols: int +//| """Map width in tiles. (read-only)""" //| rows: int -//| """Map size in tiles (read-only).""" +//| """Map height in tiles. (read-only)""" //| //| static mp_obj_t tilemap_get_x(mp_obj_t self_in) { diff --git a/shared-bindings/picogame/Triangles.c b/shared-bindings/picogame/Triangles.c index d3b7fea51a7..bbb1f5e6fcb 100644 --- a/shared-bindings/picogame/Triangles.c +++ b/shared-bindings/picogame/Triangles.c @@ -27,15 +27,21 @@ #include "shared-module/picogame/Sprite.h" //| class Triangles: +//| """A retained triangle batch drawn as a `Scene` layer. The batch is +//| rasterized directly into each render strip; no per-strip Python runs and no +//| pixel buffer is held. Triangles layers always draw in screen coordinates and +//| ignore the scene's view offset. +//| +//| A typical frame projects points with :py:func:`project`, fills the arrays in +//| place back to front, sets :py:attr:`count` and calls +//| :py:meth:`Scene.refresh`.""" +//| //| def __init__(self, verts: ReadableBuffer, colors: ReadableBuffer) -> None: -//| """A retained SCREEN-SPACE triangle batch drawn entirely in C by the compositor: -//| ``verts`` = int16 x0,y0,x1,y1,x2,y2 per triangle, ``colors`` = uint16 wire RGB565 per -//| triangle - both CALLER-OWNED (fill them in place each frame). Set ``count`` to how -//| many triangles should draw; the assignment marks the layer dirty (full screen). -//| Unlike a StripDraw callback this runs no Python per strip, and unlike a Canvas it -//| holds no pixel buffer - the batch rasterises straight into each render strip with -//| a cheap band reject. The 3D-scene layer: pg.project into the arrays, painter's-order -//| the faces, set count, scene.refresh().""" +//| """:param ~circuitpython_typing.ReadableBuffer verts: caller-owned buffer of +//| ``int16`` values, six per triangle: x0, y0, x1, y1, x2, y2. Refill it in +//| place each frame. +//| :param ~circuitpython_typing.ReadableBuffer colors: caller-owned buffer of +//| ``uint16`` colors, one per triangle""" //| ... //| static mp_obj_t picogame_triangles_make_new(const mp_obj_type_t *type, size_t n_args, @@ -58,8 +64,8 @@ static mp_obj_t picogame_triangles_make_new(const mp_obj_type_t *type, size_t n_ } //| count: int -//| """How many triangles of the batch draw next refresh (clamped to the buffer -//| capacity). Assigning marks the layer dirty for a full repaint.""" +//| """How many triangles of the batch draw on the next refresh, clamped to the +//| buffer capacity. Assigning marks the layer dirty for a full repaint.""" //| //| static mp_obj_t tri_get_count(mp_obj_t self_in) { diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c index e5116ceec8c..739d781cf52 100644 --- a/shared-bindings/picogame/__init__.c +++ b/shared-bindings/picogame/__init__.c @@ -50,36 +50,91 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { return MP_OBJ_TO_PTR(native); } -//| """2D game engine for the PicoPad and similar boards. -//| -//| Draws arbitrary-size sprites (unlike ``_stage``'s fixed 16x16 tiles) to a -//| ``busdisplay`` through a reusable strip buffer, with a dirty-rect scene, -//| tilemaps, particles, a drawing canvas and camera/effects. -//| -//| **Relationship to displayio.** picogame does not replace or extend -//| :py:mod:`displayio`; it is a second, game-shaped way to drive the same -//| hardware, and the two do not share a display at the same time. displayio -//| retains a widget tree the supervisor refreshes for you, holds a full -//| :py:class:`~displayio.Bitmap` per image and is the right tool for UI. picogame -//| composites on demand, one horizontal strip at a time, into a buffer the game -//| owns: nothing is retained per pixel, so a scrolling game fits in the RAM a -//| microcontroller actually has, and the game decides when a frame happens -//| (``scene.refresh()``). -//| -//| displayio and picogame share the Display object. A ``picogame.Scene`` takes the same -//| :py:class:`~busdisplay.BusDisplay` displayio uses - it just talks to it -//| directly instead of through the displayio refresh loop, so set -//| ``display.auto_refresh = False`` (``picogame_game.setup()`` does this) and let -//| the game drive. On boards that scan out of RAM, ``picogame.Framebuffer`` takes -//| that buffer instead. Bitmaps are separate types: displayio's is a mutable -//| indexed surface, picogame's is read-only pixel data (PAL8 or wire RGB565) that -//| may live in flash, so it costs no RAM at all.""" +//| """Game rendering +//| +//| The `picogame` module composites sprites, tilemaps, drawing canvases, +//| particle layers, 3D triangle batches and immediate-mode callbacks into a +//| small reusable strip buffer and sends each strip to the display, so a full-screen game does not +//| need a full-screen buffer. A :py:class:`Scene` tracks what changed and +//| repaints only those regions when :py:meth:`Scene.refresh` is called. +//| +//| A scene targets a :py:class:`~busdisplay.BusDisplay`, an accelerated +//| :py:class:`Display` or a RAM :py:class:`Framebuffer`. picogame drives the +//| display itself: set ``display.auto_refresh = False``, and do not use +//| displayio groups on the same display at the same time. +//| +//| Unless stated otherwise, color integers are display transfer-order RGB565 +//| values as returned by :py:func:`rgb565`. Render rectangles include +//| ``(x0, y0)`` and exclude ``(x1, y1)``; collision rectangles use inclusive +//| edges as documented by :py:func:`collide`. +//| +//| .. note:: +//| This module is the engine's rendering and compute core and is fully +//| usable on its own. The separately distributed pure-Python `picogame +//| helper libraries `_ +//| (``picogame_game``, ``picogame_ray`` and others) build a complete game +//| framework on top of it: display, input and audio setup that adapts to +//| the board, game-loop timing, sprite pools and collision helpers, +//| animation, text, HUD and menus, sound effects and music, visual +//| effects, saved games, scene loading and pseudo-3D cameras. A desktop +//| simulator, asset-conversion tools, examples and tutorials live in the +//| `picogame repository `_, with +//| documentation at `picogame.makerclass.cz +//| `_. +//| +//| Example:: +//| +//| import array +//| import board +//| import time +//| +//| import picogame +//| +//| display = board.DISPLAY +//| display.auto_refresh = False +//| +//| size = display.width * picogame.STRIP_H * 2 +//| scene = picogame.Scene(display, bytearray(size), bytearray(size)) +//| +//| # One solid white 8x8 frame. +//| data = array.array("H", [0xFFFF] * 64) +//| bitmap = picogame.Bitmap(data, 8, 8) +//| player = scene.add(picogame.Sprite(bitmap, x=0, y=display.height // 2)) +//| +//| while True: +//| player.x = (player.x + 1) % display.width +//| scene.refresh() +//| time.sleep(0.02) +//| +//| This moves a white square across the screen, repainting only the pixels +//| that changed each frame.""" //| //| RGB565: int //| """16-bit color bitmap format (wire byte order).""" //| PAL8: int //| """8-bit paletted bitmap format.""" //| +//| STRIP_H: int +//| """Default render-strip height in rows for this build. A `Scene` strip +//| buffer is ``display.width * STRIP_H * 2`` bytes.""" +//| +//| FPU: int +//| """``1`` when `project` uses hardware floating point (its buffers are +//| ``float32``), ``0`` when it uses signed 16.16 fixed-point ``int32``.""" +//| +//| API_LEVEL: int +//| """Version of the picogame API. Separately distributed helpers compare it +//| against the version they were written for.""" +//| +//| RGB444_SUPPORTED: bool +//| """Whether `Display` supports ``rgb444=True`` on this board.""" +//| +//| FAST_DISPLAY_SUPPORTED: bool +//| """Whether the accelerated `Display` backend is available on this board.""" +//| +//| FRAMEBUFFER_SUPPORTED: bool +//| """Whether `Framebuffer` is available on this board.""" +//| //| //| def rgb565(r: int, g: int, b: int) -> int: //| """Build a display wire-order RGB565 color from 8-bit components.""" @@ -116,19 +171,39 @@ static MP_DEFINE_CONST_FUN_OBJ_3(picogame_rgb565_obj, picogame_rgb565); //| dist: WriteableBuffer, //| runs: Optional[WriteableBuffer] = None, //| ) -> Optional[int]: -//| """Cast one frame of DDA wall rays (the compute core of the ``picogame_ray`` helper). -//| -//| ``map`` holds ``mw*mh`` wall-type bytes (0 = empty). The camera position -//| (``posx``/``posy``), the column-0 ray (``lrx``/``lry``) and the per-column ray step -//| (``srx``/``sry``) are 16.16 fixed-point; ``sh`` is the screen height and ``stride`` -//| the pixel width of one column. For each of the ``ncols`` columns the wall top/bottom -//| rows, the wall colour (near/side pairs from ``wcolors``) and the perpendicular -//| distance (16.16, into ``dist``) are written to the output buffers. -//| -//| With ``runs`` (a ``uint16`` buffer of at least ``5*ncols``, five ``ncols``-long -//| planes: x0s, x1s, tops, bots, colors) adjacent equal columns are merged into wall -//| runs for :py:meth:`Canvas.vspans` and the run count is returned; without it -//| returns ``None``.""" +//| """Cast one frame of DDA wall rays. This function is intended for use by the +//| separately distributed ``picogame_ray`` helper, which computes the inputs. +//| +//| All fixed-point arguments are signed 16.16 integers. +//| +//| :param ~circuitpython_typing.ReadableBuffer map: at least ``mw * mh`` wall-type +//| bytes, row-major; 0 is empty +//| :param int mw: map width in cells +//| :param int mh: map height in cells +//| :param int posx: camera x position (fixed-point) +//| :param int posy: camera y position (fixed-point) +//| :param int lrx: x of the column-0 ray direction (fixed-point) +//| :param int lry: y of the column-0 ray direction (fixed-point) +//| :param int srx: per-column ray step x (fixed-point) +//| :param int sry: per-column ray step y (fixed-point) +//| :param int sh: screen height in pixels +//| :param int stride: pixel width of one column +//| :param int ncols: number of columns to cast +//| :param ~circuitpython_typing.ReadableBuffer wcolors: two ``uint16`` colors per +//| wall type: near face at ``[type * 2]``, side face at ``[type * 2 + 1]`` +//| :param ~circuitpython_typing.WriteableBuffer top: at least ``ncols`` ``uint16`` +//| values; receives each column's wall top row +//| :param ~circuitpython_typing.WriteableBuffer bot: at least ``ncols`` ``uint16`` +//| values; receives each column's wall bottom row +//| :param ~circuitpython_typing.WriteableBuffer col: at least ``ncols`` ``uint16`` +//| values; receives each column's wall color +//| :param ~circuitpython_typing.WriteableBuffer dist: at least ``ncols`` ``int32`` +//| values; receives each column's perpendicular distance (fixed-point) +//| :param ~circuitpython_typing.WriteableBuffer runs: optional; at least +//| ``5 * ncols`` ``uint16`` values, laid out as five ``ncols``-long planes +//| (x0s, x1s, tops, bots, colors). When given, adjacent equal columns are +//| merged into wall runs suitable for :py:meth:`Canvas.vspans` and the run +//| count is returned; otherwise `None` is returned.""" //| ... //| // C DDA wall raycaster for picogame_ray.Raycaster - INTEGER ONLY (16.16 fixed-point, no FPU; the paint, @@ -289,14 +364,25 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_raycast_obj, 17, 18, picogam //| dist: int, //| cfg: ReadableBuffer, //| ) -> None: -//| """Compute one racing-road frame's left/right edge columns (the OutRun-style -//| ``compute_road`` loop of the ``picogame_road`` helper). +//| """Compute one racing-road frame's left and right edge columns. This function is +//| intended for use by the separately distributed ``picogame_road`` helper, which +//| packs the inputs. //| //| Walks ``n`` screen rows bottom-up, accumulating the road curve, and writes the -//| left/right edge x coordinates into the ``int16`` buffers ``rl``/``rr``. -//| ``hw`` holds per-row half-widths (``int32``, 16.16), ``cx0`` is the 16.16 screen -//| centre including lateral offset, ``dist`` the integer world distance and ``cfg`` -//| seven ``int32`` curve parameters (layout documented in the shared-module core).""" +//| edge x coordinates into ``rl`` and ``rr``. +//| +//| :param ~circuitpython_typing.WriteableBuffer rl: at least ``n`` ``int16`` values; +//| receives the left edge per row +//| :param ~circuitpython_typing.WriteableBuffer rr: at least ``n`` ``int16`` values; +//| receives the right edge per row +//| :param ~circuitpython_typing.ReadableBuffer hw: at least ``n`` ``int32`` per-row +//| half-widths (signed 16.16 fixed-point) +//| :param int n: number of rows to compute +//| :param int cx0: screen center x including lateral offset (signed 16.16 fixed-point) +//| :param int dist: integer world distance +//| :param ~circuitpython_typing.ReadableBuffer cfg: seven ``int32`` curve parameters, +//| in order: ``f1_q20``, ``f2_q20``, ``amp1k_q16``, ``amp2k_q16``, ``world_step``, +//| ``curve_step``, ``d_row_off``""" //| ... //| // road_edges(rl, rr, hw, n, cx0, dist, cfg) - one racing-road frame's curve accumulator + integer @@ -333,15 +419,22 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_road_edges_obj, 7, 7, picoga //| out_sx: WriteableBuffer, //| out_sy: WriteableBuffer, //| ) -> None: -//| """Batch-project ``n`` 3D world points to screen coordinates (the shared hot path -//| of the pseudo-3D helpers - project a box's corners, then fill triangles). -//| -//| ``cam`` holds 15 camera parameters (eye x/y/z, right x/z, up x/y/z, -//| forward x/y/z, focal, screen centre x/y, near); ``pts`` holds ``n*3`` world -//| coordinates. Screen x/y land in the ``int16`` buffers ``out_sx``/``out_sy``; -//| a point behind the near plane gets the sentinel ``-32768``. On an FPU build -//| (``picogame.FPU`` is 1) ``cam``/``pts`` are ``float32``, otherwise 16.16 -//| fixed-point ``int32``.""" +//| """Batch-project ``n`` 3D world points to screen coordinates. +//| +//| When :py:data:`FPU` is ``1``, ``cam`` and ``pts`` hold ``float32`` elements; +//| otherwise they hold signed 16.16 fixed-point ``int32`` elements. +//| +//| :param ~circuitpython_typing.ReadableBuffer cam: 15 camera parameters, in order: +//| eye x/y/z, right x/z, up x/y/z, forward x/y/z, focal length, screen center +//| x/y, near-plane distance +//| :param ~circuitpython_typing.ReadableBuffer pts: ``3 * n`` world coordinates +//| (x, y, z per point) +//| :param int n: number of points +//| :param ~circuitpython_typing.WriteableBuffer out_sx: at least ``n`` ``int16`` +//| values; receives screen x, or the sentinel ``-32768`` for a point behind +//| the near plane +//| :param ~circuitpython_typing.WriteableBuffer out_sy: at least ``n`` ``int16`` +//| values; receives screen y, or ``-32768`` for a point behind the near plane""" //| ... //| // project(cam, pts, n, out_sx, out_sy) - batch perspective projection of `n` 3D points to screen. @@ -419,10 +512,15 @@ static mp_obj_t picogame_project(size_t n_args, const mp_obj_t *args) { } static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_project_obj, 5, 5, picogame_project); -//| def invert(display: busdisplay.BusDisplay, on: bool) -> None: -//| """Toggle the panel's hardware colour inversion (INVON/INVOFF). Instant and sends NO -//| pixel data, so a brief invert is a FREE full-screen flash (a 1-bit negative 'hit' look) -//| - cheaper than a Fade overlay. ST7789/ST7735 support it.""" +//| def invert( +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], on: bool +//| ) -> None: +//| """Enable or disable color inversion. +//| +//| Bus displays receive the controller's inversion command (INVON/INVOFF), which +//| takes effect immediately and sends no pixel data; the controller must support +//| it (ST7789 and ST7735 do). A `Framebuffer` target is instead inverted during +//| composition, starting with the next refresh.""" //| ... //| //| @@ -441,9 +539,9 @@ static mp_obj_t picogame_invert(mp_obj_t display_in, mp_obj_t on_in) { static MP_DEFINE_CONST_FUN_OBJ_2(picogame_invert_obj, picogame_invert); //| def render( -//| display: busdisplay.BusDisplay, -//| sprites: List[Sprite], -//| buffer: WriteableBuffer, +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], +//| layers: List[Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]], +//| buffer: Optional[WriteableBuffer], //| x0: int, //| y0: int, //| x1: int, @@ -451,8 +549,19 @@ static MP_DEFINE_CONST_FUN_OBJ_2(picogame_invert_obj, picogame_invert); //| *, //| background: int = 0, //| ) -> None: -//| """Render ``sprites`` into the screen region [x0,x1) x [y0,y1) and push it -//| to ``display``. ``buffer`` is a reusable strip buffer (>= region_width*2 bytes).""" +//| """Render ``layers`` into the screen region from ``(x0, y0)`` up to, but not +//| including, ``(x1, y1)``, and push it to ``display``, without a `Scene`. +//| +//| :param display: the render target +//| :param layers: layers of any kind, drawn bottom to top +//| :param ~circuitpython_typing.WriteableBuffer buffer: a reusable strip buffer of +//| at least ``(x1 - x0) * 2`` bytes; ignored (may be `None`) on a +//| `Framebuffer` target +//| :param int x0: left edge of the region +//| :param int y0: top edge of the region +//| :param int x1: right edge of the region (exclusive) +//| :param int y1: bottom edge of the region (exclusive) +//| :param int background: color the region is cleared to first""" //| ... //| //| @@ -575,12 +684,16 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_render_obj, 7, picogame_render_fun); //| def collide( //| x1: int, y1: int, x2: int, y2: int, ax1: int, ay1: int, ax2: int = ..., ay2: int = ... //| ) -> bool: -//| """AABB overlap test with INCLUSIVE bounds - both corners are part of the box, so two -//| boxes collide the moment they TOUCH (no visible overlap, no gap). Pass sprite hitboxes -//| as (x, y, x+w, y+h): collision fires on contact, the usual game feel. With 8 args: box -//| (x1,y1,x2,y2) vs box (ax1,ay1,ax2,ay2). With 6 args: box vs point (ax1, ay1). -//| NOTE: this is intentionally inclusive, unlike render's half-open [x0,x1) pixel ranges - -//| render is about pixels, collide is about game hitboxes (touch = hit).""" +//| """Return whether an inclusive rectangle overlaps another rectangle or contains +//| a point. Both corners are part of the rectangle, so touching edges count as an +//| overlap. +//| +//| With six arguments, test rectangle ``(x1, y1, x2, y2)`` against the point +//| ``(ax1, ay1)``. With eight arguments, test it against the rectangle +//| ``(ax1, ay1, ax2, ay2)``. Seven arguments are not accepted. +//| +//| Unlike the pixel regions used by `render`, whose upper bounds are excluded, +//| collision bounds are inclusive.""" //| ... //| //| @@ -645,7 +758,7 @@ static float pg_value1d(float x, int32_t seed) { } //| def value2d(x: float, y: float, *, seed: int = 0) -> float: -//| """Smooth 2-D value noise in 0..1 (fast C).""" +//| """Smooth 2-D value noise in ``0..1``.""" //| ... //| //| @@ -658,7 +771,9 @@ static mp_obj_t picogame_value2d(size_t n_args, const mp_obj_t *pos, mp_map_t *k } static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_value2d_obj, 2, picogame_value2d); -//| def value1d(x: float, *, seed: int = 0) -> float: ... +//| def value1d(x: float, *, seed: int = 0) -> float: +//| """Smooth 1-D value noise in ``0..1``.""" +//| ... static mp_obj_t picogame_value1d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { static const mp_arg_t spec[] = { {MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL}}, {MP_QSTR_seed, MP_ARG_INT, {.u_int = 0}} }; @@ -680,7 +795,10 @@ static const mp_arg_t pg_fbm2d_args[] = { }; #if 0 // float reference fbm - superseded by the fixed-point path below -//| def fbm2d(x: float, y: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: ... +//| def fbm2d(x: float, y: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: +//| """Fractal (fBm) 2-D noise in ``0..1``: ``octaves`` layers of :py:func:`value2d`, each +//| ``lacunarity`` times finer and ``gain`` times weaker than the last.""" +//| ... static mp_obj_t picogame_fbm2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { mp_arg_val_t a[6]; mp_arg_parse_all(n_args, pos, kw, 6, pg_fbm2d_args, a); @@ -700,7 +818,10 @@ static mp_obj_t picogame_fbm2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) } static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm2d_obj, 2, picogame_fbm2d); -//| def fbm1d(x: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: ... +//| def fbm1d(x: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: +//| """Fractal (fBm) 1-D noise in ``0..1``: the :py:func:`fbm2d` layering applied +//| to :py:func:`value1d`.""" +//| ... //| //| static mp_obj_t picogame_fbm1d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) { From dddef671d8fbf2bf4258d3aaaa06f61de42be98d Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Thu, 27 Aug 2026 05:51:35 +0000 Subject: [PATCH 866/876] picogame: tighten three API edges before the freeze Module-level render() now takes its layer list as `layers` - it accepts every layer kind, and the documentation already described it that way; `sprites` remains the keyword on Display.render(), which really is sprites-only. Nothing in the shipped ecosystem passed it by keyword. StripDraw.invalidate() with a partial rectangle now raises ValueError instead of silently repainting the whole layer: the only meaningful forms are no rectangle or all four values, and a partial one is a bug in the caller. Scene's strip buffers become optional, defaulting to None: a Framebuffer-target scene never uses them, and requiring two explicit None arguments was a wart every framebuffer board would carry forever. Buffer-using targets still validate them at construction. Their documentation now also states that the buffer size selects the strip height rather than merely satisfying a minimum. --- shared-bindings/picogame/Scene.c | 18 ++++++++++-------- shared-bindings/picogame/StripDraw.c | 8 ++++++-- shared-bindings/picogame/__init__.c | 23 ++++++++++------------- 3 files changed, 26 insertions(+), 23 deletions(-) diff --git a/shared-bindings/picogame/Scene.c b/shared-bindings/picogame/Scene.c index 1f7e7c0d455..ed914d5b99d 100644 --- a/shared-bindings/picogame/Scene.c +++ b/shared-bindings/picogame/Scene.c @@ -71,8 +71,8 @@ static mp_obj_t scene_resolve_target(mp_obj_t disp, bool *fast, bool *fb_target) //| def __init__( //| self, //| display: Union[Display, busdisplay.BusDisplay, Framebuffer], -//| buffer_a: Optional[WriteableBuffer], -//| buffer_b: Optional[WriteableBuffer], +//| buffer_a: Optional[WriteableBuffer] = None, +//| buffer_b: Optional[WriteableBuffer] = None, //| *, //| background: int = 0, //| top: int = 0, @@ -81,10 +81,12 @@ static mp_obj_t scene_resolve_target(mp_obj_t disp, bool *fast, bool *fb_target) //| right: int = 0, //| ) -> None: //| """:param display: the render target -//| :param ~circuitpython_typing.WriteableBuffer buffer_a: a strip buffer of at -//| least ``display.width * STRIP_H * 2`` bytes. Two buffers let the next -//| strip be composited while the previous one is being sent. On a -//| `Framebuffer` target there are no strips and both may be `None`. +//| :param ~circuitpython_typing.WriteableBuffer buffer_a: a strip buffer, +//| typically ``display.width * STRIP_H * 2`` bytes. Its size sets the +//| strip height: each strip is ``size // (display.width * 2)`` rows. Two +//| buffers let the next strip be composited while the previous one is +//| being sent. On a `Framebuffer` target there are no strips and the +//| buffers are unused; both default to `None`. //| :param ~circuitpython_typing.WriteableBuffer buffer_b: the second strip //| buffer, sized like ``buffer_a`` //| :param int background: color that exposed areas are cleared to @@ -103,8 +105,8 @@ static mp_obj_t picogame_scene_make_new(const mp_obj_type_t *type, size_t n_args ARG_top, ARG_bottom, ARG_left, ARG_right }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_buffer_a, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_buffer_b, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_buffer_a, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, + { MP_QSTR_buffer_b, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} }, { MP_QSTR_background, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, { MP_QSTR_top, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // reserved border insets: { MP_QSTR_bottom, MP_ARG_INT | MP_ARG_KW_ONLY, {.u_int = 0} }, // the scene renders only the diff --git a/shared-bindings/picogame/StripDraw.c b/shared-bindings/picogame/StripDraw.c index 02436a928ca..7b0898ae592 100644 --- a/shared-bindings/picogame/StripDraw.c +++ b/shared-bindings/picogame/StripDraw.c @@ -183,13 +183,17 @@ MP_PROPERTY_GETSET(sd_always_dirty_obj, (mp_obj_t)&sd_get_always_dirty_obj, (mp_ //| //| With no arguments the whole layer repaints. To repaint one region, pass //| all four values as a rectangle in the view-local coordinates the draw -//| callback uses; an incomplete rectangle repaints the whole layer. Repeated -//| calls accumulate, and the rectangle is clamped to the layer.""" +//| callback uses; passing only some of them raises :py:class:`ValueError`. +//| Repeated calls accumulate, and the rectangle is clamped to the layer.""" //| ... //| //| static mp_obj_t sd_invalidate(size_t n_args, const mp_obj_t *args) { picogame_stripdraw_obj_t *self = MP_OBJ_TO_PTR(args[0]); + if (n_args != 1 && n_args != 5) { + // A partial rectangle is a bug, not a request for "everything". + mp_arg_error_invalid(MP_QSTR_rect); + } if (n_args >= 5) { // (x, y, w, h) in view-local coords -> clamped scene rect int x1 = self->x + mp_obj_get_int(args[1]); int y1 = self->y + mp_obj_get_int(args[2]); diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c index 739d781cf52..327c6494610 100644 --- a/shared-bindings/picogame/__init__.c +++ b/shared-bindings/picogame/__init__.c @@ -60,13 +60,8 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { //| //| A scene targets a :py:class:`~busdisplay.BusDisplay`, an accelerated //| :py:class:`Display` or a RAM :py:class:`Framebuffer`. picogame drives the -//| display itself: set ``display.auto_refresh = False``, and do not use -//| displayio groups on the same display at the same time. -//| -//| Unless stated otherwise, color integers are display transfer-order RGB565 -//| values as returned by :py:func:`rgb565`. Render rectangles include -//| ``(x0, y0)`` and exclude ``(x1, y1)``; collision rectangles use inclusive -//| edges as documented by :py:func:`collide`. +//| display itself, so it requires ``display.auto_refresh = False`` and cannot +//| show displayio groups on the same display at the same time. //| //| .. note:: //| This module is the engine's rendering and compute core and is fully @@ -115,8 +110,9 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { //| """8-bit paletted bitmap format.""" //| //| STRIP_H: int -//| """Default render-strip height in rows for this build. A `Scene` strip -//| buffer is ``display.width * STRIP_H * 2`` bytes.""" +//| """Recommended render-strip height in rows for this build. Sizing a `Scene` +//| strip buffer as ``display.width * STRIP_H * 2`` bytes yields strips this +//| tall.""" //| //| FPU: int //| """``1`` when `project` uses hardware floating point (its buffers are @@ -137,7 +133,8 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { //| //| //| def rgb565(r: int, g: int, b: int) -> int: -//| """Build a display wire-order RGB565 color from 8-bit components.""" +//| """Build an RGB565 color in the display's transfer byte order from 8-bit +//| components. Every color integer in this module is such a value.""" //| ... //| //| @@ -591,10 +588,10 @@ uint8_t picogame_kind_of(mp_obj_t o) { } static mp_obj_t picogame_render_fun(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - enum { ARG_display, ARG_sprites, ARG_buffer, ARG_x0, ARG_y0, ARG_x1, ARG_y1, ARG_background }; + enum { ARG_display, ARG_layers, ARG_buffer, ARG_x0, ARG_y0, ARG_x1, ARG_y1, ARG_background }; static const mp_arg_t allowed_args[] = { { MP_QSTR_display, MP_ARG_REQUIRED | MP_ARG_OBJ }, - { MP_QSTR_sprites, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_layers, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ }, { MP_QSTR_x0, MP_ARG_REQUIRED | MP_ARG_INT }, { MP_QSTR_y0, MP_ARG_REQUIRED | MP_ARG_INT }, @@ -620,7 +617,7 @@ static mp_obj_t picogame_render_fun(size_t n_args, const mp_obj_t *pos_args, mp_ size_t n = 0; mp_obj_t *items; - mp_obj_get_array(args[ARG_sprites].u_obj, &n, &items); + mp_obj_get_array(args[ARG_layers].u_obj, &n, &items); // Classify items into layer kinds. All-Sprite lists stay on the NULL-kinds fast path (no alloc - // the common case). Any non-Sprite layer (StripDraw/Canvas/Tilemap/Particles) builds a small kinds From 93ba81580beb74190a8491d3e8432212b704a1e9 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Thu, 27 Aug 2026 10:14:58 +0000 Subject: [PATCH 867/876] picogame: editorial pass on the API docs From two independent editorial reviews of the rendered page: - the low-level compute functions (project, raycast, road_edges) move after the everyday API in the page order instead of greeting the reader right below the module intro - doubled words removed ("frame frame"), the last "wire byte order" unified to transfer byte order, "arbitrary size" phrasing fixed, transpose no longer described as rotation - Bitmap.stride documents its 0-means-default sentinel; project explains why the right vector has no y component; fbm1d is described on its own terms - the ASCII limitation moves to Canvas.text itself; StripDraw's stale-area note moves to the class docstring where all four rectangle attributes are in scope; always_dirty is described inline instead of a circular reference - per-function helper mentions shortened now that the module note covers distribution --- shared-bindings/picogame/Bitmap.c | 17 +- shared-bindings/picogame/Canvas.c | 24 +- shared-bindings/picogame/Particles.c | 6 +- shared-bindings/picogame/Scene.c | 7 +- shared-bindings/picogame/Sprite.c | 23 +- shared-bindings/picogame/StripDraw.c | 19 +- shared-bindings/picogame/Tilemap.c | 15 +- shared-bindings/picogame/Triangles.c | 4 +- shared-bindings/picogame/__init__.c | 841 ++++++++++++++------------- 9 files changed, 486 insertions(+), 470 deletions(-) diff --git a/shared-bindings/picogame/Bitmap.c b/shared-bindings/picogame/Bitmap.c index 114e5e136de..8c970a5a0c0 100644 --- a/shared-bindings/picogame/Bitmap.c +++ b/shared-bindings/picogame/Bitmap.c @@ -30,9 +30,10 @@ // --------------------------------------------------------------------------- //| class Bitmap: -//| """An image atlas of one or more equal-size frames, of arbitrary size. -//| Pixel data and palette entries must be in the display's transfer byte -//| order; use :py:func:`rgb565` to build colors. +//| """An image atlas of one or more frames that all share one size. RGB565 +//| pixel data and palette entries must be in the display's transfer byte +//| order (use :py:func:`rgb565` to build colors); PAL8 pixel data are +//| palette indices. //| //| The bitmap references the caller-provided data without copying or modifying //| it. The backing buffer may live in RAM or in read-only memory.""" @@ -49,8 +50,8 @@ //| stride: int = 0, //| transparent: Optional[int] = None, //| ) -> None: -//| """:param ~circuitpython_typing.ReadableBuffer data: pixel data in the -//| display's transfer byte order +//| """:param ~circuitpython_typing.ReadableBuffer data: RGB565 pixel data in +//| the display's transfer byte order, or palette indices for ``PAL8`` //| :param int width: width of one frame in pixels //| :param int height: height of one frame in pixels //| :param int format: :py:data:`RGB565` (2 bytes per pixel) or :py:data:`PAL8` @@ -61,9 +62,9 @@ //| ``len(palette) // 2``. //| :param int frames: number of equal-size frames, laid out left to right in //| one horizontal atlas -//| :param int stride: distance between two rows in pixels. Defaults to -//| ``width * frames``; set explicitly to reference a sub-region of a -//| wider image. +//| :param int stride: distance between two rows in pixels. ``0``, the +//| default, means ``width * frames``; set it explicitly to reference a +//| sub-region of a wider image. //| :param int transparent: color (``RGB565``) or index (``PAL8``) that is //| skipped when drawing. Defaults to `None`, fully opaque.""" //| ... diff --git a/shared-bindings/picogame/Canvas.c b/shared-bindings/picogame/Canvas.c index b432bf26bf5..675826936ff 100644 --- a/shared-bindings/picogame/Canvas.c +++ b/shared-bindings/picogame/Canvas.c @@ -12,8 +12,8 @@ #include "shared-module/picogame/Canvas.h" //| class Canvas: -//| """A RAM drawing surface of any size, composited as a `Scene` layer. Draw -//| primitives into it; only redrawn areas repaint. Colors come from +//| """A RAM drawing surface composited as a `Scene` layer. Draw primitives +//| into it; only redrawn areas repaint. Colors come from //| :py:func:`rgb565`.""" //| //| def __init__( @@ -146,8 +146,8 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_fill_rect_obj, 6, 6, canvas_fi //| flip_x: bool = False, //| flip_y: bool = False, //| ) -> None: -//| """Stamp frame ``frame`` of ``bitmap`` into the canvas at ``(x, y)``, -//| honoring the bitmap's transparent color.""" +//| """Copy one frame of ``bitmap``, selected by ``frame``, into the canvas +//| at ``(x, y)``, honoring the bitmap's transparent color.""" //| ... //| static mp_obj_t canvas_blit(size_t n, const mp_obj_t *a) { @@ -177,8 +177,7 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_blit_obj, 4, 7, canvas_blit); //| cam_y: int, //| ) -> None: //| """Fill rows below ``horizon`` with a perspective projection of ``texture``. -//| For a higher-level interface see the separately distributed -//| ``picogame_mode7`` helper, which computes the camera terms from an angle, +//| The ``picogame_mode7`` helper computes the camera terms from an angle, //| position and field of view. //| //| :param Bitmap texture: texture whose width and height are powers of two @@ -330,9 +329,8 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_vspans_obj, 7, 9, canvas_vspan //| d07_q8: int, //| colors: ReadableBuffer, //| ) -> None: -//| """Draw one racing-road strip from precomputed tables. This method is -//| intended for use by the separately distributed ``picogame_road`` helper, -//| which builds the tables. +//| """Draw one racing-road strip from precomputed tables. A low-level +//| interface used by the ``picogame_road`` helper, which builds the tables. //| //| :param int ri0: road-table row of this surface's row 0; negative values //| are sky rows @@ -511,10 +509,10 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canvas_frame3d_obj, 7, 7, canvas_fram //| self, x: int, y: int, s: str, fg: int, font: fontio.BuiltinFont, bg: int | None = None //| ) -> None: //| """Draw ``s`` into the surface, rasterizing each glyph from ``font`` as it -//| is drawn; no memory is retained between calls. If ``bg`` is given the glyph -//| background is filled with it, otherwise it is transparent. Inside a -//| `StripDraw` callback the view is a Canvas, so ``view.text(...)`` draws -//| text directly into the frame.""" +//| is drawn; no memory is retained between calls. Only ASCII characters are +//| supported. If ``bg`` is given the glyph background is filled with it, +//| otherwise it is transparent. Inside a `StripDraw` callback the view is a +//| Canvas, so ``view.text(...)`` draws text directly into the frame.""" //| ... //| static mp_obj_t canvas_text(size_t n, const mp_obj_t *a) { diff --git a/shared-bindings/picogame/Particles.c b/shared-bindings/picogame/Particles.c index d9602b307ba..bc7f286b46a 100644 --- a/shared-bindings/picogame/Particles.c +++ b/shared-bindings/picogame/Particles.c @@ -26,8 +26,8 @@ static void reset_dirty(picogame_particles_obj_t *self) { //| self, capacity: int, *, size: int = 1, gravity: float = 0.0, fade: bool = False //| ) -> None: //| """``capacity`` is how many particles may be alive at once; the pool is -//| allocated once here and never grows, so an ``emit()`` beyond it simply drops the -//| extra particles. +//| allocated once here and never grows. If :py:meth:`emit` would exceed it, +//| the excess particles are dropped. //| //| ``size`` is the square side of one particle in pixels. ``gravity`` is added to //| each particle's vertical speed every :py:meth:`tick`. ``fade=True`` dims @@ -81,7 +81,7 @@ static mp_obj_t picogame_particles_make_new(const mp_obj_type_t *type, size_t n_ //| self, x: int, y: int, count: int, speed: int = 1, life: int = 30, color: int = 0xFFFF //| ) -> None: //| """Spawn ``count`` particles at ``(x, y)``, living ``life`` ticks, in -//| ``color``. Each particle's horizontal and vertical velocity is chosen +//| ``color`` (default white). Each particle's horizontal and vertical velocity is chosen //| independently from ``-speed`` through ``speed`` pixels per tick.""" //| ... //| diff --git a/shared-bindings/picogame/Scene.c b/shared-bindings/picogame/Scene.c index ed914d5b99d..ea016047331 100644 --- a/shared-bindings/picogame/Scene.c +++ b/shared-bindings/picogame/Scene.c @@ -96,7 +96,8 @@ static mp_obj_t scene_resolve_target(mp_obj_t disp, bool *fast, bool *fb_target) //| :param int right: columns at the right edge the scene never renders into //| //| The four border insets reserve screen edges for content the application -//| draws itself; the scene renders only the inner rectangle.""" +//| draws itself, for example with :py:func:`render`; the scene renders only +//| the inner rectangle and never repaints the border.""" //| ... //| static mp_obj_t picogame_scene_make_new(const mp_obj_type_t *type, size_t n_args, @@ -463,8 +464,8 @@ static mp_obj_t scene_refresh_fb(picogame_scene_obj_t *self) { #endif // CIRCUITPY_PICOGAME_FRAMEBUFFER //| def refresh(self) -> Optional[list]: -//| """Repaint the regions reported changed by the scene's layers since the -//| previous refresh. Returns the bounding dirty rectangle as a list +//| """Repaint the regions changed by the scene's layers since the previous +//| refresh. Returns the bounding dirty rectangle as a list //| ``[x1, y1, x2, y2]`` with exclusive ``x2``/``y2``, or `None` if nothing //| changed. The returned list object is reused: read it before the next //| ``refresh()`` call.""" diff --git a/shared-bindings/picogame/Sprite.c b/shared-bindings/picogame/Sprite.c index fb3f93dc0bb..37f13775681 100644 --- a/shared-bindings/picogame/Sprite.c +++ b/shared-bindings/picogame/Sprite.c @@ -50,8 +50,9 @@ static int32_t pg_int_to_fp8(mp_int_t v) { //| flip_x: bool = False, //| flip_y: bool = False, //| ) -> None: -//| """Place frame ``frame`` of ``bitmap`` at (``x``, ``y``) - the top-left corner, in -//| world pixels, so a sprite on a scrolling layer moves with the view. +//| """Place ``bitmap`` with its top-left corner at ``(x, y)`` in scene +//| coordinates, showing the frame selected by ``frame``. Scene coordinates +//| follow the view offset, so the sprite moves with a scrolling world. //| //| ``visible=False`` creates the sprite without drawing it, for example to //| pre-allocate a pool of sprites up front. ``flip_x`` and ``flip_y`` mirror @@ -312,7 +313,9 @@ MP_PROPERTY_GETSET(sprite_shadow_obj, (mp_obj_t)&sprite_get_shadow_obj, (mp_obj_ //| flash: int //| """Draw opaque pixels as one solid color instead of their own, for example as //| a brief hit flash. Set to a color from :py:func:`rgb565` to enable, ``0`` to -//| disable. Mutually exclusive with `shadow`, `dither` and `tint`.""" +//| disable. Because ``0`` disables the effect, pure black cannot be the flash +//| color; use a near-black color instead. Mutually exclusive with `shadow`, +//| `dither` and `tint`.""" static mp_obj_t sprite_get_flash(mp_obj_t self_in) { picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_FLASH) ? s->flash_color : 0); @@ -360,8 +363,9 @@ MP_PROPERTY_GETSET(sprite_dither_obj, (mp_obj_t)&sprite_get_dither_obj, (mp_obj_ //| tint: int //| """Multiply opaque pixels by a color from :py:func:`rgb565`, preserving the -//| sprite's shading (unlike `flash`, which replaces it). ``0`` disables. Mutually -//| exclusive with `shadow`, `flash` and `dither`.""" +//| sprite's shading (unlike `flash`, which replaces it). ``0`` disables, so pure +//| black cannot be the tint color. Mutually exclusive with `shadow`, `flash` +//| and `dither`.""" static mp_obj_t sprite_get_tint(mp_obj_t self_in) { picogame_sprite_obj_t *s = MP_OBJ_TO_PTR(self_in); return MP_OBJ_NEW_SMALL_INT((s->flags & PICOGAME_SPR_TINT) ? s->flash_color : 0); @@ -381,11 +385,10 @@ static MP_DEFINE_CONST_FUN_OBJ_2(sprite_set_tint_obj, sprite_set_tint); MP_PROPERTY_GETSET(sprite_tint_obj, (mp_obj_t)&sprite_get_tint_obj, (mp_obj_t)&sprite_set_tint_obj); //| transpose: bool -//| """Swap the sprite's x and y axes, turning the frame by 90 degrees without -//| resampling. Combined with `flip_x` and `flip_y` this yields all 8 -//| orientations. Applies only at ``scale == 1.0`` and ``angle == 0``; for -//| rotation combined with scaling use `angle`. The drawn footprint swaps -//| width and height.""" +//| """Transpose the frame by swapping its x and y axes. Combined with `flip_x` +//| and `flip_y` this yields all 8 orthogonal orientations. Applies only at +//| ``scale == 1.0`` and ``angle == 0``; for rotation combined with scaling use +//| `angle`. The drawn footprint swaps width and height.""" static mp_obj_t sprite_get_transpose(mp_obj_t self_in) { return mp_obj_new_bool((((picogame_sprite_obj_t *)MP_OBJ_TO_PTR(self_in))->flags & PICOGAME_SPR_TRANSPOSE) != 0); } diff --git a/shared-bindings/picogame/StripDraw.c b/shared-bindings/picogame/StripDraw.c index 7b0898ae592..45bfc591e35 100644 --- a/shared-bindings/picogame/StripDraw.c +++ b/shared-bindings/picogame/StripDraw.c @@ -40,10 +40,13 @@ //| ``(vx, vy)`` is the view origin in screen coordinates and ``(vw, vh)`` is //| its size: to draw a screen point ``(sx, sy)``, draw at ``(sx - vx, sy - vy)`` //| in ``view``. The view may span the full render-region width even when the -//| layer is narrower (the layer's rectangle only selects which rows run), so -//| fill your own rectangle with :py:meth:`Canvas.fill_rect` rather than -//| ``view.clear()``, which fills the whole width. Text drawn with -//| :py:meth:`Canvas.text` supports ASCII only.""" +//| layer is narrower (the layer's rectangle only limits which rows are drawn), +//| so fill your own rectangle with :py:meth:`Canvas.fill_rect` rather than +//| ``view.clear()``, which fills the whole width. +//| +//| Moving or resizing the layer by assigning :py:attr:`x`, :py:attr:`y`, +//| :py:attr:`width` or :py:attr:`height` can leave the old area stale; call +//| :py:meth:`Scene.invalidate` afterwards for a clean repaint.""" //| //| def __init__( //| self, @@ -61,7 +64,8 @@ //| :param int y: top edge of the layer's screen rectangle //| :param int width: rectangle width in pixels //| :param int height: rectangle height in pixels -//| :param bool always_dirty: see :py:attr:`always_dirty`""" +//| :param bool always_dirty: when `True` the layer redraws every refresh; +//| when `False`, call :py:meth:`invalidate` after its content changes""" //| ... //| static mp_obj_t picogame_stripdraw_make_new(const mp_obj_type_t *type, size_t n_args, @@ -112,10 +116,7 @@ static mp_obj_t picogame_stripdraw_make_new(const mp_obj_type_t *type, size_t n_ //| width: int //| """Width of the layer's screen rectangle in pixels.""" //| height: int -//| """Height of the layer's screen rectangle in pixels. -//| -//| Moving or resizing the rectangle by assigning any of these can leave the old -//| area stale; call :py:meth:`Scene.invalidate` afterwards for a clean repaint.""" +//| """Height of the layer's screen rectangle in pixels.""" static mp_obj_t sd_get_x(mp_obj_t self_in) { return MP_OBJ_NEW_SMALL_INT(((picogame_stripdraw_obj_t *)MP_OBJ_TO_PTR(self_in))->x); } diff --git a/shared-bindings/picogame/Tilemap.c b/shared-bindings/picogame/Tilemap.c index 27b8dfadbc5..955deef1b96 100644 --- a/shared-bindings/picogame/Tilemap.c +++ b/shared-bindings/picogame/Tilemap.c @@ -11,13 +11,14 @@ #include "shared-module/picogame/Tilemap.h" //| class Tilemap: -//| """A grid of tile indices into a tileset Bitmap (each frame = one tile). -//| Add it to a Scene as a background layer; setting tiles or moving the map -//| marks only the affected area dirty.""" +//| """A grid of tile indices into a tileset `Bitmap`, where each bitmap frame +//| is one tile. Add it to a `Scene` as a background layer; setting tiles or +//| moving the map marks only the affected area dirty.""" //| //| def __init__(self, tileset: Bitmap, cols: int, rows: int) -> None: -//| """A map ``cols`` tiles wide by ``rows`` tiles tall (each cell indexes a -//| frame of ``tileset``).""" +//| """:param Bitmap tileset: the tile images, one frame per tile +//| :param int cols: map width in tiles +//| :param int rows: map height in tiles""" //| ... //| static mp_obj_t picogame_tilemap_make_new(const mp_obj_type_t *type, size_t n_args, @@ -85,8 +86,8 @@ static MP_DEFINE_CONST_FUN_OBJ_3(picogame_tilemap_get_tile_obj, picogame_tilemap //| """Set the tile at ``(tx, ty)`` and mark it dirty. The keyword flags orient //| the tile at draw time; together they yield all 8 orientations (4 rotations //| times mirror), so one stored tile can serve as several. The flags can -//| represent the remap table emitted by the separately distributed -//| ``png2picogame.py --dedup`` tool. Out-of-range writes are ignored.""" +//| represent the remap table emitted by the ``png2picogame.py --dedup`` +//| tool. Out-of-range writes are ignored.""" //| ... //| static mp_obj_t picogame_tilemap_set_tile(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { diff --git a/shared-bindings/picogame/Triangles.c b/shared-bindings/picogame/Triangles.c index bbb1f5e6fcb..4401a1b9c66 100644 --- a/shared-bindings/picogame/Triangles.c +++ b/shared-bindings/picogame/Triangles.c @@ -32,8 +32,8 @@ //| pixel buffer is held. Triangles layers always draw in screen coordinates and //| ignore the scene's view offset. //| -//| A typical frame projects points with :py:func:`project`, fills the arrays in -//| place back to front, sets :py:attr:`count` and calls +//| For each frame: project points with :py:func:`project`, write triangles +//| into the buffers in back-to-front order, set :py:attr:`count`, then call //| :py:meth:`Scene.refresh`.""" //| //| def __init__(self, verts: ReadableBuffer, colors: ReadableBuffer) -> None: diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c index 327c6494610..d8ec1df17bc 100644 --- a/shared-bindings/picogame/__init__.c +++ b/shared-bindings/picogame/__init__.c @@ -50,7 +50,7 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { return MP_OBJ_TO_PTR(native); } -//| """Game rendering +//| """Rendering core for games //| //| The `picogame` module composites sprites, tilemaps, drawing canvases, //| particle layers, 3D triangle batches and immediate-mode callbacks into a @@ -63,10 +63,13 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { //| display itself, so it requires ``display.auto_refresh = False`` and cannot //| show displayio groups on the same display at the same time. //| +//| Most programs start with :py:class:`Scene`, :py:class:`Sprite` and +//| :py:class:`Bitmap`. +//| //| .. note:: //| This module is the engine's rendering and compute core and is fully -//| usable on its own. The separately distributed pure-Python `picogame -//| helper libraries `_ +//| usable on its own. The pure-Python `picogame helper libraries +//| `_ //| (``picogame_game``, ``picogame_ray`` and others) build a complete game //| framework on top of it: display, input and audio setup that adapts to //| the board, game-loop timing, sprite pools and collision helpers, @@ -92,8 +95,8 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { //| scene = picogame.Scene(display, bytearray(size), bytearray(size)) //| //| # One solid white 8x8 frame. -//| data = array.array("H", [0xFFFF] * 64) -//| bitmap = picogame.Bitmap(data, 8, 8) +//| white = picogame.rgb565(255, 255, 255) +//| bitmap = picogame.Bitmap(array.array("H", [white] * 64), 8, 8) //| player = scene.add(picogame.Sprite(bitmap, x=0, y=display.height // 2)) //| //| while True: @@ -105,7 +108,7 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { //| that changed each frame.""" //| //| RGB565: int -//| """16-bit color bitmap format (wire byte order).""" +//| """16-bit color bitmap format (transfer byte order).""" //| PAL8: int //| """8-bit paletted bitmap format.""" //| @@ -119,8 +122,8 @@ static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { //| ``float32``), ``0`` when it uses signed 16.16 fixed-point ``int32``.""" //| //| API_LEVEL: int -//| """Version of the picogame API. Separately distributed helpers compare it -//| against the version they were written for.""" +//| """Version of the picogame API. Helper libraries compare this value against +//| the API level they target.""" //| //| RGB444_SUPPORTED: bool //| """Whether `Display` supports ``rgb444=True`` on this board.""" @@ -148,418 +151,57 @@ static mp_obj_t picogame_rgb565(mp_obj_t r_in, mp_obj_t g_in, mp_obj_t b_in) { } static MP_DEFINE_CONST_FUN_OBJ_3(picogame_rgb565_obj, picogame_rgb565); -//| def raycast( -//| map: ReadableBuffer, -//| mw: int, -//| mh: int, -//| posx: int, -//| posy: int, -//| lrx: int, -//| lry: int, -//| srx: int, -//| sry: int, -//| sh: int, -//| stride: int, -//| ncols: int, -//| wcolors: ReadableBuffer, -//| top: WriteableBuffer, -//| bot: WriteableBuffer, -//| col: WriteableBuffer, -//| dist: WriteableBuffer, -//| runs: Optional[WriteableBuffer] = None, -//| ) -> Optional[int]: -//| """Cast one frame of DDA wall rays. This function is intended for use by the -//| separately distributed ``picogame_ray`` helper, which computes the inputs. -//| -//| All fixed-point arguments are signed 16.16 integers. +//| def invert( +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], on: bool +//| ) -> None: +//| """Enable or disable color inversion. //| -//| :param ~circuitpython_typing.ReadableBuffer map: at least ``mw * mh`` wall-type -//| bytes, row-major; 0 is empty -//| :param int mw: map width in cells -//| :param int mh: map height in cells -//| :param int posx: camera x position (fixed-point) -//| :param int posy: camera y position (fixed-point) -//| :param int lrx: x of the column-0 ray direction (fixed-point) -//| :param int lry: y of the column-0 ray direction (fixed-point) -//| :param int srx: per-column ray step x (fixed-point) -//| :param int sry: per-column ray step y (fixed-point) -//| :param int sh: screen height in pixels -//| :param int stride: pixel width of one column -//| :param int ncols: number of columns to cast -//| :param ~circuitpython_typing.ReadableBuffer wcolors: two ``uint16`` colors per -//| wall type: near face at ``[type * 2]``, side face at ``[type * 2 + 1]`` -//| :param ~circuitpython_typing.WriteableBuffer top: at least ``ncols`` ``uint16`` -//| values; receives each column's wall top row -//| :param ~circuitpython_typing.WriteableBuffer bot: at least ``ncols`` ``uint16`` -//| values; receives each column's wall bottom row -//| :param ~circuitpython_typing.WriteableBuffer col: at least ``ncols`` ``uint16`` -//| values; receives each column's wall color -//| :param ~circuitpython_typing.WriteableBuffer dist: at least ``ncols`` ``int32`` -//| values; receives each column's perpendicular distance (fixed-point) -//| :param ~circuitpython_typing.WriteableBuffer runs: optional; at least -//| ``5 * ncols`` ``uint16`` values, laid out as five ``ncols``-long planes -//| (x0s, x1s, tops, bots, colors). When given, adjacent equal columns are -//| merged into wall runs suitable for :py:meth:`Canvas.vspans` and the run -//| count is returned; otherwise `None` is returned.""" +//| Bus displays receive the controller's inversion command (INVON/INVOFF), which +//| takes effect immediately and sends no pixel data; the controller must support +//| it (ST7789 and ST7735 do). A `Framebuffer` target is instead inverted during +//| composition, starting with the next refresh.""" //| ... //| -// C DDA wall raycaster for picogame_ray.Raycaster - INTEGER ONLY (16.16 fixed-point, no FPU; the paint, -// temporal invalidate, pose-cache and billboard math stay in Python; Python does the once-per-frame -// trig and passes Q16 ray params). map: read-only bytes, mw*mh wall types (0 = empty). pos*, l*x/l*y -// (leftRay, column 0), s*x/s*y (rayStep per column) are all 16.16. wcolors: uint16[(maxtype+1)*2] - -// [t*2] near, [t*2+1] side colour. top/bot/col: uint16 write buffers (len>=ncols); dist: int32 write -// buffer (perpendicular distance, 16.16). The int64 divides/muls are ONLY the per-column setup -// (O(ncols)); the DDA step loop is pure 32-bit. Mirrors the Python float fallback closely. -// Optional arg 17 (runs - ONE uint16 write buffer, len>=5*ncols, laid out as five ncols-long -// planes [x0s | x1s | tops | bots | colors]): also emit the RLE-MERGED wall runs (adjacent equal -// columns fused; x in PIXELS = column*stride) and return the run count. The planes feed -// Canvas.vspans directly as memoryview slices. This hoists picogame_ray's per-frame Python merge -// loop into the same C pass (measured 2-6.5 ms/frame of interpreted merge at stride=1 on RP2040). -// Callers clamp the LAST run's x1 to the screen width (stride rounding can overshoot by = 18) { // run outputs requested - mp_buffer_info_t q; - mp_get_buffer_raise(args[17], &q, MP_BUFFER_WRITE); - int cap = (int)(q.len / 10); // five uint16 planes - if (ncols > cap) { - ncols = cap; // never write past the run planes - } - r0 = q.buf; - r1 = r0 + cap; - rt = r1 + cap; - rb = rt + cap; - rcol = rb + cap; - } - const uint8_t *map = mi.buf; - const uint16_t *wc = wi.buf; - int wc_types = (int)(wi.len >> 2); - uint16_t *top = ti.buf; - uint16_t *bot = bi.buf; - uint16_t *col = ci.buf; - int32_t *dist_out = di.buf; // perpendicular distance, 16.16 - int half = sh >> 1; - int imapx0 = posx >> 16; - int imapy0 = posy >> 16; - int32_t fracx = posx & 0xFFFF; // fractional part of pos, 16.16 - int32_t fracy = posy & 0xFFFF; - const int32_t DD_CAP = (int32_t)1 << 24; // cap deltaDist so a 64-step accumulation stays in int32 - if (ncols > (int)(ti.len >> 1)) { - ncols = (int)(ti.len >> 1); - } - for (int c = 0; c < ncols; c++) { - int mapx = imapx0; - int mapy = imapy0; - int32_t ax = rdx < 0 ? -rdx : rdx; - int32_t ay = rdy < 0 ? -rdy : rdy; - // deltaDist = |1/rayDir| in 16.16 = (1<<32)/|rayDir_q16| (int64; per-column setup, not per-step) - int64_t ddx64 = ax ? (((int64_t)1 << 32) / ax) : (int64_t)DD_CAP; - int64_t ddy64 = ay ? (((int64_t)1 << 32) / ay) : (int64_t)DD_CAP; - int32_t ddx = ddx64 > DD_CAP ? DD_CAP : (int32_t)ddx64; - int32_t ddy = ddy64 > DD_CAP ? DD_CAP : (int32_t)ddy64; - int stepx, stepy; - int32_t sidex, sidey; - // sideDist to the first grid line = (fractional distance) * deltaDist, 16.16 (int64 mul, setup only) - if (rdx < 0) { - stepx = -1; - sidex = (int32_t)(((int64_t)fracx * ddx) >> 16); - } else { - stepx = 1; - sidex = (int32_t)(((int64_t)(65536 - fracx) * ddx) >> 16); - } - if (rdy < 0) { - stepy = -1; - sidey = (int32_t)(((int64_t)fracy * ddy) >> 16); - } else { - stepy = 1; - sidey = (int32_t)(((int64_t)(65536 - fracy) * ddy) >> 16); - } - int side = 0; - int cell = 1; - for (int i = 0; i < 64; i++) { // DDA - pure 32-bit - if (sidex < sidey) { - sidex += ddx; - mapx += stepx; - side = 0; - } else { - sidey += ddy; - mapy += stepy; - side = 1; - } - cell = (mapx >= 0 && mapx < mw && mapy >= 0 && mapy < mh) ? map[mapy * mw + mapx] : 1; - if (cell) { - break; - } - } - int32_t perp = (side == 0) ? (sidex - ddx) : (sidey - ddy); // perpWallDist, 16.16 - if (perp < 655) { - perp = 655; // ~0.01 in 16.16 - } - int lh = (int)(((int32_t)sh << 16) / perp); // sh / perpWallDist (px); 32-bit (sh<<16 <= ~15.7M) - int t = half - (lh >> 1); - int b = t + lh; - if (t < 0) { - t = 0; - } - if (b > sh) { - b = sh; - } - top[c] = (uint16_t)t; - bot[c] = (uint16_t)b; - int ct = (cell < wc_types) ? cell : 1; // unknown type -> type 1 (matches Python default) - col[c] = wc[ct * 2 + side]; - dist_out[c] = perp; - rdx += srx; // accumulate ray direction for the next column (no overflow) - rdy += sry; - } - if (r0 && ncols > 0) { - // post-pass RLE over the just-written (cache-hot) column arrays: one flush point - int nr = 0; - int rstart = 0; - for (int c = 1; c <= ncols; c++) { - if (c == ncols || top[c] != top[rstart] || bot[c] != bot[rstart] || col[c] != col[rstart]) { - r0[nr] = (uint16_t)(rstart * stride); - r1[nr] = (uint16_t)(c * stride); - rt[nr] = top[rstart]; - rb[nr] = bot[rstart]; - rcol[nr] = col[rstart]; - nr++; - rstart = c; - } - } - return MP_OBJ_NEW_SMALL_INT(nr); +//| +static mp_obj_t picogame_invert(mp_obj_t display_in, mp_obj_t on_in) { + #if CIRCUITPY_PICOGAME_FRAMEBUFFER + // A Framebuffer target (RP2350 DVI, the WASM playground) has no hardware INVON/INVOFF - + // emulate the flash by XORing the composite (mirrors the Scene/render Framebuffer handling). + if (mp_obj_is_type(display_in, &picogame_framebuffer_type)) { + picogame_fb_set_invert(mp_obj_is_true(on_in)); + return mp_const_none; } + #endif + picogame_set_invert(pg_get_display(display_in), mp_obj_is_true(on_in)); return mp_const_none; } -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_raycast_obj, 17, 18, picogame_raycast); +static MP_DEFINE_CONST_FUN_OBJ_2(picogame_invert_obj, picogame_invert); -//| def road_edges( -//| rl: WriteableBuffer, -//| rr: WriteableBuffer, -//| hw: ReadableBuffer, -//| n: int, -//| cx0: int, -//| dist: int, -//| cfg: ReadableBuffer, +//| def render( +//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], +//| layers: List[Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]], +//| buffer: Optional[WriteableBuffer], +//| x0: int, +//| y0: int, +//| x1: int, +//| y1: int, +//| *, +//| background: int = 0, //| ) -> None: -//| """Compute one racing-road frame's left and right edge columns. This function is -//| intended for use by the separately distributed ``picogame_road`` helper, which -//| packs the inputs. +//| """Render ``layers`` into the screen region from ``(x0, y0)`` up to, but not +//| including, ``(x1, y1)``, and push it to ``display``, without a `Scene`. //| -//| Walks ``n`` screen rows bottom-up, accumulating the road curve, and writes the -//| edge x coordinates into ``rl`` and ``rr``. -//| -//| :param ~circuitpython_typing.WriteableBuffer rl: at least ``n`` ``int16`` values; -//| receives the left edge per row -//| :param ~circuitpython_typing.WriteableBuffer rr: at least ``n`` ``int16`` values; -//| receives the right edge per row -//| :param ~circuitpython_typing.ReadableBuffer hw: at least ``n`` ``int32`` per-row -//| half-widths (signed 16.16 fixed-point) -//| :param int n: number of rows to compute -//| :param int cx0: screen center x including lateral offset (signed 16.16 fixed-point) -//| :param int dist: integer world distance -//| :param ~circuitpython_typing.ReadableBuffer cfg: seven ``int32`` curve parameters, -//| in order: ``f1_q20``, ``f2_q20``, ``amp1k_q16``, ``amp2k_q16``, ``world_step``, -//| ``curve_step``, ``d_row_off``""" -//| ... -//| -// road_edges(rl, rr, hw, n, cx0, dist, cfg) - one racing-road frame's curve accumulator + integer -// edges in one call (the OutRun-genre compute_road loop; core + cfg layout documented in -// shared-module). rl/rr = int16 out, hw = int32 Q16 half-widths, cx0 = Q16 screen centre -// (incl. lateral), dist = integer world distance, cfg = int32[7]. -static mp_obj_t picogame_road_edges_fn(size_t n_args, const mp_obj_t *args) { - mp_buffer_info_t rli, rri, hwi, cfgi; - mp_get_buffer_raise(args[0], &rli, MP_BUFFER_WRITE); - mp_get_buffer_raise(args[1], &rri, MP_BUFFER_WRITE); - mp_get_buffer_raise(args[2], &hwi, MP_BUFFER_READ); - mp_get_buffer_raise(args[6], &cfgi, MP_BUFFER_READ); - int n = mp_obj_get_int(args[3]); - int cap = (int)(rli.len < rri.len ? rli.len : rri.len) / 2; - if (n > cap) { - n = cap; - } - if (n > (int)(hwi.len / 4)) { - n = (int)(hwi.len / 4); - } - if (n <= 0 || cfgi.len < 7 * 4) { - return mp_const_none; - } - picogame_road_edges((int16_t *)rli.buf, (int16_t *)rri.buf, (const int32_t *)hwi.buf, n, - mp_obj_get_int(args[4]), mp_obj_get_int(args[5]), (const int32_t *)cfgi.buf); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_road_edges_obj, 7, 7, picogame_road_edges_fn); - -//| def project( -//| cam: ReadableBuffer, -//| pts: ReadableBuffer, -//| n: int, -//| out_sx: WriteableBuffer, -//| out_sy: WriteableBuffer, -//| ) -> None: -//| """Batch-project ``n`` 3D world points to screen coordinates. -//| -//| When :py:data:`FPU` is ``1``, ``cam`` and ``pts`` hold ``float32`` elements; -//| otherwise they hold signed 16.16 fixed-point ``int32`` elements. -//| -//| :param ~circuitpython_typing.ReadableBuffer cam: 15 camera parameters, in order: -//| eye x/y/z, right x/z, up x/y/z, forward x/y/z, focal length, screen center -//| x/y, near-plane distance -//| :param ~circuitpython_typing.ReadableBuffer pts: ``3 * n`` world coordinates -//| (x, y, z per point) -//| :param int n: number of points -//| :param ~circuitpython_typing.WriteableBuffer out_sx: at least ``n`` ``int16`` -//| values; receives screen x, or the sentinel ``-32768`` for a point behind -//| the near plane -//| :param ~circuitpython_typing.WriteableBuffer out_sy: at least ``n`` ``int16`` -//| values; receives screen y, or ``-32768`` for a point behind the near plane""" -//| ... -//| -// project(cam, pts, n, out_sx, out_sy) - batch perspective projection of `n` 3D points to screen. -// cam = 15 camera params: ex,ey,ez, rx,rz, ux,uy,uz, fx,fy,fz, focal, cx0, cy0, near -// pts = n*3 world coords (x,y,z per point) -// out_sx/out_sy = int16 screen coords; a point behind the near plane gets sentinel -32768 -// On an FPU board (CIRCUITPY_PICOGAME_FPU) cam/pts are float32; else they are 16.16 fixed int32. -// This is the shared hot path for blocky pseudo-3D (project the 8 corners of each box, then fill). -static mp_obj_t picogame_project(size_t n_args, const mp_obj_t *args) { - mp_buffer_info_t ci, pi, xi, yi; - mp_get_buffer_raise(args[0], &ci, MP_BUFFER_READ); - mp_get_buffer_raise(args[1], &pi, MP_BUFFER_READ); - int n = mp_obj_get_int(args[2]); - mp_get_buffer_raise(args[3], &xi, MP_BUFFER_WRITE); - mp_get_buffer_raise(args[4], &yi, MP_BUFFER_WRITE); - int16_t *osx = xi.buf; - int16_t *osy = yi.buf; - if (n > (int)(xi.len >> 1)) { - n = (int)(xi.len >> 1); - } - #if CIRCUITPY_PICOGAME_FPU - const float *cam = ci.buf; - const float *pts = pi.buf; - float ex = cam[0], ey = cam[1], ez = cam[2]; - float rx = cam[3], rz = cam[4]; - float ux = cam[5], uy = cam[6], uz = cam[7]; - float fx = cam[8], fy = cam[9], fz = cam[10]; - float focal = cam[11], cx0 = cam[12], cy0 = cam[13], near = cam[14]; - for (int i = 0; i < n; i++) { - float X = pts[i * 3] - ex, Y = pts[i * 3 + 1] - ey, Z = pts[i * 3 + 2] - ez; - float cz = X * fx + Y * fy + Z * fz; - if (cz < near) { - osx[i] = -32768; - osy[i] = -32768; - continue; - } - float k = focal / cz; // hardware divide on an FPU part - osx[i] = (int16_t)(cx0 + (X * rx + Z * rz) * k); - osy[i] = (int16_t)(cy0 - (X * ux + Y * uy + Z * uz) * k); - } - #else - const int32_t *cam = ci.buf; // all values 16.16 - const int32_t *pts = pi.buf; - int32_t ex = cam[0], ey = cam[1], ez = cam[2]; - int32_t rx = cam[3], rz = cam[4]; - int32_t ux = cam[5], uy = cam[6], uz = cam[7]; - int32_t fx = cam[8], fy = cam[9], fz = cam[10]; - int32_t focal = cam[11], cx0 = cam[12], cy0 = cam[13], near = cam[14]; - // Full-precision Q16 dot products (int64 mul per term). A Q8-prescaled-basis/MULS variant was - // ~30% faster, but its error grows with |coord| (~0.2%/axis) and k = focal/cz AMPLIFIES it near - // the near plane - host-measured 23-34 px warps on close fly-bys at a file-browser world scale - // (walls visibly broke). Correctness first: Q16 keeps the worst error a few px at any cz >= near, - // for coords up to +-32k units; still ~4-5x faster than the same math in Python on the M0+. - #define FMUL(a, b) ((int32_t)(((int64_t)(a) * (b)) >> 16)) - for (int i = 0; i < n; i++) { - int32_t X = pts[i * 3] - ex, Y = pts[i * 3 + 1] - ey, Z = pts[i * 3 + 2] - ez; - int32_t cz = FMUL(X, fx) + FMUL(Y, fy) + FMUL(Z, fz); - if (cz < near) { - osx[i] = -32768; - osy[i] = -32768; - continue; - } - // focal/cz in 16.16. A 32-bit divide (focal<<8 = Q24, cz>>8 = Q8 -> Q16) is ~4x cheaper than - // an int64 divide on the M0+ (no HW divide) and the lost cz precision costs <0.02 px (host- - // measured). Needs FOCAL < ~250 (focal<<8 in uint32) and near >= 1/256 (cz>>8 nonzero). - int32_t k = (int32_t)(((uint32_t)focal << 8) / (uint32_t)(cz >> 8)); - int32_t rr = FMUL(X, rx) + FMUL(Z, rz); - int32_t uu = FMUL(X, ux) + FMUL(Y, uy) + FMUL(Z, uz); - osx[i] = (int16_t)((cx0 + FMUL(rr, k)) >> 16); - osy[i] = (int16_t)((cy0 - FMUL(uu, k)) >> 16); - } -#undef FMUL - #endif - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_project_obj, 5, 5, picogame_project); - -//| def invert( -//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], on: bool -//| ) -> None: -//| """Enable or disable color inversion. -//| -//| Bus displays receive the controller's inversion command (INVON/INVOFF), which -//| takes effect immediately and sends no pixel data; the controller must support -//| it (ST7789 and ST7735 do). A `Framebuffer` target is instead inverted during -//| composition, starting with the next refresh.""" -//| ... -//| -//| -static mp_obj_t picogame_invert(mp_obj_t display_in, mp_obj_t on_in) { - #if CIRCUITPY_PICOGAME_FRAMEBUFFER - // A Framebuffer target (RP2350 DVI, the WASM playground) has no hardware INVON/INVOFF - - // emulate the flash by XORing the composite (mirrors the Scene/render Framebuffer handling). - if (mp_obj_is_type(display_in, &picogame_framebuffer_type)) { - picogame_fb_set_invert(mp_obj_is_true(on_in)); - return mp_const_none; - } - #endif - picogame_set_invert(pg_get_display(display_in), mp_obj_is_true(on_in)); - return mp_const_none; -} -static MP_DEFINE_CONST_FUN_OBJ_2(picogame_invert_obj, picogame_invert); - -//| def render( -//| display: Union[Display, busdisplay.BusDisplay, Framebuffer], -//| layers: List[Union[Sprite, Tilemap, Canvas, Particles, StripDraw, Triangles]], -//| buffer: Optional[WriteableBuffer], -//| x0: int, -//| y0: int, -//| x1: int, -//| y1: int, -//| *, -//| background: int = 0, -//| ) -> None: -//| """Render ``layers`` into the screen region from ``(x0, y0)`` up to, but not -//| including, ``(x1, y1)``, and push it to ``display``, without a `Scene`. -//| -//| :param display: the render target -//| :param layers: layers of any kind, drawn bottom to top -//| :param ~circuitpython_typing.WriteableBuffer buffer: a reusable strip buffer of -//| at least ``(x1 - x0) * 2`` bytes; ignored (may be `None`) on a -//| `Framebuffer` target -//| :param int x0: left edge of the region -//| :param int y0: top edge of the region -//| :param int x1: right edge of the region (exclusive) -//| :param int y1: bottom edge of the region (exclusive) -//| :param int background: color the region is cleared to first""" -//| ... +//| :param display: the render target +//| :param layers: layers of any kind, drawn bottom to top +//| :param ~circuitpython_typing.WriteableBuffer buffer: a reusable strip buffer of +//| at least ``(x1 - x0) * 2`` bytes; ignored (may be `None`) on a +//| `Framebuffer` target +//| :param int x0: left edge of the region +//| :param int y0: top edge of the region +//| :param int x1: right edge of the region (exclusive) +//| :param int y1: bottom edge of the region (exclusive) +//| :param int background: color the region is cleared to first""" +//| ... //| //| @@ -686,8 +328,8 @@ static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_render_obj, 7, picogame_render_fun); //| overlap. //| //| With six arguments, test rectangle ``(x1, y1, x2, y2)`` against the point -//| ``(ax1, ay1)``. With eight arguments, test it against the rectangle -//| ``(ax1, ay1, ax2, ay2)``. Seven arguments are not accepted. +//| ``(ax1, ay1)``; with eight, test it against the rectangle +//| ``(ax1, ay1, ax2, ay2)``. //| //| Unlike the pixel regions used by `render`, whose upper bounds are excluded, //| collision bounds are inclusive.""" @@ -816,8 +458,9 @@ static mp_obj_t picogame_fbm2d(size_t n_args, const mp_obj_t *pos, mp_map_t *kw) static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm2d_obj, 2, picogame_fbm2d); //| def fbm1d(x: float, *, octaves: int = 4, seed: int = 0, lacunarity: float = 2.0, gain: float = 0.5) -> float: -//| """Fractal (fBm) 1-D noise in ``0..1``: the :py:func:`fbm2d` layering applied -//| to :py:func:`value1d`.""" +//| """Fractal (fBm) 1-D noise in ``0..1``: ``octaves`` layers of +//| :py:func:`value1d`, each ``lacunarity`` times finer and ``gain`` times +//| weaker than the last.""" //| ... //| //| @@ -931,6 +574,374 @@ static mp_obj_t picogame_fbm1d_fx(size_t n_args, const mp_obj_t *pos, mp_map_t * static MP_DEFINE_CONST_FUN_OBJ_KW(picogame_fbm1d_fx_obj, 1, picogame_fbm1d_fx); +//| def project( +//| cam: ReadableBuffer, +//| pts: ReadableBuffer, +//| n: int, +//| out_sx: WriteableBuffer, +//| out_sy: WriteableBuffer, +//| ) -> None: +//| """Batch-project ``n`` 3D world points to screen coordinates. +//| +//| When :py:data:`FPU` is ``1``, ``cam`` and ``pts`` hold ``float32`` elements; +//| otherwise they hold signed 16.16 fixed-point ``int32`` elements. +//| +//| :param ~circuitpython_typing.ReadableBuffer cam: 15 camera parameters, in order: +//| eye x/y/z, right x/z (the camera cannot roll, so right has no y +//| component), up x/y/z, forward x/y/z, focal length, screen center x/y, +//| near-plane distance +//| :param ~circuitpython_typing.ReadableBuffer pts: ``3 * n`` world coordinates +//| (x, y, z per point) +//| :param int n: number of points +//| :param ~circuitpython_typing.WriteableBuffer out_sx: at least ``n`` ``int16`` +//| values; receives screen x, or the sentinel ``-32768`` for a point behind +//| the near plane +//| :param ~circuitpython_typing.WriteableBuffer out_sy: at least ``n`` ``int16`` +//| values; receives screen y, or ``-32768`` for a point behind the near plane""" +//| ... +//| +// project(cam, pts, n, out_sx, out_sy) - batch perspective projection of `n` 3D points to screen. +// cam = 15 camera params: ex,ey,ez, rx,rz, ux,uy,uz, fx,fy,fz, focal, cx0, cy0, near +// pts = n*3 world coords (x,y,z per point) +// out_sx/out_sy = int16 screen coords; a point behind the near plane gets sentinel -32768 +// On an FPU board (CIRCUITPY_PICOGAME_FPU) cam/pts are float32; else they are 16.16 fixed int32. +// This is the shared hot path for blocky pseudo-3D (project the 8 corners of each box, then fill). +static mp_obj_t picogame_project(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t ci, pi, xi, yi; + mp_get_buffer_raise(args[0], &ci, MP_BUFFER_READ); + mp_get_buffer_raise(args[1], &pi, MP_BUFFER_READ); + int n = mp_obj_get_int(args[2]); + mp_get_buffer_raise(args[3], &xi, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[4], &yi, MP_BUFFER_WRITE); + int16_t *osx = xi.buf; + int16_t *osy = yi.buf; + if (n > (int)(xi.len >> 1)) { + n = (int)(xi.len >> 1); + } + #if CIRCUITPY_PICOGAME_FPU + const float *cam = ci.buf; + const float *pts = pi.buf; + float ex = cam[0], ey = cam[1], ez = cam[2]; + float rx = cam[3], rz = cam[4]; + float ux = cam[5], uy = cam[6], uz = cam[7]; + float fx = cam[8], fy = cam[9], fz = cam[10]; + float focal = cam[11], cx0 = cam[12], cy0 = cam[13], near = cam[14]; + for (int i = 0; i < n; i++) { + float X = pts[i * 3] - ex, Y = pts[i * 3 + 1] - ey, Z = pts[i * 3 + 2] - ez; + float cz = X * fx + Y * fy + Z * fz; + if (cz < near) { + osx[i] = -32768; + osy[i] = -32768; + continue; + } + float k = focal / cz; // hardware divide on an FPU part + osx[i] = (int16_t)(cx0 + (X * rx + Z * rz) * k); + osy[i] = (int16_t)(cy0 - (X * ux + Y * uy + Z * uz) * k); + } + #else + const int32_t *cam = ci.buf; // all values 16.16 + const int32_t *pts = pi.buf; + int32_t ex = cam[0], ey = cam[1], ez = cam[2]; + int32_t rx = cam[3], rz = cam[4]; + int32_t ux = cam[5], uy = cam[6], uz = cam[7]; + int32_t fx = cam[8], fy = cam[9], fz = cam[10]; + int32_t focal = cam[11], cx0 = cam[12], cy0 = cam[13], near = cam[14]; + // Full-precision Q16 dot products (int64 mul per term). A Q8-prescaled-basis/MULS variant was + // ~30% faster, but its error grows with |coord| (~0.2%/axis) and k = focal/cz AMPLIFIES it near + // the near plane - host-measured 23-34 px warps on close fly-bys at a file-browser world scale + // (walls visibly broke). Correctness first: Q16 keeps the worst error a few px at any cz >= near, + // for coords up to +-32k units; still ~4-5x faster than the same math in Python on the M0+. + #define FMUL(a, b) ((int32_t)(((int64_t)(a) * (b)) >> 16)) + for (int i = 0; i < n; i++) { + int32_t X = pts[i * 3] - ex, Y = pts[i * 3 + 1] - ey, Z = pts[i * 3 + 2] - ez; + int32_t cz = FMUL(X, fx) + FMUL(Y, fy) + FMUL(Z, fz); + if (cz < near) { + osx[i] = -32768; + osy[i] = -32768; + continue; + } + // focal/cz in 16.16. A 32-bit divide (focal<<8 = Q24, cz>>8 = Q8 -> Q16) is ~4x cheaper than + // an int64 divide on the M0+ (no HW divide) and the lost cz precision costs <0.02 px (host- + // measured). Needs FOCAL < ~250 (focal<<8 in uint32) and near >= 1/256 (cz>>8 nonzero). + int32_t k = (int32_t)(((uint32_t)focal << 8) / (uint32_t)(cz >> 8)); + int32_t rr = FMUL(X, rx) + FMUL(Z, rz); + int32_t uu = FMUL(X, ux) + FMUL(Y, uy) + FMUL(Z, uz); + osx[i] = (int16_t)((cx0 + FMUL(rr, k)) >> 16); + osy[i] = (int16_t)((cy0 - FMUL(uu, k)) >> 16); + } +#undef FMUL + #endif + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_project_obj, 5, 5, picogame_project); + + + +//| def raycast( +//| map: ReadableBuffer, +//| mw: int, +//| mh: int, +//| posx: int, +//| posy: int, +//| lrx: int, +//| lry: int, +//| srx: int, +//| sry: int, +//| sh: int, +//| stride: int, +//| ncols: int, +//| wcolors: ReadableBuffer, +//| top: WriteableBuffer, +//| bot: WriteableBuffer, +//| col: WriteableBuffer, +//| dist: WriteableBuffer, +//| runs: Optional[WriteableBuffer] = None, +//| ) -> Optional[int]: +//| """Cast one frame of wall-finding rays across the screen columns of a +//| grid-map view. A low-level interface used by the ``picogame_ray`` helper, +//| which computes these inputs. +//| +//| All fixed-point arguments are signed 16.16 integers. +//| +//| :param ~circuitpython_typing.ReadableBuffer map: at least ``mw * mh`` wall-type +//| bytes, row-major; 0 is empty +//| :param int mw: map width in cells +//| :param int mh: map height in cells +//| :param int posx: camera x position (fixed-point) +//| :param int posy: camera y position (fixed-point) +//| :param int lrx: x of the column-0 ray direction (fixed-point) +//| :param int lry: y of the column-0 ray direction (fixed-point) +//| :param int srx: per-column ray step x (fixed-point) +//| :param int sry: per-column ray step y (fixed-point) +//| :param int sh: screen height in pixels +//| :param int stride: pixel width of one column +//| :param int ncols: number of columns to cast +//| :param ~circuitpython_typing.ReadableBuffer wcolors: two ``uint16`` colors per +//| wall type: near face at ``[type * 2]``, side face at ``[type * 2 + 1]`` +//| :param ~circuitpython_typing.WriteableBuffer top: at least ``ncols`` ``uint16`` +//| values; receives each column's wall top row +//| :param ~circuitpython_typing.WriteableBuffer bot: at least ``ncols`` ``uint16`` +//| values; receives each column's wall bottom row +//| :param ~circuitpython_typing.WriteableBuffer col: at least ``ncols`` ``uint16`` +//| values; receives each column's wall color +//| :param ~circuitpython_typing.WriteableBuffer dist: at least ``ncols`` ``int32`` +//| values; receives each column's perpendicular distance (fixed-point) +//| :param ~circuitpython_typing.WriteableBuffer runs: optional; at least +//| ``5 * ncols`` ``uint16`` values, laid out as five ``ncols``-long planes +//| (x0s, x1s, tops, bots, colors). When given, adjacent equal columns are +//| merged into wall runs suitable for :py:meth:`Canvas.vspans` and the run +//| count is returned; otherwise `None` is returned.""" +//| ... +//| +// C DDA wall raycaster for picogame_ray.Raycaster - INTEGER ONLY (16.16 fixed-point, no FPU; the paint, +// temporal invalidate, pose-cache and billboard math stay in Python; Python does the once-per-frame +// trig and passes Q16 ray params). map: read-only bytes, mw*mh wall types (0 = empty). pos*, l*x/l*y +// (leftRay, column 0), s*x/s*y (rayStep per column) are all 16.16. wcolors: uint16[(maxtype+1)*2] - +// [t*2] near, [t*2+1] side colour. top/bot/col: uint16 write buffers (len>=ncols); dist: int32 write +// buffer (perpendicular distance, 16.16). The int64 divides/muls are ONLY the per-column setup +// (O(ncols)); the DDA step loop is pure 32-bit. Mirrors the Python float fallback closely. +// Optional arg 17 (runs - ONE uint16 write buffer, len>=5*ncols, laid out as five ncols-long +// planes [x0s | x1s | tops | bots | colors]): also emit the RLE-MERGED wall runs (adjacent equal +// columns fused; x in PIXELS = column*stride) and return the run count. The planes feed +// Canvas.vspans directly as memoryview slices. This hoists picogame_ray's per-frame Python merge +// loop into the same C pass (measured 2-6.5 ms/frame of interpreted merge at stride=1 on RP2040). +// Callers clamp the LAST run's x1 to the screen width (stride rounding can overshoot by = 18) { // run outputs requested + mp_buffer_info_t q; + mp_get_buffer_raise(args[17], &q, MP_BUFFER_WRITE); + int cap = (int)(q.len / 10); // five uint16 planes + if (ncols > cap) { + ncols = cap; // never write past the run planes + } + r0 = q.buf; + r1 = r0 + cap; + rt = r1 + cap; + rb = rt + cap; + rcol = rb + cap; + } + const uint8_t *map = mi.buf; + const uint16_t *wc = wi.buf; + int wc_types = (int)(wi.len >> 2); + uint16_t *top = ti.buf; + uint16_t *bot = bi.buf; + uint16_t *col = ci.buf; + int32_t *dist_out = di.buf; // perpendicular distance, 16.16 + int half = sh >> 1; + int imapx0 = posx >> 16; + int imapy0 = posy >> 16; + int32_t fracx = posx & 0xFFFF; // fractional part of pos, 16.16 + int32_t fracy = posy & 0xFFFF; + const int32_t DD_CAP = (int32_t)1 << 24; // cap deltaDist so a 64-step accumulation stays in int32 + if (ncols > (int)(ti.len >> 1)) { + ncols = (int)(ti.len >> 1); + } + for (int c = 0; c < ncols; c++) { + int mapx = imapx0; + int mapy = imapy0; + int32_t ax = rdx < 0 ? -rdx : rdx; + int32_t ay = rdy < 0 ? -rdy : rdy; + // deltaDist = |1/rayDir| in 16.16 = (1<<32)/|rayDir_q16| (int64; per-column setup, not per-step) + int64_t ddx64 = ax ? (((int64_t)1 << 32) / ax) : (int64_t)DD_CAP; + int64_t ddy64 = ay ? (((int64_t)1 << 32) / ay) : (int64_t)DD_CAP; + int32_t ddx = ddx64 > DD_CAP ? DD_CAP : (int32_t)ddx64; + int32_t ddy = ddy64 > DD_CAP ? DD_CAP : (int32_t)ddy64; + int stepx, stepy; + int32_t sidex, sidey; + // sideDist to the first grid line = (fractional distance) * deltaDist, 16.16 (int64 mul, setup only) + if (rdx < 0) { + stepx = -1; + sidex = (int32_t)(((int64_t)fracx * ddx) >> 16); + } else { + stepx = 1; + sidex = (int32_t)(((int64_t)(65536 - fracx) * ddx) >> 16); + } + if (rdy < 0) { + stepy = -1; + sidey = (int32_t)(((int64_t)fracy * ddy) >> 16); + } else { + stepy = 1; + sidey = (int32_t)(((int64_t)(65536 - fracy) * ddy) >> 16); + } + int side = 0; + int cell = 1; + for (int i = 0; i < 64; i++) { // DDA - pure 32-bit + if (sidex < sidey) { + sidex += ddx; + mapx += stepx; + side = 0; + } else { + sidey += ddy; + mapy += stepy; + side = 1; + } + cell = (mapx >= 0 && mapx < mw && mapy >= 0 && mapy < mh) ? map[mapy * mw + mapx] : 1; + if (cell) { + break; + } + } + int32_t perp = (side == 0) ? (sidex - ddx) : (sidey - ddy); // perpWallDist, 16.16 + if (perp < 655) { + perp = 655; // ~0.01 in 16.16 + } + int lh = (int)(((int32_t)sh << 16) / perp); // sh / perpWallDist (px); 32-bit (sh<<16 <= ~15.7M) + int t = half - (lh >> 1); + int b = t + lh; + if (t < 0) { + t = 0; + } + if (b > sh) { + b = sh; + } + top[c] = (uint16_t)t; + bot[c] = (uint16_t)b; + int ct = (cell < wc_types) ? cell : 1; // unknown type -> type 1 (matches Python default) + col[c] = wc[ct * 2 + side]; + dist_out[c] = perp; + rdx += srx; // accumulate ray direction for the next column (no overflow) + rdy += sry; + } + if (r0 && ncols > 0) { + // post-pass RLE over the just-written (cache-hot) column arrays: one flush point + int nr = 0; + int rstart = 0; + for (int c = 1; c <= ncols; c++) { + if (c == ncols || top[c] != top[rstart] || bot[c] != bot[rstart] || col[c] != col[rstart]) { + r0[nr] = (uint16_t)(rstart * stride); + r1[nr] = (uint16_t)(c * stride); + rt[nr] = top[rstart]; + rb[nr] = bot[rstart]; + rcol[nr] = col[rstart]; + nr++; + rstart = c; + } + } + return MP_OBJ_NEW_SMALL_INT(nr); + } + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_raycast_obj, 17, 18, picogame_raycast); + + + +//| def road_edges( +//| rl: WriteableBuffer, +//| rr: WriteableBuffer, +//| hw: ReadableBuffer, +//| n: int, +//| cx0: int, +//| dist: int, +//| cfg: ReadableBuffer, +//| ) -> None: +//| """Compute one racing-road frame's left and right edge columns. A low-level +//| interface used by the ``picogame_road`` helper, which packs these inputs. +//| +//| Walks ``n`` screen rows bottom-up, accumulating the road curve, and writes the +//| edge x coordinates into ``rl`` and ``rr``. +//| +//| :param ~circuitpython_typing.WriteableBuffer rl: at least ``n`` ``int16`` values; +//| receives the left edge per row +//| :param ~circuitpython_typing.WriteableBuffer rr: at least ``n`` ``int16`` values; +//| receives the right edge per row +//| :param ~circuitpython_typing.ReadableBuffer hw: at least ``n`` ``int32`` per-row +//| half-widths (signed 16.16 fixed-point) +//| :param int n: number of rows to compute +//| :param int cx0: screen center x including lateral offset (signed 16.16 fixed-point) +//| :param int dist: integer world distance +//| :param ~circuitpython_typing.ReadableBuffer cfg: seven ``int32`` curve parameters, +//| in order: ``f1_q20``, ``f2_q20``, ``amp1k_q16``, ``amp2k_q16``, ``world_step``, +//| ``curve_step``, ``d_row_off``""" +//| ... +//| +// road_edges(rl, rr, hw, n, cx0, dist, cfg) - one racing-road frame's curve accumulator + integer +// edges in one call (the OutRun-genre compute_road loop; core + cfg layout documented in +// shared-module). rl/rr = int16 out, hw = int32 Q16 half-widths, cx0 = Q16 screen centre +// (incl. lateral), dist = integer world distance, cfg = int32[7]. +static mp_obj_t picogame_road_edges_fn(size_t n_args, const mp_obj_t *args) { + mp_buffer_info_t rli, rri, hwi, cfgi; + mp_get_buffer_raise(args[0], &rli, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[1], &rri, MP_BUFFER_WRITE); + mp_get_buffer_raise(args[2], &hwi, MP_BUFFER_READ); + mp_get_buffer_raise(args[6], &cfgi, MP_BUFFER_READ); + int n = mp_obj_get_int(args[3]); + int cap = (int)(rli.len < rri.len ? rli.len : rri.len) / 2; + if (n > cap) { + n = cap; + } + if (n > (int)(hwi.len / 4)) { + n = (int)(hwi.len / 4); + } + if (n <= 0 || cfgi.len < 7 * 4) { + return mp_const_none; + } + picogame_road_edges((int16_t *)rli.buf, (int16_t *)rri.buf, (const int32_t *)hwi.buf, n, + mp_obj_get_int(args[4]), mp_obj_get_int(args[5]), (const int32_t *)cfgi.buf); + return mp_const_none; +} +static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(picogame_road_edges_obj, 7, 7, picogame_road_edges_fn); + + + // Builds without a given display backend still expose its type: constructing it raises, the same // way an unsupported rgb444= does, instead of the module changing shape with build flags. #if !CIRCUITPY_PICOGAME_FAST_DISPLAY || !CIRCUITPY_PICOGAME_FRAMEBUFFER From 4ce46306c703aa4d3b95f4e3b4332e9a07b08832 Mon Sep 17 00:00:00 2001 From: Vladimir Smitka Date: Thu, 27 Aug 2026 10:36:40 +0000 Subject: [PATCH 868/876] picogame: accept subclasses of Framebuffer and Display as render targets Scene, render() and invert() resolved a Framebuffer with a bare type check, so an instance of a Python subclass fell through to the busdisplay branch and the renderer cast the wrong pointer - a memory fault instead of an error. BusDisplay targets already accepted subclasses through mp_obj_cast_to_native_base; the Framebuffer and Display checks now do the same and resolve to the native base object. Found by running the module example against a Framebuffer subclass. --- shared-bindings/picogame/Scene.c | 20 ++++++++++++++------ shared-bindings/picogame/__init__.c | 23 ++++++++++++++++++----- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/shared-bindings/picogame/Scene.c b/shared-bindings/picogame/Scene.c index ea016047331..02bfffe843e 100644 --- a/shared-bindings/picogame/Scene.c +++ b/shared-bindings/picogame/Scene.c @@ -42,15 +42,23 @@ static mp_obj_t scene_resolve_target(mp_obj_t disp, bool *fast, bool *fb_target) *fast = false; *fb_target = false; #if CIRCUITPY_PICOGAME_FAST_DISPLAY - if (mp_obj_is_type(disp, &picogame_display_type)) { - *fast = true; - return disp; + { + // Accept subclasses too (same as the busdisplay path below): resolve to the + // native base object, which the C renderer can safely cast. + mp_obj_t ndisp = mp_obj_cast_to_native_base(disp, &picogame_display_type); + if (ndisp != MP_OBJ_NULL && mp_obj_is_type(ndisp, &picogame_display_type)) { + *fast = true; + return ndisp; + } } #endif #if CIRCUITPY_PICOGAME_FRAMEBUFFER - if (mp_obj_is_type(disp, &picogame_framebuffer_type)) { - *fb_target = true; // refresh() composites dirty rects straight into its RAM buffer - return disp; + { + mp_obj_t nfb = mp_obj_cast_to_native_base(disp, &picogame_framebuffer_type); + if (nfb != MP_OBJ_NULL && mp_obj_is_type(nfb, &picogame_framebuffer_type)) { + *fb_target = true; // refresh() composites dirty rects straight into its RAM buffer + return nfb; + } } #endif // Plain busdisplay: accept a subclass by casting to its native base; the portable diff --git a/shared-bindings/picogame/__init__.c b/shared-bindings/picogame/__init__.c index d8ec1df17bc..4e6e6f5e87e 100644 --- a/shared-bindings/picogame/__init__.c +++ b/shared-bindings/picogame/__init__.c @@ -37,6 +37,17 @@ // expected, so the same object a Scene renders through also works for render()/invert(). // Without this, code holding the wrapper (custom setup, rgb444) worked on ports WITHOUT the // fast backend and TypeError'd on ports WITH it. +#if CIRCUITPY_PICOGAME_FRAMEBUFFER +// Resolve a Framebuffer, or a subclass of it, to the native object; NULL otherwise. +static picogame_framebuffer_obj_t *pg_fb_native(mp_obj_t obj) { + mp_obj_t nfb = mp_obj_cast_to_native_base(obj, &picogame_framebuffer_type); + if (nfb != MP_OBJ_NULL && mp_obj_is_type(nfb, &picogame_framebuffer_type)) { + return MP_OBJ_TO_PTR(nfb); + } + return NULL; +} +#endif + static busdisplay_busdisplay_obj_t *pg_get_display(mp_obj_t obj) { #if CIRCUITPY_PICOGAME_FAST_DISPLAY if (mp_obj_is_type(obj, &picogame_display_type)) { @@ -167,9 +178,12 @@ static mp_obj_t picogame_invert(mp_obj_t display_in, mp_obj_t on_in) { #if CIRCUITPY_PICOGAME_FRAMEBUFFER // A Framebuffer target (RP2350 DVI, the WASM playground) has no hardware INVON/INVOFF - // emulate the flash by XORing the composite (mirrors the Scene/render Framebuffer handling). - if (mp_obj_is_type(display_in, &picogame_framebuffer_type)) { - picogame_fb_set_invert(mp_obj_is_true(on_in)); - return mp_const_none; + { + mp_obj_t nfb = mp_obj_cast_to_native_base(display_in, &picogame_framebuffer_type); + if (nfb != MP_OBJ_NULL && mp_obj_is_type(nfb, &picogame_framebuffer_type)) { + picogame_fb_set_invert(mp_obj_is_true(on_in)); + return mp_const_none; + } } #endif picogame_set_invert(pg_get_display(display_in), mp_obj_is_true(on_in)); @@ -250,8 +264,7 @@ static mp_obj_t picogame_render_fun(size_t n_args, const mp_obj_t *pos_args, mp_ // HudBar / immediate-mode path on scanout-buffer platforms. Mirrors the Scene change. #if CIRCUITPY_PICOGAME_FRAMEBUFFER picogame_framebuffer_obj_t *fbt = - mp_obj_is_type(args[ARG_display].u_obj, &picogame_framebuffer_type) - ? MP_OBJ_TO_PTR(args[ARG_display].u_obj) : NULL; + pg_fb_native(args[ARG_display].u_obj); busdisplay_busdisplay_obj_t *display = fbt ? NULL : pg_get_display(args[ARG_display].u_obj); #else busdisplay_busdisplay_obj_t *display = pg_get_display(args[ARG_display].u_obj); From 08ad3f91bb51b34a7f264dae9d3c82b76f35b928 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Sat, 1 Aug 2026 15:35:16 -0700 Subject: [PATCH 869/876] zephyr-cp/wifi: implement radio.ap_info common_hal_wifi_radio_get_ap_info() returned mp_const_none unconditionally, with the espressif implementation left commented out beneath it. So there was no way to read the RSSI, BSSID or channel of the AP actually associated with. The only workaround was a full scan matched against the connected SSID, which costs a scan, briefly takes the radio away from the association being asked about, and cannot distinguish the connected AP from another radio broadcasting the same SSID. Zephyr already exposes this through NET_REQUEST_WIFI_IFACE_STATUS. Translate the resulting wifi_iface_status into the wifi_scan_result that wifi.Network wraps, and return None when there is nothing to report. Two details worth keeping: - Guarded on WIFI_STATE_ASSOCIATED rather than a connected flag alone. Associated is the weakest state in which BSSID and RSSI are meaningful. - status.rssi is int, scan_result.rssi is int8_t dBm. Clamped rather than truncated: a wrapped value would surface as a positive dBm, which is the same class of bug as the driver's unsigned-magnitude RSSI fixed in siwx917/fix-scan-rssi-sign. Verified on BRD2605A against the scan-based workaround it replaces: ap_info ('foreverrun', 'b0:19:21:df:d4:03', -43, 5) scan ('foreverrun', 'b0:19:21:df:d4:03', -42, 5) bssid match True | channel match True | rssi delta -1 Same BSSID and channel; the 1 dBm difference is the two samples being taken a scan apart. The BSSID is also distinct from wifi.radio.mac_address, confirming it reports the access point rather than the station. Depends on siwx917/feat-wifi-station-connect: the guard needs self->connected to be maintained, which is what that branch fixes. Co-Authored-By: Claude Opus 5 (1M context) (cherry picked from commit 098263a8eb81119ec682df54b05873fa5609c8a6) --- ports/zephyr-cp/common-hal/wifi/Radio.c | 37 +++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 7658deac26e..78ff844a167 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -594,8 +594,41 @@ bool common_hal_wifi_radio_get_connected(wifi_radio_obj_t *self) { } mp_obj_t common_hal_wifi_radio_get_ap_info(wifi_radio_obj_t *self) { - // if (!esp_netif_is_netif_up(self->netif)) { - return mp_const_none; + if (self->sta_netif == NULL || !self->connected) { + return mp_const_none; + } + + // NET_REQUEST_WIFI_IFACE_STATUS carries everything a wifi.Network needs, so + // this reports the live association without spending a scan on it. + struct wifi_iface_status status = { 0 }; + if (net_mgmt(NET_REQUEST_WIFI_IFACE_STATUS, self->sta_netif, + &status, sizeof(status)) != 0) { + return mp_const_none; + } + + // Associated is the weakest state that has a meaningful BSSID and RSSI. + if (status.state < WIFI_STATE_ASSOCIATED) { + return mp_const_none; + } + + // wifi.Network wraps a scan result, so translate the status into one. + wifi_network_obj_t *ap_info = mp_obj_malloc(wifi_network_obj_t, &wifi_network_type); + size_t ssid_len = MIN(status.ssid_len, sizeof(ap_info->scan_result.ssid) - 1); + memcpy(ap_info->scan_result.ssid, status.ssid, ssid_len); + ap_info->scan_result.ssid[ssid_len] = '\0'; + ap_info->scan_result.ssid_length = ssid_len; + memcpy(ap_info->scan_result.mac, status.bssid, WIFI_MAC_ADDR_LEN); + ap_info->scan_result.mac_length = WIFI_MAC_ADDR_LEN; + ap_info->scan_result.band = status.band; + ap_info->scan_result.channel = status.channel; + ap_info->scan_result.security = status.security; + ap_info->scan_result.wpa3_ent_type = status.wpa3_ent_type; + ap_info->scan_result.mfp = status.mfp; + // status.rssi is int, scan_result.rssi is int8_t. Clamp, since a truncated + // value would wrap to a positive dBm. + ap_info->scan_result.rssi = (int8_t)MIN(MAX(status.rssi, INT8_MIN), INT8_MAX); + return MP_OBJ_FROM_PTR(ap_info); + // } // // Make sure the interface is in STA mode From 75b247098a64b0d5d964c5a252bf21ca40cd14ef Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Thu, 13 Aug 2026 20:29:03 -0700 Subject: [PATCH 870/876] zephyr-cp/wifi: implement radio.ping() on Zephyr's ICMP API common_hal_wifi_radio_ping() was a stub: the ESP-IDF body was commented out and it ended `return 0;`. The binding treats -1 and only -1 as failure (shared-bindings/wifi/Radio.c), so 0 was handed to Python as a successful 0 ms round trip. Callers written as `if result is None` read every failed ping as a success, including pings to unreachable addresses and pings issued while the radio was not even associated. Fixes mikeysklar/circuitpython#46. Implemented on net_icmp_init_ctx() / net_icmp_send_echo_request(). No Kconfig change is needed: there is no CONFIG_NET_ICMPV4 symbol in this Zephyr revision, ICMP gates on NET_IP/NET_IPV4, and NET_IPV4 is already set for this board. Notes on the implementation: - Returns elapsed milliseconds, and -1 for every failure path: bad context, send failure, timeout, and interruption. Never 0 except for a genuine sub-millisecond round trip. - Per-call state lives on the caller's stack and reaches the reply handler as the ICMP context's user_data, so there are no globals. This is safe in both directions: icmp.c assigns ctx->user_data before handing the packet to the stack, so a racing reply cannot see a stale pointer, and net_icmp_cleanup_ctx() takes the same lock the stack holds while dispatching handlers, so teardown cannot race a handler mid-dereference. - The handler matches on identifier and sequence and returns NET_CONTINUE on a mismatch. Without it, back-to-back pings report each other's timings. It reads the header with net_pkt_get_data(), which leaves the packet cursor alone, because NET_CONTINUE passes the packet to the next handler. - The wait polls with k_sem_take clamped to the time actually remaining, so ctrl-C stays responsive at 50 ms granularity while a sub-50 ms timeout cannot report a round trip that exceeded it. - Arrival is timestamped inside the handler rather than after the semaphore wakes, so the measurement excludes scheduling delay. - This Zephyr renamed the socket address types, so the destination is a struct net_sockaddr_in with NET_AF_INET. Code copied from older ICMP examples will not compile. Verified on BRD2605A: ping(gateway 192.168.0.1) 0.02 (float), wall 0.023 s ping(192.0.2.1, timeout=2) None, wall 2.003 s ping("not-an-address") ValueError: Only IPv4 addresses supported interleaved: 192.168.0.1 0.014 -> 1.1.1.1 0.024 192.168.0.1 0.010 -> 8.8.8.8 0.022 The interleaved run exercises the sequence guard: the local gateway stays at 10-14 ms across both visits while the two internet hosts sit at 22-24 ms, and every reported value tracks its own wall-clock measurement to within 3 ms. Costs 1,392 B of flash. Known limitation: an unroutable address and a routable but absent one are indistinguishable from Python, since both return None after the timeout. Destination-unreachable replies are not observed either, as the context is registered for NET_ICMPV4_ECHO_REPLY only. Built and tested on top of siwx917/fix-dns-zvfs-poll-max, though it does not depend on it. Radio.c is identical at both bases. Co-Authored-By: Claude Opus 5 (1M context) (cherry picked from commit 6fc0583d2ea4d2445843388e1e96b4da23e69485) --- ports/zephyr-cp/common-hal/wifi/Radio.c | 211 +++++++++++++++++++----- 1 file changed, 168 insertions(+), 43 deletions(-) diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 78ff844a167..6c1c3e90056 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -30,8 +30,11 @@ // dns_resolve_get_default() for radio.ipv4_dns. #include #include +// net_icmp_* for radio.ping(). +#include #include #include +#include #if CIRCUITPY_MDNS #include "common-hal/mdns/Server.h" @@ -895,57 +898,179 @@ void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t // common_hal_wifi_radio_start_dhcp_server(self); // restart access point DHCP } -// static void ping_success_cb(esp_ping_handle_t hdl, void *args) { -// wifi_radio_obj_t *self = (wifi_radio_obj_t *)args; -// esp_ping_get_profile(hdl, ESP_PING_PROF_TIMEGAP, &self->ping_elapsed_time, sizeof(self->ping_elapsed_time)); -// } +// Zephyr delivers the echo reply on the network RX thread, not the caller's, so +// the two halves share this state through the ICMP context's user_data. It lives +// on the calling thread's stack, hence the cleanup discipline in ping() below. +typedef struct { + struct k_sem reply_sem; + int64_t sent_ms; + int64_t elapsed_ms; + uint16_t identifier; + uint16_t sequence; +} ping_session_t; + +// Zephyr keeps struct net_icmpv4_echo_req in subsys/net/ip/icmpv4.h, a private +// header that code outside the net stack cannot include, so mirror the four +// bytes that follow the ICMP header here. +struct ping_echo_hdr { + uint16_t identifier; + uint16_t sequence; +} __packed; + +// An echo carries no port number, so the sequence is the only thing telling two +// back-to-back requests apart; without it a late reply would be reported as the +// next call's round trip. The identifier is randomized once per boot. +static uint16_t ping_identifier; +static uint16_t ping_sequence; + +static enum net_verdict ping_reply_handler(struct net_icmp_ctx *ctx, + struct net_pkt *pkt, + struct net_icmp_ip_hdr *ip_hdr, + struct net_icmp_hdr *icmp_hdr, + void *user_data) { + NET_PKT_DATA_ACCESS_CONTIGUOUS_DEFINE(echo_access, struct ping_echo_hdr); + ping_session_t *session = user_data; + struct ping_echo_hdr *echo; + + (void)ctx; + (void)ip_hdr; + (void)icmp_hdr; + + if (session == NULL) { + return NET_CONTINUE; + } + + // net_pkt_get_data() leaves the cursor where it found it, which the + // NET_CONTINUE below relies on: the next handler starts at the echo header. + echo = (struct ping_echo_hdr *)net_pkt_get_data(pkt, &echo_access); + if (echo == NULL) { + return NET_CONTINUE; + } + + if (net_ntohs(echo->identifier) != session->identifier || + net_ntohs(echo->sequence) != session->sequence) { + // A reply to an earlier ping of ours, or to somebody else's. Leave it + // alone rather than waking the caller with a round trip time that + // belongs to a different request. + return NET_CONTINUE; + } + + // Stamp arrival here rather than after k_sem_take() returns, so the + // measurement does not absorb the woken thread's scheduling delay. + session->elapsed_ms = k_uptime_get() - session->sent_ms; + k_sem_give(&session->reply_sem); + + return NET_OK; +} mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout) { - // esp_ping_config_t ping_config = ESP_PING_DEFAULT_CONFIG(); - // ipaddress_ipaddress_to_esp_idf(ip_address, &ping_config.target_addr); - // ping_config.count = 1; - - // // We must fetch ping information using the callback mechanism, because the session storage is freed when - // // the ping session is done, even before esp_ping_delete_session(). - // esp_ping_callbacks_t ping_callbacks = { - // .on_ping_success = ping_success_cb, - // .cb_args = (void *)self, - // }; + // radio.ping() is documented to take an ipaddress.IPv4Address. + if (!mp_obj_is_type(ip_address, &ipaddress_ipv4address_type)) { + mp_raise_ValueError(MP_ERROR_TEXT("Only IPv4 addresses supported")); + } - // size_t timeout_ms = timeout * 1000; + // get_packed() takes a concrete ipaddress_ipv4address_obj_t *, so the + // MP_OBJ_TO_PTR is needed under object representations C and D. + ipaddress_ipv4address_obj_t *addr_obj = MP_OBJ_TO_PTR(ip_address); + size_t packed_len; + const char *packed = mp_obj_str_get_data( + common_hal_ipaddress_ipv4address_get_packed(addr_obj), &packed_len); + if (packed_len != sizeof(struct net_in_addr)) { + mp_raise_ValueError(MP_ERROR_TEXT("Only IPv4 addresses supported")); + } - // // ESP-IDF creates a task to do the ping session. It shuts down when done, but only after a one second delay. - // // Calling common_hal_wifi_radio_ping() too fast will cause resource exhaustion. - // esp_ping_handle_t ping; - // if (esp_ping_new_session(&ping_config, &ping_callbacks, &ping) != ESP_OK) { - // // Wait for old task to go away and then try again. - // // Empirical testing shows we have to wait at least two seconds, despite the task - // // having a one-second timeout. - // common_hal_time_delay_ms(2000); - // // Return if interrupted now, to show the interruption as KeyboardInterrupt instead of the - // // IDF error. - // if (mp_hal_is_interrupted()) { - // return (uint32_t)(-1); - // } - // CHECK_ESP_RESULT(esp_ping_new_session(&ping_config, &ping_callbacks, &ping)); - // } + // This Zephyr renamed the socket address types, so the destination is a + // struct net_sockaddr_in carrying NET_AF_INET, not a sockaddr_in/AF_INET. + struct net_sockaddr_in dst = { + .sin_family = NET_AF_INET, + }; + memcpy(&dst.sin_addr, packed, sizeof(dst.sin_addr)); + + if (ping_identifier == 0) { + // Seeded lazily. sys_rand16_get() may legitimately return 0, in which + // case we simply reseed on the next call. + ping_identifier = sys_rand16_get(); + } - // // Use all ones as a flag that the elapsed time was not set (ping failed or timed out). - // self->ping_elapsed_time = (uint32_t)(-1); + ping_session_t session = { + .identifier = ping_identifier, + .sequence = ++ping_sequence, + .elapsed_ms = -1, + }; + k_sem_init(&session.reply_sem, 0, 1); - // esp_ping_start(ping); + struct net_icmp_ctx icmp_ctx; + int res = net_icmp_init_ctx(&icmp_ctx, NET_AF_INET, NET_ICMPV4_ECHO_REPLY, 0, + ping_reply_handler); + if (res < 0) { + LOG_DBG("ping: net_icmp_init_ctx failed (%d)", res); + return -1; + } - // uint32_t start_time = common_hal_time_monotonic_ms(); - // while ((self->ping_elapsed_time == (uint32_t)(-1)) && - // (common_hal_time_monotonic_ms() - start_time < timeout_ms) && - // !mp_hal_is_interrupted()) { - // RUN_BACKGROUND_TASKS; - // } - // esp_ping_stop(ping); - // esp_ping_delete_session(ping); + struct net_icmp_ping_params params = { + .identifier = session.identifier, + .sequence = session.sequence, + .tc_tos = 0, + // A negative priority leaves the packet at the stack default and lets + // tc_tos drive the DSCP/ECN bits instead. + .priority = -1, + .data = NULL, + .data_size = 0, + }; + + session.sent_ms = k_uptime_get(); + + // A NULL sta_netif is fine; the stack picks an interface from the + // destination. This is the blocking send, as Zephyr's net shell uses: it + // waits up to a second for a buffer, so a ping can take timeout + 1s. + res = net_icmp_send_echo_request(&icmp_ctx, self->sta_netif, + (struct net_sockaddr *)&dst, ¶ms, &session); + if (res < 0) { + LOG_DBG("ping: send failed (%d)", res); + (void)net_icmp_cleanup_ctx(&icmp_ctx); + return -1; + } + + // Wait for ping_reply_handler() to signal, staying responsive to ctrl-C at + // the same 50 ms granularity as the association wait in + // common_hal_wifi_radio_connect(). + mp_float_t timeout_s = timeout <= 0 ? (mp_float_t)0.5 : timeout; + int64_t deadline = k_uptime_get() + (int64_t)(timeout_s * 1000); + bool replied = false; + while (true) { + int64_t remaining_ms = deadline - k_uptime_get(); + if (remaining_ms <= 0) { + break; + } + + // Poll in 50 ms slices so ctrl-C stays responsive, clamped to the + // caller's deadline so a reply arriving after the timeout is not + // reported as a success. MIN() is avoided here because py/misc.h and + // zephyr/sys/util.h both define it and this file includes both. + int64_t wait_ms = remaining_ms < 50 ? remaining_ms : 50; + + if (k_sem_take(&session.reply_sem, K_MSEC(wait_ms)) == 0) { + replied = true; + break; + } + if (mp_hal_is_interrupted()) { + break; + } + } + + // Unregister before returning. net_icmp_cleanup_ctx() takes the same mutex + // the stack holds while dispatching handlers, so once it returns no handler + // can still be looking at session, which lives on this stack frame. This + // has to happen on every exit path, including the error paths above. + (void)net_icmp_cleanup_ctx(&icmp_ctx); + + if (!replied || session.elapsed_ms < 0) { + return -1; + } - // return (mp_int_t)self->ping_elapsed_time; - return 0; + // shared-bindings turns exactly -1 into None and divides anything else by + // 1000, so every failure path must return -1, not 0. + return (mp_int_t)session.elapsed_ms; } void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self) { From 2ebfde00f82f44c861d769ea6bb8974cbc362864 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Sun, 23 Aug 2026 09:45:22 -0700 Subject: [PATCH 871/876] zephyr-cp/wifi: let boards turn radio.ping() off to save flash Adds CIRCUITPY_WIFI_PING to the port Kconfig, default y, and sets it to n for nrf7002dk_nrf5340_cpuapp, which is at 99.85% of flash before this series and overflows by 516 bytes once the ICMP ping code is in. With the option off, common_hal_wifi_radio_ping() returns -1, so radio.ping() reports None the same way it does for an unreachable host. Built for nordic_nrf7002dk with the option off: links at 966388 of 966656 bytes with the Homebrew arm-none-eabi toolchain, which is about 1 KB larger than the Zephyr SDK build CI uses. --- ports/zephyr-cp/Kconfig | 9 +++++++++ ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf | 3 +++ ports/zephyr-cp/common-hal/wifi/Radio.c | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/ports/zephyr-cp/Kconfig b/ports/zephyr-cp/Kconfig index 015864100ec..b202b53d53f 100644 --- a/ports/zephyr-cp/Kconfig +++ b/ports/zephyr-cp/Kconfig @@ -25,6 +25,15 @@ config UART_LINE_CTRL config ENTROPY_GENERATOR default y +# ===== CircuitPython feature defaults — enabled by default, boards can disable ===== + +config CIRCUITPY_WIFI_PING + bool "wifi.radio.ping() on Zephyr's ICMP API" + default y + help + Boards that are out of flash can set this to n. radio.ping() then + returns None, as it does for an unreachable host. + # ===== Bluetooth defaults ===== # Use a variable for the chosen name so the comma isn't parsed as an argument separator diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index 2255bd760d3..a4da934009a 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -8,3 +8,6 @@ CONFIG_LOG=n CONFIG_ASSERT=n CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_BT=n + +# Out of flash; radio.ping() alone overflows it. +CONFIG_CIRCUITPY_WIFI_PING=n diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 6c1c3e90056..513b4f84334 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -30,8 +30,10 @@ // dns_resolve_get_default() for radio.ipv4_dns. #include #include +#if defined(CONFIG_CIRCUITPY_WIFI_PING) // net_icmp_* for radio.ping(). #include +#endif #include #include #include @@ -898,6 +900,7 @@ void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t // common_hal_wifi_radio_start_dhcp_server(self); // restart access point DHCP } +#if defined(CONFIG_CIRCUITPY_WIFI_PING) // Zephyr delivers the echo reply on the network RX thread, not the caller's, so // the two halves share this state through the ICMP context's user_data. It lives // on the calling thread's stack, hence the cleanup discipline in ping() below. @@ -1072,6 +1075,12 @@ mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, // 1000, so every failure path must return -1, not 0. return (mp_int_t)session.elapsed_ms; } +#else +mp_int_t common_hal_wifi_radio_ping(wifi_radio_obj_t *self, mp_obj_t ip_address, mp_float_t timeout) { + // Boards that turn ping off to save flash report no reply. + return -1; +} +#endif void common_hal_wifi_radio_gc_collect(wifi_radio_obj_t *self) { // Only bother to scan the actual object references. From 1fb1c8087241fccb8c0ab6aa03f50859268030e9 Mon Sep 17 00:00:00 2001 From: Mikey Sklar Date: Tue, 25 Aug 2026 12:03:10 -0700 Subject: [PATCH 872/876] zephyr-cp/wifi: gate radio.ping() from circuitpython.toml, not Kconfig Review feedback from #11229: keep Kconfig for Zephyr configuration and put CircuitPython feature settings in circuitpython.toml. Drops the CIRCUITPY_WIFI_PING Kconfig symbol and the CONFIG_ override in the board .conf. The flag is now emitted by build_circuitpython.py the same way CIRCUITPY_ULAB is, defaulting on, and nordic_nrf7002dk opts out in its circuitpython.toml. The C guards become #if CIRCUITPY_WIFI_PING. Verified on two SiWx917-DK2605A boards, ping still compiled in and working: 5 of 5 replies from the gateway and None for an unreachable host on both. --- ports/zephyr-cp/Kconfig | 9 --------- .../zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml | 3 +++ ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf | 3 --- ports/zephyr-cp/common-hal/wifi/Radio.c | 4 ++-- ports/zephyr-cp/cptools/build_circuitpython.py | 6 ++++++ 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/ports/zephyr-cp/Kconfig b/ports/zephyr-cp/Kconfig index b202b53d53f..015864100ec 100644 --- a/ports/zephyr-cp/Kconfig +++ b/ports/zephyr-cp/Kconfig @@ -25,15 +25,6 @@ config UART_LINE_CTRL config ENTROPY_GENERATOR default y -# ===== CircuitPython feature defaults — enabled by default, boards can disable ===== - -config CIRCUITPY_WIFI_PING - bool "wifi.radio.ping() on Zephyr's ICMP API" - default y - help - Boards that are out of flash can set this to n. radio.ping() then - returns None, as it does for an unreachable host. - # ===== Bluetooth defaults ===== # Use a variable for the chosen name so the comma isn't parsed as an argument separator diff --git a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml index f37513d252b..badaffb8e1b 100644 --- a/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml +++ b/ports/zephyr-cp/boards/nordic/nrf7002dk/circuitpython.toml @@ -7,3 +7,6 @@ DISABLED_MODULES=["aesio", "adafruit_bus_device", "zlib", "jpegio", "tilepalette # ulab is on by default. This board has under 3 KB of flash headroom, and # ulab costs about 90 KB, so it opts out. CIRCUITPY_ULAB = false + +# The same 3 KB is why radio.ping() is off here too. +CIRCUITPY_WIFI_PING = false diff --git a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf index a4da934009a..2255bd760d3 100644 --- a/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf +++ b/ports/zephyr-cp/boards/nrf7002dk_nrf5340_cpuapp.conf @@ -8,6 +8,3 @@ CONFIG_LOG=n CONFIG_ASSERT=n CONFIG_TEST_RANDOM_GENERATOR=y CONFIG_BT=n - -# Out of flash; radio.ping() alone overflows it. -CONFIG_CIRCUITPY_WIFI_PING=n diff --git a/ports/zephyr-cp/common-hal/wifi/Radio.c b/ports/zephyr-cp/common-hal/wifi/Radio.c index 513b4f84334..a85f6bbb736 100644 --- a/ports/zephyr-cp/common-hal/wifi/Radio.c +++ b/ports/zephyr-cp/common-hal/wifi/Radio.c @@ -30,7 +30,7 @@ // dns_resolve_get_default() for radio.ipv4_dns. #include #include -#if defined(CONFIG_CIRCUITPY_WIFI_PING) +#if CIRCUITPY_WIFI_PING // net_icmp_* for radio.ping(). #include #endif @@ -900,7 +900,7 @@ void common_hal_wifi_radio_set_ipv4_address_ap(wifi_radio_obj_t *self, mp_obj_t // common_hal_wifi_radio_start_dhcp_server(self); // restart access point DHCP } -#if defined(CONFIG_CIRCUITPY_WIFI_PING) +#if CIRCUITPY_WIFI_PING // Zephyr delivers the echo reply on the network RX thread, not the caller's, so // the two halves share this state through the ICMP context's user_data. It lives // on the calling thread's stack, hence the cleanup discipline in ping() below. diff --git a/ports/zephyr-cp/cptools/build_circuitpython.py b/ports/zephyr-cp/cptools/build_circuitpython.py index 72cd7d28342..cb36ce7f3da 100644 --- a/ports/zephyr-cp/cptools/build_circuitpython.py +++ b/ports/zephyr-cp/cptools/build_circuitpython.py @@ -657,6 +657,12 @@ async def build_circuitpython(): # noqa: C901 str(top / "extmod" / "ulab" / "code"), ) ) + # radio.ping() builds on Zephyr's ICMP API. On by default; boards that cannot + # spare the flash set CIRCUITPY_WIFI_PING = false in their circuitpython.toml + # and radio.ping() then reports no reply, as it does for an unreachable host. + circuitpython_flags.append( + f"-DCIRCUITPY_WIFI_PING={1 if mpconfigboard.get('CIRCUITPY_WIFI_PING', True) else 0}" + ) source_files = supervisor_source + hal_source + ["extmod/vfs.c"] if ulab_enabled: From 395ec50d88059ac1f741367b5c81f15629791b21 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Thu, 27 Aug 2026 19:26:20 +0200 Subject: [PATCH 873/876] Update translation files Updated by "Update PO files to match POT (msgmerge)" hook in Weblate. Translation: CircuitPython/main Translate-URL: https://hosted.weblate.org/projects/circuitpython/main/ --- locale/cs.po | 37 +++++++++++++++++++++---------------- locale/el.po | 37 +++++++++++++++++++++---------------- locale/hi.po | 37 +++++++++++++++++++++---------------- locale/ko.po | 37 +++++++++++++++++++++---------------- locale/ru.po | 37 +++++++++++++++++++++---------------- locale/tr.po | 37 +++++++++++++++++++++---------------- 6 files changed, 126 insertions(+), 96 deletions(-) diff --git a/locale/cs.po b/locale/cs.po index a3432ce8d7f..18b5dea7fbb 100644 --- a/locale/cs.po +++ b/locale/cs.po @@ -1049,7 +1049,7 @@ msgstr "%q: selhání %d" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format msgid "Buffer must be a multiple of %d bytes" msgstr "" @@ -1487,6 +1487,7 @@ msgid "Requested resource not found" msgstr "Požadovaný zdroj nebyl nalezen" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c msgid "Operation or feature not supported" msgstr "Operace nebo funkce není podporována" @@ -1829,9 +1830,9 @@ msgstr "Konverze audia není implementována" #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/Filter.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" msgstr "%q musí být typu %q nebo %q, ne %q" @@ -1985,6 +1986,13 @@ msgstr "Není možné zapisovat do paměti jen pro čtení" msgid "All timers for this pin are in use" msgstr "Všechny časovače pro tento pin jsou používány" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q musí být typu %q, ne %q" + #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "" @@ -2324,7 +2332,7 @@ msgid "extra keyword arguments given" msgstr "" #: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c msgid "argument num/types mismatch" msgstr "" @@ -2345,12 +2353,6 @@ msgstr "%q musí být >= %d" msgid "%q must be <= %d" msgstr "%q musí být <= %d" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q musí být typu %q, ne %q" - #: py/argcheck.c msgid "%q length must be %d-%d" msgstr "%q délka musí být %d-%d" @@ -2905,7 +2907,9 @@ msgstr "záporný faktoriál" msgid "schedule queue full" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c msgid "buffer too small" msgstr "" @@ -4114,6 +4118,11 @@ msgstr "" msgid "Specify exactly one of data0 or data_pins" msgstr "Specifikuj přesně jeden z data0 nebo data_pins" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "Špatný formát" + #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." msgstr "Nepodařilo se odeslat příkaz." @@ -4439,10 +4448,6 @@ msgstr "" msgid "no default packer" msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "Špatný formát" - #: shared-module/paralleldisplaybus/ParallelBus.c msgid "" "This microcontroller only supports data0=, not data_pins=, because it " diff --git a/locale/el.po b/locale/el.po index 6598505448c..d97ea22b03f 100644 --- a/locale/el.po +++ b/locale/el.po @@ -1052,7 +1052,7 @@ msgstr "%q αποτυχία: %d" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format msgid "Buffer must be a multiple of %d bytes" msgstr "" @@ -1488,6 +1488,7 @@ msgid "Requested resource not found" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c msgid "Operation or feature not supported" msgstr "" @@ -1828,9 +1829,9 @@ msgstr "Η μετατροπή ήχου δεν υποστηρίζεται" #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/Filter.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" msgstr "%q πρέπει να είναι τύπου %q ή %q, όχι %q" @@ -1984,6 +1985,13 @@ msgstr "" msgid "All timers for this pin are in use" msgstr "Όλοι οι χρονιστές για αυτό το pin χρησιμοποιούνται ήδη" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q πρέπει να είναι τύπου %q, όχι %q" + #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "" @@ -2322,7 +2330,7 @@ msgid "extra keyword arguments given" msgstr "" #: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c msgid "argument num/types mismatch" msgstr "" @@ -2343,12 +2351,6 @@ msgstr "%q πρέπει να είναι >= %d" msgid "%q must be <= %d" msgstr "%q πρέπει να είναι <= %d" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q πρέπει να είναι τύπου %q, όχι %q" - #: py/argcheck.c msgid "%q length must be %d-%d" msgstr "%q μήκος πρέπει να είναι %d-%d" @@ -2898,7 +2900,9 @@ msgstr "" msgid "schedule queue full" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c msgid "buffer too small" msgstr "" @@ -4114,6 +4118,11 @@ msgstr "" msgid "Specify exactly one of data0 or data_pins" msgstr "" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "" + #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." msgstr "" @@ -4438,10 +4447,6 @@ msgstr "" msgid "no default packer" msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "" - #: shared-module/paralleldisplaybus/ParallelBus.c msgid "" "This microcontroller only supports data0=, not data_pins=, because it " diff --git a/locale/hi.po b/locale/hi.po index 3eb187fcf8e..68b041e16a5 100644 --- a/locale/hi.po +++ b/locale/hi.po @@ -1043,7 +1043,7 @@ msgstr "" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format msgid "Buffer must be a multiple of %d bytes" msgstr "" @@ -1478,6 +1478,7 @@ msgid "Requested resource not found" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c msgid "Operation or feature not supported" msgstr "" @@ -1818,9 +1819,9 @@ msgstr "" #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/Filter.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" msgstr "" @@ -1974,6 +1975,13 @@ msgstr "" msgid "All timers for this pin are in use" msgstr "" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "" + #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "" @@ -2312,7 +2320,7 @@ msgid "extra keyword arguments given" msgstr "" #: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c msgid "argument num/types mismatch" msgstr "" @@ -2333,12 +2341,6 @@ msgstr "" msgid "%q must be <= %d" msgstr "" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "" - #: py/argcheck.c msgid "%q length must be %d-%d" msgstr "" @@ -2888,7 +2890,9 @@ msgstr "" msgid "schedule queue full" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c msgid "buffer too small" msgstr "" @@ -4096,6 +4100,11 @@ msgstr "" msgid "Specify exactly one of data0 or data_pins" msgstr "" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "" + #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." msgstr "" @@ -4419,10 +4428,6 @@ msgstr "" msgid "no default packer" msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "" - #: shared-module/paralleldisplaybus/ParallelBus.c msgid "" "This microcontroller only supports data0=, not data_pins=, because it " diff --git a/locale/ko.po b/locale/ko.po index 0ff994e2e18..0811406c436 100644 --- a/locale/ko.po +++ b/locale/ko.po @@ -1053,7 +1053,7 @@ msgstr "%q 실패: %d" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format msgid "Buffer must be a multiple of %d bytes" msgstr "" @@ -1497,6 +1497,7 @@ msgid "Requested resource not found" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c msgid "Operation or feature not supported" msgstr "작업 또는 기능이 지원되지 않습니다" @@ -1844,9 +1845,9 @@ msgstr "오디오 변환이 구현되지 않음" #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/Filter.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" msgstr "%q는 %q가 아닌 %q 또는 %q 유형이어야 합니다" @@ -2003,6 +2004,13 @@ msgstr "" msgid "All timers for this pin are in use" msgstr "핀의 모든 타이머가 사용 중입니다" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q는 %q가 아니라 %q 유형이어야 합니다" + #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "핀은 순차적인 GPIO 핀이어야 합니다" @@ -2353,7 +2361,7 @@ msgid "extra keyword arguments given" msgstr "" #: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c msgid "argument num/types mismatch" msgstr "" @@ -2376,12 +2384,6 @@ msgstr "%q 는 >= %d 여야 합니다" msgid "%q must be <= %d" msgstr "%q 는 <= %d 여야 합니다" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q는 %q가 아니라 %q 유형이어야 합니다" - #: py/argcheck.c msgid "%q length must be %d-%d" msgstr "%q 길이는 %d - %d이어야 합니다" @@ -2937,7 +2939,9 @@ msgstr "" msgid "schedule queue full" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c msgid "buffer too small" msgstr "" @@ -4155,6 +4159,11 @@ msgstr "임의의 하드웨어를 사용할 수 없습니다" msgid "Specify exactly one of data0 or data_pins" msgstr "" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "잘못된 형식" + #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." msgstr "명령을 보내는 것에 실패했습니다." @@ -4483,10 +4492,6 @@ msgstr "" msgid "no default packer" msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "잘못된 형식" - #: shared-module/paralleldisplaybus/ParallelBus.c msgid "" "This microcontroller only supports data0=, not data_pins=, because it " diff --git a/locale/ru.po b/locale/ru.po index 9dac60be0b9..3e8d2d4e634 100644 --- a/locale/ru.po +++ b/locale/ru.po @@ -1056,7 +1056,7 @@ msgstr "%q сбой: %d" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format msgid "Buffer must be a multiple of %d bytes" msgstr "Буфер должен быть кратен %d байт" @@ -1496,6 +1496,7 @@ msgid "Requested resource not found" msgstr "Запрошенный ресурс не найден" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c msgid "Operation or feature not supported" msgstr "Операция или функция, не поддерживаемые" @@ -1842,9 +1843,9 @@ msgstr "Преобразование звука не реализовано" #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/Filter.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" msgstr "%q должно быть типа%q или%q, а не%q" @@ -1998,6 +1999,13 @@ msgstr "Невозможно записать в постоянную памят msgid "All timers for this pin are in use" msgstr "Все таймеры для этого пина уже используются" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q должно быть типа %q, а не %q" + #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "Пины должны быть последовательными выводами GPIO" @@ -2342,7 +2350,7 @@ msgid "extra keyword arguments given" msgstr "Приведены дополнительные аргументы ключевых слов" #: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c msgid "argument num/types mismatch" msgstr "Аргумент Несоответствие числа/типов" @@ -2365,12 +2373,6 @@ msgstr "%q должно быть >= %d" msgid "%q must be <= %d" msgstr "%q должно быть <= %d" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q должно быть типа %q, а не %q" - #: py/argcheck.c msgid "%q length must be %d-%d" msgstr "Длинна %q должна быть %d-%d" @@ -2927,7 +2929,9 @@ msgstr "отрицательный факториал" msgid "schedule queue full" msgstr "Расписание Очередь заполнена" -#: py/modstruct.c shared-module/struct/__init__.c +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c msgid "buffer too small" msgstr "буфер слишком мал" @@ -4167,6 +4171,11 @@ msgstr "Отсутствует аппаратный генератор случ msgid "Specify exactly one of data0 or data_pins" msgstr "Укажите точно один из data0 или data_pins" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "Недопустимый формат" + #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." msgstr "Не удалось отправить команду." @@ -4499,10 +4508,6 @@ msgstr "короткое чтение" msgid "no default packer" msgstr "Нет упаковщика по умолчанию" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "Недопустимый формат" - #: shared-module/paralleldisplaybus/ParallelBus.c msgid "" "This microcontroller only supports data0=, not data_pins=, because it " diff --git a/locale/tr.po b/locale/tr.po index 0b4d0026e47..41505586489 100644 --- a/locale/tr.po +++ b/locale/tr.po @@ -1052,7 +1052,7 @@ msgstr "%q hata: %d" #: ports/espressif/common-hal/sdioio/SDCard.c #: ports/raspberrypi/common-hal/sdioio/SDCard.c #: ports/stm/common-hal/sdioio/SDCard.c shared-bindings/floppyio/__init__.c -#: shared-module/sdcardio/SDCard.c +#: shared-bindings/picogame/Canvas.c shared-module/sdcardio/SDCard.c #, c-format msgid "Buffer must be a multiple of %d bytes" msgstr "Tampon, %d baytların katı olmalıdır" @@ -1490,6 +1490,7 @@ msgid "Requested resource not found" msgstr "" #: ports/espressif/common-hal/espidf/__init__.c +#: ports/raspberrypi/common-hal/picogame/Display.c msgid "Operation or feature not supported" msgstr "" @@ -1834,9 +1835,9 @@ msgstr "Ses dönüşümü implemente edilmedi" #: ports/raspberrypi/bindings/cyw43/__init__.c py/argcheck.c py/objexcept.c #: shared-bindings/bitmapfilter/__init__.c shared-bindings/canio/CAN.c -#: shared-bindings/digitalio/Pull.c shared-bindings/supervisor/__init__.c -#: shared-module/audiofilters/Filter.c shared-module/displayio/__init__.c -#: shared-module/synthio/Synthesizer.c +#: shared-bindings/digitalio/Pull.c shared-bindings/picogame/Sprite.c +#: shared-bindings/supervisor/__init__.c shared-module/audiofilters/Filter.c +#: shared-module/displayio/__init__.c shared-module/synthio/Synthesizer.c msgid "%q must be of type %q or %q, not %q" msgstr "%q; %q veya %q tipi olmalıdır, %q değil" @@ -1990,6 +1991,13 @@ msgstr "" msgid "All timers for this pin are in use" msgstr "Bu pin için tüm zamanlayıcılar kullanımda" +#: ports/raspberrypi/common-hal/picogame/Display.c py/argcheck.c py/runtime.c +#: shared-bindings/bitmapfilter/__init__.c +#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c +#: shared-module/synthio/__init__.c +msgid "%q must be of type %q, not %q" +msgstr "%q; %q tipi olmalıdır, %q değil" + #: ports/raspberrypi/common-hal/rotaryio/IncrementalEncoder.c msgid "Pins must be sequential GPIO pins" msgstr "" @@ -2329,7 +2337,7 @@ msgid "extra keyword arguments given" msgstr "" #: py/argcheck.c shared-bindings/_stage/__init__.c -#: shared-bindings/digitalio/DigitalInOut.c +#: shared-bindings/digitalio/DigitalInOut.c shared-bindings/picogame/__init__.c msgid "argument num/types mismatch" msgstr "" @@ -2350,12 +2358,6 @@ msgstr "%q >= %d olmalıdır" msgid "%q must be <= %d" msgstr "%q <= %d olmalıdır" -#: py/argcheck.c py/runtime.c shared-bindings/bitmapfilter/__init__.c -#: shared-module/audiodelays/MultiTapDelay.c shared-module/synthio/Note.c -#: shared-module/synthio/__init__.c -msgid "%q must be of type %q, not %q" -msgstr "%q; %q tipi olmalıdır, %q değil" - #: py/argcheck.c msgid "%q length must be %d-%d" msgstr "%q boyutları %d-%d olmalıdır" @@ -2905,7 +2907,9 @@ msgstr "" msgid "schedule queue full" msgstr "" -#: py/modstruct.c shared-module/struct/__init__.c +#: py/modstruct.c shared-bindings/picogame/Bitmap.c +#: shared-bindings/picogame/Canvas.c shared-bindings/picogame/Framebuffer.c +#: shared-module/picogame/__init__.c shared-module/struct/__init__.c msgid "buffer too small" msgstr "" @@ -4116,6 +4120,11 @@ msgstr "" msgid "Specify exactly one of data0 or data_pins" msgstr "" +#: shared-bindings/picogame/Bitmap.c shared-module/msgpack/__init__.c +#: supervisor/shared/settings.c +msgid "Invalid format" +msgstr "" + #: shared-bindings/ps2io/Ps2.c msgid "Failed sending command." msgstr "Komut gönderilemedi." @@ -4442,10 +4451,6 @@ msgstr "" msgid "no default packer" msgstr "" -#: shared-module/msgpack/__init__.c supervisor/shared/settings.c -msgid "Invalid format" -msgstr "" - #: shared-module/paralleldisplaybus/ParallelBus.c msgid "" "This microcontroller only supports data0=, not data_pins=, because it " From 0cf0486bc08843976bf7a34dcb4b97c4fc3a8375 Mon Sep 17 00:00:00 2001 From: Scott Shawcroft Date: Thu, 27 Aug 2026 15:06:41 -0700 Subject: [PATCH 874/876] Raise zephyr test timeouts and build nrf54lm20 bsim --- .github/workflows/run-tests.yml | 2 ++ ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py | 1 + ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 5bb3aaee736..711b5f321b6 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -99,5 +99,7 @@ jobs: working-directory: ports/zephyr-cp/tools/bsim - name: Build native_nrf5340bsim run: make -C ports/zephyr-cp -j2 BOARD=native_nrf5340bsim + - name: Build native_nrf54lm20bsim + run: make -C ports/zephyr-cp -j2 BOARD=native_nrf54lm20bsim - name: Run Zephyr tests run: make -C ports/zephyr-cp test diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py index 27fa78a5b7f..c8450e2af9f 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_advertising.py @@ -128,6 +128,7 @@ @pytest.mark.zephyr_sample("tests/bsim/samples/observer") @pytest.mark.circuitpy_drive({"code.py": BSIM_ADV_CODE}) +@pytest.mark.duration(60) def test_bsim_advertise_and_scan(bsim_phy, circuitpython, zephyr_sample): """Advertise from CircuitPython and verify Zephyr observer sees traffic.""" observer = zephyr_sample diff --git a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py index a8eb2612b40..ff99b789f0c 100644 --- a/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py +++ b/ports/zephyr-cp/tests/bsim/test_bsim_ble_peripheral.py @@ -95,7 +95,7 @@ def test_bsim_peripheral_zephyr_central(bsim_phy, circuitpython, zephyr_sample): assert "Disconnected:" in central_output -@pytest.mark.duration(14) +@pytest.mark.duration(20) @pytest.mark.circuitpy_drive({"code.py": BSIM_PERIPHERAL_CODE}) @pytest.mark.circuitpy_drive({"code.py": BSIM_CENTRAL_CODE}) def test_bsim_peripheral_cp_central(bsim_phy, circuitpython1, circuitpython2): From 689d4deeff20ab4b7952c11602f9cdf33da8e668 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Thu, 27 Aug 2026 19:35:56 -0400 Subject: [PATCH 875/876] shrink pybadge: turn off epaperdisplay --- ports/atmel-samd/boards/pybadge/mpconfigboard.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/ports/atmel-samd/boards/pybadge/mpconfigboard.mk b/ports/atmel-samd/boards/pybadge/mpconfigboard.mk index 70571b6c77d..86ce2d47e8c 100644 --- a/ports/atmel-samd/boards/pybadge/mpconfigboard.mk +++ b/ports/atmel-samd/boards/pybadge/mpconfigboard.mk @@ -14,6 +14,7 @@ CIRCUITPY_AESIO = 0 CIRCUITPY_FLOPPYIO = 0 CIRCUITPY_FRAMEBUFFERIO = 0 CIRCUITPY_GIFIO = 0 +CIRCUITPY_EPAPERDISPLAY = 0 CIRCUITPY_I2CDISPLAYBUS = 0 CIRCUITPY_JPEGIO = 0 CIRCUITPY_KEYPAD = 1 From 7a5f6b1e63eb7ae6f849440b070ca63af777acac Mon Sep 17 00:00:00 2001 From: ladyada Date: Thu, 27 Aug 2026 22:21:57 -0400 Subject: [PATCH 876/876] raspberrypi: rename port-specific PSRAM timing helper Co-authored-by: Limor Fried --- ports/raspberrypi/common-hal/microcontroller/Processor.c | 4 ++-- ports/raspberrypi/common-hal/microcontroller/Processor.h | 2 +- ports/raspberrypi/supervisor/port.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.c b/ports/raspberrypi/common-hal/microcontroller/Processor.c index a5f4691c075..fbbef51acb4 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.c +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.c @@ -57,7 +57,7 @@ uint32_t common_hal_mcu_processor_get_frequency(void) { } #ifdef CIRCUITPY_PSRAM_CHIP_SELECT -void __no_inline_not_in_flash_func(common_hal_mcu_processor_update_psram_timing)(uint32_t sys_clk_khz) { +void __no_inline_not_in_flash_func(mcu_processor_update_psram_timing)(uint32_t sys_clk_khz) { // MAX_SELECT is in units of 64 system clock cycles; PSRAM allows 8 us max CS // assertion. Use 7.5 us so there is margin at any clk_sys. uint32_t max_select = (75 * sys_clk_khz) / 640000; @@ -102,7 +102,7 @@ void common_hal_mcu_processor_set_frequency(mcu_processor_obj_t *self, uint32_t #endif set_sys_clock_khz(freq_khz, false); #ifdef CIRCUITPY_PSRAM_CHIP_SELECT - common_hal_mcu_processor_update_psram_timing(freq_khz); + mcu_processor_update_psram_timing(freq_khz); common_hal_mcu_enable_interrupts(); #endif } diff --git a/ports/raspberrypi/common-hal/microcontroller/Processor.h b/ports/raspberrypi/common-hal/microcontroller/Processor.h index bf3293672b9..9503eaf21f4 100644 --- a/ports/raspberrypi/common-hal/microcontroller/Processor.h +++ b/ports/raspberrypi/common-hal/microcontroller/Processor.h @@ -18,5 +18,5 @@ typedef struct { } mcu_processor_obj_t; #ifdef CIRCUITPY_PSRAM_CHIP_SELECT -void common_hal_mcu_processor_update_psram_timing(uint32_t sys_clk_khz); +void mcu_processor_update_psram_timing(uint32_t sys_clk_khz); #endif diff --git a/ports/raspberrypi/supervisor/port.c b/ports/raspberrypi/supervisor/port.c index 23917061abd..34e9fc159fd 100644 --- a/ports/raspberrypi/supervisor/port.c +++ b/ports/raspberrypi/supervisor/port.c @@ -241,7 +241,7 @@ static void __no_inline_not_in_flash_func(setup_psram)(void) { // Disable direct csr. qmi_hw->direct_csr &= ~(QMI_DIRECT_CSR_ASSERT_CS1N_BITS | QMI_DIRECT_CSR_EN_BITS); - common_hal_mcu_processor_update_psram_timing(sys_clk_khz); + mcu_processor_update_psram_timing(sys_clk_khz); qmi_hw->m[1].rfmt = (QMI_M0_RFMT_PREFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_PREFIX_WIDTH_LSB | QMI_M0_RFMT_ADDR_WIDTH_VALUE_Q << QMI_M0_RFMT_ADDR_WIDTH_LSB | QMI_M0_RFMT_SUFFIX_WIDTH_VALUE_Q << QMI_M0_RFMT_SUFFIX_WIDTH_LSB |